summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile130
-rw-r--r--lib/Makefile.inc3
-rw-r--r--lib/bind/Makefile5
-rw-r--r--lib/bind/bind/Makefile83
-rw-r--r--lib/bind/bind/config.h60
-rw-r--r--lib/bind/bind/port_after.h413
-rw-r--r--lib/bind/bind/port_before.h148
-rw-r--r--lib/bind/bind9/Makefile27
-rw-r--r--lib/bind/config.h277
-rw-r--r--lib/bind/config.mk99
-rw-r--r--lib/bind/dns/Makefile150
-rw-r--r--lib/bind/dns/code.h1598
-rw-r--r--lib/bind/dns/dns/enumclass.h48
-rw-r--r--lib/bind/dns/dns/enumtype.h140
-rw-r--r--lib/bind/dns/dns/rdatastruct.h1733
-rw-r--r--lib/bind/isc/Makefile126
-rw-r--r--lib/bind/isc/isc/platform.h257
-rw-r--r--lib/bind/isccc/Makefile39
-rw-r--r--lib/bind/isccfg/Makefile29
-rw-r--r--lib/bind/lwres/Makefile122
-rw-r--r--lib/bind/lwres/lwres/netdb.h520
-rw-r--r--lib/bind/lwres/lwres/platform.h113
-rw-r--r--lib/csu/alpha/Makefile21
-rw-r--r--lib/csu/alpha/crt1.c114
-rw-r--r--lib/csu/alpha/crti.S53
-rw-r--r--lib/csu/alpha/crtn.S45
-rw-r--r--lib/csu/amd64/Makefile22
-rw-r--r--lib/csu/amd64/crt1.c95
-rw-r--r--lib/csu/amd64/crti.S41
-rw-r--r--lib/csu/amd64/crtn.S35
-rw-r--r--lib/csu/arm/Makefile23
-rw-r--r--lib/csu/arm/crt1.c137
-rw-r--r--lib/csu/arm/crti.S21
-rw-r--r--lib/csu/arm/crtn.S9
-rw-r--r--lib/csu/common/crtbegin.c81
-rw-r--r--lib/csu/common/crtbrand.c52
-rw-r--r--lib/csu/common/crtend.c33
-rw-r--r--lib/csu/i386-elf/Makefile19
-rw-r--r--lib/csu/i386-elf/crt1.c113
-rw-r--r--lib/csu/i386-elf/crti.S41
-rw-r--r--lib/csu/i386-elf/crtn.S35
-rw-r--r--lib/csu/ia64/Makefile23
-rw-r--r--lib/csu/ia64/crt1.S196
-rw-r--r--lib/csu/ia64/crti.S57
-rw-r--r--lib/csu/ia64/crtn.S43
-rw-r--r--lib/csu/powerpc/Makefile23
-rw-r--r--lib/csu/powerpc/crt1.c123
-rw-r--r--lib/csu/powerpc/crti.S50
-rw-r--r--lib/csu/powerpc/crtn.S45
-rw-r--r--lib/csu/sparc64/Makefile21
-rw-r--r--lib/csu/sparc64/crt1.c125
-rw-r--r--lib/csu/sparc64/crti.S58
-rw-r--r--lib/csu/sparc64/crtn.S42
-rw-r--r--lib/libalias/Makefile16
-rw-r--r--lib/libarchive/COPYING37
-rw-r--r--lib/libarchive/Makefile197
-rw-r--r--lib/libarchive/README91
-rw-r--r--lib/libarchive/archive.h.in344
-rw-r--r--lib/libarchive/archive_check_magic.c110
-rw-r--r--lib/libarchive/archive_entry.3341
-rw-r--r--lib/libarchive/archive_entry.c1742
-rw-r--r--lib/libarchive/archive_entry.h251
-rw-r--r--lib/libarchive/archive_platform.h193
-rw-r--r--lib/libarchive/archive_private.h244
-rw-r--r--lib/libarchive/archive_read.3493
-rw-r--r--lib/libarchive/archive_read.c601
-rw-r--r--lib/libarchive/archive_read_data_into_buffer.c49
-rw-r--r--lib/libarchive/archive_read_data_into_fd.c84
-rw-r--r--lib/libarchive/archive_read_extract.c1604
-rw-r--r--lib/libarchive/archive_read_open_fd.c106
-rw-r--r--lib/libarchive/archive_read_open_file.c168
-rw-r--r--lib/libarchive/archive_read_open_filename.c168
-rw-r--r--lib/libarchive/archive_read_support_compression_all.c44
-rw-r--r--lib/libarchive/archive_read_support_compression_bzip2.c393
-rw-r--r--lib/libarchive/archive_read_support_compression_compress.c482
-rw-r--r--lib/libarchive/archive_read_support_compression_gzip.c531
-rw-r--r--lib/libarchive/archive_read_support_compression_none.c266
-rw-r--r--lib/libarchive/archive_read_support_format_all.c40
-rw-r--r--lib/libarchive/archive_read_support_format_cpio.c610
-rw-r--r--lib/libarchive/archive_read_support_format_iso9660.c1061
-rw-r--r--lib/libarchive/archive_read_support_format_tar.c1898
-rw-r--r--lib/libarchive/archive_read_support_format_zip.c797
-rw-r--r--lib/libarchive/archive_string.c113
-rw-r--r--lib/libarchive/archive_string.h112
-rw-r--r--lib/libarchive/archive_string_sprintf.c129
-rw-r--r--lib/libarchive/archive_util.3135
-rw-r--r--lib/libarchive/archive_util.c161
-rw-r--r--lib/libarchive/archive_write.3433
-rw-r--r--lib/libarchive/archive_write.c229
-rw-r--r--lib/libarchive/archive_write_open_fd.c133
-rw-r--r--lib/libarchive/archive_write_open_file.c166
-rw-r--r--lib/libarchive/archive_write_open_filename.c166
-rw-r--r--lib/libarchive/archive_write_set_compression_bzip2.c343
-rw-r--r--lib/libarchive/archive_write_set_compression_gzip.c399
-rw-r--r--lib/libarchive/archive_write_set_compression_none.c218
-rw-r--r--lib/libarchive/archive_write_set_format.c65
-rw-r--r--lib/libarchive/archive_write_set_format_by_name.c63
-rw-r--r--lib/libarchive/archive_write_set_format_cpio.c246
-rw-r--r--lib/libarchive/archive_write_set_format_pax.c1187
-rw-r--r--lib/libarchive/archive_write_set_format_shar.c534
-rw-r--r--lib/libarchive/archive_write_set_format_ustar.c498
-rw-r--r--lib/libarchive/libarchive-formats.5255
-rw-r--r--lib/libarchive/libarchive.3317
-rw-r--r--lib/libarchive/tar.5730
-rw-r--r--lib/libatm/Makefile40
-rw-r--r--lib/libatm/atm_addr.c328
-rw-r--r--lib/libatm/cache_key.c104
-rw-r--r--lib/libatm/ioctl_subr.c461
-rw-r--r--lib/libatm/ip_addr.c160
-rw-r--r--lib/libatm/ip_checksum.c92
-rw-r--r--lib/libatm/libatm.h117
-rw-r--r--lib/libatm/timer.c258
-rw-r--r--lib/libautofs/Makefile12
-rw-r--r--lib/libautofs/libautofs.3265
-rw-r--r--lib/libautofs/libautofs.c479
-rw-r--r--lib/libautofs/libautofs.h104
-rw-r--r--lib/libbegemot/Makefile28
-rw-r--r--lib/libbluetooth/Makefile30
-rw-r--r--lib/libbluetooth/bluetooth.3289
-rw-r--r--lib/libbluetooth/bluetooth.c369
-rw-r--r--lib/libbluetooth/bluetooth.h78
-rw-r--r--lib/libbsm/Makefile140
-rw-r--r--lib/libbsnmp/Makefile5
-rw-r--r--lib/libbsnmp/Makefile.inc6
-rw-r--r--lib/libbsnmp/libbsnmp/Makefile19
-rw-r--r--lib/libbz2/Makefile13
-rw-r--r--lib/libc/Makefile119
-rw-r--r--lib/libc/Versions.def12
-rw-r--r--lib/libc/alpha/Makefile.inc8
-rw-r--r--lib/libc/alpha/SYS.h74
-rw-r--r--lib/libc/alpha/Symbol.map77
-rw-r--r--lib/libc/alpha/_fpmath.h49
-rw-r--r--lib/libc/alpha/arith.h20
-rw-r--r--lib/libc/alpha/gen/Makefile.inc47
-rw-r--r--lib/libc/alpha/gen/_ctx_start.S45
-rw-r--r--lib/libc/alpha/gen/_set_tp.c40
-rw-r--r--lib/libc/alpha/gen/_setjmp.S127
-rw-r--r--lib/libc/alpha/gen/divrem.m4198
-rw-r--r--lib/libc/alpha/gen/fabs.S36
-rw-r--r--lib/libc/alpha/gen/flt_rounds.c60
-rw-r--r--lib/libc/alpha/gen/fpgetmask.c52
-rw-r--r--lib/libc/alpha/gen/fpgetround.c52
-rw-r--r--lib/libc/alpha/gen/fpgetsticky.c52
-rw-r--r--lib/libc/alpha/gen/fpsetmask.c54
-rw-r--r--lib/libc/alpha/gen/fpsetround.c61
-rw-r--r--lib/libc/alpha/gen/infinity.c39
-rw-r--r--lib/libc/alpha/gen/makecontext.c172
-rw-r--r--lib/libc/alpha/gen/modf.c107
-rw-r--r--lib/libc/alpha/gen/rfork_thread.S66
-rw-r--r--lib/libc/alpha/gen/setjmp.S138
-rw-r--r--lib/libc/alpha/gen/signalcontext.c103
-rw-r--r--lib/libc/alpha/gen/sigsetjmp.S64
-rw-r--r--lib/libc/alpha/net/Makefile.inc3
-rw-r--r--lib/libc/alpha/net/byte_swap_2.S49
-rw-r--r--lib/libc/alpha/net/byte_swap_4.S55
-rw-r--r--lib/libc/alpha/net/htonl.S36
-rw-r--r--lib/libc/alpha/net/htons.S36
-rw-r--r--lib/libc/alpha/net/ntohl.S36
-rw-r--r--lib/libc/alpha/net/ntohs.S36
-rw-r--r--lib/libc/alpha/stdlib/Makefile.inc3
-rw-r--r--lib/libc/alpha/string/Makefile.inc3
-rw-r--r--lib/libc/alpha/string/bcopy.S289
-rw-r--r--lib/libc/alpha/string/bzero.S111
-rw-r--r--lib/libc/alpha/string/ffs.S92
-rw-r--r--lib/libc/alpha/string/memcpy.S8
-rw-r--r--lib/libc/alpha/string/memmove.S7
-rw-r--r--lib/libc/alpha/sys/Makefile.inc12
-rw-r--r--lib/libc/alpha/sys/Ovfork.S38
-rw-r--r--lib/libc/alpha/sys/brk.S53
-rw-r--r--lib/libc/alpha/sys/cerror.S56
-rw-r--r--lib/libc/alpha/sys/exect.S38
-rw-r--r--lib/libc/alpha/sys/fork.S38
-rw-r--r--lib/libc/alpha/sys/pipe.S40
-rw-r--r--lib/libc/alpha/sys/ptrace.S40
-rw-r--r--lib/libc/alpha/sys/sbrk.S53
-rw-r--r--lib/libc/alpha/sys/setlogin.S40
-rw-r--r--lib/libc/alpha/sys/sigreturn.S41
-rw-r--r--lib/libc/amd64/Makefile.inc9
-rw-r--r--lib/libc/amd64/SYS.h66
-rw-r--r--lib/libc/amd64/Symbol.map73
-rw-r--r--lib/libc/amd64/_fpmath.h50
-rw-r--r--lib/libc/amd64/arith.h19
-rw-r--r--lib/libc/amd64/gen/Makefile.inc8
-rw-r--r--lib/libc/amd64/gen/_set_tp.c38
-rw-r--r--lib/libc/amd64/gen/_setjmp.S87
-rw-r--r--lib/libc/amd64/gen/fabs.S43
-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/infinity.c14
-rw-r--r--lib/libc/amd64/gen/ldexp.c66
-rw-r--r--lib/libc/amd64/gen/makecontext.c107
-rw-r--r--lib/libc/amd64/gen/modf.S92
-rw-r--r--lib/libc/amd64/gen/rfork_thread.S101
-rw-r--r--lib/libc/amd64/gen/setjmp.S105
-rw-r--r--lib/libc/amd64/gen/signalcontext.c106
-rw-r--r--lib/libc/amd64/gen/sigsetjmp.S115
-rw-r--r--lib/libc/amd64/net/Makefile.inc4
-rw-r--r--lib/libc/amd64/net/htonl.S50
-rw-r--r--lib/libc/amd64/net/htons.S50
-rw-r--r--lib/libc/amd64/net/ntohl.S50
-rw-r--r--lib/libc/amd64/net/ntohs.S52
-rw-r--r--lib/libc/amd64/string/Makefile.inc4
-rw-r--r--lib/libc/amd64/string/bcmp.S24
-rw-r--r--lib/libc/amd64/string/bcopy.S88
-rw-r--r--lib/libc/amd64/string/bzero.S43
-rw-r--r--lib/libc/amd64/string/memcmp.S41
-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.S60
-rw-r--r--lib/libc/amd64/string/strcat.S165
-rw-r--r--lib/libc/amd64/string/strcmp.S73
-rw-r--r--lib/libc/amd64/string/strcpy.S111
-rw-r--r--lib/libc/amd64/sys/Makefile.inc14
-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.S87
-rw-r--r--lib/libc/amd64/sys/cerror.S62
-rw-r--r--lib/libc/amd64/sys/exect.S59
-rw-r--r--lib/libc/amd64/sys/getcontext.S54
-rw-r--r--lib/libc/amd64/sys/pipe.S63
-rw-r--r--lib/libc/amd64/sys/ptrace.S63
-rw-r--r--lib/libc/amd64/sys/reboot.S60
-rw-r--r--lib/libc/amd64/sys/sbrk.S91
-rw-r--r--lib/libc/amd64/sys/setlogin.S68
-rw-r--r--lib/libc/amd64/sys/sigreturn.S50
-rw-r--r--lib/libc/amd64/sys/vfork.S62
-rw-r--r--lib/libc/arm/Makefile.inc12
-rw-r--r--lib/libc/arm/SYS.h90
-rw-r--r--lib/libc/arm/Symbol.map66
-rw-r--r--lib/libc/arm/_fpmath.h55
-rw-r--r--lib/libc/arm/arith.h16
-rw-r--r--lib/libc/arm/gen/Makefile.inc6
-rw-r--r--lib/libc/arm/gen/_ctx_start.S9
-rw-r--r--lib/libc/arm/gen/_set_tp.c35
-rw-r--r--lib/libc/arm/gen/_setjmp.S106
-rw-r--r--lib/libc/arm/gen/alloca.S45
-rw-r--r--lib/libc/arm/gen/divsi3.S387
-rw-r--r--lib/libc/arm/gen/fabs.c46
-rw-r--r--lib/libc/arm/gen/infinity.c26
-rw-r--r--lib/libc/arm/gen/makecontext.c96
-rw-r--r--lib/libc/arm/gen/modf.c107
-rw-r--r--lib/libc/arm/gen/setjmp.S129
-rw-r--r--lib/libc/arm/gen/signalcontext.c78
-rw-r--r--lib/libc/arm/gen/sigsetjmp.S62
-rw-r--r--lib/libc/arm/net/Makefile.inc4
-rw-r--r--lib/libc/arm/net/htonl.S48
-rw-r--r--lib/libc/arm/net/htons.S47
-rw-r--r--lib/libc/arm/net/ntohl.S48
-rw-r--r--lib/libc/arm/net/ntohs.S47
-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.h313
-rw-r--r--lib/libc/arm/stdlib/Makefile.inc4
-rw-r--r--lib/libc/arm/string/Makefile.inc7
-rw-r--r--lib/libc/arm/string/bcopy.S6
-rw-r--r--lib/libc/arm/string/bzero.S44
-rw-r--r--lib/libc/arm/string/ffs.S82
-rw-r--r--lib/libc/arm/string/memcmp.S180
-rw-r--r--lib/libc/arm/string/memcpy.S9
-rw-r--r--lib/libc/arm/string/memcpy_arm.S339
-rw-r--r--lib/libc/arm/string/memcpy_xscale.S1783
-rw-r--r--lib/libc/arm/string/memmove.S589
-rw-r--r--lib/libc/arm/string/memset.S236
-rw-r--r--lib/libc/arm/string/strcmp.S43
-rw-r--r--lib/libc/arm/string/strlen.S78
-rw-r--r--lib/libc/arm/string/strncmp.S51
-rw-r--r--lib/libc/arm/sys/Makefile.inc9
-rw-r--r--lib/libc/arm/sys/Ovfork.S57
-rw-r--r--lib/libc/arm/sys/brk.S100
-rw-r--r--lib/libc/arm/sys/cerror.S76
-rw-r--r--lib/libc/arm/sys/fork.S49
-rw-r--r--lib/libc/arm/sys/pipe.S50
-rw-r--r--lib/libc/arm/sys/ptrace.S77
-rw-r--r--lib/libc/arm/sys/sbrk.S88
-rw-r--r--lib/libc/arm/sys/shmat.S7
-rw-r--r--lib/libc/arm/sys/sigreturn.S42
-rw-r--r--lib/libc/arm/sys/syscall.S38
-rw-r--r--lib/libc/compat-43/Makefile.inc19
-rw-r--r--lib/libc/compat-43/Symbol.map21
-rw-r--r--lib/libc/compat-43/creat.266
-rw-r--r--lib/libc/compat-43/creat.c50
-rw-r--r--lib/libc/compat-43/gethostid.384
-rw-r--r--lib/libc/compat-43/gethostid.c58
-rw-r--r--lib/libc/compat-43/getwd.c55
-rw-r--r--lib/libc/compat-43/killpg.2102
-rw-r--r--lib/libc/compat-43/killpg.c55
-rw-r--r--lib/libc/compat-43/sethostid.c53
-rw-r--r--lib/libc/compat-43/setpgrp.c47
-rw-r--r--lib/libc/compat-43/setrgid.c47
-rw-r--r--lib/libc/compat-43/setruid.384
-rw-r--r--lib/libc/compat-43/setruid.c47
-rw-r--r--lib/libc/compat-43/sigcompat.c112
-rw-r--r--lib/libc/compat-43/sigpause.297
-rw-r--r--lib/libc/compat-43/sigsetmask.2107
-rw-r--r--lib/libc/compat-43/sigvec.2346
-rw-r--r--lib/libc/db/Makefile.inc13
-rw-r--r--lib/libc/db/README40
-rw-r--r--lib/libc/db/Symbol.map30
-rw-r--r--lib/libc/db/btree/Makefile.inc8
-rw-r--r--lib/libc/db/btree/bt_close.c186
-rw-r--r--lib/libc/db/btree/bt_conv.c223
-rw-r--r--lib/libc/db/btree/bt_debug.c332
-rw-r--r--lib/libc/db/btree/bt_delete.c659
-rw-r--r--lib/libc/db/btree/bt_get.c107
-rw-r--r--lib/libc/db/btree/bt_open.c449
-rw-r--r--lib/libc/db/btree/bt_overflow.c230
-rw-r--r--lib/libc/db/btree/bt_page.c102
-rw-r--r--lib/libc/db/btree/bt_put.c325
-rw-r--r--lib/libc/db/btree/bt_search.c215
-rw-r--r--lib/libc/db/btree/bt_seq.c462
-rw-r--r--lib/libc/db/btree/bt_split.c827
-rw-r--r--lib/libc/db/btree/bt_utils.c262
-rw-r--r--lib/libc/db/btree/btree.h384
-rw-r--r--lib/libc/db/btree/extern.h71
-rw-r--r--lib/libc/db/changelog103
-rw-r--r--lib/libc/db/db/Makefile.inc6
-rw-r--r--lib/libc/db/db/db.c101
-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/README72
-rw-r--r--lib/libc/db/hash/extern.h66
-rw-r--r--lib/libc/db/hash/hash.c1006
-rw-r--r--lib/libc/db/hash/hash.h294
-rw-r--r--lib/libc/db/hash/hash_bigkey.c670
-rw-r--r--lib/libc/db/hash/hash_buf.c356
-rw-r--r--lib/libc/db/hash/hash_func.c214
-rw-r--r--lib/libc/db/hash/hash_log2.c56
-rw-r--r--lib/libc/db/hash/hash_page.c948
-rw-r--r--lib/libc/db/hash/ndbm.c231
-rw-r--r--lib/libc/db/hash/page.h93
-rw-r--r--lib/libc/db/man/Makefile.inc18
-rw-r--r--lib/libc/db/man/btree.3275
-rw-r--r--lib/libc/db/man/dbm.3230
-rw-r--r--lib/libc/db/man/dbopen.3550
-rw-r--r--lib/libc/db/man/hash.3200
-rw-r--r--lib/libc/db/man/mpool.3231
-rw-r--r--lib/libc/db/man/recno.3232
-rw-r--r--lib/libc/db/mpool/Makefile.inc6
-rw-r--r--lib/libc/db/mpool/README7
-rw-r--r--lib/libc/db/mpool/mpool.c462
-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.h55
-rw-r--r--lib/libc/db/recno/rec_close.c188
-rw-r--r--lib/libc/db/recno/rec_delete.c199
-rw-r--r--lib/libc/db/recno/rec_get.c313
-rw-r--r--lib/libc/db/recno/rec_open.c245
-rw-r--r--lib/libc/db/recno/rec_put.c287
-rw-r--r--lib/libc/db/recno/rec_search.c128
-rw-r--r--lib/libc/db/recno/rec_seq.c134
-rw-r--r--lib/libc/db/recno/rec_utils.c124
-rw-r--r--lib/libc/db/recno/recno.h40
-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.c767
-rw-r--r--lib/libc/db/test/dbtest.c742
-rw-r--r--lib/libc/db/test/hash.tests/driver2.c116
-rw-r--r--lib/libc/db/test/hash.tests/makedb.sh13
-rw-r--r--lib/libc/db/test/hash.tests/tcreat3.c107
-rw-r--r--lib/libc/db/test/hash.tests/tdel.c124
-rw-r--r--lib/libc/db/test/hash.tests/testit147
-rw-r--r--lib/libc/db/test/hash.tests/thash4.c134
-rw-r--r--lib/libc/db/test/hash.tests/tread2.c107
-rw-r--r--lib/libc/db/test/hash.tests/tseq.c90
-rw-r--r--lib/libc/db/test/hash.tests/tverify.c109
-rw-r--r--lib/libc/db/test/run.test705
-rw-r--r--lib/libc/gdtoa/Makefile.inc20
-rw-r--r--lib/libc/gdtoa/Symbol.map39
-rw-r--r--lib/libc/gdtoa/_hdtoa.c319
-rw-r--r--lib/libc/gdtoa/_ldtoa.c100
-rw-r--r--lib/libc/gdtoa/glue.c13
-rw-r--r--lib/libc/gdtoa/machdep_ldisQ.c45
-rw-r--r--lib/libc/gdtoa/machdep_ldisd.c43
-rw-r--r--lib/libc/gdtoa/machdep_ldisx.c45
-rw-r--r--lib/libc/gen/Makefile.inc154
-rw-r--r--lib/libc/gen/Symbol.map446
-rw-r--r--lib/libc/gen/__xuname.c142
-rw-r--r--lib/libc/gen/_pthread_stubs.c303
-rw-r--r--lib/libc/gen/_rand48.c49
-rw-r--r--lib/libc/gen/_spinlock_stub.c82
-rw-r--r--lib/libc/gen/_thread_init.c41
-rw-r--r--lib/libc/gen/alarm.398
-rw-r--r--lib/libc/gen/alarm.c61
-rw-r--r--lib/libc/gen/arc4random.3107
-rw-r--r--lib/libc/gen/arc4random.c235
-rw-r--r--lib/libc/gen/assert.c60
-rw-r--r--lib/libc/gen/basename.3103
-rw-r--r--lib/libc/gen/basename.c84
-rw-r--r--lib/libc/gen/check_utility_compat.389
-rw-r--r--lib/libc/gen/check_utility_compat.c75
-rw-r--r--lib/libc/gen/clock.380
-rw-r--r--lib/libc/gen/clock.c59
-rw-r--r--lib/libc/gen/closedir.c74
-rw-r--r--lib/libc/gen/confstr.3135
-rw-r--r--lib/libc/gen/confstr.c125
-rw-r--r--lib/libc/gen/crypt.c98
-rw-r--r--lib/libc/gen/ctermid.3111
-rw-r--r--lib/libc/gen/ctermid.c61
-rw-r--r--lib/libc/gen/daemon.3116
-rw-r--r--lib/libc/gen/daemon.c95
-rw-r--r--lib/libc/gen/devname.397
-rw-r--r--lib/libc/gen/devname.c81
-rw-r--r--lib/libc/gen/directory.3208
-rw-r--r--lib/libc/gen/dirname.3110
-rw-r--r--lib/libc/gen/dirname.c87
-rw-r--r--lib/libc/gen/disklabel.c163
-rw-r--r--lib/libc/gen/dladdr.3133
-rw-r--r--lib/libc/gen/dlfcn.c129
-rw-r--r--lib/libc/gen/dlfunc.c30
-rw-r--r--lib/libc/gen/dlinfo.3282
-rw-r--r--lib/libc/gen/dllockinit.3127
-rw-r--r--lib/libc/gen/dlopen.3360
-rw-r--r--lib/libc/gen/drand48.c25
-rw-r--r--lib/libc/gen/erand48.c26
-rw-r--r--lib/libc/gen/err.3236
-rw-r--r--lib/libc/gen/err.c213
-rw-r--r--lib/libc/gen/errlst.c158
-rw-r--r--lib/libc/gen/errno.c30
-rw-r--r--lib/libc/gen/exec.3325
-rw-r--r--lib/libc/gen/exec.c275
-rw-r--r--lib/libc/gen/fmtcheck.3117
-rw-r--r--lib/libc/gen/fmtcheck.c267
-rw-r--r--lib/libc/gen/fmtmsg.3260
-rw-r--r--lib/libc/gen/fmtmsg.c220
-rw-r--r--lib/libc/gen/fnmatch.3155
-rw-r--r--lib/libc/gen/fnmatch.c295
-rw-r--r--lib/libc/gen/fpclassify.3133
-rw-r--r--lib/libc/gen/fpclassify.c93
-rw-r--r--lib/libc/gen/frexp.398
-rw-r--r--lib/libc/gen/frexp.c57
-rw-r--r--lib/libc/gen/fstab.c298
-rw-r--r--lib/libc/gen/ftok.383
-rw-r--r--lib/libc/gen/ftok.c46
-rw-r--r--lib/libc/gen/fts-compat.c1226
-rw-r--r--lib/libc/gen/fts-compat.h145
-rw-r--r--lib/libc/gen/fts.3820
-rw-r--r--lib/libc/gen/fts.c1226
-rw-r--r--lib/libc/gen/ftw.3216
-rw-r--r--lib/libc/gen/ftw.c98
-rw-r--r--lib/libc/gen/getbootfile.373
-rw-r--r--lib/libc/gen/getbootfile.c57
-rw-r--r--lib/libc/gen/getbsize.382
-rw-r--r--lib/libc/gen/getbsize.c109
-rw-r--r--lib/libc/gen/getcap.3571
-rw-r--r--lib/libc/gen/getcap.c1058
-rw-r--r--lib/libc/gen/getcontext.3121
-rw-r--r--lib/libc/gen/getcwd.3158
-rw-r--r--lib/libc/gen/getcwd.c261
-rw-r--r--lib/libc/gen/getdiskbyname.368
-rw-r--r--lib/libc/gen/getdomainname.3104
-rw-r--r--lib/libc/gen/getdomainname.c59
-rw-r--r--lib/libc/gen/getfsent.3189
-rw-r--r--lib/libc/gen/getgrent.3291
-rw-r--r--lib/libc/gen/getgrent.c1428
-rw-r--r--lib/libc/gen/getgrouplist.396
-rw-r--r--lib/libc/gen/getgrouplist.c91
-rw-r--r--lib/libc/gen/gethostname.3135
-rw-r--r--lib/libc/gen/gethostname.c64
-rw-r--r--lib/libc/gen/getloadavg.369
-rw-r--r--lib/libc/gen/getloadavg.c73
-rw-r--r--lib/libc/gen/getlogin.c106
-rw-r--r--lib/libc/gen/getmntinfo.3113
-rw-r--r--lib/libc/gen/getmntinfo.c72
-rw-r--r--lib/libc/gen/getnetgrent.3135
-rw-r--r--lib/libc/gen/getnetgrent.c642
-rw-r--r--lib/libc/gen/getobjformat.3135
-rw-r--r--lib/libc/gen/getobjformat.c44
-rw-r--r--lib/libc/gen/getosreldate.386
-rw-r--r--lib/libc/gen/getosreldate.c63
-rw-r--r--lib/libc/gen/getpagesize.365
-rw-r--r--lib/libc/gen/getpagesize.c68
-rw-r--r--lib/libc/gen/getpass.397
-rw-r--r--lib/libc/gen/getpeereid.3137
-rw-r--r--lib/libc/gen/getpeereid.c54
-rw-r--r--lib/libc/gen/getprogname.394
-rw-r--r--lib/libc/gen/getprogname.c17
-rw-r--r--lib/libc/gen/getpwent.3319
-rw-r--r--lib/libc/gen/getpwent.c2009
-rw-r--r--lib/libc/gen/getttyent.3213
-rw-r--r--lib/libc/gen/getttyent.c303
-rw-r--r--lib/libc/gen/getusershell.3103
-rw-r--r--lib/libc/gen/getusershell.c274
-rw-r--r--lib/libc/gen/getvfsbyname.3114
-rw-r--r--lib/libc/gen/getvfsbyname.c80
-rw-r--r--lib/libc/gen/glob.3475
-rw-r--r--lib/libc/gen/glob.c956
-rw-r--r--lib/libc/gen/initgroups.390
-rw-r--r--lib/libc/gen/initgroups.c63
-rw-r--r--lib/libc/gen/isatty.c52
-rw-r--r--lib/libc/gen/isgreater.3102
-rw-r--r--lib/libc/gen/isinf.c70
-rw-r--r--lib/libc/gen/isnan.c57
-rw-r--r--lib/libc/gen/jrand48.c24
-rw-r--r--lib/libc/gen/lcong48.c33
-rw-r--r--lib/libc/gen/ldexp.381
-rw-r--r--lib/libc/gen/ldexp.c123
-rw-r--r--lib/libc/gen/lockf.3273
-rw-r--r--lib/libc/gen/lockf.c89
-rw-r--r--lib/libc/gen/lrand48.c26
-rw-r--r--lib/libc/gen/makecontext.3120
-rw-r--r--lib/libc/gen/modf.375
-rw-r--r--lib/libc/gen/mrand48.c26
-rw-r--r--lib/libc/gen/msgctl.3214
-rw-r--r--lib/libc/gen/msgget.3141
-rw-r--r--lib/libc/gen/msgrcv.3222
-rw-r--r--lib/libc/gen/msgsnd.3179
-rw-r--r--lib/libc/gen/nftw.c117
-rw-r--r--lib/libc/gen/nice.373
-rw-r--r--lib/libc/gen/nice.c60
-rw-r--r--lib/libc/gen/nlist.381
-rw-r--r--lib/libc/gen/nlist.c416
-rw-r--r--lib/libc/gen/nrand48.c24
-rw-r--r--lib/libc/gen/opendir.c287
-rw-r--r--lib/libc/gen/pause.386
-rw-r--r--lib/libc/gen/pause.c52
-rw-r--r--lib/libc/gen/pmadvise.c16
-rw-r--r--lib/libc/gen/popen.3201
-rw-r--r--lib/libc/gen/popen.c208
-rw-r--r--lib/libc/gen/posixshm.c72
-rw-r--r--lib/libc/gen/pselect.3127
-rw-r--r--lib/libc/gen/pselect.c78
-rw-r--r--lib/libc/gen/psignal.3113
-rw-r--r--lib/libc/gen/psignal.c67
-rw-r--r--lib/libc/gen/pw_scan.c205
-rw-r--r--lib/libc/gen/pw_scan.h40
-rw-r--r--lib/libc/gen/pwcache.397
-rw-r--r--lib/libc/gen/pwcache.c117
-rw-r--r--lib/libc/gen/raise.377
-rw-r--r--lib/libc/gen/raise.c51
-rw-r--r--lib/libc/gen/rand48.3184
-rw-r--r--lib/libc/gen/rand48.h32
-rw-r--r--lib/libc/gen/readdir.c135
-rw-r--r--lib/libc/gen/readpassphrase.3191
-rw-r--r--lib/libc/gen/readpassphrase.c178
-rw-r--r--lib/libc/gen/rewinddir.c52
-rw-r--r--lib/libc/gen/rfork_thread.379
-rw-r--r--lib/libc/gen/scandir.3109
-rw-r--r--lib/libc/gen/scandir.c150
-rw-r--r--lib/libc/gen/seed48.c39
-rw-r--r--lib/libc/gen/seekdir.c63
-rw-r--r--lib/libc/gen/sem.c361
-rw-r--r--lib/libc/gen/sem_destroy.388
-rw-r--r--lib/libc/gen/sem_getvalue.381
-rw-r--r--lib/libc/gen/sem_init.3108
-rw-r--r--lib/libc/gen/sem_open.3227
-rw-r--r--lib/libc/gen/sem_post.378
-rw-r--r--lib/libc/gen/sem_wait.394
-rw-r--r--lib/libc/gen/semctl.c57
-rw-r--r--lib/libc/gen/setdomainname.c55
-rw-r--r--lib/libc/gen/sethostname.c55
-rw-r--r--lib/libc/gen/setjmp.3176
-rw-r--r--lib/libc/gen/setjmperr.c57
-rw-r--r--lib/libc/gen/setmode.3118
-rw-r--r--lib/libc/gen/setmode.c450
-rw-r--r--lib/libc/gen/setproctitle.3121
-rw-r--r--lib/libc/gen/setproctitle.c176
-rw-r--r--lib/libc/gen/setprogname.c19
-rw-r--r--lib/libc/gen/shm_open.3192
-rw-r--r--lib/libc/gen/siginterrupt.3124
-rw-r--r--lib/libc/gen/siginterrupt.c67
-rw-r--r--lib/libc/gen/siglist.c112
-rw-r--r--lib/libc/gen/signal.3281
-rw-r--r--lib/libc/gen/signal.c65
-rw-r--r--lib/libc/gen/sigsetops.3121
-rw-r--r--lib/libc/gen/sigsetops.c106
-rw-r--r--lib/libc/gen/sleep.387
-rw-r--r--lib/libc/gen/sleep.c72
-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.3135
-rw-r--r--lib/libc/gen/stringlist.c125
-rw-r--r--lib/libc/gen/strtofflags.399
-rw-r--r--lib/libc/gen/strtofflags.c159
-rw-r--r--lib/libc/gen/swapcontext.c55
-rw-r--r--lib/libc/gen/sysconf.3212
-rw-r--r--lib/libc/gen/sysconf.c582
-rw-r--r--lib/libc/gen/sysctl.3879
-rw-r--r--lib/libc/gen/sysctl.c187
-rw-r--r--lib/libc/gen/sysctlbyname.c39
-rw-r--r--lib/libc/gen/sysctlnametomib.c55
-rw-r--r--lib/libc/gen/syslog.3299
-rw-r--r--lib/libc/gen/syslog.c439
-rw-r--r--lib/libc/gen/tcgetpgrp.382
-rw-r--r--lib/libc/gen/tcsendbreak.3157
-rw-r--r--lib/libc/gen/tcsetattr.3333
-rw-r--r--lib/libc/gen/tcsetpgrp.399
-rw-r--r--lib/libc/gen/telldir.c133
-rw-r--r--lib/libc/gen/telldir.h66
-rw-r--r--lib/libc/gen/termios.c245
-rw-r--r--lib/libc/gen/time.3104
-rw-r--r--lib/libc/gen/time.c57
-rw-r--r--lib/libc/gen/times.3144
-rw-r--r--lib/libc/gen/times.c71
-rw-r--r--lib/libc/gen/timezone.373
-rw-r--r--lib/libc/gen/timezone.c137
-rw-r--r--lib/libc/gen/tls.c317
-rw-r--r--lib/libc/gen/ttyname.3161
-rw-r--r--lib/libc/gen/ttyname.c124
-rw-r--r--lib/libc/gen/ttyslot.c70
-rw-r--r--lib/libc/gen/tzset.3342
-rw-r--r--lib/libc/gen/ualarm.3101
-rw-r--r--lib/libc/gen/ualarm.c67
-rw-r--r--lib/libc/gen/ucontext.3107
-rw-r--r--lib/libc/gen/ulimit.398
-rw-r--r--lib/libc/gen/ulimit.c68
-rw-r--r--lib/libc/gen/uname.3121
-rw-r--r--lib/libc/gen/uname.c51
-rw-r--r--lib/libc/gen/unvis.3204
-rw-r--r--lib/libc/gen/unvis.c297
-rw-r--r--lib/libc/gen/usleep.384
-rw-r--r--lib/libc/gen/usleep.c57
-rw-r--r--lib/libc/gen/utime.396
-rw-r--r--lib/libc/gen/utime.c59
-rw-r--r--lib/libc/gen/valloc.381
-rw-r--r--lib/libc/gen/valloc.c52
-rw-r--r--lib/libc/gen/vis.3312
-rw-r--r--lib/libc/gen/vis.c205
-rw-r--r--lib/libc/gen/wait.c54
-rw-r--r--lib/libc/gen/wait3.c54
-rw-r--r--lib/libc/gen/waitpid.c54
-rw-r--r--lib/libc/gen/wordexp.3206
-rw-r--r--lib/libc/gen/wordexp.c316
-rw-r--r--lib/libc/gmon/Makefile.inc23
-rw-r--r--lib/libc/gmon/Symbol.map13
-rw-r--r--lib/libc/gmon/gmon.c267
-rw-r--r--lib/libc/gmon/mcount.c325
-rw-r--r--lib/libc/gmon/moncontrol.3114
-rw-r--r--lib/libc/i386/Makefile.inc6
-rw-r--r--lib/libc/i386/SYS.h61
-rw-r--r--lib/libc/i386/Symbol.map71
-rw-r--r--lib/libc/i386/_fpmath.h49
-rw-r--r--lib/libc/i386/arith.h15
-rw-r--r--lib/libc/i386/gen/Makefile.inc6
-rw-r--r--lib/libc/i386/gen/_ctx_start.S50
-rw-r--r--lib/libc/i386/gen/_set_tp.c40
-rw-r--r--lib/libc/i386/gen/_setjmp.S83
-rw-r--r--lib/libc/i386/gen/alloca.S62
-rw-r--r--lib/libc/i386/gen/fabs.S46
-rw-r--r--lib/libc/i386/gen/flt_rounds.c25
-rw-r--r--lib/libc/i386/gen/infinity.c14
-rw-r--r--lib/libc/i386/gen/ldexp.c68
-rw-r--r--lib/libc/i386/gen/makecontext.c163
-rw-r--r--lib/libc/i386/gen/modf.S76
-rw-r--r--lib/libc/i386/gen/rfork_thread.S117
-rw-r--r--lib/libc/i386/gen/setjmp.S103
-rw-r--r--lib/libc/i386/gen/signalcontext.c79
-rw-r--r--lib/libc/i386/gen/sigsetjmp.S114
-rw-r--r--lib/libc/i386/net/Makefile.inc4
-rw-r--r--lib/libc/i386/net/htonl.S50
-rw-r--r--lib/libc/i386/net/htons.S50
-rw-r--r--lib/libc/i386/net/ntohl.S50
-rw-r--r--lib/libc/i386/net/ntohs.S52
-rw-r--r--lib/libc/i386/stdlib/Makefile.inc4
-rw-r--r--lib/libc/i386/stdlib/abs.S50
-rw-r--r--lib/libc/i386/stdlib/div.S41
-rw-r--r--lib/libc/i386/stdlib/labs.S50
-rw-r--r--lib/libc/i386/stdlib/ldiv.S41
-rw-r--r--lib/libc/i386/string/Makefile.inc7
-rw-r--r--lib/libc/i386/string/bcmp.S63
-rw-r--r--lib/libc/i386/string/bcopy.S103
-rw-r--r--lib/libc/i386/string/bzero.S81
-rw-r--r--lib/libc/i386/string/ffs.S53
-rw-r--r--lib/libc/i386/string/index.S63
-rw-r--r--lib/libc/i386/string/memchr.S58
-rw-r--r--lib/libc/i386/string/memcmp.S75
-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.S89
-rw-r--r--lib/libc/i386/string/rindex.S64
-rw-r--r--lib/libc/i386/string/strcat.S100
-rw-r--r--lib/libc/i386/string/strchr.S63
-rw-r--r--lib/libc/i386/string/strcmp.S119
-rw-r--r--lib/libc/i386/string/strcpy.S89
-rw-r--r--lib/libc/i386/string/strlen.S53
-rw-r--r--lib/libc/i386/string/strncmp.S166
-rw-r--r--lib/libc/i386/string/strrchr.S64
-rw-r--r--lib/libc/i386/string/swab.S99
-rw-r--r--lib/libc/i386/string/wcschr.S76
-rw-r--r--lib/libc/i386/string/wcscmp.S79
-rw-r--r--lib/libc/i386/string/wcslen.S68
-rw-r--r--lib/libc/i386/string/wmemchr.S105
-rw-r--r--lib/libc/i386/sys/Makefile.inc26
-rw-r--r--lib/libc/i386/sys/Ovfork.S58
-rw-r--r--lib/libc/i386/sys/brk.S90
-rw-r--r--lib/libc/i386/sys/cerror.S69
-rw-r--r--lib/libc/i386/sys/exect.S55
-rw-r--r--lib/libc/i386/sys/getcontext.S50
-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.2143
-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/pipe.S50
-rw-r--r--lib/libc/i386/sys/ptrace.S61
-rw-r--r--lib/libc/i386/sys/reboot.S46
-rw-r--r--lib/libc/i386/sys/sbrk.S94
-rw-r--r--lib/libc/i386/sys/setlogin.S58
-rw-r--r--lib/libc/i386/sys/sigreturn.S50
-rw-r--r--lib/libc/i386/sys/syscall.S56
-rw-r--r--lib/libc/ia64/Makefile.inc9
-rw-r--r--lib/libc/ia64/SYS.h77
-rw-r--r--lib/libc/ia64/Symbol.map77
-rw-r--r--lib/libc/ia64/_fpmath.h71
-rw-r--r--lib/libc/ia64/arith.h37
-rw-r--r--lib/libc/ia64/gen/Makefile.inc11
-rw-r--r--lib/libc/ia64/gen/__divdf3.S142
-rw-r--r--lib/libc/ia64/gen/__divdi3.S143
-rw-r--r--lib/libc/ia64/gen/__divsf3.S116
-rw-r--r--lib/libc/ia64/gen/__divsi3.S125
-rw-r--r--lib/libc/ia64/gen/__moddi3.S160
-rw-r--r--lib/libc/ia64/gen/__modsi3.S132
-rw-r--r--lib/libc/ia64/gen/__udivdi3.S144
-rw-r--r--lib/libc/ia64/gen/__udivsi3.S125
-rw-r--r--lib/libc/ia64/gen/__umoddi3.S156
-rw-r--r--lib/libc/ia64/gen/__umodsi3.S132
-rw-r--r--lib/libc/ia64/gen/_mcount.S75
-rw-r--r--lib/libc/ia64/gen/_set_tp.c35
-rw-r--r--lib/libc/ia64/gen/_setjmp.S310
-rw-r--r--lib/libc/ia64/gen/fabs.S33
-rw-r--r--lib/libc/ia64/gen/flt_rounds.c25
-rw-r--r--lib/libc/ia64/gen/fpgetmask.c40
-rw-r--r--lib/libc/ia64/gen/fpgetround.c39
-rw-r--r--lib/libc/ia64/gen/fpsetmask.c44
-rw-r--r--lib/libc/ia64/gen/fpsetround.c43
-rw-r--r--lib/libc/ia64/gen/infinity.c48
-rw-r--r--lib/libc/ia64/gen/makecontext.c123
-rw-r--r--lib/libc/ia64/gen/modf.c106
-rw-r--r--lib/libc/ia64/gen/setjmp.S82
-rw-r--r--lib/libc/ia64/gen/signalcontext.c123
-rw-r--r--lib/libc/ia64/gen/sigsetjmp.S66
-rw-r--r--lib/libc/ia64/gen/unwind.c129
-rw-r--r--lib/libc/ia64/net/Makefile.inc3
-rw-r--r--lib/libc/ia64/net/byte_swap_2.S48
-rw-r--r--lib/libc/ia64/net/byte_swap_4.S48
-rw-r--r--lib/libc/ia64/net/htonl.S36
-rw-r--r--lib/libc/ia64/net/htons.S36
-rw-r--r--lib/libc/ia64/net/ntohl.S36
-rw-r--r--lib/libc/ia64/net/ntohs.S36
-rw-r--r--lib/libc/ia64/stdlib/Makefile.inc3
-rw-r--r--lib/libc/ia64/string/Makefile.inc3
-rw-r--r--lib/libc/ia64/string/bcopy.S95
-rw-r--r--lib/libc/ia64/string/bzero.S81
-rw-r--r--lib/libc/ia64/string/ffs.S99
-rw-r--r--lib/libc/ia64/string/memcpy.S36
-rw-r--r--lib/libc/ia64/string/memmove.S36
-rw-r--r--lib/libc/ia64/sys/Makefile.inc11
-rw-r--r--lib/libc/ia64/sys/Ovfork.S37
-rw-r--r--lib/libc/ia64/sys/brk.S57
-rw-r--r--lib/libc/ia64/sys/cerror.S46
-rw-r--r--lib/libc/ia64/sys/exect.S38
-rw-r--r--lib/libc/ia64/sys/fork.S37
-rw-r--r--lib/libc/ia64/sys/getcontext.S39
-rw-r--r--lib/libc/ia64/sys/pipe.S47
-rw-r--r--lib/libc/ia64/sys/ptrace.S41
-rw-r--r--lib/libc/ia64/sys/sbrk.S63
-rw-r--r--lib/libc/ia64/sys/setlogin.S42
-rw-r--r--lib/libc/ia64/sys/sigreturn.S41
-rw-r--r--lib/libc/ia64/sys/swapcontext.S39
-rw-r--r--lib/libc/include/fpmath.h66
-rw-r--r--lib/libc/include/libc_private.h175
-rw-r--r--lib/libc/include/namespace.h259
-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.h22
-rw-r--r--lib/libc/include/reentrant.h135
-rw-r--r--lib/libc/include/spinlock.h73
-rw-r--r--lib/libc/include/un-namespace.h249
-rw-r--r--lib/libc/inet/Makefile.inc11
-rw-r--r--lib/libc/inet/Symbol.map34
-rw-r--r--lib/libc/inet/inet_addr.c13
-rw-r--r--lib/libc/inet/inet_cidr_pton.c6
-rw-r--r--lib/libc/inet/inet_lnaof.c13
-rw-r--r--lib/libc/inet/inet_makeaddr.c11
-rw-r--r--lib/libc/inet/inet_net_ntop.c25
-rw-r--r--lib/libc/inet/inet_net_pton.c17
-rw-r--r--lib/libc/inet/inet_neta.c13
-rw-r--r--lib/libc/inet/inet_netof.c13
-rw-r--r--lib/libc/inet/inet_network.c21
-rw-r--r--lib/libc/inet/inet_ntoa.c9
-rw-r--r--lib/libc/inet/inet_ntop.c46
-rw-r--r--lib/libc/inet/inet_pton.c26
-rw-r--r--lib/libc/inet/nsap_addr.c11
-rw-r--r--lib/libc/isc/Makefile.inc6
-rw-r--r--lib/libc/isc/ev_streams.c10
-rw-r--r--lib/libc/isc/ev_timers.c16
-rw-r--r--lib/libc/isc/eventlib_p.h9
-rw-r--r--lib/libc/locale/Makefile.inc59
-rw-r--r--lib/libc/locale/Symbol.map102
-rw-r--r--lib/libc/locale/big5.551
-rw-r--r--lib/libc/locale/big5.c172
-rw-r--r--lib/libc/locale/btowc.379
-rw-r--r--lib/libc/locale/btowc.c53
-rw-r--r--lib/libc/locale/collate.c298
-rw-r--r--lib/libc/locale/collate.h69
-rw-r--r--lib/libc/locale/collcmp.c44
-rw-r--r--lib/libc/locale/ctype.3155
-rw-r--r--lib/libc/locale/digittoint.363
-rw-r--r--lib/libc/locale/euc.5138
-rw-r--r--lib/libc/locale/euc.c265
-rw-r--r--lib/libc/locale/fix_grouping.c86
-rw-r--r--lib/libc/locale/gb18030.578
-rw-r--r--lib/libc/locale/gb18030.c218
-rw-r--r--lib/libc/locale/gb2312.557
-rw-r--r--lib/libc/locale/gb2312.c154
-rw-r--r--lib/libc/locale/gbk.563
-rw-r--r--lib/libc/locale/gbk.c169
-rw-r--r--lib/libc/locale/isalnum.3107
-rw-r--r--lib/libc/locale/isalpha.3105
-rw-r--r--lib/libc/locale/isascii.357
-rw-r--r--lib/libc/locale/isblank.388
-rw-r--r--lib/libc/locale/iscntrl.395
-rw-r--r--lib/libc/locale/isctype.c233
-rw-r--r--lib/libc/locale/isdigit.3106
-rw-r--r--lib/libc/locale/isgraph.3110
-rw-r--r--lib/libc/locale/isideogram.357
-rw-r--r--lib/libc/locale/islower.395
-rw-r--r--lib/libc/locale/isphonogram.357
-rw-r--r--lib/libc/locale/isprint.3108
-rw-r--r--lib/libc/locale/ispunct.3100
-rw-r--r--lib/libc/locale/isrune.363
-rw-r--r--lib/libc/locale/isspace.392
-rw-r--r--lib/libc/locale/isspecial.356
-rw-r--r--lib/libc/locale/isupper.395
-rw-r--r--lib/libc/locale/iswalnum.3162
-rw-r--r--lib/libc/locale/iswctype.c214
-rw-r--r--lib/libc/locale/isxdigit.3106
-rw-r--r--lib/libc/locale/ldpart.c166
-rw-r--r--lib/libc/locale/ldpart.h39
-rw-r--r--lib/libc/locale/lmessages.c91
-rw-r--r--lib/libc/locale/lmessages.h42
-rw-r--r--lib/libc/locale/lmonetary.c192
-rw-r--r--lib/libc/locale/lmonetary.h59
-rw-r--r--lib/libc/locale/lnumeric.c93
-rw-r--r--lib/libc/locale/lnumeric.h41
-rw-r--r--lib/libc/locale/localeconv.3226
-rw-r--r--lib/libc/locale/localeconv.c112
-rw-r--r--lib/libc/locale/mblen.3110
-rw-r--r--lib/libc/locale/mblen.c50
-rw-r--r--lib/libc/locale/mblocal.h61
-rw-r--r--lib/libc/locale/mbrlen.3145
-rw-r--r--lib/libc/locale/mbrlen.c41
-rw-r--r--lib/libc/locale/mbrtowc.3139
-rw-r--r--lib/libc/locale/mbrtowc.c42
-rw-r--r--lib/libc/locale/mbsinit.367
-rw-r--r--lib/libc/locale/mbsinit.c38
-rw-r--r--lib/libc/locale/mbsnrtowcs.c91
-rw-r--r--lib/libc/locale/mbsrtowcs.3135
-rw-r--r--lib/libc/locale/mbsrtowcs.c45
-rw-r--r--lib/libc/locale/mbstowcs.391
-rw-r--r--lib/libc/locale/mbstowcs.c43
-rw-r--r--lib/libc/locale/mbtowc.3118
-rw-r--r--lib/libc/locale/mbtowc.c50
-rw-r--r--lib/libc/locale/mskanji.570
-rw-r--r--lib/libc/locale/mskanji.c157
-rw-r--r--lib/libc/locale/multibyte.3146
-rw-r--r--lib/libc/locale/nextwctype.367
-rw-r--r--lib/libc/locale/nextwctype.c90
-rw-r--r--lib/libc/locale/nl_langinfo.390
-rw-r--r--lib/libc/locale/nl_langinfo.c175
-rw-r--r--lib/libc/locale/nomacros.c12
-rw-r--r--lib/libc/locale/none.c193
-rw-r--r--lib/libc/locale/rpmatch.366
-rw-r--r--lib/libc/locale/rpmatch.c55
-rw-r--r--lib/libc/locale/rune.c290
-rw-r--r--lib/libc/locale/runefile.h61
-rw-r--r--lib/libc/locale/runetype.c70
-rw-r--r--lib/libc/locale/setlocale.3178
-rw-r--r--lib/libc/locale/setlocale.c336
-rw-r--r--lib/libc/locale/setlocale.h40
-rw-r--r--lib/libc/locale/setrunelocale.c177
-rw-r--r--lib/libc/locale/table.c253
-rw-r--r--lib/libc/locale/toascii.373
-rw-r--r--lib/libc/locale/tolower.383
-rw-r--r--lib/libc/locale/tolower.c68
-rw-r--r--lib/libc/locale/toupper.383
-rw-r--r--lib/libc/locale/toupper.c68
-rw-r--r--lib/libc/locale/towlower.370
-rw-r--r--lib/libc/locale/towupper.370
-rw-r--r--lib/libc/locale/utf8.5106
-rw-r--r--lib/libc/locale/utf8.c421
-rw-r--r--lib/libc/locale/wcrtomb.3105
-rw-r--r--lib/libc/locale/wcrtomb.c41
-rw-r--r--lib/libc/locale/wcsftime.366
-rw-r--r--lib/libc/locale/wcsftime.c105
-rw-r--r--lib/libc/locale/wcsnrtombs.c111
-rw-r--r--lib/libc/locale/wcsrtombs.3134
-rw-r--r--lib/libc/locale/wcsrtombs.c45
-rw-r--r--lib/libc/locale/wcstod.373
-rw-r--r--lib/libc/locale/wcstod.c94
-rw-r--r--lib/libc/locale/wcstof.c70
-rw-r--r--lib/libc/locale/wcstoimax.c128
-rw-r--r--lib/libc/locale/wcstol.394
-rw-r--r--lib/libc/locale/wcstol.c121
-rw-r--r--lib/libc/locale/wcstold.c70
-rw-r--r--lib/libc/locale/wcstoll.c127
-rw-r--r--lib/libc/locale/wcstombs.394
-rw-r--r--lib/libc/locale/wcstombs.c43
-rw-r--r--lib/libc/locale/wcstoul.c119
-rw-r--r--lib/libc/locale/wcstoull.c126
-rw-r--r--lib/libc/locale/wcstoumax.c126
-rw-r--r--lib/libc/locale/wctob.c45
-rw-r--r--lib/libc/locale/wctomb.3112
-rw-r--r--lib/libc/locale/wctomb.c49
-rw-r--r--lib/libc/locale/wctrans.3122
-rw-r--r--lib/libc/locale/wctrans.c80
-rw-r--r--lib/libc/locale/wctype.3119
-rw-r--r--lib/libc/locale/wctype.c74
-rw-r--r--lib/libc/locale/wcwidth.387
-rw-r--r--lib/libc/locale/wcwidth.c54
-rw-r--r--lib/libc/nameser/Makefile.inc8
-rw-r--r--lib/libc/nameser/Symbol.map28
-rw-r--r--lib/libc/nameser/ns_print.c11
-rw-r--r--lib/libc/nameser/ns_samedomain.c4
-rw-r--r--lib/libc/net/Makefile.inc126
-rw-r--r--lib/libc/net/Symbol.map143
-rw-r--r--lib/libc/net/addr2ascii.3235
-rw-r--r--lib/libc/net/addr2ascii.c95
-rw-r--r--lib/libc/net/ascii2addr.c75
-rw-r--r--lib/libc/net/base64.c315
-rw-r--r--lib/libc/net/byteorder.390
-rw-r--r--lib/libc/net/ether_addr.c231
-rw-r--r--lib/libc/net/ethers.3201
-rw-r--r--lib/libc/net/eui64.3230
-rw-r--r--lib/libc/net/eui64.c311
-rw-r--r--lib/libc/net/gai_strerror.390
-rw-r--r--lib/libc/net/gai_strerror.c60
-rw-r--r--lib/libc/net/getaddrinfo.3434
-rw-r--r--lib/libc/net/getaddrinfo.c2772
-rw-r--r--lib/libc/net/gethostbydns.c762
-rw-r--r--lib/libc/net/gethostbyht.c335
-rw-r--r--lib/libc/net/gethostbyname.3379
-rw-r--r--lib/libc/net/gethostbynis.c348
-rw-r--r--lib/libc/net/gethostnamadr.c725
-rw-r--r--lib/libc/net/getifaddrs.3167
-rw-r--r--lib/libc/net/getifaddrs.c418
-rw-r--r--lib/libc/net/getifmaddrs.3116
-rw-r--r--lib/libc/net/getifmaddrs.c203
-rw-r--r--lib/libc/net/getipnodebyname.3478
-rw-r--r--lib/libc/net/getnameinfo.3270
-rw-r--r--lib/libc/net/getnameinfo.c345
-rw-r--r--lib/libc/net/getnetbydns.c465
-rw-r--r--lib/libc/net/getnetbyht.c284
-rw-r--r--lib/libc/net/getnetbynis.c255
-rw-r--r--lib/libc/net/getnetent.3176
-rw-r--r--lib/libc/net/getnetnamadr.c450
-rw-r--r--lib/libc/net/getproto.c145
-rw-r--r--lib/libc/net/getprotoent.3150
-rw-r--r--lib/libc/net/getprotoent.c555
-rw-r--r--lib/libc/net/getprotoname.c153
-rw-r--r--lib/libc/net/getservent.3159
-rw-r--r--lib/libc/net/getservent.c1213
-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.c99
-rw-r--r--lib/libc/net/inet.3303
-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.3224
-rw-r--r--lib/libc/net/inet6_rthdr_space.357
-rw-r--r--lib/libc/net/inet_net.3167
-rw-r--r--lib/libc/net/ip6opt.c610
-rw-r--r--lib/libc/net/linkaddr.3144
-rw-r--r--lib/libc/net/linkaddr.c160
-rw-r--r--lib/libc/net/map_v4v6.c123
-rw-r--r--lib/libc/net/name6.c2354
-rw-r--r--lib/libc/net/netdb_private.h145
-rw-r--r--lib/libc/net/nscache.c438
-rw-r--r--lib/libc/net/nscachedcli.c576
-rw-r--r--lib/libc/net/nsdispatch.3250
-rw-r--r--lib/libc/net/nsdispatch.c715
-rw-r--r--lib/libc/net/nslexer.l119
-rw-r--r--lib/libc/net/nsparser.y179
-rw-r--r--lib/libc/net/nss_backends.h43
-rw-r--r--lib/libc/net/nss_compat.c278
-rw-r--r--lib/libc/net/rcmd.3302
-rw-r--r--lib/libc/net/rcmd.c765
-rw-r--r--lib/libc/net/rcmdsh.3120
-rw-r--r--lib/libc/net/rcmdsh.c170
-rw-r--r--lib/libc/net/recv.c54
-rw-r--r--lib/libc/net/res_config.h6
-rw-r--r--lib/libc/net/res_mkupdate.c406
-rw-r--r--lib/libc/net/res_update.c522
-rw-r--r--lib/libc/net/resolver.3438
-rw-r--r--lib/libc/net/rthdr.c442
-rw-r--r--lib/libc/net/send.c54
-rw-r--r--lib/libc/net/sockatmark.3123
-rw-r--r--lib/libc/net/sockatmark.c36
-rw-r--r--lib/libc/net/vars.c45
-rw-r--r--lib/libc/nls/C.msg249
-rw-r--r--lib/libc/nls/Makefile.inc10
-rw-r--r--lib/libc/nls/Symbol.map7
-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/ko_KR.UTF-8.msg249
-rw-r--r--lib/libc/nls/ko_KR.eucKR.msg249
-rw-r--r--lib/libc/nls/msgcat.c307
-rw-r--r--lib/libc/nls/pl_PL.ISO8859-2.msg249
-rw-r--r--lib/libc/nls/ru_RU.KOI8-R.msg256
-rw-r--r--lib/libc/posix1e/Makefile.inc89
-rw-r--r--lib/libc/posix1e/Symbol.map68
-rw-r--r--lib/libc/posix1e/acl.3244
-rw-r--r--lib/libc/posix1e/acl_add_perm.389
-rw-r--r--lib/libc/posix1e/acl_calc_mask.398
-rw-r--r--lib/libc/posix1e/acl_calc_mask.c119
-rw-r--r--lib/libc/posix1e/acl_clear_perms.379
-rw-r--r--lib/libc/posix1e/acl_copy.c72
-rw-r--r--lib/libc/posix1e/acl_copy_entry.385
-rw-r--r--lib/libc/posix1e/acl_create_entry.382
-rw-r--r--lib/libc/posix1e/acl_delete.3140
-rw-r--r--lib/libc/posix1e/acl_delete.c75
-rw-r--r--lib/libc/posix1e/acl_delete_entry.383
-rw-r--r--lib/libc/posix1e/acl_delete_entry.c79
-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.c98
-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.c238
-rw-r--r--lib/libc/posix1e/acl_get.3156
-rw-r--r--lib/libc/posix1e/acl_get.c215
-rw-r--r--lib/libc/posix1e/acl_get_entry.3145
-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_init.3111
-rw-r--r--lib/libc/posix1e/acl_init.c76
-rw-r--r--lib/libc/posix1e/acl_perm.c98
-rw-r--r--lib/libc/posix1e/acl_set.3142
-rw-r--r--lib/libc/posix1e/acl_set.c199
-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.381
-rw-r--r--lib/libc/posix1e/acl_size.c43
-rw-r--r--lib/libc/posix1e/acl_support.c437
-rw-r--r--lib/libc/posix1e/acl_support.h49
-rw-r--r--lib/libc/posix1e/acl_to_text.3141
-rw-r--r--lib/libc/posix1e/acl_to_text.c237
-rw-r--r--lib/libc/posix1e/acl_valid.3170
-rw-r--r--lib/libc/posix1e/acl_valid.c136
-rw-r--r--lib/libc/posix1e/extattr.3100
-rw-r--r--lib/libc/posix1e/extattr.c77
-rw-r--r--lib/libc/posix1e/mac.3187
-rw-r--r--lib/libc/posix1e/mac.c448
-rw-r--r--lib/libc/posix1e/mac.conf.5123
-rw-r--r--lib/libc/posix1e/mac_exec.c45
-rw-r--r--lib/libc/posix1e/mac_free.398
-rw-r--r--lib/libc/posix1e/mac_get.3151
-rw-r--r--lib/libc/posix1e/mac_get.c86
-rw-r--r--lib/libc/posix1e/mac_is_present.387
-rw-r--r--lib/libc/posix1e/mac_is_present_np.387
-rw-r--r--lib/libc/posix1e/mac_prepare.3126
-rw-r--r--lib/libc/posix1e/mac_set.3148
-rw-r--r--lib/libc/posix1e/mac_set.c68
-rw-r--r--lib/libc/posix1e/mac_text.3116
-rw-r--r--lib/libc/posix1e/posix1e.3134
-rw-r--r--lib/libc/powerpc/Makefile.inc5
-rw-r--r--lib/libc/powerpc/SYS.h75
-rw-r--r--lib/libc/powerpc/Symbol.map60
-rw-r--r--lib/libc/powerpc/_fpmath.h49
-rw-r--r--lib/libc/powerpc/arith.h16
-rw-r--r--lib/libc/powerpc/gen/Makefile.inc9
-rw-r--r--lib/libc/powerpc/gen/_ctx_start.S43
-rw-r--r--lib/libc/powerpc/gen/_set_tp.c35
-rw-r--r--lib/libc/powerpc/gen/_setjmp.S71
-rw-r--r--lib/libc/powerpc/gen/fabs.S35
-rw-r--r--lib/libc/powerpc/gen/flt_rounds.c54
-rw-r--r--lib/libc/powerpc/gen/fpgetmask.c53
-rw-r--r--lib/libc/powerpc/gen/fpgetround.c53
-rw-r--r--lib/libc/powerpc/gen/fpgetsticky.c59
-rw-r--r--lib/libc/powerpc/gen/fpsetmask.c57
-rw-r--r--lib/libc/powerpc/gen/fpsetround.c57
-rw-r--r--lib/libc/powerpc/gen/infinity.c17
-rw-r--r--lib/libc/powerpc/gen/makecontext.c120
-rw-r--r--lib/libc/powerpc/gen/modf.c107
-rw-r--r--lib/libc/powerpc/gen/setjmp.S91
-rw-r--r--lib/libc/powerpc/gen/signalcontext.c103
-rw-r--r--lib/libc/powerpc/gen/sigsetjmp.S97
-rw-r--r--lib/libc/powerpc/gen/syncicache.c100
-rw-r--r--lib/libc/powerpc/net/Makefile.inc4
-rw-r--r--lib/libc/powerpc/net/htonl.S38
-rw-r--r--lib/libc/powerpc/net/htons.S38
-rw-r--r--lib/libc/powerpc/net/ntohl.S38
-rw-r--r--lib/libc/powerpc/net/ntohs.S40
-rw-r--r--lib/libc/powerpc/sys/Makefile.inc11
-rw-r--r--lib/libc/powerpc/sys/brk.S73
-rw-r--r--lib/libc/powerpc/sys/cerror.S57
-rw-r--r--lib/libc/powerpc/sys/exect.S39
-rw-r--r--lib/libc/powerpc/sys/pipe.S43
-rw-r--r--lib/libc/powerpc/sys/ptrace.S58
-rw-r--r--lib/libc/powerpc/sys/sbrk.S70
-rw-r--r--lib/libc/powerpc/sys/setlogin.S49
-rw-r--r--lib/libc/quad/Makefile.inc21
-rw-r--r--lib/libc/quad/Symbol.map34
-rw-r--r--lib/libc/quad/TESTS/Makefile11
-rw-r--r--lib/libc/quad/TESTS/divrem.c80
-rw-r--r--lib/libc/quad/TESTS/mul.c76
-rw-r--r--lib/libc/quad/adddi3.c62
-rw-r--r--lib/libc/quad/anddi3.c60
-rw-r--r--lib/libc/quad/ashldi3.c68
-rw-r--r--lib/libc/quad/ashrdi3.c77
-rw-r--r--lib/libc/quad/cmpdi2.c61
-rw-r--r--lib/libc/quad/divdi3.c67
-rw-r--r--lib/libc/quad/fixdfdi.c64
-rw-r--r--lib/libc/quad/fixsfdi.c65
-rw-r--r--lib/libc/quad/fixunsdfdi.c98
-rw-r--r--lib/libc/quad/fixunssfdi.c102
-rw-r--r--lib/libc/quad/floatdidf.c76
-rw-r--r--lib/libc/quad/floatdisf.c78
-rw-r--r--lib/libc/quad/floatunsdidf.c61
-rw-r--r--lib/libc/quad/iordi3.c60
-rw-r--r--lib/libc/quad/lshldi3.c68
-rw-r--r--lib/libc/quad/lshrdi3.c67
-rw-r--r--lib/libc/quad/moddi3.c69
-rw-r--r--lib/libc/quad/muldi3.c248
-rw-r--r--lib/libc/quad/negdi2.c59
-rw-r--r--lib/libc/quad/notdi2.c60
-rw-r--r--lib/libc/quad/qdivrem.c281
-rw-r--r--lib/libc/quad/quad.h107
-rw-r--r--lib/libc/quad/subdi3.c61
-rw-r--r--lib/libc/quad/ucmpdi2.c60
-rw-r--r--lib/libc/quad/udivdi3.c55
-rw-r--r--lib/libc/quad/umoddi3.c57
-rw-r--r--lib/libc/quad/xordi3.c60
-rw-r--r--lib/libc/regex/COPYRIGHT56
-rw-r--r--lib/libc/regex/Makefile.inc17
-rw-r--r--lib/libc/regex/Symbol.map8
-rw-r--r--lib/libc/regex/WHATSNEW94
-rw-r--r--lib/libc/regex/cname.h142
-rw-r--r--lib/libc/regex/engine.c1197
-rw-r--r--lib/libc/regex/grot/Makefile98
-rw-r--r--lib/libc/regex/grot/debug.c212
-rw-r--r--lib/libc/regex/grot/main.c513
-rwxr-xr-xlib/libc/regex/grot/mkh77
-rw-r--r--lib/libc/regex/grot/split.c319
-rw-r--r--lib/libc/regex/grot/tests450
-rw-r--r--lib/libc/regex/re_format.7476
-rw-r--r--lib/libc/regex/regcomp.c1844
-rw-r--r--lib/libc/regex/regerror.c181
-rw-r--r--lib/libc/regex/regex.3731
-rw-r--r--lib/libc/regex/regex2.h196
-rw-r--r--lib/libc/regex/regexec.c244
-rw-r--r--lib/libc/regex/regfree.c94
-rw-r--r--lib/libc/regex/utils.h58
-rw-r--r--lib/libc/resolv/Makefile.inc9
-rw-r--r--lib/libc/resolv/Symbol.map105
-rw-r--r--lib/libc/resolv/h_errno.c49
-rw-r--r--lib/libc/resolv/herror.c11
-rw-r--r--lib/libc/resolv/mtctxres.c14
-rw-r--r--lib/libc/resolv/res_comp.c11
-rw-r--r--lib/libc/resolv/res_data.c41
-rw-r--r--lib/libc/resolv/res_debug.c27
-rw-r--r--lib/libc/resolv/res_init.c87
-rw-r--r--lib/libc/resolv/res_mkquery.c14
-rw-r--r--lib/libc/resolv/res_query.c55
-rw-r--r--lib/libc/resolv/res_send.c118
-rw-r--r--lib/libc/resolv/res_state.c96
-rw-r--r--lib/libc/rpc/DISCLAIMER31
-rw-r--r--lib/libc/rpc/LICENSE335
-rw-r--r--lib/libc/rpc/Makefile.inc178
-rw-r--r--lib/libc/rpc/PSD.doc/nfs.rfc.ms1374
-rw-r--r--lib/libc/rpc/PSD.doc/rpc.prog.ms2686
-rw-r--r--lib/libc/rpc/PSD.doc/rpc.rfc.ms1304
-rw-r--r--lib/libc/rpc/PSD.doc/rpcgen.ms1301
-rw-r--r--lib/libc/rpc/PSD.doc/stubs3
-rw-r--r--lib/libc/rpc/PSD.doc/xdr.nts.ms1968
-rw-r--r--lib/libc/rpc/PSD.doc/xdr.rfc.ms1060
-rw-r--r--lib/libc/rpc/README176
-rw-r--r--lib/libc/rpc/Symbol.map244
-rw-r--r--lib/libc/rpc/auth_des.c498
-rw-r--r--lib/libc/rpc/auth_none.c176
-rw-r--r--lib/libc/rpc/auth_time.c498
-rw-r--r--lib/libc/rpc/auth_unix.c373
-rw-r--r--lib/libc/rpc/authdes_prot.c93
-rw-r--r--lib/libc/rpc/authunix_prot.c76
-rw-r--r--lib/libc/rpc/bindresvport.3103
-rw-r--r--lib/libc/rpc/bindresvport.c161
-rw-r--r--lib/libc/rpc/clnt_bcast.c670
-rw-r--r--lib/libc/rpc/clnt_dg.c788
-rw-r--r--lib/libc/rpc/clnt_generic.c466
-rw-r--r--lib/libc/rpc/clnt_perror.c326
-rw-r--r--lib/libc/rpc/clnt_raw.c312
-rw-r--r--lib/libc/rpc/clnt_simple.c196
-rw-r--r--lib/libc/rpc/clnt_vc.c846
-rw-r--r--lib/libc/rpc/crypt_client.c101
-rw-r--r--lib/libc/rpc/des_crypt.3130
-rw-r--r--lib/libc/rpc/des_crypt.c154
-rw-r--r--lib/libc/rpc/des_soft.c71
-rw-r--r--lib/libc/rpc/getnetconfig.3222
-rw-r--r--lib/libc/rpc/getnetconfig.c702
-rw-r--r--lib/libc/rpc/getnetpath.3170
-rw-r--r--lib/libc/rpc/getnetpath.c273
-rw-r--r--lib/libc/rpc/getpublickey.c179
-rw-r--r--lib/libc/rpc/getrpcent.3109
-rw-r--r--lib/libc/rpc/getrpcent.c1048
-rw-r--r--lib/libc/rpc/getrpcport.336
-rw-r--r--lib/libc/rpc/getrpcport.c78
-rw-r--r--lib/libc/rpc/key_call.c474
-rw-r--r--lib/libc/rpc/key_prot_xdr.c176
-rw-r--r--lib/libc/rpc/mt_misc.c118
-rw-r--r--lib/libc/rpc/mt_misc.h66
-rw-r--r--lib/libc/rpc/netconfig.5132
-rw-r--r--lib/libc/rpc/netname.c153
-rw-r--r--lib/libc/rpc/netnamer.c335
-rw-r--r--lib/libc/rpc/pmap_clnt.c120
-rw-r--r--lib/libc/rpc/pmap_getmaps.c100
-rw-r--r--lib/libc/rpc/pmap_getport.c104
-rw-r--r--lib/libc/rpc/pmap_prot.c69
-rw-r--r--lib/libc/rpc/pmap_prot2.c143
-rw-r--r--lib/libc/rpc/pmap_rmt.c176
-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.c205
-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.h95
-rw-r--r--lib/libc/rpc/rpc_commondata.c48
-rw-r--r--lib/libc/rpc/rpc_dtablesize.c67
-rw-r--r--lib/libc/rpc/rpc_generic.c842
-rw-r--r--lib/libc/rpc/rpc_prot.c355
-rw-r--r--lib/libc/rpc/rpc_secure.3287
-rw-r--r--lib/libc/rpc/rpc_soc.31726
-rw-r--r--lib/libc/rpc/rpc_soc.c579
-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.c1353
-rw-r--r--lib/libc/rpc/rpcb_prot.c330
-rw-r--r--lib/libc/rpc/rpcb_st_xdr.c270
-rw-r--r--lib/libc/rpc/rpcbind.3194
-rw-r--r--lib/libc/rpc/rpcdname.c82
-rw-r--r--lib/libc/rpc/rtime.350
-rw-r--r--lib/libc/rpc/rtime.c160
-rw-r--r--lib/libc/rpc/svc.c750
-rw-r--r--lib/libc/rpc/svc_auth.c210
-rw-r--r--lib/libc/rpc/svc_auth_des.c538
-rw-r--r--lib/libc/rpc/svc_auth_unix.c156
-rw-r--r--lib/libc/rpc/svc_dg.c603
-rw-r--r--lib/libc/rpc/svc_generic.c311
-rw-r--r--lib/libc/rpc/svc_raw.c257
-rw-r--r--lib/libc/rpc/svc_run.c98
-rw-r--r--lib/libc/rpc/svc_simple.c309
-rw-r--r--lib/libc/rpc/svc_vc.c787
-rw-r--r--lib/libc/softfloat/Makefile.inc20
-rw-r--r--lib/libc/softfloat/README.NetBSD9
-rw-r--r--lib/libc/softfloat/README.txt40
-rw-r--r--lib/libc/softfloat/Symbol.map45
-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.c5500
-rw-r--r--lib/libc/softfloat/eqdf2.c22
-rw-r--r--lib/libc/softfloat/eqsf2.c22
-rw-r--r--lib/libc/softfloat/fpgetmask.c60
-rw-r--r--lib/libc/softfloat/fpgetround.c60
-rw-r--r--lib/libc/softfloat/fpgetsticky.c60
-rw-r--r--lib/libc/softfloat/fpsetmask.c63
-rw-r--r--lib/libc/softfloat/fpsetround.c63
-rw-r--r--lib/libc/softfloat/fpsetsticky.c63
-rw-r--r--lib/libc/softfloat/gedf2.c22
-rw-r--r--lib/libc/softfloat/gesf2.c22
-rw-r--r--lib/libc/softfloat/gtdf2.c22
-rw-r--r--lib/libc/softfloat/gtsf2.c22
-rw-r--r--lib/libc/softfloat/ledf2.c22
-rw-r--r--lib/libc/softfloat/lesf2.c22
-rw-r--r--lib/libc/softfloat/ltdf2.c22
-rw-r--r--lib/libc/softfloat/ltsf2.c22
-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/nesf2.c22
-rw-r--r--lib/libc/softfloat/softfloat-for-gcc.h43
-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-specialize490
-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.inc11
-rw-r--r--lib/libc/sparc64/SYS.h90
-rw-r--r--lib/libc/sparc64/Symbol.map100
-rw-r--r--lib/libc/sparc64/_fpmath.h52
-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.c470
-rw-r--r--lib/libc/sparc64/fpu/fpu_add.c218
-rw-r--r--lib/libc/sparc64/fpu/fpu_arith.h96
-rw-r--r--lib/libc/sparc64/fpu/fpu_compare.c181
-rw-r--r--lib/libc/sparc64/fpu/fpu_div.c272
-rw-r--r--lib/libc/sparc64/fpu/fpu_emu.h184
-rw-r--r--lib/libc/sparc64/fpu/fpu_explode.c324
-rw-r--r--lib/libc/sparc64/fpu/fpu_extern.h93
-rw-r--r--lib/libc/sparc64/fpu/fpu_implode.c537
-rw-r--r--lib/libc/sparc64/fpu/fpu_mul.c230
-rw-r--r--lib/libc/sparc64/fpu/fpu_qp.c148
-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.c401
-rw-r--r--lib/libc/sparc64/fpu/fpu_subr.c225
-rw-r--r--lib/libc/sparc64/gen/Makefile.inc6
-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.S83
-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.S97
-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/modf.S181
-rw-r--r--lib/libc/sparc64/gen/setjmp.S92
-rw-r--r--lib/libc/sparc64/gen/signalcontext.c77
-rw-r--r--lib/libc/sparc64/gen/sigsetjmp.S56
-rw-r--r--lib/libc/sparc64/net/Makefile.inc3
-rw-r--r--lib/libc/sparc64/net/htonl.S56
-rw-r--r--lib/libc/sparc64/net/htons.S58
-rw-r--r--lib/libc/sparc64/net/ntohl.S56
-rw-r--r--lib/libc/sparc64/net/ntohs.S58
-rw-r--r--lib/libc/sparc64/stdlib/Makefile.inc1
-rw-r--r--lib/libc/sparc64/string/Makefile.inc1
-rw-r--r--lib/libc/sparc64/sys/Makefile.inc23
-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.S69
-rw-r--r--lib/libc/sparc64/sys/cerror.S63
-rw-r--r--lib/libc/sparc64/sys/exect.S55
-rw-r--r--lib/libc/sparc64/sys/pipe.S61
-rw-r--r--lib/libc/sparc64/sys/ptrace.S61
-rw-r--r--lib/libc/sparc64/sys/sbrk.S75
-rw-r--r--lib/libc/sparc64/sys/setlogin.S59
-rw-r--r--lib/libc/sparc64/sys/sigaction.S49
-rw-r--r--lib/libc/sparc64/sys/sigcode.S40
-rw-r--r--lib/libc/stdio/Makefile.inc72
-rw-r--r--lib/libc/stdio/Symbol.map145
-rw-r--r--lib/libc/stdio/_flock_stub.c149
-rw-r--r--lib/libc/stdio/asprintf.c71
-rw-r--r--lib/libc/stdio/clrerr.c56
-rw-r--r--lib/libc/stdio/fclose.3115
-rw-r--r--lib/libc/stdio/fclose.c75
-rw-r--r--lib/libc/stdio/fcloseall.c39
-rw-r--r--lib/libc/stdio/fdopen.c93
-rw-r--r--lib/libc/stdio/feof.c59
-rw-r--r--lib/libc/stdio/ferror.3136
-rw-r--r--lib/libc/stdio/ferror.c59
-rw-r--r--lib/libc/stdio/fflush.3115
-rw-r--r--lib/libc/stdio/fflush.c145
-rw-r--r--lib/libc/stdio/fgetc.c60
-rw-r--r--lib/libc/stdio/fgetln.3128
-rw-r--r--lib/libc/stdio/fgetln.c168
-rw-r--r--lib/libc/stdio/fgetpos.c55
-rw-r--r--lib/libc/stdio/fgets.3161
-rw-r--r--lib/libc/stdio/fgets.c116
-rw-r--r--lib/libc/stdio/fgetwc.c96
-rw-r--r--lib/libc/stdio/fgetwln.3120
-rw-r--r--lib/libc/stdio/fgetwln.c67
-rw-r--r--lib/libc/stdio/fgetws.3125
-rw-r--r--lib/libc/stdio/fgetws.c100
-rw-r--r--lib/libc/stdio/fileno.c60
-rw-r--r--lib/libc/stdio/findfp.c249
-rw-r--r--lib/libc/stdio/flags.c94
-rw-r--r--lib/libc/stdio/floatio.h58
-rw-r--r--lib/libc/stdio/flockfile.3104
-rw-r--r--lib/libc/stdio/fopen.3287
-rw-r--r--lib/libc/stdio/fopen.c88
-rw-r--r--lib/libc/stdio/fprintf.c56
-rw-r--r--lib/libc/stdio/fpurge.c74
-rw-r--r--lib/libc/stdio/fputc.c61
-rw-r--r--lib/libc/stdio/fputs.3111
-rw-r--r--lib/libc/stdio/fputs.c72
-rw-r--r--lib/libc/stdio/fputwc.c87
-rw-r--r--lib/libc/stdio/fputws.392
-rw-r--r--lib/libc/stdio/fputws.c71
-rw-r--r--lib/libc/stdio/fread.3109
-rw-r--r--lib/libc/stdio/fread.c100
-rw-r--r--lib/libc/stdio/freopen.c221
-rw-r--r--lib/libc/stdio/fscanf.c62
-rw-r--r--lib/libc/stdio/fseek.3272
-rw-r--r--lib/libc/stdio/fseek.c314
-rw-r--r--lib/libc/stdio/fsetpos.c55
-rw-r--r--lib/libc/stdio/ftell.c143
-rw-r--r--lib/libc/stdio/funopen.3180
-rw-r--r--lib/libc/stdio/funopen.c80
-rw-r--r--lib/libc/stdio/fvwrite.c211
-rw-r--r--lib/libc/stdio/fvwrite.h53
-rw-r--r--lib/libc/stdio/fwalk.c71
-rw-r--r--lib/libc/stdio/fwide.397
-rw-r--r--lib/libc/stdio/fwide.c51
-rw-r--r--lib/libc/stdio/fwprintf.c45
-rw-r--r--lib/libc/stdio/fwrite.c80
-rw-r--r--lib/libc/stdio/fwscanf.c45
-rw-r--r--lib/libc/stdio/getc.3174
-rw-r--r--lib/libc/stdio/getc.c61
-rw-r--r--lib/libc/stdio/getchar.c64
-rw-r--r--lib/libc/stdio/gets.c81
-rw-r--r--lib/libc/stdio/getw.c52
-rw-r--r--lib/libc/stdio/getwc.3118
-rw-r--r--lib/libc/stdio/getwc.c48
-rw-r--r--lib/libc/stdio/getwchar.c47
-rw-r--r--lib/libc/stdio/glue.h49
-rw-r--r--lib/libc/stdio/local.h142
-rw-r--r--lib/libc/stdio/makebuf.c124
-rw-r--r--lib/libc/stdio/mktemp.3255
-rw-r--r--lib/libc/stdio/mktemp.c186
-rw-r--r--lib/libc/stdio/perror.c80
-rw-r--r--lib/libc/stdio/printf.3863
-rw-r--r--lib/libc/stdio/printf.c56
-rw-r--r--lib/libc/stdio/putc.3169
-rw-r--r--lib/libc/stdio/putc.c63
-rw-r--r--lib/libc/stdio/putchar.c67
-rw-r--r--lib/libc/stdio/puts.c75
-rw-r--r--lib/libc/stdio/putw.c66
-rw-r--r--lib/libc/stdio/putwc.3107
-rw-r--r--lib/libc/stdio/putwc.c48
-rw-r--r--lib/libc/stdio/putwchar.c47
-rw-r--r--lib/libc/stdio/refill.c150
-rw-r--r--lib/libc/stdio/remove.387
-rw-r--r--lib/libc/stdio/remove.c59
-rw-r--r--lib/libc/stdio/rewind.c65
-rw-r--r--lib/libc/stdio/rget.c59
-rw-r--r--lib/libc/stdio/scanf.3517
-rw-r--r--lib/libc/stdio/scanf.c62
-rw-r--r--lib/libc/stdio/setbuf.3213
-rw-r--r--lib/libc/stdio/setbuf.c50
-rw-r--r--lib/libc/stdio/setbuffer.c64
-rw-r--r--lib/libc/stdio/setvbuf.c165
-rw-r--r--lib/libc/stdio/snprintf.c75
-rw-r--r--lib/libc/stdio/sprintf.c67
-rw-r--r--lib/libc/stdio/sscanf.c82
-rw-r--r--lib/libc/stdio/stdio.3333
-rw-r--r--lib/libc/stdio/stdio.c191
-rw-r--r--lib/libc/stdio/swprintf.c45
-rw-r--r--lib/libc/stdio/swscanf.c45
-rw-r--r--lib/libc/stdio/tempnam.c94
-rw-r--r--lib/libc/stdio/tmpfile.c96
-rw-r--r--lib/libc/stdio/tmpnam.3239
-rw-r--r--lib/libc/stdio/tmpnam.c65
-rw-r--r--lib/libc/stdio/ungetc.3102
-rw-r--r--lib/libc/stdio/ungetc.c172
-rw-r--r--lib/libc/stdio/ungetwc.399
-rw-r--r--lib/libc/stdio/ungetwc.c77
-rw-r--r--lib/libc/stdio/unlocked.c94
-rw-r--r--lib/libc/stdio/vasprintf.c69
-rw-r--r--lib/libc/stdio/vfprintf.c1656
-rw-r--r--lib/libc/stdio/vfscanf.c1068
-rw-r--r--lib/libc/stdio/vfwprintf.c1648
-rw-r--r--lib/libc/stdio/vfwscanf.c880
-rw-r--r--lib/libc/stdio/vprintf.c50
-rw-r--r--lib/libc/stdio/vscanf.c60
-rw-r--r--lib/libc/stdio/vsnprintf.c79
-rw-r--r--lib/libc/stdio/vsprintf.c63
-rw-r--r--lib/libc/stdio/vsscanf.c80
-rw-r--r--lib/libc/stdio/vswprintf.c96
-rw-r--r--lib/libc/stdio/vswscanf.c99
-rw-r--r--lib/libc/stdio/vwprintf.c39
-rw-r--r--lib/libc/stdio/vwscanf.c39
-rw-r--r--lib/libc/stdio/wbuf.c95
-rw-r--r--lib/libc/stdio/wprintf.3622
-rw-r--r--lib/libc/stdio/wprintf.c45
-rw-r--r--lib/libc/stdio/wscanf.3483
-rw-r--r--lib/libc/stdio/wscanf.c45
-rw-r--r--lib/libc/stdio/wsetup.c96
-rw-r--r--lib/libc/stdio/xprintf.c688
-rw-r--r--lib/libc/stdio/xprintf_errno.c65
-rw-r--r--lib/libc/stdio/xprintf_float.c425
-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.c115
-rw-r--r--lib/libc/stdio/xprintf_vis.c78
-rw-r--r--lib/libc/stdlib/Makefile.inc50
-rw-r--r--lib/libc/stdlib/Symbol.map100
-rw-r--r--lib/libc/stdlib/_Exit.c22
-rw-r--r--lib/libc/stdlib/a64l.3186
-rw-r--r--lib/libc/stdlib/a64l.c46
-rw-r--r--lib/libc/stdlib/abort.383
-rw-r--r--lib/libc/stdlib/abort.c83
-rw-r--r--lib/libc/stdlib/abs.379
-rw-r--r--lib/libc/stdlib/abs.c47
-rw-r--r--lib/libc/stdlib/alloca.383
-rw-r--r--lib/libc/stdlib/atexit.392
-rw-r--r--lib/libc/stdlib/atexit.c189
-rw-r--r--lib/libc/stdlib/atexit.h40
-rw-r--r--lib/libc/stdlib/atof.399
-rw-r--r--lib/libc/stdlib/atof.c47
-rw-r--r--lib/libc/stdlib/atoi.395
-rw-r--r--lib/libc/stdlib/atoi.c47
-rw-r--r--lib/libc/stdlib/atol.3110
-rw-r--r--lib/libc/stdlib/atol.c47
-rw-r--r--lib/libc/stdlib/atoll.c44
-rw-r--r--lib/libc/stdlib/bsearch.393
-rw-r--r--lib/libc/stdlib/bsearch.c83
-rw-r--r--lib/libc/stdlib/div.372
-rw-r--r--lib/libc/stdlib/div.c81
-rw-r--r--lib/libc/stdlib/exit.3134
-rw-r--r--lib/libc/stdlib/exit.c75
-rw-r--r--lib/libc/stdlib/getenv.3174
-rw-r--r--lib/libc/stdlib/getenv.c93
-rw-r--r--lib/libc/stdlib/getopt.3310
-rw-r--r--lib/libc/stdlib/getopt.c139
-rw-r--r--lib/libc/stdlib/getopt_long.3506
-rw-r--r--lib/libc/stdlib/getopt_long.c642
-rw-r--r--lib/libc/stdlib/getsubopt.3149
-rw-r--r--lib/libc/stdlib/getsubopt.c101
-rw-r--r--lib/libc/stdlib/grantpt.3225
-rw-r--r--lib/libc/stdlib/grantpt.c302
-rw-r--r--lib/libc/stdlib/hcreate.3226
-rw-r--r--lib/libc/stdlib/hcreate.c185
-rw-r--r--lib/libc/stdlib/heapsort.c185
-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.c45
-rw-r--r--lib/libc/stdlib/insque.361
-rw-r--r--lib/libc/stdlib/insque.c47
-rw-r--r--lib/libc/stdlib/l64a.c52
-rw-r--r--lib/libc/stdlib/labs.371
-rw-r--r--lib/libc/stdlib/labs.c47
-rw-r--r--lib/libc/stdlib/ldiv.375
-rw-r--r--lib/libc/stdlib/ldiv.c60
-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.c45
-rw-r--r--lib/libc/stdlib/lsearch.3105
-rw-r--r--lib/libc/stdlib/lsearch.c64
-rw-r--r--lib/libc/stdlib/malloc.3473
-rw-r--r--lib/libc/stdlib/malloc.c3641
-rw-r--r--lib/libc/stdlib/memory.381
-rw-r--r--lib/libc/stdlib/merge.c355
-rw-r--r--lib/libc/stdlib/posix_memalign.389
-rw-r--r--lib/libc/stdlib/putenv.c60
-rw-r--r--lib/libc/stdlib/qsort.3290
-rw-r--r--lib/libc/stdlib/qsort.c197
-rw-r--r--lib/libc/stdlib/qsort_r.c8
-rw-r--r--lib/libc/stdlib/radixsort.3164
-rw-r--r--lib/libc/stdlib/radixsort.c331
-rw-r--r--lib/libc/stdlib/rand.3121
-rw-r--r--lib/libc/stdlib/rand.c172
-rw-r--r--lib/libc/stdlib/random.3199
-rw-r--r--lib/libc/stdlib/random.c506
-rw-r--r--lib/libc/stdlib/reallocf.c41
-rw-r--r--lib/libc/stdlib/realpath.3124
-rw-r--r--lib/libc/stdlib/realpath.c197
-rw-r--r--lib/libc/stdlib/remque.c30
-rw-r--r--lib/libc/stdlib/setenv.c120
-rw-r--r--lib/libc/stdlib/strfmon.3167
-rw-r--r--lib/libc/stdlib/strfmon.c604
-rw-r--r--lib/libc/stdlib/strtod.3185
-rw-r--r--lib/libc/stdlib/strtoimax.c144
-rw-r--r--lib/libc/stdlib/strtol.3226
-rw-r--r--lib/libc/stdlib/strtol.c144
-rw-r--r--lib/libc/stdlib/strtoll.c144
-rw-r--r--lib/libc/stdlib/strtonum.3154
-rw-r--r--lib/libc/stdlib/strtonum.c68
-rw-r--r--lib/libc/stdlib/strtoq.c52
-rw-r--r--lib/libc/stdlib/strtoul.3228
-rw-r--r--lib/libc/stdlib/strtoul.c122
-rw-r--r--lib/libc/stdlib/strtoull.c122
-rw-r--r--lib/libc/stdlib/strtoumax.c122
-rw-r--r--lib/libc/stdlib/strtouq.c52
-rw-r--r--lib/libc/stdlib/system.3103
-rw-r--r--lib/libc/stdlib/system.c102
-rw-r--r--lib/libc/stdlib/tdelete.c71
-rw-r--r--lib/libc/stdlib/tfind.c48
-rw-r--r--lib/libc/stdlib/tsearch.3132
-rw-r--r--lib/libc/stdlib/tsearch.c58
-rw-r--r--lib/libc/stdlib/twalk.c58
-rw-r--r--lib/libc/stdtime/Makefile.inc18
-rw-r--r--lib/libc/stdtime/Symbol.map34
-rw-r--r--lib/libc/stdtime/asctime.c78
-rw-r--r--lib/libc/stdtime/ctime.3378
-rw-r--r--lib/libc/stdtime/difftime.c87
-rw-r--r--lib/libc/stdtime/localtime.c1813
-rw-r--r--lib/libc/stdtime/private.h260
-rw-r--r--lib/libc/stdtime/strftime.3282
-rw-r--r--lib/libc/stdtime/strftime.c592
-rw-r--r--lib/libc/stdtime/strptime.3173
-rw-r--r--lib/libc/stdtime/strptime.c538
-rw-r--r--lib/libc/stdtime/time2posix.3120
-rw-r--r--lib/libc/stdtime/time32.c100
-rw-r--r--lib/libc/stdtime/timelocal.c117
-rw-r--r--lib/libc/stdtime/timelocal.h55
-rw-r--r--lib/libc/stdtime/tzfile.5138
-rw-r--r--lib/libc/stdtime/tzfile.h192
-rw-r--r--lib/libc/string/Makefile.inc64
-rw-r--r--lib/libc/string/Symbol.map80
-rw-r--r--lib/libc/string/bcmp.381
-rw-r--r--lib/libc/string/bcmp.c59
-rw-r--r--lib/libc/string/bcopy.381
-rw-r--r--lib/libc/string/bcopy.c141
-rw-r--r--lib/libc/string/bstring.3112
-rw-r--r--lib/libc/string/bzero.378
-rw-r--r--lib/libc/string/bzero.c5
-rw-r--r--lib/libc/string/ffs.3100
-rw-r--r--lib/libc/string/ffs.c55
-rw-r--r--lib/libc/string/ffsl.c52
-rw-r--r--lib/libc/string/fls.c52
-rw-r--r--lib/libc/string/flsl.c52
-rw-r--r--lib/libc/string/index.3106
-rw-r--r--lib/libc/string/index.c65
-rw-r--r--lib/libc/string/memccpy.376
-rw-r--r--lib/libc/string/memccpy.c60
-rw-r--r--lib/libc/string/memchr.383
-rw-r--r--lib/libc/string/memchr.c60
-rw-r--r--lib/libc/string/memcmp.385
-rw-r--r--lib/libc/string/memcmp.c62
-rw-r--r--lib/libc/string/memcpy.391
-rw-r--r--lib/libc/string/memcpy.c5
-rw-r--r--lib/libc/string/memmem.386
-rw-r--r--lib/libc/string/memmem.c67
-rw-r--r--lib/libc/string/memmove.378
-rw-r--r--lib/libc/string/memmove.c5
-rw-r--r--lib/libc/string/memset.373
-rw-r--r--lib/libc/string/memset.c132
-rw-r--r--lib/libc/string/rindex.c66
-rw-r--r--lib/libc/string/stpcpy.c46
-rw-r--r--lib/libc/string/strcasecmp.3104
-rw-r--r--lib/libc/string/strcasecmp.c77
-rw-r--r--lib/libc/string/strcasestr.c65
-rw-r--r--lib/libc/string/strcat.3159
-rw-r--r--lib/libc/string/strcat.c50
-rw-r--r--lib/libc/string/strchr.399
-rw-r--r--lib/libc/string/strchr.c5
-rw-r--r--lib/libc/string/strcmp.3104
-rw-r--r--lib/libc/string/strcmp.c56
-rw-r--r--lib/libc/string/strcoll.376
-rw-r--r--lib/libc/string/strcoll.c86
-rw-r--r--lib/libc/string/strcpy.3202
-rw-r--r--lib/libc/string/strcpy.c49
-rw-r--r--lib/libc/string/strcspn.392
-rw-r--r--lib/libc/string/strcspn.c72
-rw-r--r--lib/libc/string/strdup.370
-rw-r--r--lib/libc/string/strdup.c56
-rw-r--r--lib/libc/string/strerror.3190
-rw-r--r--lib/libc/string/strerror.c130
-rw-r--r--lib/libc/string/string.3161
-rw-r--r--lib/libc/string/strlcat.c75
-rw-r--r--lib/libc/string/strlcpy.3204
-rw-r--r--lib/libc/string/strlcpy.c70
-rw-r--r--lib/libc/string/strlen.373
-rw-r--r--lib/libc/string/strlen.c51
-rw-r--r--lib/libc/string/strmode.3148
-rw-r--r--lib/libc/string/strmode.c154
-rw-r--r--lib/libc/string/strncat.c66
-rw-r--r--lib/libc/string/strncmp.c58
-rw-r--r--lib/libc/string/strncpy.c66
-rw-r--r--lib/libc/string/strnstr.c72
-rw-r--r--lib/libc/string/strpbrk.380
-rw-r--r--lib/libc/string/strpbrk.c58
-rw-r--r--lib/libc/string/strrchr.c5
-rw-r--r--lib/libc/string/strsep.3124
-rw-r--r--lib/libc/string/strsep.c81
-rw-r--r--lib/libc/string/strsignal.c112
-rw-r--r--lib/libc/string/strspn.387
-rw-r--r--lib/libc/string/strspn.c71
-rw-r--r--lib/libc/string/strstr.3148
-rw-r--r--lib/libc/string/strstr.c66
-rw-r--r--lib/libc/string/strtok.3178
-rw-r--r--lib/libc/string/strtok.c140
-rw-r--r--lib/libc/string/strxfrm.3100
-rw-r--r--lib/libc/string/strxfrm.c83
-rw-r--r--lib/libc/string/swab.368
-rw-r--r--lib/libc/string/swab.c63
-rw-r--r--lib/libc/string/wcscat.c53
-rw-r--r--lib/libc/string/wcschr.c41
-rw-r--r--lib/libc/string/wcscmp.c61
-rw-r--r--lib/libc/string/wcscoll.3112
-rw-r--r--lib/libc/string/wcscoll.c98
-rw-r--r--lib/libc/string/wcscpy.c51
-rw-r--r--lib/libc/string/wcscspn.c60
-rw-r--r--lib/libc/string/wcsdup.c43
-rw-r--r--lib/libc/string/wcslcat.c77
-rw-r--r--lib/libc/string/wcslcpy.c73
-rw-r--r--lib/libc/string/wcslen.c50
-rw-r--r--lib/libc/string/wcsncat.c60
-rw-r--r--lib/libc/string/wcsncmp.c63
-rw-r--r--lib/libc/string/wcsncpy.c68
-rw-r--r--lib/libc/string/wcspbrk.c60
-rw-r--r--lib/libc/string/wcsrchr.c47
-rw-r--r--lib/libc/string/wcsspn.c62
-rw-r--r--lib/libc/string/wcsstr.c67
-rw-r--r--lib/libc/string/wcstok.3133
-rw-r--r--lib/libc/string/wcstok.c90
-rw-r--r--lib/libc/string/wcswidth.362
-rw-r--r--lib/libc/string/wcswidth.c61
-rw-r--r--lib/libc/string/wcsxfrm.3126
-rw-r--r--lib/libc/string/wcsxfrm.c116
-rw-r--r--lib/libc/string/wmemchr.3150
-rw-r--r--lib/libc/string/wmemchr.c55
-rw-r--r--lib/libc/string/wmemcmp.c56
-rw-r--r--lib/libc/string/wmemcpy.c48
-rw-r--r--lib/libc/string/wmemmove.c48
-rw-r--r--lib/libc/string/wmemset.c54
-rw-r--r--lib/libc/sys/Makefile.inc159
-rw-r--r--lib/libc/sys/Symbol.map950
-rw-r--r--lib/libc/sys/__error.c48
-rw-r--r--lib/libc/sys/_exit.2127
-rw-r--r--lib/libc/sys/abort2.299
-rw-r--r--lib/libc/sys/accept.2185
-rw-r--r--lib/libc/sys/access.2160
-rw-r--r--lib/libc/sys/acct.2135
-rw-r--r--lib/libc/sys/adjtime.2115
-rw-r--r--lib/libc/sys/aio_cancel.2117
-rw-r--r--lib/libc/sys/aio_error.2102
-rw-r--r--lib/libc/sys/aio_read.2215
-rw-r--r--lib/libc/sys/aio_return.2104
-rw-r--r--lib/libc/sys/aio_suspend.2117
-rw-r--r--lib/libc/sys/aio_waitcomplete.2137
-rw-r--r--lib/libc/sys/aio_write.2210
-rw-r--r--lib/libc/sys/bind.2135
-rw-r--r--lib/libc/sys/brk.2175
-rw-r--r--lib/libc/sys/chdir.2136
-rw-r--r--lib/libc/sys/chflags.2237
-rw-r--r--lib/libc/sys/chmod.2237
-rw-r--r--lib/libc/sys/chown.2182
-rw-r--r--lib/libc/sys/chroot.2146
-rw-r--r--lib/libc/sys/clock_gettime.2133
-rw-r--r--lib/libc/sys/close.2140
-rw-r--r--lib/libc/sys/connect.2162
-rw-r--r--lib/libc/sys/dup.2166
-rw-r--r--lib/libc/sys/execve.2310
-rw-r--r--lib/libc/sys/extattr_get_file.2270
-rw-r--r--lib/libc/sys/fcntl.2586
-rw-r--r--lib/libc/sys/fhopen.2147
-rw-r--r--lib/libc/sys/flock.2174
-rw-r--r--lib/libc/sys/fork.2138
-rw-r--r--lib/libc/sys/fsync.291
-rw-r--r--lib/libc/sys/ftruncate.c55
-rw-r--r--lib/libc/sys/getdirentries.2189
-rw-r--r--lib/libc/sys/getdtablesize.264
-rw-r--r--lib/libc/sys/getfh.2115
-rw-r--r--lib/libc/sys/getfsstat.2126
-rw-r--r--lib/libc/sys/getgid.285
-rw-r--r--lib/libc/sys/getgroups.2103
-rw-r--r--lib/libc/sys/getitimer.2184
-rw-r--r--lib/libc/sys/getlogin.2208
-rw-r--r--lib/libc/sys/getpeername.298
-rw-r--r--lib/libc/sys/getpgrp.2146
-rw-r--r--lib/libc/sys/getpid.290
-rw-r--r--lib/libc/sys/getpriority.2154
-rw-r--r--lib/libc/sys/getrlimit.2196
-rw-r--r--lib/libc/sys/getrusage.2184
-rw-r--r--lib/libc/sys/getsid.282
-rw-r--r--lib/libc/sys/getsockname.298
-rw-r--r--lib/libc/sys/getsockopt.2425
-rw-r--r--lib/libc/sys/gettimeofday.2139
-rw-r--r--lib/libc/sys/getuid.294
-rw-r--r--lib/libc/sys/intro.2739
-rw-r--r--lib/libc/sys/ioctl.2137
-rw-r--r--lib/libc/sys/issetugid.2102
-rw-r--r--lib/libc/sys/jail.2142
-rw-r--r--lib/libc/sys/kenv.2179
-rw-r--r--lib/libc/sys/kill.2155
-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.2125
-rw-r--r--lib/libc/sys/kldsym.2122
-rw-r--r--lib/libc/sys/kldunload.278
-rw-r--r--lib/libc/sys/kqueue.2549
-rw-r--r--lib/libc/sys/kse.2703
-rw-r--r--lib/libc/sys/ktrace.2200
-rw-r--r--lib/libc/sys/link.2175
-rw-r--r--lib/libc/sys/lio_listio.2175
-rw-r--r--lib/libc/sys/listen.2174
-rw-r--r--lib/libc/sys/lseek.2161
-rw-r--r--lib/libc/sys/lseek.c55
-rw-r--r--lib/libc/sys/madvise.2186
-rw-r--r--lib/libc/sys/mincore.2117
-rw-r--r--lib/libc/sys/minherit.2141
-rw-r--r--lib/libc/sys/mkdir.2116
-rw-r--r--lib/libc/sys/mkfifo.2127
-rw-r--r--lib/libc/sys/mknod.2130
-rw-r--r--lib/libc/sys/mlock.2169
-rw-r--r--lib/libc/sys/mlockall.2140
-rw-r--r--lib/libc/sys/mmap.2367
-rw-r--r--lib/libc/sys/mmap.c61
-rw-r--r--lib/libc/sys/modfind.286
-rw-r--r--lib/libc/sys/modnext.297
-rw-r--r--lib/libc/sys/modstat.2128
-rw-r--r--lib/libc/sys/mount.2376
-rw-r--r--lib/libc/sys/mprotect.2101
-rw-r--r--lib/libc/sys/mq_close.285
-rw-r--r--lib/libc/sys/mq_getattr.2107
-rw-r--r--lib/libc/sys/mq_notify.2131
-rw-r--r--lib/libc/sys/mq_open.2303
-rw-r--r--lib/libc/sys/mq_receive.2197
-rw-r--r--lib/libc/sys/mq_send.2216
-rw-r--r--lib/libc/sys/mq_setattr.2103
-rw-r--r--lib/libc/sys/msync.2125
-rw-r--r--lib/libc/sys/munmap.282
-rw-r--r--lib/libc/sys/nanosleep.2113
-rw-r--r--lib/libc/sys/nfssvc.2262
-rw-r--r--lib/libc/sys/ntp_adjtime.2150
-rw-r--r--lib/libc/sys/ntp_gettime.2116
-rw-r--r--lib/libc/sys/open.2352
-rw-r--r--lib/libc/sys/pathconf.2230
-rw-r--r--lib/libc/sys/pipe.2122
-rw-r--r--lib/libc/sys/poll.2213
-rw-r--r--lib/libc/sys/pread.c56
-rw-r--r--lib/libc/sys/profil.2126
-rw-r--r--lib/libc/sys/ptrace.2390
-rw-r--r--lib/libc/sys/pwrite.c56
-rw-r--r--lib/libc/sys/quotactl.2236
-rw-r--r--lib/libc/sys/read.2285
-rw-r--r--lib/libc/sys/readlink.2104
-rw-r--r--lib/libc/sys/reboot.2170
-rw-r--r--lib/libc/sys/recv.2337
-rw-r--r--lib/libc/sys/rename.2215
-rw-r--r--lib/libc/sys/revoke.2109
-rw-r--r--lib/libc/sys/rfork.2186
-rw-r--r--lib/libc/sys/rmdir.2114
-rw-r--r--lib/libc/sys/rtprio.2126
-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.2167
-rw-r--r--lib/libc/sys/sched_yield.258
-rw-r--r--lib/libc/sys/select.2228
-rw-r--r--lib/libc/sys/semctl.2203
-rw-r--r--lib/libc/sys/semget.2148
-rw-r--r--lib/libc/sys/semop.2289
-rw-r--r--lib/libc/sys/send.2240
-rw-r--r--lib/libc/sys/sendfile.2278
-rw-r--r--lib/libc/sys/setgroups.293
-rw-r--r--lib/libc/sys/setpgid.2109
-rw-r--r--lib/libc/sys/setregid.294
-rw-r--r--lib/libc/sys/setresuid.299
-rw-r--r--lib/libc/sys/setreuid.294
-rw-r--r--lib/libc/sys/setsid.285
-rw-r--r--lib/libc/sys/setuid.2197
-rw-r--r--lib/libc/sys/shm_open.2192
-rw-r--r--lib/libc/sys/shmat.2123
-rw-r--r--lib/libc/sys/shmctl.2140
-rw-r--r--lib/libc/sys/shmget.2146
-rw-r--r--lib/libc/sys/shutdown.2108
-rw-r--r--lib/libc/sys/sigaction.2669
-rw-r--r--lib/libc/sys/sigaltstack.2168
-rw-r--r--lib/libc/sys/sigpending.281
-rw-r--r--lib/libc/sys/sigprocmask.2129
-rw-r--r--lib/libc/sys/sigqueue.2146
-rw-r--r--lib/libc/sys/sigreturn.297
-rw-r--r--lib/libc/sys/sigstack.254
-rw-r--r--lib/libc/sys/sigsuspend.285
-rw-r--r--lib/libc/sys/sigwait.2119
-rw-r--r--lib/libc/sys/sigwaitinfo.2199
-rw-r--r--lib/libc/sys/socket.2297
-rw-r--r--lib/libc/sys/socketpair.295
-rw-r--r--lib/libc/sys/stat.2345
-rw-r--r--lib/libc/sys/statfs.2236
-rw-r--r--lib/libc/sys/swapon.2151
-rw-r--r--lib/libc/sys/symlink.2140
-rw-r--r--lib/libc/sys/sync.281
-rw-r--r--lib/libc/sys/sysarch.285
-rw-r--r--lib/libc/sys/syscall.281
-rw-r--r--lib/libc/sys/timer_create.2162
-rw-r--r--lib/libc/sys/timer_delete.278
-rw-r--r--lib/libc/sys/timer_settime.2263
-rw-r--r--lib/libc/sys/truncate.2140
-rw-r--r--lib/libc/sys/truncate.c56
-rw-r--r--lib/libc/sys/umask.292
-rw-r--r--lib/libc/sys/undelete.2109
-rw-r--r--lib/libc/sys/unlink.2129
-rw-r--r--lib/libc/sys/utimes.2213
-rw-r--r--lib/libc/sys/utrace.286
-rw-r--r--lib/libc/sys/uuidgen.2142
-rw-r--r--lib/libc/sys/vfork.2141
-rw-r--r--lib/libc/sys/wait.2348
-rw-r--r--lib/libc/sys/write.2290
-rw-r--r--lib/libc/uuid/Makefile.inc19
-rw-r--r--lib/libc/uuid/Symbol.map12
-rw-r--r--lib/libc/uuid/uuid.3100
-rw-r--r--lib/libc/uuid/uuid_compare.c78
-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_to_string.c67
-rw-r--r--lib/libc/xdr/Makefile.inc50
-rw-r--r--lib/libc/xdr/Symbol.map45
-rw-r--r--lib/libc/xdr/xdr.3829
-rw-r--r--lib/libc/xdr/xdr.c875
-rw-r--r--lib/libc/xdr/xdr_array.c163
-rw-r--r--lib/libc/xdr/xdr_float.c309
-rw-r--r--lib/libc/xdr/xdr_mem.c260
-rw-r--r--lib/libc/xdr/xdr_rec.c788
-rw-r--r--lib/libc/xdr/xdr_reference.c143
-rw-r--r--lib/libc/xdr/xdr_sizeof.c168
-rw-r--r--lib/libc/xdr/xdr_stdio.c196
-rw-r--r--lib/libc/yp/Makefile.inc19
-rw-r--r--lib/libc/yp/Symbol.map23
-rw-r--r--lib/libc/yp/xdryp.c114
-rw-r--r--lib/libc/yp/yplib.c1166
-rw-r--r--lib/libc_r/Makefile38
-rw-r--r--lib/libc_r/arch/alpha/_atomic_lock.S45
-rw-r--r--lib/libc_r/arch/amd64/_atomic_lock.S41
-rw-r--r--lib/libc_r/arch/i386/_atomic_lock.S42
-rw-r--r--lib/libc_r/arch/ia64/_atomic_lock.S47
-rw-r--r--lib/libc_r/arch/sparc64/_atomic_lock.S45
-rw-r--r--lib/libc_r/sys/Makefile.inc6
-rw-r--r--lib/libc_r/sys/uthread_error.c49
-rw-r--r--lib/libc_r/test/Makefile115
-rw-r--r--lib/libc_r/test/README28
-rw-r--r--lib/libc_r/test/guard_b.c151
-rw-r--r--lib/libc_r/test/guard_b.exp3
-rwxr-xr-xlib/libc_r/test/guard_s.pl69
-rw-r--r--lib/libc_r/test/hello_b.c13
-rw-r--r--lib/libc_r/test/hello_d.c38
-rw-r--r--lib/libc_r/test/hello_d.exp1
-rw-r--r--lib/libc_r/test/hello_s.c47
-rw-r--r--lib/libc_r/test/join_leak_d.c112
-rw-r--r--lib/libc_r/test/join_leak_d.exp2
-rw-r--r--lib/libc_r/test/mutex_d.c1555
-rw-r--r--lib/libc_r/test/mutex_d.exp290
-rwxr-xr-xlib/libc_r/test/propagate_s.pl74
-rw-r--r--lib/libc_r/test/sem_d.c133
-rw-r--r--lib/libc_r/test/sem_d.exp22
-rw-r--r--lib/libc_r/test/sigsuspend_d.c288
-rw-r--r--lib/libc_r/test/sigsuspend_d.exp8
-rw-r--r--lib/libc_r/test/sigwait_d.c304
-rw-r--r--lib/libc_r/test/sigwait_d.exp10
-rwxr-xr-xlib/libc_r/test/verify474
-rw-r--r--lib/libc_r/uthread/Makefile.inc143
-rw-r--r--lib/libc_r/uthread/pthread_private.h1414
-rw-r--r--lib/libc_r/uthread/uthread_accept.c123
-rw-r--r--lib/libc_r/uthread/uthread_acl_aclcheck_fd.c47
-rw-r--r--lib/libc_r/uthread/uthread_acl_delete_fd.c46
-rw-r--r--lib/libc_r/uthread/uthread_acl_get_fd.c47
-rw-r--r--lib/libc_r/uthread/uthread_acl_set_fd.c46
-rw-r--r--lib/libc_r/uthread/uthread_aio_suspend.c50
-rw-r--r--lib/libc_r/uthread/uthread_atfork.c56
-rw-r--r--lib/libc_r/uthread/uthread_attr_destroy.c62
-rw-r--r--lib/libc_r/uthread/uthread_attr_get_np.c57
-rw-r--r--lib/libc_r/uthread/uthread_attr_getdetachstate.c59
-rw-r--r--lib/libc_r/uthread/uthread_attr_getguardsize.c52
-rw-r--r--lib/libc_r/uthread/uthread_attr_getinheritsched.c51
-rw-r--r--lib/libc_r/uthread/uthread_attr_getschedparam.c51
-rw-r--r--lib/libc_r/uthread/uthread_attr_getschedpolicy.c51
-rw-r--r--lib/libc_r/uthread/uthread_attr_getscope.c54
-rw-r--r--lib/libc_r/uthread/uthread_attr_getstack.c59
-rw-r--r--lib/libc_r/uthread/uthread_attr_getstackaddr.c54
-rw-r--r--lib/libc_r/uthread/uthread_attr_getstacksize.c54
-rw-r--r--lib/libc_r/uthread/uthread_attr_init.c61
-rw-r--r--lib/libc_r/uthread/uthread_attr_setcreatesuspend_np.c52
-rw-r--r--lib/libc_r/uthread/uthread_attr_setdetachstate.c61
-rw-r--r--lib/libc_r/uthread/uthread_attr_setguardsize.c61
-rw-r--r--lib/libc_r/uthread/uthread_attr_setinheritsched.c51
-rw-r--r--lib/libc_r/uthread/uthread_attr_setschedparam.c57
-rw-r--r--lib/libc_r/uthread/uthread_attr_setschedpolicy.c53
-rw-r--r--lib/libc_r/uthread/uthread_attr_setscope.c56
-rw-r--r--lib/libc_r/uthread/uthread_attr_setstack.c58
-rw-r--r--lib/libc_r/uthread/uthread_attr_setstackaddr.c54
-rw-r--r--lib/libc_r/uthread/uthread_attr_setstacksize.c54
-rw-r--r--lib/libc_r/uthread/uthread_autoinit.c64
-rw-r--r--lib/libc_r/uthread/uthread_bind.c51
-rw-r--r--lib/libc_r/uthread/uthread_cancel.c231
-rw-r--r--lib/libc_r/uthread/uthread_clean.c72
-rw-r--r--lib/libc_r/uthread/uthread_close.c122
-rw-r--r--lib/libc_r/uthread/uthread_concurrency.c60
-rw-r--r--lib/libc_r/uthread/uthread_cond.c768
-rw-r--r--lib/libc_r/uthread/uthread_condattr_destroy.c53
-rw-r--r--lib/libc_r/uthread/uthread_condattr_init.c60
-rw-r--r--lib/libc_r/uthread/uthread_connect.c91
-rw-r--r--lib/libc_r/uthread/uthread_creat.c48
-rw-r--r--lib/libc_r/uthread/uthread_create.c284
-rw-r--r--lib/libc_r/uthread/uthread_detach.c90
-rw-r--r--lib/libc_r/uthread/uthread_dup.c70
-rw-r--r--lib/libc_r/uthread/uthread_dup2.c98
-rw-r--r--lib/libc_r/uthread/uthread_equal.c44
-rw-r--r--lib/libc_r/uthread/uthread_execve.c115
-rw-r--r--lib/libc_r/uthread/uthread_exit.c227
-rw-r--r--lib/libc_r/uthread/uthread_fchflags.c24
-rw-r--r--lib/libc_r/uthread/uthread_fchmod.c51
-rw-r--r--lib/libc_r/uthread/uthread_fchown.c52
-rw-r--r--lib/libc_r/uthread/uthread_fcntl.c171
-rw-r--r--lib/libc_r/uthread/uthread_fd.c1057
-rw-r--r--lib/libc_r/uthread/uthread_file.c54
-rw-r--r--lib/libc_r/uthread/uthread_find_thread.c66
-rw-r--r--lib/libc_r/uthread/uthread_flock.c50
-rw-r--r--lib/libc_r/uthread/uthread_fork.c265
-rw-r--r--lib/libc_r/uthread/uthread_fpathconf.c45
-rw-r--r--lib/libc_r/uthread/uthread_fstat.c59
-rw-r--r--lib/libc_r/uthread/uthread_fstatfs.c58
-rw-r--r--lib/libc_r/uthread/uthread_fsync.c62
-rw-r--r--lib/libc_r/uthread/uthread_gc.c221
-rw-r--r--lib/libc_r/uthread/uthread_getdirentries.c51
-rw-r--r--lib/libc_r/uthread/uthread_getpeername.c52
-rw-r--r--lib/libc_r/uthread/uthread_getprio.c56
-rw-r--r--lib/libc_r/uthread/uthread_getschedparam.c59
-rw-r--r--lib/libc_r/uthread/uthread_getsockname.c51
-rw-r--r--lib/libc_r/uthread/uthread_getsockopt.c52
-rw-r--r--lib/libc_r/uthread/uthread_info.c296
-rw-r--r--lib/libc_r/uthread/uthread_init.c579
-rw-r--r--lib/libc_r/uthread/uthread_ioctl.c84
-rw-r--r--lib/libc_r/uthread/uthread_jmp.c118
-rw-r--r--lib/libc_r/uthread/uthread_join.c167
-rw-r--r--lib/libc_r/uthread/uthread_kern.c1138
-rw-r--r--lib/libc_r/uthread/uthread_kevent.c77
-rw-r--r--lib/libc_r/uthread/uthread_kill.c74
-rw-r--r--lib/libc_r/uthread/uthread_kqueue.c53
-rw-r--r--lib/libc_r/uthread/uthread_listen.c52
-rw-r--r--lib/libc_r/uthread/uthread_main_np.c47
-rw-r--r--lib/libc_r/uthread/uthread_mattr_init.c60
-rw-r--r--lib/libc_r/uthread/uthread_mattr_kind_np.c97
-rw-r--r--lib/libc_r/uthread/uthread_msync.c42
-rw-r--r--lib/libc_r/uthread/uthread_multi_np.c50
-rw-r--r--lib/libc_r/uthread/uthread_mutex.c1545
-rw-r--r--lib/libc_r/uthread/uthread_mutex_prioceiling.c115
-rw-r--r--lib/libc_r/uthread/uthread_mutex_protocol.c70
-rw-r--r--lib/libc_r/uthread/uthread_mutexattr_destroy.c53
-rw-r--r--lib/libc_r/uthread/uthread_nanosleep.c143
-rw-r--r--lib/libc_r/uthread/uthread_once.c55
-rw-r--r--lib/libc_r/uthread/uthread_open.c96
-rw-r--r--lib/libc_r/uthread/uthread_pause.c48
-rw-r--r--lib/libc_r/uthread/uthread_pipe.c54
-rw-r--r--lib/libc_r/uthread/uthread_poll.c111
-rw-r--r--lib/libc_r/uthread/uthread_priority_queue.c370
-rw-r--r--lib/libc_r/uthread/uthread_pselect.c56
-rw-r--r--lib/libc_r/uthread/uthread_read.c111
-rw-r--r--lib/libc_r/uthread/uthread_readv.c106
-rw-r--r--lib/libc_r/uthread/uthread_recvfrom.c89
-rw-r--r--lib/libc_r/uthread/uthread_recvmsg.c87
-rw-r--r--lib/libc_r/uthread/uthread_resume_np.c111
-rw-r--r--lib/libc_r/uthread/uthread_rwlock.c379
-rw-r--r--lib/libc_r/uthread/uthread_rwlockattr.c98
-rw-r--r--lib/libc_r/uthread/uthread_select.c231
-rw-r--r--lib/libc_r/uthread/uthread_self.c44
-rw-r--r--lib/libc_r/uthread/uthread_sem.c256
-rw-r--r--lib/libc_r/uthread/uthread_sendfile.c194
-rw-r--r--lib/libc_r/uthread/uthread_sendmsg.c86
-rw-r--r--lib/libc_r/uthread/uthread_sendto.c88
-rw-r--r--lib/libc_r/uthread/uthread_seterrno.c59
-rw-r--r--lib/libc_r/uthread/uthread_setprio.c52
-rw-r--r--lib/libc_r/uthread/uthread_setschedparam.c119
-rw-r--r--lib/libc_r/uthread/uthread_setsockopt.c52
-rw-r--r--lib/libc_r/uthread/uthread_shutdown.c72
-rw-r--r--lib/libc_r/uthread/uthread_sig.c1147
-rw-r--r--lib/libc_r/uthread/uthread_sigaction.c112
-rw-r--r--lib/libc_r/uthread/uthread_sigmask.c106
-rw-r--r--lib/libc_r/uthread/uthread_sigpending.c61
-rw-r--r--lib/libc_r/uthread/uthread_sigprocmask.c48
-rw-r--r--lib/libc_r/uthread/uthread_sigsuspend.c101
-rw-r--r--lib/libc_r/uthread/uthread_sigwait.c174
-rw-r--r--lib/libc_r/uthread/uthread_single_np.c49
-rw-r--r--lib/libc_r/uthread/uthread_sleep.c48
-rw-r--r--lib/libc_r/uthread/uthread_socket.c58
-rw-r--r--lib/libc_r/uthread/uthread_socketpair.c56
-rw-r--r--lib/libc_r/uthread/uthread_spec.c225
-rw-r--r--lib/libc_r/uthread/uthread_spinlock.c117
-rw-r--r--lib/libc_r/uthread/uthread_stack.c242
-rw-r--r--lib/libc_r/uthread/uthread_suspend_np.c104
-rw-r--r--lib/libc_r/uthread/uthread_switch_np.c71
-rw-r--r--lib/libc_r/uthread/uthread_system.c48
-rw-r--r--lib/libc_r/uthread/uthread_tcdrain.c48
-rw-r--r--lib/libc_r/uthread/uthread_vfork.c12
-rw-r--r--lib/libc_r/uthread/uthread_wait.c47
-rw-r--r--lib/libc_r/uthread/uthread_wait4.c82
-rw-r--r--lib/libc_r/uthread/uthread_waitpid.c49
-rw-r--r--lib/libc_r/uthread/uthread_write.c165
-rw-r--r--lib/libc_r/uthread/uthread_writev.c233
-rw-r--r--lib/libc_r/uthread/uthread_yield.c66
-rw-r--r--lib/libcalendar/Makefile16
-rw-r--r--lib/libcalendar/calendar.3203
-rw-r--r--lib/libcalendar/calendar.c330
-rw-r--r--lib/libcalendar/calendar.h42
-rw-r--r--lib/libcalendar/easter.c101
-rw-r--r--lib/libcam/Makefile42
-rw-r--r--lib/libcam/cam.3435
-rw-r--r--lib/libcam/cam_cdbparse.3568
-rw-r--r--lib/libcam/camlib.c792
-rw-r--r--lib/libcam/camlib.h181
-rw-r--r--lib/libcam/scsi_cmdparse.c849
-rw-r--r--lib/libcom_err/Makefile14
-rw-r--r--lib/libcom_err/doc/Makefile7
-rw-r--r--lib/libcom_err/doc/com_err.texinfo615
-rw-r--r--lib/libcompat/4.1/ascftime.c45
-rw-r--r--lib/libcompat/4.1/cftime.3105
-rw-r--r--lib/libcompat/4.1/cftime.c46
-rw-r--r--lib/libcompat/4.1/ftime.386
-rw-r--r--lib/libcompat/4.1/ftime.c54
-rw-r--r--lib/libcompat/4.1/getpw.392
-rw-r--r--lib/libcompat/4.1/getpw.c52
-rw-r--r--lib/libcompat/4.1/gtty.c52
-rw-r--r--lib/libcompat/4.1/stty.398
-rw-r--r--lib/libcompat/4.1/stty.c52
-rw-r--r--lib/libcompat/4.3/cfree.349
-rw-r--r--lib/libcompat/4.3/cfree.c45
-rw-r--r--lib/libcompat/4.3/re_comp.3129
-rw-r--r--lib/libcompat/4.3/regex.c96
-rw-r--r--lib/libcompat/4.3/rexec.3135
-rw-r--r--lib/libcompat/4.3/rexec.c393
-rw-r--r--lib/libcompat/4.4/cuserid.387
-rw-r--r--lib/libcompat/4.4/cuserid.c61
-rw-r--r--lib/libcompat/Makefile47
-rw-r--r--lib/libcompat/regexp/COPYRIGHT22
-rw-r--r--lib/libcompat/regexp/README84
-rw-r--r--lib/libcompat/regexp/regerror.c18
-rw-r--r--lib/libcompat/regexp/regexp.3323
-rw-r--r--lib/libcompat/regexp/regexp.c1337
-rw-r--r--lib/libcompat/regexp/regmagic.h5
-rw-r--r--lib/libcompat/regexp/regsub.c85
-rw-r--r--lib/libcrypt/Makefile38
-rw-r--r--lib/libcrypt/crypt-md5.c153
-rw-r--r--lib/libcrypt/crypt-nthash.c88
-rw-r--r--lib/libcrypt/crypt.3307
-rw-r--r--lib/libcrypt/crypt.c131
-rw-r--r--lib/libcrypt/crypt.h40
-rw-r--r--lib/libcrypt/misc.c47
-rw-r--r--lib/libdevinfo/Makefile8
-rw-r--r--lib/libdevinfo/devinfo.3247
-rw-r--r--lib/libdevinfo/devinfo.c500
-rw-r--r--lib/libdevinfo/devinfo.h147
-rw-r--r--lib/libdevinfo/devinfo_var.h70
-rw-r--r--lib/libdevstat/Makefile38
-rw-r--r--lib/libdevstat/devstat.3795
-rw-r--r--lib/libdevstat/devstat.c1631
-rw-r--r--lib/libdevstat/devstat.h168
-rw-r--r--lib/libdisk/Makefile41
-rw-r--r--lib/libdisk/blocks.c50
-rw-r--r--lib/libdisk/change.c132
-rw-r--r--lib/libdisk/chunk.c595
-rw-r--r--lib/libdisk/create_chunk.c296
-rw-r--r--lib/libdisk/disk.c400
-rw-r--r--lib/libdisk/libdisk.3345
-rw-r--r--lib/libdisk/libdisk.h364
-rw-r--r--lib/libdisk/open_disk.c280
-rw-r--r--lib/libdisk/open_ia64_disk.c273
-rw-r--r--lib/libdisk/rules.c296
-rw-r--r--lib/libdisk/tst01.c323
-rw-r--r--lib/libdisk/write_alpha_disk.c88
-rw-r--r--lib/libdisk/write_amd64_disk.c204
-rw-r--r--lib/libdisk/write_arm_disk.c47
-rw-r--r--lib/libdisk/write_disk.c76
-rw-r--r--lib/libdisk/write_i386_disk.c204
-rw-r--r--lib/libdisk/write_ia64_disk.c421
-rw-r--r--lib/libdisk/write_pc98_disk.c179
-rw-r--r--lib/libdisk/write_powerpc_disk.c64
-rw-r--r--lib/libdisk/write_sparc64_disk.c106
-rw-r--r--lib/libedit/Makefile70
-rw-r--r--lib/libedit/TEST/test.c298
-rw-r--r--lib/libedit/chared.c776
-rw-r--r--lib/libedit/chared.h168
-rw-r--r--lib/libedit/common.c920
-rw-r--r--lib/libedit/editline.3788
-rw-r--r--lib/libedit/editrc.5516
-rw-r--r--lib/libedit/el.c562
-rw-r--r--lib/libedit/el.h149
-rw-r--r--lib/libedit/emacs.c506
-rw-r--r--lib/libedit/hist.c208
-rw-r--r--lib/libedit/hist.h76
-rw-r--r--lib/libedit/history.c985
-rw-r--r--lib/libedit/key.c690
-rw-r--r--lib/libedit/key.h81
-rw-r--r--lib/libedit/makelist250
-rw-r--r--lib/libedit/map.c1413
-rw-r--r--lib/libedit/map.h75
-rw-r--r--lib/libedit/parse.c261
-rw-r--r--lib/libedit/parse.h48
-rw-r--r--lib/libedit/prompt.c168
-rw-r--r--lib/libedit/prompt.h58
-rw-r--r--lib/libedit/read.c610
-rw-r--r--lib/libedit/read.h58
-rw-r--r--lib/libedit/refresh.c1137
-rw-r--r--lib/libedit/refresh.h59
-rw-r--r--lib/libedit/search.c631
-rw-r--r--lib/libedit/search.h66
-rw-r--r--lib/libedit/sig.c192
-rw-r--r--lib/libedit/sig.h69
-rw-r--r--lib/libedit/sys.h109
-rw-r--r--lib/libedit/term.c1588
-rw-r--r--lib/libedit/term.h123
-rw-r--r--lib/libedit/tokenizer.c445
-rw-r--r--lib/libedit/tty.c1254
-rw-r--r--lib/libedit/tty.h480
-rw-r--r--lib/libedit/vi.c1120
-rw-r--r--lib/libexpat/Makefile27
-rw-r--r--lib/libexpat/expat_config.h89
-rw-r--r--lib/libexpat/libbsdxml.360
-rw-r--r--lib/libfetch/Makefile76
-rw-r--r--lib/libfetch/common.c736
-rw-r--r--lib/libfetch/common.h124
-rw-r--r--lib/libfetch/fetch.3668
-rw-r--r--lib/libfetch/fetch.c438
-rw-r--r--lib/libfetch/fetch.h150
-rw-r--r--lib/libfetch/file.c146
-rw-r--r--lib/libfetch/ftp.c1159
-rw-r--r--lib/libfetch/ftp.errors47
-rw-r--r--lib/libfetch/http.c1213
-rw-r--r--lib/libfetch/http.errors45
-rw-r--r--lib/libform/Makefile100
-rw-r--r--lib/libftpio/Makefile27
-rw-r--r--lib/libftpio/ftp.errors45
-rw-r--r--lib/libftpio/ftpio.3260
-rw-r--r--lib/libftpio/ftpio.c1070
-rw-r--r--lib/libftpio/ftpio.h71
-rw-r--r--lib/libgeom/Makefile36
-rw-r--r--lib/libgeom/geom_ctl.c238
-rw-r--r--lib/libgeom/geom_getxml.c66
-rw-r--r--lib/libgeom/geom_stats.c185
-rw-r--r--lib/libgeom/geom_xml2tree.c441
-rw-r--r--lib/libgeom/libgeom.3258
-rw-r--r--lib/libgeom/libgeom.h149
-rw-r--r--lib/libgpib/Makefile10
-rw-r--r--lib/libgpib/gpib.h33
-rw-r--r--lib/libgpib/ibfoo.c647
-rw-r--r--lib/libgssapi/Makefile95
-rw-r--r--lib/libgssapi/context.h32
-rw-r--r--lib/libgssapi/cred.h43
-rw-r--r--lib/libgssapi/gss_accept_sec_context.3484
-rw-r--r--lib/libgssapi/gss_accept_sec_context.c221
-rw-r--r--lib/libgssapi/gss_acquire_cred.3238
-rw-r--r--lib/libgssapi/gss_acquire_cred.c166
-rw-r--r--lib/libgssapi/gss_add_cred.3338
-rw-r--r--lib/libgssapi/gss_add_cred.c178
-rw-r--r--lib/libgssapi/gss_add_oid_set_member.3130
-rw-r--r--lib/libgssapi/gss_add_oid_set_member.c77
-rw-r--r--lib/libgssapi/gss_canonicalize_name.3137
-rw-r--r--lib/libgssapi/gss_canonicalize_name.c91
-rw-r--r--lib/libgssapi/gss_compare_name.3122
-rw-r--r--lib/libgssapi/gss_compare_name.c76
-rw-r--r--lib/libgssapi/gss_context_time.3108
-rw-r--r--lib/libgssapi/gss_context_time.c43
-rw-r--r--lib/libgssapi/gss_create_empty_oid_set.3112
-rw-r--r--lib/libgssapi/gss_create_empty_oid_set.c53
-rw-r--r--lib/libgssapi/gss_delete_sec_context.3163
-rw-r--r--lib/libgssapi/gss_delete_sec_context.c62
-rw-r--r--lib/libgssapi/gss_display_name.3151
-rw-r--r--lib/libgssapi/gss_display_name.c78
-rw-r--r--lib/libgssapi/gss_display_status.3210
-rw-r--r--lib/libgssapi/gss_display_status.c110
-rw-r--r--lib/libgssapi/gss_duplicate_name.3123
-rw-r--r--lib/libgssapi/gss_duplicate_name.c78
-rw-r--r--lib/libgssapi/gss_export_name.3128
-rw-r--r--lib/libgssapi/gss_export_name.c58
-rw-r--r--lib/libgssapi/gss_export_sec_context.3168
-rw-r--r--lib/libgssapi/gss_export_sec_context.c77
-rw-r--r--lib/libgssapi/gss_get_mic.3165
-rw-r--r--lib/libgssapi/gss_get_mic.c46
-rw-r--r--lib/libgssapi/gss_import_name.3139
-rw-r--r--lib/libgssapi/gss_import_name.c219
-rw-r--r--lib/libgssapi/gss_import_sec_context.3120
-rw-r--r--lib/libgssapi/gss_import_sec_context.c86
-rw-r--r--lib/libgssapi/gss_indicate_mechs.3107
-rw-r--r--lib/libgssapi/gss_indicate_mechs.c60
-rw-r--r--lib/libgssapi/gss_init_sec_context.3571
-rw-r--r--lib/libgssapi/gss_init_sec_context.c129
-rw-r--r--lib/libgssapi/gss_inquire_context.3284
-rw-r--r--lib/libgssapi/gss_inquire_context.c88
-rw-r--r--lib/libgssapi/gss_inquire_cred.3158
-rw-r--r--lib/libgssapi/gss_inquire_cred.c167
-rw-r--r--lib/libgssapi/gss_inquire_cred_by_mech.3173
-rw-r--r--lib/libgssapi/gss_inquire_cred_by_mech.c82
-rw-r--r--lib/libgssapi/gss_inquire_mechs_for_name.3134
-rw-r--r--lib/libgssapi/gss_inquire_mechs_for_name.c77
-rw-r--r--lib/libgssapi/gss_inquire_names_for_mech.3107
-rw-r--r--lib/libgssapi/gss_inquire_names_for_mech.c74
-rw-r--r--lib/libgssapi/gss_krb5.c87
-rw-r--r--lib/libgssapi/gss_mech_switch.c301
-rw-r--r--lib/libgssapi/gss_names.c253
-rw-r--r--lib/libgssapi/gss_process_context_token.3136
-rw-r--r--lib/libgssapi/gss_process_context_token.c44
-rw-r--r--lib/libgssapi/gss_release_buffer.3111
-rw-r--r--lib/libgssapi/gss_release_buffer.c43
-rw-r--r--lib/libgssapi/gss_release_cred.3108
-rw-r--r--lib/libgssapi/gss_release_cred.c56
-rw-r--r--lib/libgssapi/gss_release_name.3104
-rw-r--r--lib/libgssapi/gss_release_name.c59
-rw-r--r--lib/libgssapi/gss_release_oid_set.3109
-rw-r--r--lib/libgssapi/gss_release_oid_set.c46
-rw-r--r--lib/libgssapi/gss_seal.c45
-rw-r--r--lib/libgssapi/gss_sign.c41
-rw-r--r--lib/libgssapi/gss_test_oid_set_member.3116
-rw-r--r--lib/libgssapi/gss_test_oid_set_member.c56
-rw-r--r--lib/libgssapi/gss_unseal.c43
-rw-r--r--lib/libgssapi/gss_unwrap.3191
-rw-r--r--lib/libgssapi/gss_unwrap.c48
-rw-r--r--lib/libgssapi/gss_utils.c79
-rw-r--r--lib/libgssapi/gss_verify.c41
-rw-r--r--lib/libgssapi/gss_verify_mic.3172
-rw-r--r--lib/libgssapi/gss_verify_mic.c46
-rw-r--r--lib/libgssapi/gss_wrap.3178
-rw-r--r--lib/libgssapi/gss_wrap.c49
-rw-r--r--lib/libgssapi/gss_wrap_size_limit.3163
-rw-r--r--lib/libgssapi/gss_wrap_size_limit.c47
-rw-r--r--lib/libgssapi/gssapi.3261
-rw-r--r--lib/libgssapi/mech.594
-rw-r--r--lib/libgssapi/mech_switch.h327
-rw-r--r--lib/libgssapi/name.h48
-rw-r--r--lib/libgssapi/spnego.h34
-rw-r--r--lib/libgssapi/utils.h32
-rw-r--r--lib/libio/Makefile9
-rw-r--r--lib/libio/alpha_sethae.c46
-rw-r--r--lib/libio/bwx.c244
-rw-r--r--lib/libio/io.c173
-rw-r--r--lib/libio/io.h48
-rw-r--r--lib/libio/swiz.c248
-rw-r--r--lib/libipsec/Makefile58
-rw-r--r--lib/libipsec/ipsec_dump_policy.c306
-rw-r--r--lib/libipsec/ipsec_get_policylen.c49
-rw-r--r--lib/libipsec/ipsec_set_policy.3335
-rw-r--r--lib/libipsec/ipsec_strerror.390
-rw-r--r--lib/libipsec/ipsec_strerror.c90
-rw-r--r--lib/libipsec/ipsec_strerror.h63
-rw-r--r--lib/libipsec/libpfkey.h86
-rw-r--r--lib/libipsec/pfkey.c2125
-rw-r--r--lib/libipsec/pfkey_dump.c632
-rw-r--r--lib/libipsec/policy_parse.y439
-rw-r--r--lib/libipsec/policy_token.l155
-rw-r--r--lib/libipsec/test-policy.c334
-rw-r--r--lib/libipx/Makefile9
-rw-r--r--lib/libipx/ipx.3129
-rw-r--r--lib/libipx/ipx_addr.c231
-rw-r--r--lib/libipx/ipx_ntoa.c103
-rw-r--r--lib/libkiconv/Makefile18
-rw-r--r--lib/libkiconv/kiconv.3130
-rw-r--r--lib/libkiconv/quirks.c192
-rw-r--r--lib/libkiconv/quirks.h45
-rw-r--r--lib/libkiconv/xlat16_iconv.c399
-rw-r--r--lib/libkiconv/xlat16_sysctl.c81
-rw-r--r--lib/libkse/Makefile54
-rw-r--r--lib/libkse/arch/amd64/Makefile.inc5
-rw-r--r--lib/libkse/arch/amd64/amd64/context.S217
-rw-r--r--lib/libkse/arch/amd64/amd64/enter_uts.S41
-rw-r--r--lib/libkse/arch/amd64/amd64/pthread_md.c82
-rw-r--r--lib/libkse/arch/amd64/include/atomic_ops.h57
-rw-r--r--lib/libkse/arch/amd64/include/pthread_md.h268
-rw-r--r--lib/libkse/arch/arm/Makefile.inc7
-rw-r--r--lib/libkse/arch/arm/arm/context.S79
-rw-r--r--lib/libkse/arch/arm/arm/pthread_md.c86
-rw-r--r--lib/libkse/arch/arm/include/atomic_ops.h53
-rw-r--r--lib/libkse/arch/arm/include/pthread_md.h257
-rw-r--r--lib/libkse/arch/i386/Makefile.inc5
-rw-r--r--lib/libkse/arch/i386/i386/pthread_md.c100
-rw-r--r--lib/libkse/arch/i386/i386/thr_enter_uts.S44
-rw-r--r--lib/libkse/arch/i386/i386/thr_getcontext.S156
-rw-r--r--lib/libkse/arch/i386/include/atomic_ops.h51
-rw-r--r--lib/libkse/arch/i386/include/pthread_md.h264
-rw-r--r--lib/libkse/arch/ia64/Makefile.inc5
-rw-r--r--lib/libkse/arch/ia64/ia64/context.S351
-rw-r--r--lib/libkse/arch/ia64/ia64/enter_uts.S60
-rw-r--r--lib/libkse/arch/ia64/ia64/pthread_md.c75
-rw-r--r--lib/libkse/arch/ia64/include/atomic_ops.h47
-rw-r--r--lib/libkse/arch/ia64/include/pthread_md.h252
-rw-r--r--lib/libkse/arch/powerpc/Makefile.inc8
-rw-r--r--lib/libkse/arch/powerpc/include/atomic_ops.h62
-rw-r--r--lib/libkse/arch/powerpc/include/pthread_md.h258
-rw-r--r--lib/libkse/arch/powerpc/powerpc/assym.c113
-rw-r--r--lib/libkse/arch/powerpc/powerpc/assym.s113
-rw-r--r--lib/libkse/arch/powerpc/powerpc/context.S151
-rw-r--r--lib/libkse/arch/powerpc/powerpc/enter_uts.S40
-rw-r--r--lib/libkse/arch/powerpc/powerpc/pthread_md.c76
-rw-r--r--lib/libkse/arch/sparc64/Makefile.inc5
-rw-r--r--lib/libkse/arch/sparc64/include/atomic_ops.h75
-rw-r--r--lib/libkse/arch/sparc64/include/pthread_md.h254
-rw-r--r--lib/libkse/arch/sparc64/sparc64/assym.s15
-rw-r--r--lib/libkse/arch/sparc64/sparc64/pthread_md.c91
-rw-r--r--lib/libkse/arch/sparc64/sparc64/thr_getcontext.S87
-rw-r--r--lib/libkse/support/Makefile.inc40
-rw-r--r--lib/libkse/support/thr_support.c62
-rw-r--r--lib/libkse/sys/Makefile.inc5
-rw-r--r--lib/libkse/sys/lock.c351
-rw-r--r--lib/libkse/sys/lock.h95
-rw-r--r--lib/libkse/sys/thr_error.c61
-rw-r--r--lib/libkse/test/Makefile116
-rw-r--r--lib/libkse/test/README28
-rw-r--r--lib/libkse/test/guard_b.c152
-rw-r--r--lib/libkse/test/guard_b.exp3
-rw-r--r--lib/libkse/test/guard_s.pl69
-rw-r--r--lib/libkse/test/hello_b.c13
-rw-r--r--lib/libkse/test/hello_d.c38
-rw-r--r--lib/libkse/test/hello_d.exp1
-rw-r--r--lib/libkse/test/hello_s.c47
-rw-r--r--lib/libkse/test/join_leak_d.c108
-rw-r--r--lib/libkse/test/join_leak_d.exp2
-rw-r--r--lib/libkse/test/mutex_d.c1558
-rw-r--r--lib/libkse/test/mutex_d.exp290
-rw-r--r--lib/libkse/test/propagate_s.pl74
-rw-r--r--lib/libkse/test/sem_d.c133
-rw-r--r--lib/libkse/test/sem_d.exp22
-rw-r--r--lib/libkse/test/sigsuspend_d.c290
-rw-r--r--lib/libkse/test/sigsuspend_d.exp8
-rw-r--r--lib/libkse/test/sigwait_d.c304
-rw-r--r--lib/libkse/test/sigwait_d.exp10
-rw-r--r--lib/libkse/test/verify474
-rw-r--r--lib/libkse/thread/Makefile.inc117
-rw-r--r--lib/libkse/thread/thr_accept.c52
-rw-r--r--lib/libkse/thread/thr_aio_suspend.c54
-rw-r--r--lib/libkse/thread/thr_atfork.c59
-rw-r--r--lib/libkse/thread/thr_attr_destroy.c65
-rw-r--r--lib/libkse/thread/thr_attr_get_np.c57
-rw-r--r--lib/libkse/thread/thr_attr_getdetachstate.c62
-rw-r--r--lib/libkse/thread/thr_attr_getguardsize.c55
-rw-r--r--lib/libkse/thread/thr_attr_getinheritsched.c54
-rw-r--r--lib/libkse/thread/thr_attr_getschedparam.c54
-rw-r--r--lib/libkse/thread/thr_attr_getschedpolicy.c54
-rw-r--r--lib/libkse/thread/thr_attr_getscope.c57
-rw-r--r--lib/libkse/thread/thr_attr_getstack.c62
-rw-r--r--lib/libkse/thread/thr_attr_getstackaddr.c57
-rw-r--r--lib/libkse/thread/thr_attr_getstacksize.c57
-rw-r--r--lib/libkse/thread/thr_attr_init.c67
-rw-r--r--lib/libkse/thread/thr_attr_setcreatesuspend_np.c55
-rw-r--r--lib/libkse/thread/thr_attr_setdetachstate.c64
-rw-r--r--lib/libkse/thread/thr_attr_setguardsize.c56
-rw-r--r--lib/libkse/thread/thr_attr_setinheritsched.c57
-rw-r--r--lib/libkse/thread/thr_attr_setschedparam.c60
-rw-r--r--lib/libkse/thread/thr_attr_setschedpolicy.c56
-rw-r--r--lib/libkse/thread/thr_attr_setscope.c60
-rw-r--r--lib/libkse/thread/thr_attr_setstack.c61
-rw-r--r--lib/libkse/thread/thr_attr_setstackaddr.c57
-rw-r--r--lib/libkse/thread/thr_attr_setstacksize.c57
-rw-r--r--lib/libkse/thread/thr_autoinit.c64
-rw-r--r--lib/libkse/thread/thr_barrier.c129
-rw-r--r--lib/libkse/thread/thr_barrierattr.c102
-rw-r--r--lib/libkse/thread/thr_cancel.c311
-rw-r--r--lib/libkse/thread/thr_clean.c79
-rw-r--r--lib/libkse/thread/thr_close.c58
-rw-r--r--lib/libkse/thread/thr_concurrency.c177
-rw-r--r--lib/libkse/thread/thr_cond.c847
-rw-r--r--lib/libkse/thread/thr_condattr_destroy.c56
-rw-r--r--lib/libkse/thread/thr_condattr_init.c61
-rw-r--r--lib/libkse/thread/thr_condattr_pshared.c56
-rw-r--r--lib/libkse/thread/thr_connect.c52
-rw-r--r--lib/libkse/thread/thr_creat.c58
-rw-r--r--lib/libkse/thread/thr_create.c348
-rw-r--r--lib/libkse/thread/thr_detach.c120
-rw-r--r--lib/libkse/thread/thr_equal.c47
-rw-r--r--lib/libkse/thread/thr_execve.c66
-rw-r--r--lib/libkse/thread/thr_exit.c162
-rw-r--r--lib/libkse/thread/thr_fcntl.c81
-rw-r--r--lib/libkse/thread/thr_find_thread.c98
-rw-r--r--lib/libkse/thread/thr_fork.c131
-rw-r--r--lib/libkse/thread/thr_fsync.c54
-rw-r--r--lib/libkse/thread/thr_getprio.c63
-rw-r--r--lib/libkse/thread/thr_getschedparam.c78
-rw-r--r--lib/libkse/thread/thr_info.c228
-rw-r--r--lib/libkse/thread/thr_init.c533
-rw-r--r--lib/libkse/thread/thr_join.c165
-rw-r--r--lib/libkse/thread/thr_kern.c2551
-rw-r--r--lib/libkse/thread/thr_kill.c69
-rw-r--r--lib/libkse/thread/thr_main_np.c50
-rw-r--r--lib/libkse/thread/thr_mattr_init.c61
-rw-r--r--lib/libkse/thread/thr_mattr_kind_np.c106
-rw-r--r--lib/libkse/thread/thr_mattr_pshared.c56
-rw-r--r--lib/libkse/thread/thr_msync.c36
-rw-r--r--lib/libkse/thread/thr_multi_np.c55
-rw-r--r--lib/libkse/thread/thr_mutex.c1832
-rw-r--r--lib/libkse/thread/thr_mutex_prioceiling.c124
-rw-r--r--lib/libkse/thread/thr_mutex_protocol.c75
-rw-r--r--lib/libkse/thread/thr_mutexattr_destroy.c56
-rw-r--r--lib/libkse/thread/thr_nanosleep.c135
-rw-r--r--lib/libkse/thread/thr_once.c101
-rw-r--r--lib/libkse/thread/thr_open.c74
-rw-r--r--lib/libkse/thread/thr_pause.c54
-rw-r--r--lib/libkse/thread/thr_poll.c60
-rw-r--r--lib/libkse/thread/thr_printf.c135
-rw-r--r--lib/libkse/thread/thr_priority_queue.c324
-rw-r--r--lib/libkse/thread/thr_private.h1320
-rw-r--r--lib/libkse/thread/thr_pselect.c60
-rw-r--r--lib/libkse/thread/thr_pspinlock.c174
-rw-r--r--lib/libkse/thread/thr_raise.c56
-rw-r--r--lib/libkse/thread/thr_read.c59
-rw-r--r--lib/libkse/thread/thr_readv.c59
-rw-r--r--lib/libkse/thread/thr_resume_np.c112
-rw-r--r--lib/libkse/thread/thr_rtld.c302
-rw-r--r--lib/libkse/thread/thr_rwlock.c438
-rw-r--r--lib/libkse/thread/thr_rwlockattr.c107
-rw-r--r--lib/libkse/thread/thr_select.c68
-rw-r--r--lib/libkse/thread/thr_self.c50
-rw-r--r--lib/libkse/thread/thr_sem.c267
-rw-r--r--lib/libkse/thread/thr_seterrno.c59
-rw-r--r--lib/libkse/thread/thr_setprio.c55
-rw-r--r--lib/libkse/thread/thr_setschedparam.c139
-rw-r--r--lib/libkse/thread/thr_sig.c1259
-rw-r--r--lib/libkse/thread/thr_sigaction.c120
-rw-r--r--lib/libkse/thread/thr_sigaltstack.c110
-rw-r--r--lib/libkse/thread/thr_sigmask.c116
-rw-r--r--lib/libkse/thread/thr_sigpending.c76
-rw-r--r--lib/libkse/thread/thr_sigprocmask.c58
-rw-r--r--lib/libkse/thread/thr_sigsuspend.c113
-rw-r--r--lib/libkse/thread/thr_sigwait.c212
-rw-r--r--lib/libkse/thread/thr_single_np.c54
-rw-r--r--lib/libkse/thread/thr_sleep.c71
-rw-r--r--lib/libkse/thread/thr_spec.c243
-rw-r--r--lib/libkse/thread/thr_spinlock.c152
-rw-r--r--lib/libkse/thread/thr_stack.c258
-rw-r--r--lib/libkse/thread/thr_suspend_np.c114
-rw-r--r--lib/libkse/thread/thr_switch_np.c57
-rw-r--r--lib/libkse/thread/thr_symbols.c81
-rw-r--r--lib/libkse/thread/thr_system.c54
-rw-r--r--lib/libkse/thread/thr_tcdrain.c54
-rw-r--r--lib/libkse/thread/thr_vfork.c17
-rw-r--r--lib/libkse/thread/thr_wait.c53
-rw-r--r--lib/libkse/thread/thr_wait4.c60
-rw-r--r--lib/libkse/thread/thr_waitpid.c55
-rw-r--r--lib/libkse/thread/thr_write.c59
-rw-r--r--lib/libkse/thread/thr_writev.c61
-rw-r--r--lib/libkse/thread/thr_yield.c78
-rw-r--r--lib/libkvm/Makefile21
-rw-r--r--lib/libkvm/kvm.3120
-rw-r--r--lib/libkvm/kvm.c442
-rw-r--r--lib/libkvm/kvm.h95
-rw-r--r--lib/libkvm/kvm_alpha.c213
-rw-r--r--lib/libkvm/kvm_amd64.c352
-rw-r--r--lib/libkvm/kvm_arm.c247
-rw-r--r--lib/libkvm/kvm_file.c192
-rw-r--r--lib/libkvm/kvm_geterr.382
-rw-r--r--lib/libkvm/kvm_getfiles.391
-rw-r--r--lib/libkvm/kvm_getloadavg.366
-rw-r--r--lib/libkvm/kvm_getloadavg.c106
-rw-r--r--lib/libkvm/kvm_getprocs.3185
-rw-r--r--lib/libkvm/kvm_getswapinfo.3111
-rw-r--r--lib/libkvm/kvm_getswapinfo.c188
-rw-r--r--lib/libkvm/kvm_i386.c448
-rw-r--r--lib/libkvm/kvm_ia64.c209
-rw-r--r--lib/libkvm/kvm_minidump_amd64.c255
-rw-r--r--lib/libkvm/kvm_minidump_i386.c294
-rw-r--r--lib/libkvm/kvm_nlist.389
-rw-r--r--lib/libkvm/kvm_open.3209
-rw-r--r--lib/libkvm/kvm_powerpc.c103
-rw-r--r--lib/libkvm/kvm_private.h89
-rw-r--r--lib/libkvm/kvm_proc.c1024
-rw-r--r--lib/libkvm/kvm_read.396
-rw-r--r--lib/libkvm/kvm_sparc.c240
-rw-r--r--lib/libkvm/kvm_sparc64.c225
-rw-r--r--lib/libmagic/Makefile56
-rw-r--r--lib/libmagic/config.h215
-rw-r--r--lib/libmd/Makefile197
-rw-r--r--lib/libmd/i386/rmd160.S2018
-rw-r--r--lib/libmd/i386/sha.S1951
-rw-r--r--lib/libmd/md2.copyright17
-rw-r--r--lib/libmd/md2.h46
-rw-r--r--lib/libmd/md2c.c211
-rw-r--r--lib/libmd/md4.copyright20
-rw-r--r--lib/libmd/md4.h48
-rw-r--r--lib/libmd/md4c.c292
-rw-r--r--lib/libmd/md5.copyright21
-rw-r--r--lib/libmd/md5.h4
-rw-r--r--lib/libmd/md5c.c337
-rw-r--r--lib/libmd/mdX.3202
-rw-r--r--lib/libmd/mdXhl.c98
-rw-r--r--lib/libmd/mddriver.c72
-rw-r--r--lib/libmd/ripemd.3141
-rw-r--r--lib/libmd/ripemd.h94
-rw-r--r--lib/libmd/rmd160c.c547
-rw-r--r--lib/libmd/rmd_locl.h216
-rw-r--r--lib/libmd/rmdconst.h399
-rw-r--r--lib/libmd/rmddriver.c53
-rw-r--r--lib/libmd/sha.3185
-rw-r--r--lib/libmd/sha.h98
-rw-r--r--lib/libmd/sha0c.c454
-rw-r--r--lib/libmd/sha1c.c490
-rw-r--r--lib/libmd/sha256.3139
-rw-r--r--lib/libmd/sha256.h50
-rw-r--r--lib/libmd/sha256c.c300
-rw-r--r--lib/libmd/sha_locl.h243
-rw-r--r--lib/libmd/shadriver.c66
-rw-r--r--lib/libmemstat/Makefile30
-rw-r--r--lib/libmemstat/libmemstat.3496
-rw-r--r--lib/libmemstat/memstat.c421
-rw-r--r--lib/libmemstat/memstat.h174
-rw-r--r--lib/libmemstat/memstat_all.c58
-rw-r--r--lib/libmemstat/memstat_internal.h124
-rw-r--r--lib/libmemstat/memstat_malloc.c408
-rw-r--r--lib/libmemstat/memstat_uma.c465
-rw-r--r--lib/libmenu/Makefile84
-rw-r--r--lib/libmilter/Makefile32
-rw-r--r--lib/libmp/Makefile14
-rw-r--r--lib/libmp/libmp.3322
-rw-r--r--lib/libmp/mp.h32
-rw-r--r--lib/libmp/mpasbn.c590
-rw-r--r--lib/libncp/CREDITS27
-rw-r--r--lib/libncp/Makefile14
-rw-r--r--lib/libncp/ipx.c355
-rw-r--r--lib/libncp/ipxsap.h95
-rw-r--r--lib/libncp/ncpl_bind.c270
-rw-r--r--lib/libncp/ncpl_conn.c514
-rw-r--r--lib/libncp/ncpl_crypt.c139
-rw-r--r--lib/libncp/ncpl_file.c266
-rw-r--r--lib/libncp/ncpl_misc.c296
-rw-r--r--lib/libncp/ncpl_msg.c133
-rw-r--r--lib/libncp/ncpl_net.c150
-rw-r--r--lib/libncp/ncpl_nls.c350
-rw-r--r--lib/libncp/ncpl_queue.c224
-rw-r--r--lib/libncp/ncpl_rcfile.c409
-rw-r--r--lib/libncp/ncpl_rpc.c139
-rw-r--r--lib/libncp/ncpl_subr.c493
-rw-r--r--lib/libncp/sap.c304
-rw-r--r--lib/libncurses/Makefile564
-rw-r--r--lib/libncurses/ncurses_cfg.h155
-rw-r--r--lib/libncurses/pathnames.h38
-rw-r--r--lib/libncurses/termcap.c267
-rw-r--r--lib/libnetgraph/Makefile28
-rw-r--r--lib/libnetgraph/debug.c346
-rw-r--r--lib/libnetgraph/internal.h74
-rw-r--r--lib/libnetgraph/msg.c378
-rw-r--r--lib/libnetgraph/netgraph.3398
-rw-r--r--lib/libnetgraph/netgraph.h69
-rw-r--r--lib/libnetgraph/sock.c300
-rw-r--r--lib/libngatm/Makefile54
-rw-r--r--lib/libopie/Makefile36
-rw-r--r--lib/libopie/config.h381
-rw-r--r--lib/libopie/opieextra.c98
-rw-r--r--lib/libpam/Makefile31
-rw-r--r--lib/libpam/Makefile.inc32
-rw-r--r--lib/libpam/libpam/Makefile168
-rw-r--r--lib/libpam/libpam/pam_debug_log.c62
-rw-r--r--lib/libpam/libpam/pam_std_option.c178
-rw-r--r--lib/libpam/libpam/security/pam_mod_misc.h56
-rw-r--r--lib/libpam/modules/Makefile31
-rw-r--r--lib/libpam/modules/Makefile.inc22
-rw-r--r--lib/libpam/modules/modules.inc33
-rw-r--r--lib/libpam/modules/pam_chroot/Makefile7
-rw-r--r--lib/libpam/modules/pam_chroot/pam_chroot.894
-rw-r--r--lib/libpam/modules/pam_chroot/pam_chroot.c109
-rw-r--r--lib/libpam/modules/pam_deny/Makefile31
-rw-r--r--lib/libpam/modules/pam_deny/pam_deny.880
-rw-r--r--lib/libpam/modules/pam_deny/pam_deny.c93
-rw-r--r--lib/libpam/modules/pam_echo/Makefile7
-rw-r--r--lib/libpam/modules/pam_echo/pam_echo.893
-rw-r--r--lib/libpam/modules/pam_echo/pam_echo.c156
-rw-r--r--lib/libpam/modules/pam_exec/Makefile9
-rw-r--r--lib/libpam/modules/pam_exec/pam_exec.875
-rw-r--r--lib/libpam/modules/pam_exec/pam_exec.c198
-rw-r--r--lib/libpam/modules/pam_ftpusers/Makefile7
-rw-r--r--lib/libpam/modules/pam_ftpusers/pam_ftpusers.899
-rw-r--r--lib/libpam/modules/pam_ftpusers/pam_ftpusers.c115
-rw-r--r--lib/libpam/modules/pam_group/Makefile7
-rw-r--r--lib/libpam/modules/pam_group/pam_group.883
-rw-r--r--lib/libpam/modules/pam_group/pam_group.c117
-rw-r--r--lib/libpam/modules/pam_guest/Makefile7
-rw-r--r--lib/libpam/modules/pam_guest/pam_guest.898
-rw-r--r--lib/libpam/modules/pam_guest/pam_guest.c114
-rw-r--r--lib/libpam/modules/pam_krb5/Makefile38
-rw-r--r--lib/libpam/modules/pam_krb5/pam_krb5.8217
-rw-r--r--lib/libpam/modules/pam_krb5/pam_krb5.c971
-rw-r--r--lib/libpam/modules/pam_ksu/Makefile34
-rw-r--r--lib/libpam/modules/pam_ksu/pam_ksu.8122
-rw-r--r--lib/libpam/modules/pam_ksu/pam_ksu.c256
-rw-r--r--lib/libpam/modules/pam_lastlog/Makefile34
-rw-r--r--lib/libpam/modules/pam_lastlog/pam_lastlog.8106
-rw-r--r--lib/libpam/modules/pam_lastlog/pam_lastlog.c187
-rw-r--r--lib/libpam/modules/pam_login_access/Makefile31
-rw-r--r--lib/libpam/modules/pam_login_access/login.access.558
-rw-r--r--lib/libpam/modules/pam_login_access/login_access.c231
-rw-r--r--lib/libpam/modules/pam_login_access/pam_login_access.889
-rw-r--r--lib/libpam/modules/pam_login_access/pam_login_access.c101
-rw-r--r--lib/libpam/modules/pam_login_access/pam_login_access.h39
-rw-r--r--lib/libpam/modules/pam_nologin/Makefile34
-rw-r--r--lib/libpam/modules/pam_nologin/pam_nologin.890
-rw-r--r--lib/libpam/modules/pam_nologin/pam_nologin.c122
-rw-r--r--lib/libpam/modules/pam_opie/Makefile35
-rw-r--r--lib/libpam/modules/pam_opie/pam_opie.8123
-rw-r--r--lib/libpam/modules/pam_opie/pam_opie.c146
-rw-r--r--lib/libpam/modules/pam_opieaccess/Makefile10
-rw-r--r--lib/libpam/modules/pam_opieaccess/pam_opieaccess.8140
-rw-r--r--lib/libpam/modules/pam_opieaccess/pam_opieaccess.c95
-rw-r--r--lib/libpam/modules/pam_passwdqc/Makefile17
-rw-r--r--lib/libpam/modules/pam_passwdqc/pam_passwdqc.8268
-rw-r--r--lib/libpam/modules/pam_permit/Makefile31
-rw-r--r--lib/libpam/modules/pam_permit/pam_permit.875
-rw-r--r--lib/libpam/modules/pam_permit/pam_permit.c93
-rw-r--r--lib/libpam/modules/pam_radius/Makefile35
-rw-r--r--lib/libpam/modules/pam_radius/pam_radius.8138
-rw-r--r--lib/libpam/modules/pam_radius/pam_radius.c364
-rw-r--r--lib/libpam/modules/pam_rhosts/Makefile7
-rw-r--r--lib/libpam/modules/pam_rhosts/pam_rhosts.895
-rw-r--r--lib/libpam/modules/pam_rhosts/pam_rhosts.c95
-rw-r--r--lib/libpam/modules/pam_rootok/Makefile31
-rw-r--r--lib/libpam/modules/pam_rootok/pam_rootok.875
-rw-r--r--lib/libpam/modules/pam_rootok/pam_rootok.c73
-rw-r--r--lib/libpam/modules/pam_securetty/Makefile31
-rw-r--r--lib/libpam/modules/pam_securetty/pam_securetty.892
-rw-r--r--lib/libpam/modules/pam_securetty/pam_securetty.c96
-rw-r--r--lib/libpam/modules/pam_self/Makefile31
-rw-r--r--lib/libpam/modules/pam_self/pam_self.896
-rw-r--r--lib/libpam/modules/pam_self/pam_self.c89
-rw-r--r--lib/libpam/modules/pam_ssh/Makefile20
-rw-r--r--lib/libpam/modules/pam_ssh/pam_ssh.8157
-rw-r--r--lib/libpam/modules/pam_ssh/pam_ssh.c424
-rw-r--r--lib/libpam/modules/pam_tacplus/Makefile34
-rw-r--r--lib/libpam/modules/pam_tacplus/pam_tacplus.8130
-rw-r--r--lib/libpam/modules/pam_tacplus/pam_tacplus.c281
-rw-r--r--lib/libpam/modules/pam_unix/Makefile53
-rw-r--r--lib/libpam/modules/pam_unix/pam_unix.8201
-rw-r--r--lib/libpam/modules/pam_unix/pam_unix.c465
-rw-r--r--lib/libpanel/Makefile48
-rw-r--r--lib/libpcap/Makefile47
-rw-r--r--lib/libpcap/config.h181
-rw-r--r--lib/libpmc/Makefile51
-rw-r--r--lib/libpmc/libpmc.c2237
-rw-r--r--lib/libpmc/pmc.33421
-rw-r--r--lib/libpmc/pmc.h109
-rw-r--r--lib/libpmc/pmclog.3320
-rw-r--r--lib/libpmc/pmclog.c553
-rw-r--r--lib/libpmc/pmclog.h154
-rw-r--r--lib/libpthread/Makefile54
-rw-r--r--lib/libpthread/arch/alpha/Makefile.inc5
-rw-r--r--lib/libpthread/arch/alpha/alpha/context.S353
-rw-r--r--lib/libpthread/arch/alpha/alpha/enter_uts.S42
-rw-r--r--lib/libpthread/arch/alpha/alpha/pthread_md.c76
-rw-r--r--lib/libpthread/arch/alpha/include/atomic_ops.h75
-rw-r--r--lib/libpthread/arch/alpha/include/pthread_md.h247
-rw-r--r--lib/libpthread/arch/amd64/Makefile.inc5
-rw-r--r--lib/libpthread/arch/amd64/amd64/context.S217
-rw-r--r--lib/libpthread/arch/amd64/amd64/enter_uts.S41
-rw-r--r--lib/libpthread/arch/amd64/amd64/pthread_md.c82
-rw-r--r--lib/libpthread/arch/amd64/include/atomic_ops.h57
-rw-r--r--lib/libpthread/arch/amd64/include/pthread_md.h268
-rw-r--r--lib/libpthread/arch/arm/Makefile.inc7
-rw-r--r--lib/libpthread/arch/arm/arm/context.S79
-rw-r--r--lib/libpthread/arch/arm/arm/pthread_md.c86
-rw-r--r--lib/libpthread/arch/arm/include/atomic_ops.h53
-rw-r--r--lib/libpthread/arch/arm/include/pthread_md.h257
-rw-r--r--lib/libpthread/arch/i386/Makefile.inc5
-rw-r--r--lib/libpthread/arch/i386/i386/pthread_md.c100
-rw-r--r--lib/libpthread/arch/i386/i386/thr_enter_uts.S44
-rw-r--r--lib/libpthread/arch/i386/i386/thr_getcontext.S156
-rw-r--r--lib/libpthread/arch/i386/include/atomic_ops.h51
-rw-r--r--lib/libpthread/arch/i386/include/pthread_md.h264
-rw-r--r--lib/libpthread/arch/ia64/Makefile.inc5
-rw-r--r--lib/libpthread/arch/ia64/ia64/context.S351
-rw-r--r--lib/libpthread/arch/ia64/ia64/enter_uts.S60
-rw-r--r--lib/libpthread/arch/ia64/ia64/pthread_md.c75
-rw-r--r--lib/libpthread/arch/ia64/include/atomic_ops.h47
-rw-r--r--lib/libpthread/arch/ia64/include/pthread_md.h252
-rw-r--r--lib/libpthread/arch/powerpc/Makefile.inc8
-rw-r--r--lib/libpthread/arch/powerpc/include/atomic_ops.h62
-rw-r--r--lib/libpthread/arch/powerpc/include/pthread_md.h258
-rw-r--r--lib/libpthread/arch/powerpc/powerpc/assym.c113
-rw-r--r--lib/libpthread/arch/powerpc/powerpc/assym.s113
-rw-r--r--lib/libpthread/arch/powerpc/powerpc/context.S151
-rw-r--r--lib/libpthread/arch/powerpc/powerpc/enter_uts.S40
-rw-r--r--lib/libpthread/arch/powerpc/powerpc/pthread_md.c76
-rw-r--r--lib/libpthread/arch/sparc64/Makefile.inc5
-rw-r--r--lib/libpthread/arch/sparc64/include/atomic_ops.h75
-rw-r--r--lib/libpthread/arch/sparc64/include/pthread_md.h254
-rw-r--r--lib/libpthread/arch/sparc64/sparc64/assym.s15
-rw-r--r--lib/libpthread/arch/sparc64/sparc64/pthread_md.c91
-rw-r--r--lib/libpthread/arch/sparc64/sparc64/thr_getcontext.S87
-rw-r--r--lib/libpthread/pthread.map737
-rw-r--r--lib/libpthread/support/Makefile.inc40
-rw-r--r--lib/libpthread/support/thr_support.c62
-rw-r--r--lib/libpthread/sys/Makefile.inc5
-rw-r--r--lib/libpthread/sys/lock.c351
-rw-r--r--lib/libpthread/sys/lock.h95
-rw-r--r--lib/libpthread/sys/thr_error.c61
-rw-r--r--lib/libpthread/test/Makefile116
-rw-r--r--lib/libpthread/test/README28
-rw-r--r--lib/libpthread/test/guard_b.c152
-rw-r--r--lib/libpthread/test/guard_b.exp3
-rwxr-xr-xlib/libpthread/test/guard_s.pl69
-rw-r--r--lib/libpthread/test/hello_b.c13
-rw-r--r--lib/libpthread/test/hello_d.c38
-rw-r--r--lib/libpthread/test/hello_d.exp1
-rw-r--r--lib/libpthread/test/hello_s.c47
-rw-r--r--lib/libpthread/test/join_leak_d.c108
-rw-r--r--lib/libpthread/test/join_leak_d.exp2
-rw-r--r--lib/libpthread/test/mutex_d.c1558
-rw-r--r--lib/libpthread/test/mutex_d.exp290
-rwxr-xr-xlib/libpthread/test/propagate_s.pl74
-rw-r--r--lib/libpthread/test/sem_d.c133
-rw-r--r--lib/libpthread/test/sem_d.exp22
-rw-r--r--lib/libpthread/test/sigsuspend_d.c290
-rw-r--r--lib/libpthread/test/sigsuspend_d.exp8
-rw-r--r--lib/libpthread/test/sigwait_d.c304
-rw-r--r--lib/libpthread/test/sigwait_d.exp10
-rwxr-xr-xlib/libpthread/test/verify474
-rw-r--r--lib/libpthread/thread/Makefile.inc117
-rw-r--r--lib/libpthread/thread/thr_accept.c52
-rw-r--r--lib/libpthread/thread/thr_aio_suspend.c54
-rw-r--r--lib/libpthread/thread/thr_atfork.c59
-rw-r--r--lib/libpthread/thread/thr_attr_destroy.c65
-rw-r--r--lib/libpthread/thread/thr_attr_get_np.c57
-rw-r--r--lib/libpthread/thread/thr_attr_getdetachstate.c62
-rw-r--r--lib/libpthread/thread/thr_attr_getguardsize.c55
-rw-r--r--lib/libpthread/thread/thr_attr_getinheritsched.c54
-rw-r--r--lib/libpthread/thread/thr_attr_getschedparam.c54
-rw-r--r--lib/libpthread/thread/thr_attr_getschedpolicy.c54
-rw-r--r--lib/libpthread/thread/thr_attr_getscope.c57
-rw-r--r--lib/libpthread/thread/thr_attr_getstack.c62
-rw-r--r--lib/libpthread/thread/thr_attr_getstackaddr.c57
-rw-r--r--lib/libpthread/thread/thr_attr_getstacksize.c57
-rw-r--r--lib/libpthread/thread/thr_attr_init.c67
-rw-r--r--lib/libpthread/thread/thr_attr_setcreatesuspend_np.c55
-rw-r--r--lib/libpthread/thread/thr_attr_setdetachstate.c64
-rw-r--r--lib/libpthread/thread/thr_attr_setguardsize.c56
-rw-r--r--lib/libpthread/thread/thr_attr_setinheritsched.c57
-rw-r--r--lib/libpthread/thread/thr_attr_setschedparam.c60
-rw-r--r--lib/libpthread/thread/thr_attr_setschedpolicy.c56
-rw-r--r--lib/libpthread/thread/thr_attr_setscope.c60
-rw-r--r--lib/libpthread/thread/thr_attr_setstack.c61
-rw-r--r--lib/libpthread/thread/thr_attr_setstackaddr.c57
-rw-r--r--lib/libpthread/thread/thr_attr_setstacksize.c57
-rw-r--r--lib/libpthread/thread/thr_autoinit.c64
-rw-r--r--lib/libpthread/thread/thr_barrier.c129
-rw-r--r--lib/libpthread/thread/thr_barrierattr.c102
-rw-r--r--lib/libpthread/thread/thr_cancel.c311
-rw-r--r--lib/libpthread/thread/thr_clean.c79
-rw-r--r--lib/libpthread/thread/thr_close.c58
-rw-r--r--lib/libpthread/thread/thr_concurrency.c177
-rw-r--r--lib/libpthread/thread/thr_cond.c847
-rw-r--r--lib/libpthread/thread/thr_condattr_destroy.c56
-rw-r--r--lib/libpthread/thread/thr_condattr_init.c61
-rw-r--r--lib/libpthread/thread/thr_condattr_pshared.c56
-rw-r--r--lib/libpthread/thread/thr_connect.c52
-rw-r--r--lib/libpthread/thread/thr_creat.c58
-rw-r--r--lib/libpthread/thread/thr_create.c348
-rw-r--r--lib/libpthread/thread/thr_detach.c120
-rw-r--r--lib/libpthread/thread/thr_equal.c47
-rw-r--r--lib/libpthread/thread/thr_execve.c66
-rw-r--r--lib/libpthread/thread/thr_exit.c162
-rw-r--r--lib/libpthread/thread/thr_fcntl.c81
-rw-r--r--lib/libpthread/thread/thr_find_thread.c98
-rw-r--r--lib/libpthread/thread/thr_fork.c131
-rw-r--r--lib/libpthread/thread/thr_fsync.c54
-rw-r--r--lib/libpthread/thread/thr_getprio.c63
-rw-r--r--lib/libpthread/thread/thr_getschedparam.c78
-rw-r--r--lib/libpthread/thread/thr_info.c228
-rw-r--r--lib/libpthread/thread/thr_init.c533
-rw-r--r--lib/libpthread/thread/thr_join.c165
-rw-r--r--lib/libpthread/thread/thr_kern.c2551
-rw-r--r--lib/libpthread/thread/thr_kill.c69
-rw-r--r--lib/libpthread/thread/thr_main_np.c50
-rw-r--r--lib/libpthread/thread/thr_mattr_init.c61
-rw-r--r--lib/libpthread/thread/thr_mattr_kind_np.c106
-rw-r--r--lib/libpthread/thread/thr_mattr_pshared.c56
-rw-r--r--lib/libpthread/thread/thr_msync.c36
-rw-r--r--lib/libpthread/thread/thr_multi_np.c55
-rw-r--r--lib/libpthread/thread/thr_mutex.c1832
-rw-r--r--lib/libpthread/thread/thr_mutex_prioceiling.c124
-rw-r--r--lib/libpthread/thread/thr_mutex_protocol.c75
-rw-r--r--lib/libpthread/thread/thr_mutexattr_destroy.c56
-rw-r--r--lib/libpthread/thread/thr_nanosleep.c135
-rw-r--r--lib/libpthread/thread/thr_once.c101
-rw-r--r--lib/libpthread/thread/thr_open.c74
-rw-r--r--lib/libpthread/thread/thr_pause.c54
-rw-r--r--lib/libpthread/thread/thr_poll.c60
-rw-r--r--lib/libpthread/thread/thr_printf.c135
-rw-r--r--lib/libpthread/thread/thr_priority_queue.c324
-rw-r--r--lib/libpthread/thread/thr_private.h1320
-rw-r--r--lib/libpthread/thread/thr_pselect.c60
-rw-r--r--lib/libpthread/thread/thr_pspinlock.c174
-rw-r--r--lib/libpthread/thread/thr_raise.c56
-rw-r--r--lib/libpthread/thread/thr_read.c59
-rw-r--r--lib/libpthread/thread/thr_readv.c59
-rw-r--r--lib/libpthread/thread/thr_resume_np.c112
-rw-r--r--lib/libpthread/thread/thr_rtld.c302
-rw-r--r--lib/libpthread/thread/thr_rwlock.c438
-rw-r--r--lib/libpthread/thread/thr_rwlockattr.c107
-rw-r--r--lib/libpthread/thread/thr_select.c68
-rw-r--r--lib/libpthread/thread/thr_self.c50
-rw-r--r--lib/libpthread/thread/thr_sem.c267
-rw-r--r--lib/libpthread/thread/thr_seterrno.c59
-rw-r--r--lib/libpthread/thread/thr_setprio.c55
-rw-r--r--lib/libpthread/thread/thr_setschedparam.c139
-rw-r--r--lib/libpthread/thread/thr_sig.c1259
-rw-r--r--lib/libpthread/thread/thr_sigaction.c120
-rw-r--r--lib/libpthread/thread/thr_sigaltstack.c110
-rw-r--r--lib/libpthread/thread/thr_sigmask.c116
-rw-r--r--lib/libpthread/thread/thr_sigpending.c76
-rw-r--r--lib/libpthread/thread/thr_sigprocmask.c58
-rw-r--r--lib/libpthread/thread/thr_sigsuspend.c113
-rw-r--r--lib/libpthread/thread/thr_sigwait.c212
-rw-r--r--lib/libpthread/thread/thr_single_np.c54
-rw-r--r--lib/libpthread/thread/thr_sleep.c71
-rw-r--r--lib/libpthread/thread/thr_spec.c243
-rw-r--r--lib/libpthread/thread/thr_spinlock.c152
-rw-r--r--lib/libpthread/thread/thr_stack.c258
-rw-r--r--lib/libpthread/thread/thr_suspend_np.c114
-rw-r--r--lib/libpthread/thread/thr_switch_np.c57
-rw-r--r--lib/libpthread/thread/thr_symbols.c81
-rw-r--r--lib/libpthread/thread/thr_system.c54
-rw-r--r--lib/libpthread/thread/thr_tcdrain.c54
-rw-r--r--lib/libpthread/thread/thr_vfork.c17
-rw-r--r--lib/libpthread/thread/thr_wait.c53
-rw-r--r--lib/libpthread/thread/thr_wait4.c60
-rw-r--r--lib/libpthread/thread/thr_waitpid.c55
-rw-r--r--lib/libpthread/thread/thr_write.c59
-rw-r--r--lib/libpthread/thread/thr_writev.c61
-rw-r--r--lib/libpthread/thread/thr_yield.c78
-rw-r--r--lib/libradius/Makefile45
-rw-r--r--lib/libradius/libradius.3555
-rw-r--r--lib/libradius/radius.conf.5185
-rw-r--r--lib/libradius/radlib.c1232
-rw-r--r--lib/libradius/radlib.h220
-rw-r--r--lib/libradius/radlib_private.h103
-rw-r--r--lib/libradius/radlib_vs.h84
-rw-r--r--lib/librpcsvc/Makefile40
-rw-r--r--lib/librpcsvc/rnusers.c72
-rw-r--r--lib/librpcsvc/rstat.c71
-rw-r--r--lib/librpcsvc/rwall.c56
-rw-r--r--lib/librpcsvc/secretkey.c89
-rw-r--r--lib/librpcsvc/xcrypt.c188
-rw-r--r--lib/librpcsvc/yp_passwd.c87
-rw-r--r--lib/librpcsvc/yp_update.c199
-rw-r--r--lib/librt/Makefile14
-rw-r--r--lib/librt/aio.c196
-rw-r--r--lib/librt/mq.c232
-rw-r--r--lib/librt/sigev_thread.c465
-rw-r--r--lib/librt/sigev_thread.h85
-rw-r--r--lib/librt/timer.c181
-rw-r--r--lib/libsbuf/Makefile10
-rw-r--r--lib/libsdp/Makefile36
-rw-r--r--lib/libsdp/sdp-int.h62
-rw-r--r--lib/libsdp/sdp.3415
-rw-r--r--lib/libsdp/sdp.h653
-rw-r--r--lib/libsdp/search.c421
-rw-r--r--lib/libsdp/service.c237
-rw-r--r--lib/libsdp/session.c177
-rw-r--r--lib/libsdp/util.c448
-rw-r--r--lib/libsm/Makefile39
-rw-r--r--lib/libsmb/Makefile19
-rw-r--r--lib/libsmdb/Makefile23
-rw-r--r--lib/libsmutil/Makefile23
-rw-r--r--lib/libstand/Makefile199
-rw-r--r--lib/libstand/__main.c43
-rw-r--r--lib/libstand/alpha/_setjmp.S120
-rw-r--r--lib/libstand/arm/_setjmp.S106
-rw-r--r--lib/libstand/arp.c313
-rw-r--r--lib/libstand/assert.c44
-rw-r--r--lib/libstand/bcd.c38
-rw-r--r--lib/libstand/bootp.c418
-rw-r--r--lib/libstand/bootp.h145
-rw-r--r--lib/libstand/bootparam.c452
-rw-r--r--lib/libstand/bootparam.h5
-rw-r--r--lib/libstand/bswap.c40
-rw-r--r--lib/libstand/bzipfs.c303
-rw-r--r--lib/libstand/cd9660.c588
-rw-r--r--lib/libstand/close.c100
-rw-r--r--lib/libstand/closeall.c80
-rw-r--r--lib/libstand/dev.c65
-rw-r--r--lib/libstand/dosfs.c708
-rw-r--r--lib/libstand/dosfs.h120
-rw-r--r--lib/libstand/environment.c219
-rw-r--r--lib/libstand/ether.c154
-rw-r--r--lib/libstand/ext2fs.c906
-rw-r--r--lib/libstand/fstat.c65
-rw-r--r--lib/libstand/getopt.c115
-rw-r--r--lib/libstand/gets.c116
-rw-r--r--lib/libstand/globals.c36
-rw-r--r--lib/libstand/gzipfs.c345
-rw-r--r--lib/libstand/i386/_setjmp.S79
-rw-r--r--lib/libstand/if_ether.h265
-rw-r--r--lib/libstand/in_cksum.c98
-rw-r--r--lib/libstand/inet_ntoa.c68
-rw-r--r--lib/libstand/ioctl.c92
-rw-r--r--lib/libstand/iodesc.h54
-rw-r--r--lib/libstand/libstand.3680
-rw-r--r--lib/libstand/lseek.c146
-rw-r--r--lib/libstand/net.c293
-rw-r--r--lib/libstand/net.h125
-rw-r--r--lib/libstand/netif.c335
-rw-r--r--lib/libstand/netif.h67
-rw-r--r--lib/libstand/nfs.c768
-rw-r--r--lib/libstand/nfsv2.h168
-rw-r--r--lib/libstand/nullfs.c109
-rw-r--r--lib/libstand/open.c148
-rw-r--r--lib/libstand/pager.c161
-rw-r--r--lib/libstand/powerpc/_setjmp.S36
-rw-r--r--lib/libstand/printf.c435
-rw-r--r--lib/libstand/qdivrem.c353
-rw-r--r--lib/libstand/quad.h116
-rw-r--r--lib/libstand/random.c74
-rw-r--r--lib/libstand/rarp.c229
-rw-r--r--lib/libstand/read.c131
-rw-r--r--lib/libstand/readdir.c51
-rw-r--r--lib/libstand/rpc.c443
-rw-r--r--lib/libstand/rpc.h68
-rw-r--r--lib/libstand/rpcv2.h89
-rw-r--r--lib/libstand/saioctl.h52
-rw-r--r--lib/libstand/sbrk.c62
-rw-r--r--lib/libstand/sparc64/_setjmp.S98
-rw-r--r--lib/libstand/splitfs.c313
-rw-r--r--lib/libstand/stand.h415
-rw-r--r--lib/libstand/stat.c56
-rw-r--r--lib/libstand/strcasecmp.c77
-rw-r--r--lib/libstand/strdup.c59
-rw-r--r--lib/libstand/strerror.c91
-rw-r--r--lib/libstand/strtol.c136
-rw-r--r--lib/libstand/tftp.c426
-rw-r--r--lib/libstand/tftp.h36
-rw-r--r--lib/libstand/twiddle.c56
-rw-r--r--lib/libstand/udp.c275
-rw-r--r--lib/libstand/ufs.c869
-rw-r--r--lib/libstand/write.c99
-rw-r--r--lib/libstand/zalloc.c303
-rw-r--r--lib/libstand/zalloc_defs.h81
-rw-r--r--lib/libstand/zalloc_malloc.c209
-rw-r--r--lib/libstand/zalloc_mem.h55
-rw-r--r--lib/libstand/zalloc_protos.h35
-rw-r--r--lib/libtacplus/Makefile36
-rw-r--r--lib/libtacplus/libtacplus.3490
-rw-r--r--lib/libtacplus/taclib.c1318
-rw-r--r--lib/libtacplus/taclib.h132
-rw-r--r--lib/libtacplus/taclib_private.h177
-rw-r--r--lib/libtacplus/tacplus.conf.5134
-rw-r--r--lib/libtelnet/Makefile33
-rw-r--r--lib/libthr/Makefile55
-rw-r--r--lib/libthr/arch/alpha/Makefile.inc5
-rw-r--r--lib/libthr/arch/alpha/alpha/pthread_md.c53
-rw-r--r--lib/libthr/arch/alpha/include/pthread_md.h75
-rw-r--r--lib/libthr/arch/amd64/Makefile.inc5
-rw-r--r--lib/libthr/arch/amd64/amd64/pthread_md.c55
-rw-r--r--lib/libthr/arch/amd64/include/pthread_md.h99
-rw-r--r--lib/libthr/arch/arm/Makefile.inc5
-rw-r--r--lib/libthr/arch/arm/arm/pthread_md.c50
-rw-r--r--lib/libthr/arch/arm/include/pthread_md.h83
-rw-r--r--lib/libthr/arch/i386/Makefile.inc5
-rw-r--r--lib/libthr/arch/i386/i386/pthread_md.c57
-rw-r--r--lib/libthr/arch/i386/include/pthread_md.h103
-rw-r--r--lib/libthr/arch/ia64/Makefile.inc5
-rw-r--r--lib/libthr/arch/ia64/ia64/pthread_md.c58
-rw-r--r--lib/libthr/arch/ia64/include/pthread_md.h78
-rw-r--r--lib/libthr/arch/powerpc/Makefile.inc5
-rw-r--r--lib/libthr/arch/powerpc/include/pthread_md.h80
-rw-r--r--lib/libthr/arch/powerpc/powerpc/pthread_md.c58
-rw-r--r--lib/libthr/arch/sparc64/Makefile.inc5
-rw-r--r--lib/libthr/arch/sparc64/include/pthread_md.h87
-rw-r--r--lib/libthr/arch/sparc64/sparc64/pthread_md.c56
-rw-r--r--lib/libthr/libthr.370
-rw-r--r--lib/libthr/pthread.map761
-rw-r--r--lib/libthr/support/Makefile.inc22
-rw-r--r--lib/libthr/sys/Makefile.inc5
-rw-r--r--lib/libthr/sys/thr_error.c54
-rw-r--r--lib/libthr/thread/Makefile.inc54
-rw-r--r--lib/libthr/thread/thr_atfork.c57
-rw-r--r--lib/libthr/thread/thr_attr.c540
-rw-r--r--lib/libthr/thread/thr_autoinit.c65
-rw-r--r--lib/libthr/thread/thr_barrier.c111
-rw-r--r--lib/libthr/thread/thr_barrierattr.c96
-rw-r--r--lib/libthr/thread/thr_cancel.c163
-rw-r--r--lib/libthr/thread/thr_clean.c78
-rw-r--r--lib/libthr/thread/thr_concurrency.c65
-rw-r--r--lib/libthr/thread/thr_cond.c350
-rw-r--r--lib/libthr/thread/thr_condattr.c130
-rw-r--r--lib/libthr/thread/thr_create.c251
-rw-r--r--lib/libthr/thread/thr_detach.c71
-rw-r--r--lib/libthr/thread/thr_equal.c46
-rw-r--r--lib/libthr/thread/thr_event.c65
-rw-r--r--lib/libthr/thread/thr_exit.c146
-rw-r--r--lib/libthr/thread/thr_fork.c198
-rw-r--r--lib/libthr/thread/thr_getprio.c58
-rw-r--r--lib/libthr/thread/thr_getschedparam.c77
-rw-r--r--lib/libthr/thread/thr_info.c73
-rw-r--r--lib/libthr/thread/thr_init.c466
-rw-r--r--lib/libthr/thread/thr_join.c146
-rw-r--r--lib/libthr/thread/thr_kern.c98
-rw-r--r--lib/libthr/thread/thr_kill.c69
-rw-r--r--lib/libthr/thread/thr_list.c343
-rw-r--r--lib/libthr/thread/thr_main_np.c50
-rw-r--r--lib/libthr/thread/thr_multi_np.c53
-rw-r--r--lib/libthr/thread/thr_mutex.c669
-rw-r--r--lib/libthr/thread/thr_mutex_prioceiling.c116
-rw-r--r--lib/libthr/thread/thr_mutex_protocol.c71
-rw-r--r--lib/libthr/thread/thr_mutexattr.c262
-rw-r--r--lib/libthr/thread/thr_once.c99
-rw-r--r--lib/libthr/thread/thr_printf.c135
-rw-r--r--lib/libthr/thread/thr_private.h741
-rw-r--r--lib/libthr/thread/thr_pspinlock.c136
-rw-r--r--lib/libthr/thread/thr_resume_np.c94
-rw-r--r--lib/libthr/thread/thr_rtld.c219
-rw-r--r--lib/libthr/thread/thr_rwlock.c417
-rw-r--r--lib/libthr/thread/thr_rwlockattr.c100
-rw-r--r--lib/libthr/thread/thr_self.c50
-rw-r--r--lib/libthr/thread/thr_sem.c271
-rw-r--r--lib/libthr/thread/thr_seterrno.c59
-rw-r--r--lib/libthr/thread/thr_setprio.c56
-rw-r--r--lib/libthr/thread/thr_setschedparam.c95
-rw-r--r--lib/libthr/thread/thr_sig.c284
-rw-r--r--lib/libthr/thread/thr_sigmask.c52
-rw-r--r--lib/libthr/thread/thr_single_np.c52
-rw-r--r--lib/libthr/thread/thr_spec.c230
-rw-r--r--lib/libthr/thread/thr_spinlock.c126
-rw-r--r--lib/libthr/thread/thr_stack.c256
-rw-r--r--lib/libthr/thread/thr_suspend_np.c145
-rw-r--r--lib/libthr/thread/thr_switch_np.c57
-rw-r--r--lib/libthr/thread/thr_symbols.c61
-rw-r--r--lib/libthr/thread/thr_syscalls.c675
-rw-r--r--lib/libthr/thread/thr_umtx.c83
-rw-r--r--lib/libthr/thread/thr_umtx.h87
-rw-r--r--lib/libthr/thread/thr_yield.c48
-rw-r--r--lib/libthread_db/Makefile22
-rw-r--r--lib/libthread_db/Symbol.map31
-rw-r--r--lib/libthread_db/arch/alpha/libc_r_md.c73
-rw-r--r--lib/libthread_db/arch/alpha/libpthread_md.c62
-rw-r--r--lib/libthread_db/arch/amd64/libc_r_md.c41
-rw-r--r--lib/libthread_db/arch/amd64/libpthread_md.c117
-rw-r--r--lib/libthread_db/arch/i386/libc_r_md.c48
-rw-r--r--lib/libthread_db/arch/i386/libpthread_md.c119
-rw-r--r--lib/libthread_db/arch/ia64/libc_r_md.c41
-rw-r--r--lib/libthread_db/arch/ia64/libpthread_md.c62
-rw-r--r--lib/libthread_db/arch/sparc64/libc_r_md.c41
-rw-r--r--lib/libthread_db/arch/sparc64/libpthread_md.c62
-rw-r--r--lib/libthread_db/libc_r_db.c348
-rw-r--r--lib/libthread_db/libpthread_db.c1149
-rw-r--r--lib/libthread_db/libpthread_db.h93
-rw-r--r--lib/libthread_db/libthr_db.c793
-rw-r--r--lib/libthread_db/thread_db.c263
-rw-r--r--lib/libthread_db/thread_db.h248
-rw-r--r--lib/libthread_db/thread_db_int.h96
-rw-r--r--lib/libufs/Makefile25
-rw-r--r--lib/libufs/block.c135
-rw-r--r--lib/libufs/bread.386
-rw-r--r--lib/libufs/cgread.387
-rw-r--r--lib/libufs/cgroup.c73
-rw-r--r--lib/libufs/inode.c95
-rw-r--r--lib/libufs/libufs.377
-rw-r--r--lib/libufs/libufs.h135
-rw-r--r--lib/libufs/sblock.c119
-rw-r--r--lib/libufs/sbread.381
-rw-r--r--lib/libufs/type.c160
-rw-r--r--lib/libufs/ufs_disk_close.3112
-rw-r--r--lib/libugidfw/Makefile17
-rw-r--r--lib/libugidfw/bsde_get_rule.3159
-rw-r--r--lib/libugidfw/bsde_get_rule_count.393
-rw-r--r--lib/libugidfw/bsde_parse_rule.3105
-rw-r--r--lib/libugidfw/bsde_rule_to_string.382
-rw-r--r--lib/libugidfw/libugidfw.3115
-rw-r--r--lib/libugidfw/ugidfw.c1323
-rw-r--r--lib/libugidfw/ugidfw.h58
-rw-r--r--lib/libusbhid/Makefile22
-rw-r--r--lib/libusbhid/data.c94
-rw-r--r--lib/libusbhid/descr.c79
-rw-r--r--lib/libusbhid/parse.c440
-rw-r--r--lib/libusbhid/usage.c238
-rw-r--r--lib/libusbhid/usbhid.3222
-rw-r--r--lib/libusbhid/usbhid.h109
-rw-r--r--lib/libusbhid/usbvar.h36
-rw-r--r--lib/libutil/Makefile49
-rw-r--r--lib/libutil/_secure_path.375
-rw-r--r--lib/libutil/_secure_path.c74
-rw-r--r--lib/libutil/auth.356
-rw-r--r--lib/libutil/auth.c70
-rw-r--r--lib/libutil/auth.conf.535
-rw-r--r--lib/libutil/fparseln.3158
-rw-r--r--lib/libutil/fparseln.c222
-rw-r--r--lib/libutil/humanize_number.3148
-rw-r--r--lib/libutil/humanize_number.c148
-rw-r--r--lib/libutil/kld.398
-rw-r--r--lib/libutil/kld.c74
-rw-r--r--lib/libutil/libutil.h165
-rw-r--r--lib/libutil/login.367
-rw-r--r--lib/libutil/login.c75
-rw-r--r--lib/libutil/login.conf.5437
-rw-r--r--lib/libutil/login_auth.372
-rw-r--r--lib/libutil/login_auth.c108
-rw-r--r--lib/libutil/login_cap.3442
-rw-r--r--lib/libutil/login_cap.c808
-rw-r--r--lib/libutil/login_cap.h158
-rw-r--r--lib/libutil/login_class.3197
-rw-r--r--lib/libutil/login_class.c429
-rw-r--r--lib/libutil/login_crypt.c50
-rw-r--r--lib/libutil/login_ok.3142
-rw-r--r--lib/libutil/login_ok.c250
-rw-r--r--lib/libutil/login_times.3161
-rw-r--r--lib/libutil/login_times.c161
-rw-r--r--lib/libutil/login_tty.365
-rw-r--r--lib/libutil/login_tty.c62
-rw-r--r--lib/libutil/logout.369
-rw-r--r--lib/libutil/logout.c78
-rw-r--r--lib/libutil/logwtmp.371
-rw-r--r--lib/libutil/logwtmp.c104
-rw-r--r--lib/libutil/pidfile.3249
-rw-r--r--lib/libutil/pidfile.c246
-rw-r--r--lib/libutil/property.399
-rw-r--r--lib/libutil/property.c259
-rw-r--r--lib/libutil/pty.3149
-rw-r--r--lib/libutil/pty.c172
-rw-r--r--lib/libutil/pw_util.c616
-rw-r--r--lib/libutil/realhostname.3105
-rw-r--r--lib/libutil/realhostname.c186
-rw-r--r--lib/libutil/realhostname_sa.3133
-rw-r--r--lib/libutil/stub.c46
-rw-r--r--lib/libutil/trimdomain.385
-rw-r--r--lib/libutil/trimdomain.c115
-rw-r--r--lib/libutil/uucplock.3183
-rw-r--r--lib/libutil/uucplock.c230
-rw-r--r--lib/libvgl/Makefile41
-rw-r--r--lib/libvgl/bitmap.c406
-rw-r--r--lib/libvgl/keyboard.c94
-rw-r--r--lib/libvgl/main.c574
-rw-r--r--lib/libvgl/mouse.c285
-rw-r--r--lib/libvgl/simple.c503
-rw-r--r--lib/libvgl/text.c245
-rw-r--r--lib/libvgl/vgl.3470
-rw-r--r--lib/libvgl/vgl.h154
-rw-r--r--lib/libwrap/Makefile34
-rw-r--r--lib/libwrap/libvars.c2
-rw-r--r--lib/liby/Makefile7
-rw-r--r--lib/liby/main.c49
-rw-r--r--lib/liby/yyerror.c49
-rw-r--r--lib/libypclnt/Makefile55
-rw-r--r--lib/libypclnt/ypclnt.h62
-rw-r--r--lib/libypclnt/ypclnt_connect.c90
-rw-r--r--lib/libypclnt/ypclnt_error.c59
-rw-r--r--lib/libypclnt/ypclnt_free.c51
-rw-r--r--lib/libypclnt/ypclnt_get.c52
-rw-r--r--lib/libypclnt/ypclnt_new.c62
-rw-r--r--lib/libypclnt/ypclnt_passwd.c316
-rw-r--r--lib/libz/ChangeLog855
-rw-r--r--lib/libz/FAQ339
-rw-r--r--lib/libz/FREEBSD-upgrade44
-rw-r--r--lib/libz/Makefile33
-rw-r--r--lib/libz/README125
-rw-r--r--lib/libz/adler32.c149
-rw-r--r--lib/libz/algorithm.txt209
-rw-r--r--lib/libz/compress.c79
-rw-r--r--lib/libz/crc32.c423
-rw-r--r--lib/libz/crc32.h441
-rw-r--r--lib/libz/deflate.c1736
-rw-r--r--lib/libz/deflate.h331
-rw-r--r--lib/libz/example.c565
-rw-r--r--lib/libz/gzio.c1027
-rw-r--r--lib/libz/infback.c623
-rw-r--r--lib/libz/inffast.c318
-rw-r--r--lib/libz/inffast.h11
-rw-r--r--lib/libz/inffixed.h94
-rw-r--r--lib/libz/inflate.c1368
-rw-r--r--lib/libz/inflate.h115
-rw-r--r--lib/libz/inftrees.c329
-rw-r--r--lib/libz/inftrees.h55
-rw-r--r--lib/libz/minigzip.c372
-rw-r--r--lib/libz/trees.c1219
-rw-r--r--lib/libz/trees.h128
-rw-r--r--lib/libz/uncompr.c61
-rw-r--r--lib/libz/zconf.h341
-rw-r--r--lib/libz/zlib.3159
-rw-r--r--lib/libz/zlib.h1357
-rw-r--r--lib/libz/zopen.c37
-rw-r--r--lib/libz/zutil.c318
-rw-r--r--lib/libz/zutil.h269
-rw-r--r--lib/msun/Makefile164
-rw-r--r--lib/msun/Symbol.map181
-rw-r--r--lib/msun/alpha/Makefile.inc11
-rw-r--r--lib/msun/alpha/Symbol.map13
-rw-r--r--lib/msun/alpha/fenv.c144
-rw-r--r--lib/msun/alpha/fenv.h185
-rw-r--r--lib/msun/alpha/s_copysign.S45
-rw-r--r--lib/msun/alpha/s_copysignf.S45
-rw-r--r--lib/msun/amd64/Makefile.inc6
-rw-r--r--lib/msun/amd64/Symbol.map12
-rw-r--r--lib/msun/amd64/e_sqrt.S33
-rw-r--r--lib/msun/amd64/e_sqrtf.S32
-rw-r--r--lib/msun/amd64/fenv.c148
-rw-r--r--lib/msun/amd64/fenv.h203
-rw-r--r--lib/msun/amd64/s_llrint.S6
-rw-r--r--lib/msun/amd64/s_llrintf.S6
-rw-r--r--lib/msun/amd64/s_lrint.S36
-rw-r--r--lib/msun/amd64/s_lrintf.S36
-rw-r--r--lib/msun/amd64/s_remquo.S65
-rw-r--r--lib/msun/amd64/s_remquof.S65
-rw-r--r--lib/msun/amd64/s_scalbn.S39
-rw-r--r--lib/msun/amd64/s_scalbnf.S42
-rw-r--r--lib/msun/amd64/s_scalbnl.S19
-rw-r--r--lib/msun/arm/Makefile.inc4
-rw-r--r--lib/msun/arm/Symbol.map3
-rw-r--r--lib/msun/arm/fenv.c35
-rw-r--r--lib/msun/arm/fenv.h217
-rw-r--r--lib/msun/bsdsrc/b_exp.c177
-rw-r--r--lib/msun/bsdsrc/b_log.c473
-rw-r--r--lib/msun/bsdsrc/b_tgamma.c315
-rw-r--r--lib/msun/bsdsrc/mathimpl.h74
-rw-r--r--lib/msun/i387/Makefile.inc19
-rw-r--r--lib/msun/i387/Symbol.map14
-rw-r--r--lib/msun/i387/e_exp.S98
-rw-r--r--lib/msun/i387/e_fmod.S48
-rw-r--r--lib/msun/i387/e_log.S44
-rw-r--r--lib/msun/i387/e_log10.S44
-rw-r--r--lib/msun/i387/e_log10f.S15
-rw-r--r--lib/msun/i387/e_logf.S15
-rw-r--r--lib/msun/i387/e_remainder.S48
-rw-r--r--lib/msun/i387/e_remainderf.S19
-rw-r--r--lib/msun/i387/e_scalb.S45
-rw-r--r--lib/msun/i387/e_scalbf.S15
-rw-r--r--lib/msun/i387/e_sqrt.S43
-rw-r--r--lib/msun/i387/e_sqrtf.S14
-rw-r--r--lib/msun/i387/fenv.c211
-rw-r--r--lib/msun/i387/fenv.h240
-rw-r--r--lib/msun/i387/s_ceil.S58
-rw-r--r--lib/msun/i387/s_ceilf.S29
-rw-r--r--lib/msun/i387/s_ceill.S27
-rw-r--r--lib/msun/i387/s_copysign.S48
-rw-r--r--lib/msun/i387/s_copysignf.S19
-rw-r--r--lib/msun/i387/s_copysignl.S17
-rw-r--r--lib/msun/i387/s_cos.S56
-rw-r--r--lib/msun/i387/s_finite.S46
-rw-r--r--lib/msun/i387/s_floor.S58
-rw-r--r--lib/msun/i387/s_floorf.S29
-rw-r--r--lib/msun/i387/s_floorl.S27
-rw-r--r--lib/msun/i387/s_llrint.S36
-rw-r--r--lib/msun/i387/s_llrintf.S36
-rw-r--r--lib/msun/i387/s_logb.S44
-rw-r--r--lib/msun/i387/s_logbf.S15
-rw-r--r--lib/msun/i387/s_lrint.S35
-rw-r--r--lib/msun/i387/s_lrintf.S35
-rw-r--r--lib/msun/i387/s_remquo.S62
-rw-r--r--lib/msun/i387/s_remquof.S62
-rw-r--r--lib/msun/i387/s_rint.S43
-rw-r--r--lib/msun/i387/s_rintf.S14
-rw-r--r--lib/msun/i387/s_scalbn.S45
-rw-r--r--lib/msun/i387/s_scalbnf.S19
-rw-r--r--lib/msun/i387/s_scalbnl.S19
-rw-r--r--lib/msun/i387/s_significand.S44
-rw-r--r--lib/msun/i387/s_significandf.S15
-rw-r--r--lib/msun/i387/s_sin.S56
-rw-r--r--lib/msun/i387/s_tan.S58
-rw-r--r--lib/msun/i387/s_trunc.S26
-rw-r--r--lib/msun/i387/s_truncf.S26
-rw-r--r--lib/msun/i387/s_truncl.S26
-rw-r--r--lib/msun/ia64/Makefile.inc5
-rw-r--r--lib/msun/ia64/Symbol.map4
-rw-r--r--lib/msun/ia64/fenv.c49
-rw-r--r--lib/msun/ia64/fenv.h242
-rw-r--r--lib/msun/ia64/s_fma.S34
-rw-r--r--lib/msun/ia64/s_fmaf.S34
-rw-r--r--lib/msun/ia64/s_fmal.S34
-rw-r--r--lib/msun/man/acos.392
-rw-r--r--lib/msun/man/acosh.382
-rw-r--r--lib/msun/man/asin.394
-rw-r--r--lib/msun/man/asinh.378
-rw-r--r--lib/msun/man/atan.384
-rw-r--r--lib/msun/man/atan2.3187
-rw-r--r--lib/msun/man/atanh.385
-rw-r--r--lib/msun/man/ceil.382
-rw-r--r--lib/msun/man/cimag.396
-rw-r--r--lib/msun/man/copysign.390
-rw-r--r--lib/msun/man/cos.383
-rw-r--r--lib/msun/man/cosh.372
-rw-r--r--lib/msun/man/erf.397
-rw-r--r--lib/msun/man/exp.3236
-rw-r--r--lib/msun/man/fabs.387
-rw-r--r--lib/msun/man/fdim.386
-rw-r--r--lib/msun/man/feclearexcept.3139
-rw-r--r--lib/msun/man/feenableexcept.398
-rw-r--r--lib/msun/man/fegetenv.3113
-rw-r--r--lib/msun/man/fegetround.383
-rw-r--r--lib/msun/man/fenv.3289
-rw-r--r--lib/msun/man/floor.382
-rw-r--r--lib/msun/man/fma.3116
-rw-r--r--lib/msun/man/fmax.397
-rw-r--r--lib/msun/man/fmod.387
-rw-r--r--lib/msun/man/hypot.3134
-rw-r--r--lib/msun/man/ieee.3448
-rw-r--r--lib/msun/man/ieee_test.393
-rw-r--r--lib/msun/man/ilogb.3127
-rw-r--r--lib/msun/man/j0.3142
-rw-r--r--lib/msun/man/lgamma.3185
-rw-r--r--lib/msun/man/lrint.394
-rw-r--r--lib/msun/man/lround.3112
-rw-r--r--lib/msun/man/math.3242
-rw-r--r--lib/msun/man/nextafter.3100
-rw-r--r--lib/msun/man/remainder.3146
-rw-r--r--lib/msun/man/rint.3103
-rw-r--r--lib/msun/man/round.380
-rw-r--r--lib/msun/man/scalbn.395
-rw-r--r--lib/msun/man/signbit.357
-rw-r--r--lib/msun/man/sin.382
-rw-r--r--lib/msun/man/sinh.371
-rw-r--r--lib/msun/man/sqrt.3100
-rw-r--r--lib/msun/man/tan.381
-rw-r--r--lib/msun/man/tanh.380
-rw-r--r--lib/msun/man/trunc.380
-rw-r--r--lib/msun/powerpc/Makefile.inc4
-rw-r--r--lib/msun/powerpc/Symbol.map3
-rw-r--r--lib/msun/powerpc/fenv.c31
-rw-r--r--lib/msun/powerpc/fenv.h263
-rw-r--r--lib/msun/sparc64/Makefile.inc5
-rw-r--r--lib/msun/sparc64/Symbol.map3
-rw-r--r--lib/msun/sparc64/e_sqrt.S33
-rw-r--r--lib/msun/sparc64/e_sqrtf.S33
-rw-r--r--lib/msun/sparc64/fenv.c36
-rw-r--r--lib/msun/sparc64/fenv.h254
-rw-r--r--lib/msun/src/e_acos.c104
-rw-r--r--lib/msun/src/e_acosf.c81
-rw-r--r--lib/msun/src/e_acosh.c63
-rw-r--r--lib/msun/src/e_acoshf.c49
-rw-r--r--lib/msun/src/e_asin.c113
-rw-r--r--lib/msun/src/e_asinf.c84
-rw-r--r--lib/msun/src/e_atan2.c124
-rw-r--r--lib/msun/src/e_atan2f.c97
-rw-r--r--lib/msun/src/e_atanh.c63
-rw-r--r--lib/msun/src/e_atanhf.c46
-rw-r--r--lib/msun/src/e_cosh.c86
-rw-r--r--lib/msun/src/e_coshf.c63
-rw-r--r--lib/msun/src/e_exp.c159
-rw-r--r--lib/msun/src/e_expf.c95
-rw-r--r--lib/msun/src/e_fmod.c133
-rw-r--r--lib/msun/src/e_fmodf.c105
-rw-r--r--lib/msun/src/e_gamma.c34
-rw-r--r--lib/msun/src/e_gamma_r.c33
-rw-r--r--lib/msun/src/e_gammaf.c35
-rw-r--r--lib/msun/src/e_gammaf_r.c34
-rw-r--r--lib/msun/src/e_hypot.c125
-rw-r--r--lib/msun/src/e_hypotf.c83
-rw-r--r--lib/msun/src/e_j0.c382
-rw-r--r--lib/msun/src/e_j0f.c338
-rw-r--r--lib/msun/src/e_j1.c377
-rw-r--r--lib/msun/src/e_j1f.c334
-rw-r--r--lib/msun/src/e_jn.c266
-rw-r--r--lib/msun/src/e_jnf.c196
-rw-r--r--lib/msun/src/e_lgamma.c34
-rw-r--r--lib/msun/src/e_lgamma_r.c297
-rw-r--r--lib/msun/src/e_lgammaf.c35
-rw-r--r--lib/msun/src/e_lgammaf_r.c231
-rw-r--r--lib/msun/src/e_log.c135
-rw-r--r--lib/msun/src/e_log10.c87
-rw-r--r--lib/msun/src/e_log10f.c55
-rw-r--r--lib/msun/src/e_logf.c83
-rw-r--r--lib/msun/src/e_pow.c304
-rw-r--r--lib/msun/src/e_powf.c247
-rw-r--r--lib/msun/src/e_rem_pio2.c168
-rw-r--r--lib/msun/src/e_rem_pio2f.c98
-rw-r--r--lib/msun/src/e_remainder.c73
-rw-r--r--lib/msun/src/e_remainderf.c65
-rw-r--r--lib/msun/src/e_scalb.c48
-rw-r--r--lib/msun/src/e_scalbf.c46
-rw-r--r--lib/msun/src/e_sinh.c79
-rw-r--r--lib/msun/src/e_sinhf.c60
-rw-r--r--lib/msun/src/e_sqrt.c446
-rw-r--r--lib/msun/src/e_sqrtf.c89
-rw-r--r--lib/msun/src/k_cos.c79
-rw-r--r--lib/msun/src/k_cosf.c47
-rw-r--r--lib/msun/src/k_rem_pio2.c304
-rw-r--r--lib/msun/src/k_rem_pio2f.c197
-rw-r--r--lib/msun/src/k_sin.c70
-rw-r--r--lib/msun/src/k_sinf.c47
-rw-r--r--lib/msun/src/k_tan.c133
-rw-r--r--lib/msun/src/k_tanf.c67
-rw-r--r--lib/msun/src/math.h473
-rw-r--r--lib/msun/src/math_private.h272
-rw-r--r--lib/msun/src/s_asinh.c57
-rw-r--r--lib/msun/src/s_asinhf.c49
-rw-r--r--lib/msun/src/s_atan.c119
-rw-r--r--lib/msun/src/s_atanf.c99
-rw-r--r--lib/msun/src/s_cbrt.c114
-rw-r--r--lib/msun/src/s_cbrtf.c74
-rw-r--r--lib/msun/src/s_ceil.c72
-rw-r--r--lib/msun/src/s_ceilf.c53
-rw-r--r--lib/msun/src/s_ceill.c102
-rw-r--r--lib/msun/src/s_cimag.c35
-rw-r--r--lib/msun/src/s_cimagf.c35
-rw-r--r--lib/msun/src/s_cimagl.c35
-rw-r--r--lib/msun/src/s_conj.c35
-rw-r--r--lib/msun/src/s_conjf.c35
-rw-r--r--lib/msun/src/s_conjl.c35
-rw-r--r--lib/msun/src/s_copysign.c34
-rw-r--r--lib/msun/src/s_copysignf.c37
-rw-r--r--lib/msun/src/s_copysignl.c42
-rw-r--r--lib/msun/src/s_cos.c82
-rw-r--r--lib/msun/src/s_cosf.c84
-rw-r--r--lib/msun/src/s_creal.c35
-rw-r--r--lib/msun/src/s_crealf.c35
-rw-r--r--lib/msun/src/s_creall.c35
-rw-r--r--lib/msun/src/s_erf.c302
-rw-r--r--lib/msun/src/s_erff.c211
-rw-r--r--lib/msun/src/s_exp2.c389
-rw-r--r--lib/msun/src/s_exp2f.c141
-rw-r--r--lib/msun/src/s_expm1.c220
-rw-r--r--lib/msun/src/s_expm1f.c125
-rw-r--r--lib/msun/src/s_fabs.c31
-rw-r--r--lib/msun/src/s_fabsf.c34
-rw-r--r--lib/msun/src/s_fabsl.c43
-rw-r--r--lib/msun/src/s_fdim.c46
-rw-r--r--lib/msun/src/s_finite.c30
-rw-r--r--lib/msun/src/s_finitef.c33
-rw-r--r--lib/msun/src/s_floor.c73
-rw-r--r--lib/msun/src/s_floorf.c62
-rw-r--r--lib/msun/src/s_floorl.c102
-rw-r--r--lib/msun/src/s_fma.c202
-rw-r--r--lib/msun/src/s_fmaf.c47
-rw-r--r--lib/msun/src/s_fmal.c182
-rw-r--r--lib/msun/src/s_fmax.c53
-rw-r--r--lib/msun/src/s_fmaxf.c53
-rw-r--r--lib/msun/src/s_fmaxl.c55
-rw-r--r--lib/msun/src/s_fmin.c53
-rw-r--r--lib/msun/src/s_fminf.c53
-rw-r--r--lib/msun/src/s_fminl.c55
-rw-r--r--lib/msun/src/s_frexp.c58
-rw-r--r--lib/msun/src/s_frexpf.c44
-rw-r--r--lib/msun/src/s_frexpl.c62
-rw-r--r--lib/msun/src/s_ilogb.c49
-rw-r--r--lib/msun/src/s_ilogbf.c41
-rw-r--r--lib/msun/src/s_ilogbl.c54
-rw-r--r--lib/msun/src/s_isfinite.c58
-rw-r--r--lib/msun/src/s_isnan.c62
-rw-r--r--lib/msun/src/s_isnormal.c58
-rw-r--r--lib/msun/src/s_llrint.c9
-rw-r--r--lib/msun/src/s_llrintf.c9
-rw-r--r--lib/msun/src/s_llround.c11
-rw-r--r--lib/msun/src/s_llroundf.c11
-rw-r--r--lib/msun/src/s_llroundl.c11
-rw-r--r--lib/msun/src/s_log1p.c168
-rw-r--r--lib/msun/src/s_log1pf.c107
-rw-r--r--lib/msun/src/s_logb.c44
-rw-r--r--lib/msun/src/s_logbf.c41
-rw-r--r--lib/msun/src/s_lrint.c58
-rw-r--r--lib/msun/src/s_lrintf.c9
-rw-r--r--lib/msun/src/s_lround.c66
-rw-r--r--lib/msun/src/s_lroundf.c11
-rw-r--r--lib/msun/src/s_lroundl.c11
-rw-r--r--lib/msun/src/s_modf.c75
-rw-r--r--lib/msun/src/s_modff.c56
-rw-r--r--lib/msun/src/s_nearbyint.c54
-rw-r--r--lib/msun/src/s_nextafter.c85
-rw-r--r--lib/msun/src/s_nextafterf.c67
-rw-r--r--lib/msun/src/s_nextafterl.c82
-rw-r--r--lib/msun/src/s_nexttoward.c73
-rw-r--r--lib/msun/src/s_nexttowardf.c60
-rw-r--r--lib/msun/src/s_remquo.c152
-rw-r--r--lib/msun/src/s_remquof.c121
-rw-r--r--lib/msun/src/s_rint.c87
-rw-r--r--lib/msun/src/s_rintf.c52
-rw-r--r--lib/msun/src/s_round.c51
-rw-r--r--lib/msun/src/s_roundf.c51
-rw-r--r--lib/msun/src/s_roundl.c51
-rw-r--r--lib/msun/src/s_scalbln.c76
-rw-r--r--lib/msun/src/s_scalbn.c66
-rw-r--r--lib/msun/src/s_scalbnf.c58
-rw-r--r--lib/msun/src/s_scalbnl.c71
-rw-r--r--lib/msun/src/s_signbit.c58
-rw-r--r--lib/msun/src/s_signgam.c3
-rw-r--r--lib/msun/src/s_significand.c30
-rw-r--r--lib/msun/src/s_significandf.c27
-rw-r--r--lib/msun/src/s_sin.c82
-rw-r--r--lib/msun/src/s_sinf.c82
-rw-r--r--lib/msun/src/s_tan.c76
-rw-r--r--lib/msun/src/s_tanf.c69
-rw-r--r--lib/msun/src/s_tanh.c78
-rw-r--r--lib/msun/src/s_tanhf.c56
-rw-r--r--lib/msun/src/s_trunc.c61
-rw-r--r--lib/msun/src/s_truncf.c53
-rw-r--r--lib/msun/src/s_truncl.c68
-rw-r--r--lib/msun/src/w_cabs.c28
-rw-r--r--lib/msun/src/w_cabsf.c23
-rw-r--r--lib/msun/src/w_drem.c15
-rw-r--r--lib/msun/src/w_dremf.c16
-rw-r--r--lib/ncurses/form/Makefile100
-rw-r--r--lib/ncurses/menu/Makefile84
-rw-r--r--lib/ncurses/ncurses/Makefile564
-rw-r--r--lib/ncurses/ncurses/ncurses_cfg.h155
-rw-r--r--lib/ncurses/ncurses/pathnames.h38
-rw-r--r--lib/ncurses/ncurses/termcap.c267
-rw-r--r--lib/ncurses/panel/Makefile48
3596 files changed, 625215 insertions, 118 deletions
diff --git a/lib/Makefile b/lib/Makefile
new file mode 100644
index 0000000..8ba968e
--- /dev/null
+++ b/lib/Makefile
@@ -0,0 +1,130 @@
+# @(#)Makefile 8.1 (Berkeley) 6/4/93
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+# To satisfy shared library or ELF linkage when only the libraries being
+# built are visible:
+#
+# csu must be built before all shared libaries for ELF.
+# libcom_err must be built before libkrb5 and libpam.
+# libcrypt must be built before libkrb5 and libpam.
+# libkvm must be built before libdevstat.
+# msun must be built before libg++ and libstdc++.
+# libmd must be built before libatm, libopie, libradius, and libtacplus.
+# libncurses must be built before libdialog, libedit and libreadline.
+# libnetgraph must be built before libbsnmp/modules/snmp_netgraph.
+# libopie must be built before libpam.
+# libradius must be built before libpam.
+# librpcsvc must be built before libpam.
+# libsbuf must be built before libcam.
+# libtacplus must be built before libpam.
+# libutil must be built before libpam.
+# libypclnt must be built before libpam.
+#
+# Otherwise, the SUBDIR list should be in alphabetical order.
+
+SUBDIR= ${_csu} libbsm libcom_err libcrypt libkvm msun libmd libncurses \
+ libnetgraph libradius librpcsvc libsbuf libtacplus libutil \
+ ${_libypclnt} libalias libarchive ${_libatm} \
+ libbegemot ${_libbluetooth} libbsnmp libbz2 libc ${_libc_r} \
+ libcalendar libcam libcompat libdevinfo libdevstat libdisk \
+ libedit libexpat libfetch libform libftpio libgeom ${_libgpib} \
+ libgssapi ${_libio} libipsec \
+ ${_libipx} libkiconv libmagic libmemstat libmenu ${_libmilter} ${_libmp} \
+ ${_libncp} ${_libngatm} libopie libpam libpanel libpcap \
+ libpmc ${_libpthread} librt ${_libsdp} ${_libsm} ${_libsmb} \
+ ${_libsmdb} \
+ ${_libsmutil} libstand libtelnet ${_libthr} ${_libthread_db} libufs \
+ libugidfw ${_libusbhid} ${_libvgl} libwrap liby libz ${_bind}
+
+.if exists(${.CURDIR}/csu/${MACHINE_ARCH}-elf)
+_csu=csu/${MACHINE_ARCH}-elf
+.elif exists(${.CURDIR}/csu/${MACHINE_ARCH}/Makefile)
+_csu=csu/${MACHINE_ARCH}
+.else
+_csu=csu
+.endif
+
+.if ${MK_ATM} != "no"
+_libatm= libatm
+_libngatm= libngatm
+.endif
+
+.if ${MK_BIND} != "no"
+_bind= bind
+.endif
+
+.if ${MK_BLUETOOTH} != "no"
+_libbluetooth= libbluetooth
+_libsdp= libsdp
+.endif
+
+.if ${MK_IPX} != "no"
+_libipx= libipx
+.endif
+
+.if ${MACHINE_ARCH} == "i386"
+.if ${MK_NCP} != "no"
+_libncp= libncp
+.endif
+_libsmb= libsmb
+_libvgl= libvgl
+.endif
+
+.if ${MACHINE_ARCH} != "arm" && ${MACHINE_ARCH} != "ia64" && \
+ ${MACHINE_ARCH} != "powerpc" && ${MK_LIBC_R} != "no"
+_libc_r=
+.endif
+
+.if ${MACHINE_ARCH} == "alpha"
+_libio= libio
+.endif
+
+.if ${MK_SENDMAIL} != "no"
+_libmilter= libmilter
+_libsm= libsm
+_libsmdb= libsmdb
+_libsmutil= libsmutil
+.endif
+
+.if ${MK_OPENSSL} != "no"
+_libmp= libmp
+.endif
+
+.if ${MACHINE_ARCH} == "amd64"
+.if ${MK_NCP} != "no"
+_libncp= libncp
+.endif
+_libsmb= libsmb
+.endif
+
+.if ${MACHINE_ARCH} == "powerpc"
+_libsmb= libsmb
+.endif
+
+.if ${MK_LIBPTHREAD} != "no"
+_libpthread= libpthread
+.endif
+
+.if ${MK_LIBTHR} != "no"
+_libthr= libthr
+.endif
+
+.if ${MACHINE_ARCH} != "arm" && ${MACHINE_ARCH} != "powerpc"
+_libthread_db= libthread_db
+.endif
+
+.if ${MK_USB} != "no"
+_libusbhid= libusbhid
+.endif
+
+.if ${MK_NIS} != "no"
+_libypclnt= libypclnt
+.endif
+
+.if ${MK_GPIB} != "no"
+_libgpib= libgpib
+.endif
+
+.include <bsd.subdir.mk>
diff --git a/lib/Makefile.inc b/lib/Makefile.inc
new file mode 100644
index 0000000..ae850ba
--- /dev/null
+++ b/lib/Makefile.inc
@@ -0,0 +1,3 @@
+# $FreeBSD$
+# Default version for system libs (override in <lib>/Makefile if necessary)
+SHLIB_MAJOR?= 3
diff --git a/lib/bind/Makefile b/lib/bind/Makefile
new file mode 100644
index 0000000..5eccf49
--- /dev/null
+++ b/lib/bind/Makefile
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+SUBDIR= bind bind9 dns isc isccc isccfg lwres
+
+.include <bsd.subdir.mk>
diff --git a/lib/bind/bind/Makefile b/lib/bind/bind/Makefile
new file mode 100644
index 0000000..c10025c
--- /dev/null
+++ b/lib/bind/bind/Makefile
@@ -0,0 +1,83 @@
+# $FreeBSD$
+
+#.include <bsd.own.mk>
+
+BIND_DIR= ${.CURDIR}/../../../contrib/bind9
+LIB_BIND_REL= ..
+LIB_BIND_DIR= ${.CURDIR}/${LIB_BIND_REL}
+SRCDIR= ${BIND_DIR}/lib/bind
+
+# XXX These should come before -I's from config.mk.
+CFLAGS+= -I${SRCDIR}/port/freebsd/include -I${SRCDIR}/include
+CFLAGS+= -I${.CURDIR}
+
+.include "${LIB_BIND_DIR}/config.mk"
+
+LIB= bind
+
+.PATH: ${SRCDIR}/bsd
+SRCS+= ftruncate.c gettimeofday.c \
+ mktemp.c putenv.c readv.c setenv.c \
+ setitimer.c strcasecmp.c strdup.c \
+ strerror.c strpbrk.c strtoul.c utimes.c \
+ writev.c
+
+.PATH: ${SRCDIR}/dst
+SRCS+= dst_api.c hmac_link.c md5_dgst.c support.c
+
+.PATH: ${SRCDIR}/inet
+SRCS+= inet_addr.c inet_cidr_ntop.c inet_cidr_pton.c \
+ inet_data.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
+
+.PATH: ${SRCDIR}/irs
+SRCS+= gethostent_r.c getnetgrent_r.c \
+ getprotoent_r.c getservent_r.c \
+ dns.c dns_ho.c dns_nw.c dns_pr.c \
+ dns_sv.c gai_strerror.c gen.c gen_ho.c \
+ gen_ng.c gen_nw.c gen_pr.c gen_sv.c \
+ getaddrinfo.c gethostent.c getnameinfo.c \
+ getnetent.c getnetent_r.c getnetgrent.c \
+ getprotoent.c getservent.c hesiod.c \
+ irp.c irp_ho.c irp_ng.c irp_nw.c \
+ irp_pr.c irp_sv.c irpmarshall.c irs_data.c \
+ lcl.c lcl_ho.c lcl_ng.c lcl_nw.c \
+ lcl_pr.c lcl_sv.c nis.c nul_ng.c util.c
+
+.PATH: ${SRCDIR}/isc
+SRCS+= assertions.c base64.c bitncmp.c ctl_clnt.c \
+ ctl_p.c ctl_srvr.c ev_connects.c ev_files.c \
+ ev_streams.c ev_timers.c ev_waits.c \
+ eventlib.c heap.c hex.c logging.c \
+ memcluster.c movefile.c tree.c
+
+.PATH: ${SRCDIR}/nameser
+SRCS+= ns_date.c ns_name.c ns_netint.c \
+ ns_parse.c ns_print.c ns_samedomain.c \
+ ns_sign.c ns_ttl.c ns_verify.c
+
+.PATH: ${SRCDIR}/resolv
+SRCS+= herror.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_sendsigned.c res_update.c
+
+#.if ${MK_BIND_LIBS} != "no"
+#INCS= ${SRCDIR}/include/isc/assertions.h \
+# ${SRCDIR}/include/isc/ctl.h \
+# ${SRCDIR}/include/isc/dst.h \
+# ${SRCDIR}/include/isc/eventlib.h \
+# ${SRCDIR}/include/isc/heap.h \
+# ${SRCDIR}/include/isc/irpmarshall.h \
+# ${SRCDIR}/include/isc/list.h \
+# ${SRCDIR}/include/isc/logging.h \
+# ${SRCDIR}/include/isc/memcluster.h \
+# ${SRCDIR}/include/isc/misc.h \
+# ${SRCDIR}/include/isc/tree.h
+#
+#INCSDIR= ${INCLUDEDIR}/isc
+#.endif
+
+.include <bsd.lib.mk>
diff --git a/lib/bind/bind/config.h b/lib/bind/bind/config.h
new file mode 100644
index 0000000..5177431
--- /dev/null
+++ b/lib/bind/bind/config.h
@@ -0,0 +1,60 @@
+/* $FreeBSD$ */
+
+/* config.h. Generated by configure. */
+/* #undef _SOCKADDR_LEN */
+#define HAVE_FCNTL_H 1
+#define HAVE_PATHS_H 1
+#define HAVE_INTTYPES_H 1
+/* #undef HAVE_STROPTS_H */
+#define HAVE_SYS_TIMERS_H 1
+/* #undef SYS_CDEFS_H */
+/* #undef _POSIX_PTHREAD_SEMANTICS */
+/* #undef POSIX_GETPWUID_R */
+/* #undef POSIX_GETPWNAM_R */
+/* #undef POSIX_GETGRGID_R */
+/* #undef POSIX_GETGRNAM_R */
+
+/* #undef NEED_SETGROUPENT */
+/* #undef NEED_GETGROUPLIST */
+
+/* define if prototype for getgrnam_r() is required */
+/* #undef NEED_GETGRNAM_R */
+/* #undef NEED_GETGRGID_R */
+/* #undef NEED_GETGRENT_R */
+#define NEED_SETGRENT_R 1
+#define NEED_ENDGRENT_R 1
+
+#define NEED_INNETGR_R 1
+/* #undef NEED_SETNETGRENT_R */
+#define NEED_ENDNETGRENT_R 1
+
+/* #undef NEED_GETPWNAM_R */
+/* #undef NEED_GETPWUID_R */
+#define NEED_SETPWENT_R 1
+#define NEED_SETPASSENT_R 1
+#define NEED_SETPWENT_R 1
+/* #undef NEED_GETPWENT_R */
+#define NEED_ENDPWENT_R 1
+
+/* #undef NEED_SETPASSENT */
+
+#define HAS_PW_CLASS 1
+
+/* #undef uintptr_t */
+
+/* Shut up warnings about sputaux in stdio.h on BSD/OS pre-4.1 */
+/* #undef SHUTUP_SPUTAUX */
+#ifdef SHUTUP_SPUTAUX
+struct __sFILE;
+extern __inline int __sputaux(int _c, struct __sFILE *_p);
+#endif
+/* #undef BROKEN_IN6ADDR_INIT_MACROS */
+#define HAVE_STRLCAT 1
+/* Shut up warnings about missing braces */
+/* #undef SHUTUP_MUTEX_INITIALIZER */
+#ifdef SHUTUP_MUTEX_INITIALIZER
+#define LIBBIND_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER }
+#else
+#define LIBBIND_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
+#endif
+
diff --git a/lib/bind/bind/port_after.h b/lib/bind/bind/port_after.h
new file mode 100644
index 0000000..93b8e75
--- /dev/null
+++ b/lib/bind/bind/port_after.h
@@ -0,0 +1,413 @@
+/* $FreeBSD$ */
+
+#ifndef port_after_h
+#define port_after_h
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/param.h>
+#if (!defined(BSD)) || (BSD < 199306)
+#include <sys/bitypes.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+#undef NEED_PSELECT
+#define HAVE_SA_LEN 1
+#define HAVE_MINIMUM_IFREQ 1
+#undef NEED_DAEMON
+#undef NEED_STRSEP
+#undef NEED_STRERROR
+#define HAS_INET6_STRUCTS 1
+#define HAVE_SIN6_SCOPE_ID 1
+#undef NEED_IN6ADDR_ANY
+#undef HAS_IN_ADDR6
+#define HAVE_SOCKADDR_STORAGE 1
+#undef NEED_GETTIMEOFDAY
+#undef HAVE_STRNDUP
+#undef USE_FIONBIO_IOCTL
+#undef USE_SYSERROR_LIST
+#undef INNETGR_ARGS
+#undef SETNETGRENT_ARGS
+#define USE_IFNAMELINKID 1
+#define PORT_NONBLOCK O_NONBLOCK
+
+/*
+ * We need to know the IPv6 address family number even on IPv4-only systems.
+ * Note that this is NOT a protocol constant, and that if the system has its
+ * own AF_INET6, different from ours below, all of BIND's libraries and
+ * executables will need to be recompiled after the system <sys/socket.h>
+ * has had this type added. The type number below is correct on most BSD-
+ * derived systems for which AF_INET6 is defined.
+ */
+#ifndef AF_INET6
+#define AF_INET6 24
+#endif
+
+#ifndef PF_INET6
+#define PF_INET6 AF_INET6
+#endif
+
+#ifdef HAS_IN_ADDR6
+/* Map to pre-RFC structure. */
+#define in6_addr in_addr6
+#endif
+
+#ifndef HAS_INET6_STRUCTS
+/* Replace with structure from later rev of O/S if known. */
+struct in6_addr {
+ u_int8_t s6_addr[16];
+};
+
+#define IN6ADDR_ANY_INIT \
+ {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}
+
+#define IN6ADDR_LOOPBACK_INIT \
+ {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }}
+
+/* Replace with structure from later rev of O/S if known. */
+struct sockaddr_in6 {
+#ifdef HAVE_SA_LEN
+ u_int8_t sin6_len; /* length of this struct */
+ u_int8_t sin6_family; /* AF_INET6 */
+#else
+ u_int16_t sin6_family; /* AF_INET6 */
+#endif
+ u_int16_t sin6_port; /* transport layer port # */
+ u_int32_t sin6_flowinfo; /* IPv6 flow information */
+ struct in6_addr sin6_addr; /* IPv6 address */
+ u_int32_t sin6_scope_id; /* set of interfaces for a scope */
+};
+#endif /* HAS_INET6_STRUCTS */
+
+#ifdef BROKEN_IN6ADDR_INIT_MACROS
+#undef IN6ADDR_ANY_INIT
+#undef IN6ADDR_LOOPBACK_INIT
+#endif
+
+#ifdef _AIX
+#ifndef IN6ADDR_ANY_INIT
+#define IN6ADDR_ANY_INIT {{{ 0, 0, 0, 0 }}}
+#endif
+#ifndef IN6ADDR_LOOPBACK_INIT
+#if BYTE_ORDER == BIG_ENDIAN
+#define IN6ADDR_LOOPBACK_INIT {{{ 0, 0, 0, 1 }}}
+#else
+#define IN6ADDR_LOOPBACK_INIT {{{0, 0, 0, 0x01000000}}}
+#endif
+#endif
+#endif
+
+#ifndef IN6ADDR_ANY_INIT
+#ifdef s6_addr
+#define IN6ADDR_ANY_INIT \
+ {{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}}
+#else
+#define IN6ADDR_ANY_INIT \
+ {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}
+#endif
+
+#endif
+#ifndef IN6ADDR_LOOPBACK_INIT
+#ifdef s6_addr
+#define IN6ADDR_LOOPBACK_INIT \
+ {{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }}}
+#else
+#define IN6ADDR_LOOPBACK_INIT \
+ {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }}
+#endif
+#endif
+
+#ifndef HAVE_SOCKADDR_STORAGE
+#define __SS_MAXSIZE 128
+#define __SS_ALLIGSIZE (sizeof (long))
+
+struct sockaddr_storage {
+#ifdef HAVE_SA_LEN
+ u_int8_t ss_len; /* address length */
+ u_int8_t ss_family; /* address family */
+ char __ss_pad1[__SS_ALLIGSIZE - 2 * sizeof(u_int8_t)];
+ long __ss_align;
+ char __ss_pad2[__SS_MAXSIZE - 2 * __SS_ALLIGSIZE];
+#else
+ u_int16_t ss_family; /* address family */
+ char __ss_pad1[__SS_ALLIGSIZE - sizeof(u_int16_t)];
+ long __ss_align;
+ char __ss_pad2[__SS_MAXSIZE - 2 * __SS_ALLIGSIZE];
+#endif
+};
+#endif
+
+
+#if !defined(HAS_INET6_STRUCTS) || defined(NEED_IN6ADDR_ANY)
+#define in6addr_any isc_in6addr_any
+extern const struct in6_addr in6addr_any;
+#endif
+
+/*
+ * IN6_ARE_ADDR_EQUAL, IN6_IS_ADDR_UNSPECIFIED, IN6_IS_ADDR_V4COMPAT and
+ * IN6_IS_ADDR_V4MAPPED are broken in glibc 2.1.
+ */
+#ifdef __GLIBC__
+#if __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 2)
+#undef IN6_ARE_ADDR_EQUAL
+#undef IN6_IS_ADDR_UNSPECIFIED
+#undef IN6_IS_ADDR_V4COMPAT
+#undef IN6_IS_ADDR_V4MAPPED
+#endif
+#endif
+
+#ifndef IN6_ARE_ADDR_EQUAL
+#define IN6_ARE_ADDR_EQUAL(a,b) \
+ (memcmp(&(a)->s6_addr[0], &(b)->s6_addr[0], sizeof(struct in6_addr)) == 0)
+#endif
+
+#ifndef IN6_IS_ADDR_UNSPECIFIED
+#define IN6_IS_ADDR_UNSPECIFIED(a) \
+ IN6_ARE_ADDR_EQUAL(a, &in6addr_any)
+#endif
+
+#ifndef IN6_IS_ADDR_LOOPBACK
+extern const struct in6_addr isc_in6addr_loopback;
+#define IN6_IS_ADDR_LOOPBACK(a) \
+ IN6_ARE_ADDR_EQUAL(a, &isc_in6addr_loopback)
+#endif
+
+#ifndef IN6_IS_ADDR_V4MAPPED
+#define IN6_IS_ADDR_V4MAPPED(a) \
+ ((a)->s6_addr[0] == 0x00 && (a)->s6_addr[1] == 0x00 && \
+ (a)->s6_addr[2] == 0x00 && (a)->s6_addr[3] == 0x00 && \
+ (a)->s6_addr[4] == 0x00 && (a)->s6_addr[5] == 0x00 && \
+ (a)->s6_addr[6] == 0x00 && (a)->s6_addr[9] == 0x00 && \
+ (a)->s6_addr[8] == 0x00 && (a)->s6_addr[9] == 0x00 && \
+ (a)->s6_addr[10] == 0xff && (a)->s6_addr[11] == 0xff)
+#endif
+
+#ifndef IN6_IS_ADDR_SITELOCAL
+#define IN6_IS_ADDR_SITELOCAL(a) \
+ (((a)->s6_addr[0] == 0xfe) && (((a)->s6_addr[1] & 0xc0) == 0xc0))
+#endif
+
+#ifndef IN6_IS_ADDR_LINKLOCAL
+#define IN6_IS_ADDR_LINKLOCAL(a) \
+ (((a)->s6_addr[0] == 0xfe) && (((a)->s6_addr[1] & 0xc0) == 0x80))
+#endif
+
+#ifndef IN6_IS_ADDR_MULTICAST
+#define IN6_IS_ADDR_MULTICAST(a) ((a)->s6_addr[0] == 0xff)
+#endif
+
+#ifndef __IPV6_ADDR_MC_SCOPE
+#define __IPV6_ADDR_MC_SCOPE(a) ((a)->s6_addr[1] & 0x0f)
+#endif
+
+#ifndef __IPV6_ADDR_SCOPE_SITELOCAL
+#define __IPV6_ADDR_SCOPE_SITELOCAL 0x05
+#endif
+#ifndef __IPV6_ADDR_SCOPE_ORGLOCAL
+#define __IPV6_ADDR_SCOPE_ORGLOCAL 0x08
+#endif
+
+#ifndef IN6_IS_ADDR_MC_SITELOCAL
+#define IN6_IS_ADDR_MC_SITELOCAL(a) \
+ (IN6_IS_ADDR_MULTICAST(a) && \
+ (__IPV6_ADDR_MC_SCOPE(a) == __IPV6_ADDR_SCOPE_SITELOCAL))
+#endif
+
+#ifndef IN6_IS_ADDR_MC_ORGLOCAL
+#define IN6_IS_ADDR_MC_ORGLOCAL(a) \
+ (IN6_IS_ADDR_MULTICAST(a) && \
+ (__IPV6_ADDR_MC_SCOPE(a) == __IPV6_ADDR_SCOPE_ORGLOCAL))
+#endif
+
+#ifndef INADDR_NONE
+#define INADDR_NONE 0xffffffff
+#endif
+
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 256
+#endif
+
+#ifndef INET6_ADDRSTRLEN
+/* sizeof("aaaa:bbbb:cccc:dddd:eeee:ffff:123.123.123.123") */
+#define INET6_ADDRSTRLEN 46
+#endif
+
+#ifndef MIN
+#define MIN(x,y) (((x) <= (y)) ? (x) : (y))
+#endif
+
+#ifndef MAX
+#define MAX(x,y) (((x) >= (y)) ? (x) : (y))
+#endif
+
+#ifdef NEED_DAEMON
+int daemon(int nochdir, int noclose);
+#endif
+
+#ifdef NEED_STRSEP
+char * strsep(char **stringp, const char *delim);
+#endif
+
+#ifndef ALIGN
+#define ALIGN(p) (((uintptr_t)(p) + (sizeof(long) - 1)) & ~(sizeof(long) - 1))
+#endif
+
+#ifdef NEED_SETGROUPENT
+int setgroupent(int stayopen);
+#endif
+
+#ifdef NEED_GETGROUPLIST
+int getgrouplist(GETGROUPLIST_ARGS);
+#endif
+
+#ifdef POSIX_GETGRNAM_R
+int
+__posix_getgrnam_r(const char *, struct group *, char *, int, struct group **);
+#endif
+
+#ifdef NEED_GETGRNAM_R
+int
+getgrnam_r(const char *, struct group *, char *, size_t, struct group **);
+#endif
+
+#ifdef POSIX_GETGRGID_R
+int
+__posix_getgrgid_r(gid_t, struct group *, char *, int, struct group **) ;
+#endif
+
+#ifdef NEED_GETGRGID_R
+int
+getgrgid_r(gid_t, struct group *, char *, size_t, struct group **);
+#endif
+
+#ifdef NEED_GETGRENT_R
+GROUP_R_RETURN getgrent_r(struct group *gptr, GROUP_R_ARGS);
+#endif
+
+#ifdef NEED_SETGRENT_R
+GROUP_R_SET_RETURN setgrent_r(GROUP_R_ENT_ARGS);
+#endif
+
+#ifdef NEED_ENDGRENT_R
+GROUP_R_END_RETURN endgrent_r(GROUP_R_ENT_ARGS);
+#endif
+
+#if defined(NEED_INNETGR_R) && defined(NGR_R_RETURN)
+NGR_R_RETURN
+innetgr_r(const char *, const char *, const char *, const char *);
+#endif
+
+#ifdef NEED_SETNETGRENT_R
+#ifdef NGR_R_ENT_ARGS
+NGR_R_SET_RETURN setnetgrent_r(const char *netgroup, NGR_R_ENT_ARGS);
+#else
+NGR_R_SET_RETURN setnetgrent_r(const char *netgroup);
+#endif
+#endif
+
+#ifdef NEED_ENDNETGRENT_R
+#ifdef NGR_R_ENT_ARGS
+NGR_R_END_RETURN endnetgrent_r(NGR_R_ENT_ARGS);
+#else
+NGR_R_END_RETURN endnetgrent_r(void);
+#endif
+#endif
+
+#ifdef POSIX_GETPWNAM_R
+int
+__posix_getpwnam_r(const char *login, struct passwd *pwptr,
+ char *buf, size_t buflen, struct passwd **result);
+#endif
+
+#ifdef NEED_GETPWNAM_R
+int
+getpwnam_r(const char *login, struct passwd *pwptr,
+ char *buf, size_t buflen, struct passwd **result);
+#endif
+
+#ifdef POSIX_GETPWUID_R
+int
+__posix_getpwuid_r(uid_t uid, struct passwd *pwptr,
+ char *buf, int buflen, struct passwd **result);
+#endif
+
+#ifdef NEED_GETPWUID_R
+int
+getpwuid_r(uid_t uid, struct passwd *pwptr,
+ char *buf, size_t buflen, struct passwd **result);
+#endif
+
+#ifdef NEED_SETPWENT_R
+#ifdef PASS_R_ENT_ARGS
+PASS_R_SET_RETURN setpwent_r(PASS_R_ENT_ARGS);
+#else
+PASS_R_SET_RETURN setpwent_r(void);
+#endif
+
+#endif
+
+#ifdef NEED_SETPASSENT_R
+#ifdef PASS_R_ENT_ARGS
+PASS_R_SET_RETURN setpassent_r(int stayopen, PASS_R_ENT_ARGS);
+#else
+PASS_R_SET_RETURN setpassent_r(int stayopen);
+#endif
+#endif
+
+#ifdef NEED_GETPWENT_R
+PASS_R_RETURN getpwent_r(struct passwd *pwptr, PASS_R_ARGS);
+#endif
+
+#ifdef NEED_ENDPWENT_R
+void endpwent_r(void);
+#endif
+
+#ifdef NEED_SETPASSENT
+int setpassent(int stayopen);
+#endif
+
+#define gettimeofday isc__gettimeofday
+#ifdef NEED_GETTIMEOFDAY
+int isc__gettimeofday(struct timeval *tvp, struct _TIMEZONE *tzp);
+#else
+int isc__gettimeofday(struct timeval *tp, struct timezone *tzp);
+#endif
+
+int getnetgrent(char **machinep, char **userp, char **domainp);
+
+#ifdef NGR_R_ARGS
+int getnetgrent_r(char **machinep, char **userp, char **domainp, NGR_R_ARGS);
+#endif
+
+#ifdef SETNETGRENT_ARGS
+void setnetgrent(SETNETGRENT_ARGS);
+#else
+void setnetgrent(const char *netgroup);
+#endif
+
+void endnetgrent(void);
+
+#ifdef INNETGR_ARGS
+int innetgr(INNETGR_ARGS);
+#else
+int innetgr(const char *netgroup, const char *machine,
+ const char *user, const char *domain);
+#endif
+
+#ifdef NGR_R_ENT_ARGS
+NGR_R_SET_RETURN
+setnetgrent_r(const char *netgroup, NGR_R_ENT_ARGS);
+#else
+NGR_R_SET_RETURN
+setnetgrent_r(const char *netgroup);
+#endif
+#endif
diff --git a/lib/bind/bind/port_before.h b/lib/bind/bind/port_before.h
new file mode 100644
index 0000000..712de93
--- /dev/null
+++ b/lib/bind/bind/port_before.h
@@ -0,0 +1,148 @@
+/* $FreeBSD$ */
+
+#ifndef port_before_h
+#define port_before_h
+#include <config.h>
+
+struct group; /* silence warning */
+struct passwd; /* silence warning */
+struct timeval; /* silence warning */
+struct timezone; /* silence warning */
+
+#ifdef HAVE_SYS_TIMERS_H
+#include <sys/timers.h>
+#endif
+#include <limits.h>
+
+
+#undef WANT_IRS_GR
+#undef WANT_IRS_NIS
+#undef WANT_IRS_PW
+
+#undef BSD_COMP
+#undef HAVE_POLL
+#undef HAVE_MD5
+#undef SOLARIS2
+
+#undef DO_PTHREADS
+#define GETGROUPLIST_ARGS const char *name, gid_t basegid, gid_t *groups, int *ngroups
+#define GETNETBYADDR_ADDR_T long
+#define SETPWENT_VOID 1
+#undef SETGRENT_VOID
+
+#define NET_R_ARGS char *buf, int buflen
+#define NET_R_BAD NULL
+#define NET_R_COPY buf, buflen
+#define NET_R_COPY_ARGS NET_R_ARGS
+#define NET_R_END_RESULT(x) /*empty*/
+#define NET_R_END_RETURN void
+#undef NET_R_ENT_ARGS /*empty*/
+#define NET_R_OK nptr
+#define NET_R_RETURN struct netent *
+#undef NET_R_SET_RESULT /*empty*/
+#undef NET_R_SETANSWER
+#define NET_R_SET_RETURN void
+#undef NETENT_DATA
+
+
+#define GROUP_R_SET_RETURN void
+#undef GROUP_R_SET_RESULT /*empty*/
+#define GROUP_R_END_RETURN void
+#define GROUP_R_END_RESULT(x) /*empty*/
+
+#define GROUP_R_ENT_ARGS void
+
+
+
+#define HOST_R_ARGS char *buf, int buflen, int *h_errnop
+#define HOST_R_BAD NULL
+#define HOST_R_COPY buf, buflen
+#define HOST_R_COPY_ARGS char *buf, int buflen
+#define HOST_R_END_RESULT(x) /*empty*/
+#define HOST_R_END_RETURN void
+#undef HOST_R_ENT_ARGS /*empty*/
+#define HOST_R_ERRNO *h_errnop = h_errno
+#define HOST_R_OK hptr
+#define HOST_R_RETURN struct hostent *
+#undef HOST_R_SETANSWER
+#undef HOST_R_SET_RESULT
+#define HOST_R_SET_RETURN void
+#undef HOSTENT_DATA
+
+#define NGR_R_ARGS char *buf, int buflen
+#define NGR_R_BAD (0)
+#define NGR_R_COPY buf, buflen
+#define NGR_R_COPY_ARGS NGR_R_ARGS
+#define NGR_R_END_RESULT(x) /*empty*/
+#define NGR_R_END_RETURN void
+#undef NGR_R_ENT_ARGS /*empty*/
+#define NGR_R_OK 1
+#define NGR_R_RETURN int
+#undef NGR_R_SET_RESULT /*empty*/
+#define NGR_R_SET_RETURN void
+
+
+#define PROTO_R_ARGS char *buf, int buflen
+#define PROTO_R_BAD NULL
+#define PROTO_R_COPY buf, buflen
+#define PROTO_R_COPY_ARGS PROTO_R_ARGS
+#define PROTO_R_END_RESULT(x) /*empty*/
+#define PROTO_R_END_RETURN void
+#undef PROTO_R_ENT_ARGS /*empty*/
+#define PROTO_R_OK pptr
+#undef PROTO_R_SETANSWER
+#define PROTO_R_RETURN struct protoent *
+#undef PROTO_R_SET_RESULT
+#define PROTO_R_SET_RETURN void
+
+
+
+
+
+#define PASS_R_END_RESULT(x) /*empty*/
+#define PASS_R_END_RETURN void
+#undef PASS_R_ENT_ARGS
+
+
+#undef PASS_R_SET_RESULT /*empty*/
+#define PASS_R_SET_RETURN void
+
+#define SERV_R_ARGS char *buf, int buflen
+#define SERV_R_BAD NULL
+#define SERV_R_COPY buf, buflen
+#define SERV_R_COPY_ARGS SERV_R_ARGS
+#define SERV_R_END_RESULT(x) /*empty*/
+#define SERV_R_END_RETURN void
+#undef SERV_R_ENT_ARGS /*empty*/
+#define SERV_R_OK sptr
+#undef SERV_R_SETANSWER
+#define SERV_R_RETURN struct servent *
+#undef SERV_R_SET_RESULT
+#define SERV_R_SET_RETURN void
+
+
+#define DE_CONST(konst, var) \
+ do { \
+ union { const void *k; void *v; } _u; \
+ _u.k = konst; \
+ var = _u.v; \
+ } while (0)
+
+#define UNUSED(x) (x) = (x)
+
+#undef NEED_SOLARIS_BITTYPES
+#define ISC_SOCKLEN_T socklen_t
+
+#ifdef __GNUC__
+#define ISC_FORMAT_PRINTF(fmt, args) \
+ __attribute__((__format__(__printf__, fmt, args)))
+#else
+#define ISC_FORMAT_PRINTF(fmt, args)
+#endif
+
+/* Pull in host order macros when _XOPEN_SOURCE_EXTENDED is defined. */
+#if defined(__hpux) && defined(_XOPEN_SOURCE_EXTENDED)
+#include <sys/byteorder.h>
+#endif
+
+#endif
diff --git a/lib/bind/bind9/Makefile b/lib/bind/bind9/Makefile
new file mode 100644
index 0000000..68f72d7
--- /dev/null
+++ b/lib/bind/bind9/Makefile
@@ -0,0 +1,27 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+BIND_DIR= ${.CURDIR}/../../../contrib/bind9
+LIB_BIND_REL= ..
+LIB_BIND_DIR= ${.CURDIR}/${LIB_BIND_REL}
+SRCDIR= ${BIND_DIR}/lib/bind9
+
+.include "${LIB_BIND_DIR}/config.mk"
+
+LIB= bind9
+
+.PATH: ${SRCDIR}
+SRCS= check.c getaddresses.c version.c
+
+CFLAGS+= -I${SRCDIR}/include
+
+.if ${MK_BIND_LIBS} != "no"
+INCS= ${SRCDIR}/include/bind9/check.h \
+ ${SRCDIR}/include/bind9/getaddresses.h \
+ ${SRCDIR}/include/bind9/version.h
+
+INCSDIR= ${INCLUDEDIR}/bind9
+.endif
+
+.include <bsd.lib.mk>
diff --git a/lib/bind/config.h b/lib/bind/config.h
new file mode 100644
index 0000000..df9f40e
--- /dev/null
+++ b/lib/bind/config.h
@@ -0,0 +1,277 @@
+/* $FreeBSD$ */
+
+/* config.h. Generated by configure. */
+/* config.h.in. Generated from configure.in by autoheader. */
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2003 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.
+ */
+
+/* $Id: acconfig.h,v 1.35.2.4.2.10 2004/12/04 06:50:02 marka Exp $ */
+
+/***
+ *** This file is not to be included by any public header files, because
+ *** it does not get installed.
+ ***/
+
+/* define to `int' if <sys/types.h> doesn't define. */
+/* #undef ssize_t */
+
+/* define on DEC OSF to enable 4.4BSD style sa_len support */
+/* #undef _SOCKADDR_LEN */
+
+/* define if your system needs pthread_init() before using pthreads */
+/* #undef NEED_PTHREAD_INIT */
+
+/* define if your system has sigwait() */
+/* #undef HAVE_SIGWAIT */
+
+/* define if sigwait() is the UnixWare flavor */
+/* #undef HAVE_UNIXWARE_SIGWAIT */
+
+/* define on Solaris to get sigwait() to work using pthreads semantics */
+/* #undef _POSIX_PTHREAD_SEMANTICS */
+
+/* define if LinuxThreads is in use */
+/* #undef HAVE_LINUXTHREADS */
+
+/* define if sysconf() is available */
+/* #undef HAVE_SYSCONF */
+
+/* define if sysctlbyname() is available */
+#define HAVE_SYSCTLBYNAME 1
+
+/* define if catgets() is available */
+#define HAVE_CATGETS 1
+
+/* define if getifaddrs() exists */
+#define HAVE_GETIFADDRS 1
+
+/* define if you have the NET_RT_IFLIST sysctl variable and sys/sysctl.h */
+#define HAVE_IFLIST_SYSCTL 1
+
+/* define if chroot() is available */
+#define HAVE_CHROOT 1
+
+/* define if tzset() is available */
+#define HAVE_TZSET 1
+
+/* define if struct addrinfo exists */
+#define HAVE_ADDRINFO 1
+
+/* define if getaddrinfo() exists */
+#define HAVE_GETADDRINFO 1
+
+/* define if gai_strerror() exists */
+#define HAVE_GAISTRERROR 1
+
+/* define if arc4random() exists */
+#define HAVE_ARC4RANDOM 1
+
+/* define if pthread_setconcurrency() should be called to tell the
+ * OS how many threads we might want to run.
+ */
+/* #undef CALL_PTHREAD_SETCONCURRENCY */
+
+/* define if IPv6 is not disabled */
+/* #undef WANT_IPV6 */
+
+/* define if flockfile() is available */
+#define HAVE_FLOCKFILE 1
+
+/* define if getc_unlocked() is available */
+#define HAVE_GETCUNLOCKED 1
+
+/* Shut up warnings about sputaux in stdio.h on BSD/OS pre-4.1 */
+/* #undef SHUTUP_SPUTAUX */
+#ifdef SHUTUP_SPUTAUX
+struct __sFILE;
+extern __inline int __sputaux(int _c, struct __sFILE *_p);
+#endif
+
+/* Shut up warnings about missing sigwait prototype on BSD/OS 4.0* */
+/* #undef SHUTUP_SIGWAIT */
+#ifdef SHUTUP_SIGWAIT
+int sigwait(const unsigned int *set, int *sig);
+#endif
+
+/* Shut up warnings from gcc -Wcast-qual on BSD/OS 4.1. */
+/* #undef SHUTUP_STDARG_CAST */
+#if defined(SHUTUP_STDARG_CAST) && defined(__GNUC__)
+#include <stdarg.h> /* Grr. Must be included *every time*. */
+/*
+ * The silly continuation line is to keep configure from
+ * commenting out the #undef.
+ */
+#undef \
+ va_start
+#define va_start(ap, last) \
+ do { \
+ union { const void *konst; long *var; } _u; \
+ _u.konst = &(last); \
+ ap = (va_list)(_u.var + __va_words(__typeof(last))); \
+ } while (0)
+#endif /* SHUTUP_STDARG_CAST && __GNUC__ */
+
+/* define if the system has a random number generating device */
+#define PATH_RANDOMDEV "/dev/random"
+
+/* define if pthread_attr_getstacksize() is available */
+/* #undef HAVE_PTHREAD_ATTR_GETSTACKSIZE */
+
+/* define if pthread_attr_setstacksize() is available */
+/* #undef HAVE_PTHREAD_ATTR_SETSTACKSIZE */
+
+/* define if you have strerror in the C library. */
+#define HAVE_STRERROR 1
+
+/* Define if you are running under Compaq TruCluster. */
+/* #undef HAVE_TRUCLUSTER */
+
+/* Define if OpenSSL includes DSA support */
+#define HAVE_OPENSSL_DSA 1
+
+/* Define to the length type used by the socket API (socklen_t, size_t, int). */
+#define ISC_SOCKADDR_LEN_T socklen_t
+
+/* Define if threads need PTHREAD_SCOPE_SYSTEM */
+/* #undef NEED_PTHREAD_SCOPE_SYSTEM */
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `c' library (-lc). */
+/* #undef HAVE_LIBC */
+
+/* Define to 1 if you have the `c_r' library (-lc_r). */
+/* #undef HAVE_LIBC_R */
+
+/* Define to 1 if you have the `nsl' library (-lnsl). */
+/* #undef HAVE_LIBNSL */
+
+/* Define to 1 if you have the `pthread' library (-lpthread). */
+/* #undef HAVE_LIBPTHREAD */
+
+/* Define to 1 if you have the `scf' library (-lscf). */
+/* #undef HAVE_LIBSCF */
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+/* #undef HAVE_LIBSOCKET */
+
+/* Define to 1 if you have the <linux/capability.h> header file. */
+/* #undef HAVE_LINUX_CAPABILITY_H */
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <net/if6.h> header file. */
+/* #undef HAVE_NET_IF6_H */
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/prctl.h> header file. */
+/* #undef HAVE_SYS_PRCTL_H */
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#define HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/sockio.h> header file. */
+#define HAVE_SYS_SOCKIO_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/sysctl.h> header file. */
+#define HAVE_SYS_SYSCTL_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define if running under Compaq TruCluster */
+/* #undef HAVE_TRUCLUSTER */
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Defined if extern char *optarg is not declared. */
+/* #undef NEED_OPTARG */
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME ""
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING ""
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION ""
+
+/* Sets which flag to pass to open/fcntl to make non-blocking
+ (O_NDELAY/O_NONBLOCK). */
+#define PORT_NONBLOCK O_NONBLOCK
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Defined if you need to use ioctl(FIONBIO) instead a fcntl call to make
+ non-blocking. */
+/* #undef USE_FIONBIO_IOCTL */
+
+/* Define to 1 if your processor stores words with the most significant byte
+ first (like Motorola and SPARC, unlike Intel and VAX). */
+/* #undef WORDS_BIGENDIAN */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define as `__inline' if that's what the C compiler calls it, or to nothing
+ if it is not supported. */
+/* #undef inline */
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+/* Define to `int' if <sys/types.h> does not define. */
+/* #undef ssize_t */
+
+/* Define to `unsigned long' if <sys/types.h> does not define. */
+/* #undef uintptr_t */
diff --git a/lib/bind/config.mk b/lib/bind/config.mk
new file mode 100644
index 0000000..d89207b
--- /dev/null
+++ b/lib/bind/config.mk
@@ -0,0 +1,99 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+# BIND version number
+.if defined(BIND_DIR) && exists(${BIND_DIR}/version)
+.include "${BIND_DIR}/version"
+BIND_VERSION= ${MAJORVER}.${MINORVER}.${PATCHVER}${RELEASETYPE}${RELEASEVER}
+CFLAGS+= -DVERSION='"${BIND_VERSION}"'
+.endif
+
+CFLAGS+= -DHAVE_CONFIG_H
+
+# Get version numbers (for libraries)
+.if defined(SRCDIR) && exists(${SRCDIR}/api)
+.include "${SRCDIR}/api"
+CFLAGS+= -DLIBINTERFACE=${LIBINTERFACE}
+CFLAGS+= -DLIBREVISION=${LIBREVISION}
+CFLAGS+= -DLIBAGE=${LIBAGE}
+.if ${MK_BIND_LIBS} != "no"
+SHLIB_MAJOR= ${LIBINTERFACE}
+SHLIB_MINOR= ${LIBINTERFACE}
+.else
+INTERNALLIB=
+.endif
+.endif
+
+# GSSAPI support is incomplete in 9.3.0
+#.if ${MK_KERBEROS} != "no"
+#CFLAGS+= -DGSSAPI
+#.endif
+
+# Enable IPv6 support if available
+.if ${MK_INET6_SUPPORT} != "no"
+CFLAGS+= -DWANT_IPV6
+.endif
+
+# Enable crypto if available
+.if ${MK_OPENSSL} != "no"
+CFLAGS+= -DOPENSSL
+.endif
+
+# Enable MD5 - BIND has its own implementation
+CFLAGS+= -DUSE_MD5
+
+# Endianness
+.if ${MACHINE_ARCH} == "powerpc" || ${MACHINE_ARCH} == "sparc64"
+CFLAGS+= -DWORDS_BIGENDIAN
+.endif
+
+# Default file locations
+LOCALSTATEDIR= /var
+SYSCONFDIR= /etc/namedb
+CFLAGS+= -DNS_LOCALSTATEDIR='"${LOCALSTATEDIR}"'
+CFLAGS+= -DNS_SYSCONFDIR='"${SYSCONFDIR}"'
+CFLAGS+= -DNAMED_CONFFILE='"${SYSCONFDIR}/named.conf"'
+CFLAGS+= -DRNDC_CONFFILE='"${SYSCONFDIR}/rndc.conf"'
+CFLAGS+= -DRNDC_KEYFILE='"${SYSCONFDIR}/rndc.key"'
+
+# Add correct include path for config.h
+.if defined(LIB_BIND_DIR) && exists(${LIB_BIND_DIR}/config.h)
+CFLAGS+= -I${LIB_BIND_DIR}
+.endif
+
+# Link against BIND libraries
+.if ${MK_BIND_LIBS} == "no"
+LIBBIND9= ${LIB_BIND_REL}/bind9/libbind9.a
+CFLAGS+= -I${BIND_DIR}/lib/bind9/include
+LIBDNS= ${LIB_BIND_REL}/dns/libdns.a
+CFLAGS+= -I${BIND_DIR}/lib/dns/include/dst \
+ -I${BIND_DIR}/lib/dns/include \
+ -I${LIB_BIND_DIR}/dns
+LIBISCCC= ${LIB_BIND_REL}/isccc/libisccc.a
+CFLAGS+= -I${BIND_DIR}/lib/isccc/include
+LIBISCCFG= ${LIB_BIND_REL}/isccfg/libisccfg.a
+CFLAGS+= -I${BIND_DIR}/lib/isccfg/include
+LIBISC= ${LIB_BIND_REL}/isc/libisc.a
+CFLAGS+= -I${BIND_DIR}/lib/isc/unix/include \
+ -I${BIND_DIR}/lib/isc/nothreads/include \
+ -I${BIND_DIR}/lib/isc/include \
+ -I${LIB_BIND_DIR}/isc
+LIBLWRES= ${LIB_BIND_REL}/lwres/liblwres.a
+CFLAGS+= -I${BIND_DIR}/lib/lwres/unix/include \
+ -I${BIND_DIR}/lib/lwres/include \
+ -I${LIB_BIND_DIR}/lwres
+.endif
+BIND_DPADD= ${LIBBIND9} ${LIBDNS} ${LIBISCCC} ${LIBISCCFG} \
+ ${LIBISC} ${LIBLWRES}
+.if ${MK_BIND_LIBS} != "no"
+BIND_LDADD= -lbind9 -ldns -lisccc -lisccfg -lisc -llwres
+.else
+BIND_LDADD= ${BIND_DPADD}
+.endif
+
+# Link against crypto library
+.if ${MK_OPENSSL} != "no"
+CRYPTO_DPADD= ${LIBCRYPTO}
+CRYPTO_LDADD= -lcrypto
+.endif
diff --git a/lib/bind/dns/Makefile b/lib/bind/dns/Makefile
new file mode 100644
index 0000000..04be449
--- /dev/null
+++ b/lib/bind/dns/Makefile
@@ -0,0 +1,150 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+BIND_DIR= ${.CURDIR}/../../../contrib/bind9
+LIB_BIND_REL= ..
+LIB_BIND_DIR= ${.CURDIR}/${LIB_BIND_REL}
+SRCDIR= ${BIND_DIR}/lib/dns
+
+.include "${LIB_BIND_DIR}/config.mk"
+
+LIB= dns
+
+.PATH: ${SRCDIR}
+SRCS+= acl.c adb.c byaddr.c \
+ cache.c callbacks.c compress.c \
+ db.c dbiterator.c dbtable.c diff.c dispatch.c \
+ dnssec.c ds.c \
+ dst_api.c dst_lib.c dst_parse.c dst_result.c \
+ forward.c \
+ gssapi_link.c gssapictx.c hmac_link.c \
+ journal.c \
+ key.c \
+ keytable.c \
+ lib.c log.c lookup.c \
+ master.c masterdump.c message.c \
+ name.c ncache.c nsec.c \
+ openssl_link.c openssldh_link.c \
+ openssldsa_link.c opensslrsa_link.c \
+ order.c peer.c portlist.c \
+ rbt.c rbtdb.c rbtdb64.c rcode.c rdata.c \
+ rdatalist.c \
+ rdataset.c rdatasetiter.c rdataslab.c request.c \
+ resolver.c result.c rootns.c sdb.c soa.c ssu.c \
+ stats.c tcpmsg.c time.c timer.c tkey.c \
+ tsig.c ttl.c validator.c \
+ version.c view.c xfrin.c zone.c zonekey.c zt.c
+
+CFLAGS+= -I${SRCDIR}/include/dst -I${SRCDIR}/include -I${SRCDIR}
+CFLAGS+= -I${.CURDIR}
+
+DPADD= ${CRYPTO_DPADD}
+LDADD= ${CRYPTO_LDADD}
+
+.if ${MK_BIND_LIBS} != "no"
+DNSINCS= ${SRCDIR}/include/dns/acl.h \
+ ${SRCDIR}/include/dns/adb.h \
+ ${SRCDIR}/include/dns/bit.h \
+ ${SRCDIR}/include/dns/byaddr.h \
+ ${SRCDIR}/include/dns/cache.h \
+ ${SRCDIR}/include/dns/callbacks.h \
+ ${SRCDIR}/include/dns/cert.h \
+ ${SRCDIR}/include/dns/compress.h \
+ ${SRCDIR}/include/dns/db.h \
+ ${SRCDIR}/include/dns/dbiterator.h \
+ ${SRCDIR}/include/dns/dbtable.h \
+ ${SRCDIR}/include/dns/diff.h \
+ ${SRCDIR}/include/dns/dispatch.h \
+ ${SRCDIR}/include/dns/dnssec.h \
+ ${SRCDIR}/include/dns/ds.h \
+ ${SRCDIR}/include/dns/events.h \
+ ${SRCDIR}/include/dns/fixedname.h \
+ ${SRCDIR}/include/dns/forward.h \
+ ${SRCDIR}/include/dns/journal.h \
+ ${SRCDIR}/include/dns/keyflags.h \
+ ${SRCDIR}/include/dns/keytable.h \
+ ${SRCDIR}/include/dns/keyvalues.h \
+ ${SRCDIR}/include/dns/lib.h \
+ ${SRCDIR}/include/dns/log.h \
+ ${SRCDIR}/include/dns/lookup.h \
+ ${SRCDIR}/include/dns/master.h \
+ ${SRCDIR}/include/dns/masterdump.h \
+ ${SRCDIR}/include/dns/message.h \
+ ${SRCDIR}/include/dns/name.h \
+ ${SRCDIR}/include/dns/ncache.h \
+ ${SRCDIR}/include/dns/nsec.h \
+ ${SRCDIR}/include/dns/opcode.h \
+ ${SRCDIR}/include/dns/order.h \
+ ${SRCDIR}/include/dns/peer.h \
+ ${SRCDIR}/include/dns/portlist.h \
+ ${SRCDIR}/include/dns/rbt.h \
+ ${SRCDIR}/include/dns/rcode.h \
+ ${SRCDIR}/include/dns/rdata.h \
+ ${SRCDIR}/include/dns/rdatasetiter.h \
+ ${SRCDIR}/include/dns/rdataclass.h \
+ ${SRCDIR}/include/dns/rdatalist.h \
+ ${SRCDIR}/include/dns/rdataset.h \
+ ${SRCDIR}/include/dns/rdataslab.h \
+ ${SRCDIR}/include/dns/rdatatype.h \
+ ${SRCDIR}/include/dns/request.h \
+ ${SRCDIR}/include/dns/resolver.h \
+ ${SRCDIR}/include/dns/result.h \
+ ${SRCDIR}/include/dns/rootns.h \
+ ${SRCDIR}/include/dns/sdb.h \
+ ${SRCDIR}/include/dns/secalg.h \
+ ${SRCDIR}/include/dns/secproto.h \
+ ${SRCDIR}/include/dns/soa.h \
+ ${SRCDIR}/include/dns/ssu.h \
+ ${SRCDIR}/include/dns/stats.h \
+ ${SRCDIR}/include/dns/tcpmsg.h \
+ ${SRCDIR}/include/dns/time.h \
+ ${SRCDIR}/include/dns/timer.h \
+ ${SRCDIR}/include/dns/tkey.h \
+ ${SRCDIR}/include/dns/tsig.h \
+ ${SRCDIR}/include/dns/ttl.h \
+ ${SRCDIR}/include/dns/types.h \
+ ${SRCDIR}/include/dns/validator.h \
+ ${SRCDIR}/include/dns/version.h \
+ ${SRCDIR}/include/dns/view.h \
+ ${SRCDIR}/include/dns/xfrin.h \
+ ${SRCDIR}/include/dns/zone.h \
+ ${SRCDIR}/include/dns/zonekey.h \
+ ${SRCDIR}/include/dns/zt.h \
+ dns/enumtype.h \
+ dns/enumclass.h \
+ dns/rdatastruct.h
+
+DNSINCSDIR= ${INCLUDEDIR}/dns
+
+DSTINCS= ${SRCDIR}/include/dst/dst.h \
+ ${SRCDIR}/include/dst/gssapi.h \
+ ${SRCDIR}/include/dst/lib.h \
+ ${SRCDIR}/include/dst/result.h
+
+DSTINCSDIR= ${INCLUDEDIR}/dst
+
+INCSGROUPS= DNSINCS DSTINCS
+.endif
+
+.if defined(MAINTAINER_MODE)
+generate: ${.CURDIR}/dns/enumtype.h ${.CURDIR}/dns/enumclass.h \
+ ${.CURDIR}/dns/rdatastruct.h ${.CURDIR}/code.h
+
+gen: ${SRCDIR}/gen.c
+
+${.CURDIR}/dns/enumtype.h: gen
+ (cd ${SRCDIR} && ${.OBJDIR}/gen -t) >${.TARGET}
+
+${.CURDIR}/dns/enumclass.h: gen
+ (cd ${SRCDIR} && ${.OBJDIR}/gen -c) >${.TARGET}
+
+${.CURDIR}/dns/rdatastruct.h: gen
+ (cd ${SRCDIR} && ${.OBJDIR}/gen -i -P rdata/rdatastructpre.h \
+ -S rdata/rdatastructsuf.h) >${.TARGET}
+
+${.CURDIR}/code.h: gen
+ (cd ${SRCDIR} && ${.OBJDIR}/gen) >${.TARGET}
+.endif
+
+.include <bsd.lib.mk>
diff --git a/lib/bind/dns/code.h b/lib/bind/dns/code.h
new file mode 100644
index 0000000..7cf495e
--- /dev/null
+++ b/lib/bind/dns/code.h
@@ -0,0 +1,1598 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2004-2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-2003 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.
+ */
+
+/***************
+ ***************
+ *************** THIS FILE IS AUTOMATICALLY GENERATED BY gen.c.
+ *************** DO NOT EDIT!
+ ***************
+ ***************/
+
+#ifndef DNS_CODE_H
+#define DNS_CODE_H 1
+
+#include <isc/boolean.h>
+#include <isc/result.h>
+
+#include <dns/name.h>
+
+#include "rdata/in_1/a_1.c"
+#include "rdata/hs_4/a_1.c"
+#include "rdata/generic/ns_2.c"
+#include "rdata/generic/md_3.c"
+#include "rdata/generic/mf_4.c"
+#include "rdata/generic/cname_5.c"
+#include "rdata/generic/soa_6.c"
+#include "rdata/generic/mb_7.c"
+#include "rdata/generic/mg_8.c"
+#include "rdata/generic/mr_9.c"
+#include "rdata/generic/null_10.c"
+#include "rdata/in_1/wks_11.c"
+#include "rdata/generic/ptr_12.c"
+#include "rdata/generic/hinfo_13.c"
+#include "rdata/generic/minfo_14.c"
+#include "rdata/generic/mx_15.c"
+#include "rdata/generic/txt_16.c"
+#include "rdata/generic/rp_17.c"
+#include "rdata/generic/afsdb_18.c"
+#include "rdata/generic/x25_19.c"
+#include "rdata/generic/isdn_20.c"
+#include "rdata/generic/rt_21.c"
+#include "rdata/in_1/nsap_22.c"
+#include "rdata/in_1/nsap-ptr_23.c"
+#include "rdata/generic/sig_24.c"
+#include "rdata/generic/key_25.c"
+#include "rdata/in_1/px_26.c"
+#include "rdata/generic/gpos_27.c"
+#include "rdata/in_1/aaaa_28.c"
+#include "rdata/generic/loc_29.c"
+#include "rdata/generic/nxt_30.c"
+#include "rdata/in_1/srv_33.c"
+#include "rdata/in_1/naptr_35.c"
+#include "rdata/in_1/kx_36.c"
+#include "rdata/generic/cert_37.c"
+#include "rdata/in_1/a6_38.c"
+#include "rdata/generic/dname_39.c"
+#include "rdata/generic/opt_41.c"
+#include "rdata/in_1/apl_42.c"
+#include "rdata/generic/ds_43.c"
+#include "rdata/generic/sshfp_44.c"
+#include "rdata/generic/rrsig_46.c"
+#include "rdata/generic/nsec_47.c"
+#include "rdata/generic/dnskey_48.c"
+#include "rdata/generic/unspec_103.c"
+#include "rdata/generic/tkey_249.c"
+#include "rdata/any_255/tsig_250.c"
+#include "rdata/generic/dlv_65323.c"
+
+
+
+#define FROMTEXTSWITCH \
+ switch (type) { \
+ case 1: switch (rdclass) { \
+ case 1: result = fromtext_in_a(rdclass, type, lexer, origin, options, target, callbacks); break; \
+ case 4: result = fromtext_hs_a(rdclass, type, lexer, origin, options, target, callbacks); break; \
+ default: result = DNS_R_UNKNOWN; break; \
+ } \
+ break; \
+ case 2: result = fromtext_ns(rdclass, type, lexer, origin, options, target, callbacks); break; \
+ case 3: result = fromtext_md(rdclass, type, lexer, origin, options, target, callbacks); break; \
+ case 4: result = fromtext_mf(rdclass, type, lexer, origin, options, target, callbacks); break; \
+ case 5: result = fromtext_cname(rdclass, type, lexer, origin, options, target, callbacks); break; \
+ case 6: result = fromtext_soa(rdclass, type, lexer, origin, options, target, callbacks); break; \
+ case 7: result = fromtext_mb(rdclass, type, lexer, origin, options, target, callbacks); break; \
+ case 8: result = fromtext_mg(rdclass, type, lexer, origin, options, target, callbacks); break; \
+ case 9: result = fromtext_mr(rdclass, type, lexer, origin, options, target, callbacks); break; \
+ case 10: result = fromtext_null(rdclass, type, lexer, origin, options, target, callbacks); break; \
+ case 11: switch (rdclass) { \
+ case 1: result = fromtext_in_wks(rdclass, type, lexer, origin, options, target, callbacks); break; \
+ default: result = DNS_R_UNKNOWN; break; \
+ } \
+ break; \
+ case 12: result = fromtext_ptr(rdclass, type, lexer, origin, options, target, callbacks); break; \
+ case 13: result = fromtext_hinfo(rdclass, type, lexer, origin, options, target, callbacks); break; \
+ case 14: result = fromtext_minfo(rdclass, type, lexer, origin, options, target, callbacks); break; \
+ case 15: result = fromtext_mx(rdclass, type, lexer, origin, options, target, callbacks); break; \
+ case 16: result = fromtext_txt(rdclass, type, lexer, origin, options, target, callbacks); break; \
+ case 17: result = fromtext_rp(rdclass, type, lexer, origin, options, target, callbacks); break; \
+ case 18: result = fromtext_afsdb(rdclass, type, lexer, origin, options, target, callbacks); break; \
+ case 19: result = fromtext_x25(rdclass, type, lexer, origin, options, target, callbacks); break; \
+ case 20: result = fromtext_isdn(rdclass, type, lexer, origin, options, target, callbacks); break; \
+ case 21: result = fromtext_rt(rdclass, type, lexer, origin, options, target, callbacks); break; \
+ case 22: switch (rdclass) { \
+ case 1: result = fromtext_in_nsap(rdclass, type, lexer, origin, options, target, callbacks); break; \
+ default: result = DNS_R_UNKNOWN; break; \
+ } \
+ break; \
+ case 23: switch (rdclass) { \
+ case 1: result = fromtext_in_nsap_ptr(rdclass, type, lexer, origin, options, target, callbacks); break; \
+ default: result = DNS_R_UNKNOWN; break; \
+ } \
+ break; \
+ case 24: result = fromtext_sig(rdclass, type, lexer, origin, options, target, callbacks); break; \
+ case 25: result = fromtext_key(rdclass, type, lexer, origin, options, target, callbacks); break; \
+ case 26: switch (rdclass) { \
+ case 1: result = fromtext_in_px(rdclass, type, lexer, origin, options, target, callbacks); break; \
+ default: result = DNS_R_UNKNOWN; break; \
+ } \
+ break; \
+ case 27: result = fromtext_gpos(rdclass, type, lexer, origin, options, target, callbacks); break; \
+ case 28: switch (rdclass) { \
+ case 1: result = fromtext_in_aaaa(rdclass, type, lexer, origin, options, target, callbacks); break; \
+ default: result = DNS_R_UNKNOWN; break; \
+ } \
+ break; \
+ case 29: result = fromtext_loc(rdclass, type, lexer, origin, options, target, callbacks); break; \
+ case 30: result = fromtext_nxt(rdclass, type, lexer, origin, options, target, callbacks); break; \
+ case 33: switch (rdclass) { \
+ case 1: result = fromtext_in_srv(rdclass, type, lexer, origin, options, target, callbacks); break; \
+ default: result = DNS_R_UNKNOWN; break; \
+ } \
+ break; \
+ case 35: switch (rdclass) { \
+ case 1: result = fromtext_in_naptr(rdclass, type, lexer, origin, options, target, callbacks); break; \
+ default: result = DNS_R_UNKNOWN; break; \
+ } \
+ break; \
+ case 36: switch (rdclass) { \
+ case 1: result = fromtext_in_kx(rdclass, type, lexer, origin, options, target, callbacks); break; \
+ default: result = DNS_R_UNKNOWN; break; \
+ } \
+ break; \
+ case 37: result = fromtext_cert(rdclass, type, lexer, origin, options, target, callbacks); break; \
+ case 38: switch (rdclass) { \
+ case 1: result = fromtext_in_a6(rdclass, type, lexer, origin, options, target, callbacks); break; \
+ default: result = DNS_R_UNKNOWN; break; \
+ } \
+ break; \
+ case 39: result = fromtext_dname(rdclass, type, lexer, origin, options, target, callbacks); break; \
+ case 41: result = fromtext_opt(rdclass, type, lexer, origin, options, target, callbacks); break; \
+ case 42: switch (rdclass) { \
+ case 1: result = fromtext_in_apl(rdclass, type, lexer, origin, options, target, callbacks); break; \
+ default: result = DNS_R_UNKNOWN; break; \
+ } \
+ break; \
+ case 43: result = fromtext_ds(rdclass, type, lexer, origin, options, target, callbacks); break; \
+ case 44: result = fromtext_sshfp(rdclass, type, lexer, origin, options, target, callbacks); break; \
+ case 46: result = fromtext_rrsig(rdclass, type, lexer, origin, options, target, callbacks); break; \
+ case 47: result = fromtext_nsec(rdclass, type, lexer, origin, options, target, callbacks); break; \
+ case 48: result = fromtext_dnskey(rdclass, type, lexer, origin, options, target, callbacks); break; \
+ case 103: result = fromtext_unspec(rdclass, type, lexer, origin, options, target, callbacks); break; \
+ case 249: result = fromtext_tkey(rdclass, type, lexer, origin, options, target, callbacks); break; \
+ case 250: switch (rdclass) { \
+ case 255: result = fromtext_any_tsig(rdclass, type, lexer, origin, options, target, callbacks); break; \
+ default: result = DNS_R_UNKNOWN; break; \
+ } \
+ break; \
+ case 65323: result = fromtext_dlv(rdclass, type, lexer, origin, options, target, callbacks); break; \
+ default: result = DNS_R_UNKNOWN; break; \
+ }
+
+#define TOTEXTSWITCH \
+ switch (rdata->type) { \
+ case 1: switch (rdata->rdclass) { \
+ case 1: result = totext_in_a(rdata, tctx, target); break; \
+ case 4: result = totext_hs_a(rdata, tctx, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 2: result = totext_ns(rdata, tctx, target); break; \
+ case 3: result = totext_md(rdata, tctx, target); break; \
+ case 4: result = totext_mf(rdata, tctx, target); break; \
+ case 5: result = totext_cname(rdata, tctx, target); break; \
+ case 6: result = totext_soa(rdata, tctx, target); break; \
+ case 7: result = totext_mb(rdata, tctx, target); break; \
+ case 8: result = totext_mg(rdata, tctx, target); break; \
+ case 9: result = totext_mr(rdata, tctx, target); break; \
+ case 10: result = totext_null(rdata, tctx, target); break; \
+ case 11: switch (rdata->rdclass) { \
+ case 1: result = totext_in_wks(rdata, tctx, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 12: result = totext_ptr(rdata, tctx, target); break; \
+ case 13: result = totext_hinfo(rdata, tctx, target); break; \
+ case 14: result = totext_minfo(rdata, tctx, target); break; \
+ case 15: result = totext_mx(rdata, tctx, target); break; \
+ case 16: result = totext_txt(rdata, tctx, target); break; \
+ case 17: result = totext_rp(rdata, tctx, target); break; \
+ case 18: result = totext_afsdb(rdata, tctx, target); break; \
+ case 19: result = totext_x25(rdata, tctx, target); break; \
+ case 20: result = totext_isdn(rdata, tctx, target); break; \
+ case 21: result = totext_rt(rdata, tctx, target); break; \
+ case 22: switch (rdata->rdclass) { \
+ case 1: result = totext_in_nsap(rdata, tctx, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 23: switch (rdata->rdclass) { \
+ case 1: result = totext_in_nsap_ptr(rdata, tctx, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 24: result = totext_sig(rdata, tctx, target); break; \
+ case 25: result = totext_key(rdata, tctx, target); break; \
+ case 26: switch (rdata->rdclass) { \
+ case 1: result = totext_in_px(rdata, tctx, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 27: result = totext_gpos(rdata, tctx, target); break; \
+ case 28: switch (rdata->rdclass) { \
+ case 1: result = totext_in_aaaa(rdata, tctx, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 29: result = totext_loc(rdata, tctx, target); break; \
+ case 30: result = totext_nxt(rdata, tctx, target); break; \
+ case 33: switch (rdata->rdclass) { \
+ case 1: result = totext_in_srv(rdata, tctx, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 35: switch (rdata->rdclass) { \
+ case 1: result = totext_in_naptr(rdata, tctx, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 36: switch (rdata->rdclass) { \
+ case 1: result = totext_in_kx(rdata, tctx, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 37: result = totext_cert(rdata, tctx, target); break; \
+ case 38: switch (rdata->rdclass) { \
+ case 1: result = totext_in_a6(rdata, tctx, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 39: result = totext_dname(rdata, tctx, target); break; \
+ case 41: result = totext_opt(rdata, tctx, target); break; \
+ case 42: switch (rdata->rdclass) { \
+ case 1: result = totext_in_apl(rdata, tctx, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 43: result = totext_ds(rdata, tctx, target); break; \
+ case 44: result = totext_sshfp(rdata, tctx, target); break; \
+ case 46: result = totext_rrsig(rdata, tctx, target); break; \
+ case 47: result = totext_nsec(rdata, tctx, target); break; \
+ case 48: result = totext_dnskey(rdata, tctx, target); break; \
+ case 103: result = totext_unspec(rdata, tctx, target); break; \
+ case 249: result = totext_tkey(rdata, tctx, target); break; \
+ case 250: switch (rdata->rdclass) { \
+ case 255: result = totext_any_tsig(rdata, tctx, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 65323: result = totext_dlv(rdata, tctx, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ }
+
+#define FROMWIRESWITCH \
+ switch (type) { \
+ case 1: switch (rdclass) { \
+ case 1: result = fromwire_in_a(rdclass, type, source, dctx, options, target); break; \
+ case 4: result = fromwire_hs_a(rdclass, type, source, dctx, options, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 2: result = fromwire_ns(rdclass, type, source, dctx, options, target); break; \
+ case 3: result = fromwire_md(rdclass, type, source, dctx, options, target); break; \
+ case 4: result = fromwire_mf(rdclass, type, source, dctx, options, target); break; \
+ case 5: result = fromwire_cname(rdclass, type, source, dctx, options, target); break; \
+ case 6: result = fromwire_soa(rdclass, type, source, dctx, options, target); break; \
+ case 7: result = fromwire_mb(rdclass, type, source, dctx, options, target); break; \
+ case 8: result = fromwire_mg(rdclass, type, source, dctx, options, target); break; \
+ case 9: result = fromwire_mr(rdclass, type, source, dctx, options, target); break; \
+ case 10: result = fromwire_null(rdclass, type, source, dctx, options, target); break; \
+ case 11: switch (rdclass) { \
+ case 1: result = fromwire_in_wks(rdclass, type, source, dctx, options, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 12: result = fromwire_ptr(rdclass, type, source, dctx, options, target); break; \
+ case 13: result = fromwire_hinfo(rdclass, type, source, dctx, options, target); break; \
+ case 14: result = fromwire_minfo(rdclass, type, source, dctx, options, target); break; \
+ case 15: result = fromwire_mx(rdclass, type, source, dctx, options, target); break; \
+ case 16: result = fromwire_txt(rdclass, type, source, dctx, options, target); break; \
+ case 17: result = fromwire_rp(rdclass, type, source, dctx, options, target); break; \
+ case 18: result = fromwire_afsdb(rdclass, type, source, dctx, options, target); break; \
+ case 19: result = fromwire_x25(rdclass, type, source, dctx, options, target); break; \
+ case 20: result = fromwire_isdn(rdclass, type, source, dctx, options, target); break; \
+ case 21: result = fromwire_rt(rdclass, type, source, dctx, options, target); break; \
+ case 22: switch (rdclass) { \
+ case 1: result = fromwire_in_nsap(rdclass, type, source, dctx, options, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 23: switch (rdclass) { \
+ case 1: result = fromwire_in_nsap_ptr(rdclass, type, source, dctx, options, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 24: result = fromwire_sig(rdclass, type, source, dctx, options, target); break; \
+ case 25: result = fromwire_key(rdclass, type, source, dctx, options, target); break; \
+ case 26: switch (rdclass) { \
+ case 1: result = fromwire_in_px(rdclass, type, source, dctx, options, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 27: result = fromwire_gpos(rdclass, type, source, dctx, options, target); break; \
+ case 28: switch (rdclass) { \
+ case 1: result = fromwire_in_aaaa(rdclass, type, source, dctx, options, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 29: result = fromwire_loc(rdclass, type, source, dctx, options, target); break; \
+ case 30: result = fromwire_nxt(rdclass, type, source, dctx, options, target); break; \
+ case 33: switch (rdclass) { \
+ case 1: result = fromwire_in_srv(rdclass, type, source, dctx, options, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 35: switch (rdclass) { \
+ case 1: result = fromwire_in_naptr(rdclass, type, source, dctx, options, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 36: switch (rdclass) { \
+ case 1: result = fromwire_in_kx(rdclass, type, source, dctx, options, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 37: result = fromwire_cert(rdclass, type, source, dctx, options, target); break; \
+ case 38: switch (rdclass) { \
+ case 1: result = fromwire_in_a6(rdclass, type, source, dctx, options, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 39: result = fromwire_dname(rdclass, type, source, dctx, options, target); break; \
+ case 41: result = fromwire_opt(rdclass, type, source, dctx, options, target); break; \
+ case 42: switch (rdclass) { \
+ case 1: result = fromwire_in_apl(rdclass, type, source, dctx, options, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 43: result = fromwire_ds(rdclass, type, source, dctx, options, target); break; \
+ case 44: result = fromwire_sshfp(rdclass, type, source, dctx, options, target); break; \
+ case 46: result = fromwire_rrsig(rdclass, type, source, dctx, options, target); break; \
+ case 47: result = fromwire_nsec(rdclass, type, source, dctx, options, target); break; \
+ case 48: result = fromwire_dnskey(rdclass, type, source, dctx, options, target); break; \
+ case 103: result = fromwire_unspec(rdclass, type, source, dctx, options, target); break; \
+ case 249: result = fromwire_tkey(rdclass, type, source, dctx, options, target); break; \
+ case 250: switch (rdclass) { \
+ case 255: result = fromwire_any_tsig(rdclass, type, source, dctx, options, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 65323: result = fromwire_dlv(rdclass, type, source, dctx, options, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ }
+
+#define TOWIRESWITCH \
+ switch (rdata->type) { \
+ case 1: switch (rdata->rdclass) { \
+ case 1: result = towire_in_a(rdata, cctx, target); break; \
+ case 4: result = towire_hs_a(rdata, cctx, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 2: result = towire_ns(rdata, cctx, target); break; \
+ case 3: result = towire_md(rdata, cctx, target); break; \
+ case 4: result = towire_mf(rdata, cctx, target); break; \
+ case 5: result = towire_cname(rdata, cctx, target); break; \
+ case 6: result = towire_soa(rdata, cctx, target); break; \
+ case 7: result = towire_mb(rdata, cctx, target); break; \
+ case 8: result = towire_mg(rdata, cctx, target); break; \
+ case 9: result = towire_mr(rdata, cctx, target); break; \
+ case 10: result = towire_null(rdata, cctx, target); break; \
+ case 11: switch (rdata->rdclass) { \
+ case 1: result = towire_in_wks(rdata, cctx, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 12: result = towire_ptr(rdata, cctx, target); break; \
+ case 13: result = towire_hinfo(rdata, cctx, target); break; \
+ case 14: result = towire_minfo(rdata, cctx, target); break; \
+ case 15: result = towire_mx(rdata, cctx, target); break; \
+ case 16: result = towire_txt(rdata, cctx, target); break; \
+ case 17: result = towire_rp(rdata, cctx, target); break; \
+ case 18: result = towire_afsdb(rdata, cctx, target); break; \
+ case 19: result = towire_x25(rdata, cctx, target); break; \
+ case 20: result = towire_isdn(rdata, cctx, target); break; \
+ case 21: result = towire_rt(rdata, cctx, target); break; \
+ case 22: switch (rdata->rdclass) { \
+ case 1: result = towire_in_nsap(rdata, cctx, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 23: switch (rdata->rdclass) { \
+ case 1: result = towire_in_nsap_ptr(rdata, cctx, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 24: result = towire_sig(rdata, cctx, target); break; \
+ case 25: result = towire_key(rdata, cctx, target); break; \
+ case 26: switch (rdata->rdclass) { \
+ case 1: result = towire_in_px(rdata, cctx, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 27: result = towire_gpos(rdata, cctx, target); break; \
+ case 28: switch (rdata->rdclass) { \
+ case 1: result = towire_in_aaaa(rdata, cctx, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 29: result = towire_loc(rdata, cctx, target); break; \
+ case 30: result = towire_nxt(rdata, cctx, target); break; \
+ case 33: switch (rdata->rdclass) { \
+ case 1: result = towire_in_srv(rdata, cctx, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 35: switch (rdata->rdclass) { \
+ case 1: result = towire_in_naptr(rdata, cctx, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 36: switch (rdata->rdclass) { \
+ case 1: result = towire_in_kx(rdata, cctx, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 37: result = towire_cert(rdata, cctx, target); break; \
+ case 38: switch (rdata->rdclass) { \
+ case 1: result = towire_in_a6(rdata, cctx, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 39: result = towire_dname(rdata, cctx, target); break; \
+ case 41: result = towire_opt(rdata, cctx, target); break; \
+ case 42: switch (rdata->rdclass) { \
+ case 1: result = towire_in_apl(rdata, cctx, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 43: result = towire_ds(rdata, cctx, target); break; \
+ case 44: result = towire_sshfp(rdata, cctx, target); break; \
+ case 46: result = towire_rrsig(rdata, cctx, target); break; \
+ case 47: result = towire_nsec(rdata, cctx, target); break; \
+ case 48: result = towire_dnskey(rdata, cctx, target); break; \
+ case 103: result = towire_unspec(rdata, cctx, target); break; \
+ case 249: result = towire_tkey(rdata, cctx, target); break; \
+ case 250: switch (rdata->rdclass) { \
+ case 255: result = towire_any_tsig(rdata, cctx, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 65323: result = towire_dlv(rdata, cctx, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ }
+
+#define COMPARESWITCH \
+ switch (rdata1->type) { \
+ case 1: switch (rdata1->rdclass) { \
+ case 1: result = compare_in_a(rdata1, rdata2); break; \
+ case 4: result = compare_hs_a(rdata1, rdata2); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 2: result = compare_ns(rdata1, rdata2); break; \
+ case 3: result = compare_md(rdata1, rdata2); break; \
+ case 4: result = compare_mf(rdata1, rdata2); break; \
+ case 5: result = compare_cname(rdata1, rdata2); break; \
+ case 6: result = compare_soa(rdata1, rdata2); break; \
+ case 7: result = compare_mb(rdata1, rdata2); break; \
+ case 8: result = compare_mg(rdata1, rdata2); break; \
+ case 9: result = compare_mr(rdata1, rdata2); break; \
+ case 10: result = compare_null(rdata1, rdata2); break; \
+ case 11: switch (rdata1->rdclass) { \
+ case 1: result = compare_in_wks(rdata1, rdata2); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 12: result = compare_ptr(rdata1, rdata2); break; \
+ case 13: result = compare_hinfo(rdata1, rdata2); break; \
+ case 14: result = compare_minfo(rdata1, rdata2); break; \
+ case 15: result = compare_mx(rdata1, rdata2); break; \
+ case 16: result = compare_txt(rdata1, rdata2); break; \
+ case 17: result = compare_rp(rdata1, rdata2); break; \
+ case 18: result = compare_afsdb(rdata1, rdata2); break; \
+ case 19: result = compare_x25(rdata1, rdata2); break; \
+ case 20: result = compare_isdn(rdata1, rdata2); break; \
+ case 21: result = compare_rt(rdata1, rdata2); break; \
+ case 22: switch (rdata1->rdclass) { \
+ case 1: result = compare_in_nsap(rdata1, rdata2); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 23: switch (rdata1->rdclass) { \
+ case 1: result = compare_in_nsap_ptr(rdata1, rdata2); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 24: result = compare_sig(rdata1, rdata2); break; \
+ case 25: result = compare_key(rdata1, rdata2); break; \
+ case 26: switch (rdata1->rdclass) { \
+ case 1: result = compare_in_px(rdata1, rdata2); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 27: result = compare_gpos(rdata1, rdata2); break; \
+ case 28: switch (rdata1->rdclass) { \
+ case 1: result = compare_in_aaaa(rdata1, rdata2); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 29: result = compare_loc(rdata1, rdata2); break; \
+ case 30: result = compare_nxt(rdata1, rdata2); break; \
+ case 33: switch (rdata1->rdclass) { \
+ case 1: result = compare_in_srv(rdata1, rdata2); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 35: switch (rdata1->rdclass) { \
+ case 1: result = compare_in_naptr(rdata1, rdata2); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 36: switch (rdata1->rdclass) { \
+ case 1: result = compare_in_kx(rdata1, rdata2); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 37: result = compare_cert(rdata1, rdata2); break; \
+ case 38: switch (rdata1->rdclass) { \
+ case 1: result = compare_in_a6(rdata1, rdata2); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 39: result = compare_dname(rdata1, rdata2); break; \
+ case 41: result = compare_opt(rdata1, rdata2); break; \
+ case 42: switch (rdata1->rdclass) { \
+ case 1: result = compare_in_apl(rdata1, rdata2); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 43: result = compare_ds(rdata1, rdata2); break; \
+ case 44: result = compare_sshfp(rdata1, rdata2); break; \
+ case 46: result = compare_rrsig(rdata1, rdata2); break; \
+ case 47: result = compare_nsec(rdata1, rdata2); break; \
+ case 48: result = compare_dnskey(rdata1, rdata2); break; \
+ case 103: result = compare_unspec(rdata1, rdata2); break; \
+ case 249: result = compare_tkey(rdata1, rdata2); break; \
+ case 250: switch (rdata1->rdclass) { \
+ case 255: result = compare_any_tsig(rdata1, rdata2); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 65323: result = compare_dlv(rdata1, rdata2); break; \
+ default: use_default = ISC_TRUE; break; \
+ }
+
+#define FROMSTRUCTSWITCH \
+ switch (type) { \
+ case 1: switch (rdclass) { \
+ case 1: result = fromstruct_in_a(rdclass, type, source, target); break; \
+ case 4: result = fromstruct_hs_a(rdclass, type, source, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 2: result = fromstruct_ns(rdclass, type, source, target); break; \
+ case 3: result = fromstruct_md(rdclass, type, source, target); break; \
+ case 4: result = fromstruct_mf(rdclass, type, source, target); break; \
+ case 5: result = fromstruct_cname(rdclass, type, source, target); break; \
+ case 6: result = fromstruct_soa(rdclass, type, source, target); break; \
+ case 7: result = fromstruct_mb(rdclass, type, source, target); break; \
+ case 8: result = fromstruct_mg(rdclass, type, source, target); break; \
+ case 9: result = fromstruct_mr(rdclass, type, source, target); break; \
+ case 10: result = fromstruct_null(rdclass, type, source, target); break; \
+ case 11: switch (rdclass) { \
+ case 1: result = fromstruct_in_wks(rdclass, type, source, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 12: result = fromstruct_ptr(rdclass, type, source, target); break; \
+ case 13: result = fromstruct_hinfo(rdclass, type, source, target); break; \
+ case 14: result = fromstruct_minfo(rdclass, type, source, target); break; \
+ case 15: result = fromstruct_mx(rdclass, type, source, target); break; \
+ case 16: result = fromstruct_txt(rdclass, type, source, target); break; \
+ case 17: result = fromstruct_rp(rdclass, type, source, target); break; \
+ case 18: result = fromstruct_afsdb(rdclass, type, source, target); break; \
+ case 19: result = fromstruct_x25(rdclass, type, source, target); break; \
+ case 20: result = fromstruct_isdn(rdclass, type, source, target); break; \
+ case 21: result = fromstruct_rt(rdclass, type, source, target); break; \
+ case 22: switch (rdclass) { \
+ case 1: result = fromstruct_in_nsap(rdclass, type, source, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 23: switch (rdclass) { \
+ case 1: result = fromstruct_in_nsap_ptr(rdclass, type, source, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 24: result = fromstruct_sig(rdclass, type, source, target); break; \
+ case 25: result = fromstruct_key(rdclass, type, source, target); break; \
+ case 26: switch (rdclass) { \
+ case 1: result = fromstruct_in_px(rdclass, type, source, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 27: result = fromstruct_gpos(rdclass, type, source, target); break; \
+ case 28: switch (rdclass) { \
+ case 1: result = fromstruct_in_aaaa(rdclass, type, source, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 29: result = fromstruct_loc(rdclass, type, source, target); break; \
+ case 30: result = fromstruct_nxt(rdclass, type, source, target); break; \
+ case 33: switch (rdclass) { \
+ case 1: result = fromstruct_in_srv(rdclass, type, source, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 35: switch (rdclass) { \
+ case 1: result = fromstruct_in_naptr(rdclass, type, source, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 36: switch (rdclass) { \
+ case 1: result = fromstruct_in_kx(rdclass, type, source, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 37: result = fromstruct_cert(rdclass, type, source, target); break; \
+ case 38: switch (rdclass) { \
+ case 1: result = fromstruct_in_a6(rdclass, type, source, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 39: result = fromstruct_dname(rdclass, type, source, target); break; \
+ case 41: result = fromstruct_opt(rdclass, type, source, target); break; \
+ case 42: switch (rdclass) { \
+ case 1: result = fromstruct_in_apl(rdclass, type, source, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 43: result = fromstruct_ds(rdclass, type, source, target); break; \
+ case 44: result = fromstruct_sshfp(rdclass, type, source, target); break; \
+ case 46: result = fromstruct_rrsig(rdclass, type, source, target); break; \
+ case 47: result = fromstruct_nsec(rdclass, type, source, target); break; \
+ case 48: result = fromstruct_dnskey(rdclass, type, source, target); break; \
+ case 103: result = fromstruct_unspec(rdclass, type, source, target); break; \
+ case 249: result = fromstruct_tkey(rdclass, type, source, target); break; \
+ case 250: switch (rdclass) { \
+ case 255: result = fromstruct_any_tsig(rdclass, type, source, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 65323: result = fromstruct_dlv(rdclass, type, source, target); break; \
+ default: use_default = ISC_TRUE; break; \
+ }
+
+#define TOSTRUCTSWITCH \
+ switch (rdata->type) { \
+ case 1: switch (rdata->rdclass) { \
+ case 1: result = tostruct_in_a(rdata, target, mctx); break; \
+ case 4: result = tostruct_hs_a(rdata, target, mctx); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 2: result = tostruct_ns(rdata, target, mctx); break; \
+ case 3: result = tostruct_md(rdata, target, mctx); break; \
+ case 4: result = tostruct_mf(rdata, target, mctx); break; \
+ case 5: result = tostruct_cname(rdata, target, mctx); break; \
+ case 6: result = tostruct_soa(rdata, target, mctx); break; \
+ case 7: result = tostruct_mb(rdata, target, mctx); break; \
+ case 8: result = tostruct_mg(rdata, target, mctx); break; \
+ case 9: result = tostruct_mr(rdata, target, mctx); break; \
+ case 10: result = tostruct_null(rdata, target, mctx); break; \
+ case 11: switch (rdata->rdclass) { \
+ case 1: result = tostruct_in_wks(rdata, target, mctx); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 12: result = tostruct_ptr(rdata, target, mctx); break; \
+ case 13: result = tostruct_hinfo(rdata, target, mctx); break; \
+ case 14: result = tostruct_minfo(rdata, target, mctx); break; \
+ case 15: result = tostruct_mx(rdata, target, mctx); break; \
+ case 16: result = tostruct_txt(rdata, target, mctx); break; \
+ case 17: result = tostruct_rp(rdata, target, mctx); break; \
+ case 18: result = tostruct_afsdb(rdata, target, mctx); break; \
+ case 19: result = tostruct_x25(rdata, target, mctx); break; \
+ case 20: result = tostruct_isdn(rdata, target, mctx); break; \
+ case 21: result = tostruct_rt(rdata, target, mctx); break; \
+ case 22: switch (rdata->rdclass) { \
+ case 1: result = tostruct_in_nsap(rdata, target, mctx); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 23: switch (rdata->rdclass) { \
+ case 1: result = tostruct_in_nsap_ptr(rdata, target, mctx); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 24: result = tostruct_sig(rdata, target, mctx); break; \
+ case 25: result = tostruct_key(rdata, target, mctx); break; \
+ case 26: switch (rdata->rdclass) { \
+ case 1: result = tostruct_in_px(rdata, target, mctx); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 27: result = tostruct_gpos(rdata, target, mctx); break; \
+ case 28: switch (rdata->rdclass) { \
+ case 1: result = tostruct_in_aaaa(rdata, target, mctx); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 29: result = tostruct_loc(rdata, target, mctx); break; \
+ case 30: result = tostruct_nxt(rdata, target, mctx); break; \
+ case 33: switch (rdata->rdclass) { \
+ case 1: result = tostruct_in_srv(rdata, target, mctx); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 35: switch (rdata->rdclass) { \
+ case 1: result = tostruct_in_naptr(rdata, target, mctx); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 36: switch (rdata->rdclass) { \
+ case 1: result = tostruct_in_kx(rdata, target, mctx); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 37: result = tostruct_cert(rdata, target, mctx); break; \
+ case 38: switch (rdata->rdclass) { \
+ case 1: result = tostruct_in_a6(rdata, target, mctx); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 39: result = tostruct_dname(rdata, target, mctx); break; \
+ case 41: result = tostruct_opt(rdata, target, mctx); break; \
+ case 42: switch (rdata->rdclass) { \
+ case 1: result = tostruct_in_apl(rdata, target, mctx); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 43: result = tostruct_ds(rdata, target, mctx); break; \
+ case 44: result = tostruct_sshfp(rdata, target, mctx); break; \
+ case 46: result = tostruct_rrsig(rdata, target, mctx); break; \
+ case 47: result = tostruct_nsec(rdata, target, mctx); break; \
+ case 48: result = tostruct_dnskey(rdata, target, mctx); break; \
+ case 103: result = tostruct_unspec(rdata, target, mctx); break; \
+ case 249: result = tostruct_tkey(rdata, target, mctx); break; \
+ case 250: switch (rdata->rdclass) { \
+ case 255: result = tostruct_any_tsig(rdata, target, mctx); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 65323: result = tostruct_dlv(rdata, target, mctx); break; \
+ default: use_default = ISC_TRUE; break; \
+ }
+
+#define FREESTRUCTSWITCH \
+ switch (common->rdtype) { \
+ case 1: switch (common->rdclass) { \
+ case 1: freestruct_in_a(source); break; \
+ case 4: freestruct_hs_a(source); break; \
+ default: break; \
+ } \
+ break; \
+ case 2: freestruct_ns(source); break; \
+ case 3: freestruct_md(source); break; \
+ case 4: freestruct_mf(source); break; \
+ case 5: freestruct_cname(source); break; \
+ case 6: freestruct_soa(source); break; \
+ case 7: freestruct_mb(source); break; \
+ case 8: freestruct_mg(source); break; \
+ case 9: freestruct_mr(source); break; \
+ case 10: freestruct_null(source); break; \
+ case 11: switch (common->rdclass) { \
+ case 1: freestruct_in_wks(source); break; \
+ default: break; \
+ } \
+ break; \
+ case 12: freestruct_ptr(source); break; \
+ case 13: freestruct_hinfo(source); break; \
+ case 14: freestruct_minfo(source); break; \
+ case 15: freestruct_mx(source); break; \
+ case 16: freestruct_txt(source); break; \
+ case 17: freestruct_rp(source); break; \
+ case 18: freestruct_afsdb(source); break; \
+ case 19: freestruct_x25(source); break; \
+ case 20: freestruct_isdn(source); break; \
+ case 21: freestruct_rt(source); break; \
+ case 22: switch (common->rdclass) { \
+ case 1: freestruct_in_nsap(source); break; \
+ default: break; \
+ } \
+ break; \
+ case 23: switch (common->rdclass) { \
+ case 1: freestruct_in_nsap_ptr(source); break; \
+ default: break; \
+ } \
+ break; \
+ case 24: freestruct_sig(source); break; \
+ case 25: freestruct_key(source); break; \
+ case 26: switch (common->rdclass) { \
+ case 1: freestruct_in_px(source); break; \
+ default: break; \
+ } \
+ break; \
+ case 27: freestruct_gpos(source); break; \
+ case 28: switch (common->rdclass) { \
+ case 1: freestruct_in_aaaa(source); break; \
+ default: break; \
+ } \
+ break; \
+ case 29: freestruct_loc(source); break; \
+ case 30: freestruct_nxt(source); break; \
+ case 33: switch (common->rdclass) { \
+ case 1: freestruct_in_srv(source); break; \
+ default: break; \
+ } \
+ break; \
+ case 35: switch (common->rdclass) { \
+ case 1: freestruct_in_naptr(source); break; \
+ default: break; \
+ } \
+ break; \
+ case 36: switch (common->rdclass) { \
+ case 1: freestruct_in_kx(source); break; \
+ default: break; \
+ } \
+ break; \
+ case 37: freestruct_cert(source); break; \
+ case 38: switch (common->rdclass) { \
+ case 1: freestruct_in_a6(source); break; \
+ default: break; \
+ } \
+ break; \
+ case 39: freestruct_dname(source); break; \
+ case 41: freestruct_opt(source); break; \
+ case 42: switch (common->rdclass) { \
+ case 1: freestruct_in_apl(source); break; \
+ default: break; \
+ } \
+ break; \
+ case 43: freestruct_ds(source); break; \
+ case 44: freestruct_sshfp(source); break; \
+ case 46: freestruct_rrsig(source); break; \
+ case 47: freestruct_nsec(source); break; \
+ case 48: freestruct_dnskey(source); break; \
+ case 103: freestruct_unspec(source); break; \
+ case 249: freestruct_tkey(source); break; \
+ case 250: switch (common->rdclass) { \
+ case 255: freestruct_any_tsig(source); break; \
+ default: break; \
+ } \
+ break; \
+ case 65323: freestruct_dlv(source); break; \
+ default: break; \
+ }
+
+#define ADDITIONALDATASWITCH \
+ switch (rdata->type) { \
+ case 1: switch (rdata->rdclass) { \
+ case 1: result = additionaldata_in_a(rdata, add, arg); break; \
+ case 4: result = additionaldata_hs_a(rdata, add, arg); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 2: result = additionaldata_ns(rdata, add, arg); break; \
+ case 3: result = additionaldata_md(rdata, add, arg); break; \
+ case 4: result = additionaldata_mf(rdata, add, arg); break; \
+ case 5: result = additionaldata_cname(rdata, add, arg); break; \
+ case 6: result = additionaldata_soa(rdata, add, arg); break; \
+ case 7: result = additionaldata_mb(rdata, add, arg); break; \
+ case 8: result = additionaldata_mg(rdata, add, arg); break; \
+ case 9: result = additionaldata_mr(rdata, add, arg); break; \
+ case 10: result = additionaldata_null(rdata, add, arg); break; \
+ case 11: switch (rdata->rdclass) { \
+ case 1: result = additionaldata_in_wks(rdata, add, arg); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 12: result = additionaldata_ptr(rdata, add, arg); break; \
+ case 13: result = additionaldata_hinfo(rdata, add, arg); break; \
+ case 14: result = additionaldata_minfo(rdata, add, arg); break; \
+ case 15: result = additionaldata_mx(rdata, add, arg); break; \
+ case 16: result = additionaldata_txt(rdata, add, arg); break; \
+ case 17: result = additionaldata_rp(rdata, add, arg); break; \
+ case 18: result = additionaldata_afsdb(rdata, add, arg); break; \
+ case 19: result = additionaldata_x25(rdata, add, arg); break; \
+ case 20: result = additionaldata_isdn(rdata, add, arg); break; \
+ case 21: result = additionaldata_rt(rdata, add, arg); break; \
+ case 22: switch (rdata->rdclass) { \
+ case 1: result = additionaldata_in_nsap(rdata, add, arg); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 23: switch (rdata->rdclass) { \
+ case 1: result = additionaldata_in_nsap_ptr(rdata, add, arg); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 24: result = additionaldata_sig(rdata, add, arg); break; \
+ case 25: result = additionaldata_key(rdata, add, arg); break; \
+ case 26: switch (rdata->rdclass) { \
+ case 1: result = additionaldata_in_px(rdata, add, arg); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 27: result = additionaldata_gpos(rdata, add, arg); break; \
+ case 28: switch (rdata->rdclass) { \
+ case 1: result = additionaldata_in_aaaa(rdata, add, arg); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 29: result = additionaldata_loc(rdata, add, arg); break; \
+ case 30: result = additionaldata_nxt(rdata, add, arg); break; \
+ case 33: switch (rdata->rdclass) { \
+ case 1: result = additionaldata_in_srv(rdata, add, arg); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 35: switch (rdata->rdclass) { \
+ case 1: result = additionaldata_in_naptr(rdata, add, arg); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 36: switch (rdata->rdclass) { \
+ case 1: result = additionaldata_in_kx(rdata, add, arg); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 37: result = additionaldata_cert(rdata, add, arg); break; \
+ case 38: switch (rdata->rdclass) { \
+ case 1: result = additionaldata_in_a6(rdata, add, arg); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 39: result = additionaldata_dname(rdata, add, arg); break; \
+ case 41: result = additionaldata_opt(rdata, add, arg); break; \
+ case 42: switch (rdata->rdclass) { \
+ case 1: result = additionaldata_in_apl(rdata, add, arg); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 43: result = additionaldata_ds(rdata, add, arg); break; \
+ case 44: result = additionaldata_sshfp(rdata, add, arg); break; \
+ case 46: result = additionaldata_rrsig(rdata, add, arg); break; \
+ case 47: result = additionaldata_nsec(rdata, add, arg); break; \
+ case 48: result = additionaldata_dnskey(rdata, add, arg); break; \
+ case 103: result = additionaldata_unspec(rdata, add, arg); break; \
+ case 249: result = additionaldata_tkey(rdata, add, arg); break; \
+ case 250: switch (rdata->rdclass) { \
+ case 255: result = additionaldata_any_tsig(rdata, add, arg); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 65323: result = additionaldata_dlv(rdata, add, arg); break; \
+ default: use_default = ISC_TRUE; break; \
+ }
+
+#define DIGESTSWITCH \
+ switch (rdata->type) { \
+ case 1: switch (rdata->rdclass) { \
+ case 1: result = digest_in_a(rdata, digest, arg); break; \
+ case 4: result = digest_hs_a(rdata, digest, arg); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 2: result = digest_ns(rdata, digest, arg); break; \
+ case 3: result = digest_md(rdata, digest, arg); break; \
+ case 4: result = digest_mf(rdata, digest, arg); break; \
+ case 5: result = digest_cname(rdata, digest, arg); break; \
+ case 6: result = digest_soa(rdata, digest, arg); break; \
+ case 7: result = digest_mb(rdata, digest, arg); break; \
+ case 8: result = digest_mg(rdata, digest, arg); break; \
+ case 9: result = digest_mr(rdata, digest, arg); break; \
+ case 10: result = digest_null(rdata, digest, arg); break; \
+ case 11: switch (rdata->rdclass) { \
+ case 1: result = digest_in_wks(rdata, digest, arg); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 12: result = digest_ptr(rdata, digest, arg); break; \
+ case 13: result = digest_hinfo(rdata, digest, arg); break; \
+ case 14: result = digest_minfo(rdata, digest, arg); break; \
+ case 15: result = digest_mx(rdata, digest, arg); break; \
+ case 16: result = digest_txt(rdata, digest, arg); break; \
+ case 17: result = digest_rp(rdata, digest, arg); break; \
+ case 18: result = digest_afsdb(rdata, digest, arg); break; \
+ case 19: result = digest_x25(rdata, digest, arg); break; \
+ case 20: result = digest_isdn(rdata, digest, arg); break; \
+ case 21: result = digest_rt(rdata, digest, arg); break; \
+ case 22: switch (rdata->rdclass) { \
+ case 1: result = digest_in_nsap(rdata, digest, arg); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 23: switch (rdata->rdclass) { \
+ case 1: result = digest_in_nsap_ptr(rdata, digest, arg); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 24: result = digest_sig(rdata, digest, arg); break; \
+ case 25: result = digest_key(rdata, digest, arg); break; \
+ case 26: switch (rdata->rdclass) { \
+ case 1: result = digest_in_px(rdata, digest, arg); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 27: result = digest_gpos(rdata, digest, arg); break; \
+ case 28: switch (rdata->rdclass) { \
+ case 1: result = digest_in_aaaa(rdata, digest, arg); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 29: result = digest_loc(rdata, digest, arg); break; \
+ case 30: result = digest_nxt(rdata, digest, arg); break; \
+ case 33: switch (rdata->rdclass) { \
+ case 1: result = digest_in_srv(rdata, digest, arg); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 35: switch (rdata->rdclass) { \
+ case 1: result = digest_in_naptr(rdata, digest, arg); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 36: switch (rdata->rdclass) { \
+ case 1: result = digest_in_kx(rdata, digest, arg); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 37: result = digest_cert(rdata, digest, arg); break; \
+ case 38: switch (rdata->rdclass) { \
+ case 1: result = digest_in_a6(rdata, digest, arg); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 39: result = digest_dname(rdata, digest, arg); break; \
+ case 41: result = digest_opt(rdata, digest, arg); break; \
+ case 42: switch (rdata->rdclass) { \
+ case 1: result = digest_in_apl(rdata, digest, arg); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 43: result = digest_ds(rdata, digest, arg); break; \
+ case 44: result = digest_sshfp(rdata, digest, arg); break; \
+ case 46: result = digest_rrsig(rdata, digest, arg); break; \
+ case 47: result = digest_nsec(rdata, digest, arg); break; \
+ case 48: result = digest_dnskey(rdata, digest, arg); break; \
+ case 103: result = digest_unspec(rdata, digest, arg); break; \
+ case 249: result = digest_tkey(rdata, digest, arg); break; \
+ case 250: switch (rdata->rdclass) { \
+ case 255: result = digest_any_tsig(rdata, digest, arg); break; \
+ default: use_default = ISC_TRUE; break; \
+ } \
+ break; \
+ case 65323: result = digest_dlv(rdata, digest, arg); break; \
+ default: use_default = ISC_TRUE; break; \
+ }
+
+#define CHECKOWNERSWITCH \
+ switch (type) { \
+ case 1: switch (rdclass) { \
+ case 1: result = checkowner_in_a(name, rdclass, type, wildcard); break; \
+ case 4: result = checkowner_hs_a(name, rdclass, type, wildcard); break; \
+ default: result = ISC_TRUE; break; \
+ } \
+ break; \
+ case 2: result = checkowner_ns(name, rdclass, type, wildcard); break; \
+ case 3: result = checkowner_md(name, rdclass, type, wildcard); break; \
+ case 4: result = checkowner_mf(name, rdclass, type, wildcard); break; \
+ case 5: result = checkowner_cname(name, rdclass, type, wildcard); break; \
+ case 6: result = checkowner_soa(name, rdclass, type, wildcard); break; \
+ case 7: result = checkowner_mb(name, rdclass, type, wildcard); break; \
+ case 8: result = checkowner_mg(name, rdclass, type, wildcard); break; \
+ case 9: result = checkowner_mr(name, rdclass, type, wildcard); break; \
+ case 10: result = checkowner_null(name, rdclass, type, wildcard); break; \
+ case 11: switch (rdclass) { \
+ case 1: result = checkowner_in_wks(name, rdclass, type, wildcard); break; \
+ default: result = ISC_TRUE; break; \
+ } \
+ break; \
+ case 12: result = checkowner_ptr(name, rdclass, type, wildcard); break; \
+ case 13: result = checkowner_hinfo(name, rdclass, type, wildcard); break; \
+ case 14: result = checkowner_minfo(name, rdclass, type, wildcard); break; \
+ case 15: result = checkowner_mx(name, rdclass, type, wildcard); break; \
+ case 16: result = checkowner_txt(name, rdclass, type, wildcard); break; \
+ case 17: result = checkowner_rp(name, rdclass, type, wildcard); break; \
+ case 18: result = checkowner_afsdb(name, rdclass, type, wildcard); break; \
+ case 19: result = checkowner_x25(name, rdclass, type, wildcard); break; \
+ case 20: result = checkowner_isdn(name, rdclass, type, wildcard); break; \
+ case 21: result = checkowner_rt(name, rdclass, type, wildcard); break; \
+ case 22: switch (rdclass) { \
+ case 1: result = checkowner_in_nsap(name, rdclass, type, wildcard); break; \
+ default: result = ISC_TRUE; break; \
+ } \
+ break; \
+ case 23: switch (rdclass) { \
+ case 1: result = checkowner_in_nsap_ptr(name, rdclass, type, wildcard); break; \
+ default: result = ISC_TRUE; break; \
+ } \
+ break; \
+ case 24: result = checkowner_sig(name, rdclass, type, wildcard); break; \
+ case 25: result = checkowner_key(name, rdclass, type, wildcard); break; \
+ case 26: switch (rdclass) { \
+ case 1: result = checkowner_in_px(name, rdclass, type, wildcard); break; \
+ default: result = ISC_TRUE; break; \
+ } \
+ break; \
+ case 27: result = checkowner_gpos(name, rdclass, type, wildcard); break; \
+ case 28: switch (rdclass) { \
+ case 1: result = checkowner_in_aaaa(name, rdclass, type, wildcard); break; \
+ default: result = ISC_TRUE; break; \
+ } \
+ break; \
+ case 29: result = checkowner_loc(name, rdclass, type, wildcard); break; \
+ case 30: result = checkowner_nxt(name, rdclass, type, wildcard); break; \
+ case 33: switch (rdclass) { \
+ case 1: result = checkowner_in_srv(name, rdclass, type, wildcard); break; \
+ default: result = ISC_TRUE; break; \
+ } \
+ break; \
+ case 35: switch (rdclass) { \
+ case 1: result = checkowner_in_naptr(name, rdclass, type, wildcard); break; \
+ default: result = ISC_TRUE; break; \
+ } \
+ break; \
+ case 36: switch (rdclass) { \
+ case 1: result = checkowner_in_kx(name, rdclass, type, wildcard); break; \
+ default: result = ISC_TRUE; break; \
+ } \
+ break; \
+ case 37: result = checkowner_cert(name, rdclass, type, wildcard); break; \
+ case 38: switch (rdclass) { \
+ case 1: result = checkowner_in_a6(name, rdclass, type, wildcard); break; \
+ default: result = ISC_TRUE; break; \
+ } \
+ break; \
+ case 39: result = checkowner_dname(name, rdclass, type, wildcard); break; \
+ case 41: result = checkowner_opt(name, rdclass, type, wildcard); break; \
+ case 42: switch (rdclass) { \
+ case 1: result = checkowner_in_apl(name, rdclass, type, wildcard); break; \
+ default: result = ISC_TRUE; break; \
+ } \
+ break; \
+ case 43: result = checkowner_ds(name, rdclass, type, wildcard); break; \
+ case 44: result = checkowner_sshfp(name, rdclass, type, wildcard); break; \
+ case 46: result = checkowner_rrsig(name, rdclass, type, wildcard); break; \
+ case 47: result = checkowner_nsec(name, rdclass, type, wildcard); break; \
+ case 48: result = checkowner_dnskey(name, rdclass, type, wildcard); break; \
+ case 103: result = checkowner_unspec(name, rdclass, type, wildcard); break; \
+ case 249: result = checkowner_tkey(name, rdclass, type, wildcard); break; \
+ case 250: switch (rdclass) { \
+ case 255: result = checkowner_any_tsig(name, rdclass, type, wildcard); break; \
+ default: result = ISC_TRUE; break; \
+ } \
+ break; \
+ case 65323: result = checkowner_dlv(name, rdclass, type, wildcard); break; \
+ default: result = ISC_TRUE; break; \
+ }
+
+#define CHECKNAMESSWITCH \
+ switch (rdata->type) { \
+ case 1: switch (rdata->rdclass) { \
+ case 1: result = checknames_in_a(rdata, owner, bad); break; \
+ case 4: result = checknames_hs_a(rdata, owner, bad); break; \
+ default: result = ISC_TRUE; break; \
+ } \
+ break; \
+ case 2: result = checknames_ns(rdata, owner, bad); break; \
+ case 3: result = checknames_md(rdata, owner, bad); break; \
+ case 4: result = checknames_mf(rdata, owner, bad); break; \
+ case 5: result = checknames_cname(rdata, owner, bad); break; \
+ case 6: result = checknames_soa(rdata, owner, bad); break; \
+ case 7: result = checknames_mb(rdata, owner, bad); break; \
+ case 8: result = checknames_mg(rdata, owner, bad); break; \
+ case 9: result = checknames_mr(rdata, owner, bad); break; \
+ case 10: result = checknames_null(rdata, owner, bad); break; \
+ case 11: switch (rdata->rdclass) { \
+ case 1: result = checknames_in_wks(rdata, owner, bad); break; \
+ default: result = ISC_TRUE; break; \
+ } \
+ break; \
+ case 12: result = checknames_ptr(rdata, owner, bad); break; \
+ case 13: result = checknames_hinfo(rdata, owner, bad); break; \
+ case 14: result = checknames_minfo(rdata, owner, bad); break; \
+ case 15: result = checknames_mx(rdata, owner, bad); break; \
+ case 16: result = checknames_txt(rdata, owner, bad); break; \
+ case 17: result = checknames_rp(rdata, owner, bad); break; \
+ case 18: result = checknames_afsdb(rdata, owner, bad); break; \
+ case 19: result = checknames_x25(rdata, owner, bad); break; \
+ case 20: result = checknames_isdn(rdata, owner, bad); break; \
+ case 21: result = checknames_rt(rdata, owner, bad); break; \
+ case 22: switch (rdata->rdclass) { \
+ case 1: result = checknames_in_nsap(rdata, owner, bad); break; \
+ default: result = ISC_TRUE; break; \
+ } \
+ break; \
+ case 23: switch (rdata->rdclass) { \
+ case 1: result = checknames_in_nsap_ptr(rdata, owner, bad); break; \
+ default: result = ISC_TRUE; break; \
+ } \
+ break; \
+ case 24: result = checknames_sig(rdata, owner, bad); break; \
+ case 25: result = checknames_key(rdata, owner, bad); break; \
+ case 26: switch (rdata->rdclass) { \
+ case 1: result = checknames_in_px(rdata, owner, bad); break; \
+ default: result = ISC_TRUE; break; \
+ } \
+ break; \
+ case 27: result = checknames_gpos(rdata, owner, bad); break; \
+ case 28: switch (rdata->rdclass) { \
+ case 1: result = checknames_in_aaaa(rdata, owner, bad); break; \
+ default: result = ISC_TRUE; break; \
+ } \
+ break; \
+ case 29: result = checknames_loc(rdata, owner, bad); break; \
+ case 30: result = checknames_nxt(rdata, owner, bad); break; \
+ case 33: switch (rdata->rdclass) { \
+ case 1: result = checknames_in_srv(rdata, owner, bad); break; \
+ default: result = ISC_TRUE; break; \
+ } \
+ break; \
+ case 35: switch (rdata->rdclass) { \
+ case 1: result = checknames_in_naptr(rdata, owner, bad); break; \
+ default: result = ISC_TRUE; break; \
+ } \
+ break; \
+ case 36: switch (rdata->rdclass) { \
+ case 1: result = checknames_in_kx(rdata, owner, bad); break; \
+ default: result = ISC_TRUE; break; \
+ } \
+ break; \
+ case 37: result = checknames_cert(rdata, owner, bad); break; \
+ case 38: switch (rdata->rdclass) { \
+ case 1: result = checknames_in_a6(rdata, owner, bad); break; \
+ default: result = ISC_TRUE; break; \
+ } \
+ break; \
+ case 39: result = checknames_dname(rdata, owner, bad); break; \
+ case 41: result = checknames_opt(rdata, owner, bad); break; \
+ case 42: switch (rdata->rdclass) { \
+ case 1: result = checknames_in_apl(rdata, owner, bad); break; \
+ default: result = ISC_TRUE; break; \
+ } \
+ break; \
+ case 43: result = checknames_ds(rdata, owner, bad); break; \
+ case 44: result = checknames_sshfp(rdata, owner, bad); break; \
+ case 46: result = checknames_rrsig(rdata, owner, bad); break; \
+ case 47: result = checknames_nsec(rdata, owner, bad); break; \
+ case 48: result = checknames_dnskey(rdata, owner, bad); break; \
+ case 103: result = checknames_unspec(rdata, owner, bad); break; \
+ case 249: result = checknames_tkey(rdata, owner, bad); break; \
+ case 250: switch (rdata->rdclass) { \
+ case 255: result = checknames_any_tsig(rdata, owner, bad); break; \
+ default: result = ISC_TRUE; break; \
+ } \
+ break; \
+ case 65323: result = checknames_dlv(rdata, owner, bad); break; \
+ default: result = ISC_TRUE; break; \
+ }
+#define RDATATYPE_COMPARE(_s, _d, _tn, _n, _tp) \
+ do { \
+ if (sizeof(_s) - 1 == _n && \
+ strncasecmp(_s,(_tn),(sizeof(_s) - 1)) == 0) { \
+ if ((dns_rdatatype_attributes(_d) & DNS_RDATATYPEATTR_RESERVED) != 0) \
+ return (ISC_R_NOTIMPLEMENTED); \
+ *(_tp) = _d; \
+ return (ISC_R_SUCCESS); \
+ } \
+ } while (0)
+
+#define RDATATYPE_FROMTEXT_SW(_hash,_typename,_length,_typep) \
+ switch (_hash) { \
+ case 16: \
+ RDATATYPE_COMPARE("reserved0", 0, _typename, _length, _typep); \
+ break; \
+ case 34: \
+ RDATATYPE_COMPARE("a", 1, _typename, _length, _typep); \
+ break; \
+ case 80: \
+ RDATATYPE_COMPARE("ns", 2, _typename, _length, _typep); \
+ break; \
+ case 92: \
+ RDATATYPE_COMPARE("md", 3, _typename, _length, _typep); \
+ break; \
+ case 58: \
+ RDATATYPE_COMPARE("mf", 4, _typename, _length, _typep); \
+ break; \
+ case 8: \
+ RDATATYPE_COMPARE("cname", 5, _typename, _length, _typep); \
+ RDATATYPE_COMPARE("mx", 15, _typename, _length, _typep); \
+ break; \
+ case 182: \
+ RDATATYPE_COMPARE("soa", 6, _typename, _length, _typep); \
+ break; \
+ case 126: \
+ RDATATYPE_COMPARE("mb", 7, _typename, _length, _typep); \
+ break; \
+ case 169: \
+ RDATATYPE_COMPARE("mg", 8, _typename, _length, _typep); \
+ break; \
+ case 110: \
+ RDATATYPE_COMPARE("mr", 9, _typename, _length, _typep); \
+ RDATATYPE_COMPARE("minfo", 14, _typename, _length, _typep); \
+ break; \
+ case 24: \
+ RDATATYPE_COMPARE("null", 10, _typename, _length, _typep); \
+ RDATATYPE_COMPARE("kx", 36, _typename, _length, _typep); \
+ break; \
+ case 206: \
+ RDATATYPE_COMPARE("wks", 11, _typename, _length, _typep); \
+ break; \
+ case 54: \
+ RDATATYPE_COMPARE("ptr", 12, _typename, _length, _typep); \
+ RDATATYPE_COMPARE("naptr", 35, _typename, _length, _typep); \
+ break; \
+ case 67: \
+ RDATATYPE_COMPARE("hinfo", 13, _typename, _length, _typep); \
+ break; \
+ case 236: \
+ RDATATYPE_COMPARE("txt", 16, _typename, _length, _typep); \
+ break; \
+ case 192: \
+ RDATATYPE_COMPARE("rp", 17, _typename, _length, _typep); \
+ break; \
+ case 12: \
+ RDATATYPE_COMPARE("afsdb", 18, _typename, _length, _typep); \
+ break; \
+ case 119: \
+ RDATATYPE_COMPARE("x25", 19, _typename, _length, _typep); \
+ break; \
+ case 214: \
+ RDATATYPE_COMPARE("isdn", 20, _typename, _length, _typep); \
+ break; \
+ case 144: \
+ RDATATYPE_COMPARE("rt", 21, _typename, _length, _typep); \
+ break; \
+ case 224: \
+ RDATATYPE_COMPARE("nsap", 22, _typename, _length, _typep); \
+ RDATATYPE_COMPARE("uid", 101, _typename, _length, _typep); \
+ break; \
+ case 140: \
+ RDATATYPE_COMPARE("nsap-ptr", 23, _typename, _length, _typep); \
+ break; \
+ case 122: \
+ RDATATYPE_COMPARE("sig", 24, _typename, _length, _typep); \
+ RDATATYPE_COMPARE("dlv", 65323, _typename, _length, _typep); \
+ break; \
+ case 254: \
+ RDATATYPE_COMPARE("key", 25, _typename, _length, _typep); \
+ break; \
+ case 112: \
+ RDATATYPE_COMPARE("px", 26, _typename, _length, _typep); \
+ break; \
+ case 17: \
+ RDATATYPE_COMPARE("gpos", 27, _typename, _length, _typep); \
+ break; \
+ case 69: \
+ RDATATYPE_COMPARE("aaaa", 28, _typename, _length, _typep); \
+ RDATATYPE_COMPARE("atma", 34, _typename, _length, _typep); \
+ break; \
+ case 237: \
+ RDATATYPE_COMPARE("loc", 29, _typename, _length, _typep); \
+ break; \
+ case 52: \
+ RDATATYPE_COMPARE("nxt", 30, _typename, _length, _typep); \
+ break; \
+ case 160: \
+ RDATATYPE_COMPARE("eid", 31, _typename, _length, _typep); \
+ break; \
+ case 220: \
+ RDATATYPE_COMPARE("nimloc", 32, _typename, _length, _typep); \
+ break; \
+ case 100: \
+ RDATATYPE_COMPARE("srv", 33, _typename, _length, _typep); \
+ break; \
+ case 172: \
+ RDATATYPE_COMPARE("cert", 37, _typename, _length, _typep); \
+ break; \
+ case 226: \
+ RDATATYPE_COMPARE("a6", 38, _typename, _length, _typep); \
+ break; \
+ case 109: \
+ RDATATYPE_COMPARE("dname", 39, _typename, _length, _typep); \
+ break; \
+ case 168: \
+ RDATATYPE_COMPARE("opt", 41, _typename, _length, _typep); \
+ break; \
+ case 48: \
+ RDATATYPE_COMPARE("apl", 42, _typename, _length, _typep); \
+ break; \
+ case 210: \
+ RDATATYPE_COMPARE("ds", 43, _typename, _length, _typep); \
+ break; \
+ case 128: \
+ RDATATYPE_COMPARE("sshfp", 44, _typename, _length, _typep); \
+ break; \
+ case 225: \
+ RDATATYPE_COMPARE("rrsig", 46, _typename, _length, _typep); \
+ break; \
+ case 22: \
+ RDATATYPE_COMPARE("nsec", 47, _typename, _length, _typep); \
+ break; \
+ case 26: \
+ RDATATYPE_COMPARE("dnskey", 48, _typename, _length, _typep); \
+ break; \
+ case 230: \
+ RDATATYPE_COMPARE("uinfo", 100, _typename, _length, _typep); \
+ break; \
+ case 104: \
+ RDATATYPE_COMPARE("gid", 102, _typename, _length, _typep); \
+ break; \
+ case 145: \
+ RDATATYPE_COMPARE("unspec", 103, _typename, _length, _typep); \
+ break; \
+ case 184: \
+ RDATATYPE_COMPARE("tkey", 249, _typename, _length, _typep); \
+ break; \
+ case 72: \
+ RDATATYPE_COMPARE("tsig", 250, _typename, _length, _typep); \
+ break; \
+ case 138: \
+ RDATATYPE_COMPARE("ixfr", 251, _typename, _length, _typep); \
+ break; \
+ case 250: \
+ RDATATYPE_COMPARE("axfr", 252, _typename, _length, _typep); \
+ break; \
+ case 164: \
+ RDATATYPE_COMPARE("mailb", 253, _typename, _length, _typep); \
+ break; \
+ case 50: \
+ RDATATYPE_COMPARE("maila", 254, _typename, _length, _typep); \
+ break; \
+ case 68: \
+ RDATATYPE_COMPARE("any", 255, _typename, _length, _typep); \
+ break; \
+ }
+#define RDATATYPE_ATTRIBUTE_SW \
+ switch (type) { \
+ case 0: return (DNS_RDATATYPEATTR_RESERVED); \
+ case 1: return (RRTYPE_A_ATTRIBUTES); \
+ case 2: return (RRTYPE_NS_ATTRIBUTES); \
+ case 3: return (RRTYPE_MD_ATTRIBUTES); \
+ case 4: return (RRTYPE_MF_ATTRIBUTES); \
+ case 5: return (RRTYPE_CNAME_ATTRIBUTES); \
+ case 6: return (RRTYPE_SOA_ATTRIBUTES); \
+ case 7: return (RRTYPE_MB_ATTRIBUTES); \
+ case 8: return (RRTYPE_MG_ATTRIBUTES); \
+ case 9: return (RRTYPE_MR_ATTRIBUTES); \
+ case 10: return (RRTYPE_NULL_ATTRIBUTES); \
+ case 11: return (RRTYPE_WKS_ATTRIBUTES); \
+ case 12: return (RRTYPE_PTR_ATTRIBUTES); \
+ case 13: return (RRTYPE_HINFO_ATTRIBUTES); \
+ case 14: return (RRTYPE_MINFO_ATTRIBUTES); \
+ case 15: return (RRTYPE_MX_ATTRIBUTES); \
+ case 16: return (RRTYPE_TXT_ATTRIBUTES); \
+ case 17: return (RRTYPE_RP_ATTRIBUTES); \
+ case 18: return (RRTYPE_AFSDB_ATTRIBUTES); \
+ case 19: return (RRTYPE_X25_ATTRIBUTES); \
+ case 20: return (RRTYPE_ISDN_ATTRIBUTES); \
+ case 21: return (RRTYPE_RT_ATTRIBUTES); \
+ case 22: return (RRTYPE_NSAP_ATTRIBUTES); \
+ case 23: return (RRTYPE_NSAP_PTR_ATTRIBUTES); \
+ case 24: return (RRTYPE_SIG_ATTRIBUTES); \
+ case 25: return (RRTYPE_KEY_ATTRIBUTES); \
+ case 26: return (RRTYPE_PX_ATTRIBUTES); \
+ case 27: return (RRTYPE_GPOS_ATTRIBUTES); \
+ case 28: return (RRTYPE_AAAA_ATTRIBUTES); \
+ case 29: return (RRTYPE_LOC_ATTRIBUTES); \
+ case 30: return (RRTYPE_NXT_ATTRIBUTES); \
+ case 31: return (DNS_RDATATYPEATTR_RESERVED); \
+ case 32: return (DNS_RDATATYPEATTR_RESERVED); \
+ case 33: return (RRTYPE_SRV_ATTRIBUTES); \
+ case 34: return (DNS_RDATATYPEATTR_RESERVED); \
+ case 35: return (RRTYPE_NAPTR_ATTRIBUTES); \
+ case 36: return (RRTYPE_KX_ATTRIBUTES); \
+ case 37: return (RRTYPE_CERT_ATTRIBUTES); \
+ case 38: return (RRTYPE_A6_ATTRIBUTES); \
+ case 39: return (RRTYPE_DNAME_ATTRIBUTES); \
+ case 41: return (RRTYPE_OPT_ATTRIBUTES); \
+ case 42: return (RRTYPE_APL_ATTRIBUTES); \
+ case 43: return (RRTYPE_DS_ATTRIBUTES); \
+ case 44: return (RRTYPE_SSHFP_ATTRIBUTES); \
+ case 46: return (RRTYPE_RRSIG_ATTRIBUTES); \
+ case 47: return (RRTYPE_NSEC_ATTRIBUTES); \
+ case 48: return (RRTYPE_DNSKEY_ATTRIBUTES); \
+ case 100: return (DNS_RDATATYPEATTR_RESERVED); \
+ case 101: return (DNS_RDATATYPEATTR_RESERVED); \
+ case 102: return (DNS_RDATATYPEATTR_RESERVED); \
+ case 103: return (RRTYPE_UNSPEC_ATTRIBUTES); \
+ case 249: return (RRTYPE_TKEY_ATTRIBUTES); \
+ case 250: return (RRTYPE_TSIG_ATTRIBUTES); \
+ case 251: return (DNS_RDATATYPEATTR_META | DNS_RDATATYPEATTR_QUESTIONONLY); \
+ case 252: return (DNS_RDATATYPEATTR_META | DNS_RDATATYPEATTR_QUESTIONONLY); \
+ case 253: return (DNS_RDATATYPEATTR_META | DNS_RDATATYPEATTR_QUESTIONONLY); \
+ case 254: return (DNS_RDATATYPEATTR_META | DNS_RDATATYPEATTR_QUESTIONONLY); \
+ case 255: return (DNS_RDATATYPEATTR_META | DNS_RDATATYPEATTR_QUESTIONONLY); \
+ case 65323: return (RRTYPE_DLV_ATTRIBUTES); \
+ }
+#define RDATATYPE_TOTEXT_SW \
+ switch (type) { \
+ case 0: return (str_totext("RESERVED0", target)); \
+ case 1: return (str_totext("A", target)); \
+ case 2: return (str_totext("NS", target)); \
+ case 3: return (str_totext("MD", target)); \
+ case 4: return (str_totext("MF", target)); \
+ case 5: return (str_totext("CNAME", target)); \
+ case 6: return (str_totext("SOA", target)); \
+ case 7: return (str_totext("MB", target)); \
+ case 8: return (str_totext("MG", target)); \
+ case 9: return (str_totext("MR", target)); \
+ case 10: return (str_totext("NULL", target)); \
+ case 11: return (str_totext("WKS", target)); \
+ case 12: return (str_totext("PTR", target)); \
+ case 13: return (str_totext("HINFO", target)); \
+ case 14: return (str_totext("MINFO", target)); \
+ case 15: return (str_totext("MX", target)); \
+ case 16: return (str_totext("TXT", target)); \
+ case 17: return (str_totext("RP", target)); \
+ case 18: return (str_totext("AFSDB", target)); \
+ case 19: return (str_totext("X25", target)); \
+ case 20: return (str_totext("ISDN", target)); \
+ case 21: return (str_totext("RT", target)); \
+ case 22: return (str_totext("NSAP", target)); \
+ case 23: return (str_totext("NSAP-PTR", target)); \
+ case 24: return (str_totext("SIG", target)); \
+ case 25: return (str_totext("KEY", target)); \
+ case 26: return (str_totext("PX", target)); \
+ case 27: return (str_totext("GPOS", target)); \
+ case 28: return (str_totext("AAAA", target)); \
+ case 29: return (str_totext("LOC", target)); \
+ case 30: return (str_totext("NXT", target)); \
+ case 31: return (str_totext("EID", target)); \
+ case 32: return (str_totext("NIMLOC", target)); \
+ case 33: return (str_totext("SRV", target)); \
+ case 34: return (str_totext("ATMA", target)); \
+ case 35: return (str_totext("NAPTR", target)); \
+ case 36: return (str_totext("KX", target)); \
+ case 37: return (str_totext("CERT", target)); \
+ case 38: return (str_totext("A6", target)); \
+ case 39: return (str_totext("DNAME", target)); \
+ case 41: return (str_totext("OPT", target)); \
+ case 42: return (str_totext("APL", target)); \
+ case 43: return (str_totext("DS", target)); \
+ case 44: return (str_totext("SSHFP", target)); \
+ case 46: return (str_totext("RRSIG", target)); \
+ case 47: return (str_totext("NSEC", target)); \
+ case 48: return (str_totext("DNSKEY", target)); \
+ case 100: return (str_totext("UINFO", target)); \
+ case 101: return (str_totext("UID", target)); \
+ case 102: return (str_totext("GID", target)); \
+ case 103: return (str_totext("UNSPEC", target)); \
+ case 249: return (str_totext("TKEY", target)); \
+ case 250: return (str_totext("TSIG", target)); \
+ case 251: return (str_totext("IXFR", target)); \
+ case 252: return (str_totext("AXFR", target)); \
+ case 253: return (str_totext("MAILB", target)); \
+ case 254: return (str_totext("MAILA", target)); \
+ case 255: return (str_totext("ANY", target)); \
+ case 65323: return (str_totext("DLV", target)); \
+ }
+#endif /* DNS_CODE_H */
diff --git a/lib/bind/dns/dns/enumclass.h b/lib/bind/dns/dns/enumclass.h
new file mode 100644
index 0000000..f3490a4
--- /dev/null
+++ b/lib/bind/dns/dns/enumclass.h
@@ -0,0 +1,48 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2004-2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-2003 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.
+ */
+
+/***************
+ ***************
+ *************** THIS FILE IS AUTOMATICALLY GENERATED BY gen.c.
+ *************** DO NOT EDIT!
+ ***************
+ ***************/
+
+#ifndef DNS_ENUMCLASS_H
+#define DNS_ENUMCLASS_H 1
+
+enum {
+ dns_rdataclass_reserved0 = 0,
+#define dns_rdataclass_reserved0 \
+ ((dns_rdataclass_t)dns_rdataclass_reserved0)
+ dns_rdataclass_in = 1,
+#define dns_rdataclass_in ((dns_rdataclass_t)dns_rdataclass_in)
+ dns_rdataclass_ch = 3,
+#define dns_rdataclass_ch ((dns_rdataclass_t)dns_rdataclass_ch)
+ dns_rdataclass_chaos = 3,
+#define dns_rdataclass_chaos ((dns_rdataclass_t)dns_rdataclass_chaos)
+ dns_rdataclass_hs = 4,
+#define dns_rdataclass_hs ((dns_rdataclass_t)dns_rdataclass_hs)
+ dns_rdataclass_none = 254,
+#define dns_rdataclass_none ((dns_rdataclass_t)dns_rdataclass_none)
+ dns_rdataclass_any = 255
+#define dns_rdataclass_any ((dns_rdataclass_t)dns_rdataclass_any)
+};
+
+#endif /* DNS_ENUMCLASS_H */
diff --git a/lib/bind/dns/dns/enumtype.h b/lib/bind/dns/dns/enumtype.h
new file mode 100644
index 0000000..8692368
--- /dev/null
+++ b/lib/bind/dns/dns/enumtype.h
@@ -0,0 +1,140 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2004-2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-2003 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.
+ */
+
+/***************
+ ***************
+ *************** THIS FILE IS AUTOMATICALLY GENERATED BY gen.c.
+ *************** DO NOT EDIT!
+ ***************
+ ***************/
+
+#ifndef DNS_ENUMTYPE_H
+#define DNS_ENUMTYPE_H 1
+
+enum {
+ dns_rdatatype_none = 0,
+ dns_rdatatype_a = 1,
+ dns_rdatatype_ns = 2,
+ dns_rdatatype_md = 3,
+ dns_rdatatype_mf = 4,
+ dns_rdatatype_cname = 5,
+ dns_rdatatype_soa = 6,
+ dns_rdatatype_mb = 7,
+ dns_rdatatype_mg = 8,
+ dns_rdatatype_mr = 9,
+ dns_rdatatype_null = 10,
+ dns_rdatatype_wks = 11,
+ dns_rdatatype_ptr = 12,
+ dns_rdatatype_hinfo = 13,
+ dns_rdatatype_minfo = 14,
+ dns_rdatatype_mx = 15,
+ dns_rdatatype_txt = 16,
+ dns_rdatatype_rp = 17,
+ dns_rdatatype_afsdb = 18,
+ dns_rdatatype_x25 = 19,
+ dns_rdatatype_isdn = 20,
+ dns_rdatatype_rt = 21,
+ dns_rdatatype_nsap = 22,
+ dns_rdatatype_nsap_ptr = 23,
+ dns_rdatatype_sig = 24,
+ dns_rdatatype_key = 25,
+ dns_rdatatype_px = 26,
+ dns_rdatatype_gpos = 27,
+ dns_rdatatype_aaaa = 28,
+ dns_rdatatype_loc = 29,
+ dns_rdatatype_nxt = 30,
+ dns_rdatatype_srv = 33,
+ dns_rdatatype_naptr = 35,
+ dns_rdatatype_kx = 36,
+ dns_rdatatype_cert = 37,
+ dns_rdatatype_a6 = 38,
+ dns_rdatatype_dname = 39,
+ dns_rdatatype_opt = 41,
+ dns_rdatatype_apl = 42,
+ dns_rdatatype_ds = 43,
+ dns_rdatatype_sshfp = 44,
+ dns_rdatatype_rrsig = 46,
+ dns_rdatatype_nsec = 47,
+ dns_rdatatype_dnskey = 48,
+ dns_rdatatype_unspec = 103,
+ dns_rdatatype_tkey = 249,
+ dns_rdatatype_tsig = 250,
+ dns_rdatatype_dlv = 65323,
+ dns_rdatatype_ixfr = 251,
+ dns_rdatatype_axfr = 252,
+ dns_rdatatype_mailb = 253,
+ dns_rdatatype_maila = 254,
+ dns_rdatatype_any = 255
+};
+
+#define dns_rdatatype_none ((dns_rdatatype_t)dns_rdatatype_none)
+#define dns_rdatatype_a ((dns_rdatatype_t)dns_rdatatype_a)
+#define dns_rdatatype_ns ((dns_rdatatype_t)dns_rdatatype_ns)
+#define dns_rdatatype_md ((dns_rdatatype_t)dns_rdatatype_md)
+#define dns_rdatatype_mf ((dns_rdatatype_t)dns_rdatatype_mf)
+#define dns_rdatatype_cname ((dns_rdatatype_t)dns_rdatatype_cname)
+#define dns_rdatatype_soa ((dns_rdatatype_t)dns_rdatatype_soa)
+#define dns_rdatatype_mb ((dns_rdatatype_t)dns_rdatatype_mb)
+#define dns_rdatatype_mg ((dns_rdatatype_t)dns_rdatatype_mg)
+#define dns_rdatatype_mr ((dns_rdatatype_t)dns_rdatatype_mr)
+#define dns_rdatatype_null ((dns_rdatatype_t)dns_rdatatype_null)
+#define dns_rdatatype_wks ((dns_rdatatype_t)dns_rdatatype_wks)
+#define dns_rdatatype_ptr ((dns_rdatatype_t)dns_rdatatype_ptr)
+#define dns_rdatatype_hinfo ((dns_rdatatype_t)dns_rdatatype_hinfo)
+#define dns_rdatatype_minfo ((dns_rdatatype_t)dns_rdatatype_minfo)
+#define dns_rdatatype_mx ((dns_rdatatype_t)dns_rdatatype_mx)
+#define dns_rdatatype_txt ((dns_rdatatype_t)dns_rdatatype_txt)
+#define dns_rdatatype_rp ((dns_rdatatype_t)dns_rdatatype_rp)
+#define dns_rdatatype_afsdb ((dns_rdatatype_t)dns_rdatatype_afsdb)
+#define dns_rdatatype_x25 ((dns_rdatatype_t)dns_rdatatype_x25)
+#define dns_rdatatype_isdn ((dns_rdatatype_t)dns_rdatatype_isdn)
+#define dns_rdatatype_rt ((dns_rdatatype_t)dns_rdatatype_rt)
+#define dns_rdatatype_nsap ((dns_rdatatype_t)dns_rdatatype_nsap)
+#define dns_rdatatype_nsap_ptr ((dns_rdatatype_t)dns_rdatatype_nsap_ptr)
+#define dns_rdatatype_sig ((dns_rdatatype_t)dns_rdatatype_sig)
+#define dns_rdatatype_key ((dns_rdatatype_t)dns_rdatatype_key)
+#define dns_rdatatype_px ((dns_rdatatype_t)dns_rdatatype_px)
+#define dns_rdatatype_gpos ((dns_rdatatype_t)dns_rdatatype_gpos)
+#define dns_rdatatype_aaaa ((dns_rdatatype_t)dns_rdatatype_aaaa)
+#define dns_rdatatype_loc ((dns_rdatatype_t)dns_rdatatype_loc)
+#define dns_rdatatype_nxt ((dns_rdatatype_t)dns_rdatatype_nxt)
+#define dns_rdatatype_srv ((dns_rdatatype_t)dns_rdatatype_srv)
+#define dns_rdatatype_naptr ((dns_rdatatype_t)dns_rdatatype_naptr)
+#define dns_rdatatype_kx ((dns_rdatatype_t)dns_rdatatype_kx)
+#define dns_rdatatype_cert ((dns_rdatatype_t)dns_rdatatype_cert)
+#define dns_rdatatype_a6 ((dns_rdatatype_t)dns_rdatatype_a6)
+#define dns_rdatatype_dname ((dns_rdatatype_t)dns_rdatatype_dname)
+#define dns_rdatatype_opt ((dns_rdatatype_t)dns_rdatatype_opt)
+#define dns_rdatatype_apl ((dns_rdatatype_t)dns_rdatatype_apl)
+#define dns_rdatatype_ds ((dns_rdatatype_t)dns_rdatatype_ds)
+#define dns_rdatatype_sshfp ((dns_rdatatype_t)dns_rdatatype_sshfp)
+#define dns_rdatatype_rrsig ((dns_rdatatype_t)dns_rdatatype_rrsig)
+#define dns_rdatatype_nsec ((dns_rdatatype_t)dns_rdatatype_nsec)
+#define dns_rdatatype_dnskey ((dns_rdatatype_t)dns_rdatatype_dnskey)
+#define dns_rdatatype_unspec ((dns_rdatatype_t)dns_rdatatype_unspec)
+#define dns_rdatatype_tkey ((dns_rdatatype_t)dns_rdatatype_tkey)
+#define dns_rdatatype_tsig ((dns_rdatatype_t)dns_rdatatype_tsig)
+#define dns_rdatatype_dlv ((dns_rdatatype_t)dns_rdatatype_dlv)
+#define dns_rdatatype_ixfr ((dns_rdatatype_t)dns_rdatatype_ixfr)
+#define dns_rdatatype_axfr ((dns_rdatatype_t)dns_rdatatype_axfr)
+#define dns_rdatatype_mailb ((dns_rdatatype_t)dns_rdatatype_mailb)
+#define dns_rdatatype_maila ((dns_rdatatype_t)dns_rdatatype_maila)
+#define dns_rdatatype_any ((dns_rdatatype_t)dns_rdatatype_any)
+
+#endif /* DNS_ENUMTYPE_H */
diff --git a/lib/bind/dns/dns/rdatastruct.h b/lib/bind/dns/dns/rdatastruct.h
new file mode 100644
index 0000000..ce30e49
--- /dev/null
+++ b/lib/bind/dns/dns/rdatastruct.h
@@ -0,0 +1,1733 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2004-2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-2003 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.
+ */
+
+/***************
+ ***************
+ *************** THIS FILE IS AUTOMATICALLY GENERATED BY gen.c.
+ *************** DO NOT EDIT!
+ ***************
+ ***************/
+
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-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.
+ */
+
+/* $Id: rdatastructpre.h,v 1.13.206.1 2004/03/06 08:14:02 marka Exp $ */
+
+#ifndef DNS_RDATASTRUCT_H
+#define DNS_RDATASTRUCT_H 1
+
+#include <isc/lang.h>
+#include <isc/sockaddr.h>
+
+#include <dns/name.h>
+#include <dns/types.h>
+
+ISC_LANG_BEGINDECLS
+
+typedef struct dns_rdatacommon {
+ dns_rdataclass_t rdclass;
+ dns_rdatatype_t rdtype;
+ ISC_LINK(struct dns_rdatacommon) link;
+} dns_rdatacommon_t;
+
+#define DNS_RDATACOMMON_INIT(_data, _rdtype, _rdclass) \
+ do { \
+ (_data)->common.rdtype = (_rdtype); \
+ (_data)->common.rdclass = (_rdclass); \
+ ISC_LINK_INIT(&(_data)->common, link); \
+ } while (0)
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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.
+ */
+
+#ifndef IN_1_A_1_H
+#define IN_1_A_1_H 1
+
+/* $Id: a_1.h,v 1.23.206.1 2004/03/06 08:14:16 marka Exp $ */
+
+typedef struct dns_rdata_in_a {
+ dns_rdatacommon_t common;
+ struct in_addr in_addr;
+} dns_rdata_in_a_t;
+
+#endif /* IN_1_A_1_H */
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-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.
+ */
+
+#ifndef HS_4_A_1_H
+#define HS_4_A_1_H 1
+
+/* $Id: a_1.h,v 1.7.206.1 2004/03/06 08:14:15 marka Exp $ */
+
+typedef struct dns_rdata_hs_a {
+ dns_rdatacommon_t common;
+ struct in_addr in_addr;
+} dns_rdata_hs_a_t;
+
+#endif /* HS_4_A_1_H */
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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.
+ */
+
+#ifndef GENERIC_NS_2_H
+#define GENERIC_NS_2_H 1
+
+/* $Id: ns_2.h,v 1.22.206.1 2004/03/06 08:14:09 marka Exp $ */
+
+typedef struct dns_rdata_ns {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ dns_name_t name;
+} dns_rdata_ns_t;
+
+
+#endif /* GENERIC_NS_2_H */
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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.
+ */
+
+#ifndef GENERIC_MD_3_H
+#define GENERIC_MD_3_H 1
+
+/* $Id: md_3.h,v 1.23.206.1 2004/03/06 08:14:07 marka Exp $ */
+
+typedef struct dns_rdata_md {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ dns_name_t md;
+} dns_rdata_md_t;
+
+
+#endif /* GENERIC_MD_3_H */
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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.
+ */
+
+#ifndef GENERIC_MF_4_H
+#define GENERIC_MF_4_H 1
+
+/* $Id: mf_4.h,v 1.21.206.1 2004/03/06 08:14:07 marka Exp $ */
+
+typedef struct dns_rdata_mf {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ dns_name_t mf;
+} dns_rdata_mf_t;
+
+#endif /* GENERIC_MF_4_H */
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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.
+ */
+
+/* $Id: cname_5.h,v 1.23.206.1 2004/03/06 08:14:04 marka Exp $ */
+
+#ifndef GENERIC_CNAME_5_H
+#define GENERIC_CNAME_5_H 1
+
+typedef struct dns_rdata_cname {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ dns_name_t cname;
+} dns_rdata_cname_t;
+
+#endif /* GENERIC_CNAME_5_H */
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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.
+ */
+
+#ifndef GENERIC_SOA_6_H
+#define GENERIC_SOA_6_H 1
+
+/* $Id: soa_6.h,v 1.27.206.1 2004/03/06 08:14:12 marka Exp $ */
+
+typedef struct dns_rdata_soa {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ dns_name_t origin;
+ dns_name_t contact;
+ isc_uint32_t serial; /* host order */
+ isc_uint32_t refresh; /* host order */
+ isc_uint32_t retry; /* host order */
+ isc_uint32_t expire; /* host order */
+ isc_uint32_t minimum; /* host order */
+} dns_rdata_soa_t;
+
+
+#endif /* GENERIC_SOA_6_H */
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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.
+ */
+
+#ifndef GENERIC_MB_7_H
+#define GENERIC_MB_7_H 1
+
+/* $Id: mb_7.h,v 1.22.206.1 2004/03/06 08:14:06 marka Exp $ */
+
+typedef struct dns_rdata_mb {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ dns_name_t mb;
+} dns_rdata_mb_t;
+
+#endif /* GENERIC_MB_7_H */
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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.
+ */
+
+#ifndef GENERIC_MG_8_H
+#define GENERIC_MG_8_H 1
+
+/* $Id: mg_8.h,v 1.21.206.1 2004/03/06 08:14:07 marka Exp $ */
+
+typedef struct dns_rdata_mg {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ dns_name_t mg;
+} dns_rdata_mg_t;
+
+#endif /* GENERIC_MG_8_H */
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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.
+ */
+
+#ifndef GENERIC_MR_9_H
+#define GENERIC_MR_9_H 1
+
+/* $Id: mr_9.h,v 1.21.206.1 2004/03/06 08:14:08 marka Exp $ */
+
+typedef struct dns_rdata_mr {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ dns_name_t mr;
+} dns_rdata_mr_t;
+
+#endif /* GENERIC_MR_9_H */
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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.
+ */
+
+#ifndef GENERIC_NULL_10_H
+#define GENERIC_NULL_10_H 1
+
+/* $Id: null_10.h,v 1.20.206.1 2004/03/06 08:14:09 marka Exp $ */
+
+typedef struct dns_rdata_null {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ isc_uint16_t length;
+ unsigned char *data;
+} dns_rdata_null_t;
+
+
+#endif /* GENERIC_NULL_10_H */
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-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.
+ */
+
+#ifndef IN_1_WKS_11_H
+#define IN_1_WKS_11_H 1
+
+/* $Id: wks_11.h,v 1.19.206.1 2004/03/06 08:14:19 marka Exp $ */
+
+typedef struct dns_rdata_in_wks {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ struct in_addr in_addr;
+ isc_uint16_t protocol;
+ unsigned char *map;
+ isc_uint16_t map_len;
+} dns_rdata_in_wks_t;
+
+#endif /* IN_1_WKS_11_H */
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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.
+ */
+
+#ifndef GENERIC_PTR_12_H
+#define GENERIC_PTR_12_H 1
+
+/* $Id: ptr_12.h,v 1.22.206.1 2004/03/06 08:14:11 marka Exp $ */
+
+typedef struct dns_rdata_ptr {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ dns_name_t ptr;
+} dns_rdata_ptr_t;
+
+#endif /* GENERIC_PTR_12_H */
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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.
+ */
+
+#ifndef GENERIC_HINFO_13_H
+#define GENERIC_HINFO_13_H 1
+
+/* $Id: hinfo_13.h,v 1.22.206.1 2004/03/06 08:14:05 marka Exp $ */
+
+typedef struct dns_rdata_hinfo {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ char *cpu;
+ char *os;
+ isc_uint8_t cpu_len;
+ isc_uint8_t os_len;
+} dns_rdata_hinfo_t;
+
+#endif /* GENERIC_HINFO_13_H */
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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.
+ */
+
+#ifndef GENERIC_MINFO_14_H
+#define GENERIC_MINFO_14_H 1
+
+/* $Id: minfo_14.h,v 1.22.206.1 2004/03/06 08:14:08 marka Exp $ */
+
+typedef struct dns_rdata_minfo {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ dns_name_t rmailbox;
+ dns_name_t emailbox;
+} dns_rdata_minfo_t;
+
+#endif /* GENERIC_MINFO_14_H */
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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.
+ */
+
+#ifndef GENERIC_MX_15_H
+#define GENERIC_MX_15_H 1
+
+/* $Id: mx_15.h,v 1.24.206.1 2004/03/06 08:14:09 marka Exp $ */
+
+typedef struct dns_rdata_mx {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ isc_uint16_t pref;
+ dns_name_t mx;
+} dns_rdata_mx_t;
+
+#endif /* GENERIC_MX_15_H */
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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.
+ */
+
+#ifndef GENERIC_TXT_16_H
+#define GENERIC_TXT_16_H 1
+
+/* $Id: txt_16.h,v 1.23.206.1 2004/03/06 08:14:14 marka Exp $ */
+
+typedef struct dns_rdata_txt_string {
+ isc_uint8_t length;
+ unsigned char *data;
+} dns_rdata_txt_string_t;
+
+typedef struct dns_rdata_txt {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ unsigned char *txt;
+ isc_uint16_t txt_len;
+ /* private */
+ isc_uint16_t offset;
+} dns_rdata_txt_t;
+
+/*
+ * ISC_LANG_BEGINDECLS and ISC_LANG_ENDDECLS are already done
+ * via rdatastructpre.h and rdatastructsuf.h.
+ */
+
+isc_result_t
+dns_rdata_txt_first(dns_rdata_txt_t *);
+
+isc_result_t
+dns_rdata_txt_next(dns_rdata_txt_t *);
+
+isc_result_t
+dns_rdata_txt_current(dns_rdata_txt_t *, dns_rdata_txt_string_t *);
+
+#endif /* GENERIC_TXT_16_H */
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-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.
+ */
+
+#ifndef GENERIC_RP_17_H
+#define GENERIC_RP_17_H 1
+
+/* $Id: rp_17.h,v 1.16.206.1 2004/03/06 08:14:11 marka Exp $ */
+
+/* RFC 1183 */
+
+typedef struct dns_rdata_rp {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ dns_name_t mail;
+ dns_name_t text;
+} dns_rdata_rp_t;
+
+
+#endif /* GENERIC_RP_17_H */
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-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.
+ */
+
+#ifndef GENERIC_AFSDB_18_H
+#define GENERIC_AFSDB_18_H 1
+
+/* $Id: afsdb_18.h,v 1.15.206.1 2004/03/06 08:14:03 marka Exp $ */
+
+/* RFC 1183 */
+
+typedef struct dns_rdata_afsdb {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ isc_uint16_t subtype;
+ dns_name_t server;
+} dns_rdata_afsdb_t;
+
+#endif /* GENERIC_AFSDB_18_H */
+
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-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.
+ */
+
+#ifndef GENERIC_X25_19_H
+#define GENERIC_X25_19_H 1
+
+/* $Id: x25_19.h,v 1.13.206.1 2004/03/06 08:14:14 marka Exp $ */
+
+/* RFC 1183 */
+
+typedef struct dns_rdata_x25 {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ unsigned char *x25;
+ isc_uint8_t x25_len;
+} dns_rdata_x25_t;
+
+#endif /* GENERIC_X25_19_H */
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-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.
+ */
+
+#ifndef GENERIC_ISDN_20_H
+#define GENERIC_ISDN_20_H 1
+
+/* $Id: isdn_20.h,v 1.13.206.1 2004/03/06 08:14:05 marka Exp $ */
+
+/* RFC 1183 */
+
+typedef struct dns_rdata_isdn {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ char *isdn;
+ char *subaddress;
+ isc_uint8_t isdn_len;
+ isc_uint8_t subaddress_len;
+} dns_rdata_isdn_t;
+
+#endif /* GENERIC_ISDN_20_H */
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-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.
+ */
+
+#ifndef GENERIC_RT_21_H
+#define GENERIC_RT_21_H 1
+
+/* $Id: rt_21.h,v 1.16.206.1 2004/03/06 08:14:12 marka Exp $ */
+
+/* RFC 1183 */
+
+typedef struct dns_rdata_rt {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ isc_uint16_t preference;
+ dns_name_t host;
+} dns_rdata_rt_t;
+
+#endif /* GENERIC_RT_21_H */
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-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.
+ */
+
+#ifndef IN_1_NSAP_22_H
+#define IN_1_NSAP_22_H 1
+
+/* $Id: nsap_22.h,v 1.13.206.1 2004/03/06 08:14:18 marka Exp $ */
+
+/* RFC 1706 */
+
+typedef struct dns_rdata_in_nsap {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ unsigned char *nsap;
+ isc_uint16_t nsap_len;
+} dns_rdata_in_nsap_t;
+
+#endif /* IN_1_NSAP_22_H */
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-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.
+ */
+
+#ifndef IN_1_NSAP_PTR_23_H
+#define IN_1_NSAP_PTR_23_H 1
+
+/* $Id: nsap-ptr_23.h,v 1.14.206.1 2004/03/06 08:14:18 marka Exp $ */
+
+/* RFC 1348. Obsoleted in RFC 1706 - use PTR instead. */
+
+typedef struct dns_rdata_in_nsap_ptr {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ dns_name_t owner;
+} dns_rdata_in_nsap_ptr_t;
+
+#endif /* IN_1_NSAP_PTR_23_H */
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-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.
+ */
+
+#ifndef GENERIC_SIG_24_H
+#define GENERIC_SIG_24_H 1
+
+/* $Id: sig_24.h,v 1.21.206.1 2004/03/06 08:14:12 marka Exp $ */
+
+/* RFC 2535 */
+
+typedef struct dns_rdata_sig_t {
+ dns_rdatacommon_t common;
+ isc_mem_t * mctx;
+ dns_rdatatype_t covered;
+ dns_secalg_t algorithm;
+ isc_uint8_t labels;
+ isc_uint32_t originalttl;
+ isc_uint32_t timeexpire;
+ isc_uint32_t timesigned;
+ isc_uint16_t keyid;
+ dns_name_t signer;
+ isc_uint16_t siglen;
+ unsigned char * signature;
+} dns_rdata_sig_t;
+
+
+#endif /* GENERIC_SIG_24_H */
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-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.
+ */
+
+#ifndef GENERIC_KEY_25_H
+#define GENERIC_KEY_25_H 1
+
+/* $Id: key_25.h,v 1.14.206.1 2004/03/06 08:14:06 marka Exp $ */
+
+/* RFC 2535 */
+
+typedef struct dns_rdata_key_t {
+ dns_rdatacommon_t common;
+ isc_mem_t * mctx;
+ isc_uint16_t flags;
+ isc_uint8_t protocol;
+ isc_uint8_t algorithm;
+ isc_uint16_t datalen;
+ unsigned char * data;
+} dns_rdata_key_t;
+
+
+#endif /* GENERIC_KEY_25_H */
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-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.
+ */
+
+#ifndef IN_1_PX_26_H
+#define IN_1_PX_26_H 1
+
+/* $Id: px_26.h,v 1.14.206.1 2004/03/06 08:14:18 marka Exp $ */
+
+/* RFC 2163 */
+
+typedef struct dns_rdata_in_px {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ isc_uint16_t preference;
+ dns_name_t map822;
+ dns_name_t mapx400;
+} dns_rdata_in_px_t;
+
+#endif /* IN_1_PX_26_H */
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-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.
+ */
+
+#ifndef GENERIC_GPOS_27_H
+#define GENERIC_GPOS_27_H 1
+
+/* $Id: gpos_27.h,v 1.12.206.1 2004/03/06 08:14:04 marka Exp $ */
+
+/* RFC 1712 */
+
+typedef struct dns_rdata_gpos {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ char *longitude;
+ char *latitude;
+ char *altitude;
+ isc_uint8_t long_len;
+ isc_uint8_t lat_len;
+ isc_uint8_t alt_len;
+} dns_rdata_gpos_t;
+
+#endif /* GENERIC_GPOS_27_H */
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-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.
+ */
+
+#ifndef IN_1_AAAA_28_H
+#define IN_1_AAAA_28_H 1
+
+/* $Id: aaaa_28.h,v 1.16.206.1 2004/03/06 08:14:16 marka Exp $ */
+
+/* RFC 1886 */
+
+typedef struct dns_rdata_in_aaaa {
+ dns_rdatacommon_t common;
+ struct in6_addr in6_addr;
+} dns_rdata_in_aaaa_t;
+
+#endif /* IN_1_AAAA_28_H */
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-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.
+ */
+
+#ifndef GENERIC_LOC_29_H
+#define GENERIC_LOC_29_H 1
+
+/* $Id: loc_29.h,v 1.14.206.1 2004/03/06 08:14:06 marka Exp $ */
+
+/* RFC 1876 */
+
+typedef struct dns_rdata_loc_0 {
+ isc_uint8_t version; /* must be first and zero */
+ isc_uint8_t size;
+ isc_uint8_t horizontal;
+ isc_uint8_t vertical;
+ isc_uint32_t latitude;
+ isc_uint32_t longitude;
+ isc_uint32_t altitude;
+} dns_rdata_loc_0_t;
+
+typedef struct dns_rdata_loc {
+ dns_rdatacommon_t common;
+ union {
+ dns_rdata_loc_0_t v0;
+ } v;
+} dns_rdata_loc_t;
+
+#endif /* GENERIC_LOC_29_H */
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2002 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 GENERIC_NXT_30_H
+#define GENERIC_NXT_30_H 1
+
+/* $Id: nxt_30.h,v 1.18.12.3 2004/03/08 09:04:41 marka Exp $ */
+
+/* RFC 2535 */
+
+typedef struct dns_rdata_nxt {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ dns_name_t next;
+ unsigned char *typebits;
+ isc_uint16_t len;
+} dns_rdata_nxt_t;
+
+#endif /* GENERIC_NXT_30_H */
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-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.
+ */
+
+#ifndef IN_1_SRV_33_H
+#define IN_1_SRV_33_H 1
+
+/* $Id: srv_33.h,v 1.14.206.1 2004/03/06 08:14:19 marka Exp $ */
+
+/* Reviewed: Fri Mar 17 13:01:00 PST 2000 by bwelling */
+
+/* RFC 2782 */
+
+typedef struct dns_rdata_in_srv {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ isc_uint16_t priority;
+ isc_uint16_t weight;
+ isc_uint16_t port;
+ dns_name_t target;
+} dns_rdata_in_srv_t;
+
+#endif /* IN_1_SRV_33_H */
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-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.
+ */
+
+#ifndef IN_1_NAPTR_35_H
+#define IN_1_NAPTR_35_H 1
+
+/* $Id: naptr_35.h,v 1.18.206.1 2004/03/06 08:14:17 marka Exp $ */
+
+/* RFC 2915 */
+
+typedef struct dns_rdata_in_naptr {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ isc_uint16_t order;
+ isc_uint16_t preference;
+ char *flags;
+ isc_uint8_t flags_len;
+ char *service;
+ isc_uint8_t service_len;
+ char *regexp;
+ isc_uint8_t regexp_len;
+ dns_name_t replacement;
+} dns_rdata_in_naptr_t;
+
+#endif /* IN_1_NAPTR_35_H */
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-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.
+ */
+
+#ifndef IN_1_KX_36_H
+#define IN_1_KX_36_H 1
+
+/* $Id: kx_36.h,v 1.15.206.1 2004/03/06 08:14:17 marka Exp $ */
+
+/* RFC 2230 */
+
+typedef struct dns_rdata_in_kx {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ isc_uint16_t preference;
+ dns_name_t exchange;
+} dns_rdata_in_kx_t;
+
+#endif /* IN_1_KX_36_H */
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-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.
+ */
+
+/* $Id: cert_37.h,v 1.15.206.1 2004/03/06 08:14:03 marka Exp $ */
+
+/* RFC 2538 */
+#ifndef GENERIC_CERT_37_H
+#define GENERIC_CERT_37_H 1
+
+typedef struct dns_rdata_cert {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ isc_uint16_t type;
+ isc_uint16_t key_tag;
+ isc_uint8_t algorithm;
+ isc_uint16_t length;
+ unsigned char *certificate;
+} dns_rdata_cert_t;
+
+#endif /* GENERIC_CERT_37_H */
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-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.
+ */
+
+#ifndef IN_1_A6_38_H
+#define IN_1_A6_38_H 1
+
+/* $Id: a6_38.h,v 1.19.206.1 2004/03/06 08:14:15 marka Exp $ */
+
+/* RFC2874 */
+
+typedef struct dns_rdata_in_a6 {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ dns_name_t prefix;
+ isc_uint8_t prefixlen;
+ struct in6_addr in6_addr;
+} dns_rdata_in_a6_t;
+
+#endif /* IN_1_A6_38_H */
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-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.
+ */
+
+#ifndef GENERIC_DNAME_39_H
+#define GENERIC_DNAME_39_H 1
+
+/* $Id: dname_39.h,v 1.16.206.1 2004/03/06 08:14:04 marka Exp $ */
+
+/* RFC2672 */
+
+typedef struct dns_rdata_dname {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ dns_name_t dname;
+} dns_rdata_dname_t;
+
+#endif /* GENERIC_DNAME_39_H */
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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.
+ */
+
+#ifndef GENERIC_OPT_41_H
+#define GENERIC_OPT_41_H 1
+
+/* $Id: opt_41.h,v 1.13.206.1 2004/03/06 08:14:10 marka Exp $ */
+
+/* RFC 2671 */
+
+typedef struct dns_rdata_opt_opcode {
+ isc_uint16_t opcode;
+ isc_uint16_t length;
+ unsigned char *data;
+} dns_rdata_opt_opcode_t;
+
+typedef struct dns_rdata_opt {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ unsigned char *options;
+ isc_uint16_t length;
+ /* private */
+ isc_uint16_t offset;
+} dns_rdata_opt_t;
+
+/*
+ * ISC_LANG_BEGINDECLS and ISC_LANG_ENDDECLS are already done
+ * via rdatastructpre.h and rdatastructsuf.h.
+ */
+
+isc_result_t
+dns_rdata_opt_first(dns_rdata_opt_t *);
+
+isc_result_t
+dns_rdata_opt_next(dns_rdata_opt_t *);
+
+isc_result_t
+dns_rdata_opt_current(dns_rdata_opt_t *, dns_rdata_opt_opcode_t *);
+
+#endif /* GENERIC_OPT_41_H */
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2002 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 IN_1_APL_42_H
+#define IN_1_APL_42_H 1
+
+/* $Id: apl_42.h,v 1.1.202.3 2004/03/08 09:04:44 marka Exp $ */
+
+typedef struct dns_rdata_apl_ent {
+ isc_boolean_t negative;
+ isc_uint16_t family;
+ isc_uint8_t prefix;
+ isc_uint8_t length;
+ unsigned char *data;
+} dns_rdata_apl_ent_t;
+
+typedef struct dns_rdata_in_apl {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ /* type & class specific elements */
+ unsigned char *apl;
+ isc_uint16_t apl_len;
+ /* private */
+ isc_uint16_t offset;
+} dns_rdata_in_apl_t;
+
+/*
+ * ISC_LANG_BEGINDECLS and ISC_LANG_ENDDECLS are already done
+ * via rdatastructpre.h and rdatastructsuf.h.
+ */
+
+isc_result_t
+dns_rdata_apl_first(dns_rdata_in_apl_t *);
+
+isc_result_t
+dns_rdata_apl_next(dns_rdata_in_apl_t *);
+
+isc_result_t
+dns_rdata_apl_current(dns_rdata_in_apl_t *, dns_rdata_apl_ent_t *);
+
+#endif /* IN_1_APL_42_H */
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2002 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.
+ */
+
+/* $Id: ds_43.h,v 1.3.2.1 2004/03/08 02:08:03 marka Exp $ */
+
+/* draft-ietf-dnsext-delegation-signer-05.txt */
+#ifndef GENERIC_DS_43_H
+#define GENERIC_DS_43_H 1
+
+typedef struct dns_rdata_ds {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ isc_uint16_t key_tag;
+ isc_uint8_t algorithm;
+ isc_uint8_t digest_type;
+ isc_uint16_t length;
+ unsigned char *digest;
+} dns_rdata_ds_t;
+
+#endif /* GENERIC_DS_43_H */
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2003 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.
+ */
+
+/* $Id: sshfp_44.h,v 1.1.8.2 2004/03/06 08:14:13 marka Exp $ */
+
+/* draft-ietf-secsh-dns-05.txt */
+
+#ifndef GENERIC_SSHFP_44_H
+#define GENERIC_SSHFP_44_H 1
+
+typedef struct dns_rdata_sshfp {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ isc_uint8_t algorithm;
+ isc_uint8_t digest_type;
+ isc_uint16_t length;
+ unsigned char *digest;
+} dns_rdata_sshfp_t;
+
+#endif /* GENERIC_SSHFP_44_H */
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2003 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 GENERIC_DNSSIG_46_H
+#define GENERIC_DNSSIG_46_H 1
+
+/* $Id: rrsig_46.h,v 1.3.2.1 2004/03/08 02:08:04 marka Exp $ */
+
+/* RFC 2535 */
+typedef struct dns_rdata_rrsig {
+ dns_rdatacommon_t common;
+ isc_mem_t * mctx;
+ dns_rdatatype_t covered;
+ dns_secalg_t algorithm;
+ isc_uint8_t labels;
+ isc_uint32_t originalttl;
+ isc_uint32_t timeexpire;
+ isc_uint32_t timesigned;
+ isc_uint16_t keyid;
+ dns_name_t signer;
+ isc_uint16_t siglen;
+ unsigned char * signature;
+} dns_rdata_rrsig_t;
+
+
+#endif /* GENERIC_DNSSIG_46_H */
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2003 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 GENERIC_NSEC_47_H
+#define GENERIC_NSEC_47_H 1
+
+/* $Id: nsec_47.h,v 1.4.2.1 2004/03/08 02:08:03 marka Exp $ */
+
+/* draft-ietf-dnsext-nsec-rdata-01.txt */
+
+typedef struct dns_rdata_nsec {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ dns_name_t next;
+ unsigned char *typebits;
+ isc_uint16_t len;
+} dns_rdata_nsec_t;
+
+#endif /* GENERIC_NSEC_47_H */
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2003 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 GENERIC_DNSKEY_48_H
+#define GENERIC_DNSKEY_48_H 1
+
+/* $Id: dnskey_48.h,v 1.3.2.1 2004/03/08 02:08:02 marka Exp $ */
+
+/* RFC 2535 */
+
+typedef struct dns_rdata_dnskey {
+ dns_rdatacommon_t common;
+ isc_mem_t * mctx;
+ isc_uint16_t flags;
+ isc_uint8_t protocol;
+ isc_uint8_t algorithm;
+ isc_uint16_t datalen;
+ unsigned char * data;
+} dns_rdata_dnskey_t;
+
+
+#endif /* GENERIC_DNSKEY_48_H */
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-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.
+ */
+
+#ifndef GENERIC_UNSPEC_103_H
+#define GENERIC_UNSPEC_103_H 1
+
+/* $Id: unspec_103.h,v 1.12.206.1 2004/03/06 08:14:14 marka Exp $ */
+
+typedef struct dns_rdata_unspec_t {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ unsigned char *data;
+ isc_uint16_t datalen;
+} dns_rdata_unspec_t;
+
+#endif /* GENERIC_UNSPEC_103_H */
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2001, 2003 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 GENERIC_TKEY_249_H
+#define GENERIC_TKEY_249_H 1
+
+/* $Id: tkey_249.h,v 1.18.206.2 2004/03/06 08:14:13 marka Exp $ */
+
+/* draft-ietf-dnsind-tkey-00.txt */
+
+typedef struct dns_rdata_tkey {
+ dns_rdatacommon_t common;
+ isc_mem_t * mctx;
+ dns_name_t algorithm;
+ isc_uint32_t inception;
+ isc_uint32_t expire;
+ isc_uint16_t mode;
+ isc_uint16_t error;
+ isc_uint16_t keylen;
+ unsigned char * key;
+ isc_uint16_t otherlen;
+ unsigned char * other;
+} dns_rdata_tkey_t;
+
+
+#endif /* GENERIC_TKEY_249_H */
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-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.
+ */
+
+/* $Id: tsig_250.h,v 1.20.206.1 2004/03/06 08:14:02 marka Exp $ */
+
+/* RFC 2845 */
+
+#ifndef ANY_255_TSIG_250_H
+#define ANY_255_TSIG_250_H 1
+
+typedef struct dns_rdata_any_tsig {
+ dns_rdatacommon_t common;
+ isc_mem_t * mctx;
+ dns_name_t algorithm;
+ isc_uint64_t timesigned;
+ isc_uint16_t fudge;
+ isc_uint16_t siglen;
+ unsigned char * signature;
+ isc_uint16_t originalid;
+ isc_uint16_t error;
+ isc_uint16_t otherlen;
+ unsigned char * other;
+} dns_rdata_any_tsig_t;
+
+#endif /* ANY_255_TSIG_250_H */
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * 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.
+ */
+
+/* $Id: dlv_65323.h,v 1.2.2.3 2004/03/15 01:02:55 marka Exp $ */
+
+/* draft-ietf-dnsext-delegation-signer-05.txt */
+#ifndef GENERIC_DLV_65323_H
+#define GENERIC_DLV_65323_H 1
+
+typedef struct dns_rdata_dlv {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ isc_uint16_t key_tag;
+ isc_uint8_t algorithm;
+ isc_uint8_t digest_type;
+ isc_uint16_t length;
+ unsigned char *digest;
+} dns_rdata_dlv_t;
+
+#endif /* GENERIC_DLV_65323_H */
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-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.
+ */
+
+/* $Id: rdatastructsuf.h,v 1.7.206.1 2004/03/06 08:14:02 marka Exp $ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_RDATASTRUCT_H */
diff --git a/lib/bind/isc/Makefile b/lib/bind/isc/Makefile
new file mode 100644
index 0000000..0fd8342
--- /dev/null
+++ b/lib/bind/isc/Makefile
@@ -0,0 +1,126 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+BIND_DIR= ${.CURDIR}/../../../contrib/bind9
+LIB_BIND_REL= ..
+LIB_BIND_DIR= ${.CURDIR}/${LIB_BIND_REL}
+SRCDIR= ${BIND_DIR}/lib/isc
+
+.include "${LIB_BIND_DIR}/config.mk"
+
+LIB= isc
+
+.PATH: ${SRCDIR}/unix
+SRCS+= app.c dir.c entropy.c \
+ errno2result.c file.c fsaccess.c \
+ interfaceiter.c keyboard.c net.c \
+ os.c resource.c socket.c stdio.c \
+ stdtime.c strerror.c syslog.c time.c \
+
+.PATH: ${SRCDIR}/nls
+SRCS+= msgcat.c \
+
+.PATH: ${SRCDIR}/nothreads
+SRCS+= condition.c mutex.c \
+ thread.c
+
+.PATH: ${SRCDIR}
+SRCS+= inet_pton.c \
+ assertions.c base64.c bitstring.c buffer.c \
+ bufferlist.c commandline.c error.c event.c \
+ hash.c heap.c hex.c hmacmd5.c \
+ lex.c lfsr.c lib.c log.c md5.c \
+ mem.c mutexblock.c netaddr.c netscope.c ondestroy.c \
+ parseint.c print.c quota.c random.c \
+ ratelimiter.c region.c result.c rwlock.c \
+ serial.c sha1.c sockaddr.c string.c strtoul.c \
+ symtab.c task.c taskpool.c timer.c version.c
+
+CFLAGS+= -I${SRCDIR}/unix/include -I${SRCDIR}/nothreads/include
+CFLAGS+= -I${SRCDIR}/include -I${.CURDIR}
+
+.if ${MK_BIND_LIBS} != "no"
+INCS= ${SRCDIR}/include/isc/app.h \
+ ${SRCDIR}/include/isc/assertions.h \
+ ${SRCDIR}/include/isc/base64.h \
+ ${SRCDIR}/include/isc/bitstring.h \
+ ${SRCDIR}/include/isc/boolean.h \
+ ${SRCDIR}/include/isc/buffer.h \
+ ${SRCDIR}/include/isc/bufferlist.h \
+ ${SRCDIR}/include/isc/commandline.h \
+ ${SRCDIR}/include/isc/entropy.h \
+ ${SRCDIR}/include/isc/error.h \
+ ${SRCDIR}/include/isc/event.h \
+ ${SRCDIR}/include/isc/eventclass.h \
+ ${SRCDIR}/include/isc/file.h \
+ ${SRCDIR}/include/isc/formatcheck.h \
+ ${SRCDIR}/include/isc/fsaccess.h \
+ ${SRCDIR}/include/isc/hash.h \
+ ${SRCDIR}/include/isc/heap.h \
+ ${SRCDIR}/include/isc/hex.h \
+ ${SRCDIR}/include/isc/hmacmd5.h \
+ ${SRCDIR}/include/isc/interfaceiter.h \
+ ${SRCDIR}/include/isc/ipv6.h \
+ ${SRCDIR}/include/isc/lang.h \
+ ${SRCDIR}/include/isc/lex.h \
+ ${SRCDIR}/include/isc/lfsr.h \
+ ${SRCDIR}/include/isc/lib.h \
+ ${SRCDIR}/include/isc/list.h \
+ ${SRCDIR}/include/isc/log.h \
+ ${SRCDIR}/include/isc/magic.h \
+ ${SRCDIR}/include/isc/md5.h \
+ ${SRCDIR}/include/isc/mem.h \
+ ${SRCDIR}/include/isc/msgcat.h \
+ ${SRCDIR}/include/isc/msgs.h \
+ ${SRCDIR}/include/isc/mutexblock.h \
+ ${SRCDIR}/include/isc/netaddr.h \
+ ${SRCDIR}/include/isc/netscope.h \
+ ${SRCDIR}/include/isc/ondestroy.h \
+ ${SRCDIR}/include/isc/os.h \
+ ${SRCDIR}/include/isc/parseint.h \
+ ${SRCDIR}/include/isc/print.h \
+ ${SRCDIR}/include/isc/quota.h \
+ ${SRCDIR}/include/isc/random.h \
+ ${SRCDIR}/include/isc/ratelimiter.h \
+ ${SRCDIR}/include/isc/refcount.h \
+ ${SRCDIR}/include/isc/region.h \
+ ${SRCDIR}/include/isc/resource.h \
+ ${SRCDIR}/include/isc/result.h \
+ ${SRCDIR}/include/isc/resultclass.h \
+ ${SRCDIR}/include/isc/rwlock.h \
+ ${SRCDIR}/include/isc/serial.h \
+ ${SRCDIR}/include/isc/sha1.h \
+ ${SRCDIR}/include/isc/sockaddr.h \
+ ${SRCDIR}/include/isc/socket.h \
+ ${SRCDIR}/include/isc/stdio.h \
+ ${SRCDIR}/include/isc/stdlib.h \
+ ${SRCDIR}/include/isc/string.h \
+ ${SRCDIR}/include/isc/symtab.h \
+ ${SRCDIR}/include/isc/task.h \
+ ${SRCDIR}/include/isc/taskpool.h \
+ ${SRCDIR}/include/isc/timer.h \
+ ${SRCDIR}/include/isc/types.h \
+ ${SRCDIR}/include/isc/util.h \
+ ${SRCDIR}/include/isc/version.h \
+ ${SRCDIR}/nothreads/include/isc/condition.h \
+ ${SRCDIR}/nothreads/include/isc/mutex.h \
+ ${SRCDIR}/nothreads/include/isc/once.h \
+ ${SRCDIR}/nothreads/include/isc/thread.h \
+ ${SRCDIR}/unix/include/isc/dir.h \
+ ${SRCDIR}/unix/include/isc/int.h \
+ ${SRCDIR}/unix/include/isc/keyboard.h \
+ ${SRCDIR}/unix/include/isc/net.h \
+ ${SRCDIR}/unix/include/isc/netdb.h \
+ ${SRCDIR}/unix/include/isc/offset.h \
+ ${SRCDIR}/unix/include/isc/stat.h \
+ ${SRCDIR}/unix/include/isc/stdtime.h \
+ ${SRCDIR}/unix/include/isc/strerror.h \
+ ${SRCDIR}/unix/include/isc/syslog.h \
+ ${SRCDIR}/unix/include/isc/time.h \
+ isc/platform.h
+
+INCSDIR= ${INCLUDEDIR}/isc
+.endif
+
+.include <bsd.lib.mk>
diff --git a/lib/bind/isc/isc/platform.h b/lib/bind/isc/isc/platform.h
new file mode 100644
index 0000000..ae1cdc2
--- /dev/null
+++ b/lib/bind/isc/isc/platform.h
@@ -0,0 +1,257 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2003 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.
+ */
+
+/* $Id: platform.h.in,v 1.24.2.1.10.11 2004/03/08 09:04:52 marka Exp $ */
+
+#ifndef ISC_PLATFORM_H
+#define ISC_PLATFORM_H 1
+
+/*****
+ ***** Platform-dependent defines.
+ *****/
+
+/***
+ *** Network.
+ ***/
+
+/*
+ * Define if this system needs the <netinet/in6.h> header file included
+ * for full IPv6 support (pretty much only UnixWare).
+ */
+#undef ISC_PLATFORM_NEEDNETINETIN6H
+
+/*
+ * Define if this system needs the <netinet6/in6.h> header file included
+ * to support in6_pkinfo (pretty much only BSD/OS).
+ */
+#undef ISC_PLATFORM_NEEDNETINET6IN6H
+
+/*
+ * If sockaddrs on this system have an sa_len field, ISC_PLATFORM_HAVESALEN
+ * will be defined.
+ */
+#define ISC_PLATFORM_HAVESALEN 1
+
+/*
+ * If this system has the IPv6 structure definitions, ISC_PLATFORM_HAVEIPV6
+ * will be defined.
+ */
+#define ISC_PLATFORM_HAVEIPV6 1
+
+/*
+ * If this system is missing in6addr_any, ISC_PLATFORM_NEEDIN6ADDRANY will
+ * be defined.
+ */
+#undef ISC_PLATFORM_NEEDIN6ADDRANY
+
+/*
+ * If this system is missing in6addr_loopback, ISC_PLATFORM_NEEDIN6ADDRLOOPBACK
+ * will be defined.
+ */
+#undef ISC_PLATFORM_NEEDIN6ADDRLOOPBACK
+
+/*
+ * If this system has in6_pktinfo, ISC_PLATFORM_HAVEIN6PKTINFO will be
+ * defined.
+ */
+#define ISC_PLATFORM_HAVEIN6PKTINFO 1
+
+/*
+ * If this system has in_addr6, rather than in6_addr, ISC_PLATFORM_HAVEINADDR6
+ * will be defined.
+ */
+#undef ISC_PLATFORM_HAVEINADDR6
+
+/*
+ * If this system has sin6_scope_id, ISC_PLATFORM_HAVESCOPEID will be defined.
+ */
+#define ISC_PLATFORM_HAVESCOPEID 1
+
+/*
+ * If this system needs inet_ntop(), ISC_PLATFORM_NEEDNTOP will be defined.
+ */
+#undef ISC_PLATFORM_NEEDNTOP
+
+/*
+ * If this system needs inet_pton(), ISC_PLATFORM_NEEDPTON will be defined.
+ */
+#undef ISC_PLATFORM_NEEDPTON
+
+/*
+ * If this system needs inet_aton(), ISC_PLATFORM_NEEDATON will be defined.
+ */
+#undef ISC_PLATFORM_NEEDATON
+
+/*
+ * If this system needs in_port_t, ISC_PLATFORM_NEEDPORTT will be defined.
+ */
+#undef ISC_PLATFORM_NEEDPORTT
+
+/*
+ * If the system needs strsep(), ISC_PLATFORM_NEEDSTRSEP will be defined.
+ */
+#undef ISC_PLATFORM_NEEDSTRSEP
+
+/*
+ * If the system needs strlcpy(), ISC_PLATFORM_NEEDSTRLCPY will be defined.
+ */
+#undef ISC_PLATFORM_NEEDSTRLCPY
+
+/*
+ * If the system needs strlcat(), ISC_PLATFORM_NEEDSTRLCAT will be defined.
+ */
+#undef ISC_PLATFORM_NEEDSTRLCAT
+
+/*
+ * Define either ISC_PLATFORM_BSD44MSGHDR or ISC_PLATFORM_BSD43MSGHDR.
+ */
+#define ISC_NET_BSD44MSGHDR 1
+
+/*
+ * Define if PTHREAD_ONCE_INIT should be surrounded by braces to
+ * prevent compiler warnings (such as with gcc on Solaris 2.8).
+ */
+#undef ISC_PLATFORM_BRACEPTHREADONCEINIT
+
+/*
+ * Define on some UnixWare systems to fix erroneous definitions of various
+ * IN6_IS_ADDR_* macros.
+ */
+#undef ISC_PLATFORM_FIXIN6ISADDR
+
+/***
+ *** Printing.
+ ***/
+
+/*
+ * If this system needs vsnprintf() and snprintf(), ISC_PLATFORM_NEEDVSNPRINTF
+ * will be defined.
+ */
+#undef ISC_PLATFORM_NEEDVSNPRINTF
+
+/*
+ * If this system need a modern sprintf() that returns (int) not (char*).
+ */
+#undef ISC_PLATFORM_NEEDSPRINTF
+
+/*
+ * The printf format string modifier to use with isc_uint64_t values.
+ */
+#define ISC_PLATFORM_QUADFORMAT "ll"
+
+/*
+ * Defined if we are using threads.
+ */
+#undef ISC_PLATFORM_USETHREADS
+
+/*
+ * Defined if unistd.h does not cause fd_set to be delared.
+ */
+#undef ISC_PLATFORM_NEEDSYSSELECTH
+
+/*
+ * Type used for resource limits.
+ */
+#define ISC_PLATFORM_RLIMITTYPE rlim_t
+
+/*
+ * Define if your compiler supports "long long int".
+ */
+#define ISC_PLATFORM_HAVELONGLONG 1
+
+/*
+ * Define if the system has struct lifconf which is a extended struct ifconf
+ * for IPv6.
+ */
+#undef ISC_PLATFORM_HAVELIFCONF
+
+/*
+ * Define if the system has struct if_laddrconf which is a extended struct
+ * ifconf for IPv6.
+ */
+#undef ISC_PLATFORM_HAVEIF_LADDRCONF
+
+/*
+ * Define if the system has struct if_laddrreq.
+ */
+#undef ISC_PLATFORM_HAVEIF_LADDRREQ
+
+/*
+ * Used to control how extern data is linked; needed for Win32 platforms.
+ */
+#undef ISC_PLATFORM_USEDECLSPEC
+
+/*
+ * Define if the system supports if_nametoindex.
+ */
+#define ISC_PLATFORM_HAVEIFNAMETOINDEX 1
+
+/*
+ * Define if this system needs strtoul.
+ */
+#undef ISC_PLATFORM_NEEDSTRTOUL
+
+/*
+ * Define if this system needs memmove.
+ */
+#undef ISC_PLATFORM_NEEDMEMMOVE
+
+#ifndef ISC_PLATFORM_USEDECLSPEC
+#define LIBISC_EXTERNAL_DATA
+#define LIBDNS_EXTERNAL_DATA
+#define LIBISCCC_EXTERNAL_DATA
+#define LIBISCCFG_EXTERNAL_DATA
+#define LIBBIND9_EXTERNAL_DATA
+#else /* ISC_PLATFORM_USEDECLSPEC */
+#ifdef LIBISC_EXPORTS
+#define LIBISC_EXTERNAL_DATA __declspec(dllexport)
+#else
+#define LIBISC_EXTERNAL_DATA __declspec(dllimport)
+#endif
+#ifdef LIBDNS_EXPORTS
+#define LIBDNS_EXTERNAL_DATA __declspec(dllexport)
+#else
+#define LIBDNS_EXTERNAL_DATA __declspec(dllimport)
+#endif
+#ifdef LIBISCCC_EXPORTS
+#define LIBISCCC_EXTERNAL_DATA __declspec(dllexport)
+#else
+#define LIBISCCC_EXTERNAL_DATA __declspec(dllimport)
+#endif
+#ifdef LIBISCCFG_EXPORTS
+#define LIBISCCFG_EXTERNAL_DATA __declspec(dllexport)
+#else
+#define LIBISCCFG_EXTERNAL_DATA __declspec(dllimport)
+#endif
+#ifdef LIBBIND9_EXPORTS
+#define LIBBIND9_EXTERNAL_DATA __declspec(dllexport)
+#else
+#define LIBBIND9_EXTERNAL_DATA __declspec(dllimport)
+#endif
+#endif /* ISC_PLATFORM_USEDECLSPEC */
+
+/*
+ * Tell emacs to use C mode for this file.
+ *
+ * Local Variables:
+ * mode: c
+ * End:
+ */
+
+#endif /* ISC_PLATFORM_H */
diff --git a/lib/bind/isccc/Makefile b/lib/bind/isccc/Makefile
new file mode 100644
index 0000000..84e1ba8
--- /dev/null
+++ b/lib/bind/isccc/Makefile
@@ -0,0 +1,39 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+BIND_DIR= ${.CURDIR}/../../../contrib/bind9
+LIB_BIND_REL= ..
+LIB_BIND_DIR= ${.CURDIR}/${LIB_BIND_REL}
+SRCDIR= ${BIND_DIR}/lib/isccc
+
+.include "${LIB_BIND_DIR}/config.mk"
+
+LIB= isccc
+
+.PATH: ${SRCDIR}
+SRCS= alist.c base64.c cc.c ccmsg.c \
+ lib.c \
+ result.c sexpr.c symtab.c version.c
+
+CFLAGS+= -I${SRCDIR}/include
+
+.if ${MK_BIND_LIBS} != "no"
+INCS= ${SRCDIR}/include/isccc/alist.h \
+ ${SRCDIR}/include/isccc/base64.h \
+ ${SRCDIR}/include/isccc/cc.h \
+ ${SRCDIR}/include/isccc/ccmsg.h \
+ ${SRCDIR}/include/isccc/events.h \
+ ${SRCDIR}/include/isccc/lib.h \
+ ${SRCDIR}/include/isccc/result.h \
+ ${SRCDIR}/include/isccc/sexpr.h \
+ ${SRCDIR}/include/isccc/symtab.h \
+ ${SRCDIR}/include/isccc/symtype.h \
+ ${SRCDIR}/include/isccc/types.h \
+ ${SRCDIR}/include/isccc/util.h \
+ ${SRCDIR}/include/isccc/version.h
+
+INCSDIR= ${INCLUDEDIR}/isccc
+.endif
+
+.include <bsd.lib.mk>
diff --git a/lib/bind/isccfg/Makefile b/lib/bind/isccfg/Makefile
new file mode 100644
index 0000000..6c2309c
--- /dev/null
+++ b/lib/bind/isccfg/Makefile
@@ -0,0 +1,29 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+BIND_DIR= ${.CURDIR}/../../../contrib/bind9
+LIB_BIND_REL= ..
+LIB_BIND_DIR= ${.CURDIR}/${LIB_BIND_REL}
+SRCDIR= ${BIND_DIR}/lib/isccfg
+
+.include "${LIB_BIND_DIR}/config.mk"
+
+LIB= isccfg
+
+.PATH: ${SRCDIR}
+SRCS= log.c namedconf.c parser.c version.c
+
+CFLAGS+= -I${SRCDIR}/include -I${.CURDIR}
+
+.if ${MK_BIND_LIBS} != "no"
+INCS= ${SRCDIR}/include/isccfg/cfg.h \
+ ${SRCDIR}/include/isccfg/grammar.h \
+ ${SRCDIR}/include/isccfg/log.h \
+ ${SRCDIR}/include/isccfg/namedconf.h \
+ ${SRCDIR}/include/isccfg/version.h
+
+INCSDIR= ${INCLUDEDIR}/isccfg
+.endif
+
+.include <bsd.lib.mk>
diff --git a/lib/bind/lwres/Makefile b/lib/bind/lwres/Makefile
new file mode 100644
index 0000000..eef4589
--- /dev/null
+++ b/lib/bind/lwres/Makefile
@@ -0,0 +1,122 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+BIND_DIR= ${.CURDIR}/../../../contrib/bind9
+LIB_BIND_REL= ..
+LIB_BIND_DIR= ${.CURDIR}/${LIB_BIND_REL}
+SRCDIR= ${BIND_DIR}/lib/lwres
+
+# Unlike other BIND libs, this should be installed unless the user says NO.
+.if ${MK_BIND_LIBS_LWRES} != "no"
+MK_BIND_LIBS= yes
+.endif
+
+.include "${LIB_BIND_DIR}/config.mk"
+
+LIB= lwres
+
+.PATH: ${SRCDIR} ${SRCDIR}/man
+SRCS+= context.c gai_strerror.c getaddrinfo.c gethost.c \
+ getipnode.c getnameinfo.c getrrset.c herror.c \
+ lwbuffer.c lwconfig.c lwpacket.c lwresutil.c \
+ lwres_gabn.c lwres_gnba.c lwres_grbn.c lwres_noop.c \
+ lwinetaton.c lwinetpton.c lwinetntop.c print.c
+
+CFLAGS+= -I${SRCDIR}/unix/include -I${SRCDIR}/include
+CFLAGS+= -I${.CURDIR}
+
+.if ${MK_BIND_LIBS} != "no"
+MAN= lwres.3 lwres_buffer.3 lwres_config.3 lwres_context.3 \
+ lwres_gabn.3 lwres_gai_strerror.3 lwres_getaddrinfo.3 \
+ lwres_gethostent.3 lwres_getipnode.3 lwres_getnameinfo.3 \
+ lwres_getrrsetbyname.3 lwres_gnba.3 lwres_hstrerror.3 \
+ lwres_inetntop.3 lwres_noop.3 lwres_packet.3 lwres_resutil.3
+
+MLINKS= lwres_buffer.3 lwres_buffer_add.3 \
+ lwres_buffer.3 lwres_buffer_back.3 \
+ lwres_buffer.3 lwres_buffer_clear.3 \
+ lwres_buffer.3 lwres_buffer_first.3 \
+ lwres_buffer.3 lwres_buffer_forward.3 \
+ lwres_buffer.3 lwres_buffer_getmem.3 \
+ lwres_buffer.3 lwres_buffer_getuint16.3 \
+ lwres_buffer.3 lwres_buffer_getuint32.3 \
+ lwres_buffer.3 lwres_buffer_getuint8.3 \
+ lwres_buffer.3 lwres_buffer_init.3 \
+ lwres_buffer.3 lwres_buffer_invalidate.3 \
+ lwres_buffer.3 lwres_buffer_putmem.3 \
+ lwres_buffer.3 lwres_buffer_putuint16.3 \
+ lwres_buffer.3 lwres_buffer_putuint32.3 \
+ lwres_buffer.3 lwres_buffer_putuint8.3 \
+ lwres_buffer.3 lwres_buffer_subtract.3 \
+ lwres_config.3 lwres_conf_clear.3 \
+ lwres_config.3 lwres_conf_get.3 \
+ lwres_config.3 lwres_conf_init.3 \
+ lwres_config.3 lwres_conf_parse.3 \
+ lwres_config.3 lwres_conf_print.3 \
+ lwres_context.3 lwres_context_allocmem.3 \
+ lwres_context.3 lwres_context_create.3 \
+ lwres_context.3 lwres_context_destroy.3 \
+ lwres_context.3 lwres_context_freemem.3 \
+ lwres_context.3 lwres_context_initserial.3 \
+ lwres_context.3 lwres_context_nextserial.3 \
+ lwres_context.3 lwres_context_sendrecv.3 \
+ lwres_gabn.3 lwres_gabnrequest_free.3 \
+ lwres_gabn.3 lwres_gabnrequest_parse.3 \
+ lwres_gabn.3 lwres_gabnrequest_render.3 \
+ lwres_gabn.3 lwres_gabnresponse_free.3 \
+ lwres_gabn.3 lwres_gabnresponse_parse.3 \
+ lwres_gabn.3 lwres_gabnresponse_render.3 \
+ lwres_getaddrinfo.3 lwres_freeaddrinfo.3 \
+ lwres_gethostent.3 lwres_endhostent.3 \
+ lwres_gethostent.3 lwres_endhostent_r.3 \
+ lwres_gethostent.3 lwres_gethostbyaddr.3 \
+ lwres_gethostent.3 lwres_gethostbyaddr_r.3 \
+ lwres_gethostent.3 lwres_gethostbyname.3 \
+ lwres_gethostent.3 lwres_gethostbyname2.3 \
+ lwres_gethostent.3 lwres_gethostbyname_r.3 \
+ lwres_gethostent.3 lwres_gethostent_r.3 \
+ lwres_gethostent.3 lwres_sethostent.3 \
+ lwres_gethostent.3 lwres_sethostent_r.3 \
+ lwres_getipnode.3 lwres_freehostent.3 \
+ lwres_getipnode.3 lwres_getipnodebyaddr.3 \
+ lwres_getipnode.3 lwres_getipnodebyname.3 \
+ lwres_gnba.3 lwres_gnbarequest_free.3 \
+ lwres_gnba.3 lwres_gnbarequest_parse.3 \
+ lwres_gnba.3 lwres_gnbarequest_render.3 \
+ lwres_gnba.3 lwres_gnbaresponse_free.3 \
+ lwres_gnba.3 lwres_gnbaresponse_parse.3 \
+ lwres_gnba.3 lwres_gnbaresponse_render.3 \
+ lwres_hstrerror.3 lwres_herror.3 \
+ lwres_inetntop.3 lwres_net_ntop.3 \
+ lwres_noop.3 lwres_nooprequest_free.3 \
+ lwres_noop.3 lwres_nooprequest_parse.3 \
+ lwres_noop.3 lwres_nooprequest_render.3 \
+ lwres_noop.3 lwres_noopresponse_free.3 \
+ lwres_noop.3 lwres_noopresponse_parse.3 \
+ lwres_noop.3 lwres_noopresponse_render.3 \
+ lwres_packet.3 lwres_lwpacket_parseheader.3 \
+ lwres_packet.3 lwres_lwpacket_renderheader.3 \
+ lwres_resutil.3 lwres_addr_parse.3 \
+ lwres_resutil.3 lwres_getaddrsbyname.3 \
+ lwres_resutil.3 lwres_getnamebyaddr.3 \
+ lwres_resutil.3 lwres_string_parse.3
+
+INCS= ${SRCDIR}/include/lwres/context.h \
+ ${SRCDIR}/include/lwres/int.h \
+ ${SRCDIR}/include/lwres/ipv6.h \
+ ${SRCDIR}/include/lwres/lang.h \
+ ${SRCDIR}/include/lwres/list.h \
+ ${SRCDIR}/include/lwres/lwbuffer.h \
+ ${SRCDIR}/include/lwres/lwpacket.h \
+ ${SRCDIR}/include/lwres/lwres.h \
+ ${SRCDIR}/include/lwres/result.h \
+ ${SRCDIR}/include/lwres/version.h \
+ ${SRCDIR}/unix/include/lwres/net.h \
+ lwres/netdb.h \
+ lwres/platform.h
+
+INCSDIR= ${INCLUDEDIR}/lwres
+.endif
+
+.include <bsd.lib.mk>
diff --git a/lib/bind/lwres/lwres/netdb.h b/lib/bind/lwres/lwres/netdb.h
new file mode 100644
index 0000000..0746e14
--- /dev/null
+++ b/lib/bind/lwres/lwres/netdb.h
@@ -0,0 +1,520 @@
+/* $FreeBSD$ */
+
+/*
+ * 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.
+ */
+
+/* $Id: netdb.h.in,v 1.34.206.1 2004/03/06 08:15:35 marka Exp $ */
+
+#ifndef LWRES_NETDB_H
+#define LWRES_NETDB_H 1
+
+#include <stddef.h> /* Required on FreeBSD (and others?) for size_t. */
+#include <netdb.h> /* Contractual provision. */
+
+#include <lwres/lang.h>
+
+/*
+ * Define if <netdb.h> does not declare struct addrinfo.
+ */
+#undef ISC_LWRES_NEEDADDRINFO
+
+#ifdef ISC_LWRES_NEEDADDRINFO
+struct addrinfo {
+ int ai_flags; /* AI_PASSIVE, AI_CANONNAME */
+ int ai_family; /* PF_xxx */
+ int ai_socktype; /* SOCK_xxx */
+ int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
+ size_t ai_addrlen; /* Length of ai_addr */
+ char *ai_canonname; /* Canonical name for hostname */
+ struct sockaddr *ai_addr; /* Binary address */
+ struct addrinfo *ai_next; /* Next structure in linked list */
+};
+#endif
+
+/*
+ * Undefine all #defines we are interested in as <netdb.h> may or may not have
+ * defined them.
+ */
+
+/*
+ * Error return codes from gethostbyname() and gethostbyaddr()
+ * (left in extern int h_errno).
+ */
+
+#undef NETDB_INTERNAL
+#undef NETDB_SUCCESS
+#undef HOST_NOT_FOUND
+#undef TRY_AGAIN
+#undef NO_RECOVERY
+#undef NO_DATA
+#undef NO_ADDRESS
+
+#define NETDB_INTERNAL -1 /* see errno */
+#define NETDB_SUCCESS 0 /* no problem */
+#define HOST_NOT_FOUND 1 /* Authoritative Answer Host not found */
+#define TRY_AGAIN 2 /* Non-Authoritive Host not found, or SERVERFAIL */
+#define NO_RECOVERY 3 /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */
+#define NO_DATA 4 /* Valid name, no data record of requested type */
+#define NO_ADDRESS NO_DATA /* no address, look for MX record */
+
+/*
+ * Error return codes from getaddrinfo()
+ */
+
+#undef EAI_ADDRFAMILY
+#undef EAI_AGAIN
+#undef EAI_BADFLAGS
+#undef EAI_FAIL
+#undef EAI_FAMILY
+#undef EAI_MEMORY
+#undef EAI_NODATA
+#undef EAI_NONAME
+#undef EAI_SERVICE
+#undef EAI_SOCKTYPE
+#undef EAI_SYSTEM
+#undef EAI_BADHINTS
+#undef EAI_PROTOCOL
+#undef EAI_MAX
+
+#define EAI_ADDRFAMILY 1 /* address family for hostname not supported */
+#define EAI_AGAIN 2 /* temporary failure in name resolution */
+#define EAI_BADFLAGS 3 /* invalid value for ai_flags */
+#define EAI_FAIL 4 /* non-recoverable failure in name resolution */
+#define EAI_FAMILY 5 /* ai_family not supported */
+#define EAI_MEMORY 6 /* memory allocation failure */
+#define EAI_NODATA 7 /* no address associated with hostname */
+#define EAI_NONAME 8 /* hostname nor servname provided, or not known */
+#define EAI_SERVICE 9 /* servname not supported for ai_socktype */
+#define EAI_SOCKTYPE 10 /* ai_socktype not supported */
+#define EAI_SYSTEM 11 /* system error returned in errno */
+#define EAI_BADHINTS 12
+#define EAI_PROTOCOL 13
+#define EAI_MAX 14
+
+/*
+ * Flag values for getaddrinfo()
+ */
+#undef AI_PASSIVE
+#undef AI_CANONNAME
+#undef AI_NUMERICHOST
+
+#define AI_PASSIVE 0x00000001
+#define AI_CANONNAME 0x00000002
+#define AI_NUMERICHOST 0x00000004
+
+/*
+ * Flag values for getipnodebyname()
+ */
+#undef AI_V4MAPPED
+#undef AI_ALL
+#undef AI_ADDRCONFIG
+#undef AI_DEFAULT
+
+#define AI_V4MAPPED 0x00000008
+#define AI_ALL 0x00000010
+#define AI_ADDRCONFIG 0x00000020
+#define AI_DEFAULT (AI_V4MAPPED|AI_ADDRCONFIG)
+
+/*
+ * Constants for lwres_getnameinfo()
+ */
+#undef NI_MAXHOST
+#undef NI_MAXSERV
+
+#define NI_MAXHOST 1025
+#define NI_MAXSERV 32
+
+/*
+ * Flag values for lwres_getnameinfo()
+ */
+#undef NI_NOFQDN
+#undef NI_NUMERICHOST
+#undef NI_NAMEREQD
+#undef NI_NUMERICSERV
+#undef NI_DGRAM
+#undef NI_NUMERICSCOPE
+
+#define NI_NOFQDN 0x00000001
+#define NI_NUMERICHOST 0x00000002
+#define NI_NAMEREQD 0x00000004
+#define NI_NUMERICSERV 0x00000008
+#define NI_DGRAM 0x00000010
+#define NI_NUMERICSCOPE 0x00000020 /*2553bis-00*/
+
+/*
+ * Define if <netdb.h> does not declare struct rrsetinfo.
+ */
+#define ISC_LWRES_NEEDRRSETINFO 1
+
+#ifdef ISC_LWRES_NEEDRRSETINFO
+/*
+ * Structures for getrrsetbyname()
+ */
+struct rdatainfo {
+ unsigned int rdi_length;
+ unsigned char *rdi_data;
+};
+
+struct rrsetinfo {
+ unsigned int rri_flags;
+ int rri_rdclass;
+ int rri_rdtype;
+ unsigned int rri_ttl;
+ unsigned int rri_nrdatas;
+ unsigned int rri_nsigs;
+ char *rri_name;
+ struct rdatainfo *rri_rdatas;
+ struct rdatainfo *rri_sigs;
+};
+
+/*
+ * Flags for getrrsetbyname()
+ */
+#define RRSET_VALIDATED 0x00000001
+ /* Set was dnssec validated */
+
+/*
+ * Return codes for getrrsetbyname()
+ */
+#define ERRSET_SUCCESS 0
+#define ERRSET_NOMEMORY 1
+#define ERRSET_FAIL 2
+#define ERRSET_INVAL 3
+#define ERRSET_NONAME 4
+#define ERRSET_NODATA 5
+#endif
+
+/*
+ * Define to map into lwres_ namespace.
+ */
+
+#define LWRES_NAMESPACE
+
+#ifdef LWRES_NAMESPACE
+
+/*
+ * Use our versions not the ones from the C library.
+ */
+
+#ifdef getnameinfo
+#undef getnameinfo
+#endif
+#define getnameinfo lwres_getnameinfo
+
+#ifdef getaddrinfo
+#undef getaddrinfo
+#endif
+#define getaddrinfo lwres_getaddrinfo
+
+#ifdef freeaddrinfo
+#undef freeaddrinfo
+#endif
+#define freeaddrinfo lwres_freeaddrinfo
+
+#ifdef gai_strerror
+#undef gai_strerror
+#endif
+#define gai_strerror lwres_gai_strerror
+
+#ifdef herror
+#undef herror
+#endif
+#define herror lwres_herror
+
+#ifdef hstrerror
+#undef hstrerror
+#endif
+#define hstrerror lwres_hstrerror
+
+#ifdef getipnodebyname
+#undef getipnodebyname
+#endif
+#define getipnodebyname lwres_getipnodebyname
+
+#ifdef getipnodebyaddr
+#undef getipnodebyaddr
+#endif
+#define getipnodebyaddr lwres_getipnodebyaddr
+
+#ifdef freehostent
+#undef freehostent
+#endif
+#define freehostent lwres_freehostent
+
+#ifdef gethostbyname
+#undef gethostbyname
+#endif
+#define gethostbyname lwres_gethostbyname
+
+#ifdef gethostbyname2
+#undef gethostbyname2
+#endif
+#define gethostbyname2 lwres_gethostbyname2
+
+#ifdef gethostbyaddr
+#undef gethostbyaddr
+#endif
+#define gethostbyaddr lwres_gethostbyaddr
+
+#ifdef gethostent
+#undef gethostent
+#endif
+#define gethostent lwres_gethostent
+
+#ifdef sethostent
+#undef sethostent
+#endif
+#define sethostent lwres_sethostent
+
+#ifdef endhostent
+#undef endhostent
+#endif
+#define endhostent lwres_endhostent
+
+/* #define sethostfile lwres_sethostfile */
+
+#ifdef gethostbyname_r
+#undef gethostbyname_r
+#endif
+#define gethostbyname_r lwres_gethostbyname_r
+
+#ifdef gethostbyaddr_r
+#undef gethostbyaddr_r
+#endif
+#define gethostbyaddr_r lwres_gethostbyaddr_r
+
+#ifdef gethostent_r
+#undef gethostent_r
+#endif
+#define gethostent_r lwres_gethostent_r
+
+#ifdef sethostent_r
+#undef sethostent_r
+#endif
+#define sethostent_r lwres_sethostent_r
+
+#ifdef endhostent_r
+#undef endhostent_r
+#endif
+#define endhostent_r lwres_endhostent_r
+
+#ifdef getrrsetbyname
+#undef getrrsetbyname
+#endif
+#define getrrsetbyname lwres_getrrsetbyname
+
+#ifdef freerrset
+#undef freerrset
+#endif
+#define freerrset lwres_freerrset
+
+#ifdef notyet
+#define getservbyname lwres_getservbyname
+#define getservbyport lwres_getservbyport
+#define getservent lwres_getservent
+#define setservent lwres_setservent
+#define endservent lwres_endservent
+
+#define getservbyname_r lwres_getservbyname_r
+#define getservbyport_r lwres_getservbyport_r
+#define getservent_r lwres_getservent_r
+#define setservent_r lwres_setservent_r
+#define endservent_r lwres_endservent_r
+
+#define getprotobyname lwres_getprotobyname
+#define getprotobynumber lwres_getprotobynumber
+#define getprotoent lwres_getprotoent
+#define setprotoent lwres_setprotoent
+#define endprotoent lwres_endprotoent
+
+#define getprotobyname_r lwres_getprotobyname_r
+#define getprotobynumber_r lwres_getprotobynumber_r
+#define getprotoent_r lwres_getprotoent_r
+#define setprotoent_r lwres_setprotoent_r
+#define endprotoent_r lwres_endprotoent_r
+
+#ifdef getnetbyname
+#undef getnetbyname
+#endif
+#define getnetbyname lwres_getnetbyname
+
+#ifdef getnetbyaddr
+#undef getnetbyaddr
+#endif
+#define getnetbyaddr lwres_getnetbyaddr
+
+#ifdef getnetent
+#undef getnetent
+#endif
+#define getnetent lwres_getnetent
+
+#ifdef setnetent
+#undef setnetent
+#endif
+#define setnetent lwres_setnetent
+
+#ifdef endnetent
+#undef endnetent
+#endif
+#define endnetent lwres_endnetent
+
+
+#ifdef getnetbyname_r
+#undef getnetbyname_r
+#endif
+#define getnetbyname_r lwres_getnetbyname_r
+
+#ifdef getnetbyaddr_r
+#undef getnetbyaddr_r
+#endif
+#define getnetbyaddr_r lwres_getnetbyaddr_r
+
+#ifdef getnetent_r
+#undef getnetent_r
+#endif
+#define getnetent_r lwres_getnetent_r
+
+#ifdef setnetent_r
+#undef setnetent_r
+#endif
+#define setnetent_r lwres_setnetent_r
+
+#ifdef endnetent_r
+#undef endnetent_r
+#endif
+#define endnetent_r lwres_endnetent_r
+#endif /* notyet */
+
+#ifdef h_errno
+#undef h_errno
+#endif
+#define h_errno lwres_h_errno
+
+#endif /* LWRES_NAMESPACE */
+
+LWRES_LANG_BEGINDECLS
+
+extern int lwres_h_errno;
+
+int lwres_getaddrinfo(const char *, const char *,
+ const struct addrinfo *, struct addrinfo **);
+int lwres_getnameinfo(const struct sockaddr *, size_t, char *,
+ size_t, char *, size_t, int);
+void lwres_freeaddrinfo(struct addrinfo *);
+char *lwres_gai_strerror(int);
+
+struct hostent *lwres_gethostbyaddr(const char *, int, int);
+struct hostent *lwres_gethostbyname(const char *);
+struct hostent *lwres_gethostbyname2(const char *, int);
+struct hostent *lwres_gethostent(void);
+struct hostent *lwres_getipnodebyname(const char *, int, int, int *);
+struct hostent *lwres_getipnodebyaddr(const void *, size_t, int, int *);
+void lwres_endhostent(void);
+void lwres_sethostent(int);
+/* void lwres_sethostfile(const char *); */
+void lwres_freehostent(struct hostent *);
+
+int lwres_getrrsetbyname(const char *, unsigned int, unsigned int,
+ unsigned int, struct rrsetinfo **);
+void lwres_freerrset(struct rrsetinfo *);
+
+#ifdef notyet
+struct netent *lwres_getnetbyaddr(unsigned long, int);
+struct netent *lwres_getnetbyname(const char *);
+struct netent *lwres_getnetent(void);
+void lwres_endnetent(void);
+void lwres_setnetent(int);
+
+struct protoent *lwres_getprotobyname(const char *);
+struct protoent *lwres_getprotobynumber(int);
+struct protoent *lwres_getprotoent(void);
+void lwres_endprotoent(void);
+void lwres_setprotoent(int);
+
+struct servent *lwres_getservbyname(const char *, const char *);
+struct servent *lwres_getservbyport(int, const char *);
+struct servent *lwres_getservent(void);
+void lwres_endservent(void);
+void lwres_setservent(int);
+#endif /* notyet */
+
+void lwres_herror(const char *);
+const char *lwres_hstrerror(int);
+
+
+struct hostent *lwres_gethostbyaddr_r(const char *, int, int, struct hostent *,
+ char *, int, int *);
+struct hostent *lwres_gethostbyname_r(const char *, struct hostent *,
+ char *, int, int *);
+struct hostent *lwres_gethostent_r(struct hostent *, char *, int, int *);
+void lwres_sethostent_r(int);
+void lwres_endhostent_r(void);
+
+#ifdef notyet
+struct netent *lwres_getnetbyname_r(const char *, struct netent *,
+ char *, int);
+struct netent *lwres_getnetbyaddr_r(long, int, struct netent *,
+ char *, int);
+struct netent *lwres_getnetent_r(struct netent *, char *, int);
+void lwres_setnetent_r(int);
+void lwres_endnetent_r(void);
+
+struct protoent *lwres_getprotobyname_r(const char *,
+ struct protoent *, char *, int);
+struct protoent *lwres_getprotobynumber_r(int,
+ struct protoent *, char *, int);
+struct protoent *lwres_getprotoent_r(struct protoent *, char *, int);
+void lwres_setprotoent_r(int);
+void lwres_endprotoent_r(void);
+
+struct servent *lwres_getservbyname_r(const char *name, const char *,
+ struct servent *, char *, int);
+struct servent *lwres_getservbyport_r(int port, const char *,
+ struct servent *, char *, int);
+struct servent *lwres_getservent_r(struct servent *, char *, int);
+void lwres_setservent_r(int);
+void lwres_endservent_r(void);
+#endif /* notyet */
+
+LWRES_LANG_ENDDECLS
+
+#ifdef notyet
+/* This is nec'y to make this include file properly replace the sun version. */
+#ifdef sun
+#ifdef __GNU_LIBRARY__
+#include <rpc/netdb.h> /* Required. */
+#else /* !__GNU_LIBRARY__ */
+struct rpcent {
+ char *r_name; /* name of server for this rpc program */
+ char **r_aliases; /* alias list */
+ int r_number; /* rpc program number */
+};
+struct rpcent *lwres_getrpcbyname();
+struct rpcent *lwres_getrpcbynumber(),
+struct rpcent *lwres_getrpcent();
+#endif /* __GNU_LIBRARY__ */
+#endif /* sun */
+#endif /* notyet */
+
+/*
+ * Tell Emacs to use C mode on this file.
+ * Local variables:
+ * mode: c
+ * End:
+ */
+
+#endif /* LWRES_NETDB_H */
diff --git a/lib/bind/lwres/lwres/platform.h b/lib/bind/lwres/lwres/platform.h
new file mode 100644
index 0000000..ed87c89
--- /dev/null
+++ b/lib/bind/lwres/lwres/platform.h
@@ -0,0 +1,113 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2004, 2005 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.
+ */
+
+/* $Id: platform.h.in,v 1.12.2.1.10.2 2004/08/28 06:25:26 marka Exp $ */
+
+#ifndef LWRES_PLATFORM_H
+#define LWRES_PLATFORM_H 1
+
+/*****
+ ***** Platform-dependent defines.
+ *****/
+
+/***
+ *** Network.
+ ***/
+
+/*
+ * Define if this system needs the <netinet/in6.h> header file for IPv6.
+ */
+#undef LWRES_PLATFORM_NEEDNETINETIN6H
+
+/*
+ * Define if this system needs the <netinet6/in6.h> header file for IPv6.
+ */
+#undef LWRES_PLATFORM_NEEDNETINET6IN6H
+
+/*
+ * If sockaddrs on this system have an sa_len field, LWRES_PLATFORM_HAVESALEN
+ * will be defined.
+ */
+#define LWRES_PLATFORM_HAVESALEN 1
+
+/*
+ * If this system has the IPv6 structure definitions, LWRES_PLATFORM_HAVEIPV6
+ * will be defined.
+ */
+#define LWRES_PLATFORM_HAVEIPV6 1
+
+/*
+ * If this system is missing in6addr_any, LWRES_PLATFORM_NEEDIN6ADDRANY will
+ * be defined.
+ */
+#undef LWRES_PLATFORM_NEEDIN6ADDRANY
+
+/*
+ * If this system is missing in6addr_loopback,
+ * LWRES_PLATFORM_NEEDIN6ADDRLOOPBACK will be defined.
+ */
+#undef LWRES_PLATFORM_NEEDIN6ADDRLOOPBACK
+
+/*
+ * If this system has in_addr6, rather than in6_addr,
+ * LWRES_PLATFORM_HAVEINADDR6 will be defined.
+ */
+#undef LWRES_PLATFORM_HAVEINADDR6
+
+/*
+ * Defined if unistd.h does not cause fd_set to be delared.
+ */
+#undef LWRES_PLATFORM_NEEDSYSSELECTH
+
+/*
+ * Used to control how extern data is linked; needed for Win32 platforms.
+ */
+#undef LWRES_PLATFORM_USEDECLSPEC
+
+/*
+ * Defined this system needs vsnprintf() and snprintf().
+ */
+#undef LWRES_PLATFORM_NEEDVSNPRINTF
+
+/*
+ * If this system need a modern sprintf() that returns (int) not (char*).
+ */
+#undef LWRES_PLATFORM_NEEDSPRINTF
+
+/*
+ * The printf format string modifier to use with lwres_uint64_t values.
+ */
+#define LWRES_PLATFORM_QUADFORMAT "ll"
+
+/*! \brief
+ * Define if this system needs strtoul.
+ */
+#undef ISC_PLATFORM_NEEDSTRTOUL
+
+#ifndef LWRES_PLATFORM_USEDECLSPEC
+#define LIBLWRES_EXTERNAL_DATA
+#else
+#ifdef LIBLWRES_EXPORTS
+#define LIBLWRES_EXTERNAL_DATA __declspec(dllexport)
+#else
+#define LIBLWRES_EXTERNAL_DATA __declspec(dllimport)
+#endif
+#endif
+
+#endif /* LWRES_PLATFORM_H */
diff --git a/lib/csu/alpha/Makefile b/lib/csu/alpha/Makefile
new file mode 100644
index 0000000..8b81815
--- /dev/null
+++ b/lib/csu/alpha/Makefile
@@ -0,0 +1,21 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../common
+SRCS= crt1.c crti.S crtn.S
+OBJS= ${SRCS:N*.h:R:S/$/.o/g}
+OBJS+= gcrt1.o
+WARNS?= 6
+CFLAGS+= -I${.CURDIR}/../common -I${.CURDIR}/../../libc/include
+
+all: ${OBJS}
+
+CLEANFILES= ${OBJS}
+
+gcrt1.o: crt1.c
+ ${CC} ${CFLAGS} -DGCRT -c -o gcrt1.o ${.ALLSRC}
+
+realinstall:
+ ${INSTALL} -o ${LIBOWN} -g ${LIBGRP} -m ${LIBMODE} \
+ ${OBJS} ${DESTDIR}${LIBDIR}
+
+.include <bsd.lib.mk>
diff --git a/lib/csu/alpha/crt1.c b/lib/csu/alpha/crt1.c
new file mode 100644
index 0000000..b8ad3ea
--- /dev/null
+++ b/lib/csu/alpha/crt1.c
@@ -0,0 +1,114 @@
+/* LINTLIBRARY */
+/*-
+ * Copyright 2001 David E. O'Brien.
+ * All rights reserved.
+ * Copyright 1996-1998 John D. Polstra.
+ * All rights reserved.
+ * Copyright (c) 1995 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 FreeBSD Project.
+ * See http://www.freebsd.org/ for information about FreeBSD.
+ * This product includes software developed by Christopher G. Demetriou
+ * 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.
+ */
+
+#ifndef lint
+#ifndef __GNUC__
+#error "GCC is needed to compile this file"
+#endif
+#endif /* lint */
+
+#include <stdlib.h>
+
+#include "libc_private.h"
+#include "crtbrand.c"
+
+struct Struct_Obj_Entry;
+struct ps_strings;
+
+extern int _DYNAMIC;
+#pragma weak _DYNAMIC
+
+extern void _fini(void);
+extern void _init(void);
+extern int main(int, char **, char **);
+extern void _start(char **, void (*)(void), struct Struct_Obj_Entry *,
+ struct ps_strings *);
+
+#ifdef GCRT
+extern void _mcleanup(void);
+extern void monstartup(void *, void *);
+extern int eprol;
+extern int etext;
+#endif
+
+char **environ;
+const char *__progname = "";
+
+/* The entry function. */
+/* ARGSUSED */
+void
+_start(char **ap, void (*cleanup)(void), struct Struct_Obj_Entry *obj __unused,
+ struct ps_strings *ps_strings __unused)
+{
+ int argc;
+ char **argv;
+ char **env;
+ const char *s;
+
+ argc = *(long *)(void *)ap;
+ argv = ap + 1;
+ env = ap + 2 + argc;
+ environ = env;
+ if (argc > 0 && argv[0] != NULL) {
+ __progname = argv[0];
+ for (s = __progname; *s != '\0'; s++)
+ if (*s == '/')
+ __progname = s + 1;
+ }
+
+ if (&_DYNAMIC != NULL)
+ atexit(cleanup);
+
+#ifdef GCRT
+ atexit(_mcleanup);
+#endif
+ atexit(_fini);
+#ifdef GCRT
+ monstartup(&eprol, &etext);
+#endif
+ _init();
+ exit( main(argc, argv, env) );
+}
+
+#ifdef GCRT
+__asm__(".text");
+__asm__("eprol:");
+__asm__(".previous");
+#endif
+
+__asm__(".ident\t\"$FreeBSD$\"");
diff --git a/lib/csu/alpha/crti.S b/lib/csu/alpha/crti.S
new file mode 100644
index 0000000..5ecd99c
--- /dev/null
+++ b/lib/csu/alpha/crti.S
@@ -0,0 +1,53 @@
+/*-
+ * Copyright 2000 David O'Brien, 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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, 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.
+ */
+
+ .section .init,"ax",@progbits
+ .align 5
+ .globl _init
+_init:
+ ldgp $29,0($27)
+$_init..ng:
+ lda $30,-16($30)
+ stq $26,0($30)
+ stq $15,8($30)
+ mov $30,$15
+ .align 5
+
+
+ .section .fini,"ax",@progbits
+ .align 5
+ .globl _fini
+_fini:
+ ldgp $29,0($27)
+$_fini..ng:
+ lda $30,-16($30)
+ stq $26,0($30)
+ stq $15,8($30)
+ mov $30,$15
+ .align 5
+
+
+ .section .rodata
+.ascii "$FreeBSD$\0"
diff --git a/lib/csu/alpha/crtn.S b/lib/csu/alpha/crtn.S
new file mode 100644
index 0000000..6928d37
--- /dev/null
+++ b/lib/csu/alpha/crtn.S
@@ -0,0 +1,45 @@
+/*-
+ * Copyright 2000 David O'Brien, 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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, 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.
+ */
+
+ .section .init,"ax",@progbits
+ ldgp $29,0($26)
+ mov $15,$30
+ ldq $26,0($30)
+ ldq $15,8($30)
+ lda $30,16($30)
+ ret $31,($26),1
+
+
+ .section .fini,"ax",@progbits
+ ldgp $29,0($26)
+ mov $15,$30
+ ldq $26,0($30)
+ ldq $15,8($30)
+ lda $30,16($30)
+ ret $31,($26),1
+
+
+ .section .rodata
+.ascii "$FreeBSD$\0"
diff --git a/lib/csu/amd64/Makefile b/lib/csu/amd64/Makefile
new file mode 100644
index 0000000..4b51e6b
--- /dev/null
+++ b/lib/csu/amd64/Makefile
@@ -0,0 +1,22 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../common
+
+SRCS= crt1.c crti.S crtn.S
+OBJS= ${SRCS:N*.h:R:S/$/.o/g}
+OBJS+= gcrt1.o
+CFLAGS+= -I${.CURDIR}/../common \
+ -I${.CURDIR}/../../libc/include
+
+all: ${OBJS}
+
+CLEANFILES= ${OBJS}
+
+gcrt1.o: crt1.c
+ ${CC} ${CFLAGS} -DGCRT -c -o gcrt1.o ${.CURDIR}/crt1.c
+
+realinstall:
+ ${INSTALL} -o ${LIBOWN} -g ${LIBGRP} -m ${LIBMODE} \
+ ${OBJS} ${DESTDIR}${LIBDIR}
+
+.include <bsd.lib.mk>
diff --git a/lib/csu/amd64/crt1.c b/lib/csu/amd64/crt1.c
new file mode 100644
index 0000000..943b07b
--- /dev/null
+++ b/lib/csu/amd64/crt1.c
@@ -0,0 +1,95 @@
+/* LINTLIBRARY */
+/*-
+ * Copyright 1996-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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef lint
+#ifndef __GNUC__
+#error "GCC is needed to compile this file"
+#endif
+#endif /* lint */
+
+#include <stdlib.h>
+
+#include "libc_private.h"
+#include "crtbrand.c"
+
+extern int _DYNAMIC;
+#pragma weak _DYNAMIC
+
+typedef void (*fptr)(void);
+
+extern void _fini(void);
+extern void _init(void);
+extern int main(int, char **, char **);
+extern void _start(char **, void (*)(void));
+
+#ifdef GCRT
+extern void _mcleanup(void);
+extern void monstartup(void *, void *);
+extern int eprol;
+extern int etext;
+#endif
+
+char **environ;
+const char *__progname = "";
+
+/* The entry function. */
+void
+_start(char **ap, void (*cleanup)(void))
+{
+ int argc;
+ char **argv;
+ char **env;
+ const char *s;
+
+ argc = *(long *)(void *)ap;
+ argv = ap + 1;
+ env = ap + 2 + argc;
+ environ = env;
+ if (argc > 0 && argv[0] != NULL) {
+ __progname = argv[0];
+ for (s = __progname; *s != '\0'; s++)
+ if (*s == '/')
+ __progname = s + 1;
+ }
+
+ if (&_DYNAMIC != NULL)
+ atexit(cleanup);
+ else
+ _init_tls();
+
+#ifdef GCRT
+ atexit(_mcleanup);
+#endif
+ atexit(_fini);
+#ifdef GCRT
+ monstartup(&eprol, &etext);
+__asm__("eprol:");
+#endif
+ _init();
+ exit( main(argc, argv, env) );
+}
+
+__asm__(".ident\t\"$FreeBSD$\"");
diff --git a/lib/csu/amd64/crti.S b/lib/csu/amd64/crti.S
new file mode 100644
index 0000000..c46f001
--- /dev/null
+++ b/lib/csu/amd64/crti.S
@@ -0,0 +1,41 @@
+/*-
+ * Copyright 1996, 1997, 1998, 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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, 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.
+ */
+
+ .section .init,"ax",@progbits
+ .align 4
+ .globl _init
+ .type _init,@function
+_init:
+ subq $8,%rsp
+
+ .section .fini,"ax",@progbits
+ .align 4
+ .globl _fini
+ .type _fini,@function
+_fini:
+ subq $8,%rsp
+
+ .section .rodata
+.ascii "$FreeBSD$\0"
diff --git a/lib/csu/amd64/crtn.S b/lib/csu/amd64/crtn.S
new file mode 100644
index 0000000..d6d09da
--- /dev/null
+++ b/lib/csu/amd64/crtn.S
@@ -0,0 +1,35 @@
+/*-
+ * Copyright 1996, 1997, 1998, 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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, 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.
+ */
+
+ .section .init,"ax",@progbits
+ addq $8,%rsp
+ ret
+
+ .section .fini,"ax",@progbits
+ addq $8,%rsp
+ ret
+
+ .section .rodata
+.ascii "$FreeBSD$\0"
diff --git a/lib/csu/arm/Makefile b/lib/csu/arm/Makefile
new file mode 100644
index 0000000..23954e8
--- /dev/null
+++ b/lib/csu/arm/Makefile
@@ -0,0 +1,23 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../common
+
+SRCS= crt1.c crti.S crtn.S
+OBJS= ${SRCS:N*.h:R:S/$/.o/g}
+OBJS+= gcrt1.o
+CFLAGS+= -Wall -Wno-unused \
+ -I${.CURDIR}/../common \
+ -I${.CURDIR}/../../libc/include
+
+all: ${OBJS}
+
+CLEANFILES= ${OBJS}
+
+gcrt1.o: crt1.c
+ ${CC} ${CFLAGS} -DGCRT -c -o gcrt1.o ${.ALLSRC}
+
+realinstall:
+ ${INSTALL} -o ${LIBOWN} -g ${LIBGRP} -m ${LIBMODE} \
+ ${OBJS} ${DESTDIR}${LIBDIR}
+
+.include <bsd.lib.mk>
diff --git a/lib/csu/arm/crt1.c b/lib/csu/arm/crt1.c
new file mode 100644
index 0000000..02af3c2
--- /dev/null
+++ b/lib/csu/arm/crt1.c
@@ -0,0 +1,137 @@
+/* LINTLIBRARY */
+/*-
+ * Copyright 2001 David E. O'Brien.
+ * All rights reserved.
+ * Copyright 1996-1998 John D. Polstra.
+ * All rights reserved.
+ * Copyright (c) 1997 Jason R. Thorpe.
+ * Copyright (c) 1995 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
+ * FreeBSD Project. See http://www.freebsd.org/ for
+ * information about FreeBSD.
+ * 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.
+ */
+
+#ifndef lint
+#ifndef __GNUC__
+#error "GCC is needed to compile this file"
+#endif
+#endif /* lint */
+
+#include <stdlib.h>
+
+#include "libc_private.h"
+#include "crtbrand.c"
+#include <machine/asm.h>
+
+struct Struct_Obj_Entry;
+struct ps_strings;
+
+extern int _DYNAMIC;
+#pragma weak _DYNAMIC
+
+extern void _fini(void);
+extern void _init(void);
+extern int main(int, char **, char **);
+extern void _start(int, char **, char **, const struct Struct_Obj_Entry *,
+ void (*)(void), struct ps_strings *);
+
+#ifdef GCRT
+extern void _mcleanup(void);
+extern void monstartup(void *, void *);
+extern int eprol;
+extern int etext;
+#endif
+
+char **environ;
+const char *__progname = "";
+struct ps_strings *__ps_strings;
+
+/* The entry function. */
+__asm(" .text \n"
+" .align 0 \n"
+" .globl _start \n"
+" _start: \n"
+" mov r5, r2 /* cleanup */ \n"
+" mov r4, r1 /* obj_main */ \n"
+" mov r3, r0 /* ps_strings */ \n"
+" /* Get argc, argv, and envp from stack */ \n"
+" ldr r0, [sp, #0x0000] \n"
+" add r1, sp, #0x0004 \n"
+" add r2, r1, r0, lsl #2 \n"
+" add r2, r2, #0x0004 \n"
+" /* Ensure the stack is properly aligned before calling C code. */\n"
+" bic sp, sp, #7 \n"
+" sub sp, sp, #8 \n"
+" str r5, [sp, #4] \n"
+" str r4, [sp, #0] \n"
+"\n"
+" b __start ");
+/* ARGSUSED */
+void
+__start(int argc, char **argv, char **env, struct ps_strings *ps_strings,
+ const struct Struct_Obj_Entry *obj __unused, void (*cleanup)(void))
+{
+ const char *s;
+
+ environ = env;
+
+ if (argc > 0 && argv[0] != NULL) {
+ __progname = argv[0];
+ for (s = __progname; *s != '\0'; s++)
+ if (*s == '/')
+ __progname = s + 1;
+ }
+
+ if (ps_strings != (struct ps_strings *)0)
+ __ps_strings = ps_strings;
+
+ if (&_DYNAMIC != NULL)
+ atexit(cleanup);
+ else
+ _init_tls();
+#ifdef GCRT
+ atexit(_mcleanup);
+#endif
+ atexit(_fini);
+#ifdef GCRT
+ monstartup(&eprol, &etext);
+#endif
+ _init();
+ exit( main(argc, argv, env) );
+}
+
+#ifdef GCRT
+__asm__(".text");
+__asm__("eprol:");
+__asm__(".previous");
+#endif
+
+__asm__(".ident\t\"$FreeBSD$\"");
diff --git a/lib/csu/arm/crti.S b/lib/csu/arm/crti.S
new file mode 100644
index 0000000..40e83bb
--- /dev/null
+++ b/lib/csu/arm/crti.S
@@ -0,0 +1,21 @@
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+ .section .init,"ax",%progbits
+ .align 4
+ .globl _init
+ .type _init,%function
+_init:
+ mov ip, sp
+ stmdb sp!, {fp, ip, lr, pc}
+ sub fp, ip, #4
+
+ .section .fini,"ax",%progbits
+ .align 4
+ .globl _fini
+ .type _fini,%function
+_fini:
+ mov ip, sp
+ stmdb sp!, {fp, ip, lr, pc}
+ sub fp, ip, #4
+
diff --git a/lib/csu/arm/crtn.S b/lib/csu/arm/crtn.S
new file mode 100644
index 0000000..d148b1e
--- /dev/null
+++ b/lib/csu/arm/crtn.S
@@ -0,0 +1,9 @@
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+ .section .init,"ax",%progbits
+ ldmea fp, {fp, sp, pc}
+ mov pc, lr
+
+ .section .fini,"ax",%progbits
+ ldmea fp, {fp, sp, pc}
+ mov pc, lr
diff --git a/lib/csu/common/crtbegin.c b/lib/csu/common/crtbegin.c
new file mode 100644
index 0000000..ec50ecd
--- /dev/null
+++ b/lib/csu/common/crtbegin.c
@@ -0,0 +1,81 @@
+/*-
+ * Copyright 1996, 1997, 1998, 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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, 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$
+ */
+
+#include <sys/param.h>
+
+typedef void (*fptr)(void);
+
+static fptr ctor_list[1] __attribute__((section(".ctors"))) = { (fptr) -1 };
+static fptr dtor_list[1] __attribute__((section(".dtors"))) = { (fptr) -1 };
+
+static void
+do_ctors(void)
+{
+ fptr *fpp;
+
+ for(fpp = ctor_list + 1; *fpp != 0; ++fpp)
+ ;
+ while(--fpp > ctor_list)
+ (**fpp)();
+}
+
+static void
+do_dtors(void)
+{
+ fptr *fpp;
+
+ for(fpp = dtor_list + 1; *fpp != 0; ++fpp)
+ (**fpp)();
+}
+
+/*
+ * With very large programs on some architectures (e.g., the Alpha),
+ * it is possible to get relocation overflows on the limited
+ * displacements of call/bsr instructions. It is particularly likely
+ * for the calls from _init() and _fini(), because they are in
+ * separate sections. Avoid the problem by forcing indirect calls.
+ */
+static void (*p_do_ctors)(void) = do_ctors;
+static void (*p_do_dtors)(void) = do_dtors;
+
+extern void _init(void) __attribute__((section(".init")));
+
+void
+_init(void)
+{
+ (*p_do_ctors)();
+}
+
+extern void _fini(void) __attribute__((section(".fini")));
+
+void
+_fini(void)
+{
+ (*p_do_dtors)();
+}
+
+#include "crtbrand.c"
diff --git a/lib/csu/common/crtbrand.c b/lib/csu/common/crtbrand.c
new file mode 100644
index 0000000..dde60b3
--- /dev/null
+++ b/lib/csu/common/crtbrand.c
@@ -0,0 +1,52 @@
+/*-
+ * Copyright 2000 David E. O'Brien, 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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, 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>
+
+#define ABI_VENDOR "FreeBSD"
+#define ABI_SECTION ".note.ABI-tag"
+#define ABI_NOTETYPE 1
+
+/*
+ * Special ".note" entry specifying the ABI version. See
+ * http://www.netbsd.org/Documentation/kernel/elf-notes.html
+ * for more information.
+ */
+static const struct {
+ int32_t namesz;
+ int32_t descsz;
+ int32_t type;
+ char name[sizeof ABI_VENDOR];
+ int32_t desc;
+} abitag __attribute__ ((section (ABI_SECTION), aligned(4))) __unused = {
+ sizeof ABI_VENDOR,
+ sizeof(int32_t),
+ ABI_NOTETYPE,
+ ABI_VENDOR,
+ __FreeBSD_version
+};
diff --git a/lib/csu/common/crtend.c b/lib/csu/common/crtend.c
new file mode 100644
index 0000000..4b33f0c
--- /dev/null
+++ b/lib/csu/common/crtend.c
@@ -0,0 +1,33 @@
+/*-
+ * Copyright 1996-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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, 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$
+ */
+
+#include <sys/cdefs.h>
+
+typedef void (*fptr)(void);
+
+static fptr ctor_end[1] __attribute__((section(".ctors"))) __unused = { 0 };
+static fptr dtor_end[1] __attribute__((section(".dtors"))) __unused = { 0 };
diff --git a/lib/csu/i386-elf/Makefile b/lib/csu/i386-elf/Makefile
new file mode 100644
index 0000000..8598ce8
--- /dev/null
+++ b/lib/csu/i386-elf/Makefile
@@ -0,0 +1,19 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../common
+
+SRCS= crt1.c crti.S crtn.S
+FILES= ${SRCS:N*.h:R:S/$/.o/g} gcrt1.o
+FILESOWN= ${LIBOWN}
+FILESGRP= ${LIBGRP}
+FILESMODE= ${LIBMODE}
+FILESDIR= ${LIBDIR}
+WARNS?= 6
+CFLAGS+= -I${.CURDIR}/../common \
+ -I${.CURDIR}/../../libc/include
+CLEANFILES= ${FILES}
+
+gcrt1.o: crt1.c
+ ${CC} ${CFLAGS} -DGCRT -c -o gcrt1.o ${.CURDIR}/crt1.c
+
+.include <bsd.prog.mk>
diff --git a/lib/csu/i386-elf/crt1.c b/lib/csu/i386-elf/crt1.c
new file mode 100644
index 0000000..0934333
--- /dev/null
+++ b/lib/csu/i386-elf/crt1.c
@@ -0,0 +1,113 @@
+/* LINTLIBRARY */
+/*-
+ * Copyright 1996-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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef lint
+#ifndef __GNUC__
+#error "GCC is needed to compile this file"
+#endif
+#endif /* lint */
+
+#include <stdlib.h>
+
+#include "libc_private.h"
+#include "crtbrand.c"
+
+extern int _DYNAMIC;
+#pragma weak _DYNAMIC
+
+typedef void (*fptr)(void);
+
+extern void _fini(void);
+extern void _init(void);
+extern int main(int, char **, char **);
+extern void _start(char *, ...);
+
+#ifdef GCRT
+extern void _mcleanup(void);
+extern void monstartup(void *, void *);
+extern int eprol;
+extern int etext;
+#endif
+
+char **environ;
+const char *__progname = "";
+
+static __inline fptr
+get_rtld_cleanup(void)
+{
+ fptr retval;
+
+#ifdef __GNUC__
+ __asm__("movl %%edx,%0" : "=rm"(retval));
+#else
+ retval = (fptr)0; /* XXXX Fix this for other compilers */
+#endif
+ return(retval);
+}
+
+/* The entry function. */
+void
+_start(char *ap, ...)
+{
+ fptr cleanup;
+ int argc;
+ char **argv;
+ char **env;
+ const char *s;
+
+#ifdef __GNUC__
+ __asm__("and $0xfffffff0,%esp");
+#endif
+ cleanup = get_rtld_cleanup();
+ argv = &ap;
+ argc = *(long *)(void *)(argv - 1);
+ env = argv + argc + 1;
+ environ = env;
+ if (argc > 0 && argv[0] != NULL) {
+ __progname = argv[0];
+ for (s = __progname; *s != '\0'; s++)
+ if (*s == '/')
+ __progname = s + 1;
+ }
+
+ if (&_DYNAMIC != NULL)
+ atexit(cleanup);
+ else
+ _init_tls();
+
+#ifdef GCRT
+ atexit(_mcleanup);
+#endif
+ atexit(_fini);
+#ifdef GCRT
+ monstartup(&eprol, &etext);
+__asm__("eprol:");
+#endif
+ _init();
+ exit( main(argc, argv, env) );
+}
+
+__asm__(".ident\t\"$FreeBSD$\"");
diff --git a/lib/csu/i386-elf/crti.S b/lib/csu/i386-elf/crti.S
new file mode 100644
index 0000000..bb11f3a
--- /dev/null
+++ b/lib/csu/i386-elf/crti.S
@@ -0,0 +1,41 @@
+/*-
+ * Copyright 1996, 1997, 1998, 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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, 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.
+ */
+
+ .section .init,"ax",@progbits
+ .align 4
+ .globl _init
+ .type _init,@function
+_init:
+ sub $12,%esp /* re-align stack pointer */
+
+ .section .fini,"ax",@progbits
+ .align 4
+ .globl _fini
+ .type _fini,@function
+_fini:
+ sub $12,%esp /* re-align stack pointer */
+
+ .section .rodata
+.ascii "$FreeBSD$\0"
diff --git a/lib/csu/i386-elf/crtn.S b/lib/csu/i386-elf/crtn.S
new file mode 100644
index 0000000..bc90d31
--- /dev/null
+++ b/lib/csu/i386-elf/crtn.S
@@ -0,0 +1,35 @@
+/*-
+ * Copyright 1996, 1997, 1998, 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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, 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.
+ */
+
+ .section .init,"ax",@progbits
+ add $12,%esp
+ ret
+
+ .section .fini,"ax",@progbits
+ add $12,%esp
+ ret
+
+ .section .rodata
+.ascii "$FreeBSD$\0"
diff --git a/lib/csu/ia64/Makefile b/lib/csu/ia64/Makefile
new file mode 100644
index 0000000..c906c09
--- /dev/null
+++ b/lib/csu/ia64/Makefile
@@ -0,0 +1,23 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../common
+
+SRCS= crt1.S crti.S crtn.S
+OBJS= ${SRCS:N*.h:R:S/$/.o/g}
+OBJS+= gcrt1.o
+CFLAGS+= -Wall -Wno-unused \
+ -I${.CURDIR}/../common \
+ -I${.CURDIR}/../../libc/include
+
+all: ${OBJS}
+
+CLEANFILES= ${OBJS}
+
+gcrt1.o: crt1.S
+ ${CC} ${CFLAGS} -DGCRT -c -o gcrt1.o ${.ALLSRC}
+
+realinstall:
+ ${INSTALL} -o ${LIBOWN} -g ${LIBGRP} -m ${LIBMODE} \
+ ${OBJS} ${DESTDIR}${LIBDIR}
+
+.include <bsd.lib.mk>
diff --git a/lib/csu/ia64/crt1.S b/lib/csu/ia64/crt1.S
new file mode 100644
index 0000000..10e1a63
--- /dev/null
+++ b/lib/csu/ia64/crt1.S
@@ -0,0 +1,196 @@
+/*
+ * 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.
+ */
+
+ .ident "$FreeBSD$"
+
+ .text
+
+/*
+ * void _start(char **ap, struct ps_strings *, void (*cleanup)(void));
+ */
+#define AP in0
+#define CLEANUP in2
+
+#define GP loc0
+#define ARGC loc1
+#define ARGV loc2
+#define ENVP loc3
+
+ .global _start
+ .type _start, @function
+ .proc _start
+_start:
+ .prologue
+ .save rp, r0
+ .body
+{ .mlx
+ alloc r14=ar.pfs,3,4,3,0
+ movl r15=@gprel(1f)
+}
+1:
+{ .mmi
+ ld4 ARGC=[AP]
+ adds ARGV=8,AP
+ mov r16=ip
+ ;;
+}
+{ .mmi
+ sub gp=r16,r15
+ sub GP=r16,r15
+ shladd r14=ARGC,3,AP
+ ;;
+}
+{ .mii
+ addl r15=@ltoff(environ),gp
+ cmp4.ge p6,p7=0,ARGC
+ adds ENVP=16,r14
+ ;;
+}
+{ .mmi
+ ld8 r14=[r15]
+(p7) ld8 r15=[ARGV]
+ addl r16=@gprel(__progname),gp
+ ;;
+}
+{ .mib
+ st8 [r14]=ENVP
+(p7) cmp.eq p6,p0=0,r15
+(p6) br.dpnt .L1
+ ;;
+}
+ /* Normalize __progname. */
+{ .mmi
+ st8 [r16]=r15
+ ld1 r14=[r15],1
+ nop 0
+ ;;
+}
+.L0:
+{ .mib
+ cmp4.eq p7,p0=0,r14
+ cmp4.eq p6,p0=0x2f,r14
+(p7) br.dptk .L1
+ ;;
+}
+{ .mmb
+(p6) st8 [r16]=r15
+ ld1 r14=[r15],1
+ br.dptk.many .L0
+}
+.L1:
+{ .mib
+ cmp.ne p7,p0=0,CLEANUP
+ mov out0=CLEANUP
+(p7) br.call.sptk b0=atexit
+ ;;
+}
+{ .mfb
+ mov gp=GP
+ nop 0
+ br.call.sptk b0=_init_tls
+}
+#ifdef GCRT
+{ .mmi
+ mov gp=GP
+ ;;
+ addl r14=@ltoff(@fptr(_mcleanup)),gp
+ nop 0
+ ;;
+}
+{ .mfb
+ ld8 out0=[r14]
+ nop 0
+ br.call.sptk b0=atexit
+ ;;
+}
+#endif
+{ .mmi
+ mov gp=GP
+ ;;
+ addl r14=@ltoff(@fptr(_fini)),gp
+ nop 0
+ ;;
+}
+{ .mfb
+ ld8 out0=[r14]
+ nop 0
+ br.call.sptk b0=atexit
+ ;;
+}
+#ifdef GCRT
+{ .mmi
+ mov gp=GP
+ ;;
+ addl r14=@ltoff(eprol),gp
+ addl r15=@ltoff(etext),gp
+ ;;
+}
+{ .mmb
+ ld8 out0=[r14]
+ ld8 out1=[r15]
+ br.call.sptk b0=monstartup
+ ;;
+}
+#endif
+{ .mfb
+ mov gp=GP
+ nop 0
+ br.call.sptk b0=_init
+ ;;
+}
+{ .mmi
+ mov gp=GP
+ mov out0=ARGC
+ mov out1=ARGV
+}
+{ .mfb
+ mov out2=ENVP
+ nop 0
+ br.call.sptk b0=main
+ ;;
+}
+{ .mib
+ mov gp=GP
+ mov out0=r8
+ br.call.sptk b0=exit
+ ;;
+}
+ .endp _start
+
+#ifdef GCRT
+eprol:
+#endif
+
+ .rodata
+.empty: stringz ""
+
+ .sdata
+ .global __progname
+ .size __progname,8
+ .type __progname,@object
+__progname: data8 .empty
+
+ .common environ,8,8
diff --git a/lib/csu/ia64/crti.S b/lib/csu/ia64/crti.S
new file mode 100644
index 0000000..1314cb3
--- /dev/null
+++ b/lib/csu/ia64/crti.S
@@ -0,0 +1,57 @@
+/*-
+ * Copyright (c) 2001 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$
+ */
+
+/*
+ * This file (and its companion crtn.S) form the terminators of the
+ * .init and .fini sections.
+ */
+ .file "crti.S"
+
+ .section .init,"ax",@progbits
+ .global _init#
+ .proc _init#
+_init:
+ .regstk 0,2,0,0
+ .prologue 12,loc0
+ .save ar.pfs,loc1
+ alloc loc1=ar.pfs,0,2,0,0
+ mov loc0=b0 /* Save return addr */
+ .body
+ .endp _init#
+
+ .section .fini,"ax",@progbits
+ .global _fini#
+ .proc _fini#
+_fini:
+ .regstk 0,2,0,0
+ .prologue 12,loc0
+ .save ar.pfs,loc1
+ alloc loc1=ar.pfs,0,2,0,0
+ mov loc0=b0 /* Save return addr */
+ .body
+ .endp _fini#
diff --git a/lib/csu/ia64/crtn.S b/lib/csu/ia64/crtn.S
new file mode 100644
index 0000000..42ec1fe
--- /dev/null
+++ b/lib/csu/ia64/crtn.S
@@ -0,0 +1,43 @@
+/*-
+ * Copyright (c) 2001 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$
+ */
+
+ .file "crtn.S"
+
+ .section .init,"ax",@progbits
+ .regstk 0,2,0,0
+ mov b0=loc0 /* Recover return addr */
+ mov ar.pfs=loc1
+ br.ret.sptk.many b0
+ .endp _init#
+
+ .section .fini,"ax",@progbits
+ .regstk 0,2,0,0
+ mov b0=loc0 /* Recover return addr */
+ mov ar.pfs=loc1
+ br.ret.sptk.many b0
+ .endp _fini#
diff --git a/lib/csu/powerpc/Makefile b/lib/csu/powerpc/Makefile
new file mode 100644
index 0000000..23954e8
--- /dev/null
+++ b/lib/csu/powerpc/Makefile
@@ -0,0 +1,23 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../common
+
+SRCS= crt1.c crti.S crtn.S
+OBJS= ${SRCS:N*.h:R:S/$/.o/g}
+OBJS+= gcrt1.o
+CFLAGS+= -Wall -Wno-unused \
+ -I${.CURDIR}/../common \
+ -I${.CURDIR}/../../libc/include
+
+all: ${OBJS}
+
+CLEANFILES= ${OBJS}
+
+gcrt1.o: crt1.c
+ ${CC} ${CFLAGS} -DGCRT -c -o gcrt1.o ${.ALLSRC}
+
+realinstall:
+ ${INSTALL} -o ${LIBOWN} -g ${LIBGRP} -m ${LIBMODE} \
+ ${OBJS} ${DESTDIR}${LIBDIR}
+
+.include <bsd.lib.mk>
diff --git a/lib/csu/powerpc/crt1.c b/lib/csu/powerpc/crt1.c
new file mode 100644
index 0000000..080691c
--- /dev/null
+++ b/lib/csu/powerpc/crt1.c
@@ -0,0 +1,123 @@
+/* LINTLIBRARY */
+/*-
+ * Copyright 2001 David E. O'Brien.
+ * All rights reserved.
+ * Copyright 1996-1998 John D. Polstra.
+ * All rights reserved.
+ * Copyright (c) 1997 Jason R. Thorpe.
+ * Copyright (c) 1995 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
+ * FreeBSD Project. See http://www.freebsd.org/ for
+ * information about FreeBSD.
+ * 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.
+ */
+
+#ifndef lint
+#ifndef __GNUC__
+#error "GCC is needed to compile this file"
+#endif
+#endif /* lint */
+
+#include <stdlib.h>
+
+#include "libc_private.h"
+#include "crtbrand.c"
+
+struct Struct_Obj_Entry;
+struct ps_strings;
+
+extern int _DYNAMIC;
+#pragma weak _DYNAMIC
+
+extern void _fini(void);
+extern void _init(void);
+extern int main(int, char **, char **);
+extern void _start(int, char **, char **, const struct Struct_Obj_Entry *,
+ void (*)(void), struct ps_strings *);
+
+#ifdef GCRT
+extern void _mcleanup(void);
+extern void monstartup(void *, void *);
+extern int eprol;
+extern int etext;
+#endif
+
+char **environ;
+const char *__progname = "";
+struct ps_strings *__ps_strings;
+
+/* The entry function. */
+/*
+ * First 5 arguments are specified by the PowerPC SVR4 ABI.
+ * The last argument, ps_strings, is a BSD extension.
+ */
+/* ARGSUSED */
+void
+_start(int argc, char **argv, char **env,
+ const struct Struct_Obj_Entry *obj __unused, void (*cleanup)(void),
+ struct ps_strings *ps_strings)
+{
+ const char *s;
+
+ environ = env;
+
+ if (argc > 0 && argv[0] != NULL) {
+ __progname = argv[0];
+ for (s = __progname; *s != '\0'; s++)
+ if (*s == '/')
+ __progname = s + 1;
+ }
+
+ if (ps_strings != (struct ps_strings *)0)
+ __ps_strings = ps_strings;
+
+ if (&_DYNAMIC != NULL)
+ atexit(cleanup);
+ else
+ _init_tls();
+
+#ifdef GCRT
+ atexit(_mcleanup);
+#endif
+ atexit(_fini);
+#ifdef GCRT
+ monstartup(&eprol, &etext);
+#endif
+ _init();
+ exit( main(argc, argv, env) );
+}
+
+#ifdef GCRT
+__asm__(".text");
+__asm__("eprol:");
+__asm__(".previous");
+#endif
+
+__asm__(".ident\t\"$FreeBSD$\"");
diff --git a/lib/csu/powerpc/crti.S b/lib/csu/powerpc/crti.S
new file mode 100644
index 0000000..75d4345
--- /dev/null
+++ b/lib/csu/powerpc/crti.S
@@ -0,0 +1,50 @@
+/*-
+ * Copyright 2001 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.
+ *
+ * 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.
+ */
+
+ .section .init,"ax",@progbits
+ .align 2
+ .globl _init
+ .type _init,@function
+_init:
+ stwu 1,-16(1)
+ mflr 0
+ stw 31,12(1)
+ stw 0,20(1)
+ mr 31,1
+
+
+ .section .fini,"ax",@progbits
+ .align 2
+ .globl _fini
+_fini:
+ stwu 1,-16(1)
+ mflr 0
+ stw 31,12(1)
+ stw 0,20(1)
+ mr 31,1
+
+
+ .section .rodata
+.ascii "$FreeBSD$\0"
diff --git a/lib/csu/powerpc/crtn.S b/lib/csu/powerpc/crtn.S
new file mode 100644
index 0000000..80735cc
--- /dev/null
+++ b/lib/csu/powerpc/crtn.S
@@ -0,0 +1,45 @@
+/*-
+ * Copyright 2001 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.
+ *
+ * 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.
+ */
+
+ .section .init,"ax",@progbits
+ lwz 11,0(1)
+ lwz 0,4(11)
+ mtlr 0
+ lwz 31,-4(11)
+ mr 1,11
+ blr
+
+
+ .section .fini,"ax",@progbits
+ lwz 11,0(1)
+ lwz 0,4(11)
+ mtlr 0
+ lwz 31,-4(11)
+ mr 1,11
+ blr
+
+
+ .section .rodata
+.ascii "$FreeBSD$\0"
diff --git a/lib/csu/sparc64/Makefile b/lib/csu/sparc64/Makefile
new file mode 100644
index 0000000..2e1d03f
--- /dev/null
+++ b/lib/csu/sparc64/Makefile
@@ -0,0 +1,21 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../common
+
+SRCS= crt1.c crti.S crtn.S
+OBJS= ${SRCS:N*.h:R:S/$/.o/g}
+OBJS+= gcrt1.o
+CFLAGS+= -I${.CURDIR}/../common -I${.CURDIR}/../../libc/include
+
+all: ${OBJS}
+
+CLEANFILES= ${OBJS}
+
+gcrt1.o: crt1.c
+ ${CC} ${CFLAGS} -DGCRT -c -o gcrt1.o ${.ALLSRC}
+
+realinstall:
+ ${INSTALL} -o ${LIBOWN} -g ${LIBGRP} -m ${LIBMODE} \
+ ${OBJS} ${DESTDIR}${LIBDIR}
+
+.include <bsd.lib.mk>
diff --git a/lib/csu/sparc64/crt1.c b/lib/csu/sparc64/crt1.c
new file mode 100644
index 0000000..19c0fad
--- /dev/null
+++ b/lib/csu/sparc64/crt1.c
@@ -0,0 +1,125 @@
+/* LINTLIBRARY */
+/*-
+ * Copyright 2001 David E. O'Brien.
+ * All rights reserved.
+ * Copyright (c) 1995, 1998 Berkeley Software Design, Inc.
+ * All rights reserved.
+ * Copyright 1996-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.
+ * 3. The name 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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef lint
+#ifndef __GNUC__
+#error "GCC is needed to compile this file"
+#endif
+#endif /* lint */
+
+#include <stdlib.h>
+
+#include "libc_private.h"
+#include "crtbrand.c"
+
+struct Struct_Obj_Entry;
+struct ps_strings;
+
+extern int _DYNAMIC;
+#pragma weak _DYNAMIC
+
+extern void _fini(void);
+extern void _init(void);
+extern int main(int, char **, char **);
+extern void _start(char **, void (*)(void), struct Struct_Obj_Entry *,
+ struct ps_strings *);
+extern void __sparc_utrap_setup(void);
+
+#ifdef GCRT
+extern void _mcleanup(void);
+extern void monstartup(void *, void *);
+extern int eprol;
+extern int etext;
+#endif
+
+char **environ;
+const char *__progname = "";
+
+/* The entry function. */
+/*
+ * %o0 holds ps_strings pointer.
+ *
+ * Note: kernel may (is not set in stone yet) pass ELF aux vector in %o1,
+ * but for now we do not use it here.
+ *
+ * The SPARC compliance definitions specifies that the kernel pass the
+ * address of a function to be executed on exit in %g1. We do not make
+ * use of it as it is quite broken, because gcc can use this register
+ * as a temporary, so it is not safe from C code. Its even more broken
+ * for dynamic executables since rtld runs first.
+ */
+/* ARGSUSED */
+void
+_start(char **ap, void (*cleanup)(void), struct Struct_Obj_Entry *obj __unused,
+ struct ps_strings *ps_strings __unused)
+{
+ int argc;
+ char **argv;
+ char **env;
+ const char *s;
+
+ argc = *(long *)(void *)ap;
+ argv = ap + 1;
+ env = ap + 2 + argc;
+ environ = env;
+ if (argc > 0 && argv[0] != NULL) {
+ __progname = argv[0];
+ for (s = __progname; *s != '\0'; s++)
+ if (*s == '/')
+ __progname = s + 1;
+ }
+
+ __sparc_utrap_setup();
+
+ if (&_DYNAMIC != NULL)
+ atexit(cleanup);
+ else
+ _init_tls();
+
+#ifdef GCRT
+ atexit(_mcleanup);
+#endif
+ atexit(_fini);
+#ifdef GCRT
+ monstartup(&eprol, &etext);
+#endif
+ _init();
+ exit( main(argc, argv, env) );
+}
+
+#ifdef GCRT
+__asm__(".text");
+__asm__("eprol:");
+__asm__(".previous");
+#endif
+
+__asm__(".ident\t\"$FreeBSD$\"");
diff --git a/lib/csu/sparc64/crti.S b/lib/csu/sparc64/crti.S
new file mode 100644
index 0000000..e3e81af
--- /dev/null
+++ b/lib/csu/sparc64/crti.S
@@ -0,0 +1,58 @@
+/*-
+ * Copyright 2001 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 additional 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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, 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.
+ */
+
+ .file "crti.S"
+
+ /* The minimum stack frame size (bytes) is:
+ * 16 extended words for saving the current register window,
+ * 1 extended word for "hidden parameter",
+ * 6 extended words in wihch a callee can store its arguments
+ * ("The SPARC Architecure Manual" by Weaver & Germond)
+ * This gives 184 bytes. However we must round up to an extended
+ * word boundary, thus 192 bytes.
+ * (if we weren't v9, it would be 96 bytes rather than 192)
+ */
+
+ .section .init,"ax",@progbits
+ .align 4
+ .globl _init
+ .type _init,#function
+_init:
+ save %sp,-192,%sp
+
+
+ .section .fini,"ax",@progbits
+ .globl _fini
+ .type _fini,#function
+ .align 4
+_fini:
+ save %sp,-192,%sp
+
+
+ .section .rodata
+.ascii "$FreeBSD$\0"
diff --git a/lib/csu/sparc64/crtn.S b/lib/csu/sparc64/crtn.S
new file mode 100644
index 0000000..7c0d160
--- /dev/null
+++ b/lib/csu/sparc64/crtn.S
@@ -0,0 +1,42 @@
+/*-
+ * Copyright 2001 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 additional 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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, 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.
+ */
+
+ .file "crtn.S"
+
+ .section .init,"ax",@progbits
+ .align 4
+ ret
+ restore
+
+ .section .fini,"ax",@progbits
+ .align 4
+ ret
+ restore
+
+ .section .rodata
+.ascii "$FreeBSD$\0"
diff --git a/lib/libalias/Makefile b/lib/libalias/Makefile
new file mode 100644
index 0000000..465216a
--- /dev/null
+++ b/lib/libalias/Makefile
@@ -0,0 +1,16 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../../sys/netinet/libalias
+
+LIB= alias
+SHLIBDIR?= /lib
+SHLIB_MAJOR= 5
+MAN= libalias.3
+SRCS= alias.c alias_cuseeme.c alias_db.c alias_ftp.c alias_irc.c \
+ alias_nbt.c alias_pptp.c alias_proxy.c alias_skinny.c alias_smedia.c \
+ alias_util.c alias_old.c
+INCS= alias.h
+WARNS?= 6
+NO_WERROR=
+
+.include <bsd.lib.mk>
diff --git a/lib/libarchive/COPYING b/lib/libarchive/COPYING
new file mode 100644
index 0000000..5a02bcc
--- /dev/null
+++ b/lib/libarchive/COPYING
@@ -0,0 +1,37 @@
+All of the C source code, header files, and documentation in this
+package are covered by the following:
+
+Copyright (c) 2003-2005 Tim Kientzle
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer
+ in this position and unchanged.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR(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 AUTHOR(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.
+
+===========================================================================
+
+Shell scripts, makefiles, and certain other files may be covered by
+other licenses. In particular, some distributions of this library
+contain Makefiles and/or shell scripts that are generated
+automatically by GNU autoconf and GNU automake. Those generated files
+are controlled by the relevant licenses.
+
+$FreeBSD$
+
diff --git a/lib/libarchive/Makefile b/lib/libarchive/Makefile
new file mode 100644
index 0000000..718ebea
--- /dev/null
+++ b/lib/libarchive/Makefile
@@ -0,0 +1,197 @@
+# $FreeBSD$
+
+LIB= archive
+DPADD= ${LIBBZ2} ${LIBZ}
+LDADD= -lbz2 -lz
+
+# The libarchive version stamp.
+# Version is three numbers:
+# Major: Bumped ONLY when API/ABI breakage happens.
+# Minor: Bumped when significant new features are added (see SHLIB_MAJOR)
+# Revision: Bumped on any notable change
+VERSION= 1.2.53
+ARCHIVE_API_MAJOR!= echo ${VERSION} | sed -e 's/\..*//'
+ARCHIVE_API_MINOR!= echo ${VERSION} | sed -e 's/[0-9]*\.//' | sed -e 's/\..*//'
+
+# The FreeBSD SHLIB_MAJOR is computed from the above values.
+# To bump SHLIB_MAJOR, increase the MINOR number in "version" file.
+SHLIB_MAJOR!= echo $$((${ARCHIVE_API_MAJOR} + ${ARCHIVE_API_MINOR}))
+# The SHLIB_MAJOR computation above attempts to match the
+# version number generated by libtool. (This may change
+# when the FreeBSD port of libtool gets fixed.)
+
+CFLAGS+= -DPACKAGE_NAME=\"lib${LIB}\"
+CFLAGS+= -DPACKAGE_VERSION=\"${VERSION}\"
+CFLAGS+= -I${.OBJDIR}
+
+# FreeBSD/arm has some limitations.
+.if ${MACHINE_ARCH} == "arm"
+WARNS?= 3
+.else
+WARNS?= 6
+.endif
+
+# Headers to be installed in /usr/include
+INCS= archive.h archive_entry.h
+
+# Build archive.h from archive.h.in by substituting version information.
+archive.h: archive.h.in Makefile
+ cat ${.CURDIR}/archive.h.in | \
+ sed 's/@VERSION@/${VERSION}/g' | \
+ sed 's/@SHLIB_MAJOR@/${SHLIB_MAJOR}/g' | \
+ sed 's/@ARCHIVE_API_MAJOR@/${ARCHIVE_API_MAJOR}/g' | \
+ sed 's/@ARCHIVE_API_MINOR@/${ARCHIVE_API_MINOR}/g' | \
+ cat > archive.h
+
+# archive.h needs to be cleaned
+CLEANFILES+= archive.h
+
+# Sources to be compiled.
+SRCS= archive.h \
+ archive_check_magic.c \
+ archive_entry.c \
+ archive_read.c \
+ archive_read_data_into_buffer.c \
+ archive_read_data_into_fd.c \
+ archive_read_extract.c \
+ archive_read_open_fd.c \
+ archive_read_open_file.c \
+ archive_read_support_compression_all.c \
+ archive_read_support_compression_bzip2.c \
+ archive_read_support_compression_compress.c \
+ archive_read_support_compression_gzip.c \
+ archive_read_support_compression_none.c \
+ archive_read_support_format_all.c \
+ archive_read_support_format_cpio.c \
+ archive_read_support_format_iso9660.c \
+ archive_read_support_format_tar.c \
+ archive_read_support_format_zip.c \
+ archive_string.c \
+ archive_string_sprintf.c \
+ archive_util.c \
+ archive_write.c \
+ archive_write_open_fd.c \
+ archive_write_open_file.c \
+ archive_write_set_compression_bzip2.c \
+ archive_write_set_compression_gzip.c \
+ archive_write_set_compression_none.c \
+ archive_write_set_format.c \
+ archive_write_set_format_by_name.c \
+ archive_write_set_format_cpio.c \
+ archive_write_set_format_pax.c \
+ archive_write_set_format_shar.c \
+ archive_write_set_format_ustar.c
+
+# Man pages to be installed.
+MAN= archive_entry.3 \
+ archive_read.3 \
+ archive_util.3 \
+ archive_write.3 \
+ libarchive.3 \
+ libarchive-formats.5 \
+ tar.5
+
+# Symlink the man pages under each function name.
+MLINKS+= archive_entry.3 archive_entry_acl_add_entry.3
+MLINKS+= archive_entry.3 archive_entry_acl_add_entry_w.3
+MLINKS+= archive_entry.3 archive_entry_acl_clear.3
+MLINKS+= archive_entry.3 archive_entry_acl_count.3
+MLINKS+= archive_entry.3 archive_entry_acl_next.3
+MLINKS+= archive_entry.3 archive_entry_acl_next_w.3
+MLINKS+= archive_entry.3 archive_entry_acl_reset.3
+MLINKS+= archive_entry.3 archive_entry_acl_text_w.3
+MLINKS+= archive_entry.3 archive_entry_clear.3
+MLINKS+= archive_entry.3 archive_entry_clone.3
+MLINKS+= archive_entry.3 archive_entry_copy_fflags_text_w.3
+MLINKS+= archive_entry.3 archive_entry_copy_gname_w.3
+MLINKS+= archive_entry.3 archive_entry_copy_hardlink_w.3
+MLINKS+= archive_entry.3 archive_entry_copy_pathname_w.3
+MLINKS+= archive_entry.3 archive_entry_copy_stat.3
+MLINKS+= archive_entry.3 archive_entry_copy_symlink_w.3
+MLINKS+= archive_entry.3 archive_entry_copy_uname_w.3
+MLINKS+= archive_entry.3 archive_entry_fflags.3
+MLINKS+= archive_entry.3 archive_entry_fflags_text.3
+MLINKS+= archive_entry.3 archive_entry_free.3
+MLINKS+= archive_entry.3 archive_entry_gid.3
+MLINKS+= archive_entry.3 archive_entry_gname.3
+MLINKS+= archive_entry.3 archive_entry_gname_w.3
+MLINKS+= archive_entry.3 archive_entry_hardlink.3
+MLINKS+= archive_entry.3 archive_entry_ino.3
+MLINKS+= archive_entry.3 archive_entry_mode.3
+MLINKS+= archive_entry.3 archive_entry_mtime.3
+MLINKS+= archive_entry.3 archive_entry_mtime_nsec.3
+MLINKS+= archive_entry.3 archive_entry_new.3
+MLINKS+= archive_entry.3 archive_entry_pathname.3
+MLINKS+= archive_entry.3 archive_entry_pathname_w.3
+MLINKS+= archive_entry.3 archive_entry_rdev.3
+MLINKS+= archive_entry.3 archive_entry_rdevmajor.3
+MLINKS+= archive_entry.3 archive_entry_rdevminor.3
+MLINKS+= archive_entry.3 archive_entry_set_fflags.3
+MLINKS+= archive_entry.3 archive_entry_set_gid.3
+MLINKS+= archive_entry.3 archive_entry_set_gname.3
+MLINKS+= archive_entry.3 archive_entry_set_hardlink.3
+MLINKS+= archive_entry.3 archive_entry_set_link.3
+MLINKS+= archive_entry.3 archive_entry_set_mode.3
+MLINKS+= archive_entry.3 archive_entry_set_pathname.3
+MLINKS+= archive_entry.3 archive_entry_set_rdevmajor.3
+MLINKS+= archive_entry.3 archive_entry_set_rdevminor.3
+MLINKS+= archive_entry.3 archive_entry_set_size.3
+MLINKS+= archive_entry.3 archive_entry_set_symlink.3
+MLINKS+= archive_entry.3 archive_entry_set_uid.3
+MLINKS+= archive_entry.3 archive_entry_set_uname.3
+MLINKS+= archive_entry.3 archive_entry_size.3
+MLINKS+= archive_entry.3 archive_entry_stat.3
+MLINKS+= archive_entry.3 archive_entry_symlink.3
+MLINKS+= archive_entry.3 archive_entry_uid.3
+MLINKS+= archive_entry.3 archive_entry_uname.3
+MLINKS+= archive_entry.3 archive_entry_uname_w.3
+MLINKS+= archive_read.3 archive_read_data.3
+MLINKS+= archive_read.3 archive_read_data_block.3
+MLINKS+= archive_read.3 archive_read_data_into_buffer.3
+MLINKS+= archive_read.3 archive_read_data_into_fd.3
+MLINKS+= archive_read.3 archive_read_data_skip.3
+MLINKS+= archive_read.3 archive_read_extract.3
+MLINKS+= archive_read.3 archive_read_extract_set_progress_callback.3
+MLINKS+= archive_read.3 archive_read_finish.3
+MLINKS+= archive_read.3 archive_read_new.3
+MLINKS+= archive_read.3 archive_read_next_header.3
+MLINKS+= archive_read.3 archive_read_open.3
+MLINKS+= archive_read.3 archive_read_open_fd.3
+MLINKS+= archive_read.3 archive_read_open_file.3
+MLINKS+= archive_read.3 archive_read_set_bytes_per_block.3
+MLINKS+= archive_read.3 archive_read_support_compression_all.3
+MLINKS+= archive_read.3 archive_read_support_compression_bzip2.3
+MLINKS+= archive_read.3 archive_read_support_compression_compress.3
+MLINKS+= archive_read.3 archive_read_support_compression_gzip.3
+MLINKS+= archive_read.3 archive_read_support_compression_none.3
+MLINKS+= archive_read.3 archive_read_support_format_all.3
+MLINKS+= archive_read.3 archive_read_support_format_cpio.3
+MLINKS+= archive_read.3 archive_read_support_format_iso9660.3
+MLINKS+= archive_read.3 archive_read_support_format_tar.3
+MLINKS+= archive_read.3 archive_read_support_format_zip.3
+MLINKS+= archive_util.3 archive_compression.3
+MLINKS+= archive_util.3 archive_compression_name.3
+MLINKS+= archive_util.3 archive_errno.3
+MLINKS+= archive_util.3 archive_error_string.3
+MLINKS+= archive_util.3 archive_format.3
+MLINKS+= archive_util.3 archive_format_name.3
+MLINKS+= archive_util.3 archive_set_error.3
+MLINKS+= archive_write.3 archive_write_data.3
+MLINKS+= archive_write.3 archive_write_finish.3
+MLINKS+= archive_write.3 archive_write_header.3
+MLINKS+= archive_write.3 archive_write_new.3
+MLINKS+= archive_write.3 archive_write_open.3
+MLINKS+= archive_write.3 archive_write_open_fd.3
+MLINKS+= archive_write.3 archive_write_open_file.3
+MLINKS+= archive_write.3 archive_write_prepare.3
+MLINKS+= archive_write.3 archive_write_set_bytes_per_block.3
+MLINKS+= archive_write.3 archive_write_set_bytes_in_last_block.3
+MLINKS+= archive_write.3 archive_write_set_callbacks.3
+MLINKS+= archive_write.3 archive_write_set_compression_bzip2.3
+MLINKS+= archive_write.3 archive_write_set_compression_gzip.3
+MLINKS+= archive_write.3 archive_write_set_format_pax.3
+MLINKS+= archive_write.3 archive_write_set_format_shar.3
+MLINKS+= archive_write.3 archive_write_set_format_ustar.3
+MLINKS+= libarchive.3 archive.3
+
+.include <bsd.lib.mk>
diff --git a/lib/libarchive/README b/lib/libarchive/README
new file mode 100644
index 0000000..1380b4a
--- /dev/null
+++ b/lib/libarchive/README
@@ -0,0 +1,91 @@
+$FreeBSD$
+
+libarchive: a library for reading and writing streaming archives
+
+This is all under a BSD license. Use, enjoy, but don't blame me if it breaks!
+
+Documentation:
+ * libarchive.3 gives an overview of the library as a whole
+ * archive_read.3 and archive_write.3 provide detailed calling
+ sequences for the read and write APIs
+ * archive_entry.3 details the "struct archive_entry" utility class
+ * libarchive-formats.5 documents the file formats supported by the library
+ * tar.5 provides some detailed information about a variety of different
+ "tar" formats.
+
+You should also read the copious comments in "archive.h" and the source
+code for the sample "bsdtar" program for more details. Please let me know
+about any errors or omissions you find.
+
+Currently, the library automatically detects and reads the following:
+ * gzip compression
+ * bzip2 compression
+ * compress/LZW compression
+ * GNU tar format (including GNU long filenames, long link names, and
+ sparse files)
+ * Solaris 9 extended tar format (including ACLs)
+ * Old V7 tar archives
+ * POSIX ustar
+ * POSIX pax interchange format
+ * POSIX octet-oriented cpio
+ * SVR4 ASCII cpio
+ * Binary cpio (big-endian or little-endian)
+ * ISO9660 CD-ROM images (with optional Rockridge extensions)
+ * ZIP archives (with uncompressed or "deflate" compressed entries)
+
+The library can write:
+ * gzip compression
+ * bzip2 compression
+ * POSIX ustar
+ * POSIX pax interchange format
+ * "restricted" pax format, which will create ustar archives except for
+ entries that require pax extensions (for long filenames, ACLs, etc).
+ * POSIX octet-oriented cpio
+ * shar archives
+
+Notes:
+ * This is a heavily stream-oriented system. There is no direct
+ support for in-place modification or random access and no intention
+ of ever adding such support. Adding such support would require
+ sacrificing a lot of other features, so don't bother asking.
+
+ * The library is designed to be extended with new compression and
+ archive formats. The only requirement is that the format be
+ readable or writable as a stream and that each archive entry be
+ independent.
+
+ * On read, compression and format are always detected automatically.
+
+ * I've attempted to minimize static link pollution. If you don't
+ explicitly invoke a particular feature (such as support for a
+ particular compression or format), it won't get pulled in.
+ In particular, if you don't explicitly enable a particular
+ compression or decompression support, you won't need to link
+ against the corresponding compression or decompression libraries.
+ This also reduces the size of statically-linked binaries in
+ environments where that matters.
+
+ * On read, the library accepts whatever blocks you hand it.
+ Your read callback is free to pass the library a byte at a time
+ or mmap the entire archive and give it to the library at once.
+ On write, the library always produces correctly-blocked
+ output.
+
+ * The object-style approach allows you to have multiple archive streams
+ open at once. bsdtar uses this in its "@archive" extension.
+
+ * The archive itself is read/written using callback functions.
+ You can read an archive directly from an in-memory buffer or
+ write it to a socket, if you wish. There are some utility
+ functions to provide easy-to-use "open file," etc, capabilities.
+
+ * The read/write APIs are designed to allow individual entries
+ to be read or written to any data source: You can create
+ a block of data in memory and add it to a tar archive without
+ first writing a temporary file. You can also read an entry from
+ an archive and write the data directly to a socket. If you want
+ to read/write entries to disk, there are convenience functions to
+ make this especially easy.
+
+ * Note: "pax interchange format" is really an extended tar format,
+ despite what the name says.
diff --git a/lib/libarchive/archive.h.in b/lib/libarchive/archive.h.in
new file mode 100644
index 0000000..62c4d52
--- /dev/null
+++ b/lib/libarchive/archive.h.in
@@ -0,0 +1,344 @@
+/*-
+ * Copyright (c) 2003-2004 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(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 AUTHOR(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$
+ */
+
+#ifndef ARCHIVE_H_INCLUDED
+#define ARCHIVE_H_INCLUDED
+
+/*
+ * This header file corresponds to:
+ * Library version @VERSION@
+ * Shared library version @SHLIB_MAJOR@
+ */
+
+#include <sys/types.h> /* Linux requires this for off_t */
+#include <inttypes.h> /* For int64_t */
+#include <unistd.h> /* For ssize_t and size_t */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ * If ARCHIVE_API_VERSION != archive_api_version(), then the library you
+ * were linked with is using an incompatible API. This is almost
+ * certainly a fatal problem.
+ *
+ * ARCHIVE_API_FEATURE is incremented with each significant feature
+ * addition, so you can test (at compile or run time) if a particular
+ * feature is implemented. It's no big deal if ARCHIVE_API_FEATURE !=
+ * archive_api_feature(), as long as both are high enough to include
+ * the features you're relying on. Specific values of FEATURE are
+ * documented here:
+ *
+ * 1 - Version tests are available.
+ * 2 - archive_{read,write}_close available separately from _finish.
+ */
+#define ARCHIVE_API_VERSION @ARCHIVE_API_MAJOR@
+int archive_api_version(void);
+#define ARCHIVE_API_FEATURE @ARCHIVE_API_MINOR@
+int archive_api_feature(void);
+/* Textual name/version of the library. */
+#define ARCHIVE_LIBRARY_VERSION "libarchive @VERSION@"
+const char * archive_version(void);
+
+#define ARCHIVE_BYTES_PER_RECORD 512
+#define ARCHIVE_DEFAULT_BYTES_PER_BLOCK 10240
+
+/* Declare our basic types. */
+struct archive;
+struct archive_entry;
+
+/*
+ * Error codes: Use archive_errno() and archive_error_string()
+ * to retrieve details. Unless specified otherwise, all functions
+ * that return 'int' use these codes.
+ */
+#define ARCHIVE_EOF 1 /* Found end of archive. */
+#define ARCHIVE_OK 0 /* Operation was successful. */
+#define ARCHIVE_RETRY (-10) /* Retry might succeed. */
+#define ARCHIVE_WARN (-20) /* Partial sucess. */
+#define ARCHIVE_FATAL (-30) /* No more operations are possible. */
+
+/*
+ * As far as possible, archive_errno returns standard platform errno codes.
+ * Of course, the details vary by platform, so the actual definitions
+ * here are stored in "archive_platform.h". The symbols are listed here
+ * for reference; as a rule, clients should not need to know the exact
+ * platform-dependent error code.
+ */
+/* Unrecognized or invalid file format. */
+/* #define ARCHIVE_ERRNO_FILE_FORMAT */
+/* Illegal usage of the library. */
+/* #define ARCHIVE_ERRNO_PROGRAMMER_ERROR */
+/* Unknown or unclassified error. */
+/* #define ARCHIVE_ERRNO_MISC */
+
+/*
+ * Callbacks are invoked to automatically read/write/open/close the archive.
+ * You can provide your own for complex tasks (like breaking archives
+ * across multiple tapes) or use standard ones built into the library.
+ */
+
+/* Returns pointer and size of next block of data from archive. */
+typedef ssize_t archive_read_callback(struct archive *, void *_client_data,
+ const void **_buffer);
+/* Returns size actually written, zero on EOF, -1 on error. */
+typedef ssize_t archive_write_callback(struct archive *, void *_client_data,
+ void *_buffer, size_t _length);
+typedef int archive_open_callback(struct archive *, void *_client_data);
+typedef int archive_close_callback(struct archive *, void *_client_data);
+
+/*
+ * Codes for archive_compression.
+ */
+#define ARCHIVE_COMPRESSION_NONE 0
+#define ARCHIVE_COMPRESSION_GZIP 1
+#define ARCHIVE_COMPRESSION_BZIP2 2
+#define ARCHIVE_COMPRESSION_COMPRESS 3
+
+/*
+ * Codes returned by archive_format.
+ *
+ * Top 16 bits identifies the format family (e.g., "tar"); lower
+ * 16 bits indicate the variant. This is updated by read_next_header.
+ * Note that the lower 16 bits will often vary from entry to entry.
+ */
+#define ARCHIVE_FORMAT_BASE_MASK 0xff0000U
+#define ARCHIVE_FORMAT_CPIO 0x10000
+#define ARCHIVE_FORMAT_CPIO_POSIX (ARCHIVE_FORMAT_CPIO | 1)
+#define ARCHIVE_FORMAT_CPIO_BIN_LE (ARCHIVE_FORMAT_CPIO | 2)
+#define ARCHIVE_FORMAT_CPIO_BIN_BE (ARCHIVE_FORMAT_CPIO | 3)
+#define ARCHIVE_FORMAT_CPIO_SVR4_NOCRC (ARCHIVE_FORMAT_CPIO | 4)
+#define ARCHIVE_FORMAT_CPIO_SVR4_CRC (ARCHIVE_FORMAT_CPIO | 5)
+#define ARCHIVE_FORMAT_SHAR 0x20000
+#define ARCHIVE_FORMAT_SHAR_BASE (ARCHIVE_FORMAT_SHAR | 1)
+#define ARCHIVE_FORMAT_SHAR_DUMP (ARCHIVE_FORMAT_SHAR | 2)
+#define ARCHIVE_FORMAT_TAR 0x30000
+#define ARCHIVE_FORMAT_TAR_USTAR (ARCHIVE_FORMAT_TAR | 1)
+#define ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE (ARCHIVE_FORMAT_TAR | 2)
+#define ARCHIVE_FORMAT_TAR_PAX_RESTRICTED (ARCHIVE_FORMAT_TAR | 3)
+#define ARCHIVE_FORMAT_TAR_GNUTAR (ARCHIVE_FORMAT_TAR | 4)
+#define ARCHIVE_FORMAT_ISO9660 0x40000
+#define ARCHIVE_FORMAT_ISO9660_ROCKRIDGE (ARCHIVE_FORMAT_ISO9660 | 1)
+#define ARCHIVE_FORMAT_ZIP 0x50000
+
+/*-
+ * Basic outline for reading an archive:
+ * 1) Ask archive_read_new for an archive reader object.
+ * 2) Update any global properties as appropriate.
+ * In particular, you'll certainly want to call appropriate
+ * archive_read_support_XXX functions.
+ * 3) Call archive_read_open_XXX to open the archive
+ * 4) Repeatedly call archive_read_next_header to get information about
+ * successive archive entries. Call archive_read_data to extract
+ * data for entries of interest.
+ * 5) Call archive_read_finish to end processing.
+ */
+struct archive *archive_read_new(void);
+
+/*
+ * The archive_read_support_XXX calls enable auto-detect for this
+ * archive handle. They also link in the necessary support code.
+ * For example, if you don't want bzlib linked in, don't invoke
+ * support_compression_bzip2(). The "all" functions provide the
+ * obvious shorthand.
+ */
+int archive_read_support_compression_all(struct archive *);
+int archive_read_support_compression_bzip2(struct archive *);
+int archive_read_support_compression_compress(struct archive *);
+int archive_read_support_compression_gzip(struct archive *);
+int archive_read_support_compression_none(struct archive *);
+
+int archive_read_support_format_all(struct archive *);
+int archive_read_support_format_cpio(struct archive *);
+int archive_read_support_format_gnutar(struct archive *);
+int archive_read_support_format_iso9660(struct archive *);
+int archive_read_support_format_tar(struct archive *);
+int archive_read_support_format_zip(struct archive *);
+
+
+/* Open the archive using callbacks for archive I/O. */
+int archive_read_open(struct archive *, void *_client_data,
+ archive_open_callback *, archive_read_callback *,
+ archive_close_callback *);
+
+/*
+ * The archive_read_open_file function is a convenience function built
+ * on archive_read_open that uses a canned callback suitable for
+ * common situations. Note that a NULL filename indicates stdin.
+ */
+int archive_read_open_file(struct archive *, const char *_file,
+ size_t _block_size);
+int archive_read_open_fd(struct archive *, int _fd,
+ size_t _block_size);
+
+/* Parses and returns next entry header. */
+int archive_read_next_header(struct archive *,
+ struct archive_entry **);
+
+/*
+ * Retrieve the byte offset in UNCOMPRESSED data where last-read
+ * header started.
+ */
+int64_t archive_read_header_position(struct archive *);
+
+/* Read data from the body of an entry. Similar to read(2). */
+ssize_t archive_read_data(struct archive *, void *, size_t);
+/*
+ * A zero-copy version of archive_read_data that also exposes the file offset
+ * of each returned block. Note that the client has no way to specify
+ * the desired size of the block. The API does gaurantee that offsets will
+ * be strictly increasing and that returned blocks will not overlap.
+ */
+int archive_read_data_block(struct archive *a,
+ const void **buff, size_t *size, off_t *offset);
+
+/*-
+ * Some convenience functions that are built on archive_read_data:
+ * 'skip': skips entire entry
+ * 'into_buffer': writes data into memory buffer that you provide
+ * 'into_fd': writes data to specified filedes
+ */
+int archive_read_data_skip(struct archive *);
+int archive_read_data_into_buffer(struct archive *, void *buffer,
+ ssize_t len);
+int archive_read_data_into_fd(struct archive *, int fd);
+
+/*-
+ * Convenience function to recreate the current entry (whose header
+ * has just been read) on disk.
+ *
+ * This does quite a bit more than just copy data to disk. It also:
+ * - Creates intermediate directories as required.
+ * - Manages directory permissions: non-writable directories will
+ * be initially created with write permission enabled; when the
+ * archive is closed, dir permissions are edited to the values specified
+ * in the archive.
+ * - Checks hardlinks: hardlinks will not be extracted unless the
+ * linked-to file was also extracted within the same session. (TODO)
+ */
+
+/* The "flags" argument selects optional behavior, 'OR' the flags you want. */
+/* TODO: The 'Default' comments here are not quite correct; clean this up. */
+#define ARCHIVE_EXTRACT_OWNER (1) /* Default: owner/group not restored */
+#define ARCHIVE_EXTRACT_PERM (2) /* Default: restore perm only for reg file*/
+#define ARCHIVE_EXTRACT_TIME (4) /* Default: mod time not restored */
+#define ARCHIVE_EXTRACT_NO_OVERWRITE (8) /* Default: Replace files on disk */
+#define ARCHIVE_EXTRACT_UNLINK (16) /* Default: don't unlink existing files */
+#define ARCHIVE_EXTRACT_ACL (32) /* Default: don't restore ACLs */
+#define ARCHIVE_EXTRACT_FFLAGS (64) /* Default: don't restore fflags */
+#define ARCHIVE_EXTRACT_XATTR (128) /* Default: don't restore xattrs */
+
+int archive_read_extract(struct archive *, struct archive_entry *,
+ int flags);
+void archive_read_extract_set_progress_callback(struct archive *,
+ void (*_progress_func)(void *), void *_user_data);
+
+/* Close the file and release most resources. */
+int archive_read_close(struct archive *);
+/* Release all resources and destroy the object. */
+/* Note that archive_read_finish will call archive_read_close for you. */
+void archive_read_finish(struct archive *);
+
+/*-
+ * To create an archive:
+ * 1) Ask archive_write_new for a archive writer object.
+ * 2) Set any global properties. In particular, you should set
+ * the compression and format to use.
+ * 3) Call archive_write_open to open the file (most people
+ * will use archive_write_open_file or archive_write_open_fd,
+ * which provide convenient canned I/O callbacks for you).
+ * 4) For each entry:
+ * - construct an appropriate struct archive_entry structure
+ * - archive_write_header to write the header
+ * - archive_write_data to write the entry data
+ * 5) archive_write_close to close the output
+ * 6) archive_write_finish to cleanup the writer and release resources
+ */
+struct archive *archive_write_new(void);
+int archive_write_set_bytes_per_block(struct archive *,
+ int bytes_per_block);
+/* XXX This is badly misnamed; suggestions appreciated. XXX */
+int archive_write_set_bytes_in_last_block(struct archive *,
+ int bytes_in_last_block);
+
+int archive_write_set_compression_bzip2(struct archive *);
+int archive_write_set_compression_gzip(struct archive *);
+int archive_write_set_compression_none(struct archive *);
+/* A convenience function to set the format based on the code or name. */
+int archive_write_set_format(struct archive *, int format_code);
+int archive_write_set_format_by_name(struct archive *,
+ const char *name);
+/* To minimize link pollution, use one or more of the following. */
+int archive_write_set_format_cpio(struct archive *);
+/* TODO: int archive_write_set_format_old_tar(struct archive *); */
+int archive_write_set_format_pax(struct archive *);
+int archive_write_set_format_pax_restricted(struct archive *);
+int archive_write_set_format_shar(struct archive *);
+int archive_write_set_format_shar_dump(struct archive *);
+int archive_write_set_format_ustar(struct archive *);
+int archive_write_open(struct archive *, void *,
+ archive_open_callback *, archive_write_callback *,
+ archive_close_callback *);
+int archive_write_open_fd(struct archive *, int _fd);
+int archive_write_open_file(struct archive *, const char *_file);
+
+/*
+ * Note that the library will truncate writes beyond the size provided
+ * to archive_write_header or pad if the provided data is short.
+ */
+int archive_write_header(struct archive *,
+ struct archive_entry *);
+/* TODO: should be ssize_t, but that might require .so version bump? */
+int archive_write_data(struct archive *, const void *, size_t);
+int archive_write_close(struct archive *);
+void archive_write_finish(struct archive *);
+
+/*
+ * Accessor functions to read/set various information in
+ * the struct archive object:
+ */
+/* Bytes written after compression or read before decompression. */
+int64_t archive_position_compressed(struct archive *);
+/* Bytes written to compressor or read from decompressor. */
+int64_t archive_position_uncompressed(struct archive *);
+
+const char *archive_compression_name(struct archive *);
+int archive_compression(struct archive *);
+int archive_errno(struct archive *);
+const char *archive_error_string(struct archive *);
+const char *archive_format_name(struct archive *);
+int archive_format(struct archive *);
+void archive_set_error(struct archive *, int _err, const char *fmt, ...);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !ARCHIVE_H_INCLUDED */
diff --git a/lib/libarchive/archive_check_magic.c b/lib/libarchive/archive_check_magic.c
new file mode 100644
index 0000000..528da5e
--- /dev/null
+++ b/lib/libarchive/archive_check_magic.c
@@ -0,0 +1,110 @@
+/*-
+ * Copyright (c) 2003-2004 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(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 AUTHOR(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 "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "archive_private.h"
+
+static void
+errmsg(const char *m)
+{
+ write(STDERR_FILENO, m, strlen(m));
+}
+
+static void
+diediedie(void)
+{
+ *(char *)0 = 1; /* Deliberately segfault and force a coredump. */
+ _exit(1); /* If that didn't work, just exit with an error. */
+}
+
+static const char *
+state_name(unsigned s)
+{
+ switch (s) {
+ case ARCHIVE_STATE_NEW: return ("new");
+ case ARCHIVE_STATE_HEADER: return ("header");
+ case ARCHIVE_STATE_DATA: return ("data");
+ case ARCHIVE_STATE_EOF: return ("eof");
+ case ARCHIVE_STATE_CLOSED: return ("closed");
+ case ARCHIVE_STATE_FATAL: return ("fatal");
+ default: return ("??");
+ }
+}
+
+
+static void
+write_all_states(int states)
+{
+ unsigned lowbit;
+
+ /* A trick for computing the lowest set bit. */
+ while ((lowbit = states & (-states)) != 0) {
+ states &= ~lowbit; /* Clear the low bit. */
+ errmsg(state_name(lowbit));
+ if (states != 0)
+ errmsg("/");
+ }
+}
+
+/*
+ * Check magic value and current state; bail if it isn't valid.
+ *
+ * This is designed to catch serious programming errors that violate
+ * the libarchive API.
+ */
+void
+__archive_check_magic(struct archive *a, unsigned magic, unsigned state,
+ const char *function)
+{
+ if (a->magic != magic) {
+ errmsg("INTERNAL ERROR: Function ");
+ errmsg(function);
+ errmsg(" invoked with invalid struct archive structure.\n");
+ diediedie();
+ }
+
+ if (state == ARCHIVE_STATE_ANY)
+ return;
+
+ if ((a->state & state) == 0) {
+ errmsg("INTERNAL ERROR: Function '");
+ errmsg(function);
+ errmsg("' invoked with archive structure in state '");
+ write_all_states(a->state);
+ errmsg("', should be in state '");
+ write_all_states(state);
+ errmsg("'\n");
+ diediedie();
+ }
+}
diff --git a/lib/libarchive/archive_entry.3 b/lib/libarchive/archive_entry.3
new file mode 100644
index 0000000..b619577
--- /dev/null
+++ b/lib/libarchive/archive_entry.3
@@ -0,0 +1,341 @@
+.\" Copyright (c) 2003-2004 Tim Kientzle
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING 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, 2003
+.Dt archive_entry 3
+.Os
+.Sh NAME
+.Nm archive_entry_acl_add_entry ,
+.Nm archive_entry_acl_add_entry_w ,
+.Nm archive_entry_acl_clear ,
+.Nm archive_entry_acl_count ,
+.Nm archive_entry_acl_next ,
+.Nm archive_entry_acl_next_w ,
+.Nm archive_entry_acl_reset ,
+.Nm archive_entry_acl_text_w ,
+.Nm archive_entry_atime ,
+.Nm archive_entry_atime_nsec ,
+.Nm archive_entry_clear ,
+.Nm archive_entry_clone ,
+.Nm archive_entry_copy_fflags_text_w ,
+.Nm archive_entry_copy_gname_w ,
+.Nm archive_entry_copy_hardlink ,
+.Nm archive_entry_copy_hardlink_w ,
+.Nm archive_entry_copy_pathname_w ,
+.Nm archive_entry_copy_stat ,
+.Nm archive_entry_copy_symlink_w ,
+.Nm archive_entry_copy_uname_w ,
+.Nm archive_entry_dev ,
+.Nm archive_entry_fflags ,
+.Nm archive_entry_fflags_text ,
+.Nm archive_entry_free ,
+.Nm archive_entry_gid ,
+.Nm archive_entry_gname ,
+.Nm archive_entry_hardlink ,
+.Nm archive_entry_ino ,
+.Nm archive_entry_mode ,
+.Nm archive_entry_mtime ,
+.Nm archive_entry_mtime_nsec ,
+.Nm archive_entry_new ,
+.Nm archive_entry_pathname ,
+.Nm archive_entry_pathname_w ,
+.Nm archive_entry_rdev ,
+.Nm archive_entry_rdevmajor ,
+.Nm archive_entry_rdevminor ,
+.Nm archive_entry_set_fflags ,
+.Nm archive_entry_set_gid ,
+.Nm archive_entry_set_gname ,
+.Nm archive_entry_set_hardlink ,
+.Nm archive_entry_set_link ,
+.Nm archive_entry_set_mode ,
+.Nm archive_entry_set_mtime ,
+.Nm archive_entry_set_pathname ,
+.Nm archive_entry_set_rdevmajor ,
+.Nm archive_entry_set_rdevminor ,
+.Nm archive_entry_set_size ,
+.Nm archive_entry_set_symlink ,
+.Nm archive_entry_set_uid ,
+.Nm archive_entry_set_uname ,
+.Nm archive_entry_size ,
+.Nm archive_entry_stat ,
+.Nm archive_entry_symlink ,
+.Nm archive_entry_uid ,
+.Nm archive_entry_uname
+.Nd functions for manipulating archive entry descriptions
+.Sh SYNOPSIS
+.In archive_entry.h
+.Ft void
+.Fn archive_entry_acl_add_entry "struct archive_entry *" "int type" "int permset" "int tag" "int qual" "const char *name"
+.Ft void
+.Fn archive_entry_acl_add_entry_w "struct archive_entry *" "int type" "int permset" "int tag" "int qual" "const wchar_t *name"
+.Ft void
+.Fn archive_entry_acl_clear "struct archive_entry *"
+.Ft int
+.Fn archive_entry_acl_count "struct archive_entry *" "int type"
+.Ft int
+.Fn archive_entry_acl_next "struct archive_entry *" "int want_type" "int *type" "int *permset" "int *tag" "int *qual" "const char **name"
+.Ft int
+.Fn archive_entry_acl_next_w "struct archive_entry *" "int want_type" "int *type" "int *permset" "int *tag" "int *qual" "const wchar_t **name"
+.Ft int
+.Fn archive_entry_acl_reset "struct archive_entry *" "int want_type"
+.Ft const wchar_t *
+.Fn archive_entry_acl_text_w "struct archive_entry *" "int flags"
+.Ft time_t
+.Fn archive_entry_atime "struct archive_entry *"
+.Ft long
+.Fn archive_entry_atime_nsec "struct archive_entry *"
+.Ft "struct archive_entry *"
+.Fn archive_entry_clear "struct archive_entry *"
+.Ft struct archive_entry *
+.Fn archive_entry_clone "struct archive_entry *"
+.Ft const wchar_t *
+.Fn archive_entry_copy_fflags_text_w "struct archive_entry *" "const wchar_t *"
+.Ft void
+.Fn archive_entry_copy_gname_w "struct archive_entry *" "const wchar_t *"
+.Ft void
+.Fn archive_entry_copy_hardlink "struct archive_entry *" "const char *"
+.Ft void
+.Fn archive_entry_copy_hardlink_w "struct archive_entry *" "const wchar_t *"
+.Ft void
+.Fn archive_entry_copy_pathname_w "struct archive_entry *" "const wchar_t *"
+.Ft void
+.Fn archive_entry_copy_stat "struct archive_entry *" "const struct stat *"
+.Ft void
+.Fn archive_entry_copy_symlink_w "struct archive_entry *" "const wchar_t *"
+.Ft void
+.Fn archive_entry_copy_uname_w "struct archive_entry *" "const wchar_t *"
+.Ft dev_t
+.Fn archive_entry_dev "struct archive_entry *"
+.Ft void
+.Fn archive_entry_fflags "struct archive_entry *" "unsigned long *set" "unsigned long *clear"
+.Ft const char *
+.Fn archive_entry_fflags_text "struct archive_entry *"
+.Ft void
+.Fn archive_entry_free "struct archive_entry *"
+.Ft const char *
+.Fn archive_entry_gname "struct archive_entry *"
+.Ft const char *
+.Fn archive_entry_hardlink "struct archive_entry *"
+.Ft ino_t
+.Fn archive_entry_ino "struct archive_entry *"
+.Ft mode_t
+.Fn archive_entry_mode "struct archive_entry *"
+.Ft time_t
+.Fn archive_entry_mtime "struct archive_entry *"
+.Ft long
+.Fn archive_entry_mtime_nsec "struct archive_entry *"
+.Ft struct archive_entry *
+.Fn archive_entry_new "void"
+.Ft const char *
+.Fn archive_entry_pathname "struct archive_entry *"
+.Ft const wchar_t *
+.Fn archive_entry_pathname_w "struct archive_entry *"
+.Ft dev_t
+.Fn archive_entry_rdev "struct archive_entry *"
+.Ft dev_t
+.Fn archive_entry_rdevmajor "struct archive_entry *"
+.Ft dev_t
+.Fn archive_entry_rdevminor "struct archive_entry *"
+.Ft void
+.Fn archive_entry_set_fflags "struct archive_entry *" "unsigned long set" "unsigned long clear"
+.Ft void
+.Fn archive_entry_set_gid "struct archive_entry *" "gid_t"
+.Ft void
+.Fn archive_entry_set_gname "struct archive_entry *" "const char *"
+.Ft void
+.Fn archive_entry_set_hardlink "struct archive_entry *" "const char *"
+.Ft void
+.Fn archive_entry_set_link "struct archive_entry *" "const char *"
+.Ft void
+.Fn archive_entry_set_mode "struct archive_entry *" "mode_t"
+.Ft void
+.Fn archive_entry_set_mtime "struct archive_entry *" "time_t" "long nanos"
+.Ft void
+.Fn archive_entry_set_pathname "struct archive_entry *" "const char *"
+.Ft void
+.Fn archive_entry_set_rdevmajor "struct archive_entry *" "dev_t"
+.Ft void
+.Fn archive_entry_set_rdevminor "struct archive_entry *" "dev_t"
+.Ft void
+.Fn archive_entry_set_size "struct archive_entry *" "int64_t"
+.Ft void
+.Fn archive_entry_set_symlink "struct archive_entry *" "const char *"
+.Ft void
+.Fn archive_entry_set_uid "struct archive_entry *" "uid_t"
+.Ft void
+.Fn archive_entry_set_uname "struct archive_entry *" "const char *"
+.Ft int64_t
+.Fn archive_entry_size "struct archive_entry *"
+.Ft const struct stat *
+.Fn archive_entry_stat "struct archive_entry *"
+.Ft const char *
+.Fn archive_entry_symlink "struct archive_entry *"
+.Ft const char *
+.Fn archive_entry_uname "struct archive_entry *"
+.Sh DESCRIPTION
+These functions create and manipulate data objects that
+represent entries within an archive.
+You can think of a
+.Tn struct archive_entry
+as a heavy-duty version of
+.Tn struct stat :
+it includes everything from
+.Tn struct stat
+plus associated pathname, textual group and user names, etc.
+These objects are used by
+.Xr libarchive 3
+to represent the metadata associated with a particular
+entry in an archive.
+.Ss Create and Destroy
+There are functions to allocate, destroy, clear, and copy
+.Va archive_entry
+objects:
+.Bl -tag -compact -width indent
+.It Fn archive_entry_clear
+Erases the object, resetting all internal fields to the
+same state as a newly-created object.
+This is provided to allow you to quickly recycle objects
+without thrashing the heap.
+.It Fn archive_entry_clone
+A deep copy operation; all text fields are duplicated.
+.It Fn archive_entry_free
+Releases the
+.Tn struct archive_entry
+object.
+.It Fn archive_entry_new
+Allocate and return a blank
+.Tn struct archive_entry
+object.
+.El
+.Ss Set and Get Functions
+Most of the functions here set or read entries in an object.
+Such functions have one of the following forms:
+.Bl -tag -compact -width indent
+.It Fn archive_entry_set_XXXX
+Stores the provided data in the object.
+In particular, for strings, the pointer is stored,
+not the referenced string.
+.It Fn archive_entry_copy_XXXX
+As above, except that the referenced data is copied
+into the object.
+.It Fn archive_entry_XXXX
+Returns the specified data.
+In the case of strings, a const-qualified pointer to
+the string is returned.
+.El
+String data can be set or accessed as wide character strings
+or normal
+.Va char
+strings.
+The functions that use wide character strings are suffixed with
+.Cm _w .
+Note that these are different representations of the same data:
+For example, if you store a narrow string and read the corresponding
+wide string, the object will transparently convert formats
+using the current locale.
+Similarly, if you store a wide string and then store a
+narrow string for the same data, the previously-set wide string will
+be discarded in favor of the new data.
+.Pp
+There are a few set/get functions that merit additional description:
+.Bl -tag -compact -width indent
+.It Fn archive_entry_set_link
+This function sets the symlink field if it is already set.
+Otherwise, it sets the hardlink field.
+.El
+.Ss File Flags
+File flags are transparently converted between a bitmap
+representation and a textual format.
+For example, if you set the bitmap and ask for text, the library
+will build a canonical text format.
+However, if you set a text format and request a text format,
+you will get back the same text, even if it is ill-formed.
+If you need to canonicalize a textual flags string, you should first set the
+text form, then request the bitmap form, then use that to set the bitmap form.
+Setting the bitmap format will clear the internal text representation
+and force it to be reconstructed when you next request the text form.
+.Pp
+The bitmap format consists of two integers, one containing bits
+that should be set, the other specifying bits that should be
+cleared.
+Bits not mentioned in either bitmap will be ignored.
+Usually, the bitmap of bits to be cleared will be set to zero.
+In unusual circumstances, you can force a fully-specified set
+of file flags by setting the bitmap of flags to clear to the complement
+of the bitmap of flags to set.
+(This differs from
+.Xr fflagstostr 3 ,
+which only includes names for set bits.)
+Converting a bitmap to a textual string is a platform-specific
+operation; bits that are not meaningful on the current platform
+will be ignored.
+.Pp
+The canonical text format is a comma-separated list of flag names.
+The
+.Fn archive_entry_copy_fflags_text_w
+function parses the provided text and sets the internal bitmap values.
+This is a platform-specific operation; names that are not meaningful
+on the current platform will be ignored.
+The function returns a pointer to the start of the first name that was not
+recognized, or NULL if every name was recognized.
+Note that every name--including names that follow an unrecognized name--will
+be evaluated, and the bitmaps will be set to reflect every name that is
+recognized.
+(In particular, this differs from
+.Xr strtofflags 3 ,
+which stops parsing at the first unrecognized name.)
+.Ss ACL Handling
+XXX This needs serious help.
+XXX
+.Pp
+An
+.Dq Access Control List
+(ACL) is a list of permissions that grant access to particular users or
+groups beyond what would normally be provided by standard POSIX mode bits.
+The ACL handling here addresses some deficiencies in the POSIX.1e draft 17 ACL
+specification.
+In particular, POSIX.1e draft 17 specifies several different formats, but
+none of those formats include both textual user/group names and numeric
+UIDs/GIDs.
+.Pp
+XXX explain ACL stuff XXX
+.\" .Sh EXAMPLE
+.\" .Sh RETURN VALUES
+.\" .Sh ERRORS
+.Sh SEE ALSO
+.Xr archive 3
+.Sh HISTORY
+The
+.Nm libarchive
+library first appeared in
+.Fx 5.3 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm libarchive
+library was written by
+.An Tim Kientzle Aq kientzle@acm.org .
+.\" .Sh BUGS
diff --git a/lib/libarchive/archive_entry.c b/lib/libarchive/archive_entry.c
new file mode 100644
index 0000000..7ec0052
--- /dev/null
+++ b/lib/libarchive/archive_entry.c
@@ -0,0 +1,1742 @@
+/*-
+ * Copyright (c) 2003-2004 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(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 AUTHOR(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 "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#ifdef MAJOR_IN_MKDEV
+#include <sys/mkdev.h>
+#else
+#ifdef MAJOR_IN_SYSMACROS
+#include <sys/sysmacros.h>
+#endif
+#endif
+#ifdef HAVE_EXT2FS_EXT2_FS_H
+#include <ext2fs/ext2_fs.h> /* for Linux file flags */
+#endif
+#include <limits.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Obtain suitable wide-character manipulation functions. */
+#ifdef HAVE_WCHAR_H
+#include <wchar.h>
+#else
+static size_t wcslen(const wchar_t *s)
+{
+ const wchar_t *p = s;
+ while (*p != L'\0')
+ ++p;
+ return p - s;
+}
+static wchar_t * wcscpy(wchar_t *s1, const wchar_t *s2)
+{
+ wchar_t *dest = s1;
+ while ((*s1 = *s2) != L'\0')
+ ++s1, ++s2;
+ return dest;
+}
+#define wmemcpy(a,b,i) (wchar_t *)memcpy((a), (b), (i) * sizeof(wchar_t))
+/* Good enough for simple equality testing, but not for sorting. */
+#define wmemcmp(a,b,i) memcmp((a), (b), (i) * sizeof(wchar_t))
+#endif
+
+#include "archive.h"
+#include "archive_entry.h"
+#include "archive_private.h"
+
+#undef max
+#define max(a, b) ((a)>(b)?(a):(b))
+
+/*
+ * Handle wide character (i.e., Unicode) and non-wide character
+ * strings transparently.
+ *
+ */
+
+struct aes {
+ const char *aes_mbs;
+ char *aes_mbs_alloc;
+ const wchar_t *aes_wcs;
+ wchar_t *aes_wcs_alloc;
+};
+
+struct ae_acl {
+ struct ae_acl *next;
+ int type; /* E.g., access or default */
+ int tag; /* E.g., user/group/other/mask */
+ int permset; /* r/w/x bits */
+ int id; /* uid/gid for user/group */
+ struct aes name; /* uname/gname */
+};
+
+struct ae_xattr {
+ struct ae_xattr *next;
+
+ char *name;
+ void *value;
+ size_t size;
+};
+
+static void aes_clean(struct aes *);
+static void aes_copy(struct aes *dest, struct aes *src);
+static const char * aes_get_mbs(struct aes *);
+static const wchar_t * aes_get_wcs(struct aes *);
+static void aes_set_mbs(struct aes *, const char *mbs);
+static void aes_copy_mbs(struct aes *, const char *mbs);
+/* static void aes_set_wcs(struct aes *, const wchar_t *wcs); */
+static void aes_copy_wcs(struct aes *, const wchar_t *wcs);
+
+static char * ae_fflagstostr(unsigned long bitset, unsigned long bitclear);
+static const wchar_t *ae_wcstofflags(const wchar_t *stringp,
+ unsigned long *setp, unsigned long *clrp);
+static void append_entry_w(wchar_t **wp, const wchar_t *prefix, int tag,
+ const wchar_t *wname, int perm, int id);
+static void append_id_w(wchar_t **wp, int id);
+
+static int acl_special(struct archive_entry *entry,
+ int type, int permset, int tag);
+static struct ae_acl *acl_new_entry(struct archive_entry *entry,
+ int type, int permset, int tag, int id);
+static void next_field_w(const wchar_t **wp, const wchar_t **start,
+ const wchar_t **end, wchar_t *sep);
+static int prefix_w(const wchar_t *start, const wchar_t *end,
+ const wchar_t *test);
+
+
+/*
+ * Description of an archive entry.
+ *
+ * Basically, this is a "struct stat" with a few text fields added in.
+ *
+ * TODO: Add "comment", "charset", and possibly other entries
+ * that are supported by "pax interchange" format. However, GNU, ustar,
+ * cpio, and other variants don't support these features, so they're not an
+ * excruciatingly high priority right now.
+ *
+ * TODO: "pax interchange" format allows essentially arbitrary
+ * key/value attributes to be attached to any entry. Supporting
+ * such extensions may make this library useful for special
+ * applications (e.g., a package manager could attach special
+ * package-management attributes to each entry). There are tricky
+ * API issues involved, so this is not going to happen until
+ * there's a real demand for it.
+ *
+ * TODO: Design a good API for handling sparse files.
+ */
+struct archive_entry {
+ /*
+ * Note that ae_stat.st_mode & S_IFMT can be 0!
+ *
+ * This occurs when the actual file type of the object is not
+ * in the archive. For example, 'tar' archives store
+ * hardlinks without marking the type of the underlying
+ * object.
+ */
+ struct stat ae_stat;
+
+ /*
+ * Use aes here so that we get transparent mbs<->wcs conversions.
+ */
+ struct aes ae_fflags_text; /* Text fflags per fflagstostr(3) */
+ unsigned long ae_fflags_set; /* Bitmap fflags */
+ unsigned long ae_fflags_clear;
+ struct aes ae_gname; /* Name of owning group */
+ struct aes ae_hardlink; /* Name of target for hardlink */
+ struct aes ae_pathname; /* Name of entry */
+ struct aes ae_symlink; /* symlink contents */
+ struct aes ae_uname; /* Name of owner */
+
+ struct ae_acl *acl_head;
+ struct ae_acl *acl_p;
+ int acl_state; /* See acl_next for details. */
+ wchar_t *acl_text_w;
+
+ struct ae_xattr *xattr_head;
+ struct ae_xattr *xattr_p;
+};
+
+static void
+aes_clean(struct aes *aes)
+{
+ if (aes->aes_mbs_alloc) {
+ free(aes->aes_mbs_alloc);
+ aes->aes_mbs_alloc = NULL;
+ }
+ if (aes->aes_wcs_alloc) {
+ free(aes->aes_wcs_alloc);
+ aes->aes_wcs_alloc = NULL;
+ }
+ memset(aes, 0, sizeof(*aes));
+}
+
+static void
+aes_copy(struct aes *dest, struct aes *src)
+{
+ *dest = *src;
+ if (src->aes_mbs != NULL) {
+ dest->aes_mbs_alloc = strdup(src->aes_mbs);
+ dest->aes_mbs = dest->aes_mbs_alloc;
+ if (dest->aes_mbs == NULL)
+ __archive_errx(1, "No memory for aes_copy()");
+ }
+
+ if (src->aes_wcs != NULL) {
+ dest->aes_wcs_alloc = malloc((wcslen(src->aes_wcs) + 1)
+ * sizeof(wchar_t));
+ dest->aes_wcs = dest->aes_wcs_alloc;
+ if (dest->aes_wcs == NULL)
+ __archive_errx(1, "No memory for aes_copy()");
+ wcscpy(dest->aes_wcs_alloc, src->aes_wcs);
+ }
+}
+
+static const char *
+aes_get_mbs(struct aes *aes)
+{
+ if (aes->aes_mbs == NULL && aes->aes_wcs == NULL)
+ return NULL;
+ if (aes->aes_mbs == NULL && aes->aes_wcs != NULL) {
+ /*
+ * XXX Need to estimate the number of byte in the
+ * multi-byte form. Assume that, on average, wcs
+ * chars encode to no more than 3 bytes. There must
+ * be a better way... XXX
+ */
+ int mbs_length = wcslen(aes->aes_wcs) * 3 + 64;
+ aes->aes_mbs_alloc = malloc(mbs_length);
+ aes->aes_mbs = aes->aes_mbs_alloc;
+ if (aes->aes_mbs == NULL)
+ __archive_errx(1, "No memory for aes_get_mbs()");
+ wcstombs(aes->aes_mbs_alloc, aes->aes_wcs, mbs_length - 1);
+ aes->aes_mbs_alloc[mbs_length - 1] = 0;
+ }
+ return (aes->aes_mbs);
+}
+
+static const wchar_t *
+aes_get_wcs(struct aes *aes)
+{
+ if (aes->aes_wcs == NULL && aes->aes_mbs == NULL)
+ return NULL;
+ if (aes->aes_wcs == NULL && aes->aes_mbs != NULL) {
+ /*
+ * No single byte will be more than one wide character,
+ * so this length estimate will always be big enough.
+ */
+ int wcs_length = strlen(aes->aes_mbs);
+ aes->aes_wcs_alloc
+ = malloc((wcs_length + 1) * sizeof(wchar_t));
+ aes->aes_wcs = aes->aes_wcs_alloc;
+ if (aes->aes_wcs == NULL)
+ __archive_errx(1, "No memory for aes_get_wcs()");
+ mbstowcs(aes->aes_wcs_alloc, aes->aes_mbs, wcs_length);
+ aes->aes_wcs_alloc[wcs_length] = 0;
+ }
+ return (aes->aes_wcs);
+}
+
+static void
+aes_set_mbs(struct aes *aes, const char *mbs)
+{
+ if (aes->aes_mbs_alloc) {
+ free(aes->aes_mbs_alloc);
+ aes->aes_mbs_alloc = NULL;
+ }
+ if (aes->aes_wcs_alloc) {
+ free(aes->aes_wcs_alloc);
+ aes->aes_wcs_alloc = NULL;
+ }
+ aes->aes_mbs = mbs;
+ aes->aes_wcs = NULL;
+}
+
+static void
+aes_copy_mbs(struct aes *aes, const char *mbs)
+{
+ if (aes->aes_mbs_alloc) {
+ free(aes->aes_mbs_alloc);
+ aes->aes_mbs_alloc = NULL;
+ }
+ if (aes->aes_wcs_alloc) {
+ free(aes->aes_wcs_alloc);
+ aes->aes_wcs_alloc = NULL;
+ }
+ aes->aes_mbs_alloc = malloc((strlen(mbs) + 1) * sizeof(char));
+ if (aes->aes_mbs_alloc == NULL)
+ __archive_errx(1, "No memory for aes_copy_mbs()");
+ strcpy(aes->aes_mbs_alloc, mbs);
+ aes->aes_mbs = aes->aes_mbs_alloc;
+ aes->aes_wcs = NULL;
+}
+
+#if 0
+static void
+aes_set_wcs(struct aes *aes, const wchar_t *wcs)
+{
+ if (aes->aes_mbs_alloc) {
+ free(aes->aes_mbs_alloc);
+ aes->aes_mbs_alloc = NULL;
+ }
+ if (aes->aes_wcs_alloc) {
+ free(aes->aes_wcs_alloc);
+ aes->aes_wcs_alloc = NULL;
+ }
+ aes->aes_mbs = NULL;
+ aes->aes_wcs = wcs;
+}
+#endif
+
+static void
+aes_copy_wcs(struct aes *aes, const wchar_t *wcs)
+{
+ if (aes->aes_mbs_alloc) {
+ free(aes->aes_mbs_alloc);
+ aes->aes_mbs_alloc = NULL;
+ }
+ if (aes->aes_wcs_alloc) {
+ free(aes->aes_wcs_alloc);
+ aes->aes_wcs_alloc = NULL;
+ }
+ aes->aes_mbs = NULL;
+ aes->aes_wcs_alloc = malloc((wcslen(wcs) + 1) * sizeof(wchar_t));
+ if (aes->aes_wcs_alloc == NULL)
+ __archive_errx(1, "No memory for aes_copy_wcs()");
+ wcscpy(aes->aes_wcs_alloc, wcs);
+ aes->aes_wcs = aes->aes_wcs_alloc;
+}
+
+struct archive_entry *
+archive_entry_clear(struct archive_entry *entry)
+{
+ aes_clean(&entry->ae_fflags_text);
+ aes_clean(&entry->ae_gname);
+ aes_clean(&entry->ae_hardlink);
+ aes_clean(&entry->ae_pathname);
+ aes_clean(&entry->ae_symlink);
+ aes_clean(&entry->ae_uname);
+ archive_entry_acl_clear(entry);
+ archive_entry_xattr_clear(entry);
+ memset(entry, 0, sizeof(*entry));
+ return entry;
+}
+
+struct archive_entry *
+archive_entry_clone(struct archive_entry *entry)
+{
+ struct archive_entry *entry2;
+
+ /* Allocate new structure and copy over all of the fields. */
+ entry2 = malloc(sizeof(*entry2));
+ if (entry2 == NULL)
+ return (NULL);
+ memset(entry2, 0, sizeof(*entry2));
+ entry2->ae_stat = entry->ae_stat;
+ entry2->ae_fflags_set = entry->ae_fflags_set;
+ entry2->ae_fflags_clear = entry->ae_fflags_clear;
+
+ aes_copy(&entry2->ae_fflags_text, &entry->ae_fflags_text);
+ aes_copy(&entry2->ae_gname, &entry->ae_gname);
+ aes_copy(&entry2->ae_hardlink, &entry->ae_hardlink);
+ aes_copy(&entry2->ae_pathname, &entry->ae_pathname);
+ aes_copy(&entry2->ae_symlink, &entry->ae_symlink);
+ aes_copy(&entry2->ae_uname, &entry->ae_uname);
+
+ /* XXX TODO: Copy ACL data over as well. XXX */
+ /* XXX TODO: Copy xattr data over as well. XXX */
+ return (entry2);
+}
+
+void
+archive_entry_free(struct archive_entry *entry)
+{
+ archive_entry_clear(entry);
+ free(entry);
+}
+
+struct archive_entry *
+archive_entry_new(void)
+{
+ struct archive_entry *entry;
+
+ entry = malloc(sizeof(*entry));
+ if (entry == NULL)
+ return (NULL);
+ memset(entry, 0, sizeof(*entry));
+ return (entry);
+}
+
+/*
+ * Functions for reading fields from an archive_entry.
+ */
+
+time_t
+archive_entry_atime(struct archive_entry *entry)
+{
+ return (entry->ae_stat.st_atime);
+}
+
+long
+archive_entry_atime_nsec(struct archive_entry *entry)
+{
+ (void)entry; /* entry can be unused here. */
+ return (ARCHIVE_STAT_ATIME_NANOS(&entry->ae_stat));
+}
+
+time_t
+archive_entry_ctime(struct archive_entry *entry)
+{
+ return (entry->ae_stat.st_ctime);
+}
+
+long
+archive_entry_ctime_nsec(struct archive_entry *entry)
+{
+ (void)entry; /* entry can be unused here. */
+ return (ARCHIVE_STAT_CTIME_NANOS(&entry->ae_stat));
+}
+
+dev_t
+archive_entry_dev(struct archive_entry *entry)
+{
+ return (entry->ae_stat.st_dev);
+}
+
+void
+archive_entry_fflags(struct archive_entry *entry,
+ unsigned long *set, unsigned long *clear)
+{
+ *set = entry->ae_fflags_set;
+ *clear = entry->ae_fflags_clear;
+}
+
+/*
+ * Note: if text was provided, this just returns that text. If you
+ * really need the text to be rebuilt in a canonical form, set the
+ * text, ask for the bitmaps, then set the bitmaps. (Setting the
+ * bitmaps clears any stored text.) This design is deliberate: if
+ * we're editing archives, we don't want to discard flags just because
+ * they aren't supported on the current system. The bitmap<->text
+ * conversions are platform-specific (see below).
+ */
+const char *
+archive_entry_fflags_text(struct archive_entry *entry)
+{
+ const char *f;
+ char *p;
+
+ f = aes_get_mbs(&entry->ae_fflags_text);
+ if (f != NULL)
+ return (f);
+
+ if (entry->ae_fflags_set == 0 && entry->ae_fflags_clear == 0)
+ return (NULL);
+
+ p = ae_fflagstostr(entry->ae_fflags_set, entry->ae_fflags_clear);
+ if (p == NULL)
+ return (NULL);
+
+ aes_copy_mbs(&entry->ae_fflags_text, p);
+ free(p);
+ f = aes_get_mbs(&entry->ae_fflags_text);
+ return (f);
+}
+
+gid_t
+archive_entry_gid(struct archive_entry *entry)
+{
+ return (entry->ae_stat.st_gid);
+}
+
+const char *
+archive_entry_gname(struct archive_entry *entry)
+{
+ return (aes_get_mbs(&entry->ae_gname));
+}
+
+const wchar_t *
+archive_entry_gname_w(struct archive_entry *entry)
+{
+ return (aes_get_wcs(&entry->ae_gname));
+}
+
+const char *
+archive_entry_hardlink(struct archive_entry *entry)
+{
+ return (aes_get_mbs(&entry->ae_hardlink));
+}
+
+const wchar_t *
+archive_entry_hardlink_w(struct archive_entry *entry)
+{
+ return (aes_get_wcs(&entry->ae_hardlink));
+}
+
+ino_t
+archive_entry_ino(struct archive_entry *entry)
+{
+ return (entry->ae_stat.st_ino);
+}
+
+mode_t
+archive_entry_mode(struct archive_entry *entry)
+{
+ return (entry->ae_stat.st_mode);
+}
+
+time_t
+archive_entry_mtime(struct archive_entry *entry)
+{
+ return (entry->ae_stat.st_mtime);
+}
+
+long
+archive_entry_mtime_nsec(struct archive_entry *entry)
+{
+ (void)entry; /* entry can be unused here. */
+ return (ARCHIVE_STAT_MTIME_NANOS(&entry->ae_stat));
+}
+
+const char *
+archive_entry_pathname(struct archive_entry *entry)
+{
+ return (aes_get_mbs(&entry->ae_pathname));
+}
+
+const wchar_t *
+archive_entry_pathname_w(struct archive_entry *entry)
+{
+ return (aes_get_wcs(&entry->ae_pathname));
+}
+
+dev_t
+archive_entry_rdev(struct archive_entry *entry)
+{
+ return (entry->ae_stat.st_rdev);
+}
+
+dev_t
+archive_entry_rdevmajor(struct archive_entry *entry)
+{
+ return (major(entry->ae_stat.st_rdev));
+}
+
+dev_t
+archive_entry_rdevminor(struct archive_entry *entry)
+{
+ return (minor(entry->ae_stat.st_rdev));
+}
+
+int64_t
+archive_entry_size(struct archive_entry *entry)
+{
+ return (entry->ae_stat.st_size);
+}
+
+const struct stat *
+archive_entry_stat(struct archive_entry *entry)
+{
+ return (&entry->ae_stat);
+}
+
+const char *
+archive_entry_symlink(struct archive_entry *entry)
+{
+ return (aes_get_mbs(&entry->ae_symlink));
+}
+
+const wchar_t *
+archive_entry_symlink_w(struct archive_entry *entry)
+{
+ return (aes_get_wcs(&entry->ae_symlink));
+}
+
+uid_t
+archive_entry_uid(struct archive_entry *entry)
+{
+ return (entry->ae_stat.st_uid);
+}
+
+const char *
+archive_entry_uname(struct archive_entry *entry)
+{
+ return (aes_get_mbs(&entry->ae_uname));
+}
+
+const wchar_t *
+archive_entry_uname_w(struct archive_entry *entry)
+{
+ return (aes_get_wcs(&entry->ae_uname));
+}
+
+/*
+ * Functions to set archive_entry properties.
+ */
+
+/*
+ * Note "copy" not "set" here. The "set" functions that accept a pointer
+ * only store the pointer; they don't copy the underlying object.
+ */
+void
+archive_entry_copy_stat(struct archive_entry *entry, const struct stat *st)
+{
+ entry->ae_stat = *st;
+}
+
+void
+archive_entry_set_fflags(struct archive_entry *entry,
+ unsigned long set, unsigned long clear)
+{
+ aes_clean(&entry->ae_fflags_text);
+ entry->ae_fflags_set = set;
+ entry->ae_fflags_clear = clear;
+}
+
+const wchar_t *
+archive_entry_copy_fflags_text_w(struct archive_entry *entry,
+ const wchar_t *flags)
+{
+ aes_copy_wcs(&entry->ae_fflags_text, flags);
+ return (ae_wcstofflags(flags,
+ &entry->ae_fflags_set, &entry->ae_fflags_clear));
+}
+
+void
+archive_entry_set_gid(struct archive_entry *entry, gid_t g)
+{
+ entry->ae_stat.st_gid = g;
+}
+
+void
+archive_entry_set_gname(struct archive_entry *entry, const char *name)
+{
+ aes_set_mbs(&entry->ae_gname, name);
+}
+
+void
+archive_entry_copy_gname_w(struct archive_entry *entry, const wchar_t *name)
+{
+ aes_copy_wcs(&entry->ae_gname, name);
+}
+
+void
+archive_entry_set_hardlink(struct archive_entry *entry, const char *target)
+{
+ aes_set_mbs(&entry->ae_hardlink, target);
+}
+
+void
+archive_entry_copy_hardlink(struct archive_entry *entry, const char *target)
+{
+ aes_copy_mbs(&entry->ae_hardlink, target);
+}
+
+void
+archive_entry_copy_hardlink_w(struct archive_entry *entry, const wchar_t *target)
+{
+ aes_copy_wcs(&entry->ae_hardlink, target);
+}
+
+void
+archive_entry_set_atime(struct archive_entry *entry, time_t t, long ns)
+{
+ entry->ae_stat.st_atime = t;
+ ARCHIVE_STAT_SET_ATIME_NANOS(&entry->ae_stat, ns);
+}
+
+void
+archive_entry_set_ctime(struct archive_entry *entry, time_t t, long ns)
+{
+ entry->ae_stat.st_ctime = t;
+ ARCHIVE_STAT_SET_CTIME_NANOS(&entry->ae_stat, ns);
+}
+
+/* Set symlink if symlink is already set, else set hardlink. */
+void
+archive_entry_set_link(struct archive_entry *entry, const char *target)
+{
+ if (entry->ae_symlink.aes_mbs != NULL ||
+ entry->ae_symlink.aes_wcs != NULL)
+ aes_set_mbs(&entry->ae_symlink, target);
+ else
+ aes_set_mbs(&entry->ae_hardlink, target);
+}
+
+void
+archive_entry_set_mode(struct archive_entry *entry, mode_t m)
+{
+ entry->ae_stat.st_mode = m;
+}
+
+void
+archive_entry_set_mtime(struct archive_entry *entry, time_t m, long ns)
+{
+ entry->ae_stat.st_mtime = m;
+ ARCHIVE_STAT_SET_MTIME_NANOS(&entry->ae_stat, ns);
+}
+
+void
+archive_entry_set_pathname(struct archive_entry *entry, const char *name)
+{
+ aes_set_mbs(&entry->ae_pathname, name);
+}
+
+void
+archive_entry_copy_pathname(struct archive_entry *entry, const char *name)
+{
+ aes_copy_mbs(&entry->ae_pathname, name);
+}
+
+void
+archive_entry_copy_pathname_w(struct archive_entry *entry, const wchar_t *name)
+{
+ aes_copy_wcs(&entry->ae_pathname, name);
+}
+
+void
+archive_entry_set_rdevmajor(struct archive_entry *entry, dev_t m)
+{
+ dev_t d;
+
+ d = entry->ae_stat.st_rdev;
+ entry->ae_stat.st_rdev = makedev(major(m), minor(d));
+}
+
+void
+archive_entry_set_rdevminor(struct archive_entry *entry, dev_t m)
+{
+ dev_t d;
+
+ d = entry->ae_stat.st_rdev;
+ entry->ae_stat.st_rdev = makedev(major(d), minor(m));
+}
+
+void
+archive_entry_set_size(struct archive_entry *entry, int64_t s)
+{
+ entry->ae_stat.st_size = s;
+}
+
+void
+archive_entry_set_symlink(struct archive_entry *entry, const char *linkname)
+{
+ aes_set_mbs(&entry->ae_symlink, linkname);
+}
+
+void
+archive_entry_copy_symlink_w(struct archive_entry *entry, const wchar_t *linkname)
+{
+ aes_copy_wcs(&entry->ae_symlink, linkname);
+}
+
+void
+archive_entry_set_uid(struct archive_entry *entry, uid_t u)
+{
+ entry->ae_stat.st_uid = u;
+}
+
+void
+archive_entry_set_uname(struct archive_entry *entry, const char *name)
+{
+ aes_set_mbs(&entry->ae_uname, name);
+}
+
+void
+archive_entry_copy_uname_w(struct archive_entry *entry, const wchar_t *name)
+{
+ aes_copy_wcs(&entry->ae_uname, name);
+}
+
+/*
+ * ACL management. The following would, of course, be a lot simpler
+ * if: 1) the last draft of POSIX.1e were a really thorough and
+ * complete standard that addressed the needs of ACL archiving and 2)
+ * everyone followed it faithfully. Alas, neither is true, so the
+ * following is a lot more complex than might seem necessary to the
+ * uninitiated.
+ */
+
+void
+archive_entry_acl_clear(struct archive_entry *entry)
+{
+ struct ae_acl *ap;
+
+ while (entry->acl_head != NULL) {
+ ap = entry->acl_head->next;
+ aes_clean(&entry->acl_head->name);
+ free(entry->acl_head);
+ entry->acl_head = ap;
+ }
+ if (entry->acl_text_w != NULL) {
+ free(entry->acl_text_w);
+ entry->acl_text_w = NULL;
+ }
+ entry->acl_p = NULL;
+ entry->acl_state = 0; /* Not counting. */
+}
+
+/*
+ * Add a single ACL entry to the internal list of ACL data.
+ */
+void
+archive_entry_acl_add_entry(struct archive_entry *entry,
+ int type, int permset, int tag, int id, const char *name)
+{
+ struct ae_acl *ap;
+
+ if (acl_special(entry, type, permset, tag) == 0)
+ return;
+ ap = acl_new_entry(entry, type, permset, tag, id);
+ if (ap == NULL) {
+ /* XXX Error XXX */
+ return;
+ }
+ if (name != NULL && *name != '\0')
+ aes_copy_mbs(&ap->name, name);
+ else
+ aes_clean(&ap->name);
+}
+
+/*
+ * As above, but with a wide-character name.
+ */
+void
+archive_entry_acl_add_entry_w(struct archive_entry *entry,
+ int type, int permset, int tag, int id, const wchar_t *name)
+{
+ struct ae_acl *ap;
+
+ if (acl_special(entry, type, permset, tag) == 0)
+ return;
+ ap = acl_new_entry(entry, type, permset, tag, id);
+ if (ap == NULL) {
+ /* XXX Error XXX */
+ return;
+ }
+ if (name != NULL && *name != L'\0')
+ aes_copy_wcs(&ap->name, name);
+ else
+ aes_clean(&ap->name);
+}
+
+/*
+ * If this ACL entry is part of the standard POSIX permissions set,
+ * store the permissions in the stat structure and return zero.
+ */
+static int
+acl_special(struct archive_entry *entry, int type, int permset, int tag)
+{
+ if (type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS) {
+ switch (tag) {
+ case ARCHIVE_ENTRY_ACL_USER_OBJ:
+ entry->ae_stat.st_mode &= ~0700;
+ entry->ae_stat.st_mode |= (permset & 7) << 6;
+ return (0);
+ case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
+ entry->ae_stat.st_mode &= ~0070;
+ entry->ae_stat.st_mode |= (permset & 7) << 3;
+ return (0);
+ case ARCHIVE_ENTRY_ACL_OTHER:
+ entry->ae_stat.st_mode &= ~0007;
+ entry->ae_stat.st_mode |= permset & 7;
+ return (0);
+ }
+ }
+ return (1);
+}
+
+/*
+ * Allocate and populate a new ACL entry with everything but the
+ * name.
+ */
+static struct ae_acl *
+acl_new_entry(struct archive_entry *entry,
+ int type, int permset, int tag, int id)
+{
+ struct ae_acl *ap;
+
+ if (type != ARCHIVE_ENTRY_ACL_TYPE_ACCESS &&
+ type != ARCHIVE_ENTRY_ACL_TYPE_DEFAULT)
+ return (NULL);
+ if (entry->acl_text_w != NULL) {
+ free(entry->acl_text_w);
+ entry->acl_text_w = NULL;
+ }
+
+ /* XXX TODO: More sanity-checks on the arguments XXX */
+
+ /* If there's a matching entry already in the list, overwrite it. */
+ for (ap = entry->acl_head; ap != NULL; ap = ap->next) {
+ if (ap->type == type && ap->tag == tag && ap->id == id) {
+ ap->permset = permset;
+ return (ap);
+ }
+ }
+
+ /* Add a new entry to the list. */
+ ap = malloc(sizeof(*ap));
+ if (ap == NULL)
+ return (NULL);
+ memset(ap, 0, sizeof(*ap));
+ ap->next = entry->acl_head;
+ entry->acl_head = ap;
+ ap->type = type;
+ ap->tag = tag;
+ ap->id = id;
+ ap->permset = permset;
+ return (ap);
+}
+
+/*
+ * Return a count of entries matching "want_type".
+ */
+int
+archive_entry_acl_count(struct archive_entry *entry, int want_type)
+{
+ int count;
+ struct ae_acl *ap;
+
+ count = 0;
+ ap = entry->acl_head;
+ while (ap != NULL) {
+ if ((ap->type & want_type) != 0)
+ count++;
+ ap = ap->next;
+ }
+
+ if (count > 0 && ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0))
+ count += 3;
+ return (count);
+}
+
+/*
+ * Prepare for reading entries from the ACL data. Returns a count
+ * of entries matching "want_type", or zero if there are no
+ * non-extended ACL entries of that type.
+ */
+int
+archive_entry_acl_reset(struct archive_entry *entry, int want_type)
+{
+ int count, cutoff;
+
+ count = archive_entry_acl_count(entry, want_type);
+
+ /*
+ * If the only entries are the three standard ones,
+ * then don't return any ACL data. (In this case,
+ * client can just use chmod(2) to set permissions.)
+ */
+ if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0)
+ cutoff = 3;
+ else
+ cutoff = 0;
+
+ if (count > cutoff)
+ entry->acl_state = ARCHIVE_ENTRY_ACL_USER_OBJ;
+ else
+ entry->acl_state = 0;
+ entry->acl_p = entry->acl_head;
+ return (count);
+}
+
+/*
+ * Return the next ACL entry in the list. Fake entries for the
+ * standard permissions and include them in the returned list.
+ */
+
+int
+archive_entry_acl_next(struct archive_entry *entry, int want_type, int *type,
+ int *permset, int *tag, int *id, const char **name)
+{
+ *name = NULL;
+ *id = -1;
+
+ /*
+ * The acl_state is either zero (no entries available), -1
+ * (reading from list), or an entry type (retrieve that type
+ * from ae_stat.st_mode).
+ */
+ if (entry->acl_state == 0)
+ return (ARCHIVE_WARN);
+
+ /* The first three access entries are special. */
+ if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
+ switch (entry->acl_state) {
+ case ARCHIVE_ENTRY_ACL_USER_OBJ:
+ *permset = (entry->ae_stat.st_mode >> 6) & 7;
+ *type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
+ *tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
+ entry->acl_state = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
+ return (ARCHIVE_OK);
+ case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
+ *permset = (entry->ae_stat.st_mode >> 3) & 7;
+ *type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
+ *tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
+ entry->acl_state = ARCHIVE_ENTRY_ACL_OTHER;
+ return (ARCHIVE_OK);
+ case ARCHIVE_ENTRY_ACL_OTHER:
+ *permset = entry->ae_stat.st_mode & 7;
+ *type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
+ *tag = ARCHIVE_ENTRY_ACL_OTHER;
+ entry->acl_state = -1;
+ entry->acl_p = entry->acl_head;
+ return (ARCHIVE_OK);
+ default:
+ break;
+ }
+ }
+
+ while (entry->acl_p != NULL && (entry->acl_p->type & want_type) == 0)
+ entry->acl_p = entry->acl_p->next;
+ if (entry->acl_p == NULL) {
+ entry->acl_state = 0;
+ return (ARCHIVE_WARN);
+ }
+ *type = entry->acl_p->type;
+ *permset = entry->acl_p->permset;
+ *tag = entry->acl_p->tag;
+ *id = entry->acl_p->id;
+ *name = aes_get_mbs(&entry->acl_p->name);
+ entry->acl_p = entry->acl_p->next;
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Generate a text version of the ACL. The flags parameter controls
+ * the style of the generated ACL.
+ */
+const wchar_t *
+archive_entry_acl_text_w(struct archive_entry *entry, int flags)
+{
+ int count;
+ int length;
+ const wchar_t *wname;
+ const wchar_t *prefix;
+ wchar_t separator;
+ struct ae_acl *ap;
+ int id;
+ wchar_t *wp;
+
+ if (entry->acl_text_w != NULL) {
+ free (entry->acl_text_w);
+ entry->acl_text_w = NULL;
+ }
+
+ separator = L',';
+ count = 0;
+ length = 0;
+ ap = entry->acl_head;
+ while (ap != NULL) {
+ if ((ap->type & flags) != 0) {
+ count++;
+ if ((flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) &&
+ (ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT))
+ length += 8; /* "default:" */
+ length += 5; /* tag name */
+ length += 1; /* colon */
+ wname = aes_get_wcs(&ap->name);
+ if (wname != NULL)
+ length += wcslen(wname);
+ length ++; /* colon */
+ length += 3; /* rwx */
+ length += 1; /* colon */
+ length += max(sizeof(uid_t), sizeof(gid_t)) * 3 + 1;
+ length ++; /* newline */
+ }
+ ap = ap->next;
+ }
+
+ if (count > 0 && ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0)) {
+ length += 10; /* "user::rwx\n" */
+ length += 11; /* "group::rwx\n" */
+ length += 11; /* "other::rwx\n" */
+ }
+
+ if (count == 0)
+ return (NULL);
+
+ /* Now, allocate the string and actually populate it. */
+ wp = entry->acl_text_w = malloc(length * sizeof(wchar_t));
+ if (wp == NULL)
+ __archive_errx(1, "No memory to generate the text version of the ACL");
+ count = 0;
+ if ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
+ append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_USER_OBJ, NULL,
+ entry->ae_stat.st_mode & 0700, -1);
+ *wp++ = ',';
+ append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_GROUP_OBJ, NULL,
+ entry->ae_stat.st_mode & 0070, -1);
+ *wp++ = ',';
+ append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_OTHER, NULL,
+ entry->ae_stat.st_mode & 0007, -1);
+ count += 3;
+
+ ap = entry->acl_head;
+ while (ap != NULL) {
+ if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
+ wname = aes_get_wcs(&ap->name);
+ *wp++ = separator;
+ if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)
+ id = ap->id;
+ else
+ id = -1;
+ append_entry_w(&wp, NULL, ap->tag, wname,
+ ap->permset, id);
+ count++;
+ }
+ ap = ap->next;
+ }
+ }
+
+
+ if ((flags & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) {
+ if (flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT)
+ prefix = L"default:";
+ else
+ prefix = NULL;
+ ap = entry->acl_head;
+ count = 0;
+ while (ap != NULL) {
+ if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) {
+ wname = aes_get_wcs(&ap->name);
+ if (count > 0)
+ *wp++ = separator;
+ if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)
+ id = ap->id;
+ else
+ id = -1;
+ append_entry_w(&wp, prefix, ap->tag,
+ wname, ap->permset, id);
+ count ++;
+ }
+ ap = ap->next;
+ }
+ }
+
+ return (entry->acl_text_w);
+}
+
+static void
+append_id_w(wchar_t **wp, int id)
+{
+ if (id > 9)
+ append_id_w(wp, id / 10);
+ *(*wp)++ = L"0123456789"[id % 10];
+}
+
+static void
+append_entry_w(wchar_t **wp, const wchar_t *prefix, int tag,
+ const wchar_t *wname, int perm, int id)
+{
+ if (prefix != NULL) {
+ wcscpy(*wp, prefix);
+ *wp += wcslen(*wp);
+ }
+ switch (tag) {
+ case ARCHIVE_ENTRY_ACL_USER_OBJ:
+ wname = NULL;
+ id = -1;
+ /* FALL THROUGH */
+ case ARCHIVE_ENTRY_ACL_USER:
+ wcscpy(*wp, L"user");
+ break;
+ case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
+ wname = NULL;
+ id = -1;
+ /* FALL THROUGH */
+ case ARCHIVE_ENTRY_ACL_GROUP:
+ wcscpy(*wp, L"group");
+ break;
+ case ARCHIVE_ENTRY_ACL_MASK:
+ wcscpy(*wp, L"mask");
+ wname = NULL;
+ id = -1;
+ break;
+ case ARCHIVE_ENTRY_ACL_OTHER:
+ wcscpy(*wp, L"other");
+ wname = NULL;
+ id = -1;
+ break;
+ }
+ *wp += wcslen(*wp);
+ *(*wp)++ = L':';
+ if (wname != NULL) {
+ wcscpy(*wp, wname);
+ *wp += wcslen(*wp);
+ }
+ *(*wp)++ = L':';
+ *(*wp)++ = (perm & 0444) ? L'r' : L'-';
+ *(*wp)++ = (perm & 0222) ? L'w' : L'-';
+ *(*wp)++ = (perm & 0111) ? L'x' : L'-';
+ if (id != -1) {
+ *(*wp)++ = L':';
+ append_id_w(wp, id);
+ }
+ **wp = L'\0';
+}
+
+/*
+ * Parse a textual ACL. This automatically recognizes and supports
+ * extensions described above. The 'type' argument is used to
+ * indicate the type that should be used for any entries not
+ * explicitly marked as "default:".
+ */
+int
+__archive_entry_acl_parse_w(struct archive_entry *entry,
+ const wchar_t *text, int default_type)
+{
+ int type, tag, permset, id;
+ const wchar_t *start, *end;
+ const wchar_t *name_start, *name_end;
+ wchar_t sep;
+ wchar_t *namebuff;
+ int namebuff_length;
+
+ name_start = name_end = NULL;
+ namebuff = NULL;
+ namebuff_length = 0;
+
+ while (text != NULL && *text != L'\0') {
+ next_field_w(&text, &start, &end, &sep);
+ if (sep != L':')
+ goto fail;
+
+ /*
+ * Solaris extension: "defaultuser::rwx" is the
+ * default ACL corresponding to "user::rwx", etc.
+ */
+ if (end-start > 7 && wmemcmp(start, L"default", 7) == 0) {
+ type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT;
+ start += 7;
+ } else
+ type = default_type;
+
+ if (prefix_w(start, end, L"user")) {
+ next_field_w(&text, &start, &end, &sep);
+ if (sep != L':')
+ goto fail;
+ if (end > start) {
+ tag = ARCHIVE_ENTRY_ACL_USER;
+ name_start = start;
+ name_end = end;
+ } else
+ tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
+ } else if (prefix_w(start, end, L"group")) {
+ next_field_w(&text, &start, &end, &sep);
+ if (sep != L':')
+ goto fail;
+ if (end > start) {
+ tag = ARCHIVE_ENTRY_ACL_GROUP;
+ name_start = start;
+ name_end = end;
+ } else
+ tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
+ } else if (prefix_w(start, end, L"other")) {
+ next_field_w(&text, &start, &end, &sep);
+ if (sep != L':')
+ goto fail;
+ if (end > start)
+ goto fail;
+ tag = ARCHIVE_ENTRY_ACL_OTHER;
+ } else if (prefix_w(start, end, L"mask")) {
+ next_field_w(&text, &start, &end, &sep);
+ if (sep != L':')
+ goto fail;
+ if (end > start)
+ goto fail;
+ tag = ARCHIVE_ENTRY_ACL_MASK;
+ } else
+ goto fail;
+
+ next_field_w(&text, &start, &end, &sep);
+ permset = 0;
+ while (start < end) {
+ switch (*start++) {
+ case 'r': case 'R':
+ permset |= ARCHIVE_ENTRY_ACL_READ;
+ break;
+ case 'w': case 'W':
+ permset |= ARCHIVE_ENTRY_ACL_WRITE;
+ break;
+ case 'x': case 'X':
+ permset |= ARCHIVE_ENTRY_ACL_EXECUTE;
+ break;
+ case '-':
+ break;
+ default:
+ goto fail;
+ }
+ }
+
+ /*
+ * Support star-compatible numeric UID/GID extension.
+ * This extension adds a ":" followed by the numeric
+ * ID so that "group:groupname:rwx", for example,
+ * becomes "group:groupname:rwx:999", where 999 is the
+ * numeric GID. This extension makes it possible, for
+ * example, to correctly restore ACLs on a system that
+ * might have a damaged passwd file or be disconnected
+ * from a central NIS server. This extension is compatible
+ * with POSIX.1e draft 17.
+ */
+ if (sep == L':' && (tag == ARCHIVE_ENTRY_ACL_USER ||
+ tag == ARCHIVE_ENTRY_ACL_GROUP)) {
+ next_field_w(&text, &start, &end, &sep);
+
+ id = 0;
+ while (start < end && *start >= '0' && *start <= '9') {
+ if (id > (INT_MAX / 10))
+ id = INT_MAX;
+ else {
+ id *= 10;
+ id += *start - '0';
+ start++;
+ }
+ }
+ } else
+ id = -1; /* No id specified. */
+
+ /* Skip any additional entries. */
+ while (sep == L':') {
+ next_field_w(&text, &start, &end, &sep);
+ }
+
+ /* Add entry to the internal list. */
+ if (name_end == name_start) {
+ archive_entry_acl_add_entry_w(entry, type, permset,
+ tag, id, NULL);
+ } else {
+ if (namebuff_length <= name_end - name_start) {
+ if (namebuff != NULL)
+ free(namebuff);
+ namebuff_length = name_end - name_start + 256;
+ namebuff =
+ malloc(namebuff_length * sizeof(wchar_t));
+ if (namebuff == NULL)
+ goto fail;
+ }
+ wmemcpy(namebuff, name_start, name_end - name_start);
+ namebuff[name_end - name_start] = L'\0';
+ archive_entry_acl_add_entry_w(entry, type,
+ permset, tag, id, namebuff);
+ }
+ }
+ if (namebuff != NULL)
+ free(namebuff);
+ return (ARCHIVE_OK);
+
+fail:
+ if (namebuff != NULL)
+ free(namebuff);
+ return (ARCHIVE_WARN);
+}
+
+/*
+ * extended attribute handling
+ */
+
+void
+archive_entry_xattr_clear(struct archive_entry *entry)
+{
+ struct ae_xattr *xp;
+
+ while (entry->xattr_head != NULL) {
+ xp = entry->xattr_head->next;
+ free(entry->xattr_head->name);
+ free(entry->xattr_head->value);
+ free(entry->xattr_head);
+ entry->xattr_head = xp;
+ }
+
+ entry->xattr_head = NULL;
+}
+
+void
+archive_entry_xattr_add_entry(struct archive_entry *entry,
+ const char *name, const void *value, size_t size)
+{
+ struct ae_xattr *xp;
+
+ for (xp = entry->xattr_head; xp != NULL; xp = xp->next)
+ ;
+
+ if ((xp = malloc(sizeof(struct ae_xattr))) == NULL)
+ /* XXX Error XXX */
+ return;
+
+ xp->name = strdup(name);
+ if ((xp -> value = malloc(size)) != NULL) {
+ memcpy(xp -> value, value, size);
+ xp -> size = size;
+ } else
+ xp -> size = 0;
+
+ xp->next = entry->xattr_head;
+ entry->xattr_head = xp;
+}
+
+
+/*
+ * returns number of the extended attribute entries
+ */
+int
+archive_entry_xattr_count(struct archive_entry *entry)
+{
+ struct ae_xattr *xp;
+ int count = 0;
+
+ for (xp = entry->xattr_head; xp != NULL; xp = xp->next)
+ count++;
+
+ return count;
+}
+
+int
+archive_entry_xattr_reset(struct archive_entry * entry)
+{
+ entry->xattr_p = entry->xattr_head;
+
+ return archive_entry_xattr_count(entry);
+}
+
+int
+archive_entry_xattr_next(struct archive_entry * entry,
+ const char **name, const void **value, size_t *size)
+{
+ if (entry->xattr_p) {
+ *name = entry->xattr_p->name;
+ *value = entry->xattr_p->value;
+ *size = entry->xattr_p->size;
+
+ entry->xattr_p = entry->xattr_p->next;
+
+ return (ARCHIVE_OK);
+ } else {
+ *name = NULL;
+ *name = NULL;
+ *size = (size_t)0;
+ return (ARCHIVE_WARN);
+ }
+}
+
+/*
+ * end of xattr handling
+ */
+
+/*
+ * Match "[:whitespace:]*(.*)[:whitespace:]*[:,\n]". *wp is updated
+ * to point to just after the separator. *start points to the first
+ * character of the matched text and *end just after the last
+ * character of the matched identifier. In particular *end - *start
+ * is the length of the field body, not including leading or trailing
+ * whitespace.
+ */
+static void
+next_field_w(const wchar_t **wp, const wchar_t **start,
+ const wchar_t **end, wchar_t *sep)
+{
+ /* Skip leading whitespace to find start of field. */
+ while (**wp == L' ' || **wp == L'\t' || **wp == L'\n') {
+ (*wp)++;
+ }
+ *start = *wp;
+
+ /* Scan for the separator. */
+ while (**wp != L'\0' && **wp != L',' && **wp != L':' &&
+ **wp != L'\n') {
+ (*wp)++;
+ }
+ *sep = **wp;
+
+ /* Trim trailing whitespace to locate end of field. */
+ *end = *wp - 1;
+ while (**end == L' ' || **end == L'\t' || **end == L'\n') {
+ (*end)--;
+ }
+ (*end)++;
+
+ /* Adjust scanner location. */
+ if (**wp != L'\0')
+ (*wp)++;
+}
+
+static int
+prefix_w(const wchar_t *start, const wchar_t *end, const wchar_t *test)
+{
+ if (start == end)
+ return (0);
+
+ if (*start++ != *test++)
+ return (0);
+
+ while (start < end && *start++ == *test++)
+ ;
+
+ if (start < end)
+ return (0);
+
+ return (1);
+}
+
+
+/*
+ * Following code is modified from UC Berkeley sources, and
+ * is subject to the following copyright notice.
+ */
+
+/*-
+ * 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.
+ */
+
+static struct flag {
+ const char *name;
+ const wchar_t *wname;
+ unsigned long set;
+ unsigned long clear;
+} flags[] = {
+ /* Preferred (shorter) names per flag first, all prefixed by "no" */
+#ifdef SF_APPEND
+ { "nosappnd", L"nosappnd", SF_APPEND, 0 },
+ { "nosappend", L"nosappend", SF_APPEND, 0 },
+#endif
+#ifdef EXT2_APPEND_FL /* 'a' */
+ { "nosappnd", L"nosappnd", EXT2_APPEND_FL, 0 },
+ { "nosappend", L"nosappend", EXT2_APPEND_FL, 0 },
+#endif
+#ifdef SF_ARCHIVED
+ { "noarch", L"noarch", SF_ARCHIVED, 0 },
+ { "noarchived", L"noarchived", SF_ARCHIVED, 0 },
+#endif
+#ifdef SF_IMMUTABLE
+ { "noschg", L"noschg", SF_IMMUTABLE, 0 },
+ { "noschange", L"noschange", SF_IMMUTABLE, 0 },
+ { "nosimmutable", L"nosimmutable", SF_IMMUTABLE, 0 },
+#endif
+#ifdef EXT2_IMMUTABLE_FL /* 'i' */
+ { "noschg", L"noschg", EXT2_IMMUTABLE_FL, 0 },
+ { "noschange", L"noschange", EXT2_IMMUTABLE_FL, 0 },
+ { "nosimmutable", L"nosimmutable", EXT2_IMMUTABLE_FL, 0 },
+#endif
+#ifdef SF_NOUNLINK
+ { "nosunlnk", L"nosunlnk", SF_NOUNLINK, 0 },
+ { "nosunlink", L"nosunlink", SF_NOUNLINK, 0 },
+#endif
+#ifdef SF_SNAPSHOT
+ { "nosnapshot", L"nosnapshot", SF_SNAPSHOT, 0 },
+#endif
+#ifdef UF_APPEND
+ { "nouappnd", L"nouappnd", UF_APPEND, 0 },
+ { "nouappend", L"nouappend", UF_APPEND, 0 },
+#endif
+#ifdef UF_IMMUTABLE
+ { "nouchg", L"nouchg", UF_IMMUTABLE, 0 },
+ { "nouchange", L"nouchange", UF_IMMUTABLE, 0 },
+ { "nouimmutable", L"nouimmutable", UF_IMMUTABLE, 0 },
+#endif
+#ifdef UF_NODUMP
+ { "nodump", L"nodump", 0, UF_NODUMP},
+#endif
+#ifdef EXT2_NODUMP_FL /* 'd' */
+ { "nodump", L"nodump", 0, EXT2_NODUMP_FL},
+#endif
+#ifdef UF_OPAQUE
+ { "noopaque", L"noopaque", UF_OPAQUE, 0 },
+#endif
+#ifdef UF_NOUNLINK
+ { "nouunlnk", L"nouunlnk", UF_NOUNLINK, 0 },
+ { "nouunlink", L"nouunlink", UF_NOUNLINK, 0 },
+#endif
+#ifdef EXT2_COMPR_FL /* 'c' */
+ { "nocompress", L"nocompress", EXT2_COMPR_FL, 0 },
+#endif
+
+#ifdef EXT2_NOATIME_FL /* 'A' */
+ { "noatime", L"noatime", 0, EXT2_NOATIME_FL},
+#endif
+ { NULL, NULL, 0, 0 }
+};
+
+/*
+ * fflagstostr --
+ * Convert file flags to a comma-separated string. If no flags
+ * are set, return the empty string.
+ */
+char *
+ae_fflagstostr(unsigned long bitset, unsigned long bitclear)
+{
+ char *string, *dp;
+ const char *sp;
+ unsigned long bits;
+ struct flag *flag;
+ int length;
+
+ bits = bitset | bitclear;
+ length = 0;
+ for (flag = flags; flag->name != NULL; flag++)
+ if (bits & (flag->set | flag->clear)) {
+ length += strlen(flag->name) + 1;
+ bits &= ~(flag->set | flag->clear);
+ }
+
+ if (length == 0)
+ return (NULL);
+ string = malloc(length);
+ if (string == NULL)
+ return (NULL);
+
+ dp = string;
+ for (flag = flags; flag->name != NULL; flag++) {
+ if (bitset & flag->set || bitclear & flag->clear) {
+ sp = flag->name + 2;
+ } else if (bitset & flag->clear || bitclear & flag->set) {
+ sp = flag->name;
+ } else
+ continue;
+ bitset &= ~(flag->set | flag->clear);
+ bitclear &= ~(flag->set | flag->clear);
+ if (dp > string)
+ *dp++ = ',';
+ while ((*dp++ = *sp++) != '\0')
+ ;
+ dp--;
+ }
+
+ *dp = '\0';
+ return (string);
+}
+
+/*
+ * wcstofflags --
+ * Take string of arguments and return file flags. This
+ * version works a little differently than strtofflags(3).
+ * In particular, it always tests every token, skipping any
+ * unrecognized tokens. It returns a pointer to the first
+ * unrecognized token, or NULL if every token was recognized.
+ * This version is also const-correct and does not modify the
+ * provided string.
+ */
+const wchar_t *
+ae_wcstofflags(const wchar_t *s, unsigned long *setp, unsigned long *clrp)
+{
+ const wchar_t *start, *end;
+ struct flag *flag;
+ unsigned long set, clear;
+ const wchar_t *failed;
+
+ set = clear = 0;
+ start = s;
+ failed = NULL;
+ /* Find start of first token. */
+ while (*start == L'\t' || *start == L' ' || *start == L',')
+ start++;
+ while (*start != L'\0') {
+ /* Locate end of token. */
+ end = start;
+ while (*end != L'\0' && *end != L'\t' &&
+ *end != L' ' && *end != L',')
+ end++;
+ for (flag = flags; flag->wname != NULL; flag++) {
+ if (wmemcmp(start, flag->wname, end - start) == 0) {
+ /* Matched "noXXXX", so reverse the sense. */
+ clear |= flag->set;
+ set |= flag->clear;
+ break;
+ } else if (wmemcmp(start, flag->wname + 2, end - start)
+ == 0) {
+ /* Matched "XXXX", so don't reverse. */
+ set |= flag->set;
+ clear |= flag->clear;
+ break;
+ }
+ }
+ /* Ignore unknown flag names. */
+ if (flag->wname == NULL && failed == NULL)
+ failed = start;
+
+ /* Find start of next token. */
+ start = end;
+ while (*start == L'\t' || *start == L' ' || *start == L',')
+ start++;
+
+ }
+
+ if (setp)
+ *setp = set;
+ if (clrp)
+ *clrp = clear;
+
+ /* Return location of first failure. */
+ return (failed);
+}
+
+
+#ifdef TEST
+#include <stdio.h>
+int
+main(int argc, char **argv)
+{
+ struct archive_entry *entry = archive_entry_new();
+ unsigned long set, clear;
+ const wchar_t *remainder;
+
+ remainder = archive_entry_copy_fflags_text_w(entry, L"nosappnd dump archive,,,,,,,");
+ archive_entry_fflags(entry, &set, &clear);
+
+ wprintf(L"set=0x%lX clear=0x%lX remainder='%ls'\n", set, clear, remainder);
+
+ wprintf(L"new flags='%s'\n", archive_entry_fflags_text(entry));
+ return (0);
+}
+#endif
diff --git a/lib/libarchive/archive_entry.h b/lib/libarchive/archive_entry.h
new file mode 100644
index 0000000..3c3f73d
--- /dev/null
+++ b/lib/libarchive/archive_entry.h
@@ -0,0 +1,251 @@
+/*-
+ * Copyright (c) 2003-2004 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(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 AUTHOR(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$
+ */
+
+#ifndef ARCHIVE_ENTRY_H_INCLUDED
+#define ARCHIVE_ENTRY_H_INCLUDED
+
+#include <stddef.h> /* for wchar_t */
+#include <unistd.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ * Description of an archive entry.
+ *
+ * Basically, a "struct stat" with a few text fields added in.
+ *
+ * TODO: Add "comment", "charset", and possibly other entries that are
+ * supported by "pax interchange" format. However, GNU, ustar, cpio,
+ * and other variants don't support these features, so they're not an
+ * excruciatingly high priority right now.
+ *
+ * TODO: "pax interchange" format allows essentially arbitrary
+ * key/value attributes to be attached to any entry. Supporting
+ * such extensions may make this library useful for special
+ * applications (e.g., a package manager could attach special
+ * package-management attributes to each entry).
+ */
+struct archive_entry;
+
+/*
+ * Basic object manipulation
+ */
+
+struct archive_entry *archive_entry_clear(struct archive_entry *);
+/* The 'clone' function does a deep copy; all of the strings are copied too. */
+struct archive_entry *archive_entry_clone(struct archive_entry *);
+void archive_entry_free(struct archive_entry *);
+struct archive_entry *archive_entry_new(void);
+
+/*
+ * Retrieve fields from an archive_entry.
+ */
+
+time_t archive_entry_atime(struct archive_entry *);
+long archive_entry_atime_nsec(struct archive_entry *);
+time_t archive_entry_ctime(struct archive_entry *);
+long archive_entry_ctime_nsec(struct archive_entry *);
+dev_t archive_entry_dev(struct archive_entry *);
+void archive_entry_fflags(struct archive_entry *,
+ unsigned long *set, unsigned long *clear);
+const char *archive_entry_fflags_text(struct archive_entry *);
+gid_t archive_entry_gid(struct archive_entry *);
+const char *archive_entry_gname(struct archive_entry *);
+const wchar_t *archive_entry_gname_w(struct archive_entry *);
+const char *archive_entry_hardlink(struct archive_entry *);
+const wchar_t *archive_entry_hardlink_w(struct archive_entry *);
+ino_t archive_entry_ino(struct archive_entry *);
+mode_t archive_entry_mode(struct archive_entry *);
+time_t archive_entry_mtime(struct archive_entry *);
+long archive_entry_mtime_nsec(struct archive_entry *);
+const char *archive_entry_pathname(struct archive_entry *);
+const wchar_t *archive_entry_pathname_w(struct archive_entry *);
+dev_t archive_entry_rdev(struct archive_entry *);
+dev_t archive_entry_rdevmajor(struct archive_entry *);
+dev_t archive_entry_rdevminor(struct archive_entry *);
+int64_t archive_entry_size(struct archive_entry *);
+const struct stat *archive_entry_stat(struct archive_entry *);
+const char *archive_entry_symlink(struct archive_entry *);
+const wchar_t *archive_entry_symlink_w(struct archive_entry *);
+uid_t archive_entry_uid(struct archive_entry *);
+const char *archive_entry_uname(struct archive_entry *);
+const wchar_t *archive_entry_uname_w(struct archive_entry *);
+
+/*
+ * Set fields in an archive_entry.
+ *
+ * Note that string 'set' functions do not copy the string, only the pointer.
+ * In contrast, 'copy' functions do copy the object pointed to.
+ */
+
+void archive_entry_copy_stat(struct archive_entry *, const struct stat *);
+void archive_entry_set_atime(struct archive_entry *, time_t, long);
+void archive_entry_set_ctime(struct archive_entry *, time_t, long);
+void archive_entry_set_fflags(struct archive_entry *,
+ unsigned long set, unsigned long clear);
+/* Returns pointer to start of first invalid token, or NULL if none. */
+/* Note that all recognized tokens are processed, regardless. */
+const wchar_t *archive_entry_copy_fflags_text_w(struct archive_entry *,
+ const wchar_t *);
+void archive_entry_set_gid(struct archive_entry *, gid_t);
+void archive_entry_set_gname(struct archive_entry *, const char *);
+void archive_entry_copy_gname_w(struct archive_entry *, const wchar_t *);
+void archive_entry_set_hardlink(struct archive_entry *, const char *);
+void archive_entry_copy_hardlink(struct archive_entry *, const char *);
+void archive_entry_copy_hardlink_w(struct archive_entry *, const wchar_t *);
+void archive_entry_set_link(struct archive_entry *, const char *);
+void archive_entry_set_mode(struct archive_entry *, mode_t);
+void archive_entry_set_mtime(struct archive_entry *, time_t, long);
+void archive_entry_set_pathname(struct archive_entry *, const char *);
+void archive_entry_copy_pathname(struct archive_entry *, const char *);
+void archive_entry_copy_pathname_w(struct archive_entry *, const wchar_t *);
+void archive_entry_set_rdevmajor(struct archive_entry *, dev_t);
+void archive_entry_set_rdevminor(struct archive_entry *, dev_t);
+void archive_entry_set_size(struct archive_entry *, int64_t);
+void archive_entry_set_symlink(struct archive_entry *, const char *);
+void archive_entry_copy_symlink_w(struct archive_entry *, const wchar_t *);
+void archive_entry_set_uid(struct archive_entry *, uid_t);
+void archive_entry_set_uname(struct archive_entry *, const char *);
+void archive_entry_copy_uname_w(struct archive_entry *, const wchar_t *);
+
+/*
+ * ACL routines. This used to simply store and return text-format ACL
+ * strings, but that proved insufficient for a number of reasons:
+ * = clients need control over uname/uid and gname/gid mappings
+ * = there are many different ACL text formats
+ * = would like to be able to read/convert archives containing ACLs
+ * on platforms that lack ACL libraries
+ */
+
+/*
+ * Permission bits mimic POSIX.1e. Note that I've not followed POSIX.1e's
+ * "permset"/"perm" abstract type nonsense. A permset is just a simple
+ * bitmap, following long-standing Unix tradition.
+ */
+#define ARCHIVE_ENTRY_ACL_EXECUTE 1
+#define ARCHIVE_ENTRY_ACL_WRITE 2
+#define ARCHIVE_ENTRY_ACL_READ 4
+
+/* We need to be able to specify either or both of these. */
+#define ARCHIVE_ENTRY_ACL_TYPE_ACCESS 256
+#define ARCHIVE_ENTRY_ACL_TYPE_DEFAULT 512
+
+/* Tag values mimic POSIX.1e */
+#define ARCHIVE_ENTRY_ACL_USER 10001 /* Specified user. */
+#define ARCHIVE_ENTRY_ACL_USER_OBJ 10002 /* User who owns the file. */
+#define ARCHIVE_ENTRY_ACL_GROUP 10003 /* Specified group. */
+#define ARCHIVE_ENTRY_ACL_GROUP_OBJ 10004 /* Group who owns the file. */
+#define ARCHIVE_ENTRY_ACL_MASK 10005 /* Modify group access. */
+#define ARCHIVE_ENTRY_ACL_OTHER 10006 /* Public. */
+
+/*
+ * Set the ACL by clearing it and adding entries one at a time.
+ * Unlike the POSIX.1e ACL routines, you must specify the type
+ * (access/default) for each entry. Internally, the ACL data is just
+ * a soup of entries. API calls here allow you to retrieve just the
+ * entries of interest. This design (which goes against the spirit of
+ * POSIX.1e) is useful for handling archive formats that combine
+ * default and access information in a single ACL list.
+ */
+void archive_entry_acl_clear(struct archive_entry *);
+void archive_entry_acl_add_entry(struct archive_entry *,
+ int type, int permset, int tag, int qual, const char *name);
+void archive_entry_acl_add_entry_w(struct archive_entry *,
+ int type, int permset, int tag, int qual, const wchar_t *name);
+
+/*
+ * To retrieve the ACL, first "reset", then repeatedly ask for the
+ * "next" entry. The want_type parameter allows you to request only
+ * access entries or only default entries.
+ */
+int archive_entry_acl_reset(struct archive_entry *, int want_type);
+int archive_entry_acl_next(struct archive_entry *, int want_type,
+ int *type, int *permset, int *tag, int *qual, const char **name);
+int archive_entry_acl_next_w(struct archive_entry *, int want_type,
+ int *type, int *permset, int *tag, int *qual,
+ const wchar_t **name);
+
+/*
+ * Construct a text-format ACL. The flags argument is a bitmask that
+ * can include any of the following:
+ *
+ * ARCHIVE_ENTRY_ACL_TYPE_ACCESS - Include access entries.
+ * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT - Include default entries.
+ * ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID - Include extra numeric ID field in
+ * each ACL entry. (As used by 'star'.)
+ * ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT - Include "default:" before each
+ * default ACL entry.
+ */
+#define ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID 1024
+#define ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT 2048
+const wchar_t *archive_entry_acl_text_w(struct archive_entry *, int flags);
+
+/* Return a count of entries matching 'want_type' */
+int archive_entry_acl_count(struct archive_entry *, int want_type);
+
+/*
+ * Private ACL parser. This is private because it handles some
+ * very weird formats that clients should not be messing with.
+ * Clients should only deal with their platform-native formats.
+ * Because of the need to support many formats cleanly, new arguments
+ * are likely to get added on a regular basis. Clients who try to use
+ * this interface are likely to be surprised when it changes.
+ *
+ * You were warned!
+ */
+int __archive_entry_acl_parse_w(struct archive_entry *,
+ const wchar_t *, int type);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+/*
+ * extended attributes
+ */
+
+void archive_entry_xattr_clear(struct archive_entry *);
+void archive_entry_xattr_add_entry(struct archive_entry *,
+ const char *name, const void *value, size_t size);
+
+/*
+ * To retrieve the xattr list, first "reset", then repeatedly ask for the
+ * "next" entry.
+ */
+
+int archive_entry_xattr_count(struct archive_entry *);
+int archive_entry_xattr_reset(struct archive_entry *);
+int archive_entry_xattr_next(struct archive_entry *,
+ const char **name, const void **value, size_t *);
+
+
+#endif /* !ARCHIVE_ENTRY_H_INCLUDED */
diff --git a/lib/libarchive/archive_platform.h b/lib/libarchive/archive_platform.h
new file mode 100644
index 0000000..e49ab5e
--- /dev/null
+++ b/lib/libarchive/archive_platform.h
@@ -0,0 +1,193 @@
+/*-
+ * Copyright (c) 2003-2004 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(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 AUTHOR(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$
+ */
+
+/*
+ * This header is the first thing included in any of the libarchive
+ * source files. As far as possible, platform-specific issues should
+ * be dealt with here and not within individual source files. I'm
+ * actively trying to minimize #if blocks within the main source,
+ * since they obfuscate the code.
+ */
+
+#ifndef ARCHIVE_PLATFORM_H_INCLUDED
+#define ARCHIVE_PLATFORM_H_INCLUDED
+
+#if HAVE_CONFIG_H
+#include "../config.h"
+#else
+
+/* A default configuration for FreeBSD, used if there is no config.h. */
+#ifdef __FreeBSD__
+#if __FreeBSD__ > 4
+#define HAVE_ACL_CREATE_ENTRY 1
+#define HAVE_ACL_INIT 1
+#define HAVE_ACL_SET_FD 1
+#define HAVE_ACL_SET_FD_NP 1
+#define HAVE_ACL_SET_FILE 1
+#define HAVE_ACL_USER 1
+#endif
+#define HAVE_BZLIB_H 1
+#define HAVE_CHFLAGS 1
+#define HAVE_DECL_STRERROR_R 1
+#define HAVE_EFTYPE 1
+#define HAVE_EILSEQ 1
+#define HAVE_ERRNO_H 1
+#define HAVE_FCHDIR 1
+#define HAVE_FCHFLAGS 1
+#define HAVE_FCHMOD 1
+#define HAVE_FCHOWN 1
+#define HAVE_FCNTL_H 1
+#define HAVE_FUTIMES 1
+#define HAVE_INTTYPES_H 1
+#define HAVE_LCHFLAGS 1
+#define HAVE_LCHMOD 1
+#define HAVE_LCHOWN 1
+#define HAVE_LIMITS_H 1
+#define HAVE_LUTIMES 1
+#define HAVE_MALLOC 1
+#define HAVE_MEMMOVE 1
+#define HAVE_MEMORY_H 1
+#define HAVE_MEMSET 1
+#define HAVE_MKDIR 1
+#define HAVE_MKFIFO 1
+#define HAVE_PATHS_H 1
+#define HAVE_STDINT_H 1
+#define HAVE_STDLIB_H 1
+#define HAVE_STRCHR 1
+#define HAVE_STRDUP 1
+#define HAVE_STRERROR 1
+#define HAVE_STRERROR_R 1
+#define HAVE_STRINGS_H 1
+#define HAVE_STRING_H 1
+#define HAVE_STRRCHR 1
+#define HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC 1
+#define HAVE_STRUCT_STAT_ST_RDEV 1
+#define HAVE_SYS_ACL_H 1
+#define HAVE_SYS_IOCTL_H 1
+#define HAVE_SYS_STAT_H 1
+#define HAVE_SYS_TIME_H 1
+#define HAVE_SYS_TYPES_H 1
+#define HAVE_SYS_WAIT_H 1
+#define HAVE_TIMEGM 1
+#define HAVE_UNISTD_H 1
+#define HAVE_WCHAR_H 1
+#define HAVE_ZLIB_H 1
+#define STDC_HEADERS 1
+#define TIME_WITH_SYS_TIME 1
+#else /* !__FreeBSD__ */
+/* Warn if the library hasn't been (automatically or manually) configured. */
+#error Oops: No config.h and no built-in configuration in archive_platform.h.
+#endif /* !__FreeBSD__ */
+
+#endif /* !HAVE_CONFIG_H */
+
+/* No non-FreeBSD platform will have __FBSDID, so just define it here. */
+#ifdef __FreeBSD__
+#include <sys/cdefs.h> /* For __FBSDID */
+#else
+#define __FBSDID(a) /* null */
+#endif
+
+#if HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+/* FreeBSD 4 and earlier lack intmax_t/uintmax_t */
+#if defined(__FreeBSD__) && __FreeBSD__ < 5
+#define intmax_t int64_t
+#define uintmax_t uint64_t
+#endif
+
+/*
+ * If this platform has <sys/acl.h>, acl_create(), acl_init(),
+ * acl_set_file(), and ACL_USER, we assume it has the rest of the
+ * POSIX.1e draft functions used in archive_read_extract.c.
+ */
+#if HAVE_SYS_ACL_H && HAVE_ACL_CREATE_ENTRY && HAVE_ACL_INIT && HAVE_ACL_SET_FILE && HAVE_ACL_USER
+#define HAVE_POSIX_ACL 1
+#endif
+
+/*
+ * If we can't restore metadata using a file descriptor, then
+ * for compatibility's sake, close files before trying to restore metadata.
+ */
+#if defined(HAVE_FCHMOD) || defined(HAVE_FUTIMES) || defined(HAVE_ACL_SET_FD) || defined(HAVE_ACL_SET_FD_NP) || defined(HAVE_FCHOWN)
+#define CAN_RESTORE_METADATA_FD
+#endif
+
+/* Set up defaults for internal error codes. */
+#ifndef ARCHIVE_ERRNO_FILE_FORMAT
+#if HAVE_EFTYPE
+#define ARCHIVE_ERRNO_FILE_FORMAT EFTYPE
+#else
+#if HAVE_EILSEQ
+#define ARCHIVE_ERRNO_FILE_FORMAT EILSEQ
+#else
+#define ARCHIVE_ERRNO_FILE_FORMAT EINVAL
+#endif
+#endif
+#endif
+
+#ifndef ARCHIVE_ERRNO_PROGRAMMER
+#define ARCHIVE_ERRNO_PROGRAMMER EINVAL
+#endif
+
+#ifndef ARCHIVE_ERRNO_MISC
+#define ARCHIVE_ERRNO_MISC (-1)
+#endif
+
+/* Select the best way to set/get hi-res timestamps. */
+#if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC
+/* FreeBSD uses "timespec" members. */
+#define ARCHIVE_STAT_ATIME_NANOS(st) (st)->st_atimespec.tv_nsec
+#define ARCHIVE_STAT_CTIME_NANOS(st) (st)->st_ctimespec.tv_nsec
+#define ARCHIVE_STAT_MTIME_NANOS(st) (st)->st_mtimespec.tv_nsec
+#define ARCHIVE_STAT_SET_ATIME_NANOS(st, n) (st)->st_atimespec.tv_nsec = (n)
+#define ARCHIVE_STAT_SET_CTIME_NANOS(st, n) (st)->st_ctimespec.tv_nsec = (n)
+#define ARCHIVE_STAT_SET_MTIME_NANOS(st, n) (st)->st_mtimespec.tv_nsec = (n)
+#else
+#if HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
+/* Linux uses "tim" members. */
+#define ARCHIVE_STAT_ATIME_NANOS(pstat) (pstat)->st_atim.tv_nsec
+#define ARCHIVE_STAT_CTIME_NANOS(pstat) (pstat)->st_ctim.tv_nsec
+#define ARCHIVE_STAT_MTIME_NANOS(pstat) (pstat)->st_mtim.tv_nsec
+#define ARCHIVE_STAT_SET_ATIME_NANOS(st, n) (st)->st_atim.tv_nsec = (n)
+#define ARCHIVE_STAT_SET_CTIME_NANOS(st, n) (st)->st_ctim.tv_nsec = (n)
+#define ARCHIVE_STAT_SET_MTIME_NANOS(st, n) (st)->st_mtim.tv_nsec = (n)
+#else
+/* If we can't find a better way, just use stubs. */
+#define ARCHIVE_STAT_ATIME_NANOS(pstat) 0
+#define ARCHIVE_STAT_CTIME_NANOS(pstat) 0
+#define ARCHIVE_STAT_MTIME_NANOS(pstat) 0
+#define ARCHIVE_STAT_SET_ATIME_NANOS(st, n)
+#define ARCHIVE_STAT_SET_CTIME_NANOS(st, n)
+#define ARCHIVE_STAT_SET_MTIME_NANOS(st, n)
+#endif
+#endif
+
+#endif /* !ARCHIVE_H_INCLUDED */
diff --git a/lib/libarchive/archive_private.h b/lib/libarchive/archive_private.h
new file mode 100644
index 0000000..6b93820
--- /dev/null
+++ b/lib/libarchive/archive_private.h
@@ -0,0 +1,244 @@
+/*-
+ * Copyright (c) 2003-2004 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(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 AUTHOR(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$
+ */
+
+#ifndef ARCHIVE_PRIVATE_H_INCLUDED
+#define ARCHIVE_PRIVATE_H_INCLUDED
+
+#include "archive.h"
+#include "archive_string.h"
+
+#define ARCHIVE_WRITE_MAGIC (0xb0c5c0deU)
+#define ARCHIVE_READ_MAGIC (0xdeb0c5U)
+
+struct archive {
+ /*
+ * The magic/state values are used to sanity-check the
+ * client's usage. If an API function is called at a
+ * rediculous time, or the client passes us an invalid
+ * pointer, these values allow me to catch that.
+ */
+ unsigned magic;
+ unsigned state;
+
+ struct archive_entry *entry;
+ uid_t user_uid; /* UID of current user. */
+
+ /* Dev/ino of the archive being read/written. */
+ dev_t skip_file_dev;
+ ino_t skip_file_ino;
+
+ /* Utility: Pointer to a block of nulls. */
+ const unsigned char *nulls;
+ size_t null_length;
+
+ /*
+ * Used by archive_read_data() to track blocks and copy
+ * data to client buffers, filling gaps with zero bytes.
+ */
+ const char *read_data_block;
+ off_t read_data_offset;
+ off_t read_data_output_offset;
+ size_t read_data_remaining;
+
+ /* Callbacks to open/read/write/close archive stream. */
+ archive_open_callback *client_opener;
+ archive_read_callback *client_reader;
+ archive_write_callback *client_writer;
+ archive_close_callback *client_closer;
+ void *client_data;
+
+ /*
+ * Blocking information. Note that bytes_in_last_block is
+ * misleadingly named; I should find a better name. These
+ * control the final output from all compressors, including
+ * compression_none.
+ */
+ int bytes_per_block;
+ int bytes_in_last_block;
+
+ /*
+ * These control whether data within a gzip/bzip2 compressed
+ * stream gets padded or not. If pad_uncompressed is set,
+ * the data will be padded to a full block before being
+ * compressed. The pad_uncompressed_byte determines the value
+ * that will be used for padding. Note that these have no
+ * effect on compression "none."
+ */
+ int pad_uncompressed;
+ int pad_uncompressed_byte; /* TODO: Support this. */
+
+ /* Position in UNCOMPRESSED data stream. */
+ off_t file_position;
+ /* Position in COMPRESSED data stream. */
+ off_t raw_position;
+ /* File offset of beginning of most recently-read header. */
+ off_t header_position;
+
+ /*
+ * Detection functions for decompression: bid functions are
+ * given a block of data from the beginning of the stream and
+ * can bid on whether or not they support the data stream.
+ * General guideline: bid the number of bits that you actually
+ * test, e.g., 16 if you test a 2-byte magic value. The
+ * highest bidder will have their init function invoked, which
+ * can set up pointers to specific handlers.
+ *
+ * On write, the client just invokes an archive_write_set function
+ * which sets up the data here directly.
+ */
+ int compression_code; /* Currently active compression. */
+ const char *compression_name;
+ struct {
+ int (*bid)(const void *buff, size_t);
+ int (*init)(struct archive *, const void *buff, size_t);
+ } decompressors[4];
+ /* Read/write data stream (with compression). */
+ void *compression_data; /* Data for (de)compressor. */
+ int (*compression_init)(struct archive *); /* Initialize. */
+ int (*compression_finish)(struct archive *);
+ int (*compression_write)(struct archive *, const void *, size_t);
+ /*
+ * Read uses a peek/consume I/O model: the decompression code
+ * returns a pointer to the requested block and advances the
+ * file position only when requested by a consume call. This
+ * reduces copying and also simplifies look-ahead for format
+ * detection.
+ */
+ ssize_t (*compression_read_ahead)(struct archive *,
+ const void **, size_t request);
+ ssize_t (*compression_read_consume)(struct archive *, size_t);
+
+ /*
+ * Format detection is mostly the same as compression
+ * detection, with two significant differences: The bidders
+ * use the read_ahead calls above to examine the stream rather
+ * than having the supervisor hand them a block of data to
+ * examine, and the auction is repeated for every header.
+ * Winning bidders should set the archive_format and
+ * archive_format_name appropriately. Bid routines should
+ * check archive_format and decline to bid if the format of
+ * the last header was incompatible.
+ *
+ * Again, write support is considerably simpler because there's
+ * no need for an auction.
+ */
+ int archive_format;
+ const char *archive_format_name;
+
+ struct archive_format_descriptor {
+ int (*bid)(struct archive *);
+ int (*read_header)(struct archive *, struct archive_entry *);
+ int (*read_data)(struct archive *, const void **, size_t *, off_t *);
+ int (*read_data_skip)(struct archive *);
+ int (*cleanup)(struct archive *);
+ void *format_data; /* Format-specific data for readers. */
+ } formats[8];
+ struct archive_format_descriptor *format; /* Active format. */
+
+ /*
+ * Storage for format-specific data. Note that there can be
+ * multiple format readers active at one time, so we need to
+ * allow for multiple format readers to have their data
+ * available. The pformat_data slot here is the solution: on
+ * read, it is gauranteed to always point to a void* variable
+ * that the format can use.
+ */
+ void **pformat_data; /* Pointer to current format_data. */
+ void *format_data; /* Used by writers. */
+
+ /*
+ * Pointers to format-specific functions for writing. They're
+ * initialized by archive_write_set_format_XXX() calls.
+ */
+ int (*format_init)(struct archive *); /* Only used on write. */
+ int (*format_finish)(struct archive *);
+ int (*format_finish_entry)(struct archive *);
+ int (*format_write_header)(struct archive *,
+ struct archive_entry *);
+ int (*format_write_data)(struct archive *,
+ const void *buff, size_t);
+
+ /*
+ * Various information needed by archive_extract.
+ */
+ struct extract *extract;
+ void (*extract_progress)(void *);
+ void *extract_progress_user_data;
+ void (*cleanup_archive_extract)(struct archive *);
+
+ int archive_error_number;
+ const char *error;
+ struct archive_string error_string;
+};
+
+
+#define ARCHIVE_STATE_ANY 0xFFFFU
+#define ARCHIVE_STATE_NEW 1U
+#define ARCHIVE_STATE_HEADER 2U
+#define ARCHIVE_STATE_DATA 4U
+#define ARCHIVE_STATE_EOF 8U
+#define ARCHIVE_STATE_CLOSED 0x10U
+#define ARCHIVE_STATE_FATAL 0x8000U
+
+/* Check magic value and state; exit if it isn't valid. */
+void __archive_check_magic(struct archive *, unsigned magic,
+ unsigned state, const char *func);
+
+
+int __archive_read_register_format(struct archive *a,
+ void *format_data,
+ int (*bid)(struct archive *),
+ int (*read_header)(struct archive *, struct archive_entry *),
+ int (*read_data)(struct archive *, const void **, size_t *, off_t *),
+ int (*read_data_skip)(struct archive *),
+ int (*cleanup)(struct archive *));
+
+int __archive_read_register_compression(struct archive *a,
+ int (*bid)(const void *, size_t),
+ int (*init)(struct archive *, const void *, size_t));
+
+void __archive_errx(int retvalue, const char *msg);
+
+#define err_combine(a,b) ((a) < (b) ? (a) : (b))
+
+
+/*
+ * Utility function to format a USTAR header into a buffer. If
+ * "strict" is set, this tries to create the absolutely most portable
+ * version of a ustar header. If "strict" is set to 0, then it will
+ * relax certain requirements.
+ *
+ * Generally, format-specific declarations don't belong in this
+ * header; this is a rare example of a function that is shared by
+ * two very similar formats (ustar and pax).
+ */
+int
+__archive_write_format_header_ustar(struct archive *, char buff[512],
+ struct archive_entry *, int tartype, int strict);
+
+#endif
diff --git a/lib/libarchive/archive_read.3 b/lib/libarchive/archive_read.3
new file mode 100644
index 0000000..1575c7b
--- /dev/null
+++ b/lib/libarchive/archive_read.3
@@ -0,0 +1,493 @@
+.\" Copyright (c) 2003-2005 Tim Kientzle
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING 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, 2005
+.Dt archive_read 3
+.Os
+.Sh NAME
+.Nm archive_read_new ,
+.Nm archive_read_set_bytes_per_block ,
+.Nm archive_read_support_compression_all ,
+.Nm archive_read_support_compression_bzip2 ,
+.Nm archive_read_support_compression_compress ,
+.Nm archive_read_support_compression_gzip ,
+.Nm archive_read_support_compression_none ,
+.Nm archive_read_support_format_all ,
+.Nm archive_read_support_format_cpio ,
+.Nm archive_read_support_format_iso9660 ,
+.Nm archive_read_support_format_tar ,
+.Nm archive_read_support_format_zip ,
+.Nm archive_read_open ,
+.Nm archive_read_open_fd ,
+.Nm archive_read_open_file ,
+.Nm archive_read_next_header ,
+.Nm archive_read_data ,
+.Nm archive_read_data_block ,
+.Nm archive_read_data_skip ,
+.Nm archive_read_data_into_buffer ,
+.Nm archive_read_data_into_fd ,
+.Nm archive_read_extract ,
+.Nm archive_read_extract_set_progress_callback ,
+.Nm archive_read_close ,
+.Nm archive_read_finish
+.Nd functions for reading streaming archives
+.Sh SYNOPSIS
+.In archive.h
+.Ft struct archive *
+.Fn archive_read_new "void"
+.Ft int
+.Fn archive_read_set_bytes_per_block "struct archive *" "int"
+.Ft int
+.Fn archive_read_support_compression_all "struct archive *"
+.Ft int
+.Fn archive_read_support_compression_bzip2 "struct archive *"
+.Ft int
+.Fn archive_read_support_compression_compress "struct archive *"
+.Ft int
+.Fn archive_read_support_compression_gzip "struct archive *"
+.Ft int
+.Fn archive_read_support_compression_none "struct archive *"
+.Ft int
+.Fn archive_read_support_format_all "struct archive *"
+.Ft int
+.Fn archive_read_support_format_cpio "struct archive *"
+.Ft int
+.Fn archive_read_support_format_iso9660 "struct archive *"
+.Ft int
+.Fn archive_read_support_format_tar "struct archive *"
+.Ft int
+.Fn archive_read_support_format_zip "struct archive *"
+.Ft int
+.Fn archive_read_open "struct archive *" "void *client_data" "archive_open_callback *" "archive_read_callback *" "archive_close_callback *"
+.Ft int
+.Fn archive_read_open_fd "struct archive *" "int fd" "size_t block_size"
+.Ft int
+.Fn archive_read_open_file "struct archive *" "const char *filename" "size_t block_size"
+.Ft int
+.Fn archive_read_next_header "struct archive *" "struct archive_entry **"
+.Ft ssize_t
+.Fn archive_read_data "struct archive *" "void *buff" "size_t len"
+.Ft int
+.Fn archive_read_data_block "struct archive *" "const void **buff" "size_t *len" "off_t *offset"
+.Ft int
+.Fn archive_read_data_skip "struct archive *"
+.Ft int
+.Fn archive_read_data_into_buffer "struct archive *" "void *" "ssize_t len"
+.Ft int
+.Fn archive_read_data_into_fd "struct archive *" "int fd"
+.Ft int
+.Fn archive_read_extract "struct archive *" "struct archive_entry *" "int flags"
+.Ft void
+.Fn archive_read_extract_set_progress_callback "struct archive *" "void (*func)(void *)" "void *user_data"
+.Ft int
+.Fn archive_read_close "struct archive *"
+.Ft void
+.Fn archive_read_finish "struct archive *"
+.Sh DESCRIPTION
+These functions provide a complete API for reading streaming archives.
+The general process is to first create the
+.Tn struct archive
+object, set options, initialize the reader, iterate over the archive
+headers and associated data, then close the archive and release all
+resources.
+The following summary describes the functions in approximately the
+order they would be used:
+.Bl -tag -compact -width indent
+.It Fn archive_read_new
+Allocates and initializes a
+.Tn struct archive
+object suitable for reading from an archive.
+.It Fn archive_read_set_bytes_per_block
+Sets the block size used for reading the archive data.
+This controls the size that will be used when invoking the read
+callback function.
+The default is 20 records or 10240 bytes for tar formats.
+.It Fn archive_read_support_compression_all , Fn archive_read_support_compression_bzip2 , Fn archive_read_support_compression_compress , Fn archive_read_support_compression_gzip , Fn archive_read_support_compression_none
+Enables auto-detection code and decompression support for the
+specified compression.
+Note that
+.Dq none
+is always enabled by default.
+For convenience,
+.Fn archive_read_support_compression_all
+enables all available decompression code.
+.It Fn archive_read_support_format_all , Fn archive_read_support_format_cpio , Fn archive_read_support_format_iso9660 , Fn archive_read_support_format_tar, Fn archive_read_support_format_zip
+Enables support---including auto-detection code---for the
+specified archive format.
+For example,
+.Fn archive_read_support_format_tar
+enables support for a variety of standard tar formats, old-style tar,
+ustar, pax interchange format, and many common variants.
+For convenience,
+.Fn archive_read_support_format_all
+enables support for all available formats.
+Note that there is no default.
+.It Fn archive_read_open
+Freeze the settings, open the archive, and prepare for reading entries.
+This is the most generic version of this call, which accepts
+three callback functions.
+Most clients will want to use
+.Fn archive_read_open_file
+or
+.Fn archive_read_open_fd
+instead.
+The library invokes the client-provided functions to obtain
+raw bytes from the archive.
+Note: The API permits a decompression method to fork and invoke the
+callbacks from another process.
+Although none of the current decompression methods use this technique,
+future decompression methods may utilize this technique.
+If the decompressor forks, it will ensure that the open and close
+callbacks are invoked within the same process as the read callback.
+In particular, clients should not attempt to use shared variables to
+communicate between the open/read/close callbacks and the mainline code.
+.It Fn archive_read_open_fd
+Like
+.Fn archive_read_open ,
+except that it accepts a file descriptor and block size rather than
+a trio of function pointers.
+Note that the file descriptor will not be automatically closed at
+end-of-archive.
+.It Fn archive_read_open_file
+Like
+.Fn archive_read_open ,
+except that it accepts a simple filename and a block size.
+A NULL filename represents standard input.
+.It Fn archive_read_next_header
+Read the header for the next entry and return a pointer to
+a
+.Tn struct archive_entry .
+.It Fn archive_read_data
+Read data associated with the header just read.
+Internally, this is a convenience function that calls
+.Fn archive_read_data_block
+and fills any gaps with nulls so that callers see a single
+continuous stream of data.
+.It Fn archive_read_data_block
+Return the next available block of data for this entry.
+Unlike
+.Fn archive_read_data ,
+the
+.Fn archive_read_data_block
+function avoids copying data and allows you to correctly handle
+sparse files, as supported by some archive formats.
+The library guarantees that offsets will increase and that blocks
+will not overlap.
+Note that the blocks returned from this function can be much larger
+than the block size read from disk, due to compression
+and internal buffer optimizations.
+.It Fn archive_read_data_skip
+A convenience function that repeatedly calls
+.Fn archive_read_data_block
+to skip all of the data for this archive entry.
+.It Fn archive_read_data_into_buffer
+A convenience function that repeatedly calls
+.Fn archive_read_data_block
+to copy the entire entry into the client-supplied buffer.
+Note that the client is responsible for sizing the buffer appropriately.
+.It Fn archive_read_data_into_fd
+A convenience function that repeatedly calls
+.Fn archive_read_data_block
+to copy the entire entry to the provided file descriptor.
+.It Fn archive_read_extract
+A convenience function that recreates the specified object on
+disk and reads the entry data into that object.
+The filename, permissions, and other critical information
+are taken from the provided
+.Va archive_entry
+object.
+The
+.Va flags
+argument modifies how the object is recreated.
+It consists of a bitwise OR of one or more of the following values:
+.Bl -tag -compact -width "indent"
+.It Cm ARCHIVE_EXTRACT_OWNER
+The user and group IDs should be set on the restored file.
+By default, the user and group IDs are not restored.
+.It Cm ARCHIVE_EXTRACT_PERM
+The permissions (mode bits) should be restored for all objects.
+By default, permissions are only restored for regular files.
+.It Cm ARCHIVE_EXTRACT_TIME
+The timestamps (mtime, ctime, and atime) should be restored.
+By default, they are ignored.
+Note that restoring of atime is not currently supported.
+.It Cm ARCHIVE_EXTRACT_NO_OVERWRITE
+Existing files on disk will not be overwritten.
+By default, existing regular files are truncated and overwritten;
+existing directories will have their permissions updated;
+other pre-existing objects are unlinked and recreated from scratch.
+.It Cm ARCHIVE_EXTRACT_UNLINK
+Existing files on disk will be unlinked and recreated from scratch.
+By default, existing files are truncated and rewritten, but
+the file is not recreated.
+In particular, the default behavior does not break existing hard links.
+.It Cm ARCHIVE_EXTRACT_ACL
+Attempt to restore ACLs.
+By default, extended ACLs are ignored.
+.It Cm ARCHIVE_EXTRACT_FFLAGS
+Attempt to restore extended file flags.
+By default, file flags are ignored.
+.El
+Note that not all attributes are set immediately;
+some attributes are cached in memory and written to disk only
+when the archive is closed.
+(For example, read-only directories are initially created
+writable so that files within those directories can be
+restored.
+The final permissions are set when the archive is closed.)
+.It Fn archive_read_extract_set_progress_callback
+Sets a pointer to a user-defined callback that can be used
+for updating progress displays during extraction.
+The progress function will be invoked during the extraction of large
+regular files.
+The progress function will be invoked with the pointer provided to this call.
+Generally, the data pointed to should include a reference to the archive
+object and the archive_entry object so that various statistics
+can be retrieved for the progress display.
+.It Fn archive_read_close
+Complete the archive and invoke the close callback.
+.It Fn archive_read_finish
+Invokes
+.Fn archive_read_close
+if it was not invoked manually, then release all resources.
+.El
+.Pp
+Note that the library determines most of the relevant information about
+the archive by inspection.
+In particular, it automatically detects
+.Xr gzip 1
+or
+.Xr bzip2 1
+compression and transparently performs the appropriate decompression.
+It also automatically detects the archive format.
+.Pp
+A complete description of the
+.Tn struct archive
+and
+.Tn struct archive_entry
+objects can be found in the overview manual page for
+.Xr libarchive 3 .
+.Sh CLIENT CALLBACKS
+The callback functions must match the following prototypes:
+.Bl -item -offset indent
+.It
+.Ft typedef ssize_t
+.Fn archive_read_callback "struct archive *" "void *client_data" "const void **buffer"
+.It
+.Ft typedef int
+.Fn archive_open_callback "struct archive *" "void *client_data"
+.It
+.Ft typedef int
+.Fn archive_close_callback "struct archive *" "void *client_data"
+.El
+.Pp
+The open callback is invoked by
+.Fn archive_open .
+It should return
+.Cm ARCHIVE_OK
+if the underlying file or data source is successfully
+opened.
+If the open fails, it should call
+.Fn archive_set_error
+to register an error code and message and return
+.Cm ARCHIVE_FATAL .
+.Pp
+The read callback is invoked whenever the library
+requires raw bytes from the archive.
+The read callback should read data into a buffer,
+set the
+.Li const void **buffer
+argument to point to the available data, and
+return a count of the number of bytes available.
+The library will invoke the read callback again
+only after it has consumed this data.
+The library imposes no constraints on the size
+of the data blocks returned.
+On end-of-file, the read callback should
+return zero.
+On error, the read callback should invoke
+.Fn archive_set_error
+to register an error code and message and
+return -1.
+.Pp
+The close callback is invoked by archive_close when
+the archive processing is complete.
+The callback should return
+.Cm ARCHIVE_OK
+on success.
+On failure, the callback should invoke
+.Fn archive_set_error
+to register an error code and message and
+return
+.Cm ARCHIVE_FATAL.
+.Sh EXAMPLE
+The following illustrates basic usage of the library.
+In this example,
+the callback functions are simply wrappers around the standard
+.Xr open 2 ,
+.Xr read 2 ,
+and
+.Xr close 2
+system calls.
+.Bd -literal -offset indent
+void
+list_archive(const char *name)
+{
+ struct mydata *mydata;
+ struct archive *a;
+ struct archive_entry *entry;
+
+ mydata = malloc(sizeof(struct mydata));
+ a = archive_read_new();
+ mydata->name = name;
+ archive_read_support_compression_all(a);
+ archive_read_support_format_all(a);
+ archive_read_open(a, mydata, myopen, myread, myclose);
+ while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
+ printf("%s\\n",archive_entry_pathname(entry));
+ archive_read_data_skip(a);
+ }
+ archive_read_finish(a);
+ free(mydata);
+}
+
+ssize_t
+myread(struct archive *a, void *client_data, const void **buff)
+{
+ struct mydata *mydata = client_data;
+
+ *buff = mydata->buff;
+ return (read(mydata->fd, mydata->buff, 10240));
+}
+
+int
+myopen(struct archive *a, void *client_data)
+{
+ struct mydata *mydata = client_data;
+
+ mydata->fd = open(mydata->name, O_RDONLY);
+ return (mydata->fd >= 0 ? ARCHIVE_OK : ARCHIVE_FATAL);
+}
+
+int
+myclose(struct archive *a, void *client_data)
+{
+ struct mydata *mydata = client_data;
+
+ if (mydata->fd > 0)
+ close(mydata->fd);
+ return (ARCHIVE_OK);
+}
+.Ed
+.Sh RETURN VALUES
+Most functions return zero on success, non-zero on error.
+The possible return codes include:
+.Cm ARCHIVE_OK
+(the operation succeeded),
+.Cm ARCHIVE_WARN
+(the operation succeeded but a non-critical error was encountered),
+.Cm ARCHIVE_EOF
+(end-of-archive was encountered),
+.Cm ARCHIVE_RETRY
+(the operation failed but can be retried),
+and
+.Cm ARCHIVE_FATAL
+(there was a fatal error; the archive should be closed immediately).
+Detailed error codes and textual descriptions are available from the
+.Fn archive_errno
+and
+.Fn archive_error_string
+functions.
+.Pp
+.Fn archive_read_new
+returns a pointer to a freshly allocated
+.Tn struct archive
+object.
+It returns
+.Dv NULL
+on error.
+.Pp
+.Fn archive_read_data
+returns a count of bytes actually read or zero at the end of the entry.
+On error, a value of
+.Cm ARCHIVE_FATAL ,
+.Cm ARCHIVE_WARN ,
+or
+.Cm ARCHIVE_RETRY
+is returned and an error code and textual description can be retrieved from the
+.Fn archive_errno
+and
+.Fn archive_error_string
+functions.
+.Pp
+The library expects the client callbacks to behave similarly.
+If there is an error, you can use
+.Fn archive_set_error
+to set an appropriate error code and description,
+then return one of the non-zero values above.
+(Note that the value eventually returned to the client may
+not be the same; many errors that are not critical at the level
+of basic I/O can prevent the archive from being properly read,
+thus most I/O errors eventually cause
+.Cm ARCHIVE_FATAL
+to be returned.)
+.\" .Sh ERRORS
+.Sh SEE ALSO
+.Xr tar 1 ,
+.Xr archive 3 ,
+.Xr archive_util 3 ,
+.Xr tar 5
+.Sh HISTORY
+The
+.Nm libarchive
+library first appeared in
+.Fx 5.3 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm libarchive
+library was written by
+.An Tim Kientzle Aq kientzle@acm.org .
+.Sh BUGS
+Directories are actually extracted in two distinct phases.
+Directories are created during
+.Fn archive_read_extract ,
+but final permissions are not set until
+.Fn archive_read_close .
+This separation is necessary to correctly handle borderline
+cases such as a non-writable directory containing
+files, but can cause unexpected results.
+In particular, directory permissions are not fully
+restored until the archive is closed.
+If you use
+.Xr chdir 2
+to change the current directory between calls to
+.Fn archive_read_extract
+or before calling
+.Fn archive_read_close ,
+you may confuse the permission-setting logic with
+the result that directory permissions are restored
+incorrectly.
diff --git a/lib/libarchive/archive_read.c b/lib/libarchive/archive_read.c
new file mode 100644
index 0000000..c6e47e1
--- /dev/null
+++ b/lib/libarchive/archive_read.c
@@ -0,0 +1,601 @@
+/*-
+ * Copyright (c) 2003-2004 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(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 AUTHOR(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.
+ */
+
+/*
+ * This file contains the "essential" portions of the read API, that
+ * is, stuff that will probably always be used by any client that
+ * actually needs to read an archive. Optional pieces have been, as
+ * far as possible, separated out into separate files to avoid
+ * needlessly bloating statically-linked clients.
+ */
+
+#include "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "archive.h"
+#include "archive_entry.h"
+#include "archive_private.h"
+
+static int choose_decompressor(struct archive *, const void*, size_t);
+static int choose_format(struct archive *);
+
+/*
+ * Allocate, initialize and return a struct archive object.
+ */
+struct archive *
+archive_read_new(void)
+{
+ struct archive *a;
+ unsigned char *nulls;
+
+ a = malloc(sizeof(*a));
+ if (a == NULL) {
+ archive_set_error(a, ENOMEM, "Can't allocate archive object");
+ return (NULL);
+ }
+ memset(a, 0, sizeof(*a));
+
+ a->user_uid = geteuid();
+ a->magic = ARCHIVE_READ_MAGIC;
+ a->bytes_per_block = ARCHIVE_DEFAULT_BYTES_PER_BLOCK;
+
+ a->null_length = 1024;
+ nulls = malloc(a->null_length);
+ if (nulls == NULL) {
+ archive_set_error(a, ENOMEM, "Can't allocate archive object 'nulls' element");
+ free(a);
+ return (NULL);
+ }
+ memset(nulls, 0, a->null_length);
+ a->nulls = nulls;
+
+ a->state = ARCHIVE_STATE_NEW;
+ a->entry = archive_entry_new();
+
+ /* We always support uncompressed archives. */
+ archive_read_support_compression_none((struct archive*)a);
+
+ return (a);
+}
+
+/*
+ * Set the block size.
+ */
+/*
+int
+archive_read_set_bytes_per_block(struct archive *a, int bytes_per_block)
+{
+ __archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, "archive_read_set_bytes_per_block");
+ if (bytes_per_block < 1)
+ bytes_per_block = 1;
+ a->bytes_per_block = bytes_per_block;
+ return (0);
+}
+*/
+
+/*
+ * Open the archive
+ */
+int
+archive_read_open(struct archive *a, void *client_data,
+ archive_open_callback *client_opener, archive_read_callback *client_reader,
+ archive_close_callback *client_closer)
+{
+ const void *buffer;
+ ssize_t bytes_read;
+ int high_bidder;
+ int e;
+
+ __archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, "archive_read_open");
+
+ if (client_reader == NULL)
+ __archive_errx(1,
+ "No reader function provided to archive_read_open");
+
+ /*
+ * Set these NULL initially. If the open or initial read fails,
+ * we'll leave them NULL to indicate that the file is invalid.
+ * (In particular, this helps ensure that the closer doesn't
+ * get called more than once.)
+ */
+ a->client_opener = NULL;
+ a->client_reader = NULL;
+ a->client_closer = NULL;
+ a->client_data = NULL;
+
+ /* Open data source. */
+ if (client_opener != NULL) {
+ e =(client_opener)(a, client_data);
+ if (e != 0) {
+ /* If the open failed, call the closer to clean up. */
+ if (client_closer)
+ (client_closer)(a, client_data);
+ return (e);
+ }
+ }
+
+ /* Read first block now for format detection. */
+ bytes_read = (client_reader)(a, client_data, &buffer);
+
+ if (bytes_read < 0) {
+ /* If the first read fails, close before returning error. */
+ if (client_closer)
+ (client_closer)(a, client_data);
+ /* client_reader should have already set error information. */
+ return (ARCHIVE_FATAL);
+ }
+
+ /* An empty archive is a serious error. */
+ if (bytes_read == 0) {
+ archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Empty input file");
+ /* Close the empty file. */
+ if (client_closer)
+ (client_closer)(a, client_data);
+ return (ARCHIVE_FATAL);
+ }
+
+ /* Now that the client callbacks have worked, remember them. */
+ a->client_opener = client_opener; /* Do we need to remember this? */
+ a->client_reader = client_reader;
+ a->client_closer = client_closer;
+ a->client_data = client_data;
+
+ /* Select a decompression routine. */
+ high_bidder = choose_decompressor(a, buffer, bytes_read);
+ if (high_bidder < 0)
+ return (ARCHIVE_FATAL);
+
+ /* Initialize decompression routine with the first block of data. */
+ e = (a->decompressors[high_bidder].init)(a, buffer, bytes_read);
+
+ if (e == ARCHIVE_OK)
+ a->state = ARCHIVE_STATE_HEADER;
+
+ return (e);
+}
+
+/*
+ * Allow each registered decompression routine to bid on whether it
+ * wants to handle this stream. Return index of winning bidder.
+ */
+static int
+choose_decompressor(struct archive *a, const void *buffer, size_t bytes_read)
+{
+ int decompression_slots, i, bid, best_bid, best_bid_slot;
+
+ decompression_slots = sizeof(a->decompressors) /
+ sizeof(a->decompressors[0]);
+
+ best_bid = -1;
+ best_bid_slot = -1;
+
+ for (i = 0; i < decompression_slots; i++) {
+ if (a->decompressors[i].bid) {
+ bid = (a->decompressors[i].bid)(buffer, bytes_read);
+ if ((bid > best_bid) || (best_bid_slot < 0)) {
+ best_bid = bid;
+ best_bid_slot = i;
+ }
+ }
+ }
+
+ /*
+ * There were no bidders; this is a serious programmer error
+ * and demands a quick and definitive abort.
+ */
+ if (best_bid_slot < 0)
+ __archive_errx(1, "No decompressors were registered; you "
+ "must call at least one "
+ "archive_read_support_compression_XXX function in order "
+ "to successfully read an archive.");
+
+ /*
+ * There were bidders, but no non-zero bids; this means we can't
+ * support this stream.
+ */
+ if (best_bid < 1) {
+ archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Unrecognized archive format");
+ return (ARCHIVE_FATAL);
+ }
+
+ return (best_bid_slot);
+}
+
+/*
+ * Read header of next entry.
+ */
+int
+archive_read_next_header(struct archive *a, struct archive_entry **entryp)
+{
+ struct archive_entry *entry;
+ int slot, ret;
+
+ __archive_check_magic(a, ARCHIVE_READ_MAGIC,
+ ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, "archive_read_next_header");
+
+ *entryp = NULL;
+ entry = a->entry;
+ archive_entry_clear(entry);
+ archive_string_empty(&a->error_string);
+
+ /*
+ * If client didn't consume entire data, skip any remainder
+ * (This is especially important for GNU incremental directories.)
+ */
+ if (a->state == ARCHIVE_STATE_DATA) {
+ ret = archive_read_data_skip(a);
+ if (ret == ARCHIVE_EOF) {
+ archive_set_error(a, EIO, "Premature end-of-file.");
+ a->state = ARCHIVE_STATE_FATAL;
+ return (ARCHIVE_FATAL);
+ }
+ if (ret != ARCHIVE_OK)
+ return (ret);
+ }
+
+ /* Record start-of-header. */
+ a->header_position = a->file_position;
+
+ slot = choose_format(a);
+ if (slot < 0) {
+ a->state = ARCHIVE_STATE_FATAL;
+ return (ARCHIVE_FATAL);
+ }
+ a->format = &(a->formats[slot]);
+ a->pformat_data = &(a->format->format_data);
+ ret = (a->format->read_header)(a, entry);
+
+ /*
+ * EOF and FATAL are persistent at this layer. By
+ * modifying the state, we gaurantee that future calls to
+ * read a header or read data will fail.
+ */
+ switch (ret) {
+ case ARCHIVE_EOF:
+ a->state = ARCHIVE_STATE_EOF;
+ break;
+ case ARCHIVE_OK:
+ a->state = ARCHIVE_STATE_DATA;
+ break;
+ case ARCHIVE_WARN:
+ a->state = ARCHIVE_STATE_DATA;
+ break;
+ case ARCHIVE_RETRY:
+ break;
+ case ARCHIVE_FATAL:
+ a->state = ARCHIVE_STATE_FATAL;
+ break;
+ }
+
+ *entryp = entry;
+ a->read_data_output_offset = 0;
+ a->read_data_remaining = 0;
+ return (ret);
+}
+
+/*
+ * Allow each registered format to bid on whether it wants to handle
+ * the next entry. Return index of winning bidder.
+ */
+static int
+choose_format(struct archive *a)
+{
+ int slots;
+ int i;
+ int bid, best_bid;
+ int best_bid_slot;
+
+ slots = sizeof(a->formats) / sizeof(a->formats[0]);
+ best_bid = -1;
+ best_bid_slot = -1;
+
+ /* Set up a->format and a->pformat_data for convenience of bidders. */
+ a->format = &(a->formats[0]);
+ for (i = 0; i < slots; i++, a->format++) {
+ if (a->format->bid) {
+ a->pformat_data = &(a->format->format_data);
+ bid = (a->format->bid)(a);
+ if (bid == ARCHIVE_FATAL)
+ return (ARCHIVE_FATAL);
+ if ((bid > best_bid) || (best_bid_slot < 0)) {
+ best_bid = bid;
+ best_bid_slot = i;
+ }
+ }
+ }
+
+ /*
+ * There were no bidders; this is a serious programmer error
+ * and demands a quick and definitive abort.
+ */
+ if (best_bid_slot < 0)
+ __archive_errx(1, "No formats were registered; you must "
+ "invoke at least one archive_read_support_format_XXX "
+ "function in order to successfully read an archive.");
+
+ /*
+ * There were bidders, but no non-zero bids; this means we
+ * can't support this stream.
+ */
+ if (best_bid < 1) {
+ archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Unrecognized archive format");
+ return (ARCHIVE_FATAL);
+ }
+
+ return (best_bid_slot);
+}
+
+/*
+ * Return the file offset (within the uncompressed data stream) where
+ * the last header started.
+ */
+int64_t
+archive_read_header_position(struct archive *a)
+{
+ return (a->header_position);
+}
+
+/*
+ * Read data from an archive entry, using a read(2)-style interface.
+ * This is a convenience routine that just calls
+ * archive_read_data_block and copies the results into the client
+ * buffer, filling any gaps with zero bytes. Clients using this
+ * API can be completely ignorant of sparse-file issues; sparse files
+ * will simply be padded with nulls.
+ *
+ * DO NOT intermingle calls to this function and archive_read_data_block
+ * to read a single entry body.
+ */
+ssize_t
+archive_read_data(struct archive *a, void *buff, size_t s)
+{
+ char *dest;
+ size_t bytes_read;
+ size_t len;
+ int r;
+
+ bytes_read = 0;
+ dest = buff;
+
+ while (s > 0) {
+ if (a->read_data_remaining <= 0) {
+ r = archive_read_data_block(a,
+ (const void **)&a->read_data_block,
+ &a->read_data_remaining,
+ &a->read_data_offset);
+ if (r == ARCHIVE_EOF)
+ return (bytes_read);
+ /*
+ * Error codes are all negative, so the status
+ * return here cannot be confused with a valid
+ * byte count. (ARCHIVE_OK is zero.)
+ */
+ if (r < ARCHIVE_OK)
+ return (r);
+ }
+
+ if (a->read_data_offset < a->read_data_output_offset) {
+ archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Encountered out-of-order sparse blocks");
+ return (ARCHIVE_RETRY);
+ } else {
+ len = a->read_data_remaining;
+ if (len > s)
+ len = s;
+ memcpy(dest, a->read_data_block, len);
+ s -= len;
+ a->read_data_block += len;
+ a->read_data_remaining -= len;
+ a->read_data_output_offset += len;
+ a->read_data_offset += len;
+ dest += len;
+ bytes_read += len;
+ }
+ }
+ return (bytes_read);
+}
+
+/*
+ * Skip over all remaining data in this entry.
+ */
+int
+archive_read_data_skip(struct archive *a)
+{
+ int r;
+ const void *buff;
+ size_t size;
+ off_t offset;
+
+ __archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA, "archive_read_data_skip");
+
+ if (a->format->read_data_skip != NULL)
+ r = (a->format->read_data_skip)(a);
+ else {
+ while ((r = archive_read_data_block(a, &buff, &size, &offset))
+ == ARCHIVE_OK)
+ ;
+ }
+
+ if (r == ARCHIVE_EOF)
+ r = ARCHIVE_OK;
+
+ a->state = ARCHIVE_STATE_HEADER;
+ return (r);
+}
+
+/*
+ * Read the next block of entry data from the archive.
+ * This is a zero-copy interface; the client receives a pointer,
+ * size, and file offset of the next available block of data.
+ *
+ * Returns ARCHIVE_OK if the operation is successful, ARCHIVE_EOF if
+ * the end of entry is encountered.
+ */
+int
+archive_read_data_block(struct archive *a,
+ const void **buff, size_t *size, off_t *offset)
+{
+ __archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA, "archive_read_data_block");
+
+ if (a->format->read_data == NULL) {
+ archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER,
+ "Internal error: "
+ "No format_read_data_block function registered");
+ return (ARCHIVE_FATAL);
+ }
+
+ return (a->format->read_data)(a, buff, size, offset);
+}
+
+/*
+ * Close the file and release most resources.
+ *
+ * Be careful: client might just call read_new and then read_finish.
+ * Don't assume we actually read anything or performed any non-trivial
+ * initialization.
+ */
+int
+archive_read_close(struct archive *a)
+{
+ __archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_ANY, "archive_read_close");
+ a->state = ARCHIVE_STATE_CLOSED;
+
+ /* Call cleanup functions registered by optional components. */
+ if (a->cleanup_archive_extract != NULL)
+ (a->cleanup_archive_extract)(a);
+
+ /* TODO: Finish the format processing. */
+
+ /* Close the input machinery. */
+ if (a->compression_finish != NULL)
+ (a->compression_finish)(a);
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Release memory and other resources.
+ */
+void
+archive_read_finish(struct archive *a)
+{
+ int i;
+ int slots;
+
+ __archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_ANY, "archive_read_finish");
+ if (a->state != ARCHIVE_STATE_CLOSED)
+ archive_read_close(a);
+
+ /* Cleanup format-specific data. */
+ slots = sizeof(a->formats) / sizeof(a->formats[0]);
+ for (i = 0; i < slots; i++) {
+ a->pformat_data = &(a->formats[i].format_data);
+ if (a->formats[i].cleanup)
+ (a->formats[i].cleanup)(a);
+ }
+
+ /* Casting a pointer to int allows us to remove 'const.' */
+ free((void *)(uintptr_t)(const void *)a->nulls);
+ archive_string_free(&a->error_string);
+ if (a->entry)
+ archive_entry_free(a->entry);
+ a->magic = 0;
+ free(a);
+}
+
+/*
+ * Used internally by read format handlers to register their bid and
+ * initialization functions.
+ */
+int
+__archive_read_register_format(struct archive *a,
+ void *format_data,
+ int (*bid)(struct archive *),
+ int (*read_header)(struct archive *, struct archive_entry *),
+ int (*read_data)(struct archive *, const void **, size_t *, off_t *),
+ int (*read_data_skip)(struct archive *),
+ int (*cleanup)(struct archive *))
+{
+ int i, number_slots;
+
+ __archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, "__archive_read_register_format");
+
+ number_slots = sizeof(a->formats) / sizeof(a->formats[0]);
+
+ for (i = 0; i < number_slots; i++) {
+ if (a->formats[i].bid == bid)
+ return (ARCHIVE_WARN); /* We've already installed */
+ if (a->formats[i].bid == NULL) {
+ a->formats[i].bid = bid;
+ a->formats[i].read_header = read_header;
+ a->formats[i].read_data = read_data;
+ a->formats[i].read_data_skip = read_data_skip;
+ a->formats[i].cleanup = cleanup;
+ a->formats[i].format_data = format_data;
+ return (ARCHIVE_OK);
+ }
+ }
+
+ __archive_errx(1, "Not enough slots for format registration");
+ return (ARCHIVE_FATAL); /* Never actually called. */
+}
+
+/*
+ * Used internally by decompression routines to register their bid and
+ * initialization functions.
+ */
+int
+__archive_read_register_compression(struct archive *a,
+ int (*bid)(const void *, size_t),
+ int (*init)(struct archive *, const void *, size_t))
+{
+ int i, number_slots;
+
+ __archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, "__archive_read_register_compression");
+
+ number_slots = sizeof(a->decompressors) / sizeof(a->decompressors[0]);
+
+ for (i = 0; i < number_slots; i++) {
+ if (a->decompressors[i].bid == bid)
+ return (ARCHIVE_OK); /* We've already installed */
+ if (a->decompressors[i].bid == NULL) {
+ a->decompressors[i].bid = bid;
+ a->decompressors[i].init = init;
+ return (ARCHIVE_OK);
+ }
+ }
+
+ __archive_errx(1, "Not enough slots for compression registration");
+ return (ARCHIVE_FATAL); /* Never actually executed. */
+}
diff --git a/lib/libarchive/archive_read_data_into_buffer.c b/lib/libarchive/archive_read_data_into_buffer.c
new file mode 100644
index 0000000..0b52617
--- /dev/null
+++ b/lib/libarchive/archive_read_data_into_buffer.c
@@ -0,0 +1,49 @@
+/*-
+ * Copyright (c) 2003-2004 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(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 AUTHOR(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 "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#include <string.h>
+
+#include "archive.h"
+
+int
+archive_read_data_into_buffer(struct archive *a, void *d, ssize_t len)
+{
+ char *dest;
+ ssize_t bytes_read, total_bytes;
+
+ dest = d;
+ total_bytes = 0;
+ bytes_read = archive_read_data(a, dest, len);
+ while (bytes_read > 0) {
+ total_bytes += bytes_read;
+ bytes_read = archive_read_data(a, dest + total_bytes,
+ len - total_bytes);
+ }
+ return (ARCHIVE_OK);
+}
diff --git a/lib/libarchive/archive_read_data_into_fd.c b/lib/libarchive/archive_read_data_into_fd.c
new file mode 100644
index 0000000..9b31d22
--- /dev/null
+++ b/lib/libarchive/archive_read_data_into_fd.c
@@ -0,0 +1,84 @@
+/*-
+ * Copyright (c) 2003-2004 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(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 AUTHOR(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 "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "archive.h"
+#include "archive_private.h"
+
+/* Maximum amount of data to write at one time. */
+#define MAX_WRITE (1024 * 1024)
+
+/*
+ * This implementation minimizes copying of data and is sparse-file aware.
+ */
+int
+archive_read_data_into_fd(struct archive *a, int fd)
+{
+ int r;
+ const void *buff;
+ size_t size;
+ ssize_t bytes_to_write, bytes_written, total_written;
+ off_t offset;
+ off_t output_offset;
+
+ __archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA, "archive_read_data_into_fd");
+
+ total_written = 0;
+ output_offset = 0;
+
+ while ((r = archive_read_data_block(a, &buff, &size, &offset)) ==
+ ARCHIVE_OK) {
+ if (offset > output_offset) {
+ lseek(fd, offset - output_offset, SEEK_CUR);
+ output_offset = offset;
+ }
+ while (size > 0) {
+ bytes_to_write = size;
+ if (bytes_to_write > MAX_WRITE)
+ bytes_to_write = MAX_WRITE;
+ bytes_written = write(fd, buff, bytes_to_write);
+ if (bytes_written < 0) {
+ archive_set_error(a, errno, "Write error");
+ return (-1);
+ }
+ output_offset += bytes_written;
+ total_written += bytes_written;
+ size -= bytes_written;
+ if (a->extract_progress != NULL)
+ (*a->extract_progress)(a->extract_progress_user_data);
+ }
+ }
+
+ if (r != ARCHIVE_EOF)
+ return (r);
+ return (ARCHIVE_OK);
+}
diff --git a/lib/libarchive/archive_read_extract.c b/lib/libarchive/archive_read_extract.c
new file mode 100644
index 0000000..aedd392
--- /dev/null
+++ b/lib/libarchive/archive_read_extract.c
@@ -0,0 +1,1604 @@
+/*-
+ * Copyright (c) 2003-2005 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(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 AUTHOR(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 "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#ifdef HAVE_SYS_ACL_H
+#include <sys/acl.h>
+#endif
+#ifdef HAVE_ATTR_XATTR_H
+#include <attr/xattr.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#ifdef HAVE_EXT2FS_EXT2_FS_H
+#include <ext2fs/ext2_fs.h> /* for Linux file flags */
+#endif
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+#ifdef HAVE_LINUX_EXT2_FS_H
+#include <linux/ext2_fs.h> /* for Linux file flags */
+#endif
+#include <limits.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "archive.h"
+#include "archive_string.h"
+#include "archive_entry.h"
+#include "archive_private.h"
+
+struct fixup_entry {
+ struct fixup_entry *next;
+ mode_t mode;
+ int64_t mtime;
+ int64_t atime;
+ unsigned long mtime_nanos;
+ unsigned long atime_nanos;
+ unsigned long fflags_set;
+ int fixup; /* bitmask of what needs fixing */
+ char *name;
+};
+
+#define FIXUP_MODE 1
+#define FIXUP_TIMES 2
+#define FIXUP_FFLAGS 4
+
+struct bucket {
+ char *name;
+ int hash;
+ id_t id;
+};
+
+struct extract {
+ mode_t umask;
+ mode_t default_dir_mode;
+ struct archive_string create_parent_dir;
+ struct fixup_entry *fixup_list;
+ struct fixup_entry *current_fixup;
+
+ struct bucket ucache[127];
+ struct bucket gcache[127];
+
+ /*
+ * Cached stat data from disk for the current entry.
+ * If this is valid, pst points to st. Otherwise,
+ * pst is null.
+ */
+ struct stat st;
+ struct stat *pst;
+};
+
+/* Default mode for dirs created automatically (will be modified by umask). */
+#define DEFAULT_DIR_MODE 0777
+/*
+ * Mode to use for newly-created dirs during extraction; the correct
+ * mode will be set at the end of the extraction.
+ */
+#define SECURE_DIR_MODE 0700
+
+static void archive_extract_cleanup(struct archive *);
+static int extract_block_device(struct archive *,
+ struct archive_entry *, int);
+static int extract_char_device(struct archive *,
+ struct archive_entry *, int);
+static int extract_device(struct archive *,
+ struct archive_entry *, int flags, mode_t mode);
+static int extract_dir(struct archive *, struct archive_entry *, int);
+static int extract_fifo(struct archive *, struct archive_entry *, int);
+static int extract_file(struct archive *, struct archive_entry *, int);
+static int extract_hard_link(struct archive *, struct archive_entry *, int);
+static int extract_symlink(struct archive *, struct archive_entry *, int);
+static unsigned int hash(const char *);
+static gid_t lookup_gid(struct archive *, const char *uname, gid_t);
+static uid_t lookup_uid(struct archive *, const char *uname, uid_t);
+static int create_dir(struct archive *, const char *, int flags);
+static int create_dir_mutable(struct archive *, char *, int flags);
+static int create_dir_recursive(struct archive *, char *, int flags);
+static int create_parent_dir(struct archive *, const char *, int flags);
+static int create_parent_dir_mutable(struct archive *, char *, int flags);
+static int restore_metadata(struct archive *, int fd,
+ struct archive_entry *, int flags);
+#ifdef HAVE_POSIX_ACL
+static int set_acl(struct archive *, int fd, struct archive_entry *,
+ acl_type_t, int archive_entry_acl_type, const char *tn);
+#endif
+static int set_acls(struct archive *, int fd, struct archive_entry *);
+static int set_xattrs(struct archive *, int fd, struct archive_entry *);
+static int set_fflags(struct archive *, int fd, const char *name, mode_t,
+ unsigned long fflags_set, unsigned long fflags_clear);
+static int set_ownership(struct archive *, int fd, struct archive_entry *,
+ int flags);
+static int set_perm(struct archive *, int fd, struct archive_entry *,
+ int mode, int flags);
+static int set_time(struct archive *, int fd, struct archive_entry *, int);
+static struct fixup_entry *sort_dir_list(struct fixup_entry *p);
+
+
+/*
+ * Extract this entry to disk.
+ *
+ * TODO: Validate hardlinks. According to the standards, we're
+ * supposed to check each extracted hardlink and squawk if it refers
+ * to a file that we didn't restore. I'm not entirely convinced this
+ * is a good idea, but more importantly: Is there any way to validate
+ * hardlinks without keeping a complete list of filenames from the
+ * entire archive?? Ugh.
+ *
+ */
+int
+archive_read_extract(struct archive *a, struct archive_entry *entry, int flags)
+{
+ mode_t mode;
+ struct extract *extract;
+ int ret;
+ int restore_pwd;
+ char *original_filename;
+
+ if (a->extract == NULL) {
+ a->extract = malloc(sizeof(*a->extract));
+ if (a->extract == NULL) {
+ archive_set_error(a, ENOMEM, "Can't extract");
+ return (ARCHIVE_FATAL);
+ }
+ a->cleanup_archive_extract = archive_extract_cleanup;
+ memset(a->extract, 0, sizeof(*a->extract));
+ }
+ extract = a->extract;
+ umask(extract->umask = umask(0)); /* Read the current umask. */
+ extract->default_dir_mode = DEFAULT_DIR_MODE & ~extract->umask;
+ extract->pst = NULL;
+ extract->current_fixup = NULL;
+ restore_pwd = -1;
+ original_filename = NULL;
+
+ /* The following is not possible without fchdir. <sigh> */
+#ifdef HAVE_FCHDIR
+ /*
+ * If pathname is longer than PATH_MAX, record starting directory
+ * and chdir to a suitable intermediate dir.
+ */
+ if (strlen(archive_entry_pathname(entry)) > PATH_MAX) {
+ char *intdir, *tail;
+
+ restore_pwd = open(".", O_RDONLY);
+ if (restore_pwd < 0) {
+ archive_set_error(a, errno,
+ "Unable to restore long pathname");
+ return (ARCHIVE_WARN);
+ }
+
+ /*
+ * Yes, the copy here is necessary because we edit
+ * the pathname in-place to create intermediate dirnames.
+ */
+ original_filename = strdup(archive_entry_pathname(entry));
+
+ /*
+ * "intdir" points to the initial dir section we're going
+ * to remove, "tail" points to the remainder of the path.
+ */
+ intdir = tail = original_filename;
+ while (strlen(tail) > PATH_MAX) {
+ intdir = tail;
+
+ /* Locate a dir prefix shorter than PATH_MAX. */
+ tail = intdir + PATH_MAX - 8;
+ while (tail > intdir && *tail != '/')
+ tail--;
+ if (tail <= intdir) {
+ archive_set_error(a, EPERM,
+ "Path element too long");
+ ret = ARCHIVE_WARN;
+ goto cleanup;
+ }
+
+ /* Create intdir and chdir to it. */
+ *tail = '\0'; /* Terminate dir portion */
+ ret = create_dir(a, intdir, flags);
+ if (ret == ARCHIVE_OK && chdir(intdir) != 0) {
+ archive_set_error(a, errno, "Couldn't chdir");
+ ret = ARCHIVE_WARN;
+ }
+ *tail = '/'; /* Restore the / we removed. */
+ if (ret != ARCHIVE_OK)
+ goto cleanup;
+ tail++;
+ }
+ archive_entry_set_pathname(entry, tail);
+ }
+#endif
+
+ if (stat(archive_entry_pathname(entry), &extract->st) == 0)
+ extract->pst = &extract->st;
+
+ if (extract->pst != NULL &&
+ extract->pst->st_dev == a->skip_file_dev &&
+ extract->pst->st_ino == a->skip_file_ino) {
+ archive_set_error(a, 0, "Refusing to overwrite archive");
+ ret = ARCHIVE_WARN;
+ } else if (archive_entry_hardlink(entry) != NULL)
+ ret = extract_hard_link(a, entry, flags);
+ else {
+ mode = archive_entry_mode(entry);
+ switch (mode & S_IFMT) {
+ default:
+ /* Fall through, as required by POSIX. */
+ case S_IFREG:
+ ret = extract_file(a, entry, flags);
+ break;
+ case S_IFLNK: /* Symlink */
+ ret = extract_symlink(a, entry, flags);
+ break;
+ case S_IFCHR:
+ ret = extract_char_device(a, entry, flags);
+ break;
+ case S_IFBLK:
+ ret = extract_block_device(a, entry, flags);
+ break;
+ case S_IFDIR:
+ ret = extract_dir(a, entry, flags);
+ break;
+ case S_IFIFO:
+ ret = extract_fifo(a, entry, flags);
+ break;
+ }
+ }
+
+
+cleanup:
+#ifdef HAVE_FCHDIR
+ /* If we changed directory above, restore it here. */
+ if (restore_pwd >= 0 && original_filename != NULL) {
+ fchdir(restore_pwd);
+ close(restore_pwd);
+ archive_entry_copy_pathname(entry, original_filename);
+ free(original_filename);
+ }
+#endif
+
+ return (ret);
+}
+
+/*
+ * Cleanup function for archive_extract. Mostly, this involves processing
+ * the fixup list, which is used to address a number of problems:
+ * * Dir permissions might prevent us from restoring a file in that
+ * dir, so we restore the dir 0700 first, then correct the
+ * mode at the end.
+ * * Similarly, the act of restoring a file touches the directory
+ * and changes the timestamp on the dir, so we have to touch-up dir
+ * timestamps at the end as well.
+ * * Some file flags can interfere with the restore by, for example,
+ * preventing the creation of hardlinks to those files.
+ *
+ * Note that tar/cpio do not require that archives be in a particular
+ * order; there is no way to know when the last file has been restored
+ * within a directory, so there's no way to optimize the memory usage
+ * here by fixing up the directory any earlier than the
+ * end-of-archive.
+ *
+ * XXX TODO: Directory ACLs should be restored here, for the same
+ * reason we set directory perms here. XXX
+ *
+ * Registering this function (rather than calling it explicitly by
+ * name from archive_read_finish) reduces static link pollution, since
+ * applications that don't use this API won't get this file linked in.
+ */
+static void
+archive_extract_cleanup(struct archive *a)
+{
+ struct fixup_entry *next, *p;
+ struct extract *extract;
+
+ /* Sort dir list so directories are fixed up in depth-first order. */
+ extract = a->extract;
+ p = sort_dir_list(extract->fixup_list);
+
+ while (p != NULL) {
+ extract->pst = NULL; /* Mark stat cache as out-of-date. */
+ if (p->fixup & FIXUP_TIMES) {
+ struct timeval times[2];
+ times[1].tv_sec = p->mtime;
+ times[1].tv_usec = p->mtime_nanos / 1000;
+ times[0].tv_sec = p->atime;
+ times[0].tv_usec = p->atime_nanos / 1000;
+ utimes(p->name, times);
+ }
+ if (p->fixup & FIXUP_MODE)
+ chmod(p->name, p->mode);
+
+ if (p->fixup & FIXUP_FFLAGS)
+ set_fflags(a, -1, p->name, p->mode, p->fflags_set, 0);
+
+ next = p->next;
+ free(p->name);
+ free(p);
+ p = next;
+ }
+ extract->fixup_list = NULL;
+ archive_string_free(&extract->create_parent_dir);
+ free(a->extract);
+ a->extract = NULL;
+}
+
+/*
+ * Simple O(n log n) merge sort to order the fixup list. In
+ * particular, we want to restore dir timestamps depth-first.
+ */
+static struct fixup_entry *
+sort_dir_list(struct fixup_entry *p)
+{
+ struct fixup_entry *a, *b, *t;
+
+ if (p == NULL)
+ return (NULL);
+ /* A one-item list is already sorted. */
+ if (p->next == NULL)
+ return (p);
+
+ /* Step 1: split the list. */
+ t = p;
+ a = p->next->next;
+ while (a != NULL) {
+ /* Step a twice, t once. */
+ a = a->next;
+ if (a != NULL)
+ a = a->next;
+ t = t->next;
+ }
+ /* Now, t is at the mid-point, so break the list here. */
+ b = t->next;
+ t->next = NULL;
+ a = p;
+
+ /* Step 2: Recursively sort the two sub-lists. */
+ a = sort_dir_list(a);
+ b = sort_dir_list(b);
+
+ /* Step 3: Merge the returned lists. */
+ /* Pick the first element for the merged list. */
+ if (strcmp(a->name, b->name) > 0) {
+ t = p = a;
+ a = a->next;
+ } else {
+ t = p = b;
+ b = b->next;
+ }
+
+ /* Always put the later element on the list first. */
+ while (a != NULL && b != NULL) {
+ if (strcmp(a->name, b->name) > 0) {
+ t->next = a;
+ a = a->next;
+ } else {
+ t->next = b;
+ b = b->next;
+ }
+ t = t->next;
+ }
+
+ /* Only one list is non-empty, so just splice it on. */
+ if (a != NULL)
+ t->next = a;
+ if (b != NULL)
+ t->next = b;
+
+ return (p);
+}
+
+/*
+ * Returns a new, initialized fixup entry.
+ *
+ * TODO: Reduce the memory requirements for this list by using a tree
+ * structure rather than a simple list of names.
+ */
+static struct fixup_entry *
+new_fixup(struct archive *a, const char *pathname)
+{
+ struct extract *extract;
+ struct fixup_entry *fe;
+
+ extract = a->extract;
+ fe = malloc(sizeof(struct fixup_entry));
+ if (fe == NULL)
+ return (NULL);
+ fe->next = extract->fixup_list;
+ extract->fixup_list = fe;
+ fe->fixup = 0;
+ fe->name = strdup(pathname);
+ return (fe);
+}
+
+/*
+ * Returns a fixup structure for the current entry.
+ */
+static struct fixup_entry *
+current_fixup(struct archive *a, const char *pathname)
+{
+ struct extract *extract;
+
+ extract = a->extract;
+ if (extract->current_fixup == NULL)
+ extract->current_fixup = new_fixup(a, pathname);
+ return (extract->current_fixup);
+}
+
+static int
+extract_file(struct archive *a, struct archive_entry *entry, int flags)
+{
+ struct extract *extract;
+ const char *name;
+ mode_t mode;
+ int fd, r, r2;
+
+ extract = a->extract;
+ name = archive_entry_pathname(entry);
+ mode = archive_entry_mode(entry) & 0777;
+ r = ARCHIVE_OK;
+
+ /*
+ * If we're not supposed to overwrite pre-existing files,
+ * use O_EXCL. Otherwise, use O_TRUNC.
+ */
+ if (flags & (ARCHIVE_EXTRACT_UNLINK | ARCHIVE_EXTRACT_NO_OVERWRITE))
+ fd = open(name, O_WRONLY | O_CREAT | O_EXCL, mode);
+ else
+ fd = open(name, O_WRONLY | O_CREAT | O_TRUNC, mode);
+
+ /* Try removing a pre-existing file. */
+ if (fd < 0 && !(flags & ARCHIVE_EXTRACT_NO_OVERWRITE)) {
+ unlink(name);
+ fd = open(name, O_WRONLY | O_CREAT | O_EXCL, mode);
+ }
+
+ /* Might be a non-existent parent dir; try fixing that. */
+ if (fd < 0) {
+ create_parent_dir(a, name, flags);
+ fd = open(name, O_WRONLY | O_CREAT | O_EXCL, mode);
+ }
+ if (fd < 0) {
+ archive_set_error(a, errno, "Can't open '%s'", name);
+ return (ARCHIVE_WARN);
+ }
+ r = archive_read_data_into_fd(a, fd);
+ extract->pst = NULL; /* Cached stat data no longer valid. */
+ r2 = restore_metadata(a, fd, entry, flags);
+ close(fd);
+ return (err_combine(r, r2));
+}
+
+static int
+extract_dir(struct archive *a, struct archive_entry *entry, int flags)
+{
+ struct extract *extract;
+ struct fixup_entry *fe;
+ char *path, *p;
+
+ extract = a->extract;
+ extract->pst = NULL; /* Invalidate cached stat data. */
+
+ /* Copy path to mutable storage. */
+ archive_strcpy(&(extract->create_parent_dir),
+ archive_entry_pathname(entry));
+ path = extract->create_parent_dir.s;
+
+ if (*path == '\0') {
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "Invalid empty pathname");
+ return (ARCHIVE_WARN);
+ }
+
+ /* Deal with any troublesome trailing path elements. */
+ /* TODO: Someday, generalize this to remove '//' or '/./' from
+ * the middle of paths. But, it should not compress '..' from
+ * the middle of paths. It's a feature that restoring
+ * "a/../b" creates both 'a' and 'b' directories. */
+ for (;;) {
+ /* Locate last element. */
+ p = strrchr(path, '/');
+ if (p != NULL)
+ p++;
+ else
+ p = path;
+ /* Trim trailing '/' unless that's the entire path. */
+ if (p[0] == '\0' && p - 1 > path) {
+ p[-1] = '\0';
+ continue;
+ }
+ /* Trim trailing '.' unless that's the entire path. */
+ if (p > path && p[0] == '.' && p[1] == '\0') {
+ p[0] = '\0';
+ continue;
+ }
+ /* Just exit on trailing '..'. */
+ if (p[0] == '.' && p[1] == '.' && p[2] == '\0') {
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "Can't restore directory '..'");
+ return (ARCHIVE_WARN);
+ }
+ break;
+ }
+
+ if (mkdir(path, SECURE_DIR_MODE) == 0)
+ goto success;
+
+ if (extract->pst == NULL && stat(path, &extract->st) == 0)
+ extract->pst = &extract->st;
+
+ if (extract->pst != NULL) {
+ extract->pst = &extract->st;
+ /* If dir already exists, don't reset permissions. */
+ if (S_ISDIR(extract->pst->st_mode))
+ return (ARCHIVE_OK);
+ /* It exists but isn't a dir. */
+ if ((flags & ARCHIVE_EXTRACT_UNLINK))
+ unlink(path);
+ } else {
+ /* Doesn't already exist; try building the parent path. */
+ if (create_parent_dir_mutable(a, path, flags) != ARCHIVE_OK)
+ return (ARCHIVE_WARN);
+ }
+
+ /* One final attempt to create the dir. */
+ if (mkdir(path, SECURE_DIR_MODE) != 0) {
+ archive_set_error(a, errno, "Can't create directory");
+ return (ARCHIVE_WARN);
+ }
+
+success:
+ /* Add this dir to the fixup list. */
+ fe = current_fixup(a, path);
+ fe->fixup |= FIXUP_MODE;
+ fe->mode = archive_entry_mode(entry);
+ if ((flags & ARCHIVE_EXTRACT_PERM) == 0)
+ fe->mode &= ~extract->umask;
+ if (flags & ARCHIVE_EXTRACT_TIME) {
+ fe->fixup |= FIXUP_TIMES;
+ fe->mtime = archive_entry_mtime(entry);
+ fe->mtime_nanos = archive_entry_mtime_nsec(entry);
+ fe->atime = archive_entry_atime(entry);
+ fe->atime_nanos = archive_entry_atime_nsec(entry);
+ }
+ /* For now, set the mode to SECURE_DIR_MODE. */
+ archive_entry_set_mode(entry, SECURE_DIR_MODE);
+ return (restore_metadata(a, -1, entry, flags));
+}
+
+
+/*
+ * Create the parent of the specified path. Copy the provided
+ * path into mutable storage first.
+ */
+static int
+create_parent_dir(struct archive *a, const char *path, int flags)
+{
+ int r;
+
+ /* Copy path to mutable storage. */
+ archive_strcpy(&(a->extract->create_parent_dir), path);
+ r = create_parent_dir_mutable(a, a->extract->create_parent_dir.s, flags);
+ return (r);
+}
+
+/*
+ * Like create_parent_dir, but creates the dir actually requested, not
+ * the parent.
+ */
+static int
+create_dir(struct archive *a, const char *path, int flags)
+{
+ int r;
+ /* Copy path to mutable storage. */
+ archive_strcpy(&(a->extract->create_parent_dir), path);
+ r = create_dir_mutable(a, a->extract->create_parent_dir.s, flags);
+ return (r);
+}
+
+/*
+ * Create the parent directory of the specified path, assuming path
+ * is already in mutable storage.
+ */
+static int
+create_parent_dir_mutable(struct archive *a, char *path, int flags)
+{
+ char *slash;
+ int r;
+
+ /* Remove tail element to obtain parent name. */
+ slash = strrchr(path, '/');
+ if (slash == NULL)
+ return (ARCHIVE_OK);
+ *slash = '\0';
+ r = create_dir_mutable(a, path, flags);
+ *slash = '/';
+ return (r);
+}
+
+/*
+ * Create the specified dir, assuming path is already in
+ * mutable storage.
+ */
+static int
+create_dir_mutable(struct archive *a, char *path, int flags)
+{
+ mode_t old_umask;
+ int r;
+
+ old_umask = umask(~SECURE_DIR_MODE);
+ r = create_dir_recursive(a, path, flags);
+ umask(old_umask);
+ return (r);
+}
+
+/*
+ * Create the specified dir, recursing to create parents as necessary.
+ *
+ * Returns ARCHIVE_OK if the path exists when we're done here.
+ * Otherwise, returns ARCHIVE_WARN.
+ */
+static int
+create_dir_recursive(struct archive *a, char *path, int flags)
+{
+ struct stat st;
+ struct extract *extract;
+ struct fixup_entry *le;
+ char *slash, *base;
+ int r;
+
+ extract = a->extract;
+ r = ARCHIVE_OK;
+
+ /* Check for special names and just skip them. */
+ slash = strrchr(path, '/');
+ base = strrchr(path, '/');
+ if (slash == NULL)
+ base = path;
+ else
+ base = slash + 1;
+
+ if (base[0] == '\0' ||
+ (base[0] == '.' && base[1] == '\0') ||
+ (base[0] == '.' && base[1] == '.' && base[2] == '\0')) {
+ /* Don't bother trying to create null path, '.', or '..'. */
+ if (slash != NULL) {
+ *slash = '\0';
+ r = create_dir_recursive(a, path, flags);
+ *slash = '/';
+ return (r);
+ }
+ return (ARCHIVE_OK);
+ }
+
+ /*
+ * Yes, this should be stat() and not lstat(). Using lstat()
+ * here loses the ability to extract through symlinks. Also note
+ * that this should not use the extract->st cache.
+ */
+ if (stat(path, &st) == 0) {
+ if (S_ISDIR(st.st_mode))
+ return (ARCHIVE_OK);
+ if ((flags & ARCHIVE_EXTRACT_NO_OVERWRITE)) {
+ archive_set_error(a, EEXIST,
+ "Can't create directory '%s'", path);
+ return (ARCHIVE_WARN);
+ }
+ if (unlink(path) != 0) {
+ archive_set_error(a, errno,
+ "Can't create directory '%s': "
+ "Conflicting file cannot be removed");
+ return (ARCHIVE_WARN);
+ }
+ } else if (errno != ENOENT && errno != ENOTDIR) {
+ /* Stat failed? */
+ archive_set_error(a, errno, "Can't test directory '%s'", path);
+ return (ARCHIVE_WARN);
+ } else if (slash != NULL) {
+ *slash = '\0';
+ r = create_dir_recursive(a, path, flags);
+ *slash = '/';
+ if (r != ARCHIVE_OK)
+ return (r);
+ }
+
+ if (mkdir(path, SECURE_DIR_MODE) == 0) {
+ le = new_fixup(a, path);
+ le->fixup |= FIXUP_MODE;
+ le->mode = extract->default_dir_mode;
+ return (ARCHIVE_OK);
+ }
+
+ /*
+ * Without the following check, a/b/../b/c/d fails at the
+ * second visit to 'b', so 'd' can't be created. Note that we
+ * don't add it to the fixup list here, as it's already been
+ * added.
+ */
+ if (stat(path, &st) == 0 && S_ISDIR(st.st_mode))
+ return (ARCHIVE_OK);
+
+ archive_set_error(a, errno, "Failed to create dir '%s'", path);
+ return (ARCHIVE_WARN);
+}
+
+static int
+extract_hard_link(struct archive *a, struct archive_entry *entry, int flags)
+{
+ struct extract *extract;
+ int r;
+ const char *pathname;
+ const char *linkname;
+
+ extract = a->extract;
+ pathname = archive_entry_pathname(entry);
+ linkname = archive_entry_hardlink(entry);
+
+ /* Just remove any pre-existing file with this name. */
+ if (!(flags & ARCHIVE_EXTRACT_NO_OVERWRITE))
+ unlink(pathname);
+
+ r = link(linkname, pathname);
+ extract->pst = NULL; /* Invalidate cached stat data. */
+
+ if (r != 0) {
+ /* Might be a non-existent parent dir; try fixing that. */
+ create_parent_dir(a, pathname, flags);
+ r = link(linkname, pathname);
+ }
+
+ if (r != 0) {
+ /* XXX Better error message here XXX */
+ archive_set_error(a, errno,
+ "Can't restore hardlink to '%s'", linkname);
+ return (ARCHIVE_WARN);
+ }
+
+ /* Set ownership, time, permission information. */
+ r = restore_metadata(a, -1, entry, flags);
+ return (r);
+}
+
+static int
+extract_symlink(struct archive *a, struct archive_entry *entry, int flags)
+{
+ struct extract *extract;
+ int r;
+ const char *pathname;
+ const char *linkname;
+
+ extract = a->extract;
+ pathname = archive_entry_pathname(entry);
+ linkname = archive_entry_symlink(entry);
+
+ /* Just remove any pre-existing file with this name. */
+ if (!(flags & ARCHIVE_EXTRACT_NO_OVERWRITE))
+ unlink(pathname);
+
+ r = symlink(linkname, pathname);
+ extract->pst = NULL; /* Invalidate cached stat data. */
+
+ if (r != 0) {
+ /* Might be a non-existent parent dir; try fixing that. */
+ create_parent_dir(a, pathname, flags);
+ r = symlink(linkname, pathname);
+ }
+
+ if (r != 0) {
+ /* XXX Better error message here XXX */
+ archive_set_error(a, errno,
+ "Can't restore symlink to '%s'", linkname);
+ return (ARCHIVE_WARN);
+ }
+
+ r = restore_metadata(a, -1, entry, flags);
+ return (r);
+}
+
+static int
+extract_device(struct archive *a, struct archive_entry *entry,
+ int flags, mode_t mode)
+{
+ struct extract *extract;
+ int r;
+
+ extract = a->extract;
+ /* Just remove any pre-existing file with this name. */
+ if (!(flags & ARCHIVE_EXTRACT_NO_OVERWRITE))
+ unlink(archive_entry_pathname(entry));
+
+ r = mknod(archive_entry_pathname(entry), mode,
+ archive_entry_rdev(entry));
+ extract->pst = NULL; /* Invalidate cached stat data. */
+
+ /* Might be a non-existent parent dir; try fixing that. */
+ if (r != 0 && errno == ENOENT) {
+ create_parent_dir(a, archive_entry_pathname(entry), flags);
+ r = mknod(archive_entry_pathname(entry), mode,
+ archive_entry_rdev(entry));
+ }
+
+ if (r != 0) {
+ archive_set_error(a, errno, "Can't restore device node");
+ return (ARCHIVE_WARN);
+ }
+
+ r = restore_metadata(a, -1, entry, flags);
+ return (r);
+}
+
+static int
+extract_char_device(struct archive *a, struct archive_entry *entry, int flags)
+{
+ mode_t mode;
+
+ mode = (archive_entry_mode(entry) & ~S_IFMT) | S_IFCHR;
+ return (extract_device(a, entry, flags, mode));
+}
+
+static int
+extract_block_device(struct archive *a, struct archive_entry *entry, int flags)
+{
+ mode_t mode;
+
+ mode = (archive_entry_mode(entry) & ~S_IFMT) | S_IFBLK;
+ return (extract_device(a, entry, flags, mode));
+}
+
+static int
+extract_fifo(struct archive *a, struct archive_entry *entry, int flags)
+{
+ struct extract *extract;
+ int r;
+
+ extract = a->extract;
+ /* Just remove any pre-existing file with this name. */
+ if (!(flags & ARCHIVE_EXTRACT_NO_OVERWRITE))
+ unlink(archive_entry_pathname(entry));
+
+ r = mkfifo(archive_entry_pathname(entry),
+ archive_entry_mode(entry));
+ extract->pst = NULL; /* Invalidate cached stat data. */
+
+ /* Might be a non-existent parent dir; try fixing that. */
+ if (r != 0 && errno == ENOENT) {
+ create_parent_dir(a, archive_entry_pathname(entry), flags);
+ r = mkfifo(archive_entry_pathname(entry),
+ archive_entry_mode(entry));
+ }
+
+ if (r != 0) {
+ archive_set_error(a, errno, "Can't restore fifo");
+ return (ARCHIVE_WARN);
+ }
+
+ r = restore_metadata(a, -1, entry, flags);
+ return (r);
+}
+
+static int
+restore_metadata(struct archive *a, int fd, struct archive_entry *entry, int flags)
+{
+ int r, r2;
+
+ r = set_ownership(a, fd, entry, flags);
+ r2 = set_time(a, fd, entry, flags);
+ r = err_combine(r, r2);
+ r2 = set_perm(a, fd, entry, archive_entry_mode(entry), flags);
+ return (err_combine(r, r2));
+}
+
+static int
+set_ownership(struct archive *a, int fd,
+ struct archive_entry *entry, int flags)
+{
+ uid_t uid;
+ gid_t gid;
+
+ /* Not changed. */
+ if ((flags & ARCHIVE_EXTRACT_OWNER) == 0)
+ return (ARCHIVE_OK);
+
+ uid = lookup_uid(a, archive_entry_uname(entry),
+ archive_entry_uid(entry));
+ gid = lookup_gid(a, archive_entry_gname(entry),
+ archive_entry_gid(entry));
+
+ /* If we know we can't change it, don't bother trying. */
+ if (a->user_uid != 0 && a->user_uid != uid)
+ return (ARCHIVE_OK);
+
+#ifdef HAVE_FCHOWN
+ if (fd >= 0 && fchown(fd, uid, gid) == 0)
+ return (ARCHIVE_OK);
+#endif
+
+#ifdef HAVE_LCHOWN
+ if (lchown(archive_entry_pathname(entry), uid, gid))
+#else
+ if (!S_ISLNK(archive_entry_mode(entry))
+ && chown(archive_entry_pathname(entry), uid, gid) != 0)
+#endif
+ {
+ archive_set_error(a, errno,
+ "Can't set user=%d/group=%d for %s", uid, gid,
+ archive_entry_pathname(entry));
+ return (ARCHIVE_WARN);
+ }
+ return (ARCHIVE_OK);
+}
+
+static int
+set_time(struct archive *a, int fd, struct archive_entry *entry, int flags)
+{
+ const struct stat *st;
+ struct timeval times[2];
+
+ (void)a; /* UNUSED */
+ st = archive_entry_stat(entry);
+
+ if ((flags & ARCHIVE_EXTRACT_TIME) == 0)
+ return (ARCHIVE_OK);
+ /* It's a waste of time to mess with dir timestamps here. */
+ if (S_ISDIR(archive_entry_mode(entry)))
+ return (ARCHIVE_OK);
+
+ times[1].tv_sec = st->st_mtime;
+ times[1].tv_usec = ARCHIVE_STAT_MTIME_NANOS(st) / 1000;
+
+ times[0].tv_sec = st->st_atime;
+ times[0].tv_usec = ARCHIVE_STAT_ATIME_NANOS(st) / 1000;
+
+#ifdef HAVE_FUTIMES
+ if (fd >= 0 && futimes(fd, times) == 0)
+ return (ARCHIVE_OK);
+#endif
+
+#ifdef HAVE_LUTIMES
+ if (lutimes(archive_entry_pathname(entry), times) != 0) {
+#else
+ if ((archive_entry_mode(entry) & S_IFMT) != S_IFLNK &&
+ utimes(archive_entry_pathname(entry), times) != 0) {
+#endif
+ archive_set_error(a, errno, "Can't update time for %s",
+ archive_entry_pathname(entry));
+ return (ARCHIVE_WARN);
+ }
+
+ /*
+ * Note: POSIX does not provide a portable way to restore ctime.
+ * (Apart from resetting the system clock, which is distasteful.)
+ * So, any restoration of ctime will necessarily be OS-specific.
+ */
+
+ /* XXX TODO: Can FreeBSD restore ctime? XXX */
+
+ return (ARCHIVE_OK);
+}
+
+static int
+set_perm(struct archive *a, int fd, struct archive_entry *entry,
+ int mode, int flags)
+{
+ struct extract *extract;
+ struct fixup_entry *le;
+ const char *name;
+ unsigned long set, clear;
+ int r;
+ int critical_flags;
+
+ extract = a->extract;
+
+ /* Obey umask unless ARCHIVE_EXTRACT_PERM. */
+ if ((flags & ARCHIVE_EXTRACT_PERM) == 0)
+ mode &= ~extract->umask; /* Enforce umask. */
+ name = archive_entry_pathname(entry);
+
+ if (mode & (S_ISUID | S_ISGID)) {
+ if (extract->pst != NULL) {
+ /* Already have stat() data available. */
+#ifdef HAVE_FSTAT
+ } else if (fd >= 0 && fstat(fd, &extract->st) == 0) {
+ extract->pst = &extract->st;
+#endif
+ } else if (stat(name, &extract->st) == 0) {
+ extract->pst = &extract->st;
+ } else {
+ archive_set_error(a, errno,
+ "Couldn't stat file");
+ return (ARCHIVE_WARN);
+ }
+
+ /*
+ * TODO: Use the uid/gid looked up in set_ownership
+ * above rather than the uid/gid stored in the entry.
+ */
+ if (extract->pst->st_uid != archive_entry_uid(entry))
+ mode &= ~ S_ISUID;
+ if (extract->pst->st_gid != archive_entry_gid(entry))
+ mode &= ~ S_ISGID;
+ }
+
+ /*
+ * Ensure we change permissions on the object we extracted,
+ * and not any incidental symlink that might have gotten in
+ * the way.
+ */
+ if (!S_ISLNK(archive_entry_mode(entry))) {
+#ifdef HAVE_FCHMOD
+ if (fd >= 0) {
+ if (fchmod(fd, mode) != 0) {
+ archive_set_error(a, errno,
+ "Can't set permissions");
+ return (ARCHIVE_WARN);
+ }
+ } else
+#endif
+ if (chmod(name, mode) != 0) {
+ archive_set_error(a, errno, "Can't set permissions");
+ return (ARCHIVE_WARN);
+ }
+#ifdef HAVE_LCHMOD
+ } else {
+ /*
+ * If lchmod() isn't supported, it's no big deal.
+ * Permissions on symlinks are actually ignored on
+ * most platforms.
+ */
+ if (lchmod(name, mode) != 0) {
+ archive_set_error(a, errno, "Can't set permissions");
+ return (ARCHIVE_WARN);
+ }
+#endif
+ }
+
+ if (flags & ARCHIVE_EXTRACT_ACL) {
+ r = set_acls(a, fd, entry);
+ if (r != ARCHIVE_OK)
+ return (r);
+ }
+
+ if (flags & ARCHIVE_EXTRACT_XATTR) {
+ r = set_xattrs(a, fd, entry);
+ if (r != ARCHIVE_OK)
+ return (r);
+ }
+
+ /*
+ * Make 'critical_flags' hold all file flags that can't be
+ * immediately restored. For example, on BSD systems,
+ * SF_IMMUTABLE prevents hardlinks from being created, so
+ * should not be set until after any hardlinks are created. To
+ * preserve some semblance of portability, this uses #ifdef
+ * extensively. Ugly, but it works.
+ *
+ * Yes, Virginia, this does create a security race. It's mitigated
+ * somewhat by the practice of creating dirs 0700 until the extract
+ * is done, but it would be nice if we could do more than that.
+ * People restoring critical file systems should be wary of
+ * other programs that might try to muck with files as they're
+ * being restored.
+ */
+ /* Hopefully, the compiler will optimize this mess into a constant. */
+ critical_flags = 0;
+#ifdef SF_IMMUTABLE
+ critical_flags |= SF_IMMUTABLE;
+#endif
+#ifdef UF_IMMUTABLE
+ critical_flags |= UF_IMMUTABLE;
+#endif
+#ifdef SF_APPEND
+ critical_flags |= SF_APPEND;
+#endif
+#ifdef UF_APPEND
+ critical_flags |= UF_APPEND;
+#endif
+#ifdef EXT2_APPEND_FL
+ critical_flags |= EXT2_APPEND_FL;
+#endif
+#ifdef EXT2_IMMUTABLE_FL
+ critical_flags |= EXT2_IMMUTABLE_FL;
+#endif
+
+ if (flags & ARCHIVE_EXTRACT_FFLAGS) {
+ archive_entry_fflags(entry, &set, &clear);
+
+ /*
+ * The first test encourages the compiler to eliminate
+ * all of this if it's not necessary.
+ */
+ if ((critical_flags != 0) && (set & critical_flags)) {
+ le = current_fixup(a, archive_entry_pathname(entry));
+ le->fixup |= FIXUP_FFLAGS;
+ le->fflags_set = set;
+ /* Store the mode if it's not already there. */
+ if ((le->fixup & FIXUP_MODE) == 0)
+ le->mode = mode;
+ } else {
+ r = set_fflags(a, fd, archive_entry_pathname(entry),
+ mode, set, clear);
+ if (r != ARCHIVE_OK)
+ return (r);
+ }
+ }
+ return (ARCHIVE_OK);
+}
+
+
+#if ( defined(HAVE_LCHFLAGS) || defined(HAVE_CHFLAGS) || defined(HAVE_FCHFLAGS) ) && !defined(__linux)
+static int
+set_fflags(struct archive *a, int fd, const char *name, mode_t mode,
+ unsigned long set, unsigned long clear)
+{
+ struct extract *extract;
+
+ extract = a->extract;
+ if (set == 0 && clear == 0)
+ return (ARCHIVE_OK);
+
+ (void)mode; /* UNUSED */
+ /*
+ * XXX Is the stat here really necessary? Or can I just use
+ * the 'set' flags directly? In particular, I'm not sure
+ * about the correct approach if we're overwriting an existing
+ * file that already has flags on it. XXX
+ */
+ if (extract->pst != NULL) {
+ /* Already have stat() data available. */
+ } else if (fd >= 0 && fstat(fd, &extract->st) == 0)
+ extract->pst = &extract->st;
+ else if (stat(name, &extract->st) == 0)
+ extract->pst = &extract->st;
+ else {
+ archive_set_error(a, errno,
+ "Couldn't stat file");
+ return (ARCHIVE_WARN);
+ }
+
+ extract->st.st_flags &= ~clear;
+ extract->st.st_flags |= set;
+#ifdef HAVE_FCHFLAGS
+ /* If platform has fchflags() and we were given an fd, use it. */
+ if (fd >= 0 && fchflags(fd, extract->st.st_flags) == 0)
+ return (ARCHIVE_OK);
+#endif
+ /*
+ * If we can't use the fd to set the flags, we'll use the
+ * pathname to set flags. We prefer lchflags() but will use
+ * chflags() if we must.
+ */
+#ifdef HAVE_LCHFLAGS
+ if (lchflags(name, extract->st.st_flags) == 0)
+ return (ARCHIVE_OK);
+#elif defined(HAVE_CHFLAGS)
+ if (chflags(name, extract->st.st_flags) == 0)
+ return (ARCHIVE_OK);
+#endif
+ archive_set_error(a, errno,
+ "Failed to set file flags");
+ return (ARCHIVE_WARN);
+}
+
+#elif defined(__linux) && defined(EXT2_IOC_GETFLAGS) && defined(EXT2_IOC_SETFLAGS)
+
+/*
+ * Linux has flags too, but uses ioctl() to access them instead of
+ * having a separate chflags() system call.
+ */
+static int
+set_fflags(struct archive *a, int fd, const char *name, mode_t mode,
+ unsigned long set, unsigned long clear)
+{
+ struct extract *extract;
+ int ret;
+ int myfd = fd;
+ unsigned long newflags, oldflags;
+ unsigned long sf_mask = 0;
+
+ extract = a->extract;
+ if (set == 0 && clear == 0)
+ return (ARCHIVE_OK);
+ /* Only regular files and dirs can have flags. */
+ if (!S_ISREG(mode) && !S_ISDIR(mode))
+ return (ARCHIVE_OK);
+
+ /* If we weren't given an fd, open it ourselves. */
+ if (myfd < 0)
+ myfd = open(name, O_RDONLY|O_NONBLOCK);
+ if (myfd < 0)
+ return (ARCHIVE_OK);
+
+ /*
+ * Linux has no define for the flags that are only settable by
+ * the root user. This code may seem a little complex, but
+ * there seem to be some Linux systems that lack these
+ * defines. (?) The code below degrades reasonably gracefully
+ * if sf_mask is incomplete.
+ */
+#ifdef EXT2_IMMUTABLE_FL
+ sf_mask |= EXT2_IMMUTABLE_FL;
+#endif
+#ifdef EXT2_APPEND_FL
+ sf_mask |= EXT2_APPEND_FL;
+#endif
+ /*
+ * XXX As above, this would be way simpler if we didn't have
+ * to read the current flags from disk. XXX
+ */
+ ret = ARCHIVE_OK;
+ /* Try setting the flags as given. */
+ if (ioctl(myfd, EXT2_IOC_GETFLAGS, &oldflags) >= 0) {
+ newflags = (oldflags & ~clear) | set;
+ if (ioctl(myfd, EXT2_IOC_SETFLAGS, &newflags) >= 0)
+ goto cleanup;
+ if (errno != EPERM)
+ goto fail;
+ }
+ /* If we couldn't set all the flags, try again with a subset. */
+ if (ioctl(myfd, EXT2_IOC_GETFLAGS, &oldflags) >= 0) {
+ newflags &= ~sf_mask;
+ oldflags &= sf_mask;
+ newflags |= oldflags;
+ if (ioctl(myfd, EXT2_IOC_SETFLAGS, &newflags) >= 0)
+ goto cleanup;
+ }
+ /* We couldn't set the flags, so report the failure. */
+fail:
+ archive_set_error(a, errno,
+ "Failed to set file flags");
+ ret = ARCHIVE_WARN;
+cleanup:
+ if (fd < 0)
+ close(myfd);
+ return (ret);
+}
+
+#else /* Not HAVE_CHFLAGS && Not __linux */
+
+/*
+ * Of course, some systems have neither BSD chflags() nor Linux' flags
+ * support through ioctl().
+ */
+static int
+set_fflags(struct archive *a, int fd, const char *name, mode_t mode,
+ unsigned long set, unsigned long clear)
+{
+ (void)a;
+ (void)fd;
+ (void)name;
+ (void)mode;
+ (void)set;
+ (void)clear;
+ return (ARCHIVE_OK);
+}
+
+#endif /* __linux */
+
+#ifndef HAVE_POSIX_ACL
+/* Default empty function body to satisfy mainline code. */
+static int
+set_acls(struct archive *a, int fd, struct archive_entry *entry)
+{
+ (void)a;
+ (void)fd;
+ (void)entry;
+
+ return (ARCHIVE_OK);
+}
+
+#else
+
+/*
+ * XXX TODO: What about ACL types other than ACCESS and DEFAULT?
+ */
+static int
+set_acls(struct archive *a, int fd, struct archive_entry *entry)
+{
+ int ret;
+
+ ret = set_acl(a, fd, entry, ACL_TYPE_ACCESS,
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS, "access");
+ if (ret != ARCHIVE_OK)
+ return (ret);
+ ret = set_acl(a, fd, entry, ACL_TYPE_DEFAULT,
+ ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, "default");
+ return (ret);
+}
+
+
+static int
+set_acl(struct archive *a, int fd, struct archive_entry *entry,
+ acl_type_t acl_type, int ae_requested_type, const char *typename)
+{
+ acl_t acl;
+ acl_entry_t acl_entry;
+ acl_permset_t acl_permset;
+ int ret;
+ int ae_type, ae_permset, ae_tag, ae_id;
+ uid_t ae_uid;
+ gid_t ae_gid;
+ const char *ae_name;
+ int entries;
+ const char *name;
+
+ ret = ARCHIVE_OK;
+ entries = archive_entry_acl_reset(entry, ae_requested_type);
+ if (entries == 0)
+ return (ARCHIVE_OK);
+ acl = acl_init(entries);
+ while (archive_entry_acl_next(entry, ae_requested_type, &ae_type,
+ &ae_permset, &ae_tag, &ae_id, &ae_name) == ARCHIVE_OK) {
+ acl_create_entry(&acl, &acl_entry);
+
+ switch (ae_tag) {
+ case ARCHIVE_ENTRY_ACL_USER:
+ acl_set_tag_type(acl_entry, ACL_USER);
+ ae_uid = lookup_uid(a, ae_name, ae_id);
+ acl_set_qualifier(acl_entry, &ae_uid);
+ break;
+ case ARCHIVE_ENTRY_ACL_GROUP:
+ acl_set_tag_type(acl_entry, ACL_GROUP);
+ ae_gid = lookup_gid(a, ae_name, ae_id);
+ acl_set_qualifier(acl_entry, &ae_gid);
+ break;
+ case ARCHIVE_ENTRY_ACL_USER_OBJ:
+ acl_set_tag_type(acl_entry, ACL_USER_OBJ);
+ break;
+ case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
+ acl_set_tag_type(acl_entry, ACL_GROUP_OBJ);
+ break;
+ case ARCHIVE_ENTRY_ACL_MASK:
+ acl_set_tag_type(acl_entry, ACL_MASK);
+ break;
+ case ARCHIVE_ENTRY_ACL_OTHER:
+ acl_set_tag_type(acl_entry, ACL_OTHER);
+ break;
+ default:
+ /* XXX */
+ break;
+ }
+
+ acl_get_permset(acl_entry, &acl_permset);
+ acl_clear_perms(acl_permset);
+ if (ae_permset & ARCHIVE_ENTRY_ACL_EXECUTE)
+ acl_add_perm(acl_permset, ACL_EXECUTE);
+ if (ae_permset & ARCHIVE_ENTRY_ACL_WRITE)
+ acl_add_perm(acl_permset, ACL_WRITE);
+ if (ae_permset & ARCHIVE_ENTRY_ACL_READ)
+ acl_add_perm(acl_permset, ACL_READ);
+ }
+
+ name = archive_entry_pathname(entry);
+
+ /* Try restoring the ACL through 'fd' if we can. */
+#if HAVE_ACL_SET_FD
+ if (fd >= 0 && acl_type == ACL_TYPE_ACCESS && acl_set_fd(fd, acl) == 0)
+ ret = ARCHIVE_OK;
+ else
+#else
+#if HAVE_ACL_SET_FD_NP
+ if (fd >= 0 && acl_set_fd_np(fd, acl, acl_type) == 0)
+ ret = ARCHIVE_OK;
+ else
+#endif
+#endif
+ if (acl_set_file(name, acl_type, acl) != 0) {
+ archive_set_error(a, errno, "Failed to set %s acl", typename);
+ ret = ARCHIVE_WARN;
+ }
+ acl_free(acl);
+ return (ret);
+}
+#endif
+
+#if HAVE_LSETXATTR
+/*
+ * Restore extended attributes - Linux implementation
+ */
+static int
+set_xattrs(struct archive *a, int fd, struct archive_entry *entry)
+{
+ static int warning_done = 0;
+ int ret = ARCHIVE_OK;
+ int i = archive_entry_xattr_reset(entry);
+
+ while (i--) {
+ const char *name;
+ const void *value;
+ size_t size;
+ archive_entry_xattr_next(entry, &name, &value, &size);
+ if (name != NULL &&
+ strncmp(name, "xfsroot.", 8) != 0 &&
+ strncmp(name, "system.", 7) != 0) {
+ int e;
+#if HAVE_FSETXATTR
+ if (fd >= 0)
+ e = fsetxattr(fd, name, value, size, 0);
+ else
+#endif
+ {
+ e = lsetxattr(archive_entry_pathname(entry),
+ name, value, size, 0);
+ }
+ if (e == -1) {
+ if (errno == ENOTSUP) {
+ if (!warning_done) {
+ warning_done = 1;
+ archive_set_error(a, errno,
+ "Cannot restore extended "
+ "attributes on this file "
+ "system");
+ }
+ } else
+ archive_set_error(a, errno,
+ "Failed to set extended attribute");
+ ret = ARCHIVE_WARN;
+ }
+ } else {
+ archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Invalid extended attribute encountered");
+ ret = ARCHIVE_WARN;
+ }
+ }
+ return (ret);
+}
+#else
+/*
+ * Restore extended attributes - stub implementation for unsupported systems
+ */
+static int
+set_xattrs(struct archive *a, int fd, struct archive_entry *entry)
+{
+ static int warning_done = 0;
+ (void)a; /* UNUSED */
+ (void)fd; /* UNUSED */
+
+ /* If there aren't any extended attributes, then it's okay not
+ * to extract them, otherwise, issue a single warning. */
+ if (archive_entry_xattr_count(entry) != 0 && !warning_done) {
+ warning_done = 1;
+ archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Cannot restore extended attributes on this system");
+ return (ARCHIVE_WARN);
+ }
+ /* Warning was already emitted; suppress further warnings. */
+ return (ARCHIVE_OK);
+}
+#endif
+
+/*
+ * The following routines do some basic caching of uname/gname
+ * lookups. All such lookups go through these routines, including ACL
+ * conversions. Even a small cache here provides an enormous speedup,
+ * especially on systems using NIS, LDAP, or a similar networked
+ * directory system.
+ *
+ * TODO: Provide an API for clients to override these routines.
+ */
+static gid_t
+lookup_gid(struct archive *a, const char *gname, gid_t gid)
+{
+ struct group *grent;
+ struct extract *extract;
+ int h;
+ struct bucket *b;
+ int cache_size;
+
+ extract = a->extract;
+ cache_size = sizeof(extract->gcache) / sizeof(extract->gcache[0]);
+
+ /* If no gname, just use the gid provided. */
+ if (gname == NULL || *gname == '\0')
+ return (gid);
+
+ /* Try to find gname in the cache. */
+ h = hash(gname);
+ b = &extract->gcache[h % cache_size ];
+ if (b->name != NULL && b->hash == h && strcmp(gname, b->name) == 0)
+ return ((gid_t)b->id);
+
+ /* Free the cache slot for a new entry. */
+ if (b->name != NULL)
+ free(b->name);
+ b->name = strdup(gname);
+ /* Note: If strdup fails, that's okay; we just won't cache. */
+ b->hash = h;
+ grent = getgrnam(gname);
+ if (grent != NULL)
+ gid = grent->gr_gid;
+ b->id = gid;
+
+ return (gid);
+}
+
+static uid_t
+lookup_uid(struct archive *a, const char *uname, uid_t uid)
+{
+ struct passwd *pwent;
+ struct extract *extract;
+ int h;
+ struct bucket *b;
+ int cache_size;
+
+ extract = a->extract;
+ cache_size = sizeof(extract->ucache) / sizeof(extract->ucache[0]);
+
+ /* If no uname, just use the uid provided. */
+ if (uname == NULL || *uname == '\0')
+ return (uid);
+
+ /* Try to find uname in the cache. */
+ h = hash(uname);
+ b = &extract->ucache[h % cache_size ];
+ if (b->name != NULL && b->hash == h && strcmp(uname, b->name) == 0)
+ return ((uid_t)b->id);
+
+ /* Free the cache slot for a new entry. */
+ if (b->name != NULL)
+ free(b->name);
+ b->name = strdup(uname);
+ /* Note: If strdup fails, that's okay; we just won't cache. */
+ b->hash = h;
+ pwent = getpwnam(uname);
+ if (pwent != NULL)
+ uid = pwent->pw_uid;
+ b->id = uid;
+
+ return (uid);
+}
+
+static unsigned int
+hash(const char *p)
+{
+ /* A 32-bit version of Peter Weinberger's (PJW) hash algorithm,
+ as used by ELF for hashing function names. */
+ unsigned g, h = 0;
+ while (*p != '\0') {
+ h = ( h << 4 ) + *p++;
+ if (( g = h & 0xF0000000 )) {
+ h ^= g >> 24;
+ h &= 0x0FFFFFFF;
+ }
+ }
+ return h;
+}
+
+void
+archive_read_extract_set_progress_callback(struct archive *a,
+ void (*progress_func)(void *), void *user_data)
+{
+ a->extract_progress = progress_func;
+ a->extract_progress_user_data = user_data;
+}
diff --git a/lib/libarchive/archive_read_open_fd.c b/lib/libarchive/archive_read_open_fd.c
new file mode 100644
index 0000000..c5716e7
--- /dev/null
+++ b/lib/libarchive/archive_read_open_fd.c
@@ -0,0 +1,106 @@
+/*-
+ * Copyright (c) 2003-2004 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(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 AUTHOR(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 "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#include <sys/stat.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "archive.h"
+#include "archive_private.h"
+
+struct read_fd_data {
+ int fd;
+ size_t block_size;
+ void *buffer;
+};
+
+static int file_close(struct archive *, void *);
+static int file_open(struct archive *, void *);
+static ssize_t file_read(struct archive *, void *, const void **buff);
+
+int
+archive_read_open_fd(struct archive *a, int fd, size_t block_size)
+{
+ struct read_fd_data *mine;
+
+ mine = malloc(sizeof(*mine));
+ if (mine == NULL) {
+ archive_set_error(a, ENOMEM, "No memory");
+ return (ARCHIVE_FATAL);
+ }
+ mine->block_size = block_size;
+ mine->buffer = malloc(mine->block_size);
+ if (mine->buffer == NULL) {
+ archive_set_error(a, ENOMEM, "No memory");
+ free(mine);
+ return (ARCHIVE_FATAL);
+ }
+ mine->fd = fd;
+ return (archive_read_open(a, mine, file_open, file_read, file_close));
+}
+
+static int
+file_open(struct archive *a, void *client_data)
+{
+ struct read_fd_data *mine = client_data;
+ struct stat st;
+
+ if (fstat(mine->fd, &st) != 0) {
+ archive_set_error(a, errno, "Can't stat fd %d", mine->fd);
+ return (ARCHIVE_FATAL);
+ }
+
+ a->skip_file_dev = st.st_dev;
+ a->skip_file_ino = st.st_ino;
+ return (ARCHIVE_OK);
+}
+
+static ssize_t
+file_read(struct archive *a, void *client_data, const void **buff)
+{
+ struct read_fd_data *mine = client_data;
+
+ (void)a; /* UNUSED */
+ *buff = mine->buffer;
+ return (read(mine->fd, mine->buffer, mine->block_size));
+}
+
+static int
+file_close(struct archive *a, void *client_data)
+{
+ struct read_fd_data *mine = client_data;
+
+ (void)a; /* UNUSED */
+ if (mine->buffer != NULL)
+ free(mine->buffer);
+ free(mine);
+ return (ARCHIVE_OK);
+}
diff --git a/lib/libarchive/archive_read_open_file.c b/lib/libarchive/archive_read_open_file.c
new file mode 100644
index 0000000..b0db61c
--- /dev/null
+++ b/lib/libarchive/archive_read_open_file.c
@@ -0,0 +1,168 @@
+/*-
+ * Copyright (c) 2003-2004 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(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 AUTHOR(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 "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#include <sys/stat.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "archive.h"
+#include "archive_private.h"
+
+struct read_file_data {
+ int fd;
+ size_t block_size;
+ void *buffer;
+ mode_t st_mode; /* Mode bits for opened file. */
+ char filename[1]; /* Must be last! */
+};
+
+static int file_close(struct archive *, void *);
+static int file_open(struct archive *, void *);
+static ssize_t file_read(struct archive *, void *, const void **buff);
+
+int
+archive_read_open_file(struct archive *a, const char *filename,
+ size_t block_size)
+{
+ struct read_file_data *mine;
+
+ if (filename == NULL || filename[0] == '\0') {
+ mine = malloc(sizeof(*mine));
+ if (mine == NULL) {
+ archive_set_error(a, ENOMEM, "No memory");
+ return (ARCHIVE_FATAL);
+ }
+ mine->filename[0] = '\0';
+ } else {
+ mine = malloc(sizeof(*mine) + strlen(filename));
+ if (mine == NULL) {
+ archive_set_error(a, ENOMEM, "No memory");
+ return (ARCHIVE_FATAL);
+ }
+ strcpy(mine->filename, filename);
+ }
+ mine->block_size = block_size;
+ mine->buffer = NULL;
+ mine->fd = -1;
+ return (archive_read_open(a, mine, file_open, file_read, file_close));
+}
+
+static int
+file_open(struct archive *a, void *client_data)
+{
+ struct read_file_data *mine = client_data;
+ struct stat st;
+
+ mine->buffer = malloc(mine->block_size);
+ if (mine->buffer == NULL) {
+ archive_set_error(a, ENOMEM, "No memory");
+ return (ARCHIVE_FATAL);
+ }
+ if (mine->filename[0] != '\0')
+ mine->fd = open(mine->filename, O_RDONLY);
+ else
+ mine->fd = 0; /* Fake "open" for stdin. */
+ if (mine->fd < 0) {
+ archive_set_error(a, errno, "Failed to open '%s'",
+ mine->filename);
+ return (ARCHIVE_FATAL);
+ }
+ if (fstat(mine->fd, &st) == 0) {
+ /* Set dev/ino of archive file so extract won't overwrite. */
+ a->skip_file_dev = st.st_dev;
+ a->skip_file_ino = st.st_ino;
+ /* Remember mode so close can decide whether to flush. */
+ mine->st_mode = st.st_mode;
+ } else {
+ if (mine->filename[0] == '\0')
+ archive_set_error(a, errno, "Can't stat stdin");
+ else
+ archive_set_error(a, errno, "Can't stat '%s'",
+ mine->filename);
+ return (ARCHIVE_FATAL);
+ }
+ return (0);
+}
+
+static ssize_t
+file_read(struct archive *a, void *client_data, const void **buff)
+{
+ struct read_file_data *mine = client_data;
+ ssize_t bytes_read;
+
+ (void)a; /* UNUSED */
+ *buff = mine->buffer;
+ bytes_read = read(mine->fd, mine->buffer, mine->block_size);
+ if (bytes_read < 0) {
+ if (mine->filename[0] == '\0')
+ archive_set_error(a, errno, "Error reading stdin");
+ else
+ archive_set_error(a, errno, "Error reading '%s'",
+ mine->filename);
+ }
+ return (bytes_read);
+}
+
+static int
+file_close(struct archive *a, void *client_data)
+{
+ struct read_file_data *mine = client_data;
+
+ (void)a; /* UNUSED */
+
+ /*
+ * Sometimes, we should flush the input before closing.
+ * Regular files: faster to just close without flush.
+ * Devices: must not flush (user might need to
+ * read the "next" item on a non-rewind device).
+ * Pipes and sockets: must flush (otherwise, the
+ * program feeding the pipe or socket may complain).
+ * Here, I flush everything except for regular files and
+ * device nodes.
+ */
+ if (!S_ISREG(mine->st_mode)
+ && !S_ISCHR(mine->st_mode)
+ && !S_ISBLK(mine->st_mode)) {
+ ssize_t bytesRead;
+ do {
+ bytesRead = read(mine->fd, mine->buffer,
+ mine->block_size);
+ } while (bytesRead > 0);
+ }
+ /* If a named file was opened, then it needs to be closed. */
+ if (mine->filename[0] != '\0')
+ close(mine->fd);
+ if (mine->buffer != NULL)
+ free(mine->buffer);
+ free(mine);
+ return (ARCHIVE_OK);
+}
diff --git a/lib/libarchive/archive_read_open_filename.c b/lib/libarchive/archive_read_open_filename.c
new file mode 100644
index 0000000..b0db61c
--- /dev/null
+++ b/lib/libarchive/archive_read_open_filename.c
@@ -0,0 +1,168 @@
+/*-
+ * Copyright (c) 2003-2004 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(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 AUTHOR(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 "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#include <sys/stat.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "archive.h"
+#include "archive_private.h"
+
+struct read_file_data {
+ int fd;
+ size_t block_size;
+ void *buffer;
+ mode_t st_mode; /* Mode bits for opened file. */
+ char filename[1]; /* Must be last! */
+};
+
+static int file_close(struct archive *, void *);
+static int file_open(struct archive *, void *);
+static ssize_t file_read(struct archive *, void *, const void **buff);
+
+int
+archive_read_open_file(struct archive *a, const char *filename,
+ size_t block_size)
+{
+ struct read_file_data *mine;
+
+ if (filename == NULL || filename[0] == '\0') {
+ mine = malloc(sizeof(*mine));
+ if (mine == NULL) {
+ archive_set_error(a, ENOMEM, "No memory");
+ return (ARCHIVE_FATAL);
+ }
+ mine->filename[0] = '\0';
+ } else {
+ mine = malloc(sizeof(*mine) + strlen(filename));
+ if (mine == NULL) {
+ archive_set_error(a, ENOMEM, "No memory");
+ return (ARCHIVE_FATAL);
+ }
+ strcpy(mine->filename, filename);
+ }
+ mine->block_size = block_size;
+ mine->buffer = NULL;
+ mine->fd = -1;
+ return (archive_read_open(a, mine, file_open, file_read, file_close));
+}
+
+static int
+file_open(struct archive *a, void *client_data)
+{
+ struct read_file_data *mine = client_data;
+ struct stat st;
+
+ mine->buffer = malloc(mine->block_size);
+ if (mine->buffer == NULL) {
+ archive_set_error(a, ENOMEM, "No memory");
+ return (ARCHIVE_FATAL);
+ }
+ if (mine->filename[0] != '\0')
+ mine->fd = open(mine->filename, O_RDONLY);
+ else
+ mine->fd = 0; /* Fake "open" for stdin. */
+ if (mine->fd < 0) {
+ archive_set_error(a, errno, "Failed to open '%s'",
+ mine->filename);
+ return (ARCHIVE_FATAL);
+ }
+ if (fstat(mine->fd, &st) == 0) {
+ /* Set dev/ino of archive file so extract won't overwrite. */
+ a->skip_file_dev = st.st_dev;
+ a->skip_file_ino = st.st_ino;
+ /* Remember mode so close can decide whether to flush. */
+ mine->st_mode = st.st_mode;
+ } else {
+ if (mine->filename[0] == '\0')
+ archive_set_error(a, errno, "Can't stat stdin");
+ else
+ archive_set_error(a, errno, "Can't stat '%s'",
+ mine->filename);
+ return (ARCHIVE_FATAL);
+ }
+ return (0);
+}
+
+static ssize_t
+file_read(struct archive *a, void *client_data, const void **buff)
+{
+ struct read_file_data *mine = client_data;
+ ssize_t bytes_read;
+
+ (void)a; /* UNUSED */
+ *buff = mine->buffer;
+ bytes_read = read(mine->fd, mine->buffer, mine->block_size);
+ if (bytes_read < 0) {
+ if (mine->filename[0] == '\0')
+ archive_set_error(a, errno, "Error reading stdin");
+ else
+ archive_set_error(a, errno, "Error reading '%s'",
+ mine->filename);
+ }
+ return (bytes_read);
+}
+
+static int
+file_close(struct archive *a, void *client_data)
+{
+ struct read_file_data *mine = client_data;
+
+ (void)a; /* UNUSED */
+
+ /*
+ * Sometimes, we should flush the input before closing.
+ * Regular files: faster to just close without flush.
+ * Devices: must not flush (user might need to
+ * read the "next" item on a non-rewind device).
+ * Pipes and sockets: must flush (otherwise, the
+ * program feeding the pipe or socket may complain).
+ * Here, I flush everything except for regular files and
+ * device nodes.
+ */
+ if (!S_ISREG(mine->st_mode)
+ && !S_ISCHR(mine->st_mode)
+ && !S_ISBLK(mine->st_mode)) {
+ ssize_t bytesRead;
+ do {
+ bytesRead = read(mine->fd, mine->buffer,
+ mine->block_size);
+ } while (bytesRead > 0);
+ }
+ /* If a named file was opened, then it needs to be closed. */
+ if (mine->filename[0] != '\0')
+ close(mine->fd);
+ if (mine->buffer != NULL)
+ free(mine->buffer);
+ free(mine);
+ return (ARCHIVE_OK);
+}
diff --git a/lib/libarchive/archive_read_support_compression_all.c b/lib/libarchive/archive_read_support_compression_all.c
new file mode 100644
index 0000000..bd3a9b9
--- /dev/null
+++ b/lib/libarchive/archive_read_support_compression_all.c
@@ -0,0 +1,44 @@
+/*-
+ * Copyright (c) 2003-2004 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(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 AUTHOR(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 "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#include "archive.h"
+
+int
+archive_read_support_compression_all(struct archive *a)
+{
+#if HAVE_BZLIB_H
+ archive_read_support_compression_bzip2(a);
+#endif
+ /* The decompress code doesn't use an outside library. */
+ archive_read_support_compression_compress(a);
+#if HAVE_ZLIB_H
+ archive_read_support_compression_gzip(a);
+#endif
+ return (ARCHIVE_OK);
+}
diff --git a/lib/libarchive/archive_read_support_compression_bzip2.c b/lib/libarchive/archive_read_support_compression_bzip2.c
new file mode 100644
index 0000000..aa2d531
--- /dev/null
+++ b/lib/libarchive/archive_read_support_compression_bzip2.c
@@ -0,0 +1,393 @@
+/*-
+ * Copyright (c) 2003-2004 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(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 AUTHOR(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 "archive_platform.h"
+
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#ifdef HAVE_BZLIB_H
+#include <bzlib.h>
+#endif
+
+#include "archive.h"
+#include "archive_private.h"
+
+#if HAVE_BZLIB_H
+struct private_data {
+ bz_stream stream;
+ char *uncompressed_buffer;
+ size_t uncompressed_buffer_size;
+ char *read_next;
+ int64_t total_out;
+};
+
+static int finish(struct archive *);
+static ssize_t read_ahead(struct archive *, const void **, size_t);
+static ssize_t read_consume(struct archive *, size_t);
+static int drive_decompressor(struct archive *a, struct private_data *);
+#endif
+
+/* These two functions are defined even if we lack bzlib. See below. */
+static int bid(const void *, size_t);
+static int init(struct archive *, const void *, size_t);
+
+int
+archive_read_support_compression_bzip2(struct archive *a)
+{
+ return (__archive_read_register_compression(a, bid, init));
+}
+
+/*
+ * Test whether we can handle this data.
+ *
+ * This logic returns zero if any part of the signature fails. It
+ * also tries to Do The Right Thing if a very short buffer prevents us
+ * from verifying as much as we would like.
+ */
+static int
+bid(const void *buff, size_t len)
+{
+ const unsigned char *buffer;
+ int bits_checked;
+
+ if (len < 1)
+ return (0);
+
+ buffer = buff;
+ bits_checked = 0;
+ if (buffer[0] != 'B') /* Verify first ID byte. */
+ return (0);
+ bits_checked += 8;
+ if (len < 2)
+ return (bits_checked);
+
+ if (buffer[1] != 'Z') /* Verify second ID byte. */
+ return (0);
+ bits_checked += 8;
+ if (len < 3)
+ return (bits_checked);
+
+ if (buffer[2] != 'h') /* Verify third ID byte. */
+ return (0);
+ bits_checked += 8;
+ if (len < 4)
+ return (bits_checked);
+
+ if (buffer[3] < '1' || buffer[3] > '9')
+ return (0);
+ bits_checked += 5;
+
+ /*
+ * Research Question: Can we do any more to verify that this
+ * really is BZip2 format?? For 99.9% of the time, the above
+ * test is sufficient, but it would be nice to do a more
+ * thorough check. It's especially troubling that the BZip2
+ * signature begins with all ASCII characters; a tar archive
+ * whose first filename begins with 'BZh3' would potentially
+ * fool this logic. (It may also be possible to gaurd against
+ * such anomalies in archive_read_support_compression_none.)
+ */
+
+ return (bits_checked);
+}
+
+#ifndef HAVE_BZLIB_H
+
+/*
+ * If we don't have bzlib on this system, we can't actually do the
+ * decompression. We can, however, still detect bzip2-compressed
+ * archives and emit a useful message.
+ */
+static int
+init(struct archive *a, const void *buff, size_t n)
+{
+ (void)a; /* UNUSED */
+ (void)buff; /* UNUSED */
+ (void)n; /* UNUSED */
+
+ archive_set_error(a, -1,
+ "This version of libarchive was compiled without bzip2 support");
+ return (ARCHIVE_FATAL);
+}
+
+
+#else
+
+/*
+ * Setup the callbacks.
+ */
+static int
+init(struct archive *a, const void *buff, size_t n)
+{
+ struct private_data *state;
+ int ret;
+
+ a->compression_code = ARCHIVE_COMPRESSION_BZIP2;
+ a->compression_name = "bzip2";
+
+ state = malloc(sizeof(*state));
+ if (state == NULL) {
+ archive_set_error(a, ENOMEM,
+ "Can't allocate data for %s decompression",
+ a->compression_name);
+ return (ARCHIVE_FATAL);
+ }
+ memset(state, 0, sizeof(*state));
+
+ state->uncompressed_buffer_size = 64 * 1024;
+ state->uncompressed_buffer = malloc(state->uncompressed_buffer_size);
+ state->stream.next_out = state->uncompressed_buffer;
+ state->read_next = state->uncompressed_buffer;
+ state->stream.avail_out = state->uncompressed_buffer_size;
+
+ if (state->uncompressed_buffer == NULL) {
+ archive_set_error(a, ENOMEM,
+ "Can't allocate %s decompression buffers",
+ a->compression_name);
+ free(state);
+ return (ARCHIVE_FATAL);
+ }
+
+ /*
+ * A bug in bzlib.h: stream.next_in should be marked 'const'
+ * but isn't (the library never alters data through the
+ * next_in pointer, only reads it). The result: this ugly
+ * cast to remove 'const'.
+ */
+ state->stream.next_in = (void *)(uintptr_t)(const void *)buff;
+ state->stream.avail_in = n;
+
+ a->compression_read_ahead = read_ahead;
+ a->compression_read_consume = read_consume;
+ a->compression_finish = finish;
+
+ /* Initialize compression library. */
+ ret = BZ2_bzDecompressInit(&(state->stream),
+ 0 /* library verbosity */,
+ 0 /* don't use slow low-mem algorithm */);
+
+ /* If init fails, try using low-memory algorithm instead. */
+ if (ret == BZ_MEM_ERROR) {
+ ret = BZ2_bzDecompressInit(&(state->stream),
+ 0 /* library verbosity */,
+ 1 /* do use slow low-mem algorithm */);
+ }
+
+ if (ret == BZ_OK) {
+ a->compression_data = state;
+ return (ARCHIVE_OK);
+ }
+
+ /* Library setup failed: Clean up. */
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "Internal error initializing %s library", a->compression_name);
+ free(state->uncompressed_buffer);
+ free(state);
+
+ /* Override the error message if we know what really went wrong. */
+ switch (ret) {
+ case BZ_PARAM_ERROR:
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "Internal error initializing compression library: "
+ "invalid setup parameter");
+ break;
+ case BZ_MEM_ERROR:
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "Internal error initializing compression library: "
+ "out of memory");
+ break;
+ case BZ_CONFIG_ERROR:
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "Internal error initializing compression library: "
+ "mis-compiled library");
+ break;
+ }
+
+ return (ARCHIVE_FATAL);
+}
+
+/*
+ * Return a block of data from the decompression buffer. Decompress more
+ * as necessary.
+ */
+static ssize_t
+read_ahead(struct archive *a, const void **p, size_t min)
+{
+ struct private_data *state;
+ int read_avail, was_avail, ret;
+
+ state = a->compression_data;
+ was_avail = -1;
+ if (!a->client_reader) {
+ archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER,
+ "No read callback is registered? "
+ "This is probably an internal programming error.");
+ return (ARCHIVE_FATAL);
+ }
+
+ read_avail = state->stream.next_out - state->read_next;
+
+ if (read_avail + state->stream.avail_out < min) {
+ memmove(state->uncompressed_buffer, state->read_next,
+ read_avail);
+ state->read_next = state->uncompressed_buffer;
+ state->stream.next_out = state->read_next + read_avail;
+ state->stream.avail_out
+ = state->uncompressed_buffer_size - read_avail;
+ }
+
+ while (was_avail < read_avail && /* Made some progress. */
+ read_avail < (int)min && /* Haven't satisfied min. */
+ read_avail < (int)state->uncompressed_buffer_size) { /* !full */
+ if ((ret = drive_decompressor(a, state)) != ARCHIVE_OK)
+ return (ret);
+ was_avail = read_avail;
+ read_avail = state->stream.next_out - state->read_next;
+ }
+
+ *p = state->read_next;
+ return (read_avail);
+}
+
+/*
+ * Mark a previously-returned block of data as read.
+ */
+static ssize_t
+read_consume(struct archive *a, size_t n)
+{
+ struct private_data *state;
+
+ state = a->compression_data;
+ a->file_position += n;
+ state->read_next += n;
+ if (state->read_next > state->stream.next_out)
+ __archive_errx(1, "Request to consume too many "
+ "bytes from bzip2 decompressor");
+ return (n);
+}
+
+/*
+ * Clean up the decompressor.
+ */
+static int
+finish(struct archive *a)
+{
+ struct private_data *state;
+ int ret;
+
+ state = a->compression_data;
+ ret = ARCHIVE_OK;
+ switch (BZ2_bzDecompressEnd(&(state->stream))) {
+ case BZ_OK:
+ break;
+ default:
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "Failed to clean up %s compressor", a->compression_name);
+ ret = ARCHIVE_FATAL;
+ }
+
+ free(state->uncompressed_buffer);
+ free(state);
+
+ a->compression_data = NULL;
+ if (a->client_closer != NULL)
+ (a->client_closer)(a, a->client_data);
+
+ return (ret);
+}
+
+/*
+ * Utility function to pull data through decompressor, reading input
+ * blocks as necessary.
+ */
+static int
+drive_decompressor(struct archive *a, struct private_data *state)
+{
+ ssize_t ret;
+ int decompressed, total_decompressed;
+ char *output;
+
+ total_decompressed = 0;
+ for (;;) {
+ if (state->stream.avail_in == 0) {
+ ret = (a->client_reader)(a, a->client_data,
+ (const void **)&state->stream.next_in);
+ if (ret < 0) {
+ /*
+ * TODO: Find a better way to handle
+ * this read failure.
+ */
+ goto fatal;
+ }
+ if (ret == 0 && total_decompressed == 0) {
+ archive_set_error(a, EIO,
+ "Premature end of %s compressed data",
+ a->compression_name);
+ return (ARCHIVE_FATAL);
+ }
+ a->raw_position += ret;
+ state->stream.avail_in = ret;
+ }
+
+ {
+ output = state->stream.next_out;
+
+ /* Decompress some data. */
+ ret = BZ2_bzDecompress(&(state->stream));
+ decompressed = state->stream.next_out - output;
+
+ /* Accumulate the total bytes of output. */
+ state->total_out += decompressed;
+ total_decompressed += decompressed;
+
+ switch (ret) {
+ case BZ_OK: /* Decompressor made some progress. */
+ if (decompressed > 0)
+ return (ARCHIVE_OK);
+ break;
+ case BZ_STREAM_END: /* Found end of stream. */
+ return (ARCHIVE_OK);
+ default:
+ /* Any other return value is an error. */
+ goto fatal;
+ }
+ }
+ }
+ return (ARCHIVE_OK);
+
+ /* Return a fatal error. */
+fatal:
+ archive_set_error(a, ARCHIVE_ERRNO_MISC, "%s decompression failed",
+ a->compression_name);
+ return (ARCHIVE_FATAL);
+}
+
+#endif /* HAVE_BZLIB_H */
diff --git a/lib/libarchive/archive_read_support_compression_compress.c b/lib/libarchive/archive_read_support_compression_compress.c
new file mode 100644
index 0000000..30a7377
--- /dev/null
+++ b/lib/libarchive/archive_read_support_compression_compress.c
@@ -0,0 +1,482 @@
+/*-
+ * Copyright (c) 2003-2004 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(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 AUTHOR(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.
+ */
+
+/*
+ * This code borrows heavily from "compress" source code, which is
+ * protected by the following copyright. (Clause 3 dropped by request
+ * of the Regents.)
+ */
+
+/*-
+ * Copyright (c) 1985, 1986, 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Diomidis Spinellis and James A. Woods, derived from original
+ * work by Spencer Thomas and Joseph Orost.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#include "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "archive.h"
+#include "archive_private.h"
+
+/*
+ * Because LZW decompression is pretty simple, I've just implemented
+ * the whole decompressor here (cribbing from "compress" source code,
+ * of course), rather than relying on an external library. I have
+ * made an effort to clarify and simplify the algorithm, so the
+ * names and structure here don't exactly match those used by compress.
+ */
+
+struct private_data {
+ /* Input variables. */
+ const unsigned char *next_in;
+ size_t avail_in;
+ int bit_buffer;
+ int bits_avail;
+ size_t bytes_in_section;
+
+ /* Output variables. */
+ size_t uncompressed_buffer_size;
+ void *uncompressed_buffer;
+ unsigned char *read_next; /* Data for client. */
+ unsigned char *next_out; /* Where to write new data. */
+ size_t avail_out; /* Space at end of buffer. */
+
+ /* Decompression status variables. */
+ int use_reset_code;
+ int end_of_stream; /* EOF status. */
+ int maxcode; /* Largest code. */
+ int maxcode_bits; /* Length of largest code. */
+ int section_end_code; /* When to increase bits. */
+ int bits; /* Current code length. */
+ int oldcode; /* Previous code. */
+ int finbyte; /* Last byte of prev code. */
+
+ /* Dictionary. */
+ int free_ent; /* Next dictionary entry. */
+ unsigned char suffix[65536];
+ uint16_t prefix[65536];
+
+ /*
+ * Scratch area for expanding dictionary entries. Note:
+ * "worst" case here comes from compressing /dev/zero: the
+ * last code in the dictionary will code a sequence of
+ * 65536-256 zero bytes. Thus, we need stack space to expand
+ * a 65280-byte dictionary entry. (Of course, 32640:1
+ * compression could also be considered the "best" case. ;-)
+ */
+ unsigned char *stackp;
+ unsigned char stack[65300];
+};
+
+static int bid(const void *, size_t);
+static int finish(struct archive *);
+static int init(struct archive *, const void *, size_t);
+static ssize_t read_ahead(struct archive *, const void **, size_t);
+static ssize_t read_consume(struct archive *, size_t);
+static int getbits(struct archive *, struct private_data *, int n);
+static int next_code(struct archive *a, struct private_data *state);
+
+int
+archive_read_support_compression_compress(struct archive *a)
+{
+ return (__archive_read_register_compression(a, bid, init));
+}
+
+/*
+ * Test whether we can handle this data.
+ *
+ * This logic returns zero if any part of the signature fails. It
+ * also tries to Do The Right Thing if a very short buffer prevents us
+ * from verifying as much as we would like.
+ */
+static int
+bid(const void *buff, size_t len)
+{
+ const unsigned char *buffer;
+ int bits_checked;
+
+ if (len < 1)
+ return (0);
+
+ buffer = buff;
+ bits_checked = 0;
+ if (buffer[0] != 037) /* Verify first ID byte. */
+ return (0);
+ bits_checked += 8;
+ if (len < 2)
+ return (bits_checked);
+
+ if (buffer[1] != 0235) /* Verify second ID byte. */
+ return (0);
+ bits_checked += 8;
+ if (len < 3)
+ return (bits_checked);
+
+ /*
+ * TODO: Verify more.
+ */
+
+ return (bits_checked);
+}
+
+/*
+ * Setup the callbacks.
+ */
+static int
+init(struct archive *a, const void *buff, size_t n)
+{
+ struct private_data *state;
+ int code;
+
+ a->compression_code = ARCHIVE_COMPRESSION_COMPRESS;
+ a->compression_name = "compress (.Z)";
+
+ a->compression_read_ahead = read_ahead;
+ a->compression_read_consume = read_consume;
+ a->compression_finish = finish;
+
+ state = malloc(sizeof(*state));
+ if (state == NULL) {
+ archive_set_error(a, ENOMEM,
+ "Can't allocate data for %s decompression",
+ a->compression_name);
+ return (ARCHIVE_FATAL);
+ }
+ memset(state, 0, sizeof(*state));
+ a->compression_data = state;
+
+ state->uncompressed_buffer_size = 64 * 1024;
+ state->uncompressed_buffer = malloc(state->uncompressed_buffer_size);
+
+ if (state->uncompressed_buffer == NULL) {
+ archive_set_error(a, ENOMEM,
+ "Can't allocate %s decompression buffers",
+ a->compression_name);
+ goto fatal;
+ }
+
+ state->next_in = buff;
+ state->avail_in = n;
+ state->read_next = state->next_out = state->uncompressed_buffer;
+ state->avail_out = state->uncompressed_buffer_size;
+
+ code = getbits(a, state, 8);
+ if (code != 037) /* This should be impossible. */
+ goto fatal;
+
+ code = getbits(a, state, 8);
+ if (code != 0235) {
+ /* This can happen if the library is receiving 1-byte
+ * blocks and gzip and compress are both enabled.
+ * You can't distinguish gzip and compress only from
+ * the first byte. */
+ archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Compress signature did not match.");
+ goto fatal;
+ }
+
+ code = getbits(a, state, 8);
+ state->maxcode_bits = code & 0x1f;
+ state->maxcode = (1 << state->maxcode_bits);
+ state->use_reset_code = code & 0x80;
+
+ /* Initialize decompressor. */
+ state->free_ent = 256;
+ state->stackp = state->stack;
+ if (state->use_reset_code)
+ state->free_ent++;
+ state->bits = 9;
+ state->section_end_code = (1<<state->bits) - 1;
+ state->oldcode = -1;
+ for (code = 255; code >= 0; code--) {
+ state->prefix[code] = 0;
+ state->suffix[code] = code;
+ }
+ next_code(a, state);
+ return (ARCHIVE_OK);
+
+fatal:
+ finish(a);
+ return (ARCHIVE_FATAL);
+}
+
+/*
+ * Return a block of data from the decompression buffer. Decompress more
+ * as necessary.
+ */
+static ssize_t
+read_ahead(struct archive *a, const void **p, size_t min)
+{
+ struct private_data *state;
+ int read_avail, was_avail, ret;
+
+ state = a->compression_data;
+ was_avail = -1;
+ if (!a->client_reader) {
+ archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER,
+ "No read callback is registered? "
+ "This is probably an internal programming error.");
+ return (ARCHIVE_FATAL);
+ }
+
+ read_avail = state->next_out - state->read_next;
+
+ if (read_avail < (int)min && state->end_of_stream) {
+ if (state->end_of_stream == ARCHIVE_EOF)
+ return (0);
+ else
+ return (-1);
+ }
+
+ if (read_avail < (int)min) {
+ memmove(state->uncompressed_buffer, state->read_next,
+ read_avail);
+ state->read_next = state->uncompressed_buffer;
+ state->next_out = state->read_next + read_avail;
+ state->avail_out
+ = state->uncompressed_buffer_size - read_avail;
+
+ while (read_avail < (int)state->uncompressed_buffer_size
+ && !state->end_of_stream) {
+ if (state->stackp > state->stack) {
+ *state->next_out++ = *--state->stackp;
+ state->avail_out--;
+ read_avail++;
+ } else {
+ ret = next_code(a, state);
+ if (ret == ARCHIVE_EOF)
+ state->end_of_stream = ret;
+ else if (ret != ARCHIVE_OK)
+ return (ret);
+ }
+ }
+ }
+
+ *p = state->read_next;
+ return (read_avail);
+}
+
+/*
+ * Mark a previously-returned block of data as read.
+ */
+static ssize_t
+read_consume(struct archive *a, size_t n)
+{
+ struct private_data *state;
+
+ state = a->compression_data;
+ a->file_position += n;
+ state->read_next += n;
+ if (state->read_next > state->next_out)
+ __archive_errx(1, "Request to consume too many "
+ "bytes from compress decompressor");
+ return (n);
+}
+
+/*
+ * Clean up the decompressor.
+ */
+static int
+finish(struct archive *a)
+{
+ struct private_data *state;
+ int ret = ARCHIVE_OK;
+
+ state = a->compression_data;
+
+ if (state != NULL) {
+ if (state->uncompressed_buffer != NULL)
+ free(state->uncompressed_buffer);
+ free(state);
+ }
+
+ a->compression_data = NULL;
+ if (a->client_closer != NULL)
+ ret = (a->client_closer)(a, a->client_data);
+
+ return (ret);
+}
+
+/*
+ * Process the next code and fill the stack with the expansion
+ * of the code. Returns ARCHIVE_FATAL if there is a fatal I/O or
+ * format error, ARCHIVE_EOF if we hit end of data, ARCHIVE_OK otherwise.
+ */
+static int
+next_code(struct archive *a, struct private_data *state)
+{
+ int code, newcode;
+
+ static int debug_buff[1024];
+ static unsigned debug_index;
+
+ code = newcode = getbits(a, state, state->bits);
+ if (code < 0)
+ return (code);
+
+ debug_buff[debug_index++] = code;
+ if (debug_index >= sizeof(debug_buff)/sizeof(debug_buff[0]))
+ debug_index = 0;
+
+ /* If it's a reset code, reset the dictionary. */
+ if ((code == 256) && state->use_reset_code) {
+ /*
+ * The original 'compress' implementation blocked its
+ * I/O in a manner that resulted in junk bytes being
+ * inserted after every reset. The next section skips
+ * this junk. (Yes, the number of *bytes* to skip is
+ * a function of the current *bit* length.)
+ */
+ int skip_bytes = state->bits -
+ (state->bytes_in_section % state->bits);
+ skip_bytes %= state->bits;
+ state->bits_avail = 0; /* Discard rest of this byte. */
+ while (skip_bytes-- > 0) {
+ code = getbits(a, state, 8);
+ if (code < 0)
+ return (code);
+ }
+ /* Now, actually do the reset. */
+ state->bytes_in_section = 0;
+ state->bits = 9;
+ state->section_end_code = (1 << state->bits) - 1;
+ state->free_ent = 257;
+ state->oldcode = -1;
+ return (next_code(a, state));
+ }
+
+ if (code > state->free_ent) {
+ /* An invalid code is a fatal error. */
+ archive_set_error(a, -1, "Invalid compressed data");
+ return (ARCHIVE_FATAL);
+ }
+
+ /* Special case for KwKwK string. */
+ if (code >= state->free_ent) {
+ *state->stackp++ = state->finbyte;
+ code = state->oldcode;
+ }
+
+ /* Generate output characters in reverse order. */
+ while (code >= 256) {
+ *state->stackp++ = state->suffix[code];
+ code = state->prefix[code];
+ }
+ *state->stackp++ = state->finbyte = code;
+
+ /* Generate the new entry. */
+ code = state->free_ent;
+ if (code < state->maxcode && state->oldcode >= 0) {
+ state->prefix[code] = state->oldcode;
+ state->suffix[code] = state->finbyte;
+ ++state->free_ent;
+ }
+ if (state->free_ent > state->section_end_code) {
+ state->bits++;
+ state->bytes_in_section = 0;
+ if (state->bits == state->maxcode_bits)
+ state->section_end_code = state->maxcode;
+ else
+ state->section_end_code = (1 << state->bits) - 1;
+ }
+
+ /* Remember previous code. */
+ state->oldcode = newcode;
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Return next 'n' bits from stream.
+ *
+ * -1 indicates end of available data.
+ */
+static int
+getbits(struct archive *a, struct private_data *state, int n)
+{
+ int code, ret;
+ static const int mask[] = {
+ 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff,
+ 0x1ff, 0x3ff, 0x7ff, 0xfff, 0x1fff, 0x3fff, 0x7fff, 0xffff
+ };
+
+
+ while (state->bits_avail < n) {
+ if (state->avail_in <= 0) {
+ ret = (a->client_reader)(a, a->client_data,
+ (const void **)&state->next_in);
+ if (ret < 0)
+ return (ARCHIVE_FATAL);
+ if (ret == 0)
+ return (ARCHIVE_EOF);
+ a->raw_position += ret;
+ state->avail_in = ret;
+ }
+ state->bit_buffer |= *state->next_in++ << state->bits_avail;
+ state->avail_in--;
+ state->bits_avail += 8;
+ state->bytes_in_section++;
+ }
+
+ code = state->bit_buffer;
+ state->bit_buffer >>= n;
+ state->bits_avail -= n;
+
+ return (code & mask[n]);
+}
diff --git a/lib/libarchive/archive_read_support_compression_gzip.c b/lib/libarchive/archive_read_support_compression_gzip.c
new file mode 100644
index 0000000..b0cda3a
--- /dev/null
+++ b/lib/libarchive/archive_read_support_compression_gzip.c
@@ -0,0 +1,531 @@
+/*-
+ * Copyright (c) 2003-2004 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(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 AUTHOR(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 "archive_platform.h"
+
+__FBSDID("$FreeBSD$");
+
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#ifdef HAVE_ZLIB_H
+#include <zlib.h>
+#endif
+
+#include "archive.h"
+#include "archive_private.h"
+
+#ifdef HAVE_ZLIB_H
+struct private_data {
+ z_stream stream;
+ unsigned char *uncompressed_buffer;
+ size_t uncompressed_buffer_size;
+ unsigned char *read_next;
+ int64_t total_out;
+ unsigned long crc;
+ char header_done;
+};
+
+static int finish(struct archive *);
+static ssize_t read_ahead(struct archive *, const void **, size_t);
+static ssize_t read_consume(struct archive *, size_t);
+static int drive_decompressor(struct archive *a, struct private_data *);
+#endif
+
+/* These two functions are defined even if we lack zlib. See below. */
+static int bid(const void *, size_t);
+static int init(struct archive *, const void *, size_t);
+
+int
+archive_read_support_compression_gzip(struct archive *a)
+{
+ return (__archive_read_register_compression(a, bid, init));
+}
+
+/*
+ * Test whether we can handle this data.
+ *
+ * This logic returns zero if any part of the signature fails. It
+ * also tries to Do The Right Thing if a very short buffer prevents us
+ * from verifying as much as we would like.
+ */
+static int
+bid(const void *buff, size_t len)
+{
+ const unsigned char *buffer;
+ int bits_checked;
+
+ if (len < 1)
+ return (0);
+
+ buffer = buff;
+ bits_checked = 0;
+ if (buffer[0] != 037) /* Verify first ID byte. */
+ return (0);
+ bits_checked += 8;
+ if (len < 2)
+ return (bits_checked);
+
+ if (buffer[1] != 0213) /* Verify second ID byte. */
+ return (0);
+ bits_checked += 8;
+ if (len < 3)
+ return (bits_checked);
+
+ if (buffer[2] != 8) /* Compression must be 'deflate'. */
+ return (0);
+ bits_checked += 8;
+ if (len < 4)
+ return (bits_checked);
+
+ if ((buffer[3] & 0xE0)!= 0) /* No reserved flags set. */
+ return (0);
+ bits_checked += 3;
+ if (len < 5)
+ return (bits_checked);
+
+ /*
+ * TODO: Verify more; in particular, gzip has an optional
+ * header CRC, which would give us 16 more verified bits. We
+ * may also be able to verify certain constraints on other
+ * fields.
+ */
+
+ return (bits_checked);
+}
+
+
+#ifndef HAVE_ZLIB_H
+
+/*
+ * If we don't have zlib on this system, we can't actually do the
+ * decompression. We can, however, still detect gzip-compressed
+ * archives and emit a useful message.
+ */
+static int
+init(struct archive *a, const void *buff, size_t n)
+{
+ (void)a; /* UNUSED */
+ (void)buff; /* UNUSED */
+ (void)n; /* UNUSED */
+
+ archive_set_error(a, -1,
+ "This version of libarchive was compiled without gzip support");
+ return (ARCHIVE_FATAL);
+}
+
+
+#else
+
+/*
+ * Setup the callbacks.
+ */
+static int
+init(struct archive *a, const void *buff, size_t n)
+{
+ struct private_data *state;
+ int ret;
+
+ a->compression_code = ARCHIVE_COMPRESSION_GZIP;
+ a->compression_name = "gzip";
+
+ state = malloc(sizeof(*state));
+ if (state == NULL) {
+ archive_set_error(a, ENOMEM,
+ "Can't allocate data for %s decompression",
+ a->compression_name);
+ return (ARCHIVE_FATAL);
+ }
+ memset(state, 0, sizeof(*state));
+
+ state->crc = crc32(0L, NULL, 0);
+ state->header_done = 0; /* We've not yet begun to parse header... */
+
+ state->uncompressed_buffer_size = 64 * 1024;
+ state->uncompressed_buffer = malloc(state->uncompressed_buffer_size);
+ state->stream.next_out = state->uncompressed_buffer;
+ state->read_next = state->uncompressed_buffer;
+ state->stream.avail_out = state->uncompressed_buffer_size;
+
+ if (state->uncompressed_buffer == NULL) {
+ archive_set_error(a, ENOMEM,
+ "Can't allocate %s decompression buffers",
+ a->compression_name);
+ free(state);
+ return (ARCHIVE_FATAL);
+ }
+
+ /*
+ * A bug in zlib.h: stream.next_in should be marked 'const'
+ * but isn't (the library never alters data through the
+ * next_in pointer, only reads it). The result: this ugly
+ * cast to remove 'const'.
+ */
+ state->stream.next_in = (void *)(uintptr_t)(const void *)buff;
+ state->stream.avail_in = n;
+
+ a->compression_read_ahead = read_ahead;
+ a->compression_read_consume = read_consume;
+ a->compression_finish = finish;
+
+ /*
+ * TODO: Do I need to parse the gzip header before calling
+ * inflateInit2()? In particular, one of the header bytes
+ * marks "best compression" or "fastest", which may be
+ * appropriate for setting the second parameter here.
+ * However, I think the only penalty for not setting it
+ * correctly is wasted memory. If this is necessary, it
+ * should probably go into drive_decompressor() below.
+ */
+
+ /* Initialize compression library. */
+ ret = inflateInit2(&(state->stream),
+ -15 /* Don't check for zlib header */);
+ if (ret == Z_OK) {
+ a->compression_data = state;
+ return (ARCHIVE_OK);
+ }
+
+ /* Library setup failed: Clean up. */
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "Internal error initializing %s library", a->compression_name);
+ free(state->uncompressed_buffer);
+ free(state);
+
+ /* Override the error message if we know what really went wrong. */
+ switch (ret) {
+ case Z_STREAM_ERROR:
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "Internal error initializing compression library: "
+ "invalid setup parameter");
+ break;
+ case Z_MEM_ERROR:
+ archive_set_error(a, ENOMEM,
+ "Internal error initializing compression library: "
+ "out of memory");
+ break;
+ case Z_VERSION_ERROR:
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "Internal error initializing compression library: "
+ "invalid library version");
+ break;
+ }
+
+ return (ARCHIVE_FATAL);
+}
+
+/*
+ * Return a block of data from the decompression buffer. Decompress more
+ * as necessary.
+ */
+static ssize_t
+read_ahead(struct archive *a, const void **p, size_t min)
+{
+ struct private_data *state;
+ int read_avail, was_avail, ret;
+
+ state = a->compression_data;
+ was_avail = -1;
+ if (!a->client_reader) {
+ archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER,
+ "No read callback is registered? "
+ "This is probably an internal programming error.");
+ return (ARCHIVE_FATAL);
+ }
+
+ read_avail = state->stream.next_out - state->read_next;
+
+ if (read_avail + state->stream.avail_out < min) {
+ memmove(state->uncompressed_buffer, state->read_next,
+ read_avail);
+ state->read_next = state->uncompressed_buffer;
+ state->stream.next_out = state->read_next + read_avail;
+ state->stream.avail_out
+ = state->uncompressed_buffer_size - read_avail;
+ }
+
+ while (was_avail < read_avail && /* Made some progress. */
+ read_avail < (int)min && /* Haven't satisfied min. */
+ read_avail < (int)state->uncompressed_buffer_size) { /* !full */
+ if ((ret = drive_decompressor(a, state)) != ARCHIVE_OK)
+ return (ret);
+ was_avail = read_avail;
+ read_avail = state->stream.next_out - state->read_next;
+ }
+
+ *p = state->read_next;
+ return (read_avail);
+}
+
+/*
+ * Mark a previously-returned block of data as read.
+ */
+static ssize_t
+read_consume(struct archive *a, size_t n)
+{
+ struct private_data *state;
+
+ state = a->compression_data;
+ a->file_position += n;
+ state->read_next += n;
+ if (state->read_next > state->stream.next_out)
+ __archive_errx(1, "Request to consume too many "
+ "bytes from gzip decompressor");
+ return (n);
+}
+
+/*
+ * Clean up the decompressor.
+ */
+static int
+finish(struct archive *a)
+{
+ struct private_data *state;
+ int ret;
+
+ state = a->compression_data;
+ ret = ARCHIVE_OK;
+ switch (inflateEnd(&(state->stream))) {
+ case Z_OK:
+ break;
+ default:
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "Failed to clean up %s compressor", a->compression_name);
+ ret = ARCHIVE_FATAL;
+ }
+
+ free(state->uncompressed_buffer);
+ free(state);
+
+ a->compression_data = NULL;
+ if (a->client_closer != NULL)
+ (a->client_closer)(a, a->client_data);
+
+ return (ret);
+}
+
+/*
+ * Utility function to pull data through decompressor, reading input
+ * blocks as necessary.
+ */
+static int
+drive_decompressor(struct archive *a, struct private_data *state)
+{
+ ssize_t ret;
+ int decompressed, total_decompressed;
+ int count, flags, header_state;
+ unsigned char *output;
+ unsigned char b;
+
+ flags = 0;
+ count = 0;
+ header_state = 0;
+ total_decompressed = 0;
+ for (;;) {
+ if (state->stream.avail_in == 0) {
+ ret = (a->client_reader)(a, a->client_data,
+ (const void **)&state->stream.next_in);
+ if (ret < 0) {
+ /*
+ * TODO: Find a better way to handle
+ * this read failure.
+ */
+ goto fatal;
+ }
+ if (ret == 0 && total_decompressed == 0) {
+ archive_set_error(a, EIO,
+ "Premature end of %s compressed data",
+ a->compression_name);
+ return (ARCHIVE_FATAL);
+ }
+ a->raw_position += ret;
+ state->stream.avail_in = ret;
+ }
+
+ if (!state->header_done) {
+ /*
+ * If still parsing the header, interpret the
+ * next byte.
+ */
+ b = *(state->stream.next_in++);
+ state->stream.avail_in--;
+
+ /*
+ * Yes, this is somewhat crude, but it works,
+ * GZip format isn't likely to change anytime
+ * in the near future, and header parsing is
+ * certainly not a performance issue, so
+ * there's little point in making this more
+ * elegant. Of course, if you see an easy way
+ * to make this more elegant, please let me
+ * know.. ;-)
+ */
+ switch (header_state) {
+ case 0: /* First byte of signature. */
+ if (b != 037)
+ goto fatal;
+ header_state = 1;
+ break;
+ case 1: /* Second byte of signature. */
+ if (b != 0213)
+ goto fatal;
+ header_state = 2;
+ break;
+ case 2: /* Compression type must be 8. */
+ if (b != 8)
+ goto fatal;
+ header_state = 3;
+ break;
+ case 3: /* GZip flags. */
+ flags = b;
+ header_state = 4;
+ break;
+ case 4: case 5: case 6: case 7: /* Mod time. */
+ header_state++;
+ break;
+ case 8: /* Deflate flags. */
+ header_state = 9;
+ break;
+ case 9: /* OS. */
+ header_state = 10;
+ break;
+ case 10: /* Optional Extra: First byte of Length. */
+ if ((flags & 4)) {
+ count = 255 & (int)b;
+ header_state = 11;
+ break;
+ }
+ /*
+ * Fall through if there is no
+ * Optional Extra field.
+ */
+ case 11: /* Optional Extra: Second byte of Length. */
+ if ((flags & 4)) {
+ count = (0xff00 & ((int)b << 8)) | count;
+ header_state = 12;
+ break;
+ }
+ /*
+ * Fall through if there is no
+ * Optional Extra field.
+ */
+ case 12: /* Optional Extra Field: counted length. */
+ if ((flags & 4)) {
+ --count;
+ if (count == 0) header_state = 13;
+ else header_state = 12;
+ break;
+ }
+ /*
+ * Fall through if there is no
+ * Optional Extra field.
+ */
+ case 13: /* Optional Original Filename. */
+ if ((flags & 8)) {
+ if (b == 0) header_state = 14;
+ else header_state = 13;
+ break;
+ }
+ /*
+ * Fall through if no Optional
+ * Original Filename.
+ */
+ case 14: /* Optional Comment. */
+ if ((flags & 16)) {
+ if (b == 0) header_state = 15;
+ else header_state = 14;
+ break;
+ }
+ /* Fall through if no Optional Comment. */
+ case 15: /* Optional Header CRC: First byte. */
+ if ((flags & 2)) {
+ header_state = 16;
+ break;
+ }
+ /* Fall through if no Optional Header CRC. */
+ case 16: /* Optional Header CRC: Second byte. */
+ if ((flags & 2)) {
+ header_state = 17;
+ break;
+ }
+ /* Fall through if no Optional Header CRC. */
+ case 17: /* First byte of compressed data. */
+ state->header_done = 1; /* done with header */
+ state->stream.avail_in++;
+ state->stream.next_in--;
+ }
+
+ /*
+ * TODO: Consider moving the inflateInit2 call
+ * here so it can include the compression type
+ * from the header?
+ */
+ } else {
+ output = state->stream.next_out;
+
+ /* Decompress some data. */
+ ret = inflate(&(state->stream), 0);
+ decompressed = state->stream.next_out - output;
+
+ /* Accumulate the CRC of the uncompressed data. */
+ state->crc = crc32(state->crc, output, decompressed);
+
+ /* Accumulate the total bytes of output. */
+ state->total_out += decompressed;
+ total_decompressed += decompressed;
+
+ switch (ret) {
+ case Z_OK: /* Decompressor made some progress. */
+ if (decompressed > 0)
+ return (ARCHIVE_OK);
+ break;
+ case Z_STREAM_END: /* Found end of stream. */
+ /*
+ * TODO: Verify gzip trailer
+ * (uncompressed length and CRC).
+ */
+ return (ARCHIVE_OK);
+ default:
+ /* Any other return value is an error. */
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "gzip decompression failed (%s)",
+ state->stream.msg);
+ goto fatal;
+ }
+ }
+ }
+ return (ARCHIVE_OK);
+
+ /* Return a fatal error. */
+fatal:
+ archive_set_error(a, ARCHIVE_ERRNO_MISC, "%s decompression failed",
+ a->compression_name);
+ return (ARCHIVE_FATAL);
+}
+
+#endif /* HAVE_ZLIB_H */
diff --git a/lib/libarchive/archive_read_support_compression_none.c b/lib/libarchive/archive_read_support_compression_none.c
new file mode 100644
index 0000000..8e7ca3c
--- /dev/null
+++ b/lib/libarchive/archive_read_support_compression_none.c
@@ -0,0 +1,266 @@
+/*-
+ * Copyright (c) 2003-2004 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(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 AUTHOR(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 "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "archive.h"
+#include "archive_private.h"
+
+struct archive_decompress_none {
+ char *buffer;
+ size_t buffer_size;
+ char *next; /* Current read location. */
+ size_t avail; /* Bytes in my buffer. */
+ const char *client_buff; /* Client buffer information. */
+ size_t client_total;
+ const char *client_next;
+ size_t client_avail;
+ char end_of_file;
+ char fatal;
+};
+
+/*
+ * Size of internal buffer used for combining short reads. This is
+ * also an upper limit on the size of a read request. Recall,
+ * however, that we can (and will!) return blocks of data larger than
+ * this. The read semantics are: you ask for a minimum, I give you a
+ * pointer to my best-effort match and tell you how much data is
+ * there. It could be less than you asked for, it could be much more.
+ * For example, a client might use mmap() to "read" the entire file as
+ * a single block. In that case, I will return that entire block to
+ * my clients.
+ */
+#define BUFFER_SIZE 65536
+
+static int archive_decompressor_none_bid(const void *, size_t);
+static int archive_decompressor_none_finish(struct archive *);
+static int archive_decompressor_none_init(struct archive *,
+ const void *, size_t);
+static ssize_t archive_decompressor_none_read_ahead(struct archive *,
+ const void **, size_t);
+static ssize_t archive_decompressor_none_read_consume(struct archive *,
+ size_t);
+
+int
+archive_read_support_compression_none(struct archive *a)
+{
+ return (__archive_read_register_compression(a,
+ archive_decompressor_none_bid,
+ archive_decompressor_none_init));
+}
+
+/*
+ * Try to detect an "uncompressed" archive.
+ */
+static int
+archive_decompressor_none_bid(const void *buff, size_t len)
+{
+ (void)buff;
+ (void)len;
+
+ return (1); /* Default: We'll take it if noone else does. */
+}
+
+static int
+archive_decompressor_none_init(struct archive *a, const void *buff, size_t n)
+{
+ struct archive_decompress_none *state;
+
+ a->compression_code = ARCHIVE_COMPRESSION_NONE;
+ a->compression_name = "none";
+
+ state = (struct archive_decompress_none *)malloc(sizeof(*state));
+ if (!state) {
+ archive_set_error(a, ENOMEM, "Can't allocate input data");
+ return (ARCHIVE_FATAL);
+ }
+ memset(state, 0, sizeof(*state));
+
+ state->buffer_size = BUFFER_SIZE;
+ state->buffer = malloc(state->buffer_size);
+ state->next = state->buffer;
+ if (state->buffer == NULL) {
+ free(state);
+ archive_set_error(a, ENOMEM, "Can't allocate input buffer");
+ return (ARCHIVE_FATAL);
+ }
+
+ /* Save reference to first block of data. */
+ state->client_buff = buff;
+ state->client_total = n;
+ state->client_next = state->client_buff;
+ state->client_avail = state->client_total;
+
+ a->compression_data = state;
+ a->compression_read_ahead = archive_decompressor_none_read_ahead;
+ a->compression_read_consume = archive_decompressor_none_read_consume;
+ a->compression_finish = archive_decompressor_none_finish;
+
+ return (ARCHIVE_OK);
+}
+
+/*
+ * We just pass through pointers to the client buffer if we can.
+ * If the client buffer is short, then we copy stuff to our internal
+ * buffer to combine reads.
+ */
+static ssize_t
+archive_decompressor_none_read_ahead(struct archive *a, const void **buff,
+ size_t min)
+{
+ struct archive_decompress_none *state;
+ ssize_t bytes_read;
+
+ state = a->compression_data;
+ if (state->fatal)
+ return (-1);
+
+ /*
+ * Don't make special efforts to handle requests larger than
+ * the copy buffer.
+ */
+ if (min > state->buffer_size)
+ min = state->buffer_size;
+
+ /*
+ * Try to satisfy the request directly from the client
+ * buffer. We can do this if all of the data in the copy
+ * buffer was copied from the current client buffer. This
+ * also covers the case where the copy buffer is empty and
+ * the client buffer has all the data we need.
+ */
+ if (state->client_total >= state->client_avail + state->avail
+ && state->client_avail + state->avail >= min) {
+ state->client_avail += state->avail;
+ state->client_next -= state->avail;
+ state->avail = 0;
+ state->next = state->buffer;
+ *buff = state->client_next;
+ return (state->client_avail);
+ }
+
+ /*
+ * If we can't use client buffer, we'll have to use copy buffer.
+ */
+
+ /* Move data forward in copy buffer if necessary. */
+ if (state->next > state->buffer &&
+ state->next + min > state->buffer + state->buffer_size) {
+ if (state->avail > 0)
+ memmove(state->buffer, state->next, state->avail);
+ state->next = state->buffer;
+ }
+
+ /* Collect data in copy buffer to fulfill request. */
+ while (state->avail < min) {
+ /* Copy data from client buffer to our copy buffer. */
+ if (state->client_avail > 0) {
+ /* First estimate: copy to fill rest of buffer. */
+ size_t tocopy = (state->buffer + state->buffer_size)
+ - (state->next + state->avail);
+ /* Don't copy more than is available. */
+ if (tocopy > state->client_avail)
+ tocopy = state->client_avail;
+ memcpy(state->next + state->avail, state->client_next,
+ tocopy);
+ state->client_next += tocopy;
+ state->client_avail -= tocopy;
+ state->avail += tocopy;
+ } else {
+ /* There is no more client data: fetch more. */
+ /*
+ * It seems to me that const void ** and const
+ * char ** should be compatible, but they
+ * aren't, hence the cast.
+ */
+ bytes_read = (a->client_reader)(a, a->client_data,
+ (const void **)&state->client_buff);
+ if (bytes_read < 0) { /* Read error. */
+ state->client_total = state->client_avail = 0;
+ state->client_next = state->client_buff = NULL;
+ state->fatal = 1;
+ return (-1);
+ }
+ if (bytes_read == 0) { /* End-of-file. */
+ state->client_total = state->client_avail = 0;
+ state->client_next = state->client_buff = NULL;
+ state->end_of_file = 1;
+ break;
+ }
+ a->raw_position += bytes_read;
+ state->client_total = bytes_read;
+ state->client_avail = state->client_total;
+ state->client_next = state->client_buff;
+ }
+ }
+
+ *buff = state->next;
+ return (state->avail);
+}
+
+/*
+ * Mark the appropriate data as used. Note that the request here will
+ * often be much smaller than the size of the previous read_ahead
+ * request.
+ */
+static ssize_t
+archive_decompressor_none_read_consume(struct archive *a, size_t request)
+{
+ struct archive_decompress_none *state;
+
+ state = a->compression_data;
+ if (state->avail > 0) {
+ /* Read came from copy buffer. */
+ state->next += request;
+ state->avail -= request;
+ } else {
+ /* Read came from client buffer. */
+ state->client_next += request;
+ state->client_avail -= request;
+ }
+ a->file_position += request;
+ return (request);
+}
+
+static int
+archive_decompressor_none_finish(struct archive *a)
+{
+ struct archive_decompress_none *state;
+
+ state = a->compression_data;
+ free(state->buffer);
+ free(state);
+ a->compression_data = NULL;
+ if (a->client_closer != NULL)
+ return ((a->client_closer)(a, a->client_data));
+ return (ARCHIVE_OK);
+}
diff --git a/lib/libarchive/archive_read_support_format_all.c b/lib/libarchive/archive_read_support_format_all.c
new file mode 100644
index 0000000..3b7eaaf
--- /dev/null
+++ b/lib/libarchive/archive_read_support_format_all.c
@@ -0,0 +1,40 @@
+/*-
+ * Copyright (c) 2003-2004 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(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 AUTHOR(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 "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#include "archive.h"
+
+int
+archive_read_support_format_all(struct archive *a)
+{
+ archive_read_support_format_cpio(a);
+ archive_read_support_format_iso9660(a);
+ archive_read_support_format_tar(a);
+ archive_read_support_format_zip(a);
+ return (ARCHIVE_OK);
+}
diff --git a/lib/libarchive/archive_read_support_format_cpio.c b/lib/libarchive/archive_read_support_format_cpio.c
new file mode 100644
index 0000000..75b0417
--- /dev/null
+++ b/lib/libarchive/archive_read_support_format_cpio.c
@@ -0,0 +1,610 @@
+/*-
+ * Copyright (c) 2003-2004 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(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 AUTHOR(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 "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#include <sys/stat.h>
+
+#include <errno.h>
+/* #include <stdint.h> */ /* See archive_platform.h */
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "archive.h"
+#include "archive_entry.h"
+#include "archive_private.h"
+
+struct cpio_bin_header {
+ unsigned char c_magic[2];
+ unsigned char c_dev[2];
+ unsigned char c_ino[2];
+ unsigned char c_mode[2];
+ unsigned char c_uid[2];
+ unsigned char c_gid[2];
+ unsigned char c_nlink[2];
+ unsigned char c_rdev[2];
+ unsigned char c_mtime[4];
+ unsigned char c_namesize[2];
+ unsigned char c_filesize[4];
+};
+
+struct cpio_odc_header {
+ char c_magic[6];
+ char c_dev[6];
+ char c_ino[6];
+ char c_mode[6];
+ char c_uid[6];
+ char c_gid[6];
+ char c_nlink[6];
+ char c_rdev[6];
+ char c_mtime[11];
+ char c_namesize[6];
+ char c_filesize[11];
+};
+
+struct cpio_newc_header {
+ char c_magic[6];
+ char c_ino[8];
+ char c_mode[8];
+ char c_uid[8];
+ char c_gid[8];
+ char c_nlink[8];
+ char c_mtime[8];
+ char c_filesize[8];
+ char c_devmajor[8];
+ char c_devminor[8];
+ char c_rdevmajor[8];
+ char c_rdevminor[8];
+ char c_namesize[8];
+ char c_crc[8];
+};
+
+struct links_entry {
+ struct links_entry *next;
+ struct links_entry *previous;
+ int links;
+ dev_t dev;
+ ino_t ino;
+ char *name;
+};
+
+#define CPIO_MAGIC 0x13141516
+struct cpio {
+ int magic;
+ int (*read_header)(struct archive *, struct cpio *,
+ struct stat *, size_t *, size_t *);
+ struct links_entry *links_head;
+ struct archive_string entry_name;
+ struct archive_string entry_linkname;
+ off_t entry_bytes_remaining;
+ off_t entry_offset;
+ off_t entry_padding;
+};
+
+static int64_t atol16(const char *, unsigned);
+static int64_t atol8(const char *, unsigned);
+static int archive_read_format_cpio_bid(struct archive *);
+static int archive_read_format_cpio_cleanup(struct archive *);
+static int archive_read_format_cpio_read_data(struct archive *,
+ const void **, size_t *, off_t *);
+static int archive_read_format_cpio_read_header(struct archive *,
+ struct archive_entry *);
+static int be4(const unsigned char *);
+static int header_bin_be(struct archive *, struct cpio *, struct stat *,
+ size_t *, size_t *);
+static int header_bin_le(struct archive *, struct cpio *, struct stat *,
+ size_t *, size_t *);
+static int header_newc(struct archive *, struct cpio *, struct stat *,
+ size_t *, size_t *);
+static int header_odc(struct archive *, struct cpio *, struct stat *,
+ size_t *, size_t *);
+static int le4(const unsigned char *);
+static void record_hardlink(struct cpio *cpio, struct archive_entry *entry,
+ const struct stat *st);
+
+int
+archive_read_support_format_cpio(struct archive *a)
+{
+ struct cpio *cpio;
+ int r;
+
+ cpio = malloc(sizeof(*cpio));
+ if (cpio == NULL) {
+ archive_set_error(a, ENOMEM, "Can't allocate cpio data");
+ return (ARCHIVE_FATAL);
+ }
+ memset(cpio, 0, sizeof(*cpio));
+ cpio->magic = CPIO_MAGIC;
+
+ r = __archive_read_register_format(a,
+ cpio,
+ archive_read_format_cpio_bid,
+ archive_read_format_cpio_read_header,
+ archive_read_format_cpio_read_data,
+ NULL,
+ archive_read_format_cpio_cleanup);
+
+ if (r != ARCHIVE_OK)
+ free(cpio);
+ return (ARCHIVE_OK);
+}
+
+
+static int
+archive_read_format_cpio_bid(struct archive *a)
+{
+ int bid, bytes_read;
+ const void *h;
+ const unsigned char *p;
+ struct cpio *cpio;
+
+ cpio = *(a->pformat_data);
+ bid = 0;
+ bytes_read = (a->compression_read_ahead)(a, &h, 6);
+ /* Convert error code into error return. */
+ if (bytes_read < 0)
+ return ((int)bytes_read);
+ if (bytes_read < 6)
+ return (-1);
+
+ p = h;
+ if (memcmp(p, "070707", 6) == 0) {
+ /* ASCII cpio archive (odc, POSIX.1) */
+ cpio->read_header = header_odc;
+ bid += 48;
+ /*
+ * XXX TODO: More verification; Could check that only octal
+ * digits appear in appropriate header locations. XXX
+ */
+ } else if (memcmp(p, "070701", 6) == 0) {
+ /* ASCII cpio archive (SVR4 without CRC) */
+ cpio->read_header = header_newc;
+ bid += 48;
+ /*
+ * XXX TODO: More verification; Could check that only hex
+ * digits appear in appropriate header locations. XXX
+ */
+ } else if (memcmp(p, "070702", 6) == 0) {
+ /* ASCII cpio archive (SVR4 with CRC) */
+ /* XXX TODO: Flag that we should check the CRC. XXX */
+ cpio->read_header = header_newc;
+ bid += 48;
+ /*
+ * XXX TODO: More verification; Could check that only hex
+ * digits appear in appropriate header locations. XXX
+ */
+ } else if (p[0] * 256 + p[1] == 070707) {
+ /* big-endian binary cpio archives */
+ cpio->read_header = header_bin_be;
+ bid += 16;
+ /* Is more verification possible here? */
+ } else if (p[0] + p[1] * 256 == 070707) {
+ /* little-endian binary cpio archives */
+ cpio->read_header = header_bin_le;
+ bid += 16;
+ /* Is more verification possible here? */
+ } else
+ return (ARCHIVE_WARN);
+
+ return (bid);
+}
+
+static int
+archive_read_format_cpio_read_header(struct archive *a,
+ struct archive_entry *entry)
+{
+ struct stat st;
+ struct cpio *cpio;
+ size_t bytes;
+ const void *h;
+ size_t namelength;
+ size_t name_pad;
+ int r;
+
+ memset(&st, 0, sizeof(st));
+
+ cpio = *(a->pformat_data);
+ r = (cpio->read_header(a, cpio, &st, &namelength, &name_pad));
+
+ if (r != ARCHIVE_OK)
+ return (r);
+
+ /* Assign all of the 'stat' fields at once. */
+ archive_entry_copy_stat(entry, &st);
+
+ /* Read name from buffer. */
+ bytes = (a->compression_read_ahead)(a, &h, namelength + name_pad);
+ if (bytes < namelength + name_pad)
+ return (ARCHIVE_FATAL);
+ (a->compression_read_consume)(a, namelength + name_pad);
+ archive_strncpy(&cpio->entry_name, h, namelength);
+ archive_entry_set_pathname(entry, cpio->entry_name.s);
+ cpio->entry_offset = 0;
+
+ /* If this is a symlink, read the link contents. */
+ if (S_ISLNK(st.st_mode)) {
+ bytes = (a->compression_read_ahead)(a, &h,
+ cpio->entry_bytes_remaining);
+ if ((off_t)bytes < cpio->entry_bytes_remaining)
+ return (ARCHIVE_FATAL);
+ (a->compression_read_consume)(a, cpio->entry_bytes_remaining);
+ archive_strncpy(&cpio->entry_linkname, h,
+ cpio->entry_bytes_remaining);
+ archive_entry_set_symlink(entry, cpio->entry_linkname.s);
+ cpio->entry_bytes_remaining = 0;
+ }
+
+ /* Compare name to "TRAILER!!!" to test for end-of-archive. */
+ if (namelength == 11 && strcmp(h, "TRAILER!!!") == 0) {
+ /* TODO: Store file location of start of block. */
+ archive_set_error(a, 0, NULL);
+ return (ARCHIVE_EOF);
+ }
+
+ /* Detect and record hardlinks to previously-extracted entries. */
+ record_hardlink(cpio, entry, &st);
+
+ return (ARCHIVE_OK);
+}
+
+static int
+archive_read_format_cpio_read_data(struct archive *a,
+ const void **buff, size_t *size, off_t *offset)
+{
+ ssize_t bytes_read;
+ struct cpio *cpio;
+
+ cpio = *(a->pformat_data);
+ if (cpio->entry_bytes_remaining > 0) {
+ bytes_read = (a->compression_read_ahead)(a, buff, 1);
+ if (bytes_read <= 0)
+ return (ARCHIVE_FATAL);
+ if (bytes_read > cpio->entry_bytes_remaining)
+ bytes_read = cpio->entry_bytes_remaining;
+ *size = bytes_read;
+ *offset = cpio->entry_offset;
+ cpio->entry_offset += bytes_read;
+ cpio->entry_bytes_remaining -= bytes_read;
+ (a->compression_read_consume)(a, bytes_read);
+ return (ARCHIVE_OK);
+ } else {
+ while (cpio->entry_padding > 0) {
+ bytes_read = (a->compression_read_ahead)(a, buff, 1);
+ if (bytes_read <= 0)
+ return (ARCHIVE_FATAL);
+ if (bytes_read > cpio->entry_padding)
+ bytes_read = cpio->entry_padding;
+ (a->compression_read_consume)(a, bytes_read);
+ cpio->entry_padding -= bytes_read;
+ }
+ *buff = NULL;
+ *size = 0;
+ *offset = cpio->entry_offset;
+ return (ARCHIVE_EOF);
+ }
+}
+
+static int
+header_newc(struct archive *a, struct cpio *cpio, struct stat *st,
+ size_t *namelength, size_t *name_pad)
+{
+ const void *h;
+ const struct cpio_newc_header *header;
+ size_t bytes;
+
+ /* Read fixed-size portion of header. */
+ bytes = (a->compression_read_ahead)(a, &h, sizeof(struct cpio_newc_header));
+ if (bytes < sizeof(struct cpio_newc_header))
+ return (ARCHIVE_FATAL);
+ (a->compression_read_consume)(a, sizeof(struct cpio_newc_header));
+
+ /* Parse out hex fields into struct stat. */
+ header = h;
+
+ if (memcmp(header->c_magic, "070701", 6) == 0) {
+ a->archive_format = ARCHIVE_FORMAT_CPIO_SVR4_NOCRC;
+ a->archive_format_name = "ASCII cpio (SVR4 with no CRC)";
+ } else if (memcmp(header->c_magic, "070702", 6) == 0) {
+ a->archive_format = ARCHIVE_FORMAT_CPIO_SVR4_CRC;
+ a->archive_format_name = "ASCII cpio (SVR4 with CRC)";
+ } else {
+ /* TODO: Abort here? */
+ }
+
+ st->st_dev = makedev(
+ atol16(header->c_devmajor, sizeof(header->c_devmajor)),
+ atol16(header->c_devminor, sizeof(header->c_devminor)));
+ st->st_ino = atol16(header->c_ino, sizeof(header->c_ino));
+ st->st_mode = atol16(header->c_mode, sizeof(header->c_mode));
+ st->st_uid = atol16(header->c_uid, sizeof(header->c_uid));
+ st->st_gid = atol16(header->c_gid, sizeof(header->c_gid));
+ st->st_nlink = atol16(header->c_nlink, sizeof(header->c_nlink));
+ st->st_rdev = makedev(
+ atol16(header->c_rdevmajor, sizeof(header->c_rdevmajor)),
+ atol16(header->c_rdevminor, sizeof(header->c_rdevminor)));
+ st->st_mtime = atol16(header->c_mtime, sizeof(header->c_mtime));
+ *namelength = atol16(header->c_namesize, sizeof(header->c_namesize));
+ /* Pad name to 2 more than a multiple of 4. */
+ *name_pad = (2 - *namelength) & 3;
+
+ /*
+ * Note: entry_bytes_remaining is at least 64 bits and
+ * therefore gauranteed to be big enough for a 33-bit file
+ * size. struct stat.st_size may only be 32 bits, so
+ * assigning there first could lose information.
+ */
+ cpio->entry_bytes_remaining =
+ atol16(header->c_filesize, sizeof(header->c_filesize));
+ st->st_size = cpio->entry_bytes_remaining;
+ /* Pad file contents to a multiple of 4. */
+ cpio->entry_padding = 3 & -cpio->entry_bytes_remaining;
+ return (ARCHIVE_OK);
+}
+
+static int
+header_odc(struct archive *a, struct cpio *cpio, struct stat *st,
+ size_t *namelength, size_t *name_pad)
+{
+ const void *h;
+ const struct cpio_odc_header *header;
+ size_t bytes;
+
+ a->archive_format = ARCHIVE_FORMAT_CPIO_POSIX;
+ a->archive_format_name = "POSIX octet-oriented cpio";
+
+ /* Read fixed-size portion of header. */
+ bytes = (a->compression_read_ahead)(a, &h, sizeof(struct cpio_odc_header));
+ if (bytes < sizeof(struct cpio_odc_header))
+ return (ARCHIVE_FATAL);
+ (a->compression_read_consume)(a, sizeof(struct cpio_odc_header));
+
+ /* Parse out octal fields into struct stat. */
+ header = h;
+
+ st->st_dev = atol8(header->c_dev, sizeof(header->c_dev));
+ st->st_ino = atol8(header->c_ino, sizeof(header->c_ino));
+ st->st_mode = atol8(header->c_mode, sizeof(header->c_mode));
+ st->st_uid = atol8(header->c_uid, sizeof(header->c_uid));
+ st->st_gid = atol8(header->c_gid, sizeof(header->c_gid));
+ st->st_nlink = atol8(header->c_nlink, sizeof(header->c_nlink));
+ st->st_rdev = atol8(header->c_rdev, sizeof(header->c_rdev));
+ st->st_mtime = atol8(header->c_mtime, sizeof(header->c_mtime));
+ *namelength = atol8(header->c_namesize, sizeof(header->c_namesize));
+ *name_pad = 0; /* No padding of filename. */
+
+ /*
+ * Note: entry_bytes_remaining is at least 64 bits and
+ * therefore gauranteed to be big enough for a 33-bit file
+ * size. struct stat.st_size may only be 32 bits, so
+ * assigning there first could lose information.
+ */
+ cpio->entry_bytes_remaining =
+ atol8(header->c_filesize, sizeof(header->c_filesize));
+ st->st_size = cpio->entry_bytes_remaining;
+ cpio->entry_padding = 0;
+ return (ARCHIVE_OK);
+}
+
+static int
+header_bin_le(struct archive *a, struct cpio *cpio, struct stat *st,
+ size_t *namelength, size_t *name_pad)
+{
+ const void *h;
+ const struct cpio_bin_header *header;
+ size_t bytes;
+
+ a->archive_format = ARCHIVE_FORMAT_CPIO_BIN_LE;
+ a->archive_format_name = "cpio (little-endian binary)";
+
+ /* Read fixed-size portion of header. */
+ bytes = (a->compression_read_ahead)(a, &h, sizeof(struct cpio_bin_header));
+ if (bytes < sizeof(struct cpio_bin_header))
+ return (ARCHIVE_FATAL);
+ (a->compression_read_consume)(a, sizeof(struct cpio_bin_header));
+
+ /* Parse out binary fields into struct stat. */
+ header = h;
+
+ st->st_dev = header->c_dev[0] + header->c_dev[1] * 256;
+ st->st_ino = header->c_ino[0] + header->c_ino[1] * 256;
+ st->st_mode = header->c_mode[0] + header->c_mode[1] * 256;
+ st->st_uid = header->c_uid[0] + header->c_uid[1] * 256;
+ st->st_gid = header->c_gid[0] + header->c_gid[1] * 256;
+ st->st_nlink = header->c_nlink[0] + header->c_nlink[1] * 256;
+ st->st_rdev = header->c_rdev[0] + header->c_rdev[1] * 256;
+ st->st_mtime = le4(header->c_mtime);
+ *namelength = header->c_namesize[0] + header->c_namesize[1] * 256;
+ *name_pad = *namelength & 1; /* Pad to even. */
+
+ cpio->entry_bytes_remaining = le4(header->c_filesize);
+ st->st_size = cpio->entry_bytes_remaining;
+ cpio->entry_padding = cpio->entry_bytes_remaining & 1; /* Pad to even. */
+ return (ARCHIVE_OK);
+}
+
+static int
+header_bin_be(struct archive *a, struct cpio *cpio, struct stat *st,
+ size_t *namelength, size_t *name_pad)
+{
+ const void *h;
+ const struct cpio_bin_header *header;
+ size_t bytes;
+
+ a->archive_format = ARCHIVE_FORMAT_CPIO_BIN_BE;
+ a->archive_format_name = "cpio (big-endian binary)";
+
+ /* Read fixed-size portion of header. */
+ bytes = (a->compression_read_ahead)(a, &h,
+ sizeof(struct cpio_bin_header));
+ if (bytes < sizeof(struct cpio_bin_header))
+ return (ARCHIVE_FATAL);
+ (a->compression_read_consume)(a, sizeof(struct cpio_bin_header));
+
+ /* Parse out binary fields into struct stat. */
+ header = h;
+ st->st_dev = header->c_dev[0] * 256 + header->c_dev[1];
+ st->st_ino = header->c_ino[0] * 256 + header->c_ino[1];
+ st->st_mode = header->c_mode[0] * 256 + header->c_mode[1];
+ st->st_uid = header->c_uid[0] * 256 + header->c_uid[1];
+ st->st_gid = header->c_gid[0] * 256 + header->c_gid[1];
+ st->st_nlink = header->c_nlink[0] * 256 + header->c_nlink[1];
+ st->st_rdev = header->c_rdev[0] * 256 + header->c_rdev[1];
+ st->st_mtime = be4(header->c_mtime);
+ *namelength = header->c_namesize[0] * 256 + header->c_namesize[1];
+ *name_pad = *namelength & 1; /* Pad to even. */
+
+ cpio->entry_bytes_remaining = be4(header->c_filesize);
+ st->st_size = cpio->entry_bytes_remaining;
+ cpio->entry_padding = cpio->entry_bytes_remaining & 1; /* Pad to even. */
+ return (ARCHIVE_OK);
+}
+
+static int
+archive_read_format_cpio_cleanup(struct archive *a)
+{
+ struct cpio *cpio;
+
+ cpio = *(a->pformat_data);
+ /* Free inode->name map */
+ while (cpio->links_head != NULL) {
+ struct links_entry *lp = cpio->links_head->next;
+
+ if (cpio->links_head->name)
+ free(cpio->links_head->name);
+ free(cpio->links_head);
+ cpio->links_head = lp;
+ }
+
+ free(cpio);
+ *(a->pformat_data) = NULL;
+ return (ARCHIVE_OK);
+}
+
+static int
+le4(const unsigned char *p)
+{
+ return ((p[0]<<16) + (p[1]<<24) + (p[2]<<0) + (p[3]<<8));
+}
+
+
+static int
+be4(const unsigned char *p)
+{
+ return (p[0] + (p[1]<<8) + (p[2]<<16) + (p[3]<<24));
+}
+
+/*
+ * Note that this implementation does not (and should not!) obey
+ * locale settings; you cannot simply substitute strtol here, since
+ * it does obey locale.
+ */
+static int64_t
+atol8(const char *p, unsigned char_cnt)
+{
+ int64_t l;
+ int digit;
+
+ l = 0;
+ while (char_cnt-- > 0) {
+ if (*p >= '0' && *p <= '7')
+ digit = *p - '0';
+ else
+ return (l);
+ p++;
+ l <<= 3;
+ l |= digit;
+ }
+ return (l);
+}
+
+static int64_t
+atol16(const char *p, unsigned char_cnt)
+{
+ int64_t l;
+ int digit;
+
+ l = 0;
+ while (char_cnt-- > 0) {
+ if (*p >= 'a' && *p <= 'f')
+ digit = *p - 'a' + 10;
+ else if (*p >= 'A' && *p <= 'F')
+ digit = *p - 'A' + 10;
+ else if (*p >= '0' && *p <= '9')
+ digit = *p - '0';
+ else
+ return (l);
+ p++;
+ l <<= 4;
+ l |= digit;
+ }
+ return (l);
+}
+
+static void
+record_hardlink(struct cpio *cpio, struct archive_entry *entry,
+ const struct stat *st)
+{
+ struct links_entry *le;
+
+ /*
+ * First look in the list of multiply-linked files. If we've
+ * already dumped it, convert this entry to a hard link entry.
+ */
+ for (le = cpio->links_head; le; le = le->next) {
+ if (le->dev == st->st_dev && le->ino == st->st_ino) {
+ archive_entry_set_hardlink(entry, le->name);
+
+ if (--le->links <= 0) {
+ if (le->previous != NULL)
+ le->previous->next = le->next;
+ if (le->next != NULL)
+ le->next->previous = le->previous;
+ if (cpio->links_head == le)
+ cpio->links_head = le->next;
+ free(le);
+ }
+
+ return;
+ }
+ }
+
+ le = malloc(sizeof(struct links_entry));
+ if (le == NULL)
+ __archive_errx(1, "Out of memory adding file to list");
+ if (cpio->links_head != NULL)
+ cpio->links_head->previous = le;
+ le->next = cpio->links_head;
+ le->previous = NULL;
+ cpio->links_head = le;
+ le->dev = st->st_dev;
+ le->ino = st->st_ino;
+ le->links = st->st_nlink - 1;
+ le->name = strdup(archive_entry_pathname(entry));
+ if (le->name == NULL)
+ __archive_errx(1, "Out of memory adding file to list");
+}
diff --git a/lib/libarchive/archive_read_support_format_iso9660.c b/lib/libarchive/archive_read_support_format_iso9660.c
new file mode 100644
index 0000000..065bf9b
--- /dev/null
+++ b/lib/libarchive/archive_read_support_format_iso9660.c
@@ -0,0 +1,1061 @@
+/*-
+ * Copyright (c) 2003-2004 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(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 AUTHOR(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 "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#include <sys/stat.h>
+
+#include <errno.h>
+/* #include <stdint.h> */ /* See archive_platform.h */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "archive.h"
+#include "archive_entry.h"
+#include "archive_private.h"
+#include "archive_string.h"
+
+/*
+ * An overview of ISO 9660 format:
+ *
+ * Each disk is laid out as follows:
+ * * 32k reserved for private use
+ * * Volume descriptor table. Each volume descriptor
+ * is 2k and specifies basic format information.
+ * The "Primary Volume Descriptor" (PVD) is defined by the
+ * standard and should always be present; other volume
+ * descriptors include various vendor-specific extensions.
+ * * Files and directories. Each file/dir is specified by
+ * an "extent" (starting sector and length in bytes).
+ * Dirs are just files with directory records packed one
+ * after another. The PVD contains a single dir entry
+ * specifying the location of the root directory. Everything
+ * else follows from there.
+ *
+ * This module works by first reading the volume descriptors, then
+ * building a list of directory entries, sorted by starting
+ * sector. At each step, I look for the earliest dir entry that
+ * hasn't yet been read, seek forward to that location and read
+ * that entry. If it's a dir, I slurp in the new dir entries and
+ * add them to the heap; if it's a regular file, I return the
+ * corresponding archive_entry and wait for the client to request
+ * the file body. This strategy allows us to read most compliant
+ * CDs with a single pass through the data, as required by libarchive.
+ */
+
+/* Structure of on-disk PVD. */
+struct iso9660_primary_volume_descriptor {
+ unsigned char type[1];
+ char id[5];
+ unsigned char version[1];
+ char reserved1[1];
+ char system_id[32];
+ char volume_id[32];
+ char reserved2[8];
+ char volume_space_size[8];
+ char reserved3[32];
+ char volume_set_size[4];
+ char volume_sequence_number[4];
+ char logical_block_size[4];
+ char path_table_size[8];
+ char type_1_path_table[4];
+ char opt_type_1_path_table[4];
+ char type_m_path_table[4];
+ char opt_type_m_path_table[4];
+ char root_directory_record[34];
+ char volume_set_id[128];
+ char publisher_id[128];
+ char preparer_id[128];
+ char application_id[128];
+ char copyright_file_id[37];
+ char abstract_file_id[37];
+ char bibliographic_file_id[37];
+ char creation_date[17];
+ char modification_date[17];
+ char expiration_date[17];
+ char effective_date[17];
+ char file_structure_version[1];
+ char reserved4[1];
+ char application_data[512];
+};
+
+/* Structure of an on-disk directory record. */
+struct iso9660_directory_record {
+ unsigned char length[1];
+ unsigned char ext_attr_length[1];
+ unsigned char extent[8];
+ unsigned char size[8];
+ char date[7];
+ unsigned char flags[1];
+ unsigned char file_unit_size[1];
+ unsigned char interleave[1];
+ unsigned char volume_sequence_number[4];
+ unsigned char name_len[1];
+ char name[1];
+};
+
+/*
+ * Our private data.
+ */
+
+/* In-memory storage for a directory record. */
+struct file_info {
+ struct file_info *parent;
+ int refcount;
+ uint64_t offset; /* Offset on disk. */
+ uint64_t size; /* File size in bytes. */
+ uint64_t ce_offset; /* Offset of CE */
+ uint64_t ce_size; /* Size of CE */
+ time_t mtime; /* File last modified time. */
+ time_t atime; /* File last accessed time. */
+ time_t ctime; /* File creation time. */
+ mode_t mode;
+ uid_t uid;
+ gid_t gid;
+ ino_t inode;
+ int nlinks;
+ char *name; /* Null-terminated filename. */
+ struct archive_string symlink;
+};
+
+
+struct iso9660 {
+ int magic;
+#define ISO9660_MAGIC 0x96609660
+ int bid; /* If non-zero, return this as our bid. */
+ struct archive_string pathname;
+ char seenRockridge; /* Set true if RR extensions are used. */
+ unsigned char suspOffset;
+
+ uint64_t previous_offset;
+ uint64_t previous_size;
+ struct archive_string previous_pathname;
+
+ /* TODO: Make this a heap for fast inserts and deletions. */
+ struct file_info **pending_files;
+ int pending_files_allocated;
+ int pending_files_used;
+
+ uint64_t current_position;
+ ssize_t logical_block_size;
+
+ off_t entry_sparse_offset;
+ ssize_t entry_bytes_remaining;
+};
+
+static void add_entry(struct iso9660 *iso9660, struct file_info *file);
+static int archive_read_format_iso9660_bid(struct archive *);
+static int archive_read_format_iso9660_cleanup(struct archive *);
+static int archive_read_format_iso9660_read_data(struct archive *,
+ const void **, size_t *, off_t *);
+static int archive_read_format_iso9660_read_header(struct archive *,
+ struct archive_entry *);
+static const char *build_pathname(struct archive_string *, struct file_info *);
+static void dump_isodirrec(FILE *, const struct iso9660_directory_record *);
+static time_t time_from_tm(struct tm *);
+static time_t isodate17(const void *);
+static time_t isodate7(const void *);
+static int isPVD(struct iso9660 *, const char *);
+static struct file_info *next_entry(struct iso9660 *);
+static int next_entry_seek(struct archive *a, struct iso9660 *iso9660,
+ struct file_info **pfile);
+static struct file_info *
+ parse_file_info(struct iso9660 *iso9660,
+ struct file_info *parent,
+ const struct iso9660_directory_record *isodirrec);
+static void parse_rockridge(struct iso9660 *iso9660,
+ struct file_info *file, const unsigned char *start,
+ const unsigned char *end);
+static void release_file(struct iso9660 *, struct file_info *);
+static int toi(const void *p, int n);
+
+int
+archive_read_support_format_iso9660(struct archive *a)
+{
+ struct iso9660 *iso9660;
+ int r;
+
+ iso9660 = malloc(sizeof(*iso9660));
+ if (iso9660 == NULL) {
+ archive_set_error(a, ENOMEM, "Can't allocate iso9660 data");
+ return (ARCHIVE_FATAL);
+ }
+ memset(iso9660, 0, sizeof(*iso9660));
+ iso9660->magic = ISO9660_MAGIC;
+ iso9660->bid = -1; /* We haven't yet bid. */
+
+ r = __archive_read_register_format(a,
+ iso9660,
+ archive_read_format_iso9660_bid,
+ archive_read_format_iso9660_read_header,
+ archive_read_format_iso9660_read_data,
+ NULL,
+ archive_read_format_iso9660_cleanup);
+
+ if (r != ARCHIVE_OK) {
+ free(iso9660);
+ return (r);
+ }
+ return (ARCHIVE_OK);
+}
+
+
+static int
+archive_read_format_iso9660_bid(struct archive *a)
+{
+ struct iso9660 *iso9660;
+ ssize_t bytes_read;
+ const void *h;
+ const char *p;
+
+ iso9660 = *(a->pformat_data);
+
+ if (iso9660->bid >= 0)
+ return (iso9660->bid);
+
+ /*
+ * Skip the first 32k (reserved area) and get the first
+ * 8 sectors of the volume descriptor table. Of course,
+ * if the I/O layer gives us more, we'll take it.
+ */
+ bytes_read = (a->compression_read_ahead)(a, &h, 32768 + 8*2048);
+ if (bytes_read < 32768 + 8*2048)
+ return (iso9660->bid = -1);
+ p = (const char *)h;
+
+ /* Skip the reserved area. */
+ bytes_read -= 32768;
+ p += 32768;
+
+ /* Check each volume descriptor to locate the PVD. */
+ for (; bytes_read > 2048; bytes_read -= 2048, p += 2048) {
+ iso9660->bid = isPVD(iso9660, p);
+ if (iso9660->bid > 0)
+ return (iso9660->bid);
+ if (*p == '\xff') /* End-of-volume-descriptor marker. */
+ break;
+ }
+
+ /* We didn't find a valid PVD; return a bid of zero. */
+ iso9660->bid = 0;
+ return (iso9660->bid);
+}
+
+static int
+isPVD(struct iso9660 *iso9660, const char *h)
+{
+ const struct iso9660_primary_volume_descriptor *voldesc;
+ struct file_info *file;
+
+ if (h[0] != 1)
+ return (0);
+ if (memcmp(h+1, "CD001", 5) != 0)
+ return (0);
+
+
+ voldesc = (const struct iso9660_primary_volume_descriptor *)h;
+ iso9660->logical_block_size = toi(&voldesc->logical_block_size, 2);
+
+ /* Store the root directory in the pending list. */
+ file = parse_file_info(iso9660, NULL,
+ (struct iso9660_directory_record *)&voldesc->root_directory_record);
+ add_entry(iso9660, file);
+ return (48);
+}
+
+static int
+archive_read_format_iso9660_read_header(struct archive *a,
+ struct archive_entry *entry)
+{
+ struct stat st;
+ struct iso9660 *iso9660;
+ struct file_info *file;
+ ssize_t bytes_read;
+ int r;
+
+ iso9660 = *(a->pformat_data);
+
+ if (!a->archive_format) {
+ a->archive_format = ARCHIVE_FORMAT_ISO9660;
+ a->archive_format_name = "ISO9660";
+ }
+
+ /* Get the next entry that appears after the current offset. */
+ r = next_entry_seek(a, iso9660, &file);
+ if (r != ARCHIVE_OK)
+ return (r);
+
+ iso9660->entry_bytes_remaining = file->size;
+ iso9660->entry_sparse_offset = 0; /* Offset for sparse-file-aware clients. */
+
+ /* Set up the entry structure with information about this entry. */
+ memset(&st, 0, sizeof(st));
+ st.st_mode = file->mode;
+ st.st_uid = file->uid;
+ st.st_gid = file->gid;
+ st.st_nlink = file->nlinks;
+ st.st_ino = file->inode;
+ st.st_mtime = file->mtime;
+ st.st_ctime = file->ctime;
+ st.st_atime = file->atime;
+ st.st_size = iso9660->entry_bytes_remaining;
+ archive_entry_copy_stat(entry, &st);
+ archive_string_empty(&iso9660->pathname);
+ archive_entry_set_pathname(entry,
+ build_pathname(&iso9660->pathname, file));
+ if (file->symlink.s != NULL)
+ archive_entry_set_symlink(entry, file->symlink.s);
+
+ /* If this entry points to the same data as the previous
+ * entry, convert this into a hardlink to that entry.
+ * But don't bother for zero-length files. */
+ if (file->offset == iso9660->previous_offset
+ && file->size == iso9660->previous_size
+ && file->size > 0) {
+ archive_entry_set_hardlink(entry,
+ iso9660->previous_pathname.s);
+ iso9660->entry_bytes_remaining = 0;
+ iso9660->entry_sparse_offset = 0;
+ release_file(iso9660, file);
+ return (ARCHIVE_OK);
+ }
+
+ /* If the offset is before our current position, we can't
+ * seek backwards to extract it, so issue a warning. */
+ if (file->offset < iso9660->current_position) {
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "Ignoring out-of-order file");
+ iso9660->entry_bytes_remaining = 0;
+ iso9660->entry_sparse_offset = 0;
+ release_file(iso9660, file);
+ return (ARCHIVE_WARN);
+ }
+
+ iso9660->previous_size = file->size;
+ iso9660->previous_offset = file->offset;
+ archive_strcpy(&iso9660->previous_pathname, iso9660->pathname.s);
+
+ /* If this is a directory, read in all of the entries right now. */
+ if (S_ISDIR(st.st_mode)) {
+ while (iso9660->entry_bytes_remaining > 0) {
+ const void *block;
+ const unsigned char *p;
+ ssize_t step = iso9660->logical_block_size;
+ if (step > iso9660->entry_bytes_remaining)
+ step = iso9660->entry_bytes_remaining;
+ bytes_read = (a->compression_read_ahead)(a, &block, step);
+ if (bytes_read < step) {
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "Failed to read full block when scanning ISO9660 directory list");
+ release_file(iso9660, file);
+ return (ARCHIVE_FATAL);
+ }
+ if (bytes_read > step)
+ bytes_read = step;
+ (a->compression_read_consume)(a, bytes_read);
+ iso9660->current_position += bytes_read;
+ iso9660->entry_bytes_remaining -= bytes_read;
+ for (p = block;
+ *p != 0 && p < (const unsigned char *)block + bytes_read;
+ p += *p) {
+ const struct iso9660_directory_record *dr
+ = (const struct iso9660_directory_record *)p;
+ struct file_info *child;
+
+ /* Skip '.' entry. */
+ if (dr->name_len[0] == 1
+ && dr->name[0] == '\0')
+ continue;
+ /* Skip '..' entry. */
+ if (dr->name_len[0] == 1
+ && dr->name[0] == '\001')
+ continue;
+ child = parse_file_info(iso9660, file, dr);
+ add_entry(iso9660, child);
+ if (iso9660->seenRockridge) {
+ a->archive_format =
+ ARCHIVE_FORMAT_ISO9660_ROCKRIDGE;
+ a->archive_format_name =
+ "ISO9660 with Rockridge extensions";
+ }
+ }
+ }
+ }
+
+ release_file(iso9660, file);
+ return (ARCHIVE_OK);
+}
+
+static int
+archive_read_format_iso9660_read_data(struct archive *a,
+ const void **buff, size_t *size, off_t *offset)
+{
+ ssize_t bytes_read;
+ struct iso9660 *iso9660;
+
+ iso9660 = *(a->pformat_data);
+ if (iso9660->entry_bytes_remaining <= 0) {
+ *buff = NULL;
+ *size = 0;
+ *offset = iso9660->entry_sparse_offset;
+ return (ARCHIVE_EOF);
+ }
+
+ bytes_read = (a->compression_read_ahead)(a, buff, 1);
+ if (bytes_read == 0)
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "Truncated input file");
+ if (bytes_read <= 0)
+ return (ARCHIVE_FATAL);
+ if (bytes_read > iso9660->entry_bytes_remaining)
+ bytes_read = iso9660->entry_bytes_remaining;
+ *size = bytes_read;
+ *offset = iso9660->entry_sparse_offset;
+ iso9660->entry_sparse_offset += bytes_read;
+ iso9660->entry_bytes_remaining -= bytes_read;
+ iso9660->current_position += bytes_read;
+ (a->compression_read_consume)(a, bytes_read);
+ return (ARCHIVE_OK);
+}
+
+static int
+archive_read_format_iso9660_cleanup(struct archive *a)
+{
+ struct iso9660 *iso9660;
+ struct file_info *file;
+
+ iso9660 = *(a->pformat_data);
+ while ((file = next_entry(iso9660)) != NULL)
+ release_file(iso9660, file);
+ archive_string_free(&iso9660->pathname);
+ archive_string_free(&iso9660->previous_pathname);
+ free(iso9660);
+ *(a->pformat_data) = NULL;
+ return (ARCHIVE_OK);
+}
+
+/*
+ * This routine parses a single ISO directory record, makes sense
+ * of any extensions, and stores the result in memory.
+ */
+static struct file_info *
+parse_file_info(struct iso9660 *iso9660, struct file_info *parent,
+ const struct iso9660_directory_record *isodirrec)
+{
+ struct file_info *file;
+
+ /* TODO: Sanity check that name_len doesn't exceed length, etc. */
+
+ /* Create a new file entry and copy data from the ISO dir record. */
+ file = malloc(sizeof(*file));
+ if (file == NULL)
+ return (NULL);
+ memset(file, 0, sizeof(*file));
+ file->parent = parent;
+ if (parent != NULL)
+ parent->refcount++;
+ file->offset = toi(isodirrec->extent, 4)
+ * iso9660->logical_block_size;
+ file->size = toi(isodirrec->size, 4);
+ file->mtime = isodate7(isodirrec->date);
+ file->ctime = file->atime = file->mtime;
+ file->name = malloc(isodirrec->name_len[0] + 1);
+ if (file->name == NULL) {
+ free(file);
+ return (NULL);
+ }
+ memcpy(file->name, isodirrec->name, isodirrec->name_len[0]);
+ file->name[(int)isodirrec->name_len[0]] = '\0';
+ if (isodirrec->flags[0] & 0x02)
+ file->mode = S_IFDIR | 0700;
+ else
+ file->mode = S_IFREG | 0400;
+
+ /* Rockridge extensions overwrite information from above. */
+ {
+ const unsigned char *rr_start, *rr_end;
+ rr_end = (const unsigned char *)isodirrec
+ + isodirrec->length[0];
+ rr_start = (const unsigned char *)isodirrec->name
+ + isodirrec->name_len[0];
+ if ((isodirrec->name_len[0] & 1) == 0)
+ rr_start++;
+ rr_start += iso9660->suspOffset;
+ parse_rockridge(iso9660, file, rr_start, rr_end);
+ }
+
+ /* DEBUGGING: Warn about attributes I don't yet fully support. */
+ if ((isodirrec->flags[0] & ~0x02) != 0) {
+ fprintf(stderr, "\n ** Unrecognized flag: ");
+ dump_isodirrec(stderr, isodirrec);
+ fprintf(stderr, "\n");
+ } else if (toi(isodirrec->volume_sequence_number, 2) != 1) {
+ fprintf(stderr, "\n ** Unrecognized sequence number: ");
+ dump_isodirrec(stderr, isodirrec);
+ fprintf(stderr, "\n");
+ } else if (isodirrec->file_unit_size[0] != 0) {
+ fprintf(stderr, "\n ** Unexpected file unit size: ");
+ dump_isodirrec(stderr, isodirrec);
+ fprintf(stderr, "\n");
+ } else if (isodirrec->interleave[0] != 0) {
+ fprintf(stderr, "\n ** Unexpected interleave: ");
+ dump_isodirrec(stderr, isodirrec);
+ fprintf(stderr, "\n");
+ } else if (isodirrec->ext_attr_length[0] != 0) {
+ fprintf(stderr, "\n ** Unexpected extended attribute length: ");
+ dump_isodirrec(stderr, isodirrec);
+ fprintf(stderr, "\n");
+ }
+
+ return (file);
+}
+
+static void
+add_entry(struct iso9660 *iso9660, struct file_info *file)
+{
+ /* Expand our pending files list as necessary. */
+ if (iso9660->pending_files_used >= iso9660->pending_files_allocated) {
+ struct file_info **new_pending_files;
+ int new_size = iso9660->pending_files_allocated * 2;
+
+ if (new_size < 1024)
+ new_size = 1024;
+ new_pending_files = malloc(new_size * sizeof(new_pending_files[0]));
+ if (new_pending_files == NULL)
+ __archive_errx(1, "Out of memory");
+ memcpy(new_pending_files, iso9660->pending_files,
+ iso9660->pending_files_allocated * sizeof(new_pending_files[0]));
+ if (iso9660->pending_files != NULL)
+ free(iso9660->pending_files);
+ iso9660->pending_files = new_pending_files;
+ iso9660->pending_files_allocated = new_size;
+ }
+
+ iso9660->pending_files[iso9660->pending_files_used++] = file;
+}
+
+static void
+parse_rockridge(struct iso9660 *iso9660, struct file_info *file,
+ const unsigned char *p, const unsigned char *end)
+{
+ (void)iso9660; /* UNUSED */
+
+ while (p + 4 < end /* Enough space for another entry. */
+ && p[0] >= 'A' && p[0] <= 'Z' /* Sanity-check 1st char of name. */
+ && p[1] >= 'A' && p[1] <= 'Z' /* Sanity-check 2nd char of name. */
+ && p + p[2] <= end) { /* Sanity-check length. */
+ const unsigned char *data = p + 4;
+ int data_length = p[2] - 4;
+ int version = p[3];
+
+ /*
+ * Yes, each 'if' here does test p[0] again.
+ * Otherwise, the fall-through handling to catch
+ * unsupported extensions doesn't work.
+ */
+ switch(p[0]) {
+ case 'C':
+ if (p[0] == 'C' && p[1] == 'E' && version == 1) {
+ /*
+ * CE extension comprises:
+ * 8 byte sector containing extension
+ * 8 byte offset w/in above sector
+ * 8 byte length of continuation
+ */
+ file->ce_offset = toi(data, 4)
+ * iso9660->logical_block_size
+ + toi(data + 8, 4);
+ file->ce_size = toi(data + 16, 4);
+ break;
+ }
+ /* FALLTHROUGH */
+ case 'N':
+ if (p[0] == 'N' && p[1] == 'M' && version == 1
+ && *data == 0) {
+ /* NM extension with flag byte == 0 */
+ /*
+ * NM extension comprises:
+ * one byte flag
+ * rest is long name
+ */
+ /* TODO: Obey flags. */
+ char *old_name = file->name;
+
+ data++; /* Skip flag byte. */
+ data_length--;
+ file->name = malloc(data_length + 1);
+ if (file->name != NULL) {
+ free(old_name);
+ memcpy(file->name, data, data_length);
+ file->name[data_length] = '\0';
+ } else
+ file->name = old_name;
+ break;
+ }
+ /* FALLTHROUGH */
+ case 'P':
+ if (p[0] == 'P' && p[1] == 'D' && version == 1) {
+ /*
+ * PD extension is padding;
+ * contents are always ignored.
+ */
+ break;
+ }
+ if (p[0] == 'P' && p[1] == 'X' && version == 1) {
+ /*
+ * PX extension comprises:
+ * 8 bytes for mode,
+ * 8 bytes for nlinks,
+ * 8 bytes for uid,
+ * 8 bytes for gid,
+ * 8 bytes for inode.
+ */
+ if (data_length == 32) {
+ file->mode = toi(data, 4);
+ file->nlinks = toi(data + 8, 4);
+ file->uid = toi(data + 16, 4);
+ file->gid = toi(data + 24, 4);
+ file->inode = toi(data + 32, 4);
+ }
+ break;
+ }
+ /* FALLTHROUGH */
+ case 'R':
+ if (p[0] == 'R' && p[1] == 'R' && version == 1) {
+ iso9660->seenRockridge = 1;
+ /*
+ * RR extension comprises:
+ * one byte flag value
+ */
+ /* TODO: Handle RR extension. */
+ break;
+ }
+ /* FALLTHROUGH */
+ case 'S':
+ if (p[0] == 'S' && p[1] == 'L' && version == 1
+ && *data == 0) {
+ int cont = 1;
+ /* SL extension with flags == 0 */
+ /* TODO: handle non-zero flag values. */
+ data++; /* Skip flag byte. */
+ data_length--;
+ while (data_length > 0) {
+ unsigned char flag = *data++;
+ unsigned char nlen = *data++;
+ data_length -= 2;
+
+ if (cont == 0)
+ archive_strcat(&file->symlink, "/");
+ cont = 0;
+
+ switch(flag) {
+ case 0x01: /* Continue */
+ archive_strncat(&file->symlink,
+ (const char *)data, nlen);
+ cont = 1;
+ break;
+ case 0x02: /* Current */
+ archive_strcat(&file->symlink, ".");
+ break;
+ case 0x04: /* Parent */
+ archive_strcat(&file->symlink, "..");
+ break;
+ case 0x08: /* Root */
+ case 0x10: /* Volume root */
+ archive_string_empty(&file->symlink);
+ break;
+ case 0x20: /* Hostname */
+ archive_strcat(&file->symlink, "hostname");
+ break;
+ case 0:
+ archive_strncat(&file->symlink,
+ (const char *)data, nlen);
+ break;
+ default:
+ /* TODO: issue a warning ? */
+ break;
+ }
+ data += nlen;
+ data_length -= nlen;
+ }
+ break;
+ }
+ if (p[0] == 'S' && p[1] == 'P'
+ && version == 1 && data_length == 7
+ && data[0] == (unsigned char)'\xbe'
+ && data[1] == (unsigned char)'\xef') {
+ /*
+ * SP extension stores the suspOffset
+ * (Number of bytes to skip between
+ * filename and SUSP records.)
+ * It is mandatory by the SUSP standard
+ * (IEEE 1281).
+ *
+ * It allows SUSP to coexist with
+ * non-SUSP uses of the System
+ * Use Area by placing non-SUSP data
+ * before SUSP data.
+ *
+ * TODO: Add a check for 'SP' in
+ * first directory entry, disable all SUSP
+ * processing if not found.
+ */
+ iso9660->suspOffset = data[2];
+ break;
+ }
+ if (p[0] == 'S' && p[1] == 'T'
+ && data_length == 0 && version == 1) {
+ /*
+ * ST extension marks end of this
+ * block of SUSP entries.
+ *
+ * It allows SUSP to coexist with
+ * non-SUSP uses of the System
+ * Use Area by placing non-SUSP data
+ * after SUSP data.
+ */
+ return;
+ }
+ case 'T':
+ if (p[0] == 'T' && p[1] == 'F' && version == 1) {
+ char flag = data[0];
+ /*
+ * TF extension comprises:
+ * one byte flag
+ * create time (optional)
+ * modify time (optional)
+ * access time (optional)
+ * attribute time (optional)
+ * Time format and presence of fields
+ * is controlled by flag bits.
+ */
+ data++;
+ if (flag & 0x80) {
+ /* Use 17-byte time format. */
+ if (flag & 1) /* Create time. */
+ data += 17;
+ if (flag & 2) { /* Modify time. */
+ file->mtime = isodate17(data);
+ data += 17;
+ }
+ if (flag & 4) { /* Access time. */
+ file->atime = isodate17(data);
+ data += 17;
+ }
+ if (flag & 8) { /* Attribute time. */
+ file->ctime = isodate17(data);
+ data += 17;
+ }
+ } else {
+ /* Use 7-byte time format. */
+ if (flag & 1) /* Create time. */
+ data += 7;
+ if (flag & 2) { /* Modify time. */
+ file->mtime = isodate7(data);
+ data += 7;
+ }
+ if (flag & 4) { /* Access time. */
+ file->atime = isodate7(data);
+ data += 7;
+ }
+ if (flag & 8) { /* Attribute time. */
+ file->ctime = isodate7(data);
+ data += 7;
+ }
+ }
+ break;
+ }
+ /* FALLTHROUGH */
+ default:
+ /* The FALLTHROUGHs above leave us here for
+ * any unsupported extension. */
+ {
+ const unsigned char *t;
+ fprintf(stderr, "\nUnsupported RRIP extension for %s\n", file->name);
+ fprintf(stderr, " %c%c(%d):", p[0], p[1], data_length);
+ for (t = data; t < data + data_length && t < data + 16; t++)
+ fprintf(stderr, " %02x", *t);
+ fprintf(stderr, "\n");
+ }
+ }
+
+
+
+ p += p[2];
+ }
+}
+
+static void
+release_file(struct iso9660 *iso9660, struct file_info *file)
+{
+ struct file_info *parent;
+
+ if (file->refcount == 0) {
+ parent = file->parent;
+ if (file->name)
+ free(file->name);
+ archive_string_free(&file->symlink);
+ free(file);
+ if (parent != NULL) {
+ parent->refcount--;
+ release_file(iso9660, parent);
+ }
+ }
+}
+
+static int
+next_entry_seek(struct archive *a, struct iso9660 *iso9660,
+ struct file_info **pfile)
+{
+ struct file_info *file;
+ uint64_t offset;
+
+ *pfile = NULL;
+ for (;;) {
+ *pfile = file = next_entry(iso9660);
+ if (file == NULL)
+ return (ARCHIVE_EOF);
+
+ /* CE area precedes actual file data? Ignore it. */
+ if (file->ce_offset > file->offset) {
+fprintf(stderr, " *** Discarding CE data.\n");
+ file->ce_offset = 0;
+ file->ce_size = 0;
+ }
+
+ /* If CE exists, find and read it now. */
+ if (file->ce_offset > 0)
+ offset = file->ce_offset;
+ else
+ offset = file->offset;
+
+ /* Seek forward to the start of the entry. */
+ while (iso9660->current_position < offset) {
+ ssize_t step = offset - iso9660->current_position;
+ ssize_t bytes_read;
+ const void *buff;
+
+ if (step > iso9660->logical_block_size)
+ step = iso9660->logical_block_size;
+ bytes_read = (a->compression_read_ahead)(a, &buff, step);
+ if (bytes_read <= 0) {
+ release_file(iso9660, file);
+ return (ARCHIVE_FATAL);
+ }
+ if (bytes_read > step)
+ bytes_read = step;
+ iso9660->current_position += bytes_read;
+ (a->compression_read_consume)(a, bytes_read);
+ }
+
+ /* We found body of file; handle it now. */
+ if (offset == file->offset)
+ return (ARCHIVE_OK);
+
+ /* Found CE? Process it and push the file back onto list. */
+ if (offset == file->ce_offset) {
+ const void *p;
+ ssize_t size = file->ce_size;
+ ssize_t bytes_read;
+ const unsigned char *rr_start;
+
+ file->ce_offset = 0;
+ file->ce_size = 0;
+ bytes_read = (a->compression_read_ahead)(a, &p, size);
+ if (bytes_read > size)
+ bytes_read = size;
+ rr_start = (const unsigned char *)p;
+ parse_rockridge(iso9660, file, rr_start,
+ rr_start + bytes_read);
+ (a->compression_read_consume)(a, bytes_read);
+ iso9660->current_position += bytes_read;
+ add_entry(iso9660, file);
+ }
+ }
+}
+
+static struct file_info *
+next_entry(struct iso9660 *iso9660)
+{
+ int least_index;
+ uint64_t least_end_offset;
+ int i;
+ struct file_info *r;
+
+ if (iso9660->pending_files_used < 1)
+ return (NULL);
+
+ /* Assume the first file in the list is the earliest on disk. */
+ least_index = 0;
+ least_end_offset = iso9660->pending_files[0]->offset
+ + iso9660->pending_files[0]->size;
+
+ /* Now, try to find an earlier one. */
+ for (i = 0; i < iso9660->pending_files_used; i++) {
+ /* Use the position of the file *end* as our comparison. */
+ uint64_t end_offset = iso9660->pending_files[i]->offset
+ + iso9660->pending_files[i]->size;
+ if (iso9660->pending_files[i]->ce_offset > 0
+ && iso9660->pending_files[i]->ce_offset < iso9660->pending_files[i]->offset)
+ end_offset = iso9660->pending_files[i]->ce_offset
+ + iso9660->pending_files[i]->ce_size;
+ if (least_end_offset > end_offset) {
+ least_index = i;
+ least_end_offset = end_offset;
+ }
+ }
+ r = iso9660->pending_files[least_index];
+ iso9660->pending_files[least_index]
+ = iso9660->pending_files[--iso9660->pending_files_used];
+ return (r);
+}
+
+static int
+toi(const void *p, int n)
+{
+ const unsigned char *v = (const unsigned char *)p;
+ if (n > 1)
+ return v[0] + 256 * toi(v + 1, n - 1);
+ if (n == 1)
+ return v[0];
+ return (0);
+}
+
+static time_t
+isodate7(const void *p)
+{
+ struct tm tm;
+ const unsigned char *v = (const unsigned char *)p;
+ int offset;
+ memset(&tm, 0, sizeof(tm));
+ tm.tm_year = v[0];
+ tm.tm_mon = v[1] - 1;
+ tm.tm_mday = v[2];
+ tm.tm_hour = v[3];
+ tm.tm_min = v[4];
+ tm.tm_sec = v[5];
+ /* v[6] is the timezone offset, in 1/4-hour increments. */
+ offset = ((const signed char *)p)[6];
+ if (offset > -48 && offset < 52) {
+ tm.tm_hour -= offset / 4;
+ tm.tm_min -= (offset % 4) * 15;
+ }
+ return (time_from_tm(&tm));
+}
+
+static time_t
+isodate17(const void *p)
+{
+ struct tm tm;
+ const unsigned char *v = (const unsigned char *)p;
+ int offset;
+ memset(&tm, 0, sizeof(tm));
+ tm.tm_year = (v[0] - '0') * 1000 + (v[1] - '0') * 100
+ + (v[2] - '0') * 10 + (v[3] - '0')
+ - 1900;
+ tm.tm_mon = (v[4] - '0') * 10 + (v[5] - '0');
+ tm.tm_mday = (v[6] - '0') * 10 + (v[7] - '0');
+ tm.tm_hour = (v[8] - '0') * 10 + (v[9] - '0');
+ tm.tm_min = (v[10] - '0') * 10 + (v[11] - '0');
+ tm.tm_sec = (v[12] - '0') * 10 + (v[13] - '0');
+ /* v[16] is the timezone offset, in 1/4-hour increments. */
+ offset = ((const signed char *)p)[16];
+ if (offset > -48 && offset < 52) {
+ tm.tm_hour -= offset / 4;
+ tm.tm_min -= (offset % 4) * 15;
+ }
+ return (time_from_tm(&tm));
+}
+
+/*
+ * timegm() converts a struct tm to a time_t, except it isn't standard,
+ * so I provide my own function here that (ideally) is just a wrapper
+ * for timegm().
+ */
+static time_t
+time_from_tm(struct tm *t)
+{
+#if HAVE_TIMEGM
+ return (timegm(t));
+#else
+ /*
+ * Unfortunately, timegm() isn't standard. The standard
+ * mktime() function is a close match, except that it uses
+ * local timezone instead of GMT. Close enough for now.
+ * Note that it is not possible to emulate timegm() using
+ * standard interfaces:
+ * * ANSI C90 does not even guarantee that time_t is
+ * an arithmetic type, so time adjustments can only be
+ * done by manipulating struct tm elements. You cannot
+ * portably calculate time_t values.
+ * * POSIX does promise that time_t is an arithmetic type
+ * measured in seconds, so you can do time_t calculations
+ * while remaining POSIX-compliant.
+ * * Neither ANSI nor POSIX provides an easy way to measure
+ * the timezone offset, so you can't adjust mktime() to
+ * work like timegm().
+ * * POSIX does not promise that the epoch begins in 1970,
+ * so you can't write a portable timegm() function from
+ * scratch.
+ */
+ time_t result = mktime(t);
+ /* TODO: Find a way to improve this approximation to timegm(). */
+ return result;
+#endif
+}
+
+static const char *
+build_pathname(struct archive_string *as, struct file_info *file)
+{
+ if (file->parent != NULL && file->parent->name[0] != '\0') {
+ build_pathname(as, file->parent);
+ archive_strcat(as, "/");
+ }
+ if (file->name[0] == '\0')
+ archive_strcat(as, ".");
+ else
+ archive_strcat(as, file->name);
+ return (as->s);
+}
+
+static void
+dump_isodirrec(FILE *out, const struct iso9660_directory_record *isodirrec)
+{
+ fprintf(out, " l %d,", isodirrec->length[0]);
+ fprintf(out, " a %d,", isodirrec->ext_attr_length[0]);
+ fprintf(out, " ext 0x%x,", toi(isodirrec->extent, 4));
+ fprintf(out, " s %d,", toi(isodirrec->size, 4));
+ fprintf(out, " f 0x%02x,", isodirrec->flags[0]);
+ fprintf(out, " u %d,", isodirrec->file_unit_size[0]);
+ fprintf(out, " ilv %d,", isodirrec->interleave[0]);
+ fprintf(out, " seq %d,", toi(isodirrec->volume_sequence_number,2));
+ fprintf(out, " nl %d:", isodirrec->name_len[0]);
+ fprintf(out, " `%.*s'", isodirrec->name_len[0], isodirrec->name);
+}
diff --git a/lib/libarchive/archive_read_support_format_tar.c b/lib/libarchive/archive_read_support_format_tar.c
new file mode 100644
index 0000000..271a41f
--- /dev/null
+++ b/lib/libarchive/archive_read_support_format_tar.c
@@ -0,0 +1,1898 @@
+/*-
+ * Copyright (c) 2003-2006 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(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 AUTHOR(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 "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#include <sys/stat.h>
+#ifdef MAJOR_IN_MKDEV
+#include <sys/mkdev.h>
+#else
+#ifdef MAJOR_IN_SYSMACROS
+#include <sys/sysmacros.h>
+#endif
+#endif
+#include <errno.h>
+#include <stddef.h>
+/* #include <stdint.h> */ /* See archive_platform.h */
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/* Obtain suitable wide-character manipulation functions. */
+#ifdef HAVE_WCHAR_H
+#include <wchar.h>
+#else
+/* Good enough for equality testing, which is all we need. */
+static int wcscmp(const wchar_t *s1, const wchar_t *s2)
+{
+ int diff = *s1 - *s2;
+ while (*s1 && diff == 0)
+ diff = (int)*++s1 - (int)*++s2;
+ return diff;
+}
+/* Good enough for equality testing, which is all we need. */
+static int wcsncmp(const wchar_t *s1, const wchar_t *s2, size_t n)
+{
+ int diff = *s1 - *s2;
+ while (*s1 && diff == 0 && n-- > 0)
+ diff = (int)*++s1 - (int)*++s2;
+ return diff;
+}
+static size_t wcslen(const wchar_t *s)
+{
+ const wchar_t *p = s;
+ while (*p)
+ p++;
+ return p - s;
+}
+#endif
+
+#include "archive.h"
+#include "archive_entry.h"
+#include "archive_private.h"
+
+/*
+ * Layout of POSIX 'ustar' tar header.
+ */
+struct archive_entry_header_ustar {
+ char name[100];
+ char mode[8];
+ char uid[8];
+ char gid[8];
+ char size[12];
+ char mtime[12];
+ char checksum[8];
+ char typeflag[1];
+ char linkname[100]; /* "old format" header ends here */
+ char magic[6]; /* For POSIX: "ustar\0" */
+ char version[2]; /* For POSIX: "00" */
+ char uname[32];
+ char gname[32];
+ char rdevmajor[8];
+ char rdevminor[8];
+ char prefix[155];
+};
+
+/*
+ * Structure of GNU tar header
+ */
+struct gnu_sparse {
+ char offset[12];
+ char numbytes[12];
+};
+
+struct archive_entry_header_gnutar {
+ char name[100];
+ char mode[8];
+ char uid[8];
+ char gid[8];
+ char size[12];
+ char mtime[12];
+ char checksum[8];
+ char typeflag[1];
+ char linkname[100];
+ char magic[8]; /* "ustar \0" (note blank/blank/null at end) */
+ char uname[32];
+ char gname[32];
+ char rdevmajor[8];
+ char rdevminor[8];
+ char atime[12];
+ char ctime[12];
+ char offset[12];
+ char longnames[4];
+ char unused[1];
+ struct gnu_sparse sparse[4];
+ char isextended[1];
+ char realsize[12];
+ /*
+ * GNU doesn't use POSIX 'prefix' field; they use the 'L' (longname)
+ * entry instead.
+ */
+};
+
+/*
+ * Data specific to this format.
+ */
+struct sparse_block {
+ struct sparse_block *next;
+ off_t offset;
+ off_t remaining;
+};
+
+struct tar {
+ struct archive_string acl_text;
+ struct archive_string entry_name;
+ struct archive_string entry_linkname;
+ struct archive_string entry_uname;
+ struct archive_string entry_gname;
+ struct archive_string longlink;
+ struct archive_string longname;
+ struct archive_string pax_header;
+ struct archive_string pax_global;
+ wchar_t *pax_entry;
+ size_t pax_entry_length;
+ int header_recursion_depth;
+ off_t entry_bytes_remaining;
+ off_t entry_offset;
+ off_t entry_padding;
+ struct sparse_block *sparse_list;
+};
+
+static size_t UTF8_mbrtowc(wchar_t *pwc, const char *s, size_t n);
+static int archive_block_is_null(const unsigned char *p);
+static char *base64_decode(const wchar_t *, size_t, size_t *);
+static int gnu_read_sparse_data(struct archive *, struct tar *,
+ const struct archive_entry_header_gnutar *header);
+static void gnu_parse_sparse_data(struct archive *, struct tar *,
+ const struct gnu_sparse *sparse, int length);
+static int header_Solaris_ACL(struct archive *, struct tar *,
+ struct archive_entry *, struct stat *, const void *);
+static int header_common(struct archive *, struct tar *,
+ struct archive_entry *, struct stat *, const void *);
+static int header_old_tar(struct archive *, struct tar *,
+ struct archive_entry *, struct stat *, const void *);
+static int header_pax_extensions(struct archive *, struct tar *,
+ struct archive_entry *, struct stat *, const void *);
+static int header_pax_global(struct archive *, struct tar *,
+ struct archive_entry *, struct stat *, const void *h);
+static int header_longlink(struct archive *, struct tar *,
+ struct archive_entry *, struct stat *, const void *h);
+static int header_longname(struct archive *, struct tar *,
+ struct archive_entry *, struct stat *, const void *h);
+static int header_volume(struct archive *, struct tar *,
+ struct archive_entry *, struct stat *, const void *h);
+static int header_ustar(struct archive *, struct tar *,
+ struct archive_entry *, struct stat *, const void *h);
+static int header_gnutar(struct archive *, struct tar *,
+ struct archive_entry *, struct stat *, const void *h);
+static int archive_read_format_tar_bid(struct archive *);
+static int archive_read_format_tar_cleanup(struct archive *);
+static int archive_read_format_tar_read_data(struct archive *a,
+ const void **buff, size_t *size, off_t *offset);
+static int archive_read_format_tar_read_header(struct archive *,
+ struct archive_entry *);
+static int checksum(struct archive *, const void *);
+static int pax_attribute(struct archive_entry *, struct stat *,
+ wchar_t *key, wchar_t *value);
+static int pax_header(struct archive *, struct tar *,
+ struct archive_entry *, struct stat *, char *attr);
+static void pax_time(const wchar_t *, int64_t *sec, long *nanos);
+static int read_body_to_string(struct archive *, struct tar *,
+ struct archive_string *, const void *h);
+static int64_t tar_atol(const char *, unsigned);
+static int64_t tar_atol10(const wchar_t *, unsigned);
+static int64_t tar_atol256(const char *, unsigned);
+static int64_t tar_atol8(const char *, unsigned);
+static int tar_read_header(struct archive *, struct tar *,
+ struct archive_entry *, struct stat *);
+static int tohex(int c);
+static char *url_decode(const char *);
+static int utf8_decode(wchar_t *, const char *, size_t length);
+static char *wide_to_narrow(const wchar_t *wval);
+
+/*
+ * ANSI C99 defines constants for these, but not everyone supports
+ * those constants, so I define a couple of static variables here and
+ * compute the values. These calculations should be portable to any
+ * 2s-complement architecture.
+ */
+#ifdef UINT64_MAX
+static const uint64_t max_uint64 = UINT64_MAX;
+#else
+static const uint64_t max_uint64 = ~(uint64_t)0;
+#endif
+#ifdef INT64_MAX
+static const int64_t max_int64 = INT64_MAX;
+#else
+static const int64_t max_int64 = (int64_t)((~(uint64_t)0) >> 1);
+#endif
+#ifdef INT64_MIN
+static const int64_t min_int64 = INT64_MIN;
+#else
+static const int64_t min_int64 = (int64_t)(~((~(uint64_t)0) >> 1));
+#endif
+
+int
+archive_read_support_format_gnutar(struct archive *a)
+{
+ return (archive_read_support_format_tar(a));
+}
+
+
+int
+archive_read_support_format_tar(struct archive *a)
+{
+ struct tar *tar;
+ int r;
+
+ tar = malloc(sizeof(*tar));
+ if (tar == NULL) {
+ archive_set_error(a, ENOMEM, "Can't allocate tar data");
+ return (ARCHIVE_FATAL);
+ }
+ memset(tar, 0, sizeof(*tar));
+
+ r = __archive_read_register_format(a, tar,
+ archive_read_format_tar_bid,
+ archive_read_format_tar_read_header,
+ archive_read_format_tar_read_data,
+ NULL,
+ archive_read_format_tar_cleanup);
+
+ if (r != ARCHIVE_OK)
+ free(tar);
+ return (ARCHIVE_OK);
+}
+
+static int
+archive_read_format_tar_cleanup(struct archive *a)
+{
+ struct tar *tar;
+
+ tar = *(a->pformat_data);
+ archive_string_free(&tar->acl_text);
+ archive_string_free(&tar->entry_name);
+ archive_string_free(&tar->entry_linkname);
+ archive_string_free(&tar->entry_uname);
+ archive_string_free(&tar->entry_gname);
+ archive_string_free(&tar->pax_global);
+ archive_string_free(&tar->pax_header);
+ if (tar->pax_entry != NULL)
+ free(tar->pax_entry);
+ free(tar);
+ *(a->pformat_data) = NULL;
+ return (ARCHIVE_OK);
+}
+
+
+static int
+archive_read_format_tar_bid(struct archive *a)
+{
+ int bid;
+ ssize_t bytes_read;
+ const void *h;
+ const struct archive_entry_header_ustar *header;
+
+ /*
+ * If we're already reading a non-tar file, don't
+ * bother to bid.
+ */
+ if (a->archive_format != 0 &&
+ (a->archive_format & ARCHIVE_FORMAT_BASE_MASK) !=
+ ARCHIVE_FORMAT_TAR)
+ return (0);
+ bid = 0;
+
+ /*
+ * If we're already reading a tar format, start the bid at 1 as
+ * a failsafe.
+ */
+ if ((a->archive_format & ARCHIVE_FORMAT_BASE_MASK) ==
+ ARCHIVE_FORMAT_TAR)
+ bid++;
+
+ /* Now let's look at the actual header and see if it matches. */
+ if (a->compression_read_ahead != NULL)
+ bytes_read = (a->compression_read_ahead)(a, &h, 512);
+ else
+ bytes_read = 0; /* Empty file. */
+ if (bytes_read < 0)
+ return (ARCHIVE_FATAL);
+ if (bytes_read == 0 && bid > 0) {
+ /* An archive without a proper end-of-archive marker. */
+ /* Hold our nose and bid 1 anyway. */
+ return (1);
+ }
+ if (bytes_read < 512) {
+ /* If it's a new archive, then just return a zero bid. */
+ if (bid == 0)
+ return (0);
+ /*
+ * If we already know this is a tar archive,
+ * then we have a problem.
+ */
+ archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated tar archive");
+ return (ARCHIVE_FATAL);
+ }
+
+ /* If it's an end-of-archive mark, we can handle it. */
+ if ((*(const char *)h) == 0 && archive_block_is_null(h)) {
+ /* If it's a known tar file, end-of-archive is definite. */
+ if ((a->archive_format & ARCHIVE_FORMAT_BASE_MASK) ==
+ ARCHIVE_FORMAT_TAR)
+ return (512);
+ /* Empty archive? */
+ return (1);
+ }
+
+ /* If it's not an end-of-archive mark, it must have a valid checksum.*/
+ if (!checksum(a, h))
+ return (0);
+ bid += 48; /* Checksum is usually 6 octal digits. */
+
+ header = h;
+
+ /* Recognize POSIX formats. */
+ if ((memcmp(header->magic, "ustar\0", 6) == 0)
+ &&(memcmp(header->version, "00", 2)==0))
+ bid += 56;
+
+ /* Recognize GNU tar format. */
+ if ((memcmp(header->magic, "ustar ", 6) == 0)
+ &&(memcmp(header->version, " \0", 2)==0))
+ bid += 56;
+
+ /* Type flag must be null, digit or A-Z, a-z. */
+ if (header->typeflag[0] != 0 &&
+ !( header->typeflag[0] >= '0' && header->typeflag[0] <= '9') &&
+ !( header->typeflag[0] >= 'A' && header->typeflag[0] <= 'Z') &&
+ !( header->typeflag[0] >= 'a' && header->typeflag[0] <= 'z') )
+ return (0);
+ bid += 2; /* 6 bits of variation in an 8-bit field leaves 2 bits. */
+
+ /* Sanity check: Look at first byte of mode field. */
+ switch (255 & (unsigned)header->mode[0]) {
+ case 0: case 255:
+ /* Base-256 value: No further verification possible! */
+ break;
+ case ' ': /* Not recommended, but not illegal, either. */
+ break;
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ /* Octal Value. */
+ /* TODO: Check format of remainder of this field. */
+ break;
+ default:
+ /* Not a valid mode; bail out here. */
+ return (0);
+ }
+ /* TODO: Sanity test uid/gid/size/mtime/rdevmajor/rdevminor fields. */
+
+ return (bid);
+}
+
+/*
+ * The function invoked by archive_read_header(). This
+ * just sets up a few things and then calls the internal
+ * tar_read_header() function below.
+ */
+static int
+archive_read_format_tar_read_header(struct archive *a,
+ struct archive_entry *entry)
+{
+ /*
+ * When converting tar archives to cpio archives, it is
+ * essential that each distinct file have a distinct inode
+ * number. To simplify this, we keep a static count here to
+ * assign fake dev/inode numbers to each tar entry. Note that
+ * pax format archives may overwrite this with something more
+ * useful.
+ *
+ * Ideally, we would track every file read from the archive so
+ * that we could assign the same dev/ino pair to hardlinks,
+ * but the memory required to store a complete lookup table is
+ * probably not worthwhile just to support the relatively
+ * obscure tar->cpio conversion case.
+ */
+ static int default_inode;
+ static int default_dev;
+ struct stat st;
+ struct tar *tar;
+ const char *p;
+ int r;
+ size_t l;
+
+ memset(&st, 0, sizeof(st));
+ /* Assign default device/inode values. */
+ st.st_dev = 1 + default_dev; /* Don't use zero. */
+ st.st_ino = ++default_inode; /* Don't use zero. */
+ /* Limit generated st_ino number to 16 bits. */
+ if (default_inode >= 0xffff) {
+ ++default_dev;
+ default_inode = 0;
+ }
+
+ tar = *(a->pformat_data);
+ tar->entry_offset = 0;
+
+ r = tar_read_header(a, tar, entry, &st);
+
+ if (r == ARCHIVE_OK) {
+ /*
+ * "Regular" entry with trailing '/' is really
+ * directory: This is needed for certain old tar
+ * variants and even for some broken newer ones.
+ */
+ p = archive_entry_pathname(entry);
+ l = strlen(p);
+ if (S_ISREG(st.st_mode) && p[l-1] == '/') {
+ st.st_mode &= ~S_IFMT;
+ st.st_mode |= S_IFDIR;
+ }
+
+ /* Copy the final stat data into the entry. */
+ archive_entry_copy_stat(entry, &st);
+ }
+ return (r);
+}
+
+static int
+archive_read_format_tar_read_data(struct archive *a,
+ const void **buff, size_t *size, off_t *offset)
+{
+ ssize_t bytes_read;
+ struct tar *tar;
+ struct sparse_block *p;
+
+ tar = *(a->pformat_data);
+ if (tar->sparse_list != NULL) {
+ /* Remove exhausted entries from sparse list. */
+ while (tar->sparse_list != NULL &&
+ tar->sparse_list->remaining == 0) {
+ p = tar->sparse_list;
+ tar->sparse_list = p->next;
+ free(p);
+ }
+ if (tar->sparse_list == NULL) {
+ /* We exhausted the entire sparse list. */
+ tar->entry_bytes_remaining = 0;
+ }
+ }
+
+ if (tar->entry_bytes_remaining > 0) {
+ bytes_read = (a->compression_read_ahead)(a, buff, 1);
+ if (bytes_read <= 0)
+ return (ARCHIVE_FATAL);
+ if (bytes_read > tar->entry_bytes_remaining)
+ bytes_read = tar->entry_bytes_remaining;
+ if (tar->sparse_list != NULL) {
+ /* Don't read more than is available in the
+ * current sparse block. */
+ if (tar->sparse_list->remaining < bytes_read)
+ bytes_read = tar->sparse_list->remaining;
+ tar->entry_offset = tar->sparse_list->offset;
+ tar->sparse_list->remaining -= bytes_read;
+ tar->sparse_list->offset += bytes_read;
+ }
+ *size = bytes_read;
+ *offset = tar->entry_offset;
+ tar->entry_offset += bytes_read;
+ tar->entry_bytes_remaining -= bytes_read;
+ (a->compression_read_consume)(a, bytes_read);
+ return (ARCHIVE_OK);
+ } else {
+ while (tar->entry_padding > 0) {
+ bytes_read = (a->compression_read_ahead)(a, buff, 1);
+ if (bytes_read <= 0)
+ return (ARCHIVE_FATAL);
+ if (bytes_read > tar->entry_padding)
+ bytes_read = tar->entry_padding;
+ (a->compression_read_consume)(a, bytes_read);
+ tar->entry_padding -= bytes_read;
+ }
+ *buff = NULL;
+ *size = 0;
+ *offset = tar->entry_offset;
+ return (ARCHIVE_EOF);
+ }
+}
+
+/*
+ * This function recursively interprets all of the headers associated
+ * with a single entry.
+ */
+static int
+tar_read_header(struct archive *a, struct tar *tar,
+ struct archive_entry *entry, struct stat *st)
+{
+ ssize_t bytes;
+ int err;
+ const void *h;
+ const struct archive_entry_header_ustar *header;
+
+ /* Read 512-byte header record */
+ bytes = (a->compression_read_ahead)(a, &h, 512);
+ if (bytes < 512) {
+ /*
+ * If we're here, it's becase the _bid function accepted
+ * this file. So just call a short read end-of-archive
+ * and be done with it.
+ */
+ return (ARCHIVE_EOF);
+ }
+ (a->compression_read_consume)(a, 512);
+
+ /* Check for end-of-archive mark. */
+ if (((*(const char *)h)==0) && archive_block_is_null(h)) {
+ /* Try to consume a second all-null record, as well. */
+ bytes = (a->compression_read_ahead)(a, &h, 512);
+ if (bytes > 0)
+ (a->compression_read_consume)(a, bytes);
+ archive_set_error(a, 0, NULL);
+ return (ARCHIVE_EOF);
+ }
+
+ /*
+ * Note: If the checksum fails and we return ARCHIVE_RETRY,
+ * then the client is likely to just retry. This is a very
+ * crude way to search for the next valid header!
+ *
+ * TODO: Improve this by implementing a real header scan.
+ */
+ if (!checksum(a, h)) {
+ archive_set_error(a, EINVAL, "Damaged tar archive");
+ return (ARCHIVE_RETRY); /* Retryable: Invalid header */
+ }
+
+ if (++tar->header_recursion_depth > 32) {
+ archive_set_error(a, EINVAL, "Too many special headers");
+ return (ARCHIVE_WARN);
+ }
+
+ /* Determine the format variant. */
+ header = h;
+ switch(header->typeflag[0]) {
+ case 'A': /* Solaris tar ACL */
+ a->archive_format = ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE;
+ a->archive_format_name = "Solaris tar";
+ err = header_Solaris_ACL(a, tar, entry, st, h);
+ break;
+ case 'g': /* POSIX-standard 'g' header. */
+ a->archive_format = ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE;
+ a->archive_format_name = "POSIX pax interchange format";
+ err = header_pax_global(a, tar, entry, st, h);
+ break;
+ case 'K': /* Long link name (GNU tar, others) */
+ err = header_longlink(a, tar, entry, st, h);
+ break;
+ case 'L': /* Long filename (GNU tar, others) */
+ err = header_longname(a, tar, entry, st, h);
+ break;
+ case 'V': /* GNU volume header */
+ err = header_volume(a, tar, entry, st, h);
+ break;
+ case 'X': /* Used by SUN tar; same as 'x'. */
+ a->archive_format = ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE;
+ a->archive_format_name =
+ "POSIX pax interchange format (Sun variant)";
+ err = header_pax_extensions(a, tar, entry, st, h);
+ break;
+ case 'x': /* POSIX-standard 'x' header. */
+ a->archive_format = ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE;
+ a->archive_format_name = "POSIX pax interchange format";
+ err = header_pax_extensions(a, tar, entry, st, h);
+ break;
+ default:
+ if (memcmp(header->magic, "ustar \0", 8) == 0) {
+ a->archive_format = ARCHIVE_FORMAT_TAR_GNUTAR;
+ a->archive_format_name = "GNU tar format";
+ err = header_gnutar(a, tar, entry, st, h);
+ } else if (memcmp(header->magic, "ustar", 5) == 0) {
+ if (a->archive_format != ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE) {
+ a->archive_format = ARCHIVE_FORMAT_TAR_USTAR;
+ a->archive_format_name = "POSIX ustar format";
+ }
+ err = header_ustar(a, tar, entry, st, h);
+ } else {
+ a->archive_format = ARCHIVE_FORMAT_TAR;
+ a->archive_format_name = "tar (non-POSIX)";
+ err = header_old_tar(a, tar, entry, st, h);
+ }
+ }
+ --tar->header_recursion_depth;
+ return (err);
+}
+
+/*
+ * Return true if block checksum is correct.
+ */
+static int
+checksum(struct archive *a, const void *h)
+{
+ const unsigned char *bytes;
+ const struct archive_entry_header_ustar *header;
+ int check, i, sum;
+
+ (void)a; /* UNUSED */
+ bytes = h;
+ header = h;
+
+ /*
+ * Test the checksum. Note that POSIX specifies _unsigned_
+ * bytes for this calculation.
+ */
+ sum = tar_atol(header->checksum, sizeof(header->checksum));
+ check = 0;
+ for (i = 0; i < 148; i++)
+ check += (unsigned char)bytes[i];
+ for (; i < 156; i++)
+ check += 32;
+ for (; i < 512; i++)
+ check += (unsigned char)bytes[i];
+ if (sum == check)
+ return (1);
+
+ /*
+ * Repeat test with _signed_ bytes, just in case this archive
+ * was created by an old BSD, Solaris, or HP-UX tar with a
+ * broken checksum calculation.
+ */
+ check = 0;
+ for (i = 0; i < 148; i++)
+ check += (signed char)bytes[i];
+ for (; i < 156; i++)
+ check += 32;
+ for (; i < 512; i++)
+ check += (signed char)bytes[i];
+ if (sum == check)
+ return (1);
+
+ return (0);
+}
+
+/*
+ * Return true if this block contains only nulls.
+ */
+static int
+archive_block_is_null(const unsigned char *p)
+{
+ unsigned i;
+
+ for (i = 0; i < ARCHIVE_BYTES_PER_RECORD / sizeof(*p); i++)
+ if (*p++)
+ return (0);
+ return (1);
+}
+
+/*
+ * Interpret 'A' Solaris ACL header
+ */
+static int
+header_Solaris_ACL(struct archive *a, struct tar *tar,
+ struct archive_entry *entry, struct stat *st, const void *h)
+{
+ int err, err2;
+ char *p;
+ wchar_t *wp;
+
+ err = read_body_to_string(a, tar, &(tar->acl_text), h);
+ err2 = tar_read_header(a, tar, entry, st);
+ err = err_combine(err, err2);
+
+ /* XXX Ensure p doesn't overrun acl_text */
+
+ /* Skip leading octal number. */
+ /* XXX TODO: Parse the octal number and sanity-check it. */
+ p = tar->acl_text.s;
+ while (*p != '\0')
+ p++;
+ p++;
+
+ wp = malloc((strlen(p) + 1) * sizeof(wchar_t));
+ if (wp != NULL) {
+ utf8_decode(wp, p, strlen(p));
+ err2 = __archive_entry_acl_parse_w(entry, wp,
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
+ err = err_combine(err, err2);
+ free(wp);
+ }
+
+ return (err);
+}
+
+/*
+ * Interpret 'K' long linkname header.
+ */
+static int
+header_longlink(struct archive *a, struct tar *tar,
+ struct archive_entry *entry, struct stat *st, const void *h)
+{
+ int err, err2;
+
+ err = read_body_to_string(a, tar, &(tar->longlink), h);
+ err2 = tar_read_header(a, tar, entry, st);
+ if (err == ARCHIVE_OK && err2 == ARCHIVE_OK) {
+ /* Set symlink if symlink already set, else hardlink. */
+ archive_entry_set_link(entry, tar->longlink.s);
+ }
+ return (err_combine(err, err2));
+}
+
+/*
+ * Interpret 'L' long filename header.
+ */
+static int
+header_longname(struct archive *a, struct tar *tar,
+ struct archive_entry *entry, struct stat *st, const void *h)
+{
+ int err, err2;
+
+ err = read_body_to_string(a, tar, &(tar->longname), h);
+ /* Read and parse "real" header, then override name. */
+ err2 = tar_read_header(a, tar, entry, st);
+ if (err == ARCHIVE_OK && err2 == ARCHIVE_OK)
+ archive_entry_set_pathname(entry, tar->longname.s);
+ return (err_combine(err, err2));
+}
+
+
+/*
+ * Interpret 'V' GNU tar volume header.
+ */
+static int
+header_volume(struct archive *a, struct tar *tar,
+ struct archive_entry *entry, struct stat *st, const void *h)
+{
+ (void)h;
+
+ /* Just skip this and read the next header. */
+ return (tar_read_header(a, tar, entry, st));
+}
+
+/*
+ * Read body of an archive entry into an archive_string object.
+ */
+static int
+read_body_to_string(struct archive *a, struct tar *tar,
+ struct archive_string *as, const void *h)
+{
+ off_t size, padded_size;
+ ssize_t bytes_read, bytes_to_copy;
+ const struct archive_entry_header_ustar *header;
+ const void *src;
+ char *dest;
+
+ (void)tar; /* UNUSED */
+ header = h;
+ size = tar_atol(header->size, sizeof(header->size));
+
+ /* Read the body into the string. */
+ archive_string_ensure(as, size+1);
+ padded_size = (size + 511) & ~ 511;
+ dest = as->s;
+ while (padded_size > 0) {
+ bytes_read = (a->compression_read_ahead)(a, &src, padded_size);
+ if (bytes_read < 0)
+ return (ARCHIVE_FATAL);
+ if (bytes_read > padded_size)
+ bytes_read = padded_size;
+ (a->compression_read_consume)(a, bytes_read);
+ bytes_to_copy = bytes_read;
+ if ((off_t)bytes_to_copy > size)
+ bytes_to_copy = (ssize_t)size;
+ memcpy(dest, src, bytes_to_copy);
+ dest += bytes_to_copy;
+ size -= bytes_to_copy;
+ padded_size -= bytes_read;
+ }
+ *dest = '\0';
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Parse out common header elements.
+ *
+ * This would be the same as header_old_tar, except that the
+ * filename is handled slightly differently for old and POSIX
+ * entries (POSIX entries support a 'prefix'). This factoring
+ * allows header_old_tar and header_ustar
+ * to handle filenames differently, while still putting most of the
+ * common parsing into one place.
+ */
+static int
+header_common(struct archive *a, struct tar *tar, struct archive_entry *entry,
+ struct stat *st, const void *h)
+{
+ const struct archive_entry_header_ustar *header;
+ char tartype;
+
+ (void)a; /* UNUSED */
+
+ header = h;
+ if (header->linkname[0])
+ archive_strncpy(&(tar->entry_linkname), header->linkname,
+ sizeof(header->linkname));
+ else
+ archive_string_empty(&(tar->entry_linkname));
+
+ /* Parse out the numeric fields (all are octal) */
+ st->st_mode = tar_atol(header->mode, sizeof(header->mode));
+ st->st_uid = tar_atol(header->uid, sizeof(header->uid));
+ st->st_gid = tar_atol(header->gid, sizeof(header->gid));
+ st->st_size = tar_atol(header->size, sizeof(header->size));
+ st->st_mtime = tar_atol(header->mtime, sizeof(header->mtime));
+
+ /* Handle the tar type flag appropriately. */
+ tartype = header->typeflag[0];
+ st->st_mode &= ~S_IFMT;
+
+ switch (tartype) {
+ case '1': /* Hard link */
+ archive_entry_set_hardlink(entry, tar->entry_linkname.s);
+ /*
+ * The following may seem odd, but: Technically, tar
+ * does not store the file type for a "hard link"
+ * entry, only the fact that it is a hard link. So, I
+ * leave the type zero normally. But, pax interchange
+ * format allows hard links to have data, which
+ * implies that the underlying entry is a regular
+ * file.
+ */
+ if (st->st_size > 0)
+ st->st_mode |= S_IFREG;
+
+ /*
+ * A tricky point: Traditionally, tar readers have
+ * ignored the size field when reading hardlink
+ * entries, and some writers put non-zero sizes even
+ * though the body is empty. POSIX.1-2001 broke with
+ * this tradition by permitting hardlink entries to
+ * store valid bodies in pax interchange format, but
+ * not in ustar format. Since there is no hard and
+ * fast way to distinguish pax interchange from
+ * earlier archives (the 'x' and 'g' entries are
+ * optional, after all), we need a heuristic. Here, I
+ * use the bid function to test whether or not there's
+ * a valid header following. Of course, if we know
+ * this is pax interchange format, then we must obey
+ * the size.
+ *
+ * This heuristic will only fail for a pax interchange
+ * archive that is storing hardlink bodies, no pax
+ * extended attribute entries have yet occurred, and
+ * we encounter a hardlink entry for a file that is
+ * itself an uncompressed tar archive.
+ */
+ if (st->st_size > 0 &&
+ a->archive_format != ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE &&
+ archive_read_format_tar_bid(a) > 50)
+ st->st_size = 0;
+ break;
+ case '2': /* Symlink */
+ st->st_mode |= S_IFLNK;
+ st->st_size = 0;
+ archive_entry_set_symlink(entry, tar->entry_linkname.s);
+ break;
+ case '3': /* Character device */
+ st->st_mode |= S_IFCHR;
+ st->st_size = 0;
+ break;
+ case '4': /* Block device */
+ st->st_mode |= S_IFBLK;
+ st->st_size = 0;
+ break;
+ case '5': /* Dir */
+ st->st_mode |= S_IFDIR;
+ st->st_size = 0;
+ break;
+ case '6': /* FIFO device */
+ st->st_mode |= S_IFIFO;
+ st->st_size = 0;
+ break;
+ case 'D': /* GNU incremental directory type */
+ /*
+ * No special handling is actually required here.
+ * It might be nice someday to preprocess the file list and
+ * provide it to the client, though.
+ */
+ st->st_mode |= S_IFDIR;
+ break;
+ case 'M': /* GNU "Multi-volume" (remainder of file from last archive)*/
+ /*
+ * As far as I can tell, this is just like a regular file
+ * entry, except that the contents should be _appended_ to
+ * the indicated file at the indicated offset. This may
+ * require some API work to fully support.
+ */
+ break;
+ case 'N': /* Old GNU "long filename" entry. */
+ /* The body of this entry is a script for renaming
+ * previously-extracted entries. Ugh. It will never
+ * be supported by libarchive. */
+ st->st_mode |= S_IFREG;
+ break;
+ case 'S': /* GNU sparse files */
+ /*
+ * Sparse files are really just regular files with
+ * sparse information in the extended area.
+ */
+ /* FALL THROUGH */
+ default: /* Regular file and non-standard types */
+ /*
+ * Per POSIX: non-recognized types should always be
+ * treated as regular files.
+ */
+ st->st_mode |= S_IFREG;
+ break;
+ }
+ return (0);
+}
+
+/*
+ * Parse out header elements for "old-style" tar archives.
+ */
+static int
+header_old_tar(struct archive *a, struct tar *tar, struct archive_entry *entry,
+ struct stat *st, const void *h)
+{
+ const struct archive_entry_header_ustar *header;
+
+ /* Copy filename over (to ensure null termination). */
+ header = h;
+ archive_strncpy(&(tar->entry_name), header->name, sizeof(header->name));
+ archive_entry_set_pathname(entry, tar->entry_name.s);
+
+ /* Grab rest of common fields */
+ header_common(a, tar, entry, st, h);
+
+ tar->entry_bytes_remaining = st->st_size;
+ tar->entry_padding = 0x1ff & (-tar->entry_bytes_remaining);
+ return (0);
+}
+
+/*
+ * Parse a file header for a pax extended archive entry.
+ */
+static int
+header_pax_global(struct archive *a, struct tar *tar,
+ struct archive_entry *entry, struct stat *st, const void *h)
+{
+ int err, err2;
+
+ err = read_body_to_string(a, tar, &(tar->pax_global), h);
+ err2 = tar_read_header(a, tar, entry, st);
+ return (err_combine(err, err2));
+}
+
+static int
+header_pax_extensions(struct archive *a, struct tar *tar,
+ struct archive_entry *entry, struct stat *st, const void *h)
+{
+ int err, err2;
+
+ read_body_to_string(a, tar, &(tar->pax_header), h);
+
+ /* Parse the next header. */
+ err = tar_read_header(a, tar, entry, st);
+
+ /*
+ * TODO: Parse global/default options into 'entry' struct here
+ * before handling file-specific options.
+ *
+ * This design (parse standard header, then overwrite with pax
+ * extended attribute data) usually works well, but isn't ideal;
+ * it would be better to parse the pax extended attributes first
+ * and then skip any fields in the standard header that were
+ * defined in the pax header.
+ */
+ err2 = pax_header(a, tar, entry, st, tar->pax_header.s);
+ err = err_combine(err, err2);
+ tar->entry_bytes_remaining = st->st_size;
+ tar->entry_padding = 0x1ff & (-tar->entry_bytes_remaining);
+ return (err);
+}
+
+
+/*
+ * Parse a file header for a Posix "ustar" archive entry. This also
+ * handles "pax" or "extended ustar" entries.
+ */
+static int
+header_ustar(struct archive *a, struct tar *tar, struct archive_entry *entry,
+ struct stat *st, const void *h)
+{
+ const struct archive_entry_header_ustar *header;
+ struct archive_string *as;
+
+ header = h;
+
+ /* Copy name into an internal buffer to ensure null-termination. */
+ as = &(tar->entry_name);
+ if (header->prefix[0]) {
+ archive_strncpy(as, header->prefix, sizeof(header->prefix));
+ if (as->s[archive_strlen(as) - 1] != '/')
+ archive_strappend_char(as, '/');
+ archive_strncat(as, header->name, sizeof(header->name));
+ } else
+ archive_strncpy(as, header->name, sizeof(header->name));
+
+ archive_entry_set_pathname(entry, as->s);
+
+ /* Handle rest of common fields. */
+ header_common(a, tar, entry, st, h);
+
+ /* Handle POSIX ustar fields. */
+ archive_strncpy(&(tar->entry_uname), header->uname,
+ sizeof(header->uname));
+ archive_entry_set_uname(entry, tar->entry_uname.s);
+
+ archive_strncpy(&(tar->entry_gname), header->gname,
+ sizeof(header->gname));
+ archive_entry_set_gname(entry, tar->entry_gname.s);
+
+ /* Parse out device numbers only for char and block specials. */
+ if (header->typeflag[0] == '3' || header->typeflag[0] == '4') {
+ st->st_rdev = makedev(
+ tar_atol(header->rdevmajor, sizeof(header->rdevmajor)),
+ tar_atol(header->rdevminor, sizeof(header->rdevminor)));
+ }
+
+ tar->entry_bytes_remaining = st->st_size;
+ tar->entry_padding = 0x1ff & (-tar->entry_bytes_remaining);
+
+ return (0);
+}
+
+
+/*
+ * Parse the pax extended attributes record.
+ *
+ * Returns non-zero if there's an error in the data.
+ */
+static int
+pax_header(struct archive *a, struct tar *tar, struct archive_entry *entry,
+ struct stat *st, char *attr)
+{
+ size_t attr_length, l, line_length;
+ char *line, *p;
+ wchar_t *key, *wp, *value;
+ int err, err2;
+
+ attr_length = strlen(attr);
+ err = ARCHIVE_OK;
+ while (attr_length > 0) {
+ /* Parse decimal length field at start of line. */
+ line_length = 0;
+ l = attr_length;
+ line = p = attr; /* Record start of line. */
+ while (l>0) {
+ if (*p == ' ') {
+ p++;
+ l--;
+ break;
+ }
+ if (*p < '0' || *p > '9')
+ return (-1);
+ line_length *= 10;
+ line_length += *p - '0';
+ if (line_length > 999999) {
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "Rejecting pax extended attribute > 1MB");
+ return (ARCHIVE_WARN);
+ }
+ p++;
+ l--;
+ }
+
+ if (line_length > attr_length)
+ return (0);
+
+ /* Ensure pax_entry buffer is big enough. */
+ if (tar->pax_entry_length <= line_length) {
+ wchar_t *old_entry = tar->pax_entry;
+
+ if (tar->pax_entry_length <= 0)
+ tar->pax_entry_length = 1024;
+ while (tar->pax_entry_length <= line_length + 1)
+ tar->pax_entry_length *= 2;
+
+ old_entry = tar->pax_entry;
+ tar->pax_entry = realloc(tar->pax_entry,
+ tar->pax_entry_length * sizeof(wchar_t));
+ if (tar->pax_entry == NULL) {
+ free(old_entry);
+ archive_set_error(a, ENOMEM,
+ "No memory");
+ return (ARCHIVE_FATAL);
+ }
+ }
+
+ /* Decode UTF-8 to wchar_t, null-terminate result. */
+ if (utf8_decode(tar->pax_entry, p,
+ line_length - (p - attr) - 1)) {
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "Invalid UTF8 character in pax extended attribute");
+ err = err_combine(err, ARCHIVE_WARN);
+ }
+
+ /* Null-terminate 'key' value. */
+ wp = key = tar->pax_entry;
+ if (key[0] == L'=')
+ return (-1);
+ while (*wp && *wp != L'=')
+ ++wp;
+ if (*wp == L'\0' || wp == NULL) {
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "Invalid pax extended attributes");
+ return (ARCHIVE_WARN);
+ }
+ *wp = 0;
+
+ /* Identify null-terminated 'value' portion. */
+ value = wp + 1;
+
+ /* Identify this attribute and set it in the entry. */
+ err2 = pax_attribute(entry, st, key, value);
+ err = err_combine(err, err2);
+
+ /* Skip to next line */
+ attr += line_length;
+ attr_length -= line_length;
+ }
+ return (err);
+}
+
+static int
+pax_attribute_xattr(struct archive_entry *entry,
+ wchar_t *name, wchar_t *value)
+{
+ char *name_decoded, *name_narrow;
+ void *value_decoded;
+ size_t value_len;
+
+ if (wcslen(name) < 18 || (wcsncmp(name, L"LIBARCHIVE.xattr.", 17)) != 0)
+ return 3;
+
+ name += 17;
+
+ /* URL-decode name */
+ name_narrow = wide_to_narrow(name);
+ if (name_narrow == NULL)
+ return 2;
+ name_decoded = url_decode(name_narrow);
+ free(name_narrow);
+ if (name_decoded == NULL)
+ return 2;
+
+ /* Base-64 decode value */
+ value_decoded = base64_decode(value, wcslen(value), &value_len);
+ if (value_decoded == NULL) {
+ free(name_decoded);
+ return 1;
+ }
+
+ archive_entry_xattr_add_entry(entry, name_decoded,
+ value_decoded, value_len);
+
+ free(name_decoded);
+ free(value_decoded);
+ return 0;
+}
+
+/*
+ * Parse a single key=value attribute. key/value pointers are
+ * assumed to point into reasonably long-lived storage.
+ *
+ * Note that POSIX reserves all-lowercase keywords. Vendor-specific
+ * extensions should always have keywords of the form "VENDOR.attribute"
+ * In particular, it's quite feasible to support many different
+ * vendor extensions here. I'm using "LIBARCHIVE" for extensions
+ * unique to this library (currently, there are none).
+ *
+ * Investigate other vendor-specific extensions, as well and see if
+ * any of them look useful.
+ */
+static int
+pax_attribute(struct archive_entry *entry, struct stat *st,
+ wchar_t *key, wchar_t *value)
+{
+ int64_t s;
+ long n;
+
+ switch (key[0]) {
+ case 'L':
+ /* Our extensions */
+/* TODO: Handle arbitrary extended attributes... */
+/*
+ if (strcmp(key, "LIBARCHIVE.xxxxxxx")==0)
+ archive_entry_set_xxxxxx(entry, value);
+*/
+ if (wcsncmp(key, L"LIBARCHIVE.xattr.", 17)==0)
+ pax_attribute_xattr(entry, key, value);
+ break;
+ case 'S':
+ /* We support some keys used by the "star" archiver */
+ if (wcscmp(key, L"SCHILY.acl.access")==0)
+ __archive_entry_acl_parse_w(entry, value,
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
+ else if (wcscmp(key, L"SCHILY.acl.default")==0)
+ __archive_entry_acl_parse_w(entry, value,
+ ARCHIVE_ENTRY_ACL_TYPE_DEFAULT);
+ else if (wcscmp(key, L"SCHILY.devmajor")==0)
+ st->st_rdev = makedev(tar_atol10(value, wcslen(value)),
+ minor(st->st_rdev));
+ else if (wcscmp(key, L"SCHILY.devminor")==0)
+ st->st_rdev = makedev(major(st->st_rdev),
+ tar_atol10(value, wcslen(value)));
+ else if (wcscmp(key, L"SCHILY.fflags")==0)
+ archive_entry_copy_fflags_text_w(entry, value);
+ else if (wcscmp(key, L"SCHILY.nlink")==0)
+ st->st_nlink = tar_atol10(value, wcslen(value));
+ break;
+ case 'a':
+ if (wcscmp(key, L"atime")==0) {
+ pax_time(value, &s, &n);
+ st->st_atime = s;
+ ARCHIVE_STAT_SET_ATIME_NANOS(st, n);
+ }
+ break;
+ case 'c':
+ if (wcscmp(key, L"ctime")==0) {
+ pax_time(value, &s, &n);
+ st->st_ctime = s;
+ ARCHIVE_STAT_SET_CTIME_NANOS(st, n);
+ } else if (wcscmp(key, L"charset")==0) {
+ /* TODO: Publish charset information in entry. */
+ } else if (wcscmp(key, L"comment")==0) {
+ /* TODO: Publish comment in entry. */
+ }
+ break;
+ case 'g':
+ if (wcscmp(key, L"gid")==0)
+ st->st_gid = tar_atol10(value, wcslen(value));
+ else if (wcscmp(key, L"gname")==0)
+ archive_entry_copy_gname_w(entry, value);
+ break;
+ case 'l':
+ /* pax interchange doesn't distinguish hardlink vs. symlink. */
+ if (wcscmp(key, L"linkpath")==0) {
+ if (archive_entry_hardlink(entry))
+ archive_entry_copy_hardlink_w(entry, value);
+ else
+ archive_entry_copy_symlink_w(entry, value);
+ }
+ break;
+ case 'm':
+ if (wcscmp(key, L"mtime")==0) {
+ pax_time(value, &s, &n);
+ st->st_mtime = s;
+ ARCHIVE_STAT_SET_MTIME_NANOS(st, n);
+ }
+ break;
+ case 'p':
+ if (wcscmp(key, L"path")==0)
+ archive_entry_copy_pathname_w(entry, value);
+ break;
+ case 'r':
+ /* POSIX has reserved 'realtime.*' */
+ break;
+ case 's':
+ /* POSIX has reserved 'security.*' */
+ /* Someday: if (wcscmp(key, L"security.acl")==0) { ... } */
+ if (wcscmp(key, L"size")==0)
+ st->st_size = tar_atol10(value, wcslen(value));
+ break;
+ case 'u':
+ if (wcscmp(key, L"uid")==0)
+ st->st_uid = tar_atol10(value, wcslen(value));
+ else if (wcscmp(key, L"uname")==0)
+ archive_entry_copy_uname_w(entry, value);
+ break;
+ }
+ return (0);
+}
+
+
+
+/*
+ * parse a decimal time value, which may include a fractional portion
+ */
+static void
+pax_time(const wchar_t *p, int64_t *ps, long *pn)
+{
+ char digit;
+ int64_t s;
+ unsigned long l;
+ int sign;
+ int64_t limit, last_digit_limit;
+
+ limit = max_int64 / 10;
+ last_digit_limit = max_int64 % 10;
+
+ s = 0;
+ sign = 1;
+ if (*p == '-') {
+ sign = -1;
+ p++;
+ }
+ while (*p >= '0' && *p <= '9') {
+ digit = *p - '0';
+ if (s > limit ||
+ (s == limit && digit > last_digit_limit)) {
+ s = max_uint64;
+ break;
+ }
+ s = (s * 10) + digit;
+ ++p;
+ }
+
+ *ps = s * sign;
+
+ /* Calculate nanoseconds. */
+ *pn = 0;
+
+ if (*p != '.')
+ return;
+
+ l = 100000000UL;
+ do {
+ ++p;
+ if (*p >= '0' && *p <= '9')
+ *pn += (*p - '0') * l;
+ else
+ break;
+ } while (l /= 10);
+}
+
+/*
+ * Parse GNU tar header
+ */
+static int
+header_gnutar(struct archive *a, struct tar *tar, struct archive_entry *entry,
+ struct stat *st, const void *h)
+{
+ const struct archive_entry_header_gnutar *header;
+
+ (void)a;
+
+ /*
+ * GNU header is like POSIX ustar, except 'prefix' is
+ * replaced with some other fields. This also means the
+ * filename is stored as in old-style archives.
+ */
+
+ /* Grab fields common to all tar variants. */
+ header_common(a, tar, entry, st, h);
+
+ /* Copy filename over (to ensure null termination). */
+ header = h;
+ archive_strncpy(&(tar->entry_name), header->name,
+ sizeof(header->name));
+ archive_entry_set_pathname(entry, tar->entry_name.s);
+
+ /* Fields common to ustar and GNU */
+ /* XXX Can the following be factored out since it's common
+ * to ustar and gnu tar? Is it okay to move it down into
+ * header_common, perhaps? */
+ archive_strncpy(&(tar->entry_uname),
+ header->uname, sizeof(header->uname));
+ archive_entry_set_uname(entry, tar->entry_uname.s);
+
+ archive_strncpy(&(tar->entry_gname),
+ header->gname, sizeof(header->gname));
+ archive_entry_set_gname(entry, tar->entry_gname.s);
+
+ /* Parse out device numbers only for char and block specials */
+ if (header->typeflag[0] == '3' || header->typeflag[0] == '4')
+ st->st_rdev = makedev (
+ tar_atol(header->rdevmajor, sizeof(header->rdevmajor)),
+ tar_atol(header->rdevminor, sizeof(header->rdevminor)));
+ else
+ st->st_rdev = 0;
+
+ tar->entry_bytes_remaining = st->st_size;
+ tar->entry_padding = 0x1ff & (-tar->entry_bytes_remaining);
+
+ /* Grab GNU-specific fields. */
+ st->st_atime = tar_atol(header->atime, sizeof(header->atime));
+ st->st_ctime = tar_atol(header->ctime, sizeof(header->ctime));
+ if (header->realsize[0] != 0) {
+ st->st_size = tar_atol(header->realsize,
+ sizeof(header->realsize));
+ }
+
+ if (header->sparse[0].offset[0] != 0) {
+ gnu_read_sparse_data(a, tar, header);
+ } else {
+ if (header->isextended[0] != 0) {
+ /* XXX WTF? XXX */
+ }
+ }
+
+ return (0);
+}
+
+static int
+gnu_read_sparse_data(struct archive *a, struct tar *tar,
+ const struct archive_entry_header_gnutar *header)
+{
+ ssize_t bytes_read;
+ const void *data;
+ struct extended {
+ struct gnu_sparse sparse[21];
+ char isextended[1];
+ char padding[7];
+ };
+ const struct extended *ext;
+
+ gnu_parse_sparse_data(a, tar, header->sparse, 4);
+ if (header->isextended[0] == 0)
+ return (ARCHIVE_OK);
+
+ do {
+ bytes_read = (a->compression_read_ahead)(a, &data, 512);
+ if (bytes_read < 0)
+ return (ARCHIVE_FATAL);
+ if (bytes_read < 512) {
+ archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated tar archive "
+ "detected while reading sparse file data");
+ return (ARCHIVE_FATAL);
+ }
+ (a->compression_read_consume)(a, 512);
+ ext = (const struct extended *)data;
+ gnu_parse_sparse_data(a, tar, ext->sparse, 21);
+ } while (ext->isextended[0] != 0);
+ if (tar->sparse_list != NULL)
+ tar->entry_offset = tar->sparse_list->offset;
+ return (ARCHIVE_OK);
+}
+
+static void
+gnu_parse_sparse_data(struct archive *a, struct tar *tar,
+ const struct gnu_sparse *sparse, int length)
+{
+ struct sparse_block *last;
+ struct sparse_block *p;
+
+ (void)a; /* UNUSED */
+
+ last = tar->sparse_list;
+ while (last != NULL && last->next != NULL)
+ last = last->next;
+
+ while (length > 0 && sparse->offset[0] != 0) {
+ p = malloc(sizeof(*p));
+ if (p == NULL)
+ __archive_errx(1, "Out of memory");
+ memset(p, 0, sizeof(*p));
+ if (last != NULL)
+ last->next = p;
+ else
+ tar->sparse_list = p;
+ last = p;
+ p->offset = tar_atol(sparse->offset, sizeof(sparse->offset));
+ p->remaining =
+ tar_atol(sparse->numbytes, sizeof(sparse->numbytes));
+ sparse++;
+ length--;
+ }
+}
+
+/*-
+ * Convert text->integer.
+ *
+ * Traditional tar formats (including POSIX) specify base-8 for
+ * all of the standard numeric fields. This is a significant limitation
+ * in practice:
+ * = file size is limited to 8GB
+ * = rdevmajor and rdevminor are limited to 21 bits
+ * = uid/gid are limited to 21 bits
+ *
+ * There are two workarounds for this:
+ * = pax extended headers, which use variable-length string fields
+ * = GNU tar and STAR both allow either base-8 or base-256 in
+ * most fields. The high bit is set to indicate base-256.
+ *
+ * On read, this implementation supports both extensions.
+ */
+static int64_t
+tar_atol(const char *p, unsigned char_cnt)
+{
+ /*
+ * Technically, GNU tar considers a field to be in base-256
+ * only if the first byte is 0xff or 0x80.
+ */
+ if (*p & 0x80)
+ return (tar_atol256(p, char_cnt));
+ return (tar_atol8(p, char_cnt));
+}
+
+/*
+ * Note that this implementation does not (and should not!) obey
+ * locale settings; you cannot simply substitute strtol here, since
+ * it does obey locale.
+ */
+static int64_t
+tar_atol8(const char *p, unsigned char_cnt)
+{
+ int64_t l, limit, last_digit_limit;
+ int digit, sign, base;
+
+ base = 8;
+ limit = max_int64 / base;
+ last_digit_limit = max_int64 % base;
+
+ while (*p == ' ' || *p == '\t')
+ p++;
+ if (*p == '-') {
+ sign = -1;
+ p++;
+ } else
+ sign = 1;
+
+ l = 0;
+ digit = *p - '0';
+ while (digit >= 0 && digit < base && char_cnt-- > 0) {
+ if (l>limit || (l == limit && digit > last_digit_limit)) {
+ l = max_uint64; /* Truncate on overflow. */
+ break;
+ }
+ l = (l * base) + digit;
+ digit = *++p - '0';
+ }
+ return (sign < 0) ? -l : l;
+}
+
+
+/*
+ * Note that this implementation does not (and should not!) obey
+ * locale settings; you cannot simply substitute strtol here, since
+ * it does obey locale.
+ */
+static int64_t
+tar_atol10(const wchar_t *p, unsigned char_cnt)
+{
+ int64_t l, limit, last_digit_limit;
+ int base, digit, sign;
+
+ base = 10;
+ limit = max_int64 / base;
+ last_digit_limit = max_int64 % base;
+
+ while (*p == ' ' || *p == '\t')
+ p++;
+ if (*p == '-') {
+ sign = -1;
+ p++;
+ } else
+ sign = 1;
+
+ l = 0;
+ digit = *p - '0';
+ while (digit >= 0 && digit < base && char_cnt-- > 0) {
+ if (l > limit || (l == limit && digit > last_digit_limit)) {
+ l = max_uint64; /* Truncate on overflow. */
+ break;
+ }
+ l = (l * base) + digit;
+ digit = *++p - '0';
+ }
+ return (sign < 0) ? -l : l;
+}
+
+/*
+ * Parse a base-256 integer. This is just a straight signed binary
+ * value in big-endian order, except that the high-order bit is
+ * ignored. Remember that "int64_t" may or may not be exactly 64
+ * bits; the implementation here tries to avoid making any assumptions
+ * about the actual size of an int64_t. It does assume we're using
+ * twos-complement arithmetic, though.
+ */
+static int64_t
+tar_atol256(const char *_p, unsigned char_cnt)
+{
+ int64_t l, upper_limit, lower_limit;
+ const unsigned char *p = (const unsigned char *)_p;
+
+ upper_limit = max_int64 / 256;
+ lower_limit = min_int64 / 256;
+
+ /* Pad with 1 or 0 bits, depending on sign. */
+ if ((0x40 & *p) == 0x40)
+ l = (int64_t)-1;
+ else
+ l = 0;
+ l = (l << 6) | (0x3f & *p++);
+ while (--char_cnt > 0) {
+ if (l > upper_limit) {
+ l = max_int64; /* Truncate on overflow */
+ break;
+ } else if (l < lower_limit) {
+ l = min_int64;
+ break;
+ }
+ l = (l << 8) | (0xff & (int64_t)*p++);
+ }
+ return (l);
+}
+
+static int
+utf8_decode(wchar_t *dest, const char *src, size_t length)
+{
+ size_t n;
+ int err;
+
+ err = 0;
+ while (length > 0) {
+ n = UTF8_mbrtowc(dest, src, length);
+ if (n == 0)
+ break;
+ dest++;
+ src += n;
+ length -= n;
+ }
+ *dest++ = L'\0';
+ return (err);
+}
+
+/*
+ * Copied and simplified from FreeBSD libc/locale.
+ */
+static size_t
+UTF8_mbrtowc(wchar_t *pwc, const char *s, size_t n)
+{
+ int ch, i, len, mask;
+ unsigned long wch;
+
+ if (s == NULL || n == 0 || pwc == NULL)
+ return (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.
+ */
+ ch = (unsigned char)*s;
+ if ((ch & 0x80) == 0) {
+ mask = 0x7f;
+ len = 1;
+ } else if ((ch & 0xe0) == 0xc0) {
+ mask = 0x1f;
+ len = 2;
+ } else if ((ch & 0xf0) == 0xe0) {
+ mask = 0x0f;
+ len = 3;
+ } else if ((ch & 0xf8) == 0xf0) {
+ mask = 0x07;
+ len = 4;
+ } else if ((ch & 0xfc) == 0xf8) {
+ mask = 0x03;
+ len = 5;
+ } else if ((ch & 0xfe) == 0xfc) {
+ mask = 0x01;
+ len = 6;
+ } else {
+ /* Invalid first byte; convert to '?' */
+ *pwc = '?';
+ return (1);
+ }
+
+ if (n < (size_t)len) {
+ /* Invalid first byte; convert to '?' */
+ *pwc = '?';
+ return (1);
+ }
+
+ /*
+ * Decode the octet sequence representing the character in chunks
+ * of 6 bits, most significant first.
+ */
+ wch = (unsigned char)*s++ & mask;
+ i = len;
+ while (--i != 0) {
+ if ((*s & 0xc0) != 0x80) {
+ /* Invalid intermediate byte; consume one byte and
+ * emit '?' */
+ *pwc = '?';
+ return (1);
+ }
+ wch <<= 6;
+ wch |= *s++ & 0x3f;
+ }
+
+ /* Assign the value to the output; out-of-range values
+ * just get truncated. */
+ *pwc = (wchar_t)wch;
+#ifdef WCHAR_MAX
+ /*
+ * If platform has WCHAR_MAX, we can do something
+ * more sensible with out-of-range values.
+ */
+ if (wch >= WCHAR_MAX)
+ *pwc = '?';
+#endif
+ /* Return number of bytes input consumed: 0 for end-of-string. */
+ return (wch == L'\0' ? 0 : len);
+}
+
+
+/*
+ * base64_decode - Base64 decode
+ *
+ * This accepts most variations of base-64 encoding, including:
+ * * with or without line breaks
+ * * with or without the final group padded with '=' or '_' characters
+ * (The most economical Base-64 variant does not pad the last group and
+ * omits line breaks; RFC1341 used for MIME requires both.)
+ */
+static char *
+base64_decode(const wchar_t *src, size_t len, size_t *out_len)
+{
+ static const unsigned char digits[64] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ static unsigned char decode_table[128];
+ char *out, *d;
+
+ /* If the decode table is not yet initialized, prepare it. */
+ if (decode_table[digits[1]] != 1) {
+ size_t i;
+ memset(decode_table, 0xff, sizeof(decode_table));
+ for (i = 0; i < sizeof(digits); i++)
+ decode_table[digits[i]] = i;
+ }
+
+ /* Allocate enough space to hold the entire output. */
+ /* Note that we may not use all of this... */
+ out = malloc((len * 3 + 3) / 4);
+ if (out == NULL) {
+ *out_len = 0;
+ return (NULL);
+ }
+ d = out;
+
+ while (len > 0) {
+ /* Collect the next group of (up to) four characters. */
+ int v = 0;
+ int group_size = 0;
+ while (group_size < 4 && len > 0) {
+ /* '=' or '_' padding indicates final group. */
+ if (*src == '=' || *src == '_') {
+ len = 0;
+ break;
+ }
+ /* Skip illegal characters (including line breaks) */
+ if (*src > 127 || *src < 32
+ || decode_table[*src] == 0xff) {
+ len--;
+ src++;
+ continue;
+ }
+ v <<= 6;
+ v |= decode_table[*src++];
+ len --;
+ group_size++;
+ }
+ /* Align a short group properly. */
+ v <<= 6 * (4 - group_size);
+ /* Unpack the group we just collected. */
+ switch (group_size) {
+ case 4: d[2] = v & 0xff;
+ /* FALLTHROUGH */
+ case 3: d[1] = (v >> 8) & 0xff;
+ /* FALLTHROUGH */
+ case 2: d[0] = (v >> 16) & 0xff;
+ break;
+ case 1: /* this is invalid! */
+ break;
+ }
+ d += group_size * 3 / 4;
+ }
+
+ *out_len = d - out;
+ return (out);
+}
+
+/*
+ * This is a little tricky because the C99 standard wcstombs()
+ * function returns the number of bytes that were converted,
+ * not the number that should be converted. As a result,
+ * we can never accurately size the output buffer (without
+ * doing a tedious output size calculation in advance).
+ * This approach (try a conversion, then try again if it fails)
+ * will almost always succeed on the first try, and is thus
+ * much faster, at the cost of sometimes requiring multiple
+ * passes while we expand the buffer.
+ */
+static char *
+wide_to_narrow(const wchar_t *wval)
+{
+ int converted_length;
+ /* Guess an output buffer size and try the conversion. */
+ int alloc_length = wcslen(wval) * 3;
+ char *mbs_val = malloc(alloc_length + 1);
+ if (mbs_val == NULL)
+ return (NULL);
+ converted_length = wcstombs(mbs_val, wval, alloc_length);
+
+ /* If we exhausted the buffer, resize and try again. */
+ while (converted_length >= alloc_length) {
+ free(mbs_val);
+ alloc_length *= 2;
+ mbs_val = malloc(alloc_length + 1);
+ if (mbs_val == NULL)
+ return (NULL);
+ converted_length = wcstombs(mbs_val, wval, alloc_length);
+ }
+
+ /* Ensure a trailing null and return the final string. */
+ mbs_val[alloc_length] = '\0';
+ return (mbs_val);
+}
+
+static char *
+url_decode(const char *in)
+{
+ char *out, *d;
+ const char *s;
+
+ out = malloc(strlen(in) + 1);
+ if (out == NULL)
+ return (NULL);
+ for (s = in, d = out; *s != '\0'; ) {
+ if (*s == '%') {
+ /* Try to convert % escape */
+ int digit1 = tohex(s[1]);
+ int digit2 = tohex(s[2]);
+ if (digit1 >= 0 && digit2 >= 0) {
+ /* Looks good, consume three chars */
+ s += 3;
+ /* Convert output */
+ *d++ = ((digit1 << 4) | digit2);
+ continue;
+ }
+ /* Else fall through and treat '%' as normal char */
+ }
+ *d++ = *s++;
+ }
+ *d = '\0';
+ return (out);
+}
+
+static int
+tohex(int c)
+{
+ if (c >= '0' && c <= '9')
+ return (c - '0');
+ else if (c >= 'A' && c <= 'F')
+ return (c - 'A' + 10);
+ else if (c >= 'a' && c <= 'f')
+ return (c - 'a' + 10);
+ else
+ return (-1);
+}
diff --git a/lib/libarchive/archive_read_support_format_zip.c b/lib/libarchive/archive_read_support_format_zip.c
new file mode 100644
index 0000000..c29d11d
--- /dev/null
+++ b/lib/libarchive/archive_read_support_format_zip.c
@@ -0,0 +1,797 @@
+/*-
+ * Copyright (c) 2004 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(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 AUTHOR(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 "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#include <sys/stat.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#ifdef HAVE_ZLIB_H
+#include <zlib.h>
+#endif
+
+#include "archive.h"
+#include "archive_entry.h"
+#include "archive_private.h"
+
+struct zip {
+ /* entry_bytes_remaining is the number of bytes we expect. */
+ off_t entry_bytes_remaining;
+ off_t entry_offset;
+
+ /* These count the number of bytes actually read for the entry. */
+ off_t entry_compressed_bytes_read;
+ off_t entry_uncompressed_bytes_read;
+
+ unsigned version;
+ unsigned system;
+ unsigned flags;
+ unsigned compression;
+ const char * compression_name;
+ time_t mtime;
+ time_t ctime;
+ time_t atime;
+ mode_t mode;
+ uid_t uid;
+ gid_t gid;
+
+ /* Flags to mark progress of decompression. */
+ char decompress_init;
+ char end_of_entry;
+ char end_of_entry_cleanup;
+
+ long crc32;
+ ssize_t filename_length;
+ ssize_t extra_length;
+ off_t uncompressed_size;
+ off_t compressed_size;
+
+ unsigned char *uncompressed_buffer;
+ size_t uncompressed_buffer_size;
+#ifdef HAVE_ZLIB_H
+ z_stream stream;
+#endif
+
+ struct archive_string pathname;
+ struct archive_string extra;
+ char format_name[64];
+};
+
+#define ZIP_LENGTH_AT_END 8
+
+struct zip_file_header {
+ char signature[4];
+ char version[2];
+ char flags[2];
+ char compression[2];
+ char timedate[4];
+ char crc32[4];
+ char compressed_size[4];
+ char uncompressed_size[4];
+ char filename_length[2];
+ char extra_length[2];
+};
+
+static const char *compression_names[] = {
+ "uncompressed",
+ "shrinking",
+ "reduced-1",
+ "reduced-2",
+ "reduced-3",
+ "reduced-4",
+ "imploded",
+ "reserved",
+ "deflation"
+};
+
+static int archive_read_format_zip_bid(struct archive *);
+static int archive_read_format_zip_cleanup(struct archive *);
+static int archive_read_format_zip_read_data(struct archive *,
+ const void **, size_t *, off_t *);
+static int archive_read_format_zip_read_data_skip(struct archive *a);
+static int archive_read_format_zip_read_header(struct archive *,
+ struct archive_entry *);
+static int i2(const char *);
+static int i4(const char *);
+static unsigned int u2(const char *);
+static unsigned int u4(const char *);
+static uint64_t u8(const char *);
+static int zip_read_data_deflate(struct archive *a, const void **buff,
+ size_t *size, off_t *offset);
+static int zip_read_data_none(struct archive *a, const void **buff,
+ size_t *size, off_t *offset);
+static int zip_read_file_header(struct archive *a,
+ struct archive_entry *entry, struct zip *zip);
+static time_t zip_time(const char *);
+static void process_extra(const void* extra, struct zip* zip);
+
+int
+archive_read_support_format_zip(struct archive *a)
+{
+ struct zip *zip;
+ int r;
+
+ zip = malloc(sizeof(*zip));
+ if (zip == NULL) {
+ archive_set_error(a, ENOMEM, "Can't allocate zip data");
+ return (ARCHIVE_FATAL);
+ }
+ memset(zip, 0, sizeof(*zip));
+
+ r = __archive_read_register_format(a,
+ zip,
+ archive_read_format_zip_bid,
+ archive_read_format_zip_read_header,
+ archive_read_format_zip_read_data,
+ archive_read_format_zip_read_data_skip,
+ archive_read_format_zip_cleanup);
+
+ if (r != ARCHIVE_OK)
+ free(zip);
+ return (ARCHIVE_OK);
+}
+
+
+static int
+archive_read_format_zip_bid(struct archive *a)
+{
+ int bytes_read;
+ int bid = 0;
+ const void *h;
+ const char *p;
+
+ if (a->archive_format == ARCHIVE_FORMAT_ZIP)
+ bid += 1;
+
+ bytes_read = (a->compression_read_ahead)(a, &h, 4);
+ if (bytes_read < 4)
+ return (-1);
+ p = h;
+
+ if (p[0] == 'P' && p[1] == 'K') {
+ bid += 16;
+ if (p[2] == '\001' && p[3] == '\002')
+ bid += 16;
+ else if (p[2] == '\003' && p[3] == '\004')
+ bid += 16;
+ else if (p[2] == '\005' && p[3] == '\006')
+ bid += 16;
+ else if (p[2] == '\007' && p[3] == '\010')
+ bid += 16;
+ }
+ return (bid);
+}
+
+static int
+archive_read_format_zip_read_header(struct archive *a,
+ struct archive_entry *entry)
+{
+ int bytes_read;
+ const void *h;
+ const char *signature;
+ struct zip *zip;
+
+ a->archive_format = ARCHIVE_FORMAT_ZIP;
+ if (a->archive_format_name == NULL)
+ a->archive_format_name = "ZIP";
+
+ zip = *(a->pformat_data);
+ zip->decompress_init = 0;
+ zip->end_of_entry = 0;
+ zip->end_of_entry_cleanup = 0;
+ zip->entry_uncompressed_bytes_read = 0;
+ zip->entry_compressed_bytes_read = 0;
+ bytes_read = (a->compression_read_ahead)(a, &h, 4);
+ if (bytes_read < 4)
+ return (ARCHIVE_FATAL);
+
+ signature = h;
+ if (signature[0] != 'P' || signature[1] != 'K') {
+ archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Bad ZIP file");
+ return (ARCHIVE_FATAL);
+ }
+
+ if (signature[2] == '\001' && signature[3] == '\002') {
+ /* Beginning of central directory. */
+ return (ARCHIVE_EOF);
+ }
+
+ if (signature[2] == '\003' && signature[3] == '\004') {
+ /* Regular file entry. */
+ return (zip_read_file_header(a, entry, zip));
+ }
+
+ if (signature[2] == '\005' && signature[3] == '\006') {
+ /* End-of-archive record. */
+ return (ARCHIVE_EOF);
+ }
+
+ if (signature[2] == '\007' && signature[3] == '\010') {
+ /*
+ * We should never encounter this record here;
+ * see ZIP_LENGTH_AT_END handling below for details.
+ */
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "Bad ZIP file: Unexpected end-of-entry record");
+ return (ARCHIVE_FATAL);
+ }
+
+ archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Damaged ZIP file or unsupported format variant (%d,%d)",
+ signature[2], signature[3]);
+ return (ARCHIVE_FATAL);
+}
+
+int
+zip_read_file_header(struct archive *a, struct archive_entry *entry,
+ struct zip *zip)
+{
+ const struct zip_file_header *p;
+ const void *h;
+ int bytes_read;
+ struct stat st;
+
+ bytes_read =
+ (a->compression_read_ahead)(a, &h, sizeof(struct zip_file_header));
+ if (bytes_read < (int)sizeof(struct zip_file_header)) {
+ archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated ZIP file header");
+ return (ARCHIVE_FATAL);
+ }
+ p = h;
+
+ zip->version = p->version[0];
+ zip->system = p->version[1];
+ zip->flags = i2(p->flags);
+ zip->compression = i2(p->compression);
+ if (zip->compression <
+ sizeof(compression_names)/sizeof(compression_names[0]))
+ zip->compression_name = compression_names[zip->compression];
+ else
+ zip->compression_name = "??";
+ zip->mtime = zip_time(p->timedate);
+ zip->ctime = 0;
+ zip->atime = 0;
+ zip->mode = 0;
+ zip->uid = 0;
+ zip->gid = 0;
+ zip->crc32 = i4(p->crc32);
+ zip->filename_length = i2(p->filename_length);
+ zip->extra_length = i2(p->extra_length);
+ zip->uncompressed_size = u4(p->uncompressed_size);
+ zip->compressed_size = u4(p->compressed_size);
+
+ (a->compression_read_consume)(a, sizeof(struct zip_file_header));
+
+
+ /* Read the filename. */
+ bytes_read = (a->compression_read_ahead)(a, &h, zip->filename_length);
+ if (bytes_read < zip->filename_length) {
+ archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated ZIP file header");
+ return (ARCHIVE_FATAL);
+ }
+ archive_string_ensure(&zip->pathname, zip->filename_length);
+ archive_strncpy(&zip->pathname, h, zip->filename_length);
+ (a->compression_read_consume)(a, zip->filename_length);
+ archive_entry_set_pathname(entry, zip->pathname.s);
+
+ if (zip->pathname.s[archive_strlen(&zip->pathname) - 1] == '/')
+ zip->mode = S_IFDIR | 0777;
+ else
+ zip->mode = S_IFREG | 0777;
+
+ /* Read the extra data. */
+ bytes_read = (a->compression_read_ahead)(a, &h, zip->extra_length);
+ if (bytes_read < zip->extra_length) {
+ archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated ZIP file header");
+ return (ARCHIVE_FATAL);
+ }
+ process_extra(h, zip);
+ (a->compression_read_consume)(a, zip->extra_length);
+
+ /* Populate some additional entry fields: */
+ memset(&st, 0, sizeof(st));
+ st.st_mode = zip->mode;
+ st.st_uid = zip->uid;
+ st.st_gid = zip->gid;
+ st.st_mtime = zip->mtime;
+ st.st_ctime = zip->ctime;
+ st.st_atime = zip->atime;
+ st.st_size = zip->uncompressed_size;
+ archive_entry_copy_stat(entry, &st);
+
+ zip->entry_bytes_remaining = zip->compressed_size;
+ zip->entry_offset = 0;
+
+ /* Set up a more descriptive format name. */
+ sprintf(zip->format_name, "ZIP %d.%d (%s)",
+ zip->version / 10, zip->version % 10,
+ zip->compression_name);
+ a->archive_format_name = zip->format_name;
+
+ return (ARCHIVE_OK);
+}
+
+/* Convert an MSDOS-style date/time into Unix-style time. */
+static time_t
+zip_time(const char *p)
+{
+ int msTime, msDate;
+ struct tm ts;
+
+ msTime = (0xff & (unsigned)p[0]) + 256 * (0xff & (unsigned)p[1]);
+ msDate = (0xff & (unsigned)p[2]) + 256 * (0xff & (unsigned)p[3]);
+
+ memset(&ts, 0, sizeof(ts));
+ ts.tm_year = ((msDate >> 9) & 0x7f) + 80; /* Years since 1900. */
+ ts.tm_mon = ((msDate >> 5) & 0x0f) - 1; /* Month number. */
+ ts.tm_mday = msDate & 0x1f; /* Day of month. */
+ ts.tm_hour = (msTime >> 11) & 0x1f;
+ ts.tm_min = (msTime >> 5) & 0x3f;
+ ts.tm_sec = (msTime << 1) & 0x3e;
+ ts.tm_isdst = -1;
+ return mktime(&ts);
+}
+
+static int
+archive_read_format_zip_read_data(struct archive *a,
+ const void **buff, size_t *size, off_t *offset)
+{
+ int r;
+ struct zip *zip;
+
+ zip = *(a->pformat_data);
+
+ /*
+ * If we hit end-of-entry last time, clean up and return
+ * ARCHIVE_EOF this time.
+ */
+ if (zip->end_of_entry) {
+ if (!zip->end_of_entry_cleanup) {
+ if (zip->flags & ZIP_LENGTH_AT_END) {
+ const void *h;
+ const char *p;
+ int bytes_read =
+ (a->compression_read_ahead)(a, &h, 16);
+ if (bytes_read < 16) {
+ archive_set_error(a,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated ZIP end-of-file record");
+ return (ARCHIVE_FATAL);
+ }
+ p = h;
+ zip->crc32 = i4(p + 4);
+ zip->compressed_size = u4(p + 8);
+ zip->uncompressed_size = u4(p + 12);
+ bytes_read = (a->compression_read_consume)(a, 16);
+ }
+
+ /* Check file size, CRC against these values. */
+ if (zip->compressed_size != zip->entry_compressed_bytes_read) {
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "ZIP compressed data is wrong size");
+ return (ARCHIVE_WARN);
+ }
+ if (zip->uncompressed_size != zip->entry_uncompressed_bytes_read) {
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "ZIP uncompressed data is wrong size");
+ return (ARCHIVE_WARN);
+ }
+/* TODO: Compute CRC. */
+/*
+ if (zip->crc32 != zip->entry_crc32_calculated) {
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "ZIP data CRC error");
+ return (ARCHIVE_WARN);
+ }
+*/
+ /* End-of-entry cleanup done. */
+ zip->end_of_entry_cleanup = 1;
+ }
+ return (ARCHIVE_EOF);
+ }
+
+ switch(zip->compression) {
+ case 0: /* No compression. */
+ r = zip_read_data_none(a, buff, size, offset);
+ break;
+ case 8: /* Deflate compression. */
+ r = zip_read_data_deflate(a, buff, size, offset);
+ break;
+ default: /* Unsupported compression. */
+ *buff = NULL;
+ *size = 0;
+ *offset = 0;
+ /* Return a warning. */
+ archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Unsupported ZIP compression method (%s)",
+ zip->compression_name);
+ if (zip->flags & ZIP_LENGTH_AT_END) {
+ /*
+ * ZIP_LENGTH_AT_END requires us to
+ * decompress the entry in order to
+ * skip it, but we don't know this
+ * compression method, so we give up.
+ */
+ r = ARCHIVE_FATAL;
+ } else {
+ /* We know compressed size; just skip it. */
+ archive_read_format_zip_read_data_skip(a);
+ r = ARCHIVE_WARN;
+ }
+ break;
+ }
+ return (r);
+}
+
+/*
+ * Read "uncompressed" data. According to the current specification,
+ * if ZIP_LENGTH_AT_END is specified, then the size fields in the
+ * initial file header are supposed to be set to zero. This would, of
+ * course, make it impossible for us to read the archive, since we
+ * couldn't determine the end of the file data. Info-ZIP seems to
+ * include the real size fields both before and after the data in this
+ * case (the CRC only appears afterwards), so this works as you would
+ * expect.
+ *
+ * Returns ARCHIVE_OK if successful, ARCHIVE_FATAL otherwise, sets
+ * zip->end_of_entry if it consumes all of the data.
+ */
+static int
+zip_read_data_none(struct archive *a, const void **buff,
+ size_t *size, off_t *offset)
+{
+ struct zip *zip;
+ ssize_t bytes_avail;
+
+ zip = *(a->pformat_data);
+
+ if (zip->entry_bytes_remaining == 0) {
+ *buff = NULL;
+ *size = 0;
+ *offset = zip->entry_offset;
+ zip->end_of_entry = 1;
+ return (ARCHIVE_OK);
+ }
+ /*
+ * Note: '1' here is a performance optimization.
+ * Recall that the decompression layer returns a count of
+ * available bytes; asking for more than that forces the
+ * decompressor to combine reads by copying data.
+ */
+ bytes_avail = (a->compression_read_ahead)(a, buff, 1);
+ if (bytes_avail <= 0) {
+ archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated ZIP file data");
+ return (ARCHIVE_FATAL);
+ }
+ if (bytes_avail > zip->entry_bytes_remaining)
+ bytes_avail = zip->entry_bytes_remaining;
+ (a->compression_read_consume)(a, bytes_avail);
+ *size = bytes_avail;
+ *offset = zip->entry_offset;
+ zip->entry_offset += *size;
+ zip->entry_bytes_remaining -= *size;
+ zip->entry_uncompressed_bytes_read += *size;
+ zip->entry_compressed_bytes_read += *size;
+ return (ARCHIVE_OK);
+}
+
+#ifdef HAVE_ZLIB_H
+static int
+zip_read_data_deflate(struct archive *a, const void **buff,
+ size_t *size, off_t *offset)
+{
+ struct zip *zip;
+ ssize_t bytes_avail;
+ const void *compressed_buff;
+ int r;
+
+ zip = *(a->pformat_data);
+
+ /* If the buffer hasn't been allocated, allocate it now. */
+ if (zip->uncompressed_buffer == NULL) {
+ zip->uncompressed_buffer_size = 32 * 1024;
+ zip->uncompressed_buffer
+ = malloc(zip->uncompressed_buffer_size);
+ if (zip->uncompressed_buffer == NULL) {
+ archive_set_error(a, ENOMEM,
+ "No memory for ZIP decompression");
+ return (ARCHIVE_FATAL);
+ }
+ }
+
+ /* If we haven't yet read any data, initialize the decompressor. */
+ if (!zip->decompress_init) {
+ r = inflateInit2(&zip->stream,
+ -15 /* Don't check for zlib header */);
+ if (r != Z_OK) {
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "Can't initialize ZIP decompression.");
+ return (ARCHIVE_FATAL);
+ }
+ zip->decompress_init = 1;
+ }
+
+ /*
+ * Note: '1' here is a performance optimization.
+ * Recall that the decompression layer returns a count of
+ * available bytes; asking for more than that forces the
+ * decompressor to combine reads by copying data.
+ */
+ bytes_avail = (a->compression_read_ahead)(a, &compressed_buff, 1);
+ if (bytes_avail <= 0) {
+ archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated ZIP file body");
+ return (ARCHIVE_FATAL);
+ }
+
+ /*
+ * A bug in zlib.h: stream.next_in should be marked 'const'
+ * but isn't (the library never alters data through the
+ * next_in pointer, only reads it). The result: this ugly
+ * cast to remove 'const'.
+ */
+ zip->stream.next_in = (void *)(uintptr_t)(const void *)compressed_buff;
+ zip->stream.avail_in = bytes_avail;
+ zip->stream.total_in = 0;
+ zip->stream.next_out = zip->uncompressed_buffer;
+ zip->stream.avail_out = zip->uncompressed_buffer_size;
+ zip->stream.total_out = 0;
+
+ r = inflate(&zip->stream, 0);
+ switch (r) {
+ case Z_OK:
+ break;
+ case Z_STREAM_END:
+ zip->end_of_entry = 1;
+ break;
+ case Z_MEM_ERROR:
+ archive_set_error(a, ENOMEM,
+ "Out of memory for ZIP decompression");
+ return (ARCHIVE_FATAL);
+ default:
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "ZIP decompression failed (%d)", r);
+ return (ARCHIVE_FATAL);
+ }
+
+ /* Consume as much as the compressor actually used. */
+ bytes_avail = zip->stream.total_in;
+ (a->compression_read_consume)(a, bytes_avail);
+ zip->entry_bytes_remaining -= bytes_avail;
+ zip->entry_compressed_bytes_read += bytes_avail;
+
+ *offset = zip->entry_offset;
+ *size = zip->stream.total_out;
+ zip->entry_uncompressed_bytes_read += *size;
+ *buff = zip->uncompressed_buffer;
+ zip->entry_offset += *size;
+ return (ARCHIVE_OK);
+}
+#else
+static int
+zip_read_data_deflate(struct archive *a, const void **buff,
+ size_t *size, off_t *offset)
+{
+ int r;
+
+ *buff = NULL;
+ *size = 0;
+ *offset = 0;
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "libarchive compiled without deflate support (no libz)");
+ return (ARCHIVE_FATAL);
+}
+#endif
+
+static int
+archive_read_format_zip_read_data_skip(struct archive *a)
+{
+ struct zip *zip;
+ const void *buff = NULL;
+ ssize_t bytes_avail;
+
+ zip = *(a->pformat_data);
+
+ /*
+ * If the length is at the end, we have no choice but
+ * to decompress all the data to find the end marker.
+ */
+ if (zip->flags & ZIP_LENGTH_AT_END) {
+ size_t size;
+ off_t offset;
+ int r;
+ do {
+ r = archive_read_format_zip_read_data(a, &buff,
+ &size, &offset);
+ } while (r == ARCHIVE_OK);
+ return (r);
+ }
+
+ /*
+ * If the length is at the beginning, we can skip the
+ * compressed data much more quickly.
+ */
+ while (zip->entry_bytes_remaining > 0) {
+ bytes_avail = (a->compression_read_ahead)(a, &buff, 1);
+ if (bytes_avail <= 0) {
+ archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated ZIP file body");
+ return (ARCHIVE_FATAL);
+ }
+ if (bytes_avail > zip->entry_bytes_remaining)
+ bytes_avail = zip->entry_bytes_remaining;
+ (a->compression_read_consume)(a, bytes_avail);
+ zip->entry_bytes_remaining -= bytes_avail;
+ }
+ /* This entry is finished and done. */
+ zip->end_of_entry_cleanup = zip->end_of_entry = 1;
+ return (ARCHIVE_OK);
+}
+
+static int
+archive_read_format_zip_cleanup(struct archive *a)
+{
+ struct zip *zip;
+
+ zip = *(a->pformat_data);
+ if (zip->uncompressed_buffer != NULL)
+ free(zip->uncompressed_buffer);
+ archive_string_free(&(zip->pathname));
+ archive_string_free(&(zip->extra));
+ free(zip);
+ *(a->pformat_data) = NULL;
+ return (ARCHIVE_OK);
+}
+
+static int
+i2(const char *p)
+{
+ return ((0xff & (int)p[0]) + 256 * (0xff & (int)p[1]));
+}
+
+
+static int
+i4(const char *p)
+{
+ return ((0xffff & i2(p)) + 0x10000 * (0xffff & i2(p+2)));
+}
+
+static unsigned int
+u2(const char *p)
+{
+ return ((0xff & (unsigned int)p[0]) + 256 * (0xff & (unsigned int)p[1]));
+}
+
+static unsigned int
+u4(const char *p)
+{
+ return u2(p) + 0x10000 * u2(p+2);
+}
+
+static uint64_t
+u8(const char *p)
+{
+ return u4(p) + 0x100000000LL * u4(p+4);
+}
+
+/*
+ * The extra data is stored as a list of
+ * id1+size1+data1 + id2+size2+data2 ...
+ * triplets. id and size are 2 bytes each.
+ */
+static void
+process_extra(const void* extra, struct zip* zip)
+{
+ int offset = 0;
+ const char *p = extra;
+ while (offset < zip->extra_length - 4)
+ {
+ unsigned short headerid = u2(p + offset);
+ unsigned short datasize = u2(p + offset + 2);
+ offset += 4;
+ if (offset + datasize > zip->extra_length)
+ break;
+#ifdef DEBUG
+ fprintf(stderr, "Header id 0x%04x, length %d\n",
+ headerid, datasize);
+#endif
+ switch (headerid) {
+ case 0x0001:
+ /* Zip64 extended information extra field. */
+ if (datasize >= 8)
+ zip->uncompressed_size = u8(p + offset);
+ if (datasize >= 16)
+ zip->compressed_size = u8(p + offset + 8);
+ break;
+ case 0x5455:
+ {
+ /* Extended time field "UT". */
+ int flags = p[offset];
+ offset++;
+ datasize--;
+ /* Flag bits indicate which dates are present. */
+ if (flags & 0x01)
+ {
+#ifdef DEBUG
+ fprintf(stderr, "mtime: %d -> %d\n",
+ zip->mtime, i4(p + offset));
+#endif
+ if (datasize < 4)
+ break;
+ zip->mtime = i4(p + offset);
+ offset += 4;
+ datasize -= 4;
+ }
+ if (flags & 0x02)
+ {
+ if (datasize < 4)
+ break;
+ zip->atime = i4(p + offset);
+ offset += 4;
+ datasize -= 4;
+ }
+ if (flags & 0x04)
+ {
+ if (datasize < 4)
+ break;
+ zip->ctime = i4(p + offset);
+ offset += 4;
+ datasize -= 4;
+ }
+ break;
+ }
+ case 0x7855:
+ /* Info-ZIP Unix Extra Field (type 2) "Ux". */
+#ifdef DEBUG
+ fprintf(stderr, "uid %d gid %d\n",
+ i2(p + offset), i2(p + offset + 2));
+#endif
+ if (datasize >= 2)
+ zip->uid = i2(p + offset);
+ if (datasize >= 4)
+ zip->gid = i2(p + offset + 2);
+ break;
+ default:
+ break;
+ }
+ offset += datasize;
+ }
+#ifdef DEBUG
+ if (offset != zip->extra_length)
+ {
+ fprintf(stderr,
+ "Extra data field contents do not match reported size!");
+ }
+#endif
+}
diff --git a/lib/libarchive/archive_string.c b/lib/libarchive/archive_string.c
new file mode 100644
index 0000000..b18f31d
--- /dev/null
+++ b/lib/libarchive/archive_string.c
@@ -0,0 +1,113 @@
+/*-
+ * Copyright (c) 2003-2004 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(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 AUTHOR(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 "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+/*
+ * Basic resizable string support, to simplify manipulating arbitrary-sized
+ * strings while minimizing heap activity.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "archive_private.h"
+#include "archive_string.h"
+
+struct archive_string *
+__archive_string_append(struct archive_string *as, const char *p, size_t s)
+{
+ __archive_string_ensure(as, as->length + s + 1);
+ memcpy(as->s + as->length, p, s);
+ as->s[as->length + s] = 0;
+ as->length += s;
+ return (as);
+}
+
+void
+__archive_string_free(struct archive_string *as)
+{
+ as->length = 0;
+ as->buffer_length = 0;
+ if (as->s != NULL)
+ free(as->s);
+}
+
+struct archive_string *
+__archive_string_ensure(struct archive_string *as, size_t s)
+{
+ if (as->s && (s <= as->buffer_length))
+ return (as);
+
+ if (as->buffer_length < 32)
+ as->buffer_length = 32;
+ while (as->buffer_length < s)
+ as->buffer_length *= 2;
+ as->s = realloc(as->s, as->buffer_length);
+ /* TODO: Return null instead and fix up all of our callers to
+ * handle this correctly. */
+ if (as->s == NULL)
+ __archive_errx(1, "Out of memory");
+ return (as);
+}
+
+struct archive_string *
+__archive_strncat(struct archive_string *as, const char *p, size_t n)
+{
+ size_t s;
+ const char *pp;
+
+ /* Like strlen(p), except won't examine positions beyond p[n]. */
+ s = 0;
+ pp = p;
+ while (*pp && s < n) {
+ pp++;
+ s++;
+ }
+ return (__archive_string_append(as, p, s));
+}
+
+struct archive_string *
+__archive_strappend_char(struct archive_string *as, char c)
+{
+ return (__archive_string_append(as, &c, 1));
+}
+
+struct archive_string *
+__archive_strappend_int(struct archive_string *as, int d, int base)
+{
+ static const char *digits = "0123457890abcdef";
+
+ if (d < 0) {
+ __archive_strappend_char(as, '-');
+ d = -d;
+ }
+ if (d >= base)
+ __archive_strappend_int(as, d/base, base);
+ __archive_strappend_char(as, digits[d % base]);
+ return (as);
+}
diff --git a/lib/libarchive/archive_string.h b/lib/libarchive/archive_string.h
new file mode 100644
index 0000000..c9d1c00
--- /dev/null
+++ b/lib/libarchive/archive_string.h
@@ -0,0 +1,112 @@
+/*-
+ * Copyright (c) 2003-2004 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(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 AUTHOR(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$
+ *
+ */
+
+#ifndef ARCHIVE_STRING_H_INCLUDED
+#define ARCHIVE_STRING_H_INCLUDED
+
+#include <stdarg.h>
+#include <string.h>
+
+/*
+ * Basic resizable/reusable string support a la Java's "StringBuffer."
+ *
+ * Unlike sbuf(9), the buffers here are fully reusable and track the
+ * length throughout.
+ *
+ * Note that all visible symbols here begin with "__archive" as they
+ * are internal symbols not intended for anyone outside of this library
+ * to see or use.
+ */
+
+struct archive_string {
+ char *s; /* Pointer to the storage */
+ size_t length; /* Length of 's' */
+ size_t buffer_length; /* Length of malloc-ed storage */
+};
+
+/* Initialize an archive_string object on the stack or elsewhere. */
+#define archive_string_init(a) \
+ do { (a)->s = NULL; (a)->length = 0; (a)->buffer_length = 0; } while(0)
+
+/* Append a C char to an archive_string, resizing as necessary. */
+struct archive_string *
+__archive_strappend_char(struct archive_string *, char);
+#define archive_strappend_char __archive_strappend_char
+
+/* Append a char to an archive_string using UTF8. */
+struct archive_string *
+__archive_strappend_char_UTF8(struct archive_string *, int);
+#define archive_strappend_char_UTF8 __archive_strappend_char_UTF8
+
+/* Append an integer in the specified base (2 <= base <= 16). */
+struct archive_string *
+__archive_strappend_int(struct archive_string *as, int d, int base);
+#define archive_strappend_int __archive_strappend_int
+
+/* Basic append operation. */
+struct archive_string *
+__archive_string_append(struct archive_string *as, const char *p, size_t s);
+
+/* Ensure that the underlying buffer is at least as large as the request. */
+struct archive_string *
+__archive_string_ensure(struct archive_string *, size_t);
+#define archive_string_ensure __archive_string_ensure
+
+/* Append C string, which may lack trailing \0. */
+struct archive_string *
+__archive_strncat(struct archive_string *, const char *, size_t);
+#define archive_strncat __archive_strncat
+
+/* Append a C string to an archive_string, resizing as necessary. */
+#define archive_strcat(as,p) __archive_string_append((as),(p),strlen(p))
+
+/* Copy a C string to an archive_string, resizing as necessary. */
+#define archive_strcpy(as,p) \
+ ((as)->length = 0, __archive_string_append((as), (p), strlen(p)))
+
+/* Copy a C string to an archive_string with limit, resizing as necessary. */
+#define archive_strncpy(as,p,l) \
+ ((as)->length=0, archive_strncat((as), (p), (l)))
+
+/* Return length of string. */
+#define archive_strlen(a) ((a)->length)
+
+/* Set string length to zero. */
+#define archive_string_empty(a) ((a)->length = 0)
+
+/* Release any allocated storage resources. */
+void __archive_string_free(struct archive_string *);
+#define archive_string_free __archive_string_free
+
+/* Like 'vsprintf', but resizes the underlying string as necessary. */
+void __archive_string_vsprintf(struct archive_string *, const char *,
+ va_list);
+#define archive_string_vsprintf __archive_string_vsprintf
+
+#endif
diff --git a/lib/libarchive/archive_string_sprintf.c b/lib/libarchive/archive_string_sprintf.c
new file mode 100644
index 0000000..64ca7d0
--- /dev/null
+++ b/lib/libarchive/archive_string_sprintf.c
@@ -0,0 +1,129 @@
+/*-
+ * Copyright (c) 2003-2004 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(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 AUTHOR(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 "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+/*
+ * The use of printf()-family functions can be troublesome
+ * for space-constrained applications. In addition, correctly
+ * implementing this function in terms of vsnprintf() requires
+ * two calls (one to determine the size, another to format the
+ * result), which in turn requires duplicating the argument list
+ * using va_copy, which isn't yet universally available.
+ *
+ * So, I've implemented a bare minimum of printf()-like capability
+ * here. This is only used to format error messages, so doesn't
+ * require any floating-point support or field-width handling.
+ */
+
+#include <stdio.h>
+
+#include "archive_string.h"
+
+/*
+ * Like 'vsprintf', but ensures the target is big enough, resizing if
+ * necessary.
+ */
+void
+__archive_string_vsprintf(struct archive_string *as, const char *fmt,
+ va_list ap)
+{
+ char long_flag;
+ intmax_t s; /* Signed integer temp. */
+ uintmax_t u; /* Unsigned integer temp. */
+ const char *p, *p2;
+
+ __archive_string_ensure(as, 64);
+
+ if (fmt == NULL) {
+ as->s[0] = 0;
+ return;
+ }
+
+ long_flag = '\0';
+ for (p = fmt; *p != '\0'; p++) {
+ const char *saved_p = p;
+
+ if (*p != '%') {
+ archive_strappend_char(as, *p);
+ continue;
+ }
+
+ p++;
+
+ switch(*p) {
+ case 'j':
+ long_flag = 'j';
+ p++;
+ break;
+ case 'l':
+ long_flag = 'l';
+ p++;
+ break;
+ }
+
+ switch (*p) {
+ case '%':
+ __archive_strappend_char(as, '%');
+ break;
+ case 'c':
+ s = va_arg(ap, int);
+ __archive_strappend_char(as, s);
+ break;
+ case 'd':
+ switch(long_flag) {
+ case 'j': s = va_arg(ap, intmax_t); break;
+ case 'l': s = va_arg(ap, long); break;
+ default: s = va_arg(ap, int); break;
+ }
+ archive_strappend_int(as, s, 10);
+ break;
+ case 's':
+ p2 = va_arg(ap, char *);
+ archive_strcat(as, p2);
+ break;
+ case 'o': case 'u': case 'x': case 'X':
+ /* Common handling for unsigned integer formats. */
+ switch(long_flag) {
+ case 'j': u = va_arg(ap, uintmax_t); break;
+ case 'l': u = va_arg(ap, unsigned long); break;
+ default: u = va_arg(ap, unsigned int); break;
+ }
+ /* Format it in the correct base. */
+ switch (*p) {
+ case 'o': archive_strappend_int(as, u, 8); break;
+ case 'u': archive_strappend_int(as, u, 10); break;
+ default: archive_strappend_int(as, u, 16); break;
+ }
+ break;
+ default:
+ /* Rewind and print the initial '%' literally. */
+ p = saved_p;
+ archive_strappend_char(as, *p);
+ }
+ }
+}
diff --git a/lib/libarchive/archive_util.3 b/lib/libarchive/archive_util.3
new file mode 100644
index 0000000..4646ac9
--- /dev/null
+++ b/lib/libarchive/archive_util.3
@@ -0,0 +1,135 @@
+.\" Copyright (c) 2003-2004 Tim Kientzle
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING 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, 2005
+.Dt archive_util 3
+.Os
+.Sh NAME
+.Nm archive_compression ,
+.Nm archive_compression_name ,
+.Nm archive_errno ,
+.Nm archive_error_string ,
+.Nm archive_format ,
+.Nm archive_format_name ,
+.Nm archive_set_error
+.Nd libarchive utility functions
+.Sh SYNOPSIS
+.In archive.h
+.Ft int
+.Fn archive_compression "struct archive *"
+.Ft const char *
+.Fn archive_compression_name "struct archive *"
+.Ft int
+.Fn archive_errno "struct archive *"
+.Ft const char *
+.Fn archive_error_string "struct archive *"
+.Ft int
+.Fn archive_format "struct archive *"
+.Ft const char *
+.Fn archive_format_name "struct archive *"
+.Ft void
+.Fn archive_set_error "struct archive *" "int error_code" "const char *fmt" "..."
+.Sh DESCRIPTION
+These functions provide access to various information about the
+.Tn struct archive
+object used in the
+.Xr libarchive 3
+library.
+.Bl -tag -compact -width indent
+.It Fn archive_compression
+Returns a numeric code indicating the current compression.
+This value is set by
+.Fn archive_read_open .
+.It Fn archive_compression_name
+Returns a text description of the current compression suitable for display.
+.It Fn archive_errno
+Returns a numeric error code (see
+.Xr errno 2 )
+indicating the reason for the most recent error return.
+.It Fn archive_error_string
+Returns a textual error message suitable for display.
+The error message here is usually more specific than that
+obtained from passing the result of
+.Fn archive_errno
+to
+.Xr strerror 3 .
+.It Fn archive_format
+Returns a numeric code indicating the format of the current
+archive entry.
+This value is set by a successful call to
+.Fn archive_read_next_header .
+Note that it is common for this value to change from
+entry to entry.
+For example, a tar archive might have several entries that
+utilize GNU tar extensions and several entries that do not.
+These entries will have different format codes.
+.It Fn archive_format_name
+A textual description of the format of the current entry.
+.It Fn archive_set_error
+Sets the numeric error code and error description that will be returned
+by
+.Fn archive_errno
+and
+.Fn archive_error_string .
+This function should be used within I/O callbacks to set system-specific
+error codes and error descriptions.
+This function accepts a printf-like format string and arguments.
+However, you should be careful to use only the following printf
+format specifiers:
+.Dq %c ,
+.Dq %d ,
+.Dq %jd ,
+.Dq %jo ,
+.Dq %ju ,
+.Dq %jx ,
+.Dq %ld ,
+.Dq %lo ,
+.Dq %lu ,
+.Dq %lx ,
+.Dq %o ,
+.Dq %u ,
+.Dq %s ,
+.Dq %x ,
+.Dq %% .
+Field-width specifiers and other printf features are
+not uniformly supported and should not be used.
+.El
+.Sh SEE ALSO
+.Xr archive_read 3 ,
+.Xr archive_write 3 ,
+.Xr libarchive 3 ,
+.Xr printf 3
+.Sh HISTORY
+The
+.Nm libarchive
+library first appeared in
+.Fx 5.3 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm libarchive
+library was written by
+.An Tim Kientzle Aq kientzle@acm.org .
diff --git a/lib/libarchive/archive_util.c b/lib/libarchive/archive_util.c
new file mode 100644
index 0000000..1567234
--- /dev/null
+++ b/lib/libarchive/archive_util.c
@@ -0,0 +1,161 @@
+/*-
+ * Copyright (c) 2003-2004 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(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 AUTHOR(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 "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "archive.h"
+#include "archive_private.h"
+
+int
+archive_api_feature(void)
+{
+ return (ARCHIVE_API_FEATURE);
+}
+
+int
+archive_api_version(void)
+{
+ return (ARCHIVE_API_VERSION);
+}
+
+const char *
+archive_version(void)
+{
+ return (PACKAGE_NAME " " PACKAGE_VERSION);
+}
+
+int
+archive_errno(struct archive *a)
+{
+ return (a->archive_error_number);
+}
+
+const char *
+archive_error_string(struct archive *a)
+{
+
+ if (a->error != NULL && *a->error != '\0')
+ return (a->error);
+ else
+ return ("(Empty error message)");
+}
+
+
+int
+archive_format(struct archive *a)
+{
+ return (a->archive_format);
+}
+
+const char *
+archive_format_name(struct archive *a)
+{
+ return (a->archive_format_name);
+}
+
+
+int
+archive_compression(struct archive *a)
+{
+ return (a->compression_code);
+}
+
+const char *
+archive_compression_name(struct archive *a)
+{
+ return (a->compression_name);
+}
+
+
+/*
+ * Return a count of the number of compressed bytes processed.
+ */
+int64_t
+archive_position_compressed(struct archive *a)
+{
+ return (a->raw_position);
+}
+
+/*
+ * Return a count of the number of uncompressed bytes processed.
+ */
+int64_t
+archive_position_uncompressed(struct archive *a)
+{
+ return (a->file_position);
+}
+
+
+void
+archive_set_error(struct archive *a, int error_number, const char *fmt, ...)
+{
+ va_list ap;
+#ifdef HAVE_STRERROR_R
+ char errbuff[512];
+#endif
+ char *errp;
+
+ a->archive_error_number = error_number;
+ if (fmt == NULL) {
+ a->error = NULL;
+ return;
+ }
+
+ va_start(ap, fmt);
+ archive_string_vsprintf(&(a->error_string), fmt, ap);
+ if (error_number > 0) {
+ archive_strcat(&(a->error_string), ": ");
+#ifdef HAVE_STRERROR_R
+#ifdef STRERROR_R_CHAR_P
+ errp = strerror_r(error_number, errbuff, sizeof(errbuff));
+#else
+ strerror_r(error_number, errbuff, sizeof(errbuff));
+ errp = errbuff;
+#endif
+#else
+ /* Note: this is not threadsafe! */
+ errp = strerror(error_number);
+#endif
+ archive_strcat(&(a->error_string), errp);
+ }
+ a->error = a->error_string.s;
+ va_end(ap);
+}
+
+void
+__archive_errx(int retvalue, const char *msg)
+{
+ static const char *msg1 = "Fatal Internal Error in libarchive: ";
+ write(2, msg1, strlen(msg1));
+ write(2, msg, strlen(msg));
+ write(2, "\n", 1);
+ exit(retvalue);
+}
diff --git a/lib/libarchive/archive_write.3 b/lib/libarchive/archive_write.3
new file mode 100644
index 0000000..f32bfcb
--- /dev/null
+++ b/lib/libarchive/archive_write.3
@@ -0,0 +1,433 @@
+.\" Copyright (c) 2003-2005 Tim Kientzle
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING 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, 2005
+.Dt archive_write 3
+.Os
+.Sh NAME
+.Nm archive_write_new ,
+.Nm archive_write_set_format_cpio ,
+.Nm archive_write_set_format_pax ,
+.Nm archive_write_set_format_pax_restricted ,
+.Nm archive_write_set_format_shar ,
+.Nm archive_write_set_format_shar_binary ,
+.Nm archive_write_set_format_ustar ,
+.Nm archive_write_set_bytes_per_block ,
+.Nm archive_write_set_bytes_in_last_block ,
+.Nm archive_write_set_compressor_gzip ,
+.Nm archive_write_set_compressor_bzip2 ,
+.Nm archive_write_open ,
+.Nm archive_write_open_fd ,
+.Nm archive_write_open_file ,
+.Nm archive_write_prepare ,
+.Nm archive_write_header ,
+.Nm archive_write_data ,
+.Nm archive_write_close ,
+.Nm archive_write_finish
+.Nd functions for creating archives
+.Sh SYNOPSIS
+.In archive.h
+.Ft struct archive *
+.Fn archive_write_new "void"
+.Ft int
+.Fn archive_write_set_bytes_per_block "struct archive *" "int bytes_per_block"
+.Ft int
+.Fn archive_write_set_bytes_in_last_block "struct archive *" "int"
+.Ft int
+.Fn archive_write_set_compressor_gzip "struct archive *"
+.Ft int
+.Fn archive_write_set_compressor_bzip2 "struct archive *"
+.Ft int
+.Fn archive_write_set_format_cpio "struct archive *"
+.Ft int
+.Fn archive_write_set_format_pax "struct archive *"
+.Ft int
+.Fn archive_write_set_format_pax_restricted "struct archive *"
+.Ft int
+.Fn archive_write_set_format_shar "struct archive *"
+.Ft int
+.Fn archive_write_set_format_shar_binary "struct archive *"
+.Ft int
+.Fn archive_write_set_format_ustar "struct archive *"
+.Ft int
+.Fn archive_write_open "struct archive *" "void *client_data" "archive_open_callback *" "archive_write_callback *" "archive_close_callback *"
+.Ft int
+.Fn archive_write_open_fd "struct archive *" "int fd"
+.Ft int
+.Fn archive_write_open_file "struct archive *" "const char *filename"
+.Ft int
+.Fn archive_write_header "struct archive *" "struct archive_entry *"
+.Ft int
+.Fn archive_write_data "struct archive *" "const void *" "size_t"
+.Ft int
+.Fn archive_write_close "struct archive *"
+.Ft void
+.Fn archive_write_finish "struct archive *"
+.Sh DESCRIPTION
+These functions provide a complete API for creating streaming
+archive files.
+The general process is to first create the
+.Tn struct archive
+object, set any desired options, initialize the archive, append entries, then
+close the archive and release all resources.
+The following summary describes the functions in approximately
+the order they are ordinarily used:
+.Bl -tag -width indent
+.It Fn archive_write_new
+Allocates and initializes a
+.Tn struct archive
+object suitable for writing a tar archive.
+.It Fn archive_write_set_bytes_per_block
+Sets the block size used for writing the archive data.
+Every call to the write callback function, except possibly the last one, will
+use this value for the length.
+The third parameter is a boolean that specifies whether or not the final block
+written will be padded to the full block size.
+If it is zero, the last block will not be padded.
+If it is non-zero, padding will be added both before and after compression.
+The default is to use a block size of 10240 bytes and to pad the last block.
+.It Fn archive_write_set_bytes_in_last_block
+Sets the block size used for writing the last block.
+If this value is zero, the last block will be padded to the same size
+as the other blocks.
+Otherwise, the final block will be padded to a multiple of this size.
+In particular, setting it to 1 will cause the final block to not be padded.
+For compressed output, any padding generated by this option
+is applied only after the compression.
+The uncompressed data is always unpadded.
+The default is to pad the last block to the full block size (note that
+.Fn archive_write_open_file
+will set this based on the file type).
+Unlike the other
+.Dq set
+functions, this function can be called after the archive is opened.
+.It Fn archive_write_set_format_cpio , Fn archive_write_set_format_pax , Fn archive_write_set_format_pax_restricted , Fn archive_write_set_format_shar , Fn archive_write_set_format_shar_binary , Fn archive_write_set_format_ustar
+Sets the format that will be used for the archive.
+The library can write
+POSIX octet-oriented cpio format archives,
+POSIX-standard
+.Dq pax interchange
+format archives,
+traditional
+.Dq shar
+archives,
+enhanced
+.Dq binary
+shar archives that store a variety of file attributes and handle binary files,
+and
+POSIX-standard
+.Dq ustar
+archives.
+The pax interchange format is a backwards-compatible tar format that
+adds key/value attributes to each entry and supports arbitrary
+filenames, linknames, uids, sizes, etc.
+.Dq Restricted pax interchange format
+is the library default; this is the same as pax format, but suppresses
+the pax extended header for most normal files.
+In most cases, this will result in ordinary ustar archives.
+.It Fn archive_write_set_compression_gzip , Fn archive_write_set_compression_bzip2
+The resulting archive will be compressed as specified.
+Note that the compressed output is always properly blocked.
+.It Fn archive_write_open
+Freeze the settings, open the archive, and prepare for writing entries.
+This is the most generic form of this function, which accepts
+pointers to three callback functions which will be invoked by
+the compression layer to write the constructed archive.
+In order to support external compression programs, the compression
+is permitted to fork and invoke the callbacks from a separate process.
+In particular, clients should not assume that they can communicate
+between the callbacks and the mainline code using shared variables.
+(The standard gzip, bzip2, and "none" compression methods do not fork.)
+.It Fn archive_write_open_fd
+A convenience form of
+.Fn archive_write_open
+that accepts a file descriptor.
+.It Fn archive_write_open_file
+A convenience form of
+.Fn archive_write_open
+that accepts a filename.
+A NULL argument indicates that the output should be written to standard output;
+an argument of
+.Dq -
+will open a file with that name.
+If you have not invoked
+.Fn archive_write_set_bytes_in_last_block ,
+then
+.Fn archive_write_open_file
+will adjust the last-block padding depending on the file:
+it will enable padding when writing to standard output or
+to a character or block device node, it will disable padding otherwise.
+You can override this by manually invoking
+.Fn archive_write_set_bytes_in_last_block
+either before or after calling
+.Fn archive_write_open .
+.It Fn archive_write_header
+Build and write a header using the data in the provided
+.Tn struct archive_entry
+structure.
+.It Fn archive_write_data
+Write data corresponding to the header just written.
+Returns number of bytes written or -1 on error.
+.It Fn archive_write_close
+Complete the archive and invoke the close callback.
+.It Fn archive_write_finish
+Invokes
+.Fn archive_write_close
+if it was not invoked manually, then release all resources.
+.El
+More information about the
+.Va struct archive
+object and the overall design of the library can be found in the
+.Xr libarchive 3
+overview.
+.Sh IMPLEMENTATION
+Compression support is built-in to libarchive, which uses zlib and bzlib
+to handle gzip and bzip2 compression, respectively.
+.Sh CLIENT CALLBACKS
+To use this library, you will need to define and register
+callback functions that will be invoked to write data to the
+resulting archive.
+These functions are registered by calling
+.Fn archive_write_open :
+.Bl -item -offset indent
+.It
+.Ft typedef int
+.Fn archive_open_callback "struct archive *" "void *client_data"
+.El
+.Pp
+The open callback is invoked by
+.Fn archive_write_open .
+It should return
+.Cm ARCHIVE_OK
+if the underlying file or data source is successfully
+opened.
+If the open fails, it should call
+.Fn archive_set_error
+to register an error code and message and return
+.Cm ARCHIVE_FATAL .
+.Bl -item -offset indent
+.It
+.Ft typedef ssize_t
+.Fn archive_write_callback "struct archive *" "void *client_data" "void *buffer" "size_t length"
+.El
+.Pp
+The write callback is invoked whenever the library
+needs to write raw bytes to the archive.
+For correct blocking, each call to the write callback function
+should translate into a single
+.Xr write 2
+system call.
+This is especially critical when writing archives to tape drives.
+On success, the write callback should return the
+number of bytes actually written.
+On error, the callback should invoke
+.Fn archive_set_error
+to register an error code and message and return -1.
+.Bl -item -offset indent
+.It
+.Ft typedef int
+.Fn archive_close_callback "struct archive *" "void *client_data"
+.El
+.Pp
+The close callback is invoked by archive_close when
+the archive processing is complete.
+The callback should return
+.Cm ARCHIVE_OK
+on success.
+On failure, the callback should invoke
+.Fn archive_set_error
+to register an error code and message and
+regurn
+.Cm ARCHIVE_FATAL.
+.Sh EXAMPLE
+The following sketch illustrates basic usage of the library.
+In this example,
+the callback functions are simply wrappers around the standard
+.Xr open 2 ,
+.Xr write 2 ,
+and
+.Xr close 2
+system calls.
+.Bd -literal -offset indent
+#include <sys/stat.h>
+#include <archive.h>
+#include <archive_entry.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+struct mydata {
+ const char *name;
+ int fd;
+};
+
+int
+myopen(struct archive *a, void *client_data)
+{
+ struct mydata *mydata = client_data;
+
+ mydata->fd = open(mydata->name, O_WRONLY | O_CREAT, 0644);
+ if (mydata->fd >= 0)
+ return (ARCHIVE_OK);
+ else
+ return (ARCHIVE_FATAL);
+}
+
+ssize_t
+mywrite(struct archive *a, void *client_data, void *buff, size_t n)
+{
+ struct mydata *mydata = client_data;
+
+ return (write(mydata->fd, buff, n));
+}
+
+int
+myclose(struct archive *a, void *client_data)
+{
+ struct mydata *mydata = client_data;
+
+ if (mydata->fd > 0)
+ close(mydata->fd);
+ return (0);
+}
+
+void
+write_archive(const char *outname, const char **filename)
+{
+ struct mydata *mydata = malloc(sizeof(struct mydata));
+ struct archive *a;
+ struct archive_entry *entry;
+ struct stat st;
+ char buff[8192];
+ int len;
+ int fd;
+
+ a = archive_write_new();
+ mydata->name = outname;
+ archive_write_set_compression_gzip(a);
+ archive_write_set_format_ustar(a);
+ archive_write_open(a, mydata, myopen, mywrite, myclose);
+ while (*filename) {
+ stat(*filename, &st);
+ entry = archive_entry_new();
+ archive_entry_copy_stat(entry, &st);
+ archive_entry_set_pathname(entry, *filename);
+ archive_write_header(a, entry);
+ fd = open(*filename, O_RDONLY);
+ len = read(fd, buff, sizeof(buff));
+ while ( len > 0 ) {
+ archive_write_data(a, buff, len);
+ len = read(fd, buff, sizeof(buff));
+ }
+ archive_entry_free(entry);
+ filename++;
+ }
+ archive_write_finish(a);
+}
+
+int main(int argc, const char **argv)
+{
+ const char *outname;
+ argv++;
+ outname = argv++;
+ write_archive(outname, argv);
+ return 0;
+}
+.Ed
+.Sh RETURN VALUES
+Most functions return zero on success, non-zero on error.
+The
+.Fn archive_errno
+and
+.Fn archive_error_string
+functions can be used to retrieve an appropriate error code and a
+textual error message.
+.Pp
+.Fn archive_write_new
+returns a pointer to a newly-allocated
+.Tn struct archive
+object.
+.Pp
+.Fn archive_write_data
+returns a count of the number of bytes actually written.
+On error, -1 is returned and the
+.Fn archive_errno
+and
+.Fn archive_error_string
+functions will return appropriate values.
+Note that if the client-provided write callback function
+returns a non-zero value, that error will be propagated back to the caller
+through whatever API function resulted in that call, which
+may include
+.Fn archive_write_header ,
+.Fn archive_write_data ,
+or
+.Fn archive_write_close .
+The client callback can call
+.Fn archive_set_error
+to provide values that can then be retrieved by
+.Fn archive_errno
+and
+.Fn archive_error_string .
+.Sh SEE ALSO
+.Xr tar 1 ,
+.Xr libarchive 3 ,
+.Xr tar 5
+.Sh HISTORY
+The
+.Nm libarchive
+library first appeared in
+.Fx 5.3 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm libarchive
+library was written by
+.An Tim Kientzle Aq kientzle@acm.org .
+.Sh BUGS
+There are many peculiar bugs in historic tar implementations that may cause
+certain programs to reject archives written by this library.
+For example, several historic implementations calculated header checksums
+incorrectly and will thus reject valid archives; GNU tar does not fully support
+pax interchange format; some old tar implementations required specific
+field terminations.
+.Pp
+The default pax interchange format eliminates most of the historic
+tar limitations and provides a generic key/value attribute facility
+for vendor-defined extensions.
+One oversight in POSIX is the failure to provide a standard attribute
+for large device numbers.
+This library uses
+.Dq SCHILY.devminor
+and
+.Dq SCHILY.devmajor
+for device numbers that exceed the range supported by the backwards-compatible
+ustar header.
+These keys are compatible with Joerg Schilling's
+.Nm star
+archiver.
+Other implementations may not recognize these keys and will thus be unable
+to correctly restore large device numbers archived by this library.
diff --git a/lib/libarchive/archive_write.c b/lib/libarchive/archive_write.c
new file mode 100644
index 0000000..73283e4
--- /dev/null
+++ b/lib/libarchive/archive_write.c
@@ -0,0 +1,229 @@
+/*-
+ * Copyright (c) 2003-2004 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(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 AUTHOR(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 "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+/*
+ * This file contains the "essential" portions of the write API, that
+ * is, stuff that will essentially always be used by any client that
+ * actually needs to write a archive. Optional pieces have been, as
+ * far as possible, separated out into separate files to reduce
+ * needlessly bloating statically-linked clients.
+ */
+
+#include <sys/wait.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "archive.h"
+#include "archive_entry.h"
+#include "archive_private.h"
+
+extern char **environ;
+
+/*
+ * Allocate, initialize and return an archive object.
+ */
+struct archive *
+archive_write_new(void)
+{
+ struct archive *a;
+ unsigned char *nulls;
+
+ a = malloc(sizeof(*a));
+ if (a == NULL)
+ return (NULL);
+ memset(a, 0, sizeof(*a));
+ a->magic = ARCHIVE_WRITE_MAGIC;
+ a->user_uid = geteuid();
+ a->bytes_per_block = ARCHIVE_DEFAULT_BYTES_PER_BLOCK;
+ a->bytes_in_last_block = -1; /* Default */
+ a->state = ARCHIVE_STATE_NEW;
+ a->pformat_data = &(a->format_data);
+
+ /* Initialize a block of nulls for padding purposes. */
+ a->null_length = 1024;
+ nulls = malloc(a->null_length);
+ if (nulls == NULL) {
+ free(a);
+ return (NULL);
+ }
+ memset(nulls, 0, a->null_length);
+ a->nulls = nulls;
+ /*
+ * Set default compression, but don't set a default format.
+ * Were we to set a default format here, we would force every
+ * client to link in support for that format, even if they didn't
+ * ever use it.
+ */
+ archive_write_set_compression_none(a);
+ return (a);
+}
+
+
+/*
+ * Set the block size. Returns 0 if successful.
+ */
+int
+archive_write_set_bytes_per_block(struct archive *a, int bytes_per_block)
+{
+ __archive_check_magic(a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW, "archive_write_set_bytes_per_block");
+ a->bytes_per_block = bytes_per_block;
+ return (ARCHIVE_OK);
+}
+
+
+/*
+ * Set the size for the last block.
+ * Returns 0 if successful.
+ */
+int
+archive_write_set_bytes_in_last_block(struct archive *a, int bytes)
+{
+ __archive_check_magic(a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_ANY, "archive_write_set_bytes_in_last_block");
+ a->bytes_in_last_block = bytes;
+ return (ARCHIVE_OK);
+}
+
+
+/*
+ * Open the archive using the current settings.
+ */
+int
+archive_write_open(struct archive *a, void *client_data,
+ archive_open_callback *opener, archive_write_callback *writer,
+ archive_close_callback *closer)
+{
+ int ret;
+
+ ret = ARCHIVE_OK;
+ __archive_check_magic(a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW, "archive_write_open");
+ archive_string_empty(&a->error_string);
+ a->state = ARCHIVE_STATE_HEADER;
+ a->client_data = client_data;
+ a->client_writer = writer;
+ a->client_opener = opener;
+ a->client_closer = closer;
+ ret = (a->compression_init)(a);
+ if (a->format_init && ret == ARCHIVE_OK)
+ ret = (a->format_init)(a);
+ return (ret);
+}
+
+
+/*
+ * Close out the archive.
+ *
+ * Be careful: user might just call write_new and then write_finish.
+ * Don't assume we actually wrote anything or performed any non-trivial
+ * initialization.
+ */
+int
+archive_write_close(struct archive *a)
+{
+ __archive_check_magic(a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_ANY, "archive_write_close");
+
+ /* Finish the last entry. */
+ if (a->state & ARCHIVE_STATE_DATA)
+ ((a->format_finish_entry)(a));
+
+ /* Finish off the archive. */
+ if (a->format_finish != NULL)
+ (a->format_finish)(a);
+
+ /* Finish the compression and close the stream. */
+ if (a->compression_finish != NULL)
+ (a->compression_finish)(a);
+
+ a->state = ARCHIVE_STATE_CLOSED;
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Destroy the archive structure.
+ */
+void
+archive_write_finish(struct archive *a)
+{
+ __archive_check_magic(a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_ANY, "archive_write_finish");
+ if (a->state != ARCHIVE_STATE_CLOSED)
+ archive_write_close(a);
+
+ /* Release various dynamic buffers. */
+ free((void *)(uintptr_t)(const void *)a->nulls);
+ archive_string_free(&a->error_string);
+ a->magic = 0;
+ free(a);
+}
+
+
+/*
+ * Write the appropriate header.
+ */
+int
+archive_write_header(struct archive *a, struct archive_entry *entry)
+{
+ int ret;
+
+ __archive_check_magic(a, ARCHIVE_WRITE_MAGIC,
+ ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, "archive_write_header");
+ archive_string_empty(&a->error_string);
+
+ /* Finish last entry. */
+ if (a->state & ARCHIVE_STATE_DATA)
+ ((a->format_finish_entry)(a));
+
+ if (archive_entry_dev(entry) == a->skip_file_dev &&
+ archive_entry_ino(entry) == a->skip_file_ino) {
+ archive_set_error(a, 0, "Can't add archive to itself");
+ return (ARCHIVE_WARN);
+ }
+
+ /* Format and write header. */
+ ret = ((a->format_write_header)(a, entry));
+
+ a->state = ARCHIVE_STATE_DATA;
+ return (ret);
+}
+
+/*
+ * Note that the compressor is responsible for blocking.
+ */
+/* Should be "ssize_t", but that breaks the ABI. <sigh> */
+int
+archive_write_data(struct archive *a, const void *buff, size_t s)
+{
+ int ret;
+ __archive_check_magic(a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_DATA, "archive_write_data");
+ archive_string_empty(&a->error_string);
+ ret = (a->format_write_data)(a, buff, s);
+ return (ret == ARCHIVE_OK ? (ssize_t)s : -1);
+}
diff --git a/lib/libarchive/archive_write_open_fd.c b/lib/libarchive/archive_write_open_fd.c
new file mode 100644
index 0000000..58bfbd3
--- /dev/null
+++ b/lib/libarchive/archive_write_open_fd.c
@@ -0,0 +1,133 @@
+/*-
+ * Copyright (c) 2003-2004 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(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 AUTHOR(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 "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#include <sys/stat.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "archive.h"
+#include "archive_private.h"
+
+struct write_fd_data {
+ off_t offset;
+ int fd;
+};
+
+static int file_close(struct archive *, void *);
+static int file_open(struct archive *, void *);
+static ssize_t file_write(struct archive *, void *, void *buff, size_t);
+
+int
+archive_write_open_fd(struct archive *a, int fd)
+{
+ struct write_fd_data *mine;
+
+ mine = malloc(sizeof(*mine));
+ if (mine == NULL) {
+ archive_set_error(a, ENOMEM, "No memory");
+ return (ARCHIVE_FATAL);
+ }
+ mine->fd = fd;
+ return (archive_write_open(a, mine,
+ file_open, file_write, file_close));
+}
+
+static int
+file_open(struct archive *a, void *client_data)
+{
+ struct write_fd_data *mine;
+ struct stat st, *pst;
+
+ pst = NULL;
+ mine = client_data;
+
+ /*
+ * If client hasn't explicitly set the last block handling,
+ * then set it here: If the output is a block or character
+ * device, pad the last block, otherwise leave it unpadded.
+ */
+ if (mine->fd >= 0 && a->bytes_in_last_block < 0) {
+ /* Last block will be fully padded. */
+ if (fstat(mine->fd, &st) == 0) {
+ pst = &st;
+ if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode) ||
+ S_ISFIFO(st.st_mode))
+ archive_write_set_bytes_in_last_block(a, 0);
+ else
+ archive_write_set_bytes_in_last_block(a, 1);
+ }
+ }
+
+ if (mine->fd == 1) {
+ if (a->bytes_in_last_block < 0) /* Still default? */
+ /* Last block will be fully padded. */
+ archive_write_set_bytes_in_last_block(a, 0);
+ }
+
+ if (mine->fd < 0) {
+ archive_set_error(a, errno, "Failed to open");
+ return (ARCHIVE_FATAL);
+ }
+
+ if (pst == NULL && fstat(mine->fd, &st) == 0)
+ pst = &st;
+ if (pst == NULL) {
+ archive_set_error(a, errno, "Couldn't stat fd %d", mine->fd);
+ return (ARCHIVE_FATAL);
+ }
+
+ return (ARCHIVE_OK);
+}
+
+static ssize_t
+file_write(struct archive *a, void *client_data, void *buff, size_t length)
+{
+ struct write_fd_data *mine;
+ ssize_t bytesWritten;
+
+ mine = client_data;
+ bytesWritten = write(mine->fd, buff, length);
+ if (bytesWritten <= 0) {
+ archive_set_error(a, errno, "Write error");
+ return (-1);
+ }
+ return (bytesWritten);
+}
+
+static int
+file_close(struct archive *a, void *client_data)
+{
+ struct write_fd_data *mine = client_data;
+
+ (void)a; /* UNUSED */
+ free(mine);
+ return (ARCHIVE_OK);
+}
diff --git a/lib/libarchive/archive_write_open_file.c b/lib/libarchive/archive_write_open_file.c
new file mode 100644
index 0000000..65cdbb6
--- /dev/null
+++ b/lib/libarchive/archive_write_open_file.c
@@ -0,0 +1,166 @@
+/*-
+ * Copyright (c) 2003-2004 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(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 AUTHOR(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 "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#include <sys/stat.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "archive.h"
+#include "archive_private.h"
+
+struct write_file_data {
+ int fd;
+ char filename[1];
+};
+
+static int file_close(struct archive *, void *);
+static int file_open(struct archive *, void *);
+static ssize_t file_write(struct archive *, void *, void *buff, size_t);
+
+int
+archive_write_open_file(struct archive *a, const char *filename)
+{
+ struct write_file_data *mine;
+
+ if (filename == NULL || filename[0] == '\0') {
+ mine = malloc(sizeof(*mine));
+ if (mine == NULL) {
+ archive_set_error(a, ENOMEM, "No memory");
+ return (ARCHIVE_FATAL);
+ }
+ mine->filename[0] = '\0'; /* Record that we're using stdout. */
+ } else {
+ mine = malloc(sizeof(*mine) + strlen(filename));
+ if (mine == NULL) {
+ archive_set_error(a, ENOMEM, "No memory");
+ return (ARCHIVE_FATAL);
+ }
+ strcpy(mine->filename, filename);
+ }
+ mine->fd = -1;
+ return (archive_write_open(a, mine,
+ file_open, file_write, file_close));
+}
+
+static int
+file_open(struct archive *a, void *client_data)
+{
+ int flags;
+ struct write_file_data *mine;
+ struct stat st, *pst;
+
+ pst = NULL;
+ mine = client_data;
+ flags = O_WRONLY | O_CREAT | O_TRUNC;
+
+ if (mine->filename[0] != '\0') {
+ mine->fd = open(mine->filename, flags, 0666);
+
+ /*
+ * If client hasn't explicitly set the last block
+ * handling, then set it here: If the output is a
+ * block or character device, pad the last block,
+ * otherwise leave it unpadded.
+ */
+ if (mine->fd >= 0 && a->bytes_in_last_block < 0) {
+ if (fstat(mine->fd, &st) == 0) {
+ pst = &st;
+ if (S_ISCHR(st.st_mode) ||
+ S_ISBLK(st.st_mode) ||
+ S_ISFIFO(st.st_mode))
+ /* Pad last block. */
+ archive_write_set_bytes_in_last_block(a, 0);
+ else
+ /* Don't pad last block. */
+ archive_write_set_bytes_in_last_block(a, 1);
+ }
+ }
+ } else {
+ mine->fd = 1;
+ if (a->bytes_in_last_block < 0) /* Still default? */
+ /* Last block will be fully padded. */
+ archive_write_set_bytes_in_last_block(a, 0);
+ }
+
+ if (mine->fd < 0) {
+ archive_set_error(a, errno, "Failed to open '%s'",
+ mine->filename);
+ return (ARCHIVE_FATAL);
+ }
+
+ if (pst == NULL && fstat(mine->fd, &st) == 0)
+ pst = &st;
+ if (pst == NULL) {
+ archive_set_error(a, errno, "Couldn't stat '%s'",
+ mine->filename);
+ return (ARCHIVE_FATAL);
+ }
+
+ /*
+ * If the output file is a regular file, don't add it to
+ * itself. If it's a device file, it's okay to add the device
+ * entry to the output archive.
+ */
+ if (S_ISREG(pst->st_mode)) {
+ a->skip_file_dev = pst->st_dev;
+ a->skip_file_ino = pst->st_ino;
+ }
+
+ return (ARCHIVE_OK);
+}
+
+static ssize_t
+file_write(struct archive *a, void *client_data, void *buff, size_t length)
+{
+ struct write_file_data *mine;
+ ssize_t bytesWritten;
+
+ mine = client_data;
+ bytesWritten = write(mine->fd, buff, length);
+ if (bytesWritten <= 0) {
+ archive_set_error(a, errno, "Write error");
+ return (-1);
+ }
+ return (bytesWritten);
+}
+
+static int
+file_close(struct archive *a, void *client_data)
+{
+ struct write_file_data *mine = client_data;
+
+ (void)a; /* UNUSED */
+ if (mine->filename[0] != '\0')
+ close(mine->fd);
+ free(mine);
+ return (ARCHIVE_OK);
+}
diff --git a/lib/libarchive/archive_write_open_filename.c b/lib/libarchive/archive_write_open_filename.c
new file mode 100644
index 0000000..65cdbb6
--- /dev/null
+++ b/lib/libarchive/archive_write_open_filename.c
@@ -0,0 +1,166 @@
+/*-
+ * Copyright (c) 2003-2004 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(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 AUTHOR(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 "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#include <sys/stat.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "archive.h"
+#include "archive_private.h"
+
+struct write_file_data {
+ int fd;
+ char filename[1];
+};
+
+static int file_close(struct archive *, void *);
+static int file_open(struct archive *, void *);
+static ssize_t file_write(struct archive *, void *, void *buff, size_t);
+
+int
+archive_write_open_file(struct archive *a, const char *filename)
+{
+ struct write_file_data *mine;
+
+ if (filename == NULL || filename[0] == '\0') {
+ mine = malloc(sizeof(*mine));
+ if (mine == NULL) {
+ archive_set_error(a, ENOMEM, "No memory");
+ return (ARCHIVE_FATAL);
+ }
+ mine->filename[0] = '\0'; /* Record that we're using stdout. */
+ } else {
+ mine = malloc(sizeof(*mine) + strlen(filename));
+ if (mine == NULL) {
+ archive_set_error(a, ENOMEM, "No memory");
+ return (ARCHIVE_FATAL);
+ }
+ strcpy(mine->filename, filename);
+ }
+ mine->fd = -1;
+ return (archive_write_open(a, mine,
+ file_open, file_write, file_close));
+}
+
+static int
+file_open(struct archive *a, void *client_data)
+{
+ int flags;
+ struct write_file_data *mine;
+ struct stat st, *pst;
+
+ pst = NULL;
+ mine = client_data;
+ flags = O_WRONLY | O_CREAT | O_TRUNC;
+
+ if (mine->filename[0] != '\0') {
+ mine->fd = open(mine->filename, flags, 0666);
+
+ /*
+ * If client hasn't explicitly set the last block
+ * handling, then set it here: If the output is a
+ * block or character device, pad the last block,
+ * otherwise leave it unpadded.
+ */
+ if (mine->fd >= 0 && a->bytes_in_last_block < 0) {
+ if (fstat(mine->fd, &st) == 0) {
+ pst = &st;
+ if (S_ISCHR(st.st_mode) ||
+ S_ISBLK(st.st_mode) ||
+ S_ISFIFO(st.st_mode))
+ /* Pad last block. */
+ archive_write_set_bytes_in_last_block(a, 0);
+ else
+ /* Don't pad last block. */
+ archive_write_set_bytes_in_last_block(a, 1);
+ }
+ }
+ } else {
+ mine->fd = 1;
+ if (a->bytes_in_last_block < 0) /* Still default? */
+ /* Last block will be fully padded. */
+ archive_write_set_bytes_in_last_block(a, 0);
+ }
+
+ if (mine->fd < 0) {
+ archive_set_error(a, errno, "Failed to open '%s'",
+ mine->filename);
+ return (ARCHIVE_FATAL);
+ }
+
+ if (pst == NULL && fstat(mine->fd, &st) == 0)
+ pst = &st;
+ if (pst == NULL) {
+ archive_set_error(a, errno, "Couldn't stat '%s'",
+ mine->filename);
+ return (ARCHIVE_FATAL);
+ }
+
+ /*
+ * If the output file is a regular file, don't add it to
+ * itself. If it's a device file, it's okay to add the device
+ * entry to the output archive.
+ */
+ if (S_ISREG(pst->st_mode)) {
+ a->skip_file_dev = pst->st_dev;
+ a->skip_file_ino = pst->st_ino;
+ }
+
+ return (ARCHIVE_OK);
+}
+
+static ssize_t
+file_write(struct archive *a, void *client_data, void *buff, size_t length)
+{
+ struct write_file_data *mine;
+ ssize_t bytesWritten;
+
+ mine = client_data;
+ bytesWritten = write(mine->fd, buff, length);
+ if (bytesWritten <= 0) {
+ archive_set_error(a, errno, "Write error");
+ return (-1);
+ }
+ return (bytesWritten);
+}
+
+static int
+file_close(struct archive *a, void *client_data)
+{
+ struct write_file_data *mine = client_data;
+
+ (void)a; /* UNUSED */
+ if (mine->filename[0] != '\0')
+ close(mine->fd);
+ free(mine);
+ return (ARCHIVE_OK);
+}
diff --git a/lib/libarchive/archive_write_set_compression_bzip2.c b/lib/libarchive/archive_write_set_compression_bzip2.c
new file mode 100644
index 0000000..429cc15
--- /dev/null
+++ b/lib/libarchive/archive_write_set_compression_bzip2.c
@@ -0,0 +1,343 @@
+/*-
+ * Copyright (c) 2003-2004 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(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 AUTHOR(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 "archive_platform.h"
+
+/* Don't compile this if we don't have bzlib. */
+#if HAVE_BZLIB_H
+
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <bzlib.h>
+
+#include "archive.h"
+#include "archive_private.h"
+
+struct private_data {
+ bz_stream stream;
+ int64_t total_in;
+ char *compressed;
+ size_t compressed_buffer_size;
+};
+
+
+/*
+ * Yuck. bzlib.h is not const-correct, so I need this one bit
+ * of ugly hackery to convert a const * pointer to a non-const pointer.
+ */
+#define SET_NEXT_IN(st,src) \
+ (st)->stream.next_in = (void *)(uintptr_t)(const void *)(src)
+
+static int archive_compressor_bzip2_finish(struct archive *);
+static int archive_compressor_bzip2_init(struct archive *);
+static int archive_compressor_bzip2_write(struct archive *, const void *,
+ size_t);
+static int drive_compressor(struct archive *, struct private_data *,
+ int finishing);
+
+/*
+ * Allocate, initialize and return an archive object.
+ */
+int
+archive_write_set_compression_bzip2(struct archive *a)
+{
+ __archive_check_magic(a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW, "archive_write_set_compression_bzip2");
+ a->compression_init = &archive_compressor_bzip2_init;
+ a->compression_code = ARCHIVE_COMPRESSION_BZIP2;
+ a->compression_name = "bzip2";
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Setup callback.
+ */
+static int
+archive_compressor_bzip2_init(struct archive *a)
+{
+ int ret;
+ struct private_data *state;
+
+ a->compression_code = ARCHIVE_COMPRESSION_BZIP2;
+ a->compression_name = "bzip2";
+
+ if (a->client_opener != NULL) {
+ ret = (a->client_opener)(a, a->client_data);
+ if (ret != 0)
+ return (ret);
+ }
+
+ state = malloc(sizeof(*state));
+ if (state == NULL) {
+ archive_set_error(a, ENOMEM,
+ "Can't allocate data for compression");
+ return (ARCHIVE_FATAL);
+ }
+ memset(state, 0, sizeof(*state));
+
+ state->compressed_buffer_size = a->bytes_per_block;
+ state->compressed = malloc(state->compressed_buffer_size);
+
+ if (state->compressed == NULL) {
+ archive_set_error(a, ENOMEM,
+ "Can't allocate data for compression buffer");
+ free(state);
+ return (ARCHIVE_FATAL);
+ }
+
+ state->stream.next_out = state->compressed;
+ state->stream.avail_out = state->compressed_buffer_size;
+ a->compression_write = archive_compressor_bzip2_write;
+ a->compression_finish = archive_compressor_bzip2_finish;
+
+ /* Initialize compression library */
+ ret = BZ2_bzCompressInit(&(state->stream), 9, 0, 30);
+ if (ret == BZ_OK) {
+ a->compression_data = state;
+ return (ARCHIVE_OK);
+ }
+
+ /* Library setup failed: clean up. */
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "Internal error initializing compression library");
+ free(state->compressed);
+ free(state);
+
+ /* Override the error message if we know what really went wrong. */
+ switch (ret) {
+ case BZ_PARAM_ERROR:
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "Internal error initializing compression library: "
+ "invalid setup parameter");
+ break;
+ case BZ_MEM_ERROR:
+ archive_set_error(a, ENOMEM,
+ "Internal error initializing compression library: "
+ "out of memory");
+ break;
+ case BZ_CONFIG_ERROR:
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "Internal error initializing compression library: "
+ "mis-compiled library");
+ break;
+ }
+
+ return (ARCHIVE_FATAL);
+
+}
+
+/*
+ * Write data to the compressed stream.
+ *
+ * Returns ARCHIVE_OK if all data written, error otherwise.
+ */
+static int
+archive_compressor_bzip2_write(struct archive *a, const void *buff,
+ size_t length)
+{
+ struct private_data *state;
+
+ state = a->compression_data;
+ if (a->client_writer == NULL) {
+ archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER,
+ "No write callback is registered? "
+ "This is probably an internal programming error.");
+ return (ARCHIVE_FATAL);
+ }
+
+ /* Update statistics */
+ state->total_in += length;
+
+ /* Compress input data to output buffer */
+ SET_NEXT_IN(state, buff);
+ state->stream.avail_in = length;
+ if (drive_compressor(a, state, 0))
+ return (ARCHIVE_FATAL);
+ a->file_position += length;
+ return (ARCHIVE_OK);
+}
+
+
+/*
+ * Finish the compression.
+ */
+static int
+archive_compressor_bzip2_finish(struct archive *a)
+{
+ ssize_t block_length;
+ int ret;
+ struct private_data *state;
+ ssize_t target_block_length;
+ ssize_t bytes_written;
+ unsigned tocopy;
+
+ state = a->compression_data;
+ ret = ARCHIVE_OK;
+ if (a->client_writer == NULL) {
+ archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER,
+ "No write callback is registered?\n"
+ "This is probably an internal programming error.");
+ ret = ARCHIVE_FATAL;
+ goto cleanup;
+ }
+
+ /* By default, always pad the uncompressed data. */
+ if (a->pad_uncompressed) {
+ tocopy = a->bytes_per_block -
+ (state->total_in % a->bytes_per_block);
+ while (tocopy > 0 && tocopy < (unsigned)a->bytes_per_block) {
+ SET_NEXT_IN(state, a->nulls);
+ state->stream.avail_in = tocopy < a->null_length ?
+ tocopy : a->null_length;
+ state->total_in += state->stream.avail_in;
+ tocopy -= state->stream.avail_in;
+ ret = drive_compressor(a, state, 0);
+ if (ret != ARCHIVE_OK)
+ goto cleanup;
+ }
+ }
+
+ /* Finish compression cycle. */
+ if ((ret = drive_compressor(a, state, 1)))
+ goto cleanup;
+
+ /* Optionally, pad the final compressed block. */
+ block_length = state->stream.next_out - state->compressed;
+
+
+ /* Tricky calculation to determine size of last block. */
+ target_block_length = block_length;
+ if (a->bytes_in_last_block <= 0)
+ /* Default or Zero: pad to full block */
+ target_block_length = a->bytes_per_block;
+ else
+ /* Round length to next multiple of bytes_in_last_block. */
+ target_block_length = a->bytes_in_last_block *
+ ( (block_length + a->bytes_in_last_block - 1) /
+ a->bytes_in_last_block);
+ if (target_block_length > a->bytes_per_block)
+ target_block_length = a->bytes_per_block;
+ if (block_length < target_block_length) {
+ memset(state->stream.next_out, 0,
+ target_block_length - block_length);
+ block_length = target_block_length;
+ }
+
+ /* Write the last block */
+ bytes_written = (a->client_writer)(a, a->client_data,
+ state->compressed, block_length);
+
+ /* TODO: Handle short write of final block. */
+ if (bytes_written <= 0)
+ ret = ARCHIVE_FATAL;
+ else {
+ a->raw_position += ret;
+ ret = ARCHIVE_OK;
+ }
+
+ /* Cleanup: shut down compressor, release memory, etc. */
+cleanup:
+ switch (BZ2_bzCompressEnd(&(state->stream))) {
+ case BZ_OK:
+ break;
+ default:
+ archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER,
+ "Failed to clean up compressor");
+ ret = ARCHIVE_FATAL;
+ }
+
+ free(state->compressed);
+ free(state);
+
+ /* Close the output */
+ if (a->client_closer != NULL)
+ (a->client_closer)(a, a->client_data);
+
+ return (ret);
+}
+
+/*
+ * Utility function to push input data through compressor, writing
+ * full output blocks as necessary.
+ *
+ * Note that this handles both the regular write case (finishing ==
+ * false) and the end-of-archive case (finishing == true).
+ */
+static int
+drive_compressor(struct archive *a, struct private_data *state, int finishing)
+{
+ ssize_t bytes_written;
+ int ret;
+
+ for (;;) {
+ if (state->stream.avail_out == 0) {
+ bytes_written = (a->client_writer)(a, a->client_data,
+ state->compressed, state->compressed_buffer_size);
+ if (bytes_written <= 0) {
+ /* TODO: Handle this write failure */
+ return (ARCHIVE_FATAL);
+ } else if ((size_t)bytes_written < state->compressed_buffer_size) {
+ /* Short write: Move remainder to
+ * front and keep filling */
+ memmove(state->compressed,
+ state->compressed + bytes_written,
+ state->compressed_buffer_size - bytes_written);
+ }
+
+ a->raw_position += bytes_written;
+ state->stream.next_out = state->compressed +
+ state->compressed_buffer_size - bytes_written;
+ state->stream.avail_out = bytes_written;
+ }
+
+ ret = BZ2_bzCompress(&(state->stream),
+ finishing ? BZ_FINISH : BZ_RUN);
+
+ switch (ret) {
+ case BZ_RUN_OK:
+ /* In non-finishing case, did compressor
+ * consume everything? */
+ if (!finishing && state->stream.avail_in == 0)
+ return (ARCHIVE_OK);
+ break;
+ case BZ_FINISH_OK: /* Finishing: There's more work to do */
+ break;
+ case BZ_STREAM_END: /* Finishing: all done */
+ /* Only occurs in finishing case */
+ return (ARCHIVE_OK);
+ default:
+ /* Any other return value indicates an error */
+ archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER,
+ "Bzip2 compression failed");
+ return (ARCHIVE_FATAL);
+ }
+ }
+}
+
+#endif /* HAVE_BZLIB_H */
diff --git a/lib/libarchive/archive_write_set_compression_gzip.c b/lib/libarchive/archive_write_set_compression_gzip.c
new file mode 100644
index 0000000..3229507
--- /dev/null
+++ b/lib/libarchive/archive_write_set_compression_gzip.c
@@ -0,0 +1,399 @@
+/*-
+ * Copyright (c) 2003-2004 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(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 AUTHOR(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 "archive_platform.h"
+
+/* Don't compile this if we don't have zlib. */
+#if HAVE_ZLIB_H
+
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <zlib.h>
+
+#include "archive.h"
+#include "archive_private.h"
+
+struct private_data {
+ z_stream stream;
+ int64_t total_in;
+ unsigned char *compressed;
+ size_t compressed_buffer_size;
+ unsigned long crc;
+};
+
+
+/*
+ * Yuck. zlib.h is not const-correct, so I need this one bit
+ * of ugly hackery to convert a const * pointer to a non-const pointer.
+ */
+#define SET_NEXT_IN(st,src) \
+ (st)->stream.next_in = (void *)(uintptr_t)(const void *)(src)
+
+static int archive_compressor_gzip_finish(struct archive *);
+static int archive_compressor_gzip_init(struct archive *);
+static int archive_compressor_gzip_write(struct archive *, const void *,
+ size_t);
+static int drive_compressor(struct archive *, struct private_data *,
+ int finishing);
+
+
+/*
+ * Allocate, initialize and return a archive object.
+ */
+int
+archive_write_set_compression_gzip(struct archive *a)
+{
+ __archive_check_magic(a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW, "archive_write_set_compression_gzip");
+ a->compression_init = &archive_compressor_gzip_init;
+ a->compression_code = ARCHIVE_COMPRESSION_GZIP;
+ a->compression_name = "gzip";
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Setup callback.
+ */
+static int
+archive_compressor_gzip_init(struct archive *a)
+{
+ int ret;
+ struct private_data *state;
+ time_t t;
+
+ a->compression_code = ARCHIVE_COMPRESSION_GZIP;
+ a->compression_name = "gzip";
+
+ if (a->client_opener != NULL) {
+ ret = (a->client_opener)(a, a->client_data);
+ if (ret != ARCHIVE_OK)
+ return (ret);
+ }
+
+ state = (struct private_data *)malloc(sizeof(*state));
+ if (state == NULL) {
+ archive_set_error(a, ENOMEM,
+ "Can't allocate data for compression");
+ return (ARCHIVE_FATAL);
+ }
+ memset(state, 0, sizeof(*state));
+
+ state->compressed_buffer_size = a->bytes_per_block;
+ state->compressed = malloc(state->compressed_buffer_size);
+ state->crc = crc32(0L, NULL, 0);
+
+ if (state->compressed == NULL) {
+ archive_set_error(a, ENOMEM,
+ "Can't allocate data for compression buffer");
+ free(state);
+ return (ARCHIVE_FATAL);
+ }
+
+ state->stream.next_out = state->compressed;
+ state->stream.avail_out = state->compressed_buffer_size;
+
+ /* Prime output buffer with a gzip header. */
+ t = time(NULL);
+ state->compressed[0] = 0x1f; /* GZip signature bytes */
+ state->compressed[1] = 0x8b;
+ state->compressed[2] = 0x08; /* "Deflate" compression */
+ state->compressed[3] = 0; /* No options */
+ state->compressed[4] = (t)&0xff; /* Timestamp */
+ state->compressed[5] = (t>>8)&0xff;
+ state->compressed[6] = (t>>16)&0xff;
+ state->compressed[7] = (t>>24)&0xff;
+ state->compressed[8] = 0; /* No deflate options */
+ state->compressed[9] = 3; /* OS=Unix */
+ state->stream.next_out += 10;
+ state->stream.avail_out -= 10;
+
+ a->compression_write = archive_compressor_gzip_write;
+ a->compression_finish = archive_compressor_gzip_finish;
+
+ /* Initialize compression library. */
+ ret = deflateInit2(&(state->stream),
+ Z_DEFAULT_COMPRESSION,
+ Z_DEFLATED,
+ -15 /* < 0 to suppress zlib header */,
+ 8,
+ Z_DEFAULT_STRATEGY);
+
+ if (ret == Z_OK) {
+ a->compression_data = state;
+ return (0);
+ }
+
+ /* Library setup failed: clean up. */
+ archive_set_error(a, ARCHIVE_ERRNO_MISC, "Internal error "
+ "initializing compression library");
+ free(state->compressed);
+ free(state);
+
+ /* Override the error message if we know what really went wrong. */
+ switch (ret) {
+ case Z_STREAM_ERROR:
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "Internal error initializing "
+ "compression library: invalid setup parameter");
+ break;
+ case Z_MEM_ERROR:
+ archive_set_error(a, ENOMEM, "Internal error initializing "
+ "compression library");
+ break;
+ case Z_VERSION_ERROR:
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "Internal error initializing "
+ "compression library: invalid library version");
+ break;
+ }
+
+ return (ARCHIVE_FATAL);
+}
+
+/*
+ * Write data to the compressed stream.
+ */
+static int
+archive_compressor_gzip_write(struct archive *a, const void *buff,
+ size_t length)
+{
+ struct private_data *state;
+ int ret;
+
+ state = a->compression_data;
+ if (a->client_writer == NULL) {
+ archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER,
+ "No write callback is registered? "
+ "This is probably an internal programming error.");
+ return (ARCHIVE_FATAL);
+ }
+
+ /* Update statistics */
+ state->crc = crc32(state->crc, buff, length);
+ state->total_in += length;
+
+ /* Compress input data to output buffer */
+ SET_NEXT_IN(state, buff);
+ state->stream.avail_in = length;
+ if ((ret = drive_compressor(a, state, 0)) != ARCHIVE_OK)
+ return (ret);
+
+ a->file_position += length;
+ return (ARCHIVE_OK);
+}
+
+
+/*
+ * Finish the compression...
+ */
+static int
+archive_compressor_gzip_finish(struct archive *a)
+{
+ ssize_t block_length, target_block_length, bytes_written;
+ int ret;
+ struct private_data *state;
+ unsigned tocopy;
+ unsigned char trailer[8];
+
+ state = a->compression_data;
+ ret = 0;
+ if (a->client_writer == NULL) {
+ archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER,
+ "No write callback is registered? "
+ "This is probably an internal programming error.");
+ ret = ARCHIVE_FATAL;
+ goto cleanup;
+ }
+
+ /* By default, always pad the uncompressed data. */
+ if (a->pad_uncompressed) {
+ tocopy = a->bytes_per_block -
+ (state->total_in % a->bytes_per_block);
+ while (tocopy > 0 && tocopy < (unsigned)a->bytes_per_block) {
+ SET_NEXT_IN(state, a->nulls);
+ state->stream.avail_in = tocopy < a->null_length ?
+ tocopy : a->null_length;
+ state->crc = crc32(state->crc, a->nulls,
+ state->stream.avail_in);
+ state->total_in += state->stream.avail_in;
+ tocopy -= state->stream.avail_in;
+ ret = drive_compressor(a, state, 0);
+ if (ret != ARCHIVE_OK)
+ goto cleanup;
+ }
+ }
+
+ /* Finish compression cycle */
+ if (((ret = drive_compressor(a, state, 1))) != ARCHIVE_OK)
+ goto cleanup;
+
+ /* Build trailer: 4-byte CRC and 4-byte length. */
+ trailer[0] = (state->crc)&0xff;
+ trailer[1] = (state->crc >> 8)&0xff;
+ trailer[2] = (state->crc >> 16)&0xff;
+ trailer[3] = (state->crc >> 24)&0xff;
+ trailer[4] = (state->total_in)&0xff;
+ trailer[5] = (state->total_in >> 8)&0xff;
+ trailer[6] = (state->total_in >> 16)&0xff;
+ trailer[7] = (state->total_in >> 24)&0xff;
+
+ /* Add trailer to current block. */
+ tocopy = 8;
+ if (tocopy > state->stream.avail_out)
+ tocopy = state->stream.avail_out;
+ memcpy(state->stream.next_out, trailer, tocopy);
+ state->stream.next_out += tocopy;
+ state->stream.avail_out -= tocopy;
+
+ /* If it overflowed, flush and start a new block. */
+ if (tocopy < 8) {
+ bytes_written = (a->client_writer)(a, a->client_data,
+ state->compressed, state->compressed_buffer_size);
+ if (bytes_written <= 0) {
+ ret = ARCHIVE_FATAL;
+ goto cleanup;
+ }
+ a->raw_position += bytes_written;
+ state->stream.next_out = state->compressed;
+ state->stream.avail_out = state->compressed_buffer_size;
+ memcpy(state->stream.next_out, trailer + tocopy, 8-tocopy);
+ state->stream.next_out += 8-tocopy;
+ state->stream.avail_out -= 8-tocopy;
+ }
+
+ /* Optionally, pad the final compressed block. */
+ block_length = state->stream.next_out - state->compressed;
+
+
+ /* Tricky calculation to determine size of last block. */
+ target_block_length = block_length;
+ if (a->bytes_in_last_block <= 0)
+ /* Default or Zero: pad to full block */
+ target_block_length = a->bytes_per_block;
+ else
+ /* Round length to next multiple of bytes_in_last_block. */
+ target_block_length = a->bytes_in_last_block *
+ ( (block_length + a->bytes_in_last_block - 1) /
+ a->bytes_in_last_block);
+ if (target_block_length > a->bytes_per_block)
+ target_block_length = a->bytes_per_block;
+ if (block_length < target_block_length) {
+ memset(state->stream.next_out, 0,
+ target_block_length - block_length);
+ block_length = target_block_length;
+ }
+
+ /* Write the last block */
+ bytes_written = (a->client_writer)(a, a->client_data,
+ state->compressed, block_length);
+ if (bytes_written <= 0) {
+ ret = ARCHIVE_FATAL;
+ goto cleanup;
+ }
+ a->raw_position += bytes_written;
+
+ /* Cleanup: shut down compressor, release memory, etc. */
+cleanup:
+ switch (deflateEnd(&(state->stream))) {
+ case Z_OK:
+ break;
+ default:
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "Failed to clean up compressor");
+ ret = ARCHIVE_FATAL;
+ }
+ free(state->compressed);
+ free(state);
+
+ /* Close the output */
+ if (a->client_closer != NULL)
+ (a->client_closer)(a, a->client_data);
+
+ return (ret);
+}
+
+/*
+ * Utility function to push input data through compressor,
+ * writing full output blocks as necessary.
+ *
+ * Note that this handles both the regular write case (finishing ==
+ * false) and the end-of-archive case (finishing == true).
+ */
+static int
+drive_compressor(struct archive *a, struct private_data *state, int finishing)
+{
+ ssize_t bytes_written;
+ int ret;
+
+ for (;;) {
+ if (state->stream.avail_out == 0) {
+ bytes_written = (a->client_writer)(a, a->client_data,
+ state->compressed, state->compressed_buffer_size);
+ if (bytes_written <= 0) {
+ /* TODO: Handle this write failure */
+ return (ARCHIVE_FATAL);
+ } else if ((size_t)bytes_written < state->compressed_buffer_size) {
+ /* Short write: Move remaining to
+ * front of block and keep filling */
+ memmove(state->compressed,
+ state->compressed + bytes_written,
+ state->compressed_buffer_size - bytes_written);
+ }
+ a->raw_position += bytes_written;
+ state->stream.next_out
+ = state->compressed +
+ state->compressed_buffer_size - bytes_written;
+ state->stream.avail_out = bytes_written;
+ }
+
+ ret = deflate(&(state->stream),
+ finishing ? Z_FINISH : Z_NO_FLUSH );
+
+ switch (ret) {
+ case Z_OK:
+ /* In non-finishing case, check if compressor
+ * consumed everything */
+ if (!finishing && state->stream.avail_in == 0)
+ return (ARCHIVE_OK);
+ /* In finishing case, this return always means
+ * there's more work */
+ break;
+ case Z_STREAM_END:
+ /* This return can only occur in finishing case. */
+ return (ARCHIVE_OK);
+ default:
+ /* Any other return value indicates an error. */
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "GZip compression failed");
+ return (ARCHIVE_FATAL);
+ }
+ }
+}
+
+#endif /* HAVE_ZLIB_H */
diff --git a/lib/libarchive/archive_write_set_compression_none.c b/lib/libarchive/archive_write_set_compression_none.c
new file mode 100644
index 0000000..2a63629
--- /dev/null
+++ b/lib/libarchive/archive_write_set_compression_none.c
@@ -0,0 +1,218 @@
+/*-
+ * Copyright (c) 2003-2004 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(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 AUTHOR(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 "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "archive.h"
+#include "archive_private.h"
+
+static int archive_compressor_none_finish(struct archive *a);
+static int archive_compressor_none_init(struct archive *);
+static int archive_compressor_none_write(struct archive *, const void *,
+ size_t);
+
+struct archive_none {
+ char *buffer;
+ ssize_t buffer_size;
+ char *next; /* Current insert location */
+ ssize_t avail; /* Free space left in buffer */
+};
+
+int
+archive_write_set_compression_none(struct archive *a)
+{
+ __archive_check_magic(a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW, "archive_write_set_compression_none");
+ a->compression_init = &archive_compressor_none_init;
+ a->compression_code = ARCHIVE_COMPRESSION_NONE;
+ a->compression_name = "none";
+ return (0);
+}
+
+/*
+ * Setup callback.
+ */
+static int
+archive_compressor_none_init(struct archive *a)
+{
+ int ret;
+ struct archive_none *state;
+
+ a->compression_code = ARCHIVE_COMPRESSION_NONE;
+ a->compression_name = "none";
+
+ if (a->client_opener != NULL) {
+ ret = (a->client_opener)(a, a->client_data);
+ if (ret != 0)
+ return (ret);
+ }
+
+ state = (struct archive_none *)malloc(sizeof(*state));
+ if (state == NULL) {
+ archive_set_error(a, ENOMEM,
+ "Can't allocate data for output buffering");
+ return (ARCHIVE_FATAL);
+ }
+ memset(state, 0, sizeof(*state));
+
+ state->buffer_size = a->bytes_per_block;
+ state->buffer = malloc(state->buffer_size);
+
+ if (state->buffer == NULL) {
+ archive_set_error(a, ENOMEM,
+ "Can't allocate output buffer");
+ free(state);
+ return (ARCHIVE_FATAL);
+ }
+
+ state->next = state->buffer;
+ state->avail = state->buffer_size;
+
+ a->compression_data = state;
+ a->compression_write = archive_compressor_none_write;
+ a->compression_finish = archive_compressor_none_finish;
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Write data to the stream.
+ */
+static int
+archive_compressor_none_write(struct archive *a, const void *vbuff,
+ size_t length)
+{
+ const char *buff;
+ ssize_t remaining, to_copy;
+ ssize_t bytes_written;
+ struct archive_none *state;
+
+ state = a->compression_data;
+ buff = vbuff;
+ if (a->client_writer == NULL) {
+ archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER,
+ "No write callback is registered? "
+ "This is probably an internal programming error.");
+ return (ARCHIVE_FATAL);
+ }
+
+ remaining = length;
+ while (remaining > 0) {
+ /*
+ * If we have a full output block, write it and reset the
+ * output buffer.
+ */
+ if (state->avail == 0) {
+ bytes_written = (a->client_writer)(a, a->client_data,
+ state->buffer, state->buffer_size);
+ if (bytes_written <= 0)
+ return (ARCHIVE_FATAL);
+ /* XXX TODO: if bytes_written < state->buffer_size */
+ a->raw_position += bytes_written;
+ state->next = state->buffer;
+ state->avail = state->buffer_size;
+ }
+
+ /* Now we have space in the buffer; copy new data into it. */
+ to_copy = (remaining > state->avail) ?
+ state->avail : remaining;
+ memcpy(state->next, buff, to_copy);
+ state->next += to_copy;
+ state->avail -= to_copy;
+ buff += to_copy;
+ remaining -= to_copy;
+ }
+ a->file_position += length;
+ return (ARCHIVE_OK);
+}
+
+
+/*
+ * Finish the compression.
+ */
+static int
+archive_compressor_none_finish(struct archive *a)
+{
+ ssize_t block_length;
+ ssize_t target_block_length;
+ ssize_t bytes_written;
+ int ret;
+ int ret2;
+ struct archive_none *state;
+
+ state = a->compression_data;
+ ret = ret2 = ARCHIVE_OK;
+ if (a->client_writer == NULL) {
+ archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER,
+ "No write callback is registered? "
+ "This is probably an internal programming error.");
+ return (ARCHIVE_FATAL);
+ }
+
+ /* If there's pending data, pad and write the last block */
+ if (state->next != state->buffer) {
+ block_length = state->buffer_size - state->avail;
+
+ /* Tricky calculation to determine size of last block */
+ target_block_length = block_length;
+ if (a->bytes_in_last_block <= 0)
+ /* Default or Zero: pad to full block */
+ target_block_length = a->bytes_per_block;
+ else
+ /* Round to next multiple of bytes_in_last_block. */
+ target_block_length = a->bytes_in_last_block *
+ ( (block_length + a->bytes_in_last_block - 1) /
+ a->bytes_in_last_block);
+ if (target_block_length > a->bytes_per_block)
+ target_block_length = a->bytes_per_block;
+ if (block_length < target_block_length) {
+ memset(state->next, 0,
+ target_block_length - block_length);
+ block_length = target_block_length;
+ }
+ bytes_written = (a->client_writer)(a, a->client_data,
+ state->buffer, block_length);
+ if (bytes_written <= 0)
+ ret = ARCHIVE_FATAL;
+ else {
+ a->raw_position += bytes_written;
+ ret = ARCHIVE_OK;
+ }
+ }
+
+ /* Close the output */
+ if (a->client_closer != NULL)
+ ret2 = (a->client_closer)(a, a->client_data);
+
+ free(state->buffer);
+ free(state);
+ a->compression_data = NULL;
+
+ return (ret != ARCHIVE_OK ? ret : ret2);
+}
diff --git a/lib/libarchive/archive_write_set_format.c b/lib/libarchive/archive_write_set_format.c
new file mode 100644
index 0000000..5f6df0e
--- /dev/null
+++ b/lib/libarchive/archive_write_set_format.c
@@ -0,0 +1,65 @@
+/*-
+ * Copyright (c) 2003-2004 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(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 AUTHOR(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 "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include "archive.h"
+#include "archive_private.h"
+
+/* A table that maps format codes to functions. */
+static
+struct { int code; int (*setter)(struct archive *); } codes[] =
+{
+ { ARCHIVE_FORMAT_CPIO, archive_write_set_format_cpio },
+ { ARCHIVE_FORMAT_CPIO_POSIX, archive_write_set_format_cpio },
+ { ARCHIVE_FORMAT_SHAR, archive_write_set_format_shar },
+ { ARCHIVE_FORMAT_SHAR_BASE, archive_write_set_format_shar },
+ { ARCHIVE_FORMAT_SHAR_DUMP, archive_write_set_format_shar_dump },
+ { ARCHIVE_FORMAT_TAR, archive_write_set_format_pax_restricted },
+ { ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE, archive_write_set_format_pax },
+ { ARCHIVE_FORMAT_TAR_PAX_RESTRICTED,
+ archive_write_set_format_pax_restricted },
+ { ARCHIVE_FORMAT_TAR_USTAR, archive_write_set_format_ustar },
+ { 0, NULL }
+};
+
+int
+archive_write_set_format(struct archive *a, int code)
+{
+ int i;
+
+ for (i = 0; codes[i].code != 0; i++) {
+ if (code == codes[i].code)
+ return ((codes[i].setter)(a));
+ }
+
+ archive_set_error(a, EINVAL, "No such format");
+ return (ARCHIVE_FATAL);
+}
diff --git a/lib/libarchive/archive_write_set_format_by_name.c b/lib/libarchive/archive_write_set_format_by_name.c
new file mode 100644
index 0000000..2402e1c
--- /dev/null
+++ b/lib/libarchive/archive_write_set_format_by_name.c
@@ -0,0 +1,63 @@
+/*-
+ * Copyright (c) 2003-2004 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(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 AUTHOR(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 "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <string.h>
+
+#include "archive.h"
+#include "archive_private.h"
+
+/* A table that maps names to functions. */
+static
+struct { const char *name; int (*setter)(struct archive *); } names[] =
+{
+ { "cpio", archive_write_set_format_cpio },
+ { "pax", archive_write_set_format_pax },
+ { "posix", archive_write_set_format_pax },
+ { "shar", archive_write_set_format_shar },
+ { "shardump", archive_write_set_format_shar_dump },
+ { "ustar", archive_write_set_format_ustar },
+ { NULL, NULL }
+};
+
+int
+archive_write_set_format_by_name(struct archive *a, const char *name)
+{
+ int i;
+
+ for (i = 0; names[i].name != NULL; i++) {
+ if (strcmp(name, names[i].name) == 0)
+ return ((names[i].setter)(a));
+ }
+
+ archive_set_error(a, EINVAL, "No such format '%s'", name);
+ return (ARCHIVE_FATAL);
+}
diff --git a/lib/libarchive/archive_write_set_format_cpio.c b/lib/libarchive/archive_write_set_format_cpio.c
new file mode 100644
index 0000000..659b0a1
--- /dev/null
+++ b/lib/libarchive/archive_write_set_format_cpio.c
@@ -0,0 +1,246 @@
+/*-
+ * Copyright (c) 2003-2004 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(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 AUTHOR(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 "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#include <sys/stat.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "archive.h"
+#include "archive_entry.h"
+#include "archive_private.h"
+
+static int archive_write_cpio_data(struct archive *, const void *buff,
+ size_t s);
+static int archive_write_cpio_finish(struct archive *);
+static int archive_write_cpio_finish_entry(struct archive *);
+static int archive_write_cpio_header(struct archive *,
+ struct archive_entry *);
+static int format_octal(int64_t, void *, int);
+static int64_t format_octal_recursive(int64_t, char *, int);
+
+struct cpio {
+ uint64_t entry_bytes_remaining;
+};
+
+struct cpio_header {
+ char c_magic[6];
+ char c_dev[6];
+ char c_ino[6];
+ char c_mode[6];
+ char c_uid[6];
+ char c_gid[6];
+ char c_nlink[6];
+ char c_rdev[6];
+ char c_mtime[11];
+ char c_namesize[6];
+ char c_filesize[11];
+};
+
+/*
+ * Set output format to 'cpio' format.
+ */
+int
+archive_write_set_format_cpio(struct archive *a)
+{
+ struct cpio *cpio;
+
+ /* If someone else was already registered, unregister them. */
+ if (a->format_finish != NULL)
+ (a->format_finish)(a);
+
+ cpio = malloc(sizeof(*cpio));
+ if (cpio == NULL) {
+ archive_set_error(a, ENOMEM, "Can't allocate cpio data");
+ return (ARCHIVE_FATAL);
+ }
+ memset(cpio, 0, sizeof(*cpio));
+ a->format_data = cpio;
+
+ a->pad_uncompressed = 1;
+ a->format_write_header = archive_write_cpio_header;
+ a->format_write_data = archive_write_cpio_data;
+ a->format_finish_entry = archive_write_cpio_finish_entry;
+ a->format_finish = archive_write_cpio_finish;
+ a->archive_format = ARCHIVE_FORMAT_CPIO_POSIX;
+ a->archive_format_name = "POSIX cpio";
+ return (ARCHIVE_OK);
+}
+
+static int
+archive_write_cpio_header(struct archive *a, struct archive_entry *entry)
+{
+ struct cpio *cpio;
+ const char *p, *path;
+ int pathlength, ret;
+ const struct stat *st;
+ struct cpio_header h;
+
+ cpio = a->format_data;
+ ret = 0;
+
+ path = archive_entry_pathname(entry);
+ pathlength = strlen(path) + 1; /* Include trailing null. */
+ st = archive_entry_stat(entry);
+
+ memset(&h, 0, sizeof(h));
+ format_octal(070707, &h.c_magic, sizeof(h.c_magic));
+ format_octal(st->st_dev, &h.c_dev, sizeof(h.c_dev));
+ /*
+ * TODO: Generate artificial inode numbers rather than just
+ * re-using the ones off the disk. That way, the 18-bit c_ino
+ * field only limits the number of files in the archive.
+ */
+ if (st->st_ino > 0777777) {
+ archive_set_error(a, ERANGE, "large inode number truncated");
+ ret = ARCHIVE_WARN;
+ }
+
+ format_octal(st->st_ino & 0777777, &h.c_ino, sizeof(h.c_ino));
+ format_octal(st->st_mode, &h.c_mode, sizeof(h.c_mode));
+ format_octal(st->st_uid, &h.c_uid, sizeof(h.c_uid));
+ format_octal(st->st_gid, &h.c_gid, sizeof(h.c_gid));
+ format_octal(st->st_nlink, &h.c_nlink, sizeof(h.c_nlink));
+ if (S_ISBLK(st->st_mode) || S_ISCHR(st->st_mode))
+ format_octal(st->st_rdev, &h.c_rdev, sizeof(h.c_rdev));
+ else
+ format_octal(0, &h.c_rdev, sizeof(h.c_rdev));
+ format_octal(st->st_mtime, &h.c_mtime, sizeof(h.c_mtime));
+ format_octal(pathlength, &h.c_namesize, sizeof(h.c_namesize));
+
+ /* Symlinks get the link written as the body of the entry. */
+ p = archive_entry_symlink(entry);
+ if (p != NULL && *p != '\0')
+ format_octal(strlen(p), &h.c_filesize, sizeof(h.c_filesize));
+ else
+ format_octal(st->st_size, &h.c_filesize, sizeof(h.c_filesize));
+
+ ret = (a->compression_write)(a, &h, sizeof(h));
+ if (ret != ARCHIVE_OK)
+ return (ARCHIVE_FATAL);
+
+ ret = (a->compression_write)(a, path, pathlength);
+ if (ret != ARCHIVE_OK)
+ return (ARCHIVE_FATAL);
+
+ cpio->entry_bytes_remaining = st->st_size;
+
+ /* Write the symlink now. */
+ if (p != NULL && *p != '\0')
+ ret = (a->compression_write)(a, p, strlen(p));
+
+ return (ret);
+}
+
+static int
+archive_write_cpio_data(struct archive *a, const void *buff, size_t s)
+{
+ struct cpio *cpio;
+ int ret;
+
+ cpio = a->format_data;
+ if (s > cpio->entry_bytes_remaining)
+ s = cpio->entry_bytes_remaining;
+
+ ret = (a->compression_write)(a, buff, s);
+ cpio->entry_bytes_remaining -= s;
+ return (ret);
+}
+
+/*
+ * Format a number into the specified field.
+ */
+static int
+format_octal(int64_t v, void *p, int digits)
+{
+ int64_t max;
+ int ret;
+
+ max = (((int64_t)1) << (digits * 3)) - 1;
+ if (v >= 0 && v <= max) {
+ format_octal_recursive(v, p, digits);
+ ret = 0;
+ } else {
+ format_octal_recursive(max, p, digits);
+ ret = -1;
+ }
+ return (ret);
+}
+
+static int64_t
+format_octal_recursive(int64_t v, char *p, int s)
+{
+ if (s == 0)
+ return (v);
+ v = format_octal_recursive(v, p+1, s-1);
+ *p = '0' + (v & 7);
+ return (v >>= 3);
+}
+
+static int
+archive_write_cpio_finish(struct archive *a)
+{
+ struct cpio *cpio;
+ struct stat st;
+ int er;
+ struct archive_entry *trailer;
+
+ cpio = a->format_data;
+ trailer = archive_entry_new();
+ memset(&st, 0, sizeof(st));
+ st.st_nlink = 1;
+ archive_entry_copy_stat(trailer, &st);
+ archive_entry_set_pathname(trailer, "TRAILER!!!");
+ er = archive_write_cpio_header(a, trailer);
+ archive_entry_free(trailer);
+
+ free(cpio);
+ a->format_data = NULL;
+ return (er);
+}
+
+static int
+archive_write_cpio_finish_entry(struct archive *a)
+{
+ struct cpio *cpio;
+ int to_write, ret;
+
+ cpio = a->format_data;
+ ret = ARCHIVE_OK;
+ while (cpio->entry_bytes_remaining > 0) {
+ to_write = cpio->entry_bytes_remaining < a->null_length ?
+ cpio->entry_bytes_remaining : a->null_length;
+ ret = (a->compression_write)(a, a->nulls, to_write);
+ if (ret != ARCHIVE_OK)
+ return (ret);
+ cpio->entry_bytes_remaining -= to_write;
+ }
+ return (ret);
+}
diff --git a/lib/libarchive/archive_write_set_format_pax.c b/lib/libarchive/archive_write_set_format_pax.c
new file mode 100644
index 0000000..c256cb2
--- /dev/null
+++ b/lib/libarchive/archive_write_set_format_pax.c
@@ -0,0 +1,1187 @@
+/*-
+ * Copyright (c) 2003-2004 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(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 AUTHOR(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 "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#include <sys/stat.h>
+#ifdef MAJOR_IN_MKDEV
+#include <sys/mkdev.h>
+#else
+#ifdef MAJOR_IN_SYSMACROS
+#include <sys/sysmacros.h>
+#endif
+#endif
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "archive.h"
+#include "archive_entry.h"
+#include "archive_private.h"
+
+struct pax {
+ uint64_t entry_bytes_remaining;
+ uint64_t entry_padding;
+ struct archive_string pax_header;
+ char written;
+};
+
+static void add_pax_attr(struct archive_string *, const char *key,
+ const char *value);
+static void add_pax_attr_int(struct archive_string *,
+ const char *key, int64_t value);
+static void add_pax_attr_time(struct archive_string *,
+ const char *key, int64_t sec,
+ unsigned long nanos);
+static void add_pax_attr_w(struct archive_string *,
+ const char *key, const wchar_t *wvalue);
+static int archive_write_pax_data(struct archive *,
+ const void *, size_t);
+static int archive_write_pax_finish(struct archive *);
+static int archive_write_pax_finish_entry(struct archive *);
+static int archive_write_pax_header(struct archive *,
+ struct archive_entry *);
+static char *base64_encode(const char *src, size_t len);
+static char *build_pax_attribute_name(char *dest, const char *src);
+static char *build_ustar_entry_name(char *dest, const char *src,
+ size_t src_length, const char *insert);
+static char *format_int(char *dest, int64_t);
+static int has_non_ASCII(const wchar_t *);
+static char *url_encode(const char *in);
+static int write_nulls(struct archive *, size_t);
+
+/*
+ * Set output format to 'restricted pax' format.
+ *
+ * This is the same as normal 'pax', but tries to suppress
+ * the pax header whenever possible. This is the default for
+ * bsdtar, for instance.
+ */
+int
+archive_write_set_format_pax_restricted(struct archive *a)
+{
+ int r;
+ r = archive_write_set_format_pax(a);
+ a->archive_format = ARCHIVE_FORMAT_TAR_PAX_RESTRICTED;
+ a->archive_format_name = "restricted POSIX pax interchange";
+ return (r);
+}
+
+/*
+ * Set output format to 'pax' format.
+ */
+int
+archive_write_set_format_pax(struct archive *a)
+{
+ struct pax *pax;
+
+ if (a->format_finish != NULL)
+ (a->format_finish)(a);
+
+ pax = malloc(sizeof(*pax));
+ if (pax == NULL) {
+ archive_set_error(a, ENOMEM, "Can't allocate pax data");
+ return (ARCHIVE_FATAL);
+ }
+ memset(pax, 0, sizeof(*pax));
+ a->format_data = pax;
+
+ a->pad_uncompressed = 1;
+ a->format_write_header = archive_write_pax_header;
+ a->format_write_data = archive_write_pax_data;
+ a->format_finish = archive_write_pax_finish;
+ a->format_finish_entry = archive_write_pax_finish_entry;
+ a->archive_format = ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE;
+ a->archive_format_name = "POSIX pax interchange";
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Note: This code assumes that 'nanos' has the same sign as 'sec',
+ * which implies that sec=-1, nanos=200000000 represents -1.2 seconds
+ * and not -0.8 seconds. This is a pretty pedantic point, as we're
+ * unlikely to encounter many real files created before Jan 1, 1970,
+ * much less ones with timestamps recorded to sub-second resolution.
+ */
+static void
+add_pax_attr_time(struct archive_string *as, const char *key,
+ int64_t sec, unsigned long nanos)
+{
+ int digit, i;
+ char *t;
+ /*
+ * Note that each byte contributes fewer than 3 base-10
+ * digits, so this will always be big enough.
+ */
+ char tmp[1 + 3*sizeof(sec) + 1 + 3*sizeof(nanos)];
+
+ tmp[sizeof(tmp) - 1] = 0;
+ t = tmp + sizeof(tmp) - 1;
+
+ /* Skip trailing zeros in the fractional part. */
+ for (digit = 0, i = 10; i > 0 && digit == 0; i--) {
+ digit = nanos % 10;
+ nanos /= 10;
+ }
+
+ /* Only format the fraction if it's non-zero. */
+ if (i > 0) {
+ while (i > 0) {
+ *--t = "0123456789"[digit];
+ digit = nanos % 10;
+ nanos /= 10;
+ i--;
+ }
+ *--t = '.';
+ }
+ t = format_int(t, sec);
+
+ add_pax_attr(as, key, t);
+}
+
+static char *
+format_int(char *t, int64_t i)
+{
+ int sign;
+
+ if (i < 0) {
+ sign = -1;
+ i = -i;
+ } else
+ sign = 1;
+
+ do {
+ *--t = "0123456789"[i % 10];
+ } while (i /= 10);
+ if (sign < 0)
+ *--t = '-';
+ return (t);
+}
+
+static void
+add_pax_attr_int(struct archive_string *as, const char *key, int64_t value)
+{
+ char tmp[1 + 3 * sizeof(value)];
+
+ tmp[sizeof(tmp) - 1] = 0;
+ add_pax_attr(as, key, format_int(tmp + sizeof(tmp) - 1, value));
+}
+
+static char *
+utf8_encode(const wchar_t *wval)
+{
+ int utf8len;
+ const wchar_t *wp;
+ unsigned long wc;
+ char *utf8_value, *p;
+
+ utf8len = 0;
+ for (wp = wval; *wp != L'\0'; ) {
+ wc = *wp++;
+ if (wc <= 0x7f)
+ utf8len++;
+ else if (wc <= 0x7ff)
+ utf8len += 2;
+ else if (wc <= 0xffff)
+ utf8len += 3;
+ else if (wc <= 0x1fffff)
+ utf8len += 4;
+ else if (wc <= 0x3ffffff)
+ utf8len += 5;
+ else if (wc <= 0x7fffffff)
+ utf8len += 6;
+ /* Ignore larger values; UTF-8 can't encode them. */
+ }
+
+ utf8_value = malloc(utf8len + 1);
+ if (utf8_value == NULL) {
+ __archive_errx(1, "Not enough memory for attributes");
+ return (NULL);
+ }
+
+ for (wp = wval, p = utf8_value; *wp != L'\0'; ) {
+ wc = *wp++;
+ if (wc <= 0x7f) {
+ *p++ = (char)wc;
+ } else if (wc <= 0x7ff) {
+ p[0] = 0xc0 | ((wc >> 6) & 0x1f);
+ p[1] = 0x80 | (wc & 0x3f);
+ p += 2;
+ } else if (wc <= 0xffff) {
+ p[0] = 0xe0 | ((wc >> 12) & 0x0f);
+ p[1] = 0x80 | ((wc >> 6) & 0x3f);
+ p[2] = 0x80 | (wc & 0x3f);
+ p += 3;
+ } else if (wc <= 0x1fffff) {
+ p[0] = 0xf0 | ((wc >> 18) & 0x07);
+ p[1] = 0x80 | ((wc >> 12) & 0x3f);
+ p[2] = 0x80 | ((wc >> 6) & 0x3f);
+ p[3] = 0x80 | (wc & 0x3f);
+ p += 4;
+ } else if (wc <= 0x3ffffff) {
+ p[0] = 0xf8 | ((wc >> 24) & 0x03);
+ p[1] = 0x80 | ((wc >> 18) & 0x3f);
+ p[2] = 0x80 | ((wc >> 12) & 0x3f);
+ p[3] = 0x80 | ((wc >> 6) & 0x3f);
+ p[4] = 0x80 | (wc & 0x3f);
+ p += 5;
+ } else if (wc <= 0x7fffffff) {
+ p[0] = 0xfc | ((wc >> 30) & 0x01);
+ p[1] = 0x80 | ((wc >> 24) & 0x3f);
+ p[1] = 0x80 | ((wc >> 18) & 0x3f);
+ p[2] = 0x80 | ((wc >> 12) & 0x3f);
+ p[3] = 0x80 | ((wc >> 6) & 0x3f);
+ p[4] = 0x80 | (wc & 0x3f);
+ p += 6;
+ }
+ /* Ignore larger values; UTF-8 can't encode them. */
+ }
+ *p = '\0';
+
+ return (utf8_value);
+}
+
+static void
+add_pax_attr_w(struct archive_string *as, const char *key, const wchar_t *wval)
+{
+ char *utf8_value = utf8_encode(wval);
+ if (utf8_value == NULL)
+ return;
+ add_pax_attr(as, key, utf8_value);
+ free(utf8_value);
+}
+
+/*
+ * Add a key/value attribute to the pax header. This function handles
+ * the length field and various other syntactic requirements.
+ */
+static void
+add_pax_attr(struct archive_string *as, const char *key, const char *value)
+{
+ int digits, i, len, next_ten;
+ char tmp[1 + 3 * sizeof(int)]; /* < 3 base-10 digits per byte */
+
+ /*-
+ * PAX attributes have the following layout:
+ * <len> <space> <key> <=> <value> <nl>
+ */
+ len = 1 + strlen(key) + 1 + strlen(value) + 1;
+
+ /*
+ * The <len> field includes the length of the <len> field, so
+ * computing the correct length is tricky. I start by
+ * counting the number of base-10 digits in 'len' and
+ * computing the next higher power of 10.
+ */
+ next_ten = 1;
+ digits = 0;
+ i = len;
+ while (i > 0) {
+ i = i / 10;
+ digits++;
+ next_ten = next_ten * 10;
+ }
+ /*
+ * For example, if string without the length field is 99
+ * chars, then adding the 2 digit length "99" will force the
+ * total length past 100, requiring an extra digit. The next
+ * statement adjusts for this effect.
+ */
+ if (len + digits >= next_ten)
+ digits++;
+
+ /* Now, we have the right length so we can build the line. */
+ tmp[sizeof(tmp) - 1] = 0; /* Null-terminate the work area. */
+ archive_strcat(as, format_int(tmp + sizeof(tmp) - 1, len + digits));
+ archive_strappend_char(as, ' ');
+ archive_strcat(as, key);
+ archive_strappend_char(as, '=');
+ archive_strcat(as, value);
+ archive_strappend_char(as, '\n');
+}
+
+static void
+archive_write_pax_header_xattrs(struct pax *pax, struct archive_entry *entry)
+{
+ struct archive_string s;
+ int i = archive_entry_xattr_reset(entry);
+
+ while (i--) {
+ const char *name;
+ const void *value;
+ char *encoded_value;
+ char *url_encoded_name = NULL, *encoded_name = NULL;
+ wchar_t *wcs_name = NULL;
+ size_t size;
+
+ archive_entry_xattr_next(entry, &name, &value, &size);
+ /* Name is URL-encoded, then converted to wchar_t,
+ * then UTF-8 encoded. */
+ url_encoded_name = url_encode(name);
+ if (url_encoded_name != NULL) {
+ /* Convert narrow-character to wide-character. */
+ int wcs_length = strlen(url_encoded_name);
+ wcs_name = malloc((wcs_length + 1) * sizeof(wchar_t));
+ if (wcs_name == NULL)
+ __archive_errx(1, "No memory for xattr conversion");
+ mbstowcs(wcs_name, url_encoded_name, wcs_length);
+ wcs_name[wcs_length] = 0;
+ free(url_encoded_name); /* Done with this. */
+ }
+ if (wcs_name != NULL) {
+ encoded_name = utf8_encode(wcs_name);
+ free(wcs_name); /* Done with wchar_t name. */
+ }
+
+ encoded_value = base64_encode(value, size);
+
+ if (encoded_name != NULL && encoded_value != NULL) {
+ archive_string_init(&s);
+ archive_strcpy(&s, "LIBARCHIVE.xattr.");
+ archive_strcat(&s, encoded_name);
+ add_pax_attr(&(pax->pax_header), s.s, encoded_value);
+ archive_string_free(&s);
+ }
+ free(encoded_name);
+ free(encoded_value);
+ }
+}
+
+/*
+ * TODO: Consider adding 'comment' and 'charset' fields to
+ * archive_entry so that clients can specify them. Also, consider
+ * adding generic key/value tags so clients can add arbitrary
+ * key/value data.
+ */
+static int
+archive_write_pax_header(struct archive *a,
+ struct archive_entry *entry_original)
+{
+ struct archive_entry *entry_main;
+ const char *linkname, *p;
+ const char *hardlink;
+ const wchar_t *wp;
+ const char *suffix_start;
+ int need_extension, r, ret;
+ struct pax *pax;
+ const struct stat *st_main, *st_original;
+
+ char paxbuff[512];
+ char ustarbuff[512];
+ char ustar_entry_name[256];
+ char pax_entry_name[256];
+
+ need_extension = 0;
+ pax = a->format_data;
+ pax->written = 1;
+
+ st_original = archive_entry_stat(entry_original);
+
+ hardlink = archive_entry_hardlink(entry_original);
+
+ /* Make sure this is a type of entry that we can handle here */
+ if (hardlink == NULL) {
+ switch (st_original->st_mode & S_IFMT) {
+ case S_IFREG:
+ case S_IFLNK:
+ case S_IFCHR:
+ case S_IFBLK:
+ case S_IFDIR:
+ case S_IFIFO:
+ break;
+ case S_IFSOCK:
+ archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ "tar format cannot archive socket");
+ return (ARCHIVE_WARN);
+ default:
+ archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ "tar format cannot archive this (mode=0%lo)",
+ (unsigned long)st_original->st_mode);
+ return (ARCHIVE_WARN);
+ }
+ }
+
+ /* Copy entry so we can modify it as needed. */
+ entry_main = archive_entry_clone(entry_original);
+ archive_string_empty(&(pax->pax_header)); /* Blank our work area. */
+ st_main = archive_entry_stat(entry_main);
+
+ /*
+ * Determining whether or not the name is too big is ugly
+ * because of the rules for dividing names between 'name' and
+ * 'prefix' fields. Here, I pick out the longest possible
+ * suffix, then test whether the remaining prefix is too long.
+ */
+ wp = archive_entry_pathname_w(entry_main);
+ p = archive_entry_pathname(entry_main);
+ if (strlen(p) <= 100) /* Short enough for just 'name' field */
+ suffix_start = p; /* Record a zero-length prefix */
+ else
+ /* Find the largest suffix that fits in 'name' field. */
+ suffix_start = strchr(p + strlen(p) - 100 - 1, '/');
+
+ /*
+ * If name is too long, or has non-ASCII characters, add
+ * 'path' to pax extended attrs.
+ */
+ if (suffix_start == NULL || suffix_start - p > 155 || has_non_ASCII(wp)) {
+ add_pax_attr_w(&(pax->pax_header), "path", wp);
+ archive_entry_set_pathname(entry_main,
+ build_ustar_entry_name(ustar_entry_name, p, strlen(p), NULL));
+ need_extension = 1;
+ }
+
+ /* If link name is too long or has non-ASCII characters, add
+ * 'linkpath' to pax extended attrs. */
+ linkname = hardlink;
+ if (linkname == NULL)
+ linkname = archive_entry_symlink(entry_main);
+
+ if (linkname != NULL) {
+ /* There is a link name, get the wide version as well. */
+ if (hardlink != NULL)
+ wp = archive_entry_hardlink_w(entry_main);
+ else
+ wp = archive_entry_symlink_w(entry_main);
+
+ /* If the link is long or has a non-ASCII character,
+ * store it as a pax extended attribute. */
+ if (strlen(linkname) > 100 || has_non_ASCII(wp)) {
+ add_pax_attr_w(&(pax->pax_header), "linkpath", wp);
+ if (hardlink != NULL)
+ archive_entry_set_hardlink(entry_main,
+ "././@LongHardLink");
+ else
+ archive_entry_set_symlink(entry_main,
+ "././@LongSymLink");
+ need_extension = 1;
+ }
+ }
+
+ /* If file size is too large, add 'size' to pax extended attrs. */
+ if (st_main->st_size >= (((int64_t)1) << 33)) {
+ add_pax_attr_int(&(pax->pax_header), "size", st_main->st_size);
+ need_extension = 1;
+ }
+
+ /* If numeric GID is too large, add 'gid' to pax extended attrs. */
+ if (st_main->st_gid >= (1 << 18)) {
+ add_pax_attr_int(&(pax->pax_header), "gid", st_main->st_gid);
+ need_extension = 1;
+ }
+
+ /* If group name is too large or has non-ASCII characters, add
+ * 'gname' to pax extended attrs. */
+ p = archive_entry_gname(entry_main);
+ wp = archive_entry_gname_w(entry_main);
+ if (p != NULL && (strlen(p) > 31 || has_non_ASCII(wp))) {
+ add_pax_attr_w(&(pax->pax_header), "gname", wp);
+ archive_entry_set_gname(entry_main, NULL);
+ need_extension = 1;
+ }
+
+ /* If numeric UID is too large, add 'uid' to pax extended attrs. */
+ if (st_main->st_uid >= (1 << 18)) {
+ add_pax_attr_int(&(pax->pax_header), "uid", st_main->st_uid);
+ need_extension = 1;
+ }
+
+ /* If user name is too large, add 'uname' to pax extended attrs. */
+ /* TODO: If uname has non-ASCII characters, use pax attribute. */
+ p = archive_entry_uname(entry_main);
+ wp = archive_entry_uname_w(entry_main);
+ if (p != NULL && (strlen(p) > 31 || has_non_ASCII(wp))) {
+ add_pax_attr_w(&(pax->pax_header), "uname", wp);
+ archive_entry_set_uname(entry_main, NULL);
+ need_extension = 1;
+ }
+
+ /*
+ * POSIX/SUSv3 doesn't provide a standard key for large device
+ * numbers. I use the same keys here that Joerg Schilling
+ * used for 'star.' (Which, somewhat confusingly, are called
+ * "devXXX" even though they code "rdev" values.) No doubt,
+ * other implementations use other keys. Note that there's no
+ * reason we can't write the same information into a number of
+ * different keys.
+ *
+ * Of course, this is only needed for block or char device entries.
+ */
+ if (S_ISBLK(st_main->st_mode) ||
+ S_ISCHR(st_main->st_mode)) {
+ /*
+ * If rdevmajor is too large, add 'SCHILY.devmajor' to
+ * extended attributes.
+ */
+ dev_t rdevmajor, rdevminor;
+ rdevmajor = major(st_main->st_rdev);
+ rdevminor = minor(st_main->st_rdev);
+ if (rdevmajor >= (1 << 18)) {
+ add_pax_attr_int(&(pax->pax_header), "SCHILY.devmajor",
+ rdevmajor);
+ /*
+ * Non-strict formatting below means we don't
+ * have to truncate here. Not truncating improves
+ * the chance that some more modern tar archivers
+ * (such as GNU tar 1.13) can restore the full
+ * value even if they don't understand the pax
+ * extended attributes. See my rant below about
+ * file size fields for additional details.
+ */
+ /* archive_entry_set_rdevmajor(entry_main,
+ rdevmajor & ((1 << 18) - 1)); */
+ need_extension = 1;
+ }
+
+ /*
+ * If devminor is too large, add 'SCHILY.devminor' to
+ * extended attributes.
+ */
+ if (rdevminor >= (1 << 18)) {
+ add_pax_attr_int(&(pax->pax_header), "SCHILY.devminor",
+ rdevminor);
+ /* Truncation is not necessary here, either. */
+ /* archive_entry_set_rdevminor(entry_main,
+ rdevminor & ((1 << 18) - 1)); */
+ need_extension = 1;
+ }
+ }
+
+ /*
+ * Technically, the mtime field in the ustar header can
+ * support 33 bits, but many platforms use signed 32-bit time
+ * values. The cutoff of 0x7fffffff here is a compromise.
+ * Yes, this check is duplicated just below; this helps to
+ * avoid writing an mtime attribute just to handle a
+ * high-resolution timestamp in "restricted pax" mode.
+ */
+ if (!need_extension &&
+ ((st_main->st_mtime < 0) || (st_main->st_mtime >= 0x7fffffff)))
+ need_extension = 1;
+
+ /* I use a star-compatible file flag attribute. */
+ p = archive_entry_fflags_text(entry_main);
+ if (!need_extension && p != NULL && *p != '\0')
+ need_extension = 1;
+
+ /* If there are non-trivial ACL entries, we need an extension. */
+ if (!need_extension && archive_entry_acl_count(entry_original,
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS) > 0)
+ need_extension = 1;
+
+ /* If there are non-trivial ACL entries, we need an extension. */
+ if (!need_extension && archive_entry_acl_count(entry_original,
+ ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) > 0)
+ need_extension = 1;
+
+ /* If there are extended attributes, we need an extension */
+ if (!need_extension && archive_entry_xattr_count(entry_original) > 0)
+ need_extension = 1;
+
+ /*
+ * The following items are handled differently in "pax
+ * restricted" format. In particular, in "pax restricted"
+ * format they won't be added unless need_extension is
+ * already set (we're already generating an extended header, so
+ * may as well include these).
+ */
+ if (a->archive_format != ARCHIVE_FORMAT_TAR_PAX_RESTRICTED ||
+ need_extension) {
+
+ if (st_main->st_mtime < 0 ||
+ st_main->st_mtime >= 0x7fffffff ||
+ ARCHIVE_STAT_MTIME_NANOS(st_main) != 0)
+ add_pax_attr_time(&(pax->pax_header), "mtime",
+ st_main->st_mtime,
+ ARCHIVE_STAT_MTIME_NANOS(st_main));
+
+ if (st_main->st_ctime != 0 ||
+ ARCHIVE_STAT_CTIME_NANOS(st_main) != 0)
+ add_pax_attr_time(&(pax->pax_header), "ctime",
+ st_main->st_ctime,
+ ARCHIVE_STAT_CTIME_NANOS(st_main));
+
+ if (st_main->st_atime != 0 ||
+ ARCHIVE_STAT_ATIME_NANOS(st_main) != 0)
+ add_pax_attr_time(&(pax->pax_header), "atime",
+ st_main->st_atime,
+ ARCHIVE_STAT_ATIME_NANOS(st_main));
+
+ /* I use a star-compatible file flag attribute. */
+ p = archive_entry_fflags_text(entry_main);
+ if (p != NULL && *p != '\0')
+ add_pax_attr(&(pax->pax_header), "SCHILY.fflags", p);
+
+ /* I use star-compatible ACL attributes. */
+ wp = archive_entry_acl_text_w(entry_original,
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS |
+ ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID);
+ if (wp != NULL && *wp != L'\0')
+ add_pax_attr_w(&(pax->pax_header),
+ "SCHILY.acl.access", wp);
+ wp = archive_entry_acl_text_w(entry_original,
+ ARCHIVE_ENTRY_ACL_TYPE_DEFAULT |
+ ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID);
+ if (wp != NULL && *wp != L'\0')
+ add_pax_attr_w(&(pax->pax_header),
+ "SCHILY.acl.default", wp);
+
+ /* Include star-compatible metadata info. */
+ /* Note: "SCHILY.dev{major,minor}" are NOT the
+ * major/minor portions of "SCHILY.dev". */
+ add_pax_attr_int(&(pax->pax_header), "SCHILY.dev",
+ st_main->st_dev);
+ add_pax_attr_int(&(pax->pax_header), "SCHILY.ino",
+ st_main->st_ino);
+ add_pax_attr_int(&(pax->pax_header), "SCHILY.nlink",
+ st_main->st_nlink);
+
+ /* Store extended attributes */
+ archive_write_pax_header_xattrs(pax, entry_original);
+ }
+
+ /* Only regular files have data. */
+ if (!S_ISREG(archive_entry_mode(entry_main)))
+ archive_entry_set_size(entry_main, 0);
+
+ /*
+ * Pax-restricted does not store data for hardlinks, in order
+ * to improve compatibility with ustar.
+ */
+ if (a->archive_format != ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE &&
+ hardlink != NULL)
+ archive_entry_set_size(entry_main, 0);
+
+ /*
+ * XXX Full pax interchange format does permit a hardlink
+ * entry to have data associated with it. I'm not supporting
+ * that here because the client expects me to tell them whether
+ * or not this format expects data for hardlinks. If I
+ * don't check here, then every pax archive will end up with
+ * duplicated data for hardlinks. Someday, there may be
+ * need to select this behavior, in which case the following
+ * will need to be revisited. XXX
+ */
+ if (hardlink != NULL)
+ archive_entry_set_size(entry_main, 0);
+
+ /* Format 'ustar' header for main entry.
+ *
+ * The trouble with file size: If the reader can't understand
+ * the file size, they may not be able to locate the next
+ * entry and the rest of the archive is toast. Pax-compliant
+ * readers are supposed to ignore the file size in the main
+ * header, so the question becomes how to maximize portability
+ * for readers that don't support pax attribute extensions.
+ * For maximum compatibility, I permit numeric extensions in
+ * the main header so that the file size stored will always be
+ * correct, even if it's in a format that only some
+ * implementations understand. The technique used here is:
+ *
+ * a) If possible, follow the standard exactly. This handles
+ * files up to 8 gigabytes minus 1.
+ *
+ * b) If that fails, try octal but omit the field terminator.
+ * That handles files up to 64 gigabytes minus 1.
+ *
+ * c) Otherwise, use base-256 extensions. That handles files
+ * up to 2^63 in this implementation, with the potential to
+ * go up to 2^94. That should hold us for a while. ;-)
+ *
+ * The non-strict formatter uses similar logic for other
+ * numeric fields, though they're less critical.
+ */
+ __archive_write_format_header_ustar(a, ustarbuff, entry_main, -1, 0);
+
+ /* If we built any extended attributes, write that entry first. */
+ ret = ARCHIVE_OK;
+ if (archive_strlen(&(pax->pax_header)) > 0) {
+ struct stat st;
+ struct archive_entry *pax_attr_entry;
+ time_t s;
+ long ns;
+
+ memset(&st, 0, sizeof(st));
+ pax_attr_entry = archive_entry_new();
+ p = archive_entry_pathname(entry_main);
+ archive_entry_set_pathname(pax_attr_entry,
+ build_pax_attribute_name(pax_entry_name, p));
+ st.st_size = archive_strlen(&(pax->pax_header));
+ /* Copy uid/gid (but clip to ustar limits). */
+ st.st_uid = st_main->st_uid;
+ if (st.st_uid >= 1 << 18)
+ st.st_uid = (1 << 18) - 1;
+ st.st_gid = st_main->st_gid;
+ if (st.st_gid >= 1 << 18)
+ st.st_gid = (1 << 18) - 1;
+ /* Copy mode over (but not setuid/setgid bits) */
+ st.st_mode = st_main->st_mode;
+#ifdef S_ISUID
+ st.st_mode &= ~S_ISUID;
+#endif
+#ifdef S_ISGID
+ st.st_mode &= ~S_ISGID;
+#endif
+#ifdef S_ISVTX
+ st.st_mode &= ~S_ISVTX;
+#endif
+ archive_entry_copy_stat(pax_attr_entry, &st);
+
+ /* Copy uname/gname. */
+ archive_entry_set_uname(pax_attr_entry,
+ archive_entry_uname(entry_main));
+ archive_entry_set_gname(pax_attr_entry,
+ archive_entry_gname(entry_main));
+
+ /* Copy mtime, but clip to ustar limits. */
+ s = archive_entry_mtime(entry_main);
+ ns = archive_entry_mtime_nsec(entry_main);
+ if (s < 0) { s = 0; ns = 0; }
+ if (s > 0x7fffffff) { s = 0x7fffffff; ns = 0; }
+ archive_entry_set_mtime(pax_attr_entry, s, ns);
+
+ /* Ditto for atime. */
+ s = archive_entry_atime(entry_main);
+ ns = archive_entry_atime_nsec(entry_main);
+ if (s < 0) { s = 0; ns = 0; }
+ if (s > 0x7fffffff) { s = 0x7fffffff; ns = 0; }
+ archive_entry_set_atime(pax_attr_entry, s, ns);
+
+ /* Standard ustar doesn't support ctime. */
+ archive_entry_set_ctime(pax_attr_entry, 0, 0);
+
+ ret = __archive_write_format_header_ustar(a, paxbuff,
+ pax_attr_entry, 'x', 1);
+
+ archive_entry_free(pax_attr_entry);
+
+ /* Note that the 'x' header shouldn't ever fail to format */
+ if (ret != 0) {
+ const char *msg = "archive_write_pax_header: "
+ "'x' header failed?! This can't happen.\n";
+ write(2, msg, strlen(msg));
+ exit(1);
+ }
+ r = (a->compression_write)(a, paxbuff, 512);
+ if (r != ARCHIVE_OK) {
+ pax->entry_bytes_remaining = 0;
+ pax->entry_padding = 0;
+ return (ARCHIVE_FATAL);
+ }
+
+ pax->entry_bytes_remaining = archive_strlen(&(pax->pax_header));
+ pax->entry_padding = 0x1ff & (- pax->entry_bytes_remaining);
+
+ r = (a->compression_write)(a, pax->pax_header.s,
+ archive_strlen(&(pax->pax_header)));
+ if (r != ARCHIVE_OK) {
+ /* If a write fails, we're pretty much toast. */
+ return (ARCHIVE_FATAL);
+ }
+ /* Pad out the end of the entry. */
+ r = write_nulls(a, pax->entry_padding);
+ if (r != ARCHIVE_OK) {
+ /* If a write fails, we're pretty much toast. */
+ return (ARCHIVE_FATAL);
+ }
+ pax->entry_bytes_remaining = pax->entry_padding = 0;
+ }
+
+ /* Write the header for main entry. */
+ r = (a->compression_write)(a, ustarbuff, 512);
+ if (r != ARCHIVE_OK)
+ return (r);
+
+ /*
+ * Inform the client of the on-disk size we're using, so
+ * they can avoid unnecessarily writing a body for something
+ * that we're just going to ignore.
+ */
+ archive_entry_set_size(entry_original, archive_entry_size(entry_main));
+ pax->entry_bytes_remaining = archive_entry_size(entry_main);
+ pax->entry_padding = 0x1ff & (- pax->entry_bytes_remaining);
+ archive_entry_free(entry_main);
+
+ return (ret);
+}
+
+/*
+ * We need a valid name for the regular 'ustar' entry. This routine
+ * tries to hack something more-or-less reasonable.
+ *
+ * The approach here tries to preserve leading dir names. We do so by
+ * working with four sections:
+ * 1) "prefix" directory names,
+ * 2) "suffix" directory names,
+ * 3) inserted dir name (optional),
+ * 4) filename.
+ *
+ * These sections must satisfy the following requirements:
+ * * Parts 1 & 2 together form an initial portion of the dir name.
+ * * Part 3 is specified by the caller. (It should not contain a leading
+ * or trailing '/'.)
+ * * Part 4 forms an initial portion of the base filename.
+ * * The filename must be <= 99 chars to fit the ustar 'name' field.
+ * * Parts 2, 3, 4 together must be <= 99 chars to fit the ustar 'name' fld.
+ * * Part 1 must be <= 155 chars to fit the ustar 'prefix' field.
+ * * If the original name ends in a '/', the new name must also end in a '/'
+ * * Trailing '/.' sequences may be stripped.
+ *
+ * Note: Recall that the ustar format does not store the '/' separating
+ * parts 1 & 2, but does store the '/' separating parts 2 & 3.
+ */
+static char *
+build_ustar_entry_name(char *dest, const char *src, size_t src_length,
+ const char *insert)
+{
+ const char *prefix, *prefix_end;
+ const char *suffix, *suffix_end;
+ const char *filename, *filename_end;
+ char *p;
+ int need_slash = 0; /* Was there a trailing slash? */
+ size_t suffix_length = 99;
+ int insert_length;
+
+ /* Length of additional dir element to be added. */
+ if (insert == NULL)
+ insert_length = 0;
+ else
+ /* +2 here allows for '/' before and after the insert. */
+ insert_length = strlen(insert) + 2;
+
+ /* Step 0: Quick bailout in a common case. */
+ if (src_length < 100 && insert == NULL) {
+ strncpy(dest, src, src_length);
+ dest[src_length] = '\0';
+ return (dest);
+ }
+
+ /* Step 1: Locate filename and enforce the length restriction. */
+ filename_end = src + src_length;
+ /* Remove trailing '/' chars and '/.' pairs. */
+ for (;;) {
+ if (filename_end > src && filename_end[-1] == '/') {
+ filename_end --;
+ need_slash = 1; /* Remember to restore trailing '/'. */
+ continue;
+ }
+ if (filename_end > src + 1 && filename_end[-1] == '.'
+ && filename_end[-2] == '/') {
+ filename_end -= 2;
+ need_slash = 1; /* "foo/." will become "foo/" */
+ continue;
+ }
+ break;
+ }
+ if (need_slash)
+ suffix_length--;
+ /* Find start of filename. */
+ filename = filename_end - 1;
+ while ((filename > src) && (*filename != '/'))
+ filename --;
+ if ((*filename == '/') && (filename < filename_end - 1))
+ filename ++;
+ /* Adjust filename_end so that filename + insert fits in 99 chars. */
+ suffix_length -= insert_length;
+ if (filename_end > filename + suffix_length)
+ filename_end = filename + suffix_length;
+ /* Calculate max size for "suffix" section (#3 above). */
+ suffix_length -= filename_end - filename;
+
+ /* Step 2: Locate the "prefix" section of the dirname, including
+ * trailing '/'. */
+ prefix = src;
+ prefix_end = prefix + 155;
+ if (prefix_end > filename)
+ prefix_end = filename;
+ while (prefix_end > prefix && *prefix_end != '/')
+ prefix_end--;
+ if ((prefix_end < filename) && (*prefix_end == '/'))
+ prefix_end++;
+
+ /* Step 3: Locate the "suffix" section of the dirname,
+ * including trailing '/'. */
+ suffix = prefix_end;
+ suffix_end = suffix + suffix_length; /* Enforce limit. */
+ if (suffix_end > filename)
+ suffix_end = filename;
+ if (suffix_end < suffix)
+ suffix_end = suffix;
+ while (suffix_end > suffix && *suffix_end != '/')
+ suffix_end--;
+ if ((suffix_end < filename) && (*suffix_end == '/'))
+ suffix_end++;
+
+ /* Step 4: Build the new name. */
+ /* The OpenBSD strlcpy function is safer, but less portable. */
+ /* Rather than maintain two versions, just use the strncpy version. */
+ p = dest;
+ if (prefix_end > prefix) {
+ strncpy(p, prefix, prefix_end - prefix);
+ p += prefix_end - prefix;
+ }
+ if (suffix_end > suffix) {
+ strncpy(p, suffix, suffix_end - suffix);
+ p += suffix_end - suffix;
+ }
+ if (insert != NULL) {
+ /* Note: assume insert does not have leading or trailing '/' */
+ strcpy(p, insert);
+ p += strlen(insert);
+ *p++ = '/';
+ }
+ strncpy(p, filename, filename_end - filename);
+ p += filename_end - filename;
+ if (need_slash)
+ *p++ = '/';
+ *p++ = '\0';
+
+ return (dest);
+}
+
+/*
+ * The ustar header for the pax extended attributes must have a
+ * reasonable name: SUSv3 suggests 'dirname'/PaxHeader/'filename'
+ *
+ * Joerg Schiling has argued that this is unnecessary because, in practice,
+ * if the pax extended attributes get extracted as regular files, noone is
+ * going to bother reading those attributes to manually restore them.
+ * Based on this, 'star' uses /tmp/PaxHeader/'basename' as the ustar header
+ * name. This is a tempting argument, but I'm not entirely convinced.
+ * I'm also uncomfortable with the fact that "/tmp" is a Unix-ism.
+ *
+ * The following routine implements the SUSv3 recommendation, and is
+ * much simpler because build_ustar_entry_name() above already does
+ * most of the work (we just need to give it an extra path element to
+ * insert and handle a few pathological cases).
+ */
+static char *
+build_pax_attribute_name(char *dest, const char *src)
+{
+ const char *p;
+
+ /* Handle the null filename case. */
+ if (src == NULL || *src == '\0') {
+ strcpy(dest, "PaxHeader/blank");
+ return (dest);
+ }
+
+ /* Prune final '/' and other unwanted final elements. */
+ p = src + strlen(src);
+ for (;;) {
+ /* Ends in "/", remove the '/' */
+ if (p > src && p[-1] == '/') {
+ --p;
+ continue;
+ }
+ /* Ends in "/.", remove the '.' */
+ if (p > src + 1 && p[-1] == '.'
+ && p[-2] == '/') {
+ --p;
+ continue;
+ }
+ break;
+ }
+
+ /* Pathological case: After above, there was nothing left.
+ * This includes "/." "/./." "/.//./." etc. */
+ if (p == src) {
+ strcpy(dest, "/PaxHeader/rootdir");
+ return (dest);
+ }
+
+ /* Convert unadorned "." into a suitable filename. */
+ if (*src == '.' && p == src + 1) {
+ strcpy(dest, "PaxHeader/currentdir");
+ return (dest);
+ }
+
+ /* General case: build a ustar-compatible name adding "/PaxHeader/". */
+ build_ustar_entry_name(dest, src, p - src, "PaxHeader");
+
+ return (dest);
+}
+
+/* Write two null blocks for the end of archive */
+static int
+archive_write_pax_finish(struct archive *a)
+{
+ struct pax *pax;
+ int r;
+
+ r = ARCHIVE_OK;
+ pax = a->format_data;
+ if (pax->written && a->compression_write != NULL)
+ r = write_nulls(a, 512 * 2);
+ archive_string_free(&pax->pax_header);
+ free(pax);
+ a->format_data = NULL;
+ return (r);
+}
+
+static int
+archive_write_pax_finish_entry(struct archive *a)
+{
+ struct pax *pax;
+ int ret;
+
+ pax = a->format_data;
+ ret = write_nulls(a, pax->entry_bytes_remaining + pax->entry_padding);
+ pax->entry_bytes_remaining = pax->entry_padding = 0;
+ return (ret);
+}
+
+static int
+write_nulls(struct archive *a, size_t padding)
+{
+ int ret, to_write;
+
+ while (padding > 0) {
+ to_write = padding < a->null_length ? padding : a->null_length;
+ ret = (a->compression_write)(a, a->nulls, to_write);
+ if (ret != ARCHIVE_OK)
+ return (ret);
+ padding -= to_write;
+ }
+ return (ARCHIVE_OK);
+}
+
+static int
+archive_write_pax_data(struct archive *a, const void *buff, size_t s)
+{
+ struct pax *pax;
+ int ret;
+
+ pax = a->format_data;
+ pax->written = 1;
+ if (s > pax->entry_bytes_remaining)
+ s = pax->entry_bytes_remaining;
+
+ ret = (a->compression_write)(a, buff, s);
+ pax->entry_bytes_remaining -= s;
+ return (ret);
+}
+
+static int
+has_non_ASCII(const wchar_t *wp)
+{
+ while (*wp != L'\0' && *wp < 128)
+ wp++;
+ return (*wp != L'\0');
+}
+
+/*
+ * Used by extended attribute support; encodes the name
+ * so that there will be no '=' characters in the result.
+ */
+static char *
+url_encode(const char *in)
+{
+ const char *s;
+ char *d;
+ int out_len = 0;
+ char *out;
+
+ for (s = in; *s != '\0'; s++) {
+ if (*s < 33 || *s > 126 || *s == '%' || *s == '=')
+ out_len += 3;
+ else
+ out_len++;
+ }
+
+ out = (char *)malloc(out_len + 1);
+ if (out == NULL)
+ return (NULL);
+
+ for (s = in, d = out; *s != '\0'; s++) {
+ /* encode any non-printable ASCII character or '%' or '=' */
+ if (*s < 33 || *s > 126 || *s == '%' || *s == '=') {
+ /* URL encoding is '%' followed by two hex digits */
+ *d++ = '%';
+ *d++ = "0123456789ABCDEF"[0x0f & (*s >> 4)];
+ *d++ = "0123456789ABCDEF"[0x0f & *s];
+ } else {
+ *d++ = *s;
+ }
+ }
+ *d = '\0';
+ return (out);
+}
+
+/*
+ * Encode a sequence of bytes into a C string using base-64 encoding.
+ *
+ * Returns a null-terminated C string allocated with malloc(); caller
+ * is responsible for freeing the result.
+ */
+static char *
+base64_encode(const char *s, size_t len)
+{
+ static const char digits[64] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ int v;
+ char *d, *out;
+
+ /* 3 bytes becomes 4 chars, but round up and allow for trailing NUL */
+ out = malloc((len * 4 + 2) / 3 + 1);
+ if (out == NULL)
+ return (NULL);
+ d = out;
+
+ /* Convert each group of 3 bytes into 4 characters. */
+ while (len >= 3) {
+ v = (((int)s[0] << 16) & 0xff0000)
+ | (((int)s[1] << 8) & 0xff00)
+ | (((int)s[2]) & 0x00ff);
+ s += 3;
+ len -= 3;
+ *d++ = digits[(v >> 18) & 0x3f];
+ *d++ = digits[(v >> 12) & 0x3f];
+ *d++ = digits[(v >> 6) & 0x3f];
+ *d++ = digits[(v) & 0x3f];
+ }
+ /* Handle final group of 1 byte (2 chars) or 2 bytes (3 chars). */
+ switch (len) {
+ case 0: break;
+ case 1:
+ v = (((int)s[0] << 16) & 0xff0000);
+ *d++ = digits[(v >> 18) & 0x3f];
+ *d++ = digits[(v >> 12) & 0x3f];
+ break;
+ case 2:
+ v = (((int)s[0] << 16) & 0xff0000)
+ | (((int)s[1] << 8) & 0xff00);
+ *d++ = digits[(v >> 18) & 0x3f];
+ *d++ = digits[(v >> 12) & 0x3f];
+ *d++ = digits[(v >> 6) & 0x3f];
+ break;
+ }
+ /* Add trailing NUL character so output is a valid C string. */
+ *d++ = '\0';
+ return (out);
+}
diff --git a/lib/libarchive/archive_write_set_format_shar.c b/lib/libarchive/archive_write_set_format_shar.c
new file mode 100644
index 0000000..b636cfb
--- /dev/null
+++ b/lib/libarchive/archive_write_set_format_shar.c
@@ -0,0 +1,534 @@
+/*-
+ * Copyright (c) 2003-2004 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(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 AUTHOR(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 "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#include <sys/stat.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "archive.h"
+#include "archive_entry.h"
+#include "archive_private.h"
+
+struct shar {
+ int dump;
+ int end_of_line;
+ struct archive_entry *entry;
+ int has_data;
+ char *last_dir;
+ char outbuff[1024];
+ size_t outbytes;
+ size_t outpos;
+ int uuavail;
+ char uubuffer[3];
+ int wrote_header;
+ struct archive_string work;
+};
+
+static int archive_write_shar_finish(struct archive *);
+static int archive_write_shar_header(struct archive *,
+ struct archive_entry *);
+static int archive_write_shar_data_sed(struct archive *,
+ const void * buff, size_t);
+static int archive_write_shar_data_uuencode(struct archive *,
+ const void * buff, size_t);
+static int archive_write_shar_finish_entry(struct archive *);
+static int shar_printf(struct archive *, const char *fmt, ...);
+static void uuencode_group(struct shar *);
+
+static int
+shar_printf(struct archive *a, const char *fmt, ...)
+{
+ struct shar *shar;
+ va_list ap;
+ int ret;
+
+ shar = a->format_data;
+ va_start(ap, fmt);
+ archive_string_empty(&(shar->work));
+ archive_string_vsprintf(&(shar->work), fmt, ap);
+ ret = ((a->compression_write)(a, shar->work.s, strlen(shar->work.s)));
+ va_end(ap);
+ return (ret);
+}
+
+/*
+ * Set output format to 'shar' format.
+ */
+int
+archive_write_set_format_shar(struct archive *a)
+{
+ struct shar *shar;
+
+ /* If someone else was already registered, unregister them. */
+ if (a->format_finish != NULL)
+ (a->format_finish)(a);
+
+ shar = malloc(sizeof(*shar));
+ if (shar == NULL) {
+ archive_set_error(a, ENOMEM, "Can't allocate shar data");
+ return (ARCHIVE_FATAL);
+ }
+ memset(shar, 0, sizeof(*shar));
+ a->format_data = shar;
+
+ a->pad_uncompressed = 0;
+ a->format_write_header = archive_write_shar_header;
+ a->format_finish = archive_write_shar_finish;
+ a->format_write_data = archive_write_shar_data_sed;
+ a->format_finish_entry = archive_write_shar_finish_entry;
+ a->archive_format = ARCHIVE_FORMAT_SHAR_BASE;
+ a->archive_format_name = "shar";
+ return (ARCHIVE_OK);
+}
+
+/*
+ * An alternate 'shar' that uses uudecode instead of 'sed' to encode
+ * file contents and can therefore be used to archive binary files.
+ * In addition, this variant also attempts to restore ownership, file modes,
+ * and other extended file information.
+ */
+int
+archive_write_set_format_shar_dump(struct archive *a)
+{
+ struct shar *shar;
+
+ archive_write_set_format_shar(a);
+ shar = a->format_data;
+ shar->dump = 1;
+ a->format_write_data = archive_write_shar_data_uuencode;
+ a->archive_format = ARCHIVE_FORMAT_SHAR_DUMP;
+ a->archive_format_name = "shar dump";
+ return (ARCHIVE_OK);
+}
+
+static int
+archive_write_shar_header(struct archive *a, struct archive_entry *entry)
+{
+ const char *linkname;
+ const char *name;
+ char *p, *pp;
+ struct shar *shar;
+ const struct stat *st;
+ int ret;
+
+ shar = a->format_data;
+ if (!shar->wrote_header) {
+ ret = shar_printf(a, "#!/bin/sh\n");
+ if (ret != ARCHIVE_OK)
+ return (ret);
+ ret = shar_printf(a, "# This is a shell archive\n");
+ if (ret != ARCHIVE_OK)
+ return (ret);
+ shar->wrote_header = 1;
+ }
+
+ /* Save the entry for the closing. */
+ if (shar->entry)
+ archive_entry_free(shar->entry);
+ shar->entry = archive_entry_clone(entry);
+ name = archive_entry_pathname(entry);
+ st = archive_entry_stat(entry);
+
+ /* Handle some preparatory issues. */
+ switch(st->st_mode & S_IFMT) {
+ case S_IFREG:
+ /* Only regular files have non-zero size. */
+ break;
+ case S_IFDIR:
+ archive_entry_set_size(entry, 0);
+ /* Don't bother trying to recreate '.' */
+ if (strcmp(name, ".") == 0 || strcmp(name, "./") == 0)
+ return (ARCHIVE_OK);
+ break;
+ case S_IFIFO:
+ case S_IFCHR:
+ case S_IFBLK:
+ /* All other file types have zero size in the archive. */
+ archive_entry_set_size(entry, 0);
+ break;
+ default:
+ archive_entry_set_size(entry, 0);
+ if (archive_entry_hardlink(entry) == NULL &&
+ archive_entry_symlink(entry) == NULL) {
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "shar format cannot archive this");
+ return (ARCHIVE_WARN);
+ }
+ }
+
+ /* Stock preparation for all file types. */
+ ret = shar_printf(a, "echo x %s\n", name);
+ if (ret != ARCHIVE_OK)
+ return (ret);
+
+ if (!S_ISDIR(st->st_mode)) {
+ /* Try to create the dir. */
+ p = strdup(name);
+ pp = strrchr(p, '/');
+ /* If there is a / character, try to create the dir. */
+ if (pp != NULL) {
+ *pp = '\0';
+
+ /* Try to avoid a lot of redundant mkdir commands. */
+ if (strcmp(p, ".") == 0) {
+ /* Don't try to "mkdir ." */
+ } else if (shar->last_dir == NULL) {
+ ret = shar_printf(a,
+ "mkdir -p %s > /dev/null 2>&1\n", p);
+ if (ret != ARCHIVE_OK)
+ return (ret);
+ shar->last_dir = p;
+ } else if (strcmp(p, shar->last_dir) == 0) {
+ /* We've already created this exact dir. */
+ free(p);
+ } else if (strlen(p) < strlen(shar->last_dir) &&
+ strncmp(p, shar->last_dir, strlen(p)) == 0) {
+ /* We've already created a subdir. */
+ free(p);
+ } else {
+ ret = shar_printf(a,
+ "mkdir -p %s > /dev/null 2>&1\n", p);
+ if (ret != ARCHIVE_OK)
+ return (ret);
+ free(shar->last_dir);
+ shar->last_dir = p;
+ }
+ }
+ }
+
+ /* Handle file-type specific issues. */
+ shar->has_data = 0;
+ if ((linkname = archive_entry_hardlink(entry)) != NULL) {
+ ret = shar_printf(a, "ln -f %s %s\n", linkname, name);
+ if (ret != ARCHIVE_OK)
+ return (ret);
+ } else if ((linkname = archive_entry_symlink(entry)) != NULL) {
+ ret = shar_printf(a, "ln -fs %s %s\n", linkname, name);
+ if (ret != ARCHIVE_OK)
+ return (ret);
+ } else {
+ switch(st->st_mode & S_IFMT) {
+ case S_IFREG:
+ if (archive_entry_size(entry) == 0) {
+ /* More portable than "touch." */
+ ret = shar_printf(a, "test -e \"%s\" || :> \"%s\"\n", name, name);
+ if (ret != ARCHIVE_OK)
+ return (ret);
+ } else {
+ if (shar->dump) {
+ ret = shar_printf(a,
+ "uudecode -o %s << 'SHAR_END'\n",
+ name);
+ if (ret != ARCHIVE_OK)
+ return (ret);
+ ret = shar_printf(a, "begin %o %s\n",
+ archive_entry_mode(entry) & 0777,
+ name);
+ if (ret != ARCHIVE_OK)
+ return (ret);
+ } else {
+ ret = shar_printf(a,
+ "sed 's/^X//' > %s << 'SHAR_END'\n",
+ name);
+ if (ret != ARCHIVE_OK)
+ return (ret);
+ }
+ shar->has_data = 1;
+ shar->end_of_line = 1;
+ shar->outpos = 0;
+ shar->outbytes = 0;
+ }
+ break;
+ case S_IFDIR:
+ ret = shar_printf(a, "mkdir -p %s > /dev/null 2>&1\n",
+ name);
+ if (ret != ARCHIVE_OK)
+ return (ret);
+ /* Record that we just created this directory. */
+ if (shar->last_dir != NULL)
+ free(shar->last_dir);
+
+ shar->last_dir = strdup(name);
+ /* Trim a trailing '/'. */
+ pp = strrchr(shar->last_dir, '/');
+ if (pp != NULL && pp[1] == '\0')
+ *pp = '\0';
+ /*
+ * TODO: Put dir name/mode on a list to be fixed
+ * up at end of archive.
+ */
+ break;
+ case S_IFIFO:
+ ret = shar_printf(a, "mkfifo %s\n", name);
+ if (ret != ARCHIVE_OK)
+ return (ret);
+ break;
+ case S_IFCHR:
+ ret = shar_printf(a, "mknod %s c %d %d\n", name,
+ archive_entry_rdevmajor(entry),
+ archive_entry_rdevminor(entry));
+ if (ret != ARCHIVE_OK)
+ return (ret);
+ break;
+ case S_IFBLK:
+ ret = shar_printf(a, "mknod %s b %d %d\n", name,
+ archive_entry_rdevmajor(entry),
+ archive_entry_rdevminor(entry));
+ if (ret != ARCHIVE_OK)
+ return (ret);
+ break;
+ default:
+ return (ARCHIVE_WARN);
+ }
+ }
+
+ return (ARCHIVE_OK);
+}
+
+/* XXX TODO: This could be more efficient XXX */
+static int
+archive_write_shar_data_sed(struct archive *a, const void *buff, size_t n)
+{
+ struct shar *shar;
+ const char *src;
+ int ret;
+
+ shar = a->format_data;
+ if (!shar->has_data)
+ return (0);
+
+ src = buff;
+ ret = ARCHIVE_OK;
+ shar->outpos = 0;
+ while (n-- > 0) {
+ if (shar->end_of_line) {
+ shar->outbuff[shar->outpos++] = 'X';
+ shar->end_of_line = 0;
+ }
+ if (*src == '\n')
+ shar->end_of_line = 1;
+ shar->outbuff[shar->outpos++] = *src++;
+
+ if (shar->outpos > sizeof(shar->outbuff) - 2) {
+ ret = (a->compression_write)(a, shar->outbuff,
+ shar->outpos);
+ if (ret != ARCHIVE_OK)
+ return (ret);
+ shar->outpos = 0;
+ }
+ }
+
+ if (shar->outpos > 0)
+ ret = (a->compression_write)(a, shar->outbuff, shar->outpos);
+ return (ret);
+}
+
+#define UUENC(c) (((c)!=0) ? ((c) & 077) + ' ': '`')
+
+/* XXX This could be a lot more efficient. XXX */
+static void
+uuencode_group(struct shar *shar)
+{
+ int t;
+
+ t = 0;
+ if (shar->uuavail > 0)
+ t = 0xff0000 & (shar->uubuffer[0] << 16);
+ if (shar->uuavail > 1)
+ t |= 0x00ff00 & (shar->uubuffer[1] << 8);
+ if (shar->uuavail > 2)
+ t |= 0x0000ff & (shar->uubuffer[2]);
+ shar->outbuff[shar->outpos++] = UUENC( 0x3f & (t>>18) );
+ shar->outbuff[shar->outpos++] = UUENC( 0x3f & (t>>12) );
+ shar->outbuff[shar->outpos++] = UUENC( 0x3f & (t>>6) );
+ shar->outbuff[shar->outpos++] = UUENC( 0x3f & (t) );
+ shar->uuavail = 0;
+ shar->outbytes += shar->uuavail;
+ shar->outbuff[shar->outpos] = 0;
+}
+
+static int
+archive_write_shar_data_uuencode(struct archive *a, const void *buff,
+ size_t length)
+{
+ struct shar *shar;
+ const char *src;
+ size_t n;
+ int ret;
+
+ shar = a->format_data;
+ if (!shar->has_data)
+ return (ARCHIVE_OK);
+ src = buff;
+ n = length;
+ while (n-- > 0) {
+ if (shar->uuavail == 3)
+ uuencode_group(shar);
+ if (shar->outpos >= 60) {
+ ret = shar_printf(a, "%c%s\n", UUENC(shar->outbytes),
+ shar->outbuff);
+ if (ret != ARCHIVE_OK)
+ return (ret);
+ shar->outpos = 0;
+ shar->outbytes = 0;
+ }
+
+ shar->uubuffer[shar->uuavail++] = *src++;
+ shar->outbytes++;
+ }
+ return (ARCHIVE_OK);
+}
+
+static int
+archive_write_shar_finish_entry(struct archive *a)
+{
+ const char *g, *p, *u;
+ struct shar *shar;
+ int ret;
+
+ shar = a->format_data;
+ if (shar->entry == NULL)
+ return (0);
+
+ if (shar->dump) {
+ /* Finish uuencoded data. */
+ if (shar->has_data) {
+ if (shar->uuavail > 0)
+ uuencode_group(shar);
+ if (shar->outpos > 0) {
+ ret = shar_printf(a, "%c%s\n",
+ UUENC(shar->outbytes), shar->outbuff);
+ if (ret != ARCHIVE_OK)
+ return (ret);
+ shar->outpos = 0;
+ shar->uuavail = 0;
+ shar->outbytes = 0;
+ }
+ ret = shar_printf(a, "%c\n", UUENC(0));
+ if (ret != ARCHIVE_OK)
+ return (ret);
+ ret = shar_printf(a, "end\n", UUENC(0));
+ if (ret != ARCHIVE_OK)
+ return (ret);
+ ret = shar_printf(a, "SHAR_END\n");
+ if (ret != ARCHIVE_OK)
+ return (ret);
+ }
+ /* Restore file mode, owner, flags. */
+ /*
+ * TODO: Don't immediately restore mode for
+ * directories; defer that to end of script.
+ */
+ ret = shar_printf(a, "chmod %o %s\n",
+ archive_entry_mode(shar->entry) & 07777,
+ archive_entry_pathname(shar->entry));
+ if (ret != ARCHIVE_OK)
+ return (ret);
+
+ u = archive_entry_uname(shar->entry);
+ g = archive_entry_gname(shar->entry);
+ if (u != NULL || g != NULL) {
+ ret = shar_printf(a, "chown %s%s%s %s\n",
+ (u != NULL) ? u : "",
+ (g != NULL) ? ":" : "", (g != NULL) ? g : "",
+ archive_entry_pathname(shar->entry));
+ if (ret != ARCHIVE_OK)
+ return (ret);
+ }
+
+ if ((p = archive_entry_fflags_text(shar->entry)) != NULL) {
+ ret = shar_printf(a, "chflags %s %s\n", p,
+ archive_entry_pathname(shar->entry));
+ if (ret != ARCHIVE_OK)
+ return (ret);
+ }
+
+ /* TODO: restore ACLs */
+
+ } else {
+ if (shar->has_data) {
+ /* Finish sed-encoded data: ensure last line ends. */
+ if (!shar->end_of_line) {
+ ret = shar_printf(a, "\n");
+ if (ret != ARCHIVE_OK)
+ return (ret);
+ }
+ ret = shar_printf(a, "SHAR_END\n");
+ if (ret != ARCHIVE_OK)
+ return (ret);
+ }
+ }
+
+ archive_entry_free(shar->entry);
+ shar->entry = NULL;
+ return (0);
+}
+
+static int
+archive_write_shar_finish(struct archive *a)
+{
+ struct shar *shar;
+ int ret;
+
+ /*
+ * TODO: Accumulate list of directory names/modes and
+ * fix them all up at end-of-archive.
+ */
+
+ shar = a->format_data;
+
+ /*
+ * Only write the end-of-archive markers if the archive was
+ * actually started. This avoids problems if someone sets
+ * shar format, then sets another format (which would invoke
+ * shar_finish to free the format-specific data).
+ */
+ if (shar->wrote_header) {
+ ret = shar_printf(a, "exit\n");
+ if (ret != ARCHIVE_OK)
+ return (ret);
+ /* Shar output is never padded. */
+ archive_write_set_bytes_in_last_block(a, 1);
+ /*
+ * TODO: shar should also suppress padding of
+ * uncompressed data within gzip/bzip2 streams.
+ */
+ }
+ if (shar->entry != NULL)
+ archive_entry_free(shar->entry);
+ if (shar->last_dir != NULL)
+ free(shar->last_dir);
+ archive_string_free(&(shar->work));
+ free(shar);
+ a->format_data = NULL;
+ return (ARCHIVE_OK);
+}
diff --git a/lib/libarchive/archive_write_set_format_ustar.c b/lib/libarchive/archive_write_set_format_ustar.c
new file mode 100644
index 0000000..95006e8
--- /dev/null
+++ b/lib/libarchive/archive_write_set_format_ustar.c
@@ -0,0 +1,498 @@
+/*-
+ * Copyright (c) 2003-2004 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(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 AUTHOR(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 "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#include <sys/stat.h>
+#ifdef MAJOR_IN_MKDEV
+#include <sys/mkdev.h>
+#else
+#ifdef MAJOR_IN_SYSMACROS
+#include <sys/sysmacros.h>
+#endif
+#endif
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "archive.h"
+#include "archive_entry.h"
+#include "archive_private.h"
+
+struct ustar {
+ uint64_t entry_bytes_remaining;
+ uint64_t entry_padding;
+ char written;
+};
+
+/*
+ * Define structure of POSIX 'ustar' tar header.
+ */
+struct archive_entry_header_ustar {
+ char name[100];
+ char mode[6];
+ char mode_padding[2];
+ char uid[6];
+ char uid_padding[2];
+ char gid[6];
+ char gid_padding[2];
+ char size[11];
+ char size_padding[1];
+ char mtime[11];
+ char mtime_padding[1];
+ char checksum[8];
+ char typeflag[1];
+ char linkname[100];
+ char magic[6]; /* For POSIX: "ustar\0" */
+ char version[2]; /* For POSIX: "00" */
+ char uname[32];
+ char gname[32];
+ char rdevmajor[6];
+ char rdevmajor_padding[2];
+ char rdevminor[6];
+ char rdevminor_padding[2];
+ char prefix[155];
+ char padding[12];
+};
+
+/*
+ * A filled-in copy of the header for initialization.
+ */
+static const struct archive_entry_header_ustar template_header = {
+ { "" }, /* name */
+ { "000000" }, { ' ', '\0' }, /* mode, space-null termination. */
+ { "000000" }, { ' ', '\0' }, /* uid, space-null termination. */
+ { "000000" }, { ' ', '\0' }, /* gid, space-null termination. */
+ { "00000000000" }, { ' ' }, /* size, space termination. */
+ { "00000000000" }, { ' ' }, /* mtime, space termination. */
+ { " " }, /* Initial checksum value. */
+ { '0' }, /* default: regular file */
+ { "" }, /* linkname */
+ { "ustar" }, /* magic */
+ { '0', '0' }, /* version */
+ { "" }, /* uname */
+ { "" }, /* gname */
+ { "000000" }, { ' ', '\0' }, /* rdevmajor, space-null termination */
+ { "000000" }, { ' ', '\0' }, /* rdevminor, space-null termination */
+ { "" }, /* prefix */
+ { "" } /* padding */
+};
+
+static int archive_write_ustar_data(struct archive *a, const void *buff,
+ size_t s);
+static int archive_write_ustar_finish(struct archive *);
+static int archive_write_ustar_finish_entry(struct archive *);
+static int archive_write_ustar_header(struct archive *,
+ struct archive_entry *entry);
+static int format_256(int64_t, char *, int);
+static int format_number(int64_t, char *, int size, int max, int strict);
+static int format_octal(int64_t, char *, int);
+static int write_nulls(struct archive *a, size_t);
+
+/*
+ * Set output format to 'ustar' format.
+ */
+int
+archive_write_set_format_ustar(struct archive *a)
+{
+ struct ustar *ustar;
+
+ /* If someone else was already registered, unregister them. */
+ if (a->format_finish != NULL)
+ (a->format_finish)(a);
+
+ ustar = malloc(sizeof(*ustar));
+ if (ustar == NULL) {
+ archive_set_error(a, ENOMEM, "Can't allocate ustar data");
+ return (ARCHIVE_FATAL);
+ }
+ memset(ustar, 0, sizeof(*ustar));
+ a->format_data = ustar;
+
+ a->pad_uncompressed = 1; /* Mimic gtar in this respect. */
+ a->format_write_header = archive_write_ustar_header;
+ a->format_write_data = archive_write_ustar_data;
+ a->format_finish = archive_write_ustar_finish;
+ a->format_finish_entry = archive_write_ustar_finish_entry;
+ a->archive_format = ARCHIVE_FORMAT_TAR_USTAR;
+ a->archive_format_name = "POSIX ustar";
+ return (ARCHIVE_OK);
+}
+
+static int
+archive_write_ustar_header(struct archive *a, struct archive_entry *entry)
+{
+ char buff[512];
+ int ret;
+ struct ustar *ustar;
+
+ ustar = a->format_data;
+ ustar->written = 1;
+
+ /* Only regular files (not hardlinks) have data. */
+ if (archive_entry_hardlink(entry) != NULL ||
+ archive_entry_symlink(entry) != NULL ||
+ !S_ISREG(archive_entry_mode(entry)))
+ archive_entry_set_size(entry, 0);
+
+ ret = __archive_write_format_header_ustar(a, buff, entry, -1, 1);
+ if (ret != ARCHIVE_OK)
+ return (ret);
+ ret = (a->compression_write)(a, buff, 512);
+ if (ret != ARCHIVE_OK)
+ return (ret);
+
+ ustar->entry_bytes_remaining = archive_entry_size(entry);
+ ustar->entry_padding = 0x1ff & (- ustar->entry_bytes_remaining);
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Format a basic 512-byte "ustar" header.
+ *
+ * Returns -1 if format failed (due to field overflow).
+ * Note that this always formats as much of the header as possible.
+ * If "strict" is set to zero, it will extend numeric fields as
+ * necessary (overwriting terminators or using base-256 extensions).
+ *
+ * This is exported so that other 'tar' formats can use it.
+ */
+int
+__archive_write_format_header_ustar(struct archive *a, char buff[512],
+ struct archive_entry *entry, int tartype, int strict)
+{
+ unsigned int checksum;
+ struct archive_entry_header_ustar *h;
+ int i, ret;
+ size_t copy_length;
+ const char *p, *pp;
+ const struct stat *st;
+ int mytartype;
+
+ ret = 0;
+ mytartype = -1;
+ /*
+ * The "template header" already includes the "ustar"
+ * signature, various end-of-field markers and other required
+ * elements.
+ */
+ memcpy(buff, &template_header, 512);
+
+ h = (struct archive_entry_header_ustar *)buff;
+
+ /*
+ * Because the block is already null-filled, and strings
+ * are allowed to exactly fill their destination (without null),
+ * I use memcpy(dest, src, strlen()) here a lot to copy strings.
+ */
+
+ pp = archive_entry_pathname(entry);
+ if (strlen(pp) <= sizeof(h->name))
+ memcpy(h->name, pp, strlen(pp));
+ else {
+ /* Store in two pieces, splitting at a '/'. */
+ p = strchr(pp + strlen(pp) - sizeof(h->name) - 1, '/');
+ /*
+ * If there is no path separator, or the prefix or
+ * remaining name are too large, return an error.
+ */
+ if (!p) {
+ archive_set_error(a, ENAMETOOLONG,
+ "Pathname too long");
+ ret = ARCHIVE_WARN;
+ } else if (p > pp + sizeof(h->prefix)) {
+ archive_set_error(a, ENAMETOOLONG,
+ "Pathname too long");
+ ret = ARCHIVE_WARN;
+ } else {
+ /* Copy prefix and remainder to appropriate places */
+ memcpy(h->prefix, pp, p - pp);
+ memcpy(h->name, p + 1, pp + strlen(pp) - p - 1);
+ }
+ }
+
+ p = archive_entry_hardlink(entry);
+ if (p != NULL)
+ mytartype = '1';
+ else
+ p = archive_entry_symlink(entry);
+ if (p != NULL && p[0] != '\0') {
+ copy_length = strlen(p);
+ if (copy_length > sizeof(h->linkname)) {
+ archive_set_error(a, ENAMETOOLONG,
+ "Link contents too long");
+ ret = ARCHIVE_WARN;
+ copy_length = sizeof(h->linkname);
+ }
+ memcpy(h->linkname, p, copy_length);
+ }
+
+ p = archive_entry_uname(entry);
+ if (p != NULL && p[0] != '\0') {
+ copy_length = strlen(p);
+ if (copy_length > sizeof(h->uname)) {
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "Username too long");
+ ret = ARCHIVE_WARN;
+ copy_length = sizeof(h->uname);
+ }
+ memcpy(h->uname, p, copy_length);
+ }
+
+ p = archive_entry_gname(entry);
+ if (p != NULL && p[0] != '\0') {
+ copy_length = strlen(p);
+ if (strlen(p) > sizeof(h->gname)) {
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "Group name too long");
+ ret = ARCHIVE_WARN;
+ copy_length = sizeof(h->gname);
+ }
+ memcpy(h->gname, p, copy_length);
+ }
+
+ st = archive_entry_stat(entry);
+
+ if (format_number(st->st_mode & 07777, h->mode, sizeof(h->mode), 8, strict)) {
+ archive_set_error(a, ERANGE, "Numeric mode too large");
+ ret = ARCHIVE_WARN;
+ }
+
+ if (format_number(st->st_uid, h->uid, sizeof(h->uid), 8, strict)) {
+ archive_set_error(a, ERANGE, "Numeric user ID too large");
+ ret = ARCHIVE_WARN;
+ }
+
+ if (format_number(st->st_gid, h->gid, sizeof(h->gid), 8, strict)) {
+ archive_set_error(a, ERANGE, "Numeric group ID too large");
+ ret = ARCHIVE_WARN;
+ }
+
+ if (format_number(st->st_size, h->size, sizeof(h->size), 12, strict)) {
+ archive_set_error(a, ERANGE, "File size out of range");
+ ret = ARCHIVE_WARN;
+ }
+
+ if (format_number(st->st_mtime, h->mtime, sizeof(h->mtime), 12, strict)) {
+ archive_set_error(a, ERANGE,
+ "File modification time too large");
+ ret = ARCHIVE_WARN;
+ }
+
+ if (S_ISBLK(st->st_mode) || S_ISCHR(st->st_mode)) {
+ if (format_number(major(st->st_rdev), h->rdevmajor,
+ sizeof(h->rdevmajor), 8, strict)) {
+ archive_set_error(a, ERANGE,
+ "Major device number too large");
+ ret = ARCHIVE_WARN;
+ }
+
+ if (format_number(minor(st->st_rdev), h->rdevminor,
+ sizeof(h->rdevminor), 8, strict)) {
+ archive_set_error(a, ERANGE,
+ "Minor device number too large");
+ ret = ARCHIVE_WARN;
+ }
+ }
+
+ if (tartype >= 0) {
+ h->typeflag[0] = tartype;
+ } else if (mytartype >= 0) {
+ h->typeflag[0] = mytartype;
+ } else {
+ switch (st->st_mode & S_IFMT) {
+ case S_IFREG: h->typeflag[0] = '0' ; break;
+ case S_IFLNK: h->typeflag[0] = '2' ; break;
+ case S_IFCHR: h->typeflag[0] = '3' ; break;
+ case S_IFBLK: h->typeflag[0] = '4' ; break;
+ case S_IFDIR: h->typeflag[0] = '5' ; break;
+ case S_IFIFO: h->typeflag[0] = '6' ; break;
+ case S_IFSOCK:
+ archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ "tar format cannot archive socket");
+ ret = ARCHIVE_WARN;
+ break;
+ default:
+ archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ "tar format cannot archive this (mode=0%lo)",
+ (unsigned long)st->st_mode);
+ ret = ARCHIVE_WARN;
+ }
+ }
+
+ checksum = 0;
+ for (i = 0; i < 512; i++)
+ checksum += 255 & (unsigned int)buff[i];
+ h->checksum[6] = '\0'; /* Can't be pre-set in the template. */
+ /* h->checksum[7] = ' '; */ /* This is pre-set in the template. */
+ format_octal(checksum, h->checksum, 6);
+ return (ret);
+}
+
+/*
+ * Format a number into a field, with some intelligence.
+ */
+static int
+format_number(int64_t v, char *p, int s, int maxsize, int strict)
+{
+ int64_t limit;
+
+ limit = ((int64_t)1 << (s*3));
+
+ /* "Strict" only permits octal values with proper termination. */
+ if (strict)
+ return (format_octal(v, p, s));
+
+ /*
+ * In non-strict mode, we allow the number to overwrite one or
+ * more bytes of the field termination. Even old tar
+ * implementations should be able to handle this with no
+ * problem.
+ */
+ if (v >= 0) {
+ while (s <= maxsize) {
+ if (v < limit)
+ return (format_octal(v, p, s));
+ s++;
+ limit <<= 3;
+ }
+ }
+
+ /* Base-256 can handle any number, positive or negative. */
+ return (format_256(v, p, maxsize));
+}
+
+/*
+ * Format a number into the specified field using base-256.
+ */
+static int
+format_256(int64_t v, char *p, int s)
+{
+ p += s;
+ while (s-- > 0) {
+ *--p = (char)(v & 0xff);
+ v >>= 8;
+ }
+ *p |= 0x80; /* Set the base-256 marker bit. */
+ return (0);
+}
+
+/*
+ * Format a number into the specified field.
+ */
+static int
+format_octal(int64_t v, char *p, int s)
+{
+ int len;
+
+ len = s;
+
+ /* Octal values can't be negative, so use 0. */
+ if (v < 0) {
+ while (len-- > 0)
+ *p++ = '0';
+ return (-1);
+ }
+
+ p += s; /* Start at the end and work backwards. */
+ while (s-- > 0) {
+ *--p = '0' + (v & 7);
+ v >>= 3;
+ }
+
+ if (v == 0)
+ return (0);
+
+ /* If it overflowed, fill field with max value. */
+ while (len-- > 0)
+ *p++ = '7';
+
+ return (-1);
+}
+
+static int
+archive_write_ustar_finish(struct archive *a)
+{
+ struct ustar *ustar;
+ int r;
+
+ r = ARCHIVE_OK;
+ ustar = a->format_data;
+ /*
+ * Suppress end-of-archive if nothing else was ever written.
+ * This fixes a problem where setting one format, then another
+ * ends up writing a gratuitous end-of-archive marker.
+ */
+ if (ustar->written && a->compression_write != NULL)
+ r = write_nulls(a, 512*2);
+ free(ustar);
+ a->format_data = NULL;
+ return (r);
+}
+
+static int
+archive_write_ustar_finish_entry(struct archive *a)
+{
+ struct ustar *ustar;
+ int ret;
+
+ ustar = a->format_data;
+ ret = write_nulls(a,
+ ustar->entry_bytes_remaining + ustar->entry_padding);
+ ustar->entry_bytes_remaining = ustar->entry_padding = 0;
+ return (ret);
+}
+
+static int
+write_nulls(struct archive *a, size_t padding)
+{
+ int ret, to_write;
+
+ while (padding > 0) {
+ to_write = padding < a->null_length ? padding : a->null_length;
+ ret = (a->compression_write)(a, a->nulls, to_write);
+ if (ret != ARCHIVE_OK)
+ return (ret);
+ padding -= to_write;
+ }
+ return (ARCHIVE_OK);
+}
+
+static int
+archive_write_ustar_data(struct archive *a, const void *buff, size_t s)
+{
+ struct ustar *ustar;
+ int ret;
+
+ ustar = a->format_data;
+ if (s > ustar->entry_bytes_remaining)
+ s = ustar->entry_bytes_remaining;
+ ret = (a->compression_write)(a, buff, s);
+ ustar->entry_bytes_remaining -= s;
+ return (ret);
+}
diff --git a/lib/libarchive/libarchive-formats.5 b/lib/libarchive/libarchive-formats.5
new file mode 100644
index 0000000..8dc2d2a
--- /dev/null
+++ b/lib/libarchive/libarchive-formats.5
@@ -0,0 +1,255 @@
+.\" Copyright (c) 2003-2004 Tim Kientzle
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING 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 27, 2004
+.Dt libarchive-formats 3
+.Os
+.Sh NAME
+.Nm libarchive-formats
+.Nd archive formats supported by the libarchive library
+.Sh DESCRIPTION
+The
+.Xr libarchive 3
+library reads and writes a variety of streaming archive formats.
+Generally speaking, all of these archive formats consist of a series of
+.Dq entries .
+Each entry stores a single file system object, such as a file, directory,
+or symbolic link.
+.Pp
+The following provides a brief description of each format supported
+by libarchive, with some information about recognized extensions or
+limitations of the current library support.
+Note that just because a format is supported by libarchive does not
+imply that a program that uses libarchive will support that format.
+Applications that use libarchive specify which formats they wish
+to support.
+.Ss Tar Formats
+The
+.Xr libarchive 3
+library can read most tar archives.
+However, it only writes POSIX-standard
+.Dq ustar
+and
+.Dq pax interchange
+formats.
+.Pp
+All tar formats store each entry in one or more 512-byte records.
+The first record is used for file metadata, including filename,
+timestamp, and mode information, and the file data is stored in
+subsequent records.
+Later variants have extended this by either appropriating undefined
+areas of the header record, extending the header to multiple records,
+or by storing special entries that modify the interpretation of
+subsequent entries.
+.Pp
+.Bl -tag -width indent
+.It Cm gnutar
+The
+.Xr libarchive 3
+library can read GNU-format tar archives.
+It currently supports the most popular GNU extensions, including
+modern long filename and linkname support, as well as atime and ctime data.
+The libarchive library does not support multi-volume
+archives, nor the old GNU long filename format.
+.It Cm pax
+The
+.Xr libarchive 3
+library can read and write POSIX-compliant pax interchange format
+archives.
+Pax interchange format archives are an extension of the older ustar
+format that adds a separate entry with additional attributes stored
+as key/value pairs.
+The presence of this additional entry is the only difference between
+pax interchange format and the older ustar format.
+The extended attributes are of unlimited length and are stored
+as UTF-8 Unicode strings.
+Keywords defined in the standard are in all lowercase; vendors are allowed
+to define custom keys by preceding them with the vendor name in all uppercase.
+When writing pax archives, libarchive uses many of the SCHILY keys
+defined by Joerg Schilling's
+.Dq star
+archiver.
+The libarchive library can read most of the SCHILY keys.
+It ignores any keywords that it does not understand.
+.It Cm restricted pax
+The libarchive library can also write pax archives in which it
+attempts to suppress the extended attributes entry whenever
+possible.
+The result will be identical to a ustar archive unless the
+extended attributes entry is required to store a long file
+name, long linkname, extended ACL, file flags, or if any of the standard
+ustar data (user name, group name, UID, GID, etc) cannot be fully
+represented in the ustar header.
+In all cases, the result can be dearchived by any program that
+can read POSIX-compliant pax interchange format archives.
+Programs that correctly read ustar format (see below) will also be
+able to read this format; any extended attributes will be extracted as
+separate files stored in
+.Pa PaxHeader
+directories.
+.It Cm ustar
+The libarchive library can both read and write this format.
+This format has the following limitations:
+.Bl -bullet -compact
+.It
+Device major and minor numbers are limited to 21 bits.
+Nodes with larger numbers will not be added to the archive.
+.It
+Path names in the archive are limited to 255 bytes.
+(Shorter if there is no / character in exactly the right place.)
+.It
+Symbolic links and hard links are stored in the archive with
+the name of the referenced file.
+This name is limited to 100 bytes.
+.It
+Extended attributes, file flags, and other extended
+security information cannot be stored.
+.It
+Archive entries are limited to 2 gigabytes in size.
+.El
+Note that the pax interchange format has none of these restrictions.
+.El
+.Pp
+The libarchive library can also read a variety of commonly-used extensions to
+the basic tar format.
+In particular, it supports base-256 values in certain numeric fields.
+This essentially removes the limitations on file size, modification time,
+and device numbers.
+.Pp
+The first tar program appeared in Sixth Edition Unix (circa 1976).
+This makes the tar format one of the oldest and most widely-supported
+archive formats.
+The first official standard for the tar file format was the
+.Dq ustar
+(Unix Standard Tar) format defined by POSIX in 1988.
+POSIX.1-2001 extended the ustar format to create the
+.Dq pax interchange
+format.
+There have also been many custom variations.
+.Ss Cpio Formats
+The libarchive library can read a number of common cpio variants and can write
+.Dq odc
+format archives.
+A cpio archive stores each entry as a fixed-size header followed
+by a variable-length filename and variable-length data.
+Unlike tar, cpio does only minimal padding of the header or file data.
+There are a variety of cpio formats, which differ primarily in
+how they store the initial header: some store the values as
+octal or hexadecimal numbers in ASCII, others as binary values of
+varying byte order and length.
+.Bl -tag -width indent
+.It Cm binary
+The libarchive library can read both big-endian and little-endian
+variants of the original binary cpio format.
+This format used 32-bit binary values for file size and mtime,
+and 16-bit binary values for the other fields.
+.It Cm odc
+The libarchive library can both read and write this
+POSIX-standard format.
+This format stores the header contents as octal values in ASCII.
+It is standard, portable, and immune from byte-order confusion.
+File sizes and mtime are limited to 33 bits (8GB file size),
+other fields are limited to 18 bits.
+.It Cm SVR4
+The libarchive library can read both CRC and non-CRC variants of
+this format.
+The SVR4 format uses eight-digit hexadecimal values for
+all header fields.
+This limits file size to 4GB, and also limits the mtime and
+other fields to 32 bits.
+The SVR4 format can optionally include a CRC of the file
+contents, although libarchive does not currently verify this CRC.
+.El
+.Pp
+Cpio is an old format that was widely used because of its simplicity
+and its support for very long filenames.
+Unfortunately, it has many limitations that make it unsuitable
+for widespread use.
+Only the POSIX format permits files over 4GB, and its 18-bit
+limit for most other fields makes it unsuitable for modern systems.
+In addition, cpio formats only store numeric UID/GID values (not
+usernames and group names), which can make it very difficult to correctly
+transfer archives across systems.
+.Ss Shar Formats
+A
+.Dq shell archive
+is a shell script that, when executed on a POSIX-compliant
+system, will recreate a collection of file system objects.
+The libarchive library can write two different kinds of shar archives:
+.Bl -tag -width indent
+.It Cm shar
+The traditional shar format uses a limited set of POSIX
+commands, including
+.Xr echo 1 ,
+.Xr mkdir 1 ,
+and
+.Xr sed 1 .
+It is suitable for portably archiving small collections of plain text files.
+However, it is not generally well-suited for large archives
+(many implementations of
+.Xr sh 1
+have limits on the size of a script) nor should it be used with non-text files.
+.It Cm shardump
+This format is similar to shar but encodes files using
+.Xr uuencode 1
+so that the result will be a plain text file regardless of the file contents.
+It also includes additional shell commands that attempt to reproduce as
+many file attributes as possible, including owner, mode, and flags.
+The additional commands used to restore file attributes make
+shardump archives less portable than plain shar archives.
+.El
+.Ss ISO9660 format
+Libarchive can read and extract from files containing ISO9660-compliant
+CDROM images.
+It also has partial support for Rockridge extensions.
+In many cases, this can remove the need to burn a physical CDROM.
+It also avoids security and complexity issues that come with
+virtual mounts and loopback devices.
+.Ss Zip format
+Libarchive can extract from most zip format archives.
+It currently only supports uncompressed entries and entries
+compressed with the
+.Dq deflate
+algorithm.
+Older zip compression algorithms are not supported.
+.Ss Tp Formats
+The libarchive library has experimental support for tp format,
+which was used in Fourth Edition through Sixth Edition Unix.
+(It was supplanted by tar in Seventh Edition Unix.)
+There were several distinct variants of this format; libarchive
+supports the original tp format and the itp variant.
+Currently, tp format support is not enabled by
+.Fn archive_read_support_format_all ,
+it must be explicitly enabled by calling
+.Fn archive_read_support_format_tp .
+.Sh SEE ALSO
+.Xr cpio 1 ,
+.Xr mkisofs 1 ,
+.Xr shar 1 ,
+.Xr tar 1 ,
+.Xr zip 1 ,
+.Xr zlib 3 ,
+.Xr tar 5
diff --git a/lib/libarchive/libarchive.3 b/lib/libarchive/libarchive.3
new file mode 100644
index 0000000..5c8976d
--- /dev/null
+++ b/lib/libarchive/libarchive.3
@@ -0,0 +1,317 @@
+.\" Copyright (c) 2003-2005 Tim Kientzle
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING 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, 2005
+.Dt LIBARCHIVE 3
+.Os
+.Sh NAME
+.Nm libarchive
+.Nd functions for reading and writing streaming archives
+.Sh LIBRARY
+.Lb libarchive
+.Sh OVERVIEW
+The
+.Nm
+library provides a flexible interface for reading and writing
+streaming archive files such as tar and cpio.
+The library is inherently stream-oriented; readers serially iterate through
+the archive, writers serially add things to the archive.
+In particular, note that there is no built-in support for
+random access nor for in-place modification.
+.Pp
+When reading an archive, the library automatically detects the
+format and the compression.
+The library currently has read support for:
+.Bl -bullet -compact
+.It
+old-style tar
+.It
+most variants of the POSIX
+.Dq ustar
+format,
+.It
+the POSIX
+.Dq pax interchange
+format,
+.It
+GNU-format tar archives,
+.It
+POSIX octet-oriented cpio archives.
+.El
+The library automatically detects archives compressed with
+.Xr gzip 1 ,
+.Xr bzip2 1 ,
+or
+.Xr compress 1
+and decompresses them transparently.
+.Pp
+When writing an archive, you can specify the compression
+to be used and the format to use.
+The library can write
+.Bl -bullet -compact
+.It
+POSIX-standard
+.Dq ustar
+archives,
+.It
+POSIX
+.Dq pax interchange format
+archives,
+.It
+POSIX octet-oriented cpio archives,
+.It
+two different variants of shar archives.
+.El
+Pax interchange format is an extension of the tar archive format that
+eliminates essentially all of the limitations of historic tar formats
+in a standard fashion that is supported
+by POSIX-compliant
+.Xr pax 1
+implementations on many systems as well as several newer implementations of
+.Xr tar 1 .
+Note that the default write format will suppress the pax extended
+attributes for most entries; explicitly requesting pax format will
+enable those attributes for all entries.
+.Pp
+The read and write APIs are accessed through the
+.Fn archive_read_XXX
+functions and the
+.Fn archive_write_XXX
+functions, respectively, and either can be used independently
+of the other.
+.Pp
+The rest of this manual page provides an overview of the library
+operation.
+More detailed information can be found in the individual manual
+pages for each API or utility function.
+.Sh READING AN ARCHIVE
+To read an archive, you must first obtain an initialized
+.Tn struct archive
+object from
+.Fn archive_read_new .
+You can then modify this object for the desired operations with the
+various
+.Fn archive_read_set_XXX
+and
+.Fn archive_read_support_XXX
+functions.
+In particular, you will need to invoke appropriate
+.Fn archive_read_support_XXX
+functions to enable the corresponding compression and format
+support.
+Note that these latter functions perform two distinct operations:
+they cause the corresponding support code to be linked into your
+program, and they enable the corresponding auto-detect code.
+Unless you have specific constraints, you will generally want
+to invoke
+.Fn archive_read_support_compression_all
+and
+.Fn archive_read_support_format_all
+to enable auto-detect for all formats and compression types
+currently supported by the library.
+.Pp
+Once you have prepared the
+.Tn struct archive
+object, you call
+.Fn archive_read_open
+to actually open the archive and prepare it for reading.
+.Pp
+Each archive entry consists of a header followed by a certain
+amount of data.
+You can obtain the next header with
+.Fn archive_read_next_header ,
+which returns a pointer to an
+.Tn struct archive_entry
+structure with information about the current archive element.
+If the entry is a regular file, then the header will be followed
+by the file data.
+You can use
+.Fn archive_read_data
+(which works much like the
+.Xr read 2
+system call)
+to read this data from the archive.
+You may prefer to use the higher-level
+.Fn archive_read_data_skip ,
+which reads and discards the data for this entry,
+.Fn archive_read_data_to_buffer ,
+which reads the data into an in-memory buffer,
+.Fn archive_read_data_to_file ,
+which copies the data to the provided file descriptor, or
+.Fn archive_read_extract ,
+which recreates the specified entry on disk and copies data
+from the archive.
+In particular, note that
+.Fn archive_read_extract
+uses the
+.Tn struct archive_entry
+structure that you provide it, which may differ from the
+entry just read from the archive.
+In particular, many applications will want to override the
+pathname, file permissions, or ownership.
+.Pp
+Once you have finished reading data from the archive, you
+should call
+.Fn archive_read_finish
+to release all resources.
+In particular,
+.Fn archive_read_finish
+closes the archive and frees any memory that was allocated by the library.
+.Pp
+The
+.Xr archive_read 3
+manual page provides more detailed calling information for this API.
+.Sh WRITING AN ARCHIVE
+You use a similar process to write an archive.
+The
+.Fn archive_write_new
+function creates an archive object useful for writing,
+the various
+.Fn archive_write_set_XXX
+functions are used to set parameters for writing the archive, and
+.Fn archive_write_open
+completes the setup and opens the archive for writing.
+.Pp
+Individual archive entries are written in a three-step
+process:
+You first initialize a
+.Tn struct archive_entry
+structure with information about the new entry.
+At a minimum, you should set the pathname of the
+entry and provide a
+.Va struct stat
+with a valid
+.Va st_mode
+field, which specifies the type of object and
+.Va st_size
+field, which specifies the size of the data portion of the object.
+The
+.Fn archive_write_header
+function actually writes the header data to the archive.
+You can then use
+.Fn archive_write_data
+to write the actual data.
+.Pp
+After all entries have been written, use the
+.Fn archive_write_finish
+function to release all resources.
+.Pp
+The
+.Xr archive_write 3
+manual page provides more detailed calling information for this API.
+.Sh DESCRIPTION
+Detailed descriptions of each function are provided by the
+corresponding manual pages.
+.Pp
+All of the functions utilize an opaque
+.Tn struct archive
+datatype that provides access to the archive contents.
+.Pp
+The
+.Tn struct archive_entry
+structure contains a complete description of a single archive
+entry.
+It uses an opaque interface that is fully documented in
+.Xr archive_entry 3 .
+.Pp
+Users familiar with historic formats should be aware that the newer
+variants have eliminated most restrictions on the length of textual fields.
+Clients should not assume that filenames, link names, user names, or
+group names are limited in length.
+In particular, pax interchange format can easily accomodate pathnames
+in arbitrary character sets that exceed
+.Va PATH_MAX .
+.Sh RETURN VALUES
+Most functions return zero on success, non-zero on error.
+The return value indicates the general severity of the error, ranging
+from
+.Cm ARCHIVE_WARNING ,
+which indicates a minor problem that should probably be reported
+to the user, to
+.Cm ARCHIVE_FATAL ,
+which indicates a serious problem that will prevent any further
+operations on this archive.
+On error, the
+.Fn archive_errno
+function can be used to retrieve a numeric error code (see
+.Xr errno 2 ) .
+The
+.Fn archive_error_string
+returns a textual error message suitable for display.
+.Pp
+.Fn archive_read_new
+and
+.Fn archive_write_new
+return pointers to an allocated and initialized
+.Tn struct archive
+object.
+.Pp
+.Fn archive_read_data
+and
+.Fn archive_write_data
+return a count of the number of bytes actually read or written.
+A value of zero indicates the end of the data for this entry.
+A negative value indicates an error, in which case the
+.Fn archive_errno
+and
+.Fn archive_error_string
+functions can be used to obtain more information.
+.Sh ENVIRONMENT
+There are character set conversions within the
+.Xr archive_entry 3
+functions that are impacted by the currently-selected locale.
+.Sh SEE ALSO
+.Xr tar 1 ,
+.Xr archive_entry 3 ,
+.Xr archive_read 3 ,
+.Xr archive_util 3 ,
+.Xr archive_write 3 ,
+.Xr tar 5
+.Sh HISTORY
+The
+.Nm libarchive
+library first appeared in
+.Fx 5.3 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm libarchive
+library was written by
+.An Tim Kientzle Aq kientzle@acm.org .
+.Sh BUGS
+Some archive formats support information that is not supported by
+.Tn struct archive_entry .
+Such information cannot be fully archived or restored using this library.
+This includes, for example, comments, character sets,
+or the arbitrary key/value pairs that can appear in
+pax interchange format archives.
+.Pp
+Conversely, of course, not all of the information that can be
+stored in an
+.Tn struct archive_entry
+is supported by all formats.
+For example, cpio formats do not support nanosecond timestamps;
+old tar formats do not support large device numbers.
diff --git a/lib/libarchive/tar.5 b/lib/libarchive/tar.5
new file mode 100644
index 0000000..242a3d0
--- /dev/null
+++ b/lib/libarchive/tar.5
@@ -0,0 +1,730 @@
+.\" Copyright (c) 2003-2004 Tim Kientzle
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING 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 20, 2004
+.Dt TAR 5
+.Os
+.Sh NAME
+.Nm tar
+.Nd format of tape archive files
+.Sh DESCRIPTION
+The
+.Nm
+archive format collects any number of files, directories, and other
+file system objects (symbolic links, device nodes, etc.) into a single
+stream of bytes.
+The format was originally designed to be used with
+tape drives that operate with fixed-size blocks, but is widely used as
+a general packaging mechanism.
+.Ss General Format
+A
+.Nm
+archive consists of a series of 512-byte records.
+Each file system object requires a header record which stores basic metadata
+(pathname, owner, permissions, etc.) and zero or more records containing any
+file data.
+The end of the archive is indicated by two records consisting
+entirely of zero bytes.
+.Pp
+For compatibility with tape drives that use fixed block sizes,
+programs that read or write tar files always read or write a fixed
+number of records with each I/O operation.
+These
+.Dq blocks
+are always a multiple of the record size.
+The most common block size\(emand the maximum supported by historic
+implementations\(emis 10240 bytes or 20 records.
+(Note: the terms
+.Dq block
+and
+.Dq record
+here are not entirely standard; this document follows the
+convention established by John Gilmore in documenting
+.Nm pdtar . )
+.Ss Old-Style Archive Format
+The original tar archive format has been extended many times to
+include additional information that various implementors found
+necessary.
+This section describes the variant implemented by the tar command
+included in
+.At v7 ,
+which is one of the earliest widely-used versions of the tar program.
+.Pp
+The header record for an old-style
+.Nm
+archive consists of the following:
+.Bd -literal -offset indent
+struct header_old_tar {
+ char name[100];
+ char mode[8];
+ char uid[8];
+ char gid[8];
+ char size[12];
+ char mtime[12];
+ char checksum[8];
+ char linkflag[1];
+ char linkname[100];
+ char pad[255];
+};
+.Ed
+All unused bytes in the header record are filled with nulls.
+.Bl -tag -width indent
+.It Va name
+Pathname, stored as a null-terminated string.
+Early tar implementations only stored regular files (including
+hardlinks to those files).
+One common early convention used a trailing "/" character to indicate
+a directory name, allowing directory permissions and owner information
+to be archived and restored.
+.It Va mode
+File mode, stored as an octal number in ASCII.
+.It Va uid , Va gid
+User id and group id of owner, as octal numbers in ASCII.
+.It Va size
+Size of file, as octal number in ASCII.
+For regular files only, this indicates the amount of data
+that follows the header.
+In particular, this field was ignored by early tar implementations
+when extracting hardlinks.
+Modern writers should always store a zero length for hardlink entries.
+.It Va mtime
+Modification time of file, as an octal number in ASCII.
+This indicates the number of seconds since the start of the epoch,
+00:00:00 UTC January 1, 1970.
+Note that negative values should be avoided
+here, as they are handled inconsistently.
+.It Va checksum
+Header checksum, stored as an octal number in ASCII.
+To compute the checksum, set the checksum field to all spaces,
+then sum all bytes in the header using unsigned arithmetic.
+This field should be stored as six octal digits followed by a null and a space
+character.
+Note that many early implementations of tar used signed arithmetic
+for the checksum field, which can cause interoperability problems
+when transferring archives between systems.
+Modern robust readers compute the checksum both ways and accept the
+header if either computation matches.
+.It Va linkflag , Va linkname
+In order to preserve hardlinks and conserve tape, a file
+with multiple links is only written to the archive the first
+time it is encountered.
+The next time it is encountered, the
+.Va linkflag
+is set to an ASCII
+.Sq 1
+and the
+.Va linkname
+field holds the first name under which this file appears.
+(Note that regular files have a null value in the
+.Va linkflag
+field.)
+.El
+.Pp
+Early tar implementations varied in how they terminated these fields.
+The tar command in
+.At v7
+used the following conventions (this is also documented in early BSD manpages):
+the pathname must be null-terminated;
+the mode, uid, and gid fields must end in a space and a null byte;
+the size and mtime fields must end in a space;
+the checksum is terminated by a null and a space.
+Early implementations filled the numeric fields with leading spaces.
+This seems to have been common practice until the
+.St -p1003.1
+standard was released.
+For best portability, modern implementations should fill the numeric
+fields with leading zeros.
+.Ss Pre-POSIX Archives
+An early draft of
+.St -p1003.1-88
+served as the basis for John Gilmore's
+.Nm pdtar
+program and many system implementations from the late 1980s
+and early 1990s.
+These archives generally follow the POSIX ustar
+format described below with the following variations:
+.Bl -bullet -compact -width indent
+.It
+The magic value is
+.Dq ustar\ \&
+(note the following space).
+The version field contains a space character followed by a null.
+.It
+The numeric fields are generally filled with leading spaces
+(not leading zeros as recommended in the final standard).
+.It
+The prefix field is often not used, limiting pathnames to
+the 100 characters of old-style archives.
+.El
+.Ss POSIX ustar Archives
+.St -p1003.1-88
+defined a standard tar file format to be read and written
+by compliant implementations of
+.Xr tar 1
+and
+.Xr pax 1 .
+This format is often called the
+.Dq ustar
+format, after the magic value used
+in the header.
+(The name is an acronym for
+.Dq Unix Standard TAR . )
+It extends the historic format with new fields:
+.Bd -literal -offset indent
+struct header_posix_ustar {
+ char name[100];
+ char mode[8];
+ char uid[8];
+ char gid[8];
+ char size[12];
+ char mtime[12];
+ char checksum[8];
+ char typeflag[1];
+ char linkname[100];
+ char magic[6];
+ char version[2];
+ char uname[32];
+ char gname[32];
+ char devmajor[8];
+ char devminor[8];
+ char prefix[155];
+ char pad[12];
+};
+.Ed
+.Bl -tag -width indent
+.It Va typeflag
+Type of entry.
+POSIX extended the earlier
+.Va linkflag
+field with several new type values:
+.Bl -tag -width indent -compact
+.It Dq 0
+Regular file.
+NULL should be treated as a synonym, for compatibility purposes.
+.It Dq 1
+Hard link.
+.It Dq 2
+Symbolic link.
+.It Dq 3
+Character device node.
+.It Dq 4
+Block device node.
+.It Dq 5
+Directory.
+.It Dq 6
+FIFO node.
+.It Dq 7
+Reserved.
+.It Other
+A POSIX-compliant implementation must treat any unrecognized typeflag value
+as a regular file.
+In particular, writers should ensure that all entries
+have a valid filename so that they can be restored by readers that do not
+support the corresponding extension.
+Uppercase letters "A" through "Z" are reserved for custom extensions.
+Note that sockets and whiteout entries are not archivable.
+.El
+It is worth noting that the
+.Va size
+field, in particular, has different meanings depending on the type.
+For regular files, of course, it indicates the amount of data
+following the header.
+For directories, it may be used to indicate the total size of all
+files in the directory, for use by operating systems that pre-allocate
+directory space.
+For all other types, it should be set to zero by writers and ignored
+by readers.
+.It Va magic
+Contains the magic value
+.Dq ustar
+followed by a NULL byte to indicate that this is a POSIX standard archive.
+Full compliance requires the uname and gname fields be properly set.
+.It Va version
+Version.
+This should be
+.Dq 00
+(two copies of the ASCII digit zero) for POSIX standard archives.
+.It Va uname , Va gname
+User and group names, as null-terminated ASCII strings.
+These should be used in preference to the uid/gid values
+when they are set and the corresponding names exist on
+the system.
+.It Va devmajor , Va devminor
+Major and minor numbers for character device or block device entry.
+.It Va prefix
+First part of pathname.
+If the pathname is too long to fit in the 100 bytes provided by the standard
+format, it can be split at any
+.Pa /
+character with the first portion going here.
+If the prefix field is not empty, the reader will prepend
+the prefix value and a
+.Pa /
+character to the regular name field to obtain the full pathname.
+.El
+.Pp
+Note that all unused bytes must be set to
+.Dv NULL .
+.Pp
+Field termination is specified slightly differently by POSIX
+than by previous implementations.
+The
+.Va magic ,
+.Va uname ,
+and
+.Va gname
+fields must have a trailing
+.Dv NULL .
+The
+.Va pathname ,
+.Va linkname ,
+and
+.Va prefix
+fields must have a trailing
+.Dv NULL
+unless they fill the entire field.
+(In particular, it is possible to store a 256-character pathname if it
+happens to have a
+.Pa /
+as the 156th character.)
+POSIX requires numeric fields to be zero-padded in the front, and allows
+them to be terminated with either space or
+.Dv NULL
+characters.
+.Pp
+Currently, most tar implementations comply with the ustar
+format, occasionally extending it by adding new fields to the
+blank area at the end of the header record.
+.Ss Pax Interchange Format
+There are many attributes that cannot be portably stored in a
+POSIX ustar archive.
+.St -p1003.1-2001
+defined a
+.Dq pax interchange format
+that uses two new types of entries to hold text-formatted
+metadata that applies to following entries.
+Note that a pax interchange format archive is a ustar archive in every
+respect.
+The new data is stored in ustar-compatible archive entries that use the
+.Dq x
+or
+.Dq g
+typeflag.
+In particular, older implementations that do not fully support these
+extensions will extract the metadata into regular files, where the
+metadata can be examined as necessary.
+.Pp
+An entry in a pax interchange format archive consists of one or
+two standard ustar entries, each with its own header and data.
+The first optional entry stores the extended attributes
+for the following entry.
+This optional first entry has an "x" typeflag and a size field that
+indicates the total size of the extended attributes.
+The extended attributes themselves are stored as a series of text-format
+lines encoded in the portable UTF-8 encoding.
+Each line consists of a decimal number, a space, a key string, an equals
+sign, a value string, and a new line.
+The decimal number indicates the length of the entire line, including the
+initial length field and the trailing newline.
+An example of such a field is:
+.Dl 25 ctime=1084839148.1212\en
+Keys in all lowercase are standard keys.
+Vendors can add their own keys by prefixing them with an all uppercase
+vendor name and a period.
+Note that, unlike the historic header, numeric values are stored using
+decimal, not octal.
+A description of some common keys follows:
+.Bl -tag -width indent
+.It Cm atime , Cm ctime , Cm mtime
+File access, inode change, and modification times.
+These fields can be negative or include a decimal point and a fractional value.
+.It Cm uname , Cm uid , Cm gname , Cm gid
+User name, group name, and numeric UID and GID values.
+The user name and group name stored here are encoded in UTF8
+and can thus include non-ASCII characters.
+The UID and GID fields can be of arbitrary length.
+.It Cm linkpath
+The full path of the linked-to file.
+Note that this is encoded in UTF8 and can thus include non-ASCII characters.
+.It Cm path
+The full pathname of the entry.
+Note that this is encoded in UTF8 and can thus include non-ASCII characters.
+.It Cm realtime.* , Cm security.*
+These keys are reserved and may be used for future standardization.
+.It Cm size
+The size of the file.
+Note that there is no length limit on this field, allowing conforming
+archives to store files much larger than the historic 8GB limit.
+.It Cm SCHILY.*
+Vendor-specific attributes used by Joerg Schilling's
+.Nm star
+implementation.
+.It Cm SCHILY.acl.access , Cm SCHILY.acl.default
+Stores the access and default ACLs as textual strings in a format
+that is an extension of the format specified by POSIX.1e draft 17.
+In particular, each user or group access specification can include a fourth
+colon-separated field with the numeric UID or GID.
+This allows ACLs to be restored on systems that may not have complete
+user or group information available (such as when NIS/YP or LDAP services
+are temporarily unavailable).
+.It Cm SCHILY.devminor , Cm SCHILY.devmajor
+The full minor and major numbers for device nodes.
+.It Cm SCHILY.dev, Cm SCHILY.ino , Cm SCHILY.nlinks
+The device number, inode number, and link count for the entry.
+In particular, note that a pax interchange format archive using Joerg
+Schilling's
+.Cm SCHILY.*
+extensions can store all of the data from
+.Va struct stat .
+.It Cm LIBARCHIVE.xattr. Ns Ar namespace Ns . Ns Ar key
+Libarchive stores POSIX.1e-style extended attributes using
+keys of this form. The
+.Ar key
+value is URL-encoded:
+All non-ASCII characters and the two special characters
+.Dq =
+and
+.Dq %
+are encoded as
+.Dq %
+followed by two uppercase hexadecimal digits.
+The value of this key is the extended attribute value
+encoded in base 64.
+XXX Detail the base-64 format here XXX
+.It Cm VENDOR.*
+XXX document other vendor-specific extensions XXX
+.El
+.Pp
+Any values stored in an extended attribute override the corresponding
+values in the regular tar header.
+Note that compliant readers should ignore the regular fields when they
+are overridden.
+This is important, as existing archivers are known to store non-compliant
+values in the standard header fields in this situation.
+There are no limits on length for any of these fields.
+In particular, numeric fields can be arbitrarily large.
+All text fields are encoded in UTF8.
+Compliant writers should store only portable 7-bit ASCII characters in
+the standard ustar header and use extended
+attributes whenever a text value contains non-ASCII characters.
+.Pp
+In addition to the
+.Cm x
+entry described above, the pax interchange format
+also supports a
+.Cm g
+entry.
+The
+.Cm g
+entry is identical in format, but specifies attributes that serve as
+defaults for all subsequent archive entries.
+The
+.Cm g
+entry is not widely used.
+.Pp
+Besides the new
+.Cm x
+and
+.Cm g
+entries, the pax interchange format has a few other minor variations
+from the earlier ustar format.
+The most troubling one is that hardlinks are permitted to have
+data following them.
+This allows readers to restore any hardlink to a file without
+having to rewind the archive to find an earlier entry.
+However, it creates complications for robust readers, as it is no longer
+clear whether or not they should ignore the size field for hardlink entries.
+.Ss GNU Tar Archives
+The GNU tar program started with a pre-POSIX format similar to that
+described earlier and has extended it using several different mechanisms:
+It added new fields to the empty space in the header (some of which was later
+used by POSIX for conflicting purposes);
+it allowed the header to be continued over multiple records;
+and it defined new entries that modify following entries
+(similar in principle to the
+.Cm x
+entry described above, but each GNU special entry is single-purpose,
+unlike the general-purpose
+.Cm x
+entry).
+As a result, GNU tar archives are not POSIX compatible, although
+more lenient POSIX-compliant readers can successfully extract most
+GNU tar archives.
+.Bd -literal -offset indent
+struct header_gnu_tar {
+ char name[100];
+ char mode[8];
+ char uid[8];
+ char gid[8];
+ char size[12];
+ char mtime[12];
+ char checksum[8];
+ char typeflag[1];
+ char linkname[100];
+ char magic[6];
+ char version[2];
+ char uname[32];
+ char gname[32];
+ char devmajor[8];
+ char devminor[8];
+ char atime[12];
+ char ctime[12];
+ char offset[12];
+ char longnames[4];
+ char unused[1];
+ struct {
+ char offset[12];
+ char numbytes[12];
+ } sparse[4];
+ char isextended[1];
+ char realsize[12];
+ char pad[17];
+};
+.Ed
+.Bl -tag -width indent
+.It Va typeflag
+GNU tar uses the following special entry types, in addition to
+those defined by POSIX:
+.Bl -tag -width indent
+.It "7"
+GNU tar treats type "7" records identically to type "0" records,
+except on one obscure RTOS where they are used to indicate the
+pre-allocation of a contiguous file on disk.
+.It "D"
+This indicates a directory entry.
+Unlike the POSIX-standard "5"
+typeflag, the header is followed by data records listing the names
+of files in this directory.
+Each name is preceded by an ASCII "Y"
+if the file is stored in this archive or "N" if the file is not
+stored in this archive.
+Each name is terminated with a null, and
+an extra null marks the end of the name list.
+The purpose of this
+entry is to support incremental backups; a program restoring from
+such an archive may wish to delete files on disk that did not exist
+in the directory when the archive was made.
+.Pp
+Note that the "D" typeflag specifically violates POSIX, which requires
+that unrecognized typeflags be restored as normal files.
+In this case, restoring the "D" entry as a file could interfere
+with subsequent creation of the like-named directory.
+.It "K"
+The data for this entry is a long linkname for the following regular entry.
+.It "L"
+The data for this entry is a long pathname for the following regular entry.
+.It "M"
+This is a continuation of the last file on the previous volume.
+GNU multi-volume archives guarantee that each volume begins with a valid
+entry header.
+To ensure this, a file may be split, with part stored at the end of one volume,
+and part stored at the beginning of the next volume.
+The "M" typeflag indicates that this entry continues an existing file.
+Such entries can only occur as the first or second entry
+in an archive (the latter only if the first entry is a volume label).
+The
+.Va size
+field specifies the size of this entry.
+The
+.Va offset
+field at bytes 369-380 specifies the offset where this file fragment
+begins.
+The
+.Va realsize
+field specifies the total size of the file (which must equal
+.Va size
+plus
+.Va offset ) .
+When extracting, GNU tar checks that the header file name is the one it is
+expecting, that the header offset is in the correct sequence, and that
+the sum of offset and size is equal to realsize.
+FreeBSD's version of GNU tar does not handle the corner case of an
+archive's being continued in the middle of a long name or other
+extension header.
+.It "N"
+Type "N" records are no longer generated by GNU tar.
+They contained a
+list of files to be renamed or symlinked after extraction; this was
+originally used to support long names.
+The contents of this record
+are a text description of the operations to be done, in the form
+.Dq Rename %s to %s\en
+or
+.Dq Symlink %s to %s\en ;
+in either case, both
+filenames are escaped using K&R C syntax.
+.It "S"
+This is a
+.Dq sparse
+regular file.
+Sparse files are stored as a series of fragments.
+The header contains a list of fragment offset/length pairs.
+If more than four such entries are required, the header is
+extended as necessary with
+.Dq extra
+header extensions (an older format that is no longer used), or
+.Dq sparse
+extensions.
+.It "V"
+The
+.Va name
+field should be interpreted as a tape/volume header name.
+This entry should generally be ignored on extraction.
+.El
+.It Va magic
+The magic field holds the five characters
+.Dq ustar
+followed by a space.
+Note that POSIX ustar archives have a trailing null.
+.It Va version
+The version field holds a space character followed by a null.
+Note that POSIX ustar archives use two copies of the ASCII digit
+.Dq 0 .
+.It Va atime , Va ctime
+The time the file was last accessed and the time of
+last change of file information, stored in octal as with
+.Va mtime .
+.It Va longnames
+This field is apparently no longer used.
+.It Sparse Va offset / Va numbytes
+Each such structure specifies a single fragment of a sparse
+file.
+The two fields store values as octal numbers.
+The fragments are each padded to a multiple of 512 bytes
+in the archive.
+On extraction, the list of fragments is collected from the
+header (including any extension headers), and the data
+is then read and written to the file at appropriate offsets.
+.It Va isextended
+If this is set to non-zero, the header will be followed by additional
+.Dq sparse header
+records.
+Each such record contains information about as many as 21 additional
+sparse blocks as shown here:
+.Bd -literal -offset indent
+struct gnu_sparse_header {
+ struct {
+ char offset[12];
+ char numbytes[12];
+ } sparse[21];
+ char isextended[1];
+ char padding[7];
+};
+.Ed
+.It Va realsize
+A binary representation of the file's complete size, with a much larger range
+than the POSIX file size.
+In particular, with
+.Cm M
+type files, the current entry is only a portion of the file.
+In that case, the POSIX size field will indicate the size of this
+entry; the
+.Va realsize
+field will indicate the total size of the file.
+.El
+.Ss Solaris Tar
+XXX More Details Needed XXX
+.Pp
+Solaris tar (beginning with SunOS XXX 5.7 ?? XXX) supports an
+.Dq extended
+format that is fundamentally similar to pax interchange format,
+with the following differences:
+.Bl -bullet -compact -width indent
+.It
+Extended attributes are stored in an entry whose type is
+.Cm X ,
+not
+.Cm x ,
+as used by pax interchange format.
+The detailed format of this entry appears to be the same
+as detailed above for the
+.Cm x
+entry.
+.It
+An additional
+.Cm A
+entry is used to store an ACL for the following regular entry.
+The body of this entry contains a seven-digit octal number
+(whose value is 01000000 plus the number of ACL entries)
+followed by a zero byte, followed by the
+textual ACL description.
+.El
+.Ss Other Extensions
+One common extension, utilized by GNU tar, star, and other newer
+.Nm
+implementations, permits binary numbers in the standard numeric
+fields.
+This is flagged by setting the high bit of the first character.
+This permits 95-bit values for the length and time fields
+and 63-bit values for the uid, gid, and device numbers.
+GNU tar supports this extension for the
+length, mtime, ctime, and atime fields.
+Joerg Schilling's star program supports this extension for
+all numeric fields.
+Note that this extension is largely obsoleted by the extended attribute
+record provided by the pax interchange format.
+.Pp
+Another early GNU extension allowed base-64 values rather
+than octal.
+This extension was short-lived and such archives are almost never seen.
+However, there is still code in GNU tar to support them; this code is
+responsible for a very cryptic warning message that is sometimes seen when
+GNU tar encounters a damaged archive.
+.Sh SEE ALSO
+.Xr ar 1 ,
+.Xr pax 1 ,
+.Xr tar 1
+.Sh STANDARDS
+The
+.Nm tar
+utility is no longer a part of POSIX or the Single Unix Standard.
+It last appeared in
+.St -susv2 .
+It has been supplanted in subsequent standards by
+.Xr pax 1 .
+The ustar format is currently part of the specification for the
+.Xr pax 1
+utility.
+The pax interchange file format is new with
+.St -p1003.1-2001 .
+.Sh HISTORY
+A
+.Nm tar
+command appeared in Seventh Edition Unix, which was released in January, 1979.
+It replaced the
+.Nm tp
+program from Fourth Edition Unix which in turn replaced the
+.Nm tap
+program from First Edition Unix.
+John Gilmore's
+.Nm pdtar
+public-domain implementation (circa 1987) was highly influential
+and formed the basis of GNU tar.
+Joerg Shilling's
+.Nm star
+archiver is another open-source (GPL) archiver (originally developed
+circa 1985) which features complete support for pax interchange
+format.
diff --git a/lib/libatm/Makefile b/lib/libatm/Makefile
new file mode 100644
index 0000000..bc5fb9d
--- /dev/null
+++ b/lib/libatm/Makefile
@@ -0,0 +1,40 @@
+# ===================================
+# HARP | Host ATM Research Platform
+# ===================================
+#
+# This Host ATM Research Platform ("HARP") file (the "Software") is
+# made available by Network Computing Services, Inc. ("NetworkCS")
+# "AS IS". NetworkCS does not provide maintenance, improvements or
+# support of any kind.
+#
+# NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
+# INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
+# SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
+# In no event shall NetworkCS be responsible for any damages, including
+# but not limited to consequential damages, arising from or relating to
+# any use of the Software or related support.
+#
+# Copyright 1994-1998 Network Computing Services, Inc.
+#
+# Copies of this Software may be made, however, the above copyright
+# notice must be reproduced on all copies.
+#
+# @(#) $Id: Makefile,v 1.5 1998/07/10 16:01:58 jpt Exp $
+# $FreeBSD$
+
+LIB= atm
+SHLIBDIR?= /lib
+SRCS= atm_addr.c cache_key.c ioctl_subr.c ip_addr.c ip_checksum.c timer.c
+INCS= libatm.h
+
+DPADD= ${LIBMD}
+LDADD= -lmd
+
+.if ${MACHINE_ARCH} == "arm"
+WARNS?= 3
+.else
+WARNS?= 6
+.endif
+
+.include <bsd.lib.mk>
diff --git a/lib/libatm/atm_addr.c b/lib/libatm/atm_addr.c
new file mode 100644
index 0000000..f4c65f2
--- /dev/null
+++ b/lib/libatm/atm_addr.c
@@ -0,0 +1,328 @@
+/*
+ *
+ * ===================================
+ * HARP | Host ATM Research Platform
+ * ===================================
+ *
+ *
+ * This Host ATM Research Platform ("HARP") file (the "Software") is
+ * made available by Network Computing Services, Inc. ("NetworkCS")
+ * "AS IS". NetworkCS does not provide maintenance, improvements or
+ * support of any kind.
+ *
+ * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
+ * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
+ * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
+ * In no event shall NetworkCS be responsible for any damages, including
+ * but not limited to consequential damages, arising from or relating to
+ * any use of the Software or related support.
+ *
+ * Copyright 1994-1998 Network Computing Services, Inc.
+ *
+ * Copies of this Software may be made, however, the above copyright
+ * notice must be reproduced on all copies.
+ */
+
+#ifndef lint
+#if 0 /* original (broken) import id */
+static char *RCSid = "@(#) $Id: atm_addr.c,v 1.1 1998/07/09 21:45:18 johnc Exp $";
+#endif
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * User Space Library Functions
+ * ----------------------------
+ *
+ * ATM address utility functions
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netatm/port.h>
+#include <netatm/atm.h>
+#include <netatm/atm_if.h>
+#include <netatm/atm_sap.h>
+#include <netatm/atm_sys.h>
+#include <netatm/atm_ioctl.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include "libatm.h"
+
+extern char *prog;
+
+/*
+ * Get NSAP, NSAP prefix or MAC address
+ *
+ * Arguments:
+ * in pointer to an address in ASCII
+ * out pointer to a buffer for the converted address
+ * len the length of the output buffer
+ *
+ * Returns:
+ * 0 error in format
+ * len the length of the data in the output buffer
+ *
+ */
+int
+get_hex_atm_addr(const char *in, u_char *out, int len)
+{
+ int c_type, c_value, i, out_len, state, val = 0;
+
+ /*
+ * Character table
+ */
+ static struct {
+ char c;
+ int type;
+ int value;
+ } char_table[] = {
+ {'.', 0, 0}, /* Type 0 -- period */
+ {':', 0, 0}, /* Type 0 -- colon */
+ {'0', 1, 0}, /* Type 1 -- hex digit */
+ {'1', 1, 1},
+ {'2', 1, 2},
+ {'3', 1, 3},
+ {'4', 1, 4},
+ {'5', 1, 5},
+ {'6', 1, 6},
+ {'7', 1, 7},
+ {'8', 1, 8},
+ {'9', 1, 9},
+ {'a', 1, 10},
+ {'b', 1, 11},
+ {'c', 1, 12},
+ {'d', 1, 13},
+ {'e', 1, 14},
+ {'f', 1, 15},
+ {'A', 1, 10},
+ {'B', 1, 11},
+ {'C', 1, 12},
+ {'D', 1, 13},
+ {'E', 1, 14},
+ {'F', 1, 15},
+ {'\0', 2, 0}, /* Type 2 -- end of input */
+ };
+
+ /*
+ * State table
+ */
+ static struct {
+ int action;
+ int state;
+ } state_table[3][3] = {
+ /* Period Hex End */
+ { { 0, 0 }, { 1, 1 }, { 2, 0} }, /* Init */
+ { { 4, 0 }, { 3, 2 }, { 4, 0} }, /* C1 */
+ { { 0, 2 }, { 1, 1 }, { 2, 0} }, /* C2 */
+ };
+
+ /*
+ * Initialize
+ */
+ state = 0;
+ out_len = 0;
+ if (!strncasecmp(in, "0x", 2)) {
+ in += 2;
+ }
+
+ /*
+ * Loop through input until state table says to return
+ */
+ while (1) {
+ /*
+ * Get the character type and value
+ */
+ for (i=0; char_table[i].c; i++)
+ if (char_table[i].c == *in)
+ break;
+ if (char_table[i].c != *in)
+ return(0);
+ c_type = char_table[i].type;
+ c_value = char_table[i].value;
+
+ /*
+ * Process next character based on state and type
+ */
+ switch(state_table[state][c_type].action) {
+ case 0:
+ /*
+ * Ignore the character
+ */
+ break;
+
+ case 1:
+ /*
+ * Save the character's value
+ */
+ val = c_value;
+ break;
+
+ case 2:
+ /*
+ * Return the assembled NSAP
+ */
+ return(out_len);
+
+ case 3:
+ /*
+ * Assemble and save the output byte
+ */
+ val = val << 4;
+ val += c_value;
+ out[out_len] = (u_char) val;
+ out_len++;
+ if (out_len > len)
+ (void)fprintf(stderr, "%s() out_len > len (%d > %d)\n",
+ __func__, out_len, len);
+
+ break;
+
+ case 4:
+ /*
+ * Invalid input sequence
+ */
+ return(0);
+
+ default:
+ return(0);
+ }
+
+ /*
+ * Set the next state and go on to the next character
+ */
+ state = state_table[state][c_type].state;
+ in++;
+ }
+}
+
+
+/*
+ * Format an ATM address into a string
+ *
+ * Arguments:
+ * addr pointer to an atm address
+ *
+ * Returns:
+ * none
+ *
+ */
+char *
+format_atm_addr(const Atm_addr *addr)
+{
+ int i;
+ const char *nsap_format;
+ const Atm_addr_nsap *atm_nsap;
+ const Atm_addr_e164 *atm_e164;
+ const Atm_addr_spans *atm_spans;
+ const Atm_addr_pvc *atm_pvc;
+ static char str[256];
+ union {
+ int w;
+ char c[4];
+ } u1, u2;
+
+ static const char nsap_format_DCC[] = "0x%02x.%02x%02x.%02x.%02x%02x%02x.%02x%02x.%02x%02x.%02x%02x.%02x%02x%02x%02x%02x%02x.%02x";
+ static const char nsap_format_ICD[] = "0x%02x.%02x%02x.%02x.%02x%02x%02x.%02x%02x.%02x%02x.%02x%02x.%02x%02x%02x%02x%02x%02x.%02x";
+ static const char nsap_format_E164[] = "0x%02x.%02x%02x%02x%02x%02x%02x%02x%02x.%02x%02x.%02x%02x.%02x%02x%02x%02x%02x%02x.%02x";
+
+ /*
+ * Clear the returned string
+ */
+ bzero(str, sizeof(str));
+ strcpy(str, "-");
+
+ /*
+ * Print format is determined by address type
+ */
+ switch (addr->address_format) {
+ case T_ATM_ENDSYS_ADDR:
+ atm_nsap = (const Atm_addr_nsap *)addr->address;
+ switch(atm_nsap->aan_afi) {
+ default:
+ case AFI_DCC:
+ nsap_format = nsap_format_DCC;
+ break;
+ case AFI_ICD:
+ nsap_format = nsap_format_ICD;
+ break;
+ case AFI_E164:
+ nsap_format = nsap_format_E164;
+ break;
+ }
+ sprintf(str, nsap_format,
+ atm_nsap->aan_afi,
+ atm_nsap->aan_afspec[0],
+ atm_nsap->aan_afspec[1],
+ atm_nsap->aan_afspec[2],
+ atm_nsap->aan_afspec[3],
+ atm_nsap->aan_afspec[4],
+ atm_nsap->aan_afspec[5],
+ atm_nsap->aan_afspec[6],
+ atm_nsap->aan_afspec[7],
+ atm_nsap->aan_afspec[8],
+ atm_nsap->aan_afspec[9],
+ atm_nsap->aan_afspec[10],
+ atm_nsap->aan_afspec[11],
+ atm_nsap->aan_esi[0],
+ atm_nsap->aan_esi[1],
+ atm_nsap->aan_esi[2],
+ atm_nsap->aan_esi[3],
+ atm_nsap->aan_esi[4],
+ atm_nsap->aan_esi[5],
+ atm_nsap->aan_sel);
+ break;
+
+ case T_ATM_E164_ADDR:
+ atm_e164 = (const Atm_addr_e164 *)addr->address;
+ for(i=0; i<addr->address_length; i++) {
+ sprintf(&str[strlen(str)], "%c",
+ atm_e164->aae_addr[i]);
+ }
+ break;
+
+ case T_ATM_SPANS_ADDR:
+ /*
+ * Print SPANS address as two words, xxxx.yyyy
+ */
+ atm_spans = (const Atm_addr_spans *)addr->address;
+ u1.c[0] = atm_spans->aas_addr[0];
+ u1.c[1] = atm_spans->aas_addr[1];
+ u1.c[2] = atm_spans->aas_addr[2];
+ u1.c[3] = atm_spans->aas_addr[3];
+
+ u2.c[0] = atm_spans->aas_addr[4];
+ u2.c[1] = atm_spans->aas_addr[5];
+ u2.c[2] = atm_spans->aas_addr[6];
+ u2.c[3] = atm_spans->aas_addr[7];
+
+ if (!(u1.w == 0 && u2.w == 0))
+ sprintf(str, "0x%08lx.%08lx",
+ (u_long)ntohl(u1.w), (u_long)ntohl(u2.w));
+ break;
+
+ case T_ATM_PVC_ADDR:
+ /*
+ * Print PVC as VPI, VCI
+ */
+ atm_pvc = (const Atm_addr_pvc *)addr->address;
+ sprintf(str, "%d, %d",
+ ATM_PVC_GET_VPI(atm_pvc),
+ ATM_PVC_GET_VCI(atm_pvc));
+ break;
+
+ case T_ATM_ABSENT:
+ default:
+ break;
+ }
+
+ return(str);
+}
diff --git a/lib/libatm/cache_key.c b/lib/libatm/cache_key.c
new file mode 100644
index 0000000..8e212e6
--- /dev/null
+++ b/lib/libatm/cache_key.c
@@ -0,0 +1,104 @@
+/*
+ *
+ * ===================================
+ * HARP | Host ATM Research Platform
+ * ===================================
+ *
+ *
+ * This Host ATM Research Platform ("HARP") file (the "Software") is
+ * made available by Network Computing Services, Inc. ("NetworkCS")
+ * "AS IS". NetworkCS does not provide maintenance, improvements or
+ * support of any kind.
+ *
+ * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
+ * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
+ * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
+ * In no event shall NetworkCS be responsible for any damages, including
+ * but not limited to consequential damages, arising from or relating to
+ * any use of the Software or related support.
+ *
+ * Copyright 1994-1998 Network Computing Services, Inc.
+ *
+ * Copies of this Software may be made, however, the above copyright
+ * notice must be reproduced on all copies.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * User Space Library Functions
+ * ----------------------------
+ *
+ * SCSP cache key computation
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netatm/port.h>
+#include <netatm/atm.h>
+#include <netatm/atm_if.h>
+#include <netatm/atm_sap.h>
+#include <netatm/atm_sys.h>
+#include <netatm/atm_ioctl.h>
+
+#include <md5.h>
+#include <string.h>
+
+#include "libatm.h"
+
+/*
+ * Compute an SCSP cache key
+ *
+ * Arguments:
+ * ap pointer to an Atm_addr with the ATM address
+ * ip pointer to a struct in_addr with the IP address
+ * ol the required length of the cache key
+ * op pointer to receive cache key
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+scsp_cache_key(const Atm_addr *ap, const struct in_addr *ip, int ol, char *op)
+{
+ int i, len;
+ char buff[32], digest[16];
+ MD5_CTX context;
+
+ /*
+ * Initialize
+ */
+ bzero(buff, sizeof(buff));
+
+ /*
+ * Copy the addresses into a buffer for MD5 computation
+ */
+ len = sizeof(struct in_addr) + ap->address_length;
+ if (len > (int)sizeof(buff))
+ len = sizeof(buff);
+ bcopy(ip, buff, sizeof(struct in_addr));
+ bcopy(ap->address, &buff[sizeof(struct in_addr)],
+ len - sizeof(struct in_addr));
+
+ /*
+ * Compute the MD5 digest of the combined IP and ATM addresses
+ */
+ MD5Init(&context);
+ MD5Update(&context, buff, len);
+ MD5Final(digest, &context);
+
+ /*
+ * Fold the 16-byte digest to the required length
+ */
+ bzero((caddr_t)op, ol);
+ for (i = 0; i < 16; i++) {
+ op[i % ol] = op[i % ol] ^ digest[i];
+ }
+}
diff --git a/lib/libatm/ioctl_subr.c b/lib/libatm/ioctl_subr.c
new file mode 100644
index 0000000..f7b15f1
--- /dev/null
+++ b/lib/libatm/ioctl_subr.c
@@ -0,0 +1,461 @@
+/*
+ *
+ * ===================================
+ * HARP | Host ATM Research Platform
+ * ===================================
+ *
+ *
+ * This Host ATM Research Platform ("HARP") file (the "Software") is
+ * made available by Network Computing Services, Inc. ("NetworkCS")
+ * "AS IS". NetworkCS does not provide maintenance, improvements or
+ * support of any kind.
+ *
+ * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
+ * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
+ * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
+ * In no event shall NetworkCS be responsible for any damages, including
+ * but not limited to consequential damages, arising from or relating to
+ * any use of the Software or related support.
+ *
+ * Copyright 1994-1998 Network Computing Services, Inc.
+ *
+ * Copies of this Software may be made, however, the above copyright
+ * notice must be reproduced on all copies.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * User Space Library Functions
+ * ----------------------------
+ *
+ * IOCTL subroutines
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netatm/port.h>
+#include <netatm/atm.h>
+#include <netatm/atm_if.h>
+#include <netatm/atm_sap.h>
+#include <netatm/atm_sys.h>
+#include <netatm/atm_ioctl.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "libatm.h"
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+extern char *prog;
+
+
+/*
+ * Issue an informational IOCTL
+ *
+ * The user fills out the opcode and any subtype information. This
+ * routine will allocate a buffer and issue the IOCTL. If the request
+ * fails because the buffer wasn't big enough, this routine will double
+ * the buffer size and retry the request repeatedly. The buffer must
+ * be freed by the caller.
+ *
+ * Arguments:
+ * req pointer to an ATM information request IOCTL structure
+ * buf_len length of buffer to be allocated
+ *
+ * Returns:
+ * -1 error encountered (reason in errno)
+ * int length of the returned VCC information
+ *
+ */
+ssize_t
+do_info_ioctl(struct atminfreq *req, size_t buf_len)
+{
+ int rc, s;
+ caddr_t buf;
+
+ /*
+ * Open a socket for the IOCTL
+ */
+ s = socket(AF_ATM, SOCK_DGRAM, 0);
+ if (s < 0) {
+ return(-1);
+ }
+
+ /*
+ * Get memory for returned information
+ */
+mem_retry:
+ buf = malloc(buf_len);
+ if (buf == NULL) {
+ errno = ENOMEM;
+ return(-1);
+ }
+ bzero(buf, buf_len);
+
+ /*
+ * Set the buffer address and length in the request
+ */
+ req->air_buf_addr = buf;
+ req->air_buf_len = buf_len;
+
+ /*
+ * Issue the IOCTL
+ */
+ rc = ioctl(s, AIOCINFO, (caddr_t)req);
+ if (rc) {
+ free(buf);
+ if (errno == ENOSPC) {
+ buf_len = buf_len * 2;
+ goto mem_retry;
+ }
+ return(-1);
+ }
+ (void)close(s);
+ /*
+ * Set a pointer to the returned info in the request
+ * and return its length
+ */
+ req->air_buf_addr = buf;
+ return(req->air_buf_len);
+}
+
+
+/*
+ * Get VCC information
+ *
+ * Arguments:
+ * intf pointer to interface name (or null string)
+ * vccp pointer to a pointer to a struct air_vcc_rsp for the
+ * address of the returned VCC information
+ *
+ * Returns:
+ * int length of the retuned VCC information
+ *
+ */
+ssize_t
+get_vcc_info(const char *intf, struct air_vcc_rsp **vccp)
+{
+ size_t buf_len = sizeof(struct air_vcc_rsp) * 100;
+ struct atminfreq air;
+
+ /*
+ * Initialize IOCTL request
+ */
+ air.air_opcode = AIOCS_INF_VCC;
+ bzero(air.air_vcc_intf, sizeof(air.air_vcc_intf));
+ if (intf != NULL && strlen(intf) != 0)
+ strncpy(air.air_vcc_intf, intf, IFNAMSIZ - 1);
+
+ buf_len = do_info_ioctl(&air, buf_len);
+
+ /*
+ * Return a pointer to the VCC info and its length
+ */
+ *vccp = (struct air_vcc_rsp *)(void *)air.air_buf_addr;
+ return(buf_len);
+}
+
+
+/*
+ * Get subnet mask
+ *
+ * Arguments:
+ * intf pointer to an interface name
+ * mask pointer to a struct sockaddr_in to receive the mask
+ *
+ * Returns:
+ * 0 good completion
+ * -1 error
+ *
+ */
+int
+get_subnet_mask(const char *intf, struct sockaddr_in *mask)
+{
+ int rc, s;
+ struct ifreq req;
+ struct sockaddr_in *ip_mask;
+
+ /*
+ * Check parameters
+ */
+ if (!intf || !mask ||
+ strlen(intf) == 0 ||
+ strlen(intf) > IFNAMSIZ-1)
+ return(-1);
+
+ /*
+ * Open a socket for the IOCTL
+ */
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0)
+ return(-1);
+
+ /*
+ * Set up and issue the IOCTL
+ */
+ bzero(&req, sizeof(req));
+ strcpy(req.ifr_name, intf);
+ rc = ioctl(s, SIOCGIFNETMASK, (caddr_t)&req);
+ (void)close(s);
+ if (rc)
+ return(-1);
+
+ /*
+ * Give the answer back to the caller
+ */
+ ip_mask = (struct sockaddr_in *)(void *)&req.ifr_addr;
+ *mask = *ip_mask;
+ mask->sin_family = AF_INET;
+
+ return(0);
+}
+
+
+/*
+ * Get an interface's MTU
+ *
+ * Arguments:
+ * intf pointer to an interface name
+ * mtu pointer to an int to receive the MTU
+ *
+ * Returns:
+ * >= 0 interface MTU
+ * -1 error
+ *
+ */
+int
+get_mtu(const char *intf)
+{
+ int rc, s;
+ struct ifreq req;
+
+ /*
+ * Check parameters
+ */
+ if (!intf || strlen(intf) == 0 ||
+ strlen(intf) > IFNAMSIZ-1)
+ return(-1);
+
+ /*
+ * Open a socket for the IOCTL
+ */
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0)
+ return(-1);
+
+ /*
+ * Set up and issue the IOCTL
+ */
+ bzero(&req, sizeof(req));
+ strcpy(req.ifr_name, intf);
+ rc = ioctl(s, SIOCGIFMTU, (caddr_t)&req);
+ (void)close(s);
+
+ /*
+ * Set the appropriate return value
+ */
+ if (rc)
+ return(-1);
+ else
+ return(req.ifr_mtu);
+}
+
+
+/*
+ * Verify netif name
+ *
+ * This routine issues an IOCTL to check whether the passed string is
+ * a valid network interface name.
+ *
+ * Arguments:
+ * req pointer to an ATM information request IOCTL structure
+ *
+ * Returns:
+ * -1 error encountered
+ * FALSE (0) the string is not a NIF name
+ * TRUE (> 0) the string is a valid NIF name
+ *
+ */
+int
+verify_nif_name(const char *name)
+{
+ int rc, s;
+ struct atminfreq air;
+ struct air_netif_rsp *nif_info;
+
+ /*
+ * Check whether name is of a valid length
+ */
+ if (strlen(name) > IFNAMSIZ - 1 ||
+ strlen(name) < 1) {
+ return(FALSE);
+ }
+
+ /*
+ * Open a socket for the IOCTL
+ */
+ s = socket(AF_ATM, SOCK_DGRAM, 0);
+ if (s < 0) {
+ return(-1);
+ }
+
+ /*
+ * Get memory for returned information
+ */
+ nif_info = malloc(sizeof(struct air_netif_rsp));
+ if (nif_info == NULL) {
+ errno = ENOMEM;
+ return(-1);
+ }
+ bzero(nif_info, sizeof(struct air_netif_rsp));
+
+ /*
+ * Set up the request
+ */
+ air.air_opcode = AIOCS_INF_NIF;
+ air.air_buf_addr = (caddr_t)nif_info;
+ air.air_buf_len = sizeof(struct air_netif_rsp);
+ bzero(air.air_netif_intf, sizeof(air.air_netif_intf));
+ strcpy(air.air_netif_intf, name);
+
+ /*
+ * Issue the IOCTL
+ */
+ rc = ioctl(s, AIOCINFO, (caddr_t)&air);
+ free(nif_info);
+ (void)close(s);
+
+ /*
+ * Base return value on IOCTL return code
+ */
+ if (rc)
+ return(FALSE);
+ else
+ return(TRUE);
+}
+
+/*
+ * Get Config information
+ *
+ * Arguments:
+ * intf pointer to interface name (or null string)
+ * cfgp pointer to a pointer to a struct air_cfg_rsp for the
+ * address of the returned Config information
+ *
+ * Returns:
+ * int length of returned Config information
+ *
+ */
+ssize_t
+get_cfg_info(const char *intf, struct air_cfg_rsp **cfgp)
+{
+ size_t buf_len = sizeof(struct air_cfg_rsp) * 4;
+ struct atminfreq air;
+
+ /*
+ * Initialize IOCTL request
+ */
+ air.air_opcode = AIOCS_INF_CFG;
+ bzero ( air.air_cfg_intf, sizeof(air.air_cfg_intf));
+ if ( intf != NULL && strlen(intf) != 0 )
+ strncpy(air.air_cfg_intf, intf, IFNAMSIZ - 1);
+
+ buf_len = do_info_ioctl ( &air, buf_len );
+
+ /*
+ * Return a pointer to the Config info and its length
+ */
+ *cfgp = (struct air_cfg_rsp *)(void *)air.air_buf_addr;
+ return ( buf_len );
+
+}
+
+/*
+ * Get Physical Interface information
+ *
+ * Arguments:
+ * intf pointer to interface name (or null string)
+ * intp pointer to a pointer to a struct air_cfg_rsp for the
+ * address of the returned Config information
+ *
+ * Returns:
+ * int length of returned Config information
+ *
+ */
+ssize_t
+get_intf_info(const char *intf, struct air_int_rsp **intp)
+{
+ size_t buf_len = sizeof(struct air_int_rsp) * 4;
+ struct atminfreq air;
+
+ /*
+ * Initialize IOCTL request
+ */
+ air.air_opcode = AIOCS_INF_INT;
+ bzero ( air.air_int_intf, sizeof(air.air_int_intf));
+ if ( intf != NULL && strlen(intf) != 0 )
+ strncpy(air.air_int_intf, intf, IFNAMSIZ - 1);
+
+ buf_len = do_info_ioctl ( &air, buf_len );
+
+ /*
+ * Return a pointer to the Physical Interface info and its length
+ */
+ *intp = (struct air_int_rsp *)(void *)air.air_buf_addr;
+ return ( buf_len );
+
+}
+
+
+/*
+ * Get Netif information
+ *
+ * Arguments:
+ * intf pointer to interface name (or null string)
+ * netp pointer to a pointer to a struct air_netif_rsp for the
+ * address of the returned Netif information
+ *
+ * Returns:
+ * int length of returned Netif information
+ *
+ */
+ssize_t
+get_netif_info(const char *intf, struct air_netif_rsp **netp)
+{
+ size_t buf_len = sizeof(struct air_netif_rsp) * 10;
+ struct atminfreq air;
+
+ /*
+ * Initialize IOCTL request
+ */
+ air.air_opcode = AIOCS_INF_NIF;
+ bzero ( air.air_int_intf, sizeof(air.air_int_intf) );
+ if ( intf != NULL && strlen(intf) != 0 )
+ strncpy(air.air_int_intf, intf, IFNAMSIZ - 1);
+
+ buf_len = do_info_ioctl ( &air, buf_len );
+
+ /*
+ * Return a pointer to the Netif info and its length
+ */
+ *netp = (struct air_netif_rsp *) air.air_buf_addr;
+ return ( buf_len );
+
+}
diff --git a/lib/libatm/ip_addr.c b/lib/libatm/ip_addr.c
new file mode 100644
index 0000000..d3a5276
--- /dev/null
+++ b/lib/libatm/ip_addr.c
@@ -0,0 +1,160 @@
+/*
+ *
+ * ===================================
+ * HARP | Host ATM Research Platform
+ * ===================================
+ *
+ *
+ * This Host ATM Research Platform ("HARP") file (the "Software") is
+ * made available by Network Computing Services, Inc. ("NetworkCS")
+ * "AS IS". NetworkCS does not provide maintenance, improvements or
+ * support of any kind.
+ *
+ * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
+ * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
+ * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
+ * In no event shall NetworkCS be responsible for any damages, including
+ * but not limited to consequential damages, arising from or relating to
+ * any use of the Software or related support.
+ *
+ * Copyright 1994-1998 Network Computing Services, Inc.
+ *
+ * Copies of this Software may be made, however, the above copyright
+ * notice must be reproduced on all copies.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * User Space Library Functions
+ * ----------------------------
+ *
+ * IP address utilities
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <stdio.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netatm/port.h>
+#include <netatm/atm.h>
+#include <netatm/atm_if.h>
+#include <netatm/atm_sap.h>
+#include <netatm/atm_sys.h>
+#include <netatm/atm_ioctl.h>
+
+#include <netdb.h>
+#include <string.h>
+
+#include "libatm.h"
+
+/*
+ * Get IP address
+ *
+ * Return an IP address in a socket address structure, given a character
+ * string with a domain name or a dotted decimal number.
+ *
+ * Arguments:
+ * p pointer to a host name or IP address
+ *
+ * Returns:
+ * null error was encountered
+ * struct sockaddr_in * a pointer to a socket address with the
+ * requested IP address
+ *
+ */
+struct sockaddr_in *
+get_ip_addr(const char *p)
+{
+ struct hostent *ip_host;
+ static struct sockaddr_in s;
+
+ /*
+ * Get IP address of specified host name
+ */
+ bzero(&s, sizeof(s));
+ s.sin_family = AF_INET;
+ if (p[0] >= '0' && p[0] <= '9') {
+ /*
+ * IP address is in dotted decimal format
+ */
+ if ((s.sin_addr.s_addr = inet_addr(p)) == INADDR_NONE) {
+ return((struct sockaddr_in *)0);
+ }
+ } else {
+ /*
+ * Host name is in domain name system format
+ */
+ ip_host = gethostbyname(p);
+ if (!ip_host ||
+ ip_host->h_addrtype != AF_INET) {
+ return((struct sockaddr_in *)0);
+ }
+ memcpy(&s.sin_addr.s_addr, ip_host->h_addr_list[0],
+ sizeof(s.sin_addr.s_addr));
+ }
+ return(&s);
+}
+
+
+/*
+ * Format an IP address
+ *
+ * Return a text-formatted string with an IP address and domain name
+ * given a sockaddr_in with an IP address.
+ *
+ * Arguments:
+ * addr pointer to sockaddr_in with an IP address
+ *
+ * Returns:
+ * char * pointer to a text-formatted string
+ *
+ */
+const char *
+format_ip_addr(const struct in_addr *addr)
+{
+ static char host_name[MAXHOSTNAMELEN + 18];
+ char *ip_num;
+ struct hostent *ip_host;
+
+ /*
+ * Initialize
+ */
+ bzero(host_name, sizeof(host_name));
+
+ /*
+ * Check for a zero address
+ */
+ if (!addr || addr->s_addr == 0) {
+ return("-");
+ }
+
+ /*
+ * Get address in dotted decimal format
+ */
+ ip_num = inet_ntoa(*addr);
+
+ /*
+ * Look up name in DNS
+ */
+ ip_host = gethostbyaddr((const char *)addr, sizeof(addr), AF_INET);
+ if (ip_host && ip_host->h_name && strlen(ip_host->h_name)) {
+ /*
+ * Return host name followed by dotted decimal address
+ */
+ snprintf(host_name, sizeof(host_name), "%s (%s)",
+ ip_host->h_name, ip_num);
+ return (host_name);
+ } else {
+ /*
+ * No host name -- just return dotted decimal address
+ */
+ return(ip_num);
+ }
+}
diff --git a/lib/libatm/ip_checksum.c b/lib/libatm/ip_checksum.c
new file mode 100644
index 0000000..2881c24
--- /dev/null
+++ b/lib/libatm/ip_checksum.c
@@ -0,0 +1,92 @@
+/*
+ *
+ * ===================================
+ * HARP | Host ATM Research Platform
+ * ===================================
+ *
+ *
+ * This Host ATM Research Platform ("HARP") file (the "Software") is
+ * made available by Network Computing Services, Inc. ("NetworkCS")
+ * "AS IS". NetworkCS does not provide maintenance, improvements or
+ * support of any kind.
+ *
+ * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
+ * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
+ * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
+ * In no event shall NetworkCS be responsible for any damages, including
+ * but not limited to consequential damages, arising from or relating to
+ * any use of the Software or related support.
+ *
+ * Copyright 1994-1998 Network Computing Services, Inc.
+ *
+ * Copies of this Software may be made, however, the above copyright
+ * notice must be reproduced on all copies.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * User Space Library Functions
+ * ----------------------------
+ *
+ * IP checksum computation
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netatm/port.h>
+#include <netatm/atm.h>
+#include <netatm/atm_if.h>
+#include <netatm/atm_sap.h>
+#include <netatm/atm_sys.h>
+#include <netatm/atm_ioctl.h>
+
+#include "libatm.h"
+
+/*
+ * Compute an IP checksum
+ *
+ * This code was taken from RFC 1071.
+ *
+ * "The following "C" code algorithm computes the checksum with an inner
+ * loop that sums 16 bits at a time in a 32-bit accumulator."
+ *
+ * Arguments:
+ * addr pointer to the buffer whose checksum is to be computed
+ * count number of bytes to include in the checksum
+ *
+ * Returns:
+ * the computed checksum
+ *
+ */
+short
+ip_checksum(const char *addr, int count)
+{
+ /* Compute Internet Checksum for "count" bytes
+ * beginning at location "addr".
+ */
+ long sum = 0;
+
+ while( count > 1 ) {
+ /* This is the inner loop */
+ sum += ntohs(* (const unsigned short *)(const void *)addr);
+ addr += sizeof(unsigned short);
+ count -= sizeof(unsigned short);
+ }
+
+ /* Add left-over byte, if any */
+ if( count > 0 )
+ sum += * (const unsigned char *) addr;
+
+ /* Fold 32-bit sum to 16 bits */
+ while (sum>>16)
+ sum = (sum & 0xffff) + (sum >> 16);
+
+ return((short)~sum);
+}
diff --git a/lib/libatm/libatm.h b/lib/libatm/libatm.h
new file mode 100644
index 0000000..1c2088f
--- /dev/null
+++ b/lib/libatm/libatm.h
@@ -0,0 +1,117 @@
+/*
+ *
+ * ===================================
+ * HARP | Host ATM Research Platform
+ * ===================================
+ *
+ *
+ * This Host ATM Research Platform ("HARP") file (the "Software") is
+ * made available by Network Computing Services, Inc. ("NetworkCS")
+ * "AS IS". NetworkCS does not provide maintenance, improvements or
+ * support of any kind.
+ *
+ * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
+ * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
+ * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
+ * In no event shall NetworkCS be responsible for any damages, including
+ * but not limited to consequential damages, arising from or relating to
+ * any use of the Software or related support.
+ *
+ * Copyright 1994-1998 Network Computing Services, Inc.
+ *
+ * Copies of this Software may be made, however, the above copyright
+ * notice must be reproduced on all copies.
+ *
+ * @(#) $FreeBSD$
+ *
+ */
+
+/*
+ * User Space Library Functions
+ * ----------------------------
+ *
+ * Library functions
+ *
+ */
+
+#ifndef _HARP_LIBHARP_H
+#define _HARP_LIBHARP_H
+
+/*
+ * Start a HARP user-space timer
+ *
+ * tp pointer to timer control block
+ * time number of seconds for timer to run
+ * fp pointer to function to call at expiration
+ */
+#define HARP_TIMER(tp, time, fp) \
+{ \
+ (tp)->ht_ticks = (time); \
+ (tp)->ht_mark = 0; \
+ (tp)->ht_func = (fp); \
+ LINK2HEAD((tp), Harp_timer, harp_timer_head, ht_next); \
+}
+
+/*
+ * Cancel a HARP user-space timer
+ *
+ * tp pointer to timer control block
+ */
+#define HARP_CANCEL(tp) \
+{ \
+ UNLINK((tp), Harp_timer, harp_timer_head, ht_next); \
+}
+
+
+/*
+ * HARP user-space timer control block
+ */
+struct harp_timer {
+ struct harp_timer *ht_next; /* Timer chain */
+ int ht_ticks; /* Seconds till exp */
+ int ht_mark; /* Processing flag */
+ void (*ht_func)(struct harp_timer *); /* Function to call */
+};
+typedef struct harp_timer Harp_timer;
+
+
+/*
+ * Externally-visible variables and functions
+ */
+
+/* atm_addr.c */
+extern int get_hex_atm_addr(const char *, u_char *, int);
+extern char *format_atm_addr(const Atm_addr *);
+
+/* cache_key.c */
+extern void scsp_cache_key(const Atm_addr *,
+ const struct in_addr *, int, char *);
+
+/* ioctl_subr.c */
+extern ssize_t do_info_ioctl(struct atminfreq *, size_t);
+extern ssize_t get_vcc_info(const char *, struct air_vcc_rsp **);
+extern int get_subnet_mask(const char *, struct sockaddr_in *);
+extern int get_mtu(const char *);
+extern int verify_nif_name(const char *);
+extern ssize_t get_cfg_info(const char *, struct air_cfg_rsp **);
+extern ssize_t get_intf_info(const char *, struct air_int_rsp **);
+extern ssize_t get_netif_info(const char *, struct air_netif_rsp **);
+
+/* ip_addr.c */
+extern struct sockaddr_in *get_ip_addr(const char *);
+extern const char *format_ip_addr(const struct in_addr *);
+
+/* ip_checksum.c */
+extern short ip_checksum(const char *, int);
+
+/* timer.c */
+extern Harp_timer *harp_timer_head;
+extern int harp_timer_exec;
+extern void timer_proc(void);
+extern int init_timer(void);
+extern int block_timer(void);
+extern void enable_timer(int);
+
+
+#endif /* _HARP_LIBHARP_H */
diff --git a/lib/libatm/timer.c b/lib/libatm/timer.c
new file mode 100644
index 0000000..1870e55
--- /dev/null
+++ b/lib/libatm/timer.c
@@ -0,0 +1,258 @@
+/*
+ *
+ * ===================================
+ * HARP | Host ATM Research Platform
+ * ===================================
+ *
+ *
+ * This Host ATM Research Platform ("HARP") file (the "Software") is
+ * made available by Network Computing Services, Inc. ("NetworkCS")
+ * "AS IS". NetworkCS does not provide maintenance, improvements or
+ * support of any kind.
+ *
+ * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
+ * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
+ * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
+ * In no event shall NetworkCS be responsible for any damages, including
+ * but not limited to consequential damages, arising from or relating to
+ * any use of the Software or related support.
+ *
+ * Copyright 1994-1998 Network Computing Services, Inc.
+ *
+ * Copies of this Software may be made, however, the above copyright
+ * notice must be reproduced on all copies.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * User Space Library Functions
+ * ----------------------------
+ *
+ * Timer functions
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netatm/port.h>
+#include <netatm/queue.h>
+#include <netatm/atm.h>
+#include <netatm/atm_if.h>
+#include <netatm/atm_sap.h>
+#include <netatm/atm_sys.h>
+#include <netatm/atm_ioctl.h>
+
+#include <errno.h>
+#include <signal.h>
+
+#include "libatm.h"
+
+Harp_timer *harp_timer_head;
+int harp_timer_exec;
+
+
+/*
+ * Process a HARP timer tick
+ *
+ * This function is called via the SIGALRM signal. It increments
+ * harp_timer_exec. The user should check this flag frequently and
+ * call timer_proc when it is set.
+ *
+ * Arguments:
+ * None
+ *
+ * Returns:
+ * None
+ *
+ */
+static void
+timer_tick(void)
+{
+ /*
+ * Bump the timer flag
+ */
+ harp_timer_exec++;
+}
+
+
+/*
+ * Process HARP timers
+ *
+ * This function is called after a SIGALRM signal is posted. It runs
+ * down the list of timer entries, calling the specified functions
+ * for any timers that have expired.
+ *
+ * Arguments:
+ * None
+ *
+ * Returns:
+ * None
+ *
+ */
+void
+timer_proc(void)
+{
+ Harp_timer *htp;
+ void (*f)(Harp_timer *);
+
+ /*
+ * Reset marks in all timers on the queue
+ */
+ for (htp = harp_timer_head; htp; htp = htp->ht_next) {
+ htp->ht_mark = -1;
+ }
+
+ /*
+ * Run through timer chain decrementing each timer.
+ * If an expired timer is found, take the timer block
+ * off the chain and call the specified function. A
+ * timer's action can result in other timers being
+ * cancelled (taken off the queue), so every time we
+ * call a user function, we start over from the top of
+ * the list.
+ */
+timer_cont:
+ for (htp = harp_timer_head; htp; htp = htp->ht_next) {
+ /*
+ * Make sure we only process each entry once and
+ * don't process entries that are put on the queue
+ * by user functions we call for this tick
+ */
+ if (htp->ht_mark == -1) {
+ /*
+ * Decrement the timer and mark that we've
+ * processed the entry
+ */
+ htp->ht_ticks -= harp_timer_exec;
+ htp->ht_mark = 1;
+
+ /*
+ * Check whether the timer is expired
+ */
+ if (htp->ht_ticks <= 0) {
+ /*
+ * Unlink the timer block and call
+ * the user function
+ */
+ f = htp->ht_func;
+ UNLINK(htp, Harp_timer, harp_timer_head,
+ ht_next);
+ f(htp);
+
+ /*
+ * Start over
+ */
+ goto timer_cont;
+ }
+ }
+ }
+
+ /*
+ * Reset the timer exec flag
+ */
+ harp_timer_exec = 0;
+}
+
+
+/*
+ * Start the timer
+ *
+ * Set up the SIGALRM signal handler and set up the real-time
+ * timer to tick once per second.
+ *
+ * Arguments:
+ * None
+ *
+ * Returns:
+ * 0 success
+ * errno reason for failure
+ *
+ */
+int
+init_timer()
+{
+ int rc = 0;
+ struct itimerval timeval;
+
+ /*
+ * Clear the timer flag
+ */
+ harp_timer_exec = 0;
+
+ /*
+ * Set up signal handler
+ */
+ if (signal(SIGALRM, (sig_t)timer_tick) == SIG_ERR) {
+ return(errno);
+ }
+
+ /*
+ * Start timer
+ */
+ timeval.it_value.tv_sec = 1;
+ timeval.it_value.tv_usec = 0;
+ timeval.it_interval.tv_sec = 1;
+ timeval.it_interval.tv_usec = 0;
+
+ if (setitimer(ITIMER_REAL, &timeval,
+ (struct itimerval *)0) == -1) {
+ rc = errno;
+ (void)signal(SIGALRM, SIG_DFL);
+ }
+
+ return(rc);
+}
+
+
+/*
+ * Block timers from firing
+ *
+ * Block the SIGALRM signal.
+ *
+ * Arguments:
+ * None
+ *
+ * Returns:
+ * mask the previous blocked signal mask
+ *
+ */
+int
+block_timer()
+{
+ /*
+ * Block the SIGALRM signal
+ */
+ return(sigblock(sigmask(SIGALRM)));
+}
+
+
+/*
+ * Re-enable timers
+ *
+ * Restore the signal mask (presumably one that was returned by
+ * block_timer).
+ *
+ * Arguments:
+ * mask the signal mask to be restored
+ *
+ * Returns:
+ * mask the previous blocked signal mask
+ *
+ */
+void
+enable_timer(mask)
+ int mask;
+{
+ /*
+ * Set the signal mask
+ */
+ sigsetmask(mask);
+
+ return;
+}
diff --git a/lib/libautofs/Makefile b/lib/libautofs/Makefile
new file mode 100644
index 0000000..744bc63
--- /dev/null
+++ b/lib/libautofs/Makefile
@@ -0,0 +1,12 @@
+# $Id: Makefile,v 1.5 2004/09/08 08:12:21 bright Exp $
+# $FreeBSD$
+
+LIB= autofs
+SHLIB_MAJOR= 1
+WARNS?= 4
+
+SRCS= libautofs.c
+INCS= libautofs.h
+MAN= libautofs.3
+
+.include <bsd.lib.mk>
diff --git a/lib/libautofs/libautofs.3 b/lib/libautofs/libautofs.3
new file mode 100644
index 0000000..f4e07a9
--- /dev/null
+++ b/lib/libautofs/libautofs.3
@@ -0,0 +1,265 @@
+.\" Copyright (c) 2004 Alfred Perlstein <alfred@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.
+.\"
+.\" $Id: libautofs.3,v 1.4 2004/09/08 08:12:21 bright Exp $
+.\" $FreeBSD$
+.Dd September 9, 2004
+.Dt LIBAUTOFS 3
+.Os
+.Sh NAME
+.Nm libautofs
+.Nd "procedural interface to managing an autofs file system"
+.Sh SYNOPSIS
+.In libautofs.h
+.Ft int
+.Fn autoh_get "const char *path" "autoh_t *hndlp"
+.Ft void
+.Fn autoh_free "autoh_t hndl"
+.Ft int
+.Fn autoh_getall "autoh_t **hndlpp" "int *cnt"
+.Ft void
+.Fn autoh_freeall "autoh_t *hndlep"
+.Ft int
+.Fn autoh_fd "autoh_t hndl"
+.Ft const char *
+.Fn autoh_mp "autoh_t hndl"
+.Ft int
+.Fn autoreq_get "autoh_t hndl" "autoreq_t **reqpp" "int *cntp"
+.Ft void
+.Fn autoreq_free "autoh_t hndl" "autoreq_t *reqp"
+.Ft int
+.Fn autoreq_serv "autoh_t hndl" "autoreq_t req"
+.Ft enum autoreq_op
+.Fn autoreq_getop "autoreq_t req"
+.Ft const char *
+.Fn autoreq_getpath "autoreq_t req"
+.Ft autoino_t
+.Fn autoreq_getino "autoreq_t req"
+.Ft autoino_t
+.Fn autoreq_getdirino "autoreq_t req"
+.Ft void
+.Fn autoreq_getaux "autoreq_t req" "void **auxdatap" "size_t *auxsizep"
+.Ft void
+.Fn autoreq_getoffset "autoreq_t req" "off_t *offp"
+.Ft void
+.Fn autoreq_getxid "autoreq_t req" "int *xidp"
+.Ft void
+.Fn autoreq_setino "autoreq_t req" "autoino_t ino"
+.Ft void
+.Fn autoreq_seterrno "autoreq_t req" "int errno"
+.Ft void
+.Fn autoreq_setaux "autoreq_t req" "void *auxdata" "size_t auxsize"
+.Ft void
+.Fn autoreq_seteof "autoreq_t req" "int eof"
+.Ft int
+.Fn autoh_togglepath "autoh_t hndl" "int toggle" "pid_t pid" "const char *path"
+.Ft int
+.Fn autoh_togglefd "autoh_t hndl" "int toggle" "pid_t pid" "int fd"
+.Sh DESCRIPTION
+The
+.Nm libautofs
+library provides a "mostly" stable interface to the
+.Xr autofs 9
+file system.
+.Pp
+The interface to
+.Xr autofs 9
+is managed via handles of type
+.Fa autoh_t
+and
+.Fa autoreq_t
+which refer to handles to
+.Xr autofs 9
+mount points and requests respectively.
+.Pp
+The
+.Fn autoh_get
+function returns a handle to an
+.Xr autofs 9
+file system based on the
+.Fa path
+parameter.
+The handle returned should be freed via the
+.Fn autoh_free
+function.
+.Pp
+The
+.Fn autoh_getall
+function returns an array of handles to all mounted
+.Xr autofs 9
+file systems, each of which should be released via the
+.Fn autoh_free
+function or released en-mass via the
+.Fn autoh_freeall
+function.
+.Pp
+The
+.Fn autoh_fd
+function returns a file descriptor that can be used with
+.Xr select 2
+or
+.Xr poll 2
+to check for "exceptional" data to detect an
+.Xr autofs 9
+event.
+Users of
+.Xr select 2
+should set the fd in the
+.Fa exceptfds
+fd_set.
+Users of
+.Xr poll 2
+should set POLLPRI in the pollfd
+.Fa fds
+argument.
+.Pp
+The
+.Fn autoh_mp
+function returns the path to the autofs file system that the
+.Fa hndl
+is derived from.
+.Pp
+The
+.Fn autoreq_get
+function returns an array of autofs requests in
+.Fa reqpp ,
+the number of requests is stored into
+.Fa cntp .
+Each request should be released using the
+.Fn autoreq_free
+function.
+.Pp
+Requests that are retrieved via the
+.Fn autoreq_get
+are served via the "autoreq_" functions.
+.Pp
+The following functions returns information about the request.
+.Bl -tag -width indent
+.It Fn autoreq_getop
+return the operation type of the request, that would be one of
+AUTOREQ_OP_UNKNOWN, AUTOREQ_OP_LOOKUP, AUTOREQ_OP_STAT, AUTOREQ_OP_READDIR
+depending on the type of request that
+.Xr autofs 9
+requires service from.
+.It Fn autoreq_getpath
+return the path of the mountpoint associated with the request
+.Fa req .
+.It Fn autoreq_getino
+return the inode associated with the request
+.Fa req .
+.It Fn autoreq_getdirno
+return the directory inode associated with the request
+.Fa req .
+.It Fn autoreq_getaux
+return the auxiliary data associated with the request
+.Fa req .
+.It Fn autoreq_getoffset
+return the offset request associated with the request
+.Fa req .
+(used for readdir request)
+.It Fn autoreq_getxid
+return the transaction id associated with an autofs request, these
+are unique per mount point, but not system wide.
+They can be used
+for debugging to ensure requests are being accepted by the kernel.
+.El
+.Pp
+The following functions allow one to set the response sent to
+.Xr autofs 9
+to the requesting userland application.
+.Bl -tag -width indent
+.It Fn autoreq_setino
+Set the request
+.Fa req
+inode to
+.Fa ino ,
+this is typically unused.
+.It Fn autoreq_seterrno
+set the error returned to the application sending the request, typically
+this is left alone, or set to ENOENT if the request is for a non-existent
+name.
+The default error is no error.
+Meaning the application will see
+a successful return.
+.It Fn autoreq_setaux
+used to set the auxiliary data for a request, currently used to set
+the dirent structures for serving a readdir request.
+Default is no
+auxiliary data.
+.It Fn autoreq_seteof
+used to set the eof flag for readdir requests (default is not eof.)
+.El
+.Pp
+The functions
+.Fn autoh_togglepath
+and
+.Fn autoh_togglefd
+are used to set options on an
+.Xr autofs 9
+directory via
+.Fa path
+and
+.Fa fd
+respectively.
+The
+.Fa pid
+argument should be set to the pid of the process serving
+.Xr autofs 9
+requests, or -1 to disable the option.
+The options are
+.Bl -tag -width AUTO_INDIRECT
+.It Fa AUTO_MOUNTER
+set this process as the one responsible for the
+.Xr autofs 9
+node, if this process exits, then requests into the autofs will begin to fail.
+.It Fa AUTO_BROWSE
+dispatch directory read requests for this node to the process identified by
+.Fa pid .
+Specifically, calls to
+.Xr getdirentries 2
+and
+.Xr getdents 2
+will be routed to userland after the current actual directory contents
+are read into userland.
+.It Fa AUTO_DIRECT
+Set the directory as a mount trigger.
+Any request to enter the directory
+will trigger a callback into the process
+.Fa pid .
+.It Fa AUTO_INDIRECT
+Set the directory as an indirect trigger.
+Any request for an entry inside
+the directory will be routed to the process identified by
+.Fa pid .
+.El
+.Sh EXAMPLES
+See /usr/share/examples/autofs/driver/
+.Sh HISTORY
+The
+.Nm
+utility first appeared in
+.Fx 6.0 .
+.Sh AUTHORS
+This manual page and the autofs file system suite were written by
+.An Alfred Perlstein .
diff --git a/lib/libautofs/libautofs.c b/lib/libautofs/libautofs.c
new file mode 100644
index 0000000..459b32d
--- /dev/null
+++ b/lib/libautofs/libautofs.c
@@ -0,0 +1,479 @@
+/*
+ * Copyright (c) 2004 Alfred Perlstein <alfred@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$
+ * $Id: libautofs.c,v 1.5 2004/09/08 08:44:12 bright Exp $
+ */
+#include <err.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <sys/poll.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+
+#ifdef AUTOFSSTANDALONE
+#include "../autofs/autofs.h"
+#else
+#include <fs/autofs/autofs.h>
+#endif
+
+#include "libautofs.h"
+
+struct auto_handle {
+ char ah_mp[MNAMELEN];
+ fsid_t ah_fsid;
+ int ah_fd;
+};
+
+static int autofs_sysctl(int, fsid_t *, void *, size_t *, void *, size_t);
+static void safe_free(void *ptr);
+static int getmntlst(struct statfs **sfsp, int *cntp);
+
+static void
+safe_free(void *ptr)
+{
+ int saved_errno;
+
+ saved_errno = errno;
+ free(ptr);
+ errno = saved_errno;
+}
+
+int
+getmntlst(struct statfs **sfsp, int *cntp)
+{
+ int cnt;
+ long bufsize;
+
+ *sfsp = NULL;
+ cnt = getfsstat(NULL, 0, MNT_NOWAIT);
+ bufsize = cnt * sizeof(**sfsp);
+ /*fprintf(stderr, "getmntlst bufsize %ld, cnt %d\n", bufsize, cnt);*/
+ *sfsp = malloc(bufsize);
+ if (sfsp == NULL)
+ goto err;
+ cnt = getfsstat(*sfsp, bufsize, MNT_NOWAIT);
+ if (cnt == -1)
+ goto err;
+ *cntp = cnt;
+ /*fprintf(stderr, "getmntlst ok, cnt %d\n", cnt);*/
+ return (0);
+err:
+ safe_free(sfsp);
+ *sfsp = NULL;
+ /*fprintf(stderr, "getmntlst bad\n");*/
+ return (-1);
+}
+
+/* get a handle based on a path. */
+int
+autoh_get(const char *path, autoh_t *ahp)
+{
+ struct statfs *sfsp, *sp;
+ int cnt, fd, i;
+ autoh_t ret;
+
+ ret = NULL;
+ /*
+ * We use getfsstat to prevent avoid the lookups on the mountpoints
+ * that statfs(2) would do.
+ */
+ if (getmntlst(&sfsp, &cnt))
+ goto err;
+ for (i = 0; i < cnt; i++) {
+ if (strcmp(sfsp[i].f_mntonname, path) == 0)
+ break;
+ }
+ if (i == cnt) {
+ /*fprintf(stderr, "autoh_get bad %d %d\n", i, cnt);*/
+ errno = ENOENT;
+ goto err;
+ }
+ sp = &sfsp[i];
+ if (strcmp(sp->f_fstypename, "autofs")) {
+ errno = ENOTTY;
+ goto err;
+ }
+ fd = open(sp->f_mntonname, O_RDONLY);
+ if (fd == -1)
+ goto err;
+ ret = malloc(sizeof(*ret));
+ if (ret == NULL)
+ goto err;
+
+ ret->ah_fsid = sp->f_fsid;
+ ret->ah_fd = fd;
+ strlcpy(ret->ah_mp, sp->f_mntonname, sizeof(ret->ah_mp));
+ safe_free(sfsp);
+ *ahp = ret;
+ return (0);
+err:
+ safe_free(ret);
+ safe_free(sfsp);
+ return (-1);
+}
+
+/* release. */
+void
+autoh_free(autoh_t ah)
+{
+ int saved_errno;
+
+ saved_errno = errno;
+ close(ah->ah_fd);
+ free(ah);
+ errno = saved_errno;
+}
+
+/*
+ * Get an array of pointers to all the currently mounted autofs
+ * instances.
+ */
+int
+autoh_getall(autoh_t **arrayp, int *cntp)
+{
+ struct statfs *sfsp;
+ int cnt, i, pos;
+ autoh_t *array;
+
+ array = NULL;
+ /*
+ * We use getfsstat to prevent avoid the lookups on the mountpoints
+ * that statfs(2) would do.
+ */
+ if (getmntlst(&sfsp, &cnt))
+ goto err;
+ array = *arrayp = calloc(cnt + 1, sizeof(**arrayp));
+ if (array == NULL)
+ goto err;
+ for (i = 0, pos = 0; i < cnt; i++) {
+ if (autoh_get(sfsp[i].f_mntonname, &array[pos]) == -1) {
+ /* not an autofs entry, that's ok, otherwise bail */
+ if (errno == ENOTTY)
+ continue;
+ goto err;
+ }
+ pos++;
+ }
+ if (pos == 0) {
+ errno = ENOENT;
+ goto err;
+ }
+ *arrayp = array;
+ *cntp = pos;
+ safe_free(sfsp);
+ return (0);
+err:
+ safe_free(sfsp);
+ if (array)
+ autoh_freeall(array);
+ return (-1);
+}
+
+/* release. */
+void
+autoh_freeall(autoh_t *ah)
+{
+ autoh_t *ahp;
+
+ ahp = ah;
+
+ while (*ahp != NULL) {
+ autoh_free(*ahp);
+ ahp++;
+ }
+ safe_free(ah);
+}
+
+/* return fd to select on. */
+int
+autoh_fd(autoh_t ah)
+{
+
+ return (ah->ah_fd);
+}
+
+const char *
+autoh_mp(autoh_t ah)
+{
+
+ return (ah->ah_mp);
+}
+
+static int do_autoreq_get(autoh_t ah, autoreq_t *reqp, int *cntp);
+
+/* get an array of pending requests */
+int
+autoreq_get(autoh_t ah, autoreq_t **reqpp, int *cntp)
+{
+ int cnt, i;
+ autoreq_t req, *reqp;
+
+ if (do_autoreq_get(ah, &req, &cnt))
+ return (-1);
+
+ reqp = calloc(cnt + 1, sizeof(*reqp));
+ if (reqp == NULL) {
+ safe_free(req);
+ return (-1);
+ }
+ for (i = 0; i < cnt; i++)
+ reqp[i] = &req[i];
+ *reqpp = reqp;
+ *cntp = cnt;
+ return (0);
+}
+
+int
+do_autoreq_get(autoh_t ah, autoreq_t *reqp, int *cntp)
+{
+ size_t olen;
+ struct autofs_userreq *reqs;
+ int cnt, error;
+ int vers;
+
+ vers = AUTOFS_PROTOVERS;
+
+ error = 0;
+ reqs = NULL;
+ olen = 0;
+ cnt = 0;
+ error = autofs_sysctl(AUTOFS_CTL_GETREQS, &ah->ah_fsid, NULL, &olen,
+ &vers, sizeof(vers));
+ if (error == -1)
+ goto out;
+ if (olen == 0)
+ goto out;
+
+ reqs = malloc(olen);
+ if (reqs == NULL)
+ goto out;
+ error = autofs_sysctl(AUTOFS_CTL_GETREQS, &ah->ah_fsid, reqs, &olen,
+ &vers, sizeof(vers));
+ if (error == -1)
+ goto out;
+out:
+ if (error) {
+ safe_free(reqs);
+ return (-1);
+ }
+ cnt = olen / sizeof(*reqs);
+ *cntp = cnt;
+ *reqp = reqs;
+ return (0);
+}
+
+/* free an array of requests */
+void
+autoreq_free(autoh_t ah __unused, autoreq_t *req)
+{
+
+ free(*req);
+ free(req);
+}
+
+/* serve a request */
+int
+autoreq_serv(autoh_t ah, autoreq_t req)
+{
+ int error;
+
+ error = autofs_sysctl(AUTOFS_CTL_SERVREQ, &ah->ah_fsid, NULL, NULL,
+ req, sizeof(*req));
+ return (error);
+}
+
+enum autoreq_op
+autoreq_getop(autoreq_t req)
+{
+
+ switch (req->au_op) {
+ case AREQ_LOOKUP:
+ return (AUTOREQ_OP_LOOKUP);
+ case AREQ_STAT:
+ return (AUTOREQ_OP_STAT);
+ case AREQ_READDIR:
+ return (AUTOREQ_OP_READDIR);
+ default:
+ return (AUTOREQ_OP_UNKNOWN);
+ }
+}
+
+/* get a request's file name. */
+const char *
+autoreq_getpath(autoreq_t req)
+{
+
+ return (req->au_name);
+}
+
+/* get a request's inode. a indirect mount may return AUTO_INODE_NONE. */
+autoino_t
+autoreq_getino(autoreq_t req)
+{
+
+ return (req->au_ino);
+}
+
+void
+autoreq_setino(autoreq_t req, autoino_t ino)
+{
+
+ req->au_ino = ino;
+}
+
+/* get a request's directory inode. */
+autoino_t
+autoreq_getdirino(autoreq_t req)
+{
+
+ return (req->au_dino);
+}
+
+void
+autoreq_seterrno(autoreq_t req, int error)
+{
+
+ req->au_errno = error;
+}
+
+void
+autoreq_setaux(autoreq_t req, void *auxdata, size_t auxlen)
+{
+
+ req->au_auxdata = auxdata;
+ req->au_auxlen = auxlen;
+}
+
+void
+autoreq_getaux(autoreq_t req, void **auxdatap, size_t *auxlenp)
+{
+
+ *auxdatap = req->au_auxdata;
+ *auxlenp = req->au_auxlen;
+}
+
+void
+autoreq_seteof(autoreq_t req, int eof)
+{
+
+ req->au_eofflag = eof;
+}
+
+void
+autoreq_getoffset(autoreq_t req, off_t *offp)
+{
+
+ *offp = req->au_offset - AUTOFS_USEROFF;
+}
+
+void
+autoreq_getxid(autoreq_t req, int *xid)
+{
+
+ *xid = req->au_xid;
+}
+
+/* toggle by path. args = handle, AUTO_?, pid (-1 to disable), path. */
+int
+autoh_togglepath(autoh_t ah, int op, pid_t pid, const char *path)
+{
+ int fd, ret;
+
+ fd = open(path, O_RDONLY);
+ if (fd == -1)
+ return (-1);
+ ret = autoh_togglefd(ah, op, pid, fd);
+ close(fd);
+ return (ret);
+}
+
+/* toggle by fd. args = handle, AUTO_?, pid (-1 to disable), fd. */
+int
+autoh_togglefd(autoh_t ah, int op, pid_t pid, int fd)
+{
+ struct stat sb;
+ struct autofs_mounterreq mr;
+ int error, realop;
+
+ switch (op) {
+ case AUTO_DIRECT:
+ realop = AUTOFS_CTL_TRIGGER;
+ break;
+ case AUTO_INDIRECT:
+ realop = AUTOFS_CTL_SUBTRIGGER;
+ break;
+ case AUTO_MOUNTER:
+ realop = AUTOFS_CTL_MOUNTER;
+ break;
+ case AUTO_BROWSE:
+ realop = AUTOFS_CTL_BROWSE;
+ break;
+ default:
+ errno = ENOTTY;
+ return (-1);
+ }
+
+ if (fstat(fd, &sb))
+ return (-1);
+ bzero(&mr, sizeof(mr));
+ mr.amu_ino = sb.st_ino;
+ mr.amu_pid = pid;
+ error = autofs_sysctl(realop, &ah->ah_fsid, NULL, NULL,
+ &mr, sizeof(mr));
+ return (error);
+}
+
+int
+autofs_sysctl(op, fsid, oldp, oldlenp, newp, newlen)
+ int op;
+ fsid_t *fsid;
+ void *oldp;
+ size_t *oldlenp;
+ void *newp;
+ size_t newlen;
+{
+ struct vfsidctl vc;
+
+ bzero(&vc, sizeof(vc));
+ vc.vc_op = op;
+ strcpy(vc.vc_fstypename, "*");
+ vc.vc_vers = VFS_CTL_VERS1;
+ vc.vc_fsid = *fsid;
+ vc.vc_ptr = newp;
+ vc.vc_len = newlen;
+ return (sysctlbyname("vfs.autofs.ctl", oldp, oldlenp, &vc, sizeof(vc)));
+}
+
diff --git a/lib/libautofs/libautofs.h b/lib/libautofs/libautofs.h
new file mode 100644
index 0000000..f391bad
--- /dev/null
+++ b/lib/libautofs/libautofs.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2004 Alfred Perlstein <alfred@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$
+ * $Id: libautofs.h,v 1.4 2004/09/08 08:12:21 bright Exp $
+ */
+#ifndef _LIBAUTOFS_H
+#define _LIBAUTOFS_H
+
+struct auto_handle;
+typedef struct auto_handle * autoh_t;
+struct autofs_userreq;
+typedef struct autofs_userreq * autoreq_t;
+typedef uint64_t autoino_t;
+
+#define AUTO_INODE_NONE 0
+
+#define AUTO_DIRECT 1
+#define AUTO_INDIRECT 2
+#define AUTO_MOUNTER 3
+#define AUTO_BROWSE 4
+
+enum autoreq_op {
+ AUTOREQ_OP_UNKNOWN = 0,
+ AUTOREQ_OP_LOOKUP,
+ AUTOREQ_OP_STAT,
+ AUTOREQ_OP_READDIR
+};
+
+/* get a handle based on a path. */
+int autoh_get(const char *, autoh_t *);
+/* release. */
+void autoh_free(autoh_t);
+
+/*
+ * Get an array of pointers to handles for all autofs mounts, returns count
+ * or -1
+ */
+int autoh_getall(autoh_t **, int *cnt);
+/* free the array of pointers */
+void autoh_freeall(autoh_t *);
+
+/* return fd to select on. */
+int autoh_fd(autoh_t);
+
+/* returns the mount point of the autofs instance. */
+const char *autoh_mp(autoh_t);
+
+/* get an array of pending requests */
+int autoreq_get(autoh_t, autoreq_t **, int *);
+/* free an array of requests */
+void autoreq_free(autoh_t, autoreq_t *);
+/* serve a request */
+int autoreq_serv(autoh_t, autoreq_t);
+
+/* get the operation requested */
+enum autoreq_op autoreq_getop(autoreq_t);
+
+/* get a request's file name. */
+const char *autoreq_getpath(autoreq_t);
+/* get a request's inode. a indirect mount may return AUTO_INODE_NONE. */
+autoino_t autoreq_getino(autoreq_t);
+/*
+ * set a request's inode. an indirect mount may return AUTO_INODE_NONE,
+ * this is a fixup for indirect mounts.
+ */
+void autoreq_setino(autoreq_t, autoino_t);
+/* get a request's directory inode. */
+autoino_t autoreq_getdirino(autoreq_t);
+void autoreq_seterrno(autoreq_t, int);
+void autoreq_setaux(autoreq_t, void *, size_t);
+void autoreq_getaux(autoreq_t, void **, size_t *);
+void autoreq_seteof(autoreq_t, int);
+void autoreq_getoffset(autoreq_t, off_t *);
+void autoreq_getxid(autoreq_t, int *);
+
+/* toggle by path. args = handle, AUTO_?, pid (-1 to disable), path. */
+int autoh_togglepath(autoh_t, int, pid_t, const char *);
+/* toggle by fd. args = handle, AUTO_?, pid (-1 to disable), fd. */
+int autoh_togglefd(autoh_t, int, pid_t, int);
+
+#endif
diff --git a/lib/libbegemot/Makefile b/lib/libbegemot/Makefile
new file mode 100644
index 0000000..1b728aa
--- /dev/null
+++ b/lib/libbegemot/Makefile
@@ -0,0 +1,28 @@
+# $FreeBSD$
+
+LIBBEGEMOT_DIR=${.CURDIR}/../../contrib/libbegemot
+
+.PATH: ${LIBBEGEMOT_DIR}
+
+LIB= begemot
+SHLIB_MAJOR= 2
+SHLIBDIR?= /lib
+
+# WARNS?= 6
+
+CFLAGS+= -DUSE_SELECT -DQUADFMT='"ll"'
+SRCS= rpoll.c
+INCS= rpoll.h
+MAN= rpoll.3
+
+CLEANFILES= rpoll.3
+rpoll.3: rpoll.man
+ cat ${.ALLSRC} > ${.TARGET}
+
+MLINKS= rpoll.3 poll_register.3 \
+ rpoll.3 poll_unregister.3 \
+ rpoll.3 poll_start_timer.3 \
+ rpoll.3 poll_stop_timer.3 \
+ rpoll.3 poll_dispatch.3
+
+.include <bsd.lib.mk>
diff --git a/lib/libbluetooth/Makefile b/lib/libbluetooth/Makefile
new file mode 100644
index 0000000..200f7e1
--- /dev/null
+++ b/lib/libbluetooth/Makefile
@@ -0,0 +1,30 @@
+# $Id: Makefile,v 1.5 2003/07/22 18:38:04 max Exp $
+# $FreeBSD$
+
+LIB= bluetooth
+MAN= bluetooth.3
+
+WARNS?= 2
+CFLAGS+= -I${.CURDIR} -I${.CURDIR}/../../sys
+
+SHLIB_MAJOR= 2
+
+SRCS= bluetooth.c
+INCS= bluetooth.h
+
+MLINKS+= bluetooth.3 bt_gethostbyname.3
+MLINKS+= bluetooth.3 bt_gethostbyaddr.3
+MLINKS+= bluetooth.3 bt_gethostent.3
+MLINKS+= bluetooth.3 bt_sethostent.3
+MLINKS+= bluetooth.3 bt_endhostent.3
+
+MLINKS+= bluetooth.3 bt_getprotobyname.3
+MLINKS+= bluetooth.3 bt_getprotobynumber.3
+MLINKS+= bluetooth.3 bt_getprotoent.3
+MLINKS+= bluetooth.3 bt_setprotoent.3
+MLINKS+= bluetooth.3 bt_endprotoent.3
+
+MLINKS+= bluetooth.3 bt_ntoa.3
+MLINKS+= bluetooth.3 bt_aton.3
+
+.include <bsd.lib.mk>
diff --git a/lib/libbluetooth/bluetooth.3 b/lib/libbluetooth/bluetooth.3
new file mode 100644
index 0000000..d6adb26
--- /dev/null
+++ b/lib/libbluetooth/bluetooth.3
@@ -0,0 +1,289 @@
+.\" Copyright (c) 2003 Maksim Yevmenkin <m_evmenkin@yahoo.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.
+.\"
+.\" $Id: bluetooth.3,v 1.5 2003/05/20 23:04:30 max Exp $
+.\" $FreeBSD$
+.\"
+.Dd May 7, 2003
+.Dt BLUETOOTH 3
+.Os
+.Sh NAME
+.Nm bt_gethostbyname ,
+.Nm bt_gethostbyaddr ,
+.Nm bt_gethostent ,
+.Nm bt_sethostent ,
+.Nm bt_endhostent ,
+.Nm bt_getprotobyname ,
+.Nm bt_getprotobynumber ,
+.Nm bt_getprotoent ,
+.Nm bt_setprotoent ,
+.Nm bt_endprotoent ,
+.Nm bt_aton ,
+.Nm bt_ntoa
+.Nd Bluetooth routines
+.Sh LIBRARY
+.Lb libbluetooth
+.Sh SYNOPSIS
+.In bluetooth.h
+.Ft struct hostent *
+.Fn bt_gethostbyname "const char *name"
+.Ft struct hostent *
+.Fn bt_gethostbyaddr "const char *addr" "int len" "int type"
+.Ft struct hostent *
+.Fn bt_gethostent void
+.Ft void
+.Fn bt_sethostent "int stayopen"
+.Ft void
+.Fn bt_endhostent void
+.Ft struct protoent *
+.Fn bt_getprotobyname "const char *name"
+.Ft struct protoent *
+.Fn bt_getprotobynumber "int proto"
+.Ft struct protoent *
+.Fn bt_getprotoent void
+.Ft void
+.Fn bt_setprotoent "int stayopen"
+.Ft void
+.Fn bt_endprotoent void
+.Ft int
+.Fn bt_aton "const char *str" "bdaddr_t *ba"
+.Ft const char *
+.Fn bt_ntoa "const bdaddr_t *ba" "char *str"
+.Sh DESCRIPTION
+The
+.Fn bt_gethostent ,
+.Fn bt_gethostbyname
+and
+.Fn bt_gethostbyaddr
+functions
+each return a pointer to an object with the
+.Vt hostent
+structure describing a Bluetooth host
+referenced by name or by address, respectively.
+.Pp
+The
+.Fa name
+argument passed to
+.Fn bt_gethostbyname
+should point to a
+.Dv NUL Ns -terminated
+hostname.
+The
+.Fa addr
+argument passed to
+.Fn bt_gethostbyaddr
+should point to an address which is
+.Fa len
+bytes long,
+in binary form
+(i.e., not a Bluetooth BD_ADDR in human readable
+.Tn ASCII
+form).
+The
+.Fa type
+argument specifies the address family of this address and must be set to
+.Dv AF_BLUETOOTH .
+.Pp
+The structure returned contains the information obtained from a line in
+.Pa /etc/bluetooth/hosts
+file.
+.Pp
+The
+.Fn bt_sethostent
+function controls whether
+.Pa /etc/bluetooth/hosts
+file should stay open after each call to
+.Fn bt_gethostbyname
+or
+.Fn bt_gethostbyaddr .
+If the
+.Fa stayopen
+flag is non-zero, the file will not be closed.
+.Pp
+The
+.Fn bt_endhostent
+function closes the
+.Pa /etc/bluetooth/hosts
+file.
+.Pp
+The
+.Fn bt_getprotoent ,
+.Fn bt_getprotobyname
+and
+.Fn bt_getprotobynumber
+functions each return a pointer to an object with the
+.Vt protoent
+structure describing a Bluetooth Protocol Service Multiplexor referenced
+by name or number, respectively.
+.Pp
+The
+.Fa name
+argument passed to
+.Fn bt_getprotobyname
+should point to a
+.Dv NUL Ns -terminated
+Bluetooth Protocol Service Multiplexor name.
+The
+.Fa proto
+argument passed to
+.Fn bt_getprotobynumber
+should have numeric value of the desired Bluetooth Protocol Service Multiplexor.
+.Pp
+The structure returned contains the information obtained from a line in
+.Pa /etc/bluetooth/protocols
+file.
+.Pp
+The
+.Fn bt_setprotoent
+function controls whether
+.Pa /etc/bluetooth/protocols
+file should stay open after each call to
+.Fn bt_getprotobyname
+or
+.Fn bt_getprotobynumber .
+If the
+.Fa stayopen
+flag is non-zero, the file will not be closed.
+.Pp
+The
+.Fn bt_endprotoent
+function closes the
+.Pa /etc/bluetooth/protocols
+file.
+.Pp
+The
+.Fn bt_aton
+routine interprets the specified character string as a Bluetooth address,
+placing the address into the structure provided.
+It returns 1 if the string was successfully interpreted,
+or 0 if the string is invalid.
+.Pp
+The routine
+.Fn bt_ntoa
+takes a Bluetooth address and places an
+.Tn ASCII
+string representing the address into the buffer provided.
+It is up to the caller to ensure that provided buffer has enough space.
+If no buffer was provided then internal static buffer will be used.
+.Sh FILES
+.Bl -tag -width ".Pa /etc/bluetooth/hosts" -compact
+.It Pa /etc/bluetooth/hosts
+.It Pa /etc/bluetooth/protocols
+.El
+.Sh EXAMPLES
+Print out the hostname associated with a specific BD_ADDR:
+.Bd -literal -offset indent
+const char *bdstr = "00:01:02:03:04:05";
+bdaddr_t bd;
+struct hostent *hp;
+
+if (!bt_aton(bdstr, &bd))
+ errx(1, "can't parse BD_ADDR %s", bdstr);
+
+if ((hp = bt_gethostbyaddr((const char *)&bd,
+ sizeof(bd), AF_BLUETOOTH)) == NULL)
+ errx(1, "no name associated with %s", bdstr);
+
+printf("name associated with %s is %s\en", bdstr, hp->h_name);
+.Ed
+.Sh DIAGNOSTICS
+Error return status from
+.Fn bt_gethostent ,
+.Fn bt_gethostbyname
+and
+.Fn bt_gethostbyaddr
+is indicated by return of a
+.Dv NULL
+pointer.
+The external integer
+.Va h_errno
+may then be checked to see whether this is a temporary failure
+or an invalid or unknown host.
+The routine
+.Xr herror 3
+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 ".Dv HOST_NOT_FOUND"
+.It Dv HOST_NOT_FOUND
+No such host is known.
+.It Dv NO_RECOVERY
+Some unexpected server failure was encountered.
+This is a non-recoverable error.
+.El
+.Pp
+The
+.Fn bt_getprotoent ,
+.Fn bt_getprotobyname
+and
+.Fn bt_getprotobynumber
+return
+.Dv NULL
+on EOF or error.
+.Sh SEE ALSO
+.Xr gethostbyaddr 3 ,
+.Xr gethostbyname 3 ,
+.Xr getprotobyname 3 ,
+.Xr getprotobynumber 3 ,
+.Xr herror 3 ,
+.Xr inet_aton 3 ,
+.Xr inet_ntoa 3
+.Sh CAVEAT
+The
+.Fn bt_gethostent
+function reads the next line of
+.Pa /etc/bluetooth/hosts ,
+opening the file if necessary.
+.Pp
+The
+.Fn bt_sethostent
+function opens and/or rewinds the
+.Pa /etc/bluetooth/hosts
+file.
+.Pp
+The
+.Fn bt_getprotoent
+function reads the next line of
+.Pa /etc/bluetooth/protocols ,
+opening the file if necessary.
+.Pp
+The
+.Fn bt_setprotoent
+function opens and/or rewinds the
+.Pa /etc/bluetooth/protocols
+file.
+.Sh AUTHORS
+.An Maksim Yevmenkin Aq m_evmenkin@yahoo.com
+.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/libbluetooth/bluetooth.c b/lib/libbluetooth/bluetooth.c
new file mode 100644
index 0000000..f206aee
--- /dev/null
+++ b/lib/libbluetooth/bluetooth.c
@@ -0,0 +1,369 @@
+/*
+ * bluetooth.c
+ *
+ * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.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.
+ *
+ * $Id: bluetooth.c,v 1.3 2003/05/20 23:04:30 max Exp $
+ * $FreeBSD$
+ */
+
+#include <bluetooth.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define _PATH_BT_HOSTS "/etc/bluetooth/hosts"
+#define _PATH_BT_PROTOCOLS "/etc/bluetooth/protocols"
+#define MAXALIASES 35
+
+static FILE *hostf = NULL;
+static int host_stayopen = 0;
+static struct hostent host;
+static bdaddr_t host_addr;
+static char *host_addr_ptrs[2];
+static char *host_aliases[MAXALIASES];
+
+static FILE *protof = NULL;
+static int proto_stayopen = 0;
+static struct protoent proto;
+static char *proto_aliases[MAXALIASES];
+
+static char buf[BUFSIZ + 1];
+
+static int bt_hex_byte (char const *str);
+static int bt_hex_nibble (char nibble);
+
+struct hostent *
+bt_gethostbyname(char const *name)
+{
+ struct hostent *p;
+ char **cp;
+
+ bt_sethostent(host_stayopen);
+ while ((p = bt_gethostent()) != NULL) {
+ if (strcasecmp(p->h_name, name) == 0)
+ break;
+ for (cp = p->h_aliases; *cp != 0; cp++)
+ if (strcasecmp(*cp, name) == 0)
+ goto found;
+ }
+found:
+ bt_endhostent();
+
+ return (p);
+}
+
+struct hostent *
+bt_gethostbyaddr(char const *addr, int len, int type)
+{
+ struct hostent *p;
+
+ if (type != AF_BLUETOOTH || len != sizeof(bdaddr_t)) {
+ h_errno = NO_RECOVERY;
+ return (NULL);
+ }
+
+ bt_sethostent(host_stayopen);
+ while ((p = bt_gethostent()) != NULL)
+ if (p->h_addrtype == type && bcmp(p->h_addr, addr, len) == 0)
+ break;
+ bt_endhostent();
+
+ return (p);
+}
+
+struct hostent *
+bt_gethostent(void)
+{
+ char *p, *cp, **q;
+
+ if (hostf == NULL)
+ hostf = fopen(_PATH_BT_HOSTS, "r");
+
+ if (hostf == NULL) {
+ h_errno = NETDB_INTERNAL;
+ return (NULL);
+ }
+again:
+ if ((p = fgets(buf, sizeof(buf), hostf)) == NULL) {
+ h_errno = HOST_NOT_FOUND;
+ return (NULL);
+ }
+ if (*p == '#')
+ goto again;
+ if ((cp = strpbrk(p, "#\n")) == NULL)
+ goto again;
+ *cp = 0;
+ if ((cp = strpbrk(p, " \t")) == NULL)
+ goto again;
+ *cp++ = 0;
+ if (bt_aton(p, &host_addr) == 0)
+ goto again;
+ host_addr_ptrs[0] = (char *) &host_addr;
+ host_addr_ptrs[1] = NULL;
+ host.h_addr_list = host_addr_ptrs;
+ host.h_length = sizeof(host_addr);
+ host.h_addrtype = AF_BLUETOOTH;
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ host.h_name = cp;
+ q = host.h_aliases = host_aliases;
+ if ((cp = strpbrk(cp, " \t")) != NULL)
+ *cp++ = 0;
+ while (cp != NULL && *cp != 0) {
+ if (*cp == ' ' || *cp == '\t') {
+ cp++;
+ continue;
+ }
+ if (q < &host_aliases[MAXALIASES - 1])
+ *q++ = cp;
+ if ((cp = strpbrk(cp, " \t")) != NULL)
+ *cp++ = 0;
+ }
+ *q = NULL;
+ h_errno = NETDB_SUCCESS;
+
+ return (&host);
+}
+
+void
+bt_sethostent(int stayopen)
+{
+ if (hostf == NULL)
+ hostf = fopen(_PATH_BT_HOSTS, "r");
+ else
+ rewind(hostf);
+
+ host_stayopen = stayopen;
+}
+
+void
+bt_endhostent(void)
+{
+ if (hostf != NULL && host_stayopen == 0) {
+ (void) fclose(hostf);
+ hostf = NULL;
+ }
+}
+
+struct protoent *
+bt_getprotobyname(char const *name)
+{
+ struct protoent *p;
+ char **cp;
+
+ bt_setprotoent(proto_stayopen);
+ while ((p = bt_getprotoent()) != NULL) {
+ if (strcmp(p->p_name, name) == 0)
+ break;
+ for (cp = p->p_aliases; *cp != 0; cp++)
+ if (strcmp(*cp, name) == 0)
+ goto found;
+ }
+found:
+ bt_endprotoent();
+
+ return (p);
+}
+
+struct protoent *
+bt_getprotobynumber(int proto)
+{
+ struct protoent *p;
+
+ bt_setprotoent(proto_stayopen);
+ while ((p = bt_getprotoent()) != NULL)
+ if (p->p_proto == proto)
+ break;
+ bt_endprotoent();
+
+ return (p);
+}
+
+struct protoent *
+bt_getprotoent(void)
+{
+ char *p, *cp, **q;
+
+ if (protof == NULL)
+ protof = fopen(_PATH_BT_PROTOCOLS, "r");
+
+ if (protof == NULL)
+ return (NULL);
+again:
+ if ((p = fgets(buf, sizeof(buf), protof)) == NULL)
+ return (NULL);
+ if (*p == '#')
+ goto again;
+ if ((cp = strpbrk(p, "#\n")) == NULL)
+ goto again;
+ *cp = '\0';
+ proto.p_name = p;
+ if ((cp = strpbrk(p, " \t")) == NULL)
+ goto again;
+ *cp++ = '\0';
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ if ((p = strpbrk(cp, " \t")) != NULL)
+ *p++ = '\0';
+ proto.p_proto = atoi(cp);
+ q = proto.p_aliases = proto_aliases;
+ if (p != NULL) {
+ cp = p;
+ while (cp != NULL && *cp != 0) {
+ if (*cp == ' ' || *cp == '\t') {
+ cp++;
+ continue;
+ }
+ if (q < &proto_aliases[MAXALIASES - 1])
+ *q++ = cp;
+ if ((cp = strpbrk(cp, " \t")) != NULL)
+ *cp++ = '\0';
+ }
+ }
+ *q = NULL;
+
+ return (&proto);
+}
+
+void
+bt_setprotoent(int stayopen)
+{
+ if (protof == NULL)
+ protof = fopen(_PATH_BT_PROTOCOLS, "r");
+ else
+ rewind(protof);
+
+ proto_stayopen = stayopen;
+}
+
+void
+bt_endprotoent(void)
+{
+ if (protof != NULL) {
+ (void) fclose(protof);
+ protof = NULL;
+ }
+}
+
+char const *
+bt_ntoa(bdaddr_t const *ba, char *str)
+{
+ static char buffer[24];
+
+ if (str == NULL)
+ str = buffer;
+
+ sprintf(str, "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
+ ba->b[5], ba->b[4], ba->b[3], ba->b[2], ba->b[1], ba->b[0]);
+
+ return (str);
+}
+
+int
+bt_aton(char const *str, bdaddr_t *ba)
+{
+ int i, b;
+ char *end = NULL;
+
+ memset(ba, 0, sizeof(*ba));
+
+ for (i = 5, end = strchr(str, ':');
+ i > 0 && *str != '\0' && end != NULL;
+ i --, str = end + 1, end = strchr(str, ':')) {
+ switch (end - str) {
+ case 1:
+ b = bt_hex_nibble(str[0]);
+ break;
+
+ case 2:
+ b = bt_hex_byte(str);
+ break;
+
+ default:
+ b = -1;
+ break;
+ }
+
+ if (b < 0)
+ return (0);
+
+ ba->b[i] = b;
+ }
+
+ if (i != 0 || end != NULL || *str == 0)
+ return (0);
+
+ switch (strlen(str)) {
+ case 1:
+ b = bt_hex_nibble(str[0]);
+ break;
+
+ case 2:
+ b = bt_hex_byte(str);
+ break;
+
+ default:
+ b = -1;
+ break;
+ }
+
+ if (b < 0)
+ return (0);
+
+ ba->b[i] = b;
+
+ return (1);
+}
+
+static int
+bt_hex_byte(char const *str)
+{
+ int n1, n2;
+
+ if ((n1 = bt_hex_nibble(str[0])) < 0)
+ return (-1);
+
+ if ((n2 = bt_hex_nibble(str[1])) < 0)
+ return (-1);
+
+ return ((((n1 & 0x0f) << 4) | (n2 & 0x0f)) & 0xff);
+}
+
+static int
+bt_hex_nibble(char nibble)
+{
+ if ('0' <= nibble && nibble <= '9')
+ return (nibble - '0');
+
+ if ('a' <= nibble && nibble <= 'f')
+ return (nibble - 'a' + 0xa);
+
+ if ('A' <= nibble && nibble <= 'F')
+ return (nibble - 'A' + 0xa);
+
+ return (-1);
+}
+
diff --git a/lib/libbluetooth/bluetooth.h b/lib/libbluetooth/bluetooth.h
new file mode 100644
index 0000000..d979787
--- /dev/null
+++ b/lib/libbluetooth/bluetooth.h
@@ -0,0 +1,78 @@
+/*
+ * bluetooth.h
+ *
+ * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.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.
+ *
+ * $Id: bluetooth.h,v 1.5 2003/09/14 23:28:42 max Exp $
+ * $FreeBSD$
+ */
+
+#ifndef _BLUETOOTH_H_
+#define _BLUETOOTH_H_
+
+#include <sys/types.h>
+#include <sys/bitstring.h>
+#include <sys/endian.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netdb.h>
+#include <netgraph/bluetooth/include/ng_hci.h>
+#include <netgraph/bluetooth/include/ng_l2cap.h>
+#include <netgraph/bluetooth/include/ng_btsocket.h>
+
+__BEGIN_DECLS
+
+/*
+ * Linux BlueZ compatibility
+ */
+
+#define bacmp(ba1, ba2) memcmp((ba1), (ba2), sizeof(bdaddr_t))
+#define bacpy(dst, src) memcpy((dst), (src), sizeof(bdaddr_t))
+#define ba2str(ba, str) bt_ntoa((ba), (str))
+#define str2ba(str, ba) (bt_aton((str), (ba)) == 1? 0 : -1)
+
+/*
+ * Interface to the outside world
+ */
+
+struct hostent * bt_gethostbyname (char const *name);
+struct hostent * bt_gethostbyaddr (char const *addr, int len, int type);
+struct hostent * bt_gethostent (void);
+void bt_sethostent (int stayopen);
+void bt_endhostent (void);
+
+struct protoent * bt_getprotobyname (char const *name);
+struct protoent * bt_getprotobynumber (int proto);
+struct protoent * bt_getprotoent (void);
+void bt_setprotoent (int stayopen);
+void bt_endprotoent (void);
+
+char const * bt_ntoa (bdaddr_t const *ba, char *str);
+int bt_aton (char const *str, bdaddr_t *ba);
+
+__END_DECLS
+
+#endif /* ndef _BLUETOOTH_H_ */
+
diff --git a/lib/libbsm/Makefile b/lib/libbsm/Makefile
new file mode 100644
index 0000000..0018453
--- /dev/null
+++ b/lib/libbsm/Makefile
@@ -0,0 +1,140 @@
+#
+# $FreeBSD$
+#
+
+OPENBSMDIR= ${.CURDIR}/../../contrib/openbsm
+LIBBSMDIR= ${OPENBSMDIR}/libbsm
+
+LIB= bsm
+SHLIB_MAJOR= 1
+
+.PATH: ${LIBBSMDIR}
+.PATH: ${OPENBSMDIR}/bsm
+.PATH: ${OPENBSMDIR}/man
+
+SRCS= bsm_audit.c \
+ bsm_class.c \
+ bsm_control.c \
+ bsm_event.c \
+ bsm_flags.c \
+ bsm_io.c \
+ bsm_mask.c \
+ bsm_notify.c \
+ bsm_token.c \
+ bsm_user.c \
+ bsm_wrappers.c
+
+#
+# Must use BSM include files from within the contrib area, not the system.
+#
+CFLAGS+= -I${OPENBSMDIR} -I${LIBBSMDIR} -I${.CURDIR}/../../sys
+
+INCS= audit_uevents.h libbsm.h
+INCSDIR= ${INCLUDEDIR}/bsm
+
+MAN= libbsm.3 \
+ au_class.3 \
+ au_control.3 \
+ au_event.3 \
+ au_free_token.3 \
+ au_io.3 \
+ au_mask.3 \
+ au_token.3 \
+ au_user.3
+
+#
+# It seems like maybe some of these should be installed separately, since
+# they're not all libbsm parts.
+#
+MAN+= audit.2 \
+ audit.log.5 \
+ audit_class.5 \
+ audit_control.5 \
+ audit_event.5 \
+ audit_user.5 \
+ audit_warn.5 \
+ auditctl.2 \
+ auditon.2 \
+ getaudit.2 \
+ getauid.2 \
+ setaudit.2 \
+ setauid.2
+
+MLINKS= libbsm.3 bsm.3 \
+ au_class.3 getauclassent.3 \
+ au_class.3 getauclassnam.3 \
+ au_class.3 setauclass.3 \
+ au_class.3 endauclass.3 \
+ au_control.3 setac.3 \
+ au_control.3 endac.3 \
+ au_control.3 getacdir.3 \
+ au_control.3 getacmin.3 \
+ au_control.3 getacflg.3 \
+ au_control.3 getacna.3 \
+ au_event.3 setauevent.3 \
+ au_event.3 endauevent.3 \
+ au_event.3 getauevent.3 \
+ au_event.3 getauevnam.3 \
+ au_event.3 getauevnum.3 \
+ au_event.3 getauevnonam.3 \
+ au_io.3 au_fetch_tok.3 \
+ au_io.3 au_print_tok.3 \
+ au_io.3 au_read_rec.3 \
+ au_mask.3 au_preselect.3 \
+ au_mask.3 getauditflagsbin.3 \
+ au_mask.3 getauditflagschar.3 \
+ au_user.3 setauuser.3 \
+ au_user.3 endauuser.3 \
+ au_user.3 getauuserent.3 \
+ au_user.3 getauusernam.3 \
+ au_user.3 au_user_mask.3 \
+ au_user.3 getfauditflags.3 \
+ au_token.3 au_to_arg32.3 \
+ au_token.3 au_to_arg64.3 \
+ au_token.3 au_to_arg.3 \
+ au_token.3 au_to_attr64.3 \
+ au_token.3 au_to_data.3 \
+ au_token.3 au_to_exit.3 \
+ au_token.3 au_to_groups.3 \
+ au_token.3 au_to_newgroups.3 \
+ au_token.3 au_to_in_addr.3 \
+ au_token.3 au_to_in_addr_ex.3 \
+ au_token.3 au_to_ip.3 \
+ au_token.3 au_to_ipc.3 \
+ au_token.3 au_to_ipc_perm.3 \
+ au_token.3 au_to_iport.3 \
+ au_token.3 au_to_opaque.3 \
+ au_token.3 au_to_file.3 \
+ au_token.3 au_to_text.3 \
+ au_token.3 au_to_path.3 \
+ au_token.3 au_to_process32.3 \
+ au_token.3 au_to_process64.3 \
+ au_token.3 au_to_process.3 \
+ au_token.3 au_to_process32_ex.3 \
+ au_token.3 au_to_process64_ex.3 \
+ au_token.3 au_to_process_ex.3 \
+ au_token.3 au_to_return32.3 \
+ au_token.3 au_to_return64.3 \
+ au_token.3 au_to_return.3 \
+ au_token.3 au_to_seq.3 \
+ au_token.3 au_to_socket.3 \
+ au_token.3 au_to_socket_ex_32.3 \
+ au_token.3 au_to_socket_ex_128.3 \
+ au_token.3 au_to_sock_inet32.3 \
+ au_token.3 au_to_sock_inet128.3 \
+ au_token.3 au_to_sock_inet.3 \
+ au_token.3 au_to_subject32.3 \
+ au_token.3 au_to_subject64.3 \
+ au_token.3 au_to_subject.3 \
+ au_token.3 au_to_subject32_ex.3 \
+ au_token.3 au_to_subject64_ex.3 \
+ au_token.3 au_to_subject_ex.3 \
+ au_token.3 au_to_me.3 \
+ au_token.3 au_to_exec_args.3 \
+ au_token.3 au_to_exec_env.3 \
+ au_token.3 au_to_header.3 \
+ au_token.3 au_to_header32.3 \
+ au_token.3 au_to_header64.3 \
+ au_token.3 au_to_trailer.3
+
+.include <bsd.lib.mk>
diff --git a/lib/libbsnmp/Makefile b/lib/libbsnmp/Makefile
new file mode 100644
index 0000000..22821c7
--- /dev/null
+++ b/lib/libbsnmp/Makefile
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+SUBDIR= libbsnmp
+
+.include <bsd.subdir.mk>
diff --git a/lib/libbsnmp/Makefile.inc b/lib/libbsnmp/Makefile.inc
new file mode 100644
index 0000000..c5dec8d
--- /dev/null
+++ b/lib/libbsnmp/Makefile.inc
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+SHLIB_MAJOR= 3
+WARNS?= 6
+NO_WERROR=
+INCSDIR= ${INCLUDEDIR}/bsnmp
diff --git a/lib/libbsnmp/libbsnmp/Makefile b/lib/libbsnmp/libbsnmp/Makefile
new file mode 100644
index 0000000..91351c0
--- /dev/null
+++ b/lib/libbsnmp/libbsnmp/Makefile
@@ -0,0 +1,19 @@
+# $FreeBSD$
+#
+# Author: Harti Brandt <harti@freebsd.org>
+
+CONTRIB= ${.CURDIR}/../../../contrib/bsnmp/lib
+.PATH: ${CONTRIB}
+
+LIB = bsnmp
+SHLIBDIR ?= /lib
+WARNS ?= 6
+
+CFLAGS+= -I${CONTRIB} -DHAVE_ERR_H -DHAVE_GETADDRINFO -DHAVE_STRLCPY
+CFLAGS+= -DHAVE_STDINT_H -DHAVE_INTTYPES_H -DQUADFMT='"llu"' -DQUADXFMT='"llx"'
+
+SRCS= asn1.c snmp.c snmpagent.c snmpclient.c support.c
+INCS= asn1.h snmp.h snmpagent.h snmpclient.h
+MAN= asn1.3 bsnmplib.3 bsnmpclient.3 bsnmpagent.3
+
+.include <bsd.lib.mk>
diff --git a/lib/libbz2/Makefile b/lib/libbz2/Makefile
new file mode 100644
index 0000000..1bd848e
--- /dev/null
+++ b/lib/libbz2/Makefile
@@ -0,0 +1,13 @@
+# $FreeBSD$
+
+BZ2DIR= ${.CURDIR}/../../contrib/bzip2
+.PATH: ${BZ2DIR}
+
+LIB= bz2
+SHLIB_MAJOR= 2
+SRCS= bzlib.c blocksort.c compress.c crctable.c decompress.c \
+ huffman.c randtable.c
+INCS= bzlib.h
+CFLAGS+= -I${BZ2DIR}
+
+.include <bsd.lib.mk>
diff --git a/lib/libc/Makefile b/lib/libc/Makefile
new file mode 100644
index 0000000..496598a
--- /dev/null
+++ b/lib/libc/Makefile
@@ -0,0 +1,119 @@
+# @(#)Makefile 8.2 (Berkeley) 2/3/94
+# $FreeBSD$
+
+SHLIBDIR?= /lib
+
+.include <bsd.own.mk>
+
+# 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
+# If you bump SHLIB_MAJOR, remove the kluge from gen/gethostname.c.
+# If you bump SHLIB_MAJOR, see standards/55112.
+SHLIB_MAJOR= 6
+WARNS?= 2
+CFLAGS+=-I${.CURDIR}/include -I${.CURDIR}/../../include
+CFLAGS+=-I${.CURDIR}/${MACHINE_ARCH}
+CLEANFILES+=tags
+INSTALL_PIC_ARCHIVE=
+PRECIOUSLIB=
+
+# 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 "${.CURDIR}/${MACHINE_ARCH}/Makefile.inc"
+.include "${.CURDIR}/db/Makefile.inc"
+.include "${.CURDIR}/compat-43/Makefile.inc"
+.include "${.CURDIR}/gdtoa/Makefile.inc"
+.include "${.CURDIR}/gen/Makefile.inc"
+.include "${.CURDIR}/gmon/Makefile.inc"
+.include "${.CURDIR}/inet/Makefile.inc"
+.include "${.CURDIR}/isc/Makefile.inc"
+.include "${.CURDIR}/locale/Makefile.inc"
+.include "${.CURDIR}/nameser/Makefile.inc"
+.include "${.CURDIR}/net/Makefile.inc"
+.include "${.CURDIR}/nls/Makefile.inc"
+.include "${.CURDIR}/posix1e/Makefile.inc"
+.if ${MACHINE_ARCH} != "alpha" && \
+ ${MACHINE_ARCH} != "amd64" && \
+ ${MACHINE_ARCH} != "ia64" && \
+ ${MACHINE_ARCH} != "sparc64"
+.include "${.CURDIR}/quad/Makefile.inc"
+.endif
+.include "${.CURDIR}/regex/Makefile.inc"
+.include "${.CURDIR}/resolv/Makefile.inc"
+.include "${.CURDIR}/stdio/Makefile.inc"
+.include "${.CURDIR}/stdlib/Makefile.inc"
+.include "${.CURDIR}/stdtime/Makefile.inc"
+.include "${.CURDIR}/string/Makefile.inc"
+.include "${.CURDIR}/sys/Makefile.inc"
+.include "${.CURDIR}/rpc/Makefile.inc"
+.include "${.CURDIR}/uuid/Makefile.inc"
+.include "${.CURDIR}/xdr/Makefile.inc"
+.if ${MACHINE_ARCH} == "arm"
+.include "${.CURDIR}/softfloat/Makefile.inc"
+.endif
+.if ${MK_NIS} != "no"
+CFLAGS+= -DYP
+.include "${.CURDIR}/yp/Makefile.inc"
+.endif
+.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(SYMVER_ENABLED)
+VERSION_DEF=${.CURDIR}/Versions.def
+SYMBOL_MAPS=${SYM_MAPS}
+CFLAGS+= -DSYMBOL_VERSIONING
+.endif
+
+# 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 index.c mcount.c rindex.c \
+ strcat.c strcmp.c strcpy.c strlen.c strncpy.c
+
+libkern: libkern.gen libkern.${MACHINE_ARCH}
+
+libkern.gen: ${KQSRCS} ${KSRCS}
+ cp -p ${.CURDIR}/quad/quad.h ${.ALLSRC} ${DESTDIR}/sys/libkern
+
+libkern.${MACHINE_ARCH}:: ${KMSRCS}
+.if defined(KMSRCS) && !empty(KMSRCS)
+ cp -p ${.ALLSRC} ${DESTDIR}/sys/libkern/${MACHINE_ARCH}
+.endif
+
+.include <bsd.lib.mk>
+
+# Disable warnings in contributed sources.
+CWARNFLAGS:= ${.IMPSRC:Ngdtoa_*.c:C/^.+$/${CWARNFLAGS}/}
diff --git a/lib/libc/Versions.def b/lib/libc/Versions.def
new file mode 100644
index 0000000..68c0f32
--- /dev/null
+++ b/lib/libc/Versions.def
@@ -0,0 +1,12 @@
+# $FreeBSD$
+
+# This is our first version; it depends on no other.
+FBSD_1.0 {
+};
+
+# 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.
+FBSDprivate {
+};
diff --git a/lib/libc/alpha/Makefile.inc b/lib/libc/alpha/Makefile.inc
new file mode 100644
index 0000000..49f6a3e
--- /dev/null
+++ b/lib/libc/alpha/Makefile.inc
@@ -0,0 +1,8 @@
+# $FreeBSD$
+#
+# Machine dependent definitions for the alpha architecture.
+#
+
+# On Alpha, long double is just double precision.
+MDSRCS+=machdep_ldisd.c
+SYM_MAPS+=${.CURDIR}/alpha/Symbol.map
diff --git a/lib/libc/alpha/SYS.h b/lib/libc/alpha/SYS.h
new file mode 100644
index 0000000..5365e67
--- /dev/null
+++ b/lib/libc/alpha/SYS.h
@@ -0,0 +1,74 @@
+/* From: NetBSD: SYS.h,v 1.5 1997/05/02 18:15:15 kleink Exp */
+
+/*
+ * Copyright (c) 1994, 1995 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ *
+ * $FreeBSD$
+ */
+
+#include <machine/asm.h>
+#include <sys/syscall.h>
+
+#define CALLSYS_ERROR(name) \
+ CALLSYS_NOERROR(name); \
+ br gp, LLABEL(name,0); \
+LLABEL(name,0): \
+ LDGP(gp); \
+ beq a3, LLABEL(name,1); \
+ jmp zero, .cerror; \
+LLABEL(name,1):
+
+
+#define SYSCALL(name) \
+LEAF(__CONCAT(__sys_,name),0); /* XXX # of args? */ \
+ WEAK_ALIAS(name, __CONCAT(__sys_,name)); \
+ WEAK_ALIAS(__CONCAT(_,name), __CONCAT(__sys_,name)); \
+ CALLSYS_ERROR(name)
+
+#define SYSCALL_NOERROR(name) \
+LEAF(__CONCAT(__sys_,name),0); /* XXX # of args? */ \
+ WEAK_ALIAS(name, __CONCAT(__sys_,name)); \
+ WEAK_ALIAS(__CONCAT(_,name), __CONCAT(__sys_,name)); \
+ CALLSYS_NOERROR(name)
+
+
+#define RSYSCALL(name) \
+ SYSCALL(name); \
+ RET; \
+END(__CONCAT(__sys_,name))
+
+#define RSYSCALL_NOERROR(name) \
+ SYSCALL_NOERROR(name); \
+ RET; \
+END(__CONCAT(__sys_,name))
+
+
+#define PSEUDO(name) \
+LEAF(__CONCAT(__sys_,name),0); /* XXX # of args? */ \
+ WEAK_ALIAS(__CONCAT(_,name), __CONCAT(__sys_, name)); \
+ CALLSYS_ERROR(name); \
+ RET; \
+END(__CONCAT(__sys_,name))
diff --git a/lib/libc/alpha/Symbol.map b/lib/libc/alpha/Symbol.map
new file mode 100644
index 0000000..51c81ed
--- /dev/null
+++ b/lib/libc/alpha/Symbol.map
@@ -0,0 +1,77 @@
+# $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;
+
+ __flt_rounds;
+ fpgetmask;
+ fpgetround;
+ fpgetsticky;
+ fpsetmask;
+ fpsetround;
+ __infinity;
+ __nan;
+ makecontext;
+ modf;
+ _setjmp;
+ _longjmp;
+ fabs;
+ rfork_thread;
+ setjmp;
+ longjmp;
+ sigsetjmp;
+ siglongjmp;
+ __htonl;
+ htonl;
+ __htons;
+ htons;
+ __ntohl;
+ ntohl;
+ __ntohs;
+ ntohs;
+ vfork;
+ exect;
+ fork;
+ sbrk;
+};
+
+#
+# FreeBSD private ABI
+#
+FBSDprivate {
+ # PSEUDO syscalls
+ __sys_getlogin;
+ _getlogin;
+ __sys_exit;
+
+ _set_tp;
+ __makecontext;
+ __signalcontext;
+ signalcontext;
+ ___longjmp;
+ __longjmp;
+ __siglongjmp;
+ __divqu;
+ __divq;
+ __divlu;
+ __divl;
+ __remqu;
+ __remq;
+ __remlu;
+ __reml;
+ __sys_vork;
+ _vfork;
+ __sys_fork;
+ _fork;
+ _end;
+ curbrk;
+ minbrk;
+ brk;
+ .cerror;
+};
diff --git a/lib/libc/alpha/_fpmath.h b/lib/libc/alpha/_fpmath.h
new file mode 100644
index 0000000..8b6d09e
--- /dev/null
+++ b/lib/libc/alpha/_fpmath.h
@@ -0,0 +1,49 @@
+/*-
+ * 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 :20;
+ unsigned int exp :11;
+ unsigned int sign :1;
+ } 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/alpha/arith.h b/lib/libc/alpha/arith.h
new file mode 100644
index 0000000..c8af6de
--- /dev/null
+++ b/lib/libc/alpha/arith.h
@@ -0,0 +1,20 @@
+/*
+ * MD header for contrib/netlib/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
+#define Sudden_Underflow
diff --git a/lib/libc/alpha/gen/Makefile.inc b/lib/libc/alpha/gen/Makefile.inc
new file mode 100644
index 0000000..8f8caf8
--- /dev/null
+++ b/lib/libc/alpha/gen/Makefile.inc
@@ -0,0 +1,47 @@
+# $FreeBSD$
+
+SRCS+= _setjmp.S _set_tp.c fabs.S infinity.c ldexp.c modf.c setjmp.S
+SRCS+= flt_rounds.c fpgetmask.c fpgetround.c fpgetsticky.c fpsetmask.c \
+ fpsetround.c
+
+SRCS+= sigsetjmp.S
+SRCS+= __divqu.S __divq.S __divlu.S __divl.S
+SRCS+= __remqu.S __remq.S __remlu.S __reml.S
+SRCS+= rfork_thread.S
+SRCS+= _ctx_start.S makecontext.c signalcontext.c
+
+CLEANFILES+= __divqu.S __divq.S __divlu.S __divl.S
+CLEANFILES+= __remqu.S __remq.S __remlu.S __reml.S
+
+
+__divqu.S: ${.CURDIR}/alpha/gen/divrem.m4
+ m4 -DNAME=__divqu -DOP=div -DS=false -DWORDSIZE=64 \
+ ${.ALLSRC} > ${.TARGET}
+
+__divq.S: ${.CURDIR}/alpha/gen/divrem.m4
+ m4 -DNAME=__divq -DOP=div -DS=true -DWORDSIZE=64 \
+ ${.ALLSRC} > ${.TARGET}
+
+__divlu.S: ${.CURDIR}/alpha/gen/divrem.m4
+ m4 -DNAME=__divlu -DOP=div -DS=false -DWORDSIZE=32 \
+ ${.ALLSRC} > ${.TARGET}
+
+__divl.S: ${.CURDIR}/alpha/gen/divrem.m4
+ m4 -DNAME=__divl -DOP=div -DS=true -DWORDSIZE=32 \
+ ${.ALLSRC} > ${.TARGET}
+
+__remqu.S: ${.CURDIR}/alpha/gen/divrem.m4
+ m4 -DNAME=__remqu -DOP=rem -DS=false -DWORDSIZE=64 \
+ ${.ALLSRC} > ${.TARGET}
+
+__remq.S: ${.CURDIR}/alpha/gen/divrem.m4
+ m4 -DNAME=__remq -DOP=rem -DS=true -DWORDSIZE=64 \
+ ${.ALLSRC} > ${.TARGET}
+
+__remlu.S: ${.CURDIR}/alpha/gen/divrem.m4
+ m4 -DNAME=__remlu -DOP=rem -DS=false -DWORDSIZE=32 \
+ ${.ALLSRC} > ${.TARGET}
+
+__reml.S: ${.CURDIR}/alpha/gen/divrem.m4
+ m4 -DNAME=__reml -DOP=rem -DS=true -DWORDSIZE=32 \
+ ${.ALLSRC} > ${.TARGET}
diff --git a/lib/libc/alpha/gen/_ctx_start.S b/lib/libc/alpha/gen/_ctx_start.S
new file mode 100644
index 0000000..229a6c1
--- /dev/null
+++ b/lib/libc/alpha/gen/_ctx_start.S
@@ -0,0 +1,45 @@
+/*
+ * 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$");
+
+/*
+ * A0-A5 are the first 6 arguments to the start routine with the
+ * remaining arguments (if any) placed on the stack. S0 is the
+ * address of the user-supplied start routine, and S1 is the pointer
+ * to the ucontext.
+ */
+ .set noreorder
+LEAF(_ctx_start,0)
+ mov s0, t12
+ jsr ra, (s0) /* call start routine; args already set */
+ LDGP(ra)
+ mov s1, a0 /* load A0 (arg 1) with pointer to ucontext */
+ CALL(_ctx_done) /* call context completion routine */
+ CALL(abort) /* should never return from above call */
+ RET
+END(_ctx_start)
diff --git a/lib/libc/alpha/gen/_set_tp.c b/lib/libc/alpha/gen/_set_tp.c
new file mode 100644
index 0000000..7aff9f7
--- /dev/null
+++ b/lib/libc/alpha/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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <machine/alpha_cpu.h>
+
+void
+_set_tp(void *tp)
+{
+
+ alpha_pal_wrunique((uintptr_t) tp);
+}
diff --git a/lib/libc/alpha/gen/_setjmp.S b/lib/libc/alpha/gen/_setjmp.S
new file mode 100644
index 0000000..85ed8c7
--- /dev/null
+++ b/lib/libc/alpha/gen/_setjmp.S
@@ -0,0 +1,127 @@
+/* $NetBSD: _setjmp.S,v 1.2 1996/10/17 03:08:03 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#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 stack,
+ * The previous signal state is NOT restored.
+ */
+
+ .set noreorder
+
+LEAF(_setjmp, 1)
+ LDGP(pv)
+ stq ra, (2 * 8)(a0) /* sc_pc = return address */
+ stq s0, (( 9 + 4) * 8)(a0) /* saved bits of sc_regs */
+ stq s1, ((10 + 4) * 8)(a0)
+ stq s2, ((11 + 4) * 8)(a0)
+ stq s3, ((12 + 4) * 8)(a0)
+ stq s4, ((13 + 4) * 8)(a0)
+ stq s5, ((14 + 4) * 8)(a0)
+ stq s6, ((15 + 4) * 8)(a0)
+ stq ra, ((26 + 4) * 8)(a0)
+ stq t12,((27 + 4) * 8)(a0)
+ stq sp, ((30 + 4) * 8)(a0)
+ ldiq t0, 0xacedbadd /* sigcontext magic number */
+ stq t0, ((31 + 4) * 8)(a0) /* magic in sc_regs[31] */
+ /* Too bad we can't check if we actually used FP */
+ ldiq t0, 1
+ stq t0, (36 * 8)(a0) /* say we've used FP. */
+ stt fs0, ((2 + 37) * 8)(a0) /* saved bits of sc_fpregs */
+ stt fs1, ((3 + 37) * 8)(a0)
+ stt fs2, ((4 + 37) * 8)(a0)
+ stt fs3, ((5 + 37) * 8)(a0)
+ stt fs4, ((6 + 37) * 8)(a0)
+ stt fs5, ((7 + 37) * 8)(a0)
+ stt fs6, ((8 + 37) * 8)(a0)
+ stt fs7, ((9 + 37) * 8)(a0)
+ mf_fpcr ft0 /* get FP control reg */
+ stt ft0, (69 * 8)(a0) /* and store it in sc_fpcr */
+ stq zero, (70 * 8)(a0) /* FP software control XXX */
+ stq zero, (71 * 8)(a0) /* sc_reserved[0] */
+ stq zero, (72 * 8)(a0) /* sc_reserved[1] */
+ stq zero, (73 * 8)(a0) /* sc_xxx[0] */
+ stq zero, (74 * 8)(a0) /* sc_xxx[1] */
+ stq zero, (75 * 8)(a0) /* sc_xxx[2] */
+ stq zero, (76 * 8)(a0) /* sc_xxx[3] */
+ stq zero, (77 * 8)(a0) /* sc_xxx[4] */
+ stq zero, (78 * 8)(a0) /* sc_xxx[5] */
+ stq zero, (79 * 8)(a0) /* sc_xxx[6] */
+ stq zero, (80 * 8)(a0) /* sc_xxx[7] */
+
+ mov zero, v0 /* return zero */
+ RET
+END(_setjmp)
+
+XLEAF(_longjmp, 2)
+LEAF(___longjmp, 2)
+ LDGP(pv)
+ ldq t0, ((31 + 4) * 8)(a0) /* magic in sc_regs[31] */
+ ldiq t1, 0xacedbadd
+ cmpeq t0, t1, t0
+ beq t0, botch /* If the magic was bad, punt */
+
+ ldq ra, (2 * 8)(a0) /* sc_pc = return address */
+ ldq s0, (( 9 + 4) * 8)(a0) /* saved bits of sc_regs */
+ ldq s1, ((10 + 4) * 8)(a0)
+ ldq s2, ((11 + 4) * 8)(a0)
+ ldq s3, ((12 + 4) * 8)(a0)
+ ldq s4, ((13 + 4) * 8)(a0)
+ ldq s5, ((14 + 4) * 8)(a0)
+ ldq s6, ((15 + 4) * 8)(a0)
+ /* ldq ra, ((26 + 4) * 8)(a0) set above */
+ ldq t12,((27 + 4) * 8)(a0)
+ ldq sp, ((30 + 4) * 8)(a0)
+ ldt fs0, ((2 + 37) * 8)(a0) /* saved bits of sc_fpregs */
+ ldt fs1, ((3 + 37) * 8)(a0)
+ ldt fs2, ((4 + 37) * 8)(a0)
+ ldt fs3, ((5 + 37) * 8)(a0)
+ ldt fs4, ((6 + 37) * 8)(a0)
+ ldt fs5, ((7 + 37) * 8)(a0)
+ ldt fs6, ((8 + 37) * 8)(a0)
+ ldt fs7, ((9 + 37) * 8)(a0)
+ ldt ft0, (69 * 8)(a0) /* get sc_fpcr */
+ mt_fpcr ft0 /* and restore it. */
+
+ mov a1, v0 /* return second arg */
+ RET
+
+botch:
+ CALL(longjmperror)
+ CALL(abort)
+ RET /* "can't" get here... */
+END(___longjmp)
diff --git a/lib/libc/alpha/gen/divrem.m4 b/lib/libc/alpha/gen/divrem.m4
new file mode 100644
index 0000000..6afa2e1
--- /dev/null
+++ b/lib/libc/alpha/gen/divrem.m4
@@ -0,0 +1,198 @@
+/* $NetBSD: divrem.m4,v 1.7 1996/10/17 03:08:04 cgd Exp $ */
+/* $FreeBSD$ */
+
+/*
+ * Copyright (c) 1994, 1995 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+/*
+ * Division and remainder.
+ *
+ * The use of m4 is modeled after the sparc code, but the algorithm is
+ * simple binary long division.
+ *
+ * Note that the loops could probably benefit from unrolling.
+ */
+
+/*
+ * M4 Parameters
+ * NAME name of function to generate
+ * OP OP=div: t10 / t11 -> t12; OP=rem: t10 % t11 -> t12
+ * S S=true: signed; S=false: unsigned
+ * WORDSIZE total number of bits
+ */
+
+define(A, `t10')
+define(B, `t11')
+define(RESULT, `t12')
+
+define(BIT, `t0')
+define(I, `t1')
+define(CC, `t2')
+define(T_0, `t3')
+ifelse(S, `true', `define(NEG, `t4')')
+
+#include <machine/asm.h>
+
+NESTED(NAME, 0, 0, t9, 0, 0) /* Get the right ra */
+ lda sp, -64(sp)
+ stq BIT, 0(sp)
+ stq I, 8(sp)
+ stq CC, 16(sp)
+ stq T_0, 24(sp)
+ifelse(S, `true',
+` stq NEG, 32(sp)')
+ stq A, 40(sp)
+ stq B, 48(sp)
+ mov zero, RESULT /* Initialize result to zero */
+
+ifelse(S, `true',
+`
+ /* Compute sign of result. If either is negative, this is easy. */
+ or A, B, NEG /* not the sign, but... */
+ srl NEG, WORDSIZE - 1, NEG /* rather, or of high bits */
+ blbc NEG, Ldoit /* neither negative? do it! */
+
+ifelse(OP, `div',
+` xor A, B, NEG /* THIS is the sign! */
+', ` mov A, NEG /* sign follows A. */
+')
+ srl NEG, WORDSIZE - 1, NEG /* make negation the low bit. */
+
+ srl A, WORDSIZE - 1, I /* is A negative? */
+ blbc I, LnegB /* no. */
+ /* A is negative; flip it. */
+ifelse(WORDSIZE, `32', `
+ /* top 32 bits may be random junk */
+ zap A, 0xf0, A
+')
+ subq zero, A, A
+ srl B, WORDSIZE - 1, I /* is B negative? */
+ blbc I, Ldoit /* no. */
+LnegB:
+ /* B is definitely negative, no matter how we got here. */
+ifelse(WORDSIZE, `32', `
+ /* top 32 bits may be random junk */
+ zap B, 0xf0, B
+')
+ subq zero, B, B
+Ldoit:
+')
+ifelse(WORDSIZE, `32', `
+ /*
+ * Clear the top 32 bits of each operand, as they may
+ * sign extension (if negated above), or random junk.
+ */
+ zap A, 0xf0, A
+ zap B, 0xf0, B
+')
+
+ /* kill the special cases. */
+ beq B, Ldotrap /* division by zero! */
+
+ cmpult A, B, CC /* A < B? */
+ /* RESULT is already zero, from above. A is untouched. */
+ bne CC, Lret_result
+
+ cmpeq A, B, CC /* A == B? */
+ cmovne CC, 1, RESULT
+ cmovne CC, zero, A
+ bne CC, Lret_result
+
+ /*
+ * Find out how many bits of zeros are at the beginning of the divisor.
+ */
+LBbits:
+ ldiq T_0, 1 /* I = 0; BIT = 1<<WORDSIZE-1 */
+ mov zero, I
+ sll T_0, WORDSIZE-1, BIT
+LBloop:
+ and B, BIT, CC /* if bit in B is set, done. */
+ bne CC, LAbits
+ addq I, 1, I /* increment I, shift bit */
+ srl BIT, 1, BIT
+ cmplt I, WORDSIZE-1, CC /* if I leaves one bit, done. */
+ bne CC, LBloop
+
+LAbits:
+ beq I, Ldodiv /* If I = 0, divide now. */
+ ldiq T_0, 1 /* BIT = 1<<WORDSIZE-1 */
+ sll T_0, WORDSIZE-1, BIT
+
+LAloop:
+ and A, BIT, CC /* if bit in A is set, done. */
+ bne CC, Ldodiv
+ subq I, 1, I /* decrement I, shift bit */
+ srl BIT, 1, BIT
+ bne I, LAloop /* If I != 0, loop again */
+
+Ldodiv:
+ sll B, I, B /* B <<= i */
+ ldiq T_0, 1
+ sll T_0, I, BIT
+
+Ldivloop:
+ cmpult A, B, CC
+ or RESULT, BIT, T_0
+ cmoveq CC, T_0, RESULT
+ subq A, B, T_0
+ cmoveq CC, T_0, A
+ srl BIT, 1, BIT
+ srl B, 1, B
+ beq A, Lret_result
+ bne BIT, Ldivloop
+
+Lret_result:
+ifelse(OP, `div',
+`', ` mov A, RESULT
+')
+ifelse(S, `true',
+`
+ /* Check to see if we should negate it. */
+ subq zero, RESULT, T_0
+ cmovlbs NEG, T_0, RESULT
+')
+
+ ldq BIT, 0(sp)
+ ldq I, 8(sp)
+ ldq CC, 16(sp)
+ ldq T_0, 24(sp)
+ifelse(S, `true',
+` ldq NEG, 32(sp)')
+ ldq A, 40(sp)
+ ldq B, 48(sp)
+ lda sp, 64(sp)
+ ret zero, (t9), 1
+
+Ldotrap:
+ ldiq a0, -2 /* This is the signal to SIGFPE! */
+ call_pal PAL_gentrap
+ifelse(OP, `div',
+`', ` mov zero, A /* so that zero will be returned */
+')
+ br zero, Lret_result
+
+END(NAME)
diff --git a/lib/libc/alpha/gen/fabs.S b/lib/libc/alpha/gen/fabs.S
new file mode 100644
index 0000000..5a742fe
--- /dev/null
+++ b/lib/libc/alpha/gen/fabs.S
@@ -0,0 +1,36 @@
+/* $NetBSD: fabs.S,v 1.2 1996/10/17 03:08:05 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+LEAF(fabs, 1)
+ cpys fzero, fa0, fv0
+ RET
+END(fabs)
diff --git a/lib/libc/alpha/gen/flt_rounds.c b/lib/libc/alpha/gen/flt_rounds.c
new file mode 100644
index 0000000..c3219d9
--- /dev/null
+++ b/lib/libc/alpha/gen/flt_rounds.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 1995 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 by Christopher G. Demetriou
+ * 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.
+ *
+ * $NetBSD: flt_rounds.c,v 1.2 1997/07/18 00:30:30 thorpej Exp $
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <machine/float.h>
+
+static const int map[] = {
+ 0, /* round to zero */
+ 3, /* round to negative infinity */
+ 1, /* round to nearest */
+ 2 /* round to positive infinity */
+};
+
+int
+__flt_rounds()
+{
+ union {
+ double fpcrval;
+ u_int64_t intval;
+ } u;
+
+ __asm__("trapb");
+ __asm__("mf_fpcr %0" : "=f" (u.fpcrval));
+ __asm__("trapb");
+
+ return map[(u.intval >> 58) & 0x3];
+}
diff --git a/lib/libc/alpha/gen/fpgetmask.c b/lib/libc/alpha/gen/fpgetmask.c
new file mode 100644
index 0000000..036a150
--- /dev/null
+++ b/lib/libc/alpha/gen/fpgetmask.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1995 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 by Christopher G. Demetriou
+ * 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.
+ *
+ * $NetBSD: fpgetmask.c,v 1.1 1995/04/29 05:10:55 cgd Exp $
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <ieeefp.h>
+#include <machine/sysarch.h>
+
+struct params {
+ u_int64_t mask;
+};
+
+fp_except_t
+fpgetmask()
+{
+ struct params p;
+
+ sysarch(ALPHA_GET_FPMASK, &p);
+ return((fp_except_t) p.mask);
+}
diff --git a/lib/libc/alpha/gen/fpgetround.c b/lib/libc/alpha/gen/fpgetround.c
new file mode 100644
index 0000000..1fd96b2
--- /dev/null
+++ b/lib/libc/alpha/gen/fpgetround.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1995 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 by Christopher G. Demetriou
+ * 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.
+ *
+ * $NetBSD: fpgetround.c,v 1.1 1995/04/29 05:09:55 cgd Exp $
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <ieeefp.h>
+#include <machine/fpu.h>
+
+fp_rnd_t
+fpgetround()
+{
+ union {
+ double fpcrval;
+ u_int64_t intval;
+ } u;
+
+ GET_FPCR(u.fpcrval);
+
+ return ((u.intval & FPCR_DYN_MASK) >> FPCR_DYN_SHIFT);
+}
diff --git a/lib/libc/alpha/gen/fpgetsticky.c b/lib/libc/alpha/gen/fpgetsticky.c
new file mode 100644
index 0000000..7586eb4
--- /dev/null
+++ b/lib/libc/alpha/gen/fpgetsticky.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1995 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 by Christopher G. Demetriou
+ * 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.
+ *
+ * $NetBSD: fpgetsticky.c,v 1.1 1995/04/29 05:10:59 cgd Exp $
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <ieeefp.h>
+#include <machine/fpu.h>
+
+fp_except_t
+fpgetsticky()
+{
+ union {
+ double fpcrval;
+ u_int64_t intval;
+ } u;
+
+ GET_FPCR(u.fpcrval);
+ return (((u.intval >> IEEE_STATUS_TO_FPCR_SHIFT) & IEEE_STATUS_MASK)
+ >> IEEE_STATUS_TO_EXCSUM_SHIFT);
+}
diff --git a/lib/libc/alpha/gen/fpsetmask.c b/lib/libc/alpha/gen/fpsetmask.c
new file mode 100644
index 0000000..65da3c5
--- /dev/null
+++ b/lib/libc/alpha/gen/fpsetmask.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1995 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 by Christopher G. Demetriou
+ * 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.
+ *
+ * $NetBSD: fpsetmask.c,v 1.1 1995/04/29 05:11:01 cgd Exp $
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <ieeefp.h>
+#include <machine/sysarch.h>
+
+struct params {
+ u_int64_t mask;
+};
+
+fp_except_t
+fpsetmask(mask)
+ fp_except_t mask;
+{
+ struct params p;
+
+ p.mask = (u_int64_t) mask;
+ sysarch(ALPHA_SET_FPMASK, &p);
+ return ((fp_except_t) p.mask);
+}
diff --git a/lib/libc/alpha/gen/fpsetround.c b/lib/libc/alpha/gen/fpsetround.c
new file mode 100644
index 0000000..8e994c7
--- /dev/null
+++ b/lib/libc/alpha/gen/fpsetround.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1995 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 by Christopher G. Demetriou
+ * 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.
+ *
+ * $NetBSD: fpsetround.c,v 1.1 1995/04/29 05:09:57 cgd Exp $
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <ieeefp.h>
+#include <machine/fpu.h>
+
+fp_rnd_t
+fpsetround(rnd_dir)
+ fp_rnd_t rnd_dir;
+{
+ union {
+ double fpcrval;
+ u_int64_t intval;
+ } u;
+ u_int64_t old, new;
+
+ GET_FPCR(u.fpcrval);
+
+ old = u.intval;
+ new = old & (~FPCR_DYN_MASK);
+ new |= ((long) rnd_dir << FPCR_DYN_SHIFT) & FPCR_DYN_MASK;
+
+ u.intval = new;
+ SET_FPCR(u.fpcrval);
+
+ return ((old & FPCR_DYN_MASK) >> FPCR_DYN_SHIFT);
+}
diff --git a/lib/libc/alpha/gen/infinity.c b/lib/libc/alpha/gen/infinity.c
new file mode 100644
index 0000000..b10f6d3
--- /dev/null
+++ b/lib/libc/alpha/gen/infinity.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 1994, 1995 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ *
+ * $NetBSD: infinity.c,v 1.1 1995/02/10 17:50:23 cgd Exp $
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <math.h>
+
+/* bytes for +Infinity on an Alpha (IEEE double format) */
+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/alpha/gen/makecontext.c b/lib/libc/alpha/gen/makecontext.c
new file mode 100644
index 0000000..bc8ea03
--- /dev/null
+++ b/lib/libc/alpha/gen/makecontext.c
@@ -0,0 +1,172 @@
+/*
+ * 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 <errno.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <ucontext.h>
+#include <unistd.h>
+
+
+/* Prototypes */
+extern void _ctx_start(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_format = 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_format = 0;
+ }
+ /* XXX - Do we want to sanity check argc? */
+ else if ((argc < 0) || (argc > NCARGS)) {
+ ucp->uc_mcontext.mc_format = 0;
+ }
+ /*
+ * Make sure the context is valid. For now, we only allow
+ * trapframe format contexts to be used for makecontext.
+ */
+ else if (ucp->uc_mcontext.mc_format == _MC_REV0_TRAPFRAME) {
+ /*
+ * Alpha passes the first 6 parameters in registers and
+ * remaining parameters on the stack. Set up the context
+ * accordingly, with the user start routine in register
+ * S0, and the context start wrapper (_ctx_start) in the
+ * program counter and return address. The context must
+ * be in trapframe format.
+ *
+ * Note: The context start wrapper needs to retrieve the
+ * ucontext pointer. Place this in register S1
+ * which must be saved by the callee.
+ */
+ stack_top = (char *)(ucp->uc_stack.ss_sp +
+ ucp->uc_stack.ss_size - sizeof(double));
+ stack_top = (char *)ALIGN(stack_top);
+
+ /*
+ * Adjust top of stack to allow for any additional integer
+ * arguments beyond 6.
+ */
+ if (argc > 6)
+ stack_top = stack_top - (sizeof(intptr_t) * (argc - 6));
+
+ argp = (intptr_t *)stack_top;
+
+ va_start(ap, argc);
+ for (i = 0; i < argc; i++) {
+ switch (i) {
+ case 0: ucp->uc_mcontext.mc_regs[FRAME_A0] =
+ (unsigned long)va_arg(ap, intptr_t);
+ break;
+
+ case 1: ucp->uc_mcontext.mc_regs[FRAME_A1] =
+ (unsigned long)va_arg(ap, intptr_t);
+ break;
+
+ case 2: ucp->uc_mcontext.mc_regs[FRAME_A2] =
+ (unsigned long)va_arg(ap, intptr_t);
+ break;
+
+ case 3: ucp->uc_mcontext.mc_regs[FRAME_A3] =
+ (unsigned long)va_arg(ap, intptr_t);
+ break;
+
+ case 4: ucp->uc_mcontext.mc_regs[FRAME_A4] =
+ (unsigned long)va_arg(ap, intptr_t);
+ break;
+
+ case 5: ucp->uc_mcontext.mc_regs[FRAME_A5] =
+ (unsigned long)va_arg(ap, intptr_t);
+ break;
+
+ default:
+ *argp = va_arg(ap, intptr_t);
+ argp++;
+ break;
+ }
+ }
+ va_end(ap);
+
+ /*
+ * The start routine and ucontext are placed in registers
+ * S0 and S1 respectively.
+ */
+ ucp->uc_mcontext.mc_regs[FRAME_S0] = (unsigned long)start;
+ ucp->uc_mcontext.mc_regs[FRAME_S1] = (unsigned long)ucp;
+
+ /*
+ * Set the machine context to point to the top of the stack,
+ * and the program counter and return address to the context
+ * start wrapper.
+ */
+ ucp->uc_mcontext.mc_regs[FRAME_SP] = (unsigned long)stack_top;
+ ucp->uc_mcontext.mc_regs[FRAME_PC] = (unsigned long)_ctx_start;
+ ucp->uc_mcontext.mc_regs[FRAME_RA] = (unsigned long)_ctx_start;
+ ucp->uc_mcontext.mc_regs[FRAME_T12] = (unsigned long)_ctx_start;
+ }
+}
diff --git a/lib/libc/alpha/gen/modf.c b/lib/libc/alpha/gen/modf.c
new file mode 100644
index 0000000..37786dc
--- /dev/null
+++ b/lib/libc/alpha/gen/modf.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 1994, 1995 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ *
+ * $NetBSD: modf.c,v 1.1 1995/02/10 17:50:25 cgd Exp $
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <machine/ieee.h>
+#include <errno.h>
+#include <math.h>
+
+/*
+ * double modf(double val, double *iptr)
+ * returns: f and i such that |f| < 1.0, (f + i) = val, and
+ * sign(f) == sign(i) == sign(val).
+ *
+ * Beware signedness when doing subtraction, and also operand size!
+ */
+double
+modf(val, iptr)
+ double val, *iptr;
+{
+ union doub {
+ double v;
+ struct ieee_double s;
+ } u, v;
+ u_int64_t frac;
+
+ /*
+ * If input is Inf or NaN, return it and leave i alone.
+ */
+ u.v = val;
+ if (u.s.dbl_exp == DBL_EXP_INFNAN)
+ return (u.v);
+
+ /*
+ * If input can't have a fractional part, return
+ * (appropriately signed) zero, and make i be the input.
+ */
+ if ((int)u.s.dbl_exp - DBL_EXP_BIAS > DBL_FRACBITS - 1) {
+ *iptr = u.v;
+ v.v = 0.0;
+ v.s.dbl_sign = u.s.dbl_sign;
+ return (v.v);
+ }
+
+ /*
+ * If |input| < 1.0, return it, and set i to the appropriately
+ * signed zero.
+ */
+ if (u.s.dbl_exp < DBL_EXP_BIAS) {
+ v.v = 0.0;
+ v.s.dbl_sign = u.s.dbl_sign;
+ *iptr = v.v;
+ return (u.v);
+ }
+
+ /*
+ * There can be a fractional part of the input.
+ * If you look at the math involved for a few seconds, it's
+ * plain to see that the integral part is the input, with the
+ * low (DBL_FRACBITS - (exponent - DBL_EXP_BIAS)) bits zeroed,
+ * the the fractional part is the part with the rest of the
+ * bits zeroed. Just zeroing the high bits to get the
+ * fractional part would yield a fraction in need of
+ * normalization. Therefore, we take the easy way out, and
+ * just use subtraction to get the fractional part.
+ */
+ v.v = u.v;
+ /* Zero the low bits of the fraction, the sleazy way. */
+ frac = ((u_int64_t)v.s.dbl_frach << 32) + v.s.dbl_fracl;
+ frac >>= DBL_FRACBITS - (u.s.dbl_exp - DBL_EXP_BIAS);
+ frac <<= DBL_FRACBITS - (u.s.dbl_exp - DBL_EXP_BIAS);
+ v.s.dbl_fracl = frac & 0xffffffff;
+ v.s.dbl_frach = frac >> 32;
+ *iptr = v.v;
+
+ u.v -= v.v;
+ u.s.dbl_sign = v.s.dbl_sign;
+ return (u.v);
+}
diff --git a/lib/libc/alpha/gen/rfork_thread.S b/lib/libc/alpha/gen/rfork_thread.S
new file mode 100644
index 0000000..68b0233
--- /dev/null
+++ b/lib/libc/alpha/gen/rfork_thread.S
@@ -0,0 +1,66 @@
+/*-
+ * 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$");
+
+#include "SYS.h"
+#include <sys/syscall.h>
+/* #include <machine/pal.h> */
+
+/*
+ * This is pretty evil and based mostly on examples from other syscall
+ * stubs and code that gcc generated. Correctness is uncertain, but it
+ * seems to work quite happily.
+ */
+LEAF(rfork_thread, 1)
+ br gp,L1 /* XXX profiling */
+L1:
+ LDGP(pv)
+ lda sp,-16(sp)
+ stq ra,0(sp)
+ mov a3,a5
+ CALLSYS_ERROR(rfork)
+ beq v0,$child
+ addl v0,zero,v0
+ ldq ra,0(sp)
+ lda sp,16(sp)
+ RET
+$child:
+ mov a1,sp
+ lda sp,-16(sp)
+ stq zero,0(sp)
+ mov a5,a0
+ mov a2,t12
+ jsr ra,(t12),0
+ ldgp gp,0(ra)
+ mov v0,a0
+#ifdef SYS_exit
+ CALLSYS_NOERROR(exit)
+#else
+ CALLSYS_NOERROR(sys_exit)
+#endif
+END(rfork_thread)
diff --git a/lib/libc/alpha/gen/setjmp.S b/lib/libc/alpha/gen/setjmp.S
new file mode 100644
index 0000000..779684d
--- /dev/null
+++ b/lib/libc/alpha/gen/setjmp.S
@@ -0,0 +1,138 @@
+/* $NetBSD: setjmp.S,v 1.3 1997/12/05 02:06:27 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+/*
+ * 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 the previous signal state.
+ */
+
+ .set noreorder
+
+LEAF(setjmp, 1)
+ LDGP(pv)
+ stq ra, (2 * 8)(a0) /* sc_pc = return address */
+ stq s0, (( 9 + 4) * 8)(a0) /* saved bits of sc_regs */
+ stq s1, ((10 + 4) * 8)(a0)
+ stq s2, ((11 + 4) * 8)(a0)
+ stq s3, ((12 + 4) * 8)(a0)
+ stq s4, ((13 + 4) * 8)(a0)
+ stq s5, ((14 + 4) * 8)(a0)
+ stq s6, ((15 + 4) * 8)(a0)
+ stq ra, ((26 + 4) * 8)(a0)
+ stq t12,((27 + 4) * 8)(a0)
+ stq sp, ((30 + 4) * 8)(a0)
+
+ /*
+ * get signal information
+ */
+ mov a0, s0 /* squirrel away ptr to sc */
+
+ /* see what's blocked */
+ lda a2, (71 * 8)(a0) /* oset: sc_reserved */
+ mov zero, a1 /* set: NULL */
+ addq a1, 1, a0 /* how: SIG_BLOCK */
+ CALL(_sigprocmask) /* see what's blocked */
+
+ lda sp, -24(sp) /* sizeof struct sigaltstack */
+ mov zero, a0
+ mov sp, a1
+ CALL(_sigaltstack)
+ ldl t0, 16(sp) /* offset of ss_flags */
+ lda sp, 24(sp) /* sizeof struct sigaltstack */
+ ldq ra, ((26 + 4) * 8)(s0) /* restore return address */
+ blt v0, botch /* check for error */
+ and t0, 0x1, t0 /* get SA_ONSTACK flag */
+ stq t0, (0 * 8)(s0) /* and save it in sc_onstack */
+ /*
+ * Restore old s0 and a0, and continue saving registers
+ */
+ mov s0, a0
+ ldq s0, (( 9 + 4) * 8)(a0)
+
+ ldiq t0, 0xacedbadd /* sigcontext magic number */
+ stq t0, ((31 + 4) * 8)(a0) /* magic in sc_regs[31] */
+ /* Too bad we can't check if we actually used FP */
+ ldiq t0, 1
+ stq t0, (36 * 8)(a0) /* say we've used FP. */
+ stt fs0, ((2 + 37) * 8)(a0) /* saved bits of sc_fpregs */
+ stt fs1, ((3 + 37) * 8)(a0)
+ stt fs2, ((4 + 37) * 8)(a0)
+ stt fs3, ((5 + 37) * 8)(a0)
+ stt fs4, ((6 + 37) * 8)(a0)
+ stt fs5, ((7 + 37) * 8)(a0)
+ stt fs6, ((8 + 37) * 8)(a0)
+ stt fs7, ((9 + 37) * 8)(a0)
+ mf_fpcr ft0 /* get FP control reg */
+ stt ft0, (69 * 8)(a0) /* and store it in sc_fpcr */
+ stq zero, (70 * 8)(a0) /* FP software control XXX */
+ stq zero, (71 * 8)(a0) /* sc_reserved[0] */
+ stq zero, (72 * 8)(a0) /* sc_reserved[1] */
+ stq zero, (73 * 8)(a0) /* sc_xxx[0] */
+ stq zero, (74 * 8)(a0) /* sc_xxx[1] */
+ stq zero, (75 * 8)(a0) /* sc_xxx[2] */
+ stq zero, (76 * 8)(a0) /* sc_xxx[3] */
+ stq zero, (77 * 8)(a0) /* sc_xxx[4] */
+ stq zero, (78 * 8)(a0) /* sc_xxx[5] */
+ stq zero, (79 * 8)(a0) /* sc_xxx[6] */
+ stq zero, (80 * 8)(a0) /* sc_xxx[7] */
+
+ mov zero, v0 /* return zero */
+ RET
+END(setjmp)
+
+XLEAF(longjmp, 2)
+LEAF(__longjmp, 2)
+ LDGP(pv)
+ mov a1, s1 /* save return value */
+ mov a0, s0 /* save the sc pointer */
+ /* restore the mask */
+ mov zero, a2 /* oset: NULL */
+ lda a1, (71 * 8)(a0) /* set: sc_reserved */
+ addq a2, 3, a0 /* how: SIG_SET */
+ CALL(_sigprocmask) /* restore the mask */
+ mov s0, a0 /* restore the sc pointer */
+ mov s1, a1 /* restore the return value */
+ jmp zero, ___longjmp /* use ___longjmp to return */
+
+botch:
+ CALL(longjmperror)
+ CALL(abort)
+ RET /* "can't" get here... */
+END(__longjmp)
diff --git a/lib/libc/alpha/gen/signalcontext.c b/lib/libc/alpha/gen/signalcontext.c
new file mode 100644
index 0000000..a3f6397
--- /dev/null
+++ b/lib/libc/alpha/gen/signalcontext.c
@@ -0,0 +1,103 @@
+/*
+ * 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/param.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 ctx_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. We only need 3 arguments, but we
+ * create room for 4 so that we are 16-byte aligned.
+ */
+ sp = (ucp->uc_mcontext.mc_regs[FRAME_SP] - 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 -= 4 * sizeof(uint64_t);
+ args = (uint64_t *)sp;
+ args[0] = sig;
+ args[1] = (intptr_t)sig_si;
+ args[2] = (intptr_t)sig_uc;
+ args[3] = 0;
+
+ /*
+ * 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_format = _MC_REV0_TRAPFRAME;
+ ucp->uc_mcontext.mc_regs[FRAME_A0] = (register_t)ucp;
+ ucp->uc_mcontext.mc_regs[FRAME_A1] = (register_t)func;
+ ucp->uc_mcontext.mc_regs[FRAME_A1] = (register_t)args;
+ ucp->uc_mcontext.mc_regs[FRAME_SP] = (register_t)sp;
+ ucp->uc_mcontext.mc_regs[FRAME_PC] = (register_t)ctx_wrapper;
+ ucp->uc_mcontext.mc_regs[FRAME_RA] = (register_t)ctx_wrapper;
+ ucp->uc_mcontext.mc_regs[FRAME_T12] = (register_t)ctx_wrapper;
+ return (0);
+}
+
+static void
+ctx_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/alpha/gen/sigsetjmp.S b/lib/libc/alpha/gen/sigsetjmp.S
new file mode 100644
index 0000000..0f7e400
--- /dev/null
+++ b/lib/libc/alpha/gen/sigsetjmp.S
@@ -0,0 +1,64 @@
+/* $NetBSD: sigsetjmp.S,v 1.2 1996/10/17 03:08:07 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * C library -- sigsetjmp, siglongjmp
+ *
+ * siglongjmp(a,v)
+ * will generate a "return(v)" from
+ * the last call to
+ * sigsetjmp(a, mask)
+ * by restoring registers from the stack.
+ * If `mask' is non-zero, the previous signal
+ * state will be restored.
+ */
+
+ .set noreorder
+
+LEAF(sigsetjmp, 2)
+ LDGP(pv)
+ stq a1, (81 * 8)(a0) /* save the mask */
+ bne a1, Lsavesig /* if !zero, save signals */
+ jmp zero, _setjmp /* else don't. */
+Lsavesig:
+ jmp zero, setjmp
+END(sigsetjmp)
+
+XLEAF(siglongjmp, 2)
+LEAF(__siglongjmp, 2)
+ LDGP(pv)
+ ldq t0, (81 * 8)(a0) /* get the mask */
+ bne t0, Lrestoresig /* if !zero, restore signals */
+ jmp zero, ___longjmp
+Lrestoresig:
+ jmp zero, __longjmp
+END(__siglongjmp)
diff --git a/lib/libc/alpha/net/Makefile.inc b/lib/libc/alpha/net/Makefile.inc
new file mode 100644
index 0000000..b717813
--- /dev/null
+++ b/lib/libc/alpha/net/Makefile.inc
@@ -0,0 +1,3 @@
+# $FreeBSD$
+
+SRCS+= htonl.S htons.S ntohl.S ntohs.S
diff --git a/lib/libc/alpha/net/byte_swap_2.S b/lib/libc/alpha/net/byte_swap_2.S
new file mode 100644
index 0000000..d7933c4
--- /dev/null
+++ b/lib/libc/alpha/net/byte_swap_2.S
@@ -0,0 +1,49 @@
+/* $NetBSD: byte_swap_2.S,v 1.2 1996/10/17 03:08:08 cgd Exp $ */
+
+/*
+ * Copyright (c) 1996 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#if !defined(ALIAS) || !defined(NAME)
+#error ALIAS or NAME not defined
+#endif
+
+/*
+ * Byte-swap a 2-byte quantity. (Convert 0x0123 to 0x2301.)
+ *
+ * Argument is an unsigned 2-byte integer (u_int16_t).
+ */
+XLEAF(ALIAS, 1)
+LEAF(NAME, 1) /* a0 contains 0x0123 */
+ extbl a0, 0, t0 /* t0 = 0x 23 */
+ extbl a0, 1, t1 /* t1 = 0x 01 */
+ sll t0, 8, t0 /* t1 = 0x23 */
+ or t0, t1, v0 /* v0 = 0x2301 */
+ RET
+END(NAME)
diff --git a/lib/libc/alpha/net/byte_swap_4.S b/lib/libc/alpha/net/byte_swap_4.S
new file mode 100644
index 0000000..04acc85
--- /dev/null
+++ b/lib/libc/alpha/net/byte_swap_4.S
@@ -0,0 +1,55 @@
+/* $NetBSD: byte_swap_4.S,v 1.2 1996/10/17 03:08:09 cgd Exp $ */
+
+/*
+ * Copyright (c) 1996 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#if !defined(ALIAS) || !defined(NAME)
+#error ALIAS or NAME not defined
+#endif
+
+/*
+ * Byte-swap a 4-byte quantity. (Convert 0x01234567 to 0x67452301.)
+ *
+ * Argument is an unsigned 4-byte integer (u_int32_t).
+ */
+XLEAF(ALIAS, 1)
+LEAF(NAME, 1) /* a0 contains 0x01234567 */
+ extbl a0, 0, t0 /* t0 = 0x 67 */
+ extbl a0, 1, t1 /* t1 = 0x 45 */
+ extbl a0, 2, t2 /* t2 = 0x 23 */
+ extbl a0, 3, t3 /* t3 = 0x 01 */
+ sll t0, 24, t0 /* t0 = 0x67 */
+ sll t1, 16, t1 /* t1 = 0x 45 */
+ sll t2, 8, t2 /* t2 = 0x 23 */
+ or t3, t0, v0 /* v0 = 0x67 01 */
+ or t1, t2, t1 /* t1 = 0x 4523 */
+ or t1, v0, v0 /* v0 = 0x67452301 */
+ RET
+END(NAME)
diff --git a/lib/libc/alpha/net/htonl.S b/lib/libc/alpha/net/htonl.S
new file mode 100644
index 0000000..05c906c
--- /dev/null
+++ b/lib/libc/alpha/net/htonl.S
@@ -0,0 +1,36 @@
+/* $NetBSD: htonl.S,v 1.1 1996/04/17 22:36:52 cgd Exp $ */
+
+/*
+ * Copyright (c) 1996 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#define ALIAS htonl
+#define NAME __htonl
+
+#include "byte_swap_4.S"
diff --git a/lib/libc/alpha/net/htons.S b/lib/libc/alpha/net/htons.S
new file mode 100644
index 0000000..4bd3a8b
--- /dev/null
+++ b/lib/libc/alpha/net/htons.S
@@ -0,0 +1,36 @@
+/* $NetBSD: htons.S,v 1.1 1996/04/17 22:36:54 cgd Exp $ */
+
+/*
+ * Copyright (c) 1996 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#define ALIAS htons
+#define NAME __htons
+
+#include "byte_swap_2.S"
diff --git a/lib/libc/alpha/net/ntohl.S b/lib/libc/alpha/net/ntohl.S
new file mode 100644
index 0000000..a08a162
--- /dev/null
+++ b/lib/libc/alpha/net/ntohl.S
@@ -0,0 +1,36 @@
+/* $NetBSD: ntohl.S,v 1.1 1996/04/17 22:36:57 cgd Exp $ */
+
+/*
+ * Copyright (c) 1996 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#define ALIAS ntohl
+#define NAME __ntohl
+
+#include "byte_swap_4.S"
diff --git a/lib/libc/alpha/net/ntohs.S b/lib/libc/alpha/net/ntohs.S
new file mode 100644
index 0000000..79e6e0c
--- /dev/null
+++ b/lib/libc/alpha/net/ntohs.S
@@ -0,0 +1,36 @@
+/* $NetBSD: ntohs.S,v 1.1 1996/04/17 22:37:02 cgd Exp $ */
+
+/*
+ * Copyright (c) 1996 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#define ALIAS ntohs
+#define NAME __ntohs
+
+#include "byte_swap_2.S"
diff --git a/lib/libc/alpha/stdlib/Makefile.inc b/lib/libc/alpha/stdlib/Makefile.inc
new file mode 100644
index 0000000..dda8c76
--- /dev/null
+++ b/lib/libc/alpha/stdlib/Makefile.inc
@@ -0,0 +1,3 @@
+# $FreeBSD$
+
+MDSRCS+= abs.c div.c labs.c ldiv.c
diff --git a/lib/libc/alpha/string/Makefile.inc b/lib/libc/alpha/string/Makefile.inc
new file mode 100644
index 0000000..7bbcc8d
--- /dev/null
+++ b/lib/libc/alpha/string/Makefile.inc
@@ -0,0 +1,3 @@
+# $FreeBSD$
+
+MDSRCS+= bcopy.S bzero.S ffs.S memcpy.S memmove.S
diff --git a/lib/libc/alpha/string/bcopy.S b/lib/libc/alpha/string/bcopy.S
new file mode 100644
index 0000000..dc23063
--- /dev/null
+++ b/lib/libc/alpha/string/bcopy.S
@@ -0,0 +1,289 @@
+/* $NetBSD: bcopy.S,v 1.3 1996/10/17 03:08:11 cgd Exp $ */
+
+/*
+ * Copyright (c) 1995 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Trevor Blackwell. Support for use as memcpy() and memmove()
+ * added by Chris Demetriou.
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#if defined(MEMCOPY) || defined(MEMMOVE)
+#ifdef MEMCOPY
+#define FUNCTION memcpy
+#else
+#define FUNCTION memmove
+#endif
+#define SRCREG a1
+#define DSTREG a0
+#else /* !(defined(MEMCOPY) || defined(MEMMOVE)) */
+#define FUNCTION bcopy
+#define SRCREG a0
+#define DSTREG a1
+#endif /* !(defined(MEMCOPY) || defined(MEMMOVE)) */
+
+#define SIZEREG a2
+
+/*
+ * Copy bytes.
+ *
+ * void bcopy(char *from, char *to, size_t len);
+ * char *memcpy(void *to, const void *from, size_t len);
+ * char *memmove(void *to, const void *from, size_t len);
+ *
+ * No matter how invoked, the source and destination registers
+ * for calculation. There's no point in copying them to "working"
+ * registers, since the code uses their values "in place," and
+ * copying them would be slower.
+ */
+
+LEAF(FUNCTION,3)
+
+#if defined(MEMCOPY) || defined(MEMMOVE)
+ /* set up return value, while we still can */
+ mov DSTREG,v0
+#endif
+
+ /* Check for negative length */
+ ble SIZEREG,bcopy_done
+
+ /* Check for overlap */
+ subq DSTREG,SRCREG,t5
+ cmpult t5,SIZEREG,t5
+ bne t5,bcopy_overlap
+
+ /* a3 = end address */
+ addq SRCREG,SIZEREG,a3
+
+ /* Get the first word */
+ ldq_u t2,0(SRCREG)
+
+ /* Do they have the same alignment? */
+ xor SRCREG,DSTREG,t0
+ and t0,7,t0
+ and DSTREG,7,t1
+ bne t0,bcopy_different_alignment
+
+ /* src & dst have same alignment */
+ beq t1,bcopy_all_aligned
+
+ ldq_u t3,0(DSTREG)
+ addq SIZEREG,t1,SIZEREG
+ mskqh t2,SRCREG,t2
+ mskql t3,SRCREG,t3
+ or t2,t3,t2
+
+ /* Dst is 8-byte aligned */
+
+bcopy_all_aligned:
+ /* If less than 8 bytes,skip loop */
+ subq SIZEREG,1,t0
+ and SIZEREG,7,SIZEREG
+ bic t0,7,t0
+ beq t0,bcopy_samealign_lp_end
+
+bcopy_samealign_lp:
+ stq_u t2,0(DSTREG)
+ addq DSTREG,8,DSTREG
+ ldq_u t2,8(SRCREG)
+ subq t0,8,t0
+ addq SRCREG,8,SRCREG
+ bne t0,bcopy_samealign_lp
+
+bcopy_samealign_lp_end:
+ /* If we're done, exit */
+ bne SIZEREG,bcopy_small_left
+ stq_u t2,0(DSTREG)
+ RET
+
+bcopy_small_left:
+ mskql t2,SIZEREG,t4
+ ldq_u t3,0(DSTREG)
+ mskqh t3,SIZEREG,t3
+ or t4,t3,t4
+ stq_u t4,0(DSTREG)
+ RET
+
+bcopy_different_alignment:
+ /*
+ * this is the fun part
+ */
+ addq SRCREG,SIZEREG,a3
+ cmpule SIZEREG,8,t0
+ bne t0,bcopy_da_finish
+
+ beq t1,bcopy_da_noentry
+
+ /* Do the initial partial word */
+ subq zero,DSTREG,t0
+ and t0,7,t0
+ ldq_u t3,7(SRCREG)
+ extql t2,SRCREG,t2
+ extqh t3,SRCREG,t3
+ or t2,t3,t5
+ insql t5,DSTREG,t5
+ ldq_u t6,0(DSTREG)
+ mskql t6,DSTREG,t6
+ or t5,t6,t5
+ stq_u t5,0(DSTREG)
+ addq SRCREG,t0,SRCREG
+ addq DSTREG,t0,DSTREG
+ subq SIZEREG,t0,SIZEREG
+ ldq_u t2,0(SRCREG)
+
+bcopy_da_noentry:
+ subq SIZEREG,1,t0
+ bic t0,7,t0
+ and SIZEREG,7,SIZEREG
+ beq t0,bcopy_da_finish2
+
+bcopy_da_lp:
+ ldq_u t3,7(SRCREG)
+ addq SRCREG,8,SRCREG
+ extql t2,SRCREG,t4
+ extqh t3,SRCREG,t5
+ subq t0,8,t0
+ or t4,t5,t5
+ stq t5,0(DSTREG)
+ addq DSTREG,8,DSTREG
+ beq t0,bcopy_da_finish1
+ ldq_u t2,7(SRCREG)
+ addq SRCREG,8,SRCREG
+ extql t3,SRCREG,t4
+ extqh t2,SRCREG,t5
+ subq t0,8,t0
+ or t4,t5,t5
+ stq t5,0(DSTREG)
+ addq DSTREG,8,DSTREG
+ bne t0,bcopy_da_lp
+
+bcopy_da_finish2:
+ /* Do the last new word */
+ mov t2,t3
+
+bcopy_da_finish1:
+ /* Do the last partial word */
+ ldq_u t2,-1(a3)
+ extql t3,SRCREG,t3
+ extqh t2,SRCREG,t2
+ or t2,t3,t2
+ br zero,bcopy_samealign_lp_end
+
+bcopy_da_finish:
+ /* Do the last word in the next source word */
+ ldq_u t3,-1(a3)
+ extql t2,SRCREG,t2
+ extqh t3,SRCREG,t3
+ or t2,t3,t2
+ insqh t2,DSTREG,t3
+ insql t2,DSTREG,t2
+ lda t4,-1(zero)
+ mskql t4,SIZEREG,t5
+ cmovne t5,t5,t4
+ insqh t4,DSTREG,t5
+ insql t4,DSTREG,t4
+ addq DSTREG,SIZEREG,a4
+ ldq_u t6,0(DSTREG)
+ ldq_u t7,-1(a4)
+ bic t6,t4,t6
+ bic t7,t5,t7
+ and t2,t4,t2
+ and t3,t5,t3
+ or t2,t6,t2
+ or t3,t7,t3
+ stq_u t3,-1(a4)
+ stq_u t2,0(DSTREG)
+ RET
+
+bcopy_overlap:
+ /*
+ * Basically equivalent to previous case, only backwards.
+ * Not quite as highly optimized
+ */
+ addq SRCREG,SIZEREG,a3
+ addq DSTREG,SIZEREG,a4
+
+ /* less than 8 bytes - don't worry about overlap */
+ cmpule SIZEREG,8,t0
+ bne t0,bcopy_ov_short
+
+ /* Possibly do a partial first word */
+ and a4,7,t4
+ beq t4,bcopy_ov_nostart2
+ subq a3,t4,a3
+ subq a4,t4,a4
+ ldq_u t1,0(a3)
+ subq SIZEREG,t4,SIZEREG
+ ldq_u t2,7(a3)
+ ldq t3,0(a4)
+ extql t1,a3,t1
+ extqh t2,a3,t2
+ or t1,t2,t1
+ mskqh t3,t4,t3
+ mskql t1,t4,t1
+ or t1,t3,t1
+ stq t1,0(a4)
+
+bcopy_ov_nostart2:
+ bic SIZEREG,7,t4
+ and SIZEREG,7,SIZEREG
+ beq t4,bcopy_ov_lp_end
+
+bcopy_ov_lp:
+ /* This could be more pipelined, but it doesn't seem worth it */
+ ldq_u t0,-8(a3)
+ subq a4,8,a4
+ ldq_u t1,-1(a3)
+ subq a3,8,a3
+ extql t0,a3,t0
+ extqh t1,a3,t1
+ subq t4,8,t4
+ or t0,t1,t0
+ stq t0,0(a4)
+ bne t4,bcopy_ov_lp
+
+bcopy_ov_lp_end:
+ beq SIZEREG,bcopy_done
+
+ ldq_u t0,0(SRCREG)
+ ldq_u t1,7(SRCREG)
+ ldq_u t2,0(DSTREG)
+ extql t0,SRCREG,t0
+ extqh t1,SRCREG,t1
+ or t0,t1,t0
+ insql t0,DSTREG,t0
+ mskql t2,DSTREG,t2
+ or t2,t0,t2
+ stq_u t2,0(DSTREG)
+
+bcopy_done:
+ RET
+
+bcopy_ov_short:
+ ldq_u t2,0(SRCREG)
+ br zero,bcopy_da_finish
+
+ END(FUNCTION)
diff --git a/lib/libc/alpha/string/bzero.S b/lib/libc/alpha/string/bzero.S
new file mode 100644
index 0000000..dd94200
--- /dev/null
+++ b/lib/libc/alpha/string/bzero.S
@@ -0,0 +1,111 @@
+/* $NetBSD: bzero.S,v 1.2 1996/10/17 03:08:12 cgd Exp $ */
+
+/*
+ * Copyright (c) 1995 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Trevor Blackwell
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+LEAF(bzero,2)
+ ble a1,bzero_done
+ bic a1,63,t3 /* t3 is # bytes to do 64 bytes at a time */
+
+ /* If nothing in first word, ignore it */
+ subq zero,a0,t0
+ and t0,7,t0 /* t0 = (0-size)%8 */
+ beq t0,bzero_nostart1
+
+ cmpult a1,t0,t1 /* if size > size%8 goto noshort */
+ beq t1,bzero_noshort
+
+ /*
+ * The whole thing is less than a word.
+ * Mask off 1..7 bytes, and finish.
+ */
+ ldq_u t2,0(a0)
+ lda t0,-1(zero) /* t0=-1 */
+ mskql t0,a1,t0 /* Get ff in bytes (a0%8)..((a0+a1-1)%8) */
+ insql t0,a0,t0
+ bic t2,t0,t2 /* zero those bytes in word */
+ stq_u t2,0(a0)
+ RET
+
+bzero_noshort:
+ /* Handle the first partial word */
+ ldq_u t2,0(a0)
+ subq a1,t0,a1
+ mskql t2,a0,t2 /* zero bytes (a0%8)..7 in word */
+ stq_u t2,0(a0)
+
+ addq a0,t0,a0 /* round a0 up to next word */
+ bic a1,63,t3 /* recalc t3 (# bytes to do 64 bytes at a
+ time) */
+
+bzero_nostart1:
+ /*
+ * Loop, zeroing 64 bytes at a time
+ */
+ beq t3,bzero_lp_done
+bzero_lp:
+ stq zero,0(a0)
+ stq zero,8(a0)
+ stq zero,16(a0)
+ stq zero,24(a0)
+ subq t3,64,t3
+ stq zero,32(a0)
+ stq zero,40(a0)
+ stq zero,48(a0)
+ stq zero,56(a0)
+ addq a0,64,a0
+ bne t3,bzero_lp
+
+bzero_lp_done:
+ /*
+ * Handle the last 0..7 words.
+ * We mask off the low bits, so we don't need an extra
+ * compare instruction for the loop (just a bne. heh-heh)
+ */
+ and a1,0x38,t4
+ beq t4,bzero_finish_lp_done
+bzero_finish_lp:
+ stq zero,0(a0)
+ subq t4,8,t4
+ addq a0,8,a0
+ bne t4,bzero_finish_lp
+
+ /* Do the last partial word */
+bzero_finish_lp_done:
+ and a1,7,t5 /* 0..7 bytes left */
+ beq t5,bzero_done /* mskqh won't change t0 if t5==0, but I
+ don't want to touch, say, a new VM page */
+ ldq t0,0(a0)
+ mskqh t0,t5,t0
+ stq t0,0(a0)
+bzero_done:
+ RET
+
+ END(bzero)
diff --git a/lib/libc/alpha/string/ffs.S b/lib/libc/alpha/string/ffs.S
new file mode 100644
index 0000000..11147d6
--- /dev/null
+++ b/lib/libc/alpha/string/ffs.S
@@ -0,0 +1,92 @@
+/* $NetBSD: ffs.S,v 1.3 1996/10/17 03:08:13 cgd Exp $ */
+
+/*
+ * Copyright (c) 1995 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 by Christopher G. Demetriou
+ * 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 <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+LEAF(ffs, 1)
+ addl a0, 0, t0
+ beq t0, Lallzero
+
+ /*
+ * Initialize return value (v0), and set up t1 so that it
+ * contains the mask with only the lowest bit set.
+ */
+ subl zero, t0, t1
+ ldil v0, 1
+ and t0, t1, t1
+
+ and t1, 0xff, t2
+ bne t2, Ldo8
+
+ /*
+ * If lower 16 bits empty, add 16 to result and use upper 16.
+ */
+ zapnot t1, 0x03, t3
+ bne t3, Ldo16
+ sra t1, 16, t1
+ addl v0, 16, v0
+
+Ldo16:
+ /*
+ * If lower 8 bits empty, add 8 to result and use upper 8.
+ */
+ and t1, 0xff, t4
+ bne t4, Ldo8
+ sra t1, 8, t1
+ addl v0, 8, v0
+
+Ldo8:
+ and t1, 0x0f, t5 /* lower 4 of 8 empty? */
+ and t1, 0x33, t6 /* lower 2 of each 4 empty? */
+ and t1, 0x55, t7 /* lower 1 of each 2 empty? */
+
+ /* If lower 4 bits empty, add 4 to result. */
+ bne t5, Ldo4
+ addl v0, 4, v0
+
+Ldo4: /* If lower 2 bits of each 4 empty, add 2 to result. */
+ bne t6, Ldo2
+ addl v0, 2, v0
+
+Ldo2: /* If lower bit of each 2 empty, add 1 to result. */
+ bne t7, Ldone
+ addl v0, 1, v0
+
+Ldone:
+ RET
+
+Lallzero:
+ bis zero, zero, v0
+ RET
+END(ffs)
diff --git a/lib/libc/alpha/string/memcpy.S b/lib/libc/alpha/string/memcpy.S
new file mode 100644
index 0000000..ef50ab1
--- /dev/null
+++ b/lib/libc/alpha/string/memcpy.S
@@ -0,0 +1,8 @@
+/* $NetBSD: memcpy.S,v 1.1 1995/08/13 00:40:47 cgd Exp $ */
+
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#define MEMCOPY
+#include "bcopy.S"
diff --git a/lib/libc/alpha/string/memmove.S b/lib/libc/alpha/string/memmove.S
new file mode 100644
index 0000000..ad80b1c
--- /dev/null
+++ b/lib/libc/alpha/string/memmove.S
@@ -0,0 +1,7 @@
+/* $NetBSD: memmove.S,v 1.1 1995/08/13 00:40:48 cgd Exp $ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#define MEMMOVE
+#include "bcopy.S"
diff --git a/lib/libc/alpha/sys/Makefile.inc b/lib/libc/alpha/sys/Makefile.inc
new file mode 100644
index 0000000..d0b21ed
--- /dev/null
+++ b/lib/libc/alpha/sys/Makefile.inc
@@ -0,0 +1,12 @@
+# $FreeBSD$
+
+MDASM+= Ovfork.S brk.S cerror.S exect.S fork.S pipe.S ptrace.S \
+ sbrk.S setlogin.S sigreturn.S
+
+# Don't generate default code for these syscalls:
+NOASM= break.o exit.o ftruncate.o getdomainname.o getlogin.o \
+ lseek.o mmap.o openbsd_poll.o pread.o \
+ pwrite.o setdomainname.o sstk.o truncate.o uname.o vfork.o yield.o
+
+PSEUDO= _getlogin.o _exit.o
+
diff --git a/lib/libc/alpha/sys/Ovfork.S b/lib/libc/alpha/sys/Ovfork.S
new file mode 100644
index 0000000..99663f1
--- /dev/null
+++ b/lib/libc/alpha/sys/Ovfork.S
@@ -0,0 +1,38 @@
+/* $NetBSD: Ovfork.S,v 1.1 1995/02/10 17:50:29 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+SYSCALL(vfork)
+ cmovne a4, zero, v0 /* a4 (rv[1]) != 0, child */
+ RET
+END(__sys_vfork)
diff --git a/lib/libc/alpha/sys/brk.S b/lib/libc/alpha/sys/brk.S
new file mode 100644
index 0000000..9f3385b
--- /dev/null
+++ b/lib/libc/alpha/sys/brk.S
@@ -0,0 +1,53 @@
+/* $NetBSD: brk.S,v 1.4 1996/10/17 03:08:15 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+ .globl _end
+IMPORT(curbrk, 8)
+
+ .data
+EXPORT(minbrk)
+ .quad _end
+
+ .text
+LEAF(brk, 1)
+ br pv, L1 /* XXX profiling */
+L1: LDGP(pv)
+ ldq v0, minbrk
+ cmpult a0, v0, t0
+ cmovne t0, v0, a0
+ CALLSYS_ERROR(break)
+ stq a0, curbrk
+ mov zero, v0
+ RET
+END(brk)
diff --git a/lib/libc/alpha/sys/cerror.S b/lib/libc/alpha/sys/cerror.S
new file mode 100644
index 0000000..5744129
--- /dev/null
+++ b/lib/libc/alpha/sys/cerror.S
@@ -0,0 +1,56 @@
+/* $NetBSD: cerror.S,v 1.4 1996/11/08 00:52:46 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+#define FRAME_SIZE 16
+#define FRAME_RA_OFFSET 0
+#define FRAME_V0_OFFSET 8
+
+NESTED(.cerror, 0, FRAME_SIZE, ra, IM_RA|IM_V0, 0)
+ br t0, L1
+L1: LDGP(t0)
+
+ lda sp, -FRAME_SIZE(sp)
+ stq ra, FRAME_RA_OFFSET(sp)
+ stq v0, FRAME_V0_OFFSET(sp)
+
+ CALL(__error)
+
+ ldq t0, FRAME_V0_OFFSET(sp)
+ stl t0, 0(v0)
+
+ ldiq v0, -1
+ ldq ra, FRAME_RA_OFFSET(sp)
+ lda sp, FRAME_SIZE(sp)
+ RET
+END(.cerror)
diff --git a/lib/libc/alpha/sys/exect.S b/lib/libc/alpha/sys/exect.S
new file mode 100644
index 0000000..8ad065f
--- /dev/null
+++ b/lib/libc/alpha/sys/exect.S
@@ -0,0 +1,38 @@
+/* $NetBSD: exect.S,v 1.2 1996/10/17 03:08:18 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+LEAF(exect, 3)
+ CALLSYS_ERROR(execve)
+ RET
+END(exect)
diff --git a/lib/libc/alpha/sys/fork.S b/lib/libc/alpha/sys/fork.S
new file mode 100644
index 0000000..5f40896
--- /dev/null
+++ b/lib/libc/alpha/sys/fork.S
@@ -0,0 +1,38 @@
+/* $NetBSD: fork.S,v 1.1 1995/02/10 17:50:34 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+SYSCALL(fork)
+ cmovne a4, zero, v0 /* a4 (rv[1]) != 0, child */
+ RET
+END(__sys_fork)
diff --git a/lib/libc/alpha/sys/pipe.S b/lib/libc/alpha/sys/pipe.S
new file mode 100644
index 0000000..e94398e
--- /dev/null
+++ b/lib/libc/alpha/sys/pipe.S
@@ -0,0 +1,40 @@
+/* $NetBSD: pipe.S,v 1.1 1995/02/10 17:50:35 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+SYSCALL(pipe)
+ stl v0, 0(a0)
+ stl a4, 4(a0)
+ mov zero, v0
+ RET
+END(__sys_pipe)
diff --git a/lib/libc/alpha/sys/ptrace.S b/lib/libc/alpha/sys/ptrace.S
new file mode 100644
index 0000000..8e4c371
--- /dev/null
+++ b/lib/libc/alpha/sys/ptrace.S
@@ -0,0 +1,40 @@
+/* $NetBSD: ptrace.S,v 1.4 1996/11/08 00:51:24 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+LEAF(ptrace, 4)
+ LDGP(pv)
+ stl zero, errno
+ CALLSYS_ERROR(ptrace)
+ RET
+END(ptrace)
diff --git a/lib/libc/alpha/sys/sbrk.S b/lib/libc/alpha/sys/sbrk.S
new file mode 100644
index 0000000..4d79906
--- /dev/null
+++ b/lib/libc/alpha/sys/sbrk.S
@@ -0,0 +1,53 @@
+/* $NetBSD: sbrk.S,v 1.4 1996/10/17 03:08:20 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+ .globl _end
+
+ .data
+EXPORT(curbrk)
+ .quad _end
+
+ .text
+LEAF(sbrk, 1)
+ br pv, L1 /* XXX profiling */
+L1: LDGP(pv)
+ ldq a1, curbrk
+ beq a0, L2
+ addq a0, a1, a0
+ CALLSYS_ERROR(break)
+ stq a0, curbrk
+L2:
+ mov a1, v0
+ RET
+END(sbrk)
diff --git a/lib/libc/alpha/sys/setlogin.S b/lib/libc/alpha/sys/setlogin.S
new file mode 100644
index 0000000..00b1d3c
--- /dev/null
+++ b/lib/libc/alpha/sys/setlogin.S
@@ -0,0 +1,40 @@
+/* $NetBSD: setlogin.S,v 1.1 1995/02/10 17:50:39 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+IMPORT(_logname_valid, 4) /* in _getlogin() */
+
+SYSCALL(setlogin)
+ stl zero, _logname_valid /* clear it */
+ RET
+END(__sys_setlogin)
diff --git a/lib/libc/alpha/sys/sigreturn.S b/lib/libc/alpha/sys/sigreturn.S
new file mode 100644
index 0000000..9b13d5f
--- /dev/null
+++ b/lib/libc/alpha/sys/sigreturn.S
@@ -0,0 +1,41 @@
+/* $NetBSD: sigreturn.S,v 1.1 1995/02/10 17:50:42 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+/*
+ * We must preserve the state of the registers as the user has set them up.
+ * However, that doesn't involve any special work on the Alpha.
+ * (XXX PROFILING)
+ */
+
+RSYSCALL(sigreturn)
diff --git a/lib/libc/amd64/Makefile.inc b/lib/libc/amd64/Makefile.inc
new file mode 100644
index 0000000..e3f0c48
--- /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+=strtopx.c
+MDSRCS+=machdep_ldisx.c
+SYM_MAPS+=${.CURDIR}/amd64/Symbol.map
diff --git a/lib/libc/amd64/SYS.h b/lib/libc/amd64/SYS.h
new file mode 100644
index 0000000..844fe6a
--- /dev/null
+++ b/lib/libc/amd64/SYS.h
@@ -0,0 +1,66 @@
+/*-
+ * 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. 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.
+ *
+ * @(#)SYS.h 5.5 (Berkeley) 5/7/91
+ * $FreeBSD$
+ */
+
+#include <sys/syscall.h>
+#include <machine/asm.h>
+
+#ifdef PIC
+#define RSYSCALL(x) ENTRY(__CONCAT(__sys_,x)); \
+ .weak CNAME(x); \
+ .set CNAME(x),CNAME(__CONCAT(__sys_,x)); \
+ .weak CNAME(__CONCAT(_,x)); \
+ .set CNAME(__CONCAT(_,x)),CNAME(__CONCAT(__sys_,x)); \
+ mov __CONCAT($SYS_,x),%rax; KERNCALL; jb 2f; ret; \
+ 2: movq PIC_GOT(HIDENAME(cerror)),%rcx; jmp *%rcx
+#else
+#define RSYSCALL(x) ENTRY(__CONCAT(__sys_,x)); \
+ .weak CNAME(x); \
+ .set CNAME(x),CNAME(__CONCAT(__sys_,x)); \
+ .weak CNAME(__CONCAT(_,x)); \
+ .set CNAME(__CONCAT(_,x)),CNAME(__CONCAT(__sys_,x)); \
+ mov __CONCAT($SYS_,x),%rax; KERNCALL; jb 2f; ret; \
+ 2: jmp HIDENAME(cerror)
+#endif
+
+#define PSEUDO(x) ENTRY(__CONCAT(__sys_,x)); \
+ .weak CNAME(__CONCAT(_,x)); \
+ .set CNAME(__CONCAT(_,x)),CNAME(__CONCAT(__sys_,x)); \
+ mov __CONCAT($SYS_,x),%rax; KERNCALL; ret
+
+#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 0000000..5640062
--- /dev/null
+++ b/lib/libc/amd64/Symbol.map
@@ -0,0 +1,73 @@
+# $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;
+ fpgetprec;
+ fpgetround;
+ fpgetsticky;
+ fpsetmask;
+ fpsetprec;
+ fpsetround;
+ __infinity;
+ __nan;
+ makecontext;
+ modf;
+ rfork_thread;
+ setjmp;
+ longjmp;
+ sigsetjmp;
+ siglongjmp;
+ htonl;
+ __htonl;
+ htons;
+ __htons;
+ ntohl;
+ __ntohl;
+ ntohs;
+ __ntohs;
+ amd64_get_fsbase;
+ amd64_get_gsbase;
+ amd64_set_fsbase;
+ amd64_set_gsbase;
+ brk;
+ exect;
+ sbrk;
+ vfork;
+};
+
+#
+# FreeBSD private ABI
+#
+FBSDprivate {
+ # PSEUDO syscalls
+ __sys_getlogin;
+ _getlogin;
+ __sys_exit;
+
+ _set_tp;
+ ___longjmp;
+ __makecontext;
+ __longjmp;
+ __signalcontext;
+ signalcontext;
+ __siglongjmp;
+ .curbrk;
+ .minbrk;
+ _brk;
+ .cerror;
+ _end;
+ __sys_vfork;
+ _vfork;
+};
diff --git a/lib/libc/amd64/_fpmath.h b/lib/libc/amd64/_fpmath.h
new file mode 100644
index 0000000..8f8cf6f
--- /dev/null
+++ b/lib/libc/amd64/_fpmath.h
@@ -0,0 +1,50 @@
+/*-
+ * 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;
+};
+
+#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 0000000..ecb1a33
--- /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/gen/Makefile.inc b/lib/libc/amd64/gen/Makefile.inc
new file mode 100644
index 0000000..38fe7e1
--- /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 modf.S \
+ 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 0000000..02e5e14
--- /dev/null
+++ b/lib/libc/amd64/gen/_set_tp.c
@@ -0,0 +1,38 @@
+/*-
+ * 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>
+
+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 0000000..eed057b
--- /dev/null
+++ b/lib/libc/amd64/gen/_setjmp.S
@@ -0,0 +1,87 @@
+/*-
+ * 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. 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.
+ */
+
+#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 */
+ xorq %rax,%rax
+ ret
+
+ .weak CNAME(_longjmp)
+ .set CNAME(_longjmp),CNAME(___longjmp)
+ENTRY(___longjmp)
+ 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
+ fninit
+ fldcw 64(%rdx)
+ testq %rax,%rax
+ jnz 1f
+ incq %rax
+1: movq %rcx,0(%rsp)
+ ret
diff --git a/lib/libc/amd64/gen/fabs.S b/lib/libc/amd64/gen/fabs.S
new file mode 100644
index 0000000..59cd910
--- /dev/null
+++ b/lib/libc/amd64/gen/fabs.S
@@ -0,0 +1,43 @@
+/*-
+ * 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
+
+ .data
+signbit:
+ .quad 0x8000000000000000
diff --git a/lib/libc/amd64/gen/flt_rounds.c b/lib/libc/amd64/gen/flt_rounds.c
new file mode 100644
index 0000000..c0ce81f
--- /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 0000000..03bb274
--- /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 0000000..22d2148
--- /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 0000000..9c066b1
--- /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 0000000..c3acb91
--- /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 0000000..996e167
--- /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 0000000..5898de7
--- /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 0000000..6f13367
--- /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/infinity.c b/lib/libc/amd64/gen/infinity.c
new file mode 100644
index 0000000..464b402
--- /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/ldexp.c b/lib/libc/amd64/gen/ldexp.c
new file mode 100644
index 0000000..b01b937
--- /dev/null
+++ b/lib/libc/amd64/gen/ldexp.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
+ * Sean Eric Fagan.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)ldexp.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * ldexp(value, exp): return value * (2 ** exp).
+ *
+ * Written by Sean Eric Fagan (sef@kithrup.COM)
+ * Sun Mar 11 20:27:09 PST 1990
+ */
+
+/*
+ * We do the conversion in C to let gcc optimize it away, if possible.
+ */
+double
+ldexp (double value, int exp)
+{
+ double temp, texp, temp2;
+ texp = exp;
+#ifdef __GNUC__
+ __asm ("fscale "
+ : "=u" (temp2), "=t" (temp)
+ : "0" (texp), "1" (value));
+#else
+#error unknown asm
+#endif
+ return (temp);
+}
diff --git a/lib/libc/amd64/gen/makecontext.c b/lib/libc/amd64/gen/makecontext.c
new file mode 100644
index 0000000..15f10b5
--- /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/modf.S b/lib/libc/amd64/gen/modf.S
new file mode 100644
index 0000000..d448de1
--- /dev/null
+++ b/lib/libc/amd64/gen/modf.S
@@ -0,0 +1,92 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Sean Eric Fagan.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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.
+ *
+ * from: @(#)modf.s 5.5 (Berkeley) 3/18/91
+ */
+
+#include <machine/asm.h>
+#if defined(LIBC_SCCS)
+ RCSID("$NetBSD: modf.S,v 1.5 1997/07/16 14:37:18 christos Exp $")
+#endif
+__FBSDID("$FreeBSD$");
+
+/*
+ * modf(value, iptr): return fractional part of value, and stores the
+ * integral part into iptr (a pointer to double).
+ *
+ * Written by Sean Eric Fagan (sef@kithrup.COM)
+ * Sun Mar 11 20:27:30 PST 1990
+ */
+
+/* With CHOP mode on, frndint behaves as TRUNC does. Useful. */
+ENTRY(modf)
+
+ /*
+ * Set chop mode.
+ */
+ fnstcw -12(%rsp)
+ movw -12(%rsp),%dx
+ orw $3072,%dx
+ movw %dx,-16(%rsp)
+ fldcw -16(%rsp)
+
+ /*
+ * Get integral part.
+ */
+ movsd %xmm0,-24(%rsp)
+ fldl -24(%rsp)
+ frndint
+ fstpl -8(%rsp)
+
+ /*
+ * Restore control word.
+ */
+ fldcw -12(%rsp)
+
+ /*
+ * Store integral part.
+ */
+ movsd -8(%rsp),%xmm0
+ movsd %xmm0,(%rdi)
+
+ /*
+ * Get fractional part and return it.
+ */
+ fldl -24(%rsp)
+ fsubl -8(%rsp)
+ fstpl -8(%rsp)
+ movsd -8(%rsp),%xmm0
+
+ ret
diff --git a/lib/libc/amd64/gen/rfork_thread.S b/lib/libc/amd64/gen/rfork_thread.S
new file mode 100644
index 0000000..aa7001c
--- /dev/null
+++ b/lib/libc/amd64/gen/rfork_thread.S
@@ -0,0 +1,101 @@
+/*-
+ * 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
+#ifdef PIC
+ movq PIC_GOT(HIDENAME(cerror)), %rdx
+ jmp *%rdx
+#else
+ jmp HIDENAME(cerror)
+#endif
diff --git a/lib/libc/amd64/gen/setjmp.S b/lib/libc/amd64/gen/setjmp.S
new file mode 100644
index 0000000..14696f6
--- /dev/null
+++ b/lib/libc/amd64/gen/setjmp.S
@@ -0,0 +1,105 @@
+/*-
+ * 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. 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.
+ */
+
+#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 */
+ call PIC_PLT(CNAME(_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 */
+ xorq %rax,%rax
+ ret
+
+ .weak CNAME(longjmp)
+ .set CNAME(longjmp),CNAME(__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 */
+ call PIC_PLT(CNAME(_sigprocmask))
+ popq %rsi
+ popq %rdi /* jmpbuf */
+ 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
+ fninit
+ fldcw 64(%rdx)
+ testq %rax,%rax
+ jnz 1f
+ incq %rax
+1: movq %rcx,0(%rsp)
+ ret
diff --git a/lib/libc/amd64/gen/signalcontext.c b/lib/libc/amd64/gen/signalcontext.c
new file mode 100644
index 0000000..1a2621a
--- /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 0000000..3b13801
--- /dev/null
+++ b/lib/libc/amd64/gen/sigsetjmp.S
@@ -0,0 +1,115 @@
+/*-
+ * 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. 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.
+ *
+ * @(#)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 */
+ call PIC_PLT(CNAME(_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
+
+ .weak CNAME(siglongjmp)
+ .set CNAME(siglongjmp),CNAME(__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 */
+ call PIC_PLT(CNAME(_sigprocmask))
+ 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
+ fninit
+ fldcw 64(%rdx)
+ testq %rax,%rax
+ jnz 1f
+ incq %rax
+1: movq %rcx,0(%rsp)
+ ret
diff --git a/lib/libc/amd64/net/Makefile.inc b/lib/libc/amd64/net/Makefile.inc
new file mode 100644
index 0000000..96e559b
--- /dev/null
+++ b/lib/libc/amd64/net/Makefile.inc
@@ -0,0 +1,4 @@
+# @(#)Makefile.inc 8.1 (Berkeley) 6/4/93
+# $FreeBSD$
+
+SRCS+= htonl.S htons.S ntohl.S ntohs.S
diff --git a/lib/libc/amd64/net/htonl.S b/lib/libc/amd64/net/htonl.S
new file mode 100644
index 0000000..8d802d6
--- /dev/null
+++ b/lib/libc/amd64/net/htonl.S
@@ -0,0 +1,50 @@
+/*-
+ * 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. 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+ .asciz "@(#)htonl.s 5.3 (Berkeley) 12/17/90"
+#endif /* LIBC_SCCS and not lint */
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/* netorder = htonl(hostorder) */
+
+ .weak CNAME(htonl)
+ .set CNAME(htonl),CNAME(__htonl)
+ENTRY(__htonl)
+ movl %edi,%eax
+ bswap %eax
+ ret
diff --git a/lib/libc/amd64/net/htons.S b/lib/libc/amd64/net/htons.S
new file mode 100644
index 0000000..6940ef0
--- /dev/null
+++ b/lib/libc/amd64/net/htons.S
@@ -0,0 +1,50 @@
+/*-
+ * 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. 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+ .asciz "@(#)htons.s 5.2 (Berkeley) 12/17/90"
+#endif /* LIBC_SCCS and not lint */
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/* netorder = htons(hostorder) */
+
+ .weak CNAME(htons)
+ .set CNAME(htons),CNAME(__htons)
+ENTRY(__htons)
+ movl %edi,%eax
+ xchgb %al,%ah
+ ret
diff --git a/lib/libc/amd64/net/ntohl.S b/lib/libc/amd64/net/ntohl.S
new file mode 100644
index 0000000..e5e2150
--- /dev/null
+++ b/lib/libc/amd64/net/ntohl.S
@@ -0,0 +1,50 @@
+/*-
+ * 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. 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+ .asciz "@(#)ntohl.s 5.2 (Berkeley) 12/17/90"
+#endif /* LIBC_SCCS and not lint */
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/* hostorder = ntohl(netorder) */
+
+ .weak CNAME(ntohl)
+ .set CNAME(ntohl),CNAME(__ntohl)
+ENTRY(__ntohl)
+ movl %edi,%eax
+ bswap %eax
+ ret
diff --git a/lib/libc/amd64/net/ntohs.S b/lib/libc/amd64/net/ntohs.S
new file mode 100644
index 0000000..02e4441
--- /dev/null
+++ b/lib/libc/amd64/net/ntohs.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.
+ * 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+ .asciz "@(#)ntohs.s 5.2 (Berkeley) 12/17/90"
+#endif /* LIBC_SCCS and not lint */
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/* hostorder = ntohs(netorder) */
+
+#include <machine/asm.h>
+
+ .weak CNAME(ntohs)
+ .set CNAME(ntohs),CNAME(__ntohs)
+ENTRY(__ntohs)
+ movl %edi,%eax
+ xchgb %al,%ah
+ ret
diff --git a/lib/libc/amd64/string/Makefile.inc b/lib/libc/amd64/string/Makefile.inc
new file mode 100644
index 0000000..f5d69d6
--- /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 strcpy.S
diff --git a/lib/libc/amd64/string/bcmp.S b/lib/libc/amd64/string/bcmp.S
new file mode 100644
index 0000000..36a0c7e
--- /dev/null
+++ b/lib/libc/amd64/string/bcmp.S
@@ -0,0 +1,24 @@
+#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
diff --git a/lib/libc/amd64/string/bcopy.S b/lib/libc/amd64/string/bcopy.S
new file mode 100644
index 0000000..d58f591
--- /dev/null
+++ b/lib/libc/amd64/string/bcopy.S
@@ -0,0 +1,88 @@
+/*-
+ * 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
diff --git a/lib/libc/amd64/string/bzero.S b/lib/libc/amd64/string/bzero.S
new file mode 100644
index 0000000..d9d2a45
--- /dev/null
+++ b/lib/libc/amd64/string/bzero.S
@@ -0,0 +1,43 @@
+/*
+ * 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
diff --git a/lib/libc/amd64/string/memcmp.S b/lib/libc/amd64/string/memcmp.S
new file mode 100644
index 0000000..28194f8
--- /dev/null
+++ b/lib/libc/amd64/string/memcmp.S
@@ -0,0 +1,41 @@
+/*
+ * 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
diff --git a/lib/libc/amd64/string/memcpy.S b/lib/libc/amd64/string/memcpy.S
new file mode 100644
index 0000000..bd1e842
--- /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 0000000..85beb26
--- /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 0000000..142387a
--- /dev/null
+++ b/lib/libc/amd64/string/memset.S
@@ -0,0 +1,60 @@
+/*
+ * 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
diff --git a/lib/libc/amd64/string/strcat.S b/lib/libc/amd64/string/strcat.S
new file mode 100644
index 0000000..78a1b56
--- /dev/null
+++ b/lib/libc/amd64/string/strcat.S
@@ -0,0 +1,165 @@
+/*
+ * 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
diff --git a/lib/libc/amd64/string/strcmp.S b/lib/libc/amd64/string/strcmp.S
new file mode 100644
index 0000000..a7d2523
--- /dev/null
+++ b/lib/libc/amd64/string/strcmp.S
@@ -0,0 +1,73 @@
+/*
+ * 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 boundry. 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
diff --git a/lib/libc/amd64/string/strcpy.S b/lib/libc/amd64/string/strcpy.S
new file mode 100644
index 0000000..04676fa
--- /dev/null
+++ b/lib/libc/amd64/string/strcpy.S
@@ -0,0 +1,111 @@
+/*
+ * Written by J.T. Conklin <jtc@acorntoolworks.com>
+ * Public domain.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#if 0
+ RCSID("$NetBSD: strcpy.S,v 1.3 2004/07/19 20:04:41 drochner Exp $")
+#endif
+
+/*
+ * This strcpy 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.
+ */
+
+ENTRY(strcpy)
+ movq %rdi,%rax
+ 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
+ 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)
+ 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 .Lword_aligned
+
+.Ldone:
+ ret
diff --git a/lib/libc/amd64/sys/Makefile.inc b/lib/libc/amd64/sys/Makefile.inc
new file mode 100644
index 0000000..4f8bef7
--- /dev/null
+++ b/lib/libc/amd64/sys/Makefile.inc
@@ -0,0 +1,14 @@
+# 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 pipe.S ptrace.S \
+ reboot.S sbrk.S setlogin.S sigreturn.S
+
+# Don't generate default code for these syscalls:
+NOASM= break.o exit.o ftruncate.o getdomainname.o getlogin.o \
+ lseek.o mmap.o openbsd_poll.o pread.o \
+ pwrite.o setdomainname.o sstk.o truncate.o uname.o vfork.o yield.o
+
+PSEUDO= _getlogin.o _exit.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 0000000..ff5eb8f
--- /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 0000000..ddbf977
--- /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 0000000..e091485
--- /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 0000000..f896328
--- /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 0000000..ee04cac
--- /dev/null
+++ b/lib/libc/amd64/sys/brk.S
@@ -0,0 +1,87 @@
+/*-
+ * 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. 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.
+ */
+
+#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
+
+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
+#ifdef PIC
+ movq PIC_GOT(HIDENAME(cerror)),%rdx
+ jmp *%rdx
+#else
+ jmp HIDENAME(cerror)
+#endif
diff --git a/lib/libc/amd64/sys/cerror.S b/lib/libc/amd64/sys/cerror.S
new file mode 100644
index 0000000..fa28eca
--- /dev/null
+++ b/lib/libc/amd64/sys/cerror.S
@@ -0,0 +1,62 @@
+/*-
+ * 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. 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.
+ */
+
+#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)
+
+ /*
+ * 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
+
diff --git a/lib/libc/amd64/sys/exect.S b/lib/libc/amd64/sys/exect.S
new file mode 100644
index 0000000..d71a94b
--- /dev/null
+++ b/lib/libc/amd64/sys/exect.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.
+ * 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.
+ */
+
+#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
+#ifdef PIC
+ movq PIC_GOT(HIDENAME(cerror)),%rdx
+ jmp *%rdx
+#else
+ jmp HIDENAME(cerror)
+#endif
diff --git a/lib/libc/amd64/sys/getcontext.S b/lib/libc/amd64/sys/getcontext.S
new file mode 100644
index 0000000..9fa95fa
--- /dev/null
+++ b/lib/libc/amd64/sys/getcontext.S
@@ -0,0 +1,54 @@
+/*-
+ * 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 _getcontext
+ .set _getcontext,__sys_getcontext
+ .weak getcontext
+ .set getcontext,__sys_getcontext
+ENTRY(__sys_getcontext)
+ movq (%rsp),%rsi /* save getcontext return address */
+ mov $SYS_getcontext,%rax
+ KERNCALL
+ jb 1f
+ addq $8,%rsp /* remove stale (setcontext) return address */
+ jmp *%rsi /* restore return address */
+1:
+#ifdef PIC
+ movq PIC_GOT(HIDENAME(cerror)),%rdx
+ jmp *%rdx
+#else
+ jmp HIDENAME(cerror)
+#endif
diff --git a/lib/libc/amd64/sys/pipe.S b/lib/libc/amd64/sys/pipe.S
new file mode 100644
index 0000000..4baf20c
--- /dev/null
+++ b/lib/libc/amd64/sys/pipe.S
@@ -0,0 +1,63 @@
+/*-
+ * 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. 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.
+ */
+
+#if defined(SYSLIBC_SCCS) && !defined(lint)
+ .asciz "@(#)pipe.s 5.1 (Berkeley) 4/23/90"
+#endif /* SYSLIBC_SCCS and not lint */
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+ .weak _pipe
+ .set _pipe,__sys_pipe
+ .weak pipe
+ .set pipe,__sys_pipe
+ENTRY(__sys_pipe)
+ mov $SYS_pipe,%rax
+ KERNCALL
+ jb 1f
+ movl %eax,(%rdi) /* %rdi is preserved by syscall */
+ movl %edx,4(%rdi)
+ movq $0,%rax
+ ret
+1:
+#ifdef PIC
+ movq PIC_GOT(HIDENAME(cerror)),%rdx
+ jmp *%rdx
+#else
+ jmp HIDENAME(cerror)
+#endif
diff --git a/lib/libc/amd64/sys/ptrace.S b/lib/libc/amd64/sys/ptrace.S
new file mode 100644
index 0000000..f0b86f4
--- /dev/null
+++ b/lib/libc/amd64/sys/ptrace.S
@@ -0,0 +1,63 @@
+/*-
+ * 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. 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.
+ */
+
+#if defined(SYSLIBC_SCCS) && !defined(lint)
+ .asciz "@(#)ptrace.s 5.1 (Berkeley) 4/23/90"
+#endif /* SYSLIBC_SCCS and not lint */
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+ENTRY(ptrace)
+ xorl %eax,%eax
+#ifdef PIC
+ movq PIC_GOT(CNAME(errno)),%r8
+ movl %eax,(%r8)
+#else
+ movl %eax,CNAME(errno)(%rip)
+#endif
+ mov $SYS_ptrace,%eax
+ KERNCALL
+ jb err
+ ret
+err:
+#ifdef PIC
+ movq PIC_GOT(HIDENAME(cerror)),%rdx
+ jmp *%rdx
+#else
+ jmp HIDENAME(cerror)
+#endif
diff --git a/lib/libc/amd64/sys/reboot.S b/lib/libc/amd64/sys/reboot.S
new file mode 100644
index 0000000..0ed4329
--- /dev/null
+++ b/lib/libc/amd64/sys/reboot.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.
+ * 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.
+ */
+
+#if defined(SYSLIBC_SCCS) && !defined(lint)
+ .asciz "@(#)reboot.s 5.1 (Berkeley) 4/23/90"
+#endif /* SYSLIBC_SCCS and not lint */
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+ .weak _reboot
+ .set _reboot,__sys_reboot
+ .weak reboot
+ .set reboot,__sys_reboot
+ENTRY(__sys_reboot)
+ mov $SYS_reboot,%rax
+ KERNCALL
+ jb 1f
+ iretq
+1:
+#ifdef PIC
+ movq PIC_GOT(HIDENAME(cerror)),%rdx
+ jmp *%rdx
+#else
+ jmp HIDENAME(cerror)
+#endif
diff --git a/lib/libc/amd64/sys/sbrk.S b/lib/libc/amd64/sys/sbrk.S
new file mode 100644
index 0000000..dde1bcd
--- /dev/null
+++ b/lib/libc/amd64/sys/sbrk.S
@@ -0,0 +1,91 @@
+/*-
+ * 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. 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.
+ */
+
+#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
+#ifdef PIC
+ movq PIC_GOT(HIDENAME(cerror)),%rdx
+ jmp *%rdx
+#else
+ jmp HIDENAME(cerror)
+#endif
diff --git a/lib/libc/amd64/sys/setlogin.S b/lib/libc/amd64/sys/setlogin.S
new file mode 100644
index 0000000..439e417
--- /dev/null
+++ b/lib/libc/amd64/sys/setlogin.S
@@ -0,0 +1,68 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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 _setlogin
+ .set _setlogin,__sys_setlogin
+ .weak setlogin
+ .set setlogin,__sys_setlogin
+ENTRY(__sys_setlogin)
+ mov $SYS_setlogin,%rax
+ KERNCALL
+ jb 1f
+#ifdef PIC
+ movq PIC_GOT(CNAME(_logname_valid)),%rdx
+ movl $0,(%rdx)
+#else
+ movl $0,CNAME(_logname_valid)(%rip)
+#endif
+ ret /* setlogin(name) */
+1:
+#ifdef PIC
+ movq PIC_GOT(HIDENAME(cerror)),%rdx
+ jmp *%rdx
+#else
+ jmp HIDENAME(cerror)
+#endif
diff --git a/lib/libc/amd64/sys/sigreturn.S b/lib/libc/amd64/sys/sigreturn.S
new file mode 100644
index 0000000..2556ab9
--- /dev/null
+++ b/lib/libc/amd64/sys/sigreturn.S
@@ -0,0 +1,50 @@
+/*-
+ * 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. 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.
+ */
+
+#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)
diff --git a/lib/libc/amd64/sys/vfork.S b/lib/libc/amd64/sys/vfork.S
new file mode 100644
index 0000000..e49bca9
--- /dev/null
+++ b/lib/libc/amd64/sys/vfork.S
@@ -0,0 +1,62 @@
+/*-
+ * 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. 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.
+ */
+
+#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 _vfork
+ .set _vfork,__sys_vfork
+ .weak vfork
+ .set vfork,__sys_vfork
+ENTRY(__sys_vfork)
+ popq %rsi /* fetch return address (%rsi preserved) */
+ mov $SYS_vfork,%rax
+ KERNCALL
+ jb 1f
+ jmp *%rsi
+1:
+ pushq %rsi
+#ifdef PIC
+ movq PIC_GOT(HIDENAME(cerror)),%rdx
+ jmp *%rdx
+#else
+ jmp HIDENAME(cerror)
+#endif
diff --git a/lib/libc/arm/Makefile.inc b/lib/libc/arm/Makefile.inc
new file mode 100644
index 0000000..666cadc
--- /dev/null
+++ b/lib/libc/arm/Makefile.inc
@@ -0,0 +1,12 @@
+# $FreeBSD$
+#
+# Machine dependent definitions for the arm architecture.
+#
+
+SOFTFLOAT_BITS=32
+
+CFLAGS+=-DSOFTFLOAT
+
+# Long double is just double precision.
+MDSRCS+=machdep_ldisd.c
+SYM_MAPS+=${.CURDIR}/arm/Symbol.map
diff --git a/lib/libc/arm/SYS.h b/lib/libc/arm/SYS.h
new file mode 100644
index 0000000..b9bc742
--- /dev/null
+++ b/lib/libc/arm/SYS.h
@@ -0,0 +1,90 @@
+/* $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>
+
+#ifdef __STDC__
+#define SYSTRAP(x) swi 0 | SYS_ ## x
+#else
+#define SYSTRAP(x) swi 0 | SYS_/**/x
+#endif
+
+#ifdef __ELF__
+#define CERROR _C_LABEL(cerror)
+#define CURBRK _C_LABEL(curbrk)
+#else
+#define CERROR _ASM_LABEL(cerror)
+#define CURBRK _ASM_LABEL(curbrk)
+#endif
+
+#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); \
+ bcs PIC_SYM(CERROR, PLT)
+
+#define SYSCALL_NOERROR(x) \
+ _SYSCALL_NOERROR(x)
+
+#define SYSCALL(x) \
+ _SYSCALL(x)
+
+
+#define PSEUDO_NOERROR(x) \
+ _SYSCALL_NOERROR(x); \
+ RET
+
+#define PSEUDO(x) \
+ _SYSCALL(x); \
+ RET
+
+
+#define RSYSCALL_NOERROR(x) \
+ PSEUDO_NOERROR(x)
+
+#define RSYSCALL(x) \
+ PSEUDO(x)
+
+ .globl CERROR
diff --git a/lib/libc/arm/Symbol.map b/lib/libc/arm/Symbol.map
new file mode 100644
index 0000000..44709af
--- /dev/null
+++ b/lib/libc/arm/Symbol.map
@@ -0,0 +1,66 @@
+# $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;
+ modf;
+ setjmp;
+ longjmp;
+ sigsetjmp;
+ siglongjmp
+ htonl;
+ __htonl;
+ htons;
+ __htons;
+ ntohl;
+ __ntohl;
+ ntohs;
+ __ntohs;
+ vfork;
+ brk;
+ cerror; # XXX - Should this be .cerror (see sys/cerror.S)?
+ fork;
+ sbrk;
+};
+
+FBSDprivate {
+ # PSEUDO syscalls
+ __sys_getlogin;
+ _getlogin;
+ __sys_exit;
+
+ _set_tp;
+ ___longjmp;
+ __umodsi3;
+ __modsi3;
+ __udivsi3;
+ __divsi3;
+ __makecontext;
+ __longjmp;
+ signalcontext;
+ _signalcontext;
+ __siglongjmp;
+ __sys_vfork;
+ _vfork;
+ _brk;
+ end; # XXX - Should this be _end (see sys/brk.S)?
+ curbrk;
+ minbrk;
+ _brk;
+ __sys_fork;
+ _fork;
+ _sbrk;
+};
diff --git a/lib/libc/arm/_fpmath.h b/lib/libc/arm/_fpmath.h
new file mode 100644
index 0000000..98d7832
--- /dev/null
+++ b/lib/libc/arm/_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 {
+#ifndef __ARMEB__
+ 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_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/arm/arith.h b/lib/libc/arm/arith.h
new file mode 100644
index 0000000..86121bf
--- /dev/null
+++ b/lib/libc/arm/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_8087
+#define Arith_Kind_ASL 1
+#define Sudden_Underflow
diff --git a/lib/libc/arm/gen/Makefile.inc b/lib/libc/arm/gen/Makefile.inc
new file mode 100644
index 0000000..bbe2257
--- /dev/null
+++ b/lib/libc/arm/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 alloca.S fabs.c \
+ infinity.c ldexp.c makecontext.c modf.c \
+ setjmp.S signalcontext.c sigsetjmp.S divsi3.S
diff --git a/lib/libc/arm/gen/_ctx_start.S b/lib/libc/arm/gen/_ctx_start.S
new file mode 100644
index 0000000..fbde357
--- /dev/null
+++ b/lib/libc/arm/gen/_ctx_start.S
@@ -0,0 +1,9 @@
+#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)
diff --git a/lib/libc/arm/gen/_set_tp.c b/lib/libc/arm/gen/_set_tp.c
new file mode 100644
index 0000000..4c26dff
--- /dev/null
+++ b/lib/libc/arm/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 <string.h>
+#include <stdint.h>
+
+void
+_set_tp(void *tp)
+{
+}
diff --git a/lib/libc/arm/gen/_setjmp.S b/lib/libc/arm/gen/_setjmp.S
new file mode 100644
index 0000000..b938405
--- /dev/null
+++ b/lib/libc/arm/gen/_setjmp.S
@@ -0,0 +1,106 @@
+/* $NetBSD: _setjmp.S,v 1.5 2003/04/05 23:08:51 bjh21 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$");
+
+/*
+ * 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 are scratch registers in functions
+ */
+
+ENTRY(_setjmp)
+ ldr r1, .L_setjmp_magic
+ str r1, [r0], #4
+#ifdef SOFTFLOAT
+ add r0, r0, #52
+#else
+ /* Store fp registers */
+ sfm f4, 4, [r0], #48
+ /* Store fpsr */
+ rfs r1
+ str r1, [r0], #0x0004
+#endif /* SOFTFLOAT */
+ /* Store integer registers */
+ stmia r0, {r4-r14}
+
+ mov r0, #0x00000000
+ RET
+
+.L_setjmp_magic:
+ .word _JB_MAGIC__SETJMP
+
+WEAK_ALIAS(___longjmp, _longjmp)
+ENTRY(_longjmp)
+ ldr r2, .L_setjmp_magic
+ ldr r3, [r0], #4
+ teq r2, r3
+ bne botch
+
+#ifdef SOFTFLOAT
+ add r0, r0, #52
+#else
+ /* Restore fp registers */
+ lfm f4, 4, [r0], #48
+ /* Restore fpsr */
+ ldr r4, [r0], #0x0004
+ wfs r4
+#endif /* SOFTFLOAT */
+ /* Restore integer registers */
+ ldmia r0, {r4-r14}
+
+ /* Validate sp and r14 */
+ teq sp, #0
+ teqne r14, #0
+ beq botch
+
+ /* Set return value */
+ mov r0, r1
+ teq r0, #0x00000000
+ moveq r0, #0x00000001
+ RET
+
+ /* validation failed, die die die. */
+botch:
+ bl PIC_SYM(_C_LABEL(longjmperror), PLT)
+ bl PIC_SYM(_C_LABEL(abort), PLT)
+ b . - 8 /* Cannot get here */
diff --git a/lib/libc/arm/gen/alloca.S b/lib/libc/arm/gen/alloca.S
new file mode 100644
index 0000000..9569d86
--- /dev/null
+++ b/lib/libc/arm/gen/alloca.S
@@ -0,0 +1,45 @@
+/* $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
diff --git a/lib/libc/arm/gen/divsi3.S b/lib/libc/arm/gen/divsi3.S
new file mode 100644
index 0000000..104a958
--- /dev/null
+++ b/lib/libc/arm/gen/divsi3.S
@@ -0,0 +1,387 @@
+/* $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}
+
+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
+
+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
+
+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
diff --git a/lib/libc/arm/gen/fabs.c b/lib/libc/arm/gen/fabs.c
new file mode 100644
index 0000000..8bb1502
--- /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/infinity.c b/lib/libc/arm/gen/infinity.c
new file mode 100644
index 0000000..60faf42
--- /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 0000000..4fd3953
--- /dev/null
+++ b/lib/libc/arm/gen/makecontext.c
@@ -0,0 +1,96 @@
+/* $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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 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.
+ */
+
+#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/modf.c b/lib/libc/arm/gen/modf.c
new file mode 100644
index 0000000..347090c
--- /dev/null
+++ b/lib/libc/arm/gen/modf.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 1994, 1995 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ *
+ * $NetBSD: modf.c,v 1.1 1995/02/10 17:50:25 cgd Exp $
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <errno.h>
+#include <math.h>
+#include <machine/ieee.h>
+
+/*
+ * double modf(double val, double *iptr)
+ * returns: f and i such that |f| < 1.0, (f + i) = val, and
+ * sign(f) == sign(i) == sign(val).
+ *
+ * Beware signedness when doing subtraction, and also operand size!
+ */
+double
+modf(val, iptr)
+ double val, *iptr;
+{
+ union doub {
+ double v;
+ struct ieee_double s;
+ } u, v;
+ u_int64_t frac;
+
+ /*
+ * If input is Inf or NaN, return it and leave i alone.
+ */
+ u.v = val;
+ if (u.s.dbl_exp == DBL_EXP_INFNAN)
+ return (u.v);
+
+ /*
+ * If input can't have a fractional part, return
+ * (appropriately signed) zero, and make i be the input.
+ */
+ if ((int)u.s.dbl_exp - DBL_EXP_BIAS > DBL_FRACBITS - 1) {
+ *iptr = u.v;
+ v.v = 0.0;
+ v.s.dbl_sign = u.s.dbl_sign;
+ return (v.v);
+ }
+
+ /*
+ * If |input| < 1.0, return it, and set i to the appropriately
+ * signed zero.
+ */
+ if (u.s.dbl_exp < DBL_EXP_BIAS) {
+ v.v = 0.0;
+ v.s.dbl_sign = u.s.dbl_sign;
+ *iptr = v.v;
+ return (u.v);
+ }
+
+ /*
+ * There can be a fractional part of the input.
+ * If you look at the math involved for a few seconds, it's
+ * plain to see that the integral part is the input, with the
+ * low (DBL_FRACBITS - (exponent - DBL_EXP_BIAS)) bits zeroed,
+ * the the fractional part is the part with the rest of the
+ * bits zeroed. Just zeroing the high bits to get the
+ * fractional part would yield a fraction in need of
+ * normalization. Therefore, we take the easy way out, and
+ * just use subtraction to get the fractional part.
+ */
+ v.v = u.v;
+ /* Zero the low bits of the fraction, the sleazy way. */
+ frac = ((u_int64_t)v.s.dbl_frach << 32) + v.s.dbl_fracl;
+ frac >>= DBL_FRACBITS - (u.s.dbl_exp - DBL_EXP_BIAS);
+ frac <<= DBL_FRACBITS - (u.s.dbl_exp - DBL_EXP_BIAS);
+ v.s.dbl_fracl = frac & 0xffffffff;
+ v.s.dbl_frach = frac >> 32;
+ *iptr = v.v;
+
+ u.v -= v.v;
+ u.s.dbl_sign = v.s.dbl_sign;
+ return (u.v);
+}
diff --git a/lib/libc/arm/gen/setjmp.S b/lib/libc/arm/gen/setjmp.S
new file mode 100644
index 0000000..f0e9cfa
--- /dev/null
+++ b/lib/libc/arm/gen/setjmp.S
@@ -0,0 +1,129 @@
+/* $NetBSD: setjmp.S,v 1.5 2003/04/05 23:08:51 bjh21 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$");
+/*
+ * 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, #(25 * 4) /* oset */
+ mov r0, #0x00000001 /* SIG_BLOCK */
+ mov r1, #0 /* set */
+
+ bl PIC_SYM(_C_LABEL(sigprocmask), PLT)
+
+ ldmfd sp!, {r0, r14}
+
+ ldr r1, .Lsetjmp_magic
+ str r1, [r0], #4
+
+#ifdef SOFTFLOAT
+ add r0, r0, #52
+#else
+ /* Store fp registers */
+ sfm f4, 4, [r0], #48
+ /* Store fpsr */
+ rfs r1
+ str r1, [r0], #0x0004
+#endif /*SOFTFLOAT*/
+ /* Store integer registers */
+ stmia r0, {r4-r14}
+ mov r0, #0x00000000
+ RET
+
+.Lsetjmp_magic:
+ .word _JB_MAGIC_SETJMP
+
+
+.weak _C_LABEL(longjmp)
+.set _C_LABEL(longjmp), _C_LABEL(__longjmp)
+ENTRY(__longjmp)
+ ldr r2, .Lsetjmp_magic
+ ldr r3, [r0]
+ teq r2, r3
+ bne botch
+
+
+ /* Set signal mask */
+ stmfd sp!, {r0, r1, r14}
+ sub sp, sp, #4 /* align the stack */
+
+ add r1, r0, #(25 * 4) /* Signal mask */
+ mov r0, #3 /* SIG_SETMASK */
+ mov r2, #0
+ bl PIC_SYM(_C_LABEL(sigprocmask), PLT)
+
+ add sp, sp, #4 /* unalign the stack */
+ ldmfd sp!, {r0, r1, r14}
+
+ add r0, r0, #4
+#ifdef SOFTFLOAT
+ add r0, r0, #52
+#else
+ /* Restore fp registers */
+ lfm f4, 4, [r0], #48
+ /* Restore FPSR */
+ ldr r4, [r0], #0x0004
+ wfs r4
+#endif /* SOFTFLOAT */
+ /* Restore integer registers */
+ ldmia r0, {r4-r14}
+
+ /* Validate sp and r14 */
+ teq sp, #0
+ teqne r14, #0
+ beq botch
+
+ /* Set return value */
+
+ mov r0, r1
+ teq r0, #0x00000000
+ moveq r0, #0x00000001
+ RET
+
+ /* validation failed, die die die. */
+botch:
+ bl PIC_SYM(_C_LABEL(longjmperror), PLT)
+ bl PIC_SYM(_C_LABEL(abort), PLT)
+ b . - 8 /* Cannot get here */
diff --git a/lib/libc/arm/gen/signalcontext.c b/lib/libc/arm/gen/signalcontext.c
new file mode 100644
index 0000000..bb9a54d
--- /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 0000000..09ec256
--- /dev/null
+++ b/lib/libc/arm/gen/sigsetjmp.S
@@ -0,0 +1,62 @@
+/* $NetBSD: sigsetjmp.S,v 1.3 2002/08/17 19:54:30 thorpej 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$");
+
+/*
+ * 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)
+
+.L_setjmp_magic:
+ .word _JB_MAGIC__SETJMP
+WEAK_ALIAS(__siglongjmp, siglongjmp)
+
+ENTRY(siglongjmp)
+ ldr r2, .L_setjmp_magic
+ ldr r3, [r0]
+ teq r2, r3
+ beq PIC_SYM(_C_LABEL(_longjmp), PLT)
+ b PIC_SYM(_C_LABEL(longjmp), PLT)
diff --git a/lib/libc/arm/net/Makefile.inc b/lib/libc/arm/net/Makefile.inc
new file mode 100644
index 0000000..69c34cb
--- /dev/null
+++ b/lib/libc/arm/net/Makefile.inc
@@ -0,0 +1,4 @@
+# @(#)Makefile.inc 8.1 (Berkeley) 6/4/93
+# $FreeBSD$
+
+SRCS+= ntohl.S ntohs.S htonl.S htons.S
diff --git a/lib/libc/arm/net/htonl.S b/lib/libc/arm/net/htonl.S
new file mode 100644
index 0000000..152511e
--- /dev/null
+++ b/lib/libc/arm/net/htonl.S
@@ -0,0 +1,48 @@
+/* $NetBSD: byte_swap_4.S,v 1.2 2003/04/05 23:08:51 bjh21 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 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.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+_ENTRY(_C_LABEL(htonl))
+_PROF_PROLOGUE
+ eor r1, r0, r0, ror #16
+ bic r1, r1, #0x00FF0000
+ mov r0, r0, ror #8
+ eor r0, r0, r1, lsr #8
+ mov pc, lr
diff --git a/lib/libc/arm/net/htons.S b/lib/libc/arm/net/htons.S
new file mode 100644
index 0000000..c031c1d
--- /dev/null
+++ b/lib/libc/arm/net/htons.S
@@ -0,0 +1,47 @@
+/* $NetBSD: byte_swap_2.S,v 1.3 2003/04/05 23:08:51 bjh21 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 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.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+_ENTRY(_C_LABEL(htons))
+_PROF_PROLOGUE
+ and r1, r0, #0xff
+ mov r0, r0, lsr #8
+ orr r0, r0, r1, lsl #8
+ mov pc, lr
diff --git a/lib/libc/arm/net/ntohl.S b/lib/libc/arm/net/ntohl.S
new file mode 100644
index 0000000..5b5e0a9
--- /dev/null
+++ b/lib/libc/arm/net/ntohl.S
@@ -0,0 +1,48 @@
+/* $NetBSD: byte_swap_4.S,v 1.2 2003/04/05 23:08:51 bjh21 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 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.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+_ENTRY(_C_LABEL(ntohl))
+_PROF_PROLOGUE
+ eor r1, r0, r0, ror #16
+ bic r1, r1, #0x00FF0000
+ mov r0, r0, ror #8
+ eor r0, r0, r1, lsr #8
+ mov pc, lr
diff --git a/lib/libc/arm/net/ntohs.S b/lib/libc/arm/net/ntohs.S
new file mode 100644
index 0000000..8c44db6
--- /dev/null
+++ b/lib/libc/arm/net/ntohs.S
@@ -0,0 +1,47 @@
+/* $NetBSD: byte_swap_2.S,v 1.3 2003/04/05 23:08:51 bjh21 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 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.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+_ENTRY(_C_LABEL(ntohs))
+_PROF_PROLOGUE
+ and r1, r0, #0xff
+ mov r0, r0, lsr #8
+ orr r0, r0, r1, lsl #8
+ mov pc, lr
diff --git a/lib/libc/arm/softfloat/arm-gcc.h b/lib/libc/arm/softfloat/arm-gcc.h
new file mode 100644
index 0000000..1204108
--- /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(__VFP_FP__) || defined(__ARMEB__)
+#define FLOAT64_DEMANGLE(a) (a)
+#define FLOAT64_MANGLE(a) (a)
+#else
+#define FLOAT64_DEMANGLE(a) (((a) << 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 0000000..54775c7
--- /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 0000000..3019d90
--- /dev/null
+++ b/lib/libc/arm/softfloat/softfloat.h
@@ -0,0 +1,313 @@
+/* $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.
+-------------------------------------------------------------------------------
+*/
+extern int float_detect_tininess;
+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.
+-------------------------------------------------------------------------------
+*/
+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
+#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/stdlib/Makefile.inc b/lib/libc/arm/stdlib/Makefile.inc
new file mode 100644
index 0000000..1814a0a
--- /dev/null
+++ b/lib/libc/arm/stdlib/Makefile.inc
@@ -0,0 +1,4 @@
+# @(#)Makefile.inc 8.1 (Berkeley) 6/4/93
+# $FreeBSD$
+
+MDSRCS+=abs.c div.c labs.c ldiv.c
diff --git a/lib/libc/arm/string/Makefile.inc b/lib/libc/arm/string/Makefile.inc
new file mode 100644
index 0000000..6658ce7
--- /dev/null
+++ b/lib/libc/arm/string/Makefile.inc
@@ -0,0 +1,7 @@
+# @(#)Makefile.inc 8.1 (Berkeley) 6/4/93
+# $FreeBSD$
+
+MDSRCS+=bcmp.c bcopy.S bzero.S ffs.S index.c memchr.c memcmp.S memcpy.S \
+ memmove.S memset.S rindex.c 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 0000000..f2583fc
--- /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 0000000..008c485
--- /dev/null
+++ b/lib/libc/arm/string/bzero.S
@@ -0,0 +1,44 @@
+/* $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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 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.
+ */
+
+#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 0000000..223d55d
--- /dev/null
+++ b/lib/libc/arm/string/ffs.S
@@ -0,0 +1,82 @@
+/* $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$");
+
+/*
+ * 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 __XSCALE__
+ /*
+ * 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 */
+ ldrneb 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
+ clzne r0, r0
+ rsbne r0, r0, #32
+ RET
+#endif
diff --git a/lib/libc/arm/string/memcmp.S b/lib/libc/arm/string/memcmp.S
new file mode 100644
index 0000000..a81c960
--- /dev/null
+++ b/lib/libc/arm/string/memcmp.S
@@ -0,0 +1,180 @@
+/* $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$");
+
+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
+ eornes 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
diff --git a/lib/libc/arm/string/memcpy.S b/lib/libc/arm/string/memcpy.S
new file mode 100644
index 0000000..1d17b93
--- /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(__XSCALE__) || 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 0000000..005c8c2
--- /dev/null
+++ b/lib/libc/arm/string/memcpy_arm.S
@@ -0,0 +1,339 @@
+/* $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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 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.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+/*
+ * 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
+ ldmgeia r1!, {r3, r4, r12, lr} /* blat a remaining 16 bytes */
+ stmgeia 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:
+ ldmgeia r1!, {r3, r12, lr}
+ stmgeia r0!, {r3, r12, lr}
+ subges 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
+ ldmgeia r1!, {r3, r12}
+ stmgeia r0!, {r3, r12}
+ subge r2, r2, #4
+
+.Lmemcpy_l4:
+ /* less than 4 bytes to go */
+ adds r2, r2, #4
+#ifdef __APCS_26_
+ ldmeqia sp!, {r0, pc}^ /* done */
+#else
+ ldmeqia sp!, {r0, pc} /* done */
+#endif
+ /* copy the crud byte at a time */
+ cmp r2, #2
+ ldrb r3, [r1], #1
+ strb r3, [r0], #1
+ ldrgeb r3, [r1], #1
+ strgeb r3, [r0], #1
+ ldrgtb r3, [r1], #1
+ strgtb 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
+ ldrgeb r3, [r1], #1
+ strgeb r3, [r0], #1
+ ldrgtb r3, [r1], #1
+ strgtb 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
diff --git a/lib/libc/arm/string/memcpy_xscale.S b/lib/libc/arm/string/memcpy_xscale.S
new file mode 100644
index 0000000..02cca5e
--- /dev/null
+++ b/lib/libc/arm/string/memcpy_xscale.S
@@ -0,0 +1,1783 @@
+/* $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$");
+
+/* 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
+ ldrleb ip, [r1], #0x01
+ suble r2, r2, #0x01
+ strleb ip, [r3], #0x01
+ ldrltb ip, [r1], #0x01
+ sublt r2, r2, #0x01
+ strltb 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 */
+ ldmeqfd 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 */
+ ldmeqfd 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
+ ldrgeb r2, [r1], #0x01
+ strb ip, [r3], #0x01
+ ldrgtb ip, [r1]
+ strgeb r2, [r3], #0x01
+ strgtb 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
+ ldmeqfd 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
+ ldmeqfd 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
+ ldmeqfd 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
+ ldrgeb r2, [r1], #0x01
+ strb ip, [r3], #0x01
+ ldrgtb ip, [r1]
+ strgeb r2, [r3], #0x01
+ strgtb 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
+ ldrneb 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 */
diff --git a/lib/libc/arm/string/memmove.S b/lib/libc/arm/string/memmove.S
new file mode 100644
index 0000000..f65a254
--- /dev/null
+++ b/lib/libc/arm/string/memmove.S
@@ -0,0 +1,589 @@
+/* $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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 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.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#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
+ RETeq /* Bail now if src/dst are the same */
+ 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
+ bcc .Lmemmove_backwards
+
+ 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
+ ldmgeia r1!, {r3, r4, r12, lr} /* blat a remaining 16 bytes */
+ stmgeia 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:
+ ldmgeia r1!, {r3, r12, lr}
+ stmgeia r0!, {r3, r12, lr}
+ subges r2, r2, #0x0c
+ bge .Lmemmove_floop12
+
+.Lmemmove_fl12:
+ adds r2, r2, #8
+ blt .Lmemmove_fl4
+
+ subs r2, r2, #4
+ ldrlt r3, [r1], #4
+ strlt r3, [r0], #4
+ ldmgeia r1!, {r3, r12}
+ stmgeia r0!, {r3, r12}
+ subge r2, r2, #4
+
+.Lmemmove_fl4:
+ /* less than 4 bytes to go */
+ adds r2, r2, #4
+ ldmeqia sp!, {r0, pc} /* done */
+
+ /* copy the crud byte at a time */
+ cmp r2, #2
+ ldrb r3, [r1], #1
+ strb r3, [r0], #1
+ ldrgeb r3, [r1], #1
+ strgeb r3, [r0], #1
+ ldrgtb r3, [r1], #1
+ strgtb 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
+ ldrgeb r3, [r1], #1
+ strgeb r3, [r0], #1
+ ldrgtb r3, [r1], #1
+ strgtb 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
+ ldmgedb r1!, {r3, r4, r12, lr} /* blat a remaining 16 bytes */
+ stmgedb r0!, {r3, r4, r12, lr}
+ subge r2, r2, #0x10
+ adds r2, r2, #0x14
+ ldmgedb r1!, {r3, r12, lr} /* blat a remaining 12 bytes */
+ stmgedb 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
+ ldrlt r3, [r1, #-4]!
+ strlt r3, [r0, #-4]!
+ ldmgedb r1!, {r3, r12}
+ stmgedb r0!, {r3, r12}
+ subge r2, r2, #4
+
+.Lmemmove_bl4:
+ /* less than 4 bytes to go */
+ adds r2, r2, #4
+ RETeq /* done */
+
+ /* copy the crud byte at a time */
+ cmp r2, #2
+ ldrb r3, [r1, #-1]!
+ strb r3, [r0, #-1]!
+ ldrgeb r3, [r1, #-1]!
+ strgeb r3, [r0, #-1]!
+ ldrgtb r3, [r1, #-1]!
+ strgtb 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]!
+ ldrgeb r3, [r1, #-1]!
+ strgeb r3, [r0, #-1]!
+ ldrgtb r3, [r1, #-1]!
+ strgtb 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
diff --git a/lib/libc/arm/string/memset.S b/lib/libc/arm/string/memset.S
new file mode 100644
index 0000000..1e97846
--- /dev/null
+++ b/lib/libc/arm/string/memset.S
@@ -0,0 +1,236 @@
+/* $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$");
+
+/*
+ * 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 __XSCALE__
+ tst ip, #0x04 /* Quad-align for Xscale */
+#else
+ cmp r1, #0x10
+#endif
+#ifndef _BZERO
+ orr r3, r3, r3, lsl #16 /* Extend value to 32-bits */
+#endif
+#ifdef __XSCALE__
+ 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 __XSCALE__
+ strged r2, [ip], #0x08
+ strged r2, [ip], #0x08
+ strged r2, [ip], #0x08
+ strged r2, [ip], #0x08
+ strged r2, [ip], #0x08
+ strged r2, [ip], #0x08
+ strged r2, [ip], #0x08
+ strged r2, [ip], #0x08
+ strged r2, [ip], #0x08
+ strged r2, [ip], #0x08
+ strged r2, [ip], #0x08
+ strged r2, [ip], #0x08
+ strged r2, [ip], #0x08
+ strged r2, [ip], #0x08
+ strged r2, [ip], #0x08
+ strged r2, [ip], #0x08
+#else
+ stmgeia ip!, {r2-r3}
+ stmgeia ip!, {r2-r3}
+ stmgeia ip!, {r2-r3}
+ stmgeia ip!, {r2-r3}
+ stmgeia ip!, {r2-r3}
+ stmgeia ip!, {r2-r3}
+ stmgeia ip!, {r2-r3}
+ stmgeia ip!, {r2-r3}
+ stmgeia ip!, {r2-r3}
+ stmgeia ip!, {r2-r3}
+ stmgeia ip!, {r2-r3}
+ stmgeia ip!, {r2-r3}
+ stmgeia ip!, {r2-r3}
+ stmgeia ip!, {r2-r3}
+ stmgeia ip!, {r2-r3}
+ stmgeia ip!, {r2-r3}
+#endif
+ bgt .Lmemset_loop128
+ 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
+#ifdef __XSCALE__
+ strged r2, [ip], #0x08
+ strged r2, [ip], #0x08
+ strged r2, [ip], #0x08
+ strged r2, [ip], #0x08
+#else
+ stmgeia ip!, {r2-r3}
+ stmgeia ip!, {r2-r3}
+ stmgeia ip!, {r2-r3}
+ stmgeia ip!, {r2-r3}
+#endif
+ bgt .Lmemset_loop32
+ RETeq /* Zero length so just exit */
+
+ adds r1, r1, #0x10 /* Partially adjust for extra sub */
+
+ /* Deal with 16 bytes or more */
+#ifdef __XSCALE__
+ strged r2, [ip], #0x08
+ strged r2, [ip], #0x08
+#else
+ stmgeia ip!, {r2-r3}
+ stmgeia ip!, {r2-r3}
+#endif
+ RETeq /* Zero length so just exit */
+
+ 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
+ strge r3, [ip], #0x04
+ bgt .Lmemset_loop4
+ RETeq /* Zero length so just exit */
+
+#ifdef __XSCALE__
+ /* Compensate for 64-bit alignment check */
+ adds r1, r1, #0x04
+ RETeq
+ cmp r1, #2
+#else
+ cmp r1, #-2
+#endif
+
+ strb r3, [ip], #0x01 /* Set 1 byte */
+ strgeb r3, [ip], #0x01 /* Set another byte */
+ strgtb r3, [ip] /* and a third */
+ RET /* Exit */
+
+.Lmemset_wordunaligned:
+ rsb r2, r2, #0x004
+ strb r3, [ip], #0x01 /* Set 1 byte */
+ cmp r2, #0x02
+ strgeb r3, [ip], #0x01 /* Set another byte */
+ sub r1, r1, r2
+ strgtb r3, [ip], #0x01 /* and a third */
+ cmp r1, #0x04 /* More than 4 bytes left? */
+ bge .Lmemset_wordaligned /* Yup */
+
+.Lmemset_lessthanfour:
+ cmp r1, #0x00
+ RETeq /* Zero length so exit */
+ strb r3, [ip], #0x01 /* Set 1 byte */
+ cmp r1, #0x02
+ strgeb r3, [ip], #0x01 /* Set another byte */
+ strgtb r3, [ip] /* and a third */
+ RET /* Exit */
diff --git a/lib/libc/arm/string/strcmp.S b/lib/libc/arm/string/strcmp.S
new file mode 100644
index 0000000..e5cba7d
--- /dev/null
+++ b/lib/libc/arm/string/strcmp.S
@@ -0,0 +1,43 @@
+/* $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
+ cmpcs r2, r3
+ beq 1b
+ sub r0, r2, r3
+ RET
diff --git a/lib/libc/arm/string/strlen.S b/lib/libc/arm/string/strlen.S
new file mode 100644
index 0000000..378257d
--- /dev/null
+++ b/lib/libc/arm/string/strlen.S
@@ -0,0 +1,78 @@
+/*-
+ * 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$");
+
+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
+ addne r1, r1, #1
+.Ldo_3:
+#ifndef __ARMEB__
+ andnes r3, r2, #0x0000ff00
+#else
+ andnes r3, r2, #0x00ff0000
+#endif
+ addne r1, r1, #1
+.Ldo_2:
+#ifndef __ARMEB__
+ andnes r3, r2, #0x00ff0000
+#else
+ andnes r3, r2, #0x0000ff00
+#endif
+ addne r1, r1, #1
+.Ldo_1:
+#ifndef __ARMEB__
+ andnes r3, r2, #0xff000000
+#else
+ andnes r3, r2, #0x000000ff
+#endif
+ addne r1, r1, #1
+ bne .Loop
+.Lexit:
+ mov r0, r1
+ RET
diff --git a/lib/libc/arm/string/strncmp.S b/lib/libc/arm/string/strncmp.S
new file mode 100644
index 0000000..d172264
--- /dev/null
+++ b/lib/libc/arm/string/strncmp.S
@@ -0,0 +1,51 @@
+/* $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 - 1) < 0) return 0 */
+ subs r2, r2, #1
+ movmi r0, #0
+ movmi pc, lr
+
+/* ip == last src address to compare */
+ add ip, r0, r2
+1:
+ ldrb r2, [r0], #1
+ ldrb r3, [r1], #1
+ cmp ip, r0
+ cmpcs r2, #1
+ cmpcs r2, r3
+ beq 1b
+ sub r0, r2, r3
+ RET
diff --git a/lib/libc/arm/sys/Makefile.inc b/lib/libc/arm/sys/Makefile.inc
new file mode 100644
index 0000000..28aabb3
--- /dev/null
+++ b/lib/libc/arm/sys/Makefile.inc
@@ -0,0 +1,9 @@
+# $FreeBSD$
+
+MDASM= Ovfork.S brk.S cerror.S pipe.S ptrace.S sbrk.S shmat.S sigreturn.S syscall.S
+
+# Don't generate default code for these syscalls:
+NOASM= break.o exit.o ftruncate.o getdomainname.o getlogin.o \
+ lseek.o mmap.o openbsd_poll.o pread.o \
+ pwrite.o setdomainname.o sstk.o truncate.o uname.o vfork.o yield.o
+PSEUDO= _exit.o _getlogin.o
diff --git a/lib/libc/arm/sys/Ovfork.S b/lib/libc/arm/sys/Ovfork.S
new file mode 100644
index 0000000..0082bbc
--- /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"
+
+WARN_REFERENCES(vfork, \
+ "warning: reference to compatibility vfork(); include <unistd.h> for correct reference")
+
+/*
+ * 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
diff --git a/lib/libc/arm/sys/brk.S b/lib/libc/arm/sys/brk.S
new file mode 100644
index 0000000..9141cf0
--- /dev/null
+++ b/lib/libc/arm/sys/brk.S
@@ -0,0 +1,100 @@
+/* $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)
+#ifdef PIC
+ /* Setup the GOT */
+ ldr r3, .Lgot
+ add r3, pc, r3
+.L1:
+ ldr r1, .Lminbrk
+ ldr r1, [r3, r1]
+#else
+ ldr r1, .Lminbrk
+#endif
+ /* 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
+ 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
+#ifdef PIC
+.Lgot:
+ .word _GLOBAL_OFFSET_TABLE_ - (.L1+4)
+#endif
+.Lminbrk:
+ .word PIC_SYM(_C_LABEL(minbrk), GOT)
+.Lcurbrk:
+ .word PIC_SYM(CURBRK, GOT)
diff --git a/lib/libc/arm/sys/cerror.S b/lib/libc/arm/sys/cerror.S
new file mode 100644
index 0000000..e657248
--- /dev/null
+++ b/lib/libc/arm/sys/cerror.S
@@ -0,0 +1,76 @@
+/* $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)
+#if 1
+ 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}
+#else
+#ifdef PIC
+ /* Setup the GOT */
+ ldr r3, .Lgot
+ add r3, pc, r3
+.L1:
+ ldr r1, .Lerrno
+ ldr r1, [r3, r1]
+#else
+ ldr r1, .Lerrno
+#endif /* PIC */
+ str r0, [r1]
+ mvn r0, #0x00000000
+ mvn r1, #0x00000000
+ RET
+
+#if 0
+ .align 0
+.Lgot:
+ .word _C_LABEL(_GLOBAL_OFFSET_TABLE_) + (. - (.L1+4))
+#endif /* PIC */
+
+ .globl _C_LABEL(errno)
+
+.Lerrno:
+ .word PIC_SYM(_C_LABEL(errno), GOT)
+#endif /* _REENTRANT */
diff --git a/lib/libc/arm/sys/fork.S b/lib/libc/arm/sys/fork.S
new file mode 100644
index 0000000..a5ae1f0
--- /dev/null
+++ b/lib/libc/arm/sys/fork.S
@@ -0,0 +1,49 @@
+/* $NetBSD: fork.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: @(#)fork.s 5.1 (Berkeley) 4/23/90
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+#include "SYS.h"
+
+/*
+ * pid = fork();
+ *
+ * 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.
+ */
+
+_SYSCALL(fork)
+ sub r1, r1, #1 /* r1 == 0xffffffff if parent, 0 if child */
+ and r0, r0, r1 /* r0 == 0 if child, else unchanged */
+ RET
diff --git a/lib/libc/arm/sys/pipe.S b/lib/libc/arm/sys/pipe.S
new file mode 100644
index 0000000..83518fc2
--- /dev/null
+++ b/lib/libc/arm/sys/pipe.S
@@ -0,0 +1,50 @@
+/* $NetBSD: pipe.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: @(#)pipe.s 5.1 (Berkeley) 4/23/90
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+#include "SYS.h"
+
+#ifdef WEAK_ALIAS
+WEAK_ALIAS(pipe, _pipe)
+WEAK_ALIAS(__sys_pipe, _pipe)
+#endif
+
+ENTRY(_pipe)
+ mov r2, r0
+ SYSTRAP(pipe)
+ bcs PIC_SYM(CERROR, PLT)
+ str r0, [r2, #0x0000]
+ str r1, [r2, #0x0004]
+ mov r0, #0x00000000
+ RET
diff --git a/lib/libc/arm/sys/ptrace.S b/lib/libc/arm/sys/ptrace.S
new file mode 100644
index 0000000..46b31bc
--- /dev/null
+++ b/lib/libc/arm/sys/ptrace.S
@@ -0,0 +1,77 @@
+/* $NetBSD: ptrace.S,v 1.7 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: @(#)ptrace.s 5.1 (Berkeley) 4/23/90
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+#include "SYS.h"
+
+ENTRY(ptrace)
+#ifdef _REENTRANT
+ stmfd sp!, {r0-r3, lr}
+ sub sp, sp, #4 /* align stack */
+ bl PIC_SYM(_C_LABEL(__errno), PLT)
+ add sp, sp, #4 /* unalign stack */
+ mov r1, #0x00000000
+ str r1, [r0]
+ ldmfd sp!, {r0-r3, lr}
+#else
+ stmfd sp!, {r0, r1}
+#ifdef PIC
+ /* Setup the GOT */
+ ldr r0, .Lgot
+ add r0, pc, r0
+.L1:
+ ldr r1, .Lerrno
+ ldr r1, [r0, r1]
+#else
+ ldr r1, .Lerrno
+#endif /* PIC */
+ mov r0, #0x00000000
+ str r0, [r1]
+ ldmfd sp!, {r0, r1}
+#endif /* _REENTRANT */
+
+ SYSTRAP(ptrace)
+ bcs PIC_SYM(CERROR, PLT)
+ RET
+
+#ifndef _REENTRANT
+#ifdef PIC
+ .align 0
+.Lgot:
+ .word _C_LABEL(_GLOBAL_OFFSET_TABLE_) + (. - (.L1+4))
+#endif /* PIC */
+
+.Lerrno:
+ .word PIC_SYM(_C_LABEL(errno), GOT)
+#endif /* !_REENTRANT */
diff --git a/lib/libc/arm/sys/sbrk.S b/lib/libc/arm/sys/sbrk.S
new file mode 100644
index 0000000..20821fe
--- /dev/null
+++ b/lib/libc/arm/sys/sbrk.S
@@ -0,0 +1,88 @@
+/* $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)
+#ifdef PIC
+ /* Setup the GOT */
+ ldr r3, .Lgot
+ add r3, pc, r3
+.L1:
+ ldr r2, .Lcurbrk
+ ldr r2, [r3, r2]
+#else
+ ldr r2, .Lcurbrk
+#endif
+ /* 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
+#ifdef PIC
+.Lgot:
+ .word _GLOBAL_OFFSET_TABLE_ - (.L1+4)
+#endif
+.Lcurbrk:
+ .word PIC_SYM(CURBRK, GOT)
diff --git a/lib/libc/arm/sys/shmat.S b/lib/libc/arm/sys/shmat.S
new file mode 100644
index 0000000..3fc3d02
--- /dev/null
+++ b/lib/libc/arm/sys/shmat.S
@@ -0,0 +1,7 @@
+/* $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)
diff --git a/lib/libc/arm/sys/sigreturn.S b/lib/libc/arm/sys/sigreturn.S
new file mode 100644
index 0000000..1e0f245
--- /dev/null
+++ b/lib/libc/arm/sys/sigreturn.S
@@ -0,0 +1,42 @@
+/* $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)
diff --git a/lib/libc/arm/sys/syscall.S b/lib/libc/arm/sys/syscall.S
new file mode 100644
index 0000000..73e6b83
--- /dev/null
+++ b/lib/libc/arm/sys/syscall.S
@@ -0,0 +1,38 @@
+/* $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)
diff --git a/lib/libc/compat-43/Makefile.inc b/lib/libc/compat-43/Makefile.inc
new file mode 100644
index 0000000..836f0a6
--- /dev/null
+++ b/lib/libc/compat-43/Makefile.inc
@@ -0,0 +1,19 @@
+# @(#)Makefile.inc 8.1 (Berkeley) 6/2/93
+# $FreeBSD$
+
+# compat-43 sources
+.PATH: ${.CURDIR}/${MACHINE_ARCH}/compat-43 ${.CURDIR}/compat-43
+
+SRCS+= creat.c gethostid.c getwd.c killpg.c sethostid.c setpgrp.c \
+ setrgid.c setruid.c sigcompat.c
+
+SYM_MAPS+=${.CURDIR}/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+=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 0000000..09e2a61
--- /dev/null
+++ b/lib/libc/compat-43/Symbol.map
@@ -0,0 +1,21 @@
+# $FreeBSD$
+
+FBSD_1.0 {
+ creat;
+ gethostid;
+ getwd;
+ killpg;
+ sethostid;
+ setpgrp;
+ setrgid;
+ setruid;
+ sigblock;
+ sigpause;
+ sigsetmask;
+ sigvec;
+};
+
+FBSDprivate {
+ __creat;
+ _creat;
+};
diff --git a/lib/libc/compat-43/creat.2 b/lib/libc/compat-43/creat.2
new file mode 100644
index 0000000..6f8fc6f
--- /dev/null
+++ b/lib/libc/compat-43/creat.2
@@ -0,0 +1,66 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)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 0000000..0030e50
--- /dev/null
+++ b/lib/libc/compat-43/creat.c
@@ -0,0 +1,50 @@
+/*
+ * 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. 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.
+ */
+
+#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"
+
+int
+__creat(const char *path, mode_t mode)
+{
+ return(_open(path, O_WRONLY|O_CREAT|O_TRUNC, mode));
+}
+__weak_reference(__creat, creat);
+__weak_reference(__creat, _creat);
diff --git a/lib/libc/compat-43/gethostid.3 b/lib/libc/compat-43/gethostid.3
new file mode 100644
index 0000000..4b5446d
--- /dev/null
+++ b/lib/libc/compat-43/gethostid.3
@@ -0,0 +1,84 @@
+.\" 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. 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.
+.\"
+.\" @(#)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 0000000..5126371
--- /dev/null
+++ b/lib/libc/compat-43/gethostid.c
@@ -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. 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.
+ */
+
+#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 0000000..5d413a6
--- /dev/null
+++ b/lib/libc/compat-43/getwd.c
@@ -0,0 +1,55 @@
+/*-
+ * 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. 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.
+ */
+
+#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 0000000..fe78a96
--- /dev/null
+++ b/lib/libc/compat-43/killpg.2
@@ -0,0 +1,102 @@
+.\" 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. 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.
+.\"
+.\" @(#)killpg.2 8.1 (Berkeley) 6/2/93
+.\" $FreeBSD$
+.\"
+.Dd June 2, 1993
+.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 and members of the process group must
+have the same effective user ID, or
+the sender must be the super-user.
+As a single special case the continue signal SIGCONT may be sent
+to any process that is a descendant of the current process.
+.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 ESRCH
+The process group was given as 0
+but the sending process does not have a process group.
+.It Bq Er EPERM
+The sending process is not the super-user and one or more
+of the target processes has an effective user ID different from that
+of the sending process.
+.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 0000000..3eafc76
--- /dev/null
+++ b/lib/libc/compat-43/killpg.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.
+ * 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.
+ */
+
+#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 0000000..33f0ccf
--- /dev/null
+++ b/lib/libc/compat-43/sethostid.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.
+ * 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.
+ */
+
+#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 0000000..381c018
--- /dev/null
+++ b/lib/libc/compat-43/setpgrp.c
@@ -0,0 +1,47 @@
+/*-
+ * 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. 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.
+ */
+
+#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 0000000..1617ab13
--- /dev/null
+++ b/lib/libc/compat-43/setrgid.c
@@ -0,0 +1,47 @@
+/*
+ * 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. 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.
+ */
+
+#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 0000000..31228dc
--- /dev/null
+++ b/lib/libc/compat-43/setruid.3
@@ -0,0 +1,84 @@
+.\" 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. 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.
+.\"
+.\" @(#)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 0000000..a0a6e81
--- /dev/null
+++ b/lib/libc/compat-43/setruid.c
@@ -0,0 +1,47 @@
+/*
+ * 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. 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.
+ */
+
+#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 0000000..67a7412
--- /dev/null
+++ b/lib/libc/compat-43/sigcompat.c
@@ -0,0 +1,112 @@
+/*
+ * 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. 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.
+ */
+
+#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 <signal.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+
+int
+sigvec(signo, sv, osv)
+ int signo;
+ struct sigvec *sv, *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 = _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(mask)
+ int mask;
+{
+ sigset_t set, oset;
+ int n;
+
+ sigemptyset(&set);
+ set.__bits[0] = mask;
+ n = _sigprocmask(SIG_SETMASK, &set, &oset);
+ if (n)
+ return (n);
+ return (oset.__bits[0]);
+}
+
+int
+sigblock(mask)
+ int mask;
+{
+ sigset_t set, oset;
+ int n;
+
+ sigemptyset(&set);
+ set.__bits[0] = mask;
+ n = _sigprocmask(SIG_BLOCK, &set, &oset);
+ if (n)
+ return (n);
+ return (oset.__bits[0]);
+}
+
+int
+sigpause(mask)
+ int mask;
+{
+ sigset_t set;
+
+ sigemptyset(&set);
+ set.__bits[0] = mask;
+ return (_sigsuspend(&set));
+}
diff --git a/lib/libc/compat-43/sigpause.2 b/lib/libc/compat-43/sigpause.2
new file mode 100644
index 0000000..2711d18
--- /dev/null
+++ b/lib/libc/compat-43/sigpause.2
@@ -0,0 +1,97 @@
+.\" 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. 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.
+.\"
+.\" @(#)sigpause.2 8.1 (Berkeley) 6/2/93
+.\" $FreeBSD$
+.\"
+.Dd June 2, 1993
+.Dt SIGPAUSE 2
+.Os
+.Sh NAME
+.Nm sigpause
+.Nd atomically release blocked signals and wait for interrupt
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In signal.h
+.Ft int
+.Fn sigpause "int sigmask"
+.Sh DESCRIPTION
+.Sy This interface is made obsolete by
+.Xr sigsuspend 2 .
+.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.
+The
+.Fn sigpause
+function
+always terminates by being interrupted, returning -1 with
+.Va errno
+set to
+.Er EINTR
+.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 .
+.Sh HISTORY
+The
+.Fn sigpause
+function appeared in
+.Bx 4.2
+and has been deprecated.
diff --git a/lib/libc/compat-43/sigsetmask.2 b/lib/libc/compat-43/sigsetmask.2
new file mode 100644
index 0000000..8e8d78f
--- /dev/null
+++ b/lib/libc/compat-43/sigsetmask.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.
+.\" 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.
+.\"
+.\" @(#)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 0000000..4e5cedd
--- /dev/null
+++ b/lib/libc/compat-43/sigvec.2
@@ -0,0 +1,346 @@
+.\" 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. 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.
+.\"
+.\" @(#)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 0000000..bbfb7e7
--- /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 "${.CURDIR}/db/btree/Makefile.inc"
+.include "${.CURDIR}/db/db/Makefile.inc"
+.include "${.CURDIR}/db/hash/Makefile.inc"
+.include "${.CURDIR}/db/man/Makefile.inc"
+.include "${.CURDIR}/db/mpool/Makefile.inc"
+.include "${.CURDIR}/db/recno/Makefile.inc"
+
+SYM_MAPS+=${.CURDIR}/db/Symbol.map
diff --git a/lib/libc/db/README b/lib/libc/db/README
new file mode 100644
index 0000000..bed2c92
--- /dev/null
+++ b/lib/libc/db/README
@@ -0,0 +1,40 @@
+# @(#)README 8.27 (Berkeley) 9/1/94
+
+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.
+
+============================================
+Debugging:
+
+If you're running a memory checker (e.g. Purify) on DB, make sure that
+you recompile it with "-DPURIFY" in the CFLAGS, first. By default,
+allocated pages are not initialized by the DB code, and they will show
+up as reads of uninitialized memory in the buffer write routines.
diff --git a/lib/libc/db/Symbol.map b/lib/libc/db/Symbol.map
new file mode 100644
index 0000000..c1dce63
--- /dev/null
+++ b/lib/libc/db/Symbol.map
@@ -0,0 +1,30 @@
+# $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_new;
+ mpool_get;
+ mpool_put;
+ mpool_close;
+ mpool_sync;
+ mpool_stat;
+};
+
+FBSDprivate {
+ __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 0000000..76c2238
--- /dev/null
+++ b/lib/libc/db/btree/Makefile.inc
@@ -0,0 +1,8 @@
+# from @(#)Makefile.inc 8.2 (Berkeley) 7/14/94
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/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 0000000..3bdb505
--- /dev/null
+++ b/lib/libc/db/btree/bt_close.c
@@ -0,0 +1,186 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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(dbp)
+ 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(dbp, flags)
+ 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))
+ 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(t)
+ 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 0000000..18f3774
--- /dev/null
+++ b/lib/libc/db/btree/bt_conv.c
@@ -0,0 +1,223 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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(t, pg, pp)
+ 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(t, pg, pp)
+ 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(pg)
+ 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 0000000..14aadc6
--- /dev/null
+++ b/lib/libc/db/btree/bt_debug.c
@@ -0,0 +1,332 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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(dbp)
+ DB *dbp;
+{
+ BTREE *t;
+ PAGE *h;
+ pgno_t i;
+ char *sep;
+
+ t = dbp->internal;
+ (void)fprintf(stderr, "%s: pgsz %d",
+ 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, 0)) != NULL; ++i) {
+ __bt_dpage(h);
+ (void)mpool_put(t->bt_mp, h, 0);
+ }
+}
+
+/*
+ * BT_DMPAGE -- Dump the meta page
+ *
+ * Parameters:
+ * h: pointer to the PAGE
+ */
+void
+__bt_dmpage(h)
+ 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(dbp, pgno)
+ DB *dbp;
+ pgno_t pgno;
+{
+ BTREE *t;
+ PAGE *h;
+
+ t = dbp->internal;
+ if ((h = mpool_get(t->bt_mp, pgno, 0)) != NULL) {
+ __bt_dpage(h);
+ (void)mpool_put(t->bt_mp, h, 0);
+ }
+}
+
+/*
+ * BT_DPAGE -- Dump the page
+ *
+ * Parameters:
+ * h: pointer to the PAGE
+ */
+void
+__bt_dpage(h)
+ PAGE *h;
+{
+ BINTERNAL *bi;
+ BLEAF *bl;
+ RINTERNAL *ri;
+ RLEAF *rl;
+ indx_t cur, top;
+ char *sep;
+
+ (void)fprintf(stderr, " page %d: (", 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 %2d next %2d", 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(dbp)
+ 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, 0)) != 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;
+ }
+ (void)mpool_put(t->bt_mp, h, 0);
+ }
+
+ /* Count the levels of the tree. */
+ for (i = P_ROOT, levels = 0 ;; ++levels) {
+ h = mpool_get(t->bt_mp, i, 0);
+ if (h->flags & (P_BLEAF|P_RLEAF)) {
+ if (levels == 0)
+ levels = 1;
+ (void)mpool_put(t->bt_mp, h, 0);
+ break;
+ }
+ i = F_ISSET(t, R_RECNO) ?
+ GETRINTERNAL(h, 0)->pgno :
+ GETBINTERNAL(h, 0)->pgno;
+ (void)mpool_put(t->bt_mp, h, 0);
+ }
+
+ (void)fprintf(stderr, "%d level%s with %ld keys",
+ levels, levels == 1 ? "" : "s", nkeys);
+ if (F_ISSET(t, R_RECNO))
+ (void)fprintf(stderr, " (%d header count)", t->bt_nrecs);
+ (void)fprintf(stderr,
+ "\n%u pages (leaf %d, internal %d, overflow %d)\n",
+ pinternal + pleaf + pcont, pleaf, pinternal, pcont);
+ (void)fprintf(stderr, "%ld cache hits, %ld 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 (%ld bytes used, %ld bytes free)\n",
+ ((double)(pleaf - lfree) / pleaf) * 100,
+ pleaf - lfree, lfree);
+ pinternal *= t->bt_psize - BTDATAOFF;
+ if (pinternal)
+ (void)fprintf(stderr,
+ "%.0f%% internal fill (%ld bytes used, %ld 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 0000000..13e43df
--- /dev/null
+++ b/lib/libc/db/btree/bt_delete.c
@@ -0,0 +1,659 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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(dbp, key, flags)
+ 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(t, hp, c)
+ BTREE *t;
+ PAGE **hp;
+ CURSOR *c;
+{
+ BINTERNAL *bi;
+ EPG *e;
+ EPGNO *parent;
+ PAGE *h;
+ indx_t index;
+ 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) {
+ index = parent->index + 1;
+ BT_PUSH(t, h->pgno, index);
+ break;
+ }
+ mpool_put(t->bt_mp, h, 0);
+ }
+
+ /* Restore the stack. */
+ while (level--) {
+ /* Push the next level down onto the stack. */
+ bi = GETBINTERNAL(h, index);
+ 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);
+ index = 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) {
+ index = parent->index - 1;
+ BT_PUSH(t, h->pgno, index);
+ break;
+ }
+ mpool_put(t->bt_mp, h, 0);
+ }
+
+ /* Restore the stack. */
+ while (level--) {
+ /* Push the next level down onto the stack. */
+ bi = GETBINTERNAL(h, index);
+ 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);
+
+ index = NEXTINDEX(h) - 1;
+ BT_PUSH(t, pgno, index);
+ }
+ 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(t, key)
+ 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(t, h)
+ BTREE *t;
+ PAGE *h;
+{
+ BINTERNAL *bi;
+ PAGE *pg;
+ EPGNO *parent;
+ indx_t cnt, index, *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);
+
+ index = parent->index;
+ bi = GETBINTERNAL(pg, index);
+
+ /* 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[index];
+ for (cnt = index, ip = &pg->linp[0]; cnt--; ++ip)
+ if (ip[0] < offset)
+ ip[0] += nksize;
+ for (cnt = NEXTINDEX(pg) - index; --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
+ * index: index on page to delete
+ *
+ * Returns:
+ * RET_SUCCESS, RET_ERROR.
+ */
+int
+__bt_dleaf(t, key, h, index)
+ BTREE *t;
+ const DBT *key;
+ PAGE *h;
+ u_int index;
+{
+ 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 == index &&
+ __bt_curdel(t, key, h, index))
+ return (RET_ERROR);
+
+ /* If the entry uses overflow pages, make them available for reuse. */
+ to = bl = GETBLEAF(h, index);
+ 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[index];
+ for (cnt = index, ip = &h->linp[0]; cnt--; ++ip)
+ if (ip[0] < offset)
+ ip[0] += nbytes;
+ for (cnt = NEXTINDEX(h) - index; --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 > index)
+ --t->bt_cursor.pg.index;
+
+ return (RET_SUCCESS);
+}
+
+/*
+ * __bt_curdel --
+ * Delete the cursor.
+ *
+ * Parameters:
+ * t: tree
+ * key: referenced key (or NULL)
+ * h: page
+ * index: index on page to delete
+ *
+ * Returns:
+ * RET_SUCCESS, RET_ERROR.
+ */
+static int
+__bt_curdel(t, key, h, index)
+ BTREE *t;
+ const DBT *key;
+ PAGE *h;
+ u_int index;
+{
+ 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 = index;
+ 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 (index > 0) {
+ e.page = h;
+ e.index = index - 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 (index < NEXTINDEX(h) - 1) {
+ e.page = h;
+ e.index = index + 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 (index == 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 (index == 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 = index;
+ 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(t, h)
+ 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 0000000..1911731
--- /dev/null
+++ b/lib/libc/db/btree/bt_get.c
@@ -0,0 +1,107 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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(dbp, key, data, flags)
+ 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 0000000..40b00a5
--- /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.
+ * 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.
+ */
+
+#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 <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(fname, flags, mode, openinfo, dflags)
+ const char *fname;
+ int flags, mode, dflags;
+ const BTREEINFO *openinfo;
+{
+ struct stat sb;
+ BTMETA m;
+ BTREE *t;
+ BTREEINFO b;
+ DB *dbp;
+ pgno_t ncache;
+ ssize_t nr;
+ int machine_lorder;
+
+ 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 *)malloc(sizeof(BTREE))) == NULL)
+ goto err;
+ memset(t, 0, sizeof(BTREE));
+ 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 *)malloc(sizeof(DB))) == NULL)
+ goto err;
+ memset(t->bt_dbp, 0, sizeof(DB));
+ 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, 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 (_fcntl(t->bt_fd, F_SETFD, 1) == -1)
+ goto err;
+
+ 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 = (b.cachesize + t->bt_psize - 1) / 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: if (t) {
+ if (t->bt_dbp)
+ free(t->bt_dbp);
+ if (t->bt_fd != -1)
+ (void)_close(t->bt_fd);
+ free(t);
+ }
+ return (NULL);
+}
+
+/*
+ * NROOT -- Create the root of a new tree.
+ *
+ * Parameters:
+ * t: tree
+ *
+ * Returns:
+ * RET_ERROR, RET_SUCCESS
+ */
+static int
+nroot(t)
+ BTREE *t;
+{
+ PAGE *meta, *root;
+ pgno_t npg;
+
+ if ((meta = mpool_get(t->bt_mp, 0, 0)) != NULL) {
+ mpool_put(t->bt_mp, meta, 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)) == NULL)
+ return (RET_ERROR);
+
+ if ((root = mpool_new(t->bt_mp, &npg)) == 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()
+{
+ sigset_t set, oset;
+ int fd;
+ char *envtmp = NULL;
+ char path[MAXPATHLEN];
+
+ if (issetugid() == 0)
+ envtmp = getenv("TMPDIR");
+ (void)snprintf(path,
+ sizeof(path), "%s/bt.XXXXXXXXXX", envtmp ? envtmp : "/tmp");
+
+ (void)sigfillset(&set);
+ (void)_sigprocmask(SIG_BLOCK, &set, &oset);
+ if ((fd = mkstemp(path)) != -1)
+ (void)unlink(path);
+ (void)_sigprocmask(SIG_SETMASK, &oset, NULL);
+ return(fd);
+}
+
+static int
+byteorder()
+{
+ 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(dbp)
+ 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 0000000..7f479f5
--- /dev/null
+++ b/lib/libc/db/btree/bt_overflow.c
@@ -0,0 +1,230 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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(t, p, ssz, buf, bufsz)
+ 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 = (char *)(*buf == NULL ? malloc(sz) : 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(t, dbt, pg)
+ 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(t, p)
+ 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 0000000..105ffa5
--- /dev/null
+++ b/lib/libc/db/btree/bt_page.c
@@ -0,0 +1,102 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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(t, h)
+ 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(t, npg)
+ 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));
+}
diff --git a/lib/libc/db/btree/bt_put.c b/lib/libc/db/btree/bt_put.c
new file mode 100644
index 0000000..42b6f7e
--- /dev/null
+++ b/lib/libc/db/btree/bt_put.c
@@ -0,0 +1,325 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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
+ *
+ * Returns:
+ * RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key is already in the
+ * tree and R_NOOVERWRITE specified.
+ */
+int
+__bt_put(dbp, key, data, flags)
+ const DB *dbp;
+ DBT *key;
+ const DBT *data;
+ u_int flags;
+{
+ BTREE *t;
+ DBT tkey, tdata;
+ EPG *e;
+ PAGE *h;
+ indx_t index, 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:
+ 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);
+ index = 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;
+ index = 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, index) == 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 (h->upper - h->lower < nbytes + sizeof(indx_t)) {
+ if ((status = __bt_split(t, h, key,
+ data, dflags, nbytes, index)) != RET_SUCCESS)
+ return (status);
+ goto success;
+ }
+
+ if (index < (nxtindex = NEXTINDEX(h)))
+ memmove(h->linp + index + 1, h->linp + index,
+ (nxtindex - index) * sizeof(indx_t));
+ h->lower += sizeof(indx_t);
+
+ h->linp[index] = 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 >= index)
+ ++t->bt_cursor.pg.index;
+
+ if (t->bt_order == NOT) {
+ if (h->nextpg == P_INVALID) {
+ if (index == NEXTINDEX(h) - 1) {
+ t->bt_order = FORWARD;
+ t->bt_last.index = index;
+ t->bt_last.pgno = h->pgno;
+ }
+ } else if (h->prevpg == P_INVALID) {
+ if (index == 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(t, key, data, exactp)
+ BTREE *t;
+ const DBT *key, *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 (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 0000000..4fc39e9
--- /dev/null
+++ b/lib/libc/db/btree/bt_search.c
@@ -0,0 +1,215 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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(t, key, exactp)
+ BTREE *t;
+ const DBT *key;
+ int *exactp;
+{
+ PAGE *h;
+ indx_t base, index, 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 = index = 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 = index + 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.
+ */
+ index = base ? base - 1 : base;
+
+next: BT_PUSH(t, h->pgno, index);
+ pg = GETBINTERNAL(h, index)->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(t, h, key, exactp)
+ 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(t, h, key, exactp)
+ 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 0000000..8b0dae2
--- /dev/null
+++ b/lib/libc/db/btree/bt_seq.c
@@ -0,0 +1,462 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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(dbp, key, data, flags)
+ const DB *dbp;
+ DBT *key, *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(t, ep, key, flags)
+ 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(t, ep, flags)
+ BTREE *t;
+ EPG *ep;
+ int flags;
+{
+ CURSOR *c;
+ PAGE *h;
+ indx_t index;
+ 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;
+ index = c->pg.index;
+ if (++index == 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);
+ index = 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);
+ }
+ index = c->pg.index;
+ if (index == 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);
+ index = NEXTINDEX(h) - 1;
+ } else
+ --index;
+ break;
+ }
+
+ ep->page = h;
+ ep->index = index;
+ 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(t, key, erval, exactp)
+ 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
+ * index: page index
+ */
+void
+__bt_setcur(t, pgno, index)
+ BTREE *t;
+ pgno_t pgno;
+ u_int index;
+{
+ /* 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 = index;
+ 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 0000000..1dd4666
--- /dev/null
+++ b/lib/libc/db/btree/bt_split.c
@@ -0,0 +1,827 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)bt_split.c 8.9 (Berkeley) 7/26/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.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(t, sp, key, data, flags, ilen, argskip)
+ BTREE *t;
+ PAGE *sp;
+ const DBT *key, *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 (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 &&
+ bt_preserve(t, *(pgno_t *)bl->bytes) == 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(t, h, lp, rp, skip, ilen)
+ BTREE *t;
+ PAGE *h, **lp, **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 *)malloc(t->bt_psize)) == NULL) {
+ mpool_put(t->bt_mp, r, 0);
+ return (NULL);
+ }
+#ifdef PURIFY
+ memset(l, 0xff, t->bt_psize);
+#endif
+ 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(t, h, lp, rp, skip, ilen)
+ BTREE *t;
+ PAGE *h, **lp, **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(t, h, l, r)
+ BTREE *t;
+ PAGE *h, *l, *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);
+
+ 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(t, h, l, r)
+ BTREE *t;
+ PAGE *h, *l, *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);
+ 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 &&
+ bt_preserve(t, *(pgno_t *)bl->bytes) == RET_ERROR)
+ return (RET_ERROR);
+ break;
+ case P_BINTERNAL:
+ bi = GETBINTERNAL(r, 0);
+ nbytes = NBINTERNAL(bi->ksize);
+ 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(t, h, l, r, pskip, ilen)
+ BTREE *t;
+ PAGE *h, *l, *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(t, pg)
+ 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(h)
+ 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 0000000..0f8ef34
--- /dev/null
+++ b/lib/libc/db/btree/bt_utils.c
@@ -0,0 +1,262 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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(t, e, key, rkey, data, rdata, copy)
+ BTREE *t;
+ EPG *e;
+ DBT *key, *rkey, *data, *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 = (void *)(rkey->data == NULL ?
+ malloc(bl->ksize) : 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 = (void *)(rdata->data == NULL ?
+ malloc(bl->dsize + 1) :
+ 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(t, k1, e)
+ 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(a, b)
+ const DBT *a, *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(a, b)
+ const DBT *a, *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 0000000..1ac6fe1
--- /dev/null
+++ b/lib/libc/db/btree/btree.h
@@ -0,0 +1,384 @@
+/*-
+ * 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.
+ * 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.
+ *
+ * @(#)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 0000000..a151acc
--- /dev/null
+++ b/lib/libc/db/btree/extern.h
@@ -0,0 +1,71 @@
+/*-
+ * 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.
+ * 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.
+ *
+ * @(#)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 0000000..1540ca8
--- /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 0000000..2bbac4e
--- /dev/null
+++ b/lib/libc/db/db/Makefile.inc
@@ -0,0 +1,6 @@
+# from @(#)Makefile.inc 8.1 (Berkeley) 6/4/93
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/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 0000000..830f581
--- /dev/null
+++ b/lib/libc/db/db/db.c
@@ -0,0 +1,101 @@
+/*-
+ * 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. 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.
+ */
+
+#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>
+
+DB *
+dbopen(fname, flags, mode, type, openinfo)
+ const char *fname;
+ int flags, 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_NONBLOCK | O_RDONLY | \
+ O_RDWR | O_SHLOCK | O_TRUNC)
+
+ 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()
+{
+ return (RET_ERROR);
+}
+
+/*
+ * __DBPANIC -- Stop.
+ *
+ * Parameters:
+ * dbp: pointer to the DB structure.
+ */
+void
+__dbpanic(dbp)
+ DB *dbp;
+{
+ /* The only thing that can succeed is a close. */
+ dbp->del = (int (*)())__dberr;
+ dbp->fd = (int (*)())__dberr;
+ dbp->get = (int (*)())__dberr;
+ dbp->put = (int (*)())__dberr;
+ dbp->seq = (int (*)())__dberr;
+ dbp->sync = (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 0000000..3a0cf44
--- /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 0000000..b7e441a
--- /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 0000000..2ecb817
--- /dev/null
+++ b/lib/libc/db/hash/Makefile.inc
@@ -0,0 +1,7 @@
+# from @(#)Makefile.inc 8.1 (Berkeley) 6/4/93
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/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 0000000..f29ccf7
--- /dev/null
+++ b/lib/libc/db/hash/README
@@ -0,0 +1,72 @@
+# @(#)README 8.1 (Berkeley) 6/4/93
+
+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 file search.h is provided for using the hsearch compatible interface
+on BSD systems. On System V derived systems, search.h should appear in
+/usr/include.
+
+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 0000000..9ae5832
--- /dev/null
+++ b/lib/libc/db/hash/extern.h
@@ -0,0 +1,66 @@
+/*-
+ * 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.
+ * 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.
+ *
+ * @(#)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 0000000..4dd1267
--- /dev/null
+++ b/lib/libc/db/hash/hash.c
@@ -0,0 +1,1006 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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 *, 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 */
+
+extern DB *
+__hash_open(file, flags, mode, info, dflags)
+ const char *file;
+ int flags, mode, dflags;
+ const HASHINFO *info; /* Special directives for create */
+{
+ 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;
+
+ new_table = 0;
+ if (!file || (flags & O_TRUNC) ||
+ (stat(file, &statbuf) && (errno == ENOENT))) {
+ if (errno == ENOENT)
+ errno = 0; /* Just in case someone looks at errno */
+ new_table = 1;
+ }
+ if (file) {
+ if ((hashp->fp = _open(file, flags, mode)) == -1)
+ RETURN_ERROR(errno, error0);
+
+ /* if the .db file is empty, and we had permission to create
+ a new .db file, then reinitialize the database */
+ if ((flags & O_CREAT) &&
+ _fstat(hashp->fp, &statbuf) == 0 && statbuf.st_size == 0)
+ new_table = 1;
+
+ (void)_fcntl(hashp->fp, F_SETFD, 1);
+ }
+ if (new_table) {
+ if (!(hashp = init_hash(hashp, file, (HASHINFO *)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 (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 = (hashp->MAX_BUCKET + 1 + hashp->SGSIZE - 1) /
+ hashp->SGSIZE;
+ hashp->nsegs = 0;
+ 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(dbp)
+ 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(dbp)
+ 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(hashp, file, info)
+ HTAB *hashp;
+ const char *file;
+ 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;
+ 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(hashp, nelem)
+ HTAB *hashp;
+ int nelem;
+{
+ int nbuckets, nsegs;
+ int 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(hashp)
+ 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->fp != -1)
+ (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(dbp, flags)
+ 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);
+ hashp->new_file = 0;
+ return (0);
+}
+
+/*
+ * Returns:
+ * 0 == OK
+ * -1 indicates that errno should be set
+ */
+static int
+flush_meta(hashp)
+ 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 ((lseek(fp, (off_t)0, SEEK_SET) == -1) ||
+ ((wsize = _write(fp, whdrp, sizeof(HASHHDR))) == -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(dbp, key, data, flag)
+ 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(dbp, key, data, flag)
+ 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 = EINVAL;
+ 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(dbp, key, flag)
+ 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(hashp, action, key, val)
+ HTAB *hashp;
+ ACTION action;
+ DBT *key, *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(dbp, key, data, flag)
+ const DB *dbp;
+ DBT *key, *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;
+ }
+
+ 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 (hashp->cbucket > hashp->MAX_BUCKET) {
+ hashp->cbucket = -1;
+ return (ABNORMAL);
+ }
+ } else
+ bp = (u_int16_t *)hashp->cpage->page;
+
+#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 {
+ 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];
+ ndx += 2;
+ if (ndx > bp[0]) {
+ hashp->cpage = NULL;
+ hashp->cbucket++;
+ hashp->cndx = 1;
+ } else
+ hashp->cndx = ndx;
+ }
+ return (SUCCESS);
+}
+
+/********************************* UTILITIES ************************/
+
+/*
+ * Returns:
+ * 0 ==> OK
+ * -1 ==> Error
+ */
+extern int
+__expand_table(hashp)
+ 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] =
+ (SEGMENT)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(p_ptr, oldsize, newsize)
+ SEGMENT **p_ptr;
+ int oldsize, 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);
+}
+
+extern u_int32_t
+__call_hash(hashp, k, len)
+ HTAB *hashp;
+ char *k;
+ int len;
+{
+ 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(hashp, nsegs)
+ HTAB *hashp;
+ int nsegs;
+{
+ int i;
+ SEGMENT store;
+
+ int save_errno;
+
+ if ((hashp->dir =
+ (SEGMENT *)calloc(hashp->DSIZE, sizeof(SEGMENT *))) == NULL) {
+ save_errno = errno;
+ (void)hdestroy(hashp);
+ errno = save_errno;
+ return (-1);
+ }
+ /* Allocate segments */
+ if ((store =
+ (SEGMENT)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->nsegs++)
+ 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(srcp, destp)
+ HASHHDR *srcp, *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(hashp)
+ 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 0000000..2c0a542
--- /dev/null
+++ b/lib/libc/db/hash/hash.h
@@ -0,0 +1,294 @@
+/*-
+ * 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.
+ * 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.
+ *
+ * @(#)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 */
+ int magic; /* Magic NO for hash tables */
+ int version; /* Version ID */
+ u_int32_t lorder; /* Byte Order */
+ int bsize; /* Bucket/Page Size */
+ int bshift; /* Bucket shift */
+ int dsize; /* Directory Size */
+ int ssize; /* Segment Size */
+ int sshift; /* Segment shift */
+ int ovfl_point; /* Where overflow pages are being
+ * allocated */
+ int last_freed; /* Last overflow page freed */
+ int max_bucket; /* ID of Maximum bucket in use */
+ int high_mask; /* Mask to modulo into entire table */
+ int low_mask; /* Mask to modulo into lower half of
+ * table */
+ int ffactor; /* Fill factor */
+ int nkeys; /* Number of keys in hash table */
+ int hdrpages; /* Size of table header */
+ int h_charkey; /* value of hash(CHARKEY) */
+#define NCACHED 32 /* number of bit maps and spare
+ * points */
+ int 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 65536 /* 2^16 */
+#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 *)((ptrdiff_t)(X)&~0x3))
+#define ISMOD(X) ((u_int32_t)(ptrdiff_t)(X)&0x1)
+#define DOMOD(X) ((X) = (char *)((ptrdiff_t)(X)|0x1))
+#define ISDISK(X) ((u_int32_t)(ptrdiff_t)(X)&0x2)
+#define DODISK(X) ((X) = (char *)((ptrdiff_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 0000000..c70b375
--- /dev/null
+++ b/lib/libc/db/hash/hash_bigkey.c
@@ -0,0 +1,670 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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
+ */
+extern int
+__big_insert(hashp, bufp, key, val)
+ HTAB *hashp;
+ BUFHEAD *bufp;
+ const DBT *key, *val;
+{
+ u_int16_t *p;
+ int key_size, n, 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) {
+ if (FREESPACE(p)) {
+ move_bytes = MIN(FREESPACE(p), val_size);
+ off = OFFSET(p) - move_bytes;
+ p[n] = off;
+ memmove(cp + off, val_data, move_bytes);
+ val_data += move_bytes;
+ val_size -= move_bytes;
+ p[n - 2] = FULL_KEY_DATA;
+ FREESPACE(p) = FREESPACE(p) - move_bytes;
+ OFFSET(p) = off;
+ } else
+ 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
+ */
+extern int
+__big_delete(hashp, bufp)
+ 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 - 1;
+
+ bufp->flags |= BUF_MOD;
+ if (rbufp)
+ __free_ovflpage(hashp, rbufp);
+ if (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
+ */
+extern int
+__find_bigpair(hashp, bufp, ndx, key, size)
+ 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)
+ */
+extern u_int16_t
+__find_last_page(hashp, bpp)
+ 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).
+ */
+extern int
+__big_return(hashp, bufp, ndx, val, set_current)
+ 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 = collect_data(hashp, bufp, (int)len, set_current);
+ if (val->size == -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(hashp, bufp, len, set)
+ HTAB *hashp;
+ BUFHEAD *bufp;
+ int len, 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.
+ */
+extern int
+__big_keydata(hashp, bufp, key, val, set)
+ HTAB *hashp;
+ BUFHEAD *bufp;
+ DBT *key, *val;
+ int set;
+{
+ key->size = collect_key(hashp, bufp, 0, val, set);
+ if (key->size == -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(hashp, bufp, len, val, set)
+ 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
+ */
+extern int
+__big_split(hashp, op, np, big_keyp, addr, obucket, ret)
+ HTAB *hashp;
+ BUFHEAD *op; /* Pointer to where to put keys that go in old bucket */
+ BUFHEAD *np; /* Pointer to new bucket page */
+ /* Pointer to first page containing the big key/data */
+ BUFHEAD *big_keyp;
+ int addr; /* Address of big_keyp */
+ u_int32_t obucket;/* Old Bucket */
+ SPLIT_RETURN *ret;
+{
+ BUFHEAD *tmpp;
+ u_int16_t *tp;
+ BUFHEAD *bp;
+ DBT key, val;
+ u_int32_t change;
+ u_int16_t free_space, n, off;
+
+ 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 0000000..1ec6b11
--- /dev/null
+++ b/lib/libc/db/hash/hash_buf.c
@@ -0,0 +1,356 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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>
+
+#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.
+ */
+extern BUFHEAD *
+__get_buf(hashp, addr, prev_bp, newpage)
+ HTAB *hashp;
+ u_int32_t addr;
+ BUFHEAD *prev_bp;
+ int newpage; /* If prev_bp set, indicates a new overflow page. */
+{
+ 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 *)((ptrdiff_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(hashp, addr, prev_bp)
+ 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;
+ /*
+ * If LRU buffer is pinned, the buffer pool is too small. We need to
+ * allocate more buffers.
+ */
+ if (hashp->nbufs || (bp->flags & BUF_PIN)) {
+ /* Allocate a new one */
+ if ((bp = (BUFHEAD *)malloc(sizeof(BUFHEAD))) == NULL)
+ return (NULL);
+#ifdef PURIFY
+ memset(bp, 0xff, sizeof(BUFHEAD));
+#endif
+ if ((bp->page = (char *)malloc(hashp->BSIZE)) == NULL) {
+ free(bp);
+ return (NULL);
+ }
+#ifdef PURIFY
+ memset(bp->page, 0xff, hashp->BSIZE);
+#endif
+ 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 = 0;
+ 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 ? 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);
+}
+
+extern void
+__buf_init(hashp, nbytes)
+ 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;
+ */
+}
+
+extern int
+__buf_free(hashp, do_free, to_disk)
+ HTAB *hashp;
+ int do_free, 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)
+ free(bp->page);
+ BUF_REMOVE(bp);
+ free(bp);
+ bp = LRU;
+ } else
+ bp = bp->prev;
+ }
+ return (0);
+}
+
+extern void
+__reclaim_buf(hashp, bp)
+ HTAB *hashp;
+ BUFHEAD *bp;
+{
+ bp->ovfl = 0;
+ 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 0000000..194c872
--- /dev/null
+++ b/lib/libc/db/hash/hash_func.c
@@ -0,0 +1,214 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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"
+
+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;
+static u_int32_t hash4(const void *, size_t);
+
+/* Global default hash function */
+u_int32_t (*__default_hash)(const void *, size_t) = hash4;
+
+/*
+ * HASH FUNCTIONS
+ *
+ * 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.
+ *
+ * This came from ejb's hsearch.
+ */
+
+#define PRIME1 37
+#define PRIME2 1048583
+
+static u_int32_t
+hash1(keyarg, len)
+ const void *keyarg;
+ size_t len;
+{
+ const u_char *key;
+ u_int32_t h;
+
+ /* Convert string to integer */
+ for (key = keyarg, h = 0; len--;)
+ h = h * PRIME1 ^ (*key++ - ' ');
+ h %= PRIME2;
+ return (h);
+}
+
+/*
+ * Phong's linear congruential hash
+ */
+#define dcharhash(h, c) ((h) = 0x63c63cd9*(h) + 0x9c39c33d + (c))
+
+static u_int32_t
+hash2(keyarg, len)
+ const void *keyarg;
+ size_t len;
+{
+ const u_char *e, *key;
+ u_int32_t h;
+ u_char c;
+
+ key = keyarg;
+ e = key + len;
+ for (h = 0; key != e;) {
+ c = *key++;
+ if (!c && key > 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.
+ *
+ * OZ's original sdbm hash
+ */
+static u_int32_t
+hash3(keyarg, len)
+ const void *keyarg;
+ size_t len;
+{
+ const u_char *key;
+ size_t loop;
+ u_int32_t h;
+
+#define HASHC h = *key++ + 65599 * h
+
+ h = 0;
+ key = keyarg;
+ if (len > 0) {
+ loop = (len + 8 - 1) >> 3;
+
+ switch (len & (8 - 1)) {
+ case 0:
+ do {
+ HASHC;
+ /* FALLTHROUGH */
+ case 7:
+ HASHC;
+ /* FALLTHROUGH */
+ case 6:
+ HASHC;
+ /* FALLTHROUGH */
+ case 5:
+ HASHC;
+ /* FALLTHROUGH */
+ case 4:
+ HASHC;
+ /* FALLTHROUGH */
+ case 3:
+ HASHC;
+ /* FALLTHROUGH */
+ case 2:
+ HASHC;
+ /* FALLTHROUGH */
+ case 1:
+ HASHC;
+ } while (--loop);
+ }
+ }
+ return (h);
+}
+
+/* Hash function from Chris Torek. */
+static u_int32_t
+hash4(keyarg, len)
+ const void *keyarg;
+ size_t len;
+{
+ const u_char *key;
+ size_t loop;
+ u_int32_t h;
+
+#define HASH4a h = (h << 5) - h + *key++;
+#define HASH4b h = (h << 5) + h + *key++;
+#define HASH4 HASH4b
+
+ h = 0;
+ key = keyarg;
+ if (len > 0) {
+ loop = (len + 8 - 1) >> 3;
+
+ switch (len & (8 - 1)) {
+ case 0:
+ do {
+ HASH4;
+ /* FALLTHROUGH */
+ case 7:
+ HASH4;
+ /* FALLTHROUGH */
+ case 6:
+ HASH4;
+ /* FALLTHROUGH */
+ case 5:
+ HASH4;
+ /* FALLTHROUGH */
+ case 4:
+ HASH4;
+ /* FALLTHROUGH */
+ case 3:
+ HASH4;
+ /* FALLTHROUGH */
+ case 2:
+ HASH4;
+ /* FALLTHROUGH */
+ 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 0000000..c9634dc
--- /dev/null
+++ b/lib/libc/db/hash/hash_log2.c
@@ -0,0 +1,56 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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 <sys/types.h>
+
+#include <db.h>
+
+u_int32_t
+__log2(num)
+ 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 0000000..f0739fb
--- /dev/null
+++ b/lib/libc/db/hash/hash_page.c
@@ -0,0 +1,948 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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/types.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 <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(p, key, val)
+ char *p;
+ const DBT *key, *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
+ */
+extern int
+__delpair(hashp, bufp, ndx)
+ HTAB *hashp;
+ BUFHEAD *bufp;
+ int ndx;
+{
+ u_int16_t *bp, newoff;
+ int n;
+ u_int16_t pairlen;
+
+ 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;
+ }
+ }
+ }
+ /* 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
+ */
+extern int
+__split_page(hashp, obucket, nbucket)
+ HTAB *hashp;
+ u_int32_t obucket, 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(hashp, obucket, old_bufp, new_bufp, copyto, moved)
+ HTAB *hashp;
+ u_int32_t obucket; /* Same as __split_page. */
+ BUFHEAD *old_bufp, *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
+ */
+extern int
+__addel(hashp, bufp, key, val)
+ HTAB *hashp;
+ BUFHEAD *bufp;
+ const DBT *key, *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
+ /* Try to squeeze key on this page */
+ if (FREESPACE(bp) > PAIRSIZE(key, val)) {
+ squeeze_key(bp, key, val);
+ return (0);
+ } 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);
+ }
+ 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
+ */
+extern BUFHEAD *
+__add_ovflpage(hashp, bufp)
+ HTAB *hashp;
+ BUFHEAD *bufp;
+{
+ u_int16_t *sp;
+ u_int16_t 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
+ */
+extern int
+__get_page(hashp, p, bucket, is_bucket, is_disk, is_bitmap)
+ HTAB *hashp;
+ char *p;
+ u_int32_t bucket;
+ int is_bucket, is_disk, is_bitmap;
+{
+ int fd, page, size;
+ int 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 ((lseek(fd, (off_t)page << hashp->BSHIFT, SEEK_SET) == -1) ||
+ ((rsize = _read(fd, p, size)) == -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
+ */
+extern int
+__put_page(hashp, p, bucket, is_bucket, is_bitmap)
+ HTAB *hashp;
+ char *p;
+ u_int32_t bucket;
+ int is_bucket, is_bitmap;
+{
+ int fd, page, size;
+ int wsize;
+
+ size = hashp->BSIZE;
+ if ((hashp->fp == -1) && open_temp(hashp))
+ return (-1);
+ fd = hashp->fp;
+
+ if (hashp->LORDER != BYTE_ORDER) {
+ int i;
+ int max;
+
+ if (is_bitmap) {
+ max = hashp->BSIZE >> 2; /* divide by 4 */
+ for (i = 0; i < max; i++)
+ M_32_SWAP(((int *)p)[i]);
+ } else {
+ max = ((u_int16_t *)p)[0] + 2;
+ for (i = 0; i <= max; i++)
+ M_16_SWAP(((u_int16_t *)p)[i]);
+ }
+ }
+ if (is_bucket)
+ page = BUCKET_TO_PAGE(bucket);
+ else
+ page = OADDR_TO_PAGE(bucket);
+ if ((lseek(fd, (off_t)page << hashp->BSHIFT, SEEK_SET) == -1) ||
+ ((wsize = _write(fd, p, size)) == -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.
+ */
+extern int
+__ibitmap(hashp, pnum, nbits, ndx)
+ HTAB *hashp;
+ int pnum, nbits, 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(map)
+ 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(hashp)
+ 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 = bit & ~(BITS_PER_MAP - 1);
+ } 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);
+ 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);
+ 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);
+ 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)
+ 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.
+ */
+extern void
+__free_ovflpage(hashp, obufp)
+ 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(hashp)
+ HTAB *hashp;
+{
+ sigset_t set, oset;
+ static char namestr[] = "_hashXXXXXX";
+
+ /* Block signals; make sure file goes away at process exit. */
+ (void)sigfillset(&set);
+ (void)_sigprocmask(SIG_BLOCK, &set, &oset);
+ if ((hashp->fp = mkstemp(namestr)) != -1) {
+ (void)unlink(namestr);
+ (void)_fcntl(hashp->fp, F_SETFD, 1);
+ }
+ (void)_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(sp, key, val)
+ u_int16_t *sp;
+ const DBT *key, *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(hashp, ndx)
+ 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(addr)
+ 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 0000000..b1d825d
--- /dev/null
+++ b/lib/libc/db/hash/ndbm.c
@@ -0,0 +1,231 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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(file, flags, mode)
+ const char *file;
+ int flags, 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(db)
+ DBM *db;
+{
+ (void)(db->close)(db);
+}
+
+/*
+ * Returns:
+ * DATUM on success
+ * NULL on failure
+ */
+extern datum
+dbm_fetch(db, key)
+ 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(db)
+ 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(db)
+ 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(db, key)
+ 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(db, key, data, flags)
+ DBM *db;
+ datum key, 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(db)
+ DBM *db;
+{
+ HTAB *hp;
+
+ hp = (HTAB *)db->internal;
+ return (hp->error);
+}
+
+extern int
+dbm_clearerr(db)
+ DBM *db;
+{
+ HTAB *hp;
+
+ hp = (HTAB *)db->internal;
+ hp->error = 0;
+ return (0);
+}
+
+extern int
+dbm_dirfno(db)
+ 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 0000000..6ad92484
--- /dev/null
+++ b/lib/libc/db/hash/page.h
@@ -0,0 +1,93 @@
+/*-
+ * 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.
+ * 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.
+ *
+ * @(#)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 0000000..349b029
--- /dev/null
+++ b/lib/libc/db/man/Makefile.inc
@@ -0,0 +1,18 @@
+# from @(#)Makefile.inc 8.1 (Berkeley) 6/4/93
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/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 0000000..5712d18
--- /dev/null
+++ b/lib/libc/db/man/btree.3
@@ -0,0 +1,275 @@
+.\" 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. 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.
+.\"
+.\" @(#)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 0000000..16becc6
--- /dev/null
+++ b/lib/libc/db/man/dbm.3
@@ -0,0 +1,230 @@
+.\" 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$
+.\"
+.\" Note: The date here should be updated whenever a non-trivial
+.\" change is made to the manual page.
+.Dd April 16, 2006
+.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" "int 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 {
+ char *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 but returns 1 if there was no entry with
+.Fa key
+in the database 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 0000000..f35194b
--- /dev/null
+++ b/lib/libc/db/man/dbopen.3
@@ -0,0 +1,550 @@
+.\" 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. 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.
+.\"
+.\" @(#)dbopen.3 8.5 (Berkeley) 1/2/94
+.\" $FreeBSD$
+.\"
+.Dd January 2, 1994
+.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_NONBLOCK ,
+.Dv O_RDONLY , O_RDWR , O_SHLOCK
+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 0000000..6c2e930
--- /dev/null
+++ b/lib/libc/db/man/hash.3
@@ -0,0 +1,200 @@
+.\" 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. 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.
+.\"
+.\" @(#)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;
+ u_int32_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, 256 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 0000000..0c8a12a
--- /dev/null
+++ b/lib/libc/db/man/mpool.3
@@ -0,0 +1,231 @@
+.\" 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. 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.
+.\"
+.\" @(#)mpool.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.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"
+.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
+.Fn mpool_new
+function takes an
+.Ft MPOOL
+pointer and an address 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.
+.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 not currently used.
+.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 0000000..726f74f
--- /dev/null
+++ b/lib/libc/db/man/recno.3
@@ -0,0 +1,232 @@
+.\" 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. 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.
+.\"
+.\" @(#)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 0000000..9fef712
--- /dev/null
+++ b/lib/libc/db/mpool/Makefile.inc
@@ -0,0 +1,6 @@
+# from @(#)Makefile.inc 8.1 (Berkeley) 6/4/93
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/db/mpool
+
+SRCS+= mpool.c
diff --git a/lib/libc/db/mpool/README b/lib/libc/db/mpool/README
new file mode 100644
index 0000000..0f01fbc
--- /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.c b/lib/libc/db/mpool/mpool.c
new file mode 100644
index 0000000..e1c503f
--- /dev/null
+++ b/lib/libc/db/mpool/mpool.c
@@ -0,0 +1,462 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)mpool.c 8.5 (Berkeley) 7/26/94";
+#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.
+ */
+MPOOL *
+mpool_open(key, fd, pagesize, maxcache)
+ void *key;
+ int fd;
+ pgno_t pagesize, 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(mp, pgin, pgout, pgcookie)
+ 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(mp, pgnoaddr)
+ MPOOL *mp;
+ pgno_t *pgnoaddr;
+{
+ 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);
+ *pgnoaddr = bp->pgno = mp->npages++;
+ bp->flags = MPOOL_PINNED;
+
+ head = &mp->hqh[HASHKEY(bp->pgno)];
+ TAILQ_INSERT_HEAD(head, bp, hq);
+ TAILQ_INSERT_TAIL(&mp->lqh, bp, q);
+ return (bp->page);
+}
+
+/*
+ * mpool_get
+ * Get a page.
+ */
+void *
+mpool_get(mp, pgno, flags)
+ MPOOL *mp;
+ pgno_t pgno;
+ u_int flags; /* XXX not used? */
+{
+ struct _hqh *head;
+ BKT *bp;
+ off_t off;
+ int nr;
+
+ /* Check for attempt to retrieve a non-existent page. */
+ if (pgno >= mp->npages) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+#ifdef STATISTICS
+ ++mp->pageget;
+#endif
+
+ /* Check for a page that is cached. */
+ if ((bp = mpool_look(mp, pgno)) != NULL) {
+#ifdef DEBUG
+ if (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. */
+#ifdef STATISTICS
+ ++mp->pageread;
+#endif
+ off = mp->pagesize * pgno;
+ nr = pread(mp->fd, bp->page, mp->pagesize, off);
+ if (nr != mp->pagesize) {
+ if (nr >= 0)
+ errno = EFTYPE;
+ return (NULL);
+ }
+
+ /* Set the page number, pin the page. */
+ bp->pgno = pgno;
+ bp->flags = MPOOL_PINNED;
+
+ /*
+ * 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.
+ */
+int
+mpool_put(mp, page, flags)
+ 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;
+ bp->flags |= flags & MPOOL_DIRTY;
+ return (RET_SUCCESS);
+}
+
+/*
+ * mpool_close
+ * Close the buffer pool.
+ */
+int
+mpool_close(mp)
+ 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(mp)
+ 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(mp)
+ 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
+ return (bp);
+ }
+
+new: if ((bp = (BKT *)malloc(sizeof(BKT) + mp->pagesize)) == NULL)
+ return (NULL);
+#ifdef STATISTICS
+ ++mp->pagealloc;
+#endif
+#if defined(DEBUG) || defined(PURIFY)
+ memset(bp, 0xff, sizeof(BKT) + mp->pagesize);
+#endif
+ bp->page = (char *)bp + sizeof(BKT);
+ ++mp->curcache;
+ return (bp);
+}
+
+/*
+ * mpool_write
+ * Write a page to disk.
+ */
+static int
+mpool_write(mp, bp)
+ 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) != mp->pagesize)
+ return (RET_ERROR);
+
+ bp->flags &= ~MPOOL_DIRTY;
+ return (RET_SUCCESS);
+}
+
+/*
+ * mpool_look
+ * Lookup a page in the cache.
+ */
+static BKT *
+mpool_look(mp, pgno)
+ MPOOL *mp;
+ pgno_t pgno;
+{
+ struct _hqh *head;
+ BKT *bp;
+
+ head = &mp->hqh[HASHKEY(pgno)];
+ TAILQ_FOREACH(bp, head, hq)
+ if (bp->pgno == pgno) {
+#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(mp)
+ MPOOL *mp;
+{
+ BKT *bp;
+ int cnt;
+ char *sep;
+
+ (void)fprintf(stderr, "%u pages in the file\n", mp->npages);
+ (void)fprintf(stderr,
+ "page size %lu, cacheing %u pages of %u 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 0000000..bcd827d
--- /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 0000000..6e08e3f
--- /dev/null
+++ b/lib/libc/db/recno/Makefile.inc
@@ -0,0 +1,7 @@
+# from @(#)Makefile.inc 8.1 (Berkeley) 6/4/93
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/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 0000000..ffa7243
--- /dev/null
+++ b/lib/libc/db/recno/extern.h
@@ -0,0 +1,55 @@
+/*-
+ * 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. 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.
+ *
+ * @(#)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 0000000..326a943
--- /dev/null
+++ b/lib/libc/db/recno/rec_close.c
@@ -0,0 +1,188 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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(dbp)
+ 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(dbp, flags)
+ 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) !=
+ data.size)
+ return (RET_ERROR);
+ status = (dbp->seq)(dbp, &key, &data, R_NEXT);
+ }
+ } else {
+ iov[1].iov_base = (char *)&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) != 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 0000000..9996c2d
--- /dev/null
+++ b/lib/libc/db/recno/rec_delete.c
@@ -0,0 +1,199 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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(dbp, key, flags)
+ 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(t, nrec)
+ 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
+ * index: index on current page to delete
+ *
+ * Returns:
+ * RET_SUCCESS, RET_ERROR.
+ */
+int
+__rec_dleaf(t, h, index)
+ BTREE *t;
+ PAGE *h;
+ u_int32_t index;
+{
+ 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, index);
+ 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[index];
+ for (cnt = &h->linp[index] - (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 0000000..e7ae123
--- /dev/null
+++ b/lib/libc/db/recno/rec_get.c
@@ -0,0 +1,313 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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(dbp, key, data, flags)
+ 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(t, top)
+ 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 = t->bt_rdata.data == NULL ?
+ malloc(t->bt_reclen) :
+ 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(t, top)
+ 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 = t->bt_rdata.data == NULL ?
+ malloc(t->bt_rdata.size) :
+ 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(t, top)
+ 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 = t->bt_rdata.data == NULL ?
+ malloc(t->bt_reclen) :
+ 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(t, top)
+ 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 0000000..5370577
--- /dev/null
+++ b/lib/libc/db/recno/rec_open.c
@@ -0,0 +1,245 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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(fname, flags, mode, openinfo, dflags)
+ const char *fname;
+ int flags, mode, dflags;
+ const RECNOINFO *openinfo;
+{
+ 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, 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(dbp)
+ 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 0000000..10210d5
--- /dev/null
+++ b/lib/libc/db/recno/rec_put.c
@@ -0,0 +1,287 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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(dbp, key, data, flags)
+ 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 =
+ (void *)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(t, nrec, data, flags)
+ BTREE *t;
+ recno_t nrec;
+ const DBT *data;
+ u_int flags;
+{
+ DBT tdata;
+ EPG *e;
+ PAGE *h;
+ indx_t index, 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;
+ *(pgno_t *)db = 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;
+ index = 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:
+ ++index;
+ break;
+ case R_IBEFORE:
+ break;
+ default:
+ if (nrec < t->bt_nrecs &&
+ __rec_dleaf(t, h, index) == 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 (h->upper - h->lower < nbytes + sizeof(indx_t)) {
+ status = __bt_split(t, h, NULL, data, dflags, nbytes, index);
+ if (status == RET_SUCCESS)
+ ++t->bt_nrecs;
+ return (status);
+ }
+
+ if (index < (nxtindex = NEXTINDEX(h)))
+ memmove(h->linp + index + 1, h->linp + index,
+ (nxtindex - index) * sizeof(indx_t));
+ h->lower += sizeof(indx_t);
+
+ h->linp[index] = 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 0000000..8e82917
--- /dev/null
+++ b/lib/libc/db/recno/rec_search.c
@@ -0,0 +1,128 @@
+/*-
+ * 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. 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.
+ */
+
+#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(t, recno, op)
+ BTREE *t;
+ recno_t recno;
+ enum SRCHOP op;
+{
+ indx_t index;
+ 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 (index = 0, top = NEXTINDEX(h);;) {
+ r = GETRINTERNAL(h, index);
+ if (++index == top || total + r->nrecs > recno)
+ break;
+ total += r->nrecs;
+ }
+
+ BT_PUSH(t, pg, index - 1);
+
+ pg = r->pgno;
+ switch (op) {
+ case SDELETE:
+ --GETRINTERNAL(h, (index - 1))->nrecs;
+ mpool_put(t->bt_mp, h, MPOOL_DIRTY);
+ break;
+ case SINSERT:
+ ++GETRINTERNAL(h, (index - 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 0000000..b75d44e
--- /dev/null
+++ b/lib/libc/db/recno/rec_seq.c
@@ -0,0 +1,134 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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(dbp, key, data, flags)
+ const DB *dbp;
+ DBT *key, *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 0000000..1ace3ba
--- /dev/null
+++ b/lib/libc/db/recno/rec_utils.c
@@ -0,0 +1,124 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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(t, e, nrec, key, data)
+ BTREE *t;
+ EPG *e;
+ recno_t nrec;
+ DBT *key, *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 = (void *)(t->bt_rkey.data == NULL ?
+ malloc(sizeof(recno_t)) :
+ 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 = (void *)(t->bt_rdata.data == NULL ?
+ malloc(rl->dsize + 1) :
+ 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 0000000..0318571
--- /dev/null
+++ b/lib/libc/db/recno/recno.h
@@ -0,0 +1,40 @@
+/*-
+ * 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. 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.
+ *
+ * @(#)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 0000000..712ad62
--- /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 0000000..0c0cd13
--- /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 0000000..6308dcb
--- /dev/null
+++ b/lib/libc/db/test/btree.tests/main.c
@@ -0,0 +1,767 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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")) != EOF) {
+ 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 0000000..4d81aee
--- /dev/null
+++ b/lib/libc/db/test/dbtest.c
@@ -0,0 +1,742 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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")) != EOF)
+ 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 0000000..8b1c644
--- /dev/null
+++ b/lib/libc/db/test/hash.tests/driver2.c
@@ -0,0 +1,116 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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 0000000..f28e281
--- /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 0000000..eff661a
--- /dev/null
+++ b/lib/libc/db/test/hash.tests/tcreat3.c
@@ -0,0 +1,107 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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 0000000..0a5eabb
--- /dev/null
+++ b/lib/libc/db/test/hash.tests/tdel.c
@@ -0,0 +1,124 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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 0000000..039457a
--- /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 0000000..90b3783
--- /dev/null
+++ b/lib/libc/db/test/hash.tests/thash4.c
@@ -0,0 +1,134 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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 0000000..75f9fbb
--- /dev/null
+++ b/lib/libc/db/test/hash.tests/tread2.c
@@ -0,0 +1,107 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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 0000000..4e5dc84
--- /dev/null
+++ b/lib/libc/db/test/hash.tests/tseq.c
@@ -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
+ * 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.
+ * 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.
+ */
+
+#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 0000000..18505f5
--- /dev/null
+++ b/lib/libc/db/test/hash.tests/tverify.c
@@ -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
+ * 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.
+ * 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.
+ */
+
+#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 0000000..52b74c3
--- /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 0000000..dce7dc3
--- /dev/null
+++ b/lib/libc/gdtoa/Makefile.inc
@@ -0,0 +1,20 @@
+# $FreeBSD$
+
+# netlib gdtoa sources
+.PATH: ${.CURDIR}/gdtoa
+
+MISRCS+=_hdtoa.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+=${.CURDIR}/gdtoa/Symbol.map
+
+CFLAGS+=-I${.CURDIR}/../../contrib/gdtoa
+
+.for src in ${GDTOASRCS}
+MISRCS+=gdtoa_${src}
+CLEANFILES+=gdtoa_${src}
+gdtoa_${src}:
+ ln -sf ${.CURDIR}/../../contrib/gdtoa/${src} ${.TARGET}
+.endfor
diff --git a/lib/libc/gdtoa/Symbol.map b/lib/libc/gdtoa/Symbol.map
new file mode 100644
index 0000000..62d6c70
--- /dev/null
+++ b/lib/libc/gdtoa/Symbol.map
@@ -0,0 +1,39 @@
+# $FreeBSD$
+
+FBSD_1.0 {
+ # Standard functions from contrib/gdtoa
+ # (dtoa is renamed to __dtoa and not exported)
+ freedtoa;
+ g_Qfmt;
+ g_ddfmt;
+ g_dfmt;
+ g_ffmt;
+ g_xLfmt;
+ g_xfmt;
+ gdtoa;
+ strtoIQ;
+ strtoId;
+ strtoIdd;
+ strtoIf;
+ strtoIx;
+ strtoIxL;
+ strtod;
+ strtodI;
+ strtodg;
+ strtof;
+ strtopQ;
+ strtopd;
+ strtopdd;
+ strtopf;
+ strtopx;
+ strtopxL;
+ strtorQ;
+ strtord;
+ strtordd;
+ strtorf;
+ strtorx;
+ strtorxL;
+
+ # FreeBSD additions
+ strtold;
+};
diff --git a/lib/libc/gdtoa/_hdtoa.c b/lib/libc/gdtoa/_hdtoa.c
new file mode 100644
index 0000000..ff7ed55
--- /dev/null
+++ b/lib/libc/gdtoa/_hdtoa.c
@@ -0,0 +1,319 @@
+/*-
+ * Copyright (c) 2004, 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 <float.h>
+#include <limits.h>
+#include <math.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 + ((DBL_MANT_DIG - 1) % 4))
+#define LDBL_ADJ (LDBL_MAX_EXP - 2 + ((LDBL_MANT_DIG - 1) % 4))
+
+/*
+ * Round up the given digit string. If the digit string is fff...f,
+ * this procedure sets it to 100...0 and returns 1 to indicate that
+ * the exponent needs to be bumped. Otherwise, 0 is returned.
+ */
+static int
+roundup(char *s0, int ndigits)
+{
+ char *s;
+
+ for (s = s0 + ndigits - 1; *s == 0xf; s--) {
+ if (s == s0) {
+ *s = 1;
+ return (1);
+ }
+ ++*s;
+ }
+ ++*s;
+ return (0);
+}
+
+/*
+ * Round the given digit string to ndigits digits according to the
+ * current rounding mode. Note that this could produce a string whose
+ * value is not representable in the corresponding floating-point
+ * type. The exponent pointed to by decpt is adjusted if necessary.
+ */
+static void
+dorounding(char *s0, int ndigits, int sign, int *decpt)
+{
+ int adjust = 0; /* do we need to adjust the exponent? */
+
+ switch (FLT_ROUNDS) {
+ case 0: /* toward zero */
+ default: /* implementation-defined */
+ break;
+ case 1: /* to nearest, halfway rounds to even */
+ if ((s0[ndigits] > 8) ||
+ (s0[ndigits] == 8 && s0[ndigits - 1] & 1))
+ adjust = roundup(s0, ndigits);
+ break;
+ case 2: /* toward +inf */
+ if (sign == 0)
+ adjust = roundup(s0, ndigits);
+ break;
+ case 3: /* toward -inf */
+ if (sign != 0)
+ adjust = roundup(s0, ndigits);
+ break;
+ }
+
+ if (adjust)
+ *decpt += 4;
+}
+
+/*
+ * 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 chooses the
+ * first digit so that subsequent digits are aligned on nibble
+ * boundaries (before rounding).
+ *
+ * Inputs: d, xdigs, ndigits
+ * Outputs: decpt, sign, rve
+ */
+char *
+__hdtoa(double d, const char *xdigs, int ndigits, int *decpt, int *sign,
+ char **rve)
+{
+ static const int sigfigs = (DBL_MANT_DIG + 3) / 4;
+ union IEEEd2bits u;
+ char *s, *s0;
+ int bufsize;
+
+ 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));
+ case FP_NAN:
+ *decpt = INT_MAX;
+ return (nrv_alloc(NANSTR, rve, sizeof(NANSTR) - 1));
+ default:
+ abort();
+ }
+
+ /* FP_NORMAL or FP_SUBNORMAL */
+
+ if (ndigits == 0) /* dtoa() compatibility */
+ ndigits = 1;
+
+ /*
+ * For simplicity, we generate all the digits even if the
+ * caller has requested fewer.
+ */
+ bufsize = (sigfigs > ndigits) ? sigfigs : ndigits;
+ s0 = rv_alloc(bufsize);
+
+ /*
+ * We work from right to left, first adding any requested zero
+ * padding, then the least significant portion of the
+ * mantissa, followed by the most significant. The buffer is
+ * filled with the byte values 0x0 through 0xf, which are
+ * converted to xdigs[0x0] through xdigs[0xf] after the
+ * rounding phase.
+ */
+ for (s = s0 + bufsize - 1; s > s0 + sigfigs - 1; s--)
+ *s = 0;
+ for (; s > s0 + sigfigs - (DBL_MANL_SIZE / 4) - 1 && s > s0; s--) {
+ *s = u.bits.manl & 0xf;
+ u.bits.manl >>= 4;
+ }
+ for (; s > s0; s--) {
+ *s = u.bits.manh & 0xf;
+ u.bits.manh >>= 4;
+ }
+
+ /*
+ * At this point, we have snarfed all the bits in the
+ * mantissa, with the possible exception of the highest-order
+ * (partial) nibble, which is dealt with by the next
+ * statement. We also tack on the implicit normalization bit.
+ */
+ *s = u.bits.manh | (1U << ((DBL_MANT_DIG - 1) % 4));
+
+ /* If ndigits < 0, we are expected to auto-size the precision. */
+ if (ndigits < 0) {
+ for (ndigits = sigfigs; s0[ndigits - 1] == 0; ndigits--)
+ ;
+ }
+
+ if (sigfigs > ndigits && s0[ndigits] != 0)
+ dorounding(s0, ndigits, u.bits.sign, decpt);
+
+ s = s0 + ndigits;
+ if (rve != NULL)
+ *rve = s;
+ *s-- = '\0';
+ for (; s >= s0; s--)
+ *s = xdigs[(unsigned int)*s];
+
+ return (s0);
+}
+
+#if (LDBL_MANT_DIG > DBL_MANT_DIG)
+
+/*
+ * This is the long double version of __hdtoa().
+ */
+char *
+__hldtoa(long double e, const char *xdigs, int ndigits, int *decpt, int *sign,
+ char **rve)
+{
+ static const int sigfigs = (LDBL_MANT_DIG + 3) / 4;
+ union IEEEl2bits u;
+ char *s, *s0;
+ int bufsize;
+
+ 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:
+ u.e *= 0x1p514L;
+ *decpt = u.bits.exp - (514 + LDBL_ADJ);
+ break;
+ case FP_INFINITE:
+ *decpt = INT_MAX;
+ return (nrv_alloc(INFSTR, rve, sizeof(INFSTR) - 1));
+ case FP_NAN:
+ *decpt = INT_MAX;
+ return (nrv_alloc(NANSTR, rve, sizeof(NANSTR) - 1));
+ default:
+ abort();
+ }
+
+ /* FP_NORMAL or FP_SUBNORMAL */
+
+ if (ndigits == 0) /* dtoa() compatibility */
+ ndigits = 1;
+
+ /*
+ * For simplicity, we generate all the digits even if the
+ * caller has requested fewer.
+ */
+ bufsize = (sigfigs > ndigits) ? sigfigs : ndigits;
+ s0 = rv_alloc(bufsize);
+
+ /*
+ * We work from right to left, first adding any requested zero
+ * padding, then the least significant portion of the
+ * mantissa, followed by the most significant. The buffer is
+ * filled with the byte values 0x0 through 0xf, which are
+ * converted to xdigs[0x0] through xdigs[0xf] after the
+ * rounding phase.
+ */
+ for (s = s0 + bufsize - 1; s > s0 + sigfigs - 1; s--)
+ *s = 0;
+ for (; s > s0 + sigfigs - (LDBL_MANL_SIZE / 4) - 1 && s > s0; s--) {
+ *s = u.bits.manl & 0xf;
+ u.bits.manl >>= 4;
+ }
+ for (; s > s0; s--) {
+ *s = u.bits.manh & 0xf;
+ u.bits.manh >>= 4;
+ }
+
+ /*
+ * At this point, we have snarfed all the bits in the
+ * mantissa, with the possible exception of the highest-order
+ * (partial) nibble, which is dealt with by the next
+ * statement. We also tack on the implicit normalization bit.
+ */
+ *s = u.bits.manh | (1U << ((LDBL_MANT_DIG - 1) % 4));
+
+ /* If ndigits < 0, we are expected to auto-size the precision. */
+ if (ndigits < 0) {
+ for (ndigits = sigfigs; s0[ndigits - 1] == 0; ndigits--)
+ ;
+ }
+
+ if (sigfigs > ndigits && s0[ndigits] != 0)
+ dorounding(s0, ndigits, u.bits.sign, decpt);
+
+ s = s0 + ndigits;
+ if (rve != NULL)
+ *rve = s;
+ *s-- = '\0';
+ for (; s >= s0; s--)
+ *s = xdigs[(unsigned int)*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 0000000..750a252
--- /dev/null
+++ b/lib/libc/gdtoa/_ldtoa.c
@@ -0,0 +1,100 @@
+/*-
+ * 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 "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)
+{
+ static FPI fpi = {
+ LDBL_MANT_DIG, /* nbits */
+ LDBL_MIN_EXP - LDBL_MANT_DIG, /* emin */
+ LDBL_MAX_EXP - LDBL_MANT_DIG, /* emax */
+ FPI_Round_near, /* 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];
+
+ u.e = *ld;
+ *sign = 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;
+#ifdef LDBL_IMPLICIT_NBIT
+ be++;
+#endif
+ break;
+ case FP_INFINITE:
+ kind = STRTOG_Infinite;
+ break;
+ case FP_NAN:
+ kind = STRTOG_NaN;
+ break;
+ default:
+ abort();
+ }
+
+ ret = gdtoa(&fpi, be, (ULong *)bits, &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 0000000..39e491a
--- /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 0000000..e5cf6e6
--- /dev/null
+++ b/lib/libc/gdtoa/machdep_ldisQ.c
@@ -0,0 +1,45 @@
+/*-
+ * 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.
+ */
+
+/*
+ * 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 "gdtoaimp.h"
+
+long double
+strtold(const char * __restrict s, char ** __restrict sp)
+{
+ long double result;
+
+ strtopQ(s, sp, &result);
+ return result;
+}
diff --git a/lib/libc/gdtoa/machdep_ldisd.c b/lib/libc/gdtoa/machdep_ldisd.c
new file mode 100644
index 0000000..e2dbb60
--- /dev/null
+++ b/lib/libc/gdtoa/machdep_ldisd.c
@@ -0,0 +1,43 @@
+/*-
+ * 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.
+ */
+
+/*
+ * 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"
+
+long double
+strtold(const char * __restrict s, char ** __restrict sp)
+{
+
+ return strtod(s, sp);
+}
diff --git a/lib/libc/gdtoa/machdep_ldisx.c b/lib/libc/gdtoa/machdep_ldisx.c
new file mode 100644
index 0000000..0b61de6
--- /dev/null
+++ b/lib/libc/gdtoa/machdep_ldisx.c
@@ -0,0 +1,45 @@
+/*-
+ * 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.
+ */
+
+/*
+ * 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 "gdtoaimp.h"
+
+long double
+strtold(const char * __restrict s, char ** __restrict sp)
+{
+ long double result;
+
+ strtopx(s, sp, &result);
+ return result;
+}
diff --git a/lib/libc/gen/Makefile.inc b/lib/libc/gen/Makefile.inc
new file mode 100644
index 0000000..af92c63
--- /dev/null
+++ b/lib/libc/gen/Makefile.inc
@@ -0,0 +1,154 @@
+# @(#)Makefile.inc 8.6 (Berkeley) 5/4/95
+# $FreeBSD$
+
+# machine-independent gen sources
+.PATH: ${.CURDIR}/${MACHINE_ARCH}/gen ${.CURDIR}/gen
+
+SRCS+= __xuname.c _pthread_stubs.c _rand48.c _spinlock_stub.c _thread_init.c \
+ alarm.c arc4random.c assert.c basename.c check_utility_compat.c \
+ clock.c closedir.c confstr.c \
+ crypt.c ctermid.c daemon.c devname.c dirname.c disklabel.c \
+ dlfcn.c dlfunc.c drand48.c erand48.c err.c errlst.c errno.c \
+ exec.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 \
+ getobjformat.c getosreldate.c getpagesize.c \
+ getpeereid.c getprogname.c getpwent.c getttyent.c \
+ getusershell.c getvfsbyname.c glob.c \
+ initgroups.c isatty.c isinf.c isnan.c jrand48.c lcong48.c \
+ lockf.c lrand48.c mrand48.c nftw.c nice.c \
+ nlist.c nrand48.c opendir.c \
+ pause.c pmadvise.c popen.c posixshm.c pselect.c \
+ psignal.c pw_scan.c pwcache.c \
+ raise.c readdir.c readpassphrase.c rewinddir.c \
+ scandir.c seed48.c seekdir.c sem.c semctl.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 unvis.c \
+ usleep.c utime.c valloc.c vis.c wait.c wait3.c waitpid.c \
+ wordexp.c
+
+SYM_MAPS+=${.CURDIR}/gen/Symbol.map
+
+# machine-dependent gen sources
+.if exists(${.CURDIR}/${MACHINE_ARCH}/gen/Makefile.inc)
+.include "${.CURDIR}/${MACHINE_ARCH}/gen/Makefile.inc"
+.endif
+
+MAN+= alarm.3 arc4random.3 \
+ basename.3 check_utility_compat.3 clock.3 \
+ confstr.3 ctermid.3 daemon.3 devname.3 directory.3 dirname.3 \
+ dladdr.3 dlinfo.3 dllockinit.3 dlopen.3 \
+ err.3 exec.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 getobjformat.3 getosreldate.3 \
+ getpagesize.3 getpass.3 getpeereid.3 getprogname.3 getpwent.3 \
+ getttyent.3 getusershell.3 getvfsbyname.3 \
+ glob.3 initgroups.3 isgreater.3 ldexp.3 lockf.3 makecontext.3 \
+ modf.3 msgctl.3 msgget.3 msgrcv.3 msgsnd.3 \
+ nice.3 nlist.3 pause.3 popen.3 pselect.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_wait.3 \
+ setjmp.3 setmode.3 setproctitle.3 shm_open.3 \
+ siginterrupt.3 signal.3 sigsetops.3 sleep.3 \
+ statvfs.3 stringlist.3 \
+ strtofflags.3 sysconf.3 sysctl.3 syslog.3 tcgetpgrp.3 \
+ tcsendbreak.3 tcsetattr.3 tcsetpgrp.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
+MLINKS+=ctermid.3 ctermid_r.3
+MLINKS+=devname.3 devname_r.3
+MLINKS+=directory.3 closedir.3 directory.3 dirfd.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 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
+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 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 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+=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+=popen.3 pclose.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+=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+=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+=shm_open.3 shm_unlink.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 cfsetispeed.3 \
+ tcsetattr.3 cfsetospeed.3 tcsetattr.3 cfsetspeed.3 \
+ tcsetattr.3 tcgetattr.3
+MLINKS+=ttyname.3 isatty.3 ttyname.3 ttyname_r.3 ttyname.3 ttyslot.3
+MLINKS+=tzset.3 tzsetwall.3
+MLINKS+=unvis.3 strunvis.3 unvis.3 strunvisx.3
+MLINKS+=vis.3 strvis.3 vis.3 strvisx.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 0000000..5850390
--- /dev/null
+++ b/lib/libc/gen/Symbol.map
@@ -0,0 +1,446 @@
+# $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;
+ basename;
+ check_utility_compat;
+ clock;
+ closedir;
+ confstr;
+ encrypt;
+ des_setkey;
+ des_cipher;
+ setkey;
+ ctermid;
+ ctermid_r;
+ daemon;
+ devname;
+ devname_r;
+ dirname;
+ getdiskbyname;
+ dladdr;
+ dlclose;
+ dlerror;
+ dlfunc;
+ dllockinit;
+ dlopen;
+ dlsym;
+ dlvsym;
+ dlinfo;
+ 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;
+ fts_open;
+ fts_close;
+ fts_read;
+ fts_set;
+ fts_children;
+ fts_get_clientptr;
+ fts_get_stream;
+ fts_set_clientptr;
+ 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;
+ getobjformat;
+ 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;
+ mrand48;
+ nftw;
+ nice;
+ nlist;
+ nrand48;
+ opendir;
+ pause;
+ posix_madvise;
+ popen;
+ pclose;
+ shm_open;
+ shm_unlink;
+ pselect;
+ psignal;
+ raise;
+ readdir;
+ readdir_r;
+ readpassphrase;
+ getpass;
+ rewinddir;
+ scandir;
+ alphasort;
+ seed48;
+ seekdir;
+ user_from_uid;
+ group_from_gid;
+ sem_init;
+ sem_destroy;
+ sem_open;
+ sem_close;
+ sem_unlink;
+ sem_wait;
+ sem_trywait;
+ sem_timedwait;
+ sem_post;
+ sem_getvalue;
+ semctl;
+ 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;
+ ttyslot;
+ ttyname_r;
+ ttyname;
+ timezone;
+ times;
+ time;
+ telldir;
+ tcgetattr;
+ tcsetattr;
+ tcsetpgrp;
+ tcgetpgrp;
+ cfgetospeed;
+ cfgetispeed;
+ cfsetospeed;
+ cfsetispeed;
+ cfsetspeed;
+ cfmakeraw;
+ tcsendbreak;
+ _init_tls;
+ tcdrain;
+ tcflush;
+ tcflow;
+ ualarm;
+ ulimit;
+ uname;
+ unvis;
+ strunvis;
+ strunvisx;
+ usleep;
+ utime;
+ valloc;
+ vis;
+ strvis;
+ strvisx;
+ wait;
+ wait3;
+ waitpid;
+ wordexp;
+ wordfree;
+};
+
+FBSDprivate {
+ # 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_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;
+ _spinlock;
+ _spinlock_debug;
+ _spinunlock;
+ _rtld_error; # for private use
+ _rtld_thread_init; # for private use
+ _err;
+ _warn;
+ __fmtcheck;
+ # __pw_match_entry;
+ # __pw_parse_entry;
+ __fdnlist; # used by libkvm
+ # __aout_fdnlist;
+ # __elf_is_okay__;
+ # __elf_fdnlist;
+ __opendir2;
+ __pause;
+ _pause;
+ __pselect;
+ __pw_scan; # Used by (at least) libutil
+ __raise;
+ _raise;
+ __sem_init;
+ __sem_destroy;
+ __sem_open;
+ __sem_close;
+ __sem_unlink;
+ __sem_wait;
+ __sem_trywait;
+ __sem_timedwait;
+ __sem_post;
+ __sem_getvalue;
+ __sleep;
+ _sleep;
+ _rtld_allocate_tls;
+ _rtld_free_tls;
+ __libc_allocate_tls;
+ __libc_free_tls;
+ ___tls_get_addr; # x86 only
+ ___libc_tls_get_addr; # x86 only
+ __libc_tls_get_addr;
+ __tls_get_addr;
+ __tcdrain;
+ _tcdrain;
+ __usleep;
+ _usleep;
+ __wait;
+ _wait;
+ __waitpid;
+ _waitpid;
+};
diff --git a/lib/libc/gen/__xuname.c b/lib/libc/gen/__xuname.c
new file mode 100644
index 0000000..ee96ad6
--- /dev/null
+++ b/lib/libc/gen/__xuname.c
@@ -0,0 +1,142 @@
+/*-
+ * 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.
+ */
+
+#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;
+ int oerrno;
+ struct xutsname {
+ char sysname[namesize]; /* Name of this OS. */
+ char nodename[namesize]; /* Name of this network node. */
+ char release[namesize]; /* Release level. */
+ char version[namesize]; /* Version level. */
+ char machine[namesize]; /* Hardware type. */
+ } *name;
+
+ name = (struct xutsname *)namebuf;
+ rval = 0;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_OSTYPE;
+ len = sizeof(name->sysname);
+ oerrno = errno;
+ if (sysctl(mib, 2, &name->sysname, &len, NULL, 0) == -1) {
+ if(errno == ENOMEM)
+ errno = oerrno;
+ else
+ rval = -1;
+ }
+ name->sysname[sizeof(name->sysname) - 1] = '\0';
+ if ((p = getenv("UNAME_s")))
+ strlcpy(name->sysname, p, sizeof(name->sysname));
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_HOSTNAME;
+ len = sizeof(name->nodename);
+ oerrno = errno;
+ if (sysctl(mib, 2, &name->nodename, &len, NULL, 0) == -1) {
+ if(errno == ENOMEM)
+ errno = oerrno;
+ else
+ rval = -1;
+ }
+ name->nodename[sizeof(name->nodename) - 1] = '\0';
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_OSRELEASE;
+ len = sizeof(name->release);
+ oerrno = errno;
+ if (sysctl(mib, 2, &name->release, &len, NULL, 0) == -1) {
+ if(errno == ENOMEM)
+ errno = oerrno;
+ else
+ rval = -1;
+ }
+ name->release[sizeof(name->release) - 1] = '\0';
+ if ((p = getenv("UNAME_r")))
+ strlcpy(name->release, p, sizeof(name->release));
+
+ /* The version may have newlines in it, turn them into spaces. */
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_VERSION;
+ len = sizeof(name->version);
+ oerrno = errno;
+ if (sysctl(mib, 2, &name->version, &len, NULL, 0) == -1) {
+ if (errno == ENOMEM)
+ errno = oerrno;
+ else
+ rval = -1;
+ }
+ name->version[sizeof(name->version) - 1] = '\0';
+ for (p = name->version; len--; ++p) {
+ if (*p == '\n' || *p == '\t') {
+ if (len > 1)
+ *p = ' ';
+ else
+ *p = '\0';
+ }
+ }
+ if ((p = getenv("UNAME_v")))
+ strlcpy(name->version, p, sizeof(name->version));
+
+ mib[0] = CTL_HW;
+ mib[1] = HW_MACHINE;
+ len = sizeof(name->machine);
+ oerrno = errno;
+ if (sysctl(mib, 2, &name->machine, &len, NULL, 0) == -1) {
+ if (errno == ENOMEM)
+ errno = oerrno;
+ else
+ rval = -1;
+ }
+ name->machine[sizeof(name->machine) - 1] = '\0';
+ if ((p = getenv("UNAME_m")))
+ strlcpy(name->machine, p, sizeof(name->machine));
+ return (rval);
+}
diff --git a/lib/libc/gen/_pthread_stubs.c b/lib/libc/gen/_pthread_stubs.c
new file mode 100644
index 0000000..a3e55b0
--- /dev/null
+++ b/lib/libc/gen/_pthread_stubs.c
@@ -0,0 +1,303 @@
+/*
+ * 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 "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_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_zero)}, /* 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_zero)}, /* 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 */
+};
+
+/*
+ * 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_mutexattr_destroy, PJT_MUTEXATTR_DESTROY, int, void *)
+STUB_FUNC1(pthread_mutexattr_init, PJT_MUTEXATTR_INIT, int, void *)
+STUB_FUNC1(pthread_mutexattr_settype, PJT_MUTEXATTR_SETTYPE, int, void *)
+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)
+
+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_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 0000000..279bbc3
--- /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 0000000..9ef42e9
--- /dev/null
+++ b/lib/libc/gen/_spinlock_stub.c
@@ -0,0 +1,82 @@
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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"
+
+/*
+ * Declare weak definitions in case the application is not linked
+ * with libpthread.
+ */
+__weak_reference(_atomic_lock_stub, _atomic_lock);
+__weak_reference(_spinlock_stub, _spinlock);
+__weak_reference(_spinunlock_stub, _spinunlock);
+__weak_reference(_spinlock_debug_stub, _spinlock_debug);
+
+
+/*
+ * This function is a stub for the _atomic_lock function in libpthread.
+ */
+long
+_atomic_lock_stub(volatile long *lck)
+{
+ return (0L);
+}
+
+
+/*
+ * This function is a stub for the spinlock function in libpthread.
+ */
+void
+_spinlock_stub(spinlock_t *lck)
+{
+}
+
+/*
+ * This function is a stub for the spinunlock function in libpthread.
+ */
+void
+_spinunlock_stub(spinlock_t *lck)
+{
+}
+
+/*
+ * This function is a stub for the debug spinlock function in libpthread.
+ */
+void
+_spinlock_debug_stub(spinlock_t *lck, char *fname, int lineno)
+{
+}
diff --git a/lib/libc/gen/_thread_init.c b/lib/libc/gen/_thread_init.c
new file mode 100644
index 0000000..acaf65c
--- /dev/null
+++ b/lib/libc/gen/_thread_init.c
@@ -0,0 +1,41 @@
+/*
+ * 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>
+
+__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 0000000..b85b879
--- /dev/null
+++ b/lib/libc/gen/alarm.3
@@ -0,0 +1,98 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)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 sigpause 2 ,
+.Xr sigvec 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 0000000..d3920cc
--- /dev/null
+++ b/lib/libc/gen/alarm.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.
+ * 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.
+ */
+
+#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(secs)
+ 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 0000000..27c6fd1
--- /dev/null
+++ b/lib/libc/gen/arc4random.3
@@ -0,0 +1,107 @@
+.\" $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_stir ,
+.Nm arc4random_addrandom
+.Nd arc4 random number generator
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft u_int32_t
+.Fn arc4random "void"
+.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
+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 ,
+since
+.Fn arc4random
+automatically initializes itself.
+.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 0000000..e2448d5
--- /dev/null
+++ b/lib/libc/gen/arc4random.c
@@ -0,0 +1,235 @@
+/*
+ * Arc4 random number generator for OpenBSD.
+ * Copyright 1996 David Mazieres <dm@lcs.mit.edu>.
+ *
+ * Modification and redistribution in source and binary forms is
+ * permitted provided that due credit is given to the author and the
+ * OpenBSD project (for instance by leaving this copyright notice
+ * intact).
+ */
+
+/*
+ * 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.
+ *
+ * Here the stream cipher has been modified always to include the time
+ * when initializing the state. That makes it impossible to
+ * regenerate the same random sequence twice, so this can't be used
+ * for encryption, but will generate good random numbers.
+ *
+ * RC4 is a registered trademark of RSA Laboratories.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/time.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <pthread.h>
+
+#include "libc_private.h"
+#include "un-namespace.h"
+
+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/urandom"
+#define THREAD_LOCK() \
+ do { \
+ if (__isthreaded) \
+ _pthread_mutex_lock(&arc4random_mtx); \
+ } while (0)
+
+#define THREAD_UNLOCK() \
+ do { \
+ if (__isthreaded) \
+ _pthread_mutex_unlock(&arc4random_mtx); \
+ } while (0)
+
+static struct arc4_stream rs;
+static int rs_initialized;
+static int rs_stired;
+
+static inline u_int8_t arc4_getbyte(struct arc4_stream *);
+static void arc4_stir(struct arc4_stream *);
+
+static inline void
+arc4_init(as)
+ struct arc4_stream *as;
+{
+ int n;
+
+ for (n = 0; n < 256; n++)
+ as->s[n] = n;
+ as->i = 0;
+ as->j = 0;
+}
+
+static inline void
+arc4_addrandom(as, dat, datlen)
+ struct arc4_stream *as;
+ u_char *dat;
+ int datlen;
+{
+ int n;
+ u_int8_t si;
+
+ as->i--;
+ for (n = 0; n < 256; n++) {
+ as->i = (as->i + 1);
+ si = as->s[as->i];
+ as->j = (as->j + si + dat[n % datlen]);
+ as->s[as->i] = as->s[as->j];
+ as->s[as->j] = si;
+ }
+}
+
+static void
+arc4_stir(as)
+ struct arc4_stream *as;
+{
+ int fd, n;
+ struct {
+ struct timeval tv;
+ pid_t pid;
+ u_int8_t rnd[128 - sizeof(struct timeval) - sizeof(pid_t)];
+ } rdat;
+
+ gettimeofday(&rdat.tv, NULL);
+ rdat.pid = getpid();
+ fd = _open(RANDOMDEV, O_RDONLY, 0);
+ if (fd >= 0) {
+ (void) _read(fd, rdat.rnd, sizeof(rdat.rnd));
+ _close(fd);
+ }
+ /* fd < 0? Ah, what the heck. We'll just take whatever was on the
+ * stack... */
+
+ arc4_addrandom(as, (void *) &rdat, sizeof(rdat));
+
+ /*
+ * Throw away the first N bytes of output, as suggested in the
+ * paper "Weaknesses in the Key Scheduling Algorithm of RC4"
+ * by Fluher, Mantin, and Shamir. N=1024 is based on
+ * suggestions in the paper "(Not So) Random Shuffles of RC4"
+ * by Ilya Mironov.
+ */
+ for (n = 0; n < 1024; n++)
+ arc4_getbyte(as);
+}
+
+static inline u_int8_t
+arc4_getbyte(as)
+ struct arc4_stream *as;
+{
+ u_int8_t si, sj;
+
+ as->i = (as->i + 1);
+ si = as->s[as->i];
+ as->j = (as->j + si);
+ sj = as->s[as->j];
+ as->s[as->i] = sj;
+ as->s[as->j] = si;
+
+ return (as->s[(si + sj) & 0xff]);
+}
+
+static inline u_int32_t
+arc4_getword(as)
+ struct arc4_stream *as;
+{
+ u_int32_t val;
+
+ val = arc4_getbyte(as) << 24;
+ val |= arc4_getbyte(as) << 16;
+ val |= arc4_getbyte(as) << 8;
+ val |= arc4_getbyte(as);
+
+ return (val);
+}
+
+static void
+arc4_check_init(void)
+{
+ if (!rs_initialized) {
+ arc4_init(&rs);
+ rs_initialized = 1;
+ }
+}
+
+static void
+arc4_check_stir(void)
+{
+ if (!rs_stired) {
+ arc4_stir(&rs);
+ rs_stired = 1;
+ }
+}
+
+void
+arc4random_stir()
+{
+ THREAD_LOCK();
+ arc4_check_init();
+ arc4_stir(&rs);
+ THREAD_UNLOCK();
+}
+
+void
+arc4random_addrandom(dat, datlen)
+ u_char *dat;
+ int datlen;
+{
+ THREAD_LOCK();
+ arc4_check_init();
+ arc4_check_stir();
+ arc4_addrandom(&rs, dat, datlen);
+ THREAD_UNLOCK();
+}
+
+u_int32_t
+arc4random()
+{
+ u_int32_t rnd;
+
+ THREAD_LOCK();
+ arc4_check_init();
+ arc4_check_stir();
+ rnd = arc4_getword(&rs);
+ THREAD_UNLOCK();
+
+ return (rnd);
+}
+
+#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 0000000..117f0d8
--- /dev/null
+++ b/lib/libc/gen/assert.c
@@ -0,0 +1,60 @@
+/*-
+ * 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. 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.
+ */
+
+#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(func, file, line, failedexpr)
+ const char *func, *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/basename.3 b/lib/libc/gen/basename.3
new file mode 100644
index 0000000..6f03b4a
--- /dev/null
+++ b/lib/libc/gen/basename.3
@@ -0,0 +1,103 @@
+.\"
+.\" 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: basename.3,v 1.12 2000/04/18 03:01:25 aaron Exp $
+.\" $FreeBSD$
+.\"
+.Dd August 17, 1997
+.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 "const 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.
+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.
+.Sh RETURN VALUES
+On successful completion,
+.Fn basename
+returns a pointer to the last component of
+.Fa path .
+.Pp
+If
+.Fn basename
+fails, a null pointer is returned and the global variable
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+The following error codes may be set in
+.Va errno :
+.Bl -tag -width Er
+.It Bq Er ENAMETOOLONG
+The path component to be returned was larger than
+.Dv MAXPATHLEN .
+.El
+.Sh WARNINGS
+The
+.Fn basename
+function
+returns a pointer to internal static storage space that will be overwritten
+by subsequent calls.
+.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 .
+.Sh AUTHORS
+.An "Todd C. Miller" Aq Todd.Miller@courtesan.com
diff --git a/lib/libc/gen/basename.c b/lib/libc/gen/basename.c
new file mode 100644
index 0000000..9552ab3
--- /dev/null
+++ b/lib/libc/gen/basename.c
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+
+#if 0
+#ifndef lint
+static char rcsid[] = "$OpenBSD: basename.c,v 1.4 1999/05/30 17:10:30 espie Exp $";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <libgen.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/param.h>
+
+char *
+basename(path)
+ const char *path;
+{
+ static char *bname = NULL;
+ const char *endp, *startp;
+
+ if (bname == NULL) {
+ bname = (char *)malloc(MAXPATHLEN);
+ if (bname == NULL)
+ return(NULL);
+ }
+
+ /* Empty or NULL string gets treated as "." */
+ if (path == NULL || *path == '\0') {
+ (void)strcpy(bname, ".");
+ return(bname);
+ }
+
+ /* Strip trailing slashes */
+ endp = path + strlen(path) - 1;
+ while (endp > path && *endp == '/')
+ endp--;
+
+ /* All slashes becomes "/" */
+ if (endp == path && *endp == '/') {
+ (void)strcpy(bname, "/");
+ return(bname);
+ }
+
+ /* Find the start of the base */
+ startp = endp;
+ while (startp > path && *(startp - 1) != '/')
+ startp--;
+
+ if (endp - startp + 2 > MAXPATHLEN) {
+ errno = ENAMETOOLONG;
+ return(NULL);
+ }
+ (void)strncpy(bname, startp, endp - startp + 1);
+ bname[endp - startp + 1] = '\0';
+ return(bname);
+}
diff --git a/lib/libc/gen/check_utility_compat.3 b/lib/libc/gen/check_utility_compat.3
new file mode 100644
index 0000000..7a96bac
--- /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
+.Os
+.Dt CHECK_UTILITY_COMPAT 3
+.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 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 0000000..0ccdec1
--- /dev/null
+++ b/lib/libc/gen/check_utility_compat.c
@@ -0,0 +1,75 @@
+/*
+ * 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 <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifndef LINE_MAX
+#define LINE_MAX _POSIX2_LINE_MAX
+#endif
+
+#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[LINE_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)) < 0)
+ return 0;
+ if (len > sizeof buf)
+ len = sizeof buf;
+ 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 0000000..2418762
--- /dev/null
+++ b/lib/libc/gen/clock.3
@@ -0,0 +1,80 @@
+.\" 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. 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.
+.\"
+.\" @(#)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 0000000..91d20db
--- /dev/null
+++ b/lib/libc/gen/clock.c
@@ -0,0 +1,59 @@
+/*
+ * 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. 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.
+ */
+
+#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()
+{
+ 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/closedir.c b/lib/libc/gen/closedir.c
new file mode 100644
index 0000000..11838d1
--- /dev/null
+++ b/lib/libc/gen/closedir.c
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ * 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.
+ */
+
+#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 "telldir.h"
+
+/*
+ * close a directory.
+ */
+int
+closedir(dirp)
+ DIR *dirp;
+{
+ int fd;
+
+ if (__isthreaded)
+ _pthread_mutex_lock((pthread_mutex_t *)&dirp->dd_lock);
+ _seekdir(dirp, dirp->dd_rewind); /* free seekdir storage */
+ 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((pthread_mutex_t *)&dirp->dd_lock);
+ _pthread_mutex_destroy((pthread_mutex_t *)&dirp->dd_lock);
+ }
+ free((void *)dirp);
+ return(_close(fd));
+}
diff --git a/lib/libc/gen/confstr.3 b/lib/libc/gen/confstr.3
new file mode 100644
index 0000000..6344059
--- /dev/null
+++ b/lib/libc/gen/confstr.3
@@ -0,0 +1,135 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)confstr.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 18, 2001
+.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:
+.Pp
+.Bl -tag -width 6n
+.Pp
+.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, \-1 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 0000000..966c3fe
--- /dev/null
+++ b/lib/libc/gen/confstr.c
@@ -0,0 +1,125 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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 0000000..5fee537
--- /dev/null
+++ b/lib/libc/gen/crypt.c
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ * 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.
+ */
+
+#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.
+ */
+
+__warn_references(des_setkey,
+ "WARNING! des_setkey(3) not present in the system!");
+
+/* ARGSUSED */
+int
+des_setkey(const char *key __unused)
+{
+ fprintf(stderr, "WARNING! des_setkey(3) not present in the system!\n");
+ return (0);
+}
+
+__warn_references(des_cipher,
+ "WARNING! des_cipher(3) not present in the system!");
+
+/* ARGSUSED */
+int
+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);
+}
+
+__warn_references(setkey,
+ "WARNING! setkey(3) not present in the system!");
+
+/* ARGSUSED */
+int
+setkey(const char *key __unused)
+{
+ fprintf(stderr, "WARNING! setkey(3) not present in the system!\n");
+ return (0);
+}
+
+__warn_references(encrypt,
+ "WARNING! encrypt(3) not present in the system!");
+
+/* ARGSUSED */
+int
+encrypt(char *block __unused, int flag __unused)
+{
+ fprintf(stderr, "WARNING! encrypt(3) not present in the system!\n");
+ return (0);
+}
diff --git a/lib/libc/gen/ctermid.3 b/lib/libc/gen/ctermid.3
new file mode 100644
index 0000000..c8f3c10
--- /dev/null
+++ b/lib/libc/gen/ctermid.3
@@ -0,0 +1,111 @@
+.\" 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. 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.
+.\"
+.\" @(#)ctermid.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.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
+The current implementation simply 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 0000000..4c2ffe3
--- /dev/null
+++ b/lib/libc/gen/ctermid.c
@@ -0,0 +1,61 @@
+/*-
+ * 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. 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)ctermid.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <paths.h>
+#include <string.h>
+
+char *
+ctermid(char *s)
+{
+ static char def[] = _PATH_TTY;
+
+ if (s) {
+ bcopy(def, s, sizeof(_PATH_TTY));
+ return(s);
+ }
+ return(def);
+}
+
+
+char *
+ctermid_r(char *s)
+{
+ return (s) ? ctermid(s) : NULL;
+}
diff --git a/lib/libc/gen/daemon.3 b/lib/libc/gen/daemon.3
new file mode 100644
index 0000000..5b4a5e0
--- /dev/null
+++ b/lib/libc/gen/daemon.3
@@ -0,0 +1,116 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)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 0000000..a0c0150
--- /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.
+ * 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.
+ */
+
+#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"
+
+int
+daemon(nochdir, noclose)
+ int nochdir, 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 = _sigaction(SIGHUP, &sa, &osa);
+
+ switch (fork()) {
+ case -1:
+ return (-1);
+ case 0:
+ break;
+ default:
+ _exit(0);
+ }
+
+ newgrp = setsid();
+ oerrno = errno;
+ if (osa_ok != -1)
+ _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 0000000..79bc7df
--- /dev/null
+++ b/lib/libc/gen/devname.3
@@ -0,0 +1,97 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)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"
+.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
+.Fn devname
+returns the name stored in a static buffer which will be overwritten
+on subsequent calls.
+.Fn devname_r
+takes 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));
+.Ed
+.Sh SEE ALSO
+.Xr stat 2
+.Sh HISTORY
+The
+.Fn devname
+function appeared in
+.Bx 4.4 .
diff --git a/lib/libc/gen/devname.c b/lib/libc/gen/devname.c
new file mode 100644
index 0000000..0563180
--- /dev/null
+++ b/lib/libc/gen/devname.c
@@ -0,0 +1,81 @@
+/*
+ * 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. 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.
+ */
+
+#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/types.h>
+#include <sys/sysctl.h>
+
+#include <err.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+
+char *
+devname_r(dev_t dev, mode_t type, char *buf, int len)
+{
+ int i;
+ size_t j;
+ char *r;
+
+ if ((type & S_IFMT) == S_IFCHR) {
+ j = len;
+ i = sysctlbyname("kern.devname", buf, &j, &dev, sizeof (dev));
+ if (i == 0)
+ return (buf);
+ }
+
+ /* Finally just format it */
+ if (dev == NODEV)
+ r = "#NODEV";
+ else
+ r = "#%c:%d:0x%x";
+ snprintf(buf, len, r,
+ (type & S_IFMT) == S_IFCHR ? 'C' : 'B', major(dev), minor(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 0000000..2edf5dc
--- /dev/null
+++ b/lib/libc/gen/directory.3
@@ -0,0 +1,208 @@
+.\" 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. 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.
+.\"
+.\" @(#)directory.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt DIRECTORY 3
+.Os
+.Sh NAME
+.Nm opendir ,
+.Nm readdir ,
+.Nm readdir_r ,
+.Nm telldir ,
+.Nm seekdir ,
+.Nm rewinddir ,
+.Nm closedir ,
+.Nm dirfd
+.Nd directory operations
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In dirent.h
+.Ft DIR *
+.Fn opendir "const char *filename"
+.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 dirfd "DIR *dirp"
+.Sh DESCRIPTION
+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 readdir
+function
+returns a pointer to the next directory entry.
+It returns
+.Dv NULL
+upon reaching the end of the directory or detecting an invalid
+.Fn seekdir
+operation.
+.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.
+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 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.
+.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 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
+len = strlen(name);
+dirp = opendir(".");
+while ((dp = readdir(dirp)) != NULL)
+ if (dp->d_namlen == len && !strcmp(dp->d_name, name)) {
+ (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 .
diff --git a/lib/libc/gen/dirname.3 b/lib/libc/gen/dirname.3
new file mode 100644
index 0000000..eac042d
--- /dev/null
+++ b/lib/libc/gen/dirname.3
@@ -0,0 +1,110 @@
+.\"
+.\" 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: dirname.3,v 1.9 2000/04/18 03:01:25 aaron Exp $
+.\" $FreeBSD$
+.\"
+.Dd August 17, 1997
+.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 "const 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.
+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.
+.Sh RETURN VALUES
+On successful completion,
+.Fn dirname
+returns a pointer to the parent directory of
+.Fa path .
+.Pp
+If
+.Fn dirname
+fails, a null pointer is returned and the global variable
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+The following error codes may be set in
+.Va errno :
+.Bl -tag -width Er
+.It Bq Er ENAMETOOLONG
+The path component to be returned was larger than
+.Dv MAXPATHLEN .
+.El
+.Sh WARNINGS
+The
+.Fn dirname
+function
+returns a pointer to internal static storage space that will be overwritten
+by subsequent calls (each function has its own separate storage).
+.Pp
+Other vendor implementations of
+.Fn dirname
+may modify the contents of the string passed to
+.Fn dirname ;
+this should be taken into account when writing code which calls this function
+if portability is desired.
+.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 .
+.Sh AUTHORS
+.An "Todd C. Miller" Aq Todd.Miller@courtesan.com
diff --git a/lib/libc/gen/dirname.c b/lib/libc/gen/dirname.c
new file mode 100644
index 0000000..56b75f6
--- /dev/null
+++ b/lib/libc/gen/dirname.c
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ */
+
+#if 0
+#ifndef lint
+static char rcsid[] = "$OpenBSD: dirname.c,v 1.4 1999/05/30 17:10:30 espie Exp $";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <libgen.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/param.h>
+
+char *
+dirname(path)
+ const char *path;
+{
+ static char *bname = NULL;
+ const char *endp;
+
+ if (bname == NULL) {
+ bname = (char *)malloc(MAXPATHLEN);
+ if (bname == NULL)
+ return(NULL);
+ }
+
+ /* Empty or NULL string gets treated as "." */
+ if (path == NULL || *path == '\0') {
+ (void)strcpy(bname, ".");
+ return(bname);
+ }
+
+ /* Strip 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) {
+ (void)strcpy(bname, *endp == '/' ? "/" : ".");
+ return(bname);
+ } else {
+ do {
+ endp--;
+ } while (endp > path && *endp == '/');
+ }
+
+ if (endp - path + 2 > MAXPATHLEN) {
+ errno = ENAMETOOLONG;
+ return(NULL);
+ }
+ (void)strncpy(bname, path, endp - path + 1);
+ bname[endp - path + 1] = '\0';
+ return(bname);
+}
diff --git a/lib/libc/gen/disklabel.c b/lib/libc/gen/disklabel.c
new file mode 100644
index 0000000..2ff3061
--- /dev/null
+++ b/lib/libc/gen/disklabel.c
@@ -0,0 +1,163 @@
+/*
+ * 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.
+ * 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.
+ */
+
+#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 && strcmp(cq, "removable") == 0)
+ dp->d_flags |= D_REMOVABLE;
+ else if (cq && strcmp(cq, "simulated") == 0)
+ dp->d_flags |= D_RAMDISK;
+ 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);
+ 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 && cgetstr(buf, ptype, &cq) > 0)
+ pp->p_fstype = gettype(cq, fstypenames);
+ 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/dladdr.3 b/lib/libc/gen/dladdr.3
new file mode 100644
index 0000000..414fa49
--- /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
+.Os
+.Dt DLADDR 3
+.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 0000000..e0a8233
--- /dev/null
+++ b/lib/libc/gen/dlfcn.c
@@ -0,0 +1,129 @@
+/*-
+ * 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 <dlfcn.h>
+#include <stddef.h>
+
+static const char sorry[] = "Service unavailable";
+
+/*
+ * 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
+const 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 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);
+}
diff --git a/lib/libc/gen/dlfunc.c b/lib/libc/gen/dlfunc.c
new file mode 100644
index 0000000..72a683a
--- /dev/null
+++ b/lib/libc/gen/dlfunc.c
@@ -0,0 +1,30 @@
+/*
+ * This source file is in the public domain.
+ * Garrett A. Wollman, 2002-05-28.
+ *
+ * $FreeBSD$
+ */
+
+#include <dlfcn.h>
+
+/*
+ * Implement the dlfunc() interface, which behaves exactly the same as
+ * dlsym() except that it returns a function pointer instead of a data
+ * pointer. This can be used by applications to avoid compiler warnings
+ * about undefined behavior, and is intended as prior art for future
+ * POSIX standardization. This function requires that all pointer types
+ * have the same representation, which is true on all platforms FreeBSD
+ * runs on, but is not guaranteed by the C standard.
+ */
+dlfunc_t
+dlfunc(void * __restrict handle, const char * __restrict symbol)
+{
+ union {
+ void *d;
+ dlfunc_t f;
+ } rv;
+
+ rv.d = dlsym(handle, symbol);
+ return (rv.f);
+}
+
diff --git a/lib/libc/gen/dlinfo.3 b/lib/libc/gen/dlinfo.3
new file mode 100644
index 0000000..9433fb6
--- /dev/null
+++ b/lib/libc/gen/dlinfo.3
@@ -0,0 +1,282 @@
+.\"
+.\" 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
+.Os
+.Dt DLINFO 3
+.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 phantom@FreeBSD.org
+and later extended and improved by
+.An Alexander Kabaev
+.Aq kan@FreeBSD.org .
+.Pp
+The manual page for this function was written by
+.An Alexey Zelkin
+.Aq phantom@FreeBSD.org .
diff --git a/lib/libc/gen/dllockinit.3 b/lib/libc/gen/dllockinit.3
new file mode 100644
index 0000000..98d1074
--- /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
+.Os
+.Dt DLLOCKINIT 3
+.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 0000000..118e165
--- /dev/null
+++ b/lib/libc/gen/dlopen.3
@@ -0,0 +1,360 @@
+.\" 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 September 10, 2002
+.Os
+.Dt DLOPEN 3
+.Sh NAME
+.Nm dlopen ,
+.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 dlsym "void * restrict handle" "const char * restrict symbol"
+.Ft dlfunc_t
+.Fn dlfunc "void * restrict handle" "const char * restrict symbol"
+.Ft const 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_GLOBALX
+.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.
+.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 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 Wsymbolic
+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 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 0000000..672b5ee
--- /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/erand48.c b/lib/libc/gen/erand48.c
new file mode 100644
index 0000000..cdb3ec8
--- /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 0000000..1e2d7c3
--- /dev/null
+++ b/lib/libc/gen/err.3
@@ -0,0 +1,236 @@
+.\" 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.
+.\" 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.
+.\"
+.\" From: @(#)err.3 8.1 (Berkeley) 6/9/93
+.\" $FreeBSD$
+.\"
+.Dd March 6, 1999
+.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
+-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 code 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(1, NULL);
+if ((fd = open(file_name, O_RDONLY, 0)) == -1)
+ err(1, "%s", file_name);
+.Ed
+.Pp
+Display an error message and exit:
+.Bd -literal -offset indent
+if (tm.tm_hour < START_TIME)
+ errx(1, "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(1, "%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 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 0000000..9365d7d
--- /dev/null
+++ b/lib/libc/gen/err.c
@@ -0,0 +1,213 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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(eval, fmt, ap)
+ 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(eval, code, fmt, ap)
+ int eval;
+ int code;
+ const char *fmt;
+ va_list ap;
+{
+ if (err_file == 0)
+ 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(eval, fmt, ap)
+ int eval;
+ const char *fmt;
+ va_list ap;
+{
+ if (err_file == 0)
+ 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(fmt, ap)
+ 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(code, fmt, ap)
+ int code;
+ const char *fmt;
+ va_list ap;
+{
+ if (err_file == 0)
+ 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(fmt, ap)
+ const char *fmt;
+ va_list ap;
+{
+ if (err_file == 0)
+ 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 0000000..2e5a684
--- /dev/null
+++ b/lib/libc/gen/errlst.c
@@ -0,0 +1,158 @@
+/*
+ * 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.
+ * 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.
+ */
+
+#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>
+
+const char *const sys_errlist[] = {
+ "Undefined 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 */
+};
+const int sys_nerr = sizeof(sys_errlist) / sizeof(sys_errlist[0]);
diff --git a/lib/libc/gen/errno.c b/lib/libc/gen/errno.c
new file mode 100644
index 0000000..02e0351
--- /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 0000000..3fbf2b5
--- /dev/null
+++ b/lib/libc/gen/exec.3
@@ -0,0 +1,325 @@
+.\" 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. 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.
+.\"
+.\" @(#)exec.3 8.3 (Berkeley) 1/24/94
+.\" $FreeBSD$
+.\"
+.Dd January 24, 1994
+.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 /usr/bin:/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 place the current directory last 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 0000000..a832bdc
--- /dev/null
+++ b/lib/libc/gen/exec.c
@@ -0,0 +1,275 @@
+/*-
+ * 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. 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.
+ */
+
+#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/types.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"
+
+extern char **environ;
+
+int
+execl(const char *name, const char *arg, ...)
+{
+ va_list ap;
+ 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] = (char *)arg;
+ while ((argv[n] = va_arg(ap, char *)) != NULL)
+ n++;
+ va_end(ap);
+ return (_execve(name, argv, environ));
+}
+
+int
+execle(const char *name, const char *arg, ...)
+{
+ va_list ap;
+ char **argv, **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] = (char *)arg;
+ while ((argv[n] = va_arg(ap, char *)) != NULL)
+ n++;
+ envp = va_arg(ap, char **);
+ va_end(ap);
+ return (_execve(name, argv, envp));
+}
+
+int
+execlp(const char *name, const char *arg, ...)
+{
+ va_list ap;
+ 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] = (char *)arg;
+ while ((argv[n] = va_arg(ap, char *)) != NULL)
+ n++;
+ va_end(ap);
+ return (execvp(name, argv));
+}
+
+int
+execv(name, argv)
+ const char *name;
+ char * const *argv;
+{
+ (void)_execve(name, argv, environ);
+ return (-1);
+}
+
+int
+execvp(const char *name, char * const *argv)
+{
+ const char *path;
+
+ /* Get the path we're searching. */
+ if ((path = getenv("PATH")) == NULL)
+ path = _PATH_DEFPATH;
+
+ return (execvP(name, path, argv));
+}
+
+int
+execvP(name, path, argv)
+ const char *name;
+ const char *path;
+ char * const *argv;
+{
+ char **memp;
+ int cnt, lp, ln;
+ char *p;
+ int eacces, save_errno;
+ char *bp, *cur, buf[MAXPATHLEN];
+ struct stat sb;
+
+ eacces = 0;
+
+ /* If it's an absolute or relative path name, it's easy. */
+ if (index(name, '/')) {
+ bp = (char *)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, environ);
+ 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, memp, environ);
+ 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);
+}
diff --git a/lib/libc/gen/fmtcheck.3 b/lib/libc/gen/fmtcheck.3
new file mode 100644
index 0000000..3663558
--- /dev/null
+++ b/lib/libc/gen/fmtcheck.3
@@ -0,0 +1,117 @@
+.\" 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.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the NetBSD
+.\" Foundation, Inc. and its contributors.
+.\" 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 October 16, 2002
+.Os
+.Dt FMTCHECK 3
+.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 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.
+.Sh SEE ALSO
+.Xr printf 3
+.Sh BUGS
+The
+.Fn fmtcheck
+function does not understand all of the conversions that
+.Xr printf 3
+does.
diff --git a/lib/libc/gen/fmtcheck.c b/lib/libc/gen/fmtcheck.c
new file mode 100644
index 0000000..ca93983
--- /dev/null
+++ b/lib/libc/gen/fmtcheck.c
@@ -0,0 +1,267 @@
+/*-
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 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.
+ */
+
+/* $NetBSD: fmtcheck.c,v 1.2 2000/11/01 01:17:20 briggs Exp $ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+__weak_reference(__fmtcheck, fmtcheck);
+
+enum __e_fmtcheck_types {
+ FMTCHECK_START,
+ FMTCHECK_SHORT,
+ FMTCHECK_INT,
+ FMTCHECK_LONG,
+ FMTCHECK_QUAD,
+ FMTCHECK_PTRDIFFT,
+ FMTCHECK_SIZET,
+ FMTCHECK_SHORTPOINTER,
+ FMTCHECK_INTPOINTER,
+ FMTCHECK_LONGPOINTER,
+ FMTCHECK_QUADPOINTER,
+ FMTCHECK_PTRDIFFTPOINTER,
+ FMTCHECK_SIZETPOINTER,
+#ifndef NO_FLOATING_POINT
+ FMTCHECK_DOUBLE,
+ FMTCHECK_LONGDOUBLE,
+#endif
+ FMTCHECK_STRING,
+ FMTCHECK_WIDTH,
+ FMTCHECK_PRECISION,
+ FMTCHECK_DONE,
+ FMTCHECK_UNKNOWN
+};
+typedef enum __e_fmtcheck_types EFT;
+
+#define RETURN(pf,f,r) do { \
+ *(pf) = (f); \
+ return r; \
+ } /*NOTREACHED*/ /*CONSTCOND*/ while (0)
+
+static EFT
+get_next_format_from_precision(const char **pf)
+{
+ int sh, lg, quad, longdouble, ptrdifft, sizet;
+ const char *f;
+
+ sh = lg = quad = longdouble = ptrdifft = sizet = 0;
+
+ f = *pf;
+ switch (*f) {
+ case 'h':
+ f++;
+ sh = 1;
+ break;
+ case 'l':
+ f++;
+ if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
+ if (*f == 'l') {
+ f++;
+ quad = 1;
+ } else {
+ lg = 1;
+ }
+ break;
+ case 'q':
+ f++;
+ quad = 1;
+ break;
+ case 't':
+ f++;
+ ptrdifft = 1;
+ break;
+ case 'z':
+ f++;
+ sizet = 1;
+ break;
+ case 'L':
+ f++;
+ longdouble = 1;
+ break;
+ default:
+ break;
+ }
+ if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
+ if (strchr("diouxX", *f)) {
+ if (longdouble)
+ RETURN(pf,f,FMTCHECK_UNKNOWN);
+ if (lg)
+ RETURN(pf,f,FMTCHECK_LONG);
+ if (quad)
+ RETURN(pf,f,FMTCHECK_QUAD);
+ if (ptrdifft)
+ RETURN(pf,f,FMTCHECK_PTRDIFFT);
+ if (sizet)
+ RETURN(pf,f,FMTCHECK_SIZET);
+ RETURN(pf,f,FMTCHECK_INT);
+ }
+ if (*f == 'n') {
+ if (longdouble)
+ RETURN(pf,f,FMTCHECK_UNKNOWN);
+ if (sh)
+ RETURN(pf,f,FMTCHECK_SHORTPOINTER);
+ if (lg)
+ RETURN(pf,f,FMTCHECK_LONGPOINTER);
+ if (quad)
+ RETURN(pf,f,FMTCHECK_QUADPOINTER);
+ if (ptrdifft)
+ RETURN(pf,f,FMTCHECK_PTRDIFFTPOINTER);
+ if (sizet)
+ RETURN(pf,f,FMTCHECK_SIZETPOINTER);
+ RETURN(pf,f,FMTCHECK_INTPOINTER);
+ }
+ if (strchr("DOU", *f)) {
+ if (sh + lg + quad + longdouble + ptrdifft + sizet)
+ RETURN(pf,f,FMTCHECK_UNKNOWN);
+ RETURN(pf,f,FMTCHECK_LONG);
+ }
+#ifndef NO_FLOATING_POINT
+ if (strchr("aAeEfFgG", *f)) {
+ if (longdouble)
+ RETURN(pf,f,FMTCHECK_LONGDOUBLE);
+ if (sh + lg + quad + ptrdifft + sizet)
+ RETURN(pf,f,FMTCHECK_UNKNOWN);
+ RETURN(pf,f,FMTCHECK_DOUBLE);
+ }
+#endif
+ if (*f == 'c') {
+ if (sh + lg + quad + longdouble + ptrdifft + sizet)
+ RETURN(pf,f,FMTCHECK_UNKNOWN);
+ RETURN(pf,f,FMTCHECK_INT);
+ }
+ if (*f == 's') {
+ if (sh + lg + quad + longdouble + ptrdifft + sizet)
+ RETURN(pf,f,FMTCHECK_UNKNOWN);
+ RETURN(pf,f,FMTCHECK_STRING);
+ }
+ if (*f == 'p') {
+ if (sh + lg + quad + longdouble + ptrdifft + sizet)
+ 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 0000000..7995d7b
--- /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 0000000..6caabbb
--- /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 *);
+
+static const char *validlist[] = {
+ "label", "severity", "text", "action", "tag", NULL
+};
+
+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", "a")) == 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 (text != 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)
+{
+ char *msgcomp;
+ int i, equality;
+
+ equality = 0;
+ while ((msgcomp = nextcomp(msgverb)) != NULL) {
+ equality--;
+ for (i = 0; validlist[i] != NULL; i++) {
+ if (strcmp(msgcomp, validlist[i]) == 0)
+ equality++;
+ }
+ }
+ return (!equality);
+}
diff --git a/lib/libc/gen/fnmatch.3 b/lib/libc/gen/fnmatch.3
new file mode 100644
index 0000000..db27033
--- /dev/null
+++ b/lib/libc/gen/fnmatch.3
@@ -0,0 +1,155 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)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 0000000..f041df8
--- /dev/null
+++ b/lib/libc/gen/fnmatch.c
@@ -0,0 +1,295 @@
+/*
+ * 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.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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.
+ */
+
+#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 *, int, mbstate_t, mbstate_t);
+
+int
+fnmatch(pattern, string, flags)
+ const char *pattern, *string;
+ int flags;
+{
+ static const mbstate_t initial;
+
+ return (fnmatch1(pattern, string, flags, initial, initial));
+}
+
+static int
+fnmatch1(pattern, string, flags, patmbs, strmbs)
+ const char *pattern, *string;
+ int flags;
+ mbstate_t patmbs, strmbs;
+{
+ const char *stringstart;
+ char *newp;
+ char c;
+ wchar_t pc, sc;
+ size_t pclen, sclen;
+
+ for (stringstart = string;;) {
+ 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);
+ return (sc == EOS ? 0 : FNM_NOMATCH);
+ case '?':
+ if (sc == EOS)
+ return (FNM_NOMATCH);
+ if (sc == '/' && (flags & FNM_PATHNAME))
+ return (FNM_NOMATCH);
+ if (sc == '.' && (flags & FNM_PERIOD) &&
+ (string == stringstart ||
+ ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
+ return (FNM_NOMATCH);
+ 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) == '/')))
+ return (FNM_NOMATCH);
+
+ /* 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;
+ }
+
+ /* General case, use recursion. */
+ while (sc != EOS) {
+ if (!fnmatch1(pattern, string,
+ flags & ~FNM_PERIOD, patmbs, strmbs))
+ return (0);
+ 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));
+ }
+ if (sc == '/' && flags & FNM_PATHNAME)
+ break;
+ string += sclen;
+ }
+ return (FNM_NOMATCH);
+ case '[':
+ if (sc == EOS)
+ return (FNM_NOMATCH);
+ if (sc == '/' && (flags & FNM_PATHNAME))
+ return (FNM_NOMATCH);
+ if (sc == '.' && (flags & FNM_PERIOD) &&
+ (string == stringstart ||
+ ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
+ return (FNM_NOMATCH);
+
+ switch (rangematch(pattern, sc, flags, &newp,
+ &patmbs)) {
+ case RANGE_ERROR:
+ goto norm;
+ case RANGE_MATCH:
+ pattern = newp;
+ break;
+ case RANGE_NOMATCH:
+ return (FNM_NOMATCH);
+ }
+ 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);
+ if (pclen == 0)
+ pc = '\\';
+ pattern += pclen;
+ }
+ /* FALLTHROUGH */
+ default:
+ norm:
+ if (pc == sc)
+ ;
+ else if ((flags & FNM_CASEFOLD) &&
+ (towlower(pc) == towlower(sc)))
+ ;
+ else
+ return (FNM_NOMATCH);
+ string += sclen;
+ break;
+ }
+ }
+ /* NOTREACHED */
+}
+
+static int
+rangematch(pattern, test, flags, newp, patmbs)
+ 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;
+
+ /*
+ * 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 (__collate_load_error ?
+ c <= test && test <= c2 :
+ __collate_range_cmp(c, test) <= 0
+ && __collate_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 0000000..a547eeb
--- /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 0000000..754a1df
--- /dev/null
+++ b/lib/libc/gen/fpclassify.c
@@ -0,0 +1,93 @@
+/*-
+ * 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 <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 (u.bits.exp == 32767) {
+ if ((u.bits.manl | u.bits.manh) == 0)
+ return (FP_INFINITE);
+ return (FP_NAN);
+ }
+ return (FP_NORMAL);
+}
diff --git a/lib/libc/gen/frexp.3 b/lib/libc/gen/frexp.3
new file mode 100644
index 0000000..f3bf8da
--- /dev/null
+++ b/lib/libc/gen/frexp.3
@@ -0,0 +1,98 @@
+.\" 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. 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.
+.\"
+.\" @(#)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
+.Bo 1/2 , 1 Pc
+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 0000000..53483da
--- /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 0000000..beeb700
--- /dev/null
+++ b/lib/libc/gen/fstab.c
@@ -0,0 +1,298 @@
+/*
+ * 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.
+ * 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.
+ */
+
+#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 "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()
+{
+ static char buf[sizeof(_PATH_DEV) + MNAMELEN];
+ struct stat sb;
+ struct statfs sf;
+
+ if (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()
+{
+ 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 || *_fs_fstab.fs_spec == '#')
+ continue;
+ while ((cp = strsep(&p, " \t\n")) != NULL && *cp == '\0')
+ ;
+ _fs_fstab.fs_file = cp;
+ 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);
+ }
+ strcpy(subline, _fs_fstab.fs_mntops);
+ 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()
+{
+ if ((!_fs_fp && !setfsent()) || !fstabscan())
+ return((struct fstab *)NULL);
+ return(&_fs_fstab);
+}
+
+struct fstab *
+getfsspec(name)
+ const char *name;
+{
+ if (setfsent())
+ while (fstabscan())
+ if (!strcmp(_fs_fstab.fs_spec, name))
+ return(&_fs_fstab);
+ return((struct fstab *)NULL);
+}
+
+struct fstab *
+getfsfile(name)
+ const char *name;
+{
+ if (setfsent())
+ while (fstabscan())
+ if (!strcmp(_fs_fstab.fs_file, name))
+ return(&_fs_fstab);
+ return((struct fstab *)NULL);
+}
+
+int
+setfsent()
+{
+ 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, "r")) != NULL) {
+ LineNo = 0;
+ return(1);
+ }
+ error(errno);
+ return(0);
+}
+
+void
+endfsent()
+{
+ if (_fs_fp) {
+ (void)fclose(_fs_fp);
+ _fs_fp = NULL;
+ }
+
+ fsp_set = 0;
+}
+
+static void
+error(err)
+ 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 0000000..a1c7dde
--- /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 June 24, 1994
+.Os
+.Dt FTOK 3
+.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 3 ,
+.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 semget 2 ,
+.Xr shmget 2 ,
+.Xr msgget 3
+.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 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 0000000..4269e37
--- /dev/null
+++ b/lib/libc/gen/ftok.c
@@ -0,0 +1,46 @@
+/*
+ * 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(path, id)
+ 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 0000000..48f9e0b
--- /dev/null
+++ b/lib/libc/gen/fts-compat.c
@@ -0,0 +1,1226 @@
+/*-
+ * 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.
+ * 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.
+ *
+ * $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"
+
+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",
+ "nfs",
+ "nfs4",
+ "ext2fs",
+ 0
+};
+
+FTS *
+fts_open(argv, options, compar)
+ 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 = malloc(sizeof(*priv))) == NULL)
+ return (NULL);
+ memset(priv, 0, sizeof(*priv));
+ 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, 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(sp, p)
+ 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(sp)
+ 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(sp)
+ 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, 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, 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(sp, p, instr)
+ 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(sp, instr)
+ 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, 0)) < 0)
+ return (NULL);
+ sp->fts_child = fts_build(sp, instr);
+ if (fchdir(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)(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(sp, type)
+ 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(sp, p, follow)
+ 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(sp, head, nitems)
+ 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(sp, name, namelen)
+ 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(head)
+ 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(sp, more)
+ 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(sp, head)
+ 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(argv)
+ 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(sp, p, fd, path)
+ 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, 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/fts-compat.h b/lib/libc/gen/fts-compat.h
new file mode 100644
index 0000000..7eb03a6
--- /dev/null
+++ b/lib/libc/gen/fts-compat.h
@@ -0,0 +1,145 @@
+/*
+ * 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. 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.
+ *
+ * @(#)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;
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+FTSENT *fts_children(FTS *, int);
+int fts_close(FTS *);
+void *fts_get_clientptr(FTS *);
+#define fts_get_clientptr(fts) ((fts)->fts_clientptr)
+FTS *fts_get_stream(FTSENT *);
+#define fts_get_stream(ftsent) ((ftsent)->fts_fts)
+FTS *fts_open(char * const *, int,
+ int (*)(const FTSENT * const *, const FTSENT * const *));
+FTSENT *fts_read(FTS *);
+int fts_set(FTS *, FTSENT *, int);
+void fts_set_clientptr(FTS *, void *);
+__END_DECLS
+
+#endif /* !_FTS_H_ */
diff --git a/lib/libc/gen/fts.3 b/lib/libc/gen/fts.3
new file mode 100644
index 0000000..b4fe3df
--- /dev/null
+++ b/lib/libc/gen/fts.3
@@ -0,0 +1,820 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)fts.3 8.5 (Berkeley) 4/16/94
+.\" $FreeBSD$
+.\"
+.Dd January 7, 2005
+.Dt FTS 3
+.Os
+.Sh NAME
+.Nm fts
+.Nd traverse a file hierarchy
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/stat.h
+.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 {
+ u_short fts_info; /* flags for FTSENT structure */
+ char *fts_accpath; /* access path */
+ char *fts_path; /* root path */
+ u_short fts_pathlen; /* strlen(fts_path) */
+ char *fts_name; /* file name */
+ u_short fts_namelen; /* strlen(fts_name) */
+ short fts_level; /* depth (\-1 to N) */
+ int fts_errno; /* file errno */
+ long fts_number; /* local numeric value */
+ void *fts_pointer; /* local address value */
+ int64_t fts_bignum; /* local 64-bit numeric 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
+it was returned in pre-order, i.e., with the
+.Fa fts_info
+field set to
+.Dv FTS_D .
+.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.
+Note that this field is overlaid by
+.Fa fts_bignum .
+.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 .
+Note that this field is overlaid by
+.Fa fts_bignum .
+.It Fa fts_bignum
+This field is provided for the use of the application program and is
+not modified by the
+.Nm
+functions.
+It is initialized to 0.
+Note that this field overlays
+.Fa fts_number
+and
+.Fa fts_pointer .
+.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_bignum ,
+.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 .
+.Pp
+Note that the use of
+.Fa fts_bignum
+is mutually exclusive with the use of
+.Fa fts_number
+or
+.Fa fts_pointer .
+.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
+As a performance optimization, 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 optimization, 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.
+.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.
diff --git a/lib/libc/gen/fts.c b/lib/libc/gen/fts.c
new file mode 100644
index 0000000..48f9e0b
--- /dev/null
+++ b/lib/libc/gen/fts.c
@@ -0,0 +1,1226 @@
+/*-
+ * 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.
+ * 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.
+ *
+ * $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"
+
+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",
+ "nfs",
+ "nfs4",
+ "ext2fs",
+ 0
+};
+
+FTS *
+fts_open(argv, options, compar)
+ 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 = malloc(sizeof(*priv))) == NULL)
+ return (NULL);
+ memset(priv, 0, sizeof(*priv));
+ 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, 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(sp, p)
+ 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(sp)
+ 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(sp)
+ 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, 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, 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(sp, p, instr)
+ 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(sp, instr)
+ 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, 0)) < 0)
+ return (NULL);
+ sp->fts_child = fts_build(sp, instr);
+ if (fchdir(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)(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(sp, type)
+ 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(sp, p, follow)
+ 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(sp, head, nitems)
+ 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(sp, name, namelen)
+ 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(head)
+ 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(sp, more)
+ 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(sp, head)
+ 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(argv)
+ 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(sp, p, fd, path)
+ 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, 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 0000000..ba8859b
--- /dev/null
+++ b/lib/libc/gen/ftw.3
@@ -0,0 +1,216 @@
+.\" $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
+.Fn ( nftw
+only).
+.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
+.Fn ( nftw
+only).
+.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 0000000..0177712
--- /dev/null
+++ b/lib/libc/gen/ftw.c
@@ -0,0 +1,98 @@
+/* $OpenBSD: ftw.c,v 1.4 2004/07/07 16:05:23 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.
+ */
+
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$OpenBSD: ftw.c,v 1.4 2004/07/07 16:05:23 millert Exp $";
+#endif /* LIBC_SCCS and not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <fts.h>
+#include <ftw.h>
+#include <limits.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 || nfds > OPEN_MAX) {
+ 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/getbootfile.3 b/lib/libc/gen/getbootfile.3
new file mode 100644
index 0000000..e9cc8b6
--- /dev/null
+++ b/lib/libc/gen/getbootfile.3
@@ -0,0 +1,73 @@
+.\" 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. 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.
+.\"
+.\" 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 0000000..739af15
--- /dev/null
+++ b/lib/libc/gen/getbootfile.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. 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.
+ */
+
+#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 0000000..cbf4863
--- /dev/null
+++ b/lib/libc/gen/getbsize.3
@@ -0,0 +1,82 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)getbsize.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt GETBSIZE 3
+.Os
+.Sh NAME
+.Nm getbsize
+.Nd get user 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 determines the user's preferred block size based on the value of the
+.Dq BLOCKSIZE
+environment variable; see
+.Xr environ 7
+for details on its use and format.
+.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.
+.Pp
+If the user's block size is unreasonable, a warning message is
+written to standard error and the returned information reflects
+a block size of 512 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 0000000..1a3a70d
--- /dev/null
+++ b/lib/libc/gen/getbsize.c
@@ -0,0 +1,109 @@
+/*-
+ * 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. 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.
+ */
+
+#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(headerlenp, blocksizep)
+ 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;
+ 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 0000000..ed926aa
--- /dev/null
+++ b/lib/libc/gen/getcap.3
@@ -0,0 +1,571 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)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
+.Fn ( cgetfirst
+or
+.Fn cgetnext ) ,
+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:
+.Bl -column "nameTvalue"
+.It name Ta "typeless [boolean] capability"
+.Em name No "is present [true]"
+.It name Ns Em \&T Ns value Ta capability
+.Pq Em name , \&T
+has value
+.Em value
+.It name@ Ta "no capability" Em name No exists
+.It name Ns Em T Ns \&@ Ta 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.
+.Pp
+.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 :
+.Bl -column "nameXnumber"
+.Sm off
+.It Em name No \&# Em number Ta numeric
+.Sm on
+capability
+.Em name
+has value
+.Em number
+.Sm off
+.It Em name No = Em string Ta "string capability"
+.Sm on
+.Em name
+has value
+.Em string
+.Sm off
+.It Em name No \&#@ Ta "the numeric capability"
+.Sm on
+.Em name
+does not exist
+.Sm off
+.It Em name No \&=@ Ta "the string capability"
+.Sm on
+.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 cgetseq
+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 0000000..af05113
--- /dev/null
+++ b/lib/libc/gen/getcap.c
@@ -0,0 +1,1058 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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, clen;
+ 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 */
+ clen = strlen(record);
+ cbuf = malloc(clen + 1);
+ memcpy(cbuf, record, clen + 1);
+ if (capdbp->close(capdbp) < 0) {
+ free(cbuf);
+ return (-2);
+ }
+ *len = clen;
+ *cap = cbuf;
+ return (retval);
+ } else {
+ fd = _open(*db_p, O_RDONLY, 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, i, 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, "r")) == 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, "r")) == 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.
+ */
+ i = 0;
+ 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 0000000..2fda6b8
--- /dev/null
+++ b/lib/libc/gen/getcontext.3
@@ -0,0 +1,121 @@
+.\" 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 GETCONTEXT 3
+.Os
+.Sh NAME
+.Nm getcontext , 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 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 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.
+.Sh ERRORS
+No errors are defined for
+.Fn getcontext
+or
+.Fn setcontext .
+.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 0000000..ba59c15
--- /dev/null
+++ b/lib/libc/gen/getcwd.3
@@ -0,0 +1,158 @@
+.\" 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. 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.
+.\"
+.\" @(#)getcwd.3 8.2 (Berkeley) 12/11/93
+.\" $FreeBSD$
+.\"
+.Dd November 24, 1997
+.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 EACCES
+Read or search permission was denied for a component of the pathname.
+.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
+.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 0000000..b18921b
--- /dev/null
+++ b/lib/libc/gen/getcwd.c
@@ -0,0 +1,261 @@
+/*
+ * 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.
+ * 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.
+ */
+
+#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"
+
+#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(pt, size)
+ char *pt;
+ size_t size;
+{
+ struct dirent *dp;
+ DIR *dir = NULL;
+ dev_t dev;
+ ino_t ino;
+ int first;
+ char *bpt, *bup;
+ struct stat s;
+ dev_t root_dev;
+ ino_t root_ino;
+ size_t ptsize, upsize;
+ int save_errno;
+ char *ept, *eup, *up, c;
+
+ /*
+ * 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';
+
+ /*
+ * Allocate 1024 bytes for the string of "../"'s.
+ * Should always be enough. If it's not, allocate
+ * as necessary. Special case the first stat, it's ".", not "..".
+ */
+ if ((up = malloc(upsize = 1024)) == NULL)
+ goto err;
+ eup = up + upsize;
+ bup = up;
+ up[0] = '.';
+ up[1] = '\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 (lstat(up, &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);
+ free(up);
+ return (pt);
+ }
+
+ /*
+ * Build pointer to the parent directory, allocating memory
+ * as necessary. Max length is 3 for "../", the largest
+ * possible component name, plus a trailing NUL.
+ */
+ while (bup + 3 + MAXNAMLEN + 1 >= eup) {
+ if ((up = reallocf(up, upsize *= 2)) == NULL)
+ goto err;
+ bup = up;
+ eup = up + upsize;
+ }
+ *bup++ = '.';
+ *bup++ = '.';
+ *bup = '\0';
+
+ /* Open and stat parent directory. */
+ if (!(dir = opendir(up)) || _fstat(dirfd(dir), &s))
+ goto err;
+
+ /* Add trailing slash for next directory. */
+ *bup++ = '/';
+ *bup = '\0';
+
+ /*
+ * 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;
+ bcopy(dp->d_name, bup, dp->d_namlen + 1);
+
+ /* Save the first error for later. */
+ if (lstat(up, &s)) {
+ 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);
+ (void) closedir(dir);
+ dir = NULL;
+
+ /* Truncate any file name. */
+ *bup = '\0';
+ }
+
+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);
+ free(up);
+
+ errno = save_errno;
+ return (NULL);
+}
diff --git a/lib/libc/gen/getdiskbyname.3 b/lib/libc/gen/getdiskbyname.3
new file mode 100644
index 0000000..0dffef9
--- /dev/null
+++ b/lib/libc/gen/getdiskbyname.3
@@ -0,0 +1,68 @@
+.\" 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. 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.
+.\"
+.\" @(#)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 disklabel 5 ,
+.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 0000000..ec1e07a
--- /dev/null
+++ b/lib/libc/gen/getdomainname.3
@@ -0,0 +1,104 @@
+.\" 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. 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.
+.\"
+.\" @(#)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 0000000..fa9679a
--- /dev/null
+++ b/lib/libc/gen/getdomainname.c
@@ -0,0 +1,59 @@
+/*
+ * 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. 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.
+ */
+
+#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(name, namelen)
+ 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 0000000..e08f798
--- /dev/null
+++ b/lib/libc/gen/getfsent.3
@@ -0,0 +1,189 @@
+.\" 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. 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.
+.\"
+.\" @(#)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 0000000..2f5dd77
--- /dev/null
+++ b/lib/libc/gen/getgrent.3
@@ -0,0 +1,291 @@
+.\" Copyright (c) 1989, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. 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.
+.\"
+.\" From: @(#)getgrent.3 8.2 (Berkeley) 4/19/94
+.\" $FreeBSD$
+.\"
+.Dd April 16, 2003
+.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 int
+.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 functions
+.Fn setgroupent
+and
+.Fn setgrent
+return the value 1 if successful, otherwise the value
+0 is returned.
+The functions
+.Fn endgrent
+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 0000000..d9ea5bd
--- /dev/null
+++ b/lib/libc/gen/getgrent.c
@@ -0,0 +1,1428 @@
+/*-
+ * 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 <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 __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);
+
+#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 */
+
+
+/* XXX IEEE Std 1003.1, 2003 specifies `void setgrent(void)' */
+int
+setgrent(void)
+{
+#ifdef NS_CACHING
+ static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
+ group, (void *)nss_lt_all,
+ NULL, NULL);
+#endif
+
+ static const ns_dtab 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(&cache_info)
+#endif
+ { NULL, NULL, NULL }
+ };
+ (void)_nsdispatch(NULL, dtab, NSDB_GROUP, "setgrent", defaultsrc, 0);
+ return (1);
+}
+
+
+int
+setgroupent(int stayopen)
+{
+#ifdef NS_CACHING
+ static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
+ group, (void *)nss_lt_all,
+ NULL, NULL);
+#endif
+
+ static const ns_dtab 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(&cache_info)
+#endif
+ { NULL, NULL, NULL }
+ };
+ (void)_nsdispatch(NULL, dtab, NSDB_GROUP, "setgrent", defaultsrc,
+ stayopen);
+ return (1);
+}
+
+
+void
+endgrent(void)
+{
+#ifdef NS_CACHING
+ static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
+ group, (void *)nss_lt_all,
+ NULL, NULL);
+#endif
+
+ static const ns_dtab 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(&cache_info)
+#endif
+ { NULL, NULL, NULL }
+ };
+ (void)_nsdispatch(NULL, dtab, NSDB_GROUP, "endgrent", defaultsrc);
+}
+
+
+int
+getgrent_r(struct group *grp, char *buffer, size_t bufsize,
+ struct group **result)
+{
+#ifdef NS_CACHING
+ static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
+ group, (void *)nss_lt_all,
+ grp_marshal_func, grp_unmarshal_func);
+#endif
+
+ static const ns_dtab 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(&cache_info)
+#endif
+ { NULL, NULL, NULL }
+ };
+ int rv, ret_errno;
+
+ ret_errno = 0;
+ *result = NULL;
+ rv = _nsdispatch(result, 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);
+}
+
+
+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, "r");
+ 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;
+ 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, "r")) == NULL)) {
+ *errnop = errno;
+ return (NS_UNAVAIL);
+ }
+ if (how == nss_lt_all)
+ stayopen = 1;
+ else {
+ rewind(st->fp);
+ stayopen = st->stayopen;
+ }
+ rv = NS_NOTFOUND;
+ 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;
+ }
+ if (!stayopen && st->fp != NULL) {
+ fclose(st->fp);
+ st->fp = NULL;
+ }
+ if (rv == NS_SUCCESS && retval != NULL)
+ *(struct group **)retval = grp;
+ 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 *))
+ 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 < (sizeof(x)/sizeof(x[0])) - 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, "r");
+ 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;
+ int rv, stayopen, *errnop;
+
+#define set_lookup_type(x, y) do { \
+ int i; \
+ \
+ for (i = 0; i < (sizeof(x)/sizeof(x[0])) - 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, "r")) == 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;
+ 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;
+ }
+fin:
+ if (!stayopen && st->fp != NULL) {
+ fclose(st->fp);
+ st->fp = NULL;
+ }
+ if (rv == NS_SUCCESS && retval != NULL)
+ *(struct group **)retval = grp;
+ 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 0000000..da949c7
--- /dev/null
+++ b/lib/libc/gen/getgrouplist.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.
+.\" 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.
+.\"
+.\" @(#)getgrouplist.3 8.1 (Berkeley) 6/9/93
+.\" $FreeBSD$
+.\"
+.Dd June 9, 1993
+.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 \-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 .
+.Sh BUGS
+The
+.Fn getgrouplist
+function
+uses the routines based on
+.Xr getgrent 3 .
+If the invoking program uses any of these routines,
+the group structure will
+be overwritten in the call to
+.Fn getgrouplist .
diff --git a/lib/libc/gen/getgrouplist.c b/lib/libc/gen/getgrouplist.c
new file mode 100644
index 0000000..63446cf
--- /dev/null
+++ b/lib/libc/gen/getgrouplist.c
@@ -0,0 +1,91 @@
+/*-
+ * 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. 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.
+ */
+
+#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>
+
+int
+getgrouplist(const char *uname, gid_t agroup, gid_t *groups, int *grpcnt)
+{
+ const struct group *grp;
+ int i, maxgroups, ngroups, ret;
+
+ ret = 0;
+ ngroups = 0;
+ maxgroups = *grpcnt;
+ /*
+ * When installing primary group, duplicate it;
+ * the first element of groups is the effective gid
+ * and will be overwritten when a setgid file is executed.
+ */
+ groups[ngroups++] = agroup;
+ if (maxgroups > 1)
+ groups[ngroups++] = agroup;
+ /*
+ * Scan the group file to find additional groups.
+ */
+ setgrent();
+ while ((grp = getgrent()) != NULL) {
+ for (i = 0; i < ngroups; i++) {
+ if (grp->gr_gid == groups[i])
+ goto skip;
+ }
+ for (i = 0; grp->gr_mem[i]; i++) {
+ if (!strcmp(grp->gr_mem[i], uname)) {
+ if (ngroups >= maxgroups) {
+ ret = -1;
+ break;
+ }
+ groups[ngroups++] = grp->gr_gid;
+ break;
+ }
+ }
+skip:
+ ;
+ }
+ endgrent();
+ *grpcnt = ngroups;
+ return (ret);
+}
diff --git a/lib/libc/gen/gethostname.3 b/lib/libc/gen/gethostname.3
new file mode 100644
index 0000000..9a0afed
--- /dev/null
+++ b/lib/libc/gen/gethostname.3
@@ -0,0 +1,135 @@
+.\" 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. 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.
+.\"
+.\" @(#)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 0000000..fa22c11
--- /dev/null
+++ b/lib/libc/gen/gethostname.c
@@ -0,0 +1,64 @@
+/*
+ * 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. 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.
+ */
+
+#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(name, namelen)
+ char *name;
+ size_t namelen;
+{
+ int mib[2];
+
+ /* Kluge to avoid ABI breakage. */
+ namelen = (int)namelen;
+
+ 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 0000000..37a8d67
--- /dev/null
+++ b/lib/libc/gen/getloadavg.3
@@ -0,0 +1,69 @@
+.\" Copyright (c) 1989, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. 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.
+.\"
+.\" @(#)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 0000000..5022d0d
--- /dev/null
+++ b/lib/libc/gen/getloadavg.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.
+ * 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.
+ */
+
+#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(loadavg, nelem)
+ 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 0000000..92af0d1
--- /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.
+ * 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.
+ */
+
+#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 <utmp.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; /* 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;
+
+ THREAD_LOCK();
+ result = getlogin_basic(&status);
+ if (status == 0) {
+ if ((len = strlen(result) + 1) > 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 0000000..7a3cc02
--- /dev/null
+++ b/lib/libc/gen/getmntinfo.3
@@ -0,0 +1,113 @@
+.\" Copyright (c) 1989, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. 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.
+.\"
+.\" @(#)getmntinfo.3 8.1 (Berkeley) 6/9/93
+.\" $FreeBSD$
+.\"
+.Dd June 9, 1993
+.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 flags"
+.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 flags
+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 0000000..636039a
--- /dev/null
+++ b/lib/libc/gen/getmntinfo.c
@@ -0,0 +1,72 @@
+/*
+ * 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. 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.
+ */
+
+#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(mntbufp, flags)
+ struct statfs **mntbufp;
+ int flags;
+{
+ 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, flags)) < 0)
+ return (0);
+ while (bufsize <= mntsize * sizeof(struct statfs)) {
+ if (mntbuf)
+ free(mntbuf);
+ bufsize = (mntsize + 1) * sizeof(struct statfs);
+ if ((mntbuf = (struct statfs *)malloc(bufsize)) == 0)
+ return (0);
+ if ((mntsize = getfsstat(mntbuf, bufsize, flags)) < 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 0000000..aa93324
--- /dev/null
+++ b/lib/libc/gen/getnetgrent.3
@@ -0,0 +1,135 @@
+.\" 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. 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.
+.\"
+.\" @(#)getnetgrent.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.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 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
+.Sy (char *)0
+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
+.Sy (char *)0
+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 0000000..abc3185
--- /dev/null
+++ b/lib/libc/gen/getnetgrent.c
@@ -0,0 +1,642 @@
+/*
+ * 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.
+ * 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.
+ */
+
+#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 <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.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/types.h>
+#include <sys/stat.h>
+#include <sys/param.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
+
+/*
+ * 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 */
+};
+#define NG_HOST 0 /* Host name */
+#define NG_USER 1 /* User name */
+#define NG_DOM 2 /* and Domain name */
+
+static struct linelist *linehead = (struct linelist *)0;
+static struct netgrp *nextgrp = (struct netgrp *)0;
+static struct {
+ struct netgrp *gr;
+ char *grname;
+} grouphead = {
+ (struct netgrp *)0,
+ (char *)0,
+};
+static FILE *netf = (FILE *)0;
+
+static int parse_netgrp(const char *);
+static struct linelist *read_for_group(const char *);
+void setnetgrent(const char *);
+void endnetgrent(void);
+int getnetgrent(char **, char **, char **);
+int innetgr(const char *, const char *, const char *, const char *);
+
+#define LINSIZ 1024 /* Length of netgroup file line */
+
+/*
+ * 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.
+ */
+void
+setnetgrent(const char *group)
+{
+#ifdef YP
+ struct stat _yp_statp;
+ char _yp_plus;
+#endif
+
+ /* Sanity check */
+
+ if (group == NULL || !strlen(group))
+ return;
+
+ if (grouphead.gr == (struct netgrp *)0 ||
+ strcmp(group, grouphead.grname)) {
+ endnetgrent();
+#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,"r")) != NULL ||_use_only_yp){
+ /*
+ * 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;
+ }
+#else
+ if ((netf = fopen(_PATH_NETGROUP, "r"))) {
+#endif
+ if (parse_netgrp(group))
+ endnetgrent();
+ else {
+ grouphead.grname = (char *)
+ malloc(strlen(group) + 1);
+ strcpy(grouphead.grname, group);
+ }
+ if (netf)
+ fclose(netf);
+ }
+ }
+ nextgrp = grouphead.gr;
+}
+
+/*
+ * Get the next netgroup off the list.
+ */
+int
+getnetgrent(char **hostp, char **userp, char **domp)
+{
+#ifdef YP
+ _yp_innetgr = 0;
+#endif
+
+ if (nextgrp) {
+ *hostp = nextgrp->ng_str[NG_HOST];
+ *userp = nextgrp->ng_str[NG_USER];
+ *domp = nextgrp->ng_str[NG_DOM];
+ nextgrp = nextgrp->ng_next;
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * endnetgrent() - cleanup
+ */
+void
+endnetgrent(void)
+{
+ struct linelist *lp, *olp;
+ struct netgrp *gp, *ogp;
+
+ lp = linehead;
+ while (lp) {
+ olp = lp;
+ lp = lp->l_next;
+ free(olp->l_groupname);
+ free(olp->l_line);
+ free((char *)olp);
+ }
+ linehead = (struct linelist *)0;
+ if (grouphead.grname) {
+ free(grouphead.grname);
+ grouphead.grname = (char *)0;
+ }
+ gp = grouphead.gr;
+ while (gp) {
+ ogp = gp;
+ gp = gp->ng_next;
+ if (ogp->ng_str[NG_HOST])
+ free(ogp->ng_str[NG_HOST]);
+ if (ogp->ng_str[NG_USER])
+ free(ogp->ng_str[NG_USER]);
+ if (ogp->ng_str[NG_DOM])
+ free(ogp->ng_str[NG_DOM]);
+ free((char *)ogp);
+ }
+ grouphead.gr = (struct netgrp *)0;
+ nextgrp = (struct netgrp *)0;
+#ifdef YP
+ _netgr_yp_enabled = 0;
+#endif
+}
+
+#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.
+ */
+int
+innetgr(const char *group, const char *host, const char *user, const char *dom)
+{
+ char *hst, *usr, *dm;
+ /* Sanity check */
+
+ if (group == NULL || !strlen(group))
+ return (0);
+
+#ifdef YP
+ _yp_innetgr = 1;
+#endif
+ setnetgrent(group);
+#ifdef YP
+ _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(0);
+ ret = _revnetgr_lookup(_netgr_yp_domain,
+ host?"netgroup.byhost":"netgroup.byuser",
+ host?host:user, dom, group);
+ if (ret == 1)
+ return(1);
+ else if (ret == 0 && dom != NULL)
+ return(0);
+ }
+
+ setnetgrent(group);
+#endif /* YP */
+
+ while (getnetgrent(&hst, &usr, &dm))
+ if ((host == NULL || hst == NULL || !strcmp(host, hst)) &&
+ (user == NULL || usr == NULL || !strcmp(user, usr)) &&
+ ( dom == NULL || dm == NULL || !strcmp(dom, dm))) {
+ endnetgrent();
+ return (1);
+ }
+ endnetgrent();
+ return (0);
+}
+
+/*
+ * Parse the netgroup file setting up the linked lists.
+ */
+static int
+parse_netgrp(const char *group)
+{
+ char *spos, *epos;
+ int len, strpos;
+#ifdef DEBUG
+ int fields;
+#endif
+ char *pos, *gpos;
+ struct netgrp *grp;
+ struct linelist *lp = linehead;
+
+ /*
+ * 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 == (struct linelist *)0 &&
+ (lp = read_for_group(group)) == (struct linelist *)0)
+ 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 = (struct netgrp *)malloc(sizeof (struct netgrp));
+ bzero((char *)grp, sizeof (struct netgrp));
+ grp->ng_next = grouphead.gr;
+ grouphead.gr = grp;
+ pos++;
+ gpos = strsep(&pos, ")");
+#ifdef DEBUG
+ fields = 0;
+#endif
+ for (strpos = 0; strpos < 3; strpos++) {
+ if ((spos = strsep(&gpos, ","))) {
+#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) {
+ grp->ng_str[strpos] = (char *)
+ malloc(len + 1);
+ bcopy(spos, grp->ng_str[strpos],
+ len + 1);
+ }
+ } else {
+ /*
+ * All other systems I've tested
+ * return NULL for empty netgroup
+ * fields. It's up to user programs
+ * to handle the NULLs appropriately.
+ */
+ grp->ng_str[strpos] = NULL;
+ }
+ }
+#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",
+ grp->ng_str[NG_HOST] == NULL ? "" : grp->ng_str[NG_HOST],
+ grp->ng_str[NG_USER] == NULL ? "" : ",",
+ grp->ng_str[NG_USER] == NULL ? "" : grp->ng_str[NG_USER],
+ grp->ng_str[NG_DOM] == NULL ? "" : ",",
+ grp->ng_str[NG_DOM] == NULL ? "" : grp->ng_str[NG_DOM],
+ lp->l_groupname);
+#endif
+ } else {
+ spos = strsep(&pos, ", \t");
+ if (parse_netgrp(spos))
+ 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)
+{
+ char *pos, *spos, *linep, *olinep;
+ int len, olen;
+ int cont;
+ struct linelist *lp;
+ char line[LINSIZ + 2];
+#ifdef YP
+ char *result;
+ int resultlen;
+
+ while (_netgr_yp_enabled || 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;
+ }
+ }
+ snprintf(line, LINSIZ, "%s %s", group, result);
+ free(result);
+ }
+#else
+ while (fgets(line, LINSIZ, netf) != NULL) {
+#endif
+ pos = (char *)&line;
+#ifdef YP
+ if (*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 = (struct linelist *)malloc(sizeof (*lp));
+ lp->l_parsed = 0;
+ lp->l_groupname = (char *)malloc(len + 1);
+ 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 = (char *)malloc(olen + len + 1);
+ 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 = linehead;
+ 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 ((struct linelist *)0);
+}
diff --git a/lib/libc/gen/getobjformat.3 b/lib/libc/gen/getobjformat.3
new file mode 100644
index 0000000..8705f01
--- /dev/null
+++ b/lib/libc/gen/getobjformat.3
@@ -0,0 +1,135 @@
+.\" 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 September 7, 1998
+.Dt GETOBJFORMAT 3
+.Os
+.Sh NAME
+.Nm getobjformat
+.Nd get preferred object file format
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In objformat.h
+.Ft int
+.Fn getobjformat "char *buf" "size_t bufsize" "int *argcp" "char **argv"
+.Sh DESCRIPTION
+The
+.Fn getobjformat
+function
+queries several sources to determine the preferred object file
+format, and copies its name into a buffer provided by the caller.
+.Pp
+The object file format is determined as follows.
+If
+.Va argv
+is
+.No non- Ns Ev NULL
+and an explicit command line argument such as
+.Fl aout
+or
+.Fl elf
+is present, then that determines the object file format.
+.Pp
+Otherwise, if the variable
+.Ev OBJFORMAT
+is set in the environment, the object file format is taken from its
+value.
+.Pp
+Otherwise, if the file
+.Pa /etc/objformat
+is readable and contains a line of the form
+.Ql OBJFORMAT=xxx ,
+the object file format is taken from there.
+.Pp
+Otherwise, a built-in system default object file format is returned.
+.Pp
+.Va buf
+points to a user-supplied buffer into which the name of the object
+file format is copied.
+.Va bufsize
+gives the size of the buffer in bytes.
+The string placed in
+.Va buf
+is always null-terminated.
+It is an error if the buffer is too
+small to hold the null-terminated name.
+.Pp
+.Va argv
+points to a
+.Dv NULL Ns -terminated
+argument vector to be scanned for object
+format options.
+.Va argv
+may be
+.Dv NULL ,
+in which case the argument vector is not scanned.
+.Pp
+If
+.Va argcp
+is non-NULL, any object format options are deleted from the
+argument vector, and the updated argument count is stored into
+the integer referenced by
+.Va argcp .
+If
+.Va argcp
+is
+.Dv NULL ,
+the argument vector is left unchanged.
+.Sh RETURN VALUES
+On success,
+.Fn getobjformat
+returns the length of the object file format name, not counting the
+null terminator.
+If the supplied buffer is too small to hold the object file format
+and its null terminator,
+.Fn getobjformat
+returns -1.
+In that case, the contents of the buffer and argument
+vector supplied by the caller are indeterminate.
+.Sh ENVIRONMENT
+.Bl -tag -width OBJFORMAT
+.It Ev OBJFORMAT
+If the environment variable
+.Ev OBJFORMAT
+is set, it overrides the default object file format.
+.Ev OBJFORMAT takes precedence over
+.Pa /etc/objformat .
+.El
+.Sh FILES
+.Bl -tag -width /etc/objformat -compact
+.It Pa /etc/objformat
+If present, specifies the object file format to use.
+Syntax is
+.Ql OBJFORMAT=xxx .
+.El
+.Sh SEE ALSO
+.Xr objformat 1
+.Sh HISTORY
+The
+.Fn getobjformat
+function first appeared in
+.Fx 3.0 .
diff --git a/lib/libc/gen/getobjformat.c b/lib/libc/gen/getobjformat.c
new file mode 100644
index 0000000..7428f36
--- /dev/null
+++ b/lib/libc/gen/getobjformat.c
@@ -0,0 +1,44 @@
+/*-
+ * 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$");
+
+#include <sys/param.h>
+#include <objformat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int
+getobjformat(char *buf, size_t bufsize, int *argcp, char **argv)
+{
+
+ if (bufsize < 4)
+ return -1;
+ strcpy(buf, "elf");
+ return 3;
+}
diff --git a/lib/libc/gen/getosreldate.3 b/lib/libc/gen/getosreldate.3
new file mode 100644
index 0000000..ff4d10e
--- /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 December 2, 2005
+.Dt GETOSRELDATE 3
+.Os
+.Sh NAME
+.Nm getosreldate
+.Nd get the value of
+.Dv __FreeBSD_version
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In osreldate.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 0000000..03a00c1
--- /dev/null
+++ b/lib/libc/gen/getosreldate.c
@@ -0,0 +1,63 @@
+/*
+ * 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. 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.
+ */
+
+#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 <stdlib.h>
+
+#include <osreldate.h>
+
+int
+getosreldate(void)
+{
+ int mib[2];
+ size_t size;
+ int value;
+
+ char *temp;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_OSRELDATE;
+ size = sizeof value;
+ if (sysctl(mib, 2, &value, &size, NULL, 0) == -1)
+ return (-1);
+ if ((temp = getenv("OSVERSION")))
+ value = atoi(temp);
+ return (value);
+}
diff --git a/lib/libc/gen/getpagesize.3 b/lib/libc/gen/getpagesize.3
new file mode 100644
index 0000000..80f2f19
--- /dev/null
+++ b/lib/libc/gen/getpagesize.3
@@ -0,0 +1,65 @@
+.\" 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. 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.
+.\"
+.\" @(#)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 0000000..5e8e723
--- /dev/null
+++ b/lib/libc/gen/getpagesize.c
@@ -0,0 +1,68 @@
+/*
+ * 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. 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.
+ */
+
+#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 <unistd.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()
+{
+ int mib[2];
+ static int value;
+ size_t size;
+
+ if (!value) {
+ mib[0] = CTL_HW;
+ mib[1] = HW_PAGESIZE;
+ size = sizeof value;
+ if (sysctl(mib, 2, &value, &size, NULL, 0) == -1)
+ return (-1);
+ }
+ return (value);
+}
diff --git a/lib/libc/gen/getpass.3 b/lib/libc/gen/getpass.3
new file mode 100644
index 0000000..7a85fc3
--- /dev/null
+++ b/lib/libc/gen/getpass.3
@@ -0,0 +1,97 @@
+.\" Copyright (c) 1989, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. 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.
+.\"
+.\" @(#)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 0000000..12999e5
--- /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 0000000..5ecb243
--- /dev/null
+++ b/lib/libc/gen/getpeereid.c
@@ -0,0 +1,54 @@
+/*
+ * 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 <sys/param.h>
+#include <sys/socket.h>
+#include <sys/ucred.h>
+#include <sys/un.h>
+
+#include <errno.h>
+#include <unistd.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 0000000..53d39a6
--- /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 0000000..fd51d13
--- /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 0000000..dc47181
--- /dev/null
+++ b/lib/libc/gen/getpwent.3
@@ -0,0 +1,319 @@
+.\" 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. 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.
+.\"
+.\" 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 0000000..f729cdf
--- /dev/null
+++ b/lib/libc/gen/getpwent.c
@@ -0,0 +1,2009 @@
+/*-
+ * 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 >= sizeof(pwdb_versions)/sizeof(pwdb_versions[0])) {
+ 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, *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 (!stayopen && st->db != NULL) {
+ (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)
+ 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 rv, e, i;
+
+ for (i = 0; i < sizeof(dtab)/sizeof(dtab[0]) - 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 < (sizeof(x)/sizeof(x[0])) - 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 (!stayopen && st->db != NULL) {
+ (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 0000000..9c2be8f
--- /dev/null
+++ b/lib/libc/gen/getttyent.3
@@ -0,0 +1,213 @@
+.\" Copyright (c) 1989, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. 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.
+.\"
+.\" @(#)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 ttyslot 3 ,
+.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 0000000..ecfdbf0
--- /dev/null
+++ b/lib/libc/gen/getttyent.c
@@ -0,0 +1,303 @@
+/*
+ * 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. 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.
+ */
+
+#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 <dirent.h>
+#include <paths.h>
+
+static char zapchar;
+static FILE *tf;
+static int maxpts = 0;
+static int curpts = 0;
+static int pts_valid = 0;
+static size_t lbsize;
+static char *line;
+
+#define PTS "pts/"
+#define MALLOCCHUNK 100
+
+static char *skip(char *);
+static char *value(char *);
+
+struct ttyent *
+getttynam(tty)
+ 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);
+}
+
+struct ttyent *
+getttyent()
+{
+ static struct ttyent tty;
+ static char devpts_name[] = "pts/4294967295";
+ char *p;
+ int c;
+ size_t i;
+
+ if (!tf && !setttyent())
+ return (NULL);
+ for (;;) {
+ if (!fgets(p = line, lbsize, tf)) {
+ if (pts_valid == 1 && curpts <= maxpts) {
+ sprintf(devpts_name, "pts/%d", curpts++);
+ tty.ty_name = devpts_name;
+ tty.ty_getty = tty.ty_type = NULL;
+ tty.ty_status = TTY_NETWORK;
+ tty.ty_window = NULL;
+ tty.ty_comment = NULL;
+ tty.ty_group = _TTYS_NOGROUP;
+ return (&tty);
+ }
+ return (NULL);
+ }
+ /* extend buffer if line was too big, and retry */
+ while (!index(p, '\n')) {
+ 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_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 = index(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(p)
+ 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(p)
+ char *p;
+{
+
+ return ((p = index(p, '=')) ? ++p : NULL);
+}
+
+int
+setttyent()
+{
+ DIR *devpts_dir;
+
+ if (line == NULL) {
+ if ((line = malloc(MALLOCCHUNK)) == NULL)
+ return (0);
+ lbsize = MALLOCCHUNK;
+ }
+ devpts_dir = opendir(_PATH_DEV PTS);
+ if (devpts_dir) {
+ struct dirent *dp;
+
+ while ((dp = readdir(devpts_dir))) {
+ if (strcmp(dp->d_name, ".") != 0 &&
+ strcmp(dp->d_name, "..") != 0) {
+ if (atoi(dp->d_name) > maxpts) {
+ maxpts = atoi(dp->d_name);
+ pts_valid = 1;
+ curpts = 0;
+ }
+ }
+ }
+ closedir(devpts_dir);
+ }
+ if (tf) {
+ rewind(tf);
+ return (1);
+ } else if ( (tf = fopen(_PATH_TTYS, "r")) )
+ return (1);
+ return (0);
+}
+
+int
+endttyent()
+{
+ int rval;
+
+ pts_valid = 0;
+ /*
+ * 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(tty, flag)
+ const char *tty;
+ int flag;
+{
+ struct ttyent *t;
+
+ return ((t = getttynam(tty)) == NULL) ? 0 : !!(t->ty_status & flag);
+}
+
+
+int
+isdialuptty(tty)
+ const char *tty;
+{
+
+ return isttystat(tty, TTY_DIALUP);
+}
+
+int isnettty(tty)
+ 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 0000000..48eef79
--- /dev/null
+++ b/lib/libc/gen/getusershell.3
@@ -0,0 +1,103 @@
+.\" $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.
+.\" 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.
+.\"
+.\" @(#)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 0000000..62061c1
--- /dev/null
+++ b/lib/libc/gen/getusershell.c
@@ -0,0 +1,274 @@
+/*
+ * 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. 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.
+ */
+
+#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"
+
+/*
+ * Local shells should NOT be added here. They should be added in
+ * /etc/shells.
+ */
+
+static const char *const okshells[] = { _PATH_BSHELL, _PATH_CSHELL, NULL };
+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(rv, cb_data, ap)
+ 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, "r")) == NULL)
+ return NS_UNAVAIL;
+
+ sp = 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(rv, cb_data, ap)
+ 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(rv, cb_data, ap)
+ 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()
+{
+ 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 = NULL;
+ return (okshells);
+ }
+ sl_add(sl, NULL);
+
+ return (const char *const *)(sl->sl_str);
+}
diff --git a/lib/libc/gen/getvfsbyname.3 b/lib/libc/gen/getvfsbyname.3
new file mode 100644
index 0000000..a7cfa2e
--- /dev/null
+++ b/lib/libc/gen/getvfsbyname.3
@@ -0,0 +1,114 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)kvm_getvfsbyname.3 8.3 (Berkeley) 5/4/95
+.\" $FreeBSD$
+.\"
+.Dd May 4, 1995
+.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_SYNTHETIC -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
+.El
+.Sh RETURN VALUES
+.Rv -std getvfsbyname
+.Sh ERRORS
+The following errors may be reported:
+.Bl -tag -width Er
+.It Bq Er EFAULT
+The
+.Fa vfc
+argument
+points to an invalid address.
+.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 mount 2 ,
+.Xr sysctl 3 ,
+.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 0000000..20f389d
--- /dev/null
+++ b/lib/libc/gen/getvfsbyname.c
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ * 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.
+ */
+
+#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(fsname, vfcp)
+ 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 0000000..a9f0458
--- /dev/null
+++ b/lib/libc/gen/glob.3
@@ -0,0 +1,475 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)glob.3 8.3 (Berkeley) 4/16/94
+.\" $FreeBSD$
+.\"
+.Dd September 1, 2004
+.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 *pattern" "int flags" "int (*errfunc)(const char *, int)" "glob_t *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 {
+ int gl_pathc; /* count of total paths so far */
+ int gl_matchc; /* count of paths matching pattern */
+ int 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
+.Tn ASCII
+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 ) .
+This may be unintuitive: a pattern like
+.Ql */Makefile
+will try to
+.Xr stat 2
+.Ql foo/Makefile
+even if
+.Ql foo
+is not a directory, resulting in a
+call to
+.Fa errfunc .
+The error routine can suppress this action by testing for
+.Er ENOENT
+and
+.Er ENOTDIR ;
+however, the
+.Dv GLOB_ERR
+flag will still 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 0
+.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 regexp 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 0000000..8e5ee69
--- /dev/null
+++ b/lib/libc/gen/glob.c
@@ -0,0 +1,956 @@
+/*
+ * 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.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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.
+ */
+
+#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 value of the first byte 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"
+
+#define DOLLAR '$'
+#define DOT '.'
+#define EOS '\0'
+#define LBRACKET '['
+#define NOT '!'
+#define QUESTION '?'
+#define QUOTE '\\'
+#define RANGE '-'
+#define RBRACKET ']'
+#define SEP '/'
+#define STAR '*'
+#define TILDE '~'
+#define UNDERSCORE '_'
+#define LBRACE '{'
+#define RBRACE '}'
+#define SLASH '/'
+#define COMMA ','
+
+#ifndef DEBUG
+
+#define M_QUOTE 0x8000000000ULL
+#define M_PROTECT 0x4000000000ULL
+#define M_MASK 0xffffffffffULL
+#define M_CHAR 0x00ffffffffULL
+
+typedef uint_fast64_t Char;
+
+#else
+
+#define M_QUOTE 0x80
+#define M_PROTECT 0x40
+#define M_MASK 0xff
+#define M_CHAR 0x7f
+
+typedef char Char;
+
+#endif
+
+
+#define CHAR(c) ((Char)((c)&M_CHAR))
+#define META(c) ((Char)((c)|M_QUOTE))
+#define M_ALL META('*')
+#define M_END META(']')
+#define M_NOT META('!')
+#define M_ONE META('?')
+#define M_RNG META('-')
+#define M_SET META('[')
+#define ismeta(c) (((c)&M_QUOTE) != 0)
+
+
+static int compare(const void *, const void *);
+static int g_Ctoc(const Char *, char *, u_int);
+static int g_lstat(Char *, struct stat *, glob_t *);
+static DIR *g_opendir(Char *, glob_t *);
+static Char *g_strchr(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 *, int *);
+static int glob1(Char *, glob_t *, int *);
+static int glob2(Char *, Char *, Char *, Char *, glob_t *, int *);
+static int glob3(Char *, Char *, Char *, Char *, Char *, glob_t *, int *);
+static int globextend(const Char *, glob_t *, int *);
+static const Char *
+ globtilde(const Char *, Char *, size_t, glob_t *);
+static int globexp1(const Char *, glob_t *, int *);
+static int globexp2(const Char *, const Char *, glob_t *, int *, int *);
+static int match(Char *, Char *, Char *);
+#ifdef DEBUG
+static void qprintf(const char *, Char *);
+#endif
+
+int
+glob(pattern, flags, errfunc, pglob)
+ const char *pattern;
+ int flags, (*errfunc)(const char *, int);
+ glob_t *pglob;
+{
+ const u_char *patnext;
+ int limit;
+ Char *bufnext, *bufend, patbuf[MAXPATHLEN], prot;
+ mbstate_t mbs;
+ wchar_t wc;
+ size_t clen;
+
+ patnext = (u_char *) 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 = pglob->gl_matchc;
+ if (limit == 0)
+ limit = ARG_MAX;
+ } else
+ limit = 0;
+ pglob->gl_flags = flags & ~GLOB_MAGCHAR;
+ pglob->gl_errfunc = errfunc;
+ pglob->gl_matchc = 0;
+
+ bufnext = patbuf;
+ bufend = bufnext + MAXPATHLEN - 1;
+ if (flags & GLOB_NOESCAPE) {
+ memset(&mbs, 0, sizeof(mbs));
+ while (bufend - bufnext >= MB_CUR_MAX) {
+ clen = mbrtowc(&wc, patnext, MB_LEN_MAX, &mbs);
+ if (clen == (size_t)-1 || clen == (size_t)-2)
+ return (GLOB_NOMATCH);
+ else if (clen == 0)
+ break;
+ *bufnext++ = wc;
+ patnext += clen;
+ }
+ } else {
+ /* Protect the quoted characters. */
+ memset(&mbs, 0, sizeof(mbs));
+ while (bufend - bufnext >= MB_CUR_MAX) {
+ if (*patnext == QUOTE) {
+ if (*++patnext == EOS) {
+ *bufnext++ = QUOTE | M_PROTECT;
+ 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 (GLOB_NOMATCH);
+ else if (clen == 0)
+ break;
+ *bufnext++ = wc | prot;
+ patnext += clen;
+ }
+ }
+ *bufnext = EOS;
+
+ if (flags & GLOB_BRACE)
+ return globexp1(patbuf, pglob, &limit);
+ else
+ return glob0(patbuf, pglob, &limit);
+}
+
+/*
+ * 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(pattern, pglob, limit)
+ const Char *pattern;
+ glob_t *pglob;
+ int *limit;
+{
+ const Char* ptr = pattern;
+ int rv;
+
+ /* Protect a single {}, for find(1), like csh */
+ if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS)
+ return glob0(pattern, pglob, limit);
+
+ while ((ptr = (const Char *) g_strchr((Char *) ptr, LBRACE)) != NULL)
+ if (!globexp2(ptr, pattern, pglob, &rv, limit))
+ return rv;
+
+ return glob0(pattern, pglob, limit);
+}
+
+
+/*
+ * 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(ptr, pattern, pglob, rv, limit)
+ const Char *ptr, *pattern;
+ glob_t *pglob;
+ int *rv, *limit;
+{
+ int i;
+ 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; 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) {
+ *rv = glob0(patbuf, pglob, limit);
+ return 0;
+ }
+
+ 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);
+
+ /* move after the comma, to the next string */
+ pl = pm + 1;
+ }
+ break;
+
+ default:
+ break;
+ }
+ *rv = 0;
+ return 0;
+}
+
+
+
+/*
+ * expand tilde from the passwd file.
+ */
+static const Char *
+globtilde(pattern, patbuf, patbuf_len, pglob)
+ const Char *pattern;
+ Char *patbuf;
+ size_t patbuf_len;
+ glob_t *pglob;
+{
+ struct passwd *pwd;
+ char *h;
+ const Char *p;
+ Char *b, *eb;
+
+ 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, h = (char *) patbuf;
+ h < (char *)eb && *p && *p != SLASH; *h++ = *p++)
+ continue;
+
+ *h = EOS;
+
+ if (((char *) 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 ((pwd = getpwnam((char*) patbuf)) == NULL)
+ return pattern;
+ else
+ h = pwd->pw_dir;
+ }
+
+ /* Copy the home directory */
+ for (b = patbuf; b < eb && *h; *b++ = *h++)
+ continue;
+
+ /* Append the rest of the pattern */
+ while (b < eb && (*b++ = *p++) != EOS)
+ continue;
+ *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(pattern, pglob, limit)
+ const Char *pattern;
+ glob_t *pglob;
+ int *limit;
+{
+ const Char *qpatnext;
+ int c, err, oldpathc;
+ Char *bufnext, patbuf[MAXPATHLEN];
+
+ qpatnext = globtilde(pattern, patbuf, MAXPATHLEN, pglob);
+ 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((Char *) 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 there was no match we are going to append the pattern
+ * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
+ * and the pattern did not contain any magic characters
+ * GLOB_NOMAGIC is there just for compatibility with csh.
+ */
+ if (pglob->gl_pathc == oldpathc) {
+ if (((pglob->gl_flags & GLOB_NOCHECK) ||
+ ((pglob->gl_flags & GLOB_NOMAGIC) &&
+ !(pglob->gl_flags & GLOB_MAGCHAR))))
+ return(globextend(pattern, pglob, limit));
+ else
+ return(GLOB_NOMATCH);
+ }
+ 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(p, q)
+ const void *p, *q;
+{
+ return(strcmp(*(char **)p, *(char **)q));
+}
+
+static int
+glob1(pattern, pglob, limit)
+ Char *pattern;
+ glob_t *pglob;
+ int *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(pathbuf, pathend, pathend_last, pattern, pglob, limit)
+ Char *pathbuf, *pathend, *pathend_last, *pattern;
+ glob_t *pglob;
+ int *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_MARK) &&
+ 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)
+ return (GLOB_ABORTED);
+ *pathend++ = SEP;
+ *pathend = EOS;
+ }
+ ++pglob->gl_matchc;
+ return(globextend(pathbuf, pglob, limit));
+ }
+
+ /* Find end of next segment, copy tentatively to pathend. */
+ q = pathend;
+ p = pattern;
+ while (*p != EOS && *p != SEP) {
+ if (ismeta(*p))
+ anymeta = 1;
+ if (q + 1 > pathend_last)
+ return (GLOB_ABORTED);
+ *q++ = *p++;
+ }
+
+ if (!anymeta) { /* No expansion, do next segment. */
+ pathend = q;
+ pattern = p;
+ while (*pattern == SEP) {
+ if (pathend + 1 > pathend_last)
+ return (GLOB_ABORTED);
+ *pathend++ = *pattern++;
+ }
+ } else /* Need expansion, recurse. */
+ return(glob3(pathbuf, pathend, pathend_last, pattern, p,
+ pglob, limit));
+ }
+ /* NOTREACHED */
+}
+
+static int
+glob3(pathbuf, pathend, pathend_last, pattern, restpattern, pglob, limit)
+ Char *pathbuf, *pathend, *pathend_last, *pattern, *restpattern;
+ glob_t *pglob;
+ int *limit;
+{
+ struct dirent *dp;
+ DIR *dirp;
+ int err;
+ char buf[MAXPATHLEN];
+
+ /*
+ * The readdirfunc declaration can't be prototyped, because it is
+ * assigned, below, to two functions which are prototyped in glob.h
+ * and dirent.h as taking pointers to differently typed opaque
+ * structures.
+ */
+ struct dirent *(*readdirfunc)();
+
+ if (pathend > pathend_last)
+ return (GLOB_ABORTED);
+ *pathend = EOS;
+ errno = 0;
+
+ if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
+ /* TODO: don't call for ENOENT or ENOTDIR? */
+ if (pglob->gl_errfunc) {
+ if (g_Ctoc(pathbuf, buf, sizeof(buf)))
+ return (GLOB_ABORTED);
+ if (pglob->gl_errfunc(buf, errno) ||
+ pglob->gl_flags & GLOB_ERR)
+ return (GLOB_ABORTED);
+ }
+ return(0);
+ }
+
+ err = 0;
+
+ /* Search directory for matching names. */
+ if (pglob->gl_flags & GLOB_ALTDIRFUNC)
+ readdirfunc = pglob->gl_readdir;
+ else
+ readdirfunc = readdir;
+ while ((dp = (*readdirfunc)(dirp))) {
+ u_char *sc;
+ Char *dc;
+ wchar_t wc;
+ size_t clen;
+ mbstate_t mbs;
+
+ /* Initial DOT must be matched literally. */
+ if (dp->d_name[0] == DOT && *pattern != DOT)
+ continue;
+ memset(&mbs, 0, sizeof(mbs));
+ dc = pathend;
+ sc = (u_char *) dp->d_name;
+ while (dc < pathend_last) {
+ clen = mbrtowc(&wc, sc, MB_LEN_MAX, &mbs);
+ if (clen == (size_t)-1 || clen == (size_t)-2) {
+ wc = *sc;
+ clen = 1;
+ memset(&mbs, 0, sizeof(mbs));
+ }
+ if ((*dc++ = wc) == EOS)
+ break;
+ sc += clen;
+ }
+ if (!match(pathend, pattern, restpattern)) {
+ *pathend = EOS;
+ continue;
+ }
+ err = glob2(pathbuf, --dc, pathend_last, restpattern,
+ pglob, limit);
+ if (err)
+ break;
+ }
+
+ if (pglob->gl_flags & GLOB_ALTDIRFUNC)
+ (*pglob->gl_closedir)(dirp);
+ else
+ closedir(dirp);
+ return(err);
+}
+
+
+/*
+ * Extend the gl_pathv member of a glob_t structure to accomodate 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(path, pglob, limit)
+ const Char *path;
+ glob_t *pglob;
+ int *limit;
+{
+ char **pathv;
+ int i;
+ u_int newsize, len;
+ char *copy;
+ const Char *p;
+
+ if (*limit && pglob->gl_pathc > *limit) {
+ errno = 0;
+ return (GLOB_NOSPACE);
+ }
+
+ newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
+ pathv = pglob->gl_pathv ?
+ realloc((char *)pglob->gl_pathv, newsize) :
+ malloc(newsize);
+ if (pathv == NULL) {
+ if (pglob->gl_pathv) {
+ free(pglob->gl_pathv);
+ pglob->gl_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; --i >= 0; )
+ *--pathv = NULL;
+ }
+ pglob->gl_pathv = pathv;
+
+ for (p = path; *p++;)
+ continue;
+ len = MB_CUR_MAX * (size_t)(p - path); /* XXX overallocation */
+ if ((copy = malloc(len)) != NULL) {
+ if (g_Ctoc(path, copy, len)) {
+ free(copy);
+ 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(name, pat, patend)
+ Char *name, *pat, *patend;
+{
+ int ok, negate_range;
+ Char c, k;
+
+ 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)) != EOS)
+ ++pat;
+ while (((c = *pat++) & M_MASK) != M_END)
+ if ((*pat & M_MASK) == M_RNG) {
+ if (__collate_load_error ?
+ CHAR(c) <= CHAR(k) && CHAR(k) <= CHAR(pat[1]) :
+ __collate_range_cmp(CHAR(c), CHAR(k)) <= 0
+ && __collate_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(pglob)
+ glob_t *pglob;
+{
+ int 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(str, pglob)
+ Char *str;
+ glob_t *pglob;
+{
+ char buf[MAXPATHLEN];
+
+ if (!*str)
+ strcpy(buf, ".");
+ else {
+ if (g_Ctoc(str, buf, sizeof(buf)))
+ return (NULL);
+ }
+
+ if (pglob->gl_flags & GLOB_ALTDIRFUNC)
+ return((*pglob->gl_opendir)(buf));
+
+ return(opendir(buf));
+}
+
+static int
+g_lstat(fn, sb, pglob)
+ Char *fn;
+ struct stat *sb;
+ glob_t *pglob;
+{
+ char buf[MAXPATHLEN];
+
+ 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(fn, sb, pglob)
+ Char *fn;
+ struct stat *sb;
+ glob_t *pglob;
+{
+ char buf[MAXPATHLEN];
+
+ 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 Char *
+g_strchr(str, ch)
+ Char *str;
+ wchar_t ch;
+{
+ do {
+ if (*str == ch)
+ return (str);
+ } while (*str++);
+ return (NULL);
+}
+
+static int
+g_Ctoc(str, buf, len)
+ const Char *str;
+ char *buf;
+ u_int len;
+{
+ mbstate_t mbs;
+ size_t clen;
+
+ memset(&mbs, 0, sizeof(mbs));
+ while (len >= MB_CUR_MAX) {
+ clen = wcrtomb(buf, *str, &mbs);
+ if (clen == (size_t)-1)
+ return (1);
+ if (*str == L'\0')
+ return (0);
+ str++;
+ buf += clen;
+ len -= clen;
+ }
+ return (1);
+}
+
+#ifdef DEBUG
+static void
+qprintf(str, s)
+ const char *str;
+ Char *s;
+{
+ Char *p;
+
+ (void)printf("%s:\n", str);
+ for (p = s; *p; p++)
+ (void)printf("%c", CHAR(*p));
+ (void)printf("\n");
+ for (p = s; *p; p++)
+ (void)printf("%c", *p & M_PROTECT ? '"' : ' ');
+ (void)printf("\n");
+ for (p = s; *p; 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 0000000..3df1ffd
--- /dev/null
+++ b/lib/libc/gen/initgroups.3
@@ -0,0 +1,90 @@
+.\" 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. 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.
+.\"
+.\" @(#)initgroups.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.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 .
+.Sh SEE ALSO
+.Xr setgroups 2 ,
+.Xr getgrouplist 3
+.Sh HISTORY
+The
+.Fn initgroups
+function appeared in
+.Bx 4.2 .
+.Sh BUGS
+The
+.Fn getgrouplist
+function called by
+.Fn initgroups
+uses the routines based on
+.Xr getgrent 3 .
+If the invoking program uses any of these routines,
+the group structure will
+be overwritten in the call to
+.Fn initgroups .
diff --git a/lib/libc/gen/initgroups.c b/lib/libc/gen/initgroups.c
new file mode 100644
index 0000000..82bbb3a
--- /dev/null
+++ b/lib/libc/gen/initgroups.c
@@ -0,0 +1,63 @@
+/*
+ * 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. 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.
+ */
+
+#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 <stdio.h>
+#include "namespace.h"
+#include <err.h>
+#include "un-namespace.h"
+#include <unistd.h>
+
+int
+initgroups(uname, agroup)
+ const char *uname;
+ gid_t agroup;
+{
+ int ngroups;
+ /*
+ * Provide space for one group more than NGROUPS to allow
+ * setgroups to fail and set errno.
+ */
+ gid_t groups[NGROUPS + 1];
+
+ ngroups = NGROUPS + 1;
+ getgrouplist(uname, agroup, groups, &ngroups);
+ return (setgroups(ngroups, groups));
+}
diff --git a/lib/libc/gen/isatty.c b/lib/libc/gen/isatty.c
new file mode 100644
index 0000000..c70cb1a
--- /dev/null
+++ b/lib/libc/gen/isatty.c
@@ -0,0 +1,52 @@
+/*
+ * 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. 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.
+ */
+
+#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(fd)
+ 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 0000000..0106155
--- /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 0000000..4a4152a
--- /dev/null
+++ b/lib/libc/gen/isinf.c
@@ -0,0 +1,70 @@
+/*-
+ * 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.
+ */
+
+__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);
+#ifndef __alpha__
+ return (u.bits.exp == 32767 && u.bits.manl == 0 && u.bits.manh == 0);
+#else
+ return (u.bits.exp == 2047 && 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 0000000..ec81362
--- /dev/null
+++ b/lib/libc/gen/isnan.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"
+
+/*
+ * 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(__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);
+}
diff --git a/lib/libc/gen/jrand48.c b/lib/libc/gen/jrand48.c
new file mode 100644
index 0000000..1707620
--- /dev/null
+++ b/lib/libc/gen/jrand48.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
+jrand48(unsigned short xseed[3])
+{
+ _dorand48(xseed);
+ return ((long) xseed[2] << 16) + (long) xseed[1];
+}
diff --git a/lib/libc/gen/lcong48.c b/lib/libc/gen/lcong48.c
new file mode 100644
index 0000000..ab0d1f7
--- /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 0000000..dcf34eb
--- /dev/null
+++ b/lib/libc/gen/ldexp.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.
+.\" 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.
+.\"
+.\" @(#)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 0000000..887f673
--- /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/lockf.3 b/lib/libc/gen/lockf.3
new file mode 100644
index 0000000..cb3b8ef
--- /dev/null
+++ b/lib/libc/gen/lockf.3
@@ -0,0 +1,273 @@
+.\" $NetBSD: lockf.3,v 1.2 1998/02/05 18:47:28 perry 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.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the NetBSD
+.\" Foundation, Inc. and its contributors.
+.\" 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 December 19, 1997
+.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 filedes" "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 filedes
+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 filedes
+is not a valid open file descriptor.
+.Pp
+The argument
+.Fa function
+is
+.Dv F_LOCK
+or
+.Dv F_TLOCK ,
+and
+.Fa filedes
+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 filedes
+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 0000000..c448f18
--- /dev/null
+++ b/lib/libc/gen/lockf.c
@@ -0,0 +1,89 @@
+/*-
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 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.
+ */
+
+/* $NetBSD: lockf.c,v 1.1 1997/12/20 20:23:18 kleink Exp $ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+int
+lockf(filedes, function, size)
+ 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 (_fcntl(filedes, F_GETLK, &fl) == -1)
+ return (-1);
+ if (fl.l_type == F_UNLCK || fl.l_pid == getpid())
+ return (0);
+ errno = EAGAIN;
+ return (-1);
+ /* NOTREACHED */
+ default:
+ errno = EINVAL;
+ return (-1);
+ /* NOTREACHED */
+ }
+
+ return (_fcntl(filedes, cmd, &fl));
+}
diff --git a/lib/libc/gen/lrand48.c b/lib/libc/gen/lrand48.c
new file mode 100644
index 0000000..44a7f5d
--- /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 0000000..ad55e7a
--- /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 0000000..4afd4e6
--- /dev/null
+++ b/lib/libc/gen/modf.3
@@ -0,0 +1,75 @@
+.\" 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. 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.
+.\"
+.\" @(#)modf.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt MODF 3
+.Os
+.Sh NAME
+.Nm modf
+.Nd extract signed integral and fractional values from floating-point number
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In math.h
+.Ft double
+.Fn modf "double value" "double *iptr"
+.Sh DESCRIPTION
+The
+.Fn modf
+function breaks 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
+.Vt double
+in the object pointed to by
+.Fa iptr .
+.Sh RETURN VALUES
+The
+.Fn modf
+function returns the signed fractional part of
+.Fa value .
+.Sh SEE ALSO
+.Xr frexp 3 ,
+.Xr ldexp 3 ,
+.Xr math 3
+.Sh STANDARDS
+The
+.Fn modf
+function conforms to
+.St -isoC .
diff --git a/lib/libc/gen/mrand48.c b/lib/libc/gen/mrand48.c
new file mode 100644
index 0000000..ef20fb87b
--- /dev/null
+++ b/lib/libc/gen/mrand48.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
+mrand48(void)
+{
+ _dorand48(_rand48_seed);
+ return ((long) _rand48_seed[2] << 16) + (long) _rand48_seed[1];
+}
diff --git a/lib/libc/gen/msgctl.3 b/lib/libc/gen/msgctl.3
new file mode 100644
index 0000000..f049a1c
--- /dev/null
+++ b/lib/libc/gen/msgctl.3
@@ -0,0 +1,214 @@
+.\" $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 November 24, 1997
+.Dt MSGCTL 3
+.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 */
+ u_long msg_cbytes; /* number of bytes in use on the queue */
+ u_long msg_qnum; /* number of msgs in the queue */
+ u_long 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() */
+ long msg_pad1;
+ time_t msg_rtime; /* time of last msgrcv() */
+ long msg_pad2;
+ time_t msg_ctime; /* time of last msgctl() */
+ long msg_pad3;
+ long msg_pad4[4];
+};
+.Ed
+.Pp
+The
+.Vt ipc_perm
+structure used inside the
+.Vt shmid_ds
+structure is defined in
+.In sys/ipc.h
+and looks like this:
+.Bd -literal
+struct ipc_perm {
+ ushort cuid; /* creator user id */
+ ushort cgid; /* creator group id */
+ ushort uid; /* user id */
+ ushort gid; /* group id */
+ ushort mode; /* r/w permission */
+ ushort seq; /* sequence # (to generate unique msg/sem/shm id) */
+ 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 3
+and
+.Xr msgrcv 3 )
+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 3 ,
+.Xr msgrcv 3 ,
+.Xr msgsnd 3
+.Sh HISTORY
+Message queues appeared in the first release of
+.At V .
diff --git a/lib/libc/gen/msgget.3 b/lib/libc/gen/msgget.3
new file mode 100644
index 0000000..e257c60
--- /dev/null
+++ b/lib/libc/gen/msgget.3
@@ -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 August 17, 1995
+.Dt MSGGET 3
+.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 3 )
+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 3 ,
+.Xr msgrcv 3 ,
+.Xr msgsnd 3
+.Sh HISTORY
+Message queues appeared in the first release of
+.At V .
diff --git a/lib/libc/gen/msgrcv.3 b/lib/libc/gen/msgrcv.3
new file mode 100644
index 0000000..e554dcd
--- /dev/null
+++ b/lib/libc/gen/msgrcv.3
@@ -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 June 15, 2005
+.Dt MSGRCV 3
+.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 int
+.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 3 ,
+.Xr msgget 3 ,
+.Xr msgsnd 3
+.Sh HISTORY
+Message queues appeared in the first release of
+.At V .
diff --git a/lib/libc/gen/msgsnd.3 b/lib/libc/gen/msgsnd.3
new file mode 100644
index 0000000..89e9d75
--- /dev/null
+++ b/lib/libc/gen/msgsnd.3
@@ -0,0 +1,179 @@
+.\" $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 November 24, 1997
+.Dt MSGSND 3
+.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 3 ) ,
+.Va mtext
+is an array of bytes, with a size up to that of the system limit
+.Pf ( 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 3 ) ,
+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 less than 0, or 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/gen/nftw.c b/lib/libc/gen/nftw.c
new file mode 100644
index 0000000..43110c1
--- /dev/null
+++ b/lib/libc/gen/nftw.c
@@ -0,0 +1,117 @@
+/* $OpenBSD: nftw.c,v 1.4 2004/07/07 16:05:23 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.
+ */
+
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$OpenBSD: nftw.c,v 1.4 2004/07/07 16:05:23 millert Exp $";
+#endif /* LIBC_SCCS and not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <fts.h>
+#include <ftw.h>
+#include <limits.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 || nfds > OPEN_MAX) {
+ 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_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;
+ case FTS_DC:
+ errno = ELOOP;
+ /* FALLTHROUGH */
+ 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 0000000..bfb01ae
--- /dev/null
+++ b/lib/libc/gen/nice.3
@@ -0,0 +1,73 @@
+.\" 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. 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.
+.\"
+.\" @(#)nice.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.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 obtains the scheduling priority of the process
+from the system and sets it to the priority value specified in
+.Fa incr .
+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 SEE ALSO
+.Xr nice 1 ,
+.Xr fork 2 ,
+.Xr setpriority 2 ,
+.Xr renice 8
+.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 0000000..8ec41d1
--- /dev/null
+++ b/lib/libc/gen/nice.c
@@ -0,0 +1,60 @@
+/*
+ * 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. 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.
+ */
+
+#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(incr)
+ int incr;
+{
+ int prio;
+
+ errno = 0;
+ prio = getpriority(PRIO_PROCESS, 0);
+ if (prio == -1 && errno)
+ return (-1);
+ return (setpriority(PRIO_PROCESS, 0, prio + incr));
+}
diff --git a/lib/libc/gen/nlist.3 b/lib/libc/gen/nlist.3
new file mode 100644
index 0000000..d72dad6
--- /dev/null
+++ b/lib/libc/gen/nlist.3
@@ -0,0 +1,81 @@
+.\" 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. 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.
+.\"
+.\" @(#)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 0000000..73b9ea1
--- /dev/null
+++ b/lib/libc/gen/nlist.c
@@ -0,0 +1,416 @@
+/*
+ * 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. 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.
+ */
+
+#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"
+
+#define _NLIST_DO_AOUT
+#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
+nlist(name, list)
+ const char *name;
+ struct nlist *list;
+{
+ int fd, n;
+
+ fd = _open(name, O_RDONLY, 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(fd, list)
+ int fd;
+ struct nlist *list;
+{
+ int n = -1, i;
+
+ for (i = 0; i < sizeof(nlist_fn) / sizeof(nlist_fn[0]); 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(fd, list)
+ 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__(ehdr)
+ 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(fd, list)
+ 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, 0, 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, 0, 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(nl, s, shdr, shnum)
+ 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 0000000..16c8ca1
--- /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 0000000..c076abb
--- /dev/null
+++ b/lib/libc/gen/opendir.c
@@ -0,0 +1,287 @@
+/*
+ * 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. 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.
+ */
+
+#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 "telldir.h"
+/*
+ * Open a directory.
+ */
+DIR *
+opendir(name)
+ const char *name;
+{
+
+ return (__opendir2(name, DTF_HIDEW|DTF_NODUP));
+}
+
+DIR *
+__opendir2(name, flags)
+ const char *name;
+ int flags;
+{
+ DIR *dirp;
+ int fd;
+ int incr;
+ int saved_errno;
+ int unionstack;
+ struct stat statb;
+
+ /*
+ * stat() before _open() because opening of special files may be
+ * harmful. _fstat() after open because the file may have changed.
+ */
+ if (stat(name, &statb) != 0)
+ return (NULL);
+ if (!S_ISDIR(statb.st_mode)) {
+ errno = ENOTDIR;
+ return (NULL);
+ }
+ if ((fd = _open(name, O_RDONLY | O_NONBLOCK)) == -1)
+ return (NULL);
+ dirp = NULL;
+ if (_fstat(fd, &statb) != 0)
+ goto fail;
+ if (!S_ISDIR(statb.st_mode)) {
+ errno = ENOTDIR;
+ goto fail;
+ }
+ if (_fcntl(fd, F_SETFD, FD_CLOEXEC) == -1 ||
+ (dirp = malloc(sizeof(DIR) + sizeof(struct _telldir))) == NULL)
+ goto fail;
+
+ 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) {
+ int len = 0;
+ int space = 0;
+ char *buf = 0;
+ char *ddptr = 0;
+ char *ddeptr;
+ int n;
+ struct dirent **dpv;
+
+ /*
+ * 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.
+ */
+
+ do {
+ /*
+ * Always make at least DIRBLKSIZ bytes
+ * available to _getdirentries
+ */
+ if (space < DIRBLKSIZ) {
+ space += incr;
+ len += incr;
+ buf = reallocf(buf, len);
+ if (buf == NULL)
+ goto fail;
+ ddptr = buf + (len - space);
+ }
+
+ n = _getdirentries(fd, ddptr, space, &dirp->dd_seek);
+ if (n > 0) {
+ ddptr += n;
+ space -= n;
+ }
+ } while (n > 0);
+
+ ddeptr = ddptr;
+ flags |= __DTF_READALL;
+
+ /*
+ * Re-open the directory.
+ * This has the effect of rewinding back to the
+ * top of the union stack and is needed by
+ * programs which plan to fchdir to a descriptor
+ * which has also been read -- see fts.c.
+ */
+ if (flags & DTF_REWIND) {
+ (void)_close(fd);
+ if ((fd = _open(name, O_RDONLY)) == -1) {
+ saved_errno = errno;
+ free(buf);
+ free(dirp);
+ errno = saved_errno;
+ return (NULL);
+ }
+ }
+
+ /*
+ * 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 = 0;;) {
+ 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), alphasort);
+
+ 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 &&
+ (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;
+ } else {
+ dirp->dd_len = incr;
+ dirp->dd_size = 0;
+ dirp->dd_buf = malloc(dirp->dd_len);
+ if (dirp->dd_buf == NULL)
+ goto fail;
+ dirp->dd_seek = 0;
+ flags &= ~DTF_REWIND;
+ }
+
+ dirp->dd_loc = 0;
+ dirp->dd_fd = fd;
+ dirp->dd_flags = flags;
+ dirp->dd_lock = NULL;
+
+ /*
+ * Set up seek point for rewinddir.
+ */
+ dirp->dd_rewind = telldir(dirp);
+
+ return (dirp);
+
+fail:
+ saved_errno = errno;
+ free(dirp);
+ (void)_close(fd);
+ errno = saved_errno;
+ return (NULL);
+}
diff --git a/lib/libc/gen/pause.3 b/lib/libc/gen/pause.3
new file mode 100644
index 0000000..1822283
--- /dev/null
+++ b/lib/libc/gen/pause.3
@@ -0,0 +1,86 @@
+.\" 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. 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.
+.\"
+.\" @(#)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 0000000..f1b5c25
--- /dev/null
+++ b/lib/libc/gen/pause.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.
+ * 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.
+ */
+
+#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>
+
+/*
+ * Backwards compatible pause.
+ */
+int
+__pause()
+{
+ return sigpause(sigblock(0L));
+}
+__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 0000000..60cef63
--- /dev/null
+++ b/lib/libc/gen/pmadvise.c
@@ -0,0 +1,16 @@
+/*
+ * 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>
+
+int
+posix_madvise(void *address, size_t size, int how)
+{
+ return madvise(address, size, how);
+}
diff --git a/lib/libc/gen/popen.3 b/lib/libc/gen/popen.3
new file mode 100644
index 0000000..ae020da
--- /dev/null
+++ b/lib/libc/gen/popen.3
@@ -0,0 +1,201 @@
+.\" 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. 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.
+.\"
+.\" @(#)popen.3 8.2 (Berkeley) 5/3/95
+.\" $FreeBSD$
+.\"
+.Dd May 3, 1995
+.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
+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 0000000..5cb57fb
--- /dev/null
+++ b/lib/libc/gen/popen.c
@@ -0,0 +1,208 @@
+/*
+ * 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.
+ * 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.
+ */
+
+#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/wait.h>
+
+#include <signal.h>
+#include <errno.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;
+
+static struct pid {
+ struct pid *next;
+ FILE *fp;
+ pid_t pid;
+} *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(command, type)
+ const char *command, *type;
+{
+ struct pid *cur;
+ FILE *iop;
+ int pdes[2], pid, twoway;
+ char *argv[4];
+ struct pid *p;
+
+ /*
+ * 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])
+ return (NULL);
+ }
+ if (pipe(pdes) < 0)
+ return (NULL);
+
+ if ((cur = malloc(sizeof(struct pid))) == NULL) {
+ (void)_close(pdes[0]);
+ (void)_close(pdes[1]);
+ 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();
+ (void)_close(pdes[0]);
+ (void)_close(pdes[1]);
+ free(cur);
+ 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.
+ */
+ (void)_close(pdes[0]);
+ if (pdes[1] != STDOUT_FILENO) {
+ (void)_dup2(pdes[1], STDOUT_FILENO);
+ (void)_close(pdes[1]);
+ if (twoway)
+ (void)_dup2(STDOUT_FILENO, STDIN_FILENO);
+ } else if (twoway && (pdes[1] != STDIN_FILENO))
+ (void)_dup2(pdes[1], STDIN_FILENO);
+ } else {
+ if (pdes[0] != STDIN_FILENO) {
+ (void)_dup2(pdes[0], STDIN_FILENO);
+ (void)_close(pdes[0]);
+ }
+ (void)_close(pdes[1]);
+ }
+ for (p = pidlist; p; p = p->next) {
+ (void)_close(fileno(p->fp));
+ }
+ _execve(_PATH_BSHELL, argv, environ);
+ _exit(127);
+ /* NOTREACHED */
+ }
+ THREAD_UNLOCK();
+
+ /* Parent; assume fdopen can't fail. */
+ if (*type == 'r') {
+ iop = fdopen(pdes[0], type);
+ (void)_close(pdes[1]);
+ } else {
+ iop = fdopen(pdes[1], type);
+ (void)_close(pdes[0]);
+ }
+
+ /* Link into list of file descriptors. */
+ cur->fp = iop;
+ cur->pid = pid;
+ THREAD_LOCK();
+ cur->next = pidlist;
+ pidlist = cur;
+ THREAD_UNLOCK();
+
+ 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(iop)
+ FILE *iop;
+{
+ struct pid *cur, *last;
+ int pstat;
+ pid_t pid;
+
+ /*
+ * Find the appropriate file pointer and remove it from the list.
+ */
+ THREAD_LOCK();
+ for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next)
+ if (cur->fp == iop)
+ break;
+ if (cur == NULL) {
+ THREAD_UNLOCK();
+ return (-1);
+ }
+ if (last == NULL)
+ pidlist = cur->next;
+ else
+ last->next = cur->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/posixshm.c b/lib/libc/gen/posixshm.c
new file mode 100644
index 0000000..05fc1c9
--- /dev/null
+++ b/lib/libc/gen/posixshm.c
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+int
+shm_open(const char *path, int flags, mode_t mode)
+{
+ int fd;
+ struct stat stab;
+
+ if ((flags & O_ACCMODE) == O_WRONLY)
+ return (EINVAL);
+
+ fd = _open(path, flags, mode);
+ if (fd != -1) {
+ if (_fstat(fd, &stab) != 0 || !S_ISREG(stab.st_mode)) {
+ _close(fd);
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (_fcntl(fd, F_SETFL, (int)FPOSIXSHM) != 0) {
+ _close(fd);
+ return (-1);
+ }
+ }
+ return (fd);
+}
+
+int
+shm_unlink(const char *path)
+{
+ return (unlink(path));
+}
diff --git a/lib/libc/gen/pselect.3 b/lib/libc/gen/pselect.3
new file mode 100644
index 0000000..a56a0a8
--- /dev/null
+++ b/lib/libc/gen/pselect.3
@@ -0,0 +1,127 @@
+.\"
+.\" 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 June 16, 2002
+.Dt PSELECT 3
+.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 IMPLEMENTATION NOTES
+The
+.Fn pselect
+function is implemented in the C library as a wrapper around
+.Fn select .
+.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
+.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
+.Fn pselect
+function and this manual page were written by
+.An Garrett Wollman Aq wollman@FreeBSD.org .
diff --git a/lib/libc/gen/pselect.c b/lib/libc/gen/pselect.c
new file mode 100644
index 0000000..28066a2
--- /dev/null
+++ b/lib/libc/gen/pselect.c
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/select.h>
+#include <sys/time.h>
+
+#include <errno.h>
+#include <signal.h>
+#include "un-namespace.h"
+
+__weak_reference(__pselect, pselect);
+
+/*
+ * Emulate the POSIX 1003.1g-2000 `pselect' interface. This is the
+ * same as the traditional BSD `select' function, except that it uses
+ * a timespec rather than a timeval, doesn't modify the timeout argument,
+ * and allows the user to specify a signal mask to apply during the select.
+ */
+int
+__pselect(int count, fd_set * __restrict rfds, fd_set * __restrict wfds,
+ fd_set * __restrict efds, const struct timespec * __restrict timo,
+ const sigset_t * __restrict mask)
+{
+ sigset_t omask;
+ struct timeval tvtimo, *tvp;
+ int rv, sverrno;
+
+ if (timo) {
+ TIMESPEC_TO_TIMEVAL(&tvtimo, timo);
+ tvp = &tvtimo;
+ } else
+ tvp = 0;
+
+ if (mask != 0) {
+ rv = _sigprocmask(SIG_SETMASK, mask, &omask);
+ if (rv != 0)
+ return rv;
+ }
+
+ rv = _select(count, rfds, wfds, efds, tvp);
+ if (mask != 0) {
+ sverrno = errno;
+ _sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0);
+ errno = sverrno;
+ }
+
+ return rv;
+}
diff --git a/lib/libc/gen/psignal.3 b/lib/libc/gen/psignal.3
new file mode 100644
index 0000000..771de7d
--- /dev/null
+++ b/lib/libc/gen/psignal.3
@@ -0,0 +1,113 @@
+.\" 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. 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.
+.\"
+.\" @(#)psignal.3 8.2 (Berkeley) 2/27/95
+.\" $FreeBSD$
+.\"
+.Dd February 27, 1995
+.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 "unsigned 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, lower-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 0000000..c0f63cd
--- /dev/null
+++ b/lib/libc/gen/psignal.c
@@ -0,0 +1,67 @@
+/*
+ * 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. 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.
+ */
+
+#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(sig, s)
+ unsigned int sig;
+ const char *s;
+{
+ const char *c;
+
+ if (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/pw_scan.c b/lib/libc/gen/pw_scan.c
new file mode 100644
index 0000000..04cc388
--- /dev/null
+++ b/lib/libc/gen/pw_scan.c
@@ -0,0 +1,205 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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.
+ */
+static int pw_big_ids_warning = -1;
+
+int
+__pw_scan(char *bp, struct passwd *pw, int flags)
+{
+ uid_t id;
+ int root;
+ char *ep, *p, *sh;
+
+ 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);
+ }
+ }
+ id = strtoul(p, &ep, 10);
+ if (errno == ERANGE) {
+ if (flags & _PWSCAN_WARN)
+ warnx("%s > max uid value (%lu)", p, ULONG_MAX);
+ return (0);
+ }
+ 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);
+ }
+ }
+ id = strtoul(p, &ep, 10);
+ if (errno == ERANGE) {
+ if (flags & _PWSCAN_WARN)
+ warnx("%s > max gid value (%lu)", p, ULONG_MAX);
+ return (0);
+ }
+ 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 0000000..f83df2c
--- /dev/null
+++ b/lib/libc/gen/pw_scan.h
@@ -0,0 +1,40 @@
+/*-
+ * 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.
+ *
+ * @(#)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/pwcache.3 b/lib/libc/gen/pwcache.3
new file mode 100644
index 0000000..feb834d
--- /dev/null
+++ b/lib/libc/gen/pwcache.3
@@ -0,0 +1,97 @@
+.\" Copyright (c) 1989, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. 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.
+.\"
+.\" @(#)pwcache.3 8.1 (Berkeley) 6/9/93
+.\" $FreeBSD$
+.\"
+.Dd Dd March 22, 2002
+.Dt PWCACHE 3
+.Os
+.Sh NAME
+.Nm pwcache
+.Nd cache password and group entries
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In pwd.h
+.Ft const char *
+.Fn user_from_uid "uid_t uid" "int nouser"
+.In grp.h
+.Ft const char *
+.Fn group_from_gid "gid_t gid" "int nogroup"
+.Sh DESCRIPTION
+The
+.Fn user_from_uid
+function returns the user name associated with the argument
+.Fa uid .
+The user name is cached so that multiple calls with the same
+.Fa uid
+do not require additional calls to
+.Xr getpwuid 3 .
+If there is no user associated with the
+.Fa uid ,
+a pointer is returned
+to a string representation of the
+.Fa uid ,
+unless the argument
+.Fa nouser
+is non-zero, in which case a
+.Dv NULL
+pointer is returned.
+.Pp
+The
+.Fn group_from_gid
+function returns the group name associated with the argument
+.Fa gid .
+The group name is cached so that multiple calls with the same
+.Fa gid
+do not require additional calls to
+.Xr getgrgid 3 .
+If there is no group associated with the
+.Fa gid ,
+a pointer is returned
+to a string representation of the
+.Fa gid ,
+unless the argument
+.Fa nogroup
+is non-zero, in which case a
+.Dv NULL
+pointer is returned.
+.Sh SEE ALSO
+.Xr getgrgid 3 ,
+.Xr getpwuid 3
+.Sh HISTORY
+The
+.Fn user_from_uid
+and
+.Fn group_from_gid
+functions first appeared in
+.Bx 4.4 .
diff --git a/lib/libc/gen/pwcache.c b/lib/libc/gen/pwcache.c
new file mode 100644
index 0000000..cb2aa42
--- /dev/null
+++ b/lib/libc/gen/pwcache.c
@@ -0,0 +1,117 @@
+/*
+ * 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. 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)pwcache.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include <grp.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <string.h>
+#include <utmp.h>
+
+#define NCACHE 64 /* power of 2 */
+#define MASK (NCACHE - 1) /* bits to store with */
+
+const char *
+user_from_uid(uid_t uid, int nouser)
+{
+ static struct ncache {
+ uid_t uid;
+ int found;
+ char name[UT_NAMESIZE + 1];
+ } c_uid[NCACHE];
+ static int pwopen;
+ struct passwd *pw;
+ struct ncache *cp;
+
+ cp = c_uid + (uid & MASK);
+ if (cp->uid != uid || !*cp->name) {
+ if (pwopen == 0) {
+ setpassent(1);
+ pwopen = 1;
+ }
+ pw = getpwuid(uid);
+ cp->uid = uid;
+ if (pw != NULL) {
+ cp->found = 1;
+ (void)strncpy(cp->name, pw->pw_name, UT_NAMESIZE);
+ cp->name[UT_NAMESIZE] = '\0';
+ } else {
+ cp->found = 0;
+ (void)snprintf(cp->name, UT_NAMESIZE, "%u", uid);
+ if (nouser)
+ return (NULL);
+ }
+ }
+ return ((nouser && !cp->found) ? NULL : cp->name);
+}
+
+const char *
+group_from_gid(gid_t gid, int nogroup)
+{
+ static struct ncache {
+ gid_t gid;
+ int found;
+ char name[UT_NAMESIZE + 1];
+ } c_gid[NCACHE];
+ static int gropen;
+ struct group *gr;
+ struct ncache *cp;
+
+ cp = c_gid + (gid & MASK);
+ if (cp->gid != gid || !*cp->name) {
+ if (gropen == 0) {
+ setgroupent(1);
+ gropen = 1;
+ }
+ gr = getgrgid(gid);
+ cp->gid = gid;
+ if (gr != NULL) {
+ cp->found = 1;
+ (void)strncpy(cp->name, gr->gr_name, UT_NAMESIZE);
+ cp->name[UT_NAMESIZE] = '\0';
+ } else {
+ cp->found = 0;
+ (void)snprintf(cp->name, UT_NAMESIZE, "%u", gid);
+ if (nogroup)
+ return (NULL);
+ }
+ }
+ return ((nogroup && !cp->found) ? NULL : cp->name);
+}
diff --git a/lib/libc/gen/raise.3 b/lib/libc/gen/raise.3
new file mode 100644
index 0000000..8dac8f5
--- /dev/null
+++ b/lib/libc/gen/raise.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
+.\" 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. 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.
+.\"
+.\" @(#)raise.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt RAISE 3
+.Os
+.Sh NAME
+.Nm raise
+.Nd send a signal to the current process
+.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 process.
+.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 0000000..2e50fd4
--- /dev/null
+++ b/lib/libc/gen/raise.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. 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.
+ */
+
+#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>
+
+__weak_reference(__raise, raise);
+__weak_reference(__raise, _raise);
+
+int
+__raise(s)
+ int s;
+{
+ return(kill(getpid(), s));
+}
diff --git a/lib/libc/gen/rand48.3 b/lib/libc/gen/rand48.3
new file mode 100644
index 0000000..a703ba0
--- /dev/null
+++ b/lib/libc/gen/rand48.3
@@ -0,0 +1,184 @@
+.\" 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 October 8, 1993
+.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
+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 = 0xfdeece66d = 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.
+.Pp
+For a more powerful random number generator, see
+.Xr random 3 .
+.Sh SEE ALSO
+.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 0000000..b6602dc
--- /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 0000000..20c2eb3
--- /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.
+ * 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.
+ */
+
+#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 "telldir.h"
+
+/*
+ * get next entry in a directory.
+ */
+struct dirent *
+_readdir_unlocked(dirp)
+ DIR *dirp;
+{
+ struct dirent *dp;
+
+ for (;;) {
+ if (dirp->dd_loc >= dirp->dd_size) {
+ if (dirp->dd_flags & __DTF_READALL)
+ return (NULL);
+ dirp->dd_loc = 0;
+ }
+ if (dirp->dd_loc == 0 && !(dirp->dd_flags & __DTF_READALL)) {
+ dirp->dd_size = _getdirentries(dirp->dd_fd,
+ dirp->dd_buf, dirp->dd_len, &dirp->dd_seek);
+ if (dirp->dd_size <= 0)
+ return (NULL);
+ }
+ 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)
+ continue;
+ if (dp->d_type == DT_WHT && (dirp->dd_flags & DTF_HIDEW))
+ continue;
+ return (dp);
+ }
+}
+
+struct dirent *
+readdir(dirp)
+ DIR *dirp;
+{
+ struct dirent *dp;
+
+ if (__isthreaded) {
+ _pthread_mutex_lock((pthread_mutex_t *)&dirp->dd_lock);
+ dp = _readdir_unlocked(dirp);
+ _pthread_mutex_unlock((pthread_mutex_t *)&dirp->dd_lock);
+ }
+ else
+ dp = _readdir_unlocked(dirp);
+ return (dp);
+}
+
+int
+readdir_r(dirp, entry, result)
+ DIR *dirp;
+ struct dirent *entry;
+ struct dirent **result;
+{
+ struct dirent *dp;
+ int saved_errno;
+
+ saved_errno = errno;
+ errno = 0;
+ if (__isthreaded) {
+ _pthread_mutex_lock((pthread_mutex_t *)&dirp->dd_lock);
+ if ((dp = _readdir_unlocked(dirp)) != NULL)
+ memcpy(entry, dp, _GENERIC_DIRSIZ(dp));
+ _pthread_mutex_unlock((pthread_mutex_t *)&dirp->dd_lock);
+ }
+ else if ((dp = _readdir_unlocked(dirp)) != 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 0000000..0d6a7ff
--- /dev/null
+++ b/lib/libc/gen/readpassphrase.3
@@ -0,0 +1,191 @@
+.\" $OpenBSD: readpassphrase.3,v 1.7 2001/12/15 15:37:51 millert Exp $
+.\"
+.\" Copyright (c) 2000 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd December 7, 2001
+.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
+.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 null-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 SIGNALS
+The
+.Fn readpassphrase
+function
+will catch the following signals:
+.Pp
+.Bl -tag -compact
+.It Dv SIGINT
+.It Dv SIGHUP
+.It Dv SIGQUIT
+.It Dv SIGTERM
+.It Dv SIGTSTP
+.It Dv SIGTTIN
+.It Dv SIGTTOU
+.El
+.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 signal 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 ERRORS
+.Bl -tag -width Er
+.It Bq Er EINTR
+The
+.Fn readpassphrase
+function was interrupted by a signal.
+.It Bq Er EINVAL
+The
+.Fa 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 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 0000000..983e01d
--- /dev/null
+++ b/lib/libc/gen/readpassphrase.c
@@ -0,0 +1,178 @@
+/* $OpenBSD: readpassphrase.c,v 1.12 2001/12/15 05:41:00 millert Exp $ */
+
+/*
+ * Copyright (c) 2000 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$OpenBSD: readpassphrase.c,v 1.12 2001/12/15 05:41:00 millert Exp $";
+#endif /* LIBC_SCCS and not lint */
+#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"
+
+static volatile sig_atomic_t signo;
+
+static void handler(int);
+
+char *
+readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags)
+{
+ ssize_t nr;
+ int input, output, save_errno;
+ char ch, *p, *end;
+ struct termios term, oterm;
+ struct sigaction sa, saveint, savehup, savequit, saveterm;
+ struct sigaction savetstp, savettin, savettou;
+
+ /* I suppose we could alloc on demand in this case (XXX). */
+ if (bufsiz == 0) {
+ errno = EINVAL;
+ return(NULL);
+ }
+
+restart:
+ /*
+ * Read and write to /dev/tty if available. If not, read from
+ * stdin and write to stderr unless a tty is required.
+ */
+ if ((input = output = _open(_PATH_TTY, O_RDWR)) == -1) {
+ if (flags & RPP_REQUIRE_TTY) {
+ errno = ENOTTY;
+ return(NULL);
+ }
+ input = STDIN_FILENO;
+ output = STDERR_FILENO;
+ }
+
+ /*
+ * Catch signals that would otherwise cause the user to end
+ * up with echo turned off in the shell. Don't worry about
+ * things like SIGALRM and SIGPIPE for now.
+ */
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0; /* don't restart system calls */
+ sa.sa_handler = handler;
+ (void)_sigaction(SIGINT, &sa, &saveint);
+ (void)_sigaction(SIGHUP, &sa, &savehup);
+ (void)_sigaction(SIGQUIT, &sa, &savequit);
+ (void)_sigaction(SIGTERM, &sa, &saveterm);
+ (void)_sigaction(SIGTSTP, &sa, &savetstp);
+ (void)_sigaction(SIGTTIN, &sa, &savettin);
+ (void)_sigaction(SIGTTOU, &sa, &savettou);
+
+ /* Turn off echo if possible. */
+ if (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));
+ memset(&oterm, 0, sizeof(oterm));
+ }
+
+ (void)_write(output, prompt, strlen(prompt));
+ end = buf + bufsiz - 1;
+ for (p = buf; (nr = _read(input, &ch, 1)) == 1 && ch != '\n' && ch != '\r';) {
+ if (p < end) {
+ if ((flags & RPP_SEVENBIT))
+ ch &= 0x7f;
+ if (isalpha(ch)) {
+ if ((flags & RPP_FORCELOWER))
+ ch = tolower(ch);
+ if ((flags & RPP_FORCEUPPER))
+ ch = toupper(ch);
+ }
+ *p++ = ch;
+ }
+ }
+ *p = '\0';
+ save_errno = errno;
+ if (!(term.c_lflag & ECHO))
+ (void)_write(output, "\n", 1);
+
+ /* Restore old terminal settings and signals. */
+ if (memcmp(&term, &oterm, sizeof(term)) != 0)
+ (void)tcsetattr(input, TCSANOW|TCSASOFT, &oterm);
+ (void)_sigaction(SIGINT, &saveint, NULL);
+ (void)_sigaction(SIGHUP, &savehup, NULL);
+ (void)_sigaction(SIGQUIT, &savequit, NULL);
+ (void)_sigaction(SIGTERM, &saveterm, NULL);
+ (void)_sigaction(SIGTSTP, &savetstp, NULL);
+ (void)_sigaction(SIGTTIN, &savettin, NULL);
+ (void)_sigaction(SIGTTOU, &savettou, NULL);
+ if (input != STDIN_FILENO)
+ (void)_close(input);
+
+ /*
+ * If we were interrupted by a signal, resend it to ourselves
+ * now that we have restored the signal handlers.
+ */
+ if (signo) {
+ kill(getpid(), signo);
+ switch (signo) {
+ case SIGTSTP:
+ case SIGTTIN:
+ case SIGTTOU:
+ signo = 0;
+ goto restart;
+ }
+ }
+
+ 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;
+}
diff --git a/lib/libc/gen/rewinddir.c b/lib/libc/gen/rewinddir.c
new file mode 100644
index 0000000..294301e
--- /dev/null
+++ b/lib/libc/gen/rewinddir.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. 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.
+ */
+
+#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 <sys/types.h>
+#include <dirent.h>
+
+#include "telldir.h"
+
+void
+rewinddir(dirp)
+ DIR *dirp;
+{
+
+ _seekdir(dirp, dirp->dd_rewind);
+ dirp->dd_rewind = telldir(dirp);
+}
diff --git a/lib/libc/gen/rfork_thread.3 b/lib/libc/gen/rfork_thread.3
new file mode 100644
index 0000000..e985e1c
--- /dev/null
+++ b/lib/libc/gen/rfork_thread.3
@@ -0,0 +1,79 @@
+.\"
+.\" 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 July 29, 2000
+.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
+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
+.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 0000000..045e4ec
--- /dev/null
+++ b/lib/libc/gen/scandir.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.
+.\" 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.
+.\"
+.\" @(#)scandir.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt SCANDIR 3
+.Os
+.Sh NAME
+.Nm scandir ,
+.Nm alphasort
+.Nd scan a directory
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In dirent.h
+.Ft int
+.Fn scandir "const char *dirname" "struct dirent ***namelist" "int \\*(lp*select\\*(rp\\*(lpstruct dirent *\\*(rp" "int \\*(lp*compar\\*(rp\\*(lpconst void *, const void *\\*(rp"
+.Ft int
+.Fn alphasort "const void *d1" "const void *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.
+.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.
+.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 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 0000000..6c7259f
--- /dev/null
+++ b/lib/libc/gen/scandir.c
@@ -0,0 +1,150 @@
+/*
+ * 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. 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.
+ */
+
+#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 <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <stdlib.h>
+#include <string.h>
+#include "un-namespace.h"
+
+/*
+ * 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
+scandir(dirname, namelist, select, dcomp)
+ const char *dirname;
+ struct dirent ***namelist;
+ int (*select)(struct dirent *);
+ int (*dcomp)(const void *, const void *);
+{
+ struct dirent *d, *p, **names = NULL;
+ size_t nitems = 0;
+ struct stat stb;
+ long arraysz;
+ DIR *dirp;
+
+ if ((dirp = opendir(dirname)) == NULL)
+ return(-1);
+ if (_fstat(dirp->dd_fd, &stb) < 0)
+ goto fail;
+
+ /*
+ * estimate the array size by taking the size of the directory file
+ * and dividing it by a multiple of the minimum size entry.
+ */
+ arraysz = (stb.st_size / 24);
+ 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) {
+ const int inc = 10; /* increase by this much */
+ struct dirent **names2;
+
+ names2 = (struct dirent **)realloc((char *)names,
+ (arraysz + inc) * sizeof(struct dirent *));
+ if (names2 == NULL) {
+ free(p);
+ goto fail;
+ }
+ names = names2;
+ arraysz += inc;
+ }
+ names[nitems++] = p;
+ }
+ closedir(dirp);
+ if (nitems && dcomp != NULL)
+ qsort(names, nitems, sizeof(struct dirent *), dcomp);
+ *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.
+ */
+int
+alphasort(d1, d2)
+ const void *d1;
+ const void *d2;
+{
+ return(strcmp((*(struct dirent **)d1)->d_name,
+ (*(struct dirent **)d2)->d_name));
+}
diff --git a/lib/libc/gen/seed48.c b/lib/libc/gen/seed48.c
new file mode 100644
index 0000000..5339b8c
--- /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 0000000..e6fbf10
--- /dev/null
+++ b/lib/libc/gen/seekdir.c
@@ -0,0 +1,63 @@
+/*
+ * 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. 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.
+ */
+
+#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 "telldir.h"
+
+/*
+ * Seek to an entry in a directory.
+ * _seekdir is in telldir.c so that it can share opaque data structures.
+ */
+void
+seekdir(dirp, loc)
+ DIR *dirp;
+ long loc;
+{
+ if (__isthreaded)
+ _pthread_mutex_lock((pthread_mutex_t *)&dirp->dd_lock);
+ _seekdir(dirp, loc);
+ if (__isthreaded)
+ _pthread_mutex_unlock((pthread_mutex_t *)&dirp->dd_lock);
+}
diff --git a/lib/libc/gen/sem.c b/lib/libc/gen/sem.c
new file mode 100644
index 0000000..439f0fe
--- /dev/null
+++ b/lib/libc/gen/sem.c
@@ -0,0 +1,361 @@
+/*
+ * 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 <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <time.h>
+#include <_semaphore.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+
+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;
+
+__weak_reference(__sem_init, sem_init);
+__weak_reference(__sem_destroy, sem_destroy);
+__weak_reference(__sem_open, sem_open);
+__weak_reference(__sem_close, sem_close);
+__weak_reference(__sem_unlink, sem_unlink);
+__weak_reference(__sem_wait, sem_wait);
+__weak_reference(__sem_trywait, sem_trywait);
+__weak_reference(__sem_timedwait, sem_timedwait);
+__weak_reference(__sem_post, sem_post);
+__weak_reference(__sem_getvalue, 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)
+{
+
+ _pthread_mutex_destroy(&sem->lock);
+ _pthread_cond_destroy(&sem->gtzero);
+ 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;
+ sem->lock = PTHREAD_MUTEX_INITIALIZER;
+ sem->gtzero = PTHREAD_COND_INITIALIZER;
+ return (sem);
+}
+
+int
+__sem_init(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.
+ */
+ if (ksem_init(&semid, value) != 0)
+ return (-1);
+
+ (*sem) = sem_alloc(value, semid, 1);
+ if ((*sem) == NULL) {
+ ksem_destroy(semid);
+ return (-1);
+ }
+ return (0);
+}
+
+int
+__sem_destroy(sem_t *sem)
+{
+ int retval;
+
+ if (sem_check_validity(sem) != 0)
+ return (-1);
+
+ _pthread_mutex_lock(&(*sem)->lock);
+ /*
+ * 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;
+ }
+ _pthread_mutex_unlock(&(*sem)->lock);
+
+ if (retval == 0) {
+ _pthread_mutex_destroy(&(*sem)->lock);
+ _pthread_cond_destroy(&(*sem)->gtzero);
+ sem_free(*sem);
+ }
+ return (retval);
+}
+
+sem_t *
+__sem_open(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
+__sem_close(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
+__sem_unlink(const char *name)
+{
+
+ return (ksem_unlink(name));
+}
+
+int
+__sem_wait(sem_t *sem)
+{
+
+ if (sem_check_validity(sem) != 0)
+ return (-1);
+
+ return (ksem_wait((*sem)->semid));
+}
+
+int
+__sem_trywait(sem_t *sem)
+{
+ int retval;
+
+ if (sem_check_validity(sem) != 0)
+ return (-1);
+
+ if ((*sem)->syssem != 0)
+ retval = ksem_trywait((*sem)->semid);
+ else {
+ _pthread_mutex_lock(&(*sem)->lock);
+ if ((*sem)->count > 0) {
+ (*sem)->count--;
+ retval = 0;
+ } else {
+ errno = EAGAIN;
+ retval = -1;
+ }
+ _pthread_mutex_unlock(&(*sem)->lock);
+ }
+ return (retval);
+}
+
+int
+__sem_timedwait(sem_t * __restrict sem,
+ const struct timespec * __restrict abs_timeout)
+{
+ if (sem_check_validity(sem) != 0)
+ return (-1);
+
+ return (ksem_timedwait((*sem)->semid, abs_timeout));
+}
+
+int
+__sem_post(sem_t *sem)
+{
+
+ if (sem_check_validity(sem) != 0)
+ return (-1);
+
+ return (ksem_post((*sem)->semid));
+}
+
+int
+__sem_getvalue(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 {
+ _pthread_mutex_lock(&(*sem)->lock);
+ *sval = (int)(*sem)->count;
+ _pthread_mutex_unlock(&(*sem)->lock);
+
+ 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 0000000..f488b4e
--- /dev/null
+++ b/lib/libc/gen/sem_destroy.3
@@ -0,0 +1,88 @@
+.\" 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 ,
+.Xr sem 4
+.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 0000000..a8dd177
--- /dev/null
+++ b/lib/libc/gen/sem_getvalue.3
@@ -0,0 +1,81 @@
+.\" 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 ,
+.Xr sem 4
+.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 0000000..d765a57
--- /dev/null
+++ b/lib/libc/gen/sem_init.3
@@ -0,0 +1,108 @@
+.\" 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_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 .
+A non-zero value for
+.Fa pshared
+specifies a shared semaphore that can be used by multiple processes, which this
+implementation is not capable of.
+.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.
+.It Bq Er EPERM
+Unable to initialize a shared semaphore.
+.El
+.Sh SEE ALSO
+.Xr sem_destroy 3 ,
+.Xr sem_getvalue 3 ,
+.Xr sem_post 3 ,
+.Xr sem_trywait 3 ,
+.Xr sem_wait 3 ,
+.Xr sem 4
+.Sh STANDARDS
+The
+.Fn sem_init
+function conforms to
+.St -p1003.1-96 .
+.Pp
+This implementation does not support shared semaphores, and reports this fact
+by setting
+.Va errno
+to
+.Er EPERM .
+This is perhaps a stretch of the intention of
+.Tn POSIX ,
+but is
+compliant, with the caveat that
+.Fn sem_init
+always reports a permissions error when an attempt to create a shared semaphore
+is made.
diff --git a/lib/libc/gen/sem_open.3 b/lib/libc/gen/sem_open.3
new file mode 100644
index 0000000..f5ba249
--- /dev/null
+++ b/lib/libc/gen/sem_open.3
@@ -0,0 +1,227 @@
+.\" 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 15, 2003
+.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
+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 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 ,
+.Xr sem 4
+.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 .
+.Sh BUGS
+This implementation places strict requirements on the value of
+.Fa name :
+it must begin with a slash
+.Pq Ql / ,
+contain no other slash characters,
+and be less than 14 characters in length
+not including the terminating null character.
diff --git a/lib/libc/gen/sem_post.3 b/lib/libc/gen/sem_post.3
new file mode 100644
index 0000000..67559cc
--- /dev/null
+++ b/lib/libc/gen/sem_post.3
@@ -0,0 +1,78 @@
+.\" 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_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.
+.El
+.Sh SEE ALSO
+.Xr sem_getvalue 3 ,
+.Xr sem_trywait 3 ,
+.Xr sem_wait 3 ,
+.Xr sem 4
+.Sh STANDARDS
+The
+.Fn sem_post
+function conforms to
+.St -p1003.1-96 .
diff --git a/lib/libc/gen/sem_wait.3 b/lib/libc/gen/sem_wait.3
new file mode 100644
index 0000000..43d6fad
--- /dev/null
+++ b/lib/libc/gen/sem_wait.3
@@ -0,0 +1,94 @@
+.\" 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_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_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 4
+.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 0000000..4b5283f
--- /dev/null
+++ b/lib/libc/gen/semctl.c
@@ -0,0 +1,57 @@
+/*-
+ * 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$");
+
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/sem.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+extern int __semctl(int semid, int semnum, int cmd, union semun *arg);
+
+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));
+}
diff --git a/lib/libc/gen/setdomainname.c b/lib/libc/gen/setdomainname.c
new file mode 100644
index 0000000..90d5be8
--- /dev/null
+++ b/lib/libc/gen/setdomainname.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.
+ * 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.
+ */
+
+#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 0000000..0acddbe
--- /dev/null
+++ b/lib/libc/gen/sethostname.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.
+ * 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.
+ */
+
+#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 0000000..9820298
--- /dev/null
+++ b/lib/libc/gen/setjmp.3
@@ -0,0 +1,176 @@
+.\" 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. 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.
+.\"
+.\" @(#)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 0000000..917a21c
--- /dev/null
+++ b/lib/libc/gen/setjmperr.c
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ * 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.
+ */
+
+#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()
+{
+#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 0000000..bca8e68
--- /dev/null
+++ b/lib/libc/gen/setmode.3
@@ -0,0 +1,118 @@
+.\" Copyright (c) 1989, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. 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.
+.\"
+.\" @(#)setmode.3 8.2 (Berkeley) 4/28/95
+.\" $FreeBSD$
+.\"
+.Dd April 28, 1995
+.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 .
+.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 0000000..cfeb199
--- /dev/null
+++ b/lib/libc/gen/setmode.c
@@ -0,0 +1,450 @@
+/*
+ * 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.
+ * 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.
+ */
+
+#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 <ctype.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#ifdef SETMODE_DEBUG
+#include <stdio.h>
+#endif
+#include "un-namespace.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 BITCMD *addcmd(BITCMD *, int, int, int, u_int);
+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) { \
+ if (saveset) \
+ free(saveset); \
+ saveset = NULL; \
+ return (NULL); \
+ } \
+ set = newset + (set - saveset); \
+ saveset = newset; \
+ endset = newset + (setlen - 2); \
+ } \
+ set = addcmd(set, (a), (b), (c), (d))
+
+#define STANDARD_BITS (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
+
+void *
+setmode(const char *p)
+{
+ int perm, who;
+ char op, *ep;
+ BITCMD *set, *saveset, *endset;
+ sigset_t sigset, sigoset;
+ mode_t mask;
+ int equalopdone=0, permXbits, setlen;
+ long perml;
+
+ if (!*p)
+ return (NULL);
+
+ /*
+ * Get a copy of the mask for the permissions that are mask relative.
+ * Flip the bits, we want what's not set. Since it's possible that
+ * the caller is opening files inside a signal handler, protect them
+ * as best we can.
+ */
+ sigfillset(&sigset);
+ (void)_sigprocmask(SIG_BLOCK, &sigset, &sigoset);
+ (void)umask(mask = umask(0));
+ mask = ~mask;
+ (void)_sigprocmask(SIG_SETMASK, &sigoset, NULL);
+
+ 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)) {
+ perml = strtol(p, &ep, 8);
+ if (*ep || perml < 0 || perml & ~(STANDARD_BITS|S_ISTXT)) {
+ free(saveset);
+ return (NULL);
+ }
+ 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.
+ */
+ 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 != '=') {
+ free(saveset);
+ return (NULL);
+ }
+ 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);
+}
+
+static BITCMD *
+addcmd(BITCMD *set, int op, int who, int oparg, u_int 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 0000000..fe9f19a
--- /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
+.Os
+.Dt SETPROCTITLE 3
+.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 peter@FreeBSD.org
+stole the idea from the
+.Sy "Sendmail 8.7.3"
+source code by
+.An Eric Allman Aq 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 0000000..cd705fb
--- /dev/null
+++ b/lib/libc/gen/setproctitle.c
@@ -0,0 +1,176 @@
+/*
+ * 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/types.h>
+#include <sys/param.h>
+#include <sys/exec.h>
+#include <sys/sysctl.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/pmap.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.
+ * This attempts to support a kernel built in the #2 and #3 era.
+ */
+
+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)
+ ul_ps_strings = PS_STRINGS;
+ ps_strings = (struct ps_strings *)ul_ps_strings;
+ }
+
+ /* PS_STRINGS points to zeroed memory on a style #2 kernel */
+ if (ps_strings->ps_argvstr) {
+ /* 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 ? " " : "", oargv[i]);
+ if (len)
+ len++;
+ len += strlen(oargv[i]);
+ if (len >= SPT_BUFSIZE)
+ break;
+ }
+ }
+ ps_strings->ps_nargvstr = nargc;
+ ps_strings->ps_argvstr = nargvp;
+ } else {
+ /* style #2 - we can only restore our first arg :-( */
+ if (*obuf == '\0')
+ strncpy(obuf, OLD_PS_STRINGS->old_ps_argvstr,
+ SPT_BUFSIZE - 1);
+ OLD_PS_STRINGS->old_ps_nargvstr = 1;
+ OLD_PS_STRINGS->old_ps_argvstr = nargvp[0];
+ }
+}
diff --git a/lib/libc/gen/setprogname.c b/lib/libc/gen/setprogname.c
new file mode 100644
index 0000000..29a6cd0
--- /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/shm_open.3 b/lib/libc/gen/shm_open.3
new file mode 100644
index 0000000..b68e85b
--- /dev/null
+++ b/lib/libc/gen/shm_open.3
@@ -0,0 +1,192 @@
+.\"
+.\" 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 March 24, 2000
+.Dt SHM_OPEN 3
+.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
+.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
+function opens (or optionally creates) a
+.Tn POSIX
+shared memory object named
+.Fa path .
+The
+.Fn shm_unlink
+function removes a shared memory object named
+.Fa path .
+.Pp
+In the
+.Fx
+implementation,
+.Tn POSIX
+shared memory objects are implemented as ordinary files.
+The
+.Fn shm_open
+and
+.Fn shm_unlink
+act as wrappers around the
+.Xr open 2
+and
+.Xr unlink 2
+routines, and
+.Fa path ,
+.Fa flags ,
+and
+.Fa mode
+arguments are as specified for those functions.
+The
+.Fa flags
+argument is checked to ensure that the access mode specified is not
+.Dv O_WRONLY
+(which is not defined for shared memory objects).
+.Pp
+In addition, the
+.Fx
+implementation causes
+.Fn mmap
+of a descriptor returned by
+.Fn shm_open
+to behave as if the
+.Dv MAP_NOSYNC
+flag had been specified to
+.Xr mmap 2 .
+(It does so by setting a special file flag using
+.Xr fcntl 2 . )
+.Pp
+The
+.Fn shm_unlink
+function makes no effort to ensure that
+.Fa path
+refers to a shared memory object.
+.Sh RETURN VALUES
+If successful,
+.Fn shm_open
+returns a non-negative integer;
+.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 this
+and 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
+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.
+It is also undefined whether the shared memory object itself, or its
+contents, persist across reboots.
+.Sh ERRORS
+The
+.Fn shm_open
+and
+.Fn shm_unlink
+functions can fail with any error defined for
+.Fn open
+and
+.Fn unlink ,
+respectively.
+In addition, the following errors are defined for
+.Fn shm_open :
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The object named by
+.Fa path
+is not a shared memory object
+(i.e., it is not a regular file).
+.It Bq Er EINVAL
+The
+.Fa flags
+argument to
+.Fn shm_open
+specifies an access mode of
+.Dv O_WRONLY .
+.El
+.Sh SEE ALSO
+.Xr mmap 2 ,
+.Xr munmap 2 ,
+.Xr open 2 ,
+.Xr unlink 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 .
+.Sh AUTHORS
+.An Garrett A. Wollman Aq wollman@FreeBSD.org
+(C library support and this manual page)
+.Pp
+.An Matthew Dillon Aq dillon@FreeBSD.org
+.Pq Dv MAP_NOSYNC
diff --git a/lib/libc/gen/siginterrupt.3 b/lib/libc/gen/siginterrupt.3
new file mode 100644
index 0000000..9680a15
--- /dev/null
+++ b/lib/libc/gen/siginterrupt.3
@@ -0,0 +1,124 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)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 sigblock 2 ,
+.Xr sigpause 2 ,
+.Xr sigsetmask 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 0000000..8269499
--- /dev/null
+++ b/lib/libc/gen/siginterrupt.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.
+ * 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.
+ */
+
+#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(sig, flag)
+ int sig, flag;
+{
+ extern sigset_t _sigintr;
+ struct sigaction sa;
+ int ret;
+
+ if ((ret = _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 (_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 0000000..d723e3e
--- /dev/null
+++ b/lib/libc/gen/siglist.c
@@ -0,0 +1,112 @@
+/*
+ * 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. 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.
+ */
+
+#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 <sys/cdefs.h>
+#include <signal.h>
+
+const char *const sys_signame[NSIG] = {
+ "Signal 0",
+ "hup", /* SIGHUP */
+ "int", /* SIGINT */
+ "quit", /* SIGQUIT */
+ "ill", /* SIGILL */
+ "trap", /* SIGTRAP */
+ "abrt", /* SIGABRT */
+ "emt", /* SIGEMT */
+ "fpe", /* SIGFPE */
+ "kill", /* SIGKILL */
+ "bus", /* SIGBUS */
+ "segv", /* SIGSEGV */
+ "sys", /* SIGSYS */
+ "pipe", /* SIGPIPE */
+ "alrm", /* SIGALRM */
+ "term", /* SIGTERM */
+ "urg", /* SIGURG */
+ "stop", /* SIGSTOP */
+ "tstp", /* SIGTSTP */
+ "cont", /* SIGCONT */
+ "chld", /* SIGCHLD */
+ "ttin", /* SIGTTIN */
+ "ttou", /* SIGTTOU */
+ "io", /* SIGIO */
+ "xcpu", /* SIGXCPU */
+ "xfsz", /* SIGXFSZ */
+ "vtalrm", /* SIGVTALRM */
+ "prof", /* SIGPROF */
+ "winch", /* SIGWINCH */
+ "info", /* SIGINFO */
+ "usr1", /* SIGUSR1 */
+ "usr2" /* SIGUSR2 */
+};
+
+const char *const sys_siglist[NSIG] = {
+ "Signal 0",
+ "Hangup", /* SIGHUP */
+ "Interrupt", /* SIGINT */
+ "Quit", /* SIGQUIT */
+ "Illegal instruction", /* SIGILL */
+ "Trace/BPT trap", /* SIGTRAP */
+ "Abort trap", /* SIGABRT */
+ "EMT trap", /* SIGEMT */
+ "Floating point exception", /* SIGFPE */
+ "Killed", /* SIGKILL */
+ "Bus error", /* SIGBUS */
+ "Segmentation fault", /* SIGSEGV */
+ "Bad system call", /* SIGSYS */
+ "Broken pipe", /* SIGPIPE */
+ "Alarm clock", /* SIGALRM */
+ "Terminated", /* SIGTERM */
+ "Urgent I/O condition", /* SIGURG */
+ "Suspended (signal)", /* SIGSTOP */
+ "Suspended", /* SIGTSTP */
+ "Continued", /* SIGCONT */
+ "Child exited", /* SIGCHLD */
+ "Stopped (tty input)", /* SIGTTIN */
+ "Stopped (tty output)", /* SIGTTOU */
+ "I/O possible", /* SIGIO */
+ "Cputime limit exceeded", /* SIGXCPU */
+ "Filesize limit exceeded", /* SIGXFSZ */
+ "Virtual timer expired", /* SIGVTALRM */
+ "Profiling timer expired", /* SIGPROF */
+ "Window size changes", /* SIGWINCH */
+ "Information request", /* SIGINFO */
+ "User defined signal 1", /* SIGUSR1 */
+ "User defined signal 2" /* SIGUSR2 */
+};
+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 0000000..7b99fab
--- /dev/null
+++ b/lib/libc/gen/signal.3
@@ -0,0 +1,281 @@
+.\" 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. 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.
+.\"
+.\" @(#)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
+.\" XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX
+.\" The prototype for signal(3) cannot be cleanly marked up in -mdoc
+.\" without the following lower-level tweak.
+.nr in-synopsis-section 0
+.Pp
+.Ft "void \*(lp*" Ns
+.Fo signal
+.Fa "int sig"
+.Fa "void \*(lp*func\*(rp\*(lpint\*(rp"
+.Fc Ns
+.Ft "\*(rp\*(lpint\*(rp" ;
+.Pp
+.nr in-synopsis-section 1
+.\" XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX
+or in
+.Fx Ap s
+equivalent but easier to read typedef'd version:
+.Ft typedef "void \*(lp*sig_t\*(rp \*(lpint\*(rp" ;
+.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 "No Name Default Action 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"
+.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.
+(The handler is installed using the
+.Dv SA_RESTART
+flag with
+.Xr sigaction 2 . )
+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 0000000..d954cd4
--- /dev/null
+++ b/lib/libc/gen/signal.c
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ * 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.
+ */
+
+#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; /* shared with siginterrupt */
+
+sig_t
+signal(s, a)
+ 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 (_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 0000000..3fd72b6
--- /dev/null
+++ b/lib/libc/gen/sigsetops.3
@@ -0,0 +1,121 @@
+.\" 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. 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.
+.\"
+.\" @(#)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 0000000..38014da
--- /dev/null
+++ b/lib/libc/gen/sigsetops.c
@@ -0,0 +1,106 @@
+/*-
+ * 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. 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.
+ *
+ * @(#)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(set, signo)
+ 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(set, signo)
+ 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(set)
+ sigset_t *set;
+{
+ int i;
+
+ for (i = 0; i < _SIG_WORDS; i++)
+ set->__bits[i] = 0;
+ return (0);
+}
+
+int
+sigfillset(set)
+ sigset_t *set;
+{
+ int i;
+
+ for (i = 0; i < _SIG_WORDS; i++)
+ set->__bits[i] = ~0U;
+ return (0);
+}
+
+int
+sigismember(set, signo)
+ 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 0000000..4c204dc
--- /dev/null
+++ b/lib/libc/gen/sleep.3
@@ -0,0 +1,87 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)sleep.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd February 13, 1998
+.Dt SLEEP 3
+.Os
+.Sh NAME
+.Nm sleep
+.Nd suspend process 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 process until either
+.Fa seconds
+seconds 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 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 0000000..71318ce
--- /dev/null
+++ b/lib/libc/gen/sleep.c
@@ -0,0 +1,72 @@
+/*
+ * 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. 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.
+ */
+
+#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"
+
+unsigned int
+__sleep(seconds)
+ 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 (_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 0000000..fd369a0
--- /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 0000000..f9c7430
--- /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 wollman@FreeBSD.org .
diff --git a/lib/libc/gen/statvfs.c b/lib/libc/gen/statvfs.c
new file mode 100644
index 0000000..fe9462b
--- /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 0000000..30dd299
--- /dev/null
+++ b/lib/libc/gen/stringlist.3
@@ -0,0 +1,135 @@
+.\" $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.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the NetBSD
+.\" Foundation, Inc. and its contributors.
+.\" 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 REGENTS OR CONTRIBUTORS BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 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
+.Os
+.Dt STRINGLIST 3
+.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" "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
+.Pp
+.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 0000000..79e605d
--- /dev/null
+++ b/lib/libc/gen/stringlist.c
@@ -0,0 +1,125 @@
+/*
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Christos Zoulas.
+ * 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.
+ */
+
+#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()
+{
+ 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(sl, name)
+ 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(sl, all)
+ 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(sl, name)
+ StringList *sl;
+ 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 0000000..4b2d5c5
--- /dev/null
+++ b/lib/libc/gen/strtofflags.3
@@ -0,0 +1,99 @@
+.\" Copyright (c) 1989, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. 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.
+.\"
+.\" @(#)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 0000000..fee52af
--- /dev/null
+++ b/lib/libc/gen/strtofflags.c
@@ -0,0 +1,159 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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>
+
+static struct {
+ char *name;
+ u_long flag;
+ int invert;
+} mapping[] = {
+ /* shorter names per flag first, all prefixed by "no" */
+ { "nosappnd", SF_APPEND, 0 },
+ { "nosappend", SF_APPEND, 0 },
+ { "noarch", SF_ARCHIVED, 0 },
+ { "noarchived", SF_ARCHIVED, 0 },
+ { "noschg", SF_IMMUTABLE, 0 },
+ { "noschange", SF_IMMUTABLE, 0 },
+ { "nosimmutable", SF_IMMUTABLE, 0 },
+ { "nosunlnk", SF_NOUNLINK, 0 },
+ { "nosunlink", SF_NOUNLINK, 0 },
+#ifdef SF_SNAPSHOT
+ { "nosnapshot", SF_SNAPSHOT, 0 },
+#endif
+ { "nouappnd", UF_APPEND, 0 },
+ { "nouappend", UF_APPEND, 0 },
+ { "nouchg", UF_IMMUTABLE, 0 },
+ { "nouchange", UF_IMMUTABLE, 0 },
+ { "nouimmutable", UF_IMMUTABLE, 0 },
+ { "nodump", UF_NODUMP, 1 },
+ { "noopaque", UF_OPAQUE, 0 },
+ { "nouunlnk", UF_NOUNLINK, 0 },
+ { "nouunlink", UF_NOUNLINK, 0 }
+};
+#define longestflaglen 12
+#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(flags)
+ u_long flags;
+{
+ char *string;
+ char *sp, *dp;
+ u_long setflags;
+ 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(stringp, setp, clrp)
+ char **stringp;
+ u_long *setp, *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/swapcontext.c b/lib/libc/gen/swapcontext.c
new file mode 100644
index 0000000..c34cb23
--- /dev/null
+++ b/lib/libc/gen/swapcontext.c
@@ -0,0 +1,55 @@
+/*
+ * 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 <stddef.h>
+
+__weak_reference(__swapcontext, swapcontext);
+
+int
+__swapcontext(ucontext_t *oucp, const ucontext_t *ucp)
+{
+ int ret;
+
+ if ((oucp == NULL) || (ucp == NULL)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ oucp->uc_flags &= ~UCF_SWAPPED;
+ ret = getcontext(oucp);
+ if ((ret == 0) && !(oucp->uc_flags & UCF_SWAPPED)) {
+ oucp->uc_flags |= UCF_SWAPPED;
+ ret = setcontext(ucp);
+ }
+ return (ret);
+}
diff --git a/lib/libc/gen/sysconf.3 b/lib/libc/gen/sysconf.3
new file mode 100644
index 0000000..cd6d3ad
--- /dev/null
+++ b/lib/libc/gen/sysconf.3
@@ -0,0 +1,212 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)sysconf.3 8.3 (Berkeley) 4/19/94
+.\" $FreeBSD$
+.\"
+.Dd June 18, 2001
+.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:
+.Pp
+.Bl -tag -width 6n
+.Pp
+.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
+The maximum number of open files per user id.
+.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.
+.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 0000000..27729a6
--- /dev/null
+++ b/lib/libc/gen/sysconf.c
@@ -0,0 +1,582 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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 <sys/param.h>
+#include <sys/time.h>
+#include <sys/sysctl.h>
+#include <sys/resource.h>
+#include <sys/socket.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 "../stdlib/atexit.h"
+#include "../stdtime/tzfile.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(name)
+ int name;
+{
+ struct rlimit rl;
+ size_t len;
+ int mib[2], sverrno, value;
+ long defaultresult;
+ const char *path;
+
+ len = sizeof(value);
+ 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:
+ case _SC_STREAM_MAX: /* assume fds run out before memory does */
+ 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_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;
+ value = pathconf(path, _PC_NAME_MAX);
+ if (value == -1 && errno != 0)
+ return (-1);
+ errno = sverrno;
+ return (value);
+
+ 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: if (sysctl(mib, 2, &value, &len, NULL, 0) == -1)
+ return (-1);
+ if (value == 0)
+ return (defaultresult);
+ return (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:
+#if _POSIX_CPUTIME == 0
+#error "_POSIX_CPUTIME"
+#else
+ return (_POSIX_CPUTIME);
+#endif
+#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
+#if _POSIX_THREAD_SAFE_FUNCTIONS > -1
+ case _SC_GETGR_R_SIZE_MAX:
+ case _SC_GETPW_R_SIZE_MAX:
+#error "somebody needs to implement this"
+#endif
+ 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:
+ sverrno = errno;
+ if (sysctlbyname("kern.ipc.shmmin", &value, &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:
+ mib[0] = CTL_HW;
+ mib[1] = HW_NCPU;
+ break;
+
+ default:
+ errno = EINVAL;
+ return (-1);
+ }
+ return (sysctl(mib, 2, &value, &len, NULL, 0) == -1 ? -1 : value);
+}
diff --git a/lib/libc/gen/sysctl.3 b/lib/libc/gen/sysctl.3
new file mode 100644
index 0000000..9ac8cee
--- /dev/null
+++ b/lib/libc/gen/sysctl.3
@@ -0,0 +1,879 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)sysctl.3 8.4 (Berkeley) 5/9/95
+.\" $FreeBSD$
+.\"
+.Dd January 23, 2001
+.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 "int *name" "u_int namelen" "void *oldp" "size_t *oldlenp" "void *newp" "size_t newlen"
+.Ft int
+.Fn sysctlbyname "const char *name" "void *oldp" "size_t *oldlenp" "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.
+.Pp
+.Bl -column CTLXMACHDEPXXX "Next level namesXXXXXX" -offset indent
+.It Sy "Name Next level names Description"
+.It "CTL_DEBUG sys/sysctl.h Debugging"
+.It "CTL_VFS sys/mount.h File system"
+.It "CTL_HW sys/sysctl.h Generic CPU, I/O"
+.It "CTL_KERN sys/sysctl.h High kernel limits"
+.It "CTL_MACHDEP sys/sysctl.h Machine dependent"
+.It "CTL_NET sys/socket.h Networking"
+.It "CTL_USER sys/sysctl.h User-level"
+.It "CTL_VM vm/vm_param.h 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 nameXXXXXX" integerXXX -offset indent
+.It Sy "Second level name Type Changeable"
+.It "HW_MACHINE string no"
+.It "HW_MODEL string no"
+.It "HW_NCPU integer no"
+.It "HW_BYTEORDER integer no"
+.It "HW_PHYSMEM integer no"
+.It "HW_USERMEM integer no"
+.It "HW_PAGESIZE integer no"
+.It "HW_FLOATINGPOINT integer no"
+.It "HW_MACHINE_ARCH string no"
+.\".It "HW_DISKNAMES integer no"
+.\".It "HW_DISKSTATS integer no"
+.El
+.Pp
+.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 (4,321, or 1,234).
+.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 Li HW_FLOATINGPOINT
+Nonzero if the floating point support is in hardware.
+.It Li HW_MACHINE_ARCH
+The machine dependent architecture type.
+.\".It Fa HW_DISKNAMES
+.\".It Fa HW_DISKSTATS
+.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 Type Changeable"
+.It "KERN_ARGMAX integer no"
+.It "KERN_BOOTFILE string yes"
+.It "KERN_BOOTTIME struct timeval no"
+.It "KERN_CLOCKRATE struct clockinfo no"
+.It "KERN_FILE struct file no"
+.It "KERN_HOSTID integer yes"
+.It "KERN_HOSTNAME string yes"
+.It "KERN_JOB_CONTROL integer no"
+.It "KERN_MAXFILES integer yes"
+.It "KERN_MAXFILESPERPROC integer yes"
+.It "KERN_MAXPROC integer no"
+.It "KERN_MAXPROCPERUID integer yes"
+.It "KERN_MAXVNODES integer yes"
+.It "KERN_NGROUPS integer no"
+.It "KERN_NISDOMAINNAME string yes"
+.It "KERN_OSRELDATE integer no"
+.It "KERN_OSRELEASE string no"
+.It "KERN_OSREV integer no"
+.It "KERN_OSTYPE string no"
+.It "KERN_POSIX1 integer no"
+.It "KERN_PROC struct proc no"
+.It "KERN_PROF node not applicable"
+.It "KERN_QUANTUM integer yes"
+.It "KERN_SAVED_IDS integer no"
+.It "KERN_SECURELVL integer raise only"
+.It "KERN_UPDATEINTERVAL integer no"
+.It "KERN_VERSION string no"
+.It "KERN_VNODE struct vnode no"
+.El
+.Pp
+.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 a single
+.Va struct filehead
+followed by an array of
+.Va struct file ,
+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_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 pairs of
+.Va struct proc
+followed by corresponding
+.Va struct eproc
+structures is returned,
+whose size depends on the current number of such objects in the system.
+.Bl -column "Third level nameXXXXXX" "Fourth level is:XXXXXX" -offset indent
+.It "Third level name Fourth level is:"
+.It "KERN_PROC_ALL None"
+.It "KERN_PROC_PID A process ID"
+.It "KERN_PROC_PGRP A process group"
+.It "KERN_PROC_TTY A tty device"
+.It "KERN_PROC_UID A user ID"
+.It "KERN_PROC_RUID 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 level is:XXXXXX" -offset indent
+.It Sy "Third level name Fourth level is:"
+.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 Type Changeable"
+.It "GPROF_STATE integer yes"
+.It "GPROF_COUNT u_short[\|] yes"
+.It "GPROF_FROMS u_short[\|] yes"
+.It "GPROF_TOS struct tostruct yes"
+.It "GPROF_GMONPARAM struct gmonparam 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 contains the kernel address of a vnode
+.Va struct vnode *
+followed by the vnode itself
+.Va struct vnode .
+.El
+.Ss CTL_MACHDEP
+The set of variables defined is architecture dependent.
+The following variables are defined for the i386 architecture.
+.Bl -column "CONSOLE_DEVICEXXX" "struct bootinfoXXX" -offset indent
+.It Sy "Second level name Type Changeable"
+.It Li "CPU_CONSDEV dev_t no"
+.It Li "CPU_ADJKERNTZ int yes"
+.It Li "CPU_DISRTCSET int yes"
+.It Li "CPU_BOOTINFO struct bootinfo no"
+.It Li "CPU_WALLCLOCK int yes"
+.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 Type Changeable"
+.It "PF_ROUTE routing messages no"
+.It "PF_INET IPv4 values yes"
+.It "PF_INET6 IPv6 values yes"
+.El
+.Pp
+.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 and sixth level names are as follows:
+.Bl -column "Fifth level nameXXXXXX" "Sixth level is:XXX" -offset indent
+.It Sy "Fifth level name Sixth level is:"
+.It "NET_RT_FLAGS rtflags"
+.It "NET_RT_DUMP None"
+.It "NET_RT_IFLIST 0 or if_index"
+.It "NET_RT_IFMALIST 0 or if_index"
+.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 .
+.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 Variable Type Changeable"
+.It "icmp bmcastecho integer yes"
+.It "icmp maskrepl integer yes"
+.It "ip forwarding integer yes"
+.It "ip redirect integer yes"
+.It "ip ttl integer yes"
+.It "udp checksum integer 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 Type Changeable"
+.It "USER_BC_BASE_MAX integer no"
+.It "USER_BC_DIM_MAX integer no"
+.It "USER_BC_SCALE_MAX integer no"
+.It "USER_BC_STRING_MAX integer no"
+.It "USER_COLL_WEIGHTS_MAX integer no"
+.It "USER_CS_PATH string no"
+.It "USER_EXPR_NEST_MAX integer no"
+.It "USER_LINE_MAX integer no"
+.It "USER_POSIX2_CHAR_TERM integer no"
+.It "USER_POSIX2_C_BIND integer no"
+.It "USER_POSIX2_C_DEV integer no"
+.It "USER_POSIX2_FORT_DEV integer no"
+.It "USER_POSIX2_FORT_RUN integer no"
+.It "USER_POSIX2_LOCALEDEF integer no"
+.It "USER_POSIX2_SW_DEV integer no"
+.It "USER_POSIX2_UPE integer no"
+.It "USER_POSIX2_VERSION integer no"
+.It "USER_RE_DUP_MAX integer no"
+.It "USER_STREAM_MAX integer no"
+.It "USER_TZNAME_MAX integer no"
+.El
+.Bl -tag -width 6n
+.Pp
+.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 Type Changeable"
+.It "VM_LOADAVG struct loadavg no"
+.It "VM_METER struct vmtotal no"
+.It "VM_PAGEOUT_ALGORITHM integer yes"
+.It "VM_SWAPPING_ENABLED integer maybe"
+.It "VM_V_CACHE_MAX integer yes"
+.It "VM_V_CACHE_MIN integer yes"
+.It "VM_V_FREE_MIN integer yes"
+.It "VM_V_FREE_RESERVED integer yes"
+.It "VM_V_FREE_TARGET integer yes"
+.It "VM_V_INACTIVE_TARGET integer yes"
+.It "VM_V_PAGEOUT_FREE_MIN integer yes"
+.El
+.Pp
+.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_METER
+Return the system wide virtual memory statistics.
+The returned data consists of a
+.Va struct vmtotal .
+.It Li VM_PAGEOUT_ALGORITHM
+0 if the statistics-based page management algorithm is in use
+or 1 if the near-LRU algorithm is in use.
+.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_CACHE_MAX
+Maximum desired size of the cache queue.
+.It Li VM_V_CACHE_MIN
+Minimum desired size of the cache queue.
+If the cache queue size
+falls very far below this value, the pageout daemon is awakened.
+.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 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 0000000..525175a1
--- /dev/null
+++ b/lib/libc/gen/sysctl.c
@@ -0,0 +1,187 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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(int *name, u_int namelen, void *oldp, size_t *oldlenp,
+ void *newp, size_t newlen);
+
+int
+sysctl(name, namelen, oldp, oldlenp, newp, newlen)
+ int *name;
+ u_int namelen;
+ void *oldp, *newp;
+ size_t *oldlenp, newlen;
+{
+ if (name[0] != CTL_USER)
+ return (__sysctl(name, namelen, oldp, oldlenp, newp, newlen));
+
+ if (newp != NULL) {
+ errno = EPERM;
+ return (-1);
+ }
+ if (namelen != 2) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ switch (name[1]) {
+ case USER_CS_PATH:
+ if (oldp && *oldlenp < 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 0000000..4510fe0
--- /dev/null
+++ b/lib/libc/gen/sysctlbyname.c
@@ -0,0 +1,39 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "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>
+#include <string.h>
+
+int
+sysctlbyname(const char *name, void *oldp, size_t *oldlenp, void *newp,
+ size_t newlen)
+{
+ int name2oid_oid[2];
+ int real_oid[CTL_MAXNAME+2];
+ int error;
+ size_t oidlen;
+
+ name2oid_oid[0] = 0; /* This is magic & undocumented! */
+ name2oid_oid[1] = 3;
+
+ oidlen = sizeof(real_oid);
+ error = sysctl(name2oid_oid, 2, real_oid, &oidlen, (void *)name,
+ strlen(name));
+ if (error < 0)
+ return error;
+ oidlen /= sizeof (int);
+ error = sysctl(real_oid, oidlen, oldp, oldlenp, newp, newlen);
+ return (error);
+}
+
diff --git a/lib/libc/gen/sysctlnametomib.c b/lib/libc/gen/sysctlnametomib.c
new file mode 100644
index 0000000..1515784
--- /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, (void *)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 0000000..0163611
--- /dev/null
+++ b/lib/libc/gen/syslog.3
@@ -0,0 +1,299 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)syslog.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd December 30, 2004
+.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("%s", string);
diff --git a/lib/libc/gen/syslog.c b/lib/libc/gen/syslog.c
new file mode 100644
index 0000000..e58e695
--- /dev/null
+++ b/lib/libc/gen/syslog.c
@@ -0,0 +1,439 @@
+/*
+ * 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.
+ * 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.
+ */
+
+#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 0;
+}
+
+/*
+ * 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() failed, 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.
+ * We attempt to reconnect to /var/run/log to take care of
+ * case #1 and keep send()ing data to cover case #2
+ * to give syslogd a chance to empty its socket buffer.
+ *
+ * If we are working with a priveleged socket, then take
+ * only one attempt, because we don't want to freeze a
+ * critical application like su(1) or sshd(8).
+ *
+ */
+
+ if (send(LogFile, tbuf, cnt, 0) < 0) {
+ if (errno != ENOBUFS) {
+ disconnectlog();
+ connectlog();
+ }
+ do {
+ _usleep(1);
+ if (send(LogFile, tbuf, cnt, 0) >= 0) {
+ THREAD_UNLOCK();
+ return;
+ }
+ if (status == CONNPRIV)
+ break;
+ } while (errno == ENOBUFS);
+ } 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, 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, 0)) == -1)
+ return;
+ (void)_fcntl(LogFile, F_SETFD, 1);
+ }
+ if (LogFile != -1 && status == NOCONN) {
+ SyslogAddr.sun_len = sizeof(SyslogAddr);
+ SyslogAddr.sun_family = AF_UNIX;
+
+ /*
+ * First try priveleged 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();
+ (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 0000000..d6aaa76
--- /dev/null
+++ b/lib/libc/gen/tcgetpgrp.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.
+.\" 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.
+.\"
+.\" @(#)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/tcsendbreak.3 b/lib/libc/gen/tcsendbreak.3
new file mode 100644
index 0000000..e85d104
--- /dev/null
+++ b/lib/libc/gen/tcsendbreak.3
@@ -0,0 +1,157 @@
+.\" 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. 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.
+.\"
+.\" @(#)tcsendbreak.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.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.
+.El
+.Sh SEE ALSO
+.Xr tcsetattr 3 ,
+.Xr termios 4
+.Sh STANDARDS
+The
+.Fn tcsendbreak ,
+.Fn tcdrain ,
+.Fn tcflush
+and
+.Fn tcflow
+functions are expected to be compliant with the
+.St -p1003.1-88
+specification.
diff --git a/lib/libc/gen/tcsetattr.3 b/lib/libc/gen/tcsetattr.3
new file mode 100644
index 0000000..82df2a6
--- /dev/null
+++ b/lib/libc/gen/tcsetattr.3
@@ -0,0 +1,333 @@
+.\" 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. 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.
+.\"
+.\" @(#)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 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 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 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 .
+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 mode with
+.Fn cfmakeraw
+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
+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 0000000..8ddb469
--- /dev/null
+++ b/lib/libc/gen/tcsetpgrp.3
@@ -0,0 +1,99 @@
+.\" 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. 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.
+.\"
+.\" @(#)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/telldir.c b/lib/libc/gen/telldir.c
new file mode 100644
index 0000000..170e547
--- /dev/null
+++ b/lib/libc/gen/telldir.c
@@ -0,0 +1,133 @@
+/*
+ * 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. 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.
+ */
+
+#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 "telldir.h"
+
+/*
+ * The option SINGLEUSE may be defined to say that a telldir
+ * cookie may be used only once before it is freed. This option
+ * is used to avoid having memory usage grow without bound.
+ */
+#define SINGLEUSE
+
+/*
+ * return a pointer into a directory
+ */
+long
+telldir(dirp)
+ DIR *dirp;
+{
+ struct ddloc *lp;
+
+ if ((lp = (struct ddloc *)malloc(sizeof(struct ddloc))) == NULL)
+ return (-1);
+ if (__isthreaded)
+ _pthread_mutex_lock((pthread_mutex_t *)&dirp->dd_lock);
+ 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);
+ if (__isthreaded)
+ _pthread_mutex_unlock((pthread_mutex_t *)&dirp->dd_lock);
+ return (lp->loc_index);
+}
+
+/*
+ * seek to an entry in a directory.
+ * Only values returned by "telldir" should be passed to seekdir.
+ */
+void
+_seekdir(dirp, loc)
+ 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)
+ goto found;
+ (void) lseek(dirp->dd_fd, (off_t)lp->loc_seek, SEEK_SET);
+ dirp->dd_seek = lp->loc_seek;
+ dirp->dd_loc = 0;
+ while (dirp->dd_loc < lp->loc_loc) {
+ dp = _readdir_unlocked(dirp);
+ if (dp == NULL)
+ break;
+ }
+found:
+#ifdef SINGLEUSE
+ LIST_REMOVE(lp, loc_lqe);
+ free((caddr_t)lp);
+#endif
+}
+
+/*
+ * Reclaim memory for telldir cookies which weren't used.
+ */
+void
+_reclaim_telldir(dirp)
+ 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 0000000..4fb4cb6
--- /dev/null
+++ b/lib/libc/gen/telldir.h
@@ -0,0 +1,66 @@
+/*
+ * 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>
+
+/*
+ * 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 */
+};
+
+struct dirent *_readdir_unlocked(DIR *);
+void _reclaim_telldir(DIR *);
+void _seekdir(DIR *, long);
+
+#endif
diff --git a/lib/libc/gen/termios.c b/lib/libc/gen/termios.c
new file mode 100644
index 0000000..cc57cf8
--- /dev/null
+++ b/lib/libc/gen/termios.c
@@ -0,0 +1,245 @@
+/*-
+ * 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. 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.
+ */
+
+#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 <termios.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+int
+tcgetattr(fd, t)
+ int fd;
+ struct termios *t;
+{
+
+ return (_ioctl(fd, TIOCGETA, t));
+}
+
+int
+tcsetattr(fd, opt, t)
+ int fd, 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(fd)
+ int fd;
+{
+ int s;
+
+ if (_ioctl(fd, TIOCGPGRP, &s) < 0)
+ return ((pid_t)-1);
+
+ return ((pid_t)s);
+}
+
+speed_t
+cfgetospeed(t)
+ const struct termios *t;
+{
+
+ return (t->c_ospeed);
+}
+
+speed_t
+cfgetispeed(t)
+ const struct termios *t;
+{
+
+ return (t->c_ispeed);
+}
+
+int
+cfsetospeed(t, speed)
+ struct termios *t;
+ speed_t speed;
+{
+
+ t->c_ospeed = speed;
+ return (0);
+}
+
+int
+cfsetispeed(t, speed)
+ struct termios *t;
+ speed_t speed;
+{
+
+ t->c_ispeed = speed;
+ return (0);
+}
+
+int
+cfsetspeed(t, speed)
+ 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(t)
+ 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;
+}
+
+int
+tcsendbreak(fd, len)
+ int fd, len;
+{
+ 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
+__tcdrain(fd)
+ int fd;
+{
+ return (_ioctl(fd, TIOCDRAIN, 0));
+}
+
+__weak_reference(__tcdrain, tcdrain);
+__weak_reference(__tcdrain, _tcdrain);
+
+int
+tcflush(fd, which)
+ int fd, 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(fd, action)
+ int fd, 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 0000000..241494a
--- /dev/null
+++ b/lib/libc/gen/time.3
@@ -0,0 +1,104 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)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 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 0000000..4468b01
--- /dev/null
+++ b/lib/libc/gen/time.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.
+ * 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.
+ */
+
+#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(t)
+ time_t *t;
+{
+ struct timeval tt;
+ time_t retval;
+
+ if (gettimeofday(&tt, (struct timezone *)0) < 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 0000000..4ef554c
--- /dev/null
+++ b/lib/libc/gen/times.3
@@ -0,0 +1,144 @@
+.\" 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. 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.
+.\"
+.\" @(#)times.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.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
+0 hours, 0 minutes, 0 seconds, January 1, 1970, Coordinated Universal
+Time.
+.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 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 0000000..dd31524
--- /dev/null
+++ b/lib/libc/gen/times.c
@@ -0,0 +1,71 @@
+/*-
+ * 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. 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.
+ */
+
+#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 0000000..2a90c11
--- /dev/null
+++ b/lib/libc/gen/timezone.3
@@ -0,0 +1,73 @@
+.\" 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. 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.
+.\"
+.\" @(#)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 0000000..c9d5957
--- /dev/null
+++ b/lib/libc/gen/timezone.c
@@ -0,0 +1,137 @@
+/*
+ * 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. 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.
+ */
+
+#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();
+
+/*
+ * 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(zone, dst)
+ int zone,
+ dst;
+{
+ char *beg,
+ *end;
+
+ if ( (beg = getenv("TZNAME")) ) { /* set in environment */
+ if ( (end = index(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(zone,dst)
+ 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 0000000..f63b361
--- /dev/null
+++ b/lib/libc/gen/tls.c
@@ -0,0 +1,317 @@
+/*-
+ * 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 <stdlib.h>
+#include <string.h>
+#include <elf.h>
+#include <assert.h>
+
+#include "libc_private.h"
+
+/* XXX not sure what variants to use for arm. */
+
+__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(__ia64__) || defined(__alpha__) || defined(__powerpc__)
+#define TLS_VARIANT_I
+#endif
+#if defined(__i386__) || defined(__amd64__) || defined(__sparc64__) || \
+ defined(__arm__)
+#define TLS_VARIANT_II
+#endif
+
+#ifndef PIC
+
+#define round(size, align) \
+ (((size) + (align) - 1) & ~((align) - 1))
+
+static size_t tls_static_space;
+static size_t tls_init_size;
+#ifdef TLS_VARIANT_I
+static size_t tls_init_offset;
+#endif
+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
+
+/*
+ * Free Static TLS using the Variant I method.
+ */
+void
+__libc_free_tls(void *tls, size_t tcbsize __unused, size_t tcbalign __unused)
+{
+ Elf_Addr* dtv;
+
+ dtv = ((Elf_Addr**)tls)[0];
+ free(tls);
+ free(dtv);
+}
+
+/*
+ * Allocate Static TLS using the Variant I method.
+ */
+void *
+__libc_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign __unused)
+{
+ size_t size;
+ char *tls;
+ Elf_Addr *dtv;
+
+ size = tls_static_space;
+ if (size < tcbsize)
+ size = tcbsize;
+
+ tls = calloc(1, size);
+ dtv = malloc(3 * sizeof(Elf_Addr));
+
+ *(Elf_Addr **) tls = dtv;
+
+ dtv[0] = 1;
+ dtv[1] = 1;
+ dtv[2] = (Elf_Addr)(tls + tls_init_offset);
+ if (oldtls) {
+ /*
+ * Copy the static TLS block over whole.
+ */
+ memcpy(tls + tls_init_offset,
+ (char *)oldtls + tls_init_offset,
+ tls_static_space - tls_init_offset);
+
+ /*
+ * 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(tls + tls_init_offset, tls_init, tls_init_size);
+ memset(tls + tls_init_offset + tls_init_size,
+ 0, tls_static_space - tls_init_size);
+ }
+
+ return tls;
+}
+
+#endif
+
+#ifdef TLS_VARIANT_II
+
+/*
+ * 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 = round(tls_static_space, tcbalign);
+
+ dtv = ((Elf_Addr**)tcb)[1];
+ tlsend = (Elf_Addr) tcb;
+ tlsstart = tlsend - size;
+ free((void*) tlsstart);
+ 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 = round(tls_static_space, tcbalign);
+
+ assert(tcbsize >= 2*sizeof(Elf_Addr));
+ tls = calloc(1, size + tcbsize);
+ dtv = 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()
+{
+#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 = 0;
+ 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 == 0 || phent != sizeof(Elf_Phdr) || phnum == 0)
+ return;
+
+ for (i = 0; (unsigned) i < phnum; i++) {
+ if (phdr[i].p_type == PT_TLS) {
+#ifdef TLS_VARIANT_I
+ tls_static_space = round(2*sizeof(Elf_Addr),
+ phdr[i].p_align) + phdr[i].p_memsz;
+ tls_init_offset = round(2*sizeof(Elf_Addr),
+ phdr[i].p_align);
+#else
+ tls_static_space = round(phdr[i].p_memsz,
+ phdr[i].p_align);
+#endif
+ tls_init_size = phdr[i].p_filesz;
+ tls_init = (void*) phdr[i].p_vaddr;
+ }
+ }
+
+ tls = _rtld_allocate_tls(NULL, 3*sizeof(Elf_Addr),
+ sizeof(Elf_Addr));
+
+ _set_tp(tls);
+#endif
+}
diff --git a/lib/libc/gen/ttyname.3 b/lib/libc/gen/ttyname.3
new file mode 100644
index 0000000..5f427fb
--- /dev/null
+++ b/lib/libc/gen/ttyname.3
@@ -0,0 +1,161 @@
+.\" 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. 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.
+.\"
+.\" @(#)ttyname.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd May 14, 2005
+.Dt TTYNAME 3
+.Os
+.Sh NAME
+.Nm ttyname ,
+.Nm ttyname_r ,
+.Nm isatty ,
+.Nm ttyslot
+.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"
+.Ft int
+.Fn ttyslot void
+.Sh DESCRIPTION
+These functions operate on the system file descriptors for terminal
+type devices.
+These descriptors are not related to the standard
+.Tn I/O
+.Dv FILE
+typedef, but refer to the special device files found in
+.Pa /dev
+and named
+.Pa /dev/tty Ns Ar xx
+and for which an entry exists
+in the initialization file
+.Pa /etc/ttys .
+(See
+.Xr ttys 5 . )
+.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.
+.Pp
+The
+.Fn ttyslot
+function
+fetches the current process' control terminal number from the
+.Xr ttys 5
+file entry.
+.Sh RETURN VALUES
+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.
+.Pp
+The
+.Fn ttyslot
+function
+returns the unit number of the device file if found; otherwise
+the value zero is returned.
+.Sh FILES
+.Bl -tag -width ".Pa /etc/ttys" -compact
+.It Pa /dev/\(**
+.It Pa /etc/ttys
+.El
+.Sh ERRORS
+The
+.Fn ttyname_r
+may fail and return the following error codes:
+.Bl -tag -width Er
+.It Bq Er ENOTTY
+The
+.Fa fd
+argument
+is not a valid file descriptor.
+.It Bq Er ERANGE
+The
+.Fa bufsize
+argument
+is smaller than the length of the string to be returned.
+.El
+.Sh SEE ALSO
+.Xr ioctl 2 ,
+.Xr ttys 5
+.Sh HISTORY
+The
+.Fn isatty ,
+.Fn ttyname ,
+and
+.Fn ttyslot
+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 0000000..ed198ea
--- /dev/null
+++ b/lib/libc/gen/ttyname.c
@@ -0,0 +1,124 @@
+/*
+ * 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. 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.
+ */
+
+#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/stat.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)
+{
+ struct stat sb;
+ struct fiodgname_arg fgn;
+ size_t used;
+
+ *buf = '\0';
+
+ /* Must be a terminal. */
+ if (!isatty(fd))
+ return (ENOTTY);
+ /* Must be a character device. */
+ if (_fstat(fd, &sb) || !S_ISCHR(sb.st_mode))
+ return (ENOTTY);
+ /* Must have enough room */
+ if (len <= sizeof(_PATH_DEV))
+ return (ERANGE);
+
+ strcpy(buf, _PATH_DEV);
+ used = strlen(buf);
+ fgn.len = len - used;
+ fgn.buf = buf + used;
+ if (!_ioctl(fd, FIODGNAME, &fgn))
+ return (0);
+ used = strlen(buf);
+ devname_r(sb.st_rdev, S_IFCHR, buf + used, len - used);
+ 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 0000000..2710e70
--- /dev/null
+++ b/lib/libc/gen/ttyslot.c
@@ -0,0 +1,70 @@
+/*
+ * 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. 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.
+ */
+
+#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$");
+
+#include <ttyent.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+int
+ttyslot()
+{
+ struct ttyent *ttyp;
+ int slot;
+ char *p;
+ int cnt;
+ char *name;
+
+ setttyent();
+ for (cnt = 0; cnt < 3; ++cnt)
+ if ( (name = ttyname(cnt)) ) {
+ if ( (p = rindex(name, '/')) )
+ ++p;
+ else
+ p = name;
+ for (slot = 1; (ttyp = getttyent()); ++slot)
+ if (!strcmp(ttyp->ty_name, p)) {
+ endttyent();
+ return(slot);
+ }
+ break;
+ }
+ endttyent();
+ return(0);
+}
diff --git a/lib/libc/gen/tzset.3 b/lib/libc/gen/tzset.3
new file mode 100644
index 0000000..80c525d
--- /dev/null
+++ b/lib/libc/gen/tzset.3
@@ -0,0 +1,342 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)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/GMT
+for
+.Tn UTC
+leap seconds
+.El
+.Pp
+If the file
+.Pa /usr/share/zoneinfo/GMT
+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 0000000..7783a30
--- /dev/null
+++ b/lib/libc/gen/ualarm.3
@@ -0,0 +1,101 @@
+.\" 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.
+.\" 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.
+.\"
+.\" 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 sigpause 2 ,
+.Xr sigvec 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 0000000..f56a70d
--- /dev/null
+++ b/lib/libc/gen/ualarm.c
@@ -0,0 +1,67 @@
+/*
+ * 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. 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.
+ */
+
+#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(usecs, reload)
+ 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 0000000..0574322
--- /dev/null
+++ b/lib/libc/gen/ucontext.3
@@ -0,0 +1,107 @@
+.\" 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 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 makecontext 3
diff --git a/lib/libc/gen/ulimit.3 b/lib/libc/gen/ulimit.3
new file mode 100644
index 0000000..e4c2d76
--- /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 0000000..e1bc020
--- /dev/null
+++ b/lib/libc/gen/ulimit.c
@@ -0,0 +1,68 @@
+/*-
+ * 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;
+ long 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);
+ limit.rlim_max = limit.rlim_cur = (rlim_t)arg * 512;
+
+ /* The setrlimit() function sets errno to EPERM if needed. */
+ if (setrlimit(RLIMIT_FSIZE, &limit) == -1)
+ return (-1);
+ if (arg * 512 > LONG_MAX)
+ return (LONG_MAX);
+ return (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 0000000..b9e2c9a
--- /dev/null
+++ b/lib/libc/gen/uname.3
@@ -0,0 +1,121 @@
+.\" 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.
+.\"
+.\" @(#)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 0000000..b5d5af3
--- /dev/null
+++ b/lib/libc/gen/uname.c
@@ -0,0 +1,51 @@
+/*-
+ * 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.
+ */
+
+#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 *name)
+{
+ return __xuname(32, name);
+}
diff --git a/lib/libc/gen/unvis.3 b/lib/libc/gen/unvis.3
new file mode 100644
index 0000000..f371f9a
--- /dev/null
+++ b/lib/libc/gen/unvis.3
@@ -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.
+.\" 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.
+.\"
+.\" @(#)unvis.3 8.2 (Berkeley) 12/11/93
+.\" $FreeBSD$
+.\"
+.Dd December 11, 1993
+.Dt UNVIS 3
+.Os
+.Sh NAME
+.Nm unvis ,
+.Nm strunvis
+.Nd decode a visual representation of characters
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In vis.h
+.Ft int
+.Fn unvis "char *cp" "int c" "int *astate" "int flag"
+.Ft int
+.Fn strunvis "char *dst" "const char *src"
+.Ft int
+.Fn strunvisx "char *dst" "const char *src" "int flag"
+.Sh DESCRIPTION
+The
+.Fn unvis ,
+.Fn strunvis
+and
+.Fn strunvisx
+functions
+are used to decode a visual representation of characters, as produced
+by the
+.Xr vis 3
+function, back into
+the original form.
+Unvis is called with successive characters in
+.Fa c
+until a valid
+sequence is recognized, at which time the decoded character is
+available at the character pointed to by
+.Fa cp .
+Strunvis decodes the
+characters pointed to by
+.Fa src
+into the buffer pointed to by
+.Fa dst .
+.Pp
+The
+.Fn strunvis
+function
+simply copies
+.Fa src
+to
+.Fa dst ,
+decoding any escape sequences along the way,
+and returns the number of characters placed into
+.Fa dst ,
+or \-1 if an
+invalid escape sequence was detected.
+The size of
+.Fa dst
+should be
+equal to the size of
+.Fa src
+(that is, no expansion takes place during
+decoding).
+.Pp
+The
+.Fn strunvisx
+function does the same as the
+.Fn strunvis
+function,
+but it allows you to add a flag that specifies the style the string
+.Fa src
+is encoded with.
+Currently, the only supported flag is
+.Dv VIS_HTTPSTYLE .
+.Pp
+The
+.Fn unvis
+function
+implements a state machine that can be used to decode an arbitrary
+stream of bytes.
+All state associated with the bytes being decoded
+is stored outside the
+.Fn unvis
+function (that is, a pointer to the state is passed in), so
+calls decoding different streams can be freely intermixed.
+To
+start decoding a stream of bytes, first initialize an integer
+to zero.
+Call
+.Fn unvis
+with each successive byte, along with a pointer
+to this integer, and a pointer to a destination character.
+The
+.Fn unvis
+function
+has several return codes that must be handled properly.
+They are:
+.Bl -tag -width UNVIS_VALIDPUSH
+.It Li \&0 (zero)
+Another character is necessary; nothing has been recognized yet.
+.It Dv UNVIS_VALID
+A valid character has been recognized and is available at the location
+pointed to by cp.
+.It Dv UNVIS_VALIDPUSH
+A valid character has been recognized and is available at the location
+pointed to by cp; however, the character currently passed in should
+be passed in again.
+.It Dv UNVIS_NOCHAR
+A valid sequence was detected, but no character was produced.
+This
+return code is necessary to indicate a logical break between characters.
+.It Dv UNVIS_SYNBAD
+An invalid escape sequence was detected, or the decoder is in an
+unknown state.
+The decoder is placed into the starting state.
+.El
+.Pp
+When all bytes in the stream have been processed, call
+.Fn unvis
+one more time with
+.Fa flag
+set to
+.Dv UNVIS_END
+to extract any remaining character (the character passed in is ignored).
+.Pp
+The
+.Fa flag
+argument is also used to specify the encoding style of the source.
+If set to
+.Dv VIS_HTTPSTYLE ,
+.Fn unvis
+will decode URI strings as specified in RFC 1808.
+.Pp
+The following code fragment illustrates a proper use of
+.Fn unvis .
+.Bd -literal -offset indent
+int state = 0;
+char out;
+
+while ((ch = getchar()) != EOF) {
+again:
+ switch(unvis(&out, ch, &state, 0)) {
+ case 0:
+ case UNVIS_NOCHAR:
+ break;
+ case UNVIS_VALID:
+ (void) putchar(out);
+ break;
+ case UNVIS_VALIDPUSH:
+ (void) putchar(out);
+ goto again;
+ case UNVIS_SYNBAD:
+ (void)fprintf(stderr, "bad sequence!\en");
+ exit(1);
+ }
+}
+if (unvis(&out, (char)0, &state, UNVIS_END) == UNVIS_VALID)
+ (void) putchar(out);
+.Ed
+.Sh SEE ALSO
+.Xr vis 1 ,
+.Xr vis 3
+.Rs
+.%A R. Fielding
+.%T Relative Uniform Resource Locators
+.%O RFC1808
+.Re
+.Sh HISTORY
+The
+.Fn unvis
+function
+first appeared in
+.Bx 4.4 .
diff --git a/lib/libc/gen/unvis.c b/lib/libc/gen/unvis.c
new file mode 100644
index 0000000..c5bf6bb
--- /dev/null
+++ b/lib/libc/gen/unvis.c
@@ -0,0 +1,297 @@
+/*-
+ * 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. 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)unvis.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <ctype.h>
+#include <vis.h>
+
+/*
+ * decode driven by state machine
+ */
+#define S_GROUND 0 /* haven't seen escape char */
+#define S_START 1 /* start decoding special sequence */
+#define S_META 2 /* metachar started (M) */
+#define S_META1 3 /* metachar more, regular char (-) */
+#define S_CTRL 4 /* control char started (^) */
+#define S_OCTAL2 5 /* octal digit 2 */
+#define S_OCTAL3 6 /* octal digit 3 */
+#define S_HEX2 7 /* hex digit 2 */
+
+#define S_HTTP 0x080 /* %HEXHEX escape */
+
+#define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
+#define ishex(c) ((((u_char)(c)) >= '0' && ((u_char)(c)) <= '9') || (((u_char)(c)) >= 'a' && ((u_char)(c)) <= 'f'))
+
+/*
+ * unvis - decode characters previously encoded by vis
+ */
+int
+unvis(char *cp, int c, int *astate, int flag)
+{
+
+ if (flag & UNVIS_END) {
+ if (*astate == S_OCTAL2 || *astate == S_OCTAL3) {
+ *astate = S_GROUND;
+ return (UNVIS_VALID);
+ }
+ return (*astate == S_GROUND ? UNVIS_NOCHAR : UNVIS_SYNBAD);
+ }
+
+ switch (*astate & ~S_HTTP) {
+
+ case S_GROUND:
+ *cp = 0;
+ if (c == '\\') {
+ *astate = S_START;
+ return (0);
+ }
+ if (flag & VIS_HTTPSTYLE && c == '%') {
+ *astate = S_START | S_HTTP;
+ return (0);
+ }
+ *cp = c;
+ return (UNVIS_VALID);
+
+ case S_START:
+ if (*astate & S_HTTP) {
+ if (ishex(tolower(c))) {
+ *cp = isdigit(c) ? (c - '0') : (tolower(c) - 'a');
+ *astate = S_HEX2;
+ return (0);
+ }
+ }
+ switch(c) {
+ case '\\':
+ *cp = c;
+ *astate = S_GROUND;
+ return (UNVIS_VALID);
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ *cp = (c - '0');
+ *astate = S_OCTAL2;
+ return (0);
+ case 'M':
+ *cp = 0200;
+ *astate = S_META;
+ return (0);
+ case '^':
+ *astate = S_CTRL;
+ return (0);
+ case 'n':
+ *cp = '\n';
+ *astate = S_GROUND;
+ return (UNVIS_VALID);
+ case 'r':
+ *cp = '\r';
+ *astate = S_GROUND;
+ return (UNVIS_VALID);
+ case 'b':
+ *cp = '\b';
+ *astate = S_GROUND;
+ return (UNVIS_VALID);
+ case 'a':
+ *cp = '\007';
+ *astate = S_GROUND;
+ return (UNVIS_VALID);
+ case 'v':
+ *cp = '\v';
+ *astate = S_GROUND;
+ return (UNVIS_VALID);
+ case 't':
+ *cp = '\t';
+ *astate = S_GROUND;
+ return (UNVIS_VALID);
+ case 'f':
+ *cp = '\f';
+ *astate = S_GROUND;
+ return (UNVIS_VALID);
+ case 's':
+ *cp = ' ';
+ *astate = S_GROUND;
+ return (UNVIS_VALID);
+ case 'E':
+ *cp = '\033';
+ *astate = S_GROUND;
+ return (UNVIS_VALID);
+ case '\n':
+ /*
+ * hidden newline
+ */
+ *astate = S_GROUND;
+ return (UNVIS_NOCHAR);
+ case '$':
+ /*
+ * hidden marker
+ */
+ *astate = S_GROUND;
+ return (UNVIS_NOCHAR);
+ }
+ *astate = S_GROUND;
+ return (UNVIS_SYNBAD);
+
+ case S_META:
+ if (c == '-')
+ *astate = S_META1;
+ else if (c == '^')
+ *astate = S_CTRL;
+ else {
+ *astate = S_GROUND;
+ return (UNVIS_SYNBAD);
+ }
+ return (0);
+
+ case S_META1:
+ *astate = S_GROUND;
+ *cp |= c;
+ return (UNVIS_VALID);
+
+ case S_CTRL:
+ if (c == '?')
+ *cp |= 0177;
+ else
+ *cp |= c & 037;
+ *astate = S_GROUND;
+ return (UNVIS_VALID);
+
+ case S_OCTAL2: /* second possible octal digit */
+ if (isoctal(c)) {
+ /*
+ * yes - and maybe a third
+ */
+ *cp = (*cp << 3) + (c - '0');
+ *astate = S_OCTAL3;
+ return (0);
+ }
+ /*
+ * no - done with current sequence, push back passed char
+ */
+ *astate = S_GROUND;
+ return (UNVIS_VALIDPUSH);
+
+ case S_OCTAL3: /* third possible octal digit */
+ *astate = S_GROUND;
+ if (isoctal(c)) {
+ *cp = (*cp << 3) + (c - '0');
+ return (UNVIS_VALID);
+ }
+ /*
+ * we were done, push back passed char
+ */
+ return (UNVIS_VALIDPUSH);
+
+ case S_HEX2: /* second mandatory hex digit */
+ if (ishex(tolower(c))) {
+ *cp = (isdigit(c) ? (*cp << 4) + (c - '0') : (*cp << 4) + (tolower(c) - 'a' + 10));
+ }
+ *astate = S_GROUND;
+ return (UNVIS_VALID);
+
+ default:
+ /*
+ * decoder in unknown state - (probably uninitialized)
+ */
+ *astate = S_GROUND;
+ return (UNVIS_SYNBAD);
+ }
+}
+
+/*
+ * strunvis - decode src into dst
+ *
+ * Number of chars decoded into dst is returned, -1 on error.
+ * Dst is null terminated.
+ */
+
+int
+strunvis(char *dst, const char *src)
+{
+ char c;
+ char *start = dst;
+ int state = 0;
+
+ while ( (c = *src++) ) {
+ again:
+ switch (unvis(dst, c, &state, 0)) {
+ case UNVIS_VALID:
+ dst++;
+ break;
+ case UNVIS_VALIDPUSH:
+ dst++;
+ goto again;
+ case 0:
+ case UNVIS_NOCHAR:
+ break;
+ default:
+ return (-1);
+ }
+ }
+ if (unvis(dst, c, &state, UNVIS_END) == UNVIS_VALID)
+ dst++;
+ *dst = '\0';
+ return (dst - start);
+}
+
+int
+strunvisx(char *dst, const char *src, int flag)
+{
+ char c;
+ char *start = dst;
+ int state = 0;
+
+ while ( (c = *src++) ) {
+ again:
+ switch (unvis(dst, c, &state, flag)) {
+ case UNVIS_VALID:
+ dst++;
+ break;
+ case UNVIS_VALIDPUSH:
+ dst++;
+ goto again;
+ case 0:
+ case UNVIS_NOCHAR:
+ break;
+ default:
+ return (-1);
+ }
+ }
+ if (unvis(dst, c, &state, UNVIS_END) == UNVIS_VALID)
+ dst++;
+ *dst = '\0';
+ return (dst - start);
+}
diff --git a/lib/libc/gen/usleep.3 b/lib/libc/gen/usleep.3
new file mode 100644
index 0000000..ffdc922
--- /dev/null
+++ b/lib/libc/gen/usleep.3
@@ -0,0 +1,84 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)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 0000000..1eefbdb
--- /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.
+ * 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.
+ */
+
+#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"
+
+int
+__usleep(useconds)
+ useconds_t useconds;
+{
+ struct timespec time_to_sleep;
+
+ time_to_sleep.tv_nsec = (useconds % 1000000) * 1000;
+ time_to_sleep.tv_sec = useconds / 1000000;
+ return (_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 0000000..aed098e
--- /dev/null
+++ b/lib/libc/gen/utime.3
@@ -0,0 +1,96 @@
+.\" 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. 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.
+.\"
+.\" @(#)utime.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.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 utimes 2 .
+.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 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 0000000..7e544ad
--- /dev/null
+++ b/lib/libc/gen/utime.c
@@ -0,0 +1,59 @@
+/*-
+ * 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. 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.
+ */
+
+#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(path, times)
+ 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/valloc.3 b/lib/libc/gen/valloc.3
new file mode 100644
index 0000000..d9d60c1
--- /dev/null
+++ b/lib/libc/gen/valloc.3
@@ -0,0 +1,81 @@
+.\" 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. 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.
+.\"
+.\" @(#)valloc.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd September 13, 2005
+.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
+.Bf -symbolic
+The
+.Fn valloc
+function is obsoleted by
+.Xr posix_memalign 3 ,
+which can be used to request page-aligned allocations.
+.Ef
+.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
+in
+.Bx 7.0 .
diff --git a/lib/libc/gen/valloc.c b/lib/libc/gen/valloc.c
new file mode 100644
index 0000000..9d888d3
--- /dev/null
+++ b/lib/libc/gen/valloc.c
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ * 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.
+ */
+
+#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/vis.3 b/lib/libc/gen/vis.3
new file mode 100644
index 0000000..58b2c76
--- /dev/null
+++ b/lib/libc/gen/vis.3
@@ -0,0 +1,312 @@
+.\" Copyright (c) 1989, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. 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.
+.\"
+.\" From: @(#)vis.3 8.1 (Berkeley) 6/9/93
+.\" $FreeBSD$
+.\"
+.Dd April 9, 2006
+.Dt VIS 3
+.Os
+.Sh NAME
+.Nm vis
+.Nd visually encode characters
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In vis.h
+.Ft char *
+.Fn vis "char *dst" "int c" "int flag" "int nextc"
+.Ft int
+.Fn strvis "char *dst" "const char *src" "int flag"
+.Ft int
+.Fn strvisx "char *dst" "const char *src" "size_t len" "int flag"
+.Sh DESCRIPTION
+The
+.Fn vis
+function
+copies into
+.Fa dst
+a string which represents the character
+.Fa c .
+If
+.Fa c
+needs no encoding, it is copied in unaltered.
+The string is
+null terminated, and a pointer to the end of the string is
+returned.
+The maximum length of any encoding is four
+characters (not including the trailing
+.Dv NUL ) ;
+thus, when
+encoding a set of characters into a buffer, the size of the buffer should
+be four times the number of characters encoded, plus one for the trailing
+.Dv NUL .
+The
+.Fa flag
+argument is used for altering the default range of
+characters considered for encoding and for altering the visual
+representation.
+The additional character,
+.Fa nextc ,
+is only used when selecting the
+.Dv VIS_CSTYLE
+encoding format (explained below).
+.Pp
+The
+.Fn strvis
+and
+.Fn strvisx
+functions copy into
+.Fa dst
+a visual representation of
+the string
+.Fa src .
+The
+.Fn strvis
+function encodes characters from
+.Fa src
+up to the
+first
+.Dv NUL .
+The
+.Fn strvisx
+function encodes exactly
+.Fa len
+characters from
+.Fa src
+(this
+is useful for encoding a block of data that may contain
+.Dv NUL Ns 's ) .
+Both forms
+.Dv NUL
+terminate
+.Fa dst .
+The size of
+.Fa dst
+must be four times the number
+of characters encoded from
+.Fa src
+(plus one for the
+.Dv NUL ) .
+Both
+forms return the number of characters in dst (not including
+the trailing
+.Dv NUL ) .
+.Pp
+The encoding is a unique, invertible representation composed entirely of
+graphic characters; it can be decoded back into the original form using
+the
+.Xr unvis 3
+or
+.Xr strunvis 3
+functions.
+.Pp
+There are two parameters that can be controlled: the range of
+characters that are encoded, and the type
+of representation used.
+By default, all non-graphic characters
+except space, tab, and newline are encoded.
+(See
+.Xr isgraph 3 . )
+The following flags
+alter this:
+.Bl -tag -width VIS_WHITEX
+.It Dv VIS_GLOB
+Also encode magic characters
+.Ql ( * ,
+.Ql \&? ,
+.Ql \&[
+and
+.Ql # )
+recognized by
+.Xr glob 3 .
+.It Dv VIS_SP
+Also encode space.
+.It Dv VIS_TAB
+Also encode tab.
+.It Dv VIS_NL
+Also encode newline.
+.It Dv VIS_WHITE
+Synonym for
+.Dv VIS_SP
+\&|
+.Dv VIS_TAB
+\&|
+.Dv VIS_NL .
+.It Dv VIS_SAFE
+Only encode "unsafe" characters.
+Unsafe means control
+characters which may cause common terminals to perform
+unexpected functions.
+Currently this form allows space,
+tab, newline, backspace, bell, and return - in addition
+to all graphic characters - unencoded.
+.El
+.Pp
+There are four forms of encoding.
+Most forms use the backslash character
+.Ql \e
+to introduce a special
+sequence; two backslashes are used to represent a real backslash.
+These are the visual formats:
+.Bl -tag -width VIS_HTTPSTYLE
+.It (default)
+Use an
+.Ql M
+to represent meta characters (characters with the 8th
+bit set), and use caret
+.Ql ^
+to represent control characters see
+.Pf ( Xr iscntrl 3 ) .
+The following formats are used:
+.Bl -tag -width xxxxx
+.It Dv \e^C
+Represents the control character
+.Ql C .
+Spans characters
+.Ql \e000
+through
+.Ql \e037 ,
+and
+.Ql \e177
+(as
+.Ql \e^? ) .
+.It Dv \eM-C
+Represents character
+.Ql C
+with the 8th bit set.
+Spans characters
+.Ql \e241
+through
+.Ql \e376 .
+.It Dv \eM^C
+Represents control character
+.Ql C
+with the 8th bit set.
+Spans characters
+.Ql \e200
+through
+.Ql \e237 ,
+and
+.Ql \e377
+(as
+.Ql \eM^? ) .
+.It Dv \e040
+Represents
+.Tn ASCII
+space.
+.It Dv \e240
+Represents Meta-space.
+.El
+.Pp
+.It Dv VIS_CSTYLE
+Use C-style backslash sequences to represent standard non-printable
+characters.
+The following sequences are used to represent the indicated characters:
+.Pp
+.Bl -tag -width ".Li \e0" -offset indent -compact
+.It Li \ea
+.Dv BEL No (007)
+.It Li \eb
+.Dv BS No (010)
+.It Li \ef
+.Dv NP No (014)
+.It Li \en
+.Dv NL No (012)
+.It Li \er
+.Dv CR No (015)
+.It Li \es
+.Dv SP No (040)
+.It Li \et
+.Dv HT No (011)
+.It Li \ev
+.Dv VT No (013)
+.It Li \e0
+.Dv NUL No (000)
+.El
+.Pp
+When using this format, the
+.Fa nextc
+argument is looked at to determine
+if a
+.Dv NUL
+character can be encoded as
+.Ql \e0
+instead of
+.Ql \e000 .
+If
+.Fa nextc
+is an octal digit, the latter representation is used to
+avoid ambiguity.
+.It Dv VIS_HTTPSTYLE
+Use URI encoding as described in RFC 1808.
+The form is
+.Ql %dd
+where
+.Ar d
+represents a hexadecimal digit.
+.It Dv VIS_OCTAL
+Use a three digit octal sequence.
+The form is
+.Ql \eddd
+where
+.Ar d
+represents an octal digit.
+.El
+.Pp
+There is one additional flag,
+.Dv VIS_NOSLASH ,
+which inhibits the
+doubling of backslashes and the backslash before the default
+format (that is, control characters are represented by
+.Ql ^C
+and
+meta characters as
+.Ql M-C ) .
+With this flag set, the encoding is
+ambiguous and non-invertible.
+.Sh SEE ALSO
+.Xr unvis 1 ,
+.Xr unvis 3
+.Rs
+.%A R. Fielding
+.%T Relative Uniform Resource Locators
+.%O RFC1808
+.Re
+.Sh HISTORY
+These functions first appeared in
+.Bx 4.4 .
+.Sh BUGS
+The
+.Nm
+family of functions do not recognize multibyte characters, and thus
+may consider them to be non-printable when they are in fact printable
+(and vice versa.)
diff --git a/lib/libc/gen/vis.c b/lib/libc/gen/vis.c
new file mode 100644
index 0000000..1d7e860
--- /dev/null
+++ b/lib/libc/gen/vis.c
@@ -0,0 +1,205 @@
+/*-
+ * 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. 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)vis.c 8.1 (Berkeley) 7/19/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <limits.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <vis.h>
+
+#define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
+
+/*
+ * vis - visually encode characters
+ */
+char *
+vis(dst, c, flag, nextc)
+ char *dst;
+ int c, nextc;
+ int flag;
+{
+ c = (unsigned char)c;
+
+ if (flag & VIS_HTTPSTYLE) {
+ /* Described in RFC 1808 */
+ if (!(isalnum(c) /* alpha-numeric */
+ /* safe */
+ || c == '$' || c == '-' || c == '_' || c == '.' || c == '+'
+ /* extra */
+ || c == '!' || c == '*' || c == '\'' || c == '('
+ || c == ')' || c == ',')) {
+ *dst++ = '%';
+ snprintf(dst, 4, (c < 16 ? "0%X" : "%X"), c);
+ dst += 2;
+ goto done;
+ }
+ }
+
+ if ((flag & VIS_GLOB) &&
+ (c == '*' || c == '?' || c == '[' || c == '#'))
+ ;
+ else if (isgraph(c) ||
+ ((flag & VIS_SP) == 0 && c == ' ') ||
+ ((flag & VIS_TAB) == 0 && c == '\t') ||
+ ((flag & VIS_NL) == 0 && c == '\n') ||
+ ((flag & VIS_SAFE) && (c == '\b' || c == '\007' || c == '\r'))) {
+ *dst++ = c;
+ if (c == '\\' && (flag & VIS_NOSLASH) == 0)
+ *dst++ = '\\';
+ *dst = '\0';
+ return (dst);
+ }
+
+ if (flag & VIS_CSTYLE) {
+ switch(c) {
+ case '\n':
+ *dst++ = '\\';
+ *dst++ = 'n';
+ goto done;
+ case '\r':
+ *dst++ = '\\';
+ *dst++ = 'r';
+ goto done;
+ case '\b':
+ *dst++ = '\\';
+ *dst++ = 'b';
+ goto done;
+ case '\a':
+ *dst++ = '\\';
+ *dst++ = 'a';
+ goto done;
+ case '\v':
+ *dst++ = '\\';
+ *dst++ = 'v';
+ goto done;
+ case '\t':
+ *dst++ = '\\';
+ *dst++ = 't';
+ goto done;
+ case '\f':
+ *dst++ = '\\';
+ *dst++ = 'f';
+ goto done;
+ case ' ':
+ *dst++ = '\\';
+ *dst++ = 's';
+ goto done;
+ case '\0':
+ *dst++ = '\\';
+ *dst++ = '0';
+ if (isoctal(nextc)) {
+ *dst++ = '0';
+ *dst++ = '0';
+ }
+ goto done;
+ }
+ }
+ if (((c & 0177) == ' ') || isgraph(c) || (flag & VIS_OCTAL)) {
+ *dst++ = '\\';
+ *dst++ = ((u_char)c >> 6 & 07) + '0';
+ *dst++ = ((u_char)c >> 3 & 07) + '0';
+ *dst++ = ((u_char)c & 07) + '0';
+ goto done;
+ }
+ if ((flag & VIS_NOSLASH) == 0)
+ *dst++ = '\\';
+ if (c & 0200) {
+ c &= 0177;
+ *dst++ = 'M';
+ }
+ if (iscntrl(c)) {
+ *dst++ = '^';
+ if (c == 0177)
+ *dst++ = '?';
+ else
+ *dst++ = c + '@';
+ } else {
+ *dst++ = '-';
+ *dst++ = c;
+ }
+done:
+ *dst = '\0';
+ return (dst);
+}
+
+/*
+ * strvis, strvisx - visually encode characters from src into dst
+ *
+ * Dst must be 4 times the size of src to account for possible
+ * expansion. The length of dst, not including the trailing NUL,
+ * is returned.
+ *
+ * Strvisx encodes exactly len bytes from src into dst.
+ * This is useful for encoding a block of data.
+ */
+int
+strvis(dst, src, flag)
+ char *dst;
+ const char *src;
+ int flag;
+{
+ char c;
+ char *start;
+
+ for (start = dst; (c = *src); )
+ dst = vis(dst, c, flag, *++src);
+ *dst = '\0';
+ return (dst - start);
+}
+
+int
+strvisx(dst, src, len, flag)
+ char *dst;
+ const char *src;
+ size_t len;
+ int flag;
+{
+ int c;
+ char *start;
+
+ for (start = dst; len > 1; len--) {
+ c = *src;
+ dst = vis(dst, c, flag, *++src);
+ }
+ if (len)
+ dst = vis(dst, *src, flag, '\0');
+ *dst = '\0';
+
+ return (dst - start);
+}
diff --git a/lib/libc/gen/wait.c b/lib/libc/gen/wait.c
new file mode 100644
index 0000000..f1711cd
--- /dev/null
+++ b/lib/libc/gen/wait.c
@@ -0,0 +1,54 @@
+/*
+ * 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. 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.
+ */
+
+#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"
+
+pid_t
+__wait(int *istat)
+{
+ return (_wait4(WAIT_ANY, istat, 0, (struct rusage *)0));
+}
+
+__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 0000000..edfd227
--- /dev/null
+++ b/lib/libc/gen/wait3.c
@@ -0,0 +1,54 @@
+/*
+ * 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. 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.
+ */
+
+#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"
+
+pid_t
+wait3(istat, options, rup)
+ int *istat;
+ int options;
+ struct rusage *rup;
+{
+ return (_wait4(WAIT_ANY, istat, options, rup));
+}
diff --git a/lib/libc/gen/waitpid.c b/lib/libc/gen/waitpid.c
new file mode 100644
index 0000000..ecb0e4d
--- /dev/null
+++ b/lib/libc/gen/waitpid.c
@@ -0,0 +1,54 @@
+/*
+ * 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. 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.
+ */
+
+#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"
+
+pid_t
+__waitpid(pid_t pid, int *istat, int options)
+{
+ return (_wait4(pid, istat, options, (struct rusage *)0));
+}
+
+__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 0000000..02fc253
--- /dev/null
+++ b/lib/libc/gen/wordexp.3
@@ -0,0 +1,206 @@
+.\"
+.\" 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 July 29, 2004
+.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 as a wrapper around the undocumented
+.Ic 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 attempt was made to expand an undefined shell variable and
+.Dv WRDE_UNDEF
+is 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.
+.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
+Do not pass untrusted user data to
+.Fn wordexp ,
+regardless of whether the
+.Dv WRDE_NOCMD
+flag is set.
+The
+.Fn wordexp
+function attempts to detect input that would cause commands to be
+executed before passing it to the shell
+but it does not use the same parser so it may be fooled.
+.Pp
+The current
+.Fn wordexp
+implementation does not recognize multibyte characters, since the
+shell (which it invokes to perform expansions) does not.
diff --git a/lib/libc/gen/wordexp.c b/lib/libc/gen/wordexp.c
new file mode 100644
index 0000000..a437543
--- /dev/null
+++ b/lib/libc/gen/wordexp.c
@@ -0,0 +1,316 @@
+/*-
+ * 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 <fcntl.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <wordexp.h>
+#include "un-namespace.h"
+
+__FBSDID("$FreeBSD$");
+
+static int we_askshell(const char *, wordexp_t *, int);
+static int we_check(const char *, int);
+
+/*
+ * 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, flags)) != 0) {
+ wordfree(we);
+ return (error);
+ }
+ if ((error = we_askshell(words, we, flags)) != 0) {
+ wordfree(we);
+ return (error);
+ }
+ return (0);
+}
+
+/*
+ * we_askshell --
+ * Use the `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 pdes[2]; /* Pipe to child */
+ char bbuf[9]; /* Buffer for byte count */
+ char wbuf[9]; /* Buffer for 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 */
+ int status; /* Child exit status */
+ char *ifs; /* IFS env. var. */
+ char *np, *p; /* Handy pointers */
+ char *nstrings; /* Temporary for realloc() */
+ char **nwv; /* Temporary for realloc() */
+
+ if ((ifs = getenv("IFS")) == NULL)
+ ifs = " \t\n";
+
+ if (pipe(pdes) < 0)
+ return (WRDE_NOSPACE); /* XXX */
+ if ((pid = fork()) < 0) {
+ _close(pdes[0]);
+ _close(pdes[1]);
+ return (WRDE_NOSPACE); /* XXX */
+ }
+ else if (pid == 0) {
+ /*
+ * We are the child; just get /bin/sh to run the wordexp
+ * builtin on `words'.
+ */
+ int devnull;
+ char *cmd;
+
+ _close(pdes[0]);
+ if (_dup2(pdes[1], STDOUT_FILENO) < 0)
+ _exit(1);
+ _close(pdes[1]);
+ if (asprintf(&cmd, "wordexp%c%s\n", *ifs, words) < 0)
+ _exit(1);
+ if ((flags & WRDE_SHOWERR) == 0) {
+ if ((devnull = _open(_PATH_DEVNULL, O_RDWR, 0666)) < 0)
+ _exit(1);
+ if (_dup2(devnull, STDERR_FILENO) < 0)
+ _exit(1);
+ _close(devnull);
+ }
+ execl(_PATH_BSHELL, "sh", flags & WRDE_UNDEF ? "-u" : "+u",
+ "-c", cmd, (char *)NULL);
+ _exit(1);
+ }
+
+ /*
+ * We are the parent; read the output of the shell wordexp function,
+ * which is a 32-bit hexadecimal word count, a 32-bit hexadecimal
+ * byte count (not including terminating null bytes), followed by
+ * the expanded words separated by nulls.
+ */
+ _close(pdes[1]);
+ if (_read(pdes[0], wbuf, 8) != 8 || _read(pdes[0], bbuf, 8) != 8) {
+ _close(pdes[0]);
+ _waitpid(pid, &status, 0);
+ return (flags & WRDE_UNDEF ? WRDE_BADVAL : WRDE_SYNTAX);
+ }
+ wbuf[8] = bbuf[8] = '\0';
+ nwords = strtol(wbuf, NULL, 16);
+ nbytes = strtol(bbuf, 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) {
+ _close(pdes[0]);
+ _waitpid(pid, &status, 0);
+ return (WRDE_NOSPACE);
+ }
+ we->we_wordv = nwv;
+ if ((nstrings = realloc(we->we_strings, we->we_nbytes)) == NULL) {
+ _close(pdes[0]);
+ _waitpid(pid, &status, 0);
+ return (WRDE_NOSPACE);
+ }
+ 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 (_read(pdes[0], we->we_strings + sofs, nbytes) != nbytes) {
+ _close(pdes[0]);
+ _waitpid(pid, &status, 0);
+ return (flags & WRDE_UNDEF ? WRDE_BADVAL : WRDE_SYNTAX);
+ }
+
+ if (_waitpid(pid, &status, 0) < 0 || !WIFEXITED(status) ||
+ WEXITSTATUS(status) != 0) {
+ _close(pdes[0]);
+ return (flags & WRDE_UNDEF ? WRDE_BADVAL : WRDE_SYNTAX);
+ }
+ _close(pdes[0]);
+
+ /*
+ * 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> |&;<>(){}
+ * or command substitutions when WRDE_NOCMD is set in flags.
+ */
+static int
+we_check(const char *words, int flags)
+{
+ char c;
+ int dquote, level, quote, squote;
+
+ quote = squote = dquote = 0;
+ while ((c = *words++) != '\0') {
+ switch (c) {
+ case '\\':
+ quote ^= 1;
+ continue;
+ case '\'':
+ if (quote + dquote == 0)
+ squote ^= 1;
+ break;
+ case '"':
+ if (quote + squote == 0)
+ dquote ^= 1;
+ break;
+ case '`':
+ if (quote + squote == 0 && flags & WRDE_NOCMD)
+ return (WRDE_CMDSUB);
+ while ((c = *words++) != '\0' && c != '`')
+ if (c == '\\' && (c = *words++) == '\0')
+ break;
+ if (c == '\0')
+ return (WRDE_SYNTAX);
+ break;
+ case '|': case '&': case ';': case '<': case '>':
+ case '{': case '}': case '(': case ')': case '\n':
+ if (quote + squote + dquote == 0)
+ return (WRDE_BADCHAR);
+ break;
+ case '$':
+ if ((c = *words++) == '\0')
+ break;
+ else if (quote + squote == 0 && c == '(') {
+ if (flags & WRDE_NOCMD && *words != '(')
+ return (WRDE_CMDSUB);
+ level = 1;
+ while ((c = *words++) != '\0') {
+ if (c == '\\') {
+ if ((c = *words++) == '\0')
+ break;
+ } else if (c == '(')
+ level++;
+ else if (c == ')' && --level == 0)
+ break;
+ }
+ if (c == '\0' || level != 0)
+ return (WRDE_SYNTAX);
+ } else if (quote + squote == 0 && c == '{') {
+ level = 1;
+ while ((c = *words++) != '\0') {
+ if (c == '\\') {
+ if ((c = *words++) == '\0')
+ break;
+ } else if (c == '{')
+ level++;
+ else if (c == '}' && --level == 0)
+ break;
+ }
+ if (c == '\0' || level != 0)
+ return (WRDE_SYNTAX);
+ } else
+ c = *--words;
+ break;
+ default:
+ break;
+ }
+ quote = 0;
+ }
+ if (quote + squote + dquote != 0)
+ 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 0000000..2b353d8
--- /dev/null
+++ b/lib/libc/gmon/Makefile.inc
@@ -0,0 +1,23 @@
+# from @(#)Makefile.inc 8.1 (Berkeley) 6/4/93
+# $FreeBSD$
+
+# gmon sources
+.PATH: ${.CURDIR}/gmon
+
+SRCS+= gmon.c mcount.c
+
+SYM_MAPS+=${.CURDIR}/gmon/Symbol.map
+
+MAN+= moncontrol.3
+
+MLINKS+=moncontrol.3 monstartup.3
+
+.if ${MACHINE_ARCH} == amd64
+# mcount needs to be compiled with frame pointers and without profiling
+mcount.po: mcount.c
+ ${CC} ${CFLAGS} -fno-omit-frame-pointer -c ${.IMPSRC} -o ${.TARGET}
+.else
+# mcount cannot be compiled with profiling
+mcount.po: mcount.o
+ cp mcount.o mcount.po
+.endif
diff --git a/lib/libc/gmon/Symbol.map b/lib/libc/gmon/Symbol.map
new file mode 100644
index 0000000..b94339b
--- /dev/null
+++ b/lib/libc/gmon/Symbol.map
@@ -0,0 +1,13 @@
+# $FreeBSD$
+
+FBSD_1.0 {
+ monstartup;
+ moncontrol;
+ mexitcount;
+};
+
+FBSDprivate {
+ .mcount; # ???
+ _gmonparam;
+ _mcleanup;
+};
diff --git a/lib/libc/gmon/gmon.c b/lib/libc/gmon/gmon.c
new file mode 100644
index 0000000..3f29009
--- /dev/null
+++ b/lib/libc/gmon/gmon.c
@@ -0,0 +1,267 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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/sysctl.h>
+
+#include <err.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+#include "libc_private.h"
+
+#if defined(__i386__) || defined(__sparc64__) || defined(__amd64__) || defined(__powerpc__)
+extern char *minbrk __asm (".minbrk");
+#else
+extern char *minbrk __asm ("minbrk");
+#endif
+
+struct gmonparam _gmonparam = { GMON_PROF_OFF };
+
+static int s_scale;
+/* see profil(2) where this is describe (incorrectly) */
+#define SCALE_1_TO_1 0x10000L
+
+#define ERR(s) _write(2, s, sizeof(s))
+
+void moncontrol(int);
+static int hertz(void);
+
+void
+monstartup(lowpc, highpc)
+ 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 = sbrk(p->kcountsize + p->fromssize + p->tossize);
+ if (cp == (char *)-1) {
+ 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;
+
+ minbrk = sbrk(0);
+ p->tos[0].link = 0;
+
+ o = p->highpc - p->lowpc;
+ if (p->kcountsize < o) {
+#ifndef hp300
+ s_scale = ((float)p->kcountsize / o ) * SCALE_1_TO_1;
+#else /* avoid floating point */
+ int quot = o / p->kcountsize;
+
+ if (quot >= 0x10000)
+ s_scale = 1;
+ else if (quot >= 0x100)
+ s_scale = 0x10000 / quot;
+ else if (o >= 0x800000)
+ s_scale = 0x1000000 / (o / (p->kcountsize >> 8));
+ else
+ s_scale = 0x1000000 / ((o << 8) / p->kcountsize);
+#endif
+ } else
+ s_scale = SCALE_1_TO_1;
+
+ moncontrol(1);
+}
+
+void
+_mcleanup()
+{
+ 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);
+ snprintf(outname, sizeof(outname), "%s.gmon", _getprogname());
+ fd = _open(outname, O_CREAT|O_TRUNC|O_WRONLY, 0666);
+ if (fd < 0) {
+ _warn("_mcleanup: %s", outname);
+ return;
+ }
+#ifdef DEBUG
+ log = _open("gmon.log", O_CREAT|O_TRUNC|O_WRONLY, 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(mode)
+ 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()
+{
+ 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 0000000..b3b561c
--- /dev/null
+++ b/lib/libc/gmon/mcount.c
@@ -0,0 +1,325 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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 0000000..b846856
--- /dev/null
+++ b/lib/libc/gmon/moncontrol.3
@@ -0,0 +1,114 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)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 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 0000000..05b07cc
--- /dev/null
+++ b/lib/libc/i386/Makefile.inc
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+# Long double is 80 bits
+GDTOASRCS+=strtopx.c
+MDSRCS+=machdep_ldisx.c
+SYM_MAPS+=${.CURDIR}/i386/Symbol.map
diff --git a/lib/libc/i386/SYS.h b/lib/libc/i386/SYS.h
new file mode 100644
index 0000000..1483f9d
--- /dev/null
+++ b/lib/libc/i386/SYS.h
@@ -0,0 +1,61 @@
+/*-
+ * 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. 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.
+ *
+ * @(#)SYS.h 5.5 (Berkeley) 5/7/91
+ * $FreeBSD$
+ */
+
+#include <sys/syscall.h>
+#include <machine/asm.h>
+
+#define SYSCALL(x) 2: PIC_PROLOGUE; jmp PIC_PLT(HIDENAME(cerror)); \
+ ENTRY(__CONCAT(__sys_,x)); \
+ .weak CNAME(x); \
+ .set CNAME(x),CNAME(__CONCAT(__sys_,x)); \
+ .weak CNAME(__CONCAT(_,x)); \
+ .set CNAME(__CONCAT(_,x)),CNAME(__CONCAT(__sys_,x)); \
+ mov __CONCAT($SYS_,x),%eax; KERNCALL; jb 2b
+
+#define RSYSCALL(x) SYSCALL(x); ret
+
+#define PSEUDO(x) ENTRY(__CONCAT(__sys_,x)); \
+ .weak CNAME(__CONCAT(_,x)); \
+ .set CNAME(__CONCAT(_,x)),CNAME(__CONCAT(__sys_,x)); \
+ mov __CONCAT($SYS_,x),%eax; KERNCALL; ret
+
+/* 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 0000000..6f367a1
--- /dev/null
+++ b/lib/libc/i386/Symbol.map
@@ -0,0 +1,71 @@
+# $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;
+ __flt_rounds;
+ __nan;
+ __infinity;
+ makecontext;
+ modf;
+ rfork_thread;
+ setjmp;
+ longjmp;
+ sigsetjmp;
+ siglongjmp;
+ __htonl;
+ htonl;
+ __htons;
+ htons;
+ __ntohl;
+ ntohl;
+ __ntohs;
+ 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;
+};
+
+FBSDprivate {
+ # PSEUDO syscalls
+ __sys_getlogin;
+ _getlogin;
+ __sys_exit;
+
+ _set_tp;
+ ___longjmp;
+ __makecontext;
+ __longjmp;
+ __signalcontext;
+ signalcontext;
+ __siglongjmp;
+ __sys_vfork;
+ _vfork;
+ _end;
+ .cerror;
+ _brk;
+ .curbrk;
+ .minbrk;
+};
diff --git a/lib/libc/i386/_fpmath.h b/lib/libc/i386/_fpmath.h
new file mode 100644
index 0000000..80e764f
--- /dev/null
+++ b/lib/libc/i386/_fpmath.h
@@ -0,0 +1,49 @@
+/*-
+ * 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;
+};
+
+#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 0000000..2d65061
--- /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/gen/Makefile.inc b/lib/libc/i386/gen/Makefile.inc
new file mode 100644
index 0000000..709cf5d
--- /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 alloca.S fabs.S \
+ flt_rounds.c infinity.c ldexp.c makecontext.c modf.S \
+ 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 0000000..91a06b8
--- /dev/null
+++ b/lib/libc/i386/gen/_ctx_start.S
@@ -0,0 +1,50 @@
+/*
+ * 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 */
+ movl %esi, %esp /*
+ * setup stack for completion routine;
+ * ucp is now at top of stack
+ */
+ call _ctx_done /* should never return */
+ call abort /* fubar */
+ ret
diff --git a/lib/libc/i386/gen/_set_tp.c b/lib/libc/i386/gen/_set_tp.c
new file mode 100644
index 0000000..8a6c929
--- /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 0000000..d2b7b6e
--- /dev/null
+++ b/lib/libc/i386/gen/_setjmp.S
@@ -0,0 +1,83 @@
+/*-
+ * 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. 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.
+ */
+
+#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
+
+ .weak CNAME(_longjmp)
+ .set CNAME(_longjmp),CNAME(___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
+ fninit
+ fldcw 24(%edx)
+ testl %eax,%eax
+ jnz 1f
+ incl %eax
+1: movl %ecx,0(%esp)
+ ret
diff --git a/lib/libc/i386/gen/alloca.S b/lib/libc/i386/gen/alloca.S
new file mode 100644
index 0000000..657c114
--- /dev/null
+++ b/lib/libc/i386/gen/alloca.S
@@ -0,0 +1,62 @@
+/*-
+ * 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. 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.
+ */
+
+#if !defined(__GNUC__) && !defined(__INTEL_COMPILER)
+#error Please add alloca support for this compiler on FreeBSD.
+
+#if defined(LIBC_SCCS) && !defined(lint)
+ .asciz "@(#)alloca.s 5.2 (Berkeley) 5/14/90"
+#endif /* LIBC_SCCS and not lint */
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+
+/* like alloc, but automatic automatic free in return */
+
+ENTRY(alloca)
+ popl %edx /* pop return addr */
+ popl %eax /* pop amount to allocate */
+ movl %esp,%ecx
+ addl $3,%eax /* round up to next word */
+ andl $0xfffffffc,%eax
+ subl %eax,%esp
+ movl %esp,%eax /* base of newly allocated space */
+ pushl 8(%ecx) /* copy possible saved registers */
+ pushl 4(%ecx)
+ pushl 0(%ecx)
+ pushl %eax /* dummy to pop at callsite */
+ jmp *%edx /* "return" */
+#endif /*!__GNUC__*/
diff --git a/lib/libc/i386/gen/fabs.S b/lib/libc/i386/gen/fabs.S
new file mode 100644
index 0000000..52784cf
--- /dev/null
+++ b/lib/libc/i386/gen/fabs.S
@@ -0,0 +1,46 @@
+/*-
+ * 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. 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.
+ */
+
+#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
diff --git a/lib/libc/i386/gen/flt_rounds.c b/lib/libc/i386/gen/flt_rounds.c
new file mode 100644
index 0000000..16417ff
--- /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/infinity.c b/lib/libc/i386/gen/infinity.c
new file mode 100644
index 0000000..464b402
--- /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/ldexp.c b/lib/libc/i386/gen/ldexp.c
new file mode 100644
index 0000000..45802be
--- /dev/null
+++ b/lib/libc/i386/gen/ldexp.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
+ * Sean Eric Fagan.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)ldexp.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <math.h>
+
+/*
+ * ldexp(value, exp): return value * (2 ** exp).
+ *
+ * Written by Sean Eric Fagan (sef@kithrup.COM)
+ * Sun Mar 11 20:27:09 PST 1990
+ */
+
+/*
+ * We do the conversion in C to let gcc optimize it away, if possible.
+ */
+double
+ldexp (double value, int exp)
+{
+ double temp, texp, temp2;
+ texp = exp;
+#ifdef __GNUC__
+ __asm ("fscale "
+ : "=u" (temp2), "=t" (temp)
+ : "0" (texp), "1" (value));
+#else
+#error unknown asm
+#endif
+ return (temp);
+}
diff --git a/lib/libc/i386/gen/makecontext.c b/lib/libc/i386/gen/makecontext.c
new file mode 100644
index 0000000..167cb12
--- /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/modf.S b/lib/libc/i386/gen/modf.S
new file mode 100644
index 0000000..426037b
--- /dev/null
+++ b/lib/libc/i386/gen/modf.S
@@ -0,0 +1,76 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Sean Eric Fagan.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+ .asciz "@(#)modf.s 5.5 (Berkeley) 3/18/91"
+#endif /* LIBC_SCCS and not lint */
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * modf(value, iptr): return fractional part of value, and stores the
+ * integral part into iptr (a pointer to double).
+ *
+ * Written by Sean Eric Fagan (sef@kithrup.COM)
+ * Sun Mar 11 20:27:30 PST 1990
+ */
+
+/* With CHOP mode on, frndint behaves as TRUNC does. Useful. */
+
+ENTRY(modf)
+ pushl %ebp
+ movl %esp,%ebp
+ subl $16,%esp
+ fnstcw -12(%ebp)
+ movw -12(%ebp),%dx
+ orw $3072,%dx
+ movw %dx,-16(%ebp)
+ fldcw -16(%ebp)
+ fldl 8(%ebp)
+ frndint
+ fstpl -8(%ebp)
+ fldcw -12(%ebp)
+ movl 16(%ebp),%eax
+ movl -8(%ebp),%edx
+ movl -4(%ebp),%ecx
+ movl %edx,(%eax)
+ movl %ecx,4(%eax)
+ fldl 8(%ebp)
+ fsubl -8(%ebp)
+ jmp L1
+L1:
+ leave
+ ret
diff --git a/lib/libc/i386/gen/rfork_thread.S b/lib/libc/i386/gen/rfork_thread.S
new file mode 100644
index 0000000..c0fc624
--- /dev/null
+++ b/lib/libc/i386/gen/rfork_thread.S
@@ -0,0 +1,117 @@
+/*-
+ * 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
+ PIC_PROLOGUE
+ jmp PIC_PLT(HIDENAME(cerror))
diff --git a/lib/libc/i386/gen/setjmp.S b/lib/libc/i386/gen/setjmp.S
new file mode 100644
index 0000000..f64c77f
--- /dev/null
+++ b/lib/libc/i386/gen/setjmp.S
@@ -0,0 +1,103 @@
+/*-
+ * 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. 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.
+ */
+
+#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
+ PIC_PROLOGUE
+ leal 28(%ecx), %eax
+ pushl %eax /* (sigset_t*)oset */
+ pushl $0 /* (sigset_t*)set */
+ pushl $1 /* SIG_BLOCK */
+ call PIC_PLT(CNAME(_sigprocmask))
+ addl $12,%esp
+ PIC_EPILOGUE
+ 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
+
+ .weak CNAME(longjmp)
+ .set CNAME(longjmp),CNAME(__longjmp)
+ENTRY(__longjmp)
+ movl 4(%esp),%edx
+ PIC_PROLOGUE
+ pushl $0 /* (sigset_t*)oset */
+ leal 28(%edx), %eax
+ pushl %eax /* (sigset_t*)set */
+ pushl $3 /* SIG_SETMASK */
+ call PIC_PLT(CNAME(_sigprocmask))
+ addl $12,%esp
+ PIC_EPILOGUE
+ 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
+ fninit
+ fldcw 24(%edx)
+ testl %eax,%eax
+ jnz 1f
+ incl %eax
+1: movl %ecx,0(%esp)
+ ret
diff --git a/lib/libc/i386/gen/signalcontext.c b/lib/libc/i386/gen/signalcontext.c
new file mode 100644
index 0000000..877b655
--- /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 0000000..09b512d
--- /dev/null
+++ b/lib/libc/i386/gen/sigsetjmp.S
@@ -0,0 +1,114 @@
+/*-
+ * 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. 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.
+ *
+ * @(#)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
+ PIC_PROLOGUE
+ leal 28(%ecx), %eax
+ pushl %eax /* (sigset_t*)oset */
+ pushl $0 /* (sigset_t*)set */
+ pushl $1 /* SIG_BLOCK */
+ call PIC_PLT(CNAME(_sigprocmask))
+ addl $12,%esp
+ PIC_EPILOGUE
+ 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
+
+ .weak CNAME(siglongjmp);
+ .set CNAME(siglongjmp),CNAME(__siglongjmp);
+ENTRY(__siglongjmp);
+ movl 4(%esp),%edx
+ cmpl $0,44(%edx)
+ jz 2f
+ PIC_PROLOGUE
+ pushl $0 /* (sigset_t*)oset */
+ leal 28(%edx), %eax
+ pushl %eax /* (sigset_t*)set */
+ pushl $3 /* SIG_SETMASK */
+ call PIC_PLT(CNAME(_sigprocmask))
+ addl $12,%esp
+ PIC_EPILOGUE
+ 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
+ fninit
+ fldcw 24(%edx)
+ testl %eax,%eax
+ jnz 1f
+ incl %eax
+1: movl %ecx,0(%esp)
+ ret
diff --git a/lib/libc/i386/net/Makefile.inc b/lib/libc/i386/net/Makefile.inc
new file mode 100644
index 0000000..96e559b
--- /dev/null
+++ b/lib/libc/i386/net/Makefile.inc
@@ -0,0 +1,4 @@
+# @(#)Makefile.inc 8.1 (Berkeley) 6/4/93
+# $FreeBSD$
+
+SRCS+= htonl.S htons.S ntohl.S ntohs.S
diff --git a/lib/libc/i386/net/htonl.S b/lib/libc/i386/net/htonl.S
new file mode 100644
index 0000000..37f5c60
--- /dev/null
+++ b/lib/libc/i386/net/htonl.S
@@ -0,0 +1,50 @@
+/*-
+ * 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. 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+ .asciz "@(#)htonl.s 5.3 (Berkeley) 12/17/90"
+#endif /* LIBC_SCCS and not lint */
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/* netorder = htonl(hostorder) */
+
+ .weak CNAME(htonl)
+ .set CNAME(htonl),CNAME(__htonl)
+ENTRY(__htonl)
+ movl 4(%esp),%eax
+ bswap %eax
+ ret
diff --git a/lib/libc/i386/net/htons.S b/lib/libc/i386/net/htons.S
new file mode 100644
index 0000000..d5d63fc
--- /dev/null
+++ b/lib/libc/i386/net/htons.S
@@ -0,0 +1,50 @@
+/*-
+ * 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. 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+ .asciz "@(#)htons.s 5.2 (Berkeley) 12/17/90"
+#endif /* LIBC_SCCS and not lint */
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/* netorder = htons(hostorder) */
+
+ .weak CNAME(htons)
+ .set CNAME(htons),CNAME(__htons)
+ENTRY(__htons)
+ movzwl 4(%esp),%eax
+ xchgb %al,%ah
+ ret
diff --git a/lib/libc/i386/net/ntohl.S b/lib/libc/i386/net/ntohl.S
new file mode 100644
index 0000000..497f300
--- /dev/null
+++ b/lib/libc/i386/net/ntohl.S
@@ -0,0 +1,50 @@
+/*-
+ * 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. 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+ .asciz "@(#)ntohl.s 5.2 (Berkeley) 12/17/90"
+#endif /* LIBC_SCCS and not lint */
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/* hostorder = ntohl(netorder) */
+
+ .weak CNAME(ntohl)
+ .set CNAME(ntohl),CNAME(__ntohl)
+ENTRY(__ntohl)
+ movl 4(%esp),%eax
+ bswap %eax
+ ret
diff --git a/lib/libc/i386/net/ntohs.S b/lib/libc/i386/net/ntohs.S
new file mode 100644
index 0000000..eb0668c
--- /dev/null
+++ b/lib/libc/i386/net/ntohs.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.
+ * 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+ .asciz "@(#)ntohs.s 5.2 (Berkeley) 12/17/90"
+#endif /* LIBC_SCCS and not lint */
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/* hostorder = ntohs(netorder) */
+
+#include <machine/asm.h>
+
+ .weak CNAME(ntohs)
+ .set CNAME(ntohs),CNAME(__ntohs)
+ENTRY(__ntohs)
+ movzwl 4(%esp),%eax
+ xchgb %al,%ah
+ ret
diff --git a/lib/libc/i386/stdlib/Makefile.inc b/lib/libc/i386/stdlib/Makefile.inc
new file mode 100644
index 0000000..0a6a6a8
--- /dev/null
+++ b/lib/libc/i386/stdlib/Makefile.inc
@@ -0,0 +1,4 @@
+# @(#)Makefile.inc 8.1 (Berkeley) 6/4/93
+# $FreeBSD$
+
+MDSRCS+=abs.S div.S labs.S ldiv.S
diff --git a/lib/libc/i386/stdlib/abs.S b/lib/libc/i386/stdlib/abs.S
new file mode 100644
index 0000000..55a9296
--- /dev/null
+++ b/lib/libc/i386/stdlib/abs.S
@@ -0,0 +1,50 @@
+/*-
+ * 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. 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+ .text
+ .asciz "@(#)abs.s 5.2 (Berkeley) 12/17/90"
+#endif /* LIBC_SCCS and not lint */
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+
+ENTRY(abs)
+ movl 4(%esp),%eax
+ testl %eax,%eax
+ jns 1f
+ negl %eax
+1: ret
diff --git a/lib/libc/i386/stdlib/div.S b/lib/libc/i386/stdlib/div.S
new file mode 100644
index 0000000..bafaf6a
--- /dev/null
+++ b/lib/libc/i386/stdlib/div.S
@@ -0,0 +1,41 @@
+/*
+ * 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(div)
+ movl 4(%esp),%eax
+ movl 8(%esp),%ecx
+ cdq
+ idiv %ecx
+ movl %eax,4(%esp)
+ movl %edx,8(%esp)
+ ret
diff --git a/lib/libc/i386/stdlib/labs.S b/lib/libc/i386/stdlib/labs.S
new file mode 100644
index 0000000..9dd474d
--- /dev/null
+++ b/lib/libc/i386/stdlib/labs.S
@@ -0,0 +1,50 @@
+/*-
+ * 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. 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+ .text
+ .asciz "@(#)abs.s 5.2 (Berkeley) 12/17/90"
+#endif /* LIBC_SCCS and not lint */
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+
+ENTRY(labs)
+ movl 4(%esp),%eax
+ testl %eax,%eax
+ jns 1f
+ negl %eax
+1: ret
diff --git a/lib/libc/i386/stdlib/ldiv.S b/lib/libc/i386/stdlib/ldiv.S
new file mode 100644
index 0000000..578eff0
--- /dev/null
+++ b/lib/libc/i386/stdlib/ldiv.S
@@ -0,0 +1,41 @@
+/*
+ * 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
+ movl %eax,4(%esp)
+ movl %edx,8(%esp)
+ ret
diff --git a/lib/libc/i386/string/Makefile.inc b/lib/libc/i386/string/Makefile.inc
new file mode 100644
index 0000000..cd908a6
--- /dev/null
+++ b/lib/libc/i386/string/Makefile.inc
@@ -0,0 +1,7 @@
+# @(#)Makefile.inc 8.1 (Berkeley) 6/4/93
+# $FreeBSD$
+
+MDSRCS+=bcmp.S bcopy.S bzero.S ffs.S index.S memchr.S memcmp.S memcpy.S \
+ memmove.S memset.S rindex.S strcat.S strchr.S strcmp.S strcpy.S \
+ strlen.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 0000000..aa6a6ab
--- /dev/null
+++ b/lib/libc/i386/string/bcmp.S
@@ -0,0 +1,63 @@
+/*
+ * 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
diff --git a/lib/libc/i386/string/bcopy.S b/lib/libc/i386/string/bcopy.S
new file mode 100644
index 0000000..1050ed2
--- /dev/null
+++ b/lib/libc/i386/string/bcopy.S
@@ -0,0 +1,103 @@
+/*-
+ * 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. 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.
+ */
+
+#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
diff --git a/lib/libc/i386/string/bzero.S b/lib/libc/i386/string/bzero.S
new file mode 100644
index 0000000..f66bd78
--- /dev/null
+++ b/lib/libc/i386/string/bzero.S
@@ -0,0 +1,81 @@
+/*
+ * 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
diff --git a/lib/libc/i386/string/ffs.S b/lib/libc/i386/string/ffs.S
new file mode 100644
index 0000000..450f586
--- /dev/null
+++ b/lib/libc/i386/string/ffs.S
@@ -0,0 +1,53 @@
+/*
+ * 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
diff --git a/lib/libc/i386/string/index.S b/lib/libc/i386/string/index.S
new file mode 100644
index 0000000..db0a162
--- /dev/null
+++ b/lib/libc/i386/string/index.S
@@ -0,0 +1,63 @@
+/*
+ * 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$");
+
+/*
+ * index(s, c)
+ * return a pointer to the first occurance 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 occurance of 'c'
+ * %cl - character we're comparing against
+ * %bl - character at %edx
+ *
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+ENTRY(index)
+ 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
diff --git a/lib/libc/i386/string/memchr.S b/lib/libc/i386/string/memchr.S
new file mode 100644
index 0000000..639077d
--- /dev/null
+++ b/lib/libc/i386/string/memchr.S
@@ -0,0 +1,58 @@
+/*
+ * 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 occurance 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
diff --git a/lib/libc/i386/string/memcmp.S b/lib/libc/i386/string/memcmp.S
new file mode 100644
index 0000000..8aa2f4e
--- /dev/null
+++ b/lib/libc/i386/string/memcmp.S
@@ -0,0 +1,75 @@
+/*
+ * 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
diff --git a/lib/libc/i386/string/memcpy.S b/lib/libc/i386/string/memcpy.S
new file mode 100644
index 0000000..f85a1a5
--- /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 0000000..02330c4
--- /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 0000000..52f0485
--- /dev/null
+++ b/lib/libc/i386/string/memset.S
@@ -0,0 +1,89 @@
+/*
+ * 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
diff --git a/lib/libc/i386/string/rindex.S b/lib/libc/i386/string/rindex.S
new file mode 100644
index 0000000..f0d99f1
--- /dev/null
+++ b/lib/libc/i386/string/rindex.S
@@ -0,0 +1,64 @@
+/*
+ * 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$");
+
+/*
+ * rindex(s, c)
+ * return a pointer to the last occurance 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 occurance of 'c'
+ * %cl - character we're comparing against
+ * %bl - character at %edx
+ *
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+ENTRY(rindex)
+ 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
diff --git a/lib/libc/i386/string/strcat.S b/lib/libc/i386/string/strcat.S
new file mode 100644
index 0000000..3a667ca
--- /dev/null
+++ b/lib/libc/i386/string/strcat.S
@@ -0,0 +1,100 @@
+/*
+ * 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
diff --git a/lib/libc/i386/string/strchr.S b/lib/libc/i386/string/strchr.S
new file mode 100644
index 0000000..19ff5d4
--- /dev/null
+++ b/lib/libc/i386/string/strchr.S
@@ -0,0 +1,63 @@
+/*
+ * 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 occurance 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 occurance 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
diff --git a/lib/libc/i386/string/strcmp.S b/lib/libc/i386/string/strcmp.S
new file mode 100644
index 0000000..07a87b6
--- /dev/null
+++ b/lib/libc/i386/string/strcmp.S
@@ -0,0 +1,119 @@
+/*
+ * 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
diff --git a/lib/libc/i386/string/strcpy.S b/lib/libc/i386/string/strcpy.S
new file mode 100644
index 0000000..a474ec1
--- /dev/null
+++ b/lib/libc/i386/string/strcpy.S
@@ -0,0 +1,89 @@
+/*
+ * 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
diff --git a/lib/libc/i386/string/strlen.S b/lib/libc/i386/string/strlen.S
new file mode 100644
index 0000000..22d683e
--- /dev/null
+++ b/lib/libc/i386/string/strlen.S
@@ -0,0 +1,53 @@
+/*
+ * 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$");
+
+/*
+ * strlen (s)
+ * compute the length of the string s.
+ *
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+ENTRY(strlen)
+ pushl %edi
+ movl 8(%esp),%edi /* string 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
+ notl %ecx /* get length by taking complement */
+ leal -1(%ecx),%eax /* and subtracting one */
+ popl %edi
+ ret
diff --git a/lib/libc/i386/string/strncmp.S b/lib/libc/i386/string/strncmp.S
new file mode 100644
index 0000000..e5953c5
--- /dev/null
+++ b/lib/libc/i386/string/strncmp.S
@@ -0,0 +1,166 @@
+/*
+ * 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
diff --git a/lib/libc/i386/string/strrchr.S b/lib/libc/i386/string/strrchr.S
new file mode 100644
index 0000000..8b63ddf
--- /dev/null
+++ b/lib/libc/i386/string/strrchr.S
@@ -0,0 +1,64 @@
+/*
+ * 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 occurance 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 occurance 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
diff --git a/lib/libc/i386/string/swab.S b/lib/libc/i386/string/swab.S
new file mode 100644
index 0000000..80b2f3c
--- /dev/null
+++ b/lib/libc/i386/string/swab.S
@@ -0,0 +1,99 @@
+/*
+ * 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
diff --git a/lib/libc/i386/string/wcschr.S b/lib/libc/i386/string/wcschr.S
new file mode 100644
index 0000000..c020d74
--- /dev/null
+++ b/lib/libc/i386/string/wcschr.S
@@ -0,0 +1,76 @@
+/*-
+ * 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
diff --git a/lib/libc/i386/string/wcscmp.S b/lib/libc/i386/string/wcscmp.S
new file mode 100644
index 0000000..aa44140
--- /dev/null
+++ b/lib/libc/i386/string/wcscmp.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$");
+
+/*
+ * 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
diff --git a/lib/libc/i386/string/wcslen.S b/lib/libc/i386/string/wcslen.S
new file mode 100644
index 0000000..2bebc1e
--- /dev/null
+++ b/lib/libc/i386/string/wcslen.S
@@ -0,0 +1,68 @@
+/*-
+ * 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
diff --git a/lib/libc/i386/string/wmemchr.S b/lib/libc/i386/string/wmemchr.S
new file mode 100644
index 0000000..a4ef081
--- /dev/null
+++ b/lib/libc/i386/string/wmemchr.S
@@ -0,0 +1,105 @@
+/*-
+ * 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
diff --git a/lib/libc/i386/sys/Makefile.inc b/lib/libc/i386/sys/Makefile.inc
new file mode 100644
index 0000000..ca487a6
--- /dev/null
+++ b/lib/libc/i386/sys/Makefile.inc
@@ -0,0 +1,26 @@
+# 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_get_ioperm.c \
+ i386_set_ioperm.c i386_set_watch.c i386_vm86.c
+.endif
+SRCS+= i386_get_fsbase.c i386_get_gsbase.c i386_get_ldt.c \
+ i386_set_fsbase.c i386_set_gsbase.c i386_set_ldt.c
+
+MDASM= Ovfork.S brk.S cerror.S exect.S getcontext.S pipe.S ptrace.S \
+ reboot.S sbrk.S setlogin.S sigreturn.S syscall.S
+
+# Don't generate default code for these syscalls:
+NOASM= break.o exit.o ftruncate.o getdomainname.o getlogin.o \
+ lseek.o mmap.o openbsd_poll.o pread.o \
+ pwrite.o setdomainname.o sstk.o truncate.o uname.o vfork.o yield.o
+
+PSEUDO= _getlogin.o _exit.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 0000000..20ece5e
--- /dev/null
+++ b/lib/libc/i386/sys/Ovfork.S
@@ -0,0 +1,58 @@
+/*-
+ * 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. 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.
+ */
+
+#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 _vfork
+ .set _vfork,__sys_vfork
+ .weak vfork
+ .set vfork,__sys_vfork
+ENTRY(__sys_vfork)
+ popl %ecx /* my rta into ecx */
+ mov $SYS_vfork,%eax
+ KERNCALL
+ jb 1f
+ jmp *%ecx
+1:
+ pushl %ecx
+ PIC_PROLOGUE
+ jmp PIC_PLT(HIDENAME(cerror))
diff --git a/lib/libc/i386/sys/brk.S b/lib/libc/i386/sys/brk.S
new file mode 100644
index 0000000..61f6cbe
--- /dev/null
+++ b/lib/libc/i386/sys/brk.S
@@ -0,0 +1,90 @@
+/*-
+ * 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. 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.
+ */
+
+#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
+
+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 err
+ movl 4(%esp),%eax
+ movl %eax,(%edx)
+ movl $0,%eax
+ ret
+err:
+ PIC_PROLOGUE
+ jmp PIC_PLT(HIDENAME(cerror))
+
+#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 err
+ movl 4(%esp),%eax
+ movl %eax,HIDENAME(curbrk)
+ movl $0,%eax
+ ret
+err:
+ jmp HIDENAME(cerror)
+#endif
diff --git a/lib/libc/i386/sys/cerror.S b/lib/libc/i386/sys/cerror.S
new file mode 100644
index 0000000..1d625be
--- /dev/null
+++ b/lib/libc/i386/sys/cerror.S
@@ -0,0 +1,69 @@
+/*-
+ * 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. 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.
+ */
+
+#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)
+
+ /*
+ * 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):
+ pushl %eax
+#ifdef PIC
+ /* The caller must execute the PIC prologue before jumping to cerror. */
+ call PIC_PLT(CNAME(__error))
+ popl %ecx
+ PIC_EPILOGUE
+#else
+ call CNAME(__error)
+ popl %ecx
+#endif
+ movl %ecx,(%eax)
+ movl $-1,%eax
+ movl $-1,%edx
+ ret
+
diff --git a/lib/libc/i386/sys/exect.S b/lib/libc/i386/sys/exect.S
new file mode 100644
index 0000000..5848e61
--- /dev/null
+++ b/lib/libc/i386/sys/exect.S
@@ -0,0 +1,55 @@
+/*-
+ * 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. 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.
+ */
+
+#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
+ PIC_PROLOGUE
+ jmp PIC_PLT(HIDENAME(cerror)) /* exect(file, argv, env); */
diff --git a/lib/libc/i386/sys/getcontext.S b/lib/libc/i386/sys/getcontext.S
new file mode 100644
index 0000000..b66ad30
--- /dev/null
+++ b/lib/libc/i386/sys/getcontext.S
@@ -0,0 +1,50 @@
+/*-
+ * 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 _getcontext
+ .set _getcontext,__sys_getcontext
+ .weak getcontext
+ .set getcontext,__sys_getcontext
+ENTRY(__sys_getcontext)
+ movl (%esp),%ecx /* save getcontext return address */
+ mov $SYS_getcontext,%eax
+ KERNCALL
+ jb 1f
+ addl $4,%esp /* remove stale (setcontext) return address */
+ jmp *%ecx /* restore return address */
+1:
+ PIC_PROLOGUE
+ jmp PIC_PLT(HIDENAME(cerror))
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 0000000..721c1b8
--- /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 0000000..24c4764
--- /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 0000000..f524f31
--- /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 0000000..4d3bbf1
--- /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
+.Os
+.Dt I386_GET_IOPERM 2
+.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 0000000..7bc27f8
--- /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 0000000..135d8b8
--- /dev/null
+++ b/lib/libc/i386/sys/i386_get_ldt.2
@@ -0,0 +1,143 @@
+.\" 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.
+.\" 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.
+.\"
+.\" from: @(#)fork.2 6.5 (Berkeley) 3/10/91
+.\" $FreeBSD$
+.\"
+.Dd September 20, 1993
+.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
+will return the list of i386 descriptors that the process has in its
+LDT.
+The
+.Fn i386_set_ldt
+system call
+will set a list of i386 descriptors for the current process in its
+LDT.
+Both routines accept a starting selector number
+.Fa start_sel ,
+an array of memory that
+will contain the descriptors to be set or returned
+.Fa descs ,
+and the number of entries to set or return
+.Fa num_sels .
+.Pp
+The argument
+.Fa descs
+can be either 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.
+In the case when a descriptor is allocated by the kernel, its number will
+be 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 0000000..73d7667
--- /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 0000000..6b55446
--- /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 0000000..aaf2312
--- /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 0000000..258e2af
--- /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 0000000..0bb109a
--- /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 0000000..e3195fc
--- /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
+.Os
+.Dt I386_SET_WATCH 3
+.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 0000000..cc1b8ed
--- /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 0000000..03c1873
--- /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
+.Os
+.Dt I386_VM86 2
+.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 0000000..c007608
--- /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/pipe.S b/lib/libc/i386/sys/pipe.S
new file mode 100644
index 0000000..99a7ff0
--- /dev/null
+++ b/lib/libc/i386/sys/pipe.S
@@ -0,0 +1,50 @@
+/*-
+ * 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. 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.
+ */
+
+#if defined(SYSLIBC_SCCS) && !defined(lint)
+ .asciz "@(#)pipe.s 5.1 (Berkeley) 4/23/90"
+#endif /* SYSLIBC_SCCS and not lint */
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+SYSCALL(pipe)
+ movl 4(%esp),%ecx
+ movl %eax,(%ecx)
+ movl %edx,4(%ecx)
+ movl $0,%eax
+ ret
diff --git a/lib/libc/i386/sys/ptrace.S b/lib/libc/i386/sys/ptrace.S
new file mode 100644
index 0000000..71ce5c7
--- /dev/null
+++ b/lib/libc/i386/sys/ptrace.S
@@ -0,0 +1,61 @@
+/*-
+ * 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. 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.
+ */
+
+#if defined(SYSLIBC_SCCS) && !defined(lint)
+ .asciz "@(#)ptrace.s 5.1 (Berkeley) 4/23/90"
+#endif /* SYSLIBC_SCCS and not lint */
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+ENTRY(ptrace)
+ xorl %eax,%eax
+#ifdef PIC
+ PIC_PROLOGUE
+ movl PIC_GOT(CNAME(errno)),%edx
+ movl %eax,(%edx)
+ PIC_EPILOGUE
+#else
+ movl %eax,CNAME(errno)
+#endif
+ mov $SYS_ptrace,%eax
+ KERNCALL
+ jb err
+ ret
+err:
+ PIC_PROLOGUE
+ jmp PIC_PLT(HIDENAME(cerror))
diff --git a/lib/libc/i386/sys/reboot.S b/lib/libc/i386/sys/reboot.S
new file mode 100644
index 0000000..80e3d36
--- /dev/null
+++ b/lib/libc/i386/sys/reboot.S
@@ -0,0 +1,46 @@
+/*-
+ * 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. 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.
+ */
+
+#if defined(SYSLIBC_SCCS) && !defined(lint)
+ .asciz "@(#)reboot.s 5.1 (Berkeley) 4/23/90"
+#endif /* SYSLIBC_SCCS and not lint */
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+SYSCALL(reboot)
+ iret
diff --git a/lib/libc/i386/sys/sbrk.S b/lib/libc/i386/sys/sbrk.S
new file mode 100644
index 0000000..97c4769
--- /dev/null
+++ b/lib/libc/i386/sys/sbrk.S
@@ -0,0 +1,94 @@
+/*-
+ * 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. 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.
+ */
+
+#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 err
+ PIC_PROLOGUE
+ movl PIC_GOT(HIDENAME(curbrk)),%edx
+ movl (%edx),%eax
+ addl %ecx,(%edx)
+ PIC_EPILOGUE
+back:
+ ret
+err:
+ PIC_PROLOGUE
+ jmp PIC_PLT(HIDENAME(cerror))
+
+#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 err
+ movl HIDENAME(curbrk),%eax
+ addl %ecx,HIDENAME(curbrk)
+back:
+ ret
+err:
+ jmp HIDENAME(cerror)
+#endif /* PIC */
diff --git a/lib/libc/i386/sys/setlogin.S b/lib/libc/i386/sys/setlogin.S
new file mode 100644
index 0000000..013dc7e
--- /dev/null
+++ b/lib/libc/i386/sys/setlogin.S
@@ -0,0 +1,58 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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)
+#ifdef PIC
+ PIC_PROLOGUE
+ pushl %eax
+ movl PIC_GOT(CNAME(_logname_valid)),%eax
+ movl $0,(%eax)
+ popl %eax
+ PIC_EPILOGUE
+#else
+ movl $0,CNAME(_logname_valid)
+#endif
+ ret /* setlogin(name) */
diff --git a/lib/libc/i386/sys/sigreturn.S b/lib/libc/i386/sys/sigreturn.S
new file mode 100644
index 0000000..2556ab9
--- /dev/null
+++ b/lib/libc/i386/sys/sigreturn.S
@@ -0,0 +1,50 @@
+/*-
+ * 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. 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.
+ */
+
+#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)
diff --git a/lib/libc/i386/sys/syscall.S b/lib/libc/i386/sys/syscall.S
new file mode 100644
index 0000000..c6e9083
--- /dev/null
+++ b/lib/libc/i386/sys/syscall.S
@@ -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.
+ * 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.
+ */
+
+#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 1f
+ ret
+1:
+ PIC_PROLOGUE
+ jmp PIC_PLT(HIDENAME(cerror))
diff --git a/lib/libc/ia64/Makefile.inc b/lib/libc/ia64/Makefile.inc
new file mode 100644
index 0000000..3043777
--- /dev/null
+++ b/lib/libc/ia64/Makefile.inc
@@ -0,0 +1,9 @@
+# $FreeBSD$
+#
+# Machine dependent definitions for the ia64 architecture.
+#
+
+# Long double is 80 bits
+GDTOASRCS+=strtopx.c
+MDSRCS+=machdep_ldisx.c
+SYM_MAPS+=${.CURDIR}/ia64/Symbol.map
diff --git a/lib/libc/ia64/SYS.h b/lib/libc/ia64/SYS.h
new file mode 100644
index 0000000..64d50d2
--- /dev/null
+++ b/lib/libc/ia64/SYS.h
@@ -0,0 +1,77 @@
+/* $NetBSD: SYS.h,v 1.5 1997/05/02 18:15:15 kleink Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ *
+ * $FreeBSD$
+ */
+
+#include <machine/asm.h>
+#include <sys/syscall.h>
+
+#define CALLSYS_ERROR(name) \
+ CALLSYS_NOERROR(name); \
+ cmp.ne p6,p0=r0,r10; \
+(p6) br.cond.sptk.few .cerror
+
+
+#define SYSCALL(name) \
+ENTRY(__sys_ ## name,0); /* XXX # of args? */ \
+ WEAK_ALIAS(name, __sys_ ## name); \
+ WEAK_ALIAS(_ ## name, __sys_ ## name); \
+ CALLSYS_ERROR(name)
+
+#define SYSCALL_NOERROR(name) \
+ENTRY(__sys_ ## name,0); /* XXX # of args? */ \
+ WEAK_ALIAS(name, __sys_ ## name); \
+ WEAK_ALIAS(_ ## name, __sys_ ## name); \
+ CALLSYS_NOERROR(name)
+
+
+#define RSYSCALL(name) \
+ SYSCALL(name); \
+ br.ret.sptk.few rp; \
+END(__sys_ ## name)
+
+#define RSYSCALL_NOERROR(name) \
+ SYSCALL_NOERROR(name); \
+ br.ret.sptk.few rp; \
+END(__sys_ ## name)
+
+
+#define PSEUDO(name) \
+ENTRY(__sys_ ## name,0); /* XXX # of args? */ \
+ WEAK_ALIAS(_ ## name, __sys_ ## name); \
+ CALLSYS_ERROR(name); \
+ br.ret.sptk.few rp; \
+END(__sys_ ## name);
+
+#define PSEUDO_NOERROR(name) \
+ENTRY(__sys_ ## name,0); /* XXX # of args? */ \
+ WEAK_ALIAS(_ ## name, __sys_ ## name); \
+ CALLSYS_NOERROR(name); \
+ br.ret.sptk.few rp; \
+END(__sys_ ## name);
diff --git a/lib/libc/ia64/Symbol.map b/lib/libc/ia64/Symbol.map
new file mode 100644
index 0000000..401c03a
--- /dev/null
+++ b/lib/libc/ia64/Symbol.map
@@ -0,0 +1,77 @@
+# $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;
+ fpsetmask;
+ fpsetround;
+ __infinity;
+ __nan;
+ makecontext;
+ modf;
+ setjmp;
+ longjmp;
+ sigsetjmp;
+ siglongjmp;
+ htonl;
+ __htonl;
+ htons;
+ __htons;
+ ntohl;
+ __ntohl;
+ ntohs;
+ __ntohs;
+ vfork;
+ brk;
+ exect;
+ fork;
+ sbrk;
+};
+
+FBSDprivate {
+ # PSEUDO syscalls
+ __sys_getlogin;
+ _getlogin;
+ __sys_exit;
+
+ _set_tp;
+ __divdf3;
+ __divdi3;
+ __divsf3;
+ __divsi3;
+ __moddi3;
+ __modsi3;
+ __udivdi3;
+ __udivsi3;
+ __umoddi3;
+ __umodsi3;
+ _mcount;
+ ___longjmp;
+ __makecontext;
+ __longjmp;
+ signalcontext;
+ __signalcontext;
+ __siglongjmp;
+ _Unwind_FindTableEntry;
+ __sys_vfork;
+ _vfork;
+ _end;
+ minbrk;
+ .cerror;
+ __sys_fork;
+ _fork;
+ curbrk;
+};
diff --git a/lib/libc/ia64/_fpmath.h b/lib/libc/ia64/_fpmath.h
new file mode 100644
index 0000000..7f24e76
--- /dev/null
+++ b/lib/libc/ia64/_fpmath.h
@@ -0,0 +1,71 @@
+/*-
+ * 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>
+
+union IEEEl2bits {
+ long double e;
+ struct {
+#if _BYTE_ORDER == _LITTLE_ENDIAN
+ unsigned int manl :32;
+ unsigned int manh :32;
+ unsigned int exp :15;
+ unsigned int sign :1;
+ unsigned long junk :48;
+#else /* _BIG_ENDIAN */
+ unsigned long junk :48;
+ unsigned int sign :1;
+ unsigned int exp :15;
+ unsigned int manh :32;
+ unsigned int manl :32;
+#endif
+ } bits;
+};
+
+#if _BYTE_ORDER == _LITTLE_ENDIAN
+#define LDBL_NBIT 0x80000000
+#define mask_nbit_l(u) ((u).bits.manh &= ~LDBL_NBIT)
+#else /* _BIG_ENDIAN */
+/*
+ * XXX This doesn't look right. Very few machines have a different
+ * endianness for integers and floating-point, and in nextafterl()
+ * we assume that none do. If you have an environment for testing
+ * this, please let me know. --das
+ */
+#define LDBL_NBIT 0x80
+#define mask_nbit_l(u) ((u).bits.manh &= ~LDBL_NBIT)
+#endif
+
+#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/ia64/arith.h b/lib/libc/ia64/arith.h
new file mode 100644
index 0000000..6726528
--- /dev/null
+++ b/lib/libc/ia64/arith.h
@@ -0,0 +1,37 @@
+/*
+ * 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 == _LITTLE_ENDIAN
+
+#define IEEE_8087
+#define Arith_Kind_ASL 1
+#define Long int
+#define Intcast (int)(long)
+#define Double_Align
+#define X64_bit_pointers
+
+#else /* _BYTE_ORDER == _LITTLE_ENDIAN */
+
+#define IEEE_MC68k
+#define Arith_Kind_ASL 2
+#define Long int
+#define Intcast (int)(long)
+#define Double_Align
+#define X64_bit_pointers
+#ifdef gcc_bug /* XXX Why does arithchk report sudden underflow here? */
+#define Sudden_Underflow
+#endif
+
+#endif
diff --git a/lib/libc/ia64/gen/Makefile.inc b/lib/libc/ia64/gen/Makefile.inc
new file mode 100644
index 0000000..5358ea8
--- /dev/null
+++ b/lib/libc/ia64/gen/Makefile.inc
@@ -0,0 +1,11 @@
+# $FreeBSD$
+
+SRCS+= __divdf3.S __divdi3.S __divsf3.S __divsi3.S __moddi3.S __modsi3.S \
+ __udivdi3.S __udivsi3.S __umoddi3.S __umodsi3.S _mcount.S _set_tp.c \
+ _setjmp.S fabs.S flt_rounds.c fpgetmask.c fpgetround.c fpsetmask.c \
+ fpsetround.c infinity.c ldexp.c makecontext.c modf.c setjmp.S \
+ signalcontext.c sigsetjmp.S
+
+# The following may go away if function _Unwind_FindTableEntry()
+# will be part of GCC.
+SRCS+= unwind.c
diff --git a/lib/libc/ia64/gen/__divdf3.S b/lib/libc/ia64/gen/__divdf3.S
new file mode 100644
index 0000000..58425d9
--- /dev/null
+++ b/lib/libc/ia64/gen/__divdf3.S
@@ -0,0 +1,142 @@
+//
+// Copyright (c) 2000, Intel Corporation
+// All rights reserved.
+//
+// Contributed 2/15/2000 by Marius Cornea, John Harrison, Cristina Iordache,
+// Ted Kubaska, Bob Norin, and Shane Story of the Computational Software Lab,
+// Intel Corporation.
+//
+// WARRANTY DISCLAIMER
+//
+// 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 INTEL 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.
+//
+// Intel Corporation is the author of this code, and requests that all
+// problem reports or change requests be submitted to it directly at
+// http://developer.intel.com/opensource.
+//
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+ .section .text
+
+ENTRY(__divdf3, 0)
+{ .mfi
+ // a is in f8
+ // b is in f9
+
+ // predicate registers used: p6
+ // floating-point registers used: f6, f7, f8, f9, f10, f11
+
+ // load a, the first argument, in f6
+ nop.m 0
+ mov f6=f8
+ nop.i 0
+} { .mfi
+ // load b, the second argument, in f7
+ nop.m 0
+ mov f7=f9
+ nop.i 0;;
+} { .mfi
+
+ // BEGIN DOUBLE PRECISION LATENCY-OPTIMIZED DIVIDE ALGORITHM
+
+ nop.m 0
+ // Step (1)
+ // y0 = 1 / b in f8
+ frcpa.s0 f8,p6=f6,f7
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // Step (2)
+ // q0 = a * y0 in f9
+ (p6) fma.s1 f9=f6,f8,f0
+ nop.i 0
+} { .mfi
+ nop.m 0
+ // Step (3)
+ // e0 = 1 - b * y0 in f10
+ (p6) fnma.s1 f10=f7,f8,f1
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // Step (4)
+ // q1 = q0 + e0 * q0 in f9
+ (p6) fma.s1 f9=f10,f9,f9
+ nop.i 0
+} { .mfi
+ nop.m 0
+ // Step (5)
+ // e1 = e0 * e0 in f11
+ (p6) fma.s1 f11=f10,f10,f0
+ nop.i 0
+} { .mfi
+ nop.m 0
+ // Step (6)
+ // y1 = y0 + e0 * y0 in f8
+ (p6) fma.s1 f8=f10,f8,f8
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // Step (7)
+ // q2 = q1 + e1 * q1 in f9
+ (p6) fma.s1 f9=f11,f9,f9
+ nop.i 0
+} { .mfi
+ nop.m 0
+ // Step (8)
+ // e2 = e1 * e1 in f10
+ (p6) fma.s1 f10=f11,f11,f0
+ nop.i 0
+} { .mfi
+ nop.m 0
+ // Step (9)
+ // y2 = y1 + e1 * y1 in f8
+ (p6) fma.s1 f8=f11,f8,f8
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // Step (10)
+ // q3 = q2 + e2 * q2 in f9
+ (p6) fma.d.s1 f9=f10,f9,f9
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // Step (11)
+ // y3 = y2 + e2 * y2 in f8
+ (p6) fma.s1 f8=f10,f8,f8
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // Step (12)
+ // r0 = a - b * q3 in f6
+ (p6) fnma.d.s1 f6=f7,f9,f6
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // Step (13)
+ // q4 = q3 + r0 * y3 in f8
+ (p6) fma.d.s0 f8=f6,f8,f9
+ nop.i 0;;
+
+ // END DOUBLE PRECISION LATENCY-OPTIMIZED DIVIDE ALGORITHM
+
+} { .mib
+ nop.m 0
+ nop.i 0
+ // return
+ br.ret.sptk b0;;
+}
+
+END(__divdf3)
+
diff --git a/lib/libc/ia64/gen/__divdi3.S b/lib/libc/ia64/gen/__divdi3.S
new file mode 100644
index 0000000..92e2911
--- /dev/null
+++ b/lib/libc/ia64/gen/__divdi3.S
@@ -0,0 +1,143 @@
+.file "__divdi3.s"
+
+//
+// Copyright (c) 2000, Intel Corporation
+// All rights reserved.
+//
+// Contributed 2/15/2000 by Marius Cornea, John Harrison, Cristina Iordache,
+// Ted Kubaska, Bob Norin, and Shane Story of the Computational Software Lab,
+// Intel Corporation.
+//
+// WARRANTY DISCLAIMER
+//
+// 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 INTEL 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.
+//
+// Intel Corporation is the author of this code, and requests that all
+// problem reports or change requests be submitted to it directly at
+// http://developer.intel.com/opensource.
+//
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+.section .text
+.proc __divdi3#
+.align 32
+.global __divdi3#
+.align 32
+
+// 64-bit signed integer divide
+
+__divdi3:
+
+{ .mii
+ alloc r31=ar.pfs,2,0,0,0
+ nop.i 0
+ nop.i 0;;
+} { .mmi
+
+ // 64-BIT SIGNED INTEGER DIVIDE BEGINS HERE
+
+ setf.sig f8=r32
+ setf.sig f9=r33
+ nop.i 0;;
+} { .mfb
+ nop.m 0
+ fcvt.xf f6=f8
+ nop.b 0
+} { .mfb
+ nop.m 0
+ fcvt.xf f7=f9
+ nop.b 0;;
+} { .mfi
+ nop.m 0
+ // Step (1)
+ // y0 = 1 / b in f8
+ frcpa.s1 f8,p6=f6,f7
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // Step (2)
+ // e0 = 1 - b * y0 in f9
+ (p6) fnma.s1 f9=f7,f8,f1
+ nop.i 0
+} { .mfi
+ nop.m 0
+ // Step (3)
+ // q0 = a * y0 in f10
+ (p6) fma.s1 f10=f6,f8,f0
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // Step (4)
+ // e1 = e0 * e0 in f11
+ (p6) fma.s1 f11=f9,f9,f0
+ nop.i 0
+} { .mfi
+ nop.m 0
+ // Step (5)
+ // q1 = q0 + e0 * q0 in f10
+ (p6) fma.s1 f10=f9,f10,f10
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // Step (6)
+ // y1 = y0 + e0 * y0 in f8
+ (p6) fma.s1 f8=f9,f8,f8
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // Step (7)
+ // q2 = q1 + e1 * q1 in f9
+ (p6) fma.s1 f9=f11,f10,f10
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // Step (8)
+ // y2 = y1 + e1 * y1 in f8
+ (p6) fma.s1 f8=f11,f8,f8
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // Step (9)
+ // r2 = a - b * q2 in f10
+ (p6) fnma.s1 f10=f7,f9,f6
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // Step (10)
+ // q3 = q2 + r2 * y2 in f8
+ (p6) fma.s1 f8=f10,f8,f9
+ nop.i 0;;
+} { .mfb
+ nop.m 0
+ // Step (11)
+ // q = trunc (q3)
+ fcvt.fx.trunc.s1 f8=f8
+ nop.b 0;;
+} { .mmi
+ // quotient will be in r8 (if b != 0)
+ getf.sig r8=f8
+ nop.m 0
+ nop.i 0;;
+}
+
+ // 64-BIT SIGNED INTEGER DIVIDE ENDS HERE
+
+{ .mmb
+ nop.m 0
+ nop.m 0
+ br.ret.sptk b0;;
+}
+
+.endp __divdi3
diff --git a/lib/libc/ia64/gen/__divsf3.S b/lib/libc/ia64/gen/__divsf3.S
new file mode 100644
index 0000000..fe7bcb4
--- /dev/null
+++ b/lib/libc/ia64/gen/__divsf3.S
@@ -0,0 +1,116 @@
+//
+// Copyright (c) 2000, Intel Corporation
+// All rights reserved.
+//
+// Contributed 2/15/2000 by Marius Cornea, John Harrison, Cristina Iordache,
+// Ted Kubaska, Bob Norin, and Shane Story of the Computational Software Lab,
+// Intel Corporation.
+//
+// WARRANTY DISCLAIMER
+//
+// 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 INTEL 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.
+//
+// Intel Corporation is the author of this code, and requests that all
+// problem reports or change requests be submitted to it directly at
+// http://developer.intel.com/opensource.
+//
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+ENTRY(__divsf3, 0)
+{ .mfi
+ // a is in f8
+ // b is in f9
+
+ // general registers used: r31, r32, r33, r34
+ // predicate registers used: p6
+ // floating-point registers used: f6, f7, f8
+
+ nop.m 0
+ // load a, the first argument, in f6
+ mov f6=f8
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // load b, the second argument, in f7
+ mov f7=f9
+ nop.i 0;;
+} { .mfi
+
+ // BEGIN SINGLE PRECISION LATENCY-OPTIMIZED DIVIDE ALGORITHM
+
+ nop.m 0
+ // Step (1)
+ // y0 = 1 / b in f8
+ frcpa.s0 f8,p6=f6,f7
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // Step (2)
+ // q0 = a * y0 in f6
+ (p6) fma.s1 f6=f6,f8,f0
+ nop.i 0
+} { .mfi
+ nop.m 0
+ // Step (3)
+ // e0 = 1 - b * y0 in f7
+ (p6) fnma.s1 f7=f7,f8,f1
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // Step (4)
+ // q1 = q0 + e0 * q0 in f6
+ (p6) fma.s1 f6=f7,f6,f6
+ nop.i 0
+} { .mfi
+ nop.m 0
+ // Step (5)
+ // e1 = e0 * e0 in f7
+ (p6) fma.s1 f7=f7,f7,f0
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // Step (6)
+ // q2 = q1 + e1 * q1 in f6
+ (p6) fma.s1 f6=f7,f6,f6
+ nop.i 0
+} { .mfi
+ nop.m 0
+ // Step (7)
+ // e2 = e1 * e1 in f7
+ (p6) fma.s1 f7=f7,f7,f0
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // Step (8)
+ // q3 = q2 + e2 * q2 in f6
+ (p6) fma.d.s1 f6=f7,f6,f6
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // Step (9)
+ // q3' = q3 in f8
+ (p6) fma.s.s0 f8=f6,f1,f0
+ nop.i 0;;
+
+ // END SINGLE PRECISION LATENCY-OPTIMIZED DIVIDE ALGORITHM
+
+} { .mmb
+ nop.m 0
+ nop.m 0
+ // return
+ br.ret.sptk b0;;
+}
+
+END(__divsf3)
diff --git a/lib/libc/ia64/gen/__divsi3.S b/lib/libc/ia64/gen/__divsi3.S
new file mode 100644
index 0000000..4c82e32
--- /dev/null
+++ b/lib/libc/ia64/gen/__divsi3.S
@@ -0,0 +1,125 @@
+.file "__divsi3.s"
+
+//
+// Copyright (c) 2000, Intel Corporation
+// All rights reserved.
+//
+// Contributed 2/15/2000 by Marius Cornea, John Harrison, Cristina Iordache,
+// Ted Kubaska, Bob Norin, and Shane Story of the Computational Software Lab,
+// Intel Corporation.
+//
+// WARRANTY DISCLAIMER
+//
+// 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 INTEL 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.
+//
+// Intel Corporation is the author of this code, and requests that all
+// problem reports or change requests be submitted to it directly at
+// http://developer.intel.com/opensource.
+//
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+.section .text
+
+// 32-bit signed integer divide
+
+.proc __divsi3#
+.align 32
+.global __divsi3#
+.align 32
+
+__divsi3:
+
+{ .mii
+ alloc r31=ar.pfs,2,0,0,0
+ nop.i 0
+ nop.i 0;;
+} { .mii
+ nop.m 0
+
+ // 32-BIT SIGNED INTEGER DIVIDE BEGINS HERE
+
+ // general register used:
+ // r32 - 32-bit signed integer dividend
+ // r33 - 32-bit signed integer divisor
+ // r8 - 32-bit signed integer result
+ // r2 - scratch register
+ // floating-point registers used: f6, f7, f8, f9
+ // predicate registers used: p6
+
+ sxt4 r32=r32
+ sxt4 r33=r33;;
+} { .mmb
+ setf.sig f6=r32
+ setf.sig f7=r33
+ nop.b 0;;
+} { .mfi
+ nop.m 0
+ fcvt.xf f6=f6
+ nop.i 0
+} { .mfi
+ nop.m 0
+ fcvt.xf f7=f7
+ mov r2 = 0x0ffdd;;
+} { .mfi
+ setf.exp f9 = r2
+ // (1) y0
+ frcpa.s1 f8,p6=f6,f7
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // (2) q0 = a * y0
+ (p6) fma.s1 f6=f6,f8,f0
+ nop.i 0
+} { .mfi
+ nop.m 0
+ // (3) e0 = 1 - b * y0
+ (p6) fnma.s1 f7=f7,f8,f1
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // (4) q1 = q0 + e0 * q0
+ (p6) fma.s1 f6=f7,f6,f6
+ nop.i 0
+} { .mfi
+ nop.m 0
+ // (5) e1 = e0 * e0 + 2^-34
+ (p6) fma.s1 f7=f7,f7,f9
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // (6) q2 = q1 + e1 * q1
+ (p6) fma.s1 f8=f7,f6,f6
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // (7) q = trunc(q2)
+ fcvt.fx.trunc.s1 f8=f8
+ nop.i 0;;
+} { .mmi
+ // quotient will be in the least significant 32 bits of r8 (if b != 0)
+ getf.sig r8=f8
+ nop.m 0
+ nop.i 0;;
+}
+
+ // 32-BIT SIGNED INTEGER DIVIDE ENDS HERE
+
+{ .mmb
+ nop.m 0
+ nop.m 0
+ br.ret.sptk b0;;
+}
+
+.endp __divsi3
diff --git a/lib/libc/ia64/gen/__moddi3.S b/lib/libc/ia64/gen/__moddi3.S
new file mode 100644
index 0000000..e15f964
--- /dev/null
+++ b/lib/libc/ia64/gen/__moddi3.S
@@ -0,0 +1,160 @@
+.file "__moddi3.s"
+
+//
+// Copyright (c) 2000, Intel Corporation
+// All rights reserved.
+//
+// Contributed 2/15/2000 by Marius Cornea, John Harrison, Cristina Iordache,
+// Ted Kubaska, Bob Norin, and Shane Story of the Computational Software Lab,
+// Intel Corporation.
+//
+// WARRANTY DISCLAIMER
+//
+// 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 INTEL 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.
+//
+// Intel Corporation is the author of this code, and requests that all
+// problem reports or change requests be submitted to it directly at
+// http://developer.intel.com/opensource.
+//
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+.section .text
+
+// 64-bit signed integer remainder
+
+.proc __moddi3#
+.align 32
+.global __moddi3#
+.align 32
+
+__moddi3:
+
+{ .mii
+ alloc r31=ar.pfs,3,0,0,0
+ nop.i 0
+ nop.i 0
+} { .mmb
+
+ // 64-BIT SIGNED INTEGER REMAINDER BEGINS HERE
+
+ // general register used:
+ // r32 - 64-bit signed integer dividend
+ // r33 - 64-bit signed integer divisor
+ // r8 - 64-bit signed integer result
+ // r2 - scratch register
+ // floating-point registers used: f6, f7, f8, f9, f10, f11, f12
+ // predicate registers used: p6
+
+ setf.sig f12=r32 // holds an in integer form
+ setf.sig f7=r33
+ nop.b 0
+} { .mlx
+ nop.m 0
+ //movl r2=0x8000000000000000;;
+ movl r2=0xffffffffffffffff;;
+} { .mfi
+ // get the 2's complement of b
+ sub r33=r0,r33
+ fcvt.xf f6=f12
+ nop.i 0
+} { .mfi
+ nop.m 0
+ fcvt.xf f7=f7
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // Step (1)
+ // y0 = 1 / b in f8
+ frcpa.s1 f8,p6=f6,f7
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // Step (2)
+ // q0 = a * y0 in f10
+ (p6) fma.s1 f10=f6,f8,f0
+ nop.i 0
+} { .mfi
+ nop.m 0
+ // Step (3)
+ // e0 = 1 - b * y0 in f9
+ (p6) fnma.s1 f9=f7,f8,f1
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // Step (4)
+ // q1 = q0 + e0 * q0 in f10
+ (p6) fma.s1 f10=f9,f10,f10
+ nop.i 0
+} { .mfi
+ nop.m 0
+ // Step (5)
+ // e1 = e0 * e0 in f11
+ (p6) fma.s1 f11=f9,f9,f0
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // Step (6)
+ // y1 = y0 + e0 * y0 in f8
+ (p6) fma.s1 f8=f9,f8,f8
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // Step (7)
+ // q2 = q1 + e1 * q1 in f9
+ (p6) fma.s1 f9=f11,f10,f10
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // Step (8)
+ // y2 = y1 + e1 * y1 in f8
+ (p6) fma.s1 f8=f11,f8,f8
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // Step (9)
+ // r2 = a - b * q2 in f10
+ (p6) fnma.s1 f10=f7,f9,f6
+ nop.i 0;;
+} { .mfi
+ setf.sig f7=r33
+ // Step (10)
+ // q3 = q2 + r2 * y2 in f8
+ (p6) fma.s1 f8=f10,f8,f9
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // (11) q = trunc(q3)
+ fcvt.fx.trunc.s1 f8=f8
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // (12) r = a + (-b) * q
+ xma.l f8=f8,f7,f12
+ nop.i 0;;
+} { .mib
+ getf.sig r8=f8
+ nop.i 0
+ nop.b 0
+}
+
+ // 64-BIT SIGNED INTEGER REMAINDER ENDS HERE
+
+{ .mib
+ nop.m 0
+ nop.i 0
+ br.ret.sptk b0;;
+}
+
+.endp __moddi3
diff --git a/lib/libc/ia64/gen/__modsi3.S b/lib/libc/ia64/gen/__modsi3.S
new file mode 100644
index 0000000..1939493
--- /dev/null
+++ b/lib/libc/ia64/gen/__modsi3.S
@@ -0,0 +1,132 @@
+.file "__modsi3.s"
+
+//
+// Copyright (c) 2000, Intel Corporation
+// All rights reserved.
+//
+// Contributed 2/15/2000 by Marius Cornea, John Harrison, Cristina Iordache,
+// Ted Kubaska, Bob Norin, and Shane Story of the Computational Software Lab,
+// Intel Corporation.
+//
+// WARRANTY DISCLAIMER
+//
+// 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 INTEL 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.
+//
+// Intel Corporation is the author of this code, and requests that all
+// problem reports or change requests be submitted to it directly at
+// http://developer.intel.com/opensource.
+//
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+.section .text
+
+// 32-bit signed integer remainder
+
+.proc __modsi3#
+.align 32
+.global __modsi3#
+.align 32
+
+__modsi3:
+
+{ .mii
+ alloc r31=ar.pfs,2,0,0,0
+ nop.i 0
+ nop.i 0;;
+} { .mii
+ nop.m 0
+
+ // 32-BIT SIGNED INTEGER REMAINDER BEGINS HERE
+
+ // general register used:
+ // r32 - 32-bit signed integer dividend
+ // r33 - 32-bit signed integer divisor
+ // r8 - 32-bit signed integer result
+ // r2 - scratch register
+ // floating-point registers used: f6, f7, f8, f9, f10, f11
+ // predicate registers used: p6
+
+ sxt4 r32=r32
+ sxt4 r33=r33;;
+} { .mmb
+ setf.sig f11=r32
+ setf.sig f7=r33
+ nop.b 0;;
+} { .mfi
+ // get 2's complement of b
+ sub r33=r0,r33
+ fcvt.xf f6=f11
+ nop.i 0
+} { .mfi
+ nop.m 0
+ fcvt.xf f7=f7
+ mov r2 = 0x0ffdd;;
+} { .mfi
+ setf.exp f9 = r2
+ // (1) y0
+ frcpa.s1 f8,p6=f6,f7
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // (2) q0 = a * y0
+ (p6) fma.s1 f10=f6,f8,f0
+ nop.i 0
+} { .mfi
+ nop.m 0
+ // (3) e0 = 1 - b * y0
+ (p6) fnma.s1 f8=f7,f8,f1
+ nop.i 0;;
+} { .mfi
+ // 2's complement of b
+ setf.sig f7=r33
+ // (4) q1 = q0 + e0 * q0
+ (p6) fma.s1 f10=f8,f10,f10
+ nop.i 0
+} { .mfi
+ nop.m 0
+ // (5) e1 = e0 * e0 + 2^-34
+ (p6) fma.s1 f8=f8,f8,f9
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // (6) q2 = q1 + e1 * q1
+ (p6) fma.s1 f8=f8,f10,f10
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // (7) q = trunc(q2)
+ fcvt.fx.trunc.s1 f8=f8
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // (8) r = a + (-b) * q
+ xma.l f8=f8,f7,f11
+ nop.i 0;;
+} { .mmi
+ // remainder will be in the least significant 32 bits of r8 (if b != 0)
+ getf.sig r8=f8
+ nop.m 0
+ nop.i 0;;
+}
+
+ // 32-BIT SIGNED INTEGER REMAINDER ENDS HERE
+
+{ .mmb
+ nop.m 0
+ nop.m 0
+ br.ret.sptk b0;;
+}
+
+.endp __modsi3
diff --git a/lib/libc/ia64/gen/__udivdi3.S b/lib/libc/ia64/gen/__udivdi3.S
new file mode 100644
index 0000000..1233e8a
--- /dev/null
+++ b/lib/libc/ia64/gen/__udivdi3.S
@@ -0,0 +1,144 @@
+.file "__udivdi3.s"
+
+//
+// Copyright (c) 2000, Intel Corporation
+// All rights reserved.
+//
+// Contributed 2/15/2000 by Marius Cornea, John Harrison, Cristina Iordache,
+// Ted Kubaska, Bob Norin, and Shane Story of the Computational Software Lab,
+// Intel Corporation.
+//
+// WARRANTY DISCLAIMER
+//
+// 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 INTEL 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.
+//
+// Intel Corporation is the author of this code, and requests that all
+// problem reports or change requests be submitted to it directly at
+// http://developer.intel.com/opensource.
+//
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+.section .text
+.proc __udivdi3#
+.align 32
+.global __udivdi3#
+.align 32
+
+// 64-bit unsigned integer divide
+
+__udivdi3:
+
+{ .mii
+ alloc r31=ar.pfs,2,0,0,0
+ nop.i 0
+ nop.i 0;;
+}
+
+{ .mmi
+
+ // 64-BIT UNSIGNED INTEGER DIVIDE BEGINS HERE
+
+ setf.sig f8=r32
+ setf.sig f9=r33
+ nop.i 0;;
+} { .mfb
+ nop.m 0
+ fma.s1 f6=f8,f1,f0
+ nop.b 0
+} { .mfb
+ nop.m 0
+ fma.s1 f7=f9,f1,f0
+ nop.b 0;;
+} { .mfi
+ nop.m 0
+ // Step (1)
+ // y0 = 1 / b in f8
+ frcpa.s1 f8,p6=f6,f7
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // Step (2)
+ // e0 = 1 - b * y0 in f9
+ (p6) fnma.s1 f9=f7,f8,f1
+ nop.i 0
+} { .mfi
+ nop.m 0
+ // Step (3)
+ // q0 = a * y0 in f10
+ (p6) fma.s1 f10=f6,f8,f0
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // Step (4)
+ // e1 = e0 * e0 in f11
+ (p6) fma.s1 f11=f9,f9,f0
+ nop.i 0
+} { .mfi
+ nop.m 0
+ // Step (5)
+ // q1 = q0 + e0 * q0 in f10
+ (p6) fma.s1 f10=f9,f10,f10
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // Step (6)
+ // y1 = y0 + e0 * y0 in f8
+ (p6) fma.s1 f8=f9,f8,f8
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // Step (7)
+ // q2 = q1 + e1 * q1 in f9
+ (p6) fma.s1 f9=f11,f10,f10
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // Step (8)
+ // y2 = y1 + e1 * y1 in f8
+ (p6) fma.s1 f8=f11,f8,f8
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // Step (9)
+ // r2 = a - b * q2 in f10
+ (p6) fnma.s1 f10=f7,f9,f6
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // Step (10)
+ // q3 = q2 + r2 * y2 in f8
+ (p6) fma.s1 f8=f10,f8,f9
+ nop.i 0;;
+} { .mfb
+ nop.m 0
+ // (11) q = trunc(q3)
+ fcvt.fxu.trunc.s1 f8=f8
+ nop.b 0;;
+} { .mmi
+ // quotient will be in r8 (if b != 0)
+ getf.sig r8=f8
+ nop.m 0
+ nop.i 0;;
+}
+
+ // 64-BIT UNSIGNED INTEGER DIVIDE ENDS HERE
+
+{ .mmb
+ nop.m 0
+ nop.m 0
+ br.ret.sptk b0;;
+}
+
+.endp __udivdi3
diff --git a/lib/libc/ia64/gen/__udivsi3.S b/lib/libc/ia64/gen/__udivsi3.S
new file mode 100644
index 0000000..25959b8
--- /dev/null
+++ b/lib/libc/ia64/gen/__udivsi3.S
@@ -0,0 +1,125 @@
+.file "__udivsi3.s"
+
+//
+// Copyright (c) 2000, Intel Corporation
+// All rights reserved.
+//
+// Contributed 2/15/2000 by Marius Cornea, John Harrison, Cristina Iordache,
+// Ted Kubaska, Bob Norin, and Shane Story of the Computational Software Lab,
+// Intel Corporation.
+//
+// WARRANTY DISCLAIMER
+//
+// 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 INTEL 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.
+//
+// Intel Corporation is the author of this code, and requests that all
+// problem reports or change requests be submitted to it directly at
+// http://developer.intel.com/opensource.
+//
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+.section .text
+
+// 32-bit unsigned integer divide
+
+.proc __udivsi3#
+.align 32
+.global __udivsi3#
+.align 32
+
+__udivsi3:
+
+{ .mii
+ alloc r31=ar.pfs,2,0,0,0
+ nop.i 0
+ nop.i 0;;
+} { .mii
+ nop.m 0
+
+ // 32-BIT UNSIGNED INTEGER DIVIDE BEGINS HERE
+
+ // general register used:
+ // r32 - 32-bit unsigned integer dividend
+ // r33 - 32-bit unsigned integer divisor
+ // r8 - 32-bit unsigned integer result
+ // r2 - scratch register
+ // floating-point registers used: f6, f7, f8, f9
+ // predicate registers used: p6
+
+ zxt4 r32=r32
+ zxt4 r33=r33;;
+} { .mmb
+ setf.sig f6=r32
+ setf.sig f7=r33
+ nop.b 0;;
+} { .mfi
+ nop.m 0
+ fcvt.xf f6=f6
+ nop.i 0
+} { .mfi
+ nop.m 0
+ fcvt.xf f7=f7
+ mov r2 = 0x0ffdd;;
+} { .mfi
+ setf.exp f9 = r2
+ // (1) y0
+ frcpa.s1 f8,p6=f6,f7
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // (2) q0 = a * y0
+ (p6) fma.s1 f6=f6,f8,f0
+ nop.i 0
+} { .mfi
+ nop.m 0
+ // (3) e0 = 1 - b * y0
+ (p6) fnma.s1 f7=f7,f8,f1
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // (4) q1 = q0 + e0 * q0
+ (p6) fma.s1 f6=f7,f6,f6
+ nop.i 0
+} { .mfi
+ nop.m 0
+ // (5) e1 = e0 * e0 + 2^-34
+ (p6) fma.s1 f7=f7,f7,f9
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // (6) q2 = q1 + e1 * q1
+ (p6) fma.s1 f8=f7,f6,f6
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // (7) q = trunc(q2)
+ fcvt.fxu.trunc.s1 f8=f8
+ nop.i 0;;
+} { .mmi
+ // quotient will be in the least significant 32 bits of r8 (if b != 0)
+ getf.sig r8=f8
+ nop.m 0
+ nop.i 0;;
+}
+
+ // 32-BIT UNSIGNED INTEGER DIVIDE ENDS HERE
+
+{ .mmb
+ nop.m 0
+ nop.m 0
+ br.ret.sptk b0;;
+}
+
+.endp __udivsi3
diff --git a/lib/libc/ia64/gen/__umoddi3.S b/lib/libc/ia64/gen/__umoddi3.S
new file mode 100644
index 0000000..509c62b
--- /dev/null
+++ b/lib/libc/ia64/gen/__umoddi3.S
@@ -0,0 +1,156 @@
+.file "__umoddi3.s"
+
+//
+// Copyright (c) 2000, Intel Corporation
+// All rights reserved.
+//
+// Contributed 2/15/2000 by Marius Cornea, John Harrison, Cristina Iordache,
+// Ted Kubaska, Bob Norin, and Shane Story of the Computational Software Lab,
+// Intel Corporation.
+//
+// WARRANTY DISCLAIMER
+//
+// 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 INTEL 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.
+//
+// Intel Corporation is the author of this code, and requests that all
+// problem reports or change requests be submitted to it directly at
+// http://developer.intel.com/opensource.
+//
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+.section .text
+
+ // 64-bit unsigned integer remainder
+
+.proc __umoddi3#
+.align 32
+.global __umoddi3#
+.align 32
+
+__umoddi3:
+
+{ .mii
+ alloc r31=ar.pfs,3,0,0,0
+ nop.i 0
+ nop.i 0
+} { .mmb
+
+ // 64-BIT UNSIGNED INTEGER REMAINDER BEGINS HERE
+
+ // general register used:
+ // r32 - 64-bit unsigned integer dividend
+ // r33 - 64-bit unsigned integer divisor
+ // r8 - 64-bit unsigned integer result
+ // floating-point registers used: f6, f7, f8, f9, f10, f11, f12
+ // predicate registers used: p6
+
+ setf.sig f12=r32 // holds an in integer form
+ setf.sig f7=r33
+ nop.b 0;;
+} { .mfi
+ // get 2's complement of b
+ sub r33=r0,r33
+ fcvt.xuf.s1 f6=f12
+ nop.i 0
+} { .mfi
+ nop.m 0
+ fcvt.xuf.s1 f7=f7
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // Step (1)
+ // y0 = 1 / b in f8
+ frcpa.s1 f8,p6=f6,f7
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // Step (2)
+ // q0 = a * y0 in f10
+ (p6) fma.s1 f10=f6,f8,f0
+ nop.i 0
+} { .mfi
+ nop.m 0
+ // Step (3)
+ // e0 = 1 - b * y0 in f9
+ (p6) fnma.s1 f9=f7,f8,f1
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // Step (4)
+ // q1 = q0 + e0 * q0 in f10
+ (p6) fma.s1 f10=f9,f10,f10
+ nop.i 0
+} { .mfi
+ nop.m 0
+ // Step (5)
+ // e1 = e0 * e0 in f11
+ (p6) fma.s1 f11=f9,f9,f0
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // Step (6)
+ // y1 = y0 + e0 * y0 in f8
+ (p6) fma.s1 f8=f9,f8,f8
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // Step (7)
+ // q2 = q1 + e1 * q1 in f9
+ (p6) fma.s1 f9=f11,f10,f10
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // Step (8)
+ // y2 = y1 + e1 * y1 in f8
+ (p6) fma.s1 f8=f11,f8,f8
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // Step (9)
+ // r2 = a - b * q2 in f10
+ (p6) fnma.s1 f10=f7,f9,f6
+ nop.i 0;;
+} { .mfi
+ // f7=-b
+ setf.sig f7=r33
+ // Step (10)
+ // q3 = q2 + r2 * y2 in f8
+ (p6) fma.s1 f8=f10,f8,f9
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // (11) q = trunc(q3)
+ fcvt.fxu.trunc.s1 f8=f8
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // (12) r = a + (-b) * q
+ xma.l f8=f8,f7,f12
+ nop.i 0;;
+} { .mib
+ getf.sig r8=f8
+ nop.i 0
+ nop.b 0
+}
+
+ // 64-BIT UNSIGNED INTEGER REMAINDER ENDS HERE
+
+{ .mib
+ nop.m 0
+ nop.i 0
+ br.ret.sptk b0;;
+}
+
+.endp __umoddi3
diff --git a/lib/libc/ia64/gen/__umodsi3.S b/lib/libc/ia64/gen/__umodsi3.S
new file mode 100644
index 0000000..697db2e
--- /dev/null
+++ b/lib/libc/ia64/gen/__umodsi3.S
@@ -0,0 +1,132 @@
+.file "__umodsi3.s"
+
+//
+// Copyright (c) 2000, Intel Corporation
+// All rights reserved.
+//
+// Contributed 2/15/2000 by Marius Cornea, John Harrison, Cristina Iordache,
+// Ted Kubaska, Bob Norin, and Shane Story of the Computational Software Lab,
+// Intel Corporation.
+//
+// WARRANTY DISCLAIMER
+//
+// 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 INTEL 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.
+//
+// Intel Corporation is the author of this code, and requests that all
+// problem reports or change requests be submitted to it directly at
+// http://developer.intel.com/opensource.
+//
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+.section .text
+
+// 32-bit unsigned integer remainder
+
+.proc __umodsi3#
+.align 32
+.global __umodsi3#
+.align 32
+
+__umodsi3:
+
+{ .mii
+ alloc r31=ar.pfs,2,0,0,0
+ nop.i 0
+ nop.i 0;;
+} { .mii
+ nop.m 0
+
+ // 32-BIT UNSIGNED INTEGER REMAINDER BEGINS HERE
+
+ // general register used:
+ // r32 - 32-bit unsigned integer dividend
+ // r33 - 32-bit unsigned integer divisor
+ // r8 - 32-bit unsigned integer result
+ // r2 - scratch register
+ // floating-point registers used: f6, f7, f8, f9, f10, f11
+ // predicate registers used: p6
+
+ zxt4 r32=r32
+ zxt4 r33=r33;;
+} { .mmb
+ setf.sig f11=r32
+ setf.sig f7=r33
+ nop.b 0;;
+} { .mfi
+ nop.m 0
+ fcvt.xf f6=f11
+ nop.i 0
+} { .mfi
+ // get 2's complement of b
+ sub r33=r0,r33
+ fcvt.xf f7=f7
+ mov r2 = 0x0ffdd;;
+} { .mfi
+ setf.exp f9 = r2
+ // (1) y0
+ frcpa.s1 f8,p6=f6,f7
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // (2) q0 = a * y0
+ (p6) fma.s1 f10=f6,f8,f0
+ nop.i 0
+} { .mfi
+ nop.m 0
+ // (3) e0 = 1 - b * y0
+ (p6) fnma.s1 f8=f7,f8,f1
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // (4) q1 = q0 + e0 * q0
+ (p6) fma.s1 f10=f8,f10,f10
+ nop.i 0
+} { .mfi
+ // get 2's complement of b
+ setf.sig f7=r33
+ // (5) e1 = e0 * e0 + 2^-34
+ (p6) fma.s1 f8=f8,f8,f9
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // (6) q2 = q1 + e1 * q1
+ (p6) fma.s1 f8=f8,f10,f10
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // (7) q = trunc(q2)
+ fcvt.fxu.trunc.s1 f8=f8
+ nop.i 0;;
+} { .mfi
+ nop.m 0
+ // (8) r = a + (-b) * q
+ xma.l f8=f8,f7,f11
+ nop.i 0;;
+} { .mmi
+ // remainder will be in the least significant 32 bits of r8 (if b != 0)
+ getf.sig r8=f8
+ nop.m 0
+ nop.i 0;;
+}
+
+ // 32-BIT UNSIGNED INTEGER REMAINDER ENDS HERE
+
+{ .mmb
+ nop.m 0
+ nop.m 0
+ br.ret.sptk b0;;
+}
+
+.endp __umodsi3
diff --git a/lib/libc/ia64/gen/_mcount.S b/lib/libc/ia64/gen/_mcount.S
new file mode 100644
index 0000000..d9e9b76
--- /dev/null
+++ b/lib/libc/ia64/gen/_mcount.S
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2004 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 <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+ .text
+
+/*
+ * Important registers:
+ * r8 structure return address
+ * r15 static link (nested routines)
+ * rp our return address
+ * in0 caller's ar.pfs
+ * in1 caller's gp
+ * in2 caller's rp
+ * in3 GOT entry
+ * ar.pfs our pfs
+ */
+ENTRY_NOPROFILE(_mcount, 4)
+ alloc loc0 = ar.pfs, 4, 4, 2, 0
+ mov loc1 = r8
+ mov loc2 = rp
+ mov loc3 = r15
+ ;;
+ mov out0 = in2
+ mov out1 = rp
+ br.call.sptk rp = __mcount
+ ;;
+1:
+ mov gp = in1
+ mov r14 = ip
+ mov b7 = loc2
+ ;;
+ add r14 = 2f - 1b, r14
+ mov ar.pfs = loc0
+ mov rp = in2
+ ;;
+ mov r15 = loc3
+ mov b7 = r14
+ mov b6 = loc2
+ mov r8 = loc1
+ mov r14 = in0
+ br.ret.sptk b7
+ ;;
+2:
+ mov ar.pfs = r14
+ br.sptk b6
+ ;;
+END(_mcount)
+
+WEAK_ALIAS(mcount, _mcount)
diff --git a/lib/libc/ia64/gen/_set_tp.c b/lib/libc/ia64/gen/_set_tp.c
new file mode 100644
index 0000000..2419e10
--- /dev/null
+++ b/lib/libc/ia64/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$
+ */
+
+void
+_set_tp(void *tpval)
+{
+ register void* tp __asm__("r13");
+
+ tp = tpval;
+}
diff --git a/lib/libc/ia64/gen/_setjmp.S b/lib/libc/ia64/gen/_setjmp.S
new file mode 100644
index 0000000..3966e83
--- /dev/null
+++ b/lib/libc/ia64/gen/_setjmp.S
@@ -0,0 +1,310 @@
+//
+// Copyright (c) 1999, 2000
+// Intel 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. All advertising materials mentioning features or use of this software
+// must display the following acknowledgement:
+//
+// This product includes software developed by Intel Corporation and
+// its contributors.
+//
+// 4. Neither the name of Intel Corporation or its contributors may be
+// used to endorse or promote products derived from this software
+// without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION AND CONTRIBUTORS ``AS IS''
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL INTEL CORPORATION OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+// THE POSSIBILITY OF SUCH DAMAGE.
+//
+//
+
+//
+// Module Name:
+//
+// setjmp.s
+//
+// Abstract:
+//
+// Contains an implementation of setjmp and longjmp for the
+// IA-64 architecture.
+
+ .file "setjmp.s"
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#define LOCORE
+#include <machine/setjmp.h>
+
+// int _setjmp(struct jmp_buffer *)
+//
+// Setup a non-local goto.
+//
+// Description:
+//
+// SetJump stores the current register set in the area pointed to
+// by "save". It returns zero. Subsequent calls to "LongJump" will
+// restore the registers and return non-zero to the same location.
+//
+// On entry, r32 contains the pointer to the jmp_buffer
+//
+
+ENTRY(_setjmp, 1)
+ add r10 = J_PREDS, r32 // skip Unats & pfs save area
+ add r11 = J_BSP, r32
+ //
+ // save immediate context
+ //
+ mov r2 = ar.bsp // save backing store pointer
+ mov r3 = pr // save predicates
+ flushrs
+ ;;
+ //
+ // save user Unat register
+ //
+ mov r16 = ar.lc // save loop count register
+ mov r14 = ar.unat // save user Unat register
+
+ st8 [r10] = r3, J_LC-J_PREDS
+ st8 [r11] = r2, J_R4-J_BSP
+ ;;
+ st8 [r10] = r16, J_R5-J_LC
+ st8 [r32] = r14, J_NATS // Note: Unat at the
+ // beginning of the save area
+ mov r15 = ar.pfs
+ ;;
+ //
+ // save preserved general registers & NaT's
+ //
+ .mem.offset 0,0
+ st8.spill [r11] = r4, J_R6-J_R4
+ .mem.offset 8,0
+ st8.spill [r10] = r5, J_R7-J_R5
+ ;;
+ .mem.offset 16,0
+ st8.spill [r11] = r6, J_SP-J_R6
+ .mem.offset 24,0
+ st8.spill [r10] = r7, J_F3-J_R7
+ ;;
+ st8.spill [r11] = sp, J_F2-J_SP
+ mov r16 = ar.rsc
+ ;;
+ //
+ // save spilled Unat and pfs registers
+ //
+ mov r2 = ar.unat // save Unat register after spill
+ mov ar.rsc = r0
+ ;;
+ st8 [r32] = r2, J_PFS-J_NATS // save unat for spilled regs
+ mov r17 = ar.rnat
+ ;;
+ st8 [r32] = r15, J_RNAT-J_PFS // save pfs
+ mov ar.rsc = r16
+ //
+ // save floating registers
+ //
+ stf.spill [r11] = f2, J_F4-J_F2
+ stf.spill [r10] = f3, J_F5-J_F3
+ ;;
+ stf.spill [r11] = f4, J_F16-J_F4
+ stf.spill [r10] = f5, J_F17-J_F5
+ ;;
+ stf.spill [r11] = f16, J_F18-J_F16
+ stf.spill [r10] = f17, J_F19-J_F17
+ ;;
+ stf.spill [r11] = f18, J_F20-J_F18
+ stf.spill [r10] = f19, J_F21-J_F19
+ ;;
+ stf.spill [r11] = f20, J_F22-J_F20
+ stf.spill [r10] = f21, J_F23-J_F21
+ ;;
+ stf.spill [r11] = f22, J_F24-J_F22
+ stf.spill [r10] = f23, J_F25-J_F23
+ ;;
+ stf.spill [r11] = f24, J_F26-J_F24
+ stf.spill [r10] = f25, J_F27-J_F25
+ ;;
+ stf.spill [r11] = f26, J_F28-J_F26
+ stf.spill [r10] = f27, J_F29-J_F27
+ ;;
+ stf.spill [r11] = f28, J_F30-J_F28
+ stf.spill [r10] = f29, J_F31-J_F29
+ ;;
+ stf.spill [r11] = f30, J_FPSR-J_F30
+ stf.spill [r10] = f31, J_B0-J_F31 // size of f31 + fpsr
+ ;;
+ st8 [r32] = r17
+ //
+ // save FPSR register & branch registers
+ //
+ mov r2 = ar.fpsr // save fpsr register
+ mov r3 = b0
+ ;;
+ st8 [r11] = r2, J_B1-J_FPSR
+ st8 [r10] = r3, J_B2-J_B0
+ mov r2 = b1
+ mov r3 = b2
+ ;;
+ st8 [r11] = r2, J_B3-J_B1
+ st8 [r10] = r3, J_B4-J_B2
+ mov r2 = b3
+ mov r3 = b4
+ ;;
+ st8 [r11] = r2, J_B5-J_B3
+ st8 [r10] = r3
+ mov r2 = b5
+ ;;
+ st8 [r11] = r2
+ ;;
+ //
+ // return
+ //
+ mov r8 = r0 // return 0 from setjmp
+ mov ar.unat = r14 // restore unat
+ br.ret.sptk b0
+
+END(_setjmp)
+
+
+//
+// void _longjmp(struct jmp_buffer *, int val)
+//
+// Perform a non-local goto.
+//
+// Description:
+//
+// LongJump initializes the register set to the values saved by a
+// previous 'SetJump' and jumps to the return location saved by that
+// 'SetJump'. This has the effect of unwinding the stack and returning
+// for a second time to the 'SetJump'.
+//
+
+ WEAK_ALIAS(_longjmp,___longjmp)
+ENTRY(___longjmp, 2)
+ mov r14 = ar.rsc // get user RSC conf
+ mov r8 = r33 // return value
+ add r10 = J_PFS, r32 // get address of pfs
+ ;;
+ mov ar.rsc = r0
+ add r11 = J_NATS, r32
+ add r17 = J_RNAT, r32
+ ;;
+ ld8 r15 = [r10], J_BSP-J_PFS // get pfs
+ ld8 r2 = [r11], J_LC-J_NATS // get unat for spilled regs
+ mov r31 = r32
+ ;;
+ loadrs
+ mov ar.unat = r2
+ cmp.eq p6,p0=0,r8 // Return value 0?
+ ;;
+ ld8 r16 = [r10], J_PREDS-J_BSP // get backing store pointer
+ ld8 r17 = [r17] // ar.rnat
+ mov ar.pfs = r15
+ ;;
+ mov ar.bspstore = r16
+(p6) add r8 = 1, r0
+ ;;
+ mov ar.rnat = r17
+ mov ar.rsc = r14 // restore RSC conf
+
+ ld8 r3 = [r11], J_R4-J_LC // get lc register
+ ld8 r2 = [r10], J_R5-J_PREDS // get predicates
+ ;;
+ mov pr = r2, -1
+ mov ar.lc = r3
+ //
+ // restore preserved general registers & NaT's
+ //
+ ld8.fill r4 = [r11], J_R6-J_R4
+ ;;
+ ld8.fill r5 = [r10], J_R7-J_R5
+ ld8.fill r6 = [r11], J_SP-J_R6
+ ;;
+ ld8.fill r7 = [r10], J_F2-J_R7
+ ld8.fill sp = [r11], J_F3-J_SP
+ ;;
+ //
+ // restore floating registers
+ //
+ ldf.fill f2 = [r10], J_F4-J_F2
+ ldf.fill f3 = [r11], J_F5-J_F3
+ ;;
+ ldf.fill f4 = [r10], J_F16-J_F4
+ ldf.fill f5 = [r11], J_F17-J_F5
+ ;;
+ ldf.fill f16 = [r10], J_F18-J_F16
+ ldf.fill f17 = [r11], J_F19-J_F17
+ ;;
+ ldf.fill f18 = [r10], J_F20-J_F18
+ ldf.fill f19 = [r11], J_F21-J_F19
+ ;;
+ ldf.fill f20 = [r10], J_F22-J_F20
+ ldf.fill f21 = [r11], J_F23-J_F21
+ ;;
+ ldf.fill f22 = [r10], J_F24-J_F22
+ ldf.fill f23 = [r11], J_F25-J_F23
+ ;;
+ ldf.fill f24 = [r10], J_F26-J_F24
+ ldf.fill f25 = [r11], J_F27-J_F25
+ ;;
+ ldf.fill f26 = [r10], J_F28-J_F26
+ ldf.fill f27 = [r11], J_F29-J_F27
+ ;;
+ ldf.fill f28 = [r10], J_F30-J_F28
+ ldf.fill f29 = [r11], J_F31-J_F29
+ ;;
+ ldf.fill f30 = [r10], J_FPSR-J_F30
+ ldf.fill f31 = [r11], J_B0-J_F31 ;;
+
+ //
+ // restore branch registers and fpsr
+ //
+ ld8 r16 = [r10], J_B1-J_FPSR // get fpsr
+ ld8 r17 = [r11], J_B2-J_B0 // get return pointer
+ ;;
+ mov ar.fpsr = r16
+ mov b0 = r17
+ ld8 r2 = [r10], J_B3-J_B1
+ ld8 r3 = [r11], J_B4-J_B2
+ ;;
+ mov b1 = r2
+ mov b2 = r3
+ ld8 r2 = [r10], J_B5-J_B3
+ ld8 r3 = [r11]
+ ;;
+ mov b3 = r2
+ mov b4 = r3
+ ld8 r2 = [r10]
+ ld8 r21 = [r31] // get user unat
+ ;;
+ mov b5 = r2
+ mov ar.unat = r21
+
+ //
+ // invalidate ALAT
+ //
+ invala ;;
+
+ br.ret.sptk b0
+
+END(___longjmp)
diff --git a/lib/libc/ia64/gen/fabs.S b/lib/libc/ia64/gen/fabs.S
new file mode 100644
index 0000000..036d492
--- /dev/null
+++ b/lib/libc/ia64/gen/fabs.S
@@ -0,0 +1,33 @@
+/*-
+ * Copyright (c) 2000 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 <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+ENTRY(fabs, 1)
+ fabs fret0=farg0
+ br.ret.sptk.few rp
+END(fabs)
diff --git a/lib/libc/ia64/gen/flt_rounds.c b/lib/libc/ia64/gen/flt_rounds.c
new file mode 100644
index 0000000..d650965
--- /dev/null
+++ b/lib/libc/ia64/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("mov %0=ar.fpsr" : "=r" (x));
+ return (map[(x >> 10) & 0x03]);
+}
diff --git a/lib/libc/ia64/gen/fpgetmask.c b/lib/libc/ia64/gen/fpgetmask.c
new file mode 100644
index 0000000..ac166e2
--- /dev/null
+++ b/lib/libc/ia64/gen/fpgetmask.c
@@ -0,0 +1,40 @@
+/*-
+ * Copyright (c) 2001 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$");
+
+#include <sys/types.h>
+#include <ieeefp.h>
+
+fp_except_t
+fpgetmask(void)
+{
+ u_int64_t fpsr;
+
+ __asm __volatile("mov %0=ar.fpsr" : "=r" (fpsr));
+ return (~fpsr & 0x3d);
+}
diff --git a/lib/libc/ia64/gen/fpgetround.c b/lib/libc/ia64/gen/fpgetround.c
new file mode 100644
index 0000000..6f5e8cc
--- /dev/null
+++ b/lib/libc/ia64/gen/fpgetround.c
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <ieeefp.h>
+
+fp_rnd_t
+fpgetround(void)
+{
+ uint64_t fpsr;
+
+ __asm __volatile("mov %0=ar.fpsr" : "=r"(fpsr));
+ return ((fp_rnd_t)((fpsr >> 10) & 3));
+}
diff --git a/lib/libc/ia64/gen/fpsetmask.c b/lib/libc/ia64/gen/fpsetmask.c
new file mode 100644
index 0000000..d959dc6
--- /dev/null
+++ b/lib/libc/ia64/gen/fpsetmask.c
@@ -0,0 +1,44 @@
+/*-
+ * Copyright (c) 2001 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$");
+
+#include <sys/types.h>
+#include <ieeefp.h>
+
+fp_except_t
+fpsetmask(fp_except_t mask)
+{
+ u_int64_t fpsr;
+ u_int64_t oldmask;
+
+ __asm __volatile("mov %0=ar.fpsr" : "=r" (fpsr));
+ oldmask = ~fpsr & 0x3d;
+ fpsr = (fpsr & ~0x3d) | (~mask & 0x3d);
+ __asm __volatile("mov ar.fpsr=%0" :: "r" (fpsr));
+ return (oldmask);
+}
diff --git a/lib/libc/ia64/gen/fpsetround.c b/lib/libc/ia64/gen/fpsetround.c
new file mode 100644
index 0000000..db2eef1
--- /dev/null
+++ b/lib/libc/ia64/gen/fpsetround.c
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <ieeefp.h>
+
+fp_rnd_t
+fpsetround(fp_rnd_t rnd)
+{
+ uint64_t fpsr;
+ fp_rnd_t prev;
+
+ __asm __volatile("mov %0=ar.fpsr" : "=r"(fpsr));
+ prev = (fp_rnd_t)((fpsr >> 10) & 3);
+ fpsr = (fpsr & ~0xC00ULL) | ((unsigned int)rnd << 10);
+ __asm __volatile("mov ar.fpsr=%0" :: "r"(fpsr));
+ return (prev);
+}
diff --git a/lib/libc/ia64/gen/infinity.c b/lib/libc/ia64/gen/infinity.c
new file mode 100644
index 0000000..1ae92a8
--- /dev/null
+++ b/lib/libc/ia64/gen/infinity.c
@@ -0,0 +1,48 @@
+/* $NetBSD: infinity.c,v 1.1 1995/02/10 17:50:23 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/endian.h>
+#include <math.h>
+
+/* bytes for +Infinity on an ia64 (IEEE double format) */
+#if _BYTE_ORDER == _LITTLE_ENDIAN
+const union __infinity_un __infinity = { { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f } };
+#else /* _BIG_ENDIAN */
+const union __infinity_un __infinity = { { 0x7f, 0xf0, 0, 0, 0, 0, 0, 0 } };
+#endif
+
+/* bytes for NaN */
+#if _BYTE_ORDER == _LITTLE_ENDIAN
+const union __nan_un __nan = { { 0, 0, 0xc0, 0xff } };
+#else /* _BIG_ENDIAN */
+const union __nan_un __nan = { { 0xff, 0xc0, 0, 0 } };
+#endif
diff --git a/lib/libc/ia64/gen/makecontext.c b/lib/libc/ia64/gen/makecontext.c
new file mode 100644
index 0000000..bee47f1
--- /dev/null
+++ b/lib/libc/ia64/gen/makecontext.c
@@ -0,0 +1,123 @@
+/*
+ * 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 <machine/fpu.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct fdesc {
+ uint64_t ip;
+ uint64_t gp;
+};
+
+typedef void (*func_t)(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t,
+ uint64_t, uint64_t, uint64_t);
+
+static __inline uint64_t *
+spill(uint64_t *bsp, uint64_t arg)
+{
+ *bsp++ = arg;
+ if (((intptr_t)bsp & 0x1ff) == 0x1f8)
+ *bsp++ = 0;
+ return (bsp);
+}
+
+static void
+ctx_wrapper(ucontext_t *ucp, func_t func, uint64_t *args)
+{
+
+ (*func)(args[0], args[1], args[2], args[3], args[4], args[5], args[6],
+ args[7]);
+ if (ucp->uc_link == NULL)
+ exit(0);
+ setcontext((const ucontext_t *)ucp->uc_link);
+ /* should never get here */
+ abort();
+ /* NOTREACHED */
+}
+
+__weak_reference(__makecontext, makecontext);
+
+void
+__makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...)
+{
+ uint64_t *args, *bsp;
+ va_list ap;
+ int i;
+
+ /*
+ * Drop the ball completely if something's not right. We only
+ * support general registers as arguments and not more than 8
+ * of them. Things get hairy if we need to support FP registers
+ * (alignment issues) or more than 8 arguments (stack based).
+ */
+ if (argc < 0 || argc > 8 || ucp == NULL ||
+ ucp->uc_stack.ss_sp == NULL || (ucp->uc_stack.ss_size & 15) ||
+ ((intptr_t)ucp->uc_stack.ss_sp & 15) ||
+ ucp->uc_stack.ss_size < MINSIGSTKSZ)
+ abort();
+
+ /*
+ * Copy the arguments of function 'func' onto the (memory) stack.
+ * Always take up space for 8 arguments.
+ */
+ va_start(ap, argc);
+ args = (uint64_t*)(ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size) - 8;
+ i = 0;
+ while (i < argc)
+ args[i++] = va_arg(ap, uint64_t);
+ while (i < 8)
+ args[i++] = 0;
+ va_end(ap);
+
+ /*
+ * Push (spill) the arguments of the context wrapper onto the register
+ * stack. They get loaded by the RSE on a context switch.
+ */
+ bsp = (uint64_t*)ucp->uc_stack.ss_sp;
+ bsp = spill(bsp, (intptr_t)ucp);
+ bsp = spill(bsp, (intptr_t)func);
+ bsp = spill(bsp, (intptr_t)args);
+
+ /*
+ * Setup the MD portion of the context.
+ */
+ memset(&ucp->uc_mcontext, 0, sizeof(ucp->uc_mcontext));
+ ucp->uc_mcontext.mc_special.sp = (intptr_t)args - 16;
+ ucp->uc_mcontext.mc_special.bspstore = (intptr_t)bsp;
+ ucp->uc_mcontext.mc_special.pfs = (3 << 7) | 3;
+ ucp->uc_mcontext.mc_special.rsc = 0xf;
+ ucp->uc_mcontext.mc_special.rp = ((struct fdesc*)ctx_wrapper)->ip;
+ ucp->uc_mcontext.mc_special.gp = ((struct fdesc*)ctx_wrapper)->gp;
+ ucp->uc_mcontext.mc_special.fpsr = IA64_FPSR_DEFAULT;
+}
diff --git a/lib/libc/ia64/gen/modf.c b/lib/libc/ia64/gen/modf.c
new file mode 100644
index 0000000..def3aad
--- /dev/null
+++ b/lib/libc/ia64/gen/modf.c
@@ -0,0 +1,106 @@
+/* $NetBSD: modf.c,v 1.1 1995/02/10 17:50:25 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <machine/ieee.h>
+#include <math.h>
+
+/*
+ * double modf(double val, double *iptr)
+ * returns: f and i such that |f| < 1.0, (f + i) = val, and
+ * sign(f) == sign(i) == sign(val).
+ *
+ * Beware signedness when doing subtraction, and also operand size!
+ */
+double
+modf(val, iptr)
+ double val, *iptr;
+{
+ union doub {
+ double v;
+ struct ieee_double s;
+ } u, v;
+ u_int64_t frac;
+
+ /*
+ * If input is Inf or NaN, return it and leave i alone.
+ */
+ u.v = val;
+ if (u.s.dbl_exp == DBL_EXP_INFNAN)
+ return (u.v);
+
+ /*
+ * If input can't have a fractional part, return
+ * (appropriately signed) zero, and make i be the input.
+ */
+ if ((int)u.s.dbl_exp - DBL_EXP_BIAS > DBL_FRACBITS - 1) {
+ *iptr = u.v;
+ v.v = 0.0;
+ v.s.dbl_sign = u.s.dbl_sign;
+ return (v.v);
+ }
+
+ /*
+ * If |input| < 1.0, return it, and set i to the appropriately
+ * signed zero.
+ */
+ if (u.s.dbl_exp < DBL_EXP_BIAS) {
+ v.v = 0.0;
+ v.s.dbl_sign = u.s.dbl_sign;
+ *iptr = v.v;
+ return (u.v);
+ }
+
+ /*
+ * There can be a fractional part of the input.
+ * If you look at the math involved for a few seconds, it's
+ * plain to see that the integral part is the input, with the
+ * low (DBL_FRACBITS - (exponent - DBL_EXP_BIAS)) bits zeroed,
+ * the the fractional part is the part with the rest of the
+ * bits zeroed. Just zeroing the high bits to get the
+ * fractional part would yield a fraction in need of
+ * normalization. Therefore, we take the easy way out, and
+ * just use subtraction to get the fractional part.
+ */
+ v.v = u.v;
+ /* Zero the low bits of the fraction, the sleazy way. */
+ frac = ((u_int64_t)v.s.dbl_frach << 32) + v.s.dbl_fracl;
+ frac >>= DBL_FRACBITS - (u.s.dbl_exp - DBL_EXP_BIAS);
+ frac <<= DBL_FRACBITS - (u.s.dbl_exp - DBL_EXP_BIAS);
+ v.s.dbl_fracl = frac & 0xffffffff;
+ v.s.dbl_frach = frac >> 32;
+ *iptr = v.v;
+
+ u.v -= v.v;
+ u.s.dbl_sign = v.s.dbl_sign;
+ return (u.v);
+}
diff --git a/lib/libc/ia64/gen/setjmp.S b/lib/libc/ia64/gen/setjmp.S
new file mode 100644
index 0000000..a2b56d6
--- /dev/null
+++ b/lib/libc/ia64/gen/setjmp.S
@@ -0,0 +1,82 @@
+/* $NetBSD: setjmp.S,v 1.3 1997/12/05 02:06:27 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#define LOCORE
+#include <machine/setjmp.h>
+
+/*
+ * 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 the previous signal state.
+ */
+
+ENTRY(setjmp, 1)
+ alloc loc0=ar.pfs,1,2,3,0
+ mov loc1=rp
+ ;;
+ mov out0=1 // how = SIG_BLOCK
+ mov out1=0 // set = NULL
+ add out2=J_SIGSET,in0 // oset = &jb[J_SIGSET]
+ br.call.sptk.few rp=__sys_sigprocmask
+ ;;
+ mov rp=loc1
+ mov r14=loc0
+ ;;
+ alloc r15=ar.pfs,1,0,0,0 // drop register frame
+ ;;
+ mov ar.pfs=r14 // restore ar.pfs
+ br.sptk.many _setjmp // finish saving state
+END(setjmp)
+
+ WEAK_ALIAS(longjmp,__longjmp)
+ENTRY(__longjmp, 2)
+ alloc loc0=ar.pfs,2,2,3,0
+ mov loc1=rp
+ ;;
+ mov out0=3 // how = SIG_SETMASK
+ add out1=J_SIGSET,in0 // set = &jb[J_SIGSET]
+ mov out2=0 // oset = NULL
+ br.call.sptk.few rp=__sys_sigprocmask
+ ;;
+ mov rp=loc1
+ mov r14=loc0
+ ;;
+ alloc r15=ar.pfs,2,0,0,0 // drop register frame
+ ;;
+ mov ar.pfs=r14 // restore ar.pfs
+ br.sptk.many _longjmp // finish restoring state
+END(__longjmp)
diff --git a/lib/libc/ia64/gen/signalcontext.c b/lib/libc/ia64/gen/signalcontext.c
new file mode 100644
index 0000000..b47daf3
--- /dev/null
+++ b/lib/libc/ia64/gen/signalcontext.c
@@ -0,0 +1,123 @@
+/*
+ * 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 <machine/fpu.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+
+struct fdesc {
+ uint64_t ip;
+ uint64_t gp;
+};
+
+typedef void (*handler_t)(uint64_t, uint64_t, uint64_t);
+
+static __inline uint64_t *
+spill(uint64_t *bsp, uint64_t arg)
+{
+ *bsp++ = arg;
+ if (((intptr_t)bsp & 0x1ff) == 0x1f8)
+ *bsp++ = 0;
+ return (bsp);
+}
+
+static void
+ctx_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 */
+}
+
+__weak_reference(__signalcontext, signalcontext);
+
+int
+__signalcontext(ucontext_t *ucp, int sig, __sighandler_t *func)
+{
+ uint64_t *args, *bsp;
+ 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 (memory) stack. We only need 3 arguments, but
+ * we create room for 4 so that we are 16-byte aligned.
+ */
+ sp = (ucp->uc_mcontext.mc_special.sp - 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 -= 4 * sizeof(uint64_t);
+ args = (uint64_t*)sp;
+ args[0] = sig;
+ args[1] = (intptr_t)sig_si;
+ args[2] = (intptr_t)sig_uc;
+
+ /*
+ * Push (spill) the arguments of the context wrapper onto the register
+ * stack. They get loaded by the RSE on a context switch.
+ */
+ bsp = (uint64_t*)ucp->uc_mcontext.mc_special.bspstore;
+ bsp = spill(bsp, (intptr_t)ucp);
+ bsp = spill(bsp, (intptr_t)func);
+ bsp = spill(bsp, (intptr_t)args);
+
+ /*
+ * Setup the ucontext of the signal handler.
+ */
+ memset(&ucp->uc_mcontext, 0, sizeof(ucp->uc_mcontext));
+ ucp->uc_link = sig_uc;
+ sigdelset(&ucp->uc_sigmask, sig);
+ ucp->uc_mcontext.mc_special.sp = (intptr_t)args - 16;
+ ucp->uc_mcontext.mc_special.bspstore = (intptr_t)bsp;
+ ucp->uc_mcontext.mc_special.pfs = (3 << 7) | 3;
+ ucp->uc_mcontext.mc_special.rsc = 0xf;
+ ucp->uc_mcontext.mc_special.rp = ((struct fdesc*)ctx_wrapper)->ip;
+ ucp->uc_mcontext.mc_special.gp = ((struct fdesc*)ctx_wrapper)->gp;
+ ucp->uc_mcontext.mc_special.fpsr = IA64_FPSR_DEFAULT;
+ return (0);
+}
diff --git a/lib/libc/ia64/gen/sigsetjmp.S b/lib/libc/ia64/gen/sigsetjmp.S
new file mode 100644
index 0000000..9f02a26
--- /dev/null
+++ b/lib/libc/ia64/gen/sigsetjmp.S
@@ -0,0 +1,66 @@
+/* $NetBSD: sigsetjmp.S,v 1.2 1996/10/17 03:08:07 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#define LOCORE
+#include <machine/setjmp.h>
+
+/*
+ * C library -- sigsetjmp, siglongjmp
+ *
+ * siglongjmp(a,v)
+ * will generate a "return(v)" from
+ * the last call to
+ * sigsetjmp(a, mask)
+ * by restoring registers from the stack.
+ * If `mask' is non-zero, the previous signal
+ * state will be restored.
+ */
+
+ENTRY(sigsetjmp, 2)
+ add r14=J_SIGMASK,in0 // place to save mask
+ cmp.ne p6,p7=0,in1 // save signal state?
+ ;;
+ st8 [r14]=in1 // save mask value
+(p6) br.cond.dptk.many setjmp
+(p7) br.cond.dpnt.many _setjmp
+END(sigsetjmp)
+
+ WEAK_ALIAS(siglongjmp,__siglongjmp)
+ENTRY(__siglongjmp, 2)
+ add r14=J_SIGMASK,in0 // address of mask value
+ ;;
+ ld8 r14=[r14]
+ ;;
+ cmp.ne p6,p7=0,r14 // did we save signals?
+(p6) br.cond.dptk.many longjmp
+(p7) br.cond.dpnt.many _longjmp
+END(__siglongjmp)
diff --git a/lib/libc/ia64/gen/unwind.c b/lib/libc/ia64/gen/unwind.c
new file mode 100644
index 0000000..7afd0ef
--- /dev/null
+++ b/lib/libc/ia64/gen/unwind.c
@@ -0,0 +1,129 @@
+/*
+ * 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$
+ */
+
+#include <sys/types.h>
+
+#include <assert.h>
+#include <dlfcn.h>
+#include <stdlib.h>
+
+#include <machine/elf.h>
+
+#ifndef PT_IA_64_UNWIND
+#define PT_IA_64_UNWIND 0x70000001
+#endif
+
+#define SANITY 0
+
+struct ia64_unwind_entry
+{
+ Elf64_Addr start;
+ Elf64_Addr end;
+ Elf64_Addr descr;
+};
+
+struct ia64_unwind_entry *
+_Unwind_FindTableEntry(const void *pc, unsigned long *pseg, unsigned long *pgp)
+{
+ Dl_info info;
+ Elf_Dyn *dyn;
+ Elf_Ehdr *ehdr;
+ Elf_Phdr *phdr;
+ char *p, *p_top;
+ struct ia64_unwind_entry *unw, *res;
+ register unsigned long gp __asm__("gp"); /* XXX assumes gcc */
+ unsigned long reloc, vaddr;
+ size_t l, m, r;
+
+ if (!dladdr(pc, &info))
+ return NULL;
+
+ ehdr = (Elf_Ehdr*)info.dli_fbase;
+
+#if SANITY
+ assert(IS_ELF(*ehdr));
+ assert(ehdr->e_ident[EI_CLASS] == ELFCLASS64);
+ assert(ehdr->e_ident[EI_DATA] == ELFDATA2LSB);
+ assert(ehdr->e_machine == EM_IA_64);
+#endif
+
+ reloc = (ehdr->e_type == ET_DYN) ? (uintptr_t)info.dli_fbase : 0;
+ *pgp = gp;
+ *pseg = 0UL;
+ res = NULL;
+
+ p = (char*)info.dli_fbase + ehdr->e_phoff;
+ p_top = p + ehdr->e_phnum * ehdr->e_phentsize;
+ while (p < p_top) {
+ phdr = (Elf_Phdr*)p;
+ vaddr = phdr->p_vaddr + reloc;
+
+ switch (phdr->p_type) {
+ case PT_DYNAMIC:
+ dyn = (Elf_Dyn*)vaddr;
+ while (dyn->d_tag != DT_NULL) {
+ if (dyn->d_tag == DT_PLTGOT) {
+ *pgp = dyn->d_un.d_ptr + reloc;
+ break;
+ }
+ dyn++;
+ }
+ break;
+ case PT_LOAD:
+ if (pc >= (void*)vaddr &&
+ pc < (void*)(vaddr + phdr->p_memsz))
+ *pseg = vaddr;
+ break;
+ case PT_IA_64_UNWIND:
+#if SANITY
+ assert(*pseg != 0UL);
+ assert(res == NULL);
+#endif
+ unw = (struct ia64_unwind_entry*)vaddr;
+ l = 0;
+ r = phdr->p_memsz / sizeof(struct ia64_unwind_entry);
+ while (l < r) {
+ m = (l + r) >> 1;
+ res = unw + m;
+ if (pc < (void*)(res->start + *pseg))
+ r = m;
+ else if (pc >= (void*)(res->end + *pseg))
+ l = m + 1;
+ else
+ break; /* found */
+ }
+ if (l >= r)
+ res = NULL;
+ break;
+ }
+
+ p += ehdr->e_phentsize;
+ }
+
+ return res;
+}
diff --git a/lib/libc/ia64/net/Makefile.inc b/lib/libc/ia64/net/Makefile.inc
new file mode 100644
index 0000000..b717813
--- /dev/null
+++ b/lib/libc/ia64/net/Makefile.inc
@@ -0,0 +1,3 @@
+# $FreeBSD$
+
+SRCS+= htonl.S htons.S ntohl.S ntohs.S
diff --git a/lib/libc/ia64/net/byte_swap_2.S b/lib/libc/ia64/net/byte_swap_2.S
new file mode 100644
index 0000000..34498b7
--- /dev/null
+++ b/lib/libc/ia64/net/byte_swap_2.S
@@ -0,0 +1,48 @@
+/* $NetBSD: byte_swap_2.S,v 1.2 1996/10/17 03:08:08 cgd Exp $ */
+
+/*
+ * Copyright (c) 1996 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#if !defined(ALIAS) || !defined(NAME)
+#error ALIAS or NAME not defined
+#endif
+
+/*
+ * Byte-swap a 2-byte quantity. (Convert 0x0123 to 0x2301.)
+ *
+ * Argument is an unsigned 2-byte integer (u_int16_t).
+ */
+WEAK_ALIAS(ALIAS, NAME)
+ENTRY(NAME, 1)
+ mux1 r16=in0,@rev
+ ;;
+ extr.u r8=r16,48,16
+ br.ret.sptk.few rp
+END(NAME)
diff --git a/lib/libc/ia64/net/byte_swap_4.S b/lib/libc/ia64/net/byte_swap_4.S
new file mode 100644
index 0000000..c5daa81
--- /dev/null
+++ b/lib/libc/ia64/net/byte_swap_4.S
@@ -0,0 +1,48 @@
+/* $NetBSD: byte_swap_4.S,v 1.2 1996/10/17 03:08:09 cgd Exp $ */
+
+/*
+ * Copyright (c) 1996 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#if !defined(ALIAS) || !defined(NAME)
+#error ALIAS or NAME not defined
+#endif
+
+/*
+ * Byte-swap a 4-byte quantity. (Convert 0x01234567 to 0x67452301.)
+ *
+ * Argument is an unsigned 4-byte integer (u_int32_t).
+ */
+WEAK_ALIAS(ALIAS, NAME)
+ENTRY(NAME, 1)
+ mux1 r16=in0,@rev
+ ;;
+ extr.u r8=r16,32,32
+ br.ret.sptk.few rp
+END(NAME)
diff --git a/lib/libc/ia64/net/htonl.S b/lib/libc/ia64/net/htonl.S
new file mode 100644
index 0000000..05c906c
--- /dev/null
+++ b/lib/libc/ia64/net/htonl.S
@@ -0,0 +1,36 @@
+/* $NetBSD: htonl.S,v 1.1 1996/04/17 22:36:52 cgd Exp $ */
+
+/*
+ * Copyright (c) 1996 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#define ALIAS htonl
+#define NAME __htonl
+
+#include "byte_swap_4.S"
diff --git a/lib/libc/ia64/net/htons.S b/lib/libc/ia64/net/htons.S
new file mode 100644
index 0000000..4bd3a8b
--- /dev/null
+++ b/lib/libc/ia64/net/htons.S
@@ -0,0 +1,36 @@
+/* $NetBSD: htons.S,v 1.1 1996/04/17 22:36:54 cgd Exp $ */
+
+/*
+ * Copyright (c) 1996 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#define ALIAS htons
+#define NAME __htons
+
+#include "byte_swap_2.S"
diff --git a/lib/libc/ia64/net/ntohl.S b/lib/libc/ia64/net/ntohl.S
new file mode 100644
index 0000000..a08a162
--- /dev/null
+++ b/lib/libc/ia64/net/ntohl.S
@@ -0,0 +1,36 @@
+/* $NetBSD: ntohl.S,v 1.1 1996/04/17 22:36:57 cgd Exp $ */
+
+/*
+ * Copyright (c) 1996 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#define ALIAS ntohl
+#define NAME __ntohl
+
+#include "byte_swap_4.S"
diff --git a/lib/libc/ia64/net/ntohs.S b/lib/libc/ia64/net/ntohs.S
new file mode 100644
index 0000000..79e6e0c
--- /dev/null
+++ b/lib/libc/ia64/net/ntohs.S
@@ -0,0 +1,36 @@
+/* $NetBSD: ntohs.S,v 1.1 1996/04/17 22:37:02 cgd Exp $ */
+
+/*
+ * Copyright (c) 1996 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#define ALIAS ntohs
+#define NAME __ntohs
+
+#include "byte_swap_2.S"
diff --git a/lib/libc/ia64/stdlib/Makefile.inc b/lib/libc/ia64/stdlib/Makefile.inc
new file mode 100644
index 0000000..dda8c76
--- /dev/null
+++ b/lib/libc/ia64/stdlib/Makefile.inc
@@ -0,0 +1,3 @@
+# $FreeBSD$
+
+MDSRCS+= abs.c div.c labs.c ldiv.c
diff --git a/lib/libc/ia64/string/Makefile.inc b/lib/libc/ia64/string/Makefile.inc
new file mode 100644
index 0000000..7bbcc8d
--- /dev/null
+++ b/lib/libc/ia64/string/Makefile.inc
@@ -0,0 +1,3 @@
+# $FreeBSD$
+
+MDSRCS+= bcopy.S bzero.S ffs.S memcpy.S memmove.S
diff --git a/lib/libc/ia64/string/bcopy.S b/lib/libc/ia64/string/bcopy.S
new file mode 100644
index 0000000..34aac19
--- /dev/null
+++ b/lib/libc/ia64/string/bcopy.S
@@ -0,0 +1,95 @@
+/*-
+ * Copyright (c) 2000 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 <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Not the fastest bcopy in the world.
+ */
+ENTRY(bcopy, 3)
+
+ cmp.le p6,p0=in2,r0 // bail if len <= 0
+(p6) br.ret.spnt.few rp
+
+ sub r14=in1,in0 ;; // check for overlap
+ cmp.ltu p6,p0=r14,in2 // dst-src < len
+(p6) br.cond.spnt.few 5f
+
+ extr.u r14=in0,0,3 // src & 7
+ extr.u r15=in1,0,3 ;; // dst & 7
+ cmp.eq p6,p0=r14,r15 // different alignment?
+(p6) br.cond.spnt.few 2f // branch if same alignment
+
+1: ld1 r14=[in0],1 ;; // copy bytewise
+ st1 [in1]=r14,1
+ add in2=-1,in2 ;; // len--
+ cmp.ne p6,p0=r0,in2
+(p6) br.cond.dptk.few 1b // loop
+ br.ret.sptk.few rp // done
+
+2: cmp.eq p6,p0=r14,r0 // aligned?
+(p6) br.cond.sptk.few 4f
+
+3: ld1 r14=[in0],1 ;; // copy bytewise
+ st1 [in1]=r14,1
+ extr.u r15=in0,0,3 // src & 7
+ add in2=-1,in2 ;; // len--
+ cmp.eq p6,p0=r0,in2 // done?
+ cmp.eq p7,p0=r0,r15 ;; // aligned now?
+(p6) br.ret.spnt.few rp // return if done
+(p7) br.cond.spnt.few 4f // go to main copy
+ br.cond.sptk.few 3b // more bytes to copy
+
+ // At this point, in2 is non-zero
+
+4: mov r14=8 ;;
+ cmp.ltu p6,p0=in2,r14 ;; // len < 8?
+(p6) br.cond.spnt.few 1b // byte copy the end
+ ld8 r15=[in0],8 ;; // copy word
+ st8 [in1]=r15,8
+ add in2=-8,in2 ;; // len -= 8
+ cmp.ne p6,p0=r0,in2 // done?
+(p6) br.cond.spnt.few 4b // again
+
+ br.ret.sptk.few rp // return
+
+ // Don't bother optimising overlap case
+
+5: add in0=in0,in2
+ add in1=in1,in2 ;;
+ add in0=-1,in0
+ add in1=-1,in1 ;;
+
+6: ld1 r14=[in0],-1 ;;
+ st1 [in1]=r14,-1
+ add in2=-1,in2 ;;
+ cmp.ne p6,p0=r0,in2
+(p6) br.cond.spnt.few 6b
+
+ br.ret.sptk.few rp
+
+END(bcopy)
diff --git a/lib/libc/ia64/string/bzero.S b/lib/libc/ia64/string/bzero.S
new file mode 100644
index 0000000..0963c36
--- /dev/null
+++ b/lib/libc/ia64/string/bzero.S
@@ -0,0 +1,81 @@
+/*-
+ * Copyright (c) 2000 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 <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+ENTRY(bzero, 2)
+
+ cmp.le p6,p0=in1,r0 // bail if len <= 0
+(p6) br.ret.spnt.few rp
+ ;;
+ mov r14=ar.lc // save ar.lc
+
+ cmp.ltu p6,p0=17,in1 // check for small
+(p6) br.dptk.few 3f
+
+1: add r15=-1,in1 ;;
+ mov ar.lc=r15 ;;
+2: st1 [in0]=r0,1 // zero one byte
+ br.cloop.sptk.few 2b // loop
+
+ ;;
+ mov ar.lc=r14 // done
+ br.ret.sptk.few rp
+
+ // Zero up to 8byte alignment
+
+3: tbit.nz p6,p0=in0,0 ;;
+(p6) st1 [in0]=r0,1
+(p6) add in1=-1,in1 ;;
+
+ tbit.nz p6,p0=in0,1 ;;
+(p6) st2 [in0]=r0,2
+(p6) add in1=-2,in1 ;;
+
+ tbit.nz p6,p0=in0,2 ;;
+(p6) st4 [in0]=r0,4
+(p6) add in1=-4,in1
+
+ ;;
+ shr.u r15=in1,3 // word count
+ extr.u in1=in1,0,3 ;; // trailing bytes
+ cmp.eq p6,p0=r15,r0 // check for zero
+ cmp.ne p7,p0=in1,r0
+(p6) br.dpnt.few 1b // zero last bytes
+
+ add r15=-1,r15 ;;
+ mov ar.lc=r15 ;;
+4: st8 [in0]=r0,8
+ br.cloop.sptk.few 4b
+
+(p7) br.dpnt.few 1b // zero last bytes
+
+ ;;
+ mov ar.lc=r14 // done
+ br.ret.sptk.few rp
+
+END(bzero)
diff --git a/lib/libc/ia64/string/ffs.S b/lib/libc/ia64/string/ffs.S
new file mode 100644
index 0000000..d99d765
--- /dev/null
+++ b/lib/libc/ia64/string/ffs.S
@@ -0,0 +1,99 @@
+/* $NetBSD: ffs.S,v 1.3 1996/10/17 03:08:13 cgd Exp $ */
+
+/*
+ * Copyright (c) 1995 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 by Christopher G. Demetriou
+ * 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 <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+ENTRY(ffs, 1)
+ sxt4 r14=in0 ;;
+ cmp.eq p6,p0=r14,r0
+(p6) br.dpnt.few Lallzero
+
+ /*
+ * Initialize return value (ret0), and set up r15 so that it
+ * contains the mask with only the lowest bit set.
+ */
+ sub r15=r0,r14
+ mov ret0=1 ;;
+ and r15=r14,r15 ;;
+
+ extr.u r16=r15,0,8 ;;
+ cmp.ne p6,p0=r0,r16
+(p6) br.dptk.few Ldo8
+
+ /*
+ * If lower 16 bits empty, add 16 to result and use upper 16.
+ */
+ extr.u r16=r15,0,16 ;;
+ cmp.ne p6,p0=r0,r16
+(p6) br.dptk.few Ldo16
+ extr.u r15=r15,16,16
+ add ret0=16,ret0 ;;
+
+Ldo16:
+ /*
+ * If lower 8 bits empty, add 8 to result and use upper 8.
+ */
+ extr.u r16=r15,0,8 ;;
+ cmp.ne p6,p0=r0,r16
+(p6) br.dptk.few Ldo8
+ extr.u r15=r15,8,24
+ add ret0=8,ret0 ;;
+
+Ldo8:
+ and r16=0x0f,r15 /* lower 4 of 8 empty? */
+ and r17=0x33,r15 /* lower 2 of each 4 empty? */
+ and r18=0x55,r15 ;; /* lower 1 of each 2 empty? */
+ cmp.ne p6,p0=r16,r0
+ cmp.ne p7,p0=r17,r0
+ cmp.ne p8,p0=r18,r0
+
+ /* If lower 4 bits empty, add 4 to result. */
+(p6) br.dptk.few Ldo4
+ add ret0=4,ret0 ;;
+
+Ldo4: /* If lower 2 bits of each 4 empty, add 2 to result. */
+(p7) br.dptk.few Ldo2
+ add ret0=2,ret0 ;;
+
+Ldo2: /* If lower bit of each 2 empty, add 1 to result. */
+(p8) br.dptk.few Ldone
+ add ret0=1,ret0
+
+Ldone:
+ br.ret.sptk.few rp
+
+Lallzero:
+ mov ret0=0
+ br.ret.sptk.few rp
+END(ffs)
diff --git a/lib/libc/ia64/string/memcpy.S b/lib/libc/ia64/string/memcpy.S
new file mode 100644
index 0000000..d7557c1
--- /dev/null
+++ b/lib/libc/ia64/string/memcpy.S
@@ -0,0 +1,36 @@
+/*-
+ * Copyright (c) 2000 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 <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+ENTRY(memcpy,3)
+ mov r8 = in0
+ mov in0 = in1
+ ;;
+ mov in1 = r8
+ br.sptk.few bcopy
+END(memcpy)
diff --git a/lib/libc/ia64/string/memmove.S b/lib/libc/ia64/string/memmove.S
new file mode 100644
index 0000000..19fa8af
--- /dev/null
+++ b/lib/libc/ia64/string/memmove.S
@@ -0,0 +1,36 @@
+/*-
+ * Copyright (c) 2000 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 <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+ENTRY(memmove,3)
+ mov r8 = in0
+ mov in0 = in1
+ ;;
+ mov in1 = r8
+ br.sptk.few bcopy
+END(memmove)
diff --git a/lib/libc/ia64/sys/Makefile.inc b/lib/libc/ia64/sys/Makefile.inc
new file mode 100644
index 0000000..dacd2f9
--- /dev/null
+++ b/lib/libc/ia64/sys/Makefile.inc
@@ -0,0 +1,11 @@
+# $FreeBSD$
+
+MDASM+= Ovfork.S brk.S cerror.S exect.S fork.S getcontext.S pipe.S ptrace.S \
+ sbrk.S setlogin.S sigreturn.S swapcontext.S
+
+# Don't generate default code for these syscalls:
+NOASM= break.o exit.o ftruncate.o getdomainname.o getlogin.o \
+ lseek.o mmap.o openbsd_poll.o pread.o \
+ pwrite.o setdomainname.o sstk.o truncate.o uname.o vfork.o yield.o
+
+PSEUDO= _getlogin.o _exit.o
diff --git a/lib/libc/ia64/sys/Ovfork.S b/lib/libc/ia64/sys/Ovfork.S
new file mode 100644
index 0000000..6eb6958
--- /dev/null
+++ b/lib/libc/ia64/sys/Ovfork.S
@@ -0,0 +1,37 @@
+/*-
+ * Copyright (c) 2000 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 <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+SYSCALL(vfork)
+ cmp.ne p7,p0=ret1,r0 /* ret1!=0 for child */
+ ;;
+(p7) mov ret0=r0
+ br.ret.sptk.few rp
+END(__sys_vfork)
diff --git a/lib/libc/ia64/sys/brk.S b/lib/libc/ia64/sys/brk.S
new file mode 100644
index 0000000..fee1728
--- /dev/null
+++ b/lib/libc/ia64/sys/brk.S
@@ -0,0 +1,57 @@
+/* $NetBSD: brk.S,v 1.4 1996/10/17 03:08:15 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+ .globl _end
+IMPORT(curbrk, 8)
+
+ .data
+EXPORT(minbrk)
+ .quad _end
+
+ .text
+ENTRY(brk, 1)
+ add r14=@ltoff(minbrk),gp ;;
+ ld8 r14=[r14] ;;
+ ld8 r14=[r14] ;;
+ cmp.ltu p6,p0=r32,r14 ;;
+(p6) mov r32=r14 ;;
+ st8 [sp]=r32
+ CALLSYS_ERROR(break)
+ ld8 r15=[sp]
+ add r14=@ltoff(curbrk),gp ;;
+ ld8 r14=[r14] ;;
+ st8 [r14]=r15
+ mov ret0=0
+ br.ret.sptk.few rp
+END(brk)
diff --git a/lib/libc/ia64/sys/cerror.S b/lib/libc/ia64/sys/cerror.S
new file mode 100644
index 0000000..ca0b0c7
--- /dev/null
+++ b/lib/libc/ia64/sys/cerror.S
@@ -0,0 +1,46 @@
+/*-
+ * Copyright (c) 2000 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 <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+
+ENTRY(.cerror, 0)
+ alloc loc0=ar.pfs,0,3,1,0
+ ;;
+ mov loc1=rp
+ mov loc2=ret0
+ mov out0=ret0
+ ;;
+ br.call.sptk.few rp=__error
+ st4 [ret0]=loc2
+ ;;
+ mov ret0=-1
+ mov ar.pfs=loc0
+ mov rp=loc1
+ ;;
+ br.ret.sptk.few rp
+END(.cerror)
diff --git a/lib/libc/ia64/sys/exect.S b/lib/libc/ia64/sys/exect.S
new file mode 100644
index 0000000..817d3b1
--- /dev/null
+++ b/lib/libc/ia64/sys/exect.S
@@ -0,0 +1,38 @@
+/* $NetBSD: exect.S,v 1.2 1996/10/17 03:08:18 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+ENTRY(exect, 3)
+ CALLSYS_ERROR(execve)
+ br.ret.sptk.few rp
+END(exect)
diff --git a/lib/libc/ia64/sys/fork.S b/lib/libc/ia64/sys/fork.S
new file mode 100644
index 0000000..5b09f77
--- /dev/null
+++ b/lib/libc/ia64/sys/fork.S
@@ -0,0 +1,37 @@
+/*-
+ * Copyright (c) 2000 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 <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+SYSCALL(fork)
+ cmp.ne p7,p0=ret1,r0 /* ret1!=0 for child */
+ ;;
+(p7) mov ret0=r0
+ br.ret.sptk.few rp
+END(__sys_fork)
diff --git a/lib/libc/ia64/sys/getcontext.S b/lib/libc/ia64/sys/getcontext.S
new file mode 100644
index 0000000..0ec6f92
--- /dev/null
+++ b/lib/libc/ia64/sys/getcontext.S
@@ -0,0 +1,39 @@
+/*
+ * 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 <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+ENTRY(__sys_getcontext,2)
+ WEAK_ALIAS(getcontext, __sys_getcontext)
+ WEAK_ALIAS(_getcontext, __sys_getcontext)
+ flushrs
+ ;;
+ CALLSYS_ERROR(getcontext)
+ br.ret.sptk.few rp
+END(__sys_getcontext)
diff --git a/lib/libc/ia64/sys/pipe.S b/lib/libc/ia64/sys/pipe.S
new file mode 100644
index 0000000..a6413df
--- /dev/null
+++ b/lib/libc/ia64/sys/pipe.S
@@ -0,0 +1,47 @@
+/* $NetBSD: pipe.S,v 1.1 1995/02/10 17:50:35 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+ENTRY(__sys_pipe, 1)
+ WEAK_ALIAS(pipe, __sys_pipe)
+ WEAK_ALIAS(_pipe, __sys_pipe)
+ st8 [sp]=r32
+ CALLSYS_ERROR(pipe)
+ ld8 r14=[sp]
+ ;;
+ st4 [r14]=ret0,4
+ ;;
+ st4 [r14]=ret1
+ mov ret0=0
+ br.ret.sptk.few rp
+END(__sys_pipe)
diff --git a/lib/libc/ia64/sys/ptrace.S b/lib/libc/ia64/sys/ptrace.S
new file mode 100644
index 0000000..b6d3abd
--- /dev/null
+++ b/lib/libc/ia64/sys/ptrace.S
@@ -0,0 +1,41 @@
+/* $NetBSD: ptrace.S,v 1.4 1996/11/08 00:51:24 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+ENTRY(ptrace, 4)
+ add r14=@ltoff(errno),gp ;;
+ ld8 r14=[r14] ;;
+ st4 [r14]=r0
+ CALLSYS_ERROR(ptrace)
+ br.ret.sptk.few rp
+END(ptrace)
diff --git a/lib/libc/ia64/sys/sbrk.S b/lib/libc/ia64/sys/sbrk.S
new file mode 100644
index 0000000..98b5ce9
--- /dev/null
+++ b/lib/libc/ia64/sys/sbrk.S
@@ -0,0 +1,63 @@
+/* $NetBSD: sbrk.S,v 1.4 1996/10/17 03:08:20 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+ .globl _end
+
+ .data
+EXPORT(curbrk)
+ .quad _end
+
+ .text
+ENTRY(sbrk, 1)
+ add r14 = @ltoff(curbrk), gp
+ ;;
+ ld8 r14 = [r14]
+ cmp.eq p6, p0 = r32, r0
+ ;;
+ ld8 ret0 = [r14]
+(p6) br.ret.sptk.few rp
+ ;;
+ add r32 = ret0, r32
+ ;;
+ st8 [sp] = r32
+ CALLSYS_ERROR(break)
+ ld8 r15 = [sp]
+ add r14 = @ltoff(curbrk), gp
+ ;;
+ ld8 r14 = [r14]
+ ;;
+ ld8 ret0 = [r14]
+ st8 [r14] = r15
+ br.ret.sptk.few rp
+END(sbrk)
diff --git a/lib/libc/ia64/sys/setlogin.S b/lib/libc/ia64/sys/setlogin.S
new file mode 100644
index 0000000..1d29a40
--- /dev/null
+++ b/lib/libc/ia64/sys/setlogin.S
@@ -0,0 +1,42 @@
+/* $NetBSD: setlogin.S,v 1.1 1995/02/10 17:50:39 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+IMPORT(_logname_valid, 4) /* in getlogin() */
+
+SYSCALL(setlogin)
+ add r14=@ltoff(_logname_valid),gp ;;
+ ld8 r14=[r14] ;;
+ st4 [r14]=r0 /* clear it */
+ br.ret.sptk.few rp
+END(__sys_setlogin)
diff --git a/lib/libc/ia64/sys/sigreturn.S b/lib/libc/ia64/sys/sigreturn.S
new file mode 100644
index 0000000..2c7a710
--- /dev/null
+++ b/lib/libc/ia64/sys/sigreturn.S
@@ -0,0 +1,41 @@
+/* $NetBSD: sigreturn.S,v 1.1 1995/02/10 17:50:42 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+/*
+ * We must preserve the state of the registers as the user has set them up.
+ * However, that doesn't involve any special work on the ia64.
+ * (XXX PROFILING)
+ */
+
+RSYSCALL(sigreturn)
diff --git a/lib/libc/ia64/sys/swapcontext.S b/lib/libc/ia64/sys/swapcontext.S
new file mode 100644
index 0000000..210189f
--- /dev/null
+++ b/lib/libc/ia64/sys/swapcontext.S
@@ -0,0 +1,39 @@
+/*
+ * 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 <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+ENTRY(__sys_swapcontext,2)
+ WEAK_ALIAS(swapcontext, __sys_swapcontext)
+ WEAK_ALIAS(_swapcontext, __sys_swapcontext)
+ flushrs
+ ;;
+ CALLSYS_ERROR(swapcontext)
+ br.ret.sptk.few rp
+END(__sys_swapcontext)
diff --git a/lib/libc/include/fpmath.h b/lib/libc/include/fpmath.h
new file mode 100644
index 0000000..d33cfdc
--- /dev/null
+++ b/lib/libc/include/fpmath.h
@@ -0,0 +1,66 @@
+/*-
+ * 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"
+
+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
+ unsigned int manl :32;
+ unsigned int manh :20;
+ unsigned int exp :11;
+ unsigned int sign :1;
+#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/libc_private.h b/lib/libc/include/libc_private.h
new file mode 100644
index 0000000..cd5769e
--- /dev/null
+++ b/lib/libc/include/libc_private.h
@@ -0,0 +1,175 @@
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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_
+
+/*
+ * 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;
+
+/*
+ * 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)
+
+/*
+ * 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_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[];
+
+/*
+ * yplib internal interfaces
+ */
+#ifdef YP
+int _yp_check(char **);
+#endif
+
+/*
+ * Initialise TLS for static programs
+ */
+void _init_tls(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;
+
+/*
+ * These functions are used by the threading libraries in order to protect
+ * malloc across fork().
+ */
+void _malloc_prefork(void);
+void _malloc_postfork(void);
+
+/*
+ * Function to clean up streams, called from abort() and exit().
+ */
+extern void (*__cleanup)(void);
+
+#endif /* _LIBC_PRIVATE_H_ */
diff --git a/lib/libc/include/namespace.h b/lib/libc/include/namespace.h
new file mode 100644
index 0000000..9ad181e
--- /dev/null
+++ b/lib/libc/include/namespace.h
@@ -0,0 +1,259 @@
+/*
+ * 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 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_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_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_cleanup_pop _pthread_cleanup_pop
+#define pthread_cleanup_push _pthread_cleanup_push
+#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_getconcurrency _pthread_getconcurrency
+#define pthread_getprio _pthread_getprio
+#define pthread_getschedparam _pthread_getschedparam
+#define pthread_getspecific _pthread_getspecific
+#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_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_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 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 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 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 0000000..015c4ec
--- /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 0000000..b0f79bd
--- /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 0000000..13ab367
--- /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 0000000..94f3a64
--- /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 0000000..beef71d
--- /dev/null
+++ b/lib/libc/include/port_before.h
@@ -0,0 +1,22 @@
+/* $FreeBSD$ */
+
+#ifndef _PORT_BEFORE_H_
+#define _PORT_BEFORE_H_
+
+#define _LIBC 1
+#define DO_PTHREADS 1
+#define USE_KQUEUE 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) (x) = (x)
+
+#endif /* _PORT_BEFORE_H_ */
diff --git a/lib/libc/include/reentrant.h b/lib/libc/include/reentrant.h
new file mode 100644
index 0000000..8ab328b
--- /dev/null
+++ b/lib/libc/include/reentrant.h
@@ -0,0 +1,135 @@
+/*-
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 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$
+ */
+
+/*
+ * 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 efficent 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/spinlock.h b/lib/libc/include/spinlock.h
new file mode 100644
index 0000000..eee1969
--- /dev/null
+++ b/lib/libc/include/spinlock.h
@@ -0,0 +1,73 @@
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 0000000..ccdc2a1
--- /dev/null
+++ b/lib/libc/include/un-namespace.h
@@ -0,0 +1,249 @@
+/*
+ * 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 poll
+#undef pthread_atfork
+#undef pthread_attr_destroy
+#undef pthread_attr_get_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_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_cleanup_pop
+#undef pthread_cleanup_push
+#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_getconcurrency
+#undef pthread_getprio
+#undef pthread_getschedparam
+#undef pthread_getspecific
+#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_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_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 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 sendto
+#undef setsockopt
+#undef sigaction
+#undef sigprocmask
+#undef sigsuspend
+#undef socket
+#undef socketpair
+#undef usleep
+#undef wait4
+#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 0000000..0e6cc39
--- /dev/null
+++ b/lib/libc/inet/Makefile.inc
@@ -0,0 +1,11 @@
+# $FreeBSD$
+
+# inet sources
+.PATH: ${.CURDIR}/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+= ${.CURDIR}/inet/Symbol.map
diff --git a/lib/libc/inet/Symbol.map b/lib/libc/inet/Symbol.map
new file mode 100644
index 0000000..03cacc7
--- /dev/null
+++ b/lib/libc/inet/Symbol.map
@@ -0,0 +1,34 @@
+# $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_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
index b967dc2..aa6504a 100644
--- a/lib/libc/inet/inet_addr.c
+++ b/lib/libc/inet/inet_addr.c
@@ -72,6 +72,8 @@
static const char sccsid[] = "@(#)inet_addr.c 8.1 (Berkeley) 6/17/93";
static const char rcsid[] = "$Id: inet_addr.c,v 1.2.206.2 2004/03/17 00:29:45 marka Exp $";
#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
#include "port_before.h"
@@ -89,7 +91,7 @@ static const char rcsid[] = "$Id: inet_addr.c,v 1.2.206.2 2004/03/17 00:29:45 ma
* Ascii internet address interpretation routine.
* The value returned is in network order.
*/
-u_long
+in_addr_t /* XXX should be struct in_addr :( */
inet_addr(const char *cp) {
struct in_addr val;
@@ -204,3 +206,12 @@ inet_aton(const char *cp, struct in_addr *addr) {
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);
diff --git a/lib/libc/inet/inet_cidr_pton.c b/lib/libc/inet/inet_cidr_pton.c
index 5bfef71..3089eb9 100644
--- a/lib/libc/inet/inet_cidr_pton.c
+++ b/lib/libc/inet/inet_cidr_pton.c
@@ -18,6 +18,8 @@
#if defined(LIBC_SCCS) && !defined(lint)
static const char rcsid[] = "$Id: inet_cidr_pton.c,v 1.2.2.1.8.2 2004/03/17 00:29:46 marka Exp $";
#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
#include "port_before.h"
@@ -27,7 +29,7 @@ static const char rcsid[] = "$Id: inet_cidr_pton.c,v 1.2.2.1.8.2 2004/03/17 00:2
#include <arpa/nameser.h>
#include <arpa/inet.h>
-#include <isc/assertions.h>
+#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
@@ -92,7 +94,7 @@ inet_cidr_pton_ipv4(const char *src, u_char *dst, int *pbits, int ipv6) {
tmp = 0;
do {
n = strchr(digits, ch) - digits;
- INSIST(n >= 0 && n <= 9);
+ assert(n >= 0 && n <= 9);
tmp *= 10;
tmp += n;
if (tmp > 255)
diff --git a/lib/libc/inet/inet_lnaof.c b/lib/libc/inet/inet_lnaof.c
index 97b80cf..678e02c 100644
--- a/lib/libc/inet/inet_lnaof.c
+++ b/lib/libc/inet/inet_lnaof.c
@@ -34,6 +34,8 @@
#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"
@@ -48,11 +50,11 @@ static const char sccsid[] = "@(#)inet_lnaof.c 8.1 (Berkeley) 6/4/93";
* internet address; handles class a/b/c network
* number formats.
*/
-u_long
+in_addr_t
inet_lnaof(in)
struct in_addr in;
{
- register u_long i = ntohl(in.s_addr);
+ in_addr_t i = ntohl(in.s_addr);
if (IN_CLASSA(i))
return ((i)&IN_CLASSA_HOST);
@@ -61,3 +63,10 @@ inet_lnaof(in)
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);
diff --git a/lib/libc/inet/inet_makeaddr.c b/lib/libc/inet/inet_makeaddr.c
index 6e4ecc3..fa6cffe 100644
--- a/lib/libc/inet/inet_makeaddr.c
+++ b/lib/libc/inet/inet_makeaddr.c
@@ -34,6 +34,8 @@
#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"
@@ -49,7 +51,7 @@ static const char sccsid[] = "@(#)inet_makeaddr.c 8.1 (Berkeley) 6/4/93";
*/
struct in_addr
inet_makeaddr(net, host)
- u_long net, host;
+ in_addr_t net, host;
{
struct in_addr a;
@@ -64,3 +66,10 @@ inet_makeaddr(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);
diff --git a/lib/libc/inet/inet_net_ntop.c b/lib/libc/inet/inet_net_ntop.c
index f508629..e221d21 100644
--- a/lib/libc/inet/inet_net_ntop.c
+++ b/lib/libc/inet/inet_net_ntop.c
@@ -18,6 +18,8 @@
#if defined(LIBC_SCCS) && !defined(lint)
static const char rcsid[] = "$Id: inet_net_ntop.c,v 1.1.2.1.8.1 2004/03/09 08:33:32 marka Exp $";
#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
#include "port_before.h"
@@ -39,10 +41,10 @@ static const char rcsid[] = "$Id: inet_net_ntop.c,v 1.1.2.1.8.1 2004/03/09 08:33
# define SPRINTF(x) ((size_t)sprintf x)
#endif
-static char * inet_net_ntop_ipv4 __P((const u_char *src, int bits,
- char *dst, size_t size));
-static char * inet_net_ntop_ipv6 __P((const u_char *src, int bits,
- char *dst, size_t size));
+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 *
@@ -159,7 +161,7 @@ inet_net_ntop_ipv4(src, bits, dst, size)
* pointer to dst, or NULL if an error occurred (check errno).
* note:
* network byte order assumed. this means 192.5.5.240/28 has
- * 0x11110000 in its fourth octet.
+ * 0b11110000 in its fourth octet.
* author:
* Vadim Kogan (UCB), June 2001
* Original version (IPv4) by Paul Vixie (ISC), July 1996
@@ -191,7 +193,7 @@ inet_net_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size) {
*cp++ = ':';
*cp = '\0';
} else {
- /* Copy src to private buffer. Zero host part. */
+ /* Copy src to private buffer. Zero host part. */
p = (bits + 7) / 8;
memcpy(inbuf, src, p);
memset(inbuf + p, 0, 16 - p);
@@ -207,7 +209,7 @@ inet_net_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size) {
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) {
@@ -268,10 +270,17 @@ inet_net_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size) {
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);
diff --git a/lib/libc/inet/inet_net_pton.c b/lib/libc/inet/inet_net_pton.c
index abecfc7..3d9650c 100644
--- a/lib/libc/inet/inet_net_pton.c
+++ b/lib/libc/inet/inet_net_pton.c
@@ -18,6 +18,8 @@
#if defined(LIBC_SCCS) && !defined(lint)
static const char rcsid[] = "$Id: inet_net_pton.c,v 1.4.2.1.8.2 2004/03/17 00:29:47 marka Exp $";
#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
#include "port_before.h"
@@ -27,7 +29,7 @@ static const char rcsid[] = "$Id: inet_net_pton.c,v 1.4.2.1.8.2 2004/03/17 00:29
#include <arpa/nameser.h>
#include <arpa/inet.h>
-#include <isc/assertions.h>
+#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
@@ -78,7 +80,7 @@ inet_net_pton_ipv4(const char *src, u_char *dst, size_t size) {
if (isupper(ch))
ch = tolower(ch);
n = strchr(xdigits, ch) - xdigits;
- INSIST(n >= 0 && n <= 15);
+ assert(n >= 0 && n <= 15);
if (dirty == 0)
tmp = n;
else
@@ -101,7 +103,7 @@ inet_net_pton_ipv4(const char *src, u_char *dst, size_t size) {
tmp = 0;
do {
n = strchr(digits, ch) - digits;
- INSIST(n >= 0 && n <= 9);
+ assert(n >= 0 && n <= 9);
tmp *= 10;
tmp += n;
if (tmp > 255)
@@ -130,7 +132,7 @@ inet_net_pton_ipv4(const char *src, u_char *dst, size_t size) {
bits = 0;
do {
n = strchr(digits, ch) - digits;
- INSIST(n >= 0 && n <= 9);
+ assert(n >= 0 && n <= 9);
bits *= 10;
bits += n;
} while ((ch = *src++) != '\0' && isascii(ch) && isdigit(ch));
@@ -403,3 +405,10 @@ inet_net_pton(int af, const char *src, void *dst, size_t size) {
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);
diff --git a/lib/libc/inet/inet_neta.c b/lib/libc/inet/inet_neta.c
index 325b7ce..872ad48 100644
--- a/lib/libc/inet/inet_neta.c
+++ b/lib/libc/inet/inet_neta.c
@@ -18,6 +18,8 @@
#if defined(LIBC_SCCS) && !defined(lint)
static const char rcsid[] = "$Id: inet_neta.c,v 1.1.206.1 2004/03/09 08:33:33 marka Exp $";
#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
#include "port_before.h"
@@ -41,7 +43,7 @@ static const char rcsid[] = "$Id: inet_neta.c,v 1.1.206.1 2004/03/09 08:33:33 ma
/*
* char *
* inet_neta(src, dst, size)
- * format a u_long network number into presentation format.
+ * format an in_addr_t network number into presentation format.
* return:
* pointer to dst, or NULL if an error occurred (check errno).
* note:
@@ -51,7 +53,7 @@ static const char rcsid[] = "$Id: inet_neta.c,v 1.1.206.1 2004/03/09 08:33:33 ma
*/
char *
inet_neta(src, dst, size)
- u_long src;
+ in_addr_t src;
char *dst;
size_t size;
{
@@ -85,3 +87,10 @@ inet_neta(src, dst, size)
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);
diff --git a/lib/libc/inet/inet_netof.c b/lib/libc/inet/inet_netof.c
index e887530..e993459 100644
--- a/lib/libc/inet/inet_netof.c
+++ b/lib/libc/inet/inet_netof.c
@@ -34,6 +34,8 @@
#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"
@@ -47,11 +49,11 @@ static const char sccsid[] = "@(#)inet_netof.c 8.1 (Berkeley) 6/4/93";
* Return the network number from an internet
* address; handles class a/b/c network #'s.
*/
-u_long
+in_addr_t
inet_netof(in)
struct in_addr in;
{
- register u_long i = ntohl(in.s_addr);
+ in_addr_t i = ntohl(in.s_addr);
if (IN_CLASSA(i))
return (((i)&IN_CLASSA_NET) >> IN_CLASSA_NSHIFT);
@@ -60,3 +62,10 @@ inet_netof(in)
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);
diff --git a/lib/libc/inet/inet_network.c b/lib/libc/inet/inet_network.c
index aaa50c8..9d417ac 100644
--- a/lib/libc/inet/inet_network.c
+++ b/lib/libc/inet/inet_network.c
@@ -34,6 +34,8 @@
#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"
@@ -49,14 +51,14 @@ static const char sccsid[] = "@(#)inet_network.c 8.1 (Berkeley) 6/4/93";
* The library routines call this routine to interpret
* network numbers.
*/
-u_long
+in_addr_t
inet_network(cp)
- register const char *cp;
+ const char *cp;
{
- register u_long val, base, n, i;
- register char c;
- u_long parts[4], *pp = parts;
- int digit;
+ 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;
@@ -102,3 +104,10 @@ again:
}
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);
diff --git a/lib/libc/inet/inet_ntoa.c b/lib/libc/inet/inet_ntoa.c
index 7fad4b8..f1fe1a9 100644
--- a/lib/libc/inet/inet_ntoa.c
+++ b/lib/libc/inet/inet_ntoa.c
@@ -35,6 +35,8 @@
static const char sccsid[] = "@(#)inet_ntoa.c 8.1 (Berkeley) 6/4/93";
static const char rcsid[] = "$Id: inet_ntoa.c,v 1.1 2001/03/29 06:31:38 marka Exp $";
#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
#include "port_before.h"
@@ -60,3 +62,10 @@ inet_ntoa(struct in_addr in) {
(void) inet_ntop(AF_INET, &in, ret, sizeof ret);
return (ret);
}
+
+/*
+ * 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);
diff --git a/lib/libc/inet/inet_ntop.c b/lib/libc/inet/inet_ntop.c
index cd502ab..48c2efe 100644
--- a/lib/libc/inet/inet_ntop.c
+++ b/lib/libc/inet/inet_ntop.c
@@ -18,6 +18,8 @@
#if defined(LIBC_SCCS) && !defined(lint)
static const char rcsid[] = "$Id: inet_ntop.c,v 1.1.2.1.8.2 2005/11/03 23:08:40 marka Exp $";
#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
#include "port_before.h"
@@ -35,19 +37,13 @@ static const char rcsid[] = "$Id: inet_ntop.c,v 1.1.2.1.8.2 2005/11/03 23:08:40
#include "port_after.h"
-#ifdef SPRINTF_CHAR
-# define SPRINTF(x) strlen(sprintf/**/x)
-#else
-# define SPRINTF(x) ((size_t)sprintf x)
-#endif
-
/*
* 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 __P((const u_char *src, char *dst, size_t size));
-static const char *inet_ntop6 __P((const u_char *src, char *dst, size_t size));
+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);
/* char *
* inet_ntop(af, src, dst, size)
@@ -58,11 +54,8 @@ static const char *inet_ntop6 __P((const u_char *src, char *dst, size_t size));
* Paul Vixie, 1996.
*/
const char *
-inet_ntop(af, src, dst, size)
- int af;
- const void *src;
- char *dst;
- size_t size;
+inet_ntop(int af, const void * __restrict src, char * __restrict dst,
+ socklen_t size)
{
switch (af) {
case AF_INET:
@@ -88,19 +81,18 @@ inet_ntop(af, src, dst, size)
* Paul Vixie, 1996.
*/
static const char *
-inet_ntop4(src, dst, size)
- const u_char *src;
- char *dst;
- size_t size;
+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;
- if (SPRINTF((tmp, fmt, src[0], src[1], src[2], src[3])) >= size) {
+ 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);
}
- strcpy(dst, tmp);
+ strlcpy(dst, tmp, size);
return (dst);
}
@@ -111,10 +103,7 @@ inet_ntop4(src, dst, size)
* Paul Vixie, 1996.
*/
static const char *
-inet_ntop6(src, dst, size)
- const u_char *src;
- char *dst;
- size_t size;
+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
@@ -185,7 +174,7 @@ inet_ntop6(src, dst, size)
tp += strlen(tp);
break;
}
- tp += SPRINTF((tp, "%x", words[i]));
+ tp += sprintf(tp, "%x", words[i]);
}
/* Was it a trailing run of 0x00's? */
if (best.base != -1 && (best.base + best.len) ==
@@ -196,10 +185,17 @@ inet_ntop6(src, dst, size)
/*
* Check for overflow, copy, and we're done.
*/
- if ((size_t)(tp - tmp) > size) {
+ 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);
diff --git a/lib/libc/inet/inet_pton.c b/lib/libc/inet/inet_pton.c
index f18a7b6..44d9c61 100644
--- a/lib/libc/inet/inet_pton.c
+++ b/lib/libc/inet/inet_pton.c
@@ -18,6 +18,8 @@
#if defined(LIBC_SCCS) && !defined(lint)
static const char rcsid[] = "$Id: inet_pton.c,v 1.2.206.2 2005/07/28 07:43:18 marka Exp $";
#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
#include "port_before.h"
#include <sys/param.h>
@@ -35,8 +37,8 @@ static const char rcsid[] = "$Id: inet_pton.c,v 1.2.206.2 2005/07/28 07:43:18 ma
* sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
*/
-static int inet_pton4 __P((const char *src, u_char *dst));
-static int inet_pton6 __P((const char *src, u_char *dst));
+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)
@@ -50,10 +52,7 @@ static int inet_pton6 __P((const char *src, u_char *dst));
* Paul Vixie, 1996.
*/
int
-inet_pton(af, src, dst)
- int af;
- const char *src;
- void *dst;
+inet_pton(int af, const char * __restrict src, void * __restrict dst)
{
switch (af) {
case AF_INET:
@@ -78,9 +77,7 @@ inet_pton(af, src, dst)
* Paul Vixie, 1996.
*/
static int
-inet_pton4(src, dst)
- const char *src;
- u_char *dst;
+inet_pton4(const char *src, u_char *dst)
{
static const char digits[] = "0123456789";
int saw_digit, octets, ch;
@@ -133,9 +130,7 @@ inet_pton4(src, dst)
* Paul Vixie, 1996.
*/
static int
-inet_pton6(src, dst)
- const char *src;
- u_char *dst;
+inet_pton6(const char *src, u_char *dst)
{
static const char xdigits_l[] = "0123456789abcdef",
xdigits_u[] = "0123456789ABCDEF";
@@ -219,3 +214,10 @@ inet_pton6(src, dst)
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);
diff --git a/lib/libc/inet/nsap_addr.c b/lib/libc/inet/nsap_addr.c
index a4b98e7..27d44ba 100644
--- a/lib/libc/inet/nsap_addr.c
+++ b/lib/libc/inet/nsap_addr.c
@@ -18,6 +18,8 @@
#if defined(LIBC_SCCS) && !defined(lint)
static const char rcsid[] = "$Id: nsap_addr.c,v 1.2.206.2 2005/07/28 07:43:18 marka Exp $";
#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
#include "port_before.h"
@@ -107,3 +109,12 @@ inet_nsap_ntoa(int binlen, const u_char *binary, char *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);
diff --git a/lib/libc/isc/Makefile.inc b/lib/libc/isc/Makefile.inc
new file mode 100644
index 0000000..48c90f7
--- /dev/null
+++ b/lib/libc/isc/Makefile.inc
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+# isc sources
+.PATH: ${.CURDIR}/isc
+
+SRCS+= ev_streams.c ev_timers.c
diff --git a/lib/libc/isc/ev_streams.c b/lib/libc/isc/ev_streams.c
index 64e88b0..4ad82cf 100644
--- a/lib/libc/isc/ev_streams.c
+++ b/lib/libc/isc/ev_streams.c
@@ -22,9 +22,13 @@
#if !defined(LINT) && !defined(CODECENTER)
static const char rcsid[] = "$Id: ev_streams.c,v 1.2.206.2 2004/03/17 00:29:51 marka 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>
@@ -32,16 +36,20 @@ static const char rcsid[] = "$Id: ev_streams.c,v 1.2.206.2 2004/03/17 00:29:51 m
#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) {
@@ -53,6 +61,7 @@ evConsIovec(void *buf, size_t cnt) {
return (ret);
}
+#ifndef _LIBC
int
evWrite(evContext opaqueCtx, int fd, const struct iovec *iov, int iocnt,
evStreamFunc func, void *uap, evStreamID *id)
@@ -304,3 +313,4 @@ readable(evContext opaqueCtx, void *uap, int fd, int evmask) {
if (str->ioDone <= 0 || str->ioDone == str->ioTotal)
done(opaqueCtx, str);
}
+#endif
diff --git a/lib/libc/isc/ev_timers.c b/lib/libc/isc/ev_timers.c
index 11433fb..47c3dcf 100644
--- a/lib/libc/isc/ev_timers.c
+++ b/lib/libc/isc/ev_timers.c
@@ -22,15 +22,21 @@
#if !defined(LINT) && !defined(CODECENTER)
static const char rcsid[] = "$Id: ev_timers.c,v 1.2.2.1.4.5 2004/03/17 02:39:13 marka 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"
@@ -43,6 +49,9 @@ static const char rcsid[] = "$Id: ev_timers.c,v 1.2.2.1.4.5 2004/03/17 02:39:13
/* 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 *);
@@ -58,6 +67,7 @@ typedef struct {
struct timespec max_idle;
evTimer * timer;
} idle_timer;
+#endif
/* Public. */
@@ -138,12 +148,14 @@ evUTCTime() {
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) {
@@ -154,6 +166,7 @@ evTimeSpec(struct timeval tv) {
return (ts);
}
+#if !defined(USE_KQUEUE) || !defined(_LIBC)
struct timeval
evTimeVal(struct timespec ts) {
struct timeval tv;
@@ -162,7 +175,9 @@ evTimeVal(struct timespec ts) {
tv.tv_usec = ts.tv_nsec / 1000;
return (tv);
}
+#endif
+#ifndef _LIBC
int
evSetTimer(evContext opaqueCtx,
evTimerFunc func,
@@ -495,3 +510,4 @@ idle_timeout(evContext opaqueCtx,
this->timer->inter = evSubTime(this->max_idle, idle);
}
}
+#endif
diff --git a/lib/libc/isc/eventlib_p.h b/lib/libc/isc/eventlib_p.h
index b95741d..38b1852 100644
--- a/lib/libc/isc/eventlib_p.h
+++ b/lib/libc/isc/eventlib_p.h
@@ -19,6 +19,7 @@
* vix 09sep95 [initial]
*
* $Id: eventlib_p.h,v 1.3.2.1.4.3 2005/07/28 07:43:20 marka Exp $
+ * $FreeBSD$
*/
#ifndef _EVENTLIB_P_H
@@ -38,9 +39,11 @@
#include <stdlib.h>
#include <string.h>
-#include <isc/heap.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)
@@ -83,6 +86,7 @@ typedef struct evConn {
struct evConn * next;
} evConn;
+#ifndef _LIBC
typedef struct evAccept {
int fd;
union {
@@ -172,6 +176,7 @@ typedef struct evEvent_p {
struct { const void *placeholder; } null;
} u;
} evEvent_p;
+#endif
#ifdef USE_POLL
typedef struct {
@@ -207,6 +212,7 @@ extern void __fd_set(int fd, __evEmulMask *maskp);
#endif /* USE_POLL */
+#ifndef _LIBC
typedef struct {
/* Global. */
const evEvent_p *cur;
@@ -271,6 +277,7 @@ void evDestroyTimers(const evContext_p *);
/* ev_waits.c */
#define evFreeWait __evFreeWait
evWait *evFreeWait(evContext_p *ctx, evWait *old);
+#endif
/* Global options */
extern int __evOptMonoTime;
diff --git a/lib/libc/locale/Makefile.inc b/lib/libc/locale/Makefile.inc
new file mode 100644
index 0000000..24ac904
--- /dev/null
+++ b/lib/libc/locale/Makefile.inc
@@ -0,0 +1,59 @@
+# from @(#)Makefile.inc 8.1 (Berkeley) 6/4/93
+# $FreeBSD$
+
+# locale sources
+.PATH: ${.CURDIR}/${MACHINE_ARCH}/locale ${.CURDIR}/locale
+
+SRCS+= big5.c btowc.c collate.c collcmp.c euc.c fix_grouping.c \
+ gb18030.c gb2312.c gbk.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
+
+SYM_MAPS+=${.CURDIR}/locale/Symbol.map
+
+MAN+= btowc.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 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
+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+=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+=isxdigit.3 ishexnumber.3
+MLINKS+=mbsrtowcs.3 mbsnrtowcs.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 0000000..ce56657
--- /dev/null
+++ b/lib/libc/locale/Symbol.map
@@ -0,0 +1,102 @@
+# $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;
+ __istype;
+ __isctype;
+ __toupper;
+ __tolower;
+ __wcwidth;
+ __mb_cur_max;
+ 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;
+};
+
+FBSDprivate {
+ _PathLocale;
+ __detect_path_locale;
+ __collate_load_error;
+ __collate_range_cmp;
+};
diff --git a/lib/libc/locale/big5.5 b/lib/libc/locale/big5.5
new file mode 100644
index 0000000..13d0c7b
--- /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 0000000..44b9957
--- /dev/null
+++ b/lib/libc/locale/big5.c
@@ -0,0 +1,172 @@
+/*-
+ * 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.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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.
+ */
+
+#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"
+
+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);
+
+typedef struct {
+ wchar_t ch;
+} _BIG5State;
+
+int
+_BIG5_init(_RuneLocale *rl)
+{
+
+ __mbrtowc = _BIG5_mbrtowc;
+ __wcrtomb = _BIG5_wcrtomb;
+ __mbsinit = _BIG5_mbsinit;
+ _CurrentRuneLocale = rl;
+ __mb_cur_max = 2;
+ 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);
+}
diff --git a/lib/libc/locale/btowc.3 b/lib/libc/locale/btowc.3
new file mode 100644
index 0000000..85ee751
--- /dev/null
+++ b/lib/libc/locale/btowc.3
@@ -0,0 +1,79 @@
+.\" 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 3, 2002
+.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"
+.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 WEOF .
+.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 0000000..2c4d493
--- /dev/null
+++ b/lib/libc/locale/btowc.c
@@ -0,0 +1,53 @@
+/*-
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <wchar.h>
+#include "mblocal.h"
+
+wint_t
+btowc(int c)
+{
+ static const mbstate_t initial;
+ mbstate_t mbs = initial;
+ char cc;
+ wchar_t wc;
+
+ 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 (__mbrtowc(&wc, &cc, 1, &mbs) > 1)
+ return (WEOF);
+ return (wc);
+}
diff --git a/lib/libc/locale/collate.c b/lib/libc/locale/collate.c
new file mode 100644
index 0000000..6833598
--- /dev/null
+++ b/lib/libc/locale/collate.c
@@ -0,0 +1,298 @@
+/*-
+ * Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua>
+ * at Electronni Visti IA, Kiev, Ukraine.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list 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 <arpa/inet.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sysexits.h>
+#include "un-namespace.h"
+
+#include "collate.h"
+#include "setlocale.h"
+#include "ldpart.h"
+
+#include "libc_private.h"
+
+int __collate_load_error = 1;
+int __collate_substitute_nontrivial;
+
+u_char __collate_substitute_table[UCHAR_MAX + 1][STR_LEN];
+struct __collate_st_char_pri __collate_char_pri_table[UCHAR_MAX + 1];
+struct __collate_st_chain_pri *__collate_chain_pri_table;
+
+void __collate_err(int ex, const char *f) __dead2;
+
+int
+__collate_load_tables(const char *encoding)
+{
+ FILE *fp;
+ int i, saverr, chains;
+ uint32_t u32;
+ char strbuf[STR_LEN], buf[PATH_MAX];
+ void *TMP_substitute_table, *TMP_char_pri_table, *TMP_chain_pri_table;
+ static char collate_encoding[ENCODING_LEN + 1];
+
+ /* 'encoding' must be already checked. */
+ if (strcmp(encoding, "C") == 0 || strcmp(encoding, "POSIX") == 0) {
+ __collate_load_error = 1;
+ return (_LDP_CACHE);
+ }
+
+ /*
+ * If the locale name is the same as our cache, use the cache.
+ */
+ if (strcmp(encoding, collate_encoding) == 0) {
+ __collate_load_error = 0;
+ return (_LDP_CACHE);
+ }
+
+ /*
+ * Slurp the locale file into the cache.
+ */
+
+ /* 'PathLocale' must be already set & checked. */
+ /* Range checking not needed, encoding has fixed size */
+ (void)strcpy(buf, _PathLocale);
+ (void)strcat(buf, "/");
+ (void)strcat(buf, encoding);
+ (void)strcat(buf, "/LC_COLLATE");
+ if ((fp = fopen(buf, "r")) == NULL)
+ return (_LDP_ERROR);
+
+ if (fread(strbuf, sizeof(strbuf), 1, fp) != 1) {
+ saverr = errno;
+ (void)fclose(fp);
+ errno = saverr;
+ return (_LDP_ERROR);
+ }
+ chains = -1;
+ if (strcmp(strbuf, COLLATE_VERSION) == 0)
+ chains = 0;
+ else if (strcmp(strbuf, COLLATE_VERSION1_2) == 0)
+ chains = 1;
+ if (chains < 0) {
+ (void)fclose(fp);
+ errno = EFTYPE;
+ return (_LDP_ERROR);
+ }
+ if (chains) {
+ if (fread(&u32, sizeof(u32), 1, fp) != 1) {
+ saverr = errno;
+ (void)fclose(fp);
+ errno = saverr;
+ return (_LDP_ERROR);
+ }
+ if ((chains = (int)ntohl(u32)) < 1) {
+ (void)fclose(fp);
+ errno = EFTYPE;
+ return (_LDP_ERROR);
+ }
+ } else
+ chains = TABLE_SIZE;
+
+ if ((TMP_substitute_table =
+ malloc(sizeof(__collate_substitute_table))) == NULL) {
+ saverr = errno;
+ (void)fclose(fp);
+ errno = saverr;
+ return (_LDP_ERROR);
+ }
+ if ((TMP_char_pri_table =
+ malloc(sizeof(__collate_char_pri_table))) == NULL) {
+ saverr = errno;
+ free(TMP_substitute_table);
+ (void)fclose(fp);
+ errno = saverr;
+ return (_LDP_ERROR);
+ }
+ if ((TMP_chain_pri_table =
+ malloc(sizeof(*__collate_chain_pri_table) * chains)) == NULL) {
+ saverr = errno;
+ free(TMP_substitute_table);
+ free(TMP_char_pri_table);
+ (void)fclose(fp);
+ errno = saverr;
+ return (_LDP_ERROR);
+ }
+
+#define FREAD(a, b, c, d) \
+{ \
+ if (fread(a, b, c, d) != c) { \
+ saverr = errno; \
+ free(TMP_substitute_table); \
+ free(TMP_char_pri_table); \
+ free(TMP_chain_pri_table); \
+ (void)fclose(d); \
+ errno = saverr; \
+ return (_LDP_ERROR); \
+ } \
+}
+
+ FREAD(TMP_substitute_table, sizeof(__collate_substitute_table), 1, fp);
+ FREAD(TMP_char_pri_table, sizeof(__collate_char_pri_table), 1, fp);
+ FREAD(TMP_chain_pri_table,
+ sizeof(*__collate_chain_pri_table), chains, fp);
+ (void)fclose(fp);
+
+ (void)strcpy(collate_encoding, encoding);
+ if (__collate_substitute_table_ptr != NULL)
+ free(__collate_substitute_table_ptr);
+ __collate_substitute_table_ptr = TMP_substitute_table;
+ if (__collate_char_pri_table_ptr != NULL)
+ free(__collate_char_pri_table_ptr);
+ __collate_char_pri_table_ptr = TMP_char_pri_table;
+ for (i = 0; i < UCHAR_MAX + 1; i++) {
+ __collate_char_pri_table[i].prim =
+ ntohl(__collate_char_pri_table[i].prim);
+ __collate_char_pri_table[i].sec =
+ ntohl(__collate_char_pri_table[i].sec);
+ }
+ if (__collate_chain_pri_table != NULL)
+ free(__collate_chain_pri_table);
+ __collate_chain_pri_table = TMP_chain_pri_table;
+ for (i = 0; i < chains; i++) {
+ __collate_chain_pri_table[i].prim =
+ ntohl(__collate_chain_pri_table[i].prim);
+ __collate_chain_pri_table[i].sec =
+ ntohl(__collate_chain_pri_table[i].sec);
+ }
+ __collate_substitute_nontrivial = 0;
+ for (i = 0; i < UCHAR_MAX + 1; i++) {
+ if (__collate_substitute_table[i][0] != i ||
+ __collate_substitute_table[i][1] != 0) {
+ __collate_substitute_nontrivial = 1;
+ break;
+ }
+ }
+ __collate_load_error = 0;
+
+ return (_LDP_LOADED);
+}
+
+u_char *
+__collate_substitute(const u_char *s)
+{
+ int dest_len, len, nlen;
+ int delta = strlen(s);
+ u_char *dest_str = NULL;
+
+ if (s == NULL || *s == '\0')
+ return (__collate_strdup(""));
+ delta += delta / 8;
+ dest_str = malloc(dest_len = delta);
+ if (dest_str == NULL)
+ __collate_err(EX_OSERR, __func__);
+ len = 0;
+ while (*s) {
+ nlen = len + strlen(__collate_substitute_table[*s]);
+ if (dest_len <= nlen) {
+ dest_str = reallocf(dest_str, dest_len = nlen + delta);
+ if (dest_str == NULL)
+ __collate_err(EX_OSERR, __func__);
+ }
+ (void)strcpy(dest_str + len, __collate_substitute_table[*s++]);
+ len = nlen;
+ }
+ return (dest_str);
+}
+
+void
+__collate_lookup(const u_char *t, int *len, int *prim, int *sec)
+{
+ struct __collate_st_chain_pri *p2;
+
+ *len = 1;
+ *prim = *sec = 0;
+ for (p2 = __collate_chain_pri_table; p2->str[0] != '\0'; p2++) {
+ if (*t == p2->str[0] &&
+ strncmp(t, p2->str, strlen(p2->str)) == 0) {
+ *len = strlen(p2->str);
+ *prim = p2->prim;
+ *sec = p2->sec;
+ return;
+ }
+ }
+ *prim = __collate_char_pri_table[*t].prim;
+ *sec = __collate_char_pri_table[*t].sec;
+}
+
+u_char *
+__collate_strdup(u_char *s)
+{
+ u_char *t = strdup(s);
+
+ if (t == NULL)
+ __collate_err(EX_OSERR, __func__);
+ return (t);
+}
+
+void
+__collate_err(int ex, const char *f)
+{
+ const char *s;
+ int serrno = errno;
+
+ s = _getprogname();
+ _write(STDERR_FILENO, s, strlen(s));
+ _write(STDERR_FILENO, ": ", 2);
+ s = f;
+ _write(STDERR_FILENO, s, strlen(s));
+ _write(STDERR_FILENO, ": ", 2);
+ s = strerror(serrno);
+ _write(STDERR_FILENO, s, strlen(s));
+ _write(STDERR_FILENO, "\n", 1);
+ exit(ex);
+}
+
+#ifdef COLLATE_DEBUG
+void
+__collate_print_tables()
+{
+ int i;
+ struct __collate_st_chain_pri *p2;
+
+ printf("Substitute table:\n");
+ for (i = 0; i < UCHAR_MAX + 1; i++)
+ if (i != *__collate_substitute_table[i])
+ printf("\t'%c' --> \"%s\"\n", i,
+ __collate_substitute_table[i]);
+ printf("Chain priority table:\n");
+ for (p2 = __collate_chain_pri_table; p2->str[0] != '\0'; p2++)
+ printf("\t\"%s\" : %d %d\n", p2->str, p2->prim, p2->sec);
+ printf("Char priority table:\n");
+ for (i = 0; i < UCHAR_MAX + 1; i++)
+ printf("\t'%c' : %d %d\n", i, __collate_char_pri_table[i].prim,
+ __collate_char_pri_table[i].sec);
+}
+#endif
diff --git a/lib/libc/locale/collate.h b/lib/libc/locale/collate.h
new file mode 100644
index 0000000..2f5f5d4
--- /dev/null
+++ b/lib/libc/locale/collate.h
@@ -0,0 +1,69 @@
+/*-
+ * Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua>
+ * at Electronni Visti IA, Kiev, Ukraine.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list 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>
+
+#define STR_LEN 10
+#define TABLE_SIZE 100
+#define COLLATE_VERSION "1.0\n"
+#define COLLATE_VERSION1_2 "1.2\n"
+
+struct __collate_st_char_pri {
+ int prim, sec;
+};
+struct __collate_st_chain_pri {
+ u_char str[STR_LEN];
+ int prim, sec;
+};
+
+extern int __collate_load_error;
+extern int __collate_substitute_nontrivial;
+#define __collate_substitute_table (*__collate_substitute_table_ptr)
+extern u_char __collate_substitute_table[UCHAR_MAX + 1][STR_LEN];
+#define __collate_char_pri_table (*__collate_char_pri_table_ptr)
+extern struct __collate_st_char_pri __collate_char_pri_table[UCHAR_MAX + 1];
+extern struct __collate_st_chain_pri *__collate_chain_pri_table;
+
+__BEGIN_DECLS
+u_char *__collate_strdup(u_char *);
+u_char *__collate_substitute(const u_char *);
+int __collate_load_tables(const char *);
+void __collate_lookup(const u_char *, int *, int *, int *);
+int __collate_range_cmp(int, int);
+#ifdef COLLATE_DEBUG
+void __collate_print_tables(void);
+#endif
+__END_DECLS
+
+#endif /* !_COLLATE_H_ */
diff --git a/lib/libc/locale/collcmp.c b/lib/libc/locale/collcmp.c
new file mode 100644
index 0000000..313e043
--- /dev/null
+++ b/lib/libc/locale/collcmp.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 1996 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <string.h>
+#include "collate.h"
+
+/*
+ * Compare two characters using collate
+ */
+
+int __collate_range_cmp(int c1, int c2)
+{
+ static char s1[2], s2[2];
+
+ s1[0] = c1;
+ s2[0] = c2;
+ return (strcoll(s1, s2));
+}
diff --git a/lib/libc/locale/ctype.3 b/lib/libc/locale/ctype.3
new file mode 100644
index 0000000..44aeac7
--- /dev/null
+++ b/lib/libc/locale/ctype.3
@@ -0,0 +1,155 @@
+.\" 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. 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.
+.\"
+.\" @(#)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 macros
+.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/digittoint.3 b/lib/libc/locale/digittoint.3
new file mode 100644
index 0000000..672e246
--- /dev/null
+++ b/lib/libc/locale/digittoint.3
@@ -0,0 +1,63 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)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"
+.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.
+.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
diff --git a/lib/libc/locale/euc.5 b/lib/libc/locale/euc.5
new file mode 100644
index 0000000..d4e128b
--- /dev/null
+++ b/lib/libc/locale/euc.5
@@ -0,0 +1,138 @@
+.\" 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. 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.
+.\"
+.\" @(#)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 0000000..b3b35ed
--- /dev/null
+++ b/lib/libc/locale/euc.c
@@ -0,0 +1,265 @@
+/*-
+ * 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.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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.
+ */
+
+#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"
+
+static size_t _EUC_mbrtowc(wchar_t * __restrict, const char * __restrict,
+ size_t, mbstate_t * __restrict);
+static int _EUC_mbsinit(const mbstate_t *);
+static size_t _EUC_wcrtomb(char * __restrict, wchar_t,
+ mbstate_t * __restrict);
+
+typedef struct {
+ int count[4];
+ wchar_t bits[4];
+ wchar_t mask;
+} _EucInfo;
+
+typedef struct {
+ wchar_t ch;
+ int set;
+ int want;
+} _EucState;
+
+int
+_EUC_init(_RuneLocale *rl)
+{
+ _EucInfo *ei;
+ int x, new__mb_cur_max;
+ char *v, *e;
+
+ if (rl->__variable == NULL)
+ return (EFTYPE);
+
+ v = (char *)rl->__variable;
+
+ while (*v == ' ' || *v == '\t')
+ ++v;
+
+ if ((ei = malloc(sizeof(_EucInfo))) == NULL)
+ return (errno == 0 ? ENOMEM : errno);
+
+ new__mb_cur_max = 0;
+ for (x = 0; x < 4; ++x) {
+ ei->count[x] = (int)strtol(v, &e, 0);
+ if (v == e || !(v = e)) {
+ free(ei);
+ return (EFTYPE);
+ }
+ if (new__mb_cur_max < ei->count[x])
+ new__mb_cur_max = ei->count[x];
+ while (*v == ' ' || *v == '\t')
+ ++v;
+ ei->bits[x] = (int)strtol(v, &e, 0);
+ if (v == e || !(v = e)) {
+ free(ei);
+ return (EFTYPE);
+ }
+ while (*v == ' ' || *v == '\t')
+ ++v;
+ }
+ ei->mask = (int)strtol(v, &e, 0);
+ if (v == e || !(v = e)) {
+ free(ei);
+ return (EFTYPE);
+ }
+ rl->__variable = ei;
+ rl->__variable_len = sizeof(_EucInfo);
+ _CurrentRuneLocale = rl;
+ __mb_cur_max = new__mb_cur_max;
+ __mbrtowc = _EUC_mbrtowc;
+ __wcrtomb = _EUC_wcrtomb;
+ __mbsinit = _EUC_mbsinit;
+ return (0);
+}
+
+static int
+_EUC_mbsinit(const mbstate_t *ps)
+{
+
+ return (ps == NULL || ((const _EucState *)ps)->want == 0);
+}
+
+#define CEI ((_EucInfo *)(_CurrentRuneLocale->__variable))
+
+#define _SS2 0x008e
+#define _SS3 0x008f
+
+#define GR_BITS 0x80808080 /* XXX: to be fixed */
+
+static __inline int
+_euc_set(u_int c)
+{
+
+ c &= 0xff;
+ return ((c & 0x80) ? c == _SS3 ? 3 : c == _SS2 ? 2 : 1 : 0);
+}
+
+static size_t
+_EUC_mbrtowc(wchar_t * __restrict pwc, const char * __restrict s, size_t n,
+ mbstate_t * __restrict ps)
+{
+ _EucState *es;
+ int i, set, want;
+ wchar_t wc;
+ const char *os;
+
+ es = (_EucState *)ps;
+
+ if (es->want < 0 || es->want > MB_CUR_MAX || es->set < 0 ||
+ es->set > 3) {
+ errno = EINVAL;
+ return ((size_t)-1);
+ }
+
+ if (s == NULL) {
+ s = "";
+ n = 1;
+ pwc = NULL;
+ }
+
+ if (n == 0)
+ /* Incomplete multibyte sequence */
+ return ((size_t)-2);
+
+ os = s;
+
+ if (es->want == 0) {
+ want = CEI->count[set = _euc_set(*s)];
+ if (set == 2 || set == 3) {
+ --want;
+ if (--n == 0) {
+ /* Incomplete multibyte sequence */
+ es->set = set;
+ es->want = want;
+ es->ch = 0;
+ return ((size_t)-2);
+ }
+ ++s;
+ if (*s == '\0') {
+ errno = EILSEQ;
+ return ((size_t)-1);
+ }
+ }
+ wc = (unsigned char)*s++;
+ } else {
+ set = es->set;
+ want = es->want;
+ wc = es->ch;
+ }
+ for (i = (es->want == 0) ? 1 : 0; i < MIN(want, n); i++) {
+ if (*s == '\0') {
+ errno = EILSEQ;
+ return ((size_t)-1);
+ }
+ wc = (wc << 8) | (unsigned char)*s++;
+ }
+ if (i < want) {
+ /* Incomplete multibyte sequence */
+ es->set = set;
+ es->want = want - i;
+ es->ch = wc;
+ return ((size_t)-2);
+ }
+ wc = (wc & ~CEI->mask) | CEI->bits[set];
+ if (pwc != NULL)
+ *pwc = wc;
+ es->want = 0;
+ return (wc == L'\0' ? 0 : s - os);
+}
+
+static size_t
+_EUC_wcrtomb(char * __restrict s, wchar_t wc, mbstate_t * __restrict ps)
+{
+ _EucState *es;
+ wchar_t m, nm;
+ int i, len;
+
+ 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);
+
+ m = wc & CEI->mask;
+ nm = wc & ~m;
+
+ if (m == CEI->bits[1]) {
+CodeSet1:
+ /* Codeset 1: The first byte must have 0x80 in it. */
+ i = len = CEI->count[1];
+ while (i-- > 0)
+ *s++ = (nm >> (i << 3)) | 0x80;
+ } else {
+ if (m == CEI->bits[0])
+ i = len = CEI->count[0];
+ else if (m == CEI->bits[2]) {
+ i = len = CEI->count[2];
+ *s++ = _SS2;
+ --i;
+ /* SS2 designates G2 into GR */
+ nm |= GR_BITS;
+ } else if (m == CEI->bits[3]) {
+ i = len = CEI->count[3];
+ *s++ = _SS3;
+ --i;
+ /* SS3 designates G3 into GR */
+ nm |= GR_BITS;
+ } else
+ goto CodeSet1; /* Bletch */
+ while (i-- > 0)
+ *s++ = (nm >> (i << 3)) & 0xff;
+ }
+ return (len);
+}
diff --git a/lib/libc/locale/fix_grouping.c b/lib/libc/locale/fix_grouping.c
new file mode 100644
index 0000000..2e5bc04
--- /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/gb18030.5 b/lib/libc/locale/gb18030.5
new file mode 100644
index 0000000..3a296c0
--- /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 0000000..3e43179
--- /dev/null
+++ b/lib/libc/locale/gb18030.c
@@ -0,0 +1,218 @@
+/*-
+ * 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.
+ */
+/*
+ * 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);
+
+typedef struct {
+ int count;
+ u_char bytes[4];
+} _GB18030State;
+
+int
+_GB18030_init(_RuneLocale *rl)
+{
+
+ __mbrtowc = _GB18030_mbrtowc;
+ __wcrtomb = _GB18030_wcrtomb;
+ __mbsinit = _GB18030_mbsinit;
+ _CurrentRuneLocale = rl;
+ __mb_cur_max = 4;
+
+ 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);
+}
diff --git a/lib/libc/locale/gb2312.5 b/lib/libc/locale/gb2312.5
new file mode 100644
index 0000000..5f1f712
--- /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 0000000..232daba
--- /dev/null
+++ b/lib/libc/locale/gb2312.c
@@ -0,0 +1,154 @@
+/*-
+ * Copyright (c) 2004 Tim J. Robbins. All rights reserved.
+ * Copyright (c) 2003 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.
+ */
+
+#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);
+
+typedef struct {
+ int count;
+ u_char bytes[2];
+} _GB2312State;
+
+int
+_GB2312_init(_RuneLocale *rl)
+{
+
+ _CurrentRuneLocale = rl;
+ __mbrtowc = _GB2312_mbrtowc;
+ __wcrtomb = _GB2312_wcrtomb;
+ __mbsinit = _GB2312_mbsinit;
+ __mb_cur_max = 2;
+ return (0);
+}
+
+static int
+_GB2312_mbsinit(const mbstate_t *ps)
+{
+
+ return (ps == NULL || ((const _GB2312State *)ps)->count == 0);
+}
+
+static __inline 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);
+}
diff --git a/lib/libc/locale/gbk.5 b/lib/libc/locale/gbk.5
new file mode 100644
index 0000000..cec22c6
--- /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 0000000..573fd08
--- /dev/null
+++ b/lib/libc/locale/gbk.c
@@ -0,0 +1,169 @@
+/*-
+ * 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.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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.
+ */
+
+#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"
+
+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);
+
+typedef struct {
+ wchar_t ch;
+} _GBKState;
+
+int
+_GBK_init(_RuneLocale *rl)
+{
+
+ __mbrtowc = _GBK_mbrtowc;
+ __wcrtomb = _GBK_wcrtomb;
+ __mbsinit = _GBK_mbsinit;
+ _CurrentRuneLocale = rl;
+ __mb_cur_max = 2;
+ return (0);
+}
+
+static int
+_GBK_mbsinit(const mbstate_t *ps)
+{
+
+ return (ps == NULL || ((const _GBKState *)ps)->ch == 0);
+}
+
+static __inline 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);
+}
diff --git a/lib/libc/locale/isalnum.3 b/lib/libc/locale/isalnum.3
new file mode 100644
index 0000000..d550485
--- /dev/null
+++ b/lib/libc/locale/isalnum.3
@@ -0,0 +1,107 @@
+.\" 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. 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.
+.\"
+.\" @(#)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"
+.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):
+.Pp
+.Bl -column \&000_``0''__ \&000_``0''__ \&000_``0''__ \&000_``0''__ \&000_``0''__
+.It "\&060\ ``0'' \t061\ ``1'' \t062\ ``2'' \t063\ ``3'' \t064\ ``4''"
+.It "\&065\ ``5'' \t066\ ``6'' \t067\ ``7'' \t070\ ``8'' \t071\ ``9''"
+.It "\&101\ ``A'' \t102\ ``B'' \t103\ ``C'' \t104\ ``D'' \t105\ ``E''"
+.It "\&106\ ``F'' \t107\ ``G'' \t110\ ``H'' \t111\ ``I'' \t112\ ``J''"
+.It "\&113\ ``K'' \t114\ ``L'' \t115\ ``M'' \t116\ ``N'' \t117\ ``O''"
+.It "\&120\ ``P'' \t121\ ``Q'' \t122\ ``R'' \t123\ ``S'' \t124\ ``T''"
+.It "\&125\ ``U'' \t126\ ``V'' \t127\ ``W'' \t130\ ``X'' \t131\ ``Y''"
+.It "\&132\ ``Z'' \t141\ ``a'' \t142\ ``b'' \t143\ ``c'' \t144\ ``d''"
+.It "\&145\ ``e'' \t146\ ``f'' \t147\ ``g'' \t150\ ``h'' \t151\ ``i''"
+.It "\&152\ ``j'' \t153\ ``k'' \t154\ ``l'' \t155\ ``m'' \t156\ ``n''"
+.It "\&157\ ``o'' \t160\ ``p'' \t161\ ``q'' \t162\ ``r'' \t163\ ``s''"
+.It "\&164\ ``t'' \t165\ ``u'' \t166\ ``v'' \t167\ ``w'' \t170\ ``x''"
+.It "\&171\ ``y'' \t172\ ``z''"
+.El
+.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 ascii 7
+.Sh STANDARDS
+The
+.Fn isalnum
+function conforms to
+.St -isoC .
diff --git a/lib/libc/locale/isalpha.3 b/lib/libc/locale/isalpha.3
new file mode 100644
index 0000000..1996059
--- /dev/null
+++ b/lib/libc/locale/isalpha.3
@@ -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
+.\" 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. 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.
+.\"
+.\" @(#)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"
+.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):
+.Pp
+.Bl -column \&000_``0''__ \&000_``0''__ \&000_``0''__ \&000_``0''__ \&000_``0''__
+.It "\&101\ ``A'' \t102\ ``B'' \t103\ ``C'' \t104\ ``D'' \t105\ ``E''"
+.It "\&106\ ``F'' \t107\ ``G'' \t110\ ``H'' \t111\ ``I'' \t112\ ``J''"
+.It "\&113\ ``K'' \t114\ ``L'' \t115\ ``M'' \t116\ ``N'' \t117\ ``O''"
+.It "\&120\ ``P'' \t121\ ``Q'' \t122\ ``R'' \t123\ ``S'' \t124\ ``T''"
+.It "\&125\ ``U'' \t126\ ``V'' \t127\ ``W'' \t130\ ``X'' \t131\ ``Y''"
+.It "\&132\ ``Z'' \t141\ ``a'' \t142\ ``b'' \t143\ ``c'' \t144\ ``d''"
+.It "\&145\ ``e'' \t146\ ``f'' \t147\ ``g'' \t150\ ``h'' \t151\ ``i''"
+.It "\&152\ ``j'' \t153\ ``k'' \t154\ ``l'' \t155\ ``m'' \t156\ ``n''"
+.It "\&157\ ``o'' \t160\ ``p'' \t161\ ``q'' \t162\ ``r'' \t163\ ``s''"
+.It "\&164\ ``t'' \t165\ ``u'' \t166\ ``v'' \t167\ ``w'' \t170\ ``x''"
+.It "\&171\ ``y'' \t172\ ``z''"
+.El
+.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 ascii 7
+.Sh STANDARDS
+The
+.Fn isalpha
+function conforms to
+.St -isoC .
diff --git a/lib/libc/locale/isascii.3 b/lib/libc/locale/isascii.3
new file mode 100644
index 0000000..a031d8b
--- /dev/null
+++ b/lib/libc/locale/isascii.3
@@ -0,0 +1,57 @@
+.\" Copyright (c) 1989, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. 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.
+.\"
+.\" @(#)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 0000000..2af673a
--- /dev/null
+++ b/lib/libc/locale/isblank.3
@@ -0,0 +1,88 @@
+.\" 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. 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.
+.\"
+.\" @(#)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"
+.Sh DESCRIPTION
+The
+.Fn isblank
+function tests for a space or tab character.
+For any locale, this includes the following standard characters:
+.Pp
+.Bl -column \&`\et''___ \&``\et''___
+.It "\&``\et''\t`` ''"
+.El
+.Pp
+In the "C" locale
+.Fn isblank
+successful test is limited to this characters only.
+The value of the argument must be representable as an
+.Vt "unsigned char"
+or the value of
+.Dv EOF .
+.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 ascii 7
+.Sh STANDARDS
+The
+.Fn isblank
+function
+conforms to
+.St -isoC-99 .
diff --git a/lib/libc/locale/iscntrl.3 b/lib/libc/locale/iscntrl.3
new file mode 100644
index 0000000..e8b537b
--- /dev/null
+++ b/lib/libc/locale/iscntrl.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. 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.
+.\"
+.\" @(#)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"
+.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):
+.Pp
+.Bl -column \&000_``0''__ \&000_``0''__ \&000_``0''__ \&000_``0''__ \&000_``0''__
+.It "\&000\ NUL \t001\ SOH \t002\ STX \t003\ ETX \t004\ EOT"
+.It "\&005\ ENQ \t006\ ACK \t007\ BEL \t010\ BS \t011\ HT"
+.It "\&012\ NL \t013\ VT \t014\ NP \t015\ CR \t016\ SO"
+.It "\&017\ SI \t020\ DLE \t021\ DC1 \t022\ DC2 \t023\ DC3"
+.It "\&024\ DC4 \t025\ NAK \t026\ SYN \t027\ ETB \t030\ CAN"
+.It "\&031\ EM \t032\ SUB \t033\ ESC \t034\ FS \t035\ GS"
+.It "\&036\ RS \t037\ US \t177\ DEL"
+.El
+.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 ascii 7
+.Sh STANDARDS
+The
+.Fn iscntrl
+function conforms to
+.St -isoC .
diff --git a/lib/libc/locale/isctype.c b/lib/libc/locale/isctype.c
new file mode 100644
index 0000000..d25772b
--- /dev/null
+++ b/lib/libc/locale/isctype.c
@@ -0,0 +1,233 @@
+/*
+ * 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.
+ * 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.
+ */
+
+#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(c)
+ int c;
+{
+ return (__maskrune(c, 0xFF));
+}
+
+#undef isalnum
+int
+isalnum(c)
+ int c;
+{
+ return (__istype(c, _CTYPE_A|_CTYPE_D));
+}
+
+#undef isalpha
+int
+isalpha(c)
+ int c;
+{
+ return (__istype(c, _CTYPE_A));
+}
+
+#undef isascii
+int
+isascii(c)
+ int c;
+{
+ return ((c & ~0x7F) == 0);
+}
+
+#undef isblank
+int
+isblank(c)
+ int c;
+{
+ return (__istype(c, _CTYPE_B));
+}
+
+#undef iscntrl
+int
+iscntrl(c)
+ int c;
+{
+ return (__istype(c, _CTYPE_C));
+}
+
+#undef isdigit
+int
+isdigit(c)
+ int c;
+{
+ return (__isctype(c, _CTYPE_D));
+}
+
+#undef isgraph
+int
+isgraph(c)
+ int c;
+{
+ return (__istype(c, _CTYPE_G));
+}
+
+#undef ishexnumber
+int
+ishexnumber(c)
+ int c;
+{
+ return (__istype(c, _CTYPE_X));
+}
+
+#undef isideogram
+int
+isideogram(c)
+ int c;
+{
+ return (__istype(c, _CTYPE_I));
+}
+
+#undef islower
+int
+islower(c)
+ int c;
+{
+ return (__istype(c, _CTYPE_L));
+}
+
+#undef isnumber
+int
+isnumber(c)
+ int c;
+{
+ return (__istype(c, _CTYPE_D));
+}
+
+#undef isphonogram
+int
+isphonogram(c)
+ int c;
+{
+ return (__istype(c, _CTYPE_Q));
+}
+
+#undef isprint
+int
+isprint(c)
+ int c;
+{
+ return (__istype(c, _CTYPE_R));
+}
+
+#undef ispunct
+int
+ispunct(c)
+ int c;
+{
+ return (__istype(c, _CTYPE_P));
+}
+
+#undef isrune
+int
+isrune(c)
+ int c;
+{
+ return (__istype(c, 0xFFFFFF00L));
+}
+
+#undef isspace
+int
+isspace(c)
+ int c;
+{
+ return (__istype(c, _CTYPE_S));
+}
+
+#undef isspecial
+int
+isspecial(c)
+ int c;
+{
+ return (__istype(c, _CTYPE_T));
+}
+
+#undef isupper
+int
+isupper(c)
+ int c;
+{
+ return (__istype(c, _CTYPE_U));
+}
+
+#undef isxdigit
+int
+isxdigit(c)
+ int c;
+{
+ return (__isctype(c, _CTYPE_X));
+}
+
+#undef toascii
+int
+toascii(c)
+ int c;
+{
+ return (c & 0x7F);
+}
+
+#undef tolower
+int
+tolower(c)
+ int c;
+{
+ return (__tolower(c));
+}
+
+#undef toupper
+int
+toupper(c)
+ int c;
+{
+ return (__toupper(c));
+}
+
diff --git a/lib/libc/locale/isdigit.3 b/lib/libc/locale/isdigit.3
new file mode 100644
index 0000000..8bcf083
--- /dev/null
+++ b/lib/libc/locale/isdigit.3
@@ -0,0 +1,106 @@
+.\" 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. 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.
+.\"
+.\" @(#)isdigit.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd July 17, 2005
+.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"
+.Sh DESCRIPTION
+The
+.Fn isdigit
+function tests for a decimal digit character.
+Regardless of locale, this includes the following characters only:
+.Pp
+.Bl -column \&``0''______ \&``0''______ \&``0''______ \&``0''______ \&``0''______
+.It "\&``0''\t``1''\t``2''\t``3''\t``4''"
+.It "\&``5''\t``6''\t``7''\t``8''\t``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 .
+.Sh RETURN VALUES
+The
+.Fn isdigit
+and
+.Fn isnumber
+functions return 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 iswdigit
+function should be used instead.
+.Sh SEE ALSO
+.Xr ctype 3 ,
+.Xr iswdigit 3 ,
+.Xr multibyte 3 ,
+.Xr ascii 7
+.Sh STANDARDS
+The
+.Fn isdigit
+function conforms to
+.St -isoC .
+.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 0000000..f5cc2eb
--- /dev/null
+++ b/lib/libc/locale/isgraph.3
@@ -0,0 +1,110 @@
+.\" 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. 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.
+.\"
+.\" @(#)isgraph.3 8.2 (Berkeley) 12/11/93
+.\" $FreeBSD$
+.\"
+.Dd July 17, 2005
+.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"
+.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):
+.Pp
+.Bl -column \&000_``0''__ \&000_``0''__ \&000_``0''__ \&000_``0''__ \&000_``0''__
+.It "\&041\ ``!'' \t042\ ``""'' \t043\ ``#'' \t044\ ``$'' \t045\ ``%''"
+.It "\&046\ ``&'' \t047\ ``''' \t050\ ``('' \t051\ ``)'' \t052\ ``*''"
+.It "\&053\ ``+'' \t054\ ``,'' \t055\ ``-'' \t056\ ``.'' \t057\ ``/''"
+.It "\&060\ ``0'' \t061\ ``1'' \t062\ ``2'' \t063\ ``3'' \t064\ ``4''"
+.It "\&065\ ``5'' \t066\ ``6'' \t067\ ``7'' \t070\ ``8'' \t071\ ``9''"
+.It "\&072\ ``:'' \t073\ ``;'' \t074\ ``<'' \t075\ ``='' \t076\ ``>''"
+.It "\&077\ ``?'' \t100\ ``@'' \t101\ ``A'' \t102\ ``B'' \t103\ ``C''"
+.It "\&104\ ``D'' \t105\ ``E'' \t106\ ``F'' \t107\ ``G'' \t110\ ``H''"
+.It "\&111\ ``I'' \t112\ ``J'' \t113\ ``K'' \t114\ ``L'' \t115\ ``M''"
+.It "\&116\ ``N'' \t117\ ``O'' \t120\ ``P'' \t121\ ``Q'' \t122\ ``R''"
+.It "\&123\ ``S'' \t124\ ``T'' \t125\ ``U'' \t126\ ``V'' \t127\ ``W''"
+.It "\&130\ ``X'' \t131\ ``Y'' \t132\ ``Z'' \t133\ ``['' \t134\ ``\e\|''"
+.It "\&135\ ``]'' \t136\ ``^'' \t137\ ``_'' \t140\ ```'' \t141\ ``a''"
+.It "\&142\ ``b'' \t143\ ``c'' \t144\ ``d'' \t145\ ``e'' \t146\ ``f''"
+.It "\&147\ ``g'' \t150\ ``h'' \t151\ ``i'' \t152\ ``j'' \t153\ ``k''"
+.It "\&154\ ``l'' \t155\ ``m'' \t156\ ``n'' \t157\ ``o'' \t160\ ``p''"
+.It "\&161\ ``q'' \t162\ ``r'' \t163\ ``s'' \t164\ ``t'' \t165\ ``u''"
+.It "\&166\ ``v'' \t167\ ``w'' \t170\ ``x'' \t171\ ``y'' \t172\ ``z''"
+.It "\&173\ ``{'' \t174\ ``|'' \t175\ ``}'' \t176\ ``~''"
+.El
+.Sh RETURN VALUES
+The
+.Fn isgraph
+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 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 .
diff --git a/lib/libc/locale/isideogram.3 b/lib/libc/locale/isideogram.3
new file mode 100644
index 0000000..cbaa625
--- /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 0000000..5d7c378
--- /dev/null
+++ b/lib/libc/locale/islower.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. 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.
+.\"
+.\" @(#)islower.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd July 17, 2005
+.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"
+.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):
+.Pp
+.Bl -column \&000_``0''__ \&000_``0''__ \&000_``0''__ \&000_``0''__ \&000_``0''__
+.It "\&141\ ``a'' \t142\ ``b'' \t143\ ``c'' \t144\ ``d'' \t145\ ``e''"
+.It "\&146\ ``f'' \t147\ ``g'' \t150\ ``h'' \t151\ ``i'' \t152\ ``j''"
+.It "\&153\ ``k'' \t154\ ``l'' \t155\ ``m'' \t156\ ``n'' \t157\ ``o''"
+.It "\&160\ ``p'' \t161\ ``q'' \t162\ ``r'' \t163\ ``s'' \t164\ ``t''"
+.It "\&165\ ``u'' \t166\ ``v'' \t167\ ``w'' \t170\ ``x'' \t171\ ``y''"
+.It "\&172\ ``z''"
+.El
+.Sh RETURN VALUES
+The
+.Fn islower
+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 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 .
diff --git a/lib/libc/locale/isphonogram.3 b/lib/libc/locale/isphonogram.3
new file mode 100644
index 0000000..b0d82c4
--- /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 0000000..5217f13
--- /dev/null
+++ b/lib/libc/locale/isprint.3
@@ -0,0 +1,108 @@
+.\" 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. 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.
+.\"
+.\" @(#)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):
+.Pp
+.Bl -column \&000_``0''__ \&000_``0''__ \&000_``0''__ \&000_``0''__ \&000_``0''__
+.It "\&040\ sp \t041\ ``!'' \t042\ ``""'' \t043\ ``#'' \t044\ ``$''"
+.It "\&045\ ``%'' \t046\ ``&'' \t047\ ``''' \t050\ ``('' \t051\ ``)''"
+.It "\&052\ ``*'' \t053\ ``+'' \t054\ ``,'' \t055\ ``-'' \t056\ ``.''"
+.It "\&057\ ``/'' \t060\ ``0'' \t061\ ``1'' \t062\ ``2'' \t063\ ``3''"
+.It "\&064\ ``4'' \t065\ ``5'' \t066\ ``6'' \t067\ ``7'' \t070\ ``8''"
+.It "\&071\ ``9'' \t072\ ``:'' \t073\ ``;'' \t074\ ``<'' \t075\ ``=''"
+.It "\&076\ ``>'' \t077\ ``?'' \t100\ ``@'' \t101\ ``A'' \t102\ ``B''"
+.It "\&103\ ``C'' \t104\ ``D'' \t105\ ``E'' \t106\ ``F'' \t107\ ``G''"
+.It "\&110\ ``H'' \t111\ ``I'' \t112\ ``J'' \t113\ ``K'' \t114\ ``L''"
+.It "\&115\ ``M'' \t116\ ``N'' \t117\ ``O'' \t120\ ``P'' \t121\ ``Q''"
+.It "\&122\ ``R'' \t123\ ``S'' \t124\ ``T'' \t125\ ``U'' \t126\ ``V''"
+.It "\&127\ ``W'' \t130\ ``X'' \t131\ ``Y'' \t132\ ``Z'' \t133\ ``[''"
+.It "\&134\ ``\e\|'' \t135\ ``]'' \t136\ ``^'' \t137\ ``_'' \t140\ ```''"
+.It "\&141\ ``a'' \t142\ ``b'' \t143\ ``c'' \t144\ ``d'' \t145\ ``e''"
+.It "\&146\ ``f'' \t147\ ``g'' \t150\ ``h'' \t151\ ``i'' \t152\ ``j''"
+.It "\&153\ ``k'' \t154\ ``l'' \t155\ ``m'' \t156\ ``n'' \t157\ ``o''"
+.It "\&160\ ``p'' \t161\ ``q'' \t162\ ``r'' \t163\ ``s'' \t164\ ``t''"
+.It "\&165\ ``u'' \t166\ ``v'' \t167\ ``w'' \t170\ ``x'' \t171\ ``y''"
+.It "\&172\ ``z'' \t173\ ``{'' \t174\ ``|'' \t175\ ``}'' \t176\ ``~''"
+.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 0000000..80acf15
--- /dev/null
+++ b/lib/libc/locale/ispunct.3
@@ -0,0 +1,100 @@
+.\" 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. 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.
+.\"
+.\" @(#)ispunct.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd July 17, 2005
+.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"
+.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):
+.Pp
+.Bl -column \&000_``0''__ \&000_``0''__ \&000_``0''__ \&000_``0''__ \&000_``0''__
+.It "\&041\ ``!'' \t042\ ``""'' \t043\ ``#'' \t044\ ``$'' \t045\ ``%''"
+.It "\&046\ ``&'' \t047\ ``''' \t050\ ``('' \t051\ ``)'' \t052\ ``*''"
+.It "\&053\ ``+'' \t054\ ``,'' \t055\ ``-'' \t056\ ``.'' \t057\ ``/''"
+.It "\&072\ ``:'' \t073\ ``;'' \t074\ ``<'' \t075\ ``='' \t076\ ``>''"
+.It "\&077\ ``?'' \t100\ ``@'' \t133\ ``['' \t134\ ``\e\|'' \t135\ ``]''"
+.It "\&136\ ``^'' \t137\ ``_'' \t140\ ```'' \t173\ ``{'' \t174\ ``|''"
+.It "\&175\ ``}'' \t176\ ``~''"
+.El
+.Sh RETURN VALUES
+The
+.Fn ispunct
+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 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 .
diff --git a/lib/libc/locale/isrune.3 b/lib/libc/locale/isrune.3
new file mode 100644
index 0000000..424c367
--- /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 0000000..5a77015
--- /dev/null
+++ b/lib/libc/locale/isspace.3
@@ -0,0 +1,92 @@
+.\" 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. 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.
+.\"
+.\" @(#)isspace.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd July 17, 2005
+.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"
+.Sh DESCRIPTION
+The
+.Fn isspace
+function tests for the white-space characters.
+For any locale, this includes the following standard characters:
+.Pp
+.Bl -column \&`\et''___ \&``\et''___ \&``\et''___ \&``\et''___ \&``\et''___ \&``\et''___
+.It "\&``\et''\t``\en''\t``\ev''\t``\ef''\t``\er''\t`` ''"
+.El
+.Pp
+In the "C" locale
+.Fn isspace
+successful test is limited to this characters only.
+The value of the argument must be representable as an
+.Vt "unsigned char"
+or the value of
+.Dv EOF .
+.Sh RETURN VALUES
+The
+.Fn isspace
+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 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 .
diff --git a/lib/libc/locale/isspecial.3 b/lib/libc/locale/isspecial.3
new file mode 100644
index 0000000..de361d2
--- /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 0000000..b92fe7c
--- /dev/null
+++ b/lib/libc/locale/isupper.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. 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.
+.\"
+.\" @(#)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):
+.Pp
+.Bl -column \&000_``0''__ \&000_``0''__ \&000_``0''__ \&000_``0''__ \&000_``0''__
+.It "\&101\ ``A'' \t102\ ``B'' \t103\ ``C'' \t104\ ``D'' \t105\ ``E''"
+.It "\&106\ ``F'' \t107\ ``G'' \t110\ ``H'' \t111\ ``I'' \t112\ ``J''"
+.It "\&113\ ``K'' \t114\ ``L'' \t115\ ``M'' \t116\ ``N'' \t117\ ``O''"
+.It "\&120\ ``P'' \t121\ ``Q'' \t122\ ``R'' \t123\ ``S'' \t124\ ``T''"
+.It "\&125\ ``U'' \t126\ ``V'' \t127\ ``W'' \t130\ ``X'' \t131\ ``Y''"
+.It "\&132\ ``Z''"
+.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 0000000..8a20532
--- /dev/null
+++ b/lib/libc/locale/iswalnum.3
@@ -0,0 +1,162 @@
+.\" $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.
+.\" 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.
+.\"
+.\" @(#)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/iswctype.c b/lib/libc/locale/iswctype.c
new file mode 100644
index 0000000..05d1329
--- /dev/null
+++ b/lib/libc/locale/iswctype.c
@@ -0,0 +1,214 @@
+/*
+ * 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.
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <wctype.h>
+
+#undef iswalnum
+int
+iswalnum(wc)
+ wint_t wc;
+{
+ return (__istype(wc, _CTYPE_A|_CTYPE_D));
+}
+
+#undef iswalpha
+int
+iswalpha(wc)
+ wint_t wc;
+{
+ return (__istype(wc, _CTYPE_A));
+}
+
+#undef iswascii
+int
+iswascii(wc)
+ wint_t wc;
+{
+ return ((wc & ~0x7F) == 0);
+}
+
+#undef iswblank
+int
+iswblank(wc)
+ wint_t wc;
+{
+ return (__istype(wc, _CTYPE_B));
+}
+
+#undef iswcntrl
+int
+iswcntrl(wc)
+ wint_t wc;
+{
+ return (__istype(wc, _CTYPE_C));
+}
+
+#undef iswdigit
+int
+iswdigit(wc)
+ wint_t wc;
+{
+ return (__isctype(wc, _CTYPE_D));
+}
+
+#undef iswgraph
+int
+iswgraph(wc)
+ wint_t wc;
+{
+ return (__istype(wc, _CTYPE_G));
+}
+
+#undef iswhexnumber
+int
+iswhexnumber(wc)
+ wint_t wc;
+{
+ return (__istype(wc, _CTYPE_X));
+}
+
+#undef iswideogram
+int
+iswideogram(wc)
+ wint_t wc;
+{
+ return (__istype(wc, _CTYPE_I));
+}
+
+#undef iswlower
+int
+iswlower(wc)
+ wint_t wc;
+{
+ return (__istype(wc, _CTYPE_L));
+}
+
+#undef iswnumber
+int
+iswnumber(wc)
+ wint_t wc;
+{
+ return (__istype(wc, _CTYPE_D));
+}
+
+#undef iswphonogram
+int
+iswphonogram(wc)
+ wint_t wc;
+{
+ return (__istype(wc, _CTYPE_Q));
+}
+
+#undef iswprint
+int
+iswprint(wc)
+ wint_t wc;
+{
+ return (__istype(wc, _CTYPE_R));
+}
+
+#undef iswpunct
+int
+iswpunct(wc)
+ wint_t wc;
+{
+ return (__istype(wc, _CTYPE_P));
+}
+
+#undef iswrune
+int
+iswrune(wc)
+ wint_t wc;
+{
+ return (__istype(wc, 0xFFFFFF00L));
+}
+
+#undef iswspace
+int
+iswspace(wc)
+ wint_t wc;
+{
+ return (__istype(wc, _CTYPE_S));
+}
+
+#undef iswspecial
+int
+iswspecial(wc)
+ wint_t wc;
+{
+ return (__istype(wc, _CTYPE_T));
+}
+
+#undef iswupper
+int
+iswupper(wc)
+ wint_t wc;
+{
+ return (__istype(wc, _CTYPE_U));
+}
+
+#undef iswxdigit
+int
+iswxdigit(wc)
+ wint_t wc;
+{
+ return (__isctype(wc, _CTYPE_X));
+}
+
+#undef towlower
+wint_t
+towlower(wc)
+ wint_t wc;
+{
+ return (__tolower(wc));
+}
+
+#undef towupper
+wint_t
+towupper(wc)
+ 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 0000000..8e3d9b9
--- /dev/null
+++ b/lib/libc/locale/isxdigit.3
@@ -0,0 +1,106 @@
+.\" 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. 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.
+.\"
+.\" @(#)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:
+.Pp
+.Bl -column \&``0''______ \&``0''______ \&``0''______ \&``0''______ \&``0''______
+.It "\&``0''\t``1''\t``2''\t``3''\t``4''"
+.It "\&``5''\t``6''\t``7''\t``8''\t``9''"
+.It "\&``A''\t``B''\t``C''\t``D''\t``E''"
+.It "\&``F''\t``a''\t``b''\t``c''\t``d''"
+.It "\&``e''\t``f''"
+.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 0000000..ea7b388
--- /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)) < 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 0000000..45f7339
--- /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 0000000..3498be2
--- /dev/null
+++ b/lib/libc/locale/lmessages.c
@@ -0,0 +1,91 @@
+/*
+ * 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 <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 *))
+
+static char empty[] = "";
+
+static const struct lc_messages_T _C_messages_locale = {
+ "^[yY]" , /* yesexpr */
+ "^[nN]" , /* noexpr */
+ "yes" , /* yesstr */
+ "no" /* nostr */
+};
+
+static struct lc_messages_T _messages_locale;
+static int _messages_using_locale;
+static char *_messages_locale_buf;
+
+int
+__messages_load_locale(const char *name)
+{
+ int ret;
+
+ ret = __part_load_locale(name, &_messages_using_locale,
+ &_messages_locale_buf, "LC_MESSAGES",
+ LCMESSAGES_SIZE_FULL, LCMESSAGES_SIZE_MIN,
+ (const char **)&_messages_locale);
+ if (ret == _LDP_LOADED) {
+ if (_messages_locale.yesstr == NULL)
+ _messages_locale.yesstr = empty;
+ if (_messages_locale.nostr == NULL)
+ _messages_locale.nostr = empty;
+ }
+ return (ret);
+}
+
+struct lc_messages_T *
+__get_current_messages_locale(void)
+{
+ return (_messages_using_locale
+ ? &_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 0000000..41dcfa9
--- /dev/null
+++ b/lib/libc/locale/lmessages.h
@@ -0,0 +1,42 @@
+/*-
+ * 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 _LMESSAGES_H_
+#define _LMESSAGES_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(void);
+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 0000000..8d55ab2
--- /dev/null
+++ b/lib/libc/locale/lmonetary.c
@@ -0,0 +1,192 @@
+/*
+ * 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 <limits.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#include "ldpart.h"
+#include "lmonetary.h"
+
+extern int __mlocale_changed;
+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 */
+};
+
+static struct lc_monetary_T _monetary_locale;
+static int _monetary_using_locale;
+static char *_monetary_locale_buf;
+
+static char
+cnv(const char *str)
+{
+ int i = strtol(str, NULL, 10);
+
+ if (i == -1)
+ i = CHAR_MAX;
+ return ((char)i);
+}
+
+int
+__monetary_load_locale(const char *name)
+{
+ int ret;
+
+ ret = __part_load_locale(name, &_monetary_using_locale,
+ &_monetary_locale_buf, "LC_MONETARY",
+ LCMONETARY_SIZE_FULL, LCMONETARY_SIZE_MIN,
+ (const char **)&_monetary_locale);
+ if (ret != _LDP_ERROR)
+ __mlocale_changed = 1;
+ if (ret == _LDP_LOADED) {
+ _monetary_locale.mon_grouping =
+ __fix_locale_grouping_str(_monetary_locale.mon_grouping);
+
+#define M_ASSIGN_CHAR(NAME) (((char *)_monetary_locale.NAME)[0] = \
+ cnv(_monetary_locale.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 (_monetary_locale.int_##NAME == NULL) \
+ _monetary_locale.int_##NAME = \
+ _monetary_locale.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);
+}
+
+struct lc_monetary_T *
+__get_current_monetary_locale(void)
+{
+ return (_monetary_using_locale
+ ? &_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 0000000..45ec323
--- /dev/null
+++ b/lib/libc/locale/lmonetary.h
@@ -0,0 +1,59 @@
+/*-
+ * 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 _LMONETARY_H_
+#define _LMONETARY_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 lc_monetary_T *__get_current_monetary_locale(void);
+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 0000000..d4ed04f
--- /dev/null
+++ b/lib/libc/locale/lnumeric.c
@@ -0,0 +1,93 @@
+/*
+ * 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 <limits.h>
+
+#include "ldpart.h"
+#include "lnumeric.h"
+
+extern int __nlocale_changed;
+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 struct lc_numeric_T _numeric_locale;
+static int _numeric_using_locale;
+static char *_numeric_locale_buf;
+
+int
+__numeric_load_locale(const char *name)
+{
+ int ret;
+
+ ret = __part_load_locale(name, &_numeric_using_locale,
+ &_numeric_locale_buf, "LC_NUMERIC",
+ LCNUMERIC_SIZE, LCNUMERIC_SIZE,
+ (const char **)&_numeric_locale);
+ if (ret != _LDP_ERROR)
+ __nlocale_changed = 1;
+ if (ret == _LDP_LOADED) {
+ /* Can't be empty according to C99 */
+ if (*_numeric_locale.decimal_point == '\0')
+ _numeric_locale.decimal_point =
+ _C_numeric_locale.decimal_point;
+ _numeric_locale.grouping =
+ __fix_locale_grouping_str(_numeric_locale.grouping);
+ }
+ return (ret);
+}
+
+struct lc_numeric_T *
+__get_current_numeric_locale(void)
+{
+ return (_numeric_using_locale
+ ? &_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 0000000..cc6965b
--- /dev/null
+++ b/lib/libc/locale/lnumeric.h
@@ -0,0 +1,41 @@
+/*-
+ * 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 _LNUMERIC_H_
+#define _LNUMERIC_H_
+
+struct lc_numeric_T {
+ const char *decimal_point;
+ const char *thousands_sep;
+ const char *grouping;
+};
+
+struct lc_numeric_T *__get_current_numeric_locale(void);
+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 0000000..d3a5783
--- /dev/null
+++ b/lib/libc/locale/localeconv.3
@@ -0,0 +1,226 @@
+.\" 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.
+.\" 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.
+.\"
+.\" 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"
+.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:
+.Pp
+.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.
+.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 .
+.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 0000000..97c22dd
--- /dev/null
+++ b/lib/libc/locale/localeconv.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2001 Alexey Zelkin <phantom@FreeBSD.org>
+ * 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. 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.
+ */
+
+#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.
+ */
+int __mlocale_changed = 1;
+int __nlocale_changed = 1;
+
+/*
+ * Return the current locale conversion.
+ */
+struct lconv *
+localeconv()
+{
+ static struct lconv ret;
+
+ if (__mlocale_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();
+ 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);
+ __mlocale_changed = 0;
+ }
+
+ if (__nlocale_changed) {
+ /* LC_NUMERIC part */
+ struct lc_numeric_T * nptr;
+
+#define N_ASSIGN_STR(NAME) (ret.NAME = (char*)nptr->NAME)
+
+ nptr = __get_current_numeric_locale();
+ N_ASSIGN_STR(decimal_point);
+ N_ASSIGN_STR(thousands_sep);
+ N_ASSIGN_STR(grouping);
+ __nlocale_changed = 0;
+ }
+
+ return (&ret);
+}
diff --git a/lib/libc/locale/mblen.3 b/lib/libc/locale/mblen.3
new file mode 100644
index 0000000..26f2c52
--- /dev/null
+++ b/lib/libc/locale/mblen.3
@@ -0,0 +1,110 @@
+.\" 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.
+.\" 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.
+.\"
+.\" 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 0000000..4a2cc5c
--- /dev/null
+++ b/lib/libc/locale/mblen.c
@@ -0,0 +1,50 @@
+/*-
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h>
+#include <wchar.h>
+#include "mblocal.h"
+
+int
+mblen(const char *s, size_t n)
+{
+ static const mbstate_t initial;
+ static mbstate_t mbs;
+ size_t rval;
+
+ if (s == NULL) {
+ /* No support for state dependent encodings. */
+ mbs = initial;
+ return (0);
+ }
+ rval = __mbrtowc(NULL, s, n, &mbs);
+ if (rval == (size_t)-1 || rval == (size_t)-2)
+ return (-1);
+ return ((int)rval);
+}
diff --git a/lib/libc/locale/mblocal.h b/lib/libc/locale/mblocal.h
new file mode 100644
index 0000000..e424ebe
--- /dev/null
+++ b/lib/libc/locale/mblocal.h
@@ -0,0 +1,61 @@
+/*-
+ * 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$
+ */
+
+#ifndef _MBLOCAL_H_
+#define _MBLOCAL_H_
+
+/*
+ * Rune initialization function prototypes.
+ */
+int _none_init(_RuneLocale *);
+int _UTF8_init(_RuneLocale *);
+int _EUC_init(_RuneLocale *);
+int _GB18030_init(_RuneLocale *);
+int _GB2312_init(_RuneLocale *);
+int _GBK_init(_RuneLocale *);
+int _BIG5_init(_RuneLocale *);
+int _MSKanji_init(_RuneLocale *);
+
+/*
+ * Conversion function pointers for current encoding.
+ */
+extern size_t (*__mbrtowc)(wchar_t * __restrict, const char * __restrict,
+ size_t, mbstate_t * __restrict);
+extern int (*__mbsinit)(const mbstate_t *);
+extern size_t (*__mbsnrtowcs)(wchar_t * __restrict, const char ** __restrict,
+ size_t, size_t, mbstate_t * __restrict);
+extern size_t (*__wcrtomb)(char * __restrict, wchar_t, mbstate_t * __restrict);
+extern size_t (*__wcsnrtombs)(char * __restrict, const wchar_t ** __restrict,
+ size_t, size_t, mbstate_t * __restrict);
+
+extern size_t __mbsnrtowcs_std(wchar_t * __restrict, const char ** __restrict,
+ size_t, size_t, mbstate_t * __restrict);
+extern size_t __wcsnrtombs_std(char * __restrict, const wchar_t ** __restrict,
+ size_t, size_t, mbstate_t * __restrict);
+
+#endif /* _MBLOCAL_H_ */
diff --git a/lib/libc/locale/mbrlen.3 b/lib/libc/locale/mbrlen.3
new file mode 100644
index 0000000..524d2c7
--- /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 0000000..b4c3a04
--- /dev/null
+++ b/lib/libc/locale/mbrlen.c
@@ -0,0 +1,41 @@
+/*-
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <wchar.h>
+#include "mblocal.h"
+
+size_t
+mbrlen(const char * __restrict s, size_t n, mbstate_t * __restrict ps)
+{
+ static mbstate_t mbs;
+
+ if (ps == NULL)
+ ps = &mbs;
+ return (__mbrtowc(NULL, s, n, ps));
+}
diff --git a/lib/libc/locale/mbrtowc.3 b/lib/libc/locale/mbrtowc.3
new file mode 100644
index 0000000..10160d1
--- /dev/null
+++ b/lib/libc/locale/mbrtowc.3
@@ -0,0 +1,139 @@
+.\" 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 MBRTOWC 3
+.Os
+.Sh NAME
+.Nm mbrtowc
+.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 pwc" "const char * restrict s" "size_t n"
+.Fa "mbstate_t * restrict ps"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn mbrtowc
+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.
+If a character can be completed, and
+.Fa pwc
+is not
+.Dv NULL ,
+the wide character which is represented by
+.Fa s
+is stored in the
+.Vt wchar_t
+it points to.
+.Pp
+If
+.Fa s
+is
+.Dv NULL ,
+.Fn mbrtowc
+behaves as if
+.Fa pwc
+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 ,
+.Fn mbrtowc
+uses an internal, static
+.Vt mbstate_t
+object, which is initialized to the initial conversion state
+at program startup.
+.Sh RETURN VALUES
+The
+.Fn mbrtowc
+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 mbrtowc
+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 ERRORS
+The
+.Fn mbrtowc
+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 mbtowc 3 ,
+.Xr multibyte 3 ,
+.Xr setlocale 3 ,
+.Xr wcrtomb 3
+.Sh STANDARDS
+The
+.Fn mbrtowc
+function conforms to
+.St -isoC-99 .
diff --git a/lib/libc/locale/mbrtowc.c b/lib/libc/locale/mbrtowc.c
new file mode 100644
index 0000000..42d5f7a
--- /dev/null
+++ b/lib/libc/locale/mbrtowc.c
@@ -0,0 +1,42 @@
+/*-
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <wchar.h>
+#include "mblocal.h"
+
+size_t
+mbrtowc(wchar_t * __restrict pwc, const char * __restrict s,
+ size_t n, mbstate_t * __restrict ps)
+{
+ static mbstate_t mbs;
+
+ if (ps == NULL)
+ ps = &mbs;
+ return (__mbrtowc(pwc, s, n, ps));
+}
diff --git a/lib/libc/locale/mbsinit.3 b/lib/libc/locale/mbsinit.3
new file mode 100644
index 0000000..afc2500
--- /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 0000000..24408c7
--- /dev/null
+++ b/lib/libc/locale/mbsinit.c
@@ -0,0 +1,38 @@
+/*-
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <wchar.h>
+#include "mblocal.h"
+
+int
+mbsinit(const mbstate_t *ps)
+{
+
+ return (__mbsinit(ps));
+}
diff --git a/lib/libc/locale/mbsnrtowcs.c b/lib/libc/locale/mbsnrtowcs.c
new file mode 100644
index 0000000..5284087
--- /dev/null
+++ b/lib/libc/locale/mbsnrtowcs.c
@@ -0,0 +1,91 @@
+/*-
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include "mblocal.h"
+
+size_t
+mbsnrtowcs(wchar_t * __restrict dst, const char ** __restrict src,
+ size_t nms, size_t len, mbstate_t * __restrict ps)
+{
+ static mbstate_t mbs;
+
+ if (ps == NULL)
+ ps = &mbs;
+ return (__mbsnrtowcs(dst, src, nms, len, ps));
+}
+
+size_t
+__mbsnrtowcs_std(wchar_t * __restrict dst, const char ** __restrict src,
+ size_t nms, size_t len, mbstate_t * __restrict ps)
+{
+ const char *s;
+ size_t nchr;
+ wchar_t wc;
+ size_t nb;
+
+ s = *src;
+ nchr = 0;
+
+ if (dst == NULL) {
+ for (;;) {
+ if ((nb = __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*/
+ }
+
+ while (len-- > 0) {
+ if ((nb = __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);
+}
diff --git a/lib/libc/locale/mbsrtowcs.3 b/lib/libc/locale/mbsrtowcs.3
new file mode 100644
index 0000000..eaf9f90
--- /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 0000000..1239c82
--- /dev/null
+++ b/lib/libc/locale/mbsrtowcs.c
@@ -0,0 +1,45 @@
+/*-
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include "mblocal.h"
+
+size_t
+mbsrtowcs(wchar_t * __restrict dst, const char ** __restrict src, size_t len,
+ mbstate_t * __restrict ps)
+{
+ static mbstate_t mbs;
+
+ if (ps == NULL)
+ ps = &mbs;
+ return (__mbsnrtowcs(dst, src, SIZE_T_MAX, len, ps));
+}
diff --git a/lib/libc/locale/mbstowcs.3 b/lib/libc/locale/mbstowcs.3
new file mode 100644
index 0000000..2e344f8
--- /dev/null
+++ b/lib/libc/locale/mbstowcs.3
@@ -0,0 +1,91 @@
+.\" 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.
+.\" 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.
+.\"
+.\" 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 0000000..ad259d8
--- /dev/null
+++ b/lib/libc/locale/mbstowcs.c
@@ -0,0 +1,43 @@
+/*-
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <limits.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include "mblocal.h"
+
+size_t
+mbstowcs(wchar_t * __restrict pwcs, const char * __restrict s, size_t n)
+{
+ static const mbstate_t initial;
+ mbstate_t mbs;
+
+ mbs = initial;
+ return (__mbsnrtowcs(pwcs, &s, SIZE_T_MAX, n, &mbs));
+}
diff --git a/lib/libc/locale/mbtowc.3 b/lib/libc/locale/mbtowc.3
new file mode 100644
index 0000000..1d5783a
--- /dev/null
+++ b/lib/libc/locale/mbtowc.3
@@ -0,0 +1,118 @@
+.\" 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.
+.\" 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.
+.\"
+.\" 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 0000000..ad5b735
--- /dev/null
+++ b/lib/libc/locale/mbtowc.c
@@ -0,0 +1,50 @@
+/*-
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h>
+#include <wchar.h>
+#include "mblocal.h"
+
+int
+mbtowc(wchar_t * __restrict pwc, const char * __restrict s, size_t n)
+{
+ static const mbstate_t initial;
+ static mbstate_t mbs;
+ size_t rval;
+
+ if (s == NULL) {
+ /* No support for state dependent encodings. */
+ mbs = initial;
+ return (0);
+ }
+ rval = __mbrtowc(pwc, s, n, &mbs);
+ if (rval == (size_t)-1 || rval == (size_t)-2)
+ return (-1);
+ return ((int)rval);
+}
diff --git a/lib/libc/locale/mskanji.5 b/lib/libc/locale/mskanji.5
new file mode 100644
index 0000000..8ebaccd
--- /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 0000000..aba87e7
--- /dev/null
+++ b/lib/libc/locale/mskanji.c
@@ -0,0 +1,157 @@
+/*
+ * 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
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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"
+
+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);
+
+typedef struct {
+ wchar_t ch;
+} _MSKanjiState;
+
+int
+_MSKanji_init(_RuneLocale *rl)
+{
+
+ __mbrtowc = _MSKanji_mbrtowc;
+ __wcrtomb = _MSKanji_wcrtomb;
+ __mbsinit = _MSKanji_mbsinit;
+ _CurrentRuneLocale = rl;
+ __mb_cur_max = 2;
+ 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);
+}
diff --git a/lib/libc/locale/multibyte.3 b/lib/libc/locale/multibyte.3
new file mode 100644
index 0000000..02b6342
--- /dev/null
+++ b/lib/libc/locale/multibyte.3
@@ -0,0 +1,146 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)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/nextwctype.3 b/lib/libc/locale/nextwctype.3
new file mode 100644
index 0000000..0f6f880
--- /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 0000000..9363b0a
--- /dev/null
+++ b/lib/libc/locale/nextwctype.c
@@ -0,0 +1,90 @@
+/*-
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <runetype.h>
+#include <wchar.h>
+#include <wctype.h>
+
+wint_t
+nextwctype(wint_t wc, wctype_t wct)
+{
+ size_t lim;
+ _RuneRange *rr = &_CurrentRuneLocale->__runetype_ext;
+ _RuneEntry *base, *re;
+ int noinc;
+
+ noinc = 0;
+ if (wc < _CACHED_RUNES) {
+ wc++;
+ while (wc < _CACHED_RUNES) {
+ if (_CurrentRuneLocale->__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);
+}
diff --git a/lib/libc/locale/nl_langinfo.3 b/lib/libc/locale/nl_langinfo.3
new file mode 100644
index 0000000..8de1682
--- /dev/null
+++ b/lib/libc/locale/nl_langinfo.3
@@ -0,0 +1,90 @@
+.\" 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 May 3, 2001
+.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"
+.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's locale.
+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 buffer pointed 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.
+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 .
+.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 0000000..9bd5082
--- /dev/null
+++ b/lib/libc/locale/nl_langinfo.c
@@ -0,0 +1,175 @@
+/*-
+ * Copyright (c) 2001, 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <langinfo.h>
+#include <limits.h>
+#include <locale.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "lnumeric.h"
+#include "lmessages.h"
+#include "lmonetary.h"
+#include "../stdtime/timelocal.h"
+
+#define _REL(BASE) ((int)item-BASE)
+
+char *
+nl_langinfo(nl_item item)
+{
+ char *ret, *s, *cs;
+ static char *csym = NULL;
+
+ switch (item) {
+ case CODESET:
+ ret = "";
+ if ((s = setlocale(LC_CTYPE, NULL)) != NULL) {
+ if ((cs = strchr(s, '.')) != NULL)
+ ret = cs + 1;
+ else if (strcmp(s, "C") == 0 ||
+ strcmp(s, "POSIX") == 0)
+ ret = "US-ASCII";
+ }
+ break;
+ case D_T_FMT:
+ ret = (char *) __get_current_time_locale()->c_fmt;
+ break;
+ case D_FMT:
+ ret = (char *) __get_current_time_locale()->x_fmt;
+ break;
+ case T_FMT:
+ ret = (char *) __get_current_time_locale()->X_fmt;
+ break;
+ case T_FMT_AMPM:
+ ret = (char *) __get_current_time_locale()->ampm_fmt;
+ break;
+ case AM_STR:
+ ret = (char *) __get_current_time_locale()->am;
+ break;
+ case PM_STR:
+ ret = (char *) __get_current_time_locale()->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()->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()->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()->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()->mon[_REL(ABMON_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()->decimal_point;
+ break;
+ case THOUSEP:
+ ret = (char*) __get_current_numeric_locale()->thousands_sep;
+ break;
+ case YESEXPR:
+ ret = (char*) __get_current_messages_locale()->yesexpr;
+ break;
+ case NOEXPR:
+ ret = (char*) __get_current_messages_locale()->noexpr;
+ break;
+ /*
+ * YESSTR and NOSTR items marked with LEGACY are available, but not
+ * recomended 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()->yesstr;
+ break;
+ case NOSTR: /* LEGACY */
+ ret = (char*) __get_current_messages_locale()->nostr;
+ break;
+ /*
+ * SUSv2 special formatted currency string
+ */
+ case CRNCYSTR:
+ ret = "";
+ cs = (char*) __get_current_monetary_locale()->currency_symbol;
+ if (*cs != '\0') {
+ char pos = localeconv()->p_cs_precedes;
+
+ if (pos == localeconv()->n_cs_precedes) {
+ char psn = '\0';
+
+ if (pos == CHAR_MAX) {
+ if (strcmp(cs, __get_current_monetary_locale()->mon_decimal_point) == 0)
+ psn = '.';
+ } else
+ psn = pos ? '-' : '+';
+ if (psn != '\0') {
+ int clen = strlen(cs);
+
+ if ((csym = reallocf(csym, clen + 2)) != NULL) {
+ *csym = psn;
+ strcpy(csym + 1, cs);
+ ret = csym;
+ }
+ }
+ }
+ }
+ break;
+ case D_MD_ORDER: /* FreeBSD local extension */
+ ret = (char *) __get_current_time_locale()->md_order;
+ break;
+ default:
+ ret = "";
+ }
+ return (ret);
+}
diff --git a/lib/libc/locale/nomacros.c b/lib/libc/locale/nomacros.c
new file mode 100644
index 0000000..ba49a1f
--- /dev/null
+++ b/lib/libc/locale/nomacros.c
@@ -0,0 +1,12 @@
+#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_
+
+#include <ctype.h>
diff --git a/lib/libc/locale/none.c b/lib/libc/locale/none.c
new file mode 100644
index 0000000..06b55b9
--- /dev/null
+++ b/lib/libc/locale/none.c
@@ -0,0 +1,193 @@
+/*-
+ * 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.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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.
+ */
+
+#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);
+
+int
+_none_init(_RuneLocale *rl)
+{
+
+ __mbrtowc = _none_mbrtowc;
+ __mbsinit = _none_mbsinit;
+ __mbsnrtowcs = _none_mbsnrtowcs;
+ __wcrtomb = _none_wcrtomb;
+ __wcsnrtombs = _none_wcsnrtombs;
+ _CurrentRuneLocale = rl;
+ __mb_cur_max = 1;
+ 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) {
+ errno = EILSEQ;
+ return ((size_t)-1);
+ }
+ if ((*dst++ = *s++) == '\0') {
+ *src = NULL;
+ return (nchr);
+ }
+ nchr++;
+ }
+ *src = s;
+ return (nchr);
+}
+
+/* setup defaults */
+
+int __mb_cur_max = 1;
+size_t (*__mbrtowc)(wchar_t * __restrict, const char * __restrict, size_t,
+ mbstate_t * __restrict) = _none_mbrtowc;
+int (*__mbsinit)(const mbstate_t *) = _none_mbsinit;
+size_t (*__mbsnrtowcs)(wchar_t * __restrict, const char ** __restrict,
+ size_t, size_t, mbstate_t * __restrict) = _none_mbsnrtowcs;
+size_t (*__wcrtomb)(char * __restrict, wchar_t, mbstate_t * __restrict) =
+ _none_wcrtomb;
+size_t (*__wcsnrtombs)(char * __restrict, const wchar_t ** __restrict,
+ size_t, size_t, mbstate_t * __restrict) = _none_wcsnrtombs;
+
diff --git a/lib/libc/locale/rpmatch.3 b/lib/libc/locale/rpmatch.3
new file mode 100644
index 0000000..b34c5bf
--- /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 0000000..4d90eb8
--- /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 0000000..9acf67d
--- /dev/null
+++ b/lib/libc/locale/rune.c
@@ -0,0 +1,290 @@
+/*-
+ * 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. 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.
+ */
+
+#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 "un-namespace.h"
+
+#include "runefile.h"
+
+_RuneLocale *_Read_RuneMagi(FILE *);
+
+_RuneLocale *
+_Read_RuneMagi(FILE *fp)
+{
+ 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;
+
+ if (_fstat(fileno(fp), &sb) < 0)
+ return (NULL);
+
+ if ((size_t)sb.st_size < sizeof(_FileRuneLocale)) {
+ errno = EFTYPE;
+ return (NULL);
+ }
+
+ if ((fdata = malloc(sb.st_size)) == NULL)
+ return (NULL);
+
+ errno = 0;
+ rewind(fp); /* Someone might have read the magic number once already */
+ if (errno) {
+ saverr = errno;
+ free(fdata);
+ errno = saverr;
+ return (NULL);
+ }
+
+ if (fread(fdata, sb.st_size, 1, fp) != 1) {
+ saverr = errno;
+ free(fdata);
+ errno = saverr;
+ return (NULL);
+ }
+
+ frl = (_FileRuneLocale *)fdata;
+ lastp = fdata + sb.st_size;
+
+ variable = frl + 1;
+
+ if (memcmp(frl->magic, _FILE_RUNE_MAGIC_1, sizeof(frl->magic))) {
+ free(fdata);
+ errno = EFTYPE;
+ return (NULL);
+ }
+
+ frl->variable_len = ntohl(frl->variable_len);
+ frl->runetype_ext_nranges = ntohl(frl->runetype_ext_nranges);
+ frl->maplower_ext_nranges = ntohl(frl->maplower_ext_nranges);
+ frl->mapupper_ext_nranges = ntohl(frl->mapupper_ext_nranges);
+
+ for (x = 0; x < _CACHED_RUNES; ++x) {
+ frl->runetype[x] = ntohl(frl->runetype[x]);
+ frl->maplower[x] = ntohl(frl->maplower[x]);
+ frl->mapupper[x] = ntohl(frl->mapupper[x]);
+ }
+
+ runetype_ext_ranges = (_FileRuneEntry *)variable;
+ variable = runetype_ext_ranges + frl->runetype_ext_nranges;
+ if (variable > lastp) {
+ free(fdata);
+ errno = EFTYPE;
+ return (NULL);
+ }
+
+ maplower_ext_ranges = (_FileRuneEntry *)variable;
+ variable = maplower_ext_ranges + frl->maplower_ext_nranges;
+ if (variable > lastp) {
+ free(fdata);
+ errno = EFTYPE;
+ return (NULL);
+ }
+
+ mapupper_ext_ranges = (_FileRuneEntry *)variable;
+ variable = mapupper_ext_ranges + frl->mapupper_ext_nranges;
+ if (variable > lastp) {
+ free(fdata);
+ errno = EFTYPE;
+ return (NULL);
+ }
+
+ frr = runetype_ext_ranges;
+ for (x = 0; x < frl->runetype_ext_nranges; ++x) {
+ uint32_t *types;
+
+ frr[x].min = ntohl(frr[x].min);
+ frr[x].max = ntohl(frr[x].max);
+ frr[x].map = ntohl(frr[x].map);
+ if (frr[x].map == 0) {
+ int len = frr[x].max - frr[x].min + 1;
+ types = variable;
+ variable = types + len;
+ runetype_ext_len += len;
+ if (variable > lastp) {
+ free(fdata);
+ errno = EFTYPE;
+ return (NULL);
+ }
+ while (len-- > 0)
+ types[len] = ntohl(types[len]);
+ }
+ }
+
+ frr = maplower_ext_ranges;
+ for (x = 0; x < frl->maplower_ext_nranges; ++x) {
+ frr[x].min = ntohl(frr[x].min);
+ frr[x].max = ntohl(frr[x].max);
+ frr[x].map = ntohl(frr[x].map);
+ }
+
+ frr = mapupper_ext_ranges;
+ for (x = 0; x < frl->mapupper_ext_nranges; ++x) {
+ frr[x].min = ntohl(frr[x].min);
+ frr[x].max = ntohl(frr[x].max);
+ frr[x].map = ntohl(frr[x].map);
+ }
+ if ((char *)variable + frl->variable_len > (char *)lastp) {
+ free(fdata);
+ errno = EFTYPE;
+ return (NULL);
+ }
+
+ /*
+ * Convert from disk format to host format.
+ */
+ data = malloc(sizeof(_RuneLocale) +
+ (frl->runetype_ext_nranges + frl->maplower_ext_nranges +
+ frl->mapupper_ext_nranges) * sizeof(_RuneEntry) +
+ runetype_ext_len * sizeof(*rr->__types) +
+ frl->variable_len);
+ if (data == NULL) {
+ saverr = errno;
+ free(fdata);
+ 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->__invalid_rune = 0;
+
+ rl->__variable_len = frl->variable_len;
+ rl->__runetype_ext.__nranges = frl->runetype_ext_nranges;
+ rl->__maplower_ext.__nranges = frl->maplower_ext_nranges;
+ rl->__mapupper_ext.__nranges = frl->mapupper_ext_nranges;
+
+ for (x = 0; x < _CACHED_RUNES; ++x) {
+ rl->__runetype[x] = frl->runetype[x];
+ rl->__maplower[x] = frl->maplower[x];
+ rl->__mapupper[x] = 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 + 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 = frr[x].min;
+ rr[x].__max = frr[x].max;
+ rr[x].__map = 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 = frr[x].min;
+ rr[x].__max = frr[x].max;
+ rr[x].__map = frr[x].map;
+ }
+
+ frr = mapupper_ext_ranges;
+ rr = rl->__mapupper_ext.__ranges;
+ for (x = 0; x < rl->__mapupper_ext.__nranges; ++x) {
+ rr[x].__min = frr[x].min;
+ rr[x].__max = frr[x].max;
+ rr[x].__map = frr[x].map;
+ }
+
+ memcpy(rl->__variable, variable, rl->__variable_len);
+ free(fdata);
+
+ /*
+ * 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);
+}
diff --git a/lib/libc/locale/runefile.h b/lib/libc/locale/runefile.h
new file mode 100644
index 0000000..ce1e47e
--- /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 0000000..99f7aa2
--- /dev/null
+++ b/lib/libc/locale/runetype.c
@@ -0,0 +1,70 @@
+/*-
+ * 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. 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <ctype.h>
+#include <stdio.h>
+#include <runetype.h>
+
+unsigned long
+___runetype(__ct_rune_t c)
+{
+ size_t lim;
+ _RuneRange *rr = &_CurrentRuneLocale->__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);
+}
diff --git a/lib/libc/locale/setlocale.3 b/lib/libc/locale/setlocale.3
new file mode 100644
index 0000000..0d958d0
--- /dev/null
+++ b/lib/libc/locale/setlocale.3
@@ -0,0 +1,178 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)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:
+.Pp
+.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 0000000..92c5dd3
--- /dev/null
+++ b/lib/libc/locale/setlocale.c
@@ -0,0 +1,336 @@
+/*
+ * 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.
+ * 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.
+ */
+
+#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 char *categories[_LC_LAST] = {
+ "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);
+static const char *__get_locale_env(int);
+
+char *
+setlocale(category, locale)
+ 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()
+{
+ 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(category)
+ 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);
+ return (old);
+ }
+
+ return (NULL);
+}
+
+static const char *
+__get_locale_env(category)
+ 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 0000000..33b4b6e
--- /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 0000000..398bfc5
--- /dev/null
+++ b/lib/libc/locale/setrunelocale.c
@@ -0,0 +1,177 @@
+/*-
+ * 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. 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#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"
+
+extern _RuneLocale *_Read_RuneMagi(FILE *);
+
+static int __setrunelocale(const char *);
+
+static int
+__setrunelocale(const char *encoding)
+{
+ FILE *fp;
+ char name[PATH_MAX];
+ _RuneLocale *rl;
+ int saverr, ret;
+ static char ctype_encoding[ENCODING_LEN + 1];
+ static _RuneLocale *CachedRuneLocale;
+ static int Cached__mb_cur_max;
+ static size_t (*Cached__mbrtowc)(wchar_t * __restrict,
+ const char * __restrict, size_t, mbstate_t * __restrict);
+ static size_t (*Cached__wcrtomb)(char * __restrict, wchar_t,
+ mbstate_t * __restrict);
+ static int (*Cached__mbsinit)(const mbstate_t *);
+ static size_t (*Cached__mbsnrtowcs)(wchar_t * __restrict,
+ const char ** __restrict, size_t, size_t, mbstate_t * __restrict);
+ static size_t (*Cached__wcsnrtombs)(char * __restrict,
+ const wchar_t ** __restrict, size_t, size_t,
+ mbstate_t * __restrict);
+
+ /*
+ * The "C" and "POSIX" locale are always here.
+ */
+ if (strcmp(encoding, "C") == 0 || strcmp(encoding, "POSIX") == 0) {
+ _none_init(&_DefaultRuneLocale);
+ return (0);
+ }
+
+ /*
+ * If the locale name is the same as our cache, use the cache.
+ */
+ if (CachedRuneLocale != NULL &&
+ strcmp(encoding, ctype_encoding) == 0) {
+ _CurrentRuneLocale = CachedRuneLocale;
+ __mb_cur_max = Cached__mb_cur_max;
+ __mbrtowc = Cached__mbrtowc;
+ __mbsinit = Cached__mbsinit;
+ __mbsnrtowcs = Cached__mbsnrtowcs;
+ __wcrtomb = Cached__wcrtomb;
+ __wcsnrtombs = Cached__wcsnrtombs;
+ return (0);
+ }
+
+ /*
+ * Slurp the locale file into the cache.
+ */
+
+ /* Range checking not needed, encoding length already checked before */
+ (void) strcpy(name, _PathLocale);
+ (void) strcat(name, "/");
+ (void) strcat(name, encoding);
+ (void) strcat(name, "/LC_CTYPE");
+
+ if ((fp = fopen(name, "r")) == NULL)
+ return (errno == 0 ? ENOENT : errno);
+
+ if ((rl = _Read_RuneMagi(fp)) == NULL) {
+ saverr = (errno == 0 ? EFTYPE : errno);
+ (void)fclose(fp);
+ return (saverr);
+ }
+ (void)fclose(fp);
+
+ __mbrtowc = NULL;
+ __mbsinit = NULL;
+ __mbsnrtowcs = __mbsnrtowcs_std;
+ __wcrtomb = NULL;
+ __wcsnrtombs = __wcsnrtombs_std;
+ rl->__sputrune = NULL;
+ rl->__sgetrune = NULL;
+ if (strcmp(rl->__encoding, "NONE") == 0)
+ ret = _none_init(rl);
+ else if (strcmp(rl->__encoding, "UTF-8") == 0)
+ ret = _UTF8_init(rl);
+ else if (strcmp(rl->__encoding, "EUC") == 0)
+ ret = _EUC_init(rl);
+ else if (strcmp(rl->__encoding, "GB18030") == 0)
+ ret = _GB18030_init(rl);
+ else if (strcmp(rl->__encoding, "GB2312") == 0)
+ ret = _GB2312_init(rl);
+ else if (strcmp(rl->__encoding, "GBK") == 0)
+ ret = _GBK_init(rl);
+ else if (strcmp(rl->__encoding, "BIG5") == 0)
+ ret = _BIG5_init(rl);
+ else if (strcmp(rl->__encoding, "MSKanji") == 0)
+ ret = _MSKanji_init(rl);
+ else
+ ret = EFTYPE;
+ if (ret == 0) {
+ if (CachedRuneLocale != NULL) {
+ /* See euc.c */
+ if (strcmp(CachedRuneLocale->__encoding, "EUC") == 0)
+ free(CachedRuneLocale->__variable);
+ free(CachedRuneLocale);
+ }
+ CachedRuneLocale = _CurrentRuneLocale;
+ Cached__mb_cur_max = __mb_cur_max;
+ Cached__mbrtowc = __mbrtowc;
+ Cached__mbsinit = __mbsinit;
+ Cached__mbsnrtowcs = __mbsnrtowcs;
+ Cached__wcrtomb = __wcrtomb;
+ Cached__wcsnrtombs = __wcsnrtombs;
+ (void)strcpy(ctype_encoding, encoding);
+ } else
+ free(rl);
+
+ return (ret);
+}
+
+int
+__wrap_setrunelocale(const char *locale)
+{
+ int ret = __setrunelocale(locale);
+
+ if (ret != 0) {
+ errno = ret;
+ return (_LDP_ERROR);
+ }
+ return (_LDP_LOADED);
+}
+
diff --git a/lib/libc/locale/table.c b/lib/libc/locale/table.c
new file mode 100644
index 0000000..7db1b13
--- /dev/null
+++ b/lib/libc/locale/table.c
@@ -0,0 +1,253 @@
+/*-
+ * 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. 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.
+ */
+
+#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"
+
+_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|0,
+ _CTYPE_D|_CTYPE_R|_CTYPE_G|_CTYPE_X|1,
+ _CTYPE_D|_CTYPE_R|_CTYPE_G|_CTYPE_X|2,
+ _CTYPE_D|_CTYPE_R|_CTYPE_G|_CTYPE_X|3,
+ _CTYPE_D|_CTYPE_R|_CTYPE_G|_CTYPE_X|4,
+ _CTYPE_D|_CTYPE_R|_CTYPE_G|_CTYPE_X|5,
+ _CTYPE_D|_CTYPE_R|_CTYPE_G|_CTYPE_X|6,
+ _CTYPE_D|_CTYPE_R|_CTYPE_G|_CTYPE_X|7,
+ /*38*/ _CTYPE_D|_CTYPE_R|_CTYPE_G|_CTYPE_X|8,
+ _CTYPE_D|_CTYPE_R|_CTYPE_G|_CTYPE_X|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,
+ },
+};
+
+_RuneLocale *_CurrentRuneLocale = &_DefaultRuneLocale;
+
diff --git a/lib/libc/locale/toascii.3 b/lib/libc/locale/toascii.3
new file mode 100644
index 0000000..975b320
--- /dev/null
+++ b/lib/libc/locale/toascii.3
@@ -0,0 +1,73 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)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 0000000..4934284
--- /dev/null
+++ b/lib/libc/locale/tolower.3
@@ -0,0 +1,83 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)tolower.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd July 17, 2005
+.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 0000000..ff5163e
--- /dev/null
+++ b/lib/libc/locale/tolower.c
@@ -0,0 +1,68 @@
+/*-
+ * 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. 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <ctype.h>
+#include <stdio.h>
+#include <runetype.h>
+
+__ct_rune_t
+___tolower(c)
+ __ct_rune_t c;
+{
+ size_t lim;
+ _RuneRange *rr = &_CurrentRuneLocale->__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);
+}
diff --git a/lib/libc/locale/toupper.3 b/lib/libc/locale/toupper.3
new file mode 100644
index 0000000..b3ce8ff
--- /dev/null
+++ b/lib/libc/locale/toupper.3
@@ -0,0 +1,83 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)toupper.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd July 17, 2005
+.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 0000000..1b35d32
--- /dev/null
+++ b/lib/libc/locale/toupper.c
@@ -0,0 +1,68 @@
+/*-
+ * 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. 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <ctype.h>
+#include <stdio.h>
+#include <runetype.h>
+
+__ct_rune_t
+___toupper(c)
+ __ct_rune_t c;
+{
+ size_t lim;
+ _RuneRange *rr = &_CurrentRuneLocale->__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);
+}
diff --git a/lib/libc/locale/towlower.3 b/lib/libc/locale/towlower.3
new file mode 100644
index 0000000..63d6431
--- /dev/null
+++ b/lib/libc/locale/towlower.3
@@ -0,0 +1,70 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)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 0000000..0fdefa9
--- /dev/null
+++ b/lib/libc/locale/towupper.3
@@ -0,0 +1,70 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)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/utf8.5 b/lib/libc/locale/utf8.5
new file mode 100644
index 0000000..01a8a51
--- /dev/null
+++ b/lib/libc/locale/utf8.5
@@ -0,0 +1,106 @@
+.\" 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. 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.
+.\"
+.\" @(#)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 0000000..e467fc0
--- /dev/null
+++ b/lib/libc/locale/utf8.c
@@ -0,0 +1,421 @@
+/*-
+ * 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.
+ */
+
+#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"
+
+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(_RuneLocale *rl)
+{
+
+ __mbrtowc = _UTF8_mbrtowc;
+ __wcrtomb = _UTF8_wcrtomb;
+ __mbsinit = _UTF8_mbsinit;
+ __mbsnrtowcs = _UTF8_mbsnrtowcs;
+ __wcsnrtombs = _UTF8_wcsnrtombs;
+ _CurrentRuneLocale = rl;
+ __mb_cur_max = 6;
+
+ 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 && ((ch = (unsigned char)*s) & ~0x7f) == 0) {
+ /* Fast path for plain ASCII characters. */
+ if (pwc != NULL)
+ *pwc = ch;
+ return (ch != '\0' ? 1 : 0);
+ }
+
+ 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) {
+ mask = 0x7f;
+ want = 1;
+ lbound = 0;
+ } else 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 if ((ch & 0xfc) == 0xf8) {
+ mask = 0x03;
+ want = 5;
+ lbound = 0x200000;
+ } else if ((ch & 0xfe) == 0xfc) {
+ mask = 0x01;
+ want = 6;
+ lbound = 0x4000000;
+ } 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 (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);
+
+ if ((wc & ~0x7f) == 0) {
+ /* Fast path for plain ASCII characters. */
+ *s = (char)wc;
+ 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) {
+ lead = 0;
+ len = 1;
+ } else if ((wc & ~0x7ff) == 0) {
+ lead = 0xc0;
+ len = 2;
+ } else if ((wc & ~0xffff) == 0) {
+ lead = 0xe0;
+ len = 3;
+ } else if ((wc & ~0x1fffff) == 0) {
+ lead = 0xf0;
+ len = 4;
+ } else if ((wc & ~0x3ffffff) == 0) {
+ lead = 0xf8;
+ len = 5;
+ } else if ((wc & ~0x7fffffff) == 0) {
+ lead = 0xfc;
+ len = 6;
+ } 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 0000000..c89614e
--- /dev/null
+++ b/lib/libc/locale/wcrtomb.3
@@ -0,0 +1,105 @@
+.\" 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 WCRTOMB 3
+.Os
+.Sh NAME
+.Nm wcrtomb
+.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 wc" "mbstate_t * restrict ps"
+.Sh DESCRIPTION
+The
+.Fn wcrtomb
+function stores a multibyte sequence representing the
+wide character
+.Fa wc ,
+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 ,
+.Fn wcrtomb
+behaves as if
+.Fa s
+pointed to an internal buffer and
+.Fa wc
+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 ,
+.Fn wcrtomb
+uses an internal, static
+.Vt mbstate_t
+object, which is initialized to the initial conversion state
+at program startup.
+.Sh RETURN VALUES
+The
+.Fn wcrtomb
+functions returns the length (in bytes) of the multibyte sequence
+needed to represent
+.Fa wc ,
+or
+.Po Vt size_t Pc Ns \-1
+if
+.Fa wc
+is not a valid wide character code.
+.Sh ERRORS
+The
+.Fn wcrtomb
+function 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
+function conforms to
+.St -isoC-99 .
diff --git a/lib/libc/locale/wcrtomb.c b/lib/libc/locale/wcrtomb.c
new file mode 100644
index 0000000..ef75b78
--- /dev/null
+++ b/lib/libc/locale/wcrtomb.c
@@ -0,0 +1,41 @@
+/*-
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <wchar.h>
+#include "mblocal.h"
+
+size_t
+wcrtomb(char * __restrict s, wchar_t wc, mbstate_t * __restrict ps)
+{
+ static mbstate_t mbs;
+
+ if (ps == NULL)
+ ps = &mbs;
+ return (__wcrtomb(s, wc, ps));
+}
diff --git a/lib/libc/locale/wcsftime.3 b/lib/libc/locale/wcsftime.3
new file mode 100644
index 0000000..92aee93
--- /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 0000000..7a54fc0
--- /dev/null
+++ b/lib/libc/locale/wcsftime.c
@@ -0,0 +1,105 @@
+/*-
+ * 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 <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <time.h>
+#include <wchar.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(wchar_t * __restrict wcs, size_t maxsize,
+ const wchar_t * __restrict format, const struct tm * __restrict timeptr)
+{
+ static const mbstate_t initial;
+ mbstate_t mbs;
+ char *dst, *dstp, *sformat;
+ size_t n, sflen;
+ int sverrno;
+
+ sformat = dst = NULL;
+
+ /*
+ * Convert the supplied format string to a multibyte representation
+ * for strftime(), which only handles single-byte characters.
+ */
+ mbs = initial;
+ sflen = wcsrtombs(NULL, &format, 0, &mbs);
+ if (sflen == (size_t)-1)
+ goto error;
+ if ((sformat = malloc(sflen + 1)) == NULL)
+ goto error;
+ mbs = initial;
+ wcsrtombs(sformat, &format, sflen + 1, &mbs);
+
+ /*
+ * 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(dst, maxsize, sformat, timeptr) == 0)
+ goto error;
+ dstp = dst;
+ mbs = initial;
+ n = mbsrtowcs(wcs, (const char **)&dstp, maxsize, &mbs);
+ 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);
+}
diff --git a/lib/libc/locale/wcsnrtombs.c b/lib/libc/locale/wcsnrtombs.c
new file mode 100644
index 0000000..e899698
--- /dev/null
+++ b/lib/libc/locale/wcsnrtombs.c
@@ -0,0 +1,111 @@
+/*-
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include "mblocal.h"
+
+size_t
+wcsnrtombs(char * __restrict dst, const wchar_t ** __restrict src, size_t nwc,
+ size_t len, mbstate_t * __restrict ps)
+{
+ static mbstate_t mbs;
+
+ if (ps == NULL)
+ ps = &mbs;
+ return (__wcsnrtombs(dst, src, nwc, len, ps));
+}
+
+size_t
+__wcsnrtombs_std(char * __restrict dst, const wchar_t ** __restrict src,
+ size_t nwc, size_t len, mbstate_t * __restrict ps)
+{
+ 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 = __wcrtomb(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 = __wcrtomb(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 = __wcrtomb(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 0000000..ff607c2
--- /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 0000000..f3b38b7
--- /dev/null
+++ b/lib/libc/locale/wcsrtombs.c
@@ -0,0 +1,45 @@
+/*-
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include "mblocal.h"
+
+size_t
+wcsrtombs(char * __restrict dst, const wchar_t ** __restrict src, size_t len,
+ mbstate_t * __restrict ps)
+{
+ static mbstate_t mbs;
+
+ if (ps == NULL)
+ ps = &mbs;
+ return (__wcsnrtombs(dst, src, SIZE_T_MAX, len, ps));
+}
diff --git a/lib/libc/locale/wcstod.3 b/lib/libc/locale/wcstod.3
new file mode 100644
index 0000000..f8c5135
--- /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 0000000..68df1ed
--- /dev/null
+++ b/lib/libc/locale/wcstod.c
@@ -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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h>
+#include <wchar.h>
+#include <wctype.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(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr)
+{
+ static const mbstate_t initial;
+ mbstate_t mbs;
+ double val;
+ char *buf, *end;
+ const wchar_t *wcp;
+ size_t len;
+
+ while (iswspace(*nptr))
+ nptr++;
+
+ /*
+ * 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.
+ */
+ wcp = nptr;
+ mbs = initial;
+ if ((len = wcsrtombs(NULL, &wcp, 0, &mbs)) == (size_t)-1) {
+ if (endptr != NULL)
+ *endptr = (wchar_t *)nptr;
+ return (0.0);
+ }
+ if ((buf = malloc(len + 1)) == NULL)
+ return (0.0);
+ mbs = initial;
+ wcsrtombs(buf, &wcp, len + 1, &mbs);
+
+ /* Let strtod() do most of the work for us. */
+ val = strtod(buf, &end);
+
+ /*
+ * 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)
+ /* XXX Assume each wide char is one byte. */
+ *endptr = (wchar_t *)nptr + (end - buf);
+
+ free(buf);
+
+ return (val);
+}
diff --git a/lib/libc/locale/wcstof.c b/lib/libc/locale/wcstof.c
new file mode 100644
index 0000000..ba238d4
--- /dev/null
+++ b/lib/libc/locale/wcstof.c
@@ -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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h>
+#include <wchar.h>
+#include <wctype.h>
+
+/*
+ * See wcstod() for comments as to the logic used.
+ */
+float
+wcstof(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr)
+{
+ static const mbstate_t initial;
+ mbstate_t mbs;
+ float val;
+ char *buf, *end;
+ const wchar_t *wcp;
+ size_t len;
+
+ while (iswspace(*nptr))
+ nptr++;
+
+ wcp = nptr;
+ mbs = initial;
+ if ((len = wcsrtombs(NULL, &wcp, 0, &mbs)) == (size_t)-1) {
+ if (endptr != NULL)
+ *endptr = (wchar_t *)nptr;
+ return (0.0);
+ }
+ if ((buf = malloc(len + 1)) == NULL)
+ return (0.0);
+ mbs = initial;
+ wcsrtombs(buf, &wcp, len + 1, &mbs);
+
+ val = strtof(buf, &end);
+
+ if (endptr != NULL)
+ *endptr = (wchar_t *)nptr + (end - buf);
+
+ free(buf);
+
+ return (val);
+}
diff --git a/lib/libc/locale/wcstoimax.c b/lib/libc/locale/wcstoimax.c
new file mode 100644
index 0000000..0dadd5a
--- /dev/null
+++ b/lib/libc/locale/wcstoimax.c
@@ -0,0 +1,128 @@
+/*-
+ * 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. 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.
+ */
+
+#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>
+
+/*
+ * Convert a wide character string to an intmax_t integer.
+ */
+intmax_t
+wcstoimax(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
+ int base)
+{
+ const wchar_t *s;
+ uintmax_t acc;
+ wchar_t c;
+ uintmax_t cutoff;
+ int neg, any, cutlim;
+
+ /*
+ * See strtoimax for comments as to the logic used.
+ */
+ s = nptr;
+ do {
+ c = *s++;
+ } while (iswspace(c));
+ 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(c))
+ c = digittoint(c);
+ 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);
+}
diff --git a/lib/libc/locale/wcstol.3 b/lib/libc/locale/wcstol.3
new file mode 100644
index 0000000..e69a726
--- /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 0000000..fcf220e
--- /dev/null
+++ b/lib/libc/locale/wcstol.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.
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <wchar.h>
+#include <wctype.h>
+
+/*
+ * Convert a string to a long integer.
+ */
+long
+wcstol(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base)
+{
+ const wchar_t *s;
+ unsigned long acc;
+ wchar_t c;
+ unsigned long cutoff;
+ int neg, any, cutlim;
+
+ /*
+ * See strtol for comments as to the logic used.
+ */
+ s = nptr;
+ do {
+ c = *s++;
+ } while (iswspace(c));
+ 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(c))
+ c = digittoint(c);
+ 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);
+}
diff --git a/lib/libc/locale/wcstold.c b/lib/libc/locale/wcstold.c
new file mode 100644
index 0000000..cf9d874
--- /dev/null
+++ b/lib/libc/locale/wcstold.c
@@ -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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h>
+#include <wchar.h>
+#include <wctype.h>
+
+/*
+ * See wcstod() for comments as to the logic used.
+ */
+long double
+wcstold(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr)
+{
+ static const mbstate_t initial;
+ mbstate_t mbs;
+ long double val;
+ char *buf, *end;
+ const wchar_t *wcp;
+ size_t len;
+
+ while (iswspace(*nptr))
+ nptr++;
+
+ wcp = nptr;
+ mbs = initial;
+ if ((len = wcsrtombs(NULL, &wcp, 0, &mbs)) == (size_t)-1) {
+ if (endptr != NULL)
+ *endptr = (wchar_t *)nptr;
+ return (0.0);
+ }
+ if ((buf = malloc(len + 1)) == NULL)
+ return (0.0);
+ mbs = initial;
+ wcsrtombs(buf, &wcp, len + 1, &mbs);
+
+ val = strtold(buf, &end);
+
+ if (endptr != NULL)
+ *endptr = (wchar_t *)nptr + (end - buf);
+
+ free(buf);
+
+ return (val);
+}
diff --git a/lib/libc/locale/wcstoll.c b/lib/libc/locale/wcstoll.c
new file mode 100644
index 0000000..feddbdf
--- /dev/null
+++ b/lib/libc/locale/wcstoll.c
@@ -0,0 +1,127 @@
+/*-
+ * 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. 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.
+ */
+
+#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>
+
+/*
+ * Convert a wide character string to a long long integer.
+ */
+long long
+wcstoll(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base)
+{
+ const wchar_t *s;
+ unsigned long long acc;
+ wchar_t c;
+ unsigned long long cutoff;
+ int neg, any, cutlim;
+
+ /*
+ * See strtoll for comments as to the logic used.
+ */
+ s = nptr;
+ do {
+ c = *s++;
+ } while (iswspace(c));
+ 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(c))
+ c = digittoint(c);
+ 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);
+}
diff --git a/lib/libc/locale/wcstombs.3 b/lib/libc/locale/wcstombs.3
new file mode 100644
index 0000000..0cb712a
--- /dev/null
+++ b/lib/libc/locale/wcstombs.3
@@ -0,0 +1,94 @@
+.\" 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.
+.\" 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.
+.\"
+.\" 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 0000000..acd0051
--- /dev/null
+++ b/lib/libc/locale/wcstombs.c
@@ -0,0 +1,43 @@
+/*-
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <limits.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include "mblocal.h"
+
+size_t
+wcstombs(char * __restrict s, const wchar_t * __restrict pwcs, size_t n)
+{
+ static const mbstate_t initial;
+ mbstate_t mbs;
+
+ mbs = initial;
+ return (__wcsnrtombs(s, &pwcs, SIZE_T_MAX, n, &mbs));
+}
diff --git a/lib/libc/locale/wcstoul.c b/lib/libc/locale/wcstoul.c
new file mode 100644
index 0000000..4be83a3
--- /dev/null
+++ b/lib/libc/locale/wcstoul.c
@@ -0,0 +1,119 @@
+/*
+ * 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. 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <wchar.h>
+#include <wctype.h>
+
+/*
+ * Convert a wide character string to an unsigned long integer.
+ */
+unsigned long
+wcstoul(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base)
+{
+ const wchar_t *s;
+ unsigned long acc;
+ wchar_t c;
+ unsigned long cutoff;
+ int neg, any, cutlim;
+
+ /*
+ * See strtol for comments as to the logic used.
+ */
+ s = nptr;
+ do {
+ c = *s++;
+ } while (iswspace(c));
+ 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(c))
+ c = digittoint(c);
+ 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);
+}
diff --git a/lib/libc/locale/wcstoull.c b/lib/libc/locale/wcstoull.c
new file mode 100644
index 0000000..e57a37a
--- /dev/null
+++ b/lib/libc/locale/wcstoull.c
@@ -0,0 +1,126 @@
+/*-
+ * 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. 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.
+ */
+
+#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>
+
+/*
+ * Convert a wide character string to an unsigned long long integer.
+ */
+unsigned long long
+wcstoull(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
+ int base)
+{
+ const wchar_t *s;
+ unsigned long long acc;
+ wchar_t c;
+ unsigned long long cutoff;
+ int neg, any, cutlim;
+
+ /*
+ * See strtoull for comments as to the logic used.
+ */
+ s = nptr;
+ do {
+ c = *s++;
+ } while (iswspace(c));
+ 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(c))
+ c = digittoint(c);
+ 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);
+}
diff --git a/lib/libc/locale/wcstoumax.c b/lib/libc/locale/wcstoumax.c
new file mode 100644
index 0000000..9793ba3
--- /dev/null
+++ b/lib/libc/locale/wcstoumax.c
@@ -0,0 +1,126 @@
+/*-
+ * 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. 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.
+ */
+
+#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>
+
+/*
+ * Convert a wide character string to a uintmax_t integer.
+ */
+uintmax_t
+wcstoumax(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
+ int base)
+{
+ const wchar_t *s;
+ uintmax_t acc;
+ wchar_t c;
+ uintmax_t cutoff;
+ int neg, any, cutlim;
+
+ /*
+ * See strtoimax for comments as to the logic used.
+ */
+ s = nptr;
+ do {
+ c = *s++;
+ } while (iswspace(c));
+ 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(c))
+ c = digittoint(c);
+ 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);
+}
diff --git a/lib/libc/locale/wctob.c b/lib/libc/locale/wctob.c
new file mode 100644
index 0000000..cb39adc
--- /dev/null
+++ b/lib/libc/locale/wctob.c
@@ -0,0 +1,45 @@
+/*-
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <limits.h>
+#include <stdio.h>
+#include <wchar.h>
+#include "mblocal.h"
+
+int
+wctob(wint_t c)
+{
+ static const mbstate_t initial;
+ mbstate_t mbs = initial;
+ char buf[MB_LEN_MAX];
+
+ if (c == WEOF || __wcrtomb(buf, c, &mbs) != 1)
+ return (EOF);
+ return ((unsigned char)*buf);
+}
diff --git a/lib/libc/locale/wctomb.3 b/lib/libc/locale/wctomb.3
new file mode 100644
index 0000000..a669f0e
--- /dev/null
+++ b/lib/libc/locale/wctomb.3
@@ -0,0 +1,112 @@
+.\" 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.
+.\" 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.
+.\"
+.\" 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 0000000..77b9043
--- /dev/null
+++ b/lib/libc/locale/wctomb.c
@@ -0,0 +1,49 @@
+/*-
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h>
+#include <wchar.h>
+#include "mblocal.h"
+
+int
+wctomb(char *s, wchar_t wchar)
+{
+ static const mbstate_t initial;
+ static mbstate_t mbs;
+ size_t rval;
+
+ if (s == NULL) {
+ /* No support for state dependent encodings. */
+ mbs = initial;
+ return (0);
+ }
+ if ((rval = __wcrtomb(s, wchar, &mbs)) == (size_t)-1)
+ return (-1);
+ return ((int)rval);
+}
diff --git a/lib/libc/locale/wctrans.3 b/lib/libc/locale/wctrans.3
new file mode 100644
index 0000000..ce3e68c
--- /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 0000000..6813e33
--- /dev/null
+++ b/lib/libc/locale/wctrans.c
@@ -0,0 +1,80 @@
+/*-
+ * 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 <errno.h>
+#include <string.h>
+#include <wctype.h>
+
+enum {
+ _WCT_ERROR = 0,
+ _WCT_TOLOWER = 1,
+ _WCT_TOUPPER = 2
+};
+
+wint_t
+towctrans(wint_t wc, wctrans_t desc)
+{
+
+ switch (desc) {
+ case _WCT_TOLOWER:
+ wc = towlower(wc);
+ break;
+ case _WCT_TOUPPER:
+ wc = towupper(wc);
+ break;
+ case _WCT_ERROR:
+ default:
+ errno = EINVAL;
+ break;
+ }
+
+ return (wc);
+}
+
+wctrans_t
+wctrans(const char *charclass)
+{
+ 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);
+}
diff --git a/lib/libc/locale/wctype.3 b/lib/libc/locale/wctype.3
new file mode 100644
index 0000000..16f685b
--- /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 0000000..f9aa8dd
--- /dev/null
+++ b/lib/libc/locale/wctype.c
@@ -0,0 +1,74 @@
+/*-
+ * 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 <ctype.h>
+#include <string.h>
+#include <wctype.h>
+
+#undef iswctype
+int
+iswctype(wint_t wc, wctype_t charclass)
+{
+
+ return (__istype(wc, charclass));
+}
+
+wctype_t
+wctype(const char *property)
+{
+ struct {
+ const char *name;
+ wctype_t mask;
+ } props[] = {
+ { "alnum", _CTYPE_A|_CTYPE_D },
+ { "alpha", _CTYPE_A },
+ { "blank", _CTYPE_B },
+ { "cntrl", _CTYPE_C },
+ { "digit", _CTYPE_D },
+ { "graph", _CTYPE_G },
+ { "lower", _CTYPE_L },
+ { "print", _CTYPE_R },
+ { "punct", _CTYPE_P },
+ { "space", _CTYPE_S },
+ { "upper", _CTYPE_U },
+ { "xdigit", _CTYPE_X },
+ { "ideogram", _CTYPE_I }, /* BSD extension */
+ { "special", _CTYPE_T }, /* BSD extension */
+ { "phonogram", _CTYPE_Q }, /* BSD extension */
+ { "rune", 0xFFFFFF00L }, /* BSD extension */
+ { NULL, 0UL }, /* Default */
+ };
+ int i;
+
+ i = 0;
+ while (props[i].name != NULL && strcmp(props[i].name, property) != 0)
+ i++;
+
+ return (props[i].mask);
+}
diff --git a/lib/libc/locale/wcwidth.3 b/lib/libc/locale/wcwidth.3
new file mode 100644
index 0000000..0c7c74f
--- /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 0000000..f7dabab
--- /dev/null
+++ b/lib/libc/locale/wcwidth.c
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <wchar.h>
+
+#undef wcwidth
+
+int
+wcwidth(wchar_t wc)
+{
+
+ return (__wcwidth(wc));
+}
diff --git a/lib/libc/nameser/Makefile.inc b/lib/libc/nameser/Makefile.inc
new file mode 100644
index 0000000..05b4f55
--- /dev/null
+++ b/lib/libc/nameser/Makefile.inc
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+# nameser sources
+.PATH: ${.CURDIR}/nameser
+
+SRCS+= ns_name.c ns_netint.c ns_parse.c ns_print.c ns_samedomain.c ns_ttl.c
+
+SYM_MAPS+= ${.CURDIR}/nameser/Symbol.map
diff --git a/lib/libc/nameser/Symbol.map b/lib/libc/nameser/Symbol.map
new file mode 100644
index 0000000..82d0f43
--- /dev/null
+++ b/lib/libc/nameser/Symbol.map
@@ -0,0 +1,28 @@
+# $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_samename;
+ __ns_skiprr;
+ __ns_sprintrr;
+ __ns_sprintrrf;
+ __ns_format_ttl;
+ __ns_parse_ttl;
+};
diff --git a/lib/libc/nameser/ns_print.c b/lib/libc/nameser/ns_print.c
index cb61cb1..ca595a7 100644
--- a/lib/libc/nameser/ns_print.c
+++ b/lib/libc/nameser/ns_print.c
@@ -18,6 +18,8 @@
#ifndef lint
static const char rcsid[] = "$Id: ns_print.c,v 1.3.2.1.4.7 2004/09/16 07:01:12 marka Exp $";
#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
/* Import. */
@@ -30,8 +32,13 @@ static const char rcsid[] = "$Id: ns_print.c,v 1.3.2.1.4.7 2004/09/16 07:01:12 m
#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>
@@ -457,7 +464,11 @@ ns_sprintrrf(const u_char *msg, size_t msglen,
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++;
diff --git a/lib/libc/nameser/ns_samedomain.c b/lib/libc/nameser/ns_samedomain.c
index d4ca550..21117d8 100644
--- a/lib/libc/nameser/ns_samedomain.c
+++ b/lib/libc/nameser/ns_samedomain.c
@@ -18,6 +18,8 @@
#ifndef lint
static const char rcsid[] = "$Id: ns_samedomain.c,v 1.1.2.2.4.2 2004/03/16 12:34:17 marka Exp $";
#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
#include "port_before.h"
@@ -28,6 +30,7 @@ static const char rcsid[] = "$Id: ns_samedomain.c,v 1.1.2.2.4.2 2004/03/16 12:34
#include "port_after.h"
+#ifndef _LIBC
/*
* int
* ns_samedomain(a, b)
@@ -149,6 +152,7 @@ int
ns_subdomain(const char *a, const char *b) {
return (ns_samename(a, b) != 1 && ns_samedomain(a, b));
}
+#endif
/*
* int
diff --git a/lib/libc/net/Makefile.inc b/lib/libc/net/Makefile.inc
new file mode 100644
index 0000000..9921f8d
--- /dev/null
+++ b/lib/libc/net/Makefile.inc
@@ -0,0 +1,126 @@
+# from @(#)Makefile.inc 8.2 (Berkeley) 9/5/93
+# $FreeBSD$
+
+# machine-independent net sources
+.PATH: ${.CURDIR}/${MACHINE_ARCH}/net ${.CURDIR}/net
+
+SRCS+= addr2ascii.c ascii2addr.c 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 \
+ nsdispatch.c nslexer.c nsparser.c nss_compat.c \
+ rcmd.c rcmdsh.c recv.c rthdr.c send.c sockatmark.c vars.c
+
+.if ${MK_NS_CACHING} != "no"
+SRCS+= nscache.c nscachedcli.c
+.endif
+
+# for binary backward compatibility against FreeBSD 6.X and earlier
+SRCS+= res_mkupdate.c res_update.c
+
+SYM_MAPS+=${.CURDIR}/net/Symbol.map
+
+CFLAGS+=-DINET6 -I${.OBJDIR}
+
+# name6.c refers res_private.h
+CFLAGS+=-I${.CURDIR}/resolv
+
+YFLAGS+=-p_nsyy
+LFLAGS+=-P_nsyy
+
+CLEANFILES+=nsparser.c nslexer.c nsparser.h
+
+nsparser.h: nsparser.c
+ mv y.tab.h ${.TARGET}
+
+nslexer.c: nslexer.l nsparser.h
+ ${LEX} ${LFLAGS} -o/dev/stdout ${.IMPSRC} | \
+ sed -e '/YY_BUF_SIZE/s/16384/1024/' >${.TARGET}
+
+# machine-dependent net sources
+.if exists(${.CURDIR}/${MACHINE_ARCH}/net/Makefile.inc)
+.include "${.CURDIR}/${MACHINE_ARCH}/net/Makefile.inc"
+.endif
+
+MAN+= addr2ascii.3 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
+
+MLINKS+=addr2ascii.3 ascii2addr.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_ntop.3 inet.3 inet_pton.3 \
+ inet.3 network.3 inet.3 ntoa.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
+
+.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 0000000..849d392
--- /dev/null
+++ b/lib/libc/net/Symbol.map
@@ -0,0 +1,143 @@
+# $FreeBSD$
+
+FBSD_1.0 {
+ addr2ascii;
+ ascii2addr;
+ __b64_ntop;
+ __b64_pton;
+ ether_line;
+ ether_aton;
+ ether_ntoa;
+ ether_ntohost;
+ ether_hostton;
+ eui64_aton;
+ eui64_ntoa;
+ eui64_ntohost;
+ eui64_hostton;
+ gai_strerror;
+ freeaddrinfo;
+ getaddrinfo;
+ endhostdnsent;
+ 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_resolv;
+ hesiod_free_list;
+ hes_init;
+ hes_to_bind;
+ hes_resolv;
+ 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;
+ __res_freeupdrec;
+ __res_mkupdrec;
+ __res_nmkupdate;
+ __res_nupdate;
+ 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;
+};
+
+FBSDprivate {
+ _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;
+};
diff --git a/lib/libc/net/addr2ascii.3 b/lib/libc/net/addr2ascii.3
new file mode 100644
index 0000000..675c39d
--- /dev/null
+++ b/lib/libc/net/addr2ascii.3
@@ -0,0 +1,235 @@
+.\"
+.\" Copyright 1996 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.
+.\"
+.\" $ANA: addr2ascii.3,v 1.1 1996/06/13 18:41:46 wollman Exp $
+.\" $FreeBSD$
+.\"
+.Dd June 13, 1996
+.Dt ADDR2ASCII 3
+.Os
+.Sh NAME
+.Nm addr2ascii ,
+.Nm ascii2addr
+.Nd Generic address formatting routines
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In arpa/inet.h
+.Ft "char *"
+.Fn addr2ascii "int af" "const void *addrp" "int len" "char *buf"
+.Ft int
+.Fn ascii2addr "int af" "const char *ascii" "void *result"
+.Sh DESCRIPTION
+The routines
+.Fn addr2ascii
+and
+.Fn ascii2addr
+are used to convert network addresses between binary form and a
+printable form appropriate to the address family.
+Both functions take
+an
+.Fa af
+argument, specifying the address family to be used in the conversion
+process.
+(Currently, only the
+.Dv AF_INET
+and
+.Dv AF_LINK
+address families are supported.)
+.Pp
+The
+.Fn addr2ascii
+function
+is used to convert binary, network-format addresses into printable
+form.
+In addition to
+.Fa af ,
+there are three other arguments.
+The
+.Fa addrp
+argument is a pointer to the network address to be converted.
+The
+.Fa len
+argument is the length of the address.
+The
+.Fa buf
+argument is an optional pointer to a caller-allocated buffer to hold
+the result; if a null pointer is passed,
+.Fn addr2ascii
+uses a statically-allocated buffer.
+.Pp
+The
+.Fn ascii2addr
+function performs the inverse operation to
+.Fn addr2ascii .
+In addition to
+.Fa af ,
+it takes two arguments,
+.Fa ascii
+and
+.Fa result .
+The
+.Fa ascii
+argument is a pointer to the string which is to be converted into
+binary.
+The
+.Fa result
+argument is a pointer to an appropriate network address structure for
+the specified family.
+.Pp
+The following gives the appropriate structure to use for binary
+addresses in the specified family:
+.Pp
+.Bl -tag -width AF_INETxxxx -compact
+.It Dv AF_INET
+.Vt "struct in_addr"
+(in
+.In arpa/inet.h )
+.It Dv AF_LINK
+.Vt "struct sockaddr_dl"
+(in
+.In net/if_dl.h )
+.\" .It Dv AF_INET6
+.\" .Vt "struct in6_addr"
+.\" (in
+.\" .In netinet6/in6.h )
+.El
+.Pp
+.Dv AF_INET
+and
+.Dv AF_LINK
+constants are defined in
+.In sys/socket.h .
+.Sh RETURN VALUES
+The
+.Fn addr2ascii
+function returns the address of the buffer it was passed, or a static
+buffer if the a null pointer was passed; on failure, it returns a null
+pointer.
+The
+.Fn ascii2addr
+function returns the length of the binary address in bytes, or -1 on
+failure.
+.Sh EXAMPLES
+The
+.Xr inet 3
+functions
+.Fn inet_ntoa
+and
+.Fn inet_aton
+could be implemented thusly:
+.Bd -literal -offset indent
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+char *
+inet_ntoa(struct in_addr addr)
+{
+ return addr2ascii(AF_INET, &addr, sizeof addr, 0);
+}
+
+int
+inet_aton(const char *ascii, struct in_addr *addr)
+{
+ return (ascii2addr(AF_INET, ascii, addr)
+ == sizeof(*addr));
+}
+.Ed
+.Pp
+In actuality, this cannot be done because
+.Fn addr2ascii
+and
+.Fn ascii2addr
+are implemented in terms of the
+.Xr inet 3
+functions, rather than the other way around.
+.Sh ERRORS
+When a failure is returned,
+.Va errno
+is set to one of the following values:
+.Bl -tag -width Er
+.It Bq Er ENAMETOOLONG
+The
+.Fn addr2ascii
+routine was passed a
+.Fa len
+argument which was inappropriate for the address family given by
+.Fa af .
+.It Bq Er EPROTONOSUPPORT
+Either routine was passed an
+.Fa af
+argument other than
+.Dv AF_INET
+or
+.Dv AF_LINK .
+.It Bq Er EINVAL
+The string passed to
+.Fn ascii2addr
+was improperly formatted for address family
+.Fa af .
+.El
+.Sh SEE ALSO
+.Xr inet 3 ,
+.Xr linkaddr 3 ,
+.Xr inet 4
+.Sh HISTORY
+An interface close to this one was originally suggested by Craig
+Partridge.
+This particular interface originally appeared in the
+.Tn INRIA
+.Tn IPv6
+implementation.
+.Sh AUTHORS
+Code and documentation by
+.An Garrett A. Wollman ,
+MIT Laboratory for Computer Science.
+.Sh BUGS
+The original implementations supported IPv6.
+This support should
+eventually be resurrected.
+The
+.Tn NRL
+implementation also included support for the
+.Dv AF_ISO
+and
+.Dv AF_NS
+address families.
+.Pp
+The genericity of this interface is somewhat questionable.
+A truly
+generic interface would provide a means for determining the length of
+the buffer to be used so that it could be dynamically allocated, and
+would always require a
+.Vt "struct sockaddr"
+to hold the binary address.
+Unfortunately, this is incompatible with existing
+practice.
+This limitation means that a routine for printing network
+addresses from arbitrary address families must still have internal
+knowledge of the maximum buffer length needed and the appropriate part
+of the address to use as the binary address.
diff --git a/lib/libc/net/addr2ascii.c b/lib/libc/net/addr2ascii.c
new file mode 100644
index 0000000..4fad6a8
--- /dev/null
+++ b/lib/libc/net/addr2ascii.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright 1996 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.
+ *
+ * $ANA: addr2ascii.c,v 1.1 1996/06/13 18:41:46 wollman Exp $
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <errno.h>
+#include <string.h>
+
+#include <net/if_dl.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+/*-
+ * Convert a network address from binary to printable numeric format.
+ * This API is copied from INRIA's IPv6 implementation, but it is a
+ * bit bogus in two ways:
+ *
+ * 1) There is no value in passing both an address family and
+ * an address length; either one should imply the other,
+ * or we should be passing sockaddrs instead.
+ * 2) There should by contrast be /added/ a length for the buffer
+ * that we pass in, so that programmers are spared the need to
+ * manually calculate (read: ``guess'') the maximum length.
+ *
+ * Flash: the API is also the same in the NRL implementation, and seems to
+ * be some sort of standard, so we appear to be stuck with both the bad
+ * naming and the poor choice of arguments.
+ */
+char *
+addr2ascii(af, addrp, len, buf)
+ int af;
+ const void *addrp;
+ int len; /* should be size_t XXX */
+ char *buf; /* XXX should pass length of buffer */
+{
+ static char staticbuf[64]; /* 64 for AF_LINK > 16 for AF_INET */
+
+ if (!buf)
+ buf = staticbuf;
+
+ switch(af) {
+ case AF_INET:
+ if (len != sizeof(struct in_addr)) {
+ errno = ENAMETOOLONG;
+ return 0;
+ }
+ strcpy(buf, inet_ntoa(*(const struct in_addr *)addrp));
+ break;
+
+ case AF_LINK:
+ if (len != sizeof(struct sockaddr_dl)) {
+ errno = ENAMETOOLONG;
+ return 0;
+ }
+ strcpy(buf, link_ntoa((const struct sockaddr_dl *)addrp));
+ break;
+
+ default:
+ errno = EPROTONOSUPPORT;
+ return 0;
+ }
+ return buf;
+}
diff --git a/lib/libc/net/ascii2addr.c b/lib/libc/net/ascii2addr.c
new file mode 100644
index 0000000..5167a51
--- /dev/null
+++ b/lib/libc/net/ascii2addr.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright 1996 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.
+ *
+ * $ANA: ascii2addr.c,v 1.2 1996/06/13 18:46:02 wollman Exp $
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <errno.h>
+#include <string.h>
+
+#include <net/if_dl.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+int
+ascii2addr(af, ascii, result)
+ int af;
+ const char *ascii;
+ void *result;
+{
+ struct in_addr *ina;
+ char strbuf[4*sizeof("123")]; /* long enough for V4 only */
+
+ switch(af) {
+ case AF_INET:
+ ina = result;
+ strbuf[0] = '\0';
+ strncat(strbuf, ascii, (sizeof strbuf)-1);
+ if (inet_aton(strbuf, ina))
+ return sizeof(struct in_addr);
+ errno = EINVAL;
+ break;
+
+ case AF_LINK:
+ link_addr(ascii, result);
+ /* oops... no way to detect failure */
+ return sizeof(struct sockaddr_dl);
+
+ default:
+ errno = EPROTONOSUPPORT;
+ break;
+ }
+
+ return -1;
+}
diff --git a/lib/libc/net/base64.c b/lib/libc/net/base64.c
new file mode 100644
index 0000000..4335030
--- /dev/null
+++ b/lib/libc/net/base64.c
@@ -0,0 +1,315 @@
+/*
+ * 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/types.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 <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(src, target, targsize)
+ char const *src;
+ u_char *target;
+ size_t targsize;
+{
+ int tarindex, state, ch;
+ 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 == 0) /* 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 + 1 >= targsize)
+ return (-1);
+ target[tarindex] |= (pos - Base64) >> 4;
+ target[tarindex+1] = ((pos - Base64) & 0x0f)
+ << 4 ;
+ }
+ tarindex++;
+ state = 2;
+ break;
+ case 2:
+ if (target) {
+ if ((size_t)tarindex + 1 >= targsize)
+ return (-1);
+ target[tarindex] |= (pos - Base64) >> 2;
+ target[tarindex+1] = ((pos - Base64) & 0x03)
+ << 6;
+ }
+ 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 && 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 0000000..71ccc4d
--- /dev/null
+++ b/lib/libc/net/byteorder.3
@@ -0,0 +1,90 @@
+.\" 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. 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.
+.\"
+.\" @(#)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 0000000..e8bc8ba
--- /dev/null
+++ b/lib/libc/net/ether_addr.c
@@ -0,0 +1,231 @@
+/*
+ * 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.
+ *
+ * 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 <stdio.h>
+#include <paths.h>
+#include <sys/types.h>
+#include <string.h>
+#include <stdlib.h>
+#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
+
+#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(l, e, hostname)
+ 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)
+ return (i);
+
+ for (i=0; i<6; i++)
+ e->octet[i] = o[i];
+ return (0);
+}
+
+/*
+ * Convert an ASCII representation of an ethernet address to
+ * binary form.
+ */
+struct
+ether_addr *ether_aton(a)
+ const char *a;
+{
+ int i;
+ static struct ether_addr o;
+ 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);
+
+ o.octet[0]=o0;
+ o.octet[1]=o1;
+ o.octet[2]=o2;
+ o.octet[3]=o3;
+ o.octet[4]=o4;
+ o.octet[5]=o5;
+
+ return ((struct ether_addr *)&o);
+}
+
+/*
+ * Convert a binary representation of an ethernet address to
+ * an ASCII string.
+ */
+char
+*ether_ntoa(n)
+ const struct ether_addr *n;
+{
+ int i;
+ static char a[18];
+
+ 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 ((char *)&a);
+}
+
+/*
+ * Map an ethernet address to a hostname. Use either /etc/ethers or
+ * NIS/YP.
+ */
+int
+ether_ntohost(hostname, e)
+ 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, "r")) == 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(hostname, e)
+ 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, "r")) == 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 0000000..a132447
--- /dev/null
+++ b/lib/libc/net/ethers.3
@@ -0,0 +1,201 @@
+.\" 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 April 12, 1995
+.Dt ETHERS 3
+.Os
+.Sh NAME
+.Nm ethers ,
+.Nm ether_line ,
+.Nm ether_aton ,
+.Nm ether_ntoa ,
+.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 char *
+.Fn ether_ntoa "const struct ether_addr *n"
+.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 netinet/if_ether.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
+function converts an
+.Tn ASCII
+representation of an ethernet address into an
+.Vt ether_addr
+structure.
+Likewise,
+.Fn ether_ntoa
+converts an ethernet address specified as an
+.Vt ether_addr
+structure into an
+.Tn ASCII
+string.
+.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
+returns 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.
+Likewise,
+.Fn ether_aton
+returns a pointer to an
+.Vt ether_addr
+structure on success and a
+.Dv NULL
+pointer on failure.
+.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 insure 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 .
+.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.
diff --git a/lib/libc/net/eui64.3 b/lib/libc/net/eui64.3
new file mode 100644
index 0000000..3000c74
--- /dev/null
+++ b/lib/libc/net/eui64.3
@@ -0,0 +1,230 @@
+.\" 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 insure 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.
+.Sh BUGS
+The
+.Fn eui64_aton
+and
+.Fn eui64_ntoa
+functions returns values that are stored in static memory areas
+which may be overwritten the next time they are called.
diff --git a/lib/libc/net/eui64.c b/lib/libc/net/eui64.c
new file mode 100644
index 0000000..5085167
--- /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/types.h>
+#include <sys/eui64.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/param.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;
+ }
+
+ 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, "r")) == 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, "r")) == 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 0000000..7c55030
--- /dev/null
+++ b/lib/libc/net/gai_strerror.3
@@ -0,0 +1,90 @@
+.\" $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 December 20, 2004
+.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_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 0000000..bd351ab
--- /dev/null
+++ b/lib/libc/net/gai_strerror.c
@@ -0,0 +1,60 @@
+/*
+ * 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 <netdb.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 */
+};
+
+const char *
+gai_strerror(int ecode)
+{
+ 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 0000000..9c5a8b6
--- /dev/null
+++ b/lib/libc/net/getaddrinfo.3
@@ -0,0 +1,434 @@
+.\" $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 20, 2004
+.Dt GETADDRINFO 3
+.Os
+.Sh NAME
+.Nm getaddrinfo ,
+.Nm freeaddrinfo
+.Nd socket address structure to host and service name
+.Sh SYNOPSIS
+.Fd #include <sys/types.h>
+.Fd #include <sys/socket.h>
+.Fd #include <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
+.Tn IP
+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 or an IPv6 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; /* protocol 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 protocol family that should be used.
+When
+.Fa ai_family
+is set to
+.Dv PF_UNSPEC ,
+it means the caller will accept any protocol family supported by the
+operating system.
+.It Fa ai_socktype
+Denotes the type of socket that is wanted:
+.Dv SOCK_STREAM ,
+.Dv SOCK_DGRAM ,
+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
+or
+.Dv IPPROTO_TCP .
+If
+.Fa ai_protocol
+is zero the caller will accept any protocol.
+.It Fa ai_flags
+.Fa ai_flags
+is formed by
+.Tn OR Ns 'ing
+the following values:
+.Bl -tag -width "AI_CANONNAMEXX"
+.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_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.
+.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 PF_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.
+The three members
+.Fa ai_family,
+.Fa ai_socktype,
+and
+.Fa ai_protocol
+in each returned
+.Li addrinfo
+structure are suitable for a call to
+.Xr socket 2 .
+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 draft-ietf-ipv6-scoping-arch-02.txt.
+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 = PF_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 = PF_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 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 internet draft
+.%N draft-ietf-ipv6-scoping-arch-02.txt
+.%O work in progress material
+.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.1g-2000
+draft 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 0000000..b422c4b
--- /dev/null
+++ b/lib/libc/net/getaddrinfo.c
@@ -0,0 +1,2772 @@
+/* $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.
+ */
+
+/*
+ * "#ifdef FAITH" part is local hack for supporting IPv4-v6 translator.
+ *
+ * Issues to be discussed:
+ * - Thread safe-ness must be checked.
+ * - 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 netbsd/openbsd/freebsd4/bsdi4:
+ * - To avoid search order issue, we have a big amount of code duplicate
+ * from gethnamaddr.c and some other places. The issues that there's no
+ * lower layer function to lookup "IPv4 or IPv6" record. Calling
+ * gethostbyname2 from getaddrinfo will end up in wrong search order, as
+ * presented above.
+ *
+ * OS specific notes for freebsd4:
+ * - FreeBSD supported $GAI. The code does not.
+ * - FreeBSD allowed classful IPv4 numeric (127.1), the code does not.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <sys/queue.h>
+#ifdef INET6
+#include <net/if_var.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 <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 "libc_private.h"
+#ifdef NS_CACHING
+#include "nscache.h"
+#endif
+
+#if defined(__KAME__) && defined(INET6)
+# define FAITH
+#endif
+
+#define SUCCESS 0
+#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
+#else
+#define N_INET 0
+#endif
+ {PF_INET, sizeof(struct in_addr),
+ sizeof(struct sockaddr_in),
+ offsetof(struct sockaddr_in, sin_addr),
+ in_addrany, in_loopback, 0},
+ {0, 0, 0, 0, NULL, NULL, 0},
+};
+
+struct explore {
+ int e_af;
+ int e_socktype;
+ int e_protocol;
+ const char *e_protostr;
+ int e_wild;
+#define WILD_AF(ex) ((ex)->e_wild & 0x01)
+#define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02)
+#define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04)
+};
+
+static const struct explore explore[] = {
+#if 0
+ { PF_LOCAL, 0, ANY, ANY, NULL, 0x01 },
+#endif
+#ifdef INET6
+ { PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
+ { PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
+ { PF_INET6, SOCK_RAW, ANY, NULL, 0x05 },
+#endif
+ { PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
+ { PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
+ { PF_INET, SOCK_RAW, ANY, NULL, 0x05 },
+ { PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
+ { PF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
+ { PF_UNSPEC, SOCK_RAW, ANY, NULL, 0x05 },
+ { -1, 0, 0, NULL, 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;
+};
+
+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 *);
+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 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 *);
+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)
+{
+ 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)
+ return v;
+ 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;
+ struct addrinfo ai0;
+ struct addrinfo *pai;
+ const struct explore *ex;
+ int numeric = 0;
+
+ 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_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 (pai->ai_family != ex->e_af)
+ continue;
+ if (ex->e_socktype == ANY)
+ continue;
+ if (ex->e_protocol == ANY)
+ continue;
+ if (pai->ai_socktype == ex->e_socktype &&
+ pai->ai_protocol != ex->e_protocol) {
+ ERR(EAI_BADHINTS);
+ }
+ }
+ }
+ }
+
+ /*
+ * post-2553: AI_ALL and AI_V4MAPPED are effective only against
+ * AF_INET6 query. They need to be ignored if specified in other
+ * occassions.
+ */
+ switch (pai->ai_flags & (AI_ALL | AI_V4MAPPED)) {
+ case AI_V4MAPPED:
+ case AI_ALL | AI_V4MAPPED:
+ if (pai->ai_family != AF_INET6)
+ pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED);
+ break;
+ case AI_ALL:
+#if 1
+ /* illegal */
+ ERR(EAI_BADFLAGS);
+#else
+ pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED);
+#endif
+ 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)
+ ERR(error);
+
+ *pai = ai0;
+ }
+
+ ai0 = *pai;
+
+ /* NULL hostname, or numeric hostname */
+ for (ex = explore; ex->e_af >= 0; ex++) {
+ *pai = ai0;
+
+ /* PF_UNSPEC entries are prepared for DNS queries only */
+ if (ex->e_af == PF_UNSPEC)
+ continue;
+
+ 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 (hostname == NULL)
+ error = explore_null(pai, servname, &cur->ai_next);
+ else
+ error = explore_numeric_scope(pai, hostname, servname,
+ &cur->ai_next);
+
+ if (error)
+ goto free;
+
+ while (cur && cur->ai_next)
+ cur = cur->ai_next;
+ }
+
+ /*
+ * XXX
+ * If numreic representation of AF1 can be interpreted as FQDN
+ * representation of AF2, we need to think again about the code below.
+ */
+ if (sentinel.ai_next) {
+ numeric = 1;
+ goto good;
+ }
+
+ 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.
+ * we would like to prefer AF_INET6 than AF_INET, so we'll make a
+ * outer loop by AFs.
+ */
+ for (ex = explore; ex->e_af >= 0; ex++) {
+ *pai = ai0;
+
+ /* require exact match for family field */
+ if (pai->ai_family != ex->e_af)
+ 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_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;
+
+ error = explore_fqdn(pai, hostname, servname,
+ &cur->ai_next);
+
+ while (cur && cur->ai_next)
+ cur = cur->ai_next;
+ }
+
+ /* XXX inhibit errors if we have the result */
+ if (sentinel.ai_next)
+ error = 0;
+
+good:
+ /*
+ * 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.
+ */
+ if (hints == NULL || !(hints->ai_flags & AI_PASSIVE)) {
+ if (!numeric)
+ (void)reorder(&sentinel);
+ }
+ *res = sentinel.ai_next;
+ return SUCCESS;
+ } else
+ error = EAI_FAIL;
+ }
+free:
+bad:
+ if (sentinel.ai_next)
+ freeaddrinfo(sentinel.ai_next);
+ *res = NULL;
+ 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 = malloc(sizeof(*aio) * n)) == NULL)
+ return(n); /* 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 (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);
+ }
+
+ /* 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, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0)
+ return (0);
+ if ((buf = malloc(l)) == NULL)
+ return (0);
+ if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), 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);
+ key.sin6_addr.s6_addr[10] = 0xff;
+ key.sin6_addr.s6_addr[11] = 0xff;
+ memcpy(&key.sin6_addr.s6_addr[12],
+ &((struct sockaddr_in *)addr)->sin_addr, 4);
+ 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, ai.ai_protocol)) < 0)
+ return; /* give up */
+ 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;
+
+ /* XXX: interface name should not be hardcoded */
+ strncpy(ifr6.ifr_name, "lo0", sizeof(ifr6.ifr_name));
+ 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 < addrlen * 8) {
+ 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) {
+ 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. */
+ 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);
+ }
+}
+
+/*
+ * 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 *cur;
+ struct addrinfo sentinel;
+ int error;
+
+ *res = NULL;
+ sentinel.ai_next = NULL;
+ cur = &sentinel;
+
+ /*
+ * filter out AFs that are not supported by the kernel
+ * XXX errno?
+ */
+ s = _socket(pai->ai_family, SOCK_DGRAM, 0);
+ if (s < 0) {
+ if (errno != EMFILE)
+ return 0;
+ } else
+ _close(s);
+
+ /*
+ * if the servname does not match socktype/protocol, ignore it.
+ */
+ if (get_portmatch(pai, servname) != 0)
+ return 0;
+
+ afd = find_afd(pai->ai_family);
+ if (afd == NULL)
+ return 0;
+
+ if (pai->ai_flags & AI_PASSIVE) {
+ GET_AI(cur->ai_next, afd, afd->a_addrany);
+ /* xxx meaningless?
+ * GET_CANONNAME(cur->ai_next, "anyaddr");
+ */
+ GET_PORT(cur->ai_next, servname);
+ } else {
+ GET_AI(cur->ai_next, afd, afd->a_loopback);
+ /* xxx meaningless?
+ * GET_CANONNAME(cur->ai_next, "localhost");
+ */
+ GET_PORT(cur->ai_next, servname);
+ }
+ cur = cur->ai_next;
+
+ *res = sentinel.ai_next;
+ return 0;
+
+free:
+ if (sentinel.ai_next)
+ freeaddrinfo(sentinel.ai_next);
+ 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 *cur;
+ struct addrinfo sentinel;
+ int error;
+ char pton[PTON_MAX];
+
+ *res = NULL;
+ sentinel.ai_next = NULL;
+ cur = &sentinel;
+
+ /*
+ * if the servname does not match socktype/protocol, ignore it.
+ */
+ if (get_portmatch(pai, servname) != 0)
+ return 0;
+
+ afd = find_afd(pai->ai_family);
+ if (afd == NULL)
+ return 0;
+
+ switch (afd->a_af) {
+#if 1 /*X/Open spec*/
+ case AF_INET:
+ if (inet_aton(hostname, (struct in_addr *)pton) == 1) {
+ if (pai->ai_family == afd->a_af ||
+ pai->ai_family == PF_UNSPEC /*?*/) {
+ GET_AI(cur->ai_next, afd, pton);
+ GET_PORT(cur->ai_next, servname);
+ if ((pai->ai_flags & AI_CANONNAME)) {
+ /*
+ * Set the numeric address itself as
+ * the canonical name, based on a
+ * clarification in rfc3493.
+ */
+ GET_CANONNAME(cur->ai_next, canonname);
+ }
+ while (cur && cur->ai_next)
+ cur = cur->ai_next;
+ } else
+ ERR(EAI_FAMILY); /*xxx*/
+ }
+ break;
+#endif
+ default:
+ if (inet_pton(afd->a_af, hostname, pton) == 1) {
+ if (pai->ai_family == afd->a_af ||
+ pai->ai_family == PF_UNSPEC /*?*/) {
+ GET_AI(cur->ai_next, afd, pton);
+ GET_PORT(cur->ai_next, servname);
+ if ((pai->ai_flags & AI_CANONNAME)) {
+ /*
+ * Set the numeric address itself as
+ * the canonical name, based on a
+ * clarification in rfc3493.
+ */
+ GET_CANONNAME(cur->ai_next, canonname);
+ }
+ while (cur && cur->ai_next)
+ cur = cur->ai_next;
+ } else
+ ERR(EAI_FAMILY); /* XXX */
+ }
+ break;
+ }
+
+ *res = sentinel.ai_next;
+ return 0;
+
+free:
+bad:
+ if (sentinel.ai_next)
+ freeaddrinfo(sentinel.ai_next);
+ 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;
+
+ /*
+ * if the servname does not match socktype/protocol, ignore it.
+ */
+ if (get_portmatch(pai, servname) != 0)
+ return 0;
+
+ 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);
+ return(EAI_NONAME); /* XXX: is return OK? */
+ }
+ sin6->sin6_scope_id = scopeid;
+ }
+ }
+
+ free(hostname2);
+
+ 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 FAITH
+ struct in6_addr faith_prefix;
+ char *fp_str;
+ int translate = 0;
+#endif
+
+#ifdef FAITH
+ /*
+ * Transfrom an IPv4 addr into a special IPv6 addr format for
+ * IPv6->IPv4 translation gateway. (only TCP is supported now)
+ *
+ * +-----------------------------------+------------+
+ * | faith prefix part (12 bytes) | embedded |
+ * | | IPv4 addr part (4 bytes)
+ * +-----------------------------------+------------+
+ *
+ * faith prefix part is specified as ascii IPv6 addr format
+ * in environmental variable GAI.
+ * For FAITH to work correctly, routing to faith prefix must be
+ * setup toward a machine where a FAITH daemon operates.
+ * Also, the machine must enable some mechanizm
+ * (e.g. faith interface hack) to divert those packet with
+ * faith prefixed destination addr to user-land FAITH daemon.
+ */
+ fp_str = getenv("GAI");
+ if (fp_str && inet_pton(AF_INET6, fp_str, &faith_prefix) == 1 &&
+ afd->a_af == AF_INET && pai->ai_socktype == SOCK_STREAM) {
+ u_int32_t v4a;
+ u_int8_t v4a_top;
+
+ memcpy(&v4a, addr, sizeof v4a);
+ v4a_top = v4a >> IN_CLASSA_NSHIFT;
+ if (!IN_MULTICAST(v4a) && !IN_EXPERIMENTAL(v4a) &&
+ v4a_top != 0 && v4a != IN_LOOPBACKNET) {
+ afd = &afdl[N_INET6];
+ memcpy(&faith_prefix.s6_addr[12], addr,
+ sizeof(struct in_addr));
+ translate = 1;
+ }
+ }
+#endif
+
+ ai = (struct addrinfo *)malloc(sizeof(struct addrinfo)
+ + (afd->a_socklen));
+ 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;
+ ai->ai_addr->sa_family = ai->ai_family = afd->a_af;
+ p = (char *)(void *)(ai->ai_addr);
+#ifdef FAITH
+ if (translate == 1)
+ memcpy(p + afd->a_off, &faith_prefix, (size_t)afd->a_addrlen);
+ else
+#endif
+ memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen);
+ return ai;
+}
+
+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;
+ int allownumeric;
+
+ if (servname == NULL)
+ return 0;
+ switch (ai->ai_family) {
+ 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:
+ allownumeric = 1;
+ break;
+ case ANY:
+ allownumeric = 0;
+ break;
+ default:
+ return EAI_SOCKTYPE;
+ }
+
+ port = str2number(servname);
+ if (port >= 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_socktype) {
+ case SOCK_DGRAM:
+ proto = "udp";
+ break;
+ case SOCK_STREAM:
+ proto = "tcp";
+ 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;
+}
+
+/*
+ * post-2553: AI_ADDRCONFIG check. if we use getipnodeby* as backend, backend
+ * will take care of it.
+ * the semantics of AI_ADDRCONFIG is not defined well. we are not sure
+ * if the code is right or not.
+ *
+ * XXX PF_UNSPEC -> PF_INET6 + PF_INET mapping needs to be in sync with
+ * _dns_getaddrinfo.
+ */
+static int
+addrconfig(struct addrinfo *pai)
+{
+ int s, af;
+
+ /*
+ * TODO:
+ * Note that implementation dependent test for address
+ * configuration should be done everytime called
+ * (or apropriate interval),
+ * because addresses will be dynamically assigned or deleted.
+ */
+ af = pai->ai_family;
+ if (af == AF_UNSPEC) {
+ if ((s = _socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
+ af = AF_INET;
+ else {
+ _close(s);
+ if ((s = _socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ af = AF_INET6;
+ else
+ _close(s);
+ }
+ }
+ if (af != AF_UNSPEC) {
+ if ((s = _socket(af, SOCK_DGRAM, 0)) < 0)
+ return 0;
+ _close(s);
+ }
+ pai->ai_family = af;
+ return 1;
+}
+
+#ifdef INET6
+/* 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)) {
+ /*
+ * 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 = (struct addrinfo *)malloc(size);
+ memset(sentinel, 0, 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 = (char *)malloc(size + 1);
+ memset(sentinel->ai_canonname, 0, 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)
+ 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;
+ }
+
+ RES_SET_H_ERRNO(res, 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;
+ querybuf *buf, *buf2;
+ const char *hostname;
+ const struct addrinfo *pai;
+ struct addrinfo sentinel, *cur;
+ struct res_target q, q2;
+ res_state res;
+
+ 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;
+
+ 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;
+ }
+
+ 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;
+ }
+
+ res = __res_state();
+ 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) {
+ cur->ai_next = ai;
+ while (cur && cur->ai_next)
+ cur = cur->ai_next;
+ }
+ }
+ ai = getanswer(buf, q.n, q.name, q.qtype, pai, res);
+ if (ai)
+ cur->ai_next = ai;
+ free(buf);
+ free(buf2);
+ if (sentinel.ai_next == NULL)
+ switch (res->res_h_errno) {
+ case HOST_NOT_FOUND:
+ 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, "r");
+ 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, "r")))
+ 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;
+ 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;
+}
+
+/*ARGSUSED*/
+static int
+_files_getaddrinfo(void *rv, void *cb_data, va_list ap)
+{
+ const char *name;
+ const struct addrinfo *pai;
+ struct addrinfo sentinel, *cur;
+ struct addrinfo *p;
+ FILE *hostf = NULL;
+
+ name = va_arg(ap, char *);
+ pai = va_arg(ap, struct addrinfo *);
+
+ memset(&sentinel, 0, sizeof(sentinel));
+ cur = &sentinel;
+
+ _sethtent(&hostf);
+ while ((p = _gethtent(&hostf, name, pai)) != NULL) {
+ cur->ai_next = p;
+ while (cur && cur->ai_next)
+ cur = cur->ai_next;
+ }
+ _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;
+ 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;
+
+ /* hosts.byname is only for IPv4 (Solaris8) */
+ if (pai->ai_family == PF_UNSPEC || pai->ai_family == PF_INET) {
+ r = yp_match(ypdomain, "hosts.byname", name,
+ (int)strlen(name), &ypbuf, &ypbuflen);
+ if (r == 0) {
+ struct addrinfo ai4;
+
+ ai4 = *pai;
+ 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);
+ }
+ }
+
+ /* 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;
+ free(ypbuf);
+ }
+
+ 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 0000000..b19dc79
--- /dev/null
+++ b/lib/libc/net/gethostbydns.c
@@ -0,0 +1,762 @@
+/*
+ * ++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. 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.
+ * -
+ * 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/types.h>
+#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 dprintf(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
+dprintf(msg, num, res)
+ char *msg;
+ int num;
+ res_state res;
+{
+ if (res->options & RES_DEBUG) {
+ int save = errno;
+
+ printf(msg, num);
+ errno = save;
+ }
+}
+#else
+# define dprintf(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)
+ 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) {
+ dprintf("size (%d) too big\n", n, statp);
+ had_error++;
+ continue;
+ }
+ if (hap >= &hed->h_addr_ptrs[_MAXADDRS-1]) {
+ if (!toobig++)
+ dprintf("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:
+ dprintf("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);
+ dprintf("res_nsearch failed (%d)\n", n, statp);
+ *h_errnop = statp->res_h_errno;
+ return (0);
+ } else if (n > sizeof(buf->buf)) {
+ free(buf);
+ dprintf("static buffer is too small (%d)\n", n, statp);
+ *h_errnop = statp->res_h_errno;
+ return (0);
+ }
+ error = gethostanswer(buf, n, name, type, &he, hed, statp);
+ free(buf);
+ if (error != 0) {
+ *h_errnop = statp->res_h_errno;
+ return (NS_NOTFOUND);
+ }
+ if (__copy_hostent(&he, hptr, buffer, buflen) != 0) {
+ *h_errnop = statp->res_h_errno;
+ return (NS_NOTFOUND);
+ }
+ *((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);
+ dprintf("res_nquery failed (%d)\n", n, statp);
+ *h_errnop = statp->res_h_errno;
+ return (NS_UNAVAIL);
+ }
+ if (n > sizeof buf->buf) {
+ free(buf);
+ dprintf("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;
+ return (NS_NOTFOUND); /* h_errno was set by gethostanswer() */
+ }
+ 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;
+ }
+ RES_SET_H_ERRNO(statp, NETDB_SUCCESS);
+ if (__copy_hostent(&he, hptr, buffer, buflen) != 0) {
+ *h_errnop = statp->res_h_errno;
+ return (NS_NOTFOUND);
+ }
+ *((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()
+{
+ 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 0000000..cb5009d
--- /dev/null
+++ b/lib/libc/net/gethostbyht.c
@@ -0,0 +1,335 @@
+/*-
+ * 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. 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.
+ * -
+ * 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 <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, "r");
+ 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, "r"))) {
+ 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)
+ return (-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) {
+ *h_errnop = statp->res_h_errno;
+ return (NS_NOTFOUND);
+ }
+ *((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) {
+ *h_errnop = statp->res_h_errno;
+ return (NS_NOTFOUND);
+ }
+ *((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 0000000..7c83d02
--- /dev/null
+++ b/lib/libc/net/gethostbyname.3
@@ -0,0 +1,379 @@
+.\" 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.
+.\" 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.
+.\"
+.\" From: @(#)gethostbyname.3 8.4 (Berkeley) 5/25/95
+.\" $FreeBSD$
+.\"
+.Dd May 25, 1995
+.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 extern 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 type"
+.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 type
+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 external 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 0000000..7921ced
--- /dev/null
+++ b/lib/libc/net/gethostbynis.c
@@ -0,0 +1,348 @@
+/*-
+ * 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 = index(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 */
+
+/* XXX _gethostbynisname/_gethostbynisaddr only used by getipnodeby*() */
+struct hostent *
+_gethostbynisname(const char *name, int af)
+{
+#ifdef YP
+ struct hostent *he;
+ struct hostent_data *hed;
+ u_long oresopt;
+ 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);
+ }
+
+ oresopt = statp->options;
+ statp->options &= ~RES_USE_INET6;
+ error = _gethostbynisname_r(name, af, he, hed);
+ statp->options = oresopt;
+ return (error == 0) ? he : NULL;
+#else
+ return (NULL);
+#endif
+}
+
+struct hostent *
+_gethostbynisaddr(const void *addr, socklen_t len, int af)
+{
+#ifdef YP
+ struct hostent *he;
+ struct hostent_data *hed;
+ u_long oresopt;
+ 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);
+ }
+
+ oresopt = statp->options;
+ statp->options &= ~RES_USE_INET6;
+ error = _gethostbynisaddr_r(addr, len, af, he, hed);
+ statp->options = oresopt;
+ return (error == 0) ? he : NULL;
+#else
+ return (NULL);
+#endif
+}
+
+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) {
+ *h_errnop = statp->res_h_errno;
+ return (NS_NOTFOUND);
+ }
+ *((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) {
+ *h_errnop = statp->res_h_errno;
+ return (NS_NOTFOUND);
+ }
+ *((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 0000000..7ff3500
--- /dev/null
+++ b/lib/libc/net/gethostnamadr.c
@@ -0,0 +1,725 @@
+/*-
+ * 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
+
+extern int _ht_gethostbyname(void *, void *, va_list);
+extern int _dns_gethostbyname(void *, void *, va_list);
+extern int _nis_gethostbyname(void *, void *, va_list);
+extern int _ht_gethostbyaddr(void *, void *, va_list);
+extern int _dns_gethostbyaddr(void *, void *, va_list);
+extern int _nis_gethostbyaddr(void *, void *, va_list);
+
+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 nonexistant */
+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;
+ int len, 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:
+ str = va_arg(ap, char *);
+ len = va_arg(ap, int);
+ type = va_arg(ap, int);
+
+ desired_size = sizeof(res_options) + sizeof(int) +
+ sizeof(enum nss_lookup_type) + sizeof(int) * 2 + 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(int));
+ p += sizeof(int);
+
+ memcpy(p, str, 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;
+ int len, 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:
+ str = va_arg(ap, char *);
+ len = va_arg(ap, int);
+ 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;
+ int len, 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:
+ str = va_arg(ap, char *);
+ len = va_arg(ap, int);
+ 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;
+ RES_SET_H_ERRNO(statp, NETDB_SUCCESS);
+ return (__copy_hostent(&he, hp, buf, buflen));
+}
+
+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;
+ 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);
+
+ return ((rval == NS_SUCCESS) ? 0 : -1);
+}
+
+int
+gethostbyaddr_r(const void *addr,
+#if __LONG_BIT == 64
+ int len,
+#else
+ socklen_t len,
+#endif
+ 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;
+ 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);
+
+ return ((rval == NS_SUCCESS) ? 0 : -1);
+}
+
+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 *
+#if __LONG_BIT == 64
+gethostbyaddr(const void *addr, int len, int af)
+#else
+gethostbyaddr(const void *addr, socklen_t len, int af)
+#endif
+{
+ 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 0000000..a12cd00
--- /dev/null
+++ b/lib/libc/net/getifaddrs.3
@@ -0,0 +1,167 @@
+.\" $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 October 12, 1995
+.Dt GETIFADDRS 3
+.Os
+.Sh NAME
+.Nm getifaddrs
+.Nd get interface addresses
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/socket.h
+.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.
+For
+.Dv AF_LINK
+addresses it contains a pointer to the
+.Fa struct if_data
+(as defined in include file
+.In net/if.h )
+which contains various interface attributes and statistics.
+For all other address families, it contains a pointer to the
+.Fa struct ifa_data
+(as defined in include file
+.In net/if.h )
+which 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 0000000..41ef3f4
--- /dev/null
+++ b/lib/libc/net/getifaddrs.c
@@ -0,0 +1,418 @@
+/* $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
+
+#if _BSDI_VERSION >= 199701
+#define HAVE_IFM_DATA
+#endif
+
+#if _BSDI_VERSION >= 199802
+/* ifam_data is very specific to recent versions of bsdi */
+#define HAVE_IFAM_DATA
+#endif
+
+#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__)
+#define HAVE_IFM_DATA
+#endif
+
+#define MAX_SYSCTL_TRY 5
+
+int
+getifaddrs(struct ifaddrs **pif)
+{
+ int icnt = 1;
+ int dcnt = 0;
+ int ncnt = 0;
+#ifdef NET_RT_IFLIST
+ int ntry = 0;
+ int mib[6];
+ size_t needed;
+ char *buf;
+ char *next;
+ struct ifaddrs *cif = 0;
+ char *p, *p0;
+ struct rt_msghdr *rtm;
+ struct if_msghdr *ifm;
+ struct ifa_msghdr *ifam;
+ struct sockaddr_dl *dl;
+ struct sockaddr *sa;
+ struct ifaddrs *ifa, *ift;
+ u_short idx = 0;
+#else /* NET_RT_IFLIST */
+ char buf[1024];
+ int m, sock;
+ struct ifconf ifc;
+ struct ifreq *ifr;
+ struct ifreq *lifr;
+#endif /* NET_RT_IFLIST */
+ int i;
+ size_t len, alen;
+ char *data;
+ char *names;
+
+#ifdef NET_RT_IFLIST
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0; /* protocol */
+ mib[3] = 0; /* wildcard address family */
+ mib[4] = NET_RT_IFLIST;
+ 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_msghdr *)(void *)rtm;
+ if (ifm->ifm_addrs & RTA_IFP) {
+ idx = ifm->ifm_index;
+ ++icnt;
+ dl = (struct sockaddr_dl *)(void *)(ifm + 1);
+ dcnt += SA_RLEN((struct sockaddr *)(void*)dl) +
+ ALIGNBYTES;
+#ifdef HAVE_IFM_DATA
+ dcnt += sizeof(ifm->ifm_data);
+#endif /* HAVE_IFM_DATA */
+ ncnt += dl->sdl_nlen + 1;
+ } else
+ idx = 0;
+ break;
+
+ case RTM_NEWADDR:
+ ifam = (struct ifa_msghdr *)(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 *)(void *)(ifam + 1);
+ ++icnt;
+#ifdef HAVE_IFAM_DATA
+ dcnt += sizeof(ifam->ifam_data) + ALIGNBYTES;
+#endif /* HAVE_IFAM_DATA */
+ /* 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;
+ }
+ }
+#else /* NET_RT_IFLIST */
+ ifc.ifc_buf = buf;
+ ifc.ifc_len = sizeof(buf);
+
+ if ((sock = _socket(AF_INET, SOCK_STREAM, 0)) < 0)
+ return (-1);
+ i = _ioctl(sock, SIOCGIFCONF, (char *)&ifc);
+ _close(sock);
+ if (i < 0)
+ return (-1);
+
+ ifr = ifc.ifc_req;
+ lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len];
+
+ while (ifr < lifr) {
+ struct sockaddr *sa;
+
+ sa = &ifr->ifr_addr;
+ ++icnt;
+ dcnt += SA_RLEN(sa);
+ ncnt += sizeof(ifr->ifr_name) + 1;
+
+ if (SA_LEN(sa) < sizeof(*sa))
+ ifr = (struct ifreq *)(((char *)sa) + sizeof(*sa));
+ else
+ ifr = (struct ifreq *)(((char *)sa) + SA_LEN(sa));
+ }
+#endif /* NET_RT_IFLIST */
+
+ 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;
+
+#ifdef NET_RT_IFLIST
+ idx = 0;
+ 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_msghdr *)(void *)rtm;
+ if (ifm->ifm_addrs & RTA_IFP) {
+ idx = ifm->ifm_index;
+ dl = (struct sockaddr_dl *)(void *)(ifm + 1);
+
+ 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);
+
+#ifdef HAVE_IFM_DATA
+ /* ifm_data needs to be aligned */
+ ift->ifa_data = data = (void *)ALIGN(data);
+ memcpy(data, &ifm->ifm_data, sizeof(ifm->ifm_data));
+ data += sizeof(ifm->ifm_data);
+#else /* HAVE_IFM_DATA */
+ ift->ifa_data = NULL;
+#endif /* HAVE_IFM_DATA */
+
+ ift = (ift->ifa_next = ift + 1);
+ } else
+ idx = 0;
+ break;
+
+ case RTM_NEWADDR:
+ ifam = (struct ifa_msghdr *)(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 *)(void *)(ifam + 1);
+ /* 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;
+ }
+
+#ifdef HAVE_IFAM_DATA
+ /* ifam_data needs to be aligned */
+ ift->ifa_data = data = (void *)ALIGN(data);
+ memcpy(data, &ifam->ifam_data, sizeof(ifam->ifam_data));
+ data += sizeof(ifam->ifam_data);
+#endif /* HAVE_IFAM_DATA */
+
+ ift = (ift->ifa_next = ift + 1);
+ break;
+ }
+ }
+
+ free(buf);
+#else /* NET_RT_IFLIST */
+ ifr = ifc.ifc_req;
+ lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len];
+
+ while (ifr < lifr) {
+ struct sockaddr *sa;
+
+ ift->ifa_name = names;
+ names[sizeof(ifr->ifr_name)] = 0;
+ strncpy(names, ifr->ifr_name, sizeof(ifr->ifr_name));
+ while (*names++)
+ ;
+
+ ift->ifa_addr = (struct sockaddr *)data;
+ sa = &ifr->ifr_addr;
+ memcpy(data, sa, SA_LEN(sa));
+ data += SA_RLEN(sa);
+
+ ifr = (struct ifreq *)(((char *)sa) + SA_LEN(sa));
+ ift = (ift->ifa_next = ift + 1);
+ }
+#endif /* NET_RT_IFLIST */
+ 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 0000000..2d2a936
--- /dev/null
+++ b/lib/libc/net/getifmaddrs.3
@@ -0,0 +1,116 @@
+.\" 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 November 14, 2003
+.Dt GETIFMADDRS 3
+.Os
+.Sh NAME
+.Nm getifmaddrs
+.Nd get multicast group memberships
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/socket.h
+.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 0000000..adbc4a5
--- /dev/null
+++ b/lib/libc/net/getifmaddrs.c
@@ -0,0 +1,203 @@
+/*
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Bruce M. Simpson.
+ * 4. Neither the name of Bruce M. Simpson nor the names of other
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BRUCE M. SIMPSON AND AFFILIATES
+ * ``AS IS'' AND ANY EXPRESS OR 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 OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY 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 0000000..dbef578
--- /dev/null
+++ b/lib/libc/net/getipnodebyname.3
@@ -0,0 +1,478 @@
+.\" $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.
+.\" 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.
+.\"
+.\" 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
+ hptr = gethostbyname(name);
+.Ed
+.Pp
+with
+.Bd -literal -offset
+ 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
+ #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 0000000..61479cf
--- /dev/null
+++ b/lib/libc/net/getnameinfo.3
@@ -0,0 +1,270 @@
+.\" $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 December 20, 2004
+.Dt GETNAMEINFO 3
+.Os
+.Sh NAME
+.Nm getnameinfo
+.Nd socket address structure to hostname and service name
+.Sh SYNOPSIS
+.Fd #include <sys/types.h>
+.Fd #include <sys/socket.h>
+.Fd #include <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
+The
+.Li sockaddr
+structure
+.Fa sa
+should point to either a
+.Li sockaddr_in
+or
+.Li sockaddr_in6
+structure (for IPv4 or IPv6 respectively) 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_NUMERICHOSTXX"
+.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_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 draft-ietf-ipv6-scoping-arch-02.txt.
+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 resolver 3 ,
+.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 W. Stevens
+.%T Basic Socket Interface Extensions for IPv6
+.%R RFC 2553
+.%D March 1999
+.Re
+.Rs
+.%A S. Deering
+.%A B. Haberman
+.%A T. Jinmei
+.%A E. Nordmark
+.%A B. Zill
+.%T "IPv6 Scoped Address Architecture"
+.%R internet draft
+.%N draft-ietf-ipv6-scoping-arch-02.txt
+.%O work in progress material
+.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.1g-2000
+draft specification and documented in
+.Tn "RFC 2553" ,
+.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 0000000..b14cc27
--- /dev/null
+++ b/lib/libc/net/getnameinfo.c
@@ -0,0 +1,345 @@
+/* $KAME: getnameinfo.c,v 1.61 2002/06/27 09:25:47 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:
+ * - 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 <net/if.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 {
+ int a_af;
+ size_t a_addrlen;
+ socklen_t a_socklen;
+ int a_off;
+} afdl [] = {
+#ifdef INET6
+ {PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6),
+ offsetof(struct sockaddr_in6, sin6_addr)},
+#endif
+ {PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in),
+ offsetof(struct sockaddr_in, sin_addr)},
+ {0, 0, 0},
+};
+
+struct sockinet {
+ u_char si_len;
+ u_char si_family;
+ u_short si_port;
+};
+
+#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
+
+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;
+ struct servent *sp;
+ struct hostent *hp;
+ u_short port;
+ int family, i;
+ const char *addr;
+ u_int32_t v4a;
+ int h_error;
+ char numserv[512];
+ char numaddr[512];
+
+ if (sa == NULL)
+ return EAI_FAIL;
+
+ family = sa->sa_family;
+ for (i = 0; afdl[i].a_af; i++)
+ if (afdl[i].a_af == family) {
+ afd = &afdl[i];
+ goto found;
+ }
+ return EAI_FAMILY;
+
+ found:
+ if (salen != afd->a_socklen)
+ return EAI_FAIL;
+
+ /* network byte order */
+ port = ((const struct sockinet *)sa)->si_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_MEMORY;
+ 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_MEMORY;
+ if (zonelen + 1 + numaddrlen + 1 > hostlen)
+ return EAI_MEMORY;
+
+ /* 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;
+
+#ifdef NI_NUMERICSCOPE
+ if ((flags & NI_NUMERICSCOPE) != 0) {
+ n = snprintf(buf, bufsiz, "%u", sa6->sin6_scope_id);
+ if (n < 0 || n >= bufsiz)
+ return -1;
+ else
+ return n;
+ }
+#endif
+
+ /* 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 */
diff --git a/lib/libc/net/getnetbydns.c b/lib/libc/net/getnetbydns.c
new file mode 100644
index 0000000..23c9c45
--- /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.
+ * 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.
+ * -
+ * 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) {
+ *h_errnop = statp->res_h_errno;
+ return (NS_NOTFOUND);
+ }
+ *((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) {
+ *h_errnop = statp->res_h_errno;
+ return (NS_NOTFOUND);
+ }
+ *((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()
+{
+ 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 0000000..580345a
--- /dev/null
+++ b/lib/libc/net/getnetbyht.c
@@ -0,0 +1,284 @@
+/*
+ * 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. 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.
+ */
+
+/* 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 <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, "r");
+ 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, "r")) == 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)
+ return (-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) {
+ *h_errnop = statp->res_h_errno;
+ return (NS_NOTFOUND);
+ }
+ *((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) {
+ *h_errnop = statp->res_h_errno;
+ return (NS_NOTFOUND);
+ }
+ *((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 0000000..d00c7f2
--- /dev/null
+++ b/lib/libc/net/getnetbynis.c
@@ -0,0 +1,255 @@
+/*-
+ * 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 = index(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) {
+ *h_errnop = statp->res_h_errno;
+ return (NS_NOTFOUND);
+ }
+ *((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) {
+ *h_errnop = statp->res_h_errno;
+ return (NS_NOTFOUND);
+ }
+ *((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 0000000..3c329a6
--- /dev/null
+++ b/lib/libc/net/getnetent.3
@@ -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.
+.\" 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.
+.\"
+.\" @(#)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 .
+.Pp
+.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
+(0) 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 0000000..ec7e94b
--- /dev/null
+++ b/lib/libc/net/getnetnamadr.c
@@ -0,0 +1,450 @@
+/*-
+ * 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
+
+extern int _ht_getnetbyname(void *, void *, va_list);
+extern int _dns_getnetbyname(void *, void *, va_list);
+extern int _nis_getnetbyname(void *, void *, va_list);
+extern int _ht_getnetbyaddr(void *, void *, va_list);
+extern int _dns_getnetbyaddr(void *, void *, va_list);
+extern int _nis_getnetbyaddr(void *, void *, va_list);
+
+/* Network lookup order if nsswitch.conf is broken or nonexistant */
+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;
+
+ rval = _nsdispatch((void *)result, dtab, NSDB_NETWORKS,
+ "getnetbyname_r", default_src, name, ne, buffer, buflen,
+ &ret_errno, h_errorp);
+
+ return ((rval == NS_SUCCESS) ? 0 : -1);
+}
+
+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;
+
+ rval = _nsdispatch((void *)result, dtab, NSDB_NETWORKS,
+ "getnetbyaddr_r", default_src, addr, af, ne, buffer, buflen,
+ &ret_errno, h_errorp);
+
+ return ((rval == NS_SUCCESS) ? 0 : -1);
+}
+
+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 0000000..b2a3fe7
--- /dev/null
+++ b/lib/libc/net/getproto.c
@@ -0,0 +1,145 @@
+/*
+ * 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. 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.
+ */
+
+#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 <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 }
+};
+
+#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_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 = -1;
+ 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 = -1;
+ return (NS_NOTFOUND);
+ }
+ if (__copy_protoent(&pe, pptr, buffer, buflen) != 0) {
+ *errnop = -1;
+ return (NS_NOTFOUND);
+ }
+
+ *((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)
+ return (0);
+ else
+ return (ret_errno);
+}
+
+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 0000000..e15ad01
--- /dev/null
+++ b/lib/libc/net/getprotoent.3
@@ -0,0 +1,150 @@
+.\" 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. 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.
+.\"
+.\" @(#)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 .
+.Pp
+.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
+(0) 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 0000000..3d3a57e
--- /dev/null
+++ b/lib/libc/net/getprotoent.c
@@ -0,0 +1,555 @@
+/*
+ * 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. 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.
+ */
+
+#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/types.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, "r");
+ 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, "r")) == 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)
+ return (-1);
+
+ if (__getprotoent_p(&pe, ped) != 0) {
+ *errnop = errno;
+ return (NS_NOTFOUND);
+ }
+
+ if (__copy_protoent(&pe, pptr, buffer, buflen) != 0) {
+ *errnop = errno;
+ return (NS_NOTFOUND);
+ }
+
+ *((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)
+ return (0);
+ else
+ return (ret_errno);
+}
+
+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 0000000..4ef50e3
--- /dev/null
+++ b/lib/libc/net/getprotoname.c
@@ -0,0 +1,153 @@
+/*
+ * 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. 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.
+ */
+
+#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 <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 = -1;
+ 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 = -1;
+ return (NS_NOTFOUND);
+ }
+ if (__copy_protoent(&pe, pptr, buffer, buflen) != 0) {
+ *errnop = -1;
+ return (NS_NOTFOUND);
+ }
+
+ *((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)
+ return (0);
+ else
+ return (ret_errno);
+}
+
+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 0000000..8c43c8f
--- /dev/null
+++ b/lib/libc/net/getservent.3
@@ -0,0 +1,159 @@
+.\" 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. 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.
+.\"
+.\" 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
+(0) 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 0000000..b616e25
--- /dev/null
+++ b/lib/libc/net/getservent.c
@@ -0,0 +1,1213 @@
+/*
+ * 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. 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.
+ */
+
+#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/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <errno.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);
+
+#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;
+}
+
+/* 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[] = {
+#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;
+
+ char **aliases;
+ int aliases_size;
+ 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, "r")) == 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=='+') {
+ if (serv_mdata->compat_mode != 0)
+ st->compat_mode_active = 1;
+ } else {
+ 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';
+ }
+ }
+
+ 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 = servent_unpack(buffer, serv, aliases, aliases_size,
+ errnop);
+ if (rv !=0 ) {
+ if (*errnop == 0) {
+ rv = NS_NOTFOUND;
+ continue;
+ }
+ else {
+ 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 == 0 || strcmp(serv->s_proto, proto) == 0)
+ rv = NS_SUCCESS;
+ break;
+ case nss_lt_id:
+ if (port != serv->s_port)
+ continue;
+
+ if (proto == 0 || 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, "r");
+ 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);
+}
+
+/* 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;
+
+ char **aliases;
+ int aliases_size;
+
+ 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;
+ };
+
+ /* we need a room for additional \n symbol */
+ if (bufsize <=
+ resultbuflen + 1 + _ALIGNBYTES + sizeof(char *)) {
+ *errnop = ERANGE;
+ rv = NS_RETURN;
+ break;
+ }
+
+ aliases = (char **)_ALIGN(&buffer[resultbuflen + 2]);
+ aliases_size =
+ (buffer + bufsize - (char *)aliases) / sizeof(char *);
+ if (aliases_size < 1) {
+ *errnop = ERANGE;
+ rv = NS_RETURN;
+ break;
+ }
+
+ /*
+ * servent_unpack expects lines terminated with \n --
+ * make it happy
+ */
+ memcpy(buffer, resultbuf, resultbuflen);
+ buffer[resultbuflen] = '\n';
+ buffer[resultbuflen + 1] = '\0';
+
+ if (servent_unpack(buffer, serv, aliases, aliases_size,
+ errnop) != 0) {
+ if (*errnop == 0)
+ rv = NS_NOTFOUND;
+ else
+ rv = NS_RETURN;
+ } else
+ rv = NS_SUCCESS;
+ 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[] = {
+#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 },
+#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 },
+#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 },
+#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 },
+#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()
+{
+#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 },
+#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()
+{
+ 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 0000000..bae4e44
--- /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 0000000..c22bdba
--- /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/types.h>
+#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, "r");
+ 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) {
+ 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 0000000..715c33c
--- /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 0000000..4dadce3
--- /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 == ((struct sockaddr_dl*)ifa->ifa_addr)->sdl_index)
+ 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 0000000..7a12d34
--- /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 =
+ ((struct sockaddr_dl*)ifa->ifa_addr)->sdl_index;
+ 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 0000000..d0ca521
--- /dev/null
+++ b/lib/libc/net/if_nametoindex.c
@@ -0,0 +1,99 @@
+/* $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, 0);
+ if (s != -1) {
+ 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 = ((struct sockaddr_dl*)ifa->ifa_addr)->sdl_index;
+ 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 0000000..28877f1
--- /dev/null
+++ b/lib/libc/net/inet.3
@@ -0,0 +1,303 @@
+.\" 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.
+.\" 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.
+.\"
+.\" From: @(#)inet.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 14, 2004
+.Dt INET 3
+.Os
+.Sh NAME
+.Nm inet_aton ,
+.Nm inet_addr ,
+.Nm inet_network ,
+.Nm inet_ntoa ,
+.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 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 .
+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_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).
+.Pp
+The
+.Fn inet_aton
+and
+.Fn inet_ntoa
+functions are semi-deprecated in favor of the
+.Xr addr2ascii 3
+family.
+However, since those functions are not yet widely implemented,
+portable programs cannot rely on their presence and will continue
+to use the
+.Xr inet 3
+functions for some time.
+.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 addr2ascii 3 ,
+.Xr byteorder 3 ,
+.Xr gethostbyname 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
+Inet_addr 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 0000000..6713468
--- /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 0000000..e17855a
--- /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 0000000..2750170
--- /dev/null
+++ b/lib/libc/net/inet6_rth_space.3
@@ -0,0 +1,224 @@
+.\" $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 0000000..bfb2f23
--- /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 0000000..a9d0781
--- /dev/null
+++ b/lib/libc/net/inet_net.3
@@ -0,0 +1,167 @@
+.\" $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.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the NetBSD
+.\" Foundation, Inc. and its contributors.
+.\" 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 February 26, 2006
+.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/types.h
+.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 .
+.Pp
+.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 0000000..7b65d06
--- /dev/null
+++ b/lib/libc/net/ip6opt.c
@@ -0,0 +1,610 @@
+/* $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/types.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);
+
+/*
+ * 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(nbytes)
+ 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(bp, cmsgp, type)
+ void *bp;
+ struct cmsghdr **cmsgp;
+ int type;
+{
+ struct cmsghdr *ch = (struct cmsghdr *)bp;
+
+ /* argument validation */
+ if (type != IPV6_HOPOPTS && type != IPV6_DSTOPTS)
+ 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(cmsg, typep, multx, plusy)
+ 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 = (((off % multx) + (multx - 1)) & ~(multx - 1)) -
+ (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(cmsg, datalen, multx, plusy)
+ 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 = (((off % multx) + (multx - 1)) & ~(multx - 1)) -
+ (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(cmsg, tptrp)
+ 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 ||
+ (cmsg->cmsg_type != IPV6_HOPOPTS &&
+ cmsg->cmsg_type != IPV6_DSTOPTS))
+ 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(cmsg, tptrp, type)
+ 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 ||
+ (cmsg->cmsg_type != IPV6_HOPOPTS &&
+ cmsg->cmsg_type != IPV6_DSTOPTS))
+ 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(opt, lim)
+ u_int8_t *opt, *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 (extlen < 0 || (extlen % 8))
+ return(-1);
+
+ if (ext) {
+ if (extlen == 0)
+ 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 < 0 || len > 255)
+ 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 0000000..1f1c21f
--- /dev/null
+++ b/lib/libc/net/linkaddr.3
@@ -0,0 +1,144 @@
+.\" 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.
+.\" 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.
+.\"
+.\" From: @(#)linkaddr.3 8.1 (Berkeley) 7/28/93
+.\" $FreeBSD$
+.\"
+.Dd June 17, 1996
+.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.
+.Pp
+The direct use of these functions is deprecated in favor of the
+.Xr addr2ascii 3
+interface; however, portable programs cannot rely on the latter as it is
+not yet widely implemented.
+.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 addr2ascii 3
+.\" .Xr iso 4
+.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 0000000..c23559a
--- /dev/null
+++ b/lib/libc/net/linkaddr.c
@@ -0,0 +1,160 @@
+/*-
+ * 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. 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.
+ */
+
+#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_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(addr, sdl)
+ 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 char hexlist[] = "0123456789abcdef";
+
+char *
+link_ntoa(sdl)
+ const struct sockaddr_dl *sdl;
+{
+ static char obuf[64];
+ char *out = obuf;
+ int i;
+ u_char *in = (u_char *)LLADDR(sdl);
+ u_char *inlim = in + sdl->sdl_alen;
+ int firsttime = 1;
+
+ if (sdl->sdl_nlen) {
+ bcopy(sdl->sdl_data, obuf, sdl->sdl_nlen);
+ out += sdl->sdl_nlen;
+ if (sdl->sdl_alen)
+ *out++ = ':';
+ }
+ while (in < inlim) {
+ if (firsttime)
+ firsttime = 0;
+ else
+ *out++ = '.';
+ i = *in++;
+ if (i > 0xf) {
+ out[1] = hexlist[i & 0xf];
+ i >>= 4;
+ out[0] = hexlist[i];
+ out += 2;
+ } else
+ *out++ = hexlist[i];
+ }
+ *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 0000000..dbbddc0
--- /dev/null
+++ b/lib/libc/net/map_v4v6.c
@@ -0,0 +1,123 @@
+/*
+ * ++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. 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.
+ * -
+ * 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/types.h>
+#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>
+
+typedef union {
+ int32_t al;
+ char ac;
+} align;
+
+void
+_map_v4v6_address(const char *src, char *dst)
+{
+ u_char *p = (u_char *)dst;
+ char tmp[NS_INADDRSZ];
+ int i;
+
+ /* Stash a temporary copy so our caller can update in place. */
+ memcpy(tmp, src, NS_INADDRSZ);
+ /* Mark this ipv6 addr as a mapped ipv4. */
+ for (i = 0; i < 10; i++)
+ *p++ = 0x00;
+ *p++ = 0xff;
+ *p++ = 0xff;
+ /* Retrieve the saved copy and we're done. */
+ memcpy((void*)p, tmp, NS_INADDRSZ);
+}
+
+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 0000000..dc6521a
--- /dev/null
+++ b/lib/libc/net/name6.c
@@ -0,0 +1,2354 @@
+/* $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. 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.
+ * -
+ * 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"
+#ifdef ICMPNL
+#include "reentrant.h"
+#endif
+#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 <net/if_var.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_config.h"
+#include "res_private.h"
+#ifdef NS_CACHING
+#include "nscache.h"
+#endif
+
+#ifndef _PATH_HOSTS
+#define _PATH_HOSTS "/etc/hosts"
+#endif
+
+#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) && _mapped_addr_enabled()))
+
+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;
+};
+
+static struct hostent *_hpcopy(struct hostent *, int *);
+static struct hostent *_hpaddr(int, const char *, void *, int *);
+static struct hostent *_hpmerge(struct hostent *, struct hostent *, int *);
+#ifdef INET6
+static struct hostent *_hpmapv6(struct hostent *, int *);
+#endif
+static struct hostent *_hpsort(struct hostent *, res_state);
+static struct hostent *_ghbyname(const char *, int, int, int *);
+static char *_hgetword(char **);
+static int _mapped_addr_enabled(void);
+
+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 *);
+
+static FILE *_files_open(int *);
+static int _files_ghbyname(void *, void *, va_list);
+static int _files_ghbyaddr(void *, void *, va_list);
+#ifdef YP
+static int _nis_ghbyname(void *, void *, va_list);
+static int _nis_ghbyaddr(void *, void *, va_list);
+#endif
+static int _dns_ghbyname(void *, void *, va_list);
+static int _dns_ghbyaddr(void *, void *, va_list);
+static void _dns_shent(int) __unused;
+static void _dns_ehent(void) __unused;
+#ifdef ICMPNL
+static int _icmp_ghbyaddr(void *, void *, va_list);
+#endif /* ICMPNL */
+#ifdef NS_CACHING
+static int ipnode_id_func(char *, size_t *, va_list, void *);
+static int ipnode_marshal_func(char *, size_t *, void *, va_list, void *);
+static int ipnode_unmarshal_func(char *, size_t, void *, va_list, void *);
+#endif
+
+#ifdef ICMPNL
+static mutex_t _getipnodeby_thread_lock = MUTEX_INITIALIZER;
+#define THREAD_LOCK() mutex_lock(&_getipnodeby_thread_lock);
+#define THREAD_UNLOCK() mutex_unlock(&_getipnodeby_thread_lock);
+#endif
+
+/* Host lookup order if nsswitch.conf is broken or nonexistant */
+static const ns_src default_src[] = {
+ { NSSRC_FILES, NS_SUCCESS },
+ { NSSRC_DNS, NS_SUCCESS },
+#ifdef ICMPNL
+#define NSSRC_ICMP "icmp"
+ { NSSRC_ICMP, NS_SUCCESS },
+#endif
+ { 0 }
+};
+
+/*
+ * Check if kernel supports mapped address.
+ * implementation dependent
+ */
+#ifdef __KAME__
+#include <sys/sysctl.h>
+#endif /* __KAME__ */
+
+static int
+_mapped_addr_enabled(void)
+{
+ /* implementation dependent check */
+#if defined(__KAME__) && defined(IPV6CTL_MAPPED_ADDR)
+ int mib[4];
+ size_t len;
+ int val;
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_INET6;
+ mib[2] = IPPROTO_IPV6;
+ mib[3] = IPV6CTL_MAPPED_ADDR;
+ len = sizeof(val);
+ if (sysctl(mib, 4, &val, &len, 0, 0) == 0 && val != 0)
+ return 1;
+#endif /* __KAME__ && IPV6CTL_MAPPED_ADDR */
+ return 0;
+}
+
+#ifdef NS_CACHING
+static int
+ipnode_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 = 2;
+ char *name;
+ int af;
+ size_t len;
+ void *src;
+
+ char *p;
+ size_t desired_size, size;
+ enum nss_lookup_type lookup_type;
+ 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:
+ name = va_arg(ap, char *);
+ af = va_arg(ap, int);
+
+ size = strlen(name);
+ 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(enum nss_lookup_type);
+
+ memcpy(p, &af, sizeof(int));
+ p += sizeof(int);
+
+ memcpy(p, name, size + 1);
+
+ res = NS_SUCCESS;
+ break;
+ case nss_lt_id:
+ src = va_arg(ap, void *);
+ len = va_arg(ap, size_t);
+ af = va_arg(ap, int);
+
+ desired_size = sizeof(res_options) + sizeof(int) +
+ sizeof(enum nss_lookup_type) + sizeof(int) +
+ sizeof(size_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(enum nss_lookup_type);
+
+ memcpy(p, &af, sizeof(int));
+ p += sizeof(int);
+
+ memcpy(p, &len, sizeof(size_t));
+ p += sizeof(size_t);
+
+ memcpy(p, src, len);
+
+ res = NS_SUCCESS;
+ break;
+ default:
+ /* should be unreachable */
+ return (NS_UNAVAIL);
+ }
+
+fin:
+ *buffer_size = desired_size;
+ return (res);
+}
+
+static int
+ipnode_marshal_func(char *buffer, size_t *buffer_size, void *retval,
+ va_list ap, void *cache_mdata)
+{
+ struct hostent *ht;
+
+ struct hostent new_ht;
+ size_t desired_size, aliases_size, addr_size, size;
+ char *p, **iter;
+
+ ht = *((struct hostent **)retval);
+
+ 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
+ipnode_unmarshal_func(char *buffer, size_t buffer_size, void *retval,
+ va_list ap, void *cache_mdata)
+{
+ struct hostent new_ht;
+ struct hostent *ht;
+
+ char *p;
+ char **iter;
+ char *orig_buf;
+ int err;
+
+ ht = &new_ht;
+
+ memcpy(ht, buffer, sizeof(struct hostent));
+ memcpy(&p, buffer + sizeof(struct hostent), sizeof(char *));
+
+ orig_buf = buffer + 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 *);
+ }
+
+ ht = _hpcopy(ht, &err);
+ if (ht == NULL)
+ return (NS_UNAVAIL);
+
+ *((struct hostent **)retval) = ht;
+ return (NS_SUCCESS);
+}
+#endif
+
+/*
+ * Functions defined in RFC2553
+ * getipnodebyname, getipnodebyaddr, freehostent
+ */
+
+static struct hostent *
+_ghbyname(const char *name, int af, int flags, int *errp)
+{
+ struct hostent *hp;
+ int rval;
+
+#ifdef NS_CACHING
+ static const nss_cache_info cache_info =
+ NS_COMMON_CACHE_INFO_INITIALIZER(
+ hosts, (void *)nss_lt_name,
+ ipnode_id_func, ipnode_marshal_func, ipnode_unmarshal_func);
+#endif
+ static const ns_dtab dtab[] = {
+ NS_FILES_CB(_files_ghbyname, NULL)
+ { NSSRC_DNS, _dns_ghbyname, NULL },
+ NS_NIS_CB(_nis_ghbyname, NULL)
+#ifdef NS_CACHING
+ NS_CACHE_CB(&cache_info)
+#endif
+ { 0 }
+ };
+
+ if (flags & AI_ADDRCONFIG) {
+ int s;
+
+ if ((s = _socket(af, SOCK_DGRAM, 0)) < 0)
+ return NULL;
+ /*
+ * TODO:
+ * Note that implementation dependent test for address
+ * configuration should be done everytime called
+ * (or apropriate interval),
+ * because addresses will be dynamically assigned or deleted.
+ */
+ _close(s);
+ }
+
+ rval = _nsdispatch(&hp, dtab, NSDB_HOSTS, "ghbyname", default_src,
+ name, af, errp);
+ return (rval == NS_SUCCESS) ? hp : NULL;
+}
+
+struct hostent *
+getipnodebyname(const char *name, int af, int flags, int *errp)
+{
+ struct hostent *hp;
+ union inx_addr addrbuf;
+ res_state statp;
+
+ switch (af) {
+ case AF_INET:
+#ifdef INET6
+ case AF_INET6:
+#endif
+ break;
+ default:
+ *errp = NO_RECOVERY;
+ return NULL;
+ }
+
+#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;
+ }
+ }
+
+ *errp = HOST_NOT_FOUND;
+ hp = _ghbyname(name, af, flags, errp);
+
+#ifdef INET6
+ if (af == AF_INET6 && ((flags & AI_ALL) || hp == NULL) &&
+ MAPADDRENABLED(flags)) {
+ struct hostent *hp2 = _ghbyname(name, AF_INET, flags, errp);
+ if (hp == NULL)
+ hp = _hpmapv6(hp2, errp);
+ else {
+ if (hp2 && strcmp(hp->h_name, hp2->h_name) != 0) {
+ freehostent(hp2);
+ hp2 = NULL;
+ }
+ hp = _hpmerge(hp, hp2, errp);
+ }
+ }
+#endif
+ return _hpreorder(_hpsort(hp, statp));
+}
+
+struct hostent *
+getipnodebyaddr(const void *src, size_t len, int af, int *errp)
+{
+ struct hostent *hp;
+ int rval;
+#ifdef INET6
+ struct in6_addr addrbuf;
+#else
+ struct in_addr addrbuf;
+#endif
+
+#ifdef NS_CACHING
+ static const nss_cache_info cache_info =
+ NS_COMMON_CACHE_INFO_INITIALIZER(
+ hosts, (void *)nss_lt_id,
+ ipnode_id_func, ipnode_marshal_func, ipnode_unmarshal_func);
+#endif
+ static const ns_dtab dtab[] = {
+ NS_FILES_CB(_files_ghbyaddr, NULL)
+ { NSSRC_DNS, _dns_ghbyaddr, NULL },
+ NS_NIS_CB(_nis_ghbyaddr, NULL)
+#ifdef ICMPNL
+ { NSSRC_ICMP, _icmp_ghbyaddr, NULL },
+#endif
+#ifdef NS_CACHING
+ NS_CACHE_CB(&cache_info)
+#endif
+ { 0 }
+ };
+
+ *errp = HOST_NOT_FOUND;
+
+ switch (af) {
+ case AF_INET:
+ if (len != sizeof(struct in_addr)) {
+ *errp = NO_RECOVERY;
+ return NULL;
+ }
+ if ((long)src & ~(sizeof(struct in_addr) - 1)) {
+ 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 ((long)src & ~(sizeof(struct in6_addr) / 2 - 1)) { /*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;
+ }
+
+ rval = _nsdispatch(&hp, dtab, NSDB_HOSTS, "ghbyaddr", default_src,
+ src, len, af, errp);
+ return (rval == NS_SUCCESS) ? hp : NULL;
+}
+
+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);
+}
+
+/*
+ * _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 hp2;
+ if (hp2 == NULL)
+ return hp1;
+
+#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;
+#ifdef INET6
+ if (hp1->h_length != hp2->h_length) {
+ hp->h_addrtype = AF_INET6;
+ hp->h_length = sizeof(struct in6_addr);
+ } else {
+#endif
+ hp->h_addrtype = hp1->h_addrtype;
+ hp->h_length = hp1->h_length;
+#ifdef INET6
+ }
+#endif
+ 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;
+ hp = _hpcopy(hp, errp);
+ freehostent(hp1);
+ freehostent(hp2);
+ return hp;
+}
+
+/*
+ * _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 hp;
+
+ /* make dummy hostent to convert IPv6 address */
+ if ((hp6 = (struct hostent *)malloc(sizeof(struct hostent))) == NULL) {
+ *errp = TRY_AGAIN;
+ return NULL;
+ }
+ hp6->h_name = NULL;
+ hp6->h_aliases = NULL;
+ hp6->h_addrtype = AF_INET6;
+ hp6->h_length = sizeof(struct in6_addr);
+ hp6->h_addr_list = NULL;
+ 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;
+}
+
+static char *
+_hgetword(char **pp)
+{
+ char c, *p, *ret;
+ const char *sp;
+ static const char sep[] = "# \t\n";
+
+ ret = NULL;
+ for (p = *pp; (c = *p) != '\0'; p++) {
+ for (sp = sep; *sp != '\0'; sp++) {
+ if (c == *sp)
+ break;
+ }
+ if (c == '#')
+ p[1] = '\0'; /* ignore rest of line */
+ if (ret == NULL) {
+ if (*sp == '\0')
+ ret = p;
+ } else {
+ if (*sp != '\0') {
+ *p++ = '\0';
+ break;
+ }
+ }
+ }
+ *pp = p;
+ if (ret == NULL || *ret == '\0')
+ return NULL;
+ return ret;
+}
+
+/*
+ * _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:
+ free_addrselectpolicy(&policyhead);
+ 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);
+ }
+
+ /* 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, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0)
+ return (0);
+ if ((buf = malloc(l)) == NULL)
+ return (0);
+ if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), 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);
+ key.sin6_addr.s6_addr[10] = 0xff;
+ key.sin6_addr.s6_addr[11] = 0xff;
+ memcpy(&key.sin6_addr.s6_addr[12],
+ &((struct sockaddr_in *)addr)->sin_addr, 4);
+ 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, 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;
+
+ /* XXX: interface name should not be hardcoded */
+ strncpy(ifr6.ifr_name, "lo0", sizeof(ifr6.ifr_name));
+ 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 < addrlen * 8) {
+ 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. */
+ 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);
+ }
+}
+
+/*
+ * FILES (/etc/hosts)
+ */
+
+static FILE *
+_files_open(int *errp)
+{
+ FILE *fp;
+ fp = fopen(_PATH_HOSTS, "r");
+ if (fp == NULL)
+ *errp = NO_RECOVERY;
+ return fp;
+}
+
+static int
+_files_ghbyname(void *rval, void *cb_data, va_list ap)
+{
+ const char *name;
+ int af;
+ int *errp;
+ int match, nalias;
+ char *p, *line, *addrstr, *cname;
+ FILE *fp;
+ struct hostent *rethp, *hp, hpbuf;
+ char *aliases[MAXALIASES + 1], *addrs[2];
+ union inx_addr addrbuf;
+ char buf[BUFSIZ];
+
+ name = va_arg(ap, const char *);
+ af = va_arg(ap, int);
+ errp = va_arg(ap, int *);
+
+ *(struct hostent **)rval = NULL;
+
+ if ((fp = _files_open(errp)) == NULL)
+ return NS_UNAVAIL;
+ rethp = hp = NULL;
+
+ while (fgets(buf, sizeof(buf), fp)) {
+ line = buf;
+ if ((addrstr = _hgetword(&line)) == NULL
+ || (cname = _hgetword(&line)) == NULL)
+ continue;
+ match = (strcasecmp(cname, name) == 0);
+ nalias = 0;
+ while ((p = _hgetword(&line)) != NULL) {
+ if (!match)
+ match = (strcasecmp(p, name) == 0);
+ if (nalias < MAXALIASES)
+ aliases[nalias++] = p;
+ }
+ if (!match)
+ continue;
+ switch (af) {
+ case AF_INET:
+ if (inet_aton(addrstr, (struct in_addr *)&addrbuf)
+ != 1) {
+ *errp = NO_DATA; /* name found */
+ continue;
+ }
+ break;
+#ifdef INET6
+ case AF_INET6:
+ if (inet_pton(af, addrstr, &addrbuf) != 1) {
+ *errp = NO_DATA; /* name found */
+ continue;
+ }
+ break;
+#endif
+ }
+ hp = &hpbuf;
+ hp->h_name = cname;
+ hp->h_aliases = aliases;
+ aliases[nalias] = NULL;
+ hp->h_addrtype = af;
+ hp->h_length = ADDRLEN(af);
+ hp->h_addr_list = addrs;
+ addrs[0] = (char *)&addrbuf;
+ addrs[1] = NULL;
+ hp = _hpcopy(hp, errp);
+ rethp = _hpmerge(rethp, hp, errp);
+ }
+ fclose(fp);
+ *(struct hostent **)rval = rethp;
+ return (rethp != NULL) ? NS_SUCCESS : NS_NOTFOUND;
+}
+
+static int
+_files_ghbyaddr(void *rval, void *cb_data, va_list ap)
+{
+ const void *addr;
+ int addrlen;
+ int af;
+ int *errp;
+ int nalias;
+ char *p, *line;
+ FILE *fp;
+ struct hostent *hp, hpbuf;
+ char *aliases[MAXALIASES + 1], *addrs[2];
+ union inx_addr addrbuf;
+ char buf[BUFSIZ];
+
+ addr = va_arg(ap, const void *);
+ addrlen = va_arg(ap, int);
+ af = va_arg(ap, int);
+ errp = va_arg(ap, int *);
+
+ *(struct hostent**)rval = NULL;
+
+ if ((fp = _files_open(errp)) == NULL)
+ return NS_UNAVAIL;
+ hp = NULL;
+ while (fgets(buf, sizeof(buf), fp)) {
+ line = buf;
+ if ((p = _hgetword(&line)) == NULL
+ || (af == AF_INET
+ ? inet_aton(p, (struct in_addr *)&addrbuf)
+ : inet_pton(af, p, &addrbuf)) != 1
+ || memcmp(addr, &addrbuf, addrlen) != 0
+ || (p = _hgetword(&line)) == NULL)
+ continue;
+ hp = &hpbuf;
+ hp->h_name = p;
+ hp->h_aliases = aliases;
+ nalias = 0;
+ while ((p = _hgetword(&line)) != NULL) {
+ if (nalias < MAXALIASES)
+ aliases[nalias++] = p;
+ }
+ aliases[nalias] = NULL;
+ hp->h_addrtype = af;
+ hp->h_length = addrlen;
+ hp->h_addr_list = addrs;
+ addrs[0] = (char *)&addrbuf;
+ addrs[1] = NULL;
+ hp = _hpcopy(hp, errp);
+ break;
+ }
+ fclose(fp);
+ *(struct hostent **)rval = hp;
+ return (hp != NULL) ? NS_SUCCESS : NS_NOTFOUND;
+}
+
+#ifdef YP
+/*
+ * NIS
+ *
+ * XXX actually a hack.
+ */
+static int
+_nis_ghbyname(void *rval, void *cb_data, va_list ap)
+{
+ const char *name;
+ int af;
+ int *errp;
+ struct hostent *hp = NULL;
+
+ name = va_arg(ap, const char *);
+ af = va_arg(ap, int);
+ errp = va_arg(ap, int *);
+
+ hp = _gethostbynisname(name, af);
+ if (hp != NULL)
+ hp = _hpcopy(hp, errp);
+
+ *(struct hostent **)rval = hp;
+ return (hp != NULL) ? NS_SUCCESS : NS_NOTFOUND;
+}
+
+static int
+_nis_ghbyaddr(void *rval, void *cb_data, va_list ap)
+{
+ const void *addr;
+ int addrlen;
+ int af;
+ int *errp;
+ struct hostent *hp = NULL;
+
+ addr = va_arg(ap, const void *);
+ addrlen = va_arg(ap, int);
+ af = va_arg(ap, int);
+
+ hp = _gethostbynisaddr(addr, addrlen, af);
+ if (hp != NULL)
+ hp = _hpcopy(hp, errp);
+ *(struct hostent **)rval = hp;
+ return (hp != NULL) ? NS_SUCCESS : NS_NOTFOUND;
+}
+#endif
+
+#define MAXPACKET (64*1024)
+
+typedef union {
+ HEADER hdr;
+ u_char buf[MAXPACKET];
+} querybuf;
+
+static struct hostent *getanswer(const querybuf *, int, const char *, int,
+ struct hostent *, int *);
+
+/*
+ * we don't need to take care about sorting, nor IPv4 mapped address here.
+ */
+static struct hostent *
+getanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
+ struct hostent *template, int *errp)
+{
+ 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;
+ char tbuf[MAXDNAME];
+ const char *tname;
+ int (*name_ok)(const char *);
+ static char *h_addr_ptrs[MAXADDRS + 1];
+ static char *host_aliases[MAXALIASES];
+ static char hostbuf[8*1024];
+
+#define BOUNDED_INCR(x) \
+ do { \
+ cp += x; \
+ if (cp > eom) { \
+ *errp = NO_RECOVERY; \
+ return (NULL); \
+ } \
+ } while (0)
+
+#define BOUNDS_CHECK(ptr, count) \
+ do { \
+ if ((ptr) + (count) > eom) { \
+ *errp = NO_RECOVERY; \
+ return (NULL); \
+ } \
+ } while (0)
+
+/* XXX do {} while (0) cannot be put here */
+#define DNS_ASSERT(x) \
+ { \
+ if (!(x)) { \
+ cp += n; \
+ continue; \
+ } \
+ }
+
+/* XXX do {} while (0) cannot be put here */
+#define DNS_FATAL(x) \
+ { \
+ if (!(x)) { \
+ had_error++; \
+ continue; \
+ } \
+ }
+
+ tname = qname;
+ template->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:
+ 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;
+ BOUNDED_INCR(HFIXEDSZ);
+ if (qdcount != 1) {
+ *errp = NO_RECOVERY;
+ return (NULL);
+ }
+ n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
+ if ((n < 0) || !(*name_ok)(bp)) {
+ *errp = NO_RECOVERY;
+ return (NULL);
+ }
+ 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) {
+ *errp = NO_RECOVERY;
+ return (NULL);
+ }
+ template->h_name = bp;
+ bp += n;
+ /* The qname can be abbreviated, but h_name is now absolute. */
+ qname = template->h_name;
+ }
+ ap = host_aliases;
+ *ap = NULL;
+ template->h_aliases = host_aliases;
+ hap = h_addr_ptrs;
+ *hap = NULL;
+ template->h_addr_list = h_addr_ptrs;
+ haveanswer = 0;
+ had_error = 0;
+ while (ancount-- > 0 && cp < eom && !had_error) {
+ n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
+ DNS_FATAL(n >= 0);
+ DNS_FATAL((*name_ok)(bp));
+ cp += n; /* name */
+ BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ);
+ type = _getshort(cp);
+ cp += INT16SZ; /* type */
+ class = _getshort(cp);
+ cp += INT16SZ + INT32SZ; /* class, TTL */
+ n = _getshort(cp);
+ cp += INT16SZ; /* len */
+ BOUNDS_CHECK(cp, n);
+ erdata = cp + n;
+ DNS_ASSERT(class == C_IN);
+ if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) {
+ if (ap >= &host_aliases[MAXALIASES-1])
+ continue;
+ n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
+ DNS_FATAL(n >= 0);
+ DNS_FATAL((*name_ok)(tbuf));
+ cp += n;
+ if (cp != erdata) {
+ *errp = NO_RECOVERY;
+ return (NULL);
+ }
+ /* Store alias. */
+ *ap++ = bp;
+ n = strlen(bp) + 1; /* for the \0 */
+ DNS_FATAL(n < MAXHOSTNAMELEN);
+ bp += n;
+ /* Get canonical name. */
+ n = strlen(tbuf) + 1; /* for the \0 */
+ DNS_FATAL(n <= ep - bp);
+ DNS_FATAL(n < MAXHOSTNAMELEN);
+ strcpy(bp, tbuf);
+ template->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) {
+ *errp = NO_RECOVERY;
+ return (NULL);
+ }
+ /* 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;
+ }
+ DNS_ASSERT(type == qtype);
+ switch (type) {
+ case T_PTR:
+ DNS_ASSERT(strcasecmp(tname, bp) == 0);
+ n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
+ DNS_FATAL(n >= 0);
+ DNS_FATAL(res_hnok(bp));
+#if MULTI_PTRS_ARE_ALIASES
+ cp += n;
+ if (cp != erdata) {
+ *errp = NO_RECOVERY;
+ return (NULL);
+ }
+ if (!haveanswer)
+ template->h_name = bp;
+ else if (ap < &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
+ template->h_name = bp;
+ *errp = NETDB_SUCCESS;
+ return (template);
+#endif
+ case T_A:
+ case T_AAAA:
+ DNS_ASSERT(strcasecmp(template->h_name, bp) == 0);
+ DNS_ASSERT(n == template->h_length);
+ if (!haveanswer) {
+ int nn;
+
+ template->h_name = bp;
+ nn = strlen(bp) + 1; /* for the \0 */
+ bp += nn;
+ }
+ bp = (char *)ALIGN(bp);
+
+ DNS_FATAL(bp + n < ep);
+ DNS_ASSERT(hap < &h_addr_ptrs[MAXADDRS-1]);
+#ifdef FILTER_V4MAPPED
+ if (type == T_AAAA) {
+ struct in6_addr in6;
+ memcpy(&in6, cp, sizeof(in6));
+ DNS_ASSERT(IN6_IS_ADDR_V4MAPPED(&in6) == 0);
+ }
+#endif
+ bcopy(cp, *hap++ = bp, n);
+ bp += n;
+ cp += n;
+ if (cp != erdata) {
+ *errp = NO_RECOVERY;
+ return (NULL);
+ }
+ break;
+ default:
+ abort();
+ }
+ if (!had_error)
+ haveanswer++;
+ }
+ if (haveanswer) {
+ *ap = NULL;
+ *hap = NULL;
+ if (!template->h_name) {
+ n = strlen(qname) + 1; /* for the \0 */
+ if (n > ep - bp || n >= MAXHOSTNAMELEN)
+ goto no_recovery;
+ strcpy(bp, qname);
+ template->h_name = bp;
+ bp += n;
+ }
+ *errp = NETDB_SUCCESS;
+ return (template);
+ }
+ no_recovery:
+ *errp = NO_RECOVERY;
+ return (NULL);
+
+#undef BOUNDED_INCR
+#undef BOUNDS_CHECK
+#undef DNS_ASSERT
+#undef DNS_FATAL
+}
+
+static int
+_dns_ghbyname(void *rval, void *cb_data, va_list ap)
+{
+ const char *name;
+ int af;
+ int *errp;
+ int n;
+ struct hostent *hp;
+ int qtype;
+ struct hostent hbuf;
+ querybuf *buf;
+ res_state statp;
+
+ name = va_arg(ap, const char *);
+ af = va_arg(ap, int);
+ errp = va_arg(ap, int *);
+
+ statp = __res_state();
+
+ memset(&hbuf, 0, sizeof(hbuf));
+ hbuf.h_addrtype = af;
+ hbuf.h_length = ADDRLEN(af);
+
+ switch (af) {
+#ifdef INET6
+ case AF_INET6:
+ qtype = T_AAAA;
+ break;
+#endif
+ case AF_INET:
+ qtype = T_A;
+ break;
+ default:
+ *errp = NO_RECOVERY;
+ return NS_NOTFOUND;
+ }
+ buf = malloc(sizeof(*buf));
+ if (buf == NULL) {
+ *errp = NETDB_INTERNAL;
+ return NS_UNAVAIL;
+ }
+ n = res_nsearch(statp, name, C_IN, qtype, buf->buf, sizeof(buf->buf));
+ if (n < 0) {
+ free(buf);
+ *errp = statp->res_h_errno;
+ return NS_UNAVAIL;
+ }
+ hp = getanswer(buf, n, name, qtype, &hbuf, errp);
+ free(buf);
+ if (!hp) {
+ *errp = NO_RECOVERY;
+ return NS_NOTFOUND;
+ }
+ *(struct hostent **)rval = _hpcopy(&hbuf, errp);
+ if (*(struct hostent **)rval != NULL)
+ return NS_SUCCESS;
+ else if (*errp == TRY_AGAIN)
+ return NS_TRYAGAIN;
+ else
+ return NS_NOTFOUND;
+}
+
+static int
+_dns_ghbyaddr(void *rval, void *cb_data, va_list ap)
+{
+ const void *addr;
+ int addrlen;
+ int af;
+ int *errp;
+ int n;
+ int err;
+ struct hostent *hp;
+ u_char c, *cp;
+ char *bp;
+ struct hostent hbuf;
+#ifdef INET6
+ static const char hex[] = "0123456789abcdef";
+#endif
+ querybuf *buf;
+ char qbuf[MAXDNAME+1];
+ char *hlist[2];
+ char *tld6[] = { "ip6.arpa", NULL };
+ char *tld4[] = { "in-addr.arpa", NULL };
+ char **tld;
+ res_state statp;
+
+ addr = va_arg(ap, const void *);
+ addrlen = va_arg(ap, int);
+ af = va_arg(ap, int);
+ errp = va_arg(ap, int *);
+
+ *(struct hostent **)rval = NULL;
+
+#ifdef INET6
+ /* XXX */
+ if (af == AF_INET6 && IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)addr))
+ return NS_NOTFOUND;
+#endif
+
+ switch (af) {
+#ifdef INET6
+ case AF_INET6:
+ tld = tld6;
+ break;
+#endif
+ case AF_INET:
+ tld = tld4;
+ break;
+ default:
+ return NS_NOTFOUND;
+ }
+
+ statp = __res_state();
+ if ((statp->options & RES_INIT) == 0) {
+ if (res_ninit(statp) < 0) {
+ *errp = NETDB_INTERNAL;
+ return NS_UNAVAIL;
+ }
+ }
+ memset(&hbuf, 0, sizeof(hbuf));
+ hbuf.h_name = NULL;
+ hbuf.h_addrtype = af;
+ hbuf.h_length = addrlen;
+
+ buf = malloc(sizeof(*buf));
+ if (buf == NULL) {
+ *errp = NETDB_INTERNAL;
+ return NS_UNAVAIL;
+ }
+ err = NS_SUCCESS;
+ for (/* nothing */; *tld; tld++) {
+ /*
+ * XXX assumes that MAXDNAME is big enough - error checks
+ * has been made by callers
+ */
+ n = 0;
+ bp = qbuf;
+ cp = (u_char *)addr+addrlen-1;
+ switch (af) {
+#ifdef INET6
+ case AF_INET6:
+ for (; n < addrlen; n++, cp--) {
+ c = *cp;
+ *bp++ = hex[c & 0xf];
+ *bp++ = '.';
+ *bp++ = hex[c >> 4];
+ *bp++ = '.';
+ }
+ strcpy(bp, *tld);
+ break;
+#endif
+ case AF_INET:
+ for (; n < addrlen; n++, cp--) {
+ c = *cp;
+ if (c >= 100)
+ *bp++ = '0' + c / 100;
+ if (c >= 10)
+ *bp++ = '0' + (c % 100) / 10;
+ *bp++ = '0' + c % 10;
+ *bp++ = '.';
+ }
+ strcpy(bp, *tld);
+ break;
+ }
+
+ n = res_nquery(statp, qbuf, C_IN, T_PTR, buf->buf,
+ sizeof buf->buf);
+ if (n < 0) {
+ *errp = statp->res_h_errno;
+ err = NS_UNAVAIL;
+ continue;
+ } else if (n > sizeof(buf->buf)) {
+#if 0
+ errno = ERANGE; /* XXX is it OK to set errno here? */
+#endif
+ *errp = NETDB_INTERNAL;
+ err = NS_UNAVAIL;
+ continue;
+ }
+ hp = getanswer(buf, n, qbuf, T_PTR, &hbuf, errp);
+ if (!hp) {
+ err = NS_NOTFOUND;
+ continue;
+ }
+ free(buf);
+ hbuf.h_addrtype = af;
+ hbuf.h_length = addrlen;
+ hbuf.h_addr_list = hlist;
+ hlist[0] = (char *)addr;
+ hlist[1] = NULL;
+ *(struct hostent **)rval = _hpcopy(&hbuf, errp);
+ return NS_SUCCESS;
+ }
+ free(buf);
+ return err;
+}
+
+static void
+_dns_shent(int stayopen)
+{
+ res_state statp;
+
+ statp = __res_state();
+ if ((statp->options & RES_INIT) == 0) {
+ if (res_ninit(statp) < 0)
+ return;
+ }
+ if (stayopen)
+ statp->options |= RES_STAYOPEN | RES_USEVC;
+}
+
+static void
+_dns_ehent(void)
+{
+ res_state statp;
+
+ statp = __res_state();
+ statp->options &= ~(RES_STAYOPEN | RES_USEVC);
+ res_nclose(statp);
+}
+
+#ifdef ICMPNL
+
+/*
+ * experimental:
+ * draft-ietf-ipngwg-icmp-namelookups-02.txt
+ * ifindex is assumed to be encoded in addr.
+ */
+#include <sys/uio.h>
+#include <netinet/ip6.h>
+#include <netinet/icmp6.h>
+
+struct _icmp_host_cache {
+ struct _icmp_host_cache *hc_next;
+ int hc_ifindex;
+ struct in6_addr hc_addr;
+ char *hc_name;
+};
+
+static char *
+_icmp_fqdn_query(const struct in6_addr *addr, int ifindex)
+{
+ int s;
+ struct icmp6_filter filter;
+ struct msghdr msg;
+ struct cmsghdr *cmsg;
+ struct in6_pktinfo *pkt;
+ char cbuf[256];
+ char buf[1024];
+ int cc;
+ struct icmp6_fqdn_query *fq;
+ struct icmp6_fqdn_reply *fr;
+ struct _icmp_host_cache *hc;
+ struct sockaddr_in6 sin6;
+ struct iovec iov;
+ fd_set s_fds, fds;
+ struct timeval tout;
+ int len;
+ char *name;
+ static struct _icmp_host_cache *hc_head;
+
+ THREAD_LOCK();
+ for (hc = hc_head; hc; hc = hc->hc_next) {
+ if (hc->hc_ifindex == ifindex
+ && IN6_ARE_ADDR_EQUAL(&hc->hc_addr, addr)) {
+ THREAD_UNLOCK();
+ return hc->hc_name; /* XXX: never freed */
+ }
+ }
+ THREAD_UNLOCK();
+
+ ICMP6_FILTER_SETBLOCKALL(&filter);
+ ICMP6_FILTER_SETPASS(ICMP6_FQDN_REPLY, &filter);
+
+ FD_ZERO(&s_fds);
+ tout.tv_sec = 0;
+ tout.tv_usec = 200000; /*XXX: 200ms*/
+
+ fq = (struct icmp6_fqdn_query *)buf;
+ fq->icmp6_fqdn_type = ICMP6_FQDN_QUERY;
+ fq->icmp6_fqdn_code = 0;
+ fq->icmp6_fqdn_cksum = 0;
+ fq->icmp6_fqdn_id = (u_short)getpid();
+ fq->icmp6_fqdn_unused = 0;
+ fq->icmp6_fqdn_cookie[0] = 0;
+ fq->icmp6_fqdn_cookie[1] = 0;
+
+ memset(&sin6, 0, sizeof(sin6));
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_addr = *addr;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_name = (caddr_t)&sin6;
+ msg.msg_namelen = sizeof(sin6);
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ iov.iov_base = (caddr_t)buf;
+ iov.iov_len = sizeof(struct icmp6_fqdn_query);
+
+ if (ifindex) {
+ msg.msg_control = cbuf;
+ msg.msg_controllen = sizeof(cbuf);
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
+ cmsg->cmsg_level = IPPROTO_IPV6;
+ cmsg->cmsg_type = IPV6_PKTINFO;
+ pkt = (struct in6_pktinfo *)&cmsg[1];
+ memset(&pkt->ipi6_addr, 0, sizeof(struct in6_addr));
+ pkt->ipi6_ifindex = ifindex;
+ cmsg = CMSG_NXTHDR(&msg, cmsg);
+ msg.msg_controllen = (char *)cmsg - cbuf;
+ }
+
+ if ((s = _socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0)
+ return NULL;
+ (void)_setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER,
+ (char *)&filter, sizeof(filter));
+ cc = _sendmsg(s, &msg, 0);
+ if (cc < 0) {
+ _close(s);
+ return NULL;
+ }
+ FD_SET(s, &s_fds);
+ for (;;) {
+ fds = s_fds;
+ if (_select(s + 1, &fds, NULL, NULL, &tout) <= 0) {
+ _close(s);
+ return NULL;
+ }
+ len = sizeof(sin6);
+ cc = _recvfrom(s, buf, sizeof(buf), 0,
+ (struct sockaddr *)&sin6, &len);
+ if (cc <= 0) {
+ _close(s);
+ return NULL;
+ }
+ if (cc < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr))
+ continue;
+ if (!IN6_ARE_ADDR_EQUAL(addr, &sin6.sin6_addr))
+ continue;
+ fr = (struct icmp6_fqdn_reply *)(buf + sizeof(struct ip6_hdr));
+ if (fr->icmp6_fqdn_type == ICMP6_FQDN_REPLY)
+ break;
+ }
+ _close(s);
+ if (fr->icmp6_fqdn_cookie[1] != 0) {
+ /* rfc1788 type */
+ name = buf + sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) + 4;
+ len = (buf + cc) - name;
+ } else {
+ len = fr->icmp6_fqdn_namelen;
+ name = fr->icmp6_fqdn_name;
+ }
+ if (len <= 0)
+ return NULL;
+ name[len] = 0;
+
+ if ((hc = (struct _icmp_host_cache *)malloc(sizeof(*hc))) == NULL)
+ return NULL;
+ /* XXX: limit number of cached entries */
+ hc->hc_ifindex = ifindex;
+ hc->hc_addr = *addr;
+ hc->hc_name = strdup(name);
+ THREAD_LOCK();
+ hc->hc_next = hc_head;
+ hc_head = hc;
+ THREAD_UNLOCK();
+ return hc->hc_name;
+}
+
+static struct hostent *
+_icmp_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
+{
+ char *hname;
+ int ifindex;
+ struct in6_addr addr6;
+
+ if (af != AF_INET6) {
+ /*
+ * Note: rfc1788 defines Who Are You for IPv4,
+ * but no one implements it.
+ */
+ return NULL;
+ }
+
+ memcpy(&addr6, addr, addrlen);
+ ifindex = (addr6.s6_addr[2] << 8) | addr6.s6_addr[3];
+ addr6.s6_addr[2] = addr6.s6_addr[3] = 0;
+
+ if (!IN6_IS_ADDR_LINKLOCAL(&addr6))
+ return NULL; /*XXX*/
+
+ if ((hname = _icmp_fqdn_query(&addr6, ifindex)) == NULL)
+ return NULL;
+ return _hpaddr(af, hname, &addr6, errp);
+}
+#endif /* ICMPNL */
diff --git a/lib/libc/net/netdb_private.h b/lib/libc/net/netdb_private.h
new file mode 100644
index 0000000..b48dd7b
--- /dev/null
+++ b/lib/libc/net/netdb_private.h
@@ -0,0 +1,145 @@
+/*-
+ * 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 *);
+struct hostent *_gethostbynisaddr(const void *, socklen_t, int);
+struct hostent *_gethostbynisname(const char *, int);
+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 *);
+
+#endif /* _NETDB_PRIVATE_H_ */
diff --git a/lib/libc/net/nscache.c b/lib/libc/net/nscache.c
new file mode 100644
index 0000000..98a4367
--- /dev/null
+++ b/lib/libc/net/nscache.c
@@ -0,0 +1,438 @@
+/*-
+ * 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 <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/cached"
+
+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 0000000..d95a0e8
--- /dev/null
+++ b/lib/libc/net/nscachedcli.c
@@ -0,0 +1,576 @@
+/*-
+ * 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 = _write(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);
+}
+
+/*
+ * 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 availabe 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, 0) == -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, 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 0000000..06af7af
--- /dev/null
+++ b/lib/libc/net/nsdispatch.3
@@ -0,0 +1,250 @@
+.\" $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.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the NetBSD
+.\" Foundation, Inc. and its contributors.
+.\" 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 16, 2003
+.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
+.Bd -ragged -offset indent
+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 .
+.Ed
+.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;
+ u_int32_t flags;
+} ns_src;
+.Ed
+.Pp
+.Bd -ragged -offset indent
+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:
+.Dl extern const ns_src __nsdefaultsrc[];
+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.
+.Ed
+.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_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.
+.Pp
+.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 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
+Luke Mewburn
+.Aq 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 0000000..0e3c419
--- /dev/null
+++ b/lib/libc/net/nsdispatch.c
@@ -0,0 +1,715 @@
+/* $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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 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.
+ */
+/*-
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include "un-namespace.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
+
+/*
+ * 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 pthread_mutex_t conf_lock = PTHREAD_MUTEX_INITIALIZER;
+ 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) {
+ result = _pthread_mutex_trylock(&conf_lock);
+ if (result != 0)
+ return (0);
+ (void)_pthread_rwlock_unlock(&nss_lock);
+ result = _pthread_rwlock_wrlock(&nss_lock);
+ if (result != 0)
+ goto fin2;
+ }
+ _nsyyin = fopen(path, "r");
+ 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 = 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);
+ }
+fin2:
+ if (isthreaded)
+ (void)_pthread_mutex_unlock(&conf_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);
+}
+
+
+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 = 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);
+ }
+ }
+ if (is_dynamic())
+ nss_log(LOG_DEBUG, "%s, %s, %s, not found", source, database,
+ method);
+ *mdata = NULL;
+ return (NULL);
+}
+
+
+__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;
+ void *mdata;
+ int isthreaded, serrno, i, result, srclistsize;
+
+#ifdef NS_CACHING
+ nss_cache_data cache_data;
+ nss_cache_data *cache_data_p;
+ int cache_flag;
+#endif
+
+ isthreaded = __isthreaded;
+ serrno = errno;
+ if (isthreaded) {
+ result = _pthread_rwlock_rdlock(&nss_lock);
+ if (result != 0) {
+ result = NS_UNAVAIL;
+ goto fin;
+ }
+ }
+ result = nss_configure();
+ if (result != 0) {
+ result = NS_UNAVAIL;
+ goto fin;
+ }
+ dbt = vector_search(&database, _nsmap, _nsmapsize, sizeof(*_nsmap),
+ string_compare);
+ 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;
+ va_start(ap, defaults);
+ result = method(retval, mdata, ap);
+ va_end(ap);
+ }
+#else /* NS_CACHING */
+ va_start(ap, defaults);
+ result = method(retval, mdata, ap);
+ va_end(ap);
+#endif /* NS_CACHING */
+
+ if (result & (srclist[i].flags))
+ break;
+ }
+ }
+
+#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);
+fin:
+ errno = serrno;
+ return (result);
+}
diff --git a/lib/libc/net/nslexer.l b/lib/libc/net/nslexer.l
new file mode 100644
index 0000000..34c79d9
--- /dev/null
+++ b/lib/libc/net/nslexer.l
@@ -0,0 +1,119 @@
+%{
+/* $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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 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.
+ */
+
+#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"
+
+#define YY_NO_UNPUT
+
+%}
+
+%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()
+{
+ return 1;
+} /* _nsyywrap */
+
+void
+_nsyyerror(msg)
+ 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 0000000..1f0fff1
--- /dev/null
+++ b/lib/libc/net/nsparser.y
@@ -0,0 +1,179 @@
+%{
+/* $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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#define _NS_PRIVATE
+#include <nsswitch.h>
+#include <stdio.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
+ | 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(elem)
+ 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);
+ 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);
+ 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 0000000..9bea37b
--- /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 0000000..09a2d4f
--- /dev/null
+++ b/lib/libc/net/nss_compat.c
@@ -0,0 +1,278 @@
+/*-
+ * 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 (*fn)(const char *, struct group *, char *, size_t, int *);
+ const char *name;
+ struct group *grp;
+ char *buffer;
+ int *errnop;
+ size_t bufsize;
+ enum nss_status 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 *);
+ status = fn(name, grp, buffer, bufsize, errnop);
+ status = __nss_compat_result(status, *errnop);
+ if (status == NS_SUCCESS)
+ *(struct group **)retval = grp;
+ return (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;
+ size_t bufsize;
+ enum nss_status 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 *);
+ status = fn(gid, grp, buffer, bufsize, errnop);
+ status = __nss_compat_result(status, *errnop);
+ if (status == NS_SUCCESS)
+ *(struct group **)retval = grp;
+ return (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;
+ size_t bufsize;
+ enum nss_status 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 *);
+ status = fn(grp, buffer, bufsize, errnop);
+ status = __nss_compat_result(status, *errnop);
+ if (status == NS_SUCCESS)
+ *(struct group **)retval = grp;
+ else if (status != NS_RETURN)
+ SET_TERMINATOR(group, &terminator);
+ return (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;
+ size_t bufsize;
+ enum nss_status 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 *);
+ status = fn(name, pwd, buffer, bufsize, errnop);
+ status = __nss_compat_result(status, *errnop);
+ if (status == NS_SUCCESS)
+ *(struct passwd **)retval = pwd;
+ return (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;
+ size_t bufsize;
+ enum nss_status 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 *);
+ status = fn(uid, pwd, buffer, bufsize, errnop);
+ status = __nss_compat_result(status, *errnop);
+ if (status == NS_SUCCESS)
+ *(struct passwd **)retval = pwd;
+ return (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;
+ size_t bufsize;
+ enum nss_status 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 *);
+ status = fn(pwd, buffer, bufsize, errnop);
+ status = __nss_compat_result(status, *errnop);
+ if (status == NS_SUCCESS)
+ *(struct passwd **)retval = pwd;
+ else if (status != NS_RETURN)
+ SET_TERMINATOR(passwd, &terminator);
+ return (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/rcmd.3 b/lib/libc/net/rcmd.3
new file mode 100644
index 0000000..03403b8
--- /dev/null
+++ b/lib/libc/net/rcmd.3
@@ -0,0 +1,302 @@
+.\" 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. 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.
+.\"
+.\" 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 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 0000000..422e903
--- /dev/null
+++ b/lib/libc/net/rcmd.c
@@ -0,0 +1,765 @@
+/*
+ * 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.
+ * 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.
+ */
+
+#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"
+
+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(ahost, rport, locuser, remuser, cmd, fd2p)
+ char **ahost;
+ u_short rport;
+ const char *locuser, *remuser, *cmd;
+ int *fd2p;
+{
+ return rcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, AF_INET);
+}
+
+int
+rcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, af)
+ char **ahost;
+ u_short rport;
+ const char *locuser, *remuser, *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);
+ _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);
+ _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);
+ _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 == 0) {
+ _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;
+ }
+ _sigprocmask(SIG_SETMASK, (const sigset_t *)&oldmask, NULL);
+ freeaddrinfo(res);
+ return (s);
+bad2:
+ if (lport)
+ (void)_close(*fd2p);
+bad:
+ (void)_close(s);
+ _sigprocmask(SIG_SETMASK, (const sigset_t *)&oldmask, NULL);
+ freeaddrinfo(res);
+ return (-1);
+}
+
+int
+rresvport(port)
+ int *port;
+{
+ return rresvport_af(port, AF_INET);
+}
+
+int
+rresvport_af(alport, family)
+ int *alport, 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(rhost, superuser, ruser, luser)
+ const char *rhost, *ruser, *luser;
+ int superuser;
+{
+ 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(raddr, superuser, ruser, luser)
+ unsigned long raddr;
+ int superuser;
+ const char *ruser, *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(ra, rlen, superuser, ruser, luser)
+ const void *ra;
+ int rlen;
+ int superuser;
+ const char *ruser, *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, "r");
+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, "r");
+ (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(hostf, raddr, luser, ruser)
+ FILE *hostf;
+ u_int32_t raddr;
+ const char *luser, *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(hostf, raddr, luser, ruser, af, len)
+ FILE *hostf;
+ const void *raddr;
+ const char *luser, *ruser;
+ int af, 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(hostf, raddr, salen, luser, ruser)
+ FILE *hostf;
+ const struct sockaddr *raddr;
+ socklen_t salen;
+ const char *luser, *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(raddr, salen, lhost)
+ 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 0000000..03e7dab
--- /dev/null
+++ b/lib/libc/net/rcmdsh.3
@@ -0,0 +1,120 @@
+.\" $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.
+.\" 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.
+.\"
+.\" $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 0000000..bc4e87a
--- /dev/null
+++ b/lib/libc/net/rcmdsh.c
@@ -0,0 +1,170 @@
+/* $OpenBSD: rcmdsh.c,v 1.5 1998/04/25 16:23:58 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 <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>
+
+#ifndef _PATH_RSH
+#define _PATH_RSH "/usr/bin/rsh"
+#endif
+
+/*
+ * 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(ahost, rport, locuser, remuser, cmd, rshprog)
+ char **ahost;
+ int rport;
+ const char *locuser, *remuser, *cmd, *rshprog;
+{
+ struct addrinfo hints, *res;
+ int cpid, sp[2], error;
+ 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)wait(NULL);
+ return (sp[0]);
+ }
+ /* NOTREACHED */
+}
diff --git a/lib/libc/net/recv.c b/lib/libc/net/recv.c
new file mode 100644
index 0000000..267e171
--- /dev/null
+++ b/lib/libc/net/recv.c
@@ -0,0 +1,54 @@
+/*
+ * 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. 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.
+ */
+
+#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 "namespace.h"
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <stddef.h>
+#include "un-namespace.h"
+
+ssize_t
+recv(s, buf, len, flags)
+ int s, flags;
+ size_t len;
+ void *buf;
+{
+ return (_recvfrom(s, buf, len, flags, NULL, 0));
+}
diff --git a/lib/libc/net/res_config.h b/lib/libc/net/res_config.h
new file mode 100644
index 0000000..05909bc
--- /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 DONT NEED IT */
+#define MULTI_PTRS_ARE_ALIASES 1 /* fold multiple PTR records into aliases */
diff --git a/lib/libc/net/res_mkupdate.c b/lib/libc/net/res_mkupdate.c
new file mode 100644
index 0000000..ebcaba2
--- /dev/null
+++ b/lib/libc/net/res_mkupdate.c
@@ -0,0 +1,406 @@
+/*
+ * 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.
+ */
+
+/*
+ * Based on the Dynamic DNS reference implementation by Viraj Bais
+ * <viraj_bais@ccm.fm.intel.com>
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.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>
+
+#include "res_config.h"
+
+static int getnum_str(u_char **, u_char *);
+static int getword_str(char *, int, u_char **, u_char *);
+
+#define ShrinkBuffer(x) if ((buflen -= x) < 0) return (-2);
+
+/*
+ * Form update packets.
+ * Returns the size of the resulting packet if no error
+ * On error,
+ * returns -1 if error in reading a word/number in rdata
+ * portion for update packets
+ * -2 if length of buffer passed is insufficient
+ * -3 if zone section is not the first section in
+ * the linked list, or section order has a problem
+ * -4 on a number overflow
+ * -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;
+ char buf2[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;
+
+ /*
+ * Initialize header fields.
+ */
+ if ((buf == NULL) || (buflen < HFIXEDSZ))
+ return (-1);
+ memset(buf, 0, HFIXEDSZ);
+ hp = (HEADER *) buf;
+ 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 + sizeof dnptrs / sizeof dnptrs[0];
+
+ 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 = rrecp->r_grpnext) {
+ 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_nmkupdate: 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_nmkupdate: 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:
+ 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);
+ PUTSHORT(n, cp);
+ ShrinkBuffer(INT16SZ);
+ 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_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:
+ case T_HINFO:
+ case T_TXT:
+ case T_X25:
+ case T_ISDN:
+ case T_NSAP:
+ case T_LOC:
+ /* XXX - more fine tuning needed here */
+ ShrinkBuffer(rrecp->r_size);
+ memcpy(cp, rrecp->r_data, rrecp->r_size);
+ cp += rrecp->r_size;
+ 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 whitespace delimited 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)))
+ return (NULL);
+ rrecp->r_class = class;
+ rrecp->r_type = type;
+ rrecp->r_ttl = ttl;
+ rrecp->r_section = 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);
+}
diff --git a/lib/libc/net/res_update.c b/lib/libc/net/res_update.c
new file mode 100644
index 0000000..46f1efa
--- /dev/null
+++ b/lib/libc/net/res_update.c
@@ -0,0 +1,522 @@
+/*
+ * 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.
+ */
+
+/*
+ * Based on the Dynamic DNS reference implementation by Viraj Bais
+ * <viraj_bais@ccm.fm.intel.com>
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#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 <limits.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <res_update.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.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.
+ */
+
+#define NSMAX 16
+
+struct ns1 {
+ char nsname[MAXDNAME];
+ struct in_addr nsaddr1;
+};
+
+struct zonegrp {
+ char z_origin[MAXDNAME];
+ int16_t z_class;
+ char z_soardata[MAXDNAME + 5 * INT32SZ];
+ struct ns1 z_ns[NSMAX];
+ int z_nscount;
+ ns_updrec * z_rr;
+ struct zonegrp *z_next;
+};
+
+
+int
+res_nupdate(res_state statp, ns_updrec *rrecp_in, ns_tsig_key *key) {
+ ns_updrec *rrecp, *tmprrecp;
+ u_char buf[PACKETSZ], answer[PACKETSZ], packet[2*PACKETSZ];
+ char name[MAXDNAME], zname[MAXDNAME], primary[MAXDNAME],
+ mailaddr[MAXDNAME];
+ u_char soardata[2*MAXCDNAME+5*INT32SZ];
+ char *dname, *svdname, *cp1, *target;
+ u_char *cp, *eom;
+ HEADER *hp = (HEADER *) answer;
+ struct zonegrp *zptr = NULL, *tmpzptr, *prevzptr, *zgrp_start = NULL;
+ int i, j, k = 0, n, ancount, nscount, arcount, rcode, rdatasize,
+ newgroup, done, myzone, seen_before, numzones = 0;
+ u_int16_t dlen, class, qclass, type, qtype;
+ u_int32_t ttl;
+
+ if (key != NULL) {
+ /* TSIG is not supported. */
+ RES_SET_H_ERRNO(statp, NO_RECOVERY);
+ return (-1);
+ }
+
+ for (rrecp = rrecp_in; rrecp; rrecp = rrecp->r_next) {
+ dname = rrecp->r_dname;
+ n = strlen(dname);
+ if (dname[n-1] == '.')
+ dname[n-1] = '\0';
+ qtype = T_SOA;
+ qclass = rrecp->r_class;
+ done = 0;
+ seen_before = 0;
+
+ while (!done && dname) {
+ if (qtype == T_SOA) {
+ for (tmpzptr = zgrp_start;
+ tmpzptr && !seen_before;
+ tmpzptr = tmpzptr->z_next) {
+ if (strcasecmp(dname,
+ tmpzptr->z_origin) == 0 &&
+ tmpzptr->z_class == qclass)
+ seen_before++;
+ for (tmprrecp = tmpzptr->z_rr;
+ tmprrecp && !seen_before;
+ tmprrecp = tmprrecp->r_grpnext)
+ if (strcasecmp(dname, tmprrecp->r_dname) == 0
+ && tmprrecp->r_class == qclass) {
+ seen_before++;
+ break;
+ }
+ if (seen_before) {
+ /*
+ * Append to the end of
+ * current group.
+ */
+ for (tmprrecp = tmpzptr->z_rr;
+ tmprrecp->r_grpnext;
+ tmprrecp = tmprrecp->r_grpnext)
+ (void)NULL;
+ tmprrecp->r_grpnext = rrecp;
+ rrecp->r_grpnext = NULL;
+ done = 1;
+ break;
+ }
+ }
+ } else if (qtype == T_A) {
+ for (tmpzptr = zgrp_start;
+ tmpzptr && !done;
+ tmpzptr = tmpzptr->z_next)
+ for (i = 0; i < tmpzptr->z_nscount; i++)
+ if (tmpzptr->z_class == qclass &&
+ strcasecmp(tmpzptr->z_ns[i].nsname,
+ dname) == 0 &&
+ tmpzptr->z_ns[i].nsaddr1.s_addr != 0) {
+ zptr->z_ns[k].nsaddr1.s_addr =
+ tmpzptr->z_ns[i].nsaddr1.s_addr;
+ done = 1;
+ break;
+ }
+ }
+ if (done)
+ break;
+ n = res_nmkquery(statp, QUERY, dname, qclass, qtype, NULL,
+ 0, NULL, buf, sizeof buf);
+ if (n <= 0) {
+ fprintf(stderr, "res_nupdate: mkquery failed\n");
+ return (n);
+ }
+ n = res_nsend(statp, buf, n, answer, sizeof answer);
+ if (n < 0) {
+ fprintf(stderr, "res_nupdate: send error for %s\n",
+ rrecp->r_dname);
+ return (n);
+ } else if (n > sizeof(answer)) {
+ fprintf(stderr, "res_nupdate: buffer too small\n");
+ return (-1);
+ }
+ if (n < HFIXEDSZ)
+ return (-1);
+ ancount = ntohs(hp->ancount);
+ nscount = ntohs(hp->nscount);
+ arcount = ntohs(hp->arcount);
+ rcode = hp->rcode;
+ cp = answer + HFIXEDSZ;
+ eom = answer + n;
+ /* skip the question section */
+ n = dn_skipname(cp, eom);
+ if (n < 0 || cp + n + 2 * INT16SZ > eom)
+ return (-1);
+ cp += n + 2 * INT16SZ;
+
+ if (qtype == T_SOA) {
+ if (ancount == 0 && nscount == 0 && arcount == 0) {
+ /*
+ * if (rcode == NOERROR) then the dname exists but
+ * has no soa record associated with it.
+ * if (rcode == NXDOMAIN) then the dname does not
+ * exist and the server is replying out of NCACHE.
+ * in either case, proceed with the next try
+ */
+ dname = strchr(dname, '.');
+ if (dname != NULL)
+ dname++;
+ continue;
+ } else if ((rcode == NOERROR || rcode == NXDOMAIN) &&
+ ancount == 0 &&
+ nscount == 1 && arcount == 0) {
+ /*
+ * name/data does not exist, soa record supplied in the
+ * authority section
+ */
+ /* authority section must contain the soa record */
+ if ((n = dn_expand(answer, eom, cp, zname,
+ sizeof zname)) < 0)
+ return (n);
+ cp += n;
+ if (cp + 2 * INT16SZ > eom)
+ return (-1);
+ GETSHORT(type, cp);
+ GETSHORT(class, cp);
+ if (type != T_SOA || class != qclass) {
+ fprintf(stderr, "unknown answer\n");
+ return (-1);
+ }
+ myzone = 0;
+ svdname = dname;
+ while (dname)
+ if (strcasecmp(dname, zname) == 0) {
+ myzone = 1;
+ break;
+ } else if ((dname = strchr(dname, '.')) != NULL)
+ dname++;
+ if (!myzone) {
+ dname = strchr(svdname, '.');
+ if (dname != NULL)
+ dname++;
+ continue;
+ }
+ nscount = 0;
+ /* fallthrough */
+ } else if (rcode == NOERROR && ancount == 1) {
+ /*
+ * found the zone name
+ * new servers will supply NS records for the zone
+ * in authority section and A records for those
+ * nameservers in the additional section
+ * older servers have to be explicitly queried for
+ * NS records for the zone
+ */
+ /* answer section must contain the soa record */
+ if ((n = dn_expand(answer, eom, cp, zname,
+ sizeof zname)) < 0)
+ return (n);
+ else
+ cp += n;
+ if (cp + 2 * INT16SZ > eom)
+ return (-1);
+ GETSHORT(type, cp);
+ GETSHORT(class, cp);
+ if (type == T_CNAME) {
+ dname = strchr(dname, '.');
+ if (dname != NULL)
+ dname++;
+ continue;
+ }
+ if (strcasecmp(dname, zname) != 0 ||
+ type != T_SOA ||
+ class != rrecp->r_class) {
+ fprintf(stderr, "unknown answer\n");
+ return (-1);
+ }
+ /* FALLTHROUGH */
+ } else {
+ fprintf(stderr,
+ "unknown response: ans=%d, auth=%d, add=%d, rcode=%d\n",
+ ancount, nscount, arcount, hp->rcode);
+ return (-1);
+ }
+ if (cp + INT32SZ + INT16SZ > eom)
+ return (-1);
+ /* continue processing the soa record */
+ GETLONG(ttl, cp);
+ GETSHORT(dlen, cp);
+ if (cp + dlen > eom)
+ return (-1);
+ newgroup = 1;
+ zptr = zgrp_start;
+ prevzptr = NULL;
+ while (zptr) {
+ if (strcasecmp(zname, zptr->z_origin) == 0 &&
+ type == T_SOA && class == qclass) {
+ newgroup = 0;
+ break;
+ }
+ prevzptr = zptr;
+ zptr = zptr->z_next;
+ }
+ if (!newgroup) {
+ for (tmprrecp = zptr->z_rr;
+ tmprrecp->r_grpnext;
+ tmprrecp = tmprrecp->r_grpnext)
+ ;
+ tmprrecp->r_grpnext = rrecp;
+ rrecp->r_grpnext = NULL;
+ done = 1;
+ cp += dlen;
+ break;
+ } else {
+ if ((n = dn_expand(answer, eom, cp, primary,
+ sizeof primary)) < 0)
+ return (n);
+ cp += n;
+ /*
+ * We don't have to bounds check here because the
+ * next use of 'cp' is in dn_expand().
+ */
+ cp1 = (char *)soardata;
+ strcpy(cp1, primary);
+ cp1 += strlen(cp1) + 1;
+ if ((n = dn_expand(answer, eom, cp, mailaddr,
+ sizeof mailaddr)) < 0)
+ return (n);
+ cp += n;
+ strcpy(cp1, mailaddr);
+ cp1 += strlen(cp1) + 1;
+ if (cp + 5*INT32SZ > eom)
+ return (-1);
+ memcpy(cp1, cp, 5*INT32SZ);
+ cp += 5*INT32SZ;
+ cp1 += 5*INT32SZ;
+ rdatasize = (u_char *)cp1 - soardata;
+ zptr = calloc(1, sizeof(struct zonegrp));
+ if (zptr == NULL)
+ return (-1);
+ if (zgrp_start == NULL)
+ zgrp_start = zptr;
+ else
+ prevzptr->z_next = zptr;
+ zptr->z_rr = rrecp;
+ rrecp->r_grpnext = NULL;
+ strcpy(zptr->z_origin, zname);
+ zptr->z_class = class;
+ memcpy(zptr->z_soardata, soardata, rdatasize);
+ /* fallthrough to process NS and A records */
+ }
+ } else if (qtype == T_NS) {
+ if (rcode == NOERROR && ancount > 0) {
+ strcpy(zname, dname);
+ for (zptr = zgrp_start; zptr; zptr = zptr->z_next) {
+ if (strcasecmp(zname, zptr->z_origin) == 0)
+ break;
+ }
+ if (zptr == NULL)
+ /* should not happen */
+ return (-1);
+ if (nscount > 0) {
+ /*
+ * answer and authority sections contain
+ * the same information, skip answer section
+ */
+ for (j = 0; j < ancount; j++) {
+ n = dn_skipname(cp, eom);
+ if (n < 0)
+ return (-1);
+ n += 2*INT16SZ + INT32SZ;
+ if (cp + n + INT16SZ > eom)
+ return (-1);
+ cp += n;
+ GETSHORT(dlen, cp);
+ cp += dlen;
+ }
+ } else
+ nscount = ancount;
+ /* fallthrough to process NS and A records */
+ } else {
+ fprintf(stderr, "cannot determine nameservers for %s:\
+ans=%d, auth=%d, add=%d, rcode=%d\n",
+ dname, ancount, nscount, arcount, hp->rcode);
+ return (-1);
+ }
+ } else if (qtype == T_A) {
+ if (rcode == NOERROR && ancount > 0) {
+ arcount = ancount;
+ ancount = nscount = 0;
+ /* fallthrough to process A records */
+ } else {
+ fprintf(stderr, "cannot determine address for %s:\
+ans=%d, auth=%d, add=%d, rcode=%d\n",
+ dname, ancount, nscount, arcount, hp->rcode);
+ return (-1);
+ }
+ }
+ /* process NS records for the zone */
+ j = 0;
+ for (i = 0; i < nscount; i++) {
+ if ((n = dn_expand(answer, eom, cp, name,
+ sizeof name)) < 0)
+ return (n);
+ cp += n;
+ if (cp + 3 * INT16SZ + INT32SZ > eom)
+ return (-1);
+ GETSHORT(type, cp);
+ GETSHORT(class, cp);
+ GETLONG(ttl, cp);
+ GETSHORT(dlen, cp);
+ if (cp + dlen > eom)
+ return (-1);
+ if (strcasecmp(name, zname) == 0 &&
+ type == T_NS && class == qclass) {
+ if ((n = dn_expand(answer, eom, cp,
+ name, sizeof name)) < 0)
+ return (n);
+ target = zptr->z_ns[j++].nsname;
+ strcpy(target, name);
+ }
+ cp += dlen;
+ }
+ if (zptr->z_nscount == 0)
+ zptr->z_nscount = j;
+ /* get addresses for the nameservers */
+ for (i = 0; i < arcount; i++) {
+ if ((n = dn_expand(answer, eom, cp, name,
+ sizeof name)) < 0)
+ return (n);
+ cp += n;
+ if (cp + 3 * INT16SZ + INT32SZ > eom)
+ return (-1);
+ GETSHORT(type, cp);
+ GETSHORT(class, cp);
+ GETLONG(ttl, cp);
+ GETSHORT(dlen, cp);
+ if (cp + dlen > eom)
+ return (-1);
+ if (type == T_A && dlen == INT32SZ && class == qclass) {
+ for (j = 0; j < zptr->z_nscount; j++)
+ if (strcasecmp(name, zptr->z_ns[j].nsname) == 0) {
+ memcpy(&zptr->z_ns[j].nsaddr1.s_addr, cp,
+ INT32SZ);
+ break;
+ }
+ }
+ cp += dlen;
+ }
+ if (zptr->z_nscount == 0) {
+ dname = zname;
+ qtype = T_NS;
+ continue;
+ }
+ done = 1;
+ for (k = 0; k < zptr->z_nscount; k++)
+ if (zptr->z_ns[k].nsaddr1.s_addr == 0) {
+ done = 0;
+ dname = zptr->z_ns[k].nsname;
+ qtype = T_A;
+ }
+
+ } /* while */
+ }
+
+ statp->options |= RES_DEBUG;
+ for (zptr = zgrp_start; zptr; zptr = zptr->z_next) {
+
+ /* append zone section */
+ rrecp = res_mkupdrec(ns_s_zn, zptr->z_origin,
+ zptr->z_class, ns_t_soa, 0);
+ if (rrecp == NULL) {
+ fprintf(stderr, "saverrec error\n");
+ fflush(stderr);
+ return (-1);
+ }
+ rrecp->r_grpnext = zptr->z_rr;
+ zptr->z_rr = rrecp;
+
+ n = res_nmkupdate(statp, zptr->z_rr, packet, sizeof packet);
+ if (n < 0) {
+ fprintf(stderr, "res_nmkupdate error\n");
+ fflush(stderr);
+ return (-1);
+ } else
+ fprintf(stdout, "res_nmkupdate: packet size = %d\n", n);
+
+ /*
+ * Override the list of NS records from res_ninit() with
+ * the authoritative nameservers for the zone being updated.
+ * Sort primary to be the first in the list of nameservers.
+ */
+ for (i = 0; i < zptr->z_nscount; i++) {
+ if (strcasecmp(zptr->z_ns[i].nsname,
+ zptr->z_soardata) == 0) {
+ struct in_addr tmpaddr;
+
+ if (i != 0) {
+ strcpy(zptr->z_ns[i].nsname,
+ zptr->z_ns[0].nsname);
+ strcpy(zptr->z_ns[0].nsname,
+ zptr->z_soardata);
+ tmpaddr = zptr->z_ns[i].nsaddr1;
+ zptr->z_ns[i].nsaddr1 =
+ zptr->z_ns[0].nsaddr1;
+ zptr->z_ns[0].nsaddr1 = tmpaddr;
+ }
+ break;
+ }
+ }
+ for (i = 0; i < MAXNS; i++) {
+ statp->nsaddr_list[i].sin_addr = zptr->z_ns[i].nsaddr1;
+ statp->nsaddr_list[i].sin_family = AF_INET;
+ statp->nsaddr_list[i].sin_port = htons(NAMESERVER_PORT);
+ }
+ statp->nscount = (zptr->z_nscount < MAXNS) ?
+ zptr->z_nscount : MAXNS;
+ n = res_nsend(statp, packet, n, answer, sizeof(answer));
+ if (n < 0) {
+ fprintf(stderr, "res_nsend: send error, n=%d\n", n);
+ break;
+ } else if (n > sizeof(answer)) {
+ fprintf(stderr, "res_nsend: buffer too small\n");
+ break;
+ }
+ numzones++;
+ }
+
+ /* free malloc'ed memory */
+ while(zgrp_start) {
+ zptr = zgrp_start;
+ zgrp_start = zgrp_start->z_next;
+ res_freeupdrec(zptr->z_rr); /* Zone section we allocated. */
+ free((char *)zptr);
+ }
+
+ return (numzones);
+}
diff --git a/lib/libc/net/resolver.3 b/lib/libc/net/resolver.3
new file mode 100644
index 0000000..16f7006
--- /dev/null
+++ b/lib/libc/net/resolver.3
@@ -0,0 +1,438 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)resolver.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.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
+.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.
+.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.
+.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 0000000..5fbb4bb
--- /dev/null
+++ b/lib/libc/net/rthdr.c
@@ -0,0 +1,442 @@
+/* $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/types.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(type, seg)
+ int type, 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(bp, type)
+ 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(cmsg, addr, flags)
+ 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(cmsg, flags)
+ 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(in, out)
+ const struct cmsghdr *in;
+ struct cmsghdr *out;
+{
+
+ return (-1);
+}
+#endif
+
+int
+inet6_rthdr_segments(cmsg)
+ 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(cmsg, idx)
+ 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(cmsg, idx)
+ 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:
+ return (((segments * 2) + 1) << 3);
+ 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);
+
+ 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;
+ 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/send.c b/lib/libc/net/send.c
new file mode 100644
index 0000000..f10d21b
--- /dev/null
+++ b/lib/libc/net/send.c
@@ -0,0 +1,54 @@
+/*
+ * 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. 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.
+ */
+
+#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 "namespace.h"
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <stddef.h>
+#include "un-namespace.h"
+
+ssize_t
+send(s, msg, len, flags)
+ int s, flags;
+ size_t len;
+ const void *msg;
+{
+ return (_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 0000000..61a1a9f
--- /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 0000000..e416de8
--- /dev/null
+++ b/lib/libc/net/sockatmark.c
@@ -0,0 +1,36 @@
+/*
+ * 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 <sys/ioctl.h>
+
+int sockatmark(int s)
+{
+ int atmark;
+
+ if (ioctl(s, SIOCATMARK, &atmark) == -1)
+ return -1;
+ return atmark;
+}
diff --git a/lib/libc/net/vars.c b/lib/libc/net/vars.c
new file mode 100644
index 0000000..42ee205
--- /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 0000000..aa2c4cc
--- /dev/null
+++ b/lib/libc/nls/C.msg
@@ -0,0 +1,249 @@
+$ $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
+$
+$ 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
diff --git a/lib/libc/nls/Makefile.inc b/lib/libc/nls/Makefile.inc
new file mode 100644
index 0000000..90a6741
--- /dev/null
+++ b/lib/libc/nls/Makefile.inc
@@ -0,0 +1,10 @@
+# from $NetBSD: Makefile.inc,v 1.7 1995/02/27 13:06:20 cgd Exp $
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/nls
+
+SRCS+= msgcat.c
+
+SYM_MAPS+=${.CURDIR}/nls/Symbol.map
+
+MAN+= catclose.3 catgets.3 catopen.3
diff --git a/lib/libc/nls/Symbol.map b/lib/libc/nls/Symbol.map
new file mode 100644
index 0000000..3c10a62
--- /dev/null
+++ b/lib/libc/nls/Symbol.map
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+FBSD_1.0 {
+ catopen;
+ catgets;
+ catclose;
+};
diff --git a/lib/libc/nls/catclose.3 b/lib/libc/nls/catclose.3
new file mode 100644
index 0000000..ed0f639
--- /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 0000000..38e92ba
--- /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 0000000..7a16ee5
--- /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
+.No ( 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/ko_KR.UTF-8.msg b/lib/libc/nls/ko_KR.UTF-8.msg
new file mode 100644
index 0000000..4fc4e78
--- /dev/null
+++ b/lib/libc/nls/ko_KR.UTF-8.msg
@@ -0,0 +1,249 @@
+$ $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 í”„ë¡œê·¸ëž¨ìƒ ì˜¤ë¥˜ìž…ë‹ˆë‹¤
+$
+$ 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 possible
+$ 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/ko_KR.eucKR.msg b/lib/libc/nls/ko_KR.eucKR.msg
new file mode 100644
index 0000000..c2ca1a0
--- /dev/null
+++ b/lib/libc/nls/ko_KR.eucKR.msg
@@ -0,0 +1,249 @@
+$ $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 ÇÁ·Î±×·¥»ó ¿À·ùÀÔ´Ï´Ù
+$
+$ 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 possible
+$ 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 0000000..8689b7e
--- /dev/null
+++ b/lib/libc/nls/msgcat.c
@@ -0,0 +1,307 @@
+/***********************************************************
+Copyright 1990, by Alfalfa Software Incorporated, Cambridge, Massachusetts.
+
+ 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 <arpa/inet.h> /* for ntohl() */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <locale.h>
+#include <nl_types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+#include "../locale/setlocale.h" /* for ENCODING_LEN */
+
+#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 NLERR ((nl_catd) -1)
+#define NLRETERR(errc) { errno = errc; return (NLERR); }
+
+static nl_catd load_msgcat(const char *);
+
+nl_catd
+catopen(const char *name, int type)
+{
+ int spcleft, saverr;
+ char path[PATH_MAX];
+ char *nlspath, *lang, *base, *cptr, *pathP, *tmpptr;
+ char *cptr1, *plang, *pter, *pcode;
+ struct stat sbuf;
+
+ if (name == NULL || *name == '\0')
+ NLRETERR(EINVAL);
+
+ /* is it absolute path ? if yes, load immediately */
+ if (strchr(name, '/') != NULL)
+ return (load_msgcat(name));
+
+ if (type == NL_CAT_LOCALE)
+ lang = setlocale(LC_MESSAGES, NULL);
+ 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";
+
+ 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);
+ 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));
+ }
+ } else {
+ tmpptr = (char *)name;
+ --nlspath;
+ goto put_tmpptr;
+ }
+ }
+ free(plang);
+ free(base);
+ NLRETERR(ENOENT);
+}
+
+char *
+catgets(nl_catd catd, int set_id, int msg_id, const char *s)
+{
+ struct _nls_cat_hdr *cat_hdr;
+ struct _nls_set_hdr *set_hdr;
+ struct _nls_msg_hdr *msg_hdr;
+ int l, u, i, r;
+
+ 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;
+}
+
+int
+catclose(nl_catd catd)
+{
+ if (catd == NULL || catd == NLERR) {
+ errno = EBADF;
+ return (-1);
+ }
+
+ munmap(catd->__data, (size_t)catd->__size);
+ free(catd);
+ return (0);
+}
+
+/*
+ * Internal support functions
+ */
+
+static nl_catd
+load_msgcat(const char *path)
+{
+ struct stat st;
+ nl_catd catd;
+ void *data;
+ int fd;
+
+ /* XXX: path != NULL? */
+
+ if ((fd = _open(path, O_RDONLY)) == -1)
+ return (NLERR);
+
+ if (_fstat(fd, &st) != 0) {
+ _close(fd);
+ return (NLERR);
+ }
+
+ data = mmap(0, (size_t)st.st_size, PROT_READ, MAP_FILE|MAP_SHARED, fd,
+ (off_t)0);
+ _close(fd);
+
+ if (data == MAP_FAILED)
+ return (NLERR);
+
+ if (ntohl((u_int32_t)((struct _nls_cat_hdr *)data)->__magic) !=
+ _NLS_MAGIC) {
+ munmap(data, (size_t)st.st_size);
+ NLRETERR(EINVAL);
+ }
+
+ if ((catd = malloc(sizeof (*catd))) == NULL) {
+ munmap(data, (size_t)st.st_size);
+ return (NLERR);
+ }
+
+ catd->__data = data;
+ catd->__size = (int)st.st_size;
+ return (catd);
+}
+
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 0000000..1c184b3
--- /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/ru_RU.KOI8-R.msg b/lib/libc/nls/ru_RU.KOI8-R.msg
new file mode 100644
index 0000000..55233b9
--- /dev/null
+++ b/lib/libc/nls/ru_RU.KOI8-R.msg
@@ -0,0 +1,256 @@
+$ $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 ïÛÉÂËÁ ÐÒÏÇÒÁÍÉÒÏ×ÁÎÉÑ
+$
+$ 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/posix1e/Makefile.inc b/lib/libc/posix1e/Makefile.inc
new file mode 100644
index 0000000..91422d4
--- /dev/null
+++ b/lib/libc/posix1e/Makefile.inc
@@ -0,0 +1,89 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/posix1e
+
+SRCS+= acl_calc_mask.c \
+ acl_copy.c \
+ acl_delete.c \
+ acl_delete_entry.c \
+ acl_entry.c \
+ acl_free.c \
+ acl_from_text.c \
+ acl_get.c \
+ acl_init.c \
+ acl_perm.c \
+ acl_set.c \
+ acl_support.c \
+ acl_to_text.c \
+ acl_valid.c \
+ extattr.c \
+ mac.c \
+ mac_exec.c \
+ mac_get.c \
+ mac_set.c
+
+SYM_MAPS+=${.CURDIR}/posix1e/Symbol.map
+
+MAN+= acl.3 \
+ acl_add_perm.3 \
+ acl_calc_mask.3 \
+ acl_clear_perms.3 \
+ acl_copy_entry.3 \
+ acl_create_entry.3 \
+ acl_delete.3 \
+ acl_delete_entry.3 \
+ acl_delete_perm.3 \
+ acl_dup.3 \
+ acl_free.3 \
+ acl_from_text.3 \
+ acl_get.3 \
+ acl_get_entry.3 \
+ acl_get_permset.3 \
+ acl_get_perm_np.3 \
+ acl_get_qualifier.3 \
+ acl_get_tag_type.3 \
+ acl_init.3 \
+ acl_set.3 \
+ acl_set_permset.3 \
+ acl_set_qualifier.3 \
+ acl_set_tag_type.3 \
+ acl_to_text.3 \
+ acl_valid.3 \
+ extattr.3 \
+ mac.3 \
+ mac.conf.5 \
+ mac_free.3 \
+ mac_is_present_np.3 \
+ mac_get.3 \
+ mac_prepare.3 \
+ mac_set.3 \
+ mac_text.3 \
+ posix1e.3
+
+MLINKS+=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_get.3 acl_get_file.3 \
+ acl_get.3 acl_get_fd.3 \
+ acl_get.3 acl_get_fd_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_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_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_set.3 mac_set_link.3 \
+ mac_set.3 mac_set_fd.3 \
+ mac_set.3 mac_set_file.3 \
+ mac_set.3 mac_set_proc.3 \
+ mac_text.3 mac_from_text.3 \
+ mac_text.3 mac_to_text.3
diff --git a/lib/libc/posix1e/Symbol.map b/lib/libc/posix1e/Symbol.map
new file mode 100644
index 0000000..228d668
--- /dev/null
+++ b/lib/libc/posix1e/Symbol.map
@@ -0,0 +1,68 @@
+# $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_perm_np;
+ acl_get_permset;
+ acl_get_qualifier;
+ acl_get_tag_type;
+ acl_init;
+ acl_dup;
+ acl_add_perm;
+ acl_clear_perms;
+ acl_delete_perm;
+ 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_size;
+ 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;
+};
diff --git a/lib/libc/posix1e/acl.3 b/lib/libc/posix1e/acl.3
new file mode 100644
index 0000000..1c824d0
--- /dev/null
+++ b/lib/libc/posix1e/acl.3
@@ -0,0 +1,244 @@
+.\"-
+.\" 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 December 18, 2002
+.Dt ACL 3
+.Os
+.Sh NAME
+.Nm acl
+.Nd introduction to the POSIX.1e 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.
+Not all file systems provide support for ACLs, and some may require that
+ACL support be explicitly enabled by the administrator.
+The library calls include routines to allocate, duplicate, retrieve, set,
+and validate ACLs associated with file objects.
+As well as the POSIX.1e routines, there are a number of non-portable
+extensions defined that allow for alternative ACL semantics than the
+POSIX.1e semantics, such as AFS, NTFS, Coda, and NWFS semantics.
+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_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_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 Fn acl_create_entry
+This function is 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 Fn acl_delete_entry
+This function is described in
+.Xr acl_delete_entry 3 ,
+and may be used to delete an entry from an ACL.
+.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 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_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 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_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_to_text
+This function is described in
+.Xr acl_to_text 3 ,
+and may be used to generate a text-form of a POSIX.1e 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_perm 3 ,
+.Xr acl_calc_mask 3 ,
+.Xr acl_clear_perms 3 ,
+.Xr acl_copy_entry 3 ,
+.Xr acl_create_entry 3 ,
+.Xr acl_delete_entry 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_permset 3 ,
+.Xr acl_get_qualifier 3 ,
+.Xr acl_get_tag_type 3 ,
+.Xr acl_init 3 ,
+.Xr acl_set 3 ,
+.Xr acl_set_permset 3 ,
+.Xr acl_set_qualifier 3 ,
+.Xr acl_set_tag_type 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.
+.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_perm.3 b/lib/libc/posix1e/acl_add_perm.3
new file mode 100644
index 0000000..43d04f1
--- /dev/null
+++ b/lib/libc/posix1e/acl_add_perm.3
@@ -0,0 +1,89 @@
+.\"-
+.\" 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 THE VOICES IN HIS HEAD BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 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_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.
+.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.
+.El
+.Sh SEE ALSO
+.Xr acl 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_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 jedgar@fxp.org .
diff --git a/lib/libc/posix1e/acl_calc_mask.3 b/lib/libc/posix1e/acl_calc_mask.3
new file mode 100644
index 0000000..48d2678
--- /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 THE AUTHOR OR THE VOICES IN HIS HEAD BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 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 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 0000000..7e2f955
--- /dev/null
+++ b/lib/libc/posix1e/acl_calc_mask.c
@@ -0,0 +1,119 @@
+/*
+ * 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 THE VOICES IN HIS HEAD BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY 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>
+
+/*
+ * 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);
+ }
+ 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;
+ 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_perms.3 b/lib/libc/posix1e/acl_clear_perms.3
new file mode 100644
index 0000000..db026a3
--- /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 THE AUTHOR OR THE VOICES IN HIS HEAD BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 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 jedgar@fxp.org .
diff --git a/lib/libc/posix1e/acl_copy.c b/lib/libc/posix1e/acl_copy.c
new file mode 100644
index 0000000..6d1e0a8
--- /dev/null
+++ b/lib/libc/posix1e/acl_copy.c
@@ -0,0 +1,72 @@
+/*
+ * 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 THE VOICES IN HIS HEAD BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY 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>
+
+/*
+ * 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);
+ }
+
+ dest_d->ae_tag = src_d->ae_tag;
+ dest_d->ae_id = src_d->ae_id;
+ dest_d->ae_perm = src_d->ae_perm;
+
+ 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 0000000..fead89f
--- /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 THE AUTHOR OR THE VOICES IN HIS HEAD BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 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 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 0000000..fb856ad
--- /dev/null
+++ b/lib/libc/posix1e/acl_create_entry.3
@@ -0,0 +1,82 @@
+.\"-
+.\" 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 THE VOICES IN HIS HEAD BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 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 16, 2001
+.Dt ACL_CREATE_ENTRY 3
+.Os
+.Sh NAME
+.Nm acl_create_entry
+.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"
+.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 .
+.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.
+.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 jedgar@fxp.org .
diff --git a/lib/libc/posix1e/acl_delete.3 b/lib/libc/posix1e/acl_delete.3
new file mode 100644
index 0000000..fb2958b
--- /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 0000000..a93cd7b
--- /dev/null
+++ b/lib/libc/posix1e/acl_delete.c
@@ -0,0 +1,75 @@
+/*-
+ * 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>
+
+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)
+{
+
+ return (__acl_delete_file(path_p, type));
+}
+
+int
+acl_delete_link_np(const char *path_p, acl_type_t type)
+{
+
+ return (__acl_delete_link(path_p, type));
+}
+
+
+int
+acl_delete_fd_np(int filedes, acl_type_t 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 0000000..a931db0
--- /dev/null
+++ b/lib/libc/posix1e/acl_delete_entry.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 THE AUTHOR OR THE VOICES IN HIS HEAD BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 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_ENTRY 3
+.Os
+.Sh NAME
+.Nm acl_delete_entry
+.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"
+.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 .
+.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 .
+.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 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 0000000..3195fac
--- /dev/null
+++ b/lib/libc/posix1e/acl_delete_entry.c
@@ -0,0 +1,79 @@
+/*
+ * 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>
+
+/*
+ * 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;
+ int i;
+
+ if (acl == NULL || entry_d == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ acl_int = &acl->ats_acl;
+
+ if ((acl->ats_acl.acl_cnt < 1) ||
+ (acl->ats_acl.acl_cnt > ACL_MAX_ENTRIES)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ for (i = 0; i < acl->ats_acl.acl_cnt; i++) {
+ /* if this is our entry... */
+ if ((acl->ats_acl.acl_entry[i].ae_tag == entry_d->ae_tag) &&
+ (acl->ats_acl.acl_entry[i].ae_id == entry_d->ae_id)) {
+ /* ...shift the remaining entries... */
+ for (; 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);
+ }
+ }
+
+
+ errno = EINVAL;
+ return (-1);
+}
diff --git a/lib/libc/posix1e/acl_delete_perm.3 b/lib/libc/posix1e/acl_delete_perm.3
new file mode 100644
index 0000000..0740d61
--- /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 THE AUTHOR OR THE VOICES IN HIS HEAD BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 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 jedgar@fxp.org .
diff --git a/lib/libc/posix1e/acl_dup.3 b/lib/libc/posix1e/acl_dup.3
new file mode 100644
index 0000000..ae4ff4f
--- /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 0000000..f5bdbed
--- /dev/null
+++ b/lib/libc/posix1e/acl_entry.c
@@ -0,0 +1,98 @@
+/*
+ * 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;
+
+ if ((acl_int->acl_cnt >= ACL_MAX_ENTRIES) || (acl_int->acl_cnt < 0)) {
+ 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;
+
+ (*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_free.3 b/lib/libc/posix1e/acl_free.3
new file mode 100644
index 0000000..d64c72a
--- /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 0000000..6de41da
--- /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 0000000..8b10784
--- /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 0000000..59d9142
--- /dev/null
+++ b/lib/libc/posix1e/acl_from_text.c
@@ -0,0 +1,238 @@
+/*-
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "acl_support.h"
+
+static acl_tag_t acl_string_to_tag(char *tag, char *qualifier);
+static char *string_skip_whitespace(char *string);
+static void string_trim_trailing_whitespace(char *string);
+
+static char *
+string_skip_whitespace(char *string)
+{
+
+ while (*string && ((*string == ' ') || (*string == '\t'))) {
+ string++;
+ }
+ return (string);
+}
+
+static 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;
+}
+
+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);
+ }
+}
+
+/*
+ * 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_tag_t t;
+ acl_perm_t p;
+ acl_t acl;
+ char *mybuf_p, *line, *cur, *notcomment, *comment, *entry;
+ char *tag, *qualifier, *permission;
+ int error;
+ uid_t id;
+
+ /* Local copy we can mess up. */
+ mybuf_p = strdup(buf_p);
+ if (mybuf_p == NULL)
+ return(NULL);
+
+ acl = acl_init(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, ","))) {
+ /* Now split into three ':' delimited fields. */
+ tag = strsep(&entry, ":");
+ if (tag == NULL) {
+ errno = EINVAL;
+ goto error_label;
+ }
+ tag = string_skip_whitespace(tag);
+ if ((*tag == '\0') && (!entry)) {
+ /*
+ * Is an entirely comment line, skip to next
+ * comma.
+ */
+ continue;
+ }
+ string_trim_trailing_whitespace(tag);
+
+ qualifier = strsep(&entry, ":");
+ if (qualifier == NULL) {
+ errno = EINVAL;
+ goto error_label;
+ }
+ qualifier = string_skip_whitespace(qualifier);
+ string_trim_trailing_whitespace(qualifier);
+
+ permission = strsep(&entry, ":");
+ if (permission == NULL || entry) {
+ errno = EINVAL;
+ goto error_label;
+ }
+ permission = string_skip_whitespace(permission);
+ string_trim_trailing_whitespace(permission);
+
+ t = acl_string_to_tag(tag, qualifier);
+ if (t == -1) {
+ errno = EINVAL;
+ goto error_label;
+ }
+
+ error = _posix1e_acl_string_to_perm(permission, &p);
+ if (error == -1) {
+ errno = EINVAL;
+ goto error_label;
+ }
+
+ switch(t) {
+ case ACL_USER_OBJ:
+ case ACL_GROUP_OBJ:
+ case ACL_MASK:
+ case ACL_OTHER:
+ if (*qualifier != '\0') {
+ errno = EINVAL;
+ goto error_label;
+ }
+ id = 0;
+ break;
+
+ case ACL_USER:
+ case ACL_GROUP:
+ error = _posix1e_acl_name_to_id(t, qualifier,
+ &id);
+ if (error == -1)
+ goto error_label;
+ break;
+
+ default:
+ errno = EINVAL;
+ goto error_label;
+ }
+
+ error = _posix1e_acl_add_entry(acl, t, id, p);
+ if (error == -1)
+ 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
+
+ return(acl);
+
+error_label:
+ acl_free(acl);
+ free(mybuf_p);
+ return(NULL);
+}
+
+
+
diff --git a/lib/libc/posix1e/acl_get.3 b/lib/libc/posix1e/acl_get.3
new file mode 100644
index 0000000..fa915df
--- /dev/null
+++ b/lib/libc/posix1e/acl_get.3
@@ -0,0 +1,156 @@
+.\"-
+.\" 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_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.
+.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_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 0000000..1f97baa
--- /dev/null
+++ b/lib/libc/posix1e/acl_get.c
@@ -0,0 +1,215 @@
+/*-
+ * 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 <stdlib.h>
+#include <string.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);
+
+ error = __acl_get_file(path_p, type, &aclp->ats_acl);
+ if (error) {
+ acl_free(aclp);
+ return (NULL);
+ }
+
+ 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);
+
+ error = __acl_get_link(path_p, type, &aclp->ats_acl);
+ if (error) {
+ acl_free(aclp);
+ return (NULL);
+ }
+
+ return (aclp);
+}
+
+acl_t
+acl_get_fd(int fd)
+{
+ acl_t aclp;
+ int error;
+
+ aclp = acl_init(ACL_MAX_ENTRIES);
+ if (aclp == NULL)
+ return (NULL);
+
+ error = ___acl_get_fd(fd, ACL_TYPE_ACCESS, &aclp->ats_acl);
+ if (error) {
+ acl_free(aclp);
+ return (NULL);
+ }
+
+ return (aclp);
+}
+
+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);
+
+ error = ___acl_get_fd(fd, type, &aclp->ats_acl);
+ if (error) {
+ acl_free(aclp);
+ return (NULL);
+ }
+
+ return (aclp);
+}
+
+int
+acl_get_perm_np(acl_permset_t permset_d, acl_perm_t perm)
+{
+
+ if (permset_d == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ switch(perm) {
+ case ACL_READ:
+ case ACL_WRITE:
+ case ACL_EXECUTE:
+ if (*permset_d & perm)
+ return (1);
+ break;
+ default:
+ errno = EINVAL;
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * 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);
+}
diff --git a/lib/libc/posix1e/acl_get_entry.3 b/lib/libc/posix1e/acl_get_entry.3
new file mode 100644
index 0000000..42e03c1
--- /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 THE AUTHOR OR THE VOICES IN HIS HEAD BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 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 jedgar@fxp.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 0000000..7fe6c9c
--- /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 THE AUTHOR OR THE VOICES IN HIS HEAD BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 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 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 0000000..403b10a
--- /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 THE AUTHOR OR THE VOICES IN HIS HEAD BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 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 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 0000000..867809e
--- /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 THE AUTHOR OR THE VOICES IN HIS HEAD BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 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 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 0000000..ff22511
--- /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 THE AUTHOR OR THE VOICES IN HIS HEAD BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 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 jedgar@fxp.org .
diff --git a/lib/libc/posix1e/acl_init.3 b/lib/libc/posix1e/acl_init.3
new file mode 100644
index 0000000..dba8923
--- /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 0000000..6ce40de
--- /dev/null
+++ b/lib/libc/posix1e/acl_init.c
@@ -0,0 +1,76 @@
+/*-
+ * 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>
+
+acl_t
+acl_init(int count)
+{
+ acl_t acl;
+
+ if (count > ACL_MAX_ENTRIES) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ if (count < 0) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ acl = malloc(sizeof(struct acl_t_struct));
+ if (acl != NULL)
+ bzero(acl, sizeof(struct acl_t_struct));
+
+ 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_perm.c b/lib/libc/posix1e/acl_perm.c
new file mode 100644
index 0000000..c3375e0
--- /dev/null
+++ b/lib/libc/posix1e/acl_perm.c
@@ -0,0 +1,98 @@
+/*
+ * 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 THE VOICES IN HIS HEAD BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY 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>
+
+/*
+ * 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) {
+ switch(perm) {
+ case ACL_READ:
+ case ACL_WRITE:
+ case ACL_EXECUTE:
+ *permset_d |= perm;
+ return (0);
+ }
+ }
+
+ errno = EINVAL;
+ return (-1);
+}
+
+/*
+ * 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) {
+ switch(perm) {
+ case ACL_READ:
+ case ACL_WRITE:
+ case ACL_EXECUTE:
+ *permset_d &= ~(perm & ACL_PERM_BITS);
+ return (0);
+ }
+ }
+
+ errno = EINVAL;
+ return (-1);
+}
diff --git a/lib/libc/posix1e/acl_set.3 b/lib/libc/posix1e/acl_set.3
new file mode 100644
index 0000000..a2d50b8
--- /dev/null
+++ b/lib/libc/posix1e/acl_set.3
@@ -0,0 +1,142 @@
+.\"-
+.\" 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_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.
+.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 both.
+.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_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 0000000..34d5a33
--- /dev/null
+++ b/lib/libc/posix1e/acl_set.c
@@ -0,0 +1,199 @@
+/*-
+ * 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 "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)
+{
+ int error;
+
+ if (acl == NULL || path_p == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+ if (_posix1e_acl(acl, type)) {
+ error = _posix1e_acl_sort(acl);
+ if (error) {
+ errno = error;
+ return (-1);
+ }
+ }
+
+ 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)
+{
+ int error;
+
+ if (acl == NULL || path_p == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+ if (_posix1e_acl(acl, type)) {
+ error = _posix1e_acl_sort(acl);
+ if (error) {
+ errno = error;
+ return (-1);
+ }
+ }
+
+ acl->ats_cur_entry = 0;
+
+ return (__acl_set_link(path_p, type, &acl->ats_acl));
+}
+
+int
+acl_set_fd(int fd, acl_t acl)
+{
+ int error;
+
+ error = _posix1e_acl_sort(acl);
+ if (error) {
+ errno = error;
+ return(-1);
+ }
+
+ acl->ats_cur_entry = 0;
+
+ return (___acl_set_fd(fd, ACL_TYPE_ACCESS, &acl->ats_acl));
+}
+
+int
+acl_set_fd_np(int fd, acl_t acl, acl_type_t type)
+{
+ int error;
+
+ if (_posix1e_acl(acl, type)) {
+ error = _posix1e_acl_sort(acl);
+ if (error) {
+ errno = error;
+ return (-1);
+ }
+ }
+
+ 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);
+ }
+
+ 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_USER_OBJ:
+ case ACL_USER:
+ case ACL_GROUP_OBJ:
+ case ACL_GROUP:
+ case ACL_MASK:
+ case ACL_OTHER:
+ entry_d->ae_tag = tag_type;
+ return (0);
+ }
+
+ errno = EINVAL;
+ return (-1);
+}
diff --git a/lib/libc/posix1e/acl_set_permset.3 b/lib/libc/posix1e/acl_set_permset.3
new file mode 100644
index 0000000..152e226
--- /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 THE AUTHOR OR THE VOICES IN HIS HEAD BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 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 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 0000000..3442a82
--- /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 THE AUTHOR OR THE VOICES IN HIS HEAD BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 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 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 0000000..3830be7
--- /dev/null
+++ b/lib/libc/posix1e/acl_set_tag_type.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 THE AUTHOR OR THE VOICES IN HIS HEAD BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 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_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 .
+.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.
+.El
+.Sh SEE ALSO
+.Xr acl 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 jedgar@fxp.org .
diff --git a/lib/libc/posix1e/acl_size.c b/lib/libc/posix1e/acl_size.c
new file mode 100644
index 0000000..e8bd0a4
--- /dev/null
+++ b/lib/libc/posix1e/acl_size.c
@@ -0,0 +1,43 @@
+/*
+ * 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 THE VOICES IN HIS HEAD BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY 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>
+
+ssize_t
+acl_size(acl_t acl)
+{
+
+ errno = ENOSYS;
+ return (-1);
+}
diff --git a/lib/libc/posix1e/acl_support.c b/lib/libc/posix1e/acl_support.c
new file mode 100644
index 0000000..61e4cf9
--- /dev/null
+++ b/lib/libc/posix1e/acl_support.c
@@ -0,0 +1,437 @@
+/*-
+ * 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.
+ */
+/*
+ * 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 "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 '-'
+
+/*
+ * _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)
+{
+ /*
+ * 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
+ * Give the opportunity to fail, although we don't currently have a way
+ * to fail.
+ */
+int
+_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);
+
+ return (0);
+}
+
+/*
+ * 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)
+{
+
+ 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 obj_uid=-1, obj_gid=-1, 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++;
+ obj_uid = entry->ae_id;
+ break;
+
+ case ACL_USER:
+ /* printf("_posix1e_acl_check: %d: ACL_USER\n", i); */
+ if (stage > ACL_USER)
+ return (EINVAL);
+ stage = ACL_USER;
+ if (entry->ae_id == obj_uid)
+ return (EINVAL);
+ 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++;
+ obj_gid = entry->ae_id;
+ break;
+
+ case ACL_GROUP:
+ /* printf("_posix1e_acl_check: %d: ACL_GROUP\n", i); */
+ if (stage > ACL_GROUP)
+ return (EINVAL);
+ stage = ACL_GROUP;
+ if (entry->ae_id == obj_gid)
+ return (EINVAL);
+ 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 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)
+{
+ struct group *g;
+ struct passwd *p;
+ int i;
+
+ switch(tag) {
+ case ACL_USER:
+ 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:
+ 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);
+ }
+}
+
+
+/*
+ * 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
+ *
+ * XXX currently doesn't deal correctly with a numeric uid being passed
+ * instead of a username. What is correct behavior here? Check chown.
+ */
+int
+_posix1e_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);
+ }
+}
+
+
+/*
+ * 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);
+}
diff --git a/lib/libc/posix1e/acl_support.h b/lib/libc/posix1e/acl_support.h
new file mode 100644
index 0000000..6cccf0b
--- /dev/null
+++ b/lib/libc/posix1e/acl_support.h
@@ -0,0 +1,49 @@
+/*-
+ * 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 */
+
+int _posix1e_acl_check(acl_t acl);
+int _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 _posix1e_acl_name_to_id(acl_tag_t tag, char *name, uid_t *id);
+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);
+
+#endif
diff --git a/lib/libc/posix1e/acl_to_text.3 b/lib/libc/posix1e/acl_to_text.3
new file mode 100644
index 0000000..833a6d2
--- /dev/null
+++ b/lib/libc/posix1e/acl_to_text.3
@@ -0,0 +1,141 @@
+.\"-
+.\" 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_TO_TEXT 3
+.Os
+.Sh NAME
+.Nm acl_to_text
+.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"
+.Sh DESCRIPTION
+The
+.Fn acl_to_text
+function translates 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 .
+The format of the text string returned by
+.Fn acl_to_text
+shall be the POSIX.1e long ACL form.
+.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 0000000..f2905c3
--- /dev/null
+++ b/lib/libc/posix1e/acl_to_text.c
@@ -0,0 +1,237 @@
+/*-
+ * 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 <utmp.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 *
+acl_to_text(acl_t acl, ssize_t *len_p)
+{
+ struct acl *acl_int;
+ char *buf, *tmpbuf;
+ char name_buf[UT_NAMESIZE+1];
+ 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);
+
+ if (acl == NULL) {
+ errno = EINVAL;
+ 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,
+ UT_NAMESIZE+1, name_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, "%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,
+ UT_NAMESIZE+1, name_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:%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);
+}
diff --git a/lib/libc/posix1e/acl_valid.3 b/lib/libc/posix1e/acl_valid.3
new file mode 100644
index 0000000..83f7746
--- /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 0000000..9b1f9b9
--- /dev/null
+++ b/lib/libc/posix1e/acl_valid.c
@@ -0,0 +1,136 @@
+/*-
+ * 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);
+ }
+ _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)
+{
+ int error;
+
+ if (pathp == NULL || acl == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+ if (_posix1e_acl(acl, type)) {
+ error = _posix1e_acl_sort(acl);
+ if (error) {
+ errno = error;
+ return (-1);
+ }
+ }
+
+ return (__acl_aclcheck_file(pathp, type, &acl->ats_acl));
+}
+
+int
+acl_valid_link_np(const char *pathp, acl_type_t type, acl_t acl)
+{
+ int error;
+
+ if (pathp == NULL || acl == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+ if (_posix1e_acl(acl, type)) {
+ error = _posix1e_acl_sort(acl);
+ if (error) {
+ errno = error;
+ return (-1);
+ }
+ }
+
+ return (__acl_aclcheck_link(pathp, type, &acl->ats_acl));
+}
+
+int
+acl_valid_fd_np(int fd, acl_type_t type, acl_t acl)
+{
+ int error;
+
+ if (acl == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+ if (_posix1e_acl(acl, type)) {
+ error = _posix1e_acl_sort(acl);
+ if (error) {
+ errno = error;
+ return (-1);
+ }
+ }
+
+ 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 0000000..5e60686
--- /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 0000000..5a9ddce
--- /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 0000000..ac6affd
--- /dev/null
+++ b/lib/libc/posix1e/mac.3
@@ -0,0 +1,187 @@
+.\" Copyright (c) 2001, 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
+.\" 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 April 19, 2003
+.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
+.Fx
+permits administrators to define Mandatory Access Control labels
+defining levels for the privacy and integrity of data,
+overriding discretionary policies
+for those objects.
+Not all objects currently provide support for MAC labels,
+and MAC support must be explicitly enabled by the administrator.
+The library calls include routines to retrieve, duplicate,
+and set MAC labels associated with files and processes.
+.Pp
+POSIX.1e describes a set of MAC manipulation routines
+to manage the contents of MAC labels,
+as well as their relationships with
+files and processes;
+almost all of these support routines
+are implemented in
+.Fx .
+.Pp
+Available functions, sorted by behavior, include:
+.Bl -tag -width indent
+.It Fn mac_get_fd
+This function is described in
+.Xr mac_get 3 ,
+and may be used to retrieve the
+MAC label associated with
+a specific file descriptor.
+.It Fn mac_get_file
+This function is described in
+.Xr mac_get 3 ,
+and may be used to retrieve the
+MAC label associated with
+a named file.
+.It Fn mac_get_proc
+This function is described in
+.Xr mac_get 3 ,
+and may be used to retrieve the
+MAC label associated with
+the calling process.
+.It Fn mac_set_fd
+This function is described in
+.Xr mac_set 3 ,
+and may be used to set the
+MAC label associated with
+a specific file descriptor.
+.It Fn mac_set_file
+This function is described in
+.Xr mac_set 3 ,
+and may be used to set the
+MAC label associated with
+a named file.
+.It Fn mac_set_proc
+This function is described in
+.Xr mac_set 3 ,
+and may be used to set the
+MAC label associated with
+the calling process.
+.It Fn mac_free
+This function is described in
+.Xr mac_free 3 ,
+and may be used to free
+userland working MAC label storage.
+.It Fn mac_from_text
+This function is described in
+.Xr mac_text 3 ,
+and may be used to convert
+a text-form MAC label
+into a working
+.Vt mac_t .
+.It Fn mac_prepare
+.It Fn mac_prepare_file_label
+.It Fn mac_prepare_ifnet_label
+.It Fn mac_prepare_process_label
+These functions are described in
+.Xr mac_prepare 3 ,
+and may be used to preallocate storage for MAC label retrieval.
+.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
+The behavior of some of these calls is influenced by the configuration
+settings found in
+.Xr mac.conf 5 ,
+the MAC library run-time configuration file.
+.Sh IMPLEMENTATION NOTES
+.Fx Ns 's
+support for POSIX.1e interfaces and features
+is
+.Ud .
+.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_prepare 3 ,
+.Xr mac_set 3 ,
+.Xr mac_text 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.
+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.
+However, the resemblance of these APIs to the POSIX APIs is only loose,
+as the POSIX APIs were unable to express many 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.
+.Sh BUGS
+The
+.Tn TrustedBSD
+MAC Framework and associated policies, interfaces, and
+applications are considered to be an experimental feature in
+.Fx .
+Sites considering production deployment should keep the experimental
+status of these services in mind during any deployment process.
+See also
+.Xr mac 9
+for related considerations regarding the kernel framework.
diff --git a/lib/libc/posix1e/mac.c b/lib/libc/posix1e/mac.c
new file mode 100644
index 0000000..ded9059
--- /dev/null
+++ b/lib/libc/posix1e/mac.c
@@ -0,0 +1,448 @@
+/*
+ * 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.
+ *
+ * $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, "r");
+ 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 0000000..a8dfba2
--- /dev/null
+++ b/lib/libc/posix1e/mac.conf.5
@@ -0,0 +1,123 @@
+.\" 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 April 19, 2003
+.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.
+.Sh BUGS
+The
+.Tn TrustedBSD
+MAC Framework and associated policies, interfaces, and
+applications are considered to be an experimental feature in
+.Fx .
+Sites considering production deployment should keep the experimental
+status of these services in mind during any deployment process.
+See also
+.Xr mac 9
+for related considerations regarding the kernel framework.
diff --git a/lib/libc/posix1e/mac_exec.c b/lib/libc/posix1e/mac_exec.c
new file mode 100644
index 0000000..fb3f994
--- /dev/null
+++ b/lib/libc/posix1e/mac_exec.c
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ *
+ * $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 0000000..33ef9ec
--- /dev/null
+++ b/lib/libc/posix1e/mac_free.3
@@ -0,0 +1,98 @@
+.\" 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 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 that type, and must not be used to free the character
+strings returned from
+.Fn mac_to_text .
+Doing so may result in undefined behavior,
+including application failure.
diff --git a/lib/libc/posix1e/mac_get.3 b/lib/libc/posix1e/mac_get.3
new file mode 100644
index 0000000..cd498d0
--- /dev/null
+++ b/lib/libc/posix1e/mac_get.3
@@ -0,0 +1,151 @@
+.\" 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 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 0000000..1913f5d
--- /dev/null
+++ b/lib/libc/posix1e/mac_get.c
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ *
+ * $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 0000000..6466488
--- /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 January 9, 2002
+.Dt MAC_IS_PRESENT_NP 3
+.Os
+.Sh NAME
+.Nm mac_is_present_np
+.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_np
+function determines whether the currently-running kernel supports MAC for
+a given policy or not.
+If
+.Fa policyname
+is
+.No non- Ns 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_is_present_np.3 b/lib/libc/posix1e/mac_is_present_np.3
new file mode 100644
index 0000000..6466488
--- /dev/null
+++ b/lib/libc/posix1e/mac_is_present_np.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 January 9, 2002
+.Dt MAC_IS_PRESENT_NP 3
+.Os
+.Sh NAME
+.Nm mac_is_present_np
+.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_np
+function determines whether the currently-running kernel supports MAC for
+a given policy or not.
+If
+.Fa policyname
+is
+.No non- Ns 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 0000000..2e5f25a
--- /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
+.Os
+.Dt MAC_PREPARE 3
+.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
+.Dv ?
+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_np 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 0000000..175a25a
--- /dev/null
+++ b/lib/libc/posix1e/mac_set.3
@@ -0,0 +1,148 @@
+.\" 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_np 3 ,
+.Xr mac_prepare 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_set.c b/lib/libc/posix1e/mac_set.c
new file mode 100644
index 0000000..4353ee6
--- /dev/null
+++ b/lib/libc/posix1e/mac_set.c
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ *
+ * $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 0000000..068533a
--- /dev/null
+++ b/lib/libc/posix1e/mac_text.3
@@ -0,0 +1,116 @@
+.\" 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_np 3 ,
+.Xr mac_prepare 3 ,
+.Xr mac_set 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 0000000..6333b08
--- /dev/null
+++ b/lib/libc/posix1e/posix1e.3
@@ -0,0 +1,134 @@
+.\"-
+.\" Copyright (c) 2000 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 January 17, 2000
+.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/audit.h
+.\" .In sys/capability.h
+.In sys/mac.h
+.Sh DESCRIPTION
+The IEEE POSIX.1e specification never left draft form, but the interfaces
+it describes are now widely used despite inherent limitations.
+Currently, only a few of the interfaces and features are implemented in
+.Fx ,
+although efforts are underway to complete the integration at this time.
+.Pp
+POSIX.1e describes five security extensions to the base POSIX.1 API:
+Access Control Lists (ACLs), Auditing, Capabilities, Mandatory Access
+Control, and Information Flow Labels.
+.Fx
+supports POSIX.1e ACL interfaces, as well as POSIX.1e-like MAC
+interfaces.
+The TrustedBSD Project has produced but not integrated an implementation
+of POSIX.1e Capabilities.
+.Pp
+POSIX.1e defines both syntax and semantics for these features, but fairly
+substantial changes are required to implement these features in the
+operating system.
+.Pp
+As shipped,
+.Fx 4.0
+provides API and VFS support for ACLs, but not an implementation on any
+native file system.
+.Fx 5.0
+includes support for ACLs as part of UFS1 and UFS2, as well as necessary
+VFS support for additional file systems to export ACLs as appropriate.
+Available API calls relating to ACLs are described in detail in
+.Xr acl 3 .
+.Pp
+As shipped,
+.Fx 5.0
+includes support for Mandatory Access Control as well as POSIX.1e-like
+APIs for label management.
+More information on API calls relating to MAC is available in
+.Xr mac 3 .
+.Pp
+Additional patches supporting POSIX.1e features are provided by the
+TrustedBSD project:
+.Pp
+http://www.TrustedBSD.org/
+.Sh IMPLEMENTATION NOTES
+.Fx Ns 's
+support for POSIX.1e interfaces and features is still under
+development at this time, and many of these features are considered new
+or experimental.
+.Sh ENVIRONMENT
+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
+Many of these services are supported by extended attributes, documented
+in
+.Xr extattr 2
+and
+.Xr extattr 9 .
+While these APIs are not documented in POSIX.1e, they are similar in
+structure.
+.Sh SEE ALSO
+.Xr extattr 2 ,
+.Xr acl 3 ,
+.Xr mac 3 ,
+.Xr acl 9 ,
+.Xr extattr 9 ,
+.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
+POSIX.1e support was introduced in
+.Fx 4.0 ;
+most of the features are available as of
+.Fx 5.0 .
+Development continues.
+.Sh AUTHORS
+.An Robert N M Watson
+.An Chris D. Faulhaber
+.An Thomas Moestl
+.An Ilmar S Habibulin
+.Sh BUGS
+Many of these features are considered new or experimental in
+.Fx 5.0
+and should be deployed with appropriate caution.
diff --git a/lib/libc/powerpc/Makefile.inc b/lib/libc/powerpc/Makefile.inc
new file mode 100644
index 0000000..453726a
--- /dev/null
+++ b/lib/libc/powerpc/Makefile.inc
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+# Long double is 64-bits
+MDSRCS+=machdep_ldisd.c
+SYM_MAPS+=${.CURDIR}/powerpc/Symbol.map
diff --git a/lib/libc/powerpc/SYS.h b/lib/libc/powerpc/SYS.h
new file mode 100644
index 0000000..7ec3075
--- /dev/null
+++ b/lib/libc/powerpc/SYS.h
@@ -0,0 +1,75 @@
+/*-
+ * 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(x) \
+ .text; \
+ .align 2; \
+ li 0,(__CONCAT(SYS_,x)); \
+ sc
+
+#define SYSCALL(x) \
+ .text; \
+ .align 2; \
+2: b PIC_PLT(CNAME(HIDENAME(cerror))); \
+ENTRY(__CONCAT(__sys_,x)); \
+ .weak CNAME(x); \
+ .set CNAME(x),CNAME(__CONCAT(__sys_,x)); \
+ .weak CNAME(__CONCAT(_,x)); \
+ .set CNAME(__CONCAT(_,x)),CNAME(__CONCAT(__sys_,x)); \
+ _SYSCALL(x); \
+ bso 2b
+
+#define PSEUDO(x) \
+ .text; \
+ .align 2; \
+ENTRY(__CONCAT(__sys_,x)); \
+ .weak CNAME(__CONCAT(_,x)); \
+ .set CNAME(__CONCAT(_,x)),CNAME(__CONCAT(__sys_,x)); \
+ _SYSCALL(x); \
+ bnslr; \
+ b PIC_PLT(CNAME(HIDENAME(cerror)))
+
+#define RSYSCALL(x) \
+ .text; \
+ .align 2; \
+2: b PIC_PLT(CNAME(HIDENAME(cerror))); \
+ENTRY(__CONCAT(__sys_,x)); \
+ .weak CNAME(x); \
+ .set CNAME(x),CNAME(__CONCAT(__sys_,x)); \
+ .weak CNAME(__CONCAT(_,x)); \
+ .set CNAME(__CONCAT(_,x)),CNAME(__CONCAT(__sys_,x)); \
+ _SYSCALL(x); \
+ 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 0000000..a8af2ca
--- /dev/null
+++ b/lib/libc/powerpc/Symbol.map
@@ -0,0 +1,60 @@
+# $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;
+ fpgetround;
+ fpgetsticky;
+ fpsetmask;
+ fpsetround;
+ __infinity;
+ __nan;
+ makecontext;
+ modf;
+ setjmp;
+ longjmp;
+ sigsetjmp;
+ siglongjmp;
+ htonl;
+ __hton;
+ htons;
+ __htons;
+ ntohl;
+ __ntohl;
+ ntohs;
+ __ntohs;
+ brk;
+ exect;
+ pipe;
+ sbrk;
+};
+
+FBSDprivate {
+ # PSEUDO syscalls
+ __sys_getlogin;
+ _getlogin;
+ __sys_exit;
+
+ _set_tp;
+ _fpgetsticky;
+ __makecontext;
+ __longjmp;
+ signalcontext;
+ __signalcontext;
+ __syncicache;;
+ _end;
+ .curbrk;
+ .minbrk;
+ .cerror;
+};
diff --git a/lib/libc/powerpc/_fpmath.h b/lib/libc/powerpc/_fpmath.h
new file mode 100644
index 0000000..6d80eb4
--- /dev/null
+++ b/lib/libc/powerpc/_fpmath.h
@@ -0,0 +1,49 @@
+/*-
+ * 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 {
+ unsigned int sign :1;
+ unsigned int exp :11;
+ unsigned int manh :20;
+ unsigned int manl :32;
+ } 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 0000000..8e2c9ec
--- /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/gen/Makefile.inc b/lib/libc/powerpc/gen/Makefile.inc
new file mode 100644
index 0000000..4b381c3
--- /dev/null
+++ b/lib/libc/powerpc/gen/Makefile.inc
@@ -0,0 +1,9 @@
+# $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 modf.c _setjmp.S \
+ setjmp.S sigsetjmp.S signalcontext.c syncicache.c \
+ _set_tp.c
+
+
diff --git a/lib/libc/powerpc/gen/_ctx_start.S b/lib/libc/powerpc/gen/_ctx_start.S
new file mode 100644
index 0000000..a269e86
--- /dev/null
+++ b/lib/libc/powerpc/gen/_ctx_start.S
@@ -0,0 +1,43 @@
+/*
+ * 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 */
diff --git a/lib/libc/powerpc/gen/_set_tp.c b/lib/libc/powerpc/gen/_set_tp.c
new file mode 100644
index 0000000..045416d
--- /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$
+ */
+
+void
+_set_tp(void *tpval)
+{
+ register void* tp __asm__("r2");
+
+ tp = (char*) tpval + 0x7008;
+}
diff --git a/lib/libc/powerpc/gen/_setjmp.S b/lib/libc/powerpc/gen/_setjmp.S
new file mode 100644
index 0000000..6d6e5e0
--- /dev/null
+++ b/lib/libc/powerpc/gen/_setjmp.S
@@ -0,0 +1,71 @@
+/*-
+ * 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)
+ li %r3,0
+ blr
+
+ENTRY(_longjmp)
+ lmw %r9,20(%r3)
+ mtlr %r11
+ mtcr %r12
+ mr %r2,%r9
+ mr %r1,%r10
+ or. %r3,%r4,%r4
+ bnelr
+ li %r3,1
+ blr
diff --git a/lib/libc/powerpc/gen/fabs.S b/lib/libc/powerpc/gen/fabs.S
new file mode 100644
index 0000000..79475ca
--- /dev/null
+++ b/lib/libc/powerpc/gen/fabs.S
@@ -0,0 +1,35 @@
+/*
+ * 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
diff --git a/lib/libc/powerpc/gen/flt_rounds.c b/lib/libc/powerpc/gen/flt_rounds.c
new file mode 100644
index 0000000..ec32a36
--- /dev/null
+++ b/lib/libc/powerpc/gen/flt_rounds.c
@@ -0,0 +1,54 @@
+/* $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>
+
+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)];
+}
diff --git a/lib/libc/powerpc/gen/fpgetmask.c b/lib/libc/powerpc/gen/fpgetmask.c
new file mode 100644
index 0000000..4d9a3b0
--- /dev/null
+++ b/lib/libc/powerpc/gen/fpgetmask.c
@@ -0,0 +1,53 @@
+/* $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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 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.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <ieeefp.h>
+
+fp_except_t
+fpgetmask()
+{
+ u_int64_t fpscr;
+
+ __asm__("mffs %0" : "=f"(fpscr));
+ return ((fp_except_t)((fpscr >> 3) & 0x1f));
+}
diff --git a/lib/libc/powerpc/gen/fpgetround.c b/lib/libc/powerpc/gen/fpgetround.c
new file mode 100644
index 0000000..2e4b922
--- /dev/null
+++ b/lib/libc/powerpc/gen/fpgetround.c
@@ -0,0 +1,53 @@
+/* $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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 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.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <ieeefp.h>
+
+fp_rnd_t
+fpgetround()
+{
+ u_int64_t fpscr;
+
+ __asm__("mffs %0" : "=f"(fpscr));
+ return ((fp_rnd_t)(fpscr & 0x3));
+}
diff --git a/lib/libc/powerpc/gen/fpgetsticky.c b/lib/libc/powerpc/gen/fpgetsticky.c
new file mode 100644
index 0000000..e8a21ca
--- /dev/null
+++ b/lib/libc/powerpc/gen/fpgetsticky.c
@@ -0,0 +1,59 @@
+/* $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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 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$
+ */
+
+#include <sys/cdefs.h>
+
+#include "namespace.h"
+
+#include <sys/types.h>
+#include <ieeefp.h>
+
+#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));
+}
diff --git a/lib/libc/powerpc/gen/fpsetmask.c b/lib/libc/powerpc/gen/fpsetmask.c
new file mode 100644
index 0000000..76a6867
--- /dev/null
+++ b/lib/libc/powerpc/gen/fpsetmask.c
@@ -0,0 +1,57 @@
+/* $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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 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.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <ieeefp.h>
+
+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);
+}
diff --git a/lib/libc/powerpc/gen/fpsetround.c b/lib/libc/powerpc/gen/fpsetround.c
new file mode 100644
index 0000000..1337756
--- /dev/null
+++ b/lib/libc/powerpc/gen/fpsetround.c
@@ -0,0 +1,57 @@
+/* $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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 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.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <ieeefp.h>
+
+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);
+}
diff --git a/lib/libc/powerpc/gen/infinity.c b/lib/libc/powerpc/gen/infinity.c
new file mode 100644
index 0000000..cf1695e
--- /dev/null
+++ b/lib/libc/powerpc/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 powerpc */
+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/powerpc/gen/makecontext.c b/lib/libc/powerpc/gen/makecontext.c
new file mode 100644
index 0000000..d66e824
--- /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/modf.c b/lib/libc/powerpc/gen/modf.c
new file mode 100644
index 0000000..37786dc
--- /dev/null
+++ b/lib/libc/powerpc/gen/modf.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 1994, 1995 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ *
+ * $NetBSD: modf.c,v 1.1 1995/02/10 17:50:25 cgd Exp $
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <machine/ieee.h>
+#include <errno.h>
+#include <math.h>
+
+/*
+ * double modf(double val, double *iptr)
+ * returns: f and i such that |f| < 1.0, (f + i) = val, and
+ * sign(f) == sign(i) == sign(val).
+ *
+ * Beware signedness when doing subtraction, and also operand size!
+ */
+double
+modf(val, iptr)
+ double val, *iptr;
+{
+ union doub {
+ double v;
+ struct ieee_double s;
+ } u, v;
+ u_int64_t frac;
+
+ /*
+ * If input is Inf or NaN, return it and leave i alone.
+ */
+ u.v = val;
+ if (u.s.dbl_exp == DBL_EXP_INFNAN)
+ return (u.v);
+
+ /*
+ * If input can't have a fractional part, return
+ * (appropriately signed) zero, and make i be the input.
+ */
+ if ((int)u.s.dbl_exp - DBL_EXP_BIAS > DBL_FRACBITS - 1) {
+ *iptr = u.v;
+ v.v = 0.0;
+ v.s.dbl_sign = u.s.dbl_sign;
+ return (v.v);
+ }
+
+ /*
+ * If |input| < 1.0, return it, and set i to the appropriately
+ * signed zero.
+ */
+ if (u.s.dbl_exp < DBL_EXP_BIAS) {
+ v.v = 0.0;
+ v.s.dbl_sign = u.s.dbl_sign;
+ *iptr = v.v;
+ return (u.v);
+ }
+
+ /*
+ * There can be a fractional part of the input.
+ * If you look at the math involved for a few seconds, it's
+ * plain to see that the integral part is the input, with the
+ * low (DBL_FRACBITS - (exponent - DBL_EXP_BIAS)) bits zeroed,
+ * the the fractional part is the part with the rest of the
+ * bits zeroed. Just zeroing the high bits to get the
+ * fractional part would yield a fraction in need of
+ * normalization. Therefore, we take the easy way out, and
+ * just use subtraction to get the fractional part.
+ */
+ v.v = u.v;
+ /* Zero the low bits of the fraction, the sleazy way. */
+ frac = ((u_int64_t)v.s.dbl_frach << 32) + v.s.dbl_fracl;
+ frac >>= DBL_FRACBITS - (u.s.dbl_exp - DBL_EXP_BIAS);
+ frac <<= DBL_FRACBITS - (u.s.dbl_exp - DBL_EXP_BIAS);
+ v.s.dbl_fracl = frac & 0xffffffff;
+ v.s.dbl_frach = frac >> 32;
+ *iptr = v.v;
+
+ u.v -= v.v;
+ u.s.dbl_sign = v.s.dbl_sign;
+ return (u.v);
+}
diff --git a/lib/libc/powerpc/gen/setjmp.S b/lib/libc/powerpc/gen/setjmp.S
new file mode 100644
index 0000000..a796120
--- /dev/null
+++ b/lib/libc/powerpc/gen/setjmp.S
@@ -0,0 +1,91 @@
+/*-
+ * 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)
+ li %r3,0 /* return (0) */
+ blr
+
+ .weak CNAME(longjmp)
+ .set CNAME(longjmp),CNAME(__longjmp)
+ENTRY(__longjmp)
+ lmw %r9,20(%r3) /* restore regs */
+ 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
+
diff --git a/lib/libc/powerpc/gen/signalcontext.c b/lib/libc/powerpc/gen/signalcontext.c
new file mode 100644
index 0000000..30e2be8
--- /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 0000000..3d5d1e5
--- /dev/null
+++ b/lib/libc/powerpc/gen/sigsetjmp.S
@@ -0,0 +1,97 @@
+/*-
+ * 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)
+ li %r3,0
+ blr
+
+ENTRY(siglongjmp)
+ lmw %r9,20(%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
diff --git a/lib/libc/powerpc/gen/syncicache.c b/lib/libc/powerpc/gen/syncicache.c
new file mode 100644
index 0000000..e613f3a
--- /dev/null
+++ b/lib/libc/powerpc/gen/syncicache.c
@@ -0,0 +1,100 @@
+/*
+ * 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>
+
+#if defined(_KERNEL) || defined(_STANDALONE)
+#ifndef CACHELINESIZE
+#error "Must know the size of a cache line"
+#endif
+#else
+#include <stdlib.h>
+
+static void getcachelinesize(void);
+
+static int _cachelinesize;
+#define CACHELINESIZE _cachelinesize
+
+static void
+getcachelinesize()
+{
+ static int cachemib[] = { CTL_MACHDEP, CPU_CACHELINE };
+ int clen;
+
+ clen = sizeof(_cachelinesize);
+
+ if (sysctl(cachemib, sizeof(cachemib) / sizeof(cachemib[0]),
+ &_cachelinesize, &clen, NULL, 0) < 0 || !_cachelinesize) {
+ abort();
+ }
+}
+#endif
+
+void
+__syncicache(void *from, int len)
+{
+ int l, off;
+ char *p;
+
+#if !defined(_KERNEL) && !defined(_STANDALONE)
+ if (!_cachelinesize)
+ getcachelinesize();
+#endif
+ off = (u_int)from & (CACHELINESIZE - 1);
+ l = len += off;
+ p = (char *)from - off;
+ do {
+ __asm __volatile ("dcbst 0,%0" :: "r"(p));
+ p += CACHELINESIZE;
+ } while ((l -= CACHELINESIZE) > 0);
+ __asm __volatile ("sync");
+ p = (char *)from - off;
+ do {
+ __asm __volatile ("icbi 0,%0" :: "r"(p));
+ p += CACHELINESIZE;
+ } while ((len -= CACHELINESIZE) > 0);
+ __asm __volatile ("sync; isync");
+}
diff --git a/lib/libc/powerpc/net/Makefile.inc b/lib/libc/powerpc/net/Makefile.inc
new file mode 100644
index 0000000..96e559b
--- /dev/null
+++ b/lib/libc/powerpc/net/Makefile.inc
@@ -0,0 +1,4 @@
+# @(#)Makefile.inc 8.1 (Berkeley) 6/4/93
+# $FreeBSD$
+
+SRCS+= htonl.S htons.S ntohl.S ntohs.S
diff --git a/lib/libc/powerpc/net/htonl.S b/lib/libc/powerpc/net/htonl.S
new file mode 100644
index 0000000..b5a6d12
--- /dev/null
+++ b/lib/libc/powerpc/net/htonl.S
@@ -0,0 +1,38 @@
+/*-
+ * Copyright (c) 2002 David 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.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/* netorder = htonl(hostorder) */
+
+ .weak CNAME(htonl)
+ .set CNAME(htonl),CNAME(__htonl)
+ENTRY(__htonl)
+ blr
diff --git a/lib/libc/powerpc/net/htons.S b/lib/libc/powerpc/net/htons.S
new file mode 100644
index 0000000..6aba09c
--- /dev/null
+++ b/lib/libc/powerpc/net/htons.S
@@ -0,0 +1,38 @@
+/*-
+ * Copyright (c) 2002 David 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.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/* netorder = htons(hostorder) */
+
+ .weak CNAME(htons)
+ .set CNAME(htons),CNAME(__htons)
+ENTRY(__htons)
+ blr
diff --git a/lib/libc/powerpc/net/ntohl.S b/lib/libc/powerpc/net/ntohl.S
new file mode 100644
index 0000000..f85d59e
--- /dev/null
+++ b/lib/libc/powerpc/net/ntohl.S
@@ -0,0 +1,38 @@
+/*-
+ * Copyright (c) 2002 David 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.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/* hostorder = ntohl(netorder) */
+
+ .weak CNAME(ntohl)
+ .set CNAME(ntohl),CNAME(__ntohl)
+ENTRY(__ntohl)
+ blr
diff --git a/lib/libc/powerpc/net/ntohs.S b/lib/libc/powerpc/net/ntohs.S
new file mode 100644
index 0000000..21d41da
--- /dev/null
+++ b/lib/libc/powerpc/net/ntohs.S
@@ -0,0 +1,40 @@
+/*-
+ * Copyright (c) 2002 David 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.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/* hostorder = ntohs(netorder) */
+
+#include <machine/asm.h>
+
+ .weak CNAME(ntohs)
+ .set CNAME(ntohs),CNAME(__ntohs)
+ENTRY(__ntohs)
+ blr
diff --git a/lib/libc/powerpc/sys/Makefile.inc b/lib/libc/powerpc/sys/Makefile.inc
new file mode 100644
index 0000000..84579ae
--- /dev/null
+++ b/lib/libc/powerpc/sys/Makefile.inc
@@ -0,0 +1,11 @@
+# $FreeBSD$
+
+MDASM+= brk.S cerror.S exect.S pipe.S ptrace.S sbrk.S setlogin.S
+
+# Don't generate default code for these syscalls:
+NOASM= break.o exit.o ftruncate.o getdomainname.o getlogin.o \
+ lseek.o mmap.o openbsd_poll.o pread.o \
+ pwrite.o setdomainname.o sstk.o truncate.o uname.o yield.o
+
+PSEUDO= _getlogin.o _exit.o
+
diff --git a/lib/libc/powerpc/sys/brk.S b/lib/libc/powerpc/sys/brk.S
new file mode 100644
index 0000000..9223db3
--- /dev/null
+++ b/lib/libc/powerpc/sys/brk.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: 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))
diff --git a/lib/libc/powerpc/sys/cerror.S b/lib/libc/powerpc/sys/cerror.S
new file mode 100644
index 0000000..91a3006
--- /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 */
+
+
diff --git a/lib/libc/powerpc/sys/exect.S b/lib/libc/powerpc/sys/exect.S
new file mode 100644
index 0000000..d5f9c20
--- /dev/null
+++ b/lib/libc/powerpc/sys/exect.S
@@ -0,0 +1,39 @@
+/*-
+ * 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))
diff --git a/lib/libc/powerpc/sys/pipe.S b/lib/libc/powerpc/sys/pipe.S
new file mode 100644
index 0000000..3ca2358
--- /dev/null
+++ b/lib/libc/powerpc/sys/pipe.S
@@ -0,0 +1,43 @@
+/*-
+ * 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: pipe.S,v 1.6 2000/09/28 08:38:54 kleink Exp $ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+ENTRY(pipe)
+ mr %r5,%r3 /* save pointer */
+ li %r0,SYS_pipe
+ sc /* r5 is preserved */
+ bso 1f
+ stw %r3,0(%r5) /* success, store fds */
+ stw %r4,4(%r5)
+ li %r3,0
+ blr /* and return 0 */
+1:
+ b PIC_PLT(HIDENAME(cerror))
diff --git a/lib/libc/powerpc/sys/ptrace.S b/lib/libc/powerpc/sys/ptrace.S
new file mode 100644
index 0000000..f47fc67
--- /dev/null
+++ b/lib/libc/powerpc/sys/ptrace.S
@@ -0,0 +1,58 @@
+/*-
+ * 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: ptrace.S,v 1.3 2000/02/23 20:16:57 kleink Exp $ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+ENTRY(ptrace)
+ mflr %r0
+ stwu %r1,-32(%r1)
+ stw %r0,36(%r1)
+ stw %r3,8(%r1)
+ stw %r4,12(%r1)
+ stw %r5,16(%r1)
+ stw %r6,20(%r1)
+
+ bl PIC_PLT(CNAME(__error))
+ li %r7,0
+ stw %r7,0(%r3)
+
+ lwz %r3,8(%r1)
+ lwz %r4,12(%r1)
+ lwz %r5,16(%r1)
+ lwz %r0,36(%r1)
+ lwz %r6,20(%r1)
+ mtlr %r0
+ la %r1,32(%r1)
+ li %r0,SYS_ptrace
+ sc
+ bso 1f
+ blr
+1:
+ b PIC_PLT(HIDENAME(cerror))
diff --git a/lib/libc/powerpc/sys/sbrk.S b/lib/libc/powerpc/sys/sbrk.S
new file mode 100644
index 0000000..47fc0fe
--- /dev/null
+++ b/lib/libc/powerpc/sys/sbrk.S
@@ -0,0 +1,70 @@
+/*-
+ * 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))
diff --git a/lib/libc/powerpc/sys/setlogin.S b/lib/libc/powerpc/sys/setlogin.S
new file mode 100644
index 0000000..c65e639
--- /dev/null
+++ b/lib/libc/powerpc/sys/setlogin.S
@@ -0,0 +1,49 @@
+/*-
+ * 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
diff --git a/lib/libc/quad/Makefile.inc b/lib/libc/quad/Makefile.inc
new file mode 100644
index 0000000..281eb7e
--- /dev/null
+++ b/lib/libc/quad/Makefile.inc
@@ -0,0 +1,21 @@
+# from @(#)Makefile.inc 8.1 (Berkeley) 6/4/93
+# $FreeBSD$
+
+# Quad support, if needed
+.PATH: ${.CURDIR}/${MACHINE_ARCH}/quad ${.CURDIR}/quad
+
+.if ${MACHINE_ARCH} == "i386"
+
+SRCS+= cmpdi2.c divdi3.c moddi3.c qdivrem.c ucmpdi2.c udivdi3.c umoddi3.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_MAP+=${.CURDIR}/quad/Symbol.map
diff --git a/lib/libc/quad/Symbol.map b/lib/libc/quad/Symbol.map
new file mode 100644
index 0000000..e1c1d30
--- /dev/null
+++ b/lib/libc/quad/Symbol.map
@@ -0,0 +1,34 @@
+# $FreeBSD$
+
+FBSD_1.0 {
+};
+
+# XXX - Do these really need to be exported???
+FBSDprivate {
+ #__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 0000000..5834f21e
--- /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 0000000..d0cd68a
--- /dev/null
+++ b/lib/libc/quad/TESTS/divrem.c
@@ -0,0 +1,80 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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 0000000..8992c7c
--- /dev/null
+++ b/lib/libc/quad/TESTS/mul.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.
+ * 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.
+ */
+
+#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 0000000..9fdf16c
--- /dev/null
+++ b/lib/libc/quad/adddi3.c
@@ -0,0 +1,62 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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 0000000..37a3e77
--- /dev/null
+++ b/lib/libc/quad/anddi3.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.
+ * 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.
+ */
+
+#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 0000000..85dcb90
--- /dev/null
+++ b/lib/libc/quad/ashldi3.c
@@ -0,0 +1,68 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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 0000000..62bb906
--- /dev/null
+++ b/lib/libc/quad/ashrdi3.c
@@ -0,0 +1,77 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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 0000000..7e4d5f7
--- /dev/null
+++ b/lib/libc/quad/cmpdi2.c
@@ -0,0 +1,61 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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 0000000..5390e07
--- /dev/null
+++ b/lib/libc/quad/divdi3.c
@@ -0,0 +1,67 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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 0000000..fa947ef
--- /dev/null
+++ b/lib/libc/quad/fixdfdi.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.
+ * 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.
+ */
+
+#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 0000000..953c6b6
--- /dev/null
+++ b/lib/libc/quad/fixsfdi.c
@@ -0,0 +1,65 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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 0000000..632b196
--- /dev/null
+++ b/lib/libc/quad/fixunsdfdi.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.
+ * 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.
+ */
+
+#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 0000000..928e251
--- /dev/null
+++ b/lib/libc/quad/fixunssfdi.c
@@ -0,0 +1,102 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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 0000000..59ceb15
--- /dev/null
+++ b/lib/libc/quad/floatdidf.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.
+ * 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.
+ */
+
+#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 0000000..ef53b6b
--- /dev/null
+++ b/lib/libc/quad/floatdisf.c
@@ -0,0 +1,78 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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 0000000..f149dc3
--- /dev/null
+++ b/lib/libc/quad/floatunsdidf.c
@@ -0,0 +1,61 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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 0000000..d41a53e
--- /dev/null
+++ b/lib/libc/quad/iordi3.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.
+ * 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.
+ */
+
+#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 0000000..aab64f8
--- /dev/null
+++ b/lib/libc/quad/lshldi3.c
@@ -0,0 +1,68 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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 0000000..a31f3e1
--- /dev/null
+++ b/lib/libc/quad/lshrdi3.c
@@ -0,0 +1,67 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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 0000000..410e6d6
--- /dev/null
+++ b/lib/libc/quad/moddi3.c
@@ -0,0 +1,69 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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 0000000..38cc42e
--- /dev/null
+++ b/lib/libc/quad/muldi3.c
@@ -0,0 +1,248 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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 0000000..657319f
--- /dev/null
+++ b/lib/libc/quad/negdi2.c
@@ -0,0 +1,59 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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 0000000..80d082c
--- /dev/null
+++ b/lib/libc/quad/notdi2.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.
+ * 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.
+ */
+
+#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 0000000..9176b8e
--- /dev/null
+++ b/lib/libc/quad/qdivrem.c
@@ -0,0 +1,281 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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 0000000..1f7c1ac
--- /dev/null
+++ b/lib/libc/quad/quad.h
@@ -0,0 +1,107 @@
+/*-
+ * 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.
+ * 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.
+ *
+ * @(#)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 0000000..1c5690a
--- /dev/null
+++ b/lib/libc/quad/subdi3.c
@@ -0,0 +1,61 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#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 0000000..83f9195
--- /dev/null
+++ b/lib/libc/quad/ucmpdi2.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.
+ * 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.
+ */
+
+#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 0000000..54a539c
--- /dev/null
+++ b/lib/libc/quad/udivdi3.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.
+ * 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.
+ */
+
+#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 0000000..ecc5bdc
--- /dev/null
+++ b/lib/libc/quad/umoddi3.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.
+ * 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.
+ */
+
+#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 0000000..b10aee9
--- /dev/null
+++ b/lib/libc/quad/xordi3.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.
+ * 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.
+ */
+
+#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 0000000..574f6bc
--- /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 0000000..a2e23eb
--- /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: ${.CURDIR}/regex
+
+CFLAGS+=-DPOSIX_MISTAKE
+
+SRCS+= regcomp.c regerror.c regexec.c regfree.c
+
+SYM_MAPS+=${.CURDIR}/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 0000000..dda1af8
--- /dev/null
+++ b/lib/libc/regex/Symbol.map
@@ -0,0 +1,8 @@
+# $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 0000000..f4301d3
--- /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 0000000..b03085e
--- /dev/null
+++ b/lib/libc/regex/cname.h
@@ -0,0 +1,142 @@
+/*-
+ * 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.
+ *
+ * @(#)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 0000000..bb55da1
--- /dev/null
+++ b/lib/libc/regex/engine.c
@@ -0,0 +1,1197 @@
+/*-
+ * 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.
+ *
+ * @(#)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) */
+ char *offp; /* offsets work from here */
+ char *beginp; /* start of string -- virtual NUL precedes */
+ char *endp; /* end of string -- virtual NUL here */
+ char *coldp; /* can be no match starting before here */
+ 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, char *string, size_t nmatch, regmatch_t pmatch[], int eflags);
+static char *dissect(struct match *m, char *start, char *stop, sopno startst, sopno stopst);
+static char *backref(struct match *m, char *start, char *stop, sopno startst, sopno stopst, sopno lev);
+static char *fast(struct match *m, char *start, char *stop, sopno startst, sopno stopst);
+static char *slow(struct match *m, char *start, 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 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, char *caption, states st, int ch, FILE *d);
+#endif
+#ifdef REDEBUG
+static void at(struct match *m, char *title, char *start, char *stop, sopno startst, sopno stopst);
+#endif
+#ifdef REDEBUG
+static 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, char *string, \
+ == size_t nmatch, regmatch_t pmatch[], int eflags);
+ */
+static int /* 0 success, REG_NOMATCH failure */
+matcher(g, string, nmatch, pmatch, eflags)
+struct re_guts *g;
+char *string;
+size_t nmatch;
+regmatch_t pmatch[];
+int eflags;
+{
+ char *endp;
+ int i;
+ struct match mv;
+ struct match *m = &mv;
+ char *dp;
+ const sopno gf = g->firststate+1; /* +1 for OEND */
+ const sopno gl = g->laststate;
+ char *start;
+ char *stop;
+ /* Boyer-Moore algorithms variables */
+ char *pp;
+ int cj, mj;
+ char *mustfirst;
+ 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 (g->moffset > -1)
+ start = ((dp - g->moffset) < start) ? start : dp - g->moffset;
+
+ /* 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 = (char **)malloc((g->nplus+1) *
+ sizeof(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);
+ }
+ 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);
+ }
+ 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 char *dissect(struct match *m, char *start, \
+ == char *stop, sopno startst, sopno stopst);
+ */
+static char * /* == stop (success) always */
+dissect(m, start, stop, startst, stopst)
+struct match *m;
+char *start;
+char *stop;
+sopno startst;
+sopno stopst;
+{
+ int i;
+ sopno ss; /* start sop of current subRE */
+ sopno es; /* end sop of current subRE */
+ char *sp; /* start of string matched by it */
+ char *stp; /* string matched by it cannot pass here */
+ char *rest; /* start of rest of string */
+ char *tail; /* string unmatched by rest of RE */
+ sopno ssub; /* start sop of subsubRE */
+ sopno esub; /* end sop of subsubRE */
+ char *ssp; /* start of string matched by subsubRE */
+ char *sep; /* end of string matched by subsubRE */
+ char *oldssp; /* previous ssp */
+ 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 char *backref(struct match *m, char *start, \
+ == char *stop, sopno startst, sopno stopst, sopno lev);
+ */
+static char * /* == stop (success) or NULL (failure) */
+backref(m, start, stop, startst, stopst, lev)
+struct match *m;
+char *start;
+char *stop;
+sopno startst;
+sopno stopst;
+sopno lev; /* PLUS nesting level */
+{
+ int i;
+ sopno ss; /* start sop of current subRE */
+ char *sp; /* start of string matched by it */
+ sopno ssub; /* start sop of subsubRE */
+ sopno esub; /* end sop of subsubRE */
+ char *ssp; /* start of string matched by subsubRE */
+ 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->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->beginp && !(m->eflags&REG_NOTBOL)) ||
+ (sp < m->endp && *(sp-1) == '\n' &&
+ (m->g->cflags&REG_NEWLINE)) ||
+ (sp > m->beginp &&
+ !ISWORD(*(sp-1))) ) &&
+ (sp < m->endp && ISWORD(*sp)) )
+ { /* 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;
+ 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));
+ break;
+ case OQUEST_: /* to null or not */
+ dp = backref(m, sp, stop, ss+1, stopst, lev);
+ if (dp != NULL)
+ return(dp); /* not */
+ return(backref(m, sp, stop, ss+OPND(s)+1, stopst, lev));
+ break;
+ 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));
+ break;
+ case O_PLUS:
+ if (sp == m->lastpos[lev]) /* last pass matched null */
+ return(backref(m, sp, stop, ss+1, stopst, lev-1));
+ /* try another pass */
+ m->lastpos[lev] = sp;
+ dp = backref(m, sp, stop, ss-OPND(s)+1, stopst, lev);
+ if (dp == NULL)
+ return(backref(m, sp, stop, ss+1, stopst, lev-1));
+ else
+ return(dp);
+ break;
+ 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);
+ 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);
+ }
+ 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);
+ if (dp != NULL)
+ return(dp);
+ m->pmatch[i].rm_so = offsave;
+ return(NULL);
+ break;
+ 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);
+ if (dp != NULL)
+ return(dp);
+ m->pmatch[i].rm_eo = offsave;
+ return(NULL);
+ break;
+ 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 char *fast(struct match *m, char *start, \
+ == char *stop, sopno startst, sopno stopst);
+ */
+static char * /* where tentative match ended, or NULL */
+fast(m, start, stop, startst, stopst)
+struct match *m;
+char *start;
+char *stop;
+sopno startst;
+sopno stopst;
+{
+ states st = m->st;
+ states fresh = m->fresh;
+ states tmp = m->tmp;
+ char *p = start;
+ wint_t c;
+ wint_t lastc; /* previous c */
+ wint_t flagch;
+ int i;
+ char *coldp; /* last p after which no match was underway */
+ size_t clen;
+
+ CLEAR(st);
+ SET1(st, startst);
+ st = step(m->g, startst, stopst, st, NOTHING, st);
+ ASSIGN(fresh, st);
+ SP("start", st, *p);
+ coldp = NULL;
+ if (start == m->beginp)
+ 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 char *slow(struct match *m, char *start, \
+ == char *stop, sopno startst, sopno stopst);
+ */
+static char * /* where it ended */
+slow(m, start, stop, startst, stopst)
+struct match *m;
+char *start;
+char *stop;
+sopno startst;
+sopno stopst;
+{
+ states st = m->st;
+ states empty = m->empty;
+ states tmp = m->tmp;
+ char *p = start;
+ wint_t c;
+ wint_t lastc; /* previous c */
+ wint_t flagch;
+ int i;
+ 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->beginp)
+ 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(g, start, stop, bef, ch, aft)
+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);
+ }
+ 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, char *caption, states st, \
+ == int ch, FILE *d);
+ == #endif
+ */
+static void
+print(m, caption, st, ch, d)
+struct match *m;
+char *caption;
+states st;
+int ch;
+FILE *d;
+{
+ struct re_guts *g = m->g;
+ int 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, char *title, char *start, char *stop, \
+ == sopno startst, sopno stopst);
+ == #endif
+ */
+static void
+at(m, title, start, stop, startst, stopst)
+struct match *m;
+char *title;
+char *start;
+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 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 char * /* -> representation */
+pchar(ch)
+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 0000000..3e41724
--- /dev/null
+++ b/lib/libc/regex/grot/Makefile
@@ -0,0 +1,98 @@
+# $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= ${.CURDIR}/.. ${.CURDIR}/../../locale ${.CURDIR}/../../../../include
+.PATH: ${PATHS}
+
+CFLAGS+= -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: main.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 0000000..caa2ca3
--- /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, "!%d(%d)!", OP(*s), 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 0000000..6b2bf38
--- /dev/null
+++ b/lib/libc/regex/grot/main.c
@@ -0,0 +1,513 @@
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <regex.h>
+#include <assert.h>
+
+#include "main.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;
+
+
+extern int split();
+extern void regprint();
+
+/*
+ - main - do the simple case, hand off to regress() for regression
+ */
+main(argc, argv)
+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")) != EOF)
+ 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, %d/%d `%s'\n",
+ eprint(err), len, sizeof(erbuf), erbuf);
+ exit(status);
+ }
+ regprint(&re, stdout);
+
+ if (optind >= argc) {
+ regfree(&re);
+ exit(status);
+ }
+
+ if (eopts&REG_STARTEND) {
+ 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, %d/%d `%s'\n",
+ eprint(err), len, sizeof(erbuf), erbuf);
+ exit(status);
+ }
+ if (!(copts&REG_NOSUB)) {
+ len = (int)(subs[0].rm_eo - subs[0].rm_so);
+ if (subs[0].rm_so != -1) {
+ if (len != 0)
+ printf("match `%.*s'\n", 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(in)
+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);
+ */
+void
+try(f0, f1, f2, f3, f4, opts)
+char *f0;
+char *f1;
+char *f2;
+char *f3;
+char *f4;
+int opts; /* may not match f1 */
+{
+ regex_t re;
+# define NSUBS 10
+ regmatch_t subs[NSUBS];
+# define NSHOULD 15
+ char *should[NSHOULD];
+ int nshould;
+ char erbuf[100];
+ int err;
+ int len;
+ char *type = (opts & REG_EXTENDED) ? "ERE" : "BRE";
+ int i;
+ char *grump;
+ 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, %d/%d `%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, %d/%d `%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
+ == int options(int type, char *s);
+ */
+int
+options(type, s)
+int type; /* 'c' compile, 'e' exec */
+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(c, s)
+int c;
+char *s;
+{
+ return(strchr(s, c) != NULL);
+}
+
+/*
+ - fixstr - transform magic characters in strings
+ == void fixstr(char *p);
+ */
+void
+fixstr(p)
+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(str, sub, should)
+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(err)
+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(name)
+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 0000000..1deba79
--- /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 0000000..70e0ec5
--- /dev/null
+++ b/lib/libc/regex/grot/split.c
@@ -0,0 +1,319 @@
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <string.h>
+
+/*
+ - split - divide a string into fields, like awk split()
+ = int split(char *string, char *fields[], int nfields, char *sep);
+ */
+int /* number of fields, including overflow */
+split(string, fields, nfields, sep)
+char *string;
+char *fields[]; /* list is not NULL-terminated */
+int nfields; /* number of entries available in fields[] */
+char *sep; /* "" white, "c" single char, "ab" [ab]+ */
+{
+ 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(argc, argv)
+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);
+}
+
+dosplit(string, seps)
+char *string;
+char *seps;
+{
+# define NF 5
+ char *fields[NF];
+ int nf;
+
+ nf = split(string, fields, NF, seps);
+ print(nf, NF, fields);
+}
+
+print(nf, nfp, fields)
+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 },
+};
+
+regress()
+{
+ 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 0000000..07e9dfb
--- /dev/null
+++ b/lib/libc/regex/grot/tests
@@ -0,0 +1,450 @@
+# 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
+
+# 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
diff --git a/lib/libc/regex/re_format.7 b/lib/libc/regex/re_format.7
new file mode 100644
index 0000000..d4555a0
--- /dev/null
+++ b/lib/libc/regex/re_format.7
@@ -0,0 +1,476 @@
+.\" 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 March 20, 1994
+.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:
+.Pp
+.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
+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.
+.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
+.No ( Ql {1,}
+or
+.Ql {0,1}
+respectively).
+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 0000000..e03c6c2
--- /dev/null
+++ b/lib/libc/regex/regcomp.c
@@ -0,0 +1,1844 @@
+/*-
+ * 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.
+ *
+ * @(#)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 <runetype.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, wint_t stop);
+static void p_ere_exp(struct parse *p);
+static void p_str(struct parse *p);
+static void p_bre(struct parse *p, wint_t end1, wint_t 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 void 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(preg, pattern, cflags)
+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;
+#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);
+ p->ssize = len/(size_t)2*(size_t)3 + (size_t)1; /* ugh */
+ 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 stop);
+ */
+static void
+p_ere(p, stop)
+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(p)
+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();
+ ordinary(p, wc);
+ 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(p)
+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(p, end1, end2)
+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(p, starordinary)
+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(); /* repetion 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|'{':
+ 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(p)
+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(p)
+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(p, cs)
+struct parse *p;
+cset *cs;
+{
+ char c;
+ wint_t start, finish;
+ wint_t i;
+
+ /* classify what we've got */
+ switch ((MORE()) ? PEEK() : '\0') {
+ case '[':
+ c = (MORE2()) ? PEEK2() : '\0';
+ break;
+ case '-':
+ SETERROR(REG_ERANGE);
+ return; /* NOTE RETURN */
+ break;
+ 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 (__collate_load_error) {
+ (void)REQUIRE((uch)start <= (uch)finish, REG_ERANGE);
+ CHaddrange(p, cs, start, finish);
+ } else {
+ (void)REQUIRE(__collate_range_cmp(start, finish) <= 0, REG_ERANGE);
+ for (i = 0; i <= UCHAR_MAX; i++) {
+ if ( __collate_range_cmp(start, i) <= 0
+ && __collate_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(p, cs)
+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(p, cs)
+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 char p_b_symbol(struct parse *p);
+ */
+static wint_t /* value of symbol */
+p_b_symbol(p)
+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 char p_b_coll_elem(struct parse *p, int endc);
+ */
+static wint_t /* value of collating element */
+p_b_coll_elem(p, endc)
+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 char othercase(int ch);
+ */
+static wint_t /* if no counterpart, return ch */
+othercase(ch)
+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, int ch);
+ *
+ * Boy, is this implementation ever a kludge...
+ */
+static void
+bothcases(p, ch)
+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, int ch);
+ */
+static void
+ordinary(p, ch)
+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(p)
+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(p, start, from, to)
+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(p)
+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(p, e)
+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(p)
+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(p, cs)
+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(cs)
+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(p, cs, ch)
+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(p, cs, min, max)
+struct parse *p;
+cset *cs;
+wint_t min, 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].min = max;
+ cs->nranges++;
+}
+
+/*
+ - CHaddtype - add all characters of a certain type to a character set.
+ */
+static void
+CHaddtype(p, cs, wct)
+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(p, start, finish)
+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);
+ enlarge(p, p->ssize + len); /* this many unexpected additions */
+ assert(p->ssize >= p->slen + len);
+ (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(p, op, opnd)
+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)
+ enlarge(p, (p->ssize+1) / 2 * 3); /* +50% */
+ assert(p->slen < p->ssize);
+
+ /* 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(p, op, opnd, pos)
+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(p, pos, value)
+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 void enlarge(struct parse *p, sopno size);
+ */
+static void
+enlarge(p, size)
+struct parse *p;
+sopno size;
+{
+ sop *sp;
+
+ if (p->ssize >= size)
+ return;
+
+ sp = (sop *)realloc(p->strip, size*sizeof(sop));
+ if (sp == NULL) {
+ SETERROR(REG_ESPACE);
+ return;
+ }
+ p->strip = sp;
+ p->ssize = size;
+}
+
+/*
+ - stripsnug - compact the strip
+ == static void stripsnug(struct parse *p, struct re_guts *g);
+ */
+static void
+stripsnug(p, g)
+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(p, g)
+struct parse *p;
+struct re_guts *g;
+{
+ sop *scan;
+ sop *start;
+ sop *newstart;
+ 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(scan, offset)
+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(p, g)
+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(p, g)
+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(unsigned int));
+ if (pmatches == NULL) {
+ g->matchjump = NULL;
+ return;
+ }
+
+ g->matchjump = (int*) malloc(g->mlen * sizeof(unsigned int));
+ if (g->matchjump == NULL) /* Not a fatal error */
+ 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(p, g)
+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 0000000..7942ef7
--- /dev/null
+++ b/lib/libc/regex/regerror.c
@@ -0,0 +1,181 @@
+/*-
+ * 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.
+ *
+ * @(#)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(errcode, preg, errbuf, errbuf_size)
+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(preg, localbuf)
+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 0000000..c3180af
--- /dev/null
+++ b/lib/libc/regex/regex.3
@@ -0,0 +1,731 @@
+.\" 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.
+.\"
+.\" @(#)regex.3 8.4 (Berkeley) 3/20/94
+.\" $FreeBSD$
+.\"
+.Dd August 17, 2005
+.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 not the beginning of a line, so the
+.Ql ^\&
+anchor should not match before it.
+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 should 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
++
+.Fa pmatch Ns [0]. Ns Va rm_so
+and to have a terminating NUL located at
+.Fa string
++
+.Fa pmatch Ns [0]. Ns Va rm_eo
+(there need not actually be a NUL at that location),
+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.
+Note that a non-zero
+.Va rm_so
+does not imply
+.Dv REG_NOTBOL ;
+.Dv REG_STARTEND
+affects only the location of the string,
+not how it is matched.
+.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
+.Fn ( regerror
+may be able to supply a more detailed message using information
+from the
+.Ft regex_t . )
+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 0000000..3016915
--- /dev/null
+++ b/lib/libc/regex/regex2.h
@@ -0,0 +1,196 @@
+/*-
+ * 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.
+ *
+ * @(#)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 0000000..c596bdd
--- /dev/null
+++ b/lib/libc/regex/regexec.c
@@ -0,0 +1,244 @@
+/*-
+ * 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.
+ *
+ * @(#)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(wi, s, n, mbs, dummy)
+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(wi, s, n, mbs, 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(preg, string, nmatch, pmatch, eflags)
+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 0000000..b1e6a35
--- /dev/null
+++ b/lib/libc/regex/regfree.c
@@ -0,0 +1,94 @@
+/*-
+ * 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.
+ *
+ * @(#)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(preg)
+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 0000000..9d6eba3
--- /dev/null
+++ b/lib/libc/regex/utils.h
@@ -0,0 +1,58 @@
+/*-
+ * 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.
+ *
+ * @(#)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 0000000..c185b47
--- /dev/null
+++ b/lib/libc/resolv/Makefile.inc
@@ -0,0 +1,9 @@
+# $FreeBSD$
+
+# resolv sources
+.PATH: ${.CURDIR}/resolv
+
+SRCS+= herror.c h_errno.c mtctxres.c res_comp.c res_data.c res_debug.c \
+ res_init.c res_mkquery.c res_query.c res_send.c res_state.c
+
+SYM_MAPS+= ${.CURDIR}/resolv/Symbol.map
diff --git a/lib/libc/resolv/Symbol.map b/lib/libc/resolv/Symbol.map
new file mode 100644
index 0000000..7aa2256
--- /dev/null
+++ b/lib/libc/resolv/Symbol.map
@@ -0,0 +1,105 @@
+# $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_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;
+ ___res;
+ ___res_ext;
+ __h_errno;
+ __h_errno_set;
+ __h_error;
+ h_errno;
+ res_init;
+ __res_mkquery;
+ res_mkquery;
+ __res_opt;
+ __res_freeupdrec;
+ #__res_get_nibblesuffix; # Excluded
+ #__res_get_nibblesuffix2; # Excluded
+ __res_getservers;
+ __res_hostalias;
+ __res_nametoclass;
+ __res_nametotype;
+ __res_nclose;
+ __res_ndestroy;
+ __res_ninit;
+ __res_nmkquery;
+ __res_nopt;
+ __res_nquery;
+ __res_nquerydomain;
+ __res_nsearch;
+ __res_nsend;
+ __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_mkupdate;
+ res_update; # Why is this not __res_update?
+};
diff --git a/lib/libc/resolv/h_errno.c b/lib/libc/resolv/h_errno.c
new file mode 100644
index 0000000..4d471b4
--- /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)
+{
+ return (&__res_state()->res_h_errno);
+}
+
+void
+__h_errno_set(res_state res, int err)
+{
+ h_errno = res->res_h_errno = err;
+}
+
+/* binary backward compatibility for FreeBSD 5.x and 6.x */
+__weak_reference(__h_errno, __h_error);
diff --git a/lib/libc/resolv/herror.c b/lib/libc/resolv/herror.c
index 58807e9..be4b43e 100644
--- a/lib/libc/resolv/herror.c
+++ b/lib/libc/resolv/herror.c
@@ -52,9 +52,12 @@
static const char sccsid[] = "@(#)herror.c 8.1 (Berkeley) 6/4/93";
static const char rcsid[] = "$Id: herror.c,v 1.2.206.1 2004/03/09 08:33:54 marka Exp $";
#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
#include "port_before.h"
+#include "namespace.h"
#include <sys/types.h>
#include <sys/param.h>
#include <sys/uio.h>
@@ -66,7 +69,7 @@ static const char rcsid[] = "$Id: herror.c,v 1.2.206.1 2004/03/09 08:33:54 marka
#include <resolv.h>
#include <string.h>
#include <unistd.h>
-#include <irs.h>
+#include "un-namespace.h"
#include "port_after.h"
@@ -77,12 +80,10 @@ const char *h_errlist[] = {
"Unknown server error", /* 3 NO_RECOVERY */
"No address associated with name", /* 4 NO_ADDRESS */
};
-int h_nerr = { sizeof h_errlist / sizeof h_errlist[0] };
+const int h_nerr = { sizeof h_errlist / sizeof h_errlist[0] };
-#if !(__GLIBC__ > 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)
#undef h_errno
int h_errno;
-#endif
/*
* herror --
@@ -110,7 +111,7 @@ herror(const char *s) {
DE_CONST("\n", t);
v->iov_base = t;
v->iov_len = 1;
- writev(STDERR_FILENO, iov, (v - iov) + 1);
+ _writev(STDERR_FILENO, iov, (v - iov) + 1);
}
/*
diff --git a/lib/libc/resolv/mtctxres.c b/lib/libc/resolv/mtctxres.c
index f33cf11..86b5a79 100644
--- a/lib/libc/resolv/mtctxres.c
+++ b/lib/libc/resolv/mtctxres.c
@@ -1,13 +1,18 @@
+#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 <irs.h>
#include <port_after.h>
#ifdef DO_PTHREADS
@@ -40,6 +45,7 @@ _mtctxres_init(void) {
}
#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()
@@ -54,6 +60,7 @@ int
__res_disable_mt(void) {
return (0);
}
+#endif
#ifdef DO_PTHREADS
static int
@@ -99,6 +106,11 @@ ___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
diff --git a/lib/libc/resolv/res_comp.c b/lib/libc/resolv/res_comp.c
index 8cc99a7..cf45f07 100644
--- a/lib/libc/resolv/res_comp.c
+++ b/lib/libc/resolv/res_comp.c
@@ -72,6 +72,8 @@
static const char sccsid[] = "@(#)res_comp.c 8.1 (Berkeley) 6/4/93";
static const char rcsid[] = "$Id: res_comp.c,v 1.1.2.1.4.2 2005/07/28 07:43:22 marka Exp $";
#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
#include "port_before.h"
#include <sys/types.h>
@@ -261,3 +263,12 @@ 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);
diff --git a/lib/libc/resolv/res_data.c b/lib/libc/resolv/res_data.c
index 204e03d..ab6d575 100644
--- a/lib/libc/resolv/res_data.c
+++ b/lib/libc/resolv/res_data.c
@@ -18,6 +18,8 @@
#if defined(LIBC_SCCS) && !defined(lint)
static const char rcsid[] = "$Id: res_data.c,v 1.1.206.2 2004/03/16 12:34:18 marka Exp $";
#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
#include "port_before.h"
@@ -40,7 +42,6 @@ static const char rcsid[] = "$Id: res_data.c,v 1.1.206.2 2004/03/16 12:34:18 mar
#include <unistd.h>
#include "port_after.h"
-#undef _res
const char *_res_opcodes[] = {
"QUERY",
@@ -71,11 +72,6 @@ const char *_res_sectioncodes[] = {
#endif
#ifndef __BIND_NOSTATIC
-struct __res_state _res
-# if defined(__BIND_RES_TEXT)
- = { RES_TIMEOUT, } /* Motorola, et al. */
-# endif
- ;
/* Proto. */
@@ -107,7 +103,7 @@ res_init(void) {
if (!_res.retrans)
_res.retrans = RES_TIMEOUT;
if (!_res.retry)
- _res.retry = 4;
+ _res.retry = RES_DFLRETRY;
if (!(_res.options & RES_INIT))
_res.options = RES_DEFAULT;
@@ -181,6 +177,7 @@ res_query(const char *name, /* domain name */
return (res_nquery(&_res, name, class, type, answer, anslen));
}
+#ifndef _LIBC
void
res_send_setqhook(res_send_qhook hook) {
_res.qhook = hook;
@@ -190,6 +187,7 @@ void
res_send_setrhook(res_send_rhook hook) {
_res.rhook = hook;
}
+#endif
int
res_isourserver(const struct sockaddr_in *inp) {
@@ -206,6 +204,7 @@ res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) {
return (res_nsend(&_res, buf, buflen, ans, anssiz));
}
+#ifndef _LIBC
int
res_sendsigned(const u_char *buf, int buflen, ns_tsig_key *key,
u_char *ans, int anssiz)
@@ -217,6 +216,7 @@ res_sendsigned(const u_char *buf, int buflen, ns_tsig_key *key,
return (res_nsendsigned(&_res, buf, buflen, key, ans, anssiz));
}
+#endif
void
res_close(void) {
@@ -264,6 +264,12 @@ res_querydomain(const char *name,
answer, anslen));
}
+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];
@@ -288,4 +294,25 @@ local_hostname_length(const char *hostname) {
}
#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
diff --git a/lib/libc/resolv/res_debug.c b/lib/libc/resolv/res_debug.c
index 8dda12c..29c6ef4 100644
--- a/lib/libc/resolv/res_debug.c
+++ b/lib/libc/resolv/res_debug.c
@@ -97,6 +97,8 @@
static const char sccsid[] = "@(#)res_debug.c 8.1 (Berkeley) 6/4/93";
static const char rcsid[] = "$Id: res_debug.c,v 1.3.2.5.4.6 2005/07/28 07:43:22 marka Exp $";
#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
#include "port_before.h"
@@ -375,7 +377,7 @@ const struct res_sym __p_class_syms[] = {
/*
* Names of message sections.
*/
-const struct res_sym __p_default_section_syms[] = {
+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},
@@ -383,7 +385,7 @@ const struct res_sym __p_default_section_syms[] = {
{0, (char *)0, (char *)0}
};
-const struct res_sym __p_update_section_syms[] = {
+static const struct res_sym __p_update_section_syms[] = {
{S_ZONE, "ZONE", (char *)0},
{S_PREREQ, "PREREQUISITE", (char *)0},
{S_UPDATE, "UPDATE", (char *)0},
@@ -470,7 +472,7 @@ const struct res_sym __p_type_syms[] = {
/*
* Names of DNS rcodes.
*/
-const struct res_sym __p_rcode_syms[] = {
+static 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"},
@@ -1161,3 +1163,22 @@ res_nametotype(const char *buf, int *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);
diff --git a/lib/libc/resolv/res_init.c b/lib/libc/resolv/res_init.c
index 28a3ebd..30ff9dc 100644
--- a/lib/libc/resolv/res_init.c
+++ b/lib/libc/resolv/res_init.c
@@ -72,6 +72,8 @@
static const char sccsid[] = "@(#)res_init.c 8.1 (Berkeley) 6/7/93";
static const char rcsid[] = "$Id: res_init.c,v 1.9.2.5.4.5 2005/11/03 00:00:52 marka Exp $";
#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
#include "port_before.h"
@@ -106,12 +108,12 @@ static const char rcsid[] = "$Id: res_init.c,v 1.9.2.5.4.5 2005/11/03 00:00:52 m
#include <sys/systeminfo.h>
#endif
-static void res_setoptions __P((res_state, const char *, const char *));
+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 __P((struct in_addr));
+static u_int32_t net_mask(struct in_addr);
#endif
#if !defined(isascii) /* XXX - could be a function */
@@ -153,9 +155,9 @@ res_ninit(res_state statp) {
/* This function has to be reachable by res_data.c but not publically. */
int
__res_vinit(res_state statp, int preinit) {
- register FILE *fp;
- register char *cp, **pp;
- register int n;
+ FILE *fp;
+ char *cp, **pp;
+ int n;
char buf[BUFSIZ];
int nserv = 0; /* number of nameserver records read from file */
int haveenv = 0;
@@ -253,7 +255,7 @@ __res_vinit(res_state statp, int preinit) {
#endif /* SOLARIS2 */
/* Allow user to override the local domain definition */
- if ((cp = getenv("LOCALDOMAIN")) != NULL) {
+ if (issetugid() == 0 && (cp = getenv("LOCALDOMAIN")) != NULL) {
(void)strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
statp->defdname[sizeof(statp->defdname) - 1] = '\0';
haveenv++;
@@ -390,6 +392,10 @@ __res_vinit(res_state statp, int preinit) {
#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) {
@@ -424,6 +430,57 @@ __res_vinit(res_state statp, int preinit) {
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;
@@ -486,7 +543,9 @@ __res_vinit(res_state statp, int preinit) {
#endif
}
- if ((cp = getenv("RES_OPTIONS")) != NULL)
+ if (issetugid())
+ statp->options |= RES_NOALIASES;
+ else if ((cp = getenv("RES_OPTIONS")) != NULL)
res_setoptions(statp, cp, "env");
statp->options |= RES_INIT;
return (0);
@@ -506,7 +565,9 @@ res_setoptions(res_state statp, const char *options, const char *source)
{
const char *cp = options;
int i;
+#ifndef _LIBC
struct __res_state_ext *ext = statp->_u._ext.ext;
+#endif
#ifdef DEBUG
if (statp->options & RES_DEBUG)
@@ -580,6 +641,10 @@ res_setoptions(res_state statp, const char *options, const char *source)
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",
@@ -591,6 +656,7 @@ res_setoptions(res_state statp, const char *options, const char *source)
statp->options |= RES_USE_EDNS0;
}
#endif
+#ifndef _LIBC
else if (!strncmp(cp, "dname", sizeof("dname") - 1)) {
statp->options |= RES_USE_DNAME;
}
@@ -620,10 +686,13 @@ res_setoptions(res_state statp, const char *options, const char *source)
~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++;
@@ -636,7 +705,7 @@ static u_int32_t
net_mask(in) /* XXX - should really use system's version of this */
struct in_addr in;
{
- register u_int32_t i = ntohl(in.s_addr);
+ u_int32_t i = ntohl(in.s_addr);
if (IN_CLASSA(i))
return (htonl(IN_CLASSA_NET));
@@ -687,6 +756,7 @@ res_ndestroy(res_state statp) {
statp->_u._ext.ext = NULL;
}
+#ifndef _LIBC
const char *
res_get_nibblesuffix(res_state statp) {
if (statp->_u._ext.ext)
@@ -700,6 +770,7 @@ res_get_nibblesuffix2(res_state statp) {
return (statp->_u._ext.ext->nsuffix2);
return ("ip6.int");
}
+#endif
void
res_setservers(res_state statp, const union res_sockaddr_union *set, int cnt) {
diff --git a/lib/libc/resolv/res_mkquery.c b/lib/libc/resolv/res_mkquery.c
index 89000ed..60f1efc1 100644
--- a/lib/libc/resolv/res_mkquery.c
+++ b/lib/libc/resolv/res_mkquery.c
@@ -72,6 +72,8 @@
static const char sccsid[] = "@(#)res_mkquery.c 8.1 (Berkeley) 6/4/93";
static const char rcsid[] = "$Id: res_mkquery.c,v 1.1.2.2.4.2 2004/03/16 12:34:18 marka Exp $";
#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
#include "port_before.h"
#include <sys/types.h>
@@ -104,9 +106,9 @@ res_nmkquery(res_state statp,
u_char *buf, /* buffer to put query */
int buflen) /* size of buffer */
{
- register HEADER *hp;
- register u_char *cp, *ep;
- register int n;
+ HEADER *hp;
+ u_char *cp, *ep;
+ int n;
u_char *dnptrs[20], **dpp, **lastdnptr;
UNUSED(newrr_in);
@@ -214,8 +216,8 @@ res_nopt(res_state statp,
int buflen, /* size of buffer */
int anslen) /* UDP answer buffer size */
{
- register HEADER *hp;
- register u_char *cp, *ep;
+ HEADER *hp;
+ u_char *cp, *ep;
u_int16_t flags = 0;
#ifdef DEBUG
@@ -234,6 +236,8 @@ res_nopt(res_state statp,
ns_put16(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 */
diff --git a/lib/libc/resolv/res_query.c b/lib/libc/resolv/res_query.c
index 5156ce8..e715b85 100644
--- a/lib/libc/resolv/res_query.c
+++ b/lib/libc/resolv/res_query.c
@@ -72,6 +72,8 @@
static const char sccsid[] = "@(#)res_query.c 8.1 (Berkeley) 6/4/93";
static const char rcsid[] = "$Id: res_query.c,v 1.2.2.3.4.2 2004/03/16 12:34:19 marka Exp $";
#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
#include "port_before.h"
#include <sys/types.h>
@@ -86,6 +88,7 @@ static const char rcsid[] = "$Id: res_query.c,v 1.2.2.3.4.2 2004/03/16 12:34:19
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
#include "port_after.h"
/* Options. Leave them on. */
@@ -242,6 +245,21 @@ res_nsearch(res_state statp,
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++;
}
@@ -265,6 +283,9 @@ res_nsearch(res_state statp,
(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);
@@ -297,9 +318,26 @@ res_nsearch(res_state statp,
/* 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 */
- got_servfail++;
break;
}
/* FALLTHROUGH */
@@ -316,6 +354,18 @@ res_nsearch(res_state statp,
}
}
+ 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.
@@ -335,6 +385,7 @@ res_nsearch(res_state statp,
* 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)
@@ -401,6 +452,8 @@ res_hostalias(const res_state statp, const char *name, char *dst, size_t siz) {
if (statp->options & RES_NOALIASES)
return (NULL);
+ if (issetugid())
+ return (NULL);
file = getenv("HOSTALIASES");
if (file == NULL || (fp = fopen(file, "r")) == NULL)
return (NULL);
diff --git a/lib/libc/resolv/res_send.c b/lib/libc/resolv/res_send.c
index 5be2489..f31abf1 100644
--- a/lib/libc/resolv/res_send.c
+++ b/lib/libc/resolv/res_send.c
@@ -72,14 +72,19 @@
static const char sccsid[] = "@(#)res_send.c 8.1 (Berkeley) 6/4/93";
static const char rcsid[] = "$Id: res_send.c,v 1.5.2.2.4.7 2005/08/15 02:04:41 marka Exp $";
#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
/*
* Send query to name server and wait for reply.
*/
#include "port_before.h"
+#ifndef USE_KQUEUE
#include "fd_setsize.h"
+#endif
+#include "namespace.h"
#include <sys/types.h>
#include <sys/param.h>
#include <sys/time.h>
@@ -103,12 +108,18 @@ static const char rcsid[] = "$Id: res_send.c,v 1.5.2.2.4.7 2005/08/15 02:04:41 m
#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. */
#define DEBUG
@@ -125,18 +136,22 @@ static int highestFD = 0;
/* Forward. */
-static int get_salen __P((const struct sockaddr *));
-static struct sockaddr * get_nsaddr __P((res_state, size_t));
+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, const u_char *, int,
+static int send_dg(res_state,
+#ifdef USE_KQUEUE
+ int kq,
+#endif
+ const u_char *, int,
u_char *, 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)
+#if defined(NEED_PSELECT) && !defined(USE_POLL) && !defined(USE_KQUEUE)
static int pselect(int, void *, void *, void *,
struct timespec *,
const sigset_t *);
@@ -289,6 +304,9 @@ res_nsend(res_state statp,
const u_char *buf, int buflen, u_char *ans, int anssiz)
{
int gotsomewhere, terrno, try, v_circuit, resplen, ns, n;
+#ifdef USE_KQUEUE
+ int kq;
+#endif
char abuf[NI_MAXHOST];
#ifdef USE_POLL
@@ -309,6 +327,13 @@ res_nsend(res_state statp,
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.
@@ -332,7 +357,7 @@ res_nsend(res_state statp,
if (EXT(statp).nssocks[ns] == -1)
continue;
peerlen = sizeof(peer);
- if (getsockname(EXT(statp).nssocks[ns],
+ if (_getsockname(EXT(statp).nssocks[ns],
(struct sockaddr *)&peer, &peerlen) < 0) {
needclose++;
break;
@@ -424,6 +449,9 @@ res_nsend(res_state statp,
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 */
@@ -457,7 +485,11 @@ res_nsend(res_state statp,
resplen = n;
} else {
/* Use datagrams. */
- n = send_dg(statp, buf, buflen, ans, anssiz, &terrno,
+ n = send_dg(statp,
+#ifdef USE_KQUEUE
+ kq,
+#endif
+ buf, buflen, ans, anssiz, &terrno,
ns, &v_circuit, &gotsomewhere);
if (n < 0)
goto fail;
@@ -516,11 +548,17 @@ res_nsend(res_state statp,
} 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 */
@@ -531,6 +569,9 @@ res_nsend(res_state statp,
return (-1);
fail:
res_nclose(statp);
+#ifdef USE_KQUEUE
+ _close(kq);
+#endif
return (-1);
}
@@ -608,7 +649,7 @@ send_vc(res_state statp,
struct sockaddr_storage peer;
ISC_SOCKLEN_T size = sizeof peer;
- if (getpeername(statp->_vcsock,
+ if (_getpeername(statp->_vcsock,
(struct sockaddr *)&peer, &size) < 0 ||
!sock_eq((struct sockaddr *)&peer, nsap)) {
res_nclose(statp);
@@ -620,7 +661,7 @@ send_vc(res_state statp,
if (statp->_vcsock >= 0)
res_nclose(statp);
- statp->_vcsock = socket(nsap->sa_family, SOCK_STREAM, 0);
+ statp->_vcsock = _socket(nsap->sa_family, SOCK_STREAM, 0);
if (statp->_vcsock > highestFD) {
res_nclose(statp);
errno = ENOTSOCK;
@@ -641,7 +682,7 @@ send_vc(res_state statp,
}
}
errno = 0;
- if (connect(statp->_vcsock, nsap, nsaplen) < 0) {
+ if (_connect(statp->_vcsock, nsap, nsaplen) < 0) {
*terrno = errno;
Aerror(statp, stderr, "connect/vc", errno, nsap,
nsaplen);
@@ -658,7 +699,7 @@ send_vc(res_state statp,
iov[0] = evConsIovec(&len, INT16SZ);
DE_CONST(buf, tmp);
iov[1] = evConsIovec(tmp, buflen);
- if (writev(statp->_vcsock, iov, 2) != (INT16SZ + buflen)) {
+ if (_writev(statp->_vcsock, iov, 2) != (INT16SZ + buflen)) {
*terrno = errno;
Perror(statp, stderr, "write failed", errno);
res_nclose(statp);
@@ -670,7 +711,7 @@ send_vc(res_state statp,
read_len:
cp = ans;
len = INT16SZ;
- while ((n = read(statp->_vcsock, (char *)cp, (int)len)) > 0) {
+ while ((n = _read(statp->_vcsock, (char *)cp, (int)len)) > 0) {
cp += n;
if ((len -= n) == 0)
break;
@@ -716,7 +757,8 @@ send_vc(res_state statp,
return (0);
}
cp = ans;
- while (len != 0 && (n = read(statp->_vcsock, (char *)cp, (int)len)) > 0){
+ while (len != 0 &&
+ (n = _read(statp->_vcsock, (char *)cp, (int)len)) > 0) {
cp += n;
len -= n;
}
@@ -735,8 +777,8 @@ send_vc(res_state statp,
while (len != 0) {
char junk[PACKETSZ];
- n = read(statp->_vcsock, junk,
- (len > sizeof junk) ? sizeof junk : len);
+ n = _read(statp->_vcsock, junk,
+ (len > sizeof junk) ? sizeof junk : len);
if (n > 0)
len -= n;
else
@@ -767,6 +809,9 @@ send_vc(res_state statp,
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 *v_circuit, int *gotsomewhere)
{
@@ -778,17 +823,22 @@ send_dg(res_state statp,
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, 0);
+ EXT(statp).nssocks[ns] = _socket(nsap->sa_family,
+ SOCK_DGRAM, 0);
if (EXT(statp).nssocks[ns] > highestFD) {
res_nclose(statp);
errno = ENOTSOCK;
@@ -819,8 +869,16 @@ send_dg(res_state statp,
* 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 (connect(EXT(statp).nssocks[ns], nsap, nsaplen) < 0) {
+ if (!(statp->options & RES_INSECURE1) &&
+ _connect(EXT(statp).nssocks[ns], nsap, nsaplen) < 0) {
Aerror(statp, stderr, "connect(dg)", errno, nsap,
nsaplen);
res_nclose(statp);
@@ -832,13 +890,20 @@ send_dg(res_state statp,
}
s = EXT(statp).nssocks[ns];
#ifndef CANNOT_CONNECT_DGRAM
- if (send(s, (const char*)buf, buflen, 0) != buflen) {
+ 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)
+ if (_sendto(s, (const char*)buf, buflen, 0, nsap, nsaplen) != buflen)
{
Aerror(statp, stderr, "sendto", errno, nsap, nsaplen);
res_nclose(statp);
@@ -862,13 +927,18 @@ send_dg(res_state statp,
now = evNowTime();
nonow:
#ifndef USE_POLL
- FD_ZERO(&dsmask);
- FD_SET(s, &dsmask);
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)
@@ -888,17 +958,21 @@ send_dg(res_state statp,
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);
}
errno = 0;
fromlen = sizeof(from);
- resplen = recvfrom(s, (char*)ans, anssiz,0,
+ resplen = _recvfrom(s, (char*)ans, anssiz,0,
(struct sockaddr *)&from, &fromlen);
if (resplen <= 0) {
Perror(statp, stderr, "recvfrom", errno);
@@ -1061,7 +1135,7 @@ sock_eq(struct sockaddr *a, struct sockaddr *b) {
}
}
-#if defined(NEED_PSELECT) && !defined(USE_POLL)
+#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,
diff --git a/lib/libc/resolv/res_state.c b/lib/libc/resolv/res_state.c
new file mode 100644
index 0000000..b2742ce
--- /dev/null
+++ b/lib/libc/resolv/res_state.c
@@ -0,0 +1,96 @@
+/*-
+ * 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>
+#include <stdlib.h>
+
+#include "namespace.h"
+#include "reentrant.h"
+#include "un-namespace.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;
+}
+
+res_state
+__res_state(void)
+{
+ res_state statp;
+
+ if (thr_main() != 0)
+ return (&_res);
+
+ if (thr_once(&res_init_once, res_keycreate) != 0 ||
+ !res_thr_keycreated)
+ return (&_res);
+
+ statp = thr_getspecific(res_key);
+ if (statp != NULL)
+ return (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);
+}
+
+/* binary backward compatibility for FreeBSD 5.x and 6.x */
+struct __res_state_ext *
+___res_ext(void)
+{
+ return (__res_state()->_u._ext.ext);
+}
+
+__weak_reference(__res_state, ___res);
diff --git a/lib/libc/rpc/DISCLAIMER b/lib/libc/rpc/DISCLAIMER
new file mode 100644
index 0000000..9a3a991
--- /dev/null
+++ b/lib/libc/rpc/DISCLAIMER
@@ -0,0 +1,31 @@
+/* $NetBSD: DISCLAIMER,v 1.2 1998/01/09 04:11:51 perry Exp $ */
+/* $FreeBSD$ */
+
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
diff --git a/lib/libc/rpc/LICENSE b/lib/libc/rpc/LICENSE
new file mode 100644
index 0000000..5f1205c
--- /dev/null
+++ b/lib/libc/rpc/LICENSE
@@ -0,0 +1,335 @@
+$FreeBSD$
+
+Sun Industry Standards Source License 1.0
+
+DEFINITIONS
+
+1.1. "Commercial Use" means distribution or otherwise
+making the Original Code available to a third party.
+
+1.2. "Contributor Version" means the combination of the
+Original Code, and the Modifications made by that particular
+Contributor.
+
+1.3. "Electronic Distribution Mechanism" means a mechanism
+generally accepted in the software development community for
+the electronic transfer of data.
+
+1.4. "Executable" means Original Code in any form other
+than Source Code.
+
+1.5. "Initial Developer" means the individual or entity
+identified as the Initial Developer in the Source Code
+notice required by 2 (Exhibit A)
+
+1.6. "Larger Work" means a work which combines Original
+Code or portions thereof with code not governed by the terms
+of this License.
+
+1.7. "License" means this document.
+
+1.8. "Licensable" means having the right to grant, to the
+maximum extent possible, whether at the time of the initial
+grant or subsequently acquired, any and all of the rights
+conveyed herein.
+
+1.9. "Modifications" means any addition to or deletion from
+the substance or structure of either the Original Code or
+any previous Modifications. A Modification is:
+
+A. Any addition to or deletion from the contents of a file
+containing Original Code or previous Modifications.
+
+B. Any new file that contains any part of the Original Code
+or previous Modifications. .
+
+1.10. "Original Code" means Source Code of computer
+software code which is described in the Source Code notice
+required by Exhibit A as Original Code.
+
+1.11. "Patent Claims" means any patent claims, now owned or
+hereafter acquired, including without limitation, method,
+process, and apparatus claims, in any patent Licensable by
+grantor.
+
+1.12. "Source Code" means the preferred form of the
+Original Code for making modifications to it, including all
+modules it contains, plus any associated interface
+definition files, or scripts used to control compilation and
+installation of an Executable.
+
+1.13. "Standards" means the standard identified in Exhibit
+B or a subsequent version of such standard.
+
+1.14. "You" or "Your" means an individual or a legal entity
+exercising rights under, and complying with all of the terms
+of, this License or a future version of this License issued
+under Section 6.1. For legal entities, "You" includes any
+entity which controls, is controlled by, or is under common
+control with You. For purposes of this definition,
+"control" means (a) the power, direct or indirect, to cause
+the direction or management of such entity, whether by
+contract or otherwise, or (b) ownership of more than fifty
+percent (50%) of the outstanding shares or beneficial
+ownership of such entity.
+
+2.0 SOURCE CODE LICENSE
+
+2.1 The Initial Developer Grant: The Initial Developer
+hereby grants You a world-wide, royalty-free, non-exclusive
+license, subject to third party intellectual property
+claims:
+
+a) under intellectual property rights (other than patent or
+trademark) Licensable by Initial Developer to use,
+reproduce, modify, display, perform, sub license and
+distribute the Original Code (or portions thereof )with or
+without Modifications, and/or as part of a Larger Work; and
+
+b) under Patents Claims infringed by the making, using or
+selling of Original Code, to make, have made, use, practice,
+sell, and offer for sale, and/or otherwise dispose of the
+Original Code (or portions thereof).
+
+c) the licenses granted in this Section 2.1(a ) and (b) are
+effective on the date Initial Developer first distributes
+Original Code under the terms of this License.
+
+d) Notwithstanding Section 2.1(b )above, no patent license
+is granted: 1) for code that You delete from the Original
+Code; 2) separate from the Original Code; or 3) for
+infringements caused by: i) the modification of the
+Original Code or
+
+ii) the combination of the Original Code with other software
+or devices, including but not limited to Modifications.
+
+3.0 DISTRIBUTION OBLIGATIONS
+
+3.1 Application of License. The Source Code version of
+Original Code may be distributed only under the terms of
+this License or a future version of this License released
+under Section 6.1, and You must include a copy of this
+License with every copy of the Source Code You distribute.
+You may not offer or impose any terms on any Source Code
+version that alters or restricts the applicable version of
+this License or the recipient's rights hereunder. Your
+license for shipment of the Contributor Version is
+conditioned upon your full compliance with this Section.
+The Modifications which you create must comply with all
+requirements set out by the Standards body in effect 120
+days before You ship the Contributor Version. In the event
+that the Modifications do not meet such requirements, You
+agree to publish (i) any deviation from the Standards
+protocol resulting from implementation of your Modifications
+and (ii) a reference implementation of Your Modifications,
+and to make any such deviation and reference implementation
+available to all third parties under the same terms as the
+license on a royalty free basis within thirty (30) days of
+Your first customer shipment of Your Modifications.
+
+3.2 Required Notices. You must duplicate the notice in
+Exhibit A in each file of the Source Code. If it is not
+possible to put such notice in a particular Source Code file
+due to its structure, then You must include such notice in a
+location (such as a relevant directory ) where a user would
+be likely to look for such a notice. If You created one or
+more Modifications ) You may add your name as a Contributor
+to the notice described in Exhibit A. You must also
+duplicate this License in any documentation for the Source
+Code where You describe recipients' rights or ownership
+rights relating to Initial Code. You may choose to offer,
+and to charge a fee for, warranty, support, indemnity or
+liability obligations to one or more recipients of Your
+version of the Code. However, You may do so only
+
+on Your own behalf, and not on behalf of the Initial
+Developer. You must make it absolutely clear than any such
+warranty, support, indemnity or liability obligation is
+offered by You alone, and You hereby agree to indemnify the
+Initial Developer for any liability incurred by the Initial
+Developer as a result of warranty, support, indemnity or
+liability terms You offer.
+
+3.3 Distribution of Executable Versions. You may distribute
+Original Code in Executable and Source form only if the
+requirements of Section 3.1 and 3.2 have been met for that
+Original Code, and if You include a notice stating that the
+Source Code version of the Original Code is available under
+the terms of this License. The notice must be conspicuously
+included in any notice in an Executable or Source versions,
+related documentation or collateral in which You describe
+recipients' rights relating to the Original Code. You may
+distribute the Executable and Source versions of Your
+version of the Code or ownership rights under a license of
+Your choice, which may contain terms different from this
+License, provided that You are in compliance with the terms
+of this License. If You distribute the Executable and
+Source versions under a different license You must make it
+absolutely clear that any terms which differ from this
+License are offered by You alone, not by the Initial
+Developer . You hereby agree to indemnify the Initial
+Developer for any liability incurred by the Initial
+Developer as a result of any such terms You offer .
+
+3.4 Larger Works. You may create a Larger Work by combining
+Original Code with other code not governed by the terms of
+this License and distribute the Larger Work as a single
+product. In such a case, You must make sure the
+requirements of this License are fulfilled for the Original
+Code.
+
+4.0 INABILITY TO COMPLY DUE TO STATUTE OR REGULATION
+
+If it is impossible for You to comply with any of the terms
+of this License with respect to some or all of the Original
+Code due to statute, judicial order, or regulation then You
+must:
+
+a) comply with the terms of this License to the maximum
+extent possible; and
+
+b) describe the limitations and the code they affect. Such
+description must be included in the LEGAL file described in
+Section 3.2 and must be included with all distributions of
+the Source Code. Except to the extent prohibited by statute
+or regulation, such description must be sufficiently
+detailed for a recipient of ordinary skill to be able to
+understand it.
+
+5.0 APPLICATION OF THIS LICENSE This License applies to code
+to which the Initial Developer has attached the notice in
+Exhibit A and to related Modifications as set out in Section
+3.1.
+
+6.0 VERSIONS OF THE LICENSE
+
+6.1 New Versions. Sun Microsystems, Inc. Sun may publish
+revised and/or new versions of the License from time to
+time. Each version will be given a distinguishing version
+number .
+
+6.2 Effect of New Versions. Once Original Code has been
+published under a particular version of the License, You may
+always continue to use it under the terms of that version.
+You may also choose to use such Original Code under the
+terms of any subsequent version of the License published by
+Sun. No one other than Sun has the right to modify the
+terms applicable to Original Code.
+
+7. DISCLAIMER OF W ARRANTY. ORIGINAL CODE IS PROVIDED
+UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY OF
+ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT
+LIMITATION, WARRANTIES THAT THE ORIGINAL CODE IS FREE OF
+DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR
+NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND
+PERFORMANCE OF THE ORIGINAL CODE IS WITH YOU. SHOULD ANY
+ORIGINAL CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE
+INITIAL DEVELOPER )ASSUME THE COST OF ANY NECESSARY
+SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF
+WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO
+USE OF ANY ORIGINAL CODE IS AUTHORIZED HEREUNDER EXCEPT
+UNDER THIS DISCLAIMER.
+
+8.0 TERMINATION
+
+8.1 This License and the rights granted hereunder will
+terminate automatically if You fail to comply with terms
+herein and fail to cure such breach within 30 days of
+becoming aware of the breach. All sublicenses to the
+Original Code which are properly granted shall survive any
+termination of this License. Provisions which, by their
+nature, must remain in effect beyond the termination of this
+License shall survive.
+
+8.2 .In the event of termination under Section 8.1 above,
+all end user license agreements (excluding distributors and
+resellers) which have been validly granted by You or any
+distributor hereunder prior to termination shall survive
+termination.
+
+9.0 LIMIT OF LIABILITY UNDER NO CIRCUMSTANCES AND UNDER NO
+LEGAL THEORY, WHETHER TORT (INCLUDING NEGLIGENCE) ,CONTRACT,
+OR OTHER WISE, SHALL YOU, THE INITIAL DEVELOPER, ANY OTHER
+CONTRIBUTOR, OR ANY DISTRIBUTOR OF ORIGINAL CODE, OR ANY
+SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR
+ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR
+LOSS OF GOOD WILL, WORK STOPPAGE, COMPUTER FAILURE OR
+MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR
+LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE
+POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY
+SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY
+RESULTING FROM SUCH PARTYS NEGLIGENCE TO THE EXTENT
+APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME
+JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF
+INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND
+LIMITATION MAY NOT APPLY TO YOU.
+
+10.0 U .S. GOVERNMENT END USERS U.S. Government: If this
+Software is being acquired by or on behalf of the U.S.
+Government or by a U.S. Government prime contractor or
+subcontractor (at any tier), then the Government's rights in
+the Software and accompanying documentation shall be only as
+set forth in this license; this is in accordance with 48 C.F
+.R. 227.7201 through 227.7202-4 (for Department of Defense
+(DoD) acquisitions )and with 48 C.F.R.2.101 and 12.212( for
+non-DoD acquisitions).
+
+11.0 MISCELLANEOUS This License represents the complete
+agreement concerning subject matter hereof. If any
+provision of this License is held to be unenforceable, such
+provision shall be reformed only to the extent necessary to
+make it enforceable. This License shall be governed by
+California law provisions (except to the extent applicable
+law, if any, provides otherwise), excluding its
+conflict-of-law provisions. With respect to disputes in
+which at least one party is a citizen of, or an entity
+chartered or registered to do business in the United States
+of America, any litigation relating to this License shall be
+subject to the jurisdiction of the Federal Courts of the
+Northern District of California, with venue lying in Santa
+Clara County, California, with the losing party responsible
+for costs, including without limitation, court costs and
+reasonable attorneys fees and expenses. The application of
+the United Nations Convention on Contracts for the
+International Sale of Goods is expressly excluded. Any law
+or regulation which provides that the language of a contract
+shall be construed against the drafter shall not apply to
+this License.
+
+EXHIBIT A - Sun Standards
+
+"The contents of this file are subject to the Sun Standards
+License Version 1.0 the (the "License";) You may not use
+this file except in compliance with the License. You may
+obtain a copy of the License at
+_______________________________.
+
+ Software distributed under the License is distributed on
+an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either
+express or implied. See the License for the specific
+language governing rights and limitations under the License.
+
+The Original Code is Copyright 1998 by Sun Microsystems, Inc
+
+The Initial Developer of the Original Code is: Sun
+Microsystems, Inc.
+
+Portions created by _____________________________ are
+Copyright ______________________________.
+
+All Rights Reserved.
+
+Contributors: ______________________________________.
+
+EXHIBIT B - Sun Standards
+
+The Standard is defined as the following IETF RFCs:
+
+RFC1831: RPC: Remote Procedure Call Protocol Specification
+Version 2 RFC1832: XDR: External Data REpresentation
+Standard RFC1833: Binding Protocols for ONC RPC Version 2
+RFC2078: Generic Security Service Application Program
+Interface, Version 2 RFC2203: RPCSEC_GSS Protocol
+Specification RFC2695: Authentication Mechanisms for ONC RPC
diff --git a/lib/libc/rpc/Makefile.inc b/lib/libc/rpc/Makefile.inc
new file mode 100644
index 0000000..dceecc7
--- /dev/null
+++ b/lib/libc/rpc/Makefile.inc
@@ -0,0 +1,178 @@
+# @(#)Makefile 5.11 (Berkeley) 9/6/90
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/rpc ${.CURDIR}/.
+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 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+=${.CURDIR}/rpc/Symbol.map
+
+CFLAGS+= -DBROKEN_DES -DPORTMAP -DDES_BUILTIN
+CFLAGS+= -I${.CURDIR}/rpc
+
+CLEANFILES+= crypt_clnt.c crypt_xdr.c crypt.h
+
+RPCDIR= ${DESTDIR}/usr/include/rpcsvc
+RPCGEN= 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/PSD.doc/nfs.rfc.ms b/lib/libc/rpc/PSD.doc/nfs.rfc.ms
new file mode 100644
index 0000000..13d7619
--- /dev/null
+++ b/lib/libc/rpc/PSD.doc/nfs.rfc.ms
@@ -0,0 +1,1374 @@
+.\"
+.\" Must use -- tbl -- with this one
+.\"
+.\" @(#)nfs.rfc.ms 2.2 88/08/05 4.0 RPCSRC
+.\" $FreeBSD$
+.\"
+.de BT
+.if \\n%=1 .tl ''- % -''
+..
+.ND
+.\" prevent excess underlining in nroff
+.if n .fp 2 R
+.OH 'Network File System: Version 2 Protocol Specification''Page %'
+.EH 'Page %''Network File System: Version 2 Protocol Specification'
+.if \n%=1 .bp
+.SH
+\&Network File System: Version 2 Protocol Specification
+.IX NFS "" "" "" PAGE MAJOR
+.IX "Network File System" "" "" "" PAGE MAJOR
+.IX NFS "version-2 protocol specification"
+.IX "Network File System" "version-2 protocol specification"
+.LP
+.NH 0
+\&Status of this Standard
+.LP
+Note: This document specifies a protocol that Sun Microsystems, Inc.,
+and others are using. It specifies it in standard ARPA RFC form.
+.NH 1
+\&Introduction
+.IX NFS introduction
+.LP
+The Sun Network Filesystem (NFS) protocol provides transparent remote
+access to shared filesystems over local area networks. The NFS
+protocol is designed to be machine, operating system, network architecture,
+and transport protocol independent. This independence is
+achieved through the use of Remote Procedure Call (RPC) primitives
+built on top of an External Data Representation (XDR). Implementations
+exist for a variety of machines, from personal computers to
+supercomputers.
+.LP
+The supporting mount protocol allows the server to hand out remote
+access privileges to a restricted set of clients. It performs the
+operating system-specific functions that allow, for example, to
+attach remote directory trees to some local file system.
+.NH 2
+\&Remote Procedure Call
+.IX "Remote Procedure Call"
+.LP
+Sun's remote procedure call specification provides a procedure-
+oriented interface to remote services. Each server supplies a
+program that is a set of procedures. NFS is one such "program".
+The combination of host address, program number, and procedure
+number specifies one remote service procedure. RPC does not depend
+on services provided by specific protocols, so it can be used with
+any underlying transport protocol. See the
+.I "Remote Procedure Calls: Protocol Specification"
+chapter of this manual.
+.NH 2
+\&External Data Representation
+.IX "External Data Representation"
+.LP
+The External Data Representation (XDR) standard provides a common
+way of representing a set of data types over a network.
+The NFS
+Protocol Specification is written using the RPC data description
+language.
+For more information, see the
+.I " External Data Representation Standard: Protocol Specification."
+Sun provides implementations of XDR and
+RPC, but NFS does not require their use. Any software that
+provides equivalent functionality can be used, and if the encoding
+is exactly the same it can interoperate with other implementations
+of NFS.
+.NH 2
+\&Stateless Servers
+.IX "stateless servers"
+.IX servers stateless
+.LP
+The NFS protocol is stateless. That is, a server does not need to
+maintain any extra state information about any of its clients in
+order to function correctly. Stateless servers have a distinct
+advantage over stateful servers in the event of a failure. With
+stateless servers, a client need only retry a request until the
+server responds; it does not even need to know that the server has
+crashed, or the network temporarily went down. The client of a
+stateful server, on the other hand, needs to either detect a server
+crash and rebuild the server's state when it comes back up, or
+cause client operations to fail.
+.LP
+This may not sound like an important issue, but it affects the
+protocol in some unexpected ways. We feel that it is worth a bit
+of extra complexity in the protocol to be able to write very simple
+servers that do not require fancy crash recovery.
+.LP
+On the other hand, NFS deals with objects such as files and
+directories that inherently have state -- what good would a file be
+if it did not keep its contents intact? The goal is to not
+introduce any extra state in the protocol itself. Another way to
+simplify recovery is by making operations "idempotent" whenever
+possible (so that they can potentially be repeated).
+.NH 1
+\&NFS Protocol Definition
+.IX NFS "protocol definition"
+.IX NFS protocol
+.LP
+Servers have been known to change over time, and so can the
+protocol that they use. So RPC provides a version number with each
+RPC request. This RFC describes version two of the NFS protocol.
+Even in the second version, there are various obsolete procedures
+and parameters, which will be removed in later versions. An RFC
+for version three of the NFS protocol is currently under
+preparation.
+.NH 2
+\&File System Model
+.IX filesystem model
+.LP
+NFS assumes a file system that is hierarchical, with directories as
+all but the bottom-level files. Each entry in a directory (file,
+directory, device, etc.) has a string name. Different operating
+systems may have restrictions on the depth of the tree or the names
+used, as well as using different syntax to represent the "pathname",
+which is the concatenation of all the "components" (directory and
+file names) in the name. A "file system" is a tree on a single
+server (usually a single disk or physical partition) with a specified
+"root". Some operating systems provide a "mount" operation to make
+all file systems appear as a single tree, while others maintain a
+"forest" of file systems. Files are unstructured streams of
+uninterpreted bytes. Version 3 of NFS uses a slightly more general
+file system model.
+.LP
+NFS looks up one component of a pathname at a time. It may not be
+obvious why it does not just take the whole pathname, traipse down
+the directories, and return a file handle when it is done. There are
+several good reasons not to do this. First, pathnames need
+separators between the directory components, and different operating
+systems use different separators. We could define a Network Standard
+Pathname Representation, but then every pathname would have to be
+parsed and converted at each end. Other issues are discussed in
+\fINFS Implementation Issues\fP below.
+.LP
+Although files and directories are similar objects in many ways,
+different procedures are used to read directories and files. This
+provides a network standard format for representing directories. The
+same argument as above could have been used to justify a procedure
+that returns only one directory entry per call. The problem is
+efficiency. Directories can contain many entries, and a remote call
+to return each would be just too slow.
+.NH 2
+\&RPC Information
+.IX NFS "RPC information"
+.IP \fIAuthentication\fP
+The NFS service uses
+.I AUTH_UNIX ,
+.I AUTH_DES ,
+or
+.I AUTH_SHORT
+style
+authentication, except in the NULL procedure where
+.I AUTH_NONE
+is also allowed.
+.IP "\fITransport Protocols\fP"
+NFS currently is supported on UDP/IP only.
+.IP "\fIPort Number\fP"
+The NFS protocol currently uses the UDP port number 2049. This is
+not an officially assigned port, so later versions of the protocol
+use the \*QPortmapping\*U facility of RPC.
+.NH 2
+\&Sizes of XDR Structures
+.IX "XDR structure sizes"
+.LP
+These are the sizes, given in decimal bytes, of various XDR
+structures used in the protocol:
+.DS
+/* \fIThe maximum number of bytes of data in a READ or WRITE request\fP */
+const MAXDATA = 8192;
+
+/* \fIThe maximum number of bytes in a pathname argument\fP */
+const MAXPATHLEN = 1024;
+
+/* \fIThe maximum number of bytes in a file name argument\fP */
+const MAXNAMLEN = 255;
+
+/* \fIThe size in bytes of the opaque "cookie" passed by READDIR\fP */
+const COOKIESIZE = 4;
+
+/* \fIThe size in bytes of the opaque file handle\fP */
+const FHSIZE = 32;
+.DE
+.NH 2
+\&Basic Data Types
+.IX "NFS data types"
+.IX NFS "basic data types"
+.LP
+The following XDR definitions are basic structures and types used
+in other structures described further on.
+.KS
+.NH 3
+\&stat
+.IX "NFS data types" stat "" \fIstat\fP
+.DS
+enum stat {
+ NFS_OK = 0,
+ NFSERR_PERM=1,
+ NFSERR_NOENT=2,
+ NFSERR_IO=5,
+ NFSERR_NXIO=6,
+ NFSERR_ACCES=13,
+ NFSERR_EXIST=17,
+ NFSERR_NODEV=19,
+ NFSERR_NOTDIR=20,
+ NFSERR_ISDIR=21,
+ NFSERR_FBIG=27,
+ NFSERR_NOSPC=28,
+ NFSERR_ROFS=30,
+ NFSERR_NAMETOOLONG=63,
+ NFSERR_NOTEMPTY=66,
+ NFSERR_DQUOT=69,
+ NFSERR_STALE=70,
+ NFSERR_WFLUSH=99
+};
+.DE
+.KE
+.LP
+The
+.I stat
+type is returned with every procedure's results. A
+value of
+.I NFS_OK
+indicates that the call completed successfully and
+the results are valid. The other values indicate some kind of
+error occurred on the server side during the servicing of the
+procedure. The error values are derived from UNIX error numbers.
+.IP \fBNFSERR_PERM\fP:
+Not owner. The caller does not have correct ownership
+to perform the requested operation.
+.IP \fBNFSERR_NOENT\fP:
+No such file or directory. The file or directory
+specified does not exist.
+.IP \fBNFSERR_IO\fP:
+Some sort of hard error occurred when the operation was
+in progress. This could be a disk error, for example.
+.IP \fBNFSERR_NXIO\fP:
+No such device or address.
+.IP \fBNFSERR_ACCES\fP:
+Permission denied. The caller does not have the
+correct permission to perform the requested operation.
+.IP \fBNFSERR_EXIST\fP:
+File exists. The file specified already exists.
+.IP \fBNFSERR_NODEV\fP:
+No such device.
+.IP \fBNFSERR_NOTDIR\fP:
+Not a directory. The caller specified a
+non-directory in a directory operation.
+.IP \fBNFSERR_ISDIR\fP:
+Is a directory. The caller specified a directory in
+a non- directory operation.
+.IP \fBNFSERR_FBIG\fP:
+File too large. The operation caused a file to grow
+beyond the server's limit.
+.IP \fBNFSERR_NOSPC\fP:
+No space left on device. The operation caused the
+server's filesystem to reach its limit.
+.IP \fBNFSERR_ROFS\fP:
+Read-only filesystem. Write attempted on a read-only filesystem.
+.IP \fBNFSERR_NAMETOOLONG\fP:
+File name too long. The file name in an operation was too long.
+.IP \fBNFSERR_NOTEMPTY\fP:
+Directory not empty. Attempted to remove a
+directory that was not empty.
+.IP \fBNFSERR_DQUOT\fP:
+Disk quota exceeded. The client's disk quota on the
+server has been exceeded.
+.IP \fBNFSERR_STALE\fP:
+The "fhandle" given in the arguments was invalid.
+That is, the file referred to by that file handle no longer exists,
+or access to it has been revoked.
+.IP \fBNFSERR_WFLUSH\fP:
+The server's write cache used in the
+.I WRITECACHE
+call got flushed to disk.
+.LP
+.KS
+.NH 3
+\&ftype
+.IX "NFS data types" ftype "" \fIftype\fP
+.DS
+enum ftype {
+ NFNON = 0,
+ NFREG = 1,
+ NFDIR = 2,
+ NFBLK = 3,
+ NFCHR = 4,
+ NFLNK = 5
+};
+.DE
+.KE
+The enumeration
+.I ftype
+gives the type of a file. The type
+.I NFNON
+indicates a non-file,
+.I NFREG
+is a regular file,
+.I NFDIR
+is a directory,
+.I NFBLK
+is a block-special device,
+.I NFCHR
+is a character-special device, and
+.I NFLNK
+is a symbolic link.
+.KS
+.NH 3
+\&fhandle
+.IX "NFS data types" fhandle "" \fIfhandle\fP
+.DS
+typedef opaque fhandle[FHSIZE];
+.DE
+.KE
+The
+.I fhandle
+is the file handle passed between the server and the client.
+All file operations are done using file handles to refer to a file or
+directory. The file handle can contain whatever information the server
+needs to distinguish an individual file.
+.KS
+.NH 3
+\&timeval
+.IX "NFS data types" timeval "" \fItimeval\fP
+.DS
+struct timeval {
+ unsigned int seconds;
+ unsigned int useconds;
+};
+.DE
+.KE
+The
+.I timeval
+structure is the number of seconds and microseconds
+since midnight January 1, 1970, Greenwich Mean Time. It is used to
+pass time and date information.
+.KS
+.NH 3
+\&fattr
+.IX "NFS data types" fattr "" \fIfattr\fP
+.DS
+struct fattr {
+ ftype type;
+ unsigned int mode;
+ unsigned int nlink;
+ unsigned int uid;
+ unsigned int gid;
+ unsigned int size;
+ unsigned int blocksize;
+ unsigned int rdev;
+ unsigned int blocks;
+ unsigned int fsid;
+ unsigned int fileid;
+ timeval atime;
+ timeval mtime;
+ timeval ctime;
+};
+.DE
+.KE
+The
+.I fattr
+structure contains the attributes of a file; "type" is the type of
+the file; "nlink" is the number of hard links to the file (the number
+of different names for the same file); "uid" is the user
+identification number of the owner of the file; "gid" is the group
+identification number of the group of the file; "size" is the size in
+bytes of the file; "blocksize" is the size in bytes of a block of the
+file; "rdev" is the device number of the file if it is type
+.I NFCHR
+or
+.I NFBLK ;
+"blocks" is the number of blocks the file takes up on disk; "fsid" is
+the file system identifier for the filesystem containing the file;
+"fileid" is a number that uniquely identifies the file within its
+filesystem; "atime" is the time when the file was last accessed for
+either read or write; "mtime" is the time when the file data was last
+modified (written); and "ctime" is the time when the status of the
+file was last changed. Writing to the file also changes "ctime" if
+the size of the file changes.
+.LP
+"mode" is the access mode encoded as a set of bits. Notice that the
+file type is specified both in the mode bits and in the file type.
+This is really a bug in the protocol and will be fixed in future
+versions. The descriptions given below specify the bit positions
+using octal numbers.
+.TS
+box tab (&) ;
+cfI cfI
+lfL l .
+Bit&Description
+_
+0040000&This is a directory; "type" field should be NFDIR.
+0020000&This is a character special file; "type" field should be NFCHR.
+0060000&This is a block special file; "type" field should be NFBLK.
+0100000&This is a regular file; "type" field should be NFREG.
+0120000&This is a symbolic link file; "type" field should be NFLNK.
+0140000&This is a named socket; "type" field should be NFNON.
+0004000&Set user id on execution.
+0002000&Set group id on execution.
+0001000&Save swapped text even after use.
+0000400&Read permission for owner.
+0000200&Write permission for owner.
+0000100&Execute and search permission for owner.
+0000040&Read permission for group.
+0000020&Write permission for group.
+0000010&Execute and search permission for group.
+0000004&Read permission for others.
+0000002&Write permission for others.
+0000001&Execute and search permission for others.
+.TE
+.KS
+Notes:
+.IP
+The bits are the same as the mode bits returned by the
+.I stat(2)
+system call in the UNIX system. The file type is specified both in
+the mode bits and in the file type. This is fixed in future
+versions.
+.IP
+The "rdev" field in the attributes structure is an operating system
+specific device specifier. It will be removed and generalized in
+the next revision of the protocol.
+.KE
+.LP
+.KS
+.NH 3
+\&sattr
+.IX "NFS data types" sattr "" \fIsattr\fP
+.DS
+struct sattr {
+ unsigned int mode;
+ unsigned int uid;
+ unsigned int gid;
+ unsigned int size;
+ timeval atime;
+ timeval mtime;
+};
+.DE
+.KE
+The
+.I sattr
+structure contains the file attributes which can be set
+from the client. The fields are the same as for
+.I fattr
+above. A "size" of zero means the file should be truncated.
+A value of -1 indicates a field that should be ignored.
+.LP
+.KS
+.NH 3
+\&filename
+.IX "NFS data types" filename "" \fIfilename\fP
+.DS
+typedef string filename<MAXNAMLEN>;
+.DE
+.KE
+The type
+.I filename
+is used for passing file names or pathname components.
+.LP
+.KS
+.NH 3
+\&path
+.IX "NFS data types" path "" \fIpath\fP
+.DS
+typedef string path<MAXPATHLEN>;
+.DE
+.KE
+The type
+.I path
+is a pathname. The server considers it as a string
+with no internal structure, but to the client it is the name of a
+node in a filesystem tree.
+.LP
+.KS
+.NH 3
+\&attrstat
+.IX "NFS data types" attrstat "" \fIattrstat\fP
+.DS
+union attrstat switch (stat status) {
+ case NFS_OK:
+ fattr attributes;
+ default:
+ void;
+};
+.DE
+.KE
+The
+.I attrstat
+structure is a common procedure result. It contains
+a "status" and, if the call succeeded, it also contains the
+attributes of the file on which the operation was done.
+.LP
+.KS
+.NH 3
+\&diropargs
+.IX "NFS data types" diropargs "" \fIdiropargs\fP
+.DS
+struct diropargs {
+ fhandle dir;
+ filename name;
+};
+.DE
+.KE
+The
+.I diropargs
+structure is used in directory operations. The
+"fhandle" "dir" is the directory in which to find the file "name".
+A directory operation is one in which the directory is affected.
+.LP
+.KS
+.NH 3
+\&diropres
+.IX "NFS data types" diropres "" \fIdiropres\fP
+.DS
+union diropres switch (stat status) {
+ case NFS_OK:
+ struct {
+ fhandle file;
+ fattr attributes;
+ } diropok;
+ default:
+ void;
+};
+.DE
+.KE
+The results of a directory operation are returned in a
+.I diropres
+structure. If the call succeeded, a new file handle "file" and the
+"attributes" associated with that file are returned along with the
+"status".
+.NH 2
+\&Server Procedures
+.IX "NFS server procedures" "" "" "" PAGE MAJOR
+.LP
+The protocol definition is given as a set of procedures with
+arguments and results defined using the RPC language. A brief
+description of the function of each procedure should provide enough
+information to allow implementation.
+.LP
+All of the procedures in the NFS protocol are assumed to be
+synchronous. When a procedure returns to the client, the client
+can assume that the operation has completed and any data associated
+with the request is now on stable storage. For example, a client
+.I WRITE
+request may cause the server to update data blocks,
+filesystem information blocks (such as indirect blocks), and file
+attribute information (size and modify times). When the
+.I WRITE
+returns to the client, it can assume that the write is safe, even
+in case of a server crash, and it can discard the data written.
+This is a very important part of the statelessness of the server.
+If the server waited to flush data from remote requests, the client
+would have to save those requests so that it could resend them in
+case of a server crash.
+.ie t .DS
+.el .DS L
+
+.ft I
+/*
+* Remote file service routines
+*/
+.ft CW
+program NFS_PROGRAM {
+ version NFS_VERSION {
+ void NFSPROC_NULL(void) = 0;
+ attrstat NFSPROC_GETATTR(fhandle) = 1;
+ attrstat NFSPROC_SETATTR(sattrargs) = 2;
+ void NFSPROC_ROOT(void) = 3;
+ diropres NFSPROC_LOOKUP(diropargs) = 4;
+ readlinkres NFSPROC_READLINK(fhandle) = 5;
+ readres NFSPROC_READ(readargs) = 6;
+ void NFSPROC_WRITECACHE(void) = 7;
+ attrstat NFSPROC_WRITE(writeargs) = 8;
+ diropres NFSPROC_CREATE(createargs) = 9;
+ stat NFSPROC_REMOVE(diropargs) = 10;
+ stat NFSPROC_RENAME(renameargs) = 11;
+ stat NFSPROC_LINK(linkargs) = 12;
+ stat NFSPROC_SYMLINK(symlinkargs) = 13;
+ diropres NFSPROC_MKDIR(createargs) = 14;
+ stat NFSPROC_RMDIR(diropargs) = 15;
+ readdirres NFSPROC_READDIR(readdirargs) = 16;
+ statfsres NFSPROC_STATFS(fhandle) = 17;
+ } = 2;
+} = 100003;
+.DE
+.KS
+.NH 3
+\&Do Nothing
+.IX "NFS server procedures" NFSPROC_NULL() "" \fINFSPROC_NULL()\fP
+.DS
+void
+NFSPROC_NULL(void) = 0;
+.DE
+.KE
+This procedure does no work. It is made available in all RPC
+services to allow server response testing and timing.
+.KS
+.NH 3
+\&Get File Attributes
+.IX "NFS server procedures" NFSPROC_GETATTR() "" \fINFSPROC_GETATTR()\fP
+.DS
+attrstat
+NFSPROC_GETATTR (fhandle) = 1;
+.DE
+.KE
+If the reply status is
+.I NFS_OK ,
+then the reply attributes contains
+the attributes for the file given by the input fhandle.
+.KS
+.NH 3
+\&Set File Attributes
+.IX "NFS server procedures" NFSPROC_SETATTR() "" \fINFSPROC_SETATTR()\fP
+.DS
+struct sattrargs {
+ fhandle file;
+ sattr attributes;
+ };
+
+attrstat
+NFSPROC_SETATTR (sattrargs) = 2;
+.DE
+.KE
+The "attributes" argument contains fields which are either -1 or
+are the new value for the attributes of "file". If the reply
+status is
+.I NFS_OK ,
+then the reply attributes have the attributes of
+the file after the "SETATTR" operation has completed.
+.LP
+Note: The use of -1 to indicate an unused field in "attributes" is
+changed in the next version of the protocol.
+.KS
+.NH 3
+\&Get Filesystem Root
+.IX "NFS server procedures" NFSPROC_ROOT "" \fINFSPROC_ROOT\fP
+.DS
+void
+NFSPROC_ROOT(void) = 3;
+.DE
+.KE
+Obsolete. This procedure is no longer used because finding the
+root file handle of a filesystem requires moving pathnames between
+client and server. To do this right we would have to define a
+network standard representation of pathnames. Instead, the
+function of looking up the root file handle is done by the
+.I MNTPROC_MNT()
+procedure. (See the
+.I "Mount Protocol Definition"
+later in this chapter for details).
+.KS
+.NH 3
+\&Look Up File Name
+.IX "NFS server procedures" NFSPROC_LOOKUP() "" \fINFSPROC_LOOKUP()\fP
+.DS
+diropres
+NFSPROC_LOOKUP(diropargs) = 4;
+.DE
+.KE
+If the reply "status" is
+.I NFS_OK ,
+then the reply "file" and reply
+"attributes" are the file handle and attributes for the file "name"
+in the directory given by "dir" in the argument.
+.KS
+.NH 3
+\&Read From Symbolic Link
+.IX "NFS server procedures" NFSPROC_READLINK() "" \fINFSPROC_READLINK()\fP
+.DS
+union readlinkres switch (stat status) {
+ case NFS_OK:
+ path data;
+ default:
+ void;
+};
+
+readlinkres
+NFSPROC_READLINK(fhandle) = 5;
+.DE
+.KE
+If "status" has the value
+.I NFS_OK ,
+then the reply "data" is the data in
+the symbolic link given by the file referred to by the fhandle argument.
+.LP
+Note: since NFS always parses pathnames on the client, the
+pathname in a symbolic link may mean something different (or be
+meaningless) on a different client or on the server if a different
+pathname syntax is used.
+.KS
+.NH 3
+\&Read From File
+.IX "NFS server procedures" NFSPROC_READ "" \fINFSPROC_READ\fP
+.DS
+struct readargs {
+ fhandle file;
+ unsigned offset;
+ unsigned count;
+ unsigned totalcount;
+};
+
+union readres switch (stat status) {
+ case NFS_OK:
+ fattr attributes;
+ opaque data<NFS_MAXDATA>;
+ default:
+ void;
+};
+
+readres
+NFSPROC_READ(readargs) = 6;
+.DE
+.KE
+Returns up to "count" bytes of "data" from the file given by
+"file", starting at "offset" bytes from the beginning of the file.
+The first byte of the file is at offset zero. The file attributes
+after the read takes place are returned in "attributes".
+.LP
+Note: The argument "totalcount" is unused, and is removed in the
+next protocol revision.
+.KS
+.NH 3
+\&Write to Cache
+.IX "NFS server procedures" NFSPROC_WRITECACHE() "" \fINFSPROC_WRITECACHE()\fP
+.DS
+void
+NFSPROC_WRITECACHE(void) = 7;
+.DE
+.KE
+To be used in the next protocol revision.
+.KS
+.NH 3
+\&Write to File
+.IX "NFS server procedures" NFSPROC_WRITE() "" \fINFSPROC_WRITE()\fP
+.DS
+struct writeargs {
+ fhandle file;
+ unsigned beginoffset;
+ unsigned offset;
+ unsigned totalcount;
+ opaque data<NFS_MAXDATA>;
+};
+
+attrstat
+NFSPROC_WRITE(writeargs) = 8;
+.DE
+.KE
+Writes "data" beginning "offset" bytes from the beginning of
+"file". The first byte of the file is at offset zero. If the
+reply "status" is NFS_OK, then the reply "attributes" contains the
+attributes of the file after the write has completed. The write
+operation is atomic. Data from this call to
+.I WRITE
+will not be mixed with data from another client's calls.
+.LP
+Note: The arguments "beginoffset" and "totalcount" are ignored and
+are removed in the next protocol revision.
+.KS
+.NH 3
+\&Create File
+.IX "NFS server procedures" NFSPROC_CREATE() "" \fINFSPROC_CREATE()\fP
+.DS
+struct createargs {
+ diropargs where;
+ sattr attributes;
+};
+
+diropres
+NFSPROC_CREATE(createargs) = 9;
+.DE
+.KE
+The file "name" is created in the directory given by "dir". The
+initial attributes of the new file are given by "attributes". A
+reply "status" of NFS_OK indicates that the file was created, and
+reply "file" and reply "attributes" are its file handle and
+attributes. Any other reply "status" means that the operation
+failed and no file was created.
+.LP
+Note: This routine should pass an exclusive create flag, meaning
+"create the file only if it is not already there".
+.KS
+.NH 3
+\&Remove File
+.IX "NFS server procedures" NFSPROC_REMOVE() "" \fINFSPROC_REMOVE()\fP
+.DS
+stat
+NFSPROC_REMOVE(diropargs) = 10;
+.DE
+.KE
+The file "name" is removed from the directory given by "dir". A
+reply of NFS_OK means the directory entry was removed.
+.LP
+Note: possibly non-idempotent operation.
+.KS
+.NH 3
+\&Rename File
+.IX "NFS server procedures" NFSPROC_RENAME() "" \fINFSPROC_RENAME()\fP
+.DS
+struct renameargs {
+ diropargs from;
+ diropargs to;
+};
+
+stat
+NFSPROC_RENAME(renameargs) = 11;
+.DE
+.KE
+The existing file "from.name" in the directory given by "from.dir"
+is renamed to "to.name" in the directory given by "to.dir". If the
+reply is
+.I NFS_OK ,
+the file was renamed. The
+RENAME
+operation is
+atomic on the server; it cannot be interrupted in the middle.
+.LP
+Note: possibly non-idempotent operation.
+.KS
+.NH 3
+\&Create Link to File
+.IX "NFS server procedures" NFSPROC_LINK() "" \fINFSPROC_LINK()\fP
+.DS
+struct linkargs {
+ fhandle from;
+ diropargs to;
+};
+
+stat
+NFSPROC_LINK(linkargs) = 12;
+.DE
+.KE
+Creates the file "to.name" in the directory given by "to.dir",
+which is a hard link to the existing file given by "from". If the
+return value is
+.I NFS_OK ,
+a link was created. Any other return value
+indicates an error, and the link was not created.
+.LP
+A hard link should have the property that changes to either of the
+linked files are reflected in both files. When a hard link is made
+to a file, the attributes for the file should have a value for
+"nlink" that is one greater than the value before the link.
+.LP
+Note: possibly non-idempotent operation.
+.KS
+.NH 3
+\&Create Symbolic Link
+.IX "NFS server procedures" NFSPROC_SYMLINK() "" \fINFSPROC_SYMLINK()\fP
+.DS
+struct symlinkargs {
+ diropargs from;
+ path to;
+ sattr attributes;
+};
+
+stat
+NFSPROC_SYMLINK(symlinkargs) = 13;
+.DE
+.KE
+Creates the file "from.name" with ftype
+.I NFLNK
+in the directory
+given by "from.dir". The new file contains the pathname "to" and
+has initial attributes given by "attributes". If the return value
+is
+.I NFS_OK ,
+a link was created. Any other return value indicates an
+error, and the link was not created.
+.LP
+A symbolic link is a pointer to another file. The name given in
+"to" is not interpreted by the server, only stored in the newly
+created file. When the client references a file that is a symbolic
+link, the contents of the symbolic link are normally transparently
+reinterpreted as a pathname to substitute. A
+.I READLINK
+operation returns the data to the client for interpretation.
+.LP
+Note: On UNIX servers the attributes are never used, since
+symbolic links always have mode 0777.
+.KS
+.NH 3
+\&Create Directory
+.IX "NFS server procedures" NFSPROC_MKDIR() "" \fINFSPROC_MKDIR()\fP
+.DS
+diropres
+NFSPROC_MKDIR (createargs) = 14;
+.DE
+.KE
+The new directory "where.name" is created in the directory given by
+"where.dir". The initial attributes of the new directory are given
+by "attributes". A reply "status" of NFS_OK indicates that the new
+directory was created, and reply "file" and reply "attributes" are
+its file handle and attributes. Any other reply "status" means
+that the operation failed and no directory was created.
+.LP
+Note: possibly non-idempotent operation.
+.KS
+.NH 3
+\&Remove Directory
+.IX "NFS server procedures" NFSPROC_RMDIR() "" \fINFSPROC_RMDIR()\fP
+.DS
+stat
+NFSPROC_RMDIR(diropargs) = 15;
+.DE
+.KE
+The existing empty directory "name" in the directory given by "dir"
+is removed. If the reply is
+.I NFS_OK ,
+the directory was removed.
+.LP
+Note: possibly non-idempotent operation.
+.KS
+.NH 3
+\&Read From Directory
+.IX "NFS server procedures" NFSPROC_READDIR() "" \fINFSPROC_READDIR()\fP
+.DS
+struct readdirargs {
+ fhandle dir;
+ nfscookie cookie;
+ unsigned count;
+};
+
+struct entry {
+ unsigned fileid;
+ filename name;
+ nfscookie cookie;
+ entry *nextentry;
+};
+
+union readdirres switch (stat status) {
+ case NFS_OK:
+ struct {
+ entry *entries;
+ bool eof;
+ } readdirok;
+ default:
+ void;
+};
+
+readdirres
+NFSPROC_READDIR (readdirargs) = 16;
+.DE
+.KE
+Returns a variable number of directory entries, with a total size
+of up to "count" bytes, from the directory given by "dir". If the
+returned value of "status" is
+.I NFS_OK ,
+then it is followed by a
+variable number of "entry"s. Each "entry" contains a "fileid"
+which consists of a unique number to identify the file within a
+filesystem, the "name" of the file, and a "cookie" which is an
+opaque pointer to the next entry in the directory. The cookie is
+used in the next
+.I READDIR
+call to get more entries starting at a
+given point in the directory. The special cookie zero (all bits
+zero) can be used to get the entries starting at the beginning of
+the directory. The "fileid" field should be the same number as the
+"fileid" in the the attributes of the file. (See the
+.I "Basic Data Types"
+section.)
+The "eof" flag has a value of
+.I TRUE
+if there are no more entries in the directory.
+.KS
+.NH 3
+\&Get Filesystem Attributes
+.IX "NFS server procedures" NFSPROC_STATFS() "" \fINFSPROC_STATFS()\fP
+.DS
+union statfsres (stat status) {
+ case NFS_OK:
+ struct {
+ unsigned tsize;
+ unsigned bsize;
+ unsigned blocks;
+ unsigned bfree;
+ unsigned bavail;
+ } info;
+ default:
+ void;
+};
+
+statfsres
+NFSPROC_STATFS(fhandle) = 17;
+.DE
+.KE
+If the reply "status" is
+.I NFS_OK ,
+then the reply "info" gives the
+attributes for the filesystem that contains file referred to by the
+input fhandle. The attribute fields contain the following values:
+.IP tsize:
+The optimum transfer size of the server in bytes. This is
+the number of bytes the server would like to have in the
+data part of READ and WRITE requests.
+.IP bsize:
+The block size in bytes of the filesystem.
+.IP blocks:
+The total number of "bsize" blocks on the filesystem.
+.IP bfree:
+The number of free "bsize" blocks on the filesystem.
+.IP bavail:
+The number of "bsize" blocks available to non-privileged users.
+.LP
+Note: This call does not work well if a filesystem has variable
+size blocks.
+.NH 1
+\&NFS Implementation Issues
+.IX NFS implementation
+.LP
+The NFS protocol is designed to be operating system independent, but
+since this version was designed in a UNIX environment, many
+operations have semantics similar to the operations of the UNIX file
+system. This section discusses some of the implementation-specific
+semantic issues.
+.NH 2
+\&Server/Client Relationship
+.IX NFS "server/client relationship"
+.LP
+The NFS protocol is designed to allow servers to be as simple and
+general as possible. Sometimes the simplicity of the server can be a
+problem, if the client wants to implement complicated filesystem
+semantics.
+.LP
+For example, some operating systems allow removal of open files. A
+process can open a file and, while it is open, remove it from the
+directory. The file can be read and written as long as the process
+keeps it open, even though the file has no name in the filesystem.
+It is impossible for a stateless server to implement these semantics.
+The client can do some tricks such as renaming the file on remove,
+and only removing it on close. We believe that the server provides
+enough functionality to implement most file system semantics on the
+client.
+.LP
+Every NFS client can also potentially be a server, and remote and
+local mounted filesystems can be freely intermixed. This leads to
+some interesting problems when a client travels down the directory
+tree of a remote filesystem and reaches the mount point on the server
+for another remote filesystem. Allowing the server to follow the
+second remote mount would require loop detection, server lookup, and
+user revalidation. Instead, we decided not to let clients cross a
+server's mount point. When a client does a LOOKUP on a directory on
+which the server has mounted a filesystem, the client sees the
+underlying directory instead of the mounted directory. A client can
+do remote mounts that match the server's mount points to maintain the
+server's view.
+.LP
+.NH 2
+\&Pathname Interpretation
+.IX NFS "pathname interpretation"
+.LP
+There are a few complications to the rule that pathnames are always
+parsed on the client. For example, symbolic links could have
+different interpretations on different clients. Another common
+problem for non-UNIX implementations is the special interpretation of
+the pathname ".." to mean the parent of a given directory. The next
+revision of the protocol uses an explicit flag to indicate the parent
+instead.
+.NH 2
+\&Permission Issues
+.IX NFS "permission issues"
+.LP
+The NFS protocol, strictly speaking, does not define the permission
+checking used by servers. However, it is expected that a server
+will do normal operating system permission checking using
+.I AUTH_UNIX
+style authentication as the basis of its protection mechanism. The
+server gets the client's effective "uid", effective "gid", and groups
+on each call and uses them to check permission. There are various
+problems with this method that can been resolved in interesting ways.
+.LP
+Using "uid" and "gid" implies that the client and server share the
+same "uid" list. Every server and client pair must have the same
+mapping from user to "uid" and from group to "gid". Since every
+client can also be a server, this tends to imply that the whole
+network shares the same "uid/gid" space.
+.I AUTH_DES
+(and the next
+revision of the NFS protocol) uses string names instead of numbers,
+but there are still complex problems to be solved.
+.LP
+Another problem arises due to the usually stateful open operation.
+Most operating systems check permission at open time, and then check
+that the file is open on each read and write request. With stateless
+servers, the server has no idea that the file is open and must do
+permission checking on each read and write call. On a local
+filesystem, a user can open a file and then change the permissions so
+that no one is allowed to touch it, but will still be able to write
+to the file because it is open. On a remote filesystem, by contrast,
+the write would fail. To get around this problem, the server's
+permission checking algorithm should allow the owner of a file to
+access it regardless of the permission setting.
+.LP
+A similar problem has to do with paging in from a file over the
+network. The operating system usually checks for execute permission
+before opening a file for demand paging, and then reads blocks from
+the open file. The file may not have read permission, but after it
+is opened it doesn't matter. An NFS server can not tell the
+difference between a normal file read and a demand page-in read. To
+make this work, the server allows reading of files if the "uid" given
+in the call has execute or read permission on the file.
+.LP
+In most operating systems, a particular user (on the user ID zero)
+has access to all files no matter what permission and ownership they
+have. This "super-user" permission may not be allowed on the server,
+since anyone who can become super-user on their workstation could
+gain access to all remote files. The UNIX server by default maps
+user id 0 to -2 before doing its access checking. This works except
+for NFS root filesystems, where super-user access cannot be avoided.
+.NH 2
+\&Setting RPC Parameters
+.IX NFS "setting RPC parameters"
+.LP
+Various file system parameters and options should be set at mount
+time. The mount protocol is described in the appendix below. For
+example, "Soft" mounts as well as "Hard" mounts are usually both
+provided. Soft mounted file systems return errors when RPC
+operations fail (after a given number of optional retransmissions),
+while hard mounted file systems continue to retransmit forever.
+Clients and servers may need to keep caches of recent operations to
+help avoid problems with non-idempotent operations.
+.NH 1
+\&Mount Protocol Definition
+.IX "mount protocol" "" "" "" PAGE MAJOR
+.sp 1
+.NH 2
+\&Introduction
+.IX "mount protocol" introduction
+.LP
+The mount protocol is separate from, but related to, the NFS
+protocol. It provides operating system specific services to get the
+NFS off the ground -- looking up server path names, validating user
+identity, and checking access permissions. Clients use the mount
+protocol to get the first file handle, which allows them entry into a
+remote filesystem.
+.LP
+The mount protocol is kept separate from the NFS protocol to make it
+easy to plug in new access checking and validation methods without
+changing the NFS server protocol.
+.LP
+Notice that the protocol definition implies stateful servers because
+the server maintains a list of client's mount requests. The mount
+list information is not critical for the correct functioning of
+either the client or the server. It is intended for advisory use
+only, for example, to warn possible clients when a server is going
+down.
+.LP
+Version one of the mount protocol is used with version two of the NFS
+protocol. The only connecting point is the
+.I fhandle
+structure, which is the same for both protocols.
+.NH 2
+\&RPC Information
+.IX "mount protocol" "RPC information"
+.IP \fIAuthentication\fP
+The mount service uses
+.I AUTH_UNIX
+and
+.I AUTH_DES
+style authentication only.
+.IP "\fITransport Protocols\fP"
+The mount service is currently supported on UDP/IP only.
+.IP "\fIPort Number\fP"
+Consult the server's portmapper, described in the chapter
+.I "Remote Procedure Calls: Protocol Specification",
+to find the port number on which the mount service is registered.
+.NH 2
+\&Sizes of XDR Structures
+.IX "mount protocol" "XDR structure sizes"
+.LP
+These are the sizes, given in decimal bytes, of various XDR
+structures used in the protocol:
+.DS
+/* \fIThe maximum number of bytes in a pathname argument\fP */
+const MNTPATHLEN = 1024;
+
+/* \fIThe maximum number of bytes in a name argument\fP */
+const MNTNAMLEN = 255;
+
+/* \fIThe size in bytes of the opaque file handle\fP */
+const FHSIZE = 32;
+.DE
+.NH 2
+\&Basic Data Types
+.IX "mount protocol" "basic data types"
+.IX "mount data types"
+.LP
+This section presents the data types used by the mount protocol.
+In many cases they are similar to the types used in NFS.
+.KS
+.NH 3
+\&fhandle
+.IX "mount data types" fhandle "" \fIfhandle\fP
+.DS
+typedef opaque fhandle[FHSIZE];
+.DE
+.KE
+The type
+.I fhandle
+is the file handle that the server passes to the
+client. All file operations are done using file handles to refer
+to a file or directory. The file handle can contain whatever
+information the server needs to distinguish an individual file.
+.LP
+This is the same as the "fhandle" XDR definition in version 2 of
+the NFS protocol; see
+.I "Basic Data Types"
+in the definition of the NFS protocol, above.
+.KS
+.NH 3
+\&fhstatus
+.IX "mount data types" fhstatus "" \fIfhstatus\fP
+.DS
+union fhstatus switch (unsigned status) {
+ case 0:
+ fhandle directory;
+ default:
+ void;
+};
+.DE
+.KE
+The type
+.I fhstatus
+is a union. If a "status" of zero is returned,
+the call completed successfully, and a file handle for the
+"directory" follows. A non-zero status indicates some sort of
+error. In this case the status is a UNIX error number.
+.KS
+.NH 3
+\&dirpath
+.IX "mount data types" dirpath "" \fIdirpath\fP
+.DS
+typedef string dirpath<MNTPATHLEN>;
+.DE
+.KE
+The type
+.I dirpath
+is a server pathname of a directory.
+.KS
+.NH 3
+\&name
+.IX "mount data types" name "" \fIname\fP
+.DS
+typedef string name<MNTNAMLEN>;
+.DE
+.KE
+The type
+.I name
+is an arbitrary string used for various names.
+.NH 2
+\&Server Procedures
+.IX "mount server procedures"
+.LP
+The following sections define the RPC procedures supplied by a
+mount server.
+.ie t .DS
+.el .DS L
+.ft I
+/*
+* Protocol description for the mount program
+*/
+.ft CW
+
+program MOUNTPROG {
+.ft I
+/*
+* Version 1 of the mount protocol used with
+* version 2 of the NFS protocol.
+*/
+.ft CW
+ version MOUNTVERS {
+ void MOUNTPROC_NULL(void) = 0;
+ fhstatus MOUNTPROC_MNT(dirpath) = 1;
+ mountlist MOUNTPROC_DUMP(void) = 2;
+ void MOUNTPROC_UMNT(dirpath) = 3;
+ void MOUNTPROC_UMNTALL(void) = 4;
+ exportlist MOUNTPROC_EXPORT(void) = 5;
+ } = 1;
+} = 100005;
+.DE
+.KS
+.NH 3
+\&Do Nothing
+.IX "mount server procedures" MNTPROC_NULL() "" \fIMNTPROC_NULL()\fP
+.DS
+void
+MNTPROC_NULL(void) = 0;
+.DE
+.KE
+This procedure does no work. It is made available in all RPC
+services to allow server response testing and timing.
+.KS
+.NH 3
+\&Add Mount Entry
+.IX "mount server procedures" MNTPROC_MNT() "" \fIMNTPROC_MNT()\fP
+.DS
+fhstatus
+MNTPROC_MNT(dirpath) = 1;
+.DE
+.KE
+If the reply "status" is 0, then the reply "directory" contains the
+file handle for the directory "dirname". This file handle may be
+used in the NFS protocol. This procedure also adds a new entry to
+the mount list for this client mounting "dirname".
+.KS
+.NH 3
+\&Return Mount Entries
+.IX "mount server procedures" MNTPROC_DUMP() "" \fIMNTPROC_DUMP()\fP
+.DS
+struct *mountlist {
+ name hostname;
+ dirpath directory;
+ mountlist nextentry;
+};
+
+mountlist
+MNTPROC_DUMP(void) = 2;
+.DE
+.KE
+Returns the list of remote mounted filesystems. The "mountlist"
+contains one entry for each "hostname" and "directory" pair.
+.KS
+.NH 3
+\&Remove Mount Entry
+.IX "mount server procedures" MNTPROC_UMNT() "" \fIMNTPROC_UMNT()\fP
+.DS
+void
+MNTPROC_UMNT(dirpath) = 3;
+.DE
+.KE
+Removes the mount list entry for the input "dirpath".
+.KS
+.NH 3
+\&Remove All Mount Entries
+.IX "mount server procedures" MNTPROC_UMNTALL() "" \fIMNTPROC_UMNTALL()\fP
+.DS
+void
+MNTPROC_UMNTALL(void) = 4;
+.DE
+.KE
+Removes all of the mount list entries for this client.
+.KS
+.NH 3
+\&Return Export List
+.IX "mount server procedures" MNTPROC_EXPORT() "" \fIMNTPROC_EXPORT()\fP
+.DS
+struct *groups {
+ name grname;
+ groups grnext;
+};
+
+struct *exportlist {
+ dirpath filesys;
+ groups groups;
+ exportlist next;
+};
+
+exportlist
+MNTPROC_EXPORT(void) = 5;
+.DE
+.KE
+Returns a variable number of export list entries. Each entry
+contains a filesystem name and a list of groups that are allowed to
+import it. The filesystem name is in "filesys", and the group name
+is in the list "groups".
+.LP
+Note: The exportlist should contain
+more information about the status of the filesystem, such as a
+read-only flag.
diff --git a/lib/libc/rpc/PSD.doc/rpc.prog.ms b/lib/libc/rpc/PSD.doc/rpc.prog.ms
new file mode 100644
index 0000000..8b79130
--- /dev/null
+++ b/lib/libc/rpc/PSD.doc/rpc.prog.ms
@@ -0,0 +1,2686 @@
+.\"
+.\" Must use -- tbl and pic -- with this one
+.\"
+.\" @(#)rpc.prog.ms 2.3 88/08/11 4.0 RPCSRC
+.\" $FreeBSD$
+.\"
+.de BT
+.if \\n%=1 .tl ''- % -''
+..
+.nr OF 0
+.ND
+.\" prevent excess underlining in nroff
+.if n .fp 2 R
+.OH 'Remote Procedure Call Programming Guide''Page %'
+.EH 'Page %''Remote Procedure Call Programming Guide'
+.SH
+\&Remote Procedure Call Programming Guide
+.nr OF 1
+.IX "Network Programming" "" "" "" PAGE MAJOR
+.IX "RPC Programming Guide"
+.LP
+This document assumes a working knowledge of network theory. It is
+intended for programmers who wish to write network applications using
+remote procedure calls (explained below), and who want to understand
+the RPC mechanisms usually hidden by the
+.I rpcgen(1)
+protocol compiler.
+.I rpcgen
+is described in detail in the previous chapter, the
+.I "\fBrpcgen\fP \fIProgramming Guide\fP".
+.SH
+Note:
+.I
+.IX rpcgen "" \fIrpcgen\fP
+Before attempting to write a network application, or to convert an
+existing non-network application to run over the network, you may want to
+understand the material in this chapter. However, for most applications,
+you can circumvent the need to cope with the details presented here by using
+.I rpcgen .
+The
+.I "Generating XDR Routines"
+section of that chapter contains the complete source for a working RPC
+service\(ema remote directory listing service which uses
+.I rpcgen
+to generate XDR routines as well as client and server stubs.
+.LP
+.LP
+What are remote procedure calls? Simply put, they are the high-level
+communications paradigm used in the operating system.
+RPC presumes the existence of
+low-level networking mechanisms (such as TCP/IP and UDP/IP), and upon them
+it implements a logical client to server communications system designed
+specifically for the support of network applications. With RPC, the client
+makes a procedure call to send a data packet to the server. When the
+packet arrives, the server calls a dispatch routine, performs whatever
+service is requested, sends back the reply, and the procedure call returns
+to the client.
+.NH 0
+\&Layers of RPC
+.IX "layers of RPC"
+.IX "RPC" "layers"
+.LP
+The RPC interface can be seen as being divided into three layers.\**
+.FS
+For a complete specification of the routines in the remote procedure
+call Library, see the
+.I rpc(3N)
+manual page.
+.FE
+.LP
+.I "The Highest Layer:"
+.IX RPC "The Highest Layer"
+The highest layer is totally transparent to the operating system,
+machine and network upon which is is run. It's probably best to
+think of this level as a way of
+.I using
+RPC, rather than as
+a \fIpart of\fP RPC proper. Programmers who write RPC routines
+should (almost) always make this layer available to others by way
+of a simple C front end that entirely hides the networking.
+.LP
+To illustrate, at this level a program can simply make a call to
+.I rnusers (),
+a C routine which returns the number of users on a remote machine.
+The user is not explicitly aware of using RPC \(em they simply
+call a procedure, just as they would call
+.I malloc() .
+.LP
+.I "The Middle Layer:"
+.IX RPC "The Middle Layer"
+The middle layer is really \*QRPC proper.\*U Here, the user doesn't
+need to consider details about sockets, the UNIX system, or other low-level
+implementation mechanisms. They simply make remote procedure calls
+to routines on other machines. The selling point here is simplicity.
+It's this layer that allows RPC to pass the \*Qhello world\*U test \(em
+simple things should be simple. The middle-layer routines are used
+for most applications.
+.LP
+RPC calls are made with the system routines
+.I registerrpc()
+.I callrpc()
+and
+.I svc_run ().
+The first two of these are the most fundamental:
+.I registerrpc()
+obtains a unique system-wide procedure-identification number, and
+.I callrpc()
+actually executes a remote procedure call. At the middle level, a
+call to
+.I rnusers()
+is implemented by way of these two routines.
+.LP
+The middle layer is unfortunately rarely used in serious programming
+due to its inflexibility (simplicity). It does not allow timeout
+specifications or the choice of transport. It allows no UNIX
+process control or flexibility in case of errors. It doesn't support
+multiple kinds of call authentication. The programmer rarely needs
+all these kinds of control, but one or two of them is often necessary.
+.LP
+.I "The Lowest Layer:"
+.IX RPC "The Lowest Layer"
+The lowest layer does allow these details to be controlled by the
+programmer, and for that reason it is often necessary. Programs
+written at this level are also most efficient, but this is rarely a
+real issue \(em since RPC clients and servers rarely generate
+heavy network loads.
+.LP
+Although this document only discusses the interface to C,
+remote procedure calls can be made from any language.
+Even though this document discusses RPC
+when it is used to communicate
+between processes on different machines,
+it works just as well for communication
+between different processes on the same machine.
+.br
+.KS
+.NH 2
+\&The RPC Paradigm
+.IX RPC paradigm
+.LP
+Here is a diagram of the RPC paradigm:
+.LP
+\fBFigure 1-1\fI Network Communication with the Remote Reocedure Call\fR
+.LP
+.PS
+L1: arrow down 1i "client " rjust "program " rjust
+L2: line right 1.5i "\fIcallrpc\fP" "function"
+move up 1.5i; line dotted down 6i; move up 4.5i
+arrow right 1i
+L3: arrow down 1i "invoke " rjust "service " rjust
+L4: arrow right 1.5i "call" "service"
+L5: arrow down 1i " service" ljust " executes" ljust
+L6: arrow left 1.5i "\fIreturn\fP" "answer"
+L7: arrow down 1i "request " rjust "completed " rjust
+L8: line left 1i
+arrow left 1.5i "\fIreturn\fP" "reply"
+L9: arrow down 1i "program " rjust "continues " rjust
+line dashed down from L2 to L9
+line dashed down from L4 to L7
+line dashed up 1i from L3 "service " rjust "daemon " rjust
+arrow dashed down 1i from L8
+move right 1i from L3
+box invis "Machine B"
+move left 1.2i from L2; move down
+box invis "Machine A"
+.PE
+.KE
+.KS
+.NH 1
+\&Higher Layers of RPC
+.NH 2
+\&Highest Layer
+.IX "highest layer of RPC"
+.IX RPC "highest layer"
+.LP
+Imagine you're writing a program that needs to know
+how many users are logged into a remote machine.
+You can do this by calling the RPC library routine
+.I rnusers()
+as illustrated below:
+.ie t .DS
+.el .DS L
+.ft CW
+#include <stdio.h>
+
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int num;
+
+ if (argc != 2) {
+ fprintf(stderr, "usage: rnusers hostname\en");
+ exit(1);
+ }
+ if ((num = rnusers(argv[1])) < 0) {
+ fprintf(stderr, "error: rnusers\en");
+ exit(-1);
+ }
+ printf("%d users on %s\en", num, argv[1]);
+ exit(0);
+}
+.DE
+.KE
+RPC library routines such as
+.I rnusers()
+are in the RPC services library
+.I librpcsvc.a
+Thus, the program above should be compiled with
+.DS
+.ft CW
+% cc \fIprogram.c -lrpcsvc\fP
+.DE
+.I rnusers (),
+like the other RPC library routines, is documented in section 3R
+of the
+.I "System Interface Manual for the Sun Workstation" ,
+the same section which documents the standard Sun RPC services.
+.IX "RPC Services"
+See the
+.I intro(3R)
+manual page for an explanation of the documentation strategy
+for these services and their RPC protocols.
+.LP
+Here are some of the RPC service library routines available to the
+C programmer:
+.LP
+\fBTable 3-3\fI RPC Service Library Routines\fR
+.TS
+box tab (&) ;
+cfI cfI
+lfL l .
+Routine&Description
+_
+.sp .5
+rnusers&Return number of users on remote machine
+rusers&Return information about users on remote machine
+havedisk&Determine if remote machine has disk
+rstats&Get performance data from remote kernel
+rwall&Write to specified remote machines
+yppasswd&Update user password in Yellow Pages
+.TE
+.LP
+Other RPC services \(em for example
+.I ether()
+.I mount
+.I rquota()
+and
+.I spray
+\(em are not available to the C programmer as library routines.
+They do, however,
+have RPC program numbers so they can be invoked with
+.I callrpc()
+which will be discussed in the next section. Most of them also
+have compilable
+.I rpcgen(1)
+protocol description files. (The
+.I rpcgen
+protocol compiler radically simplifies the process of developing
+network applications.
+See the \fBrpcgen\fI Programming Guide\fR
+for detailed information about
+.I rpcgen
+and
+.I rpcgen
+protocol description files).
+.KS
+.NH 2
+\&Intermediate Layer
+.IX "intermediate layer of RPC"
+.IX "RPC" "intermediate layer"
+.LP
+The simplest interface, which explicitly makes RPC calls, uses the
+functions
+.I callrpc()
+and
+.I registerrpc()
+Using this method, the number of remote users can be gotten as follows:
+.ie t .DS
+.el .DS L
+#include <stdio.h>
+#include <rpc/rpc.h>
+#include <utmp.h>
+#include <rpcsvc/rusers.h>
+
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ unsigned long nusers;
+ int stat;
+
+ if (argc != 2) {
+ fprintf(stderr, "usage: nusers hostname\en");
+ exit(-1);
+ }
+ if (stat = callrpc(argv[1],
+ RUSERSPROG, RUSERSVERS, RUSERSPROC_NUM,
+ xdr_void, 0, xdr_u_long, &nusers) != 0) {
+ clnt_perrno(stat);
+ exit(1);
+ }
+ printf("%d users on %s\en", nusers, argv[1]);
+ exit(0);
+}
+.DE
+.KE
+Each RPC procedure is uniquely defined by a program number,
+version number, and procedure number. The program number
+specifies a group of related remote procedures, each of
+which has a different procedure number. Each program also
+has a version number, so when a minor change is made to a
+remote service (adding a new procedure, for example), a new
+program number doesn't have to be assigned. When you want
+to call a procedure to find the number of remote users, you
+look up the appropriate program, version and procedure numbers
+in a manual, just as you look up the name of a memory allocator
+when you want to allocate memory.
+.LP
+The simplest way of making remote procedure calls is with the the RPC
+library routine
+.I callrpc()
+It has eight parameters. The first is the name of the remote server
+machine. The next three parameters are the program, version, and procedure
+numbers\(emtogether they identify the procedure to be called.
+The fifth and sixth parameters are an XDR filter and an argument to
+be encoded and passed to the remote procedure.
+The final two parameters are a filter for decoding the results
+returned by the remote procedure and a pointer to the place where
+the procedure's results are to be stored. Multiple arguments and
+results are handled by embedding them in structures. If
+.I callrpc()
+completes successfully, it returns zero; else it returns a nonzero
+value. The return codes (of type
+.IX "enum clnt_stat (in RPC programming)" "" "\fIenum clnt_stat\fP (in RPC programming)"
+cast into an integer) are found in
+.I <rpc/clnt.h> .
+.LP
+Since data types may be represented differently on different machines,
+.I callrpc()
+needs both the type of the RPC argument, as well as
+a pointer to the argument itself (and similarly for the result). For
+.I RUSERSPROC_NUM ,
+the return value is an
+.I "unsigned long"
+so
+.I callrpc()
+has
+.I xdr_u_long()
+as its first return parameter, which says
+that the result is of type
+.I "unsigned long"
+and
+.I &nusers
+as its second return parameter,
+which is a pointer to where the long result will be placed. Since
+.I RUSERSPROC_NUM
+takes no argument, the argument parameter of
+.I callrpc()
+is
+.I xdr_void ().
+.LP
+After trying several times to deliver a message, if
+.I callrpc()
+gets no answer, it returns with an error code.
+The delivery mechanism is UDP,
+which stands for User Datagram Protocol.
+Methods for adjusting the number of retries
+or for using a different protocol require you to use the lower
+layer of the RPC library, discussed later in this document.
+The remote server procedure
+corresponding to the above might look like this:
+.ie t .DS
+.el .DS L
+.ft CW
+.ft CW
+char *
+nuser(indata)
+ char *indata;
+{
+ unsigned long nusers;
+
+.ft I
+ /*
+ * Code here to compute the number of users
+ * and place result in variable \fInusers\fP.
+ */
+.ft CW
+ return((char *)&nusers);
+}
+.DE
+.LP
+It takes one argument, which is a pointer to the input
+of the remote procedure call (ignored in our example),
+and it returns a pointer to the result.
+In the current version of C,
+character pointers are the generic pointers,
+so both the input argument and the return value are cast to
+.I "char *" .
+.LP
+Normally, a server registers all of the RPC calls it plans
+to handle, and then goes into an infinite loop waiting to service requests.
+In this example, there is only a single procedure
+to register, so the main body of the server would look like this:
+.ie t .DS
+.el .DS L
+.ft CW
+#include <stdio.h>
+#include <rpc/rpc.h>
+#include <utmp.h>
+#include <rpcsvc/rusers.h>
+
+char *nuser();
+
+main()
+{
+ registerrpc(RUSERSPROG, RUSERSVERS, RUSERSPROC_NUM,
+ nuser, xdr_void, xdr_u_long);
+ svc_run(); /* \fINever returns\fP */
+ fprintf(stderr, "Error: svc_run returned!\en");
+ exit(1);
+}
+.DE
+.LP
+The
+.I registerrpc()
+routine registers a C procedure as corresponding to a
+given RPC procedure number. The first three parameters,
+.I RUSERPROG ,
+.I RUSERSVERS ,
+and
+.I RUSERSPROC_NUM
+are the program, version, and procedure numbers
+of the remote procedure to be registered;
+.I nuser()
+is the name of the local procedure that implements the remote
+procedure; and
+.I xdr_void()
+and
+.I xdr_u_long()
+are the XDR filters for the remote procedure's arguments and
+results, respectively. (Multiple arguments or multiple results
+are passed as structures).
+.LP
+Only the UDP transport mechanism can use
+.I registerrpc()
+thus, it is always safe in conjunction with calls generated by
+.I callrpc() .
+.SH
+.IX "UDP 8K warning"
+Warning: the UDP transport mechanism can only deal with
+arguments and results less than 8K bytes in length.
+.LP
+.LP
+After registering the local procedure, the server program's
+main procedure calls
+.I svc_run (),
+the RPC library's remote procedure dispatcher. It is this
+function that calls the remote procedures in response to RPC
+call messages. Note that the dispatcher takes care of decoding
+remote procedure arguments and encoding results, using the XDR
+filters specified when the remote procedure was registered.
+.NH 2
+\&Assigning Program Numbers
+.IX "program number assignment"
+.IX "assigning program numbers"
+.LP
+Program numbers are assigned in groups of
+.I 0x20000000
+according to the following chart:
+.DS
+.ft CW
+ 0x0 - 0x1fffffff \fRDefined by Sun\fP
+0x20000000 - 0x3fffffff \fRDefined by user\fP
+0x40000000 - 0x5fffffff \fRTransient\fP
+0x60000000 - 0x7fffffff \fRReserved\fP
+0x80000000 - 0x9fffffff \fRReserved\fP
+0xa0000000 - 0xbfffffff \fRReserved\fP
+0xc0000000 - 0xdfffffff \fRReserved\fP
+0xe0000000 - 0xffffffff \fRReserved\fP
+.ft R
+.DE
+Sun Microsystems administers the first group of numbers, which
+should be identical for all Sun customers. If a customer
+develops an application that might be of general interest, that
+application should be given an assigned number in the first
+range. The second group of numbers is reserved for specific
+customer applications. This range is intended primarily for
+debugging new programs. The third group is reserved for
+applications that generate program numbers dynamically. The
+final groups are reserved for future use, and should not be
+used.
+.LP
+To register a protocol specification, send a request by network
+mail to
+.I rpc@sun
+or write to:
+.DS
+RPC Administrator
+Sun Microsystems
+2550 Garcia Ave.
+Mountain View, CA 94043
+.DE
+Please include a compilable
+.I rpcgen
+\*Q.x\*U file describing your protocol.
+You will be given a unique program number in return.
+.IX RPC administration
+.IX administration "of RPC"
+.LP
+The RPC program numbers and protocol specifications
+of standard Sun RPC services can be
+found in the include files in
+.I "/usr/include/rpcsvc" .
+These services, however, constitute only a small subset
+of those which have been registered. The complete list of
+registered programs, as of the time when this manual was
+printed, is:
+.LP
+\fBTable 3-2\fI RPC Registered Programs\fR
+.TS H
+box tab (&) ;
+lfBI lfBI lfBI
+lfL lfL lfI .
+RPC Number&Program&Description
+_
+.TH
+.sp .5
+100000&PMAPPROG&portmapper
+100001&RSTATPROG&remote stats
+100002&RUSERSPROG&remote users
+100003&NFSPROG&nfs
+100004&YPPROG&Yellow Pages
+100005&MOUNTPROG&mount daemon
+100006&DBXPROG&remote dbx
+100007&YPBINDPROG&yp binder
+100008&WALLPROG&shutdown msg
+100009&YPPASSWDPROG&yppasswd server
+100010&ETHERSTATPROG&ether stats
+100011&RQUOTAPROG&disk quotas
+100012&SPRAYPROG&spray packets
+100013&IBM3270PROG&3270 mapper
+100014&IBMRJEPROG&RJE mapper
+100015&SELNSVCPROG&selection service
+100016&RDATABASEPROG&remote database access
+100017&REXECPROG&remote execution
+100018&ALICEPROG&Alice Office Automation
+100019&SCHEDPROG&scheduling service
+100020&LOCKPROG&local lock manager
+100021&NETLOCKPROG&network lock manager
+100022&X25PROG&x.25 inr protocol
+100023&STATMON1PROG&status monitor 1
+100024&STATMON2PROG&status monitor 2
+100025&SELNLIBPROG&selection library
+100026&BOOTPARAMPROG&boot parameters service
+100027&MAZEPROG&mazewars game
+100028&YPUPDATEPROG&yp update
+100029&KEYSERVEPROG&key server
+100030&SECURECMDPROG&secure login
+100031&NETFWDIPROG&nfs net forwarder init
+100032&NETFWDTPROG&nfs net forwarder trans
+100033&SUNLINKMAP_PROG&sunlink MAP
+100034&NETMONPROG&network monitor
+100035&DBASEPROG&lightweight database
+100036&PWDAUTHPROG&password authorization
+100037&TFSPROG&translucent file svc
+100038&NSEPROG&nse server
+100039&NSE_ACTIVATE_PROG&nse activate daemon
+.sp .2i
+150001&PCNFSDPROG&pc passwd authorization
+.sp .2i
+200000&PYRAMIDLOCKINGPROG&Pyramid-locking
+200001&PYRAMIDSYS5&Pyramid-sys5
+200002&CADDS_IMAGE&CV cadds_image
+.sp .2i
+300001&ADT_RFLOCKPROG&ADT file locking
+.TE
+.NH 2
+\&Passing Arbitrary Data Types
+.IX "arbitrary data types"
+.LP
+In the previous example, the RPC call passes a single
+.I "unsigned long"
+RPC can handle arbitrary data structures, regardless of
+different machines' byte orders or structure layout conventions,
+by always converting them to a network standard called
+.I "External Data Representation"
+(XDR) before
+sending them over the wire.
+The process of converting from a particular machine representation
+to XDR format is called
+.I serializing ,
+and the reverse process is called
+.I deserializing .
+The type field parameters of
+.I callrpc()
+and
+.I registerrpc()
+can be a built-in procedure like
+.I xdr_u_long()
+in the previous example, or a user supplied one.
+XDR has these built-in type routines:
+.IX RPC "built-in routines"
+.DS
+.ft CW
+xdr_int() xdr_u_int() xdr_enum()
+xdr_long() xdr_u_long() xdr_bool()
+xdr_short() xdr_u_short() xdr_wrapstring()
+xdr_char() xdr_u_char()
+.DE
+Note that the routine
+.I xdr_string()
+exists, but cannot be used with
+.I callrpc()
+and
+.I registerrpc (),
+which only pass two parameters to their XDR routines.
+.I xdr_wrapstring()
+has only two parameters, and is thus OK. It calls
+.I xdr_string ().
+.LP
+As an example of a user-defined type routine,
+if you wanted to send the structure
+.DS
+.ft CW
+struct simple {
+ int a;
+ short b;
+} simple;
+.DE
+then you would call
+.I callrpc()
+as
+.DS
+.ft CW
+callrpc(hostname, PROGNUM, VERSNUM, PROCNUM,
+ xdr_simple, &simple ...);
+.DE
+where
+.I xdr_simple()
+is written as:
+.ie t .DS
+.el .DS L
+.ft CW
+#include <rpc/rpc.h>
+
+xdr_simple(xdrsp, simplep)
+ XDR *xdrsp;
+ struct simple *simplep;
+{
+ if (!xdr_int(xdrsp, &simplep->a))
+ return (0);
+ if (!xdr_short(xdrsp, &simplep->b))
+ return (0);
+ return (1);
+}
+.DE
+.LP
+An XDR routine returns nonzero (true in the sense of C) if it
+completes successfully, and zero otherwise.
+A complete description of XDR is in the
+.I "XDR Protocol Specification"
+section of this manual, only few implementation examples are
+given here.
+.LP
+In addition to the built-in primitives,
+there are also the prefabricated building blocks:
+.DS
+.ft CW
+xdr_array() xdr_bytes() xdr_reference()
+xdr_vector() xdr_union() xdr_pointer()
+xdr_string() xdr_opaque()
+.DE
+To send a variable array of integers,
+you might package them up as a structure like this
+.DS
+.ft CW
+struct varintarr {
+ int *data;
+ int arrlnth;
+} arr;
+.DE
+and make an RPC call such as
+.DS
+.ft CW
+callrpc(hostname, PROGNUM, VERSNUM, PROCNUM,
+ xdr_varintarr, &arr...);
+.DE
+with
+.I xdr_varintarr()
+defined as:
+.ie t .DS
+.el .DS L
+.ft CW
+xdr_varintarr(xdrsp, arrp)
+ XDR *xdrsp;
+ struct varintarr *arrp;
+{
+ return (xdr_array(xdrsp, &arrp->data, &arrp->arrlnth,
+ MAXLEN, sizeof(int), xdr_int));
+}
+.DE
+This routine takes as parameters the XDR handle,
+a pointer to the array, a pointer to the size of the array,
+the maximum allowable array size,
+the size of each array element,
+and an XDR routine for handling each array element.
+.KS
+.LP
+If the size of the array is known in advance, one can use
+.I xdr_vector (),
+which serializes fixed-length arrays.
+.ie t .DS
+.el .DS L
+.ft CW
+int intarr[SIZE];
+
+xdr_intarr(xdrsp, intarr)
+ XDR *xdrsp;
+ int intarr[];
+{
+ int i;
+
+ return (xdr_vector(xdrsp, intarr, SIZE, sizeof(int),
+ xdr_int));
+}
+.DE
+.KE
+.LP
+XDR always converts quantities to 4-byte multiples when serializing.
+Thus, if either of the examples above involved characters
+instead of integers, each character would occupy 32 bits.
+That is the reason for the XDR routine
+.I xdr_bytes()
+which is like
+.I xdr_array()
+except that it packs characters;
+.I xdr_bytes()
+has four parameters, similar to the first four parameters of
+.I xdr_array ().
+For null-terminated strings, there is also the
+.I xdr_string()
+routine, which is the same as
+.I xdr_bytes()
+without the length parameter.
+On serializing it gets the string length from
+.I strlen (),
+and on deserializing it creates a null-terminated string.
+.LP
+Here is a final example that calls the previously written
+.I xdr_simple()
+as well as the built-in functions
+.I xdr_string()
+and
+.I xdr_reference (),
+which chases pointers:
+.ie t .DS
+.el .DS L
+.ft CW
+struct finalexample {
+ char *string;
+ struct simple *simplep;
+} finalexample;
+
+xdr_finalexample(xdrsp, finalp)
+ XDR *xdrsp;
+ struct finalexample *finalp;
+{
+
+ if (!xdr_string(xdrsp, &finalp->string, MAXSTRLEN))
+ return (0);
+ if (!xdr_reference(xdrsp, &finalp->simplep,
+ sizeof(struct simple), xdr_simple);
+ return (0);
+ return (1);
+}
+.DE
+Note that we could as easily call
+.I xdr_simple()
+here instead of
+.I xdr_reference ().
+.NH 1
+\&Lowest Layer of RPC
+.IX "lowest layer of RPC"
+.IX "RPC" "lowest layer"
+.LP
+In the examples given so far,
+RPC takes care of many details automatically for you.
+In this section, we'll show you how you can change the defaults
+by using lower layers of the RPC library.
+It is assumed that you are familiar with sockets
+and the system calls for dealing with them.
+.LP
+There are several occasions when you may need to use lower layers of
+RPC. First, you may need to use TCP, since the higher layer uses UDP,
+which restricts RPC calls to 8K bytes of data. Using TCP permits calls
+to send long streams of data.
+For an example, see the
+.I TCP
+section below. Second, you may want to allocate and free memory
+while serializing or deserializing with XDR routines.
+There is no call at the higher level to let
+you free memory explicitly.
+For more explanation, see the
+.I "Memory Allocation with XDR"
+section below.
+Third, you may need to perform authentication
+on either the client or server side, by supplying
+credentials or verifying them.
+See the explanation in the
+.I Authentication
+section below.
+.NH 2
+\&More on the Server Side
+.IX RPC "server side"
+.LP
+The server for the
+.I nusers()
+program shown below does the same thing as the one using
+.I registerrpc()
+above, but is written using a lower layer of the RPC package:
+.ie t .DS
+.el .DS L
+.ft CW
+#include <stdio.h>
+#include <rpc/rpc.h>
+#include <utmp.h>
+#include <rpcsvc/rusers.h>
+
+main()
+{
+ SVCXPRT *transp;
+ int nuser();
+
+ transp = svcudp_create(RPC_ANYSOCK);
+ if (transp == NULL){
+ fprintf(stderr, "can't create an RPC server\en");
+ exit(1);
+ }
+ pmap_unset(RUSERSPROG, RUSERSVERS);
+ if (!svc_register(transp, RUSERSPROG, RUSERSVERS,
+ nuser, IPPROTO_UDP)) {
+ fprintf(stderr, "can't register RUSER service\en");
+ exit(1);
+ }
+ svc_run(); /* \fINever returns\fP */
+ fprintf(stderr, "should never reach this point\en");
+}
+
+nuser(rqstp, transp)
+ struct svc_req *rqstp;
+ SVCXPRT *transp;
+{
+ unsigned long nusers;
+
+ switch (rqstp->rq_proc) {
+ case NULLPROC:
+ if (!svc_sendreply(transp, xdr_void, 0))
+ fprintf(stderr, "can't reply to RPC call\en");
+ return;
+ case RUSERSPROC_NUM:
+.ft I
+ /*
+ * Code here to compute the number of users
+ * and assign it to the variable \fInusers\fP
+ */
+.ft CW
+ if (!svc_sendreply(transp, xdr_u_long, &nusers))
+ fprintf(stderr, "can't reply to RPC call\en");
+ return;
+ default:
+ svcerr_noproc(transp);
+ return;
+ }
+}
+.DE
+.LP
+First, the server gets a transport handle, which is used
+for receiving and replying to RPC messages.
+.I registerrpc()
+uses
+.I svcudp_create()
+to get a UDP handle.
+If you require a more reliable protocol, call
+.I svctcp_create()
+instead.
+If the argument to
+.I svcudp_create()
+is
+.I RPC_ANYSOCK
+the RPC library creates a socket
+on which to receive and reply to RPC calls. Otherwise,
+.I svcudp_create()
+expects its argument to be a valid socket number.
+If you specify your own socket, it can be bound or unbound.
+If it is bound to a port by the user, the port numbers of
+.I svcudp_create()
+and
+.I clnttcp_create()
+(the low-level client routine) must match.
+.LP
+If the user specifies the
+.I RPC_ANYSOCK
+argument, the RPC library routines will open sockets.
+Otherwise they will expect the user to do so. The routines
+.I svcudp_create()
+and
+.I clntudp_create()
+will cause the RPC library routines to
+.I bind()
+their socket if it is not bound already.
+.LP
+A service may choose to register its port number with the
+local portmapper service. This is done is done by specifying
+a non-zero protocol number in
+.I svc_register ().
+Incidently, a client can discover the server's port number by
+consulting the portmapper on their server's machine. This can
+be done automatically by specifying a zero port number in
+.I clntudp_create()
+or
+.I clnttcp_create ().
+.LP
+After creating an
+.I SVCXPRT ,
+the next step is to call
+.I pmap_unset()
+so that if the
+.I nusers()
+server crashed earlier,
+any previous trace of it is erased before restarting.
+More precisely,
+.I pmap_unset()
+erases the entry for
+.I RUSERSPROG
+from the port mapper's tables.
+.LP
+Finally, we associate the program number for
+.I nusers()
+with the procedure
+.I nuser ().
+The final argument to
+.I svc_register()
+is normally the protocol being used,
+which, in this case, is
+.I IPPROTO_UDP
+Notice that unlike
+.I registerrpc (),
+there are no XDR routines involved
+in the registration process.
+Also, registration is done on the program,
+rather than procedure, level.
+.LP
+The user routine
+.I nuser()
+must call and dispatch the appropriate XDR routines
+based on the procedure number.
+Note that
+two things are handled by
+.I nuser()
+that
+.I registerrpc()
+handles automatically.
+The first is that procedure
+.I NULLPROC
+(currently zero) returns with no results.
+This can be used as a simple test
+for detecting if a remote program is running.
+Second, there is a check for invalid procedure numbers.
+If one is detected,
+.I svcerr_noproc()
+is called to handle the error.
+.KS
+.LP
+The user service routine serializes the results and returns
+them to the RPC caller via
+.I svc_sendreply()
+Its first parameter is the
+.I SVCXPRT
+handle, the second is the XDR routine,
+and the third is a pointer to the data to be returned.
+Not illustrated above is how a server
+handles an RPC program that receives data.
+As an example, we can add a procedure
+.I RUSERSPROC_BOOL
+which has an argument
+.I nusers (),
+and returns
+.I TRUE
+or
+.I FALSE
+depending on whether there are nusers logged on.
+It would look like this:
+.ie t .DS
+.el .DS L
+.ft CW
+case RUSERSPROC_BOOL: {
+ int bool;
+ unsigned nuserquery;
+
+ if (!svc_getargs(transp, xdr_u_int, &nuserquery) {
+ svcerr_decode(transp);
+ return;
+ }
+.ft I
+ /*
+ * Code to set \fInusers\fP = number of users
+ */
+.ft CW
+ if (nuserquery == nusers)
+ bool = TRUE;
+ else
+ bool = FALSE;
+ if (!svc_sendreply(transp, xdr_bool, &bool)) {
+ fprintf(stderr, "can't reply to RPC call\en");
+ return (1);
+ }
+ return;
+}
+.DE
+.KE
+.LP
+The relevant routine is
+.I svc_getargs()
+which takes an
+.I SVCXPRT
+handle, the XDR routine,
+and a pointer to where the input is to be placed as arguments.
+.NH 2
+\&Memory Allocation with XDR
+.IX "memory allocation with XDR"
+.IX XDR "memory allocation"
+.LP
+XDR routines not only do input and output,
+they also do memory allocation.
+This is why the second parameter of
+.I xdr_array()
+is a pointer to an array, rather than the array itself.
+If it is
+.I NULL ,
+then
+.I xdr_array()
+allocates space for the array and returns a pointer to it,
+putting the size of the array in the third argument.
+As an example, consider the following XDR routine
+.I xdr_chararr1()
+which deals with a fixed array of bytes with length
+.I SIZE .
+.ie t .DS
+.el .DS L
+.ft CW
+xdr_chararr1(xdrsp, chararr)
+ XDR *xdrsp;
+ char chararr[];
+{
+ char *p;
+ int len;
+
+ p = chararr;
+ len = SIZE;
+ return (xdr_bytes(xdrsp, &p, &len, SIZE));
+}
+.DE
+If space has already been allocated in
+.I chararr ,
+it can be called from a server like this:
+.ie t .DS
+.el .DS L
+.ft CW
+char chararr[SIZE];
+
+svc_getargs(transp, xdr_chararr1, chararr);
+.DE
+If you want XDR to do the allocation,
+you would have to rewrite this routine in the following way:
+.ie t .DS
+.el .DS L
+.ft CW
+xdr_chararr2(xdrsp, chararrp)
+ XDR *xdrsp;
+ char **chararrp;
+{
+ int len;
+
+ len = SIZE;
+ return (xdr_bytes(xdrsp, charrarrp, &len, SIZE));
+}
+.DE
+Then the RPC call might look like this:
+.ie t .DS
+.el .DS L
+.ft CW
+char *arrptr;
+
+arrptr = NULL;
+svc_getargs(transp, xdr_chararr2, &arrptr);
+.ft I
+/*
+ * Use the result here
+ */
+.ft CW
+svc_freeargs(transp, xdr_chararr2, &arrptr);
+.DE
+Note that, after being used, the character array can be freed with
+.I svc_freeargs()
+.I svc_freeargs()
+will not attempt to free any memory if the variable indicating it
+is NULL. For example, in the the routine
+.I xdr_finalexample (),
+given earlier, if
+.I finalp->string
+was NULL, then it would not be freed. The same is true for
+.I finalp->simplep .
+.LP
+To summarize, each XDR routine is responsible
+for serializing, deserializing, and freeing memory.
+When an XDR routine is called from
+.I callrpc()
+the serializing part is used.
+When called from
+.I svc_getargs()
+the deserializer is used.
+And when called from
+.I svc_freeargs()
+the memory deallocator is used. When building simple examples like those
+in this section, a user doesn't have to worry
+about the three modes.
+See the
+.I "External Data Representation: Sun Technical Notes"
+for examples of more sophisticated XDR routines that determine
+which of the three modes they are in and adjust their behavior accordingly.
+.KS
+.NH 2
+\&The Calling Side
+.IX RPC "calling side"
+.LP
+When you use
+.I callrpc()
+you have no control over the RPC delivery
+mechanism or the socket used to transport the data.
+To illustrate the layer of RPC that lets you adjust these
+parameters, consider the following code to call the
+.I nusers
+service:
+.ie t .DS
+.el .DS L
+.ft CW
+.vs 11
+#include <stdio.h>
+#include <rpc/rpc.h>
+#include <utmp.h>
+#include <rpcsvc/rusers.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netdb.h>
+
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ struct hostent *hp;
+ struct timeval pertry_timeout, total_timeout;
+ struct sockaddr_in server_addr;
+ int sock = RPC_ANYSOCK;
+ register CLIENT *client;
+ enum clnt_stat clnt_stat;
+ unsigned long nusers;
+
+ if (argc != 2) {
+ fprintf(stderr, "usage: nusers hostname\en");
+ exit(-1);
+ }
+ if ((hp = gethostbyname(argv[1])) == NULL) {
+ fprintf(stderr, "can't get addr for %s\en",argv[1]);
+ exit(-1);
+ }
+ pertry_timeout.tv_sec = 3;
+ pertry_timeout.tv_usec = 0;
+ bcopy(hp->h_addr, (caddr_t)&server_addr.sin_addr,
+ hp->h_length);
+ server_addr.sin_family = AF_INET;
+ server_addr.sin_port = 0;
+ if ((client = clntudp_create(&server_addr, RUSERSPROG,
+ RUSERSVERS, pertry_timeout, &sock)) == NULL) {
+ clnt_pcreateerror("clntudp_create");
+ exit(-1);
+ }
+ total_timeout.tv_sec = 20;
+ total_timeout.tv_usec = 0;
+ clnt_stat = clnt_call(client, RUSERSPROC_NUM, xdr_void,
+ 0, xdr_u_long, &nusers, total_timeout);
+ if (clnt_stat != RPC_SUCCESS) {
+ clnt_perror(client, "rpc");
+ exit(-1);
+ }
+ clnt_destroy(client);
+ close(sock);
+ exit(0);
+}
+.vs
+.DE
+.KE
+The low-level version of
+.I callrpc()
+is
+.I clnt_call()
+which takes a
+.I CLIENT
+pointer rather than a host name. The parameters to
+.I clnt_call()
+are a
+.I CLIENT
+pointer, the procedure number,
+the XDR routine for serializing the argument,
+a pointer to the argument,
+the XDR routine for deserializing the return value,
+a pointer to where the return value will be placed,
+and the time in seconds to wait for a reply.
+.LP
+The
+.I CLIENT
+pointer is encoded with the transport mechanism.
+.I callrpc()
+uses UDP, thus it calls
+.I clntudp_create()
+to get a
+.I CLIENT
+pointer. To get TCP (Transmission Control Protocol), you would use
+.I clnttcp_create() .
+.LP
+The parameters to
+.I clntudp_create()
+are the server address, the program number, the version number,
+a timeout value (between tries), and a pointer to a socket.
+The final argument to
+.I clnt_call()
+is the total time to wait for a response.
+Thus, the number of tries is the
+.I clnt_call()
+timeout divided by the
+.I clntudp_create()
+timeout.
+.LP
+Note that the
+.I clnt_destroy()
+call
+always deallocates the space associated with the
+.I CLIENT
+handle. It closes the socket associated with the
+.I CLIENT
+handle, however, only if the RPC library opened it. It the
+socket was opened by the user, it stays open. This makes it
+possible, in cases where there are multiple client handles
+using the same socket, to destroy one handle without closing
+the socket that other handles are using.
+.LP
+To make a stream connection, the call to
+.I clntudp_create()
+is replaced with a call to
+.I clnttcp_create() .
+.DS
+.ft CW
+clnttcp_create(&server_addr, prognum, versnum, &sock,
+ inputsize, outputsize);
+.DE
+There is no timeout argument; instead, the receive and send buffer
+sizes must be specified. When the
+.I clnttcp_create()
+call is made, a TCP connection is established.
+All RPC calls using that
+.I CLIENT
+handle would use this connection.
+The server side of an RPC call using TCP has
+.I svcudp_create()
+replaced by
+.I svctcp_create() .
+.DS
+.ft CW
+transp = svctcp_create(RPC_ANYSOCK, 0, 0);
+.DE
+The last two arguments to
+.I svctcp_create()
+are send and receive sizes respectively. If `0' is specified for
+either of these, the system chooses a reasonable default.
+.KS
+.NH 1
+\&Other RPC Features
+.IX "RPC" "miscellaneous features"
+.IX "miscellaneous RPC features"
+.LP
+This section discusses some other aspects of RPC
+that are occasionally useful.
+.NH 2
+\&Select on the Server Side
+.IX RPC select() RPC \fIselect()\fP
+.IX select() "" \fIselect()\fP "on the server side"
+.LP
+Suppose a process is processing RPC requests
+while performing some other activity.
+If the other activity involves periodically updating a data structure,
+the process can set an alarm signal before calling
+.I svc_run()
+But if the other activity
+involves waiting on a file descriptor, the
+.I svc_run()
+call won't work.
+The code for
+.I svc_run()
+is as follows:
+.ie t .DS
+.el .DS L
+.ft CW
+.vs 11
+void
+svc_run()
+{
+ fd_set readfds;
+ int dtbsz = getdtablesize();
+
+ for (;;) {
+ readfds = svc_fds;
+ switch (select(dtbsz, &readfds, NULL,NULL,NULL)) {
+
+ case -1:
+ if (errno == EINTR)
+ continue;
+ perror("select");
+ return;
+ case 0:
+ break;
+ default:
+ svc_getreqset(&readfds);
+ }
+ }
+}
+.vs
+.DE
+.KE
+.LP
+You can bypass
+.I svc_run()
+and call
+.I svc_getreqset()
+yourself.
+All you need to know are the file descriptors
+of the socket(s) associated with the programs you are waiting on.
+Thus you can have your own
+.I select()
+.IX select() "" \fIselect()\fP
+that waits on both the RPC socket,
+and your own descriptors. Note that
+.I svc_fds()
+is a bit mask of all the file descriptors that RPC is using for
+services. It can change everytime that
+.I any
+RPC library routine is called, because descriptors are constantly
+being opened and closed, for example for TCP connections.
+.NH 2
+\&Broadcast RPC
+.IX "broadcast RPC"
+.IX RPC "broadcast"
+.LP
+The
+.I portmapper
+is a daemon that converts RPC program numbers
+into DARPA protocol port numbers; see the
+.I portmap
+man page. You can't do broadcast RPC without the portmapper.
+Here are the main differences between
+broadcast RPC and normal RPC calls:
+.IP 1.
+Normal RPC expects one answer, whereas
+broadcast RPC expects many answers
+(one or more answer from each responding machine).
+.IP 2.
+Broadcast RPC can only be supported by packet-oriented (connectionless)
+transport protocols like UPD/IP.
+.IP 3.
+The implementation of broadcast RPC
+treats all unsuccessful responses as garbage by filtering them out.
+Thus, if there is a version mismatch between the
+broadcaster and a remote service,
+the user of broadcast RPC never knows.
+.IP 4.
+All broadcast messages are sent to the portmap port.
+Thus, only services that register themselves with their portmapper
+are accessible via the broadcast RPC mechanism.
+.IP 5.
+Broadcast requests are limited in size to the MTU (Maximum Transfer
+Unit) of the local network. For Ethernet, the MTU is 1500 bytes.
+.KS
+.NH 3
+\&Broadcast RPC Synopsis
+.IX "broadcast RPC" synopsis
+.IX "RPC" "broadcast synopsis"
+.ie t .DS
+.el .DS L
+.ft CW
+#include <rpc/pmap_clnt.h>
+ . . .
+enum clnt_stat clnt_stat;
+ . . .
+clnt_stat = clnt_broadcast(prognum, versnum, procnum,
+ inproc, in, outproc, out, eachresult)
+ u_long prognum; /* \fIprogram number\fP */
+ u_long versnum; /* \fIversion number\fP */
+ u_long procnum; /* \fIprocedure number\fP */
+ xdrproc_t inproc; /* \fIxdr routine for args\fP */
+ caddr_t in; /* \fIpointer to args\fP */
+ xdrproc_t outproc; /* \fIxdr routine for results\fP */
+ caddr_t out; /* \fIpointer to results\fP */
+ bool_t (*eachresult)();/* \fIcall with each result gotten\fP */
+.DE
+.KE
+The procedure
+.I eachresult()
+is called each time a valid result is obtained.
+It returns a boolean that indicates
+whether or not the user wants more responses.
+.ie t .DS
+.el .DS L
+.ft CW
+bool_t done;
+ . . .
+done = eachresult(resultsp, raddr)
+ caddr_t resultsp;
+ struct sockaddr_in *raddr; /* \fIAddr of responding machine\fP */
+.DE
+If
+.I done
+is
+.I TRUE ,
+then broadcasting stops and
+.I clnt_broadcast()
+returns successfully.
+Otherwise, the routine waits for another response.
+The request is rebroadcast
+after a few seconds of waiting.
+If no responses come back,
+the routine returns with
+.I RPC_TIMEDOUT .
+.NH 2
+\&Batching
+.IX "batching"
+.IX RPC "batching"
+.LP
+The RPC architecture is designed so that clients send a call message,
+and wait for servers to reply that the call succeeded.
+This implies that clients do not compute
+while servers are processing a call.
+This is inefficient if the client does not want or need
+an acknowledgement for every message sent.
+It is possible for clients to continue computing
+while waiting for a response,
+using RPC batch facilities.
+.LP
+RPC messages can be placed in a \*Qpipeline\*U of calls
+to a desired server; this is called batching.
+Batching assumes that:
+1) each RPC call in the pipeline requires no response from the server,
+and the server does not send a response message; and
+2) the pipeline of calls is transported on a reliable
+byte stream transport such as TCP/IP.
+Since the server does not respond to every call,
+the client can generate new calls in parallel
+with the server executing previous calls.
+Furthermore, the TCP/IP implementation can buffer up
+many call messages, and send them to the server in one
+.I write()
+system call. This overlapped execution
+greatly decreases the interprocess communication overhead of
+the client and server processes,
+and the total elapsed time of a series of calls.
+.LP
+Since the batched calls are buffered,
+the client should eventually do a nonbatched call
+in order to flush the pipeline.
+.LP
+A contrived example of batching follows.
+Assume a string rendering service (like a window system)
+has two similar calls: one renders a string and returns void results,
+while the other renders a string and remains silent.
+The service (using the TCP/IP transport) may look like:
+.ie t .DS
+.el .DS L
+.ft CW
+#include <stdio.h>
+#include <rpc/rpc.h>
+#include <suntool/windows.h>
+
+void windowdispatch();
+
+main()
+{
+ SVCXPRT *transp;
+
+ transp = svctcp_create(RPC_ANYSOCK, 0, 0);
+ if (transp == NULL){
+ fprintf(stderr, "can't create an RPC server\en");
+ exit(1);
+ }
+ pmap_unset(WINDOWPROG, WINDOWVERS);
+ if (!svc_register(transp, WINDOWPROG, WINDOWVERS,
+ windowdispatch, IPPROTO_TCP)) {
+ fprintf(stderr, "can't register WINDOW service\en");
+ exit(1);
+ }
+ svc_run(); /* \fINever returns\fP */
+ fprintf(stderr, "should never reach this point\en");
+}
+
+void
+windowdispatch(rqstp, transp)
+ struct svc_req *rqstp;
+ SVCXPRT *transp;
+{
+ char *s = NULL;
+
+ switch (rqstp->rq_proc) {
+ case NULLPROC:
+ if (!svc_sendreply(transp, xdr_void, 0))
+ fprintf(stderr, "can't reply to RPC call\en");
+ return;
+ case RENDERSTRING:
+ if (!svc_getargs(transp, xdr_wrapstring, &s)) {
+ fprintf(stderr, "can't decode arguments\en");
+.ft I
+ /*
+ * Tell caller he screwed up
+ */
+.ft CW
+ svcerr_decode(transp);
+ break;
+ }
+.ft I
+ /*
+ * Code here to render the string \fIs\fP
+ */
+.ft CW
+ if (!svc_sendreply(transp, xdr_void, NULL))
+ fprintf(stderr, "can't reply to RPC call\en");
+ break;
+ case RENDERSTRING_BATCHED:
+ if (!svc_getargs(transp, xdr_wrapstring, &s)) {
+ fprintf(stderr, "can't decode arguments\en");
+.ft I
+ /*
+ * We are silent in the face of protocol errors
+ */
+.ft CW
+ break;
+ }
+.ft I
+ /*
+ * Code here to render string s, but send no reply!
+ */
+.ft CW
+ break;
+ default:
+ svcerr_noproc(transp);
+ return;
+ }
+.ft I
+ /*
+ * Now free string allocated while decoding arguments
+ */
+.ft CW
+ svc_freeargs(transp, xdr_wrapstring, &s);
+}
+.DE
+Of course the service could have one procedure
+that takes the string and a boolean
+to indicate whether or not the procedure should respond.
+.LP
+In order for a client to take advantage of batching,
+the client must perform RPC calls on a TCP-based transport
+and the actual calls must have the following attributes:
+1) the result's XDR routine must be zero
+.I NULL ),
+and 2) the RPC call's timeout must be zero.
+.KS
+.LP
+Here is an example of a client that uses batching to render a
+bunch of strings; the batching is flushed when the client gets
+a null string (EOF):
+.ie t .DS
+.el .DS L
+.ft CW
+.vs 11
+#include <stdio.h>
+#include <rpc/rpc.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netdb.h>
+#include <suntool/windows.h>
+
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ struct hostent *hp;
+ struct timeval pertry_timeout, total_timeout;
+ struct sockaddr_in server_addr;
+ int sock = RPC_ANYSOCK;
+ register CLIENT *client;
+ enum clnt_stat clnt_stat;
+ char buf[1000], *s = buf;
+
+ if ((client = clnttcp_create(&server_addr,
+ WINDOWPROG, WINDOWVERS, &sock, 0, 0)) == NULL) {
+ perror("clnttcp_create");
+ exit(-1);
+ }
+ total_timeout.tv_sec = 0;
+ total_timeout.tv_usec = 0;
+ while (scanf("%s", s) != EOF) {
+ clnt_stat = clnt_call(client, RENDERSTRING_BATCHED,
+ xdr_wrapstring, &s, NULL, NULL, total_timeout);
+ if (clnt_stat != RPC_SUCCESS) {
+ clnt_perror(client, "batched rpc");
+ exit(-1);
+ }
+ }
+
+ /* \fINow flush the pipeline\fP */
+
+ total_timeout.tv_sec = 20;
+ clnt_stat = clnt_call(client, NULLPROC, xdr_void, NULL,
+ xdr_void, NULL, total_timeout);
+ if (clnt_stat != RPC_SUCCESS) {
+ clnt_perror(client, "rpc");
+ exit(-1);
+ }
+ clnt_destroy(client);
+ exit(0);
+}
+.vs
+.DE
+.KE
+Since the server sends no message,
+the clients cannot be notified of any of the failures that may occur.
+Therefore, clients are on their own when it comes to handling errors.
+.LP
+The above example was completed to render
+all of the (2000) lines in the file
+.I /etc/termcap .
+The rendering service did nothing but throw the lines away.
+The example was run in the following four configurations:
+1) machine to itself, regular RPC;
+2) machine to itself, batched RPC;
+3) machine to another, regular RPC; and
+4) machine to another, batched RPC.
+The results are as follows:
+1) 50 seconds;
+2) 16 seconds;
+3) 52 seconds;
+4) 10 seconds.
+Running
+.I fscanf()
+on
+.I /etc/termcap
+only requires six seconds.
+These timings show the advantage of protocols
+that allow for overlapped execution,
+though these protocols are often hard to design.
+.NH 2
+\&Authentication
+.IX "authentication"
+.IX "RPC" "authentication"
+.LP
+In the examples presented so far,
+the caller never identified itself to the server,
+and the server never required an ID from the caller.
+Clearly, some network services, such as a network filesystem,
+require stronger security than what has been presented so far.
+.LP
+In reality, every RPC call is authenticated by
+the RPC package on the server, and similarly,
+the RPC client package generates and sends authentication parameters.
+Just as different transports (TCP/IP or UDP/IP)
+can be used when creating RPC clients and servers,
+different forms of authentication can be associated with RPC clients;
+the default authentication type used as a default is type
+.I none .
+.LP
+The authentication subsystem of the RPC package is open ended.
+That is, numerous types of authentication are easy to support.
+.NH 3
+\&UNIX Authentication
+.IX "UNIX Authentication"
+.IP "\fIThe Client Side\fP"
+.LP
+When a caller creates a new RPC client handle as in:
+.DS
+.ft CW
+clnt = clntudp_create(address, prognum, versnum,
+ wait, sockp)
+.DE
+the appropriate transport instance defaults
+the associate authentication handle to be
+.DS
+.ft CW
+clnt->cl_auth = authnone_create();
+.DE
+The RPC client can choose to use
+.I UNIX
+style authentication by setting
+.I clnt\->cl_auth
+after creating the RPC client handle:
+.DS
+.ft CW
+clnt->cl_auth = authunix_create_default();
+.DE
+This causes each RPC call associated with
+.I clnt
+to carry with it the following authentication credentials structure:
+.ie t .DS
+.el .DS L
+.ft I
+/*
+ * UNIX style credentials.
+ */
+.ft CW
+struct authunix_parms {
+ u_long aup_time; /* \fIcredentials creation time\fP */
+ char *aup_machname; /* \fIhost name where client is\fP */
+ int aup_uid; /* \fIclient's UNIX effective uid\fP */
+ int aup_gid; /* \fIclient's current group id\fP */
+ u_int aup_len; /* \fIelement length of aup_gids\fP */
+ int *aup_gids; /* \fIarray of groups user is in\fP */
+};
+.DE
+These fields are set by
+.I authunix_create_default()
+by invoking the appropriate system calls.
+Since the RPC user created this new style of authentication,
+the user is responsible for destroying it with:
+.DS
+.ft CW
+auth_destroy(clnt->cl_auth);
+.DE
+This should be done in all cases, to conserve memory.
+.sp
+.IP "\fIThe Server Side\fP"
+.LP
+Service implementors have a harder time dealing with authentication issues
+since the RPC package passes the service dispatch routine a request
+that has an arbitrary authentication style associated with it.
+Consider the fields of a request handle passed to a service dispatch routine:
+.ie t .DS
+.el .DS L
+.ft I
+/*
+ * An RPC Service request
+ */
+.ft CW
+struct svc_req {
+ u_long rq_prog; /* \fIservice program number\fP */
+ u_long rq_vers; /* \fIservice protocol vers num\fP */
+ u_long rq_proc; /* \fIdesired procedure number\fP */
+ struct opaque_auth rq_cred; /* \fIraw credentials from wire\fP */
+ caddr_t rq_clntcred; /* \fIcredentials (read only)\fP */
+};
+.DE
+The
+.I rq_cred
+is mostly opaque, except for one field of interest:
+the style or flavor of authentication credentials:
+.ie t .DS
+.el .DS L
+.ft I
+/*
+ * Authentication info. Mostly opaque to the programmer.
+ */
+.ft CW
+struct opaque_auth {
+ enum_t oa_flavor; /* \fIstyle of credentials\fP */
+ caddr_t oa_base; /* \fIaddress of more auth stuff\fP */
+ u_int oa_length; /* \fInot to exceed \fIMAX_AUTH_BYTES */
+};
+.DE
+.IX RPC guarantees
+The RPC package guarantees the following
+to the service dispatch routine:
+.IP 1.
+That the request's
+.I rq_cred
+is well formed. Thus the service implementor may inspect the request's
+.I rq_cred.oa_flavor
+to determine which style of authentication the caller used.
+The service implementor may also wish to inspect the other fields of
+.I rq_cred
+if the style is not one of the styles supported by the RPC package.
+.IP 2.
+That the request's
+.I rq_clntcred
+field is either
+.I NULL
+or points to a well formed structure
+that corresponds to a supported style of authentication credentials.
+Remember that only
+.I unix
+style is currently supported, so (currently)
+.I rq_clntcred
+could be cast to a pointer to an
+.I authunix_parms
+structure. If
+.I rq_clntcred
+is
+.I NULL ,
+the service implementor may wish to inspect the other (opaque) fields of
+.I rq_cred
+in case the service knows about a new type of authentication
+that the RPC package does not know about.
+.LP
+Our remote users service example can be extended so that
+it computes results for all users except UID 16:
+.ie t .DS
+.el .DS L
+.ft CW
+.vs 11
+nuser(rqstp, transp)
+ struct svc_req *rqstp;
+ SVCXPRT *transp;
+{
+ struct authunix_parms *unix_cred;
+ int uid;
+ unsigned long nusers;
+
+.ft I
+ /*
+ * we don't care about authentication for null proc
+ */
+.ft CW
+ if (rqstp->rq_proc == NULLPROC) {
+ if (!svc_sendreply(transp, xdr_void, 0)) {
+ fprintf(stderr, "can't reply to RPC call\en");
+ return (1);
+ }
+ return;
+ }
+.ft I
+ /*
+ * now get the uid
+ */
+.ft CW
+ switch (rqstp->rq_cred.oa_flavor) {
+ case AUTH_UNIX:
+ unix_cred =
+ (struct authunix_parms *)rqstp->rq_clntcred;
+ uid = unix_cred->aup_uid;
+ break;
+ case AUTH_NULL:
+ default:
+ svcerr_weakauth(transp);
+ return;
+ }
+ switch (rqstp->rq_proc) {
+ case RUSERSPROC_NUM:
+.ft I
+ /*
+ * make sure caller is allowed to call this proc
+ */
+.ft CW
+ if (uid == 16) {
+ svcerr_systemerr(transp);
+ return;
+ }
+.ft I
+ /*
+ * Code here to compute the number of users
+ * and assign it to the variable \fInusers\fP
+ */
+.ft CW
+ if (!svc_sendreply(transp, xdr_u_long, &nusers)) {
+ fprintf(stderr, "can't reply to RPC call\en");
+ return (1);
+ }
+ return;
+ default:
+ svcerr_noproc(transp);
+ return;
+ }
+}
+.vs
+.DE
+A few things should be noted here.
+First, it is customary not to check
+the authentication parameters associated with the
+.I NULLPROC
+(procedure number zero).
+Second, if the authentication parameter's type is not suitable
+for your service, you should call
+.I svcerr_weakauth() .
+And finally, the service protocol itself should return status
+for access denied; in the case of our example, the protocol
+does not have such a status, so we call the service primitive
+.I svcerr_systemerr()
+instead.
+.LP
+The last point underscores the relation between
+the RPC authentication package and the services;
+RPC deals only with
+.I authentication
+and not with individual services'
+.I "access control" .
+The services themselves must implement their own access control policies
+and reflect these policies as return statuses in their protocols.
+.NH 2
+\&DES Authentication
+.IX RPC DES
+.IX RPC authentication
+.LP
+UNIX authentication is quite easy to defeat. Instead of using
+.I authunix_create_default (),
+one can call
+.I authunix_create()
+and then modify the RPC authentication handle it returns by filling in
+whatever user ID and hostname they wish the server to think they have.
+DES authentication is thus recommended for people who want more security
+than UNIX authentication offers.
+.LP
+The details of the DES authentication protocol are complicated and
+are not explained here.
+See
+.I "Remote Procedure Calls: Protocol Specification"
+for the details.
+.LP
+In order for DES authentication to work, the
+.I keyserv(8c)
+daemon must be running on both the server and client machines. The
+users on these machines need public keys assigned by the network
+administrator in the
+.I publickey(5)
+database. And, they need to have decrypted their secret keys
+using their login password. This automatically happens when one
+logs in using
+.I login(1) ,
+or can be done manually using
+.I keylogin(1) .
+The
+.I "Network Services"
+chapter
+.\" XXX
+explains more how to setup secure networking.
+.sp
+.IP "\fIClient Side\fP"
+.LP
+If a client wishes to use DES authentication, it must set its
+authentication handle appropriately. Here is an example:
+.DS
+cl->cl_auth =
+ authdes_create(servername, 60, &server_addr, NULL);
+.DE
+The first argument is the network name or \*Qnetname\*U of the owner of
+the server process. Typically, server processes are root processes
+and their netname can be derived using the following call:
+.DS
+char servername[MAXNETNAMELEN];
+
+host2netname(servername, rhostname, NULL);
+.DE
+Here,
+.I rhostname
+is the hostname of the machine the server process is running on.
+.I host2netname()
+fills in
+.I servername
+to contain this root process's netname. If the
+server process was run by a regular user, one could use the call
+.I user2netname()
+instead. Here is an example for a server process with the same user
+ID as the client:
+.DS
+char servername[MAXNETNAMELEN];
+
+user2netname(servername, getuid(), NULL);
+.DE
+The last argument to both of these calls,
+.I user2netname()
+and
+.I host2netname (),
+is the name of the naming domain where the server is located. The
+.I NULL
+used here means \*Quse the local domain name.\*U
+.LP
+The second argument to
+.I authdes_create()
+is a lifetime for the credential. Here it is set to sixty
+seconds. What that means is that the credential will expire 60
+seconds from now. If some mischievous user tries to reuse the
+credential, the server RPC subsystem will recognize that it has
+expired and not grant any requests. If the same mischievous user
+tries to reuse the credential within the sixty second lifetime,
+he will still be rejected because the server RPC subsystem
+remembers which credentials it has already seen in the near past,
+and will not grant requests to duplicates.
+.LP
+The third argument to
+.I authdes_create()
+is the address of the host to synchronize with. In order for DES
+authentication to work, the server and client must agree upon the
+time. Here we pass the address of the server itself, so the
+client and server will both be using the same time: the server's
+time. The argument can be
+.I NULL ,
+which means \*Qdon't bother synchronizing.\*U You should only do this
+if you are sure the client and server are already synchronized.
+.LP
+The final argument to
+.I authdes_create()
+is the address of a DES encryption key to use for encrypting
+timestamps and data. If this argument is
+.I NULL ,
+as it is in this example, a random key will be chosen. The client
+may find out the encryption key being used by consulting the
+.I ah_key
+field of the authentication handle.
+.sp
+.IP "\fIServer Side\fP"
+.LP
+The server side is a lot simpler than the client side. Here is the
+previous example rewritten to use
+.I AUTH_DES
+instead of
+.I AUTH_UNIX :
+.ie t .DS
+.el .DS L
+.ft CW
+.vs 11
+#include <sys/time.h>
+#include <rpc/auth_des.h>
+ . . .
+ . . .
+nuser(rqstp, transp)
+ struct svc_req *rqstp;
+ SVCXPRT *transp;
+{
+ struct authdes_cred *des_cred;
+ int uid;
+ int gid;
+ int gidlen;
+ int gidlist[10];
+.ft I
+ /*
+ * we don't care about authentication for null proc
+ */
+.ft CW
+
+ if (rqstp->rq_proc == NULLPROC) {
+ /* \fIsame as before\fP */
+ }
+
+.ft I
+ /*
+ * now get the uid
+ */
+.ft CW
+ switch (rqstp->rq_cred.oa_flavor) {
+ case AUTH_DES:
+ des_cred =
+ (struct authdes_cred *) rqstp->rq_clntcred;
+ if (! netname2user(des_cred->adc_fullname.name,
+ &uid, &gid, &gidlen, gidlist))
+ {
+ fprintf(stderr, "unknown user: %s\en",
+ des_cred->adc_fullname.name);
+ svcerr_systemerr(transp);
+ return;
+ }
+ break;
+ case AUTH_NULL:
+ default:
+ svcerr_weakauth(transp);
+ return;
+ }
+
+.ft I
+ /*
+ * The rest is the same as before
+ */
+.ft CW
+.vs
+.DE
+Note the use of the routine
+.I netname2user (),
+the inverse of
+.I user2netname ():
+it takes a network ID and converts to a unix ID.
+.I netname2user ()
+also supplies the group IDs which we don't use in this example,
+but which may be useful to other UNIX programs.
+.NH 2
+\&Using Inetd
+.IX inetd "" "using \fIinetd\fP"
+.LP
+An RPC server can be started from
+.I inetd
+The only difference from the usual code is that the service
+creation routine should be called in the following form:
+.ie t .DS
+.el .DS L
+.ft CW
+transp = svcudp_create(0); /* \fIFor UDP\fP */
+transp = svctcp_create(0,0,0); /* \fIFor listener TCP sockets\fP */
+transp = svcfd_create(0,0,0); /* \fIFor connected TCP sockets\fP */
+.DE
+since
+.I inet
+passes a socket as file descriptor 0.
+Also,
+.I svc_register()
+should be called as
+.ie t .DS
+.el .DS L
+.ft CW
+svc_register(transp, PROGNUM, VERSNUM, service, 0);
+.DE
+with the final flag as 0,
+since the program would already be registered by
+.I inetd
+Remember that if you want to exit
+from the server process and return control to
+.I inet
+you need to explicitly exit, since
+.I svc_run()
+never returns.
+.LP
+The format of entries in
+.I /etc/inetd.conf
+for RPC services is in one of the following two forms:
+.ie t .DS
+.el .DS L
+.ft CW
+p_name/version dgram rpc/udp wait/nowait user server args
+p_name/version stream rpc/tcp wait/nowait user server args
+.DE
+where
+.I p_name
+is the symbolic name of the program as it appears in
+.I rpc(5) ,
+.I server
+is the program implementing the server,
+and
+.I program
+and
+.I version
+are the program and version numbers of the service.
+For more information, see
+.I inetd.conf(5) .
+.LP
+If the same program handles multiple versions,
+then the version number can be a range,
+as in this example:
+.ie t .DS
+.el .DS L
+.ft CW
+rstatd/1-2 dgram rpc/udp wait root /usr/etc/rpc.rstatd
+.DE
+.NH 1
+\&More Examples
+.sp 1
+.NH 2
+\&Versions
+.IX "versions"
+.IX "RPC" "versions"
+.LP
+By convention, the first version number of program
+.I PROG
+is
+.I PROGVERS_ORIG
+and the most recent version is
+.I PROGVERS
+Suppose there is a new version of the
+.I user
+program that returns an
+.I "unsigned short"
+rather than a
+.I long .
+If we name this version
+.I RUSERSVERS_SHORT
+then a server that wants to support both versions
+would do a double register.
+.ie t .DS
+.el .DS L
+.ft CW
+if (!svc_register(transp, RUSERSPROG, RUSERSVERS_ORIG,
+ nuser, IPPROTO_TCP)) {
+ fprintf(stderr, "can't register RUSER service\en");
+ exit(1);
+}
+if (!svc_register(transp, RUSERSPROG, RUSERSVERS_SHORT,
+ nuser, IPPROTO_TCP)) {
+ fprintf(stderr, "can't register RUSER service\en");
+ exit(1);
+}
+.DE
+Both versions can be handled by the same C procedure:
+.ie t .DS
+.el .DS L
+.ft CW
+.vs 11
+nuser(rqstp, transp)
+ struct svc_req *rqstp;
+ SVCXPRT *transp;
+{
+ unsigned long nusers;
+ unsigned short nusers2;
+
+ switch (rqstp->rq_proc) {
+ case NULLPROC:
+ if (!svc_sendreply(transp, xdr_void, 0)) {
+ fprintf(stderr, "can't reply to RPC call\en");
+ return (1);
+ }
+ return;
+ case RUSERSPROC_NUM:
+.ft I
+ /*
+ * Code here to compute the number of users
+ * and assign it to the variable \fInusers\fP
+ */
+.ft CW
+ nusers2 = nusers;
+ switch (rqstp->rq_vers) {
+ case RUSERSVERS_ORIG:
+ if (!svc_sendreply(transp, xdr_u_long,
+ &nusers)) {
+ fprintf(stderr,"can't reply to RPC call\en");
+ }
+ break;
+ case RUSERSVERS_SHORT:
+ if (!svc_sendreply(transp, xdr_u_short,
+ &nusers2)) {
+ fprintf(stderr,"can't reply to RPC call\en");
+ }
+ break;
+ }
+ default:
+ svcerr_noproc(transp);
+ return;
+ }
+}
+.vs
+.DE
+.KS
+.NH 2
+\&TCP
+.IX "TCP"
+.LP
+Here is an example that is essentially
+.I rcp.
+The initiator of the RPC
+.I snd
+call takes its standard input and sends it to the server
+.I rcv
+which prints it on standard output.
+The RPC call uses TCP.
+This also illustrates an XDR procedure that behaves differently
+on serialization than on deserialization.
+.ie t .DS
+.el .DS L
+.vs 11
+.ft I
+/*
+ * The xdr routine:
+ * on decode, read from wire, write onto fp
+ * on encode, read from fp, write onto wire
+ */
+.ft CW
+#include <stdio.h>
+#include <rpc/rpc.h>
+
+xdr_rcp(xdrs, fp)
+ XDR *xdrs;
+ FILE *fp;
+{
+ unsigned long size;
+ char buf[BUFSIZ], *p;
+
+ if (xdrs->x_op == XDR_FREE)/* nothing to free */
+ return 1;
+ while (1) {
+ if (xdrs->x_op == XDR_ENCODE) {
+ if ((size = fread(buf, sizeof(char), BUFSIZ,
+ fp)) == 0 && ferror(fp)) {
+ fprintf(stderr, "can't fread\en");
+ return (1);
+ }
+ }
+ p = buf;
+ if (!xdr_bytes(xdrs, &p, &size, BUFSIZ))
+ return 0;
+ if (size == 0)
+ return 1;
+ if (xdrs->x_op == XDR_DECODE) {
+ if (fwrite(buf, sizeof(char), size,
+ fp) != size) {
+ fprintf(stderr, "can't fwrite\en");
+ return (1);
+ }
+ }
+ }
+}
+.vs
+.DE
+.KE
+.ie t .DS
+.el .DS L
+.vs 11
+.ft I
+/*
+ * The sender routines
+ */
+.ft CW
+#include <stdio.h>
+#include <netdb.h>
+#include <rpc/rpc.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int xdr_rcp();
+ int err;
+
+ if (argc < 2) {
+ fprintf(stderr, "usage: %s servername\en", argv[0]);
+ exit(-1);
+ }
+ if ((err = callrpctcp(argv[1], RCPPROG, RCPPROC,
+ RCPVERS, xdr_rcp, stdin, xdr_void, 0) != 0)) {
+ clnt_perrno(err);
+ fprintf(stderr, "can't make RPC call\en");
+ exit(1);
+ }
+ exit(0);
+}
+
+callrpctcp(host, prognum, procnum, versnum,
+ inproc, in, outproc, out)
+ char *host, *in, *out;
+ xdrproc_t inproc, outproc;
+{
+ struct sockaddr_in server_addr;
+ int socket = RPC_ANYSOCK;
+ enum clnt_stat clnt_stat;
+ struct hostent *hp;
+ register CLIENT *client;
+ struct timeval total_timeout;
+
+ if ((hp = gethostbyname(host)) == NULL) {
+ fprintf(stderr, "can't get addr for '%s'\en", host);
+ return (-1);
+ }
+ bcopy(hp->h_addr, (caddr_t)&server_addr.sin_addr,
+ hp->h_length);
+ server_addr.sin_family = AF_INET;
+ server_addr.sin_port = 0;
+ if ((client = clnttcp_create(&server_addr, prognum,
+ versnum, &socket, BUFSIZ, BUFSIZ)) == NULL) {
+ perror("rpctcp_create");
+ return (-1);
+ }
+ total_timeout.tv_sec = 20;
+ total_timeout.tv_usec = 0;
+ clnt_stat = clnt_call(client, procnum,
+ inproc, in, outproc, out, total_timeout);
+ clnt_destroy(client);
+ return (int)clnt_stat;
+}
+.vs
+.DE
+.ie t .DS
+.el .DS L
+.vs 11
+.ft I
+/*
+ * The receiving routines
+ */
+.ft CW
+#include <stdio.h>
+#include <rpc/rpc.h>
+
+main()
+{
+ register SVCXPRT *transp;
+ int rcp_service(), xdr_rcp();
+
+ if ((transp = svctcp_create(RPC_ANYSOCK,
+ BUFSIZ, BUFSIZ)) == NULL) {
+ fprintf("svctcp_create: error\en");
+ exit(1);
+ }
+ pmap_unset(RCPPROG, RCPVERS);
+ if (!svc_register(transp,
+ RCPPROG, RCPVERS, rcp_service, IPPROTO_TCP)) {
+ fprintf(stderr, "svc_register: error\en");
+ exit(1);
+ }
+ svc_run(); /* \fInever returns\fP */
+ fprintf(stderr, "svc_run should never return\en");
+}
+
+rcp_service(rqstp, transp)
+ register struct svc_req *rqstp;
+ register SVCXPRT *transp;
+{
+ switch (rqstp->rq_proc) {
+ case NULLPROC:
+ if (svc_sendreply(transp, xdr_void, 0) == 0) {
+ fprintf(stderr, "err: rcp_service");
+ return (1);
+ }
+ return;
+ case RCPPROC_FP:
+ if (!svc_getargs(transp, xdr_rcp, stdout)) {
+ svcerr_decode(transp);
+ return;
+ }
+ if (!svc_sendreply(transp, xdr_void, 0)) {
+ fprintf(stderr, "can't reply\en");
+ return;
+ }
+ return (0);
+ default:
+ svcerr_noproc(transp);
+ return;
+ }
+}
+.vs
+.DE
+.NH 2
+\&Callback Procedures
+.IX RPC "callback procedures"
+.LP
+Occasionally, it is useful to have a server become a client,
+and make an RPC call back to the process which is its client.
+An example is remote debugging,
+where the client is a window system program,
+and the server is a debugger running on the remote machine.
+Most of the time,
+the user clicks a mouse button at the debugging window,
+which converts this to a debugger command,
+and then makes an RPC call to the server
+(where the debugger is actually running),
+telling it to execute that command.
+However, when the debugger hits a breakpoint, the roles are reversed,
+and the debugger wants to make an rpc call to the window program,
+so that it can inform the user that a breakpoint has been reached.
+.LP
+In order to do an RPC callback,
+you need a program number to make the RPC call on.
+Since this will be a dynamically generated program number,
+it should be in the transient range,
+.I "0x40000000 - 0x5fffffff" .
+The routine
+.I gettransient()
+returns a valid program number in the transient range,
+and registers it with the portmapper.
+It only talks to the portmapper running on the same machine as the
+.I gettransient()
+routine itself. The call to
+.I pmap_set()
+is a test and set operation,
+in that it indivisibly tests whether a program number
+has already been registered,
+and if it has not, then reserves it. On return, the
+.I sockp
+argument will contain a socket that can be used
+as the argument to an
+.I svcudp_create()
+or
+.I svctcp_create()
+call.
+.ie t .DS
+.el .DS L
+.ft CW
+.vs 11
+#include <stdio.h>
+#include <rpc/rpc.h>
+#include <sys/socket.h>
+
+gettransient(proto, vers, sockp)
+ int proto, vers, *sockp;
+{
+ static int prognum = 0x40000000;
+ int s, len, socktype;
+ struct sockaddr_in addr;
+
+ switch(proto) {
+ case IPPROTO_UDP:
+ socktype = SOCK_DGRAM;
+ break;
+ case IPPROTO_TCP:
+ socktype = SOCK_STREAM;
+ break;
+ default:
+ fprintf(stderr, "unknown protocol type\en");
+ return 0;
+ }
+ if (*sockp == RPC_ANYSOCK) {
+ if ((s = socket(AF_INET, socktype, 0)) < 0) {
+ perror("socket");
+ return (0);
+ }
+ *sockp = s;
+ }
+ else
+ s = *sockp;
+ addr.sin_addr.s_addr = 0;
+ addr.sin_family = AF_INET;
+ addr.sin_port = 0;
+ len = sizeof(addr);
+.ft I
+ /*
+ * may be already bound, so don't check for error
+ */
+.ft CW
+ bind(s, &addr, len);
+ if (getsockname(s, &addr, &len)< 0) {
+ perror("getsockname");
+ return (0);
+ }
+ while (!pmap_set(prognum++, vers, proto,
+ ntohs(addr.sin_port))) continue;
+ return (prognum-1);
+}
+.vs
+.DE
+.SH
+Note:
+.I
+The call to
+.I ntohs()
+is necessary to ensure that the port number in
+.I "addr.sin_port" ,
+which is in
+.I network
+byte order, is passed in
+.I host
+byte order (as
+.I pmap_set()
+expects). See the
+.I byteorder(3N)
+man page for more details on the conversion of network
+addresses from network to host byte order.
+.KS
+.LP
+The following pair of programs illustrate how to use the
+.I gettransient()
+routine.
+The client makes an RPC call to the server,
+passing it a transient program number.
+Then the client waits around to receive a callback
+from the server at that program number.
+The server registers the program
+.I EXAMPLEPROG
+so that it can receive the RPC call
+informing it of the callback program number.
+Then at some random time (on receiving an
+.I ALRM
+signal in this example), it sends a callback RPC call,
+using the program number it received earlier.
+.ie t .DS
+.el .DS L
+.vs 11
+.ft I
+/*
+ * client
+ */
+.ft CW
+#include <stdio.h>
+#include <rpc/rpc.h>
+
+int callback();
+char hostname[256];
+
+main()
+{
+ int x, ans, s;
+ SVCXPRT *xprt;
+
+ gethostname(hostname, sizeof(hostname));
+ s = RPC_ANYSOCK;
+ x = gettransient(IPPROTO_UDP, 1, &s);
+ fprintf(stderr, "client gets prognum %d\en", x);
+ if ((xprt = svcudp_create(s)) == NULL) {
+ fprintf(stderr, "rpc_server: svcudp_create\en");
+ exit(1);
+ }
+.ft I
+ /* protocol is 0 - gettransient does registering
+ */
+.ft CW
+ (void)svc_register(xprt, x, 1, callback, 0);
+ ans = callrpc(hostname, EXAMPLEPROG, EXAMPLEVERS,
+ EXAMPLEPROC_CALLBACK, xdr_int, &x, xdr_void, 0);
+ if ((enum clnt_stat) ans != RPC_SUCCESS) {
+ fprintf(stderr, "call: ");
+ clnt_perrno(ans);
+ fprintf(stderr, "\en");
+ }
+ svc_run();
+ fprintf(stderr, "Error: svc_run shouldn't return\en");
+}
+
+callback(rqstp, transp)
+ register struct svc_req *rqstp;
+ register SVCXPRT *transp;
+{
+ switch (rqstp->rq_proc) {
+ case 0:
+ if (!svc_sendreply(transp, xdr_void, 0)) {
+ fprintf(stderr, "err: exampleprog\en");
+ return (1);
+ }
+ return (0);
+ case 1:
+ if (!svc_getargs(transp, xdr_void, 0)) {
+ svcerr_decode(transp);
+ return (1);
+ }
+ fprintf(stderr, "client got callback\en");
+ if (!svc_sendreply(transp, xdr_void, 0)) {
+ fprintf(stderr, "err: exampleprog");
+ return (1);
+ }
+ }
+}
+.vs
+.DE
+.KE
+.ie t .DS
+.el .DS L
+.vs 11
+.ft I
+/*
+ * server
+ */
+.ft CW
+#include <stdio.h>
+#include <rpc/rpc.h>
+#include <sys/signal.h>
+
+char *getnewprog();
+char hostname[256];
+int docallback();
+int pnum; /* \fIprogram number for callback routine\fP */
+
+main()
+{
+ gethostname(hostname, sizeof(hostname));
+ registerrpc(EXAMPLEPROG, EXAMPLEVERS,
+ EXAMPLEPROC_CALLBACK, getnewprog, xdr_int, xdr_void);
+ fprintf(stderr, "server going into svc_run\en");
+ signal(SIGALRM, docallback);
+ alarm(10);
+ svc_run();
+ fprintf(stderr, "Error: svc_run shouldn't return\en");
+}
+
+char *
+getnewprog(pnump)
+ char *pnump;
+{
+ pnum = *(int *)pnump;
+ return NULL;
+}
+
+docallback()
+{
+ int ans;
+
+ ans = callrpc(hostname, pnum, 1, 1, xdr_void, 0,
+ xdr_void, 0);
+ if (ans != 0) {
+ fprintf(stderr, "server: ");
+ clnt_perrno(ans);
+ fprintf(stderr, "\en");
+ }
+}
+.vs
+.DE
diff --git a/lib/libc/rpc/PSD.doc/rpc.rfc.ms b/lib/libc/rpc/PSD.doc/rpc.rfc.ms
new file mode 100644
index 0000000..9a948bd
--- /dev/null
+++ b/lib/libc/rpc/PSD.doc/rpc.rfc.ms
@@ -0,0 +1,1304 @@
+.\"
+.\" Must use -- tbl -- with this one
+.\"
+.\" @(#)rpc.rfc.ms 2.2 88/08/05 4.0 RPCSRC
+.\" $FreeBSD$
+.\"
+.de BT
+.if \\n%=1 .tl ''- % -''
+..
+.ND
+.\" prevent excess underlining in nroff
+.if n .fp 2 R
+.OH 'Remote Procedure Calls: Protocol Specification''Page %'
+.EH 'Page %''Remote Procedure Calls: Protocol Specification'
+.if \n%=1 .bp
+.SH
+\&Remote Procedure Calls: Protocol Specification
+.LP
+.NH 0
+\&Status of this Memo
+.LP
+Note: This chapter specifies a protocol that Sun Microsystems, Inc.,
+and others are using.
+It has been designated RFC1050 by the ARPA Network
+Information Center.
+.LP
+.NH 1
+\&Introduction
+.LP
+This chapter specifies a message protocol used in implementing
+Sun's Remote Procedure Call (RPC) package. (The message protocol is
+specified with the External Data Representation (XDR) language.
+See the
+.I "External Data Representation Standard: Protocol Specification"
+for the details. Here, we assume that the reader is familiar
+with XDR and do not attempt to justify it or its uses). The paper
+by Birrell and Nelson [1] is recommended as an excellent background
+to and justification of RPC.
+.NH 2
+\&Terminology
+.LP
+This chapter discusses servers, services, programs, procedures,
+clients, and versions. A server is a piece of software where network
+services are implemented. A network service is a collection of one
+or more remote programs. A remote program implements one or more
+remote procedures; the procedures, their parameters, and results are
+documented in the specific program's protocol specification (see the
+\fIPort Mapper Program Protocol\fP\, below, for an example). Network
+clients are pieces of software that initiate remote procedure calls
+to services. A server may support more than one version of a remote
+program in order to be forward compatible with changing protocols.
+.LP
+For example, a network file service may be composed of two programs.
+One program may deal with high-level applications such as file system
+access control and locking. The other may deal with low-level file
+IO and have procedures like "read" and "write". A client machine of
+the network file service would call the procedures associated with
+the two programs of the service on behalf of some user on the client
+machine.
+.NH 2
+\&The RPC Model
+.LP
+The remote procedure call model is similar to the local procedure
+call model. In the local case, the caller places arguments to a
+procedure in some well-specified location (such as a result
+register). It then transfers control to the procedure, and
+eventually gains back control. At that point, the results of the
+procedure are extracted from the well-specified location, and the
+caller continues execution.
+.LP
+The remote procedure call is similar, in that one thread of control
+logically winds through two processes\(emone is the caller's process,
+the other is a server's process. That is, the caller process sends a
+call message to the server process and waits (blocks) for a reply
+message. The call message contains the procedure's parameters, among
+other things. The reply message contains the procedure's results,
+among other things. Once the reply message is received, the results
+of the procedure are extracted, and caller's execution is resumed.
+.LP
+On the server side, a process is dormant awaiting the arrival of a
+call message. When one arrives, the server process extracts the
+procedure's parameters, computes the results, sends a reply message,
+and then awaits the next call message.
+.LP
+Note that in this model, only one of the two processes is active at
+any given time. However, this model is only given as an example.
+The RPC protocol makes no restrictions on the concurrency model
+implemented, and others are possible. For example, an implementation
+may choose to have RPC calls be asynchronous, so that the client may
+do useful work while waiting for the reply from the server. Another
+possibility is to have the server create a task to process an
+incoming request, so that the server can be free to receive other
+requests.
+.NH 2
+\&Transports and Semantics
+.LP
+The RPC protocol is independent of transport protocols. That is, RPC
+does not care how a message is passed from one process to another.
+The protocol deals only with specification and interpretation of
+messages.
+.LP
+It is important to point out that RPC does not try to implement any
+kind of reliability and that the application must be aware of the
+type of transport protocol underneath RPC. If it knows it is running
+on top of a reliable transport such as TCP/IP[6], then most of the
+work is already done for it. On the other hand, if it is running on
+top of an unreliable transport such as UDP/IP[7], it must implement
+is own retransmission and time-out policy as the RPC layer does not
+provide this service.
+.LP
+Because of transport independence, the RPC protocol does not attach
+specific semantics to the remote procedures or their execution.
+Semantics can be inferred from (but should be explicitly specified
+by) the underlying transport protocol. For example, consider RPC
+running on top of an unreliable transport such as UDP/IP. If an
+application retransmits RPC messages after short time-outs, the only
+thing it can infer if it receives no reply is that the procedure was
+executed zero or more times. If it does receive a reply, then it can
+infer that the procedure was executed at least once.
+.LP
+A server may wish to remember previously granted requests from a
+client and not regrant them in order to insure some degree of
+execute-at-most-once semantics. A server can do this by taking
+advantage of the transaction ID that is packaged with every RPC
+request. The main use of this transaction is by the client RPC layer
+in matching replies to requests. However, a client application may
+choose to reuse its previous transaction ID when retransmitting a
+request. The server application, knowing this fact, may choose to
+remember this ID after granting a request and not regrant requests
+with the same ID in order to achieve some degree of
+execute-at-most-once semantics. The server is not allowed to examine
+this ID in any other way except as a test for equality.
+.LP
+On the other hand, if using a reliable transport such as TCP/IP, the
+application can infer from a reply message that the procedure was
+executed exactly once, but if it receives no reply message, it cannot
+assume the remote procedure was not executed. Note that even if a
+connection-oriented protocol like TCP is used, an application still
+needs time-outs and reconnection to handle server crashes.
+.LP
+There are other possibilities for transports besides datagram- or
+connection-oriented protocols. For example, a request-reply protocol
+such as VMTP[2] is perhaps the most natural transport for RPC.
+.SH
+.I
+NOTE: At Sun, RPC is currently implemented on top of both TCP/IP
+and UDP/IP transports.
+.LP
+.NH 2
+\&Binding and Rendezvous Independence
+.LP
+The act of binding a client to a service is NOT part of the remote
+procedure call specification. This important and necessary function
+is left up to some higher-level software. (The software may use RPC
+itself\(emsee the \fIPort Mapper Program Protocol\fP\, below).
+.LP
+Implementors should think of the RPC protocol as the jump-subroutine
+instruction ("JSR") of a network; the loader (binder) makes JSR
+useful, and the loader itself uses JSR to accomplish its task.
+Likewise, the network makes RPC useful, using RPC to accomplish this
+task.
+.NH 2
+\&Authentication
+.LP
+The RPC protocol provides the fields necessary for a client to
+identify itself to a service and vice-versa. Security and access
+control mechanisms can be built on top of the message authentication.
+Several different authentication protocols can be supported. A field
+in the RPC header indicates which protocol is being used. More
+information on specific authentication protocols can be found in the
+\fIAuthentication Protocols\fP\,
+below.
+.KS
+.NH 1
+\&RPC Protocol Requirements
+.LP
+The RPC protocol must provide for the following:
+.IP 1.
+Unique specification of a procedure to be called.
+.IP 2.
+Provisions for matching response messages to request messages.
+.KE
+.IP 3.
+Provisions for authenticating the caller to service and vice-versa.
+.LP
+Besides these requirements, features that detect the following are
+worth supporting because of protocol roll-over errors, implementation
+bugs, user error, and network administration:
+.IP 1.
+RPC protocol mismatches.
+.IP 2.
+Remote program protocol version mismatches.
+.IP 3.
+Protocol errors (such as misspecification of a procedure's parameters).
+.IP 4.
+Reasons why remote authentication failed.
+.IP 5.
+Any other reasons why the desired procedure was not called.
+.NH 2
+\&Programs and Procedures
+.LP
+The RPC call message has three unsigned fields: remote program
+number, remote program version number, and remote procedure number.
+The three fields uniquely identify the procedure to be called.
+Program numbers are administered by some central authority (like
+Sun). Once an implementor has a program number, he can implement his
+remote program; the first implementation would most likely have the
+version number of 1. Because most new protocols evolve into better,
+stable, and mature protocols, a version field of the call message
+identifies which version of the protocol the caller is using.
+Version numbers make speaking old and new protocols through the same
+server process possible.
+.LP
+The procedure number identifies the procedure to be called. These
+numbers are documented in the specific program's protocol
+specification. For example, a file service's protocol specification
+may state that its procedure number 5 is "read" and procedure number
+12 is "write".
+.LP
+Just as remote program protocols may change over several versions,
+the actual RPC message protocol could also change. Therefore, the
+call message also has in it the RPC version number, which is always
+equal to two for the version of RPC described here.
+.LP
+The reply message to a request message has enough information to
+distinguish the following error conditions:
+.IP 1.
+The remote implementation of RPC does speak protocol version 2.
+The lowest and highest supported RPC version numbers are returned.
+.IP 2.
+The remote program is not available on the remote system.
+.IP 3.
+The remote program does not support the requested version number.
+The lowest and highest supported remote program version numbers are
+returned.
+.IP 4.
+The requested procedure number does not exist. (This is usually a
+caller side protocol or programming error.)
+.IP 5.
+The parameters to the remote procedure appear to be garbage from the
+server's point of view. (Again, this is usually caused by a
+disagreement about the protocol between client and service.)
+.NH 2
+\&Authentication
+.LP
+Provisions for authentication of caller to service and vice-versa are
+provided as a part of the RPC protocol. The call message has two
+authentication fields, the credentials and verifier. The reply
+message has one authentication field, the response verifier. The RPC
+protocol specification defines all three fields to be the following
+opaque type:
+.DS
+.ft CW
+.vs 11
+enum auth_flavor {
+ AUTH_NULL = 0,
+ AUTH_UNIX = 1,
+ AUTH_SHORT = 2,
+ AUTH_DES = 3
+ /* \fIand more to be defined\fP */
+};
+
+struct opaque_auth {
+ auth_flavor flavor;
+ opaque body<400>;
+};
+.DE
+.LP
+In simple English, any
+.I opaque_auth
+structure is an
+.I auth_flavor
+enumeration followed by bytes which are opaque to the RPC protocol
+implementation.
+.LP
+The interpretation and semantics of the data contained within the
+authentication fields is specified by individual, independent
+authentication protocol specifications. (See
+\fIAuthentication Protocols\fP\,
+below, for definitions of the various authentication protocols.)
+.LP
+If authentication parameters were rejected, the response message
+contains information stating why they were rejected.
+.NH 2
+\&Program Number Assignment
+.LP
+Program numbers are given out in groups of
+.I 0x20000000
+(decimal 536870912) according to the following chart:
+.TS
+box tab (&) ;
+lfI lfI
+rfL cfI .
+Program Numbers&Description
+_
+.sp .5
+0 - 1fffffff&Defined by Sun
+20000000 - 3fffffff&Defined by user
+40000000 - 5fffffff&Transient
+60000000 - 7fffffff&Reserved
+80000000 - 9fffffff&Reserved
+a0000000 - bfffffff&Reserved
+c0000000 - dfffffff&Reserved
+e0000000 - ffffffff&Reserved
+.TE
+.LP
+The first group is a range of numbers administered by Sun
+Microsystems and should be identical for all sites. The second range
+is for applications peculiar to a particular site. This range is
+intended primarily for debugging new programs. When a site develops
+an application that might be of general interest, that application
+should be given an assigned number in the first range. The third
+group is for applications that generate program numbers dynamically.
+The final groups are reserved for future use, and should not be used.
+.NH 2
+\&Other Uses of the RPC Protocol
+.LP
+The intended use of this protocol is for calling remote procedures.
+That is, each call message is matched with a response message.
+However, the protocol itself is a message-passing protocol with which
+other (non-RPC) protocols can be implemented. Sun currently uses, or
+perhaps abuses, the RPC message protocol for the following two
+(non-RPC) protocols: batching (or pipelining) and broadcast RPC.
+These two protocols are discussed but not defined below.
+.NH 3
+\&Batching
+.LP
+Batching allows a client to send an arbitrarily large sequence of
+call messages to a server; batching typically uses reliable byte
+stream protocols (like TCP/IP) for its transport. In the case of
+batching, the client never waits for a reply from the server, and the
+server does not send replies to batch requests. A sequence of batch
+calls is usually terminated by a legitimate RPC in order to flush the
+pipeline (with positive acknowledgement).
+.NH 3
+\&Broadcast RPC
+.LP
+In broadcast RPC-based protocols, the client sends a broadcast packet
+to the network and waits for numerous replies. Broadcast RPC uses
+unreliable, packet-based protocols (like UDP/IP) as its transports.
+Servers that support broadcast protocols only respond when the
+request is successfully processed, and are silent in the face of
+errors. Broadcast RPC uses the Port Mapper RPC service to achieve
+its semantics. See the \fIPort Mapper Program Protocol\fP\, below,
+for more information.
+.KS
+.NH 1
+\&The RPC Message Protocol
+.LP
+This section defines the RPC message protocol in the XDR data
+description language. The message is defined in a top-down style.
+.ie t .DS
+.el .DS L
+.ft CW
+enum msg_type {
+ CALL = 0,
+ REPLY = 1
+};
+
+.ft I
+/*
+* A reply to a call message can take on two forms:
+* The message was either accepted or rejected.
+*/
+.ft CW
+enum reply_stat {
+ MSG_ACCEPTED = 0,
+ MSG_DENIED = 1
+};
+
+.ft I
+/*
+* Given that a call message was accepted, the following is the
+* status of an attempt to call a remote procedure.
+*/
+.ft CW
+enum accept_stat {
+ SUCCESS = 0, /* \fIRPC executed successfully \fP*/
+ PROG_UNAVAIL = 1, /* \fIremote hasn't exported program \fP*/
+ PROG_MISMATCH = 2, /* \fIremote can't support version # \fP*/
+ PROC_UNAVAIL = 3, /* \fIprogram can't support procedure \fP*/
+ GARBAGE_ARGS = 4 /* \fIprocedure can't decode params \fP*/
+};
+.DE
+.ie t .DS
+.el .DS L
+.ft I
+/*
+* Reasons why a call message was rejected:
+*/
+.ft CW
+enum reject_stat {
+ RPC_MISMATCH = 0, /* \fIRPC version number != 2 \fP*/
+ AUTH_ERROR = 1 /* \fIremote can't authenticate caller \fP*/
+};
+
+.ft I
+/*
+* Why authentication failed:
+*/
+.ft CW
+enum auth_stat {
+ AUTH_BADCRED = 1, /* \fIbad credentials \fP*/
+ AUTH_REJECTEDCRED = 2, /* \fIclient must begin new session \fP*/
+ AUTH_BADVERF = 3, /* \fIbad verifier \fP*/
+ AUTH_REJECTEDVERF = 4, /* \fIverifier expired or replayed \fP*/
+ AUTH_TOOWEAK = 5 /* \fIrejected for security reasons \fP*/
+};
+.DE
+.KE
+.ie t .DS
+.el .DS L
+.ft I
+/*
+* The RPC message:
+* All messages start with a transaction identifier, xid,
+* followed by a two-armed discriminated union. The union's
+* discriminant is a msg_type which switches to one of the two
+* types of the message. The xid of a \fIREPLY\fP message always
+* matches that of the initiating \fICALL\fP message. NB: The xid
+* field is only used for clients matching reply messages with
+* call messages or for servers detecting retransmissions; the
+* service side cannot treat this id as any type of sequence
+* number.
+*/
+.ft CW
+struct rpc_msg {
+ unsigned int xid;
+ union switch (msg_type mtype) {
+ case CALL:
+ call_body cbody;
+ case REPLY:
+ reply_body rbody;
+ } body;
+};
+.DE
+.ie t .DS
+.el .DS L
+.ft I
+/*
+* Body of an RPC request call:
+* In version 2 of the RPC protocol specification, rpcvers must
+* be equal to 2. The fields prog, vers, and proc specify the
+* remote program, its version number, and the procedure within
+* the remote program to be called. After these fields are two
+* authentication parameters: cred (authentication credentials)
+* and verf (authentication verifier). The two authentication
+* parameters are followed by the parameters to the remote
+* procedure, which are specified by the specific program
+* protocol.
+*/
+.ft CW
+struct call_body {
+ unsigned int rpcvers; /* \fImust be equal to two (2) \fP*/
+ unsigned int prog;
+ unsigned int vers;
+ unsigned int proc;
+ opaque_auth cred;
+ opaque_auth verf;
+ /* \fIprocedure specific parameters start here \fP*/
+};
+.DE
+.ie t .DS
+.el .DS L
+.ft I
+/*
+* Body of a reply to an RPC request:
+* The call message was either accepted or rejected.
+*/
+.ft CW
+union reply_body switch (reply_stat stat) {
+ case MSG_ACCEPTED:
+ accepted_reply areply;
+ case MSG_DENIED:
+ rejected_reply rreply;
+} reply;
+.DE
+.ie t .DS
+.el .DS L
+.ft I
+/*
+* Reply to an RPC request that was accepted by the server:
+* there could be an error even though the request was accepted.
+* The first field is an authentication verifier that the server
+* generates in order to validate itself to the caller. It is
+* followed by a union whose discriminant is an enum
+* accept_stat. The \fISUCCESS\fP arm of the union is protocol
+* specific. The \fIPROG_UNAVAIL\fP, \fIPROC_UNAVAIL\fP, and \fIGARBAGE_ARGP\fP
+* arms of the union are void. The \fIPROG_MISMATCH\fP arm specifies
+* the lowest and highest version numbers of the remote program
+* supported by the server.
+*/
+.ft CW
+struct accepted_reply {
+ opaque_auth verf;
+ union switch (accept_stat stat) {
+ case SUCCESS:
+ opaque results[0];
+ /* \fIprocedure-specific results start here\fP */
+ case PROG_MISMATCH:
+ struct {
+ unsigned int low;
+ unsigned int high;
+ } mismatch_info;
+ default:
+.ft I
+ /*
+ * Void. Cases include \fIPROG_UNAVAIL, PROC_UNAVAIL\fP,
+ * and \fIGARBAGE_ARGS\fP.
+ */
+.ft CW
+ void;
+ } reply_data;
+};
+.DE
+.ie t .DS
+.el .DS L
+.ft I
+/*
+* Reply to an RPC request that was rejected by the server:
+* The request can be rejected for two reasons: either the
+* server is not running a compatible version of the RPC
+* protocol (\fIRPC_MISMATCH\fP), or the server refuses to
+* authenticate the caller (\fIAUTH_ERROR\fP). In case of an RPC
+* version mismatch, the server returns the lowest and highest
+* supported RPC version numbers. In case of refused
+* authentication, failure status is returned.
+*/
+.ft CW
+union rejected_reply switch (reject_stat stat) {
+ case RPC_MISMATCH:
+ struct {
+ unsigned int low;
+ unsigned int high;
+ } mismatch_info;
+ case AUTH_ERROR:
+ auth_stat stat;
+};
+.DE
+.NH 1
+\&Authentication Protocols
+.LP
+As previously stated, authentication parameters are opaque, but
+open-ended to the rest of the RPC protocol. This section defines
+some "flavors" of authentication implemented at (and supported by)
+Sun. Other sites are free to invent new authentication types, with
+the same rules of flavor number assignment as there is for program
+number assignment.
+.NH 2
+\&Null Authentication
+.LP
+Often calls must be made where the caller does not know who he is or
+the server does not care who the caller is. In this case, the flavor
+value (the discriminant of the \fIopaque_auth\fP's union) of the RPC
+message's credentials, verifier, and response verifier is
+.I AUTH_NULL .
+The bytes of the opaque_auth's body are undefined.
+It is recommended that the opaque length be zero.
+.NH 2
+\&UNIX Authentication
+.LP
+The caller of a remote procedure may wish to identify himself as he
+is identified on a UNIX system. The value of the credential's
+discriminant of an RPC call message is
+.I AUTH_UNIX .
+The bytes of
+the credential's opaque body encode the following structure:
+.DS
+.ft CW
+struct auth_unix {
+ unsigned int stamp;
+ string machinename<255>;
+ unsigned int uid;
+ unsigned int gid;
+ unsigned int gids<10>;
+};
+.DE
+The
+.I stamp
+is an arbitrary ID which the caller machine may
+generate. The
+.I machinename
+is the name of the caller's machine (like "krypton"). The
+.I uid
+is the caller's effective user ID. The
+.I gid
+is the caller's effective group ID. The
+.I gids
+is a
+counted array of groups which contain the caller as a member. The
+verifier accompanying the credentials should be of
+.I AUTH_NULL
+(defined above).
+.LP
+The value of the discriminant of the response verifier received in
+the reply message from the server may be
+.I AUTH_NULL
+or
+.I AUTH_SHORT .
+In the case of
+.I AUTH_SHORT ,
+the bytes of the response verifier's string encode an opaque
+structure. This new opaque structure may now be passed to the server
+instead of the original
+.I AUTH_UNIX
+flavor credentials. The server keeps a cache which maps shorthand
+opaque structures (passed back by way of an
+.I AUTH_SHORT
+style response verifier) to the original credentials of the caller.
+The caller can save network bandwidth and server cpu cycles by using
+the new credentials.
+.LP
+The server may flush the shorthand opaque structure at any time. If
+this happens, the remote procedure call message will be rejected due
+to an authentication error. The reason for the failure will be
+.I AUTH_REJECTEDCRED .
+At this point, the caller may wish to try the original
+.I AUTH_UNIX
+style of credentials.
+.KS
+.NH 2
+\&DES Authentication
+.LP
+UNIX authentication suffers from two major problems:
+.IP 1.
+The naming is too UNIX-system oriented.
+.IP 2.
+There is no verifier, so credentials can easily be faked.
+.LP
+DES authentication attempts to fix these two problems.
+.KE
+.NH 3
+\&Naming
+.LP
+The first problem is handled by addressing the caller by a simple
+string of characters instead of by an operating system specific
+integer. This string of characters is known as the "netname" or
+network name of the caller. The server is not allowed to interpret
+the contents of the caller's name in any other way except to
+identify the caller. Thus, netnames should be unique for every
+caller in the internet.
+.LP
+It is up to each operating system's implementation of DES
+authentication to generate netnames for its users that insure this
+uniqueness when they call upon remote servers. Operating systems
+already know how to distinguish users local to their systems. It is
+usually a simple matter to extend this mechanism to the network.
+For example, a UNIX user at Sun with a user ID of 515 might be
+assigned the following netname: "unix.515@sun.com". This netname
+contains three items that serve to insure it is unique. Going
+backwards, there is only one naming domain called "sun.com" in the
+internet. Within this domain, there is only one UNIX user with
+user ID 515. However, there may be another user on another
+operating system, for example VMS, within the same naming domain
+that, by coincidence, happens to have the same user ID. To insure
+that these two users can be distinguished we add the operating
+system name. So one user is "unix.515@sun.com" and the other is
+"vms.515@sun.com".
+.LP
+The first field is actually a naming method rather than an
+operating system name. It just happens that today there is almost
+a one-to-one correspondence between naming methods and operating
+systems. If the world could agree on a naming standard, the first
+field could be the name of that standard, instead of an operating
+system name.
+.LP
+.NH 3
+\&DES Authentication Verifiers
+.LP
+Unlike UNIX authentication, DES authentication does have a verifier
+so the server can validate the client's credential (and
+vice-versa). The contents of this verifier is primarily an
+encrypted timestamp. The server can decrypt this timestamp, and if
+it is close to what the real time is, then the client must have
+encrypted it correctly. The only way the client could encrypt it
+correctly is to know the "conversation key" of the RPC session. And
+if the client knows the conversation key, then it must be the real
+client.
+.LP
+The conversation key is a DES [5] key which the client generates
+and notifies the server of in its first RPC call. The conversation
+key is encrypted using a public key scheme in this first
+transaction. The particular public key scheme used in DES
+authentication is Diffie-Hellman [3] with 192-bit keys. The
+details of this encryption method are described later.
+.LP
+The client and the server need the same notion of the current time
+in order for all of this to work. If network time synchronization
+cannot be guaranteed, then client can synchronize with the server
+before beginning the conversation, perhaps by consulting the
+Internet Time Server (TIME[4]).
+.LP
+The way a server determines if a client timestamp is valid is
+somewhat complicated. For any other transaction but the first, the
+server just checks for two things:
+.IP 1.
+the timestamp is greater than the one previously seen from the
+same client.
+.IP 2.
+the timestamp has not expired.
+.LP
+A timestamp is expired if the server's time is later than the sum
+of the client's timestamp plus what is known as the client's
+"window". The "window" is a number the client passes (encrypted)
+to the server in its first transaction. You can think of it as a
+lifetime for the credential.
+.LP
+This explains everything but the first transaction. In the first
+transaction, the server checks only that the timestamp has not
+expired. If this was all that was done though, then it would be
+quite easy for the client to send random data in place of the
+timestamp with a fairly good chance of succeeding. As an added
+check, the client sends an encrypted item in the first transaction
+known as the "window verifier" which must be equal to the window
+minus 1, or the server will reject the credential.
+.LP
+The client too must check the verifier returned from the server to
+be sure it is legitimate. The server sends back to the client the
+encrypted timestamp it received from the client, minus one second.
+If the client gets anything different than this, it will reject it.
+.LP
+.NH 3
+\&Nicknames and Clock Synchronization
+.LP
+After the first transaction, the server's DES authentication
+subsystem returns in its verifier to the client an integer
+"nickname" which the client may use in its further transactions
+instead of passing its netname, encrypted DES key and window every
+time. The nickname is most likely an index into a table on the
+server which stores for each client its netname, decrypted DES key
+and window.
+.LP
+Though they originally were synchronized, the client's and server's
+clocks can get out of sync again. When this happens the client RPC
+subsystem most likely will get back
+.I RPC_AUTHERROR
+at which point it should resynchronize.
+.LP
+A client may still get the
+.I RPC_AUTHERROR
+error even though it is
+synchronized with the server. The reason is that the server's
+nickname table is a limited size, and it may flush entries whenever
+it wants. A client should resend its original credential in this
+case and the server will give it a new nickname. If a server
+crashes, the entire nickname table gets flushed, and all clients
+will have to resend their original credentials.
+.KS
+.NH 3
+\&DES Authentication Protocol (in XDR language)
+.ie t .DS
+.el .DS L
+.ft I
+/*
+* There are two kinds of credentials: one in which the client uses
+* its full network name, and one in which it uses its "nickname"
+* (just an unsigned integer) given to it by the server. The
+* client must use its fullname in its first transaction with the
+* server, in which the server will return to the client its
+* nickname. The client may use its nickname in all further
+* transactions with the server. There is no requirement to use the
+* nickname, but it is wise to use it for performance reasons.
+*/
+.ft CW
+enum authdes_namekind {
+ ADN_FULLNAME = 0,
+ ADN_NICKNAME = 1
+};
+
+.ft I
+/*
+* A 64-bit block of encrypted DES data
+*/
+.ft CW
+typedef opaque des_block[8];
+
+.ft I
+/*
+* Maximum length of a network user's name
+*/
+.ft CW
+const MAXNETNAMELEN = 255;
+
+.ft I
+/*
+* A fullname contains the network name of the client, an encrypted
+* conversation key and the window. The window is actually a
+* lifetime for the credential. If the time indicated in the
+* verifier timestamp plus the window has past, then the server
+* should expire the request and not grant it. To insure that
+* requests are not replayed, the server should insist that
+* timestamps are greater than the previous one seen, unless it is
+* the first transaction. In the first transaction, the server
+* checks instead that the window verifier is one less than the
+* window.
+*/
+.ft CW
+struct authdes_fullname {
+string name<MAXNETNAMELEN>; /* \fIname of client \f(CW*/
+des_block key; /* \fIPK encrypted conversation key \f(CW*/
+unsigned int window; /* \fIencrypted window \f(CW*/
+};
+
+.ft I
+/*
+* A credential is either a fullname or a nickname
+*/
+.ft CW
+union authdes_cred switch (authdes_namekind adc_namekind) {
+ case ADN_FULLNAME:
+ authdes_fullname adc_fullname;
+ case ADN_NICKNAME:
+ unsigned int adc_nickname;
+};
+
+.ft I
+/*
+* A timestamp encodes the time since midnight, January 1, 1970.
+*/
+.ft CW
+struct timestamp {
+ unsigned int seconds; /* \fIseconds \fP*/
+ unsigned int useconds; /* \fIand microseconds \fP*/
+};
+
+.ft I
+/*
+* Verifier: client variety
+* The window verifier is only used in the first transaction. In
+* conjunction with a fullname credential, these items are packed
+* into the following structure before being encrypted:
+*
+* \f(CWstruct {\fP
+* \f(CWadv_timestamp; \fP-- one DES block
+* \f(CWadc_fullname.window; \fP-- one half DES block
+* \f(CWadv_winverf; \fP-- one half DES block
+* \f(CW}\fP
+* This structure is encrypted using CBC mode encryption with an
+* input vector of zero. All other encryptions of timestamps use
+* ECB mode encryption.
+*/
+.ft CW
+struct authdes_verf_clnt {
+ timestamp adv_timestamp; /* \fIencrypted timestamp \fP*/
+ unsigned int adv_winverf; /* \fIencrypted window verifier \fP*/
+};
+
+.ft I
+/*
+* Verifier: server variety
+* The server returns (encrypted) the same timestamp the client
+* gave it minus one second. It also tells the client its nickname
+* to be used in future transactions (unencrypted).
+*/
+.ft CW
+struct authdes_verf_svr {
+timestamp adv_timeverf; /* \fIencrypted verifier \fP*/
+unsigned int adv_nickname; /* \fInew nickname for client \fP*/
+};
+.DE
+.KE
+.NH 3
+\&Diffie-Hellman Encryption
+.LP
+In this scheme, there are two constants,
+.I BASE
+and
+.I MODULUS .
+The
+particular values Sun has chosen for these for the DES
+authentication protocol are:
+.ie t .DS
+.el .DS L
+.ft CW
+const BASE = 3;
+const MODULUS =
+ "d4a0ba0250b6fd2ec626e7efd637df76c716e22d0944b88b"; /* \fIhex \fP*/
+.DE
+.ft R
+The way this scheme works is best explained by an example. Suppose
+there are two people "A" and "B" who want to send encrypted
+messages to each other. So, A and B both generate "secret" keys at
+random which they do not reveal to anyone. Let these keys be
+represented as SK(A) and SK(B). They also publish in a public
+directory their "public" keys. These keys are computed as follows:
+.ie t .DS
+.el .DS L
+.ft CW
+PK(A) = ( BASE ** SK(A) ) mod MODULUS
+PK(B) = ( BASE ** SK(B) ) mod MODULUS
+.DE
+.ft R
+The "**" notation is used here to represent exponentiation. Now,
+both A and B can arrive at the "common" key between them,
+represented here as CK(A, B), without revealing their secret keys.
+.LP
+A computes:
+.ie t .DS
+.el .DS L
+.ft CW
+CK(A, B) = ( PK(B) ** SK(A)) mod MODULUS
+.DE
+.ft R
+while B computes:
+.ie t .DS
+.el .DS L
+.ft CW
+CK(A, B) = ( PK(A) ** SK(B)) mod MODULUS
+.DE
+.ft R
+These two can be shown to be equivalent:
+.ie t .DS
+.el .DS L
+.ft CW
+(PK(B) ** SK(A)) mod MODULUS = (PK(A) ** SK(B)) mod MODULUS
+.DE
+.ft R
+We drop the "mod MODULUS" parts and assume modulo arithmetic to
+simplify things:
+.ie t .DS
+.el .DS L
+.ft CW
+PK(B) ** SK(A) = PK(A) ** SK(B)
+.DE
+.ft R
+Then, replace PK(B) by what B computed earlier and likewise for
+PK(A).
+.ie t .DS
+.el .DS L
+.ft CW
+((BASE ** SK(B)) ** SK(A) = (BASE ** SK(A)) ** SK(B)
+.DE
+.ft R
+which leads to:
+.ie t .DS
+.el .DS L
+.ft CW
+BASE ** (SK(A) * SK(B)) = BASE ** (SK(A) * SK(B))
+.DE
+.ft R
+This common key CK(A, B) is not used to encrypt the timestamps used
+in the protocol. Rather, it is used only to encrypt a conversation
+key which is then used to encrypt the timestamps. The reason for
+doing this is to use the common key as little as possible, for fear
+that it could be broken. Breaking the conversation key is a far
+less serious offense, since conversations are relatively
+short-lived.
+.LP
+The conversation key is encrypted using 56-bit DES keys, yet the
+common key is 192 bits. To reduce the number of bits, 56 bits are
+selected from the common key as follows. The middle-most 8-bytes
+are selected from the common key, and then parity is added to the
+lower order bit of each byte, producing a 56-bit key with 8 bits of
+parity.
+.KS
+.NH 1
+\&Record Marking Standard
+.LP
+When RPC messages are passed on top of a byte stream protocol (like
+TCP/IP), it is necessary, or at least desirable, to delimit one
+message from another in order to detect and possibly recover from
+user protocol errors. This is called record marking (RM). Sun uses
+this RM/TCP/IP transport for passing RPC messages on TCP streams.
+One RPC message fits into one RM record.
+.LP
+A record is composed of one or more record fragments. A record
+fragment is a four-byte header followed by 0 to (2**31) - 1 bytes of
+fragment data. The bytes encode an unsigned binary number; as with
+XDR integers, the byte order is from highest to lowest. The number
+encodes two values\(ema boolean which indicates whether the fragment
+is the last fragment of the record (bit value 1 implies the fragment
+is the last fragment) and a 31-bit unsigned binary value which is the
+length in bytes of the fragment's data. The boolean value is the
+highest-order bit of the header; the length is the 31 low-order bits.
+(Note that this record specification is NOT in XDR standard form!)
+.KE
+.KS
+.NH 1
+\&The RPC Language
+.LP
+Just as there was a need to describe the XDR data-types in a formal
+language, there is also need to describe the procedures that operate
+on these XDR data-types in a formal language as well. We use the RPC
+Language for this purpose. It is an extension to the XDR language.
+The following example is used to describe the essence of the
+language.
+.NH 2
+\&An Example Service Described in the RPC Language
+.LP
+Here is an example of the specification of a simple ping program.
+.ie t .DS
+.el .DS L
+.vs 11
+.ft I
+/*
+* Simple ping program
+*/
+.ft CW
+program PING_PROG {
+ /* \fILatest and greatest version\fP */
+ version PING_VERS_PINGBACK {
+ void
+ PINGPROC_NULL(void) = 0;
+
+.ft I
+ /*
+ * Ping the caller, return the round-trip time
+ * (in microseconds). Returns -1 if the operation
+ * timed out.
+ */
+.ft CW
+ int
+ PINGPROC_PINGBACK(void) = 1;
+} = 2;
+
+.ft I
+/*
+* Original version
+*/
+.ft CW
+version PING_VERS_ORIG {
+ void
+ PINGPROC_NULL(void) = 0;
+ } = 1;
+} = 1;
+
+const PING_VERS = 2; /* \fIlatest version \fP*/
+.vs
+.DE
+.KE
+.LP
+The first version described is
+.I PING_VERS_PINGBACK
+with two procedures,
+.I PINGPROC_NULL
+and
+.I PINGPROC_PINGBACK .
+.I PINGPROC_NULL
+takes no arguments and returns no results, but it is useful for
+computing round-trip times from the client to the server and back
+again. By convention, procedure 0 of any RPC protocol should have
+the same semantics, and never require any kind of authentication.
+The second procedure is used for the client to have the server do a
+reverse ping operation back to the client, and it returns the amount
+of time (in microseconds) that the operation used. The next version,
+.I PING_VERS_ORIG ,
+is the original version of the protocol
+and it does not contain
+.I PINGPROC_PINGBACK
+procedure. It is useful
+for compatibility with old client programs, and as this program
+matures it may be dropped from the protocol entirely.
+.KS
+.NH 2
+\&The RPC Language Specification
+.LP
+The RPC language is identical to the XDR language, except for the
+added definition of a
+.I program-def
+described below.
+.DS
+.ft CW
+program-def:
+ "program" identifier "{"
+ version-def
+ version-def *
+ "}" "=" constant ";"
+
+version-def:
+ "version" identifier "{"
+ procedure-def
+ procedure-def *
+ "}" "=" constant ";"
+
+procedure-def:
+ type-specifier identifier "(" type-specifier ")"
+ "=" constant ";"
+.DE
+.KE
+.NH 2
+\&Syntax Notes
+.IP 1.
+The following keywords are added and cannot be used as
+identifiers: "program" and "version";
+.IP 2.
+A version name cannot occur more than once within the scope of
+a program definition. Nor can a version number occur more than once
+within the scope of a program definition.
+.IP 3.
+A procedure name cannot occur more than once within the scope
+of a version definition. Nor can a procedure number occur more than
+once within the scope of version definition.
+.IP 4.
+Program identifiers are in the same name space as constant and
+type identifiers.
+.IP 5.
+Only unsigned constants can be assigned to programs, versions
+and procedures.
+.NH 1
+\&Port Mapper Program Protocol
+.LP
+The port mapper program maps RPC program and version numbers to
+transport-specific port numbers. This program makes dynamic binding
+of remote programs possible.
+.LP
+This is desirable because the range of reserved port numbers is very
+small and the number of potential remote programs is very large. By
+running only the port mapper on a reserved port, the port numbers of
+other remote programs can be ascertained by querying the port mapper.
+.LP
+The port mapper also aids in broadcast RPC. A given RPC program will
+usually have different port number bindings on different machines, so
+there is no way to directly broadcast to all of these programs. The
+port mapper, however, does have a fixed port number. So, to
+broadcast to a given program, the client actually sends its message
+to the port mapper located at the broadcast address. Each port
+mapper that picks up the broadcast then calls the local service
+specified by the client. When the port mapper gets the reply from
+the local service, it sends the reply on back to the client.
+.KS
+.NH 2
+\&Port Mapper Protocol Specification (in RPC Language)
+.ie t .DS
+.el .DS L
+.ft CW
+.vs 11
+const PMAP_PORT = 111; /* \fIportmapper port number \fP*/
+
+.ft I
+/*
+* A mapping of (program, version, protocol) to port number
+*/
+.ft CW
+struct mapping {
+ unsigned int prog;
+ unsigned int vers;
+ unsigned int prot;
+ unsigned int port;
+};
+
+.ft I
+/*
+* Supported values for the "prot" field
+*/
+.ft CW
+const IPPROTO_TCP = 6; /* \fIprotocol number for TCP/IP \fP*/
+const IPPROTO_UDP = 17; /* \fIprotocol number for UDP/IP \fP*/
+
+.ft I
+/*
+* A list of mappings
+*/
+.ft CW
+struct *pmaplist {
+ mapping map;
+ pmaplist next;
+};
+.vs
+.DE
+.ie t .DS
+.el .DS L
+.vs 11
+.ft I
+/*
+* Arguments to callit
+*/
+.ft CW
+struct call_args {
+ unsigned int prog;
+ unsigned int vers;
+ unsigned int proc;
+ opaque args<>;
+};
+
+.ft I
+/*
+* Results of callit
+*/
+.ft CW
+struct call_result {
+ unsigned int port;
+ opaque res<>;
+};
+.vs
+.DE
+.KE
+.ie t .DS
+.el .DS L
+.vs 11
+.ft I
+/*
+* Port mapper procedures
+*/
+.ft CW
+program PMAP_PROG {
+ version PMAP_VERS {
+ void
+ PMAPPROC_NULL(void) = 0;
+
+ bool
+ PMAPPROC_SET(mapping) = 1;
+
+ bool
+ PMAPPROC_UNSET(mapping) = 2;
+
+ unsigned int
+ PMAPPROC_GETPORT(mapping) = 3;
+
+ pmaplist
+ PMAPPROC_DUMP(void) = 4;
+
+ call_result
+ PMAPPROC_CALLIT(call_args) = 5;
+ } = 2;
+} = 100000;
+.vs
+.DE
+.NH 2
+\&Port Mapper Operation
+.LP
+The portmapper program currently supports two protocols (UDP/IP and
+TCP/IP). The portmapper is contacted by talking to it on assigned
+port number 111 (SUNRPC [8]) on either of these protocols. The
+following is a description of each of the portmapper procedures:
+.IP \fBPMAPPROC_NULL:\fP
+This procedure does no work. By convention, procedure zero of any
+protocol takes no parameters and returns no results.
+.IP \fBPMAPPROC_SET:\fP
+When a program first becomes available on a machine, it registers
+itself with the port mapper program on the same machine. The program
+passes its program number "prog", version number "vers", transport
+protocol number "prot", and the port "port" on which it awaits
+service request. The procedure returns a boolean response whose
+value is
+.I TRUE
+if the procedure successfully established the mapping and
+.I FALSE
+otherwise. The procedure refuses to establish
+a mapping if one already exists for the tuple "(prog, vers, prot)".
+.IP \fBPMAPPROC_UNSET:\fP
+When a program becomes unavailable, it should unregister itself with
+the port mapper program on the same machine. The parameters and
+results have meanings identical to those of
+.I PMAPPROC_SET .
+The protocol and port number fields of the argument are ignored.
+.IP \fBPMAPPROC_GETPORT:\fP
+Given a program number "prog", version number "vers", and transport
+protocol number "prot", this procedure returns the port number on
+which the program is awaiting call requests. A port value of zeros
+means the program has not been registered. The "port" field of the
+argument is ignored.
+.IP \fBPMAPPROC_DUMP:\fP
+This procedure enumerates all entries in the port mapper's database.
+The procedure takes no parameters and returns a list of program,
+version, protocol, and port values.
+.IP \fBPMAPPROC_CALLIT:\fP
+This procedure allows a caller to call another remote procedure on
+the same machine without knowing the remote procedure's port number.
+It is intended for supporting broadcasts to arbitrary remote programs
+via the well-known port mapper's port. The parameters "prog",
+"vers", "proc", and the bytes of "args" are the program number,
+version number, procedure number, and parameters of the remote
+procedure.
+.LP
+.B Note:
+.RS
+.IP 1.
+This procedure only sends a response if the procedure was
+successfully executed and is silent (no response) otherwise.
+.IP 2.
+The port mapper communicates with the remote program using UDP/IP
+only.
+.RE
+.LP
+The procedure returns the remote program's port number, and the bytes
+of results are the results of the remote procedure.
+.bp
+.NH 1
+\&References
+.LP
+[1] Birrell, Andrew D. & Nelson, Bruce Jay; "Implementing Remote
+Procedure Calls"; XEROX CSL-83-7, October 1983.
+.LP
+[2] Cheriton, D.; "VMTP: Versatile Message Transaction Protocol",
+Preliminary Version 0.3; Stanford University, January 1987.
+.LP
+[3] Diffie & Hellman; "New Directions in Cryptography"; IEEE
+Transactions on Information Theory IT-22, November 1976.
+.LP
+[4] Harrenstien, K.; "Time Server", RFC 738; Information Sciences
+Institute, October 1977.
+.LP
+[5] National Bureau of Standards; "Data Encryption Standard"; Federal
+Information Processing Standards Publication 46, January 1977.
+.LP
+[6] Postel, J.; "Transmission Control Protocol - DARPA Internet
+Program Protocol Specification", RFC 793; Information Sciences
+Institute, September 1981.
+.LP
+[7] Postel, J.; "User Datagram Protocol", RFC 768; Information Sciences
+Institute, August 1980.
+.LP
+[8] Reynolds, J. & Postel, J.; "Assigned Numbers", RFC 923; Information
+Sciences Institute, October 1984.
diff --git a/lib/libc/rpc/PSD.doc/rpcgen.ms b/lib/libc/rpc/PSD.doc/rpcgen.ms
new file mode 100644
index 0000000..e663e7f
--- /dev/null
+++ b/lib/libc/rpc/PSD.doc/rpcgen.ms
@@ -0,0 +1,1301 @@
+.\"
+.\" Must use -- tbl -- for this one
+.\"
+.\" @(#)rpcgen.ms 2.2 88/08/04 4.0 RPCSRC
+.\" $FreeBSD$
+.\"
+.de BT
+.if \\n%=1 .tl ''- % -''
+..
+.ND
+.\" prevent excess underlining in nroff
+.if n .fp 2 R
+.OH '\fBrpcgen\fP Programming Guide''Page %'
+.EH 'Page %''\fBrpcgen\fP Programming Guide'
+.if \n%=1 .bp
+.SH
+\&\fBrpcgen\fP Programming Guide
+.NH 0
+\&The \fBrpcgen\fP Protocol Compiler
+.IX rpcgen "" \fIrpcgen\fP "" PAGE MAJOR
+.LP
+.IX RPC "" "" \fIrpcgen\fP
+The details of programming applications to use Remote Procedure Calls
+can be overwhelming. Perhaps most daunting is the writing of the XDR
+routines necessary to convert procedure arguments and results into
+their network format and vice-versa.
+.LP
+Fortunately,
+.I rpcgen(1)
+exists to help programmers write RPC applications simply and directly.
+.I rpcgen
+does most of the dirty work, allowing programmers to debug
+the main features of their application, instead of requiring them to
+spend most of their time debugging their network interface code.
+.LP
+.I rpcgen
+is a compiler. It accepts a remote program interface definition written
+in a language, called RPC Language, which is similar to C. It produces a C
+language output which includes stub versions of the client routines, a
+server skeleton, XDR filter routines for both parameters and results, and a
+header file that contains common definitions. The client stubs interface
+with the RPC library and effectively hide the network from their callers.
+The server stub similarly hides the network from the server procedures that
+are to be invoked by remote clients.
+.I rpcgen 's
+output files can be compiled and linked in the usual way. The developer
+writes server procedures\(emin any language that observes Sun calling
+conventions\(emand links them with the server skeleton produced by
+.I rpcgen
+to get an executable server program. To use a remote program, a programmer
+writes an ordinary main program that makes local procedure calls to the
+client stubs produced by
+.I rpcgen .
+Linking this program with
+.I rpcgen 's
+stubs creates an executable program. (At present the main program must be
+written in C).
+.I rpcgen
+options can be used to suppress stub generation and to specify the transport
+to be used by the server stub.
+.LP
+Like all compilers,
+.I rpcgen
+reduces development time
+that would otherwise be spent coding and debugging low-level routines.
+All compilers, including
+.I rpcgen ,
+do this at a small cost in efficiency
+and flexibility. However, many compilers allow escape hatches for
+programmers to mix low-level code with high-level code.
+.I rpcgen
+is no exception. In speed-critical applications, hand-written routines
+can be linked with the
+.I rpcgen
+output without any difficulty. Also, one may proceed by using
+.I rpcgen
+output as a starting point, and then rewriting it as necessary.
+(If you need a discussion of RPC programming without
+.I rpcgen ,
+see the
+.I "Remote Procedure Call Programming Guide)\.
+.NH 1
+\&Converting Local Procedures into Remote Procedures
+.IX rpcgen "local procedures" \fIrpcgen\fP
+.IX rpcgen "remote procedures" \fIrpcgen\fP
+.LP
+Assume an application that runs on a single machine, one which we want
+to convert to run over the network. Here we will demonstrate such a
+conversion by way of a simple example\(ema program that prints a
+message to the console:
+.ie t .DS
+.el .DS L
+.ft I
+/*
+ * printmsg.c: print a message on the console
+ */
+.ft CW
+#include <stdio.h>
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ char *message;
+
+ if (argc < 2) {
+ fprintf(stderr, "usage: %s <message>\en", argv[0]);
+ exit(1);
+ }
+ message = argv[1];
+
+ if (!printmessage(message)) {
+ fprintf(stderr, "%s: couldn't print your message\en",
+ argv[0]);
+ exit(1);
+ }
+ printf("Message Delivered!\en");
+ exit(0);
+}
+.ft I
+/*
+ * Print a message to the console.
+ * Return a boolean indicating whether the message was actually printed.
+ */
+.ft CW
+printmessage(msg)
+ char *msg;
+{
+ FILE *f;
+
+ f = fopen("/dev/console", "w");
+ if (f == NULL) {
+ return (0);
+ }
+ fprintf(f, "%s\en", msg);
+ fclose(f);
+ return(1);
+}
+.DE
+.LP
+And then, of course:
+.ie t .DS
+.el .DS L
+.ft CW
+example% \fBcc printmsg.c -o printmsg\fP
+example% \fBprintmsg "Hello, there."\fP
+Message delivered!
+example%
+.DE
+.LP
+If
+.I printmessage()
+was turned into a remote procedure,
+then it could be called from anywhere in the network.
+Ideally, one would just like to stick a keyword like
+.I remote
+in front of a
+procedure to turn it into a remote procedure. Unfortunately,
+we have to live within the constraints of the C language, since
+it existed long before RPC did. But even without language
+support, it's not very difficult to make a procedure remote.
+.LP
+In general, it's necessary to figure out what the types are for
+all procedure inputs and outputs. In this case, we have a
+procedure
+.I printmessage()
+which takes a string as input, and returns an integer
+as output. Knowing this, we can write a protocol specification in RPC
+language that describes the remote version of
+.I printmessage ().
+Here it is:
+.ie t .DS
+.el .DS L
+.ft I
+/*
+ * msg.x: Remote message printing protocol
+ */
+.ft CW
+
+program MESSAGEPROG {
+ version MESSAGEVERS {
+ int PRINTMESSAGE(string) = 1;
+ } = 1;
+} = 99;
+.DE
+.LP
+Remote procedures are part of remote programs, so we actually declared
+an entire remote program here which contains the single procedure
+.I PRINTMESSAGE .
+This procedure was declared to be in version 1 of the
+remote program. No null procedure (procedure 0) is necessary because
+.I rpcgen
+generates it automatically.
+.LP
+Notice that everything is declared with all capital letters. This is
+not required, but is a good convention to follow.
+.LP
+Notice also that the argument type is \*Qstring\*U and not \*Qchar *\*U. This
+is because a \*Qchar *\*U in C is ambiguous. Programmers usually intend it
+to mean a null-terminated string of characters, but it could also
+represent a pointer to a single character or a pointer to an array of
+characters. In RPC language, a null-terminated string is
+unambiguously called a \*Qstring\*U.
+.LP
+There are just two more things to write. First, there is the remote
+procedure itself. Here's the definition of a remote procedure
+to implement the
+.I PRINTMESSAGE
+procedure we declared above:
+.ie t .DS
+.el .DS L
+.vs 11
+.ft I
+/*
+ * msg_proc.c: implementation of the remote procedure "printmessage"
+ */
+.ft CW
+
+#include <stdio.h>
+#include <rpc/rpc.h> /* \fIalways needed\fP */
+#include "msg.h" /* \fIneed this too: msg.h will be generated by rpcgen\fP */
+
+.ft I
+/*
+ * Remote verson of "printmessage"
+ */
+.ft CW
+int *
+printmessage_1(msg)
+ char **msg;
+{
+ static int result; /* \fImust be static!\fP */
+ FILE *f;
+
+ f = fopen("/dev/console", "w");
+ if (f == NULL) {
+ result = 0;
+ return (&result);
+ }
+ fprintf(f, "%s\en", *msg);
+ fclose(f);
+ result = 1;
+ return (&result);
+}
+.vs
+.DE
+.LP
+Notice here that the declaration of the remote procedure
+.I printmessage_1()
+differs from that of the local procedure
+.I printmessage()
+in three ways:
+.IP 1.
+It takes a pointer to a string instead of a string itself. This
+is true of all remote procedures: they always take pointers to their
+arguments rather than the arguments themselves.
+.IP 2.
+It returns a pointer to an integer instead of an integer itself. This is
+also generally true of remote procedures: they always return a pointer
+to their results.
+.IP 3.
+It has an \*Q_1\*U appended to its name. In general, all remote
+procedures called by
+.I rpcgen
+are named by the following rule: the name in the program definition
+(here
+.I PRINTMESSAGE )
+is converted to all
+lower-case letters, an underbar (\*Q_\*U) is appended to it, and
+finally the version number (here 1) is appended.
+.LP
+The last thing to do is declare the main client program that will call
+the remote procedure. Here it is:
+.ie t .DS
+.el .DS L
+.ft I
+/*
+ * rprintmsg.c: remote version of "printmsg.c"
+ */
+.ft CW
+#include <stdio.h>
+#include <rpc/rpc.h> /* \fIalways needed\fP */
+#include "msg.h" /* \fIneed this too: msg.h will be generated by rpcgen\fP */
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ CLIENT *cl;
+ int *result;
+ char *server;
+ char *message;
+
+ if (argc < 3) {
+ fprintf(stderr, "usage: %s host message\en", argv[0]);
+ exit(1);
+ }
+
+.ft I
+ /*
+ * Save values of command line arguments
+ */
+.ft CW
+ server = argv[1];
+ message = argv[2];
+
+.ft I
+ /*
+ * Create client "handle" used for calling \fIMESSAGEPROG\fP on the
+ * server designated on the command line. We tell the RPC package
+ * to use the "tcp" protocol when contacting the server.
+ */
+.ft CW
+ cl = clnt_create(server, MESSAGEPROG, MESSAGEVERS, "tcp");
+ if (cl == NULL) {
+.ft I
+ /*
+ * Couldn't establish connection with server.
+ * Print error message and die.
+ */
+.ft CW
+ clnt_pcreateerror(server);
+ exit(1);
+ }
+
+.ft I
+ /*
+ * Call the remote procedure "printmessage" on the server
+ */
+.ft CW
+ result = printmessage_1(&message, cl);
+ if (result == NULL) {
+.ft I
+ /*
+ * An error occurred while calling the server.
+ * Print error message and die.
+ */
+.ft CW
+ clnt_perror(cl, server);
+ exit(1);
+ }
+
+.ft I
+ /*
+ * Okay, we successfully called the remote procedure.
+ */
+.ft CW
+ if (*result == 0) {
+.ft I
+ /*
+ * Server was unable to print our message.
+ * Print error message and die.
+ */
+.ft CW
+ fprintf(stderr, "%s: %s couldn't print your message\en",
+ argv[0], server);
+ exit(1);
+ }
+
+.ft I
+ /*
+ * The message got printed on the server's console
+ */
+.ft CW
+ printf("Message delivered to %s!\en", server);
+}
+.DE
+There are two things to note here:
+.IP 1.
+.IX "client handle, used by rpcgen" "" "client handle, used by \fIrpcgen\fP"
+First a client \*Qhandle\*U is created using the RPC library routine
+.I clnt_create ().
+This client handle will be passed to the stub routines
+which call the remote procedure.
+.IP 2.
+The remote procedure
+.I printmessage_1()
+is called exactly the same way as it is declared in
+.I msg_proc.c
+except for the inserted client handle as the first argument.
+.LP
+Here's how to put all of the pieces together:
+.ie t .DS
+.el .DS L
+.ft CW
+example% \fBrpcgen msg.x\fP
+example% \fBcc rprintmsg.c msg_clnt.c -o rprintmsg\fP
+example% \fBcc msg_proc.c msg_svc.c -o msg_server\fP
+.DE
+Two programs were compiled here: the client program
+.I rprintmsg
+and the server program
+.I msg_server .
+Before doing this though,
+.I rpcgen
+was used to fill in the missing pieces.
+.LP
+Here is what
+.I rpcgen
+did with the input file
+.I msg.x :
+.IP 1.
+It created a header file called
+.I msg.h
+that contained
+.I #define 's
+for
+.I MESSAGEPROG ,
+.I MESSAGEVERS
+and
+.I PRINTMESSAGE
+for use in the other modules.
+.IP 2.
+It created client \*Qstub\*U routines in the
+.I msg_clnt.c
+file. In this case there is only one, the
+.I printmessage_1()
+that was referred to from the
+.I printmsg
+client program. The name of the output file for
+client stub routines is always formed in this way: if the name of the
+input file is
+.I FOO.x ,
+the client stubs output file is called
+.I FOO_clnt.c .
+.IP 3.
+It created the server program which calls
+.I printmessage_1()
+in
+.I msg_proc.c .
+This server program is named
+.I msg_svc.c .
+The rule for naming the server output file is similar to the
+previous one: for an input file called
+.I FOO.x ,
+the output server file is named
+.I FOO_svc.c .
+.LP
+Now we're ready to have some fun. First, copy the server to a
+remote machine and run it. For this example, the
+machine is called \*Qmoon\*U. Server processes are run in the
+background, because they never exit.
+.ie t .DS
+.el .DS L
+.ft CW
+moon% \fBmsg_server &\fP
+.DE
+Then on our local machine (\*Qsun\*U) we can print a message on \*Qmoon\*Us
+console.
+.ie t .DS
+.el .DS L
+.ft CW
+sun% \fBprintmsg moon "Hello, moon."\fP
+.DE
+The message will get printed to \*Qmoon\*Us console. You can print a
+message on anybody's console (including your own) with this program if
+you are able to copy the server to their machine and run it.
+.NH 1
+\&Generating XDR Routines
+.IX RPC "generating XDR routines"
+.LP
+The previous example only demonstrated the automatic generation of
+client and server RPC code.
+.I rpcgen
+may also be used to generate XDR routines, that is, the routines
+necessary to convert local data
+structures into network format and vice-versa. This example presents
+a complete RPC service\(ema remote directory listing service, which uses
+.I rpcgen
+not only to generate stub routines, but also to generate the XDR
+routines. Here is the protocol description file:
+.ie t .DS
+.el .DS L
+.ft I
+/*
+ * dir.x: Remote directory listing protocol
+ */
+.ft CW
+const MAXNAMELEN = 255; /* \fImaximum length of a directory entry\fP */
+
+typedef string nametype<MAXNAMELEN>; /* \fIa directory entry\fP */
+
+typedef struct namenode *namelist; /* \fIa link in the listing\fP */
+
+.ft I
+/*
+ * A node in the directory listing
+ */
+.ft CW
+struct namenode {
+ nametype name; /* \fIname of directory entry\fP */
+ namelist next; /* \fInext entry\fP */
+};
+
+.ft I
+/*
+ * The result of a READDIR operation.
+ */
+.ft CW
+union readdir_res switch (int errno) {
+case 0:
+ namelist list; /* \fIno error: return directory listing\fP */
+default:
+ void; /* \fIerror occurred: nothing else to return\fP */
+};
+
+.ft I
+/*
+ * The directory program definition
+ */
+.ft CW
+program DIRPROG {
+ version DIRVERS {
+ readdir_res
+ READDIR(nametype) = 1;
+ } = 1;
+} = 76;
+.DE
+.SH
+Note:
+.I
+Types (like
+.I readdir_res
+in the example above) can be defined using
+the \*Qstruct\*U, \*Qunion\*U and \*Qenum\*U keywords, but those keywords
+should not be used in subsequent declarations of variables of those types.
+For example, if you define a union \*Qfoo\*U, you should declare using
+only \*Qfoo\*U and not \*Qunion foo\*U. In fact,
+.I rpcgen
+compiles
+RPC unions into C structures and it is an error to declare them using the
+\*Qunion\*U keyword.
+.LP
+Running
+.I rpcgen
+on
+.I dir.x
+creates four output files. Three are the same as before: header file,
+client stub routines and server skeleton. The fourth are the XDR routines
+necessary for converting the data types we declared into XDR format and
+vice-versa. These are output in the file
+.I dir_xdr.c .
+.LP
+Here is the implementation of the
+.I READDIR
+procedure.
+.ie t .DS
+.el .DS L
+.vs 11
+.ft I
+/*
+ * dir_proc.c: remote readdir implementation
+ */
+.ft CW
+#include <rpc/rpc.h>
+#include <sys/dir.h>
+#include "dir.h"
+
+extern int errno;
+extern char *malloc();
+extern char *strdup();
+
+readdir_res *
+readdir_1(dirname)
+ nametype *dirname;
+{
+ DIR *dirp;
+ struct direct *d;
+ namelist nl;
+ namelist *nlp;
+ static readdir_res res; /* \fImust be static\fP! */
+
+.ft I
+ /*
+ * Open directory
+ */
+.ft CW
+ dirp = opendir(*dirname);
+ if (dirp == NULL) {
+ res.errno = errno;
+ return (&res);
+ }
+
+.ft I
+ /*
+ * Free previous result
+ */
+.ft CW
+ xdr_free(xdr_readdir_res, &res);
+
+.ft I
+ /*
+ * Collect directory entries.
+ * Memory allocated here will be freed by \fIxdr_free\fP
+ * next time \fIreaddir_1\fP is called
+ */
+.ft CW
+ nlp = &res.readdir_res_u.list;
+ while (d = readdir(dirp)) {
+ nl = *nlp = (namenode *) malloc(sizeof(namenode));
+ nl->name = strdup(d->d_name);
+ nlp = &nl->next;
+ }
+ *nlp = NULL;
+
+.ft I
+ /*
+ * Return the result
+ */
+.ft CW
+ res.errno = 0;
+ closedir(dirp);
+ return (&res);
+}
+.vs
+.DE
+Finally, there is the client side program to call the server:
+.ie t .DS
+.el .DS L
+.ft I
+/*
+ * rls.c: Remote directory listing client
+ */
+.ft CW
+#include <stdio.h>
+#include <rpc/rpc.h> /* \fIalways need this\fP */
+#include "dir.h" /* \fIwill be generated by rpcgen\fP */
+
+extern int errno;
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ CLIENT *cl;
+ char *server;
+ char *dir;
+ readdir_res *result;
+ namelist nl;
+
+
+ if (argc != 3) {
+ fprintf(stderr, "usage: %s host directory\en",
+ argv[0]);
+ exit(1);
+ }
+
+.ft I
+ /*
+ * Remember what our command line arguments refer to
+ */
+.ft CW
+ server = argv[1];
+ dir = argv[2];
+
+.ft I
+ /*
+ * Create client "handle" used for calling \fIMESSAGEPROG\fP on the
+ * server designated on the command line. We tell the RPC package
+ * to use the "tcp" protocol when contacting the server.
+ */
+.ft CW
+ cl = clnt_create(server, DIRPROG, DIRVERS, "tcp");
+ if (cl == NULL) {
+.ft I
+ /*
+ * Couldn't establish connection with server.
+ * Print error message and die.
+ */
+.ft CW
+ clnt_pcreateerror(server);
+ exit(1);
+ }
+
+.ft I
+ /*
+ * Call the remote procedure \fIreaddir\fP on the server
+ */
+.ft CW
+ result = readdir_1(&dir, cl);
+ if (result == NULL) {
+.ft I
+ /*
+ * An error occurred while calling the server.
+ * Print error message and die.
+ */
+.ft CW
+ clnt_perror(cl, server);
+ exit(1);
+ }
+
+.ft I
+ /*
+ * Okay, we successfully called the remote procedure.
+ */
+.ft CW
+ if (result->errno != 0) {
+.ft I
+ /*
+ * A remote system error occurred.
+ * Print error message and die.
+ */
+.ft CW
+ errno = result->errno;
+ perror(dir);
+ exit(1);
+ }
+
+.ft I
+ /*
+ * Successfully got a directory listing.
+ * Print it out.
+ */
+.ft CW
+ for (nl = result->readdir_res_u.list; nl != NULL;
+ nl = nl->next) {
+ printf("%s\en", nl->name);
+ }
+ exit(0);
+}
+.DE
+Compile everything, and run.
+.DS
+.ft CW
+sun% \fBrpcgen dir.x\fP
+sun% \fBcc rls.c dir_clnt.c dir_xdr.c -o rls\fP
+sun% \fBcc dir_svc.c dir_proc.c dir_xdr.c -o dir_svc\fP
+
+sun% \fBdir_svc &\fP
+
+moon% \fBrls sun /usr/pub\fP
+\&.
+\&..
+ascii
+eqnchar
+greek
+kbd
+marg8
+tabclr
+tabs
+tabs4
+moon%
+.DE
+.LP
+.IX "debugging with rpcgen" "" "debugging with \fIrpcgen\fP"
+A final note about
+.I rpcgen :
+The client program and the server procedure can be tested together
+as a single program by simply linking them with each other rather
+than with the client and server stubs. The procedure calls will be
+executed as ordinary local procedure calls and the program can be
+debugged with a local debugger such as
+.I dbx .
+When the program is working, the client program can be linked to
+the client stub produced by
+.I rpcgen
+and the server procedures can be linked to the server stub produced
+by
+.I rpcgen .
+.SH
+.I NOTE :
+\fIIf you do this, you may want to comment out calls to RPC library
+routines, and have client-side routines call server routines
+directly.\fP
+.LP
+.NH 1
+\&The C-Preprocessor
+.IX rpcgen "C-preprocessor" \fIrpcgen\fP
+.LP
+The C-preprocessor is run on all input files before they are
+compiled, so all the preprocessor directives are legal within a \*Q.x\*U
+file. Four symbols may be defined, depending upon which output file is
+getting generated. The symbols are:
+.TS
+box tab (&);
+lfI lfI
+lfL l .
+Symbol&Usage
+_
+RPC_HDR&for header-file output
+RPC_XDR&for XDR routine output
+RPC_SVC&for server-skeleton output
+RPC_CLNT&for client stub output
+.TE
+.LP
+Also,
+.I rpcgen
+does a little preprocessing of its own. Any line that
+begins with a percent sign is passed directly into the output file,
+without any interpretation of the line. Here is a simple example that
+demonstrates the preprocessing features.
+.ie t .DS
+.el .DS L
+.ft I
+/*
+ * time.x: Remote time protocol
+ */
+.ft CW
+program TIMEPROG {
+ version TIMEVERS {
+ unsigned int TIMEGET(void) = 1;
+ } = 1;
+} = 44;
+
+#ifdef RPC_SVC
+%int *
+%timeget_1()
+%{
+% static int thetime;
+%
+% thetime = time(0);
+% return (&thetime);
+%}
+#endif
+.DE
+The '%' feature is not generally recommended, as there is no guarantee
+that the compiler will stick the output where you intended.
+.NH 1
+\&\fBrpcgen\fP Programming Notes
+.IX rpcgen "other operations" \fIrpcgen\fP
+.sp
+.NH 2
+\&Timeout Changes
+.IX rpcgen "timeout changes" \fIrpcgen\fP
+.LP
+RPC sets a default timeout of 25 seconds for RPC calls when
+.I clnt_create()
+is used. This timeout may be changed using
+.I clnt_control()
+Here is a small code fragment to demonstrate use of
+.I clnt_control ():
+.ID
+struct timeval tv;
+CLIENT *cl;
+.sp .5
+cl = clnt_create("somehost", SOMEPROG, SOMEVERS, "tcp");
+if (cl == NULL) {
+ exit(1);
+}
+tv.tv_sec = 60; /* \fIchange timeout to 1 minute\fP */
+tv.tv_usec = 0;
+clnt_control(cl, CLSET_TIMEOUT, &tv);
+.DE
+.NH 2
+\&Handling Broadcast on the Server Side
+.IX "broadcast RPC"
+.IX rpcgen "broadcast RPC" \fIrpcgen\fP
+.LP
+When a procedure is known to be called via broadcast RPC,
+it is usually wise for the server to not reply unless it can provide
+some useful information to the client. This prevents the network
+from getting flooded by useless replies.
+.LP
+To prevent the server from replying, a remote procedure can
+return NULL as its result, and the server code generated by
+.I rpcgen
+will detect this and not send out a reply.
+.LP
+Here is an example of a procedure that replies only if it
+thinks it is an NFS server:
+.ID
+void *
+reply_if_nfsserver()
+{
+ char notnull; /* \fIjust here so we can use its address\fP */
+.sp .5
+ if (access("/etc/exports", F_OK) < 0) {
+ return (NULL); /* \fIprevent RPC from replying\fP */
+ }
+.ft I
+ /*
+ * return non-null pointer so RPC will send out a reply
+ */
+.ft L
+ return ((void *)&notnull);
+}
+.DE
+Note that if procedure returns type \*Qvoid *\*U, they must return a non-NULL
+pointer if they want RPC to reply for them.
+.NH 2
+\&Other Information Passed to Server Procedures
+.LP
+Server procedures will often want to know more about an RPC call
+than just its arguments. For example, getting authentication information
+is important to procedures that want to implement some level of security.
+This extra information is actually supplied to the server procedure as a
+second argument. Here is an example to demonstrate its use. What we've
+done here is rewrite the previous
+.I printmessage_1()
+procedure to only allow root users to print a message to the console.
+.ID
+int *
+printmessage_1(msg, rq)
+ char **msg;
+ struct svc_req *rq;
+{
+ static in result; /* \fIMust be static\fP */
+ FILE *f;
+ struct suthunix_parms *aup;
+.sp .5
+ aup = (struct authunix_parms *)rq->rq_clntcred;
+ if (aup->aup_uid != 0) {
+ result = 0;
+ return (&result);
+ }
+.sp
+.ft I
+ /*
+ * Same code as before.
+ */
+.ft L
+}
+.DE
+.NH 1
+\&RPC Language
+.IX RPCL
+.IX rpcgen "RPC Language" \fIrpcgen\fP
+.LP
+RPC language is an extension of XDR language. The sole extension is
+the addition of the
+.I program
+type. For a complete description of the XDR language syntax, see the
+.I "External Data Representation Standard: Protocol Specification"
+chapter. For a description of the RPC extensions to the XDR language,
+see the
+.I "Remote Procedure Calls: Protocol Specification"
+chapter.
+.LP
+However, XDR language is so close to C that if you know C, you know most
+of it already. We describe here the syntax of the RPC language,
+showing a few examples along the way. We also show how the various
+RPC and XDR type definitions get compiled into C type definitions in
+the output header file.
+.KS
+.NH 2
+Definitions
+\&
+.IX rpcgen definitions \fIrpcgen\fP
+.LP
+An RPC language file consists of a series of definitions.
+.DS L
+.ft CW
+ definition-list:
+ definition ";"
+ definition ";" definition-list
+.DE
+.KE
+It recognizes five types of definitions.
+.DS L
+.ft CW
+ definition:
+ enum-definition
+ struct-definition
+ union-definition
+ typedef-definition
+ const-definition
+ program-definition
+.DE
+.NH 2
+Structures
+\&
+.IX rpcgen structures \fIrpcgen\fP
+.LP
+An XDR struct is declared almost exactly like its C counterpart. It
+looks like the following:
+.DS L
+.ft CW
+ struct-definition:
+ "struct" struct-ident "{"
+ declaration-list
+ "}"
+
+ declaration-list:
+ declaration ";"
+ declaration ";" declaration-list
+.DE
+As an example, here is an XDR structure to a two-dimensional
+coordinate, and the C structure that it gets compiled into in the
+output header file.
+.DS
+.ft CW
+ struct coord { struct coord {
+ int x; --> int x;
+ int y; int y;
+ }; };
+ typedef struct coord coord;
+.DE
+The output is identical to the input, except for the added
+.I typedef
+at the end of the output. This allows one to use \*Qcoord\*U instead of
+\*Qstruct coord\*U when declaring items.
+.NH 2
+Unions
+\&
+.IX rpcgen unions \fIrpcgen\fP
+.LP
+XDR unions are discriminated unions, and look quite different from C
+unions. They are more analogous to Pascal variant records than they
+are to C unions.
+.DS L
+.ft CW
+ union-definition:
+ "union" union-ident "switch" "(" declaration ")" "{"
+ case-list
+ "}"
+
+ case-list:
+ "case" value ":" declaration ";"
+ "default" ":" declaration ";"
+ "case" value ":" declaration ";" case-list
+.DE
+Here is an example of a type that might be returned as the result of a
+\*Qread data\*U operation. If there is no error, return a block of data.
+Otherwise, don't return anything.
+.DS L
+.ft CW
+ union read_result switch (int errno) {
+ case 0:
+ opaque data[1024];
+ default:
+ void;
+ };
+.DE
+It gets compiled into the following:
+.DS L
+.ft CW
+ struct read_result {
+ int errno;
+ union {
+ char data[1024];
+ } read_result_u;
+ };
+ typedef struct read_result read_result;
+.DE
+Notice that the union component of the output struct has the name as
+the type name, except for the trailing \*Q_u\*U.
+.NH 2
+Enumerations
+\&
+.IX rpcgen enumerations \fIrpcgen\fP
+.LP
+XDR enumerations have the same syntax as C enumerations.
+.DS L
+.ft CW
+ enum-definition:
+ "enum" enum-ident "{"
+ enum-value-list
+ "}"
+
+ enum-value-list:
+ enum-value
+ enum-value "," enum-value-list
+
+ enum-value:
+ enum-value-ident
+ enum-value-ident "=" value
+.DE
+Here is a short example of an XDR enum, and the C enum that it gets
+compiled into.
+.DS L
+.ft CW
+ enum colortype { enum colortype {
+ RED = 0, RED = 0,
+ GREEN = 1, --> GREEN = 1,
+ BLUE = 2 BLUE = 2,
+ }; };
+ typedef enum colortype colortype;
+.DE
+.NH 2
+Typedef
+\&
+.IX rpcgen typedef \fIrpcgen\fP
+.LP
+XDR typedefs have the same syntax as C typedefs.
+.DS L
+.ft CW
+ typedef-definition:
+ "typedef" declaration
+.DE
+Here is an example that defines a
+.I fname_type
+used for declaring
+file name strings that have a maximum length of 255 characters.
+.DS L
+.ft CW
+typedef string fname_type<255>; --> typedef char *fname_type;
+.DE
+.NH 2
+Constants
+\&
+.IX rpcgen constants \fIrpcgen\fP
+.LP
+XDR constants symbolic constants that may be used wherever a
+integer constant is used, for example, in array size specifications.
+.DS L
+.ft CW
+ const-definition:
+ "const" const-ident "=" integer
+.DE
+For example, the following defines a constant
+.I DOZEN
+equal to 12.
+.DS L
+.ft CW
+ const DOZEN = 12; --> #define DOZEN 12
+.DE
+.NH 2
+Programs
+\&
+.IX rpcgen programs \fIrpcgen\fP
+.LP
+RPC programs are declared using the following syntax:
+.DS L
+.ft CW
+ program-definition:
+ "program" program-ident "{"
+ version-list
+ "}" "=" value
+
+ version-list:
+ version ";"
+ version ";" version-list
+
+ version:
+ "version" version-ident "{"
+ procedure-list
+ "}" "=" value
+
+ procedure-list:
+ procedure ";"
+ procedure ";" procedure-list
+
+ procedure:
+ type-ident procedure-ident "(" type-ident ")" "=" value
+.DE
+For example, here is the time protocol, revisited:
+.ie t .DS
+.el .DS L
+.ft I
+/*
+ * time.x: Get or set the time. Time is represented as number of seconds
+ * since 0:00, January 1, 1970.
+ */
+.ft CW
+program TIMEPROG {
+ version TIMEVERS {
+ unsigned int TIMEGET(void) = 1;
+ void TIMESET(unsigned) = 2;
+ } = 1;
+} = 44;
+.DE
+This file compiles into #defines in the output header file:
+.ie t .DS
+.el .DS L
+.ft CW
+#define TIMEPROG 44
+#define TIMEVERS 1
+#define TIMEGET 1
+#define TIMESET 2
+.DE
+.NH 2
+Declarations
+\&
+.IX rpcgen declarations \fIrpcgen\fP
+.LP
+In XDR, there are only four kinds of declarations.
+.DS L
+.ft CW
+ declaration:
+ simple-declaration
+ fixed-array-declaration
+ variable-array-declaration
+ pointer-declaration
+.DE
+\fB1) Simple declarations\fP are just like simple C declarations.
+.DS L
+.ft CW
+ simple-declaration:
+ type-ident variable-ident
+.DE
+Example:
+.DS L
+.ft CW
+ colortype color; --> colortype color;
+.DE
+\fB2) Fixed-length Array Declarations\fP are just like C array declarations:
+.DS L
+.ft CW
+ fixed-array-declaration:
+ type-ident variable-ident "[" value "]"
+.DE
+Example:
+.DS L
+.ft CW
+ colortype palette[8]; --> colortype palette[8];
+.DE
+\fB3) Variable-Length Array Declarations\fP have no explicit syntax
+in C, so XDR invents its own using angle-brackets.
+.DS L
+.ft CW
+variable-array-declaration:
+ type-ident variable-ident "<" value ">"
+ type-ident variable-ident "<" ">"
+.DE
+The maximum size is specified between the angle brackets. The size may
+be omitted, indicating that the array may be of any size.
+.DS L
+.ft CW
+ int heights<12>; /* \fIat most 12 items\fP */
+ int widths<>; /* \fIany number of items\fP */
+.DE
+Since variable-length arrays have no explicit syntax in C, these
+declarations are actually compiled into \*Qstruct\*Us. For example, the
+\*Qheights\*U declaration gets compiled into the following struct:
+.DS L
+.ft CW
+ struct {
+ u_int heights_len; /* \fI# of items in array\fP */
+ int *heights_val; /* \fIpointer to array\fP */
+ } heights;
+.DE
+Note that the number of items in the array is stored in the \*Q_len\*U
+component and the pointer to the array is stored in the \*Q_val\*U
+component. The first part of each of these component's names is the
+same as the name of the declared XDR variable.
+.LP
+\fB4) Pointer Declarations\fP are made in
+XDR exactly as they are in C. You can't
+really send pointers over the network, but you can use XDR pointers
+for sending recursive data types such as lists and trees. The type is
+actually called \*Qoptional-data\*U, not \*Qpointer\*U, in XDR language.
+.DS L
+.ft CW
+ pointer-declaration:
+ type-ident "*" variable-ident
+.DE
+Example:
+.DS L
+.ft CW
+ listitem *next; --> listitem *next;
+.DE
+.NH 2
+\&Special Cases
+.IX rpcgen "special cases" \fIrpcgen\fP
+.LP
+There are a few exceptions to the rules described above.
+.LP
+.B Booleans:
+C has no built-in boolean type. However, the RPC library does a
+boolean type called
+.I bool_t
+that is either
+.I TRUE
+or
+.I FALSE .
+Things declared as type
+.I bool
+in XDR language are compiled into
+.I bool_t
+in the output header file.
+.LP
+Example:
+.DS L
+.ft CW
+ bool married; --> bool_t married;
+.DE
+.B Strings:
+C has no built-in string type, but instead uses the null-terminated
+\*Qchar *\*U convention. In XDR language, strings are declared using the
+\*Qstring\*U keyword, and compiled into \*Qchar *\*Us in the output header
+file. The maximum size contained in the angle brackets specifies the
+maximum number of characters allowed in the strings (not counting the
+.I NULL
+character). The maximum size may be left off, indicating a string
+of arbitrary length.
+.LP
+Examples:
+.DS L
+.ft CW
+ string name<32>; --> char *name;
+ string longname<>; --> char *longname;
+.DE
+.B "Opaque Data:"
+Opaque data is used in RPC and XDR to describe untyped data, that is,
+just sequences of arbitrary bytes. It may be declared either as a
+fixed or variable length array.
+.DS L
+Examples:
+.ft CW
+ opaque diskblock[512]; --> char diskblock[512];
+
+ opaque filedata<1024>; --> struct {
+ u_int filedata_len;
+ char *filedata_val;
+ } filedata;
+.DE
+.B Voids:
+In a void declaration, the variable is not named. The declaration is
+just \*Qvoid\*U and nothing else. Void declarations can only occur in two
+places: union definitions and program definitions (as the argument or
+result of a remote procedure).
diff --git a/lib/libc/rpc/PSD.doc/stubs b/lib/libc/rpc/PSD.doc/stubs
new file mode 100644
index 0000000..78b0a2c
--- /dev/null
+++ b/lib/libc/rpc/PSD.doc/stubs
@@ -0,0 +1,3 @@
+.\" $FreeBSD$
+.\"
+.if t .ftr L CR
diff --git a/lib/libc/rpc/PSD.doc/xdr.nts.ms b/lib/libc/rpc/PSD.doc/xdr.nts.ms
new file mode 100644
index 0000000..260c7f3
--- /dev/null
+++ b/lib/libc/rpc/PSD.doc/xdr.nts.ms
@@ -0,0 +1,1968 @@
+.\"
+.\" Must use -- eqn -- with this one
+.\"
+.\" @(#)xdr.nts.ms 2.2 88/08/05 4.0 RPCSRC
+.\" $FreeBSD$
+.\"
+.EQ
+delim $$
+.EN
+.de BT
+.if \\n%=1 .tl ''- % -''
+..
+.ND
+.\" prevent excess underlining in nroff
+.if n .fp 2 R
+.OH 'External Data Representation: Sun Technical Notes''Page %'
+.EH 'Page %''External Data Representation: Sun Technical Notes'
+.if \n%=1 .bp
+.SH
+\&External Data Representation: Sun Technical Notes
+.IX XDR "Sun technical notes"
+.LP
+This chapter contains technical notes on Sun's implementation of the
+External Data Representation (XDR) standard, a set of library routines
+that allow a C programmer to describe arbitrary data structures in a
+machinex-independent fashion.
+For a formal specification of the XDR
+standard, see the
+.I "External Data Representation Standard: Protocol Specification".
+XDR is the backbone of Sun's Remote Procedure Call package, in the
+sense that data for remote procedure calls is transmitted using the
+standard. XDR library routines should be used to transmit data
+that is accessed (read or written) by more than one type of machine.\**
+.FS
+.IX XDR "system routines"
+For a compete specification of the system External Data Representation
+routines, see the
+.I xdr(3N)
+manual page.
+.FE
+.LP
+This chapter contains a short tutorial overview of the XDR library
+routines, a guide to accessing currently available XDR streams, and
+information on defining new streams and data types. XDR was designed
+to work across different languages, operating systems, and machine
+architectures. Most users (particularly RPC users) will only need
+the information in the
+.I "Number Filters",
+.I "Floating Point Filters",
+and
+.I "Enumeration Filters"
+sections.
+Programmers wishing to implement RPC and XDR on new machines
+will be interested in the rest of the chapter, as well as the
+.I "External Data Representaiton Standard: Protocol Specification",
+which will be their primary reference.
+.SH
+Note:
+.I
+.I rpcgen
+can be used to write XDR routines even in cases where no RPC calls are
+being made.
+.LP
+On Sun systems,
+C programs that want to use XDR routines
+must include the file
+.I <rpc/rpc.h> ,
+which contains all the necessary interfaces to the XDR system.
+Since the C library
+.I libc.a
+contains all the XDR routines,
+compile as normal.
+.DS
+example% \fBcc\0\fIprogram\fP.c\fI
+.DE
+.ne 3i
+.NH 0
+\&Justification
+.IX XDR justification
+.LP
+Consider the following two programs,
+.I writer :
+.ie t .DS
+.el .DS L
+.ft CW
+#include <stdio.h>
+.sp .5
+main() /* \fIwriter.c\fP */
+{
+ long i;
+.sp .5
+ for (i = 0; i < 8; i++) {
+ if (fwrite((char *)&i, sizeof(i), 1, stdout) != 1) {
+ fprintf(stderr, "failed!\en");
+ exit(1);
+ }
+ }
+ exit(0);
+}
+.DE
+and
+.I reader :
+.ie t .DS
+.el .DS L
+.ft CW
+#include <stdio.h>
+.sp .5
+main() /* \fIreader.c\fP */
+{
+ long i, j;
+.sp .5
+ for (j = 0; j < 8; j++) {
+ if (fread((char *)&i, sizeof (i), 1, stdin) != 1) {
+ fprintf(stderr, "failed!\en");
+ exit(1);
+ }
+ printf("%ld ", i);
+ }
+ printf("\en");
+ exit(0);
+}
+.DE
+The two programs appear to be portable, because (a) they pass
+.I lint
+checking, and (b) they exhibit the same behavior when executed
+on two different hardware architectures, a Sun and a VAX.
+.LP
+Piping the output of the
+.I writer
+program to the
+.I reader
+program gives identical results on a Sun or a VAX.
+.DS
+.ft CW
+sun% \fBwriter | reader\fP
+0 1 2 3 4 5 6 7
+sun%
+
+
+vax% \fBwriter | reader\fP
+0 1 2 3 4 5 6 7
+vax%
+.DE
+With the advent of local area networks and 4.2BSD came the concept
+of \*Qnetwork pipes\*U \(em a process produces data on one machine,
+and a second process consumes data on another machine.
+A network pipe can be constructed with
+.I writer
+and
+.I reader .
+Here are the results if the first produces data on a Sun,
+and the second consumes data on a VAX.
+.DS
+.ft CW
+sun% \fBwriter | rsh vax reader\fP
+0 16777216 33554432 50331648 67108864 83886080 100663296
+117440512
+sun%
+.DE
+Identical results can be obtained by executing
+.I writer
+on the VAX and
+.I reader
+on the Sun. These results occur because the byte ordering
+of long integers differs between the VAX and the Sun,
+even though word size is the same.
+Note that $16777216$ is $2 sup 24$ \(em
+when four bytes are reversed, the 1 winds up in the 24th bit.
+.LP
+Whenever data is shared by two or more machine types, there is
+a need for portable data. Programs can be made data-portable by
+replacing the
+.I read()
+and
+.I write()
+calls with calls to an XDR library routine
+.I xdr_long() ,
+a filter that knows the standard representation
+of a long integer in its external form.
+Here are the revised versions of
+.I writer :
+.ie t .DS
+.el .DS L
+.ft CW
+#include <stdio.h>
+#include <rpc/rpc.h> /* \fIxdr is a sub-library of rpc\fP */
+.sp .5
+main() /* \fIwriter.c\fP */
+{
+ XDR xdrs;
+ long i;
+.sp .5
+ xdrstdio_create(&xdrs, stdout, XDR_ENCODE);
+ for (i = 0; i < 8; i++) {
+ if (!xdr_long(&xdrs, &i)) {
+ fprintf(stderr, "failed!\en");
+ exit(1);
+ }
+ }
+ exit(0);
+}
+.DE
+and
+.I reader :
+.ie t .DS
+.el .DS L
+.ft CW
+#include <stdio.h>
+#include <rpc/rpc.h> /* \fIxdr is a sub-library of rpc\fP */
+.sp .5
+main() /* \fIreader.c\fP */
+{
+ XDR xdrs;
+ long i, j;
+.sp .5
+ xdrstdio_create(&xdrs, stdin, XDR_DECODE);
+ for (j = 0; j < 8; j++) {
+ if (!xdr_long(&xdrs, &i)) {
+ fprintf(stderr, "failed!\en");
+ exit(1);
+ }
+ printf("%ld ", i);
+ }
+ printf("\en");
+ exit(0);
+}
+.DE
+The new programs were executed on a Sun,
+on a VAX, and from a Sun to a VAX;
+the results are shown below.
+.DS
+.ft CW
+sun% \fBwriter | reader\fP
+0 1 2 3 4 5 6 7
+sun%
+
+vax% \fBwriter | reader\fP
+0 1 2 3 4 5 6 7
+vax%
+
+sun% \fBwriter | rsh vax reader\fP
+0 1 2 3 4 5 6 7
+sun%
+.DE
+.SH
+Note:
+.I
+.IX XDR "portable data"
+Integers are just the tip of the portable-data iceberg. Arbitrary
+data structures present portability problems, particularly with
+respect to alignment and pointers. Alignment on word boundaries
+may cause the size of a structure to vary from machine to machine.
+And pointers, which are very convenient to use, have no meaning
+outside the machine where they are defined.
+.LP
+.NH 1
+\&A Canonical Standard
+.IX XDR "canonical standard"
+.LP
+XDR's approach to standardizing data representations is
+.I canonical .
+That is, XDR defines a single byte order (Big Endian), a single
+floating-point representation (IEEE), and so on. Any program running on
+any machine can use XDR to create portable data by translating its
+local representation to the XDR standard representations; similarly, any
+program running on any machine can read portable data by translating the
+XDR standard representaions to its local equivalents. The single standard
+completely decouples programs that create or send portable data from those
+that use or receive portable data. The advent of a new machine or a new
+language has no effect upon the community of existing portable data creators
+and users. A new machine joins this community by being \*Qtaught\*U how to
+convert the standard representations and its local representations; the
+local representations of other machines are irrelevant. Conversely, to
+existing programs running on other machines, the local representations of
+the new machine are also irrelevant; such programs can immediately read
+portable data produced by the new machine because such data conforms to the
+canonical standards that they already understand.
+.LP
+There are strong precedents for XDR's canonical approach. For example,
+TCP/IP, UDP/IP, XNS, Ethernet, and, indeed, all protocols below layer five
+of the ISO model, are canonical protocols. The advantage of any canonical
+approach is simplicity; in the case of XDR, a single set of conversion
+routines is written once and is never touched again. The canonical approach
+has a disadvantage, but it is unimportant in real-world data transfer
+applications. Suppose two Little-Endian machines are transferring integers
+according to the XDR standard. The sending machine converts the integers
+from Little-Endian byte order to XDR (Big-Endian) byte order; the receiving
+machine performs the reverse conversion. Because both machines observe the
+same byte order, their conversions are unnecessary. The point, however, is
+not necessity, but cost as compared to the alternative.
+.LP
+The time spent converting to and from a canonical representation is
+insignificant, especially in networking applications. Most of the time
+required to prepare a data structure for transfer is not spent in conversion
+but in traversing the elements of the data structure. To transmit a tree,
+for example, each leaf must be visited and each element in a leaf record must
+be copied to a buffer and aligned there; storage for the leaf may have to be
+deallocated as well. Similarly, to receive a tree, storage must be
+allocated for each leaf, data must be moved from the buffer to the leaf and
+properly aligned, and pointers must be constructed to link the leaves
+together. Every machine pays the cost of traversing and copying data
+structures whether or not conversion is required. In networking
+applications, communications overhead\(emthe time required to move the data
+down through the sender's protocol layers, across the network and up through
+the receiver's protocol layers\(emdwarfs conversion overhead.
+.NH 1
+\&The XDR Library
+.IX "XDR" "library"
+.LP
+The XDR library not only solves data portability problems, it also
+allows you to write and read arbitrary C constructs in a consistent,
+specified, well-documented manner. Thus, it can make sense to use the
+library even when the data is not shared among machines on a network.
+.LP
+The XDR library has filter routines for
+strings (null-terminated arrays of bytes),
+structures, unions, and arrays, to name a few.
+Using more primitive routines,
+you can write your own specific XDR routines
+to describe arbitrary data structures,
+including elements of arrays, arms of unions,
+or objects pointed at from other structures.
+The structures themselves may contain arrays of arbitrary elements,
+or pointers to other structures.
+.LP
+Let's examine the two programs more closely.
+There is a family of XDR stream creation routines
+in which each member treats the stream of bits differently.
+In our example, data is manipulated using standard I/O routines,
+so we use
+.I xdrstdio_create ().
+.IX xdrstdio_create() "" "\fIxdrstdio_create()\fP"
+The parameters to XDR stream creation routines
+vary according to their function.
+In our example,
+.I xdrstdio_create()
+takes a pointer to an XDR structure that it initializes,
+a pointer to a
+.I FILE
+that the input or output is performed on, and the operation.
+The operation may be
+.I XDR_ENCODE
+for serializing in the
+.I writer
+program, or
+.I XDR_DECODE
+for deserializing in the
+.I reader
+program.
+.LP
+Note: RPC users never need to create XDR streams;
+the RPC system itself creates these streams,
+which are then passed to the users.
+.LP
+The
+.I xdr_long()
+.IX xdr_long() "" "\fIxdr_long()\fP"
+primitive is characteristic of most XDR library
+primitives and all client XDR routines.
+First, the routine returns
+.I FALSE
+(0) if it fails, and
+.I TRUE
+(1) if it succeeds.
+Second, for each data type,
+.I xxx ,
+there is an associated XDR routine of the form:
+.DS
+.ft CW
+xdr_xxx(xdrs, xp)
+ XDR *xdrs;
+ xxx *xp;
+{
+}
+.DE
+In our case,
+.I xxx
+is long, and the corresponding XDR routine is
+a primitive,
+.I xdr_long() .
+The client could also define an arbitrary structure
+.I xxx
+in which case the client would also supply the routine
+.I xdr_xxx (),
+describing each field by calling XDR routines
+of the appropriate type.
+In all cases the first parameter,
+.I xdrs
+can be treated as an opaque handle,
+and passed to the primitive routines.
+.LP
+XDR routines are direction independent;
+that is, the same routines are called to serialize or deserialize data.
+This feature is critical to software engineering of portable data.
+The idea is to call the same routine for either operation \(em
+this almost guarantees that serialized data can also be deserialized.
+One routine is used by both producer and consumer of networked data.
+This is implemented by always passing the address
+of an object rather than the object itself \(em
+only in the case of deserialization is the object modified.
+This feature is not shown in our trivial example,
+but its value becomes obvious when nontrivial data structures
+are passed among machines.
+If needed, the user can obtain the
+direction of the XDR operation.
+See the
+.I "XDR Operation Directions"
+section below for details.
+.LP
+Let's look at a slightly more complicated example.
+Assume that a person's gross assets and liabilities
+are to be exchanged among processes.
+Also assume that these values are important enough
+to warrant their own data type:
+.ie t .DS
+.el .DS L
+.ft CW
+struct gnumbers {
+ long g_assets;
+ long g_liabilities;
+};
+.DE
+The corresponding XDR routine describing this structure would be:
+.ie t .DS
+.el .DS L
+.ft CW
+bool_t /* \fITRUE is success, FALSE is failure\fP */
+xdr_gnumbers(xdrs, gp)
+ XDR *xdrs;
+ struct gnumbers *gp;
+{
+ if (xdr_long(xdrs, &gp->g_assets) &&
+ xdr_long(xdrs, &gp->g_liabilities))
+ return(TRUE);
+ return(FALSE);
+}
+.DE
+Note that the parameter
+.I xdrs
+is never inspected or modified;
+it is only passed on to the subcomponent routines.
+It is imperative to inspect the return value of each XDR routine call,
+and to give up immediately and return
+.I FALSE
+if the subroutine fails.
+.LP
+This example also shows that the type
+.I bool_t
+is declared as an integer whose only values are
+.I TRUE
+(1) and
+.I FALSE
+(0). This document uses the following definitions:
+.ie t .DS
+.el .DS L
+.ft CW
+#define bool_t int
+#define TRUE 1
+#define FALSE 0
+.DE
+.LP
+Keeping these conventions in mind,
+.I xdr_gnumbers()
+can be rewritten as follows:
+.ie t .DS
+.el .DS L
+.ft CW
+xdr_gnumbers(xdrs, gp)
+ XDR *xdrs;
+ struct gnumbers *gp;
+{
+ return(xdr_long(xdrs, &gp->g_assets) &&
+ xdr_long(xdrs, &gp->g_liabilities));
+}
+.DE
+This document uses both coding styles.
+.NH 1
+\&XDR Library Primitives
+.IX "library primitives for XDR"
+.IX XDR "library primitives"
+.LP
+This section gives a synopsis of each XDR primitive.
+It starts with basic data types and moves on to constructed data types.
+Finally, XDR utilities are discussed.
+The interface to these primitives
+and utilities is defined in the include file
+.I <rpc/xdr.h> ,
+automatically included by
+.I <rpc/rpc.h> .
+.NH 2
+\&Number Filters
+.IX "XDR library" "number filters"
+.LP
+The XDR library provides primitives to translate between numbers
+and their corresponding external representations.
+Primitives cover the set of numbers in:
+.DS
+.ft CW
+[signed, unsigned] * [short, int, long]
+.DE
+.ne 2i
+Specifically, the eight primitives are:
+.DS
+.ft CW
+bool_t xdr_char(xdrs, cp)
+ XDR *xdrs;
+ char *cp;
+.sp .5
+bool_t xdr_u_char(xdrs, ucp)
+ XDR *xdrs;
+ unsigned char *ucp;
+.sp .5
+bool_t xdr_int(xdrs, ip)
+ XDR *xdrs;
+ int *ip;
+.sp .5
+bool_t xdr_u_int(xdrs, up)
+ XDR *xdrs;
+ unsigned *up;
+.sp .5
+bool_t xdr_long(xdrs, lip)
+ XDR *xdrs;
+ long *lip;
+.sp .5
+bool_t xdr_u_long(xdrs, lup)
+ XDR *xdrs;
+ u_long *lup;
+.sp .5
+bool_t xdr_short(xdrs, sip)
+ XDR *xdrs;
+ short *sip;
+.sp .5
+bool_t xdr_u_short(xdrs, sup)
+ XDR *xdrs;
+ u_short *sup;
+.DE
+The first parameter,
+.I xdrs ,
+is an XDR stream handle.
+The second parameter is the address of the number
+that provides data to the stream or receives data from it.
+All routines return
+.I TRUE
+if they complete successfully, and
+.I FALSE
+otherwise.
+.NH 2
+\&Floating Point Filters
+.IX "XDR library" "floating point filters"
+.LP
+The XDR library also provides primitive routines
+for C's floating point types:
+.DS
+.ft CW
+bool_t xdr_float(xdrs, fp)
+ XDR *xdrs;
+ float *fp;
+.sp .5
+bool_t xdr_double(xdrs, dp)
+ XDR *xdrs;
+ double *dp;
+.DE
+The first parameter,
+.I xdrs
+is an XDR stream handle.
+The second parameter is the address
+of the floating point number that provides data to the stream
+or receives data from it.
+Both routines return
+.I TRUE
+if they complete successfully, and
+.I FALSE
+otherwise.
+.LP
+Note: Since the numbers are represented in IEEE floating point,
+routines may fail when decoding a valid IEEE representation
+into a machine-specific representation, or vice-versa.
+.NH 2
+\&Enumeration Filters
+.IX "XDR library" "enumeration filters"
+.LP
+The XDR library provides a primitive for generic enumerations.
+The primitive assumes that a C
+.I enum
+has the same representation inside the machine as a C integer.
+The boolean type is an important instance of the
+.I enum .
+The external representation of a boolean is always
+.I TRUE
+(1) or
+.I FALSE
+(0).
+.DS
+.ft CW
+#define bool_t int
+#define FALSE 0
+#define TRUE 1
+.sp .5
+#define enum_t int
+.sp .5
+bool_t xdr_enum(xdrs, ep)
+ XDR *xdrs;
+ enum_t *ep;
+.sp .5
+bool_t xdr_bool(xdrs, bp)
+ XDR *xdrs;
+ bool_t *bp;
+.DE
+The second parameters
+.I ep
+and
+.I bp
+are addresses of the associated type that provides data to, or
+receives data from, the stream
+.I xdrs .
+.NH 2
+\&No Data
+.IX "XDR library" "no data"
+.LP
+Occasionally, an XDR routine must be supplied to the RPC system,
+even when no data is passed or required.
+The library provides such a routine:
+.DS
+.ft CW
+bool_t xdr_void(); /* \fIalways returns TRUE\fP */
+.DE
+.NH 2
+\&Constructed Data Type Filters
+.IX "XDR library" "constructed data type filters"
+.LP
+Constructed or compound data type primitives
+require more parameters and perform more complicated functions
+then the primitives discussed above.
+This section includes primitives for
+strings, arrays, unions, and pointers to structures.
+.LP
+Constructed data type primitives may use memory management.
+In many cases, memory is allocated when deserializing data with
+.I XDR_DECODE
+Therefore, the XDR package must provide means to deallocate memory.
+This is done by an XDR operation,
+.I XDR_FREE
+To review, the three XDR directional operations are
+.I XDR_ENCODE ,
+.I XDR_DECODE
+and
+.I XDR_FREE .
+.NH 3
+\&Strings
+.IX "XDR library" "strings"
+.LP
+In C, a string is defined as a sequence of bytes
+terminated by a null byte,
+which is not considered when calculating string length.
+However, when a string is passed or manipulated,
+a pointer to it is employed.
+Therefore, the XDR library defines a string to be a
+.I "char *"
+and not a sequence of characters.
+The external representation of a string is drastically different
+from its internal representation.
+Externally, strings are represented as
+sequences of ASCII characters,
+while internally, they are represented with character pointers.
+Conversion between the two representations
+is accomplished with the routine
+.I xdr_string ():
+.IX xdr_string() "" \fIxdr_string()\fP
+.DS
+.ft CW
+bool_t xdr_string(xdrs, sp, maxlength)
+ XDR *xdrs;
+ char **sp;
+ u_int maxlength;
+.DE
+The first parameter
+.I xdrs
+is the XDR stream handle.
+The second parameter
+.I sp
+is a pointer to a string (type
+.I "char **" .
+The third parameter
+.I maxlength
+specifies the maximum number of bytes allowed during encoding or decoding.
+its value is usually specified by a protocol. For example, a protocol
+specification may say that a file name may be no longer than 255 characters.
+.LP
+The routine returns
+.I FALSE
+if the number of characters exceeds
+.I maxlength ,
+and
+.I TRUE
+if it doesn't.
+.SH
+Keep
+.I maxlength
+small. If it is too big you can blow the heap, since
+.I xdr_string()
+will call
+.I malloc()
+for space.
+.LP
+The behavior of
+.I xdr_string()
+.IX xdr_string() "" \fIxdr_string()\fP
+is similar to the behavior of other routines
+discussed in this section. The direction
+.I XDR_ENCODE
+is easiest to understand. The parameter
+.I sp
+points to a string of a certain length;
+if the string does not exceed
+.I maxlength ,
+the bytes are serialized.
+.LP
+The effect of deserializing a string is subtle.
+First the length of the incoming string is determined;
+it must not exceed
+.I maxlength .
+Next
+.I sp
+is dereferenced; if the the value is
+.I NULL ,
+then a string of the appropriate length is allocated and
+.I *sp
+is set to this string.
+If the original value of
+.I *sp
+is non-null, then the XDR package assumes
+that a target area has been allocated,
+which can hold strings no longer than
+.I maxlength .
+In either case, the string is decoded into the target area.
+The routine then appends a null character to the string.
+.LP
+In the
+.I XDR_FREE
+operation, the string is obtained by dereferencing
+.I sp .
+If the string is not
+.I NULL ,
+it is freed and
+.I *sp
+is set to
+.I NULL .
+In this operation,
+.I xdr_string()
+ignores the
+.I maxlength
+parameter.
+.NH 3
+\&Byte Arrays
+.IX "XDR library" "byte arrays"
+.LP
+Often variable-length arrays of bytes are preferable to strings.
+Byte arrays differ from strings in the following three ways:
+1) the length of the array (the byte count) is explicitly
+located in an unsigned integer,
+2) the byte sequence is not terminated by a null character, and
+3) the external representation of the bytes is the same as their
+internal representation.
+The primitive
+.I xdr_bytes()
+.IX xdr_bytes() "" \fIxdr_bytes()\fP
+converts between the internal and external
+representations of byte arrays:
+.DS
+.ft CW
+bool_t xdr_bytes(xdrs, bpp, lp, maxlength)
+ XDR *xdrs;
+ char **bpp;
+ u_int *lp;
+ u_int maxlength;
+.DE
+The usage of the first, second and fourth parameters
+are identical to the first, second and third parameters of
+.I xdr_string (),
+respectively.
+The length of the byte area is obtained by dereferencing
+.I lp
+when serializing;
+.I *lp
+is set to the byte length when deserializing.
+.NH 3
+\&Arrays
+.IX "XDR library" "arrays"
+.LP
+The XDR library package provides a primitive
+for handling arrays of arbitrary elements.
+The
+.I xdr_bytes()
+routine treats a subset of generic arrays,
+in which the size of array elements is known to be 1,
+and the external description of each element is built-in.
+The generic array primitive,
+.I xdr_array() ,
+.IX xdr_array() "" \fIxdr_array()\fP
+requires parameters identical to those of
+.I xdr_bytes()
+plus two more:
+the size of array elements,
+and an XDR routine to handle each of the elements.
+This routine is called to encode or decode
+each element of the array.
+.DS
+.ft CW
+bool_t
+xdr_array(xdrs, ap, lp, maxlength, elementsiz, xdr_element)
+ XDR *xdrs;
+ char **ap;
+ u_int *lp;
+ u_int maxlength;
+ u_int elementsiz;
+ bool_t (*xdr_element)();
+.DE
+The parameter
+.I ap
+is the address of the pointer to the array.
+If
+.I *ap
+is
+.I NULL
+when the array is being deserialized,
+XDR allocates an array of the appropriate size and sets
+.I *ap
+to that array.
+The element count of the array is obtained from
+.I *lp
+when the array is serialized;
+.I *lp
+is set to the array length when the array is deserialized.
+The parameter
+.I maxlength
+is the maximum number of elements that the array is allowed to have;
+.I elementsiz
+is the byte size of each element of the array
+(the C function
+.I sizeof()
+can be used to obtain this value).
+The
+.I xdr_element()
+.IX xdr_element() "" \fIxdr_element()\fP
+routine is called to serialize, deserialize, or free
+each element of the array.
+.br
+.LP
+Before defining more constructed data types, it is appropriate to
+present three examples.
+.LP
+.I "Example A:"
+.br
+A user on a networked machine can be identified by
+(a) the machine name, such as
+.I krypton :
+see the
+.I gethostname
+man page; (b) the user's UID: see the
+.I geteuid
+man page; and (c) the group numbers to which the user belongs:
+see the
+.I getgroups
+man page. A structure with this information and its associated
+XDR routine could be coded like this:
+.ie t .DS
+.el .DS L
+.ft CW
+struct netuser {
+ char *nu_machinename;
+ int nu_uid;
+ u_int nu_glen;
+ int *nu_gids;
+};
+#define NLEN 255 /* \fImachine names < 256 chars\fP */
+#define NGRPS 20 /* \fIuser can't be in > 20 groups\fP */
+.sp .5
+bool_t
+xdr_netuser(xdrs, nup)
+ XDR *xdrs;
+ struct netuser *nup;
+{
+ return(xdr_string(xdrs, &nup->nu_machinename, NLEN) &&
+ xdr_int(xdrs, &nup->nu_uid) &&
+ xdr_array(xdrs, &nup->nu_gids, &nup->nu_glen,
+ NGRPS, sizeof (int), xdr_int));
+}
+.DE
+.LP
+.I "Example B:"
+.br
+A party of network users could be implemented
+as an array of
+.I netuser
+structure.
+The declaration and its associated XDR routines
+are as follows:
+.ie t .DS
+.el .DS L
+.ft CW
+struct party {
+ u_int p_len;
+ struct netuser *p_nusers;
+};
+#define PLEN 500 /* \fImax number of users in a party\fP */
+.sp .5
+bool_t
+xdr_party(xdrs, pp)
+ XDR *xdrs;
+ struct party *pp;
+{
+ return(xdr_array(xdrs, &pp->p_nusers, &pp->p_len, PLEN,
+ sizeof (struct netuser), xdr_netuser));
+}
+.DE
+.LP
+.I "Example C:"
+.br
+The well-known parameters to
+.I main ,
+.I argc
+and
+.I argv
+can be combined into a structure.
+An array of these structures can make up a history of commands.
+The declarations and XDR routines might look like:
+.ie t .DS
+.el .DS L
+.ft CW
+struct cmd {
+ u_int c_argc;
+ char **c_argv;
+};
+#define ALEN 1000 /* \fIargs cannot be > 1000 chars\fP */
+#define NARGC 100 /* \fIcommands cannot have > 100 args\fP */
+
+struct history {
+ u_int h_len;
+ struct cmd *h_cmds;
+};
+#define NCMDS 75 /* \fIhistory is no more than 75 commands\fP */
+
+bool_t
+xdr_wrap_string(xdrs, sp)
+ XDR *xdrs;
+ char **sp;
+{
+ return(xdr_string(xdrs, sp, ALEN));
+}
+.DE
+.ie t .DS
+.el .DS L
+.ft CW
+bool_t
+xdr_cmd(xdrs, cp)
+ XDR *xdrs;
+ struct cmd *cp;
+{
+ return(xdr_array(xdrs, &cp->c_argv, &cp->c_argc, NARGC,
+ sizeof (char *), xdr_wrap_string));
+}
+.DE
+.ie t .DS
+.el .DS L
+.ft CW
+bool_t
+xdr_history(xdrs, hp)
+ XDR *xdrs;
+ struct history *hp;
+{
+ return(xdr_array(xdrs, &hp->h_cmds, &hp->h_len, NCMDS,
+ sizeof (struct cmd), xdr_cmd));
+}
+.DE
+The most confusing part of this example is that the routine
+.I xdr_wrap_string()
+is needed to package the
+.I xdr_string()
+routine, because the implementation of
+.I xdr_array()
+only passes two parameters to the array element description routine;
+.I xdr_wrap_string()
+supplies the third parameter to
+.I xdr_string ().
+.LP
+By now the recursive nature of the XDR library should be obvious.
+Let's continue with more constructed data types.
+.NH 3
+\&Opaque Data
+.IX "XDR library" "opaque data"
+.LP
+In some protocols, handles are passed from a server to client.
+The client passes the handle back to the server at some later time.
+Handles are never inspected by clients;
+they are obtained and submitted.
+That is to say, handles are opaque.
+The
+.I xdr_opaque()
+.IX xdr_opaque() "" \fIxdr_opaque()\fP
+primitive is used for describing fixed sized, opaque bytes.
+.DS
+.ft CW
+bool_t xdr_opaque(xdrs, p, len)
+ XDR *xdrs;
+ char *p;
+ u_int len;
+.DE
+The parameter
+.I p
+is the location of the bytes;
+.I len
+is the number of bytes in the opaque object.
+By definition, the actual data
+contained in the opaque object are not machine portable.
+.NH 3
+\&Fixed Sized Arrays
+.IX "XDR library" "fixed sized arrays"
+.LP
+The XDR library provides a primitive,
+.I xdr_vector (),
+for fixed-length arrays.
+.ie t .DS
+.el .DS L
+.ft CW
+#define NLEN 255 /* \fImachine names must be < 256 chars\fP */
+#define NGRPS 20 /* \fIuser belongs to exactly 20 groups\fP */
+.sp .5
+struct netuser {
+ char *nu_machinename;
+ int nu_uid;
+ int nu_gids[NGRPS];
+};
+.sp .5
+bool_t
+xdr_netuser(xdrs, nup)
+ XDR *xdrs;
+ struct netuser *nup;
+{
+ int i;
+.sp .5
+ if (!xdr_string(xdrs, &nup->nu_machinename, NLEN))
+ return(FALSE);
+ if (!xdr_int(xdrs, &nup->nu_uid))
+ return(FALSE);
+ if (!xdr_vector(xdrs, nup->nu_gids, NGRPS, sizeof(int),
+ xdr_int)) {
+ return(FALSE);
+ }
+ return(TRUE);
+}
+.DE
+.NH 3
+\&Discriminated Unions
+.IX "XDR library" "discriminated unions"
+.LP
+The XDR library supports discriminated unions.
+A discriminated union is a C union and an
+.I enum_t
+value that selects an \*Qarm\*U of the union.
+.DS
+.ft CW
+struct xdr_discrim {
+ enum_t value;
+ bool_t (*proc)();
+};
+.sp .5
+bool_t xdr_union(xdrs, dscmp, unp, arms, defaultarm)
+ XDR *xdrs;
+ enum_t *dscmp;
+ char *unp;
+ struct xdr_discrim *arms;
+ bool_t (*defaultarm)(); /* \fImay equal NULL\fP */
+.DE
+First the routine translates the discriminant of the union located at
+.I *dscmp .
+The discriminant is always an
+.I enum_t .
+Next the union located at
+.I *unp
+is translated.
+The parameter
+.I arms
+is a pointer to an array of
+.I xdr_discrim
+structures.
+Each structure contains an ordered pair of
+.I [value,proc] .
+If the union's discriminant is equal to the associated
+.I value ,
+then the
+.I proc
+is called to translate the union.
+The end of the
+.I xdr_discrim
+structure array is denoted by a routine of value
+.I NULL
+(0). If the discriminant is not found in the
+.I arms
+array, then the
+.I defaultarm
+procedure is called if it is non-null;
+otherwise the routine returns
+.I FALSE .
+.LP
+.I "Example D:"
+Suppose the type of a union may be integer,
+character pointer (a string), or a
+.I gnumbers
+structure.
+Also, assume the union and its current type
+are declared in a structure.
+The declaration is:
+.ie t .DS
+.el .DS L
+.ft CW
+enum utype { INTEGER=1, STRING=2, GNUMBERS=3 };
+.sp .5
+struct u_tag {
+ enum utype utype; /* \fIthe union's discriminant\fP */
+ union {
+ int ival;
+ char *pval;
+ struct gnumbers gn;
+ } uval;
+};
+.DE
+The following constructs and XDR procedure (de)serialize
+the discriminated union:
+.ie t .DS
+.el .DS L
+.ft CW
+struct xdr_discrim u_tag_arms[4] = {
+ { INTEGER, xdr_int },
+ { GNUMBERS, xdr_gnumbers }
+ { STRING, xdr_wrap_string },
+ { __dontcare__, NULL }
+ /* \fIalways terminate arms with a NULL xdr_proc\fP */
+}
+.sp .5
+bool_t
+xdr_u_tag(xdrs, utp)
+ XDR *xdrs;
+ struct u_tag *utp;
+{
+ return(xdr_union(xdrs, &utp->utype, &utp->uval,
+ u_tag_arms, NULL));
+}
+.DE
+The routine
+.I xdr_gnumbers()
+was presented above in
+.I "The XDR Library"
+section.
+.I xdr_wrap_string()
+was presented in example C.
+The default
+.I arm
+parameter to
+.I xdr_union()
+(the last parameter) is
+.I NULL
+in this example. Therefore the value of the union's discriminant
+may legally take on only values listed in the
+.I u_tag_arms
+array. This example also demonstrates that
+the elements of the arm's array do not need to be sorted.
+.LP
+It is worth pointing out that the values of the discriminant
+may be sparse, though in this example they are not.
+It is always good
+practice to assign explicitly integer values to each element of the
+discriminant's type.
+This practice both documents the external
+representation of the discriminant and guarantees that different
+C compilers emit identical discriminant values.
+.LP
+Exercise: Implement
+.I xdr_union()
+using the other primitives in this section.
+.NH 3
+\&Pointers
+.IX "XDR library" "pointers"
+.LP
+In C it is often convenient to put pointers
+to another structure within a structure.
+The
+.I xdr_reference()
+.IX xdr_reference() "" \fIxdr_reference()\fP
+primitive makes it easy to serialize, deserialize, and free
+these referenced structures.
+.DS
+.ft CW
+bool_t xdr_reference(xdrs, pp, size, proc)
+ XDR *xdrs;
+ char **pp;
+ u_int ssize;
+ bool_t (*proc)();
+.DE
+.LP
+Parameter
+.I pp
+is the address of
+the pointer to the structure;
+parameter
+.I ssize
+is the size in bytes of the structure (use the C function
+.I sizeof()
+to obtain this value); and
+.I proc
+is the XDR routine that describes the structure.
+When decoding data, storage is allocated if
+.I *pp
+is
+.I NULL .
+.LP
+There is no need for a primitive
+.I xdr_struct()
+to describe structures within structures,
+because pointers are always sufficient.
+.LP
+Exercise: Implement
+.I xdr_reference()
+using
+.I xdr_array ().
+Warning:
+.I xdr_reference()
+and
+.I xdr_array()
+are NOT interchangeable external representations of data.
+.LP
+.I "Example E:"
+Suppose there is a structure containing a person's name
+and a pointer to a
+.I gnumbers
+structure containing the person's gross assets and liabilities.
+The construct is:
+.DS
+.ft CW
+struct pgn {
+ char *name;
+ struct gnumbers *gnp;
+};
+.DE
+The corresponding XDR routine for this structure is:
+.DS
+.ft CW
+bool_t
+xdr_pgn(xdrs, pp)
+ XDR *xdrs;
+ struct pgn *pp;
+{
+ if (xdr_string(xdrs, &pp->name, NLEN) &&
+ xdr_reference(xdrs, &pp->gnp,
+ sizeof(struct gnumbers), xdr_gnumbers))
+ return(TRUE);
+ return(FALSE);
+}
+.DE
+.IX "pointer semantics and XDR"
+.I "Pointer Semantics and XDR"
+.LP
+In many applications, C programmers attach double meaning to
+the values of a pointer. Typically the value
+.I NULL
+(or zero) means data is not needed,
+yet some application-specific interpretation applies.
+In essence, the C programmer is encoding
+a discriminated union efficiently
+by overloading the interpretation of the value of a pointer.
+For instance, in example E a
+.I NULL
+pointer value for
+.I gnp
+could indicate that
+the person's assets and liabilities are unknown.
+That is, the pointer value encodes two things:
+whether or not the data is known;
+and if it is known, where it is located in memory.
+Linked lists are an extreme example of the use
+of application-specific pointer interpretation.
+.LP
+The primitive
+.I xdr_reference()
+.IX xdr_reference() "" \fIxdr_reference()\fP
+cannot and does not attach any special
+meaning to a null-value pointer during serialization.
+That is, passing an address of a pointer whose value is
+.I NULL
+to
+.I xdr_reference()
+when serialing data will most likely cause a memory fault and, on the UNIX
+system, a core dump.
+.LP
+.I xdr_pointer()
+correctly handles
+.I NULL
+pointers. For more information about its use, see
+the
+.I "Linked Lists"
+topics below.
+.LP
+.I Exercise:
+After reading the section on
+.I "Linked Lists" ,
+return here and extend example E so that
+it can correctly deal with
+.I NULL
+pointer values.
+.LP
+.I Exercise:
+Using the
+.I xdr_union (),
+.I xdr_reference()
+and
+.I xdr_void()
+primitives, implement a generic pointer handling primitive
+that implicitly deals with
+.I NULL
+pointers. That is, implement
+.I xdr_pointer ().
+.NH 2
+\&Non-filter Primitives
+.IX "XDR" "non-filter primitives"
+.LP
+XDR streams can be manipulated with
+the primitives discussed in this section.
+.DS
+.ft CW
+u_int xdr_getpos(xdrs)
+ XDR *xdrs;
+.sp .5
+bool_t xdr_setpos(xdrs, pos)
+ XDR *xdrs;
+ u_int pos;
+.sp .5
+xdr_destroy(xdrs)
+ XDR *xdrs;
+.DE
+The routine
+.I xdr_getpos()
+.IX xdr_getpos() "" \fIxdr_getpos()\fP
+returns an unsigned integer
+that describes the current position in the data stream.
+Warning: In some XDR streams, the returned value of
+.I xdr_getpos()
+is meaningless;
+the routine returns a \-1 in this case
+(though \-1 should be a legitimate value).
+.LP
+The routine
+.I xdr_setpos()
+.IX xdr_setpos() "" \fIxdr_setpos()\fP
+sets a stream position to
+.I pos .
+Warning: In some XDR streams, setting a position is impossible;
+in such cases,
+.I xdr_setpos()
+will return
+.I FALSE .
+This routine will also fail if the requested position is out-of-bounds.
+The definition of bounds varies from stream to stream.
+.LP
+The
+.I xdr_destroy()
+.IX xdr_destroy() "" \fIxdr_destroy()\fP
+primitive destroys the XDR stream.
+Usage of the stream
+after calling this routine is undefined.
+.NH 2
+\&XDR Operation Directions
+.IX XDR "operation directions"
+.IX "direction of XDR operations"
+.LP
+At times you may wish to optimize XDR routines by taking
+advantage of the direction of the operation \(em
+.I XDR_ENCODE
+.I XDR_DECODE
+or
+.I XDR_FREE
+The value
+.I xdrs->x_op
+always contains the direction of the XDR operation.
+Programmers are not encouraged to take advantage of this information.
+Therefore, no example is presented here. However, an example in the
+.I "Linked Lists"
+topic below, demonstrates the usefulness of the
+.I xdrs->x_op
+field.
+.NH 2
+\&XDR Stream Access
+.IX "XDR" "stream access"
+.LP
+An XDR stream is obtained by calling the appropriate creation routine.
+These creation routines take arguments that are tailored to the
+specific properties of the stream.
+.LP
+Streams currently exist for (de)serialization of data to or from
+standard I/O
+.I FILE
+streams, TCP/IP connections and UNIX files, and memory.
+.NH 3
+\&Standard I/O Streams
+.IX "XDR" "standard I/O streams"
+.LP
+XDR streams can be interfaced to standard I/O using the
+.I xdrstdio_create()
+.IX xdrstdio_create() "" \fIxdrstdio_create()\fP
+routine as follows:
+.DS
+.ft CW
+#include <stdio.h>
+#include <rpc/rpc.h> /* \fIxdr streams part of rpc\fP */
+.sp .5
+void
+xdrstdio_create(xdrs, fp, x_op)
+ XDR *xdrs;
+ FILE *fp;
+ enum xdr_op x_op;
+.DE
+The routine
+.I xdrstdio_create()
+initializes an XDR stream pointed to by
+.I xdrs .
+The XDR stream interfaces to the standard I/O library.
+Parameter
+.I fp
+is an open file, and
+.I x_op
+is an XDR direction.
+.NH 3
+\&Memory Streams
+.IX "XDR" "memory streams"
+.LP
+Memory streams allow the streaming of data into or out of
+a specified area of memory:
+.DS
+.ft CW
+#include <rpc/rpc.h>
+.sp .5
+void
+xdrmem_create(xdrs, addr, len, x_op)
+ XDR *xdrs;
+ char *addr;
+ u_int len;
+ enum xdr_op x_op;
+.DE
+The routine
+.I xdrmem_create()
+.IX xdrmem_create() "" \fIxdrmem_create()\fP
+initializes an XDR stream in local memory.
+The memory is pointed to by parameter
+.I addr ;
+parameter
+.I len
+is the length in bytes of the memory.
+The parameters
+.I xdrs
+and
+.I x_op
+are identical to the corresponding parameters of
+.I xdrstdio_create ().
+Currently, the UDP/IP implementation of RPC uses
+.I xdrmem_create ().
+Complete call or result messages are built in memory before calling the
+.I sendto()
+system routine.
+.NH 3
+\&Record (TCP/IP) Streams
+.IX "XDR" "record (TCP/IP) streams"
+.LP
+A record stream is an XDR stream built on top of
+a record marking standard that is built on top of the
+UNIX file or 4.2 BSD connection interface.
+.DS
+.ft CW
+#include <rpc/rpc.h> /* \fIxdr streams part of rpc\fP */
+.sp .5
+xdrrec_create(xdrs,
+ sendsize, recvsize, iohandle, readproc, writeproc)
+ XDR *xdrs;
+ u_int sendsize, recvsize;
+ char *iohandle;
+ int (*readproc)(), (*writeproc)();
+.DE
+The routine
+.I xdrrec_create()
+provides an XDR stream interface that allows for a bidirectional,
+arbitrarily long sequence of records.
+The contents of the records are meant to be data in XDR form.
+The stream's primary use is for interfacing RPC to TCP connections.
+However, it can be used to stream data into or out of normal
+UNIX files.
+.LP
+The parameter
+.I xdrs
+is similar to the corresponding parameter described above.
+The stream does its own data buffering similar to that of standard I/O.
+The parameters
+.I sendsize
+and
+.I recvsize
+determine the size in bytes of the output and input buffers, respectively;
+if their values are zero (0), then predetermined defaults are used.
+When a buffer needs to be filled or flushed, the routine
+.I readproc()
+or
+.I writeproc()
+is called, respectively.
+The usage and behavior of these
+routines are similar to the UNIX system calls
+.I read()
+and
+.I write ().
+However,
+the first parameter to each of these routines is the opaque parameter
+.I iohandle .
+The other two parameters
+.I buf ""
+and
+.I nbytes )
+and the results
+(byte count) are identical to the system routines.
+If
+.I xxx
+is
+.I readproc()
+or
+.I writeproc (),
+then it has the following form:
+.DS
+.ft CW
+.ft I
+/*
+ * returns the actual number of bytes transferred.
+ * -1 is an error
+ */
+.ft CW
+int
+xxx(iohandle, buf, len)
+ char *iohandle;
+ char *buf;
+ int nbytes;
+.DE
+The XDR stream provides means for delimiting records in the byte stream.
+The implementation details of delimiting records in a stream are
+discussed in the
+.I "Advanced Topics"
+topic below.
+The primitives that are specific to record streams are as follows:
+.DS
+.ft CW
+bool_t
+xdrrec_endofrecord(xdrs, flushnow)
+ XDR *xdrs;
+ bool_t flushnow;
+.sp .5
+bool_t
+xdrrec_skiprecord(xdrs)
+ XDR *xdrs;
+.sp .5
+bool_t
+xdrrec_eof(xdrs)
+ XDR *xdrs;
+.DE
+The routine
+.I xdrrec_endofrecord()
+.IX xdrrec_endofrecord() "" \fIxdrrec_endofrecord()\fP
+causes the current outgoing data to be marked as a record.
+If the parameter
+.I flushnow
+is
+.I TRUE ,
+then the stream's
+.I writeproc
+will be called; otherwise,
+.I writeproc
+will be called when the output buffer has been filled.
+.LP
+The routine
+.I xdrrec_skiprecord()
+.IX xdrrec_skiprecord() "" \fIxdrrec_skiprecord()\fP
+causes an input stream's position to be moved past
+the current record boundary and onto the
+beginning of the next record in the stream.
+.LP
+If there is no more data in the stream's input buffer,
+then the routine
+.I xdrrec_eof()
+.IX xdrrec_eof() "" \fIxdrrec_eof()\fP
+returns
+.I TRUE .
+That is not to say that there is no more data
+in the underlying file descriptor.
+.NH 2
+\&XDR Stream Implementation
+.IX "XDR" "stream implementation"
+.IX "stream implementation in XDR"
+.LP
+This section provides the abstract data types needed
+to implement new instances of XDR streams.
+.NH 3
+\&The XDR Object
+.IX "XDR" "object"
+.LP
+The following structure defines the interface to an XDR stream:
+.ie t .DS
+.el .DS L
+.ft CW
+enum xdr_op { XDR_ENCODE=0, XDR_DECODE=1, XDR_FREE=2 };
+.sp .5
+typedef struct {
+ enum xdr_op x_op; /* \fIoperation; fast added param\fP */
+ struct xdr_ops {
+ bool_t (*x_getlong)(); /* \fIget long from stream\fP */
+ bool_t (*x_putlong)(); /* \fIput long to stream\fP */
+ bool_t (*x_getbytes)(); /* \fIget bytes from stream\fP */
+ bool_t (*x_putbytes)(); /* \fIput bytes to stream\fP */
+ u_int (*x_getpostn)(); /* \fIreturn stream offset\fP */
+ bool_t (*x_setpostn)(); /* \fIreposition offset\fP */
+ caddr_t (*x_inline)(); /* \fIptr to buffered data\fP */
+ VOID (*x_destroy)(); /* \fIfree private area\fP */
+ } *x_ops;
+ caddr_t x_public; /* \fIusers' data\fP */
+ caddr_t x_private; /* \fIpointer to private data\fP */
+ caddr_t x_base; /* \fIprivate for position info\fP */
+ int x_handy; /* \fIextra private word\fP */
+} XDR;
+.DE
+The
+.I x_op
+field is the current operation being performed on the stream.
+This field is important to the XDR primitives,
+but should not affect a stream's implementation.
+That is, a stream's implementation should not depend
+on this value.
+The fields
+.I x_private ,
+.I x_base ,
+and
+.I x_handy
+are private to the particular
+stream's implementation.
+The field
+.I x_public
+is for the XDR client and should never be used by
+the XDR stream implementations or the XDR primitives.
+.I x_getpostn() ,
+.I x_setpostn()
+and
+.I x_destroy()
+are macros for accessing operations. The operation
+.I x_inline()
+takes two parameters:
+an XDR *, and an unsigned integer, which is a byte count.
+The routine returns a pointer to a piece of
+the stream's internal buffer.
+The caller can then use the buffer segment for any purpose.
+From the stream's point of view, the bytes in the
+buffer segment have been consumed or put.
+The routine may return
+.I NULL
+if it cannot return a buffer segment of the requested size.
+(The
+.I x_inline()
+routine is for cycle squeezers.
+Use of the resulting buffer is not data-portable.
+Users are encouraged not to use this feature.)
+.LP
+The operations
+.I x_getbytes()
+and
+.I x_putbytes()
+blindly get and put sequences of bytes
+from or to the underlying stream;
+they return
+.I TRUE
+if they are successful, and
+.I FALSE
+otherwise. The routines have identical parameters (replace
+.I xxx ):
+.DS
+.ft CW
+bool_t
+xxxbytes(xdrs, buf, bytecount)
+ XDR *xdrs;
+ char *buf;
+ u_int bytecount;
+.DE
+The operations
+.I x_getlong()
+and
+.I x_putlong()
+receive and put
+long numbers from and to the data stream.
+It is the responsibility of these routines
+to translate the numbers between the machine representation
+and the (standard) external representation.
+The UNIX primitives
+.I htonl()
+and
+.I ntohl()
+can be helpful in accomplishing this.
+The higher-level XDR implementation assumes that
+signed and unsigned long integers contain the same number of bits,
+and that nonnegative integers
+have the same bit representations as unsigned integers.
+The routines return
+.I TRUE
+if they succeed, and
+.I FALSE
+otherwise. They have identical parameters:
+.DS
+.ft CW
+bool_t
+xxxlong(xdrs, lp)
+ XDR *xdrs;
+ long *lp;
+.DE
+Implementors of new XDR streams must make an XDR structure
+(with new operation routines) available to clients,
+using some kind of create routine.
+.NH 1
+\&Advanced Topics
+.IX XDR "advanced topics"
+.LP
+This section describes techniques for passing data structures that
+are not covered in the preceding sections. Such structures include
+linked lists (of arbitrary lengths). Unlike the simpler examples
+covered in the earlier sections, the following examples are written
+using both the XDR C library routines and the XDR data description
+language.
+The
+.I "External Data Representation Standard: Protocol Specification"
+describes this
+language in complete detail.
+.NH 2
+\&Linked Lists
+.IX XDR "linked lists"
+.LP
+The last example in the
+.I Pointers
+topic earlier in this chapter
+presented a C data structure and its associated XDR
+routines for an individual's gross assets and liabilities.
+The example is duplicated below:
+.ie t .DS
+.el .DS L
+.ft CW
+struct gnumbers {
+ long g_assets;
+ long g_liabilities;
+};
+.sp .5
+bool_t
+xdr_gnumbers(xdrs, gp)
+ XDR *xdrs;
+ struct gnumbers *gp;
+{
+ if (xdr_long(xdrs, &(gp->g_assets)))
+ return(xdr_long(xdrs, &(gp->g_liabilities)));
+ return(FALSE);
+}
+.DE
+.LP
+Now assume that we wish to implement a linked list of such information.
+A data structure could be constructed as follows:
+.ie t .DS
+.el .DS L
+.ft CW
+struct gnumbers_node {
+ struct gnumbers gn_numbers;
+ struct gnumbers_node *gn_next;
+};
+.sp .5
+typedef struct gnumbers_node *gnumbers_list;
+.DE
+.LP
+The head of the linked list can be thought of as the data object;
+that is, the head is not merely a convenient shorthand for a
+structure. Similarly the
+.I gn_next
+field is used to indicate whether or not the object has terminated.
+Unfortunately, if the object continues, the
+.I gn_next
+field is also the address of where it continues. The link addresses
+carry no useful information when the object is serialized.
+.LP
+The XDR data description of this linked list is described by the
+recursive declaration of
+.I gnumbers_list :
+.ie t .DS
+.el .DS L
+.ft CW
+struct gnumbers {
+ int g_assets;
+ int g_liabilities;
+};
+.sp .5
+struct gnumbers_node {
+ gnumbers gn_numbers;
+ gnumbers_node *gn_next;
+};
+.DE
+.LP
+In this description, the boolean indicates whether there is more data
+following it. If the boolean is
+.I FALSE ,
+then it is the last data field of the structure. If it is
+.I TRUE ,
+then it is followed by a gnumbers structure and (recursively) by a
+.I gnumbers_list .
+Note that the C declaration has no boolean explicitly declared in it
+(though the
+.I gn_next
+field implicitly carries the information), while the XDR data
+description has no pointer explicitly declared in it.
+.LP
+Hints for writing the XDR routines for a
+.I gnumbers_list
+follow easily from the XDR description above. Note how the primitive
+.I xdr_pointer()
+is used to implement the XDR union above.
+.ie t .DS
+.el .DS L
+.ft CW
+bool_t
+xdr_gnumbers_node(xdrs, gn)
+ XDR *xdrs;
+ gnumbers_node *gn;
+{
+ return(xdr_gnumbers(xdrs, &gn->gn_numbers) &&
+ xdr_gnumbers_list(xdrs, &gp->gn_next));
+}
+.sp .5
+bool_t
+xdr_gnumbers_list(xdrs, gnp)
+ XDR *xdrs;
+ gnumbers_list *gnp;
+{
+ return(xdr_pointer(xdrs, gnp,
+ sizeof(struct gnumbers_node),
+ xdr_gnumbers_node));
+}
+.DE
+.LP
+The unfortunate side effect of XDR'ing a list with these routines
+is that the C stack grows linearly with respect to the number of
+node in the list. This is due to the recursion. The following
+routine collapses the above two mutually recursive into a single,
+non-recursive one.
+.ie t .DS
+.el .DS L
+.ft CW
+bool_t
+xdr_gnumbers_list(xdrs, gnp)
+ XDR *xdrs;
+ gnumbers_list *gnp;
+{
+ bool_t more_data;
+ gnumbers_list *nextp;
+.sp .5
+ for (;;) {
+ more_data = (*gnp != NULL);
+ if (!xdr_bool(xdrs, &more_data)) {
+ return(FALSE);
+ }
+ if (! more_data) {
+ break;
+ }
+ if (xdrs->x_op == XDR_FREE) {
+ nextp = &(*gnp)->gn_next;
+ }
+ if (!xdr_reference(xdrs, gnp,
+ sizeof(struct gnumbers_node), xdr_gnumbers)) {
+
+ return(FALSE);
+ }
+ gnp = (xdrs->x_op == XDR_FREE) ?
+ nextp : &(*gnp)->gn_next;
+ }
+ *gnp = NULL;
+ return(TRUE);
+}
+.DE
+.LP
+The first task is to find out whether there is more data or not,
+so that this boolean information can be serialized. Notice that
+this statement is unnecessary in the
+.I XDR_DECODE
+case, since the value of more_data is not known until we
+deserialize it in the next statement.
+.LP
+The next statement XDR's the more_data field of the XDR union.
+Then if there is truly no more data, we set this last pointer to
+.I NULL
+to indicate the end of the list, and return
+.I TRUE
+because we are done. Note that setting the pointer to
+.I NULL
+is only important in the
+.I XDR_DECODE
+case, since it is already
+.I NULL
+in the
+.I XDR_ENCODE
+and
+XDR_FREE
+cases.
+.LP
+Next, if the direction is
+.I XDR_FREE ,
+the value of
+.I nextp
+is set to indicate the location of the next pointer in the list.
+We do this now because we need to dereference gnp to find the
+location of the next item in the list, and after the next
+statement the storage pointed to by
+.I gnp
+will be freed up and no be longer valid. We can't do this for all
+directions though, because in the
+.I XDR_DECODE
+direction the value of
+.I gnp
+won't be set until the next statement.
+.LP
+Next, we XDR the data in the node using the primitive
+.I xdr_reference ().
+.I xdr_reference()
+is like
+.I xdr_pointer()
+which we used before, but it does not
+send over the boolean indicating whether there is more data.
+We use it instead of
+.I xdr_pointer()
+because we have already XDR'd this information ourselves. Notice
+that the xdr routine passed is not the same type as an element
+in the list. The routine passed is
+.I xdr_gnumbers (),
+for XDR'ing gnumbers, but each element in the list is actually of
+type
+.I gnumbers_node .
+We don't pass
+.I xdr_gnumbers_node()
+because it is recursive, and instead use
+.I xdr_gnumbers()
+which XDR's all of the non-recursive part. Note that this trick
+will work only if the
+.I gn_numbers
+field is the first item in each element, so that their addresses
+are identical when passed to
+.I xdr_reference ().
+.LP
+Finally, we update
+.I gnp
+to point to the next item in the list. If the direction is
+.I XDR_FREE ,
+we set it to the previously saved value, otherwise we can
+dereference
+.I gnp
+to get the proper value. Though harder to understand than the
+recursive version, this non-recursive routine is far less likely
+to blow the C stack. It will also run more efficiently since
+a lot of procedure call overhead has been removed. Most lists
+are small though (in the hundreds of items or less) and the
+recursive version should be sufficient for them.
+.EQ
+delim off
+.EN
diff --git a/lib/libc/rpc/PSD.doc/xdr.rfc.ms b/lib/libc/rpc/PSD.doc/xdr.rfc.ms
new file mode 100644
index 0000000..480a339
--- /dev/null
+++ b/lib/libc/rpc/PSD.doc/xdr.rfc.ms
@@ -0,0 +1,1060 @@
+.\"
+.\" Must use -- tbl -- with this one
+.\"
+.\" @(#)xdr.rfc.ms 2.2 88/08/05 4.0 RPCSRC
+.\" $FreeBSD$
+.\"
+.de BT
+.if \\n%=1 .tl ''- % -''
+..
+.ND
+.\" prevent excess underlining in nroff
+.if n .fp 2 R
+.OH 'External Data Representation Standard''Page %'
+.EH 'Page %''External Data Representation Standard'
+.if \n%=1 .bp
+.SH
+\&External Data Representation Standard: Protocol Specification
+.IX "External Data Representation"
+.IX XDR RFC
+.IX XDR "protocol specification"
+.LP
+.NH 0
+\&Status of this Standard
+.nr OF 1
+.IX XDR "RFC status"
+.LP
+Note: This chapter specifies a protocol that Sun Microsystems, Inc., and
+others are using. It has been designated RFC1014 by the ARPA Network
+Information Center.
+.NH 1
+Introduction
+\&
+.LP
+XDR is a standard for the description and encoding of data. It is
+useful for transferring data between different computer
+architectures, and has been used to communicate data between such
+diverse machines as the Sun Workstation, VAX, IBM-PC, and Cray.
+XDR fits into the ISO presentation layer, and is roughly analogous in
+purpose to X.409, ISO Abstract Syntax Notation. The major difference
+between these two is that XDR uses implicit typing, while X.409 uses
+explicit typing.
+.LP
+XDR uses a language to describe data formats. The language can only
+be used only to describe data; it is not a programming language.
+This language allows one to describe intricate data formats in a
+concise manner. The alternative of using graphical representations
+(itself an informal language) quickly becomes incomprehensible when
+faced with complexity. The XDR language itself is similar to the C
+language [1], just as Courier [4] is similar to Mesa. Protocols such
+as Sun RPC (Remote Procedure Call) and the NFS (Network File System)
+use XDR to describe the format of their data.
+.LP
+The XDR standard makes the following assumption: that bytes (or
+octets) are portable, where a byte is defined to be 8 bits of data.
+A given hardware device should encode the bytes onto the various
+media in such a way that other hardware devices may decode the bytes
+without loss of meaning. For example, the Ethernet standard
+suggests that bytes be encoded in "little-endian" style [2], or least
+significant bit first.
+.NH 2
+\&Basic Block Size
+.IX XDR "basic block size"
+.IX XDR "block size"
+.LP
+The representation of all items requires a multiple of four bytes (or
+32 bits) of data. The bytes are numbered 0 through n-1. The bytes
+are read or written to some byte stream such that byte m always
+precedes byte m+1. If the n bytes needed to contain the data are not
+a multiple of four, then the n bytes are followed by enough (0 to 3)
+residual zero bytes, r, to make the total byte count a multiple of 4.
+.LP
+We include the familiar graphic box notation for illustration and
+comparison. In most illustrations, each box (delimited by a plus
+sign at the 4 corners and vertical bars and dashes) depicts a byte.
+Ellipses (...) between boxes show zero or more additional bytes where
+required.
+.ie t .DS
+.el .DS L
+\fIA Block\fP
+
+\f(CW+--------+--------+...+--------+--------+...+--------+
+| byte 0 | byte 1 |...|byte n-1| 0 |...| 0 |
++--------+--------+...+--------+--------+...+--------+
+|<-----------n bytes---------->|<------r bytes------>|
+|<-----------n+r (where (n+r) mod 4 = 0)>----------->|\fP
+
+.DE
+.NH 1
+\&XDR Data Types
+.IX XDR "data types"
+.IX "XDR data types"
+.LP
+Each of the sections that follow describes a data type defined in the
+XDR standard, shows how it is declared in the language, and includes
+a graphic illustration of its encoding.
+.LP
+For each data type in the language we show a general paradigm
+declaration. Note that angle brackets (< and >) denote
+variable length sequences of data and square brackets ([ and ]) denote
+fixed-length sequences of data. "n", "m" and "r" denote integers.
+For the full language specification and more formal definitions of
+terms such as "identifier" and "declaration", refer to
+.I "The XDR Language Specification" ,
+below.
+.LP
+For some data types, more specific examples are included.
+A more extensive example of a data description is in
+.I "An Example of an XDR Data Description"
+below.
+.NH 2
+\&Integer
+.IX XDR integer
+.LP
+An XDR signed integer is a 32-bit datum that encodes an integer in
+the range [-2147483648,2147483647]. The integer is represented in
+two's complement notation. The most and least significant bytes are
+0 and 3, respectively. Integers are declared as follows:
+.ie t .DS
+.el .DS L
+\fIInteger\fP
+
+\f(CW(MSB) (LSB)
++-------+-------+-------+-------+
+|byte 0 |byte 1 |byte 2 |byte 3 |
++-------+-------+-------+-------+
+<------------32 bits------------>\fP
+.DE
+.NH 2
+\&Unsigned Integer
+.IX XDR "unsigned integer"
+.IX XDR "integer, unsigned"
+.LP
+An XDR unsigned integer is a 32-bit datum that encodes a nonnegative
+integer in the range [0,4294967295]. It is represented by an
+unsigned binary number whose most and least significant bytes are 0
+and 3, respectively. An unsigned integer is declared as follows:
+.ie t .DS
+.el .DS L
+\fIUnsigned Integer\fP
+
+\f(CW(MSB) (LSB)
++-------+-------+-------+-------+
+|byte 0 |byte 1 |byte 2 |byte 3 |
++-------+-------+-------+-------+
+<------------32 bits------------>\fP
+.DE
+.NH 2
+\&Enumeration
+.IX XDR enumeration
+.LP
+Enumerations have the same representation as signed integers.
+Enumerations are handy for describing subsets of the integers.
+Enumerated data is declared as follows:
+.ft CW
+.DS
+enum { name-identifier = constant, ... } identifier;
+.DE
+For example, the three colors red, yellow, and blue could be
+described by an enumerated type:
+.DS
+.ft CW
+enum { RED = 2, YELLOW = 3, BLUE = 5 } colors;
+.DE
+It is an error to encode as an enum any other integer than those that
+have been given assignments in the enum declaration.
+.NH 2
+\&Boolean
+.IX XDR boolean
+.LP
+Booleans are important enough and occur frequently enough to warrant
+their own explicit type in the standard. Booleans are declared as
+follows:
+.DS
+.ft CW
+bool identifier;
+.DE
+This is equivalent to:
+.DS
+.ft CW
+enum { FALSE = 0, TRUE = 1 } identifier;
+.DE
+.NH 2
+\&Hyper Integer and Unsigned Hyper Integer
+.IX XDR "hyper integer"
+.IX XDR "integer, hyper"
+.LP
+The standard also defines 64-bit (8-byte) numbers called hyper
+integer and unsigned hyper integer. Their representations are the
+obvious extensions of integer and unsigned integer defined above.
+They are represented in two's complement notation. The most and
+least significant bytes are 0 and 7, respectively. Their
+declarations:
+.ie t .DS
+.el .DS L
+\fIHyper Integer\fP
+\fIUnsigned Hyper Integer\fP
+
+\f(CW(MSB) (LSB)
++-------+-------+-------+-------+-------+-------+-------+-------+
+|byte 0 |byte 1 |byte 2 |byte 3 |byte 4 |byte 5 |byte 6 |byte 7 |
++-------+-------+-------+-------+-------+-------+-------+-------+
+<----------------------------64 bits---------------------------->\fP
+.DE
+.NH 2
+\&Floating-point
+.IX XDR "integer, floating point"
+.IX XDR "floating-point integer"
+.LP
+The standard defines the floating-point data type "float" (32 bits or
+4 bytes). The encoding used is the IEEE standard for normalized
+single-precision floating-point numbers [3]. The following three
+fields describe the single-precision floating-point number:
+.RS
+.IP \fBS\fP:
+The sign of the number. Values 0 and 1 represent positive and
+negative, respectively. One bit.
+.IP \fBE\fP:
+The exponent of the number, base 2. 8 bits are devoted to this
+field. The exponent is biased by 127.
+.IP \fBF\fP:
+The fractional part of the number's mantissa, base 2. 23 bits
+are devoted to this field.
+.RE
+.LP
+Therefore, the floating-point number is described by:
+.DS
+(-1)**S * 2**(E-Bias) * 1.F
+.DE
+It is declared as follows:
+.ie t .DS
+.el .DS L
+\fISingle-Precision Floating-Point\fP
+
+\f(CW+-------+-------+-------+-------+
+|byte 0 |byte 1 |byte 2 |byte 3 |
+S| E | F |
++-------+-------+-------+-------+
+1|<- 8 ->|<-------23 bits------>|
+<------------32 bits------------>\fP
+.DE
+Just as the most and least significant bytes of a number are 0 and 3,
+the most and least significant bits of a single-precision floating-
+point number are 0 and 31. The beginning bit (and most significant
+bit) offsets of S, E, and F are 0, 1, and 9, respectively. Note that
+these numbers refer to the mathematical positions of the bits, and
+NOT to their actual physical locations (which vary from medium to
+medium).
+.LP
+The IEEE specifications should be consulted concerning the encoding
+for signed zero, signed infinity (overflow), and denormalized numbers
+(underflow) [3]. According to IEEE specifications, the "NaN" (not a
+number) is system dependent and should not be used externally.
+.NH 2
+\&Double-precision Floating-point
+.IX XDR "integer, double-precision floating point"
+.IX XDR "double-precision floating-point integer"
+.LP
+The standard defines the encoding for the double-precision floating-
+point data type "double" (64 bits or 8 bytes). The encoding used is
+the IEEE standard for normalized double-precision floating-point
+numbers [3]. The standard encodes the following three fields, which
+describe the double-precision floating-point number:
+.RS
+.IP \fBS\fP:
+The sign of the number. Values 0 and 1 represent positive and
+negative, respectively. One bit.
+.IP \fBE\fP:
+The exponent of the number, base 2. 11 bits are devoted to this
+field. The exponent is biased by 1023.
+.IP \fBF\fP:
+The fractional part of the number's mantissa, base 2. 52 bits
+are devoted to this field.
+.RE
+.LP
+Therefore, the floating-point number is described by:
+.DS
+(-1)**S * 2**(E-Bias) * 1.F
+.DE
+It is declared as follows:
+.ie t .DS
+.el .DS L
+\fIDouble-Precision Floating-Point\fP
+
+\f(CW+------+------+------+------+------+------+------+------+
+|byte 0|byte 1|byte 2|byte 3|byte 4|byte 5|byte 6|byte 7|
+S| E | F |
++------+------+------+------+------+------+------+------+
+1|<--11-->|<-----------------52 bits------------------->|
+<-----------------------64 bits------------------------->\fP
+.DE
+Just as the most and least significant bytes of a number are 0 and 3,
+the most and least significant bits of a double-precision floating-
+point number are 0 and 63. The beginning bit (and most significant
+bit) offsets of S, E , and F are 0, 1, and 12, respectively. Note
+that these numbers refer to the mathematical positions of the bits,
+and NOT to their actual physical locations (which vary from medium to
+medium).
+.LP
+The IEEE specifications should be consulted concerning the encoding
+for signed zero, signed infinity (overflow), and denormalized numbers
+(underflow) [3]. According to IEEE specifications, the "NaN" (not a
+number) is system dependent and should not be used externally.
+.NH 2
+\&Fixed-length Opaque Data
+.IX XDR "fixed-length opaque data"
+.IX XDR "opaque data, fixed length"
+.LP
+At times, fixed-length uninterpreted data needs to be passed among
+machines. This data is called "opaque" and is declared as follows:
+.DS
+.ft CW
+opaque identifier[n];
+.DE
+where the constant n is the (static) number of bytes necessary to
+contain the opaque data. If n is not a multiple of four, then the n
+bytes are followed by enough (0 to 3) residual zero bytes, r, to make
+the total byte count of the opaque object a multiple of four.
+.ie t .DS
+.el .DS L
+\fIFixed-Length Opaque\fP
+
+\f(CW0 1 ...
++--------+--------+...+--------+--------+...+--------+
+| byte 0 | byte 1 |...|byte n-1| 0 |...| 0 |
++--------+--------+...+--------+--------+...+--------+
+|<-----------n bytes---------->|<------r bytes------>|
+|<-----------n+r (where (n+r) mod 4 = 0)------------>|\fP
+.DE
+.NH 2
+\&Variable-length Opaque Data
+.IX XDR "variable-length opaque data"
+.IX XDR "opaque data, variable length"
+.LP
+The standard also provides for variable-length (counted) opaque data,
+defined as a sequence of n (numbered 0 through n-1) arbitrary bytes
+to be the number n encoded as an unsigned integer (as described
+below), and followed by the n bytes of the sequence.
+.LP
+Byte m of the sequence always precedes byte m+1 of the sequence, and
+byte 0 of the sequence always follows the sequence's length (count).
+enough (0 to 3) residual zero bytes, r, to make the total byte count
+a multiple of four. Variable-length opaque data is declared in the
+following way:
+.DS
+.ft CW
+opaque identifier<m>;
+.DE
+or
+.DS
+.ft CW
+opaque identifier<>;
+.DE
+The constant m denotes an upper bound of the number of bytes that the
+sequence may contain. If m is not specified, as in the second
+declaration, it is assumed to be (2**32) - 1, the maximum length.
+The constant m would normally be found in a protocol specification.
+For example, a filing protocol may state that the maximum data
+transfer size is 8192 bytes, as follows:
+.DS
+.ft CW
+opaque filedata<8192>;
+.DE
+This can be illustrated as follows:
+.ie t .DS
+.el .DS L
+\fIVariable-Length Opaque\fP
+
+\f(CW0 1 2 3 4 5 ...
++-----+-----+-----+-----+-----+-----+...+-----+-----+...+-----+
+| length n |byte0|byte1|...| n-1 | 0 |...| 0 |
++-----+-----+-----+-----+-----+-----+...+-----+-----+...+-----+
+|<-------4 bytes------->|<------n bytes------>|<---r bytes--->|
+|<----n+r (where (n+r) mod 4 = 0)---->|\fP
+.DE
+.LP
+It is an error to encode a length greater than the maximum
+described in the specification.
+.NH 2
+\&String
+.IX XDR string
+.LP
+The standard defines a string of n (numbered 0 through n-1) ASCII
+bytes to be the number n encoded as an unsigned integer (as described
+above), and followed by the n bytes of the string. Byte m of the
+string always precedes byte m+1 of the string, and byte 0 of the
+string always follows the string's length. If n is not a multiple of
+four, then the n bytes are followed by enough (0 to 3) residual zero
+bytes, r, to make the total byte count a multiple of four. Counted
+byte strings are declared as follows:
+.DS
+.ft CW
+string object<m>;
+.DE
+or
+.DS
+.ft CW
+string object<>;
+.DE
+The constant m denotes an upper bound of the number of bytes that a
+string may contain. If m is not specified, as in the second
+declaration, it is assumed to be (2**32) - 1, the maximum length.
+The constant m would normally be found in a protocol specification.
+For example, a filing protocol may state that a file name can be no
+longer than 255 bytes, as follows:
+.DS
+.ft CW
+string filename<255>;
+.DE
+Which can be illustrated as:
+.ie t .DS
+.el .DS L
+\fIA String\fP
+
+\f(CW0 1 2 3 4 5 ...
++-----+-----+-----+-----+-----+-----+...+-----+-----+...+-----+
+| length n |byte0|byte1|...| n-1 | 0 |...| 0 |
++-----+-----+-----+-----+-----+-----+...+-----+-----+...+-----+
+|<-------4 bytes------->|<------n bytes------>|<---r bytes--->|
+|<----n+r (where (n+r) mod 4 = 0)---->|\fP
+.DE
+.LP
+It is an error to encode a length greater than the maximum
+described in the specification.
+.NH 2
+\&Fixed-length Array
+.IX XDR "fixed-length array"
+.IX XDR "array, fixed length"
+.LP
+Declarations for fixed-length arrays of homogeneous elements are in
+the following form:
+.DS
+.ft CW
+type-name identifier[n];
+.DE
+Fixed-length arrays of elements numbered 0 through n-1 are encoded by
+individually encoding the elements of the array in their natural
+order, 0 through n-1. Each element's size is a multiple of four
+bytes. Though all elements are of the same type, the elements may
+have different sizes. For example, in a fixed-length array of
+strings, all elements are of type "string", yet each element will
+vary in its length.
+.ie t .DS
+.el .DS L
+\fIFixed-Length Array\fP
+
+\f(CW+---+---+---+---+---+---+---+---+...+---+---+---+---+
+| element 0 | element 1 |...| element n-1 |
++---+---+---+---+---+---+---+---+...+---+---+---+---+
+|<--------------------n elements------------------->|\fP
+.DE
+.NH 2
+\&Variable-length Array
+.IX XDR "variable-length array"
+.IX XDR "array, variable length"
+.LP
+Counted arrays provide the ability to encode variable-length arrays
+of homogeneous elements. The array is encoded as the element count n
+(an unsigned integer) followed by the encoding of each of the array's
+elements, starting with element 0 and progressing through element n-
+1. The declaration for variable-length arrays follows this form:
+.DS
+.ft CW
+type-name identifier<m>;
+.DE
+or
+.DS
+.ft CW
+type-name identifier<>;
+.DE
+The constant m specifies the maximum acceptable element count of an
+array; if m is not specified, as in the second declaration, it is
+assumed to be (2**32) - 1.
+.ie t .DS
+.el .DS L
+\fICounted Array\fP
+
+\f(CW0 1 2 3
++--+--+--+--+--+--+--+--+--+--+--+--+...+--+--+--+--+
+| n | element 0 | element 1 |...|element n-1|
++--+--+--+--+--+--+--+--+--+--+--+--+...+--+--+--+--+
+|<-4 bytes->|<--------------n elements------------->|\fP
+.DE
+It is an error to encode a value of n that is greater than the
+maximum described in the specification.
+.NH 2
+\&Structure
+.IX XDR structure
+.LP
+Structures are declared as follows:
+.DS
+.ft CW
+struct {
+ component-declaration-A;
+ component-declaration-B;
+ \&...
+} identifier;
+.DE
+The components of the structure are encoded in the order of their
+declaration in the structure. Each component's size is a multiple of
+four bytes, though the components may be different sizes.
+.ie t .DS
+.el .DS L
+\fIStructure\fP
+
+\f(CW+-------------+-------------+...
+| component A | component B |...
++-------------+-------------+...\fP
+.DE
+.NH 2
+\&Discriminated Union
+.IX XDR "discriminated union"
+.IX XDR union discriminated
+.LP
+A discriminated union is a type composed of a discriminant followed
+by a type selected from a set of prearranged types according to the
+value of the discriminant. The type of discriminant is either "int",
+"unsigned int", or an enumerated type, such as "bool". The component
+types are called "arms" of the union, and are preceded by the value
+of the discriminant which implies their encoding. Discriminated
+unions are declared as follows:
+.DS
+.ft CW
+union switch (discriminant-declaration) {
+ case discriminant-value-A:
+ arm-declaration-A;
+ case discriminant-value-B:
+ arm-declaration-B;
+ \&...
+ default: default-declaration;
+} identifier;
+.DE
+Each "case" keyword is followed by a legal value of the discriminant.
+The default arm is optional. If it is not specified, then a valid
+encoding of the union cannot take on unspecified discriminant values.
+The size of the implied arm is always a multiple of four bytes.
+.LP
+The discriminated union is encoded as its discriminant followed by
+the encoding of the implied arm.
+.ie t .DS
+.el .DS L
+\fIDiscriminated Union\fP
+
+\f(CW0 1 2 3
++---+---+---+---+---+---+---+---+
+| discriminant | implied arm |
++---+---+---+---+---+---+---+---+
+|<---4 bytes--->|\fP
+.DE
+.NH 2
+\&Void
+.IX XDR void
+.LP
+An XDR void is a 0-byte quantity. Voids are useful for describing
+operations that take no data as input or no data as output. They are
+also useful in unions, where some arms may contain data and others do
+not. The declaration is simply as follows:
+.DS
+.ft CW
+void;
+.DE
+Voids are illustrated as follows:
+.ie t .DS
+.el .DS L
+\fIVoid\fP
+
+\f(CW ++
+ ||
+ ++
+--><-- 0 bytes\fP
+.DE
+.NH 2
+\&Constant
+.IX XDR constant
+.LP
+The data declaration for a constant follows this form:
+.DS
+.ft CW
+const name-identifier = n;
+.DE
+"const" is used to define a symbolic name for a constant; it does not
+declare any data. The symbolic constant may be used anywhere a
+regular constant may be used. For example, the following defines a
+symbolic constant DOZEN, equal to 12.
+.DS
+.ft CW
+const DOZEN = 12;
+.DE
+.NH 2
+\&Typedef
+.IX XDR typedef
+.LP
+"typedef" does not declare any data either, but serves to define new
+identifiers for declaring data. The syntax is:
+.DS
+.ft CW
+typedef declaration;
+.DE
+The new type name is actually the variable name in the declaration
+part of the typedef. For example, the following defines a new type
+called "eggbox" using an existing type called "egg":
+.DS
+.ft CW
+typedef egg eggbox[DOZEN];
+.DE
+Variables declared using the new type name have the same type as the
+new type name would have in the typedef, if it was considered a
+variable. For example, the following two declarations are equivalent
+in declaring the variable "fresheggs":
+.DS
+.ft CW
+eggbox fresheggs;
+egg fresheggs[DOZEN];
+.DE
+When a typedef involves a struct, enum, or union definition, there is
+another (preferred) syntax that may be used to define the same type.
+In general, a typedef of the following form:
+.DS
+.ft CW
+typedef <<struct, union, or enum definition>> identifier;
+.DE
+may be converted to the alternative form by removing the "typedef"
+part and placing the identifier after the "struct", "union", or
+"enum" keyword, instead of at the end. For example, here are the two
+ways to define the type "bool":
+.DS
+.ft CW
+typedef enum { /* \fIusing typedef\fP */
+ FALSE = 0,
+ TRUE = 1
+ } bool;
+
+enum bool { /* \fIpreferred alternative\fP */
+ FALSE = 0,
+ TRUE = 1
+ };
+.DE
+The reason this syntax is preferred is one does not have to wait
+until the end of a declaration to figure out the name of the new
+type.
+.NH 2
+\&Optional-data
+.IX XDR "optional data"
+.IX XDR "data, optional"
+.LP
+Optional-data is one kind of union that occurs so frequently that we
+give it a special syntax of its own for declaring it. It is declared
+as follows:
+.DS
+.ft CW
+type-name *identifier;
+.DE
+This is equivalent to the following union:
+.DS
+.ft CW
+union switch (bool opted) {
+ case TRUE:
+ type-name element;
+ case FALSE:
+ void;
+} identifier;
+.DE
+It is also equivalent to the following variable-length array
+declaration, since the boolean "opted" can be interpreted as the
+length of the array:
+.DS
+.ft CW
+type-name identifier<1>;
+.DE
+Optional-data is not so interesting in itself, but it is very useful
+for describing recursive data-structures such as linked-lists and
+trees. For example, the following defines a type "stringlist" that
+encodes lists of arbitrary length strings:
+.DS
+.ft CW
+struct *stringlist {
+ string item<>;
+ stringlist next;
+};
+.DE
+It could have been equivalently declared as the following union:
+.DS
+.ft CW
+union stringlist switch (bool opted) {
+ case TRUE:
+ struct {
+ string item<>;
+ stringlist next;
+ } element;
+ case FALSE:
+ void;
+};
+.DE
+or as a variable-length array:
+.DS
+.ft CW
+struct stringlist<1> {
+ string item<>;
+ stringlist next;
+};
+.DE
+Both of these declarations obscure the intention of the stringlist
+type, so the optional-data declaration is preferred over both of
+them. The optional-data type also has a close correlation to how
+recursive data structures are represented in high-level languages
+such as Pascal or C by use of pointers. In fact, the syntax is the
+same as that of the C language for pointers.
+.NH 2
+\&Areas for Future Enhancement
+.IX XDR futures
+.LP
+The XDR standard lacks representations for bit fields and bitmaps,
+since the standard is based on bytes. Also missing are packed (or
+binary-coded) decimals.
+.LP
+The intent of the XDR standard was not to describe every kind of data
+that people have ever sent or will ever want to send from machine to
+machine. Rather, it only describes the most commonly used data-types
+of high-level languages such as Pascal or C so that applications
+written in these languages will be able to communicate easily over
+some medium.
+.LP
+One could imagine extensions to XDR that would let it describe almost
+any existing protocol, such as TCP. The minimum necessary for this
+are support for different block sizes and byte-orders. The XDR
+discussed here could then be considered the 4-byte big-endian member
+of a larger XDR family.
+.NH 1
+\&Discussion
+.sp 2
+.NH 2
+\&Why a Language for Describing Data?
+.IX XDR language
+.LP
+There are many advantages in using a data-description language such
+as XDR versus using diagrams. Languages are more formal than
+diagrams and lead to less ambiguous descriptions of data.
+Languages are also easier to understand and allow one to think of
+other issues instead of the low-level details of bit-encoding.
+Also, there is a close analogy between the types of XDR and a
+high-level language such as C or Pascal. This makes the
+implementation of XDR encoding and decoding modules an easier task.
+Finally, the language specification itself is an ASCII string that
+can be passed from machine to machine to perform on-the-fly data
+interpretation.
+.NH 2
+\&Why Only one Byte-Order for an XDR Unit?
+.IX XDR "byte order"
+.LP
+Supporting two byte-orderings requires a higher level protocol for
+determining in which byte-order the data is encoded. Since XDR is
+not a protocol, this can't be done. The advantage of this, though,
+is that data in XDR format can be written to a magnetic tape, for
+example, and any machine will be able to interpret it, since no
+higher level protocol is necessary for determining the byte-order.
+.NH 2
+\&Why does XDR use Big-Endian Byte-Order?
+.LP
+Yes, it is unfair, but having only one byte-order means you have to
+be unfair to somebody. Many architectures, such as the Motorola
+68000 and IBM 370, support the big-endian byte-order.
+.NH 2
+\&Why is the XDR Unit Four Bytes Wide?
+.LP
+There is a tradeoff in choosing the XDR unit size. Choosing a small
+size such as two makes the encoded data small, but causes alignment
+problems for machines that aren't aligned on these boundaries. A
+large size such as eight means the data will be aligned on virtually
+every machine, but causes the encoded data to grow too big. We chose
+four as a compromise. Four is big enough to support most
+architectures efficiently, except for rare machines such as the
+eight-byte aligned Cray. Four is also small enough to keep the
+encoded data restricted to a reasonable size.
+.NH 2
+\&Why must Variable-Length Data be Padded with Zeros?
+.IX XDR "variable-length data"
+.LP
+It is desirable that the same data encode into the same thing on all
+machines, so that encoded data can be meaningfully compared or
+checksummed. Forcing the padded bytes to be zero ensures this.
+.NH 2
+\&Why is there No Explicit Data-Typing?
+.LP
+Data-typing has a relatively high cost for what small advantages it
+may have. One cost is the expansion of data due to the inserted type
+fields. Another is the added cost of interpreting these type fields
+and acting accordingly. And most protocols already know what type
+they expect, so data-typing supplies only redundant information.
+However, one can still get the benefits of data-typing using XDR. One
+way is to encode two things: first a string which is the XDR data
+description of the encoded data, and then the encoded data itself.
+Another way is to assign a value to all the types in XDR, and then
+define a universal type which takes this value as its discriminant
+and for each value, describes the corresponding data type.
+.NH 1
+\&The XDR Language Specification
+.IX XDR language
+.sp 1
+.NH 2
+\&Notational Conventions
+.IX "XDR language" notation
+.LP
+This specification uses an extended Backus-Naur Form notation for
+describing the XDR language. Here is a brief description of the
+notation:
+.IP 1.
+The characters
+.I | ,
+.I ( ,
+.I ) ,
+.I [ ,
+.I ] ,
+.I " ,
+and
+.I *
+are special.
+.IP 2.
+Terminal symbols are strings of any characters surrounded by
+double quotes.
+.IP 3.
+Non-terminal symbols are strings of non-special characters.
+.IP 4.
+Alternative items are separated by a vertical bar ("\fI|\fP").
+.IP 5.
+Optional items are enclosed in brackets.
+.IP 6.
+Items are grouped together by enclosing them in parentheses.
+.IP 7.
+A
+.I *
+following an item means 0 or more occurrences of that item.
+.LP
+For example, consider the following pattern:
+.DS L
+"a " "very" (", " " very")* [" cold " "and"] " rainy " ("day" | "night")
+.DE
+.LP
+An infinite number of strings match this pattern. A few of them
+are:
+.DS
+"a very rainy day"
+"a very, very rainy day"
+"a very cold and rainy day"
+"a very, very, very cold and rainy night"
+.DE
+.NH 2
+\&Lexical Notes
+.IP 1.
+Comments begin with '/*' and terminate with '*/'.
+.IP 2.
+White space serves to separate items and is otherwise ignored.
+.IP 3.
+An identifier is a letter followed by an optional sequence of
+letters, digits or underbar ('_'). The case of identifiers is
+not ignored.
+.IP 4.
+A constant is a sequence of one or more decimal digits,
+optionally preceded by a minus-sign ('-').
+.NH 2
+\&Syntax Information
+.IX "XDR language" syntax
+.DS
+.ft CW
+declaration:
+ type-specifier identifier
+ | type-specifier identifier "[" value "]"
+ | type-specifier identifier "<" [ value ] ">"
+ | "opaque" identifier "[" value "]"
+ | "opaque" identifier "<" [ value ] ">"
+ | "string" identifier "<" [ value ] ">"
+ | type-specifier "*" identifier
+ | "void"
+.DE
+.DS
+.ft CW
+value:
+ constant
+ | identifier
+
+type-specifier:
+ [ "unsigned" ] "int"
+ | [ "unsigned" ] "hyper"
+ | "float"
+ | "double"
+ | "bool"
+ | enum-type-spec
+ | struct-type-spec
+ | union-type-spec
+ | identifier
+.DE
+.DS
+.ft CW
+enum-type-spec:
+ "enum" enum-body
+
+enum-body:
+ "{"
+ ( identifier "=" value )
+ ( "," identifier "=" value )*
+ "}"
+.DE
+.DS
+.ft CW
+struct-type-spec:
+ "struct" struct-body
+
+struct-body:
+ "{"
+ ( declaration ";" )
+ ( declaration ";" )*
+ "}"
+.DE
+.DS
+.ft CW
+union-type-spec:
+ "union" union-body
+
+union-body:
+ "switch" "(" declaration ")" "{"
+ ( "case" value ":" declaration ";" )
+ ( "case" value ":" declaration ";" )*
+ [ "default" ":" declaration ";" ]
+ "}"
+
+constant-def:
+ "const" identifier "=" constant ";"
+.DE
+.DS
+.ft CW
+type-def:
+ "typedef" declaration ";"
+ | "enum" identifier enum-body ";"
+ | "struct" identifier struct-body ";"
+ | "union" identifier union-body ";"
+
+definition:
+ type-def
+ | constant-def
+
+specification:
+ definition *
+.DE
+.NH 3
+\&Syntax Notes
+.IX "XDR language" syntax
+.LP
+.IP 1.
+The following are keywords and cannot be used as identifiers:
+"bool", "case", "const", "default", "double", "enum", "float",
+"hyper", "opaque", "string", "struct", "switch", "typedef", "union",
+"unsigned" and "void".
+.IP 2.
+Only unsigned constants may be used as size specifications for
+arrays. If an identifier is used, it must have been declared
+previously as an unsigned constant in a "const" definition.
+.IP 3.
+Constant and type identifiers within the scope of a specification
+are in the same name space and must be declared uniquely within this
+scope.
+.IP 4.
+Similarly, variable names must be unique within the scope of
+struct and union declarations. Nested struct and union declarations
+create new scopes.
+.IP 5.
+The discriminant of a union must be of a type that evaluates to
+an integer. That is, "int", "unsigned int", "bool", an enumerated
+type or any typedefed type that evaluates to one of these is legal.
+Also, the case values must be one of the legal values of the
+discriminant. Finally, a case value may not be specified more than
+once within the scope of a union declaration.
+.NH 1
+\&An Example of an XDR Data Description
+.LP
+Here is a short XDR data description of a thing called a "file",
+which might be used to transfer files from one machine to another.
+.ie t .DS
+.el .DS L
+.ft CW
+
+const MAXUSERNAME = 32; /*\fI max length of a user name \fP*/
+const MAXFILELEN = 65535; /*\fI max length of a file \fP*/
+const MAXNAMELEN = 255; /*\fI max length of a file name \fP*/
+
+.ft I
+/*
+ * Types of files:
+ */
+.ft CW
+
+enum filekind {
+ TEXT = 0, /*\fI ascii data \fP*/
+ DATA = 1, /*\fI raw data \fP*/
+ EXEC = 2 /*\fI executable \fP*/
+};
+
+.ft I
+/*
+ * File information, per kind of file:
+ */
+.ft CW
+
+union filetype switch (filekind kind) {
+ case TEXT:
+ void; /*\fI no extra information \fP*/
+ case DATA:
+ string creator<MAXNAMELEN>; /*\fI data creator \fP*/
+ case EXEC:
+ string interpretor<MAXNAMELEN>; /*\fI program interpretor \fP*/
+};
+
+.ft I
+/*
+ * A complete file:
+ */
+.ft CW
+
+struct file {
+ string filename<MAXNAMELEN>; /*\fI name of file \fP*/
+ filetype type; /*\fI info about file \fP*/
+ string owner<MAXUSERNAME>; /*\fI owner of file \fP*/
+ opaque data<MAXFILELEN>; /*\fI file data \fP*/
+};
+.DE
+.LP
+Suppose now that there is a user named "john" who wants to store
+his lisp program "sillyprog" that contains just the data "(quit)".
+His file would be encoded as follows:
+.TS
+box tab (&) ;
+lfI lfI lfI lfI
+rfL rfL rfL l .
+Offset&Hex Bytes&ASCII&Description
+_
+0&00 00 00 09&....&Length of filename = 9
+4&73 69 6c 6c&sill&Filename characters
+8&79 70 72 6f&ypro& ... and more characters ...
+12&67 00 00 00&g...& ... and 3 zero-bytes of fill
+16&00 00 00 02&....&Filekind is EXEC = 2
+20&00 00 00 04&....&Length of interpretor = 4
+24&6c 69 73 70&lisp&Interpretor characters
+28&00 00 00 04&....&Length of owner = 4
+32&6a 6f 68 6e&john&Owner characters
+36&00 00 00 06&....&Length of file data = 6
+40&28 71 75 69&(qui&File data bytes ...
+44&74 29 00 00&t)..& ... and 2 zero-bytes of fill
+.TE
+.NH 1
+\&References
+.LP
+[1] Brian W. Kernighan & Dennis M. Ritchie, "The C Programming
+Language", Bell Laboratories, Murray Hill, New Jersey, 1978.
+.LP
+[2] Danny Cohen, "On Holy Wars and a Plea for Peace", IEEE Computer,
+October 1981.
+.LP
+[3] "IEEE Standard for Binary Floating-Point Arithmetic", ANSI/IEEE
+Standard 754-1985, Institute of Electrical and Electronics
+Engineers, August 1985.
+.LP
+[4] "Courier: The Remote Procedure Call Protocol", XEROX
+Corporation, XSIS 038112, December 1981.
diff --git a/lib/libc/rpc/README b/lib/libc/rpc/README
new file mode 100644
index 0000000..c915fad
--- /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 siginificant 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 0000000..98dc510
--- /dev/null
+++ b/lib/libc/rpc/Symbol.map
@@ -0,0 +1,244 @@
+# $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;
+ getnetid;
+ 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 {
+ __des_crypt_LOCAL;
+ __key_encryptsession_pk_LOCAL;
+ __key_decryptsession_pk_LOCAL;
+ __key_gendes_LOCAL;
+ __tsd_lock; # Why does usr.bin/rpcinfo/Makefile need rpc_generic.c?
+ # Remove this hack if rpcinfo stops building with it.
+ __svc_clean_idle;
+};
diff --git a/lib/libc/rpc/auth_des.c b/lib/libc/rpc/auth_des.c
new file mode 100644
index 0000000..8f363e9
--- /dev/null
+++ b/lib/libc/rpc/auth_des.c
@@ -0,0 +1,498 @@
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+/*
+ * 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();
+
+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)
+{
+ /* 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, (struct timezone *)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)
+{
+/* 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 0000000..01ad701
--- /dev/null
+++ b/lib/libc/rpc/auth_none.c
@@ -0,0 +1,176 @@
+/* $NetBSD: auth_none.c,v 1.13 2000/01/22 22:19:17 mycroft Exp $ */
+
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#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();
+
+static struct auth_ops *authnone_ops();
+
+static struct authnone_private {
+ AUTH no_client;
+ char marshalled_client[MAX_MARSHAL_SIZE];
+ u_int mcnt;
+} *authnone_private;
+
+AUTH *
+authnone_create()
+{
+ struct authnone_private *ap = authnone_private;
+ XDR xdr_stream;
+ XDR *xdrs;
+
+ mutex_lock(&authnone_lock);
+ if (ap == 0) {
+ ap = (struct authnone_private *)calloc(1, sizeof (*ap));
+ if (ap == 0) {
+ 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()
+{
+ 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 0000000..ae108c2
--- /dev/null
+++ b/lib/libc/rpc/auth_time.c
@@ -0,0 +1,498 @@
+/* #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(s)
+ 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(uaddr, sin)
+#ifdef foo
+ endpoint *endpt;
+#endif
+ 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(eps, num)
+ 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.
+ */
+static nis_server *
+get_server(sin, host, srv, eps, maxep)
+ struct sockaddr_in *sin;
+ char *host; /* name of the time host */
+ nis_server *srv; /* nis_server struct to use. */
+ endpoint eps[]; /* array of endpoints */
+ int maxep; /* max array size */
+{
+ char hname[256];
+ int num_ep = 0, i;
+ struct hostent *he;
+ struct hostent dummy;
+ char *ptr[2];
+
+ 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; (he->h_addr_list[i] != NULL) && (num_ep < maxep);
+ i++, 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));
+ eps[num_ep].uaddr = strdup(hname);
+ eps[num_ep].family = strdup("inet");
+ eps[num_ep].proto = strdup("tcp");
+ }
+
+ for (i = 0; (he->h_addr_list[i] != NULL) && (num_ep < maxep);
+ i++, 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));
+ eps[num_ep].uaddr = strdup(hname);
+ eps[num_ep].family = strdup("inet");
+ eps[num_ep].proto = strdup("udp");
+ }
+
+ 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"
+ */
+int
+__rpc_get_time_offset(td, srv, thost, uaddr, netid)
+ struct timeval *td; /* Time difference */
+ nis_server *srv; /* NIS Server description */
+ char *thost; /* if no server, this is the timehost */
+ char **uaddr; /* known universal address */
+ struct sockaddr_in *netid; /* known network identifier */
+{
+ 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)() = 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 (*)())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 0000000..3fcccd4
--- /dev/null
+++ b/lib/libc/rpc/auth_unix.c
@@ -0,0 +1,373 @@
+/* $NetBSD: auth_unix.c,v 1.18 2000/07/06 03:03:30 christos Exp $ */
+
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#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(machname, uid, gid, len, aup_gids)
+ char *machname;
+ int uid;
+ int gid;
+ int len;
+ 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()
+{
+ int len;
+ char machname[MAXHOSTNAMELEN + 1];
+ uid_t uid;
+ gid_t gid;
+ gid_t gids[NGRPS];
+
+ if (gethostname(machname, sizeof machname) == -1)
+ abort();
+ machname[sizeof(machname) - 1] = 0;
+ uid = geteuid();
+ gid = getegid();
+ if ((len = getgroups(NGRPS, gids)) < 0)
+ abort();
+ /* XXX: interface problem; those should all have been unsigned */
+ return (authunix_create(machname, (int)uid, (int)gid, len,
+ (int *)gids));
+}
+
+/*
+ * authunix operations
+ */
+
+/* ARGSUSED */
+static void
+authunix_nextverf(auth)
+ AUTH *auth;
+{
+ /* no action necessary */
+}
+
+static bool_t
+authunix_marshal(auth, xdrs)
+ 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, verf)
+ 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 *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 *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()
+{
+ 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 0000000..19969b0
--- /dev/null
+++ b/lib/libc/rpc/authdes_prot.c
@@ -0,0 +1,93 @@
+#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$");
+
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+/*
+ * 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(xdrs, cred)
+ XDR *xdrs;
+ struct authdes_cred *cred;
+{
+ /*
+ * Unrolled xdr
+ */
+ ATTEMPT(xdr_enum(xdrs, (enum_t *)&cred->adc_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(xdrs, 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 0000000..441ba40
--- /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 $ */
+
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#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(xdrs, p)
+ XDR *xdrs;
+ struct authunix_parms *p;
+{
+
+ assert(xdrs != NULL);
+ assert(p != NULL);
+
+ if (xdr_u_long(xdrs, &(p->aup_time))
+ && xdr_string(xdrs, &(p->aup_machname), MAX_MACHINE_NAME)
+ && xdr_int(xdrs, &(p->aup_uid))
+ && xdr_int(xdrs, &(p->aup_gid))
+ && xdr_array(xdrs, (caddr_t *)&(p->aup_gids),
+ &(p->aup_len), NGRPS, sizeof(int), (xdrproc_t)xdr_int) ) {
+ return (TRUE);
+ }
+ return (FALSE);
+}
diff --git a/lib/libc/rpc/bindresvport.3 b/lib/libc/rpc/bindresvport.3
new file mode 100644
index 0000000..28e86e5
--- /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 0000000..75a1c8f
--- /dev/null
+++ b/lib/libc/rpc/bindresvport.c
@@ -0,0 +1,161 @@
+/* $NetBSD: bindresvport.c,v 1.19 2000/07/06 03:03:59 christos Exp $ */
+
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#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(sd, sin)
+ int sd;
+ struct sockaddr_in *sin;
+{
+ return bindresvport_sa(sd, (struct sockaddr *)sin);
+}
+
+/*
+ * Bind a socket to a privileged IP port
+ */
+int
+bindresvport_sa(sd, 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 0000000..5c48cf8
--- /dev/null
+++ b/lib/libc/rpc/clnt_bcast.c
@@ -0,0 +1,670 @@
+/* $NetBSD: clnt_bcast.c,v 1.3 2000/07/06 03:05:20 christos Exp $ */
+
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+/*
+ * 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)
+ 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;
+}
+
+
+enum clnt_stat
+rpc_broadcast_exp(prog, vers, proc, xargs, argsp, xresults, resultsp,
+ eachresult, inittime, waittime, nettype)
+ rpcprog_t prog; /* program number */
+ rpcvers_t vers; /* version number */
+ rpcproc_t proc; /* procedure number */
+ xdrproc_t xargs; /* xdr routine for args */
+ caddr_t argsp; /* pointer to args */
+ xdrproc_t xresults; /* xdr routine for results */
+ caddr_t resultsp; /* pointer to results */
+ resultproc_t eachresult; /* call with each result obtained */
+ int inittime; /* how long to wait initially */
+ int waittime; /* maximum time to wait */
+ const char *nettype; /* transport type */
+{
+ 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();
+ 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) {
+ 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;
+ if ((outbuf_pmap = malloc(udpbufsz)) == 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:
+ if (inbuf)
+ (void) free(inbuf);
+ if (outbuf)
+ (void) free(outbuf);
+#ifdef PORTMAP
+ if (outbuf_pmap)
+ (void) 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);
+}
+
+
+enum clnt_stat
+rpc_broadcast(prog, vers, proc, xargs, argsp, xresults, resultsp,
+ eachresult, nettype)
+ rpcprog_t prog; /* program number */
+ rpcvers_t vers; /* version number */
+ rpcproc_t proc; /* procedure number */
+ xdrproc_t xargs; /* xdr routine for args */
+ caddr_t argsp; /* pointer to args */
+ xdrproc_t xresults; /* xdr routine for results */
+ caddr_t resultsp; /* pointer to results */
+ resultproc_t eachresult; /* call with each result obtained */
+ const char *nettype; /* transport type */
+{
+ 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 0000000..761cc65
--- /dev/null
+++ b/lib/libc/rpc/clnt_dg.c
@@ -0,0 +1,788 @@
+/* $NetBSD: clnt_dg.c,v 1.4 2000/07/14 08:40:41 fvdl Exp $ */
+
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+/*
+ * 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 <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"
+
+
+#define RPC_MAX_BACKOFF 30 /* seconds */
+
+
+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 */
+
+/*
+ * 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_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.
+ */
+CLIENT *
+clnt_dg_create(fd, svcaddr, program, version, sendsz, recvsz)
+ int fd; /* open file descriptor */
+ const struct netbuf *svcaddr; /* servers address */
+ rpcprog_t program; /* program number */
+ rpcvers_t version; /* version number */
+ u_int sendsz; /* buffer recv size */
+ u_int recvsz; /* buffer send size */
+{
+ 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_outbuf, sendsz, 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));
+
+ /* 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);
+}
+
+static enum clnt_stat
+clnt_dg_call(cl, proc, xargs, argsp, xresults, resultsp, utimeout)
+ CLIENT *cl; /* client handle */
+ rpcproc_t 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 */
+ struct timeval utimeout; /* seconds to wait before giving up */
+{
+ 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 */
+ 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 inlen, 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:
+ xdrs = &(cu->cu_outxdrs);
+ if (cu->cu_async == TRUE && xargs == NULL)
+ goto get_reply;
+ xdrs->x_op = XDR_ENCODE;
+ XDR_SETPOS(xdrs, cu->cu_xdrpos);
+ /*
+ * 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_outbuf));
+ xid++;
+ *(u_int32_t *)(void *)(cu->cu_outbuf) = htonl(xid);
+
+ if ((! XDR_PUTINT32(xdrs, &proc)) ||
+ (! AUTH_MARSHALL(cl->cl_auth, xdrs)) ||
+ (! (*xargs)(xdrs, 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;
+ reply_msg.acpted_rply.ar_results.where = resultsp;
+ reply_msg.acpted_rply.ar_results.proc = xresults;
+
+ 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);
+ goto send_again;
+ }
+ }
+ inlen = (socklen_t)recvlen;
+
+ /*
+ * 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)) {
+ cu->cu_error.re_status = RPC_AUTHERROR;
+ cu->cu_error.re_why = AUTH_INVALIDRESP;
+ }
+ 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 unsuccesful 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(cl, errp)
+ 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(cl, xdr_res, res_ptr)
+ 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(h)
+ CLIENT *h;
+{
+}
+
+static bool_t
+clnt_dg_control(cl, request, info)
+ 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_outbuf);
+ break;
+
+ case CLSET_XID:
+ /* This will set the xid of the NEXT call */
+ *(u_int32_t *)(void *)cu->cu_outbuf =
+ 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
+ * begining of the RPC header. MUST be changed if the
+ * call_struct is changed
+ */
+ *(u_int32_t *)info =
+ ntohl(*(u_int32_t *)(void *)(cu->cu_outbuf +
+ 4 * BYTES_PER_XDR_UNIT));
+ break;
+
+ case CLSET_VERS:
+ *(u_int32_t *)(void *)(cu->cu_outbuf + 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
+ * begining of the RPC header. MUST be changed if the
+ * call_struct is changed
+ */
+ *(u_int32_t *)info =
+ ntohl(*(u_int32_t *)(void *)(cu->cu_outbuf +
+ 3 * BYTES_PER_XDR_UNIT));
+ break;
+
+ case CLSET_PROG:
+ *(u_int32_t *)(void *)(cu->cu_outbuf + 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(cl)
+ 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()
+{
+ 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(t)
+ 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 0000000..302a30e
--- /dev/null
+++ b/lib/libc/rpc/clnt_generic.c
@@ -0,0 +1,466 @@
+/* $NetBSD: clnt_generic.c,v 1.18 2000/07/06 03:10:34 christos Exp $ */
+
+/*
+ * The contents of this file are subject to the Sun Standards
+ * License Version 1.0 the (the "License";) You may not use
+ * this file except in compliance with the License. You may
+ * obtain a copy of the License at lib/libc/rpc/LICENSE
+ *
+ * Software distributed under the License is distributed on
+ * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either
+ * express or implied. See the License for the specific
+ * language governing rights and limitations under the License.
+ *
+ * The Original Code is Copyright 1998 by Sun Microsystems, Inc
+ *
+ * The Initial Developer of the Original Code is: Sun
+ * Microsystems, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+/* #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 0000000..4b6d6b1
--- /dev/null
+++ b/lib/libc/rpc/clnt_perror.c
@@ -0,0 +1,326 @@
+/* $NetBSD: clnt_perror.c,v 1.24 2000/06/02 23:11:07 fvdl Exp $ */
+
+
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#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()
+{
+
+ if (buf == 0)
+ buf = (char *)malloc(CLNT_PERROR_BUFLEN);
+ return (buf);
+}
+
+/*
+ * Print reply error info
+ */
+char *
+clnt_sperror(rpch, s)
+ 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 == 0)
+ 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(rpch, s)
+ 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(stat)
+ 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(num)
+ enum clnt_stat num;
+{
+ (void) fprintf(stderr, "%s\n", clnt_sperrno(num));
+}
+
+
+char *
+clnt_spcreateerror(s)
+ const char *s;
+{
+ char *str;
+ size_t len, i;
+
+ assert(s != NULL);
+
+ str = _buf(); /* side effect: sets CLNT_PERROR_BUFLEN */
+ if (str == 0)
+ 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(s)
+ 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 */
+};
+
+static char *
+auth_errmsg(stat)
+ 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 0000000..9d34a3d
--- /dev/null
+++ b/lib/libc/rpc/clnt_raw.c
@@ -0,0 +1,312 @@
+/* $NetBSD: clnt_raw.c,v 1.20 2000/12/10 04:12:03 christos Exp $ */
+
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#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(prog, vers)
+ rpcprog_t prog;
+ rpcvers_t vers;
+{
+ struct clntraw_private *clp = clntraw_private;
+ struct rpc_msg call_msg;
+ XDR *xdrs = &clp->xdr_stream;
+ CLIENT *client = &clp->client_object;
+
+ mutex_lock(&clntraw_lock);
+ if (clp == 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;
+ }
+ /*
+ * 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(h, proc, xargs, argsp, xresults, resultsp, timeout)
+ 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(cl, err)
+ CLIENT *cl;
+ struct rpc_err *err;
+{
+}
+
+
+/* ARGSUSED */
+static bool_t
+clnt_raw_freeres(cl, xdr_res, res_ptr)
+ 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(cl)
+ CLIENT *cl;
+{
+}
+
+/*ARGSUSED*/
+static bool_t
+clnt_raw_control(cl, ui, str)
+ CLIENT *cl;
+ u_int ui;
+ void *str;
+{
+ return (FALSE);
+}
+
+/*ARGSUSED*/
+static void
+clnt_raw_destroy(cl)
+ CLIENT *cl;
+{
+}
+
+static struct clnt_ops *
+clnt_raw_ops()
+{
+ 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 0000000..12b6679
--- /dev/null
+++ b/lib/libc/rpc/clnt_simple.c
@@ -0,0 +1,196 @@
+/* $NetBSD: clnt_simple.c,v 1.21 2000/07/06 03:10:34 christos Exp $ */
+
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+/*
+ * 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 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);
+ }
+}
+
+/*
+ * 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.
+ */
+enum clnt_stat
+rpc_call(host, prognum, versnum, procnum, inproc, in, outproc, out, nettype)
+ const char *host; /* host name */
+ rpcprog_t prognum; /* program number */
+ rpcvers_t versnum; /* version number */
+ rpcproc_t procnum; /* procedure number */
+ xdrproc_t inproc, outproc; /* in/out XDR procedures */
+ const char *in;
+ char *out; /* recv/send data */
+ const char *nettype; /* nettype */
+{
+ struct rpc_call_private *rcp = (struct rpc_call_private *) 0;
+ enum clnt_stat clnt_stat;
+ struct timeval timeout, tottimeout;
+ static thread_key_t rpc_call_key;
+ int main_thread = 1;
+
+ if ((main_thread = thr_main())) {
+ rcp = rpc_call_private_main;
+ } else {
+ if (rpc_call_key == 0) {
+ mutex_lock(&tsd_lock);
+ if (rpc_call_key == 0)
+ thr_keycreate(&rpc_call_key, rpc_call_destroy);
+ mutex_unlock(&tsd_lock);
+ }
+ 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 0000000..e15caac
--- /dev/null
+++ b/lib/libc/rpc/clnt_vc.c
@@ -0,0 +1,846 @@
+/* $NetBSD: clnt_vc.c,v 1.4 2000/07/14 08:40:42 fvdl Exp $ */
+
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#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 "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 clnt_read_vc_str[] = "read_vc";
+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
+ */
+CLIENT *
+clnt_vc_create(fd, raddr, prog, vers, sendsz, recvsz)
+ int fd; /* open file descriptor */
+ const struct netbuf *raddr; /* servers address */
+ const rpcprog_t prog; /* program number */
+ const rpcvers_t vers; /* version number */
+ u_int sendsz; /* buffer recv size */
+ u_int recvsz; /* buffer send size */
+{
+ 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);
+ if (!__rpc_fd2sockinfo(fd, &si))
+ goto err;
+ thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
+
+ 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->maxlen;
+ 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));
+
+ /*
+ * 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 (cl) {
+ 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(cl, proc, xdr_args, args_ptr, xdr_results, results_ptr, timeout)
+ 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;
+
+ 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 ((! 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);
+ }
+ 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 (! (*xdr_results)(xdrs, results_ptr)) {
+ 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(cl, errp)
+ 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(cl, xdr_res, res_ptr)
+ 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(cl)
+ CLIENT *cl;
+{
+}
+
+static bool_t
+clnt_vc_control(cl, request, info)
+ 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
+ */
+ *(u_int32_t *)info =
+ ntohl(*(u_int32_t *)(void *)&ct->ct_u.ct_mcalli);
+ break;
+ case CLSET_XID:
+ /* This will set the xid of the NEXT call */
+ *(u_int32_t *)(void *)&ct->ct_u.ct_mcalli =
+ htonl(*((u_int32_t *)info) + 1);
+ /* increment by 1 as clnt_vc_call() decrements 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
+ * begining of the RPC header. MUST be changed if the
+ * call_struct is changed
+ */
+ *(u_int32_t *)info =
+ ntohl(*(u_int32_t *)(void *)(ct->ct_u.ct_mcallc +
+ 4 * BYTES_PER_XDR_UNIT));
+ break;
+
+ case CLSET_VERS:
+ *(u_int32_t *)(void *)(ct->ct_u.ct_mcallc +
+ 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
+ * begining of the RPC header. MUST be changed if the
+ * call_struct is changed
+ */
+ *(u_int32_t *)info =
+ ntohl(*(u_int32_t *)(void *)(ct->ct_u.ct_mcallc +
+ 3 * BYTES_PER_XDR_UNIT));
+ break;
+
+ case CLSET_PROG:
+ *(u_int32_t *)(void *)(ct->ct_u.ct_mcallc +
+ 3 * BYTES_PER_XDR_UNIT) =
+ htonl(*(u_int32_t *)info);
+ 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(cl)
+ 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));
+ if (ct->ct_addr.buf)
+ free(ct->ct_addr.buf);
+ mem_free(ct, sizeof(struct ct_data));
+ 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(ctp, buf, len)
+ 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(ctp, buf, len)
+ 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()
+{
+ 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(t)
+ struct timeval *t;
+{
+ return (t->tv_sec <= -1 || t->tv_sec > 100000000 ||
+ t->tv_usec <= -1 || t->tv_usec > 1000000);
+}
+
+static int
+__msgread(sock, buf, cnt)
+ 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(sock, buf, cnt)
+ 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 0000000..255b266
--- /dev/null
+++ b/lib/libc/rpc/crypt_client.c
@@ -0,0 +1,101 @@
+/*
+ * 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(buf, len, dparms)
+ 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());
+ 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;
+ des_crypt_1_arg.des_mode = dparms->des_mode;
+ 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 0000000..b40a62c
--- /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 0000000..238d55a
--- /dev/null
+++ b/lib/libc/rpc/des_crypt.c
@@ -0,0 +1,154 @@
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+/*
+ * 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)() = 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(key, buf, len, mode, ivec)
+ 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(key, buf, len, mode)
+ 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(key, buf, len, mode, desp)
+ 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 0000000..daed265
--- /dev/null
+++ b/lib/libc/rpc/des_soft.c
@@ -0,0 +1,71 @@
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#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(p)
+ 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 0000000..e67b9bb
--- /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 0000000..0159e4b
--- /dev/null
+++ b/lib/libc/rpc/getnetconfig.c
@@ -0,0 +1,702 @@
+/* $NetBSD: getnetconfig.c,v 1.3 2000/07/06 03:10:34 christos Exp $ */
+
+/*
+ * Sun RPC 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 Sun RPC 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 or with the express written consent of
+ * Sun Microsystems, Inc.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#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 <sys/cdefs.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 struct netconfig_info ni = { 0, 0, NULL, NULL};
+
+#define MAXNETCONFIGLINE 1000
+
+static int *
+__nc_error()
+{
+ static pthread_mutex_t nc_lock = PTHREAD_MUTEX_INITIALIZER;
+ static thread_key_t nc_key = 0;
+ static int nc_error = 0;
+ int error, *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 (nc_key == 0) {
+ error = 0;
+ mutex_lock(&nc_lock);
+ if (nc_key == 0)
+ error = thr_keycreate(&nc_key, free);
+ mutex_unlock(&nc_lock);
+ if (error)
+ 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) {
+ if (nc_addr)
+ 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()
+{
+ 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.
+ */
+ ni.ref++;
+ 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;
+ return ((void *)nc_vars);
+ }
+ ni.ref--;
+ 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(handlep)
+void *handlep;
+{
+ struct netconfig_vars *ncp = (struct netconfig_vars *)handlep;
+ char *stringp; /* tmp string pointer */
+ struct netconfig_list *list;
+ struct netconfig *np;
+
+ /*
+ * Verify that handle is valid
+ */
+ if (ncp == NULL || nc_file == NULL) {
+ nc_error = NC_NOTINIT;
+ return (NULL);
+ }
+
+ 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;
+ ncp->nc_configs = ni.head;
+ 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.
+ */
+ if (ni.eof == 1) return(NULL);
+ 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.
+ */
+ do {
+ if (fgets(stringp, MAXNETCONFIGLINE, nc_file) == NULL) {
+ free(stringp);
+ ni.eof = 1;
+ return (NULL);
+ }
+ } while (*stringp == '#');
+
+ 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.
+ */
+ 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;
+ return(ni.tail->ncp);
+ }
+}
+
+/*
+ * 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(handlep)
+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;
+ if (--ni.ref > 0) {
+ free(nc_handlep);
+ return(0);
+ }
+
+ /*
+ * Noone needs these entries anymore, then frees them.
+ * Make sure all info in netconfig_info structure has been reinitialized.
+ */
+ q = p = ni.head;
+ ni.eof = ni.ref = 0;
+ ni.head = NULL;
+ ni.tail = NULL;
+ while (q) {
+ p = q->next;
+ if (q->ncp->nc_lookups != NULL) free(q->ncp->nc_lookups);
+ free(q->ncp);
+ free(q->linep);
+ free(q);
+ q = p;
+ }
+ free(nc_handlep);
+
+ fclose(nc_file);
+ nc_file = NULL;
+ 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(netid)
+ 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);
+ }
+
+ if (strcmp(netid, "unix") == 0) {
+ fprintf(stderr, "The local transport is called \"unix\" ");
+ fprintf(stderr, "in /etc/netconfig.\n");
+ fprintf(stderr, "Please change this to \"local\" manually ");
+ fprintf(stderr, "or run mergemaster(8).\n");
+ fprintf(stderr, "See UPDATING entry 20021216 for details.\n");
+ fprintf(stderr, "Continuing in 10 seconds\n\n");
+ fprintf(stderr, "This warning will be removed 20030301\n");
+ sleep(10);
+
+ }
+
+ /*
+ * 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.
+ */
+ if (ni.head != NULL) {
+ for (list = ni.head; list; list = list->next) {
+ if (strcmp(list->ncp->nc_netid, netid) == 0) {
+ return(dup_ncp(list->ncp));
+ }
+ }
+ if (ni.eof == 1) /* that's all the entries */
+ return(NULL);
+ }
+
+
+ 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(netconfigp)
+ struct netconfig *netconfigp;
+{
+ if (netconfigp != NULL) {
+ free(netconfigp->nc_netid); /* holds all netconfigp's strings */
+ if (netconfigp->nc_lookups != NULL)
+ 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.
+ */
+
+static int
+parse_ncp(stringp, ncp)
+char *stringp; /* string to parse */
+struct netconfig *ncp; /* where to put results */
+{
+ char *tokenp; /* for processing tokens */
+ char *lasts;
+
+ 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 */
+
+ if (ncp->nc_lookups != NULL) /* from last visit */
+ free(ncp->nc_lookups);
+ /* preallocate one string pointer */
+ ncp->nc_lookups = (char **)malloc(sizeof (char *));
+ ncp->nc_nlookups = 0;
+ while ((cp = tokenp) != NULL) {
+ tokenp = _get_next_token(cp, ',');
+ ncp->nc_lookups[(size_t)ncp->nc_nlookups++] = cp;
+ ncp->nc_lookups = (char **)realloc(ncp->nc_lookups,
+ (size_t)(ncp->nc_nlookups+1) *sizeof(char *)); /* for next loop */
+ }
+ }
+ return (0);
+}
+
+
+/*
+ * Returns a string describing the reason for failure.
+ */
+char *
+nc_sperror()
+{
+ 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(s)
+ const char *s;
+{
+ fprintf(stderr, "%s: %s\n", s, nc_sperror());
+}
+
+/*
+ * Duplicates the matched netconfig buffer.
+ */
+static struct netconfig *
+dup_ncp(ncp)
+struct netconfig *ncp;
+{
+ struct netconfig *p;
+ char *tmp;
+ u_int i;
+
+ if ((tmp=malloc(MAXNETCONFIGLINE)) == NULL)
+ return(NULL);
+ if ((p=(struct netconfig *)malloc(sizeof(struct netconfig))) == NULL) {
+ free(tmp);
+ return(NULL);
+ }
+ /*
+ * 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);
+ 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 0000000..5dfe68a
--- /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 0000000..db4dfc5
--- /dev/null
+++ b/lib/libc/rpc/getnetpath.c
@@ -0,0 +1,273 @@
+/* $NetBSD: getnetpath.c,v 1.3 2000/07/06 03:10:34 christos Exp $ */
+
+/*
+ * Sun RPC 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 Sun RPC 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 or with the express written consent of
+ * Sun Microsystems, Inc.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#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 <sys/cdefs.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()
+{
+
+ 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);
+ return (NULL);
+ }
+ 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) {
+ free(np_sessionp);
+ return (NULL);
+ } else {
+ (void) strcpy(np_sessionp->netpath, npp);
+ }
+ }
+ np_sessionp->netpath_start = np_sessionp->netpath;
+ return ((void *)np_sessionp);
+}
+
+/*
+ * 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(handlep)
+ 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(handlep)
+ 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.
+ */
+
+char *
+_get_next_token(npp, token)
+char *npp; /* string */
+int token; /* char to parse string for */
+{
+ 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, '\\')) != 0) {
+ 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 0000000..3c95338
--- /dev/null
+++ b/lib/libc/rpc/getpublickey.c
@@ -0,0 +1,179 @@
+/*
+ * Sun RPC 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 Sun RPC 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 or with the express written consent of
+ * Sun Microsystems, Inc.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#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)() = 0;
+
+/*
+ * Get somebody's public key
+ */
+static int
+__getpublickey_real(netname, publickey)
+ 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(key, ret)
+ 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(netname, publickey)
+ 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 0000000..1a999eb
--- /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 December 14, 1987
+.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 "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 0000000..2822c76
--- /dev/null
+++ b/lib/libc/rpc/getrpcent.c
@@ -0,0 +1,1048 @@
+/* $NetBSD: getrpcent.c,v 1.17 2000/01/22 22:19:17 mycroft Exp $ */
+
+/*
+ * Sun RPC 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 Sun RPC 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 or with the express written consent of
+ * Sun Microsystems, Inc.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#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/types.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;
+ break;
+ }
+
+ aliases=(char **)_ALIGN(&buffer[resultbuflen+2]);
+ aliases_size = (buffer + bufsize - (char *)aliases) /
+ sizeof(char *);
+ if (aliases_size < 1) {
+ *errnop = ERANGE;
+ rv = NS_RETURN;
+ 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);
+ }
+
+ memcpy(&new_rpc, rpc, sizeof(struct rpcent));
+
+ *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(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()
+{
+ 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()
+{
+#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_SERVICES, "endrpcent", defaultsrc);
+}
diff --git a/lib/libc/rpc/getrpcport.3 b/lib/libc/rpc/getrpcport.3
new file mode 100644
index 0000000..6e1f199
--- /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 0000000..676a1f5
--- /dev/null
+++ b/lib/libc/rpc/getrpcport.c
@@ -0,0 +1,78 @@
+/* $NetBSD: getrpcport.c,v 1.16 2000/01/22 22:19:18 mycroft Exp $ */
+
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#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(host, prognum, versnum, proto)
+ char *host;
+ int prognum, versnum, 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 0000000..615f24d
--- /dev/null
+++ b/lib/libc/rpc/key_call.c
@@ -0,0 +1,474 @@
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+/*
+ * 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)() = 0;
+cryptkeyres *(*__key_decryptsession_pk_LOCAL)() = 0;
+des_block *(*__key_gendes_LOCAL)() = 0;
+
+static int key_call( u_long, xdrproc_t, void *, xdrproc_t, void *);
+
+int
+key_setsecret(secretkey)
+ 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(remotename, remotekey, deskey)
+ 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(remotename, remotekey, deskey)
+ 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(remotename, deskey)
+ 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(remotename, deskey)
+ 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(key)
+ 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(arg)
+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(pkey, deskey)
+ 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 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);
+ }
+}
+
+/*
+ * Keep the handle cached. This call may be made quite often.
+ */
+static CLIENT *
+getkeyserv_handle(vers)
+int vers;
+{
+ void *localhandle;
+ struct netconfig *nconf;
+ struct netconfig *tpconf;
+ struct key_call_private *kcp = key_call_private_main;
+ struct timeval wait_time;
+ struct utsname u;
+ int main_thread;
+ int fd;
+ static thread_key_t key_call_key;
+
+#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 (key_call_key == 0) {
+ mutex_lock(&tsd_lock);
+ if (key_call_key == 0)
+ thr_keycreate(&key_call_key, key_call_destroy);
+ mutex_unlock(&tsd_lock);
+ }
+ 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(proc, xdr_arg, arg, xdr_rslt, rslt)
+ 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 0000000..18b1328
--- /dev/null
+++ b/lib/libc/rpc/key_prot_xdr.c
@@ -0,0 +1,176 @@
+/*
+ * Please do not edit this file.
+ * It was generated using rpcgen.
+ */
+
+#include "namespace.h"
+#include <rpc/key_prot.h>
+#include "un-namespace.h"
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+/* 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)
+{
+
+ if (!xdr_u_int(xdrs, &objp->uid))
+ return (FALSE);
+ if (!xdr_u_int(xdrs, &objp->gid))
+ return (FALSE);
+ if (!xdr_array(xdrs, (char **)&objp->gids.gids_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 0000000..6241611
--- /dev/null
+++ b/lib/libc/rpc/mt_misc.c
@@ -0,0 +1,118 @@
+/* $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 tsd_lock __tsd_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;
+
+/* protects TSD key creation */
+pthread_mutex_t tsd_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* xprtlist (svc_generic.c) */
+pthread_mutex_t xprtlist_lock = PTHREAD_MUTEX_INITIALIZER;
+
+#undef rpc_createerr
+
+struct rpc_createerr rpc_createerr;
+
+struct rpc_createerr *
+__rpc_createerr()
+{
+ static thread_key_t rce_key = 0;
+ struct rpc_createerr *rce_addr = 0;
+
+ if (thr_main())
+ return (&rpc_createerr);
+ if ((rce_addr =
+ (struct rpc_createerr *)thr_getspecific(rce_key)) != 0) {
+ mutex_lock(&tsd_lock);
+ if (thr_keycreate(&rce_key, free) != 0) {
+ mutex_unlock(&tsd_lock);
+ return (&rpc_createerr);
+ }
+ mutex_unlock(&tsd_lock);
+ }
+ if (!rce_addr) {
+ rce_addr = (struct rpc_createerr *)
+ malloc(sizeof (struct rpc_createerr));
+ if (thr_setspecific(rce_key, (void *) rce_addr) != 0) {
+ if (rce_addr)
+ 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 0000000..e785c30
--- /dev/null
+++ b/lib/libc/rpc/mt_misc.h
@@ -0,0 +1,66 @@
+/*
+ * 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 tsd_lock __tsd_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 0000000..edd2f63
--- /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 0000000..2f30530
--- /dev/null
+++ b/lib/libc/rpc/netname.c
@@ -0,0 +1,153 @@
+/*
+ * Sun RPC 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 Sun RPC 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 or with the express written consent of
+ * Sun Microsystems, Inc.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#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
+#ifndef NGROUPS
+#define NGROUPS 16
+#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(name)
+ 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(netname, uid, domain)
+ 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(netname, host, domain)
+ 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 0000000..7e567df
--- /dev/null
+++ b/lib/libc/rpc/netnamer.c
@@ -0,0 +1,335 @@
+/*
+ * Sun RPC 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 Sun RPC 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 or with the express written consent of
+ * Sun Microsystems, Inc.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#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 * );
+
+#ifndef NGROUPS
+#define NGROUPS 16
+#endif
+
+/*
+ * Convert network-name into unix credential
+ */
+int
+netname2user(netname, uidp, gidp, gidlenp, gidlist)
+ 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 < NGROUPS; 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(uname, groups)
+ char *uname;
+ gid_t groups[NGROUPS];
+{
+ 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 == NGROUPS) {
+#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(netname, hostname, hostlen)
+ 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(key, ret)
+ char *key, *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
+
+ fd = fopen(NETIDFILE, "r");
+ if (fd == NULL) {
+#ifdef YP
+ res = "+";
+ goto getnetidyp;
+#else
+ return (0);
+#endif
+ }
+ for (;;) {
+ if (fd == NULL)
+ return (0); /* getnetidyp brings us here */
+ res = fgets(buf, sizeof(buf), fd);
+ if (res == NULL) {
+ fclose(fd);
+ return (0);
+ }
+ 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);
+ if (fd != NULL)
+ fclose(fd);
+ return (2);
+#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);
+ fclose(fd);
+ return (1);
+
+ }
+ }
+ }
+}
diff --git a/lib/libc/rpc/pmap_clnt.c b/lib/libc/rpc/pmap_clnt.c
new file mode 100644
index 0000000..a0db013
--- /dev/null
+++ b/lib/libc/rpc/pmap_clnt.c
@@ -0,0 +1,120 @@
+/* $NetBSD: pmap_clnt.c,v 1.16 2000/07/06 03:10:34 christos Exp $ */
+
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#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 0000000..42d3720
--- /dev/null
+++ b/lib/libc/rpc/pmap_getmaps.c
@@ -0,0 +1,100 @@
+/* $NetBSD: pmap_getmaps.c,v 1.16 2000/07/06 03:10:34 christos Exp $ */
+
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#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(address)
+ 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 0000000..ca0aafd
--- /dev/null
+++ b/lib/libc/rpc/pmap_getport.c
@@ -0,0 +1,104 @@
+/* $NetBSD: pmap_getport.c,v 1.16 2000/07/06 03:10:34 christos Exp $ */
+
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#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(address, program, version, protocol)
+ 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 0000000..2c01311
--- /dev/null
+++ b/lib/libc/rpc/pmap_prot.c
@@ -0,0 +1,69 @@
+/* $NetBSD: pmap_prot.c,v 1.10 2000/01/22 22:19:18 mycroft Exp $ */
+
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#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(xdrs, regs)
+ 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 0000000..ae7c7c6
--- /dev/null
+++ b/lib/libc/rpc/pmap_prot2.c
@@ -0,0 +1,143 @@
+/* $NetBSD: pmap_prot2.c,v 1.14 2000/07/06 03:10:34 christos Exp $ */
+
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#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(xdrs, rp)
+ 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(xdrs, rp)
+ 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 0000000..ddcde2e
--- /dev/null
+++ b/lib/libc/rpc/pmap_rmt.c
@@ -0,0 +1,176 @@
+/* $NetBSD: pmap_rmt.c,v 1.29 2000/07/06 03:10:34 christos Exp $ */
+
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#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(addr, prog, vers, proc, xdrargs, argsp, xdrres, resp, tout,
+ port_ptr)
+ struct sockaddr_in *addr;
+ u_long prog, vers, proc;
+ xdrproc_t xdrargs, xdrres;
+ caddr_t argsp, 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(xdrs, cap)
+ 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(xdrs, crp)
+ 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 0000000..d0ad6cc
--- /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 NULL 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 NULL
+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 0000000..71f4ef6
--- /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 0000000..81a24ca
--- /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 u_int32_t rpcprog_t;
+ typedef u_int32_t rpcvers_t;
+ typedef u_int32_t rpcproc_t;
+ typedef u_int32_t rpcprot_t;
+ typedef u_int32_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 rpcbind 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 xdr 3 ,
+.Xr netconfig 5
diff --git a/lib/libc/rpc/rpc.5 b/lib/libc/rpc/rpc.5
new file mode 100644
index 0000000..398d9aa
--- /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 0000000..b9b64f5
--- /dev/null
+++ b/lib/libc/rpc/rpc_callmsg.c
@@ -0,0 +1,205 @@
+/* $NetBSD: rpc_callmsg.c,v 1.16 2000/07/14 08:40:42 fvdl Exp $ */
+
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#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(xdrs, cmsg)
+ XDR *xdrs;
+ struct rpc_msg *cmsg;
+{
+ 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);
+ }
+ }
+ if (
+ xdr_u_int32_t(xdrs, &(cmsg->rm_xid)) &&
+ xdr_enum(xdrs, (enum_t *)&(cmsg->rm_direction)) &&
+ (cmsg->rm_direction == CALL) &&
+ xdr_u_int32_t(xdrs, &(cmsg->rm_call.cb_rpcvers)) &&
+ (cmsg->rm_call.cb_rpcvers == RPC_MSG_VERSION) &&
+ xdr_u_int32_t(xdrs, &(cmsg->rm_call.cb_prog)) &&
+ xdr_u_int32_t(xdrs, &(cmsg->rm_call.cb_vers)) &&
+ xdr_u_int32_t(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 0000000..863707e
--- /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 0000000..213a7d1
--- /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 0000000..3008b15
--- /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 *" "do not close fd on destroy"
+.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 "u_int32_t *" Ta "get RPC program version"
+.It Dv CLSET_VERS Ta "u_int32_t *" Ta "set RPC program version"
+.It Dv CLGET_XID Ta "u_int32_t *" Ta "get XID of previous call"
+.It Dv CLSET_XID Ta "u_int32_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 0000000..f2bf11f
--- /dev/null
+++ b/lib/libc/rpc/rpc_com.h
@@ -0,0 +1,95 @@
+/* $NetBSD: rpc_com.h,v 1.3 2000/12/10 04:10:08 christos Exp $ */
+
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ *
+ * $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 *);
+
+SVCXPRT **__svc_xports;
+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 0000000..679233a
--- /dev/null
+++ b/lib/libc/rpc/rpc_commondata.c
@@ -0,0 +1,48 @@
+/* $NetBSD: rpc_commondata.c,v 1.7 2000/06/02 23:11:13 fvdl Exp $ */
+
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#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 0000000..5e50ba8
--- /dev/null
+++ b/lib/libc/rpc/rpc_dtablesize.c
@@ -0,0 +1,67 @@
+/* $NetBSD: rpc_dtablesize.c,v 1.14 1998/11/15 17:32:43 christos Exp $ */
+
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#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 0000000..a5168c4
--- /dev/null
+++ b/lib/libc/rpc/rpc_generic.c
@@ -0,0 +1,842 @@
+/* $NetBSD: rpc_generic.c,v 1.4 2000/09/28 09:07:04 kleink Exp $ */
+
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+/*
+ * 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/types.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()
+{
+ 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
+ */
+u_int
+/*ARGSUSED*/
+__rpc_get_t_size(af, proto, size)
+ int af, proto;
+ int size; /* Size requested */
+{
+ 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(af)
+ 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(p)
+ 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(nettype)
+ 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);
+}
+
+/*
+ * For the given nettype (tcp or udp only), return the first structure found.
+ * This should be freed by calling freenetconfigent()
+ */
+struct netconfig *
+__rpc_getconfip(nettype)
+ 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;
+ static thread_key_t tcp_key, udp_key;
+
+ if ((main_thread = thr_main())) {
+ netid_udp = netid_udp_main;
+ netid_tcp = netid_tcp_main;
+ } else {
+ if (tcp_key == 0) {
+ mutex_lock(&tsd_lock);
+ if (tcp_key == 0)
+ thr_keycreate(&tcp_key, free);
+ mutex_unlock(&tsd_lock);
+ }
+ netid_tcp = (char *)thr_getspecific(tcp_key);
+ if (udp_key == 0) {
+ mutex_lock(&tsd_lock);
+ if (udp_key == 0)
+ thr_keycreate(&udp_key, free);
+ mutex_unlock(&tsd_lock);
+ }
+ 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 = 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 = 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(nettype)
+ 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())) {
+ free(handle);
+ return (NULL);
+ }
+ 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);
+ free(handle);
+ return (NULL);
+ }
+ handle->nflag = FALSE;
+ break;
+ default:
+ return (NULL);
+ }
+
+ return (handle);
+}
+
+/*
+ * Returns the next netconfig struct for the given "net" type.
+ * __rpc_setconf() should have been called previously.
+ */
+struct netconfig *
+__rpc_getconf(vhandle)
+ 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(vhandle)
+ 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(clnt)
+ 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(fd)
+ 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 0000000..87278e7
--- /dev/null
+++ b/lib/libc/rpc/rpc_prot.c
@@ -0,0 +1,355 @@
+/* $NetBSD: rpc_prot.c,v 1.16 2000/06/02 23:11:13 fvdl Exp $ */
+
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#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(xdrs, ap)
+ 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(xdrs, blkp)
+ 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(xdrs, ar)
+ XDR *xdrs;
+ struct accepted_reply *ar;
+{
+
+ assert(xdrs != NULL);
+ assert(ar != NULL);
+
+ /* personalized union, rather than calling xdr_union */
+ if (! xdr_opaque_auth(xdrs, &(ar->ar_verf)))
+ return (FALSE);
+ if (! xdr_enum(xdrs, (enum_t *)&(ar->ar_stat)))
+ return (FALSE);
+ switch (ar->ar_stat) {
+
+ case SUCCESS:
+ return ((*(ar->ar_results.proc))(xdrs, ar->ar_results.where));
+
+ case PROG_MISMATCH:
+ if (! xdr_u_int32_t(xdrs, &(ar->ar_vers.low)))
+ return (FALSE);
+ return (xdr_u_int32_t(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(xdrs, rr)
+ XDR *xdrs;
+ struct rejected_reply *rr;
+{
+
+ assert(xdrs != NULL);
+ assert(rr != NULL);
+
+ /* personalized union, rather than calling xdr_union */
+ if (! xdr_enum(xdrs, (enum_t *)&(rr->rj_stat)))
+ return (FALSE);
+ switch (rr->rj_stat) {
+
+ case RPC_MISMATCH:
+ if (! xdr_u_int32_t(xdrs, &(rr->rj_vers.low)))
+ return (FALSE);
+ return (xdr_u_int32_t(xdrs, &(rr->rj_vers.high)));
+
+ case AUTH_ERROR:
+ return (xdr_enum(xdrs, (enum_t *)&(rr->rj_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(xdrs, rmsg)
+ XDR *xdrs;
+ struct rpc_msg *rmsg;
+{
+ assert(xdrs != NULL);
+ assert(rmsg != NULL);
+
+ if (
+ xdr_u_int32_t(xdrs, &(rmsg->rm_xid)) &&
+ xdr_enum(xdrs, (enum_t *)&(rmsg->rm_direction)) &&
+ (rmsg->rm_direction == REPLY) )
+ return (xdr_union(xdrs, (enum_t *)&(rmsg->rm_reply.rp_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(xdrs, cmsg)
+ XDR *xdrs;
+ struct rpc_msg *cmsg;
+{
+
+ assert(xdrs != NULL);
+ assert(cmsg != NULL);
+
+ 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 *)&(cmsg->rm_direction)) &&
+ xdr_u_int32_t(xdrs, &(cmsg->rm_call.cb_rpcvers)) &&
+ xdr_u_int32_t(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(acpt_stat, error)
+ 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(rjct_stat, error)
+ 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(msg, error)
+ 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 0000000..07c6314
--- /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 0000000..ebc666b
--- /dev/null
+++ b/lib/libc/rpc/rpc_soc.3
@@ -0,0 +1,1726 @@
+.\" @(#)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.
+.Bl -tag -width indent -compact
+.Pp
+.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" "int uid" "int gid" "int len" "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 Xo
+.Vt "struct timeval" Ta "set total timeout"
+.Xc
+.It Dv CLGET_TIMEOUT Ta Xo
+.Vt "struct timeval" Ta "get total timeout"
+.Xc
+.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 Xo
+.Vt "struct sockaddr_in" Ta "get server's address"
+.Xc
+.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 Xo
+.Vt "struct timeval" Ta "set the retry timeout"
+.Xc
+.It Dv CLGET_RETRY_TIMEOUT Ta Xo
+.Vt "struct timeval" Ta "get the retry timeout"
+.Xc
+.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 0000000..5922063
--- /dev/null
+++ b/lib/libc/rpc/rpc_soc.c
@@ -0,0 +1,579 @@
+/* $NetBSD: rpc_soc.c,v 1.6 2000/07/06 03:10:35 christos Exp $ */
+
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+/* #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(raddr, prog, vers, sockp, sendsz, recvsz, tp)
+ 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(raddr, prog, vers, wait, sockp, sendsz, recvsz)
+ 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(raddr, program, version, wait, sockp)
+ 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(raddr, prog, vers, sockp, sendsz, recvsz)
+ 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(prog, vers)
+ 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(fd, sendsize, recvsize, netid)
+ 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(fd, sendsize, recvsize)
+ int fd;
+ u_int sendsize;
+ u_int recvsize;
+{
+
+ return svc_com_create(fd, sendsize, recvsize, "tcp");
+}
+
+SVCXPRT *
+svcudp_bufcreate(fd, sendsz, recvsz)
+ int fd;
+ u_int sendsz, recvsz;
+{
+
+ return svc_com_create(fd, sendsz, recvsz, "udp");
+}
+
+SVCXPRT *
+svcfd_create(fd, sendsize, recvsize)
+ int fd;
+ u_int sendsize;
+ u_int recvsize;
+{
+
+ return svc_fd_create(fd, sendsize, recvsize);
+}
+
+
+SVCXPRT *
+svcudp_create(fd)
+ int fd;
+{
+
+ return svc_com_create(fd, UDPMSGSIZE, UDPMSGSIZE, "udp");
+}
+
+SVCXPRT *
+svcraw_create()
+{
+
+ return svc_raw_create();
+}
+
+int
+get_myaddress(addr)
+ 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(host, prognum, versnum, procnum, inproc, in, outproc, out)
+ const char *host;
+ int prognum, versnum, procnum;
+ xdrproc_t inproc, outproc;
+ void *in, *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(prognum, versnum, procnum, progname, inproc, outproc)
+ int prognum, versnum, procnum;
+ char *(*progname)(char [UDPMSGSIZE]);
+ xdrproc_t inproc, 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;
+
+/*
+ * Need to translate the netbuf address into sockaddr_in address.
+ * Dont care about netid here.
+ */
+/* ARGSUSED */
+static bool_t
+rpc_wrap_bcast(resultp, addr, 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(prog, vers, proc, xargs, argsp, xresults, resultsp, 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 {
+ if (clnt_broadcast_key == 0) {
+ mutex_lock(&tsd_lock);
+ if (clnt_broadcast_key == 0)
+ thr_keycreate(&clnt_broadcast_key, free);
+ mutex_unlock(&tsd_lock);
+ }
+ 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(servername, window, syncaddr, 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(raddr, prog, vers, sockp, sendsz, recvsz)
+ struct sockaddr_un *raddr;
+ u_long prog;
+ u_long vers;
+ int *sockp;
+ u_int sendsz;
+ u_int recvsz;
+{
+ struct netbuf *svcaddr;
+ struct netconfig *nconf;
+ CLIENT *cl;
+ int len;
+
+ cl = NULL;
+ nconf = NULL;
+ svcaddr = NULL;
+ if ((raddr->sun_len == 0) ||
+ ((svcaddr = malloc(sizeof(struct netbuf))) == NULL ) ||
+ ((svcaddr->buf = malloc(sizeof(struct sockaddr_un))) == NULL)) {
+ if (svcaddr != 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(sock, sendsize, recvsize, path)
+ 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)
+ return(xprt);
+
+ 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(fd, sendsize, recvsize)
+ 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 0000000..8732962
--- /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 0000000..4016a6c
--- /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 0000000..7a6b1f1
--- /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 0000000..aed2ba1
--- /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 rpcbind 3 ,
+.Xr rpc_svc_calls 3 ,
+.Xr rpc_svc_create 3 ,
+.Xr rpc_svc_err 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 0000000..62754fe
--- /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 0000000..ac34c34
--- /dev/null
+++ b/lib/libc/rpc/rpcb_clnt.c
@@ -0,0 +1,1353 @@
+/* $NetBSD: rpcb_clnt.c,v 1.6 2000/07/16 06:41:43 itojun Exp $ */
+
+/*
+ * The contents of this file are subject to the Sun Standards
+ * License Version 1.0 the (the "License";) You may not use
+ * this file except in compliance with the License. You may
+ * obtain a copy of the License at lib/libc/rpc/LICENSE
+ *
+ * Software distributed under the License is distributed on
+ * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either
+ * express or implied. See the License for the specific
+ * language governing rights and limitations under the License.
+ *
+ * The Original Code is Copyright 1998 by Sun Microsystems, Inc
+ *
+ * The Initial Developer of the Original Code is: Sun
+ * Microsystems, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+/*
+ * Copyright (c) 1986-1991 by Sun Microsystems Inc.
+ */
+
+/* #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.
+ *
+ * Copyright (C) 1988, Sun Microsystems, Inc.
+ */
+
+#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(request, info)
+ 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(host, netid)
+ const char *host, *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(addr)
+ 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);
+ if (cptr->ac_uaddr)
+ 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(host, netid, taddr, uaddr)
+ const char *host, *netid;
+ char *uaddr;
+ struct netbuf *taddr;
+{
+ 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)) {
+ return;
+ }
+ 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) {
+ 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);
+ if (cptr->ac_uaddr)
+ 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(host, nconf, targaddr)
+ 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;
+
+ *targaddr = malloc(sizeof(sun.sun_path));
+ 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()
+{
+ 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;
+ }
+ }
+ if (tmpnconf == NULL) {
+ rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
+ mutex_unlock(&loopnconf_lock);
+ return (NULL);
+ }
+ loopnconf = getnetconfigent(tmpnconf->nc_netid);
+ /* loopnconf is never freed */
+ endnetconfig(nc_handle);
+ }
+ 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.
+ */
+bool_t
+rpcb_set(program, version, nconf, address)
+ rpcprog_t program;
+ rpcvers_t version;
+ const struct netconfig *nconf; /* Network structure of transport */
+ const struct netbuf *address; /* Services netconfig 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(program, version, nconf)
+ 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(relp, nconf)
+ 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()
+{
+ 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;
+ }
+ if (nconf == NULL)
+ return (FALSE);
+
+ endnetconfig(localhandle);
+
+ 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(program, version, nconf, host, clpp, tp)
+ 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);
+ if (address) {
+ 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;
+ }
+ }
+
+ if ((address == NULL) || (address->len == 0)) {
+ rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
+ clnt_geterr(client, &rpc_createerr.cf_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
+ */
+int
+rpcb_getaddr(program, version, nconf, address, host)
+ 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(nconf, host)
+ 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.
+*/
+enum clnt_stat
+rpcb_rmtcall(nconf, host, prog, vers, proc, xdrargs, argsp,
+ xdrres, resp, tout, addr_ptr)
+ const struct netconfig *nconf; /* Netconfig structure */
+ const char *host; /* Remote host name */
+ rpcprog_t prog;
+ rpcvers_t vers;
+ rpcproc_t proc; /* Remote proc identifiers */
+ xdrproc_t xdrargs, xdrres; /* XDR routines */
+ caddr_t argsp, resp; /* Argument and Result */
+ struct timeval tout; /* Timeout value for this call */
+ const struct netbuf *addr_ptr; /* Preallocated netbuf address */
+{
+ 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(host, timep)
+ 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(nconf, taddr)
+ 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(nconf, uaddr)
+ 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 0000000..17dc375
--- /dev/null
+++ b/lib/libc/rpc/rpcb_prot.c
@@ -0,0 +1,330 @@
+/* $NetBSD: rpcb_prot.c,v 1.3 2000/07/14 08:40:42 fvdl Exp $ */
+
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+/*
+ * 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(xdrs, objp)
+ XDR *xdrs;
+ RPCB *objp;
+{
+ if (!xdr_u_int32_t(xdrs, &objp->r_prog)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int32_t(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(xdrs, rp)
+ 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)
+ 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 {
+ 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(xdrs, rp)
+ XDR *xdrs;
+ RPCBLIST **rp;
+{
+ bool_t dummy;
+
+ dummy = xdr_rpcblist_ptr(xdrs, (rpcblist_ptr *)rp);
+ return (dummy);
+}
+
+
+bool_t
+xdr_rpcb_entry(xdrs, objp)
+ 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(xdrs, rp)
+ 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)
+ 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 {
+ rp = &((*rp)->rpcb_entry_next);
+ }
+ }
+ /*NOTREACHED*/
+}
+
+/*
+ * XDR remote call arguments
+ * written for XDR_ENCODE direction only
+ */
+bool_t
+xdr_rpcb_rmtcallargs(xdrs, p)
+ 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_u_int32_t(xdrs, &objp->prog)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int32_t(xdrs, &objp->vers)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int32_t(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(xdrs, p)
+ 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(xdrs, objp)
+ XDR *xdrs;
+ struct netbuf *objp;
+{
+ bool_t dummy;
+
+ if (!xdr_u_int32_t(xdrs, (u_int32_t *) &objp->maxlen)) {
+ return (FALSE);
+ }
+ dummy = xdr_bytes(xdrs, (char **)&(objp->buf),
+ (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 0000000..7ca2ba9
--- /dev/null
+++ b/lib/libc/rpc/rpcb_st_xdr.c
@@ -0,0 +1,270 @@
+/* $NetBSD: rpcb_st_xdr.c,v 1.3 2000/07/14 08:40:42 fvdl Exp $ */
+
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+/*
+ * 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(xdrs, objp)
+ XDR *xdrs;
+ rpcbs_addrlist *objp;
+{
+
+ if (!xdr_u_int32_t(xdrs, &objp->prog)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int32_t(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);
+ }
+
+ if (!xdr_pointer(xdrs, (char **)&objp->next,
+ 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(xdrs, objp)
+ XDR *xdrs;
+ rpcbs_rmtcalllist *objp;
+{
+ int32_t *buf;
+
+ if (xdrs->x_op == XDR_ENCODE) {
+ buf = XDR_INLINE(xdrs, 6 * BYTES_PER_XDR_UNIT);
+ if (buf == NULL) {
+ if (!xdr_u_int32_t(xdrs, &objp->prog)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int32_t(xdrs, &objp->vers)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int32_t(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);
+ }
+ if (!xdr_pointer(xdrs, (char **)&objp->next,
+ 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_u_int32_t(xdrs, &objp->prog)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int32_t(xdrs, &objp->vers)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int32_t(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 **)&objp->next,
+ sizeof (rpcbs_rmtcalllist),
+ (xdrproc_t)xdr_rpcbs_rmtcalllist)) {
+ return (FALSE);
+ }
+ return (TRUE);
+ }
+ if (!xdr_u_int32_t(xdrs, &objp->prog)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int32_t(xdrs, &objp->vers)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int32_t(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 **)&objp->next,
+ sizeof (rpcbs_rmtcalllist),
+ (xdrproc_t)xdr_rpcbs_rmtcalllist)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_rpcbs_proc(xdrs, objp)
+ 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(xdrs, objp)
+ 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(xdrs, objp)
+ 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(xdrs, objp)
+ 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(xdrs, objp)
+ 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 0000000..0b716ca
--- /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 0000000..d4455f4
--- /dev/null
+++ b/lib/libc/rpc/rpcdname.c
@@ -0,0 +1,82 @@
+/*
+ * Sun RPC 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 Sun RPC 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 or with the express written consent of
+ * Sun Microsystems, Inc.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#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 = 0;
+
+static char *
+get_default_domain()
+{
+ char temp[256];
+
+ if (default_domain)
+ return (default_domain);
+ if (getdomainname(temp, sizeof(temp)) < 0)
+ return (0);
+ if ((int) strlen(temp) > 0) {
+ default_domain = (char *)malloc((strlen(temp)+(unsigned)1));
+ if (default_domain == 0)
+ 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(domain)
+ char **domain;
+{
+ if ((*domain = get_default_domain()) != 0)
+ return (0);
+ return (-1);
+}
diff --git a/lib/libc/rpc/rtime.3 b/lib/libc/rpc/rtime.3
new file mode 100644
index 0000000..028d2be
--- /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 0000000..39ac19b
--- /dev/null
+++ b/lib/libc/rpc/rtime.c
@@ -0,0 +1,160 @@
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+/*
+ * 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(addrp, timep, timeout)
+ 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(s)
+ 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 0000000..b924bde
--- /dev/null
+++ b/lib/libc/rpc/svc.c
@@ -0,0 +1,750 @@
+/* $NetBSD: svc.c,v 1.21 2000/07/06 03:10:35 christos Exp $ */
+
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#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) ((u_long)(xp)->xp_p3 & 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
+ * apropriate 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;
+
+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(xprt)
+ 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)
+ 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(xprt, dolock)
+ 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(xprt, prog, vers, dispatch, nconf)
+ 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) {
+ if (netid)
+ 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) {
+ if (netid)
+ 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(prog, vers)
+ 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(xprt, prog, vers, dispatch, protocol)
+ 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(prog, vers)
+ 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(prog, vers, prev, netid)
+ 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(xprt, xdr_results, xdr_location)
+ 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(xprt)
+ 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(xprt)
+ 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(xprt)
+ 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(xprt)
+ SVCXPRT *xprt;
+{
+ u_long tmp;
+
+ tmp = ((u_long) xprt->xp_p3) | SVC_VERSQUIET;
+ xprt->xp_p3 = tmp;
+}
+
+void
+__svc_versquiet_off(xprt)
+ SVCXPRT *xprt;
+{
+ u_long tmp;
+
+ tmp = ((u_long) xprt->xp_p3) & ~SVC_VERSQUIET;
+ xprt->xp_p3 = tmp;
+}
+
+void
+svc_versquiet(xprt)
+ SVCXPRT *xprt;
+{
+ __svc_versquiet_on(xprt);
+}
+
+int
+__svc_versquiet_get(xprt)
+ SVCXPRT *xprt;
+{
+ return ((int) xprt->xp_p3) & SVC_VERSQUIET;
+}
+#endif
+
+/*
+ * Authentication error reply
+ */
+void
+svcerr_auth(xprt, why)
+ 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(xprt)
+ SVCXPRT *xprt;
+{
+
+ assert(xprt != NULL);
+
+ svcerr_auth(xprt, AUTH_TOOWEAK);
+}
+
+/*
+ * Program unavailable error reply
+ */
+void
+svcerr_noprog(xprt)
+ 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(xprt, low_vers, high_vers)
+ 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);
+}
+
+/* ******************* 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(rdfds)
+ int rdfds;
+{
+ fd_set readfds;
+
+ FD_ZERO(&readfds);
+ readfds.fds_bits[0] = rdfds;
+ svc_getreqset(&readfds);
+}
+
+void
+svc_getreqset(readfds)
+ 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 = ffs(mask)) != 0;
+ mask ^= (1 << (bit - 1))) {
+ /* sock has input waiting */
+ fd = sock + bit - 1;
+ svc_getreq_common(fd);
+ }
+ }
+}
+
+void
+svc_getreq_common(fd)
+ 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) {
+ 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(pfdp, pollretval)
+ 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 0000000..eb1a5f2
--- /dev/null
+++ b/lib/libc/rpc/svc_auth.c
@@ -0,0 +1,210 @@
+/* $NetBSD: svc_auth.c,v 1.12 2000/07/06 03:10:35 christos Exp $ */
+
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+/*
+ * 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;
+
+/*
+ * 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(rqst, msg)
+ 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;
+ 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);
+}
+
+/*ARGSUSED*/
+enum auth_stat
+_svcauth_null(rqst, msg)
+ 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(cred_flavor, handler)
+ 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 0000000..84f1e19
--- /dev/null
+++ b/lib/libc/rpc/svc_auth_des.c
@@ -0,0 +1,538 @@
+
+/*
+ * Copyright (c) 1988 by Sun Microsystems, Inc.
+ */
+
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+/*
+ * 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(); /* initialize the cache */
+static short cache_spot(); /* find an entry in the cache */
+static void cache_ref(/*short sid*/); /* note that sid was ref'd */
+
+static void invalidate(); /* 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(rqst, msg)
+ 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, (struct timezone *)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()
+{
+ 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()
+{
+ return (authdes_lru[AUTHDES_CACHESZ-1]);
+}
+
+/*
+ * Note that sid was referenced
+ */
+static void
+cache_ref(sid)
+ 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(key, name, timestamp)
+ 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 {
+ short uid; /* cached uid */
+ short gid; /* cached gid */
+ short grouplen; /* length of cached groups */
+ short groups[NGROUPS]; /* 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(adc, uid, gid, grouplen, groups)
+ 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(cred)
+ 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 0000000..4d6f102
--- /dev/null
+++ b/lib/libc/rpc/svc_auth_unix.c
@@ -0,0 +1,156 @@
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#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(rqst, msg)
+ 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];
+ 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(rqst, msg)
+ 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 0000000..1c602bc
--- /dev/null
+++ b/lib/libc/rpc/svc_dg.c
@@ -0,0 +1,603 @@
+/* $NetBSD: svc_dg.c,v 1.4 2000/07/06 03:10:35 christos Exp $ */
+
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+/*
+ * 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 <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 __no_mem_str[] = "out of memory";
+
+SVCXPRT *
+svc_dg_create(fd, sendsize, recvsize)
+ 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 = mem_alloc(sizeof (SVCXPRT));
+ if (xprt == NULL)
+ goto freedata;
+ memset(xprt, 0, sizeof (SVCXPRT));
+
+ 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)
+ goto freedata;
+ 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);
+
+ xprt_register(xprt);
+ return (xprt);
+freedata:
+ (void) warnx(svc_dg_str, __no_mem_str);
+ if (xprt) {
+ if (su)
+ (void) mem_free(su, sizeof (*su));
+ (void) mem_free(xprt, sizeof (SVCXPRT));
+ }
+ return (NULL);
+}
+
+/*ARGSUSED*/
+static enum xprt_stat
+svc_dg_stat(xprt)
+ SVCXPRT *xprt;
+{
+ return (XPRT_IDLE);
+}
+
+static bool_t
+svc_dg_recv(xprt, msg)
+ 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 = _recvfrom(xprt->xp_fd, rpc_buffer(xprt), su->su_iosz, 0,
+ (struct sockaddr *)(void *)&ss, &alen);
+ 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 bool_t
+svc_dg_reply(xprt, msg)
+ SVCXPRT *xprt;
+ struct rpc_msg *msg;
+{
+ struct svc_dg_data *su = su_data(xprt);
+ XDR *xdrs = &(su->su_xdrs);
+ bool_t stat = FALSE;
+ size_t slen;
+
+ xdrs->x_op = XDR_ENCODE;
+ XDR_SETPOS(xdrs, 0);
+ msg->rm_xid = su->su_xid;
+ if (xdr_replymsg(xdrs, msg)) {
+ slen = XDR_GETPOS(xdrs);
+ if (_sendto(xprt->xp_fd, rpc_buffer(xprt), slen, 0,
+ (struct sockaddr *)xprt->xp_rtaddr.buf,
+ (socklen_t)xprt->xp_rtaddr.len) == (ssize_t) slen) {
+ stat = TRUE;
+ if (su->su_cache)
+ cache_set(xprt, slen);
+ }
+ }
+ return (stat);
+}
+
+static bool_t
+svc_dg_getargs(xprt, xdr_args, args_ptr)
+ SVCXPRT *xprt;
+ xdrproc_t xdr_args;
+ void *args_ptr;
+{
+ return (*xdr_args)(&(su_data(xprt)->su_xdrs), args_ptr);
+}
+
+static bool_t
+svc_dg_freeargs(xprt, xdr_args, args_ptr)
+ 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(xprt)
+ 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);
+ (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);
+ if (xprt->xp_tp)
+ (void) free(xprt->xp_tp);
+ (void) mem_free(xprt, sizeof (SVCXPRT));
+}
+
+static bool_t
+/*ARGSUSED*/
+svc_dg_control(xprt, rq, in)
+ SVCXPRT *xprt;
+ const u_int rq;
+ void *in;
+{
+ return (FALSE);
+}
+
+static void
+svc_dg_ops(xprt)
+ 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(transp, size)
+ 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(xprt, replylen)
+ 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(xprt, msg, replyp, replylenp)
+ 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 0000000..7f6cfb8
--- /dev/null
+++ b/lib/libc/rpc/svc_generic.c
@@ -0,0 +1,311 @@
+/* $NetBSD: svc_generic.c,v 1.3 2000/07/06 03:10:35 christos Exp $ */
+
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+/*
+ * 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.
+ */
+int
+svc_create(dispatch, prognum, versnum, nettype)
+ void (*dispatch)(struct svc_req *, SVCXPRT *);
+ rpcprog_t prognum; /* Program number */
+ rpcvers_t versnum; /* Version number */
+ const char *nettype; /* Networktype token */
+{
+ 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);
+ return (0);
+ }
+ l->xprt = xprt;
+ l->next = xprtlist;
+ xprtlist = l;
+ num++;
+ }
+ }
+ mutex_unlock(&xprtlist_lock);
+ }
+ __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();
+ */
+SVCXPRT *
+svc_tp_create(dispatch, prognum, versnum, nconf)
+ void (*dispatch)(struct svc_req *, SVCXPRT *);
+ rpcprog_t prognum; /* Program number */
+ rpcvers_t versnum; /* Version number */
+ const struct netconfig *nconf; /* Netconfig structure for the network */
+{
+ 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.
+ */
+SVCXPRT *
+svc_tli_create(fd, nconf, bindaddr, sendsz, recvsz)
+ int fd; /* Connection end point */
+ const struct netconfig *nconf; /* Netconfig struct for nettoken */
+ const struct t_bind *bindaddr; /* Local bind address */
+ u_int sendsz; /* Max sendsize */
+ u_int recvsz; /* Max recvsize */
+{
+ 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 0000000..32d1ff7
--- /dev/null
+++ b/lib/libc/rpc/svc_raw.c
@@ -0,0 +1,257 @@
+/* $NetBSD: svc_raw.c,v 1.14 2000/07/06 03:10:35 christos Exp $ */
+
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+/*
+ * 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()
+{
+ 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));
+ srp->raw_buf = __rpc_rawcombuf; /* Share it with the client */
+ svc_raw_private = srp;
+ }
+ srp->server.xp_fd = FD_SETSIZE;
+ srp->server.xp_port = 0;
+ srp->server.xp_p3 = NULL;
+ 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(xprt)
+SVCXPRT *xprt; /* args needed to satisfy ANSI-C typechecking */
+{
+ return (XPRT_IDLE);
+}
+
+/*ARGSUSED*/
+static bool_t
+svc_raw_recv(xprt, msg)
+ 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(xprt, msg)
+ 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_ENCODE;
+ (void) XDR_SETPOS(xdrs, 0);
+ if (! xdr_replymsg(xdrs, msg)) {
+ return (FALSE);
+ }
+ (void) XDR_GETPOS(xdrs); /* called just for overhead */
+ return (TRUE);
+}
+
+/*ARGSUSED*/
+static bool_t
+svc_raw_getargs(xprt, xdr_args, args_ptr)
+ 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 (*xdr_args)(&srp->xdr_stream, args_ptr);
+}
+
+/*ARGSUSED*/
+static bool_t
+svc_raw_freeargs(xprt, xdr_args, args_ptr)
+ 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(xprt)
+SVCXPRT *xprt;
+{
+}
+
+/*ARGSUSED*/
+static bool_t
+svc_raw_control(xprt, rq, in)
+ SVCXPRT *xprt;
+ const u_int rq;
+ void *in;
+{
+ return (FALSE);
+}
+
+static void
+svc_raw_ops(xprt)
+ 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 0000000..b4627d6
--- /dev/null
+++ b/lib/libc/rpc/svc_run.c
@@ -0,0 +1,98 @@
+/* $NetBSD: svc_run.c,v 1.17 2000/07/06 03:10:35 christos Exp $ */
+
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#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()
+{
+ 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()
+{
+ 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 0000000..95d34a6
--- /dev/null
+++ b/lib/libc/rpc/svc_simple.c
@@ -0,0 +1,309 @@
+/* $NetBSD: svc_simple.c,v 1.20 2000/07/06 03:10:35 christos Exp $ */
+
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+/*
+ * 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 thru 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.
+ */
+
+int
+rpc_reg(prognum, versnum, procnum, progname, inproc, outproc, nettype)
+ rpcprog_t prognum; /* program number */
+ rpcvers_t versnum; /* version number */
+ rpcproc_t procnum; /* procedure number */
+ char *(*progname)(char *); /* Server routine */
+ xdrproc_t inproc, outproc; /* in/out XDR procedures */
+ char *nettype; /* 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);
+ 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 cant 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(rqstp, transp)
+ 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, sizeof (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 0000000..50c6651
--- /dev/null
+++ b/lib/libc/rpc/svc_vc.c
@@ -0,0 +1,787 @@
+/* $NetBSD: svc_vc.c,v 1.7 2000/08/03 00:01:53 fvdl Exp $ */
+
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#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/types.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(fd, sendsize, recvsize)
+ int fd;
+ u_int sendsize;
+ u_int recvsize;
+{
+ SVCXPRT *xprt;
+ struct cf_rendezvous *r = NULL;
+ struct __rpc_sockinfo si;
+ struct sockaddr_storage sslocal;
+ socklen_t slen;
+
+ r = mem_alloc(sizeof(*r));
+ if (r == NULL) {
+ warnx("svc_vc_create: out of memory");
+ goto cleanup_svc_vc_create;
+ }
+ if (!__rpc_fd2sockinfo(fd, &si))
+ return NULL;
+ 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 = mem_alloc(sizeof(SVCXPRT));
+ if (xprt == NULL) {
+ warnx("svc_vc_create: out of memory");
+ goto cleanup_svc_vc_create;
+ }
+ xprt->xp_tp = NULL;
+ xprt->xp_p1 = r;
+ xprt->xp_p2 = NULL;
+ xprt->xp_p3 = NULL;
+ 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 (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(fd, sendsize, recvsize)
+ 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(fd, sendsize, recvsize)
+ 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 = mem_alloc(sizeof(SVCXPRT));
+ if (xprt == NULL) {
+ warnx("svc_vc: makefd_xprt: out of memory");
+ goto done;
+ }
+ memset(xprt, 0, sizeof *xprt);
+ cd = mem_alloc(sizeof(struct cf_conn));
+ if (cd == NULL) {
+ warnx("svc_tcp: makefd_xprt: out of memory");
+ mem_free(xprt, sizeof(SVCXPRT));
+ 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); /* truely 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(xprt, msg)
+ SVCXPRT *xprt;
+ struct rpc_msg *msg;
+{
+ int sock, flags;
+ struct cf_rendezvous *r;
+ struct cf_conn *cd;
+ struct sockaddr_storage addr;
+ socklen_t len;
+ 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;
+
+ gettimeofday(&cd->last_recv_time, NULL);
+
+ return (FALSE); /* there is never an rpc msg to be processed */
+}
+
+/*ARGSUSED*/
+static enum xprt_stat
+rendezvous_stat(xprt)
+ SVCXPRT *xprt;
+{
+
+ return (XPRT_IDLE);
+}
+
+static void
+svc_vc_destroy(xprt)
+ SVCXPRT *xprt;
+{
+ assert(xprt != NULL);
+
+ xprt_unregister(xprt);
+ __svc_vc_dodestroy(xprt);
+}
+
+static void
+__svc_vc_dodestroy(xprt)
+ 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);
+ if (xprt->xp_tp)
+ free(xprt->xp_tp);
+ if (xprt->xp_netid)
+ free(xprt->xp_netid);
+ mem_free(xprt, sizeof(SVCXPRT));
+}
+
+/*ARGSUSED*/
+static bool_t
+svc_vc_control(xprt, rq, in)
+ SVCXPRT *xprt;
+ const u_int rq;
+ void *in;
+{
+ return (FALSE);
+}
+
+static bool_t
+svc_vc_rendezvous_control(xprt, rq, in)
+ 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(xprtp, buf, len)
+ 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(xprtp, buf, len)
+ 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 && i != cnt) {
+ /*
+ * 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);
+ }
+ }
+ }
+ }
+
+ return (len);
+}
+
+static enum xprt_stat
+svc_vc_stat(xprt)
+ 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(xprt, msg)
+ 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;
+ }
+
+ xdrs->x_op = XDR_DECODE;
+ (void)xdrrec_skiprecord(xdrs);
+ 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(xprt, xdr_args, args_ptr)
+ SVCXPRT *xprt;
+ xdrproc_t xdr_args;
+ void *args_ptr;
+{
+
+ assert(xprt != NULL);
+ /* args_ptr may be NULL */
+ return ((*xdr_args)(&(((struct cf_conn *)(xprt->xp_p1))->xdrs),
+ args_ptr));
+}
+
+static bool_t
+svc_vc_freeargs(xprt, xdr_args, args_ptr)
+ 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(xprt, msg)
+ SVCXPRT *xprt;
+ struct rpc_msg *msg;
+{
+ struct cf_conn *cd;
+ XDR *xdrs;
+ bool_t rstat;
+
+ 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 = xdr_replymsg(xdrs, msg);
+ (void)xdrrec_endofrecord(xdrs, TRUE);
+ return (rstat);
+}
+
+static void
+svc_vc_ops(xprt)
+ 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(xprt)
+ 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/softfloat/Makefile.inc b/lib/libc/softfloat/Makefile.inc
new file mode 100644
index 0000000..c786761
--- /dev/null
+++ b/lib/libc/softfloat/Makefile.inc
@@ -0,0 +1,20 @@
+# $NetBSD: Makefile.inc,v 1.3 2003/05/06 08:58:20 rearnsha Exp $
+# $FreeBSD$
+
+SOFTFLOAT_BITS?=64
+.PATH: ${MACHINE_ARCH}/softfloat \
+ ${.CURDIR}/softfloat/bits${SOFTFLOAT_BITS} ${.CURDIR}/softfloat
+
+CFLAGS+= -I${.CURDIR}/${MACHINE_ARCH}/softfloat -I${.CURDIR}/softfloat
+CFLAGS+= -DSOFTFLOAT_FOR_GCC
+
+SRCS+= softfloat.c
+
+SRCS+= fpgetround.c fpsetround.c fpgetmask.c fpsetmask.c \
+ fpgetsticky.c
+
+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
+
+SYM_MAPS+= ${.CURDIR}/softfloat/Symbol.map
diff --git a/lib/libc/softfloat/README.NetBSD b/lib/libc/softfloat/README.NetBSD
new file mode 100644
index 0000000..c6ca7a8
--- /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 0000000..fe28ccc
--- /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 0000000..273a901
--- /dev/null
+++ b/lib/libc/softfloat/Symbol.map
@@ -0,0 +1,45 @@
+# $FreeBSD$
+
+FBSD_1.0 {
+ _fpgetmask;
+ fpgetmask;
+ _fpgetround;
+ fpgetround;
+ _fpgetsticky;
+ fpgetsticky;
+ _fpsetmask;
+ fpsetmask;
+ _fpsetround;
+ fpsetround;
+ _fpsetsticky;
+ fpsetsticky;
+};
+
+FBSDprivate {
+ _softfloat_float_exception_flags;
+ _softfloat_float_exception_mask;
+ _softfloat_float_rounding_mode;
+ _softfloat_float_raise;
+ _softfloat_float32_eq;
+ _softfloat_float32_le;
+ _softfloat_float32_lt;
+ _softfloat_float64_eq;
+ _softfloat_float64_le;
+ _softfloat_float64_lt;
+ __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 0000000..4fd4f2f
--- /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 < 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 < 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 0000000..7785c4e
--- /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.
+-------------------------------------------------------------------------------
+*/
+fp_rnd_t float_rounding_mode = float_round_nearest_even;
+fp_except 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 0000000..9b478e8
--- /dev/null
+++ b/lib/libc/softfloat/bits64/softfloat-macros
@@ -0,0 +1,746 @@
+/* $NetBSD: softfloat-macros,v 1.1 2002/05/21 23:51:08 bjh21 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 < 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 < 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 0000000..ffd5661
--- /dev/null
+++ b/lib/libc/softfloat/bits64/softfloat.c
@@ -0,0 +1,5500 @@
+/* $NetBSD: softfloat.c,v 1.2 2003/07/26 19:24:52 salo 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.
+-------------------------------------------------------------------------------
+*/
+fp_rnd_t float_rounding_mode = float_round_nearest_even;
+fp_except 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 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+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 );
+
+}
+
+#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 );
+
+}
+
+#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 );
+
+}
+
+#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;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+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, &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 0000000..68bb55c
--- /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 0000000..d45b806
--- /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/fpgetmask.c b/lib/libc/softfloat/fpgetmask.c
new file mode 100644
index 0000000..27f7460
--- /dev/null
+++ b/lib/libc/softfloat/fpgetmask.c
@@ -0,0 +1,60 @@
+/* $NetBSD: fpgetmask.c,v 1.3 2002/05/12 13:12:45 bjh21 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 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.
+ */
+
+#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 0000000..4ffb71f
--- /dev/null
+++ b/lib/libc/softfloat/fpgetround.c
@@ -0,0 +1,60 @@
+/* $NetBSD: fpgetround.c,v 1.2 2002/01/13 21:45:53 thorpej 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 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.
+ */
+
+#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 0000000..c76f985
--- /dev/null
+++ b/lib/libc/softfloat/fpgetsticky.c
@@ -0,0 +1,60 @@
+/* $NetBSD: fpgetsticky.c,v 1.2 2002/01/13 21:45:53 thorpej 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 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.
+ */
+
+#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 0000000..fb8b44d
--- /dev/null
+++ b/lib/libc/softfloat/fpsetmask.c
@@ -0,0 +1,63 @@
+/* $NetBSD: fpsetmask.c,v 1.3 2002/05/12 13:12:45 bjh21 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 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.
+ */
+
+#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 0000000..ce3ef9e
--- /dev/null
+++ b/lib/libc/softfloat/fpsetround.c
@@ -0,0 +1,63 @@
+/* $NetBSD: fpsetround.c,v 1.2 2002/01/13 21:45:53 thorpej 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 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.
+ */
+
+#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 0000000..99379b3
--- /dev/null
+++ b/lib/libc/softfloat/fpsetsticky.c
@@ -0,0 +1,63 @@
+/* $NetBSD: fpsetsticky.c,v 1.2 2002/01/13 21:45:54 thorpej 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 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.
+ */
+
+#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 0000000..76e25de
--- /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 0000000..b22e13a
--- /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/gtdf2.c b/lib/libc/softfloat/gtdf2.c
new file mode 100644
index 0000000..ff5764a
--- /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 0000000..8e7e7a9
--- /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/ledf2.c b/lib/libc/softfloat/ledf2.c
new file mode 100644
index 0000000..7d3e8fb
--- /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 0000000..6fa13e5
--- /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/ltdf2.c b/lib/libc/softfloat/ltdf2.c
new file mode 100644
index 0000000..b8c668c
--- /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 0000000..8a1e8fa9
--- /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/nedf2.c b/lib/libc/softfloat/nedf2.c
new file mode 100644
index 0000000..61f5044
--- /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 0000000..2485d58
--- /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 0000000..78f6c6b
--- /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/nesf2.c b/lib/libc/softfloat/nesf2.c
new file mode 100644
index 0000000..b8317cb
--- /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/softfloat-for-gcc.h b/lib/libc/softfloat/softfloat-for-gcc.h
new file mode 100644
index 0000000..fa5b3e8
--- /dev/null
+++ b/lib/libc/softfloat/softfloat-for-gcc.h
@@ -0,0 +1,43 @@
+/* $NetBSD: softfloat-for-gcc.h,v 1.6 2003/07/26 19:24:51 salo 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
+
+/*
+ * Macros to define functions with the GCC expected names
+ */
+
+#define float32_add __addsf3
+#define float64_add __adddf3
+#define float32_sub __subsf3
+#define float64_sub __subdf3
+#define float32_mul __mulsf3
+#define float64_mul __muldf3
+#define float32_div __divsf3
+#define float64_div __divdf3
+#define int32_to_float32 __floatsisf
+#define int32_to_float64 __floatsidf
+#define int64_to_float32 __floatdisf
+#define int64_to_float64 __floatdidf
+#define float32_to_int32_round_to_zero __fixsfsi
+#define float64_to_int32_round_to_zero __fixdfsi
+#define float32_to_int64_round_to_zero __fixsfdi
+#define float64_to_int64_round_to_zero __fixdfdi
+#define float32_to_uint32_round_to_zero __fixunssfsi
+#define float64_to_uint32_round_to_zero __fixunsdfsi
+#define float32_to_float64 __extendsfdf2
+#define float64_to_float32 __truncdfsf2
diff --git a/lib/libc/softfloat/softfloat-history.txt b/lib/libc/softfloat/softfloat-history.txt
new file mode 100644
index 0000000..d8c98db
--- /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 0000000..0675966
--- /dev/null
+++ b/lib/libc/softfloat/softfloat-source.txt
@@ -0,0 +1,384 @@
+$NetBSD: softfloat-source.txt,v 1.1 2000/06/06 08:15:10 bjh21 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 accomodate 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 0000000..c8c8028
--- /dev/null
+++ b/lib/libc/softfloat/softfloat-specialize
@@ -0,0 +1,490 @@
+/* $NetBSD: softfloat-specialize,v 1.3 2002/05/12 13:12:45 bjh21 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>
+
+/*
+-------------------------------------------------------------------------------
+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
+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;'.
+-------------------------------------------------------------------------------
+*/
+fp_except float_exception_mask = 0;
+void float_raise( fp_except flags )
+{
+
+ float_exception_flags |= flags;
+
+ if ( flags & float_exception_mask ) {
+ raise( SIGFPE );
+ }
+}
+
+/*
+-------------------------------------------------------------------------------
+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)
+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)
+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 0000000..bd63324
--- /dev/null
+++ b/lib/libc/softfloat/softfloat.txt
@@ -0,0 +1,373 @@
+$NetBSD: softfloat.txt,v 1.1 2000/06/06 08:15:10 bjh21 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 accomodate 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 0000000..b7bd8e5
--- /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 0000000..a1dc4de
--- /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 0000000..070aab2
--- /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 0000000..98b6ba2
--- /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 = 0;
+ }
+#ifdef FLOATX80
+ floatx80_rounding_precision = roundingPrecision;
+#endif
+ switch ( roundingMode ) {
+ case 0:
+ roundingModeName = 0;
+ 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 = 0;
+ 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 0000000..addc647
--- /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 0000000..2986c82
--- /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 0000000..e2f4c8f
--- /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 0000000..2b9d3ab
--- /dev/null
+++ b/lib/libc/sparc64/Makefile.inc
@@ -0,0 +1,11 @@
+# $FreeBSD$
+#
+# Machine dependent definitions for the ultra sparc architecture.
+#
+
+.include "fpu/Makefile.inc"
+
+# Long double is quad precision
+GDTOASRCS+=strtopQ.c
+MDSRCS+=machdep_ldisQ.c
+SYM_MAPS+=${.CURDIR}/sparc64/Symbol.map
diff --git a/lib/libc/sparc64/SYS.h b/lib/libc/sparc64/SYS.h
new file mode 100644
index 0000000..6fe4ccd
--- /dev/null
+++ b/lib/libc/sparc64/SYS.h
@@ -0,0 +1,90 @@
+/*-
+ * 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. 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.
+ *
+ * @(#)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)) ; \
+ mov __CONCAT(SYS_,x), %g1 ; \
+ ta %xcc, ST_SYSCALL ; \
+ 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 0000000..c3ccdab
--- /dev/null
+++ b/lib/libc/sparc64/Symbol.map
@@ -0,0 +1,100 @@
+# $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;
+ fpgetround;
+ fpgetsticky;
+ fpsetmask;
+ fpsetround;
+ __infinity;
+ __nan;
+ makecontext;
+ modf;
+ setjmp;
+ longjmp;
+ sigsetjmp;
+ siglongjmp;
+ htonl;
+ __htonl;
+ htons;
+ __htons;
+ ntohl;
+ __ntohl;
+ ntohs;
+ __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 {
+ # PSEUDO syscalls
+ __sys_getlogin;
+ _getlogin;
+ __sys_exit;
+
+ _set_tp;
+ ___longjmp;
+ __makecontext;
+ __longjmp;
+ signalcontext;
+ __signalcontext;
+ __siglongjmp;
+ .curbrk;
+ .minbrk;
+ __sys_brk;
+ _brk;
+ .cerror;
+ __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 0000000..e5f2238
--- /dev/null
+++ b/lib/libc/sparc64/_fpmath.h
@@ -0,0 +1,52 @@
+/*-
+ * 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;
+};
+
+#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 0000000..3c35b80
--- /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 0000000..1974d8a
--- /dev/null
+++ b/lib/libc/sparc64/fpu/Makefile.inc
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/sparc64/fpu
+
+CFLAGS+= -I${.CURDIR}/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 0000000..63a3c0d
--- /dev/null
+++ b/lib/libc/sparc64/fpu/fpu.c
@@ -0,0 +1,470 @@
+/*
+ * 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.
+ * 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 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 <unistd.h>
+#include <signal.h>
+#include <stdlib.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 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 char *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 int opmask[] = {0, 0, 1, 3};
+
+/* Decode 5 bit register field depending on the type. */
+#define RN_DECODE(tp, rn) \
+ ((tp == FTYPE_DBL || tp == FTYPE_EXT ? INSFPdq_RN((rn)) : (rn)) & \
+ ~opmask[tp])
+
+/* Operand size in 32-bit registers. */
+#define OPSZ(tp) ((tp) == FTYPE_LNG ? 2 : (1 << (tp)))
+
+/*
+ * 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 (1 << 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)
+{
+ u_int64_t tmp64;
+ int i;
+
+ 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.
+ */
+ for (i = 0; i < OPSZ(type); i += 2, rd += 2, rs2 += 2) {
+ tmp64 = __fpu_getreg64(rs2);
+ if (i == 0)
+ tmp64 = (tmp64 & ~((u_int64_t)nand << 32)) ^
+ ((u_int64_t)xor << 32);
+ __fpu_setreg64(rd, tmp64);
+ }
+ }
+}
+
+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;
+ u_long reg, fsr;
+ u_int space[4];
+ int i;
+
+ /*
+ * `Decode' and execute instruction. Start with no exceptions.
+ * The type of 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): /* these should all be pretty obvious */
+ __fpu_mov(fe, type, rd, rs2, 0, 0);
+ return (0);
+ case FOP(INS2_FPop1, INSFP1_FNEG):
+ __fpu_mov(fe, type, rd, rs2, 0, (1 << 31));
+ return (0);
+ case FOP(INS2_FPop1, INSFP1_FABS):
+ __fpu_mov(fe, type, rd, rs2, (1 << 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;
+ __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;
+ mask = 1; /* needs 2 registers */
+ rd = IF_F3_RD(insn) & ~mask;
+ 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 {
+ for (i = 0; i < OPSZ(type); i += 2) {
+ __fpu_setreg64(rd + i, ((u_int64_t)space[i] << 32) |
+ space[i + 1]);
+ }
+ }
+ 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 0000000..405b9b8
--- /dev/null
+++ b/lib/libc/sparc64/fpu/fpu_add.c
@@ -0,0 +1,218 @@
+/*
+ * 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.
+ * 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.
+ *
+ * @(#)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 0000000..9cb7488
--- /dev/null
+++ b/lib/libc/sparc64/fpu/fpu_arith.h
@@ -0,0 +1,96 @@
+/*
+ * 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.
+ * 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.
+ *
+ * @(#)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 0000000..428e8d3
--- /dev/null
+++ b/lib/libc/sparc64/fpu/fpu_compare.c
@@ -0,0 +1,181 @@
+/*
+ * 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.
+ * 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.
+ *
+ * @(#)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 0000000..a7b4782
--- /dev/null
+++ b/lib/libc/sparc64/fpu/fpu_div.c
@@ -0,0 +1,272 @@
+/*
+ * 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.
+ * 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.
+ *
+ * @(#)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
+ */
+ 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));
+ return (x);
+ }
+
+ /* all results at this point use XOR of operand signs */
+ 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 0000000..51996b1
--- /dev/null
+++ b/lib/libc/sparc64/fpu/fpu_emu.h
@@ -0,0 +1,184 @@
+/*
+ * 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.
+ * 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.
+ *
+ * @(#)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 -1
+
+/*
+ * Emulator state.
+ */
+struct fpemu {
+ u_long fe_fsr; /* fsr copy (modified during op) */
+ int fe_cx; /* exceptions */
+ 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) ((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 0000000..09f8908
--- /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.
+ * 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.
+ *
+ * @(#)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>
+
+#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_int32_t s, *sp;
+ u_int64_t l[2];
+
+ if (type == FTYPE_LNG || type == FTYPE_DBL || type == FTYPE_EXT) {
+ l[0] = __fpu_getreg64(reg & ~1);
+ sp = (u_int32_t *)l;
+ fp->fp_sign = sp[0] >> 31;
+ } else {
+ s = __fpu_getreg(reg);
+ fp->fp_sign = s >> 31;
+ }
+ fp->fp_sticky = 0;
+ switch (type) {
+ case FTYPE_LNG:
+ s = __fpu_xtof(fp, l[0]);
+ 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, sp[0], sp[1]);
+ break;
+
+ case FTYPE_EXT:
+ l[1] = __fpu_getreg64((reg & ~1) + 2);
+ s = __fpu_qtof(fp, sp[0], sp[1], sp[2], sp[3]);
+ 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 0000000..f22c463
--- /dev/null
+++ b/lib/libc/sparc64/fpu/fpu_extern.h
@@ -0,0 +1,93 @@
+/*-
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 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.
+ *
+ * $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;
+union instr;
+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 0000000..2c3475e
--- /dev/null
+++ b/lib/libc/sparc64/fpu/fpu_implode.c
@@ -0,0 +1,537 @@
+/*
+ * 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.
+ * 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.
+ *
+ * @(#)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>
+
+#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:
+ res[1] = 0;
+ return (0);
+
+ 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 = -1;
+ res[1] = (int)i;
+ return (i >> 32);
+
+ default: /* Inf, qNaN, sNaN */
+ break;
+ }
+ /* overflow: replace any inexact exception with invalid */
+ fe->fe_cx = (fe->fe_cx & ~FSR_NX) | FSR_NV;
+ return (0x7fffffffffffffffLL + sign);
+}
+
+/*
+ * 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. In the latter case, signal an underflow
+ * if the result was 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))
+ 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)) {
+ 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) | 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)) {
+ 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) | 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 0000000..0bdb6ff
--- /dev/null
+++ b/lib/libc/sparc64/fpu/fpu_mul.c
@@ -0,0 +1,230 @@
+/*
+ * 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.
+ * 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.
+ *
+ * @(#)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)) {
+ y->fp_sign ^= x->fp_sign;
+ 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 0000000..284ff5e
--- /dev/null
+++ b/lib/libc/sparc64/fpu/fpu_qp.c
@@ -0,0 +1,148 @@
+/*-
+ * 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_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); \
+}
+
+#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_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); \
+}
+
+#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_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__); \
+ 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_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); \
+ 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_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);
+}
+
+_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 0000000..781b4fe
--- /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 0000000..b8b7229
--- /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
+ * cacheing 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 0000000..c35e2bc
--- /dev/null
+++ b/lib/libc/sparc64/fpu/fpu_sqrt.c
@@ -0,0 +1,401 @@
+/*
+ * 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.
+ * 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.
+ *
+ * @(#)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 `(1 << 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);
+ ODD_DOUBLE;
+ if ((int)d0 >= 0) {
+ x0 = d0, x1 = d1, x2 = d2;
+ q |= bit;
+ y2 |= 1;
+ }
+ 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;
+ 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 0000000..7e6308f
--- /dev/null
+++ b/lib/libc/sparc64/fpu/fpu_subr.c
@@ -0,0 +1,225 @@
+/*
+ * 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.
+ * 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.
+ *
+ * @(#)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/gen/Makefile.inc b/lib/libc/sparc64/gen/Makefile.inc
new file mode 100644
index 0000000..979c182
--- /dev/null
+++ b/lib/libc/sparc64/gen/Makefile.inc
@@ -0,0 +1,6 @@
+# $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 modf.S \
+ signalcontext.c setjmp.S sigsetjmp.S _set_tp.c
diff --git a/lib/libc/sparc64/gen/_ctx_start.S b/lib/libc/sparc64/gen/_ctx_start.S
new file mode 100644
index 0000000..4ba3fd8
--- /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 0000000..6255fd3
--- /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$
+ */
+
+void
+_set_tp(void *tpval)
+{
+ register void* tp __asm__("%g7");
+
+ tp = tpval;
+}
diff --git a/lib/libc/sparc64/gen/_setjmp.S b/lib/libc/sparc64/gen/_setjmp.S
new file mode 100644
index 0000000..c48876e
--- /dev/null
+++ b/lib/libc/sparc64/gen/_setjmp.S
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ * 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.
+ *
+ * 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 0000000..7b205db
--- /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 0000000..bbc744a
--- /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 0000000..75fceb6
--- /dev/null
+++ b/lib/libc/sparc64/gen/fixunsdfsi.S
@@ -0,0 +1,97 @@
+/*
+ * 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.
+ * 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.
+ *
+ * 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 0000000..706ef5a
--- /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 0000000..05b151a
--- /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 0000000..dbc90d7
--- /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 0000000..274566a
--- /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 0000000..9aefb13
--- /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 0000000..1e27f59
--- /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 0000000..6d0d934
--- /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 0000000..95795de
--- /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/modf.S b/lib/libc/sparc64/gen/modf.S
new file mode 100644
index 0000000..f578c45
--- /dev/null
+++ b/lib/libc/sparc64/gen/modf.S
@@ -0,0 +1,181 @@
+/*
+ * 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.
+ * 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.
+ *
+ * from: Header: modf.s,v 1.3 92/06/20 00:00:54 torek Exp
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+ .asciz "@(#)modf.s 8.1 (Berkeley) 6/4/93"
+#if 0
+ .asciz "$NetBSD: modf.S,v 1.2 2000/07/23 07:12:22 eeh Exp $"
+#endif
+#endif /* LIBC_SCCS and not lint */
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "assym.s"
+
+/*
+ * double modf(double val, double *iptr)
+ *
+ * Returns the fractional part of `val', storing the integer part of
+ * `val' in *iptr. Both *iptr and the return value have the same sign
+ * as `val'.
+ *
+ * Method:
+ *
+ * We use the fpu's normalization hardware to compute the integer portion
+ * of the double precision argument. Sun IEEE double precision numbers
+ * have 52 bits of mantissa, 11 bits of exponent, and one bit of sign,
+ * with the sign occupying bit 31 of word 0, and the exponent bits 30:20
+ * of word 0. Thus, values >= 2^52 are by definition integers.
+ *
+ * If we take a value that is in the range [+0..2^52) and add 2^52, all
+ * of the fractional bits fall out and all of the integer bits are summed
+ * with 2^52. If we then subtract 2^52, we get those integer bits back.
+ * This must be done with rounding set to `towards 0' or `towards -inf'.
+ * `Toward -inf' fails when the value is 0 (we get -0 back)....
+ *
+ * Note that this method will work anywhere, but is machine dependent in
+ * various aspects.
+ *
+ * Stack usage:
+ * 4@[%fp + SPOFF - 4] saved %fsr
+ * 4@[%fp + SPOFF - 8] new %fsr with rounding set to `towards 0'
+ * 8@[%fp + SPOFF - 16] space for moving between %i and %f registers
+ * Register usage:
+ * %f0:f1 double val;
+ * %l0 scratch
+ * %l1 sign bit (0x80000000)
+ * %i1 double *iptr;
+ * %f2:f3 `magic number' 2^52, in fpu registers
+ * %f4:f5 double v, in fpu registers
+ * %f6:f7 double temp.
+ */
+
+ .align 8
+.Lmagic:
+ .word 0x43300000 ! sign = 0, exponent = 52 + 1023, mantissa = 0
+ .word 0 ! (i.e., .double 0r4503599627370496e+00)
+
+.L0:
+ .word 0 ! 0.0
+ .word 0
+
+ENTRY(modf)
+ save %sp, -CCFSZ - 16, %sp
+ PIC_PROLOGUE(%l6, %l7)
+
+ /*
+ * First, compute v = abs(val)
+ */
+ fabsd %f0, %f4 ! %f4:f5 = v
+ fcmped %fcc1, %f0, %f4 ! %fcc1 = (val == abs(val))
+ SET(.Lmagic, %l7, %l0)
+ ldd [%l0], %f2
+
+ /*
+ * Is %f4:f5 >= %f2:f3 ? If so, it is all integer bits.
+ * It is probably less, though.
+ */
+ fcmped %f4, %f2
+ fbuge .Lbig ! if >= (or unordered), go out
+ nop
+
+ /*
+ * v < 2^52, so add 2^52, then subtract 2^52, but do it all
+ * with rounding set towards zero. We leave any enabled
+ * traps enabled, but change the rounding mode. This might
+ * not be so good. Oh well....
+ */
+ st %fsr, [%fp + SPOFF - 4] ! %l5 = current FSR mode
+ set FSR_RD_MASK, %l3 ! %l3 = rounding direction mask
+ ld [%fp + SPOFF - 4], %l5
+ set FSR_RD_RD_Z, %l4
+ andn %l5, %l3, %l6
+ or %l6, %l4, %l6 ! round towards zero, please
+ and %l5, %l3, %l5 ! save original rounding mode
+ st %l6, [%fp + SPOFF - 8]
+ ld [%fp + SPOFF - 8], %fsr
+
+ faddd %f4, %f2, %f4 ! %f4:f5 += 2^52
+ fsubd %f4, %f2, %f4 ! %f4:f5 -= 2^52
+
+ /*
+ * Restore %fsr, but leave exceptions accrued.
+ */
+ st %fsr, [%fp + SPOFF - 4]
+ ld [%fp + SPOFF - 4], %l6
+ andn %l6, %l3, %l6 ! %l6 = %fsr & ~FSR_RD_MASK;
+ or %l5, %l6, %l5 ! %l5 |= %l6;
+ st %l5, [%fp + SPOFF - 4]
+ ld [%fp + SPOFF - 4], %fsr ! restore %fsr, leaving accrued stuff
+
+ /*
+ * Now insert the original sign in %f4:f5.
+ * %fcc1 should still have the results of (val == abs(val))
+ * from above, so we use a conditional move on %fcc1 to:
+ *
+ * %f4 = (val == abs(val)) ? %f4 : -%f4
+ *
+ */
+ fnegd %f4, %f6
+ fmovdnz %fcc1, %f6, %f4
+1:
+
+ /*
+ * The value in %f4:f5 is now the integer portion of the original
+ * argument. We need to store this in *ival (%i1), subtract it
+ * from the original value argument (%d0), and return the result.
+ */
+ std %f4, [%i1] ! *ival = %f4:f5;
+ fsubd %f0, %f4, %f0 ! %f0:f1 -= %f4:f5;
+ ret
+ restore
+
+.Lbig:
+ /*
+ * We get here if the original comparison of %f4:f5 (v) to
+ * %f2:f3 (2^52) came out `greater or unordered'. In this
+ * case the integer part is the original value, and the
+ * fractional part is 0.
+ */
+ SET(.L0, %l7, %l0)
+ std %f0, [%i1] ! *ival = val;
+ ldd [%l0], %f0 ! return 0.0;
+ ret
+ restore
+END(modf)
diff --git a/lib/libc/sparc64/gen/setjmp.S b/lib/libc/sparc64/gen/setjmp.S
new file mode 100644
index 0000000..5ad65a5
--- /dev/null
+++ b/lib/libc/sparc64/gen/setjmp.S
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ * 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.
+ *
+ * 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 0000000..622f36f
--- /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 0000000..4e44566
--- /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/net/Makefile.inc b/lib/libc/sparc64/net/Makefile.inc
new file mode 100644
index 0000000..b717813
--- /dev/null
+++ b/lib/libc/sparc64/net/Makefile.inc
@@ -0,0 +1,3 @@
+# $FreeBSD$
+
+SRCS+= htonl.S htons.S ntohl.S ntohs.S
diff --git a/lib/libc/sparc64/net/htonl.S b/lib/libc/sparc64/net/htonl.S
new file mode 100644
index 0000000..2ba02c4
--- /dev/null
+++ b/lib/libc/sparc64/net/htonl.S
@@ -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.
+ * 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.
+ *
+ * from: Header: htonl.s,v 1.1 92/06/25 12:47:05 torek Exp
+ */
+
+#include <machine/asm.h>
+
+#if defined(LIBC_SCCS) && !defined(lint)
+ .asciz "@(#)htonl.s 8.1 (Berkeley) 6/4/93"
+#if 0
+ RCSID("$NetBSD: htonl.S,v 1.1 1998/09/11 04:56:30 eeh Exp $")
+#endif
+#endif /* LIBC_SCCS and not lint */
+__FBSDID("$FreeBSD$");
+
+/* netorder = htonl(hostorder) */
+ .weak CNAME(htonl)
+ .set CNAME(htonl),CNAME(__htonl)
+ENTRY(__htonl)
+ retl
+ srl %o0, 0, %o0 /* zero extend */
+END(__htonl)
diff --git a/lib/libc/sparc64/net/htons.S b/lib/libc/sparc64/net/htons.S
new file mode 100644
index 0000000..16035e0
--- /dev/null
+++ b/lib/libc/sparc64/net/htons.S
@@ -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.
+ * 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.
+ *
+ * from: Header: htons.s,v 1.1 92/06/25 12:47:05 torek Exp
+ */
+
+#include <machine/asm.h>
+
+#if defined(LIBC_SCCS) && !defined(lint)
+ .asciz "@(#)htons.s 8.1 (Berkeley) 6/4/93"
+#if 0
+ RCSID("$NetBSD: htons.S,v 1.1 1998/09/11 04:56:30 eeh Exp $")
+#endif
+#endif /* LIBC_SCCS and not lint */
+__FBSDID("$FreeBSD$");
+
+/* netorder = htons(hostorder) */
+ .weak CNAME(htons)
+ .set CNAME(htons),CNAME(__htons)
+ENTRY(__htons)
+ sethi %hi(0xffff0000), %o1
+ signx %o1, %o1
+ retl
+ andn %o0, %o1, %o0
+END(__htons)
diff --git a/lib/libc/sparc64/net/ntohl.S b/lib/libc/sparc64/net/ntohl.S
new file mode 100644
index 0000000..4333f23
--- /dev/null
+++ b/lib/libc/sparc64/net/ntohl.S
@@ -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.
+ * 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.
+ *
+ * from: Header: ntohl.s,v 1.1 92/06/25 12:47:06 torek Exp
+ */
+
+#include <machine/asm.h>
+
+#if defined(LIBC_SCCS) && !defined(lint)
+ .asciz "@(#)ntohl.s 8.1 (Berkeley) 6/4/93"
+#if 0
+ RCSID("$NetBSD: ntohl.S,v 1.1 1998/09/11 04:56:31 eeh Exp $")
+#endif
+#endif /* LIBC_SCCS and not lint */
+__FBSDID("$FreeBSD$");
+
+/* hostorder = ntohl(netorder) */
+ .weak CNAME(ntohl)
+ .set CNAME(ntohl),CNAME(__ntohl)
+ENTRY(__ntohl)
+ retl
+ srl %o0, 0, %o0 /* zero extend */
+END(__ntohl)
diff --git a/lib/libc/sparc64/net/ntohs.S b/lib/libc/sparc64/net/ntohs.S
new file mode 100644
index 0000000..03a09b5
--- /dev/null
+++ b/lib/libc/sparc64/net/ntohs.S
@@ -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.
+ * 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.
+ *
+ * from: Header: ntohs.s,v 1.1 92/06/25 12:47:07 torek Exp
+ */
+
+#include <machine/asm.h>
+
+#if defined(LIBC_SCCS) && !defined(lint)
+ .asciz "@(#)ntohs.s 8.1 (Berkeley) 6/4/93"
+#if 0
+ RCSID("$NetBSD: ntohs.S,v 1.1 1998/09/11 04:56:31 eeh Exp $")
+#endif
+#endif /* LIBC_SCCS and not lint */
+__FBSDID("$FreeBSD$");
+
+/* hostorder = ntohs(netorder) */
+ .weak CNAME(ntohs)
+ .set CNAME(ntohs),CNAME(__ntohs)
+ENTRY(__ntohs)
+ sethi %hi(0xffff0000), %o1
+ signx %o1, %o1
+ retl
+ andn %o0, %o1, %o0
+END(__ntohs)
diff --git a/lib/libc/sparc64/stdlib/Makefile.inc b/lib/libc/sparc64/stdlib/Makefile.inc
new file mode 100644
index 0000000..e8c0da7
--- /dev/null
+++ b/lib/libc/sparc64/stdlib/Makefile.inc
@@ -0,0 +1 @@
+# $FreeBSD$
diff --git a/lib/libc/sparc64/string/Makefile.inc b/lib/libc/sparc64/string/Makefile.inc
new file mode 100644
index 0000000..e8c0da7
--- /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 0000000..f677df1
--- /dev/null
+++ b/lib/libc/sparc64/sys/Makefile.inc
@@ -0,0 +1,23 @@
+# $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${.CURDIR}/sparc64/fpu
+
+MDASM+= brk.S cerror.S exect.S pipe.S ptrace.S sbrk.S setlogin.S sigaction.S
+
+# Don't generate default code for these syscalls:
+NOASM= break.o exit.o ftruncate.o getdomainname.o getlogin.o \
+ lseek.o mmap.o openbsd_poll.o pread.o \
+ pwrite.o setdomainname.o sstk.o truncate.o uname.o yield.o
+
+PSEUDO= _getlogin.o _exit.o
+
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 0000000..4475c6d
--- /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 0000000..e556f83
--- /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(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 0000000..9b59826
--- /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 0000000..6c6dd1b
--- /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 0000000..502f81a
--- /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 0000000..6f6f0e3
--- /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 0000000..7b1a5e7
--- /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 0000000..8b9ae9e
--- /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 0000000..f4a624b
--- /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, &uia);
+}
diff --git a/lib/libc/sparc64/sys/assym.s b/lib/libc/sparc64/sys/assym.s
new file mode 100644
index 0000000..2e799f6
--- /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 0000000..018c877
--- /dev/null
+++ b/lib/libc/sparc64/sys/brk.S
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ * 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.
+ *
+ * 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 0000000..c75f27c
--- /dev/null
+++ b/lib/libc/sparc64/sys/cerror.S
@@ -0,0 +1,63 @@
+/*-
+ * 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. 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.
+ *
+ * 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 0000000..f8e3883
--- /dev/null
+++ b/lib/libc/sparc64/sys/exect.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.
+ * 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.
+ *
+ * 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/pipe.S b/lib/libc/sparc64/sys/pipe.S
new file mode 100644
index 0000000..1168134
--- /dev/null
+++ b/lib/libc/sparc64/sys/pipe.S
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ * 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.
+ *
+ * from: Header: pipe.s,v 1.1 91/07/06 13:05:58 torek Exp
+ */
+
+#if defined(SYSLIBC_SCCS) && !defined(lint)
+ .asciz "@(#)pipe.s 8.1 (Berkeley) 6/4/93"
+#if 0
+ RCSID("$NetBSD: pipe.S,v 1.3 2000/09/28 08:38:55 kleink Exp $")
+#endif
+#endif /* SYSLIBC_SCCS and not lint */
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+_SYSENTRY(pipe)
+ mov %o0, %o2
+ mov SYS_pipe, %g1
+ ta %xcc, ST_SYSCALL
+ bcc,a,pt %xcc, 1f
+ stw %o0, [%o2]
+ ERROR()
+1: stw %o1, [%o2 + 4]
+ retl
+ clr %o0
+_SYSEND(pipe)
diff --git a/lib/libc/sparc64/sys/ptrace.S b/lib/libc/sparc64/sys/ptrace.S
new file mode 100644
index 0000000..b1d1ff2
--- /dev/null
+++ b/lib/libc/sparc64/sys/ptrace.S
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ * 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.
+ *
+ * from: Header: ptrace.s,v 1.2 91/12/20 01:59:00 leres Exp
+ * from: NetBSD: ptrace.S,v 1.4 2000/07/24 00:11:10 mycroft Exp
+ */
+
+#if defined(SYSLIBC_SCCS) && !defined(lint)
+ .asciz "@(#)ptrace.s 8.1 (Berkeley) 6/4/93"
+#if 0
+ RCSID("$NetBSD: ptrace.S,v 1.4 2000/07/24 00:11:10 mycroft Exp $")
+#endif
+#endif /* SYSLIBC_SCCS and not lint */
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+_SYSENTRY(ptrace)
+ save %sp, -CCFSZ, %sp
+ call CNAME(__error)
+ nop
+ stw %g0, [%o0]
+ restore
+ _SYSCALL(ptrace)
+ retl
+ nop
+_SYSEND(ptrace)
diff --git a/lib/libc/sparc64/sys/sbrk.S b/lib/libc/sparc64/sys/sbrk.S
new file mode 100644
index 0000000..2ade273
--- /dev/null
+++ b/lib/libc/sparc64/sys/sbrk.S
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ * 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.
+ *
+ * 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 0000000..480e9ec
--- /dev/null
+++ b/lib/libc/sparc64/sys/setlogin.S
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ * 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.
+ *
+ * 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/sigaction.S b/lib/libc/sparc64/sys/sigaction.S
new file mode 100644
index 0000000..7d32f97
--- /dev/null
+++ b/lib/libc/sparc64/sys/sigaction.S
@@ -0,0 +1,49 @@
+/*-
+ * 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"
+
+_SYSENTRY(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
+_SYSEND(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 0000000..be3cb45
--- /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 0000000..d815c97
--- /dev/null
+++ b/lib/libc/stdio/Makefile.inc
@@ -0,0 +1,72 @@
+# @(#)Makefile.inc 8.3 (Berkeley) 4/17/94
+# $FreeBSD$
+
+# stdio sources
+.PATH: ${.CURDIR}/stdio
+
+SRCS+= _flock_stub.c asprintf.c clrerr.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 fopen.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 gets.c getw.c getwc.c getwchar.c makebuf.c mktemp.c \
+ perror.c printf.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 unlocked.c vasprintf.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+= ${.CURDIR}/stdio/Symbol.map
+
+MAN+= fclose.3 ferror.3 fflush.3 fgetln.3 fgets.3 fgetwln.3 fgetws.3 \
+ flockfile.3 \
+ fopen.3 fputs.3 \
+ fputws.3 fread.3 fseek.3 funopen.3 fwide.3 getc.3 getwc.3 mktemp.3 \
+ printf.3 putc.3 putwc.3 remove.3 scanf.3 setbuf.3 stdio.3 tmpnam.3 \
+ ungetc.3 ungetwc.3 wprintf.3 wscanf.3
+
+MLINKS+=fclose.3 fcloseall.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
+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+=getwc.3 fgetwc.3 getwc.3 getwchar.3
+MLINKS+=mktemp.3 mkdtemp.3 mktemp.3 mkstemp.3 mktemp.3 mkstemps.3
+MLINKS+=printf.3 asprintf.3 printf.3 fprintf.3 \
+ printf.3 snprintf.3 printf.3 sprintf.3 \
+ printf.3 vasprintf.3 \
+ printf.3 vfprintf.3 printf.3 vprintf.3 printf.3 vsnprintf.3 \
+ printf.3 vsprintf.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+=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 0000000..1296258
--- /dev/null
+++ b/lib/libc/stdio/Symbol.map
@@ -0,0 +1,145 @@
+# $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;
+ __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;
+};
+
+FBSDprivate {
+ _flockfile;
+ _flockfile_debug_stub;
+ _flockfile_debug;
+ _ftrylockfile;
+ _funlockfile;
+ __vfscanf;
+};
diff --git a/lib/libc/stdio/_flock_stub.c b/lib/libc/stdio/_flock_stub.c
new file mode 100644
index 0000000..8abc8e3
--- /dev/null
+++ b/lib/libc/stdio/_flock_stub.c
@@ -0,0 +1,149 @@
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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);
+
+/*
+ * We need to retain binary compatibility for a while. So pretend
+ * that _lock is part of FILE * even though it is dereferenced off
+ * _extra now. When we stop encoding the size of FILE into binaries
+ * this can be changed in stdio.h. This will reduce the amount of
+ * code that has to change in the future (just remove this comment
+ * and #define).
+ */
+#define _lock _extra
+
+void
+_flockfile(FILE *fp)
+{
+ pthread_t curthread = _pthread_self();
+
+ if (fp->_lock->fl_owner == curthread)
+ fp->_lock->fl_count++;
+ else {
+ /*
+ * Make sure this mutex is treated as a private
+ * internal mutex:
+ */
+ _pthread_mutex_lock(&fp->_lock->fl_mutex);
+ fp->_lock->fl_owner = curthread;
+ fp->_lock->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->_lock->fl_owner == curthread)
+ fp->_lock->fl_count++;
+ /*
+ * Make sure this mutex is treated as a private
+ * internal mutex:
+ */
+ else if (_pthread_mutex_trylock(&fp->_lock->fl_mutex) == 0) {
+ fp->_lock->fl_owner = curthread;
+ fp->_lock->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->_lock->fl_owner == curthread) {
+ /*
+ * Check if this thread has locked the FILE
+ * more than once:
+ */
+ if (fp->_lock->fl_count > 1)
+ /*
+ * Decrement the count of the number of
+ * times the running thread has locked this
+ * file:
+ */
+ fp->_lock->fl_count--;
+ else {
+ /*
+ * The running thread will release the
+ * lock now:
+ */
+ fp->_lock->fl_count = 0;
+ fp->_lock->fl_owner = NULL;
+ _pthread_mutex_unlock(&fp->_lock->fl_mutex);
+ }
+ }
+}
diff --git a/lib/libc/stdio/asprintf.c b/lib/libc/stdio/asprintf.c
new file mode 100644
index 0000000..f142651
--- /dev/null
+++ b/lib/libc/stdio/asprintf.c
@@ -0,0 +1,71 @@
+/* $OpenBSD: asprintf.c,v 1.8 2002/02/19 19:39:36 millert Exp $ */
+
+/*
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stdarg.h>
+
+#include "local.h"
+
+int
+asprintf(char **str, char const *fmt, ...)
+{
+ int ret;
+ va_list ap;
+ FILE f;
+ struct __sFILEX ext;
+
+ f._file = -1;
+ f._flags = __SWR | __SSTR | __SALC;
+ f._bf._base = f._p = (unsigned char *)malloc(128);
+ if (f._bf._base == NULL) {
+ *str = NULL;
+ errno = ENOMEM;
+ return (-1);
+ }
+ f._bf._size = f._w = 127; /* Leave room for the NUL */
+ f._extra = &ext;
+ INITEXTRA(&f);
+ va_start(ap, fmt);
+ ret = __vfprintf(&f, fmt, ap); /* Use unlocked __vfprintf */
+ va_end(ap);
+ if (ret < 0) {
+ free(f._bf._base);
+ *str = NULL;
+ errno = ENOMEM;
+ return (-1);
+ }
+ *f._p = '\0';
+ *str = (char *)f._bf._base;
+ return (ret);
+}
diff --git a/lib/libc/stdio/clrerr.c b/lib/libc/stdio/clrerr.c
new file mode 100644
index 0000000..13538d5
--- /dev/null
+++ b/lib/libc/stdio/clrerr.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. 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.
+ */
+
+#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
+
+void
+clearerr(fp)
+ FILE *fp;
+{
+ FLOCKFILE(fp);
+ __sclearerr(fp);
+ FUNLOCKFILE(fp);
+}
diff --git a/lib/libc/stdio/fclose.3 b/lib/libc/stdio/fclose.3
new file mode 100644
index 0000000..320de29
--- /dev/null
+++ b/lib/libc/stdio/fclose.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 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. 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.
+.\"
+.\" @(#)fclose.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt FCLOSE 3
+.Os
+.Sh NAME
+.Nm fclose ,
+.Nm fcloseall
+.Nd close a stream
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdio.h
+.Ft int
+.Fn fclose "FILE *stream"
+.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 fcloseall
+function calls
+.Fn fclose
+on all open streams.
+.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.
+In either case no further access to the stream is possible.
+.Sh ERRORS
+The
+.Fn fclose
+function
+may also fail and set
+.Va errno
+for any of the errors specified for the routines
+.Xr close 2
+or
+.Xr fflush 3 .
+.Sh NOTES
+The
+.Fn fclose
+function
+does not handle NULL arguments; they 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 .
+.Pp
+The
+.Fn fcloseall
+function first appeared in
+.Fx 7.0 .
diff --git a/lib/libc/stdio/fclose.c b/lib/libc/stdio/fclose.c
new file mode 100644
index 0000000..3524f60
--- /dev/null
+++ b/lib/libc/stdio/fclose.c
@@ -0,0 +1,75 @@
+/*-
+ * 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. 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.
+ */
+
+#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 <stdio.h>
+#include <stdlib.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+#include "local.h"
+
+int
+fclose(FILE *fp)
+{
+ int r;
+
+ if (fp->_flags == 0) { /* not open! */
+ errno = EBADF;
+ return (EOF);
+ }
+ FLOCKFILE(fp);
+ r = fp->_flags & __SWR ? __sflush(fp) : 0;
+ 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. */
+ fp->_flags = 0; /* Release this FILE for reuse. */
+ FUNLOCKFILE(fp);
+ return (r);
+}
diff --git a/lib/libc/stdio/fcloseall.c b/lib/libc/stdio/fcloseall.c
new file mode 100644
index 0000000..8ee9a62
--- /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 0000000..961c0d9
--- /dev/null
+++ b/lib/libc/stdio/fdopen.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. 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.
+ */
+
+#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 "un-namespace.h"
+#include "local.h"
+
+FILE *
+fdopen(fd, mode)
+ int fd;
+ const char *mode;
+{
+ FILE *fp;
+ static int nofile;
+ int flags, oflags, fdflags, tmp;
+
+ if (nofile == 0)
+ nofile = getdtablesize();
+
+ 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);
+ tmp = fdflags & O_ACCMODE;
+ if (tmp != O_RDWR && (tmp != (oflags & O_ACCMODE))) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ if ((fp = __sfp()) == NULL)
+ 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 ((oflags & O_APPEND) && !(fdflags & 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 0000000..0bb12be
--- /dev/null
+++ b/lib/libc/stdio/feof.c
@@ -0,0 +1,59 @@
+/*-
+ * 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. 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.
+ */
+
+#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
+
+int
+feof(FILE *fp)
+{
+ int ret;
+
+ FLOCKFILE(fp);
+ ret= __sfeof(fp);
+ FUNLOCKFILE(fp);
+ return (ret);
+}
diff --git a/lib/libc/stdio/ferror.3 b/lib/libc/stdio/ferror.3
new file mode 100644
index 0000000..3fe2839
--- /dev/null
+++ b/lib/libc/stdio/ferror.3
@@ -0,0 +1,136 @@
+.\" 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. 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.
+.\"
+.\" @(#)ferror.3 8.2 (Berkeley) 4/19/94
+.\" $FreeBSD$
+.\"
+.Dd January 10, 2003
+.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 can only be cleared by the function
+.Fn clearerr .
+.Pp
+The function
+.Fn ferror
+tests the error indicator for the stream pointed to by
+.Fa stream ,
+returning non-zero if it is set.
+The error indicator can only be reset by the
+.Fn clearerr
+function.
+.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 0000000..5d4c187
--- /dev/null
+++ b/lib/libc/stdio/ferror.c
@@ -0,0 +1,59 @@
+/*-
+ * 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. 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.
+ */
+
+#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
+
+int
+ferror(FILE *fp)
+{
+ int ret;
+
+ FLOCKFILE(fp);
+ ret = __sferror(fp);
+ FUNLOCKFILE(fp);
+ return (ret);
+}
diff --git a/lib/libc/stdio/fflush.3 b/lib/libc/stdio/fflush.3
new file mode 100644
index 0000000..6fa6d23
--- /dev/null
+++ b/lib/libc/stdio/fflush.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 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. 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.
+.\"
+.\" @(#)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 0000000..3090dc9
--- /dev/null
+++ b/lib/libc/stdio/fflush.c
@@ -0,0 +1,145 @@
+/*-
+ * 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. 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.
+ */
+
+#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 reading. 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.
+ */
+ if ((fp->_flags & (__SWR | __SRW)) == 0) {
+ errno = EBADF;
+ retval = EOF;
+ } 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) {
+ errno = EBADF;
+ retval = EOF;
+ } 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) {
+ 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 0000000..455c2ac
--- /dev/null
+++ b/lib/libc/stdio/fgetc.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. 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.
+ */
+
+#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(fp)
+ 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 0000000..59156ef
--- /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.
+.\" 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.
+.\"
+.\" @(#)fgetln.3 8.3 (Berkeley) 4/19/94
+.\" $FreeBSD$
+.\"
+.Dd April 19, 1994
+.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.
+.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 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 0000000..d2efe09
--- /dev/null
+++ b/lib/libc/stdio/fgetln.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. 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.
+ */
+
+#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 <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 ((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
+ * accomodate 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))
+ break; /* EOF or error: return partial line */
+ 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; /* ??? */
+ FUNLOCKFILE(fp);
+ return (NULL); /* ??? */
+}
diff --git a/lib/libc/stdio/fgetpos.c b/lib/libc/stdio/fgetpos.c
new file mode 100644
index 0000000..295b20a
--- /dev/null
+++ b/lib/libc/stdio/fgetpos.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. 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.
+ */
+
+#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 0000000..06e3c04
--- /dev/null
+++ b/lib/libc/stdio/fgets.3
@@ -0,0 +1,161 @@
+.\" 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. 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.
+.\"
+.\" @(#)fgets.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.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 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.
+(See
+the FSA.)
+.Sh SEE ALSO
+.Xr feof 3 ,
+.Xr ferror 3 ,
+.Xr fgetln 3 ,
+.Xr fgetws 3
+.Sh STANDARDS
+The functions
+.Fn fgets
+and
+.Fn gets
+conform to
+.St -isoC-99 .
diff --git a/lib/libc/stdio/fgets.c b/lib/libc/stdio/fgets.c
new file mode 100644
index 0000000..bb4ea4c
--- /dev/null
+++ b/lib/libc/stdio/fgets.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. 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.
+ */
+
+#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 <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(buf, n, fp)
+ char *buf;
+ int n;
+ FILE *fp;
+{
+ size_t len;
+ char *s;
+ unsigned char *p, *t;
+
+ if (n <= 0) /* sanity check */
+ return (NULL);
+
+ FLOCKFILE(fp);
+ ORIENT(fp, -1);
+ 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 (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 0000000..719556a
--- /dev/null
+++ b/lib/libc/stdio/fgetwc.c
@@ -0,0 +1,96 @@
+/*-
+ * 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.
+ */
+
+#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"
+
+/*
+ * MT-safe version.
+ */
+wint_t
+fgetwc(FILE *fp)
+{
+ wint_t r;
+
+ FLOCKFILE(fp);
+ ORIENT(fp, 1);
+ r = __fgetwc(fp);
+ FUNLOCKFILE(fp);
+
+ return (r);
+}
+
+/*
+ * Non-MT-safe version.
+ */
+wint_t
+__fgetwc(FILE *fp)
+{
+ wchar_t wc;
+ size_t nconv;
+
+ if (fp->_r <= 0 && __srefill(fp))
+ return (WEOF);
+ if (MB_CUR_MAX == 1) {
+ /* Fast path for single-byte encodings. */
+ wc = *fp->_p++;
+ fp->_r--;
+ return (wc);
+ }
+ do {
+ nconv = __mbrtowc(&wc, fp->_p, fp->_r, &fp->_extra->mbstate);
+ if (nconv == (size_t)-1)
+ break;
+ else if (nconv == (size_t)-2)
+ continue;
+ else if (nconv == 0) {
+ /*
+ * Assume that the only valid representation of
+ * the null wide character is a single null byte.
+ */
+ fp->_p++;
+ fp->_r--;
+ return (L'\0');
+ } else {
+ fp->_p += nconv;
+ fp->_r -= nconv;
+ return (wc);
+ }
+ } while (__srefill(fp) == 0);
+ 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 0000000..991b460
--- /dev/null
+++ b/lib/libc/stdio/fgetwln.3
@@ -0,0 +1,120 @@
+.\" 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. 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.
+.\"
+.\" @(#)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 0000000..1a1ad2d
--- /dev/null
+++ b/lib/libc/stdio/fgetwln.c
@@ -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.
+ */
+
+#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"
+
+wchar_t *
+fgetwln(FILE * __restrict fp, size_t *lenp)
+{
+ wint_t wc;
+ size_t len;
+
+ FLOCKFILE(fp);
+ ORIENT(fp, 1);
+
+ len = 0;
+ while ((wc = __fgetwc(fp)) != WEOF) {
+#define GROW 512
+ if (len * sizeof(wchar_t) >= fp->_lb._size &&
+ __slbexpand(fp, (len + GROW) * sizeof(wchar_t)))
+ goto error;
+ *((wchar_t *)fp->_lb._base + len++) = wc;
+ if (wc == L'\n')
+ break;
+ }
+ if (len == 0)
+ goto error;
+
+ FUNLOCKFILE(fp);
+ *lenp = len;
+ return ((wchar_t *)fp->_lb._base);
+
+error:
+ FUNLOCKFILE(fp);
+ *lenp = 0;
+ return (NULL);
+}
diff --git a/lib/libc/stdio/fgetws.3 b/lib/libc/stdio/fgetws.3
new file mode 100644
index 0000000..dc04275
--- /dev/null
+++ b/lib/libc/stdio/fgetws.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. 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.
+.\"
+.\" @(#)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 0000000..b6ef01e
--- /dev/null
+++ b/lib/libc/stdio/fgetws.c
@@ -0,0 +1,100 @@
+/*-
+ * 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.
+ */
+
+#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(wchar_t * __restrict ws, int n, FILE * __restrict fp)
+{
+ wchar_t *wsp;
+ size_t nconv;
+ const char *src;
+ unsigned char *nl;
+
+ FLOCKFILE(fp);
+ ORIENT(fp, 1);
+
+ if (n <= 0) {
+ errno = EINVAL;
+ goto error;
+ }
+
+ if (fp->_r <= 0 && __srefill(fp))
+ /* EOF */
+ goto error;
+ wsp = ws;
+ do {
+ src = fp->_p;
+ nl = memchr(fp->_p, '\n', fp->_r);
+ nconv = __mbsnrtowcs(wsp, &src,
+ nl != NULL ? (nl - fp->_p + 1) : fp->_r,
+ n - 1, &fp->_extra->mbstate);
+ if (nconv == (size_t)-1)
+ /* Conversion error */
+ 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[-1] != L'\n' && n > 1 && (fp->_r > 0 ||
+ __srefill(fp) == 0));
+ if (wsp == ws)
+ /* EOF */
+ goto error;
+ if (!__mbsinit(&fp->_extra->mbstate))
+ /* Incomplete character */
+ goto error;
+ *wsp++ = L'\0';
+ FUNLOCKFILE(fp);
+
+ return (ws);
+
+error:
+ FUNLOCKFILE(fp);
+ return (NULL);
+}
diff --git a/lib/libc/stdio/fileno.c b/lib/libc/stdio/fileno.c
new file mode 100644
index 0000000..51c0464
--- /dev/null
+++ b/lib/libc/stdio/fileno.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. 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.
+ */
+
+#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
+
+int
+fileno(FILE *fp)
+{
+ int fd;
+
+ FLOCKFILE(fp);
+ fd = __sfileno(fp);
+ FUNLOCKFILE(fp);
+
+ return (fd);
+}
diff --git a/lib/libc/stdio/findfp.c b/lib/libc/stdio/findfp.c
new file mode 100644
index 0000000..26d4dcf
--- /dev/null
+++ b/lib/libc/stdio/findfp.c
@@ -0,0 +1,249 @@
+/*-
+ * 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. 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.
+ */
+
+#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 <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) \
+ {0,0,0,flags,file,{0},0,__sF+file,__sclose,__sread,__sseek,__swrite, \
+ {0}, __sFX + file}
+ /* p r w flags file _bf z cookie close read seek write */
+ /* _ub _extra */
+ /* the usual - (stdin + stdout + stderr) */
+static FILE usual[FOPEN_MAX - 3];
+static struct __sFILEX usual_extra[FOPEN_MAX - 3];
+static struct glue uglue = { NULL, FOPEN_MAX - 3, usual };
+
+static struct __sFILEX __sFX[3];
+
+/*
+ * We can't make this 'static' until 6.0-current due to binary
+ * compatibility concerns. This also means we cannot change the
+ * sizeof(FILE) until that time either and must continue to use the
+ * __sFILEX stuff to add to FILE.
+ */
+FILE __sF[3] = {
+ std(__SRD, STDIN_FILENO),
+ std(__SWR, STDOUT_FILENO),
+ std(__SWR|__SNBF, STDERR_FILENO)
+};
+
+/*
+ * The following kludge is done to ensure enough binary compatibility
+ * with future versions of libc. Or rather it allows us to work with
+ * libraries that have been built with a newer libc that defines these
+ * symbols and expects libc to provide them. We only have need to support
+ * i386 and alpha because they are the only "old" systems we have deployed.
+ */
+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);
+
+static spinlock_t thread_lock = _SPINLOCK_INITIALIZER;
+#define THREAD_LOCK() if (__isthreaded) _SPINLOCK(&thread_lock)
+#define THREAD_UNLOCK() if (__isthreaded) _SPINUNLOCK(&thread_lock)
+
+#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(n)
+ int n;
+{
+ struct glue *g;
+ static FILE empty;
+ static struct __sFILEX emptyx;
+ FILE *p;
+ struct __sFILEX *fx;
+
+ g = (struct glue *)malloc(sizeof(*g) + ALIGNBYTES + n * sizeof(FILE) +
+ n * sizeof(struct __sFILEX));
+ if (g == NULL)
+ return (NULL);
+ p = (FILE *)ALIGN(g + 1);
+ fx = (struct __sFILEX *)&p[n];
+ g->next = NULL;
+ g->niobs = n;
+ g->iobs = p;
+ while (--n >= 0) {
+ *p = empty;
+ p->_extra = fx;
+ *p->_extra = emptyx;
+ p++, fx++;
+ }
+ return (g);
+}
+
+/*
+ * Find a free FILE for fopen et al.
+ */
+FILE *
+__sfp()
+{
+ FILE *fp;
+ int n;
+ struct glue *g;
+
+ if (!__sdidinit)
+ __sinit();
+ /*
+ * The list must be locked because a FILE may be updated.
+ */
+ 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;
+ }
+ THREAD_UNLOCK(); /* don't hold lock while malloc()ing. */
+ if ((g = moreglue(NDYNAMIC)) == NULL)
+ return (NULL);
+ 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 */
+ 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->_lock = NULL; */ /* once set always set (reused) */
+ fp->_extra->orientation = 0;
+ memset(&fp->_extra->mbstate, 0, sizeof(mbstate_t));
+ 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()
+{
+ 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)) {
+ THREAD_LOCK();
+ SET_GLUE_PTR(lastglue->next, g);
+ lastglue = g;
+ 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) _fwalk(fclose); */
+ (void) _fwalk(__sflush); /* `cheating' */
+}
+
+/*
+ * __sinit() is called whenever stdio's internal variables must be set up.
+ */
+void
+__sinit()
+{
+ int i;
+
+ THREAD_LOCK();
+ if (__sdidinit == 0) {
+ /* Set _extra for the usual suspects. */
+ for (i = 0; i < FOPEN_MAX - 3; i++)
+ usual[i]._extra = &usual_extra[i];
+
+ /* Make sure we clean up on exit. */
+ __cleanup = _cleanup; /* conservative */
+ __sdidinit = 1;
+ }
+ THREAD_UNLOCK();
+}
diff --git a/lib/libc/stdio/flags.c b/lib/libc/stdio/flags.c
new file mode 100644
index 0000000..8a1c7d0
--- /dev/null
+++ b/lib/libc/stdio/flags.c
@@ -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.
+ * 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.
+ */
+
+#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(mode, optr)
+ const char *mode;
+ int *optr;
+{
+ int ret, m, o;
+
+ 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);
+ }
+
+ /* [rwa]\+ or [rwa]b\+ means read and write */
+ if (*mode == '+' || (*mode == 'b' && mode[1] == '+')) {
+ ret = __SRW;
+ m = O_RDWR;
+ }
+ *optr = m | o;
+ return (ret);
+}
diff --git a/lib/libc/stdio/floatio.h b/lib/libc/stdio/floatio.h
new file mode 100644
index 0000000..2463a85
--- /dev/null
+++ b/lib/libc/stdio/floatio.h
@@ -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. 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.
+ *
+ * @(#)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 0000000..a895a0a
--- /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/fopen.3 b/lib/libc/stdio/fopen.3
new file mode 100644
index 0000000..e0680da
--- /dev/null
+++ b/lib/libc/stdio/fopen.3
@@ -0,0 +1,287 @@
+.\" 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. 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.
+.\"
+.\" @(#)fopen.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd January 26, 2003
+.Dt FOPEN 3
+.Os
+.Sh NAME
+.Nm fopen ,
+.Nm fdopen ,
+.Nm freopen
+.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"
+.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
+sequences (Additional characters may follow these sequences.):
+.Bl -tag -width indent
+.It Dq Li r
+Open text file for reading.
+The stream is positioned at the beginning of the file.
+.It Dq Li r+
+Open for reading and writing.
+The stream is positioned at the beginning of the file.
+.It Dq Li w
+Truncate to zero length or create text file for writing.
+The stream is positioned at the beginning of the file.
+.It Dq Li w+
+Open for reading and writing.
+The file is created if it does not exist, otherwise it is truncated.
+The stream is positioned at the beginning of the file.
+.It Dq Li a
+Open for writing.
+The file is created if it does not exist.
+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.
+.It Dq Li a+
+Open for reading and writing.
+The file is created if it does not exist.
+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.
+.El
+.Pp
+The
+.Fa mode
+string can also include the letter ``b'' either as a third character or
+as a character between the characters in any of the two-character strings
+described above.
+This is strictly for compatibility with
+.St -isoC
+and has no effect; the ``b'' is ignored.
+.Pp
+Any created files will have mode
+.Pf \\*q Dv S_IRUSR
+\&|
+.Dv S_IWUSR
+\&|
+.Dv S_IRGRP
+\&|
+.Dv S_IWGRP
+\&|
+.Dv S_IROTH
+\&|
+.Dv S_IWOTH Ns \\*q
+.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.
+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:
+.Bl -bullet -offset indent
+.It
+Streams originally opened with mode
+.Dq Li r
+can only be reopened with that same mode.
+.It
+Streams originally opened with mode
+.Dq Li a
+can be reopened with the same mode, or mode
+.Dq Li w .
+.It
+Streams originally opened with mode
+.Dq Li w
+can be reopened with the same mode, or mode
+.Dq Li a .
+.It
+Streams originally opened with mode
+.Dq Li r+ ,
+.Dq Li w+ ,
+or
+.Dq Li a+
+can be reopened with any mode.
+.El
+.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 ) .
+.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 ,
+or
+.Fn freopen
+was invalid.
+.El
+.Pp
+The
+.Fn fopen ,
+.Fn fdopen
+and
+.Fn freopen
+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 .
+.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 .
+The
+.Fn fdopen
+function
+conforms to
+.St -p1003.1-88 .
diff --git a/lib/libc/stdio/fopen.c b/lib/libc/stdio/fopen.c
new file mode 100644
index 0000000..b7c84a7
--- /dev/null
+++ b/lib/libc/stdio/fopen.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.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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.
+ */
+
+#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 <stdio.h>
+#include <errno.h>
+#include "un-namespace.h"
+
+#include "local.h"
+
+FILE *
+fopen(file, mode)
+ 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);
+ }
+ 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)
+ (void)_sseek(fp, (fpos_t)0, SEEK_END);
+ return (fp);
+}
diff --git a/lib/libc/stdio/fprintf.c b/lib/libc/stdio/fprintf.c
new file mode 100644
index 0000000..27b8222
--- /dev/null
+++ b/lib/libc/stdio/fprintf.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. 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.
+ */
+
+#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>
+
+int
+fprintf(FILE * __restrict fp, const char * __restrict fmt, ...)
+{
+ int ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ret = vfprintf(fp, 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 0000000..b653bc5
--- /dev/null
+++ b/lib/libc/stdio/fpurge.c
@@ -0,0 +1,74 @@
+/*-
+ * 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. 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.
+ */
+
+#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(fp)
+ 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) ? 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 0000000..97de1c0
--- /dev/null
+++ b/lib/libc/stdio/fputc.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. 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.
+ */
+
+#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(c, fp)
+ 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 0000000..3ce20b2
--- /dev/null
+++ b/lib/libc/stdio/fputs.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. 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.
+.\"
+.\" @(#)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
+.Fn fputs
+function
+returns 0 on success and
+.Dv EOF
+on error;
+.Fn puts
+returns 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 0000000..812c37d
--- /dev/null
+++ b/lib/libc/stdio/fputs.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.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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.
+ */
+
+#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 <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(s, fp)
+ const char * __restrict s;
+ FILE * __restrict fp;
+{
+ int retval;
+ struct __suio uio;
+ struct __siov iov;
+
+ iov.iov_base = (void *)s;
+ iov.iov_len = uio.uio_resid = strlen(s);
+ uio.uio_iov = &iov;
+ uio.uio_iovcnt = 1;
+ FLOCKFILE(fp);
+ ORIENT(fp, -1);
+ retval = __sfvwrite(fp, &uio);
+ FUNLOCKFILE(fp);
+ return (retval);
+}
diff --git a/lib/libc/stdio/fputwc.c b/lib/libc/stdio/fputwc.c
new file mode 100644
index 0000000..0848b74
--- /dev/null
+++ b/lib/libc/stdio/fputwc.c
@@ -0,0 +1,87 @@
+/*-
+ * 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.
+ */
+
+#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)
+{
+ char buf[MB_LEN_MAX];
+ size_t i, len;
+
+ if (MB_CUR_MAX == 1 && wc > 0 && wc <= UCHAR_MAX) {
+ /*
+ * Assume single-byte locale with no special encoding.
+ * A more careful test would be to check
+ * _CurrentRuneLocale->encoding.
+ */
+ *buf = (unsigned char)wc;
+ len = 1;
+ } else {
+ if ((len = __wcrtomb(buf, wc, &fp->_extra->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(wchar_t wc, FILE *fp)
+{
+ wint_t r;
+
+ FLOCKFILE(fp);
+ ORIENT(fp, 1);
+ r = __fputwc(wc, fp);
+ FUNLOCKFILE(fp);
+
+ return (r);
+}
diff --git a/lib/libc/stdio/fputws.3 b/lib/libc/stdio/fputws.3
new file mode 100644
index 0000000..52bae96
--- /dev/null
+++ b/lib/libc/stdio/fputws.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. 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.
+.\"
+.\" @(#)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 0000000..025e1c0
--- /dev/null
+++ b/lib/libc/stdio/fputws.c
@@ -0,0 +1,71 @@
+/*-
+ * 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.
+ */
+
+#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(const wchar_t * __restrict ws, FILE * __restrict fp)
+{
+ size_t nbytes;
+ char buf[BUFSIZ];
+ struct __suio uio;
+ struct __siov iov;
+
+ FLOCKFILE(fp);
+ ORIENT(fp, 1);
+ if (prepwrite(fp) != 0)
+ goto error;
+ uio.uio_iov = &iov;
+ uio.uio_iovcnt = 1;
+ iov.iov_base = buf;
+ do {
+ nbytes = __wcsnrtombs(buf, &ws, SIZE_T_MAX, sizeof(buf),
+ &fp->_extra->mbstate);
+ if (nbytes == (size_t)-1)
+ goto error;
+ iov.iov_len = uio.uio_resid = nbytes;
+ if (__sfvwrite(fp, &uio) != 0)
+ goto error;
+ } while (ws != NULL);
+ FUNLOCKFILE(fp);
+ return (0);
+
+error:
+ FUNLOCKFILE(fp);
+ return (-1);
+}
diff --git a/lib/libc/stdio/fread.3 b/lib/libc/stdio/fread.3
new file mode 100644
index 0000000..925ef61
--- /dev/null
+++ b/lib/libc/stdio/fread.3
@@ -0,0 +1,109 @@
+.\" 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. 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.
+.\"
+.\" @(#)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 0000000..3edb84a
--- /dev/null
+++ b/lib/libc/stdio/fread.c
@@ -0,0 +1,100 @@
+/*-
+ * 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. 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.
+ */
+
+#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 <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)
+{
+ int 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;
+
+ /*
+ * The ANSI standard requires a return value of 0 for a count
+ * or a size of 0. Peculiarily, it imposes no such requirements
+ * on fwrite; it only requires fread to be broken.
+ */
+ if ((resid = count * size) == 0)
+ return (0);
+ 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 0000000..476f3ef
--- /dev/null
+++ b/lib/libc/stdio/freopen.c
@@ -0,0 +1,221 @@
+/*-
+ * 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. 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.
+ */
+
+#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 <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(file, mode, fp)
+ const char * __restrict file;
+ const char * __restrict mode;
+ FILE *fp;
+{
+ int f;
+ int dflags, flags, isopen, oflags, sverrno, wantfd;
+
+ if ((flags = __sflags(mode, &oflags)) == 0) {
+ (void) fclose(fp);
+ 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);
+ }
+ if ((dflags & O_ACCMODE) != O_RDWR && (dflags & O_ACCMODE) !=
+ (oflags & O_ACCMODE)) {
+ fclose(fp);
+ FUNLOCKFILE(fp);
+ errno = EINVAL;
+ return (NULL);
+ }
+ 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)
+ ftruncate(fp->_file, 0);
+ if (_fseeko(fp, 0, oflags & O_APPEND ? SEEK_END : SEEK_SET,
+ 0) < 0 && errno != ESPIPE) {
+ sverrno = errno;
+ fclose(fp);
+ FUNLOCKFILE(fp);
+ errno = sverrno;
+ return (NULL);
+ }
+ 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 (f < 0 && isopen) {
+ /* If out of fd's close the old one and try again. */
+ if (errno == ENFILE || errno == EMFILE) {
+ (void) (*fp->_close)(fp->_cookie);
+ isopen = 0;
+ 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.
+ */
+ if (isopen)
+ (void) (*fp->_close)(fp->_cookie);
+ 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->_extra->orientation = 0;
+ memset(&fp->_extra->mbstate, 0, sizeof(mbstate_t));
+
+ if (f < 0) { /* did not get it after all */
+ fp->_flags = 0; /* set it free */
+ errno = sverrno; /* restore in case _close clobbered */
+ FUNLOCKFILE(fp);
+ 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 && f != wantfd) {
+ if (_dup2(f, wantfd) >= 0) {
+ (void)_close(f);
+ f = wantfd;
+ }
+ }
+
+ fp->_flags = flags;
+ fp->_file = f;
+ fp->_cookie = fp;
+ fp->_read = __sread;
+ fp->_write = __swrite;
+ fp->_seek = __sseek;
+ fp->_close = __sclose;
+ FUNLOCKFILE(fp);
+ return (fp);
+}
diff --git a/lib/libc/stdio/fscanf.c b/lib/libc/stdio/fscanf.c
new file mode 100644
index 0000000..bb5ee4c
--- /dev/null
+++ b/lib/libc/stdio/fscanf.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. 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.
+ */
+
+#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"
+
+int
+fscanf(FILE * __restrict fp, char const * __restrict fmt, ...)
+{
+ int ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ FLOCKFILE(fp);
+ ret = __svfscanf(fp, 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 0000000..96abc0a
--- /dev/null
+++ b/lib/libc/stdio/fseek.3
@@ -0,0 +1,272 @@
+.\" 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. 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.
+.\"
+.\" @(#)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 ,
+and
+.Fn ftello
+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 0000000..b346b5d
--- /dev/null
+++ b/lib/libc/stdio/fseek.c
@@ -0,0 +1,314 @@
+/*-
+ * 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. 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.
+ */
+
+#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(fp, offset, whence)
+ 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(fp, offset, whence)
+ 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(fp, offset, whence, ltest)
+ 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->_extra->_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->_extra->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;
+ 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);
+ /* 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->_extra->mbstate, 0, sizeof(mbstate_t));
+ if (ltest && ret > LONG_MAX) {
+ fp->_flags |= __SERR;
+ errno = EOVERFLOW;
+ return (-1);
+ }
+ return (0);
+}
diff --git a/lib/libc/stdio/fsetpos.c b/lib/libc/stdio/fsetpos.c
new file mode 100644
index 0000000..6eeffda
--- /dev/null
+++ b/lib/libc/stdio/fsetpos.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. 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.
+ */
+
+#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(iop, pos)
+ 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 0000000..94e962c
--- /dev/null
+++ b/lib/libc/stdio/ftell.c
@@ -0,0 +1,143 @@
+/*-
+ * 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. 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.
+ */
+
+#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(fp)
+ 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(fp)
+ 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(fp, offset)
+ 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 & __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) {
+ /*
+ * Writing. Any buffered characters cause the
+ * position to be greater than that in the
+ * underlying object.
+ */
+ n = fp->_p - fp->_bf._base;
+ 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 0000000..80ce999
--- /dev/null
+++ b/lib/libc/stdio/funopen.3
@@ -0,0 +1,180 @@
+.\" 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. 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.
+.\"
+.\" @(#)funopen.3 8.1 (Berkeley) 6/9/93
+.\" $FreeBSD$
+.\"
+.Dd March 19, 2004
+.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 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 0000000..459cd5c
--- /dev/null
+++ b/lib/libc/stdio/funopen.c
@@ -0,0 +1,80 @@
+/*-
+ * 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. 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.
+ */
+
+#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(cookie, readfn, writefn, seekfn, closefn)
+ const void *cookie;
+ int (*readfn)(), (*writefn)();
+ fpos_t (*seekfn)(void *cookie, fpos_t off, int whence);
+ int (*closefn)();
+{
+ 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 0000000..9cc4c55
--- /dev/null
+++ b/lib/libc/stdio/fvwrite.c
@@ -0,0 +1,211 @@
+/*-
+ * 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. 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.
+ */
+
+#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(fp, uio)
+ FILE *fp;
+ struct __suio *uio;
+{
+ size_t len;
+ char *p;
+ struct __siov *iov;
+ int w, s;
+ char *nl;
+ int nlknown, nldist;
+
+ if ((len = 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 0000000..df59bf0
--- /dev/null
+++ b/lib/libc/stdio/fvwrite.h
@@ -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. 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.
+ *
+ * @(#)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 0000000..811fb54
--- /dev/null
+++ b/lib/libc/stdio/fwalk.c
@@ -0,0 +1,71 @@
+/*-
+ * 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. 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.
+ */
+
+#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 <machine/atomic.h>
+#include <stdio.h>
+#include "local.h"
+#include "glue.h"
+
+int
+_fwalk(function)
+ 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 0000000..6ff8d92
--- /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 0000000..70309f5
--- /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->_extra->orientation == 0)
+ fp->_extra->orientation = mode > 0 ? 1 : -1;
+ m = fp->_extra->orientation;
+ FUNLOCKFILE(fp);
+
+ return (m);
+}
diff --git a/lib/libc/stdio/fwprintf.c b/lib/libc/stdio/fwprintf.c
new file mode 100644
index 0000000..a22edae
--- /dev/null
+++ b/lib/libc/stdio/fwprintf.c
@@ -0,0 +1,45 @@
+/*-
+ * 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 <stdarg.h>
+#include <stdio.h>
+#include <wchar.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);
+}
diff --git a/lib/libc/stdio/fwrite.c b/lib/libc/stdio/fwrite.c
new file mode 100644
index 0000000..0a74d81
--- /dev/null
+++ b/lib/libc/stdio/fwrite.c
@@ -0,0 +1,80 @@
+/*-
+ * 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. 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.
+ */
+
+#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 <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(buf, size, count, fp)
+ const void * __restrict buf;
+ size_t size, count;
+ FILE * __restrict fp;
+{
+ size_t n;
+ struct __suio uio;
+ struct __siov iov;
+
+ iov.iov_base = (void *)buf;
+ uio.uio_resid = iov.iov_len = n = count * size;
+ 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 0000000..f779c53
--- /dev/null
+++ b/lib/libc/stdio/fwscanf.c
@@ -0,0 +1,45 @@
+/*-
+ * 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 <stdarg.h>
+#include <stdio.h>
+#include <wchar.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);
+}
diff --git a/lib/libc/stdio/getc.3 b/lib/libc/stdio/getc.3
new file mode 100644
index 0000000..25c9be4
--- /dev/null
+++ b/lib/libc/stdio/getc.3
@@ -0,0 +1,174 @@
+.\" 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. 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.
+.\"
+.\" @(#)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.
+.Pp
diff --git a/lib/libc/stdio/getc.c b/lib/libc/stdio/getc.c
new file mode 100644
index 0000000..61b2c54
--- /dev/null
+++ b/lib/libc/stdio/getc.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. 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.
+ */
+
+#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
+
+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);
+}
diff --git a/lib/libc/stdio/getchar.c b/lib/libc/stdio/getchar.c
new file mode 100644
index 0000000..baf5876
--- /dev/null
+++ b/lib/libc/stdio/getchar.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. 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.
+ */
+
+#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
+
+int
+getchar()
+{
+ int retval;
+ FLOCKFILE(stdin);
+ /* Orientation set by __sgetc() when buffer is empty. */
+ /* ORIENT(stdin, -1); */
+ retval = __sgetc(stdin);
+ FUNLOCKFILE(stdin);
+ return (retval);
+}
diff --git a/lib/libc/stdio/gets.c b/lib/libc/stdio/gets.c
new file mode 100644
index 0000000..e247271
--- /dev/null
+++ b/lib/libc/stdio/gets.c
@@ -0,0 +1,81 @@
+/*-
+ * 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. 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.
+ */
+
+#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(buf)
+ char *buf;
+{
+ int c;
+ char *s;
+ static int warned;
+ static 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 0000000..e748235
--- /dev/null
+++ b/lib/libc/stdio/getw.c
@@ -0,0 +1,52 @@
+/*-
+ * 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. 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.
+ */
+
+#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(fp)
+ 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 0000000..4939ad1
--- /dev/null
+++ b/lib/libc/stdio/getwc.3
@@ -0,0 +1,118 @@
+.\" $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.
+.\" 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.
+.\"
+.\" @(#)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 0000000..ba5ab60
--- /dev/null
+++ b/lib/libc/stdio/getwc.c
@@ -0,0 +1,48 @@
+/*-
+ * 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 <stdio.h>
+#include <wchar.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));
+}
diff --git a/lib/libc/stdio/getwchar.c b/lib/libc/stdio/getwchar.c
new file mode 100644
index 0000000..79dd7bc
--- /dev/null
+++ b/lib/libc/stdio/getwchar.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 "namespace.h"
+#include <stdio.h>
+#include <wchar.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));
+}
diff --git a/lib/libc/stdio/glue.h b/lib/libc/stdio/glue.h
new file mode 100644
index 0000000..a6df6fd
--- /dev/null
+++ b/lib/libc/stdio/glue.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.
+ * 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.
+ *
+ * @(#)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 0000000..7d5f79a
--- /dev/null
+++ b/lib/libc/stdio/local.h
@@ -0,0 +1,142 @@
+/*-
+ * 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. 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.
+ *
+ * @(#)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>
+
+/*
+ * 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(FILE *);
+extern wint_t __fputwc(wchar_t, FILE *);
+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 *, 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 *);
+extern int __vfprintf(FILE *, const char *, __va_list);
+extern int __vfscanf(FILE *, const char *, __va_list);
+extern int __vfwprintf(FILE *, const wchar_t *, __va_list);
+extern int __vfwscanf(FILE * __restrict, 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;
+
+
+/* hold a buncha junk that would grow the ABI */
+struct __sFILEX {
+ unsigned char *_up; /* saved _p when _p is doing ungetc data */
+ pthread_mutex_t fl_mutex; /* used for MT-safety */
+ pthread_t fl_owner; /* current owner */
+ int fl_count; /* recursive lock count */
+ int orientation; /* orientation for fwide() */
+ mbstate_t mbstate; /* multibyte conversion state */
+};
+
+/*
+ * 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; \
+}
+
+#define INITEXTRA(fp) { \
+ (fp)->_extra->_up = NULL; \
+ (fp)->_extra->fl_mutex = PTHREAD_MUTEX_INITIALIZER; \
+ (fp)->_extra->fl_owner = NULL; \
+ (fp)->_extra->fl_count = 0; \
+ (fp)->_extra->orientation = 0; \
+ memset(&(fp)->_extra->mbstate, 0, sizeof(mbstate_t)); \
+}
+
+/*
+ * 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)->_extra->orientation == 0) \
+ (fp)->_extra->orientation = (o); \
+} while (0)
diff --git a/lib/libc/stdio/makebuf.c b/lib/libc/stdio/makebuf.c
new file mode 100644
index 0000000..bdade67
--- /dev/null
+++ b/lib/libc/stdio/makebuf.c
@@ -0,0 +1,124 @@
+/*-
+ * 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. 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.
+ */
+
+#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(fp)
+ 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(fp, bufsize, couldbetty)
+ 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 0000000..43cef21
--- /dev/null
+++ b/lib/libc/stdio/mktemp.3
@@ -0,0 +1,255 @@
+.\" Copyright (c) 1989, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. 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.
+.\"
+.\" @(#)mktemp.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd February 11, 1998
+.Dt MKTEMP 3
+.Os
+.Sh NAME
+.Nm mktemp
+.Nd make temporary file name (unique)
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft char *
+.Fn mktemp "char *template"
+.Ft int
+.Fn mkstemp "char *template"
+.Ft int
+.Fn mkstemps "char *template" "int suffixlen"
+.Ft char *
+.Fn mkdtemp "char *template"
+.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 mkstemps
+function acts the same as
+.Fn mkstemp ,
+except it permits a suffix to exist in the template.
+The template should be of the form
+.Pa /tmp/tmpXXXXXXsuffix .
+The
+.Fn mkstemps
+function
+is 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
+and
+.Fn mkstemps
+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 mkstemps
+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 mkstemp ,
+.Fn mkstemps
+and
+.Fn mkdtemp
+functions
+may also set
+.Va errno
+to any value specified by the
+.Xr stat 2
+function.
+.Pp
+The
+.Fn mkstemp
+and
+.Fn mkstemps
+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.
+If the program in question makes heavy use of that type
+of function call, you do have the option of compiling the program
+so that it will store string constants in a writable segment of memory.
+See
+.Xr gcc 1
+for more information.
+.Sh SEE ALSO
+.Xr chmod 2 ,
+.Xr getpid 2 ,
+.Xr mkdir 2 ,
+.Xr open 2 ,
+.Xr stat 2
+.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 .
+.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
+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.
+.Pp
+The implementation of these functions calls
+.Xr arc4random 3 ,
+which is not reentrant.
+You must provide your own locking around this and other consumers of the
+.Xr arc4random 3
+API.
diff --git a/lib/libc/stdio/mktemp.c b/lib/libc/stdio/mktemp.c
new file mode 100644
index 0000000..3bfad9d
--- /dev/null
+++ b/lib/libc/stdio/mktemp.c
@@ -0,0 +1,186 @@
+/*
+ * 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. 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.
+ */
+
+#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/types.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);
+
+static const unsigned char padchar[] =
+"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+int
+mkstemps(path, slen)
+ char *path;
+ int slen;
+{
+ int fd;
+
+ return (_gettemp(path, &fd, 0, slen) ? fd : -1);
+}
+
+int
+mkstemp(path)
+ char *path;
+{
+ int fd;
+
+ return (_gettemp(path, &fd, 0, 0) ? fd : -1);
+}
+
+char *
+mkdtemp(path)
+ char *path;
+{
+ return (_gettemp(path, (int *)NULL, 1, 0) ? path : (char *)NULL);
+}
+
+char *
+_mktemp(path)
+ char *path;
+{
+ return (_gettemp(path, (int *)NULL, 0, 0) ? path : (char *)NULL);
+}
+
+__warn_references(mktemp,
+ "warning: mktemp() possibly used unsafely; consider using mkstemp()");
+
+char *
+mktemp(path)
+ char *path;
+{
+ return (_mktemp(path));
+}
+
+static int
+_gettemp(path, doopen, domkdir, slen)
+ char *path;
+ int *doopen;
+ int domkdir;
+ int slen;
+{
+ char *start, *trv, *suffp;
+ char *pad;
+ struct stat sbuf;
+ int rval;
+ uint32_t rand;
+
+ if (doopen != NULL && domkdir) {
+ errno = EINVAL;
+ return (0);
+ }
+
+ for (trv = path; *trv != '\0'; ++trv)
+ ;
+ trv -= slen;
+ suffp = trv;
+ --trv;
+ if (trv < path) {
+ errno = EINVAL;
+ return (0);
+ }
+
+ /* Fill space with random characters */
+ while (trv >= path && *trv == 'X') {
+ rand = arc4random() % (sizeof(padchar) - 1);
+ *trv-- = padchar[rand];
+ }
+ start = trv + 1;
+
+ /*
+ * 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, 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;;) {
+ if (*trv == '\0' || trv == suffp)
+ return (0);
+ pad = strchr(padchar, *trv);
+ if (pad == NULL || *++pad == '\0')
+ *trv++ = padchar[0];
+ else {
+ *trv++ = *pad;
+ break;
+ }
+ }
+ }
+ /*NOTREACHED*/
+}
diff --git a/lib/libc/stdio/perror.c b/lib/libc/stdio/perror.c
new file mode 100644
index 0000000..29016f7
--- /dev/null
+++ b/lib/libc/stdio/perror.c
@@ -0,0 +1,80 @@
+/*
+ * 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. 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.
+ */
+
+#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(s)
+ 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.3 b/lib/libc/stdio/printf.3
new file mode 100644
index 0000000..feb6559
--- /dev/null
+++ b/lib/libc/stdio/printf.3
@@ -0,0 +1,863 @@
+.\" 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. 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.
+.\"
+.\" @(#)printf.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd October 16, 2004
+.Dt PRINTF 3
+.Os
+.Sh NAME
+.Nm printf , fprintf , sprintf , snprintf , asprintf ,
+.Nm vprintf , vfprintf, vsprintf , vsnprintf , vasprintf
+.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" ...
+.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"
+.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 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
+These functions return the number of characters printed
+(not including the trailing
+.Ql \e0
+used to end output to strings) or a negative value if an output error occurs,
+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 ) .
+.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.
+.Pp
+The
+.Fn sprintf
+and
+.Fn vsprintf
+functions
+effectively assume an infinite
+.Fa size .
+.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 (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 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 \\*[Pm] 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 \\*[Pm] 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 0x3.24p+0 , 0x6.48p-1
+and
+.Li 0xc.9p-2
+are all equivalent.
+The format chosen depends on the internal representation of the
+number, but the implementation guarantees that the length of the
+mantissa will be minimized.
+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 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 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);"
+.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.
+.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 .
+.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 peter@FreeBSD.org
+in
+.Fx 2.2 ,
+but were later replaced with a different implementation
+from
+.An Todd C. Miller Aq Todd.Miller@courtesan.com
+for
+.Ox 2.3 .
+.Sh BUGS
+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.
+.Pp
+The
+.Nm
+family of functions do not correctly handle multibyte characters in the
+.Fa format
+argument.
diff --git a/lib/libc/stdio/printf.c b/lib/libc/stdio/printf.c
new file mode 100644
index 0000000..cfd10d0
--- /dev/null
+++ b/lib/libc/stdio/printf.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. 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.
+ */
+
+#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>
+
+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);
+}
diff --git a/lib/libc/stdio/putc.3 b/lib/libc/stdio/putc.3
new file mode 100644
index 0000000..e149630
--- /dev/null
+++ b/lib/libc/stdio/putc.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.
+.\" 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.
+.\"
+.\" @(#)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 0000000..864df9f
--- /dev/null
+++ b/lib/libc/stdio/putc.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. 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.
+ */
+
+#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
+
+int
+putc(c, fp)
+ 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/putchar.c b/lib/libc/stdio/putchar.c
new file mode 100644
index 0000000..ead5565
--- /dev/null
+++ b/lib/libc/stdio/putchar.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.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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.
+ */
+
+#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
+
+/*
+ * A subroutine version of the macro putchar
+ */
+int
+putchar(c)
+ 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);
+}
diff --git a/lib/libc/stdio/puts.c b/lib/libc/stdio/puts.c
new file mode 100644
index 0000000..3e7c495
--- /dev/null
+++ b/lib/libc/stdio/puts.c
@@ -0,0 +1,75 @@
+/*-
+ * 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. 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.
+ */
+
+#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(s)
+ char const *s;
+{
+ int retval;
+ size_t c = strlen(s);
+ struct __suio uio;
+ struct __siov iov[2];
+
+ iov[0].iov_base = (void *)s;
+ iov[0].iov_len = c;
+ 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 0000000..717b148
--- /dev/null
+++ b/lib/libc/stdio/putw.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
+ * 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. 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.
+ */
+
+#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(w, fp)
+ int w;
+ FILE *fp;
+{
+ int retval;
+ struct __suio uio;
+ struct __siov iov;
+
+ iov.iov_base = &w;
+ iov.iov_len = uio.uio_resid = 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 0000000..4e46834
--- /dev/null
+++ b/lib/libc/stdio/putwc.3
@@ -0,0 +1,107 @@
+.\" $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.
+.\" 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.
+.\"
+.\" @(#)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 0000000..8fe065b
--- /dev/null
+++ b/lib/libc/stdio/putwc.c
@@ -0,0 +1,48 @@
+/*-
+ * 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 <stdio.h>
+#include <wchar.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+#include "local.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(wchar_t wc, FILE *fp)
+{
+
+ return (fputwc(wc, fp));
+}
diff --git a/lib/libc/stdio/putwchar.c b/lib/libc/stdio/putwchar.c
new file mode 100644
index 0000000..5503071
--- /dev/null
+++ b/lib/libc/stdio/putwchar.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 "namespace.h"
+#include <stdio.h>
+#include <wchar.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+#include "local.h"
+
+#undef putwchar
+
+/*
+ * Synonym for fputwc(wc, stdout).
+ */
+wint_t
+putwchar(wchar_t wc)
+{
+
+ return (fputwc(wc, stdout));
+}
diff --git a/lib/libc/stdio/refill.c b/lib/libc/stdio/refill.c
new file mode 100644
index 0000000..b76bb70
--- /dev/null
+++ b/lib/libc/stdio/refill.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. 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.
+ */
+
+#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->_extra->_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 0000000..cf088c7
--- /dev/null
+++ b/lib/libc/stdio/remove.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
+.\" 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. 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.
+.\"
+.\" @(#)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 0000000..b17124c
--- /dev/null
+++ b/lib/libc/stdio/remove.c
@@ -0,0 +1,59 @@
+/*-
+ * 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. 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.
+ */
+
+#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(file)
+ 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 0000000..a9b91db
--- /dev/null
+++ b/lib/libc/stdio/rewind.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. 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.
+ */
+
+#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) {
+ clearerr_unlocked(fp);
+ errno = serrno;
+ }
+ FUNLOCKFILE(fp);
+}
diff --git a/lib/libc/stdio/rget.c b/lib/libc/stdio/rget.c
new file mode 100644
index 0000000..9a0bd97
--- /dev/null
+++ b/lib/libc/stdio/rget.c
@@ -0,0 +1,59 @@
+/*-
+ * 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. 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.
+ */
+
+#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 0000000..4b74826
--- /dev/null
+++ b/lib/libc/stdio/scanf.3
@@ -0,0 +1,517 @@
+.\" 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. 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.
+.\"
+.\" @(#)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 0000000..37236cd
--- /dev/null
+++ b/lib/libc/stdio/scanf.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. 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.
+ */
+
+#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"
+
+int
+scanf(char const * __restrict fmt, ...)
+{
+ int ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ FLOCKFILE(stdin);
+ ret = __svfscanf(stdin, fmt, ap);
+ FUNLOCKFILE(stdin);
+ va_end(ap);
+ return (ret);
+}
diff --git a/lib/libc/stdio/setbuf.3 b/lib/libc/stdio/setbuf.3
new file mode 100644
index 0000000..4dccb4a
--- /dev/null
+++ b/lib/libc/stdio/setbuf.3
@@ -0,0 +1,213 @@
+.\" 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. 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.
+.\"
+.\" @(#)setbuf.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.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.
+.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 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
+The
+.Fn setbuffer
+and
+.Fn setlinebuf
+functions are not portable to versions of
+.Bx
+before
+.Bx 4.2 .
+On
+.Bx 4.2
+and
+.Bx 4.3
+systems,
+.Fn setbuf
+always 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 0000000..348104c
--- /dev/null
+++ b/lib/libc/stdio/setbuf.c
@@ -0,0 +1,50 @@
+/*-
+ * 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. 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.
+ */
+
+#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 0000000..ec77917
--- /dev/null
+++ b/lib/libc/stdio/setbuffer.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. 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.
+ */
+
+#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(fp, buf, size)
+ FILE *fp;
+ char *buf;
+ int size;
+{
+
+ (void)setvbuf(fp, buf, buf ? _IOFBF : _IONBF, (size_t)size);
+}
+
+/*
+ * set line buffering
+ */
+int
+setlinebuf(fp)
+ 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 0000000..7ab91e5
--- /dev/null
+++ b/lib/libc/stdio/setvbuf.c
@@ -0,0 +1,165 @@
+/*-
+ * 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. 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.
+ */
+
+#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 0000000..ee5219e
--- /dev/null
+++ b/lib/libc/stdio/snprintf.c
@@ -0,0 +1,75 @@
+/*-
+ * 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. 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.
+ */
+
+#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 <limits.h>
+#include <stdio.h>
+#include <stdarg.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;
+ struct __sFILEX ext;
+
+ on = n;
+ if (n != 0)
+ n--;
+ if (n > INT_MAX)
+ n = INT_MAX;
+ va_start(ap, fmt);
+ f._file = -1;
+ f._flags = __SWR | __SSTR;
+ f._bf._base = f._p = (unsigned char *)str;
+ f._bf._size = f._w = n;
+ f._extra = &ext;
+ INITEXTRA(&f);
+ ret = __vfprintf(&f, 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 0000000..cf1587f
--- /dev/null
+++ b/lib/libc/stdio/sprintf.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.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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.
+ */
+
+#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"
+
+int
+sprintf(char * __restrict str, char const * __restrict fmt, ...)
+{
+ int ret;
+ va_list ap;
+ FILE f;
+ struct __sFILEX ext;
+
+ f._file = -1;
+ f._flags = __SWR | __SSTR;
+ f._bf._base = f._p = (unsigned char *)str;
+ f._bf._size = f._w = INT_MAX;
+ f._extra = &ext;
+ INITEXTRA(&f);
+ va_start(ap, fmt);
+ ret = __vfprintf(&f, fmt, ap);
+ va_end(ap);
+ *f._p = 0;
+ return (ret);
+}
diff --git a/lib/libc/stdio/sscanf.c b/lib/libc/stdio/sscanf.c
new file mode 100644
index 0000000..4db0d29
--- /dev/null
+++ b/lib/libc/stdio/sscanf.c
@@ -0,0 +1,82 @@
+/*-
+ * 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. 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.
+ */
+
+#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 "local.h"
+
+static int eofread(void *, char *, int);
+
+/* ARGSUSED */
+static int
+eofread(cookie, buf, len)
+ void *cookie;
+ char *buf;
+ int len;
+{
+
+ return (0);
+}
+
+int
+sscanf(const char * __restrict str, char const * __restrict fmt, ...)
+{
+ int ret;
+ va_list ap;
+ struct __sFILEX extra;
+ FILE f;
+
+ f._file = -1;
+ f._flags = __SRD;
+ f._bf._base = f._p = (unsigned char *)str;
+ f._bf._size = f._r = strlen(str);
+ f._read = eofread;
+ f._ub._base = NULL;
+ f._lb._base = NULL;
+ f._extra = &extra;
+ INITEXTRA(&f);
+ va_start(ap, fmt);
+ ret = __svfscanf(&f, 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 0000000..e839bea
--- /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.
+.\" 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.
+.\"
+.\" @(#)stdio.3 8.7 (Berkeley) 4/19/94
+.\" $FreeBSD$
+.\"
+.Dd January 10, 2003
+.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 "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 "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 "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 0000000..daae1a2
--- /dev/null
+++ b/lib/libc/stdio/stdio.c
@@ -0,0 +1,191 @@
+/*-
+ * 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. 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.
+ */
+
+#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(cookie, buf, n)
+ void *cookie;
+ char *buf;
+ int n;
+{
+ FILE *fp = cookie;
+
+ return(_read(fp->_file, buf, (size_t)n));
+}
+
+int
+__swrite(cookie, buf, n)
+ void *cookie;
+ char const *buf;
+ int n;
+{
+ FILE *fp = cookie;
+
+ return (_write(fp->_file, buf, (size_t)n));
+}
+
+fpos_t
+__sseek(cookie, offset, whence)
+ void *cookie;
+ fpos_t offset;
+ int whence;
+{
+ FILE *fp = cookie;
+
+ return (lseek(fp->_file, (off_t)offset, whence));
+}
+
+int
+__sclose(cookie)
+ void *cookie;
+{
+
+ return (_close(((FILE *)cookie)->_file));
+}
+
+/*
+ * Higher level wrappers.
+ */
+int
+_sread(fp, buf, n)
+ 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(fp, buf, n)
+ 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 & (__SAPP|__SOFF)) == (__SAPP|__SOFF) &&
+ fp->_offset <= OFF_MAX - ret)
+ fp->_offset += ret;
+ else
+ fp->_flags &= ~__SOFF;
+
+ } else if (ret < 0)
+ fp->_flags &= ~__SOFF;
+ return (ret);
+}
+
+fpos_t
+_sseek(fp, offset, whence)
+ 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 0000000..d665318
--- /dev/null
+++ b/lib/libc/stdio/swprintf.c
@@ -0,0 +1,45 @@
+/*-
+ * 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 <stdarg.h>
+#include <stdio.h>
+#include <wchar.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);
+}
diff --git a/lib/libc/stdio/swscanf.c b/lib/libc/stdio/swscanf.c
new file mode 100644
index 0000000..728a3d6
--- /dev/null
+++ b/lib/libc/stdio/swscanf.c
@@ -0,0 +1,45 @@
+/*-
+ * 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 <stdarg.h>
+#include <stdio.h>
+#include <wchar.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);
+}
diff --git a/lib/libc/stdio/tempnam.c b/lib/libc/stdio/tempnam.c
new file mode 100644
index 0000000..8ac39ed
--- /dev/null
+++ b/lib/libc/stdio/tempnam.c
@@ -0,0 +1,94 @@
+/*
+ * 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. 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.
+ */
+
+#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(dir, pfx)
+ const char *dir, *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 0000000..22d0eb1
--- /dev/null
+++ b/lib/libc/stdio/tmpfile.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. 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.
+ */
+
+#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"
+
+FILE *
+tmpfile()
+{
+ 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)_sigprocmask(SIG_BLOCK, &set, &oset);
+
+ fd = mkstemp(buf);
+ if (fd != -1)
+ (void)unlink(buf);
+
+ free(buf);
+
+ (void)_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 0000000..4fe577c
--- /dev/null
+++ b/lib/libc/stdio/tmpnam.3
@@ -0,0 +1,239 @@
+.\" 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. 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.
+.\"
+.\" @(#)tmpnam.3 8.2 (Berkeley) 11/17/93
+.\" $FreeBSD$
+.\"
+.Dd November 17, 1993
+.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 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 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.
+(See
+the FSA.)
+.Sh SEE ALSO
+.Xr mkstemp 3 ,
+.Xr mktemp 3
+.Sh STANDARDS
+The
+.Fn tmpfile
+and
+.Fn tmpnam
+functions
+conform to
+.St -isoC .
diff --git a/lib/libc/stdio/tmpnam.c b/lib/libc/stdio/tmpnam.c
new file mode 100644
index 0000000..7c75b54
--- /dev/null
+++ b/lib/libc/stdio/tmpnam.c
@@ -0,0 +1,65 @@
+/*-
+ * 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. 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.
+ */
+
+#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(s)
+ 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 0000000..3ffab32
--- /dev/null
+++ b/lib/libc/stdio/ungetc.3
@@ -0,0 +1,102 @@
+.\" 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. 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.
+.\"
+.\" @(#)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 0000000..0113161
--- /dev/null
+++ b/lib/libc/stdio/ungetc.c
@@ -0,0 +1,172 @@
+/*-
+ * 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. 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.
+ */
+
+#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->_extra->_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 0000000..40907af
--- /dev/null
+++ b/lib/libc/stdio/ungetwc.3
@@ -0,0 +1,99 @@
+.\" $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.
+.\" 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.
+.\"
+.\" @(#)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 0000000..510648b
--- /dev/null
+++ b/lib/libc/stdio/ungetwc.c
@@ -0,0 +1,77 @@
+/*-
+ * 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.
+ */
+
+#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
+__ungetwc(wint_t wc, FILE *fp)
+{
+ char buf[MB_LEN_MAX];
+ size_t len;
+
+ if (wc == WEOF)
+ return (WEOF);
+ if ((len = __wcrtomb(buf, wc, &fp->_extra->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(wint_t wc, FILE *fp)
+{
+ wint_t r;
+
+ FLOCKFILE(fp);
+ ORIENT(fp, 1);
+ r = __ungetwc(wc, fp);
+ FUNLOCKFILE(fp);
+
+ return (r);
+}
diff --git a/lib/libc/stdio/unlocked.c b/lib/libc/stdio/unlocked.c
new file mode 100644
index 0000000..083d26f
--- /dev/null
+++ b/lib/libc/stdio/unlocked.c
@@ -0,0 +1,94 @@
+/*-
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+
+#undef getchar_unlocked
+int
+getchar_unlocked(void)
+{
+
+ return (__sgetc(stdin));
+}
+
+#undef getc_unlocked
+int
+getc_unlocked(FILE *fp)
+{
+
+ return (__sgetc(fp));
+}
+
+#undef putchar_unlocked
+int
+putchar_unlocked(int ch)
+{
+
+ return (__sputc(ch, stdout));
+}
+
+#undef putc_unlocked
+int
+putc_unlocked(int ch, FILE *fp)
+{
+
+ return (__sputc(ch, fp));
+}
+
+#undef feof_unlocked
+int
+feof_unlocked(FILE *fp)
+{
+
+ return (__sfeof(fp));
+}
+
+#undef ferror_unlocked
+int
+ferror_unlocked(FILE *fp)
+{
+
+ return (__sferror(fp));
+}
+
+#undef clearerr_unlocked
+void
+clearerr_unlocked(FILE *fp)
+{
+
+ __sclearerr(fp);
+}
+
+#undef fileno_unlocked
+int
+fileno_unlocked(FILE *fp)
+{
+
+ return (__sfileno(fp));
+}
diff --git a/lib/libc/stdio/vasprintf.c b/lib/libc/stdio/vasprintf.c
new file mode 100644
index 0000000..01ac068
--- /dev/null
+++ b/lib/libc/stdio/vasprintf.c
@@ -0,0 +1,69 @@
+/* $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.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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 "local.h"
+
+int
+vasprintf(str, fmt, ap)
+ char **str;
+ const char *fmt;
+ __va_list ap;
+{
+ int ret;
+ FILE f;
+ struct __sFILEX ext;
+
+ f._file = -1;
+ f._flags = __SWR | __SSTR | __SALC;
+ f._bf._base = f._p = (unsigned char *)malloc(128);
+ if (f._bf._base == NULL) {
+ *str = NULL;
+ errno = ENOMEM;
+ return (-1);
+ }
+ f._bf._size = f._w = 127; /* Leave room for the NUL */
+ f._extra = &ext;
+ INITEXTRA(&f);
+ ret = __vfprintf(&f, 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);
+}
diff --git a/lib/libc/stdio/vfprintf.c b/lib/libc/stdio/vfprintf.c
new file mode 100644
index 0000000..df4bac2
--- /dev/null
+++ b/lib/libc/stdio/vfprintf.c
@@ -0,0 +1,1656 @@
+/*-
+ * 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. 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.
+ */
+
+#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 <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 "un-namespace.h"
+
+#include "libc_private.h"
+#include "local.h"
+#include "fvwrite.h"
+
+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;
+ size_t *psizearg;
+ intmax_t *pintmaxarg;
+#ifndef NO_FLOATING_POINT
+ double doublearg;
+ long double longdoublearg;
+#endif
+ wint_t wintarg;
+ wchar_t *pwchararg;
+};
+
+/*
+ * 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_SIZET, TP_SIZET,
+ T_INTMAXT, T_UINTMAXT, TP_INTMAXT, TP_VOID, TP_CHAR, TP_SCHAR,
+ T_DOUBLE, T_LONG_DOUBLE, T_WINT, TP_WCHAR
+};
+
+static int __sprint(FILE *, struct __suio *);
+static int __sbprintf(FILE *, const char *, va_list) __printflike(2, 0);
+static char *__ujtoa(uintmax_t, char *, int, int, const char *, int, char,
+ const char *);
+static char *__ultoa(u_long, char *, int, int, const char *, int, char,
+ const char *);
+static char *__wcsconv(wchar_t *, int);
+static void __find_arguments(const char *, va_list, union arg **);
+static void __grow_type_table(int, enum typeid **, int *);
+
+/*
+ * 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)
+{
+ 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, const char *fmt, va_list ap)
+{
+ int ret;
+ FILE fake;
+ 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._extra = fp->_extra;
+
+ /* 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, fmt, ap);
+ if (ret >= 0 && __fflush(&fake))
+ ret = EOF;
+ if (fake._flags & __SERR)
+ fp->_flags |= __SERR;
+ return (ret);
+}
+
+/*
+ * 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')
+
+/*
+ * 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,
+ 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);
+ 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,
+ int needgrp, char thousep, const char *grp)
+{
+ char *cp = endp;
+ intmax_t sval;
+ int ndig;
+
+ /* 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,
+ needgrp, thousep, grp));
+ 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);
+ if (octzero && *cp != '0')
+ *--cp = '0';
+ break;
+
+ case 16:
+ do {
+ *--cp = xdigs[val & 15];
+ val >>= 4;
+ } while (val);
+ break;
+
+ default:
+ abort();
+ }
+ return (cp);
+}
+
+/*
+ * 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(FILE * __restrict fp, const char * __restrict fmt0, va_list ap)
+
+{
+ int ret;
+
+ FLOCKFILE(fp);
+ ret = __vfprintf(fp, fmt0, ap);
+ FUNLOCKFILE(fp);
+ return (ret);
+}
+
+#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, int);
+
+#endif /* !NO_FLOATING_POINT */
+
+/*
+ * 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 STATIC_ARG_TBL_SIZE 8 /* Size of static argument table. */
+
+/*
+ * 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 */
+
+/*
+ * Non-MT-safe version
+ */
+int
+__vfprintf(FILE *fp, 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) */
+ struct __siov *iovp; /* for PRINT macro */
+ 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) */
+ char thousands_sep; /* locale specific thousands separator */
+ const char *grouping; /* locale specific numeric grouping rules */
+
+ if (__use_xprintf == 0 && getenv("USE_XPRINTF"))
+ __use_xprintf = 1;
+ if (__use_xprintf > 0)
+ return (__xvprintf(fp, fmt0, ap));
+
+#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 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 lead; /* sig figs before decimal or group sep */
+ 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 */
+ int nseps; /* number of group separators with ' */
+ int nrepeats; /* number of repeats of the last group */
+#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 */
+#define NIOV 8
+ struct __suio uio; /* output information: summary */
+ struct __siov iov[NIOV];/* ... and individual io vectors */
+ 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 */
+
+ /*
+ * 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 char blanks[PADSIZE] =
+ {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
+ static char zeroes[PADSIZE] =
+ {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
+
+ static const char xdigs_lower[17] = "0123456789abcdef?";
+ static const char xdigs_upper[17] = "0123456789ABCDEF?";
+
+ /*
+ * BEWARE, these `goto error' on error, and PAD uses `n'.
+ */
+#define PRINT(ptr, len) { \
+ iovp->iov_base = (ptr); \
+ iovp->iov_len = (len); \
+ uio.uio_resid += (len); \
+ iovp++; \
+ if (++uio.uio_iovcnt >= NIOV) { \
+ if (__sprint(fp, &uio)) \
+ goto error; \
+ iovp = iov; \
+ } \
+}
+#define PAD(howmany, with) { \
+ if ((n = (howmany)) > 0) { \
+ while (n > PADSIZE) { \
+ PRINT(with, PADSIZE); \
+ n -= PADSIZE; \
+ } \
+ PRINT(with, n); \
+ } \
+}
+#define PRINTANDPAD(p, ep, len, with) do { \
+ n2 = (ep) - (p); \
+ if (n2 > (len)) \
+ n2 = (len); \
+ if (n2 > 0) \
+ PRINT((p), n2); \
+ PAD((len) - (n2 > 0 ? n2 : 0), (with)); \
+} while(0)
+#define FLUSH() { \
+ if (uio.uio_resid && __sprint(fp, &uio)) \
+ goto error; \
+ uio.uio_iovcnt = 0; \
+ iovp = iov; \
+}
+
+ /*
+ * 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(size_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; \
+ __find_arguments (fmt0, orgap, &argtable); \
+ } \
+ nextarg = n2; \
+ val = GETARG (int); \
+ nextarg = hold; \
+ fmt = ++cp; \
+ } else { \
+ val = GETARG (int); \
+ }
+
+
+ thousands_sep = '\0';
+ grouping = NULL;
+ convbuf = NULL;
+#ifndef NO_FLOATING_POINT
+ dtoaresult = NULL;
+ decimal_point = localeconv()->decimal_point;
+#endif
+ /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
+ if (prepwrite(fp) != 0)
+ return (EOF);
+
+ /* optimise fprintf(stderr) (and other unbuffered Unix files) */
+ if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
+ fp->_file >= 0)
+ return (__sbprintf(fp, fmt0, ap));
+
+ fmt = (char *)fmt0;
+ argtable = NULL;
+ nextarg = 1;
+ va_copy(orgap, ap);
+ uio.uio_iov = iovp = iov;
+ uio.uio_resid = 0;
+ uio.uio_iovcnt = 0;
+ ret = 0;
+
+ /*
+ * 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;
+ goto error;
+ }
+ PRINT(cp, n);
+ ret += n;
+ }
+ if (ch == '\0')
+ goto done;
+ fmt++; /* skip over '%' */
+
+ flags = 0;
+ dprec = 0;
+ width = 0;
+ prec = -1;
+ 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;
+ thousands_sep = *(localeconv()->thousands_sep);
+ grouping = localeconv()->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;
+ __find_arguments (fmt0, orgap,
+ &argtable);
+ }
+ 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;
+ 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;
+ } 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 (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;
+ }
+ 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)";
+ if (prec >= 0) {
+ /*
+ * can't use strlen; can only look for the
+ * NUL in the first `prec' characters, and
+ * strlen() will go further.
+ */
+ char *p = memchr(cp, 0, (size_t)prec);
+
+ if (p != NULL) {
+ size = p - cp;
+ if (size > prec)
+ size = prec;
+ } else
+ size = prec;
+ } else
+ size = 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,
+ flags & GROUPING, thousands_sep,
+ grouping);
+ } else {
+ if (ulval != 0 || prec != 0 ||
+ (flags & ALT && base == 8))
+ cp = __ultoa(ulval, cp, base,
+ flags & ALT, xdigs,
+ flags & GROUPING, thousands_sep,
+ grouping);
+ }
+ size = buf + BUF - cp;
+ if (size > BUF) /* should never happen */
+ abort();
+ 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;
+ 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);
+
+ /* leading zeroes from decimal precision */
+ PAD(dprec - size, zeroes);
+
+ /* the string or number proper */
+#ifndef NO_FLOATING_POINT
+ if ((flags & FPT) == 0) {
+ PRINT(cp, size);
+ } 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 {
+ PRINTANDPAD(cp, dtoaend, lead, zeroes);
+ cp += lead;
+ if (grouping) {
+ while (nseps>0 || nrepeats>0) {
+ if (nrepeats > 0)
+ nrepeats--;
+ else {
+ grouping--;
+ nseps--;
+ }
+ PRINT(&thousands_sep,
+ 1);
+ PRINTANDPAD(cp,dtoaend,
+ *grouping, zeroes);
+ cp += *grouping;
+ }
+ if (cp > dtoaend)
+ cp = dtoaend;
+ }
+ if (prec || flags & ALT)
+ PRINT(decimal_point,1);
+ }
+ PRINTANDPAD(cp, dtoaend, 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);
+ }
+ }
+#else
+ PRINT(cp, size);
+#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;
+ if ((argtable != NULL) && (argtable != statargtable))
+ free (argtable);
+ return (ret);
+ /* NOTREACHED */
+}
+
+/*
+ * 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.
+ */
+static void
+__find_arguments (const char *fmt0, va_list ap, union arg **argtable)
+{
+ 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 width; /* width from format (%8d), or 0 */
+ enum typeid *typetable; /* table of types */
+ enum typeid stattypetable [STATIC_ARG_TBL_SIZE];
+ int tablesize; /* current size of type table */
+ int tablemax; /* largest used index in table */
+ int nextarg; /* 1-based argument index */
+
+ /*
+ * Add an argument type to the table, expanding if necessary.
+ */
+#define ADDTYPE(type) \
+ ((nextarg >= tablesize) ? \
+ __grow_type_table(nextarg, &typetable, &tablesize) : (void)0, \
+ (nextarg > tablemax) ? tablemax = nextarg : 0, \
+ typetable[nextarg++] = type)
+
+#define ADDSARG() \
+ ((flags&INTMAXT) ? ADDTYPE(T_INTMAXT) : \
+ ((flags&SIZET) ? ADDTYPE(T_SIZET) : \
+ ((flags&PTRDIFFT) ? ADDTYPE(T_PTRDIFFT) : \
+ ((flags&LLONGINT) ? ADDTYPE(T_LLONG) : \
+ ((flags&LONGINT) ? ADDTYPE(T_LONG) : ADDTYPE(T_INT))))))
+
+#define ADDUARG() \
+ ((flags&INTMAXT) ? ADDTYPE(T_UINTMAXT) : \
+ ((flags&SIZET) ? ADDTYPE(T_SIZET) : \
+ ((flags&PTRDIFFT) ? ADDTYPE(T_PTRDIFFT) : \
+ ((flags&LLONGINT) ? ADDTYPE(T_U_LLONG) : \
+ ((flags&LONGINT) ? ADDTYPE(T_U_LONG) : ADDTYPE(T_U_INT))))))
+
+ /*
+ * Add * arguments to the type array.
+ */
+#define ADDASTER() \
+ n2 = 0; \
+ cp = fmt; \
+ while (is_digit(*cp)) { \
+ n2 = 10 * n2 + to_digit(*cp); \
+ cp++; \
+ } \
+ if (*cp == '$') { \
+ int hold = nextarg; \
+ nextarg = n2; \
+ ADDTYPE (T_INT); \
+ nextarg = hold; \
+ fmt = ++cp; \
+ } else { \
+ ADDTYPE (T_INT); \
+ }
+ fmt = (char *)fmt0;
+ typetable = stattypetable;
+ tablesize = STATIC_ARG_TBL_SIZE;
+ tablemax = 0;
+ nextarg = 1;
+ for (n = 0; n < STATIC_ARG_TBL_SIZE; n++)
+ typetable[n] = T_UNUSED;
+
+ /*
+ * Scan the format for conversions (`%' character).
+ */
+ for (;;) {
+ for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
+ /* void */;
+ if (ch == '\0')
+ goto done;
+ fmt++; /* skip over '%' */
+
+ flags = 0;
+ width = 0;
+
+rflag: ch = *fmt++;
+reswitch: switch (ch) {
+ case ' ':
+ case '#':
+ goto rflag;
+ case '*':
+ ADDASTER ();
+ goto rflag;
+ case '-':
+ case '+':
+ case '\'':
+ goto rflag;
+ case '.':
+ if ((ch = *fmt++) == '*') {
+ ADDASTER ();
+ 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);
+ ch = *fmt++;
+ } while (is_digit(ch));
+ if (ch == '$') {
+ nextarg = n;
+ 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)
+ ADDTYPE(T_WINT);
+ else
+ ADDTYPE(T_INT);
+ break;
+ case 'D':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'd':
+ case 'i':
+ ADDSARG();
+ break;
+#ifndef NO_FLOATING_POINT
+ case 'a':
+ case 'A':
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'g':
+ case 'G':
+ if (flags & LONGDBL)
+ ADDTYPE(T_LONG_DOUBLE);
+ else
+ ADDTYPE(T_DOUBLE);
+ break;
+#endif /* !NO_FLOATING_POINT */
+ case 'n':
+ if (flags & INTMAXT)
+ ADDTYPE(TP_INTMAXT);
+ else if (flags & PTRDIFFT)
+ ADDTYPE(TP_PTRDIFFT);
+ else if (flags & SIZET)
+ ADDTYPE(TP_SIZET);
+ else if (flags & LLONGINT)
+ ADDTYPE(TP_LLONG);
+ else if (flags & LONGINT)
+ ADDTYPE(TP_LONG);
+ else if (flags & SHORTINT)
+ ADDTYPE(TP_SHORT);
+ else if (flags & CHARINT)
+ ADDTYPE(TP_SCHAR);
+ else
+ ADDTYPE(TP_INT);
+ continue; /* no output */
+ case 'O':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'o':
+ ADDUARG();
+ break;
+ case 'p':
+ ADDTYPE(TP_VOID);
+ break;
+ case 'S':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 's':
+ if (flags & LONGINT)
+ ADDTYPE(TP_WCHAR);
+ else
+ ADDTYPE(TP_CHAR);
+ break;
+ case 'U':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'u':
+ case 'X':
+ case 'x':
+ ADDUARG();
+ break;
+ default: /* "%?" prints ?, unless ? is NUL */
+ if (ch == '\0')
+ goto done;
+ break;
+ }
+ }
+done:
+ /*
+ * Build the argument table.
+ */
+ if (tablemax >= STATIC_ARG_TBL_SIZE) {
+ *argtable = (union arg *)
+ malloc (sizeof (union arg) * (tablemax + 1));
+ }
+
+ (*argtable) [0].intarg = 0;
+ for (n = 1; n <= tablemax; n++) {
+ switch (typetable [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 TP_SIZET:
+ (*argtable) [n].psizearg = 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;
+ }
+ }
+
+ if ((typetable != NULL) && (typetable != stattypetable))
+ free (typetable);
+}
+
+/*
+ * Increase the size of the type table.
+ */
+static void
+__grow_type_table (int nextarg, enum typeid **typetable, int *tablesize)
+{
+ enum typeid *const oldtable = *typetable;
+ const int oldsize = *tablesize;
+ enum typeid *newtable;
+ int n, newsize = oldsize * 2;
+
+ if (newsize < nextarg + 1)
+ newsize = nextarg + 1;
+ if (oldsize == STATIC_ARG_TBL_SIZE) {
+ if ((newtable = malloc(newsize * sizeof(enum typeid))) == NULL)
+ abort(); /* XXX handle better */
+ bcopy(oldtable, newtable, oldsize * sizeof(enum typeid));
+ } else {
+ newtable = reallocf(oldtable, newsize * sizeof(enum typeid));
+ if (newtable == NULL)
+ abort(); /* XXX handle better */
+ }
+ for (n = oldsize; n < newsize; n++)
+ newtable[n] = T_UNUSED;
+
+ *typetable = newtable;
+ *tablesize = newsize;
+}
+
+
+#ifndef NO_FLOATING_POINT
+
+static int
+exponent(char *p0, int exp, int 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/vfscanf.c b/lib/libc/stdio/vfscanf.c
new file mode 100644
index 0000000..465ee0d
--- /dev/null
+++ b/lib/libc/stdio/vfscanf.c
@@ -0,0 +1,1068 @@
+/*-
+ * 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. 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.
+ */
+
+#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"
+
+#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 *);
+#endif
+
+int __scanfdebug = 0;
+
+__weak_reference(__vfscanf, vfscanf);
+
+/*
+ * __vfscanf - MT-safe version
+ */
+int
+__vfscanf(FILE *fp, char const *fmt0, va_list ap)
+{
+ int ret;
+
+ FLOCKFILE(fp);
+ ret = __svfscanf(fp, fmt0, ap);
+ FUNLOCKFILE(fp);
+ return (ret);
+}
+
+/*
+ * __svfscanf - non-MT-safe version of __vfscanf
+ */
+int
+__svfscanf(FILE *fp, const char *fmt0, va_list ap)
+{
+ const u_char *fmt = (const u_char *)fmt0;
+ int c; /* character from format, or conversion */
+ size_t width; /* field width, or 0 */
+ char *p; /* points into all kinds of strings */
+ int n; /* handy integer */
+ int flags; /* flags as defined above */
+ char *p0; /* saves original value of p when necessary */
+ int nassigned; /* number of fields assigned */
+ int nconversions; /* number of conversions */
+ 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 and mb conversions */
+ wchar_t *wcp; /* handy wide character pointer */
+ size_t nconv; /* length of multibyte sequence converted */
+ static const mbstate_t initial;
+ mbstate_t mbs;
+
+ /* `basefix' is used to avoid `if' tests in the integer scanner */
+ static short basefix[17] =
+ { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
+
+ 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':
+ nconversions++;
+ 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) {
+ if ((flags & SUPPRESS) == 0)
+ wcp = va_arg(ap, wchar_t *);
+ else
+ wcp = NULL;
+ n = 0;
+ while (width != 0) {
+ if (n == MB_CUR_MAX) {
+ fp->_flags |= __SERR;
+ goto input_failure;
+ }
+ buf[n++] = *fp->_p;
+ fp->_p++;
+ fp->_r--;
+ mbs = initial;
+ nconv = mbrtowc(wcp, buf, n, &mbs);
+ if (nconv == (size_t)-1) {
+ fp->_flags |= __SERR;
+ goto input_failure;
+ }
+ if (nconv == 0 && !(flags & SUPPRESS))
+ *wcp = L'\0';
+ if (nconv != (size_t)-2) {
+ nread += n;
+ width--;
+ if (!(flags & SUPPRESS))
+ wcp++;
+ n = 0;
+ }
+ if (fp->_r <= 0 && __srefill(fp)) {
+ if (n != 0) {
+ fp->_flags |= __SERR;
+ goto input_failure;
+ }
+ break;
+ }
+ }
+ if (!(flags & SUPPRESS))
+ nassigned++;
+ } else if (flags & SUPPRESS) {
+ size_t sum = 0;
+ for (;;) {
+ if ((n = fp->_r) < width) {
+ sum += n;
+ width -= n;
+ fp->_p += n;
+ if (__srefill(fp)) {
+ if (sum == 0)
+ goto input_failure;
+ break;
+ }
+ } else {
+ sum += width;
+ fp->_r -= width;
+ fp->_p += width;
+ break;
+ }
+ }
+ nread += sum;
+ } else {
+ size_t r = __fread((void *)va_arg(ap, char *), 1,
+ width, fp);
+
+ if (r == 0)
+ goto input_failure;
+ nread += r;
+ nassigned++;
+ }
+ nconversions++;
+ 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) {
+ wchar_t twc;
+ int nchars;
+
+ if ((flags & SUPPRESS) == 0)
+ wcp = va_arg(ap, wchar_t *);
+ else
+ wcp = &twc;
+ n = 0;
+ nchars = 0;
+ while (width != 0) {
+ if (n == MB_CUR_MAX) {
+ fp->_flags |= __SERR;
+ goto input_failure;
+ }
+ buf[n++] = *fp->_p;
+ fp->_p++;
+ fp->_r--;
+ mbs = initial;
+ nconv = mbrtowc(wcp, buf, n, &mbs);
+ if (nconv == (size_t)-1) {
+ fp->_flags |= __SERR;
+ goto input_failure;
+ }
+ if (nconv == 0)
+ *wcp = L'\0';
+ if (nconv != (size_t)-2) {
+ if (wctob(*wcp) != EOF &&
+ !ccltab[wctob(*wcp)]) {
+ while (n != 0) {
+ n--;
+ __ungetc(buf[n],
+ fp);
+ }
+ break;
+ }
+ nread += n;
+ width--;
+ if (!(flags & SUPPRESS))
+ wcp++;
+ nchars++;
+ n = 0;
+ }
+ if (fp->_r <= 0 && __srefill(fp)) {
+ if (n != 0) {
+ fp->_flags |= __SERR;
+ goto input_failure;
+ }
+ break;
+ }
+ }
+ if (n != 0) {
+ fp->_flags |= __SERR;
+ goto input_failure;
+ }
+ n = nchars;
+ if (n == 0)
+ goto match_failure;
+ if (!(flags & SUPPRESS)) {
+ *wcp = L'\0';
+ nassigned++;
+ }
+ } else if (flags & SUPPRESS) {
+ n = 0;
+ while (ccltab[*fp->_p]) {
+ n++, fp->_r--, fp->_p++;
+ if (--width == 0)
+ break;
+ if (fp->_r <= 0 && __srefill(fp)) {
+ if (n == 0)
+ goto input_failure;
+ break;
+ }
+ }
+ if (n == 0)
+ goto match_failure;
+ } else {
+ p0 = p = va_arg(ap, char *);
+ while (ccltab[*fp->_p]) {
+ fp->_r--;
+ *p++ = *fp->_p++;
+ if (--width == 0)
+ break;
+ if (fp->_r <= 0 && __srefill(fp)) {
+ if (p == p0)
+ goto input_failure;
+ break;
+ }
+ }
+ n = p - p0;
+ if (n == 0)
+ goto match_failure;
+ *p = 0;
+ nassigned++;
+ }
+ nread += n;
+ nconversions++;
+ break;
+
+ case CT_STRING:
+ /* like CCL, but zero-length string OK, & no NOSKIP */
+ if (width == 0)
+ width = (size_t)~0;
+ if (flags & LONG) {
+ wchar_t twc;
+
+ if ((flags & SUPPRESS) == 0)
+ wcp = va_arg(ap, wchar_t *);
+ else
+ wcp = &twc;
+ n = 0;
+ while (!isspace(*fp->_p) && width != 0) {
+ if (n == MB_CUR_MAX) {
+ fp->_flags |= __SERR;
+ goto input_failure;
+ }
+ buf[n++] = *fp->_p;
+ fp->_p++;
+ fp->_r--;
+ mbs = initial;
+ nconv = mbrtowc(wcp, buf, n, &mbs);
+ if (nconv == (size_t)-1) {
+ fp->_flags |= __SERR;
+ goto input_failure;
+ }
+ if (nconv == 0)
+ *wcp = L'\0';
+ if (nconv != (size_t)-2) {
+ if (iswspace(*wcp)) {
+ while (n != 0) {
+ n--;
+ __ungetc(buf[n],
+ fp);
+ }
+ break;
+ }
+ nread += n;
+ width--;
+ if (!(flags & SUPPRESS))
+ wcp++;
+ n = 0;
+ }
+ if (fp->_r <= 0 && __srefill(fp)) {
+ if (n != 0) {
+ fp->_flags |= __SERR;
+ goto input_failure;
+ }
+ break;
+ }
+ }
+ if (!(flags & SUPPRESS)) {
+ *wcp = L'\0';
+ nassigned++;
+ }
+ } else if (flags & SUPPRESS) {
+ n = 0;
+ while (!isspace(*fp->_p)) {
+ n++, fp->_r--, fp->_p++;
+ if (--width == 0)
+ break;
+ if (fp->_r <= 0 && __srefill(fp))
+ break;
+ }
+ nread += n;
+ } else {
+ p0 = p = va_arg(ap, char *);
+ while (!isspace(*fp->_p)) {
+ fp->_r--;
+ *p++ = *fp->_p++;
+ if (--width == 0)
+ break;
+ if (fp->_r <= 0 && __srefill(fp))
+ break;
+ }
+ *p = 0;
+ nread += p - p0;
+ nassigned++;
+ }
+ nconversions++;
+ continue;
+
+ 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
+ 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);
+ goto match_failure;
+ }
+ c = ((u_char *)p)[-1];
+ if (c == 'x' || c == 'X') {
+ --p;
+ (void) __ungetc(c, fp);
+ }
+ if ((flags & SUPPRESS) == 0) {
+ uintmax_t res;
+
+ *p = 0;
+ if ((flags & UNSIGNED) == 0)
+ res = strtoimax(buf, (char **)NULL, base);
+ else
+ res = strtoumax(buf, (char **)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;
+ nassigned++;
+ }
+ nread += p - buf;
+ nconversions++;
+ 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;
+ if ((width = parsefloat(fp, buf, buf + width)) == 0)
+ goto match_failure;
+ if ((flags & SUPPRESS) == 0) {
+ if (flags & LONGDBL) {
+ long double res = strtold(buf, &p);
+ *va_arg(ap, long double *) = res;
+ } else if (flags & LONG) {
+ double res = strtod(buf, &p);
+ *va_arg(ap, double *) = res;
+ } else {
+ float res = strtof(buf, &p);
+ *va_arg(ap, float *) = res;
+ }
+ if (__scanfdebug && p - buf != width)
+ abort();
+ nassigned++;
+ }
+ nread += width;
+ nconversions++;
+ break;
+#endif /* !NO_FLOATING_POINT */
+ }
+ }
+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(tab, fmt)
+ char *tab;
+ const u_char *fmt;
+{
+ int c, n, v, i;
+
+ /* 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 considerd
+ * 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 == ']'
+ || (__collate_load_error ? n < c :
+ __collate_range_cmp (n, c) < 0
+ )
+ ) {
+ c = '-';
+ break; /* resume the for(;;) */
+ }
+ fmt++;
+ /* fill in the range */
+ if (__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)
+{
+ char *commit, *p;
+ int infnanpos = 0;
+ enum {
+ S_START, S_GOTSIGN, S_INF, S_NAN, S_MAYBEHEX,
+ S_DIGITS, S_FRAC, S_EXP, S_EXPDIGITS
+ } state = S_START;
+ unsigned char c;
+ char decpt = *localeconv()->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 -1: /* XXX kludge to deal with nan(...) */
+ goto parsedone;
+ 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;
+ infnanpos = -2;
+ } else if (!isalnum(c) && c != '_')
+ goto parsedone;
+ break;
+ }
+ infnanpos++;
+ break;
+ 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;
+ 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 && 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 0000000..375d202
--- /dev/null
+++ b/lib/libc/stdio/vfwprintf.c
@@ -0,0 +1,1648 @@
+/*-
+ * 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. 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.
+ */
+
+#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 <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"
+
+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;
+ size_t *psizearg;
+ intmax_t *pintmaxarg;
+#ifndef NO_FLOATING_POINT
+ double doublearg;
+ long double longdoublearg;
+#endif
+ wint_t wintarg;
+ wchar_t *pwchararg;
+};
+
+/*
+ * 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_SIZET, TP_SIZET,
+ T_INTMAXT, T_UINTMAXT, TP_INTMAXT, TP_VOID, TP_CHAR, TP_SCHAR,
+ T_DOUBLE, T_LONG_DOUBLE, T_WINT, TP_WCHAR
+};
+
+static int __sbprintf(FILE *, const wchar_t *, va_list);
+static wint_t __xfputwc(wchar_t, FILE *);
+static wchar_t *__ujtoa(uintmax_t, wchar_t *, int, int, const char *, int,
+ char, const char *);
+static wchar_t *__ultoa(u_long, wchar_t *, int, int, const char *, int,
+ char, const char *);
+static wchar_t *__mbsconv(char *, int);
+static void __find_arguments(const wchar_t *, va_list, union arg **);
+static void __grow_type_table(int, enum typeid **, int *);
+
+/*
+ * 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, const wchar_t *fmt, va_list ap)
+{
+ int ret;
+ FILE fake;
+ 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._extra = fp->_extra;
+
+ /* 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, 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)
+{
+ static const mbstate_t initial;
+ 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));
+
+ mbs = initial;
+ 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);
+}
+
+/*
+ * 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')
+
+/*
+ * 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 wchar_t *
+__ultoa(u_long val, wchar_t *endp, int base, int octzero, const char *xdigs,
+ int needgrp, char thousep, const char *grp)
+{
+ wchar_t *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);
+ 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 wchar_t *
+__ujtoa(uintmax_t val, wchar_t *endp, int base, int octzero,
+ const char *xdigs, int needgrp, char thousep, const char *grp)
+{
+ wchar_t *cp = endp;
+ intmax_t sval;
+ int ndig;
+
+ /* 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,
+ needgrp, thousep, grp));
+ 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);
+ if (octzero && *cp != '0')
+ *--cp = '0';
+ break;
+
+ case 16:
+ do {
+ *--cp = xdigs[val & 15];
+ val >>= 4;
+ } while (val);
+ break;
+
+ default:
+ abort();
+ }
+ return (cp);
+}
+
+/*
+ * 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)
+{
+ static const mbstate_t initial;
+ 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 = 0;
+ mbs = initial;
+ 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);
+
+ /*
+ * 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;
+ 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(FILE * __restrict fp, const wchar_t * __restrict fmt0, va_list ap)
+
+{
+ int ret;
+
+ FLOCKFILE(fp);
+ ret = __vfwprintf(fp, fmt0, ap);
+ FUNLOCKFILE(fp);
+ return (ret);
+}
+
+#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(wchar_t *, int, wchar_t);
+
+#endif /* !NO_FLOATING_POINT */
+
+/*
+ * 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 STATIC_ARG_TBL_SIZE 8 /* Size of static argument table. */
+
+/*
+ * 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 */
+
+/*
+ * Non-MT-safe version
+ */
+int
+__vfwprintf(FILE *fp, const wchar_t *fmt0, va_list ap)
+{
+ wchar_t *fmt; /* format string */
+ wchar_t ch; /* character from fmt */
+ int n, n2, n3; /* 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) */
+ char thousands_sep; /* locale specific thousands separator */
+ const char *grouping; /* locale specific numeric grouping rules */
+#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 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 lead; /* sig figs before decimal or group sep */
+ 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 */
+ int nseps; /* number of group separators with ' */
+ int nrepeats; /* number of repeats of the last group */
+#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 */
+ 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 */
+
+ /*
+ * 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 wchar_t blanks[PADSIZE] =
+ {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
+ static wchar_t zeroes[PADSIZE] =
+ {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
+
+ static const char xdigs_lower[16] = "0123456789abcdef";
+ static const char xdigs_upper[16] = "0123456789ABCDEF";
+
+ /*
+ * BEWARE, these `goto error' on error, PRINT uses `n2' and
+ * PAD uses `n'.
+ */
+#define PRINT(ptr, len) do { \
+ for (n3 = 0; n3 < (len); n3++) \
+ __xfputwc((ptr)[n3], fp); \
+} while (0)
+#define PAD(howmany, with) do { \
+ if ((n = (howmany)) > 0) { \
+ while (n > PADSIZE) { \
+ PRINT(with, PADSIZE); \
+ n -= PADSIZE; \
+ } \
+ PRINT(with, n); \
+ } \
+} while (0)
+#define PRINTANDPAD(p, ep, len, with) do { \
+ n2 = (ep) - (p); \
+ if (n2 > (len)) \
+ n2 = (len); \
+ if (n2 > 0) \
+ PRINT((p), n2); \
+ PAD((len) - (n2 > 0 ? n2 : 0), (with)); \
+} while(0)
+
+ /*
+ * 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(size_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; \
+ __find_arguments (fmt0, orgap, &argtable); \
+ } \
+ nextarg = n2; \
+ val = GETARG (int); \
+ nextarg = hold; \
+ fmt = ++cp; \
+ } else { \
+ val = GETARG (int); \
+ }
+
+
+ thousands_sep = '\0';
+ grouping = NULL;
+#ifndef NO_FLOATING_POINT
+ decimal_point = localeconv()->decimal_point;
+#endif
+ convbuf = NULL;
+ /* sorry, fwprintf(read_only_file, L"") returns WEOF, not 0 */
+ if (prepwrite(fp) != 0)
+ return (EOF);
+
+ /* optimise fprintf(stderr) (and other unbuffered Unix files) */
+ if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
+ fp->_file >= 0)
+ return (__sbprintf(fp, fmt0, ap));
+
+ fmt = (wchar_t *)fmt0;
+ argtable = NULL;
+ nextarg = 1;
+ va_copy(orgap, ap);
+ ret = 0;
+
+ /*
+ * 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;
+ goto error;
+ }
+ PRINT(cp, n);
+ ret += n;
+ }
+ if (ch == '\0')
+ goto done;
+ fmt++; /* skip over '%' */
+
+ flags = 0;
+ dprec = 0;
+ width = 0;
+ prec = -1;
+ 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;
+ thousands_sep = *(localeconv()->thousands_sep);
+ grouping = localeconv()->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;
+ __find_arguments (fmt0, orgap,
+ &argtable);
+ }
+ 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;
+ 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 (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;
+ }
+ 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;
+ }
+ }
+
+ if (prec >= 0) {
+ /*
+ * can't use wcslen; can only look for the
+ * NUL in the first `prec' characters, and
+ * wcslen() will go further.
+ */
+ wchar_t *p = wmemchr(cp, 0, (size_t)prec);
+
+ if (p != NULL) {
+ size = p - cp;
+ if (size > prec)
+ size = prec;
+ } else
+ size = prec;
+ } else
+ size = 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,
+ flags & GROUPING, thousands_sep,
+ grouping);
+ } else {
+ if (ulval != 0 || prec != 0 ||
+ (flags & ALT && base == 8))
+ cp = __ultoa(ulval, cp, base,
+ flags & ALT, xdigs,
+ flags & GROUPING, thousands_sep,
+ grouping);
+ }
+ size = buf + BUF - cp;
+ if (size > BUF) /* should never happen */
+ abort();
+ 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;
+ 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);
+
+ /* leading zeroes from decimal precision */
+ PAD(dprec - size, zeroes);
+
+ /* the string or number proper */
+#ifndef NO_FLOATING_POINT
+ if ((flags & FPT) == 0) {
+ PRINT(cp, size);
+ } 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 {
+ PRINTANDPAD(cp, convbuf + ndig, lead, zeroes);
+ cp += lead;
+ if (grouping) {
+ while (nseps>0 || nrepeats>0) {
+ if (nrepeats > 0)
+ nrepeats--;
+ else {
+ grouping--;
+ nseps--;
+ }
+ PRINT(&thousands_sep,
+ 1);
+ PRINTANDPAD(cp,
+ convbuf + ndig,
+ *grouping, zeroes);
+ cp += *grouping;
+ }
+ if (cp > convbuf + ndig)
+ cp = convbuf + ndig;
+ }
+ if (prec || flags & ALT) {
+ buf[0] = *decimal_point;
+ PRINT(buf, 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);
+ }
+ }
+#else
+ PRINT(cp, size);
+#endif
+ /* left-adjusting padding (always blank) */
+ if (flags & LADJUST)
+ PAD(width - realsz, blanks);
+
+ /* finally, adjust ret */
+ ret += prsize;
+ }
+done:
+error:
+ va_end(orgap);
+ if (convbuf != NULL)
+ free(convbuf);
+ if (__sferror(fp))
+ ret = EOF;
+ if ((argtable != NULL) && (argtable != statargtable))
+ free (argtable);
+ return (ret);
+ /* NOTREACHED */
+}
+
+/*
+ * 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.
+ */
+static void
+__find_arguments (const wchar_t *fmt0, va_list ap, union arg **argtable)
+{
+ 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 width; /* width from format (%8d), or 0 */
+ enum typeid *typetable; /* table of types */
+ enum typeid stattypetable [STATIC_ARG_TBL_SIZE];
+ int tablesize; /* current size of type table */
+ int tablemax; /* largest used index in table */
+ int nextarg; /* 1-based argument index */
+
+ /*
+ * Add an argument type to the table, expanding if necessary.
+ */
+#define ADDTYPE(type) \
+ ((nextarg >= tablesize) ? \
+ __grow_type_table(nextarg, &typetable, &tablesize) : (void)0, \
+ (nextarg > tablemax) ? tablemax = nextarg : 0, \
+ typetable[nextarg++] = type)
+
+#define ADDSARG() \
+ ((flags&INTMAXT) ? ADDTYPE(T_INTMAXT) : \
+ ((flags&SIZET) ? ADDTYPE(T_SIZET) : \
+ ((flags&PTRDIFFT) ? ADDTYPE(T_PTRDIFFT) : \
+ ((flags&LLONGINT) ? ADDTYPE(T_LLONG) : \
+ ((flags&LONGINT) ? ADDTYPE(T_LONG) : ADDTYPE(T_INT))))))
+
+#define ADDUARG() \
+ ((flags&INTMAXT) ? ADDTYPE(T_UINTMAXT) : \
+ ((flags&SIZET) ? ADDTYPE(T_SIZET) : \
+ ((flags&PTRDIFFT) ? ADDTYPE(T_PTRDIFFT) : \
+ ((flags&LLONGINT) ? ADDTYPE(T_U_LLONG) : \
+ ((flags&LONGINT) ? ADDTYPE(T_U_LONG) : ADDTYPE(T_U_INT))))))
+
+ /*
+ * Add * arguments to the type array.
+ */
+#define ADDASTER() \
+ n2 = 0; \
+ cp = fmt; \
+ while (is_digit(*cp)) { \
+ n2 = 10 * n2 + to_digit(*cp); \
+ cp++; \
+ } \
+ if (*cp == '$') { \
+ int hold = nextarg; \
+ nextarg = n2; \
+ ADDTYPE (T_INT); \
+ nextarg = hold; \
+ fmt = ++cp; \
+ } else { \
+ ADDTYPE (T_INT); \
+ }
+ fmt = (wchar_t *)fmt0;
+ typetable = stattypetable;
+ tablesize = STATIC_ARG_TBL_SIZE;
+ tablemax = 0;
+ nextarg = 1;
+ for (n = 0; n < STATIC_ARG_TBL_SIZE; n++)
+ typetable[n] = T_UNUSED;
+
+ /*
+ * Scan the format for conversions (`%' character).
+ */
+ for (;;) {
+ for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
+ /* void */;
+ if (ch == '\0')
+ goto done;
+ fmt++; /* skip over '%' */
+
+ flags = 0;
+ width = 0;
+
+rflag: ch = *fmt++;
+reswitch: switch (ch) {
+ case ' ':
+ case '#':
+ goto rflag;
+ case '*':
+ ADDASTER ();
+ goto rflag;
+ case '-':
+ case '+':
+ case '\'':
+ goto rflag;
+ case '.':
+ if ((ch = *fmt++) == '*') {
+ ADDASTER ();
+ 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);
+ ch = *fmt++;
+ } while (is_digit(ch));
+ if (ch == '$') {
+ nextarg = n;
+ 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)
+ ADDTYPE(T_WINT);
+ else
+ ADDTYPE(T_INT);
+ break;
+ case 'D':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'd':
+ case 'i':
+ ADDSARG();
+ break;
+#ifndef NO_FLOATING_POINT
+ case 'a':
+ case 'A':
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'g':
+ case 'G':
+ if (flags & LONGDBL)
+ ADDTYPE(T_LONG_DOUBLE);
+ else
+ ADDTYPE(T_DOUBLE);
+ break;
+#endif /* !NO_FLOATING_POINT */
+ case 'n':
+ if (flags & INTMAXT)
+ ADDTYPE(TP_INTMAXT);
+ else if (flags & PTRDIFFT)
+ ADDTYPE(TP_PTRDIFFT);
+ else if (flags & SIZET)
+ ADDTYPE(TP_SIZET);
+ else if (flags & LLONGINT)
+ ADDTYPE(TP_LLONG);
+ else if (flags & LONGINT)
+ ADDTYPE(TP_LONG);
+ else if (flags & SHORTINT)
+ ADDTYPE(TP_SHORT);
+ else if (flags & CHARINT)
+ ADDTYPE(TP_SCHAR);
+ else
+ ADDTYPE(TP_INT);
+ continue; /* no output */
+ case 'O':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'o':
+ ADDUARG();
+ break;
+ case 'p':
+ ADDTYPE(TP_VOID);
+ break;
+ case 'S':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 's':
+ if (flags & LONGINT)
+ ADDTYPE(TP_WCHAR);
+ else
+ ADDTYPE(TP_CHAR);
+ break;
+ case 'U':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'u':
+ case 'X':
+ case 'x':
+ ADDUARG();
+ break;
+ default: /* "%?" prints ?, unless ? is NUL */
+ if (ch == '\0')
+ goto done;
+ break;
+ }
+ }
+done:
+ /*
+ * Build the argument table.
+ */
+ if (tablemax >= STATIC_ARG_TBL_SIZE) {
+ *argtable = (union arg *)
+ malloc (sizeof (union arg) * (tablemax + 1));
+ }
+
+ (*argtable) [0].intarg = 0;
+ for (n = 1; n <= tablemax; n++) {
+ switch (typetable [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 TP_SIZET:
+ (*argtable) [n].psizearg = 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;
+ }
+ }
+
+ if ((typetable != NULL) && (typetable != stattypetable))
+ free (typetable);
+}
+
+/*
+ * Increase the size of the type table.
+ */
+static void
+__grow_type_table (int nextarg, enum typeid **typetable, int *tablesize)
+{
+ enum typeid *const oldtable = *typetable;
+ const int oldsize = *tablesize;
+ enum typeid *newtable;
+ int n, newsize = oldsize * 2;
+
+ if (newsize < nextarg + 1)
+ newsize = nextarg + 1;
+ if (oldsize == STATIC_ARG_TBL_SIZE) {
+ if ((newtable = malloc(newsize * sizeof(enum typeid))) == NULL)
+ abort(); /* XXX handle better */
+ bcopy(oldtable, newtable, oldsize * sizeof(enum typeid));
+ } else {
+ newtable = reallocf(oldtable, newsize * sizeof(enum typeid));
+ if (newtable == NULL)
+ abort(); /* XXX handle better */
+ }
+ for (n = oldsize; n < newsize; n++)
+ newtable[n] = T_UNUSED;
+
+ *typetable = newtable;
+ *tablesize = newsize;
+}
+
+
+#ifndef NO_FLOATING_POINT
+
+static int
+exponent(wchar_t *p0, int exp, wchar_t fmtch)
+{
+ wchar_t *p, *t;
+ wchar_t 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/vfwscanf.c b/lib/libc/stdio/vfwscanf.c
new file mode 100644
index 0000000..a855677
--- /dev/null
+++ b/lib/libc/stdio/vfwscanf.c
@@ -0,0 +1,880 @@
+/*-
+ * 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. 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.
+ */
+
+#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"
+
+#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 */
+
+#ifndef NO_FLOATING_POINT
+static int parsefloat(FILE *, wchar_t *, wchar_t *);
+#endif
+
+extern int __scanfdebug;
+
+#define INCCL(_c) \
+ (cclcompl ? (wmemchr(ccls, (_c), ccle - ccls) == NULL) : \
+ (wmemchr(ccls, (_c), ccle - ccls) != NULL))
+
+/*
+ * MT-safe version.
+ */
+int
+vfwscanf(FILE * __restrict fp, const wchar_t * __restrict fmt, va_list ap)
+{
+ int ret;
+
+ FLOCKFILE(fp);
+ ORIENT(fp, 1);
+ ret = __vfwscanf(fp, fmt, ap);
+ FUNLOCKFILE(fp);
+ return (ret);
+}
+
+/*
+ * Non-MT-safe version.
+ */
+int
+__vfwscanf(FILE * __restrict fp, const wchar_t * __restrict fmt, va_list ap)
+{
+ wint_t c; /* character from format, or conversion */
+ size_t width; /* field width, or 0 */
+ wchar_t *p; /* points into all kinds of strings */
+ int n; /* handy integer */
+ int flags; /* flags as defined above */
+ wchar_t *p0; /* saves original value of p when necessary */
+ int nassigned; /* number of fields assigned */
+ int nconversions; /* number of conversions */
+ int nread; /* number of characters consumed from fp */
+ int base; /* base argument to conversion function */
+ wchar_t buf[BUF]; /* buffer for numeric conversions */
+ const wchar_t *ccls; /* character class start */
+ const wchar_t *ccle; /* character class end */
+ int cclcompl; /* ccl is complemented? */
+ wint_t wi; /* handy wint_t */
+ char *mbp; /* multibyte string pointer for %c %s %[ */
+ size_t nconv; /* number of bytes in mb. conversion */
+ char mbbuf[MB_LEN_MAX]; /* temporary mb. character buffer */
+ static const mbstate_t initial;
+ mbstate_t mbs;
+
+ /* `basefix' is used to avoid `if' tests in the integer scanner */
+ static short basefix[17] =
+ { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
+
+ nassigned = 0;
+ nconversions = 0;
+ nread = 0;
+ ccls = ccle = NULL;
+ for (;;) {
+ c = *fmt++;
+ if (c == 0)
+ return (nassigned);
+ if (iswspace(c)) {
+ while ((c = __fgetwc(fp)) != WEOF &&
+ iswspace(c))
+ ;
+ if (c != WEOF)
+ __ungetwc(c, fp);
+ 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)) == WEOF)
+ goto input_failure;
+ if (wi != c) {
+ __ungetwc(wi, fp);
+ 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 '[':
+ ccls = fmt;
+ if (*fmt == '^') {
+ cclcompl = 1;
+ fmt++;
+ } else
+ cclcompl = 0;
+ if (*fmt == ']')
+ fmt++;
+ while (*fmt != '\0' && *fmt != ']')
+ fmt++;
+ ccle = 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':
+ nconversions++;
+ 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)) != WEOF && iswspace(wi))
+ nread++;
+ if (wi == WEOF)
+ goto input_failure;
+ __ungetwc(wi, fp);
+ }
+
+ /*
+ * Do the conversion.
+ */
+ switch (c) {
+
+ case CT_CHAR:
+ /* scan arbitrary characters (sets NOSKIP) */
+ if (width == 0)
+ width = 1;
+ if (flags & LONG) {
+ if (!(flags & SUPPRESS))
+ p = va_arg(ap, wchar_t *);
+ n = 0;
+ while (width-- != 0 &&
+ (wi = __fgetwc(fp)) != WEOF) {
+ if (!(flags & SUPPRESS))
+ *p++ = (wchar_t)wi;
+ n++;
+ }
+ if (n == 0)
+ goto input_failure;
+ nread += n;
+ if (!(flags & SUPPRESS))
+ nassigned++;
+ } else {
+ if (!(flags & SUPPRESS))
+ mbp = va_arg(ap, char *);
+ n = 0;
+ mbs = initial;
+ while (width != 0 &&
+ (wi = __fgetwc(fp)) != WEOF) {
+ if (width >= MB_CUR_MAX &&
+ !(flags & SUPPRESS)) {
+ nconv = wcrtomb(mbp, wi, &mbs);
+ if (nconv == (size_t)-1)
+ goto input_failure;
+ } else {
+ nconv = wcrtomb(mbbuf, wi,
+ &mbs);
+ if (nconv == (size_t)-1)
+ goto input_failure;
+ if (nconv > width) {
+ __ungetwc(wi, fp);
+ break;
+ }
+ if (!(flags & SUPPRESS))
+ memcpy(mbp, mbbuf,
+ nconv);
+ }
+ if (!(flags & SUPPRESS))
+ mbp += nconv;
+ width -= nconv;
+ n++;
+ }
+ if (n == 0)
+ goto input_failure;
+ nread += n;
+ if (!(flags & SUPPRESS))
+ nassigned++;
+ }
+ nconversions++;
+ 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 & SUPPRESS) && (flags & LONG)) {
+ n = 0;
+ while ((wi = __fgetwc(fp)) != WEOF &&
+ width-- != 0 && INCCL(wi))
+ n++;
+ if (wi != WEOF)
+ __ungetwc(wi, fp);
+ if (n == 0)
+ goto match_failure;
+ } else if (flags & LONG) {
+ p0 = p = va_arg(ap, wchar_t *);
+ while ((wi = __fgetwc(fp)) != WEOF &&
+ width-- != 0 && INCCL(wi))
+ *p++ = (wchar_t)wi;
+ if (wi != WEOF)
+ __ungetwc(wi, fp);
+ n = p - p0;
+ if (n == 0)
+ goto match_failure;
+ *p = 0;
+ nassigned++;
+ } else {
+ if (!(flags & SUPPRESS))
+ mbp = va_arg(ap, char *);
+ n = 0;
+ mbs = initial;
+ while ((wi = __fgetwc(fp)) != WEOF &&
+ width != 0 && INCCL(wi)) {
+ if (width >= MB_CUR_MAX &&
+ !(flags & SUPPRESS)) {
+ nconv = wcrtomb(mbp, wi, &mbs);
+ if (nconv == (size_t)-1)
+ goto input_failure;
+ } else {
+ nconv = wcrtomb(mbbuf, wi,
+ &mbs);
+ if (nconv == (size_t)-1)
+ goto input_failure;
+ if (nconv > width)
+ break;
+ if (!(flags & SUPPRESS))
+ memcpy(mbp, mbbuf,
+ nconv);
+ }
+ if (!(flags & SUPPRESS))
+ mbp += nconv;
+ width -= nconv;
+ n++;
+ }
+ if (wi != WEOF)
+ __ungetwc(wi, fp);
+ if (!(flags & SUPPRESS)) {
+ *mbp = 0;
+ nassigned++;
+ }
+ }
+ nread += n;
+ nconversions++;
+ break;
+
+ case CT_STRING:
+ /* like CCL, but zero-length string OK, & no NOSKIP */
+ if (width == 0)
+ width = (size_t)~0;
+ if ((flags & SUPPRESS) && (flags & LONG)) {
+ while ((wi = __fgetwc(fp)) != WEOF &&
+ width-- != 0 &&
+ !iswspace(wi))
+ nread++;
+ if (wi != WEOF)
+ __ungetwc(wi, fp);
+ } else if (flags & LONG) {
+ p0 = p = va_arg(ap, wchar_t *);
+ while ((wi = __fgetwc(fp)) != WEOF &&
+ width-- != 0 &&
+ !iswspace(wi)) {
+ *p++ = (wchar_t)wi;
+ nread++;
+ }
+ if (wi != WEOF)
+ __ungetwc(wi, fp);
+ *p = '\0';
+ nassigned++;
+ } else {
+ if (!(flags & SUPPRESS))
+ mbp = va_arg(ap, char *);
+ mbs = initial;
+ while ((wi = __fgetwc(fp)) != WEOF &&
+ width != 0 &&
+ !iswspace(wi)) {
+ if (width >= MB_CUR_MAX &&
+ !(flags & SUPPRESS)) {
+ nconv = wcrtomb(mbp, wi, &mbs);
+ if (nconv == (size_t)-1)
+ goto input_failure;
+ } else {
+ nconv = wcrtomb(mbbuf, wi,
+ &mbs);
+ if (nconv == (size_t)-1)
+ goto input_failure;
+ if (nconv > width)
+ break;
+ if (!(flags & SUPPRESS))
+ memcpy(mbp, mbbuf,
+ nconv);
+ }
+ if (!(flags & SUPPRESS))
+ mbp += nconv;
+ width -= nconv;
+ nread++;
+ }
+ if (wi != WEOF)
+ __ungetwc(wi, fp);
+ if (!(flags & SUPPRESS)) {
+ *mbp = 0;
+ nassigned++;
+ }
+ }
+ nconversions++;
+ continue;
+
+ 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;
+ flags |= SIGNOK | NDIGITS | NZDIGITS;
+ for (p = buf; width; width--) {
+ c = __fgetwc(fp);
+ /*
+ * 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.
+ */
+ if (c != WEOF)
+ __ungetwc(c, fp);
+ break;
+ ok:
+ /*
+ * c is legal: store it and look at the next.
+ */
+ *p++ = (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 (p > buf)
+ __ungetwc(*--p, fp);
+ goto match_failure;
+ }
+ c = p[-1];
+ if (c == 'x' || c == 'X') {
+ --p;
+ __ungetwc(c, fp);
+ }
+ if ((flags & SUPPRESS) == 0) {
+ uintmax_t res;
+
+ *p = 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;
+ nassigned++;
+ }
+ nread += p - buf;
+ nconversions++;
+ 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;
+ if ((width = parsefloat(fp, buf, buf + width)) == 0)
+ goto match_failure;
+ if ((flags & SUPPRESS) == 0) {
+ if (flags & LONGDBL) {
+ long double res = wcstold(buf, &p);
+ *va_arg(ap, long double *) = res;
+ } else if (flags & LONG) {
+ double res = wcstod(buf, &p);
+ *va_arg(ap, double *) = res;
+ } else {
+ float res = wcstof(buf, &p);
+ *va_arg(ap, float *) = res;
+ }
+ if (__scanfdebug && p - buf != width)
+ abort();
+ nassigned++;
+ }
+ nread += width;
+ nconversions++;
+ break;
+#endif /* !NO_FLOATING_POINT */
+ }
+ }
+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)
+{
+ wchar_t *commit, *p;
+ int infnanpos = 0;
+ enum {
+ S_START, S_GOTSIGN, S_INF, S_NAN, S_MAYBEHEX,
+ S_DIGITS, S_FRAC, S_EXP, S_EXPDIGITS
+ } state = S_START;
+ wchar_t c;
+ wchar_t decpt = (wchar_t)(unsigned char)*localeconv()->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;
+ c = WEOF;
+ for (p = buf; p < end; ) {
+ if ((c = __fgetwc(fp)) == 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 -1: /* XXX kludge to deal with nan(...) */
+ goto parsedone;
+ 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;
+ infnanpos = -2;
+ } else if (!iswalnum(c) && c != '_')
+ goto parsedone;
+ break;
+ }
+ infnanpos++;
+ break;
+ 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);
+ while (commit < --p)
+ __ungetwc(*p, fp);
+ *++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 0000000..15c3241
--- /dev/null
+++ b/lib/libc/stdio/vprintf.c
@@ -0,0 +1,50 @@
+/*-
+ * 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. 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.
+ */
+
+#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>
+
+int
+vprintf(const char * __restrict fmt, __va_list ap)
+{
+
+ return (vfprintf(stdout, fmt, ap));
+}
diff --git a/lib/libc/stdio/vscanf.c b/lib/libc/stdio/vscanf.c
new file mode 100644
index 0000000..cd273e3
--- /dev/null
+++ b/lib/libc/stdio/vscanf.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
+ * 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. 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.
+ */
+
+#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"
+
+int
+vscanf(fmt, ap)
+ const char * __restrict fmt;
+ __va_list ap;
+{
+ int retval;
+
+ FLOCKFILE(stdin);
+ retval = __svfscanf(stdin, fmt, ap);
+ FUNLOCKFILE(stdin);
+ return (retval);
+}
diff --git a/lib/libc/stdio/vsnprintf.c b/lib/libc/stdio/vsnprintf.c
new file mode 100644
index 0000000..16d46ee
--- /dev/null
+++ b/lib/libc/stdio/vsnprintf.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. 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.
+ */
+
+#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 <limits.h>
+#include <stdio.h>
+#include "local.h"
+
+int
+vsnprintf(char * __restrict str, size_t n, const char * __restrict fmt,
+ __va_list ap)
+{
+ size_t on;
+ int ret;
+ char dummy[2];
+ FILE f;
+ struct __sFILEX ext;
+
+ on = n;
+ if (n != 0)
+ n--;
+ if (n > INT_MAX)
+ n = INT_MAX;
+ /* Stdio internals do not deal correctly with zero length buffer */
+ if (n == 0) {
+ if (on > 0)
+ *str = '\0';
+ str = dummy;
+ n = 1;
+ }
+ f._file = -1;
+ f._flags = __SWR | __SSTR;
+ f._bf._base = f._p = (unsigned char *)str;
+ f._bf._size = f._w = n;
+ f._extra = &ext;
+ INITEXTRA(&f);
+ ret = __vfprintf(&f, fmt, ap);
+ if (on > 0)
+ *f._p = '\0';
+ return (ret);
+}
diff --git a/lib/libc/stdio/vsprintf.c b/lib/libc/stdio/vsprintf.c
new file mode 100644
index 0000000..b3150e5
--- /dev/null
+++ b/lib/libc/stdio/vsprintf.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. 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.
+ */
+
+#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"
+
+int
+vsprintf(char * __restrict str, const char * __restrict fmt, __va_list ap)
+{
+ int ret;
+ FILE f;
+ struct __sFILEX ext;
+
+ f._file = -1;
+ f._flags = __SWR | __SSTR;
+ f._bf._base = f._p = (unsigned char *)str;
+ f._bf._size = f._w = INT_MAX;
+ f._extra = &ext;
+ INITEXTRA(&f);
+ ret = __vfprintf(&f, fmt, ap);
+ *f._p = 0;
+ return (ret);
+}
diff --git a/lib/libc/stdio/vsscanf.c b/lib/libc/stdio/vsscanf.c
new file mode 100644
index 0000000..40d4947
--- /dev/null
+++ b/lib/libc/stdio/vsscanf.c
@@ -0,0 +1,80 @@
+/*-
+ * 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.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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.
+ */
+
+#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"
+
+static int
+eofread(void *, char *, int);
+
+/* ARGSUSED */
+static int
+eofread(cookie, buf, len)
+ void *cookie;
+ char *buf;
+ int len;
+{
+
+ return (0);
+}
+
+int
+vsscanf(str, fmt, ap)
+ const char * __restrict str;
+ const char * __restrict fmt;
+ __va_list ap;
+{
+ FILE f;
+ struct __sFILEX ext;
+
+ f._file = -1;
+ f._flags = __SRD;
+ f._bf._base = f._p = (unsigned char *)str;
+ f._bf._size = f._r = strlen(str);
+ f._read = eofread;
+ f._ub._base = NULL;
+ f._lb._base = NULL;
+ f._extra = &ext;
+ INITEXTRA(&f);
+ return (__svfscanf(&f, fmt, ap));
+}
diff --git a/lib/libc/stdio/vswprintf.c b/lib/libc/stdio/vswprintf.c
new file mode 100644
index 0000000..1d8a64e
--- /dev/null
+++ b/lib/libc/stdio/vswprintf.c
@@ -0,0 +1,96 @@
+/* $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.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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 <stdio.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include "local.h"
+
+int
+vswprintf(wchar_t * __restrict s, size_t n, const wchar_t * __restrict fmt,
+ __va_list ap)
+{
+ static const mbstate_t initial;
+ mbstate_t mbs;
+ FILE f;
+ struct __sFILEX ext;
+ char *mbp;
+ int ret, sverrno;
+ size_t nwc;
+
+ if (n == 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ f._file = -1;
+ f._flags = __SWR | __SSTR | __SALC;
+ f._bf._base = f._p = (unsigned char *)malloc(128);
+ if (f._bf._base == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ f._bf._size = f._w = 127; /* Leave room for the NUL */
+ f._extra = &ext;
+ INITEXTRA(&f);
+ ret = __vfwprintf(&f, fmt, ap);
+ if (ret < 0) {
+ sverrno = errno;
+ free(f._bf._base);
+ errno = sverrno;
+ 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(s, (const char **)&mbp, n, &mbs);
+ free(f._bf._base);
+ if (nwc == (size_t)-1) {
+ errno = EILSEQ;
+ return (-1);
+ }
+ if (nwc == n) {
+ s[n - 1] = L'\0';
+ errno = EOVERFLOW;
+ return (-1);
+ }
+
+ return (ret);
+}
diff --git a/lib/libc/stdio/vswscanf.c b/lib/libc/stdio/vswscanf.c
new file mode 100644
index 0000000..7b17e2f
--- /dev/null
+++ b/lib/libc/stdio/vswscanf.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
+ * 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. 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.
+ */
+
+#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"
+
+static int eofread(void *, char *, int);
+
+static int
+eofread(void *cookie, char *buf, int len)
+{
+
+ return (0);
+}
+
+int
+vswscanf(const wchar_t * __restrict str, const wchar_t * __restrict fmt,
+ va_list ap)
+{
+ static const mbstate_t initial;
+ mbstate_t mbs;
+ FILE f;
+ struct __sFILEX ext;
+ char *mbstr;
+ size_t mlen;
+ int r;
+
+ /*
+ * 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;
+ if ((mlen = wcsrtombs(mbstr, &str, SIZE_T_MAX, &mbs)) == (size_t)-1) {
+ free(mbstr);
+ return (EOF);
+ }
+ f._file = -1;
+ f._flags = __SRD;
+ f._bf._base = f._p = (unsigned char *)mbstr;
+ f._bf._size = f._r = mlen;
+ f._read = eofread;
+ f._ub._base = NULL;
+ f._lb._base = NULL;
+ f._extra = &ext;
+ INITEXTRA(&f);
+ r = __vfwscanf(&f, fmt, ap);
+ free(mbstr);
+
+ return (r);
+}
diff --git a/lib/libc/stdio/vwprintf.c b/lib/libc/stdio/vwprintf.c
new file mode 100644
index 0000000..91212a8
--- /dev/null
+++ b/lib/libc/stdio/vwprintf.c
@@ -0,0 +1,39 @@
+/*-
+ * 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 <stdarg.h>
+#include <stdio.h>
+#include <wchar.h>
+
+int
+vwprintf(const wchar_t * __restrict fmt, va_list ap)
+{
+
+ return (vfwprintf(stdout, fmt, ap));
+}
diff --git a/lib/libc/stdio/vwscanf.c b/lib/libc/stdio/vwscanf.c
new file mode 100644
index 0000000..4a21af2
--- /dev/null
+++ b/lib/libc/stdio/vwscanf.c
@@ -0,0 +1,39 @@
+/*-
+ * 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 <stdarg.h>
+#include <stdio.h>
+#include <wchar.h>
+
+int
+vwscanf(const wchar_t * __restrict fmt, va_list ap)
+{
+
+ return (vfwscanf(stdin, fmt, ap));
+}
diff --git a/lib/libc/stdio/wbuf.c b/lib/libc/stdio/wbuf.c
new file mode 100644
index 0000000..4a12305
--- /dev/null
+++ b/lib/libc/stdio/wbuf.c
@@ -0,0 +1,95 @@
+/*-
+ * 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. 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.
+ */
+
+#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 <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(c, fp)
+ 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)
+ 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 0000000..7a3f952b
--- /dev/null
+++ b/lib/libc/stdio/wprintf.3
@@ -0,0 +1,622 @@
+.\" 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. 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.
+.\"
+.\" @(#)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 \\*[Pm] 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 \\*[Pm] 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 SECURITY CONSIDERATIONS
+Refer to
+.Xr printf 3 .
+.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 .
diff --git a/lib/libc/stdio/wprintf.c b/lib/libc/stdio/wprintf.c
new file mode 100644
index 0000000..92426f6
--- /dev/null
+++ b/lib/libc/stdio/wprintf.c
@@ -0,0 +1,45 @@
+/*-
+ * 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 <stdarg.h>
+#include <stdio.h>
+#include <wchar.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);
+}
diff --git a/lib/libc/stdio/wscanf.3 b/lib/libc/stdio/wscanf.3
new file mode 100644
index 0000000..bc8729f
--- /dev/null
+++ b/lib/libc/stdio/wscanf.3
@@ -0,0 +1,483 @@
+.\" 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. 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.
+.\"
+.\" @(#)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 0000000..5e27b40
--- /dev/null
+++ b/lib/libc/stdio/wscanf.c
@@ -0,0 +1,45 @@
+/*-
+ * 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 <stdarg.h>
+#include <stdio.h>
+#include <wchar.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);
+}
diff --git a/lib/libc/stdio/wsetup.c b/lib/libc/stdio/wsetup.c
new file mode 100644
index 0000000..4c18dd4
--- /dev/null
+++ b/lib/libc/stdio/wsetup.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. 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.
+ */
+
+#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(fp)
+ 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;
+ 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 0000000..8d529fc
--- /dev/null
+++ b/lib/libc/stdio/xprintf.c
@@ -0,0 +1,688 @@
+/*-
+ * 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 "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, const 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;
+ 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._extra = fp->_extra;
+
+ /* 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 unsigned 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 0000000..0c2be46
--- /dev/null
+++ b/lib/libc/stdio/xprintf_errno.c
@@ -0,0 +1,65 @@
+/*-
+ * 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_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 < 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 0000000..b719aac
--- /dev/null
+++ b/lib/libc/stdio/xprintf_float.c
@@ -0,0 +1,425 @@
+/*-
+ * 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 prsize; /* max size of printed field */
+ 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;
+
+ prsize = pi->width > realsz ? pi->width : realsz;
+
+ /* 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 0000000..a2956ba
--- /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 0000000..f006b54
--- /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 0000000..0edcd30
--- /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 0000000..d46fa85
--- /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 0000000..81697f1
--- /dev/null
+++ b/lib/libc/stdio/xprintf_time.c
@@ -0,0 +1,115 @@
+/*-
+ * 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;
+
+ prec = 0;
+ 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;
+ }
+
+ p = buf;
+ if (pi->alt) {
+ tx = t;
+ if (t >= YEAR) {
+ p += sprintf(p, "%jdy", t / YEAR);
+ t %= YEAR;
+ }
+ if (t >= DAY && t != 0) {
+ p += sprintf(p, "%jdd", t / DAY);
+ t %= DAY;
+ }
+ if (t >= HOUR && t != 0) {
+ p += sprintf(p, "%jdh", t / HOUR);
+ t %= HOUR;
+ }
+ if (t >= MINUTE && t != 0) {
+ p += sprintf(p, "%jdm", t / MINUTE);
+ t %= MINUTE;
+ }
+ if (t != 0 || tx == 0)
+ p += sprintf(p, "%jds", t);
+ } else {
+ p += sprintf(p, "%jd", (intmax_t)t);
+ }
+ if (pi->is_long || pi->is_long_double) {
+ if (pi->prec >= 0)
+ prec = pi->prec;
+ for (i = prec; i < 9; i++)
+ nsec /= 10;
+ p += sprintf(p, ".%.*d", prec, nsec);
+ }
+ return(__printf_out(io, pi, buf, p - buf));
+}
diff --git a/lib/libc/stdio/xprintf_vis.c b/lib/libc/stdio/xprintf_vis.c
new file mode 100644
index 0000000..819f09f
--- /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 0000000..99ea7fb
--- /dev/null
+++ b/lib/libc/stdlib/Makefile.inc
@@ -0,0 +1,50 @@
+# from @(#)Makefile.inc 8.3 (Berkeley) 2/4/95
+# $FreeBSD$
+
+# machine-independent stdlib sources
+.PATH: ${.CURDIR}/${MACHINE_ARCH}/stdlib ${.CURDIR}/stdlib
+
+MISRCS+=_Exit.c a64l.c abort.c abs.c atexit.c atof.c atoi.c atol.c atoll.c \
+ bsearch.c div.c exit.c getenv.c getopt.c getopt_long.c \
+ getsubopt.c grantpt.c hcreate.c heapsort.c imaxabs.c imaxdiv.c \
+ insque.c l64a.c labs.c ldiv.c llabs.c lldiv.c lsearch.c malloc.c \
+ merge.c putenv.c qsort.c qsort_r.c radixsort.c rand.c random.c \
+ reallocf.c realpath.c remque.c setenv.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
+
+SYM_MAPS+= ${.CURDIR}/stdlib/Symbol.map
+
+# machine-dependent stdlib sources
+.if exists(${.CURDIR}/${MACHINE_ARCH}/stdlib/Makefile.inc)
+.include "${.CURDIR}/${MACHINE_ARCH}/stdlib/Makefile.inc"
+.endif
+
+MAN+= a64l.3 abort.3 abs.3 alloca.3 atexit.3 atof.3 atoi.3 atol.3 bsearch.3 \
+ div.3 exit.3 getenv.3 getopt.3 getopt_long.3 getsubopt.3 grantpt.3 \
+ hcreate.3 imaxabs.3 imaxdiv.3 insque.3 labs.3 ldiv.3 llabs.3 lldiv.3 \
+ lsearch.3 malloc.3 memory.3 posix_memalign.3 qsort.3 radixsort.3 \
+ rand.3 random.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+=grantpt.3 posix_openpt.3 grantpt.3 ptsname.3 grantpt.3 unlockpt.3
+MLINKS+=hcreate.3 hdestroy.3 hcreate.3 hsearch.3
+MLINKS+=insque.3 remque.3
+MLINKS+=lsearch.3 lfind.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+=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+=malloc.3 calloc.3 malloc.3 free.3 malloc.3 malloc.conf.5 \
+ malloc.3 realloc.3 malloc.3 reallocf.3 malloc.3 malloc_usable_size.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 0000000..ff11d7a
--- /dev/null
+++ b/lib/libc/stdlib/Symbol.map
@@ -0,0 +1,100 @@
+# $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;
+ posix_openpt;
+ ptsname;
+ unlockpt;
+ hcreate;
+ hdestroy;
+ hsearch;
+ heapsort;
+ imaxabs;
+ imaxdiv;
+ insque;
+ l64a;
+ l64a_r;
+ labs;
+ ldiv;
+ llabs;
+ lldiv;
+ lsearch;
+ lfind;
+ _malloc_options;
+ _malloc_message;
+ malloc;
+ posix_memalign;
+ calloc;
+ realloc;
+ free;
+ malloc_usable_size;
+ 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;
+};
+
+FBSDprivate {
+ __use_pts;
+ _malloc_prefork;
+ _malloc_postfork;
+ __system;
+ _system;
+};
diff --git a/lib/libc/stdlib/_Exit.c b/lib/libc/stdlib/_Exit.c
new file mode 100644
index 0000000..e7f0f51
--- /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 0000000..50cb444
--- /dev/null
+++ b/lib/libc/stdlib/a64l.3
@@ -0,0 +1,186 @@
+.\" 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\&
+.Fl
+.Ql 9\&
+for 2
+.Fl
+11,
+.Ql A\&
+.Fl
+.Ql Z\&
+for 12
+.Fl
+37, and
+.Ql a\&
+.Fl
+.Ql z\&
+for 38
+.Fl
+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
+.Ft 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 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 NUL character.
+.Sh RETURN VALUES
+On successful completion,
+.Fn a64l
+returns the
+.Ft long
+value resulting from conversion of the input string.
+If a string pointed to by s is an empty string,
+.Fn a64l
+returns 0.
+.Pp
+The
+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 were added to
+.Fx 6.1 .
+.Sh AUTHORS
+The
+.Fn a64l ,
+.Fn l64a ,
+and
+.Fn l64a_r
+were added to
+.Fx
+by
+.An Tom Rhodes Aq 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 0000000..a130dcb
--- /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 0000000..51b6f1b
--- /dev/null
+++ b/lib/libc/stdlib/abort.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
+.\" 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. 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.
+.\"
+.\" @(#)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 0000000..468a9bf
--- /dev/null
+++ b/lib/libc/stdlib/abort.c
@@ -0,0 +1,83 @@
+/*
+ * 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. 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.
+ */
+
+#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()
+{
+ 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)_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)_sigaction(SIGABRT, &act, NULL);
+ sigdelset(&act.sa_mask, SIGABRT);
+ (void)_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 0000000..d9296ef
--- /dev/null
+++ b/lib/libc/stdlib/abs.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. 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.
+.\"
+.\" @(#)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 0000000..0cca02b
--- /dev/null
+++ b/lib/libc/stdlib/abs.c
@@ -0,0 +1,47 @@
+/*-
+ * 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. 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.
+ */
+
+#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(j)
+ 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 0000000..e87cd9f
--- /dev/null
+++ b/lib/libc/stdlib/alloca.3
@@ -0,0 +1,83 @@
+.\" 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. 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.
+.\"
+.\" @(#)alloca.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.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.
+If the allocation failed, a
+.Dv NULL
+pointer is returned.
+.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.
diff --git a/lib/libc/stdlib/atexit.3 b/lib/libc/stdlib/atexit.3
new file mode 100644
index 0000000..b3dec68
--- /dev/null
+++ b/lib/libc/stdlib/atexit.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. 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.
+.\"
+.\" @(#)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)"
+.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.
+.\" 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.
+.El
+.Sh SEE ALSO
+.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 0000000..43a0e74
--- /dev/null
+++ b/lib/libc/stdlib/atexit.c
@@ -0,0 +1,189 @@
+/*-
+ * 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. 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.
+ */
+
+#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 <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pthread.h>
+#include "atexit.h"
+#include "un-namespace.h"
+
+#include "libc_private.h"
+
+#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)
+
+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 */
+
+/*
+ * 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 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);
+}
+
+/*
+ * 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 atexit *p;
+ struct atexit_fn fn;
+ int n;
+
+ _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 */
+ if (dso != NULL && dso != p->fns[n].fn_dso)
+ continue; /* wrong DSO */
+ fn = p->fns[n];
+ /*
+ 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);
+}
diff --git a/lib/libc/stdlib/atexit.h b/lib/libc/stdlib/atexit.h
new file mode 100644
index 0000000..704c2e1
--- /dev/null
+++ b/lib/libc/stdlib/atexit.h
@@ -0,0 +1,40 @@
+/*-
+ * 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. 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.
+ *
+ * @(#)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 0000000..d338e3d
--- /dev/null
+++ b/lib/libc/stdlib/atof.3
@@ -0,0 +1,99 @@
+.\" 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. 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.
+.\"
+.\" @(#)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 0000000..2ce0012
--- /dev/null
+++ b/lib/libc/stdlib/atof.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.
+ * 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.
+ */
+
+#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>
+
+double
+atof(ascii)
+ const char *ascii;
+{
+ return strtod(ascii, (char **)NULL);
+}
diff --git a/lib/libc/stdlib/atoi.3 b/lib/libc/stdlib/atoi.3
new file mode 100644
index 0000000..34a1b2d
--- /dev/null
+++ b/lib/libc/stdlib/atoi.3
@@ -0,0 +1,95 @@
+.\" 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. 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.
+.\"
+.\" @(#)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
+.Sh IMPLEMENTATION NOTES
+The
+.Fn atoi
+function is not thread-safe and also not async-cancel safe.
+.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 0000000..7190da7
--- /dev/null
+++ b/lib/libc/stdlib/atoi.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.
+ * 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.
+ */
+
+#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>
+
+int
+atoi(str)
+ const char *str;
+{
+ return (int)strtol(str, (char **)NULL, 10);
+}
diff --git a/lib/libc/stdlib/atol.3 b/lib/libc/stdlib/atol.3
new file mode 100644
index 0000000..10b8cf7
--- /dev/null
+++ b/lib/libc/stdlib/atol.3
@@ -0,0 +1,110 @@
+.\" 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. 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.
+.\"
+.\" @(#)atol.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd November 28, 2001
+.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 ERRORS
+The functions
+.Fn atol
+and
+.Fn atoll
+need not
+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 0000000..f4d8d1f
--- /dev/null
+++ b/lib/libc/stdlib/atol.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.
+ * 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.
+ */
+
+#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>
+
+long
+atol(str)
+ const char *str;
+{
+ return strtol(str, (char **)NULL, 10);
+}
diff --git a/lib/libc/stdlib/atoll.c b/lib/libc/stdlib/atoll.c
new file mode 100644
index 0000000..463677d
--- /dev/null
+++ b/lib/libc/stdlib/atoll.c
@@ -0,0 +1,44 @@
+/*
+ * 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. 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h>
+
+long long
+atoll(str)
+ const char *str;
+{
+ return strtoll(str, (char **)NULL, 10);
+}
diff --git a/lib/libc/stdlib/bsearch.3 b/lib/libc/stdlib/bsearch.3
new file mode 100644
index 0000000..b8a18d3
--- /dev/null
+++ b/lib/libc/stdlib/bsearch.3
@@ -0,0 +1,93 @@
+.\" 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. 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.
+.\"
+.\" @(#)bsearch.3 8.3 (Berkeley) 4/19/94
+.\" $FreeBSD$
+.\"
+.Dd April 19, 1994
+.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.
+.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 0000000..1088896
--- /dev/null
+++ b/lib/libc/stdlib/bsearch.c
@@ -0,0 +1,83 @@
+/*
+ * 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. 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.
+ */
+
+#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>
+
+/*
+ * 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.
+ */
+void *
+bsearch(key, base0, nmemb, size, compar)
+ const void *key;
+ const void *base0;
+ size_t nmemb;
+ size_t size;
+ int (*compar)(const void *, const void *);
+{
+ 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/div.3 b/lib/libc/stdlib/div.3
new file mode 100644
index 0000000..05567fb
--- /dev/null
+++ b/lib/libc/stdlib/div.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.
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce 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.
+.\"
+.\" @(#)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 0000000..0c3c484
--- /dev/null
+++ b/lib/libc/stdlib/div.c
@@ -0,0 +1,81 @@
+/*
+ * 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. 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.
+ */
+
+#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;
+ /*
+ * 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;
+ }
+ return (r);
+}
diff --git a/lib/libc/stdlib/exit.3 b/lib/libc/stdlib/exit.3
new file mode 100644
index 0000000..8a5231b
--- /dev/null
+++ b/lib/libc/stdlib/exit.3
@@ -0,0 +1,134 @@
+.\" 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. 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.
+.\"
+.\" @(#)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 atexit 3 ,
+.Xr intro 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 0000000..cafb127
--- /dev/null
+++ b/lib/libc/stdlib/exit.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. 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.
+ */
+
+#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(status)
+ int status;
+{
+ /* Ensure that the auto-initialization routine is linked in: */
+ extern int _thread_autoinit_dummy_decl;
+
+ _thread_autoinit_dummy_decl = 1;
+
+ __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 0000000..a75e49f
--- /dev/null
+++ b/lib/libc/stdlib/getenv.3
@@ -0,0 +1,174 @@
+.\" 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. 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.
+.\"
+.\" @(#)getenv.3 8.2 (Berkeley) 12/11/93
+.\" $FreeBSD$
+.\"
+.Dd December 11, 1993
+.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 "const char *string"
+.Ft void
+.Fn unsetenv "const char *name"
+.Sh DESCRIPTION
+These functions set, unset and fetch environment variables from the
+host
+.Em environment list .
+For compatibility with differing environment conventions,
+the given arguments
+.Fa name
+and
+.Fa value
+may be appended and prepended,
+respectively,
+with an equal sign
+.Dq Li \&= .
+.Pp
+The
+.Fn getenv
+function obtains the current value of the environment variable,
+.Fa name .
+.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 is
+equivalent to:
+.Bd -literal -offset indent
+setenv(name, value, 1);
+.Ed
+.Pp
+The
+.Fn unsetenv
+function
+deletes all instances of the variable name pointed to by
+.Fa name
+from the list.
+.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
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er ENOMEM
+The function
+.Fn setenv
+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 .
+.Sh HISTORY
+The functions
+.Fn setenv
+and
+.Fn unsetenv
+appeared in
+.At v7 .
+The
+.Fn putenv
+function appeared in
+.Bx 4.3 Reno .
+.Sh BUGS
+Successive calls to
+.Fn setenv
+or
+.Fn putenv
+assigning a differently sized
+.Fa value
+to the same
+.Fa name
+will result in a memory leak.
+The
+.Fx
+semantics for these functions
+(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 0000000..1643db0
--- /dev/null
+++ b/lib/libc/stdlib/getenv.c
@@ -0,0 +1,93 @@
+/*
+ * 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. 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)getenv.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+
+inline char *__findenv(const char *, int *);
+
+/*
+ * __findenv --
+ * Returns pointer to value associated with name, if any, else NULL.
+ * Sets offset to be the offset of the name/value combination in the
+ * environmental array, for use by setenv(3) and unsetenv(3).
+ * Explicitly removes '=' in argument name.
+ *
+ * This routine *should* be a static; don't use it.
+ */
+inline char *
+__findenv(name, offset)
+ const char *name;
+ int *offset;
+{
+ extern char **environ;
+ int len, i;
+ const char *np;
+ char **p, *cp;
+
+ if (name == NULL || environ == NULL)
+ return (NULL);
+ for (np = name; *np && *np != '='; ++np)
+ continue;
+ len = np - name;
+ for (p = environ; (cp = *p) != NULL; ++p) {
+ for (np = name, i = len; i && *cp; i--)
+ if (*cp++ != *np++)
+ break;
+ if (i == 0 && *cp++ == '=') {
+ *offset = p - environ;
+ return (cp);
+ }
+ }
+ return (NULL);
+}
+
+/*
+ * getenv --
+ * Returns ptr to value associated with name, if any, else NULL.
+ */
+char *
+getenv(name)
+ const char *name;
+{
+ int offset;
+
+ return (__findenv(name, &offset));
+}
diff --git a/lib/libc/stdlib/getopt.3 b/lib/libc/stdlib/getopt.3
new file mode 100644
index 0000000..88fb51f
--- /dev/null
+++ b/lib/libc/stdlib/getopt.3
@@ -0,0 +1,310 @@
+.\" $NetBSD: getopt.3,v 1.31 2003/09/23 10:26:54 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. 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.
+.\"
+.\" @(#)getopt.3 8.5 (Berkeley) 4/27/95
+.\" $FreeBSD$
+.\"
+.Dd April 27, 1995
+.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.
+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 0000000..af0c5ca
--- /dev/null
+++ b/lib/libc/stdlib/getopt.c
@@ -0,0 +1,139 @@
+/* $NetBSD: getopt.c,v 1.26 2003/08/07 16:43:40 agc 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. 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.
+ */
+
+#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(nargc, nargv, ostr)
+ 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 (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 0000000..352af08
--- /dev/null
+++ b/lib/libc/stdlib/getopt_long.3
@@ -0,0 +1,506 @@
+.\" $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 April 1, 2000
+.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 expect
+.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
+.Tn GNU
+libiberty.
+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 0000000..47eab1f
--- /dev/null
+++ b/lib/libc/stdlib/getopt_long.c
@@ -0,0 +1,642 @@
+/* $OpenBSD: getopt_long.c,v 1.17 2004/06/03 18:46:52 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 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.
+ */
+
+#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! */
+
+#ifndef GNU_COMPATIBLE
+#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;
+ int posixly_correct;
+
+ if (options == NULL)
+ return (-1);
+
+ /*
+ * Disable GNU extensions if POSIXLY_CORRECT is set or options
+ * string begins with a '+'.
+ */
+ posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
+#ifdef GNU_COMPATIBLE
+ if (*options == '-')
+ flags |= FLAG_ALLARGS;
+ else if (posixly_correct || *options == '+')
+ flags &= ~FLAG_PERMUTE;
+#else
+ if (posixly_correct || *options == '+')
+ flags &= ~FLAG_PERMUTE;
+ else if (*options == '-')
+ flags |= FLAG_ALLARGS;
+#endif
+ if (*options == '+' || *options == '-')
+ options++;
+
+ /*
+ * 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;
+
+ 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;
+ /* XXX: disable test for :: if PC? (GNU doesn't) */
+ 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];
+ } else if (!(flags & FLAG_PERMUTE)) {
+ /*
+ * If permutation is disabled, we can accept an
+ * optional arg separated by whitespace so long
+ * as it does not start with a dash (-).
+ */
+ if (optind + 1 < nargc && *nargv[optind + 1] != '-')
+ 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(nargc, nargv, options, long_options, idx)
+ 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(nargc, nargv, options, long_options, idx)
+ 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 0000000..1688426
--- /dev/null
+++ b/lib/libc/stdlib/getsubopt.3
@@ -0,0 +1,149 @@
+.\" 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. 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.
+.\"
+.\" @(#)getsubopt.3 8.1 (Berkeley) 6/9/93
+.\" $FreeBSD$
+.\"
+.Dd June 9, 1993
+.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 0000000..6d76f78
--- /dev/null
+++ b/lib/libc/stdlib/getsubopt.c
@@ -0,0 +1,101 @@
+/*-
+ * 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. 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.
+ */
+
+#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(optionp, tokens, valuep)
+ char **optionp, **valuep;
+ char * const *tokens;
+{
+ 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/grantpt.3 b/lib/libc/stdlib/grantpt.3
new file mode 100644
index 0000000..b4ad8c4
--- /dev/null
+++ b/lib/libc/stdlib/grantpt.3
@@ -0,0 +1,225 @@
+.\"
+.\" 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 December 23, 2002
+.Os
+.Dt GRANTPT 3
+.Sh NAME
+.Nm grantpt ,
+.Nm ptsname ,
+.Nm unlockpt ,
+.Nm posix_openpt
+.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"
+.In fcntl.h
+.Ft int
+.Fn posix_openpt "int mode"
+.Sh DESCRIPTION
+The
+.Fn grantpt ,
+.Fn ptsname ,
+.Fn unlockpt ,
+and
+.Fn posix_openpt
+functions allow access to pseudo-terminal devices.
+The first three functions accept a file descriptor
+that references the master half of a pseudo-terminal pair.
+This file descriptor is created with
+.Fn posix_openpt .
+.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
+if it exists on the system; otherwise, it
+is left untouched.
+.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
+.Fn posix_openpt
+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 .
+.Pp
+The
+.Fn posix_openpt
+function opens the first available master pseudo-terminal
+device and returns a descriptor to it.
+The
+.Fa mode
+argument
+specifies the flags used for opening the device:
+.Bl -tag -width ".Dv O_NOCTTY"
+.It Dv O_RDWR
+Open for reading and writing.
+.It Dv O_NOCTTY
+If set, do not allow the terminal to become
+the controlling terminal for the calling process.
+.El
+.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 and the global variable
+.Va errno
+is set to indicate the error.
+.Pp
+The
+.Fn posix_openpt
+function returns a file descriptor to the first
+available master pseudo-terminal device on success;
+otherwise \-1 is returned and the global variable
+.Va errno
+is set to indicate the error.
+.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 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
+.Pp
+The
+.Fn posix_openpt
+function may fail and set
+.Va errno
+to:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+.Fa mode
+consists of an invalid mode bit.
+.It Bq Er EAGAIN
+The system has no available pseudo-terminal devices.
+.El
+.Pp
+The
+.Fn grantpt ,
+.Fn ptsname ,
+and
+.Fn unlockpt
+functions may also fail and set
+.Va errno
+for any of the errors specified for the
+.Xr fstat 2
+system call.
+.Pp
+The
+.Fn posix_openpt
+function may also fail and set
+.Va errno
+for any of the errors specified for the
+.Xr open 2
+system call.
+.Sh SEE ALSO
+.Xr open 2 ,
+.Xr pty 4 ,
+.Xr tty 4
+.Sh STANDARDS
+The
+.Fn grantpt ,
+.Fn ptsname ,
+.Fn unlockpt ,
+and
+.Fn posix_openpt
+functions conform to
+.St -p1003.1-2001 .
+.Sh HISTORY
+The
+.Fn grantpt ,
+.Fn ptsname ,
+.Fn unlockpt ,
+and
+.Fn posix_openpt
+functions appeared in
+.Fx 5.0 .
+.Sh NOTES
+The purpose of the
+.Fn unlockpt
+function has no meaning in
+.Fx .
+.Pp
+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.
diff --git a/lib/libc/stdlib/grantpt.c b/lib/libc/stdlib/grantpt.c
new file mode 100644
index 0000000..f6f31b2
--- /dev/null
+++ b/lib/libc/stdlib/grantpt.c
@@ -0,0 +1,302 @@
+/*
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__FBSDID("$FreeBSD$");
+#endif /* not lint */
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/sysctl.h>
+#include <sys/ioctl.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <paths.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+#define PTM_PREFIX "pty" /* pseudo tty master naming convention */
+#define PTS_PREFIX "tty" /* pseudo tty slave naming convention */
+#define NEWPTS_PREFIX "pts"
+#define PTMX "ptmx"
+
+/*
+ * The following are range values for pseudo TTY devices. Pseudo TTYs have a
+ * name of /dev/[pt]ty[p-sP-S][0-9a-v], yielding 256 combinations per major.
+ */
+#define PT_MAX 256
+#define PT_DEV1 "pqrsPQRS"
+#define PT_DEV2 "0123456789abcdefghijklmnopqrstuv"
+
+/*
+ * grantpt(3) support utility.
+ */
+#define _PATH_PTCHOWN "/usr/libexec/pt_chown"
+
+/*
+ * ISPTM(x) returns 0 for struct stat x if x is not a pty master.
+ * The bounds checking may be unnecessary but it does eliminate doubt.
+ */
+#define ISPTM(x) (S_ISCHR((x).st_mode) && \
+ minor((x).st_rdev) >= 0 && \
+ minor((x).st_rdev) < PT_MAX)
+
+
+static int
+is_pts(int fd)
+{
+ int nb;
+
+ return (_ioctl(fd, TIOCGPTN, &nb) == 0);
+}
+
+int
+__use_pts(void)
+{
+ int use_pts;
+ size_t len;
+ int error;
+
+ len = sizeof(use_pts);
+ error = sysctlbyname("kern.pts.enable", &use_pts, &len, NULL, 0);
+ if (error) {
+ struct stat sb;
+
+ if (stat("/dev/ptmx", &sb) != 0)
+ return (0);
+ use_pts = 1;
+ }
+ return (use_pts);
+}
+
+/*
+ * grantpt(): grant ownership of a slave pseudo-terminal device to the
+ * current user.
+ */
+
+int
+grantpt(int fildes)
+{
+ int retval, serrno, status;
+ pid_t pid, spid;
+ gid_t gid;
+ char *slave;
+ sigset_t oblock, nblock;
+ struct group *grp;
+
+ retval = -1;
+ serrno = errno;
+
+ if ((slave = ptsname(fildes)) != NULL) {
+ /*
+ * Block SIGCHLD.
+ */
+ (void)sigemptyset(&nblock);
+ (void)sigaddset(&nblock, SIGCHLD);
+ (void)_sigprocmask(SIG_BLOCK, &nblock, &oblock);
+
+ switch (pid = fork()) {
+ case -1:
+ break;
+ case 0: /* child */
+ /*
+ * pt_chown expects the master pseudo TTY to be its
+ * standard input.
+ */
+ (void)_dup2(fildes, STDIN_FILENO);
+ (void)_sigprocmask(SIG_SETMASK, &oblock, NULL);
+ execl(_PATH_PTCHOWN, _PATH_PTCHOWN, (char *)NULL);
+ _exit(EX_UNAVAILABLE);
+ /* NOTREACHED */
+ default: /* parent */
+ /*
+ * Just wait for the process. Error checking is
+ * done below.
+ */
+ while ((spid = _waitpid(pid, &status, 0)) == -1 &&
+ (errno == EINTR))
+ ;
+ if (spid != -1 && WIFEXITED(status) &&
+ WEXITSTATUS(status) == EX_OK)
+ retval = 0;
+ else
+ errno = EACCES;
+ break;
+ }
+
+ /*
+ * Restore process's signal mask.
+ */
+ (void)_sigprocmask(SIG_SETMASK, &oblock, NULL);
+
+ if (retval) {
+ /*
+ * pt_chown failed. Try to manually change the
+ * permissions for the slave.
+ */
+ gid = (grp = getgrnam("tty")) ? grp->gr_gid : -1;
+ if (chown(slave, getuid(), gid) == -1 ||
+ chmod(slave, S_IRUSR | S_IWUSR | S_IWGRP) == -1)
+ errno = EACCES;
+ else
+ retval = 0;
+ }
+ }
+
+ if (!retval)
+ errno = serrno;
+
+ return (retval);
+}
+
+/*
+ * posix_openpt(): open the first available master pseudo-terminal device
+ * and return descriptor.
+ */
+int
+posix_openpt(int oflag)
+{
+ char *mc1, *mc2, master[] = _PATH_DEV PTM_PREFIX "XY";
+ const char *pc1, *pc2;
+ int fildes, bflag, serrno;
+
+ fildes = -1;
+ bflag = 0;
+ serrno = errno;
+
+ /*
+ * Check flag validity. POSIX doesn't require it,
+ * but we still do so.
+ */
+ if (oflag & ~(O_RDWR | O_NOCTTY))
+ errno = EINVAL;
+ else {
+ if (__use_pts()) {
+ fildes = _open(_PATH_DEV PTMX, oflag);
+ return (fildes);
+ }
+ mc1 = master + strlen(_PATH_DEV PTM_PREFIX);
+ mc2 = mc1 + 1;
+
+ /* Cycle through all possible master PTY devices. */
+ for (pc1 = PT_DEV1; !bflag && (*mc1 = *pc1); ++pc1)
+ for (pc2 = PT_DEV2; (*mc2 = *pc2) != '\0'; ++pc2) {
+ /*
+ * Break out if we successfully open a PTY,
+ * or if open() fails due to limits.
+ */
+ if ((fildes = _open(master, oflag)) != -1 ||
+ (errno == EMFILE || errno == ENFILE)) {
+ ++bflag;
+ break;
+ }
+ }
+
+ if (fildes != -1)
+ errno = serrno;
+ else if (!bflag)
+ errno = EAGAIN;
+ }
+
+ return (fildes);
+}
+
+/*
+ * ptsname(): return the pathname of the slave pseudo-terminal device
+ * associated with the specified master.
+ */
+char *
+ptsname(int fildes)
+{
+ static char slave[] = _PATH_DEV PTS_PREFIX "XY";
+ static char new_slave[] = _PATH_DEV NEWPTS_PREFIX "4294967295";
+ char *retval;
+ struct stat sbuf;
+
+ retval = NULL;
+
+ if (_fstat(fildes, &sbuf) == 0) {
+ if (!ISPTM(sbuf))
+ errno = EINVAL;
+ else {
+ if (!is_pts(fildes)) {
+ (void)snprintf(slave, sizeof(slave),
+ _PATH_DEV PTS_PREFIX "%s",
+ devname(sbuf.st_rdev, S_IFCHR) +
+ strlen(PTM_PREFIX));
+ retval = slave;
+ } else {
+ (void)snprintf(new_slave, sizeof(new_slave),
+ _PATH_DEV NEWPTS_PREFIX "%s",
+ devname(sbuf.st_rdev, S_IFCHR) +
+ strlen(PTM_PREFIX));
+ retval = new_slave;
+ }
+ }
+ }
+
+ return (retval);
+}
+
+/*
+ * unlockpt(): unlock a pseudo-terminal device pair.
+ */
+int
+unlockpt(int fildes)
+{
+ int retval;
+ struct stat sbuf;
+
+ /*
+ * Unlocking a master/slave pseudo-terminal pair has no meaning in a
+ * non-streams PTY environment. However, we do ensure fildes is a
+ * valid master pseudo-terminal device.
+ */
+ if ((retval = _fstat(fildes, &sbuf)) == 0 && !ISPTM(sbuf)) {
+ errno = EINVAL;
+ retval = -1;
+ }
+
+ return (retval);
+}
diff --git a/lib/libc/stdlib/hcreate.3 b/lib/libc/stdlib/hcreate.3
new file mode 100644
index 0000000..38743af
--- /dev/null
+++ b/lib/libc/stdlib/hcreate.3
@@ -0,0 +1,226 @@
+.\" $FreeBSD$
+.\"
+.Dd May 8, 2001
+.Os
+.Dt HCREATE 3
+.Sh NAME
+.Nm hcreate , hdestroy , hsearch
+.Nd manage hash search table
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In search.h
+.Ft int
+.Fn hcreate "size_t nel"
+.Ft void
+.Fn hdestroy void
+.Ft ENTRY *
+.Fn hsearch "ENTRY item" "ACTION action"
+.Sh DESCRIPTION
+The
+.Fn hcreate ,
+.Fn hdestroy ,
+and
+.Fn hsearch
+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.
+This number may be adjusted upward by the
+algorithm in order to obtain certain mathematically favorable circumstances.
+.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) containing 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.
+.Sh RETURN VALUES
+The
+.Fn hcreate
+function returns 0 if it cannot allocate sufficient space for the table;
+otherwise, it returns non-zero.
+.Pp
+The
+.Fn hdestroy
+function does not return a value.
+.Pp
+The
+.Fn hsearch
+function returns 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
+and
+.Fn hsearch
+functions may fail if:
+.Bl -tag -width Er
+.It Bq Er ENOMEM
+Insufficient storage space is available.
+.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 .
+.Sh BUGS
+The 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 0000000..5878085
--- /dev/null
+++ b/lib/libc/stdlib/hcreate.c
@@ -0,0 +1,185 @@
+/* $NetBSD: hcreate.c,v 1.2 2001/02/19 21:26:04 ross Exp $ */
+
+/*
+ * 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.
+ *
+ * <<Id: LICENSE,v 1.2 2000/06/14 15:57:33 cgd Exp>>
+ */
+
+/*
+ * hcreate() / hsearch() / hdestroy()
+ *
+ * SysV/XPG4 hash table functions.
+ *
+ * Implementation done based on NetBSD manual page and Solaris manual page,
+ * plus my own personal experience about how they're supposed to work.
+ *
+ * I tried to look at Knuth (as cited by the Solaris manual page), but
+ * nobody had a copy in the office, so...
+ */
+
+#include <sys/cdefs.h>
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: hcreate.c,v 1.2 2001/02/19 21:26:04 ross Exp $");
+#endif /* LIBC_SCCS and not lint */
+#endif
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <errno.h>
+#include <search.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * DO NOT MAKE THIS STRUCTURE LARGER THAN 32 BYTES (4 ptrs on 64-bit
+ * ptr machine) without adjusting MAX_BUCKETS_LG2 below.
+ */
+struct internal_entry {
+ SLIST_ENTRY(internal_entry) link;
+ ENTRY ent;
+};
+SLIST_HEAD(internal_head, internal_entry);
+
+#define MIN_BUCKETS_LG2 4
+#define MIN_BUCKETS (1 << MIN_BUCKETS_LG2)
+
+/*
+ * max * sizeof internal_entry must fit into size_t.
+ * assumes internal_entry is <= 32 (2^5) bytes.
+ */
+#define MAX_BUCKETS_LG2 (sizeof (size_t) * 8 - 1 - 5)
+#define MAX_BUCKETS ((size_t)1 << MAX_BUCKETS_LG2)
+
+/* Default hash function, from db/hash/hash_func.c */
+extern u_int32_t (*__default_hash)(const void *, size_t);
+
+static struct internal_head *htable;
+static size_t htablesize;
+
+int
+hcreate(size_t nel)
+{
+ size_t idx;
+ unsigned int p2;
+
+ /* Make sure this this isn't called when a table already exists. */
+ if (htable != NULL) {
+ errno = EINVAL;
+ return 0;
+ }
+
+ /* If nel is too small, make it min sized. */
+ if (nel < MIN_BUCKETS)
+ nel = MIN_BUCKETS;
+
+ /* If it's too large, cap it. */
+ if (nel > MAX_BUCKETS)
+ nel = MAX_BUCKETS;
+
+ /* If it's is not a power of two in size, round up. */
+ if ((nel & (nel - 1)) != 0) {
+ for (p2 = 0; nel != 0; p2++)
+ nel >>= 1;
+ nel = 1 << p2;
+ }
+
+ /* Allocate the table. */
+ htablesize = nel;
+ htable = malloc(htablesize * sizeof htable[0]);
+ if (htable == NULL) {
+ errno = ENOMEM;
+ return 0;
+ }
+
+ /* Initialize it. */
+ for (idx = 0; idx < htablesize; idx++)
+ SLIST_INIT(&htable[idx]);
+
+ return 1;
+}
+
+void
+hdestroy(void)
+{
+ struct internal_entry *ie;
+ size_t idx;
+
+ if (htable == NULL)
+ return;
+
+ for (idx = 0; idx < htablesize; idx++) {
+ while (!SLIST_EMPTY(&htable[idx])) {
+ ie = SLIST_FIRST(&htable[idx]);
+ SLIST_REMOVE_HEAD(&htable[idx], link);
+ free(ie->ent.key);
+ free(ie);
+ }
+ }
+ free(htable);
+ htable = NULL;
+}
+
+ENTRY *
+hsearch(ENTRY item, ACTION action)
+{
+ struct internal_head *head;
+ struct internal_entry *ie;
+ uint32_t hashval;
+ size_t len;
+
+ len = strlen(item.key);
+ hashval = (*__default_hash)(item.key, len);
+
+ head = &htable[hashval & (htablesize - 1)];
+ ie = SLIST_FIRST(head);
+ while (ie != NULL) {
+ if (strcmp(ie->ent.key, item.key) == 0)
+ break;
+ ie = SLIST_NEXT(ie, link);
+ }
+
+ if (ie != NULL)
+ return &ie->ent;
+ else if (action == FIND)
+ return NULL;
+
+ ie = malloc(sizeof *ie);
+ if (ie == NULL)
+ return NULL;
+ ie->ent.key = item.key;
+ ie->ent.data = item.data;
+
+ SLIST_INSERT_HEAD(head, ie, link);
+ return &ie->ent;
+}
diff --git a/lib/libc/stdlib/heapsort.c b/lib/libc/stdlib/heapsort.c
new file mode 100644
index 0000000..d37d199
--- /dev/null
+++ b/lib/libc/stdlib/heapsort.c
@@ -0,0 +1,185 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. 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. 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.
+ */
+
+#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>
+
+/*
+ * 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 ususally 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); \
+ } \
+}
+
+/*
+ * 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.
+ */
+int
+heapsort(vbase, nmemb, size, compar)
+ void *vbase;
+ size_t nmemb, size;
+ int (*compar)(const void *, const void *);
+{
+ int 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/imaxabs.3 b/lib/libc/stdlib/imaxabs.3
new file mode 100644
index 0000000..430f873
--- /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 0000000..35e3dee
--- /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 0000000..0ee0971
--- /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 0000000..7dae467
--- /dev/null
+++ b/lib/libc/stdlib/imaxdiv.c
@@ -0,0 +1,45 @@
+/*-
+ * 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 (numer >= 0 && retval.rem < 0) {
+ retval.quot++;
+ retval.rem -= denom;
+ }
+ return (retval);
+}
diff --git a/lib/libc/stdlib/insque.3 b/lib/libc/stdlib/insque.3
new file mode 100644
index 0000000..a54434c
--- /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 0000000..388e4d5
--- /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/l64a.c b/lib/libc/stdlib/l64a.c
new file mode 100644
index 0000000..bc10553
--- /dev/null
+++ b/lib/libc/stdlib/l64a.c
@@ -0,0 +1,52 @@
+/*
+ * 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 <stdlib.h>
+
+#define ADOT 46 /* ASCII '.' */
+#define ASLASH ADOT + 1 /* ASCII '/' */
+#define A0 48 /* ASCII '0' */
+#define AA 65 /* ASCII 'A' */
+#define Aa 97 /* ASCII 'a' */
+
+char *
+l64a(long value)
+{
+ static char buf[8];
+
+ (void)l64a_r(value, buf, sizeof(buf));
+ return (buf);
+}
+
+int
+l64a_r(long value, char *buffer, int buflen)
+{
+ long v;
+ int digit;
+
+ v = value & (long)0xffffffff;
+ for (; v != 0 && buflen > 1; buffer++, buflen--) {
+ digit = v & 0x3f;
+ if (digit < 2)
+ *buffer = digit + ADOT;
+ else if (digit < 12)
+ *buffer = digit + A0 - 2;
+ else if (digit < 38)
+ *buffer = digit + AA - 12;
+ else
+ *buffer = digit + Aa - 38;
+ v >>= 6;
+ }
+ return (v == 0 ? 0 : -1);
+}
diff --git a/lib/libc/stdlib/labs.3 b/lib/libc/stdlib/labs.3
new file mode 100644
index 0000000..2c8db6e
--- /dev/null
+++ b/lib/libc/stdlib/labs.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
+.\" 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. 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.
+.\"
+.\" @(#)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 0000000..36ae55d
--- /dev/null
+++ b/lib/libc/stdlib/labs.c
@@ -0,0 +1,47 @@
+/*-
+ * 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. 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.
+ */
+
+#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(j)
+ 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 0000000..eddf9db
--- /dev/null
+++ b/lib/libc/stdlib/ldiv.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. 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.
+.\"
+.\" @(#)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 0000000..37e95fa
--- /dev/null
+++ b/lib/libc/stdlib/ldiv.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. 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.
+ */
+
+#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 (num >= 0 && r.rem < 0) {
+ r.quot++;
+ r.rem -= denom;
+ }
+ return (r);
+}
diff --git a/lib/libc/stdlib/llabs.3 b/lib/libc/stdlib/llabs.3
new file mode 100644
index 0000000..8c031a9
--- /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 0000000..2bfbada
--- /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 0000000..976a997
--- /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 0000000..b34b65e
--- /dev/null
+++ b/lib/libc/stdlib/lldiv.c
@@ -0,0 +1,45 @@
+/*-
+ * 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 (numer >= 0 && retval.rem < 0) {
+ retval.quot++;
+ retval.rem -= denom;
+ }
+ return (retval);
+}
diff --git a/lib/libc/stdlib/lsearch.3 b/lib/libc/stdlib/lsearch.3
new file mode 100644
index 0000000..5e76724
--- /dev/null
+++ b/lib/libc/stdlib/lsearch.3
@@ -0,0 +1,105 @@
+.\"
+.\" 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 11, 2002
+.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 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 0000000..e4d1dd5
--- /dev/null
+++ b/lib/libc/stdlib/lsearch.c
@@ -0,0 +1,64 @@
+/*
+ * 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;
+
+ /*
+ * Cast to an integer value first to avoid the warning for removing
+ * 'const' via a cast.
+ */
+ ep = (uint8_t *)(uintptr_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/malloc.3 b/lib/libc/stdlib/malloc.3
new file mode 100644
index 0000000..b29509d
--- /dev/null
+++ b/lib/libc/stdlib/malloc.3
@@ -0,0 +1,473 @@
+.\" 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 April 4, 2006
+.Dt MALLOC 3
+.Os
+.Sh NAME
+.Nm malloc , calloc , realloc , free , reallocf , malloc_usable_size
+.Nd general purpose memory allocation functions
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft void *
+.Fn malloc "size_t size"
+.Ft void *
+.Fn calloc "size_t number" "size_t size"
+.Ft void *
+.Fn realloc "void *ptr" "size_t size"
+.Ft void *
+.Fn reallocf "void *ptr" "size_t size"
+.Ft void
+.Fn free "void *ptr"
+.Ft const char *
+.Va _malloc_options ;
+.Ft void
+.Fo \*(lp*_malloc_message\*(rp
+.Fa "const char *p1" "const char *p2" "const char *p3" "const char *p4"
+.Fc
+.In malloc_np.h
+.Ft size_t
+.Fn malloc_usable_size "const void *ptr"
+.Sh DESCRIPTION
+The
+.Fn malloc
+function allocates
+.Fa size
+bytes of uninitialized memory.
+The allocated space is suitably aligned (after possible pointer coercion)
+for storage of any type of object.
+.Pp
+The
+.Fn calloc
+function allocates space for
+.Fa number
+objects,
+each
+.Fa size
+bytes in length.
+The result is identical to calling
+.Fn malloc
+with an argument of
+.Dq "number * size" ,
+with the exception that the allocated memory is explicitly initialized
+to zero bytes.
+.Pp
+The
+.Fn realloc
+function changes the size of the previously allocated memory referenced by
+.Fa ptr
+to
+.Fa size
+bytes.
+The contents of the memory are unchanged up to the lesser of the new and
+old sizes.
+If the new size is larger,
+the value of the newly allocated portion of the memory is undefined.
+Upon success, the memory referenced by
+.Fa ptr
+is freed and a pointer to the newly allocated memory is returned.
+Note that
+.Fn realloc
+and
+.Fn reallocf
+may move the memory allocation, resulting in a different return value than
+.Fa ptr .
+If
+.Fa ptr
+is
+.Dv NULL ,
+the
+.Fn realloc
+function behaves identically to
+.Fn malloc
+for the specified size.
+.Pp
+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 realloc causing memory leaks in libraries.
+.Pp
+The
+.Fn free
+function causes the allocated memory referenced by
+.Fa ptr
+to be made available for future allocations.
+If
+.Fa ptr
+is
+.Dv NULL ,
+no action occurs.
+.Pp
+The
+.Fn malloc_usable_size
+function returns the usable size of the allocation pointed to by
+.Fa ptr .
+The return value may be larger than the size that was requested during
+allocation.
+.Fn malloc_usable_size
+is not a mechanism for in-place
+.Fn realloc ;
+rather it is provided solely as a tool for introspection purposes.
+Any discrepancy between the requested allocation size and the size reported by
+.Fn malloc_usable_size
+should not be depended on, since such behavior is entirely
+implementation-dependent.
+.Sh TUNING
+Once, when the first call is made to one of these memory allocation
+routines, various flags will be set or reset, which affect the
+workings of this allocator implementation.
+.Pp
+The
+.Dq name
+of the file referenced by the symbolic link named
+.Pa /etc/malloc.conf ,
+the value of the environment variable
+.Ev MALLOC_OPTIONS ,
+and the string pointed to by the global variable
+.Va _malloc_options
+will be interpreted, in that order, character by character as flags.
+.Pp
+Most flags are single letters,
+where uppercase indicates that the behavior is set, or on,
+and lowercase means that the behavior is not set, or off.
+.Bl -tag -width indent
+.It A
+All warnings (except for the warning about unknown
+flags being set) become fatal.
+The process will call
+.Xr abort 3
+in these cases.
+.It H
+Use
+.Xr madvise 2
+when pages within a chunk are no longer in use, but the chunk as a whole cannot
+yet be deallocated.
+This is primarily of use when swapping is a real possibility, due to the high
+overhead of the
+.Fn madvise
+system call.
+.It J
+Each byte of new memory allocated by
+.Fn malloc ,
+.Fn realloc
+or
+.Fn reallocf
+will be initialized to 0xa5.
+All memory returned by
+.Fn free ,
+.Fn realloc
+or
+.Fn reallocf
+will be initialized to 0x5a.
+This is intended for debugging and will impact performance negatively.
+.It K
+Increase/decrease the virtual memory chunk size by a factor of two.
+The default chunk size is 2 MB.
+This option can be specified multiple times.
+.It N
+Increase/decrease the number of arenas by a factor of two.
+The default number of arenas is four times the number of CPUs, or one if there
+is a single CPU.
+This option can be specified multiple times.
+.It P
+Various statistics are printed at program exit via an
+.Xr atexit 3
+function.
+This has the potential to cause deadlock for a multi-threaded process that exits
+while one or more threads are executing in the memory allocation functions.
+Therefore, this option should only be used with care; it is primarily intended
+as a performance tuning aid during application development.
+.It Q
+Increase/decrease the size of the allocation quantum by a factor of two.
+The default quantum is the minimum allowed by the architecture (typically 8 or
+16 bytes).
+This option can be specified multiple times.
+.It S
+Increase/decrease the size of the maximum size class that is a multiple of the
+quantum by a factor of two.
+Above this size, power-of-two spacing is used for size classes.
+The default value is 512 bytes.
+This option can be specified multiple times.
+.It U
+Generate
+.Dq utrace
+entries for
+.Xr ktrace 1 ,
+for all operations.
+Consult the source for details on this option.
+.It V
+Attempting to allocate zero bytes will return a
+.Dv NULL
+pointer instead of
+a valid pointer.
+(The default behavior is to make a minimal allocation and return a
+pointer to it.)
+This option is provided for System V compatibility.
+This option is incompatible with the
+.Dq X
+option.
+.It X
+Rather than return failure for any allocation function,
+display a diagnostic message on
+.Dv stderr
+and cause the program to drop
+core (using
+.Xr abort 3 ) .
+This option should be set at compile time by including the following in
+the source code:
+.Bd -literal -offset indent
+_malloc_options = "X";
+.Ed
+.It Z
+Each byte of new memory allocated by
+.Fn malloc ,
+.Fn realloc
+or
+.Fn reallocf
+will be initialized to 0x0.
+Note that this initialization only happens once for each byte, so
+.Fn realloc
+and
+.Fn reallocf
+calls do not zero memory that was previously allocated.
+This is intended for debugging and will impact performance negatively.
+.El
+.Pp
+The
+.Dq J
+and
+.Dq Z
+options are intended for testing and debugging.
+An application which changes its behavior when these options are used
+is flawed.
+.Sh RETURN VALUES
+The
+.Fn malloc
+and
+.Fn calloc
+functions return a pointer to the allocated memory if successful; otherwise
+a
+.Dv NULL
+pointer is returned and
+.Va errno
+is set to
+.Er ENOMEM .
+.Pp
+The
+.Fn realloc
+and
+.Fn reallocf
+functions return 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 realloc
+function always leaves the original buffer intact
+when an error occurs, whereas
+.Fn reallocf
+deallocates it in this case.
+.Pp
+The
+.Fn free
+function returns no value.
+.Pp
+The
+.Fn malloc_usable_size
+function returns the usable size of the allocation pointed to by
+.Fa ptr .
+.Sh IMPLEMENTATION NOTES
+This allocator uses multiple arenas in order to reduce lock contention for
+threaded programs on multi-processor systems.
+This works well with regard to threading scalability, but incurs some costs.
+There is a small fixed per-arena overhead, and additionally, arenas manage
+memory completely independently of each other, which means a small fixed
+increase in overall memory fragmentation.
+These overheads are not generally an issue, given the number of arenas normally
+used.
+Note that using substantially more arenas than the default is not likely to
+improve performance, mainly due to reduced cache performance.
+However, it may make sense to reduce the number of arenas if an application
+does not make much use of the allocation functions.
+.Pp
+Chunks manage their pages by using a power-of-two buddy allocation strategy.
+Each chunk maintains a page map that makes it possible to determine the state
+of any page in the chunk in constant time.
+Allocations that are no larger than one half of a page are managed in groups by
+page
+.Dq runs .
+Each run maintains a bitmap that tracks which regions are in use.
+Allocation requests that are no more than half the quantum (see the
+.Dq Q
+option) are rounded up to the nearest power of two (typically 2, 4, or 8).
+Allocation requests that are more than half the quantum, but no more than the
+maximum quantum-multiple size class (see the
+.Dq S
+option) are rounded up to the nearest multiple of the quantum.
+Allocation requests that are larger than the maximum quantum-multiple size
+class, but no larger than one half of a page, are rounded up to the nearest
+power of two.
+Allocation requests that are larger than half of a page, but no larger than half
+of a chunk (see the
+.Dq K
+option), are rounded up to the nearest run size.
+Allocation requests that are larger than half of a chunk are rounded up to the
+nearest multiple of the chunk size.
+.Pp
+Allocations are packed tightly together, which can be an issue for
+multi-threaded applications.
+If you need to assure that allocations do not suffer from cache line sharing,
+round your allocation requests up to the nearest multiple of the cache line
+size.
+.Sh DEBUGGING MALLOC PROBLEMS
+The first thing to do is to set the
+.Dq A
+option.
+This option forces a coredump (if possible) at the first sign of trouble,
+rather than the normal policy of trying to continue if at all possible.
+.Pp
+It is probably also a good idea to recompile the program with suitable
+options and symbols for debugger support.
+.Pp
+If the program starts to give unusual results, coredump or generally behave
+differently without emitting any of the messages mentioned in the next
+section, it is likely because it depends on the storage being filled with
+zero bytes.
+Try running it with the
+.Dq Z
+option set;
+if that improves the situation, this diagnosis has been confirmed.
+If the program still misbehaves,
+the likely problem is accessing memory outside the allocated area.
+.Pp
+Alternatively, if the symptoms are not easy to reproduce, setting the
+.Dq J
+option may help provoke the problem.
+.Pp
+In truly difficult cases, the
+.Dq U
+option, if supported by the kernel, can provide a detailed trace of
+all calls made to these functions.
+.Pp
+Unfortunately this implementation does not provide much detail about
+the problems it detects; the performance impact for storing such information
+would be prohibitive.
+There are a number of allocation implementations available on the Internet
+which focus on detecting and pinpointing problems by trading performance for
+extra sanity checks and detailed diagnostics.
+.Sh DIAGNOSTIC MESSAGES
+If any of the memory allocation/deallocation functions detect an error or
+warning condition, a message will be printed to file descriptor STDERR_FILENO.
+Errors will result in the process dumping core.
+If the
+.Dq A
+option is set, all warnings are treated as errors.
+.Pp
+The
+.Va _malloc_message
+variable allows the programmer to override the function which emits
+the text strings forming the errors and warnings if for some reason
+the
+.Dv stderr
+file descriptor is not suitable for this.
+Please note that doing anything which tries to allocate memory in
+this function is likely to result in a crash or deadlock.
+.Pp
+All messages are prefixed by:
+.Bl -diag
+.It <progname>: (malloc)
+.El
+.Sh ENVIRONMENT
+The following environment variables affect the execution of the allocation
+functions:
+.Bl -tag -width ".Ev MALLOC_OPTIONS"
+.It Ev MALLOC_OPTIONS
+If the environment variable
+.Ev MALLOC_OPTIONS
+is set, the characters it contains will be interpreted as flags to the
+allocation functions.
+.El
+.Sh EXAMPLES
+To dump core whenever a problem occurs:
+.Pp
+.Bd -literal -offset indent
+ln -s 'A' /etc/malloc.conf
+.Ed
+.Pp
+To specify in the source that a program does no return value checking
+on calls to these functions:
+.Bd -literal -offset indent
+_malloc_options = "X";
+.Ed
+.Sh SEE ALSO
+.Xr madvise 2 ,
+.Xr mmap 2 ,
+.Xr alloca 3 ,
+.Xr atexit 3 ,
+.Xr getpagesize 3 ,
+.Xr memory 3 ,
+.Xr posix_memalign 3
+.Sh STANDARDS
+The
+.Fn malloc ,
+.Fn calloc ,
+.Fn realloc
+and
+.Fn free
+functions conform to
+.St -isoC .
+.Sh HISTORY
+The
+.Fn reallocf
+function first appeared in
+.Fx 3.0 .
+.Pp
+The
+.Fn malloc_usable_size
+function first appeared in
+.Fx 7.0 .
diff --git a/lib/libc/stdlib/malloc.c b/lib/libc/stdlib/malloc.c
new file mode 100644
index 0000000..f25839f
--- /dev/null
+++ b/lib/libc/stdlib/malloc.c
@@ -0,0 +1,3641 @@
+/*-
+ * Copyright (C) 2006 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.
+ *
+ *******************************************************************************
+ *
+ * This allocator implementation is designed to provide scalable performance
+ * for multi-threaded programs on multi-processor systems. The following
+ * features are included for this purpose:
+ *
+ * + Multiple arenas are used if there are multiple CPUs, which reduces lock
+ * contention and cache sloshing.
+ *
+ * + Cache line sharing between arenas is avoided for internal data
+ * structures.
+ *
+ * + Memory is managed in chunks and runs (chunks can be split into runs using
+ * a binary buddy scheme), rather than as individual pages. This provides
+ * a constant-time mechanism for associating allocations with particular
+ * arenas.
+ *
+ * Allocation requests are rounded up to the nearest size class, and no record
+ * of the original request size is maintained. Allocations are broken into
+ * categories according to size class. Assuming runtime defaults, 4 kB pages
+ * and a 16 byte quantum, the size classes in each category are as follows:
+ *
+ * |====================================|
+ * | Category | Subcategory | Size |
+ * |====================================|
+ * | Small | Tiny | 2 |
+ * | | | 4 |
+ * | | | 8 |
+ * | |----------------+--------|
+ * | | Quantum-spaced | 16 |
+ * | | | 32 |
+ * | | | 48 |
+ * | | | ... |
+ * | | | 480 |
+ * | | | 496 |
+ * | | | 512 |
+ * | |----------------+--------|
+ * | | Sub-page | 1 kB |
+ * | | | 2 kB |
+ * |====================================|
+ * | Large | 4 kB |
+ * | | 8 kB |
+ * | | 16 kB |
+ * | | ... |
+ * | | 256 kB |
+ * | | 512 kB |
+ * | | 1 MB |
+ * |====================================|
+ * | Huge | 2 MB |
+ * | | 4 MB |
+ * | | 6 MB |
+ * | | ... |
+ * |====================================|
+ *
+ * A different mechanism is used for each category:
+ *
+ * Small : Each size class is segregated into its own set of runs. Each run
+ * maintains a bitmap of which regions are free/allocated.
+ *
+ * Large : Each allocation is backed by a dedicated run. Metadata are stored
+ * in the associated arena chunk header maps.
+ *
+ * Huge : Each allocation is backed by a dedicated contiguous set of chunks.
+ * Metadata are stored in a separate red-black tree.
+ *
+ *******************************************************************************
+ */
+
+/*
+ *******************************************************************************
+ *
+ * Ring macros.
+ *
+ *******************************************************************************
+ */
+
+/* Ring definitions. */
+#define qr(a_type) struct { \
+ a_type *qre_next; \
+ a_type *qre_prev; \
+}
+
+#define qr_initializer {NULL, NULL}
+
+/* Ring functions. */
+#define qr_new(a_qr, a_field) do { \
+ (a_qr)->a_field.qre_next = (a_qr); \
+ (a_qr)->a_field.qre_prev = (a_qr); \
+} while (0)
+
+#define qr_next(a_qr, a_field) ((a_qr)->a_field.qre_next)
+
+#define qr_prev(a_qr, a_field) ((a_qr)->a_field.qre_prev)
+
+#define qr_before_insert(a_qrelm, a_qr, a_field) do { \
+ (a_qr)->a_field.qre_prev = (a_qrelm)->a_field.qre_prev; \
+ (a_qr)->a_field.qre_next = (a_qrelm); \
+ (a_qr)->a_field.qre_prev->a_field.qre_next = (a_qr); \
+ (a_qrelm)->a_field.qre_prev = (a_qr); \
+} while (0)
+
+#define qr_after_insert(a_qrelm, a_qr, a_field) do { \
+ (a_qr)->a_field.qre_next = (a_qrelm)->a_field.qre_next; \
+ (a_qr)->a_field.qre_prev = (a_qrelm); \
+ (a_qr)->a_field.qre_next->a_field.qre_prev = (a_qr); \
+ (a_qrelm)->a_field.qre_next = (a_qr); \
+} while (0)
+
+#define qr_meld(a_qr_a, a_qr_b, a_type, a_field) do { \
+ a_type *t; \
+ (a_qr_a)->a_field.qre_prev->a_field.qre_next = (a_qr_b); \
+ (a_qr_b)->a_field.qre_prev->a_field.qre_next = (a_qr_a); \
+ t = (a_qr_a)->a_field.qre_prev; \
+ (a_qr_a)->a_field.qre_prev = (a_qr_b)->a_field.qre_prev; \
+ (a_qr_b)->a_field.qre_prev = t; \
+} while (0)
+
+/*
+ * qr_meld() and qr_split() are functionally equivalent, so there's no need to
+ * have two copies of the code.
+ */
+#define qr_split(a_qr_a, a_qr_b, a_type, a_field) \
+ qr_meld((a_qr_a), (a_qr_b), a_type, a_field)
+
+#define qr_remove(a_qr, a_field) do { \
+ (a_qr)->a_field.qre_prev->a_field.qre_next \
+ = (a_qr)->a_field.qre_next; \
+ (a_qr)->a_field.qre_next->a_field.qre_prev \
+ = (a_qr)->a_field.qre_prev; \
+ (a_qr)->a_field.qre_next = (a_qr); \
+ (a_qr)->a_field.qre_prev = (a_qr); \
+} while (0)
+
+#define qr_foreach(var, a_qr, a_field) \
+ for ((var) = (a_qr); \
+ (var) != NULL; \
+ (var) = (((var)->a_field.qre_next != (a_qr)) \
+ ? (var)->a_field.qre_next : NULL))
+
+#define qr_reverse_foreach(var, a_qr, a_field) \
+ for ((var) = ((a_qr) != NULL) ? qr_prev(a_qr, a_field) : NULL; \
+ (var) != NULL; \
+ (var) = (((var) != (a_qr)) \
+ ? (var)->a_field.qre_prev : NULL))
+
+/******************************************************************************/
+
+/*
+ * In order to disable various extra features that may have negative
+ * performance impacts, (assertions, expanded statistics), define
+ * NO_MALLOC_EXTRAS.
+ */
+/* #define NO_MALLOC_EXTRAS */
+
+#ifndef NO_MALLOC_EXTRAS
+# define MALLOC_DEBUG
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "libc_private.h"
+#ifdef MALLOC_DEBUG
+# define _LOCK_DEBUG
+#endif
+#include "spinlock.h"
+#include "namespace.h"
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <sys/stddef.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <sys/tree.h>
+#include <sys/uio.h>
+#include <sys/ktrace.h> /* Must come after several other sys/ includes. */
+
+#include <machine/atomic.h>
+#include <machine/cpufunc.h>
+#include <machine/vmparam.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <pthread.h>
+#include <sched.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+
+#include "un-namespace.h"
+
+/*
+ * Calculate statistics that can be used to get an idea of how well caching is
+ * working.
+ */
+#ifndef NO_MALLOC_EXTRAS
+# define MALLOC_STATS
+#endif
+
+#ifndef MALLOC_DEBUG
+# ifndef NDEBUG
+# define NDEBUG
+# endif
+#endif
+#include <assert.h>
+
+#ifdef MALLOC_DEBUG
+ /* Disable inlining to make debugging easier. */
+# define inline
+#endif
+
+/* Size of stack-allocated buffer passed to strerror_r(). */
+#define STRERROR_BUF 64
+
+/* Minimum alignment of allocations is 2^QUANTUM_2POW_MIN bytes. */
+#ifdef __i386__
+# define QUANTUM_2POW_MIN 4
+# define SIZEOF_PTR 4
+# define USE_BRK
+#endif
+#ifdef __ia64__
+# define QUANTUM_2POW_MIN 4
+# define SIZEOF_PTR 8
+# define NO_TLS
+#endif
+#ifdef __alpha__
+# define QUANTUM_2POW_MIN 4
+# define SIZEOF_PTR 8
+# define NO_TLS
+#endif
+#ifdef __sparc64__
+# define QUANTUM_2POW_MIN 4
+# define SIZEOF_PTR 8
+# define NO_TLS
+#endif
+#ifdef __amd64__
+# define QUANTUM_2POW_MIN 4
+# define SIZEOF_PTR 8
+#endif
+#ifdef __arm__
+# define QUANTUM_2POW_MIN 3
+# define SIZEOF_PTR 4
+# define USE_BRK
+# define NO_TLS
+#endif
+#ifdef __powerpc__
+# define QUANTUM_2POW_MIN 4
+# define SIZEOF_PTR 4
+# define USE_BRK
+#endif
+
+/* sizeof(int) == (1 << SIZEOF_INT_2POW). */
+#ifndef SIZEOF_INT_2POW
+# define SIZEOF_INT_2POW 2
+#endif
+
+/* We can't use TLS in non-PIC programs, since TLS relies on loader magic. */
+#if (!defined(PIC) && !defined(NO_TLS))
+# define NO_TLS
+#endif
+
+/*
+ * Size and alignment of memory chunks that are allocated by the OS's virtual
+ * memory system.
+ *
+ * chunksize limits:
+ *
+ * 2^(pagesize_2pow - 1 + RUN_MIN_REGS_2POW) <= chunk_size <= 2^28
+ */
+#define CHUNK_2POW_DEFAULT 21
+#define CHUNK_2POW_MAX 28
+
+/*
+ * Maximum size of L1 cache line. This is used to avoid cache line aliasing,
+ * so over-estimates are okay (up to a point), but under-estimates will
+ * negatively affect performance.
+ */
+#define CACHELINE_2POW 6
+#define CACHELINE ((size_t)(1 << CACHELINE_2POW))
+
+/*
+ * Maximum size class that is a multiple of the quantum, but not (necessarily)
+ * a power of 2. Above this size, allocations are rounded up to the nearest
+ * power of 2.
+ */
+#define SMALL_MAX_2POW_DEFAULT 9
+#define SMALL_MAX_DEFAULT (1 << SMALL_MAX_2POW_DEFAULT)
+
+/*
+ * Minimum number of regions that must fit into a run that serves quantum-size
+ * bin allocations.
+ *
+ * Note that if this is set too low, space will be wasted if there are size
+ * classes that are small enough that RUN_MIN_REGS regions don't fill a page.
+ * If this is set too high, then the overhead of searching through the bitmap
+ * that tracks region usage will become excessive.
+ */
+#define RUN_MIN_REGS_2POW 10
+#define RUN_MIN_REGS (1 << RUN_MIN_REGS_2POW)
+
+/*
+ * Maximum number of pages for a run that is used for bin allocations.
+ *
+ * Note that if this is set too low, then fragmentation for the largest bin
+ * size classes will be high. If this is set too high, then even small
+ * programs will often have to allocate more than two chunks early on.
+ */
+#define RUN_MAX_PAGES_2POW 4
+#define RUN_MAX_PAGES (1 << RUN_MAX_PAGES_2POW)
+
+/******************************************************************************/
+
+/*
+ * Mutexes based on spinlocks. We can't use normal pthread mutexes, because
+ * they require malloc()ed memory.
+ */
+typedef struct {
+ spinlock_t lock;
+} malloc_mutex_t;
+
+/* Set to true once the allocator has been initialized. */
+static bool malloc_initialized = false;
+
+/* Used to avoid initialization races. */
+static malloc_mutex_t init_lock = {_SPINLOCK_INITIALIZER};
+
+/******************************************************************************/
+/*
+ * Statistics data structures.
+ */
+
+#ifdef MALLOC_STATS
+
+typedef struct malloc_bin_stats_s malloc_bin_stats_t;
+struct malloc_bin_stats_s {
+ /*
+ * Number of allocation requests that corresponded to the size of this
+ * bin.
+ */
+ uint64_t nrequests;
+
+ /* Total number of runs created for this bin's size class. */
+ uint64_t nruns;
+
+ /*
+ * Total number of run promotions/demotions for this bin's size class.
+ */
+ uint64_t npromote;
+ uint64_t ndemote;
+
+ /* High-water mark for this bin. */
+ unsigned long highruns;
+
+ /* Current number of runs in this bin. */
+ unsigned long curruns;
+};
+
+typedef struct arena_stats_s arena_stats_t;
+struct arena_stats_s {
+ /* Total byte count of allocated memory, not including overhead. */
+ size_t allocated;
+
+ /* Number of times each function was called. */
+ uint64_t nmalloc;
+ uint64_t ndalloc;
+ uint64_t nmadvise;
+
+ /* Number of large allocation requests. */
+ uint64_t large_nrequests;
+};
+
+typedef struct chunk_stats_s chunk_stats_t;
+struct chunk_stats_s {
+ /* Number of chunks that were allocated. */
+ uint64_t nchunks;
+
+ /* High-water mark for number of chunks allocated. */
+ unsigned long highchunks;
+
+ /*
+ * Current number of chunks allocated. This value isn't maintained for
+ * any other purpose, so keep track of it in order to be able to set
+ * highchunks.
+ */
+ unsigned long curchunks;
+};
+
+#endif /* #ifdef MALLOC_STATS */
+
+/******************************************************************************/
+/*
+ * Chunk data structures.
+ */
+
+/* Tree of chunks. */
+typedef struct chunk_node_s chunk_node_t;
+struct chunk_node_s {
+ /* Linkage for the chunk tree. */
+ RB_ENTRY(chunk_node_s) link;
+
+ /*
+ * Pointer to the chunk that this tree node is responsible for. In some
+ * (but certainly not all) cases, this data structure is placed at the
+ * beginning of the corresponding chunk, so this field may point to this
+ * node.
+ */
+ void *chunk;
+
+ /* Total chunk size. */
+ size_t size;
+};
+typedef struct chunk_tree_s chunk_tree_t;
+RB_HEAD(chunk_tree_s, chunk_node_s);
+
+/******************************************************************************/
+/*
+ * Arena data structures.
+ */
+
+typedef struct arena_s arena_t;
+typedef struct arena_bin_s arena_bin_t;
+
+typedef struct arena_chunk_map_s arena_chunk_map_t;
+struct arena_chunk_map_s {
+ bool free:1;
+ bool large:1;
+ unsigned npages:15; /* Limiting factor for CHUNK_2POW_MAX. */
+ unsigned pos:15;
+};
+
+/* Arena chunk header. */
+typedef struct arena_chunk_s arena_chunk_t;
+struct arena_chunk_s {
+ /* Arena that owns the chunk. */
+ arena_t *arena;
+
+ /* Linkage for the arena's chunk tree. */
+ RB_ENTRY(arena_chunk_s) link;
+
+ /*
+ * Number of pages in use. This is maintained in order to make
+ * detection of empty chunks fast.
+ */
+ uint32_t pages_used;
+
+ /*
+ * Array of counters that keeps track of how many free runs of each
+ * size are available in this chunk. This table is sized at compile
+ * time, which is wasteful. However, due to unrelated rounding, this
+ * doesn't actually waste any otherwise useful space.
+ *
+ * index == 2^n pages
+ *
+ * index | npages
+ * ------+-------
+ * 0 | 1
+ * 1 | 2
+ * 2 | 4
+ * 3 | 8
+ * :
+ */
+ uint32_t nfree_runs[CHUNK_2POW_MAX/* - PAGE_SHIFT */];
+
+ /* Map of pages within chunk that keeps track of free/large/small. */
+ arena_chunk_map_t map[1]; /* Dynamically sized. */
+};
+typedef struct arena_chunk_tree_s arena_chunk_tree_t;
+RB_HEAD(arena_chunk_tree_s, arena_chunk_s);
+
+typedef struct arena_run_s arena_run_t;
+struct arena_run_s {
+ /* Linkage for run rings. */
+ qr(arena_run_t) link;
+
+#ifdef MALLOC_DEBUG
+ uint32_t magic;
+# define ARENA_RUN_MAGIC 0x384adf93
+#endif
+
+ /* Bin this run is associated with. */
+ arena_bin_t *bin;
+
+ /* Bitmask of in-use regions (0: in use, 1: free). */
+#define REGS_MASK_NELMS \
+ (1 << (RUN_MIN_REGS_2POW - SIZEOF_INT_2POW - 2))
+ unsigned regs_mask[REGS_MASK_NELMS];
+
+ /* Index of first element that might have a free region. */
+ unsigned regs_minelm;
+
+ /* Number of free regions in run. */
+ unsigned nfree;
+
+ /*
+ * Current quartile for this run, one of: {RUN_QINIT, RUN_Q0, RUN_25,
+ * RUN_Q50, RUN_Q75, RUN_Q100}.
+ */
+#define RUN_QINIT 0
+#define RUN_Q0 1
+#define RUN_Q25 2
+#define RUN_Q50 3
+#define RUN_Q75 4
+#define RUN_Q100 5
+ unsigned quartile;
+
+ /*
+ * Limits on the number of free regions for the fullness quartile this
+ * run is currently in. If nfree goes outside these limits, the run
+ * is moved to a different fullness quartile.
+ */
+ unsigned free_max;
+ unsigned free_min;
+};
+
+/* Used for run ring headers, where the run isn't actually used. */
+typedef struct arena_run_link_s arena_run_link_t;
+struct arena_run_link_s {
+ /* Linkage for run rings. */
+ qr(arena_run_t) link;
+};
+
+struct arena_bin_s {
+ /*
+ * Current run being used to service allocations of this bin's size
+ * class.
+ */
+ arena_run_t *runcur;
+
+ /*
+ * Links into rings of runs, of various fullnesses (names indicate
+ * approximate lower bounds). A new run conceptually starts off in
+ * runsinit, and it isn't inserted into the runs0 ring until it
+ * reaches 25% full (hysteresis mechanism). For the run to be moved
+ * again, it must become either empty or 50% full. Thus, each ring
+ * contains runs that are within 50% above the advertised fullness for
+ * the ring. This provides a low-overhead mechanism for segregating
+ * runs into approximate fullness classes.
+ *
+ * Conceptually, there is a runs100 that contains completely full runs.
+ * Since we don't need to search for these runs though, no runs100 ring
+ * is actually maintained.
+ *
+ * These rings are useful when looking for an existing run to use when
+ * runcur is no longer usable. We look for usable runs in the
+ * following order:
+ *
+ * 1) runs50
+ * 2) runs25
+ * 3) runs0
+ * 4) runs75
+ *
+ * runs75 isn't a good place to look, because it contains runs that may
+ * be nearly completely full. Still, we look there as a last resort in
+ * order to avoid allocating a new run if at all possible.
+ */
+ /* arena_run_link_t runsinit; 0% <= fullness < 25% */
+ arena_run_link_t runs0; /* 0% < fullness < 50% */
+ arena_run_link_t runs25; /* 25% < fullness < 75% */
+ arena_run_link_t runs50; /* 50% < fullness < 100% */
+ arena_run_link_t runs75; /* 75% < fullness < 100% */
+ /* arena_run_link_t runs100; fullness == 100% */
+
+ /* Size of regions in a run for this bin's size class. */
+ size_t reg_size;
+
+ /* Total size of a run for this bin's size class. */
+ size_t run_size;
+
+ /* Total number of regions in a run for this bin's size class. */
+ uint32_t nregs;
+
+ /* Offset of first region in a run for this bin's size class. */
+ uint32_t reg0_offset;
+
+#ifdef MALLOC_STATS
+ /* Bin statistics. */
+ malloc_bin_stats_t stats;
+#endif
+};
+
+struct arena_s {
+#ifdef MALLOC_DEBUG
+ uint32_t magic;
+# define ARENA_MAGIC 0x947d3d24
+#endif
+
+ /* All operations on this arena require that mtx be locked. */
+ malloc_mutex_t mtx;
+
+#ifdef MALLOC_STATS
+ arena_stats_t stats;
+#endif
+
+ /*
+ * Tree of chunks this arena manages.
+ */
+ arena_chunk_tree_t chunks;
+
+ /*
+ * bins is used to store rings of free regions of the following sizes,
+ * assuming a 16-byte quantum, 4kB pagesize, and default MALLOC_OPTIONS.
+ *
+ * bins[i] | size |
+ * --------+------+
+ * 0 | 2 |
+ * 1 | 4 |
+ * 2 | 8 |
+ * --------+------+
+ * 3 | 16 |
+ * 4 | 32 |
+ * 5 | 48 |
+ * 6 | 64 |
+ * : :
+ * : :
+ * 33 | 496 |
+ * 34 | 512 |
+ * --------+------+
+ * 35 | 1024 |
+ * 36 | 2048 |
+ * --------+------+
+ */
+ arena_bin_t bins[1]; /* Dynamically sized. */
+};
+
+/******************************************************************************/
+/*
+ * Data.
+ */
+
+/* Used as a special "nil" return value for malloc(0). */
+static const int nil;
+
+/* Number of CPUs. */
+static unsigned ncpus;
+
+/* VM page size. */
+static unsigned pagesize;
+static unsigned pagesize_2pow;
+
+/* Various bin-related settings. */
+static size_t bin_maxclass; /* Max size class for bins. */
+static unsigned ntbins; /* Number of (2^n)-spaced tiny bins. */
+static unsigned nqbins; /* Number of quantum-spaced bins. */
+static unsigned nsbins; /* Number of (2^n)-spaced sub-page bins. */
+static size_t small_min;
+static size_t small_max;
+static unsigned tiny_min_2pow;
+
+/* Various quantum-related settings. */
+static size_t quantum;
+static size_t quantum_mask; /* (quantum - 1). */
+
+/* Various chunk-related settings. */
+static size_t chunk_size;
+static size_t chunk_size_mask; /* (chunk_size - 1). */
+static size_t arena_maxclass; /* Max size class for arenas. */
+static unsigned arena_chunk_maplen;
+
+/********/
+/*
+ * Chunks.
+ */
+
+/* Protects chunk-related data structures. */
+static malloc_mutex_t chunks_mtx;
+
+/* Tree of chunks that are stand-alone huge allocations. */
+static chunk_tree_t huge;
+
+#ifdef USE_BRK
+/*
+ * Try to use brk for chunk-size allocations, due to address space constraints.
+ */
+/* Result of first sbrk(0) call. */
+static void *brk_base;
+/* Current end of brk, or ((void *)-1) if brk is exhausted. */
+static void *brk_prev;
+/* Current upper limit on brk addresses. */
+static void *brk_max;
+#endif
+
+#ifdef MALLOC_STATS
+/*
+ * Byte counters for allocated/total space used by the chunks in the huge
+ * allocations tree.
+ */
+static uint64_t huge_nmalloc;
+static uint64_t huge_ndalloc;
+static size_t huge_allocated;
+#endif
+
+/*
+ * Tree of chunks that were previously allocated. This is used when allocating
+ * chunks, in an attempt to re-use address space.
+ */
+static chunk_tree_t old_chunks;
+
+/****************************/
+/*
+ * base (internal allocation).
+ */
+
+/*
+ * Current chunk that is being used for internal memory allocations. This
+ * chunk is carved up in cacheline-size quanta, so that there is no chance of
+ * false cache line sharing.
+ */
+static void *base_chunk;
+static void *base_next_addr;
+static void *base_past_addr; /* Addr immediately past base_chunk. */
+static chunk_node_t *base_chunk_nodes; /* LIFO cache of chunk nodes. */
+static malloc_mutex_t base_mtx;
+#ifdef MALLOC_STATS
+static uint64_t base_total;
+#endif
+
+/********/
+/*
+ * Arenas.
+ */
+
+/*
+ * Arenas that are used to service external requests. Not all elements of the
+ * arenas array are necessarily used; arenas are created lazily as needed.
+ */
+static arena_t **arenas;
+static unsigned narenas;
+#ifndef NO_TLS
+static unsigned next_arena;
+#endif
+static malloc_mutex_t arenas_mtx; /* Protects arenas initialization. */
+
+#ifndef NO_TLS
+/*
+ * Map of pthread_self() --> arenas[???], used for selecting an arena to use
+ * for allocations.
+ */
+static __thread arena_t *arenas_map;
+#endif
+
+#ifdef MALLOC_STATS
+/* Chunk statistics. */
+static chunk_stats_t stats_chunks;
+#endif
+
+/*******************************/
+/*
+ * Runtime configuration options.
+ */
+const char *_malloc_options;
+
+#ifndef NO_MALLOC_EXTRAS
+static bool opt_abort = true;
+static bool opt_junk = true;
+#else
+static bool opt_abort = false;
+static bool opt_junk = false;
+#endif
+static bool opt_hint = false;
+static bool opt_print_stats = false;
+static size_t opt_quantum_2pow = QUANTUM_2POW_MIN;
+static size_t opt_small_max_2pow = SMALL_MAX_2POW_DEFAULT;
+static size_t opt_chunk_2pow = CHUNK_2POW_DEFAULT;
+static bool opt_utrace = false;
+static bool opt_sysv = false;
+static bool opt_xmalloc = false;
+static bool opt_zero = false;
+static int32_t opt_narenas_lshift = 0;
+
+typedef struct {
+ void *p;
+ size_t s;
+ void *r;
+} malloc_utrace_t;
+
+#define UTRACE(a, b, c) \
+ if (opt_utrace) { \
+ malloc_utrace_t ut = {a, b, c}; \
+ utrace(&ut, sizeof(ut)); \
+ }
+
+/******************************************************************************/
+/*
+ * Begin function prototypes for non-inline static functions.
+ */
+
+static void malloc_mutex_init(malloc_mutex_t *a_mutex);
+static void wrtmessage(const char *p1, const char *p2, const char *p3,
+ const char *p4);
+static void malloc_printf(const char *format, ...);
+static void *base_alloc(size_t size);
+static chunk_node_t *base_chunk_node_alloc(void);
+static void base_chunk_node_dealloc(chunk_node_t *node);
+#ifdef MALLOC_STATS
+static void stats_print(arena_t *arena);
+#endif
+static void *pages_map(void *addr, size_t size);
+static void pages_unmap(void *addr, size_t size);
+static void *chunk_alloc(size_t size);
+static void chunk_dealloc(void *chunk, size_t size);
+#ifndef NO_TLS
+static arena_t *choose_arena_hard(void);
+#endif
+static void arena_run_split(arena_t *arena, arena_run_t *run, bool large,
+ size_t size);
+static arena_chunk_t *arena_chunk_alloc(arena_t *arena);
+static void arena_chunk_dealloc(arena_chunk_t *chunk);
+static void arena_bin_run_promote(arena_t *arena, arena_bin_t *bin,
+ arena_run_t *run, size_t size);
+static void arena_bin_run_demote(arena_t *arena, arena_bin_t *bin,
+ arena_run_t *run, size_t size);
+static arena_run_t *arena_run_alloc(arena_t *arena, bool large, size_t size);
+static void arena_run_dalloc(arena_t *arena, arena_run_t *run, size_t size);
+static arena_run_t *arena_bin_nonfull_run_get(arena_t *arena, arena_bin_t *bin,
+ size_t size);
+static void *arena_bin_malloc_hard(arena_t *arena, arena_bin_t *bin,
+ size_t size);
+static void *arena_malloc(arena_t *arena, size_t size);
+static size_t arena_salloc(const void *ptr);
+static void *arena_ralloc(void *ptr, size_t size, size_t oldsize);
+static void arena_dalloc(arena_t *arena, arena_chunk_t *chunk, void *ptr);
+static bool arena_new(arena_t *arena);
+static arena_t *arenas_extend(unsigned ind);
+static void *huge_malloc(size_t size);
+static void *huge_ralloc(void *ptr, size_t size, size_t oldsize);
+static void huge_dalloc(void *ptr);
+static void *imalloc(size_t size);
+static void *ipalloc(size_t alignment, size_t size);
+static void *icalloc(size_t size);
+static size_t isalloc(const void *ptr);
+static void *iralloc(void *ptr, size_t size);
+static void idalloc(void *ptr);
+static void malloc_print_stats(void);
+static bool malloc_init_hard(void);
+
+/*
+ * End function prototypes.
+ */
+/******************************************************************************/
+/*
+ * Begin mutex.
+ */
+
+static void
+malloc_mutex_init(malloc_mutex_t *a_mutex)
+{
+ static const spinlock_t lock = _SPINLOCK_INITIALIZER;
+
+ a_mutex->lock = lock;
+}
+
+static inline void
+malloc_mutex_lock(malloc_mutex_t *a_mutex)
+{
+
+ if (__isthreaded)
+ _SPINLOCK(&a_mutex->lock);
+}
+
+static inline void
+malloc_mutex_unlock(malloc_mutex_t *a_mutex)
+{
+
+ if (__isthreaded)
+ _SPINUNLOCK(&a_mutex->lock);
+}
+
+/*
+ * End mutex.
+ */
+/******************************************************************************/
+/*
+ * Begin Utility functions/macros.
+ */
+
+/* Return the chunk address for allocation address a. */
+#define CHUNK_ADDR2BASE(a) \
+ ((void *)((uintptr_t)(a) & ~chunk_size_mask))
+
+/* Return the chunk offset of address a. */
+#define CHUNK_ADDR2OFFSET(a) \
+ ((size_t)((uintptr_t)(a) & chunk_size_mask))
+
+/* Return the smallest chunk multiple that is >= s. */
+#define CHUNK_CEILING(s) \
+ (((s) + chunk_size_mask) & ~chunk_size_mask)
+
+/* Return the smallest cacheline multiple that is >= s. */
+#define CACHELINE_CEILING(s) \
+ (((s) + (CACHELINE - 1)) & ~(CACHELINE - 1))
+
+/* Return the smallest quantum multiple that is >= a. */
+#define QUANTUM_CEILING(a) \
+ (((a) + quantum_mask) & ~quantum_mask)
+
+/* Compute the smallest power of 2 that is >= x. */
+static inline size_t
+pow2_ceil(size_t x)
+{
+
+ x--;
+ x |= x >> 1;
+ x |= x >> 2;
+ x |= x >> 4;
+ x |= x >> 8;
+ x |= x >> 16;
+#if (SIZEOF_PTR == 8)
+ x |= x >> 32;
+#endif
+ x++;
+ return (x);
+}
+
+static void
+wrtmessage(const char *p1, const char *p2, const char *p3, const char *p4)
+{
+
+ _write(STDERR_FILENO, p1, strlen(p1));
+ _write(STDERR_FILENO, p2, strlen(p2));
+ _write(STDERR_FILENO, p3, strlen(p3));
+ _write(STDERR_FILENO, p4, strlen(p4));
+}
+
+void (*_malloc_message)(const char *p1, const char *p2, const char *p3,
+ const char *p4) = wrtmessage;
+
+/*
+ * Print to stderr in such a way as to (hopefully) avoid memory allocation.
+ */
+static void
+malloc_printf(const char *format, ...)
+{
+ char buf[4096];
+ va_list ap;
+
+ va_start(ap, format);
+ vsnprintf(buf, sizeof(buf), format, ap);
+ va_end(ap);
+ _malloc_message(buf, "", "", "");
+}
+
+/******************************************************************************/
+
+static void *
+base_alloc(size_t size)
+{
+ void *ret;
+ size_t csize;
+
+ /* Round size up to nearest multiple of the cacheline size. */
+ csize = CACHELINE_CEILING(size);
+
+ malloc_mutex_lock(&base_mtx);
+
+ /* Make sure there's enough space for the allocation. */
+ if ((uintptr_t)base_next_addr + csize > (uintptr_t)base_past_addr) {
+ void *tchunk;
+
+ assert(csize <= chunk_size);
+
+ tchunk = chunk_alloc(chunk_size);
+ if (tchunk == NULL) {
+ ret = NULL;
+ goto RETURN;
+ }
+ base_chunk = tchunk;
+ base_next_addr = (void *)base_chunk;
+ base_past_addr = (void *)((uintptr_t)base_chunk + chunk_size);
+#ifdef MALLOC_STATS
+ base_total += chunk_size;
+#endif
+ }
+
+ /* Allocate. */
+ ret = base_next_addr;
+ base_next_addr = (void *)((uintptr_t)base_next_addr + csize);
+
+RETURN:
+ malloc_mutex_unlock(&base_mtx);
+ return (ret);
+}
+
+static chunk_node_t *
+base_chunk_node_alloc(void)
+{
+ chunk_node_t *ret;
+
+ malloc_mutex_lock(&base_mtx);
+ if (base_chunk_nodes != NULL) {
+ ret = base_chunk_nodes;
+ base_chunk_nodes = *(chunk_node_t **)ret;
+ malloc_mutex_unlock(&base_mtx);
+ } else {
+ malloc_mutex_unlock(&base_mtx);
+ ret = (chunk_node_t *)base_alloc(sizeof(chunk_node_t));
+ }
+
+ return (ret);
+}
+
+static void
+base_chunk_node_dealloc(chunk_node_t *node)
+{
+
+ malloc_mutex_lock(&base_mtx);
+ *(chunk_node_t **)node = base_chunk_nodes;
+ base_chunk_nodes = node;
+ malloc_mutex_unlock(&base_mtx);
+}
+
+/******************************************************************************/
+
+#ifdef MALLOC_STATS
+static void
+stats_print(arena_t *arena)
+{
+ unsigned i;
+ int gap_start;
+
+ malloc_printf("allocated: %zu\n", arena->stats.allocated);
+
+ malloc_printf("calls:\n");
+ malloc_printf(" %12s %12s %12s\n", "nmalloc","ndalloc", "nmadvise");
+ malloc_printf(" %12llu %12llu %12llu\n",
+ arena->stats.nmalloc, arena->stats.ndalloc, arena->stats.nmadvise);
+
+ malloc_printf("large requests: %llu\n", arena->stats.large_nrequests);
+
+ malloc_printf("bins:\n");
+ malloc_printf("%13s %1s %4s %5s %6s %9s %5s %6s %7s %6s %6s\n",
+ "bin", "", "size", "nregs", "run_sz", "nrequests", "nruns",
+ "hiruns", "curruns", "npromo", "ndemo");
+ for (i = 0, gap_start = -1; i < ntbins + nqbins + nsbins; i++) {
+ if (arena->bins[i].stats.nrequests == 0) {
+ if (gap_start == -1)
+ gap_start = i;
+ } else {
+ if (gap_start != -1) {
+ if (i > gap_start + 1) {
+ /* Gap of more than one size class. */
+ malloc_printf("[%u..%u]\n",
+ gap_start, i - 1);
+ } else {
+ /* Gap of one size class. */
+ malloc_printf("[%u]\n", gap_start);
+ }
+ gap_start = -1;
+ }
+ malloc_printf(
+ "%13u %1s %4u %5u %6u %9llu %5llu"
+ " %6lu %7lu %6llu %6llu\n",
+ i,
+ i < ntbins ? "T" : i < ntbins + nqbins ? "Q" : "S",
+ arena->bins[i].reg_size,
+ arena->bins[i].nregs,
+ arena->bins[i].run_size,
+ arena->bins[i].stats.nrequests,
+ arena->bins[i].stats.nruns,
+ arena->bins[i].stats.highruns,
+ arena->bins[i].stats.curruns,
+ arena->bins[i].stats.npromote,
+ arena->bins[i].stats.ndemote);
+ }
+ }
+ if (gap_start != -1) {
+ if (i > gap_start + 1) {
+ /* Gap of more than one size class. */
+ malloc_printf("[%u..%u]\n", gap_start, i - 1);
+ } else {
+ /* Gap of one size class. */
+ malloc_printf("[%u]\n", gap_start);
+ }
+ }
+}
+#endif
+
+/*
+ * End Utility functions/macros.
+ */
+/******************************************************************************/
+/*
+ * Begin chunk management functions.
+ */
+
+static inline int
+chunk_comp(chunk_node_t *a, chunk_node_t *b)
+{
+
+ assert(a != NULL);
+ assert(b != NULL);
+
+ if ((uintptr_t)a->chunk < (uintptr_t)b->chunk)
+ return (-1);
+ else if (a->chunk == b->chunk)
+ return (0);
+ else
+ return (1);
+}
+
+/* Generate red-black tree code for chunks. */
+RB_GENERATE_STATIC(chunk_tree_s, chunk_node_s, link, chunk_comp);
+
+static void *
+pages_map(void *addr, size_t size)
+{
+ void *ret;
+
+ /*
+ * We don't use MAP_FIXED here, because it can cause the *replacement*
+ * of existing mappings, and we only want to create new mappings.
+ */
+ ret = mmap(addr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON,
+ -1, 0);
+ assert(ret != NULL);
+
+ if (ret == MAP_FAILED)
+ ret = NULL;
+ else if (addr != NULL && ret != addr) {
+ /*
+ * We succeeded in mapping memory, but not in the right place.
+ */
+ if (munmap(ret, size) == -1) {
+ char buf[STRERROR_BUF];
+
+ strerror_r(errno, buf, sizeof(buf));
+ malloc_printf("%s: (malloc) Error in munmap(): %s\n",
+ _getprogname(), buf);
+ if (opt_abort)
+ abort();
+ }
+ ret = NULL;
+ }
+
+ assert(ret == NULL || (addr == NULL && ret != addr)
+ || (addr != NULL && ret == addr));
+ return (ret);
+}
+
+static void
+pages_unmap(void *addr, size_t size)
+{
+
+ if (munmap(addr, size) == -1) {
+ char buf[STRERROR_BUF];
+
+ strerror_r(errno, buf, sizeof(buf));
+ malloc_printf("%s: (malloc) Error in munmap(): %s\n",
+ _getprogname(), buf);
+ if (opt_abort)
+ abort();
+ }
+}
+
+static void *
+chunk_alloc(size_t size)
+{
+ void *ret, *chunk;
+ chunk_node_t *tchunk, *delchunk;
+
+ assert(size != 0);
+ assert(size % chunk_size == 0);
+
+ malloc_mutex_lock(&chunks_mtx);
+
+ if (size == chunk_size) {
+ /*
+ * Check for address ranges that were previously chunks and try
+ * to use them.
+ */
+
+ tchunk = RB_MIN(chunk_tree_s, &old_chunks);
+ while (tchunk != NULL) {
+ /* Found an address range. Try to recycle it. */
+
+ chunk = tchunk->chunk;
+ delchunk = tchunk;
+ tchunk = RB_NEXT(chunk_tree_s, &old_chunks, delchunk);
+
+ /* Remove delchunk from the tree. */
+ RB_REMOVE(chunk_tree_s, &old_chunks, delchunk);
+ base_chunk_node_dealloc(delchunk);
+
+#ifdef USE_BRK
+ if ((uintptr_t)chunk >= (uintptr_t)brk_base
+ && (uintptr_t)chunk < (uintptr_t)brk_max) {
+ /* Re-use a previously freed brk chunk. */
+ ret = chunk;
+ goto RETURN;
+ }
+#endif
+ if ((ret = pages_map(chunk, size)) != NULL) {
+ /* Success. */
+ goto RETURN;
+ }
+ }
+ }
+
+#ifdef USE_BRK
+ /*
+ * Try to create allocations in brk, in order to make full use of
+ * limited address space.
+ */
+ if (brk_prev != (void *)-1) {
+ void *brk_cur;
+ intptr_t incr;
+
+ /*
+ * The loop is necessary to recover from races with other
+ * threads that are using brk for something other than malloc.
+ */
+ do {
+ /* Get the current end of brk. */
+ brk_cur = sbrk(0);
+
+ /*
+ * Calculate how much padding is necessary to
+ * chunk-align the end of brk.
+ */
+ incr = (intptr_t)size
+ - (intptr_t)CHUNK_ADDR2OFFSET(brk_cur);
+ if (incr == size) {
+ ret = brk_cur;
+ } else {
+ ret = (void *)(intptr_t)brk_cur + incr;
+ incr += size;
+ }
+
+ brk_prev = sbrk(incr);
+ if (brk_prev == brk_cur) {
+ /* Success. */
+ brk_max = (void *)(intptr_t)ret + size;
+ goto RETURN;
+ }
+ } while (brk_prev != (void *)-1);
+ }
+#endif
+
+ /*
+ * Try to over-allocate, but allow the OS to place the allocation
+ * anywhere. Beware of size_t wrap-around.
+ */
+ if (size + chunk_size > size) {
+ if ((ret = pages_map(NULL, size + chunk_size)) != NULL) {
+ size_t offset = CHUNK_ADDR2OFFSET(ret);
+
+ /*
+ * Success. Clean up unneeded leading/trailing space.
+ */
+ if (offset != 0) {
+ /* Leading space. */
+ pages_unmap(ret, chunk_size - offset);
+
+ ret = (void *)((uintptr_t)ret + (chunk_size -
+ offset));
+
+ /* Trailing space. */
+ pages_unmap((void *)((uintptr_t)ret + size),
+ offset);
+ } else {
+ /* Trailing space only. */
+ pages_unmap((void *)((uintptr_t)ret + size),
+ chunk_size);
+ }
+ goto RETURN;
+ }
+ }
+
+ /* All strategies for allocation failed. */
+ ret = NULL;
+RETURN:
+#ifdef MALLOC_STATS
+ if (ret != NULL) {
+ stats_chunks.nchunks += (size / chunk_size);
+ stats_chunks.curchunks += (size / chunk_size);
+ }
+ if (stats_chunks.curchunks > stats_chunks.highchunks)
+ stats_chunks.highchunks = stats_chunks.curchunks;
+#endif
+ malloc_mutex_unlock(&chunks_mtx);
+
+ assert(CHUNK_ADDR2BASE(ret) == ret);
+ return (ret);
+}
+
+static void
+chunk_dealloc(void *chunk, size_t size)
+{
+ size_t offset;
+ chunk_node_t *node;
+
+ assert(chunk != NULL);
+ assert(CHUNK_ADDR2BASE(chunk) == chunk);
+ assert(size != 0);
+ assert(size % chunk_size == 0);
+
+ malloc_mutex_lock(&chunks_mtx);
+
+#ifdef USE_BRK
+ if ((uintptr_t)chunk >= (uintptr_t)brk_base
+ && (uintptr_t)chunk < (uintptr_t)brk_max) {
+ void *brk_cur;
+
+ /* Get the current end of brk. */
+ brk_cur = sbrk(0);
+
+ /*
+ * Try to shrink the data segment if this chunk is at the end
+ * of the data segment. The sbrk() call here is subject to a
+ * race condition with threads that use brk(2) or sbrk(2)
+ * directly, but the alternative would be to leak memory for
+ * the sake of poorly designed multi-threaded programs.
+ */
+ if (brk_cur == brk_max
+ && (void *)(uintptr_t)chunk + size == brk_max
+ && sbrk(-(intptr_t)size) == brk_max) {
+ if (brk_prev == brk_max) {
+ /* Success. */
+ brk_prev = (void *)(intptr_t)brk_max
+ - (intptr_t)size;
+ brk_max = brk_prev;
+ }
+ goto RETURN;
+ } else
+ madvise(chunk, size, MADV_FREE);
+ } else
+#endif
+ pages_unmap(chunk, size);
+
+ /*
+ * Iteratively create records of each chunk-sized memory region that
+ * 'chunk' is comprised of, so that the address range can be recycled
+ * if memory usage increases later on.
+ */
+ for (offset = 0; offset < size; offset += chunk_size) {
+ node = base_chunk_node_alloc();
+ if (node == NULL)
+ break;
+
+ node->chunk = (void *)((uintptr_t)chunk + (uintptr_t)offset);
+ node->size = chunk_size;
+ RB_INSERT(chunk_tree_s, &old_chunks, node);
+ }
+
+#ifdef USE_BRK
+RETURN:
+#endif
+#ifdef MALLOC_STATS
+ stats_chunks.curchunks -= (size / chunk_size);
+#endif
+ malloc_mutex_unlock(&chunks_mtx);
+}
+
+/*
+ * End chunk management functions.
+ */
+/******************************************************************************/
+/*
+ * Begin arena.
+ */
+
+/*
+ * Choose an arena based on a per-thread value (fast-path code, calls slow-path
+ * code if necessary.
+ */
+static inline arena_t *
+choose_arena(void)
+{
+ arena_t *ret;
+
+ /*
+ * We can only use TLS if this is a PIC library, since for the static
+ * library version, libc's malloc is used by TLS allocation, which
+ * introduces a bootstrapping issue.
+ */
+#ifndef NO_TLS
+ if (__isthreaded == false) {
+ /*
+ * Avoid the overhead of TLS for single-threaded operation. If the
+ * app switches to threaded mode, the initial thread may end up
+ * being assigned to some other arena, but this one-time switch
+ * shouldn't cause significant issues.
+ * */
+ return (arenas[0]);
+ }
+
+ ret = arenas_map;
+ if (ret == NULL)
+ ret = choose_arena_hard();
+#else
+ if (__isthreaded) {
+ unsigned long ind;
+
+ /*
+ * Hash _pthread_self() to one of the arenas. There is a prime
+ * number of arenas, so this has a reasonable chance of
+ * working. Even so, the hashing can be easily thwarted by
+ * inconvenient _pthread_self() values. Without specific
+ * knowledge of how _pthread_self() calculates values, we can't
+ * easily do much better than this.
+ */
+ ind = (unsigned long) _pthread_self() % narenas;
+
+ /*
+ * Optimistially assume that arenas[ind] has been initialized.
+ * At worst, we find out that some other thread has already
+ * done so, after acquiring the lock in preparation. Note that
+ * this lazy locking also has the effect of lazily forcing
+ * cache coherency; without the lock acquisition, there's no
+ * guarantee that modification of arenas[ind] by another thread
+ * would be seen on this CPU for an arbitrary amount of time.
+ *
+ * In general, this approach to modifying a synchronized value
+ * isn't a good idea, but in this case we only ever modify the
+ * value once, so things work out well.
+ */
+ ret = arenas[ind];
+ if (ret == NULL) {
+ /*
+ * Avoid races with another thread that may have already
+ * initialized arenas[ind].
+ */
+ malloc_mutex_lock(&arenas_mtx);
+ if (arenas[ind] == NULL)
+ ret = arenas_extend((unsigned)ind);
+ else
+ ret = arenas[ind];
+ malloc_mutex_unlock(&arenas_mtx);
+ }
+ } else
+ ret = arenas[0];
+#endif
+
+ assert(ret != NULL);
+ return (ret);
+}
+
+#ifndef NO_TLS
+/*
+ * Choose an arena based on a per-thread value (slow-path code only, called
+ * only by choose_arena()).
+ */
+static arena_t *
+choose_arena_hard(void)
+{
+ arena_t *ret;
+
+ assert(__isthreaded);
+
+ /* Assign one of the arenas to this thread, in a round-robin fashion. */
+ malloc_mutex_lock(&arenas_mtx);
+ ret = arenas[next_arena];
+ if (ret == NULL)
+ ret = arenas_extend(next_arena);
+ if (ret == NULL) {
+ /*
+ * Make sure that this function never returns NULL, so that
+ * choose_arena() doesn't have to check for a NULL return
+ * value.
+ */
+ ret = arenas[0];
+ }
+ next_arena = (next_arena + 1) % narenas;
+ malloc_mutex_unlock(&arenas_mtx);
+ arenas_map = ret;
+
+ return (ret);
+}
+#endif
+
+static inline int
+arena_chunk_comp(arena_chunk_t *a, arena_chunk_t *b)
+{
+
+ assert(a != NULL);
+ assert(b != NULL);
+
+ if ((uintptr_t)a < (uintptr_t)b)
+ return (-1);
+ else if (a == b)
+ return (0);
+ else
+ return (1);
+}
+
+/* Generate red-black tree code for arena chunks. */
+RB_GENERATE_STATIC(arena_chunk_tree_s, arena_chunk_s, link, arena_chunk_comp);
+
+static inline void *
+arena_run_reg_alloc(arena_run_t *run, arena_bin_t *bin)
+{
+ void *ret;
+ unsigned i, mask, bit, regind;
+
+ assert(run->magic == ARENA_RUN_MAGIC);
+
+ for (i = run->regs_minelm; i < REGS_MASK_NELMS; i++) {
+ mask = run->regs_mask[i];
+ if (mask != 0) {
+ /* Usable allocation found. */
+ bit = ffs(mask) - 1;
+
+ regind = ((i << (SIZEOF_INT_2POW + 3)) + bit);
+ ret = (void *)&((char *)run)[bin->reg0_offset
+ + (bin->reg_size * regind)];
+
+ /* Clear bit. */
+ mask ^= (1 << bit);
+ run->regs_mask[i] = mask;
+
+ return (ret);
+ } else {
+ /*
+ * Make a note that nothing before this element
+ * contains a free region.
+ */
+ run->regs_minelm = i + 1;
+ }
+ }
+ /* Not reached. */
+ assert(0);
+ return (NULL);
+}
+
+static inline void
+arena_run_reg_dalloc(arena_run_t *run, arena_bin_t *bin, void *ptr, size_t size)
+{
+ unsigned diff, regind, elm, bit;
+
+ assert(run->magic == ARENA_RUN_MAGIC);
+
+ /*
+ * Avoid doing division with a variable divisor if possible. This
+ * single operation can reduce allocator throughput by around 20%!
+ */
+#define POW2_CASE(p) \
+ case (1 << (p)): \
+ regind = diff >> (p); \
+ break;
+#define QUANTUM_CASE(n) \
+ case ((n) << QUANTUM_2POW_MIN): \
+ regind = diff / ((n) << QUANTUM_2POW_MIN); \
+ break;
+
+ /*
+ * These assertions make sure that the switch statement matches
+ * compile-time configuration.
+ */
+ assert(tiny_min_2pow >= 1);
+ assert(QUANTUM_2POW_MIN >= 3 && QUANTUM_2POW_MIN <= 4);
+ assert(SMALL_MAX_2POW_DEFAULT == 9);
+
+ diff = (unsigned)((uintptr_t)ptr - (uintptr_t)run - bin->reg0_offset);
+ switch (size) {
+ POW2_CASE(1)
+ POW2_CASE(2)
+#if (QUANTUM_2POW_MIN > 3)
+ POW2_CASE(3)
+#endif
+ QUANTUM_CASE(1)
+ QUANTUM_CASE(2)
+ QUANTUM_CASE(3)
+ QUANTUM_CASE(4)
+ QUANTUM_CASE(5)
+ QUANTUM_CASE(6)
+ QUANTUM_CASE(7)
+ QUANTUM_CASE(8)
+ QUANTUM_CASE(9)
+ QUANTUM_CASE(10)
+ QUANTUM_CASE(11)
+ QUANTUM_CASE(12)
+ QUANTUM_CASE(13)
+ QUANTUM_CASE(14)
+ QUANTUM_CASE(15)
+ QUANTUM_CASE(16)
+ QUANTUM_CASE(17)
+ QUANTUM_CASE(18)
+ QUANTUM_CASE(19)
+ QUANTUM_CASE(20)
+ QUANTUM_CASE(21)
+ QUANTUM_CASE(22)
+ QUANTUM_CASE(23)
+ QUANTUM_CASE(24)
+ QUANTUM_CASE(25)
+ QUANTUM_CASE(26)
+ QUANTUM_CASE(27)
+ QUANTUM_CASE(28)
+ QUANTUM_CASE(29)
+ QUANTUM_CASE(30)
+ QUANTUM_CASE(31)
+ QUANTUM_CASE(32)
+
+ POW2_CASE(10)
+ POW2_CASE(11)
+ POW2_CASE(12) /* Handle up to 8 kB pages. */
+ default:
+ regind = diff / size;
+ }
+#undef POW2_CASE
+#undef QUANTUM_CASE
+ assert(regind < bin->nregs);
+
+ elm = regind >> (SIZEOF_INT_2POW + 3);
+ if (elm < run->regs_minelm)
+ run->regs_minelm = elm;
+ bit = regind - (elm << (SIZEOF_INT_2POW + 3));
+ assert((run->regs_mask[elm] & (1 << bit)) == 0);
+ run->regs_mask[elm] |= (1 << bit);
+}
+
+static void
+arena_run_split(arena_t *arena, arena_run_t *run, bool large, size_t size)
+{
+ arena_chunk_t *chunk;
+ unsigned run_ind, map_offset, total_pages, need_pages;
+ unsigned i, log2_run_pages, run_pages;
+
+ chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(run);
+ run_ind = (unsigned)(((uintptr_t)run - (uintptr_t)chunk)
+ >> pagesize_2pow);
+ assert(chunk->map[run_ind].free);
+ total_pages = chunk->map[run_ind].npages;
+ need_pages = (size >> pagesize_2pow);
+
+ assert(chunk->map[run_ind].free);
+ assert(chunk->map[run_ind].large == false);
+ assert(chunk->map[run_ind].npages == total_pages);
+
+ /* Split enough pages from the front of run to fit allocation size. */
+ map_offset = run_ind;
+ for (i = 0; i < need_pages; i++) {
+ chunk->map[map_offset + i].free = false;
+ chunk->map[map_offset + i].large = large;
+ chunk->map[map_offset + i].npages = need_pages;
+ chunk->map[map_offset + i].pos = i;
+ }
+
+ /* Update map for trailing pages. */
+ map_offset += need_pages;
+ while (map_offset < run_ind + total_pages) {
+ log2_run_pages = ffs(map_offset) - 1;
+ run_pages = (1 << log2_run_pages);
+
+ chunk->map[map_offset].free = true;
+ chunk->map[map_offset].large = false;
+ chunk->map[map_offset].npages = run_pages;
+
+ chunk->nfree_runs[log2_run_pages]++;
+
+ map_offset += run_pages;
+ }
+
+ chunk->pages_used += (size >> pagesize_2pow);
+}
+
+static arena_chunk_t *
+arena_chunk_alloc(arena_t *arena)
+{
+ arena_chunk_t *chunk;
+ unsigned i, j, header_npages, pow2_header_npages, map_offset;
+ unsigned log2_run_pages, run_pages;
+ size_t header_size;
+
+ chunk = (arena_chunk_t *)chunk_alloc(chunk_size);
+ if (chunk == NULL)
+ return (NULL);
+
+ chunk->arena = arena;
+
+ RB_INSERT(arena_chunk_tree_s, &arena->chunks, chunk);
+
+ /*
+ * Claim that no pages are in use, since the header is merely overhead.
+ */
+ chunk->pages_used = 0;
+
+ memset(&chunk->nfree_runs, 0, sizeof(chunk->nfree_runs));
+
+ header_size = (size_t)((uintptr_t)&chunk->map[arena_chunk_maplen]
+ - (uintptr_t)chunk);
+ if (header_size % pagesize != 0) {
+ /* Round up to the nearest page boundary. */
+ header_size += pagesize - (header_size % pagesize);
+ }
+
+ header_npages = header_size >> pagesize_2pow;
+ pow2_header_npages = pow2_ceil(header_npages);
+
+ /*
+ * Iteratively mark runs as in use, until we've spoken for the entire
+ * header.
+ */
+ map_offset = 0;
+ for (i = 0; header_npages > 0; i++) {
+ if ((pow2_header_npages >> i) <= header_npages) {
+ for (j = 0; j < (pow2_header_npages >> i); j++) {
+ chunk->map[map_offset + j].free = false;
+ chunk->map[map_offset + j].large = false;
+ chunk->map[map_offset + j].npages =
+ (pow2_header_npages >> i);
+ chunk->map[map_offset + j].pos = j;
+ }
+ header_npages -= (pow2_header_npages >> i);
+ map_offset += (pow2_header_npages >> i);
+ }
+ }
+
+ /*
+ * Finish initializing map. The chunk header takes up some space at
+ * the beginning of the chunk, which we just took care of by
+ * "allocating" the leading pages.
+ */
+ while (map_offset < (chunk_size >> pagesize_2pow)) {
+ log2_run_pages = ffs(map_offset) - 1;
+ run_pages = (1 << log2_run_pages);
+
+ chunk->map[map_offset].free = true;
+ chunk->map[map_offset].large = false;
+ chunk->map[map_offset].npages = run_pages;
+
+ chunk->nfree_runs[log2_run_pages]++;
+
+ map_offset += run_pages;
+ }
+
+ return (chunk);
+}
+
+static void
+arena_chunk_dealloc(arena_chunk_t *chunk)
+{
+
+ RB_REMOVE(arena_chunk_tree_s, &chunk->arena->chunks, chunk);
+
+ chunk_dealloc((void *)chunk, chunk_size);
+}
+
+static void
+arena_bin_run_promote(arena_t *arena, arena_bin_t *bin, arena_run_t *run,
+ size_t size)
+{
+
+ assert(bin == run->bin);
+
+ /* Promote. */
+ assert(run->free_min > run->nfree);
+ assert(run->quartile < RUN_Q100);
+ run->quartile++;
+#ifdef MALLOC_STATS
+ bin->stats.npromote++;
+#endif
+
+ /* Re-file run. */
+ switch (run->quartile) {
+ case RUN_QINIT:
+ assert(0);
+ break;
+ case RUN_Q0:
+ qr_before_insert((arena_run_t *)&bin->runs0, run, link);
+ run->free_max = bin->nregs - 1;
+ run->free_min = (bin->nregs >> 1) + 1;
+ assert(run->nfree <= run->free_max);
+ assert(run->nfree >= run->free_min);
+ break;
+ case RUN_Q25:
+ qr_remove(run, link);
+ qr_before_insert((arena_run_t *)&bin->runs25, run,
+ link);
+ run->free_max = ((bin->nregs >> 2) * 3) - 1;
+ run->free_min = (bin->nregs >> 2) + 1;
+ assert(run->nfree <= run->free_max);
+ assert(run->nfree >= run->free_min);
+ break;
+ case RUN_Q50:
+ qr_remove(run, link);
+ qr_before_insert((arena_run_t *)&bin->runs50, run,
+ link);
+ run->free_max = (bin->nregs >> 1) - 1;
+ run->free_min = 1;
+ assert(run->nfree <= run->free_max);
+ assert(run->nfree >= run->free_min);
+ break;
+ case RUN_Q75:
+ /*
+ * Skip RUN_Q75 during promotion from RUN_Q50.
+ * Separate handling of RUN_Q75 and RUN_Q100 allows us
+ * to keep completely full runs in RUN_Q100, thus
+ * guaranteeing that runs in RUN_Q75 are only mostly
+ * full. This provides a method for avoiding a linear
+ * search for non-full runs, which avoids some
+ * pathological edge cases.
+ */
+ run->quartile++;
+ /* Fall through. */
+ case RUN_Q100:
+ qr_remove(run, link);
+ assert(bin->runcur == run);
+ bin->runcur = NULL;
+ run->free_max = 0;
+ run->free_min = 0;
+ assert(run->nfree <= run->free_max);
+ assert(run->nfree >= run->free_min);
+ break;
+ default:
+ assert(0);
+ break;
+ }
+}
+
+static void
+arena_bin_run_demote(arena_t *arena, arena_bin_t *bin, arena_run_t *run,
+ size_t size)
+{
+
+ assert(bin == run->bin);
+
+ /* Demote. */
+ assert(run->free_max < run->nfree);
+ assert(run->quartile > RUN_QINIT);
+ run->quartile--;
+#ifdef MALLOC_STATS
+ bin->stats.ndemote++;
+#endif
+
+ /* Re-file run. */
+ switch (run->quartile) {
+ case RUN_QINIT:
+ qr_remove(run, link);
+#ifdef MALLOC_STATS
+ bin->stats.curruns--;
+#endif
+ if (bin->runcur == run)
+ bin->runcur = NULL;
+#ifdef MALLOC_DEBUG
+ run->magic = 0;
+#endif
+ arena_run_dalloc(arena, run, bin->run_size);
+ break;
+ case RUN_Q0:
+ qr_remove(run, link);
+ qr_before_insert((arena_run_t *)&bin->runs0, run, link);
+ run->free_max = bin->nregs - 1;
+ run->free_min = (bin->nregs >> 1) + 1;
+ assert(run->nfree <= run->free_max);
+ assert(run->nfree >= run->free_min);
+ break;
+ case RUN_Q25:
+ qr_remove(run, link);
+ qr_before_insert((arena_run_t *)&bin->runs25, run,
+ link);
+ run->free_max = ((bin->nregs >> 2) * 3) - 1;
+ run->free_min = (bin->nregs >> 2) + 1;
+ assert(run->nfree <= run->free_max);
+ assert(run->nfree >= run->free_min);
+ break;
+ case RUN_Q50:
+ qr_remove(run, link);
+ qr_before_insert((arena_run_t *)&bin->runs50, run,
+ link);
+ run->free_max = (bin->nregs >> 1) - 1;
+ run->free_min = 1;
+ assert(run->nfree <= run->free_max);
+ assert(run->nfree >= run->free_min);
+ break;
+ case RUN_Q75:
+ qr_before_insert((arena_run_t *)&bin->runs75, run,
+ link);
+ run->free_max = (bin->nregs >> 2) - 1;
+ run->free_min = 1;
+ assert(run->nfree <= run->free_max);
+ assert(run->nfree >= run->free_min);
+ break;
+ case RUN_Q100:
+ default:
+ assert(0);
+ break;
+ }
+}
+
+static arena_run_t *
+arena_run_alloc(arena_t *arena, bool large, size_t size)
+{
+ arena_run_t *run;
+ unsigned min_ind, i, j;
+ arena_chunk_t *chunk;
+#ifndef NDEBUG
+ int rep = 0;
+#endif
+
+ assert(size <= arena_maxclass);
+
+AGAIN:
+#ifndef NDEBUG
+ rep++;
+ assert(rep <= 2);
+#endif
+
+ /*
+ * Search through arena's chunks in address order for a run that is
+ * large enough. Look for a precise fit, but do not pass up a chunk
+ * that has a run which is large enough to split.
+ */
+ min_ind = ffs(size >> pagesize_2pow) - 1;
+ RB_FOREACH(chunk, arena_chunk_tree_s, &arena->chunks) {
+ for (i = min_ind;
+ i < (opt_chunk_2pow - pagesize_2pow);
+ i++) {
+ if (chunk->nfree_runs[i] > 0) {
+ arena_chunk_map_t *map = chunk->map;
+
+ /* Scan chunk's map for free run. */
+ for (j = 0;
+ j < arena_chunk_maplen;
+ j += map[j].npages) {
+ if (map[j].free
+ && map[j].npages == (1 << i))
+ {/*<----------------------------*/
+ run = (arena_run_t *)&((char *)chunk)[j
+ << pagesize_2pow];
+
+ assert(chunk->nfree_runs[i] > 0);
+ chunk->nfree_runs[i]--;
+
+ /* Update page map. */
+ arena_run_split(arena, run, large, size);
+
+ return (run);
+ }/*---------------------------->*/
+ }
+ /* Not reached. */
+ assert(0);
+ }
+ }
+ }
+
+ /* No usable runs. Allocate a new chunk, then try again. */
+ if (arena_chunk_alloc(arena) == NULL)
+ return (NULL);
+ goto AGAIN;
+}
+
+static void
+arena_run_dalloc(arena_t *arena, arena_run_t *run, size_t size)
+{
+ arena_chunk_t *chunk;
+ unsigned run_ind, buddy_ind, base_run_ind, run_pages, log2_run_pages;
+
+ chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(run);
+ run_ind = (unsigned)(((uintptr_t)run - (uintptr_t)chunk)
+ >> pagesize_2pow);
+ run_pages = (size >> pagesize_2pow);
+ log2_run_pages = ffs(run_pages) - 1;
+ assert(run_pages > 0);
+
+ /* Subtract pages from count of pages used in chunk. */
+ chunk->pages_used -= run_pages;
+
+ /* Mark run as deallocated. */
+ chunk->map[run_ind].free = true;
+ chunk->map[run_ind].large = false;
+ chunk->map[run_ind].npages = run_pages;
+
+ /*
+ * Tell the kernel that we don't need the data in this run, but only if
+ * requested via runtime configuration.
+ */
+ if (opt_hint) {
+ madvise(run, size, MADV_FREE);
+#ifdef MALLOC_STATS
+ arena->stats.nmadvise += (size >> pagesize_2pow);
+#endif
+ }
+
+ /*
+ * Iteratively coalesce with buddies. Conceptually, the buddy scheme
+ * induces a tree on the set of pages. If we know the number of pages
+ * in the subtree rooted at the current node, we can quickly determine
+ * whether a run is the left or right buddy, and then calculate the
+ * buddy's index.
+ */
+ for (;
+ (run_pages = (1 << log2_run_pages)) < arena_chunk_maplen;
+ log2_run_pages++) {
+ if (((run_ind >> log2_run_pages) & 1) == 0) {
+ /* Current run precedes its buddy. */
+ buddy_ind = run_ind + run_pages;
+ base_run_ind = run_ind;
+ } else {
+ /* Current run follows its buddy. */
+ buddy_ind = run_ind - run_pages;
+ base_run_ind = buddy_ind;
+ }
+
+ if (chunk->map[buddy_ind].free == false
+ || chunk->map[buddy_ind].npages != run_pages)
+ break;
+
+ assert(chunk->nfree_runs[log2_run_pages] > 0);
+ chunk->nfree_runs[log2_run_pages]--;
+
+ /* Coalesce. */
+ chunk->map[base_run_ind].npages = (run_pages << 1);
+
+ /* Update run_ind to be the beginning of the coalesced run. */
+ run_ind = base_run_ind;
+ }
+
+ chunk->nfree_runs[log2_run_pages]++;
+
+ /* Free pages, to the extent possible. */
+ if (chunk->pages_used == 0) {
+ /* This chunk is completely unused now, so deallocate it. */
+ arena_chunk_dealloc(chunk);
+ }
+}
+
+static arena_run_t *
+arena_bin_nonfull_run_get(arena_t *arena, arena_bin_t *bin, size_t size)
+{
+ arena_run_t *run;
+ unsigned i, remainder;
+
+ /* Look for a usable run. */
+ if ((run = qr_next((arena_run_t *)&bin->runs50, link))
+ != (arena_run_t *)&bin->runs50
+ || (run = qr_next((arena_run_t *)&bin->runs25, link))
+ != (arena_run_t *)&bin->runs25
+ || (run = qr_next((arena_run_t *)&bin->runs0, link))
+ != (arena_run_t *)&bin->runs0
+ || (run = qr_next((arena_run_t *)&bin->runs75, link))
+ != (arena_run_t *)&bin->runs75) {
+ /* run is guaranteed to have available space. */
+ qr_remove(run, link);
+ return (run);
+ }
+ /* No existing runs have any space available. */
+
+ /* Allocate a new run. */
+ run = arena_run_alloc(arena, false, bin->run_size);
+ if (run == NULL)
+ return (NULL);
+
+ /* Initialize run internals. */
+ qr_new(run, link);
+ run->bin = bin;
+
+ for (i = 0; i < (bin->nregs >> (SIZEOF_INT_2POW + 3)); i++)
+ run->regs_mask[i] = UINT_MAX;
+ remainder = bin->nregs % (1 << (SIZEOF_INT_2POW + 3));
+ if (remainder != 0) {
+ run->regs_mask[i] = (UINT_MAX >> ((1 << (SIZEOF_INT_2POW + 3))
+ - remainder));
+ i++;
+ }
+ for (; i < REGS_MASK_NELMS; i++)
+ run->regs_mask[i] = 0;
+
+ run->regs_minelm = 0;
+
+ run->nfree = bin->nregs;
+ run->quartile = RUN_QINIT;
+ run->free_max = bin->nregs;
+ run->free_min = ((bin->nregs >> 2) * 3) + 1;
+#ifdef MALLOC_DEBUG
+ run->magic = ARENA_RUN_MAGIC;
+#endif
+
+#ifdef MALLOC_STATS
+ bin->stats.nruns++;
+ bin->stats.curruns++;
+ if (bin->stats.curruns > bin->stats.highruns)
+ bin->stats.highruns = bin->stats.curruns;
+#endif
+ return (run);
+}
+
+/* bin->runcur must have space available before this function is called. */
+static inline void *
+arena_bin_malloc_easy(arena_t *arena, arena_bin_t *bin, arena_run_t *run,
+ size_t size)
+{
+ void *ret;
+
+ assert(run->magic == ARENA_RUN_MAGIC);
+ assert(run->nfree > 0);
+
+ ret = arena_run_reg_alloc(run, bin);
+ assert(ret != NULL);
+ run->nfree--;
+ if (run->nfree < run->free_min) {
+ /* Promote run to higher fullness quartile. */
+ arena_bin_run_promote(arena, bin, run, size);
+ }
+
+ return (ret);
+}
+
+/* Re-fill bin->runcur, then call arena_bin_malloc_easy(). */
+static void *
+arena_bin_malloc_hard(arena_t *arena, arena_bin_t *bin, size_t size)
+{
+
+ assert(bin->runcur == NULL || bin->runcur->quartile == RUN_Q100);
+
+ bin->runcur = arena_bin_nonfull_run_get(arena, bin, size);
+ if (bin->runcur == NULL)
+ return (NULL);
+ assert(bin->runcur->magic == ARENA_RUN_MAGIC);
+ assert(bin->runcur->nfree > 0);
+
+ return (arena_bin_malloc_easy(arena, bin, bin->runcur, size));
+}
+
+static void *
+arena_malloc(arena_t *arena, size_t size)
+{
+ void *ret;
+
+ assert(arena != NULL);
+ assert(arena->magic == ARENA_MAGIC);
+ assert(size != 0);
+ assert(QUANTUM_CEILING(size) <= arena_maxclass);
+
+ if (size <= bin_maxclass) {
+ arena_bin_t *bin;
+ arena_run_t *run;
+
+ /* Small allocation. */
+
+ if (size < small_min) {
+ /* Tiny. */
+ size = pow2_ceil(size);
+ bin = &arena->bins[ffs(size >> (tiny_min_2pow + 1))];
+#ifdef MALLOC_STATS
+ /*
+ * Bin calculation is always correct, but we may need to
+ * fix size for the purposes of stats accuracy.
+ */
+ if (size < (1 << tiny_min_2pow))
+ size = (1 << tiny_min_2pow);
+#endif
+ } else if (size <= small_max) {
+ /* Quantum-spaced. */
+ size = QUANTUM_CEILING(size);
+ bin = &arena->bins[ntbins + (size >> opt_quantum_2pow)
+ - 1];
+ } else {
+ /* Sub-page. */
+ size = pow2_ceil(size);
+ bin = &arena->bins[ntbins + nqbins
+ + (ffs(size >> opt_small_max_2pow) - 2)];
+ }
+ assert(size == bin->reg_size);
+
+ malloc_mutex_lock(&arena->mtx);
+ if ((run = bin->runcur) != NULL)
+ ret = arena_bin_malloc_easy(arena, bin, run, size);
+ else
+ ret = arena_bin_malloc_hard(arena, bin, size);
+
+#ifdef MALLOC_STATS
+ bin->stats.nrequests++;
+#endif
+ } else {
+ /* Medium allocation. */
+ size = pow2_ceil(size);
+ malloc_mutex_lock(&arena->mtx);
+ ret = (void *)arena_run_alloc(arena, true, size);
+#ifdef MALLOC_STATS
+ arena->stats.large_nrequests++;
+#endif
+ }
+
+#ifdef MALLOC_STATS
+ arena->stats.nmalloc++;
+ if (ret != NULL)
+ arena->stats.allocated += size;
+#endif
+
+ malloc_mutex_unlock(&arena->mtx);
+
+ if (opt_junk && ret != NULL)
+ memset(ret, 0xa5, size);
+ else if (opt_zero && ret != NULL)
+ memset(ret, 0, size);
+ return (ret);
+}
+
+/* Return the size of the allocation pointed to by ptr. */
+static size_t
+arena_salloc(const void *ptr)
+{
+ size_t ret;
+ arena_chunk_t *chunk;
+ uint32_t pageind;
+ arena_chunk_map_t mapelm;
+
+ assert(ptr != NULL);
+ assert(ptr != &nil);
+ assert(CHUNK_ADDR2BASE(ptr) != ptr);
+
+ /*
+ * No arena data structures that we query here can change in a way that
+ * affects this function, so we don't need to lock.
+ */
+ chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
+ pageind = (((uintptr_t)ptr - (uintptr_t)chunk) >> pagesize_2pow);
+ mapelm = chunk->map[pageind];
+ assert(mapelm.free == false);
+ if (mapelm.large == false) {
+ arena_run_t *run;
+
+ pageind -= mapelm.pos;
+
+ run = (arena_run_t *)&((char *)chunk)[pageind << pagesize_2pow];
+ assert(run->magic == ARENA_RUN_MAGIC);
+ ret = run->bin->reg_size;
+ } else
+ ret = mapelm.npages << pagesize_2pow;
+
+ return (ret);
+}
+
+static void *
+arena_ralloc(void *ptr, size_t size, size_t oldsize)
+{
+ void *ret;
+
+ /* Avoid moving the allocation if the size class would not change. */
+ if (size < small_min) {
+ if (oldsize < small_min &&
+ ffs(pow2_ceil(size) >> (tiny_min_2pow + 1))
+ == ffs(pow2_ceil(oldsize) >> (tiny_min_2pow + 1)))
+ goto IN_PLACE;
+ } else if (size <= small_max) {
+ if (oldsize >= small_min && oldsize <= small_max &&
+ (QUANTUM_CEILING(size) >> opt_quantum_2pow)
+ == (QUANTUM_CEILING(oldsize) >> opt_quantum_2pow))
+ goto IN_PLACE;
+ } else {
+ if (oldsize > small_max &&
+ pow2_ceil(size) == pow2_ceil(oldsize))
+ goto IN_PLACE;
+ }
+
+ /*
+ * If we get here, then size and oldsize are different enough that we
+ * need to use a different size class. In that case, fall back to
+ * allocating new space and copying.
+ */
+ ret = arena_malloc(choose_arena(), size);
+ if (ret == NULL)
+ return (NULL);
+
+ if (size < oldsize)
+ memcpy(ret, ptr, size);
+ else
+ memcpy(ret, ptr, oldsize);
+ idalloc(ptr);
+ return (ret);
+IN_PLACE:
+ if (opt_junk && size < oldsize)
+ memset(&((char *)ptr)[size], 0x5a, oldsize - size);
+ else if (opt_zero && size > oldsize)
+ memset(&((char *)ptr)[size], 0, size - oldsize);
+ return (ptr);
+}
+
+static void
+arena_dalloc(arena_t *arena, arena_chunk_t *chunk, void *ptr)
+{
+ unsigned pageind;
+ arena_chunk_map_t mapelm;
+ size_t size;
+
+ assert(arena != NULL);
+ assert(arena->magic == ARENA_MAGIC);
+ assert(chunk->arena == arena);
+ assert(ptr != NULL);
+ assert(ptr != &nil);
+ assert(CHUNK_ADDR2BASE(ptr) != ptr);
+
+ pageind = (((uintptr_t)ptr - (uintptr_t)chunk) >> pagesize_2pow);
+ mapelm = chunk->map[pageind];
+ assert(mapelm.free == false);
+ if (mapelm.large == false) {
+ arena_run_t *run;
+ arena_bin_t *bin;
+
+ /* Small allocation. */
+
+ pageind -= mapelm.pos;
+
+ run = (arena_run_t *)&((char *)chunk)[pageind << pagesize_2pow];
+ assert(run->magic == ARENA_RUN_MAGIC);
+ bin = run->bin;
+ size = bin->reg_size;
+
+ if (opt_junk)
+ memset(ptr, 0x5a, size);
+
+ malloc_mutex_lock(&arena->mtx);
+ arena_run_reg_dalloc(run, bin, ptr, size);
+ run->nfree++;
+ if (run->nfree > run->free_max) {
+ /* Demote run to lower fullness quartile. */
+ arena_bin_run_demote(arena, bin, run, size);
+ }
+ } else {
+ /* Medium allocation. */
+
+ size = mapelm.npages << pagesize_2pow;
+
+ if (opt_junk)
+ memset(ptr, 0x5a, size);
+
+ malloc_mutex_lock(&arena->mtx);
+ arena_run_dalloc(arena, (arena_run_t *)ptr, size);
+ }
+
+#ifdef MALLOC_STATS
+ arena->stats.allocated -= size;
+#endif
+
+ malloc_mutex_unlock(&arena->mtx);
+}
+
+static bool
+arena_new(arena_t *arena)
+{
+ unsigned i;
+ arena_bin_t *bin;
+ size_t pow2_size, run_size;
+
+ malloc_mutex_init(&arena->mtx);
+
+#ifdef MALLOC_STATS
+ memset(&arena->stats, 0, sizeof(arena_stats_t));
+#endif
+
+ /* Initialize chunks. */
+ RB_INIT(&arena->chunks);
+
+ /* Initialize bins. */
+
+ /* (2^n)-spaced tiny bins. */
+ for (i = 0; i < ntbins; i++) {
+ bin = &arena->bins[i];
+ bin->runcur = NULL;
+ qr_new((arena_run_t *)&bin->runs0, link);
+ qr_new((arena_run_t *)&bin->runs25, link);
+ qr_new((arena_run_t *)&bin->runs50, link);
+ qr_new((arena_run_t *)&bin->runs75, link);
+
+ bin->reg_size = (1 << (tiny_min_2pow + i));
+
+ /*
+ * Calculate how large of a run to allocate. Make sure that at
+ * least RUN_MIN_REGS regions fit in the run.
+ */
+ run_size = bin->reg_size << RUN_MIN_REGS_2POW;
+ if (run_size < pagesize)
+ run_size = pagesize;
+ if (run_size > (pagesize << RUN_MAX_PAGES_2POW))
+ run_size = (pagesize << RUN_MAX_PAGES_2POW);
+ if (run_size > arena_maxclass)
+ run_size = arena_maxclass;
+ bin->run_size = run_size;
+
+ assert(run_size >= sizeof(arena_run_t));
+ bin->nregs = (run_size - sizeof(arena_run_t)) / bin->reg_size;
+ if (bin->nregs > (REGS_MASK_NELMS << (SIZEOF_INT_2POW + 3))) {
+ /* Take care not to overflow regs_mask. */
+ bin->nregs = REGS_MASK_NELMS << (SIZEOF_INT_2POW + 3);
+ }
+ bin->reg0_offset = run_size - (bin->nregs * bin->reg_size);
+
+#ifdef MALLOC_STATS
+ memset(&bin->stats, 0, sizeof(malloc_bin_stats_t));
+#endif
+ }
+
+ /* Quantum-spaced bins. */
+ for (; i < ntbins + nqbins; i++) {
+ bin = &arena->bins[i];
+ bin->runcur = NULL;
+ qr_new((arena_run_t *)&bin->runs0, link);
+ qr_new((arena_run_t *)&bin->runs25, link);
+ qr_new((arena_run_t *)&bin->runs50, link);
+ qr_new((arena_run_t *)&bin->runs75, link);
+
+ bin->reg_size = quantum * (i - ntbins + 1);
+
+ /*
+ * Calculate how large of a run to allocate. Make sure that at
+ * least RUN_MIN_REGS regions fit in the run.
+ */
+ pow2_size = pow2_ceil(quantum * (i - ntbins + 1));
+ run_size = (pow2_size << RUN_MIN_REGS_2POW);
+ if (run_size < pagesize)
+ run_size = pagesize;
+ if (run_size > (pagesize << RUN_MAX_PAGES_2POW))
+ run_size = (pagesize << RUN_MAX_PAGES_2POW);
+ if (run_size > arena_maxclass)
+ run_size = arena_maxclass;
+ bin->run_size = run_size;
+
+ bin->nregs = (run_size - sizeof(arena_run_t)) / bin->reg_size;
+ assert(bin->nregs <= REGS_MASK_NELMS << (SIZEOF_INT_2POW + 3));
+ bin->reg0_offset = run_size - (bin->nregs * bin->reg_size);
+
+#ifdef MALLOC_STATS
+ memset(&bin->stats, 0, sizeof(malloc_bin_stats_t));
+#endif
+ }
+
+ /* (2^n)-spaced sub-page bins. */
+ for (; i < ntbins + nqbins + nsbins; i++) {
+ bin = &arena->bins[i];
+ bin->runcur = NULL;
+ qr_new((arena_run_t *)&bin->runs0, link);
+ qr_new((arena_run_t *)&bin->runs25, link);
+ qr_new((arena_run_t *)&bin->runs50, link);
+ qr_new((arena_run_t *)&bin->runs75, link);
+
+ bin->reg_size = (small_max << (i - (ntbins + nqbins) + 1));
+
+ /*
+ * Calculate how large of a run to allocate. Make sure that at
+ * least RUN_MIN_REGS regions fit in the run.
+ */
+ run_size = bin->reg_size << RUN_MIN_REGS_2POW;
+ if (run_size < pagesize)
+ run_size = pagesize;
+ if (run_size > (pagesize << RUN_MAX_PAGES_2POW))
+ run_size = (pagesize << RUN_MAX_PAGES_2POW);
+ if (run_size > arena_maxclass)
+ run_size = arena_maxclass;
+ bin->run_size = run_size;
+
+ bin->nregs = (run_size - sizeof(arena_run_t)) / bin->reg_size;
+ assert(bin->nregs <= REGS_MASK_NELMS << (SIZEOF_INT_2POW + 3));
+ bin->reg0_offset = run_size - (bin->nregs * bin->reg_size);
+
+#ifdef MALLOC_STATS
+ memset(&bin->stats, 0, sizeof(malloc_bin_stats_t));
+#endif
+ }
+
+#ifdef MALLOC_DEBUG
+ arena->magic = ARENA_MAGIC;
+#endif
+
+ return (false);
+}
+
+/* Create a new arena and insert it into the arenas array at index ind. */
+static arena_t *
+arenas_extend(unsigned ind)
+{
+ arena_t *ret;
+
+ /* Allocate enough space for trailing bins. */
+ ret = (arena_t *)base_alloc(sizeof(arena_t)
+ + (sizeof(arena_bin_t) * (ntbins + nqbins + nsbins - 1)));
+ if (ret != NULL && arena_new(ret) == false) {
+ arenas[ind] = ret;
+ return (ret);
+ }
+ /* Only reached if there is an OOM error. */
+
+ /*
+ * OOM here is quite inconvenient to propagate, since dealing with it
+ * would require a check for failure in the fast path. Instead, punt
+ * by using arenas[0]. In practice, this is an extremely unlikely
+ * failure.
+ */
+ malloc_printf("%s: (malloc) Error initializing arena\n",
+ _getprogname());
+ if (opt_abort)
+ abort();
+
+ return (arenas[0]);
+}
+
+/*
+ * End arena.
+ */
+/******************************************************************************/
+/*
+ * Begin general internal functions.
+ */
+
+static void *
+huge_malloc(size_t size)
+{
+ void *ret;
+ size_t csize;
+ chunk_node_t *node;
+
+ /* Allocate one or more contiguous chunks for this request. */
+
+ csize = CHUNK_CEILING(size);
+ if (csize == 0) {
+ /* size is large enough to cause size_t wrap-around. */
+ return (NULL);
+ }
+
+ /* Allocate a chunk node with which to track the chunk. */
+ node = base_chunk_node_alloc();
+ if (node == NULL)
+ return (NULL);
+
+ ret = chunk_alloc(csize);
+ if (ret == NULL) {
+ base_chunk_node_dealloc(node);
+ return (NULL);
+ }
+
+ /* Insert node into chunks. */
+ node->chunk = ret;
+ node->size = csize;
+
+ malloc_mutex_lock(&chunks_mtx);
+ RB_INSERT(chunk_tree_s, &huge, node);
+#ifdef MALLOC_STATS
+ huge_nmalloc++;
+ huge_allocated += csize;
+#endif
+ malloc_mutex_unlock(&chunks_mtx);
+
+ if (opt_junk && ret != NULL)
+ memset(ret, 0xa5, csize);
+ else if (opt_zero && ret != NULL)
+ memset(ret, 0, csize);
+
+ return (ret);
+}
+
+static void *
+huge_ralloc(void *ptr, size_t size, size_t oldsize)
+{
+ void *ret;
+
+ /* Avoid moving the allocation if the size class would not change. */
+ if (oldsize > arena_maxclass &&
+ CHUNK_CEILING(size) == CHUNK_CEILING(oldsize))
+ return (ptr);
+
+ /*
+ * If we get here, then size and oldsize are different enough that we
+ * need to use a different size class. In that case, fall back to
+ * allocating new space and copying.
+ */
+ ret = huge_malloc(size);
+ if (ret == NULL)
+ return (NULL);
+
+ if (CHUNK_ADDR2BASE(ptr) == ptr) {
+ /* The old allocation is a chunk. */
+ if (size < oldsize)
+ memcpy(ret, ptr, size);
+ else
+ memcpy(ret, ptr, oldsize);
+ } else {
+ /* The old allocation is a region. */
+ assert(oldsize < size);
+ memcpy(ret, ptr, oldsize);
+ }
+ idalloc(ptr);
+ return (ret);
+}
+
+static void
+huge_dalloc(void *ptr)
+{
+ chunk_node_t key;
+ chunk_node_t *node;
+
+ malloc_mutex_lock(&chunks_mtx);
+
+ /* Extract from tree of huge allocations. */
+ key.chunk = ptr;
+ node = RB_FIND(chunk_tree_s, &huge, &key);
+ assert(node != NULL);
+ assert(node->chunk == ptr);
+ RB_REMOVE(chunk_tree_s, &huge, node);
+
+#ifdef MALLOC_STATS
+ /* Update counters. */
+ huge_ndalloc++;
+ huge_allocated -= node->size;
+#endif
+
+ malloc_mutex_unlock(&chunks_mtx);
+
+ /* Unmap chunk. */
+#ifdef USE_BRK
+ if (opt_junk)
+ memset(node->chunk, 0x5a, node->size);
+#endif
+ chunk_dealloc(node->chunk, node->size);
+
+ base_chunk_node_dealloc(node);
+}
+
+static void *
+imalloc(size_t size)
+{
+ void *ret;
+
+ assert(size != 0);
+
+ if (size <= arena_maxclass)
+ ret = arena_malloc(choose_arena(), size);
+ else
+ ret = huge_malloc(size);
+
+ return (ret);
+}
+
+static void *
+ipalloc(size_t alignment, size_t size)
+{
+ void *ret;
+ size_t pow2_size;
+
+ /*
+ * Round up to the nearest power of two that is >= alignment and
+ * >= size.
+ */
+ if (size > alignment)
+ pow2_size = pow2_ceil(size);
+ else
+ pow2_size = alignment;
+ pow2_size = QUANTUM_CEILING(pow2_size);
+ if (pow2_size < size) {
+ /* size_t overflow. */
+ return (NULL);
+ }
+
+ if (pow2_size <= arena_maxclass)
+ ret = arena_malloc(choose_arena(), pow2_size);
+ else {
+ if (alignment <= chunk_size)
+ ret = huge_malloc(size);
+ else {
+ size_t chunksize, alloc_size, offset;
+ chunk_node_t *node;
+
+ /*
+ * This allocation requires alignment that is even
+ * larger than chunk alignment. This means that
+ * huge_malloc() isn't good enough.
+ *
+ * Allocate almost twice as many chunks as are demanded
+ * by the size or alignment, in order to assure the
+ * alignment can be achieved, then unmap leading and
+ * trailing chunks.
+ */
+
+ chunksize = CHUNK_CEILING(size);
+
+ if (size >= alignment)
+ alloc_size = chunksize + alignment - chunk_size;
+ else
+ alloc_size = (alignment << 1) - chunk_size;
+
+ /*
+ * Allocate a chunk node with which to track the chunk.
+ */
+ node = base_chunk_node_alloc();
+ if (node == NULL)
+ return (NULL);
+
+ ret = chunk_alloc(alloc_size);
+ if (ret == NULL) {
+ base_chunk_node_dealloc(node);
+ return (NULL);
+ }
+
+ offset = (uintptr_t)ret & (alignment - 1);
+ assert(offset % chunk_size == 0);
+ assert(offset < alloc_size);
+ if (offset == 0) {
+ /* Trim trailing space. */
+ chunk_dealloc((void *)((uintptr_t)ret
+ + chunksize), alloc_size - chunksize);
+ } else {
+ size_t trailsize;
+
+ /* Trim leading space. */
+ chunk_dealloc(ret, alignment - offset);
+
+ ret = (void *)((uintptr_t)ret + (alignment
+ - offset));
+
+ trailsize = alloc_size - (alignment - offset)
+ - chunksize;
+ if (trailsize != 0) {
+ /* Trim trailing space. */
+ assert(trailsize < alloc_size);
+ chunk_dealloc((void *)((uintptr_t)ret
+ + chunksize), trailsize);
+ }
+ }
+
+ /* Insert node into chunks. */
+ node->chunk = ret;
+ node->size = chunksize;
+
+ malloc_mutex_lock(&chunks_mtx);
+ RB_INSERT(chunk_tree_s, &huge, node);
+#ifdef MALLOC_STATS
+ huge_allocated += size;
+#endif
+ malloc_mutex_unlock(&chunks_mtx);
+
+ if (opt_junk)
+ memset(ret, 0xa5, chunksize);
+ else if (opt_zero)
+ memset(ret, 0, chunksize);
+ }
+ }
+
+ assert(((uintptr_t)ret & (alignment - 1)) == 0);
+ return (ret);
+}
+
+static void *
+icalloc(size_t size)
+{
+ void *ret;
+
+ if (size <= arena_maxclass) {
+ ret = arena_malloc(choose_arena(), size);
+ if (ret == NULL)
+ return (NULL);
+ memset(ret, 0, size);
+ } else {
+ /*
+ * The virtual memory system provides zero-filled pages, so
+ * there is no need to do so manually, unless opt_junk is
+ * enabled, in which case huge_malloc() fills huge allocations
+ * with junk.
+ */
+ ret = huge_malloc(size);
+ if (ret == NULL)
+ return (NULL);
+
+ if (opt_junk)
+ memset(ret, 0, size);
+#ifdef USE_BRK
+ else if ((uintptr_t)ret >= (uintptr_t)brk_base
+ && (uintptr_t)ret < (uintptr_t)brk_max) {
+ /*
+ * This may be a re-used brk chunk. Therefore, zero
+ * the memory.
+ */
+ memset(ret, 0, size);
+ }
+#endif
+ }
+
+ return (ret);
+}
+
+static size_t
+isalloc(const void *ptr)
+{
+ size_t ret;
+ arena_chunk_t *chunk;
+
+ assert(ptr != NULL);
+ assert(ptr != &nil);
+
+ chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
+ if (chunk != ptr) {
+ /* Region. */
+ assert(chunk->arena->magic == ARENA_MAGIC);
+
+ ret = arena_salloc(ptr);
+ } else {
+ chunk_node_t *node, key;
+
+ /* Chunk (huge allocation). */
+
+ malloc_mutex_lock(&chunks_mtx);
+
+ /* Extract from tree of huge allocations. */
+ key.chunk = (void *)ptr;
+ node = RB_FIND(chunk_tree_s, &huge, &key);
+ assert(node != NULL);
+
+ ret = node->size;
+
+ malloc_mutex_unlock(&chunks_mtx);
+ }
+
+ return (ret);
+}
+
+static void *
+iralloc(void *ptr, size_t size)
+{
+ void *ret;
+ size_t oldsize;
+
+ assert(ptr != NULL);
+ assert(ptr != &nil);
+ assert(size != 0);
+
+ oldsize = isalloc(ptr);
+
+ if (size <= arena_maxclass)
+ ret = arena_ralloc(ptr, size, oldsize);
+ else
+ ret = huge_ralloc(ptr, size, oldsize);
+
+ return (ret);
+}
+
+static void
+idalloc(void *ptr)
+{
+ arena_chunk_t *chunk;
+
+ assert(ptr != NULL);
+ assert(ptr != &nil);
+
+ chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
+ if (chunk != ptr) {
+ /* Region. */
+#ifdef MALLOC_STATS
+ malloc_mutex_lock(&chunk->arena->mtx);
+ chunk->arena->stats.ndalloc++;
+ malloc_mutex_unlock(&chunk->arena->mtx);
+#endif
+ arena_dalloc(chunk->arena, chunk, ptr);
+ } else
+ huge_dalloc(ptr);
+}
+
+static void
+malloc_print_stats(void)
+{
+
+ if (opt_print_stats) {
+ malloc_printf("___ Begin malloc statistics ___\n");
+ malloc_printf("Number of CPUs: %u\n", ncpus);
+ malloc_printf("Number of arenas: %u\n", narenas);
+ malloc_printf("Chunk size: %zu (2^%zu)\n", chunk_size,
+ opt_chunk_2pow);
+ malloc_printf("Quantum size: %zu (2^%zu)\n", quantum,
+ opt_quantum_2pow);
+ malloc_printf("Max small size: %zu\n", small_max);
+ malloc_printf("Pointer size: %u\n", sizeof(void *));
+ malloc_printf("Assertions %s\n",
+#ifdef NDEBUG
+ "disabled"
+#else
+ "enabled"
+#endif
+ );
+
+#ifdef MALLOC_STATS
+
+ {
+ size_t allocated, total;
+ unsigned i;
+ arena_t *arena;
+
+ /* Calculate and print allocated/total stats. */
+
+ /* arenas. */
+ for (i = 0, allocated = 0; i < narenas; i++) {
+ if (arenas[i] != NULL) {
+ malloc_mutex_lock(&arenas[i]->mtx);
+ allocated += arenas[i]->stats.allocated;
+ malloc_mutex_unlock(&arenas[i]->mtx);
+ }
+ }
+
+ /* huge. */
+ malloc_mutex_lock(&chunks_mtx);
+ allocated += huge_allocated;
+ total = stats_chunks.curchunks * chunk_size;
+ malloc_mutex_unlock(&chunks_mtx);
+
+ malloc_printf("Allocated: %zu, space used: %zu\n",
+ allocated, total);
+
+ /* Print chunk stats. */
+ {
+ chunk_stats_t chunks_stats;
+
+ malloc_mutex_lock(&chunks_mtx);
+ chunks_stats = stats_chunks;
+ malloc_mutex_unlock(&chunks_mtx);
+
+ malloc_printf("\nchunks:\n");
+ malloc_printf(" %13s%13s%13s\n", "nchunks",
+ "highchunks", "curchunks");
+ malloc_printf(" %13llu%13lu%13lu\n",
+ chunks_stats.nchunks,
+ chunks_stats.highchunks,
+ chunks_stats.curchunks);
+ }
+
+ /* Print chunk stats. */
+ malloc_printf("\nhuge:\n");
+ malloc_printf("%12s %12s %12s\n",
+ "nmalloc", "ndalloc", "allocated");
+ malloc_printf("%12llu %12llu %12zu\n",
+ huge_nmalloc, huge_ndalloc, huge_allocated);
+
+ /* Print stats for each arena. */
+ for (i = 0; i < narenas; i++) {
+ arena = arenas[i];
+ if (arena != NULL) {
+ malloc_printf(
+ "\narenas[%u] statistics:\n", i);
+ malloc_mutex_lock(&arena->mtx);
+ stats_print(arena);
+ malloc_mutex_unlock(&arena->mtx);
+ }
+ }
+ }
+#endif /* #ifdef MALLOC_STATS */
+ malloc_printf("--- End malloc statistics ---\n");
+ }
+}
+
+/*
+ * FreeBSD's pthreads implementation calls malloc(3), so the malloc
+ * implementation has to take pains to avoid infinite recursion during
+ * initialization.
+ */
+static inline bool
+malloc_init(void)
+{
+
+ if (malloc_initialized == false)
+ return (malloc_init_hard());
+
+ return (false);
+}
+
+static bool
+malloc_init_hard(void)
+{
+ unsigned i, j;
+ int linklen;
+ char buf[PATH_MAX + 1];
+ const char *opts;
+
+ malloc_mutex_lock(&init_lock);
+ if (malloc_initialized) {
+ /*
+ * Another thread initialized the allocator before this one
+ * acquired init_lock.
+ */
+ malloc_mutex_unlock(&init_lock);
+ return (false);
+ }
+
+ /* Get number of CPUs. */
+ {
+ int mib[2];
+ size_t len;
+
+ mib[0] = CTL_HW;
+ mib[1] = HW_NCPU;
+ len = sizeof(ncpus);
+ if (sysctl(mib, 2, &ncpus, &len, (void *) 0, 0) == -1) {
+ /* Error. */
+ ncpus = 1;
+ }
+ }
+
+ /* Get page size. */
+ {
+ long result;
+
+ result = sysconf(_SC_PAGESIZE);
+ assert(result != -1);
+ pagesize = (unsigned) result;
+
+ /*
+ * We assume that pagesize is a power of 2 when calculating
+ * pagesize_2pow.
+ */
+ assert(((result - 1) & result) == 0);
+ pagesize_2pow = ffs(result) - 1;
+ }
+
+ for (i = 0; i < 3; i++) {
+ /* Get runtime configuration. */
+ switch (i) {
+ case 0:
+ if ((linklen = readlink("/etc/malloc.conf", buf,
+ sizeof(buf) - 1)) != -1) {
+ /*
+ * Use the contents of the "/etc/malloc.conf"
+ * symbolic link's name.
+ */
+ buf[linklen] = '\0';
+ opts = buf;
+ } else {
+ /* No configuration specified. */
+ buf[0] = '\0';
+ opts = buf;
+ }
+ break;
+ case 1:
+ if (issetugid() == 0 && (opts =
+ getenv("MALLOC_OPTIONS")) != NULL) {
+ /*
+ * Do nothing; opts is already initialized to
+ * the value of the MALLOC_OPTIONS environment
+ * variable.
+ */
+ } else {
+ /* No configuration specified. */
+ buf[0] = '\0';
+ opts = buf;
+ }
+ break;
+ case 2:
+ if (_malloc_options != NULL) {
+ /*
+ * Use options that were compiled into the program.
+ */
+ opts = _malloc_options;
+ } else {
+ /* No configuration specified. */
+ buf[0] = '\0';
+ opts = buf;
+ }
+ break;
+ default:
+ /* NOTREACHED */
+ assert(false);
+ }
+
+ for (j = 0; opts[j] != '\0'; j++) {
+ switch (opts[j]) {
+ case 'a':
+ opt_abort = false;
+ break;
+ case 'A':
+ opt_abort = true;
+ break;
+ case 'h':
+ opt_hint = false;
+ break;
+ case 'H':
+ opt_hint = true;
+ break;
+ case 'j':
+ opt_junk = false;
+ break;
+ case 'J':
+ opt_junk = true;
+ break;
+ case 'k':
+ /*
+ * Run fullness quartile limits don't have
+ * enough resolution if there are too few
+ * regions for the largest bin size classes.
+ */
+ if (opt_chunk_2pow > pagesize_2pow + 4)
+ opt_chunk_2pow--;
+ break;
+ case 'K':
+ if (opt_chunk_2pow < CHUNK_2POW_MAX)
+ opt_chunk_2pow++;
+ break;
+ case 'n':
+ opt_narenas_lshift--;
+ break;
+ case 'N':
+ opt_narenas_lshift++;
+ break;
+ case 'p':
+ opt_print_stats = false;
+ break;
+ case 'P':
+ opt_print_stats = true;
+ break;
+ case 'q':
+ if (opt_quantum_2pow > QUANTUM_2POW_MIN)
+ opt_quantum_2pow--;
+ break;
+ case 'Q':
+ if (opt_quantum_2pow < pagesize_2pow - 1)
+ opt_quantum_2pow++;
+ break;
+ case 's':
+ if (opt_small_max_2pow > QUANTUM_2POW_MIN)
+ opt_small_max_2pow--;
+ break;
+ case 'S':
+ if (opt_small_max_2pow < pagesize_2pow - 1)
+ opt_small_max_2pow++;
+ break;
+ case 'u':
+ opt_utrace = false;
+ break;
+ case 'U':
+ opt_utrace = true;
+ break;
+ case 'v':
+ opt_sysv = false;
+ break;
+ case 'V':
+ opt_sysv = true;
+ break;
+ case 'x':
+ opt_xmalloc = false;
+ break;
+ case 'X':
+ opt_xmalloc = true;
+ break;
+ case 'z':
+ opt_zero = false;
+ break;
+ case 'Z':
+ opt_zero = true;
+ break;
+ default:
+ malloc_printf("%s: (malloc) Unsupported"
+ " character in malloc options: '%c'\n",
+ _getprogname(), opts[j]);
+ }
+ }
+ }
+
+ /* Take care to call atexit() only once. */
+ if (opt_print_stats) {
+ /* Print statistics at exit. */
+ atexit(malloc_print_stats);
+ }
+
+ /* Set variables according to the value of opt_small_max_2pow. */
+ if (opt_small_max_2pow < opt_quantum_2pow)
+ opt_small_max_2pow = opt_quantum_2pow;
+ small_max = (1 << opt_small_max_2pow);
+
+ /* Set bin-related variables. */
+ bin_maxclass = (pagesize >> 1);
+ if (pagesize_2pow > RUN_MIN_REGS_2POW + 1)
+ tiny_min_2pow = pagesize_2pow - (RUN_MIN_REGS_2POW + 1);
+ else
+ tiny_min_2pow = 1;
+ assert(opt_quantum_2pow >= tiny_min_2pow);
+ ntbins = opt_quantum_2pow - tiny_min_2pow;
+ assert(ntbins <= opt_quantum_2pow);
+ nqbins = (small_max >> opt_quantum_2pow);
+ nsbins = pagesize_2pow - opt_small_max_2pow - 1;
+
+ /* Set variables according to the value of opt_quantum_2pow. */
+ quantum = (1 << opt_quantum_2pow);
+ quantum_mask = quantum - 1;
+ if (ntbins > 0)
+ small_min = (quantum >> 1) + 1;
+ else
+ small_min = 1;
+ assert(small_min <= quantum);
+
+ /* Set variables according to the value of opt_chunk_2pow. */
+ chunk_size = (1 << opt_chunk_2pow);
+ chunk_size_mask = chunk_size - 1;
+ arena_chunk_maplen = (1 << (opt_chunk_2pow - pagesize_2pow));
+ arena_maxclass = (chunk_size >> 1);
+
+ UTRACE(0, 0, 0);
+
+#ifdef MALLOC_STATS
+ memset(&stats_chunks, 0, sizeof(chunk_stats_t));
+#endif
+
+ /* Various sanity checks that regard configuration. */
+ assert(quantum >= sizeof(void *));
+ assert(quantum <= pagesize);
+ assert(chunk_size >= pagesize);
+ assert(quantum * 4 <= chunk_size);
+
+ /* Initialize chunks data. */
+ malloc_mutex_init(&chunks_mtx);
+ RB_INIT(&huge);
+#ifdef USE_BRK
+ brk_base = sbrk(0);
+ brk_prev = brk_base;
+ brk_max = brk_base;
+#endif
+#ifdef MALLOC_STATS
+ huge_nmalloc = 0;
+ huge_ndalloc = 0;
+ huge_allocated = 0;
+#endif
+ RB_INIT(&old_chunks);
+
+ /* Initialize base allocation data structures. */
+#ifdef MALLOC_STATS
+ base_total = 0;
+#endif
+#ifdef USE_BRK
+ /*
+ * Do special brk allocation here, since the base chunk doesn't really
+ * need to be chunk-aligned.
+ */
+ {
+ void *brk_cur;
+ intptr_t incr;
+
+ do {
+ /* Get the current end of brk. */
+ brk_cur = sbrk(0);
+
+ /*
+ * Calculate how much padding is necessary to
+ * chunk-align the end of brk. Don't worry about
+ * brk_cur not being chunk-aligned though.
+ */
+ incr = (intptr_t)chunk_size
+ - (intptr_t)CHUNK_ADDR2OFFSET(brk_cur);
+
+ brk_prev = sbrk(incr);
+ if (brk_prev == brk_cur) {
+ /* Success. */
+ break;
+ }
+ } while (brk_prev != (void *)-1);
+
+ base_chunk = brk_cur;
+ base_next_addr = base_chunk;
+ base_past_addr = (void *)((uintptr_t)base_chunk + incr);
+#ifdef MALLOC_STATS
+ base_total += incr;
+ stats_chunks.nchunks = 1;
+ stats_chunks.curchunks = 1;
+ stats_chunks.highchunks = 1;
+#endif
+ }
+#else
+ /*
+ * The first base chunk will be allocated when needed by base_alloc().
+ */
+ base_chunk = NULL;
+ base_next_addr = NULL;
+ base_past_addr = NULL;
+#endif
+ base_chunk_nodes = NULL;
+ malloc_mutex_init(&base_mtx);
+
+ if (ncpus > 1) {
+ /*
+ * For SMP systems, create four times as many arenas as there
+ * are CPUs by default.
+ */
+ opt_narenas_lshift += 2;
+ }
+
+ /* Determine how many arenas to use. */
+ narenas = ncpus;
+ if (opt_narenas_lshift > 0) {
+ if ((narenas << opt_narenas_lshift) > narenas)
+ narenas <<= opt_narenas_lshift;
+ /*
+ * Make sure not to exceed the limits of what base_malloc()
+ * can handle.
+ */
+ if (narenas * sizeof(arena_t *) > chunk_size)
+ narenas = chunk_size / sizeof(arena_t *);
+ } else if (opt_narenas_lshift < 0) {
+ if ((narenas << opt_narenas_lshift) < narenas)
+ narenas <<= opt_narenas_lshift;
+ /* Make sure there is at least one arena. */
+ if (narenas == 0)
+ narenas = 1;
+ }
+
+#ifdef NO_TLS
+ if (narenas > 1) {
+ static const unsigned primes[] = {1, 3, 5, 7, 11, 13, 17, 19,
+ 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83,
+ 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149,
+ 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211,
+ 223, 227, 229, 233, 239, 241, 251, 257, 263};
+ unsigned i, nprimes, parenas;
+
+ /*
+ * Pick a prime number of hash arenas that is more than narenas
+ * so that direct hashing of pthread_self() pointers tends to
+ * spread allocations evenly among the arenas.
+ */
+ assert((narenas & 1) == 0); /* narenas must be even. */
+ nprimes = (sizeof(primes) >> SIZEOF_INT_2POW);
+ parenas = primes[nprimes - 1]; /* In case not enough primes. */
+ for (i = 1; i < nprimes; i++) {
+ if (primes[i] > narenas) {
+ parenas = primes[i];
+ break;
+ }
+ }
+ narenas = parenas;
+ }
+#endif
+
+#ifndef NO_TLS
+ next_arena = 0;
+#endif
+
+ /* Allocate and initialize arenas. */
+ arenas = (arena_t **)base_alloc(sizeof(arena_t *) * narenas);
+ if (arenas == NULL) {
+ malloc_mutex_unlock(&init_lock);
+ return (true);
+ }
+ /*
+ * Zero the array. In practice, this should always be pre-zeroed,
+ * since it was just mmap()ed, but let's be sure.
+ */
+ memset(arenas, 0, sizeof(arena_t *) * narenas);
+
+ /*
+ * Initialize one arena here. The rest are lazily created in
+ * arena_choose_hard().
+ */
+ arenas_extend(0);
+ if (arenas[0] == NULL) {
+ malloc_mutex_unlock(&init_lock);
+ return (true);
+ }
+
+ malloc_mutex_init(&arenas_mtx);
+
+ malloc_initialized = true;
+ malloc_mutex_unlock(&init_lock);
+ return (false);
+}
+
+/*
+ * End general internal functions.
+ */
+/******************************************************************************/
+/*
+ * Begin malloc(3)-compatible functions.
+ */
+
+void *
+malloc(size_t size)
+{
+ void *ret;
+
+ if (malloc_init()) {
+ ret = NULL;
+ goto RETURN;
+ }
+
+ if (size == 0) {
+ if (opt_sysv == false)
+ ret = (void *)&nil;
+ else
+ ret = NULL;
+ goto RETURN;
+ }
+
+ ret = imalloc(size);
+
+RETURN:
+ if (ret == NULL) {
+ if (opt_xmalloc) {
+ malloc_printf("%s: (malloc) Error in malloc(%zu):"
+ " out of memory\n", _getprogname(), size);
+ abort();
+ }
+ errno = ENOMEM;
+ }
+
+ UTRACE(0, size, ret);
+ return (ret);
+}
+
+int
+posix_memalign(void **memptr, size_t alignment, size_t size)
+{
+ int ret;
+ void *result;
+
+ if (malloc_init())
+ result = NULL;
+ else {
+ /* Make sure that alignment is a large enough power of 2. */
+ if (((alignment - 1) & alignment) != 0
+ || alignment < sizeof(void *)) {
+ if (opt_xmalloc) {
+ malloc_printf("%s: (malloc) Error in"
+ " posix_memalign(%zu, %zu):"
+ " invalid alignment\n",
+ _getprogname(), alignment, size);
+ abort();
+ }
+ result = NULL;
+ ret = EINVAL;
+ goto RETURN;
+ }
+
+ result = ipalloc(alignment, size);
+ }
+
+ if (result == NULL) {
+ if (opt_xmalloc) {
+ malloc_printf("%s: (malloc) Error in"
+ " posix_memalign(%zu, %zu): out of memory\n",
+ _getprogname(), alignment, size);
+ abort();
+ }
+ ret = ENOMEM;
+ goto RETURN;
+ }
+
+ *memptr = result;
+ ret = 0;
+
+RETURN:
+ UTRACE(0, size, result);
+ return (ret);
+}
+
+void *
+calloc(size_t num, size_t size)
+{
+ void *ret;
+ size_t num_size;
+
+ if (malloc_init()) {
+ ret = NULL;
+ goto RETURN;
+ }
+
+ num_size = num * size;
+ if (num_size == 0) {
+ if (opt_sysv == false)
+ ret = (void *)&nil;
+ else
+ ret = NULL;
+ goto RETURN;
+ /*
+ * Try to avoid division here. We know that it isn't possible to
+ * overflow during multiplication if neither operand uses any of the
+ * most significant half of the bits in a size_t.
+ */
+ } else if (((num | size) & (SIZE_T_MAX << (sizeof(size_t) << 2)))
+ && (num_size / size != num)) {
+ /* size_t overflow. */
+ ret = NULL;
+ goto RETURN;
+ }
+
+ ret = icalloc(num_size);
+
+RETURN:
+ if (ret == NULL) {
+ if (opt_xmalloc) {
+ malloc_printf("%s: (malloc) Error in"
+ " calloc(%zu, %zu): out of memory\n",
+ _getprogname(), num, size);
+ abort();
+ }
+ errno = ENOMEM;
+ }
+
+ UTRACE(0, num_size, ret);
+ return (ret);
+}
+
+void *
+realloc(void *ptr, size_t size)
+{
+ void *ret;
+
+ if (size != 0) {
+ if (ptr != &nil && ptr != NULL) {
+ assert(malloc_initialized);
+
+ ret = iralloc(ptr, size);
+
+ if (ret == NULL) {
+ if (opt_xmalloc) {
+ malloc_printf("%s: (malloc) Error in"
+ " ralloc(%p, %zu): out of memory\n",
+ _getprogname(), ptr, size);
+ abort();
+ }
+ errno = ENOMEM;
+ }
+ } else {
+ if (malloc_init())
+ ret = NULL;
+ else
+ ret = imalloc(size);
+
+ if (ret == NULL) {
+ if (opt_xmalloc) {
+ malloc_printf("%s: (malloc) Error in"
+ " ralloc(%p, %zu): out of memory\n",
+ _getprogname(), ptr, size);
+ abort();
+ }
+ errno = ENOMEM;
+ }
+ }
+ } else {
+ if (ptr != &nil && ptr != NULL)
+ idalloc(ptr);
+
+ ret = (void *)&nil;
+ }
+
+ UTRACE(ptr, size, ret);
+ return (ret);
+}
+
+void
+free(void *ptr)
+{
+
+ UTRACE(ptr, 0, 0);
+ if (ptr != &nil && ptr != NULL) {
+ assert(malloc_initialized);
+
+ idalloc(ptr);
+ }
+}
+
+/*
+ * End malloc(3)-compatible functions.
+ */
+/******************************************************************************/
+/*
+ * Begin non-standard functions.
+ */
+
+size_t
+malloc_usable_size(const void *ptr)
+{
+
+ assert(ptr != NULL);
+
+ if (ptr == &nil)
+ return (0);
+ else
+ return (isalloc(ptr));
+}
+
+/*
+ * End non-standard functions.
+ */
+/******************************************************************************/
+/*
+ * Begin library-private functions, used by threading libraries for protection
+ * of malloc during fork(). These functions are only called if the program is
+ * running in threaded mode, so there is no need to check whether the program
+ * is threaded here.
+ */
+
+void
+_malloc_prefork(void)
+{
+ unsigned i;
+
+ /* Acquire all mutexes in a safe order. */
+
+ malloc_mutex_lock(&arenas_mtx);
+ for (i = 0; i < narenas; i++) {
+ if (arenas[i] != NULL)
+ malloc_mutex_lock(&arenas[i]->mtx);
+ }
+ malloc_mutex_unlock(&arenas_mtx);
+
+ malloc_mutex_lock(&base_mtx);
+
+ malloc_mutex_lock(&chunks_mtx);
+}
+
+void
+_malloc_postfork(void)
+{
+ unsigned i;
+
+ /* Release all mutexes, now that fork() has completed. */
+
+ malloc_mutex_unlock(&chunks_mtx);
+
+ malloc_mutex_unlock(&base_mtx);
+
+ malloc_mutex_lock(&arenas_mtx);
+ for (i = 0; i < narenas; i++) {
+ if (arenas[i] != NULL)
+ malloc_mutex_unlock(&arenas[i]->mtx);
+ }
+ malloc_mutex_unlock(&arenas_mtx);
+}
+
+/*
+ * End library-private functions.
+ */
+/******************************************************************************/
diff --git a/lib/libc/stdlib/memory.3 b/lib/libc/stdlib/memory.3
new file mode 100644
index 0000000..a339043
--- /dev/null
+++ b/lib/libc/stdlib/memory.3
@@ -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.
+.\" 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.
+.\"
+.\" @(#)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 0000000..baf566b
--- /dev/null
+++ b/lib/libc/stdlib/merge.c
@@ -0,0 +1,355 @@
+/*-
+ * 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. 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.
+ */
+
+#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>
+
+static void setup(u_char *, u_char *, size_t, size_t,
+ int (*)(const void *, const void *));
+static void insertionsort(u_char *, size_t, size_t,
+ int (*)(const void *, const void *));
+
+#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)))
+
+/*
+ * Arguments are as for qsort.
+ */
+int
+mergesort(base, nmemb, size, cmp)
+ void *base;
+ size_t nmemb;
+ size_t size;
+ int (*cmp)(const void *, const void *);
+{
+ 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(list1, list2, n, size, cmp)
+ size_t n, size;
+ int (*cmp)(const void *, const void *);
+ u_char *list1, *list2;
+{
+ 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(a, n, size, cmp)
+ u_char *a;
+ size_t n, size;
+ int (*cmp)(const void *, const void *);
+{
+ 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/posix_memalign.3 b/lib/libc/stdlib/posix_memalign.3
new file mode 100644
index 0000000..6de2c4a
--- /dev/null
+++ b/lib/libc/stdlib/posix_memalign.3
@@ -0,0 +1,89 @@
+.\" Copyright (C) 2006 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 11, 2006
+.Dt POSIX_MEMALIGN 3
+.Os
+.Sh NAME
+.Nm posix_memalign
+.Nd aligned memory allocation
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft int
+.Fn posix_memalign "void **ptr" "size_t alignment" "size_t size"
+.Sh DESCRIPTION
+The
+.Fn posix_memalign
+function allocates
+.Fa size
+bytes of memory such that the allocation's base address is an even multiple of
+.Fa alignment ,
+and returns the allocation in the value pointed to by
+.Fa ptr .
+.Pp
+The requested
+.Fa alignment
+must be a power of 2 at least as large as sizeof(void *).
+.Pp
+Memory that is allocated via
+.Fn posix_memalign
+can be used as an argument in subsequent calls to
+.Xr realloc 3 ,
+.Xr reallocf 3 ,
+and
+.Xr free 3 .
+.Sh RETURN VALUES
+The
+.Fn posix_memalign
+function returns the value 0 if successful; otherwise it returns an error value.
+.Sh ERRORS
+The
+.Fn posix_memalign
+function will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa alignment
+parameter is not a power of 2 at least as large as sizeof(void *).
+.It Bq Er ENOMEM
+Memory allocation error.
+.El
+.Sh SEE ALSO
+.Xr malloc 3 ,
+.Xr valloc 3 ,
+.Xr realloc 3 ,
+.Xr reallocf 3 ,
+.Xr free 3
+.Sh STANDARDS
+The
+.Fn posix_memalign
+function conforms to
+.St -p1003.1-2001 .
diff --git a/lib/libc/stdlib/putenv.c b/lib/libc/stdlib/putenv.c
new file mode 100644
index 0000000..1aa9998
--- /dev/null
+++ b/lib/libc/stdlib/putenv.c
@@ -0,0 +1,60 @@
+/*-
+ * 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. 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)putenv.c 8.2 (Berkeley) 3/27/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h>
+#include <string.h>
+
+int
+putenv(str)
+ const char *str;
+{
+ char *p, *equal;
+ int rval;
+
+ if ((p = strdup(str)) == NULL)
+ return (-1);
+ if ((equal = index(p, '=')) == NULL) {
+ (void)free(p);
+ return (-1);
+ }
+ *equal = '\0';
+ rval = setenv(p, equal + 1, 1);
+ (void)free(p);
+ return (rval);
+}
diff --git a/lib/libc/stdlib/qsort.3 b/lib/libc/stdlib/qsort.3
new file mode 100644
index 0000000..a55b2e3
--- /dev/null
+++ b/lib/libc/stdlib/qsort.3
@@ -0,0 +1,290 @@
+.\" 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. 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.
+.\"
+.\" @(#)qsort.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd September 30, 2003
+.Dt QSORT 3
+.Os
+.Sh NAME
+.Nm qsort , qsort_r , heapsort , mergesort
+.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_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 mergesort
+.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.
+.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 mergesort
+algorithm is stable.
+.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 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 .
diff --git a/lib/libc/stdlib/qsort.c b/lib/libc/stdlib/qsort.c
new file mode 100644
index 0000000..47e563a
--- /dev/null
+++ b/lib/libc/stdlib/qsort.c
@@ -0,0 +1,197 @@
+/*-
+ * 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. 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.
+ */
+
+#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);
+
+#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(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
+ es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;
+
+static inline void
+swapfunc(a, b, n, swaptype)
+ char *a, *b;
+ int n, swaptype;
+{
+ if(swaptype <= 1)
+ swapcode(long, a, b, n)
+ else
+ swapcode(char, a, b, n)
+}
+
+#define swap(a, b) \
+ if (swaptype == 0) { \
+ long t = *(long *)(a); \
+ *(long *)(a) = *(long *)(b); \
+ *(long *)(b) = t; \
+ } else \
+ swapfunc(a, b, es, swaptype)
+
+#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype)
+
+#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;
+ int d, r, swaptype, swap_cnt;
+
+loop: SWAPINIT(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 && (r = CMP(thunk, pb, a)) <= 0) {
+ if (r == 0) {
+ swap_cnt = 1;
+ swap(pa, pb);
+ pa += es;
+ }
+ pb += es;
+ }
+ while (pb <= pc && (r = CMP(thunk, pc, a)) >= 0) {
+ if (r == 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 0000000..d868736
--- /dev/null
+++ b/lib/libc/stdlib/qsort_r.c
@@ -0,0 +1,8 @@
+/*
+ * This file is in the public domain. Originally written by Garrett
+ * A. Wollman.
+ *
+ * $FreeBSD$
+ */
+#define I_AM_QSORT_R
+#include "qsort.c"
diff --git a/lib/libc/stdlib/radixsort.3 b/lib/libc/stdlib/radixsort.3
new file mode 100644
index 0000000..da4ed16
--- /dev/null
+++ b/lib/libc/stdlib/radixsort.3
@@ -0,0 +1,164 @@
+.\" 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. 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.
+.\"
+.\" @(#)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 0000000..9334744
--- /dev/null
+++ b/lib/libc/stdlib/radixsort.c
@@ -0,0 +1,331 @@
+/*-
+ * 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. 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.
+ */
+
+#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(a, n, tab, endch)
+ const u_char **a, *tab;
+ int n;
+ 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(a, n, tab, endch)
+ const u_char **a, *tab;
+ int n;
+ 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(a, n, i, tr, endch)
+ const u_char **a;
+ int n, 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(a, ta, n, i, tr, endch)
+ const u_char **a, **ta;
+ int n, 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;
+ }
+}
+
+static inline void
+simplesort(a, n, b, tr, endch) /* insertion sort */
+ const u_char **a;
+ int n, 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 0000000..ee24dba
--- /dev/null
+++ b/lib/libc/stdlib/rand.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
+.\" 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. 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.
+.\"
+.\" @(#)rand.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd May 25, 1999
+.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
+These interfaces are obsoleted by
+.Xr random 3 .
+.Ef
+.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 the
+.Xr random 4
+random number device which returns good random numbers.
+However, the
+.Fn rand
+function still remains unsuitable for cryptographic use.
+.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.
+.Sh SEE ALSO
+.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 0000000..c412133
--- /dev/null
+++ b/lib/libc/stdlib/rand.c
@@ -0,0 +1,172 @@
+/*-
+ * 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. 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.
+ *
+ * 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/time.h> /* for sranddev() */
+#include <sys/types.h>
+#include <fcntl.h> /* for sranddev() */
+#include <stdlib.h>
+#include <unistd.h> /* for sranddev() */
+#include "un-namespace.h"
+
+#ifdef TEST
+#include <stdio.h>
+#endif /* TEST */
+
+static int
+do_rand(unsigned long *ctx)
+{
+#ifdef USE_WEAK_SEEDING
+/*
+ * Historic implementation compatibility.
+ * The random sequences do not vary much with the seed,
+ * even with overflowing.
+ */
+ return ((*ctx = *ctx * 1103515245 + 12345) % ((u_long)RAND_MAX + 1));
+#else /* !USE_WEAK_SEEDING */
+/*
+ * 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.
+ */
+ long hi, lo, x;
+
+ /* Can't be initialized with 0, so use another value. */
+ if (*ctx == 0)
+ *ctx = 123459876;
+ hi = *ctx / 127773;
+ lo = *ctx % 127773;
+ x = 16807 * lo - 2836 * hi;
+ if (x < 0)
+ x += 0x7fffffff;
+ return ((*ctx = x) % ((u_long)RAND_MAX + 1));
+#endif /* !USE_WEAK_SEEDING */
+}
+
+
+int
+rand_r(unsigned int *ctx)
+{
+ u_long val = (u_long) *ctx;
+ int r = do_rand(&val);
+
+ *ctx = (unsigned int) val;
+ return (r);
+}
+
+
+static u_long next = 1;
+
+int
+rand()
+{
+ return (do_rand(&next));
+}
+
+void
+srand(seed)
+u_int seed;
+{
+ next = seed;
+}
+
+
+/*
+ * sranddev:
+ *
+ * Many programs choose the seed value in a totally predictable manner.
+ * This often causes problems. We seed the generator using the much more
+ * secure random(4) interface.
+ */
+void
+sranddev()
+{
+ int fd, done;
+
+ done = 0;
+ fd = _open("/dev/random", O_RDONLY, 0);
+ if (fd >= 0) {
+ if (_read(fd, (void *) &next, sizeof(next)) == sizeof(next))
+ done = 1;
+ _close(fd);
+ }
+
+ if (!done) {
+ struct timeval tv;
+ unsigned long junk;
+
+ gettimeofday(&tv, NULL);
+ srand((getpid() << 16) ^ tv.tv_sec ^ tv.tv_usec ^ junk);
+ }
+}
+
+
+#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 0000000..70709ca
--- /dev/null
+++ b/lib/libc/stdlib/random.3
@@ -0,0 +1,199 @@
+.\" 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. 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.
+.\"
+.\" @(#)random.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.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 long seed"
+.Ft void
+.Fn srandomdev void
+.Ft char *
+.Fn initstate "unsigned long seed" "char *state" "long n"
+.Ft char *
+.Fn setstate "char *state"
+.Sh DESCRIPTION
+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 the
+.Xr random 4
+random number device which returns good random numbers,
+suitable for cryptographic use.
+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, error
+messages are printed on the standard error output.
+.Sh SEE ALSO
+.Xr arc4random 3 ,
+.Xr rand 3 ,
+.Xr srand 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.
+.Pp
+Applications requiring cryptographic quality randomness should use
+.Xr arc4random 3 .
diff --git a/lib/libc/stdlib/random.c b/lib/libc/stdlib/random.c
new file mode 100644
index 0000000..768d125
--- /dev/null
+++ b/lib/libc/stdlib/random.c
@@ -0,0 +1,506 @@
+/*
+ * 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. 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.
+ */
+
+#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/time.h> /* for srandomdev() */
+#include <fcntl.h> /* for srandomdev() */
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h> /* for srandomdev() */
+#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 */
+
+#ifdef USE_WEAK_SEEDING
+#define NSHUFF 0
+#else /* !USE_WEAK_SEEDING */
+#define NSHUFF 50 /* to drop some "seed -> 1st value" linearity */
+#endif /* !USE_WEAK_SEEDING */
+
+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,
+#ifdef USE_WEAK_SEEDING
+/* Historic implementation compatibility */
+/* The random sequences do not vary much with the seed */
+ 0x9a319039, 0x32d9c024, 0x9b663182, 0x5da1f342, 0xde3b81e0, 0xdf0a6fb5,
+ 0xf103bc02, 0x48f340fb, 0x7449e56b, 0xbeb1dbb0, 0xab5c5918, 0x946554fd,
+ 0x8c2e680f, 0xeb3d799f, 0xb11ee0b7, 0x2d436b86, 0xda672e2a, 0x1588ca88,
+ 0xe369735d, 0x904f35f7, 0xd7158fd6, 0x6fa6f051, 0x616e6b96, 0xac94efdc,
+ 0x36413f93, 0xc622c298, 0xf5a42ab8, 0x8a88d77b, 0xf5ad9d0e, 0x8999220b,
+ 0x27fb47b9,
+#else /* !USE_WEAK_SEEDING */
+ 0x991539b1, 0x16a5bce3, 0x6774a4cd, 0x3e01511e, 0x4e508aaa, 0x61048c05,
+ 0xf5500617, 0x846b7115, 0x6a19892c, 0x896a97af, 0xdb48f936, 0x14898454,
+ 0x37ffd106, 0xb58bff9c, 0x59e17104, 0xcf918a49, 0x09378c83, 0x52c7a471,
+ 0x8d293ea9, 0x1f4fc301, 0xc3db71be, 0x39b44e1c, 0xf8a44ef9, 0x4c8b80b1,
+ 0x19edc328, 0x87bf4bdd, 0xc9b240e5, 0xe9ee4b1b, 0x4382aee7, 0x535b6b41,
+ 0xf3bec5da
+#endif /* !USE_WEAK_SEEDING */
+};
+
+/*
+ * 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(int32_t);
+
+static inline uint32_t good_rand (x)
+ int32_t x;
+{
+#ifdef USE_WEAK_SEEDING
+/*
+ * Historic implementation compatibility.
+ * The random sequences do not vary much with the seed,
+ * even with overflowing.
+ */
+ return (1103515245 * x + 12345);
+#else /* !USE_WEAK_SEEDING */
+/*
+ * 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;
+
+ /* Can't be initialized with 0, so use another value. */
+ if (x == 0)
+ x = 123459876;
+ hi = x / 127773;
+ lo = x % 127773;
+ x = 16807 * lo - 2836 * hi;
+ if (x < 0)
+ x += 0x7fffffff;
+ return (x);
+#endif /* !USE_WEAK_SEEDING */
+}
+
+/*
+ * 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(x)
+ unsigned long 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 the much more
+ * secure random(4) interface. 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()
+{
+ int fd, done;
+ size_t len;
+
+ if (rand_type == TYPE_0)
+ len = sizeof state[0];
+ else
+ len = rand_deg * sizeof state[0];
+
+ done = 0;
+ fd = _open("/dev/random", O_RDONLY, 0);
+ if (fd >= 0) {
+ if (_read(fd, (void *) state, len) == (ssize_t) len)
+ done = 1;
+ _close(fd);
+ }
+
+ if (!done) {
+ struct timeval tv;
+ unsigned long junk;
+
+ gettimeofday(&tv, NULL);
+ srandom((getpid() << 16) ^ tv.tv_sec ^ tv.tv_usec ^ junk);
+ return;
+ }
+
+ 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(seed, arg_state, n)
+ unsigned long seed; /* seed for R.N.G. */
+ char *arg_state; /* pointer to state array */
+ long n; /* # bytes of state info */
+{
+ char *ostate = (char *)(&state[-1]);
+ uint32_t *int_arg_state = (uint32_t *)arg_state;
+
+ if (rand_type == TYPE_0)
+ state[-1] = rand_type;
+ else
+ state[-1] = MAX_TYPES * (rptr - state) + rand_type;
+ if (n < BREAK_0) {
+ (void)fprintf(stderr,
+ "random: not enough state (%ld bytes); ignored.\n", n);
+ return(0);
+ }
+ 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(arg_state)
+ char *arg_state; /* pointer to state array */
+{
+ 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 (rand_type == TYPE_0)
+ state[-1] = rand_type;
+ else
+ state[-1] = MAX_TYPES * (rptr - state) + rand_type;
+ switch(type) {
+ case TYPE_0:
+ case TYPE_1:
+ case TYPE_2:
+ case TYPE_3:
+ case TYPE_4:
+ rand_type = type;
+ rand_deg = degrees[type];
+ rand_sep = seps[type];
+ break;
+ default:
+ (void)fprintf(stderr,
+ "random: state info corrupted; not changed.\n");
+ }
+ 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()
+{
+ uint32_t i;
+ uint32_t *f, *r;
+
+ if (rand_type == TYPE_0) {
+ i = state[0];
+ state[0] = i = (good_rand(i)) & 0x7fffffff;
+ } else {
+ /*
+ * Use local variables rather than static variables for speed.
+ */
+ f = fptr; r = rptr;
+ *f += *r;
+ i = (*f >> 1) & 0x7fffffff; /* 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/reallocf.c b/lib/libc/stdlib/reallocf.c
new file mode 100644
index 0000000..5320926
--- /dev/null
+++ b/lib/libc/stdlib/reallocf.c
@@ -0,0 +1,41 @@
+/*-
+ * 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);
+ if (!nptr && ptr)
+ free(ptr);
+ return (nptr);
+}
diff --git a/lib/libc/stdlib/realpath.3 b/lib/libc/stdlib/realpath.3
new file mode 100644
index 0000000..3593df7
--- /dev/null
+++ b/lib/libc/stdlib/realpath.3
@@ -0,0 +1,124 @@
+.\" 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. 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.
+.\"
+.\" @(#)realpath.3 8.2 (Berkeley) 2/16/94
+.\" $FreeBSD$
+.\"
+.Dd February 16, 1994
+.Dt REALPATH 3
+.Os
+.Sh NAME
+.Nm realpath
+.Nd returns the canonicalized absolute pathname
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/param.h
+.In stdlib.h
+.Ft "char *"
+.Fn realpath "const char *pathname" "char resolved_path[PATH_MAX]"
+.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 referenced by
+.Fa resolved_path .
+The
+.Fa resolved_path
+argument
+.Em must
+refer to a buffer capable of storing at least
+.Dv PATH_MAX
+characters.
+.Pp
+The
+.Fn realpath
+function will resolve both absolute and relative paths
+and return the absolute pathname corresponding to
+.Fa pathname .
+All but the last component of
+.Fa pathname
+must exist when
+.Fn realpath
+is called.
+.Sh "RETURN VALUES"
+The
+.Fn realpath
+function returns
+.Fa resolved_path
+on success.
+If an error occurs,
+.Fn realpath
+returns
+.Dv NULL ,
+and
+.Fa resolved_path
+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 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 .
+.Sh "SEE ALSO"
+.Xr getcwd 3
+.Sh HISTORY
+The
+.Fn realpath
+function first appeared in
+.Bx 4.4 .
diff --git a/lib/libc/stdlib/realpath.c b/lib/libc/stdlib/realpath.c
new file mode 100644
index 0000000..3082f5f
--- /dev/null
+++ b/lib/libc/stdlib/realpath.c
@@ -0,0 +1,197 @@
+/*
+ * 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"
+
+/*
+ * char *realpath(const char *path, char resolved[PATH_MAX]);
+ *
+ * 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 *path, char resolved[PATH_MAX])
+{
+ struct stat sb;
+ char *p, *q, *s;
+ size_t left_len, resolved_len;
+ unsigned symlinks;
+ int serrno, slen;
+ char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX];
+
+ serrno = errno;
+ 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) {
+ strlcpy(resolved, ".", PATH_MAX);
+ return (NULL);
+ }
+ resolved_len = strlen(resolved);
+ left_len = strlcpy(left, path, sizeof(left));
+ }
+ if (left_len >= sizeof(left) || resolved_len >= PATH_MAX) {
+ 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)) {
+ 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) {
+ errno = ENAMETOOLONG;
+ return (NULL);
+ }
+ resolved[resolved_len++] = '/';
+ resolved[resolved_len] = '\0';
+ }
+ if (next_token[0] == '\0')
+ 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. If
+ * lstat() fails we still can return successfully if
+ * there are no more path components left.
+ */
+ resolved_len = strlcat(resolved, next_token, PATH_MAX);
+ if (resolved_len >= PATH_MAX) {
+ errno = ENAMETOOLONG;
+ return (NULL);
+ }
+ if (lstat(resolved, &sb) != 0) {
+ if (errno == ENOENT && p == NULL) {
+ errno = serrno;
+ return (resolved);
+ }
+ return (NULL);
+ }
+ if (S_ISLNK(sb.st_mode)) {
+ if (symlinks++ > MAXSYMLINKS) {
+ errno = ELOOP;
+ return (NULL);
+ }
+ slen = readlink(resolved, symlink, sizeof(symlink) - 1);
+ if (slen < 0)
+ 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)) {
+ errno = ENAMETOOLONG;
+ return (NULL);
+ }
+ symlink[slen] = '/';
+ symlink[slen + 1] = 0;
+ }
+ left_len = strlcat(symlink, left, sizeof(left));
+ if (left_len >= sizeof(left)) {
+ errno = ENAMETOOLONG;
+ return (NULL);
+ }
+ }
+ left_len = strlcpy(left, symlink, sizeof(left));
+ }
+ }
+
+ /*
+ * 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 0000000..0a2f28f
--- /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/setenv.c b/lib/libc/stdlib/setenv.c
new file mode 100644
index 0000000..5c6d906
--- /dev/null
+++ b/lib/libc/stdlib/setenv.c
@@ -0,0 +1,120 @@
+/*
+ * 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. 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)setenv.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 *__findenv(const char *, int *);
+
+/*
+ * setenv --
+ * Set the value of the environmental variable "name" to be
+ * "value". If rewrite is set, replace any current value.
+ */
+int
+setenv(name, value, rewrite)
+ const char *name;
+ const char *value;
+ int rewrite;
+{
+ extern char **environ;
+ static char **alloced; /* if allocated space before */
+ char *c;
+ int l_value, offset;
+
+ if (*value == '=') /* no `=' in value */
+ ++value;
+ l_value = strlen(value);
+ if ((c = __findenv(name, &offset))) { /* find if already exists */
+ if (!rewrite)
+ return (0);
+ if (strlen(c) >= l_value) { /* old larger; copy over */
+ while ( (*c++ = *value++) );
+ return (0);
+ }
+ } else { /* create new slot */
+ int cnt;
+ char **p;
+
+ for (p = environ, cnt = 0; *p; ++p, ++cnt);
+ if (alloced == environ) { /* just increase size */
+ p = (char **)realloc((char *)environ,
+ (size_t)(sizeof(char *) * (cnt + 2)));
+ if (!p)
+ return (-1);
+ alloced = environ = p;
+ }
+ else { /* get new space */
+ /* copy old entries into it */
+ p = malloc((size_t)(sizeof(char *) * (cnt + 2)));
+ if (!p)
+ return (-1);
+ bcopy(environ, p, cnt * sizeof(char *));
+ alloced = environ = p;
+ }
+ environ[cnt + 1] = NULL;
+ offset = cnt;
+ }
+ for (c = (char *)name; *c && *c != '='; ++c); /* no `=' in name */
+ if (!(environ[offset] = /* name + `=' + value */
+ malloc((size_t)((int)(c - name) + l_value + 2))))
+ return (-1);
+ for (c = environ[offset]; (*c = *name++) && *c != '='; ++c);
+ for (*c++ = '='; (*c++ = *value++); );
+ return (0);
+}
+
+/*
+ * unsetenv(name) --
+ * Delete environmental variable "name".
+ */
+void
+unsetenv(name)
+ const char *name;
+{
+ extern char **environ;
+ char **p;
+ int offset;
+
+ while (__findenv(name, &offset)) /* if set multiple times */
+ for (p = &environ[offset];; ++p)
+ if (!(*p = *(p + 1)))
+ break;
+}
diff --git a/lib/libc/stdlib/strfmon.3 b/lib/libc/stdlib/strfmon.3
new file mode 100644
index 0000000..11b8e21
--- /dev/null
+++ b/lib/libc/stdlib/strfmon.3
@@ -0,0 +1,167 @@
+.\" 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 October 12, 2002
+.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" "..."
+.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 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 NULL
+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 NULL
+byte.
+Otherwise, \-1 is returned,
+the contents of the array are indeterminate,
+and
+.Va errno
+is set to indicate the error.
+.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 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Fn strfmon
+function was implemented by
+.An Alexey Zelkin Aq phantom@FreeBSD.org .
+.Pp
+This manual page was written by
+.An Jeroen Ruigrok van der Werven Aq 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 0000000..db78232
--- /dev/null
+++ b/lib/libc/stdlib/strfmon.c
@@ -0,0 +1,604 @@
+/*-
+ * 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 <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>
+
+/* 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 /* supress 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)) { \
+ VAR *= 10; \
+ VAR += *fmt - '0'; \
+ 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);
+
+ssize_t
+strfmon(char * __restrict s, size_t maxsize, 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;
+
+ va_start(ap, format);
+
+ lc = localeconv();
+ 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 (dst + width >= s + maxsize)
+ goto e2big_error;
+ }
+
+ /* Left precision */
+ if (*fmt == '#') {
+ if (!isdigit((unsigned char)*++fmt))
+ goto format_error;
+ GET_NUMBER(left_prec);
+ }
+
+ /* Right precision */
+ if (*fmt == '.') {
+ if (!isdigit((unsigned char)*++fmt))
+ goto format_error;
+ GET_NUMBER(right_prec);
+ }
+
+ /* 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 (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;
+ }
+
+ 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');
+ va_end(ap);
+ 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;
+ va_end(ap);
+ return (-1);
+}
+
+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') ? "-"
+ : 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') ? "-"
+ : 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;
+ char fmt[32];
+
+ 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 */
+ snprintf(fmt, sizeof(fmt), "%%%d.%df", left_prec + right_prec + 1,
+ right_prec);
+ avalue_size = asprintf(&avalue, fmt, value);
+ if (avalue_size < 0)
+ return (NULL);
+
+ /* make sure that we've enough space for result string */
+ bufsize = strlen(avalue)*2+1;
+ rslt = malloc(bufsize);
+ if (rslt == NULL) {
+ free(avalue);
+ return (NULL);
+ }
+ memset(rslt, 0, bufsize);
+ bufend = rslt + bufsize - 1; /* reserve space for trailing '\0' */
+
+ /* skip spaces at beggining */
+ 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 0000000..37092bf
--- /dev/null
+++ b/lib/libc/stdlib/strtod.3
@@ -0,0 +1,185 @@
+.\" 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. 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.
+.\"
+.\" @(#)strtod.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd March 2, 2003
+.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 ``INFINITY'' or ``NAN'', ignoring
+case, it is interpreted as an infinity or a quiet NaN, respectively.
+.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 strtol 3 ,
+.Xr strtoul 3 ,
+.Xr wcstod 3
+.Sh STANDARDS
+The
+.Fn strtod
+function
+conforms to
+.St -isoC-99 ,
+with the exception of the bug noted below.
+.Sh AUTHORS
+The author of this software is
+.An David M. Gay .
+.Pp
+.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
+.Sh BUGS
+These routines do not recognize the C99 ``NaN(...)'' syntax.
diff --git a/lib/libc/stdlib/strtoimax.c b/lib/libc/stdlib/strtoimax.c
new file mode 100644
index 0000000..46ef2ba
--- /dev/null
+++ b/lib/libc/stdlib/strtoimax.c
@@ -0,0 +1,144 @@
+/*-
+ * 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. 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.
+ */
+
+#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>
+
+/*
+ * Convert a string to an intmax_t integer.
+ *
+ * Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+intmax_t
+strtoimax(const char * __restrict nptr, char ** __restrict endptr, int base)
+{
+ const char *s;
+ uintmax_t acc;
+ char c;
+ uintmax_t cutoff;
+ int neg, any, cutlim;
+
+ /*
+ * 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((unsigned char)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') &&
+ ((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);
+}
diff --git a/lib/libc/stdlib/strtol.3 b/lib/libc/stdlib/strtol.3
new file mode 100644
index 0000000..b9e8b4a
--- /dev/null
+++ b/lib/libc/stdlib/strtol.3
@@ -0,0 +1,226 @@
+.\" 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. 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.
+.\"
+.\" @(#)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 overflow" ".Sy underflow"
+.It Sy Function Ta Sy overflow Ta Sy underflow
+.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 0000000..1a6e818
--- /dev/null
+++ b/lib/libc/stdlib/strtol.c
@@ -0,0 +1,144 @@
+/*-
+ * 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. 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.
+ */
+
+#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>
+
+
+/*
+ * Convert a string to a long integer.
+ *
+ * Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+long
+strtol(const char * __restrict nptr, char ** __restrict endptr, int base)
+{
+ const char *s;
+ unsigned long acc;
+ char c;
+ unsigned long cutoff;
+ int neg, any, cutlim;
+
+ /*
+ * 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((unsigned char)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') &&
+ ((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);
+}
diff --git a/lib/libc/stdlib/strtoll.c b/lib/libc/stdlib/strtoll.c
new file mode 100644
index 0000000..f965892
--- /dev/null
+++ b/lib/libc/stdlib/strtoll.c
@@ -0,0 +1,144 @@
+/*-
+ * 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. 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.
+ */
+
+#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>
+
+/*
+ * Convert a string to a long long integer.
+ *
+ * Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+long long
+strtoll(const char * __restrict nptr, char ** __restrict endptr, int base)
+{
+ const char *s;
+ unsigned long long acc;
+ char c;
+ unsigned long long cutoff;
+ int neg, any, cutlim;
+
+ /*
+ * 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((unsigned char)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') &&
+ ((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);
+}
diff --git a/lib/libc/stdlib/strtonum.3 b/lib/libc/stdlib/strtonum.3
new file mode 100644
index 0000000..5be86d7
--- /dev/null
+++ b/lib/libc/stdlib/strtonum.3
@@ -0,0 +1,154 @@
+.\" Copyright (c) 2004 Ted Unangst
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.\" $OpenBSD: strtonum.3,v 1.12 2005/10/26 11:37:58 jmc Exp $
+.\" $FreeBSD$
+.\"
+.Dd April 29, 2004
+.Dt STRTONUM 3
+.Os
+.Sh NAME
+.Nm strtonum
+.Nd "reliably convert string value to an integer"
+.Sh SYNOPSIS
+.Fd #include <stdlib.h>
+.Fd #include <limits.h>
+.Ft long long
+.Fo strtonum
+.Fa "const char *nptr"
+.Fa "long long minval"
+.Fa "long long maxval"
+.Fa "const char **errstr"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn strtonum
+function converts the string in
+.Fa nptr
+to a
+.Li 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
+.Li 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.
+.Fa *errstr
+will be set to
+.Dv NULL
+on success;
+this fact can be used to differentiate
+a successful return of 0 from an error.
+.Sh EXAMPLES
+Using
+.Fn strtonum
+correctly is meant to be simpler than the alternative functions.
+.Bd -literal -offset indent
+int iterations;
+const char *errstr;
+
+iterations = strtonum(optarg, 1, 64, &errstr);
+if (errstr)
+ errx(1, "number of iterations is %s: %s", errstr, optarg);
+.Ed
+.Pp
+The above example will guarantee that the value of iterations is between
+1 and 64 (inclusive).
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er ERANGE
+The given string was out of range.
+.It Bq Er EINVAL
+The given string did not consist solely of digit characters.
+.It Bq Er EINVAL
+.Ar minval
+was larger than
+.Ar maxval .
+.El
+.Pp
+If an error occurs,
+.Fa errstr
+will be set to one of the following strings:
+.Pp
+.Bl -tag -width "too largeXX" -compact
+.It too large
+The result was larger than the provided maximum value.
+.It too small
+The result was smaller than the provided minimum value.
+.It 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
+.Fn strtonum
+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 0000000..6dccd97
--- /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.6 2004/08/03 19:38:01 millert Exp $
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#define INVALID 1
+#define TOOSMALL 2
+#define TOOLARGE 3
+
+long long
+strtonum(const char *numstr, long long minval, long long maxval,
+ const char **errstrp)
+{
+ long long ll = 0;
+ char *ep;
+ int error = 0;
+ struct errval {
+ const char *errstr;
+ int err;
+ } ev[4] = {
+ { NULL, 0 },
+ { "invalid", EINVAL },
+ { "too small", ERANGE },
+ { "too large", ERANGE },
+ };
+
+ ev[0].err = errno;
+ errno = 0;
+ if (minval > maxval)
+ error = INVALID;
+ else {
+ ll = strtoll(numstr, &ep, 10);
+ if (errno == EINVAL || numstr == ep || *ep != '\0')
+ error = INVALID;
+ else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval)
+ error = TOOSMALL;
+ else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval)
+ error = TOOLARGE;
+ }
+ if (errstrp != NULL)
+ *errstrp = ev[error].errstr;
+ errno = ev[error].err;
+ if (error)
+ ll = 0;
+
+ return (ll);
+}
diff --git a/lib/libc/stdlib/strtoq.c b/lib/libc/stdlib/strtoq.c
new file mode 100644
index 0000000..a3e37af
--- /dev/null
+++ b/lib/libc/stdlib/strtoq.c
@@ -0,0 +1,52 @@
+/*-
+ * 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. 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.
+ */
+
+#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 0000000..4eff5a7
--- /dev/null
+++ b/lib/libc/stdlib/strtoul.3
@@ -0,0 +1,228 @@
+.\" 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. 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.
+.\"
+.\" @(#)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 0000000..8bcc2a4
--- /dev/null
+++ b/lib/libc/stdlib/strtoul.c
@@ -0,0 +1,122 @@
+/*
+ * 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. 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.
+ */
+
+#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>
+
+/*
+ * Convert a string to an unsigned long integer.
+ *
+ * Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+unsigned long
+strtoul(const char * __restrict nptr, char ** __restrict endptr, int base)
+{
+ const char *s;
+ unsigned long acc;
+ char c;
+ unsigned long cutoff;
+ int neg, any, cutlim;
+
+ /*
+ * See strtol for comments as to the logic used.
+ */
+ s = nptr;
+ do {
+ c = *s++;
+ } while (isspace((unsigned char)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') &&
+ ((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);
+}
diff --git a/lib/libc/stdlib/strtoull.c b/lib/libc/stdlib/strtoull.c
new file mode 100644
index 0000000..2a454b9
--- /dev/null
+++ b/lib/libc/stdlib/strtoull.c
@@ -0,0 +1,122 @@
+/*-
+ * 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. 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.
+ */
+
+#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>
+
+/*
+ * 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(const char * __restrict nptr, char ** __restrict endptr, int base)
+{
+ const char *s;
+ unsigned long long acc;
+ char c;
+ unsigned long long cutoff;
+ int neg, any, cutlim;
+
+ /*
+ * See strtoq for comments as to the logic used.
+ */
+ s = nptr;
+ do {
+ c = *s++;
+ } while (isspace((unsigned char)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') &&
+ ((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);
+}
diff --git a/lib/libc/stdlib/strtoumax.c b/lib/libc/stdlib/strtoumax.c
new file mode 100644
index 0000000..c81b9d1
--- /dev/null
+++ b/lib/libc/stdlib/strtoumax.c
@@ -0,0 +1,122 @@
+/*-
+ * 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. 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.
+ */
+
+#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>
+
+/*
+ * Convert a string to a uintmax_t integer.
+ *
+ * Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+uintmax_t
+strtoumax(const char * __restrict nptr, char ** __restrict endptr, int base)
+{
+ const char *s;
+ uintmax_t acc;
+ char c;
+ uintmax_t cutoff;
+ int neg, any, cutlim;
+
+ /*
+ * See strtoimax for comments as to the logic used.
+ */
+ s = nptr;
+ do {
+ c = *s++;
+ } while (isspace((unsigned char)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') &&
+ ((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);
+}
diff --git a/lib/libc/stdlib/strtouq.c b/lib/libc/stdlib/strtouq.c
new file mode 100644
index 0000000..1a14f36
--- /dev/null
+++ b/lib/libc/stdlib/strtouq.c
@@ -0,0 +1,52 @@
+/*-
+ * 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. 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.
+ */
+
+#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 0000000..60707b4
--- /dev/null
+++ b/lib/libc/stdlib/system.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
+.\" 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. 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.
+.\"
+.\" @(#)system.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.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.
+.Pp
+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
+.Sh STANDARDS
+The
+.Fn system
+function
+conforms to
+.St -isoC
+and is expected to be
+.St -p1003.2
+compatible.
diff --git a/lib/libc/stdlib/system.c b/lib/libc/stdlib/system.c
new file mode 100644
index 0000000..ac14ae9
--- /dev/null
+++ b/lib/libc/stdlib/system.c
@@ -0,0 +1,102 @@
+/*
+ * 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. 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.
+ */
+
+#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 <unistd.h>
+#include <paths.h>
+#include <errno.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+
+int
+__system(command)
+ const char *command;
+{
+ pid_t pid, savedpid;
+ int pstat;
+ struct sigaction ign, intact, quitact;
+ sigset_t newsigblock, oldsigblock;
+
+ if (!command) /* just checking... */
+ return(1);
+
+ /*
+ * Ignore SIGINT and SIGQUIT, block SIGCHLD. Remember to save
+ * existing signal dispositions.
+ */
+ ign.sa_handler = SIG_IGN;
+ (void)sigemptyset(&ign.sa_mask);
+ ign.sa_flags = 0;
+ (void)_sigaction(SIGINT, &ign, &intact);
+ (void)_sigaction(SIGQUIT, &ign, &quitact);
+ (void)sigemptyset(&newsigblock);
+ (void)sigaddset(&newsigblock, SIGCHLD);
+ (void)_sigprocmask(SIG_BLOCK, &newsigblock, &oldsigblock);
+ switch(pid = fork()) {
+ case -1: /* error */
+ break;
+ case 0: /* child */
+ /*
+ * Restore original signal dispositions and exec the command.
+ */
+ (void)_sigaction(SIGINT, &intact, NULL);
+ (void)_sigaction(SIGQUIT, &quitact, NULL);
+ (void)_sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
+ execl(_PATH_BSHELL, "sh", "-c", command, (char *)NULL);
+ _exit(127);
+ default: /* parent */
+ savedpid = pid;
+ do {
+ pid = _wait4(savedpid, &pstat, 0, (struct rusage *)0);
+ } while (pid == -1 && errno == EINTR);
+ break;
+ }
+ (void)_sigaction(SIGINT, &intact, NULL);
+ (void)_sigaction(SIGQUIT, &quitact, NULL);
+ (void)_sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
+ return(pid == -1 ? -1 : pstat);
+}
+
+__weak_reference(__system, system);
+__weak_reference(__system, _system);
diff --git a/lib/libc/stdlib/tdelete.c b/lib/libc/stdlib/tdelete.c
new file mode 100644
index 0000000..c83afb8
--- /dev/null
+++ b/lib/libc/stdlib/tdelete.c
@@ -0,0 +1,71 @@
+/* $NetBSD: tdelete.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.
+ *
+ * The node_t structure is for internal use only, lint doesn't grok it.
+ *
+ * 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: tdelete.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 <search.h>
+#include <stdlib.h>
+
+
+/*
+ * delete node with given key
+ *
+ * vkey: key to be deleted
+ * vrootp: address of the root of the tree
+ * compar: function to carry out node comparisons
+ */
+void *
+tdelete(const void * __restrict vkey, void ** __restrict vrootp,
+ int (*compar)(const void *, const void *))
+{
+ node_t **rootp = (node_t **)vrootp;
+ node_t *p, *q, *r;
+ int cmp;
+
+ if (rootp == NULL || (p = *rootp) == NULL)
+ return NULL;
+
+ while ((cmp = (*compar)(vkey, (*rootp)->key)) != 0) {
+ p = *rootp;
+ rootp = (cmp < 0) ?
+ &(*rootp)->llink : /* follow llink branch */
+ &(*rootp)->rlink; /* follow rlink branch */
+ if (*rootp == NULL)
+ return NULL; /* key not found */
+ }
+ r = (*rootp)->rlink; /* D1: */
+ if ((q = (*rootp)->llink) == NULL) /* Left NULL? */
+ q = r;
+ else if (r != NULL) { /* Right link is NULL? */
+ if (r->llink == NULL) { /* D2: Find successor */
+ r->llink = q;
+ q = r;
+ } else { /* D3: Find NULL link */
+ for (q = r->llink; q->llink != NULL; q = r->llink)
+ r = q;
+ r->llink = q->rlink;
+ q->llink = (*rootp)->llink;
+ q->rlink = (*rootp)->rlink;
+ }
+ }
+ free(*rootp); /* D4: Free node */
+ *rootp = q; /* link parent to new node */
+ return p;
+}
diff --git a/lib/libc/stdlib/tfind.c b/lib/libc/stdlib/tfind.c
new file mode 100644
index 0000000..c5d66cf
--- /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.
+ *
+ * The node_t structure is for internal use only, lint doesn't grok it.
+ *
+ * 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 */
+void *
+tfind(vkey, vrootp, compar)
+ const void *vkey; /* key to be found */
+ void * const *vrootp; /* address of the tree root */
+ int (*compar)(const void *, const void *);
+{
+ node_t **rootp = (node_t **)vrootp;
+
+ 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 0000000..c0af27f
--- /dev/null
+++ b/lib/libc/stdlib/tsearch.3
@@ -0,0 +1,132 @@
+.\" $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 June 15, 1997
+.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" "void ** restrict rootp" "int (*compar) (const void *, const void *)"
+.Ft void *
+.Fn tfind "const void *key" "void * const *rootp" "int (*compar) (const void *, const void *)"
+.Ft void *
+.Fn tsearch "const void *key" "void **rootp" "int (*compar) (const void *, const void *)"
+.Ft void
+.Fn twalk "const void *root" "void (*compar) (const void *, VISIT, int)"
+.Sh DESCRIPTION
+The
+.Fn tdelete ,
+.Fn tfind ,
+.Fn tsearch ,
+and
+.Fn twalk
+functions manage binary search trees based on algorithms T and D
+from Knuth (6.2.2).
+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
diff --git a/lib/libc/stdlib/tsearch.c b/lib/libc/stdlib/tsearch.c
new file mode 100644
index 0000000..149c2bb
--- /dev/null
+++ b/lib/libc/stdlib/tsearch.c
@@ -0,0 +1,58 @@
+/* $NetBSD: tsearch.c,v 1.3 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.
+ *
+ * The node_t structure is for internal use only, lint doesn't grok it.
+ *
+ * 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: tsearch.c,v 1.3 1999/09/16 11:45:37 lukem Exp $");
+#endif /* LIBC_SCCS and not lint */
+#endif
+__FBSDID("$FreeBSD$");
+
+#define _SEARCH_PRIVATE
+#include <search.h>
+#include <stdlib.h>
+
+/* find or insert datum into search tree */
+void *
+tsearch(vkey, vrootp, compar)
+ const void *vkey; /* key to be located */
+ void **vrootp; /* address of tree root */
+ int (*compar)(const void *, const void *);
+{
+ node_t *q;
+ node_t **rootp = (node_t **)vrootp;
+
+ if (rootp == NULL)
+ return NULL;
+
+ while (*rootp != NULL) { /* Knuth's T1: */
+ int r;
+
+ if ((r = (*compar)(vkey, (*rootp)->key)) == 0) /* T2: */
+ return *rootp; /* we found it! */
+
+ rootp = (r < 0) ?
+ &(*rootp)->llink : /* T3: follow left branch */
+ &(*rootp)->rlink; /* T4: follow right branch */
+ }
+
+ q = malloc(sizeof(node_t)); /* T5: key not found */
+ if (q != 0) { /* make new node */
+ *rootp = q; /* link new node to old */
+ /* LINTED const castaway ok */
+ q->key = (void *)vkey; /* initialize new node */
+ q->llink = q->rlink = NULL;
+ }
+ return q;
+}
diff --git a/lib/libc/stdlib/twalk.c b/lib/libc/stdlib/twalk.c
new file mode 100644
index 0000000..55f220f3
--- /dev/null
+++ b/lib/libc/stdlib/twalk.c
@@ -0,0 +1,58 @@
+/* $NetBSD: twalk.c,v 1.1 1999/02/22 10:33:16 christos Exp $ */
+
+/*
+ * Tree search generalized from Knuth (6.2.2) Algorithm T just like
+ * the AT&T man page says.
+ *
+ * The node_t structure is for internal use only, lint doesn't grok it.
+ *
+ * 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.1 1999/02/22 10:33:16 christos Exp $");
+#endif /* LIBC_SCCS and not lint */
+#endif
+__FBSDID("$FreeBSD$");
+
+#define _SEARCH_PRIVATE
+#include <search.h>
+#include <stdlib.h>
+
+static void trecurse(const node_t *,
+ void (*action)(const void *, VISIT, int), int level);
+
+/* Walk the nodes of a tree */
+static void
+trecurse(root, action, level)
+ const node_t *root; /* Root of the tree to be walked */
+ void (*action)(const void *, VISIT, int);
+ 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(vroot, action)
+ const void *vroot; /* Root of the tree to be walked */
+ void (*action)(const void *, VISIT, int);
+{
+ 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 0000000..a58a8a2
--- /dev/null
+++ b/lib/libc/stdtime/Makefile.inc
@@ -0,0 +1,18 @@
+# Makefile.inc,v 1.2 1994/09/13 21:26:01 wollman Exp
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/stdtime ${.CURDIR}/../locale
+
+SRCS+= asctime.c difftime.c localtime.c strftime.c strptime.c timelocal.c \
+ time32.c
+
+SYM_MAPS+= ${.CURDIR}/stdtime/Symbol.map
+
+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+=time2posix.3 posix2time.3
diff --git a/lib/libc/stdtime/Symbol.map b/lib/libc/stdtime/Symbol.map
new file mode 100644
index 0000000..43b4d8e
--- /dev/null
+++ b/lib/libc/stdtime/Symbol.map
@@ -0,0 +1,34 @@
+# $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;
+ gtime;
+ time2posix;
+ posix2time;
+ difftime;
+ asctime_r;
+ asctime;
+};
diff --git a/lib/libc/stdtime/asctime.c b/lib/libc/stdtime/asctime.c
new file mode 100644
index 0000000..0f4212f
--- /dev/null
+++ b/lib/libc/stdtime/asctime.c
@@ -0,0 +1,78 @@
+/*
+** This file is in the public domain, so clarified as of
+** 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov).
+*/
+
+#include <sys/cdefs.h>
+#ifndef lint
+#ifndef NOID
+static char elsieid[] __unused = "@(#)asctime.c 7.9";
+#endif /* !defined NOID */
+#endif /* !defined lint */
+__FBSDID("$FreeBSD$");
+
+/*LINTLIBRARY*/
+
+#include "namespace.h"
+#include "private.h"
+#include "un-namespace.h"
+#include "tzfile.h"
+
+/*
+** A la ISO/IEC 9945-1, ANSI/IEEE Std 1003.1, Second Edition, 1996-07-12.
+*/
+
+char *
+asctime_r(timeptr, buf)
+const struct tm * timeptr;
+char * buf;
+{
+ static const char wday_name[][3] = {
+ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+ };
+ static const char mon_name[][3] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+ };
+ const char * wn;
+ const char * mn;
+
+ if (timeptr->tm_wday < 0 || timeptr->tm_wday >= DAYSPERWEEK)
+ wn = "???";
+ else wn = wday_name[timeptr->tm_wday];
+ if (timeptr->tm_mon < 0 || timeptr->tm_mon >= MONSPERYEAR)
+ mn = "???";
+ else mn = mon_name[timeptr->tm_mon];
+ /*
+ ** The X3J11-suggested format is
+ ** "%.3s %.3s%3d %02.2d:%02.2d:%02.2d %d\n"
+ ** Since the .2 in 02.2d is ignored, we drop it.
+ */
+ (void) sprintf(buf, "%.3s %.3s%3d %02d:%02d:%02d %d\n",
+ wn, mn,
+ timeptr->tm_mday, timeptr->tm_hour,
+ timeptr->tm_min, timeptr->tm_sec,
+ TM_YEAR_BASE + timeptr->tm_year);
+ return buf;
+}
+
+/*
+** A la X3J11, with core dump avoidance.
+*/
+
+char *
+asctime(timeptr)
+const struct tm * timeptr;
+{
+ /*
+ ** Big enough for something such as
+ ** ??? ???-2147483648 -2147483648:-2147483648:-2147483648 -2147483648\n
+ ** (two three-character abbreviations, five strings denoting integers,
+ ** three explicit spaces, two explicit colons, a newline,
+ ** and a trailing ASCII nul).
+ */
+ static char result[3 * 2 + 5 * INT_STRLEN_MAXIMUM(int) +
+ 3 + 2 + 1 + 1];
+
+ return asctime_r(timeptr, result);
+}
diff --git a/lib/libc/stdtime/ctime.3 b/lib/libc/stdtime/ctime.3
new file mode 100644
index 0000000..ec480ec
--- /dev/null
+++ b/lib/libc/stdtime/ctime.3
@@ -0,0 +1,378 @@
+.\" 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.
+.\" 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.
+.\"
+.\" From: @(#)ctime.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd January 2, 1999
+.Dt CTIME 3
+.Os
+.Sh NAME
+.Nm asctime ,
+.Nm asctime_r ,
+.Nm ctime ,
+.Nm ctime_r ,
+.Nm difftime ,
+.Nm gmtime ,
+.Nm gmtime_r ,
+.Nm localtime ,
+.Nm localtime_r ,
+.Nm mktime ,
+.Nm timegm
+.Nd transform binary date and time values
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In time.h
+.Vt extern char *tzname[2] ;
+.Ft char *
+.Fn ctime "const time_t *clock"
+.Ft double
+.Fn difftime "time_t time1" "time_t time0"
+.Ft char *
+.Fn asctime "const struct tm *tm"
+.Ft struct tm *
+.Fn localtime "const time_t *clock"
+.Ft struct tm *
+.Fn gmtime "const time_t *clock"
+.Ft time_t
+.Fn mktime "struct tm *tm"
+.Ft time_t
+.Fn timegm "struct tm *tm"
+.Ft char *
+.Fn ctime_r "const time_t *clock" "char *buf"
+.Ft struct tm *
+.Fn localtime_r "const time_t *clock" "struct tm *result"
+.Ft struct tm *
+.Fn gmtime_r "const time_t *clock" "struct tm *result"
+.Ft char *
+.Fn asctime_r "const struct tm *tm" "char *buf"
+.Sh DESCRIPTION
+The functions
+.Fn ctime ,
+.Fn gmtime
+and
+.Fn localtime
+all take as an argument a time value representing the time in seconds since
+the Epoch (00:00:00
+.Tn UTC ,
+January 1, 1970; see
+.Xr time 3 ) .
+.Pp
+The function
+.Fn localtime
+converts the time value pointed at by
+.Fa clock ,
+and returns a pointer to a
+.Dq Fa struct tm
+(described below) which contains
+the broken-out time information for the value after adjusting for the current
+time zone (and any other factors such as Daylight Saving Time).
+Time zone adjustments are performed as specified by the
+.Ev TZ
+environment variable (see
+.Xr tzset 3 ) .
+The function
+.Fn localtime
+uses
+.Xr tzset 3
+to initialize time conversion information if
+.Xr tzset 3
+has not already been called by the process.
+.Pp
+After filling in the tm structure,
+.Fn localtime
+sets the
+.Fa tm_isdst Ns 'th
+element of
+.Fa tzname
+to a pointer to an
+.Tn ASCII
+string that is the time zone abbreviation to be
+used with
+.Fn localtime Ns 's
+return value.
+.Pp
+The function
+.Fn gmtime
+similarly converts the time value, but without any time zone adjustment,
+and returns a pointer to a tm structure (described below).
+.Pp
+The
+.Fn ctime
+function
+adjusts the time value for the current time zone in the same manner as
+.Fn localtime ,
+and returns a pointer to a 26-character string of the form:
+.Bd -literal -offset indent
+Thu Nov 24 18:22:48 1986\en\e0
+.Ed
+.Pp
+All the fields have constant width.
+.Pp
+The
+.Fn ctime_r
+function
+provides the same functionality as
+.Fn ctime
+except the caller must provide the output buffer
+.Fa buf
+to store the result, which must be at least 26 characters long.
+The
+.Fn localtime_r
+and
+.Fn gmtime_r
+functions
+provide the same functionality as
+.Fn localtime
+and
+.Fn gmtime
+respectively, except the caller must provide the output buffer
+.Fa result .
+.Pp
+The
+.Fn asctime
+function
+converts the broken down time in the structure
+.Fa tm
+pointed at by
+.Fa *tm
+to the form
+shown in the example above.
+.Pp
+The
+.Fn asctime_r
+function
+provides the same functionality as
+.Fn asctime
+except the caller provide the output buffer
+.Fa buf
+to store the result, which must be at least 26 characters long.
+.Pp
+The functions
+.Fn mktime
+and
+.Fn timegm
+convert the broken-down time in the structure
+pointed to by tm into a time value with the same encoding as that of the
+values returned by the
+.Xr time 3
+function (that is, seconds from the Epoch,
+.Tn UTC ) .
+The
+.Fn mktime
+function
+interprets the input structure according to the current timezone setting
+(see
+.Xr tzset 3 ) .
+The
+.Fn timegm
+function
+interprets the input structure as representing Universal Coordinated Time
+.Pq Tn UTC .
+.Pp
+The original values of the
+.Fa tm_wday
+and
+.Fa tm_yday
+components of the structure are ignored, and the original values of the
+other components are not restricted to their normal ranges, and will be
+normalized if needed.
+For example,
+October 40 is changed into November 9,
+a
+.Fa tm_hour
+of \-1 means 1 hour before midnight,
+.Fa tm_mday
+of 0 means the day preceding the current month, and
+.Fa tm_mon
+of \-2 means 2 months before January of
+.Fa tm_year .
+(A positive or zero value for
+.Fa tm_isdst
+causes
+.Fn mktime
+to presume initially that summer time (for example, Daylight Saving Time)
+is or is not in effect for the specified time, respectively.
+A negative value for
+.Fa tm_isdst
+causes the
+.Fn mktime
+function to attempt to divine whether summer time is in effect for the
+specified time.
+The
+.Fa tm_isdst
+and
+.Fa tm_gmtoff
+members are forced to zero by
+.Fn timegm . )
+.Pp
+On successful completion, the values of the
+.Fa tm_wday
+and
+.Fa tm_yday
+components of the structure are set appropriately, and the other components
+are set to represent the specified calendar time, but with their values
+forced to their normal ranges; the final value of
+.Fa tm_mday
+is not set until
+.Fa tm_mon
+and
+.Fa tm_year
+are determined.
+The
+.Fn mktime
+function
+returns the specified calendar time; if the calendar time cannot be
+represented, it returns \-1;
+.Pp
+The
+.Fn difftime
+function
+returns the difference between two calendar times,
+.Pf ( Fa time1
+-
+.Fa time0 ) ,
+expressed in seconds.
+.Pp
+External declarations as well as the tm structure definition are in the
+.In time.h
+include file.
+The tm structure includes at least the following fields:
+.Bd -literal -offset indent
+int tm_sec; /\(** seconds (0 - 60) \(**/
+int tm_min; /\(** minutes (0 - 59) \(**/
+int tm_hour; /\(** hours (0 - 23) \(**/
+int tm_mday; /\(** day of month (1 - 31) \(**/
+int tm_mon; /\(** month of year (0 - 11) \(**/
+int tm_year; /\(** year \- 1900 \(**/
+int tm_wday; /\(** day of week (Sunday = 0) \(**/
+int tm_yday; /\(** day of year (0 - 365) \(**/
+int tm_isdst; /\(** is summer time in effect? \(**/
+char \(**tm_zone; /\(** abbreviation of timezone name \(**/
+long tm_gmtoff; /\(** offset from UTC in seconds \(**/
+.Ed
+.Pp
+The
+field
+.Fa tm_isdst
+is non-zero if summer time is in effect.
+.Pp
+The field
+.Fa tm_gmtoff
+is the offset (in seconds) of the time represented from
+.Tn UTC ,
+with positive
+values indicating east of the Prime Meridian.
+.Sh SEE ALSO
+.Xr date 1 ,
+.Xr gettimeofday 2 ,
+.Xr getenv 3 ,
+.Xr time 3 ,
+.Xr tzset 3 ,
+.Xr tzfile 5
+.Sh STANDARDS
+The
+.Fn asctime ,
+.Fn ctime ,
+.Fn difftime ,
+.Fn gmtime ,
+.Fn localtime ,
+and
+.Fn mktime
+functions conform to
+.St -isoC ,
+and conform to
+.St -p1003.1-96
+provided the selected local timezone does not contain a leap-second table
+(see
+.Xr zic 8 ) .
+.Pp
+The
+.Fn asctime_r ,
+.Fn ctime_r ,
+.Fn gmtime_r ,
+and
+.Fn localtime_r
+functions are expected to conform to
+.St -p1003.1-96
+(again provided the selected local timezone does not contain a leap-second
+table).
+.Pp
+The
+.Fn timegm
+function is not specified by any standard; its function cannot be
+completely emulated using the standard functions described above.
+.Sh HISTORY
+This manual page is derived from
+the time package contributed to Berkeley by
+.An Arthur Olson
+and which appeared in
+.Bx 4.3 .
+.Sh BUGS
+Except for
+.Fn difftime ,
+.Fn mktime ,
+and the
+.Fn \&_r
+variants of the other functions,
+these functions leaves their result in an internal static object and return
+a pointer to that object.
+Subsequent calls to these
+function will modify the same object.
+.Pp
+The C Standard provides no mechanism for a program to modify its current
+local timezone setting, and the
+.Tn POSIX Ns No \&-standard
+method is not reentrant.
+(However, thread-safe implementations are provided
+in the
+.Tn POSIX
+threaded environment.)
+.Pp
+The
+.Va tm_zone
+field of a returned
+.Vt tm
+structure points to a static array of characters,
+which will also be overwritten by any subsequent calls (as well as by
+subsequent calls to
+.Xr tzset 3
+and
+.Xr tzsetwall 3 ) .
+.Pp
+Use of the external variable
+.Fa tzname
+is discouraged; the
+.Fa tm_zone
+entry in the tm structure is preferred.
diff --git a/lib/libc/stdtime/difftime.c b/lib/libc/stdtime/difftime.c
new file mode 100644
index 0000000..596ea82
--- /dev/null
+++ b/lib/libc/stdtime/difftime.c
@@ -0,0 +1,87 @@
+/*
+** This file is in the public domain, so clarified as of
+** June 5, 1996 by Arthur David Olson (arthur_david_olson@nih.gov).
+*/
+
+#include <sys/cdefs.h>
+#ifndef lint
+#ifndef NOID
+static char elsieid[] __unused = "@(#)difftime.c 7.9";
+#endif /* !defined NOID */
+#endif /* !defined lint */
+__FBSDID("$FreeBSD$");
+
+/*LINTLIBRARY*/
+
+#include "namespace.h"
+#include "private.h"
+#include "un-namespace.h"
+
+/*
+** Algorithm courtesy Paul Eggert (eggert@twinsun.com).
+*/
+
+#ifdef HAVE_LONG_DOUBLE
+#define long_double long double
+#endif /* defined HAVE_LONG_DOUBLE */
+#ifndef HAVE_LONG_DOUBLE
+#define long_double double
+#endif /* !defined HAVE_LONG_DOUBLE */
+
+double
+difftime(time1, time0)
+const time_t time1;
+const time_t time0;
+{
+ time_t delta;
+ time_t hibit;
+
+ {
+ time_t tt;
+ double d;
+ long_double ld;
+
+ if (sizeof tt < sizeof d)
+ return (double) time1 - (double) time0;
+ if (sizeof tt < sizeof ld)
+ return (long_double) time1 - (long_double) time0;
+ }
+ if (time1 < time0)
+ return -difftime(time0, time1);
+ /*
+ ** As much as possible, avoid loss of precision
+ ** by computing the difference before converting to double.
+ */
+ delta = time1 - time0;
+ if (delta >= 0)
+ return delta;
+ /*
+ ** Repair delta overflow.
+ */
+ hibit = (~ (time_t) 0) << (TYPE_BIT(time_t) - 1);
+ /*
+ ** The following expression rounds twice, which means
+ ** the result may not be the closest to the true answer.
+ ** For example, suppose time_t is 64-bit signed int,
+ ** long_double is IEEE 754 double with default rounding,
+ ** time1 = 9223372036854775807 and time0 = -1536.
+ ** Then the true difference is 9223372036854777343,
+ ** which rounds to 9223372036854777856
+ ** with a total error of 513.
+ ** But delta overflows to -9223372036854774273,
+ ** which rounds to -9223372036854774784, and correcting
+ ** this by subtracting 2 * (long_double) hibit
+ ** (i.e. by adding 2**64 = 18446744073709551616)
+ ** yields 9223372036854776832, which
+ ** rounds to 9223372036854775808
+ ** with a total error of 1535 instead.
+ ** This problem occurs only with very large differences.
+ ** It's too painful to fix this portably.
+ ** We are not alone in this problem;
+ ** some C compilers round twice when converting
+ ** large unsigned types to small floating types,
+ ** so if time_t is unsigned the "return delta" above
+ ** has the same double-rounding problem with those compilers.
+ */
+ return delta - 2 * (long_double) hibit;
+}
diff --git a/lib/libc/stdtime/localtime.c b/lib/libc/stdtime/localtime.c
new file mode 100644
index 0000000..d7b5a36
--- /dev/null
+++ b/lib/libc/stdtime/localtime.c
@@ -0,0 +1,1813 @@
+/*
+** This file is in the public domain, so clarified as of
+** 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov).
+*/
+
+#include <sys/cdefs.h>
+#ifndef lint
+#ifndef NOID
+static char elsieid[] __unused = "@(#)localtime.c 7.78";
+#endif /* !defined NOID */
+#endif /* !defined lint */
+__FBSDID("$FreeBSD$");
+
+/*
+** Leap second handling from Bradley White (bww@k.gp.cs.cmu.edu).
+** POSIX-style TZ environment variable handling from Guy Harris
+** (guy@auspex.com).
+*/
+
+/*LINTLIBRARY*/
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include "private.h"
+#include "un-namespace.h"
+
+#include "tzfile.h"
+
+#include "libc_private.h"
+
+#define _MUTEX_LOCK(x) if (__isthreaded) _pthread_mutex_lock(x)
+#define _MUTEX_UNLOCK(x) if (__isthreaded) _pthread_mutex_unlock(x)
+
+/*
+** SunOS 4.1.1 headers lack O_BINARY.
+*/
+
+#ifdef O_BINARY
+#define OPEN_MODE (O_RDONLY | O_BINARY)
+#endif /* defined O_BINARY */
+#ifndef O_BINARY
+#define OPEN_MODE O_RDONLY
+#endif /* !defined O_BINARY */
+
+#ifndef WILDABBR
+/*
+** Someone might make incorrect use of a time zone abbreviation:
+** 1. They might reference tzname[0] before calling tzset (explicitly
+** or implicitly).
+** 2. They might reference tzname[1] before calling tzset (explicitly
+** or implicitly).
+** 3. They might reference tzname[1] after setting to a time zone
+** in which Daylight Saving Time is never observed.
+** 4. They might reference tzname[0] after setting to a time zone
+** in which Standard Time is never observed.
+** 5. They might reference tm.TM_ZONE after calling offtime.
+** What's best to do in the above cases is open to debate;
+** for now, we just set things up so that in any of the five cases
+** WILDABBR is used. Another possibility: initialize tzname[0] to the
+** string "tzname[0] used before set", and similarly for the other cases.
+** And another: initialize tzname[0] to "ERA", with an explanation in the
+** manual page of what this "time zone abbreviation" means (doing this so
+** that tzname[0] has the "normal" length of three characters).
+*/
+#define WILDABBR " "
+#endif /* !defined WILDABBR */
+
+static char wildabbr[] = "WILDABBR";
+
+/*
+ * In June 2004 it was decided UTC was a more appropriate default time
+ * zone than GMT.
+ */
+
+static const char gmt[] = "UTC";
+
+/*
+** The DST rules to use if TZ has no rules and we can't load TZDEFRULES.
+** We default to US rules as of 1999-08-17.
+** POSIX 1003.1 section 8.1.1 says that the default DST rules are
+** implementation dependent; for historical reasons, US rules are a
+** common default.
+*/
+#ifndef TZDEFRULESTRING
+#define TZDEFRULESTRING ",M4.1.0,M10.5.0"
+#endif /* !defined TZDEFDST */
+
+struct ttinfo { /* time type information */
+ long tt_gmtoff; /* UTC offset in seconds */
+ int tt_isdst; /* used to set tm_isdst */
+ int tt_abbrind; /* abbreviation list index */
+ int tt_ttisstd; /* TRUE if transition is std time */
+ int tt_ttisgmt; /* TRUE if transition is UTC */
+};
+
+struct lsinfo { /* leap second information */
+ time_t ls_trans; /* transition time */
+ long ls_corr; /* correction to apply */
+};
+
+#define BIGGEST(a, b) (((a) > (b)) ? (a) : (b))
+
+#ifdef TZNAME_MAX
+#define MY_TZNAME_MAX TZNAME_MAX
+#endif /* defined TZNAME_MAX */
+#ifndef TZNAME_MAX
+#define MY_TZNAME_MAX 255
+#endif /* !defined TZNAME_MAX */
+
+struct state {
+ int leapcnt;
+ int timecnt;
+ int typecnt;
+ int charcnt;
+ time_t ats[TZ_MAX_TIMES];
+ unsigned char types[TZ_MAX_TIMES];
+ struct ttinfo ttis[TZ_MAX_TYPES];
+ char chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt),
+ (2 * (MY_TZNAME_MAX + 1)))];
+ struct lsinfo lsis[TZ_MAX_LEAPS];
+};
+
+struct rule {
+ int r_type; /* type of rule--see below */
+ int r_day; /* day number of rule */
+ int r_week; /* week number of rule */
+ int r_mon; /* month number of rule */
+ long r_time; /* transition time of rule */
+};
+
+#define JULIAN_DAY 0 /* Jn - Julian day */
+#define DAY_OF_YEAR 1 /* n - day of year */
+#define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */
+
+/*
+** Prototypes for static functions.
+*/
+
+static long detzcode(const char * codep);
+static const char * getzname(const char * strp);
+static const char * getnum(const char * strp, int * nump, int min,
+ int max);
+static const char * getsecs(const char * strp, long * secsp);
+static const char * getoffset(const char * strp, long * offsetp);
+static const char * getrule(const char * strp, struct rule * rulep);
+static void gmtload(struct state * sp);
+static void gmtsub(const time_t * timep, long offset,
+ struct tm * tmp);
+static void localsub(const time_t * timep, long offset,
+ struct tm * tmp);
+static int increment_overflow(int * number, int delta);
+static int normalize_overflow(int * tensptr, int * unitsptr,
+ int base);
+static void settzname(void);
+static time_t time1(struct tm * tmp,
+ void(*funcp) (const time_t *,
+ long, struct tm *),
+ long offset);
+static time_t time2(struct tm *tmp,
+ void(*funcp) (const time_t *,
+ long, struct tm*),
+ long offset, int * okayp);
+static time_t time2sub(struct tm *tmp,
+ void(*funcp) (const time_t *,
+ long, struct tm*),
+ long offset, int * okayp, int do_norm_secs);
+static void timesub(const time_t * timep, long offset,
+ const struct state * sp, struct tm * tmp);
+static int tmcomp(const struct tm * atmp,
+ const struct tm * btmp);
+static time_t transtime(time_t janfirst, int year,
+ const struct rule * rulep, long offset);
+static int tzload(const char * name, struct state * sp);
+static int tzparse(const char * name, struct state * sp,
+ int lastditch);
+
+#ifdef ALL_STATE
+static struct state * lclptr;
+static struct state * gmtptr;
+#endif /* defined ALL_STATE */
+
+#ifndef ALL_STATE
+static struct state lclmem;
+static struct state gmtmem;
+#define lclptr (&lclmem)
+#define gmtptr (&gmtmem)
+#endif /* State Farm */
+
+#ifndef TZ_STRLEN_MAX
+#define TZ_STRLEN_MAX 255
+#endif /* !defined TZ_STRLEN_MAX */
+
+static char lcl_TZname[TZ_STRLEN_MAX + 1];
+static int lcl_is_set;
+static int gmt_is_set;
+static pthread_mutex_t lcl_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t gmt_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+char * tzname[2] = {
+ wildabbr,
+ wildabbr
+};
+
+/*
+** Section 4.12.3 of X3.159-1989 requires that
+** Except for the strftime function, these functions [asctime,
+** ctime, gmtime, localtime] return values in one of two static
+** objects: a broken-down time structure and an array of char.
+** Thanks to Paul Eggert (eggert@twinsun.com) for noting this.
+*/
+
+static struct tm tm;
+
+#ifdef USG_COMPAT
+time_t timezone = 0;
+int daylight = 0;
+#endif /* defined USG_COMPAT */
+
+#ifdef ALTZONE
+time_t altzone = 0;
+#endif /* defined ALTZONE */
+
+static long
+detzcode(codep)
+const char * const codep;
+{
+ long result;
+ int i;
+
+ result = (codep[0] & 0x80) ? ~0L : 0L;
+ for (i = 0; i < 4; ++i)
+ result = (result << 8) | (codep[i] & 0xff);
+ return result;
+}
+
+static void
+settzname(void)
+{
+ struct state * sp = lclptr;
+ int i;
+
+ tzname[0] = wildabbr;
+ tzname[1] = wildabbr;
+#ifdef USG_COMPAT
+ daylight = 0;
+ timezone = 0;
+#endif /* defined USG_COMPAT */
+#ifdef ALTZONE
+ altzone = 0;
+#endif /* defined ALTZONE */
+#ifdef ALL_STATE
+ if (sp == NULL) {
+ tzname[0] = tzname[1] = gmt;
+ return;
+ }
+#endif /* defined ALL_STATE */
+ for (i = 0; i < sp->typecnt; ++i) {
+ const struct ttinfo * const ttisp = &sp->ttis[i];
+
+ tzname[ttisp->tt_isdst] =
+ &sp->chars[ttisp->tt_abbrind];
+#ifdef USG_COMPAT
+ if (ttisp->tt_isdst)
+ daylight = 1;
+ if (i == 0 || !ttisp->tt_isdst)
+ timezone = -(ttisp->tt_gmtoff);
+#endif /* defined USG_COMPAT */
+#ifdef ALTZONE
+ if (i == 0 || ttisp->tt_isdst)
+ altzone = -(ttisp->tt_gmtoff);
+#endif /* defined ALTZONE */
+ }
+ /*
+ ** And to get the latest zone names into tzname. . .
+ */
+ for (i = 0; i < sp->timecnt; ++i) {
+ const struct ttinfo * const ttisp =
+ &sp->ttis[
+ sp->types[i]];
+
+ tzname[ttisp->tt_isdst] =
+ &sp->chars[ttisp->tt_abbrind];
+ }
+}
+
+static int
+tzload(name, sp)
+const char * name;
+struct state * const sp;
+{
+ const char * p;
+ int i;
+ int fid;
+
+ /* XXX The following is from OpenBSD, and I'm not sure it is correct */
+ if (name != NULL && issetugid() != 0)
+ if ((name[0] == ':' && name[1] == '/') ||
+ name[0] == '/' || strchr(name, '.'))
+ name = NULL;
+ if (name == NULL && (name = TZDEFAULT) == NULL)
+ return -1;
+ {
+ int doaccess;
+ struct stat stab;
+ /*
+ ** Section 4.9.1 of the C standard says that
+ ** "FILENAME_MAX expands to an integral constant expression
+ ** that is the size needed for an array of char large enough
+ ** to hold the longest file name string that the implementation
+ ** guarantees can be opened."
+ */
+ char fullname[FILENAME_MAX + 1];
+
+ if (name[0] == ':')
+ ++name;
+ doaccess = name[0] == '/';
+ if (!doaccess) {
+ if ((p = TZDIR) == NULL)
+ return -1;
+ if ((strlen(p) + 1 + strlen(name) + 1) >= sizeof fullname)
+ return -1;
+ (void) strcpy(fullname, p);
+ (void) strcat(fullname, "/");
+ (void) strcat(fullname, name);
+ /*
+ ** Set doaccess if '.' (as in "../") shows up in name.
+ */
+ if (strchr(name, '.') != NULL)
+ doaccess = TRUE;
+ name = fullname;
+ }
+ if (doaccess && access(name, R_OK) != 0)
+ return -1;
+ if ((fid = _open(name, OPEN_MODE)) == -1)
+ return -1;
+ if ((_fstat(fid, &stab) < 0) || !S_ISREG(stab.st_mode)) {
+ _close(fid);
+ return -1;
+ }
+ }
+ {
+ struct tzhead * tzhp;
+ union {
+ struct tzhead tzhead;
+ char buf[sizeof *sp + sizeof *tzhp];
+ } u;
+ int ttisstdcnt;
+ int ttisgmtcnt;
+
+ i = _read(fid, u.buf, sizeof u.buf);
+ if (_close(fid) != 0)
+ return -1;
+ ttisstdcnt = (int) detzcode(u.tzhead.tzh_ttisstdcnt);
+ ttisgmtcnt = (int) detzcode(u.tzhead.tzh_ttisgmtcnt);
+ sp->leapcnt = (int) detzcode(u.tzhead.tzh_leapcnt);
+ sp->timecnt = (int) detzcode(u.tzhead.tzh_timecnt);
+ sp->typecnt = (int) detzcode(u.tzhead.tzh_typecnt);
+ sp->charcnt = (int) detzcode(u.tzhead.tzh_charcnt);
+ p = u.tzhead.tzh_charcnt + sizeof u.tzhead.tzh_charcnt;
+ if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
+ sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
+ sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
+ sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
+ (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
+ (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
+ return -1;
+ if (i - (p - u.buf) < sp->timecnt * 4 + /* ats */
+ sp->timecnt + /* types */
+ sp->typecnt * (4 + 2) + /* ttinfos */
+ sp->charcnt + /* chars */
+ sp->leapcnt * (4 + 4) + /* lsinfos */
+ ttisstdcnt + /* ttisstds */
+ ttisgmtcnt) /* ttisgmts */
+ return -1;
+ for (i = 0; i < sp->timecnt; ++i) {
+ sp->ats[i] = detzcode(p);
+ p += 4;
+ }
+ for (i = 0; i < sp->timecnt; ++i) {
+ sp->types[i] = (unsigned char) *p++;
+ if (sp->types[i] >= sp->typecnt)
+ return -1;
+ }
+ for (i = 0; i < sp->typecnt; ++i) {
+ struct ttinfo * ttisp;
+
+ ttisp = &sp->ttis[i];
+ ttisp->tt_gmtoff = detzcode(p);
+ p += 4;
+ ttisp->tt_isdst = (unsigned char) *p++;
+ if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
+ return -1;
+ ttisp->tt_abbrind = (unsigned char) *p++;
+ if (ttisp->tt_abbrind < 0 ||
+ ttisp->tt_abbrind > sp->charcnt)
+ return -1;
+ }
+ for (i = 0; i < sp->charcnt; ++i)
+ sp->chars[i] = *p++;
+ sp->chars[i] = '\0'; /* ensure '\0' at end */
+ for (i = 0; i < sp->leapcnt; ++i) {
+ struct lsinfo * lsisp;
+
+ lsisp = &sp->lsis[i];
+ lsisp->ls_trans = detzcode(p);
+ p += 4;
+ lsisp->ls_corr = detzcode(p);
+ p += 4;
+ }
+ for (i = 0; i < sp->typecnt; ++i) {
+ struct ttinfo * ttisp;
+
+ ttisp = &sp->ttis[i];
+ if (ttisstdcnt == 0)
+ ttisp->tt_ttisstd = FALSE;
+ else {
+ ttisp->tt_ttisstd = *p++;
+ if (ttisp->tt_ttisstd != TRUE &&
+ ttisp->tt_ttisstd != FALSE)
+ return -1;
+ }
+ }
+ for (i = 0; i < sp->typecnt; ++i) {
+ struct ttinfo * ttisp;
+
+ ttisp = &sp->ttis[i];
+ if (ttisgmtcnt == 0)
+ ttisp->tt_ttisgmt = FALSE;
+ else {
+ ttisp->tt_ttisgmt = *p++;
+ if (ttisp->tt_ttisgmt != TRUE &&
+ ttisp->tt_ttisgmt != FALSE)
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
+
+static const int mon_lengths[2][MONSPERYEAR] = {
+ { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+ { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
+};
+
+static const int year_lengths[2] = {
+ DAYSPERNYEAR, DAYSPERLYEAR
+};
+
+/*
+** Given a pointer into a time zone string, scan until a character that is not
+** a valid character in a zone name is found. Return a pointer to that
+** character.
+*/
+
+static const char *
+getzname(strp)
+const char * strp;
+{
+ char c;
+
+ while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' &&
+ c != '+')
+ ++strp;
+ return strp;
+}
+
+/*
+** Given a pointer into a time zone string, extract a number from that string.
+** Check that the number is within a specified range; if it is not, return
+** NULL.
+** Otherwise, return a pointer to the first character not part of the number.
+*/
+
+static const char *
+getnum(strp, nump, min, max)
+const char * strp;
+int * const nump;
+const int min;
+const int max;
+{
+ char c;
+ int num;
+
+ if (strp == NULL || !is_digit(c = *strp))
+ return NULL;
+ num = 0;
+ do {
+ num = num * 10 + (c - '0');
+ if (num > max)
+ return NULL; /* illegal value */
+ c = *++strp;
+ } while (is_digit(c));
+ if (num < min)
+ return NULL; /* illegal value */
+ *nump = num;
+ return strp;
+}
+
+/*
+** Given a pointer into a time zone string, extract a number of seconds,
+** in hh[:mm[:ss]] form, from the string.
+** If any error occurs, return NULL.
+** Otherwise, return a pointer to the first character not part of the number
+** of seconds.
+*/
+
+static const char *
+getsecs(strp, secsp)
+const char * strp;
+long * const secsp;
+{
+ int num;
+
+ /*
+ ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
+ ** "M10.4.6/26", which does not conform to Posix,
+ ** but which specifies the equivalent of
+ ** ``02:00 on the first Sunday on or after 23 Oct''.
+ */
+ strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
+ if (strp == NULL)
+ return NULL;
+ *secsp = num * (long) SECSPERHOUR;
+ if (*strp == ':') {
+ ++strp;
+ strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
+ if (strp == NULL)
+ return NULL;
+ *secsp += num * SECSPERMIN;
+ if (*strp == ':') {
+ ++strp;
+ /* `SECSPERMIN' allows for leap seconds. */
+ strp = getnum(strp, &num, 0, SECSPERMIN);
+ if (strp == NULL)
+ return NULL;
+ *secsp += num;
+ }
+ }
+ return strp;
+}
+
+/*
+** Given a pointer into a time zone string, extract an offset, in
+** [+-]hh[:mm[:ss]] form, from the string.
+** If any error occurs, return NULL.
+** Otherwise, return a pointer to the first character not part of the time.
+*/
+
+static const char *
+getoffset(strp, offsetp)
+const char * strp;
+long * const offsetp;
+{
+ int neg = 0;
+
+ if (*strp == '-') {
+ neg = 1;
+ ++strp;
+ } else if (*strp == '+')
+ ++strp;
+ strp = getsecs(strp, offsetp);
+ if (strp == NULL)
+ return NULL; /* illegal time */
+ if (neg)
+ *offsetp = -*offsetp;
+ return strp;
+}
+
+/*
+** Given a pointer into a time zone string, extract a rule in the form
+** date[/time]. See POSIX section 8 for the format of "date" and "time".
+** If a valid rule is not found, return NULL.
+** Otherwise, return a pointer to the first character not part of the rule.
+*/
+
+static const char *
+getrule(strp, rulep)
+const char * strp;
+struct rule * const rulep;
+{
+ if (*strp == 'J') {
+ /*
+ ** Julian day.
+ */
+ rulep->r_type = JULIAN_DAY;
+ ++strp;
+ strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
+ } else if (*strp == 'M') {
+ /*
+ ** Month, week, day.
+ */
+ rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
+ ++strp;
+ strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
+ if (strp == NULL)
+ return NULL;
+ if (*strp++ != '.')
+ return NULL;
+ strp = getnum(strp, &rulep->r_week, 1, 5);
+ if (strp == NULL)
+ return NULL;
+ if (*strp++ != '.')
+ return NULL;
+ strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
+ } else if (is_digit(*strp)) {
+ /*
+ ** Day of year.
+ */
+ rulep->r_type = DAY_OF_YEAR;
+ strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
+ } else return NULL; /* invalid format */
+ if (strp == NULL)
+ return NULL;
+ if (*strp == '/') {
+ /*
+ ** Time specified.
+ */
+ ++strp;
+ strp = getsecs(strp, &rulep->r_time);
+ } else rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */
+ return strp;
+}
+
+/*
+** Given the Epoch-relative time of January 1, 00:00:00 UTC, in a year, the
+** year, a rule, and the offset from UTC at the time that rule takes effect,
+** calculate the Epoch-relative time that rule takes effect.
+*/
+
+static time_t
+transtime(janfirst, year, rulep, offset)
+const time_t janfirst;
+const int year;
+const struct rule * const rulep;
+const long offset;
+{
+ int leapyear;
+ time_t value;
+ int i;
+ int d, m1, yy0, yy1, yy2, dow;
+
+ INITIALIZE(value);
+ leapyear = isleap(year);
+ switch (rulep->r_type) {
+
+ case JULIAN_DAY:
+ /*
+ ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
+ ** years.
+ ** In non-leap years, or if the day number is 59 or less, just
+ ** add SECSPERDAY times the day number-1 to the time of
+ ** January 1, midnight, to get the day.
+ */
+ value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
+ if (leapyear && rulep->r_day >= 60)
+ value += SECSPERDAY;
+ break;
+
+ case DAY_OF_YEAR:
+ /*
+ ** n - day of year.
+ ** Just add SECSPERDAY times the day number to the time of
+ ** January 1, midnight, to get the day.
+ */
+ value = janfirst + rulep->r_day * SECSPERDAY;
+ break;
+
+ case MONTH_NTH_DAY_OF_WEEK:
+ /*
+ ** Mm.n.d - nth "dth day" of month m.
+ */
+ value = janfirst;
+ for (i = 0; i < rulep->r_mon - 1; ++i)
+ value += mon_lengths[leapyear][i] * SECSPERDAY;
+
+ /*
+ ** Use Zeller's Congruence to get day-of-week of first day of
+ ** month.
+ */
+ m1 = (rulep->r_mon + 9) % 12 + 1;
+ yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
+ yy1 = yy0 / 100;
+ yy2 = yy0 % 100;
+ dow = ((26 * m1 - 2) / 10 +
+ 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
+ if (dow < 0)
+ dow += DAYSPERWEEK;
+
+ /*
+ ** "dow" is the day-of-week of the first day of the month. Get
+ ** the day-of-month (zero-origin) of the first "dow" day of the
+ ** month.
+ */
+ d = rulep->r_day - dow;
+ if (d < 0)
+ d += DAYSPERWEEK;
+ for (i = 1; i < rulep->r_week; ++i) {
+ if (d + DAYSPERWEEK >=
+ mon_lengths[leapyear][rulep->r_mon - 1])
+ break;
+ d += DAYSPERWEEK;
+ }
+
+ /*
+ ** "d" is the day-of-month (zero-origin) of the day we want.
+ */
+ value += d * SECSPERDAY;
+ break;
+ }
+
+ /*
+ ** "value" is the Epoch-relative time of 00:00:00 UTC on the day in
+ ** question. To get the Epoch-relative time of the specified local
+ ** time on that day, add the transition time and the current offset
+ ** from UTC.
+ */
+ return value + rulep->r_time + offset;
+}
+
+/*
+** Given a POSIX section 8-style TZ string, fill in the rule tables as
+** appropriate.
+*/
+
+static int
+tzparse(name, sp, lastditch)
+const char * name;
+struct state * const sp;
+const int lastditch;
+{
+ const char * stdname;
+ const char * dstname;
+ size_t stdlen;
+ size_t dstlen;
+ long stdoffset;
+ long dstoffset;
+ time_t * atp;
+ unsigned char * typep;
+ char * cp;
+ int load_result;
+
+ INITIALIZE(dstname);
+ stdname = name;
+ if (lastditch) {
+ stdlen = strlen(name); /* length of standard zone name */
+ name += stdlen;
+ if (stdlen >= sizeof sp->chars)
+ stdlen = (sizeof sp->chars) - 1;
+ stdoffset = 0;
+ } else {
+ name = getzname(name);
+ stdlen = name - stdname;
+ if (stdlen < 3)
+ return -1;
+ if (*name == '\0')
+ return -1; /* was "stdoffset = 0;" */
+ else {
+ name = getoffset(name, &stdoffset);
+ if (name == NULL)
+ return -1;
+ }
+ }
+ load_result = tzload(TZDEFRULES, sp);
+ if (load_result != 0)
+ sp->leapcnt = 0; /* so, we're off a little */
+ if (*name != '\0') {
+ dstname = name;
+ name = getzname(name);
+ dstlen = name - dstname; /* length of DST zone name */
+ if (dstlen < 3)
+ return -1;
+ if (*name != '\0' && *name != ',' && *name != ';') {
+ name = getoffset(name, &dstoffset);
+ if (name == NULL)
+ return -1;
+ } else dstoffset = stdoffset - SECSPERHOUR;
+ if (*name == '\0' && load_result != 0)
+ name = TZDEFRULESTRING;
+ if (*name == ',' || *name == ';') {
+ struct rule start;
+ struct rule end;
+ int year;
+ time_t janfirst;
+ time_t starttime;
+ time_t endtime;
+
+ ++name;
+ if ((name = getrule(name, &start)) == NULL)
+ return -1;
+ if (*name++ != ',')
+ return -1;
+ if ((name = getrule(name, &end)) == NULL)
+ return -1;
+ if (*name != '\0')
+ return -1;
+ sp->typecnt = 2; /* standard time and DST */
+ /*
+ ** Two transitions per year, from EPOCH_YEAR to 2037.
+ */
+ sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1);
+ if (sp->timecnt > TZ_MAX_TIMES)
+ return -1;
+ sp->ttis[0].tt_gmtoff = -dstoffset;
+ sp->ttis[0].tt_isdst = 1;
+ sp->ttis[0].tt_abbrind = stdlen + 1;
+ sp->ttis[1].tt_gmtoff = -stdoffset;
+ sp->ttis[1].tt_isdst = 0;
+ sp->ttis[1].tt_abbrind = 0;
+ atp = sp->ats;
+ typep = sp->types;
+ janfirst = 0;
+ for (year = EPOCH_YEAR; year <= 2037; ++year) {
+ starttime = transtime(janfirst, year, &start,
+ stdoffset);
+ endtime = transtime(janfirst, year, &end,
+ dstoffset);
+ if (starttime > endtime) {
+ *atp++ = endtime;
+ *typep++ = 1; /* DST ends */
+ *atp++ = starttime;
+ *typep++ = 0; /* DST begins */
+ } else {
+ *atp++ = starttime;
+ *typep++ = 0; /* DST begins */
+ *atp++ = endtime;
+ *typep++ = 1; /* DST ends */
+ }
+ janfirst += year_lengths[isleap(year)] *
+ SECSPERDAY;
+ }
+ } else {
+ long theirstdoffset;
+ long theirdstoffset;
+ long theiroffset;
+ int isdst;
+ int i;
+ int j;
+
+ if (*name != '\0')
+ return -1;
+ /*
+ ** Initial values of theirstdoffset and theirdstoffset.
+ */
+ theirstdoffset = 0;
+ for (i = 0; i < sp->timecnt; ++i) {
+ j = sp->types[i];
+ if (!sp->ttis[j].tt_isdst) {
+ theirstdoffset =
+ -sp->ttis[j].tt_gmtoff;
+ break;
+ }
+ }
+ theirdstoffset = 0;
+ for (i = 0; i < sp->timecnt; ++i) {
+ j = sp->types[i];
+ if (sp->ttis[j].tt_isdst) {
+ theirdstoffset =
+ -sp->ttis[j].tt_gmtoff;
+ break;
+ }
+ }
+ /*
+ ** Initially we're assumed to be in standard time.
+ */
+ isdst = FALSE;
+ theiroffset = theirstdoffset;
+ /*
+ ** Now juggle transition times and types
+ ** tracking offsets as you do.
+ */
+ for (i = 0; i < sp->timecnt; ++i) {
+ j = sp->types[i];
+ sp->types[i] = sp->ttis[j].tt_isdst;
+ if (sp->ttis[j].tt_ttisgmt) {
+ /* No adjustment to transition time */
+ } else {
+ /*
+ ** If summer time is in effect, and the
+ ** transition time was not specified as
+ ** standard time, add the summer time
+ ** offset to the transition time;
+ ** otherwise, add the standard time
+ ** offset to the transition time.
+ */
+ /*
+ ** Transitions from DST to DDST
+ ** will effectively disappear since
+ ** POSIX provides for only one DST
+ ** offset.
+ */
+ if (isdst && !sp->ttis[j].tt_ttisstd) {
+ sp->ats[i] += dstoffset -
+ theirdstoffset;
+ } else {
+ sp->ats[i] += stdoffset -
+ theirstdoffset;
+ }
+ }
+ theiroffset = -sp->ttis[j].tt_gmtoff;
+ if (sp->ttis[j].tt_isdst)
+ theirdstoffset = theiroffset;
+ else theirstdoffset = theiroffset;
+ }
+ /*
+ ** Finally, fill in ttis.
+ ** ttisstd and ttisgmt need not be handled.
+ */
+ sp->ttis[0].tt_gmtoff = -stdoffset;
+ sp->ttis[0].tt_isdst = FALSE;
+ sp->ttis[0].tt_abbrind = 0;
+ sp->ttis[1].tt_gmtoff = -dstoffset;
+ sp->ttis[1].tt_isdst = TRUE;
+ sp->ttis[1].tt_abbrind = stdlen + 1;
+ sp->typecnt = 2;
+ }
+ } else {
+ dstlen = 0;
+ sp->typecnt = 1; /* only standard time */
+ sp->timecnt = 0;
+ sp->ttis[0].tt_gmtoff = -stdoffset;
+ sp->ttis[0].tt_isdst = 0;
+ sp->ttis[0].tt_abbrind = 0;
+ }
+ sp->charcnt = stdlen + 1;
+ if (dstlen != 0)
+ sp->charcnt += dstlen + 1;
+ if ((size_t) sp->charcnt > sizeof sp->chars)
+ return -1;
+ cp = sp->chars;
+ (void) strncpy(cp, stdname, stdlen);
+ cp += stdlen;
+ *cp++ = '\0';
+ if (dstlen != 0) {
+ (void) strncpy(cp, dstname, dstlen);
+ *(cp + dstlen) = '\0';
+ }
+ return 0;
+}
+
+static void
+gmtload(sp)
+struct state * const sp;
+{
+ if (tzload(gmt, sp) != 0)
+ (void) tzparse(gmt, sp, TRUE);
+}
+
+static void
+tzsetwall_basic(void)
+{
+ if (lcl_is_set < 0)
+ return;
+ lcl_is_set = -1;
+
+#ifdef ALL_STATE
+ if (lclptr == NULL) {
+ lclptr = (struct state *) malloc(sizeof *lclptr);
+ if (lclptr == NULL) {
+ settzname(); /* all we can do */
+ return;
+ }
+ }
+#endif /* defined ALL_STATE */
+ if (tzload((char *) NULL, lclptr) != 0)
+ gmtload(lclptr);
+ settzname();
+}
+
+void
+tzsetwall(void)
+{
+ _MUTEX_LOCK(&lcl_mutex);
+ tzsetwall_basic();
+ _MUTEX_UNLOCK(&lcl_mutex);
+}
+
+static void
+tzset_basic(void)
+{
+ const char * name;
+
+ name = getenv("TZ");
+ if (name == NULL) {
+ tzsetwall_basic();
+ return;
+ }
+
+ if (lcl_is_set > 0 && strcmp(lcl_TZname, name) == 0)
+ return;
+ lcl_is_set = strlen(name) < sizeof lcl_TZname;
+ if (lcl_is_set)
+ (void) strcpy(lcl_TZname, name);
+
+#ifdef ALL_STATE
+ if (lclptr == NULL) {
+ lclptr = (struct state *) malloc(sizeof *lclptr);
+ if (lclptr == NULL) {
+ settzname(); /* all we can do */
+ return;
+ }
+ }
+#endif /* defined ALL_STATE */
+ if (*name == '\0') {
+ /*
+ ** User wants it fast rather than right.
+ */
+ lclptr->leapcnt = 0; /* so, we're off a little */
+ lclptr->timecnt = 0;
+ lclptr->typecnt = 0;
+ lclptr->ttis[0].tt_isdst = 0;
+ lclptr->ttis[0].tt_gmtoff = 0;
+ lclptr->ttis[0].tt_abbrind = 0;
+ (void) strcpy(lclptr->chars, gmt);
+ } else if (tzload(name, lclptr) != 0)
+ if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0)
+ (void) gmtload(lclptr);
+ settzname();
+}
+
+void
+tzset(void)
+{
+ _MUTEX_LOCK(&lcl_mutex);
+ tzset_basic();
+ _MUTEX_UNLOCK(&lcl_mutex);
+}
+
+/*
+** The easy way to behave "as if no library function calls" localtime
+** is to not call it--so we drop its guts into "localsub", which can be
+** freely called. (And no, the PANS doesn't require the above behavior--
+** but it *is* desirable.)
+**
+** The unused offset argument is for the benefit of mktime variants.
+*/
+
+/*ARGSUSED*/
+static void
+localsub(timep, offset, tmp)
+const time_t * const timep;
+const long offset;
+struct tm * const tmp;
+{
+ struct state * sp;
+ const struct ttinfo * ttisp;
+ int i;
+ const time_t t = *timep;
+
+ sp = lclptr;
+#ifdef ALL_STATE
+ if (sp == NULL) {
+ gmtsub(timep, offset, tmp);
+ return;
+ }
+#endif /* defined ALL_STATE */
+ if (sp->timecnt == 0 || t < sp->ats[0]) {
+ i = 0;
+ while (sp->ttis[i].tt_isdst)
+ if (++i >= sp->typecnt) {
+ i = 0;
+ break;
+ }
+ } else {
+ for (i = 1; i < sp->timecnt; ++i)
+ if (t < sp->ats[i])
+ break;
+ i = sp->types[i - 1];
+ }
+ ttisp = &sp->ttis[i];
+ /*
+ ** To get (wrong) behavior that's compatible with System V Release 2.0
+ ** you'd replace the statement below with
+ ** t += ttisp->tt_gmtoff;
+ ** timesub(&t, 0L, sp, tmp);
+ */
+ timesub(&t, ttisp->tt_gmtoff, sp, tmp);
+ tmp->tm_isdst = ttisp->tt_isdst;
+ tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind];
+#ifdef TM_ZONE
+ tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];
+#endif /* defined TM_ZONE */
+}
+
+struct tm *
+localtime(timep)
+const time_t * const timep;
+{
+ static pthread_mutex_t localtime_mutex = PTHREAD_MUTEX_INITIALIZER;
+ static pthread_key_t localtime_key = -1;
+ struct tm *p_tm;
+
+ if (__isthreaded != 0) {
+ _pthread_mutex_lock(&localtime_mutex);
+ if (localtime_key < 0) {
+ if (_pthread_key_create(&localtime_key, free) < 0) {
+ _pthread_mutex_unlock(&localtime_mutex);
+ return(NULL);
+ }
+ }
+ _pthread_mutex_unlock(&localtime_mutex);
+ p_tm = _pthread_getspecific(localtime_key);
+ if (p_tm == NULL) {
+ if ((p_tm = (struct tm *)malloc(sizeof(struct tm)))
+ == NULL)
+ return(NULL);
+ _pthread_setspecific(localtime_key, p_tm);
+ }
+ _pthread_mutex_lock(&lcl_mutex);
+ tzset_basic();
+ localsub(timep, 0L, p_tm);
+ _pthread_mutex_unlock(&lcl_mutex);
+ return(p_tm);
+ } else {
+ tzset_basic();
+ localsub(timep, 0L, &tm);
+ return(&tm);
+ }
+}
+
+/*
+** Re-entrant version of localtime.
+*/
+
+struct tm *
+localtime_r(timep, tm)
+const time_t * const timep;
+struct tm * tm;
+{
+ _MUTEX_LOCK(&lcl_mutex);
+ tzset_basic();
+ localsub(timep, 0L, tm);
+ _MUTEX_UNLOCK(&lcl_mutex);
+ return tm;
+}
+
+/*
+** gmtsub is to gmtime as localsub is to localtime.
+*/
+
+static void
+gmtsub(timep, offset, tmp)
+const time_t * const timep;
+const long offset;
+struct tm * const tmp;
+{
+ _MUTEX_LOCK(&gmt_mutex);
+ if (!gmt_is_set) {
+ gmt_is_set = TRUE;
+#ifdef ALL_STATE
+ gmtptr = (struct state *) malloc(sizeof *gmtptr);
+ if (gmtptr != NULL)
+#endif /* defined ALL_STATE */
+ gmtload(gmtptr);
+ }
+ _MUTEX_UNLOCK(&gmt_mutex);
+ timesub(timep, offset, gmtptr, tmp);
+#ifdef TM_ZONE
+ /*
+ ** Could get fancy here and deliver something such as
+ ** "UTC+xxxx" or "UTC-xxxx" if offset is non-zero,
+ ** but this is no time for a treasure hunt.
+ */
+ if (offset != 0)
+ tmp->TM_ZONE = wildabbr;
+ else {
+#ifdef ALL_STATE
+ if (gmtptr == NULL)
+ tmp->TM_ZONE = gmt;
+ else tmp->TM_ZONE = gmtptr->chars;
+#endif /* defined ALL_STATE */
+#ifndef ALL_STATE
+ tmp->TM_ZONE = gmtptr->chars;
+#endif /* State Farm */
+ }
+#endif /* defined TM_ZONE */
+}
+
+struct tm *
+gmtime(timep)
+const time_t * const timep;
+{
+ static pthread_mutex_t gmtime_mutex = PTHREAD_MUTEX_INITIALIZER;
+ static pthread_key_t gmtime_key = -1;
+ struct tm *p_tm;
+
+ if (__isthreaded != 0) {
+ _pthread_mutex_lock(&gmtime_mutex);
+ if (gmtime_key < 0) {
+ if (_pthread_key_create(&gmtime_key, free) < 0) {
+ _pthread_mutex_unlock(&gmtime_mutex);
+ return(NULL);
+ }
+ }
+ _pthread_mutex_unlock(&gmtime_mutex);
+ /*
+ * Changed to follow POSIX.1 threads standard, which
+ * is what BSD currently has.
+ */
+ if ((p_tm = _pthread_getspecific(gmtime_key)) == NULL) {
+ if ((p_tm = (struct tm *)malloc(sizeof(struct tm)))
+ == NULL) {
+ return(NULL);
+ }
+ _pthread_setspecific(gmtime_key, p_tm);
+ }
+ gmtsub(timep, 0L, p_tm);
+ return(p_tm);
+ }
+ else {
+ gmtsub(timep, 0L, &tm);
+ return(&tm);
+ }
+}
+
+/*
+* Re-entrant version of gmtime.
+*/
+
+struct tm *
+gmtime_r(timep, tm)
+const time_t * const timep;
+struct tm * tm;
+{
+ gmtsub(timep, 0L, tm);
+ return tm;
+}
+
+#ifdef STD_INSPIRED
+
+struct tm *
+offtime(timep, offset)
+const time_t * const timep;
+const long offset;
+{
+ gmtsub(timep, offset, &tm);
+ return &tm;
+}
+
+#endif /* defined STD_INSPIRED */
+
+static void
+timesub(timep, offset, sp, tmp)
+const time_t * const timep;
+const long offset;
+const struct state * const sp;
+struct tm * const tmp;
+{
+ const struct lsinfo * lp;
+ long days;
+ long rem;
+ long y;
+ int yleap;
+ const int * ip;
+ long corr;
+ int hit;
+ int i;
+
+ corr = 0;
+ hit = 0;
+#ifdef ALL_STATE
+ i = (sp == NULL) ? 0 : sp->leapcnt;
+#endif /* defined ALL_STATE */
+#ifndef ALL_STATE
+ i = sp->leapcnt;
+#endif /* State Farm */
+ while (--i >= 0) {
+ lp = &sp->lsis[i];
+ if (*timep >= lp->ls_trans) {
+ if (*timep == lp->ls_trans) {
+ hit = ((i == 0 && lp->ls_corr > 0) ||
+ lp->ls_corr > sp->lsis[i - 1].ls_corr);
+ if (hit)
+ while (i > 0 &&
+ sp->lsis[i].ls_trans ==
+ sp->lsis[i - 1].ls_trans + 1 &&
+ sp->lsis[i].ls_corr ==
+ sp->lsis[i - 1].ls_corr + 1) {
+ ++hit;
+ --i;
+ }
+ }
+ corr = lp->ls_corr;
+ break;
+ }
+ }
+ days = *timep / SECSPERDAY;
+ rem = *timep % SECSPERDAY;
+#ifdef mc68k
+ if (*timep == 0x80000000) {
+ /*
+ ** A 3B1 muffs the division on the most negative number.
+ */
+ days = -24855;
+ rem = -11648;
+ }
+#endif /* defined mc68k */
+ rem += (offset - corr);
+ while (rem < 0) {
+ rem += SECSPERDAY;
+ --days;
+ }
+ while (rem >= SECSPERDAY) {
+ rem -= SECSPERDAY;
+ ++days;
+ }
+ tmp->tm_hour = (int) (rem / SECSPERHOUR);
+ rem = rem % SECSPERHOUR;
+ tmp->tm_min = (int) (rem / SECSPERMIN);
+ /*
+ ** A positive leap second requires a special
+ ** representation. This uses "... ??:59:60" et seq.
+ */
+ tmp->tm_sec = (int) (rem % SECSPERMIN) + hit;
+ tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK);
+ if (tmp->tm_wday < 0)
+ tmp->tm_wday += DAYSPERWEEK;
+ y = EPOCH_YEAR;
+#define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400)
+ while (days < 0 || days >= (long) year_lengths[yleap = isleap(y)]) {
+ long newy;
+
+ newy = y + days / DAYSPERNYEAR;
+ if (days < 0)
+ --newy;
+ days -= (newy - y) * DAYSPERNYEAR +
+ LEAPS_THRU_END_OF(newy - 1) -
+ LEAPS_THRU_END_OF(y - 1);
+ y = newy;
+ }
+ tmp->tm_year = y - TM_YEAR_BASE;
+ tmp->tm_yday = (int) days;
+ ip = mon_lengths[yleap];
+ for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon))
+ days = days - (long) ip[tmp->tm_mon];
+ tmp->tm_mday = (int) (days + 1);
+ tmp->tm_isdst = 0;
+#ifdef TM_GMTOFF
+ tmp->TM_GMTOFF = offset;
+#endif /* defined TM_GMTOFF */
+}
+
+char *
+ctime(timep)
+const time_t * const timep;
+{
+/*
+** Section 4.12.3.2 of X3.159-1989 requires that
+** The ctime function converts the calendar time pointed to by timer
+** to local time in the form of a string. It is equivalent to
+** asctime(localtime(timer))
+*/
+ return asctime(localtime(timep));
+}
+
+char *
+ctime_r(timep, buf)
+const time_t * const timep;
+char * buf;
+{
+ struct tm tm;
+
+ return asctime_r(localtime_r(timep, &tm), buf);
+}
+
+/*
+** Adapted from code provided by Robert Elz, who writes:
+** The "best" way to do mktime I think is based on an idea of Bob
+** Kridle's (so its said...) from a long time ago.
+** [kridle@xinet.com as of 1996-01-16.]
+** It does a binary search of the time_t space. Since time_t's are
+** just 32 bits, its a max of 32 iterations (even at 64 bits it
+** would still be very reasonable).
+*/
+
+#ifndef WRONG
+#define WRONG (-1)
+#endif /* !defined WRONG */
+
+/*
+** Simplified normalize logic courtesy Paul Eggert (eggert@twinsun.com).
+*/
+
+static int
+increment_overflow(number, delta)
+int * number;
+int delta;
+{
+ int number0;
+
+ number0 = *number;
+ *number += delta;
+ return (*number < number0) != (delta < 0);
+}
+
+static int
+normalize_overflow(tensptr, unitsptr, base)
+int * const tensptr;
+int * const unitsptr;
+const int base;
+{
+ int tensdelta;
+
+ tensdelta = (*unitsptr >= 0) ?
+ (*unitsptr / base) :
+ (-1 - (-1 - *unitsptr) / base);
+ *unitsptr -= tensdelta * base;
+ return increment_overflow(tensptr, tensdelta);
+}
+
+static int
+tmcomp(atmp, btmp)
+const struct tm * const atmp;
+const struct tm * const btmp;
+{
+ int result;
+
+ if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
+ (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
+ (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
+ (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
+ (result = (atmp->tm_min - btmp->tm_min)) == 0)
+ result = atmp->tm_sec - btmp->tm_sec;
+ return result;
+}
+
+static time_t
+time2sub(tmp, funcp, offset, okayp, do_norm_secs)
+struct tm * const tmp;
+void (* const funcp)(const time_t*, long, struct tm*);
+const long offset;
+int * const okayp;
+const int do_norm_secs;
+{
+ const struct state * sp;
+ int dir;
+ int bits;
+ int i, j ;
+ int saved_seconds;
+ time_t newt;
+ time_t t;
+ struct tm yourtm, mytm;
+
+ *okayp = FALSE;
+ yourtm = *tmp;
+ if (do_norm_secs) {
+ if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
+ SECSPERMIN))
+ return WRONG;
+ }
+ if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
+ return WRONG;
+ if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
+ return WRONG;
+ if (normalize_overflow(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR))
+ return WRONG;
+ /*
+ ** Turn yourtm.tm_year into an actual year number for now.
+ ** It is converted back to an offset from TM_YEAR_BASE later.
+ */
+ if (increment_overflow(&yourtm.tm_year, TM_YEAR_BASE))
+ return WRONG;
+ while (yourtm.tm_mday <= 0) {
+ if (increment_overflow(&yourtm.tm_year, -1))
+ return WRONG;
+ i = yourtm.tm_year + (1 < yourtm.tm_mon);
+ yourtm.tm_mday += year_lengths[isleap(i)];
+ }
+ while (yourtm.tm_mday > DAYSPERLYEAR) {
+ i = yourtm.tm_year + (1 < yourtm.tm_mon);
+ yourtm.tm_mday -= year_lengths[isleap(i)];
+ if (increment_overflow(&yourtm.tm_year, 1))
+ return WRONG;
+ }
+ for ( ; ; ) {
+ i = mon_lengths[isleap(yourtm.tm_year)][yourtm.tm_mon];
+ if (yourtm.tm_mday <= i)
+ break;
+ yourtm.tm_mday -= i;
+ if (++yourtm.tm_mon >= MONSPERYEAR) {
+ yourtm.tm_mon = 0;
+ if (increment_overflow(&yourtm.tm_year, 1))
+ return WRONG;
+ }
+ }
+ if (increment_overflow(&yourtm.tm_year, -TM_YEAR_BASE))
+ return WRONG;
+ /* Don't go below 1900 for POLA */
+ if (yourtm.tm_year < 0)
+ return WRONG;
+ if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
+ saved_seconds = 0;
+ else if (yourtm.tm_year + TM_YEAR_BASE < EPOCH_YEAR) {
+ /*
+ ** We can't set tm_sec to 0, because that might push the
+ ** time below the minimum representable time.
+ ** Set tm_sec to 59 instead.
+ ** This assumes that the minimum representable time is
+ ** not in the same minute that a leap second was deleted from,
+ ** which is a safer assumption than using 58 would be.
+ */
+ if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
+ return WRONG;
+ saved_seconds = yourtm.tm_sec;
+ yourtm.tm_sec = SECSPERMIN - 1;
+ } else {
+ saved_seconds = yourtm.tm_sec;
+ yourtm.tm_sec = 0;
+ }
+ /*
+ ** Divide the search space in half
+ ** (this works whether time_t is signed or unsigned).
+ */
+ bits = TYPE_BIT(time_t) - 1;
+ /*
+ ** If we have more than this, we will overflow tm_year for tmcomp().
+ ** We should really return an error if we cannot represent it.
+ */
+ if (bits > 56)
+ bits = 56;
+ /*
+ ** If time_t is signed, then 0 is just above the median,
+ ** assuming two's complement arithmetic.
+ ** If time_t is unsigned, then (1 << bits) is just above the median.
+ */
+ t = TYPE_SIGNED(time_t) ? 0 : (((time_t) 1) << bits);
+ for ( ; ; ) {
+ (*funcp)(&t, offset, &mytm);
+ dir = tmcomp(&mytm, &yourtm);
+ if (dir != 0) {
+ if (bits-- < 0)
+ return WRONG;
+ if (bits < 0)
+ --t; /* may be needed if new t is minimal */
+ else if (dir > 0)
+ t -= ((time_t) 1) << bits;
+ else t += ((time_t) 1) << bits;
+ continue;
+ }
+ if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
+ break;
+ /*
+ ** Right time, wrong type.
+ ** Hunt for right time, right type.
+ ** It's okay to guess wrong since the guess
+ ** gets checked.
+ */
+ sp = (funcp == localsub) ? lclptr : gmtptr;
+#ifdef ALL_STATE
+ if (sp == NULL)
+ return WRONG;
+#endif /* defined ALL_STATE */
+ for (i = sp->typecnt - 1; i >= 0; --i) {
+ if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
+ continue;
+ for (j = sp->typecnt - 1; j >= 0; --j) {
+ if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
+ continue;
+ newt = t + sp->ttis[j].tt_gmtoff -
+ sp->ttis[i].tt_gmtoff;
+ (*funcp)(&newt, offset, &mytm);
+ if (tmcomp(&mytm, &yourtm) != 0)
+ continue;
+ if (mytm.tm_isdst != yourtm.tm_isdst)
+ continue;
+ /*
+ ** We have a match.
+ */
+ t = newt;
+ goto label;
+ }
+ }
+ return WRONG;
+ }
+label:
+ newt = t + saved_seconds;
+ if ((newt < t) != (saved_seconds < 0))
+ return WRONG;
+ t = newt;
+ (*funcp)(&t, offset, tmp);
+ *okayp = TRUE;
+ return t;
+}
+
+static time_t
+time2(tmp, funcp, offset, okayp)
+struct tm * const tmp;
+void (* const funcp)(const time_t*, long, struct tm*);
+const long offset;
+int * const okayp;
+{
+ time_t t;
+
+ /*
+ ** First try without normalization of seconds
+ ** (in case tm_sec contains a value associated with a leap second).
+ ** If that fails, try with normalization of seconds.
+ */
+ t = time2sub(tmp, funcp, offset, okayp, FALSE);
+ return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE);
+}
+
+static time_t
+time1(tmp, funcp, offset)
+struct tm * const tmp;
+void (* const funcp)(const time_t *, long, struct tm *);
+const long offset;
+{
+ time_t t;
+ const struct state * sp;
+ int samei, otheri;
+ int sameind, otherind;
+ int i;
+ int nseen;
+ int seen[TZ_MAX_TYPES];
+ int types[TZ_MAX_TYPES];
+ int okay;
+
+ if (tmp->tm_isdst > 1)
+ tmp->tm_isdst = 1;
+ t = time2(tmp, funcp, offset, &okay);
+#ifdef PCTS
+ /*
+ ** PCTS code courtesy Grant Sullivan (grant@osf.org).
+ */
+ if (okay)
+ return t;
+ if (tmp->tm_isdst < 0)
+ tmp->tm_isdst = 0; /* reset to std and try again */
+#endif /* defined PCTS */
+#ifndef PCTS
+ if (okay || tmp->tm_isdst < 0)
+ return t;
+#endif /* !defined PCTS */
+ /*
+ ** We're supposed to assume that somebody took a time of one type
+ ** and did some math on it that yielded a "struct tm" that's bad.
+ ** We try to divine the type they started from and adjust to the
+ ** type they need.
+ */
+ sp = (funcp == localsub) ? lclptr : gmtptr;
+#ifdef ALL_STATE
+ if (sp == NULL)
+ return WRONG;
+#endif /* defined ALL_STATE */
+ for (i = 0; i < sp->typecnt; ++i)
+ seen[i] = FALSE;
+ nseen = 0;
+ for (i = sp->timecnt - 1; i >= 0; --i)
+ if (!seen[sp->types[i]]) {
+ seen[sp->types[i]] = TRUE;
+ types[nseen++] = sp->types[i];
+ }
+ for (sameind = 0; sameind < nseen; ++sameind) {
+ samei = types[sameind];
+ if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
+ continue;
+ for (otherind = 0; otherind < nseen; ++otherind) {
+ otheri = types[otherind];
+ if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
+ continue;
+ tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
+ sp->ttis[samei].tt_gmtoff;
+ tmp->tm_isdst = !tmp->tm_isdst;
+ t = time2(tmp, funcp, offset, &okay);
+ if (okay)
+ return t;
+ tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
+ sp->ttis[samei].tt_gmtoff;
+ tmp->tm_isdst = !tmp->tm_isdst;
+ }
+ }
+ return WRONG;
+}
+
+time_t
+mktime(tmp)
+struct tm * const tmp;
+{
+ time_t mktime_return_value;
+ _MUTEX_LOCK(&lcl_mutex);
+ tzset_basic();
+ mktime_return_value = time1(tmp, localsub, 0L);
+ _MUTEX_UNLOCK(&lcl_mutex);
+ return(mktime_return_value);
+}
+
+#ifdef STD_INSPIRED
+
+time_t
+timelocal(tmp)
+struct tm * const tmp;
+{
+ tmp->tm_isdst = -1; /* in case it wasn't initialized */
+ return mktime(tmp);
+}
+
+time_t
+timegm(tmp)
+struct tm * const tmp;
+{
+ tmp->tm_isdst = 0;
+ return time1(tmp, gmtsub, 0L);
+}
+
+time_t
+timeoff(tmp, offset)
+struct tm * const tmp;
+const long offset;
+{
+ tmp->tm_isdst = 0;
+ return time1(tmp, gmtsub, offset);
+}
+
+#endif /* defined STD_INSPIRED */
+
+#ifdef CMUCS
+
+/*
+** The following is supplied for compatibility with
+** previous versions of the CMUCS runtime library.
+*/
+
+long
+gtime(tmp)
+struct tm * const tmp;
+{
+ const time_t t = mktime(tmp);
+
+ if (t == WRONG)
+ return -1;
+ return t;
+}
+
+#endif /* defined CMUCS */
+
+/*
+** XXX--is the below the right way to conditionalize??
+*/
+
+#ifdef STD_INSPIRED
+
+/*
+** IEEE Std 1003.1-1988 (POSIX) legislates that 536457599
+** shall correspond to "Wed Dec 31 23:59:59 UTC 1986", which
+** is not the case if we are accounting for leap seconds.
+** So, we provide the following conversion routines for use
+** when exchanging timestamps with POSIX conforming systems.
+*/
+
+static long
+leapcorr(timep)
+time_t * timep;
+{
+ struct state * sp;
+ struct lsinfo * lp;
+ int i;
+
+ sp = lclptr;
+ i = sp->leapcnt;
+ while (--i >= 0) {
+ lp = &sp->lsis[i];
+ if (*timep >= lp->ls_trans)
+ return lp->ls_corr;
+ }
+ return 0;
+}
+
+time_t
+time2posix(t)
+time_t t;
+{
+ tzset();
+ return t - leapcorr(&t);
+}
+
+time_t
+posix2time(t)
+time_t t;
+{
+ time_t x;
+ time_t y;
+
+ tzset();
+ /*
+ ** For a positive leap second hit, the result
+ ** is not unique. For a negative leap second
+ ** hit, the corresponding time doesn't exist,
+ ** so we return an adjacent second.
+ */
+ x = t + leapcorr(&t);
+ y = x - leapcorr(&x);
+ if (y < t) {
+ do {
+ x++;
+ y = x - leapcorr(&x);
+ } while (y < t);
+ if (t != y)
+ return x - 1;
+ } else if (y > t) {
+ do {
+ --x;
+ y = x - leapcorr(&x);
+ } while (y > t);
+ if (t != y)
+ return x + 1;
+ }
+ return x;
+}
+
+#endif /* defined STD_INSPIRED */
diff --git a/lib/libc/stdtime/private.h b/lib/libc/stdtime/private.h
new file mode 100644
index 0000000..a3c7778
--- /dev/null
+++ b/lib/libc/stdtime/private.h
@@ -0,0 +1,260 @@
+#ifndef PRIVATE_H
+
+#define PRIVATE_H
+
+/*
+** This file is in the public domain, so clarified as of
+** 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov).
+**
+** $FreeBSD$
+*/
+
+/* Stuff moved from Makefile.inc to reduce clutter */
+#ifndef TM_GMTOFF
+#define TM_GMTOFF tm_gmtoff
+#define TM_ZONE tm_zone
+#define STD_INSPIRED 1
+#define PCTS 1
+#define HAVE_LONG_DOUBLE 1
+#define HAVE_STRERROR 1
+#define HAVE_UNISTD_H 1
+#define LOCALE_HOME _PATH_LOCALE
+#define TZDIR "/usr/share/zoneinfo"
+#endif /* ndef TM_GMTOFF */
+
+/*
+** This header is for use ONLY with the time conversion code.
+** There is no guarantee that it will remain unchanged,
+** or that it will remain at all.
+** Do NOT copy it to any system include directory.
+** Thank you!
+*/
+
+/*
+** ID
+*/
+
+#ifndef lint
+#ifndef NOID
+/*
+static char privatehid[] = "@(#)private.h 7.53";
+*/
+#endif /* !defined NOID */
+#endif /* !defined lint */
+
+/*
+** Defaults for preprocessor symbols.
+** You can override these in your C compiler options, e.g. `-DHAVE_ADJTIME=0'.
+*/
+
+#ifndef HAVE_ADJTIME
+#define HAVE_ADJTIME 1
+#endif /* !defined HAVE_ADJTIME */
+
+#ifndef HAVE_GETTEXT
+#define HAVE_GETTEXT 0
+#endif /* !defined HAVE_GETTEXT */
+
+#ifndef HAVE_INCOMPATIBLE_CTIME_R
+#define HAVE_INCOMPATIBLE_CTIME_R 0
+#endif /* !defined INCOMPATIBLE_CTIME_R */
+
+#ifndef HAVE_SETTIMEOFDAY
+#define HAVE_SETTIMEOFDAY 3
+#endif /* !defined HAVE_SETTIMEOFDAY */
+
+#ifndef HAVE_STRERROR
+#define HAVE_STRERROR 1
+#endif /* !defined HAVE_STRERROR */
+
+#ifndef HAVE_SYMLINK
+#define HAVE_SYMLINK 1
+#endif /* !defined HAVE_SYMLINK */
+
+#ifndef HAVE_SYS_STAT_H
+#define HAVE_SYS_STAT_H 1
+#endif /* !defined HAVE_SYS_STAT_H */
+
+#ifndef HAVE_SYS_WAIT_H
+#define HAVE_SYS_WAIT_H 1
+#endif /* !defined HAVE_SYS_WAIT_H */
+
+#ifndef HAVE_UNISTD_H
+#define HAVE_UNISTD_H 1
+#endif /* !defined HAVE_UNISTD_H */
+
+#ifndef HAVE_UTMPX_H
+#define HAVE_UTMPX_H 0
+#endif /* !defined HAVE_UTMPX_H */
+
+#ifndef LOCALE_HOME
+#define LOCALE_HOME "/usr/lib/locale"
+#endif /* !defined LOCALE_HOME */
+
+#if HAVE_INCOMPATIBLE_CTIME_R
+#define asctime_r _incompatible_asctime_r
+#define ctime_r _incompatible_ctime_r
+#endif /* HAVE_INCOMPATIBLE_CTIME_R */
+
+/*
+** Nested includes
+*/
+
+#include "sys/types.h" /* for time_t */
+#include "stdio.h"
+#include "errno.h"
+#include "string.h"
+#include "limits.h" /* for CHAR_BIT */
+#include "time.h"
+#include "stdlib.h"
+
+#if HAVE_GETTEXT - 0
+#include "libintl.h"
+#endif /* HAVE_GETTEXT - 0 */
+
+#if HAVE_SYS_WAIT_H - 0
+#include <sys/wait.h> /* for WIFEXITED and WEXITSTATUS */
+#endif /* HAVE_SYS_WAIT_H - 0 */
+
+#ifndef WIFEXITED
+#define WIFEXITED(status) (((status) & 0xff) == 0)
+#endif /* !defined WIFEXITED */
+#ifndef WEXITSTATUS
+#define WEXITSTATUS(status) (((status) >> 8) & 0xff)
+#endif /* !defined WEXITSTATUS */
+
+#if HAVE_UNISTD_H - 0
+#include "unistd.h" /* for F_OK and R_OK */
+#endif /* HAVE_UNISTD_H - 0 */
+
+#if !(HAVE_UNISTD_H - 0)
+#ifndef F_OK
+#define F_OK 0
+#endif /* !defined F_OK */
+#ifndef R_OK
+#define R_OK 4
+#endif /* !defined R_OK */
+#endif /* !(HAVE_UNISTD_H - 0) */
+
+/* Unlike <ctype.h>'s isdigit, this also works if c < 0 | c > UCHAR_MAX. */
+#define is_digit(c) ((unsigned)(c) - '0' <= 9)
+
+/*
+** SunOS 4.1.1 headers lack FILENAME_MAX.
+*/
+
+#ifndef FILENAME_MAX
+
+#ifndef MAXPATHLEN
+#ifdef unix
+#include "sys/param.h"
+#endif /* defined unix */
+#endif /* !defined MAXPATHLEN */
+
+#ifdef MAXPATHLEN
+#define FILENAME_MAX MAXPATHLEN
+#endif /* defined MAXPATHLEN */
+#ifndef MAXPATHLEN
+#define FILENAME_MAX 1024 /* Pure guesswork */
+#endif /* !defined MAXPATHLEN */
+
+#endif /* !defined FILENAME_MAX */
+
+/*
+** Private function declarations.
+*/
+char * icalloc(int nelem, int elsize);
+char * icatalloc(char * old, const char * new);
+char * icpyalloc(const char * string);
+char * imalloc(int n);
+void * irealloc(void * pointer, int size);
+void icfree(char * pointer);
+void ifree(char * pointer);
+char * scheck(const char *string, const char *format);
+
+
+/*
+** Finally, some convenience items.
+*/
+
+#ifndef TRUE
+#define TRUE 1
+#endif /* !defined TRUE */
+
+#ifndef FALSE
+#define FALSE 0
+#endif /* !defined FALSE */
+
+#ifndef TYPE_BIT
+#define TYPE_BIT(type) (sizeof (type) * CHAR_BIT)
+#endif /* !defined TYPE_BIT */
+
+#ifndef TYPE_SIGNED
+#define TYPE_SIGNED(type) (((type) -1) < 0)
+#endif /* !defined TYPE_SIGNED */
+
+#ifndef INT_STRLEN_MAXIMUM
+/*
+** 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))
+#endif /* !defined INT_STRLEN_MAXIMUM */
+
+/*
+** INITIALIZE(x)
+*/
+
+#ifndef GNUC_or_lint
+#ifdef lint
+#define GNUC_or_lint
+#endif /* defined lint */
+#ifndef lint
+#ifdef __GNUC__
+#define GNUC_or_lint
+#endif /* defined __GNUC__ */
+#endif /* !defined lint */
+#endif /* !defined GNUC_or_lint */
+
+#ifndef INITIALIZE
+#ifdef GNUC_or_lint
+#define INITIALIZE(x) ((x) = 0)
+#endif /* defined GNUC_or_lint */
+#ifndef GNUC_or_lint
+#define INITIALIZE(x)
+#endif /* !defined GNUC_or_lint */
+#endif /* !defined INITIALIZE */
+
+/*
+** For the benefit of GNU folk...
+** `_(MSGID)' uses the current locale's message library string for MSGID.
+** The default is to use gettext if available, and use MSGID otherwise.
+*/
+
+#ifndef _
+#if HAVE_GETTEXT - 0
+#define _(msgid) gettext(msgid)
+#else /* !(HAVE_GETTEXT - 0) */
+#define _(msgid) msgid
+#endif /* !(HAVE_GETTEXT - 0) */
+#endif /* !defined _ */
+
+#ifndef TZ_DOMAIN
+#define TZ_DOMAIN "tz"
+#endif /* !defined TZ_DOMAIN */
+
+#if HAVE_INCOMPATIBLE_CTIME_R
+#undef asctime_r
+#undef ctime_r
+char *asctime_r(struct tm const *, char *);
+char *ctime_r(time_t const *, char *);
+#endif /* HAVE_INCOMPATIBLE_CTIME_R */
+
+/*
+** UNIX was a registered trademark of The Open Group in 2003.
+*/
+
+#endif /* !defined PRIVATE_H */
diff --git a/lib/libc/stdtime/strftime.3 b/lib/libc/stdtime/strftime.3
new file mode 100644
index 0000000..10beb7c
--- /dev/null
+++ b/lib/libc/stdtime/strftime.3
@@ -0,0 +1,282 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)strftime.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd November 4, 2004
+.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
+.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 .
+.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 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"
+or
+"post meridiem"
+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.
+.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 0000000..3f66ea2
--- /dev/null
+++ b/lib/libc/stdtime/strftime.c
@@ -0,0 +1,592 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * 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.c 7.64";
+/*
+** 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 *);
+static char * _fmt(const char *, const struct tm *, char *, const char *, int *);
+
+size_t strftime(char * __restrict, size_t, const char * __restrict,
+ const struct tm * __restrict);
+
+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] = {
+ /* 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(char * __restrict s, size_t maxsize, const char * __restrict format,
+ const struct tm * __restrict t)
+{
+ char * p;
+ int warn;
+
+ tzset();
+ warn = IN_NONE;
+ p = _fmt(((format == NULL) ? "%c" : format), t, s, s + maxsize, &warn);
+#ifndef NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU
+ if (warn != IN_NONE && getenv(YEAR_2000_NAME) != NULL) {
+ (void) fprintf(stderr, "\n");
+ if (format == NULL)
+ (void) fprintf(stderr, "NULL strftime format ");
+ else (void) fprintf(stderr, "strftime format \"%s\" ",
+ format);
+ (void) fprintf(stderr, "yields only two digits of years in ");
+ if (warn == IN_SOME)
+ (void) fprintf(stderr, "some locales");
+ else if (warn == IN_THIS)
+ (void) fprintf(stderr, "the current locale");
+ else (void) fprintf(stderr, "all locales");
+ (void) fprintf(stderr, "\n");
+ }
+#endif /* !defined NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU */
+ if (p == s + maxsize)
+ return 0;
+ *p = '\0';
+ return p - s;
+}
+
+static char *
+_fmt(format, t, pt, ptlim, warnp)
+const char * format;
+const struct tm * const t;
+char * pt;
+const char * const ptlim;
+int * warnp;
+{
+ int Ealternative, Oalternative, PadIndex;
+ struct lc_time_T *tptr = __get_current_time_locale();
+
+ 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 = _conv((t->tm_year + TM_YEAR_BASE) / 100,
+ fmt_padding[PAD_FMT_CENTURY][PadIndex], pt, ptlim);
+ continue;
+ case 'c':
+ {
+ int warn2 = IN_SOME;
+
+ pt = _fmt(tptr->c_fmt, t, pt, ptlim, warnp);
+ if (warn2 == IN_ALL)
+ warn2 = IN_THIS;
+ if (warn2 > *warnp)
+ *warnp = warn2;
+ }
+ continue;
+ case 'D':
+ pt = _fmt("%m/%d/%y", t, pt, ptlim, warnp);
+ continue;
+ case 'd':
+ pt = _conv(t->tm_mday, fmt_padding[PAD_FMT_DAYOFMONTH][PadIndex],
+ pt, ptlim);
+ 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);
+ continue;
+ case 'F':
+ pt = _fmt("%Y-%m-%d", t, pt, ptlim, warnp);
+ continue;
+ case 'H':
+ pt = _conv(t->tm_hour, fmt_padding[PAD_FMT_HMS][PadIndex],
+ pt, ptlim);
+ continue;
+ case 'I':
+ pt = _conv((t->tm_hour % 12) ?
+ (t->tm_hour % 12) : 12,
+ fmt_padding[PAD_FMT_HMS][PadIndex], pt, ptlim);
+ continue;
+ case 'j':
+ pt = _conv(t->tm_yday + 1,
+ fmt_padding[PAD_FMT_DAYOFYEAR][PadIndex], pt, ptlim);
+ 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);
+ 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);
+ continue;
+ case 'M':
+ pt = _conv(t->tm_min, fmt_padding[PAD_FMT_HMS][PadIndex],
+ pt, ptlim);
+ continue;
+ case 'm':
+ pt = _conv(t->tm_mon + 1,
+ fmt_padding[PAD_FMT_MONTH][PadIndex], pt, ptlim);
+ 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);
+ continue;
+ case 'r':
+ pt = _fmt(tptr->ampm_fmt, t, pt, ptlim,
+ warnp);
+ continue;
+ case 'S':
+ pt = _conv(t->tm_sec, fmt_padding[PAD_FMT_HMS][PadIndex],
+ pt, ptlim);
+ 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(buf, "%ld",
+ (long) mkt);
+ else (void) sprintf(buf, "%lu",
+ (unsigned long) mkt);
+ pt = _add(buf, pt, ptlim);
+ }
+ continue;
+ case 'T':
+ pt = _fmt("%H:%M:%S", t, pt, ptlim, warnp);
+ 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);
+ 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);
+ 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 yday;
+ int wday;
+ int w;
+
+ year = t->tm_year + TM_YEAR_BASE;
+ yday = t->tm_yday;
+ wday = t->tm_wday;
+ for ( ; ; ) {
+ int len;
+ int bot;
+ int top;
+
+ len = isleap(year) ?
+ 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) {
+ ++year;
+ w = 1;
+ break;
+ }
+ if (yday >= bot) {
+ w = 1 + ((yday - bot) /
+ DAYSPERWEEK);
+ break;
+ }
+ --year;
+ yday += isleap(year) ?
+ 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);
+ else if (*format == 'g') {
+ *warnp = IN_ALL;
+ pt = _conv(year % 100, fmt_padding[PAD_FMT_SHORTYEAR][PadIndex],
+ pt, ptlim);
+ } else pt = _conv(year, fmt_padding[PAD_FMT_YEAR][PadIndex],
+ pt, ptlim);
+ }
+ 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);
+ 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);
+ continue;
+ case 'w':
+ pt = _conv(t->tm_wday, "%d", pt, ptlim);
+ continue;
+ case 'X':
+ pt = _fmt(tptr->X_fmt, t, pt, ptlim, warnp);
+ continue;
+ case 'x':
+ {
+ int warn2 = IN_SOME;
+
+ pt = _fmt(tptr->x_fmt, t, pt, ptlim, &warn2);
+ if (warn2 == IN_ALL)
+ warn2 = IN_THIS;
+ if (warn2 > *warnp)
+ *warnp = warn2;
+ }
+ continue;
+ case 'y':
+ *warnp = IN_ALL;
+ pt = _conv((t->tm_year + TM_YEAR_BASE) % 100,
+ fmt_padding[PAD_FMT_SHORTYEAR][PadIndex], pt, ptlim);
+ continue;
+ case 'Y':
+ pt = _conv(t->tm_year + TM_YEAR_BASE,
+ fmt_padding[PAD_FMT_YEAR][PadIndex],
+ pt, ptlim);
+ 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 /= 60;
+ pt = _conv((diff/60)*100 + diff%60,
+ fmt_padding[PAD_FMT_YEAR][PadIndex], pt, ptlim);
+ }
+ continue;
+ case '+':
+ pt = _fmt(tptr->date_fmt, t, pt, ptlim,
+ warnp);
+ 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(n, format, pt, ptlim)
+const int n;
+const char * const format;
+char * const pt;
+const char * const ptlim;
+{
+ char buf[INT_STRLEN_MAXIMUM(int) + 1];
+
+ (void) sprintf(buf, format, n);
+ return _add(buf, pt, ptlim);
+}
+
+static char *
+_add(str, pt, ptlim)
+const char * str;
+char * pt;
+const char * const ptlim;
+{
+ while (pt < ptlim && (*pt = *str++) != '\0')
+ ++pt;
+ return pt;
+}
diff --git a/lib/libc/stdtime/strptime.3 b/lib/libc/stdtime/strptime.3
new file mode 100644
index 0000000..d763fbc
--- /dev/null
+++ b/lib/libc/stdtime/strptime.3
@@ -0,0 +1,173 @@
+.\"
+.\" 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 January 4, 2003
+.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
+.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 .
+.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).
+.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.
+.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 %U
+and
+.Fa %W
+format specifiers accept any value within the range 00 to 53
+without validating against other values supplied (like month
+or day of the year, for example).
+.Pp
+The
+.Fa %Z
+format specifier only accepts time zone abbreviations of the local time zone,
+or the value "GMT".
+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 0000000..ddf6b57
--- /dev/null
+++ b/lib/libc/stdtime/strptime.c
@@ -0,0 +1,538 @@
+/*
+ * Powerdog Industries kindly requests feedback from anyone modifying
+ * this function:
+ *
+ * Date: Thu, 05 Jun 1997 23:17:17 -0400
+ * From: Kevin Ruddy <kevin.ruddy@powerdog.com>
+ * To: James FitzGibbon <james@nexis.net>
+ * Subject: Re: Use of your strptime(3) code (fwd)
+ *
+ * The reason for the "no mod" clause was so that modifications would
+ * come back and we could integrate them and reissue so that a wider
+ * audience could use it (thereby spreading the wealth). This has
+ * made it possible to get strptime to work on many operating systems.
+ * I'm not sure why that's "plain unacceptable" to the FreeBSD team.
+ *
+ * Anyway, you can change it to "with or without modification" as
+ * you see fit. Enjoy.
+ *
+ * Kevin Ruddy
+ * Powerdog Industries, Inc.
+ */
+/*
+ * Copyright (c) 1994 Powerdog Industries. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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 Powerdog Industries.
+ * 4. The name of Powerdog Industries may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * 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.
+ */
+
+#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"
+
+static char * _strptime(const char *, const char *, struct tm *, int *);
+
+#define asizeof(a) (sizeof (a) / sizeof ((a)[0]))
+
+static char *
+_strptime(const char *buf, const char *fmt, struct tm *tm, int *GMTp)
+{
+ char c;
+ const char *ptr;
+ int i,
+ len;
+ int Ealternative, Oalternative;
+ struct lc_time_T *tptr = __get_current_time_locale();
+
+ ptr = fmt;
+ while (*ptr != 0) {
+ if (*buf == 0)
+ break;
+
+ c = *ptr++;
+
+ if (c != '%') {
+ if (isspace((unsigned char)c))
+ while (*buf != 0 && isspace((unsigned char)*buf))
+ buf++;
+ else if (c != *buf++)
+ return 0;
+ continue;
+ }
+
+ Ealternative = 0;
+ Oalternative = 0;
+label:
+ c = *ptr++;
+ switch (c) {
+ case 0:
+ case '%':
+ if (*buf++ != '%')
+ return 0;
+ break;
+
+ case '+':
+ buf = _strptime(buf, tptr->date_fmt, tm, GMTp);
+ if (buf == 0)
+ return 0;
+ break;
+
+ case 'C':
+ if (!isdigit((unsigned char)*buf))
+ return 0;
+
+ /* XXX This will break for 3-digit centuries. */
+ len = 2;
+ for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
+ i *= 10;
+ i += *buf - '0';
+ len--;
+ }
+ if (i < 19)
+ return 0;
+
+ tm->tm_year = i * 100 - 1900;
+ break;
+
+ case 'c':
+ buf = _strptime(buf, tptr->c_fmt, tm, GMTp);
+ if (buf == 0)
+ return 0;
+ break;
+
+ case 'D':
+ buf = _strptime(buf, "%m/%d/%y", tm, GMTp);
+ if (buf == 0)
+ return 0;
+ 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);
+ if (buf == 0)
+ return 0;
+ break;
+
+ case 'R':
+ buf = _strptime(buf, "%H:%M", tm, GMTp);
+ if (buf == 0)
+ return 0;
+ break;
+
+ case 'r':
+ buf = _strptime(buf, tptr->ampm_fmt, tm, GMTp);
+ if (buf == 0)
+ return 0;
+ break;
+
+ case 'T':
+ buf = _strptime(buf, "%H:%M:%S", tm, GMTp);
+ if (buf == 0)
+ return 0;
+ break;
+
+ case 'X':
+ buf = _strptime(buf, tptr->X_fmt, tm, GMTp);
+ if (buf == 0)
+ return 0;
+ break;
+
+ case 'x':
+ buf = _strptime(buf, tptr->x_fmt, tm, GMTp);
+ if (buf == 0)
+ return 0;
+ break;
+
+ case 'j':
+ if (!isdigit((unsigned char)*buf))
+ return 0;
+
+ len = 3;
+ for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
+ i *= 10;
+ i += *buf - '0';
+ len--;
+ }
+ if (i < 1 || i > 366)
+ return 0;
+
+ tm->tm_yday = i - 1;
+ break;
+
+ case 'M':
+ case 'S':
+ if (*buf == 0 || isspace((unsigned char)*buf))
+ break;
+
+ if (!isdigit((unsigned char)*buf))
+ return 0;
+
+ len = 2;
+ for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
+ i *= 10;
+ i += *buf - '0';
+ len--;
+ }
+
+ if (c == 'M') {
+ if (i > 59)
+ return 0;
+ tm->tm_min = i;
+ } else {
+ if (i > 60)
+ return 0;
+ tm->tm_sec = i;
+ }
+
+ if (*buf != 0 && isspace((unsigned char)*buf))
+ while (*ptr != 0 && !isspace((unsigned char)*ptr))
+ ptr++;
+ 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((unsigned char)*buf))
+ return 0;
+
+ len = 2;
+ for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
+ i *= 10;
+ i += *buf - '0';
+ len--;
+ }
+ if (c == 'H' || c == 'k') {
+ if (i > 23)
+ return 0;
+ } else if (i > 12)
+ return 0;
+
+ tm->tm_hour = i;
+
+ if (*buf != 0 && isspace((unsigned char)*buf))
+ while (*ptr != 0 && !isspace((unsigned char)*ptr))
+ ptr++;
+ break;
+
+ case 'p':
+ /*
+ * XXX This is bogus if parsed before hour-related
+ * specifiers.
+ */
+ len = strlen(tptr->am);
+ if (strncasecmp(buf, tptr->am, len) == 0) {
+ if (tm->tm_hour > 12)
+ return 0;
+ if (tm->tm_hour == 12)
+ tm->tm_hour = 0;
+ buf += len;
+ break;
+ }
+
+ len = strlen(tptr->pm);
+ if (strncasecmp(buf, tptr->pm, len) == 0) {
+ if (tm->tm_hour > 12)
+ return 0;
+ if (tm->tm_hour != 12)
+ tm->tm_hour += 12;
+ buf += len;
+ break;
+ }
+
+ return 0;
+
+ case 'A':
+ case 'a':
+ for (i = 0; i < asizeof(tptr->weekday); i++) {
+ len = strlen(tptr->weekday[i]);
+ if (strncasecmp(buf, tptr->weekday[i],
+ len) == 0)
+ break;
+ len = strlen(tptr->wday[i]);
+ if (strncasecmp(buf, tptr->wday[i],
+ len) == 0)
+ break;
+ }
+ if (i == asizeof(tptr->weekday))
+ return 0;
+
+ tm->tm_wday = i;
+ buf += len;
+ 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((unsigned char)*buf))
+ return 0;
+
+ len = 2;
+ for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
+ i *= 10;
+ i += *buf - '0';
+ len--;
+ }
+ if (i > 53)
+ return 0;
+
+ if (*buf != 0 && isspace((unsigned char)*buf))
+ while (*ptr != 0 && !isspace((unsigned char)*ptr))
+ ptr++;
+ break;
+
+ case 'w':
+ if (!isdigit((unsigned char)*buf))
+ return 0;
+
+ i = *buf - '0';
+ if (i > 6)
+ return 0;
+
+ tm->tm_wday = i;
+
+ if (*buf != 0 && isspace((unsigned char)*buf))
+ while (*ptr != 0 && !isspace((unsigned char)*ptr))
+ ptr++;
+ break;
+
+ case 'd':
+ case 'e':
+ /*
+ * The %e specifier is explicitly documented as not
+ * being zero-padded but there is no harm in allowing
+ * such padding.
+ *
+ * XXX The %e specifier may gobble one too many
+ * digits if used incorrectly.
+ */
+ if (!isdigit((unsigned char)*buf))
+ return 0;
+
+ len = 2;
+ for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
+ i *= 10;
+ i += *buf - '0';
+ len--;
+ }
+ if (i > 31)
+ return 0;
+
+ tm->tm_mday = i;
+
+ if (*buf != 0 && isspace((unsigned char)*buf))
+ while (*ptr != 0 && !isspace((unsigned char)*ptr))
+ ptr++;
+ 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(buf,
+ tptr->alt_month[i],
+ len) == 0)
+ break;
+ }
+ } else {
+ len = strlen(tptr->month[i]);
+ if (strncasecmp(buf, tptr->month[i],
+ len) == 0)
+ break;
+ len = strlen(tptr->mon[i]);
+ if (strncasecmp(buf, tptr->mon[i],
+ len) == 0)
+ break;
+ }
+ }
+ if (i == asizeof(tptr->month))
+ return 0;
+
+ tm->tm_mon = i;
+ buf += len;
+ break;
+
+ case 'm':
+ if (!isdigit((unsigned char)*buf))
+ return 0;
+
+ len = 2;
+ for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
+ i *= 10;
+ i += *buf - '0';
+ len--;
+ }
+ if (i < 1 || i > 12)
+ return 0;
+
+ tm->tm_mon = i - 1;
+
+ if (*buf != 0 && isspace((unsigned char)*buf))
+ while (*ptr != 0 && !isspace((unsigned char)*ptr))
+ ptr++;
+ break;
+
+ case 's':
+ {
+ char *cp;
+ int sverrno;
+ long n;
+ time_t t;
+
+ sverrno = errno;
+ errno = 0;
+ n = strtol(buf, &cp, 10);
+ if (errno == ERANGE || (long)(t = n) != n) {
+ errno = sverrno;
+ return 0;
+ }
+ errno = sverrno;
+ buf = cp;
+ gmtime_r(&t, tm);
+ *GMTp = 1;
+ }
+ break;
+
+ case 'Y':
+ case 'y':
+ if (*buf == 0 || isspace((unsigned char)*buf))
+ break;
+
+ if (!isdigit((unsigned char)*buf))
+ return 0;
+
+ len = (c == 'Y') ? 4 : 2;
+ for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
+ i *= 10;
+ i += *buf - '0';
+ len--;
+ }
+ if (c == 'Y')
+ i -= 1900;
+ if (c == 'y' && i < 69)
+ i += 100;
+ if (i < 0)
+ return 0;
+
+ tm->tm_year = i;
+
+ if (*buf != 0 && isspace((unsigned char)*buf))
+ while (*ptr != 0 && !isspace((unsigned char)*ptr))
+ ptr++;
+ break;
+
+ case 'Z':
+ {
+ const char *cp;
+ char *zonestr;
+
+ for (cp = buf; *cp && isupper((unsigned char)*cp); ++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")) {
+ *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 0;
+ }
+ buf += cp - buf;
+ }
+ }
+ break;
+ }
+ }
+ return (char *)buf;
+}
+
+
+char *
+strptime(const char * __restrict buf, const char * __restrict fmt,
+ struct tm * __restrict tm)
+{
+ char *ret;
+ int gmt;
+
+ gmt = 0;
+ ret = _strptime(buf, fmt, tm, &gmt);
+ if (ret && gmt) {
+ time_t t = timegm(tm);
+ localtime_r(&t, tm);
+ }
+
+ return (ret);
+}
diff --git a/lib/libc/stdtime/time2posix.3 b/lib/libc/stdtime/time2posix.3
new file mode 100644
index 0000000..ce9c68d
--- /dev/null
+++ b/lib/libc/stdtime/time2posix.3
@@ -0,0 +1,120 @@
+.\" $FreeBSD$
+.\"
+.Dd September 11, 2005
+.Dt TIME2POSIX 3
+.Os
+.Sh NAME
+.Nm time2posix ,
+.Nm posix2time
+.Nd convert seconds since the Epoch
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In time.h
+.Ft time_t
+.Fn time2posix "time_t t"
+.Ft time_t
+.Fn posix2time "time_t t"
+.Sh DESCRIPTION
+.St -p1003.1-88
+legislates that a time_t value of
+536457599 shall correspond to "Wed Dec 31 23:59:59 GMT 1986."
+This effectively implies that POSIX time_t's cannot include leap
+seconds and,
+therefore,
+that the system time must be adjusted as each leap occurs.
+.Pp
+If the time package is configured with leap-second support
+enabled,
+however,
+no such adjustment is needed and
+time_t values continue to increase over leap events
+(as a true `seconds since...' value).
+This means that these values will differ from those required by POSIX
+by the net number of leap seconds inserted since the Epoch.
+.Pp
+Typically this is not a problem as the type time_t is intended
+to be
+(mostly)
+opaque\(emtime_t values should only be obtained-from and
+passed-to functions such as
+.Xr time 3 ,
+.Xr localtime 3 ,
+.Xr mktime 3
+and
+.Xr difftime 3 .
+However,
+.St -p1003.1-88
+gives an arithmetic
+expression for directly computing a time_t value from a given date/time,
+and the same relationship is assumed by some
+(usually older)
+applications.
+Any programs creating/dissecting time_t's
+using such a relationship will typically not handle intervals
+over leap seconds correctly.
+.Pp
+The
+.Fn time2posix
+and
+.Fn posix2time
+functions are provided to address this time_t mismatch by converting
+between local time_t values and their POSIX equivalents.
+This is done by accounting for the number of time-base changes that
+would have taken place on a POSIX system as leap seconds were inserted
+or deleted.
+These converted values can then be used in lieu of correcting the older
+applications,
+or when communicating with POSIX-compliant systems.
+.Pp
+The
+.Fn time2posix
+function is single-valued.
+That is,
+every local time_t
+corresponds to a single POSIX time_t.
+The
+.Fn posix2time
+function is less well-behaved:
+for a positive leap second hit the result is not unique,
+and for a negative leap second hit the corresponding
+POSIX time_t does not exist so an adjacent value is returned.
+Both of these are good indicators of the inferiority of the
+POSIX representation.
+.Pp
+The following table summarizes the relationship between time_t
+and its conversion to,
+and back from,
+the POSIX representation over the leap second inserted at the end of June,
+1993.
+.Bl -column "93/06/30" "23:59:59" "A+0" "X=time2posix(T)"
+.It Sy "DATE TIME T X=time2posix(T) posix2time(X)"
+.It "93/06/30 23:59:59 A+0 B+0 A+0"
+.It "93/06/30 23:59:60 A+1 B+1 A+1 or A+2"
+.It "93/07/01 00:00:00 A+2 B+1 A+1 or A+2"
+.It "93/07/01 00:00:01 A+3 B+2 A+3"
+.El
+.Pp
+A leap second deletion would look like...
+.Bl -column "??/06/30" "23:59:58" "A+0" "X=time2posix(T)"
+.It Sy "DATE TIME T X=time2posix(T) posix2time(X)"
+.It "??/06/30 23:59:58 A+0 B+0 A+0"
+.It "??/07/01 00:00:00 A+1 B+2 A+1"
+.It "??/07/01 00:00:01 A+2 B+3 A+2"
+.El
+.Pp
+.D1 No "[Note: posix2time(B+1) => A+0 or A+1]"
+.Pp
+If leap-second support is not enabled,
+local time_t's and
+POSIX time_t's are equivalent,
+and both
+.Fn time2posix
+and
+.Fn posix2time
+degenerate to the identity function.
+.Sh "SEE ALSO"
+.Xr difftime 3 ,
+.Xr localtime 3 ,
+.Xr mktime 3 ,
+.Xr time 3
diff --git a/lib/libc/stdtime/time32.c b/lib/libc/stdtime/time32.c
new file mode 100644
index 0000000..e852a4f
--- /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 0000000..6917e6b
--- /dev/null
+++ b/lib/libc/stdtime/timelocal.c
@@ -0,0 +1,117 @@
+/*-
+ * Copyright (c) 2001 Alexey Zelkin <phantom@FreeBSD.org>
+ * Copyright (c) 1997 FreeBSD Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stddef.h>
+
+#include "ldpart.h"
+#include "timelocal.h"
+
+static struct lc_time_T _time_locale;
+static int _time_using_locale;
+static char *time_locale_buf;
+
+#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"
+};
+
+struct lc_time_T *
+__get_current_time_locale(void)
+{
+ return (_time_using_locale
+ ? &_time_locale
+ : (struct lc_time_T *)&_C_time_locale);
+}
+
+int
+__time_load_locale(const char *name)
+{
+ return (__part_load_locale(name, &_time_using_locale,
+ &time_locale_buf, "LC_TIME",
+ LCTIME_SIZE, LCTIME_SIZE,
+ (const char **)&_time_locale));
+}
diff --git a/lib/libc/stdtime/timelocal.h b/lib/libc/stdtime/timelocal.h
new file mode 100644
index 0000000..5d26bf9
--- /dev/null
+++ b/lib/libc/stdtime/timelocal.h
@@ -0,0 +1,55 @@
+/*-
+ * Copyright (c) 1997-2002 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$
+ */
+
+#ifndef _TIMELOCAL_H_
+#define _TIMELOCAL_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(void);
+int __time_load_locale(const char *);
+
+#endif /* !_TIMELOCAL_H_ */
diff --git a/lib/libc/stdtime/tzfile.5 b/lib/libc/stdtime/tzfile.5
new file mode 100644
index 0000000..cc7e659
--- /dev/null
+++ b/lib/libc/stdtime/tzfile.5
@@ -0,0 +1,138 @@
+.\" $FreeBSD$
+.Dd September 13, 1994
+.Dt TZFILE 5
+.Os
+.Sh NAME
+.Nm tzfile
+.Nd timezone information
+.Sh SYNOPSIS
+.Fd #include \&"/usr/src/lib/libc/stdtime/tzfile.h\&"
+.Sh DESCRIPTION
+The time zone information files used by
+.Xr tzset 3
+begin with the magic characters
+.Dq Li TZif
+to identify them as
+time zone information files,
+followed by sixteen bytes reserved for future use,
+followed by four four-byte values
+written in a ``standard'' byte order
+(the high-order byte of the value is written first).
+These values are,
+in order:
+.Pp
+.Bl -tag -compact -width tzh_ttisstdcnt
+.It Va tzh_ttisgmtcnt
+The number of UTC/local indicators stored in the file.
+.It Va tzh_ttisstdcnt
+The number of standard/wall indicators stored in the file.
+.It Va tzh_leapcnt
+The number of leap seconds for which data is stored in the file.
+.It Va tzh_timecnt
+The number of ``transition times'' for which data is stored
+in the file.
+.It Va tzh_typecnt
+The number of ``local time types'' for which data is stored
+in the file (must not be zero).
+.It Va tzh_charcnt
+The number of characters of ``time zone abbreviation strings''
+stored in the file.
+.El
+.Pp
+The above header is followed by
+.Va tzh_timecnt
+four-byte values of type
+.Fa long ,
+sorted in ascending order.
+These values are written in ``standard'' byte order.
+Each is used as a transition time (as returned by
+.Xr time 3 )
+at which the rules for computing local time change.
+Next come
+.Va tzh_timecnt
+one-byte values of type
+.Fa "unsigned char" ;
+each one tells which of the different types of ``local time'' types
+described in the file is associated with the same-indexed transition time.
+These values serve as indices into an array of
+.Fa ttinfo
+structures that appears next in the file;
+these structures are defined as follows:
+.Pp
+.Bd -literal -offset indent
+struct ttinfo {
+ long tt_gmtoff;
+ int tt_isdst;
+ unsigned int tt_abbrind;
+};
+.Ed
+.Pp
+Each structure is written as a four-byte value for
+.Va tt_gmtoff
+of type
+.Fa long ,
+in a standard byte order, followed by a one-byte value for
+.Va tt_isdst
+and a one-byte value for
+.Va tt_abbrind .
+In each structure,
+.Va tt_gmtoff
+gives the number of seconds to be added to UTC,
+.Li tt_isdst
+tells whether
+.Li tm_isdst
+should be set by
+.Xr localtime 3
+and
+.Va tt_abbrind
+serves as an index into the array of time zone abbreviation characters
+that follow the
+.Li ttinfo
+structure(s) in the file.
+.Pp
+Then there are
+.Va tzh_leapcnt
+pairs of four-byte values, written in standard byte order;
+the first value of each pair gives the time
+(as returned by
+.Xr time 3 )
+at which a leap second occurs;
+the second gives the
+.Em total
+number of leap seconds to be applied after the given time.
+The pairs of values are sorted in ascending order by time.
+.Pp
+Then there are
+.Va tzh_ttisstdcnt
+standard/wall indicators, each stored as a one-byte value;
+they tell whether the transition times associated with local time types
+were specified as standard time or wall clock time,
+and are used when a time zone file is used in handling POSIX-style
+time zone environment variables.
+.Pp
+Finally there are
+.Va tzh_ttisgmtcnt
+UTC/local indicators, each stored as a one-byte value;
+they tell whether the transition times associated with local time types
+were specified as UTC or local time,
+and are used when a time zone file is used in handling POSIX-style
+time zone environment variables.
+.Pp
+.Nm localtime
+uses the first standard-time
+.Li ttinfo
+structure in the file
+(or simply the first
+.Li ttinfo
+structure in the absence of a standard-time structure)
+if either
+.Li tzh_timecnt
+is zero or the time argument is less than the first transition time recorded
+in the file.
+.Sh SEE ALSO
+.Xr ctime 3 ,
+.Xr time2posix 3 ,
+.Xr zic 8
+.\" @(#)tzfile.5 7.2
+.\" This file is in the public domain, so clarified as of
+.\" 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov).
diff --git a/lib/libc/stdtime/tzfile.h b/lib/libc/stdtime/tzfile.h
new file mode 100644
index 0000000..89c5694
--- /dev/null
+++ b/lib/libc/stdtime/tzfile.h
@@ -0,0 +1,192 @@
+#ifndef TZFILE_H
+#define TZFILE_H
+
+
+/*
+** This file is in the public domain, so clarified as of
+** 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov).
+**
+** $FreeBSD$
+*/
+
+/*
+** This header is for use ONLY with the time conversion code.
+** There is no guarantee that it will remain unchanged,
+** or that it will remain at all.
+** Do NOT copy it to any system include directory.
+** Thank you!
+*/
+
+/*
+** ID
+*/
+
+#ifndef lint
+#ifndef NOID
+/*
+static char tzfilehid[] = "@(#)tzfile.h 7.14";
+*/
+#endif /* !defined NOID */
+#endif /* !defined lint */
+
+/*
+** Information about time zone files.
+*/
+
+#ifndef TZDIR
+#define TZDIR "/usr/share/zoneinfo" /* Time zone object file directory */
+#endif /* !defined TZDIR */
+
+#ifndef TZDEFAULT
+#define TZDEFAULT "/etc/localtime"
+#endif /* !defined TZDEFAULT */
+
+#ifndef TZDEFRULES
+#define TZDEFRULES "posixrules"
+#endif /* !defined TZDEFRULES */
+
+/*
+** Each file begins with. . .
+*/
+
+#define TZ_MAGIC "TZif"
+
+struct tzhead {
+ char tzh_magic[4]; /* TZ_MAGIC */
+ char tzh_reserved[16]; /* reserved for future use */
+ char tzh_ttisgmtcnt[4]; /* coded number of trans. time flags */
+ char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */
+ char tzh_leapcnt[4]; /* coded number of leap seconds */
+ char tzh_timecnt[4]; /* coded number of transition times */
+ char tzh_typecnt[4]; /* coded number of local time types */
+ char tzh_charcnt[4]; /* coded number of abbr. chars */
+};
+
+/*
+** . . .followed by. . .
+**
+** tzh_timecnt (char [4])s coded transition times a la time(2)
+** tzh_timecnt (unsigned char)s types of local time starting at above
+** tzh_typecnt repetitions of
+** one (char [4]) coded UTC offset in seconds
+** one (unsigned char) used to set tm_isdst
+** one (unsigned char) that's an abbreviation list index
+** tzh_charcnt (char)s '\0'-terminated zone abbreviations
+** tzh_leapcnt repetitions of
+** one (char [4]) coded leap second transition times
+** one (char [4]) total correction after above
+** tzh_ttisstdcnt (char)s indexed by type; if TRUE, transition
+** time is standard time, if FALSE,
+** transition time is wall clock time
+** if absent, transition times are
+** assumed to be wall clock time
+** tzh_ttisgmtcnt (char)s indexed by type; if TRUE, transition
+** time is UTC, if FALSE,
+** transition time is local time
+** if absent, transition times are
+** assumed to be local time
+*/
+
+/*
+** In the current implementation, "tzset()" refuses to deal with files that
+** exceed any of the limits below.
+*/
+
+#ifndef TZ_MAX_TIMES
+/*
+** The TZ_MAX_TIMES value below is enough to handle a bit more than a
+** year's worth of solar time (corrected daily to the nearest second) or
+** 138 years of Pacific Presidential Election time
+** (where there are three time zone transitions every fourth year).
+*/
+#define TZ_MAX_TIMES 370
+#endif /* !defined TZ_MAX_TIMES */
+
+#ifndef TZ_MAX_TYPES
+#ifndef NOSOLAR
+#define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold */
+#endif /* !defined NOSOLAR */
+#ifdef NOSOLAR
+/*
+** Must be at least 14 for Europe/Riga as of Jan 12 1995,
+** as noted by Earl Chew <earl@hpato.aus.hp.com>.
+*/
+#define TZ_MAX_TYPES 20 /* Maximum number of local time types */
+#endif /* !defined NOSOLAR */
+#endif /* !defined TZ_MAX_TYPES */
+
+#ifndef TZ_MAX_CHARS
+#define TZ_MAX_CHARS 50 /* Maximum number of abbreviation characters */
+ /* (limited by what unsigned chars can hold) */
+#endif /* !defined TZ_MAX_CHARS */
+
+#ifndef TZ_MAX_LEAPS
+#define TZ_MAX_LEAPS 50 /* Maximum number of leap second corrections */
+#endif /* !defined TZ_MAX_LEAPS */
+
+#define SECSPERMIN 60
+#define MINSPERHOUR 60
+#define HOURSPERDAY 24
+#define DAYSPERWEEK 7
+#define DAYSPERNYEAR 365
+#define DAYSPERLYEAR 366
+#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
+#define SECSPERDAY ((long) SECSPERHOUR * HOURSPERDAY)
+#define MONSPERYEAR 12
+
+#define TM_SUNDAY 0
+#define TM_MONDAY 1
+#define TM_TUESDAY 2
+#define TM_WEDNESDAY 3
+#define TM_THURSDAY 4
+#define TM_FRIDAY 5
+#define TM_SATURDAY 6
+
+#define TM_JANUARY 0
+#define TM_FEBRUARY 1
+#define TM_MARCH 2
+#define TM_APRIL 3
+#define TM_MAY 4
+#define TM_JUNE 5
+#define TM_JULY 6
+#define TM_AUGUST 7
+#define TM_SEPTEMBER 8
+#define TM_OCTOBER 9
+#define TM_NOVEMBER 10
+#define TM_DECEMBER 11
+
+#define TM_YEAR_BASE 1900
+
+#define EPOCH_YEAR 1970
+#define EPOCH_WDAY TM_THURSDAY
+
+/*
+** Accurate only for the past couple of centuries;
+** that will probably do.
+*/
+
+#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
+
+#ifndef USG
+
+/*
+** Use of the underscored variants may cause problems if you move your code to
+** certain System-V-based systems; for maximum portability, use the
+** underscore-free variants. The underscored variants are provided for
+** backward compatibility only; they may disappear from future versions of
+** this file.
+*/
+
+#define SECS_PER_MIN SECSPERMIN
+#define MINS_PER_HOUR MINSPERHOUR
+#define HOURS_PER_DAY HOURSPERDAY
+#define DAYS_PER_WEEK DAYSPERWEEK
+#define DAYS_PER_NYEAR DAYSPERNYEAR
+#define DAYS_PER_LYEAR DAYSPERLYEAR
+#define SECS_PER_HOUR SECSPERHOUR
+#define SECS_PER_DAY SECSPERDAY
+#define MONS_PER_YEAR MONSPERYEAR
+
+#endif /* !defined USG */
+
+#endif /* !defined TZFILE_H */
diff --git a/lib/libc/string/Makefile.inc b/lib/libc/string/Makefile.inc
new file mode 100644
index 0000000..6d64ea5
--- /dev/null
+++ b/lib/libc/string/Makefile.inc
@@ -0,0 +1,64 @@
+# @(#)Makefile.inc 8.1 (Berkeley) 6/4/93
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/${MACHINE_ARCH}/string ${.CURDIR}/string
+
+CFLAGS+= -I${.CURDIR}/locale
+
+# machine-independent string sources
+MISRCS+=bcmp.c bcopy.c bzero.c ffs.c ffsl.c fls.c flsl.c index.c memccpy.c \
+ memchr.c memcmp.c \
+ memcpy.c memmem.c memmove.c memset.c rindex.c stpcpy.c strcasecmp.c \
+ strcat.c strchr.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 strcasestr.c strnstr.c \
+ strpbrk.c strrchr.c strsep.c strsignal.c strspn.c strstr.c strtok.c \
+ strxfrm.c swab.c wcscat.c wcschr.c wcscmp.c wcscoll.c wcscpy.c \
+ wcscspn.c wcsdup.c \
+ wcslcat.c wcslcpy.c wcslen.c wcsncat.c wcsncmp.c wcsncpy.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+= ${.CURDIR}/string/Symbol.map
+
+
+# machine-dependent string sources
+.if exists(${.CURDIR}/${MACHINE_ARCH}/string/Makefile.inc)
+.include "${.CURDIR}/${MACHINE_ARCH}/string/Makefile.inc"
+.endif
+
+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 strcspn.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 wcscoll.3 wcstok.3 \
+ wcswidth.3 wcsxfrm.3 wmemchr.3
+
+MLINKS+=ffs.3 ffsl.3
+MLINKS+=ffs.3 fls.3
+MLINKS+=ffs.3 flsl.3
+MLINKS+=index.3 rindex.3
+MLINKS+=strcasecmp.3 strncasecmp.3
+MLINKS+=strcat.3 strncat.3
+MLINKS+=strchr.3 strrchr.3
+MLINKS+=strcmp.3 strncmp.3
+MLINKS+=strcpy.3 stpcpy.3
+MLINKS+=strcpy.3 strncpy.3
+MLINKS+=strerror.3 perror.3 strerror.3 sys_errlist.3 strerror.3 sys_nerr.3
+MLINKS+=strerror.3 strerror_r.3
+MLINKS+=strlcpy.3 strlcat.3
+MLINKS+=strtok.3 strtok_r.3
+MLINKS+=strstr.3 strcasestr.3
+MLINKS+=strstr.3 strnstr.3
+MLINKS+=wmemchr.3 wmemcmp.3 wmemchr.3 wmemcpy.3 \
+ wmemchr.3 wmemmove.3 wmemchr.3 wmemset.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 wcsncat.3 wmemchr.3 wcsncmp.3 \
+ wmemchr.3 wcsncpy.3 wmemchr.3 wcspbrk.3 \
+ wmemchr.3 wcsrchr.3 wmemchr.3 wcsspn.3 \
+ wmemchr.3 wcsstr.3
diff --git a/lib/libc/string/Symbol.map b/lib/libc/string/Symbol.map
new file mode 100644
index 0000000..577727a
--- /dev/null
+++ b/lib/libc/string/Symbol.map
@@ -0,0 +1,80 @@
+# $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;
+};
+
+FBSDprivate {
+ __strtok_r;
+};
diff --git a/lib/libc/string/bcmp.3 b/lib/libc/string/bcmp.3
new file mode 100644
index 0000000..cc75ac1
--- /dev/null
+++ b/lib/libc/string/bcmp.3
@@ -0,0 +1,81 @@
+.\" 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. 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.
+.\"
+.\" @(#)bcmp.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.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
+.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 0000000..6c75767
--- /dev/null
+++ b/lib/libc/string/bcmp.c
@@ -0,0 +1,59 @@
+/*
+ * 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. 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.
+ */
+
+#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 0000000..c7e9706
--- /dev/null
+++ b/lib/libc/string/bcopy.3
@@ -0,0 +1,81 @@
+.\" 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. 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.
+.\"
+.\" @(#)bcopy.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.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.
diff --git a/lib/libc/string/bcopy.c b/lib/libc/string/bcopy.c
new file mode 100644
index 0000000..0c2ec94
--- /dev/null
+++ b/lib/libc/string/bcopy.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. 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.
+ */
+
+#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 0000000..4052655
--- /dev/null
+++ b/lib/libc/string/bstring.3
@@ -0,0 +1,112 @@
+.\" 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. 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.
+.\"
+.\" @(#)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 0000000..a8c4a27
--- /dev/null
+++ b/lib/libc/string/bzero.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. 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.
+.\"
+.\" @(#)bzero.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt BZERO 3
+.Os
+.Sh NAME
+.Nm 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"
+.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.
+.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.
diff --git a/lib/libc/string/bzero.c b/lib/libc/string/bzero.c
new file mode 100644
index 0000000..201bd64
--- /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 0000000..7199bf5
--- /dev/null
+++ b/lib/libc/string/ffs.3
@@ -0,0 +1,100 @@
+.\" 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. 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.
+.\"
+.\" @(#)ffs.3 8.2 (Berkeley) 4/19/94
+.\" $FreeBSD$
+.\"
+.Dd January 13, 2004
+.Dt FFS 3
+.Os
+.Sh NAME
+.Nm ffs ,
+.Nm ffsl ,
+.Nm fls ,
+.Nm flsl
+.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 fls "int value"
+.Ft int
+.Fn flsl "long value"
+.Sh DESCRIPTION
+The
+.Fn ffs
+and
+.Fn ffsl
+functions find the first bit set in
+.Fa value
+and return the index of that bit.
+.Pp
+The
+.Fn fls
+and
+.Fn flsl
+functions find the last bit set in
+.Fa value
+and return the index of that bit.
+.Pp
+Bits are numbered starting from 1, starting at the right-most
+(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
+.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 .
diff --git a/lib/libc/string/ffs.c b/lib/libc/string/ffs.c
new file mode 100644
index 0000000..f8da996
--- /dev/null
+++ b/lib/libc/string/ffs.c
@@ -0,0 +1,55 @@
+/*-
+ * 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. 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.
+ */
+
+#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 0000000..3ef9afa
--- /dev/null
+++ b/lib/libc/string/ffsl.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. 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.
+ */
+
+#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/fls.c b/lib/libc/string/fls.c
new file mode 100644
index 0000000..e27f3ff
--- /dev/null
+++ b/lib/libc/string/fls.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. 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.
+ */
+
+#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 0000000..127e311
--- /dev/null
+++ b/lib/libc/string/flsl.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. 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.
+ */
+
+#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/index.3 b/lib/libc/string/index.3
new file mode 100644
index 0000000..1245970
--- /dev/null
+++ b/lib/libc/string/index.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.
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce 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.
+.\"
+.\" @(#)index.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.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
+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.
diff --git a/lib/libc/string/index.c b/lib/libc/string/index.c
new file mode 100644
index 0000000..5d79f4f
--- /dev/null
+++ b/lib/libc/string/index.c
@@ -0,0 +1,65 @@
+/*-
+ * 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. 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.
+ */
+
+#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>
+
+#ifdef STRCHR
+#include <string.h>
+
+char *
+strchr
+#else
+#include <strings.h>
+
+char *
+index
+#endif
+(const char *p, int ch)
+{
+ char c;
+
+ c = ch;
+ for (;; ++p) {
+ if (*p == c)
+ return ((char *)p);
+ if (*p == '\0')
+ return (NULL);
+ }
+ /* NOTREACHED */
+}
diff --git a/lib/libc/string/memccpy.3 b/lib/libc/string/memccpy.3
new file mode 100644
index 0000000..84f385d
--- /dev/null
+++ b/lib/libc/string/memccpy.3
@@ -0,0 +1,76 @@
+.\" 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. 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.
+.\"
+.\" @(#)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 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 0000000..62c47a1
--- /dev/null
+++ b/lib/libc/string/memccpy.c
@@ -0,0 +1,60 @@
+/*-
+ * 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. 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.
+ */
+
+#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(t, f, c, n)
+ 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 0000000..1c06785
--- /dev/null
+++ b/lib/libc/string/memchr.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. 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.
+.\"
+.\" @(#)memchr.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.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"
+.Sh DESCRIPTION
+The
+.Fn memchr
+function
+locates the first occurrence of
+.Fa c
+(converted to an unsigned char)
+in string
+.Fa b .
+.Sh RETURN VALUES
+The
+.Fn memchr
+function
+returns 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
+.Sh STANDARDS
+The
+.Fn memchr
+function
+conforms to
+.St -isoC .
diff --git a/lib/libc/string/memchr.c b/lib/libc/string/memchr.c
new file mode 100644
index 0000000..a217a80
--- /dev/null
+++ b/lib/libc/string/memchr.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. 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.
+ */
+
+#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(s, c, n)
+ const void *s;
+ unsigned char c;
+ size_t n;
+{
+ if (n != 0) {
+ const unsigned char *p = s;
+
+ do {
+ if (*p++ == 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 0000000..d38154a
--- /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. 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.
+.\"
+.\" @(#)memcmp.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.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 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
+.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 0000000..6b28c31
--- /dev/null
+++ b/lib/libc/string/memcmp.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. 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.
+ */
+
+#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(s1, s2, n)
+ const void *s1, *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 0000000..c970d7c
--- /dev/null
+++ b/lib/libc/string/memcpy.3
@@ -0,0 +1,91 @@
+.\" 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. 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.
+.\"
+.\" @(#)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
+.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 0000000..ed03856
--- /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 0000000..73c267c
--- /dev/null
+++ b/lib/libc/string/memmem.3
@@ -0,0 +1,86 @@
+.\" 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 August 24, 2005
+.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 big_len
+is smaller than
+.Fa little_len ,
+if
+.Fa little_len
+is 0, if
+.Fa big_len
+is 0 or 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 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.
diff --git a/lib/libc/string/memmem.c b/lib/libc/string/memmem.c
new file mode 100644
index 0000000..0ac0a6d
--- /dev/null
+++ b/lib/libc/string/memmem.c
@@ -0,0 +1,67 @@
+/*-
+ * 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(l, l_len, s, s_len)
+ 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;
+
+ /* we need something to compare */
+ if (l_len == 0 || s_len == 0)
+ return NULL;
+
+ /* "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 0000000..39543c3
--- /dev/null
+++ b/lib/libc/string/memmove.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 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. 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.
+.\"
+.\" @(#)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
+.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 0000000..05cf75a
--- /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/memset.3 b/lib/libc/string/memset.3
new file mode 100644
index 0000000..71ab4d5
--- /dev/null
+++ b/lib/libc/string/memset.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
+.\" 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. 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.
+.\"
+.\" @(#)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 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
+.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 0000000..17683ae
--- /dev/null
+++ b/lib/libc/string/memset.c
@@ -0,0 +1,132 @@
+/*-
+ * 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. 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.
+ */
+
+#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/rindex.c b/lib/libc/string/rindex.c
new file mode 100644
index 0000000..641c00f
--- /dev/null
+++ b/lib/libc/string/rindex.c
@@ -0,0 +1,66 @@
+/*
+ * 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. 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.
+ */
+
+#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>
+
+#ifdef STRRCHR
+#include <string.h>
+
+char *
+strrchr
+#else
+#include <strings.h>
+
+char *
+rindex
+#endif
+(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 */
+}
diff --git a/lib/libc/string/stpcpy.c b/lib/libc/string/stpcpy.c
new file mode 100644
index 0000000..0bee746
--- /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 * to, const char * from)
+{
+
+ for (; (*to = *from); ++from, ++to);
+ return(to);
+}
diff --git a/lib/libc/string/strcasecmp.3 b/lib/libc/string/strcasecmp.3
new file mode 100644
index 0000000..346b9e3
--- /dev/null
+++ b/lib/libc/string/strcasecmp.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.
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce 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.
+.\"
+.\" @(#)strcasecmp.3 8.1 (Berkeley) 6/9/93
+.\" $FreeBSD$
+.\"
+.Dd June 9, 1993
+.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"
+.Sh DESCRIPTION
+The
+.Fn strcasecmp
+and
+.Fn strncasecmp
+functions
+compare the null-terminated strings
+.Fa s1
+and
+.Fa s2 .
+.Pp
+The
+.Fn strncasecmp
+compares at most
+.Fa len
+characters.
+.Sh RETURN VALUES
+The
+.Fn strcasecmp
+and
+.Fn strncasecmp
+return an integer greater than, equal to, or less than 0,
+according as
+.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 .
+.Sh SEE ALSO
+.Xr bcmp 3 ,
+.Xr memcmp 3 ,
+.Xr strcmp 3 ,
+.Xr strcoll 3 ,
+.Xr strxfrm 3 ,
+.Xr tolower 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 0000000..cb031ce
--- /dev/null
+++ b/lib/libc/string/strcasecmp.c
@@ -0,0 +1,77 @@
+/*
+ * 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. 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.
+ */
+
+#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>
+
+typedef unsigned char u_char;
+
+int
+strcasecmp(s1, s2)
+ const char *s1, *s2;
+{
+ const u_char
+ *us1 = (const u_char *)s1,
+ *us2 = (const u_char *)s2;
+
+ while (tolower(*us1) == tolower(*us2++))
+ if (*us1++ == '\0')
+ return (0);
+ return (tolower(*us1) - tolower(*--us2));
+}
+
+int
+strncasecmp(s1, s2, n)
+ const char *s1, *s2;
+ size_t n;
+{
+ if (n != 0) {
+ const u_char
+ *us1 = (const u_char *)s1,
+ *us2 = (const u_char *)s2;
+
+ do {
+ if (tolower(*us1) != tolower(*us2++))
+ return (tolower(*us1) - tolower(*--us2));
+ if (*us1++ == '\0')
+ break;
+ } while (--n != 0);
+ }
+ return (0);
+}
diff --git a/lib/libc/string/strcasestr.c b/lib/libc/string/strcasestr.c
new file mode 100644
index 0000000..d950766
--- /dev/null
+++ b/lib/libc/string/strcasestr.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. 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <ctype.h>
+#include <string.h>
+
+/*
+ * Find the first occurrence of find in s, ignore case.
+ */
+char *
+strcasestr(s, find)
+ const char *s, *find;
+{
+ char c, sc;
+ size_t len;
+
+ if ((c = *find++) != 0) {
+ c = tolower((unsigned char)c);
+ len = strlen(find);
+ do {
+ do {
+ if ((sc = *s++) == 0)
+ return (NULL);
+ } while ((char)tolower((unsigned char)sc) != c);
+ } while (strncasecmp(s, find, len) != 0);
+ s--;
+ }
+ return ((char *)s);
+}
diff --git a/lib/libc/string/strcat.3 b/lib/libc/string/strcat.3
new file mode 100644
index 0000000..298c865
--- /dev/null
+++ b/lib/libc/string/strcat.3
@@ -0,0 +1,159 @@
+.\" 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. 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.
+.\"
+.\" @(#)strcat.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt STRCAT 3
+.Os
+.Sh NAME
+.Nm strcat
+.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 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.
+(See
+the FSA.)
+.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
+.Sh SEE ALSO
+.Xr bcopy 3 ,
+.Xr memccpy 3 ,
+.Xr memcpy 3 ,
+.Xr memmove 3 ,
+.Xr strcpy 3 ,
+.Xr strlcat 3 ,
+.Xr strlcpy 3
+.Sh STANDARDS
+The
+.Fn strcat
+and
+.Fn strncat
+functions
+conform to
+.St -isoC .
diff --git a/lib/libc/string/strcat.c b/lib/libc/string/strcat.c
new file mode 100644
index 0000000..d30389d
--- /dev/null
+++ b/lib/libc/string/strcat.c
@@ -0,0 +1,50 @@
+/*
+ * 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. 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.
+ */
+
+#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 0000000..5d801ef
--- /dev/null
+++ b/lib/libc/string/strchr.3
@@ -0,0 +1,99 @@
+.\" 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. 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.
+.\"
+.\" @(#)strchr.3 8.2 (Berkeley) 4/19/94
+.\" $FreeBSD$
+.\"
+.Dd April 19, 1994
+.Dt STRCHR 3
+.Os
+.Sh NAME
+.Nm strchr , strrchr
+.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"
+.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 .
+.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.
+.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
+.Sh STANDARDS
+The functions
+.Fn strchr
+and
+.Fn strrchr
+conform to
+.St -isoC .
diff --git a/lib/libc/string/strchr.c b/lib/libc/string/strchr.c
new file mode 100644
index 0000000..1d82abe
--- /dev/null
+++ b/lib/libc/string/strchr.c
@@ -0,0 +1,5 @@
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#define STRCHR
+#include "index.c"
diff --git a/lib/libc/string/strcmp.3 b/lib/libc/string/strcmp.3
new file mode 100644
index 0000000..08adad0
--- /dev/null
+++ b/lib/libc/string/strcmp.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.
+.\" 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.
+.\"
+.\" @(#)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
+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
+.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 0000000..a6bb0d5
--- /dev/null
+++ b/lib/libc/string/strcmp.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. 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.
+ */
+
+#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(s1, s2)
+ const char *s1, *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 0000000..a620108
--- /dev/null
+++ b/lib/libc/string/strcoll.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
+.\" 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. 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.
+.\"
+.\" @(#)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"
+.Sh DESCRIPTION
+The
+.Fn strcoll
+function
+lexicographically compares the null-terminated strings
+.Fa s1
+and
+.Fa s2
+according to the current locale collation if any, otherwise call
+.Fa strcmp ,
+and returns an integer greater than, equal to, or less than 0,
+according as
+.Fa s1
+is greater than, equal to, or less than
+.Fa s2 .
+.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 .
diff --git a/lib/libc/string/strcoll.c b/lib/libc/string/strcoll.c
new file mode 100644
index 0000000..a0daf8d
--- /dev/null
+++ b/lib/libc/string/strcoll.c
@@ -0,0 +1,86 @@
+/*-
+ * Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua>
+ * at Electronni Visti IA, Kiev, Ukraine.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list 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 "collate.h"
+
+int
+strcoll(s, s2)
+ const char *s, *s2;
+{
+ int len, len2, prim, prim2, sec, sec2, ret, ret2;
+ const char *t, *t2;
+ char *tt, *tt2;
+
+ if (__collate_load_error)
+ return strcmp(s, s2);
+
+ len = len2 = 1;
+ ret = ret2 = 0;
+ if (__collate_substitute_nontrivial) {
+ t = tt = __collate_substitute(s);
+ t2 = tt2 = __collate_substitute(s2);
+ } else {
+ tt = tt2 = NULL;
+ t = s;
+ t2 = s2;
+ }
+ while(*t && *t2) {
+ prim = prim2 = 0;
+ while(*t && !prim) {
+ __collate_lookup(t, &len, &prim, &sec);
+ t += len;
+ }
+ while(*t2 && !prim2) {
+ __collate_lookup(t2, &len2, &prim2, &sec2);
+ t2 += len2;
+ }
+ if(!prim || !prim2)
+ break;
+ if(prim != prim2) {
+ ret = prim - prim2;
+ goto end;
+ }
+ if(!ret2)
+ ret2 = sec - sec2;
+ }
+ if(!*t && *t2)
+ ret = -(int)((u_char)*t2);
+ else if(*t && !*t2)
+ ret = (u_char)*t;
+ else if(!*t && !*t2)
+ ret = ret2;
+ end:
+ free(tt);
+ free(tt2);
+
+ return ret;
+}
diff --git a/lib/libc/string/strcpy.3 b/lib/libc/string/strcpy.3
new file mode 100644
index 0000000..2b65809
--- /dev/null
+++ b/lib/libc/string/strcpy.3
@@ -0,0 +1,202 @@
+.\" 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. 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.
+.\"
+.\" @(#)strcpy.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd August 9, 2001
+.Dt STRCPY 3
+.Os
+.Sh NAME
+.Nm strcpy , strncpy
+.Nd copy strings
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In string.h
+.Ft char *
+.Fn stpcpy "char *dst" "const char *src"
+.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 strncpy
+function copies 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
+function returns a pointer to the terminating
+.Ql \e0
+character of
+.Fa dst .
+.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 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.
+(See
+the FSA
+and
+.Sx EXAMPLES . )
+.Sh SEE ALSO
+.Xr bcopy 3 ,
+.Xr memccpy 3 ,
+.Xr memcpy 3 ,
+.Xr memmove 3 ,
+.Xr strlcpy 3
+.Sh STANDARDS
+The
+.Fn strcpy
+and
+.Fn strncpy
+functions
+conform to
+.St -isoC .
+The
+.Fn stpcpy
+function is an MS-DOS and GNUism.
+The
+.Fn stpcpy
+function
+conforms to no standard.
+.Sh HISTORY
+The
+.Fn stpcpy
+function first appeared in
+.Fx 4.4 ,
+coming from 1998-vintage Linux.
diff --git a/lib/libc/string/strcpy.c b/lib/libc/string/strcpy.c
new file mode 100644
index 0000000..630ae23
--- /dev/null
+++ b/lib/libc/string/strcpy.c
@@ -0,0 +1,49 @@
+/*
+ * 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. 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.
+ */
+
+#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.3 b/lib/libc/string/strcspn.3
new file mode 100644
index 0000000..ef905a5
--- /dev/null
+++ b/lib/libc/string/strcspn.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. 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.
+.\"
+.\" @(#)strcspn.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt STRCSPN 3
+.Os
+.Sh NAME
+.Nm strcspn
+.Nd span the complement of a string
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In string.h
+.Ft size_t
+.Fn strcspn "const char *s" "const char *charset"
+.Sh DESCRIPTION
+The
+.Fn strcspn
+function
+spans the initial part of the null-terminated string
+.Fa s
+as long as the characters from
+.Fa s
+do not occur in string
+.Fa charset
+(it
+spans the
+.Em complement
+of
+.Fa charset ) .
+In other words, it computes the string array index in
+.Fa s
+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 strcspn
+function
+returns the number of characters spanned.
+.Sh SEE ALSO
+.Xr memchr 3 ,
+.Xr strchr 3 ,
+.Xr strpbrk 3 ,
+.Xr strrchr 3 ,
+.Xr strsep 3 ,
+.Xr strspn 3 ,
+.Xr strstr 3 ,
+.Xr strtok 3
+.Sh STANDARDS
+The
+.Fn strcspn
+function
+conforms to
+.St -isoC .
diff --git a/lib/libc/string/strcspn.c b/lib/libc/string/strcspn.c
new file mode 100644
index 0000000..3879a3b
--- /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 0000000..ec91f35
--- /dev/null
+++ b/lib/libc/string/strdup.3
@@ -0,0 +1,70 @@
+.\" 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. 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.
+.\"
+.\" @(#)strdup.3 8.1 (Berkeley) 6/9/93
+.\" $FreeBSD$
+.\"
+.Dd June 9, 1993
+.Dt STRDUP 3
+.Os
+.Sh NAME
+.Nm strdup
+.Nd save a copy of a string
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In string.h
+.Ft char *
+.Fn strdup "const char *str"
+.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 .
+.Sh SEE ALSO
+.Xr free 3 ,
+.Xr malloc 3
+.Sh HISTORY
+The
+.Fn strdup
+function first appeared in
+.Bx 4.4 .
diff --git a/lib/libc/string/strdup.c b/lib/libc/string/strdup.c
new file mode 100644
index 0000000..788a185
--- /dev/null
+++ b/lib/libc/string/strdup.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.
+ * 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.
+ */
+
+#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(str)
+ 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 0000000..9f486ed
--- /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. 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.
+.\"
+.\" @(#)strerror.3 8.1 (Berkeley) 6/9/93
+.\" $FreeBSD$
+.\"
+.Dd October 12, 2004
+.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 .
+.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 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 wes@FreeBSD.org .
+.Sh BUGS
+For unknown error numbers, the
+.Fn strerror
+function will return its result in a static buffer which
+may 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 0000000..38a484f
--- /dev/null
+++ b/lib/libc/string/strerror.c
@@ -0,0 +1,130 @@
+/*-
+ * 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. 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.
+ */
+
+#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>
+
+#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 < 1 || errnum >= 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, sys_errlist[errnum]),
+#else
+ 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 0000000..2be58b8
--- /dev/null
+++ b/lib/libc/string/string.3
@@ -0,0 +1,161 @@
+.\" 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. 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.
+.\"
+.\" @(#)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 0000000..7f19f6b
--- /dev/null
+++ b/lib/libc/string/strlcat.c
@@ -0,0 +1,75 @@
+/* $OpenBSD: strlcat.c,v 1.2 1999/06/17 16:28:58 millert Exp $ */
+
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *rcsid = "$OpenBSD: strlcat.c,v 1.2 1999/06/17 16:28:58 millert Exp $";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <string.h>
+
+/*
+ * Appends src to string dst of size siz (unlike strncat, siz is the
+ * full size of dst, not space left). At most siz-1 characters
+ * will be copied. Always NUL terminates (unless siz <= strlen(dst)).
+ * Returns strlen(src) + MIN(siz, strlen(initial dst)).
+ * If retval >= siz, truncation occurred.
+ */
+size_t
+strlcat(dst, src, siz)
+ char *dst;
+ const char *src;
+ size_t siz;
+{
+ char *d = dst;
+ const char *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 + strlen(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/strlcpy.3 b/lib/libc/string/strlcpy.3
new file mode 100644
index 0000000..f674fe2
--- /dev/null
+++ b/lib/libc/string/strlcpy.3
@@ -0,0 +1,204 @@
+.\" $OpenBSD: strlcpy.3,v 1.5 1999/06/06 15:17:32 aaron Exp $
+.\"
+.\" Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" 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 June 22, 1998
+.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 *dst" "const char *src" "size_t size"
+.Ft size_t
+.Fn strlcat "char *dst" "const char *src" "size_t size"
+.Sh DESCRIPTION
+The
+.Fn strlcpy
+and
+.Fn strlcat
+functions copy and concatenate strings respectively.
+They are designed
+to be safer, more consistent, and less error prone replacements for
+.Xr strncpy 3
+and
+.Xr strncat 3 .
+Unlike those functions,
+.Fn strlcpy
+and
+.Fn strlcat
+take the full size of the buffer (not just the length) and guarantee to
+NUL-terminate the result (as long as
+.Fa size
+is larger than 0 or, in the case of
+.Fn strlcat ,
+as long as there is at least one byte free in
+.Fa dst ) .
+Note that you should include a byte for the NUL in
+.Fa size .
+Also note that
+.Fn strlcpy
+and
+.Fn strlcat
+only operate on true
+.Dq C
+strings.
+This means that for
+.Fn strlcpy
+.Fa src
+must be NUL-terminated and for
+.Fn strlcat
+both
+.Fa src
+and
+.Fa dst
+must be NUL-terminated.
+.Pp
+The
+.Fn strlcpy
+function copies up to
+.Fa size
+- 1 characters from the NUL-terminated string
+.Fa src
+to
+.Fa dst ,
+NUL-terminating the result.
+.Pp
+The
+.Fn strlcat
+function appends the NUL-terminated string
+.Fa src
+to the end of
+.Fa dst .
+It will append at most
+.Fa size
+- strlen(dst) - 1 bytes, NUL-terminating the result.
+.Sh RETURN VALUES
+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 .
+While this may seem somewhat confusing it was done to make
+truncation detection simple.
+.Pp
+Note however, that if
+.Fn strlcat
+traverses
+.Fa size
+characters without finding a NUL, the length of the string is considered
+to be
+.Fa size
+and the destination string will not be NUL-terminated (since there was
+no space for the NUL).
+This keeps
+.Fn strlcat
+from running off the end of a string.
+In practice this should not happen (as it means that either
+.Fa size
+is incorrect or that
+.Fa dst
+is not a proper
+.Dq C
+string).
+The check exists to prevent potential security problems in incorrect code.
+.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 we know how many characters we copied the first time, we can
+speed things up a bit by using a copy instead of an append:
+.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
+.Sh HISTORY
+The
+.Fn strlcpy
+and
+.Fn strlcat
+functions first appeared in
+.Ox 2.4 ,
+and made their appearance in
+.Fx 3.3 .
diff --git a/lib/libc/string/strlcpy.c b/lib/libc/string/strlcpy.c
new file mode 100644
index 0000000..77180a5
--- /dev/null
+++ b/lib/libc/string/strlcpy.c
@@ -0,0 +1,70 @@
+/* $OpenBSD: strlcpy.c,v 1.4 1999/05/01 18:56:41 millert Exp $ */
+
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *rcsid = "$OpenBSD: strlcpy.c,v 1.4 1999/05/01 18:56:41 millert Exp $";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <string.h>
+
+/*
+ * Copy src to string dst of size siz. At most siz-1 characters
+ * will be copied. Always NUL terminates (unless siz == 0).
+ * Returns strlen(src); if retval >= siz, truncation occurred.
+ */
+size_t strlcpy(dst, src, siz)
+ char *dst;
+ const char *src;
+ size_t siz;
+{
+ char *d = dst;
+ const char *s = src;
+ size_t n = siz;
+
+ /* Copy as many bytes as will fit */
+ if (n != 0 && --n != 0) {
+ do {
+ if ((*d++ = *s++) == 0)
+ 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/strlen.3 b/lib/libc/string/strlen.3
new file mode 100644
index 0000000..69b8945
--- /dev/null
+++ b/lib/libc/string/strlen.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
+.\" 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. 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.
+.\"
+.\" @(#)strlen.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt STRLEN 3
+.Os
+.Sh NAME
+.Nm strlen
+.Nd find length of string
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In string.h
+.Ft size_t
+.Fn strlen "const char *s"
+.Sh DESCRIPTION
+The
+.Fn strlen
+function
+computes the length of the string
+.Fa s .
+.Sh RETURN VALUES
+The
+.Fn strlen
+function
+returns
+the number of characters that precede the
+terminating
+.Dv NUL
+character.
+.Sh SEE ALSO
+.Xr string 3
+.Sh STANDARDS
+The
+.Fn strlen
+function
+conforms to
+.St -isoC .
diff --git a/lib/libc/string/strlen.c b/lib/libc/string/strlen.c
new file mode 100644
index 0000000..841c7c2
--- /dev/null
+++ b/lib/libc/string/strlen.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. 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strlen.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <string.h>
+
+size_t
+strlen(str)
+ const char *str;
+{
+ const char *s;
+
+ for (s = str; *s; ++s);
+ return(s - str);
+}
+
diff --git a/lib/libc/string/strmode.3 b/lib/libc/string/strmode.3
new file mode 100644
index 0000000..8c315cd
--- /dev/null
+++ b/lib/libc/string/strmode.3
@@ -0,0 +1,148 @@
+.\" 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. 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.
+.\"
+.\" @(#)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 is a plus sign ``+'' if any there are any alternate
+or additional access control methods associated with the inode, otherwise
+it will 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 0000000..fe2cf9e
--- /dev/null
+++ b/lib/libc/string/strmode.c
@@ -0,0 +1,154 @@
+/*-
+ * 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. 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.
+ */
+
+#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, p)
+ mode_t 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++ = ' '; /* will be a '+' if ACL's implemented */
+ *p = '\0';
+}
diff --git a/lib/libc/string/strncat.c b/lib/libc/string/strncat.c
new file mode 100644
index 0000000..4218ae2
--- /dev/null
+++ b/lib/libc/string/strncat.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
+ * 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. 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.
+ */
+
+#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 0000000..60d09c1
--- /dev/null
+++ b/lib/libc/string/strncmp.c
@@ -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. 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.
+ */
+
+#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(s1, s2, n)
+ const char *s1, *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 0000000..7759e61
--- /dev/null
+++ b/lib/libc/string/strncpy.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
+ * 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. 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.
+ */
+
+#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/strnstr.c b/lib/libc/string/strnstr.c
new file mode 100644
index 0000000..749c43b
--- /dev/null
+++ b/lib/libc/string/strnstr.c
@@ -0,0 +1,72 @@
+/*-
+ * 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. 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.
+ */
+
+#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(s, find, slen)
+ 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 0000000..92a3388
--- /dev/null
+++ b/lib/libc/string/strpbrk.3
@@ -0,0 +1,80 @@
+.\" 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. 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.
+.\"
+.\" @(#)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
+.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 0000000..42e8c62
--- /dev/null
+++ b/lib/libc/string/strpbrk.c
@@ -0,0 +1,58 @@
+/*
+ * 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. 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.
+ */
+
+#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(s1, s2)
+ const char *s1, *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 0000000..11cbd31
--- /dev/null
+++ b/lib/libc/string/strrchr.c
@@ -0,0 +1,5 @@
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#define STRRCHR
+#include "rindex.c"
diff --git a/lib/libc/string/strsep.3 b/lib/libc/string/strsep.3
new file mode 100644
index 0000000..7a2b0f8
--- /dev/null
+++ b/lib/libc/string/strsep.3
@@ -0,0 +1,124 @@
+.\" 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. 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.
+.\"
+.\" @(#)strsep.3 8.1 (Berkeley) 6/9/93
+.\" $FreeBSD$
+.\"
+.Dd June 9, 1993
+.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, 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 0000000..dd5ec0b
--- /dev/null
+++ b/lib/libc/string/strsep.c
@@ -0,0 +1,81 @@
+/*-
+ * 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. 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.
+ */
+
+#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(stringp, delim)
+ 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 0000000..11efb07
--- /dev/null
+++ b/lib/libc/string/strsignal.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. 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.
+ */
+
+#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 <signal.h>
+
+#define UPREFIX "Unknown signal"
+
+/* XXX: negative 'num' ? (REGR) */
+char *
+strsignal(int num)
+{
+ static char ebuf[NL_TEXTMAX];
+ 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
+
+ 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(ebuf));
+ } else {
+ n = strlcpy(ebuf,
+#if defined(NLS)
+ catgets(catd, 2, 0xffff, UPREFIX),
+#else
+ UPREFIX,
+#endif
+ sizeof(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 0000000..475fab8
--- /dev/null
+++ b/lib/libc/string/strspn.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
+.\" 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. 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.
+.\"
+.\" @(#)strspn.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt STRSPN 3
+.Os
+.Sh NAME
+.Nm strspn
+.Nd span a string
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In string.h
+.Ft size_t
+.Fn strspn "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 in
+.Fa s
+of the first character of
+.Fa s
+which is not in
+.Fa charset ,
+else the index of the first null character.
+.Sh RETURN VALUES
+The
+.Fn strspn
+function
+returns the number of characters spanned.
+.Sh SEE ALSO
+.Xr memchr 3 ,
+.Xr strchr 3 ,
+.Xr strcspn 3 ,
+.Xr strpbrk 3 ,
+.Xr strrchr 3 ,
+.Xr strsep 3 ,
+.Xr strstr 3 ,
+.Xr strtok 3
+.Sh STANDARDS
+The
+.Fn strspn
+function
+conforms to
+.St -isoC .
diff --git a/lib/libc/string/strspn.c b/lib/libc/string/strspn.c
new file mode 100644
index 0000000..5dbac0a
--- /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 0000000..a2136c8
--- /dev/null
+++ b/lib/libc/string/strstr.3
@@ -0,0 +1,148 @@
+.\" 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. 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.
+.\"
+.\" @(#)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"
+.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 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
+.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 0000000..3f6d81c
--- /dev/null
+++ b/lib/libc/string/strstr.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
+ * 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. 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.
+ */
+
+#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(s, find)
+ const char *s, *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 0000000..e5c8e33
--- /dev/null
+++ b/lib/libc/string/strtok.3
@@ -0,0 +1,178 @@
+.\" 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.
+.\"
+.\" @(#)strtok.3 8.2 (Berkeley) 2/3/94
+.\" $FreeBSD$
+.\"
+.Dd November 27, 1998
+.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 .
+.Sh AUTHORS
+.An Wes Peters ,
+Softweyr LLC:
+.Aq wes@softweyr.com
+.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 0000000..1a29cc5
--- /dev/null
+++ b/lib/libc/string/strtok.c
@@ -0,0 +1,140 @@
+/*-
+ * 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. 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 the University nor the names of 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 0000000..6f4acf4
--- /dev/null
+++ b/lib/libc/string/strxfrm.3
@@ -0,0 +1,100 @@
+.\" 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. 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.
+.\"
+.\" @(#)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"
+.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 .
+.Sh RETURN VALUES
+Upon successful completion,
+.Fn strxfrm
+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 strcmp 3 ,
+.Xr strcoll 3 ,
+.Xr wcsxfrm 3
+.Sh STANDARDS
+The
+.Fn strxfrm
+function
+conforms to
+.St -isoC .
diff --git a/lib/libc/string/strxfrm.c b/lib/libc/string/strxfrm.c
new file mode 100644
index 0000000..81e05af
--- /dev/null
+++ b/lib/libc/string/strxfrm.c
@@ -0,0 +1,83 @@
+/*-
+ * Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua>
+ * at Electronni Visti IA, Kiev, Ukraine.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list 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 "collate.h"
+
+size_t
+strxfrm(char * __restrict dest, const char * __restrict src, size_t len)
+{
+ int prim, sec, l;
+ size_t slen;
+ char *s, *ss;
+
+ if (!*src) {
+ if (len > 0)
+ *dest = '\0';
+ return 0;
+ }
+
+ if (__collate_load_error) {
+ slen = strlen(src);
+ if (len > 0) {
+ if (slen < len)
+ strcpy(dest, src);
+ else {
+ strncpy(dest, src, len - 1);
+ dest[len - 1] = '\0';
+ }
+ }
+ return slen;
+ }
+
+ slen = 0;
+ prim = sec = 0;
+ ss = s = __collate_substitute(src);
+ while (*s) {
+ while (*s && !prim) {
+ __collate_lookup(s, &l, &prim, &sec);
+ s += l;
+ }
+ if (prim) {
+ if (len > 1) {
+ *dest++ = (char)prim;
+ len--;
+ }
+ slen++;
+ prim = 0;
+ }
+ }
+ free(ss);
+ if (len > 0)
+ *dest = '\0';
+
+ return slen;
+}
diff --git a/lib/libc/string/swab.3 b/lib/libc/string/swab.3
new file mode 100644
index 0000000..05fdadd
--- /dev/null
+++ b/lib/libc/string/swab.3
@@ -0,0 +1,68 @@
+.\" 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. 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.
+.\"
+.\" @(#)swab.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd December 10, 2004
+.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.
+.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 0000000..8c0c43f
--- /dev/null
+++ b/lib/libc/string/swab.c
@@ -0,0 +1,63 @@
+/*
+ * 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. 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.
+ */
+
+#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;
+
+ 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/wcscat.c b/lib/libc/string/wcscat.c
new file mode 100644
index 0000000..1c96533
--- /dev/null
+++ b/lib/libc/string/wcscat.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: 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(s1, s2)
+ 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 0000000..1df1fe6
--- /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 0000000..7b9f702
--- /dev/null
+++ b/lib/libc/string/wcscmp.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. 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.
+ */
+
+#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(s1, s2)
+ const wchar_t *s1, *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 0000000..3270952
--- /dev/null
+++ b/lib/libc/string/wcscoll.3
@@ -0,0 +1,112 @@
+.\" 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. 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.
+.\"
+.\" @(#)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 0000000..dbfbcfa
--- /dev/null
+++ b/lib/libc/string/wcscoll.c
@@ -0,0 +1,98 @@
+/*-
+ * 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 <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include "collate.h"
+
+static char *__mbsdup(const wchar_t *);
+
+/*
+ * Placeholder implementation of wcscoll(). Attempts to use the single-byte
+ * collation ordering where possible, and falls back on wcscmp() in locales
+ * with extended character sets.
+ */
+int
+wcscoll(const wchar_t *ws1, const wchar_t *ws2)
+{
+ char *mbs1, *mbs2;
+ int diff, sverrno;
+
+ if (__collate_load_error || MB_CUR_MAX > 1)
+ /*
+ * Locale has no special collating order, could not be
+ * loaded, or has an extended character set; do a fast binary
+ * comparison.
+ */
+ return (wcscmp(ws1, ws2));
+
+ if ((mbs1 = __mbsdup(ws1)) == NULL || (mbs2 = __mbsdup(ws2)) == NULL) {
+ /*
+ * Out of memory or illegal wide chars; fall back to wcscmp()
+ * but leave errno indicating the error. Callers that don't
+ * check for error will get a reasonable but often slightly
+ * incorrect result.
+ */
+ sverrno = errno;
+ free(mbs1);
+ errno = sverrno;
+ return (wcscmp(ws1, ws2));
+ }
+
+ diff = strcoll(mbs1, mbs2);
+ sverrno = errno;
+ free(mbs1);
+ free(mbs2);
+ errno = sverrno;
+
+ return (diff);
+}
+
+static char *
+__mbsdup(const wchar_t *ws)
+{
+ static const mbstate_t initial;
+ mbstate_t st;
+ const wchar_t *wcp;
+ size_t len;
+ char *mbs;
+
+ wcp = ws;
+ st = initial;
+ if ((len = wcsrtombs(NULL, &wcp, 0, &st)) == (size_t)-1)
+ return (NULL);
+ if ((mbs = malloc(len + 1)) == NULL)
+ return (NULL);
+ st = initial;
+ wcsrtombs(mbs, &ws, len + 1, &st);
+
+ return (mbs);
+}
diff --git a/lib/libc/string/wcscpy.c b/lib/libc/string/wcscpy.c
new file mode 100644
index 0000000..180bbd1
--- /dev/null
+++ b/lib/libc/string/wcscpy.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: 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(s1, s2)
+ 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 0000000..57a804c
--- /dev/null
+++ b/lib/libc/string/wcscspn.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: 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(s, set)
+ 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 0000000..1e5db92
--- /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 0000000..6466f06
--- /dev/null
+++ b/lib/libc/string/wcslcat.c
@@ -0,0 +1,77 @@
+/*
+ * 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(dst, src, siz)
+ 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 (*d != '\0' && n-- != 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 0000000..1b9459a
--- /dev/null
+++ b/lib/libc/string/wcslcpy.c
@@ -0,0 +1,73 @@
+/*
+ * 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(dst, src, siz)
+ 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 0000000..1636d98
--- /dev/null
+++ b/lib/libc/string/wcslen.c
@@ -0,0 +1,50 @@
+/*-
+ * 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(s)
+ const wchar_t *s;
+{
+ const wchar_t *p;
+
+ p = s;
+ while (*p)
+ p++;
+
+ return p - s;
+}
diff --git a/lib/libc/string/wcsncat.c b/lib/libc/string/wcsncat.c
new file mode 100644
index 0000000..ba49a9e
--- /dev/null
+++ b/lib/libc/string/wcsncat.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: 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(s1, s2, n)
+ 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 (*r && n) {
+ *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 0000000..7544cc7
--- /dev/null
+++ b/lib/libc/string/wcsncmp.c
@@ -0,0 +1,63 @@
+/*
+ * 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. 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.
+ */
+
+#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(s1, s2, n)
+ const wchar_t *s1, *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 0000000..e9c9110
--- /dev/null
+++ b/lib/libc/string/wcsncpy.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. 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.
+ */
+
+#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/wcspbrk.c b/lib/libc/string/wcspbrk.c
new file mode 100644
index 0000000..7315c44
--- /dev/null
+++ b/lib/libc/string/wcspbrk.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: 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(s, set)
+ 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 0000000..37c81ec
--- /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 0000000..584a9d3
--- /dev/null
+++ b/lib/libc/string/wcsspn.c
@@ -0,0 +1,62 @@
+/*-
+ * 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(s, set)
+ 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 0000000..e391e9f
--- /dev/null
+++ b/lib/libc/string/wcsstr.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.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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.
+ */
+
+#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++) != 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 0000000..0de24d8
--- /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 0000000..0dbdfe0
--- /dev/null
+++ b/lib/libc/string/wcstok.c
@@ -0,0 +1,90 @@
+/*-
+ * 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. 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 the University nor the names of 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 0000000..76d32ad
--- /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 0000000..553e6d2
--- /dev/null
+++ b/lib/libc/string/wcswidth.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.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <wchar.h>
+
+int
+wcswidth(const wchar_t *pwcs, size_t n)
+{
+ wchar_t wc;
+ int len, l;
+
+ len = 0;
+ while (n-- > 0 && (wc = *pwcs++) != L'\0') {
+ if ((l = wcwidth(wc)) < 0)
+ return (-1);
+ len += l;
+ }
+ return (len);
+}
+
diff --git a/lib/libc/string/wcsxfrm.3 b/lib/libc/string/wcsxfrm.3
new file mode 100644
index 0000000..9e62647
--- /dev/null
+++ b/lib/libc/string/wcsxfrm.3
@@ -0,0 +1,126 @@
+.\" 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. 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.
+.\"
+.\" @(#)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 0000000..5e47ad9
--- /dev/null
+++ b/lib/libc/string/wcsxfrm.c
@@ -0,0 +1,116 @@
+/*-
+ * Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua>
+ * at Electronni Visti IA, Kiev, Ukraine.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list 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>
+#if 0
+__FBSDID("FreeBSD: src/lib/libc/string/strxfrm.c,v 1.15 2002/09/06 11:24:06 tjr Exp ");
+#endif
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include "collate.h"
+
+static char *__mbsdup(const wchar_t *);
+
+/*
+ * Placeholder wcsxfrm() implementation. See wcscoll.c for a description of
+ * the logic used.
+ */
+size_t
+wcsxfrm(wchar_t * __restrict dest, const wchar_t * __restrict src, size_t len)
+{
+ int prim, sec, l;
+ size_t slen;
+ char *mbsrc, *s, *ss;
+
+ if (*src == L'\0') {
+ if (len != 0)
+ *dest = L'\0';
+ return (0);
+ }
+
+ if (__collate_load_error || MB_CUR_MAX > 1) {
+ slen = wcslen(src);
+ if (len > 0) {
+ if (slen < len)
+ wcscpy(dest, src);
+ else {
+ wcsncpy(dest, src, len - 1);
+ dest[len - 1] = L'\0';
+ }
+ }
+ return (slen);
+ }
+
+ mbsrc = __mbsdup(src);
+ slen = 0;
+ prim = sec = 0;
+ ss = s = __collate_substitute(mbsrc);
+ while (*s != '\0') {
+ while (*s != '\0' && prim == 0) {
+ __collate_lookup(s, &l, &prim, &sec);
+ s += l;
+ }
+ if (prim != 0) {
+ if (len > 1) {
+ *dest++ = (wchar_t)prim;
+ len--;
+ }
+ slen++;
+ prim = 0;
+ }
+ }
+ free(ss);
+ free(mbsrc);
+ if (len != 0)
+ *dest = L'\0';
+
+ return (slen);
+}
+
+static char *
+__mbsdup(const wchar_t *ws)
+{
+ static const mbstate_t initial;
+ mbstate_t st;
+ const wchar_t *wcp;
+ size_t len;
+ char *mbs;
+
+ wcp = ws;
+ st = initial;
+ if ((len = wcsrtombs(NULL, &wcp, 0, &st)) == (size_t)-1)
+ return (NULL);
+ if ((mbs = malloc(len + 1)) == NULL)
+ return (NULL);
+ st = initial;
+ wcsrtombs(mbs, &ws, len + 1, &st);
+
+ return (mbs);
+}
diff --git a/lib/libc/string/wmemchr.3 b/lib/libc/string/wmemchr.3
new file mode 100644
index 0000000..a8b18cd
--- /dev/null
+++ b/lib/libc/string/wmemchr.3
@@ -0,0 +1,150 @@
+.\" $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. 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.
+.\"
+.\" from: @(#)strcpy.3 8.1 (Berkeley) 6/4/93
+.\"
+.\" $FreeBSD$
+.\"
+.Dd August 13, 2005
+.Dt WMEMCHR 3
+.Os
+.Sh NAME
+.Nm wmemchr ,
+.Nm wmemcmp ,
+.Nm wmemcpy ,
+.Nm wmemmove ,
+.Nm wmemset ,
+.Nm wcscat ,
+.Nm wcschr ,
+.Nm wcscmp ,
+.Nm wcscpy ,
+.Nm wcscspn ,
+.Nm wcsdup ,
+.Nm wcslcat ,
+.Nm wcslcpy ,
+.Nm wcslen ,
+.Nm wcsncat ,
+.Nm wcsncmp ,
+.Nm wcsncpy ,
+.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 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 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 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 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 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 wcsdup ,
+.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 0000000..2d96708
--- /dev/null
+++ b/lib/libc/string/wmemchr.c
@@ -0,0 +1,55 @@
+/*-
+ * 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(s, c, n)
+ 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 0000000..c9a9095
--- /dev/null
+++ b/lib/libc/string/wmemcmp.c
@@ -0,0 +1,56 @@
+/*-
+ * 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(s1, s2, n)
+ 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 0000000..38d563d
--- /dev/null
+++ b/lib/libc/string/wmemcpy.c
@@ -0,0 +1,48 @@
+/*-
+ * 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(d, s, n)
+ 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 0000000..6b3ee94
--- /dev/null
+++ b/lib/libc/string/wmemmove.c
@@ -0,0 +1,48 @@
+/*-
+ * 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(d, s, n)
+ 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 0000000..b923f14
--- /dev/null
+++ b/lib/libc/string/wmemset.c
@@ -0,0 +1,54 @@
+/*-
+ * 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(s, c, n)
+ 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 0000000..b101d78
--- /dev/null
+++ b/lib/libc/sys/Makefile.inc
@@ -0,0 +1,159 @@
+# @(#)Makefile.inc 8.3 (Berkeley) 10/24/94
+# $FreeBSD$
+
+# sys sources
+.PATH: ${.CURDIR}/${MACHINE_ARCH}/sys ${.CURDIR}/sys
+
+# Include the generated makefile containing the *complete* list
+# of syscall names in MIASM.
+.include "${.CURDIR}/../../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.
+#
+.if exists(${.CURDIR}/${MACHINE_ARCH}/sys/Makefile.inc)
+.include "${.CURDIR}/${MACHINE_ARCH}/sys/Makefile.inc"
+.endif
+
+# Sources common to both syscall interfaces:
+SRCS+= ftruncate.c lseek.c mmap.c pread.c pwrite.c truncate.c __error.c
+
+# 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
+
+OBJS+= ${ASM} ${PSEUDO}
+
+SASM= ${ASM:S/.o/.S/}
+
+SPSEUDO= ${PSEUDO:S/.o/.S/}
+
+SRCS+= ${SASM} ${SPSEUDO}
+
+SYM_MAPS+= ${.CURDIR}/sys/Symbol.map
+
+# Generated files
+CLEANFILES+= ${SASM} ${SPSEUDO}
+
+${SASM}:
+ printf '#include "SYS.h"\nRSYSCALL(${.PREFIX})\n' > ${.TARGET}
+
+${SPSEUDO}:
+ printf '#include "SYS.h"\nPSEUDO(${.PREFIX:S/_//})\n' \
+ > ${.TARGET}
+
+MAN+= _exit.2 abort2.2 accept.2 access.2 acct.2 adjtime.2 \
+ aio_cancel.2 aio_error.2 aio_read.2 aio_return.2 \
+ aio_suspend.2 aio_waitcomplete.2 aio_write.2 \
+ bind.2 brk.2 chdir.2 chflags.2 \
+ chmod.2 chown.2 chroot.2 clock_gettime.2 close.2 \
+ connect.2 dup.2 execve.2 extattr_get_file.2 \
+ fcntl.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 \
+ 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 kse.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 \
+ msync.2 munmap.2 nanosleep.2 ntp_adjtime.2 ntp_gettime.2 \
+ nfssvc.2 open.2 pathconf.2 pipe.2 poll.2 profil.2 ptrace.2 quotactl.2 \
+ read.2 readlink.2 reboot.2 recv.2 rename.2 revoke.2 rfork.2 rmdir.2 \
+ rtprio.2 select.2 semctl.2 semget.2 semop.2 send.2 sendfile.2 \
+ setgroups.2 setpgid.2 setregid.2 setresuid.2 setreuid.2 setsid.2 \
+ setuid.2 shmat.2 shmctl.2 shmget.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 \
+ timer_create.2 timer_delete.2 timer_settime.2 \
+ truncate.2 umask.2 undelete.2 \
+ unlink.2 utimes.2 utrace.2 uuidgen.2 vfork.2 wait.2 write.2
+.if !defined(NO_P1003_1B)
+MAN+= sched_get_priority_max.2 sched_setparam.2 \
+ sched_setscheduler.2 sched_yield.2
+.endif
+
+MLINKS+=access.2 eaccess.2
+MLINKS+=brk.2 sbrk.2
+MLINKS+=chdir.2 fchdir.2
+MLINKS+=chflags.2 fchflags.2 chflags.2 lchflags.2
+MLINKS+=chmod.2 fchmod.2 chmod.2 lchmod.2
+MLINKS+=chown.2 fchown.2 chown.2 lchown.2
+MLINKS+=clock_gettime.2 clock_getres.2 clock_gettime.2 clock_settime.2
+MLINKS+=dup.2 dup2.2
+MLINKS+=extattr_get_file.2 extattr_set_file.2 \
+ extattr_get_file.2 extattr_delete_file.2 \
+ extattr_get_file.2 extattr_get_fd.2 \
+ extattr_get_file.2 extattr_set_fd.2 \
+ extattr_get_file.2 extattr_delete_fd.2 \
+ extattr_get_file.2 extattr.2
+MLINKS+=fhopen.2 fhstat.2 fhopen.2 fhstatfs.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+=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
+MLINKS+=kqueue.2 kevent.2
+MLINKS+=kse.2 kse_create.2 kse.2 kse_exit.2 kse.2 kse_release.2 \
+ kse.2 kse_switchin.2 kse.2 kse_thr_interrupt.2 kse.2 kse_wakeup.2
+MLINKS+=madvise.2 posix_madvise.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_send.2 mq_timedsend.2
+MLINKS+=mq_receive.2 mq_timedreceive.2
+MLINKS+=pathconf.2 fpathconf.2
+MLINKS+=read.2 pread.2 read.2 readv.2 read.2 preadv.2
+MLINKS+=recv.2 recvfrom.2 recv.2 recvmsg.2
+MLINKS+=send.2 sendmsg.2 send.2 sendto.2
+MLINKS+=setpgid.2 setpgrp.2
+MLINKS+=setresuid.2 setresgid.2 setresuid.2 getresuid.2 setresuid.2 getresgid.2
+MLINKS+=setuid.2 setegid.2 setuid.2 seteuid.2 setuid.2 setgid.2
+MLINKS+=shmat.2 shmdt.2
+MLINKS+=sigwaitinfo.2 sigtimedwait.2
+MLINKS+=stat.2 fstat.2 stat.2 lstat.2
+MLINKS+=statfs.2 fstatfs.2
+MLINKS+=syscall.2 __syscall.2
+MLINKS+=swapon.2 swapoff.2
+MLINKS+=timer_settime.2 timer_gettime.2 timer_settime.2 timer_getoverrun.2
+MLINKS+=truncate.2 ftruncate.2
+MLINKS+=utimes.2 futimes.2 utimes.2 lutimes.2
+MLINKS+=wait.2 wait3.2 wait.2 wait4.2 wait.2 waitpid.2
+MLINKS+=write.2 pwrite.2 write.2 writev.2 write.2 pwritev.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
diff --git a/lib/libc/sys/Symbol.map b/lib/libc/sys/Symbol.map
new file mode 100644
index 0000000..7877aac
--- /dev/null
+++ b/lib/libc/sys/Symbol.map
@@ -0,0 +1,950 @@
+# $FreeBSD$
+#
+# It'd be nice to have this automatically generated, but we don't
+# know to what version they will eventually belong, 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;
+ __semctl;
+ __setugid;
+ __syscall;
+ __sysctl;
+ _umtx_lock;
+ _umtx_op;
+ _umtx_unlock;
+ abort2;
+ accept;
+ access;
+ acct;
+ adjtime;
+ aio_cancel;
+ aio_error;
+ 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 publc interfaces?
+ kmq_open; # librt uses them to provide mq_xxx.
+ kmq_setattr;
+ kmq_timedreceive;
+ kmq_timedsend;
+ kmq_unlink;
+ kse_create;
+ kse_exit;
+ kse_release;
+ kse_switchin;
+ kse_thr_interrupt;
+ kse_wakeup;
+ 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;
+ msgctl;
+ msgget;
+ msgrcv;
+ msgsnd;
+ msgsys;
+ msync;
+ munlock;
+ munlockall;
+ munmap;
+ nanosleep;
+ netbsd_lchown;
+ netbsd_msync;
+ nfsclnt;
+ nfssvc;
+ nfstat;
+ nlstat;
+ nmount;
+ nstat;
+ ntp_adjtime;
+ ntp_gettime;
+ oaio_read;
+ oaio_write;
+ olio_listio;
+ open;
+ pathconf;
+ pipe;
+ poll;
+ preadv;
+ profil;
+ ptrace;
+ pwritev;
+ quotactl;
+ read;
+ readlink;
+ readv;
+ reboot;
+ recvfrom;
+ recvmsg;
+ rename;
+ revoke;
+ rfork;
+ rmdir;
+ rtprio;
+ 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;
+ setcontext;
+ setegid;
+ seteuid;
+ setgid;
+ setgroups;
+ setitimer;
+ setlogin;
+ setpgid;
+ setpriority;
+ setregid;
+ setresgid;
+ setresuid;
+ setreuid;
+ setrlimit;
+ setsid;
+ setsockopt;
+ settimeofday;
+ setuid;
+ shmat;
+ shmctl;
+ shmdt;
+ shmget;
+ shmsys;
+ shutdown;
+ sigaction;
+ sigaltstack;
+ sigpending;
+ sigprocmask;
+ sigqueue;
+ sigreturn;
+ sigsuspend;
+ sigtimedwait;
+ sigwait;
+ sigwaitinfo;
+ socket;
+ socketpair;
+ stat;
+ statfs;
+ swapcontext;
+ swapoff;
+ swapon;
+ symlink;
+ sync;
+ sysarch;
+ syscall;
+ thr_create;
+ thr_exit;
+ thr_kill;
+ thr_new;
+ thr_self;
+ thr_set_name;
+ thr_suspend;
+ thr_wake;
+ ktimer_create; # Do we want these to be publc 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;
+};
+
+FBSDprivate {
+ ___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_lock;
+ __sys__umtx_lock;
+ __umtx_op;
+ __sys__umtx_op;
+ __umtx_unlock;
+ __sys__umtx_unlock;
+ _abort2;
+ __sys_abort2;
+ _accept;
+ __sys_accept;
+ _access;
+ __sys_access;
+ _acct;
+ __sys_acct;
+ _adjtime;
+ __sys_adjtime;
+ _aio_cancel;
+ __sys_aio_cancel;
+ _aio_error;
+ __sys_aio_error;
+ _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_getres;
+ __sys_clock_getres;
+ _clock_gettime;
+ __sys_clock_gettime;
+ _clock_settime;
+ __sys_clock_settime;
+ _close;
+ __sys_close;
+ _connect;
+ __sys_connect;
+ _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;
+ _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;
+ _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;
+ _kse_create;
+ __sys_kse_create;
+ _kse_exit;
+ __sys_kse_exit;
+ _kse_release;
+ __sys_kse_release;
+ _kse_switchin;
+ __sys_kse_switchin;
+ _kse_thr_interrupt;
+ __sys_kse_thr_interrupt;
+ _kse_wakeup;
+ __sys_kse_wakeup;
+ _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;
+ _nfsclnt;
+ __sys_nfsclnt;
+ _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;
+ _oaio_read;
+ __sys_oaio_read;
+ _oaio_write;
+ __sys_oaio_write;
+ _olio_listio;
+ __sys_olio_listio;
+ _open;
+ __sys_open;
+ _pathconf;
+ __sys_pathconf;
+ _pipe;
+ __sys_pipe;
+ _poll;
+ __sys_poll;
+ _preadv;
+ __sys_preadv;
+ _profil;
+ __sys_profil;
+ _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;
+ _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;
+ _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;
+ __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_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;
+ _write;
+ __sys_write;
+ _writev;
+ __sys_writev;
+ __error_unthreaded;
+};
diff --git a/lib/libc/sys/__error.c b/lib/libc/sys/__error.c
new file mode 100644
index 0000000..8dcf894
--- /dev/null
+++ b/lib/libc/sys/__error.c
@@ -0,0 +1,48 @@
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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$");
+
+extern int errno;
+
+/*
+ * Declare a weak reference in case the application is not linked
+ * with libpthread.
+ */
+__weak_reference(__error_unthreaded, __error);
+
+int *
+__error_unthreaded()
+{
+ return(&errno);
+}
diff --git a/lib/libc/sys/_exit.2 b/lib/libc/sys/_exit.2
new file mode 100644
index 0000000..1a43295
--- /dev/null
+++ b/lib/libc/sys/_exit.2
@@ -0,0 +1,127 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)_exit.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.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 1; the initialization process
+inherits each of these processes
+(see
+.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/abort2.2 b/lib/libc/sys/abort2.2
new file mode 100644
index 0000000..5f38080
--- /dev/null
+++ b/lib/libc/sys/abort2.2
@@ -0,0 +1,99 @@
+.\" 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 December 23, 2005
+.Dt ABORT2 3
+.Os
+.Sh NAME
+.Nm abort2
+.Nd abort process with diagnostics.
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft void
+.Fo abort2
+.Fa "char *why"
+.Fa "int argc"
+.Fa "void **args"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn abort2
+function causes the process to be killed and the specified diagnostic
+message (with arguments) is delivered by the kernel to the
+.Xr syslogd 8
+daemon.
+.Pp
+.Fa why
+is NULL-terminated string containing reason of program termination (max 128 char long).
+.Fa args
+contains pointers which will be logged numerically (kernels '%p'
+.Xr printf 9
+format).
+.Fa nargs
+is number of pointers in
+.Fa args ,
+(max 16).
+.Pp
+.Fn abort2
+is intended for use in situations where continuation of the process
+is impossible or for other definitive reasons unwanted, and normal
+diagnostic channels cannot be trusted to deliver the message.
+.Sh EXAMPLES
+.Bd -literal -compact
+#include <stdlib.h>
+
+if (weight_kg > max_load) {
+ void *ptrs[3];
+
+ ptrs[0] = (void*)weight_kg;
+ ptrs[1] = (void *)max_load;
+ ptrs[2] = haystack;
+ abort2("Camel overloaded", 3, ptrs);
+}
+.Ed
+.Sh RETURN VALUES
+The
+.Fn abort2
+function
+never returns.
+.Pp
+The process is killed sith SIGABRT unless the arguments to
+.Fn abort2
+are invalid, in which case SIGKILL is used.
+.Sh SEE ALSO
+.Xr exit 3 ,
+.Xr abort 3
+.Sh HISTORY
+The
+.Fn abort2
+function first appeared in
+.Fx 7.0 .
+.Sh AUTHORS
+Design:
+.An "Poul-Henning Kamp" Aq phk@FreeBSD.org .
+Implementation:
+.An "Wojciech A. Koszek" Aq dunstan@freebsd.czest.pl .
diff --git a/lib/libc/sys/accept.2 b/lib/libc/sys/accept.2
new file mode 100644
index 0000000..800d9a2
--- /dev/null
+++ b/lib/libc/sys/accept.2
@@ -0,0 +1,185 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)accept.2 8.2 (Berkeley) 12/11/93
+.\" $FreeBSD$
+.\"
+.Dd December 11, 1993
+.Dt ACCEPT 2
+.Os
+.Sh NAME
+.Nm accept
+.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"
+.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
+property from the original socket
+.Fa s .
+.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.
+.Sh RETURN VALUES
+The call returns \-1 on error.
+If it succeeds, it returns a non-negative
+integer that is a descriptor for the accepted socket.
+.Sh ERRORS
+The
+.Fn accept
+system call 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 EINVAL
+The
+.Fa addrlen
+argument is negative.
+.It Bq Er EFAULT
+The
+.Fa addr
+argument is not in a writable part of the
+user address space.
+.It Bq Er EWOULDBLOCK
+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
+.Sh SEE ALSO
+.Xr bind 2 ,
+.Xr connect 2 ,
+.Xr getpeername 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 .
diff --git a/lib/libc/sys/access.2 b/lib/libc/sys/access.2
new file mode 100644
index 0000000..94e7831
--- /dev/null
+++ b/lib/libc/sys/access.2
@@ -0,0 +1,160 @@
+.\" 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. 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.
+.\"
+.\" @(#)access.2 8.2 (Berkeley) 4/1/94
+.\" $FreeBSD$
+.\"
+.Dd September 21, 2001
+.Dt ACCESS 2
+.Os
+.Sh NAME
+.Nm access , eaccess
+.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"
+.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
+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
+Access to the file is denied 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 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
+.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.
+.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 .
+.Sh HISTORY
+The
+.Fn access
+function appeared in
+.At v7 .
diff --git a/lib/libc/sys/acct.2 b/lib/libc/sys/acct.2
new file mode 100644
index 0000000..4f371d3
--- /dev/null
+++ b/lib/libc/sys/acct.2
@@ -0,0 +1,135 @@
+.\" 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. 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.
+.\"
+.\" @(#)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 0000000..5794a32
--- /dev/null
+++ b/lib/libc/sys/adjtime.2
@@ -0,0 +1,115 @@
+.\" 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. 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.
+.\"
+.\" @(#)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 0000000..08102cf
--- /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 wes@softweyr.com .
+.An Christopher M Sedore Aq 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 0000000..91bb097
--- /dev/null
+++ b/lib/libc/sys/aio_error.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 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
+is returned.
+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 wes@softweyr.com .
diff --git a/lib/libc/sys/aio_read.2 b/lib/libc/sys/aio_read.2
new file mode 100644
index 0000000..2c78040
--- /dev/null
+++ b/lib/libc/sys/aio_read.2
@@ -0,0 +1,215 @@
+.\" 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 November 17, 1998
+.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.
+.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.
+For this reason, use of auto (stack) variables
+for these objects is discouraged.
+.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 after the request has been enqueued, but before the
+request has completed, are not allowed.
+.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 ENOSYS
+The
+.Fn aio_read
+system call is not supported.
+.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 .
+.Pp
+.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 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 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 0000000..4d7282f
--- /dev/null
+++ b/lib/libc/sys/aio_return.2
@@ -0,0 +1,104 @@
+.\" 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_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 int
+.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
+.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 .
+On failure,
+.Fn aio_return
+returns
+.Dv -1
+and sets
+.Dv 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 an outstanding 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 wes@softweyr.com .
diff --git a/lib/libc/sys/aio_suspend.2 b/lib/libc/sys/aio_suspend.2
new file mode 100644
index 0000000..db704f1
--- /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 wes@softweyr.com .
diff --git a/lib/libc/sys/aio_waitcomplete.2 b/lib/libc/sys/aio_waitcomplete.2
new file mode 100644
index 0000000..5145f78
--- /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 January 19, 2000
+.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 int
+.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 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 0000000..dd1e0f5
--- /dev/null
+++ b/lib/libc/sys/aio_write.2
@@ -0,0 +1,210 @@
+.\" 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_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.
+.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.
+For this reason, use of auto (stack) variables
+for these objects is discouraged.
+.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 after the request has been enqueued, but before the
+request has completed, are not allowed.
+.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 ENOSYS
+The
+.Fn aio_write
+system call is not supported.
+.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 .
+.Pp
+.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 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 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 0000000..9cad897
--- /dev/null
+++ b/lib/libc/sys/bind.2
@@ -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.
+.\" 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.
+.\"
+.\" @(#)bind.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.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/types.h
+.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 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 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/brk.2 b/lib/libc/sys/brk.2
new file mode 100644
index 0000000..ba97987
--- /dev/null
+++ b/lib/libc/sys/brk.2
@@ -0,0 +1,175 @@
+.\" 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. 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.
+.\"
+.\" @(#)brk.2 8.4 (Berkeley) 5/1/95
+.\" $FreeBSD$
+.\"
+.Dd July 12, 1999
+.Dt BRK 2
+.Os
+.Sh NAME
+.Nm brk ,
+.Nm sbrk
+.Nd change data segment size
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.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/chdir.2 b/lib/libc/sys/chdir.2
new file mode 100644
index 0000000..8e8214e
--- /dev/null
+++ b/lib/libc/sys/chdir.2
@@ -0,0 +1,136 @@
+.\" 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. 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.
+.\"
+.\" @(#)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 0000000..3897d38
--- /dev/null
+++ b/lib/libc/sys/chflags.2
@@ -0,0 +1,237 @@
+.\" 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. 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.
+.\"
+.\" @(#)chflags.2 8.3 (Berkeley) 5/2/95
+.\" $FreeBSD$
+.\"
+.Dd May 5, 2002
+.Dt CHFLAGS 2
+.Os
+.Sh NAME
+.Nm chflags ,
+.Nm lchflags ,
+.Nm fchflags
+.Nd set file flags
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/stat.h
+.In unistd.h
+.Ft int
+.Fn chflags "const char *path" "u_long flags"
+.Ft int
+.Fn lchflags "const char *path" "int flags"
+.Ft int
+.Fn fchflags "int fd" "u_long flags"
+.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 flags specified are formed by
+.Em or Ns 'ing
+the following values
+.Pp
+.Bl -tag -width "SF_IMMUTABLE" -compact -offset indent
+.It UF_NODUMP
+Do not dump the file.
+.It UF_IMMUTABLE
+The file may not be changed.
+.It UF_APPEND
+The file may only be appended to.
+.It UF_NOUNLINK
+The file may not be renamed or deleted.
+.It UF_OPAQUE
+The directory is opaque when viewed through a union stack.
+.It SF_ARCHIVED
+The file may be archived.
+.It SF_IMMUTABLE
+The file may not be changed.
+.It SF_APPEND
+The file may only be appended to.
+.It SF_NOUNLINK
+The file may not be renamed or deleted.
+.It SF_SNAPSHOT
+The file is a snapshot file.
+.El
+.Pp
+If one of
+.Dq SF_IMMUTABLE ,
+.Dq SF_APPEND ,
+or
+.Dq SF_NOUNLINK
+is set a non-super-user cannot change any flags and even the super-user
+can change flags only if securelevel is greater than 0.
+(See
+.Xr init 8
+for details.)
+.Pp
+The
+.Dq UF_IMMUTABLE ,
+.Dq UF_APPEND ,
+.Dq UF_NOUNLINK ,
+.Dq UF_NODUMP ,
+and
+.Dq UF_OPAQUE
+flags may be set or unset by either the owner of a file or the super-user.
+.Pp
+The
+.Dq SF_IMMUTABLE ,
+.Dq SF_APPEND ,
+.Dq SF_NOUNLINK ,
+and
+.Dq SF_ARCHIVED
+flags may only be set or unset by the super-user.
+Attempts to set these flags by non-super-users are rejected, attempts by
+non-superusers to clear flags that are already unset are silently ignored.
+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
+.Dq SF_SNAPSHOT
+flag is maintained by the system and cannot be changed by any user.
+.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
+.Dq SF_IMMUTABLE ,
+.Dq SF_APPEND ,
+or
+.Dq 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 tries to set one of
+.Dq SF_IMMUTABLE ,
+.Dq SF_APPEND ,
+or
+.Dq SF_NOUNLINK .
+.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.
+.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
+.Dq SF_IMMUTABLE ,
+.Dq SF_APPEND ,
+or
+.Dq 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 tries to set one of
+.Dq SF_IMMUTABLE ,
+.Dq SF_APPEND ,
+or
+.Dq SF_NOUNLINK .
+.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.
+.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 .
diff --git a/lib/libc/sys/chmod.2 b/lib/libc/sys/chmod.2
new file mode 100644
index 0000000..fc6a932
--- /dev/null
+++ b/lib/libc/sys/chmod.2
@@ -0,0 +1,237 @@
+.\" 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. 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.
+.\"
+.\" @(#)chmod.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd December 29, 2004
+.Dt CHMOD 2
+.Os
+.Sh NAME
+.Nm chmod ,
+.Nm fchmod ,
+.Nm lchmod
+.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"
+.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
+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 */
+#ifndef __BSD_VISIBLE
+#define S_ISTXT 0001000 /* sticky bit */
+#endif
+.Ed
+.Pp
+The
+.Fx
+VM system totally ignores the sticky bit
+.Pq Dv ISTXT
+for executables.
+On UFS-based file systems (FFS, LFS) the sticky
+bit may only be set upon directories.
+.Pp
+If mode
+.Dv ISTXT
+(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 8 .
+.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 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
+An attempt was made to set the sticky bit upon an executable.
+.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
+.Sh SEE ALSO
+.Xr chmod 1 ,
+.Xr chown 2 ,
+.Xr open 2 ,
+.Xr stat 2 ,
+.Xr sticky 8
+.Sh STANDARDS
+The
+.Fn chmod
+system call is expected to conform to
+.St -p1003.1-90 ,
+except for the return of
+.Er EFTYPE
+and the use of
+.Dv S_ISTXT .
+.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 .
diff --git a/lib/libc/sys/chown.2 b/lib/libc/sys/chown.2
new file mode 100644
index 0000000..555ee38
--- /dev/null
+++ b/lib/libc/sys/chown.2
@@ -0,0 +1,182 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)chown.2 8.4 (Berkeley) 4/19/94
+.\" $FreeBSD$
+.\"
+.Dd April 19, 1994
+.Dt CHOWN 2
+.Os
+.Sh NAME
+.Nm chown ,
+.Nm fchown ,
+.Nm lchown
+.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"
+.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
+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 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 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
+.Sh SEE ALSO
+.Xr chgrp 1 ,
+.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 .
+.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.
diff --git a/lib/libc/sys/chroot.2 b/lib/libc/sys/chroot.2
new file mode 100644
index 0000000..7142e0d
--- /dev/null
+++ b/lib/libc/sys/chroot.2
@@ -0,0 +1,146 @@
+.\" 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. 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.
+.\"
+.\" @(#)chroot.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.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
+.Pp
+Upon successful completion, a value of 0 is returned.
+Otherwise,
+a value of -1 is returned and
+.Va errno
+is set to indicate an error.
+.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 .
+.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.
diff --git a/lib/libc/sys/clock_gettime.2 b/lib/libc/sys/clock_gettime.2
new file mode 100644
index 0000000..15c7156
--- /dev/null
+++ b/lib/libc/sys/clock_gettime.2
@@ -0,0 +1,133 @@
+.\" $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.
+.\" 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd November 18, 2005
+.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 sys/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
+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 four values: CLOCK_REALTIME for time that increments as
+a wall clock should, CLOCK_MONOTONIC which increments in SI seconds,
+CLOCK_UPTIME which starts at zero when the kernel boots and increments
+monotonically in SI seconds while the machine is running,
+CLOCK_VIRTUAL for time that increments only when
+the CPU is running in user mode on behalf of the calling process, or
+CLOCK_PROF for time that increments when the CPU is running in user or
+kernel mode.
+.Pp
+The structure pointed to by
+.Fa tp
+is defined in
+.In sys/time.h
+as:
+.Pp
+.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.
+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
+argument
+was not a valid value.
+.It Bq Er EFAULT
+The
+.Fa *tp
+argument address referenced invalid memory.
+.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 .
diff --git a/lib/libc/sys/close.2 b/lib/libc/sys/close.2
new file mode 100644
index 0000000..04dbe3d
--- /dev/null
+++ b/lib/libc/sys/close.2
@@ -0,0 +1,140 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)close.2 8.2 (Berkeley) 4/19/94
+.\" $FreeBSD$
+.\"
+.Dd April 19, 1994
+.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 d"
+.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 d
+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.
+.El
+.Sh SEE ALSO
+.Xr accept 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/connect.2 b/lib/libc/sys/connect.2
new file mode 100644
index 0000000..5b74fbe
--- /dev/null
+++ b/lib/libc/sys/connect.2
@@ -0,0 +1,162 @@
+.\" 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. 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.
+.\"
+.\" @(#)connect.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt CONNECT 2
+.Os
+.Sh NAME
+.Nm connect
+.Nd initiate a connection on a socket
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.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.
+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 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 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.
+.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.
+.El
+.Sh SEE ALSO
+.Xr accept 2 ,
+.Xr getpeername 2 ,
+.Xr getsockname 2 ,
+.Xr select 2 ,
+.Xr socket 2
+.Sh HISTORY
+The
+.Fn connect
+system call appeared in
+.Bx 4.2 .
diff --git a/lib/libc/sys/dup.2 b/lib/libc/sys/dup.2
new file mode 100644
index 0000000..ef903f9
--- /dev/null
+++ b/lib/libc/sys/dup.2
@@ -0,0 +1,166 @@
+.\" 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. 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.
+.\"
+.\" @(#)dup.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.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 value must be less
+than the size of the table, which is returned by
+.Xr getdtablesize 2 .
+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
+The value -1 is returned if an error occurs in either call.
+The external variable
+.Va errno
+indicates the cause of the error.
+.Sh ERRORS
+The
+.Fn dup
+and
+.Fn dup2
+system calls fail if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa oldd
+or
+.Fa newd
+argument
+is not a valid active descriptor
+.It Bq Er EMFILE
+Too many descriptors are active.
+.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
+.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 0000000..45d4bae
--- /dev/null
+++ b/lib/libc/sys/execve.2
@@ -0,0 +1,310 @@
+.\" 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. 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.
+.\"
+.\" @(#)execve.2 8.5 (Berkeley) 6/1/94
+.\" $FreeBSD$
+.\"
+.Dd June 1, 1994
+.Dt EXECVE 2
+.Os
+.Sh NAME
+.Nm execve
+.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[]"
+.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 .
+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 sigvec 2 ,
+.Xr sigsetmask 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.
+.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 ENAMETOOLONG
+When invoking an interpreted script, the interpreter name
+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 or reading 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
+.Sh CAVEAT
+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.
+.Sh SEE ALSO
+.Xr ktrace 1 ,
+.Xr _exit 2 ,
+.Xr fork 2 ,
+.Xr execl 3 ,
+.Xr exit 3 ,
+.Xr sysctl 3 ,
+.Xr a.out 5 ,
+.Xr elf 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.
+.Sh HISTORY
+The
+.Fn execve
+system call appeared in
+.Bx 4.2 .
diff --git a/lib/libc/sys/extattr_get_file.2 b/lib/libc/sys/extattr_get_file.2
new file mode 100644
index 0000000..e55d94d
--- /dev/null
+++ b/lib/libc/sys/extattr_get_file.2
@@ -0,0 +1,270 @@
+.\"
+.\" 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 February 23, 2005
+.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
+.In sys/uio.h
+.Ft ssize_t
+.Fn extattr_get_fd "int fd" "int attrnamespace" "const char *attrname" "void *data" "size_t nbytes"
+.Ft int
+.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 int
+.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 int
+.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
+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 ,
+and
+.Fn extattr_delete_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
+and
+.Fn extattr_set_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
+returns 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 ,
+and
+.Fn extattr_delete_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 0000000..804b4ab
--- /dev/null
+++ b/lib/libc/sys/fcntl.2
@@ -0,0 +1,586 @@
+.\" 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. 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.
+.\"
+.\" @(#)fcntl.2 8.2 (Berkeley) 1/12/94
+.\" $FreeBSD$
+.\"
+.Dd January 12, 1994
+.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_GETOWNX
+.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 associated with the new file descriptor
+is set to remain open across
+.Xr execve 2
+system calls.
+.El
+.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.
+.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 */
+};
+.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
+field is only used with
+.Dv F_GETLK
+to return the process ID of the process holding a blocking lock.
+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
+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_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_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 execve 2 ,
+.Xr flock 2 ,
+.Xr getdtablesize 2 ,
+.Xr open 2 ,
+.Xr sigvec 2 ,
+.Xr lockf 3 ,
+.Xr tcgetpgrp 3 ,
+.Xr tcsetpgrp 3
+.Sh HISTORY
+The
+.Fn fcntl
+system call appeared in
+.Bx 4.2 .
diff --git a/lib/libc/sys/fhopen.2 b/lib/libc/sys/fhopen.2
new file mode 100644
index 0000000..2a609c1
--- /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 0000000..654f7df
--- /dev/null
+++ b/lib/libc/sys/flock.2
@@ -0,0 +1,174 @@
+.\" 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. 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.
+.\"
+.\" @(#)flock.2 8.2 (Berkeley) 12/11/93
+.\" $FreeBSD$
+.\"
+.Dd December 11, 1993
+.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.
+.El
+.Sh SEE ALSO
+.Xr close 2 ,
+.Xr dup 2 ,
+.Xr execve 2 ,
+.Xr fcntl 2 ,
+.Xr fork 2 ,
+.Xr open 2 ,
+.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 0000000..5dd6413
--- /dev/null
+++ b/lib/libc/sys/fork.2
@@ -0,0 +1,138 @@
+.\" 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. 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.
+.\"
+.\" @(#)fork.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt FORK 2
+.Os
+.Sh NAME
+.Nm fork
+.Nd create a new process
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.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.
+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 .
+.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 vfork 2 ,
+.Xr wait 2
+.Sh HISTORY
+The
+.Fn fork
+function appeared in
+.At v6 .
diff --git a/lib/libc/sys/fsync.2 b/lib/libc/sys/fsync.2
new file mode 100644
index 0000000..644f337
--- /dev/null
+++ b/lib/libc/sys/fsync.2
@@ -0,0 +1,91 @@
+.\" 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. 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.
+.\"
+.\" @(#)fsync.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt FSYNC 2
+.Os
+.Sh NAME
+.Nm fsync
+.Nd "synchronise changes to a file"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fn fsync "int fd"
+.Sh DESCRIPTION
+The
+.Fn fsync
+system call
+causes all modified data and attributes of
+.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 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.
+.Sh RETURN VALUES
+.Rv -std fsync
+.Sh ERRORS
+The
+.Fn fsync
+fails 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 .
diff --git a/lib/libc/sys/ftruncate.c b/lib/libc/sys/ftruncate.c
new file mode 100644
index 0000000..28acc58
--- /dev/null
+++ b/lib/libc/sys/ftruncate.c
@@ -0,0 +1,55 @@
+/*
+ * 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. 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)ftruncate.c 8.1 (Berkeley) 6/17/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+/*
+ * This function provides 64-bit offset padding that
+ * is not supplied by GCC 1.X but is supplied by GCC 2.X.
+ */
+int
+ftruncate(fd, length)
+ int fd;
+ off_t length;
+{
+
+ return(__syscall((quad_t)SYS_ftruncate, fd, 0, length));
+}
diff --git a/lib/libc/sys/getdirentries.2 b/lib/libc/sys/getdirentries.2
new file mode 100644
index 0000000..d739549
--- /dev/null
+++ b/lib/libc/sys/getdirentries.2
@@ -0,0 +1,189 @@
+.\" Copyright (c) 1989, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. 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.
+.\"
+.\" @(#)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
+u_int32_t d_fileno;
+u_int16_t d_reclen;
+u_int8_t d_type;
+u_int8_t d_namlen;
+char d_name[MAXNAMELEN + 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 MAXNAMELEN
+\&+ 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
+.Fn ( getdirentries
+only)
+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 0000000..b53571e
--- /dev/null
+++ b/lib/libc/sys/getdtablesize.2
@@ -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. 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.
+.\"
+.\" @(#)getdtablesize.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt GETDTABLESIZE 2
+.Os
+.Sh NAME
+.Nm getdtablesize
+.Nd get descriptor table size
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fn getdtablesize void
+.Sh DESCRIPTION
+Each process has a fixed size descriptor table,
+which is guaranteed to have at least 20 slots.
+The entries in
+the descriptor table are numbered with small integers starting at 0.
+The
+.Fn getdtablesize
+system call returns the size of this table.
+.Sh SEE ALSO
+.Xr close 2 ,
+.Xr dup 2 ,
+.Xr open 2 ,
+.Xr select 2
+.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 0000000..3896716
--- /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.
+.\" 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.
+.\"
+.\" @(#)getfh.2 8.1 (Berkeley) 6/9/93
+.\" $FreeBSD$
+.\"
+.Dd April 6, 2004
+.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 lgetfgh
+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 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 0000000..3100d93
--- /dev/null
+++ b/lib/libc/sys/getfsstat.2
@@ -0,0 +1,126 @@
+.\" Copyright (c) 1989, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. 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.
+.\"
+.\" @(#)getfsstat.2 8.3 (Berkeley) 5/25/95
+.\" $FreeBSD$
+.\"
+.Dd November 20, 2003
+.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 flags"
+.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 fsstat
+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 flags
+should be specified as
+.Dv MNT_WAIT .
+If
+.Fa flags
+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.
+.Sh RETURN VALUES
+Upon successful completion, the number of
+.Fa fsstat
+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 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 0000000..00c64ea
--- /dev/null
+++ b/lib/libc/sys/getgid.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.
+.\" 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.
+.\"
+.\" @(#)getgid.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt GETGID 2
+.Os
+.Sh NAME
+.Nm getgid ,
+.Nm getegid
+.Nd get group process identification
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.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 0000000..54b6959
--- /dev/null
+++ b/lib/libc/sys/getgroups.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.
+.\" 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.
+.\"
+.\" @(#)getgroups.2 8.2 (Berkeley) 4/16/94
+.\" $FreeBSD$
+.\"
+.Dd March 5, 1999
+.Dt GETGROUPS 2
+.Os
+.Sh NAME
+.Nm getgroups
+.Nd get group access list
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.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 .
+No more than
+.Dv NGROUPS_MAX
+will ever
+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 .
+.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
+.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 0000000..90f4977
--- /dev/null
+++ b/lib/libc/sys/getitimer.2
@@ -0,0 +1,184 @@
+.\" 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. 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.
+.\"
+.\" @(#)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 sigvec 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 0000000..cea8caf
--- /dev/null
+++ b/lib/libc/sys/getlogin.2
@@ -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.
+.\" 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.
+.\"
+.\" @(#)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/getpeername.2 b/lib/libc/sys/getpeername.2
new file mode 100644
index 0000000..a5d9bfe
--- /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.
+.\" 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.
+.\"
+.\" @(#)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 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 0000000..1daffd2
--- /dev/null
+++ b/lib/libc/sys/getpgrp.2
@@ -0,0 +1,146 @@
+.\" 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. 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.
+.\"
+.\" @(#)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 0000000..20e3319
--- /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.
+.\" 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.
+.\"
+.\" @(#)getpid.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt GETPID 2
+.Os
+.Sh NAME
+.Nm getpid ,
+.Nm getppid
+.Nd get parent or calling process identification
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.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 gethostid 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 0000000..6e7ab2a
--- /dev/null
+++ b/lib/libc/sys/getpriority.2
@@ -0,0 +1,154 @@
+.\" 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. 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.
+.\"
+.\" @(#)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
+.Bl -tag -width Er
+In addition to the errors indicated above,
+.Fn setpriority
+will fail if:
+.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 0000000..1e67083
--- /dev/null
+++ b/lib/libc/sys/getrlimit.2
@@ -0,0 +1,196 @@
+.\" 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. 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.
+.\"
+.\" @(#)getrlimit.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 13, 2004
+.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_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_RSS
+The maximum size (in bytes) to which a process's resident set size may
+grow.
+This imposes a limit on the amount of physical memory to be given to
+a process; if memory is tight, the system will prefer to take memory
+from processes that are exceeding their declared resident set size.
+.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.
+.El
+.Pp
+A resource limit is specified as a soft limit and a hard limit.
+When a
+soft limit is exceeded a process may receive a signal (for example, if
+the cpu time or file size is exceeded), but it will be allowed to
+continue execution until it reaches the hard limit (or modifies
+its resource limit).
+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 signal
+.Dv SIGXCPU
+is sent to the
+offending process.
+.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 sigaltstack 2 ,
+.Xr sigvec 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 0000000..512e6aa
--- /dev/null
+++ b/lib/libc/sys/getrusage.2
@@ -0,0 +1,184 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)getrusage.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.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"
+.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
+process, or all its terminated child processes.
+The
+.Fa who
+argument is either
+.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 .
+.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 0000000..8d31074
--- /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 0000000..b3de16f
--- /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.
+.\" 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.
+.\"
+.\" @(#)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 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 0000000..24610a3
--- /dev/null
+++ b/lib/libc/sys/getsockopt.2
@@ -0,0 +1,425 @@
+.\" 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. 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.
+.\"
+.\" @(#)getsockopt.2 8.4 (Berkeley) 5/2/95
+.\" $FreeBSD$
+.\"
+.Dd April 15, 2006
+.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.
+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 SIGPIPE for the socket"
+.It Dv SO_TYPE Ta "get the type of the socket (get only)"
+.It Dv SO_ERROR Ta "get and clear error on the socket (get only)"
+.El
+.Pp
+.Dv SO_DEBUG
+enables debugging in the underlying protocol modules.
+.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.
+.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.
+.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.
+.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.
+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.
+.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.
+.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.
+.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_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 SIGPIPE signal normally sent
+when writing to a connected socket where the other end has been
+closed returns with the error
+.Er EPIPE .
+.Pp
+Finally,
+.Dv SO_TYPE
+and
+.Dv SO_ERROR
+are options used only with
+.Fn getsockopt .
+.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_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.
+.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 socket 2 ,
+.Xr getprotoent 3 ,
+.Xr sysctl 3 ,
+.Xr protocols 5 ,
+.Xr sysctl 8 ,
+.Xr accept_filter 9
+.Sh HISTORY
+The
+.Fn getsockopt
+system call 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 0000000..f6db64c
--- /dev/null
+++ b/lib/libc/sys/gettimeofday.2
@@ -0,0 +1,139 @@
+.\" 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. 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.
+.\"
+.\" @(#)gettimeofday.2 8.2 (Berkeley) 5/26/95
+.\" $FreeBSD$
+.\"
+.Dd May 26, 1995
+.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:
+.Pp
+.Bd -literal
+struct timeval {
+#ifdef __alpha__
+ long tv_sec; /* seconds */
+#else
+ time_t tv_sec; /* seconds */
+#endif
+ 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 EFAULT
+An argument address referenced invalid memory.
+.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/getuid.2 b/lib/libc/sys/getuid.2
new file mode 100644
index 0000000..3e32fb0
--- /dev/null
+++ b/lib/libc/sys/getuid.2
@@ -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.
+.\" 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.
+.\"
+.\" @(#)getuid.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt GETUID 2
+.Os
+.Sh NAME
+.Nm getuid ,
+.Nm geteuid
+.Nd get user identification
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.In sys/types.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/intro.2 b/lib/libc/sys/intro.2
new file mode 100644
index 0000000..c9cb8b4
--- /dev/null
+++ b/lib/libc/sys/intro.2
@@ -0,0 +1,739 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)intro.2 8.5 (Berkeley) 2/27/95
+.\" $FreeBSD$
+.\"
+.Dd February 27, 1995
+.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).
+.Pp
+.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 file descriptors allowable on the system
+has been reached and a requests for an open cannot be satisfied
+until at least one has been closed.
+.It Er 24 EMFILE Em "Too many open files" .
+<As released, the limit on the number of
+open files per process is 64.>
+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.
+.Pp
+.It Er 49 EADDRNOTAVAIL Em "Cannot 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 "Cannot 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.
+.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 a system process,
+.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 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 0000000..e5a902f
--- /dev/null
+++ b/lib/libc/sys/ioctl.2
@@ -0,0 +1,137 @@
+.\" 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. 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.
+.\"
+.\" @(#)ioctl.2 8.2 (Berkeley) 12/11/93
+.\"
+.\" $FreeBSD$
+.\"
+.Dd December 11, 1993
+.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 d" "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 d
+must be an open file descriptor.
+.Pp
+The third argument to
+.Fn ioctl
+is traditionally named
+.Va "char *argp" .
+Most uses of
+.Fn ioctl
+in
+.Fx 3.0 ,
+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 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 d
+argument
+is not a valid descriptor.
+.It Bq Er ENOTTY
+The
+.Fa d
+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 d
+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 0000000..a9b234b
--- /dev/null
+++ b/lib/libc/sys/issetugid.2
@@ -0,0 +1,102 @@
+.\" $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.
+.\" 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.
+.\"
+.\" $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 0000000..5cba4bf
--- /dev/null
+++ b/lib/libc/sys/jail.2
@@ -0,0 +1,142 @@
+.\"
+.\" ----------------------------------------------------------------------------
+.\" "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
+.\" ----------------------------------------------------------------------------
+.\"
+.\" $FreeBSD$
+.\"
+.Dd April 8, 2003
+.Dt JAIL 2
+.Os
+.Sh NAME
+.Nm jail , jail_attach
+.Nd imprison current process and future descendants
+.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"
+.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 {
+ u_int32_t version;
+ char *path;
+ char *hostname;
+ u_int32_t ip_number;
+};
+.Ed
+.Pp
+.Dq Li version
+defines the version of the API in use.
+It should be set to zero at this time.
+.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 ip_number
+can be set to the IP number assigned to the prison.
+.Pp
+The
+.Fn jail_attach
+system call attaches the current process to an existing jail,
+identified by
+.Fa jid .
+.Sh RETURN VALUES
+If successful,
+.Fn jail
+returns a non-negative integer, termed the jail identifier (JID).
+It returns \-1 on failure, and sets
+.Va errno
+to indicate the error.
+.Pp
+.Rv -std jail_attach
+.Sh PRISON?
+Once a process has been put in a prison, it and its descendants cannot escape
+the prison.
+.Pp
+Inside the prison, the concept of
+.Dq superuser
+is very diluted.
+In general,
+it can be assumed that nothing can be mangled from inside a prison which
+does not exist entirely inside that prison.
+For instance the directory
+tree below
+.Dq Li path
+can be manipulated all the ways a root can normally do it, including
+.Dq Li "rm -rf /*"
+but new device special nodes cannot be created because they reference
+shared resources (the device drivers in the kernel).
+The effective
+.Dq securelevel
+for a process is the greater of the global
+.Dq securelevel
+or, if present, the per-jail
+.Dq securelevel .
+.Pp
+All IP activity will be forced to happen to/from the IP number specified,
+which should be an alias on one of the network interfaces.
+.Pp
+It is possible to identify a process as jailed by examining
+.Dq Li /proc/<pid>/status :
+it will show a field near the end of the line, either as
+a single hyphen for a process at large, or the hostname currently
+set for the prison for jailed processes.
+.Sh ERRORS
+The
+.Fn jail
+system call
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The version number of the argument is not correct.
+.El
+.Pp
+Further
+.Fn jail
+calls
+.Xr chroot 2
+internally, so it 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
+.Sh HISTORY
+The
+.Fn jail
+system call appeared in
+.Fx 4.0 .
+The
+.Fn jail_attach
+system call appeared in
+.Fx 5.1 .
+.Sh AUTHORS
+The jail feature was written by
+.An Poul-Henning Kamp
+for R&D Associates
+.Dq Li http://www.rndassociates.com/
+who contributed it to
+.Fx .
diff --git a/lib/libc/sys/kenv.2 b/lib/libc/sys/kenv.2
new file mode 100644
index 0000000..866c0d38
--- /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 davidc@FreeBSD.org .
+.Pp
+The
+.Fn kenv
+system call was written by
+.An Maxime Henrion Aq mux@FreeBSD.org .
diff --git a/lib/libc/sys/kill.2 b/lib/libc/sys/kill.2
new file mode 100644
index 0000000..5164066
--- /dev/null
+++ b/lib/libc/sys/kill.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.
+.\" 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.
+.\"
+.\" @(#)kill.2 8.3 (Berkeley) 4/19/94
+.\" $FreeBSD$
+.\"
+.Dd April 19, 1994
+.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 real or effective user ID of the receiving process must match
+that of the sending process or the user must have appropriate privileges
+(such as given by a set-user-ID program or the user is the super-user).
+A single exception is the signal SIGCONT, which may always be sent
+to any process with the same session ID as the caller.
+.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 can be found corresponding to that specified by
+.Fa pid .
+.It Bq Er ESRCH
+The process id was given as 0
+but the sending process does not have a process group.
+.It Bq Er EPERM
+The sending process is not the super-user and its effective
+user id does not match the effective user-id of the receiving process.
+When signaling a process group, this error is returned if any members
+of the group could not be signaled.
+.El
+.Sh SEE ALSO
+.Xr getpgrp 2 ,
+.Xr getpid 2 ,
+.Xr killpg 2 ,
+.Xr sigaction 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 0000000..a8892ed
--- /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 0000000..d9967cc
--- /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 0000000..d31cc08
--- /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 0000000..ff929c3
--- /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
+.Va fileid )
+or 0 if
+.Va fileid
+is the last file loaded.
+To get the fileid of the first kld file, pass
+.Va 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
+.Va 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 0000000..946417a
--- /dev/null
+++ b/lib/libc/sys/kldstat.2
@@ -0,0 +1,125 @@
+.\"
+.\" 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 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(linker_file_stat) */
+ char name[MAXPATHLEN];
+ int refs;
+ int id;
+ caddr_t address; /* load address */
+ size_t size; /* size in bytes */
+};
+.Ed
+.Pp
+.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 size of the file.
+.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 .
diff --git a/lib/libc/sys/kldsym.2 b/lib/libc/sys/kldsym.2
new file mode 100644
index 0000000..acd6fcd
--- /dev/null
+++ b/lib/libc/sys/kldsym.2
@@ -0,0 +1,122 @@
+.\" 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 July 26, 2001
+.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 command" "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 command
+implemented is
+.Dv KLDSYM_LOOKUP .
+.Pp
+The
+.Fa data
+argument is of the following structure:
+.Pp
+.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 command .
+.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 0000000..ef6282b
--- /dev/null
+++ b/lib/libc/sys/kldunload.2
@@ -0,0 +1,78 @@
+.\"
+.\" 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 KLDUNLOAD 2
+.Os
+.Sh NAME
+.Nm kldunload
+.Nd unload kld files
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/param.h
+.In sys/linker.h
+.Ft int
+.Fn kldunload "int fileid"
+.Sh DESCRIPTION
+The
+.Fn kldunload
+system call
+unloads a kld file from the kernel that was previously linked via
+.Xr kldload 2 .
+.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.
+.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 0000000..b597950
--- /dev/null
+++ b/lib/libc/sys/kqueue.2
@@ -0,0 +1,549 @@
+.\" 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 June 4, 2005
+.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 XXXfilter
+.It ident
+Value used to identify this event.
+The exact interpretation is determined by the attached filter,
+but often is a file descriptor.
+.It filter
+Identifies the kernel filter used to process this event.
+The pre-defined
+system filters are described below.
+.It flags
+Actions to perform on the event.
+.It fflags
+Filter-specific flags.
+.It data
+Filter-specific data value.
+.It udata
+Opaque user-defined value passed through the kernel unchanged.
+.El
+.Pp
+The
+.Va flags
+field can contain the following values:
+.Bl -tag -width XXXEV_ONESHOT
+.It 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 EV_ENABLE
+Permit
+.Fn kevent
+to return the event if it is triggered.
+.It EV_DISABLE
+Disable the event so
+.Fn kevent
+will not return it.
+The filter itself is not disabled.
+.It 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 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 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 EV_EOF
+Filters may set this flag to indicate filter-specific EOF condition.
+.It 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 EVFILT_SIGNAL
+.It 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.
+.Pp
+.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
+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 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.
+.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 EV_EOF in
+.Va flags .
+This may be cleared by passing in 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 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 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 EVFILT_READ case.
+.It 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_value
+containing the udata value, and
+.Va sigev_notify
+set to 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 aio_error.
+.It 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 XXNOTE_RENAME
+.It NOTE_DELETE
+The
+.Fn unlink
+system call
+was called on the file referenced by the descriptor.
+.It NOTE_WRITE
+A write occurred on the file referenced by the descriptor.
+.It NOTE_EXTEND
+The file referenced by the descriptor was extended.
+.It NOTE_ATTRIB
+The file referenced by the descriptor had its attributes changed.
+.It NOTE_LINK
+The link count on the file changed.
+.It NOTE_RENAME
+The file referenced by the descriptor was renamed.
+.It NOTE_REVOKE
+Access to the file was revoked via
+.Xr revoke 2
+or the underlying file system was unmounted.
+.El
+.Pp
+On return,
+.Va fflags
+contains the events which triggered the filter.
+.It 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 XXNOTE_TRACKERR
+.It NOTE_EXIT
+The process has exited.
+.It NOTE_FORK
+The process has called
+.Fn fork .
+.It NOTE_EXEC
+The process has executed a new process via
+.Xr execve 2
+or similar call.
+.It NOTE_TRACK
+Follow a process across
+.Fn fork
+calls.
+The parent process will return with NOTE_TRACK set in the
+.Va fflags
+field, while the child process will return with NOTE_CHILD set in
+.Va fflags
+and the parent PID in
+.Va data .
+.It NOTE_TRACKERR
+This flag is returned if the system was unable to attach an event to
+the child process, usually due to resource limitations.
+.El
+.Pp
+On return,
+.Va fflags
+contains the events which triggered the filter.
+.It 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 SIG_IGN.
+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 EV_CLEAR flag internally.
+.It EVFILT_TIMER
+Establishes an arbitrary timer identified by
+.Va ident .
+When adding a timer,
+.Va data
+specifies the timeout period in milliseconds.
+The timer will be periodic unless 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.
+.It Dv EVFILT_NETDEV
+Takes a descriptor to a network interface as the identifier, and the events to watch for in
+.Va fflags .
+It returns, when one or more of the requested events occur on the descriptor.
+The events to monitor are:
+.Bl -tag -width XXNOTE_LINKDOWN
+.It Dv NOTE_LINKUP
+The link is up.
+.It Dv NOTE_LINKDOWN
+The link is down.
+.It Dv NOTE_LINKINV
+The link state is invalid.
+.El
+.Pp
+On return,
+.Va fflags
+contains the events which triggered the filter.
+.El
+.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 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 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 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.
+.It Bq Er ESRCH
+The specified process to attach to does not exist.
+.El
+.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 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 jlemon@FreeBSD.org .
+.Sh BUGS
+It is currently not possible to watch a
+.Xr vnode 9
+that resides on anything but
+a UFS file system.
+.Pp
+The
+.Dv EVFILT_NETDEV
+filter is currently only implemented for devices that use the
+.Xr miibus 4
+driver for LINKUP and LINKDOWN operations.
+Therefore, it will not work with many non-ethernet devices.
+.Pp
+The
+.Fa timeout
+value is limited to 24 hours; longer timeouts will be silently
+reinterpreted as 24 hours.
diff --git a/lib/libc/sys/kse.2 b/lib/libc/sys/kse.2
new file mode 100644
index 0000000..d944670
--- /dev/null
+++ b/lib/libc/sys/kse.2
@@ -0,0 +1,703 @@
+.\" 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 July 12, 2004
+.Dt KSE 2
+.Os
+.Sh NAME
+.Nm kse
+.Nd "kernel support for user threads"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/kse.h
+.Ft int
+.Fn kse_create "struct kse_mailbox *mbx" "int newgroup"
+.Ft int
+.Fn kse_exit void
+.Ft int
+.Fn kse_release "struct timespec *timeout"
+.Ft int
+.Fn kse_switchin "struct kse_thr_mailbox *tmbx" "int flags"
+.Ft int
+.Fn kse_thr_interrupt "struct kse_thr_mailbox *tmbx" "int cmd" "long data"
+.Ft int
+.Fn kse_wakeup "struct kse_mailbox *mbx"
+.Sh DESCRIPTION
+These system calls implement kernel support for multi-threaded processes.
+.\"
+.Ss Overview
+.\"
+Traditionally, user threading has been implemented in one of two ways:
+either all threads are managed in user space and the kernel is unaware
+of any threading (also known as
+.Dq "N to 1" ) ,
+or else separate processes sharing
+a common memory space are created for each thread (also known as
+.Dq "N to N" ) .
+These approaches have advantages and disadvantages:
+.Bl -column "- Cannot utilize multiple CPUs" "+ Can utilize multiple CPUs"
+.It Sy "User threading Kernel threading"
+.It "+ Lightweight - Heavyweight"
+.It "+ User controls scheduling - Kernel controls scheduling"
+.It "- Syscalls must be wrapped + No syscall wrapping required"
+.It "- Cannot utilize multiple CPUs + Can utilize multiple CPUs"
+.El
+.Pp
+The KSE system is a
+hybrid approach that achieves the advantages of both the user and kernel
+threading approaches.
+The underlying philosophy of the KSE system is to give kernel support
+for user threading without taking away any of the user threading library's
+ability to make scheduling decisions.
+A kernel-to-user upcall mechanism is used to pass control to the user
+threading library whenever a scheduling decision needs to be made.
+An arbitrarily number of user threads are multiplexed onto a fixed number of
+virtual CPUs supplied by the kernel.
+This can be thought of as an
+.Dq "N to M"
+threading scheme.
+.Pp
+Some general implications of this approach include:
+.Bl -bullet
+.It
+The user process can run multiple threads simultaneously on multi-processor
+machines.
+The kernel grants the process virtual CPUs to schedule as it
+wishes; these may run concurrently on real CPUs.
+.It
+All operations that block in the kernel become asynchronous, allowing
+the user process to schedule another thread when any thread blocks.
+.It
+Multiple thread schedulers within the same process are possible, and they
+may operate independently of each other.
+.El
+.\"
+.Ss Definitions
+.\"
+KSE allows a user process to have multiple
+.Sy threads
+of execution in existence at the same time, some of which may be blocked
+in the kernel while others may be executing or blocked in user space.
+A
+.Sy "kernel scheduling entity"
+(KSE) is a
+.Dq "virtual CPU"
+granted to the process for the purpose of executing threads.
+A thread that is currently executing is always associated with
+exactly one KSE, whether executing in user space or in the kernel.
+The KSE is said to be
+.Sy assigned
+to the thread.
+.Pp
+The KSE becomes
+.Sy unassigned ,
+and the associated thread is suspended, when the KSE has an associated
+.Sy mailbox ,
+(see below) the thread has an associated
+.Sy thread mailbox ,
+(also see below) and any of the following occurs:
+.Bl -bullet
+.It
+The thread invokes a system call that blocks.
+.It
+The thread makes any other demand of the kernel that cannot be immediately
+satisfied, e.g., touches a page of memory that needs to be fetched from disk,
+causing a page fault.
+.It
+Another thread that was previously blocked in the kernel completes its
+work in the kernel (or is
+.Sy interrupted )
+and becomes ready to return to user space, and the current thread is returning
+to user space.
+.It
+A signal is delivered to the process, and this KSE is chosen to deliver it.
+.El
+.Pp
+In other words, as soon as there is a scheduling decision to be made,
+the KSE becomes unassigned, because the kernel does not presume to know
+how the process' other runnable threads should be scheduled.
+Unassigned KSEs always return to user space as soon as possible via
+the
+.Sy upcall
+mechanism (described below), allowing the user process to decide how
+that KSE should be utilized next.
+KSEs always complete as much work as possible in the kernel before
+becoming unassigned.
+.Pp
+A
+.Sy "KSE group"
+is a collection of KSEs that are scheduled uniformly and which share
+access to the same pool of threads, which are associated with the KSE group.
+A KSE group is the smallest entity to which a kernel scheduling
+priority may be assigned.
+For the purposes of process scheduling and accounting, each
+KSE group
+counts similarly to a traditional unthreaded process.
+Individual KSEs within a KSE group are effectively indistinguishable,
+and any KSE in a KSE group may be assigned by the kernel to any runnable
+(in the kernel) thread associated with that KSE group.
+In practice, the kernel attempts to preserve the affinity between threads
+and actual CPUs to optimize cache behavior, but this is invisible to the
+user process.
+(Affinity is not yet implemented.)
+.Pp
+Each KSE has a unique
+.Sy "KSE mailbox"
+supplied by the user process.
+A mailbox consists of a control structure containing a pointer to an
+.Sy "upcall function"
+and a user stack.
+The KSE invokes this function whenever it becomes unassigned.
+The kernel updates this structure with information about threads that have
+become runnable and signals that have been delivered before each upcall.
+Upcalls may be temporarily blocked by the user thread scheduling code
+during critical sections.
+.Pp
+Each user thread has a unique
+.Sy "thread mailbox"
+as well.
+Threads are referred to using pointers to these mailboxes when communicating
+between the kernel and the user thread scheduler.
+Each KSE's mailbox contains a pointer to the mailbox of the user thread
+that the KSE is currently executing.
+This pointer is saved when the thread blocks in the kernel.
+.Pp
+Whenever a thread blocked in the kernel is ready to return to user space,
+it is added to the KSE group's list of
+.Sy completed
+threads.
+This list is presented to the user code at the next upcall as a linked list
+of thread mailboxes.
+.Pp
+There is a kernel-imposed limit on the number of threads in a KSE group
+that may be simultaneously blocked in the kernel (this number is not
+currently visible to the user).
+When this limit is reached, upcalls are blocked and no work is performed
+for the KSE group until one of the threads completes (or a signal is
+received).
+.\"
+.Ss Managing KSEs
+.\"
+To become multi-threaded, a process must first invoke
+.Fn kse_create .
+The
+.Fn kse_create
+system call
+creates a new KSE (except for the very first invocation; see below).
+The KSE will be associated with the mailbox pointed to by
+.Fa mbx .
+If
+.Fa newgroup
+is non-zero, a new KSE group is also created containing the KSE.
+Otherwise, the new KSE is added to the current KSE group.
+Newly created KSEs are initially unassigned; therefore,
+they will upcall immediately.
+.Pp
+Each process initially has a single KSE in a single KSE group executing
+a single user thread.
+Since the KSE does not have an associated mailbox, it must remain assigned
+to the thread and does not perform any upcalls.
+The result is the traditional, unthreaded mode of operation.
+Therefore, as a special case, the first call to
+.Fn kse_create
+by this initial thread with
+.Fa newgroup
+equal to zero does not create a new KSE; instead, it simply associates the
+current KSE with the supplied KSE mailbox, and no immediate upcall results.
+However, an upcall will be triggered the next time the thread blocks and
+the required conditions are met.
+.Pp
+The kernel does not allow more KSEs to exist in a KSE group than the
+number of physical CPUs in the system (this number is available as the
+.Xr sysctl 3
+variable
+.Va hw.ncpu ) .
+Having more KSEs than CPUs would not add any value to the user process,
+as the additional KSEs would just compete with each other for access to
+the real CPUs.
+Since the extra KSEs would always be side-lined, the result
+to the application would be exactly the same as having fewer KSEs.
+There may however be arbitrarily many user threads, and it is up to the
+user thread scheduler to handle mapping the application's user threads
+onto the available KSEs.
+.Pp
+The
+.Fn kse_exit
+system call
+causes the KSE assigned to the currently running thread to be destroyed.
+If this KSE is the last one in the KSE group, there must be no remaining
+threads associated with the KSE group blocked in the kernel.
+This system call does not return unless there is an error.
+.Pp
+As a special case, if the last remaining KSE in the last remaining KSE group
+invokes this system call, then the KSE is not destroyed;
+instead, the KSE just looses the association with its mailbox and
+.Fn kse_exit
+returns normally.
+This returns the process to its original, unthreaded state.
+.Pp
+The
+.Fn kse_release
+system call
+is used to
+.Dq park
+the KSE assigned to the currently running thread when it is not needed,
+e.g., when there are more available KSEs than runnable user threads.
+The thread converts to an upcall but does not get scheduled until
+there is a new reason to do so, e.g., a previously
+blocked thread becomes runnable, or the timeout expires.
+If successful,
+.Fn kse_release
+does not return to the caller.
+.Pp
+The
+.Fn kse_switchin
+system call can be used by the UTS, when it has selected a new thread,
+to switch to the context of that thread.
+The use of
+.Fn kse_switchin
+is machine dependent.
+Some platforms do not need a system call to switch to a new context,
+while others require its use in particular cases.
+.Pp
+The
+.Fn kse_wakeup
+system call
+is the opposite of
+.Fn kse_release .
+It causes the (parked) KSE associated with the mailbox pointed to by
+.Fa mbx
+to be woken up, causing it to upcall.
+If the KSE has already woken up for another reason, this system call has no
+effect.
+The
+.Fa mbx
+argument
+may be
+.Dv NULL
+to specify
+.Dq "any KSE in the current KSE group" .
+.Pp
+The
+.Fn kse_thr_interrupt
+system call
+is used to interrupt a currently blocked thread.
+The thread must either be blocked in the kernel or assigned to a KSE
+(i.e., executing).
+The thread is then marked as interrupted.
+As soon as the thread invokes an interruptible system call (or immediately
+for threads already blocked in one), the thread will be made runnable again,
+even though the kernel operation may not have completed.
+The effect on the interrupted system call is the same as if it had been
+interrupted by a signal; typically this means an error is returned with
+.Va errno
+set to
+.Er EINTR .
+.\"
+.Ss Signals
+.\"
+The current implementation creates a special signal thread.
+Kernel threads (KSEs) in a process mask all signals, and only the signal
+thread waits for signals to be delivered to the process, the signal thread
+is responsible
+for dispatching signals to user threads.
+.Pp
+A downside of this is that if a multiplexed thread
+calls the
+.Fn execve
+syscall, its signal mask and pending signals may not be
+available in the kernel.
+They are stored
+in userland and the kernel does not know where to get them, however
+.Tn POSIX
+requires them to be restored and passed them to new process.
+Just setting the mask for the thread before calling
+.Fn execve
+is only a
+close approximation to the problem as it does not re-deliver back to the kernel
+any pending signals that the old process may have blocked, and it allows a
+window in which new signals may be delivered to the process between the setting
+of the mask and the
+.Fn execve .
+.Pp
+For now this problem has been solved by adding a special combined
+.Fn kse_thr_interrupt Ns / Ns Fn execve
+mode to the
+.Fn kse_thr_interrupt
+syscall.
+The
+.Fn kse_thr_interrupt
+syscall has a sub command
+.Dv KSE_INTR_EXECVE ,
+that allows it to accept a
+.Vt kse_execv_args
+structure, and allowing it to adjust the signals and then atomically
+convert into an
+.Fn execve
+call.
+Additional pending signals and the correct signal mask can be passed
+to the kernel in this way.
+The thread library overrides the
+.Fn execve
+syscall
+and translates it into
+.Fn kse_intr_interrupt
+call, allowing a multiplexed thread
+to restore pending signals and the correct signal mask before doing the
+.Fn exec .
+This solution to the problem may change.
+.\"
+.Ss KSE Mailboxes
+.\"
+Each KSE has a unique mailbox for user-kernel communication defined in
+.In sys/kse.h .
+Some of the fields there are:
+.Pp
+.Va km_version
+describes the version of this structure and must be equal to
+.Dv KSE_VER_0 .
+.Va km_udata
+is an opaque pointer ignored by the kernel.
+.Pp
+.Va km_func
+points to the KSE's upcall function;
+it will be invoked using
+.Va km_stack ,
+which must remain valid for the lifetime of the KSE.
+.Pp
+.Va km_curthread
+always points to the thread that is currently assigned to this KSE if any,
+or
+.Dv NULL
+otherwise.
+This field is modified by both the kernel and the user process as follows.
+.Pp
+When
+.Va km_curthread
+is not
+.Dv NULL ,
+it is assumed to be pointing at the mailbox for the currently executing
+thread, and the KSE may be unassigned, e.g., if the thread blocks in the
+kernel.
+The kernel will then save the contents of
+.Va km_curthread
+with the blocked thread, set
+.Va km_curthread
+to
+.Dv NULL ,
+and upcall to invoke
+.Fn km_func .
+.Pp
+When
+.Va km_curthread
+is
+.Dv NULL ,
+the kernel will never perform any upcalls with this KSE; in other words,
+the KSE remains assigned to the thread even if it blocks.
+.Va km_curthread
+must be
+.Dv NULL
+while the KSE is executing critical user thread scheduler
+code that would be disrupted by an intervening upcall;
+in particular, while
+.Fn km_func
+itself is executing.
+.Pp
+Before invoking
+.Fn km_func
+in any upcall, the kernel always sets
+.Va km_curthread
+to
+.Dv NULL .
+Once the user thread scheduler has chosen a new thread to run,
+it should point
+.Va km_curthread
+at the thread's mailbox, re-enabling upcalls, and then resume the thread.
+.Em Note :
+modification of
+.Va km_curthread
+by the user thread scheduler must be atomic
+with the loading of the context of the new thread, to avoid
+the situation where the thread context area
+may be modified by a blocking async operation, while there
+is still valid information to be read out of it.
+.Pp
+.Va km_completed
+points to a linked list of user threads that have completed their work
+in the kernel since the last upcall.
+The user thread scheduler should put these threads back into its
+own runnable queue.
+Each thread in a KSE group that completes a kernel operation
+(synchronous or asynchronous) that results in an upcall is guaranteed to be
+linked into exactly one KSE's
+.Va km_completed
+list; which KSE in the group, however, is indeterminate.
+Furthermore, the completion will be reported in only one upcall.
+.Pp
+.Va km_sigscaught
+contains the list of signals caught by this process since the previous
+upcall to any KSE in the process.
+As long as there exists one or more KSEs with an associated mailbox in
+the user process, signals are delivered this way rather than the
+traditional way.
+(This has not been implemented and may change.)
+.Pp
+.Va km_timeofday
+is set by the kernel to the current system time before performing
+each upcall.
+.Pp
+.Va km_flags
+may contain any of the following bits OR'ed together:
+.Bl -tag -width indent
+.It Dv KMF_NOUPCALL
+Block upcalls from happening.
+The thread is in some critical section.
+.It Dv KMF_NOCOMPLETED , KMF_DONE , KMF_BOUND
+This thread should be considered to be permanently bound to
+its KSE, and treated much like a non-threaded process would be.
+It is a
+.Dq "long term"
+version of
+.Dv KMF_NOUPCALL
+in some ways.
+.It Dv KMF_WAITSIGEVENT
+Implement characteristics needed for the signal delivery thread.
+.El
+.\"
+.Ss Thread Mailboxes
+.\"
+Each user thread must have associated with it a unique
+.Vt "struct kse_thr_mailbox"
+as defined in
+.In sys/kse.h .
+It includes the following fields.
+.Pp
+.Va tm_udata
+is an opaque pointer ignored by the kernel.
+.Pp
+.Va tm_context
+stores the context for the thread when the thread is blocked in user space.
+This field is also updated by the kernel before a completed thread is returned
+to the user thread scheduler via
+.Va km_completed .
+.Pp
+.Va tm_next
+links the
+.Va km_completed
+threads together when returned by the kernel with an upcall.
+The end of the list is marked with a
+.Dv NULL
+pointer.
+.Pp
+.Va tm_uticks
+and
+.Va tm_sticks
+are time counters for user mode and kernel mode execution, respectively.
+These counters count ticks of the statistics clock (see
+.Xr clocks 7 ) .
+While any thread is actively executing in the kernel, the corresponding
+.Va tm_sticks
+counter is incremented.
+While any KSE is executing in user space and that KSE's
+.Va km_curthread
+pointer is not equal to
+.Dv NULL ,
+the corresponding
+.Va tm_uticks
+counter is incremented.
+.Pp
+.Va tm_flags
+may contain any of the following bits OR'ed together:
+.Bl -tag -width indent
+.It Dv TMF_NOUPCALL
+Similar to
+.Dv KMF_NOUPCALL .
+This flag inhibits upcalling for critical sections.
+Some architectures require this to be in one place and some in the other.
+.El
+.Sh RETURN VALUES
+The
+.Fn kse_create ,
+.Fn kse_wakeup ,
+and
+.Fn kse_thr_interrupt
+system calls
+return zero if successful.
+The
+.Fn kse_exit
+and
+.Fn kse_release
+system calls
+do not return if successful.
+.Pp
+All of these system calls return a non-zero error code in case of an error.
+.Sh ERRORS
+The
+.Fn kse_create
+system call
+will fail if:
+.Bl -tag -width Er
+.It Bq Er ENXIO
+There are already as many KSEs in the KSE group as hardware processors.
+.It Bq Er EAGAIN
+The system-imposed limit on the total number of KSE groups 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 KSE groups 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 EFAULT
+The
+.Fa mbx
+argument
+points to an address which is not a valid part of the process address space.
+.El
+.Pp
+The
+.Fn kse_exit
+system call
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EDEADLK
+The current KSE is the last in its KSE group and there are still one or more
+threads associated with the KSE group blocked in the kernel.
+.It Bq Er ESRCH
+The current KSE has no associated mailbox, i.e., the process is operating
+in traditional, unthreaded mode (in this case use
+.Xr _exit 2
+to exit the process).
+.El
+.Pp
+The
+.Fn kse_release
+system call
+will fail if:
+.Bl -tag -width Er
+.It Bq Er ESRCH
+The current KSE has no associated mailbox, i.e., the process is operating is
+traditional, unthreaded mode.
+.El
+.Pp
+The
+.Fn kse_wakeup
+system call
+will fail if:
+.Bl -tag -width Er
+.It Bq Er ESRCH
+The
+.Fa mbx
+argument
+is not
+.Dv NULL
+and the mailbox pointed to by
+.Fa mbx
+is not associated with any KSE in the process.
+.It Bq Er ESRCH
+The
+.Fa mbx
+argument
+is
+.Dv NULL
+and the current KSE has no associated mailbox, i.e., the process is operating
+in traditional, unthreaded mode.
+.El
+.Pp
+The
+.Fn kse_thr_interrupt
+system call
+will fail if:
+.Bl -tag -width Er
+.It Bq Er ESRCH
+The thread corresponding to
+.Fa tmbx
+is neither currently assigned to any KSE in the process nor blocked in the
+kernel.
+.El
+.Sh SEE ALSO
+.Xr rfork 2 ,
+.Xr pthread 3 ,
+.Xr ucontext 3
+.Rs
+.%A "Thomas E. Anderson"
+.%A "Brian N. Bershad"
+.%A "Edward D. Lazowska"
+.%A "Henry M. Levy"
+.%J "ACM Transactions on Computer Systems"
+.%N Issue 1
+.%V Volume 10
+.%D February 1992
+.%I ACM Press
+.%P pp. 53-79
+.%T "Scheduler activations: effective kernel support for the user-level management of parallelism"
+.Re
+.Sh HISTORY
+The KSE system calls first appeared in
+.Fx 5.0 .
+.Sh AUTHORS
+KSE was originally implemented by
+.An -nosplit
+.An "Julian Elischer" Aq julian@FreeBSD.org ,
+with additional contributions by
+.An "Jonathan Mini" Aq mini@FreeBSD.org ,
+.An "Daniel Eischen" Aq deischen@FreeBSD.org ,
+and
+.An "David Xu" Aq davidxu@FreeBSD.org .
+.Pp
+This manual page was written by
+.An "Archie Cobbs" Aq archie@FreeBSD.org .
+.Sh BUGS
+The KSE code is
+.Ud .
diff --git a/lib/libc/sys/ktrace.2 b/lib/libc/sys/ktrace.2
new file mode 100644
index 0000000..de0a3f2
--- /dev/null
+++ b/lib/libc/sys/ktrace.2
@@ -0,0 +1,200 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)ktrace.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.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 Enable trace points specified in"
+.Fa trpoints .
+.It "KTROP_CLEAR Disable trace points specified in
+.Fa trpoints .
+.It "KTROP_CLEARFILE Stop all tracing."
+.It "KTRFLAG_DESCEND 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_SYSCALLXXX -offset indent
+.It "KTRFAC_SYSCALL Trace system calls."
+.It "KTRFAC_SYSRET Trace return values from system calls."
+.It "KTRFAC_NAMEI Trace name lookup operations."
+.It "KTRFAC_GENIO Trace all I/O (note that this option can"
+generate much output).
+.It "KTRFAC_PSIG Trace posted signals."
+.It "KTRFAC_CSW Trace context switch points."
+.It "KTRFAC_INHERIT 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 */
+ caddr_t ktr_buf;
+};
+.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_buf
+is an internal kernel pointer and is not useful.
+.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 0000000..f39768a
--- /dev/null
+++ b/lib/libc/sys/link.2
@@ -0,0 +1,175 @@
+.\" 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. 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.
+.\"
+.\" @(#)link.2 8.3 (Berkeley) 1/12/94
+.\" $FreeBSD$
+.\"
+.Dd March 5, 1999
+.Dt LINK 2
+.Os
+.Sh NAME
+.Nm link
+.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"
+.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.
+.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 or is flagged immutable or append-only
+(see
+.Xr chflags 2 ) .
+.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
+.Sh SEE ALSO
+.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 .
+.Sh HISTORY
+The
+.Fn link
+function appeared in
+.At v7 .
+.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 0000000..a584b08
--- /dev/null
+++ b/lib/libc/sys/lio_listio.2
@@ -0,0 +1,175 @@
+.\" 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 12, 2003
+.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 ,
+the requests are processed asynchronously, and the signal specified by
+.Fa sig
+is sent when all operations have completed.
+If
+.Fa sig
+is
+.Dv NULL ,
+the calling process is not notified of I/O completion.
+.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 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 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 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 0000000..4c32497
--- /dev/null
+++ b/lib/libc/sys/listen.2
@@ -0,0 +1,174 @@
+.\" 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. 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.
+.\"
+.\" From: @(#)listen.2 8.2 (Berkeley) 12/11/93
+.\" $FreeBSD$
+.\"
+.Dd August 29, 2005
+.Dt LISTEN 2
+.Os
+.Sh NAME
+.Nm listen
+.Nd listen for connections on a socket
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.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
+.Dq Va kern.ipc.somaxconn
+specifies a hard limit on
+.Fa backlog ;
+if a value greater than
+.Va kern.ipc.somaxconn
+or less than zero is specified,
+.Fa backlog
+is silently forced to
+.Va kern.ipc.somaxconn .
+.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 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 .
diff --git a/lib/libc/sys/lseek.2 b/lib/libc/sys/lseek.2
new file mode 100644
index 0000000..e770142
--- /dev/null
+++ b/lib/libc/sys/lseek.2
@@ -0,0 +1,161 @@
+.\" 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. 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.
+.\"
+.\" @(#)lseek.2 8.3 (Berkeley) 4/19/94
+.\" $FreeBSD$
+.\"
+.Dd April 19, 1994
+.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.
+.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.
+.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 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
+.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/lseek.c b/lib/libc/sys/lseek.c
new file mode 100644
index 0000000..3544fbf
--- /dev/null
+++ b/lib/libc/sys/lseek.c
@@ -0,0 +1,55 @@
+/*
+ * 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. 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)lseek.c 8.1 (Berkeley) 6/17/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+/*
+ * This function provides 64-bit offset padding that
+ * is not supplied by GCC 1.X but is supplied by GCC 2.X.
+ */
+off_t
+lseek(fd, offset, whence)
+ int fd;
+ off_t offset;
+ int whence;
+{
+ return(__syscall((quad_t)SYS_lseek, fd, 0, offset, whence));
+}
diff --git a/lib/libc/sys/madvise.2 b/lib/libc/sys/madvise.2
new file mode 100644
index 0000000..ea7e8ef
--- /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.
+.\" 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.
+.\"
+.\" @(#)madvise.2 8.1 (Berkeley) 6/9/93
+.\" $FreeBSD$
+.\"
+.Dd July 19, 1996
+.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 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 range.
+Additionally future references to
+this address range will 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
+.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 0000000..25ad076
--- /dev/null
+++ b/lib/libc/sys/mincore.2
@@ -0,0 +1,117 @@
+.\" 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. 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.
+.\"
+.\" @(#)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.
+.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 EINVAL
+The virtual address range specified by the
+.Fa addr
+and
+.Fa len
+arguments is not valid.
+.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 0000000..1ec8b2d
--- /dev/null
+++ b/lib/libc/sys/minherit.2
@@ -0,0 +1,141 @@
+.\" $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.
+.\" 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.
+.\"
+.\" @(#)minherit.2 8.1 (Berkeley) 6/9/93
+.\"
+.Dd February 17, 1996
+.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 .
+.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 0000000..e91c9ba
--- /dev/null
+++ b/lib/libc/sys/mkdir.2
@@ -0,0 +1,116 @@
+.\" 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. 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.
+.\"
+.\" @(#)mkdir.2 8.2 (Berkeley) 12/11/93
+.\" $FreeBSD$
+.\"
+.Dd December 11, 1993
+.Dt MKDIR 2
+.Os
+.Sh NAME
+.Nm mkdir
+.Nd make a directory file
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/stat.h
+.Ft int
+.Fn mkdir "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.
+.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 EROFS
+The named file resides on a read-only file system.
+.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
+.Sh SEE ALSO
+.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 .
diff --git a/lib/libc/sys/mkfifo.2 b/lib/libc/sys/mkfifo.2
new file mode 100644
index 0000000..329c26b
--- /dev/null
+++ b/lib/libc/sys/mkfifo.2
@@ -0,0 +1,127 @@
+.\" 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. 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.
+.\"
+.\" @(#)mkfifo.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt MKFIFO 2
+.Os
+.Sh NAME
+.Nm mkfifo
+.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"
+.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.
+.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
+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 EROFS
+The named file resides on a read-only file system.
+.It Bq Er EEXIST
+The named file exists.
+.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
+.Sh SEE ALSO
+.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 .
diff --git a/lib/libc/sys/mknod.2 b/lib/libc/sys/mknod.2
new file mode 100644
index 0000000..1c9fca3
--- /dev/null
+++ b/lib/libc/sys/mknod.2
@@ -0,0 +1,130 @@
+.\" 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. 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.
+.\"
+.\" @(#)mknod.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt MKNOD 2
+.Os
+.Sh NAME
+.Nm mknod
+.Nd make a special file node
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fn mknod "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.
+.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
+.Sh SEE ALSO
+.Xr chmod 2 ,
+.Xr mkfifo 2 ,
+.Xr stat 2 ,
+.Xr umask 2
+.Sh HISTORY
+The
+.Fn mknod
+function appeared in
+.At v6 .
diff --git a/lib/libc/sys/mlock.2 b/lib/libc/sys/mlock.2
new file mode 100644
index 0000000..cf2ed4c
--- /dev/null
+++ b/lib/libc/sys/mlock.2
@@ -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.
+.\" 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.
+.\"
+.\" @(#)mlock.2 8.2 (Berkeley) 12/11/93
+.\" $FreeBSD$
+.\"
+.Dd August 10, 2004
+.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.
+A single process can
+.Fn mlock
+the minimum of
+a system-wide ``wired pages'' limit and
+the per-process
+.Li RLIMIT_MEMLOCK
+resource limit.
+.Pp
+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
+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 either the system or per-process
+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.
+.El
+The
+.Fn munlock
+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 address given is not page aligned or the length is negative.
+.It Bq Er ENOMEM
+Some portion of the indicated address range is not allocated.
+.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 0000000..db4c4a9
--- /dev/null
+++ b/lib/libc/sys/mlockall.2
@@ -0,0 +1,140 @@
+.\" $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.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the NetBSD
+.\" Foundation, Inc. and its contributors.
+.\" 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 June 12, 1999
+.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 and the per-process
+.Dv RLIMIT_MEMLOCK
+resource limit.
+.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 0000000..c32371b
--- /dev/null
+++ b/lib/libc/sys/mmap.2
@@ -0,0 +1,367 @@
+.\" 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. 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.
+.\"
+.\" @(#)mmap.2 8.4 (Berkeley) 5/11/95
+.\" $FreeBSD$
+.\"
+.Dd April 21, 2006
+.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_HASSEMAPHORE
+.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 is ignored.
+.\".It Dv MAP_FILE
+.\"Mapped from a regular file or character-special device memory.
+.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 a
+.Dv MAP_FIXED
+request is successful, the mapping established by
+.Fn mmap
+replaces any previous mappings for the process' pages in the range from
+.Fa addr
+to
+.Fa addr
++
+.Fa len .
+Use of this option is discouraged.
+.It Dv MAP_HASSEMAPHORE
+Notify the kernel that the region may contain semaphores and that special
+handling may be necessary.
+.It Dv MAP_INHERIT
+This flag never operated as advertised and is no longer supported.
+Please refer to
+.Xr minherit 2
+for further information.
+.It Dv MAP_NOCORE
+Region is not included in a core file.
+.It Dv MAP_NOSYNC
+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).
+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 obsolete 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_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.
+.Pp
+The current design does not allow a process to specify the location of
+swap space.
+In the future we may define an additional mapping type,
+.Dv MAP_SWAP ,
+in which
+the file descriptor argument specifies a file or device to which swapping
+should be done.
+.Sh 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
+.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
+The
+.Fa len
+argument
+was negative.
+.It Bq Er EINVAL
+.Dv MAP_ANON
+was specified and the
+.Fa fd
+argument was not -1.
+The
+.Fa offset
+argument
+was not page-aligned.
+(See
+.Sx BUGS
+below.)
+.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.
+The system has reached the per-process mmap limit specified in the
+.Va vm.max_proc_mmap
+sysctl.
+.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 make.conf 5
+.Sh BUGS
+The
+.Fa len
+argument
+is limited to the maximum file size or available userland address
+space.
+Files may not be able to be made more than 1TB large on 32 bit systems
+due to file systems restrictions and bugs, but address space is far more
+restrictive. Larger files may be possible on 64 bit systems.
+.Pp
+The previous documented limit of 2GB was a documentation bug.
+That limit has not existed since
+.Fx 2.2 .
+.Pp
+Note that an attempt to
+.Fn mmap
+zero bytes has no effect and succeeds, while an attempt to
+.Fn munmap
+zero bytes will return
+.Bq Er EINVAL .
diff --git a/lib/libc/sys/mmap.c b/lib/libc/sys/mmap.c
new file mode 100644
index 0000000..309d2bc
--- /dev/null
+++ b/lib/libc/sys/mmap.c
@@ -0,0 +1,61 @@
+/*
+ * 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. 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)mmap.c 8.1 (Berkeley) 6/17/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+/*
+ * This function provides 64-bit offset padding that
+ * is not supplied by GCC 1.X but is supplied by GCC 2.X.
+ */
+void *
+mmap(addr, len, prot, flags, fd, offset)
+ void * addr;
+ size_t len;
+ int prot;
+ int flags;
+ int fd;
+ off_t offset;
+{
+
+ return ((void *)(intptr_t)__syscall((quad_t)SYS_mmap, addr, len, prot,
+ flags, fd, 0, offset));
+}
diff --git a/lib/libc/sys/modfind.2 b/lib/libc/sys/modfind.2
new file mode 100644
index 0000000..3f48579
--- /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 file .
+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 0000000..c0c0a0d
--- /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 0000000..9356232
--- /dev/null
+++ b/lib/libc/sys/modstat.2
@@ -0,0 +1,128 @@
+.\"
+.\" 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 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[MAXPATHLEN];
+ int refs;
+ int id;
+ modspecific_t data;
+};
+typedef union modspecific {
+ int intval;
+ u_int u_intval;
+ long longval;
+ u_long u_longval;
+} modspecific_t;
+.Ed
+.Pp
+.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 0000000..480f7a9
--- /dev/null
+++ b/lib/libc/sys/mount.2
@@ -0,0 +1,376 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)mount.2 8.3 (Berkeley) 5/24/95
+.\" $FreeBSD$
+.\"
+.Dd February 23, 2005
+.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 -item -offset indent -compact
+.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.
+.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
+.Pp
+A
+.Em ufs
+mount can also fail if the maximum number of file systems are currently
+mounted.
+.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 .
+.Sh BUGS
+Some of the error codes need translation to more obvious messages.
diff --git a/lib/libc/sys/mprotect.2 b/lib/libc/sys/mprotect.2
new file mode 100644
index 0000000..909b240
--- /dev/null
+++ b/lib/libc/sys/mprotect.2
@@ -0,0 +1,101 @@
+.\" 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. 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.
+.\"
+.\" @(#)mprotect.2 8.1 (Berkeley) 6/9/93
+.\" $FreeBSD$
+.\"
+.Dd June 9, 1993
+.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 "const 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 0000000..c2968fb
--- /dev/null
+++ b/lib/libc/sys/mq_close.2
@@ -0,0 +1,85 @@
+.\" 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 November 29, 2005
+.Dt MQ_CLOSE 2
+.Os
+.Sh NAME
+.Nm mq_close
+.Nd "close a message queue (REALTIME)"
+.Sh LIBRARY
+.Lb libc
+.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 .
diff --git a/lib/libc/sys/mq_getattr.2 b/lib/libc/sys/mq_getattr.2
new file mode 100644
index 0000000..f34c498
--- /dev/null
+++ b/lib/libc/sys/mq_getattr.2
@@ -0,0 +1,107 @@
+.\" 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 November 29, 2005
+.Dt MQ_GETATTR 2
+.Os
+.Sh NAME
+.Nm mq_getattr
+.Nd "get message queue attributes (REALTIME)"
+.Sh LIBRARY
+.Lb libc
+.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_flags"
+.It Va mq_flags
+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 .
diff --git a/lib/libc/sys/mq_notify.2 b/lib/libc/sys/mq_notify.2
new file mode 100644
index 0000000..e7361d4
--- /dev/null
+++ b/lib/libc/sys/mq_notify.2
@@ -0,0 +1,131 @@
+.\" 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 November 29, 2005
+.Dt MQ_NOTIFY 2
+.Os
+.Sh NAME
+.Nm mq_notify
+.Nd "notify process that a message is available (REALTIME)"
+.Sh LIBRARY
+.Lb libc
+.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.
+If
+.Fa notification->sigev_notify
+is
+.Dv SIGEV_SIGNAL ,
+then the signal specified in
+.Fa notification->sigev_signo
+will be sent to the process.
+The signal will be queued to the process and the value specified in
+.Fa notification->sigev_value
+will be the
+.Va si_value
+component of the generated signal.
+.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.
+.El
+.Sh SEE ALSO
+.Xr mq_open 2 ,
+.Xr mq_send 2 ,
+.Xr mq_timedsend 2 ,
+.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 .
diff --git a/lib/libc/sys/mq_open.2 b/lib/libc/sys/mq_open.2
new file mode 100644
index 0000000..940ddfc
--- /dev/null
+++ b/lib/libc/sys/mq_open.2
@@ -0,0 +1,303 @@
+.\" 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 November 29, 2005
+.Dt MQ_OPEN 2
+.Os
+.Sh NAME
+.Nm mq_open
+.Nd "open a message queue (REALTIME)"
+.Sh LIBRARY
+.Lb libc
+.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.
+.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
+.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.
diff --git a/lib/libc/sys/mq_receive.2 b/lib/libc/sys/mq_receive.2
new file mode 100644
index 0000000..e9e5efd
--- /dev/null
+++ b/lib/libc/sys/mq_receive.2
@@ -0,0 +1,197 @@
+.\" 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 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 libc
+.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 .
diff --git a/lib/libc/sys/mq_send.2 b/lib/libc/sys/mq_send.2
new file mode 100644
index 0000000..0d63a40
--- /dev/null
+++ b/lib/libc/sys/mq_send.2
@@ -0,0 +1,216 @@
+.\" 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 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 libc
+.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 .
diff --git a/lib/libc/sys/mq_setattr.2 b/lib/libc/sys/mq_setattr.2
new file mode 100644
index 0000000..e5f0726
--- /dev/null
+++ b/lib/libc/sys/mq_setattr.2
@@ -0,0 +1,103 @@
+.\" 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 November 29, 2005
+.Dt MQ_SETATTR 2
+.Os
+.Sh NAME
+.Nm mq_setattr
+.Nd "set message queue attributes (REALTIME)"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In mqueue.h
+.Ft int
+.Fo mq_setattr
+.Fa "mqd_t mqdes"
+.Fa "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 .
diff --git a/lib/libc/sys/msync.2 b/lib/libc/sys/msync.2
new file mode 100644
index 0000000..e7d50c3
--- /dev/null
+++ b/lib/libc/sys/msync.2
@@ -0,0 +1,125 @@
+.\" 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. 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.
+.\"
+.\" @(#)msync.2 8.2 (Berkeley) 6/21/94
+.\" $FreeBSD$
+.\"
+.Dd June 21, 1994
+.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 EINVAL
+The
+.Fa len
+argument
+is too large or negative.
+.It Bq Er EINVAL
+The
+.Fa flags
+argument
+was both MS_ASYNC and MS_INVALIDATE.
+Only one of these flags is allowed.
+.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 obsolete 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/munmap.2 b/lib/libc/sys/munmap.2
new file mode 100644
index 0000000..e748873
--- /dev/null
+++ b/lib/libc/sys/munmap.2
@@ -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.
+.\" 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.
+.\"
+.\" @(#)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 0000000..f086305
--- /dev/null
+++ b/lib/libc/sys/nanosleep.2
@@ -0,0 +1,113 @@
+.\" $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.
+.\" 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.
+.\"
+.\" @(#)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 process to sleep for the specified time.
+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/nfssvc.2 b/lib/libc/sys/nfssvc.2
new file mode 100644
index 0000000..7d3f645
--- /dev/null
+++ b/lib/libc/sys/nfssvc.2
@@ -0,0 +1,262 @@
+.\" Copyright (c) 1989, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. 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.
+.\"
+.\" @(#)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 */
+ u_int32_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 */
+ u_int32_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 0000000..6ed71ce
--- /dev/null
+++ b/lib/libc/sys/ntp_adjtime.2
@@ -0,0 +1,150 @@
+.\"
+.\" Copyright (c) 2003 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd April 1, 2003
+.Dt NTP_ADJTIME 2
+.Os
+.Sh NAME
+.Nm ntp_adjtime
+.Nd NTP daemon application interface
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/timex.h
+.Ft int
+.Fn ntp_adjtime "struct timex *tp"
+.Sh DESCRIPTION
+The
+.Fn ntp_adjtime
+system call is used as a kernel interface
+for the Network Time Protocol daemon,
+.Xr ntpd 8 .
+Certain fields of the
+.Vt timex
+structure are interpreted in either
+microseconds or nanoseconds, according to the state of the
+.Dv STA_NANO
+bit in the
+.Va status
+word.
+.Pp
+In the
+.Fx
+kernel, the
+.Fn ntp_adjtime
+and
+.Xr ntp_gettime 2
+system calls can be used to determine which
+resolution is in use, and to select either one at any time.
+The resolution selected affects the scaling of certain fields in the
+.Fn ntp_gettime
+and
+.Fn ntp_adjtime
+system calls.
+.Pp
+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.
+.Bd -literal
+/*
+ * NTP daemon interface (ntp_adjtime()) - used to discipline CPU clock
+ * oscillator and determine status.
+ *
+ * Note: The offset, precision and jitter members are in microseconds if
+ * STA_NANO is zero and nanoseconds if not.
+ */
+struct timex {
+ unsigned int modes; /* clock mode bits (wo) */
+ long offset; /* time offset (ns/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; /* poll interval (log2 s) (rw) */
+ long precision; /* clock precision (ns/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. They are included in all configurations to insure
+ * portability.
+ */
+ long ppsfreq; /* PPS frequency (scaled PPM) (ro) */
+ long jitter; /* PPS jitter (ns/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
+Upon successful completion,
+.Fn ntp_adjtime
+will fill the
+.Fa tp
+argument with the current clock state.
+.Sh RETURN VALUES
+Upon successful completion the clock state is returned.
+Otherwise a -1 is returned and the global variable
+.Va errno
+is set to indicate the error.
+.Pp
+Possible states of the clock are:
+.Pp
+.Bl -tag -compact -width ".Dv TIME_ERROR"
+.It Dv TIME_OK
+Everything okay, no leap second warning.
+.It Dv TIME_INS
+insert leap second warning.
+.It Dv TIME_DEL
+delete leap second warning.
+.It Dv TIME_OOP
+Leap second in progress.
+.It Dv TIME_WAIT
+Leap second has occurred.
+.It Dv TIME_ERROR
+Clock not synchronized.
+.El
+.Sh ERRORS
+The
+.Fn ntp_gettime
+system call may return
+.Er EPERM
+if the caller
+does not have sufficient permissions.
+.Sh SEE ALSO
+.Xr ntp_gettime 2 ,
+.Xr ntpd 8
+.Sh AUTHORS
+This manual page was written by
+.An Tom Rhodes Aq trhodes@FreeBSD.org .
diff --git a/lib/libc/sys/ntp_gettime.2 b/lib/libc/sys/ntp_gettime.2
new file mode 100644
index 0000000..f556d74
--- /dev/null
+++ b/lib/libc/sys/ntp_gettime.2
@@ -0,0 +1,116 @@
+.\"
+.\" Copyright (c) 2003 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd June 21, 2003
+.Dt NTP_GETTIME 2
+.Os
+.Sh NAME
+.Nm ntp_gettime
+.Nd NTP user application interface
+.Sh SYNOPSIS
+.In sys/timex.h
+.Ft int
+.Fn ntp_gettime "struct ntptimeval *ntv"
+.Sh DESCRIPTION
+The time returned by
+.Fn ntp_gettime
+is in a
+.Vt timespec
+structure, but may be in either microsecond
+(seconds and microseconds) or nanosecond (seconds and nanoseconds) format.
+The particular format in use is determined by the
+.Dv STA_NANO
+bit of the status
+word returned by the
+.Fn ntp_adjtime
+system call.
+.Fn ntp_gettime
+has as argument a pointer to the
+.Vt ntptimeval
+structure with the following members:
+.Bd -literal
+struct ntptimeval {
+ struct timespec time; /* current time (ns) (ro) */
+ long maxerror; /* maximum error (us) (ro) */
+ long esterror; /* estimated error (us) (ro) */
+ long tai; /* TAI-UTC offset */
+ int time_state; /* time status */
+};
+.Ed
+.Pp
+These are understood as:
+.Bl -tag -width ".Va time_state"
+.It Va time
+Current time (read-only).
+.It Va maxerror
+Maximum error in microseconds (read-only).
+.It Va esterror
+Estimated error in microseconds (read-only).
+.It Va tai
+Offset in seconds between the TAI and UTC time scales.
+This offset is published twice a year and is an integral number of
+seconds between TAI (which does not have leap seconds) and UTC (which
+does).
+.Xr ntpd 8
+or some other agent maintains this value.
+A value of 0 means unknown.
+As of the date of the manual page, the offset is 32 seconds.
+.It Va time_state
+Current time status.
+.El
+.Sh RETURN VALUES
+.Rv -std ntp_gettime
+.Pp
+Possible states of the clock are:
+.Pp
+.Bl -tag -compact -width ".Dv TIME_ERROR"
+.It Dv TIME_OK
+Everything okay, no leap second warning.
+.It Dv TIME_INS
+Positive leap second warning.
+At the end of the day, an additional second will be inserted after 23:59:59.
+.It Dv TIME_DEL
+Negative leap second warning.
+At the end of the day, 23:59:59 is skipped.
+.It Dv TIME_OOP
+Leap second in progress.
+.It Dv TIME_WAIT
+Leap second has occurred.
+.It Dv TIME_ERROR
+Clock not synchronized.
+.El
+.Sh SEE ALSO
+.Xr ntp_adjtime 2 ,
+.Xr ntpd 8
+.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 AUTHORS
+This manual page was written by
+.An Tom Rhodes Aq trhodes@FreeBSD.org .
diff --git a/lib/libc/sys/open.2 b/lib/libc/sys/open.2
new file mode 100644
index 0000000..c494388
--- /dev/null
+++ b/lib/libc/sys/open.2
@@ -0,0 +1,352 @@
+.\" 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. 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.
+.\"
+.\" @(#)open.2 8.2 (Berkeley) 11/16/93
+.\" $FreeBSD$
+.\"
+.Dd November 16, 1993
+.Dt OPEN 2
+.Os
+.Sh NAME
+.Nm open
+.Nd open or create a file for reading or writing
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In fcntl.h
+.Ft int
+.Fn open "const char *path" "int flags" "..."
+.Sh DESCRIPTION
+The file name specified by
+.Fa path
+is opened
+for 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
+requires a third 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 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_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 don't assign controlling terminal
+.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
+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
+When a new file is created it is given the group of the directory
+which contains it.
+.Pp
+The new descriptor is set to remain open across
+.Xr execve 2
+system calls; see
+.Xr close 2
+and
+.Xr fcntl 2 .
+.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
+returns a non-negative integer, termed a file descriptor.
+It returns -1 on failure, and sets
+.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_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 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 opened for writing.
+.It Bq Er EROFS
+The named file resides on a read-only file system,
+and the file is to be modified.
+.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
+The named file is a fifo, no process has
+it open for reading, and the arguments specify it is
+to be opened for writing.
+.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 ,
+and
+.Dv O_RDWR .
+.El
+.Sh SEE ALSO
+.Xr chmod 2 ,
+.Xr close 2 ,
+.Xr dup 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 .
diff --git a/lib/libc/sys/pathconf.2 b/lib/libc/sys/pathconf.2
new file mode 100644
index 0000000..763c7bd
--- /dev/null
+++ b/lib/libc/sys/pathconf.2
@@ -0,0 +1,230 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)pathconf.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd November 4, 2002
+.Dt PATHCONF 2
+.Os
+.Sh NAME
+.Nm pathconf ,
+.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 fpathconf "int fd" "int name"
+.Sh DESCRIPTION
+The
+.Fn pathconf
+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 ,
+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 available values are as follows:
+.Pp
+.Bl -tag -width 6n
+.Pp
+.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_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.
+.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
+.Bl -tag -width Er
+The
+.Fn fpathconf
+system call
+will fail if:
+.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 sysctl 3
+.Sh HISTORY
+The
+.Fn pathconf
+and
+.Fn fpathconf
+system calls first appeared in
+.Bx 4.4 .
diff --git a/lib/libc/sys/pipe.2 b/lib/libc/sys/pipe.2
new file mode 100644
index 0000000..5f5ac3a
--- /dev/null
+++ b/lib/libc/sys/pipe.2
@@ -0,0 +1,122 @@
+.\" 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. 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.
+.\"
+.\" @(#)pipe.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd January 30, 2006
+.Dt PIPE 2
+.Os
+.Sh NAME
+.Nm pipe
+.Nd create descriptor pair for interprocess communication
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fn pipe "int *fildes"
+.Sh DESCRIPTION
+The
+.Fn pipe
+system call
+creates a
+.Em pipe ,
+which is an object allowing
+bidirectional data flow,
+and allocates a pair of file descriptors.
+.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 RETURN VALUES
+.Rv -std pipe
+.Sh ERRORS
+The
+.Fn pipe
+system call will fail if:
+.Bl -tag -width Er
+.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.
+.It Bq Er EFAULT
+The
+.Fa fildes
+buffer is in an invalid area of the process's address
+space.
+.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 .
diff --git a/lib/libc/sys/poll.2 b/lib/libc/sys/poll.2
new file mode 100644
index 0000000..932186d
--- /dev/null
+++ b/lib/libc/sys/poll.2
@@ -0,0 +1,213 @@
+.\" $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 July 8, 2002
+.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"
+.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.
+.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 negative.
+.El
+.Sh SEE ALSO
+.Xr accept 2 ,
+.Xr connect 2 ,
+.Xr kqueue 2 ,
+.Xr read 2 ,
+.Xr recv 2 ,
+.Xr select 2 ,
+.Xr send 2 ,
+.Xr write 2
+.Sh HISTORY
+The
+.Fn poll
+function appeared in
+.At V .
+This manual page and the core of the implementation was taken from
+.Nx .
+.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/pread.c b/lib/libc/sys/pread.c
new file mode 100644
index 0000000..c1a9136
--- /dev/null
+++ b/lib/libc/sys/pread.c
@@ -0,0 +1,56 @@
+/*
+ * 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. 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)mmap.c 8.1 (Berkeley) 6/17/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+/*
+ * This function provides 64-bit offset padding that
+ * is not supplied by GCC 1.X but is supplied by GCC 2.X.
+ */
+ssize_t
+pread(fd, buf, nbyte, offset)
+ int fd;
+ void *buf;
+ size_t nbyte;
+ off_t offset;
+{
+ return ((ssize_t)__syscall((quad_t)SYS_pread, fd, buf, nbyte, 0, offset));
+}
diff --git a/lib/libc/sys/profil.2 b/lib/libc/sys/profil.2
new file mode 100644
index 0000000..5dea7ab
--- /dev/null
+++ b/lib/libc/sys/profil.2
@@ -0,0 +1,126 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)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/ptrace.2 b/lib/libc/sys/ptrace.2
new file mode 100644
index 0000000..0d6009f
--- /dev/null
+++ b/lib/libc/sys/ptrace.2
@@ -0,0 +1,390 @@
+.\" $FreeBSD$
+.\" $NetBSD: ptrace.2,v 1.2 1995/02/27 12:35:37 cgd Exp $
+.\"
+.\" This file is in the public domain.
+.Dd August 11, 2003
+.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, system calls, or stepping by the tracing
+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
+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.
+The
+.Fa request
+argument
+can be:
+.Bl -tag -width 12n
+.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.
+.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; /* LWP described. */
+ int pl_event; /* Event received. */
+};
+.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.
+.El
+.Pp
+Additionally, machine-specific requests can exist.
+.Sh RETURN VALUES
+Some requests can cause
+.Fn ptrace
+to return
+\-1
+as a non-error value; to disambiguate,
+.Va errno
+can be set to 0 before the call and checked afterwards.
+.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.)
+.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
+.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/pwrite.c b/lib/libc/sys/pwrite.c
new file mode 100644
index 0000000..e6969cd
--- /dev/null
+++ b/lib/libc/sys/pwrite.c
@@ -0,0 +1,56 @@
+/*
+ * 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. 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)mmap.c 8.1 (Berkeley) 6/17/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+/*
+ * This function provides 64-bit offset padding that
+ * is not supplied by GCC 1.X but is supplied by GCC 2.X.
+ */
+ssize_t
+pwrite(fd, buf, nbyte, offset)
+ int fd;
+ const void *buf;
+ size_t nbyte;
+ off_t offset;
+{
+ return ((ssize_t)__syscall((quad_t)SYS_pwrite, fd, buf, nbyte, 0, offset));
+}
diff --git a/lib/libc/sys/quotactl.2 b/lib/libc/sys/quotactl.2
new file mode 100644
index 0000000..d0cee9b
--- /dev/null
+++ b/lib/libc/sys/quotactl.2
@@ -0,0 +1,236 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)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
+.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
+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_QUOTAOFFxx
+.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_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_GETQUOTA
+and
+.Dv Q_SETQUOTA ,
+quotas are not currently enabled for this file system.
+.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 ,
+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/read.2 b/lib/libc/sys/read.2
new file mode 100644
index 0000000..2dccb0e
--- /dev/null
+++ b/lib/libc/sys/read.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.
+.\" 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.
+.\"
+.\" @(#)read.2 8.4 (Berkeley) 2/26/94
+.\" $FreeBSD$
+.\"
+.Dd July 29, 2005
+.Dt READ 2
+.Os
+.Sh NAME
+.Nm read ,
+.Nm readv ,
+.Nm pread ,
+.Nm preadv
+.Nd read input
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/uio.h
+.In unistd.h
+.Ft ssize_t
+.Fn read "int d" "void *buf" "size_t nbytes"
+.Ft ssize_t
+.Fn pread "int d" "void *buf" "size_t nbytes" "off_t offset"
+.Ft ssize_t
+.Fn readv "int d" "const struct iovec *iov" "int iovcnt"
+.Ft ssize_t
+.Fn preadv "int d" "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 d
+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 d
+(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 d
+argument
+is not a valid file or socket descriptor open for reading.
+.It Bq Er ECONNRESET
+The
+.Fa d
+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 EINTR
+A read from a slow device was interrupted before
+any data arrived by the delivery of a signal.
+.It Bq Er EINVAL
+The pointer associated with
+.Fa d
+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/readlink.2 b/lib/libc/sys/readlink.2
new file mode 100644
index 0000000..28ecc4b
--- /dev/null
+++ b/lib/libc/sys/readlink.2
@@ -0,0 +1,104 @@
+.\" 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. 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.
+.\"
+.\" @(#)readlink.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt READLINK 2
+.Os
+.Sh NAME
+.Nm readlink
+.Nd read value of a symbolic link
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fn readlink "const char *path" "char *buf" "int bufsiz"
+.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 .
+.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
+.Sh SEE ALSO
+.Xr lstat 2 ,
+.Xr stat 2 ,
+.Xr symlink 2 ,
+.Xr symlink 7
+.Sh HISTORY
+The
+.Fn readlink
+system call appeared in
+.Bx 4.2 .
diff --git a/lib/libc/sys/reboot.2 b/lib/libc/sys/reboot.2
new file mode 100644
index 0000000..6d9f096
--- /dev/null
+++ b/lib/libc/sys/reboot.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.
+.\" 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.
+.\"
+.\" @(#)reboot.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.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_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 .
+.Sh BUGS
+The HP300 implementation supports neither
+.Dv RB_DFLTROOT
+nor
+.Dv RB_KDB .
diff --git a/lib/libc/sys/recv.2 b/lib/libc/sys/recv.2
new file mode 100644
index 0000000..90aea6a
--- /dev/null
+++ b/lib/libc/sys/recv.2
@@ -0,0 +1,337 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)recv.2 8.3 (Berkeley) 2/21/94
+.\" $FreeBSD$
+.\"
+.Dd February 16, 2006
+.Dt RECV 2
+.Os
+.Sh NAME
+.Nm recv ,
+.Nm recvfrom ,
+.Nm recvmsg
+.Nd receive a message from a socket
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.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 * restrict 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"
+.Sh DESCRIPTION
+The
+.Fn recvfrom
+and
+.Fn recvmsg
+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.
+As it is redundant, it may not be supported in future releases.
+.Pp
+All three routines return the length of the message on successful
+completion.
+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 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 .
+.Pp
+The
+.Xr select 2
+system call may be used to determine when more data arrive.
+.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_DONTWAIT" -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
+.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.
+.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 :
+.Pp
+.Bd -literal
+struct msghdr {
+ caddr_t msg_name; /* optional address */
+ u_int msg_namelen; /* size of address */
+ struct iovec *msg_iov; /* scatter/gather array */
+ u_int msg_iovlen; /* # elements in msg_iov */
+ caddr_t msg_control; /* ancillary data, see below */
+ u_int 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 {
+ u_int 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 .
+.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:
+.Pp
+.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
+The kernel will fill in the credential information of the sending process
+and deliver it to the receiver.
+.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.
+.Sh RETURN VALUES
+These calls return the number of bytes received, or -1
+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
+.Sh HISTORY
+The
+.Fn recv
+function appeared in
+.Bx 4.2 .
diff --git a/lib/libc/sys/rename.2 b/lib/libc/sys/rename.2
new file mode 100644
index 0000000..0080f40
--- /dev/null
+++ b/lib/libc/sys/rename.2
@@ -0,0 +1,215 @@
+.\" 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. 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.
+.\"
+.\" @(#)rename.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.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"
+.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.
+.\".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 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
+.Sh SEE ALSO
+.Xr open 2 ,
+.Xr symlink 7
+.Sh STANDARDS
+The
+.Fn rename
+system call is expected to conform to
+.St -p1003.1-96 .
diff --git a/lib/libc/sys/revoke.2 b/lib/libc/sys/revoke.2
new file mode 100644
index 0000000..64de556
--- /dev/null
+++ b/lib/libc/sys/revoke.2
@@ -0,0 +1,109 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)revoke.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.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.
+.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 close 2
+.Sh HISTORY
+The
+.Fn revoke
+system call first appeared in
+.Bx 4.3 Reno .
diff --git a/lib/libc/sys/rfork.2 b/lib/libc/sys/rfork.2
new file mode 100644
index 0000000..9187a55
--- /dev/null
+++ b/lib/libc/sys/rfork.2
@@ -0,0 +1,186 @@
+.\"
+.\" 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 January 31, 2003
+.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 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.
+.It Dv RFSIGSHARE
+If set, the kernel will force sharing the sigacts structure between the
+child and the parent.
+.It Dv RFLINUXTHPN
+If set, the kernel will return SIGUSR1 instead of SIGCHILD 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 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 rfork_thread 3
+.Sh HISTORY
+The
+.Fn rfork
+function first appeared in Plan9.
+.Sh BUGS
+.Fx
+does not yet implement a native
+.Fn clone
+library call, and the current pthreads implementation does not use
+.Fn rfork
+with RFMEM.
+A native port of the linux threads library,
+.Pa /usr/ports/devel/linuxthreads ,
+contains a working
+.Fn clone
+call that utilizes RFMEM.
+The
+.Xr rfork_thread 3
+function can often be used instead of
+.Fn clone .
diff --git a/lib/libc/sys/rmdir.2 b/lib/libc/sys/rmdir.2
new file mode 100644
index 0000000..f98b952
--- /dev/null
+++ b/lib/libc/sys/rmdir.2
@@ -0,0 +1,114 @@
+.\" 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. 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.
+.\"
+.\" @(#)rmdir.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd January 22, 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 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 0000000..afed81e
--- /dev/null
+++ b/lib/libc/sys/rtprio.2
@@ -0,0 +1,126 @@
+.\" 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd July 23, 1994
+.Dt RTPRIO 2
+.Os
+.Sh NAME
+.Nm rtprio
+.Nd examine or modify a process 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"
+.Sh DESCRIPTION
+The
+.Fn rtprio
+system call
+is used to lookup or change the realtime or idle priority of a process.
+.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.
+The
+.Fa pid
+argument
+specifies the process to be used, 0 for the current process.
+.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 (usually 31) .
+0 is the highest possible priority.
+.Pp
+Realtime and idle priority is inherited through fork() and exec().
+.Pp
+A realtime process can only be preempted by a process of equal or
+higher priority, or by an interrupt; idle priority processes will run only
+when no other real/normal priority process is runnable.
+Higher real/idle priority processes
+preempt lower real/idle priority processes.
+Processes of equal real/idle priority are run round-robin.
+.Sh RETURN VALUES
+.Rv -std rtprio
+.Sh ERRORS
+The
+.Fn rtprio
+system call
+will fail if
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The specified
+.Fa prio
+was out of range.
+.It Bq Er EPERM
+The calling process is not allowed to set the realtime priority.
+Only
+root is allowed to change the realtime priority of any process, and non-root
+may only change the idle priority of the current process.
+.It Bq Er ESRCH
+The specified process was not found.
+.El
+.Sh SEE ALSO
+.Xr nice 1 ,
+.Xr ps 1 ,
+.Xr rtprio 1 ,
+.Xr setpriority 2 ,
+.Xr nice 3 ,
+.Xr renice 8
+.Sh AUTHORS
+.An -nosplit
+The original author was
+.An Henrik Vestergaard Draboel Aq hvd@terry.ping.dk .
+This implementation in
+.Fx
+was substantially rewritten by
+.An David Greenman .
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 0000000..88d1d6d
--- /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 0000000..315fd82
--- /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 0000000..21b34e0
--- /dev/null
+++ b/lib/libc/sys/sched_setscheduler.2
@@ -0,0 +1,167 @@
+.\" $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> :
+.Pp
+.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_getparam 2 ,
+.Xr sched_get_priority_max 2 ,
+.Xr sched_get_priority_min 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 0000000..9db8942
--- /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/select.2 b/lib/libc/sys/select.2
new file mode 100644
index 0000000..8d92563
--- /dev/null
+++ b/lib/libc/sys/select.2
@@ -0,0 +1,228 @@
+.\" 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. 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.
+.\"
+.\" @(#)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.
diff --git a/lib/libc/sys/semctl.2 b/lib/libc/sys/semctl.2
new file mode 100644
index 0000000..01a984a
--- /dev/null
+++ b/lib/libc/sys/semctl.2
@@ -0,0 +1,203 @@
+.\"
+.\" 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 */
+ long sem_pad1; /* SVABI/386 says I need this here */
+ time_t sem_ctime; /* last change time */
+ /* Times measured in secs since */
+ /* 00:00:00 GMT, Jan. 1, 1970 */
+ long sem_pad2; /* SVABI/386 says I need this here */
+ long sem_pad3[4]; /* SVABI/386 says I need this here */
+};
+.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 0000000..945044d
--- /dev/null
+++ b/lib/libc/sys/semget.2
@@ -0,0 +1,148 @@
+.\"
+.\" 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 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 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 0000000..86200ee
--- /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 insure 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 0000000..20e005b
--- /dev/null
+++ b/lib/libc/sys/send.2
@@ -0,0 +1,240 @@
+.\" 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. 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.
+.\"
+.\" From: @(#)send.2 8.2 (Berkeley) 2/21/94
+.\" $FreeBSD$
+.\"
+.Dd February 15, 1995
+.Dt SEND 2
+.Os
+.Sh NAME
+.Nm send ,
+.Nm sendto ,
+.Nm sendmsg
+.Nd send a message from a socket
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.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"
+.Sh DESCRIPTION
+The
+.Fn send
+function,
+and
+.Fn sendto
+and
+.Fn sendmsg
+system calls
+are used to transmit a message to another socket.
+The
+.Fn send
+function
+may be used only when the socket is in a
+.Em connected
+state, while
+.Fn sendto
+and
+.Fn sendmsg
+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
+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_PEEK 0x00002 /* peek at incoming message */
+#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, and is used to implement Transaction
+.Tn TCP
+(see
+.Xr ttcp 4 ) .
+.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.
+.Sh RETURN VALUES
+The call returns the number of characters sent, or -1
+if an error occurred.
+.Sh ERRORS
+The
+.Fn send
+function 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 EPERM
+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 .
+.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 0000000..57feb14
--- /dev/null
+++ b/lib/libc/sys/sendfile.2
@@ -0,0 +1,278 @@
+.\" 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 October 31, 2005
+.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 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
+.Fa flags
+argument has one possible value:
+.Dv SF_NODISKIO .
+This flag causes any
+.Fn sendfile
+call which would block on disk I/O to instead
+return
+.Er EBUSY .
+Busy servers may benefit by transferring requests that would
+block to a separate I/O worker thread.
+.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 IMPLEMENTATION NOTES
+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
+Internally, this system call 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 .
+.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
+Completing the entire transfer would have required disk I/O, so
+it was aborted.
+Partial data may have been sent.
+(This error can only occur when
+.Dv SF_NODISKIO
+is specified.)
+.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 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
+.Sh HISTORY
+The
+.Fn sendfile
+system call
+first appeared in
+.Fx 3.0 .
+This manual page first appeared in
+.Fx 3.1 .
+.Sh AUTHORS
+The
+.Fn sendfile
+system call
+and this manual page were written by
+.An David G. Lawrence Aq dg@dglawrence.com .
diff --git a/lib/libc/sys/setgroups.2 b/lib/libc/sys/setgroups.2
new file mode 100644
index 0000000..cbc3a36
--- /dev/null
+++ b/lib/libc/sys/setgroups.2
@@ -0,0 +1,93 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)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 ,
+as defined in
+.In sys/param.h .
+.Pp
+Only the super-user may set new groups.
+.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
+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 0000000..79ece67
--- /dev/null
+++ b/lib/libc/sys/setpgid.2
@@ -0,0 +1,109 @@
+.\" 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. 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.
+.\"
+.\" @(#)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.
+.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 0000000..fd27e71
--- /dev/null
+++ b/lib/libc/sys/setregid.2
@@ -0,0 +1,94 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)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 0000000..08d07f3
--- /dev/null
+++ b/lib/libc/sys/setresuid.2
@@ -0,0 +1,99 @@
+.\" 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 April 13, 2001
+.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 STANDARDS
+These system calls are not available on many platforms.
+They exist in
+.Fx
+to support Linux binaries linked against GNU libc2.
+.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 0000000..cd8b718
--- /dev/null
+++ b/lib/libc/sys/setreuid.2
@@ -0,0 +1,94 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)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 0000000..56506a6
--- /dev/null
+++ b/lib/libc/sys/setsid.2
@@ -0,0 +1,85 @@
+.\" 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. 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.
+.\"
+.\" @(#)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 0000000..57ccadb
--- /dev/null
+++ b/lib/libc/sys/setuid.2
@@ -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. 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.
+.\"
+.\" @(#)setuid.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.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 sys/types.h
+.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 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 is set:
+.Bd -literal
+void
+pseudocode(void)
+{
+ int fd;
+ /* ... */
+
+ fd = open("/path/to/sensitive/data", O_RDWR);
+ if (fd == -1)
+ err(1, "open");
+
+ /*
+ * Set close-on-exec flag; see fcntl(2) for more information.
+ */
+ if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
+ err(1, "fcntl(F_SETFD)");
+ /* ... */
+ execve(path, argv, environ);
+}
+.Ed
+.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 .
diff --git a/lib/libc/sys/shm_open.2 b/lib/libc/sys/shm_open.2
new file mode 100644
index 0000000..b68e85b
--- /dev/null
+++ b/lib/libc/sys/shm_open.2
@@ -0,0 +1,192 @@
+.\"
+.\" 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 March 24, 2000
+.Dt SHM_OPEN 3
+.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
+.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
+function opens (or optionally creates) a
+.Tn POSIX
+shared memory object named
+.Fa path .
+The
+.Fn shm_unlink
+function removes a shared memory object named
+.Fa path .
+.Pp
+In the
+.Fx
+implementation,
+.Tn POSIX
+shared memory objects are implemented as ordinary files.
+The
+.Fn shm_open
+and
+.Fn shm_unlink
+act as wrappers around the
+.Xr open 2
+and
+.Xr unlink 2
+routines, and
+.Fa path ,
+.Fa flags ,
+and
+.Fa mode
+arguments are as specified for those functions.
+The
+.Fa flags
+argument is checked to ensure that the access mode specified is not
+.Dv O_WRONLY
+(which is not defined for shared memory objects).
+.Pp
+In addition, the
+.Fx
+implementation causes
+.Fn mmap
+of a descriptor returned by
+.Fn shm_open
+to behave as if the
+.Dv MAP_NOSYNC
+flag had been specified to
+.Xr mmap 2 .
+(It does so by setting a special file flag using
+.Xr fcntl 2 . )
+.Pp
+The
+.Fn shm_unlink
+function makes no effort to ensure that
+.Fa path
+refers to a shared memory object.
+.Sh RETURN VALUES
+If successful,
+.Fn shm_open
+returns a non-negative integer;
+.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 this
+and 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
+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.
+It is also undefined whether the shared memory object itself, or its
+contents, persist across reboots.
+.Sh ERRORS
+The
+.Fn shm_open
+and
+.Fn shm_unlink
+functions can fail with any error defined for
+.Fn open
+and
+.Fn unlink ,
+respectively.
+In addition, the following errors are defined for
+.Fn shm_open :
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The object named by
+.Fa path
+is not a shared memory object
+(i.e., it is not a regular file).
+.It Bq Er EINVAL
+The
+.Fa flags
+argument to
+.Fn shm_open
+specifies an access mode of
+.Dv O_WRONLY .
+.El
+.Sh SEE ALSO
+.Xr mmap 2 ,
+.Xr munmap 2 ,
+.Xr open 2 ,
+.Xr unlink 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 .
+.Sh AUTHORS
+.An Garrett A. Wollman Aq wollman@FreeBSD.org
+(C library support and this manual page)
+.Pp
+.An Matthew Dillon Aq 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 0000000..8fe340c
--- /dev/null
+++ b/lib/libc/sys/shmat.2
@@ -0,0 +1,123 @@
+.\"
+.\" 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 machine/param.h
+.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 0000000..90c61c9
--- /dev/null
+++ b/lib/libc/sys/shmctl.2
@@ -0,0 +1,140 @@
+.\"
+.\" 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 July 17, 1995
+.Dt SHMCTL 2
+.Os
+.Sh NAME
+.Nm shmctl
+.Nd shared memory control
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In machine/param.h
+.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;
+however, once the IPC_RMID operation has taken place, no further
+processes will be allowed to attach the segment.
+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.
+.\" .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 */
+ int 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 */
+ short 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() */
+ void *shm_internal; /* sysv stupidity */
+};
+.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 0000000..e7fd6d1
--- /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 July 3, 1995
+.Dt SHMGET 2
+.Os
+.Sh NAME
+.Nm shmget
+.Nd obtain a shared memory identifier
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In machine/param.h
+.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 SHM_R
+Read access for user.
+.It Dv SHM_W
+Write access for user.
+.It Dv ( SHM_R>>3 )
+Read access for group.
+.It Dv ( SHM_W>>3 )
+Write access for group.
+.It Dv ( SHM_R>>6 )
+Read access for other.
+.It Dv ( SHM_W>>6 )
+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 ftok 3
diff --git a/lib/libc/sys/shutdown.2 b/lib/libc/sys/shutdown.2
new file mode 100644
index 0000000..3d258cb
--- /dev/null
+++ b/lib/libc/sys/shutdown.2
@@ -0,0 +1,108 @@
+.\" 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. 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.
+.\"
+.\" @(#)shutdown.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd February 27, 2001
+.Dt SHUTDOWN 2
+.Os
+.Sh NAME
+.Nm shutdown
+.Nd shut down part of a full-duplex connection
+.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 causes all or part of a full-duplex connection on
+the socket associated with the file descriptor
+.Fa s
+to be shut down.
+The
+.Fa how
+argument specifies the type of shutdown.
+Possible values are:
+.Bl -tag -width SHUT_RDWR
+.It Dv SHUT_RD
+further receives will be disallowed.
+.It Dv SHUT_WR
+further sends will be disallowed.
+.It Dv SHUT_RDWR
+further sends and receives will be disallowed.
+.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 socket 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
+.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 .
diff --git a/lib/libc/sys/sigaction.2 b/lib/libc/sys/sigaction.2
new file mode 100644
index 0000000..53b6a46
--- /dev/null
+++ b/lib/libc/sys/sigaction.2
@@ -0,0 +1,669 @@
+.\" 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.
+.\" 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.
+.\"
+.\" From: @(#)sigaction.2 8.2 (Berkeley) 4/3/94
+.\" $FreeBSD$
+.\"
+.Dd June 7, 2004
+.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 {
+ union {
+ void (*__sa_handler)(int);
+ void (*__sa_sigaction)(int, struct __siginfo *, void *);
+ } __sigaction_u; /* signal handler */
+ int sa_flags; /* see signal options below */
+ sigset_t sa_mask; /* signal mask to apply */
+};
+
+#define sa_handler __sigaction_u.__sa_handler
+#define sa_sigaction __sigaction_u.__sa_sigaction
+.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 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 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 ,
+in which case its delivery is postponed 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 process.
+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 process.
+The signal mask for a process is initialized
+from that of its parent (normally empty).
+It may be changed with a
+.Xr sigprocmask 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.
+Signals may be delivered any time a process 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 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 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
+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 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 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 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
+.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:
+.Pp
+Base Interfaces:
+.Pp
+.Fn _exit ,
+.Fn access ,
+.Fn alarm ,
+.Fn cfgetispeed ,
+.Fn cfgetospeed ,
+.Fn cfsetispeed ,
+.Fn cfsetospeed ,
+.Fn chdir ,
+.Fn chmod ,
+.Fn chown ,
+.Fn close ,
+.Fn creat ,
+.Fn dup ,
+.Fn dup2 ,
+.Fn execle ,
+.Fn execve ,
+.Fn fcntl ,
+.Fn fork ,
+.Fn fpathconf ,
+.Fn fstat ,
+.Fn fsync ,
+.Fn getegid ,
+.Fn geteuid ,
+.Fn getgid ,
+.Fn getgroups ,
+.Fn getpgrp ,
+.Fn getpid ,
+.Fn getppid ,
+.Fn getuid ,
+.Fn kill ,
+.Fn link ,
+.Fn lseek ,
+.Fn mkdir ,
+.Fn mkfifo ,
+.Fn open ,
+.Fn pathconf ,
+.Fn pause ,
+.Fn pipe ,
+.Fn raise ,
+.Fn read ,
+.Fn rename ,
+.Fn rmdir ,
+.Fn setgid ,
+.Fn setpgid ,
+.Fn setsid ,
+.Fn setuid ,
+.Fn sigaction ,
+.Fn sigaddset ,
+.Fn sigdelset ,
+.Fn sigemptyset ,
+.Fn sigfillset ,
+.Fn sigismember ,
+.Fn signal ,
+.Fn sigpending ,
+.Fn sigprocmask ,
+.Fn sigsuspend ,
+.Fn sleep ,
+.Fn stat ,
+.Fn sysconf ,
+.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 utime ,
+.Fn wait ,
+.Fn waitpid ,
+.Fn write .
+.Pp
+Realtime Interfaces:
+.Pp
+.Fn aio_error ,
+.Fn clock_gettime ,
+.Fn sigpause ,
+.Fn timer_getoverrun ,
+.Fn aio_return ,
+.Fn fdatasync ,
+.Fn sigqueue ,
+.Fn timer_gettime ,
+.Fn aio_suspend ,
+.Fn sem_post ,
+.Fn sigset ,
+.Fn timer_settime .
+.Pp
+.Tn ANSI C
+Interfaces:
+.Pp
+.Fn strcpy ,
+.Fn strcat ,
+.Fn strncpy ,
+.Fn strncat ,
+and perhaps some others.
+.Pp
+Extension Interfaces:
+.Pp
+.Fn strlcpy ,
+.Fn strlcat .
+.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 when called from a signal handler is undefined.
+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 EFAULT
+Either
+.Fa act
+or
+.Fa oact
+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 sigaltstack 2 ,
+.Xr sigblock 2 ,
+.Xr sigpause 2 ,
+.Xr sigpending 2 ,
+.Xr sigprocmask 2 ,
+.Xr sigsetmask 2 ,
+.Xr sigsuspend 2 ,
+.Xr sigvec 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/sigaltstack.2 b/lib/libc/sys/sigaltstack.2
new file mode 100644
index 0000000..fe8fda5
--- /dev/null
+++ b/lib/libc/sys/sigaltstack.2
@@ -0,0 +1,168 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)sigaltstack.2 8.2 (Berkeley) 5/1/95
+.\" $FreeBSD$
+.\"
+.Dd May 1, 1995
+.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 sigaltstack {
+ 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 users to define an alternate stack on which signals
+are to be processed.
+If
+.Fa ss
+is non-zero,
+it specifies a pointer to and the size of a
+.Em "signal stack"
+on which to deliver signals,
+and tells the system if the process is currently executing
+on that stack.
+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 process is currently executing on that stack.
+If the process 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
+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.
+Trying to disable an active stack will cause
+.Fn sigaltstack
+to return -1 with
+.Va errno
+set to
+.Er EINVAL .
+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 process 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,0) < 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 EINVAL
+An attempt was made to disable an active stack.
+.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 0000000..39565fd
--- /dev/null
+++ b/lib/libc/sys/sigpending.2
@@ -0,0 +1,81 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)sigpending.2 8.3 (Berkeley) 1/12/94
+.\" $FreeBSD$
+.\"
+.Dd January 12, 1994
+.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 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 0000000..8f3a586
--- /dev/null
+++ b/lib/libc/sys/sigprocmask.2
@@ -0,0 +1,129 @@
+.\" 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. 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.
+.\"
+.\" @(#)sigprocmask.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.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.
+.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 sigsetops 3
+.Sh STANDARDS
+The
+.Fn sigprocmask
+system call is expected to
+conform to
+.St -p1003.1-90 .
diff --git a/lib/libc/sys/sigqueue.2 b/lib/libc/sys/sigqueue.2
new file mode 100644
index 0000000..b556ba4
--- /dev/null
+++ b/lib/libc/sys/sigqueue.2
@@ -0,0 +1,146 @@
+.\" 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 November 11, 2005
+.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 EEPERM
+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 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 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 0000000..4598f09
--- /dev/null
+++ b/lib/libc/sys/sigreturn.2
@@ -0,0 +1,97 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)sigreturn.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.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 processes 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 NOTES
+This system call is not available in
+.Bx 4.2
+hence it should not be used if backward compatibility is needed.
+.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 process 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 sigvec 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 0000000..95c0db2
--- /dev/null
+++ b/lib/libc/sys/sigstack.2
@@ -0,0 +1,54 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)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 0000000..bf946d3
--- /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.
+.\" 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.
+.\"
+.\" @(#)sigsuspend.2 8.2 (Berkeley) 5/16/95
+.\" $FreeBSD$
+.\"
+.Dd May 16, 1995
+.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 sigaction 2 ,
+.Xr sigpending 2 ,
+.Xr sigprocmask 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/sigwait.2 b/lib/libc/sys/sigwait.2
new file mode 100644
index 0000000..8c00cf4
--- /dev/null
+++ b/lib/libc/sys/sigwait.2
@@ -0,0 +1,119 @@
+.\" 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 November 11, 2005
+.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 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 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.
+.It Bq Er EFAULT
+Any arguments point outside the allocated address space or there is a
+memory protection fault.
+.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/sigwaitinfo.2 b/lib/libc/sys/sigwaitinfo.2
new file mode 100644
index 0000000..41be9e2
--- /dev/null
+++ b/lib/libc/sys/sigwaitinfo.2
@@ -0,0 +1,199 @@
+.\" 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 November 11, 2005
+.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.
+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.
+.It Bq Er EFAULT
+Any arguments point outside the allocated address space or there is a
+memory protection fault.
+.Pp
+.El
+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/socket.2 b/lib/libc/sys/socket.2
new file mode 100644
index 0000000..dadd683
--- /dev/null
+++ b/lib/libc/sys/socket.2
@@ -0,0 +1,297 @@
+.\" 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. 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.
+.\"
+.\" From: @(#)socket.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd November 24, 1997
+.Dt SOCKET 2
+.Os
+.Sh NAME
+.Nm socket
+.Nd create an endpoint for communication
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.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, formerly called PF_UNIX,
+PF_UNIX Host-internal protocols, deprecated, use PF_LOCAL,
+PF_INET Internet version 4 protocols,
+PF_PUP PUP protocols, like BSP,
+PF_APPLETALK AppleTalk protocols,
+PF_ROUTE Internal Routing protocol,
+PF_LINK Link layer interface,
+PF_IPX Novell Internet Packet eXchange protocol,
+PF_RTIP Help Identify RTIP packets,
+PF_PIP Help Identify PIP packets,
+PF_ISDN Integrated Services Digital Network,
+PF_KEY Internal key-management function,
+PF_INET6 Internet version 6 protocols,
+PF_NATM Native ATM access,
+PF_ATM ATM,
+PF_NETGRAPH Netgraph sockets
+.Ed
+.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
+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
+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
+insure 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).
+A
+.Dv SIGPIPE
+signal is raised if a process sends
+on a broken stream; this causes naive processes,
+which do not handle the signal, to exit.
+.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 EPROTONOSUPPORT
+The protocol type or the specified protocol is not supported
+within this domain.
+.It Bq Er EMFILE
+The per-process descriptor table is full.
+.It Bq Er ENFILE
+The system file table is full.
+.It Bq Er EACCES
+Permission to create a socket of the specified type and/or protocol
+is denied.
+.It Bq Er ENOBUFS
+Insufficient buffer space is available.
+The socket cannot be created until sufficient resources are freed.
+.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 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 0000000..7f982c5
--- /dev/null
+++ b/lib/libc/sys/socketpair.2
@@ -0,0 +1,95 @@
+.\" 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. 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.
+.\"
+.\" @(#)socketpair.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.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 d" "int type" "int protocol" "int *sv"
+.Sh DESCRIPTION
+The
+.Fn socketpair
+system call creates an unnamed pair of connected sockets in
+the specified domain
+.Fa d ,
+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.
+.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 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 0000000..e3746c9
--- /dev/null
+++ b/lib/libc/sys/stat.2
@@ -0,0 +1,345 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)stat.2 8.4 (Berkeley) 5/1/95
+.\" $FreeBSD$
+.\"
+.Dd November 15, 2004
+.Dt STAT 2
+.Os
+.Sh NAME
+.Nm stat ,
+.Nm lstat ,
+.Nm fstat
+.Nd get file status
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/stat.h
+.Ft int
+.Fn stat "const char *path" "struct stat *sb"
+.Ft int
+.Fn lstat "const char *path" "struct stat *sb"
+.Ft int
+.Fn fstat "int fd" "struct stat *sb"
+.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
+.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_birthtime"
+.It Va st_atime
+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_mtime
+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_ctime
+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_birthtime
+Time when the inode was created.
+.El
+.Pp
+If
+.Dv _POSIX_SOURCE
+is not defined, the time-related fields are defined as:
+.Bd -literal
+#ifndef _POSIX_SOURCE
+#define st_atime st_atimespec.tv_sec
+#define st_mtime st_mtimespec.tv_sec
+#define st_ctime st_ctimespec.tv_sec
+#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 */
+#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_IRUSR 0000400 /* read permission, owner */
+#define S_IWUSR 0000200 /* write permission, owner */
+#define S_IXUSR 0000100 /* execute/search permission, owner */
+.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
+.Bl -tag -width Er
+The
+.Fn fstat
+system call will fail if:
+.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
+.Sh SEE ALSO
+.Xr access 2 ,
+.Xr chmod 2 ,
+.Xr chown 2 ,
+.Xr fhstat 2 ,
+.Xr utimes 2 ,
+.Xr symlink 7 ,
+.Xr sticky 8
+.Sh STANDARDS
+The
+.Fn stat
+and
+.Fn fstat
+system calls are expected to conform to
+.St -p1003.1-90 .
+.Sh HISTORY
+The
+.Fn stat
+and
+.Fn fstat
+system calls appeared in
+.At v7 .
+The
+.Fn lstat
+system call appeared in
+.Bx 4.2 .
+.Sh BUGS
+Applying
+.Fn fstat
+to a socket (and thus to a pipe)
+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 0000000..041a8df
--- /dev/null
+++ b/lib/libc/sys/statfs.2
@@ -0,0 +1,236 @@
+.\" Copyright (c) 1989, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. 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.
+.\"
+.\" @(#)statfs.2 8.5 (Berkeley) 5/24/95
+.\" $FreeBSD$
+.\"
+.Dd November 26, 2004
+.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_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/swapon.2 b/lib/libc/sys/swapon.2
new file mode 100644
index 0000000..29e9da5
--- /dev/null
+++ b/lib/libc/sys/swapon.2
@@ -0,0 +1,151 @@
+.\" 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. 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.
+.\"
+.\" @(#)swapon.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.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 EINVAL
+The system has reached the boot-time limit on the number of
+swap devices,
+.Va vm.nswapdev .
+.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 0000000..19fa7fa
--- /dev/null
+++ b/lib/libc/sys/symlink.2
@@ -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. 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.
+.\"
+.\" @(#)symlink.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt SYMLINK 2
+.Os
+.Sh NAME
+.Nm symlink
+.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"
+.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.
+.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
+prefix is 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
+The named file does not exist.
+.It Bq Er EACCES
+A component of the
+.Fa name2
+path prefix denies search permission.
+.It Bq Er ELOOP
+Too many symbolic links were encountered in translating the pathname.
+.It Bq Er EEXIST
+The path name pointed at by the
+.Fa name2
+argument
+already exists.
+.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
+.Sh SEE ALSO
+.Xr ln 1 ,
+.Xr link 2 ,
+.Xr lstat 2 ,
+.Xr readlink 2 ,
+.Xr unlink 2 ,
+.Xr symlink 7
+.Sh HISTORY
+The
+.Fn symlink
+system call appeared in
+.Bx 4.2 .
diff --git a/lib/libc/sys/sync.2 b/lib/libc/sys/sync.2
new file mode 100644
index 0000000..6e9b78b
--- /dev/null
+++ b/lib/libc/sys/sync.2
@@ -0,0 +1,81 @@
+.\" 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. 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.
+.\"
+.\" @(#)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 user 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 0000000..9d8f050
--- /dev/null
+++ b/lib/libc/sys/sysarch.2
@@ -0,0 +1,85 @@
+.\" $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.
+.\" 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.
+.\"
+.\" 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 0000000..4e7241e
--- /dev/null
+++ b/lib/libc/sys/syscall.2
@@ -0,0 +1,81 @@
+.\" 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. 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.
+.\"
+.\" @(#)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/timer_create.2 b/lib/libc/sys/timer_create.2
new file mode 100644
index 0000000..7202bc6
--- /dev/null
+++ b/lib/libc/sys/timer_create.2
@@ -0,0 +1,162 @@
+.\" 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_CREATE 2
+.Os
+.Sh NAME
+.Nm timer_create
+.Nd "create a per-process timer (REALTIME)"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In time.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.
+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, and the
+.Va sigev_value
+member having
+the value of the timer ID.
+.Pp
+The implementations supports a
+.Fa clock_id
+of
+.Dv CLOCK_REALTIME
+or
+.Dv CLOCK_MONOTONIC .
+.Pp
+If
+.Fa evp->sigev_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 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_getoverun 2 ,
+.Xr siginfo 3
+.Sh STANDARDS
+The
+.Fn timer_create
+system call conforms to
+.St -p1003.1-2004
+.Sh HISTORY
+Support for 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 0000000..97524a1
--- /dev/null
+++ b/lib/libc/sys/timer_delete.2
@@ -0,0 +1,78 @@
+.\" 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 libc
+.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 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 0000000..330410d
--- /dev/null
+++ b/lib/libc/sys/timer_settime.2
@@ -0,0 +1,263 @@
+.\" 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 libc
+.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 POSIX per-process timer first appeared in
+.Fx 7.0 .
diff --git a/lib/libc/sys/truncate.2 b/lib/libc/sys/truncate.2
new file mode 100644
index 0000000..08cc947
--- /dev/null
+++ b/lib/libc/sys/truncate.2
@@ -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. 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.
+.\"
+.\" @(#)truncate.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.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.
+With
+.Fn ftruncate ,
+the file must be open for writing.
+.Sh RETURN VALUES
+.Rv -std
+.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 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 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 socket, not a file.
+.It Bq Er EINVAL
+The
+.Fa fd
+descriptor
+is not open for writing.
+.El
+.Sh SEE ALSO
+.Xr open 2
+.Sh HISTORY
+The
+.Fn truncate
+system call 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/truncate.c b/lib/libc/sys/truncate.c
new file mode 100644
index 0000000..cedfd5b
--- /dev/null
+++ b/lib/libc/sys/truncate.c
@@ -0,0 +1,56 @@
+/*
+ * 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. 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)truncate.c 8.1 (Berkeley) 6/17/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/syscall.h>
+
+#include <unistd.h>
+
+/*
+ * This function provides 64-bit offset padding that
+ * is not supplied by GCC 1.X but is supplied by GCC 2.X.
+ */
+int
+truncate(path, length)
+ const char *path;
+ off_t length;
+{
+
+ return(__syscall((quad_t)SYS_truncate, path, 0, length));
+}
diff --git a/lib/libc/sys/umask.2 b/lib/libc/sys/umask.2
new file mode 100644
index 0000000..983ce65
--- /dev/null
+++ b/lib/libc/sys/umask.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.
+.\" 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.
+.\"
+.\" @(#)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 0000000..c52cc02
--- /dev/null
+++ b/lib/libc/sys/undelete.2
@@ -0,0 +1,109 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)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 0000000..40bbc33
--- /dev/null
+++ b/lib/libc/sys/unlink.2
@@ -0,0 +1,129 @@
+.\" 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. 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.
+.\"
+.\" @(#)unlink.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd February 23, 2005
+.Dt UNLINK 2
+.Os
+.Sh NAME
+.Nm unlink
+.Nd remove directory entry
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fn unlink "const char *path"
+.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.
+.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 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 or append-only
+flag set, see the
+.Xr chflags 2
+manual page for more information.
+.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 EBUSY
+The entry to be unlinked 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 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.
+.El
+.Sh SEE ALSO
+.Xr chflags 2 ,
+.Xr close 2 ,
+.Xr link 2 ,
+.Xr rmdir 2 ,
+.Xr symlink 7
+.Sh HISTORY
+The
+.Fn unlink
+function appeared in
+.At v6 .
+.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/utimes.2 b/lib/libc/sys/utimes.2
new file mode 100644
index 0000000..30085e4
--- /dev/null
+++ b/lib/libc/sys/utimes.2
@@ -0,0 +1,213 @@
+.\" $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.
+.\" 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.
+.\"
+.\" @(#)utimes.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd January 5, 2006
+.Dt UTIMES 2
+.Os
+.Sh NAME
+.Nm utimes ,
+.Nm lutimes ,
+.Nm futimes
+.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"
+.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 .
+.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.
+.Sh RETURN VALUES
+.Rv -std
+.Sh ERRORS
+The
+.Fn utimes
+and
+.Fn lutimes
+system calls
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EACCES
+Search permission is denied for a component of the path prefix;
+or 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 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 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
+All of the system calls will fail if:
+.Bl -tag -width Er
+.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 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 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 EROFS
+The file system containing the file is mounted read-only.
+.El
+.Sh SEE ALSO
+.Xr stat 2 ,
+.Xr utime 3
+.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 .
diff --git a/lib/libc/sys/utrace.2 b/lib/libc/sys/utrace.2
new file mode 100644
index 0000000..a83c185
--- /dev/null
+++ b/lib/libc/sys/utrace.2
@@ -0,0 +1,86 @@
+.\" $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.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the NetBSD
+.\" Foundation, Inc. and its contributors.
+.\" 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 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 28, 2000
+.Dt UTRACE 2
+.Os
+.Sh NAME
+.Nm utrace
+.Nd insert user record in ktrace log
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.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 ktrace 2
+.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 0000000..9c90102
--- /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 0000000..498ee11
--- /dev/null
+++ b/lib/libc/sys/vfork.2
@@ -0,0 +1,141 @@
+.\" 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. 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.
+.\"
+.\" @(#)vfork.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt VFORK 2
+.Os
+.Sh NAME
+.Nm vfork
+.Nd spawn new process in a virtual memory efficient way
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft pid_t
+.Fn vfork void
+.Sh DESCRIPTION
+The
+.Fn vfork
+system call
+can be used to create new processes without fully copying the address
+space of the old process, which is horrendously 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's memory and thread of
+control until a call to
+.Xr execve 2
+or an exit (either by a call to
+.Xr _exit 2
+or abnormally).
+The parent process is suspended while the child is using its resources.
+.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
+The
+.Fn vfork
+system call
+can normally be used just like
+.Xr fork 2 .
+It does not work, however, 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.
+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 execve 2 ,
+.Xr _exit 2 ,
+.Xr fork 2 ,
+.Xr rfork 2 ,
+.Xr sigvec 2 ,
+.Xr wait 2 ,
+.Xr exit 3
+.Sh HISTORY
+The
+.Fn vfork
+system call appeared in
+.Bx 2.9 .
+.Sh BUGS
+This system call will be eliminated when proper system sharing
+mechanisms are implemented.
+Users should not depend on the memory
+sharing semantics of
+.Fn vfork
+as it will, in that case, be made synonymous to
+.Xr fork 2 .
+.Pp
+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 0000000..e9fc09b
--- /dev/null
+++ b/lib/libc/sys/wait.2
@@ -0,0 +1,348 @@
+.\" 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.
+.\" 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.
+.\"
+.\" @(#)wait.2 8.2 (Berkeley) 4/19/94
+.\" $FreeBSD$
+.\"
+.Dd November 12, 2005
+.Dt WAIT 2
+.Os
+.Sh NAME
+.Nm wait ,
+.Nm waitpid ,
+.Nm wait4 ,
+.Nm wait3
+.Nd wait for process termination
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/wait.h
+.Ft pid_t
+.Fn wait "int *status"
+.In sys/time.h
+.In sys/resource.h
+.Ft pid_t
+.Fn waitpid "pid_t wpid" "int *status" "int options"
+.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"
+.Sh DESCRIPTION
+The
+.Fn wait
+function suspends execution of its calling process until
+.Fa status
+information is available for a terminated child process,
+or a signal is received.
+On return from a successful
+.Fn wait
+call,
+the
+.Fa status
+area contains termination information about the process that exited
+as defined below.
+.Pp
+The
+.Fn wait4
+system call provides a more general interface for programs
+that need to wait for certain child processes,
+that need resource utilization statistics accumulated by child processes,
+or that require options.
+The other wait functions are implemented using
+.Fn wait4 .
+.Pp
+The
+.Fa wpid
+argument specifies the set of child processes for which to wait.
+If
+.Fa wpid
+is -1, the call waits for any child process.
+If
+.Fa wpid
+is 0,
+the call waits for any child process in the process group of the caller.
+If
+.Fa wpid
+is greater than zero, the call waits for the process with process id
+.Fa wpid .
+If
+.Fa wpid
+is less than -1, the call waits for any process whose process group id
+equals the absolute value of
+.Fa wpid .
+.Pp
+The
+.Fa status
+argument is defined below.
+The
+.Fa options
+argument contains the bitwise OR of any of the following options.
+The
+.Dv WCONTINUED
+option indicates that children of the current process that
+have continued from a job control stop, by receiving a
+.Dv SIGCONT
+signal, should also have their status reported.
+The
+.Dv WNOHANG
+option
+is used to indicate that the call should not block if
+there are no processes that wish to report status.
+If the
+.Dv WUNTRACED
+option is set,
+children of the current process that are stopped
+due to a
+.Dv SIGTTIN , SIGTTOU , SIGTSTP ,
+or
+.Dv SIGSTOP
+signal also have
+their status reported.
+.Pp
+If
+.Fa rusage
+is non-zero, a summary of the resources used by the terminated
+process and all its
+children is returned (this information is currently not available
+for stopped or continued processes).
+.Pp
+When the
+.Dv WNOHANG
+option is specified and no processes
+wish to report status,
+.Fn wait4
+returns a
+process id
+of 0.
+.Pp
+The
+.Fn waitpid
+function is identical to
+.Fn wait4
+with an
+.Fa rusage
+value of zero.
+The older
+.Fn wait3
+call is the same as
+.Fn wait4
+with a
+.Fa wpid
+value of -1.
+.Pp
+The following macros may be used to test the manner of exit of the process.
+One of the first three macros will evaluate to a non-zero (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,
+.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 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.
+.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.
+.El
+.Sh SEE ALSO
+.Xr _exit 2 ,
+.Xr ptrace 2 ,
+.Xr sigaction 2 ,
+.Xr exit 3 ,
+.Xr siginfo 3
+.Sh STANDARDS
+The
+.Fn wait
+and
+.Fn waitpid
+functions are defined by POSIX;
+.Fn wait4
+and
+.Fn wait3
+are not specified by POSIX.
+The
+.Fn WCOREDUMP
+macro
+and the ability to restart a pending
+.Fn wait
+call are extensions to the POSIX interface.
+.Sh HISTORY
+The
+.Fn wait
+function appeared in
+.At v6 .
diff --git a/lib/libc/sys/write.2 b/lib/libc/sys/write.2
new file mode 100644
index 0000000..428e703
--- /dev/null
+++ b/lib/libc/sys/write.2
@@ -0,0 +1,290 @@
+.\" 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. 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.
+.\"
+.\" @(#)write.2 8.5 (Berkeley) 4/2/94
+.\" $FreeBSD$
+.\"
+.Dd July 7, 2005
+.Dt WRITE 2
+.Os
+.Sh NAME
+.Nm write ,
+.Nm writev ,
+.Nm pwrite ,
+.Nm pwritev
+.Nd write output
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/uio.h
+.In unistd.h
+.Ft ssize_t
+.Fn write "int d" "const void *buf" "size_t nbytes"
+.Ft ssize_t
+.Fn pwrite "int d" "const void *buf" "size_t nbytes" "off_t offset"
+.Ft ssize_t
+.Fn writev "int d" "const struct iovec *iov" "int iovcnt"
+.Ft ssize_t
+.Fn pwritev "int d" "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 d
+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 d ,
+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 d
+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 d
+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/uuid/Makefile.inc b/lib/libc/uuid/Makefile.inc
new file mode 100644
index 0000000..d2ef521
--- /dev/null
+++ b/lib/libc/uuid/Makefile.inc
@@ -0,0 +1,19 @@
+# $FreeBSD$
+
+# DCE 1.1 UUID implementation sources
+
+.PATH: ${.CURDIR}/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_to_string.c
+SYM_MAPS+= ${.CURDIR}/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_to_string.3
diff --git a/lib/libc/uuid/Symbol.map b/lib/libc/uuid/Symbol.map
new file mode 100644
index 0000000..cf1dba6
--- /dev/null
+++ b/lib/libc/uuid/Symbol.map
@@ -0,0 +1,12 @@
+# $FreeBSD$
+
+FBSD_1.0 {
+ uuid_to_string;
+ uuid_is_nil;
+ uuid_hash;
+ uuid_from_string;
+ uuid_equal;
+ uuid_create_nil;
+ uuid_create;
+ uuid_compare;
+};
diff --git a/lib/libc/uuid/uuid.3 b/lib/libc/uuid/uuid.3
new file mode 100644
index 0000000..08cf737
--- /dev/null
+++ b/lib/libc/uuid/uuid.3
@@ -0,0 +1,100 @@
+.\" 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 January 3, 2005
+.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"
+.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 .
+.Sh RETURN VALUES
+The successful or unsuccessful completion of the function is returned in
+the
+.Fa status
+argument.
+Possible values are:
+.Pp
+.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 meaning of the code escaped the writers mind.
+.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 0000000..f57a094
--- /dev/null
+++ b/lib/libc/uuid/uuid_compare.c
@@ -0,0 +1,78 @@
+/*-
+ * 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_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. */
+ res = (int)((int64_t)a->time_low - (int64_t)b->time_low);
+ if (res)
+ return ((res < 0) ? -1 : 1);
+ res = (int)a->time_mid - (int)b->time_mid;
+ if (res)
+ return ((res < 0) ? -1 : 1);
+ res = (int)a->time_hi_and_version - (int)b->time_hi_and_version;
+ if (res)
+ return ((res < 0) ? -1 : 1);
+ res = (int)a->clock_seq_hi_and_reserved -
+ (int)b->clock_seq_hi_and_reserved;
+ if (res)
+ return ((res < 0) ? -1 : 1);
+ res = (int)a->clock_seq_low - (int)b->clock_seq_low;
+ if (res)
+ return ((res < 0) ? -1 : 1);
+ res = memcmp(a->node, b->node, sizeof(a->node));
+ if (res)
+ return ((res < 0) ? -1 : 1);
+ return (0);
+}
diff --git a/lib/libc/uuid/uuid_create.c b/lib/libc/uuid/uuid_create.c
new file mode 100644
index 0000000..da3f1d3
--- /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 0000000..6e85ae7
--- /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 0000000..e4c48e5
--- /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 0000000..b09a04d
--- /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 0000000..e5695ee
--- /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 0000000..ee18653
--- /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_to_string.c b/lib/libc/uuid/uuid_to_string.c
new file mode 100644
index 0000000..f816391
--- /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 == 0)
+ 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/xdr/Makefile.inc b/lib/libc/xdr/Makefile.inc
new file mode 100644
index 0000000..2d360ac
--- /dev/null
+++ b/lib/libc/xdr/Makefile.inc
@@ -0,0 +1,50 @@
+# @(#)Makefile 5.11 (Berkeley) 9/6/90
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/xdr ${.CURDIR}/.
+SRCS+= xdr.c xdr_array.c xdr_float.c xdr_mem.c \
+ xdr_rec.c xdr_reference.c xdr_stdio.c
+
+SYM_MAPS+= ${.CURDIR}/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 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 0000000..f279dc5
--- /dev/null
+++ b/lib/libc/xdr/Symbol.map
@@ -0,0 +1,45 @@
+# $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;
+ #xdr_sizeof; # Why is xdr_sizeof.c not included in Makefileinc?
+ xdrstdio_create;
+};
diff --git a/lib/libc/xdr/xdr.3 b/lib/libc/xdr/xdr.3
new file mode 100644
index 0000000..19c7e57
--- /dev/null
+++ b/lib/libc/xdr/xdr.3
@@ -0,0 +1,829 @@
+.\" @(#)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 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 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
diff --git a/lib/libc/xdr/xdr.c b/lib/libc/xdr/xdr.c
new file mode 100644
index 0000000..c1e5eec
--- /dev/null
+++ b/lib/libc/xdr/xdr.c
@@ -0,0 +1,875 @@
+/* $NetBSD: xdr.c,v 1.22 2000/07/06 03:10:35 christos Exp $ */
+
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#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.
+ *
+ * Copyright (C) 1986, Sun Microsystems, Inc.
+ *
+ * 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(proc, objp)
+ 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(xdrs, ip)
+ 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(xdrs, up)
+ 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(xdrs, lp)
+ 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(xdrs, ulp)
+ 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(xdrs, int32_p)
+ 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(xdrs, u_int32_p)
+ 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 short integers
+ */
+bool_t
+xdr_short(xdrs, sp)
+ 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(xdrs, usp)
+ 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(xdrs, int16_p)
+ 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(xdrs, u_int16_p)
+ 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 a char
+ */
+bool_t
+xdr_char(xdrs, cp)
+ 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(xdrs, cp)
+ 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(xdrs, bp)
+ 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(xdrs, ep)
+ 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(xdrs, cp, cnt)
+ 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(xdrs, cpp, sizep, maxsize)
+ 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(xdrs, np)
+ 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(xdrs, dscmp, unp, choices, 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(xdrs, cpp, maxsize)
+ 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(xdrs, cpp)
+ 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(xdrs, llp)
+ 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(xdrs, ullp)
+ 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 hypers
+ */
+bool_t
+xdr_hyper(xdrs, llp)
+ 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(xdrs, ullp)
+ 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(xdrs, llp)
+ 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(xdrs, ullp)
+ 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 0000000..6c35452
--- /dev/null
+++ b/lib/libc/xdr/xdr_array.c
@@ -0,0 +1,163 @@
+/* $NetBSD: xdr_array.c,v 1.12 2000/01/22 22:19:18 mycroft Exp $ */
+
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#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.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * 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(xdrs, addrp, sizep, maxsize, elsize, 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(xdrs, basep, nelem, elemsize, xdr_elem)
+ 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 0000000..0a4f09f
--- /dev/null
+++ b/lib/libc/xdr/xdr_float.c
@@ -0,0 +1,309 @@
+/* $NetBSD: xdr_float.c,v 1.23 2000/07/17 04:59:51 matt Exp $ */
+
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#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.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * 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/types.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.
+ */
+
+#if defined(__m68k__) || defined(__sparc__) || defined(__i386__) || \
+ defined(__mips__) || defined(__ns32k__) || defined(__alpha__) || \
+ defined(__arm__) || defined(__ppc__) || defined(__ia64__) || \
+ defined(__arm26__) || defined(__sparc64__) || defined(__amd64__)
+#include <machine/endian.h>
+#define IEEEFP
+#endif
+
+#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(xdrs, fp)
+ XDR *xdrs;
+ float *fp;
+{
+#ifndef IEEEFP
+ struct ieee_single is;
+ struct vax_single vs, *vsp;
+ struct sgl_limits *lim;
+ 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 < sizeof(sgl_limits)/sizeof(struct 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 < sizeof(sgl_limits)/sizeof(struct 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(xdrs, dp)
+ 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;
+ 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 < sizeof(dbl_limits)/sizeof(struct 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 < sizeof(dbl_limits)/sizeof(struct 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 0000000..138269c
--- /dev/null
+++ b/lib/libc/xdr/xdr_mem.c
@@ -0,0 +1,260 @@
+/* $NetBSD: xdr_mem.c,v 1.15 2000/01/22 22:19:18 mycroft Exp $ */
+
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#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.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * 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(xdrs, addr, size, op)
+ 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(xdrs)
+ XDR *xdrs;
+{
+
+}
+
+static bool_t
+xdrmem_getlong_aligned(xdrs, lp)
+ 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(xdrs, lp)
+ 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(xdrs, lp)
+ 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(xdrs, lp)
+ 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(xdrs, addr, len)
+ 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(xdrs, addr, len)
+ 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(xdrs)
+ 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(xdrs, pos)
+ 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(xdrs, len)
+ XDR *xdrs;
+ u_int len;
+{
+ int32_t *buf = 0;
+
+ 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(xdrs, len)
+ 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 0000000..a50d141
--- /dev/null
+++ b/lib/libc/xdr/xdr_rec.c
@@ -0,0 +1,788 @@
+/* $NetBSD: xdr_rec.c,v 1.18 2000/07/06 03:10:35 christos Exp $ */
+
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#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).
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * 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)(1 << 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(xdrs, sendsize, recvsize, tcp_handle, readit, writeit)
+ 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(xdrs, lp)
+ 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(xdrs, lp)
+ 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(xdrs, addr, len)
+ 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(xdrs, addr, len)
+ 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(xdrs)
+ 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)
+ 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(xdrs, pos)
+ 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(xdrs, len)
+ 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(xdrs)
+ 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(xdrs)
+ 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(xdrs)
+ 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(xdrs, sendnow)
+ 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(xdrs, statp, expectdata)
+ 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;
+ }
+ }
+
+ 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(xdrs, maxrec)
+ 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(rstrm, eor)
+ 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(rstrm)
+ 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(rstrm, addr, len)
+ 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(rstrm)
+ 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(rstrm, cnt)
+ 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(s)
+ 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(rstrm, size)
+ 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 0000000..5a497b6
--- /dev/null
+++ b/lib/libc/xdr/xdr_reference.c
@@ -0,0 +1,143 @@
+/* $NetBSD: xdr_reference.c,v 1.13 2000/01/22 22:19:18 mycroft Exp $ */
+
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#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.
+ *
+ * Copyright (C) 1987, Sun Microsystems, Inc.
+ *
+ * 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(xdrs, pp, size, 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(xdrs,objpp,obj_size,xdr_obj)
+ 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 0000000..20f1c3a
--- /dev/null
+++ b/lib/libc/xdr/xdr_sizeof.c
@@ -0,0 +1,168 @@
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+/*
+ * xdr_sizeof.c
+ *
+ * Copyright 1990 Sun Microsystems, Inc.
+ *
+ * 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(xdrs, longp)
+ XDR *xdrs;
+ long *longp;
+{
+ xdrs->x_handy += BYTES_PER_XDR_UNIT;
+ return (TRUE);
+}
+
+/* ARGSUSED */
+static bool_t
+x_putbytes(xdrs, bp, len)
+ XDR *xdrs;
+ char *bp;
+ u_int len;
+{
+ xdrs->x_handy += len;
+ return (TRUE);
+}
+
+static u_int
+x_getpostn(xdrs)
+ XDR *xdrs;
+{
+ return (xdrs->x_handy);
+}
+
+/* ARGSUSED */
+static bool_t
+x_setpostn(xdrs, pos)
+ XDR *xdrs;
+ u_int pos;
+{
+ /* This is not allowed */
+ return (FALSE);
+}
+
+static int32_t *
+x_inline(xdrs, len)
+ XDR *xdrs;
+ u_int len;
+{
+ if (len == 0) {
+ return (NULL);
+ }
+ if (xdrs->x_op != XDR_ENCODE) {
+ return (NULL);
+ }
+ if (len < (u_int)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) len;
+ xdrs->x_handy += len;
+ return ((int32_t *) xdrs->x_private);
+ }
+}
+
+static int
+harmless()
+{
+ /* Always return FALSE/NULL, as the case may be */
+ return (0);
+}
+
+static void
+x_destroy(xdrs)
+ 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(func, data)
+ 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 0000000..8c1724d
--- /dev/null
+++ b/lib/libc/xdr/xdr_stdio.c
@@ -0,0 +1,196 @@
+/* $NetBSD: xdr_stdio.c,v 1.14 2000/01/22 22:19:19 mycroft Exp $ */
+
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#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.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * 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(xdrs, file, op)
+ 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(xdrs)
+ XDR *xdrs;
+{
+ (void)fflush((FILE *)xdrs->x_private);
+ /* XXX: should we close the file ?? */
+}
+
+static bool_t
+xdrstdio_getlong(xdrs, lp)
+ 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(xdrs, lp)
+ 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(xdrs, addr, len)
+ 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(xdrs, addr, len)
+ 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(xdrs)
+ XDR *xdrs;
+{
+
+ return ((u_int) ftell((FILE *)xdrs->x_private));
+}
+
+static bool_t
+xdrstdio_setpos(xdrs, pos)
+ XDR *xdrs;
+ u_int pos;
+{
+
+ return ((fseek((FILE *)xdrs->x_private, (long)pos, 0) < 0) ?
+ FALSE : TRUE);
+}
+
+/* ARGSUSED */
+static int32_t *
+xdrstdio_inline(xdrs, len)
+ 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 0000000..842e63e
--- /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: ${.CURDIR}/yp
+
+SRCS+= xdryp.c yp.h yp_xdr.c yplib.c
+CLEANFILES+= yp.h yp_xdr.c
+
+SYM_MAPS+= ${.CURDIR}/yp/Symbol.map
+
+RPCSRC= ${DESTDIR}/usr/include/rpcsvc/yp.x
+RPCGEN= 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 0000000..4fdc707
--- /dev/null
+++ b/lib/libc/yp/Symbol.map
@@ -0,0 +1,23 @@
+# $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 0000000..7aed6ad
--- /dev/null
+++ b/lib/libc/yp/xdryp.c
@@ -0,0 +1,114 @@
+/*
+ * 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 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);
+ 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);
+ 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 0000000..74a791e
--- /dev/null
+++ b/lib/libc/yp/yplib.c
@@ -0,0 +1,1166 @@
+/*
+ * 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/types.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 = 10;
+
+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 = ypdb->cache;
+
+ 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);
+ 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)) == -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;
+ }
+
+ 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;
+
+ *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);
+ bcopy(yprv.val.valdat_val, *outval, *outvallen);
+ (*outval)[*outvallen] = '\0';
+ YPUNLOCK();
+ return (0);
+ }
+#endif
+
+again:
+ 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);
+ goto again;
+ }
+
+ if (!(r = ypprot_err(yprv.stat))) {
+ *outvallen = yprv.val.valdat_len;
+ *outval = (char *)malloc(*outvallen+1);
+ 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;
+
+ /* Sanity check */
+
+ if (indomain == NULL || !strlen(indomain) ||
+ inmap == NULL || !strlen(inmap))
+ return (YPERR_BADARGS);
+
+ *outkey = *outval = NULL;
+ *outkeylen = *outvallen = 0;
+
+ 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 *)&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);
+ goto again;
+ }
+ if (!(r = ypprot_err(yprkv.stat))) {
+ *outkeylen = yprkv.key.keydat_len;
+ *outkey = (char *)malloc(*outkeylen+1);
+ bcopy(yprkv.key.keydat_val, *outkey, *outkeylen);
+ (*outkey)[*outkeylen] = '\0';
+ *outvallen = yprkv.val.valdat_len;
+ *outval = (char *)malloc(*outvallen+1);
+ 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;
+
+ /* 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 (_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);
+ goto again;
+ }
+ if (!(r = ypprot_err(yprkv.stat))) {
+ *outkeylen = yprkv.key.keydat_len;
+ *outkey = (char *)malloc(*outkeylen+1);
+ bcopy(yprkv.key.keydat_val, *outkey, *outkeylen);
+ (*outkey)[*outkeylen] = '\0';
+ *outvallen = yprkv.val.valdat_len;
+ *outval = (char *)malloc(*outvallen+1);
+ 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;
+
+ /* 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;
+
+ /* 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(ysd->dom_client, "yp_all: clnt_call");
+ clnt_destroy(clnt);
+ _yp_unbind(ysd);
+ 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);
+}
diff --git a/lib/libc_r/Makefile b/lib/libc_r/Makefile
new file mode 100644
index 0000000..bd8a2b5
--- /dev/null
+++ b/lib/libc_r/Makefile
@@ -0,0 +1,38 @@
+# $FreeBSD$
+#
+# 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 included legacy CSRG sccsid strings, add -DLIBC_SCCS and -DSYSLIBC_SCCS
+# (for system call stubs) to CFLAGS below. -DSYSLIBC_SCCS affects just the
+# system call stubs.
+LIB=c_r
+SHLIB_MAJOR= 6
+CFLAGS+=-DPTHREAD_KERNEL
+CFLAGS+=-I${.CURDIR}/../libc/include -I${.CURDIR}/uthread \
+ -I${.CURDIR}/../../include
+
+# Uncomment this if you want libc_r to contain debug information for
+# thread locking.
+CFLAGS+=-D_LOCK_DEBUG
+
+# enable extra internal consistancy checks
+CFLAGS+=-D_PTHREADS_INVARIANTS
+
+PRECIOUSLIB=
+
+.include "${.CURDIR}/uthread/Makefile.inc"
+.include "${.CURDIR}/sys/Makefile.inc"
+
+.if ${MACHINE_ARCH} == "alpha" || ${MACHINE_ARCH} == "sparc64"
+SYMLINKS+=lib${LIB}.a ${LIBDIR}/libpthread.a
+.if !defined(NO_PIC)
+SYMLINKS+=lib${LIB}.so ${LIBDIR}/libpthread.so
+.endif
+.if ${MK_PROFILE} != "no"
+SYMLINKS+=lib${LIB}_p.a ${LIBDIR}/libpthread_p.a
+.endif
+.endif
+
+.include <bsd.lib.mk>
diff --git a/lib/libc_r/arch/alpha/_atomic_lock.S b/lib/libc_r/arch/alpha/_atomic_lock.S
new file mode 100644
index 0000000..1ddceb0
--- /dev/null
+++ b/lib/libc_r/arch/alpha/_atomic_lock.S
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 1998 John Birrell <jb@cimlogic.com.au>.
+ * All rights reserved.
+ * copyright Douglas Santry 1996
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the above copyright is retained
+ * in the source form.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Douglas Santry AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Douglas Santry OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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/asm.h>
+
+/*
+ * Atomicly lock a location with an identifier provided the location
+ * is not currently locked.
+ *
+ * long _atomic_lock(long *);
+ * v0 will contain the return value (zero if lock obtained).
+ */
+LEAF(_atomic_lock,0)
+ LDGP(pv)
+
+0: ldq_l v0, 0(a0) /* read existing lock value */
+ mov 1, t0 /* locked value to store */
+ stq_c t0, 0(a0) /* attempt to store, status in t0 */
+ beq t0, 1f /* branch foward to optimise prediction */
+ mb /* sync with other processors */
+ RET /* return with v0==0 if lock obtained */
+1: br 0b /* loop to try again */
+END(_atomic_lock)
diff --git a/lib/libc_r/arch/amd64/_atomic_lock.S b/lib/libc_r/arch/amd64/_atomic_lock.S
new file mode 100644
index 0000000..aaab081
--- /dev/null
+++ b/lib/libc_r/arch/amd64/_atomic_lock.S
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>.
+ * All rights reserved.
+ * copyright Douglas Santry 1996
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the above copyright is retained
+ * in the source form.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Douglas Santry AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Douglas Santry OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_RCS) && !defined(lint)
+ .text
+ .asciz "$FreeBSD$"
+#endif /* LIBC_RCS and not lint */
+
+#include <machine/asm.h>
+
+/*
+ * Atomicly lock a location with an identifier provided the location
+ * is not currently locked.
+ *
+ * long _atomic_lock(long *);
+ * eax will contain the return value (zero if lock obtained).
+ */
+ENTRY(_atomic_lock)
+ movl $1, %eax
+ xchgq %rax, (%rdi)
+ ret
+
diff --git a/lib/libc_r/arch/i386/_atomic_lock.S b/lib/libc_r/arch/i386/_atomic_lock.S
new file mode 100644
index 0000000..af49aff
--- /dev/null
+++ b/lib/libc_r/arch/i386/_atomic_lock.S
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>.
+ * All rights reserved.
+ * copyright Douglas Santry 1996
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the above copyright is retained
+ * in the source form.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Douglas Santry AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Douglas Santry OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_RCS) && !defined(lint)
+ .text
+ .asciz "$FreeBSD$"
+#endif /* LIBC_RCS and not lint */
+
+#include <machine/asm.h>
+
+/*
+ * Atomicly lock a location with an identifier provided the location
+ * is not currently locked.
+ *
+ * long _atomic_lock(long *);
+ * eax will contain the return value (zero if lock obtained).
+ */
+ENTRY(_atomic_lock)
+ movl 4(%esp), %ecx
+ movl $1, %eax
+ xchg %eax, (%ecx)
+ ret
+
diff --git a/lib/libc_r/arch/ia64/_atomic_lock.S b/lib/libc_r/arch/ia64/_atomic_lock.S
new file mode 100644
index 0000000..b4b84da
--- /dev/null
+++ b/lib/libc_r/arch/ia64/_atomic_lock.S
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+#if defined(LIBC_RCS) && !defined(lint)
+ .text
+ .asciz "$FreeBSD$"
+#endif /* LIBC_RCS and not lint */
+
+#include <machine/asm.h>
+
+/*
+ * Atomicly lock a location with an identifier provided the location
+ * is not currently locked.
+ *
+ * long _atomic_lock(long *);
+ */
+ENTRY(_atomic_lock, 1)
+ mov ar.ccv = r0
+ add r14 = 1, r0
+ nop 0
+ ;;
+ cmpxchg8.acq r8 = [r32], r14, ar.ccv
+ br.ret.sptk rp
+END(_atomic_lock)
diff --git a/lib/libc_r/arch/sparc64/_atomic_lock.S b/lib/libc_r/arch/sparc64/_atomic_lock.S
new file mode 100644
index 0000000..ce931df
--- /dev/null
+++ b/lib/libc_r/arch/sparc64/_atomic_lock.S
@@ -0,0 +1,45 @@
+/*-
+ * Copyright (c) 2002 Dag-Erling Coïdan Smørgrav
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 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 <machine/asm.h>
+
+__FBSDID("$FreeBSD$");
+
+/*
+ * long _atomic_lock(long *)
+ *
+ * Atomically acquire a lock by storing a non-zero value in its
+ * location, provided it is not already locked. Note that we only use
+ * the first byte of the location provided.
+ */
+ENTRY(_atomic_lock)
+ ldstub [%o0], %o1
+ membar #LoadLoad | #StoreStore
+ retl
+ mov %o1, %o0
+END(_atomic_lock)
diff --git a/lib/libc_r/sys/Makefile.inc b/lib/libc_r/sys/Makefile.inc
new file mode 100644
index 0000000..e608afa
--- /dev/null
+++ b/lib/libc_r/sys/Makefile.inc
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/sys ${.CURDIR}/arch/${MACHINE_ARCH}
+
+SRCS+= uthread_error.c _atomic_lock.S
+
diff --git a/lib/libc_r/sys/uthread_error.c b/lib/libc_r/sys/uthread_error.c
new file mode 100644
index 0000000..8c52967
--- /dev/null
+++ b/lib/libc_r/sys/uthread_error.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.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 John Birrell
+ * and Chris Provenzano.
+ * 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 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$
+ */
+#include <pthread.h>
+#include "pthread_private.h"
+extern int errno;
+
+int * __error()
+{
+ int *p_errno;
+ if (_thread_run == _thread_initial) {
+ p_errno = &errno;
+ } else {
+ p_errno = &_thread_run->error;
+ }
+ return(p_errno);
+}
diff --git a/lib/libc_r/test/Makefile b/lib/libc_r/test/Makefile
new file mode 100644
index 0000000..0eb530c
--- /dev/null
+++ b/lib/libc_r/test/Makefile
@@ -0,0 +1,115 @@
+#
+# $FreeBSD$
+#
+# Automated test suite for libc_r (pthreads).
+#
+
+# File lists.
+
+# Tests written in C.
+CTESTS := hello_d.c hello_s.c join_leak_d.c mutex_d.c sem_d.c sigsuspend_d.c \
+ sigwait_d.c
+
+# C programs that are used internally by the tests. The build system merely
+# compiles these.
+BTESTS := guard_b.c hello_b.c
+
+# Tests written in perl.
+PTESTS := guard_s.pl propagate_s.pl
+
+# Munge the file lists to their final executable names (strip the .c).
+CTESTS := $(CTESTS:R)
+BTESTS := $(BTESTS:R)
+
+CPPFLAGS := -D_LIBC_R_ -D_REENTRANT
+CFLAGS := -Wall -pipe -g3
+LDFLAGS_A := -static
+LDFLAGS_P := -pg
+LDFLAGS_S :=
+LIBS := -lc_r
+
+# Flags passed to verify. "-v" or "-u" may be useful.
+VFLAGS :=
+
+all : default
+
+# Only use the following suffixes, in order to avoid any strange built-in rules.
+.SUFFIXES :
+.SUFFIXES : .c .o .d .pl
+
+# Clear out all paths, then set just one (default path) for the main build
+# directory.
+.PATH :
+.PATH : .
+
+# Build the C programs.
+.for bin in $(CTESTS) $(BTESTS)
+$(bin)_a : $(bin:S/$/&.c/)
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c $(bin:S/$/&.c/) -o $(@:S/$/&.o/)
+ $(CC) -o $@ $(@:S/$/&.o/) $(LDFLAGS_A) $(LIBS)
+ @$(SHELL) -ec "$(CC) -M $(CPPFLAGS) $(bin:S/$/&.c/) | sed \"s/\($(bin:T)\)\.o\([ :]*\)/$(bin:H:S!/!\\/!g)\/\1_a.o \2/g\" > $(@:R:S/$/&.d/)"
+
+$(bin)_p : $(bin:S/$/&.c/)
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c $(bin:S/$/&.c/) -o $(@:S/$/&.o/)
+ $(CC) -o $@ $(@:S/$/&.o/) $(LDFLAGS_P) $(LIBS)
+ @$(SHELL) -ec "$(CC) -M $(CPPFLAGS) $(bin:S/$/&.c/) | sed \"s/\($(bin:T)\)\.o\([ :]*\)/$(bin:H:S!/!\\/!g)\/\1_p.o \2/g\" > $(@:R:S/$/&.d/)"
+
+$(bin)_s : $(bin:S/$/&.c/)
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c $(bin:S/$/&.c/) -o $(@:S/$/&.o/)
+ $(CC) -o $@ $(@:S/$/&.o/) $(LDFLAGS_S) $(LIBS)
+ @$(SHELL) -ec "$(CC) -M $(CPPFLAGS) $(bin:S/$/&.c/) | sed \"s/\($(bin:T)\)\.o\([ :]*\)/$(bin:H:S!/!\\/!g)\/\1_s.o \2/g\" > $(@:R:S/$/&.d/)"
+.endfor
+
+# Dependency file inclusion.
+.for depfile in $(CTESTS:R:S/$/&_a.d/) $(BTESTS:R:S/$/&_a.d/) \
+ $(CTESTS:R:S/$/&_p.d/) $(BTESTS:R:S/$/&_p.d/) \
+ $(CTESTS:R:S/$/&_s.d/) $(BTESTS:R:S/$/&_s.d/)
+.if exists($(depfile))
+.include "$(depfile)"
+.endif
+.endfor
+
+default : check
+
+tests_a : $(CTESTS:S/$/&_a/) $(BTESTS:S/$/&_a/)
+tests_p : $(CTESTS:S/$/&_p/) $(BTESTS:S/$/&_p/)
+tests_s : $(CTESTS:S/$/&_s/) $(BTESTS:S/$/&_s/)
+
+tests : tests_a tests_p tests_s
+
+check_a : tests_a
+.for bin in $(CTESTS) $(BTESTS)
+ @cp $(bin)_a $(bin)
+.endfor
+ @echo "Test static library:"
+ @./verify $(VFLAGS) $(CTESTS) $(PTESTS)
+
+check_p : tests_p
+.for bin in $(CTESTS) $(BTESTS)
+ @cp $(bin)_p $(bin)
+.endfor
+ @echo "Test profile library:"
+ @./verify $(VFLAGS) $(CTESTS) $(PTESTS)
+
+check_s : tests_s
+.for bin in $(CTESTS) $(BTESTS)
+ @cp $(bin)_s $(bin)
+.endfor
+ @echo "Test shared library:"
+ @./verify $(VFLAGS) $(CTESTS) $(PTESTS)
+
+check : check_a check_p check_s
+
+clean :
+ rm -f *~
+ rm -f *.core
+ rm -f *.out
+ rm -f *.perf
+ rm -f *.diff
+ rm -f *.gmon
+ rm -f $(CTESTS) $(BTESTS)
+ rm -f $(CTESTS:S/$/&_a/) $(BTESTS:S/$/&_a/)
+ rm -f $(CTESTS:S/$/&_p/) $(BTESTS:S/$/&_p/)
+ rm -f $(CTESTS:S/$/&_s/) $(BTESTS:S/$/&_s/)
+ rm -f *.d
+ rm -f *.o
diff --git a/lib/libc_r/test/README b/lib/libc_r/test/README
new file mode 100644
index 0000000..507ea4e
--- /dev/null
+++ b/lib/libc_r/test/README
@@ -0,0 +1,28 @@
+$FreeBSD$
+
+This test suite is meant to test general functionality of pthreads, as well as
+provide a simple framework for regression tests. In general, this test suite
+can be used with any pthreads library, but in reality there are a number of
+libc_r-specific aspects to this test suite which would require some effort to
+get around if testing another pthreads library.
+
+This test suite assumes that libc_r is installed.
+
+There are two forms of test that the 'verify' script understands. The simpler
+form is the diff format, where the output of the test program is diff'ed with
+the correspondingly named .exp file. If there is diff output, the test fails.
+The sequence test format is somewhat more complex, and is documented in the
+command line usage output for verify. The advantage of this format is that it
+allows multiple tests to pass/fail within one program.
+
+There is no driving need for test naming consistency, but the existing tests
+generally follow these conventions:
+
+<name>_d.c <name>_d.exp : Diff mode C test and expected output file.
+<name>_s.c : Sequence mode C test.
+<name>_b*.c : Back end C program used by perl tests.
+<name>_d.pl <name>_d.pl.exp : Diff mode perl test and expected output file.
+<name>_s.pl : Sequence mode perl test.
+
+<name> is something descriptive, such as "pr14685" in the case of a PR-related
+regression test, or "mutex" in the case of a test of mutexes.
diff --git a/lib/libc_r/test/guard_b.c b/lib/libc_r/test/guard_b.c
new file mode 100644
index 0000000..35aa406
--- /dev/null
+++ b/lib/libc_r/test/guard_b.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2001 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
+ * unmodified other than the allowable 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$
+ *
+ * Test thread stack guard functionality.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <pthread.h>
+
+#define FRAME_SIZE 1024
+#define FRAME_OVERHEAD 40
+
+struct args
+{
+ void *top; /* Top of thread's initial stack frame. */
+ int cur; /* Recursion depth. */
+ int max; /* Maximum recursion depth. */
+};
+
+void *
+recurse(void *args)
+{
+ int top;
+ struct args *parms = (struct args *)args;
+ char filler[FRAME_SIZE - FRAME_OVERHEAD];
+
+ /* Touch the memory in this stack frame. */
+ top = 0xa5;
+ memset(filler, 0xa5, sizeof(filler));
+
+ if (parms->top == NULL) {
+ /* Initial stack frame. */
+ parms->top = (void*)&top;
+ }
+
+ /*
+ * Make sure frame size is what we expect. Getting this right involves
+ * hand tweaking, so just print a warning rather than aborting.
+ */
+ if (parms->top - (void *)&top != FRAME_SIZE * parms->cur) {
+ fprintf(stderr, "Stack size (%d) != expected (%d), frame %d\n",
+ (int)(parms->top - (void *)&top), FRAME_SIZE * parms->cur,
+ parms->cur);
+ }
+
+ parms->cur++;
+ if (parms->cur < parms->max)
+ recurse(args);
+
+ return NULL;
+}
+
+
+int
+main(int argc, char **argv)
+{
+ size_t def_stacksize, def_guardsize;
+ size_t stacksize, guardsize;
+ pthread_t thread;
+ pthread_attr_t attr;
+ struct args args;
+
+ if (argc != 3) {
+ fprintf(stderr, "usage: guard_b <stacksize> <guardsize>\n");
+ exit(1);
+ }
+ fprintf(stderr, "Test begin\n");
+
+ stacksize = strtoul(argv[1], NULL, 10);
+ guardsize = strtoul(argv[2], NULL, 10);
+
+ assert(pthread_attr_init(&attr) == 0);
+ /*
+ * Exercise the attribute APIs more thoroughly than is strictly
+ * necessary for the meat of this test program.
+ */
+ assert(pthread_attr_getstacksize(&attr, &def_stacksize) == 0);
+ assert(pthread_attr_getguardsize(&attr, &def_guardsize) == 0);
+ if (def_stacksize != stacksize) {
+ assert(pthread_attr_setstacksize(&attr, stacksize) == 0);
+ assert(pthread_attr_getstacksize(&attr, &def_stacksize) == 0);
+ assert(def_stacksize == stacksize);
+ }
+ if (def_guardsize != guardsize) {
+ assert(pthread_attr_setguardsize(&attr, guardsize) == 0);
+ assert(pthread_attr_getguardsize(&attr, &def_guardsize) == 0);
+ assert(def_guardsize >= guardsize);
+ }
+
+ /*
+ * Create a thread that will come just short of overflowing the thread
+ * stack. We need to leave a bit of breathing room in case the thread
+ * is context switched, and we also have to take care not to call any
+ * functions in the deepest stack frame.
+ */
+ args.top = NULL;
+ args.cur = 0;
+ args.max = (stacksize / FRAME_SIZE) - 1;
+ fprintf(stderr, "No overflow:\n");
+ assert(pthread_create(&thread, &attr, recurse, &args) == 0);
+ assert(pthread_join(thread, NULL) == 0);
+
+ /*
+ * Create a thread that will barely of overflow the thread stack. This
+ * should cause a segfault.
+ */
+ args.top = NULL;
+ args.cur = 0;
+ args.max = (stacksize / FRAME_SIZE) + 1;
+ fprintf(stderr, "Overflow:\n");
+ assert(pthread_create(&thread, &attr, recurse, &args) == 0);
+ assert(pthread_join(thread, NULL) == 0);
+
+ /* Not reached. */
+ fprintf(stderr, "Unexpected success\n");
+ abort();
+
+ return 0;
+}
diff --git a/lib/libc_r/test/guard_b.exp b/lib/libc_r/test/guard_b.exp
new file mode 100644
index 0000000..8e5b9e4
--- /dev/null
+++ b/lib/libc_r/test/guard_b.exp
@@ -0,0 +1,3 @@
+Test begin
+No overflow:
+Overflow:
diff --git a/lib/libc_r/test/guard_s.pl b/lib/libc_r/test/guard_s.pl
new file mode 100755
index 0000000..7802ff3
--- /dev/null
+++ b/lib/libc_r/test/guard_s.pl
@@ -0,0 +1,69 @@
+#!/usr/bin/perl -w
+#
+# Copyright (C) 2001 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
+# unmodified other than the allowable 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$
+#
+# Test thread stack guard functionality. The C test program needs to be driven
+# by this script because it segfaults when the stack guard is hit.
+#
+
+print "1..30\n";
+
+$i = 0;
+# Iterates 10 times.
+for ($stacksize = 65536; $stacksize < 131072; $stacksize += 7168)
+{
+ # Iterates 3 times (1024, 4096, 7168).
+ for ($guardsize = 1024; $guardsize < 8192; $guardsize += 3072)
+ {
+ $i++;
+
+ print "stacksize: $stacksize, guardsize: $guardsize\n";
+
+ `./guard_b $stacksize $guardsize >guard_b.out 2>&1`;
+
+ if (! -f "./guard_b.out")
+ {
+ print "not ok $i\n";
+ }
+ else
+ {
+ `diff guard_b.exp guard_b.out >guard_b.diff 2>&1`;
+ if ($?)
+ {
+ # diff returns non-zero if there is a difference.
+ print "not ok $i\n";
+ }
+ else
+ {
+ print "ok $i\n";
+ }
+ }
+ }
+}
diff --git a/lib/libc_r/test/hello_b.c b/lib/libc_r/test/hello_b.c
new file mode 100644
index 0000000..2eefa7f
--- /dev/null
+++ b/lib/libc_r/test/hello_b.c
@@ -0,0 +1,13 @@
+/****************************************************************************
+ *
+ * Back end C programs can be anything compilable.
+ *
+ * $FreeBSD$
+ *
+ ****************************************************************************/
+
+int
+main()
+{
+ return 0;
+}
diff --git a/lib/libc_r/test/hello_d.c b/lib/libc_r/test/hello_d.c
new file mode 100644
index 0000000..6d77526
--- /dev/null
+++ b/lib/libc_r/test/hello_d.c
@@ -0,0 +1,38 @@
+/****************************************************************************
+ *
+ * Simple diff mode test.
+ *
+ * $FreeBSD$
+ *
+ ****************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <pthread.h>
+
+void *
+entry(void * a_arg)
+{
+ fprintf(stderr, "Hello world\n");
+
+ return NULL;
+}
+
+int
+main()
+{
+ pthread_t thread;
+ int error;
+
+ error = pthread_create(&thread, NULL, entry, NULL);
+ if (error)
+ fprintf(stderr, "Error in pthread_create(): %s\n",
+ strerror(error));
+
+ error = pthread_join(thread, NULL);
+ if (error)
+ fprintf(stderr, "Error in pthread_join(): %s\n",
+ strerror(error));
+
+ return 0;
+}
diff --git a/lib/libc_r/test/hello_d.exp b/lib/libc_r/test/hello_d.exp
new file mode 100644
index 0000000..802992c
--- /dev/null
+++ b/lib/libc_r/test/hello_d.exp
@@ -0,0 +1 @@
+Hello world
diff --git a/lib/libc_r/test/hello_s.c b/lib/libc_r/test/hello_s.c
new file mode 100644
index 0000000..942bf2d
--- /dev/null
+++ b/lib/libc_r/test/hello_s.c
@@ -0,0 +1,47 @@
+/****************************************************************************
+ *
+ * Simple sequence mode test.
+ *
+ * $FreeBSD$
+ *
+ ****************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <pthread.h>
+
+void *
+entry(void * a_arg)
+{
+ fprintf(stderr, "ok 1\n");
+ fprintf(stderr, "ok \n");
+ fprintf(stderr, "ok 3\n");
+
+ return NULL;
+}
+
+int
+main()
+{
+ pthread_t thread;
+ int error;
+
+ fprintf(stderr, "1..3\n");
+
+ fprintf(stderr, "Some random text\n");
+
+ error = pthread_create(&thread, NULL, entry, NULL);
+ fprintf(stderr, "More unimportant text\n");
+ if (error)
+ fprintf(stderr,"Error in pthread_create(): %s\n",
+ strerror(error));
+
+ error = pthread_join(thread, NULL);
+ if (error)
+ fprintf(stderr, "Error in pthread_join(): %s\n",
+ strerror(error));
+
+ fprintf(stderr, "Hello world\n");
+
+ return 0;
+}
diff --git a/lib/libc_r/test/join_leak_d.c b/lib/libc_r/test/join_leak_d.c
new file mode 100644
index 0000000..9a35140
--- /dev/null
+++ b/lib/libc_r/test/join_leak_d.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2001 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$
+ *
+ * Test for leaked joined threads.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <errno.h>
+#include <string.h>
+#include <pthread.h>
+
+#define NITERATIONS 16384
+#define MAXGROWTH 16384
+
+void *
+thread_entry(void *a_arg)
+{
+ return NULL;
+}
+
+int
+main(void)
+{
+ pthread_t thread;
+ int i, error;
+ char *brk, *nbrk;
+ unsigned growth;
+
+ fprintf(stderr, "Test begin\n");
+
+ /* Get an initial brk value. */
+ brk = sbrk(0);
+
+ /* Create threads and join them, one at a time. */
+ for (i = 0; i < NITERATIONS; i++) {
+ if ((error = pthread_create(&thread, NULL, thread_entry, NULL))
+ != 0) {
+ if (error == EAGAIN) {
+ i--;
+ continue;
+ }
+ fprintf(stderr, "Error in pthread_create(): %s\n",
+ strerror(error));
+ exit(1);
+ }
+ if ((error = pthread_join(thread, NULL)) != 0) {
+ fprintf(stderr, "Error in pthread_join(): %s\n",
+ strerror(error));
+ exit(1);
+ }
+ }
+
+ /* Get a final brk value. */
+ nbrk = sbrk(0);
+
+ /*
+ * Check that the amount of heap space allocated is below an acceptable
+ * threshold. We could just compare brk and nbrk, but the test could
+ * conceivably break if the internals of the threads library changes.
+ */
+ if (nbrk > brk) {
+ /* Heap grows up. */
+ growth = nbrk - brk;
+ } else if (nbrk <= brk) {
+ /* Heap grows down, or no growth. */
+ growth = brk - nbrk;
+ }
+
+ if (growth > MAXGROWTH) {
+ fprintf(stderr, "Heap growth exceeded maximum (%u > %u)\n",
+ growth, MAXGROWTH);
+ }
+#if (0)
+ else {
+ fprintf(stderr, "Heap growth acceptable (%u <= %u)\n",
+ growth, MAXGROWTH);
+ }
+#endif
+
+ fprintf(stderr, "Test end\n");
+ return 0;
+}
diff --git a/lib/libc_r/test/join_leak_d.exp b/lib/libc_r/test/join_leak_d.exp
new file mode 100644
index 0000000..369a88d
--- /dev/null
+++ b/lib/libc_r/test/join_leak_d.exp
@@ -0,0 +1,2 @@
+Test begin
+Test end
diff --git a/lib/libc_r/test/mutex_d.c b/lib/libc_r/test/mutex_d.c
new file mode 100644
index 0000000..2f0c868
--- /dev/null
+++ b/lib/libc_r/test/mutex_d.c
@@ -0,0 +1,1555 @@
+/*
+ * Copyright (c) 1998 Daniel M. Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel M. Eischen.
+ * 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 DANIEL M. 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.
+ *
+ * $FreeBSD$
+ */
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <sys/ioctl.h>
+#include <assert.h>
+#include <errno.h>
+#include <inttypes.h>
+#include "pthread.h"
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <sysexits.h>
+
+#if defined(_LIBC_R_)
+#include <pthread_np.h>
+#endif
+
+#ifndef NELEMENTS
+#define NELEMENTS(arr) (sizeof (arr) / sizeof (arr[0]))
+#endif
+
+#ifndef NUM_THREADS
+#define NUM_THREADS 10
+#endif
+
+#define MAX_THREAD_CMDS 10
+
+static void log_error(const char *, ...) __printflike(1, 2);
+static void log_trace (const char *, ...) __printflike(1, 2);
+static void log (const char *, ...) __printflike(1, 2);
+
+/*------------------------------------------------------------
+ * Types
+ *----------------------------------------------------------*/
+
+typedef enum {
+ STAT_INITIAL, /* initial state */
+ STAT_WAITCONDVAR, /* waiting for condition variable signal */
+ STAT_WAITMUTEX /* waiting for mutex lock */
+} thread_status_t;
+
+typedef enum {
+ FLAGS_REPORT_WAITCONDMUTEX = 0x01,
+ FLAGS_REPORT_WAITCONDVAR = 0x02,
+ FLAGS_REPORT_WAITMUTEX = 0x04,
+ FLAGS_REPORT_BUSY_LOOP = 0x08,
+ FLAGS_IS_BUSY = 0x10,
+ FLAGS_WAS_BUSY = 0x20
+} thread_flags_t;
+
+typedef enum {
+ CMD_NONE,
+ CMD_TAKE_MUTEX,
+ CMD_RELEASE_MUTEX,
+ CMD_WAIT_FOR_SIGNAL,
+ CMD_BUSY_LOOP,
+ CMD_PROTECTED_OP,
+ CMD_RELEASE_ALL
+} thread_cmd_id_t;
+
+typedef struct {
+ thread_cmd_id_t cmd_id;
+ pthread_mutex_t *mutex;
+ pthread_cond_t *cond;
+} thread_cmd_t;
+
+typedef struct {
+ pthread_cond_t cond_var;
+ thread_status_t status;
+ thread_cmd_t cmd;
+ int flags;
+ int priority;
+ int ret;
+ pthread_t tid;
+ u_int8_t id;
+} thread_state_t;
+
+typedef enum {
+ M_POSIX,
+ M_SS2_DEFAULT,
+ M_SS2_ERRORCHECK,
+ M_SS2_NORMAL,
+ M_SS2_RECURSIVE
+} mutex_kind_t;
+
+
+/*------------------------------------------------------------
+ * Constants
+ *----------------------------------------------------------*/
+
+const char *protocol_strs[] = {
+ "PTHREAD_PRIO_NONE",
+ "PTHREAD_PRIO_INHERIT",
+ "PTHREAD_PRIO_PROTECT"
+};
+
+const int protocols[] = {
+ PTHREAD_PRIO_NONE,
+ PTHREAD_PRIO_INHERIT,
+ PTHREAD_PRIO_PROTECT
+};
+
+const char *mutextype_strs[] = {
+ "POSIX (type not specified)",
+ "SS2 PTHREAD_MUTEX_DEFAULT",
+ "SS2 PTHREAD_MUTEX_ERRORCHECK",
+ "SS2 PTHREAD_MUTEX_NORMAL",
+ "SS2 PTHREAD_MUTEX_RECURSIVE"
+};
+
+const int mutex_types[] = {
+ 0, /* M_POSIX */
+ PTHREAD_MUTEX_DEFAULT, /* M_SS2_DEFAULT */
+ PTHREAD_MUTEX_ERRORCHECK, /* M_SS2_ERRORCHECK */
+ PTHREAD_MUTEX_NORMAL, /* M_SS2_NORMAL */
+ PTHREAD_MUTEX_RECURSIVE /* M_SS2_RECURSIVE */
+};
+
+
+/*------------------------------------------------------------
+ * Objects
+ *----------------------------------------------------------*/
+
+static int done = 0;
+static int trace_enabled = 0;
+static int use_global_condvar = 0;
+static thread_state_t states[NUM_THREADS];
+static int pipefd[2];
+
+static pthread_mutex_t waiter_mutex;
+static pthread_mutex_t cond_mutex;
+static pthread_cond_t cond_var;
+
+static FILE *logfile;
+static int error_count = 0, pass_count = 0, total = 0;
+
+
+/*------------------------------------------------------------
+ * Prototypes
+ *----------------------------------------------------------*/
+extern char *strtok_r(char *str, const char *sep, char **last);
+
+
+/*------------------------------------------------------------
+ * Functions
+ *----------------------------------------------------------*/
+
+#ifdef DEBUG
+static void
+kern_switch (pthread_t pthread_out, pthread_t pthread_in)
+{
+ if (pthread_out != NULL)
+ printf ("Swapping out thread 0x%x, ", (int) pthread_out);
+ else
+ printf ("Swapping out kernel thread, ");
+
+ if (pthread_in != NULL)
+ printf ("swapping in thread 0x%x\n", (int) pthread_in);
+ else
+ printf ("swapping in kernel thread.\n");
+}
+#endif
+
+
+static void
+log_error (const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start (ap, fmt);
+ fprintf (logfile, "FAIL: ");
+ vfprintf (logfile, fmt, ap);
+ error_count = error_count + 1;
+ total = total + 1;
+}
+
+
+static void
+log_pass (void)
+{
+ fprintf (logfile, "PASS\n");
+ pass_count = pass_count + 1;
+ total = total + 1;
+}
+
+
+static void
+log_trace (const char *fmt, ...)
+{
+ va_list ap;
+
+ if (trace_enabled) {
+ va_start (ap, fmt);
+ vfprintf (logfile, fmt, ap);
+ }
+}
+
+
+static void
+log (const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start (ap, fmt);
+ vfprintf (logfile, fmt, ap);
+}
+
+
+static void
+check_result (int expected, int actual)
+{
+ if (expected != actual)
+ log_error ("expected %d, returned %d\n", expected, actual);
+ else
+ log_pass ();
+}
+
+
+/*
+ * Check to see that the threads ran in the specified order.
+ */
+static void
+check_run_order (char *order)
+{
+ const char *sep = ":,";
+ char *tok, *last, *idstr, *endptr;
+ int expected_id, bytes, count = 0, errors = 0;
+ u_int8_t id;
+
+ assert ((tok = (char *) malloc (strlen(order) + 1)) != NULL);
+ strcpy (tok, order); /* tok has to be larger than order */
+ assert (ioctl (pipefd[0], FIONREAD, &bytes) == 0);
+ log_trace ("%d bytes read from FIFO.\n", bytes);
+
+ for (idstr = strtok_r (tok, sep, &last);
+ (idstr != NULL) && (count < bytes);
+ idstr = strtok_r (NULL, sep, &last)) {
+
+ /* Get the expected id: */
+ expected_id = (int) strtol (idstr, &endptr, 10);
+ assert ((endptr != NULL) && (*endptr == '\0'));
+
+ /* Read the actual id from the pipe: */
+ assert (read (pipefd[0], &id, sizeof (id)) == sizeof (id));
+ count = count + sizeof (id);
+
+ if (id != expected_id) {
+ log_trace ("Thread %d ran out of order.\n", id);
+ errors = errors + 1;
+ }
+ else {
+ log_trace ("Thread %d at priority %d reporting.\n",
+ (int) id, states[id].priority);
+ }
+ }
+
+ if (count < bytes) {
+ /* Clear the pipe: */
+ while (count < bytes) {
+ read (pipefd[0], &id, sizeof (id));
+ count = count + 1;
+ errors = errors + 1;
+ }
+ }
+ else if (bytes < count)
+ errors = errors + count - bytes;
+
+ if (errors == 0)
+ log_pass ();
+ else
+ log_error ("%d threads ran out of order", errors);
+}
+
+
+static void *
+waiter (void *arg)
+{
+ thread_state_t *statep = (thread_state_t *) arg;
+ pthread_mutex_t *held_mutex[MAX_THREAD_CMDS];
+ int held_mutex_owned[MAX_THREAD_CMDS];
+ sigset_t mask;
+ struct timeval tv1, tv2;
+ thread_cmd_t cmd;
+ int i, mutex_count = 0;
+
+ statep->status = STAT_INITIAL;
+
+ /* Block all signals except for interrupt.*/
+ sigfillset (&mask);
+ sigdelset (&mask, SIGINT);
+ sigprocmask (SIG_BLOCK, &mask, NULL);
+
+ while (done == 0) {
+ /* Wait for signal from the main thread to continue. */
+ statep->status = STAT_WAITMUTEX;
+ log_trace ("Thread %d: locking cond_mutex.\n",
+ (int) statep->id);
+ pthread_mutex_lock (&cond_mutex);
+
+ /* Do we report our status. */
+ if (statep->flags & FLAGS_REPORT_WAITCONDMUTEX)
+ write (pipefd[1], &statep->id, sizeof (statep->id));
+ log_trace ("Thread %d: waiting for cond_var.\n",
+ (int) statep->id);
+
+ /* Wait for a command. */
+ statep->status = STAT_WAITCONDVAR;
+
+ /*
+ * The threads are allowed commanded to wait either on
+ * their own unique condition variable (so they may be
+ * separately signaled) or on one global condition variable
+ * (so they may be signaled together).
+ */
+ if (use_global_condvar != 0)
+ pthread_cond_wait (&cond_var, &cond_mutex);
+ else
+ pthread_cond_wait (&statep->cond_var, &cond_mutex);
+
+ /* Do we report our status? */
+ if (statep->flags & FLAGS_REPORT_WAITCONDVAR) {
+ write (pipefd[1], &statep->id, sizeof (statep->id));
+ log_trace ("Thread %d: wrote to pipe.\n",
+ (int) statep->id);
+ }
+ log_trace ("Thread %d: received cond_var signal.\n",
+ (int) statep->id);
+
+ /* Get a copy of the command before releasing the mutex. */
+ cmd = statep->cmd;
+
+ /* Clear the command after copying it. */
+ statep->cmd.cmd_id = CMD_NONE;
+
+ /* Unlock the condition variable mutex. */
+ assert (pthread_mutex_unlock (&cond_mutex) == 0);
+
+ /* Peform the command.*/
+ switch (cmd.cmd_id) {
+ case CMD_TAKE_MUTEX:
+ statep->ret = pthread_mutex_lock (cmd.mutex);
+ if (statep->ret == 0) {
+ assert (mutex_count < sizeof (held_mutex));
+ held_mutex[mutex_count] = cmd.mutex;
+ held_mutex_owned[mutex_count] = 1;
+ mutex_count++;
+ }
+ else {
+ held_mutex_owned[mutex_count] = 0;
+ log_trace ("Thread id %d unable to lock mutex, "
+ "error = %d\n", (int) statep->id,
+ statep->ret);
+ }
+ break;
+
+ case CMD_RELEASE_MUTEX:
+ assert ((mutex_count <= sizeof (held_mutex)) &&
+ (mutex_count > 0));
+ mutex_count--;
+ if (held_mutex_owned[mutex_count] != 0)
+ assert (pthread_mutex_unlock
+ (held_mutex[mutex_count]) == 0);
+ break;
+
+ case CMD_WAIT_FOR_SIGNAL:
+ assert (pthread_mutex_lock (cmd.mutex) == 0);
+ assert (pthread_cond_wait (cmd.cond, cmd.mutex) == 0);
+ assert (pthread_mutex_unlock (cmd.mutex) == 0);
+ break;
+
+ case CMD_BUSY_LOOP:
+ log_trace ("Thread %d: Entering busy loop.\n",
+ (int) statep->id);
+ /* Spin for 15 seconds. */
+ assert (gettimeofday (&tv2, NULL) == 0);
+ tv1.tv_sec = tv2.tv_sec + 5;
+ tv1.tv_usec = tv2.tv_usec;
+ statep->flags |= FLAGS_IS_BUSY;
+ while (timercmp (&tv2, &tv1,<)) {
+ assert (gettimeofday (&tv2, NULL) == 0);
+ }
+ statep->flags &= ~FLAGS_IS_BUSY;
+ statep->flags |= FLAGS_WAS_BUSY;
+
+ /* Do we report our status? */
+ if (statep->flags & FLAGS_REPORT_BUSY_LOOP)
+ write (pipefd[1], &statep->id,
+ sizeof (statep->id));
+
+ log_trace ("Thread %d: Leaving busy loop.\n",
+ (int) statep->id);
+ break;
+
+ case CMD_PROTECTED_OP:
+ assert (pthread_mutex_lock (cmd.mutex) == 0);
+ statep->flags |= FLAGS_WAS_BUSY;
+ /* Do we report our status? */
+ if (statep->flags & FLAGS_REPORT_BUSY_LOOP)
+ write (pipefd[1], &statep->id,
+ sizeof (statep->id));
+
+ assert (pthread_mutex_unlock (cmd.mutex) == 0);
+ break;
+
+ case CMD_RELEASE_ALL:
+ assert ((mutex_count <= sizeof (held_mutex)) &&
+ (mutex_count > 0));
+ for (i = mutex_count - 1; i >= 0; i--) {
+ if (held_mutex_owned[i] != 0)
+ assert (pthread_mutex_unlock
+ (held_mutex[i]) == 0);
+ }
+ mutex_count = 0;
+ break;
+
+ case CMD_NONE:
+ default:
+ break;
+ }
+
+ /* Wait for the big giant waiter lock. */
+ statep->status = STAT_WAITMUTEX;
+ log_trace ("Thread %d: waiting for big giant lock.\n",
+ (int) statep->id);
+ pthread_mutex_lock (&waiter_mutex);
+ if (statep->flags & FLAGS_REPORT_WAITMUTEX)
+ write (pipefd[1], &statep->id, sizeof (statep->id));
+ log_trace ("Thread %d: got big giant lock.\n",
+ (int) statep->id);
+ statep->status = STAT_INITIAL;
+ pthread_mutex_unlock (&waiter_mutex);
+ }
+
+ log_trace ("Thread %d: Exiting thread 0x%" PRIxPTR "\n",
+ (int) statep->id, (uintptr_t) pthread_self());
+ pthread_exit (arg);
+ return (NULL);
+}
+
+
+static void *
+lock_twice (void *arg)
+{
+ thread_state_t *statep = (thread_state_t *) arg;
+ sigset_t mask;
+
+ statep->status = STAT_INITIAL;
+
+ /* Block all signals except for interrupt.*/
+ sigfillset (&mask);
+ sigdelset (&mask, SIGINT);
+ sigprocmask (SIG_BLOCK, &mask, NULL);
+
+ /* Wait for a signal to continue. */
+ log_trace ("Thread %d: locking cond_mutex.\n", (int) statep->id);
+ pthread_mutex_lock (&cond_mutex);
+
+ log_trace ("Thread %d: waiting for cond_var.\n", (int) statep->id);
+ statep->status = STAT_WAITCONDVAR;
+ pthread_cond_wait (&cond_var, &cond_mutex);
+
+ log_trace ("Thread %d: received cond_var signal.\n", (int) statep->id);
+
+ /* Unlock the condition variable mutex. */
+ assert (pthread_mutex_unlock (&cond_mutex) == 0);
+
+ statep->status = STAT_WAITMUTEX;
+ /* Lock the mutex once. */
+ assert (pthread_mutex_lock (statep->cmd.mutex) == 0);
+
+ /* Lock it again and capture the error. */
+ statep->ret = pthread_mutex_lock (statep->cmd.mutex);
+ statep->status = 0;
+
+ assert (pthread_mutex_unlock (statep->cmd.mutex) == 0);
+
+ /* Unlock it again if it is locked recursively. */
+ if (statep->ret == 0)
+ pthread_mutex_unlock (statep->cmd.mutex);
+
+ log_trace ("Thread %d: Exiting thread 0x%" PRIxPTR "\n",
+ (int) statep->id, (uintptr_t) pthread_self());
+ pthread_exit (arg);
+ return (NULL);
+}
+
+
+static void
+sighandler (int signo)
+{
+ log ("Signal handler caught signal %d, thread id 0x%" PRIxPTR "\n",
+ signo, (uintptr_t) pthread_self());
+
+ if (signo == SIGINT)
+ done = 1;
+}
+
+
+static void
+send_cmd (int id, thread_cmd_id_t cmd)
+{
+ assert (pthread_mutex_lock (&cond_mutex) == 0);
+ assert (states[id].status == STAT_WAITCONDVAR);
+ states[id].cmd.cmd_id = cmd;
+ states[id].cmd.mutex = NULL;
+ states[id].cmd.cond = NULL;
+ /* Clear the busy flags. */
+ states[id].flags &= ~(FLAGS_WAS_BUSY | FLAGS_IS_BUSY);
+ assert (pthread_cond_signal (&states[id].cond_var) == 0);
+ assert (pthread_mutex_unlock (&cond_mutex) == 0);
+}
+
+
+static void
+send_mutex_cmd (int id, thread_cmd_id_t cmd, pthread_mutex_t *m)
+{
+ assert (pthread_mutex_lock (&cond_mutex) == 0);
+ assert (states[id].status == STAT_WAITCONDVAR);
+ states[id].cmd.cmd_id = cmd;
+ states[id].cmd.mutex = m;
+ states[id].cmd.cond = NULL;
+ /* Clear the busy flags. */
+ states[id].flags &= ~(FLAGS_WAS_BUSY | FLAGS_IS_BUSY);
+ assert (pthread_cond_signal (&states[id].cond_var) == 0);
+ assert (pthread_mutex_unlock (&cond_mutex) == 0);
+}
+
+
+static void
+send_mutex_cv_cmd (int id, thread_cmd_id_t cmd, pthread_mutex_t *m,
+ pthread_cond_t *cv)
+{
+ assert (pthread_mutex_lock (&cond_mutex) == 0);
+ assert (states[id].status == STAT_WAITCONDVAR);
+ states[id].cmd.cmd_id = cmd;
+ states[id].cmd.mutex = m;
+ states[id].cmd.cond = cv;
+ /* Clear the busy flags. */
+ states[id].flags &= ~(FLAGS_WAS_BUSY | FLAGS_IS_BUSY);
+ assert (pthread_cond_signal (&states[id].cond_var) == 0);
+ assert (pthread_mutex_unlock (&cond_mutex) == 0);
+}
+
+
+static void
+mutex_init_test (void)
+{
+ pthread_mutexattr_t mattr;
+ pthread_mutex_t mutex;
+ mutex_kind_t mkind;
+ int mproto, ret;
+
+ /*
+ * Initialize a mutex attribute.
+ *
+ * pthread_mutexattr_init not tested for: ENOMEM
+ */
+ assert (pthread_mutexattr_init (&mattr) == 0);
+
+ /*
+ * Initialize a mutex.
+ *
+ * pthread_mutex_init not tested for: EAGAIN ENOMEM EPERM EBUSY
+ */
+ log ("Testing pthread_mutex_init\n");
+ log ("--------------------------\n");
+
+ for (mproto = 0; mproto < NELEMENTS(protocols); mproto++) {
+ for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) {
+ /* Initialize the mutex attribute. */
+ assert (pthread_mutexattr_init (&mattr) == 0);
+ assert (pthread_mutexattr_setprotocol (&mattr,
+ protocols[mproto]) == 0);
+
+ /*
+ * Ensure that the first mutex type is a POSIX
+ * compliant mutex.
+ */
+ if (mkind != M_POSIX) {
+ assert (pthread_mutexattr_settype (&mattr,
+ mutex_types[mkind]) == 0);
+ }
+
+ log (" Protocol %s, Type %s - ",
+ protocol_strs[mproto], mutextype_strs[mkind]);
+ ret = pthread_mutex_init (&mutex, &mattr);
+ check_result (/* expected */ 0, ret);
+ assert (pthread_mutex_destroy (&mutex) == 0);
+
+ /*
+ * Destroy a mutex attribute.
+ *
+ * XXX - There should probably be a magic number
+ * associated with a mutex attribute so that
+ * destroy can be reasonably sure the attribute
+ * is valid.
+ *
+ * pthread_mutexattr_destroy not tested for: EINVAL
+ */
+ assert (pthread_mutexattr_destroy (&mattr) == 0);
+ }
+ }
+}
+
+
+static void
+mutex_destroy_test (void)
+{
+ pthread_mutexattr_t mattr;
+ pthread_mutex_t mutex;
+ pthread_condattr_t cattr;
+ pthread_cond_t cv;
+ pthread_attr_t pattr;
+ int mproto, ret;
+ mutex_kind_t mkind;
+ thread_state_t state;
+
+ /*
+ * Destroy a mutex.
+ *
+ * XXX - There should probably be a magic number associated
+ * with a mutex so that destroy can be reasonably sure
+ * the mutex is valid.
+ *
+ * pthread_mutex_destroy not tested for:
+ */
+ log ("Testing pthread_mutex_destroy\n");
+ log ("-----------------------------\n");
+
+ assert (pthread_attr_init (&pattr) == 0);
+ assert (pthread_attr_setdetachstate (&pattr,
+ PTHREAD_CREATE_DETACHED) == 0);
+ state.flags = 0; /* No flags yet. */
+
+ for (mproto = 0; mproto < NELEMENTS(protocols); mproto++) {
+ for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) {
+ /* Initialize the mutex attribute. */
+ assert (pthread_mutexattr_init (&mattr) == 0);
+ assert (pthread_mutexattr_setprotocol (&mattr,
+ protocols[mproto]) == 0);
+
+ /*
+ * Ensure that the first mutex type is a POSIX
+ * compliant mutex.
+ */
+ if (mkind != M_POSIX) {
+ assert (pthread_mutexattr_settype (&mattr,
+ mutex_types[mkind]) == 0);
+ }
+
+ /* Create the mutex. */
+ assert (pthread_mutex_init (&mutex, &mattr) == 0);
+
+ log (" Protocol %s, Type %s\n",
+ protocol_strs[mproto], mutextype_strs[mkind]);
+
+ log (" Destruction of unused mutex - ");
+ assert (pthread_mutex_init (&mutex, &mattr) == 0);
+ ret = pthread_mutex_destroy (&mutex);
+ check_result (/* expected */ 0, ret);
+
+ log (" Destruction of mutex locked by self - ");
+ assert (pthread_mutex_init (&mutex, &mattr) == 0);
+ assert (pthread_mutex_lock (&mutex) == 0);
+ ret = pthread_mutex_destroy (&mutex);
+ check_result (/* expected */ EBUSY, ret);
+ assert (pthread_mutex_unlock (&mutex) == 0);
+ assert (pthread_mutex_destroy (&mutex) == 0);
+
+ log (" Destruction of mutex locked by another "
+ "thread - ");
+ assert (pthread_mutex_init (&mutex, &mattr) == 0);
+ send_mutex_cmd (0, CMD_TAKE_MUTEX, &mutex);
+ sleep (1);
+ ret = pthread_mutex_destroy (&mutex);
+ check_result (/* expected */ EBUSY, ret);
+ send_cmd (0, CMD_RELEASE_ALL);
+ sleep (1);
+ assert (pthread_mutex_destroy (&mutex) == 0);
+
+ log (" Destruction of mutex while being used in "
+ "cond_wait - ");
+ assert (pthread_mutex_init (&mutex, &mattr) == 0);
+ assert (pthread_condattr_init (&cattr) == 0);
+ assert (pthread_cond_init (&cv, &cattr) == 0);
+ send_mutex_cv_cmd (0, CMD_WAIT_FOR_SIGNAL, &mutex, &cv);
+ sleep (1);
+ ret = pthread_mutex_destroy (&mutex);
+ check_result (/* expected */ EBUSY, ret);
+ pthread_cond_signal (&cv);
+ sleep (1);
+ assert (pthread_mutex_destroy (&mutex) == 0);
+ }
+ }
+}
+
+
+static void
+mutex_lock_test (void)
+{
+ pthread_mutexattr_t mattr;
+ pthread_mutex_t mutex;
+ pthread_attr_t pattr;
+ int mproto, ret;
+ mutex_kind_t mkind;
+ thread_state_t state;
+
+ /*
+ * Lock a mutex.
+ *
+ * pthread_lock not tested for:
+ */
+ log ("Testing pthread_mutex_lock\n");
+ log ("--------------------------\n");
+
+ assert (pthread_attr_init (&pattr) == 0);
+ assert (pthread_attr_setdetachstate (&pattr,
+ PTHREAD_CREATE_DETACHED) == 0);
+ state.flags = 0; /* No flags yet. */
+
+ for (mproto = 0; mproto < NELEMENTS(protocols); mproto++) {
+ for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) {
+ /* Initialize the mutex attribute. */
+ assert (pthread_mutexattr_init (&mattr) == 0);
+ assert (pthread_mutexattr_setprotocol (&mattr,
+ protocols[mproto]) == 0);
+
+ /*
+ * Ensure that the first mutex type is a POSIX
+ * compliant mutex.
+ */
+ if (mkind != M_POSIX) {
+ assert (pthread_mutexattr_settype (&mattr,
+ mutex_types[mkind]) == 0);
+ }
+
+ /* Create the mutex. */
+ assert (pthread_mutex_init (&mutex, &mattr) == 0);
+
+ log (" Protocol %s, Type %s\n",
+ protocol_strs[mproto], mutextype_strs[mkind]);
+
+ log (" Lock on unlocked mutex - ");
+ ret = pthread_mutex_lock (&mutex);
+ check_result (/* expected */ 0, ret);
+ pthread_mutex_unlock (&mutex);
+
+ log (" Lock on invalid mutex - ");
+ ret = pthread_mutex_lock (NULL);
+ check_result (/* expected */ EINVAL, ret);
+
+ log (" Lock on mutex held by self - ");
+ assert (pthread_create (&state.tid, &pattr, lock_twice,
+ (void *) &state) == 0);
+ /* Let the thread start. */
+ sleep (1);
+ state.cmd.mutex = &mutex;
+ state.ret = 0xdeadbeef;
+ assert (pthread_mutex_lock (&cond_mutex) == 0);
+ assert (pthread_cond_signal (&cond_var) == 0);
+ assert (pthread_mutex_unlock (&cond_mutex) == 0);
+ /* Let the thread receive and process the command. */
+ sleep (1);
+
+ switch (mkind) {
+ case M_POSIX:
+ check_result (/* expected */ EDEADLK,
+ state.ret);
+ break;
+ case M_SS2_DEFAULT:
+ check_result (/* expected */ EDEADLK,
+ state.ret);
+ break;
+ case M_SS2_ERRORCHECK:
+ check_result (/* expected */ EDEADLK,
+ state.ret);
+ break;
+ case M_SS2_NORMAL:
+ check_result (/* expected */ 0xdeadbeef,
+ state.ret);
+ break;
+ case M_SS2_RECURSIVE:
+ check_result (/* expected */ 0, state.ret);
+ break;
+ }
+ pthread_mutex_destroy (&mutex);
+ pthread_mutexattr_destroy (&mattr);
+ }
+ }
+}
+
+
+static void
+mutex_unlock_test (void)
+{
+ const int test_thread_id = 0; /* ID of test thread */
+ pthread_mutexattr_t mattr;
+ pthread_mutex_t mutex;
+ int mproto, ret;
+ mutex_kind_t mkind;
+
+ /*
+ * Unlock a mutex.
+ *
+ * pthread_unlock not tested for:
+ */
+ log ("Testing pthread_mutex_unlock\n");
+ log ("----------------------------\n");
+
+ for (mproto = 0; mproto < NELEMENTS(protocols); mproto++) {
+ for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) {
+ /* Initialize the mutex attribute. */
+ assert (pthread_mutexattr_init (&mattr) == 0);
+ assert (pthread_mutexattr_setprotocol (&mattr,
+ protocols[mproto]) == 0);
+
+ /*
+ * Ensure that the first mutex type is a POSIX
+ * compliant mutex.
+ */
+ if (mkind != M_POSIX) {
+ assert (pthread_mutexattr_settype (&mattr,
+ mutex_types[mkind]) == 0);
+ }
+
+ /* Create the mutex. */
+ assert (pthread_mutex_init (&mutex, &mattr) == 0);
+
+ log (" Protocol %s, Type %s\n",
+ protocol_strs[mproto], mutextype_strs[mkind]);
+
+ log (" Unlock on mutex held by self - ");
+ assert (pthread_mutex_lock (&mutex) == 0);
+ ret = pthread_mutex_unlock (&mutex);
+ check_result (/* expected */ 0, ret);
+
+ log (" Unlock on invalid mutex - ");
+ ret = pthread_mutex_unlock (NULL);
+ check_result (/* expected */ EINVAL, ret);
+
+ log (" Unlock on mutex locked by another thread - ");
+ send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &mutex);
+ sleep (1);
+ ret = pthread_mutex_unlock (&mutex);
+ switch (mkind) {
+ case M_POSIX:
+ check_result (/* expected */ EPERM, ret);
+ break;
+ case M_SS2_DEFAULT:
+ check_result (/* expected */ EPERM, ret);
+ break;
+ case M_SS2_ERRORCHECK:
+ check_result (/* expected */ EPERM, ret);
+ break;
+ case M_SS2_NORMAL:
+ check_result (/* expected */ EPERM, ret);
+ break;
+ case M_SS2_RECURSIVE:
+ check_result (/* expected */ EPERM, ret);
+ break;
+ }
+ if (ret == 0) {
+ /*
+ * If for some reason we were able to unlock
+ * the mutex, relock it so that the test
+ * thread has no problems releasing the mutex.
+ */
+ pthread_mutex_lock (&mutex);
+ }
+ send_cmd (test_thread_id, CMD_RELEASE_ALL);
+ sleep (1);
+
+ pthread_mutex_destroy (&mutex);
+ pthread_mutexattr_destroy (&mattr);
+ }
+ }
+}
+
+
+static void
+queueing_order_test (void)
+{
+ int i;
+
+ log ("Testing queueing order\n");
+ log ("----------------------\n");
+ assert (pthread_mutex_lock (&waiter_mutex) == 0);
+ /*
+ * Tell the threads to report when they take the waiters mutex.
+ */
+ assert (pthread_mutex_lock (&cond_mutex) == 0);
+ for (i = 0; i < NUM_THREADS; i++) {
+ states[i].flags = FLAGS_REPORT_WAITMUTEX;
+ assert (pthread_cond_signal (&states[i].cond_var) == 0);
+ }
+ assert (pthread_mutex_unlock (&cond_mutex) == 0);
+
+ /* Signal the threads to continue. */
+ sleep (1);
+
+ /* Use the global condition variable next time. */
+ use_global_condvar = 1;
+
+ /* Release the waiting threads and allow them to run again. */
+ assert (pthread_mutex_unlock (&waiter_mutex) == 0);
+ sleep (1);
+
+ log (" Queueing order on a mutex - ");
+ check_run_order ("9,8,7,6,5,4,3,2,1,0");
+ for (i = 0; i < NUM_THREADS; i = i + 1) {
+ /* Tell the threads to report when they've been signaled. */
+ states[i].flags = FLAGS_REPORT_WAITCONDVAR;
+ }
+
+ /*
+ * Prevent the threads from continuing their loop after we
+ * signal them.
+ */
+ assert (pthread_mutex_lock (&waiter_mutex) == 0);
+
+
+ log (" Queueing order on a condition variable - ");
+ /*
+ * Signal one thread to run and see that the highest priority
+ * thread executes.
+ */
+ assert (pthread_mutex_lock (&cond_mutex) == 0);
+ assert (pthread_cond_signal (&cond_var) == 0);
+ assert (pthread_mutex_unlock (&cond_mutex) == 0);
+ sleep (1);
+ if (states[NUM_THREADS - 1].status != STAT_WAITMUTEX)
+ log_error ("highest priority thread does not run.\n");
+
+ /* Signal the remaining threads. */
+ assert (pthread_mutex_lock (&cond_mutex) == 0);
+ assert (pthread_cond_broadcast (&cond_var) == 0);
+ assert (pthread_mutex_unlock (&cond_mutex) == 0);
+ sleep (1);
+
+ check_run_order ("9,8,7,6,5,4,3,2,1,0");
+ for (i = 0; i < NUM_THREADS; i = i + 1) {
+ /* Tell the threads not to report anything. */
+ states[i].flags = 0;
+ }
+
+ /* Use the thread unique condition variable next time. */
+ use_global_condvar = 0;
+
+ /* Allow the threads to continue their loop. */
+ assert (pthread_mutex_unlock (&waiter_mutex) == 0);
+ sleep (1);
+}
+
+
+static void
+mutex_prioceiling_test (void)
+{
+ const int test_thread_id = 0; /* ID of test thread */
+ pthread_mutexattr_t mattr;
+ struct sched_param param;
+ pthread_mutex_t m[3];
+ mutex_kind_t mkind;
+ int i, ret, policy, my_prio, old_ceiling;
+
+ log ("Testing priority ceilings\n");
+ log ("-------------------------\n");
+ for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) {
+
+ log (" Protype PTHREAD_PRIO_PROTECT, Type %s\n",
+ mutextype_strs[mkind]);
+
+ /*
+ * Initialize and create a mutex.
+ */
+ assert (pthread_mutexattr_init (&mattr) == 0);
+
+ /* Get this threads current priority. */
+ assert (pthread_getschedparam (pthread_self(), &policy,
+ &param) == 0);
+ my_prio = param.sched_priority; /* save for later use */
+ log_trace ("Current scheduling policy %d, priority %d\n",
+ policy, my_prio);
+
+ /*
+ * Initialize and create 3 priority protection mutexes with
+ * default (max priority) ceilings.
+ */
+ assert (pthread_mutexattr_setprotocol(&mattr,
+ PTHREAD_PRIO_PROTECT) == 0);
+
+ /*
+ * Ensure that the first mutex type is a POSIX
+ * compliant mutex.
+ */
+ if (mkind != M_POSIX) {
+ assert (pthread_mutexattr_settype (&mattr,
+ mutex_types[mkind]) == 0);
+ }
+
+ for (i = 0; i < 3; i++)
+ assert (pthread_mutex_init (&m[i], &mattr) == 0);
+
+ /*
+ * Set the ceiling priorities for the 3 priority protection
+ * mutexes to, 5 less than, equal to, and 5 greater than,
+ * this threads current priority.
+ */
+ for (i = 0; i < 3; i++)
+ assert (pthread_mutex_setprioceiling (&m[i],
+ my_prio - 5 + 5*i, &old_ceiling) == 0);
+
+ /*
+ * Check that if we attempt to take a mutex whose priority
+ * ceiling is lower than our priority, we get an error.
+ */
+ log (" Lock with ceiling priority < thread priority - ");
+ ret = pthread_mutex_lock (&m[0]);
+ check_result (/* expected */ EINVAL, ret);
+ if (ret == 0)
+ pthread_mutex_unlock (&m[0]);
+
+ /*
+ * Check that we can take a mutex whose priority ceiling
+ * is equal to our priority.
+ */
+ log (" Lock with ceiling priority = thread priority - ");
+ ret = pthread_mutex_lock (&m[1]);
+ check_result (/* expected */ 0, ret);
+ if (ret == 0)
+ pthread_mutex_unlock (&m[1]);
+
+ /*
+ * Check that we can take a mutex whose priority ceiling
+ * is higher than our priority.
+ */
+ log (" Lock with ceiling priority > thread priority - ");
+ ret = pthread_mutex_lock (&m[2]);
+ check_result (/* expected */ 0, ret);
+ if (ret == 0)
+ pthread_mutex_unlock (&m[2]);
+
+ /*
+ * Have the test thread go into a busy loop for 5 seconds
+ * and see that it doesn't block this thread (since the
+ * priority ceiling of mutex 0 and the priority of the test
+ * thread are both less than the priority of this thread).
+ */
+ log (" Preemption with ceiling priority < thread "
+ "priority - ");
+ /* Have the test thread take mutex 0. */
+ send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &m[0]);
+ sleep (1);
+
+ log_trace ("Sending busy command.\n");
+ send_cmd (test_thread_id, CMD_BUSY_LOOP);
+ log_trace ("Busy sent, yielding\n");
+ pthread_yield ();
+ log_trace ("Returned from yield.\n");
+ if (states[test_thread_id].flags &
+ (FLAGS_IS_BUSY | FLAGS_WAS_BUSY))
+ log_error ("test thread inproperly preempted us.\n");
+ else {
+ /* Let the thread finish its busy loop. */
+ sleep (6);
+ if ((states[test_thread_id].flags & FLAGS_WAS_BUSY) == 0)
+ log_error ("test thread never finished.\n");
+ else
+ log_pass ();
+ }
+ states[test_thread_id].flags &= ~FLAGS_WAS_BUSY;
+
+ /* Have the test thread release mutex 0. */
+ send_cmd (test_thread_id, CMD_RELEASE_ALL);
+ sleep (1);
+
+ /*
+ * Have the test thread go into a busy loop for 5 seconds
+ * and see that it preempts this thread (since the priority
+ * ceiling of mutex 1 is the same as the priority of this
+ * thread). The test thread should not run to completion
+ * as its time quantum should expire before the 5 seconds
+ * are up.
+ */
+ log (" Preemption with ceiling priority = thread "
+ "priority - ");
+
+ /* Have the test thread take mutex 1. */
+ send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &m[1]);
+ sleep (1);
+
+ log_trace ("Sending busy\n");
+ send_cmd (test_thread_id, CMD_BUSY_LOOP);
+ log_trace ("Busy sent, yielding\n");
+ pthread_yield ();
+ log_trace ("Returned from yield.\n");
+ if ((states[test_thread_id].flags & FLAGS_IS_BUSY) == 0)
+ log_error ("test thread did not switch in on yield.\n");
+ else if (states[test_thread_id].flags & FLAGS_WAS_BUSY)
+ log_error ("test thread ran to completion.\n");
+ else {
+ /* Let the thread finish its busy loop. */
+ sleep (6);
+ if ((states[test_thread_id].flags & FLAGS_WAS_BUSY) == 0)
+ log_error ("test thread never finished.\n");
+ else
+ log_pass ();
+ }
+ states[test_thread_id].flags &= ~FLAGS_WAS_BUSY;
+
+ /* Have the test thread release mutex 1. */
+ send_cmd (test_thread_id, CMD_RELEASE_ALL);
+ sleep (1);
+
+ /*
+ * Set the scheduling policy of the test thread to SCHED_FIFO
+ * and have it go into a busy loop for 5 seconds. This
+ * thread is SCHED_RR, and since the priority ceiling of
+ * mutex 1 is the same as the priority of this thread, the
+ * test thread should run to completion once it is switched
+ * in.
+ */
+ log (" SCHED_FIFO scheduling and ceiling priority = "
+ "thread priority - ");
+ param.sched_priority = states[test_thread_id].priority;
+ assert (pthread_setschedparam (states[test_thread_id].tid,
+ SCHED_FIFO, &param) == 0);
+
+ /* Have the test thread take mutex 1. */
+ send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &m[1]);
+ sleep (1);
+
+ log_trace ("Sending busy\n");
+ send_cmd (test_thread_id, CMD_BUSY_LOOP);
+ log_trace ("Busy sent, yielding\n");
+ pthread_yield ();
+ log_trace ("Returned from yield.\n");
+ if ((states[test_thread_id].flags & FLAGS_WAS_BUSY) == 0) {
+ log_error ("test thread did not run to completion.\n");
+ /* Let the thread finish it's busy loop. */
+ sleep (6);
+ }
+ else
+ log_pass ();
+ states[test_thread_id].flags &= ~FLAGS_WAS_BUSY;
+
+ /* Restore the test thread scheduling parameters. */
+ param.sched_priority = states[test_thread_id].priority;
+ assert (pthread_setschedparam (states[test_thread_id].tid,
+ SCHED_RR, &param) == 0);
+
+ /* Have the test thread release mutex 1. */
+ send_cmd (test_thread_id, CMD_RELEASE_ALL);
+ sleep (1);
+
+ /*
+ * Have the test thread go into a busy loop for 5 seconds
+ * and see that it preempts this thread (since the priority
+ * ceiling of mutex 2 is the greater than the priority of
+ * this thread). The test thread should run to completion
+ * and block this thread because its active priority is
+ * higher.
+ */
+ log (" SCHED_FIFO scheduling and ceiling priority > "
+ "thread priority - ");
+ /* Have the test thread take mutex 2. */
+ send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &m[2]);
+ sleep (1);
+
+ log_trace ("Sending busy\n");
+ send_cmd (test_thread_id, CMD_BUSY_LOOP);
+ log_trace ("Busy sent, yielding\n");
+ pthread_yield ();
+ log_trace ("Returned from yield.\n");
+ if ((states[test_thread_id].flags & FLAGS_IS_BUSY) != 0) {
+ log_error ("test thread did not run to completion.\n");
+ /* Let the thread finish it's busy loop. */
+ sleep (6);
+ }
+ else if ((states[test_thread_id].flags & FLAGS_WAS_BUSY) == 0)
+ log_error ("test thread never finished.\n");
+ else
+ log_pass ();
+ states[test_thread_id].flags &= ~FLAGS_WAS_BUSY;
+
+ /* Have the test thread release mutex 2. */
+ send_cmd (test_thread_id, CMD_RELEASE_ALL);
+ sleep (1);
+
+ /* Destroy the mutexes. */
+ for (i = 0; i < 3; i++)
+ assert (pthread_mutex_destroy (&m[i]) == 0);
+ }
+}
+
+
+static void
+mutex_prioinherit_test (void)
+{
+ pthread_mutexattr_t mattr;
+ struct sched_param param;
+ pthread_mutex_t m[3];
+ mutex_kind_t mkind;
+ int i, policy, my_prio;
+
+ /* Get this threads current priority. */
+ assert (pthread_getschedparam (pthread_self(), &policy,
+ &param) == 0);
+ my_prio = param.sched_priority; /* save for later use */
+ log_trace ("Current scheduling policy %d, priority %d\n",
+ policy, my_prio);
+
+ log ("Testing priority inheritence\n");
+ log ("----------------------------\n");
+ for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) {
+
+ log (" Protype PTHREAD_PRIO_INHERIT, Type %s\n",
+ mutextype_strs[mkind]);
+
+ /*
+ * Initialize and create a mutex.
+ */
+ assert (pthread_mutexattr_init (&mattr) == 0);
+
+ /*
+ * Initialize and create 3 priority inheritence mutexes with
+ * default (max priority) ceilings.
+ */
+ assert (pthread_mutexattr_setprotocol(&mattr,
+ PTHREAD_PRIO_INHERIT) == 0);
+
+ /*
+ * Ensure that the first mutex type is a POSIX
+ * compliant mutex.
+ */
+ if (mkind != M_POSIX) {
+ assert (pthread_mutexattr_settype (&mattr,
+ mutex_types[mkind]) == 0);
+ }
+
+ for (i = 0; i < 3; i++)
+ assert (pthread_mutex_init (&m[i], &mattr) == 0);
+
+ /*
+ * Test setup:
+ * Thread 4 - take mutex 0, 1
+ * Thread 2 - enter protected busy loop with mutex 0
+ * Thread 3 - enter protected busy loop with mutex 1
+ * Thread 4 - enter protected busy loop with mutex 2
+ * Thread 5 - enter busy loop
+ * Thread 6 - enter protected busy loop with mutex 0
+ * Thread 4 - releases mutexes 1 and 0.
+ *
+ * Expected results:
+ * Threads complete in order 4, 6, 5, 3, 2
+ */
+ log (" Simple inheritence test - ");
+
+ /*
+ * Command thread 4 to take mutexes 0 and 1.
+ */
+ send_mutex_cmd (4, CMD_TAKE_MUTEX, &m[0]);
+ sleep (1); /* Allow command to be received. */
+ send_mutex_cmd (4, CMD_TAKE_MUTEX, &m[1]);
+ sleep (1);
+
+ /*
+ * Tell the threads to report themselves when they are
+ * at the bottom of their loop (waiting on wait_mutex).
+ */
+ for (i = 0; i < NUM_THREADS; i++)
+ states[i].flags |= FLAGS_REPORT_WAITMUTEX;
+
+ /*
+ * Command thread 2 to take mutex 0 and thread 3 to take
+ * mutex 1, both via a protected operation command. Since
+ * thread 4 owns mutexes 0 and 1, both threads 2 and 3
+ * will block until the mutexes are released by thread 4.
+ */
+ log_trace ("Commanding protected operation to thread 2.\n");
+ send_mutex_cmd (2, CMD_PROTECTED_OP, &m[0]);
+ log_trace ("Commanding protected operation to thread 3.\n");
+ send_mutex_cmd (3, CMD_PROTECTED_OP, &m[1]);
+ sleep (1);
+
+ /*
+ * Command thread 4 to take mutex 2 via a protected operation
+ * and thread 5 to enter a busy loop for 5 seconds. Since
+ * thread 5 has higher priority than thread 4, thread 5 will
+ * enter the busy loop before thread 4 is activated.
+ */
+ log_trace ("Commanding protected operation to thread 4.\n");
+ send_mutex_cmd (4, CMD_PROTECTED_OP, &m[2]);
+ log_trace ("Commanding busy loop to thread 5.\n");
+ send_cmd (5, CMD_BUSY_LOOP);
+ sleep (1);
+ if ((states[5].flags & FLAGS_IS_BUSY) == 0)
+ log_error ("thread 5 is not running.\n");
+ log_trace ("Commanding protected operation thread 6.\n");
+ send_mutex_cmd (6, CMD_PROTECTED_OP, &m[0]);
+ sleep (1);
+ if ((states[4].flags & FLAGS_WAS_BUSY) == 0)
+ log_error ("thread 4 failed to inherit priority.\n");
+ states[4].flags = 0;
+ send_cmd (4, CMD_RELEASE_ALL);
+ sleep (5);
+ check_run_order ("4,6,5,3,2");
+
+ /*
+ * Clear the flags.
+ */
+ for (i = 0; i < NUM_THREADS; i++)
+ states[i].flags = 0;
+
+ /*
+ * Test setup:
+ * Thread 2 - enter busy loop (SCHED_FIFO)
+ * Thread 4 - take mutex 0
+ * Thread 4 - priority change to same priority as thread 2
+ * Thread 4 - release mutex 0
+ *
+ * Expected results:
+ * Since thread 4 owns a priority mutex, it should be
+ * placed at the front of the run queue (for its new
+ * priority slot) when its priority is lowered to the
+ * same priority as thread 2. If thread 4 did not own
+ * a priority mutex, then it would have been added to
+ * the end of the run queue and thread 2 would have
+ * executed until it blocked (because it's scheduling
+ * policy is SCHED_FIFO).
+ *
+ */
+ log (" Inheritence test with change of priority - ");
+
+ /*
+ * Change threads 2 and 4 scheduling policies to be
+ * SCHED_FIFO.
+ */
+ param.sched_priority = states[2].priority;
+ assert (pthread_setschedparam (states[2].tid, SCHED_FIFO,
+ &param) == 0);
+ param.sched_priority = states[4].priority;
+ assert (pthread_setschedparam (states[4].tid, SCHED_FIFO,
+ &param) == 0);
+
+ /*
+ * Command thread 4 to take mutex 0.
+ */
+ send_mutex_cmd (4, CMD_TAKE_MUTEX, &m[0]);
+ sleep (1);
+
+ /*
+ * Command thread 2 to enter busy loop.
+ */
+ send_cmd (2, CMD_BUSY_LOOP);
+ sleep (1); /* Allow command to be received. */
+
+ /*
+ * Command thread 4 to enter busy loop.
+ */
+ send_cmd (4, CMD_BUSY_LOOP);
+ sleep (1); /* Allow command to be received. */
+
+ /* Have threads 2 and 4 report themselves. */
+ states[2].flags = FLAGS_REPORT_WAITMUTEX;
+ states[4].flags = FLAGS_REPORT_WAITMUTEX;
+
+ /* Change the priority of thread 4. */
+ param.sched_priority = states[2].priority;
+ assert (pthread_setschedparam (states[4].tid, SCHED_FIFO,
+ &param) == 0);
+ sleep (5);
+ check_run_order ("4,2");
+
+ /* Clear the flags */
+ states[2].flags = 0;
+ states[4].flags = 0;
+
+ /* Reset the policies. */
+ param.sched_priority = states[2].priority;
+ assert (pthread_setschedparam (states[2].tid, SCHED_RR,
+ &param) == 0);
+ param.sched_priority = states[4].priority;
+ assert (pthread_setschedparam (states[4].tid, SCHED_RR,
+ &param) == 0);
+
+ send_cmd (4, CMD_RELEASE_MUTEX);
+ sleep (1);
+
+ /* Destroy the mutexes. */
+ for (i = 0; i < 3; i++)
+ assert (pthread_mutex_destroy (&m[i]) == 0);
+ }
+}
+
+
+int main (int argc, char *argv[])
+{
+ pthread_mutexattr_t mattr;
+ pthread_condattr_t cattr;
+ pthread_attr_t pattr;
+ int i, policy, main_prio;
+ void * exit_status;
+ sigset_t mask;
+ struct sigaction act;
+ struct sched_param param;
+
+ logfile = stdout;
+
+ assert (pthread_getschedparam (pthread_self (), &policy, &param) == 0);
+ main_prio = param.sched_priority;
+
+ /* Setupt our signal mask. */
+ sigfillset (&mask);
+ sigdelset (&mask, SIGINT);
+ sigprocmask (SIG_SETMASK, &mask, NULL);
+
+ /* Install a signal handler for SIGINT */
+ sigemptyset (&act.sa_mask);
+ sigaddset (&act.sa_mask, SIGINT);
+ act.sa_handler = sighandler;
+ act.sa_flags = SA_RESTART;
+ sigaction (SIGINT, &act, NULL);
+
+ /*
+ * Initialize the thread attribute.
+ */
+ assert (pthread_attr_init (&pattr) == 0);
+ assert (pthread_attr_setdetachstate (&pattr,
+ PTHREAD_CREATE_JOINABLE) == 0);
+
+ /*
+ * Initialize and create the waiter and condvar mutexes.
+ */
+ assert (pthread_mutexattr_init (&mattr) == 0);
+ assert (pthread_mutex_init (&waiter_mutex, &mattr) == 0);
+ assert (pthread_mutex_init (&cond_mutex, &mattr) == 0);
+
+ /*
+ * Initialize and create a condition variable.
+ */
+ assert (pthread_condattr_init (&cattr) == 0);
+ assert (pthread_cond_init (&cond_var, &cattr) == 0);
+
+ /* Create a pipe to catch the results of thread wakeups. */
+ assert (pipe (pipefd) == 0);
+
+#ifdef DEBUG
+ assert (pthread_switch_add_np (kern_switch) == 0);
+#endif
+
+ /*
+ * Create the waiting threads.
+ */
+ for (i = 0; i < NUM_THREADS; i++) {
+ assert (pthread_cond_init (&states[i].cond_var, &cattr) == 0);
+ states[i].id = (u_int8_t) i; /* NUM_THREADS must be <= 256 */
+ states[i].status = 0;
+ states[i].cmd.cmd_id = CMD_NONE;
+ states[i].flags = 0; /* No flags yet. */
+ assert (pthread_create (&states[i].tid, &pattr, waiter,
+ (void *) &states[i]) == 0);
+ param.sched_priority = main_prio - 10 + i;
+ states[i].priority = param.sched_priority;
+ assert (pthread_setschedparam (states[i].tid, SCHED_OTHER,
+ &param) == 0);
+#if defined(_LIBC_R_)
+ {
+ char buf[30];
+
+ snprintf (buf, sizeof(buf), "waiter_%d", i);
+ pthread_set_name_np (states[i].tid, buf);
+ }
+#endif
+ }
+
+ /* Allow the threads to start. */
+ sleep (1);
+ log_trace ("Done creating threads.\n");
+
+ log ("\n");
+ mutex_init_test ();
+ log ("\n");
+ mutex_destroy_test ();
+ log ("\n");
+ mutex_lock_test ();
+ log ("\n");
+ mutex_unlock_test ();
+ log ("\n");
+ queueing_order_test ();
+ log ("\n");
+ mutex_prioinherit_test ();
+ log ("\n");
+ mutex_prioceiling_test ();
+ log ("\n");
+
+ log ("Total tests %d, passed %d, failed %d\n",
+ total, pass_count, error_count);
+
+ /* Set the done flag and signal the threads to exit. */
+ log_trace ("Setting done flag.\n");
+ done = 1;
+
+ /*
+ * Wait for the threads to finish.
+ */
+ log_trace ("Trying to join threads.\n");
+ for (i = 0; i < NUM_THREADS; i++) {
+ send_cmd (i, CMD_NONE);
+ assert (pthread_join (states[i].tid, &exit_status) == 0);
+ }
+
+ /* Clean up after ourselves. */
+ close (pipefd[0]);
+ close (pipefd[1]);
+
+ if (error_count != 0)
+ exit (EX_OSERR); /* any better ideas??? */
+ else
+ exit (EX_OK);
+}
diff --git a/lib/libc_r/test/mutex_d.exp b/lib/libc_r/test/mutex_d.exp
new file mode 100644
index 0000000..de8a4e4
--- /dev/null
+++ b/lib/libc_r/test/mutex_d.exp
@@ -0,0 +1,290 @@
+
+Testing pthread_mutex_init
+--------------------------
+ Protocol PTHREAD_PRIO_NONE, Type POSIX (type not specified) - PASS
+ Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_DEFAULT - PASS
+ Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_ERRORCHECK - PASS
+ Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_NORMAL - PASS
+ Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_RECURSIVE - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type POSIX (type not specified) - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_DEFAULT - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_ERRORCHECK - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_NORMAL - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_RECURSIVE - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type POSIX (type not specified) - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_DEFAULT - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_ERRORCHECK - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_NORMAL - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_RECURSIVE - PASS
+
+Testing pthread_mutex_destroy
+-----------------------------
+ Protocol PTHREAD_PRIO_NONE, Type POSIX (type not specified)
+ Destruction of unused mutex - PASS
+ Destruction of mutex locked by self - PASS
+ Destruction of mutex locked by another thread - PASS
+ Destruction of mutex while being used in cond_wait - PASS
+ Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_DEFAULT
+ Destruction of unused mutex - PASS
+ Destruction of mutex locked by self - PASS
+ Destruction of mutex locked by another thread - PASS
+ Destruction of mutex while being used in cond_wait - PASS
+ Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_ERRORCHECK
+ Destruction of unused mutex - PASS
+ Destruction of mutex locked by self - PASS
+ Destruction of mutex locked by another thread - PASS
+ Destruction of mutex while being used in cond_wait - PASS
+ Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_NORMAL
+ Destruction of unused mutex - PASS
+ Destruction of mutex locked by self - PASS
+ Destruction of mutex locked by another thread - PASS
+ Destruction of mutex while being used in cond_wait - PASS
+ Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_RECURSIVE
+ Destruction of unused mutex - PASS
+ Destruction of mutex locked by self - PASS
+ Destruction of mutex locked by another thread - PASS
+ Destruction of mutex while being used in cond_wait - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type POSIX (type not specified)
+ Destruction of unused mutex - PASS
+ Destruction of mutex locked by self - PASS
+ Destruction of mutex locked by another thread - PASS
+ Destruction of mutex while being used in cond_wait - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_DEFAULT
+ Destruction of unused mutex - PASS
+ Destruction of mutex locked by self - PASS
+ Destruction of mutex locked by another thread - PASS
+ Destruction of mutex while being used in cond_wait - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_ERRORCHECK
+ Destruction of unused mutex - PASS
+ Destruction of mutex locked by self - PASS
+ Destruction of mutex locked by another thread - PASS
+ Destruction of mutex while being used in cond_wait - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_NORMAL
+ Destruction of unused mutex - PASS
+ Destruction of mutex locked by self - PASS
+ Destruction of mutex locked by another thread - PASS
+ Destruction of mutex while being used in cond_wait - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_RECURSIVE
+ Destruction of unused mutex - PASS
+ Destruction of mutex locked by self - PASS
+ Destruction of mutex locked by another thread - PASS
+ Destruction of mutex while being used in cond_wait - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type POSIX (type not specified)
+ Destruction of unused mutex - PASS
+ Destruction of mutex locked by self - PASS
+ Destruction of mutex locked by another thread - PASS
+ Destruction of mutex while being used in cond_wait - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_DEFAULT
+ Destruction of unused mutex - PASS
+ Destruction of mutex locked by self - PASS
+ Destruction of mutex locked by another thread - PASS
+ Destruction of mutex while being used in cond_wait - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_ERRORCHECK
+ Destruction of unused mutex - PASS
+ Destruction of mutex locked by self - PASS
+ Destruction of mutex locked by another thread - PASS
+ Destruction of mutex while being used in cond_wait - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_NORMAL
+ Destruction of unused mutex - PASS
+ Destruction of mutex locked by self - PASS
+ Destruction of mutex locked by another thread - PASS
+ Destruction of mutex while being used in cond_wait - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_RECURSIVE
+ Destruction of unused mutex - PASS
+ Destruction of mutex locked by self - PASS
+ Destruction of mutex locked by another thread - PASS
+ Destruction of mutex while being used in cond_wait - PASS
+
+Testing pthread_mutex_lock
+--------------------------
+ Protocol PTHREAD_PRIO_NONE, Type POSIX (type not specified)
+ Lock on unlocked mutex - PASS
+ Lock on invalid mutex - PASS
+ Lock on mutex held by self - PASS
+ Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_DEFAULT
+ Lock on unlocked mutex - PASS
+ Lock on invalid mutex - PASS
+ Lock on mutex held by self - PASS
+ Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_ERRORCHECK
+ Lock on unlocked mutex - PASS
+ Lock on invalid mutex - PASS
+ Lock on mutex held by self - PASS
+ Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_NORMAL
+ Lock on unlocked mutex - PASS
+ Lock on invalid mutex - PASS
+ Lock on mutex held by self - PASS
+ Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_RECURSIVE
+ Lock on unlocked mutex - PASS
+ Lock on invalid mutex - PASS
+ Lock on mutex held by self - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type POSIX (type not specified)
+ Lock on unlocked mutex - PASS
+ Lock on invalid mutex - PASS
+ Lock on mutex held by self - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_DEFAULT
+ Lock on unlocked mutex - PASS
+ Lock on invalid mutex - PASS
+ Lock on mutex held by self - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_ERRORCHECK
+ Lock on unlocked mutex - PASS
+ Lock on invalid mutex - PASS
+ Lock on mutex held by self - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_NORMAL
+ Lock on unlocked mutex - PASS
+ Lock on invalid mutex - PASS
+ Lock on mutex held by self - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_RECURSIVE
+ Lock on unlocked mutex - PASS
+ Lock on invalid mutex - PASS
+ Lock on mutex held by self - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type POSIX (type not specified)
+ Lock on unlocked mutex - PASS
+ Lock on invalid mutex - PASS
+ Lock on mutex held by self - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_DEFAULT
+ Lock on unlocked mutex - PASS
+ Lock on invalid mutex - PASS
+ Lock on mutex held by self - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_ERRORCHECK
+ Lock on unlocked mutex - PASS
+ Lock on invalid mutex - PASS
+ Lock on mutex held by self - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_NORMAL
+ Lock on unlocked mutex - PASS
+ Lock on invalid mutex - PASS
+ Lock on mutex held by self - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_RECURSIVE
+ Lock on unlocked mutex - PASS
+ Lock on invalid mutex - PASS
+ Lock on mutex held by self - PASS
+
+Testing pthread_mutex_unlock
+----------------------------
+ Protocol PTHREAD_PRIO_NONE, Type POSIX (type not specified)
+ Unlock on mutex held by self - PASS
+ Unlock on invalid mutex - PASS
+ Unlock on mutex locked by another thread - PASS
+ Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_DEFAULT
+ Unlock on mutex held by self - PASS
+ Unlock on invalid mutex - PASS
+ Unlock on mutex locked by another thread - PASS
+ Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_ERRORCHECK
+ Unlock on mutex held by self - PASS
+ Unlock on invalid mutex - PASS
+ Unlock on mutex locked by another thread - PASS
+ Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_NORMAL
+ Unlock on mutex held by self - PASS
+ Unlock on invalid mutex - PASS
+ Unlock on mutex locked by another thread - PASS
+ Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_RECURSIVE
+ Unlock on mutex held by self - PASS
+ Unlock on invalid mutex - PASS
+ Unlock on mutex locked by another thread - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type POSIX (type not specified)
+ Unlock on mutex held by self - PASS
+ Unlock on invalid mutex - PASS
+ Unlock on mutex locked by another thread - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_DEFAULT
+ Unlock on mutex held by self - PASS
+ Unlock on invalid mutex - PASS
+ Unlock on mutex locked by another thread - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_ERRORCHECK
+ Unlock on mutex held by self - PASS
+ Unlock on invalid mutex - PASS
+ Unlock on mutex locked by another thread - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_NORMAL
+ Unlock on mutex held by self - PASS
+ Unlock on invalid mutex - PASS
+ Unlock on mutex locked by another thread - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_RECURSIVE
+ Unlock on mutex held by self - PASS
+ Unlock on invalid mutex - PASS
+ Unlock on mutex locked by another thread - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type POSIX (type not specified)
+ Unlock on mutex held by self - PASS
+ Unlock on invalid mutex - PASS
+ Unlock on mutex locked by another thread - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_DEFAULT
+ Unlock on mutex held by self - PASS
+ Unlock on invalid mutex - PASS
+ Unlock on mutex locked by another thread - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_ERRORCHECK
+ Unlock on mutex held by self - PASS
+ Unlock on invalid mutex - PASS
+ Unlock on mutex locked by another thread - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_NORMAL
+ Unlock on mutex held by self - PASS
+ Unlock on invalid mutex - PASS
+ Unlock on mutex locked by another thread - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_RECURSIVE
+ Unlock on mutex held by self - PASS
+ Unlock on invalid mutex - PASS
+ Unlock on mutex locked by another thread - PASS
+
+Testing queueing order
+----------------------
+ Queueing order on a mutex - PASS
+ Queueing order on a condition variable - PASS
+
+Testing priority inheritence
+----------------------------
+ Protype PTHREAD_PRIO_INHERIT, Type POSIX (type not specified)
+ Simple inheritence test - PASS
+ Inheritence test with change of priority - PASS
+ Protype PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_DEFAULT
+ Simple inheritence test - PASS
+ Inheritence test with change of priority - PASS
+ Protype PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_ERRORCHECK
+ Simple inheritence test - PASS
+ Inheritence test with change of priority - PASS
+ Protype PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_NORMAL
+ Simple inheritence test - PASS
+ Inheritence test with change of priority - PASS
+ Protype PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_RECURSIVE
+ Simple inheritence test - PASS
+ Inheritence test with change of priority - PASS
+
+Testing priority ceilings
+-------------------------
+ Protype PTHREAD_PRIO_PROTECT, Type POSIX (type not specified)
+ Lock with ceiling priority < thread priority - PASS
+ Lock with ceiling priority = thread priority - PASS
+ Lock with ceiling priority > thread priority - PASS
+ Preemption with ceiling priority < thread priority - PASS
+ Preemption with ceiling priority = thread priority - PASS
+ SCHED_FIFO scheduling and ceiling priority = thread priority - PASS
+ SCHED_FIFO scheduling and ceiling priority > thread priority - PASS
+ Protype PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_DEFAULT
+ Lock with ceiling priority < thread priority - PASS
+ Lock with ceiling priority = thread priority - PASS
+ Lock with ceiling priority > thread priority - PASS
+ Preemption with ceiling priority < thread priority - PASS
+ Preemption with ceiling priority = thread priority - PASS
+ SCHED_FIFO scheduling and ceiling priority = thread priority - PASS
+ SCHED_FIFO scheduling and ceiling priority > thread priority - PASS
+ Protype PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_ERRORCHECK
+ Lock with ceiling priority < thread priority - PASS
+ Lock with ceiling priority = thread priority - PASS
+ Lock with ceiling priority > thread priority - PASS
+ Preemption with ceiling priority < thread priority - PASS
+ Preemption with ceiling priority = thread priority - PASS
+ SCHED_FIFO scheduling and ceiling priority = thread priority - PASS
+ SCHED_FIFO scheduling and ceiling priority > thread priority - PASS
+ Protype PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_NORMAL
+ Lock with ceiling priority < thread priority - PASS
+ Lock with ceiling priority = thread priority - PASS
+ Lock with ceiling priority > thread priority - PASS
+ Preemption with ceiling priority < thread priority - PASS
+ Preemption with ceiling priority = thread priority - PASS
+ SCHED_FIFO scheduling and ceiling priority = thread priority - PASS
+ SCHED_FIFO scheduling and ceiling priority > thread priority - PASS
+ Protype PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_RECURSIVE
+ Lock with ceiling priority < thread priority - PASS
+ Lock with ceiling priority = thread priority - PASS
+ Lock with ceiling priority > thread priority - PASS
+ Preemption with ceiling priority < thread priority - PASS
+ Preemption with ceiling priority = thread priority - PASS
+ SCHED_FIFO scheduling and ceiling priority = thread priority - PASS
+ SCHED_FIFO scheduling and ceiling priority > thread priority - PASS
+
+Total tests 212, passed 212, failed 0
diff --git a/lib/libc_r/test/propagate_s.pl b/lib/libc_r/test/propagate_s.pl
new file mode 100755
index 0000000..9cd5fb0
--- /dev/null
+++ b/lib/libc_r/test/propagate_s.pl
@@ -0,0 +1,74 @@
+#!/usr/bin/perl -w
+#
+# 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.
+#
+###########################################################################
+#
+# Verify that no cancellation points are propagated inside of libc_r.
+#
+# $FreeBSD$
+#
+
+@CPOINTS = ("aio_suspend", "close", "creat", "fcntl", "fsync", "mq_receive",
+ "mq_send", "msync", "nanosleep", "open", "pause",
+ "pthread_cond_timedwait", "pthread_cond_wait", "pthread_join",
+ "pthread_testcancel", "read", "sem_wait", "sigsuspend",
+ "sigtimedwait", "sigwait", "sigwaitinfo", "sleep", "system",
+ "tcdrain", "wait", "waitpid", "write");
+
+print "1..1\n";
+
+$cpoints = join '\|', @CPOINTS;
+$regexp = "\" U \\(" . $cpoints . "\\\)\$\"";
+
+`nm -a /usr/lib/libc.a |grep $regexp >propagate_s.out`;
+if (!open (NMOUT, "<./propagate_s.out"))
+{
+ print "not ok 1\n";
+}
+else
+{
+ $propagations = 0;
+
+ while (<NMOUT>)
+ {
+ $propagations++;
+ print "$_\n";
+ }
+ if ($propagations != 0)
+ {
+ print "$propagations propagation(s)\n";
+ print "not ok 1\n";
+ }
+ else
+ {
+ print "ok 1\n";
+ }
+ close NMOUT;
+ unlink "propagate_s.out";
+}
diff --git a/lib/libc_r/test/sem_d.c b/lib/libc_r/test/sem_d.c
new file mode 100644
index 0000000..b834591
--- /dev/null
+++ b/lib/libc_r/test/sem_d.c
@@ -0,0 +1,133 @@
+/****************************************************************************
+ *
+ * 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.
+ *
+ ****************************************************************************
+ *
+ * sem test.
+ *
+ * $FreeBSD$
+ *
+ ****************************************************************************/
+
+#include <assert.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <semaphore.h>
+#include <pthread.h>
+
+#define NTHREADS 10
+
+void *
+entry(void * a_arg)
+{
+ sem_t * sem = (sem_t *) a_arg;
+
+ sem_wait(sem);
+ fprintf(stderr, "Got semaphore\n");
+
+ return NULL;
+}
+
+int
+main()
+{
+ sem_t sem_a, sem_b;
+ pthread_t threads[NTHREADS];
+ unsigned i;
+ int val;
+
+ fprintf(stderr, "Test begin\n");
+
+#ifdef _LIBC_R_
+ assert(-1 == sem_init(&sem_b, 1, 0));
+ assert(EPERM == errno);
+#endif
+
+ assert(0 == sem_init(&sem_b, 0, 0));
+ assert(0 == sem_getvalue(&sem_b, &val));
+ assert(0 == val);
+
+ assert(0 == sem_post(&sem_b));
+ assert(0 == sem_getvalue(&sem_b, &val));
+ assert(1 == val);
+
+ assert(0 == sem_wait(&sem_b));
+ assert(-1 == sem_trywait(&sem_b));
+ assert(EAGAIN == errno);
+ assert(0 == sem_post(&sem_b));
+ assert(0 == sem_trywait(&sem_b));
+ assert(0 == sem_post(&sem_b));
+ assert(0 == sem_wait(&sem_b));
+ assert(0 == sem_post(&sem_b));
+
+#ifdef _LIBC_R_
+ assert(SEM_FAILED == sem_open("/foo", O_CREAT | O_EXCL, 0644, 0));
+ assert(ENOSYS == errno);
+
+ assert(-1 == sem_close(&sem_b));
+ assert(ENOSYS == errno);
+
+ assert(-1 == sem_unlink("/foo"));
+ assert(ENOSYS == errno);
+#endif
+
+ assert(0 == sem_destroy(&sem_b));
+
+ assert(0 == sem_init(&sem_a, 0, 0));
+
+ for (i = 0; i < NTHREADS; i++) {
+ pthread_create(&threads[i], NULL, entry, (void *) &sem_a);
+ }
+
+ for (i = 0; i < NTHREADS; i++) {
+ assert(0 == sem_post(&sem_a));
+ }
+
+ for (i = 0; i < NTHREADS; i++) {
+ pthread_join(threads[i], NULL);
+ }
+
+ for (i = 0; i < NTHREADS; i++) {
+ pthread_create(&threads[i], NULL, entry, (void *) &sem_a);
+ }
+
+ for (i = 0; i < NTHREADS; i++) {
+ assert(0 == sem_post(&sem_a));
+ }
+
+ for (i = 0; i < NTHREADS; i++) {
+ pthread_join(threads[i], NULL);
+ }
+
+ assert(0 == sem_destroy(&sem_a));
+
+ fprintf(stderr, "Test end\n");
+ return 0;
+}
diff --git a/lib/libc_r/test/sem_d.exp b/lib/libc_r/test/sem_d.exp
new file mode 100644
index 0000000..b0de3da
--- /dev/null
+++ b/lib/libc_r/test/sem_d.exp
@@ -0,0 +1,22 @@
+Test begin
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Test end
diff --git a/lib/libc_r/test/sigsuspend_d.c b/lib/libc_r/test/sigsuspend_d.c
new file mode 100644
index 0000000..d2420ed
--- /dev/null
+++ b/lib/libc_r/test/sigsuspend_d.c
@@ -0,0 +1,288 @@
+/*
+ * Copyright (c) 1998 Daniel M. Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel M. Eischen.
+ * 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 DANIEL M. 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 REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <unistd.h>
+
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+
+#if defined(_LIBC_R_)
+#include <pthread_np.h>
+#endif
+
+static int sigcounts[NSIG + 1];
+static int sigfifo[NSIG + 1];
+static int fifo_depth = 0;
+static sigset_t suspender_mask;
+static pthread_t suspender_tid;
+
+
+static void *
+sigsuspender (void *arg)
+{
+ int save_count, status, i;
+ sigset_t run_mask;
+
+ /* Run with all signals blocked. */
+ sigfillset (&run_mask);
+ sigprocmask (SIG_SETMASK, &run_mask, NULL);
+
+ /* Allow these signals to wake us up during a sigsuspend. */
+ sigfillset (&suspender_mask); /* Default action */
+ sigdelset (&suspender_mask, SIGINT); /* terminate */
+ sigdelset (&suspender_mask, SIGHUP); /* terminate */
+ sigdelset (&suspender_mask, SIGQUIT); /* create core image */
+ sigdelset (&suspender_mask, SIGURG); /* ignore */
+ sigdelset (&suspender_mask, SIGIO); /* ignore */
+ sigdelset (&suspender_mask, SIGUSR2); /* terminate */
+
+ while (sigcounts[SIGINT] == 0) {
+ save_count = sigcounts[SIGUSR2];
+
+ status = sigsuspend (&suspender_mask);
+ if ((status == 0) || (errno != EINTR)) {
+ fprintf (stderr, "Unable to suspend for signals, "
+ "errno %d, return value %d\n",
+ errno, status);
+ exit (1);
+ }
+ for (i = 0; i < fifo_depth; i++)
+ fprintf (stderr, "Sigsuspend woke up by signal %d\n",
+ sigfifo[i]);
+ fifo_depth = 0;
+ }
+
+ pthread_exit (arg);
+ return (NULL);
+}
+
+
+static void
+sighandler (int signo)
+{
+ sigset_t set, suspend_set;
+ pthread_t self;
+
+ if ((signo >= 0) && (signo <= NSIG))
+ sigcounts[signo]++;
+
+ /*
+ * If we are running on behalf of the suspender thread,
+ * ensure that we have the correct mask set.
+ */
+ self = pthread_self ();
+ if (self == suspender_tid) {
+ sigfifo[fifo_depth] = signo;
+ fifo_depth++;
+ fprintf (stderr,
+ " -> Suspender thread signal handler caught signal %d\n",
+ signo);
+
+ /* Get the current signal mask. */
+ sigprocmask (SIG_SETMASK, NULL, &set);
+
+ /* The handler should run with the current signal masked. */
+ suspend_set = suspender_mask;
+ sigaddset(&suspend_set, signo);
+
+ if (memcmp(&set, &suspend_set, sizeof(set)))
+ fprintf (stderr,
+ " >>> FAIL: sigsuspender signal handler running "
+ "with incorrect mask.\n");
+ }
+ else
+ fprintf (stderr,
+ " -> Main thread signal handler caught signal %d\n",
+ signo);
+}
+
+
+static void
+send_thread_signal (pthread_t tid, int signo)
+{
+ if (pthread_kill (tid, signo) != 0) {
+ fprintf (stderr, "Unable to send thread signal, errno %d.\n",
+ errno);
+ exit (1);
+ }
+}
+
+
+static void
+send_process_signal (int signo)
+{
+ if (kill (getpid (), signo) != 0) {
+ fprintf (stderr, "Unable to send process signal, errno %d.\n",
+ errno);
+ exit (1);
+ }
+}
+
+
+int main (int argc, char *argv[])
+{
+ pthread_attr_t pattr;
+ void * exit_status;
+ struct sigaction act;
+ sigset_t oldset;
+ sigset_t newset;
+
+ /* Initialize our signal counts. */
+ memset ((void *) sigcounts, 0, NSIG * sizeof (int));
+
+ /* Ignore signal SIGIO. */
+ sigemptyset (&act.sa_mask);
+ sigaddset (&act.sa_mask, SIGIO);
+ act.sa_handler = SIG_IGN;
+ act.sa_flags = 0;
+ sigaction (SIGIO, &act, NULL);
+
+ /* Install a signal handler for SIGURG. */
+ sigemptyset (&act.sa_mask);
+ sigaddset (&act.sa_mask, SIGURG);
+ act.sa_handler = sighandler;
+ act.sa_flags = SA_RESTART;
+ sigaction (SIGURG, &act, NULL);
+
+ /* Install a signal handler for SIGXCPU */
+ sigemptyset (&act.sa_mask);
+ sigaddset (&act.sa_mask, SIGXCPU);
+ sigaction (SIGXCPU, &act, NULL);
+
+ /* Get our current signal mask. */
+ sigprocmask (SIG_SETMASK, NULL, &oldset);
+
+ /* Mask out SIGUSR1 and SIGUSR2. */
+ newset = oldset;
+ sigaddset (&newset, SIGUSR1);
+ sigaddset (&newset, SIGUSR2);
+ sigprocmask (SIG_SETMASK, &newset, NULL);
+
+ /* Install a signal handler for SIGUSR1 */
+ sigemptyset (&act.sa_mask);
+ sigaddset (&act.sa_mask, SIGUSR1);
+ sigaction (SIGUSR1, &act, NULL);
+
+ /* Install a signal handler for SIGUSR2 */
+ sigemptyset (&act.sa_mask);
+ sigaddset (&act.sa_mask, SIGUSR2);
+ sigaction (SIGUSR2, &act, NULL);
+
+ /*
+ * Initialize the thread attribute.
+ */
+ if ((pthread_attr_init (&pattr) != 0) ||
+ (pthread_attr_setdetachstate (&pattr,
+ PTHREAD_CREATE_JOINABLE) != 0)) {
+ fprintf (stderr, "Unable to initialize thread attributes.\n");
+ exit (1);
+ }
+
+ /*
+ * Create the sigsuspender thread.
+ */
+ if (pthread_create (&suspender_tid, &pattr, sigsuspender, NULL) != 0) {
+ fprintf (stderr, "Unable to create thread, errno %d.\n", errno);
+ exit (1);
+ }
+#if defined(_LIBC_R)
+ pthread_set_name_np (suspender_tid, "sigsuspender");
+#endif
+
+ /*
+ * Verify that an ignored signal doesn't cause a wakeup.
+ * We don't have a handler installed for SIGIO.
+ */
+ send_thread_signal (suspender_tid, SIGIO);
+ sleep (1);
+ send_process_signal (SIGIO);
+ sleep (1);
+ if (sigcounts[SIGIO] != 0)
+ fprintf (stderr, "FAIL: sigsuspend wakes up for ignored signal "
+ "SIGIO.\n");
+
+ /*
+ * Verify that a signal with a default action of ignore, for
+ * which we have a signal handler installed, will release a
+ * sigsuspend.
+ */
+ send_thread_signal (suspender_tid, SIGURG);
+ sleep (1);
+ send_process_signal (SIGURG);
+ sleep (1);
+ if (sigcounts[SIGURG] != 2)
+ fprintf (stderr,
+ "FAIL: sigsuspend doesn't wake up for SIGURG.\n");
+
+ /*
+ * Verify that a SIGUSR2 signal will release a sigsuspended
+ * thread.
+ */
+ send_thread_signal (suspender_tid, SIGUSR2);
+ sleep (1);
+ send_process_signal (SIGUSR2);
+ sleep (1);
+ if (sigcounts[SIGUSR2] != 2)
+ fprintf (stderr,
+ "FAIL: sigsuspend doesn't wake up for SIGUSR2.\n");
+
+ /*
+ * Verify that a signal, blocked in both the main and
+ * sigsuspender threads, does not cause the signal handler
+ * to be called.
+ */
+ send_thread_signal (suspender_tid, SIGUSR1);
+ sleep (1);
+ send_process_signal (SIGUSR1);
+ sleep (1);
+ if (sigcounts[SIGUSR1] != 0)
+ fprintf (stderr, "FAIL: signal hander called for SIGUSR1.\n");
+
+ /*
+ * Verify that we can still kill the process for a signal
+ * not being waited on by sigwait.
+ */
+ send_process_signal (SIGPIPE);
+ fprintf (stderr, "FAIL: SIGPIPE did not terminate process.\n");
+
+ /*
+ * Wait for the thread to finish.
+ */
+ pthread_join (suspender_tid, &exit_status);
+
+ return (0);
+}
diff --git a/lib/libc_r/test/sigsuspend_d.exp b/lib/libc_r/test/sigsuspend_d.exp
new file mode 100644
index 0000000..901fa50
--- /dev/null
+++ b/lib/libc_r/test/sigsuspend_d.exp
@@ -0,0 +1,8 @@
+ -> Suspender thread signal handler caught signal 16
+Sigsuspend woke up by signal 16
+ -> Suspender thread signal handler caught signal 16
+Sigsuspend woke up by signal 16
+ -> Suspender thread signal handler caught signal 31
+Sigsuspend woke up by signal 31
+ -> Suspender thread signal handler caught signal 31
+Sigsuspend woke up by signal 31
diff --git a/lib/libc_r/test/sigwait_d.c b/lib/libc_r/test/sigwait_d.c
new file mode 100644
index 0000000..f3ccd6b
--- /dev/null
+++ b/lib/libc_r/test/sigwait_d.c
@@ -0,0 +1,304 @@
+/*
+ * Copyright (c) 1998 Daniel M. Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel M. Eischen.
+ * 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 DANIEL M. 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 REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <unistd.h>
+
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+
+#if defined(_LIBC_R_)
+#include <pthread_np.h>
+#endif
+
+static int sigcounts[NSIG + 1];
+static sigset_t wait_mask;
+static pthread_mutex_t waiter_mutex;
+
+
+static void *
+sigwaiter (void *arg)
+{
+ int signo;
+ sigset_t mask;
+
+ /* Block SIGHUP */
+ sigemptyset (&mask);
+ sigaddset (&mask, SIGHUP);
+ sigprocmask (SIG_BLOCK, &mask, NULL);
+
+ while (sigcounts[SIGINT] == 0) {
+ if (sigwait (&wait_mask, &signo) != 0) {
+ fprintf (stderr,
+ "Unable to wait for signal, errno %d\n",
+ errno);
+ exit (1);
+ }
+ sigcounts[signo]++;
+ fprintf (stderr, "Sigwait caught signal %d\n", signo);
+
+ /* Allow the main thread to prevent the sigwait. */
+ pthread_mutex_lock (&waiter_mutex);
+ pthread_mutex_unlock (&waiter_mutex);
+ }
+
+ pthread_exit (arg);
+ return (NULL);
+}
+
+
+static void
+sighandler (int signo)
+{
+ fprintf (stderr, " -> Signal handler caught signal %d\n", signo);
+
+ if ((signo >= 0) && (signo <= NSIG))
+ sigcounts[signo]++;
+}
+
+static void
+send_thread_signal (pthread_t tid, int signo)
+{
+ if (pthread_kill (tid, signo) != 0) {
+ fprintf (stderr, "Unable to send thread signal, errno %d.\n",
+ errno);
+ exit (1);
+ }
+}
+
+static void
+send_process_signal (int signo)
+{
+ if (kill (getpid (), signo) != 0) {
+ fprintf (stderr, "Unable to send process signal, errno %d.\n",
+ errno);
+ exit (1);
+ }
+}
+
+
+int main (int argc, char *argv[])
+{
+ pthread_mutexattr_t mattr;
+ pthread_attr_t pattr;
+ pthread_t tid;
+ void * exit_status;
+ struct sigaction act;
+
+ /* Initialize our signal counts. */
+ memset ((void *) sigcounts, 0, NSIG * sizeof (int));
+
+ /* Setup our wait mask. */
+ sigemptyset (&wait_mask); /* Default action */
+ sigaddset (&wait_mask, SIGHUP); /* terminate */
+ sigaddset (&wait_mask, SIGINT); /* terminate */
+ sigaddset (&wait_mask, SIGQUIT); /* create core image */
+ sigaddset (&wait_mask, SIGURG); /* ignore */
+ sigaddset (&wait_mask, SIGIO); /* ignore */
+ sigaddset (&wait_mask, SIGUSR1); /* terminate */
+
+ /* Ignore signals SIGHUP and SIGIO. */
+ sigemptyset (&act.sa_mask);
+ sigaddset (&act.sa_mask, SIGHUP);
+ sigaddset (&act.sa_mask, SIGIO);
+ act.sa_handler = SIG_IGN;
+ act.sa_flags = 0;
+ sigaction (SIGHUP, &act, NULL);
+ sigaction (SIGIO, &act, NULL);
+
+ /* Install a signal handler for SIGURG */
+ sigemptyset (&act.sa_mask);
+ sigaddset (&act.sa_mask, SIGURG);
+ act.sa_handler = sighandler;
+ act.sa_flags = SA_RESTART;
+ sigaction (SIGURG, &act, NULL);
+
+ /* Install a signal handler for SIGXCPU */
+ sigemptyset (&act.sa_mask);
+ sigaddset (&act.sa_mask, SIGXCPU);
+ sigaction (SIGXCPU, &act, NULL);
+
+ /*
+ * Initialize the thread attribute.
+ */
+ if ((pthread_attr_init (&pattr) != 0) ||
+ (pthread_attr_setdetachstate (&pattr,
+ PTHREAD_CREATE_JOINABLE) != 0)) {
+ fprintf (stderr, "Unable to initialize thread attributes.\n");
+ exit (1);
+ }
+
+ /*
+ * Initialize and create a mutex.
+ */
+ if ((pthread_mutexattr_init (&mattr) != 0) ||
+ (pthread_mutex_init (&waiter_mutex, &mattr) != 0)) {
+ fprintf (stderr, "Unable to create waiter mutex.\n");
+ exit (1);
+ }
+
+ /*
+ * Create the sigwaiter thread.
+ */
+ if (pthread_create (&tid, &pattr, sigwaiter, NULL) != 0) {
+ fprintf (stderr, "Unable to create thread.\n");
+ exit (1);
+ }
+#if defined(_LIBC_R_)
+ pthread_set_name_np (tid, "sigwaiter");
+#endif
+
+ /*
+ * Verify that an ignored signal doesn't cause a wakeup.
+ * We don't have a handler installed for SIGIO.
+ */
+ send_thread_signal (tid, SIGIO);
+ sleep (1);
+ send_process_signal (SIGIO);
+ sleep (1);
+ if (sigcounts[SIGIO] != 0)
+ fprintf (stderr,
+ "FAIL: sigwait wakes up for ignored signal SIGIO.\n");
+
+ /*
+ * Verify that a signal with a default action of ignore, for
+ * which we have a signal handler installed, will release a sigwait.
+ */
+ send_thread_signal (tid, SIGURG);
+ sleep (1);
+ send_process_signal (SIGURG);
+ sleep (1);
+ if (sigcounts[SIGURG] != 2)
+ fprintf (stderr, "FAIL: sigwait doesn't wake up for SIGURG.\n");
+
+ /*
+ * Verify that a signal with a default action that terminates
+ * the process will release a sigwait.
+ */
+ send_thread_signal (tid, SIGUSR1);
+ sleep (1);
+ send_process_signal (SIGUSR1);
+ sleep (1);
+ if (sigcounts[SIGUSR1] != 2)
+ fprintf (stderr,
+ "FAIL: sigwait doesn't wake up for SIGUSR1.\n");
+
+ /*
+ * Verify that if we install a signal handler for a previously
+ * ignored signal, an occurrence of this signal will release
+ * the (already waiting) sigwait.
+ */
+
+ /* Install a signal handler for SIGHUP. */
+ sigemptyset (&act.sa_mask);
+ sigaddset (&act.sa_mask, SIGHUP);
+ act.sa_handler = sighandler;
+ act.sa_flags = SA_RESTART;
+ sigaction (SIGHUP, &act, NULL);
+
+ /* Sending SIGHUP should release the sigwait. */
+ send_process_signal (SIGHUP);
+ sleep (1);
+ send_thread_signal (tid, SIGHUP);
+ sleep (1);
+ if (sigcounts[SIGHUP] != 2)
+ fprintf (stderr, "FAIL: sigwait doesn't wake up for SIGHUP.\n");
+
+ /*
+ * Verify that a pending signal in the waiters mask will
+ * cause sigwait to return the pending signal. We do this
+ * by taking the waiters mutex and signaling the waiter to
+ * release him from the sigwait. The waiter will block
+ * on taking the mutex, and we can then send the waiter a
+ * signal which should be added to his pending signals.
+ * The next time the waiter does a sigwait, he should
+ * return with the pending signal.
+ */
+ sigcounts[SIGHUP] = 0;
+ pthread_mutex_lock (&waiter_mutex);
+ /* Release the waiter from sigwait. */
+ send_process_signal (SIGHUP);
+ sleep (1);
+ if (sigcounts[SIGHUP] != 1)
+ fprintf (stderr, "FAIL: sigwait doesn't wake up for SIGHUP.\n");
+ /*
+ * Add SIGHUP to the process pending signals. Since there is
+ * a signal handler installed for SIGHUP and this signal is
+ * blocked from the waiter thread and unblocked in the main
+ * thread, the signal handler should be called once for SIGHUP.
+ */
+ send_process_signal (SIGHUP);
+ /* Release the waiter thread and allow him to run. */
+ pthread_mutex_unlock (&waiter_mutex);
+ sleep (1);
+ if (sigcounts[SIGHUP] != 2)
+ fprintf (stderr,
+ "FAIL: sigwait doesn't return for pending SIGHUP.\n");
+
+ /*
+ * Repeat the above test using pthread_kill and SIGUSR1.
+ */
+ sigcounts[SIGUSR1] = 0;
+ pthread_mutex_lock (&waiter_mutex);
+ /* Release the waiter from sigwait. */
+ send_thread_signal (tid, SIGUSR1);
+ sleep (1);
+ if (sigcounts[SIGUSR1] != 1)
+ fprintf (stderr,
+ "FAIL: sigwait doesn't wake up for SIGUSR1.\n");
+ /* Add SIGUSR1 to the waiters pending signals. */
+ send_thread_signal (tid, SIGUSR1);
+ /* Release the waiter thread and allow him to run. */
+ pthread_mutex_unlock (&waiter_mutex);
+ sleep (1);
+ if (sigcounts[SIGUSR1] != 2)
+ fprintf (stderr,
+ "FAIL: sigwait doesn't return for pending SIGUSR1.\n");
+
+ /*
+ * Verify that we can still kill the process for a signal
+ * not being waited on by sigwait.
+ */
+ send_process_signal (SIGPIPE);
+ fprintf (stderr, "FAIL: SIGPIPE did not terminate process.\n");
+
+ /*
+ * Wait for the thread to finish.
+ */
+ pthread_join (tid, &exit_status);
+
+ return (0);
+}
diff --git a/lib/libc_r/test/sigwait_d.exp b/lib/libc_r/test/sigwait_d.exp
new file mode 100644
index 0000000..2e9b2c4
--- /dev/null
+++ b/lib/libc_r/test/sigwait_d.exp
@@ -0,0 +1,10 @@
+Sigwait caught signal 16
+Sigwait caught signal 16
+Sigwait caught signal 30
+Sigwait caught signal 30
+Sigwait caught signal 1
+Sigwait caught signal 1
+Sigwait caught signal 1
+ -> Signal handler caught signal 1
+Sigwait caught signal 30
+Sigwait caught signal 30
diff --git a/lib/libc_r/test/verify b/lib/libc_r/test/verify
new file mode 100755
index 0000000..2863e5c
--- /dev/null
+++ b/lib/libc_r/test/verify
@@ -0,0 +1,474 @@
+#!/usr/bin/perl -w
+#-*-mode:perl-*-
+#############################################################################
+#
+# Copyright (C) 1999-2001 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.
+#
+#############################################################################
+#
+# Test harness.
+#
+# $FreeBSD$
+#
+#############################################################################
+
+# Shut off buffering.
+select(STDOUT);
+$| = 1;
+
+#
+# Parse command-line arguments.
+#
+use Getopt::Long;
+Getopt::Long::config("bundling"); # Allow -hv rather than forcing -h -v.
+
+# Set option defaults for optional arguments.
+$opt_help = 0;
+$opt_verbose = 0;
+$opt_quiet = 0;
+$opt_srcdir = ".";
+$opt_objdir = ".";
+$opt_ustats = 0;
+$opt_zero = 0;
+
+$opt_retval =
+&GetOptions("h|help" => \$opt_help,
+ "v|verbose" => \$opt_verbose,
+ "q|quiet" => \$opt_quiet,
+ "s|srcdir=s" => \$opt_srcdir,
+ "o|objdir=s" => \$opt_objdir,
+ "u|ustats" => \$opt_ustats,
+ "z|zero" => \$opt_zero
+ );
+
+if ($opt_help)
+{
+ &usage();
+ exit(0);
+}
+
+if ($opt_retval == 0)
+{
+ &usage();
+ exit 1;
+}
+
+if ($opt_verbose && $opt_quiet)
+{
+ print STDERR "-v and -q are incompatible\n";
+ &usage();
+ exit 1;
+}
+
+if ($#ARGV + 1 == 0)
+{
+ print STDERR "No tests specified\n";
+ &usage();
+ exit 1;
+}
+
+if ($opt_verbose)
+{
+ print STDERR "Option values: h:$opt_help, v:$opt_verbose, "
+ . "s:\"$opt_srcdir\", o:\"$opt_objdir\" "
+ . "q:$opt_quiet, u:$opt_ustats, z:$opt_zero\n";
+ printf STDERR "Tests (%d total): @ARGV\n", $#ARGV + 1;
+}
+
+#
+# Create and print header.
+#
+@TSTATS =
+(
+ "--------------------------------------------------------------------------\n",
+ "Test c_user c_system c_total chng\n",
+ " passed/FAILED h_user h_system h_total %% chng\n"
+ );
+
+if (!$opt_quiet)
+{
+ foreach $line (@TSTATS)
+ {
+ printf STDOUT "$line";
+ }
+}
+
+#
+# Run sequence test(s).
+#
+$total_utime = 0.0; # Total user time.
+$total_stime = 0.0; # Total system time.
+$total_hutime = 0.0; # Total historical user time.
+$total_hstime = 0.0; # Total historical system time.
+$total_ntime = 0.0; # Total time for tests that have historical data.
+
+foreach $test (@ARGV)
+{
+ # Strip out any whitespace in $test.
+ $test =~ s/^\s*(.*)\s*$/$1/;
+
+ $okay = 1;
+
+ if (-e "$opt_srcdir/$test.exp")
+ {
+ # Diff mode.
+
+ ($okay, $utime, $stime) = &run_test($test);
+
+ if (-e "$opt_objdir/$test.out")
+ {
+ `diff $opt_srcdir/$test.exp $opt_objdir/$test.out > $opt_objdir/$test.diff 2>&1`;
+ if ($?)
+ {
+ # diff returns non-zero if there is a difference.
+ $okay = 0;
+ }
+ }
+ else
+ {
+ $okay = 0;
+ if ($opt_verbose)
+ {
+ print STDERR
+ "Nonexistent output file \"$opt_objdir/$test.out\"\n";
+ }
+ }
+
+ ($hutime, $hstime) = &print_stats($test, $okay, 0, 0, $utime, $stime);
+ }
+ else
+ {
+ # Sequence mode.
+
+ ($okay, $utime, $stime) = &run_test($test);
+
+ if (open (STEST_OUT, "<$opt_objdir/$test.out"))
+ {
+ $num_subtests = 0;
+ $num_failed_subtests = 0;
+
+ while (defined($line = <STEST_OUT>))
+ {
+ if ($line =~ /1\.\.(\d+)/)
+ {
+ $num_subtests = $1;
+ last;
+ }
+ }
+ if ($num_subtests == 0)
+ {
+ $okay = 0;
+ if ($opt_verbose)
+ {
+ print STDERR "Malformed or missing 1..n line\n";
+ }
+ }
+ else
+ {
+ for ($subtest = 1; $subtest <= $num_subtests; $subtest++)
+ {
+ while (defined($line = <STEST_OUT>))
+ {
+ if ($line =~ /^not\s+ok\s+(\d+)?/)
+ {
+ $not = 1;
+ $test_num = $1;
+ last;
+ }
+ elsif ($line =~ /^ok\s+(\d+)?/)
+ {
+ $not = 0;
+ $test_num = $1;
+ last;
+ }
+ }
+ if (defined($line))
+ {
+ if (defined($test_num) && ($test_num != $subtest))
+ {
+ # There was no output printed for one or more tests.
+ for (; $subtest < $test_num; $subtest++)
+ {
+ $num_failed_subtests++;
+ }
+ }
+ if ($not)
+ {
+ $num_failed_subtests++;
+ }
+ }
+ else
+ {
+ for (; $subtest <= $num_subtests; $subtest++)
+ {
+ $num_failed_subtests++;
+ }
+ }
+ }
+
+ if (0 < $num_failed_subtests)
+ {
+ $okay = 0;
+ }
+ }
+ }
+ else
+ {
+ if (!$opt_quiet)
+ {
+ print STDERR "Cannot open output file \"$opt_objdir/$test.out\"\n";
+ }
+ exit 1;
+ }
+
+ ($hutime, $hstime) = &print_stats($test, $okay,
+ $num_failed_subtests, $num_subtests,
+ $utime, $stime);
+ }
+
+ $total_hutime += $hutime;
+ $total_hstime += $hstime;
+
+ if ($okay)
+ {
+ $total_utime += $utime;
+ $total_stime += $stime;
+ }
+ else
+ {
+ @FAILED_TESTS = (@FAILED_TESTS, $test);
+ }
+
+ # If there were historical data, add the run time to the total time to
+ # compare against the historical run time.
+ if (0 < ($hutime + $hstime))
+ {
+ $total_ntime += $utime + $stime;
+ }
+}
+
+# Print summary stats.
+$tt_str = sprintf ("%d / %d passed (%5.2f%%%%)",
+ ($#ARGV + 1) - ($#FAILED_TESTS + 1),
+ $#ARGV + 1,
+ (($#ARGV + 1) - ($#FAILED_TESTS + 1))
+ / ($#ARGV + 1) * 100);
+
+$t_str = sprintf ("Totals %7.2f %7.2f %7.2f"
+ . " %7.2f\n"
+ . " %s %7.2f %7.2f %7.2f %7.2f%%%%\n",
+ $total_utime, $total_stime, $total_utime + $total_stime,
+ ($total_ntime - ($total_hutime + $total_hstime)),
+ $tt_str . ' ' x (40 - length($tt_str)),
+ $total_hutime, $total_hstime, $total_hutime + $total_hstime,
+ ($total_hutime + $total_hstime == 0.0) ? 0.0 :
+ (($total_ntime
+ - ($total_hutime + $total_hstime))
+ / ($total_hutime + $total_hstime) * 100));
+
+@TSTATS = ("--------------------------------------------------------------------------\n",
+ $t_str,
+ "--------------------------------------------------------------------------\n"
+ );
+if (!$opt_quiet)
+{
+ foreach $line (@TSTATS)
+ {
+ printf STDOUT "$line";
+ }
+}
+
+if ($#FAILED_TESTS >= 0)
+{
+ # One or more tests failed, so return an error.
+ exit 1;
+}
+# End of main execution.
+
+sub run_test
+{
+ my ($test) = @_;
+ my ($okay) = 1;
+ my ($tutime, $tstime);
+ my ($utime, $stime, $cutime, $cstime);
+ my (@TSTATS, @TPATH);
+ my ($t_str);
+ my ($srcdir, $objdir);
+
+ # Get the path component of $test, if any.
+ @TPATH = split(/\//, $test);
+ pop(@TPATH);
+ $srcdir = join('/', ($opt_srcdir, @TPATH));
+ $objdir = join('/', ($opt_objdir, @TPATH));
+
+ @TSTATS = ("--------------------------------------------------------------------------\n");
+
+ $t_str = sprintf ("%s%s", $test, ' ' x (40 - length($test)));
+ @TSTATS = (@TSTATS, $t_str);
+ @STATS = (@STATS, @TSTATS);
+ if (!$opt_quiet)
+ {
+ foreach $line (@TSTATS)
+ {
+ printf STDOUT "$line";
+ }
+ }
+
+ ($utime, $stime, $cutime, $cstime) = times;
+ `$opt_objdir/$test $srcdir $objdir > $opt_objdir/$test.out 2>&1`;
+ ($utime, $stime, $tutime, $tstime) = times;
+
+ # Subtract the before time from the after time.
+ $tutime -= $cutime;
+ $tstime -= $cstime;
+
+ if ($opt_zero)
+ {
+ if ($?)
+ {
+ $okay = 0;
+ if ($opt_verbose)
+ {
+ print STDERR
+ "\"$opt_objdir/$test > $opt_objdir/$test.out 2>&1\" returned $?\n";
+ }
+ }
+ }
+
+ return ($okay, $tutime, $tstime);
+}
+
+sub print_stats
+{
+ my ($test, $okay, $failed_subtests, $subtests, $utime, $stime) = @_;
+ my ($hutime, $hstime);
+# my (TEST_PERF);
+ my (@TSTATS);
+ my ($t_str, $pass_str);
+
+ $pass_str = $okay ? "passed" : "*** FAILED ***";
+ if ((0 != $subtests) && (!$okay))
+ {
+ $pass_str = $pass_str . " ($failed_subtests/$subtests failed)";
+ }
+ $pass_str = $pass_str . ' ' x (39 - length($pass_str));
+
+ if (-r "$test.perf")
+ {
+ if (!open (TEST_PERF, "<$opt_objdir/$test.perf"))
+ {
+ print STDERR "Unable to open \"$opt_objdir/$test.perf\"\n";
+ exit 1;
+ }
+ $_ = <TEST_PERF>;
+
+ ($hutime, $hstime) = split;
+ close TEST_PERF;
+
+ $t_str = sprintf (" %7.2f %7.2f %7.2f %7.2f\n"
+ . " %s %7.2f %7.2f %7.2f %7.2f%%%%\n",
+ $utime, $stime, $utime + $stime,
+ ($utime + $stime) - ($hutime + $hstime),
+ $pass_str,
+ $hutime, $hstime, $hutime + $hstime,
+ (($hutime + $hstime) == 0.0) ? 0.0 :
+ ((($utime + $stime) - ($hutime + $hstime))
+ / ($hutime + $hstime) * 100));
+ }
+ else
+ {
+ $hutime = 0.0;
+ $hstime = 0.0;
+
+ $t_str = sprintf (" %7.2f %7.2f %7.2f \n"
+ . " %s\n",
+ $utime, $stime, $utime + $stime,
+ $pass_str);
+ }
+ @TSTATS = ($t_str);
+ if (!$opt_quiet)
+ {
+ foreach $line (@TSTATS)
+ {
+ printf STDOUT "$line";
+ }
+ }
+
+ if ($okay && $opt_ustats)
+ {
+ if (!open (TEST_PERF, ">$opt_objdir/$test.perf"))
+ {
+ if (!$opt_quiet)
+ {
+ print STDERR "Unable to update \"$opt_objdir/$test.perf\"\n";
+ }
+ }
+ else
+ {
+ print TEST_PERF "$utime $stime\n";
+ close TEST_PERF;
+ }
+ }
+
+ return ($hutime, $hstime);
+}
+
+sub usage
+{
+ print <<EOF;
+$0 usage:
+ $0 [<options>] <test>+
+
+ Option | Description
+ --------------+-------------------------------------------------------------
+ -h --help | Print usage and exit.
+ -v --verbose | Verbose (incompatible with quiet).
+ -q --quiet | Quiet (incompatible with verbose).
+ -s --srcdir | Path to source tree (default is ".").
+ -o --objdir | Path to object tree (default is ".").
+ -u --ustats | Update historical statistics (stored in "<test>.perf".
+ -z --zero | Consider non-zero exit code to be an error.
+ --------------+-------------------------------------------------------------
+
+ If <test>.exp exists, <test>'s output is diff'ed with <test>.exp. Any
+ difference is considered failure.
+
+ If <test>.exp does not exist, output to stdout of the following form is
+ expected:
+
+ 1..<n>
+ {not }ok[ 1]
+ {not }ok[ 2]
+ ...
+ {not }ok[ n]
+
+ 1 <= <n> < 2^31
+
+ Lines which do not match the patterns shown above are ignored.
+EOF
+}
diff --git a/lib/libc_r/uthread/Makefile.inc b/lib/libc_r/uthread/Makefile.inc
new file mode 100644
index 0000000..6d457c1
--- /dev/null
+++ b/lib/libc_r/uthread/Makefile.inc
@@ -0,0 +1,143 @@
+# $FreeBSD$
+
+# uthread sources
+.PATH: ${.CURDIR}/uthread
+
+SRCS+= \
+ uthread_accept.c \
+ uthread_acl_delete_fd.c \
+ uthread_acl_get_fd.c \
+ uthread_acl_set_fd.c \
+ uthread_acl_aclcheck_fd.c \
+ uthread_aio_suspend.c \
+ uthread_atfork.c \
+ uthread_attr_destroy.c \
+ uthread_attr_init.c \
+ uthread_attr_getdetachstate.c \
+ uthread_attr_getguardsize.c \
+ uthread_attr_getinheritsched.c \
+ uthread_attr_getschedparam.c \
+ uthread_attr_getschedpolicy.c \
+ uthread_attr_getscope.c \
+ uthread_attr_getstack.c \
+ uthread_attr_getstackaddr.c \
+ uthread_attr_getstacksize.c \
+ uthread_attr_get_np.c \
+ uthread_attr_setcreatesuspend_np.c \
+ uthread_attr_setdetachstate.c \
+ uthread_attr_setguardsize.c \
+ uthread_attr_setinheritsched.c \
+ uthread_attr_setschedparam.c \
+ uthread_attr_setschedpolicy.c \
+ uthread_attr_setscope.c \
+ uthread_attr_setstack.c \
+ uthread_attr_setstackaddr.c \
+ uthread_attr_setstacksize.c \
+ uthread_autoinit.c \
+ uthread_bind.c \
+ uthread_cancel.c \
+ uthread_clean.c \
+ uthread_close.c \
+ uthread_concurrency.c \
+ uthread_cond.c \
+ uthread_condattr_destroy.c \
+ uthread_condattr_init.c \
+ uthread_connect.c \
+ uthread_creat.c \
+ uthread_create.c \
+ uthread_detach.c \
+ uthread_dup.c \
+ uthread_dup2.c \
+ uthread_equal.c \
+ uthread_execve.c \
+ uthread_exit.c \
+ uthread_fchflags.c \
+ uthread_fchmod.c \
+ uthread_fchown.c \
+ uthread_fcntl.c \
+ uthread_fd.c \
+ uthread_file.c \
+ uthread_find_thread.c \
+ uthread_flock.c \
+ uthread_fork.c \
+ uthread_fpathconf.c \
+ uthread_fstat.c \
+ uthread_fstatfs.c \
+ uthread_fsync.c \
+ uthread_gc.c \
+ uthread_getdirentries.c \
+ uthread_getpeername.c \
+ uthread_getprio.c \
+ uthread_getschedparam.c \
+ uthread_getsockname.c \
+ uthread_getsockopt.c \
+ uthread_info.c \
+ uthread_init.c \
+ uthread_ioctl.c \
+ uthread_jmp.c \
+ uthread_join.c \
+ uthread_kern.c \
+ uthread_kevent.c \
+ uthread_kqueue.c \
+ uthread_kill.c \
+ uthread_listen.c \
+ uthread_main_np.c \
+ uthread_mattr_init.c \
+ uthread_mattr_kind_np.c \
+ uthread_msync.c \
+ uthread_multi_np.c \
+ uthread_mutex.c \
+ uthread_mutex_prioceiling.c \
+ uthread_mutex_protocol.c \
+ uthread_mutexattr_destroy.c \
+ uthread_nanosleep.c \
+ uthread_once.c \
+ uthread_open.c \
+ uthread_pause.c \
+ uthread_pipe.c \
+ uthread_poll.c \
+ uthread_priority_queue.c \
+ uthread_pselect.c \
+ uthread_read.c \
+ uthread_readv.c \
+ uthread_recvfrom.c \
+ uthread_recvmsg.c \
+ uthread_resume_np.c \
+ uthread_rwlock.c \
+ uthread_rwlockattr.c \
+ uthread_select.c \
+ uthread_self.c \
+ uthread_sem.c \
+ uthread_sendfile.c \
+ uthread_sendmsg.c \
+ uthread_sendto.c \
+ uthread_seterrno.c \
+ uthread_setprio.c \
+ uthread_setschedparam.c \
+ uthread_setsockopt.c \
+ uthread_shutdown.c \
+ uthread_sig.c \
+ uthread_sigaction.c \
+ uthread_sigmask.c \
+ uthread_sigpending.c \
+ uthread_sigprocmask.c \
+ uthread_sigsuspend.c \
+ uthread_sigwait.c \
+ uthread_single_np.c \
+ uthread_sleep.c \
+ uthread_socket.c \
+ uthread_socketpair.c \
+ uthread_spec.c \
+ uthread_spinlock.c \
+ uthread_stack.c \
+ uthread_suspend_np.c \
+ uthread_switch_np.c \
+ uthread_system.c \
+ uthread_tcdrain.c \
+ uthread_vfork.c \
+ uthread_wait.c \
+ uthread_wait4.c \
+ uthread_waitpid.c \
+ uthread_write.c \
+ uthread_writev.c \
+ uthread_yield.c
diff --git a/lib/libc_r/uthread/pthread_private.h b/lib/libc_r/uthread/pthread_private.h
new file mode 100644
index 0000000..9e3c2ee
--- /dev/null
+++ b/lib/libc_r/uthread/pthread_private.h
@@ -0,0 +1,1414 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Private thread definitions for the uthread kernel.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _PTHREAD_PRIVATE_H
+#define _PTHREAD_PRIVATE_H
+
+/*
+ * Evaluate the storage class specifier.
+ */
+#ifdef GLOBAL_PTHREAD_PRIVATE
+#define SCLASS
+#else
+#define SCLASS extern
+#endif
+
+/*
+ * Include files.
+ */
+#include <setjmp.h>
+#include <signal.h>
+#include <stdio.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/cdefs.h>
+#include <sched.h>
+#include <spinlock.h>
+#include <ucontext.h>
+#include <pthread_np.h>
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/pmap.h>
+#include <vm/vm_map.h>
+
+/*
+ * Define machine dependent macros to get and set the stack pointer
+ * from the supported contexts. Also define a macro to set the return
+ * address in a jmp_buf context.
+ *
+ * XXX - These need to be moved into architecture dependent support files.
+ * XXX - These need to be documented so porters know what's required.
+ */
+#if defined(__i386__)
+#define GET_STACK_JB(jb) ((unsigned long)((jb)[0]._jb[2]))
+#define GET_STACK_SJB(sjb) ((unsigned long)((sjb)[0]._sjb[2]))
+#define GET_STACK_UC(ucp) ((unsigned long)((ucp)->uc_mcontext.mc_esp))
+#define SET_STACK_JB(jb, stk) (jb)[0]._jb[2] = (int)(stk)
+#define SET_STACK_SJB(sjb, stk) (sjb)[0]._sjb[2] = (int)(stk)
+#define SET_STACK_UC(ucp, stk) (ucp)->uc_mcontext.mc_esp = (int)(stk)
+#define FP_SAVE_UC(ucp) do { \
+ char *fdata; \
+ fdata = (char *) (ucp)->uc_mcontext.mc_fpstate; \
+ __asm__("fnsave %0": :"m"(*fdata)); \
+} while (0)
+#define FP_RESTORE_UC(ucp) do { \
+ char *fdata; \
+ fdata = (char *) (ucp)->uc_mcontext.mc_fpstate; \
+ __asm__("frstor %0": :"m"(*fdata)); \
+} while (0)
+#define SET_RETURN_ADDR_JB(jb, ra) do { \
+ (jb)[0]._jb[0] = (int)(ra); \
+ (jb)[0]._jb[3] = 0; \
+} while (0)
+#elif defined(__amd64__)
+#define GET_STACK_JB(jb) ((unsigned long)((jb)[0]._jb[2]))
+#define GET_STACK_SJB(sjb) ((unsigned long)((sjb)[0]._sjb[2]))
+#define GET_STACK_UC(ucp) ((unsigned long)((ucp)->uc_mcontext.mc_rsp))
+#define SET_STACK_JB(jb, stk) (jb)[0]._jb[2] = (long)(stk)
+#define SET_STACK_SJB(sjb, stk) (sjb)[0]._sjb[2] = (long)(stk)
+#define SET_STACK_UC(ucp, stk) (ucp)->uc_mcontext.mc_rsp = (long)(stk)
+#define FP_SAVE_UC(ucp) do { \
+ char *fdata; \
+ fdata = (char *) (ucp)->uc_mcontext.mc_fpstate; \
+ __asm__("fxsave %0": :"m"(*fdata)); \
+} while (0)
+#define FP_RESTORE_UC(ucp) do { \
+ char *fdata; \
+ fdata = (char *) (ucp)->uc_mcontext.mc_fpstate; \
+ __asm__("fxrstor %0": :"m"(*fdata)); \
+} while (0)
+#define SET_RETURN_ADDR_JB(jb, ra) (jb)[0]._jb[0] = (long)(ra)
+#elif defined(__alpha__)
+#include <machine/reg.h>
+#define GET_STACK_JB(jb) ((unsigned long)((jb)[0]._jb[R_SP + 4]))
+#define GET_STACK_SJB(sjb) ((unsigned long)((sjb)[0]._sjb[R_SP + 4]))
+#define GET_STACK_UC(ucp) ((ucp)->uc_mcontext.mc_regs[R_SP])
+#define SET_STACK_JB(jb, stk) (jb)[0]._jb[R_SP + 4] = (long)(stk)
+#define SET_STACK_SJB(sjb, stk) (sjb)[0]._sjb[R_SP + 4] = (long)(stk)
+#define SET_STACK_UC(ucp, stk) (ucp)->uc_mcontext.mc_regs[R_SP] = (unsigned long)(stk)
+#define FP_SAVE_UC(ucp)
+#define FP_RESTORE_UC(ucp)
+#define SET_RETURN_ADDR_JB(jb, ra) do { \
+ (jb)[0]._jb[2] = (long)(ra); \
+ (jb)[0]._jb[R_RA + 4] = (long)(ra); \
+ (jb)[0]._jb[R_T12 + 4] = (long)(ra); \
+} while (0)
+#elif defined(__ia64__)
+#define GET_BSP_JB(jb) (*((unsigned long*)JMPBUF_ADDR_OF(jb,J_BSP)))
+#define GET_STACK_JB(jb) (*((unsigned long*)JMPBUF_ADDR_OF(jb,J_SP)))
+#define GET_STACK_SJB(sjb) GET_STACK_JB(sjb)
+#define SET_RETURN_ADDR_JB(jb, ra) \
+do { \
+ *((unsigned long*)JMPBUF_ADDR_OF(jb,J_B0)) = ((long*)(ra))[0]; \
+ *((unsigned long*)JMPBUF_ADDR_OF(jb,J_GP)) = ((long*)(ra))[1]; \
+ *((unsigned long*)JMPBUF_ADDR_OF(jb,J_PFS)) &= ~0x1FFFFFFFFFUL; \
+} while (0)
+#define SET_STACK_JB(jb, stk, sz) \
+do { \
+ UPD_STACK_JB(jb, stk + sz - 16); \
+ GET_BSP_JB(jb) = (long)(stk); \
+} while (0)
+#define UPD_STACK_JB(jb, stk) GET_STACK_JB(jb) = (long)(stk)
+#elif defined(__sparc64__)
+#include <machine/frame.h>
+
+#define CCFSZ sizeof (struct frame)
+
+#define GET_STACK_JB(jb) \
+ ((unsigned long)((jb)[0]._jb[_JB_SP]) + SPOFF)
+#define GET_STACK_SJB(sjb) \
+ ((unsigned long)((sjb)[0]._sjb[_JB_SP]) + SPOFF)
+#define GET_STACK_UC(ucp) \
+ ((ucp)->uc_mcontext.mc_sp + SPOFF)
+/*
+ * XXX: sparc64 _longjmp() expects a register window on the stack
+ * at the given position, so we must make sure that the space where
+ * it is expected is readable. Subtracting the frame size here works
+ * because the SET_STACK macros are only used to set up new stacks
+ * or signal stacks, but it is a bit dirty.
+ */
+#define SET_STACK_JB(jb, stk) \
+ (jb)[0]._jb[_JB_SP] = (long)(stk) - SPOFF - CCFSZ
+#define SET_STACK_SJB(sjb, stk) \
+ (sjb)[0]._sjb[_JB_SP] = (long)(stk) - SPOFF - CCFSZ
+#define SET_STACK_UC(ucp, stk) \
+ (ucp)->uc_mcontext.mc_sp = (unsigned long)(stk) - SPOFF - CCFSZ
+#define FP_SAVE_UC(ucp) /* XXX */
+#define FP_RESTORE_UC(ucp) /* XXX */
+#define SET_RETURN_ADDR_JB(jb, ra) \
+ (jb)[0]._jb[_JB_PC] = (long)(ra) - 8
+#else
+#error "Don't recognize this architecture!"
+#endif
+
+/*
+ * Kernel fatal error handler macro.
+ */
+#define PANIC(string) _thread_exit(__FILE__,__LINE__,string)
+
+
+/* Output debug messages like this: */
+#define stdout_debug(args...) do { \
+ char buf[128]; \
+ snprintf(buf, sizeof(buf), ##args); \
+ __sys_write(1, buf, strlen(buf)); \
+} while (0)
+#define stderr_debug(args...) do { \
+ char buf[128]; \
+ snprintf(buf, sizeof(buf), ##args); \
+ __sys_write(2, buf, strlen(buf)); \
+} while (0)
+
+
+
+/*
+ * Priority queue manipulation macros (using pqe link):
+ */
+#define PTHREAD_PRIOQ_INSERT_HEAD(thrd) _pq_insert_head(&_readyq,thrd)
+#define PTHREAD_PRIOQ_INSERT_TAIL(thrd) _pq_insert_tail(&_readyq,thrd)
+#define PTHREAD_PRIOQ_REMOVE(thrd) _pq_remove(&_readyq,thrd)
+#define PTHREAD_PRIOQ_FIRST() _pq_first(&_readyq)
+
+/*
+ * Waiting queue manipulation macros (using pqe link):
+ */
+#define PTHREAD_WAITQ_REMOVE(thrd) _waitq_remove(thrd)
+#define PTHREAD_WAITQ_INSERT(thrd) _waitq_insert(thrd)
+
+#if defined(_PTHREADS_INVARIANTS)
+#define PTHREAD_WAITQ_CLEARACTIVE() _waitq_clearactive()
+#define PTHREAD_WAITQ_SETACTIVE() _waitq_setactive()
+#else
+#define PTHREAD_WAITQ_CLEARACTIVE()
+#define PTHREAD_WAITQ_SETACTIVE()
+#endif
+
+/*
+ * Work queue manipulation macros (using qe link):
+ */
+#define PTHREAD_WORKQ_INSERT(thrd) do { \
+ TAILQ_INSERT_TAIL(&_workq,thrd,qe); \
+ (thrd)->flags |= PTHREAD_FLAGS_IN_WORKQ; \
+} while (0)
+#define PTHREAD_WORKQ_REMOVE(thrd) do { \
+ TAILQ_REMOVE(&_workq,thrd,qe); \
+ (thrd)->flags &= ~PTHREAD_FLAGS_IN_WORKQ; \
+} while (0)
+
+
+/*
+ * State change macro without scheduling queue change:
+ */
+#define PTHREAD_SET_STATE(thrd, newstate) do { \
+ (thrd)->state = newstate; \
+ (thrd)->fname = __FILE__; \
+ (thrd)->lineno = __LINE__; \
+} while (0)
+
+/*
+ * State change macro with scheduling queue change - This must be
+ * called with preemption deferred (see thread_kern_sched_[un]defer).
+ */
+#if defined(_PTHREADS_INVARIANTS)
+#include <assert.h>
+#define PTHREAD_ASSERT(cond, msg) do { \
+ if (!(cond)) \
+ PANIC(msg); \
+} while (0)
+#define PTHREAD_ASSERT_NOT_IN_SYNCQ(thrd) \
+ PTHREAD_ASSERT((((thrd)->flags & PTHREAD_FLAGS_IN_SYNCQ) == 0), \
+ "Illegal call from signal handler");
+#define PTHREAD_NEW_STATE(thrd, newstate) do { \
+ if (_thread_kern_new_state != 0) \
+ PANIC("Recursive PTHREAD_NEW_STATE"); \
+ _thread_kern_new_state = 1; \
+ if ((thrd)->state != newstate) { \
+ if ((thrd)->state == PS_RUNNING) { \
+ PTHREAD_PRIOQ_REMOVE(thrd); \
+ PTHREAD_SET_STATE(thrd, newstate); \
+ PTHREAD_WAITQ_INSERT(thrd); \
+ } else if (newstate == PS_RUNNING) { \
+ PTHREAD_WAITQ_REMOVE(thrd); \
+ PTHREAD_SET_STATE(thrd, newstate); \
+ PTHREAD_PRIOQ_INSERT_TAIL(thrd); \
+ } \
+ } \
+ _thread_kern_new_state = 0; \
+} while (0)
+#else
+#define PTHREAD_ASSERT(cond, msg)
+#define PTHREAD_ASSERT_NOT_IN_SYNCQ(thrd)
+#define PTHREAD_NEW_STATE(thrd, newstate) do { \
+ if ((thrd)->state != newstate) { \
+ if ((thrd)->state == PS_RUNNING) { \
+ PTHREAD_PRIOQ_REMOVE(thrd); \
+ PTHREAD_WAITQ_INSERT(thrd); \
+ } else if (newstate == PS_RUNNING) { \
+ PTHREAD_WAITQ_REMOVE(thrd); \
+ PTHREAD_PRIOQ_INSERT_TAIL(thrd); \
+ } \
+ } \
+ PTHREAD_SET_STATE(thrd, newstate); \
+} while (0)
+#endif
+
+/*
+ * Define the signals to be used for scheduling.
+ */
+#if defined(_PTHREADS_COMPAT_SCHED)
+#define _ITIMER_SCHED_TIMER ITIMER_VIRTUAL
+#define _SCHED_SIGNAL SIGVTALRM
+#else
+#define _ITIMER_SCHED_TIMER ITIMER_PROF
+#define _SCHED_SIGNAL SIGPROF
+#endif
+
+/*
+ * Priority queues.
+ *
+ * XXX It'd be nice if these were contained in uthread_priority_queue.[ch].
+ */
+typedef struct pq_list {
+ TAILQ_HEAD(, pthread) pl_head; /* list of threads at this priority */
+ TAILQ_ENTRY(pq_list) pl_link; /* link for queue of priority lists */
+ int pl_prio; /* the priority of this list */
+ int pl_queued; /* is this in the priority queue */
+} pq_list_t;
+
+typedef struct pq_queue {
+ TAILQ_HEAD(, pq_list) pq_queue; /* queue of priority lists */
+ pq_list_t *pq_lists; /* array of all priority lists */
+ int pq_size; /* number of priority lists */
+} pq_queue_t;
+
+
+/*
+ * TailQ initialization values.
+ */
+#define TAILQ_INITIALIZER { NULL, NULL }
+
+/*
+ * Mutex definitions.
+ */
+union pthread_mutex_data {
+ void *m_ptr;
+ int m_count;
+};
+
+struct pthread_mutex {
+ enum pthread_mutextype m_type;
+ int m_protocol;
+ TAILQ_HEAD(mutex_head, pthread) m_queue;
+ struct pthread *m_owner;
+ union pthread_mutex_data m_data;
+ long m_flags;
+ int m_refcount;
+
+ /*
+ * Used for priority inheritence and protection.
+ *
+ * m_prio - For priority inheritence, the highest active
+ * priority (threads locking the mutex inherit
+ * this priority). For priority protection, the
+ * ceiling priority of this mutex.
+ * m_saved_prio - mutex owners inherited priority before
+ * taking the mutex, restored when the owner
+ * unlocks the mutex.
+ */
+ int m_prio;
+ int m_saved_prio;
+
+ /*
+ * Link for list of all mutexes a thread currently owns.
+ */
+ TAILQ_ENTRY(pthread_mutex) m_qe;
+
+ /*
+ * Lock for accesses to this structure.
+ */
+ spinlock_t lock;
+};
+
+/*
+ * Flags for mutexes.
+ */
+#define MUTEX_FLAGS_PRIVATE 0x01
+#define MUTEX_FLAGS_INITED 0x02
+#define MUTEX_FLAGS_BUSY 0x04
+
+/*
+ * Static mutex initialization values.
+ */
+#define PTHREAD_MUTEX_STATIC_INITIALIZER \
+ { PTHREAD_MUTEX_DEFAULT, PTHREAD_PRIO_NONE, TAILQ_INITIALIZER, \
+ NULL, { NULL }, MUTEX_FLAGS_PRIVATE, 0, 0, 0, TAILQ_INITIALIZER, \
+ _SPINLOCK_INITIALIZER }
+
+struct pthread_mutex_attr {
+ enum pthread_mutextype m_type;
+ int m_protocol;
+ int m_ceiling;
+ long m_flags;
+};
+
+#define PTHREAD_MUTEXATTR_STATIC_INITIALIZER \
+ { PTHREAD_MUTEX_DEFAULT, PTHREAD_PRIO_NONE, 0, MUTEX_FLAGS_PRIVATE }
+
+/*
+ * Condition variable definitions.
+ */
+enum pthread_cond_type {
+ COND_TYPE_FAST,
+ COND_TYPE_MAX
+};
+
+struct pthread_cond {
+ enum pthread_cond_type c_type;
+ TAILQ_HEAD(cond_head, pthread) c_queue;
+ pthread_mutex_t c_mutex;
+ void *c_data;
+ long c_flags;
+ int c_seqno;
+
+ /*
+ * Lock for accesses to this structure.
+ */
+ spinlock_t lock;
+};
+
+struct pthread_cond_attr {
+ enum pthread_cond_type c_type;
+ long c_flags;
+};
+
+/*
+ * Flags for condition variables.
+ */
+#define COND_FLAGS_PRIVATE 0x01
+#define COND_FLAGS_INITED 0x02
+#define COND_FLAGS_BUSY 0x04
+
+/*
+ * Static cond initialization values.
+ */
+#define PTHREAD_COND_STATIC_INITIALIZER \
+ { COND_TYPE_FAST, TAILQ_INITIALIZER, NULL, NULL, \
+ 0, 0, _SPINLOCK_INITIALIZER }
+
+/*
+ * 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;
+};
+
+/*
+ * Cleanup definitions.
+ */
+struct pthread_cleanup {
+ struct pthread_cleanup *next;
+ void (*routine) ();
+ void *routine_arg;
+};
+
+struct pthread_atfork {
+ TAILQ_ENTRY(pthread_atfork) qe;
+ void (*prepare)(void);
+ void (*parent)(void);
+ void (*child)(void);
+};
+
+struct pthread_attr {
+ int sched_policy;
+ int sched_inherit;
+ int sched_interval;
+ int prio;
+ int suspend;
+ int flags;
+ void *arg_attr;
+ void (*cleanup_attr) ();
+ void *stackaddr_attr;
+ size_t stacksize_attr;
+ size_t guardsize_attr;
+};
+
+/*
+ * Thread creation state attributes.
+ */
+#define PTHREAD_CREATE_RUNNING 0
+#define PTHREAD_CREATE_SUSPENDED 1
+
+/*
+ * Miscellaneous definitions.
+ */
+#define PTHREAD_STACK32_DEFAULT (1 * 1024 * 1024)
+#define PTHREAD_STACK64_DEFAULT (2 * 1024 * 1024)
+
+/*
+ * Size of default red zone at the end of each stack. In actuality, this "red
+ * zone" is merely an unmapped region, except in the case of the initial stack.
+ * Since mmap() makes it possible to specify the maximum growth of a MAP_STACK
+ * region, an unmapped gap between thread stacks achieves the same effect as
+ * explicitly mapped red zones.
+ * This is declared and initialized in uthread_init.c.
+ */
+extern int _pthread_guard_default;
+
+extern int _pthread_page_size;
+
+extern int _pthread_stack_default;
+
+extern int _pthread_stack_initial;
+
+/*
+ * Maximum size of initial thread's stack. This perhaps deserves to be larger
+ * than the stacks of other threads, since many applications are likely to run
+ * almost entirely on this stack.
+ */
+#define PTHREAD_STACK32_INITIAL (2 * 1024 * 1024)
+#define PTHREAD_STACK64_INITIAL (4 * 1024 * 1024)
+
+/*
+ * Define the different priority ranges. All applications have thread
+ * priorities constrained within 0-31. The threads library raises the
+ * priority when delivering signals in order to ensure that signal
+ * delivery happens (from the POSIX spec) "as soon as possible".
+ * In the future, the threads library will also be able to map specific
+ * threads into real-time (cooperating) processes or kernel threads.
+ * The RT and SIGNAL priorities will be used internally and added to
+ * thread base priorities so that the scheduling queue can handle both
+ * normal and RT priority threads with and without signal handling.
+ *
+ * The approach taken is that, within each class, signal delivery
+ * always has priority over thread execution.
+ */
+#define PTHREAD_DEFAULT_PRIORITY 15
+#define PTHREAD_MIN_PRIORITY 0
+#define PTHREAD_MAX_PRIORITY 31 /* 0x1F */
+#define PTHREAD_SIGNAL_PRIORITY 32 /* 0x20 */
+#define PTHREAD_RT_PRIORITY 64 /* 0x40 */
+#define PTHREAD_FIRST_PRIORITY PTHREAD_MIN_PRIORITY
+#define PTHREAD_LAST_PRIORITY \
+ (PTHREAD_MAX_PRIORITY + PTHREAD_SIGNAL_PRIORITY + PTHREAD_RT_PRIORITY)
+#define PTHREAD_BASE_PRIORITY(prio) ((prio) & PTHREAD_MAX_PRIORITY)
+
+/*
+ * Clock resolution in microseconds.
+ */
+#define CLOCK_RES_USEC 10000
+#define CLOCK_RES_USEC_MIN 1000
+
+/*
+ * Time slice period in microseconds.
+ */
+#define TIMESLICE_USEC 20000
+
+/*
+ * Define a thread-safe macro to get the current time of day
+ * which is updated at regular intervals by the scheduling signal
+ * handler.
+ */
+#define GET_CURRENT_TOD(tv) \
+ do { \
+ tv.tv_sec = _sched_tod.tv_sec; \
+ tv.tv_usec = _sched_tod.tv_usec; \
+ } while (tv.tv_sec != _sched_tod.tv_sec)
+
+
+struct pthread_rwlockattr {
+ int pshared;
+};
+
+struct pthread_rwlock {
+ pthread_mutex_t lock; /* monitor lock */
+ int state; /* 0 = idle >0 = # of readers -1 = writer */
+ pthread_cond_t read_signal;
+ pthread_cond_t write_signal;
+ int blocked_writers;
+};
+
+/*
+ * Thread states.
+ */
+enum pthread_state {
+ PS_RUNNING,
+ PS_SIGTHREAD,
+ PS_MUTEX_WAIT,
+ PS_COND_WAIT,
+ PS_FDLR_WAIT,
+ PS_FDLW_WAIT,
+ PS_FDR_WAIT,
+ PS_FDW_WAIT,
+ PS_FILE_WAIT,
+ PS_POLL_WAIT,
+ PS_SELECT_WAIT,
+ PS_SLEEP_WAIT,
+ PS_WAIT_WAIT,
+ PS_SIGSUSPEND,
+ PS_SIGWAIT,
+ PS_SPINBLOCK,
+ PS_JOIN,
+ PS_SUSPENDED,
+ PS_DEAD,
+ PS_DEADLOCK,
+ PS_STATE_MAX
+};
+
+
+/*
+ * File descriptor locking definitions.
+ */
+#define FD_READ 0x1
+#define FD_WRITE 0x2
+#define FD_RDWR (FD_READ | FD_WRITE)
+
+/*
+ * File descriptor table structure.
+ */
+struct fd_table_entry {
+ /*
+ * Lock for accesses to this file descriptor table
+ * entry. This is passed to _spinlock() to provide atomic
+ * access to this structure. It does *not* represent the
+ * state of the lock on the file descriptor.
+ */
+ spinlock_t lock;
+ TAILQ_HEAD(, pthread) r_queue; /* Read queue. */
+ TAILQ_HEAD(, pthread) w_queue; /* Write queue. */
+ struct pthread *r_owner; /* Ptr to thread owning read lock. */
+ struct pthread *w_owner; /* Ptr to thread owning write lock. */
+ char *r_fname; /* Ptr to read lock source file name */
+ int r_lineno; /* Read lock source line number. */
+ char *w_fname; /* Ptr to write lock source file name */
+ int w_lineno; /* Write lock source line number. */
+ int r_lockcount; /* Count for FILE read locks. */
+ int w_lockcount; /* Count for FILE write locks. */
+ int flags; /* Flags used in open. */
+};
+
+struct pthread_poll_data {
+ int nfds;
+ struct pollfd *fds;
+};
+
+union pthread_wait_data {
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+ const sigset_t *sigwait; /* Waiting on a signal in sigwait */
+ struct {
+ short fd; /* Used when thread waiting on fd */
+ short branch; /* Line number, for debugging. */
+ char *fname; /* Source file name for debugging.*/
+ } fd;
+ FILE *fp;
+ struct pthread_poll_data *poll_data;
+ spinlock_t *spinlock;
+ struct pthread *thread;
+};
+
+/*
+ * Define a continuation routine that can be used to perform a
+ * transfer of control:
+ */
+typedef void (*thread_continuation_t) (void *);
+
+struct pthread_signal_frame;
+
+struct pthread_state_data {
+ struct pthread_signal_frame *psd_curframe;
+ sigset_t psd_sigmask;
+ struct timespec psd_wakeup_time;
+ union pthread_wait_data psd_wait_data;
+ enum pthread_state psd_state;
+ int psd_flags;
+ int psd_interrupted;
+ int psd_longjmp_val;
+ int psd_sigmask_seqno;
+ int psd_signo;
+ int psd_sig_defer_count;
+ /* XXX - What about thread->timeout and/or thread->error? */
+};
+
+struct join_status {
+ struct pthread *thread;
+ void *ret;
+ int error;
+};
+
+/*
+ * The frame that is added to the top of a threads stack when setting up
+ * up the thread to run a signal handler.
+ */
+struct pthread_signal_frame {
+ /*
+ * This stores the threads state before the signal.
+ */
+ struct pthread_state_data saved_state;
+
+ /*
+ * Threads return context; we use only jmp_buf's for now.
+ */
+ union {
+ jmp_buf jb;
+ ucontext_t uc;
+ } ctx;
+ int signo; /* signal, arg 1 to sighandler */
+ int sig_has_args; /* use signal args if true */
+ ucontext_t uc;
+ siginfo_t siginfo;
+};
+
+struct pthread_specific_elem {
+ const void *data;
+ int seqno;
+};
+
+/*
+ * Thread structure.
+ */
+struct pthread {
+ /*
+ * Magic value to help recognize a valid thread structure
+ * from an invalid one:
+ */
+#define PTHREAD_MAGIC ((u_int32_t) 0xd09ba115)
+ u_int32_t magic;
+ char *name;
+ u_int64_t uniqueid; /* for gdb */
+
+ /*
+ * Lock for accesses to this thread structure.
+ */
+ spinlock_t lock;
+
+ /* Queue entry for list of all threads: */
+ TAILQ_ENTRY(pthread) tle;
+
+ /* Queue entry for list of dead threads: */
+ TAILQ_ENTRY(pthread) dle;
+
+ /*
+ * Thread start routine, argument, stack pointer and thread
+ * attributes.
+ */
+ void *(*start_routine)(void *);
+ void *arg;
+ void *stack;
+ struct pthread_attr attr;
+
+ /*
+ * Threads return context; we use only jmp_buf's for now.
+ */
+ union {
+ jmp_buf jb;
+ ucontext_t uc;
+ } ctx;
+
+ /*
+ * Used for tracking delivery of signal handlers.
+ */
+ struct pthread_signal_frame *curframe;
+
+ /*
+ * Cancelability flags - the lower 2 bits are used by cancel
+ * definitions in pthread.h
+ */
+#define PTHREAD_AT_CANCEL_POINT 0x0004
+#define PTHREAD_CANCELLING 0x0008
+#define PTHREAD_CANCEL_NEEDED 0x0010
+ int cancelflags;
+
+ thread_continuation_t continuation;
+
+ /*
+ * Current signal mask and pending signals.
+ */
+ sigset_t sigmask;
+ sigset_t sigpend;
+ int sigmask_seqno;
+ int check_pending;
+
+ /* Thread state: */
+ enum pthread_state state;
+
+ /* Scheduling clock when this thread was last made active. */
+ long last_active;
+
+ /* Scheduling clock when this thread was last made inactive. */
+ long last_inactive;
+
+ /*
+ * Number of microseconds accumulated by this thread when
+ * time slicing is active.
+ */
+ long slice_usec;
+
+ /*
+ * Time to wake up thread. This is used for sleeping threads and
+ * for any operation which may time out (such as select).
+ */
+ struct timespec wakeup_time;
+
+ /* TRUE if operation has timed out. */
+ int timeout;
+
+ /*
+ * Error variable used instead of errno. The function __error()
+ * returns a pointer to this.
+ */
+ int error;
+
+ /*
+ * The joiner is the thread that is joining to this thread. The
+ * join status keeps track of a join operation to another thread.
+ */
+ struct pthread *joiner;
+ struct join_status join_status;
+
+ /*
+ * The current thread can belong to only one scheduling queue at
+ * a time (ready or waiting queue). It can also belong to:
+ *
+ * o A queue of threads waiting for a mutex
+ * o A queue of threads waiting for a condition variable
+ * o A queue of threads waiting for a file descriptor lock
+ * o A queue of threads needing work done by the kernel thread
+ * (waiting for a spinlock or file I/O)
+ *
+ * A thread can also be joining a thread (the joiner field above).
+ *
+ * It must not be possible for a thread to belong to any of the
+ * above queues while it is handling a signal. Signal handlers
+ * may longjmp back to previous stack frames circumventing normal
+ * control flow. This could corrupt queue integrity if the thread
+ * retains membership in the queue. Therefore, if a thread is a
+ * member of one of these queues when a signal handler is invoked,
+ * it must remove itself from the queue before calling the signal
+ * handler and reinsert itself after normal return of the handler.
+ *
+ * Use pqe for the scheduling queue link (both ready and waiting),
+ * sqe for synchronization (mutex and condition variable) queue
+ * links, and qe for all other links.
+ */
+ TAILQ_ENTRY(pthread) pqe; /* priority queue link */
+ TAILQ_ENTRY(pthread) sqe; /* synchronization queue link */
+ TAILQ_ENTRY(pthread) qe; /* all other queues link */
+
+ /* Wait data. */
+ union pthread_wait_data data;
+
+ /*
+ * Allocated for converting select into poll.
+ */
+ struct pthread_poll_data poll_data;
+
+ /*
+ * Set to TRUE if a blocking operation was
+ * interrupted by a signal:
+ */
+ int interrupted;
+
+ /* Signal number when in state PS_SIGWAIT: */
+ int signo;
+
+ /*
+ * Set to non-zero when this thread has deferred signals.
+ * We allow for recursive deferral.
+ */
+ int sig_defer_count;
+
+ /*
+ * Set to TRUE if this thread should yield after undeferring
+ * signals.
+ */
+ int yield_on_sig_undefer;
+
+ /* Miscellaneous flags; only set with signals deferred. */
+ int flags;
+#define PTHREAD_FLAGS_PRIVATE 0x0001
+#define PTHREAD_EXITING 0x0002
+#define PTHREAD_FLAGS_IN_WAITQ 0x0004 /* in waiting queue using pqe link */
+#define PTHREAD_FLAGS_IN_PRIOQ 0x0008 /* in priority queue using pqe link */
+#define PTHREAD_FLAGS_IN_WORKQ 0x0010 /* in work queue using qe link */
+#define PTHREAD_FLAGS_IN_FILEQ 0x0020 /* in file lock queue using qe link */
+#define PTHREAD_FLAGS_IN_FDQ 0x0040 /* in fd lock queue using qe link */
+#define PTHREAD_FLAGS_IN_CONDQ 0x0080 /* in condition queue using sqe link*/
+#define PTHREAD_FLAGS_IN_MUTEXQ 0x0100 /* in mutex queue using sqe link */
+#define PTHREAD_FLAGS_SUSPENDED 0x0200 /* thread is suspended */
+#define PTHREAD_FLAGS_TRACE 0x0400 /* for debugging purposes */
+#define PTHREAD_FLAGS_IN_SYNCQ \
+ (PTHREAD_FLAGS_IN_CONDQ | PTHREAD_FLAGS_IN_MUTEXQ)
+
+ /*
+ * Base priority is the user setable and retrievable priority
+ * of the thread. It is only affected by explicit calls to
+ * set thread priority and upon thread creation via a thread
+ * attribute or default priority.
+ */
+ char base_priority;
+
+ /*
+ * Inherited priority is the priority a thread inherits by
+ * taking a priority inheritence or protection mutex. It
+ * is not affected by base priority changes. Inherited
+ * priority defaults to and remains 0 until a mutex is taken
+ * that is being waited on by any other thread whose priority
+ * is non-zero.
+ */
+ char inherited_priority;
+
+ /*
+ * Active priority is always the maximum of the threads base
+ * priority and inherited priority. When there is a change
+ * in either the base or inherited priority, the active
+ * priority must be recalculated.
+ */
+ char active_priority;
+
+ /* Number of priority ceiling or protection mutexes owned. */
+ int priority_mutex_count;
+
+ /* Number rwlocks rdlocks held. */
+ int rdlock_count;
+
+ /*
+ * Queue of currently owned mutexes.
+ */
+ TAILQ_HEAD(, pthread_mutex) mutexq;
+
+ void *ret;
+ struct pthread_specific_elem *specific;
+ int specific_data_count;
+
+ /* Cleanup handlers Link List */
+ struct pthread_cleanup *cleanup;
+ char *fname; /* Ptr to source file name */
+ int lineno; /* Source line number. */
+};
+
+/*
+ * Global variables for the uthread kernel.
+ */
+
+SCLASS void *_usrstack
+#ifdef GLOBAL_PTHREAD_PRIVATE
+= (void *) USRSTACK;
+#else
+;
+#endif
+
+/* Kernel thread structure used when there are no running threads: */
+SCLASS struct pthread _thread_kern_thread;
+
+/* Ptr to the thread structure for the running thread: */
+SCLASS struct pthread * volatile _thread_run
+#ifdef GLOBAL_PTHREAD_PRIVATE
+= &_thread_kern_thread;
+#else
+;
+#endif
+
+/* Ptr to the thread structure for the last user thread to run: */
+SCLASS struct pthread * volatile _last_user_thread
+#ifdef GLOBAL_PTHREAD_PRIVATE
+= &_thread_kern_thread;
+#else
+;
+#endif
+
+/* List of all threads: */
+SCLASS TAILQ_HEAD(, pthread) _thread_list
+#ifdef GLOBAL_PTHREAD_PRIVATE
+= TAILQ_HEAD_INITIALIZER(_thread_list);
+#else
+;
+#endif
+
+/*
+ * Array of kernel pipe file descriptors that are used to ensure that
+ * no signals are missed in calls to _select.
+ */
+SCLASS int _thread_kern_pipe[2]
+#ifdef GLOBAL_PTHREAD_PRIVATE
+= {
+ -1,
+ -1
+};
+#else
+;
+#endif
+SCLASS int volatile _queue_signals
+#ifdef GLOBAL_PTHREAD_PRIVATE
+= 0;
+#else
+;
+#endif
+SCLASS int _thread_kern_in_sched
+#ifdef GLOBAL_PTHREAD_PRIVATE
+= 0;
+#else
+;
+#endif
+
+SCLASS int _sig_in_handler
+#ifdef GLOBAL_PTHREAD_PRIVATE
+= 0;
+#else
+;
+#endif
+
+/* Time of day at last scheduling timer signal: */
+SCLASS struct timeval volatile _sched_tod
+#ifdef GLOBAL_PTHREAD_PRIVATE
+= { 0, 0 };
+#else
+;
+#endif
+
+/*
+ * Current scheduling timer ticks; used as resource usage.
+ */
+SCLASS unsigned int volatile _sched_ticks
+#ifdef GLOBAL_PTHREAD_PRIVATE
+= 0;
+#else
+;
+#endif
+
+/* Dead threads: */
+SCLASS TAILQ_HEAD(, pthread) _dead_list
+#ifdef GLOBAL_PTHREAD_PRIVATE
+= TAILQ_HEAD_INITIALIZER(_dead_list);
+#else
+;
+#endif
+
+/* Initial thread: */
+SCLASS struct pthread *_thread_initial
+#ifdef GLOBAL_PTHREAD_PRIVATE
+= NULL;
+#else
+;
+#endif
+
+SCLASS TAILQ_HEAD(atfork_head, pthread_atfork) _atfork_list;
+SCLASS pthread_mutex_t _atfork_mutex;
+
+/* Default thread attributes: */
+SCLASS struct pthread_attr _pthread_attr_default
+#ifdef GLOBAL_PTHREAD_PRIVATE
+= { SCHED_RR, 0, TIMESLICE_USEC, PTHREAD_DEFAULT_PRIORITY,
+ PTHREAD_CREATE_RUNNING, PTHREAD_CREATE_JOINABLE, NULL, NULL, NULL,
+ -1, -1 };
+#else
+;
+#endif
+
+/* Default mutex attributes: */
+#define PTHREAD_MUTEXATTR_DEFAULT \
+ { PTHREAD_MUTEX_DEFAULT, PTHREAD_PRIO_NONE, 0, 0 }
+
+/* Default condition variable attributes: */
+#define PTHREAD_CONDATTR_DEFAULT { COND_TYPE_FAST, 0 }
+
+/*
+ * Standard I/O file descriptors need special flag treatment since
+ * setting one to non-blocking does all on *BSD. Sigh. This array
+ * is used to store the initial flag settings.
+ */
+SCLASS int _pthread_stdio_flags[3];
+
+/* File table information: */
+SCLASS struct fd_table_entry **_thread_fd_table
+#ifdef GLOBAL_PTHREAD_PRIVATE
+= NULL;
+#else
+;
+#endif
+
+/* Table for polling file descriptors: */
+SCLASS struct pollfd *_thread_pfd_table
+#ifdef GLOBAL_PTHREAD_PRIVATE
+= NULL;
+#else
+;
+#endif
+
+SCLASS const int dtablecount
+#ifdef GLOBAL_PTHREAD_PRIVATE
+= 4096/sizeof(struct fd_table_entry);
+#else
+;
+#endif
+SCLASS int _thread_dtablesize /* Descriptor table size. */
+#ifdef GLOBAL_PTHREAD_PRIVATE
+= 0;
+#else
+;
+#endif
+
+SCLASS int _clock_res_usec /* Clock resolution in usec. */
+#ifdef GLOBAL_PTHREAD_PRIVATE
+= CLOCK_RES_USEC;
+#else
+;
+#endif
+
+/* Garbage collector mutex and condition variable. */
+SCLASS pthread_mutex_t _gc_mutex
+#ifdef GLOBAL_PTHREAD_PRIVATE
+= NULL
+#endif
+;
+SCLASS pthread_cond_t _gc_cond
+#ifdef GLOBAL_PTHREAD_PRIVATE
+= NULL
+#endif
+;
+
+/*
+ * Array of signal actions for this process.
+ */
+SCLASS struct sigaction _thread_sigact[NSIG];
+
+/*
+ * Array of counts of dummy handlers for SIG_DFL signals. This is used to
+ * assure that there is always a dummy signal handler installed while there is a
+ * thread sigwait()ing on the corresponding signal.
+ */
+SCLASS int _thread_dfl_count[NSIG];
+
+/*
+ * Pending signals and mask for this process:
+ */
+SCLASS sigset_t _process_sigpending;
+SCLASS sigset_t _process_sigmask
+#ifdef GLOBAL_PTHREAD_PRIVATE
+= { {0, 0, 0, 0} }
+#endif
+;
+
+/*
+ * Scheduling queues:
+ */
+SCLASS pq_queue_t _readyq;
+SCLASS TAILQ_HEAD(, pthread) _waitingq;
+
+/*
+ * Work queue:
+ */
+SCLASS TAILQ_HEAD(, pthread) _workq;
+
+/* Tracks the number of threads blocked while waiting for a spinlock. */
+SCLASS volatile int _spinblock_count
+#ifdef GLOBAL_PTHREAD_PRIVATE
+= 0
+#endif
+;
+
+/* Used to maintain pending and active signals: */
+struct sigstatus {
+ int pending; /* Is this a pending signal? */
+ int blocked; /*
+ * A handler is currently active for
+ * this signal; ignore subsequent
+ * signals until the handler is done.
+ */
+ int signo; /* arg 1 to signal handler */
+ siginfo_t siginfo; /* arg 2 to signal handler */
+ ucontext_t uc; /* arg 3 to signal handler */
+};
+
+SCLASS struct sigstatus _thread_sigq[NSIG];
+
+/* Indicates that the signal queue needs to be checked. */
+SCLASS volatile int _sigq_check_reqd
+#ifdef GLOBAL_PTHREAD_PRIVATE
+= 0
+#endif
+;
+
+/* Thread switch hook. */
+SCLASS pthread_switch_routine_t _sched_switch_hook
+#ifdef GLOBAL_PTHREAD_PRIVATE
+= NULL
+#endif
+;
+
+/*
+ * Declare the kernel scheduler jump buffer and stack:
+ */
+SCLASS jmp_buf _thread_kern_sched_jb;
+
+SCLASS void * _thread_kern_sched_stack
+#ifdef GLOBAL_PTHREAD_PRIVATE
+= NULL
+#endif
+;
+
+
+/* Used for _PTHREADS_INVARIANTS checking. */
+SCLASS int _thread_kern_new_state
+#ifdef GLOBAL_PTHREAD_PRIVATE
+= 0
+#endif
+;
+
+/* Undefine the storage class specifier: */
+#undef SCLASS
+
+#ifdef _LOCK_DEBUG
+#define _FD_LOCK(_fd,_type,_ts) _thread_fd_lock_debug(_fd, _type, \
+ _ts, __FILE__, __LINE__)
+#define _FD_UNLOCK(_fd,_type) _thread_fd_unlock_debug(_fd, _type, \
+ __FILE__, __LINE__)
+#else
+#define _FD_LOCK(_fd,_type,_ts) _thread_fd_lock(_fd, _type, _ts)
+#define _FD_UNLOCK(_fd,_type) _thread_fd_unlock(_fd, _type)
+#endif
+
+/*
+ * Function prototype definitions.
+ */
+__BEGIN_DECLS
+char *__ttyname_basic(int);
+void _cond_wait_backout(pthread_t);
+void _fd_lock_backout(pthread_t);
+int _find_thread(pthread_t);
+struct pthread *_get_curthread(void);
+void _set_curthread(struct pthread *);
+void *_thread_stack_alloc(size_t, size_t);
+void _thread_stack_free(void *, size_t, size_t);
+int _thread_create(pthread_t *,const pthread_attr_t *,void *(*start_routine)(void *),void *,pthread_t);
+int _mutex_cv_lock(pthread_mutex_t *);
+int _mutex_cv_unlock(pthread_mutex_t *);
+void _mutex_lock_backout(pthread_t);
+void _mutex_notify_priochange(pthread_t);
+int _mutex_reinit(pthread_mutex_t *);
+void _mutex_unlock_private(pthread_t);
+int _cond_reinit(pthread_cond_t *);
+int _pq_alloc(struct pq_queue *, int, int);
+int _pq_init(struct pq_queue *);
+void _pq_remove(struct pq_queue *pq, struct pthread *);
+void _pq_insert_head(struct pq_queue *pq, struct pthread *);
+void _pq_insert_tail(struct pq_queue *pq, struct pthread *);
+struct pthread *_pq_first(struct pq_queue *pq);
+void *_pthread_getspecific(pthread_key_t);
+int _pthread_key_create(pthread_key_t *, void (*) (void *));
+int _pthread_key_delete(pthread_key_t);
+int _pthread_mutex_destroy(pthread_mutex_t *);
+int _pthread_mutex_init(pthread_mutex_t *, const pthread_mutexattr_t *);
+int _pthread_mutex_lock(pthread_mutex_t *);
+int _pthread_mutex_trylock(pthread_mutex_t *);
+int _pthread_mutex_unlock(pthread_mutex_t *);
+int _pthread_mutexattr_init(pthread_mutexattr_t *);
+int _pthread_mutexattr_destroy(pthread_mutexattr_t *);
+int _pthread_mutexattr_settype(pthread_mutexattr_t *, int);
+int _pthread_once(pthread_once_t *, void (*) (void));
+pthread_t _pthread_self(void);
+int _pthread_setspecific(pthread_key_t, const void *);
+void _waitq_insert(pthread_t pthread);
+void _waitq_remove(pthread_t pthread);
+#if defined(_PTHREADS_INVARIANTS)
+void _waitq_setactive(void);
+void _waitq_clearactive(void);
+#endif
+void _thread_exit(char *, int, char *) __dead2;
+void _thread_exit_cleanup(void);
+int _thread_fd_getflags(int);
+int _thread_fd_lock(int, int, struct timespec *);
+int _thread_fd_lock_debug(int, int, struct timespec *,char *fname,int lineno);
+void _thread_fd_setflags(int, int);
+int _thread_fd_table_init(int fd);
+void _thread_fd_unlock(int, int);
+void _thread_fd_unlock_debug(int, int, char *, int);
+void _thread_fd_unlock_owned(pthread_t);
+void *_thread_cleanup(pthread_t);
+void _thread_cleanupspecific(void);
+void _thread_dump_info(void);
+void _thread_init(void);
+void _thread_kern_sched(ucontext_t *);
+void _thread_kern_scheduler(void);
+void _thread_kern_sched_frame(struct pthread_signal_frame *psf);
+void _thread_kern_sched_sig(void);
+void _thread_kern_sched_state(enum pthread_state, char *fname, int lineno);
+void _thread_kern_sched_state_unlock(enum pthread_state state,
+ spinlock_t *lock, char *fname, int lineno);
+void _thread_kern_set_timeout(const struct timespec *);
+void _thread_kern_sig_defer(void);
+void _thread_kern_sig_undefer(void);
+void _thread_sig_handler(int, siginfo_t *, ucontext_t *);
+void _thread_sig_check_pending(struct pthread *pthread);
+void _thread_sig_handle_pending(void);
+void _thread_sig_send(struct pthread *pthread, int sig);
+void _thread_sig_wrapper(void);
+void _thread_sigframe_restore(struct pthread *thread,
+ struct pthread_signal_frame *psf);
+void _thread_start(void);
+void _thread_seterrno(pthread_t, int);
+pthread_addr_t _thread_gc(pthread_addr_t);
+void _thread_enter_cancellation_point(void);
+void _thread_leave_cancellation_point(void);
+void _thread_cancellation_point(void);
+
+/* #include <sys/acl.h> */
+#ifdef _SYS_ACL_H
+int __sys___acl_aclcheck_fd(int, acl_type_t, struct acl *);
+int __sys___acl_delete_fd(int, acl_type_t);
+int __sys___acl_get_fd(int, acl_type_t, struct acl *);
+int __sys___acl_set_fd(int, acl_type_t, struct acl *);
+#endif
+
+/* #include <sys/aio.h> */
+#ifdef _SYS_AIO_H_
+int __sys_aio_suspend(const struct aiocb * const[], int, const struct timespec *);
+#endif
+
+/* #include <sys/event.h> */
+#ifdef _SYS_EVENT_H_
+int __sys_kevent(int, const struct kevent *, int, struct kevent *,
+ int, const struct timespec *);
+#endif
+
+/* #include <sys/ioctl.h> */
+#ifdef _SYS_IOCTL_H_
+int __sys_ioctl(int, unsigned long, ...);
+#endif
+
+/* #include <sys/mman.h> */
+#ifdef _SYS_MMAN_H_
+int __sys_msync(void *, size_t, int);
+#endif
+
+/* #include <sys/mount.h> */
+#ifdef _SYS_MOUNT_H_
+int __sys_fstatfs(int, struct statfs *);
+#endif
+
+/* #include <sys/socket.h> */
+#ifdef _SYS_SOCKET_H_
+int __sys_accept(int, struct sockaddr *, socklen_t *);
+int __sys_bind(int, const struct sockaddr *, socklen_t);
+int __sys_connect(int, const struct sockaddr *, socklen_t);
+int __sys_getpeername(int, struct sockaddr *, socklen_t *);
+int __sys_getsockname(int, struct sockaddr *, socklen_t *);
+int __sys_getsockopt(int, int, int, void *, socklen_t *);
+int __sys_listen(int, int);
+ssize_t __sys_recvfrom(int, void *, size_t, int, struct sockaddr *, socklen_t *);
+ssize_t __sys_recvmsg(int, struct msghdr *, int);
+int __sys_sendfile(int, int, off_t, size_t, struct sf_hdtr *, off_t *, int);
+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_setsockopt(int, int, int, const void *, socklen_t);
+int __sys_shutdown(int, int);
+int __sys_socket(int, int, int);
+int __sys_socketpair(int, int, int, int *);
+#endif
+
+/* #include <sys/stat.h> */
+#ifdef _SYS_STAT_H_
+int __sys_fchflags(int, u_long);
+int __sys_fchmod(int, mode_t);
+int __sys_fstat(int, struct stat *);
+#endif
+
+/* #include <sys/uio.h> */
+#ifdef _SYS_UIO_H_
+ssize_t __sys_readv(int, const struct iovec *, int);
+ssize_t __sys_writev(int, const struct iovec *, int);
+#endif
+
+/* #include <sys/wait.h> */
+#ifdef WNOHANG
+pid_t __sys_wait4(pid_t, int *, int, struct rusage *);
+#endif
+
+/* #include <dirent.h> */
+#ifdef _DIRENT_H_
+int __sys_getdirentries(int, char *, int, long *);
+#endif
+
+/* #include <fcntl.h> */
+#ifdef _SYS_FCNTL_H_
+int __sys_fcntl(int, int, ...);
+int __sys_flock(int, int);
+int __sys_open(const char *, int, ...);
+#endif
+
+/* #include <poll.h> */
+#ifdef _SYS_POLL_H_
+int __sys_poll(struct pollfd *, unsigned, int);
+#endif
+
+/* #include <signal.h> */
+#ifdef _SIGNAL_H_
+int __sys_sigaction(int, const struct sigaction *, struct sigaction *);
+int __sys_sigprocmask(int, const sigset_t *, sigset_t *);
+int __sys_sigreturn(ucontext_t *);
+#endif
+
+/* #include <unistd.h> */
+#ifdef _UNISTD_H_
+int __sys_close(int);
+int __sys_dup(int);
+int __sys_dup2(int, int);
+int __sys_execve(const char *, char * const *, char * const *);
+void __sys_exit(int) __dead2;
+int __sys_fchown(int, uid_t, gid_t);
+pid_t __sys_fork(void);
+long __sys_fpathconf(int, int);
+int __sys_fsync(int);
+int __sys_pipe(int *);
+ssize_t __sys_read(int, void *, size_t);
+ssize_t __sys_write(int, const void *, size_t);
+#endif
+
+/* #include <setjmp.h> */
+#ifdef _SETJMP_H_
+extern void __siglongjmp(sigjmp_buf, int) __dead2;
+extern void __longjmp(jmp_buf, int) __dead2;
+extern void ___longjmp(jmp_buf, int) __dead2;
+#endif
+__END_DECLS
+
+#endif /* !_PTHREAD_PRIVATE_H */
diff --git a/lib/libc_r/uthread/uthread_accept.c b/lib/libc_r/uthread/uthread_accept.c
new file mode 100644
index 0000000..f045fc1
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_accept.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(__accept, accept);
+
+int
+_accept(int fd, struct sockaddr * name, socklen_t *namelen)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ /* Lock the file descriptor: */
+ if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) {
+ /* Enter a loop to wait for a connection request: */
+ while ((ret = __sys_accept(fd, name, namelen)) < 0) {
+ /* Check if the socket is to block: */
+ if ((_thread_fd_getflags(fd) & O_NONBLOCK) == 0
+ && (errno == EWOULDBLOCK || errno == EAGAIN)) {
+ /* Save the socket file descriptor: */
+ curthread->data.fd.fd = fd;
+ curthread->data.fd.fname = __FILE__;
+ curthread->data.fd.branch = __LINE__;
+
+ /* Set the timeout: */
+ _thread_kern_set_timeout(NULL);
+ curthread->interrupted = 0;
+
+ /* Schedule the next thread: */
+ _thread_kern_sched_state(PS_FDR_WAIT, __FILE__, __LINE__);
+
+ /* Check if the wait was interrupted: */
+ if (curthread->interrupted) {
+ /* Return an error status: */
+ errno = EINTR;
+ ret = -1;
+ break;
+ }
+ } else {
+ /*
+ * Another error has occurred, so exit the
+ * loop here:
+ */
+ break;
+ }
+ }
+
+ /* Check for errors: */
+ if (ret < 0) {
+ }
+ /* Initialise the file descriptor table for the new socket: */
+ else if (_thread_fd_table_init(ret) != 0) {
+ /* Quietly close the socket: */
+ __sys_close(ret);
+
+ /* Return an error: */
+ ret = -1;
+ }
+ /*
+ * If the parent socket was blocking, make sure that
+ * the new socket is also set blocking here (as the
+ * call to _thread_fd_table_init() above will always
+ * set the new socket flags to non-blocking, as that
+ * will be the inherited state of the new socket.
+ */
+ if((ret > 0) && (_thread_fd_getflags(fd) & O_NONBLOCK) == 0)
+ _thread_fd_setflags(ret,
+ _thread_fd_getflags(ret) & ~O_NONBLOCK);
+ /* Unlock the file descriptor: */
+ _FD_UNLOCK(fd, FD_RDWR);
+ }
+ /* Return the socket file descriptor or -1 on error: */
+ return (ret);
+}
+
+int
+__accept(int fd, struct sockaddr * name, socklen_t *namelen)
+{
+ int ret;
+
+ _thread_enter_cancellation_point();
+ ret = _accept(fd, name, namelen);
+ _thread_leave_cancellation_point();
+
+ return (ret);
+}
diff --git a/lib/libc_r/uthread/uthread_acl_aclcheck_fd.c b/lib/libc_r/uthread/uthread_acl_aclcheck_fd.c
new file mode 100644
index 0000000..19e9aaa
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_acl_aclcheck_fd.c
@@ -0,0 +1,47 @@
+/*-
+ * Copyright (c) 2001 Thomas Moestl
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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/acl.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(___acl_aclcheck_fd, __acl_aclcheck_fd);
+
+int
+___acl_aclcheck_fd(int fd, acl_type_t tp, acl_t acl)
+{
+ int error;
+
+ if ((error = _FD_LOCK(fd, FD_READ, NULL)) == 0) {
+ error = __sys___acl_aclcheck_fd(fd, tp, (struct acl *)acl);
+ _FD_UNLOCK(fd, FD_READ);
+ }
+ return (error);
+}
+
diff --git a/lib/libc_r/uthread/uthread_acl_delete_fd.c b/lib/libc_r/uthread/uthread_acl_delete_fd.c
new file mode 100644
index 0000000..2368c5f
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_acl_delete_fd.c
@@ -0,0 +1,46 @@
+/*-
+ * Copyright (c) 2001 Thomas Moestl
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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/acl.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(___acl_delete_fd, __acl_delete_fd);
+
+int
+___acl_delete_fd(int fd, acl_type_t tp)
+{
+ int error;
+
+ if ((error = _FD_LOCK(fd, FD_WRITE, NULL)) == 0) {
+ error = __sys___acl_delete_fd(fd, tp);
+ _FD_UNLOCK(fd, FD_WRITE);
+ }
+ return (error);
+}
diff --git a/lib/libc_r/uthread/uthread_acl_get_fd.c b/lib/libc_r/uthread/uthread_acl_get_fd.c
new file mode 100644
index 0000000..f0fa8b1
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_acl_get_fd.c
@@ -0,0 +1,47 @@
+/*-
+ * Copyright (c) 2001 Thomas Moestl
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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/acl.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(___acl_get_fd, __acl_get_fd);
+
+int
+___acl_get_fd(int fd, acl_type_t tp, struct acl *acl_p)
+{
+ int error;
+
+ if ((error = _FD_LOCK(fd, FD_READ, NULL)) == 0) {
+ error = __sys___acl_get_fd(fd, tp, acl_p);
+ _FD_UNLOCK(fd, FD_READ);
+ }
+ return (error);
+
+}
diff --git a/lib/libc_r/uthread/uthread_acl_set_fd.c b/lib/libc_r/uthread/uthread_acl_set_fd.c
new file mode 100644
index 0000000..c68751a
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_acl_set_fd.c
@@ -0,0 +1,46 @@
+/*-
+ * Copyright (c) 2001 Thomas Moestl
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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/acl.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(___acl_set_fd, __acl_set_fd);
+
+int
+___acl_set_fd(int fd, acl_type_t tp, struct acl *acl_p)
+{
+ int error;
+
+ if ((error = _FD_LOCK(fd, FD_WRITE, NULL)) == 0) {
+ error = __sys___acl_set_fd(fd, tp, acl_p);
+ _FD_UNLOCK(fd, FD_WRITE);
+ }
+ return (error);
+}
diff --git a/lib/libc_r/uthread/uthread_aio_suspend.c b/lib/libc_r/uthread/uthread_aio_suspend.c
new file mode 100644
index 0000000..23d34f9
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_aio_suspend.c
@@ -0,0 +1,50 @@
+/*
+ * 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$
+ */
+
+#include <aio.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_aio_suspend, aio_suspend);
+
+int
+_aio_suspend(const struct aiocb * const iocbs[], int niocb, const struct
+ timespec *timeout)
+{
+ int ret;
+
+ _thread_enter_cancellation_point();
+ ret = __sys_aio_suspend(iocbs, niocb, timeout);
+ _thread_leave_cancellation_point();
+
+ return ret;
+}
+
diff --git a/lib/libc_r/uthread/uthread_atfork.c b/lib/libc_r/uthread/uthread_atfork.c
new file mode 100644
index 0000000..8a09468
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_atfork.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2003 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 THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <sys/queue.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_atfork, pthread_atfork);
+
+int
+_pthread_atfork(void (*prepare)(void), void (*parent)(void),
+ void (*child)(void))
+{
+ struct pthread_atfork *af;
+
+ if (_thread_initial == NULL)
+ _thread_init();
+
+ if ((af = malloc(sizeof(struct pthread_atfork))) == NULL)
+ return (ENOMEM);
+
+ af->prepare = prepare;
+ af->parent = parent;
+ af->child = child;
+ _pthread_mutex_lock(&_atfork_mutex);
+ TAILQ_INSERT_TAIL(&_atfork_list, af, qe);
+ _pthread_mutex_unlock(&_atfork_mutex);
+ return (0);
+}
+
diff --git a/lib/libc_r/uthread/uthread_attr_destroy.c b/lib/libc_r/uthread/uthread_attr_destroy.c
new file mode 100644
index 0000000..420bd5a
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_attr_destroy.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 1996 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <errno.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_attr_destroy, pthread_attr_destroy);
+
+int
+_pthread_attr_destroy(pthread_attr_t *attr)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL)
+ /* Invalid argument: */
+ ret = EINVAL;
+ else {
+ /* Free the memory allocated to the attribute object: */
+ free(*attr);
+
+ /*
+ * Leave the attribute pointer NULL now that the memory
+ * has been freed:
+ */
+ *attr = NULL;
+ ret = 0;
+ }
+ return(ret);
+}
diff --git a/lib/libc_r/uthread/uthread_attr_get_np.c b/lib/libc_r/uthread/uthread_attr_get_np.c
new file mode 100644
index 0000000..ba6fd19
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_attr_get_np.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2002,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$
+ */
+#include <errno.h>
+#include <string.h>
+#include <pthread.h>
+#include <pthread_np.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_attr_get_np, pthread_attr_get_np);
+
+int
+_pthread_attr_get_np(pthread_t pid, pthread_attr_t *dst)
+{
+ int ret;
+
+ if (pid == NULL || dst == NULL || *dst == NULL)
+ return (EINVAL);
+
+ if ((ret = _find_thread(pid)) != 0)
+ return (ret);
+
+ memcpy(*dst, &pid->attr, sizeof(struct pthread_attr));
+
+ /*
+ * Special case, if stack address was not provided by caller
+ * of pthread_create(), then return address allocated internally
+ */
+ if ((*dst)->stackaddr_attr == NULL)
+ (*dst)->stackaddr_attr = pid->stack;
+
+ return (0);
+}
diff --git a/lib/libc_r/uthread/uthread_attr_getdetachstate.c b/lib/libc_r/uthread/uthread_attr_getdetachstate.c
new file mode 100644
index 0000000..515248d
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_attr_getdetachstate.c
@@ -0,0 +1,59 @@
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_attr_getdetachstate, pthread_attr_getdetachstate);
+
+int
+_pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL || detachstate == NULL)
+ ret = EINVAL;
+ else {
+ /* Check if the detached flag is set: */
+ if ((*attr)->flags & PTHREAD_DETACHED)
+ /* Return detached: */
+ *detachstate = PTHREAD_CREATE_DETACHED;
+ else
+ /* Return joinable: */
+ *detachstate = PTHREAD_CREATE_JOINABLE;
+ ret = 0;
+ }
+ return(ret);
+}
diff --git a/lib/libc_r/uthread/uthread_attr_getguardsize.c b/lib/libc_r/uthread/uthread_attr_getguardsize.c
new file mode 100644
index 0000000..849bf27
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_attr_getguardsize.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2001 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
+ * unmodified other than the allowable 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 <errno.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_attr_getguardsize, pthread_attr_getguardsize);
+
+int
+_pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL || guardsize == NULL)
+ ret = EINVAL;
+ else {
+ /* Return the guard size: */
+ *guardsize = (*attr)->guardsize_attr;
+ ret = 0;
+ }
+ return(ret);
+}
diff --git a/lib/libc_r/uthread/uthread_attr_getinheritsched.c b/lib/libc_r/uthread/uthread_attr_getinheritsched.c
new file mode 100644
index 0000000..6d6d324
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_attr_getinheritsched.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_attr_getinheritsched, pthread_attr_getinheritsched);
+
+int
+_pthread_attr_getinheritsched(const pthread_attr_t *attr, int *sched_inherit)
+{
+ int ret = 0;
+
+ if ((attr == NULL) || (*attr == NULL))
+ ret = EINVAL;
+ else
+ *sched_inherit = (*attr)->sched_inherit;
+
+ return(ret);
+}
diff --git a/lib/libc_r/uthread/uthread_attr_getschedparam.c b/lib/libc_r/uthread/uthread_attr_getschedparam.c
new file mode 100644
index 0000000..cac86fa
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_attr_getschedparam.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_attr_getschedparam, pthread_attr_getschedparam);
+
+int
+_pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param)
+{
+ int ret = 0;
+
+ if ((attr == NULL) || (*attr == NULL) || (param == NULL))
+ ret = EINVAL;
+ else
+ param->sched_priority = (*attr)->prio;
+
+ return(ret);
+}
diff --git a/lib/libc_r/uthread/uthread_attr_getschedpolicy.c b/lib/libc_r/uthread/uthread_attr_getschedpolicy.c
new file mode 100644
index 0000000..f2b74fc
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_attr_getschedpolicy.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_attr_getschedpolicy, pthread_attr_getschedpolicy);
+
+int
+_pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy)
+{
+ int ret = 0;
+
+ if ((attr == NULL) || (*attr == NULL) || (policy == NULL))
+ ret = EINVAL;
+ else
+ *policy = (*attr)->sched_policy;
+
+ return(ret);
+}
diff --git a/lib/libc_r/uthread/uthread_attr_getscope.c b/lib/libc_r/uthread/uthread_attr_getscope.c
new file mode 100644
index 0000000..8abf418
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_attr_getscope.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_attr_getscope, pthread_attr_getscope);
+
+int
+_pthread_attr_getscope(const pthread_attr_t *attr, int *contentionscope)
+{
+ int ret = 0;
+
+ if ((attr == NULL) || (*attr == NULL) || (contentionscope == NULL))
+ /* Return an invalid argument: */
+ ret = EINVAL;
+
+ else
+ *contentionscope = (*attr)->flags & PTHREAD_SCOPE_SYSTEM ?
+ PTHREAD_SCOPE_SYSTEM : PTHREAD_SCOPE_PROCESS;
+
+ return(ret);
+}
diff --git a/lib/libc_r/uthread/uthread_attr_getstack.c b/lib/libc_r/uthread/uthread_attr_getstack.c
new file mode 100644
index 0000000..e63cd8f
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_attr_getstack.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2003 Craig Rodrigues <rodrigc@attbi.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Craig Rodrigues.
+ * 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 CRAIG RODRIGUES AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_attr_getstack, pthread_attr_getstack);
+
+int
+_pthread_attr_getstack(const pthread_attr_t * __restrict attr,
+ void ** __restrict stackaddr,
+ size_t * __restrict stacksize)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL || stackaddr == NULL
+ || stacksize == NULL )
+ ret = EINVAL;
+ else {
+ /* Return the stack address and size */
+ *stackaddr = (*attr)->stackaddr_attr;
+ *stacksize = (*attr)->stacksize_attr;
+ ret = 0;
+ }
+ return(ret);
+}
+
diff --git a/lib/libc_r/uthread/uthread_attr_getstackaddr.c b/lib/libc_r/uthread/uthread_attr_getstackaddr.c
new file mode 100644
index 0000000..0cef0f3
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_attr_getstackaddr.c
@@ -0,0 +1,54 @@
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_attr_getstackaddr, pthread_attr_getstackaddr);
+
+int
+_pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL || stackaddr == NULL)
+ ret = EINVAL;
+ else {
+ /* Return the stack address: */
+ *stackaddr = (*attr)->stackaddr_attr;
+ ret = 0;
+ }
+ return(ret);
+}
diff --git a/lib/libc_r/uthread/uthread_attr_getstacksize.c b/lib/libc_r/uthread/uthread_attr_getstacksize.c
new file mode 100644
index 0000000..091a0c7
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_attr_getstacksize.c
@@ -0,0 +1,54 @@
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_attr_getstacksize, pthread_attr_getstacksize);
+
+int
+_pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL || stacksize == NULL)
+ ret = EINVAL;
+ else {
+ /* Return the stack size: */
+ *stacksize = (*attr)->stacksize_attr;
+ ret = 0;
+ }
+ return(ret);
+}
diff --git a/lib/libc_r/uthread/uthread_attr_init.c b/lib/libc_r/uthread/uthread_attr_init.c
new file mode 100644
index 0000000..10423ce
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_attr_init.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1996 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_attr_init, pthread_attr_init);
+
+int
+_pthread_attr_init(pthread_attr_t *attr)
+{
+ int ret;
+ pthread_attr_t pattr;
+
+ /* Allocate memory for the attribute object: */
+ if ((pattr = (pthread_attr_t) malloc(sizeof(struct pthread_attr))) == NULL)
+ /* Insufficient memory: */
+ ret = ENOMEM;
+ else {
+ /* Initialise the attribute object with the defaults: */
+ memcpy(pattr, &_pthread_attr_default, sizeof(*pattr));
+
+ /* Return a pointer to the attribute object: */
+ *attr = pattr;
+ ret = 0;
+ }
+ return(ret);
+}
diff --git a/lib/libc_r/uthread/uthread_attr_setcreatesuspend_np.c b/lib/libc_r/uthread/uthread_attr_setcreatesuspend_np.c
new file mode 100644
index 0000000..be6f8d7
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_attr_setcreatesuspend_np.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_attr_setcreatesuspend_np, pthread_attr_setcreatesuspend_np);
+
+int
+_pthread_attr_setcreatesuspend_np(pthread_attr_t *attr)
+{
+ int ret;
+ if (attr == NULL || *attr == NULL) {
+ errno = EINVAL;
+ ret = -1;
+ } else {
+ (*attr)->suspend = PTHREAD_CREATE_SUSPENDED;
+ ret = 0;
+ }
+ return(ret);
+}
diff --git a/lib/libc_r/uthread/uthread_attr_setdetachstate.c b/lib/libc_r/uthread/uthread_attr_setdetachstate.c
new file mode 100644
index 0000000..e0e23c2
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_attr_setdetachstate.c
@@ -0,0 +1,61 @@
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_attr_setdetachstate, pthread_attr_setdetachstate);
+
+int
+_pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL ||
+ (detachstate != PTHREAD_CREATE_DETACHED &&
+ detachstate != PTHREAD_CREATE_JOINABLE))
+ ret = EINVAL;
+ else {
+ /* Check if detached state: */
+ if (detachstate == PTHREAD_CREATE_DETACHED)
+ /* Set the detached flag: */
+ (*attr)->flags |= PTHREAD_DETACHED;
+ else
+ /* Reset the detached flag: */
+ (*attr)->flags &= ~PTHREAD_DETACHED;
+ ret = 0;
+ }
+ return(ret);
+}
diff --git a/lib/libc_r/uthread/uthread_attr_setguardsize.c b/lib/libc_r/uthread/uthread_attr_setguardsize.c
new file mode 100644
index 0000000..ad3e8bb
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_attr_setguardsize.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2001 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
+ * unmodified other than the allowable 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 <sys/param.h>
+#include <errno.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_attr_setguardsize, pthread_attr_setguardsize);
+
+int
+_pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize)
+{
+ int ret;
+
+ /* Check for invalid arguments. */
+ if (attr == NULL || *attr == NULL)
+ ret = EINVAL;
+ else {
+ /*
+ * Round guardsize up to the nearest multiple of
+ * _pthread_page_size.
+ */
+ if (guardsize % _pthread_page_size != 0)
+ guardsize = ((guardsize / _pthread_page_size) + 1) *
+ _pthread_page_size;
+
+ /* Save the stack size. */
+ (*attr)->guardsize_attr = guardsize;
+ ret = 0;
+ }
+ return(ret);
+}
diff --git a/lib/libc_r/uthread/uthread_attr_setinheritsched.c b/lib/libc_r/uthread/uthread_attr_setinheritsched.c
new file mode 100644
index 0000000..3538131
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_attr_setinheritsched.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_attr_setinheritsched, pthread_attr_setinheritsched);
+
+int
+_pthread_attr_setinheritsched(pthread_attr_t *attr, int sched_inherit)
+{
+ int ret = 0;
+
+ if ((attr == NULL) || (*attr == NULL))
+ ret = EINVAL;
+ else
+ (*attr)->sched_inherit = sched_inherit;
+
+ return(ret);
+}
diff --git a/lib/libc_r/uthread/uthread_attr_setschedparam.c b/lib/libc_r/uthread/uthread_attr_setschedparam.c
new file mode 100644
index 0000000..c42973e
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_attr_setschedparam.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_attr_setschedparam, pthread_attr_setschedparam);
+
+int
+_pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param)
+{
+ int ret = 0;
+
+ if ((attr == NULL) || (*attr == NULL))
+ ret = EINVAL;
+ else if (param == NULL) {
+ ret = ENOTSUP;
+ } else if ((param->sched_priority < PTHREAD_MIN_PRIORITY) ||
+ (param->sched_priority > PTHREAD_MAX_PRIORITY)) {
+ /* Return an unsupported value error. */
+ ret = ENOTSUP;
+ } else
+ (*attr)->prio = param->sched_priority;
+
+ return(ret);
+}
diff --git a/lib/libc_r/uthread/uthread_attr_setschedpolicy.c b/lib/libc_r/uthread/uthread_attr_setschedpolicy.c
new file mode 100644
index 0000000..d9c83e6
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_attr_setschedpolicy.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_attr_setschedpolicy, pthread_attr_setschedpolicy);
+
+int
+_pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
+{
+ int ret = 0;
+
+ if ((attr == NULL) || (*attr == NULL))
+ ret = EINVAL;
+ else if ((policy < SCHED_FIFO) || (policy > SCHED_RR)) {
+ ret = ENOTSUP;
+ } else
+ (*attr)->sched_policy = policy;
+
+ return(ret);
+}
diff --git a/lib/libc_r/uthread/uthread_attr_setscope.c b/lib/libc_r/uthread/uthread_attr_setscope.c
new file mode 100644
index 0000000..3614615
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_attr_setscope.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_attr_setscope, pthread_attr_setscope);
+
+int
+_pthread_attr_setscope(pthread_attr_t *attr, int contentionscope)
+{
+ int ret = 0;
+
+ if ((attr == NULL) || (*attr == NULL)) {
+ /* Return an invalid argument: */
+ ret = EINVAL;
+ } else if ((contentionscope != PTHREAD_SCOPE_PROCESS) ||
+ (contentionscope == PTHREAD_SCOPE_SYSTEM)) {
+ /* We don't support PTHREAD_SCOPE_SYSTEM. */
+ ret = ENOTSUP;
+ } else
+ (*attr)->flags |= contentionscope;
+
+ return(ret);
+}
diff --git a/lib/libc_r/uthread/uthread_attr_setstack.c b/lib/libc_r/uthread/uthread_attr_setstack.c
new file mode 100644
index 0000000..e03f6de
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_attr_setstack.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2003 Craig Rodrigues <rodrigc@attbi.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Craig Rodrigues.
+ * 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 CRAIG RODRIGUES AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_attr_setstack, pthread_attr_setstack);
+
+int
+_pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr,
+ size_t stacksize)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL || stackaddr == NULL
+ || stacksize < PTHREAD_STACK_MIN )
+ ret = EINVAL;
+ else {
+ /* Save the stack address and stack size */
+ (*attr)->stackaddr_attr = stackaddr;
+ (*attr)->stacksize_attr = stacksize;
+ ret = 0;
+ }
+ return(ret);
+}
+
diff --git a/lib/libc_r/uthread/uthread_attr_setstackaddr.c b/lib/libc_r/uthread/uthread_attr_setstackaddr.c
new file mode 100644
index 0000000..6046932
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_attr_setstackaddr.c
@@ -0,0 +1,54 @@
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_attr_setstackaddr, pthread_attr_setstackaddr);
+
+int
+_pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL || stackaddr == NULL)
+ ret = EINVAL;
+ else {
+ /* Save the stack address: */
+ (*attr)->stackaddr_attr = stackaddr;
+ ret = 0;
+ }
+ return(ret);
+}
diff --git a/lib/libc_r/uthread/uthread_attr_setstacksize.c b/lib/libc_r/uthread/uthread_attr_setstacksize.c
new file mode 100644
index 0000000..622ba7f
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_attr_setstacksize.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1996 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_attr_setstacksize, pthread_attr_setstacksize);
+
+int
+_pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL || stacksize < PTHREAD_STACK_MIN)
+ ret = EINVAL;
+ else {
+ /* Save the stack size: */
+ (*attr)->stacksize_attr = stacksize;
+ ret = 0;
+ }
+ return(ret);
+}
diff --git a/lib/libc_r/uthread/uthread_autoinit.c b/lib/libc_r/uthread/uthread_autoinit.c
new file mode 100644
index 0000000..03ee58d
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_autoinit.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2002 Alfred Perlstein <alfred@freebsd.org>.
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <pthread_private.h>
+
+/*
+ * This module uses GCC extentions to initialize the
+ * threads package at program start-up time.
+ */
+
+void _thread_init_hack(void) __attribute__ ((constructor));
+
+void
+_thread_init_hack(void)
+{
+
+ _thread_init();
+}
+
+/*
+ * For the shared version of the threads library, the above is sufficient.
+ * But for the archive version of the library, we need a little bit more.
+ * Namely, we must arrange for this particular module to be pulled in from
+ * the archive library at link time. To accomplish that, we define and
+ * initialize a variable, "_thread_autoinit_dummy_decl". This variable is
+ * referenced (as an extern) from libc/stdlib/exit.c. This will always
+ * create a need for this module, ensuring that it is present in the
+ * executable.
+ */
+extern int _thread_autoinit_dummy_decl;
+int _thread_autoinit_dummy_decl = 0;
diff --git a/lib/libc_r/uthread/uthread_bind.c b/lib/libc_r/uthread/uthread_bind.c
new file mode 100644
index 0000000..bb076b0
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_bind.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_bind, bind);
+
+int
+_bind(int fd, const struct sockaddr * name, socklen_t namelen)
+{
+ int ret;
+
+ if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) {
+ ret = __sys_bind(fd, name, namelen);
+ _FD_UNLOCK(fd, FD_RDWR);
+ }
+ return (ret);
+}
diff --git a/lib/libc_r/uthread/uthread_cancel.c b/lib/libc_r/uthread/uthread_cancel.c
new file mode 100644
index 0000000..d9324ab
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_cancel.c
@@ -0,0 +1,231 @@
+/*
+ * David Leonard <d@openbsd.org>, 1999. Public domain.
+ * $FreeBSD$
+ */
+#include <sys/errno.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+static void finish_cancellation(void *arg);
+
+__weak_reference(_pthread_cancel, pthread_cancel);
+__weak_reference(_pthread_setcancelstate, pthread_setcancelstate);
+__weak_reference(_pthread_setcanceltype, pthread_setcanceltype);
+__weak_reference(_pthread_testcancel, pthread_testcancel);
+
+int
+_pthread_cancel(pthread_t pthread)
+{
+ int ret;
+
+ if ((ret = _find_thread(pthread)) != 0) {
+ /* NOTHING */
+ } else if (pthread->state == PS_DEAD || pthread->state == PS_DEADLOCK
+ || (pthread->flags & PTHREAD_EXITING) != 0) {
+ ret = 0;
+ } else {
+ /* Protect the scheduling queues: */
+ _thread_kern_sig_defer();
+
+ if (((pthread->cancelflags & PTHREAD_CANCEL_DISABLE) != 0) ||
+ (((pthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) == 0) &&
+ ((pthread->cancelflags & PTHREAD_AT_CANCEL_POINT) == 0)))
+ /* Just mark it for cancellation: */
+ pthread->cancelflags |= PTHREAD_CANCELLING;
+ else {
+ /*
+ * Check if we need to kick it back into the
+ * run queue:
+ */
+ switch (pthread->state) {
+ case PS_RUNNING:
+ /* No need to resume: */
+ pthread->cancelflags |= PTHREAD_CANCELLING;
+ break;
+
+ case PS_SPINBLOCK:
+ case PS_FDR_WAIT:
+ case PS_FDW_WAIT:
+ case PS_POLL_WAIT:
+ case PS_SELECT_WAIT:
+ /* Remove these threads from the work queue: */
+ if ((pthread->flags & PTHREAD_FLAGS_IN_WORKQ)
+ != 0)
+ PTHREAD_WORKQ_REMOVE(pthread);
+ /* Fall through: */
+ case PS_SIGTHREAD:
+ case PS_SLEEP_WAIT:
+ case PS_WAIT_WAIT:
+ case PS_SIGSUSPEND:
+ case PS_SIGWAIT:
+ /* Interrupt and resume: */
+ pthread->interrupted = 1;
+ pthread->cancelflags |= PTHREAD_CANCELLING;
+ PTHREAD_NEW_STATE(pthread,PS_RUNNING);
+ break;
+
+ case PS_JOIN:
+ /*
+ * Disconnect the thread from the joinee:
+ */
+ if (pthread->join_status.thread != NULL) {
+ pthread->join_status.thread->joiner
+ = NULL;
+ pthread->join_status.thread = NULL;
+ }
+ pthread->cancelflags |= PTHREAD_CANCELLING;
+ PTHREAD_NEW_STATE(pthread, PS_RUNNING);
+ break;
+
+ case PS_SUSPENDED:
+ case PS_MUTEX_WAIT:
+ case PS_COND_WAIT:
+ case PS_FDLR_WAIT:
+ case PS_FDLW_WAIT:
+ case PS_FILE_WAIT:
+ /*
+ * Threads in these states may be in queues.
+ * In order to preserve queue integrity, the
+ * cancelled thread must remove itself from the
+ * queue. Mark the thread as interrupted and
+ * needing cancellation, and set the state to
+ * running. When the thread resumes, it will
+ * remove itself from the queue and call the
+ * cancellation completion routine.
+ */
+ pthread->interrupted = 1;
+ pthread->cancelflags |= PTHREAD_CANCEL_NEEDED;
+ PTHREAD_NEW_STATE(pthread, PS_RUNNING);
+ pthread->continuation = finish_cancellation;
+ break;
+
+ case PS_DEAD:
+ case PS_DEADLOCK:
+ case PS_STATE_MAX:
+ /* Ignore - only here to silence -Wall: */
+ break;
+ }
+ }
+
+ /* Unprotect the scheduling queues: */
+ _thread_kern_sig_undefer();
+
+ ret = 0;
+ }
+ return (ret);
+}
+
+int
+_pthread_setcancelstate(int state, int *oldstate)
+{
+ struct pthread *curthread = _get_curthread();
+ int ostate;
+ int ret;
+
+ ostate = curthread->cancelflags & PTHREAD_CANCEL_DISABLE;
+
+ switch (state) {
+ case PTHREAD_CANCEL_ENABLE:
+ if (oldstate != NULL)
+ *oldstate = ostate;
+ curthread->cancelflags &= ~PTHREAD_CANCEL_DISABLE;
+ if ((curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0)
+ pthread_testcancel();
+ ret = 0;
+ break;
+ case PTHREAD_CANCEL_DISABLE:
+ if (oldstate != NULL)
+ *oldstate = ostate;
+ curthread->cancelflags |= PTHREAD_CANCEL_DISABLE;
+ ret = 0;
+ break;
+ default:
+ ret = EINVAL;
+ }
+
+ return (ret);
+}
+
+int
+_pthread_setcanceltype(int type, int *oldtype)
+{
+ struct pthread *curthread = _get_curthread();
+ int otype;
+ int ret;
+
+ otype = curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS;
+ switch (type) {
+ case PTHREAD_CANCEL_ASYNCHRONOUS:
+ if (oldtype != NULL)
+ *oldtype = otype;
+ curthread->cancelflags |= PTHREAD_CANCEL_ASYNCHRONOUS;
+ pthread_testcancel();
+ ret = 0;
+ break;
+ case PTHREAD_CANCEL_DEFERRED:
+ if (oldtype != NULL)
+ *oldtype = otype;
+ curthread->cancelflags &= ~PTHREAD_CANCEL_ASYNCHRONOUS;
+ ret = 0;
+ break;
+ default:
+ ret = EINVAL;
+ }
+
+ return (ret);
+}
+
+void
+_pthread_testcancel(void)
+{
+ struct pthread *curthread = _get_curthread();
+
+ if (((curthread->cancelflags & PTHREAD_CANCEL_DISABLE) == 0) &&
+ ((curthread->cancelflags & PTHREAD_CANCELLING) != 0) &&
+ ((curthread->flags & PTHREAD_EXITING) == 0)) {
+ /*
+ * It is possible for this thread to be swapped out
+ * while performing cancellation; do not allow it
+ * to be cancelled again.
+ */
+ curthread->cancelflags &= ~PTHREAD_CANCELLING;
+ _thread_exit_cleanup();
+ pthread_exit(PTHREAD_CANCELED);
+ PANIC("cancel");
+ }
+}
+
+void
+_thread_enter_cancellation_point(void)
+{
+ struct pthread *curthread = _get_curthread();
+
+ /* Look for a cancellation before we block: */
+ pthread_testcancel();
+ curthread->cancelflags |= PTHREAD_AT_CANCEL_POINT;
+}
+
+void
+_thread_leave_cancellation_point(void)
+{
+ struct pthread *curthread = _get_curthread();
+
+ curthread->cancelflags &= ~PTHREAD_AT_CANCEL_POINT;
+ /* Look for a cancellation after we unblock: */
+ pthread_testcancel();
+}
+
+static void
+finish_cancellation(void *arg)
+{
+ struct pthread *curthread = _get_curthread();
+
+ curthread->continuation = NULL;
+ curthread->interrupted = 0;
+
+ if ((curthread->cancelflags & PTHREAD_CANCEL_NEEDED) != 0) {
+ curthread->cancelflags &= ~PTHREAD_CANCEL_NEEDED;
+ _thread_exit_cleanup();
+ pthread_exit(PTHREAD_CANCELED);
+ }
+}
diff --git a/lib/libc_r/uthread/uthread_clean.c b/lib/libc_r/uthread/uthread_clean.c
new file mode 100644
index 0000000..6330cb9
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_clean.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <signal.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_cleanup_push, pthread_cleanup_push);
+__weak_reference(_pthread_cleanup_pop, pthread_cleanup_pop);
+
+void
+_pthread_cleanup_push(void (*routine) (void *), void *routine_arg)
+{
+ struct pthread *curthread = _get_curthread();
+ struct pthread_cleanup *new;
+
+ if ((new = (struct pthread_cleanup *) malloc(sizeof(struct pthread_cleanup))) != NULL) {
+ new->routine = routine;
+ new->routine_arg = routine_arg;
+ new->next = curthread->cleanup;
+
+ curthread->cleanup = new;
+ }
+}
+
+void
+_pthread_cleanup_pop(int execute)
+{
+ struct pthread *curthread = _get_curthread();
+ struct pthread_cleanup *old;
+
+ if ((old = curthread->cleanup) != NULL) {
+ curthread->cleanup = old->next;
+ if (execute) {
+ old->routine(old->routine_arg);
+ }
+ free(old);
+ }
+}
+
diff --git a/lib/libc_r/uthread/uthread_close.c b/lib/libc_r/uthread/uthread_close.c
new file mode 100644
index 0000000..ba291a3
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_close.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(__close, close);
+
+int
+_close(int fd)
+{
+ int flags;
+ int ret;
+ struct stat sb;
+ struct fd_table_entry *entry;
+
+ if ((fd < 0) || (fd >= _thread_dtablesize) ||
+ (fd == _thread_kern_pipe[0]) || (fd == _thread_kern_pipe[1]) ||
+ (_thread_fd_table[fd] == NULL)) {
+ /*
+ * Don't allow silly programs to close the kernel pipe
+ * and non-active descriptors.
+ */
+ errno = EBADF;
+ ret = -1;
+ }
+ /*
+ * Lock the file descriptor while the file is closed and get
+ * the file descriptor status:
+ */
+ else if (((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) &&
+ ((ret = __sys_fstat(fd, &sb)) == 0)) {
+ /*
+ * Check if the file should be left as blocking.
+ *
+ * This is so that the file descriptors shared with a parent
+ * process aren't left set to non-blocking if the child
+ * closes them prior to exit. An example where this causes
+ * problems with /bin/sh is when a child closes stdin.
+ *
+ * Setting a file as blocking causes problems if a threaded
+ * parent accesses the file descriptor before the child exits.
+ * Once the threaded parent receives a SIGCHLD then it resets
+ * all of its files to non-blocking, and so it is then safe
+ * to access them.
+ *
+ * Pipes are not set to blocking when they are closed, as
+ * the parent and child will normally close the file
+ * descriptor of the end of the pipe that they are not
+ * using, which would then cause any reads to block
+ * indefinitely.
+ */
+ if ((S_ISREG(sb.st_mode) || S_ISCHR(sb.st_mode))
+ && (_thread_fd_getflags(fd) & O_NONBLOCK) == 0) {
+ /* Get the current flags: */
+ flags = __sys_fcntl(fd, F_GETFL, NULL);
+ /* Clear the nonblocking file descriptor flag: */
+ __sys_fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
+ }
+
+ /* XXX: Assumes well behaved threads. */
+ /* XXX: Defer real close to avoid race condition */
+ entry = _thread_fd_table[fd];
+ _thread_fd_table[fd] = NULL;
+ free(entry);
+
+ /* Drop stale pthread stdio descriptor flags. */
+ if (fd < 3)
+ _pthread_stdio_flags[fd] = -1;
+
+ /* Close the file descriptor: */
+ ret = __sys_close(fd);
+ }
+ return (ret);
+}
+
+int
+__close(int fd)
+{
+ int ret;
+
+ _thread_enter_cancellation_point();
+ ret = _close(fd);
+ _thread_leave_cancellation_point();
+
+ return ret;
+}
diff --git a/lib/libc_r/uthread/uthread_concurrency.c b/lib/libc_r/uthread/uthread_concurrency.c
new file mode 100644
index 0000000..ddb82c1
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_concurrency.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2003 Sergey Osokin <osa@FreeBSD.org.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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Sergey Osokin.
+ * 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 SERGEY OSOKIN AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <errno.h>
+
+static int current_concurrency = 0;
+
+__weak_reference(_pthread_getconcurrency, pthread_getconcurrency);
+__weak_reference(_pthread_setconcurrency, pthread_setconcurrency);
+
+int
+_pthread_getconcurrency(void)
+{
+ return current_concurrency;
+}
+
+int
+_pthread_setconcurrency(int new_level)
+{
+ int ret;
+
+ if (new_level < 0) {
+ ret = EINVAL;
+ } else {
+ current_concurrency = new_level;
+ ret = 0;
+ }
+ return(ret);
+}
diff --git a/lib/libc_r/uthread/uthread_cond.c b/lib/libc_r/uthread/uthread_cond.c
new file mode 100644
index 0000000..c3ca741
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_cond.c
@@ -0,0 +1,768 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <errno.h>
+#include <string.h>
+#include "namespace.h"
+#include <pthread.h>
+#include "un-namespace.h"
+#include "pthread_private.h"
+
+/*
+ * Prototypes
+ */
+static inline pthread_t cond_queue_deq(pthread_cond_t);
+static inline void cond_queue_remove(pthread_cond_t, pthread_t);
+static inline void cond_queue_enq(pthread_cond_t, pthread_t);
+int __pthread_cond_timedwait(pthread_cond_t *,
+ pthread_mutex_t *, const struct timespec *);
+int __pthread_cond_wait(pthread_cond_t *,
+ pthread_mutex_t *);
+
+
+/*
+ * Double underscore versions are cancellation points. Single underscore
+ * versions are not and are provided for libc internal usage (which
+ * shouldn't introduce cancellation points).
+ */
+__weak_reference(__pthread_cond_wait, pthread_cond_wait);
+__weak_reference(__pthread_cond_timedwait, pthread_cond_timedwait);
+
+__weak_reference(_pthread_cond_init, pthread_cond_init);
+__weak_reference(_pthread_cond_destroy, pthread_cond_destroy);
+__weak_reference(_pthread_cond_signal, pthread_cond_signal);
+__weak_reference(_pthread_cond_broadcast, pthread_cond_broadcast);
+
+
+/*
+ * Reinitialize a private condition variable; this is only used for
+ * internal condition variables. Currently, there is no difference.
+ */
+int
+_cond_reinit(pthread_cond_t *cond)
+{
+ int ret = 0;
+
+ if (cond == NULL)
+ ret = EINVAL;
+ else if (*cond == NULL)
+ ret = _pthread_cond_init(cond, NULL);
+ else {
+ /*
+ * Initialize the condition variable structure:
+ */
+ TAILQ_INIT(&(*cond)->c_queue);
+ (*cond)->c_flags = COND_FLAGS_INITED;
+ (*cond)->c_type = COND_TYPE_FAST;
+ (*cond)->c_mutex = NULL;
+ (*cond)->c_seqno = 0;
+ memset(&(*cond)->lock, 0, sizeof((*cond)->lock));
+ }
+ return (ret);
+}
+
+int
+_pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr)
+{
+ enum pthread_cond_type type;
+ pthread_cond_t pcond;
+ int rval = 0;
+
+ if (cond == NULL)
+ rval = EINVAL;
+ else {
+ /*
+ * Check if a pointer to a condition variable attribute
+ * structure was passed by the caller:
+ */
+ if (cond_attr != NULL && *cond_attr != NULL) {
+ /* Default to a fast condition variable: */
+ type = (*cond_attr)->c_type;
+ } else {
+ /* Default to a fast condition variable: */
+ type = COND_TYPE_FAST;
+ }
+
+ /* Process according to condition variable type: */
+ switch (type) {
+ /* Fast condition variable: */
+ case COND_TYPE_FAST:
+ /* Nothing to do here. */
+ break;
+
+ /* Trap invalid condition variable types: */
+ default:
+ /* Return an invalid argument error: */
+ rval = EINVAL;
+ break;
+ }
+
+ /* Check for no errors: */
+ if (rval == 0) {
+ if ((pcond = (pthread_cond_t)
+ malloc(sizeof(struct pthread_cond))) == NULL) {
+ rval = ENOMEM;
+ } else {
+ /*
+ * Initialise the condition variable
+ * structure:
+ */
+ TAILQ_INIT(&pcond->c_queue);
+ pcond->c_flags |= COND_FLAGS_INITED;
+ pcond->c_type = type;
+ pcond->c_mutex = NULL;
+ pcond->c_seqno = 0;
+ memset(&pcond->lock,0,sizeof(pcond->lock));
+ *cond = pcond;
+ }
+ }
+ }
+ /* Return the completion status: */
+ return (rval);
+}
+
+int
+_pthread_cond_destroy(pthread_cond_t *cond)
+{
+ int rval = 0;
+
+ if (cond == NULL || *cond == NULL)
+ rval = EINVAL;
+ else {
+ /* Lock the condition variable structure: */
+ _SPINLOCK(&(*cond)->lock);
+
+ /*
+ * Free the memory allocated for the condition
+ * variable structure:
+ */
+ free(*cond);
+
+ /*
+ * NULL the caller's pointer now that the condition
+ * variable has been destroyed:
+ */
+ *cond = NULL;
+ }
+ /* Return the completion status: */
+ return (rval);
+}
+
+int
+_pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
+{
+ struct pthread *curthread = _get_curthread();
+ int rval = 0;
+ int done = 0;
+ int interrupted = 0;
+ int seqno;
+
+ if (cond == NULL)
+ return (EINVAL);
+
+ /*
+ * If the condition variable is statically initialized,
+ * perform the dynamic initialization:
+ */
+ if (*cond == NULL &&
+ (rval = _pthread_cond_init(cond, NULL)) != 0)
+ return (rval);
+
+ /*
+ * Enter a loop waiting for a condition signal or broadcast
+ * to wake up this thread. A loop is needed in case the waiting
+ * thread is interrupted by a signal to execute a signal handler.
+ * It is not (currently) possible to remain in the waiting queue
+ * while running a handler. Instead, the thread is interrupted
+ * and backed out of the waiting queue prior to executing the
+ * signal handler.
+ */
+ do {
+ /* Lock the condition variable structure: */
+ _SPINLOCK(&(*cond)->lock);
+
+ /*
+ * If the condvar was statically allocated, properly
+ * initialize the tail queue.
+ */
+ if (((*cond)->c_flags & COND_FLAGS_INITED) == 0) {
+ TAILQ_INIT(&(*cond)->c_queue);
+ (*cond)->c_flags |= COND_FLAGS_INITED;
+ }
+
+ /* Process according to condition variable type: */
+ switch ((*cond)->c_type) {
+ /* Fast condition variable: */
+ case COND_TYPE_FAST:
+ if ((mutex == NULL) || (((*cond)->c_mutex != NULL) &&
+ ((*cond)->c_mutex != *mutex))) {
+ /* Unlock the condition variable structure: */
+ _SPINUNLOCK(&(*cond)->lock);
+
+ /* Return invalid argument error: */
+ rval = EINVAL;
+ } else {
+ /* Reset the timeout and interrupted flags: */
+ curthread->timeout = 0;
+ curthread->interrupted = 0;
+
+ /*
+ * Queue the running thread for the condition
+ * variable:
+ */
+ cond_queue_enq(*cond, curthread);
+
+ /* Remember the mutex and sequence number: */
+ (*cond)->c_mutex = *mutex;
+ seqno = (*cond)->c_seqno;
+
+ /* Wait forever: */
+ curthread->wakeup_time.tv_sec = -1;
+
+ /* Unlock the mutex: */
+ if ((rval = _mutex_cv_unlock(mutex)) != 0) {
+ /*
+ * Cannot unlock the mutex, so remove
+ * the running thread from the condition
+ * variable queue:
+ */
+ cond_queue_remove(*cond, curthread);
+
+ /* Check for no more waiters: */
+ if (TAILQ_FIRST(&(*cond)->c_queue) ==
+ NULL)
+ (*cond)->c_mutex = NULL;
+
+ /* Unlock the condition variable structure: */
+ _SPINUNLOCK(&(*cond)->lock);
+ } else {
+ /*
+ * Schedule the next thread and unlock
+ * the condition variable structure:
+ */
+ _thread_kern_sched_state_unlock(PS_COND_WAIT,
+ &(*cond)->lock, __FILE__, __LINE__);
+
+ done = (seqno != (*cond)->c_seqno);
+
+ interrupted = curthread->interrupted;
+
+ /*
+ * Check if the wait was interrupted
+ * (canceled) or needs to be resumed
+ * after handling a signal.
+ */
+ if (interrupted != 0) {
+ /*
+ * Lock the mutex and ignore any
+ * errors. Note that even
+ * though this thread may have
+ * been canceled, POSIX requires
+ * that the mutex be reaquired
+ * prior to cancellation.
+ */
+ (void)_mutex_cv_lock(mutex);
+ } else {
+ /*
+ * Lock the condition variable
+ * while removing the thread.
+ */
+ _SPINLOCK(&(*cond)->lock);
+
+ cond_queue_remove(*cond,
+ curthread);
+
+ /* Check for no more waiters: */
+ if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
+ (*cond)->c_mutex = NULL;
+
+ _SPINUNLOCK(&(*cond)->lock);
+
+ /* Lock the mutex: */
+ rval = _mutex_cv_lock(mutex);
+ }
+ }
+ }
+ break;
+
+ /* Trap invalid condition variable types: */
+ default:
+ /* Unlock the condition variable structure: */
+ _SPINUNLOCK(&(*cond)->lock);
+
+ /* Return an invalid argument error: */
+ rval = EINVAL;
+ break;
+ }
+
+ if ((interrupted != 0) && (curthread->continuation != NULL))
+ curthread->continuation((void *) curthread);
+ } while ((done == 0) && (rval == 0));
+
+ /* Return the completion status: */
+ return (rval);
+}
+
+int
+__pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
+{
+ int ret;
+
+ _thread_enter_cancellation_point();
+ ret = _pthread_cond_wait(cond, mutex);
+ _thread_leave_cancellation_point();
+ return (ret);
+}
+
+int
+_pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
+ const struct timespec *abstime)
+{
+ struct pthread *curthread = _get_curthread();
+ int rval = 0;
+ int done = 0;
+ int interrupted = 0;
+ int seqno;
+
+ if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 ||
+ abstime->tv_nsec >= 1000000000)
+ return (EINVAL);
+ /*
+ * If the condition variable is statically initialized, perform dynamic
+ * initialization.
+ */
+ if (*cond == NULL && (rval = _pthread_cond_init(cond, NULL)) != 0)
+ return (rval);
+
+ /*
+ * Enter a loop waiting for a condition signal or broadcast
+ * to wake up this thread. A loop is needed in case the waiting
+ * thread is interrupted by a signal to execute a signal handler.
+ * It is not (currently) possible to remain in the waiting queue
+ * while running a handler. Instead, the thread is interrupted
+ * and backed out of the waiting queue prior to executing the
+ * signal handler.
+ */
+ do {
+ /* Lock the condition variable structure: */
+ _SPINLOCK(&(*cond)->lock);
+
+ /*
+ * If the condvar was statically allocated, properly
+ * initialize the tail queue.
+ */
+ if (((*cond)->c_flags & COND_FLAGS_INITED) == 0) {
+ TAILQ_INIT(&(*cond)->c_queue);
+ (*cond)->c_flags |= COND_FLAGS_INITED;
+ }
+
+ /* Process according to condition variable type: */
+ switch ((*cond)->c_type) {
+ /* Fast condition variable: */
+ case COND_TYPE_FAST:
+ if ((mutex == NULL) || (((*cond)->c_mutex != NULL) &&
+ ((*cond)->c_mutex != *mutex))) {
+ /* Return invalid argument error: */
+ rval = EINVAL;
+
+ /* Unlock the condition variable structure: */
+ _SPINUNLOCK(&(*cond)->lock);
+ } else {
+ /* Set the wakeup time: */
+ curthread->wakeup_time.tv_sec =
+ abstime->tv_sec;
+ curthread->wakeup_time.tv_nsec =
+ abstime->tv_nsec;
+
+ /* Reset the timeout and interrupted flags: */
+ curthread->timeout = 0;
+ curthread->interrupted = 0;
+
+ /*
+ * Queue the running thread for the condition
+ * variable:
+ */
+ cond_queue_enq(*cond, curthread);
+
+ /* Remember the mutex and sequence number: */
+ (*cond)->c_mutex = *mutex;
+ seqno = (*cond)->c_seqno;
+
+ /* Unlock the mutex: */
+ if ((rval = _mutex_cv_unlock(mutex)) != 0) {
+ /*
+ * Cannot unlock the mutex, so remove
+ * the running thread from the condition
+ * variable queue:
+ */
+ cond_queue_remove(*cond, curthread);
+
+ /* Check for no more waiters: */
+ if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
+ (*cond)->c_mutex = NULL;
+
+ /* Unlock the condition variable structure: */
+ _SPINUNLOCK(&(*cond)->lock);
+ } else {
+ /*
+ * Schedule the next thread and unlock
+ * the condition variable structure:
+ */
+ _thread_kern_sched_state_unlock(PS_COND_WAIT,
+ &(*cond)->lock, __FILE__, __LINE__);
+
+ done = (seqno != (*cond)->c_seqno);
+
+ interrupted = curthread->interrupted;
+
+ /*
+ * Check if the wait was interrupted
+ * (canceled) or needs to be resumed
+ * after handling a signal.
+ */
+ if (interrupted != 0) {
+ /*
+ * Lock the mutex and ignore any
+ * errors. Note that even
+ * though this thread may have
+ * been canceled, POSIX requires
+ * that the mutex be reaquired
+ * prior to cancellation.
+ */
+ (void)_mutex_cv_lock(mutex);
+ } else {
+ /*
+ * Lock the condition variable
+ * while removing the thread.
+ */
+ _SPINLOCK(&(*cond)->lock);
+
+ cond_queue_remove(*cond,
+ curthread);
+
+ /* Check for no more waiters: */
+ if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
+ (*cond)->c_mutex = NULL;
+
+ _SPINUNLOCK(&(*cond)->lock);
+
+ /* Lock the mutex: */
+ rval = _mutex_cv_lock(mutex);
+
+ /*
+ * Return ETIMEDOUT if the wait
+ * timed out and there wasn't an
+ * error locking the mutex:
+ */
+ if ((curthread->timeout != 0)
+ && rval == 0)
+ rval = ETIMEDOUT;
+
+ }
+ }
+ }
+ break;
+
+ /* Trap invalid condition variable types: */
+ default:
+ /* Unlock the condition variable structure: */
+ _SPINUNLOCK(&(*cond)->lock);
+
+ /* Return an invalid argument error: */
+ rval = EINVAL;
+ break;
+ }
+
+ if ((interrupted != 0) && (curthread->continuation != NULL))
+ curthread->continuation((void *) curthread);
+ } while ((done == 0) && (rval == 0));
+
+ /* Return the completion status: */
+ return (rval);
+}
+
+int
+__pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
+ const struct timespec *abstime)
+{
+ int ret;
+
+ _thread_enter_cancellation_point();
+ ret = _pthread_cond_timedwait(cond, mutex, abstime);
+ _thread_enter_cancellation_point();
+ return (ret);
+}
+
+int
+_pthread_cond_signal(pthread_cond_t *cond)
+{
+ int rval = 0;
+ pthread_t pthread;
+
+ if (cond == NULL)
+ rval = EINVAL;
+ /*
+ * If the condition variable is statically initialized, perform dynamic
+ * initialization.
+ */
+ else if (*cond != NULL ||
+ (rval = _pthread_cond_init(cond, NULL)) == 0) {
+ /*
+ * Defer signals to protect the scheduling queues
+ * from access by the signal handler:
+ */
+ _thread_kern_sig_defer();
+
+ /* Lock the condition variable structure: */
+ _SPINLOCK(&(*cond)->lock);
+
+ /* Process according to condition variable type: */
+ switch ((*cond)->c_type) {
+ /* Fast condition variable: */
+ case COND_TYPE_FAST:
+ /* Increment the sequence number: */
+ (*cond)->c_seqno++;
+
+ if ((pthread = cond_queue_deq(*cond)) != NULL) {
+ /*
+ * Wake up the signaled thread:
+ */
+ PTHREAD_NEW_STATE(pthread, PS_RUNNING);
+ }
+
+ /* Check for no more waiters: */
+ if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
+ (*cond)->c_mutex = NULL;
+ break;
+
+ /* Trap invalid condition variable types: */
+ default:
+ /* Return an invalid argument error: */
+ rval = EINVAL;
+ break;
+ }
+
+ /* Unlock the condition variable structure: */
+ _SPINUNLOCK(&(*cond)->lock);
+
+ /*
+ * Undefer and handle pending signals, yielding if
+ * necessary:
+ */
+ _thread_kern_sig_undefer();
+ }
+
+ /* Return the completion status: */
+ return (rval);
+}
+
+int
+_pthread_cond_broadcast(pthread_cond_t *cond)
+{
+ int rval = 0;
+ pthread_t pthread;
+
+ if (cond == NULL)
+ rval = EINVAL;
+ /*
+ * If the condition variable is statically initialized, perform dynamic
+ * initialization.
+ */
+ else if (*cond != NULL ||
+ (rval = _pthread_cond_init(cond, NULL)) == 0) {
+ /*
+ * Defer signals to protect the scheduling queues
+ * from access by the signal handler:
+ */
+ _thread_kern_sig_defer();
+
+ /* Lock the condition variable structure: */
+ _SPINLOCK(&(*cond)->lock);
+
+ /* Process according to condition variable type: */
+ switch ((*cond)->c_type) {
+ /* Fast condition variable: */
+ case COND_TYPE_FAST:
+ /* Increment the sequence number: */
+ (*cond)->c_seqno++;
+
+ /*
+ * Enter a loop to bring all threads off the
+ * condition queue:
+ */
+ while ((pthread = cond_queue_deq(*cond)) != NULL) {
+ /*
+ * Wake up the signaled thread:
+ */
+ PTHREAD_NEW_STATE(pthread, PS_RUNNING);
+ }
+
+ /* There are no more waiting threads: */
+ (*cond)->c_mutex = NULL;
+ break;
+
+ /* Trap invalid condition variable types: */
+ default:
+ /* Return an invalid argument error: */
+ rval = EINVAL;
+ break;
+ }
+
+ /* Unlock the condition variable structure: */
+ _SPINUNLOCK(&(*cond)->lock);
+
+ /*
+ * Undefer and handle pending signals, yielding if
+ * necessary:
+ */
+ _thread_kern_sig_undefer();
+ }
+
+ /* Return the completion status: */
+ return (rval);
+}
+
+void
+_cond_wait_backout(pthread_t pthread)
+{
+ pthread_cond_t cond;
+
+ cond = pthread->data.cond;
+ if (cond != NULL) {
+ /*
+ * Defer signals to protect the scheduling queues
+ * from access by the signal handler:
+ */
+ _thread_kern_sig_defer();
+
+ /* Lock the condition variable structure: */
+ _SPINLOCK(&cond->lock);
+
+ /* Process according to condition variable type: */
+ switch (cond->c_type) {
+ /* Fast condition variable: */
+ case COND_TYPE_FAST:
+ cond_queue_remove(cond, pthread);
+
+ /* Check for no more waiters: */
+ if (TAILQ_FIRST(&cond->c_queue) == NULL)
+ cond->c_mutex = NULL;
+ break;
+
+ default:
+ break;
+ }
+
+ /* Unlock the condition variable structure: */
+ _SPINUNLOCK(&cond->lock);
+
+ /*
+ * Undefer and handle pending signals, yielding if
+ * necessary:
+ */
+ _thread_kern_sig_undefer();
+ }
+}
+
+/*
+ * Dequeue a waiting thread from the head of a condition queue in
+ * descending priority order.
+ */
+static inline pthread_t
+cond_queue_deq(pthread_cond_t cond)
+{
+ pthread_t pthread;
+
+ while ((pthread = TAILQ_FIRST(&cond->c_queue)) != NULL) {
+ TAILQ_REMOVE(&cond->c_queue, pthread, sqe);
+ pthread->flags &= ~PTHREAD_FLAGS_IN_CONDQ;
+ if ((pthread->timeout == 0) && (pthread->interrupted == 0))
+ /*
+ * Only exit the loop when we find a thread
+ * that hasn't timed out or been canceled;
+ * those threads are already running and don't
+ * need their run state changed.
+ */
+ break;
+ }
+
+ return(pthread);
+}
+
+/*
+ * Remove a waiting thread from a condition queue in descending priority
+ * order.
+ */
+static inline void
+cond_queue_remove(pthread_cond_t cond, pthread_t pthread)
+{
+ /*
+ * Because pthread_cond_timedwait() can timeout as well
+ * as be signaled by another thread, it is necessary to
+ * guard against removing the thread from the queue if
+ * it isn't in the queue.
+ */
+ if (pthread->flags & PTHREAD_FLAGS_IN_CONDQ) {
+ TAILQ_REMOVE(&cond->c_queue, pthread, sqe);
+ pthread->flags &= ~PTHREAD_FLAGS_IN_CONDQ;
+ }
+}
+
+/*
+ * Enqueue a waiting thread to a condition queue in descending priority
+ * order.
+ */
+static inline void
+cond_queue_enq(pthread_cond_t cond, pthread_t pthread)
+{
+ pthread_t tid = TAILQ_LAST(&cond->c_queue, cond_head);
+
+ PTHREAD_ASSERT_NOT_IN_SYNCQ(pthread);
+
+ /*
+ * For the common case of all threads having equal priority,
+ * we perform a quick check against the priority of the thread
+ * at the tail of the queue.
+ */
+ if ((tid == NULL) || (pthread->active_priority <= tid->active_priority))
+ TAILQ_INSERT_TAIL(&cond->c_queue, pthread, sqe);
+ else {
+ tid = TAILQ_FIRST(&cond->c_queue);
+ while (pthread->active_priority <= tid->active_priority)
+ tid = TAILQ_NEXT(tid, sqe);
+ TAILQ_INSERT_BEFORE(tid, pthread, sqe);
+ }
+ pthread->flags |= PTHREAD_FLAGS_IN_CONDQ;
+ pthread->data.cond = cond;
+}
diff --git a/lib/libc_r/uthread/uthread_condattr_destroy.c b/lib/libc_r/uthread/uthread_condattr_destroy.c
new file mode 100644
index 0000000..3a05487
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_condattr_destroy.c
@@ -0,0 +1,53 @@
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <errno.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_condattr_destroy, pthread_condattr_destroy);
+
+int
+_pthread_condattr_destroy(pthread_condattr_t *attr)
+{
+ int ret;
+ if (attr == NULL || *attr == NULL) {
+ ret = EINVAL;
+ } else {
+ free(*attr);
+ *attr = NULL;
+ ret = 0;
+ }
+ return(ret);
+}
diff --git a/lib/libc_r/uthread/uthread_condattr_init.c b/lib/libc_r/uthread/uthread_condattr_init.c
new file mode 100644
index 0000000..92ce709
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_condattr_init.c
@@ -0,0 +1,60 @@
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_condattr_init, pthread_condattr_init);
+
+static struct pthread_cond_attr default_condattr = PTHREAD_CONDATTR_DEFAULT;
+
+int
+_pthread_condattr_init(pthread_condattr_t *attr)
+{
+ int ret;
+ pthread_condattr_t pattr;
+
+ if ((pattr = (pthread_condattr_t)
+ malloc(sizeof(struct pthread_cond_attr))) == NULL) {
+ ret = ENOMEM;
+ } else {
+ memcpy(pattr, &default_condattr,
+ sizeof(struct pthread_cond_attr));
+ *attr = pattr;
+ ret = 0;
+ }
+ return(ret);
+}
diff --git a/lib/libc_r/uthread/uthread_connect.c b/lib/libc_r/uthread/uthread_connect.c
new file mode 100644
index 0000000..dfdcb21
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_connect.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(__connect, connect);
+
+int
+_connect(int fd, const struct sockaddr * name, socklen_t namelen)
+{
+ struct pthread *curthread = _get_curthread();
+ struct sockaddr tmpname;
+ int errnolen, ret, tmpnamelen;
+
+ if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) {
+ if ((ret = __sys_connect(fd, name, namelen)) < 0) {
+ if ((_thread_fd_getflags(fd) & O_NONBLOCK) == 0
+ && ((errno == EWOULDBLOCK) || (errno == EINPROGRESS)
+ || (errno == EALREADY) || (errno == EAGAIN))) {
+ curthread->data.fd.fd = fd;
+
+ /* Set the timeout: */
+ _thread_kern_set_timeout(NULL);
+ _thread_kern_sched_state(PS_FDW_WAIT, __FILE__, __LINE__);
+
+ tmpnamelen = sizeof(tmpname);
+ /* 0 now lets see if it really worked */
+ if (((ret = __sys_getpeername(fd, &tmpname, &tmpnamelen)) < 0) && (errno == ENOTCONN)) {
+
+ /*
+ * Get the error, this function
+ * should not fail
+ */
+ errnolen = sizeof(errno);
+ __sys_getsockopt(fd, SOL_SOCKET, SO_ERROR, &errno, &errnolen);
+ }
+ } else {
+ ret = -1;
+ }
+ }
+ _FD_UNLOCK(fd, FD_RDWR);
+ }
+ return (ret);
+}
+
+int
+__connect(int fd, const struct sockaddr * name, socklen_t namelen)
+{
+ int ret;
+
+ _thread_enter_cancellation_point();
+ ret = _connect(fd, name, namelen);
+ _thread_leave_cancellation_point();
+
+ return (ret);
+}
diff --git a/lib/libc_r/uthread/uthread_creat.c b/lib/libc_r/uthread/uthread_creat.c
new file mode 100644
index 0000000..92da971
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_creat.c
@@ -0,0 +1,48 @@
+/*
+ * 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$
+ */
+
+#include <fcntl.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(___creat, creat);
+
+int
+___creat(const char *path, mode_t mode)
+{
+ int ret;
+
+ _thread_enter_cancellation_point();
+ ret = __creat(path, mode);
+ _thread_leave_cancellation_point();
+
+ return ret;
+}
diff --git a/lib/libc_r/uthread/uthread_create.c b/lib/libc_r/uthread/uthread_create.c
new file mode 100644
index 0000000..356bc07
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_create.c
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <sys/time.h>
+#include <machine/reg.h>
+#include "namespace.h"
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "pthread_private.h"
+#include "libc_private.h"
+
+static u_int64_t next_uniqueid = 1;
+
+#define OFF(f) offsetof(struct pthread, f)
+int _thread_next_offset = OFF(tle.tqe_next);
+int _thread_uniqueid_offset = OFF(uniqueid);
+int _thread_state_offset = OFF(state);
+int _thread_name_offset = OFF(name);
+int _thread_ctx_offset = OFF(ctx);
+#undef OFF
+
+int _thread_PS_RUNNING_value = PS_RUNNING;
+int _thread_PS_DEAD_value = PS_DEAD;
+
+__weak_reference(_pthread_create, pthread_create);
+
+int
+_pthread_create(pthread_t *thread, const pthread_attr_t *attr,
+ void *(*start_routine) (void *), void *arg)
+{
+ struct pthread *curthread = _get_curthread();
+ struct itimerval itimer;
+ int f_gc = 0;
+ int ret = 0;
+ pthread_t gc_thread;
+ pthread_t new_thread;
+ pthread_attr_t pattr;
+ void *stack;
+#if !defined(__ia64__)
+ u_long stackp;
+#endif
+
+ if (thread == NULL)
+ return(EINVAL);
+
+ /*
+ * Locking functions in libc are required when there are
+ * threads other than the initial thread.
+ */
+ __isthreaded = 1;
+
+ /* Allocate memory for the thread structure: */
+ if ((new_thread = (pthread_t) malloc(sizeof(struct pthread))) == NULL) {
+ /* Insufficient memory to create a thread: */
+ ret = EAGAIN;
+ } else {
+ /* Check if default thread attributes are required: */
+ if (attr == NULL || *attr == NULL) {
+ /* Use the default thread attributes: */
+ pattr = &_pthread_attr_default;
+ } else {
+ pattr = *attr;
+ }
+ /* Check if a stack was specified in the thread attributes: */
+ if ((stack = pattr->stackaddr_attr) != NULL) {
+ }
+ /* Allocate a stack: */
+ else {
+ stack = _thread_stack_alloc(pattr->stacksize_attr,
+ pattr->guardsize_attr);
+ if (stack == NULL) {
+ ret = EAGAIN;
+ free(new_thread);
+ }
+ }
+
+ /* Check for errors: */
+ if (ret != 0) {
+ } else {
+ /* Initialise the thread structure: */
+ memset(new_thread, 0, sizeof(struct pthread));
+ new_thread->slice_usec = -1;
+ new_thread->stack = stack;
+ new_thread->start_routine = start_routine;
+ new_thread->arg = arg;
+
+ new_thread->cancelflags = PTHREAD_CANCEL_ENABLE |
+ PTHREAD_CANCEL_DEFERRED;
+
+ /*
+ * Write a magic value to the thread structure
+ * to help identify valid ones:
+ */
+ new_thread->magic = PTHREAD_MAGIC;
+
+ /* Initialise the thread for signals: */
+ new_thread->sigmask = curthread->sigmask;
+ new_thread->sigmask_seqno = 0;
+
+ /* Initialize the signal frame: */
+ new_thread->curframe = NULL;
+
+ /* Initialise the jump buffer: */
+ _setjmp(new_thread->ctx.jb);
+
+ /*
+ * Set up new stack frame so that it looks like it
+ * returned from a longjmp() to the beginning of
+ * _thread_start().
+ */
+ SET_RETURN_ADDR_JB(new_thread->ctx.jb, _thread_start);
+
+#if !defined(__ia64__)
+ stackp = (long)new_thread->stack + pattr->stacksize_attr - sizeof(double);
+#if defined(__amd64__)
+ stackp &= ~0xFUL;
+#endif
+ /* The stack starts high and builds down: */
+ SET_STACK_JB(new_thread->ctx.jb, stackp);
+#else
+ SET_STACK_JB(new_thread->ctx.jb,
+ (long)new_thread->stack, pattr->stacksize_attr);
+#endif
+
+ /* Copy the thread attributes: */
+ memcpy(&new_thread->attr, pattr, sizeof(struct pthread_attr));
+
+ /*
+ * Check if this thread is to inherit the scheduling
+ * attributes from its parent:
+ */
+ if (new_thread->attr.flags & PTHREAD_INHERIT_SCHED) {
+ /* Copy the scheduling attributes: */
+ new_thread->base_priority =
+ curthread->base_priority &
+ ~PTHREAD_SIGNAL_PRIORITY;
+ new_thread->attr.prio =
+ curthread->base_priority &
+ ~PTHREAD_SIGNAL_PRIORITY;
+ new_thread->attr.sched_policy =
+ curthread->attr.sched_policy;
+ } else {
+ /*
+ * Use just the thread priority, leaving the
+ * other scheduling attributes as their
+ * default values:
+ */
+ new_thread->base_priority =
+ new_thread->attr.prio;
+ }
+ new_thread->active_priority = new_thread->base_priority;
+ new_thread->inherited_priority = 0;
+
+ /* Initialize joiner to NULL (no joiner): */
+ new_thread->joiner = NULL;
+
+ /* Initialize the mutex queue: */
+ TAILQ_INIT(&new_thread->mutexq);
+
+ /* Initialise hooks in the thread structure: */
+ new_thread->specific = NULL;
+ new_thread->cleanup = NULL;
+ new_thread->flags = 0;
+ new_thread->poll_data.nfds = 0;
+ new_thread->poll_data.fds = NULL;
+ new_thread->continuation = NULL;
+
+ /*
+ * Defer signals to protect the scheduling queues
+ * from access by the signal handler:
+ */
+ _thread_kern_sig_defer();
+
+ /*
+ * Initialise the unique id which GDB uses to
+ * track threads.
+ */
+ new_thread->uniqueid = next_uniqueid++;
+
+ /*
+ * Check if the garbage collector thread
+ * needs to be started.
+ */
+ f_gc = (TAILQ_FIRST(&_thread_list) == _thread_initial);
+
+ /* Add the thread to the linked list of all threads: */
+ TAILQ_INSERT_HEAD(&_thread_list, new_thread, tle);
+
+ if (pattr->suspend == PTHREAD_CREATE_SUSPENDED) {
+ new_thread->flags |= PTHREAD_FLAGS_SUSPENDED;
+ new_thread->state = PS_SUSPENDED;
+ } else {
+ new_thread->state = PS_RUNNING;
+ PTHREAD_PRIOQ_INSERT_TAIL(new_thread);
+ }
+
+ /*
+ * Undefer and handle pending signals, yielding
+ * if necessary.
+ */
+ _thread_kern_sig_undefer();
+
+ /* Return a pointer to the thread structure: */
+ (*thread) = new_thread;
+
+ if (f_gc != 0) {
+ /* Install the scheduling timer: */
+ itimer.it_interval.tv_sec = 0;
+ itimer.it_interval.tv_usec = _clock_res_usec;
+ itimer.it_value = itimer.it_interval;
+ if (setitimer(_ITIMER_SCHED_TIMER, &itimer,
+ NULL) != 0)
+ PANIC("Cannot set interval timer");
+ }
+
+ /* Schedule the new user thread: */
+ _thread_kern_sched(NULL);
+
+ /*
+ * Start a garbage collector thread
+ * if necessary.
+ */
+ if (f_gc && _pthread_create(&gc_thread, NULL,
+ _thread_gc, NULL) != 0)
+ PANIC("Can't create gc thread");
+
+ }
+ }
+
+ /* Return the status: */
+ return (ret);
+}
+
+void
+_thread_start(void)
+{
+ struct pthread *curthread = _get_curthread();
+
+ /* We just left the scheduler via longjmp: */
+ _thread_kern_in_sched = 0;
+
+ /* Run the current thread's start routine with argument: */
+ _pthread_exit(curthread->start_routine(curthread->arg));
+
+ /* This point should never be reached. */
+ PANIC("Thread has resumed after exit");
+}
diff --git a/lib/libc_r/uthread/uthread_detach.c b/lib/libc_r/uthread/uthread_detach.c
new file mode 100644
index 0000000..298fdb4
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_detach.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_detach, pthread_detach);
+
+int
+_pthread_detach(pthread_t pthread)
+{
+ int rval = 0;
+
+ /* Check for invalid calling parameters: */
+ if (pthread == NULL || pthread->magic != PTHREAD_MAGIC)
+ /* Return an invalid argument error: */
+ rval = EINVAL;
+
+ /* Check if the thread has not been detached: */
+ else if ((pthread->attr.flags & PTHREAD_DETACHED) == 0) {
+ /* Flag the thread as detached: */
+ pthread->attr.flags |= PTHREAD_DETACHED;
+
+ /*
+ * Defer signals to protect the scheduling queues from
+ * access by the signal handler:
+ */
+ _thread_kern_sig_defer();
+
+ /* Check if there is a joiner: */
+ if (pthread->joiner != NULL) {
+ struct pthread *joiner = pthread->joiner;
+
+ /* Make the thread runnable: */
+ PTHREAD_NEW_STATE(joiner, PS_RUNNING);
+
+ /* Set the return value for the woken thread: */
+ joiner->join_status.error = ESRCH;
+ joiner->join_status.ret = NULL;
+ joiner->join_status.thread = NULL;
+
+ /*
+ * Disconnect the joiner from the thread being detached:
+ */
+ pthread->joiner = NULL;
+ }
+
+ /*
+ * Undefer and handle pending signals, yielding if a
+ * scheduling signal occurred while in the critical region.
+ */
+ _thread_kern_sig_undefer();
+ } else
+ /* Return an error: */
+ rval = EINVAL;
+
+ /* Return the completion status: */
+ return (rval);
+}
diff --git a/lib/libc_r/uthread/uthread_dup.c b/lib/libc_r/uthread/uthread_dup.c
new file mode 100644
index 0000000..aaae691
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_dup.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <unistd.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_dup, dup);
+
+int
+_dup(int fd)
+{
+ int ret;
+
+ /* Lock the file descriptor: */
+ if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) {
+ /* Perform the 'dup' syscall: */
+ if ((ret = __sys_dup(fd)) < 0) {
+ }
+ /* Initialise the file descriptor table entry: */
+ else if (_thread_fd_table_init(ret) != 0) {
+ /* Quietly close the file: */
+ __sys_close(ret);
+
+ /* Reset the file descriptor: */
+ ret = -1;
+ } else {
+ /*
+ * Save the file open flags so that they can be
+ * checked later:
+ */
+ _thread_fd_setflags(ret, _thread_fd_getflags(fd));
+ }
+
+ /* Unlock the file descriptor: */
+ _FD_UNLOCK(fd, FD_RDWR);
+ }
+ /* Return the completion status: */
+ return (ret);
+}
diff --git a/lib/libc_r/uthread/uthread_dup2.c b/lib/libc_r/uthread/uthread_dup2.c
new file mode 100644
index 0000000..739a7ad
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_dup2.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <unistd.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_dup2, dup2);
+
+int
+_dup2(int fd, int newfd)
+{
+ int ret;
+ int newfd_opened;
+
+ /* Check if the file descriptor is out of range: */
+ if (newfd < 0 || newfd >= _thread_dtablesize ||
+ newfd == _thread_kern_pipe[0] || newfd == _thread_kern_pipe[1]) {
+ /* Return a bad file descriptor error: */
+ errno = EBADF;
+ ret = -1;
+ }
+
+ /* Lock the file descriptor: */
+ else if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) {
+ /* Lock the file descriptor: */
+ if (!(newfd_opened = (_thread_fd_table[newfd] != NULL)) ||
+ (ret = _FD_LOCK(newfd, FD_RDWR, NULL)) == 0) {
+ /* Perform the 'dup2' syscall: */
+ ret = __sys_dup2(fd, newfd);
+ if (ret >= 0) {
+ /*
+ * If we are duplicating one of the standard
+ * file descriptors, update its flags in the
+ * table of pthread stdio descriptor flags.
+ */
+ if (ret < 3) {
+ _pthread_stdio_flags[ret] =
+ _thread_fd_table[fd]->flags;
+ }
+ /* Initialise the file descriptor table entry */
+ if (_thread_fd_table_init(ret) != 0) {
+ /* Quietly close the file: */
+ __sys_close(ret);
+
+ /* Reset the file descriptor: */
+ ret = -1;
+ } else {
+ /*
+ * Save the file open flags so that
+ * they can be checked later:
+ */
+ _thread_fd_setflags(ret,
+ _thread_fd_getflags(fd));
+ }
+ }
+
+ /* Unlock the file descriptor: */
+ if (newfd_opened)
+ _FD_UNLOCK(newfd, FD_RDWR);
+ }
+ /* Unlock the file descriptor: */
+ _FD_UNLOCK(fd, FD_RDWR);
+ }
+ /* Return the completion status: */
+ return (ret);
+}
diff --git a/lib/libc_r/uthread/uthread_equal.c b/lib/libc_r/uthread/uthread_equal.c
new file mode 100644
index 0000000..0dfb63d
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_equal.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 "pthread_private.h"
+
+__weak_reference(_pthread_equal, pthread_equal);
+
+int
+_pthread_equal(pthread_t t1, pthread_t t2)
+{
+ /* Compare the two thread pointers: */
+ return (t1 == t2);
+}
diff --git a/lib/libc_r/uthread/uthread_execve.c b/lib/libc_r/uthread/uthread_execve.c
new file mode 100644
index 0000000..c0aa31c
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_execve.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_execve, execve);
+
+int
+_execve(const char *name, char *const * argv, char *const * envp)
+{
+ struct pthread *curthread = _get_curthread();
+ int flags;
+ int i;
+ int ret;
+ struct sigaction act;
+ struct sigaction oact;
+ struct itimerval itimer;
+
+ /* Disable the interval timer: */
+ itimer.it_interval.tv_sec = 0;
+ itimer.it_interval.tv_usec = 0;
+ itimer.it_value.tv_sec = 0;
+ itimer.it_value.tv_usec = 0;
+ setitimer(_ITIMER_SCHED_TIMER, &itimer, NULL);
+
+ /* Close the pthread kernel pipe: */
+ __sys_close(_thread_kern_pipe[0]);
+ __sys_close(_thread_kern_pipe[1]);
+
+ /*
+ * Enter a loop to set all file descriptors to blocking
+ * if they were not created as non-blocking:
+ */
+ for (i = 0; i < _thread_dtablesize; i++) {
+ /* Check if this file descriptor is in use: */
+ if (_thread_fd_table[i] != NULL &&
+ (_thread_fd_getflags(i) & O_NONBLOCK) == 0) {
+ /* Skip if the close-on-exec flag is set */
+ flags = __sys_fcntl(i, F_GETFD, NULL);
+ if ((flags & FD_CLOEXEC) != 0)
+ continue; /* don't bother, no point */
+ /* Get the current flags: */
+ flags = __sys_fcntl(i, F_GETFL, NULL);
+ /* Clear the nonblocking file descriptor flag: */
+ __sys_fcntl(i, F_SETFL, flags & ~O_NONBLOCK);
+ }
+ }
+
+ /* Enter a loop to adopt the signal actions for the running thread: */
+ for (i = 1; i < NSIG; i++) {
+ /* Check for signals which cannot be caught: */
+ if (i == SIGKILL || i == SIGSTOP) {
+ /* Don't do anything with these signals. */
+ } else {
+ /* Check if ignoring this signal: */
+ if (_thread_sigact[i - 1].sa_handler == SIG_IGN) {
+ /* Continue to ignore this signal: */
+ act.sa_handler = SIG_IGN;
+ } else {
+ /* Use the default handler for this signal: */
+ act.sa_handler = SIG_DFL;
+ }
+
+ /* Copy the mask and flags for this signal: */
+ act.sa_mask = _thread_sigact[i - 1].sa_mask;
+ act.sa_flags = _thread_sigact[i - 1].sa_flags;
+
+ /* Change the signal action for the process: */
+ __sys_sigaction(i, &act, &oact);
+ }
+ }
+
+ /* Set the signal mask: */
+ __sys_sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL);
+
+ /* Execute the process: */
+ ret = __sys_execve(name, argv, envp);
+
+ /* Return the completion status: */
+ return (ret);
+}
diff --git a/lib/libc_r/uthread/uthread_exit.c b/lib/libc_r/uthread/uthread_exit.c
new file mode 100644
index 0000000..44661e4
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_exit.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "namespace.h"
+#include <pthread.h>
+#include "un-namespace.h"
+#include "pthread_private.h"
+
+__weak_reference(_pthread_exit, pthread_exit);
+
+void
+_exit(int status)
+{
+ int flags;
+ int i;
+ struct itimerval itimer;
+
+ /* Disable the interval timer: */
+ itimer.it_interval.tv_sec = 0;
+ itimer.it_interval.tv_usec = 0;
+ itimer.it_value.tv_sec = 0;
+ itimer.it_value.tv_usec = 0;
+ setitimer(_ITIMER_SCHED_TIMER, &itimer, NULL);
+
+ /* Close the pthread kernel pipe: */
+ __sys_close(_thread_kern_pipe[0]);
+ __sys_close(_thread_kern_pipe[1]);
+
+ /*
+ * Enter a loop to set all file descriptors to blocking
+ * if they were not created as non-blocking:
+ */
+ for (i = 0; i < _thread_dtablesize; i++) {
+ /* Check if this file descriptor is in use: */
+ if (_thread_fd_table[i] != NULL &&
+ (_thread_fd_getflags(i) & O_NONBLOCK) == 0) {
+ /* Get the current flags: */
+ flags = __sys_fcntl(i, F_GETFL, NULL);
+ /* Clear the nonblocking file descriptor flag: */
+ __sys_fcntl(i, F_SETFL, flags & ~O_NONBLOCK);
+ }
+ }
+
+ /* Call the _exit syscall: */
+ __sys_exit(status);
+}
+
+void
+_thread_exit(char *fname, int lineno, char *string)
+{
+ char s[256];
+
+ /* Prepare an error message string: */
+ snprintf(s, sizeof(s),
+ "Fatal error '%s' at line %d in file %s (errno = %d)\n",
+ string, lineno, fname, errno);
+
+ /* Write the string to the standard error file descriptor: */
+ __sys_write(2, s, strlen(s));
+
+ /* Force this process to exit: */
+ /* XXX - Do we want abort to be conditional on _PTHREADS_INVARIANTS? */
+#if defined(_PTHREADS_INVARIANTS)
+ abort();
+#else
+ __sys_exit(1);
+#endif
+}
+
+/*
+ * Only called when a thread is cancelled. It may be more useful
+ * to call it from pthread_exit() if other ways of asynchronous or
+ * abnormal thread termination can be found.
+ */
+void
+_thread_exit_cleanup(void)
+{
+ struct pthread *curthread = _get_curthread();
+
+ /*
+ * POSIX states that cancellation/termination of a thread should
+ * not release any visible resources (such as mutexes) and that
+ * it is the applications responsibility. Resources that are
+ * internal to the threads library, including file and fd locks,
+ * are not visible to the application and need to be released.
+ */
+ /* Unlock all owned fd locks: */
+ _thread_fd_unlock_owned(curthread);
+
+ /* Unlock all private mutexes: */
+ _mutex_unlock_private(curthread);
+
+ /*
+ * This still isn't quite correct because we don't account
+ * for held spinlocks (see libc/stdlib/malloc.c).
+ */
+}
+
+void
+_pthread_exit(void *status)
+{
+ struct pthread *curthread = _get_curthread();
+ pthread_t pthread;
+
+ /* Check if this thread is already in the process of exiting: */
+ if ((curthread->flags & PTHREAD_EXITING) != 0) {
+ char msg[128];
+ snprintf(msg, sizeof(msg), "Thread %p has called pthread_exit() from a destructor. POSIX 1003.1 1996 s16.2.5.2 does not allow this!",curthread);
+ PANIC(msg);
+ }
+
+ /* Flag this thread as exiting: */
+ curthread->flags |= PTHREAD_EXITING;
+
+ /* Save the return value: */
+ curthread->ret = status;
+
+ while (curthread->cleanup != NULL) {
+ pthread_cleanup_pop(1);
+ }
+ if (curthread->attr.cleanup_attr != NULL) {
+ curthread->attr.cleanup_attr(curthread->attr.arg_attr);
+ }
+ /* Check if there is thread specific data: */
+ if (curthread->specific != NULL) {
+ /* Run the thread-specific data destructors: */
+ _thread_cleanupspecific();
+ }
+
+ /* Free thread-specific poll_data structure, if allocated: */
+ if (curthread->poll_data.fds != NULL) {
+ free(curthread->poll_data.fds);
+ curthread->poll_data.fds = NULL;
+ }
+
+ /*
+ * Lock the garbage collector mutex to ensure that the garbage
+ * collector is not using the dead thread list.
+ */
+ if (_pthread_mutex_lock(&_gc_mutex) != 0)
+ PANIC("Cannot lock gc mutex");
+
+ /* Add this thread to the list of dead threads. */
+ TAILQ_INSERT_HEAD(&_dead_list, curthread, dle);
+
+ /*
+ * Signal the garbage collector thread that there is something
+ * to clean up.
+ */
+ if (_pthread_cond_signal(&_gc_cond) != 0)
+ PANIC("Cannot signal gc cond");
+
+ /*
+ * Avoid a race condition where a scheduling signal can occur
+ * causing the garbage collector thread to run. If this happens,
+ * the current thread can be cleaned out from under us.
+ */
+ _thread_kern_sig_defer();
+
+ /* Unlock the garbage collector mutex: */
+ if (_pthread_mutex_unlock(&_gc_mutex) != 0)
+ PANIC("Cannot unlock gc mutex");
+
+ /* Check if there is a thread joining this one: */
+ if (curthread->joiner != NULL) {
+ pthread = curthread->joiner;
+ curthread->joiner = NULL;
+
+ /* Make the joining thread runnable: */
+ PTHREAD_NEW_STATE(pthread, PS_RUNNING);
+
+ /* Set the return value for the joining thread: */
+ pthread->join_status.ret = curthread->ret;
+ pthread->join_status.error = 0;
+ pthread->join_status.thread = NULL;
+
+ /* Make this thread collectable by the garbage collector. */
+ PTHREAD_ASSERT(((curthread->attr.flags & PTHREAD_DETACHED) ==
+ 0), "Cannot join a detached thread");
+ curthread->attr.flags |= PTHREAD_DETACHED;
+ }
+
+ /* Remove this thread from the thread list: */
+ TAILQ_REMOVE(&_thread_list, curthread, tle);
+
+ /* This thread will never be re-scheduled. */
+ _thread_kern_sched_state(PS_DEAD, __FILE__, __LINE__);
+
+ /* This point should not be reached. */
+ PANIC("Dead thread has resumed");
+}
diff --git a/lib/libc_r/uthread/uthread_fchflags.c b/lib/libc_r/uthread/uthread_fchflags.c
new file mode 100644
index 0000000..cd076e2
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_fchflags.c
@@ -0,0 +1,24 @@
+/*
+ * David Leonard <d@openbsd.org>, 1999. Public Domain.
+ *
+ * $OpenBSD: uthread_fchflags.c,v 1.1 1999/01/08 05:42:18 d Exp $
+ * $FreeBSD$
+ */
+
+#include <sys/stat.h>
+#include <unistd.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_fchflags, fchflags);
+int
+_fchflags(int fd, u_long flags)
+{
+ int ret;
+
+ if ((ret = _FD_LOCK(fd, FD_WRITE, NULL)) == 0) {
+ ret = __sys_fchflags(fd, flags);
+ _FD_UNLOCK(fd, FD_WRITE);
+ }
+ return (ret);
+}
diff --git a/lib/libc_r/uthread/uthread_fchmod.c b/lib/libc_r/uthread/uthread_fchmod.c
new file mode 100644
index 0000000..05dea24
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_fchmod.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_fchmod, fchmod);
+
+int
+_fchmod(int fd, mode_t mode)
+{
+ int ret;
+
+ if ((ret = _FD_LOCK(fd, FD_WRITE, NULL)) == 0) {
+ ret = __sys_fchmod(fd, mode);
+ _FD_UNLOCK(fd, FD_WRITE);
+ }
+ return (ret);
+}
diff --git a/lib/libc_r/uthread/uthread_fchown.c b/lib/libc_r/uthread/uthread_fchown.c
new file mode 100644
index 0000000..5b27bcb
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_fchown.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <unistd.h>
+#include <dirent.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_fchown, fchown);
+
+int
+_fchown(int fd, uid_t owner, gid_t group)
+{
+ int ret;
+
+ if ((ret = _FD_LOCK(fd, FD_WRITE, NULL)) == 0) {
+ ret = __sys_fchown(fd, owner, group);
+ _FD_UNLOCK(fd, FD_WRITE);
+ }
+ return (ret);
+}
diff --git a/lib/libc_r/uthread/uthread_fcntl.c b/lib/libc_r/uthread/uthread_fcntl.c
new file mode 100644
index 0000000..a5b6405
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_fcntl.c
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <stdarg.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(__fcntl, fcntl);
+
+int
+_fcntl(int fd, int cmd,...)
+{
+ int flags = 0;
+ int nonblock;
+ int oldfd;
+ int ret;
+ va_list ap;
+
+ /* Lock the file descriptor: */
+ if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) {
+ /* Initialise the variable argument list: */
+ va_start(ap, cmd);
+
+ /* Process according to file control command type: */
+ switch (cmd) {
+ /* Duplicate a file descriptor: */
+ case F_DUPFD:
+ /*
+ * Get the file descriptor that the caller wants to
+ * use:
+ */
+ oldfd = va_arg(ap, int);
+
+ /* Initialise the file descriptor table entry: */
+ if ((ret = __sys_fcntl(fd, cmd, oldfd)) < 0) {
+ }
+ /* Initialise the file descriptor table entry: */
+ else if (_thread_fd_table_init(ret) != 0) {
+ /* Quietly close the file: */
+ __sys_close(ret);
+
+ /* Reset the file descriptor: */
+ ret = -1;
+ } else {
+ /*
+ * Save the file open flags so that they can
+ * be checked later:
+ */
+ _thread_fd_setflags(ret,
+ _thread_fd_getflags(fd));
+ }
+ break;
+ case F_SETFD:
+ flags = va_arg(ap, int);
+ ret = __sys_fcntl(fd, cmd, flags);
+ break;
+ case F_GETFD:
+ ret = __sys_fcntl(fd, cmd, 0);
+ break;
+ case F_GETFL:
+ ret = _thread_fd_getflags(fd);
+ break;
+ case F_SETFL:
+ /*
+ * Get the file descriptor flags passed by the
+ * caller:
+ */
+ flags = va_arg(ap, int);
+
+ /*
+ * Check if the user wants a non-blocking file
+ * descriptor:
+ */
+ nonblock = flags & O_NONBLOCK;
+
+ /* Set the file descriptor flags: */
+ if ((ret = __sys_fcntl(fd, cmd, flags | O_NONBLOCK)) != 0) {
+
+ /* Get the flags so that we behave like the kernel: */
+ } else if ((flags = __sys_fcntl(fd,
+ F_GETFL, 0)) == -1) {
+ /* Error getting flags: */
+ ret = -1;
+
+ /*
+ * Check if the file descriptor is non-blocking
+ * with respect to the user:
+ */
+ } else if (nonblock)
+ /* A non-blocking descriptor: */
+ _thread_fd_setflags(fd, flags | O_NONBLOCK);
+ else
+ /* Save the flags: */
+ _thread_fd_setflags(fd, flags & ~O_NONBLOCK);
+ break;
+ default:
+ /* Might want to make va_arg use a union */
+ ret = __sys_fcntl(fd, cmd, va_arg(ap, void *));
+ break;
+ }
+
+ /* Free variable arguments: */
+ va_end(ap);
+
+ /* Unlock the file descriptor: */
+ _FD_UNLOCK(fd, FD_RDWR);
+ }
+ /* Return the completion status: */
+ return (ret);
+}
+
+int
+__fcntl(int fd, int cmd,...)
+{
+ int ret;
+ va_list ap;
+
+ _thread_enter_cancellation_point();
+
+ va_start(ap, cmd);
+ switch (cmd) {
+ case F_DUPFD:
+ case F_SETFD:
+ case F_SETFL:
+ ret = _fcntl(fd, cmd, va_arg(ap, int));
+ break;
+ case F_GETFD:
+ case F_GETFL:
+ ret = _fcntl(fd, cmd);
+ break;
+ default:
+ ret = _fcntl(fd, cmd, va_arg(ap, void *));
+ }
+ va_end(ap);
+
+ _thread_leave_cancellation_point();
+
+ return ret;
+}
diff --git a/lib/libc_r/uthread/uthread_fd.c b/lib/libc_r/uthread/uthread_fd.c
new file mode 100644
index 0000000..7b8bb71
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_fd.c
@@ -0,0 +1,1057 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ */
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+#define FDQ_INSERT(q,p) \
+do { \
+ TAILQ_INSERT_TAIL(q,p,qe); \
+ p->flags |= PTHREAD_FLAGS_IN_FDQ; \
+} while (0)
+
+#define FDQ_REMOVE(q,p) \
+do { \
+ if ((p->flags & PTHREAD_FLAGS_IN_FDQ) != 0) { \
+ TAILQ_REMOVE(q,p,qe); \
+ p->flags &= ~PTHREAD_FLAGS_IN_FDQ; \
+ } \
+} while (0)
+
+
+/* Static variables: */
+static spinlock_t fd_table_lock = _SPINLOCK_INITIALIZER;
+
+/* Prototypes: */
+#ifdef _FDLOCKS_ENABLED
+static inline pthread_t fd_next_reader(int fd);
+static inline pthread_t fd_next_writer(int fd);
+#endif
+
+
+/*
+ * This function *must* return -1 and set the thread specific errno
+ * as a system call. This is because the error return from this
+ * function is propagated directly back from thread-wrapped system
+ * calls.
+ */
+
+int
+_thread_fd_table_init(int fd)
+{
+ int ret = 0;
+ struct fd_table_entry *entry;
+ int saved_errno;
+
+ if (_thread_initial == NULL)
+ _thread_init();
+
+ /* Check if the file descriptor is out of range: */
+ if (fd < 0 || fd >= _thread_dtablesize) {
+ /* Return a bad file descriptor error: */
+ errno = EBADF;
+ ret = -1;
+ }
+
+ /*
+ * Check if memory has already been allocated for this file
+ * descriptor:
+ */
+ else if (_thread_fd_table[fd] != NULL) {
+ /* Memory has already been allocated. */
+
+ /* Allocate memory for the file descriptor table entry: */
+ } else if ((entry = (struct fd_table_entry *)
+ malloc(sizeof(struct fd_table_entry))) == NULL) {
+ /* Return an insufficient memory error: */
+ errno = ENOMEM;
+ ret = -1;
+ } else {
+ /* Initialise the file locks: */
+ memset(&entry->lock, 0, sizeof(entry->lock));
+ entry->r_owner = NULL;
+ entry->w_owner = NULL;
+ entry->r_fname = NULL;
+ entry->w_fname = NULL;
+ entry->r_lineno = 0;
+ entry->w_lineno = 0;
+ entry->r_lockcount = 0;
+ entry->w_lockcount = 0;
+
+ /* Initialise the read/write queues: */
+ TAILQ_INIT(&entry->r_queue);
+ TAILQ_INIT(&entry->w_queue);
+
+ /* Get the flags for the file: */
+ if (((fd >= 3) || (_pthread_stdio_flags[fd] == -1)) &&
+ (entry->flags = __sys_fcntl(fd, F_GETFL, 0)) == -1) {
+ ret = -1;
+ }
+ else {
+ /* Check if a stdio descriptor: */
+ if ((fd < 3) && (_pthread_stdio_flags[fd] != -1))
+ /*
+ * Use the stdio flags read by
+ * _pthread_init() to avoid
+ * mistaking the non-blocking
+ * flag that, when set on one
+ * stdio fd, is set on all stdio
+ * fds.
+ */
+ entry->flags = _pthread_stdio_flags[fd];
+
+ /*
+ * Make the file descriptor non-blocking.
+ * This might fail if the device driver does
+ * not support non-blocking calls, or if the
+ * driver is naturally non-blocking.
+ */
+ saved_errno = errno;
+ __sys_fcntl(fd, F_SETFL,
+ entry->flags | O_NONBLOCK);
+ errno = saved_errno;
+
+ /* Lock the file descriptor table: */
+ _SPINLOCK(&fd_table_lock);
+
+ /*
+ * Check if another thread allocated the
+ * file descriptor entry while this thread
+ * was doing the same thing. The table wasn't
+ * kept locked during this operation because
+ * it has the potential to recurse.
+ */
+ if (_thread_fd_table[fd] == NULL) {
+ /* This thread wins: */
+ _thread_fd_table[fd] = entry;
+ entry = NULL;
+ }
+
+ /* Unlock the file descriptor table: */
+ _SPINUNLOCK(&fd_table_lock);
+ }
+
+ /*
+ * Check if another thread initialised the table entry
+ * before this one could:
+ */
+ if (entry != NULL)
+ /*
+ * Throw away the table entry that this thread
+ * prepared. The other thread wins.
+ */
+ free(entry);
+ }
+
+ /* Return the completion status: */
+ return (ret);
+}
+
+int
+_thread_fd_getflags(int fd)
+{
+ if (_thread_fd_table[fd] != NULL)
+ return (_thread_fd_table[fd]->flags);
+ else
+ return (0);
+}
+
+void
+_thread_fd_setflags(int fd, int flags)
+{
+ if (_thread_fd_table[fd] != NULL)
+ _thread_fd_table[fd]->flags = flags;
+}
+
+#ifdef _FDLOCKS_ENABLED
+void
+_thread_fd_unlock(int fd, int lock_type)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ /*
+ * Check that the file descriptor table is initialised for this
+ * entry:
+ */
+ if ((ret = _thread_fd_table_init(fd)) == 0) {
+ /*
+ * Defer signals to protect the scheduling queues from
+ * access by the signal handler:
+ */
+ _thread_kern_sig_defer();
+
+ /*
+ * Lock the file descriptor table entry to prevent
+ * other threads for clashing with the current
+ * thread's accesses:
+ */
+ _SPINLOCK(&_thread_fd_table[fd]->lock);
+
+ /* Check if the running thread owns the read lock: */
+ if (_thread_fd_table[fd]->r_owner == curthread) {
+ /* Check the file descriptor and lock types: */
+ if (lock_type == FD_READ || lock_type == FD_RDWR) {
+ /*
+ * Decrement the read lock count for the
+ * running thread:
+ */
+ _thread_fd_table[fd]->r_lockcount--;
+
+ /*
+ * Check if the running thread still has read
+ * locks on this file descriptor:
+ */
+ if (_thread_fd_table[fd]->r_lockcount != 0) {
+ }
+ /*
+ * Get the next thread in the queue for a
+ * read lock on this file descriptor:
+ */
+ else if ((_thread_fd_table[fd]->r_owner = fd_next_reader(fd)) == NULL) {
+ } else {
+ /* Remove this thread from the queue: */
+ FDQ_REMOVE(&_thread_fd_table[fd]->r_queue,
+ _thread_fd_table[fd]->r_owner);
+
+ /*
+ * Set the state of the new owner of
+ * the thread to running:
+ */
+ PTHREAD_NEW_STATE(_thread_fd_table[fd]->r_owner,PS_RUNNING);
+
+ /*
+ * Reset the number of read locks.
+ * This will be incremented by the
+ * new owner of the lock when it sees
+ * that it has the lock.
+ */
+ _thread_fd_table[fd]->r_lockcount = 0;
+ }
+ }
+ }
+ /* Check if the running thread owns the write lock: */
+ if (_thread_fd_table[fd]->w_owner == curthread) {
+ /* Check the file descriptor and lock types: */
+ if (lock_type == FD_WRITE || lock_type == FD_RDWR) {
+ /*
+ * Decrement the write lock count for the
+ * running thread:
+ */
+ _thread_fd_table[fd]->w_lockcount--;
+
+ /*
+ * Check if the running thread still has
+ * write locks on this file descriptor:
+ */
+ if (_thread_fd_table[fd]->w_lockcount != 0) {
+ }
+ /*
+ * Get the next thread in the queue for a
+ * write lock on this file descriptor:
+ */
+ else if ((_thread_fd_table[fd]->w_owner = fd_next_writer(fd)) == NULL) {
+ } else {
+ /* Remove this thread from the queue: */
+ FDQ_REMOVE(&_thread_fd_table[fd]->w_queue,
+ _thread_fd_table[fd]->w_owner);
+
+ /*
+ * Set the state of the new owner of
+ * the thread to running:
+ */
+ PTHREAD_NEW_STATE(_thread_fd_table[fd]->w_owner,PS_RUNNING);
+
+ /*
+ * Reset the number of write locks.
+ * This will be incremented by the
+ * new owner of the lock when it
+ * sees that it has the lock.
+ */
+ _thread_fd_table[fd]->w_lockcount = 0;
+ }
+ }
+ }
+
+ /* Unlock the file descriptor table entry: */
+ _SPINUNLOCK(&_thread_fd_table[fd]->lock);
+
+ /*
+ * Undefer and handle pending signals, yielding if
+ * necessary:
+ */
+ _thread_kern_sig_undefer();
+ }
+}
+
+int
+_thread_fd_lock(int fd, int lock_type, struct timespec * timeout)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ /*
+ * Check that the file descriptor table is initialised for this
+ * entry:
+ */
+ if ((ret = _thread_fd_table_init(fd)) == 0) {
+ /* Clear the interrupted flag: */
+ curthread->interrupted = 0;
+
+ /*
+ * Lock the file descriptor table entry to prevent
+ * other threads for clashing with the current
+ * thread's accesses:
+ */
+ _SPINLOCK(&_thread_fd_table[fd]->lock);
+
+ /* Check the file descriptor and lock types: */
+ if (lock_type == FD_READ || lock_type == FD_RDWR) {
+ /*
+ * Wait for the file descriptor to be locked
+ * for read for the current thread:
+ */
+ while ((_thread_fd_table[fd]->r_owner != curthread) &&
+ (curthread->interrupted == 0)) {
+ /*
+ * Check if the file descriptor is locked by
+ * another thread:
+ */
+ if (_thread_fd_table[fd]->r_owner != NULL) {
+ /*
+ * Another thread has locked the file
+ * descriptor for read, so join the
+ * queue of threads waiting for a
+ * read lock on this file descriptor:
+ */
+ FDQ_INSERT(&_thread_fd_table[fd]->r_queue, curthread);
+
+ /*
+ * Save the file descriptor details
+ * in the thread structure for the
+ * running thread:
+ */
+ curthread->data.fd.fd = fd;
+
+ /* Set the timeout: */
+ _thread_kern_set_timeout(timeout);
+
+ /*
+ * Unlock the file descriptor
+ * table entry:
+ */
+ _SPINUNLOCK(&_thread_fd_table[fd]->lock);
+
+ /*
+ * Schedule this thread to wait on
+ * the read lock. It will only be
+ * woken when it becomes the next in
+ * the queue and is granted access
+ * to the lock by the thread
+ * that is unlocking the file
+ * descriptor.
+ */
+ _thread_kern_sched_state(PS_FDLR_WAIT, __FILE__, __LINE__);
+
+ /*
+ * Lock the file descriptor
+ * table entry again:
+ */
+ _SPINLOCK(&_thread_fd_table[fd]->lock);
+
+ if (curthread->interrupted != 0) {
+ FDQ_REMOVE(&_thread_fd_table[fd]->r_queue,
+ curthread);
+ }
+ } else {
+ /*
+ * The running thread now owns the
+ * read lock on this file descriptor:
+ */
+ _thread_fd_table[fd]->r_owner = curthread;
+
+ /*
+ * Reset the number of read locks for
+ * this file descriptor:
+ */
+ _thread_fd_table[fd]->r_lockcount = 0;
+ }
+ }
+
+ if (_thread_fd_table[fd]->r_owner == curthread)
+ /* Increment the read lock count: */
+ _thread_fd_table[fd]->r_lockcount++;
+ }
+
+ /* Check the file descriptor and lock types: */
+ if (curthread->interrupted == 0 &&
+ (lock_type == FD_WRITE || lock_type == FD_RDWR)) {
+ /*
+ * Wait for the file descriptor to be locked
+ * for write for the current thread:
+ */
+ while ((_thread_fd_table[fd]->w_owner != curthread) &&
+ (curthread->interrupted == 0)) {
+ /*
+ * Check if the file descriptor is locked by
+ * another thread:
+ */
+ if (_thread_fd_table[fd]->w_owner != NULL) {
+ /*
+ * Another thread has locked the file
+ * descriptor for write, so join the
+ * queue of threads waiting for a
+ * write lock on this file
+ * descriptor:
+ */
+ FDQ_INSERT(&_thread_fd_table[fd]->w_queue, curthread);
+
+ /*
+ * Save the file descriptor details
+ * in the thread structure for the
+ * running thread:
+ */
+ curthread->data.fd.fd = fd;
+
+ /* Set the timeout: */
+ _thread_kern_set_timeout(timeout);
+
+ /*
+ * Unlock the file descriptor
+ * table entry:
+ */
+ _SPINUNLOCK(&_thread_fd_table[fd]->lock);
+
+ /*
+ * Schedule this thread to wait on
+ * the write lock. It will only be
+ * woken when it becomes the next in
+ * the queue and is granted access to
+ * the lock by the thread that is
+ * unlocking the file descriptor.
+ */
+ _thread_kern_sched_state(PS_FDLW_WAIT, __FILE__, __LINE__);
+
+ /*
+ * Lock the file descriptor
+ * table entry again:
+ */
+ _SPINLOCK(&_thread_fd_table[fd]->lock);
+
+ if (curthread->interrupted != 0) {
+ FDQ_REMOVE(&_thread_fd_table[fd]->w_queue,
+ curthread);
+ }
+ } else {
+ /*
+ * The running thread now owns the
+ * write lock on this file
+ * descriptor:
+ */
+ _thread_fd_table[fd]->w_owner = curthread;
+
+ /*
+ * Reset the number of write locks
+ * for this file descriptor:
+ */
+ _thread_fd_table[fd]->w_lockcount = 0;
+ }
+ }
+
+ if (_thread_fd_table[fd]->w_owner == curthread)
+ /* Increment the write lock count: */
+ _thread_fd_table[fd]->w_lockcount++;
+ }
+
+ /* Unlock the file descriptor table entry: */
+ _SPINUNLOCK(&_thread_fd_table[fd]->lock);
+
+ if (curthread->interrupted != 0) {
+ ret = -1;
+ errno = EINTR;
+ if (curthread->continuation != NULL)
+ curthread->continuation((void *)curthread);
+ }
+ }
+
+ /* Return the completion status: */
+ return (ret);
+}
+
+void
+_thread_fd_unlock_debug(int fd, int lock_type, char *fname, int lineno)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ /*
+ * Check that the file descriptor table is initialised for this
+ * entry:
+ */
+ if ((ret = _thread_fd_table_init(fd)) == 0) {
+ /*
+ * Defer signals to protect the scheduling queues from
+ * access by the signal handler:
+ */
+ _thread_kern_sig_defer();
+
+ /*
+ * Lock the file descriptor table entry to prevent
+ * other threads for clashing with the current
+ * thread's accesses:
+ */
+ _spinlock_debug(&_thread_fd_table[fd]->lock, fname, lineno);
+
+ /* Check if the running thread owns the read lock: */
+ if (_thread_fd_table[fd]->r_owner == curthread) {
+ /* Check the file descriptor and lock types: */
+ if (lock_type == FD_READ || lock_type == FD_RDWR) {
+ /*
+ * Decrement the read lock count for the
+ * running thread:
+ */
+ _thread_fd_table[fd]->r_lockcount--;
+
+ /*
+ * Check if the running thread still has read
+ * locks on this file descriptor:
+ */
+ if (_thread_fd_table[fd]->r_lockcount != 0) {
+ }
+ /*
+ * Get the next thread in the queue for a
+ * read lock on this file descriptor:
+ */
+ else if ((_thread_fd_table[fd]->r_owner = fd_next_reader(fd)) == NULL) {
+ } else {
+ /* Remove this thread from the queue: */
+ FDQ_REMOVE(&_thread_fd_table[fd]->r_queue,
+ _thread_fd_table[fd]->r_owner);
+
+ /*
+ * Set the state of the new owner of
+ * the thread to running:
+ */
+ PTHREAD_NEW_STATE(_thread_fd_table[fd]->r_owner,PS_RUNNING);
+
+ /*
+ * Reset the number of read locks.
+ * This will be incremented by the
+ * new owner of the lock when it sees
+ * that it has the lock.
+ */
+ _thread_fd_table[fd]->r_lockcount = 0;
+ }
+ }
+ }
+ /* Check if the running thread owns the write lock: */
+ if (_thread_fd_table[fd]->w_owner == curthread) {
+ /* Check the file descriptor and lock types: */
+ if (lock_type == FD_WRITE || lock_type == FD_RDWR) {
+ /*
+ * Decrement the write lock count for the
+ * running thread:
+ */
+ _thread_fd_table[fd]->w_lockcount--;
+
+ /*
+ * Check if the running thread still has
+ * write locks on this file descriptor:
+ */
+ if (_thread_fd_table[fd]->w_lockcount != 0) {
+ }
+ /*
+ * Get the next thread in the queue for a
+ * write lock on this file descriptor:
+ */
+ else if ((_thread_fd_table[fd]->w_owner = fd_next_writer(fd)) == NULL) {
+ } else {
+ /* Remove this thread from the queue: */
+ FDQ_REMOVE(&_thread_fd_table[fd]->w_queue,
+ _thread_fd_table[fd]->w_owner);
+
+ /*
+ * Set the state of the new owner of
+ * the thread to running:
+ */
+ PTHREAD_NEW_STATE(_thread_fd_table[fd]->w_owner,PS_RUNNING);
+
+ /*
+ * Reset the number of write locks.
+ * This will be incremented by the
+ * new owner of the lock when it
+ * sees that it has the lock.
+ */
+ _thread_fd_table[fd]->w_lockcount = 0;
+ }
+ }
+ }
+
+ /* Unlock the file descriptor table entry: */
+ _SPINUNLOCK(&_thread_fd_table[fd]->lock);
+
+ /*
+ * Undefer and handle pending signals, yielding if
+ * necessary.
+ */
+ _thread_kern_sig_undefer();
+ }
+}
+
+int
+_thread_fd_lock_debug(int fd, int lock_type, struct timespec * timeout,
+ char *fname, int lineno)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ /*
+ * Check that the file descriptor table is initialised for this
+ * entry:
+ */
+ if ((ret = _thread_fd_table_init(fd)) == 0) {
+ /* Clear the interrupted flag: */
+ curthread->interrupted = 0;
+
+ /*
+ * Lock the file descriptor table entry to prevent
+ * other threads for clashing with the current
+ * thread's accesses:
+ */
+ _spinlock_debug(&_thread_fd_table[fd]->lock, fname, lineno);
+
+ /* Check the file descriptor and lock types: */
+ if (lock_type == FD_READ || lock_type == FD_RDWR) {
+ /*
+ * Wait for the file descriptor to be locked
+ * for read for the current thread:
+ */
+ while ((_thread_fd_table[fd]->r_owner != curthread) &&
+ (curthread->interrupted == 0)) {
+ /*
+ * Check if the file descriptor is locked by
+ * another thread:
+ */
+ if (_thread_fd_table[fd]->r_owner != NULL) {
+ /*
+ * Another thread has locked the file
+ * descriptor for read, so join the
+ * queue of threads waiting for a
+ * read lock on this file descriptor:
+ */
+ FDQ_INSERT(&_thread_fd_table[fd]->r_queue, curthread);
+
+ /*
+ * Save the file descriptor details
+ * in the thread structure for the
+ * running thread:
+ */
+ curthread->data.fd.fd = fd;
+ curthread->data.fd.branch = lineno;
+ curthread->data.fd.fname = fname;
+
+ /* Set the timeout: */
+ _thread_kern_set_timeout(timeout);
+
+ /*
+ * Unlock the file descriptor
+ * table entry:
+ */
+ _SPINUNLOCK(&_thread_fd_table[fd]->lock);
+
+ /*
+ * Schedule this thread to wait on
+ * the read lock. It will only be
+ * woken when it becomes the next in
+ * the queue and is granted access
+ * to the lock by the thread
+ * that is unlocking the file
+ * descriptor.
+ */
+ _thread_kern_sched_state(PS_FDLR_WAIT, __FILE__, __LINE__);
+
+ /*
+ * Lock the file descriptor
+ * table entry again:
+ */
+ _SPINLOCK(&_thread_fd_table[fd]->lock);
+
+ if (curthread->interrupted != 0) {
+ FDQ_REMOVE(&_thread_fd_table[fd]->r_queue,
+ curthread);
+ }
+ } else {
+ /*
+ * The running thread now owns the
+ * read lock on this file descriptor:
+ */
+ _thread_fd_table[fd]->r_owner = curthread;
+
+ /*
+ * Reset the number of read locks for
+ * this file descriptor:
+ */
+ _thread_fd_table[fd]->r_lockcount = 0;
+
+ /*
+ * Save the source file details for
+ * debugging:
+ */
+ _thread_fd_table[fd]->r_fname = fname;
+ _thread_fd_table[fd]->r_lineno = lineno;
+ }
+ }
+
+ if (_thread_fd_table[fd]->r_owner == curthread)
+ /* Increment the read lock count: */
+ _thread_fd_table[fd]->r_lockcount++;
+ }
+
+ /* Check the file descriptor and lock types: */
+ if (curthread->interrupted == 0 &&
+ (lock_type == FD_WRITE || lock_type == FD_RDWR)) {
+ /*
+ * Wait for the file descriptor to be locked
+ * for write for the current thread:
+ */
+ while ((_thread_fd_table[fd]->w_owner != curthread) &&
+ (curthread->interrupted == 0)) {
+ /*
+ * Check if the file descriptor is locked by
+ * another thread:
+ */
+ if (_thread_fd_table[fd]->w_owner != NULL) {
+ /*
+ * Another thread has locked the file
+ * descriptor for write, so join the
+ * queue of threads waiting for a
+ * write lock on this file
+ * descriptor:
+ */
+ FDQ_INSERT(&_thread_fd_table[fd]->w_queue, curthread);
+
+ /*
+ * Save the file descriptor details
+ * in the thread structure for the
+ * running thread:
+ */
+ curthread->data.fd.fd = fd;
+ curthread->data.fd.branch = lineno;
+ curthread->data.fd.fname = fname;
+
+ /* Set the timeout: */
+ _thread_kern_set_timeout(timeout);
+
+ /*
+ * Unlock the file descriptor
+ * table entry:
+ */
+ _SPINUNLOCK(&_thread_fd_table[fd]->lock);
+
+ /*
+ * Schedule this thread to wait on
+ * the write lock. It will only be
+ * woken when it becomes the next in
+ * the queue and is granted access to
+ * the lock by the thread that is
+ * unlocking the file descriptor.
+ */
+ _thread_kern_sched_state(PS_FDLW_WAIT, __FILE__, __LINE__);
+
+ /*
+ * Lock the file descriptor
+ * table entry again:
+ */
+ _SPINLOCK(&_thread_fd_table[fd]->lock);
+
+ if (curthread->interrupted != 0) {
+ FDQ_REMOVE(&_thread_fd_table[fd]->w_queue,
+ curthread);
+ }
+ } else {
+ /*
+ * The running thread now owns the
+ * write lock on this file
+ * descriptor:
+ */
+ _thread_fd_table[fd]->w_owner = curthread;
+
+ /*
+ * Reset the number of write locks
+ * for this file descriptor:
+ */
+ _thread_fd_table[fd]->w_lockcount = 0;
+
+ /*
+ * Save the source file details for
+ * debugging:
+ */
+ _thread_fd_table[fd]->w_fname = fname;
+ _thread_fd_table[fd]->w_lineno = lineno;
+ }
+ }
+
+ if (_thread_fd_table[fd]->w_owner == curthread)
+ /* Increment the write lock count: */
+ _thread_fd_table[fd]->w_lockcount++;
+ }
+
+ /* Unlock the file descriptor table entry: */
+ _SPINUNLOCK(&_thread_fd_table[fd]->lock);
+
+ if (curthread->interrupted != 0) {
+ ret = -1;
+ errno = EINTR;
+ if (curthread->continuation != NULL)
+ curthread->continuation((void *)curthread);
+ }
+ }
+
+ /* Return the completion status: */
+ return (ret);
+}
+
+void
+_thread_fd_unlock_owned(pthread_t pthread)
+{
+ int fd;
+
+ for (fd = 0; fd < _thread_dtablesize; fd++) {
+ if ((_thread_fd_table[fd] != NULL) &&
+ ((_thread_fd_table[fd]->r_owner == pthread) ||
+ (_thread_fd_table[fd]->w_owner == pthread))) {
+ /*
+ * Defer signals to protect the scheduling queues
+ * from access by the signal handler:
+ */
+ _thread_kern_sig_defer();
+
+ /*
+ * Lock the file descriptor table entry to prevent
+ * other threads for clashing with the current
+ * thread's accesses:
+ */
+ _SPINLOCK(&_thread_fd_table[fd]->lock);
+
+ /* Check if the thread owns the read lock: */
+ if (_thread_fd_table[fd]->r_owner == pthread) {
+ /* Clear the read lock count: */
+ _thread_fd_table[fd]->r_lockcount = 0;
+
+ /*
+ * Get the next thread in the queue for a
+ * read lock on this file descriptor:
+ */
+ if ((_thread_fd_table[fd]->r_owner = fd_next_reader(fd)) != NULL) {
+ /* Remove this thread from the queue: */
+ FDQ_REMOVE(&_thread_fd_table[fd]->r_queue,
+ _thread_fd_table[fd]->r_owner);
+
+ /*
+ * Set the state of the new owner of
+ * the thread to running:
+ */
+ PTHREAD_NEW_STATE(_thread_fd_table[fd]->r_owner,PS_RUNNING);
+ }
+ }
+
+ /* Check if the thread owns the write lock: */
+ if (_thread_fd_table[fd]->w_owner == pthread) {
+ /* Clear the write lock count: */
+ _thread_fd_table[fd]->w_lockcount = 0;
+
+ /*
+ * Get the next thread in the queue for a
+ * write lock on this file descriptor:
+ */
+ if ((_thread_fd_table[fd]->w_owner = fd_next_writer(fd)) != NULL) {
+ /* Remove this thread from the queue: */
+ FDQ_REMOVE(&_thread_fd_table[fd]->w_queue,
+ _thread_fd_table[fd]->w_owner);
+
+ /*
+ * Set the state of the new owner of
+ * the thread to running:
+ */
+ PTHREAD_NEW_STATE(_thread_fd_table[fd]->w_owner,PS_RUNNING);
+
+ }
+ }
+
+ /* Unlock the file descriptor table entry: */
+ _SPINUNLOCK(&_thread_fd_table[fd]->lock);
+
+ /*
+ * Undefer and handle pending signals, yielding if
+ * necessary.
+ */
+ _thread_kern_sig_undefer();
+ }
+ }
+}
+
+void
+_fd_lock_backout(pthread_t pthread)
+{
+ int fd;
+
+ /*
+ * Defer signals to protect the scheduling queues
+ * from access by the signal handler:
+ */
+ _thread_kern_sig_defer();
+
+ switch (pthread->state) {
+
+ case PS_FDLR_WAIT:
+ fd = pthread->data.fd.fd;
+
+ /*
+ * Lock the file descriptor table entry to prevent
+ * other threads for clashing with the current
+ * thread's accesses:
+ */
+ _SPINLOCK(&_thread_fd_table[fd]->lock);
+
+ /* Remove the thread from the waiting queue: */
+ FDQ_REMOVE(&_thread_fd_table[fd]->r_queue, pthread);
+ break;
+
+ case PS_FDLW_WAIT:
+ fd = pthread->data.fd.fd;
+
+ /*
+ * Lock the file descriptor table entry to prevent
+ * other threads from clashing with the current
+ * thread's accesses:
+ */
+ _SPINLOCK(&_thread_fd_table[fd]->lock);
+
+ /* Remove the thread from the waiting queue: */
+ FDQ_REMOVE(&_thread_fd_table[fd]->w_queue, pthread);
+ break;
+
+ default:
+ break;
+ }
+
+ /*
+ * Undefer and handle pending signals, yielding if
+ * necessary.
+ */
+ _thread_kern_sig_undefer();
+}
+
+static inline pthread_t
+fd_next_reader(int fd)
+{
+ pthread_t pthread;
+
+ while (((pthread = TAILQ_FIRST(&_thread_fd_table[fd]->r_queue)) != NULL) &&
+ (pthread->interrupted != 0)) {
+ /*
+ * This thread has either been interrupted by a signal or
+ * it has been canceled. Remove it from the queue.
+ */
+ FDQ_REMOVE(&_thread_fd_table[fd]->r_queue, pthread);
+ }
+
+ return (pthread);
+}
+
+static inline pthread_t
+fd_next_writer(int fd)
+{
+ pthread_t pthread;
+
+ while (((pthread = TAILQ_FIRST(&_thread_fd_table[fd]->w_queue)) != NULL) &&
+ (pthread->interrupted != 0)) {
+ /*
+ * This thread has either been interrupted by a signal or
+ * it has been canceled. Remove it from the queue.
+ */
+ FDQ_REMOVE(&_thread_fd_table[fd]->w_queue, pthread);
+ }
+
+ return (pthread);
+}
+
+#else
+
+void
+_thread_fd_unlock(int fd, int lock_type)
+{
+}
+
+int
+_thread_fd_lock(int fd, int lock_type, struct timespec * timeout)
+{
+ /*
+ * Insure that the file descriptor table is initialized for this
+ * entry:
+ */
+ return (_thread_fd_table_init(fd));
+}
+
+void
+_thread_fd_unlock_debug(int fd, int lock_type, char *fname, int lineno)
+{
+}
+
+int
+_thread_fd_lock_debug(int fd, int lock_type, struct timespec * timeout,
+ char *fname, int lineno)
+{
+ /*
+ * Insure that the file descriptor table is initialized for this
+ * entry:
+ */
+ return (_thread_fd_table_init(fd));
+}
+
+void
+_thread_fd_unlock_owned(pthread_t pthread)
+{
+}
+
+void
+_fd_lock_backout(pthread_t pthread)
+{
+}
+
+#endif
diff --git a/lib/libc_r/uthread/uthread_file.c b/lib/libc_r/uthread/uthread_file.c
new file mode 100644
index 0000000..cbedbc7
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_file.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ * POSIX stdio FILE locking functions. These assume that the locking
+ * is only required at FILE structure level, not at file descriptor
+ * level too.
+ *
+ */
+#include <stdio.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+extern void _flockfile(FILE *);
+
+void
+_flockfile_debug(FILE *fp, char *fname, int lineno)
+{
+ pthread_t curthread = _pthread_self();
+
+ curthread->lineno = lineno;
+ curthread->fname = fname;
+ _flockfile(fp);
+}
diff --git a/lib/libc_r/uthread/uthread_find_thread.c b/lib/libc_r/uthread/uthread_find_thread.c
new file mode 100644
index 0000000..e6e9294
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_find_thread.c
@@ -0,0 +1,66 @@
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+/* Find a thread in the linked list of active threads: */
+int
+_find_thread(pthread_t pthread)
+{
+ pthread_t pthread1;
+
+ /* Check if the caller has specified an invalid thread: */
+ if (pthread == NULL || pthread->magic != PTHREAD_MAGIC)
+ /* Invalid thread: */
+ return(EINVAL);
+
+ /*
+ * Defer signals to protect the thread list from access
+ * by the signal handler:
+ */
+ _thread_kern_sig_defer();
+
+ /* Search for the specified thread: */
+ TAILQ_FOREACH(pthread1, &_thread_list, tle) {
+ if (pthread == pthread1)
+ break;
+ }
+
+ /* Undefer and handle pending signals, yielding if necessary: */
+ _thread_kern_sig_undefer();
+
+ /* Return zero if the thread exists: */
+ return ((pthread1 != NULL) ? 0:ESRCH);
+}
diff --git a/lib/libc_r/uthread/uthread_flock.c b/lib/libc_r/uthread/uthread_flock.c
new file mode 100644
index 0000000..03312ff
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_flock.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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/file.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_flock, flock);
+
+int
+_flock(int fd, int operation)
+{
+ int ret;
+
+ if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) {
+ ret = __sys_flock(fd, operation);
+ _FD_UNLOCK(fd, FD_RDWR);
+ }
+ return (ret);
+}
diff --git a/lib/libc_r/uthread/uthread_fork.c b/lib/libc_r/uthread/uthread_fork.c
new file mode 100644
index 0000000..0166a57
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_fork.c
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <sys/param.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+static void free_thread_resources(struct pthread *thread);
+
+__weak_reference(_fork, fork);
+
+pid_t
+_fork(void)
+{
+ struct pthread *curthread = _get_curthread();
+ struct pthread_atfork *af;
+ int i, flags, use_deadlist = 0;
+ pid_t ret;
+ pthread_t pthread;
+ pthread_t pthread_save;
+
+ /*
+ * Defer signals to protect the scheduling queues from access
+ * by the signal handler:
+ */
+ _thread_kern_sig_defer();
+
+ _pthread_mutex_lock(&_atfork_mutex);
+
+ /* Run down atfork prepare handlers. */
+ TAILQ_FOREACH_REVERSE(af, &_atfork_list, atfork_head, qe) {
+ if (af->prepare != NULL)
+ af->prepare();
+ }
+
+ /* Fork a new process: */
+ if ((ret = __sys_fork()) != 0) {
+ /* Run down atfork parent handlers. */
+ TAILQ_FOREACH(af, &_atfork_list, qe) {
+ if (af->parent != NULL)
+ af->parent();
+ }
+ _pthread_mutex_unlock(&_atfork_mutex);
+
+ } else {
+ /* Close the pthread kernel pipe: */
+ __sys_close(_thread_kern_pipe[0]);
+ __sys_close(_thread_kern_pipe[1]);
+
+ /* Reset signals pending for the running thread: */
+ sigemptyset(&curthread->sigpend);
+
+ /*
+ * Create a pipe that is written to by the signal handler to
+ * prevent signals being missed in calls to
+ * __sys_select:
+ */
+ if (__sys_pipe(_thread_kern_pipe) != 0) {
+ /* Cannot create pipe, so abort: */
+ PANIC("Cannot create pthread kernel pipe for forked process");
+ }
+ /* Get the flags for the read pipe: */
+ else if ((flags = __sys_fcntl(_thread_kern_pipe[0], F_GETFL, NULL)) == -1) {
+ /* Abort this application: */
+ abort();
+ }
+ /* Make the read pipe non-blocking: */
+ else if (__sys_fcntl(_thread_kern_pipe[0], F_SETFL, flags | O_NONBLOCK) == -1) {
+ /* Abort this application: */
+ abort();
+ }
+ /* Get the flags for the write pipe: */
+ else if ((flags = __sys_fcntl(_thread_kern_pipe[1], F_GETFL, NULL)) == -1) {
+ /* Abort this application: */
+ abort();
+ }
+ /* Make the write pipe non-blocking: */
+ else if (__sys_fcntl(_thread_kern_pipe[1], F_SETFL, flags | O_NONBLOCK) == -1) {
+ /* Abort this application: */
+ abort();
+ }
+ /* Reinitialize the GC mutex: */
+ else if (_mutex_reinit(&_gc_mutex) != 0) {
+ /* Abort this application: */
+ PANIC("Cannot initialize GC mutex for forked process");
+ }
+ /* Reinitialize the GC condition variable: */
+ else if (_cond_reinit(&_gc_cond) != 0) {
+ /* Abort this application: */
+ PANIC("Cannot initialize GC condvar for forked process");
+ }
+ /* Initialize the ready queue: */
+ else if (_pq_init(&_readyq) != 0) {
+ /* Abort this application: */
+ PANIC("Cannot initialize priority ready queue.");
+ } else {
+ /*
+ * Enter a loop to remove all threads other than
+ * the running thread from the thread list:
+ */
+ if ((pthread = TAILQ_FIRST(&_thread_list)) == NULL) {
+ pthread = TAILQ_FIRST(&_dead_list);
+ use_deadlist = 1;
+ }
+ while (pthread != NULL) {
+ /* Save the thread to be freed: */
+ pthread_save = pthread;
+
+ /*
+ * Advance to the next thread before
+ * destroying the current thread:
+ */
+ if (use_deadlist != 0)
+ pthread = TAILQ_NEXT(pthread, dle);
+ else
+ pthread = TAILQ_NEXT(pthread, tle);
+
+ /* Make sure this isn't the running thread: */
+ if (pthread_save != curthread) {
+ /*
+ * Remove this thread from the
+ * appropriate list:
+ */
+ if (use_deadlist != 0)
+ TAILQ_REMOVE(&_thread_list,
+ pthread_save, dle);
+ else
+ TAILQ_REMOVE(&_thread_list,
+ pthread_save, tle);
+
+ free_thread_resources(pthread_save);
+ }
+
+ /*
+ * Switch to the deadlist when the active
+ * thread list has been consumed. This can't
+ * be at the top of the loop because it is
+ * used to determine to which list the thread
+ * belongs (when it is removed from the list).
+ */
+ if (pthread == NULL) {
+ pthread = TAILQ_FIRST(&_dead_list);
+ use_deadlist = 1;
+ }
+ }
+
+ /* Treat the current thread as the initial thread: */
+ _thread_initial = curthread;
+
+ /* Re-init the dead thread list: */
+ TAILQ_INIT(&_dead_list);
+
+ /* Re-init the waiting and work queues. */
+ TAILQ_INIT(&_waitingq);
+ TAILQ_INIT(&_workq);
+
+ /* Re-init the threads mutex queue: */
+ TAILQ_INIT(&curthread->mutexq);
+
+ /* No spinlocks yet: */
+ _spinblock_count = 0;
+
+ /* Don't queue signals yet: */
+ _queue_signals = 0;
+
+ /* Initialize the scheduling switch hook routine: */
+ _sched_switch_hook = NULL;
+
+ /* Clear out any locks in the file descriptor table: */
+ for (i = 0; i < _thread_dtablesize; i++) {
+ if (_thread_fd_table[i] != NULL) {
+ /* Initialise the file locks: */
+ memset(&_thread_fd_table[i]->lock, 0,
+ sizeof(_thread_fd_table[i]->lock));
+ _thread_fd_table[i]->r_owner = NULL;
+ _thread_fd_table[i]->w_owner = NULL;
+ _thread_fd_table[i]->r_fname = NULL;
+ _thread_fd_table[i]->w_fname = NULL;
+ _thread_fd_table[i]->r_lineno = 0;;
+ _thread_fd_table[i]->w_lineno = 0;;
+ _thread_fd_table[i]->r_lockcount = 0;;
+ _thread_fd_table[i]->w_lockcount = 0;;
+
+ /* Initialise the read/write queues: */
+ TAILQ_INIT(&_thread_fd_table[i]->r_queue);
+ TAILQ_INIT(&_thread_fd_table[i]->w_queue);
+ }
+ }
+ }
+ /* Run down atfork child handlers. */
+ TAILQ_FOREACH(af, &_atfork_list, qe) {
+ if (af->child != NULL)
+ af->child();
+ }
+ _mutex_reinit(&_atfork_mutex);
+ }
+
+
+ /*
+ * Undefer and handle pending signals, yielding if necessary:
+ */
+ _thread_kern_sig_undefer();
+
+ /* Return the process ID: */
+ return (ret);
+}
+
+static void
+free_thread_resources(struct pthread *thread)
+{
+
+ /* Check to see if the threads library allocated the stack. */
+ if ((thread->attr.stackaddr_attr == NULL) && (thread->stack != NULL)) {
+ /*
+ * Since this is being called from fork, we are currently single
+ * threaded so there is no need to protect the call to
+ * _thread_stack_free() with _gc_mutex.
+ */
+ _thread_stack_free(thread->stack, thread->attr.stacksize_attr,
+ thread->attr.guardsize_attr);
+ }
+
+ if (thread->specific != NULL)
+ free(thread->specific);
+
+ if (thread->poll_data.fds != NULL)
+ free(thread->poll_data.fds);
+
+ free(thread);
+}
diff --git a/lib/libc_r/uthread/uthread_fpathconf.c b/lib/libc_r/uthread/uthread_fpathconf.c
new file mode 100644
index 0000000..97e1d65
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_fpathconf.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2000 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$
+ */
+#include <unistd.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_fpathconf, fpathconf);
+
+long
+_fpathconf(int fd, int name)
+{
+ long ret;
+
+ if ((ret = _FD_LOCK(fd, FD_READ, NULL)) == 0) {
+ ret = __sys_fpathconf(fd, name);
+ _FD_UNLOCK(fd, FD_READ);
+ }
+ return ret;
+}
+
diff --git a/lib/libc_r/uthread/uthread_fstat.c b/lib/libc_r/uthread/uthread_fstat.c
new file mode 100644
index 0000000..0aa49d1
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_fstat.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <signal.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_fstat, fstat);
+
+int
+_fstat(int fd, struct stat * buf)
+{
+ int ret;
+
+ /* Lock the file descriptor for read: */
+ if ((ret = _FD_LOCK(fd, FD_READ, NULL)) == 0) {
+ /* Get the file status: */
+ ret = __sys_fstat(fd, buf);
+ /* Unlock the file descriptor: */
+ _FD_UNLOCK(fd, FD_READ);
+ }
+ return (ret);
+}
+
diff --git a/lib/libc_r/uthread/uthread_fstatfs.c b/lib/libc_r/uthread/uthread_fstatfs.c
new file mode 100644
index 0000000..80a8fd5
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_fstatfs.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <signal.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_fstatfs, fstatfs);
+
+int
+_fstatfs(int fd, struct statfs * buf)
+{
+ int ret;
+
+ /* Lock the file descriptor for read: */
+ if ((ret = _FD_LOCK(fd, FD_READ, NULL)) == 0) {
+ /* Get the file system status: */
+ ret = __sys_fstatfs(fd, buf);
+ /* Unlock the file descriptor: */
+ _FD_UNLOCK(fd, FD_READ);
+ }
+ return (ret);
+}
diff --git a/lib/libc_r/uthread/uthread_fsync.c b/lib/libc_r/uthread/uthread_fsync.c
new file mode 100644
index 0000000..b8b9f3c
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_fsync.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <unistd.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(__fsync, fsync);
+
+int
+_fsync(int fd)
+{
+ int ret;
+
+ if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) {
+ ret = __sys_fsync(fd);
+ _FD_UNLOCK(fd, FD_RDWR);
+ }
+ return (ret);
+}
+
+int
+__fsync(int fd)
+{
+ int ret;
+
+ _thread_enter_cancellation_point();
+ ret = _fsync(fd);
+ _thread_leave_cancellation_point();
+
+ return ret;
+}
diff --git a/lib/libc_r/uthread/uthread_gc.c b/lib/libc_r/uthread/uthread_gc.c
new file mode 100644
index 0000000..cdc5fa7
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_gc.c
@@ -0,0 +1,221 @@
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ * Garbage collector thread. Frees memory allocated for dead threads.
+ *
+ */
+#include <sys/param.h>
+#include <errno.h>
+#include <time.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include "namespace.h"
+#include <pthread.h>
+#include "un-namespace.h"
+#include "pthread_private.h"
+
+pthread_addr_t
+_thread_gc(pthread_addr_t arg)
+{
+ struct pthread *curthread = _get_curthread();
+ int f_debug;
+ int f_done = 0;
+ int ret;
+ sigset_t mask;
+ pthread_t pthread;
+ pthread_t pthread_cln;
+ struct timespec abstime;
+ void *p_stack;
+
+ /* Block all signals */
+ sigfillset(&mask);
+ _pthread_sigmask(SIG_BLOCK, &mask, NULL);
+
+ /* Mark this thread as a library thread (not a user thread). */
+ curthread->flags |= PTHREAD_FLAGS_PRIVATE;
+
+ /* Set a debug flag based on an environment variable. */
+ f_debug = (getenv("LIBC_R_DEBUG") != NULL);
+
+ /* Set the name of this thread. */
+ pthread_set_name_np(curthread,"GC");
+
+ while (!f_done) {
+ /* Check if debugging this application. */
+ if (f_debug)
+ /* Dump thread info to file. */
+ _thread_dump_info();
+
+ /*
+ * Defer signals to protect the scheduling queues from
+ * access by the signal handler:
+ */
+ _thread_kern_sig_defer();
+
+ /* Check if this is the last running thread: */
+ if (TAILQ_FIRST(&_thread_list) == curthread &&
+ TAILQ_NEXT(curthread, tle) == NULL)
+ /*
+ * This is the last thread, so it can exit
+ * now.
+ */
+ f_done = 1;
+
+ /*
+ * Undefer and handle pending signals, yielding if
+ * necessary:
+ */
+ _thread_kern_sig_undefer();
+
+ /* No stack of thread structure to free yet: */
+ p_stack = NULL;
+ pthread_cln = NULL;
+
+ /*
+ * Lock the garbage collector mutex which ensures that
+ * this thread sees another thread exit:
+ */
+ if (_pthread_mutex_lock(&_gc_mutex) != 0)
+ PANIC("Cannot lock gc mutex");
+
+ /*
+ * Enter a loop to search for the first dead thread that
+ * has memory to free.
+ */
+ for (pthread = TAILQ_FIRST(&_dead_list);
+ p_stack == NULL && pthread_cln == NULL && pthread != NULL;
+ pthread = TAILQ_NEXT(pthread, dle)) {
+ /* Check if the initial thread: */
+ if (pthread == _thread_initial) {
+ /* Don't destroy the initial thread. */
+ }
+ /*
+ * Check if this thread has detached:
+ */
+ else if ((pthread->attr.flags &
+ PTHREAD_DETACHED) != 0) {
+ /* Remove this thread from the dead list: */
+ TAILQ_REMOVE(&_dead_list, pthread, dle);
+
+ /*
+ * Check if the stack was not specified by
+ * the caller to pthread_create() and has not
+ * been destroyed yet:
+ */
+ if (pthread->attr.stackaddr_attr == NULL &&
+ pthread->stack != NULL) {
+ _thread_stack_free(pthread->stack,
+ pthread->attr.stacksize_attr,
+ pthread->attr.guardsize_attr);
+ }
+
+ /*
+ * Point to the thread structure that must
+ * be freed outside the locks:
+ */
+ pthread_cln = pthread;
+
+ } else {
+ /*
+ * This thread has not detached, so do
+ * not destroy it.
+ *
+ * Check if the stack was not specified by
+ * the caller to pthread_create() and has not
+ * been destroyed yet:
+ */
+ if (pthread->attr.stackaddr_attr == NULL &&
+ pthread->stack != NULL) {
+ _thread_stack_free(pthread->stack,
+ pthread->attr.stacksize_attr,
+ pthread->attr.guardsize_attr);
+
+ /*
+ * NULL the stack pointer now that the
+ * memory has been freed:
+ */
+ pthread->stack = NULL;
+ }
+ }
+ }
+
+ /*
+ * Check if this is not the last thread and there is no
+ * memory to free this time around.
+ */
+ if (!f_done && p_stack == NULL && pthread_cln == NULL) {
+ /* Get the current time. */
+ if (clock_gettime(CLOCK_REALTIME,&abstime) != 0)
+ PANIC("gc cannot get time");
+
+ /*
+ * Do a backup poll in 10 seconds if no threads
+ * die before then.
+ */
+ abstime.tv_sec += 10;
+
+ /*
+ * Wait for a signal from a dying thread or a
+ * timeout (for a backup poll).
+ */
+ if ((ret = _pthread_cond_timedwait(&_gc_cond,
+ &_gc_mutex, &abstime)) != 0 && ret != ETIMEDOUT)
+ PANIC("gc cannot wait for a signal");
+ }
+
+ /* Unlock the garbage collector mutex: */
+ if (_pthread_mutex_unlock(&_gc_mutex) != 0)
+ PANIC("Cannot unlock gc mutex");
+
+ /*
+ * If there is memory to free, do it now. The call to
+ * free() might block, so this must be done outside the
+ * locks.
+ */
+ if (p_stack != NULL)
+ free(p_stack);
+ if (pthread_cln != NULL) {
+ if (pthread_cln->name != NULL) {
+ /* Free the thread name string. */
+ free(pthread_cln->name);
+ }
+ /*
+ * Free the memory allocated for the thread
+ * structure.
+ */
+ free(pthread_cln);
+ }
+ }
+ return (NULL);
+}
diff --git a/lib/libc_r/uthread/uthread_getdirentries.c b/lib/libc_r/uthread/uthread_getdirentries.c
new file mode 100644
index 0000000..b633c08
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_getdirentries.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <dirent.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_getdirentries, getdirentries);
+
+int
+_getdirentries(int fd, char *buf, int nbytes, long *basep)
+{
+ int ret;
+
+ if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) {
+ ret = __sys_getdirentries(fd, buf, nbytes, basep);
+ _FD_UNLOCK(fd, FD_RDWR);
+ }
+ return (ret);
+}
diff --git a/lib/libc_r/uthread/uthread_getpeername.c b/lib/libc_r/uthread/uthread_getpeername.c
new file mode 100644
index 0000000..8ff8b43
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_getpeername.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_getpeername, getpeername);
+
+int
+_getpeername(int fd, struct sockaddr * peer, socklen_t *paddrlen)
+{
+ int ret;
+
+ if ((ret = _FD_LOCK(fd, FD_READ, NULL)) == 0) {
+ ret = __sys_getpeername(fd, peer, paddrlen);
+ _FD_UNLOCK(fd, FD_READ);
+ }
+ return ret;
+}
+
diff --git a/lib/libc_r/uthread/uthread_getprio.c b/lib/libc_r/uthread/uthread_getprio.c
new file mode 100644
index 0000000..a10c889
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_getprio.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_getprio, pthread_getprio);
+
+int
+_pthread_getprio(pthread_t pthread)
+{
+ int policy, ret;
+ struct sched_param param;
+
+ if ((ret = pthread_getschedparam(pthread, &policy, &param)) == 0)
+ ret = param.sched_priority;
+ else {
+ /* Invalid thread: */
+ errno = ret;
+ ret = -1;
+ }
+
+ /* Return the thread priority or an error status: */
+ return (ret);
+}
diff --git a/lib/libc_r/uthread/uthread_getschedparam.c b/lib/libc_r/uthread/uthread_getschedparam.c
new file mode 100644
index 0000000..0d1ffe9
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_getschedparam.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_getschedparam, pthread_getschedparam);
+
+int
+_pthread_getschedparam(pthread_t pthread, int *policy,
+ struct sched_param *param)
+{
+ int ret;
+
+ if ((param == NULL) || (policy == NULL))
+ /* Return an invalid argument error: */
+ ret = EINVAL;
+
+ /* Find the thread in the list of active threads: */
+ else if ((ret = _find_thread(pthread)) == 0) {
+ /* Return the threads base priority and scheduling policy: */
+ param->sched_priority =
+ PTHREAD_BASE_PRIORITY(pthread->base_priority);
+ *policy = pthread->attr.sched_policy;
+ }
+
+ return(ret);
+}
diff --git a/lib/libc_r/uthread/uthread_getsockname.c b/lib/libc_r/uthread/uthread_getsockname.c
new file mode 100644
index 0000000..745ba23
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_getsockname.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_getsockname, getsockname);
+
+int
+_getsockname(int s, struct sockaddr * name, socklen_t *namelen)
+{
+ int ret;
+
+ if ((ret = _FD_LOCK(s, FD_READ, NULL)) == 0) {
+ ret = __sys_getsockname(s, name, namelen);
+ _FD_UNLOCK(s, FD_READ);
+ }
+ return ret;
+}
diff --git a/lib/libc_r/uthread/uthread_getsockopt.c b/lib/libc_r/uthread/uthread_getsockopt.c
new file mode 100644
index 0000000..ad2d10e
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_getsockopt.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_getsockopt, getsockopt);
+
+int
+_getsockopt(int fd, int level, int optname, void *optval, socklen_t
+ *optlen)
+{
+ int ret;
+
+ if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) {
+ ret = __sys_getsockopt(fd, level, optname, optval, optlen);
+ _FD_UNLOCK(fd, FD_RDWR);
+ }
+ return ret;
+}
diff --git a/lib/libc_r/uthread/uthread_info.c b/lib/libc_r/uthread/uthread_info.c
new file mode 100644
index 0000000..71a9747
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_info.c
@@ -0,0 +1,296 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <paths.h>
+#include <pthread.h>
+#include <unistd.h>
+#include "pthread_private.h"
+
+#ifndef NELEMENTS
+#define NELEMENTS(arr) (sizeof(arr) / sizeof(arr[0]))
+#endif
+
+static void dump_thread(int fd, pthread_t pthread, int long_version);
+
+__weak_reference(_pthread_set_name_np, pthread_set_name_np);
+
+struct s_thread_info {
+ enum pthread_state state;
+ char *name;
+};
+
+/* Static variables: */
+static const struct s_thread_info thread_info[] = {
+ {PS_RUNNING , "Running"},
+ {PS_SIGTHREAD , "Waiting on signal thread"},
+ {PS_MUTEX_WAIT , "Waiting on a mutex"},
+ {PS_COND_WAIT , "Waiting on a condition variable"},
+ {PS_FDLR_WAIT , "Waiting for a file read lock"},
+ {PS_FDLW_WAIT , "Waiting for a file write lock"},
+ {PS_FDR_WAIT , "Waiting for read"},
+ {PS_FDW_WAIT , "Waiting for write"},
+ {PS_FILE_WAIT , "Waiting for FILE lock"},
+ {PS_POLL_WAIT , "Waiting on poll"},
+ {PS_SELECT_WAIT , "Waiting on select"},
+ {PS_SLEEP_WAIT , "Sleeping"},
+ {PS_WAIT_WAIT , "Waiting process"},
+ {PS_SIGSUSPEND , "Suspended, waiting for a signal"},
+ {PS_SIGWAIT , "Waiting for a signal"},
+ {PS_SPINBLOCK , "Waiting for a spinlock"},
+ {PS_JOIN , "Waiting to join"},
+ {PS_SUSPENDED , "Suspended"},
+ {PS_DEAD , "Dead"},
+ {PS_DEADLOCK , "Deadlocked"},
+ {PS_STATE_MAX , "Not a real state!"}
+};
+
+void
+_thread_dump_info(void)
+{
+ char s[512];
+ int fd;
+ int i;
+ pthread_t pthread;
+ char *tmpdir;
+ char tmpfile[PATH_MAX];
+ pq_list_t *pq_list;
+
+ if (issetugid() != 0 || (tmpdir = getenv("TMPDIR")) == NULL)
+ tmpdir = _PATH_TMP;
+ for (i = 0; i < 100000; i++) {
+ snprintf(tmpfile, sizeof(tmpfile), "%s/uthread.dump.%u.%i",
+ tmpdir, getpid(), i);
+ /* Open the dump file for append and create it if necessary: */
+ if ((fd = __sys_open(tmpfile, O_RDWR | O_CREAT | O_EXCL,
+ 0644)) < 0) {
+ /* Can't open the dump file. */
+ if (errno == EEXIST)
+ continue;
+ /*
+ * We only need to continue in case of
+ * EEXIST error. Most other error
+ * codes means that we will fail all
+ * the time.
+ */
+ return;
+ } else {
+ break;
+ }
+ }
+ if (i==100000) {
+ /* all 100000 possibilities are in use :( */
+ return;
+ } else {
+ /* Output a header for active threads: */
+ strcpy(s, "\n\n=============\nACTIVE THREADS\n\n");
+ __sys_write(fd, s, strlen(s));
+
+ /* Enter a loop to report each thread in the global list: */
+ TAILQ_FOREACH(pthread, &_thread_list, tle) {
+ dump_thread(fd, pthread, /*long_verson*/ 1);
+ }
+
+ /* Output a header for ready threads: */
+ strcpy(s, "\n\n=============\nREADY THREADS\n\n");
+ __sys_write(fd, s, strlen(s));
+
+ /* Enter a loop to report each thread in the ready queue: */
+ TAILQ_FOREACH (pq_list, &_readyq.pq_queue, pl_link) {
+ TAILQ_FOREACH(pthread, &pq_list->pl_head, pqe) {
+ dump_thread(fd, pthread, /*long_version*/ 0);
+ }
+ }
+
+ /* Output a header for waiting threads: */
+ strcpy(s, "\n\n=============\nWAITING THREADS\n\n");
+ __sys_write(fd, s, strlen(s));
+
+ /* Enter a loop to report each thread in the waiting queue: */
+ TAILQ_FOREACH (pthread, &_waitingq, pqe) {
+ dump_thread(fd, pthread, /*long_version*/ 0);
+ }
+
+ /* Output a header for threads in the work queue: */
+ strcpy(s, "\n\n=============\nTHREADS IN WORKQ\n\n");
+ __sys_write(fd, s, strlen(s));
+
+ /* Enter a loop to report each thread in the waiting queue: */
+ TAILQ_FOREACH (pthread, &_workq, qe) {
+ dump_thread(fd, pthread, /*long_version*/ 0);
+ }
+
+ /* Check if there are no dead threads: */
+ if (TAILQ_FIRST(&_dead_list) == NULL) {
+ /* Output a record: */
+ strcpy(s, "\n\nTHERE ARE NO DEAD THREADS\n");
+ __sys_write(fd, s, strlen(s));
+ } else {
+ /* Output a header for dead threads: */
+ strcpy(s, "\n\nDEAD THREADS\n\n");
+ __sys_write(fd, s, strlen(s));
+
+ /*
+ * Enter a loop to report each thread in the global
+ * dead thread list:
+ */
+ TAILQ_FOREACH(pthread, &_dead_list, dle) {
+ dump_thread(fd, pthread, /*long_version*/ 0);
+ }
+ }
+
+ /* Output a header for file descriptors: */
+ snprintf(s, sizeof(s), "\n\n=============\nFILE DESCRIPTOR "
+ "TABLE (table size %d)\n\n", _thread_dtablesize);
+ __sys_write(fd, s, strlen(s));
+
+ /* Enter a loop to report file descriptor lock usage: */
+ for (i = 0; i < _thread_dtablesize; i++) {
+ /*
+ * Check if memory is allocated for this file
+ * descriptor:
+ */
+ if (_thread_fd_table[i] != NULL) {
+ /* Report the file descriptor lock status: */
+ snprintf(s, sizeof(s),
+ "fd[%3d] read owner %p count %d [%s:%d]\n"
+ " write owner %p count %d [%s:%d]\n",
+ i, _thread_fd_table[i]->r_owner,
+ _thread_fd_table[i]->r_lockcount,
+ _thread_fd_table[i]->r_fname,
+ _thread_fd_table[i]->r_lineno,
+ _thread_fd_table[i]->w_owner,
+ _thread_fd_table[i]->w_lockcount,
+ _thread_fd_table[i]->w_fname,
+ _thread_fd_table[i]->w_lineno);
+ __sys_write(fd, s, strlen(s));
+ }
+ }
+
+ /* Close the dump file: */
+ __sys_close(fd);
+ }
+}
+
+static void
+dump_thread(int fd, pthread_t pthread, int long_version)
+{
+ struct pthread *curthread = _get_curthread();
+ char s[512];
+ int i;
+
+ /* Find the state: */
+ for (i = 0; i < NELEMENTS(thread_info) - 1; i++)
+ if (thread_info[i].state == pthread->state)
+ break;
+
+ /* Output a record for the thread: */
+ snprintf(s, sizeof(s),
+ "--------------------\nThread %p (%s) prio %3d state %s",
+ pthread, (pthread->name == NULL) ? "" : pthread->name,
+ pthread->active_priority, thread_info[i].name);
+ __sys_write(fd, s, strlen(s));
+ /* And now where it is. */
+ if (pthread->fname != NULL) {
+ snprintf(s, sizeof(s), " [%s:%d]", pthread->fname,
+ pthread->lineno);
+ __sys_write(fd, s, strlen(s));
+ }
+ __sys_write(fd, "\n", 1);
+
+ if (long_version != 0) {
+ /* Check if this is the running thread: */
+ if (pthread == curthread) {
+ /* Output a record for the running thread: */
+ strcpy(s, "This is the running thread\n");
+ __sys_write(fd, s, strlen(s));
+ }
+ /* Check if this is the initial thread: */
+ if (pthread == _thread_initial) {
+ /* Output a record for the initial thread: */
+ strcpy(s, "This is the initial thread\n");
+ __sys_write(fd, s, strlen(s));
+ }
+ /* Process according to thread state: */
+ switch (pthread->state) {
+ /* File descriptor read lock wait: */
+ case PS_FDLR_WAIT:
+ case PS_FDLW_WAIT:
+ case PS_FDR_WAIT:
+ case PS_FDW_WAIT:
+ /* Write the lock details: */
+ snprintf(s, sizeof(s), "fd %d[%s:%d]",
+ pthread->data.fd.fd,
+ pthread->data.fd.fname,
+ pthread->data.fd.branch);
+ __sys_write(fd, s, strlen(s));
+ break;
+ case PS_SIGWAIT:
+ snprintf(s, sizeof(s), "sigmask (hi)");
+ __sys_write(fd, s, strlen(s));
+ for (i = _SIG_WORDS - 1; i >= 0; i--) {
+ snprintf(s, sizeof(s), "%08x\n",
+ pthread->sigmask.__bits[i]);
+ __sys_write(fd, s, strlen(s));
+ }
+ snprintf(s, sizeof(s), "(lo)\n");
+ __sys_write(fd, s, strlen(s));
+ break;
+ /*
+ * Trap other states that are not explicitly
+ * coded to dump information:
+ */
+ default:
+ /* Nothing to do here. */
+ break;
+ }
+ }
+}
+
+/* Set the thread name for debug: */
+void
+_pthread_set_name_np(pthread_t thread, const char *name)
+{
+ /* Check if the caller has specified a valid thread: */
+ if (thread != NULL && thread->magic == PTHREAD_MAGIC) {
+ if (thread->name != NULL) {
+ /* Free space for previous name. */
+ free(thread->name);
+ }
+ thread->name = strdup(name);
+ }
+}
diff --git a/lib/libc_r/uthread/uthread_init.c b/lib/libc_r/uthread/uthread_init.c
new file mode 100644
index 0000000..caed63f
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_init.c
@@ -0,0 +1,579 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/* Allocate space for global thread variables here: */
+#define GLOBAL_PTHREAD_PRIVATE
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <sys/types.h>
+#include <machine/reg.h>
+
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <sys/event.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+#include <sys/ttycom.h>
+#include <sys/wait.h>
+#include <sys/mman.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <poll.h>
+#include <pthread.h>
+#include <pthread_np.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 "pthread_private.h"
+
+int __pthread_cond_wait(pthread_cond_t *, pthread_mutex_t *);
+int __pthread_mutex_lock(pthread_mutex_t *);
+int __pthread_mutex_trylock(pthread_mutex_t *);
+
+/*
+ * All weak references used within libc should be in this table.
+ * This allows static libraries to work.
+ */
+static void *references[] = {
+ &_accept,
+ &_bind,
+ &_close,
+ &_connect,
+ &_dup,
+ &_dup2,
+ &_execve,
+ &_fcntl,
+ &_flock,
+ &_flockfile,
+ &_fstat,
+ &_fstatfs,
+ &_fsync,
+ &_funlockfile,
+ &_getdirentries,
+ &_getlogin,
+ &_getpeername,
+ &_getsockname,
+ &_getsockopt,
+ &_ioctl,
+ &_kevent,
+ &_listen,
+ &_nanosleep,
+ &_open,
+ &_pthread_cond_destroy,
+ &_pthread_cond_init,
+ &_pthread_cond_signal,
+ &_pthread_cond_wait,
+ &_pthread_getspecific,
+ &_pthread_key_create,
+ &_pthread_key_delete,
+ &_pthread_mutex_destroy,
+ &_pthread_mutex_init,
+ &_pthread_mutex_lock,
+ &_pthread_mutex_trylock,
+ &_pthread_mutex_unlock,
+ &_pthread_mutexattr_init,
+ &_pthread_mutexattr_destroy,
+ &_pthread_mutexattr_settype,
+ &_pthread_once,
+ &_pthread_setspecific,
+ &_read,
+ &_readv,
+ &_recvfrom,
+ &_recvmsg,
+ &_select,
+ &_sendmsg,
+ &_sendto,
+ &_setsockopt,
+ &_sigaction,
+ &_sigprocmask,
+ &_sigsuspend,
+ &_socket,
+ &_socketpair,
+ &_wait4,
+ &_write,
+ &_writev
+};
+
+/*
+ * These are needed when linking statically. All references within
+ * libgcc (and libc) to these routines are weak, but if they are not
+ * (strongly) referenced by the application or other libraries, then
+ * the actual functions will not be loaded.
+ */
+static void *libgcc_references[] = {
+ &_pthread_once,
+ &_pthread_key_create,
+ &_pthread_key_delete,
+ &_pthread_getspecific,
+ &_pthread_setspecific,
+ &_pthread_mutex_init,
+ &_pthread_mutex_destroy,
+ &_pthread_mutex_lock,
+ &_pthread_mutex_trylock,
+ &_pthread_mutex_unlock
+};
+
+#define DUAL_ENTRY(entry) \
+ (pthread_func_t)entry, (pthread_func_t)entry
+
+static pthread_func_t jmp_table[][2] = {
+ {DUAL_ENTRY(_pthread_cond_broadcast)}, /* PJT_COND_BROADCAST */
+ {DUAL_ENTRY(_pthread_cond_destroy)}, /* PJT_COND_DESTROY */
+ {DUAL_ENTRY(_pthread_cond_init)}, /* PJT_COND_INIT */
+ {DUAL_ENTRY(_pthread_cond_signal)}, /* PJT_COND_SIGNAL */
+ {(pthread_func_t)__pthread_cond_wait,
+ (pthread_func_t)_pthread_cond_wait}, /* PJT_COND_WAIT */
+ {DUAL_ENTRY(_pthread_getspecific)}, /* PJT_GETSPECIFIC */
+ {DUAL_ENTRY(_pthread_key_create)}, /* PJT_KEY_CREATE */
+ {DUAL_ENTRY(_pthread_key_delete)}, /* PJT_KEY_DELETE*/
+ {DUAL_ENTRY(_pthread_main_np)}, /* PJT_MAIN_NP */
+ {DUAL_ENTRY(_pthread_mutex_destroy)}, /* PJT_MUTEX_DESTROY */
+ {DUAL_ENTRY(_pthread_mutex_init)}, /* PJT_MUTEX_INIT */
+ {(pthread_func_t)__pthread_mutex_lock,
+ (pthread_func_t)_pthread_mutex_lock}, /* PJT_MUTEX_LOCK */
+ {(pthread_func_t)__pthread_mutex_trylock,
+ (pthread_func_t)_pthread_mutex_trylock},/* PJT_MUTEX_TRYLOCK */
+ {DUAL_ENTRY(_pthread_mutex_unlock)}, /* PJT_MUTEX_UNLOCK */
+ {DUAL_ENTRY(_pthread_mutexattr_destroy)}, /* PJT_MUTEXATTR_DESTROY */
+ {DUAL_ENTRY(_pthread_mutexattr_init)}, /* PJT_MUTEXATTR_INIT */
+ {DUAL_ENTRY(_pthread_mutexattr_settype)}, /* PJT_MUTEXATTR_SETTYPE */
+ {DUAL_ENTRY(_pthread_once)}, /* PJT_ONCE */
+ {DUAL_ENTRY(_pthread_rwlock_destroy)}, /* PJT_RWLOCK_DESTROY */
+ {DUAL_ENTRY(_pthread_rwlock_init)}, /* PJT_RWLOCK_INIT */
+ {DUAL_ENTRY(_pthread_rwlock_rdlock)}, /* PJT_RWLOCK_RDLOCK */
+ {DUAL_ENTRY(_pthread_rwlock_tryrdlock)},/* PJT_RWLOCK_TRYRDLOCK */
+ {DUAL_ENTRY(_pthread_rwlock_trywrlock)},/* PJT_RWLOCK_TRYWRLOCK */
+ {DUAL_ENTRY(_pthread_rwlock_unlock)}, /* PJT_RWLOCK_UNLOCK */
+ {DUAL_ENTRY(_pthread_rwlock_wrlock)}, /* PJT_RWLOCK_WRLOCK */
+ {DUAL_ENTRY(_pthread_self)}, /* PJT_SELF */
+ {DUAL_ENTRY(_pthread_setspecific)}, /* PJT_SETSPECIFIC */
+ {DUAL_ENTRY(_pthread_sigmask)} /* PJT_SIGMASK */
+};
+
+int _pthread_guard_default;
+int _pthread_page_size;
+int _pthread_stack_default;
+int _pthread_stack_initial;
+
+/*
+ * Threaded process initialization
+ */
+void
+_thread_init(void)
+{
+ int fd;
+ int flags;
+ int i;
+ size_t len;
+ int mib[2];
+ int sched_stack_size; /* Size of scheduler stack. */
+#if !defined(__ia64__)
+ u_long stackp;
+#endif
+
+ struct clockinfo clockinfo;
+ struct sigaction act;
+
+
+ /* Check if this function has already been called: */
+ if (_thread_initial)
+ /* Only initialise the threaded application once. */
+ return;
+
+ _pthread_page_size = getpagesize();;
+ _pthread_guard_default = _pthread_page_size;
+ sched_stack_size = 4 * _pthread_page_size;
+ if (sizeof(void *) == 8) {
+ _pthread_stack_default = PTHREAD_STACK64_DEFAULT;
+ _pthread_stack_initial = PTHREAD_STACK64_INITIAL;
+ }
+ else {
+ _pthread_stack_default = PTHREAD_STACK32_DEFAULT;
+ _pthread_stack_initial = PTHREAD_STACK32_INITIAL;
+ }
+
+ _pthread_attr_default.guardsize_attr = _pthread_guard_default;
+ _pthread_attr_default.stacksize_attr = _pthread_stack_default;
+
+ /*
+ * Make gcc quiescent about {,libgcc_}references not being
+ * referenced:
+ */
+ if ((references[0] == NULL) || (libgcc_references[0] == NULL))
+ PANIC("Failed loading mandatory references in _thread_init");
+
+ /*
+ * Check the size of the jump table to make sure it is preset
+ * with the correct number of entries.
+ */
+ if (sizeof(jmp_table) != (sizeof(pthread_func_t) * PJT_MAX * 2))
+ PANIC("Thread jump table not properly initialized");
+ memcpy(__thr_jtable, jmp_table, sizeof(jmp_table));
+
+ /*
+ * Check for the special case of this process running as
+ * or in place of init as pid = 1:
+ */
+ if (getpid() == 1) {
+ /*
+ * Setup a new session for this process which is
+ * assumed to be running as root.
+ */
+ if (setsid() == -1)
+ PANIC("Can't set session ID");
+ if (revoke(_PATH_CONSOLE) != 0)
+ PANIC("Can't revoke console");
+ if ((fd = __sys_open(_PATH_CONSOLE, O_RDWR)) < 0)
+ PANIC("Can't open console");
+ if (setlogin("root") == -1)
+ PANIC("Can't set login to root");
+ if (__sys_ioctl(fd, TIOCSCTTY, (char *) NULL) == -1)
+ PANIC("Can't set controlling terminal");
+ if (__sys_dup2(fd, 0) == -1 ||
+ __sys_dup2(fd, 1) == -1 ||
+ __sys_dup2(fd, 2) == -1)
+ PANIC("Can't dup2");
+ }
+
+ /* Get the standard I/O flags before messing with them : */
+ for (i = 0; i < 3; i++) {
+ if (((_pthread_stdio_flags[i] =
+ __sys_fcntl(i, F_GETFL, NULL)) == -1) &&
+ (errno != EBADF))
+ PANIC("Cannot get stdio flags");
+ }
+
+ /*
+ * Create a pipe that is written to by the signal handler to prevent
+ * signals being missed in calls to _select:
+ */
+ if (__sys_pipe(_thread_kern_pipe) != 0) {
+ /* Cannot create pipe, so abort: */
+ PANIC("Cannot create kernel pipe");
+ }
+
+ /*
+ * Make sure the pipe does not get in the way of stdio:
+ */
+ for (i = 0; i < 2; i++) {
+ if (_thread_kern_pipe[i] < 3) {
+ fd = __sys_fcntl(_thread_kern_pipe[i], F_DUPFD, 3);
+ if (fd == -1)
+ PANIC("Cannot create kernel pipe");
+ __sys_close(_thread_kern_pipe[i]);
+ _thread_kern_pipe[i] = fd;
+ }
+ }
+ /* Get the flags for the read pipe: */
+ if ((flags = __sys_fcntl(_thread_kern_pipe[0], F_GETFL, NULL)) == -1) {
+ /* Abort this application: */
+ PANIC("Cannot get kernel read pipe flags");
+ }
+ /* Make the read pipe non-blocking: */
+ else if (__sys_fcntl(_thread_kern_pipe[0], F_SETFL, flags | O_NONBLOCK) == -1) {
+ /* Abort this application: */
+ PANIC("Cannot make kernel read pipe non-blocking");
+ }
+ /* Get the flags for the write pipe: */
+ else if ((flags = __sys_fcntl(_thread_kern_pipe[1], F_GETFL, NULL)) == -1) {
+ /* Abort this application: */
+ PANIC("Cannot get kernel write pipe flags");
+ }
+ /* Make the write pipe non-blocking: */
+ else if (__sys_fcntl(_thread_kern_pipe[1], F_SETFL, flags | O_NONBLOCK) == -1) {
+ /* Abort this application: */
+ PANIC("Cannot get kernel write pipe flags");
+ }
+ /* Allocate and initialize the ready queue: */
+ else if (_pq_alloc(&_readyq, PTHREAD_MIN_PRIORITY, PTHREAD_LAST_PRIORITY) != 0) {
+ /* Abort this application: */
+ PANIC("Cannot allocate priority ready queue.");
+ }
+ /* Allocate memory for the thread structure of the initial thread: */
+ else if ((_thread_initial = (pthread_t) malloc(sizeof(struct pthread))) == NULL) {
+ /*
+ * Insufficient memory to initialise this application, so
+ * abort:
+ */
+ PANIC("Cannot allocate memory for initial thread");
+ }
+ /* Allocate memory for the scheduler stack: */
+ else if ((_thread_kern_sched_stack = malloc(sched_stack_size)) == NULL)
+ PANIC("Failed to allocate stack for scheduler");
+ else {
+ /* Zero the global kernel thread structure: */
+ memset(&_thread_kern_thread, 0, sizeof(struct pthread));
+ _thread_kern_thread.flags = PTHREAD_FLAGS_PRIVATE;
+ memset(_thread_initial, 0, sizeof(struct pthread));
+
+ /* Initialize the waiting and work queues: */
+ TAILQ_INIT(&_waitingq);
+ TAILQ_INIT(&_workq);
+
+ /* Initialize the scheduling switch hook routine: */
+ _sched_switch_hook = NULL;
+
+ /* Give this thread default attributes: */
+ memcpy((void *) &_thread_initial->attr, &_pthread_attr_default,
+ sizeof(struct pthread_attr));
+
+ /* Find the stack top */
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_USRSTACK;
+ len = sizeof (_usrstack);
+ if (sysctl(mib, 2, &_usrstack, &len, NULL, 0) == -1)
+ _usrstack = (void *)USRSTACK;
+ /*
+ * Create a red zone below the main stack. All other stacks are
+ * constrained to a maximum size by the paramters passed to
+ * mmap(), but this stack is only limited by resource limits, so
+ * this stack needs an explicitly mapped red zone to protect the
+ * thread stack that is just beyond.
+ */
+ if (mmap(_usrstack - _pthread_stack_initial -
+ _pthread_guard_default, _pthread_guard_default, 0,
+ MAP_ANON, -1, 0) == MAP_FAILED)
+ PANIC("Cannot allocate red zone for initial thread");
+
+ /* Set the main thread stack pointer. */
+ _thread_initial->stack = _usrstack - _pthread_stack_initial;
+
+ /* Set the stack attributes: */
+ _thread_initial->attr.stackaddr_attr = _thread_initial->stack;
+ _thread_initial->attr.stacksize_attr = _pthread_stack_initial;
+
+ /* Setup the context for the scheduler: */
+ _setjmp(_thread_kern_sched_jb);
+#if !defined(__ia64__)
+ stackp = (long)_thread_kern_sched_stack + sched_stack_size - sizeof(double);
+#if defined(__amd64__)
+ stackp &= ~0xFUL;
+#endif
+ SET_STACK_JB(_thread_kern_sched_jb, stackp);
+#else
+ SET_STACK_JB(_thread_kern_sched_jb, _thread_kern_sched_stack,
+ sched_stack_size);
+#endif
+ SET_RETURN_ADDR_JB(_thread_kern_sched_jb, _thread_kern_scheduler);
+
+ /*
+ * Write a magic value to the thread structure
+ * to help identify valid ones:
+ */
+ _thread_initial->magic = PTHREAD_MAGIC;
+
+ /* Set the initial cancel state */
+ _thread_initial->cancelflags = PTHREAD_CANCEL_ENABLE |
+ PTHREAD_CANCEL_DEFERRED;
+
+ /* Default the priority of the initial thread: */
+ _thread_initial->base_priority = PTHREAD_DEFAULT_PRIORITY;
+ _thread_initial->active_priority = PTHREAD_DEFAULT_PRIORITY;
+ _thread_initial->inherited_priority = 0;
+
+ /* Initialise the state of the initial thread: */
+ _thread_initial->state = PS_RUNNING;
+
+ /* Set the name of the thread: */
+ _thread_initial->name = strdup("_thread_initial");
+
+ /* Initialize joiner to NULL (no joiner): */
+ _thread_initial->joiner = NULL;
+
+ /* Initialize the owned mutex queue and count: */
+ TAILQ_INIT(&(_thread_initial->mutexq));
+ _thread_initial->priority_mutex_count = 0;
+
+ /* Initialize the global scheduling time: */
+ _sched_ticks = 0;
+ gettimeofday((struct timeval *) &_sched_tod, NULL);
+
+ /* Initialize last active: */
+ _thread_initial->last_active = (long) _sched_ticks;
+
+ /* Initialize the initial context: */
+ _thread_initial->curframe = NULL;
+
+ /* Initialise the rest of the fields: */
+ _thread_initial->poll_data.nfds = 0;
+ _thread_initial->poll_data.fds = NULL;
+ _thread_initial->sig_defer_count = 0;
+ _thread_initial->yield_on_sig_undefer = 0;
+ _thread_initial->specific = NULL;
+ _thread_initial->cleanup = NULL;
+ _thread_initial->flags = 0;
+ _thread_initial->error = 0;
+ TAILQ_INIT(&_thread_list);
+ TAILQ_INSERT_HEAD(&_thread_list, _thread_initial, tle);
+ _set_curthread(_thread_initial);
+ TAILQ_INIT(&_atfork_list);
+ _pthread_mutex_init(&_atfork_mutex, NULL);
+
+ /* Initialise the global signal action structure: */
+ sigfillset(&act.sa_mask);
+ act.sa_handler = (void (*) ()) _thread_sig_handler;
+ act.sa_flags = SA_SIGINFO | SA_RESTART;
+
+ /* Clear pending signals for the process: */
+ sigemptyset(&_process_sigpending);
+
+ /* Clear the signal queue: */
+ memset(_thread_sigq, 0, sizeof(_thread_sigq));
+
+ /* Enter a loop to get the existing signal status: */
+ for (i = 1; i < NSIG; i++) {
+ /* Check for signals which cannot be trapped: */
+ if (i == SIGKILL || i == SIGSTOP) {
+ }
+
+ /* Get the signal handler details: */
+ else if (__sys_sigaction(i, NULL,
+ &_thread_sigact[i - 1]) != 0) {
+ /*
+ * Abort this process if signal
+ * initialisation fails:
+ */
+ PANIC("Cannot read signal handler info");
+ }
+
+ /* Initialize the SIG_DFL dummy handler count. */
+ _thread_dfl_count[i] = 0;
+ }
+
+ /*
+ * Install the signal handler for the most important
+ * signals that the user-thread kernel needs. Actually
+ * SIGINFO isn't really needed, but it is nice to have.
+ */
+ if (__sys_sigaction(_SCHED_SIGNAL, &act, NULL) != 0 ||
+ __sys_sigaction(SIGINFO, &act, NULL) != 0 ||
+ __sys_sigaction(SIGCHLD, &act, NULL) != 0) {
+ /*
+ * Abort this process if signal initialisation fails:
+ */
+ PANIC("Cannot initialise signal handler");
+ }
+ _thread_sigact[_SCHED_SIGNAL - 1].sa_flags = SA_SIGINFO;
+ _thread_sigact[SIGINFO - 1].sa_flags = SA_SIGINFO;
+ _thread_sigact[SIGCHLD - 1].sa_flags = SA_SIGINFO;
+
+ /* Get the process signal mask: */
+ __sys_sigprocmask(SIG_SETMASK, NULL, &_process_sigmask);
+
+ /* Get the kernel clockrate: */
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_CLOCKRATE;
+ len = sizeof (struct clockinfo);
+ if (sysctl(mib, 2, &clockinfo, &len, NULL, 0) == 0)
+ _clock_res_usec = clockinfo.tick > CLOCK_RES_USEC_MIN ?
+ clockinfo.tick : CLOCK_RES_USEC_MIN;
+
+ /* Get the table size: */
+ if ((_thread_dtablesize = getdtablesize()) < 0) {
+ /*
+ * Cannot get the system defined table size, so abort
+ * this process.
+ */
+ PANIC("Cannot get dtablesize");
+ }
+ /* Allocate memory for the file descriptor table: */
+ if ((_thread_fd_table = (struct fd_table_entry **) malloc(sizeof(struct fd_table_entry *) * _thread_dtablesize)) == NULL) {
+ /* Avoid accesses to file descriptor table on exit: */
+ _thread_dtablesize = 0;
+
+ /*
+ * Cannot allocate memory for the file descriptor
+ * table, so abort this process.
+ */
+ PANIC("Cannot allocate memory for file descriptor table");
+ }
+ /* Allocate memory for the pollfd table: */
+ if ((_thread_pfd_table = (struct pollfd *) malloc(sizeof(struct pollfd) * _thread_dtablesize)) == NULL) {
+ /*
+ * Cannot allocate memory for the file descriptor
+ * table, so abort this process.
+ */
+ PANIC("Cannot allocate memory for pollfd table");
+ } else {
+ /*
+ * Enter a loop to initialise the file descriptor
+ * table:
+ */
+ for (i = 0; i < _thread_dtablesize; i++) {
+ /* Initialise the file descriptor table: */
+ _thread_fd_table[i] = NULL;
+ }
+
+ /* Initialize stdio file descriptor table entries: */
+ for (i = 0; i < 3; i++) {
+ if ((_thread_fd_table_init(i) != 0) &&
+ (errno != EBADF))
+ PANIC("Cannot initialize stdio file "
+ "descriptor table entry");
+ }
+ }
+ }
+
+ /* Initialise the garbage collector mutex and condition variable. */
+ if (_pthread_mutex_init(&_gc_mutex,NULL) != 0 ||
+ _pthread_cond_init(&_gc_cond,NULL) != 0)
+ PANIC("Failed to initialise garbage collector mutex or condvar");
+}
+
+
+/*
+ * Special start up code for NetBSD/Alpha
+ */
+#if defined(__NetBSD__) && defined(__alpha__)
+int
+main(int argc, char *argv[], char *env);
+
+int
+_thread_main(int argc, char *argv[], char *env)
+{
+ _thread_init();
+ return (main(argc, argv, env));
+}
+#endif
diff --git a/lib/libc_r/uthread/uthread_ioctl.c b/lib/libc_r/uthread/uthread_ioctl.c
new file mode 100644
index 0000000..7199372
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_ioctl.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <stdarg.h>
+#include <sys/ioctl.h>
+#include <sys/fcntl.h> /* O_NONBLOCK*/
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_ioctl, ioctl);
+
+int
+_ioctl(int fd, unsigned long request,...)
+{
+ int ret;
+ int flags;
+ int *op;
+ va_list ap;
+
+ /* Lock the file descriptor: */
+ if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) {
+ /* Initialise the variable argument list: */
+ va_start(ap, request);
+
+ switch( request) {
+ case FIONBIO:
+ /*
+ * descriptors must be non-blocking; we are only
+ * twiddling the flag based on the request
+ */
+ op = va_arg(ap, int *);
+ flags = _thread_fd_getflags(fd);
+ if (*op == 0)
+ flags &= ~O_NONBLOCK;
+ else
+ flags |= O_NONBLOCK;
+ _thread_fd_setflags(fd, flags);
+ ret = 0;
+ break;
+ default:
+ ret = __sys_ioctl(fd, request, va_arg(ap, char *));
+ break;
+ }
+
+ /* Free variable arguments: */
+ va_end(ap);
+
+ /* Unlock the file descriptor: */
+ _FD_UNLOCK(fd, FD_RDWR);
+ }
+
+ /* Return the completion status: */
+ return (ret);
+}
diff --git a/lib/libc_r/uthread/uthread_jmp.c b/lib/libc_r/uthread/uthread_jmp.c
new file mode 100644
index 0000000..5aa0001
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_jmp.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>.
+ * All rights reserved.
+ * Copyright (C) 2000 Daniel M. Eischen <eischen@vigrid.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(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 <unistd.h>
+#include <setjmp.h>
+#include <sys/param.h>
+#include <machine/reg.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+/* Prototypes: */
+static inline int check_stack(pthread_t thread, void *stackp);
+
+__weak_reference(_thread_siglongjmp, siglongjmp);
+__weak_reference(_thread_longjmp, longjmp);
+__weak_reference(__thread_longjmp, _longjmp);
+
+void
+_thread_siglongjmp(sigjmp_buf env, int savemask)
+{
+ struct pthread *curthread = _get_curthread();
+
+ if (check_stack(curthread, (void *) GET_STACK_SJB(env)))
+ PANIC("siglongjmp()ing between thread contexts is undefined by "
+ "POSIX 1003.1");
+
+ /*
+ * The stack pointer is somewhere within the threads stack.
+ * Jump to the users context.
+ */
+ __siglongjmp(env, savemask);
+}
+
+void
+_thread_longjmp(jmp_buf env, int val)
+{
+ struct pthread *curthread = _get_curthread();
+
+ if (check_stack(curthread, (void *) GET_STACK_JB(env)))
+ PANIC("longjmp()ing between thread contexts is undefined by "
+ "POSIX 1003.1");
+
+ /*
+ * The stack pointer is somewhere within the threads stack.
+ * Jump to the users context.
+ */
+ __longjmp(env, val);
+}
+
+void
+__thread_longjmp(jmp_buf env, int val)
+{
+ struct pthread *curthread = _get_curthread();
+
+ if (check_stack(curthread, (void *) GET_STACK_JB(env)))
+ PANIC("_longjmp()ing between thread contexts is undefined by "
+ "POSIX 1003.1");
+
+ /*
+ * The stack pointer is somewhere within the threads stack.
+ * Jump to the users context.
+ */
+ ___longjmp(env, val);
+}
+
+/* Returns 0 if stack check is OK, non-zero otherwise. */
+static inline int
+check_stack(pthread_t thread, void *stackp)
+{
+ void *stack_begin, *stack_end;
+
+ /* Get the bounds of the current threads stack. */
+ PTHREAD_ASSERT(thread->stack != NULL,
+ "Thread stack pointer is null");
+ stack_begin = thread->stack;
+ stack_end = stack_begin + thread->attr.stacksize_attr;
+
+ /*
+ * Make sure we aren't jumping to a different stack. Make sure
+ * jmp_stackp is between stack_begin and stack end, to correctly detect
+ * this condition regardless of whether the stack grows up or down.
+ */
+ if (((stackp < stack_begin) && (stackp < stack_end)) ||
+ ((stackp > stack_begin) && (stackp > stack_end)))
+ return (1);
+ else
+ return (0);
+}
diff --git a/lib/libc_r/uthread/uthread_join.c b/lib/libc_r/uthread/uthread_join.c
new file mode 100644
index 0000000..a410a01
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_join.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include "namespace.h"
+#include <pthread.h>
+#include "un-namespace.h"
+#include "pthread_private.h"
+
+__weak_reference(_pthread_join, pthread_join);
+
+int
+_pthread_join(pthread_t pthread, void **thread_return)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret = 0;
+ pthread_t thread;
+
+ _thread_enter_cancellation_point();
+
+ /* Check if the caller has specified an invalid thread: */
+ if (pthread == NULL || pthread->magic != PTHREAD_MAGIC) {
+ /* Invalid thread: */
+ _thread_leave_cancellation_point();
+ return(EINVAL);
+ }
+
+ /* Check if the caller has specified itself: */
+ if (pthread == curthread) {
+ /* Avoid a deadlock condition: */
+ _thread_leave_cancellation_point();
+ return(EDEADLK);
+ }
+
+ /*
+ * Lock the garbage collector mutex to ensure that the garbage
+ * collector is not using the dead thread list.
+ */
+ if (_pthread_mutex_lock(&_gc_mutex) != 0)
+ PANIC("Cannot lock gc mutex");
+
+ /*
+ * Defer signals to protect the thread list from access
+ * by the signal handler:
+ */
+ _thread_kern_sig_defer();
+
+ /*
+ * Unlock the garbage collector mutex, now that the garbage collector
+ * can't be run:
+ */
+ if (_pthread_mutex_unlock(&_gc_mutex) != 0)
+ PANIC("Cannot lock gc mutex");
+
+ /*
+ * Search for the specified thread in the list of active threads. This
+ * is done manually here rather than calling _find_thread() because
+ * the searches in _thread_list and _dead_list (as well as setting up
+ * join/detach state) have to be done atomically.
+ */
+ TAILQ_FOREACH(thread, &_thread_list, tle) {
+ if (thread == pthread)
+ break;
+ }
+ if (thread == NULL) {
+ /*
+ * Search for the specified thread in the list of dead threads:
+ */
+ TAILQ_FOREACH(thread, &_dead_list, dle) {
+ if (thread == pthread)
+ break;
+ }
+ }
+
+ /* Check if the thread was not found or has been detached: */
+ if (thread == NULL ||
+ ((pthread->attr.flags & PTHREAD_DETACHED) != 0)) {
+ /* Undefer and handle pending signals, yielding if necessary: */
+ _thread_kern_sig_undefer();
+
+ /* Return an error: */
+ ret = ESRCH;
+
+ } else if (pthread->joiner != NULL) {
+ /* Undefer and handle pending signals, yielding if necessary: */
+ _thread_kern_sig_undefer();
+
+ /* Multiple joiners are not supported. */
+ ret = ENOTSUP;
+
+ /* Check if the thread is not dead: */
+ } else if (pthread->state != PS_DEAD) {
+ /* Set the running thread to be the joiner: */
+ pthread->joiner = curthread;
+
+ /* Keep track of which thread we're joining to: */
+ curthread->join_status.thread = pthread;
+
+ while (curthread->join_status.thread == pthread) {
+ /* Schedule the next thread: */
+ _thread_kern_sched_state(PS_JOIN, __FILE__, __LINE__);
+ }
+
+ /*
+ * The thread return value and error are set by the thread we're
+ * joining to when it exits or detaches:
+ */
+ ret = curthread->join_status.error;
+ if ((ret == 0) && (thread_return != NULL))
+ *thread_return = curthread->join_status.ret;
+
+ /* Undefer and handle pending signals, yielding if necessary: */
+ _thread_kern_sig_undefer();
+ } else {
+ /*
+ * The thread exited (is dead) without being detached, and no
+ * thread has joined it.
+ */
+
+ /* Check if the return value is required: */
+ if (thread_return != NULL) {
+ /* Return the thread's return value: */
+ *thread_return = pthread->ret;
+ }
+
+ /* Make the thread collectable by the garbage collector. */
+ pthread->attr.flags |= PTHREAD_DETACHED;
+
+ /* Undefer and handle pending signals, yielding if necessary: */
+ _thread_kern_sig_undefer();
+ }
+
+ _thread_leave_cancellation_point();
+
+ /* Return the completion status: */
+ return (ret);
+}
diff --git a/lib/libc_r/uthread/uthread_kern.c b/lib/libc_r/uthread/uthread_kern.c
new file mode 100644
index 0000000..35953a5
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_kern.c
@@ -0,0 +1,1138 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ */
+#include <errno.h>
+#include <poll.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <setjmp.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/signalvar.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <sys/syscall.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+/* #define DEBUG_THREAD_KERN */
+#ifdef DEBUG_THREAD_KERN
+#define DBG_MSG stdout_debug
+#else
+#define DBG_MSG(x...)
+#endif
+
+/* Static function prototype definitions: */
+static void
+thread_kern_poll(int wait_reqd);
+
+static void
+dequeue_signals(void);
+
+static inline void
+thread_run_switch_hook(pthread_t thread_out, pthread_t thread_in);
+
+/* Static variables: */
+static int last_tick = 0;
+static int called_from_handler = 0;
+
+/*
+ * This is called when a signal handler finishes and wants to
+ * return to a previous frame.
+ */
+void
+_thread_kern_sched_frame(struct pthread_signal_frame *psf)
+{
+ struct pthread *curthread = _get_curthread();
+
+ /*
+ * Flag the pthread kernel as executing scheduler code
+ * to avoid a signal from interrupting this execution and
+ * corrupting the (soon-to-be) current frame.
+ */
+ _thread_kern_in_sched = 1;
+
+ /* Restore the signal frame: */
+ _thread_sigframe_restore(curthread, psf);
+
+ /* The signal mask was restored; check for any pending signals: */
+ curthread->check_pending = 1;
+
+ /* Switch to the thread scheduler: */
+ ___longjmp(_thread_kern_sched_jb, 1);
+}
+
+
+void
+_thread_kern_sched(ucontext_t *ucp)
+{
+ struct pthread *curthread = _get_curthread();
+
+ /*
+ * Flag the pthread kernel as executing scheduler code
+ * to avoid a scheduler signal from interrupting this
+ * execution and calling the scheduler again.
+ */
+ _thread_kern_in_sched = 1;
+
+ /* Check if this function was called from the signal handler: */
+ if (ucp != NULL) {
+ called_from_handler = 1;
+ DBG_MSG("Entering scheduler due to signal\n");
+ }
+
+ /* Save the state of the current thread: */
+ if (_setjmp(curthread->ctx.jb) != 0) {
+ DBG_MSG("Returned from ___longjmp, thread %p\n",
+ curthread);
+ /*
+ * This point is reached when a longjmp() is called
+ * to restore the state of a thread.
+ *
+ * This is the normal way out of the scheduler.
+ */
+ _thread_kern_in_sched = 0;
+
+ if (curthread->sig_defer_count == 0) {
+ if (((curthread->cancelflags &
+ PTHREAD_AT_CANCEL_POINT) == 0) &&
+ ((curthread->cancelflags &
+ PTHREAD_CANCEL_ASYNCHRONOUS) != 0))
+ /*
+ * Cancellations override signals.
+ *
+ * Stick a cancellation point at the
+ * start of each async-cancellable
+ * thread's resumption.
+ *
+ * We allow threads woken at cancel
+ * points to do their own checks.
+ */
+ pthread_testcancel();
+ }
+
+ if (_sched_switch_hook != NULL) {
+ /* Run the installed switch hook: */
+ thread_run_switch_hook(_last_user_thread, curthread);
+ }
+ if (ucp == NULL)
+ return;
+ else {
+ /*
+ * Set the process signal mask in the context; it
+ * could have changed by the handler.
+ */
+ ucp->uc_sigmask = _process_sigmask;
+
+ /* Resume the interrupted thread: */
+ __sys_sigreturn(ucp);
+ }
+ }
+ /* Switch to the thread scheduler: */
+ ___longjmp(_thread_kern_sched_jb, 1);
+}
+
+void
+_thread_kern_sched_sig(void)
+{
+ struct pthread *curthread = _get_curthread();
+
+ curthread->check_pending = 1;
+ _thread_kern_sched(NULL);
+}
+
+
+void
+_thread_kern_scheduler(void)
+{
+ struct timespec ts;
+ struct timeval tv;
+ struct pthread *curthread = _get_curthread();
+ pthread_t pthread, pthread_h;
+ unsigned int current_tick;
+ int add_to_prioq;
+
+ /* If the currently running thread is a user thread, save it: */
+ if ((curthread->flags & PTHREAD_FLAGS_PRIVATE) == 0)
+ _last_user_thread = curthread;
+
+ if (called_from_handler != 0) {
+ called_from_handler = 0;
+
+ /*
+ * We were called from a signal handler; restore the process
+ * signal mask.
+ */
+ if (__sys_sigprocmask(SIG_SETMASK,
+ &_process_sigmask, NULL) != 0)
+ PANIC("Unable to restore process mask after signal");
+ }
+
+ /*
+ * Enter a scheduling loop that finds the next thread that is
+ * ready to run. This loop completes when there are no more threads
+ * in the global list or when a thread has its state restored by
+ * either a sigreturn (if the state was saved as a sigcontext) or a
+ * longjmp (if the state was saved by a setjmp).
+ */
+ while (!(TAILQ_EMPTY(&_thread_list))) {
+ /* Get the current time of day: */
+ GET_CURRENT_TOD(tv);
+ TIMEVAL_TO_TIMESPEC(&tv, &ts);
+ current_tick = _sched_ticks;
+
+ /*
+ * Protect the scheduling queues from access by the signal
+ * handler.
+ */
+ _queue_signals = 1;
+ add_to_prioq = 0;
+
+ if (curthread != &_thread_kern_thread) {
+ /*
+ * This thread no longer needs to yield the CPU.
+ */
+ curthread->yield_on_sig_undefer = 0;
+
+ if (curthread->state != PS_RUNNING) {
+ /*
+ * Save the current time as the time that the
+ * thread became inactive:
+ */
+ curthread->last_inactive = (long)current_tick;
+ if (curthread->last_inactive <
+ curthread->last_active) {
+ /* Account for a rollover: */
+ curthread->last_inactive =+
+ UINT_MAX + 1;
+ }
+ }
+
+ /*
+ * Place the currently running thread into the
+ * appropriate queue(s).
+ */
+ switch (curthread->state) {
+ case PS_DEAD:
+ case PS_STATE_MAX: /* to silence -Wall */
+ case PS_SUSPENDED:
+ /*
+ * Dead and suspended threads are not placed
+ * in any queue:
+ */
+ break;
+
+ case PS_RUNNING:
+ /*
+ * Runnable threads can't be placed in the
+ * priority queue until after waiting threads
+ * are polled (to preserve round-robin
+ * scheduling).
+ */
+ add_to_prioq = 1;
+ break;
+
+ /*
+ * States which do not depend on file descriptor I/O
+ * operations or timeouts:
+ */
+ case PS_DEADLOCK:
+ case PS_FDLR_WAIT:
+ case PS_FDLW_WAIT:
+ case PS_FILE_WAIT:
+ case PS_JOIN:
+ case PS_MUTEX_WAIT:
+ case PS_SIGSUSPEND:
+ case PS_SIGTHREAD:
+ case PS_SIGWAIT:
+ case PS_WAIT_WAIT:
+ /* No timeouts for these states: */
+ curthread->wakeup_time.tv_sec = -1;
+ curthread->wakeup_time.tv_nsec = -1;
+
+ /* Restart the time slice: */
+ curthread->slice_usec = -1;
+
+ /* Insert into the waiting queue: */
+ PTHREAD_WAITQ_INSERT(curthread);
+ break;
+
+ /* States which can timeout: */
+ case PS_COND_WAIT:
+ case PS_SLEEP_WAIT:
+ /* Restart the time slice: */
+ curthread->slice_usec = -1;
+
+ /* Insert into the waiting queue: */
+ PTHREAD_WAITQ_INSERT(curthread);
+ break;
+
+ /* States that require periodic work: */
+ case PS_SPINBLOCK:
+ /* No timeouts for this state: */
+ curthread->wakeup_time.tv_sec = -1;
+ curthread->wakeup_time.tv_nsec = -1;
+
+ /* Increment spinblock count: */
+ _spinblock_count++;
+
+ /* FALLTHROUGH */
+ case PS_FDR_WAIT:
+ case PS_FDW_WAIT:
+ case PS_POLL_WAIT:
+ case PS_SELECT_WAIT:
+ /* Restart the time slice: */
+ curthread->slice_usec = -1;
+
+ /* Insert into the waiting queue: */
+ PTHREAD_WAITQ_INSERT(curthread);
+
+ /* Insert into the work queue: */
+ PTHREAD_WORKQ_INSERT(curthread);
+ break;
+ }
+
+ /*
+ * Are there pending signals for this thread?
+ *
+ * This check has to be performed after the thread
+ * has been placed in the queue(s) appropriate for
+ * its state. The process of adding pending signals
+ * can change a threads state, which in turn will
+ * attempt to add or remove the thread from any
+ * scheduling queue to which it belongs.
+ */
+ if (curthread->check_pending != 0) {
+ curthread->check_pending = 0;
+ _thread_sig_check_pending(curthread);
+ }
+ }
+
+ /*
+ * Avoid polling file descriptors if there are none
+ * waiting:
+ */
+ if (TAILQ_EMPTY(&_workq) != 0) {
+ }
+ /*
+ * Poll file descriptors only if a new scheduling signal
+ * has occurred or if we have no more runnable threads.
+ */
+ else if (((current_tick = _sched_ticks) != last_tick) ||
+ ((curthread->state != PS_RUNNING) &&
+ (PTHREAD_PRIOQ_FIRST() == NULL))) {
+ /* Unprotect the scheduling queues: */
+ _queue_signals = 0;
+
+ /*
+ * Poll file descriptors to update the state of threads
+ * waiting on file I/O where data may be available:
+ */
+ thread_kern_poll(0);
+
+ /* Protect the scheduling queues: */
+ _queue_signals = 1;
+ }
+ last_tick = current_tick;
+
+ /*
+ * Wake up threads that have timedout. This has to be
+ * done after polling in case a thread does a poll or
+ * select with zero time.
+ */
+ PTHREAD_WAITQ_SETACTIVE();
+ while (((pthread = TAILQ_FIRST(&_waitingq)) != NULL) &&
+ (pthread->wakeup_time.tv_sec != -1) &&
+ (((pthread->wakeup_time.tv_sec == 0) &&
+ (pthread->wakeup_time.tv_nsec == 0)) ||
+ (pthread->wakeup_time.tv_sec < ts.tv_sec) ||
+ ((pthread->wakeup_time.tv_sec == ts.tv_sec) &&
+ (pthread->wakeup_time.tv_nsec <= ts.tv_nsec)))) {
+ switch (pthread->state) {
+ case PS_POLL_WAIT:
+ case PS_SELECT_WAIT:
+ /* Return zero file descriptors ready: */
+ pthread->data.poll_data->nfds = 0;
+ /* FALLTHROUGH */
+ default:
+ /*
+ * Remove this thread from the waiting queue
+ * (and work queue if necessary) and place it
+ * in the ready queue.
+ */
+ PTHREAD_WAITQ_CLEARACTIVE();
+ if (pthread->flags & PTHREAD_FLAGS_IN_WORKQ)
+ PTHREAD_WORKQ_REMOVE(pthread);
+ PTHREAD_NEW_STATE(pthread, PS_RUNNING);
+ PTHREAD_WAITQ_SETACTIVE();
+ break;
+ }
+ /*
+ * Flag the timeout in the thread structure:
+ */
+ pthread->timeout = 1;
+ }
+ PTHREAD_WAITQ_CLEARACTIVE();
+
+ /*
+ * Check to see if the current thread needs to be added
+ * to the priority queue:
+ */
+ if (add_to_prioq != 0) {
+ /*
+ * Save the current time as the time that the
+ * thread became inactive:
+ */
+ current_tick = _sched_ticks;
+ curthread->last_inactive = (long)current_tick;
+ if (curthread->last_inactive <
+ curthread->last_active) {
+ /* Account for a rollover: */
+ curthread->last_inactive =+ UINT_MAX + 1;
+ }
+
+ if ((curthread->slice_usec != -1) &&
+ (curthread->attr.sched_policy != SCHED_FIFO)) {
+ /*
+ * Accumulate the number of microseconds for
+ * which the current thread has run:
+ */
+ curthread->slice_usec +=
+ (curthread->last_inactive -
+ curthread->last_active) *
+ (long)_clock_res_usec;
+ /* Check for time quantum exceeded: */
+ if (curthread->slice_usec > TIMESLICE_USEC)
+ curthread->slice_usec = -1;
+ }
+
+ if (curthread->slice_usec == -1) {
+ /*
+ * The thread exceeded its time
+ * quantum or it yielded the CPU;
+ * place it at the tail of the
+ * queue for its priority.
+ */
+ PTHREAD_PRIOQ_INSERT_TAIL(curthread);
+ } else {
+ /*
+ * The thread hasn't exceeded its
+ * interval. Place it at the head
+ * of the queue for its priority.
+ */
+ PTHREAD_PRIOQ_INSERT_HEAD(curthread);
+ }
+ }
+
+ /*
+ * Get the highest priority thread in the ready queue.
+ */
+ pthread_h = PTHREAD_PRIOQ_FIRST();
+
+ /* Check if there are no threads ready to run: */
+ if (pthread_h == NULL) {
+ /*
+ * Lock the pthread kernel by changing the pointer to
+ * the running thread to point to the global kernel
+ * thread structure:
+ */
+ _set_curthread(&_thread_kern_thread);
+ curthread = &_thread_kern_thread;
+
+ DBG_MSG("No runnable threads, using kernel thread %p\n",
+ curthread);
+
+ /* Unprotect the scheduling queues: */
+ _queue_signals = 0;
+
+ /*
+ * There are no threads ready to run, so wait until
+ * something happens that changes this condition:
+ */
+ thread_kern_poll(1);
+
+ /*
+ * This process' usage will likely be very small
+ * while waiting in a poll. Since the scheduling
+ * clock is based on the profiling timer, it is
+ * unlikely that the profiling timer will fire
+ * and update the time of day. To account for this,
+ * get the time of day after polling with a timeout.
+ */
+ gettimeofday((struct timeval *) &_sched_tod, NULL);
+
+ /* Check once more for a runnable thread: */
+ _queue_signals = 1;
+ pthread_h = PTHREAD_PRIOQ_FIRST();
+ _queue_signals = 0;
+ }
+
+ if (pthread_h != NULL) {
+ /* Remove the thread from the ready queue: */
+ PTHREAD_PRIOQ_REMOVE(pthread_h);
+
+ /* Unprotect the scheduling queues: */
+ _queue_signals = 0;
+
+ /*
+ * Check for signals queued while the scheduling
+ * queues were protected:
+ */
+ while (_sigq_check_reqd != 0) {
+ /* Clear before handling queued signals: */
+ _sigq_check_reqd = 0;
+
+ /* Protect the scheduling queues again: */
+ _queue_signals = 1;
+
+ dequeue_signals();
+
+ /*
+ * Check for a higher priority thread that
+ * became runnable due to signal handling.
+ */
+ if (((pthread = PTHREAD_PRIOQ_FIRST()) != NULL) &&
+ (pthread->active_priority > pthread_h->active_priority)) {
+ /* Remove the thread from the ready queue: */
+ PTHREAD_PRIOQ_REMOVE(pthread);
+
+ /*
+ * Insert the lower priority thread
+ * at the head of its priority list:
+ */
+ PTHREAD_PRIOQ_INSERT_HEAD(pthread_h);
+
+ /* There's a new thread in town: */
+ pthread_h = pthread;
+ }
+
+ /* Unprotect the scheduling queues: */
+ _queue_signals = 0;
+ }
+
+ /* Make the selected thread the current thread: */
+ _set_curthread(pthread_h);
+ curthread = pthread_h;
+
+ /*
+ * Save the current time as the time that the thread
+ * became active:
+ */
+ current_tick = _sched_ticks;
+ curthread->last_active = (long) current_tick;
+
+ /*
+ * Check if this thread is running for the first time
+ * or running again after using its full time slice
+ * allocation:
+ */
+ if (curthread->slice_usec == -1) {
+ /* Reset the accumulated time slice period: */
+ curthread->slice_usec = 0;
+ }
+
+ /*
+ * If we had a context switch, run any
+ * installed switch hooks.
+ */
+ if ((_sched_switch_hook != NULL) &&
+ (_last_user_thread != curthread)) {
+ thread_run_switch_hook(_last_user_thread,
+ curthread);
+ }
+ /*
+ * Continue the thread at its current frame:
+ */
+#if NOT_YET
+ _setcontext(&curthread->ctx.uc);
+#else
+ ___longjmp(curthread->ctx.jb, 1);
+#endif
+ /* This point should not be reached. */
+ PANIC("Thread has returned from sigreturn or longjmp");
+ }
+ }
+
+ /* There are no more threads, so exit this process: */
+ exit(0);
+}
+
+void
+_thread_kern_sched_state(enum pthread_state state, char *fname, int lineno)
+{
+ struct pthread *curthread = _get_curthread();
+
+ /*
+ * Flag the pthread kernel as executing scheduler code
+ * to avoid a scheduler signal from interrupting this
+ * execution and calling the scheduler again.
+ */
+ _thread_kern_in_sched = 1;
+
+ /*
+ * Prevent the signal handler from fiddling with this thread
+ * before its state is set and is placed into the proper queue.
+ */
+ _queue_signals = 1;
+
+ /* Change the state of the current thread: */
+ curthread->state = state;
+ curthread->fname = fname;
+ curthread->lineno = lineno;
+
+ /* Schedule the next thread that is ready: */
+ _thread_kern_sched(NULL);
+}
+
+void
+_thread_kern_sched_state_unlock(enum pthread_state state,
+ spinlock_t *lock, char *fname, int lineno)
+{
+ struct pthread *curthread = _get_curthread();
+
+ /*
+ * Flag the pthread kernel as executing scheduler code
+ * to avoid a scheduler signal from interrupting this
+ * execution and calling the scheduler again.
+ */
+ _thread_kern_in_sched = 1;
+
+ /*
+ * Prevent the signal handler from fiddling with this thread
+ * before its state is set and it is placed into the proper
+ * queue(s).
+ */
+ _queue_signals = 1;
+
+ /* Change the state of the current thread: */
+ curthread->state = state;
+ curthread->fname = fname;
+ curthread->lineno = lineno;
+
+ _SPINUNLOCK(lock);
+
+ /* Schedule the next thread that is ready: */
+ _thread_kern_sched(NULL);
+}
+
+static void
+thread_kern_poll(int wait_reqd)
+{
+ int count = 0;
+ int i, found;
+ int kern_pipe_added = 0;
+ int nfds = 0;
+ int timeout_ms = 0;
+ struct pthread *pthread;
+ struct timespec ts;
+ struct timeval tv;
+
+ /* Check if the caller wants to wait: */
+ if (wait_reqd == 0) {
+ timeout_ms = 0;
+ }
+ else {
+ /* Get the current time of day: */
+ GET_CURRENT_TOD(tv);
+ TIMEVAL_TO_TIMESPEC(&tv, &ts);
+
+ _queue_signals = 1;
+ pthread = TAILQ_FIRST(&_waitingq);
+ _queue_signals = 0;
+
+ if ((pthread == NULL) || (pthread->wakeup_time.tv_sec == -1)) {
+ /*
+ * Either there are no threads in the waiting queue,
+ * or there are no threads that can timeout.
+ */
+ timeout_ms = INFTIM;
+ }
+ else if (pthread->wakeup_time.tv_sec - ts.tv_sec > 60000)
+ /* Limit maximum timeout to prevent rollover. */
+ timeout_ms = 60000;
+ else {
+ /*
+ * Calculate the time left for the next thread to
+ * timeout:
+ */
+ timeout_ms = ((pthread->wakeup_time.tv_sec - ts.tv_sec) *
+ 1000) + ((pthread->wakeup_time.tv_nsec - ts.tv_nsec) /
+ 1000000);
+ /*
+ * Don't allow negative timeouts:
+ */
+ if (timeout_ms < 0)
+ timeout_ms = 0;
+ }
+ }
+
+ /* Protect the scheduling queues: */
+ _queue_signals = 1;
+
+ /*
+ * Check to see if the signal queue needs to be walked to look
+ * for threads awoken by a signal while in the scheduler.
+ */
+ if (_sigq_check_reqd != 0) {
+ /* Reset flag before handling queued signals: */
+ _sigq_check_reqd = 0;
+
+ dequeue_signals();
+ }
+
+ /*
+ * Check for a thread that became runnable due to a signal:
+ */
+ if (PTHREAD_PRIOQ_FIRST() != NULL) {
+ /*
+ * Since there is at least one runnable thread,
+ * disable the wait.
+ */
+ timeout_ms = 0;
+ }
+
+ /*
+ * Form the poll table:
+ */
+ nfds = 0;
+ if (timeout_ms != 0) {
+ /* Add the kernel pipe to the poll table: */
+ _thread_pfd_table[nfds].fd = _thread_kern_pipe[0];
+ _thread_pfd_table[nfds].events = POLLRDNORM;
+ _thread_pfd_table[nfds].revents = 0;
+ nfds++;
+ kern_pipe_added = 1;
+ }
+
+ PTHREAD_WAITQ_SETACTIVE();
+ TAILQ_FOREACH(pthread, &_workq, qe) {
+ switch (pthread->state) {
+ case PS_SPINBLOCK:
+ /*
+ * If the lock is available, let the thread run.
+ */
+ if (pthread->data.spinlock->access_lock == 0) {
+ PTHREAD_WAITQ_CLEARACTIVE();
+ PTHREAD_WORKQ_REMOVE(pthread);
+ PTHREAD_NEW_STATE(pthread,PS_RUNNING);
+ PTHREAD_WAITQ_SETACTIVE();
+ /* One less thread in a spinblock state: */
+ _spinblock_count--;
+ /*
+ * Since there is at least one runnable
+ * thread, disable the wait.
+ */
+ timeout_ms = 0;
+ }
+ break;
+
+ /* File descriptor read wait: */
+ case PS_FDR_WAIT:
+ /* Limit number of polled files to table size: */
+ if (nfds < _thread_dtablesize) {
+ _thread_pfd_table[nfds].events = POLLRDNORM;
+ _thread_pfd_table[nfds].fd = pthread->data.fd.fd;
+ nfds++;
+ }
+ break;
+
+ /* File descriptor write wait: */
+ case PS_FDW_WAIT:
+ /* Limit number of polled files to table size: */
+ if (nfds < _thread_dtablesize) {
+ _thread_pfd_table[nfds].events = POLLWRNORM;
+ _thread_pfd_table[nfds].fd = pthread->data.fd.fd;
+ nfds++;
+ }
+ break;
+
+ /* File descriptor poll or select wait: */
+ case PS_POLL_WAIT:
+ case PS_SELECT_WAIT:
+ /* Limit number of polled files to table size: */
+ if (pthread->data.poll_data->nfds + nfds <
+ _thread_dtablesize) {
+ for (i = 0; i < pthread->data.poll_data->nfds; i++) {
+ _thread_pfd_table[nfds + i].fd =
+ pthread->data.poll_data->fds[i].fd;
+ _thread_pfd_table[nfds + i].events =
+ pthread->data.poll_data->fds[i].events;
+ }
+ nfds += pthread->data.poll_data->nfds;
+ }
+ break;
+
+ /* Other states do not depend on file I/O. */
+ default:
+ break;
+ }
+ }
+ PTHREAD_WAITQ_CLEARACTIVE();
+
+ /*
+ * Wait for a file descriptor to be ready for read, write, or
+ * an exception, or a timeout to occur:
+ */
+ count = __sys_poll(_thread_pfd_table, nfds, timeout_ms);
+
+ if (kern_pipe_added != 0)
+ /*
+ * Remove the pthread kernel pipe file descriptor
+ * from the pollfd table:
+ */
+ nfds = 1;
+ else
+ nfds = 0;
+
+ /*
+ * Check if it is possible that there are bytes in the kernel
+ * read pipe waiting to be read:
+ */
+ if (count < 0 || ((kern_pipe_added != 0) &&
+ (_thread_pfd_table[0].revents & POLLRDNORM))) {
+ /*
+ * If the kernel read pipe was included in the
+ * count:
+ */
+ if (count > 0) {
+ /* Decrement the count of file descriptors: */
+ count--;
+ }
+
+ if (_sigq_check_reqd != 0) {
+ /* Reset flag before handling signals: */
+ _sigq_check_reqd = 0;
+
+ dequeue_signals();
+ }
+ }
+
+ /*
+ * Check if any file descriptors are ready:
+ */
+ if (count > 0) {
+ /*
+ * Enter a loop to look for threads waiting on file
+ * descriptors that are flagged as available by the
+ * _poll syscall:
+ */
+ PTHREAD_WAITQ_SETACTIVE();
+ TAILQ_FOREACH(pthread, &_workq, qe) {
+ switch (pthread->state) {
+ case PS_SPINBLOCK:
+ /*
+ * If the lock is available, let the thread run.
+ */
+ if (pthread->data.spinlock->access_lock == 0) {
+ PTHREAD_WAITQ_CLEARACTIVE();
+ PTHREAD_WORKQ_REMOVE(pthread);
+ PTHREAD_NEW_STATE(pthread,PS_RUNNING);
+ PTHREAD_WAITQ_SETACTIVE();
+
+ /*
+ * One less thread in a spinblock state:
+ */
+ _spinblock_count--;
+ }
+ break;
+
+ /* File descriptor read wait: */
+ case PS_FDR_WAIT:
+ if ((nfds < _thread_dtablesize) &&
+ (_thread_pfd_table[nfds].revents
+ & (POLLRDNORM|POLLERR|POLLHUP|POLLNVAL))
+ != 0) {
+ PTHREAD_WAITQ_CLEARACTIVE();
+ PTHREAD_WORKQ_REMOVE(pthread);
+ PTHREAD_NEW_STATE(pthread,PS_RUNNING);
+ PTHREAD_WAITQ_SETACTIVE();
+ }
+ nfds++;
+ break;
+
+ /* File descriptor write wait: */
+ case PS_FDW_WAIT:
+ if ((nfds < _thread_dtablesize) &&
+ (_thread_pfd_table[nfds].revents
+ & (POLLWRNORM|POLLERR|POLLHUP|POLLNVAL))
+ != 0) {
+ PTHREAD_WAITQ_CLEARACTIVE();
+ PTHREAD_WORKQ_REMOVE(pthread);
+ PTHREAD_NEW_STATE(pthread,PS_RUNNING);
+ PTHREAD_WAITQ_SETACTIVE();
+ }
+ nfds++;
+ break;
+
+ /* File descriptor poll or select wait: */
+ case PS_POLL_WAIT:
+ case PS_SELECT_WAIT:
+ if (pthread->data.poll_data->nfds + nfds <
+ _thread_dtablesize) {
+ /*
+ * Enter a loop looking for I/O
+ * readiness:
+ */
+ found = 0;
+ for (i = 0; i < pthread->data.poll_data->nfds; i++) {
+ if (_thread_pfd_table[nfds + i].revents != 0) {
+ pthread->data.poll_data->fds[i].revents =
+ _thread_pfd_table[nfds + i].revents;
+ found++;
+ }
+ }
+
+ /* Increment before destroying: */
+ nfds += pthread->data.poll_data->nfds;
+
+ if (found != 0) {
+ pthread->data.poll_data->nfds = found;
+ PTHREAD_WAITQ_CLEARACTIVE();
+ PTHREAD_WORKQ_REMOVE(pthread);
+ PTHREAD_NEW_STATE(pthread,PS_RUNNING);
+ PTHREAD_WAITQ_SETACTIVE();
+ }
+ }
+ else
+ nfds += pthread->data.poll_data->nfds;
+ break;
+
+ /* Other states do not depend on file I/O. */
+ default:
+ break;
+ }
+ }
+ PTHREAD_WAITQ_CLEARACTIVE();
+ }
+ else if (_spinblock_count != 0) {
+ /*
+ * Enter a loop to look for threads waiting on a spinlock
+ * that is now available.
+ */
+ PTHREAD_WAITQ_SETACTIVE();
+ TAILQ_FOREACH(pthread, &_workq, qe) {
+ if (pthread->state == PS_SPINBLOCK) {
+ /*
+ * If the lock is available, let the thread run.
+ */
+ if (pthread->data.spinlock->access_lock == 0) {
+ PTHREAD_WAITQ_CLEARACTIVE();
+ PTHREAD_WORKQ_REMOVE(pthread);
+ PTHREAD_NEW_STATE(pthread,PS_RUNNING);
+ PTHREAD_WAITQ_SETACTIVE();
+
+ /*
+ * One less thread in a spinblock state:
+ */
+ _spinblock_count--;
+ }
+ }
+ }
+ PTHREAD_WAITQ_CLEARACTIVE();
+ }
+
+ /* Unprotect the scheduling queues: */
+ _queue_signals = 0;
+
+ while (_sigq_check_reqd != 0) {
+ /* Handle queued signals: */
+ _sigq_check_reqd = 0;
+
+ /* Protect the scheduling queues: */
+ _queue_signals = 1;
+
+ dequeue_signals();
+
+ /* Unprotect the scheduling queues: */
+ _queue_signals = 0;
+ }
+}
+
+void
+_thread_kern_set_timeout(const struct timespec * timeout)
+{
+ struct pthread *curthread = _get_curthread();
+ struct timespec current_time;
+ struct timeval tv;
+
+ /* Reset the timeout flag for the running thread: */
+ curthread->timeout = 0;
+
+ /* Check if the thread is to wait forever: */
+ if (timeout == NULL) {
+ /*
+ * Set the wakeup time to something that can be recognised as
+ * different to an actual time of day:
+ */
+ curthread->wakeup_time.tv_sec = -1;
+ curthread->wakeup_time.tv_nsec = -1;
+ }
+ /* Check if no waiting is required: */
+ else if (timeout->tv_sec == 0 && timeout->tv_nsec == 0) {
+ /* Set the wake up time to 'immediately': */
+ curthread->wakeup_time.tv_sec = 0;
+ curthread->wakeup_time.tv_nsec = 0;
+ } else {
+ /* Get the current time: */
+ GET_CURRENT_TOD(tv);
+ TIMEVAL_TO_TIMESPEC(&tv, &current_time);
+
+ /* Calculate the time for the current thread to wake up: */
+ curthread->wakeup_time.tv_sec = current_time.tv_sec + timeout->tv_sec;
+ curthread->wakeup_time.tv_nsec = current_time.tv_nsec + timeout->tv_nsec;
+
+ /* Check if the nanosecond field needs to wrap: */
+ if (curthread->wakeup_time.tv_nsec >= 1000000000) {
+ /* Wrap the nanosecond field: */
+ curthread->wakeup_time.tv_sec += 1;
+ curthread->wakeup_time.tv_nsec -= 1000000000;
+ }
+ }
+}
+
+void
+_thread_kern_sig_defer(void)
+{
+ struct pthread *curthread = _get_curthread();
+
+ /* Allow signal deferral to be recursive. */
+ curthread->sig_defer_count++;
+}
+
+void
+_thread_kern_sig_undefer(void)
+{
+ struct pthread *curthread = _get_curthread();
+
+ /*
+ * Perform checks to yield only if we are about to undefer
+ * signals.
+ */
+ if (curthread->sig_defer_count > 1) {
+ /* Decrement the signal deferral count. */
+ curthread->sig_defer_count--;
+ }
+ else if (curthread->sig_defer_count == 1) {
+ /* Reenable signals: */
+ curthread->sig_defer_count = 0;
+
+ /*
+ * Check if there are queued signals:
+ */
+ if (_sigq_check_reqd != 0)
+ _thread_kern_sched(NULL);
+
+ /*
+ * Check for asynchronous cancellation before delivering any
+ * pending signals:
+ */
+ if (((curthread->cancelflags & PTHREAD_AT_CANCEL_POINT) == 0) &&
+ ((curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0))
+ pthread_testcancel();
+
+ /*
+ * If there are pending signals or this thread has
+ * to yield the CPU, call the kernel scheduler:
+ *
+ * XXX - Come back and revisit the pending signal problem
+ */
+ if ((curthread->yield_on_sig_undefer != 0) ||
+ SIGNOTEMPTY(curthread->sigpend)) {
+ curthread->yield_on_sig_undefer = 0;
+ _thread_kern_sched(NULL);
+ }
+ }
+}
+
+static void
+dequeue_signals(void)
+{
+ char bufr[128];
+ int num;
+
+ /*
+ * Enter a loop to clear the pthread kernel pipe:
+ */
+ while (((num = __sys_read(_thread_kern_pipe[0], bufr,
+ sizeof(bufr))) > 0) || (num == -1 && errno == EINTR)) {
+ }
+ if ((num < 0) && (errno != EAGAIN)) {
+ /*
+ * The only error we should expect is if there is
+ * no data to read.
+ */
+ PANIC("Unable to read from thread kernel pipe");
+ }
+ /* Handle any pending signals: */
+ _thread_sig_handle_pending();
+}
+
+static inline void
+thread_run_switch_hook(pthread_t thread_out, pthread_t thread_in)
+{
+ pthread_t tid_out = thread_out;
+ pthread_t tid_in = thread_in;
+
+ if ((tid_out != NULL) &&
+ (tid_out->flags & PTHREAD_FLAGS_PRIVATE) != 0)
+ tid_out = NULL;
+ if ((tid_in != NULL) &&
+ (tid_in->flags & PTHREAD_FLAGS_PRIVATE) != 0)
+ tid_in = NULL;
+
+ if ((_sched_switch_hook != NULL) && (tid_out != tid_in)) {
+ /* Run the scheduler switch hook: */
+ _sched_switch_hook(tid_out, tid_in);
+ }
+}
+
+struct pthread *
+_get_curthread(void)
+{
+ if (_thread_initial == NULL)
+ _thread_init();
+
+ return (_thread_run);
+}
+
+void
+_set_curthread(struct pthread *newthread)
+{
+ _thread_run = newthread;
+}
diff --git a/lib/libc_r/uthread/uthread_kevent.c b/lib/libc_r/uthread/uthread_kevent.c
new file mode 100644
index 0000000..17aeaea
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_kevent.c
@@ -0,0 +1,77 @@
+/*-
+ * Copyright (c) 2000 Jonathan Lemon <jlemon@flugsvamp.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.
+ *
+ * $FreeBSD$
+ */
+
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/event.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_kevent, kevent);
+
+int
+_kevent(int kq, const struct kevent *changelist, int nchanges,
+ struct kevent *eventlist, int nevents, const struct timespec *timeout)
+{
+ struct pthread *curthread = _get_curthread();
+ struct timespec nullts = { 0, 0 };
+ int rc;
+
+ /* Set the wake up time */
+ _thread_kern_set_timeout(timeout);
+
+ rc = __sys_kevent(kq, changelist, nchanges,
+ eventlist, nevents, &nullts);
+ if (rc == 0 && eventlist != NULL && nevents > 0 && (timeout == NULL ||
+ timeout->tv_sec != 0 || timeout->tv_nsec != 0)) {
+ /* Save the socket file descriptor: */
+ curthread->data.fd.fd = kq;
+ curthread->data.fd.fname = __FILE__;
+ curthread->data.fd.branch = __LINE__;
+
+ do {
+ /* Reset the interrupted and timeout flags: */
+ curthread->interrupted = 0;
+ curthread->timeout = 0;
+
+ _thread_kern_sched_state(PS_FDR_WAIT,
+ __FILE__, __LINE__);
+
+ if (curthread->interrupted) {
+ errno = EINTR;
+ rc = -1;
+ break;
+ }
+ rc = __sys_kevent(kq, NULL, 0,
+ eventlist, nevents, &nullts);
+ } while (rc == 0 && curthread->timeout == 0);
+ }
+ return (rc);
+}
diff --git a/lib/libc_r/uthread/uthread_kill.c b/lib/libc_r/uthread/uthread_kill.c
new file mode 100644
index 0000000..29e1814
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_kill.c
@@ -0,0 +1,74 @@
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <signal.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_kill, pthread_kill);
+
+int
+_pthread_kill(pthread_t pthread, int sig)
+{
+ int ret;
+
+ /* Check for invalid signal numbers: */
+ if (sig < 0 || sig >= NSIG)
+ /* Invalid signal: */
+ ret = EINVAL;
+ /*
+ * Ensure the thread is in the list of active threads, and the
+ * signal is valid (signal 0 specifies error checking only) and
+ * not being ignored:
+ */
+ else if (((ret = _find_thread(pthread)) == 0) && (sig > 0) &&
+ (_thread_sigact[sig - 1].sa_handler != SIG_IGN)) {
+ /*
+ * Defer signals to protect the scheduling queues from
+ * access by the signal handler:
+ */
+ _thread_kern_sig_defer();
+
+ _thread_sig_send(pthread, sig);
+
+ /*
+ * Undefer and handle pending signals, yielding if
+ * necessary:
+ */
+ _thread_kern_sig_undefer();
+ }
+
+ /* Return the completion status: */
+ return (ret);
+}
diff --git a/lib/libc_r/uthread/uthread_kqueue.c b/lib/libc_r/uthread/uthread_kqueue.c
new file mode 100644
index 0000000..15aceb0
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_kqueue.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2003 Mark Peek <mp@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/types.h>
+#include <sys/event.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_kqueue, kqueue);
+
+int
+_kqueue(void)
+{
+ int fd;
+
+ /* Create a kqueue: */
+ if ((fd = __sys_kqueue()) < 0) {
+ /* Error creating socket. */
+
+ /* Initialise the entry in the file descriptor table: */
+ } else if (_thread_fd_table_init(fd) != 0) {
+ __sys_close(fd);
+ fd = -1;
+ }
+ return (fd);
+}
diff --git a/lib/libc_r/uthread/uthread_listen.c b/lib/libc_r/uthread/uthread_listen.c
new file mode 100644
index 0000000..0b73ab2
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_listen.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_listen, listen);
+
+int
+_listen(int fd, int backlog)
+{
+ int ret;
+
+ if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) {
+ ret = __sys_listen(fd, backlog);
+ _FD_UNLOCK(fd, FD_RDWR);
+ }
+ return (ret);
+}
+
diff --git a/lib/libc_r/uthread/uthread_main_np.c b/lib/libc_r/uthread/uthread_main_np.c
new file mode 100644
index 0000000..1c9c30b
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_main_np.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2001 Alfred Perlstein
+ * Author: Alfred Perlstein <alfred@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 <pthread.h>
+#include <pthread_np.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_main_np, pthread_main_np);
+
+/*
+ * Provide the equivalent to Solaris thr_main() function
+ */
+int
+_pthread_main_np()
+{
+
+ if (!_thread_initial)
+ return (-1);
+ else
+ return (pthread_equal(pthread_self(), _thread_initial) ? 1 : 0);
+}
diff --git a/lib/libc_r/uthread/uthread_mattr_init.c b/lib/libc_r/uthread/uthread_mattr_init.c
new file mode 100644
index 0000000..5c1fb6f
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_mattr_init.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 1996 Jeffrey Hsu <hsu@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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jeffrey Hsu.
+ * 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 JEFFREY HSU AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_mutexattr_init, pthread_mutexattr_init);
+
+static struct pthread_mutex_attr default_mutexattr = PTHREAD_MUTEXATTR_DEFAULT;
+
+int
+_pthread_mutexattr_init(pthread_mutexattr_t *attr)
+{
+ int ret;
+ pthread_mutexattr_t pattr;
+
+ if ((pattr = (pthread_mutexattr_t)
+ malloc(sizeof(struct pthread_mutex_attr))) == NULL) {
+ ret = ENOMEM;
+ } else {
+ memcpy(pattr, &default_mutexattr,
+ sizeof(struct pthread_mutex_attr));
+ *attr = pattr;
+ ret = 0;
+ }
+ return (ret);
+}
diff --git a/lib/libc_r/uthread/uthread_mattr_kind_np.c b/lib/libc_r/uthread/uthread_mattr_kind_np.c
new file mode 100644
index 0000000..08fb0db
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_mattr_kind_np.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 1996 Jeffrey Hsu <hsu@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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jeffrey Hsu.
+ * 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 JEFFREY HSU AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_mutexattr_setkind_np, pthread_mutexattr_setkind_np);
+__weak_reference(_pthread_mutexattr_getkind_np, pthread_mutexattr_getkind_np);
+__weak_reference(_pthread_mutexattr_gettype, pthread_mutexattr_gettype);
+__weak_reference(_pthread_mutexattr_settype, pthread_mutexattr_settype);
+
+int
+_pthread_mutexattr_setkind_np(pthread_mutexattr_t *attr, int kind)
+{
+ int ret;
+ if (attr == NULL || *attr == NULL) {
+ errno = EINVAL;
+ ret = -1;
+ } else {
+ (*attr)->m_type = kind;
+ ret = 0;
+ }
+ return(ret);
+}
+
+int
+_pthread_mutexattr_getkind_np(pthread_mutexattr_t attr)
+{
+ int ret;
+ if (attr == NULL) {
+ errno = EINVAL;
+ ret = -1;
+ } else {
+ ret = attr->m_type;
+ }
+ return(ret);
+}
+
+int
+_pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
+{
+ int ret;
+ if (attr == NULL || *attr == NULL || type >= PTHREAD_MUTEX_TYPE_MAX) {
+ errno = EINVAL;
+ ret = -1;
+ } else {
+ (*attr)->m_type = type;
+ ret = 0;
+ }
+ return(ret);
+}
+
+int
+_pthread_mutexattr_gettype(pthread_mutexattr_t *attr, int *type)
+{
+ int ret;
+
+ if (attr == NULL || *attr == NULL || (*attr)->m_type >=
+ PTHREAD_MUTEX_TYPE_MAX) {
+ ret = EINVAL;
+ } else {
+ *type = (*attr)->m_type;
+ ret = 0;
+ }
+ return ret;
+}
diff --git a/lib/libc_r/uthread/uthread_msync.c b/lib/libc_r/uthread/uthread_msync.c
new file mode 100644
index 0000000..24cbaa6
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_msync.c
@@ -0,0 +1,42 @@
+/*
+ * David Leonard <d@openbsd.org>, 1999. Public Domain.
+ *
+ * $OpenBSD: uthread_msync.c,v 1.2 1999/06/09 07:16:17 d Exp $
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(__msync, msync);
+
+int
+_msync(void *addr, size_t len, int flags)
+{
+ int ret;
+
+ ret = __sys_msync(addr, len, flags);
+
+ return (ret);
+}
+
+int
+__msync(void *addr, size_t len, int flags)
+{
+ int ret;
+
+ /*
+ * XXX This is quite pointless unless we know how to get the
+ * file descriptor associated with the memory, and lock it for
+ * write. The only real use of this wrapper is to guarantee
+ * a cancellation point, as per the standard. sigh.
+ */
+ _thread_enter_cancellation_point();
+ ret = _msync(addr, len, flags);
+ _thread_leave_cancellation_point();
+
+ return ret;
+}
diff --git a/lib/libc_r/uthread/uthread_multi_np.c b/lib/libc_r/uthread/uthread_multi_np.c
new file mode 100644
index 0000000..bd42365
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_multi_np.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 1996 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <pthread_np.h>
+
+__weak_reference(_pthread_multi_np, pthread_multi_np);
+
+int
+_pthread_multi_np()
+{
+
+ /* Return to multi-threaded scheduling mode: */
+ /*
+ * XXX - Do we want to do this?
+ * __is_threaded = 1;
+ */
+ pthread_resume_all_np();
+ return (0);
+}
diff --git a/lib/libc_r/uthread/uthread_mutex.c b/lib/libc_r/uthread/uthread_mutex.c
new file mode 100644
index 0000000..7c73868
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_mutex.c
@@ -0,0 +1,1545 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <errno.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+#if defined(_PTHREADS_INVARIANTS)
+#define _MUTEX_INIT_LINK(m) do { \
+ (m)->m_qe.tqe_prev = NULL; \
+ (m)->m_qe.tqe_next = NULL; \
+} while (0)
+#define _MUTEX_ASSERT_IS_OWNED(m) do { \
+ if ((m)->m_qe.tqe_prev == NULL) \
+ PANIC("mutex is not on list"); \
+} while (0)
+#define _MUTEX_ASSERT_NOT_OWNED(m) do { \
+ if (((m)->m_qe.tqe_prev != NULL) || \
+ ((m)->m_qe.tqe_next != NULL)) \
+ PANIC("mutex is on list"); \
+} while (0)
+#else
+#define _MUTEX_INIT_LINK(m)
+#define _MUTEX_ASSERT_IS_OWNED(m)
+#define _MUTEX_ASSERT_NOT_OWNED(m)
+#endif
+
+/*
+ * Prototypes
+ */
+static inline int mutex_self_trylock(pthread_mutex_t);
+static inline int mutex_self_lock(pthread_mutex_t);
+static inline int mutex_unlock_common(pthread_mutex_t *, int);
+static void mutex_priority_adjust(pthread_mutex_t);
+static void mutex_rescan_owned (pthread_t, pthread_mutex_t);
+static inline pthread_t mutex_queue_deq(pthread_mutex_t);
+static inline void mutex_queue_remove(pthread_mutex_t, pthread_t);
+static inline void mutex_queue_enq(pthread_mutex_t, pthread_t);
+
+
+static spinlock_t static_init_lock = _SPINLOCK_INITIALIZER;
+
+static struct pthread_mutex_attr static_mutex_attr =
+ PTHREAD_MUTEXATTR_STATIC_INITIALIZER;
+static pthread_mutexattr_t static_mattr = &static_mutex_attr;
+
+/* Single underscore versions provided for libc internal usage: */
+__weak_reference(__pthread_mutex_trylock, pthread_mutex_trylock);
+__weak_reference(__pthread_mutex_lock, pthread_mutex_lock);
+
+/* No difference between libc and application usage of these: */
+__weak_reference(_pthread_mutex_init, pthread_mutex_init);
+__weak_reference(_pthread_mutex_destroy, pthread_mutex_destroy);
+__weak_reference(_pthread_mutex_unlock, pthread_mutex_unlock);
+
+
+/*
+ * Reinitialize a private mutex; this is only used for internal mutexes.
+ */
+int
+_mutex_reinit(pthread_mutex_t * mutex)
+{
+ int ret = 0;
+
+ if (mutex == NULL)
+ ret = EINVAL;
+ else if (*mutex == NULL)
+ ret = _pthread_mutex_init(mutex, NULL);
+ else {
+ /*
+ * Initialize the mutex structure:
+ */
+ (*mutex)->m_type = PTHREAD_MUTEX_DEFAULT;
+ (*mutex)->m_protocol = PTHREAD_PRIO_NONE;
+ TAILQ_INIT(&(*mutex)->m_queue);
+ (*mutex)->m_owner = NULL;
+ (*mutex)->m_data.m_count = 0;
+ (*mutex)->m_flags |= MUTEX_FLAGS_INITED | MUTEX_FLAGS_PRIVATE;
+ (*mutex)->m_refcount = 0;
+ (*mutex)->m_prio = 0;
+ (*mutex)->m_saved_prio = 0;
+ _MUTEX_INIT_LINK(*mutex);
+ memset(&(*mutex)->lock, 0, sizeof((*mutex)->lock));
+ }
+ return (ret);
+}
+
+int
+_pthread_mutex_init(pthread_mutex_t * mutex,
+ const pthread_mutexattr_t * mutex_attr)
+{
+ enum pthread_mutextype type;
+ int protocol;
+ int ceiling;
+ int flags;
+ pthread_mutex_t pmutex;
+ int ret = 0;
+
+ if (mutex == NULL)
+ ret = EINVAL;
+
+ /* Check if default mutex attributes: */
+ if (mutex_attr == NULL || *mutex_attr == NULL) {
+ /* Default to a (error checking) POSIX mutex: */
+ type = PTHREAD_MUTEX_ERRORCHECK;
+ protocol = PTHREAD_PRIO_NONE;
+ ceiling = PTHREAD_MAX_PRIORITY;
+ flags = 0;
+ }
+
+ /* Check mutex type: */
+ else if (((*mutex_attr)->m_type < PTHREAD_MUTEX_ERRORCHECK) ||
+ ((*mutex_attr)->m_type >= PTHREAD_MUTEX_TYPE_MAX))
+ /* Return an invalid argument error: */
+ ret = EINVAL;
+
+ /* Check mutex protocol: */
+ else if (((*mutex_attr)->m_protocol < PTHREAD_PRIO_NONE) ||
+ ((*mutex_attr)->m_protocol > PTHREAD_MUTEX_RECURSIVE))
+ /* Return an invalid argument error: */
+ ret = EINVAL;
+
+ else {
+ /* Use the requested mutex type and protocol: */
+ type = (*mutex_attr)->m_type;
+ protocol = (*mutex_attr)->m_protocol;
+ ceiling = (*mutex_attr)->m_ceiling;
+ flags = (*mutex_attr)->m_flags;
+ }
+
+ /* Check no errors so far: */
+ if (ret == 0) {
+ if ((pmutex = (pthread_mutex_t)
+ malloc(sizeof(struct pthread_mutex))) == NULL)
+ ret = ENOMEM;
+ else {
+ /* Set the mutex flags: */
+ pmutex->m_flags = flags;
+
+ /* Process according to mutex type: */
+ switch (type) {
+ /* case PTHREAD_MUTEX_DEFAULT: */
+ case PTHREAD_MUTEX_ERRORCHECK:
+ case PTHREAD_MUTEX_NORMAL:
+ /* Nothing to do here. */
+ break;
+
+ /* Single UNIX Spec 2 recursive mutex: */
+ case PTHREAD_MUTEX_RECURSIVE:
+ /* Reset the mutex count: */
+ pmutex->m_data.m_count = 0;
+ break;
+
+ /* Trap invalid mutex types: */
+ default:
+ /* Return an invalid argument error: */
+ ret = EINVAL;
+ break;
+ }
+ if (ret == 0) {
+ /* Initialise the rest of the mutex: */
+ TAILQ_INIT(&pmutex->m_queue);
+ pmutex->m_flags |= MUTEX_FLAGS_INITED;
+ pmutex->m_owner = NULL;
+ pmutex->m_type = type;
+ pmutex->m_protocol = protocol;
+ pmutex->m_refcount = 0;
+ if (protocol == PTHREAD_PRIO_PROTECT)
+ pmutex->m_prio = ceiling;
+ else
+ pmutex->m_prio = 0;
+ pmutex->m_saved_prio = 0;
+ _MUTEX_INIT_LINK(pmutex);
+ memset(&pmutex->lock, 0, sizeof(pmutex->lock));
+ *mutex = pmutex;
+ } else {
+ free(pmutex);
+ *mutex = NULL;
+ }
+ }
+ }
+ /* Return the completion status: */
+ return (ret);
+}
+
+int
+_pthread_mutex_destroy(pthread_mutex_t * mutex)
+{
+ int ret = 0;
+
+ if (mutex == NULL || *mutex == NULL)
+ ret = EINVAL;
+ else {
+ /* Lock the mutex structure: */
+ _SPINLOCK(&(*mutex)->lock);
+
+ /*
+ * Check to see if this mutex is in use:
+ */
+ if (((*mutex)->m_owner != NULL) ||
+ (TAILQ_FIRST(&(*mutex)->m_queue) != NULL) ||
+ ((*mutex)->m_refcount != 0)) {
+ ret = EBUSY;
+
+ /* Unlock the mutex structure: */
+ _SPINUNLOCK(&(*mutex)->lock);
+ }
+ else {
+ /*
+ * Free the memory allocated for the mutex
+ * structure:
+ */
+ _MUTEX_ASSERT_NOT_OWNED(*mutex);
+ free(*mutex);
+
+ /*
+ * Leave the caller's pointer NULL now that
+ * the mutex has been destroyed:
+ */
+ *mutex = NULL;
+ }
+ }
+
+ /* Return the completion status: */
+ return (ret);
+}
+
+static int
+init_static(pthread_mutex_t *mutex)
+{
+ int ret;
+
+ _SPINLOCK(&static_init_lock);
+
+ if (*mutex == NULL)
+ ret = _pthread_mutex_init(mutex, NULL);
+ else
+ ret = 0;
+
+ _SPINUNLOCK(&static_init_lock);
+
+ return (ret);
+}
+
+static int
+init_static_private(pthread_mutex_t *mutex)
+{
+ int ret;
+
+ _SPINLOCK(&static_init_lock);
+
+ if (*mutex == NULL)
+ ret = _pthread_mutex_init(mutex, &static_mattr);
+ else
+ ret = 0;
+
+ _SPINUNLOCK(&static_init_lock);
+
+ return (ret);
+}
+
+static int
+mutex_trylock_common(pthread_mutex_t *mutex)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret = 0;
+
+ PTHREAD_ASSERT((mutex != NULL) && (*mutex != NULL),
+ "Uninitialized mutex in pthread_mutex_trylock_basic");
+
+ /*
+ * Defer signals to protect the scheduling queues from
+ * access by the signal handler:
+ */
+ _thread_kern_sig_defer();
+
+ /* Lock the mutex structure: */
+ _SPINLOCK(&(*mutex)->lock);
+
+ /*
+ * If the mutex was statically allocated, properly
+ * initialize the tail queue.
+ */
+ if (((*mutex)->m_flags & MUTEX_FLAGS_INITED) == 0) {
+ TAILQ_INIT(&(*mutex)->m_queue);
+ _MUTEX_INIT_LINK(*mutex);
+ (*mutex)->m_flags |= MUTEX_FLAGS_INITED;
+ }
+
+ /* Process according to mutex type: */
+ switch ((*mutex)->m_protocol) {
+ /* Default POSIX mutex: */
+ case PTHREAD_PRIO_NONE:
+ /* Check if this mutex is not locked: */
+ if ((*mutex)->m_owner == NULL) {
+ /* Lock the mutex for the running thread: */
+ (*mutex)->m_owner = curthread;
+
+ /* Add to the list of owned mutexes: */
+ _MUTEX_ASSERT_NOT_OWNED(*mutex);
+ TAILQ_INSERT_TAIL(&curthread->mutexq,
+ (*mutex), m_qe);
+ } else if ((*mutex)->m_owner == curthread)
+ ret = mutex_self_trylock(*mutex);
+ else
+ /* Return a busy error: */
+ ret = EBUSY;
+ break;
+
+ /* POSIX priority inheritence mutex: */
+ case PTHREAD_PRIO_INHERIT:
+ /* Check if this mutex is not locked: */
+ if ((*mutex)->m_owner == NULL) {
+ /* Lock the mutex for the running thread: */
+ (*mutex)->m_owner = curthread;
+
+ /* Track number of priority mutexes owned: */
+ curthread->priority_mutex_count++;
+
+ /*
+ * The mutex takes on the attributes of the
+ * running thread when there are no waiters.
+ */
+ (*mutex)->m_prio = curthread->active_priority;
+ (*mutex)->m_saved_prio =
+ curthread->inherited_priority;
+
+ /* Add to the list of owned mutexes: */
+ _MUTEX_ASSERT_NOT_OWNED(*mutex);
+ TAILQ_INSERT_TAIL(&curthread->mutexq,
+ (*mutex), m_qe);
+ } else if ((*mutex)->m_owner == curthread)
+ ret = mutex_self_trylock(*mutex);
+ else
+ /* Return a busy error: */
+ ret = EBUSY;
+ break;
+
+ /* POSIX priority protection mutex: */
+ case PTHREAD_PRIO_PROTECT:
+ /* Check for a priority ceiling violation: */
+ if (curthread->active_priority > (*mutex)->m_prio)
+ ret = EINVAL;
+
+ /* Check if this mutex is not locked: */
+ else if ((*mutex)->m_owner == NULL) {
+ /* Lock the mutex for the running thread: */
+ (*mutex)->m_owner = curthread;
+
+ /* Track number of priority mutexes owned: */
+ curthread->priority_mutex_count++;
+
+ /*
+ * The running thread inherits the ceiling
+ * priority of the mutex and executes at that
+ * priority.
+ */
+ curthread->active_priority = (*mutex)->m_prio;
+ (*mutex)->m_saved_prio =
+ curthread->inherited_priority;
+ curthread->inherited_priority =
+ (*mutex)->m_prio;
+
+ /* Add to the list of owned mutexes: */
+ _MUTEX_ASSERT_NOT_OWNED(*mutex);
+ TAILQ_INSERT_TAIL(&curthread->mutexq,
+ (*mutex), m_qe);
+ } else if ((*mutex)->m_owner == curthread)
+ ret = mutex_self_trylock(*mutex);
+ else
+ /* Return a busy error: */
+ ret = EBUSY;
+ break;
+
+ /* Trap invalid mutex types: */
+ default:
+ /* Return an invalid argument error: */
+ ret = EINVAL;
+ break;
+ }
+
+ /* Unlock the mutex structure: */
+ _SPINUNLOCK(&(*mutex)->lock);
+
+ /*
+ * Undefer and handle pending signals, yielding if
+ * necessary:
+ */
+ _thread_kern_sig_undefer();
+
+ /* Return the completion status: */
+ return (ret);
+}
+
+int
+__pthread_mutex_trylock(pthread_mutex_t *mutex)
+{
+ int ret = 0;
+
+ if (mutex == NULL)
+ ret = EINVAL;
+
+ /*
+ * If the mutex is statically initialized, perform the dynamic
+ * initialization:
+ */
+ else if ((*mutex != NULL) || (ret = init_static(mutex)) == 0)
+ ret = mutex_trylock_common(mutex);
+
+ return (ret);
+}
+
+int
+_pthread_mutex_trylock(pthread_mutex_t *mutex)
+{
+ int ret = 0;
+
+ if (mutex == NULL)
+ ret = EINVAL;
+
+ /*
+ * If the mutex is statically initialized, perform the dynamic
+ * initialization marking the mutex private (delete safe):
+ */
+ else if ((*mutex != NULL) || (ret = init_static_private(mutex)) == 0)
+ ret = mutex_trylock_common(mutex);
+
+ return (ret);
+}
+
+static int
+mutex_lock_common(pthread_mutex_t * mutex)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret = 0;
+
+ PTHREAD_ASSERT((mutex != NULL) && (*mutex != NULL),
+ "Uninitialized mutex in pthread_mutex_trylock_basic");
+
+ /* Reset the interrupted flag: */
+ curthread->interrupted = 0;
+
+ /*
+ * Enter a loop waiting to become the mutex owner. We need a
+ * loop in case the waiting thread is interrupted by a signal
+ * to execute a signal handler. It is not (currently) possible
+ * to remain in the waiting queue while running a handler.
+ * Instead, the thread is interrupted and backed out of the
+ * waiting queue prior to executing the signal handler.
+ */
+ do {
+ /*
+ * Defer signals to protect the scheduling queues from
+ * access by the signal handler:
+ */
+ _thread_kern_sig_defer();
+
+ /* Lock the mutex structure: */
+ _SPINLOCK(&(*mutex)->lock);
+
+ /*
+ * If the mutex was statically allocated, properly
+ * initialize the tail queue.
+ */
+ if (((*mutex)->m_flags & MUTEX_FLAGS_INITED) == 0) {
+ TAILQ_INIT(&(*mutex)->m_queue);
+ (*mutex)->m_flags |= MUTEX_FLAGS_INITED;
+ _MUTEX_INIT_LINK(*mutex);
+ }
+
+ /* Process according to mutex type: */
+ switch ((*mutex)->m_protocol) {
+ /* Default POSIX mutex: */
+ case PTHREAD_PRIO_NONE:
+ if ((*mutex)->m_owner == NULL) {
+ /* Lock the mutex for this thread: */
+ (*mutex)->m_owner = curthread;
+
+ /* Add to the list of owned mutexes: */
+ _MUTEX_ASSERT_NOT_OWNED(*mutex);
+ TAILQ_INSERT_TAIL(&curthread->mutexq,
+ (*mutex), m_qe);
+
+ } else if ((*mutex)->m_owner == curthread)
+ ret = mutex_self_lock(*mutex);
+ else {
+ /*
+ * Join the queue of threads waiting to lock
+ * the mutex:
+ */
+ mutex_queue_enq(*mutex, curthread);
+
+ /*
+ * Keep a pointer to the mutex this thread
+ * is waiting on:
+ */
+ curthread->data.mutex = *mutex;
+
+ /*
+ * Unlock the mutex structure and schedule the
+ * next thread:
+ */
+ _thread_kern_sched_state_unlock(PS_MUTEX_WAIT,
+ &(*mutex)->lock, __FILE__, __LINE__);
+
+ /* Lock the mutex structure again: */
+ _SPINLOCK(&(*mutex)->lock);
+ }
+ break;
+
+ /* POSIX priority inheritence mutex: */
+ case PTHREAD_PRIO_INHERIT:
+ /* Check if this mutex is not locked: */
+ if ((*mutex)->m_owner == NULL) {
+ /* Lock the mutex for this thread: */
+ (*mutex)->m_owner = curthread;
+
+ /* Track number of priority mutexes owned: */
+ curthread->priority_mutex_count++;
+
+ /*
+ * The mutex takes on attributes of the
+ * running thread when there are no waiters.
+ */
+ (*mutex)->m_prio = curthread->active_priority;
+ (*mutex)->m_saved_prio =
+ curthread->inherited_priority;
+ curthread->inherited_priority =
+ (*mutex)->m_prio;
+
+ /* Add to the list of owned mutexes: */
+ _MUTEX_ASSERT_NOT_OWNED(*mutex);
+ TAILQ_INSERT_TAIL(&curthread->mutexq,
+ (*mutex), m_qe);
+
+ } else if ((*mutex)->m_owner == curthread)
+ ret = mutex_self_lock(*mutex);
+ else {
+ /*
+ * Join the queue of threads waiting to lock
+ * the mutex:
+ */
+ mutex_queue_enq(*mutex, curthread);
+
+ /*
+ * Keep a pointer to the mutex this thread
+ * is waiting on:
+ */
+ curthread->data.mutex = *mutex;
+
+ if (curthread->active_priority >
+ (*mutex)->m_prio)
+ /* Adjust priorities: */
+ mutex_priority_adjust(*mutex);
+
+ /*
+ * Unlock the mutex structure and schedule the
+ * next thread:
+ */
+ _thread_kern_sched_state_unlock(PS_MUTEX_WAIT,
+ &(*mutex)->lock, __FILE__, __LINE__);
+
+ /* Lock the mutex structure again: */
+ _SPINLOCK(&(*mutex)->lock);
+ }
+ break;
+
+ /* POSIX priority protection mutex: */
+ case PTHREAD_PRIO_PROTECT:
+ /* Check for a priority ceiling violation: */
+ if (curthread->active_priority > (*mutex)->m_prio)
+ ret = EINVAL;
+
+ /* Check if this mutex is not locked: */
+ else if ((*mutex)->m_owner == NULL) {
+ /*
+ * Lock the mutex for the running
+ * thread:
+ */
+ (*mutex)->m_owner = curthread;
+
+ /* Track number of priority mutexes owned: */
+ curthread->priority_mutex_count++;
+
+ /*
+ * The running thread inherits the ceiling
+ * priority of the mutex and executes at that
+ * priority:
+ */
+ curthread->active_priority = (*mutex)->m_prio;
+ (*mutex)->m_saved_prio =
+ curthread->inherited_priority;
+ curthread->inherited_priority =
+ (*mutex)->m_prio;
+
+ /* Add to the list of owned mutexes: */
+ _MUTEX_ASSERT_NOT_OWNED(*mutex);
+ TAILQ_INSERT_TAIL(&curthread->mutexq,
+ (*mutex), m_qe);
+ } else if ((*mutex)->m_owner == curthread)
+ ret = mutex_self_lock(*mutex);
+ else {
+ /*
+ * Join the queue of threads waiting to lock
+ * the mutex:
+ */
+ mutex_queue_enq(*mutex, curthread);
+
+ /*
+ * Keep a pointer to the mutex this thread
+ * is waiting on:
+ */
+ curthread->data.mutex = *mutex;
+
+ /* Clear any previous error: */
+ curthread->error = 0;
+
+ /*
+ * Unlock the mutex structure and schedule the
+ * next thread:
+ */
+ _thread_kern_sched_state_unlock(PS_MUTEX_WAIT,
+ &(*mutex)->lock, __FILE__, __LINE__);
+
+ /* Lock the mutex structure again: */
+ _SPINLOCK(&(*mutex)->lock);
+
+ /*
+ * The threads priority may have changed while
+ * waiting for the mutex causing a ceiling
+ * violation.
+ */
+ ret = curthread->error;
+ curthread->error = 0;
+ }
+ break;
+
+ /* Trap invalid mutex types: */
+ default:
+ /* Return an invalid argument error: */
+ ret = EINVAL;
+ break;
+ }
+
+ /*
+ * Check to see if this thread was interrupted and
+ * is still in the mutex queue of waiting threads:
+ */
+ if (curthread->interrupted != 0)
+ mutex_queue_remove(*mutex, curthread);
+
+ /* Unlock the mutex structure: */
+ _SPINUNLOCK(&(*mutex)->lock);
+
+ /*
+ * Undefer and handle pending signals, yielding if
+ * necessary:
+ */
+ _thread_kern_sig_undefer();
+ } while (((*mutex)->m_owner != curthread) && (ret == 0) &&
+ (curthread->interrupted == 0));
+
+ if (curthread->interrupted != 0 &&
+ curthread->continuation != NULL)
+ curthread->continuation((void *) curthread);
+
+ /* Return the completion status: */
+ return (ret);
+}
+
+int
+__pthread_mutex_lock(pthread_mutex_t *mutex)
+{
+ int ret = 0;
+
+ if (_thread_initial == NULL)
+ _thread_init();
+
+ if (mutex == NULL)
+ ret = EINVAL;
+
+ /*
+ * If the mutex is statically initialized, perform the dynamic
+ * initialization:
+ */
+ else if ((*mutex != NULL) || ((ret = init_static(mutex)) == 0))
+ ret = mutex_lock_common(mutex);
+
+ return (ret);
+}
+
+int
+_pthread_mutex_lock(pthread_mutex_t *mutex)
+{
+ int ret = 0;
+
+ if (_thread_initial == NULL)
+ _thread_init();
+
+ if (mutex == NULL)
+ ret = EINVAL;
+
+ /*
+ * If the mutex is statically initialized, perform the dynamic
+ * initialization marking it private (delete safe):
+ */
+ else if ((*mutex != NULL) || ((ret = init_static_private(mutex)) == 0))
+ ret = mutex_lock_common(mutex);
+
+ return (ret);
+}
+
+int
+_pthread_mutex_unlock(pthread_mutex_t * mutex)
+{
+ return (mutex_unlock_common(mutex, /* add reference */ 0));
+}
+
+int
+_mutex_cv_unlock(pthread_mutex_t * mutex)
+{
+ return (mutex_unlock_common(mutex, /* add reference */ 1));
+}
+
+int
+_mutex_cv_lock(pthread_mutex_t * mutex)
+{
+ int ret;
+ if ((ret = _pthread_mutex_lock(mutex)) == 0)
+ (*mutex)->m_refcount--;
+ return (ret);
+}
+
+static inline int
+mutex_self_trylock(pthread_mutex_t mutex)
+{
+ int ret = 0;
+
+ switch (mutex->m_type) {
+
+ /* case PTHREAD_MUTEX_DEFAULT: */
+ case PTHREAD_MUTEX_ERRORCHECK:
+ case PTHREAD_MUTEX_NORMAL:
+ /*
+ * POSIX specifies that mutexes should return EDEADLK if a
+ * recursive lock is detected.
+ */
+ ret = EBUSY;
+ break;
+
+ case PTHREAD_MUTEX_RECURSIVE:
+ /* Increment the lock count: */
+ mutex->m_data.m_count++;
+ break;
+
+ default:
+ /* Trap invalid mutex types; */
+ ret = EINVAL;
+ }
+
+ return (ret);
+}
+
+static inline int
+mutex_self_lock(pthread_mutex_t mutex)
+{
+ int ret = 0;
+
+ switch (mutex->m_type) {
+ /* case PTHREAD_MUTEX_DEFAULT: */
+ case PTHREAD_MUTEX_ERRORCHECK:
+ /*
+ * POSIX specifies that mutexes should return EDEADLK if a
+ * recursive lock is detected.
+ */
+ ret = EDEADLK;
+ break;
+
+ case PTHREAD_MUTEX_NORMAL:
+ /*
+ * What SS2 define as a 'normal' mutex. Intentionally
+ * deadlock on attempts to get a lock you already own.
+ */
+ _thread_kern_sched_state_unlock(PS_DEADLOCK,
+ &mutex->lock, __FILE__, __LINE__);
+ break;
+
+ case PTHREAD_MUTEX_RECURSIVE:
+ /* Increment the lock count: */
+ mutex->m_data.m_count++;
+ break;
+
+ default:
+ /* Trap invalid mutex types; */
+ ret = EINVAL;
+ }
+
+ return (ret);
+}
+
+static inline int
+mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret = 0;
+
+ if (mutex == NULL || *mutex == NULL) {
+ ret = EINVAL;
+ } else {
+ /*
+ * Defer signals to protect the scheduling queues from
+ * access by the signal handler:
+ */
+ _thread_kern_sig_defer();
+
+ /* Lock the mutex structure: */
+ _SPINLOCK(&(*mutex)->lock);
+
+ /* Process according to mutex type: */
+ switch ((*mutex)->m_protocol) {
+ /* Default POSIX mutex: */
+ case PTHREAD_PRIO_NONE:
+ /*
+ * Check if the running thread is not the owner of the
+ * mutex:
+ */
+ if ((*mutex)->m_owner != curthread) {
+ /*
+ * Return an invalid argument error for no
+ * owner and a permission error otherwise:
+ */
+ ret = (*mutex)->m_owner == NULL ? EINVAL : EPERM;
+ }
+ else if (((*mutex)->m_type == PTHREAD_MUTEX_RECURSIVE) &&
+ ((*mutex)->m_data.m_count > 0)) {
+ /* Decrement the count: */
+ (*mutex)->m_data.m_count--;
+ } else {
+ /*
+ * Clear the count in case this is recursive
+ * mutex.
+ */
+ (*mutex)->m_data.m_count = 0;
+
+ /* Remove the mutex from the threads queue. */
+ _MUTEX_ASSERT_IS_OWNED(*mutex);
+ TAILQ_REMOVE(&(*mutex)->m_owner->mutexq,
+ (*mutex), m_qe);
+ _MUTEX_INIT_LINK(*mutex);
+
+ /*
+ * Get the next thread from the queue of
+ * threads waiting on the mutex:
+ */
+ if (((*mutex)->m_owner =
+ mutex_queue_deq(*mutex)) != NULL) {
+ /* Make the new owner runnable: */
+ PTHREAD_NEW_STATE((*mutex)->m_owner,
+ PS_RUNNING);
+
+ /*
+ * Add the mutex to the threads list of
+ * owned mutexes:
+ */
+ TAILQ_INSERT_TAIL(&(*mutex)->m_owner->mutexq,
+ (*mutex), m_qe);
+
+ /*
+ * The owner is no longer waiting for
+ * this mutex:
+ */
+ (*mutex)->m_owner->data.mutex = NULL;
+ }
+ }
+ break;
+
+ /* POSIX priority inheritence mutex: */
+ case PTHREAD_PRIO_INHERIT:
+ /*
+ * Check if the running thread is not the owner of the
+ * mutex:
+ */
+ if ((*mutex)->m_owner != curthread) {
+ /*
+ * Return an invalid argument error for no
+ * owner and a permission error otherwise:
+ */
+ ret = (*mutex)->m_owner == NULL ? EINVAL : EPERM;
+ }
+ else if (((*mutex)->m_type == PTHREAD_MUTEX_RECURSIVE) &&
+ ((*mutex)->m_data.m_count > 0)) {
+ /* Decrement the count: */
+ (*mutex)->m_data.m_count--;
+ } else {
+ /*
+ * Clear the count in case this is recursive
+ * mutex.
+ */
+ (*mutex)->m_data.m_count = 0;
+
+ /*
+ * Restore the threads inherited priority and
+ * recompute the active priority (being careful
+ * not to override changes in the threads base
+ * priority subsequent to locking the mutex).
+ */
+ curthread->inherited_priority =
+ (*mutex)->m_saved_prio;
+ curthread->active_priority =
+ MAX(curthread->inherited_priority,
+ curthread->base_priority);
+
+ /*
+ * This thread now owns one less priority mutex.
+ */
+ curthread->priority_mutex_count--;
+
+ /* Remove the mutex from the threads queue. */
+ _MUTEX_ASSERT_IS_OWNED(*mutex);
+ TAILQ_REMOVE(&(*mutex)->m_owner->mutexq,
+ (*mutex), m_qe);
+ _MUTEX_INIT_LINK(*mutex);
+
+ /*
+ * Get the next thread from the queue of threads
+ * waiting on the mutex:
+ */
+ if (((*mutex)->m_owner =
+ mutex_queue_deq(*mutex)) == NULL)
+ /* This mutex has no priority. */
+ (*mutex)->m_prio = 0;
+ else {
+ /*
+ * Track number of priority mutexes owned:
+ */
+ (*mutex)->m_owner->priority_mutex_count++;
+
+ /*
+ * Add the mutex to the threads list
+ * of owned mutexes:
+ */
+ TAILQ_INSERT_TAIL(&(*mutex)->m_owner->mutexq,
+ (*mutex), m_qe);
+
+ /*
+ * The owner is no longer waiting for
+ * this mutex:
+ */
+ (*mutex)->m_owner->data.mutex = NULL;
+
+ /*
+ * Set the priority of the mutex. Since
+ * our waiting threads are in descending
+ * priority order, the priority of the
+ * mutex becomes the active priority of
+ * the thread we just dequeued.
+ */
+ (*mutex)->m_prio =
+ (*mutex)->m_owner->active_priority;
+
+ /*
+ * Save the owning threads inherited
+ * priority:
+ */
+ (*mutex)->m_saved_prio =
+ (*mutex)->m_owner->inherited_priority;
+
+ /*
+ * The owning threads inherited priority
+ * now becomes his active priority (the
+ * priority of the mutex).
+ */
+ (*mutex)->m_owner->inherited_priority =
+ (*mutex)->m_prio;
+
+ /*
+ * Make the new owner runnable:
+ */
+ PTHREAD_NEW_STATE((*mutex)->m_owner,
+ PS_RUNNING);
+ }
+ }
+ break;
+
+ /* POSIX priority ceiling mutex: */
+ case PTHREAD_PRIO_PROTECT:
+ /*
+ * Check if the running thread is not the owner of the
+ * mutex:
+ */
+ if ((*mutex)->m_owner != curthread) {
+ /*
+ * Return an invalid argument error for no
+ * owner and a permission error otherwise:
+ */
+ ret = (*mutex)->m_owner == NULL ? EINVAL : EPERM;
+ }
+ else if (((*mutex)->m_type == PTHREAD_MUTEX_RECURSIVE) &&
+ ((*mutex)->m_data.m_count > 0)) {
+ /* Decrement the count: */
+ (*mutex)->m_data.m_count--;
+ } else {
+ /*
+ * Clear the count in case this is recursive
+ * mutex.
+ */
+ (*mutex)->m_data.m_count = 0;
+
+ /*
+ * Restore the threads inherited priority and
+ * recompute the active priority (being careful
+ * not to override changes in the threads base
+ * priority subsequent to locking the mutex).
+ */
+ curthread->inherited_priority =
+ (*mutex)->m_saved_prio;
+ curthread->active_priority =
+ MAX(curthread->inherited_priority,
+ curthread->base_priority);
+
+ /*
+ * This thread now owns one less priority mutex.
+ */
+ curthread->priority_mutex_count--;
+
+ /* Remove the mutex from the threads queue. */
+ _MUTEX_ASSERT_IS_OWNED(*mutex);
+ TAILQ_REMOVE(&(*mutex)->m_owner->mutexq,
+ (*mutex), m_qe);
+ _MUTEX_INIT_LINK(*mutex);
+
+ /*
+ * Enter a loop to find a waiting thread whose
+ * active priority will not cause a ceiling
+ * violation:
+ */
+ while ((((*mutex)->m_owner =
+ mutex_queue_deq(*mutex)) != NULL) &&
+ ((*mutex)->m_owner->active_priority >
+ (*mutex)->m_prio)) {
+ /*
+ * Either the mutex ceiling priority
+ * been lowered and/or this threads
+ * priority has been raised subsequent
+ * to this thread being queued on the
+ * waiting list.
+ */
+ (*mutex)->m_owner->error = EINVAL;
+ PTHREAD_NEW_STATE((*mutex)->m_owner,
+ PS_RUNNING);
+ /*
+ * The thread is no longer waiting for
+ * this mutex:
+ */
+ (*mutex)->m_owner->data.mutex = NULL;
+ }
+
+ /* Check for a new owner: */
+ if ((*mutex)->m_owner != NULL) {
+ /*
+ * Track number of priority mutexes owned:
+ */
+ (*mutex)->m_owner->priority_mutex_count++;
+
+ /*
+ * Add the mutex to the threads list
+ * of owned mutexes:
+ */
+ TAILQ_INSERT_TAIL(&(*mutex)->m_owner->mutexq,
+ (*mutex), m_qe);
+
+ /*
+ * The owner is no longer waiting for
+ * this mutex:
+ */
+ (*mutex)->m_owner->data.mutex = NULL;
+
+ /*
+ * Save the owning threads inherited
+ * priority:
+ */
+ (*mutex)->m_saved_prio =
+ (*mutex)->m_owner->inherited_priority;
+
+ /*
+ * The owning thread inherits the
+ * ceiling priority of the mutex and
+ * executes at that priority:
+ */
+ (*mutex)->m_owner->inherited_priority =
+ (*mutex)->m_prio;
+ (*mutex)->m_owner->active_priority =
+ (*mutex)->m_prio;
+
+ /*
+ * Make the new owner runnable:
+ */
+ PTHREAD_NEW_STATE((*mutex)->m_owner,
+ PS_RUNNING);
+ }
+ }
+ break;
+
+ /* Trap invalid mutex types: */
+ default:
+ /* Return an invalid argument error: */
+ ret = EINVAL;
+ break;
+ }
+
+ if ((ret == 0) && (add_reference != 0)) {
+ /* Increment the reference count: */
+ (*mutex)->m_refcount++;
+ }
+
+ /* Unlock the mutex structure: */
+ _SPINUNLOCK(&(*mutex)->lock);
+
+ /*
+ * Undefer and handle pending signals, yielding if
+ * necessary:
+ */
+ _thread_kern_sig_undefer();
+ }
+
+ /* Return the completion status: */
+ return (ret);
+}
+
+
+/*
+ * This function is called when a change in base priority occurs for
+ * a thread that is holding or waiting for a priority protection or
+ * inheritence mutex. A change in a threads base priority can effect
+ * changes to active priorities of other threads and to the ordering
+ * of mutex locking by waiting threads.
+ *
+ * This must be called while thread scheduling is deferred.
+ */
+void
+_mutex_notify_priochange(pthread_t pthread)
+{
+ /* Adjust the priorites of any owned priority mutexes: */
+ if (pthread->priority_mutex_count > 0) {
+ /*
+ * Rescan the mutexes owned by this thread and correct
+ * their priorities to account for this threads change
+ * in priority. This has the side effect of changing
+ * the threads active priority.
+ */
+ mutex_rescan_owned(pthread, /* rescan all owned */ NULL);
+ }
+
+ /*
+ * If this thread is waiting on a priority inheritence mutex,
+ * check for priority adjustments. A change in priority can
+ * also effect a ceiling violation(*) for a thread waiting on
+ * a priority protection mutex; we don't perform the check here
+ * as it is done in pthread_mutex_unlock.
+ *
+ * (*) It should be noted that a priority change to a thread
+ * _after_ taking and owning a priority ceiling mutex
+ * does not affect ownership of that mutex; the ceiling
+ * priority is only checked before mutex ownership occurs.
+ */
+ if (pthread->state == PS_MUTEX_WAIT) {
+ /* Lock the mutex structure: */
+ _SPINLOCK(&pthread->data.mutex->lock);
+
+ /*
+ * Check to make sure this thread is still in the same state
+ * (the spinlock above can yield the CPU to another thread):
+ */
+ if (pthread->state == PS_MUTEX_WAIT) {
+ /*
+ * Remove and reinsert this thread into the list of
+ * waiting threads to preserve decreasing priority
+ * order.
+ */
+ mutex_queue_remove(pthread->data.mutex, pthread);
+ mutex_queue_enq(pthread->data.mutex, pthread);
+
+ if (pthread->data.mutex->m_protocol ==
+ PTHREAD_PRIO_INHERIT) {
+ /* Adjust priorities: */
+ mutex_priority_adjust(pthread->data.mutex);
+ }
+ }
+
+ /* Unlock the mutex structure: */
+ _SPINUNLOCK(&pthread->data.mutex->lock);
+ }
+}
+
+/*
+ * Called when a new thread is added to the mutex waiting queue or
+ * when a threads priority changes that is already in the mutex
+ * waiting queue.
+ */
+static void
+mutex_priority_adjust(pthread_mutex_t mutex)
+{
+ pthread_t pthread_next, pthread = mutex->m_owner;
+ int temp_prio;
+ pthread_mutex_t m = mutex;
+
+ /*
+ * Calculate the mutex priority as the maximum of the highest
+ * active priority of any waiting threads and the owning threads
+ * active priority(*).
+ *
+ * (*) Because the owning threads current active priority may
+ * reflect priority inherited from this mutex (and the mutex
+ * priority may have changed) we must recalculate the active
+ * priority based on the threads saved inherited priority
+ * and its base priority.
+ */
+ pthread_next = TAILQ_FIRST(&m->m_queue); /* should never be NULL */
+ temp_prio = MAX(pthread_next->active_priority,
+ MAX(m->m_saved_prio, pthread->base_priority));
+
+ /* See if this mutex really needs adjusting: */
+ if (temp_prio == m->m_prio)
+ /* No need to propagate the priority: */
+ return;
+
+ /* Set new priority of the mutex: */
+ m->m_prio = temp_prio;
+
+ while (m != NULL) {
+ /*
+ * Save the threads priority before rescanning the
+ * owned mutexes:
+ */
+ temp_prio = pthread->active_priority;
+
+ /*
+ * Fix the priorities for all the mutexes this thread has
+ * locked since taking this mutex. This also has a
+ * potential side-effect of changing the threads priority.
+ */
+ mutex_rescan_owned(pthread, m);
+
+ /*
+ * If the thread is currently waiting on a mutex, check
+ * to see if the threads new priority has affected the
+ * priority of the mutex.
+ */
+ if ((temp_prio != pthread->active_priority) &&
+ (pthread->state == PS_MUTEX_WAIT) &&
+ (pthread->data.mutex->m_protocol == PTHREAD_PRIO_INHERIT)) {
+ /* Grab the mutex this thread is waiting on: */
+ m = pthread->data.mutex;
+
+ /*
+ * The priority for this thread has changed. Remove
+ * and reinsert this thread into the list of waiting
+ * threads to preserve decreasing priority order.
+ */
+ mutex_queue_remove(m, pthread);
+ mutex_queue_enq(m, pthread);
+
+ /* Grab the waiting thread with highest priority: */
+ pthread_next = TAILQ_FIRST(&m->m_queue);
+
+ /*
+ * Calculate the mutex priority as the maximum of the
+ * highest active priority of any waiting threads and
+ * the owning threads active priority.
+ */
+ temp_prio = MAX(pthread_next->active_priority,
+ MAX(m->m_saved_prio, m->m_owner->base_priority));
+
+ if (temp_prio != m->m_prio) {
+ /*
+ * The priority needs to be propagated to the
+ * mutex this thread is waiting on and up to
+ * the owner of that mutex.
+ */
+ m->m_prio = temp_prio;
+ pthread = m->m_owner;
+ }
+ else
+ /* We're done: */
+ m = NULL;
+
+ }
+ else
+ /* We're done: */
+ m = NULL;
+ }
+}
+
+static void
+mutex_rescan_owned(pthread_t pthread, pthread_mutex_t mutex)
+{
+ int active_prio, inherited_prio;
+ pthread_mutex_t m;
+ pthread_t pthread_next;
+
+ /*
+ * Start walking the mutexes the thread has taken since
+ * taking this mutex.
+ */
+ if (mutex == NULL) {
+ /*
+ * A null mutex means start at the beginning of the owned
+ * mutex list.
+ */
+ m = TAILQ_FIRST(&pthread->mutexq);
+
+ /* There is no inherited priority yet. */
+ inherited_prio = 0;
+ }
+ else {
+ /*
+ * The caller wants to start after a specific mutex. It
+ * is assumed that this mutex is a priority inheritence
+ * mutex and that its priority has been correctly
+ * calculated.
+ */
+ m = TAILQ_NEXT(mutex, m_qe);
+
+ /* Start inheriting priority from the specified mutex. */
+ inherited_prio = mutex->m_prio;
+ }
+ active_prio = MAX(inherited_prio, pthread->base_priority);
+
+ while (m != NULL) {
+ /*
+ * We only want to deal with priority inheritence
+ * mutexes. This might be optimized by only placing
+ * priority inheritence mutexes into the owned mutex
+ * list, but it may prove to be useful having all
+ * owned mutexes in this list. Consider a thread
+ * exiting while holding mutexes...
+ */
+ if (m->m_protocol == PTHREAD_PRIO_INHERIT) {
+ /*
+ * Fix the owners saved (inherited) priority to
+ * reflect the priority of the previous mutex.
+ */
+ m->m_saved_prio = inherited_prio;
+
+ if ((pthread_next = TAILQ_FIRST(&m->m_queue)) != NULL)
+ /* Recalculate the priority of the mutex: */
+ m->m_prio = MAX(active_prio,
+ pthread_next->active_priority);
+ else
+ m->m_prio = active_prio;
+
+ /* Recalculate new inherited and active priorities: */
+ inherited_prio = m->m_prio;
+ active_prio = MAX(m->m_prio, pthread->base_priority);
+ }
+
+ /* Advance to the next mutex owned by this thread: */
+ m = TAILQ_NEXT(m, m_qe);
+ }
+
+ /*
+ * Fix the threads inherited priority and recalculate its
+ * active priority.
+ */
+ pthread->inherited_priority = inherited_prio;
+ active_prio = MAX(inherited_prio, pthread->base_priority);
+
+ if (active_prio != pthread->active_priority) {
+ /*
+ * If this thread is in the priority queue, it must be
+ * removed and reinserted for its new priority.
+ */
+ if (pthread->flags & PTHREAD_FLAGS_IN_PRIOQ) {
+ /*
+ * Remove the thread from the priority queue
+ * before changing its priority:
+ */
+ PTHREAD_PRIOQ_REMOVE(pthread);
+
+ /*
+ * POSIX states that if the priority is being
+ * lowered, the thread must be inserted at the
+ * head of the queue for its priority if it owns
+ * any priority protection or inheritence mutexes.
+ */
+ if ((active_prio < pthread->active_priority) &&
+ (pthread->priority_mutex_count > 0)) {
+ /* Set the new active priority. */
+ pthread->active_priority = active_prio;
+
+ PTHREAD_PRIOQ_INSERT_HEAD(pthread);
+ }
+ else {
+ /* Set the new active priority. */
+ pthread->active_priority = active_prio;
+
+ PTHREAD_PRIOQ_INSERT_TAIL(pthread);
+ }
+ }
+ else {
+ /* Set the new active priority. */
+ pthread->active_priority = active_prio;
+ }
+ }
+}
+
+void
+_mutex_unlock_private(pthread_t pthread)
+{
+ struct pthread_mutex *m, *m_next;
+
+ for (m = TAILQ_FIRST(&pthread->mutexq); m != NULL; m = m_next) {
+ m_next = TAILQ_NEXT(m, m_qe);
+ if ((m->m_flags & MUTEX_FLAGS_PRIVATE) != 0)
+ _pthread_mutex_unlock(&m);
+ }
+}
+
+void
+_mutex_lock_backout(pthread_t pthread)
+{
+ struct pthread_mutex *mutex;
+
+ /*
+ * Defer signals to protect the scheduling queues from
+ * access by the signal handler:
+ */
+ _thread_kern_sig_defer();
+ if ((pthread->flags & PTHREAD_FLAGS_IN_MUTEXQ) != 0) {
+ mutex = pthread->data.mutex;
+
+ /* Lock the mutex structure: */
+ _SPINLOCK(&mutex->lock);
+
+ mutex_queue_remove(mutex, pthread);
+
+ /* This thread is no longer waiting for the mutex: */
+ pthread->data.mutex = NULL;
+
+ /* Unlock the mutex structure: */
+ _SPINUNLOCK(&mutex->lock);
+
+ }
+ /*
+ * Undefer and handle pending signals, yielding if
+ * necessary:
+ */
+ _thread_kern_sig_undefer();
+}
+
+/*
+ * Dequeue a waiting thread from the head of a mutex queue in descending
+ * priority order.
+ */
+static inline pthread_t
+mutex_queue_deq(pthread_mutex_t mutex)
+{
+ pthread_t pthread;
+
+ while ((pthread = TAILQ_FIRST(&mutex->m_queue)) != NULL) {
+ TAILQ_REMOVE(&mutex->m_queue, pthread, sqe);
+ pthread->flags &= ~PTHREAD_FLAGS_IN_MUTEXQ;
+
+ /*
+ * Only exit the loop if the thread hasn't been
+ * cancelled.
+ */
+ if (pthread->interrupted == 0)
+ break;
+ }
+
+ return (pthread);
+}
+
+/*
+ * Remove a waiting thread from a mutex queue in descending priority order.
+ */
+static inline void
+mutex_queue_remove(pthread_mutex_t mutex, pthread_t pthread)
+{
+ if ((pthread->flags & PTHREAD_FLAGS_IN_MUTEXQ) != 0) {
+ TAILQ_REMOVE(&mutex->m_queue, pthread, sqe);
+ pthread->flags &= ~PTHREAD_FLAGS_IN_MUTEXQ;
+ }
+}
+
+/*
+ * Enqueue a waiting thread to a queue in descending priority order.
+ */
+static inline void
+mutex_queue_enq(pthread_mutex_t mutex, pthread_t pthread)
+{
+ pthread_t tid = TAILQ_LAST(&mutex->m_queue, mutex_head);
+
+ PTHREAD_ASSERT_NOT_IN_SYNCQ(pthread);
+ /*
+ * For the common case of all threads having equal priority,
+ * we perform a quick check against the priority of the thread
+ * at the tail of the queue.
+ */
+ if ((tid == NULL) || (pthread->active_priority <= tid->active_priority))
+ TAILQ_INSERT_TAIL(&mutex->m_queue, pthread, sqe);
+ else {
+ tid = TAILQ_FIRST(&mutex->m_queue);
+ while (pthread->active_priority <= tid->active_priority)
+ tid = TAILQ_NEXT(tid, sqe);
+ TAILQ_INSERT_BEFORE(tid, pthread, sqe);
+ }
+ pthread->flags |= PTHREAD_FLAGS_IN_MUTEXQ;
+}
+
diff --git a/lib/libc_r/uthread/uthread_mutex_prioceiling.c b/lib/libc_r/uthread/uthread_mutex_prioceiling.c
new file mode 100644
index 0000000..eccc9e4
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_mutex_prioceiling.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include "namespace.h"
+#include <pthread.h>
+#include "un-namespace.h"
+#include "pthread_private.h"
+
+__weak_reference(_pthread_mutexattr_getprioceiling, pthread_mutexattr_getprioceiling);
+__weak_reference(_pthread_mutexattr_setprioceiling, pthread_mutexattr_setprioceiling);
+__weak_reference(_pthread_mutex_getprioceiling, pthread_mutex_getprioceiling);
+__weak_reference(_pthread_mutex_setprioceiling, pthread_mutex_setprioceiling);
+
+int
+_pthread_mutexattr_getprioceiling(pthread_mutexattr_t *mattr, int *prioceiling)
+{
+ int ret = 0;
+
+ if ((mattr == NULL) || (*mattr == NULL))
+ ret = EINVAL;
+ else if ((*mattr)->m_protocol != PTHREAD_PRIO_PROTECT)
+ ret = EINVAL;
+ else
+ *prioceiling = (*mattr)->m_ceiling;
+
+ return(ret);
+}
+
+int
+_pthread_mutexattr_setprioceiling(pthread_mutexattr_t *mattr, int prioceiling)
+{
+ int ret = 0;
+
+ if ((mattr == NULL) || (*mattr == NULL))
+ ret = EINVAL;
+ else if ((*mattr)->m_protocol != PTHREAD_PRIO_PROTECT)
+ ret = EINVAL;
+ else
+ (*mattr)->m_ceiling = prioceiling;
+
+ return(ret);
+}
+
+int
+_pthread_mutex_getprioceiling(pthread_mutex_t *mutex,
+ int *prioceiling)
+{
+ int ret;
+
+ if ((mutex == NULL) || (*mutex == NULL))
+ ret = EINVAL;
+ else if ((*mutex)->m_protocol != PTHREAD_PRIO_PROTECT)
+ ret = EINVAL;
+ else
+ ret = (*mutex)->m_prio;
+
+ return(ret);
+}
+
+int
+_pthread_mutex_setprioceiling(pthread_mutex_t *mutex,
+ int prioceiling, int *old_ceiling)
+{
+ int ret = 0;
+
+ if ((mutex == NULL) || (*mutex == NULL))
+ ret = EINVAL;
+ else if ((*mutex)->m_protocol != PTHREAD_PRIO_PROTECT)
+ ret = EINVAL;
+ else {
+ /* Lock the mutex: */
+ if ((ret = _pthread_mutex_lock(mutex)) == 0) {
+ /* Return the old ceiling and set the new ceiling: */
+ *old_ceiling = (*mutex)->m_prio;
+ (*mutex)->m_prio = prioceiling;
+
+ /* Unlock the mutex: */
+ ret = _pthread_mutex_unlock(mutex);
+ }
+ }
+ return(ret);
+}
diff --git a/lib/libc_r/uthread/uthread_mutex_protocol.c b/lib/libc_r/uthread/uthread_mutex_protocol.c
new file mode 100644
index 0000000..4d020d6
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_mutex_protocol.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_mutexattr_getprotocol, pthread_mutexattr_getprotocol);
+__weak_reference(_pthread_mutexattr_setprotocol, pthread_mutexattr_setprotocol);
+
+int
+_pthread_mutexattr_getprotocol(pthread_mutexattr_t *mattr, int *protocol)
+{
+ int ret = 0;
+
+ if ((mattr == NULL) || (*mattr == NULL))
+ ret = EINVAL;
+ else
+ *protocol = (*mattr)->m_protocol;
+
+ return(ret);
+}
+
+int
+_pthread_mutexattr_setprotocol(pthread_mutexattr_t *mattr, int protocol)
+{
+ int ret = 0;
+
+ if ((mattr == NULL) || (*mattr == NULL) ||
+ (protocol < PTHREAD_PRIO_NONE) || (protocol > PTHREAD_PRIO_PROTECT))
+ ret = EINVAL;
+ else {
+ (*mattr)->m_protocol = protocol;
+ (*mattr)->m_ceiling = PTHREAD_MAX_PRIORITY;
+ }
+ return(ret);
+}
+
diff --git a/lib/libc_r/uthread/uthread_mutexattr_destroy.c b/lib/libc_r/uthread/uthread_mutexattr_destroy.c
new file mode 100644
index 0000000..bdc85a5
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_mutexattr_destroy.c
@@ -0,0 +1,53 @@
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <errno.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_mutexattr_destroy, pthread_mutexattr_destroy);
+
+int
+_pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
+{
+ int ret;
+ if (attr == NULL || *attr == NULL) {
+ ret = EINVAL;
+ } else {
+ free(*attr);
+ *attr = NULL;
+ ret = 0;
+ }
+ return(ret);
+}
diff --git a/lib/libc_r/uthread/uthread_nanosleep.c b/lib/libc_r/uthread/uthread_nanosleep.c
new file mode 100644
index 0000000..e5569e7
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_nanosleep.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <errno.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(__nanosleep, nanosleep);
+
+int
+_nanosleep(const struct timespec * time_to_sleep,
+ struct timespec * time_remaining)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret = 0;
+ struct timespec current_time;
+ struct timespec current_time1;
+ struct timespec remaining_time;
+ struct timeval tv;
+
+ /* Check if the time to sleep is legal: */
+ if (time_to_sleep == NULL || time_to_sleep->tv_sec < 0 ||
+ time_to_sleep->tv_nsec < 0 || time_to_sleep->tv_nsec >= 1000000000) {
+ /* Return an EINVAL error : */
+ errno = EINVAL;
+ ret = -1;
+ } else {
+ /*
+ * As long as we're going to get the time of day, we
+ * might as well store it in the global time of day:
+ */
+ gettimeofday((struct timeval *) &_sched_tod, NULL);
+ GET_CURRENT_TOD(tv);
+ TIMEVAL_TO_TIMESPEC(&tv, &current_time);
+
+ /* Calculate the time for the current thread to wake up: */
+ curthread->wakeup_time.tv_sec = current_time.tv_sec + time_to_sleep->tv_sec;
+ curthread->wakeup_time.tv_nsec = current_time.tv_nsec + time_to_sleep->tv_nsec;
+
+ /* Check if the nanosecond field has overflowed: */
+ if (curthread->wakeup_time.tv_nsec >= 1000000000) {
+ /* Wrap the nanosecond field: */
+ curthread->wakeup_time.tv_sec += 1;
+ curthread->wakeup_time.tv_nsec -= 1000000000;
+ }
+ curthread->interrupted = 0;
+
+ /* Reschedule the current thread to sleep: */
+ _thread_kern_sched_state(PS_SLEEP_WAIT, __FILE__, __LINE__);
+
+ /*
+ * As long as we're going to get the time of day, we
+ * might as well store it in the global time of day:
+ */
+ gettimeofday((struct timeval *) &_sched_tod, NULL);
+ GET_CURRENT_TOD(tv);
+ TIMEVAL_TO_TIMESPEC(&tv, &current_time1);
+
+ /* Calculate the remaining time to sleep: */
+ remaining_time.tv_sec = time_to_sleep->tv_sec + current_time.tv_sec - current_time1.tv_sec;
+ remaining_time.tv_nsec = time_to_sleep->tv_nsec + current_time.tv_nsec - current_time1.tv_nsec;
+
+ /* Check if the nanosecond field has underflowed: */
+ if (remaining_time.tv_nsec < 0) {
+ /* Handle the underflow: */
+ remaining_time.tv_sec -= 1;
+ remaining_time.tv_nsec += 1000000000;
+ }
+
+ /* Check if the nanosecond field has overflowed: */
+ if (remaining_time.tv_nsec >= 1000000000) {
+ /* Handle the overflow: */
+ remaining_time.tv_sec += 1;
+ remaining_time.tv_nsec -= 1000000000;
+ }
+
+ /* Check if the sleep was longer than the required time: */
+ if (remaining_time.tv_sec < 0) {
+ /* Reset the time left: */
+ remaining_time.tv_sec = 0;
+ remaining_time.tv_nsec = 0;
+ }
+
+ /* Check if the time remaining is to be returned: */
+ if (time_remaining != NULL) {
+ /* Return the actual time slept: */
+ time_remaining->tv_sec = remaining_time.tv_sec;
+ time_remaining->tv_nsec = remaining_time.tv_nsec;
+ }
+
+ /* Check if the sleep was interrupted: */
+ if (curthread->interrupted) {
+ /* Return an EINTR error : */
+ errno = EINTR;
+ ret = -1;
+ }
+ }
+ return (ret);
+}
+
+int
+__nanosleep(const struct timespec * time_to_sleep, struct timespec *
+ time_remaining)
+{
+ int ret;
+
+ _thread_enter_cancellation_point();
+ ret = _nanosleep(time_to_sleep, time_remaining);
+ _thread_leave_cancellation_point();
+
+ return ret;
+}
diff --git a/lib/libc_r/uthread/uthread_once.c b/lib/libc_r/uthread/uthread_once.c
new file mode 100644
index 0000000..1815f2a
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_once.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <pthread.h>
+#include "un-namespace.h"
+#include "pthread_private.h"
+
+__weak_reference(_pthread_once, pthread_once);
+
+int
+_pthread_once(pthread_once_t * once_control, void (*init_routine) (void))
+{
+ if (once_control->state == PTHREAD_NEEDS_INIT) {
+ if (_thread_initial == NULL)
+ _thread_init();
+ _pthread_mutex_lock(&(once_control->mutex));
+ if (once_control->state == PTHREAD_NEEDS_INIT) {
+ init_routine();
+ once_control->state = PTHREAD_DONE_INIT;
+ }
+ _pthread_mutex_unlock(&(once_control->mutex));
+ }
+ return (0);
+}
diff --git a/lib/libc_r/uthread/uthread_open.c b/lib/libc_r/uthread/uthread_open.c
new file mode 100644
index 0000000..380761b
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_open.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <stdarg.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <errno.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(__open, open);
+
+int
+_open(const char *path, int flags,...)
+{
+ int fd;
+ int mode = 0;
+ va_list ap;
+
+ /* Check if the file is being created: */
+ if (flags & O_CREAT) {
+ /* Get the creation mode: */
+ va_start(ap, flags);
+ mode = va_arg(ap, int);
+ va_end(ap);
+ }
+ /* Open the file: */
+ if ((fd = __sys_open(path, flags, mode)) < 0) {
+ }
+ /* Initialise the file descriptor table entry: */
+ else if (_thread_fd_table_init(fd) != 0) {
+ /* Quietly close the file: */
+ __sys_close(fd);
+
+ /* Reset the file descriptor: */
+ fd = -1;
+ }
+
+ /* Return the file descriptor or -1 on error: */
+ return (fd);
+}
+
+int
+__open(const char *path, int flags,...)
+{
+ int ret;
+ int mode = 0;
+ va_list ap;
+
+ _thread_enter_cancellation_point();
+
+ /* Check if the file is being created: */
+ if (flags & O_CREAT) {
+ /* Get the creation mode: */
+ va_start(ap, flags);
+ mode = va_arg(ap, int);
+ va_end(ap);
+ }
+
+ ret = _open(path, flags, mode);
+ _thread_leave_cancellation_point();
+
+ return ret;
+}
diff --git a/lib/libc_r/uthread/uthread_pause.c b/lib/libc_r/uthread/uthread_pause.c
new file mode 100644
index 0000000..57b508f
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_pause.c
@@ -0,0 +1,48 @@
+/*
+ * 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$
+ */
+
+#include <unistd.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pause, pause);
+
+int
+_pause(void)
+{
+ int ret;
+
+ _thread_enter_cancellation_point();
+ ret = __pause();
+ _thread_leave_cancellation_point();
+
+ return ret;
+}
diff --git a/lib/libc_r/uthread/uthread_pipe.c b/lib/libc_r/uthread/uthread_pipe.c
new file mode 100644
index 0000000..f47e7d6
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_pipe.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <unistd.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pipe, pipe);
+
+int
+_pipe(int fds[2])
+{
+ int ret;
+ if ((ret = __sys_pipe(fds)) >= 0) {
+ if (_thread_fd_table_init(fds[0]) != 0 ||
+ _thread_fd_table_init(fds[1]) != 0) {
+ __sys_close(fds[0]);
+ __sys_close(fds[1]);
+ ret = -1;
+ }
+ }
+ return (ret);
+}
diff --git a/lib/libc_r/uthread/uthread_poll.c b/lib/libc_r/uthread/uthread_poll.c
new file mode 100644
index 0000000..62b2613
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_poll.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 1999 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <poll.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/fcntl.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(__poll, poll);
+
+int
+_poll(struct pollfd *fds, unsigned int nfds, int timeout)
+{
+ struct pthread *curthread = _get_curthread();
+ struct timespec ts;
+ int numfds = nfds;
+ int i, ret = 0;
+ struct pthread_poll_data data;
+
+ if (numfds > _thread_dtablesize) {
+ numfds = _thread_dtablesize;
+ }
+ /* Check if a timeout was specified: */
+ if (timeout == INFTIM) {
+ /* Wait for ever: */
+ _thread_kern_set_timeout(NULL);
+ } else if (timeout > 0) {
+ /* Convert the timeout in msec to a timespec: */
+ ts.tv_sec = timeout / 1000;
+ ts.tv_nsec = (timeout % 1000) * 1000000;
+
+ /* Set the wake up time: */
+ _thread_kern_set_timeout(&ts);
+ } else if (timeout < 0) {
+ /* a timeout less than zero but not == INFTIM is invalid */
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (((ret = __sys_poll(fds, numfds, 0)) == 0) && (timeout != 0)) {
+ data.nfds = numfds;
+ data.fds = fds;
+
+ /*
+ * Clear revents in case of a timeout which leaves fds
+ * unchanged:
+ */
+ for (i = 0; i < numfds; i++) {
+ fds[i].revents = 0;
+ }
+
+ curthread->data.poll_data = &data;
+ curthread->interrupted = 0;
+ _thread_kern_sched_state(PS_POLL_WAIT, __FILE__, __LINE__);
+ if (curthread->interrupted) {
+ errno = EINTR;
+ ret = -1;
+ } else {
+ ret = data.nfds;
+ }
+ }
+
+ return (ret);
+}
+
+int
+__poll(struct pollfd *fds, unsigned int nfds, int timeout)
+{
+ int ret;
+
+ _thread_enter_cancellation_point();
+ ret = _poll(fds, nfds, timeout);
+ _thread_leave_cancellation_point();
+
+ return ret;
+}
diff --git a/lib/libc_r/uthread/uthread_priority_queue.c b/lib/libc_r/uthread/uthread_priority_queue.c
new file mode 100644
index 0000000..b700d97
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_priority_queue.c
@@ -0,0 +1,370 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+#include <stdlib.h>
+#include <sys/queue.h>
+#include <string.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+/* Prototypes: */
+static void pq_insert_prio_list(pq_queue_t *pq, int prio);
+
+#if defined(_PTHREADS_INVARIANTS)
+
+static int _pq_active = 0;
+
+#define _PQ_IN_SCHEDQ (PTHREAD_FLAGS_IN_PRIOQ | PTHREAD_FLAGS_IN_WAITQ | PTHREAD_FLAGS_IN_WORKQ)
+
+#define _PQ_SET_ACTIVE() _pq_active = 1
+#define _PQ_CLEAR_ACTIVE() _pq_active = 0
+#define _PQ_ASSERT_ACTIVE(msg) do { \
+ if (_pq_active == 0) \
+ PANIC(msg); \
+} while (0)
+#define _PQ_ASSERT_INACTIVE(msg) do { \
+ if (_pq_active != 0) \
+ PANIC(msg); \
+} while (0)
+#define _PQ_ASSERT_IN_WAITQ(thrd, msg) do { \
+ if (((thrd)->flags & PTHREAD_FLAGS_IN_WAITQ) == 0) \
+ PANIC(msg); \
+} while (0)
+#define _PQ_ASSERT_IN_PRIOQ(thrd, msg) do { \
+ if (((thrd)->flags & PTHREAD_FLAGS_IN_PRIOQ) == 0) \
+ PANIC(msg); \
+} while (0)
+#define _PQ_ASSERT_NOT_QUEUED(thrd, msg) do { \
+ if (((thrd)->flags & _PQ_IN_SCHEDQ) != 0) \
+ PANIC(msg); \
+} while (0)
+#define _PQ_ASSERT_PROTECTED(msg) \
+ PTHREAD_ASSERT((_thread_kern_in_sched != 0) || \
+ ((_get_curthread())->sig_defer_count > 0) ||\
+ (_sig_in_handler != 0), msg);
+
+#else
+
+#define _PQ_SET_ACTIVE()
+#define _PQ_CLEAR_ACTIVE()
+#define _PQ_ASSERT_ACTIVE(msg)
+#define _PQ_ASSERT_INACTIVE(msg)
+#define _PQ_ASSERT_IN_WAITQ(thrd, msg)
+#define _PQ_ASSERT_IN_PRIOQ(thrd, msg)
+#define _PQ_ASSERT_NOT_QUEUED(thrd, msg)
+#define _PQ_ASSERT_PROTECTED(msg)
+
+#endif
+
+int
+_pq_alloc(pq_queue_t *pq, int minprio, int maxprio)
+{
+ int ret = 0;
+ int prioslots = maxprio - minprio + 1;
+
+ if (pq == NULL)
+ ret = -1;
+
+ /* Create the priority queue with (maxprio - minprio + 1) slots: */
+ else if ((pq->pq_lists =
+ (pq_list_t *) malloc(sizeof(pq_list_t) * prioslots)) == NULL)
+ ret = -1;
+
+ else {
+ /* Remember the queue size: */
+ pq->pq_size = prioslots;
+ ret = _pq_init(pq);
+ }
+ return (ret);
+}
+
+int
+_pq_init(pq_queue_t *pq)
+{
+ int i, ret = 0;
+
+ if ((pq == NULL) || (pq->pq_lists == NULL))
+ ret = -1;
+
+ else {
+ /* Initialize the queue for each priority slot: */
+ for (i = 0; i < pq->pq_size; i++) {
+ TAILQ_INIT(&pq->pq_lists[i].pl_head);
+ pq->pq_lists[i].pl_prio = i;
+ pq->pq_lists[i].pl_queued = 0;
+ }
+
+ /* Initialize the priority queue: */
+ TAILQ_INIT(&pq->pq_queue);
+ _PQ_CLEAR_ACTIVE();
+ }
+ return (ret);
+}
+
+void
+_pq_remove(pq_queue_t *pq, pthread_t pthread)
+{
+ int prio = pthread->active_priority;
+
+ /*
+ * Make some assertions when debugging is enabled:
+ */
+ _PQ_ASSERT_INACTIVE("_pq_remove: pq_active");
+ _PQ_SET_ACTIVE();
+ _PQ_ASSERT_IN_PRIOQ(pthread, "_pq_remove: Not in priority queue");
+ _PQ_ASSERT_PROTECTED("_pq_remove: prioq not protected!");
+
+ /*
+ * Remove this thread from priority list. Note that if
+ * the priority list becomes empty, it is not removed
+ * from the priority queue because another thread may be
+ * added to the priority list (resulting in a needless
+ * removal/insertion). Priority lists are only removed
+ * from the priority queue when _pq_first is called.
+ */
+ TAILQ_REMOVE(&pq->pq_lists[prio].pl_head, pthread, pqe);
+
+ /* This thread is now longer in the priority queue. */
+ pthread->flags &= ~PTHREAD_FLAGS_IN_PRIOQ;
+
+ _PQ_CLEAR_ACTIVE();
+}
+
+
+void
+_pq_insert_head(pq_queue_t *pq, pthread_t pthread)
+{
+ int prio;
+
+ /*
+ * Don't insert suspended threads into the priority queue.
+ * The caller is responsible for setting the threads state.
+ */
+ if ((pthread->flags & PTHREAD_FLAGS_SUSPENDED) != 0) {
+ /* Make sure the threads state is suspended. */
+ if (pthread->state != PS_SUSPENDED)
+ PTHREAD_SET_STATE(pthread, PS_SUSPENDED);
+ } else {
+ /*
+ * Make some assertions when debugging is enabled:
+ */
+ _PQ_ASSERT_INACTIVE("_pq_insert_head: pq_active");
+ _PQ_SET_ACTIVE();
+ _PQ_ASSERT_NOT_QUEUED(pthread,
+ "_pq_insert_head: Already in priority queue");
+ _PQ_ASSERT_PROTECTED("_pq_insert_head: prioq not protected!");
+
+ prio = pthread->active_priority;
+ TAILQ_INSERT_HEAD(&pq->pq_lists[prio].pl_head, pthread, pqe);
+ if (pq->pq_lists[prio].pl_queued == 0)
+ /* Insert the list into the priority queue: */
+ pq_insert_prio_list(pq, prio);
+
+ /* Mark this thread as being in the priority queue. */
+ pthread->flags |= PTHREAD_FLAGS_IN_PRIOQ;
+
+ _PQ_CLEAR_ACTIVE();
+ }
+}
+
+
+void
+_pq_insert_tail(pq_queue_t *pq, pthread_t pthread)
+{
+ int prio;
+
+ /*
+ * Don't insert suspended threads into the priority queue.
+ * The caller is responsible for setting the threads state.
+ */
+ if ((pthread->flags & PTHREAD_FLAGS_SUSPENDED) != 0) {
+ /* Make sure the threads state is suspended. */
+ if (pthread->state != PS_SUSPENDED)
+ PTHREAD_SET_STATE(pthread, PS_SUSPENDED);
+ } else {
+ /*
+ * Make some assertions when debugging is enabled:
+ */
+ _PQ_ASSERT_INACTIVE("_pq_insert_tail: pq_active");
+ _PQ_SET_ACTIVE();
+ _PQ_ASSERT_NOT_QUEUED(pthread,
+ "_pq_insert_tail: Already in priority queue");
+ _PQ_ASSERT_PROTECTED("_pq_insert_tail: prioq not protected!");
+
+ prio = pthread->active_priority;
+ TAILQ_INSERT_TAIL(&pq->pq_lists[prio].pl_head, pthread, pqe);
+ if (pq->pq_lists[prio].pl_queued == 0)
+ /* Insert the list into the priority queue: */
+ pq_insert_prio_list(pq, prio);
+
+ /* Mark this thread as being in the priority queue. */
+ pthread->flags |= PTHREAD_FLAGS_IN_PRIOQ;
+
+ _PQ_CLEAR_ACTIVE();
+ }
+}
+
+
+pthread_t
+_pq_first(pq_queue_t *pq)
+{
+ pq_list_t *pql;
+ pthread_t pthread = NULL;
+
+ /*
+ * Make some assertions when debugging is enabled:
+ */
+ _PQ_ASSERT_INACTIVE("_pq_first: pq_active");
+ _PQ_SET_ACTIVE();
+ _PQ_ASSERT_PROTECTED("_pq_first: prioq not protected!");
+
+ while (((pql = TAILQ_FIRST(&pq->pq_queue)) != NULL) &&
+ (pthread == NULL)) {
+ if ((pthread = TAILQ_FIRST(&pql->pl_head)) == NULL) {
+ /*
+ * The priority list is empty; remove the list
+ * from the queue.
+ */
+ TAILQ_REMOVE(&pq->pq_queue, pql, pl_link);
+
+ /* Mark the list as not being in the queue: */
+ pql->pl_queued = 0;
+ } else if ((pthread->flags & PTHREAD_FLAGS_SUSPENDED) != 0) {
+ /*
+ * This thread is suspended; remove it from the
+ * list and ensure its state is suspended.
+ */
+ TAILQ_REMOVE(&pql->pl_head, pthread, pqe);
+ PTHREAD_SET_STATE(pthread, PS_SUSPENDED);
+
+ /* This thread is now longer in the priority queue. */
+ pthread->flags &= ~PTHREAD_FLAGS_IN_PRIOQ;
+ pthread = NULL;
+ }
+ }
+
+ _PQ_CLEAR_ACTIVE();
+ return (pthread);
+}
+
+
+static void
+pq_insert_prio_list(pq_queue_t *pq, int prio)
+{
+ pq_list_t *pql;
+
+ /*
+ * Make some assertions when debugging is enabled:
+ */
+ _PQ_ASSERT_ACTIVE("pq_insert_prio_list: pq_active");
+ _PQ_ASSERT_PROTECTED("_pq_insert_prio_list: prioq not protected!");
+
+ /*
+ * The priority queue is in descending priority order. Start at
+ * the beginning of the queue and find the list before which the
+ * new list should be inserted.
+ */
+ pql = TAILQ_FIRST(&pq->pq_queue);
+ while ((pql != NULL) && (pql->pl_prio > prio))
+ pql = TAILQ_NEXT(pql, pl_link);
+
+ /* Insert the list: */
+ if (pql == NULL)
+ TAILQ_INSERT_TAIL(&pq->pq_queue, &pq->pq_lists[prio], pl_link);
+ else
+ TAILQ_INSERT_BEFORE(pql, &pq->pq_lists[prio], pl_link);
+
+ /* Mark this list as being in the queue: */
+ pq->pq_lists[prio].pl_queued = 1;
+}
+
+void
+_waitq_insert(pthread_t pthread)
+{
+ pthread_t tid;
+
+ /*
+ * Make some assertions when debugging is enabled:
+ */
+ _PQ_ASSERT_INACTIVE("_waitq_insert: pq_active");
+ _PQ_SET_ACTIVE();
+ _PQ_ASSERT_NOT_QUEUED(pthread, "_waitq_insert: Already in queue");
+
+ if (pthread->wakeup_time.tv_sec == -1)
+ TAILQ_INSERT_TAIL(&_waitingq, pthread, pqe);
+ else {
+ tid = TAILQ_FIRST(&_waitingq);
+ while ((tid != NULL) && (tid->wakeup_time.tv_sec != -1) &&
+ ((tid->wakeup_time.tv_sec < pthread->wakeup_time.tv_sec) ||
+ ((tid->wakeup_time.tv_sec == pthread->wakeup_time.tv_sec) &&
+ (tid->wakeup_time.tv_nsec <= pthread->wakeup_time.tv_nsec))))
+ tid = TAILQ_NEXT(tid, pqe);
+ if (tid == NULL)
+ TAILQ_INSERT_TAIL(&_waitingq, pthread, pqe);
+ else
+ TAILQ_INSERT_BEFORE(tid, pthread, pqe);
+ }
+ pthread->flags |= PTHREAD_FLAGS_IN_WAITQ;
+
+ _PQ_CLEAR_ACTIVE();
+}
+
+void
+_waitq_remove(pthread_t pthread)
+{
+ /*
+ * Make some assertions when debugging is enabled:
+ */
+ _PQ_ASSERT_INACTIVE("_waitq_remove: pq_active");
+ _PQ_SET_ACTIVE();
+ _PQ_ASSERT_IN_WAITQ(pthread, "_waitq_remove: Not in queue");
+
+ TAILQ_REMOVE(&_waitingq, pthread, pqe);
+ pthread->flags &= ~PTHREAD_FLAGS_IN_WAITQ;
+
+ _PQ_CLEAR_ACTIVE();
+}
+
+void
+_waitq_setactive(void)
+{
+ _PQ_ASSERT_INACTIVE("_waitq_setactive: pq_active");
+ _PQ_SET_ACTIVE();
+}
+
+void
+_waitq_clearactive(void)
+{
+ _PQ_ASSERT_ACTIVE("_waitq_clearactive: ! pq_active");
+ _PQ_CLEAR_ACTIVE();
+}
diff --git a/lib/libc_r/uthread/uthread_pselect.c b/lib/libc_r/uthread/uthread_pselect.c
new file mode 100644
index 0000000..9848863
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_pselect.c
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 2002 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. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 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/select.h>
+#include <sys/time.h>
+
+#include <errno.h>
+#include <signal.h>
+#include <pthread.h>
+
+#include "pthread_private.h"
+
+extern int __pselect(int count, fd_set *rfds, fd_set *wfds, fd_set *efds,
+ const struct timespec *timo, const sigset_t *mask);
+
+__weak_reference(_pselect, pselect);
+
+int
+_pselect(int count, fd_set *rfds, fd_set *wfds, fd_set *efds,
+ const struct timespec *timo, const sigset_t *mask)
+{
+ int ret;
+
+ _thread_enter_cancellation_point();
+ ret = __pselect(count, rfds, wfds, efds, timo, mask);
+ _thread_leave_cancellation_point();
+
+ return (ret);
+}
diff --git a/lib/libc_r/uthread/uthread_read.c b/lib/libc_r/uthread/uthread_read.c
new file mode 100644
index 0000000..067befa
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_read.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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/fcntl.h>
+#include <sys/uio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(__read, read);
+
+ssize_t
+_read(int fd, void *buf, size_t nbytes)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+ int type;
+
+ /* POSIX says to do just this: */
+ if (nbytes == 0) {
+ return (0);
+ }
+
+ /* Lock the file descriptor for read: */
+ if ((ret = _FD_LOCK(fd, FD_READ, NULL)) == 0) {
+ /* Get the read/write mode type: */
+ type = _thread_fd_getflags(fd) & O_ACCMODE;
+
+ /* Check if the file is not open for read: */
+ if (type != O_RDONLY && type != O_RDWR) {
+ /* File is not open for read: */
+ errno = EBADF;
+ _FD_UNLOCK(fd, FD_READ);
+ return (-1);
+ }
+
+ /* Perform a non-blocking read syscall: */
+ while ((ret = __sys_read(fd, buf, nbytes)) < 0) {
+ if ((_thread_fd_getflags(fd) & O_NONBLOCK) == 0 &&
+ (errno == EWOULDBLOCK || errno == EAGAIN)) {
+ curthread->data.fd.fd = fd;
+ _thread_kern_set_timeout(NULL);
+
+ /* Reset the interrupted operation flag: */
+ curthread->interrupted = 0;
+
+ _thread_kern_sched_state(PS_FDR_WAIT,
+ __FILE__, __LINE__);
+
+ /*
+ * Check if the operation was
+ * interrupted by a signal
+ */
+ if (curthread->interrupted) {
+ errno = EINTR;
+ ret = -1;
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+ _FD_UNLOCK(fd, FD_READ);
+ }
+ return (ret);
+}
+
+ssize_t
+__read(int fd, void *buf, size_t nbytes)
+{
+ ssize_t ret;
+
+ _thread_enter_cancellation_point();
+ ret = _read(fd, buf, nbytes);
+ _thread_leave_cancellation_point();
+
+ return ret;
+}
diff --git a/lib/libc_r/uthread/uthread_readv.c b/lib/libc_r/uthread/uthread_readv.c
new file mode 100644
index 0000000..e2b79d7
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_readv.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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/fcntl.h>
+#include <sys/uio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(__readv, readv);
+
+ssize_t
+_readv(int fd, const struct iovec * iov, int iovcnt)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+ int type;
+
+ /* Lock the file descriptor for read: */
+ if ((ret = _FD_LOCK(fd, FD_READ, NULL)) == 0) {
+ /* Get the read/write mode type: */
+ type = _thread_fd_getflags(fd) & O_ACCMODE;
+
+ /* Check if the file is not open for read: */
+ if (type != O_RDONLY && type != O_RDWR) {
+ /* File is not open for read: */
+ errno = EBADF;
+ _FD_UNLOCK(fd, FD_READ);
+ return (-1);
+ }
+
+ /* Perform a non-blocking readv syscall: */
+ while ((ret = __sys_readv(fd, iov, iovcnt)) < 0) {
+ if ((_thread_fd_getflags(fd) & O_NONBLOCK) == 0 &&
+ (errno == EWOULDBLOCK || errno == EAGAIN)) {
+ curthread->data.fd.fd = fd;
+ _thread_kern_set_timeout(NULL);
+
+ /* Reset the interrupted operation flag: */
+ curthread->interrupted = 0;
+
+ _thread_kern_sched_state(PS_FDR_WAIT,
+ __FILE__, __LINE__);
+
+ /*
+ * Check if the operation was
+ * interrupted by a signal
+ */
+ if (curthread->interrupted) {
+ errno = EINTR;
+ ret = -1;
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+ _FD_UNLOCK(fd, FD_READ);
+ }
+ return (ret);
+}
+
+ssize_t
+__readv(int fd, const struct iovec *iov, int iovcnt)
+{
+ ssize_t ret;
+
+ _thread_enter_cancellation_point();
+ ret = _readv(fd, iov, iovcnt);
+ _thread_leave_cancellation_point();
+
+ return ret;
+}
diff --git a/lib/libc_r/uthread/uthread_recvfrom.c b/lib/libc_r/uthread/uthread_recvfrom.c
new file mode 100644
index 0000000..e18d449
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_recvfrom.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(__recvfrom, recvfrom);
+
+ssize_t
+_recvfrom(int fd, void *buf, size_t len, int flags, struct sockaddr * from,
+ socklen_t *from_len)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ if ((ret = _FD_LOCK(fd, FD_READ, NULL)) == 0) {
+ while ((ret = __sys_recvfrom(fd, buf, len, flags, from, from_len)) < 0) {
+ if (((_thread_fd_getflags(fd) & O_NONBLOCK) == 0)
+ && ((errno == EWOULDBLOCK) || (errno == EAGAIN))) {
+ curthread->data.fd.fd = fd;
+
+ /* Set the timeout: */
+ _thread_kern_set_timeout(NULL);
+ curthread->interrupted = 0;
+ _thread_kern_sched_state(PS_FDR_WAIT, __FILE__, __LINE__);
+
+ /* Check if the wait was interrupted: */
+ if (curthread->interrupted) {
+ /* Return an error status: */
+ errno = EINTR;
+ ret = -1;
+ break;
+ }
+ } else {
+ ret = -1;
+ break;
+ }
+ }
+ _FD_UNLOCK(fd, FD_READ);
+ }
+ return (ret);
+}
+
+ssize_t
+__recvfrom(int fd, void *buf, size_t len, int flags, struct sockaddr * from,
+ socklen_t *from_len)
+{
+ int ret;
+
+ _thread_enter_cancellation_point();
+ ret = _recvfrom(fd, buf, len, flags, from, from_len);
+ _thread_leave_cancellation_point();
+
+ return (ret);
+}
diff --git a/lib/libc_r/uthread/uthread_recvmsg.c b/lib/libc_r/uthread/uthread_recvmsg.c
new file mode 100644
index 0000000..3ecae3f
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_recvmsg.c
@@ -0,0 +1,87 @@
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(__recvmsg, recvmsg);
+
+ssize_t
+_recvmsg(int fd, struct msghdr *msg, int flags)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ if ((ret = _FD_LOCK(fd, FD_READ, NULL)) == 0) {
+ while ((ret = __sys_recvmsg(fd, msg, flags)) < 0) {
+ if (((_thread_fd_getflags(fd) & O_NONBLOCK) == 0)
+ && ((errno == EWOULDBLOCK) || (errno == EAGAIN))) {
+ curthread->data.fd.fd = fd;
+
+ /* Set the timeout: */
+ _thread_kern_set_timeout(NULL);
+ curthread->interrupted = 0;
+ _thread_kern_sched_state(PS_FDR_WAIT, __FILE__, __LINE__);
+
+ /* Check if the wait was interrupted: */
+ if (curthread->interrupted) {
+ /* Return an error status: */
+ errno = EINTR;
+ ret = -1;
+ break;
+ }
+ } else {
+ ret = -1;
+ break;
+ }
+ }
+ _FD_UNLOCK(fd, FD_READ);
+ }
+ return (ret);
+}
+
+ssize_t
+__recvmsg(int fd, struct msghdr *msg, int flags)
+{
+ int ret;
+
+ _thread_enter_cancellation_point();
+ ret = _recvmsg(fd, msg, flags);
+ _thread_leave_cancellation_point();
+
+ return (ret);
+}
diff --git a/lib/libc_r/uthread/uthread_resume_np.c b/lib/libc_r/uthread/uthread_resume_np.c
new file mode 100644
index 0000000..ed20b6a
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_resume_np.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+static void resume_common(struct pthread *);
+
+__weak_reference(_pthread_resume_np, pthread_resume_np);
+__weak_reference(_pthread_resume_all_np, pthread_resume_all_np);
+
+/* Resume a thread: */
+int
+_pthread_resume_np(pthread_t thread)
+{
+ int ret;
+
+ /* Find the thread in the list of active threads: */
+ if ((ret = _find_thread(thread)) == 0) {
+ /*
+ * Defer signals to protect the scheduling queues
+ * from access by the signal handler:
+ */
+ _thread_kern_sig_defer();
+
+ if ((thread->flags & PTHREAD_FLAGS_SUSPENDED) != 0)
+ resume_common(thread);
+
+ /*
+ * Undefer and handle pending signals, yielding if
+ * necessary:
+ */
+ _thread_kern_sig_undefer();
+ }
+ return (ret);
+}
+
+void
+_pthread_resume_all_np(void)
+{
+ struct pthread *curthread = _get_curthread();
+ struct pthread *thread;
+
+ /*
+ * Defer signals to protect the scheduling queues from access
+ * by the signal handler:
+ */
+ _thread_kern_sig_defer();
+
+ TAILQ_FOREACH(thread, &_thread_list, tle) {
+ if ((thread != curthread) &&
+ ((thread->flags & PTHREAD_FLAGS_SUSPENDED) != 0))
+ resume_common(thread);
+ }
+
+ /*
+ * Undefer and handle pending signals, yielding if necessary:
+ */
+ _thread_kern_sig_undefer();
+}
+
+static void
+resume_common(struct pthread *thread)
+{
+ /* Clear the suspend flag: */
+ thread->flags &= ~PTHREAD_FLAGS_SUSPENDED;
+
+ /*
+ * If the thread's state is suspended, that means it is
+ * now runnable but not in any scheduling queue. Set the
+ * state to running and insert it into the run queue.
+ */
+ if (thread->state == PS_SUSPENDED) {
+ PTHREAD_SET_STATE(thread, PS_RUNNING);
+ if (thread->priority_mutex_count > 0)
+ PTHREAD_PRIOQ_INSERT_HEAD(thread);
+ else
+ PTHREAD_PRIOQ_INSERT_TAIL(thread);
+ }
+}
diff --git a/lib/libc_r/uthread/uthread_rwlock.c b/lib/libc_r/uthread/uthread_rwlock.c
new file mode 100644
index 0000000..fdda04c
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_rwlock.c
@@ -0,0 +1,379 @@
+/*-
+ * Copyright (c) 1998 Alex Nash
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#include "namespace.h"
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "pthread_private.h"
+
+/* maximum number of times a read lock may be obtained */
+#define MAX_READ_LOCKS (INT_MAX - 1)
+
+__weak_reference(_pthread_rwlock_destroy, pthread_rwlock_destroy);
+__weak_reference(_pthread_rwlock_init, pthread_rwlock_init);
+__weak_reference(_pthread_rwlock_rdlock, pthread_rwlock_rdlock);
+__weak_reference(_pthread_rwlock_tryrdlock, pthread_rwlock_tryrdlock);
+__weak_reference(_pthread_rwlock_trywrlock, pthread_rwlock_trywrlock);
+__weak_reference(_pthread_rwlock_unlock, pthread_rwlock_unlock);
+__weak_reference(_pthread_rwlock_wrlock, pthread_rwlock_wrlock);
+
+static int init_static (pthread_rwlock_t *rwlock);
+
+static spinlock_t static_init_lock = _SPINLOCK_INITIALIZER;
+
+static int
+init_static (pthread_rwlock_t *rwlock)
+{
+ int ret;
+
+ _SPINLOCK(&static_init_lock);
+
+ if (*rwlock == NULL)
+ ret = _pthread_rwlock_init(rwlock, NULL);
+ else
+ ret = 0;
+
+ _SPINUNLOCK(&static_init_lock);
+
+ return (ret);
+}
+
+int
+_pthread_rwlock_destroy (pthread_rwlock_t *rwlock)
+{
+ int ret;
+
+ if (rwlock == NULL)
+ ret = EINVAL;
+ else {
+ pthread_rwlock_t prwlock;
+
+ prwlock = *rwlock;
+
+ _pthread_mutex_destroy(&prwlock->lock);
+ _pthread_cond_destroy(&prwlock->read_signal);
+ _pthread_cond_destroy(&prwlock->write_signal);
+ free(prwlock);
+
+ *rwlock = NULL;
+
+ ret = 0;
+ }
+ return (ret);
+}
+
+int
+_pthread_rwlock_init (pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr)
+{
+ pthread_rwlock_t prwlock;
+ int ret;
+
+ /* allocate rwlock object */
+ prwlock = (pthread_rwlock_t)malloc(sizeof(struct pthread_rwlock));
+
+ if (prwlock == NULL)
+ return(ENOMEM);
+
+ /* initialize the lock */
+ if ((ret = _pthread_mutex_init(&prwlock->lock, NULL)) != 0)
+ free(prwlock);
+ else {
+ /* initialize the read condition signal */
+ ret = _pthread_cond_init(&prwlock->read_signal, NULL);
+
+ if (ret != 0) {
+ _pthread_mutex_destroy(&prwlock->lock);
+ free(prwlock);
+ } else {
+ /* initialize the write condition signal */
+ ret = _pthread_cond_init(&prwlock->write_signal, NULL);
+
+ if (ret != 0) {
+ _pthread_cond_destroy(&prwlock->read_signal);
+ _pthread_mutex_destroy(&prwlock->lock);
+ free(prwlock);
+ } else {
+ /* success */
+ prwlock->state = 0;
+ prwlock->blocked_writers = 0;
+
+ *rwlock = prwlock;
+ }
+ }
+ }
+
+ return (ret);
+}
+
+int
+_pthread_rwlock_rdlock (pthread_rwlock_t *rwlock)
+{
+ pthread_rwlock_t prwlock;
+ struct pthread *curthread;
+ int ret;
+
+ if (rwlock == NULL)
+ return(EINVAL);
+
+ prwlock = *rwlock;
+
+ /* check for static initialization */
+ if (prwlock == NULL) {
+ if ((ret = init_static(rwlock)) != 0)
+ return(ret);
+
+ prwlock = *rwlock;
+ }
+
+ /* grab the monitor lock */
+ if ((ret = _pthread_mutex_lock(&prwlock->lock)) != 0)
+ return(ret);
+
+ /* check lock count */
+ if (prwlock->state == MAX_READ_LOCKS) {
+ _pthread_mutex_unlock(&prwlock->lock);
+ return (EAGAIN);
+ }
+
+ curthread = _get_curthread();
+ if ((curthread->rdlock_count > 0) && (prwlock->state > 0)) {
+ /*
+ * To avoid having to track all the rdlocks held by
+ * a thread or all of the threads that hold a rdlock,
+ * we keep a simple count of all the rdlocks held by
+ * a thread. If a thread holds any rdlocks it is
+ * possible that it is attempting to take a recursive
+ * rdlock. If there are blocked writers and precedence
+ * is given to them, then that would result in the thread
+ * deadlocking. So allowing a thread to take the rdlock
+ * when it already has one or more rdlocks avoids the
+ * deadlock. I hope the reader can follow that logic ;-)
+ */
+ ; /* nothing needed */
+ } else {
+ /* give writers priority over readers */
+ while (prwlock->blocked_writers || prwlock->state < 0) {
+ ret = _pthread_cond_wait(&prwlock->read_signal,
+ &prwlock->lock);
+
+ if (ret != 0) {
+ /* can't do a whole lot if this fails */
+ _pthread_mutex_unlock(&prwlock->lock);
+ return(ret);
+ }
+ }
+ }
+
+ curthread->rdlock_count++;
+ prwlock->state++; /* indicate we are locked for reading */
+
+ /*
+ * Something is really wrong if this call fails. Returning
+ * error won't do because we've already obtained the read
+ * lock. Decrementing 'state' is no good because we probably
+ * don't have the monitor lock.
+ */
+ _pthread_mutex_unlock(&prwlock->lock);
+
+ return (ret);
+}
+
+int
+_pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock)
+{
+ pthread_rwlock_t prwlock;
+ struct pthread *curthread;
+ int ret;
+
+ if (rwlock == NULL)
+ return(EINVAL);
+
+ prwlock = *rwlock;
+
+ /* check for static initialization */
+ if (prwlock == NULL) {
+ if ((ret = init_static(rwlock)) != 0)
+ return(ret);
+
+ prwlock = *rwlock;
+ }
+
+ /* grab the monitor lock */
+ if ((ret = _pthread_mutex_lock(&prwlock->lock)) != 0)
+ return(ret);
+
+ curthread = _get_curthread();
+ if (prwlock->state == MAX_READ_LOCKS)
+ ret = EAGAIN; /* too many read locks acquired */
+ else if ((curthread->rdlock_count > 0) && (prwlock->state > 0)) {
+ /* see comment for pthread_rwlock_rdlock() */
+ curthread->rdlock_count++;
+ prwlock->state++;
+ }
+ /* give writers priority over readers */
+ else if (prwlock->blocked_writers || prwlock->state < 0)
+ ret = EBUSY;
+ else {
+ prwlock->state++; /* indicate we are locked for reading */
+ curthread->rdlock_count++;
+ }
+
+ /* see the comment on this in pthread_rwlock_rdlock */
+ _pthread_mutex_unlock(&prwlock->lock);
+
+ return (ret);
+}
+
+int
+_pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock)
+{
+ pthread_rwlock_t prwlock;
+ int ret;
+
+ if (rwlock == NULL)
+ return(EINVAL);
+
+ prwlock = *rwlock;
+
+ /* check for static initialization */
+ if (prwlock == NULL) {
+ if ((ret = init_static(rwlock)) != 0)
+ return(ret);
+
+ prwlock = *rwlock;
+ }
+
+ /* grab the monitor lock */
+ if ((ret = _pthread_mutex_lock(&prwlock->lock)) != 0)
+ return(ret);
+
+ if (prwlock->state != 0)
+ ret = EBUSY;
+ else
+ /* indicate we are locked for writing */
+ prwlock->state = -1;
+
+ /* see the comment on this in pthread_rwlock_rdlock */
+ _pthread_mutex_unlock(&prwlock->lock);
+
+ return (ret);
+}
+
+int
+_pthread_rwlock_unlock (pthread_rwlock_t *rwlock)
+{
+ pthread_rwlock_t prwlock;
+ struct pthread *curthread;
+ int ret;
+
+ if (rwlock == NULL)
+ return(EINVAL);
+
+ prwlock = *rwlock;
+
+ if (prwlock == NULL)
+ return(EINVAL);
+
+ /* grab the monitor lock */
+ if ((ret = _pthread_mutex_lock(&prwlock->lock)) != 0)
+ return(ret);
+
+ curthread = _get_curthread();
+ if (prwlock->state > 0) {
+ curthread->rdlock_count--;
+ prwlock->state--;
+ if (prwlock->state == 0 && prwlock->blocked_writers)
+ ret = _pthread_cond_signal(&prwlock->write_signal);
+ } else if (prwlock->state < 0) {
+ prwlock->state = 0;
+
+ if (prwlock->blocked_writers)
+ ret = _pthread_cond_signal(&prwlock->write_signal);
+ else
+ ret = _pthread_cond_broadcast(&prwlock->read_signal);
+ } else
+ ret = EINVAL;
+
+ /* see the comment on this in pthread_rwlock_rdlock */
+ _pthread_mutex_unlock(&prwlock->lock);
+
+ return (ret);
+}
+
+int
+_pthread_rwlock_wrlock (pthread_rwlock_t *rwlock)
+{
+ pthread_rwlock_t prwlock;
+ int ret;
+
+ if (rwlock == NULL)
+ return(EINVAL);
+
+ prwlock = *rwlock;
+
+ /* check for static initialization */
+ if (prwlock == NULL) {
+ if ((ret = init_static(rwlock)) != 0)
+ return(ret);
+
+ prwlock = *rwlock;
+ }
+
+ /* grab the monitor lock */
+ if ((ret = _pthread_mutex_lock(&prwlock->lock)) != 0)
+ return(ret);
+
+ while (prwlock->state != 0) {
+ prwlock->blocked_writers++;
+
+ ret = _pthread_cond_wait(&prwlock->write_signal,
+ &prwlock->lock);
+
+ if (ret != 0) {
+ prwlock->blocked_writers--;
+ _pthread_mutex_unlock(&prwlock->lock);
+ return(ret);
+ }
+
+ prwlock->blocked_writers--;
+ }
+
+ /* indicate we are locked for writing */
+ prwlock->state = -1;
+
+ /* see the comment on this in pthread_rwlock_rdlock */
+ _pthread_mutex_unlock(&prwlock->lock);
+
+ return (ret);
+}
+
diff --git a/lib/libc_r/uthread/uthread_rwlockattr.c b/lib/libc_r/uthread/uthread_rwlockattr.c
new file mode 100644
index 0000000..bc1b9ee
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_rwlockattr.c
@@ -0,0 +1,98 @@
+/*-
+ * Copyright (c) 1998 Alex Nash
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_rwlockattr_destroy, pthread_rwlockattr_destroy);
+__weak_reference(_pthread_rwlockattr_getpshared, pthread_rwlockattr_getpshared);
+__weak_reference(_pthread_rwlockattr_init, pthread_rwlockattr_init);
+__weak_reference(_pthread_rwlockattr_setpshared, pthread_rwlockattr_setpshared);
+
+int
+_pthread_rwlockattr_destroy(pthread_rwlockattr_t *rwlockattr)
+{
+ pthread_rwlockattr_t prwlockattr;
+
+ if (rwlockattr == NULL)
+ return(EINVAL);
+
+ prwlockattr = *rwlockattr;
+
+ if (prwlockattr == NULL)
+ return(EINVAL);
+
+ free(prwlockattr);
+
+ return(0);
+}
+
+int
+_pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *rwlockattr,
+ int *pshared)
+{
+ *pshared = (*rwlockattr)->pshared;
+
+ return(0);
+}
+
+int
+_pthread_rwlockattr_init(pthread_rwlockattr_t *rwlockattr)
+{
+ pthread_rwlockattr_t prwlockattr;
+
+ if (rwlockattr == NULL)
+ return(EINVAL);
+
+ prwlockattr = (pthread_rwlockattr_t)
+ malloc(sizeof(struct pthread_rwlockattr));
+
+ if (prwlockattr == NULL)
+ return(ENOMEM);
+
+ prwlockattr->pshared = PTHREAD_PROCESS_PRIVATE;
+ *rwlockattr = prwlockattr;
+
+ return(0);
+}
+
+int
+_pthread_rwlockattr_setpshared(pthread_rwlockattr_t *rwlockattr, int pshared)
+{
+ /* Only PTHREAD_PROCESS_PRIVATE is supported. */
+ if (pshared != PTHREAD_PROCESS_PRIVATE)
+ return(EINVAL);
+
+ (*rwlockattr)->pshared = pshared;
+
+ return(0);
+}
+
diff --git a/lib/libc_r/uthread/uthread_select.c b/lib/libc_r/uthread/uthread_select.c
new file mode 100644
index 0000000..2776cb2
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_select.c
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <unistd.h>
+#include <errno.h>
+#include <poll.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/fcntl.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(__select, select);
+
+int
+_select(int numfds, fd_set * readfds, fd_set * writefds, fd_set * exceptfds,
+ struct timeval * timeout)
+{
+ struct pthread *curthread = _get_curthread();
+ struct timespec ts;
+ int i, ret = 0, f_wait = 1;
+ int pfd_index, got_events = 0, fd_count = 0;
+ struct pthread_poll_data data;
+
+ if (numfds > _thread_dtablesize) {
+ numfds = _thread_dtablesize;
+ }
+ /* Check if a timeout was specified: */
+ if (timeout) {
+ if (timeout->tv_sec < 0 ||
+ timeout->tv_usec < 0 || timeout->tv_usec >= 1000000) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ /* Convert the timeval to a timespec: */
+ TIMEVAL_TO_TIMESPEC(timeout, &ts);
+
+ /* Set the wake up time: */
+ _thread_kern_set_timeout(&ts);
+ if (ts.tv_sec == 0 && ts.tv_nsec == 0)
+ f_wait = 0;
+ } else {
+ /* Wait for ever: */
+ _thread_kern_set_timeout(NULL);
+ }
+
+ /* Count the number of file descriptors to be polled: */
+ if (readfds || writefds || exceptfds) {
+ for (i = 0; i < numfds; i++) {
+ if ((readfds && FD_ISSET(i, readfds)) ||
+ (exceptfds && FD_ISSET(i, exceptfds)) ||
+ (writefds && FD_ISSET(i, writefds))) {
+ fd_count++;
+ }
+ }
+ }
+
+ /*
+ * Allocate memory for poll data if it hasn't already been
+ * allocated or if previously allocated memory is insufficient.
+ */
+ if ((curthread->poll_data.fds == NULL) ||
+ (curthread->poll_data.nfds < fd_count)) {
+ data.fds = (struct pollfd *) realloc(curthread->poll_data.fds,
+ sizeof(struct pollfd) * MAX(128, fd_count));
+ if (data.fds == NULL) {
+ errno = ENOMEM;
+ ret = -1;
+ }
+ else {
+ /*
+ * Note that the threads poll data always
+ * indicates what is allocated, not what is
+ * currently being polled.
+ */
+ curthread->poll_data.fds = data.fds;
+ curthread->poll_data.nfds = MAX(128, fd_count);
+ }
+ }
+ if (ret == 0) {
+ /* Setup the wait data. */
+ data.fds = curthread->poll_data.fds;
+ data.nfds = fd_count;
+
+ /*
+ * Setup the array of pollfds. Optimize this by
+ * running the loop in reverse and stopping when
+ * the number of selected file descriptors is reached.
+ */
+ for (i = numfds - 1, pfd_index = fd_count - 1;
+ (i >= 0) && (pfd_index >= 0); i--) {
+ data.fds[pfd_index].events = 0;
+ if (readfds && FD_ISSET(i, readfds)) {
+ data.fds[pfd_index].events = POLLRDNORM;
+ }
+ if (exceptfds && FD_ISSET(i, exceptfds)) {
+ data.fds[pfd_index].events |= POLLRDBAND;
+ }
+ if (writefds && FD_ISSET(i, writefds)) {
+ data.fds[pfd_index].events |= POLLWRNORM;
+ }
+ if (data.fds[pfd_index].events != 0) {
+ /*
+ * Set the file descriptor to be polled and
+ * clear revents in case of a timeout which
+ * leaves fds unchanged:
+ */
+ data.fds[pfd_index].fd = i;
+ data.fds[pfd_index].revents = 0;
+ pfd_index--;
+ }
+ }
+ if (((ret = __sys_poll(data.fds, data.nfds, 0)) == 0) &&
+ (f_wait != 0)) {
+ curthread->data.poll_data = &data;
+ curthread->interrupted = 0;
+ _thread_kern_sched_state(PS_SELECT_WAIT, __FILE__, __LINE__);
+ if (curthread->interrupted) {
+ errno = EINTR;
+ data.nfds = 0;
+ ret = -1;
+ } else
+ ret = data.nfds;
+ }
+ }
+
+ if (ret >= 0) {
+ numfds = 0;
+ for (i = 0; i < fd_count; i++) {
+ /*
+ * Check the results of the poll and clear
+ * this file descriptor from the fdset if
+ * the requested event wasn't ready.
+ */
+
+ /*
+ * First check for invalid descriptor.
+ * If found, set errno and return -1.
+ */
+ if (data.fds[i].revents & POLLNVAL) {
+ errno = EBADF;
+ return -1;
+ }
+
+ got_events = 0;
+ if (readfds != NULL) {
+ if (FD_ISSET(data.fds[i].fd, readfds)) {
+ if ((data.fds[i].revents & (POLLIN
+ | POLLRDNORM | POLLERR
+ | POLLHUP | POLLNVAL)) != 0)
+ got_events++;
+ else
+ FD_CLR(data.fds[i].fd, readfds);
+ }
+ }
+ if (writefds != NULL) {
+ if (FD_ISSET(data.fds[i].fd, writefds)) {
+ if ((data.fds[i].revents & (POLLOUT
+ | POLLWRNORM | POLLWRBAND | POLLERR
+ | POLLHUP | POLLNVAL)) != 0)
+ got_events++;
+ else
+ FD_CLR(data.fds[i].fd,
+ writefds);
+ }
+ }
+ if (exceptfds != NULL) {
+ if (FD_ISSET(data.fds[i].fd, exceptfds)) {
+ if (data.fds[i].revents & (POLLRDBAND |
+ POLLPRI))
+ got_events++;
+ else
+ FD_CLR(data.fds[i].fd,
+ exceptfds);
+ }
+ }
+ if (got_events != 0)
+ numfds+=got_events;
+ }
+ ret = numfds;
+ }
+
+ return (ret);
+}
+
+int
+__select(int numfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+ struct timeval *timeout)
+{
+ int ret;
+
+ _thread_enter_cancellation_point();
+ ret = _select(numfds, readfds, writefds, exceptfds, timeout);
+ _thread_leave_cancellation_point();
+
+ return ret;
+}
diff --git a/lib/libc_r/uthread/uthread_self.c b/lib/libc_r/uthread/uthread_self.c
new file mode 100644
index 0000000..1c09e3d
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_self.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 "pthread_private.h"
+
+__weak_reference(_pthread_self, pthread_self);
+
+pthread_t
+_pthread_self(void)
+{
+ /* Return the running thread pointer: */
+ return (_get_curthread());
+}
diff --git a/lib/libc_r/uthread/uthread_sem.c b/lib/libc_r/uthread/uthread_sem.c
new file mode 100644
index 0000000..f85bb91
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_sem.c
@@ -0,0 +1,256 @@
+/*
+ * 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$
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <semaphore.h>
+#include "namespace.h"
+#include <pthread.h>
+#include "un-namespace.h"
+#include "pthread_private.h"
+
+#define _SEM_CHECK_VALIDITY(sem) \
+ if ((*(sem))->magic != SEM_MAGIC) { \
+ errno = EINVAL; \
+ retval = -1; \
+ goto RETURN; \
+ }
+
+__weak_reference(_sem_init, sem_init);
+__weak_reference(_sem_destroy, sem_destroy);
+__weak_reference(_sem_open, sem_open);
+__weak_reference(_sem_close, sem_close);
+__weak_reference(_sem_unlink, sem_unlink);
+__weak_reference(_sem_wait, sem_wait);
+__weak_reference(_sem_trywait, sem_trywait);
+__weak_reference(_sem_post, sem_post);
+__weak_reference(_sem_getvalue, sem_getvalue);
+
+
+int
+_sem_init(sem_t *sem, int pshared, unsigned int value)
+{
+ int retval;
+
+ /*
+ * Range check the arguments.
+ */
+ if (pshared != 0) {
+ /*
+ * The user wants a semaphore that can be shared among
+ * processes, which this implementation can't do. Sounds like a
+ * permissions problem to me (yeah right).
+ */
+ errno = EPERM;
+ retval = -1;
+ goto RETURN;
+ }
+
+ if (value > SEM_VALUE_MAX) {
+ errno = EINVAL;
+ retval = -1;
+ goto RETURN;
+ }
+
+ *sem = (sem_t)malloc(sizeof(struct sem));
+ if (*sem == NULL) {
+ errno = ENOSPC;
+ retval = -1;
+ goto RETURN;
+ }
+
+ /*
+ * Initialize the semaphore.
+ */
+ if (_pthread_mutex_init(&(*sem)->lock, NULL) != 0) {
+ free(*sem);
+ errno = ENOSPC;
+ retval = -1;
+ goto RETURN;
+ }
+
+ if (_pthread_cond_init(&(*sem)->gtzero, NULL) != 0) {
+ _pthread_mutex_destroy(&(*sem)->lock);
+ free(*sem);
+ errno = ENOSPC;
+ retval = -1;
+ goto RETURN;
+ }
+
+ (*sem)->count = (u_int32_t)value;
+ (*sem)->nwaiters = 0;
+ (*sem)->magic = SEM_MAGIC;
+
+ retval = 0;
+ RETURN:
+ return retval;
+}
+
+int
+_sem_destroy(sem_t *sem)
+{
+ int retval;
+
+ _SEM_CHECK_VALIDITY(sem);
+
+ /* Make sure there are no waiters. */
+ _pthread_mutex_lock(&(*sem)->lock);
+ if ((*sem)->nwaiters > 0) {
+ _pthread_mutex_unlock(&(*sem)->lock);
+ errno = EBUSY;
+ retval = -1;
+ goto RETURN;
+ }
+ _pthread_mutex_unlock(&(*sem)->lock);
+
+ _pthread_mutex_destroy(&(*sem)->lock);
+ _pthread_cond_destroy(&(*sem)->gtzero);
+ (*sem)->magic = 0;
+
+ free(*sem);
+
+ retval = 0;
+ RETURN:
+ return retval;
+}
+
+sem_t *
+_sem_open(const char *name, int oflag, ...)
+{
+ errno = ENOSYS;
+ return SEM_FAILED;
+}
+
+int
+_sem_close(sem_t *sem)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int
+_sem_unlink(const char *name)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int
+_sem_wait(sem_t *sem)
+{
+ int retval;
+
+ _thread_enter_cancellation_point();
+
+ _SEM_CHECK_VALIDITY(sem);
+
+ _pthread_mutex_lock(&(*sem)->lock);
+
+ while ((*sem)->count == 0) {
+ (*sem)->nwaiters++;
+ _pthread_cond_wait(&(*sem)->gtzero, &(*sem)->lock);
+ (*sem)->nwaiters--;
+ }
+ (*sem)->count--;
+
+ _pthread_mutex_unlock(&(*sem)->lock);
+
+ retval = 0;
+ RETURN:
+ _thread_leave_cancellation_point();
+ return retval;
+}
+
+int
+_sem_trywait(sem_t *sem)
+{
+ int retval;
+
+ _SEM_CHECK_VALIDITY(sem);
+
+ _pthread_mutex_lock(&(*sem)->lock);
+
+ if ((*sem)->count > 0) {
+ (*sem)->count--;
+ retval = 0;
+ } else {
+ errno = EAGAIN;
+ retval = -1;
+ }
+
+ _pthread_mutex_unlock(&(*sem)->lock);
+
+ RETURN:
+ return retval;
+}
+
+int
+_sem_post(sem_t *sem)
+{
+ int retval;
+
+ _SEM_CHECK_VALIDITY(sem);
+
+ /*
+ * sem_post() is required to be safe to call from within signal
+ * handlers. Thus, we must defer signals.
+ */
+ _thread_kern_sig_defer();
+
+ _pthread_mutex_lock(&(*sem)->lock);
+
+ (*sem)->count++;
+ if ((*sem)->nwaiters > 0)
+ _pthread_cond_signal(&(*sem)->gtzero);
+
+ _pthread_mutex_unlock(&(*sem)->lock);
+
+ _thread_kern_sig_undefer();
+ retval = 0;
+ RETURN:
+ return retval;
+}
+
+int
+_sem_getvalue(sem_t *sem, int *sval)
+{
+ int retval;
+
+ _SEM_CHECK_VALIDITY(sem);
+
+ _pthread_mutex_lock(&(*sem)->lock);
+ *sval = (int)(*sem)->count;
+ _pthread_mutex_unlock(&(*sem)->lock);
+
+ retval = 0;
+ RETURN:
+ return retval;
+}
diff --git a/lib/libc_r/uthread/uthread_sendfile.c b/lib/libc_r/uthread/uthread_sendfile.c
new file mode 100644
index 0000000..ddaddeb
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_sendfile.c
@@ -0,0 +1,194 @@
+/*
+ * 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$
+ */
+
+#include <sys/fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <errno.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_sendfile, sendfile);
+
+int
+_sendfile(int fd, int s, off_t offset, size_t nbytes, struct sf_hdtr *hdtr,
+ off_t *sbytes, int flags)
+{
+ struct pthread *curthread = _get_curthread();
+ int type, blocking;
+ int ret = 0;
+ ssize_t wvret, num = 0;
+ off_t n, nwritten = 0;
+
+ /*
+ * Write the headers if any.
+ * If some data is written but not all we must return here.
+ */
+ if ((hdtr != NULL) && (hdtr->headers != NULL)) {
+ if ((wvret = writev(s, hdtr->headers, hdtr->hdr_cnt)) == -1) {
+ ret = -1;
+ goto ERROR;
+ } else {
+ int i;
+ ssize_t hdrtot;
+
+ nwritten += wvret;
+
+ for (i = 0, hdrtot = 0; i < hdtr->hdr_cnt; i++)
+ hdrtot += hdtr->headers[i].iov_len;
+ if (wvret < hdrtot)
+ goto SHORT_WRITE;
+ }
+ }
+
+ /* Lock the descriptors. */
+ if ((ret = _FD_LOCK(fd, FD_READ, NULL)) != 0) {
+ ret = -1;
+ errno = EBADF;
+ goto ERROR;
+ }
+ if ((ret = _FD_LOCK(s, FD_WRITE, NULL)) != 0) {
+ ret = -1;
+ errno = EBADF;
+ goto ERROR_1;
+ }
+
+ /* Check the descriptor access modes. */
+ type = _thread_fd_getflags(fd) & O_ACCMODE;
+ if (type != O_RDONLY && type != O_RDWR) {
+ /* File is not open for read. */
+ ret = -1;
+ errno = EBADF;
+ goto ERROR_2;
+ }
+ type = _thread_fd_getflags(s) & O_ACCMODE;
+ if (type != O_WRONLY && type != O_RDWR) {
+ /* File is not open for write. */
+ ret = -1;
+ errno = EBADF;
+ goto ERROR_2;
+ }
+
+ /* Check if file operations are to block */
+ blocking = ((_thread_fd_getflags(s) & O_NONBLOCK) == 0);
+
+ /*
+ * Loop while no error occurs and until the expected number of bytes are
+ * written.
+ */
+ for (;;) {
+ /* Perform a non-blocking sendfile syscall. */
+ ret = __sys_sendfile(fd, s, offset + num, nbytes - num,
+ NULL, &n, flags);
+
+ /*
+ * We have to handle the sideways return path of sendfile.
+ *
+ * If the result is 0, we're done.
+ * If the result is anything else check the errno.
+ * If the errno is not EGAIN return the error.
+ * Otherwise, take into account how much
+ * sendfile may have written for us because sendfile can
+ * return EAGAIN even though it has written data.
+ *
+ * We don't clear 'ret' because the sendfile(2) syscall
+ * would not have either.
+ */
+ if (ret == 0) {
+ /* Writing completed. */
+ num += n;
+ break;
+ } else if ((ret == -1) && (errno == EAGAIN)) {
+ /*
+ * Some bytes were written but there are still more to
+ * write.
+ */
+
+ /* Update the count of bytes written. */
+ num += n;
+
+ /*
+ * If we're not blocking then return.
+ */
+ if (!blocking) {
+ _FD_UNLOCK(s, FD_WRITE);
+ _FD_UNLOCK(fd, FD_READ);
+ goto SHORT_WRITE;
+ }
+
+ /*
+ * Otherwise wait on the fd.
+ */
+ curthread->data.fd.fd = fd;
+ _thread_kern_set_timeout(NULL);
+
+ /* Reset the interrupted operation flag. */
+ curthread->interrupted = 0;
+
+ _thread_kern_sched_state(PS_FDW_WAIT, __FILE__,
+ __LINE__);
+
+ if (curthread->interrupted) {
+ /* Interrupted by a signal. Return an error. */
+ break;
+ }
+ } else {
+ /* Incomplete non-blocking syscall, or error. */
+ break;
+ }
+ }
+
+ ERROR_2:
+ _FD_UNLOCK(s, FD_WRITE);
+ ERROR_1:
+ _FD_UNLOCK(fd, FD_READ);
+ ERROR:
+ if (ret == 0) {
+ /* Write the trailers, if any. */
+ if ((hdtr != NULL) && (hdtr->trailers != NULL)) {
+ if ((wvret = writev(s, hdtr->trailers, hdtr->trl_cnt))
+ == -1)
+ ret = -1;
+ else
+ nwritten += wvret;
+ }
+ }
+ SHORT_WRITE:
+ if (sbytes != NULL) {
+ /*
+ * Number of bytes written in headers/trailers, plus in the main
+ * sendfile() loop.
+ */
+ *sbytes = nwritten + num;
+ }
+ return (ret);
+}
diff --git a/lib/libc_r/uthread/uthread_sendmsg.c b/lib/libc_r/uthread/uthread_sendmsg.c
new file mode 100644
index 0000000..5bb825c
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_sendmsg.c
@@ -0,0 +1,86 @@
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(__sendmsg, sendmsg);
+
+ssize_t
+_sendmsg(int fd, const struct msghdr *msg, int flags)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ if ((ret = _FD_LOCK(fd, FD_WRITE, NULL)) == 0) {
+ while ((ret = __sys_sendmsg(fd, msg, flags)) < 0) {
+ if (!(_thread_fd_getflags(fd) & O_NONBLOCK)
+ && ((errno == EWOULDBLOCK) || (errno == EAGAIN))) {
+ curthread->data.fd.fd = fd;
+
+ /* Set the timeout: */
+ _thread_kern_set_timeout(NULL);
+ curthread->interrupted = 0;
+ _thread_kern_sched_state(PS_FDW_WAIT, __FILE__, __LINE__);
+
+ /* Check if the operation was interrupted: */
+ if (curthread->interrupted) {
+ errno = EINTR;
+ ret = -1;
+ break;
+ }
+ } else {
+ ret = -1;
+ break;
+ }
+ }
+ _FD_UNLOCK(fd, FD_WRITE);
+ }
+ return (ret);
+}
+
+ssize_t
+__sendmsg(int fd, const struct msghdr *msg, int flags)
+{
+ int ret;
+
+ _thread_enter_cancellation_point();
+ ret = _sendmsg(fd, msg, flags);
+ _thread_leave_cancellation_point();
+
+ return (ret);
+}
diff --git a/lib/libc_r/uthread/uthread_sendto.c b/lib/libc_r/uthread/uthread_sendto.c
new file mode 100644
index 0000000..17c2907
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_sendto.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(__sendto, sendto);
+
+ssize_t
+_sendto(int fd, const void *msg, size_t len, int flags, const struct
+ sockaddr * to, socklen_t to_len)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ if ((ret = _FD_LOCK(fd, FD_WRITE, NULL)) == 0) {
+ while ((ret = __sys_sendto(fd, msg, len, flags, to, to_len)) < 0) {
+ if (((_thread_fd_getflags(fd) & O_NONBLOCK) == 0)
+ && ((errno == EWOULDBLOCK) || (errno == EAGAIN))) {
+ curthread->data.fd.fd = fd;
+
+ /* Set the timeout: */
+ _thread_kern_set_timeout(NULL);
+ curthread->interrupted = 0;
+ _thread_kern_sched_state(PS_FDW_WAIT, __FILE__, __LINE__);
+
+ /* Check if the operation was interrupted: */
+ if (curthread->interrupted) {
+ errno = EINTR;
+ ret = -1;
+ break;
+ }
+ } else {
+ ret = -1;
+ break;
+ }
+ }
+ _FD_UNLOCK(fd, FD_WRITE);
+ }
+ return (ret);
+}
+
+ssize_t
+__sendto(int fd, const void *msg, size_t len, int flags, const struct
+ sockaddr * to, socklen_t to_len)
+{
+ int ret;
+
+ _thread_enter_cancellation_point();
+ ret = _sendto(fd, msg, len, flags, to, to_len);
+ _thread_leave_cancellation_point();
+
+ return (ret);
+}
diff --git a/lib/libc_r/uthread/uthread_seterrno.c b/lib/libc_r/uthread/uthread_seterrno.c
new file mode 100644
index 0000000..0d9474f
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_seterrno.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 "pthread_private.h"
+
+/*
+ * This function needs to reference the global error variable which is
+ * normally hidden from the user.
+ */
+#ifdef errno
+#undef errno;
+#endif
+extern int errno;
+
+void
+_thread_seterrno(pthread_t thread, int error)
+{
+ /* Check for the initial thread: */
+ if (thread == _thread_initial)
+ /* The initial thread always uses the global error variable: */
+ errno = error;
+ else
+ /*
+ * Threads other than the initial thread always use the error
+ * field in the thread structureL
+ */
+ thread->error = error;
+}
diff --git a/lib/libc_r/uthread/uthread_setprio.c b/lib/libc_r/uthread/uthread_setprio.c
new file mode 100644
index 0000000..9099a6e
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_setprio.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 "pthread_private.h"
+
+__weak_reference(_pthread_setprio, pthread_setprio);
+
+int
+_pthread_setprio(pthread_t pthread, int prio)
+{
+ int ret, policy;
+ struct sched_param param;
+
+ if ((ret = pthread_getschedparam(pthread, &policy, &param)) == 0) {
+ param.sched_priority = prio;
+ ret = pthread_setschedparam(pthread, policy, &param);
+ }
+
+ /* Return the error status: */
+ return (ret);
+}
diff --git a/lib/libc_r/uthread/uthread_setschedparam.c b/lib/libc_r/uthread/uthread_setschedparam.c
new file mode 100644
index 0000000..7696762
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_setschedparam.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <sys/param.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_setschedparam, pthread_setschedparam);
+
+int
+_pthread_setschedparam(pthread_t pthread, int policy,
+ const struct sched_param *param)
+{
+ int old_prio, in_readyq = 0, ret = 0;
+
+ if ((param == NULL) || (policy < SCHED_FIFO) || (policy > SCHED_RR)) {
+ /* Return an invalid argument error: */
+ ret = EINVAL;
+ } else if ((param->sched_priority < PTHREAD_MIN_PRIORITY) ||
+ (param->sched_priority > PTHREAD_MAX_PRIORITY)) {
+ /* Return an unsupported value error. */
+ ret = ENOTSUP;
+
+ /* Find the thread in the list of active threads: */
+ } else if ((ret = _find_thread(pthread)) == 0) {
+ /*
+ * Defer signals to protect the scheduling queues from
+ * access by the signal handler:
+ */
+ _thread_kern_sig_defer();
+
+ if (param->sched_priority !=
+ PTHREAD_BASE_PRIORITY(pthread->base_priority)) {
+ /*
+ * Remove the thread from its current priority
+ * queue before any adjustments are made to its
+ * active priority:
+ */
+ old_prio = pthread->active_priority;
+ if ((pthread->flags & PTHREAD_FLAGS_IN_PRIOQ) != 0) {
+ in_readyq = 1;
+ PTHREAD_PRIOQ_REMOVE(pthread);
+ }
+
+ /* Set the thread base priority: */
+ pthread->base_priority &=
+ (PTHREAD_SIGNAL_PRIORITY | PTHREAD_RT_PRIORITY);
+ pthread->base_priority = param->sched_priority;
+
+ /* Recalculate the active priority: */
+ pthread->active_priority = MAX(pthread->base_priority,
+ pthread->inherited_priority);
+
+ if (in_readyq) {
+ if ((pthread->priority_mutex_count > 0) &&
+ (old_prio > pthread->active_priority)) {
+ /*
+ * POSIX states that if the priority is
+ * being lowered, the thread must be
+ * inserted at the head of the queue for
+ * its priority if it owns any priority
+ * protection or inheritence mutexes.
+ */
+ PTHREAD_PRIOQ_INSERT_HEAD(pthread);
+ }
+ else
+ PTHREAD_PRIOQ_INSERT_TAIL(pthread);
+ }
+
+ /*
+ * Check for any mutex priority adjustments. This
+ * includes checking for a priority mutex on which
+ * this thread is waiting.
+ */
+ _mutex_notify_priochange(pthread);
+ }
+
+ /* Set the scheduling policy: */
+ pthread->attr.sched_policy = policy;
+
+ /*
+ * Undefer and handle pending signals, yielding if
+ * necessary:
+ */
+ _thread_kern_sig_undefer();
+ }
+ return(ret);
+}
diff --git a/lib/libc_r/uthread/uthread_setsockopt.c b/lib/libc_r/uthread/uthread_setsockopt.c
new file mode 100644
index 0000000..081518c
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_setsockopt.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_setsockopt, setsockopt);
+
+int
+_setsockopt(int fd, int level, int optname, const void *optval, socklen_t
+ optlen)
+{
+ int ret;
+
+ if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) {
+ ret = __sys_setsockopt(fd, level, optname, optval, optlen);
+ _FD_UNLOCK(fd, FD_RDWR);
+ }
+ return ret;
+}
diff --git a/lib/libc_r/uthread/uthread_shutdown.c b/lib/libc_r/uthread/uthread_shutdown.c
new file mode 100644
index 0000000..a148d85
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_shutdown.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_shutdown, shutdown);
+
+int
+_shutdown(int fd, int how)
+{
+ int ret;
+
+ switch (how) {
+ case 0:
+ if ((ret = _FD_LOCK(fd, FD_READ, NULL)) == 0) {
+ ret = __sys_shutdown(fd, how);
+ _FD_UNLOCK(fd, FD_READ);
+ }
+ break;
+ case 1:
+ if ((ret = _FD_LOCK(fd, FD_WRITE, NULL)) == 0) {
+ ret = __sys_shutdown(fd, how);
+ _FD_UNLOCK(fd, FD_WRITE);
+ }
+ break;
+ case 2:
+ if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) {
+ ret = __sys_shutdown(fd, how);
+ _FD_UNLOCK(fd, FD_RDWR);
+ }
+ break;
+ default:
+ errno = EBADF;
+ ret = -1;
+ break;
+ }
+ return (ret);
+}
diff --git a/lib/libc_r/uthread/uthread_sig.c b/lib/libc_r/uthread/uthread_sig.c
new file mode 100644
index 0000000..3617b36
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_sig.c
@@ -0,0 +1,1147 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/signalvar.h>
+#include <signal.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <setjmp.h>
+#include <string.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+/* Prototypes: */
+static void thread_sig_add(struct pthread *pthread, int sig, int has_args);
+static void thread_sig_check_state(struct pthread *pthread, int sig);
+static struct pthread *thread_sig_find(int sig);
+static void thread_sig_handle_special(int sig);
+static void thread_sigframe_add(struct pthread *thread, int sig,
+ int has_args);
+static void thread_sigframe_save(struct pthread *thread,
+ struct pthread_signal_frame *psf);
+static void thread_sig_invoke_handler(int sig, siginfo_t *info,
+ ucontext_t *ucp);
+
+/*#define DEBUG_SIGNAL*/
+#ifdef DEBUG_SIGNAL
+#define DBG_MSG stdout_debug
+#else
+#define DBG_MSG(x...)
+#endif
+
+#if defined(_PTHREADS_INVARIANTS)
+#define SIG_SET_ACTIVE() _sig_in_handler = 1
+#define SIG_SET_INACTIVE() _sig_in_handler = 0
+#else
+#define SIG_SET_ACTIVE()
+#define SIG_SET_INACTIVE()
+#endif
+
+void
+_thread_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
+{
+ struct pthread *curthread = _get_curthread();
+ struct pthread *pthread, *pthread_h;
+ int in_sched = _thread_kern_in_sched;
+ char c;
+
+ if (ucp == NULL)
+ PANIC("Thread signal handler received null context");
+ DBG_MSG("Got signal %d, current thread %p\n", sig, curthread);
+
+ /* Check if an interval timer signal: */
+ if (sig == _SCHED_SIGNAL) {
+ /* Update the scheduling clock: */
+ gettimeofday((struct timeval *)&_sched_tod, NULL);
+ _sched_ticks++;
+
+ if (in_sched != 0) {
+ /*
+ * The scheduler is already running; ignore this
+ * signal.
+ */
+ }
+ /*
+ * Check if the scheduler interrupt has come when
+ * the currently running thread has deferred thread
+ * signals.
+ */
+ else if (curthread->sig_defer_count > 0)
+ curthread->yield_on_sig_undefer = 1;
+ else {
+ /* Schedule the next thread: */
+ _thread_kern_sched(ucp);
+
+ /*
+ * This point should not be reached, so abort the
+ * process:
+ */
+ PANIC("Returned to signal function from scheduler");
+ }
+ }
+ /*
+ * Check if the kernel has been interrupted while the scheduler
+ * is accessing the scheduling queues or if there is a currently
+ * running thread that has deferred signals.
+ */
+ else if ((in_sched != 0) || (curthread->sig_defer_count > 0)) {
+ /* Cast the signal number to a character variable: */
+ c = sig;
+
+ /*
+ * Write the signal number to the kernel pipe so that it will
+ * be ready to read when this signal handler returns.
+ */
+ if (_queue_signals != 0) {
+ __sys_write(_thread_kern_pipe[1], &c, 1);
+ DBG_MSG("Got signal %d, queueing to kernel pipe\n", sig);
+ }
+ if (_thread_sigq[sig - 1].blocked == 0) {
+ DBG_MSG("Got signal %d, adding to _thread_sigq\n", sig);
+ /*
+ * Do not block this signal; it will be blocked
+ * when the pending signals are run down.
+ */
+ /* _thread_sigq[sig - 1].blocked = 1; */
+
+ /*
+ * Queue the signal, saving siginfo and sigcontext
+ * (ucontext).
+ *
+ * XXX - Do we need to copy siginfo and ucp?
+ */
+ _thread_sigq[sig - 1].signo = sig;
+ if (info != NULL)
+ memcpy(&_thread_sigq[sig - 1].siginfo, info,
+ sizeof(*info));
+ memcpy(&_thread_sigq[sig - 1].uc, ucp, sizeof(*ucp));
+
+ /* Indicate that there are queued signals: */
+ _thread_sigq[sig - 1].pending = 1;
+ _sigq_check_reqd = 1;
+ }
+ /* These signals need special handling: */
+ else if (sig == SIGCHLD || sig == SIGTSTP ||
+ sig == SIGTTIN || sig == SIGTTOU) {
+ _thread_sigq[sig - 1].pending = 1;
+ _thread_sigq[sig - 1].signo = sig;
+ _sigq_check_reqd = 1;
+ }
+ else
+ DBG_MSG("Got signal %d, ignored.\n", sig);
+ }
+ /*
+ * The signal handlers should have been installed so that they
+ * cannot be interrupted by other signals.
+ */
+ else if (_thread_sigq[sig - 1].blocked == 0) {
+ /*
+ * The signal is not blocked; handle the signal.
+ *
+ * Ignore subsequent occurrences of this signal
+ * until the current signal is handled:
+ */
+ _thread_sigq[sig - 1].blocked = 1;
+
+ /* This signal will be handled; clear the pending flag: */
+ _thread_sigq[sig - 1].pending = 0;
+
+ /*
+ * Save siginfo and sigcontext (ucontext).
+ *
+ * XXX - Do we need to copy siginfo and ucp?
+ */
+ _thread_sigq[sig - 1].signo = sig;
+
+ if (info != NULL)
+ memcpy(&_thread_sigq[sig - 1].siginfo, info,
+ sizeof(*info));
+ memcpy(&_thread_sigq[sig - 1].uc, ucp, sizeof(*ucp));
+ SIG_SET_ACTIVE();
+
+ /* Handle special signals: */
+ thread_sig_handle_special(sig);
+
+ pthread_h = NULL;
+ if ((pthread = thread_sig_find(sig)) == NULL)
+ DBG_MSG("No thread to handle signal %d\n", sig);
+ else if (pthread == curthread) {
+ /*
+ * Unblock the signal and restore the process signal
+ * mask in case we don't return from the handler:
+ */
+ _thread_sigq[sig - 1].blocked = 0;
+ __sys_sigprocmask(SIG_SETMASK, &_process_sigmask, NULL);
+
+ /* Call the signal handler for the current thread: */
+ thread_sig_invoke_handler(sig, info, ucp);
+
+ /*
+ * Set the process signal mask in the context; it
+ * could have changed by the handler.
+ */
+ ucp->uc_sigmask = _process_sigmask;
+
+ /* Resume the interrupted thread: */
+ __sys_sigreturn(ucp);
+ } else {
+ DBG_MSG("Got signal %d, adding frame to thread %p\n",
+ sig, pthread);
+
+ /* Setup the target thread to receive the signal: */
+ thread_sig_add(pthread, sig, /*has_args*/ 1);
+
+ /* Take a peek at the next ready to run thread: */
+ pthread_h = PTHREAD_PRIOQ_FIRST();
+ DBG_MSG("Finished adding frame, head of prio list %p\n",
+ pthread_h);
+ }
+ SIG_SET_INACTIVE();
+
+ /*
+ * Switch to a different context if the currently running
+ * thread takes a signal, or if another thread takes a
+ * signal and the currently running thread is not in a
+ * signal handler.
+ */
+ if ((pthread_h != NULL) &&
+ (pthread_h->active_priority > curthread->active_priority)) {
+ /* Enter the kernel scheduler: */
+ _thread_kern_sched(ucp);
+ }
+ }
+ else {
+ SIG_SET_ACTIVE();
+ thread_sig_handle_special(sig);
+ SIG_SET_INACTIVE();
+ }
+}
+
+static void
+thread_sig_invoke_handler(int sig, siginfo_t *info, ucontext_t *ucp)
+ {
+ struct pthread *curthread = _get_curthread();
+ void (*sigfunc)(int, siginfo_t *, void *);
+ int saved_seqno;
+ sigset_t saved_sigmask;
+
+ /* Invoke the signal handler without going through the scheduler:
+ */
+ DBG_MSG("Got signal %d, calling handler for current thread %p\n",
+ sig, curthread);
+
+ /* Save the threads signal mask: */
+ saved_sigmask = curthread->sigmask;
+ saved_seqno = curthread->sigmask_seqno;
+
+ /* Setup the threads signal mask: */
+ SIGSETOR(curthread->sigmask, _thread_sigact[sig - 1].sa_mask);
+ sigaddset(&curthread->sigmask, sig);
+
+ /*
+ * Check that a custom handler is installed and if
+ * the signal is not blocked:
+ */
+ sigfunc = _thread_sigact[sig - 1].sa_sigaction;
+ if (((__sighandler_t *)sigfunc != SIG_DFL) &&
+ ((__sighandler_t *)sigfunc != SIG_IGN)) {
+ if (((_thread_sigact[sig - 1].sa_flags & SA_SIGINFO) != 0) ||
+ (info == NULL))
+ (*(sigfunc))(sig, info, ucp);
+ else
+ (*(sigfunc))(sig, (void*)(intptr_t)info->si_code, ucp);
+ }
+ /*
+ * Only restore the signal mask if it hasn't been changed by the
+ * application during invocation of the signal handler:
+ */
+ if (curthread->sigmask_seqno == saved_seqno)
+ curthread->sigmask = saved_sigmask;
+}
+
+/*
+ * Find a thread that can handle the signal.
+ */
+struct pthread *
+thread_sig_find(int sig)
+{
+ struct pthread *curthread = _get_curthread();
+ int handler_installed;
+ struct pthread *pthread, *pthread_next;
+ struct pthread *suspended_thread, *signaled_thread;
+
+ DBG_MSG("Looking for thread to handle signal %d\n", sig);
+ /* Check if the signal requires a dump of thread information: */
+ if (sig == SIGINFO) {
+ /* Dump thread information to file: */
+ _thread_dump_info();
+
+ /* Unblock this signal to allow further dumps: */
+ _thread_sigq[sig - 1].blocked = 0;
+ }
+ /* Check if an interval timer signal: */
+ else if (sig == _SCHED_SIGNAL) {
+ /*
+ * This shouldn't ever occur (should this panic?).
+ */
+ } else {
+ /*
+ * Enter a loop to look for threads that have the signal
+ * unmasked. POSIX specifies that a thread in a sigwait
+ * will get the signal over any other threads. Second
+ * preference will be threads in in a sigsuspend. Third
+ * preference will be the current thread. If none of the
+ * above, then the signal is delivered to the first thread
+ * that is found. Note that if a custom handler is not
+ * installed, the signal only affects threads in sigwait.
+ */
+ suspended_thread = NULL;
+ if ((curthread != &_thread_kern_thread) &&
+ !sigismember(&curthread->sigmask, sig))
+ signaled_thread = curthread;
+ else
+ signaled_thread = NULL;
+ if ((_thread_sigact[sig - 1].sa_handler == SIG_IGN) ||
+ (_thread_sigact[sig - 1].sa_handler == SIG_DFL))
+ handler_installed = 0;
+ else
+ handler_installed = 1;
+
+ for (pthread = TAILQ_FIRST(&_waitingq);
+ pthread != NULL; pthread = pthread_next) {
+ /*
+ * Grab the next thread before possibly destroying
+ * the link entry.
+ */
+ pthread_next = TAILQ_NEXT(pthread, pqe);
+
+ if ((pthread->state == PS_SIGWAIT) &&
+ sigismember(pthread->data.sigwait, sig)) {
+ /* Change the state of the thread to run: */
+ PTHREAD_NEW_STATE(pthread,PS_RUNNING);
+ /*
+ * A signal handler is not invoked for threads
+ * in sigwait. Clear the blocked and pending
+ * flags.
+ */
+ _thread_sigq[sig - 1].blocked = 0;
+ _thread_sigq[sig - 1].pending = 0;
+
+ /* Return the signal number: */
+ pthread->signo = sig;
+
+ /*
+ * POSIX doesn't doesn't specify which thread
+ * will get the signal if there are multiple
+ * waiters, so we give it to the first thread
+ * we find.
+ *
+ * Do not attempt to deliver this signal
+ * to other threads and do not add the signal
+ * to the process pending set.
+ */
+ return (NULL);
+ }
+ else if ((handler_installed != 0) &&
+ !sigismember(&pthread->sigmask, sig) &&
+ ((pthread->flags & PTHREAD_FLAGS_SUSPENDED) == 0)) {
+ if (pthread->state == PS_SIGSUSPEND) {
+ if (suspended_thread == NULL)
+ suspended_thread = pthread;
+ } else if (signaled_thread == NULL)
+ signaled_thread = pthread;
+ }
+ }
+
+ /*
+ * Only perform wakeups and signal delivery if there is a
+ * custom handler installed:
+ */
+ if (handler_installed == 0) {
+ /*
+ * There is no handler installed. Unblock the
+ * signal so that if a handler _is_ installed, any
+ * subsequent signals can be handled.
+ */
+ _thread_sigq[sig - 1].blocked = 0;
+ } else {
+ /*
+ * If we didn't find a thread in the waiting queue,
+ * check the all threads queue:
+ */
+ if (suspended_thread == NULL &&
+ signaled_thread == NULL) {
+ /*
+ * Enter a loop to look for other threads
+ * capable of receiving the signal:
+ */
+ TAILQ_FOREACH(pthread, &_thread_list, tle) {
+ if (!sigismember(&pthread->sigmask,
+ sig)) {
+ signaled_thread = pthread;
+ break;
+ }
+ }
+ }
+
+ if (suspended_thread == NULL &&
+ signaled_thread == NULL)
+ /*
+ * Add it to the set of signals pending
+ * on the process:
+ */
+ sigaddset(&_process_sigpending, sig);
+ else {
+ /*
+ * We only deliver the signal to one thread;
+ * give preference to the suspended thread:
+ */
+ if (suspended_thread != NULL)
+ pthread = suspended_thread;
+ else
+ pthread = signaled_thread;
+ return (pthread);
+ }
+ }
+ }
+
+ /* Returns nothing. */
+ return (NULL);
+}
+
+void
+_thread_sig_check_pending(struct pthread *pthread)
+{
+ sigset_t sigset;
+ int i;
+
+ /*
+ * Check if there are pending signals for the running
+ * thread or process that aren't blocked:
+ */
+ sigset = pthread->sigpend;
+ SIGSETOR(sigset, _process_sigpending);
+ SIGSETNAND(sigset, pthread->sigmask);
+ if (SIGNOTEMPTY(sigset)) {
+ for (i = 1; i < NSIG; i++) {
+ if (sigismember(&sigset, i) != 0) {
+ if (sigismember(&pthread->sigpend, i) != 0)
+ thread_sig_add(pthread, i,
+ /*has_args*/ 0);
+ else {
+ thread_sig_add(pthread, i,
+ /*has_args*/ 1);
+ sigdelset(&_process_sigpending, i);
+ }
+ }
+ }
+ }
+}
+
+/*
+ * This can only be called from the kernel scheduler. It assumes that
+ * all thread contexts are saved and that a signal frame can safely be
+ * added to any user thread.
+ */
+void
+_thread_sig_handle_pending(void)
+{
+ struct pthread *pthread;
+ int i, sig;
+
+ PTHREAD_ASSERT(_thread_kern_in_sched != 0,
+ "_thread_sig_handle_pending called from outside kernel schedule");
+ /*
+ * Check the array of pending signals:
+ */
+ for (i = 0; i < NSIG; i++) {
+ if (_thread_sigq[i].pending != 0) {
+ /* This signal is no longer pending. */
+ _thread_sigq[i].pending = 0;
+
+ sig = _thread_sigq[i].signo;
+
+ /* Some signals need special handling: */
+ thread_sig_handle_special(sig);
+
+ if (_thread_sigq[i].blocked == 0) {
+ /*
+ * Block future signals until this one
+ * is handled:
+ */
+ _thread_sigq[i].blocked = 1;
+
+ if ((pthread = thread_sig_find(sig)) != NULL) {
+ /*
+ * Setup the target thread to receive
+ * the signal:
+ */
+ thread_sig_add(pthread, sig,
+ /*has_args*/ 1);
+ }
+ }
+ }
+ }
+}
+
+static void
+thread_sig_handle_special(int sig)
+{
+ struct pthread *pthread, *pthread_next;
+ int i;
+
+ switch (sig) {
+ case SIGCHLD:
+ /*
+ * Go through the file list and set all files
+ * to non-blocking again in case the child
+ * set some of them to block. Sigh.
+ */
+ for (i = 0; i < _thread_dtablesize; i++) {
+ /* Check if this file is used: */
+ if (_thread_fd_table[i] != NULL) {
+ /*
+ * Set the file descriptor to non-blocking:
+ */
+ __sys_fcntl(i, F_SETFL,
+ _thread_fd_getflags(i) | O_NONBLOCK);
+ }
+ }
+ /*
+ * Enter a loop to wake up all threads waiting
+ * for a process to complete:
+ */
+ for (pthread = TAILQ_FIRST(&_waitingq);
+ pthread != NULL; pthread = pthread_next) {
+ /*
+ * Grab the next thread before possibly
+ * destroying the link entry:
+ */
+ pthread_next = TAILQ_NEXT(pthread, pqe);
+
+ /*
+ * If this thread is waiting for a child
+ * process to complete, wake it up:
+ */
+ if (pthread->state == PS_WAIT_WAIT) {
+ /* Make the thread runnable: */
+ PTHREAD_NEW_STATE(pthread,PS_RUNNING);
+
+ /* Return the signal number: */
+ pthread->signo = sig;
+ }
+ }
+ break;
+
+ /*
+ * POSIX says that pending SIGCONT signals are
+ * discarded when one of these signals occurs.
+ */
+ case SIGTSTP:
+ case SIGTTIN:
+ case SIGTTOU:
+ /*
+ * Enter a loop to discard pending SIGCONT
+ * signals:
+ */
+ TAILQ_FOREACH(pthread, &_thread_list, tle) {
+ sigdelset(&pthread->sigpend, SIGCONT);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+/*
+ * Perform thread specific actions in response to a signal.
+ * This function is only called if there is a handler installed
+ * for the signal, and if the target thread has the signal
+ * unmasked.
+ */
+static void
+thread_sig_add(struct pthread *pthread, int sig, int has_args)
+{
+ int restart;
+ int suppress_handler = 0;
+ int thread_is_active = 0;
+
+ restart = _thread_sigact[sig - 1].sa_flags & SA_RESTART;
+
+ /* Make sure this signal isn't still in the pending set: */
+ sigdelset(&pthread->sigpend, sig);
+
+ /*
+ * Process according to thread state:
+ */
+ switch (pthread->state) {
+ /*
+ * States which do not change when a signal is trapped:
+ */
+ case PS_DEAD:
+ case PS_DEADLOCK:
+ case PS_STATE_MAX:
+ case PS_SIGTHREAD:
+ /*
+ * You can't call a signal handler for threads in these
+ * states.
+ */
+ suppress_handler = 1;
+ break;
+
+ /*
+ * States which do not need any cleanup handling when signals
+ * occur:
+ */
+ case PS_RUNNING:
+ /*
+ * Remove the thread from the queue before changing its
+ * priority:
+ */
+ if ((pthread->flags & PTHREAD_FLAGS_IN_PRIOQ) != 0)
+ PTHREAD_PRIOQ_REMOVE(pthread);
+ else
+ /*
+ * This thread is running; avoid placing it in
+ * the run queue:
+ */
+ thread_is_active = 1;
+ break;
+
+ case PS_SUSPENDED:
+ break;
+
+ case PS_SPINBLOCK:
+ /* Remove the thread from the workq and waitq: */
+ PTHREAD_WORKQ_REMOVE(pthread);
+ PTHREAD_WAITQ_REMOVE(pthread);
+ /* Make the thread runnable: */
+ PTHREAD_SET_STATE(pthread, PS_RUNNING);
+ break;
+
+ case PS_SIGWAIT:
+ /* The signal handler is not called for threads in SIGWAIT. */
+ suppress_handler = 1;
+ /* Wake up the thread if the signal is blocked. */
+ if (sigismember(pthread->data.sigwait, sig)) {
+ /* Change the state of the thread to run: */
+ PTHREAD_NEW_STATE(pthread, PS_RUNNING);
+
+ /* Return the signal number: */
+ pthread->signo = sig;
+ } else
+ /* Increment the pending signal count. */
+ sigaddset(&pthread->sigpend, sig);
+ break;
+
+ /*
+ * The wait state is a special case due to the handling of
+ * SIGCHLD signals.
+ */
+ case PS_WAIT_WAIT:
+ if (sig == SIGCHLD) {
+ /* Change the state of the thread to run: */
+ PTHREAD_WAITQ_REMOVE(pthread);
+ PTHREAD_SET_STATE(pthread, PS_RUNNING);
+
+ /* Return the signal number: */
+ pthread->signo = sig;
+ }
+ else {
+ /*
+ * Mark the thread as interrupted only if the
+ * restart flag is not set on the signal action:
+ */
+ if (restart == 0)
+ pthread->interrupted = 1;
+ PTHREAD_WAITQ_REMOVE(pthread);
+ PTHREAD_SET_STATE(pthread, PS_RUNNING);
+ }
+ break;
+
+ /*
+ * States which cannot be interrupted but still require the
+ * signal handler to run:
+ */
+ case PS_COND_WAIT:
+ case PS_MUTEX_WAIT:
+ /*
+ * Remove the thread from the wait queue. It will
+ * be added back to the wait queue once all signal
+ * handlers have been invoked.
+ */
+ PTHREAD_WAITQ_REMOVE(pthread);
+ break;
+
+ case PS_JOIN:
+ /*
+ * Remove the thread from the wait queue. It will
+ * be added back to the wait queue once all signal
+ * handlers have been invoked.
+ */
+ PTHREAD_WAITQ_REMOVE(pthread);
+ /* Make the thread runnable: */
+ PTHREAD_SET_STATE(pthread, PS_RUNNING);
+ break;
+
+ /*
+ * States which are interruptible but may need to be removed
+ * from queues before any signal handler is called.
+ *
+ * XXX - We may not need to handle this condition, but will
+ * mark it as a potential problem.
+ */
+ case PS_FDLR_WAIT:
+ case PS_FDLW_WAIT:
+ case PS_FILE_WAIT:
+ if (restart == 0)
+ pthread->interrupted = 1;
+ /*
+ * Remove the thread from the wait queue. Our
+ * signal handler hook will remove this thread
+ * from the fd or file queue before invoking
+ * the actual handler.
+ */
+ PTHREAD_WAITQ_REMOVE(pthread);
+ break;
+
+ /*
+ * States which are interruptible:
+ */
+ case PS_FDR_WAIT:
+ case PS_FDW_WAIT:
+ if (restart == 0) {
+ /*
+ * Flag the operation as interrupted and
+ * set the state to running:
+ */
+ pthread->interrupted = 1;
+ PTHREAD_SET_STATE(pthread, PS_RUNNING);
+ }
+ PTHREAD_WORKQ_REMOVE(pthread);
+ PTHREAD_WAITQ_REMOVE(pthread);
+ break;
+
+ case PS_POLL_WAIT:
+ case PS_SELECT_WAIT:
+ case PS_SLEEP_WAIT:
+ /*
+ * Unmasked signals always cause poll, select, and sleep
+ * to terminate early, regardless of SA_RESTART:
+ */
+ pthread->interrupted = 1;
+ /* Remove threads in poll and select from the workq: */
+ if ((pthread->flags & PTHREAD_FLAGS_IN_WORKQ) != 0)
+ PTHREAD_WORKQ_REMOVE(pthread);
+ PTHREAD_WAITQ_REMOVE(pthread);
+ PTHREAD_SET_STATE(pthread, PS_RUNNING);
+ break;
+
+ case PS_SIGSUSPEND:
+ PTHREAD_WAITQ_REMOVE(pthread);
+ PTHREAD_SET_STATE(pthread, PS_RUNNING);
+ break;
+ }
+
+ if (suppress_handler == 0) {
+ /* Setup a signal frame and save the current threads state: */
+ thread_sigframe_add(pthread, sig, has_args);
+
+ /*
+ * Signals are deferred until just before the threads
+ * signal handler is invoked:
+ */
+ pthread->sig_defer_count = 1;
+
+ /* Make sure the thread is runnable: */
+ if (pthread->state != PS_RUNNING)
+ PTHREAD_SET_STATE(pthread, PS_RUNNING);
+ /*
+ * The thread should be removed from all scheduling
+ * queues at this point. Raise the priority and place
+ * the thread in the run queue. It is also possible
+ * for a signal to be sent to a suspended thread,
+ * mostly via pthread_kill(). If a thread is suspended,
+ * don't insert it into the priority queue; just set
+ * its state to suspended and it will run the signal
+ * handler when it is resumed.
+ */
+ pthread->active_priority |= PTHREAD_SIGNAL_PRIORITY;
+ if ((pthread->flags & PTHREAD_FLAGS_SUSPENDED) != 0)
+ PTHREAD_SET_STATE(pthread, PS_SUSPENDED);
+ else if (thread_is_active == 0)
+ PTHREAD_PRIOQ_INSERT_TAIL(pthread);
+ }
+}
+
+static void
+thread_sig_check_state(struct pthread *pthread, int sig)
+{
+ /*
+ * Process according to thread state:
+ */
+ switch (pthread->state) {
+ /*
+ * States which do not change when a signal is trapped:
+ */
+ case PS_DEAD:
+ case PS_DEADLOCK:
+ case PS_STATE_MAX:
+ case PS_SIGTHREAD:
+ case PS_RUNNING:
+ case PS_SUSPENDED:
+ case PS_SPINBLOCK:
+ case PS_COND_WAIT:
+ case PS_JOIN:
+ case PS_MUTEX_WAIT:
+ break;
+
+ case PS_SIGWAIT:
+ /* Wake up the thread if the signal is blocked. */
+ if (sigismember(pthread->data.sigwait, sig)) {
+ /* Change the state of the thread to run: */
+ PTHREAD_NEW_STATE(pthread, PS_RUNNING);
+
+ /* Return the signal number: */
+ pthread->signo = sig;
+ } else
+ /* Increment the pending signal count. */
+ sigaddset(&pthread->sigpend, sig);
+ break;
+
+ /*
+ * The wait state is a special case due to the handling of
+ * SIGCHLD signals.
+ */
+ case PS_WAIT_WAIT:
+ if (sig == SIGCHLD) {
+ /*
+ * Remove the thread from the wait queue and
+ * make it runnable:
+ */
+ PTHREAD_NEW_STATE(pthread, PS_RUNNING);
+
+ /* Return the signal number: */
+ pthread->signo = sig;
+ }
+ break;
+
+ case PS_FDLR_WAIT:
+ case PS_FDLW_WAIT:
+ case PS_SIGSUSPEND:
+ case PS_SLEEP_WAIT:
+ /*
+ * Remove the thread from the wait queue and make it
+ * runnable:
+ */
+ PTHREAD_NEW_STATE(pthread, PS_RUNNING);
+
+ /* Flag the operation as interrupted: */
+ pthread->interrupted = 1;
+ break;
+
+ /*
+ * These states are additionally in the work queue:
+ */
+ case PS_FDR_WAIT:
+ case PS_FDW_WAIT:
+ case PS_FILE_WAIT:
+ case PS_POLL_WAIT:
+ case PS_SELECT_WAIT:
+ /*
+ * Remove the thread from the wait and work queues, and
+ * make it runnable:
+ */
+ PTHREAD_WORKQ_REMOVE(pthread);
+ PTHREAD_NEW_STATE(pthread, PS_RUNNING);
+
+ /* Flag the operation as interrupted: */
+ pthread->interrupted = 1;
+ break;
+ }
+}
+
+/*
+ * Send a signal to a specific thread (ala pthread_kill):
+ */
+void
+_thread_sig_send(struct pthread *pthread, int sig)
+{
+ struct pthread *curthread = _get_curthread();
+
+ /* Check for signals whose actions are SIG_DFL: */
+ if (_thread_sigact[sig - 1].sa_handler == SIG_DFL) {
+ /*
+ * Check to see if a temporary signal handler is
+ * installed for sigwaiters:
+ */
+ if (_thread_dfl_count[sig] == 0)
+ /*
+ * Deliver the signal to the process if a handler
+ * is not installed:
+ */
+ kill(getpid(), sig);
+ /*
+ * Assuming we're still running after the above kill(),
+ * make any necessary state changes to the thread:
+ */
+ thread_sig_check_state(pthread, sig);
+ }
+ /*
+ * Check that the signal is not being ignored:
+ */
+ else if (_thread_sigact[sig - 1].sa_handler != SIG_IGN) {
+ if (pthread->state == PS_SIGWAIT &&
+ sigismember(pthread->data.sigwait, sig)) {
+ /* Change the state of the thread to run: */
+ PTHREAD_NEW_STATE(pthread, PS_RUNNING);
+
+ /* Return the signal number: */
+ pthread->signo = sig;
+ } else if (sigismember(&pthread->sigmask, sig))
+ /* Add the signal to the pending set: */
+ sigaddset(&pthread->sigpend, sig);
+ else if (pthread == curthread)
+ /* Call the signal handler for the current thread: */
+ thread_sig_invoke_handler(sig, NULL, NULL);
+ else {
+ /* Protect the scheduling queues: */
+ _thread_kern_sig_defer();
+ /*
+ * Perform any state changes due to signal
+ * arrival:
+ */
+ thread_sig_add(pthread, sig, /* has args */ 0);
+ /* Unprotect the scheduling queues: */
+ _thread_kern_sig_undefer();
+ }
+ }
+}
+
+/*
+ * User thread signal handler wrapper.
+ *
+ * thread - current running thread
+ */
+void
+_thread_sig_wrapper(void)
+{
+ struct pthread_signal_frame *psf;
+ struct pthread *thread = _get_curthread();
+
+ /* Get the current frame and state: */
+ psf = thread->curframe;
+ thread->curframe = NULL;
+ PTHREAD_ASSERT(psf != NULL, "Invalid signal frame in signal handler");
+
+ /*
+ * We're coming from the kernel scheduler; clear the in
+ * scheduler flag:
+ */
+ _thread_kern_in_sched = 0;
+
+ /* Check the threads previous state: */
+ if (psf->saved_state.psd_state != PS_RUNNING) {
+ /*
+ * Do a little cleanup handling for those threads in
+ * queues before calling the signal handler. Signals
+ * for these threads are temporarily blocked until
+ * after cleanup handling.
+ */
+ switch (psf->saved_state.psd_state) {
+ case PS_FDLR_WAIT:
+ case PS_FDLW_WAIT:
+ _fd_lock_backout(thread);
+ psf->saved_state.psd_state = PS_RUNNING;
+ break;
+
+ case PS_COND_WAIT:
+ _cond_wait_backout(thread);
+ psf->saved_state.psd_state = PS_RUNNING;
+ break;
+
+ case PS_MUTEX_WAIT:
+ _mutex_lock_backout(thread);
+ psf->saved_state.psd_state = PS_RUNNING;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ /* Unblock the signal in case we don't return from the handler: */
+ _thread_sigq[psf->signo - 1].blocked = 0;
+
+ /*
+ * Lower the priority before calling the handler in case
+ * it never returns (longjmps back):
+ */
+ thread->active_priority &= ~PTHREAD_SIGNAL_PRIORITY;
+
+ /*
+ * Reenable interruptions without checking for the need to
+ * context switch:
+ */
+ thread->sig_defer_count = 0;
+
+ /*
+ * Dispatch the signal via the custom signal handler:
+ */
+ if (psf->sig_has_args == 0)
+ thread_sig_invoke_handler(psf->signo, NULL, NULL);
+ else
+ thread_sig_invoke_handler(psf->signo, &psf->siginfo, &psf->uc);
+
+ /*
+ * Call the kernel scheduler to safely restore the frame and
+ * schedule the next thread:
+ */
+ _thread_kern_sched_frame(psf);
+}
+
+static void
+thread_sigframe_add(struct pthread *thread, int sig, int has_args)
+{
+ struct pthread_signal_frame *psf = NULL;
+ unsigned long stackp;
+
+ /* Get the top of the threads stack: */
+ stackp = GET_STACK_JB(thread->ctx.jb);
+
+#if !defined(__ia64__)
+ /*
+ * Leave a little space on the stack and round down to the
+ * nearest aligned word:
+ */
+#if defined(__amd64__)
+ stackp -= 128; /* Skip over 128 byte red-zone */
+#endif
+ stackp -= sizeof(double);
+#if defined(__amd64__)
+ stackp &= ~0xFUL;
+#else
+ stackp &= ~0x3UL;
+#endif
+#endif
+
+ /* Allocate room on top of the stack for a new signal frame: */
+ stackp -= sizeof(struct pthread_signal_frame);
+#if defined(__ia64__) || defined(__amd64__)
+ stackp &= ~0xFUL;
+#endif
+
+ psf = (struct pthread_signal_frame *) stackp;
+
+ /* Save the current context in the signal frame: */
+ thread_sigframe_save(thread, psf);
+
+ /* Set handler specific information: */
+ psf->sig_has_args = has_args;
+ psf->signo = sig;
+ if (has_args) {
+ /* Copy the signal handler arguments to the signal frame: */
+ memcpy(&psf->uc, &_thread_sigq[psf->signo - 1].uc,
+ sizeof(psf->uc));
+ memcpy(&psf->siginfo, &_thread_sigq[psf->signo - 1].siginfo,
+ sizeof(psf->siginfo));
+ }
+
+ /* Setup the signal mask: */
+ SIGSETOR(thread->sigmask, _thread_sigact[sig - 1].sa_mask);
+ sigaddset(&thread->sigmask, sig);
+
+ /* Set up the new frame: */
+ thread->curframe = psf;
+ thread->flags &= PTHREAD_FLAGS_PRIVATE | PTHREAD_FLAGS_TRACE |
+ PTHREAD_FLAGS_IN_SYNCQ;
+ /*
+ * Set up the context:
+ */
+#if !defined(__ia64__)
+ stackp -= sizeof(double);
+#if defined(__amd64__)
+ stackp &= ~0xFUL;
+#endif
+#endif
+ _setjmp(thread->ctx.jb);
+#if !defined(__ia64__)
+ SET_STACK_JB(thread->ctx.jb, stackp);
+#else
+ UPD_STACK_JB(thread->ctx.jb, stackp - 16);
+#endif
+ SET_RETURN_ADDR_JB(thread->ctx.jb, _thread_sig_wrapper);
+}
+
+void
+_thread_sigframe_restore(struct pthread *thread,
+ struct pthread_signal_frame *psf)
+{
+ memcpy(&thread->ctx, &psf->ctx, sizeof(thread->ctx));
+ /*
+ * Only restore the signal mask if it hasn't been changed
+ * by the application during invocation of the signal handler:
+ */
+ if (thread->sigmask_seqno == psf->saved_state.psd_sigmask_seqno)
+ thread->sigmask = psf->saved_state.psd_sigmask;
+ thread->curframe = psf->saved_state.psd_curframe;
+ thread->wakeup_time = psf->saved_state.psd_wakeup_time;
+ thread->data = psf->saved_state.psd_wait_data;
+ thread->state = psf->saved_state.psd_state;
+ thread->flags = psf->saved_state.psd_flags;
+ thread->interrupted = psf->saved_state.psd_interrupted;
+ thread->signo = psf->saved_state.psd_signo;
+ thread->sig_defer_count = psf->saved_state.psd_sig_defer_count;
+}
+
+static void
+thread_sigframe_save(struct pthread *thread, struct pthread_signal_frame *psf)
+{
+ memcpy(&psf->ctx, &thread->ctx, sizeof(thread->ctx));
+ psf->saved_state.psd_sigmask = thread->sigmask;
+ psf->saved_state.psd_curframe = thread->curframe;
+ psf->saved_state.psd_wakeup_time = thread->wakeup_time;
+ psf->saved_state.psd_wait_data = thread->data;
+ psf->saved_state.psd_state = thread->state;
+ psf->saved_state.psd_flags = thread->flags &
+ (PTHREAD_FLAGS_PRIVATE | PTHREAD_FLAGS_TRACE);
+ psf->saved_state.psd_interrupted = thread->interrupted;
+ psf->saved_state.psd_sigmask_seqno = thread->sigmask_seqno;
+ psf->saved_state.psd_signo = thread->signo;
+ psf->saved_state.psd_sig_defer_count = thread->sig_defer_count;
+}
+
diff --git a/lib/libc_r/uthread/uthread_sigaction.c b/lib/libc_r/uthread/uthread_sigaction.c
new file mode 100644
index 0000000..a476542
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_sigaction.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <signal.h>
+#include <errno.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_sigaction, sigaction);
+
+int
+_sigaction(int sig, const struct sigaction * act, struct sigaction * oact)
+{
+ int ret = 0;
+ struct sigaction gact;
+
+ /* Check if the signal number is out of range: */
+ if (sig < 1 || sig > NSIG) {
+ /* Return an invalid argument: */
+ errno = EINVAL;
+ ret = -1;
+ } else {
+ if (_thread_initial == NULL)
+ _thread_init();
+
+ /*
+ * Check if the existing signal action structure contents are
+ * to be returned:
+ */
+ if (oact != NULL) {
+ /* Return the existing signal action contents: */
+ oact->sa_handler = _thread_sigact[sig - 1].sa_handler;
+ oact->sa_mask = _thread_sigact[sig - 1].sa_mask;
+ oact->sa_flags = _thread_sigact[sig - 1].sa_flags;
+ }
+
+ /* Check if a signal action was supplied: */
+ if (act != NULL) {
+ /* Set the new signal handler: */
+ _thread_sigact[sig - 1].sa_mask = act->sa_mask;
+ _thread_sigact[sig - 1].sa_flags = act->sa_flags;
+ _thread_sigact[sig - 1].sa_handler = act->sa_handler;
+ }
+
+ /*
+ * Check if the kernel needs to be advised of a change
+ * in signal action:
+ */
+ if (act != NULL && sig != _SCHED_SIGNAL && sig != SIGCHLD &&
+ sig != SIGINFO) {
+ /*
+ * Ensure the signal handler cannot be interrupted
+ * by other signals. Always request the POSIX signal
+ * handler arguments.
+ */
+ sigfillset(&gact.sa_mask);
+ gact.sa_flags = SA_SIGINFO | SA_RESTART;
+
+ /*
+ * Check if the signal handler is being set to
+ * the default or ignore handlers:
+ */
+ if (act->sa_handler == SIG_DFL ||
+ act->sa_handler == SIG_IGN)
+ /* Specify the built in handler: */
+ gact.sa_handler = act->sa_handler;
+ else
+ /*
+ * Specify the thread kernel signal
+ * handler:
+ */
+ gact.sa_handler = (void (*) ()) _thread_sig_handler;
+
+ /* Change the signal action in the kernel: */
+ if (__sys_sigaction(sig,&gact,NULL) != 0)
+ ret = -1;
+ }
+ }
+
+ /* Return the completion status: */
+ return (ret);
+}
diff --git a/lib/libc_r/uthread/uthread_sigmask.c b/lib/libc_r/uthread/uthread_sigmask.c
new file mode 100644
index 0000000..040e7aa
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_sigmask.c
@@ -0,0 +1,106 @@
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/signalvar.h>
+#include <errno.h>
+#include <signal.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_sigmask, pthread_sigmask);
+
+int
+_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
+{
+ struct pthread *curthread = _get_curthread();
+ sigset_t sigset;
+ int ret = 0;
+
+ /* Check if the existing signal process mask is to be returned: */
+ if (oset != NULL) {
+ /* Return the current mask: */
+ *oset = curthread->sigmask;
+ }
+ /* Check if a new signal set was provided by the caller: */
+ if (set != NULL) {
+ /* Process according to what to do: */
+ switch (how) {
+ /* Block signals: */
+ case SIG_BLOCK:
+ /* Add signals to the existing mask: */
+ SIGSETOR(curthread->sigmask, *set);
+ break;
+
+ /* Unblock signals: */
+ case SIG_UNBLOCK:
+ /* Clear signals from the existing mask: */
+ SIGSETNAND(curthread->sigmask, *set);
+ break;
+
+ /* Set the signal process mask: */
+ case SIG_SETMASK:
+ /* Set the new mask: */
+ curthread->sigmask = *set;
+ break;
+
+ /* Trap invalid actions: */
+ default:
+ /* Return an invalid argument: */
+ errno = EINVAL;
+ ret = -1;
+ break;
+ }
+
+ /* Increment the sequence number: */
+ curthread->sigmask_seqno++;
+
+ /*
+ * Check if there are pending signals for the running
+ * thread or process that aren't blocked:
+ */
+ sigset = curthread->sigpend;
+ SIGSETOR(sigset, _process_sigpending);
+ SIGSETNAND(sigset, curthread->sigmask);
+ if (SIGNOTEMPTY(sigset))
+ /*
+ * Call the kernel scheduler which will safely
+ * install a signal frame for the running thread:
+ */
+ _thread_kern_sched_sig();
+ }
+
+ /* Return the completion status: */
+ return (ret);
+}
diff --git a/lib/libc_r/uthread/uthread_sigpending.c b/lib/libc_r/uthread/uthread_sigpending.c
new file mode 100644
index 0000000..5eaf6ff
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_sigpending.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1999 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/signalvar.h>
+#include <signal.h>
+#include <errno.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_sigpending, sigpending);
+
+int
+_sigpending(sigset_t *set)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret = 0;
+
+ /* Check for a null signal set pointer: */
+ if (set == NULL) {
+ /* Return an invalid argument: */
+ ret = EINVAL;
+ }
+ else {
+ *set = curthread->sigpend;
+ SIGSETOR(*set, _process_sigpending);
+ }
+ /* Return the completion status: */
+ return (ret);
+}
diff --git a/lib/libc_r/uthread/uthread_sigprocmask.c b/lib/libc_r/uthread/uthread_sigprocmask.c
new file mode 100644
index 0000000..cc0b8da
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_sigprocmask.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/signalvar.h>
+#include <signal.h>
+#include <errno.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_sigprocmask, sigprocmask);
+
+int
+_sigprocmask(int how, const sigset_t *set, sigset_t *oset)
+{
+ return (pthread_sigmask(how, set, oset));
+}
diff --git a/lib/libc_r/uthread/uthread_sigsuspend.c b/lib/libc_r/uthread/uthread_sigsuspend.c
new file mode 100644
index 0000000..42f174b
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_sigsuspend.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <signal.h>
+#include <sys/param.h>
+#include <sys/signalvar.h>
+#include <errno.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(__sigsuspend, sigsuspend);
+
+int
+_sigsuspend(const sigset_t * set)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret = -1;
+ sigset_t oset, sigset;
+
+ /* Check if a new signal set was provided by the caller: */
+ if (set != NULL) {
+ /* Save the current signal mask: */
+ oset = curthread->sigmask;
+
+ /* Change the caller's mask: */
+ curthread->sigmask = *set;
+
+ /*
+ * Check if there are pending signals for the running
+ * thread or process that aren't blocked:
+ */
+ sigset = curthread->sigpend;
+ SIGSETOR(sigset, _process_sigpending);
+ SIGSETNAND(sigset, curthread->sigmask);
+ if (SIGNOTEMPTY(sigset)) {
+ /*
+ * Call the kernel scheduler which will safely
+ * install a signal frame for the running thread:
+ */
+ _thread_kern_sched_sig();
+ } else {
+ /* Wait for a signal: */
+ _thread_kern_sched_state(PS_SIGSUSPEND,
+ __FILE__, __LINE__);
+ }
+
+ /* Always return an interrupted error: */
+ errno = EINTR;
+
+ /* Restore the signal mask: */
+ curthread->sigmask = oset;
+ } else {
+ /* Return an invalid argument error: */
+ errno = EINVAL;
+ }
+
+ /* Return the completion status: */
+ return (ret);
+}
+
+int
+__sigsuspend(const sigset_t * set)
+{
+ int ret;
+
+ _thread_enter_cancellation_point();
+ ret = _sigsuspend(set);
+ _thread_leave_cancellation_point();
+
+ return ret;
+}
diff --git a/lib/libc_r/uthread/uthread_sigwait.c b/lib/libc_r/uthread/uthread_sigwait.c
new file mode 100644
index 0000000..c245e5d
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_sigwait.c
@@ -0,0 +1,174 @@
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <signal.h>
+#include <sys/param.h>
+#include <sys/signalvar.h>
+#include <errno.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_sigwait, sigwait);
+
+int
+_sigwait(const sigset_t * __restrict set, int * __restrict sig)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret = 0;
+ int i;
+ sigset_t tempset, waitset;
+ struct sigaction act;
+
+ _thread_enter_cancellation_point();
+ /*
+ * Specify the thread kernel signal handler.
+ */
+ act.sa_handler = (void (*) ()) _thread_sig_handler;
+ act.sa_flags = SA_SIGINFO | SA_RESTART;
+ /* Ensure the signal handler cannot be interrupted by other signals: */
+ sigfillset(&act.sa_mask);
+
+ /*
+ * Initialize the set of signals that will be waited on:
+ */
+ waitset = *set;
+
+ /* These signals can't be waited on. */
+ sigdelset(&waitset, SIGKILL);
+ sigdelset(&waitset, SIGSTOP);
+ sigdelset(&waitset, _SCHED_SIGNAL);
+ sigdelset(&waitset, SIGCHLD);
+ sigdelset(&waitset, SIGINFO);
+
+ /* Check to see if a pending signal is in the wait mask. */
+ tempset = curthread->sigpend;
+ SIGSETOR(tempset, _process_sigpending);
+ SIGSETAND(tempset, waitset);
+ if (SIGNOTEMPTY(tempset)) {
+ /* Enter a loop to find a pending signal: */
+ for (i = 1; i < NSIG; i++) {
+ if (sigismember (&tempset, i))
+ break;
+ }
+
+ /* Clear the pending signal: */
+ if (sigismember(&curthread->sigpend,i))
+ sigdelset(&curthread->sigpend,i);
+ else
+ sigdelset(&_process_sigpending,i);
+
+ /* Return the signal number to the caller: */
+ *sig = i;
+
+ _thread_leave_cancellation_point();
+ return (0);
+ }
+
+ /*
+ * Access the _thread_dfl_count array under the protection of signal
+ * deferral.
+ */
+ _thread_kern_sig_defer();
+
+ /*
+ * Enter a loop to find the signals that are SIG_DFL. For
+ * these signals we must install a dummy signal handler in
+ * order for the kernel to pass them in to us. POSIX says
+ * that the _application_ must explicitly install a dummy
+ * handler for signals that are SIG_IGN in order to sigwait
+ * on them. Note that SIG_IGN signals are left in the
+ * mask because a subsequent sigaction could enable an
+ * ignored signal.
+ */
+ sigemptyset(&tempset);
+ for (i = 1; i < NSIG; i++) {
+ if (sigismember(&waitset, i) &&
+ (_thread_sigact[i - 1].sa_handler == SIG_DFL)) {
+ _thread_dfl_count[i]++;
+ sigaddset(&tempset, i);
+ if (_thread_dfl_count[i] == 1) {
+ if (__sys_sigaction(i,&act,NULL) != 0)
+ ret = -1;
+ }
+ }
+ }
+ /* Done accessing _thread_dfl_count for now. */
+ _thread_kern_sig_undefer();
+
+ if (ret == 0) {
+ /*
+ * Save the wait signal mask. The wait signal
+ * mask is independent of the threads signal mask
+ * and requires separate storage.
+ */
+ curthread->data.sigwait = &waitset;
+
+ /* Wait for a signal: */
+ _thread_kern_sched_state(PS_SIGWAIT, __FILE__, __LINE__);
+
+ /* Return the signal number to the caller: */
+ *sig = curthread->signo;
+
+ /*
+ * Probably unnecessary, but since it's in a union struct
+ * we don't know how it could be used in the future.
+ */
+ curthread->data.sigwait = NULL;
+ }
+
+ /*
+ * Access the _thread_dfl_count array under the protection of signal
+ * deferral.
+ */
+ _thread_kern_sig_defer();
+
+ /* Restore the sigactions: */
+ act.sa_handler = SIG_DFL;
+ for (i = 1; i < NSIG; i++) {
+ if (sigismember(&tempset, i)) {
+ _thread_dfl_count[i]--;
+ if ((_thread_sigact[i - 1].sa_handler == SIG_DFL) &&
+ (_thread_dfl_count[i] == 0)) {
+ if (__sys_sigaction(i,&act,NULL) != 0)
+ ret = -1;
+ }
+ }
+ }
+ /* Done accessing _thread_dfl_count. */
+ _thread_kern_sig_undefer();
+
+ _thread_leave_cancellation_point();
+
+ /* Return the completion status: */
+ return (ret);
+}
diff --git a/lib/libc_r/uthread/uthread_single_np.c b/lib/libc_r/uthread/uthread_single_np.c
new file mode 100644
index 0000000..1ee5e79
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_single_np.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 1996 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <pthread_np.h>
+
+__weak_reference(_pthread_single_np, pthread_single_np);
+
+int _pthread_single_np()
+{
+
+ /* Enter single-threaded (non-POSIX) scheduling mode: */
+ pthread_suspend_all_np();
+ /*
+ * XXX - Do we want to do this?
+ * __is_threaded = 0;
+ */
+ return (0);
+}
diff --git a/lib/libc_r/uthread/uthread_sleep.c b/lib/libc_r/uthread/uthread_sleep.c
new file mode 100644
index 0000000..9e09db7
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_sleep.c
@@ -0,0 +1,48 @@
+/*
+ * 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$
+ */
+
+#include <unistd.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_sleep, sleep);
+
+unsigned int
+_sleep(unsigned int seconds)
+{
+ unsigned int ret;
+
+ _thread_enter_cancellation_point();
+ ret = __sleep(seconds);
+ _thread_leave_cancellation_point();
+
+ return ret;
+}
diff --git a/lib/libc_r/uthread/uthread_socket.c b/lib/libc_r/uthread/uthread_socket.c
new file mode 100644
index 0000000..28b5a72
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_socket.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_socket, socket);
+
+int
+_socket(int af, int type, int protocol)
+{
+ int fd;
+
+ /* Create a socket: */
+ if ((fd = __sys_socket(af, type, protocol)) < 0) {
+ /* Error creating socket. */
+
+ /* Initialise the entry in the file descriptor table: */
+ } else if (_thread_fd_table_init(fd) != 0) {
+ __sys_close(fd);
+ fd = -1;
+ }
+ return (fd);
+}
diff --git a/lib/libc_r/uthread/uthread_socketpair.c b/lib/libc_r/uthread/uthread_socketpair.c
new file mode 100644
index 0000000..6cd9cb6
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_socketpair.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_socketpair, socketpair);
+
+int
+_socketpair(int af, int type, int protocol, int pair[2])
+{
+ int ret;
+ if (!((ret = __sys_socketpair(af, type, protocol, pair)) < 0))
+ if (_thread_fd_table_init(pair[0]) != 0 ||
+ _thread_fd_table_init(pair[1]) != 0) {
+ __sys_close(pair[0]);
+ __sys_close(pair[1]);
+ ret = -1;
+ }
+ return (ret);
+}
diff --git a/lib/libc_r/uthread/uthread_spec.c b/lib/libc_r/uthread/uthread_spec.c
new file mode 100644
index 0000000..e71f75f
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_spec.c
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+struct pthread_key {
+ spinlock_t lock;
+ volatile int allocated;
+ volatile int count;
+ int seqno;
+ void (*destructor) ();
+};
+
+/* Static variables: */
+static struct pthread_key key_table[PTHREAD_KEYS_MAX];
+
+__weak_reference(_pthread_key_create, pthread_key_create);
+__weak_reference(_pthread_key_delete, pthread_key_delete);
+__weak_reference(_pthread_getspecific, pthread_getspecific);
+__weak_reference(_pthread_setspecific, pthread_setspecific);
+
+
+int
+_pthread_key_create(pthread_key_t * key, void (*destructor) (void *))
+{
+ for ((*key) = 0; (*key) < PTHREAD_KEYS_MAX; (*key)++) {
+ /* Lock the key table entry: */
+ _SPINLOCK(&key_table[*key].lock);
+
+ if (key_table[(*key)].allocated == 0) {
+ key_table[(*key)].allocated = 1;
+ key_table[(*key)].destructor = destructor;
+ key_table[(*key)].seqno++;
+
+ /* Unlock the key table entry: */
+ _SPINUNLOCK(&key_table[*key].lock);
+ return (0);
+ }
+
+ /* Unlock the key table entry: */
+ _SPINUNLOCK(&key_table[*key].lock);
+ }
+ return (EAGAIN);
+}
+
+int
+_pthread_key_delete(pthread_key_t key)
+{
+ int ret = 0;
+
+ if (key < PTHREAD_KEYS_MAX) {
+ /* Lock the key table entry: */
+ _SPINLOCK(&key_table[key].lock);
+
+ if (key_table[key].allocated)
+ key_table[key].allocated = 0;
+ else
+ ret = EINVAL;
+
+ /* Unlock the key table entry: */
+ _SPINUNLOCK(&key_table[key].lock);
+ } else
+ ret = EINVAL;
+ return (ret);
+}
+
+void
+_thread_cleanupspecific(void)
+{
+ struct pthread *curthread = _get_curthread();
+ void *data = NULL;
+ int key;
+ int itr;
+ void (*destructor)( void *);
+
+ for (itr = 0; itr < PTHREAD_DESTRUCTOR_ITERATIONS; itr++) {
+ for (key = 0; key < PTHREAD_KEYS_MAX; key++) {
+ if (curthread->specific_data_count > 0) {
+ /* Lock the key table entry: */
+ _SPINLOCK(&key_table[key].lock);
+ destructor = NULL;
+
+ if (key_table[key].allocated &&
+ (curthread->specific[key].data != NULL)) {
+ if (curthread->specific[key].seqno ==
+ key_table[key].seqno) {
+ data = (void *) curthread->specific[key].data;
+ destructor = key_table[key].destructor;
+ }
+ curthread->specific[key].data = NULL;
+ curthread->specific_data_count--;
+ }
+
+ /* Unlock the key table entry: */
+ _SPINUNLOCK(&key_table[key].lock);
+
+ /*
+ * If there is a destructore, call it
+ * with the key table entry unlocked:
+ */
+ if (destructor)
+ destructor(data);
+ } else {
+ free(curthread->specific);
+ curthread->specific = NULL;
+ return;
+ }
+ }
+ }
+ if (curthread->specific != NULL) {
+ free(curthread->specific);
+ curthread->specific = NULL;
+ }
+}
+
+static inline struct pthread_specific_elem *
+pthread_key_allocate_data(void)
+{
+ struct pthread_specific_elem *new_data;
+
+ new_data = (struct pthread_specific_elem *)
+ malloc(sizeof(struct pthread_specific_elem) * PTHREAD_KEYS_MAX);
+ if (new_data != NULL) {
+ memset((void *) new_data, 0,
+ sizeof(struct pthread_specific_elem) * PTHREAD_KEYS_MAX);
+ }
+ return (new_data);
+}
+
+int
+_pthread_setspecific(pthread_key_t key, const void *value)
+{
+ struct pthread *pthread;
+ int ret = 0;
+
+ /* Point to the running thread: */
+ pthread = _get_curthread();
+
+ if ((pthread->specific) ||
+ (pthread->specific = pthread_key_allocate_data())) {
+ if (key < PTHREAD_KEYS_MAX) {
+ if (key_table[key].allocated) {
+ if (pthread->specific[key].data == NULL) {
+ if (value != NULL)
+ pthread->specific_data_count++;
+ } else {
+ if (value == NULL)
+ pthread->specific_data_count--;
+ }
+ pthread->specific[key].data = value;
+ pthread->specific[key].seqno =
+ key_table[key].seqno;
+ ret = 0;
+ } else
+ ret = EINVAL;
+ } else
+ ret = EINVAL;
+ } else
+ ret = ENOMEM;
+ return (ret);
+}
+
+void *
+_pthread_getspecific(pthread_key_t key)
+{
+ struct pthread *pthread;
+ void *data;
+
+ /* Point to the running thread: */
+ pthread = _get_curthread();
+
+ /* Check if there is specific data: */
+ if (pthread->specific != NULL && key < PTHREAD_KEYS_MAX) {
+ /* Check if this key has been used before: */
+ if (key_table[key].allocated &&
+ (pthread->specific[key].seqno == key_table[key].seqno)) {
+ /* Return the value: */
+ data = (void *) pthread->specific[key].data;
+ } else {
+ /*
+ * This key has not been used before, so return NULL
+ * instead:
+ */
+ data = NULL;
+ }
+ } else
+ /* No specific data has been created, so just return NULL: */
+ data = NULL;
+ return (data);
+}
diff --git a/lib/libc_r/uthread/uthread_spinlock.c b/lib/libc_r/uthread/uthread_spinlock.c
new file mode 100644
index 0000000..0c8eae3
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_spinlock.c
@@ -0,0 +1,117 @@
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <stdio.h>
+#include <string.h>
+#include <sched.h>
+#include <pthread.h>
+#include <unistd.h>
+
+#include <libc_private.h>
+
+#include "pthread_private.h"
+
+void
+_spinunlock(spinlock_t *lck)
+{
+ lck->access_lock = 0;
+}
+
+/*
+ * Lock a location for the running thread. Yield to allow other
+ * threads to run if this thread is blocked because the lock is
+ * not available. Note that this function does not sleep. It
+ * assumes that the lock will be available very soon.
+ */
+void
+_spinlock(spinlock_t *lck)
+{
+ struct pthread *curthread = _get_curthread();
+
+ /*
+ * Try to grab the lock and loop if another thread grabs
+ * it before we do.
+ */
+ while(_atomic_lock(&lck->access_lock)) {
+ /* Block the thread until the lock. */
+ curthread->data.spinlock = lck;
+ _thread_kern_sched_state(PS_SPINBLOCK, __FILE__, __LINE__);
+ }
+
+ /* The running thread now owns the lock: */
+ lck->lock_owner = (long) curthread;
+}
+
+/*
+ * Lock a location for the running thread. Yield to allow other
+ * threads to run if this thread is blocked because the lock is
+ * not available. Note that this function does not sleep. It
+ * assumes that the lock will be available very soon.
+ *
+ * This function checks if the running thread has already locked the
+ * location, warns if this occurs and creates a thread dump before
+ * returning.
+ */
+void
+_spinlock_debug(spinlock_t *lck, char *fname, int lineno)
+{
+ struct pthread *curthread = _get_curthread();
+ int cnt = 0;
+
+ /*
+ * Try to grab the lock and loop if another thread grabs
+ * it before we do.
+ */
+ while(_atomic_lock(&lck->access_lock)) {
+ cnt++;
+ if (cnt > 100) {
+ char str[256];
+ snprintf(str, sizeof(str), "%s - Warning: Thread %p attempted to lock %p from %s (%d) was left locked from %s (%d)\n", getprogname(), curthread, lck, fname, lineno, lck->fname, lck->lineno);
+ __sys_write(2,str,strlen(str));
+ __sleep(1);
+ cnt = 0;
+ }
+
+ /* Block the thread until the lock. */
+ curthread->data.spinlock = lck;
+ _thread_kern_sched_state(PS_SPINBLOCK, fname, lineno);
+ }
+
+ /* The running thread now owns the lock: */
+ lck->lock_owner = (long) curthread;
+ lck->fname = fname;
+ lck->lineno = lineno;
+}
diff --git a/lib/libc_r/uthread/uthread_stack.c b/lib/libc_r/uthread/uthread_stack.c
new file mode 100644
index 0000000..0b176ce
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_stack.c
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2001 Daniel Eischen <deischen@freebsd.org>
+ * Copyright (c) 2000-2001 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, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "pthread_private.h"
+
+/* Spare thread stack. */
+struct stack {
+ LIST_ENTRY(stack) qe; /* Stack queue linkage. */
+ size_t stacksize; /* Stack size (rounded up). */
+ size_t guardsize; /* Guard size. */
+ void *stackaddr; /* Stack address. */
+};
+
+/*
+ * Default sized (stack and guard) spare stack queue. Stacks are cached to
+ * avoid additional complexity managing mmap()ed stack regions. Spare stacks
+ * are used in LIFO order to increase cache locality.
+ */
+static LIST_HEAD(, stack) _dstackq = LIST_HEAD_INITIALIZER(_dstackq);
+
+/*
+ * Miscellaneous sized (non-default stack and/or guard) spare stack queue.
+ * Stacks are cached to avoid additional complexity managing mmap()ed stack
+ * regions. This list is unordered, since ordering on both stack size and guard
+ * size would be more trouble than it's worth. Stacks are allocated from this
+ * cache on a first size match basis.
+ */
+static LIST_HEAD(, stack) _mstackq = LIST_HEAD_INITIALIZER(_mstackq);
+
+/**
+ * Base address of the last stack allocated (including its red zone, if there is
+ * one). Stacks are allocated contiguously, starting beyond the top of the main
+ * stack. When a new stack is created, a red zone is typically created
+ * (actually, the red zone is simply left unmapped) above the top of the stack,
+ * such that the stack will not be able to grow all the way to the bottom of the
+ * next stack. This isn't fool-proof. It is possible for a stack to grow by a
+ * large amount, such that it grows into the next stack, and as long as the
+ * memory within the red zone is never accessed, nothing will prevent one thread
+ * stack from trouncing all over the next.
+ *
+ * low memory
+ * . . . . . . . . . . . . . . . . . .
+ * | |
+ * | stack 3 | start of 3rd thread stack
+ * +-----------------------------------+
+ * | |
+ * | Red Zone (guard page) | red zone for 2nd thread
+ * | |
+ * +-----------------------------------+
+ * | stack 2 - _pthread_stack_default | top of 2nd thread stack
+ * | |
+ * | |
+ * | |
+ * | |
+ * | stack 2 |
+ * +-----------------------------------+ <-- start of 2nd thread stack
+ * | |
+ * | Red Zone | red zone for 1st thread
+ * | |
+ * +-----------------------------------+
+ * | stack 1 - _pthread_stack_default | top of 1st thread stack
+ * | |
+ * | |
+ * | |
+ * | |
+ * | stack 1 |
+ * +-----------------------------------+ <-- start of 1st thread stack
+ * | | (initial value of last_stack)
+ * | Red Zone |
+ * | | red zone for main thread
+ * +-----------------------------------+
+ * | USRSTACK - _pthread_stack_initial | top of main thread stack
+ * | | ^
+ * | | |
+ * | | |
+ * | | | stack growth
+ * | |
+ * +-----------------------------------+ <-- start of main thread stack
+ * (USRSTACK)
+ * high memory
+ *
+ */
+static void * last_stack;
+
+void *
+_thread_stack_alloc(size_t stacksize, size_t guardsize)
+{
+ void *stack = NULL;
+ struct stack *spare_stack;
+ size_t stack_size;
+
+ /*
+ * Round up stack size to nearest multiple of _pthread_page_size,
+ * so that mmap() * will work. If the stack size is not an even
+ * multiple, we end up initializing things such that there is unused
+ * space above the beginning of the stack, so the stack sits snugly
+ * against its guard.
+ */
+ if (stacksize % _pthread_page_size != 0)
+ stack_size = ((stacksize / _pthread_page_size) + 1) *
+ _pthread_page_size;
+ else
+ stack_size = stacksize;
+
+ /*
+ * If the stack and guard sizes are default, try to allocate a stack
+ * from the default-size stack cache:
+ */
+ if (stack_size == _pthread_stack_default &&
+ guardsize == _pthread_guard_default) {
+ /*
+ * Use the garbage collector mutex for synchronization of the
+ * spare stack list.
+ */
+ if (_pthread_mutex_lock(&_gc_mutex) != 0)
+ PANIC("Cannot lock gc mutex");
+
+ if ((spare_stack = LIST_FIRST(&_dstackq)) != NULL) {
+ /* Use the spare stack. */
+ LIST_REMOVE(spare_stack, qe);
+ stack = spare_stack->stackaddr;
+ }
+
+ /* Unlock the garbage collector mutex. */
+ if (_pthread_mutex_unlock(&_gc_mutex) != 0)
+ PANIC("Cannot unlock gc mutex");
+ }
+ /*
+ * The user specified a non-default stack and/or guard size, so try to
+ * allocate a stack from the non-default size stack cache, using the
+ * rounded up stack size (stack_size) in the search:
+ */
+ else {
+ /*
+ * Use the garbage collector mutex for synchronization of the
+ * spare stack list.
+ */
+ if (_pthread_mutex_lock(&_gc_mutex) != 0)
+ PANIC("Cannot lock gc mutex");
+
+ LIST_FOREACH(spare_stack, &_mstackq, qe) {
+ if (spare_stack->stacksize == stack_size &&
+ spare_stack->guardsize == guardsize) {
+ LIST_REMOVE(spare_stack, qe);
+ stack = spare_stack->stackaddr;
+ break;
+ }
+ }
+
+ /* Unlock the garbage collector mutex. */
+ if (_pthread_mutex_unlock(&_gc_mutex) != 0)
+ PANIC("Cannot unlock gc mutex");
+ }
+
+ /* Check if a stack was not allocated from a stack cache: */
+ if (stack == NULL) {
+
+ if (last_stack == NULL)
+ last_stack = _usrstack - _pthread_stack_initial -
+ _pthread_guard_default;
+
+ /* Allocate a new stack. */
+ stack = last_stack - stack_size;
+
+ /*
+ * Even if stack allocation fails, we don't want to try to use
+ * this location again, so unconditionally decrement
+ * last_stack. Under normal operating conditions, the most
+ * likely reason for an mmap() error is a stack overflow of the
+ * adjacent thread stack.
+ */
+ last_stack -= (stack_size + guardsize);
+
+ /* Stack: */
+ if (mmap(stack, stack_size, PROT_READ | PROT_WRITE, MAP_STACK,
+ -1, 0) == MAP_FAILED)
+ stack = NULL;
+ }
+
+ return (stack);
+}
+
+/* This function must be called with _gc_mutex held. */
+void
+_thread_stack_free(void *stack, size_t stacksize, size_t guardsize)
+{
+ struct stack *spare_stack;
+
+ spare_stack = (stack + stacksize - sizeof(struct stack));
+ /* Round stacksize up to nearest multiple of _pthread_page_size. */
+ if (stacksize % _pthread_page_size != 0) {
+ spare_stack->stacksize =
+ ((stacksize / _pthread_page_size) + 1) *
+ _pthread_page_size;
+ } else
+ spare_stack->stacksize = stacksize;
+ spare_stack->guardsize = guardsize;
+ spare_stack->stackaddr = stack;
+
+ if (spare_stack->stacksize == _pthread_stack_default &&
+ spare_stack->guardsize == _pthread_guard_default) {
+ /* Default stack/guard size. */
+ LIST_INSERT_HEAD(&_dstackq, spare_stack, qe);
+ } else {
+ /* Non-default stack/guard size. */
+ LIST_INSERT_HEAD(&_mstackq, spare_stack, qe);
+ }
+}
diff --git a/lib/libc_r/uthread/uthread_suspend_np.c b/lib/libc_r/uthread/uthread_suspend_np.c
new file mode 100644
index 0000000..952baa3
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_suspend_np.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+static void suspend_common(struct pthread *thread);
+
+__weak_reference(_pthread_suspend_np, pthread_suspend_np);
+__weak_reference(_pthread_suspend_all_np, pthread_suspend_all_np);
+
+/* Suspend a thread: */
+int
+_pthread_suspend_np(pthread_t thread)
+{
+ int ret;
+
+ /* Suspending the current thread doesn't make sense. */
+ if (thread == _get_curthread())
+ ret = EDEADLK;
+
+ /* Find the thread in the list of active threads: */
+ else if ((ret = _find_thread(thread)) == 0) {
+ /*
+ * Defer signals to protect the scheduling queues from
+ * access by the signal handler:
+ */
+ _thread_kern_sig_defer();
+
+ suspend_common(thread);
+
+ /*
+ * Undefer and handle pending signals, yielding if
+ * necessary:
+ */
+ _thread_kern_sig_undefer();
+ }
+ return (ret);
+}
+
+void
+_pthread_suspend_all_np(void)
+{
+ struct pthread *curthread = _get_curthread();
+ struct pthread *thread;
+
+ /*
+ * Defer signals to protect the scheduling queues from
+ * access by the signal handler:
+ */
+ _thread_kern_sig_defer();
+
+ TAILQ_FOREACH(thread, &_thread_list, tle) {
+ if (thread != curthread)
+ suspend_common(thread);
+ }
+
+ /*
+ * Undefer and handle pending signals, yielding if
+ * necessary:
+ */
+ _thread_kern_sig_undefer();
+}
+
+void
+suspend_common(struct pthread *thread)
+{
+ thread->flags |= PTHREAD_FLAGS_SUSPENDED;
+ if (thread->flags & PTHREAD_FLAGS_IN_PRIOQ) {
+ PTHREAD_PRIOQ_REMOVE(thread);
+ PTHREAD_SET_STATE(thread, PS_SUSPENDED);
+ }
+}
diff --git a/lib/libc_r/uthread/uthread_switch_np.c b/lib/libc_r/uthread/uthread_switch_np.c
new file mode 100644
index 0000000..f24d99f
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_switch_np.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include <pthread_np.h>
+#include "pthread_private.h"
+
+
+__weak_reference(_pthread_switch_add_np, pthread_switch_add_np);
+__weak_reference(_pthread_switch_delete_np, pthread_switch_delete_np);
+
+int
+_pthread_switch_add_np(pthread_switch_routine_t routine)
+{
+ int ret = 0;
+
+ if (routine == NULL)
+ /* Return an invalid argument error: */
+ ret = EINVAL;
+ else
+ /* Shouldn't need a lock to protect this assigment. */
+ _sched_switch_hook = routine;
+
+ return(ret);
+}
+
+int
+_pthread_switch_delete_np(pthread_switch_routine_t routine)
+{
+ int ret = 0;
+
+ if (routine != _sched_switch_hook)
+ /* Return an invalid argument error: */
+ ret = EINVAL;
+ else
+ /* Shouldn't need a lock to protect this assigment. */
+ _sched_switch_hook = NULL;
+
+ return(ret);
+}
diff --git a/lib/libc_r/uthread/uthread_system.c b/lib/libc_r/uthread/uthread_system.c
new file mode 100644
index 0000000..d63969b
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_system.c
@@ -0,0 +1,48 @@
+/*
+ * 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$
+ */
+
+#include <stdlib.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_system, system);
+
+int
+_system(const char *string)
+{
+ int ret;
+
+ _thread_enter_cancellation_point();
+ ret = __system(string);
+ _thread_leave_cancellation_point();
+
+ return ret;
+}
diff --git a/lib/libc_r/uthread/uthread_tcdrain.c b/lib/libc_r/uthread/uthread_tcdrain.c
new file mode 100644
index 0000000..272bdf6
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_tcdrain.c
@@ -0,0 +1,48 @@
+/*
+ * 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$
+ */
+
+#include <termios.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_tcdrain, tcdrain);
+
+int
+_tcdrain(int fd)
+{
+ int ret;
+
+ _thread_enter_cancellation_point();
+ ret = __tcdrain(fd);
+ _thread_leave_cancellation_point();
+
+ return ret;
+}
diff --git a/lib/libc_r/uthread/uthread_vfork.c b/lib/libc_r/uthread/uthread_vfork.c
new file mode 100644
index 0000000..dbefc65
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_vfork.c
@@ -0,0 +1,12 @@
+/*
+ * $FreeBSD$
+ */
+#include <unistd.h>
+
+__weak_reference(_vfork, vfork);
+
+int
+_vfork(void)
+{
+ return (fork());
+}
diff --git a/lib/libc_r/uthread/uthread_wait.c b/lib/libc_r/uthread/uthread_wait.c
new file mode 100644
index 0000000..e61138b
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_wait.c
@@ -0,0 +1,47 @@
+/*
+ * 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$
+ */
+
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_wait, wait);
+
+pid_t
+_wait(int *istat)
+{
+ pid_t ret;
+
+ _thread_enter_cancellation_point();
+ ret = __wait(istat);
+ _thread_leave_cancellation_point();
+
+ return ret;
+}
diff --git a/lib/libc_r/uthread/uthread_wait4.c b/lib/libc_r/uthread/uthread_wait4.c
new file mode 100644
index 0000000..05ed065
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_wait4.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <errno.h>
+#include <sys/wait.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(__wait4, wait4);
+
+pid_t
+_wait4(pid_t pid, int *istat, int options, struct rusage * rusage)
+{
+ struct pthread *curthread = _get_curthread();
+ pid_t ret;
+
+ _thread_kern_sig_defer();
+
+ /* Perform a non-blocking wait4 syscall: */
+ while ((ret = __sys_wait4(pid, istat, options | WNOHANG, rusage)) == 0 && (options & WNOHANG) == 0) {
+ /* Reset the interrupted operation flag: */
+ curthread->interrupted = 0;
+
+ /* Schedule the next thread while this one waits: */
+ _thread_kern_sched_state(PS_WAIT_WAIT, __FILE__, __LINE__);
+
+ /* Check if this call was interrupted by a signal: */
+ if (curthread->interrupted) {
+ errno = EINTR;
+ ret = -1;
+ break;
+ }
+ }
+
+ _thread_kern_sig_undefer();
+
+ return (ret);
+}
+
+pid_t
+__wait4(pid_t pid, int *istat, int options, struct rusage *rusage)
+{
+ pid_t ret;
+
+ _thread_enter_cancellation_point();
+ ret = _wait4(pid, istat, options, rusage);
+ _thread_leave_cancellation_point();
+
+ return ret;
+}
diff --git a/lib/libc_r/uthread/uthread_waitpid.c b/lib/libc_r/uthread/uthread_waitpid.c
new file mode 100644
index 0000000..fcbbc9f
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_waitpid.c
@@ -0,0 +1,49 @@
+/*
+ * 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$
+ */
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_waitpid, waitpid);
+
+pid_t
+_waitpid(pid_t wpid, int *status, int options)
+{
+ pid_t ret;
+
+ _thread_enter_cancellation_point();
+ ret = __waitpid(wpid, status, options);
+ _thread_leave_cancellation_point();
+
+ return ret;
+}
diff --git a/lib/libc_r/uthread/uthread_write.c b/lib/libc_r/uthread/uthread_write.c
new file mode 100644
index 0000000..0b1e4a0
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_write.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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/fcntl.h>
+#include <sys/uio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(__write, write);
+
+ssize_t
+_write(int fd, const void *buf, size_t nbytes)
+{
+ struct pthread *curthread = _get_curthread();
+ int blocking;
+ int type;
+ ssize_t n;
+ ssize_t num = 0;
+ ssize_t ret;
+
+ /* POSIX says to do just this: */
+ if (nbytes == 0)
+ return (0);
+
+ /* Lock the file descriptor for write: */
+ if ((ret = _FD_LOCK(fd, FD_WRITE, NULL)) == 0) {
+ /* Get the read/write mode type: */
+ type = _thread_fd_getflags(fd) & O_ACCMODE;
+
+ /* Check if the file is not open for write: */
+ if (type != O_WRONLY && type != O_RDWR) {
+ /* File is not open for write: */
+ errno = EBADF;
+ _FD_UNLOCK(fd, FD_WRITE);
+ return (-1);
+ }
+
+ /* Check if file operations are to block */
+ blocking = ((_thread_fd_getflags(fd) & O_NONBLOCK) == 0);
+
+ /*
+ * Loop while no error occurs and until the expected number
+ * of bytes are written if performing a blocking write:
+ */
+ while (ret == 0) {
+ /* Perform a non-blocking write syscall: */
+ n = __sys_write(fd, (const char *)buf + num,
+ nbytes - num);
+
+ /* Check if one or more bytes were written: */
+ if (n > 0)
+ /*
+ * Keep a count of the number of bytes
+ * written:
+ */
+ num += n;
+
+ /*
+ * If performing a blocking write, check if the
+ * write would have blocked or if some bytes
+ * were written but there are still more to
+ * write:
+ */
+ if (blocking && ((n < 0 && (errno == EWOULDBLOCK ||
+ errno == EAGAIN)) || (n > 0 && num < nbytes))) {
+ curthread->data.fd.fd = fd;
+ _thread_kern_set_timeout(NULL);
+
+ /* Reset the interrupted operation flag: */
+ curthread->interrupted = 0;
+
+ _thread_kern_sched_state(PS_FDW_WAIT,
+ __FILE__, __LINE__);
+
+ /*
+ * Check if the operation was
+ * interrupted by a signal
+ */
+ if (curthread->interrupted) {
+ if (num > 0) {
+ /* Return partial success: */
+ ret = num;
+ } else {
+ /* Return an error: */
+ errno = EINTR;
+ ret = -1;
+ }
+ }
+
+ /*
+ * If performing a non-blocking write,
+ * just return whatever the write syscall did:
+ */
+ } else if (!blocking) {
+ /* A non-blocking call might return zero: */
+ ret = n;
+ break;
+
+ /*
+ * If there was an error, return partial success
+ * (if any bytes were written) or else the error:
+ */
+ } else if (n <= 0) {
+ if (num > 0)
+ ret = num;
+ else
+ ret = n;
+ if (n == 0)
+ break;
+
+ /* Check if the write has completed: */
+ } else if (num >= nbytes)
+ /* Return the number of bytes written: */
+ ret = num;
+ }
+ _FD_UNLOCK(fd, FD_WRITE);
+ }
+ return (ret);
+}
+
+ssize_t
+__write(int fd, const void *buf, size_t nbytes)
+{
+ ssize_t ret;
+
+ _thread_enter_cancellation_point();
+ ret = _write(fd, buf, nbytes);
+ _thread_leave_cancellation_point();
+
+ return ret;
+}
diff --git a/lib/libc_r/uthread/uthread_writev.c b/lib/libc_r/uthread/uthread_writev.c
new file mode 100644
index 0000000..31d2b8c
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_writev.c
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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/fcntl.h>
+#include <sys/uio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(__writev, writev);
+
+ssize_t
+_writev(int fd, const struct iovec * iov, int iovcnt)
+{
+ struct pthread *curthread = _get_curthread();
+ int blocking;
+ int idx = 0;
+ int type;
+ ssize_t cnt;
+ ssize_t n;
+ ssize_t num = 0;
+ ssize_t ret;
+ struct iovec liov[20];
+ struct iovec *p_iov = liov;
+
+ /* Check if the array size exceeds to compiled in size: */
+ if (iovcnt > (sizeof(liov) / sizeof(struct iovec))) {
+ /* Allocate memory for the local array: */
+ if ((p_iov = (struct iovec *)
+ malloc(iovcnt * sizeof(struct iovec))) == NULL) {
+ /* Insufficient memory: */
+ errno = ENOMEM;
+ return (-1);
+ }
+ }
+
+ /* Copy the caller's array so that it can be modified locally: */
+ memcpy(p_iov,iov,iovcnt * sizeof(struct iovec));
+
+ /* Lock the file descriptor for write: */
+ if ((ret = _FD_LOCK(fd, FD_WRITE, NULL)) == 0) {
+ /* Get the read/write mode type: */
+ type = _thread_fd_getflags(fd) & O_ACCMODE;
+
+ /* Check if the file is not open for write: */
+ if (type != O_WRONLY && type != O_RDWR) {
+ /* File is not open for write: */
+ errno = EBADF;
+ _FD_UNLOCK(fd, FD_WRITE);
+ return (-1);
+ }
+
+ /* Check if file operations are to block */
+ blocking = ((_thread_fd_getflags(fd) & O_NONBLOCK) == 0);
+
+ /*
+ * Loop while no error occurs and until the expected number
+ * of bytes are written if performing a blocking write:
+ */
+ while (ret == 0) {
+ /* Perform a non-blocking write syscall: */
+ n = __sys_writev(fd, &p_iov[idx], iovcnt - idx);
+
+ /* Check if one or more bytes were written: */
+ if (n > 0) {
+ /*
+ * Keep a count of the number of bytes
+ * written:
+ */
+ num += n;
+
+ /*
+ * Enter a loop to check if a short write
+ * occurred and move the index to the
+ * array entry where the short write
+ * ended:
+ */
+ cnt = n;
+ while (cnt > 0 && idx < iovcnt) {
+ /*
+ * If the residual count exceeds
+ * the size of this vector, then
+ * it was completely written:
+ */
+ if (cnt >= p_iov[idx].iov_len)
+ /*
+ * Decrement the residual
+ * count and increment the
+ * index to the next array
+ * entry:
+ */
+ cnt -= p_iov[idx++].iov_len;
+ else {
+ /*
+ * This entry was only
+ * partially written, so
+ * adjust it's length
+ * and base pointer ready
+ * for the next write:
+ */
+ p_iov[idx].iov_len -= cnt;
+ p_iov[idx].iov_base =
+ (char *)p_iov[idx].iov_base
+ + cnt;
+ cnt = 0;
+ }
+ }
+ } else if (n == 0) {
+ /*
+ * Avoid an infinite loop if the last iov_len is
+ * 0.
+ */
+ while (idx < iovcnt && p_iov[idx].iov_len == 0)
+ idx++;
+
+ if (idx == iovcnt) {
+ ret = num;
+ break;
+ }
+ }
+
+ /*
+ * If performing a blocking write, check if the
+ * write would have blocked or if some bytes
+ * were written but there are still more to
+ * write:
+ */
+ if (blocking && ((n < 0 && (errno == EWOULDBLOCK ||
+ errno == EAGAIN)) || (n >= 0 && idx < iovcnt))) {
+ curthread->data.fd.fd = fd;
+ _thread_kern_set_timeout(NULL);
+
+ /* Reset the interrupted operation flag: */
+ curthread->interrupted = 0;
+
+ _thread_kern_sched_state(PS_FDW_WAIT,
+ __FILE__, __LINE__);
+
+ /*
+ * Check if the operation was
+ * interrupted by a signal
+ */
+ if (curthread->interrupted) {
+ if (num > 0) {
+ /* Return partial success: */
+ ret = num;
+ } else {
+ /* Return an error: */
+ errno = EINTR;
+ ret = -1;
+ }
+ }
+
+ /*
+ * If performing a non-blocking write,
+ * just return whatever the write syscall did:
+ */
+ } else if (!blocking) {
+ /* A non-blocking call might return zero: */
+ ret = n;
+ break;
+
+ /*
+ * If there was an error, return partial success
+ * (if any bytes were written) or else the error:
+ */
+ } else if (n < 0) {
+ if (num > 0)
+ ret = num;
+ else
+ ret = n;
+
+ /* Check if the write has completed: */
+ } else if (idx == iovcnt)
+ /* Return the number of bytes written: */
+ ret = num;
+ }
+ _FD_UNLOCK(fd, FD_RDWR);
+ }
+
+ /* If memory was allocated for the array, free it: */
+ if (p_iov != liov)
+ free(p_iov);
+
+ return (ret);
+}
+
+ssize_t
+__writev(int fd, const struct iovec *iov, int iovcnt)
+{
+ ssize_t ret;
+
+ _thread_enter_cancellation_point();
+ ret = _writev(fd, iov, iovcnt);
+ _thread_leave_cancellation_point();
+
+ return ret;
+}
diff --git a/lib/libc_r/uthread/uthread_yield.c b/lib/libc_r/uthread/uthread_yield.c
new file mode 100644
index 0000000..ec89255
--- /dev/null
+++ b/lib/libc_r/uthread/uthread_yield.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 "pthread_private.h"
+
+__weak_reference(_sched_yield, sched_yield);
+__weak_reference(_pthread_yield, pthread_yield);
+
+int
+_sched_yield(void)
+{
+ struct pthread *curthread = _get_curthread();
+
+ /* Reset the accumulated time slice value for the current thread: */
+ curthread->slice_usec = -1;
+
+ /* Schedule the next thread: */
+ _thread_kern_sched(NULL);
+
+ /* Always return no error. */
+ return(0);
+}
+
+/* Draft 4 yield */
+void
+_pthread_yield(void)
+{
+ struct pthread *curthread = _get_curthread();
+
+ /* Reset the accumulated time slice value for the current thread: */
+ curthread->slice_usec = -1;
+
+ /* Schedule the next thread: */
+ _thread_kern_sched(NULL);
+}
diff --git a/lib/libcalendar/Makefile b/lib/libcalendar/Makefile
new file mode 100644
index 0000000..8bba20b
--- /dev/null
+++ b/lib/libcalendar/Makefile
@@ -0,0 +1,16 @@
+# $FreeBSD$
+
+LIB= calendar
+WARNS?= 2
+
+SRCS= calendar.c easter.c
+INCS= calendar.h
+
+MAN= calendar.3
+
+MLINKS= calendar.3 easterg.3 calendar.3 easterog.3 calendar.3 easteroj.3 \
+ calendar.3 gdate.3 calendar.3 jdate.3 \
+ calendar.3 ndaysg.3 calendar.3 ndaysj.3 \
+ calendar.3 week.3 calendar.3 weekday.3
+
+.include <bsd.lib.mk>
diff --git a/lib/libcalendar/calendar.3 b/lib/libcalendar/calendar.3
new file mode 100644
index 0000000..469f1c9
--- /dev/null
+++ b/lib/libcalendar/calendar.3
@@ -0,0 +1,203 @@
+.\" Copyright (c) 1997 Wolfgang Helbig
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING 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 29, 1997
+.Dt CALENDAR 3
+.Os
+.Sh NAME
+.Nm easterg ,
+.Nm easterog ,
+.Nm easteroj ,
+.Nm gdate ,
+.Nm jdate ,
+.Nm ndaysg ,
+.Nm ndaysj ,
+.Nm week ,
+.Nm weekday
+.Nd Calendar arithmetic for the Christian era
+.Sh LIBRARY
+.Lb libcalendar
+.Sh SYNOPSIS
+.In calendar.h
+.Ft struct date *
+.Fn easterg "int year" "struct date *dt"
+.Ft struct date *
+.Fn easterog "int year" "struct date *dt"
+.Ft struct date *
+.Fn easteroj "int year" "struct date *dt"
+.Ft struct date *
+.Fn gdate "int nd" "struct date *dt"
+.Ft struct date *
+.Fn jdate "int nd" "struct date *dt"
+.Ft int
+.Fn ndaysg "struct date *dt"
+.Ft int
+.Fn ndaysj "struct date *dt"
+.Ft int
+.Fn week "int nd" "int *year"
+.Ft int
+.Fn weekday "int nd"
+.Sh DESCRIPTION
+These functions provide calendar arithmetic for a large range of years,
+starting at March 1st, year zero (i.e., 1 B.C.) and ending way beyond
+year 100000.
+.Pp
+Programs should be linked with
+.Fl lcalendar .
+.Pp
+The functions
+.Fn easterg ,
+.Fn easterog
+and
+.Fn easteroj
+store the date of Easter Sunday into the structure pointed at by
+.Fa dt
+and return a pointer to this structure.
+The function
+.Fn easterg
+assumes Gregorian Calendar (adopted by most western churches after 1582) and
+the functions
+.Fn easterog
+and
+.Fn easteroj
+compute the date of Easter Sunday according to the orthodox rules
+(Western churches before 1582, Greek and Russian Orthodox Church
+until today).
+The result returned by
+.Fn easterog
+is the date in Gregorian Calendar, whereas
+.Fn easteroj
+returns the date in Julian Calendar.
+.Pp
+The functions
+.Fn gdate ,
+.Fn jdate ,
+.Fn ndaysg
+and
+.Fn ndaysj
+provide conversions between the common "year, month, day" notation
+of a date and the "number of days" representation, which is better suited
+for calculations.
+The days are numbered from March 1st year 1 B.C., starting
+with zero, so the number of a day gives the number of days since March 1st,
+year 1 B.C.
+The conversions work for nonnegative day numbers only.
+.Pp
+The
+.Fn gdate
+and
+.Fn jdate
+functions
+store the date corresponding to the day number
+.Fa nd
+into the structure pointed at by
+.Fa dt
+and return a pointer to this structure.
+.Pp
+The
+.Fn ndaysg
+and
+.Fn ndaysj
+functions
+return the day number of the date pointed at by
+.Fa dt .
+.Pp
+The
+.Fn gdate
+and
+.Fn ndaysg
+functions
+assume Gregorian Calendar after October 4, 1582 and Julian Calendar before,
+whereas
+.Fn jdate
+and
+.Fn ndaysj
+assume Julian Calendar throughout.
+.Pp
+The two calendars differ by the definition of the leap year.
+The
+Julian Calendar says every year that is a multiple of four is a
+leap year.
+The Gregorian Calendar excludes years that are multiples of
+100 and not multiples of 400.
+This means the years 1700, 1800, 1900, 2100 are not leap years
+and the year 2000 is
+a leap year.
+The new rules were inaugurated on October 4, 1582 by deleting ten
+days following this date.
+Most catholic countries adopted the new
+calendar by the end of the 16th century, whereas others stayed with
+the Julian Calendar until the 20th century.
+The United Kingdom and
+their colonies switched on September 2, 1752.
+They already had to
+delete 11 days.
+.Pp
+The function
+.Fn week
+returns the number of the week which contains the day numbered
+.Fa nd .
+The argument
+.Fa *year
+is set with the year that contains (the greater part of) the week.
+The weeks are numbered per year starting with week 1, which is the
+first week in a year that includes more than three days of the year.
+Weeks start on Monday.
+This function is defined for Gregorian Calendar only.
+.Pp
+The function
+.Fn weekday
+returns the weekday (Mo = 0 ..\& Su = 6) of the day numbered
+.Fa nd .
+.Pp
+The structure
+.Fa date
+is defined in
+.In calendar.h .
+It contains these fields:
+.Bd -literal -offset indent
+int y; /\(** year (0000 - ????) \(**/
+int m; /\(** month (1 - 12) \(**/
+int d; /\(** day of month (1 - 31) \(**/
+.Ed
+.Pp
+The year zero is written as "1 B.C." by historians and "0" by astronomers
+and in this library.
+.Sh SEE ALSO
+.Xr ncal 1 ,
+.Xr strftime 3
+.Sh STANDARDS
+The week number conforms to ISO 8601: 1988.
+.Sh HISTORY
+The
+.Nm calendar
+library first appeared in
+.Fx 3.0 .
+.Sh AUTHORS
+This manual page and the library was written by
+.An Wolfgang Helbig Aq helbig@FreeBSD.org .
+.Sh BUGS
+The library was coded with great care so there are no bugs left.
diff --git a/lib/libcalendar/calendar.c b/lib/libcalendar/calendar.c
new file mode 100644
index 0000000..fca63ee
--- /dev/null
+++ b/lib/libcalendar/calendar.c
@@ -0,0 +1,330 @@
+/*-
+ * Copyright (c) 1997 Wolfgang Helbig
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "calendar.h"
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+/*
+ * For each month tabulate the number of days elapsed in a year before the
+ * month. This assumes the internal date representation, where a year
+ * starts on March 1st. So we don't need a special table for leap years.
+ * But we do need a special table for the year 1582, since 10 days are
+ * deleted in October. This is month1s for the switch from Julian to
+ * Gregorian calendar.
+ */
+static int const month1[] =
+ {0, 31, 61, 92, 122, 153, 184, 214, 245, 275, 306, 337};
+ /* M A M J J A S O N D J */
+static int const month1s[]=
+ {0, 31, 61, 92, 122, 153, 184, 214, 235, 265, 296, 327};
+
+typedef struct date date;
+
+/* The last day of Julian calendar, in internal and ndays representation */
+static int nswitch; /* The last day of Julian calendar */
+static date jiswitch = {1582, 7, 3};
+
+static date *date2idt(date *idt, date *dt);
+static date *idt2date(date *dt, date *idt);
+static int ndaysji(date *idt);
+static int ndaysgi(date *idt);
+static int firstweek(int year);
+
+/*
+ * Compute the Julian date from the number of days elapsed since
+ * March 1st of year zero.
+ */
+date *
+jdate(int ndays, date *dt)
+{
+ date idt; /* Internal date representation */
+ int r; /* hold the rest of days */
+
+ /*
+ * Compute the year by starting with an approximation not smaller
+ * than the answer and using linear search for the greatest
+ * year which does not begin after ndays.
+ */
+ idt.y = ndays / 365;
+ idt.m = 0;
+ idt.d = 0;
+ while ((r = ndaysji(&idt)) > ndays)
+ idt.y--;
+
+ /*
+ * Set r to the days left in the year and compute the month by
+ * linear search as the largest month that does not begin after r
+ * days.
+ */
+ r = ndays - r;
+ for (idt.m = 11; month1[idt.m] > r; idt.m--)
+ ;
+
+ /* Compute the days left in the month */
+ idt.d = r - month1[idt.m];
+
+ /* return external representation of the date */
+ return (idt2date(dt, &idt));
+}
+
+/*
+ * Return the number of days since March 1st of the year zero.
+ * The date is given according to Julian calendar.
+ */
+int
+ndaysj(date *dt)
+{
+ date idt; /* Internal date representation */
+
+ if (date2idt(&idt, dt) == NULL)
+ return (-1);
+ else
+ return (ndaysji(&idt));
+}
+
+/*
+ * Same as above, where the Julian date is given in internal notation.
+ * This formula shows the beauty of this notation.
+ */
+static int
+ndaysji(date * idt)
+{
+
+ return (idt->d + month1[idt->m] + idt->y * 365 + idt->y / 4);
+}
+
+/*
+ * Compute the date according to the Gregorian calendar from the number of
+ * days since March 1st, year zero. The date computed will be Julian if it
+ * is older than 1582-10-05. This is the reverse of the function ndaysg().
+ */
+date *
+gdate(int ndays, date *dt)
+{
+ int const *montht; /* month-table */
+ date idt; /* for internal date representation */
+ int r; /* holds the rest of days */
+
+ /*
+ * Compute the year by starting with an approximation not smaller
+ * than the answer and search linearly for the greatest year not
+ * starting after ndays.
+ */
+ idt.y = ndays / 365;
+ idt.m = 0;
+ idt.d = 0;
+ while ((r = ndaysgi(&idt)) > ndays)
+ idt.y--;
+
+ /*
+ * Set ndays to the number of days left and compute by linear
+ * search the greatest month which does not start after ndays. We
+ * use the table month1 which provides for each month the number
+ * of days that elapsed in the year before that month. Here the
+ * year 1582 is special, as 10 days are left out in October to
+ * resynchronize the calendar with the earth's orbit. October 4th
+ * 1582 is followed by October 15th 1582. We use the "switch"
+ * table month1s for this year.
+ */
+ ndays = ndays - r;
+ if (idt.y == 1582)
+ montht = month1s;
+ else
+ montht = month1;
+
+ for (idt.m = 11; montht[idt.m] > ndays; idt.m--)
+ ;
+
+ idt.d = ndays - montht[idt.m]; /* the rest is the day in month */
+
+ /* Advance ten days deleted from October if after switch in Oct 1582 */
+ if (idt.y == jiswitch.y && idt.m == jiswitch.m && jiswitch.d < idt.d)
+ idt.d += 10;
+
+ /* return external representation of found date */
+ return (idt2date(dt, &idt));
+}
+
+/*
+ * Return the number of days since March 1st of the year zero. The date is
+ * assumed Gregorian if younger than 1582-10-04 and Julian otherwise. This
+ * is the reverse of gdate.
+ */
+int
+ndaysg(date *dt)
+{
+ date idt; /* Internal date representation */
+
+ if (date2idt(&idt, dt) == NULL)
+ return (-1);
+ return (ndaysgi(&idt));
+}
+
+/*
+ * Same as above, but with the Gregorian date given in internal
+ * representation.
+ */
+static int
+ndaysgi(date *idt)
+{
+ int nd; /* Number of days--return value */
+
+ /* Cache nswitch if not already done */
+ if (nswitch == 0)
+ nswitch = ndaysji(&jiswitch);
+
+ /*
+ * Assume Julian calendar and adapt to Gregorian if necessary, i. e.
+ * younger than nswitch. Gregori deleted
+ * the ten days from Oct 5th to Oct 14th 1582.
+ * Thereafter years which are multiples of 100 and not multiples
+ * of 400 were not leap years anymore.
+ * This makes the average length of a year
+ * 365d +.25d - .01d + .0025d = 365.2425d. But the tropical
+ * year measures 365.2422d. So in 10000/3 years we are
+ * again one day ahead of the earth. Sigh :-)
+ * (d is the average length of a day and tropical year is the
+ * time from one spring point to the next.)
+ */
+ if ((nd = ndaysji(idt)) == -1)
+ return (-1);
+ if (idt->y >= 1600)
+ nd = (nd - 10 - (idt->y - 1600) / 100 + (idt->y - 1600) / 400);
+ else if (nd > nswitch)
+ nd -= 10;
+ return (nd);
+}
+
+/*
+ * Compute the week number from the number of days since March 1st year 0.
+ * The weeks are numbered per year starting with 1. If the first
+ * week of a year includes at least four days of that year it is week 1,
+ * otherwise it gets the number of the last week of the previous year.
+ * The variable y will be filled with the year that contains the greater
+ * part of the week.
+ */
+int
+week(int nd, int *y)
+{
+ date dt;
+ int fw; /* 1st day of week 1 of previous, this and
+ * next year */
+ gdate(nd, &dt);
+ for (*y = dt.y + 1; nd < (fw = firstweek(*y)); (*y)--)
+ ;
+ return ((nd - fw) / 7 + 1);
+}
+
+/* return the first day of week 1 of year y */
+static int
+firstweek(int y)
+{
+ date idt;
+ int nd, wd;
+
+ idt.y = y - 1; /* internal representation of y-1-1 */
+ idt.m = 10;
+ idt.d = 0;
+
+ nd = ndaysgi(&idt);
+ /*
+ * If more than 3 days of this week are in the preceding year, the
+ * next week is week 1 (and the next monday is the answer),
+ * otherwise this week is week 1 and the last monday is the
+ * answer.
+ */
+ if ((wd = weekday(nd)) > 3)
+ return (nd - wd + 7);
+ else
+ return (nd - wd);
+}
+
+/* return the weekday (Mo = 0 .. Su = 6) */
+int
+weekday(int nd)
+{
+ date dmondaygi = {1997, 8, 16}; /* Internal repr. of 1997-11-17 */
+ static int nmonday; /* ... which is a monday */
+
+ /* Cache the daynumber of one monday */
+ if (nmonday == 0)
+ nmonday = ndaysgi(&dmondaygi);
+
+ /* return (nd - nmonday) modulo 7 which is the weekday */
+ nd = (nd - nmonday) % 7;
+ if (nd < 0)
+ return (nd + 7);
+ else
+ return (nd);
+}
+
+/*
+ * Convert a date to internal date representation: The year starts on
+ * March 1st, month and day numbering start at zero. E. g. March 1st of
+ * year zero is written as y=0, m=0, d=0.
+ */
+static date *
+date2idt(date *idt, date *dt)
+{
+
+ idt->d = dt->d - 1;
+ if (dt->m > 2) {
+ idt->m = dt->m - 3;
+ idt->y = dt->y;
+ } else {
+ idt->m = dt->m + 9;
+ idt->y = dt->y - 1;
+ }
+ if (idt->m < 0 || idt->m > 11 || idt->y < 0)
+ return (NULL);
+ else
+ return idt;
+}
+
+/* Reverse of date2idt */
+static date *
+idt2date(date *dt, date *idt)
+{
+
+ dt->d = idt->d + 1;
+ if (idt->m < 10) {
+ dt->m = idt->m + 3;
+ dt->y = idt->y;
+ } else {
+ dt->m = idt->m - 9;
+ dt->y = idt->y + 1;
+ }
+ if (dt->m < 1)
+ return (NULL);
+ else
+ return (dt);
+}
diff --git a/lib/libcalendar/calendar.h b/lib/libcalendar/calendar.h
new file mode 100644
index 0000000..2c42d6c
--- /dev/null
+++ b/lib/libcalendar/calendar.h
@@ -0,0 +1,42 @@
+/*-
+ * Copyright (c) 1997 Wolfgang Helbig
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+struct date {
+ int y; /* year */
+ int m; /* month */
+ int d; /* day */
+};
+
+struct date *easterg(int _year, struct date *_dt);
+struct date *easterog(int _year, struct date *_dt);
+struct date *easteroj(int _year, struct date *_dt);
+struct date *gdate(int _nd, struct date *_dt);
+struct date *jdate(int _nd, struct date *_dt);
+int ndaysg(struct date *_dt);
+int ndaysj(struct date *_dt);
+int week(int _nd, int *_year);
+int weekday(int _nd);
diff --git a/lib/libcalendar/easter.c b/lib/libcalendar/easter.c
new file mode 100644
index 0000000..8bb3e1c
--- /dev/null
+++ b/lib/libcalendar/easter.c
@@ -0,0 +1,101 @@
+/*-
+ * Copyright (c) 1997 Wolfgang Helbig
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "calendar.h"
+
+typedef struct date date;
+
+static int easterodn(int y);
+
+/* Compute Easter Sunday in Gregorian Calendar */
+date *
+easterg(int y, date *dt)
+{
+ int c, i, j, k, l, n;
+
+ n = y % 19;
+ c = y / 100;
+ k = (c - 17) / 25;
+ i = (c - c/4 -(c-k)/3 + 19 * n + 15) % 30;
+ i = i -(i/28) * (1 - (i/28) * (29/(i + 1)) * ((21 - n)/11));
+ j = (y + y/4 + i + 2 - c + c/4) % 7;
+ l = i - j;
+ dt->m = 3 + (l + 40) / 44;
+ dt->d = l + 28 - 31*(dt->m / 4);
+ dt->y = y;
+ return (dt);
+}
+
+/* Compute the Gregorian date of Easter Sunday in Julian Calendar */
+date *
+easterog(int y, date *dt)
+{
+
+ return (gdate(easterodn(y), dt));
+}
+
+/* Compute the Julian date of Easter Sunday in Julian Calendar */
+date *
+easteroj(int y, date * dt)
+{
+
+ return (jdate(easterodn(y), dt));
+}
+
+/* Compute the day number of Easter Sunday in Julian Calendar */
+static int
+easterodn(int y)
+{
+ /*
+ * Table for the easter limits in one metonic (19-year) cycle. 21
+ * to 31 is in March, 1 through 18 in April. Easter is the first
+ * sunday after the easter limit.
+ */
+ int mc[] = {5, 25, 13, 2, 22, 10, 30, 18, 7, 27, 15, 4,
+ 24, 12, 1, 21, 9, 29, 17};
+
+ /* Offset from a weekday to next sunday */
+ int ns[] = {6, 5, 4, 3, 2, 1, 7};
+ date dt;
+ int dn;
+
+ /* Assign the easter limit of y to dt */
+ dt.d = mc[y % 19];
+
+ if (dt.d < 21)
+ dt.m = 4;
+ else
+ dt.m = 3;
+
+ dt.y = y;
+
+ /* Return the next sunday after the easter limit */
+ dn = ndaysj(&dt);
+ return (dn + ns[weekday(dn)]);
+}
diff --git a/lib/libcam/Makefile b/lib/libcam/Makefile
new file mode 100644
index 0000000..92be69d
--- /dev/null
+++ b/lib/libcam/Makefile
@@ -0,0 +1,42 @@
+# $FreeBSD$
+
+LIB= cam
+SHLIBDIR?= /lib
+SRCS= camlib.c scsi_cmdparse.c scsi_all.c scsi_da.c scsi_sa.c cam.c
+INCS= camlib.h
+
+DPADD= ${LIBSBUF}
+LDADD= -lsbuf
+
+MAN= cam.3 cam_cdbparse.3
+
+
+MLINKS+= cam.3 cam_open_device.3 \
+ cam.3 cam_open_spec_device.3 \
+ cam.3 cam_open_btl.3 \
+ cam.3 cam_open_pass.3 \
+ cam.3 cam_close_device.3 \
+ cam.3 cam_close_spec_device.3 \
+ cam.3 cam_getccb.3 \
+ cam.3 cam_send_ccb.3 \
+ cam.3 cam_freeccb.3 \
+ cam.3 cam_path_string.3 \
+ cam.3 cam_device_dup.3 \
+ cam.3 cam_device_copy.3 \
+ cam.3 cam_get_device.3 \
+ cam_cdbparse.3 csio_build.3 \
+ cam_cdbparse.3 csio_build_visit.3 \
+ cam_cdbparse.3 csio_decode.3 \
+ cam_cdbparse.3 csio_decode_visit.3 \
+ cam_cdbparse.3 buff_decode.3 \
+ cam_cdbparse.3 buff_decode_visit.3 \
+ cam_cdbparse.3 csio_encode.3 \
+ cam_cdbparse.3 csio_encode_visit.3 \
+ cam_cdbparse.3 buff_encode_visit.3
+
+.PATH: ${.CURDIR}/../../sys/cam/scsi ${.CURDIR}/../../sys/cam
+
+SDIR= ${.CURDIR}/../../sys
+CFLAGS+= -I${.CURDIR} -I${SDIR}
+
+.include <bsd.lib.mk>
diff --git a/lib/libcam/cam.3 b/lib/libcam/cam.3
new file mode 100644
index 0000000..539709f
--- /dev/null
+++ b/lib/libcam/cam.3
@@ -0,0 +1,435 @@
+.\"
+.\" Copyright (c) 1998 Kenneth D. Merry.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce 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 October 10, 1998
+.Os
+.Dt CAM 3
+.Sh NAME
+.Nm cam_open_device ,
+.Nm cam_open_spec_device ,
+.Nm cam_open_btl ,
+.Nm cam_open_pass ,
+.Nm cam_close_device ,
+.Nm cam_close_spec_device ,
+.Nm cam_getccb ,
+.Nm cam_send_ccb ,
+.Nm cam_freeccb ,
+.Nm cam_path_string ,
+.Nm cam_device_dup ,
+.Nm cam_device_copy ,
+.Nm cam_get_device
+.Nd CAM user library
+.Sh LIBRARY
+.Lb libcam
+.Sh SYNOPSIS
+.In stdio.h
+.In camlib.h
+.Ft struct cam_device *
+.Fo cam_open_device
+.Fa "const char *path"
+.Fa "int flags"
+.Fc
+.Ft struct cam_device *
+.Fo cam_open_spec_device
+.Fa "const char *dev_name"
+.Fa "int unit"
+.Fa "int flags"
+.Fa "struct cam_device *device"
+.Fc
+.Ft struct cam_device *
+.Fo cam_open_btl
+.Fa "path_id_t path_id"
+.Fa "target_id_t target_id"
+.Fa "lun_id_t target_lun"
+.Fa "int flags"
+.Fa "struct cam_device *device"
+.Fc
+.Ft struct cam_device *
+.Fo cam_open_pass
+.Fa "const char *path"
+.Fa "int flags"
+.Fa "struct cam_device *device"
+.Fc
+.Ft void
+.Fo cam_close_device
+.Fa "struct cam_device *dev"
+.Fc
+.Ft void
+.Fo cam_close_spec_device
+.Fa "struct cam_device *dev"
+.Fc
+.Ft union ccb *
+.Fo cam_getccb
+.Fa "struct cam_device *dev"
+.Fc
+.Ft int
+.Fo cam_send_ccb
+.Fa "struct cam_device *device"
+.Fa "union ccb *ccb"
+.Fc
+.Ft void
+.Fo cam_freeccb
+.Fa "union ccb *ccb"
+.Fc
+.Ft char *
+.Fo cam_path_string
+.Fa "struct cam_device *dev"
+.Fa "char *str"
+.Fa "int len"
+.Fc
+.Ft struct cam_device *
+.Fo cam_device_dup
+.Fa "struct cam_device *device"
+.Fc
+.Ft void
+.Fo cam_device_copy
+.Fa "struct cam_device *src"
+.Fa "struct cam_device *dst"
+.Fc
+.Ft int
+.Fo cam_get_device
+.Fa "const char *path"
+.Fa "char *dev_name"
+.Fa "int devnamelen"
+.Fa "int *unit"
+.Fc
+.Sh DESCRIPTION
+The CAM library consists of a number of functions designed to aid in
+programming with the CAM subsystem.
+This man page covers the basic set of
+library functions.
+More functions are documented in the man pages listed
+below.
+.Pp
+Many of the CAM library functions use the
+.Va cam_device
+structure:
+.Bd -literal
+struct cam_device {
+ char device_path[MAXPATHLEN+1];/*
+ * Pathname of the
+ * device given by the
+ * user. This may be
+ * null if the user
+ * states the device
+ * name and unit number
+ * separately.
+ */
+ char given_dev_name[DEV_IDLEN+1];/*
+ * Device name given by
+ * the user.
+ */
+ u_int32_t given_unit_number; /*
+ * Unit number given by
+ * the user.
+ */
+ char device_name[DEV_IDLEN+1];/*
+ * Name of the device,
+ * e.g. 'pass'
+ */
+ u_int32_t dev_unit_num; /* Unit number of the passthrough
+ * device associated with this
+ * particular device.
+ */
+
+ char sim_name[SIM_IDLEN+1];/*
+ * Controller name, e.g.'ahc'
+ */
+ u_int32_t sim_unit_number; /* Controller unit number */
+ u_int32_t bus_id; /* Controller bus number */
+ lun_id_t target_lun; /* Logical Unit Number */
+ target_id_t target_id; /* Target ID */
+ path_id_t path_id; /* System SCSI bus number */
+ u_int16_t pd_type; /* type of peripheral device */
+ struct scsi_inquiry_data inq_data; /* SCSI Inquiry data */
+ u_int8_t serial_num[252]; /* device serial number */
+ u_int8_t serial_num_len; /* length of the serial number */
+ u_int8_t sync_period; /* Negotiated sync period */
+ u_int8_t sync_offset; /* Negotiated sync offset */
+ u_int8_t bus_width; /* Negotiated bus width */
+ int fd; /* file descriptor for device */
+};
+.Ed
+.Pp
+.Fn cam_open_device
+takes as arguments a string describing the device it is to open, and
+.Ar flags
+suitable for passing to
+.Xr open 2 .
+The "path" passed in may actually be most any type of string that contains
+a device name and unit number to be opened.
+The string will be parsed by
+.Fn cam_get_device
+into a device name and unit number.
+Once the device name and unit number
+are determined, a lookup is performed to determine the passthrough device
+that corresponds to the given device.
+.Fn cam_open_device
+is rather simple to use, but it is not really suitable for general use
+because its behavior is not necessarily deterministic.
+Programmers writing
+new applications should make the extra effort to use one of the other open
+routines documented below.
+.Pp
+.Fn cam_open_spec_device
+opens the
+.Xr pass 4
+device that corresponds to the device name and unit number passed in.
+The
+.Ar flags
+should be flags suitable for passing to
+.Xr open 2 .
+The
+.Ar device
+argument is optional.
+The user may supply pre-allocated space for the
+.Va cam_device
+structure.
+If the
+.Ar device
+argument is
+.Va NULL ,
+.Fn cam_open_spec_device
+will allocate space for the
+.Va cam_device
+structure using
+.Xr malloc 3 .
+.Pp
+.Fn cam_open_btl
+is similar to
+.Fn cam_open_spec_device ,
+except that it takes a
+.Tn SCSI
+bus, target and logical unit instead of a device name and unit number as
+arguments.
+The
+.Va path_id
+argument is the CAM equivalent of a
+.Tn SCSI
+bus number.
+It represents the logical bus number in the system.
+The
+.Ar flags
+should be flags suitable for passing to
+.Xr open 2 .
+As with
+.Fn cam_open_spec_device ,
+the
+.Fa device
+argument is optional.
+.Pp
+.Fn cam_open_pass
+takes as an argument the
+.Fa path
+of a
+.Xr pass 4
+device to open.
+No translation or lookup is performed, so the path passed
+in must be that of a CAM
+.Xr pass 4
+device.
+The
+.Fa flags
+should be flags suitable for passing to
+.Xr open 2 .
+The
+.Fa device
+argument, as with
+.Fn cam_open_spec_device
+and
+.Fn cam_open_btl ,
+should be NULL if the user wants the CAM library to allocate space for the
+.Va cam_device
+structure.
+.Fn cam_close_device
+frees the
+.Va cam_device
+structure allocated by one of the above open() calls, and closes the file
+descriptor to the passthrough device.
+This routine should not be called if
+the user allocated space for the
+.Va cam_device
+structure.
+Instead, the user should call
+.Fn cam_close_spec_device .
+.Pp
+.Fn cam_close_spec_device
+merely closes the file descriptor opened in one of the open() routines
+described above.
+This function should be called when the
+.Va cam_device
+structure was allocated by the caller, rather than the CAM library.
+.Pp
+.Fn cam_getccb
+allocates a CCB
+using
+.Xr malloc 3
+and sets fields in the CCB header using values from the
+.Va cam_device
+structure.
+.Pp
+.Fn cam_send_ccb
+sends the given
+.Va ccb
+to the
+.Fa device
+described in the
+.Va cam_device
+structure.
+.Pp
+.Fn cam_freeccb
+frees CCBs allocated by
+.Fn cam_getccb .
+.Pp
+.Fn cam_path_string
+takes as arguments a
+.Va cam_device
+structure, and a string with length
+.Fa len .
+It creates a colon-terminated printing prefix string similar to the ones
+used by the kernel.
+e.g.: "(cd0:ahc1:0:4:0): ".
+.Fn cam_path_string
+will place at most
+.Fa len Ns \-1
+characters into
+.Ar str .
+The
+.Ar len Ns 'th
+character will be the terminating
+.Ql \e0 .
+.Pp
+.Fn cam_device_dup
+operates in a fashion similar to
+.Xr strdup 3 .
+It allocates space for a
+.Va cam_device
+structure and copies the contents of the passed-in
+.Fa device
+structure to the newly allocated structure.
+.Pp
+.Fn cam_device_copy
+copies the
+.Fa src
+structure to
+.Fa dst .
+.Pp
+.Fn cam_get_device
+takes a
+.Fa path
+argument containing a string with a device name followed by a unit number.
+It then breaks the string down into a device name and unit number, and
+passes them back in
+.Fa dev_name
+and
+.Fa unit ,
+respectively.
+.Fn cam_get_device
+can handle strings of the following forms, at least:
+.Pp
+.Bl -tag -width 1234 -compact
+.It /dev/foo0a
+.It /dev/foo1s2c
+.It foo0
+.It foo0a
+.It nfoo0
+.El
+.Pp
+.Fn cam_get_device
+is provided as a convenience function for applications that need to provide
+functionality similar to
+.Fn cam_open_device .
+Programmers are encouraged to use more deterministic methods of obtaining
+device names and unit numbers if possible.
+.Sh RETURN VALUES
+.Fn cam_open_device ,
+.Fn cam_open_spec_device ,
+.Fn cam_open_btl ,
+and
+.Fn cam_open_pass
+return a pointer to a
+.Va cam_device
+structure, or NULL if there was an error.
+.Pp
+.Fn cam_getccb
+returns an allocated and partially initialized CCB, or NULL if allocation
+of the CCB failed.
+.Pp
+.Fn cam_send_ccb
+returns a value of -1 if an error occured, and
+.Va errno
+is set to indicate the error.
+.Pp
+.Fn cam_path_string
+returns a filled printing prefix string as a convenience.
+This is the same
+.Fa str
+that is passed into
+.Fn cam_path_string .
+.Pp
+.Fn cam_device_dup
+returns a copy of the
+.Va device
+passed in, or NULL if an error occurred.
+.Pp
+.Fn cam_get_device
+returns 0 for success, and -1 to indicate failure.
+.Pp
+If an error is returned from one of the base CAM library functions
+described here, the reason for the error is generally printed in the global
+string
+.Va cam_errbuf
+which is
+.Dv CAM_ERRBUF_SIZE
+characters long.
+.Sh SEE ALSO
+.Xr cam_cdbparse 3 ,
+.Xr pass 4 ,
+.Xr camcontrol 8
+.Sh HISTORY
+The CAM library first appeared in
+.Fx 3.0 .
+.Sh AUTHORS
+.An Kenneth Merry Aq ken@FreeBSD.org
+.Sh BUGS
+.Fn cam_open_device
+does not check to see if the
+.Fa path
+passed in is a symlink to something.
+It also does not check to see if the
+.Fa path
+passed in is an actual
+.Xr pass 4
+device.
+The former would be rather easy to implement, but the latter would
+require a definitive way to identify a device node as a
+.Xr pass 4
+device.
+.Pp
+Some of the functions are possibly mis-named or poorly named.
diff --git a/lib/libcam/cam_cdbparse.3 b/lib/libcam/cam_cdbparse.3
new file mode 100644
index 0000000..891652d
--- /dev/null
+++ b/lib/libcam/cam_cdbparse.3
@@ -0,0 +1,568 @@
+.\"
+.\" Copyright (c) 1998 Kenneth D. Merry.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce 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$
+.\"
+.\" This man page borrows heavily from the old scsi(3) man page, which had
+.\" the following copyright:
+.\"
+.\" Copyright (c) 1994 HD Associates (hd@world.std.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. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by HD Associates
+.\" 4. Neither the name of the HD Associates nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY HD ASSOCIATES``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL HD ASSOCIATES OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 October 13, 1998
+.Os
+.Dt CAM_CDBPARSE 3
+.Sh NAME
+.Nm csio_build ,
+.Nm csio_build_visit ,
+.Nm csio_decode ,
+.Nm csio_decode_visit ,
+.Nm buff_decode ,
+.Nm buff_decode_visit ,
+.Nm csio_encode ,
+.Nm csio_encode_visit ,
+.Nm buff_encode_visit
+.Nd CAM user library SCSI buffer parsing routines
+.Sh LIBRARY
+.Lb libcam
+.Sh SYNOPSIS
+.In stdio.h
+.In camlib.h
+.Ft int
+.Fo csio_build
+.Fa "struct ccb_scsiio *csio"
+.Fa "u_int8_t *data_ptr"
+.Fa "u_int32_t dxfer_len"
+.Fa "u_int32_t flags"
+.Fa "int retry_count"
+.Fa "int timeout"
+.Fa "const char *cmd_spec"
+.Fa "..."
+.Fc
+.Ft int
+.Fo csio_build_visit
+.Fa "struct ccb_scsiio *csio"
+.Fa "u_int8_t *data_ptr"
+.Fa "u_int32_t dxfer_len"
+.Fa "u_int32_t flags"
+.Fa "int retry_count"
+.Fa "int timeout"
+.Fa "const char *cmd_spec"
+.Fa "int (*arg_get)(void *hook, char *field_name)"
+.Fa "void *gethook"
+.Fc
+.Ft int
+.Fo csio_decode
+.Fa "struct ccb_scsiio *csio"
+.Fa "const char *fmt"
+.Fa "..."
+.Fc
+.Ft int
+.Fo csio_decode_visit
+.Fa "struct ccb_scsiio *csio"
+.Fa "const char *fmt"
+.Fa "void (*arg_put)(void *hook"
+.Fa "int letter"
+.Fa "void *val"
+.Fa "int count"
+.Fa "char *name)"
+.Fa "void *puthook"
+.Fc
+.Ft int
+.Fo buff_decode
+.Fa "u_int8_t *buff"
+.Fa "size_t len"
+.Fa "const char *fmt"
+.Fa "..."
+.Fc
+.Ft int
+.Fo buff_decode_visit
+.Fa "u_int8_t *buff"
+.Fa "size_t len"
+.Fa "const char *fmt"
+.Fa "void (*arg_put)(void *, int, void *, int, char *)"
+.Fa "void *puthook"
+.Fc
+.Ft int
+.Fo csio_encode
+.Fa "struct ccb_scsiio *csio"
+.Fa "const char *fmt"
+.Fa "..."
+.Fc
+.Ft int
+.Fo csio_encode_visit
+.Fa "struct ccb_scsiio *csio"
+.Fa "const char *fmt"
+.Fa "int (*arg_get)(void *hook, char *field_name)"
+.Fa "void *gethook"
+.Fc
+.Ft int
+.Fo buff_encode_visit
+.Fa "u_int8_t *buff"
+.Fa "size_t len"
+.Fa "const char *fmt"
+.Fa "int (*arg_get)(void *hook, char *field_name)"
+.Fa "void *gethook"
+.Fc
+.Sh DESCRIPTION
+The CAM buffer/CDB encoding and decoding routines provide a relatively easy
+migration path for userland
+.Tn SCSI
+applications written with the similarly-named
+.Va scsireq_ Ns *
+functions from the old
+.Fx
+.Tn SCSI
+layer.
+.Pp
+These functions may be used in new applications, but users may find it
+easier to use the various SCSI CCB building functions included with the
+.Xr cam 3
+library.
+(e.g.\&
+.Fn cam_fill_csio ,
+.Fn scsi_start_stop ,
+and
+.Fn scsi_read_write )
+.Pp
+.Fn csio_build
+builds up a
+.Va ccb_scsiio
+structure based on the information provided in
+the variable argument list.
+It gracefully handles a NULL
+.Fa data_ptr
+argument passed to it.
+.Pp
+.Fa dxfer_len
+is the length of the data phase; the data transfer direction is
+determined by the
+.Fa flags
+argument.
+.Pp
+.Fa data_ptr
+is the data buffer used during the
+.Tn SCSI
+data phase.
+If no data is to be
+transferred for the
+.Tn SCSI
+command in question, this should be set to NULL.
+If there is data to
+transfer for the command, this buffer must be at least
+.Fa dxfer_len
+long.
+.Pp
+.Fa flags
+are the flags defined in
+.In cam/cam_ccb.h :
+.Bd -literal
+/* Common CCB header */
+/* CAM CCB flags */
+typedef enum {
+ CAM_CDB_POINTER = 0x00000001,/* The CDB field is a pointer */
+ CAM_QUEUE_ENABLE = 0x00000002,/* SIM queue actions are enabled */
+ CAM_CDB_LINKED = 0x00000004,/* CCB contains a linked CDB */
+ CAM_SCATTER_VALID = 0x00000010,/* Scatter/gather list is valid */
+ CAM_DIS_AUTOSENSE = 0x00000020,/* Disable autosense feature */
+ CAM_DIR_RESV = 0x00000000,/* Data direction (00:reserved) */
+ CAM_DIR_IN = 0x00000040,/* Data direction (01:DATA IN) */
+ CAM_DIR_OUT = 0x00000080,/* Data direction (10:DATA OUT) */
+ CAM_DIR_NONE = 0x000000C0,/* Data direction (11:no data) */
+ CAM_DIR_MASK = 0x000000C0,/* Data direction Mask */
+ CAM_SOFT_RST_OP = 0x00000100,/* Use Soft reset alternative */
+ CAM_ENG_SYNC = 0x00000200,/* Flush resid bytes on complete */
+ CAM_DEV_QFRZDIS = 0x00000400,/* Disable DEV Q freezing */
+ CAM_DEV_QFREEZE = 0x00000800,/* Freeze DEV Q on execution */
+ CAM_HIGH_POWER = 0x00001000,/* Command takes a lot of power */
+ CAM_SENSE_PTR = 0x00002000,/* Sense data is a pointer */
+ CAM_SENSE_PHYS = 0x00004000,/* Sense pointer is physical addr*/
+ CAM_TAG_ACTION_VALID = 0x00008000,/* Use the tag action in this ccb*/
+ CAM_PASS_ERR_RECOVER = 0x00010000,/* Pass driver does err. recovery*/
+ CAM_DIS_DISCONNECT = 0x00020000,/* Disable disconnect */
+ CAM_SG_LIST_PHYS = 0x00040000,/* SG list has physical addrs. */
+ CAM_MSG_BUF_PHYS = 0x00080000,/* Message buffer ptr is physical*/
+ CAM_SNS_BUF_PHYS = 0x00100000,/* Autosense data ptr is physical*/
+ CAM_DATA_PHYS = 0x00200000,/* SG/Buffer data ptrs are phys. */
+ CAM_CDB_PHYS = 0x00400000,/* CDB pointer is physical */
+ CAM_ENG_SGLIST = 0x00800000,/* SG list is for the HBA engine */
+
+/* Phase cognizant mode flags */
+ CAM_DIS_AUTOSRP = 0x01000000,/* Disable autosave/restore ptrs */
+ CAM_DIS_AUTODISC = 0x02000000,/* Disable auto disconnect */
+ CAM_TGT_CCB_AVAIL = 0x04000000,/* Target CCB available */
+ CAM_TGT_PHASE_MODE = 0x08000000,/* The SIM runs in phase mode */
+ CAM_MSGB_VALID = 0x20000000,/* Message buffer valid */
+ CAM_STATUS_VALID = 0x40000000,/* Status buffer valid */
+ CAM_DATAB_VALID = 0x80000000,/* Data buffer valid */
+
+/* Host target Mode flags */
+ CAM_TERM_IO = 0x20000000,/* Terminate I/O Message sup. */
+ CAM_DISCONNECT = 0x40000000,/* Disconnects are mandatory */
+ CAM_SEND_STATUS = 0x80000000,/* Send status after data phase */
+} ccb_flags;
+.Ed
+.Pp
+Multiple flags should be ORed together.
+Any of the CCB flags may be used,
+although it is worth noting several important ones here:
+.Pp
+.Bl -tag -width CAM_PASS_ERR_RECOVER
+.It Dv CAM_DIR_IN
+This indicates that the operation in question is a read operation.
+i.e.,
+data is being read from the
+.Tn SCSI
+device to the user-supplied buffer.
+.It Dv CAM_DIR_OUT
+This indicates that the operation is a write operation.
+i.e., data is being
+written from the user-supplied buffer to the device.
+.It Dv CAM_DIR_NONE
+This indicates that there is no data to be transferred for this command.
+.It Dv CAM_DEV_QFRZDIS
+This flag disables device queue freezing as an error recovery mechanism.
+.It Dv CAM_PASS_ERR_RECOVER
+This flag tells the
+.Xr pass 4
+driver to enable error recovery.
+The default is to not perform error
+recovery, which means that the retry count will not be honored without this
+flag, among other things.
+.It Dv CAM_DATA_PHYS
+This indicates that the address contained in
+.Fa data_ptr
+is a physical address, not a virtual address.
+.El
+.Pp
+The
+.Fa retry_count
+tells the kernel how many times to retry the command in question.
+The
+retry count is ignored unless the
+.Xr pass 4
+driver is told to enable error recovery via the
+.Dv CAM_PASS_ERR_RECOVER
+flag.
+.Pp
+The
+.Fa timeout
+tells the kernel how long to wait for the given command to complete.
+If
+the timeout expires and the command has not completed, the CCB will be
+returned from the kernel with an appropriate error status.
+.Pp
+.Fa cmd_spec
+is a CDB format specifier used to build up the SCSI CDB.
+This text string is made up of a list of field specifiers.
+Field
+specifiers specify the value for each CDB field (including indicating
+that the value be taken from the next argument in the
+variable argument list), the width
+of the field in bits or bytes, and an optional name.
+White space is
+ignored, and the pound sign ('#') introduces a comment that ends at the
+end of the current line.
+.Pp
+The optional name is the first part of a field specifier and
+is in curly braces.
+The text in curly braces in this example are
+the names:
+.Dl "{PS} v:b1 {Reserved} 0:b1 {Page Code} v:b6 # Mode select page"
+.Pp
+This field specifier has two one bit fields and one six bit field.
+The second one bit field is the constant value 0 and the first
+one bit field and the six bit field are taken from the variable
+argument list.
+Multi byte fields are swapped into the SCSI byte order in the
+CDB and white space is ignored.
+.Pp
+When the field is a hex value or the letter v, (e.g.,
+.Fa "1A"
+or
+.Fa "v" )
+then a single byte value
+is copied to the next unused byte of the CDB.
+When the letter
+.Fa v
+is used the next integer argument is taken from the variable argument list
+and that value used.
+.Pp
+A constant hex value followed by a field width specifier or the letter
+.Fa v
+followed by a field width specifier (e.g.,
+.Fa 3:4 ,
+.Fa 3:b4 ,
+.Fa 3:i3 ,
+.Fa v:i3 )
+specifies a field of a given bit or byte width.
+Either the constant value or (for the V specifier) the next integer value from
+the variable argument list is copied to the next unused
+bits or bytes of the CDB.
+.Pp
+A decimal number or the letter
+.Fa b
+followed by a decimal number field width indicates a bit field of that width.
+The bit fields are packed as tightly as possible beginning with the
+high bit (so that it reads the same as the SCSI spec), and a new byte of
+the CDB is started whenever a byte fills completely or when an
+.Fa i
+field is encountered.
+.Pp
+A field width specifier consisting of the letter
+.Fa i
+followed by either
+1, 2, 3 or 4 indicates a 1, 2, 3 or 4 byte integral value that must
+be swapped into SCSI byte order (MSB first).
+.Pp
+For the
+.Fa v
+field specifier the next integer argument is taken from the variable argument
+list and that value is used swapped into SCSI byte order.
+.Pp
+.Fn csio_build_visit
+operates similarly to
+.Fn csio_build ,
+except that the values to substitute for variable arguments in
+.Fa cmd_spec
+are retrieved via the
+.Fn arg_get
+function passed in to
+.Fn csio_build_visit
+instead of via
+.Xr stdarg 3 .
+The
+.Fn arg_get
+function takes two arguments:
+.Bl -tag -width field_name
+.It Fa gethook
+is passed into the
+.Fn arg_get
+function at each invocation.
+This enables the
+.Fn arg_get
+function to keep some state in between calls without using global or static
+variables.
+.It Fa field_name
+is the field name supplied in
+.Fa fmt ,
+if any.
+.El
+.Pp
+.Fn csio_decode
+is used to decode information from the data in phase of the SCSI
+transfer.
+.Pp
+The decoding is similar to
+the command specifier processing of
+.Fn csio_build
+except that the data is extracted from the data pointed to by
+.Fa csio->data_ptr .
+The stdarg list should be pointers to integers instead of integer
+values.
+A seek field type and a suppression modifier are added.
+The
+.Fa *
+suppression modifier (e.g.,
+.Fa *i3
+or
+.Fa *b4 )
+suppresses assignment from the field and can be used to skip
+over bytes or bits in the data, without having to copy
+them to a dummy variable in the arg list.
+.Pp
+The seek field type
+.Fa s
+permits you to skip over data.
+This seeks to an absolute position
+.Pq Fa s3
+or a relative position
+.Pq Fa s+3
+in the data, based on whether or not the presence of the '+' sign.
+The seek value can be specified as
+.Fa v
+and the next integer value from the argument list will be
+used as the seek value.
+.Pp
+.Fn csio_decode_visit
+operates like
+.Fn csio_decode
+except that instead of placing the decoded contents of the buffer in
+variadic arguments, the decoded buffer contents are returned to the user
+via the
+.Fn arg_put
+function that is passed in.
+The
+.Fn arg_put
+function takes several arguments:
+.Bl -tag -width letter
+.It Fa hook
+The "hook" is a mechanism to allow the
+.Fn arg_put
+function to save state in between calls.
+.It Fa letter
+is the letter describing the format of the argument being passed into the
+function.
+.It Fa val
+is a void pointer to the value being passed into the function.
+.It Fa count
+is the size of the value being passed into the
+.Fn arg_put
+function.
+The argument format determines the unit of measure.
+.It Fa name
+This is a text description of the field, if one was provided in the
+.Fa fmt .
+.El
+.Pp
+.Fn buff_decode
+decodes an arbitrary data buffer using the method
+described above for
+.Fn csio_decode .
+.Pp
+.Fn buff_decode_visit
+decodes an arbitrary data buffer using the method described above for
+.Fn csio_decode_visit .
+.Pp
+.Fn csio_encode
+encodes the
+.Fa data_ptr
+portion (not the CDB!) of a
+.Va ccb_scsiio
+structure, using the method described above for
+.Fn csio_build .
+.Pp
+.Fn csio_encode_visit
+encodes the
+.Fa data_ptr
+portion (not the CDB!) of a
+.Va ccb_scsiio
+structure, using the method described above for
+.Fn csio_build_visit .
+.Pp
+.Fn buff_encode_visit
+encodes an arbitrary data pointer, using the method described
+above for
+.Fn csio_build_visit .
+.Sh RETURN VALUES
+.Fn csio_build ,
+.Fn csio_build_visit ,
+.Fn csio_encode ,
+.Fn csio_encode_visit ,
+and
+.Fn buff_encode_visit
+return the number of fields processed.
+.Pp
+.Fn csio_decode ,
+.Fn csio_decode_visit ,
+.Fn buff_decode ,
+and
+.Fn buff_decode_visit
+return the number of assignments performed.
+.Sh SEE ALSO
+.Xr cam 3 ,
+.Xr pass 4 ,
+.Xr camcontrol 8
+.Sh HISTORY
+The CAM versions of these functions are based upon similar functions
+implemented for the old
+.Fx
+.Tn SCSI
+layer.
+The encoding/decoding functions in the old
+.Tn SCSI
+code were written by Peter Dufault.
+.Pp
+Many systems have comparable interfaces to permit a user to construct a
+SCSI command in user space.
+.Pp
+The old
+.Va scsireq
+data structure was almost identical to the SGI /dev/scsi data
+structure.
+If anyone knows the name of the authors it should
+go here; Peter Dufault first read about it in a 1989 Sun Expert magazine.
+.Pp
+The new CCB data structures are derived from the CAM-2 and CAM-3
+specifications.
+.Pp
+.An Peter Dufault
+implemented a clone of SGI's interface in
+.Bx 386
+that
+led to the original
+.Fx
+.Tn SCSI
+library and the related kernel ioctl.
+If anyone needs that for compatibility contact dufault@hda.com.
+.Sh AUTHORS
+Kenneth Merry implemented the CAM versions of these encoding and decoding
+functions.
+This current work is based upon earlier work by Peter Dufault.
+.Sh BUGS
+There should probably be a function that encodes both the CDB and the data
+buffer portions of a
+.Tn SCSI
+CCB.
+I discovered this while implementing the arbitrary command execution
+code in
+.Xr camcontrol 8 ,
+but I have not yet had time to implement such a function.
+.Pp
+Some of the CCB flag descriptions really do not belong here.
+Rather they
+belong in a generic CCB man page.
+Since that man page has not yet been
+written, the shorter descriptions here will have to suffice.
diff --git a/lib/libcam/camlib.c b/lib/libcam/camlib.c
new file mode 100644
index 0000000..b252371
--- /dev/null
+++ b/lib/libcam/camlib.c
@@ -0,0 +1,792 @@
+/*
+ * Copyright (c) 1997, 1998, 1999, 2002 Kenneth D. Merry.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 <sys/types.h>
+#include <sys/param.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include <cam/cam.h>
+#include <cam/scsi/scsi_all.h>
+#include <cam/cam_ccb.h>
+#include <cam/scsi/scsi_pass.h>
+#include "camlib.h"
+
+struct cam_devequiv {
+ char *given_dev;
+ char *real_dev;
+};
+
+struct cam_devequiv devmatchtable[] = {
+ {"sd", "da"},
+ {"st", "sa"}
+};
+
+char cam_errbuf[CAM_ERRBUF_SIZE];
+
+static struct cam_device *cam_real_open_device(const char *path, int flags,
+ struct cam_device *device,
+ const char *given_path,
+ const char *given_dev_name,
+ int given_unit_number);
+static struct cam_device *cam_lookup_pass(const char *dev_name, int unit,
+ int flags, const char *given_path,
+ struct cam_device *device);
+
+/*
+ * Send a ccb to a passthrough device.
+ */
+int
+cam_send_ccb(struct cam_device *device, union ccb *ccb)
+{
+ return(ioctl(device->fd, CAMIOCOMMAND, ccb));
+}
+
+/*
+ * Malloc a CCB, zero out the header and set its path, target and lun ids.
+ */
+union ccb *
+cam_getccb(struct cam_device *dev)
+{
+ union ccb *ccb;
+
+ ccb = (union ccb *)malloc(sizeof(union ccb));
+ if (ccb != NULL) {
+ bzero(&ccb->ccb_h, sizeof(struct ccb_hdr));
+ ccb->ccb_h.path_id = dev->path_id;
+ ccb->ccb_h.target_id = dev->target_id;
+ ccb->ccb_h.target_lun = dev->target_lun;
+ }
+
+ return(ccb);
+}
+
+/*
+ * Free a CCB.
+ */
+void
+cam_freeccb(union ccb *ccb)
+{
+ free(ccb);
+}
+
+/*
+ * Take a device name or path passed in by the user, and attempt to figure
+ * out the device name and unit number. Some possible device name formats are:
+ * /dev/foo0a
+ * /dev/rfoo0a
+ * /dev/rfoos2c
+ * foo0
+ * foo0a
+ * rfoo0
+ * rfoo0a
+ * nrfoo0
+ *
+ * If the caller passes in an old style device name like 'sd' or 'st',
+ * it will be converted to the new style device name based upon devmatchtable
+ * above.
+ *
+ * Input parameters: device name/path, length of devname string
+ * Output: device name, unit number
+ * Return values: returns 0 for success, -1 for failure
+ */
+int
+cam_get_device(const char *path, char *dev_name, int devnamelen, int *unit)
+{
+ char *func_name = "cam_get_device";
+ char *tmpstr, *tmpstr2;
+ char *newpath;
+ int unit_offset;
+ int i, found = 0;
+
+
+ if (path == NULL) {
+ sprintf(cam_errbuf, "%s: device pathname was NULL", func_name);
+ return(-1);
+ }
+
+ /*
+ * We can be rather destructive to the path string. Make a copy of
+ * it so we don't hose the user's string.
+ */
+ newpath = (char *)strdup(path);
+ tmpstr = newpath;
+
+ /* Get rid of any leading white space */
+ while (isspace(*tmpstr) && (*tmpstr != '\0'))
+ tmpstr++;
+
+ /*
+ * Check to see whether we have an absolute pathname.
+ */
+ if (*tmpstr == '/') {
+ tmpstr2 = tmpstr;
+ tmpstr = (char *)rindex(tmpstr2, '/');
+ if ((tmpstr != NULL) && (*tmpstr != '\0'))
+ tmpstr++;
+ }
+
+ if (*tmpstr == '\0') {
+ sprintf(cam_errbuf, "%s: no text after slash", func_name);
+ free(newpath);
+ return(-1);
+ }
+
+ /*
+ * Check to see whether the user has given us a nonrewound tape
+ * device.
+ */
+ if (*tmpstr == 'n')
+ tmpstr++;
+
+ if (*tmpstr == '\0') {
+ sprintf(cam_errbuf, "%s: no text after leading 'n'", func_name);
+ free(newpath);
+ return(-1);
+ }
+
+ /*
+ * See if the user has given us a character device.
+ */
+ if (*tmpstr == 'r')
+ tmpstr++;
+
+ if (*tmpstr == '\0') {
+ sprintf(cam_errbuf, "%s: no text after leading 'r'", func_name);
+ free(newpath);
+ return(-1);
+ }
+
+ /*
+ * Try to get rid of any trailing white space or partition letters.
+ */
+ tmpstr2 = &tmpstr[strlen(tmpstr) - 1];
+
+ while ((*tmpstr2 != '\0') && (tmpstr2 > tmpstr) &&(!isdigit(*tmpstr2))){
+ *tmpstr2 = '\0';
+ tmpstr2--;
+ }
+
+ /*
+ * Check to see whether we have been given a partition with a slice
+ * name. If so, get rid of the slice name/number.
+ */
+ if (strlen(tmpstr) > 3) {
+ /*
+ * Basically, we're looking for a string that ends in the
+ * following general manner: 1s1 -- a number, the letter
+ * s, and then another number. This indicates that the
+ * user has given us a slice. We substitute nulls for the
+ * s and the slice number.
+ */
+ if ((isdigit(tmpstr[strlen(tmpstr) - 1]))
+ && (tmpstr[strlen(tmpstr) - 2] == 's')
+ && (isdigit(tmpstr[strlen(tmpstr) - 3]))) {
+ tmpstr[strlen(tmpstr) - 1] = '\0';
+ tmpstr[strlen(tmpstr) - 1] = '\0';
+ }
+ }
+
+ /*
+ * After we nuke off the slice, we should have just a device name
+ * and unit number. That means there must be at least 2
+ * characters. If we only have 1, we don't have a valid device name.
+ */
+ if (strlen(tmpstr) < 2) {
+ sprintf(cam_errbuf,
+ "%s: must have both device name and unit number",
+ func_name);
+ free(newpath);
+ return(-1);
+ }
+
+ /*
+ * If the first character of the string is a digit, then the user
+ * has probably given us all numbers. Point out the error.
+ */
+ if (isdigit(*tmpstr)) {
+ sprintf(cam_errbuf,
+ "%s: device name cannot begin with a number",
+ func_name);
+ free(newpath);
+ return(-1);
+ }
+
+ /*
+ * At this point, if the last character of the string isn't a
+ * number, we know the user either didn't give us a device number,
+ * or he gave us a device name/number format we don't recognize.
+ */
+ if (!isdigit(tmpstr[strlen(tmpstr) - 1])) {
+ sprintf(cam_errbuf, "%s: unable to find device unit number",
+ func_name);
+ free(newpath);
+ return(-1);
+ }
+
+ /*
+ * Attempt to figure out where the device name ends and the unit
+ * number begins. As long as unit_offset is at least 1 less than
+ * the length of the string, we can still potentially have a device
+ * name at the front of the string. When we get to something that
+ * isn't a digit, we've hit the device name. Because of the check
+ * above, we know that this cannot happen when unit_offset == 1.
+ * Therefore it is okay to decrement unit_offset -- it won't cause
+ * us to go past the end of the character array.
+ */
+ for (unit_offset = 1;
+ (unit_offset < (strlen(tmpstr)))
+ && (isdigit(tmpstr[strlen(tmpstr) - unit_offset])); unit_offset++);
+
+ unit_offset--;
+
+ /*
+ * Grab the unit number.
+ */
+ *unit = atoi(&tmpstr[strlen(tmpstr) - unit_offset]);
+
+ /*
+ * Put a null in place of the first number of the unit number so
+ * that all we have left is the device name.
+ */
+ tmpstr[strlen(tmpstr) - unit_offset] = '\0';
+
+ /*
+ * Look through our equivalency table and see if the device name
+ * the user gave us is an old style device name. If so, translate
+ * it to the new style device name.
+ */
+ for (i = 0;i < (sizeof(devmatchtable)/sizeof(struct cam_devequiv));i++){
+ if (strcmp(tmpstr, devmatchtable[i].given_dev) == 0) {
+ strlcpy(dev_name,devmatchtable[i].real_dev, devnamelen);
+ found = 1;
+ break;
+ }
+ }
+ if (found == 0)
+ strlcpy(dev_name, tmpstr, devnamelen);
+
+ /* Clean up allocated memory */
+ free(newpath);
+
+ return(0);
+
+}
+
+/*
+ * Backwards compatible wrapper for the real open routine. This translates
+ * a pathname into a device name and unit number for use with the real open
+ * routine.
+ */
+struct cam_device *
+cam_open_device(const char *path, int flags)
+{
+ int unit;
+ char dev_name[DEV_IDLEN + 1];
+
+ /*
+ * cam_get_device() has already put an error message in cam_errbuf,
+ * so we don't need to.
+ */
+ if (cam_get_device(path, dev_name, sizeof(dev_name), &unit) == -1)
+ return(NULL);
+
+ return(cam_lookup_pass(dev_name, unit, flags, path, NULL));
+}
+
+/*
+ * Open the passthrough device for a given bus, target and lun, if the
+ * passthrough device exists.
+ */
+struct cam_device *
+cam_open_btl(path_id_t path_id, target_id_t target_id, lun_id_t target_lun,
+ int flags, struct cam_device *device)
+{
+ union ccb ccb;
+ struct periph_match_pattern *match_pat;
+ char *func_name = "cam_open_btl";
+ int fd, bufsize;
+
+ if ((fd = open(XPT_DEVICE, O_RDWR)) < 0) {
+ snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
+ "%s: couldn't open %s\n%s: %s", func_name, XPT_DEVICE,
+ func_name, strerror(errno));
+ return(NULL);
+ }
+
+ bzero(&ccb, sizeof(union ccb));
+ ccb.ccb_h.func_code = XPT_DEV_MATCH;
+
+ /* Setup the result buffer */
+ bufsize = sizeof(struct dev_match_result);
+ ccb.cdm.match_buf_len = bufsize;
+ ccb.cdm.matches = (struct dev_match_result *)malloc(bufsize);
+ if (ccb.cdm.matches == NULL) {
+ snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
+ "%s: couldn't malloc match buffer", func_name);
+ close(fd);
+ return(NULL);
+ }
+ ccb.cdm.num_matches = 0;
+
+ /* Setup the pattern buffer */
+ ccb.cdm.num_patterns = 1;
+ ccb.cdm.pattern_buf_len = sizeof(struct dev_match_pattern);
+ ccb.cdm.patterns = (struct dev_match_pattern *)malloc(
+ sizeof(struct dev_match_pattern));
+ if (ccb.cdm.patterns == NULL) {
+ snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
+ "%s: couldn't malloc pattern buffer", func_name);
+ free(ccb.cdm.matches);
+ close(fd);
+ return(NULL);
+ }
+ ccb.cdm.patterns[0].type = DEV_MATCH_PERIPH;
+ match_pat = &ccb.cdm.patterns[0].pattern.periph_pattern;
+
+ /*
+ * We're looking for the passthrough device associated with this
+ * particular bus/target/lun.
+ */
+ sprintf(match_pat->periph_name, "pass");
+ match_pat->path_id = path_id;
+ match_pat->target_id = target_id;
+ match_pat->target_lun = target_lun;
+ /* Now set the flags to indicate what we're looking for. */
+ match_pat->flags = PERIPH_MATCH_PATH | PERIPH_MATCH_TARGET |
+ PERIPH_MATCH_LUN | PERIPH_MATCH_NAME;
+
+ if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
+ sprintf(cam_errbuf, "%s: CAMIOCOMMAND ioctl failed\n"
+ "%s: %s", func_name, func_name, strerror(errno));
+ goto btl_bailout;
+ }
+
+ /*
+ * Check for an outright error.
+ */
+ if ((ccb.ccb_h.status != CAM_REQ_CMP)
+ || ((ccb.cdm.status != CAM_DEV_MATCH_LAST)
+ && (ccb.cdm.status != CAM_DEV_MATCH_MORE))) {
+ sprintf(cam_errbuf, "%s: CAM error %#x, CDM error %d "
+ "returned from XPT_DEV_MATCH ccb", func_name,
+ ccb.ccb_h.status, ccb.cdm.status);
+ goto btl_bailout;
+ }
+
+ if (ccb.cdm.status == CAM_DEV_MATCH_MORE) {
+ sprintf(cam_errbuf, "%s: CDM reported more than one"
+ " passthrough device at %d:%d:%d!!\n",
+ func_name, path_id, target_id, target_lun);
+ goto btl_bailout;
+ }
+
+ if (ccb.cdm.num_matches == 0) {
+ sprintf(cam_errbuf, "%s: no passthrough device found at"
+ " %d:%d:%d", func_name, path_id, target_id,
+ target_lun);
+ goto btl_bailout;
+ }
+
+ switch(ccb.cdm.matches[0].type) {
+ case DEV_MATCH_PERIPH: {
+ int pass_unit;
+ char dev_path[256];
+ struct periph_match_result *periph_result;
+
+ periph_result = &ccb.cdm.matches[0].result.periph_result;
+ pass_unit = periph_result->unit_number;
+ free(ccb.cdm.matches);
+ free(ccb.cdm.patterns);
+ close(fd);
+ sprintf(dev_path, "/dev/pass%d", pass_unit);
+ return(cam_real_open_device(dev_path, flags, device, NULL,
+ NULL, 0));
+ break; /* NOTREACHED */
+ }
+ default:
+ sprintf(cam_errbuf, "%s: asked for a peripheral match, but"
+ " got a bus or device match", func_name);
+ goto btl_bailout;
+ break; /* NOTREACHED */
+ }
+
+btl_bailout:
+ free(ccb.cdm.matches);
+ free(ccb.cdm.patterns);
+ close(fd);
+ return(NULL);
+}
+
+struct cam_device *
+cam_open_spec_device(const char *dev_name, int unit, int flags,
+ struct cam_device *device)
+{
+ return(cam_lookup_pass(dev_name, unit, flags, NULL, device));
+}
+
+struct cam_device *
+cam_open_pass(const char *path, int flags, struct cam_device *device)
+{
+ return(cam_real_open_device(path, flags, device, path, NULL, 0));
+}
+
+static struct cam_device *
+cam_lookup_pass(const char *dev_name, int unit, int flags,
+ const char *given_path, struct cam_device *device)
+{
+ int fd;
+ union ccb ccb;
+ char dev_path[256];
+ char *func_name = "cam_lookup_pass";
+
+ /*
+ * The flags argument above only applies to the actual passthrough
+ * device open, not our open of the given device to find the
+ * passthrough device.
+ */
+ if ((fd = open(XPT_DEVICE, O_RDWR)) < 0) {
+ snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
+ "%s: couldn't open %s\n%s: %s", func_name, XPT_DEVICE,
+ func_name, strerror(errno));
+ return(NULL);
+ }
+
+ /* This isn't strictly necessary for the GETPASSTHRU ioctl. */
+ ccb.ccb_h.func_code = XPT_GDEVLIST;
+
+ /* These two are necessary for the GETPASSTHRU ioctl to work. */
+ strlcpy(ccb.cgdl.periph_name, dev_name, sizeof(ccb.cgdl.periph_name));
+ ccb.cgdl.unit_number = unit;
+
+ /*
+ * Attempt to get the passthrough device. This ioctl will fail if
+ * the device name is null, if the device doesn't exist, or if the
+ * passthrough driver isn't in the kernel.
+ */
+ if (ioctl(fd, CAMGETPASSTHRU, &ccb) == -1) {
+ char tmpstr[256];
+
+ /*
+ * If we get ENOENT from the transport layer version of
+ * the CAMGETPASSTHRU ioctl, it means one of two things:
+ * either the device name/unit number passed in doesn't
+ * exist, or the passthrough driver isn't in the kernel.
+ */
+ if (errno == ENOENT) {
+ snprintf(tmpstr, sizeof(tmpstr),
+ "\n%s: either the pass driver isn't in "
+ "your kernel\n%s: or %s%d doesn't exist",
+ func_name, func_name, dev_name, unit);
+ }
+ snprintf(cam_errbuf, sizeof(cam_errbuf),
+ "%s: CAMGETPASSTHRU ioctl failed\n"
+ "%s: %s%s", func_name, func_name, strerror(errno),
+ (errno == ENOENT) ? tmpstr : "");
+
+ close(fd);
+ return(NULL);
+ }
+
+ close(fd);
+
+ /*
+ * If the ioctl returned the right status, but we got an error back
+ * in the ccb, that means that the kernel found the device the user
+ * passed in, but was unable to find the passthrough device for
+ * the device the user gave us.
+ */
+ if (ccb.cgdl.status == CAM_GDEVLIST_ERROR) {
+ sprintf(cam_errbuf, "%s: device %s%d does not exist!",
+ func_name, dev_name, unit);
+ return(NULL);
+ }
+
+ sprintf(dev_path, "/dev/%s%d", ccb.cgdl.periph_name,
+ ccb.cgdl.unit_number);
+
+ return(cam_real_open_device(dev_path, flags, device, NULL,
+ dev_name, unit));
+}
+
+/*
+ * Open a given device. The path argument isn't strictly necessary, but it
+ * is copied into the cam_device structure as a convenience to the user.
+ */
+static struct cam_device *
+cam_real_open_device(const char *path, int flags, struct cam_device *device,
+ const char *given_path, const char *given_dev_name,
+ int given_unit_number)
+{
+ char *func_name = "cam_real_open_device";
+ union ccb ccb;
+ int fd = -1, malloced_device = 0;
+
+ /*
+ * See if the user wants us to malloc a device for him.
+ */
+ if (device == NULL) {
+ if ((device = (struct cam_device *)malloc(
+ sizeof(struct cam_device))) == NULL) {
+ sprintf(cam_errbuf, "%s: device structure malloc"
+ " failed\n%s: %s", func_name, func_name,
+ strerror(errno));
+ return(NULL);
+ }
+ device->fd = -1;
+ malloced_device = 1;
+ }
+
+ /*
+ * If the user passed in a path, save it for him.
+ */
+ if (given_path != NULL)
+ strlcpy(device->device_path, given_path,
+ sizeof(device->device_path));
+ else
+ device->device_path[0] = '\0';
+
+ /*
+ * If the user passed in a device name and unit number pair, save
+ * those as well.
+ */
+ if (given_dev_name != NULL)
+ strlcpy(device->given_dev_name, given_dev_name,
+ sizeof(device->given_dev_name));
+ else
+ device->given_dev_name[0] = '\0';
+ device->given_unit_number = given_unit_number;
+
+ if ((fd = open(path, flags)) < 0) {
+ snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
+ "%s: couldn't open passthrough device %s\n"
+ "%s: %s", func_name, path, func_name,
+ strerror(errno));
+ goto crod_bailout;
+ }
+
+ device->fd = fd;
+
+ bzero(&ccb, sizeof(union ccb));
+
+ /*
+ * Unlike the transport layer version of the GETPASSTHRU ioctl,
+ * we don't have to set any fields.
+ */
+ ccb.ccb_h.func_code = XPT_GDEVLIST;
+
+ /*
+ * We're only doing this to get some information on the device in
+ * question. Otherwise, we'd have to pass in yet another
+ * parameter: the passthrough driver unit number.
+ */
+ if (ioctl(fd, CAMGETPASSTHRU, &ccb) == -1) {
+ /*
+ * At this point we know the passthrough device must exist
+ * because we just opened it above. The only way this
+ * ioctl can fail is if the ccb size is wrong.
+ */
+ sprintf(cam_errbuf, "%s: CAMGETPASSTHRU ioctl failed\n"
+ "%s: %s", func_name, func_name, strerror(errno));
+ goto crod_bailout;
+ }
+
+ /*
+ * If the ioctl returned the right status, but we got an error back
+ * in the ccb, that means that the kernel found the device the user
+ * passed in, but was unable to find the passthrough device for
+ * the device the user gave us.
+ */
+ if (ccb.cgdl.status == CAM_GDEVLIST_ERROR) {
+ sprintf(cam_errbuf, "%s: passthrough device does not exist!",
+ func_name);
+ goto crod_bailout;
+ }
+
+ device->dev_unit_num = ccb.cgdl.unit_number;
+ strlcpy(device->device_name, ccb.cgdl.periph_name,
+ sizeof(device->device_name));
+ device->path_id = ccb.ccb_h.path_id;
+ device->target_id = ccb.ccb_h.target_id;
+ device->target_lun = ccb.ccb_h.target_lun;
+
+ ccb.ccb_h.func_code = XPT_PATH_INQ;
+ if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
+ sprintf(cam_errbuf, "%s: Path Inquiry CCB failed\n"
+ "%s: %s", func_name, func_name, strerror(errno));
+ goto crod_bailout;
+ }
+ strlcpy(device->sim_name, ccb.cpi.dev_name, sizeof(device->sim_name));
+ device->sim_unit_number = ccb.cpi.unit_number;
+ device->bus_id = ccb.cpi.bus_id;
+
+ /*
+ * It doesn't really matter what is in the payload for a getdev
+ * CCB, the kernel doesn't look at it.
+ */
+ ccb.ccb_h.func_code = XPT_GDEV_TYPE;
+ if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
+ sprintf(cam_errbuf, "%s: Get Device Type CCB failed\n"
+ "%s: %s", func_name, func_name, strerror(errno));
+ goto crod_bailout;
+ }
+ device->pd_type = SID_TYPE(&ccb.cgd.inq_data);
+ bcopy(&ccb.cgd.inq_data, &device->inq_data,
+ sizeof(struct scsi_inquiry_data));
+ device->serial_num_len = ccb.cgd.serial_num_len;
+ bcopy(&ccb.cgd.serial_num, &device->serial_num, device->serial_num_len);
+
+ /*
+ * Zero the payload, the kernel does look at the flags.
+ */
+ bzero(&(&ccb.ccb_h)[1], sizeof(struct ccb_trans_settings));
+
+ /*
+ * Get transfer settings for this device.
+ */
+ ccb.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
+
+ ccb.cts.flags = CCB_TRANS_CURRENT_SETTINGS;
+
+ if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
+ sprintf(cam_errbuf, "%s: Get Transfer Settings CCB failed\n"
+ "%s: %s", func_name, func_name, strerror(errno));
+ goto crod_bailout;
+ }
+ device->sync_period = ccb.cts.sync_period;
+ device->sync_offset = ccb.cts.sync_offset;
+ device->bus_width = ccb.cts.bus_width;
+
+ return(device);
+
+crod_bailout:
+
+ if (fd >= 0)
+ close(fd);
+
+ if (malloced_device)
+ free(device);
+
+ return(NULL);
+}
+
+void
+cam_close_device(struct cam_device *dev)
+{
+ if (dev == NULL)
+ return;
+
+ cam_close_spec_device(dev);
+
+ free(dev);
+}
+
+void
+cam_close_spec_device(struct cam_device *dev)
+{
+ if (dev == NULL)
+ return;
+
+ if (dev->fd >= 0)
+ close(dev->fd);
+}
+
+char *
+cam_path_string(struct cam_device *dev, char *str, int len)
+{
+ if (dev == NULL) {
+ snprintf(str, len, "No path");
+ return(str);
+ }
+
+ snprintf(str, len, "(%s%d:%s%d:%d:%d:%d): ",
+ (dev->device_name[0] != '\0') ? dev->device_name : "pass",
+ dev->dev_unit_num,
+ (dev->sim_name[0] != '\0') ? dev->sim_name : "unknown",
+ dev->sim_unit_number,
+ dev->bus_id,
+ dev->target_id,
+ dev->target_lun);
+
+ return(str);
+}
+
+/*
+ * Malloc/duplicate a CAM device structure.
+ */
+struct cam_device *
+cam_device_dup(struct cam_device *device)
+{
+ char *func_name = "cam_device_dup";
+ struct cam_device *newdev;
+
+ if (device == NULL) {
+ sprintf(cam_errbuf, "%s: device is NULL", func_name);
+ return(NULL);
+ }
+
+ newdev = malloc(sizeof(struct cam_device));
+ if (newdev == NULL) {
+ snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
+ "%s: couldn't malloc CAM device structure", func_name);
+ return(NULL);
+ }
+
+ bcopy(device, newdev, sizeof(struct cam_device));
+
+ return(newdev);
+}
+
+/*
+ * Copy a CAM device structure.
+ */
+void
+cam_device_copy(struct cam_device *src, struct cam_device *dst)
+{
+ char *func_name = "cam_device_copy";
+
+ if (src == NULL) {
+ sprintf(cam_errbuf, "%s: source device struct was NULL",
+ func_name);
+ return;
+ }
+
+ if (dst == NULL) {
+ sprintf(cam_errbuf, "%s: destination device struct was NULL",
+ func_name);
+ return;
+ }
+
+ bcopy(src, dst, sizeof(struct cam_device));
+
+}
diff --git a/lib/libcam/camlib.h b/lib/libcam/camlib.h
new file mode 100644
index 0000000..e505c77
--- /dev/null
+++ b/lib/libcam/camlib.h
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 1997, 1998 Kenneth D. Merry.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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$
+ */
+/*
+ * Buffer encoding/decoding routines taken from the original FreeBSD SCSI
+ * library and slightly modified. The original header file had the following
+ * copyright:
+ */
+/* Copyright (c) 1994 HD Associates (hd@world.std.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by HD Associates
+ * 4. Neither the name of the HD Associaates nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY HD ASSOCIATES``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL HD ASSOCIATES OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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 _CAMLIB_H
+#define _CAMLIB_H
+
+#include <sys/cdefs.h>
+#include <sys/param.h>
+
+#include <cam/cam.h>
+#include <cam/cam_ccb.h>
+
+#define CAM_ERRBUF_SIZE 2048 /* sizeof the CAM libarary error string */
+
+/*
+ * Right now we hard code the transport layer device, but this will change
+ * if we ever get more than one transport layer.
+ */
+#define XPT_DEVICE "/dev/xpt0"
+
+
+extern char cam_errbuf[];
+
+struct cam_device {
+ char device_path[MAXPATHLEN];/*
+ * Pathname of the device
+ * given by the user. This
+ * may be null if the
+ * user states the device
+ * name and unit number
+ * separately.
+ */
+ char given_dev_name[DEV_IDLEN+1];/*
+ * Device name given by
+ * the user.
+ */
+ u_int32_t given_unit_number; /*
+ * Unit number given by
+ * the user.
+ */
+ char device_name[DEV_IDLEN+1];/*
+ * Name of the device,
+ * e.g. 'pass'
+ */
+ u_int32_t dev_unit_num; /* Unit number of the passthrough
+ * device associated with this
+ * particular device.
+ */
+
+ char sim_name[SIM_IDLEN+1]; /* Controller name, e.g. 'ahc' */
+ u_int32_t sim_unit_number; /* Controller unit number */
+ u_int32_t bus_id; /* Controller bus number */
+ lun_id_t target_lun; /* Logical Unit Number */
+ target_id_t target_id; /* Target ID */
+ path_id_t path_id; /* System SCSI bus number */
+ u_int16_t pd_type; /* type of peripheral device */
+ struct scsi_inquiry_data inq_data; /* SCSI Inquiry data */
+ u_int8_t serial_num[252]; /* device serial number */
+ u_int8_t serial_num_len; /* length of the serial number */
+ u_int8_t sync_period; /* Negotiated sync period */
+ u_int8_t sync_offset; /* Negotiated sync offset */
+ u_int8_t bus_width; /* Negotiated bus width */
+ int fd; /* file descriptor for device */
+};
+
+__BEGIN_DECLS
+/* Basic utility commands */
+struct cam_device * cam_open_device(const char *path, int flags);
+void cam_close_device(struct cam_device *dev);
+void cam_close_spec_device(struct cam_device *dev);
+struct cam_device * cam_open_spec_device(const char *dev_name,
+ int unit, int flags,
+ struct cam_device *device);
+struct cam_device * cam_open_btl(path_id_t path_id, target_id_t target_id,
+ lun_id_t target_lun, int flags,
+ struct cam_device *device);
+struct cam_device * cam_open_pass(const char *path, int flags,
+ struct cam_device *device);
+union ccb * cam_getccb(struct cam_device *dev);
+void cam_freeccb(union ccb *ccb);
+int cam_send_ccb(struct cam_device *device, union ccb *ccb);
+char * cam_path_string(struct cam_device *dev, char *str,
+ int len);
+struct cam_device * cam_device_dup(struct cam_device *device);
+void cam_device_copy(struct cam_device *src,
+ struct cam_device *dst);
+int cam_get_device(const char *path, char *dev_name,
+ int devnamelen, int *unit);
+
+/*
+ * Buffer encoding/decoding routines, from the old SCSI library.
+ */
+int csio_decode(struct ccb_scsiio *csio, const char *fmt, ...)
+ __printflike(2, 3);
+int csio_decode_visit(struct ccb_scsiio *csio, const char *fmt,
+ void (*arg_put)(void *, int, void *, int, char *),
+ void *puthook);
+int buff_decode(u_int8_t *buff, size_t len, const char *fmt, ...)
+ __printflike(3, 4);
+int buff_decode_visit(u_int8_t *buff, size_t len, const char *fmt,
+ void (*arg_put)(void *, int, void *, int, char *),
+ void *puthook);
+int csio_build(struct ccb_scsiio *csio, u_int8_t *data_ptr,
+ u_int32_t dxfer_len, u_int32_t flags, int retry_count,
+ int timeout, const char *cmd_spec, ...);
+int csio_build_visit(struct ccb_scsiio *csio, u_int8_t *data_ptr,
+ u_int32_t dxfer_len, u_int32_t flags, int retry_count,
+ int timeout, const char *cmd_spec,
+ int (*arg_get)(void *hook, char *field_name),
+ void *gethook);
+int csio_encode(struct ccb_scsiio *csio, const char *fmt, ...)
+ __printflike(2, 3);
+int buff_encode_visit(u_int8_t *buff, size_t len, const char *fmt,
+ int (*arg_get)(void *hook, char *field_name),
+ void *gethook);
+int csio_encode_visit(struct ccb_scsiio *csio, const char *fmt,
+ int (*arg_get)(void *hook, char *field_name),
+ void *gethook);
+__END_DECLS
+
+#endif /* _CAMLIB_H */
diff --git a/lib/libcam/scsi_cmdparse.c b/lib/libcam/scsi_cmdparse.c
new file mode 100644
index 0000000..3d977e1
--- /dev/null
+++ b/lib/libcam/scsi_cmdparse.c
@@ -0,0 +1,849 @@
+/*
+ * Taken from the original FreeBSD user SCSI library.
+ */
+/* Copyright (c) 1994 HD Associates
+ * (contact: dufault@hda.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by HD Associates
+ * 4. Neither the name of the HD Associaates nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY HD ASSOCIATES``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL HD ASSOCIATES OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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: scsi.c,v 1.8 1997/02/22 15:07:54 peter Exp $
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <sys/errno.h>
+#include <stdarg.h>
+#include <fcntl.h>
+
+#include <cam/cam.h>
+#include <cam/cam_ccb.h>
+#include <cam/scsi/scsi_message.h>
+#include "camlib.h"
+
+/*
+ * Decode: Decode the data section of a scsireq. This decodes
+ * trivial grammar:
+ *
+ * fields : field fields
+ * ;
+ *
+ * field : field_specifier
+ * | control
+ * ;
+ *
+ * control : 's' seek_value
+ * | 's' '+' seek_value
+ * ;
+ *
+ * seek_value : DECIMAL_NUMBER
+ * | 'v' // For indirect seek, i.e., value from the arg list
+ * ;
+ *
+ * field_specifier : type_specifier field_width
+ * | '{' NAME '}' type_specifier field_width
+ * ;
+ *
+ * field_width : DECIMAL_NUMBER
+ * ;
+ *
+ * type_specifier : 'i' // Integral types (i1, i2, i3, i4)
+ * | 'b' // Bits
+ * | 't' // Bits
+ * | 'c' // Character arrays
+ * | 'z' // Character arrays with zeroed trailing spaces
+ * ;
+ *
+ * Notes:
+ * 1. Integral types are swapped into host order.
+ * 2. Bit fields are allocated MSB to LSB to match the SCSI spec documentation.
+ * 3. 's' permits "seeking" in the string. "s+DECIMAL" seeks relative to
+ * DECIMAL; "sDECIMAL" seeks absolute to decimal.
+ * 4. 's' permits an indirect reference. "sv" or "s+v" will get the
+ * next integer value from the arg array.
+ * 5. Field names can be anything between the braces
+ *
+ * BUGS:
+ * i and b types are promoted to ints.
+ *
+ */
+
+static int
+do_buff_decode(u_int8_t *databuf, size_t len,
+ void (*arg_put)(void *, int , void *, int, char *),
+ void *puthook, const char *fmt, va_list ap)
+{
+ int assigned = 0;
+ int width;
+ int suppress;
+ int plus;
+ int done = 0;
+ static u_char mask[] = {0, 0x01, 0x03, 0x07, 0x0f,
+ 0x1f, 0x3f, 0x7f, 0xff};
+ int value;
+ u_char *base = databuf;
+ char *intendp;
+ char letter;
+ char field_name[80];
+
+# define ARG_PUT(ARG) \
+ do \
+ { \
+ if (!suppress) \
+ { \
+ if (arg_put) \
+ (*arg_put)(puthook, (letter == 't' ? \
+ 'b' : letter), \
+ (void *)((long)(ARG)), width, \
+ field_name); \
+ else \
+ *(va_arg(ap, int *)) = (ARG); \
+ assigned++; \
+ } \
+ field_name[0] = 0; \
+ suppress = 0; \
+ } while (0)
+
+ u_char bits = 0; /* For bit fields */
+ int shift = 0; /* Bits already shifted out */
+ suppress = 0;
+ field_name[0] = 0;
+
+ while (!done) {
+ switch(letter = *fmt) {
+ case ' ': /* White space */
+ case '\t':
+ case '\r':
+ case '\n':
+ case '\f':
+ fmt++;
+ break;
+
+ case '#': /* Comment */
+ while (*fmt && (*fmt != '\n'))
+ fmt++;
+ if (fmt)
+ fmt++; /* Skip '\n' */
+ break;
+
+ case '*': /* Suppress assignment */
+ fmt++;
+ suppress = 1;
+ break;
+
+ case '{': /* Field Name */
+ {
+ int i = 0;
+ fmt++; /* Skip '{' */
+ while (*fmt && (*fmt != '}')) {
+ if (i < sizeof(field_name))
+ field_name[i++] = *fmt;
+
+ fmt++;
+ }
+ if (fmt)
+ fmt++; /* Skip '}' */
+ field_name[i] = 0;
+ break;
+ }
+
+ case 't': /* Bit (field) */
+ case 'b': /* Bits */
+ fmt++;
+ width = strtol(fmt, &intendp, 10);
+ fmt = intendp;
+ if (width > 8)
+ done = 1;
+ else {
+ if (shift <= 0) {
+ bits = *databuf++;
+ shift = 8;
+ }
+ value = (bits >> (shift - width)) &
+ mask[width];
+
+#if 0
+ printf("shift %2d bits %02x value %02x width %2d mask %02x\n",
+ shift, bits, value, width, mask[width]);
+#endif
+
+ ARG_PUT(value);
+
+ shift -= width;
+ }
+ break;
+
+ case 'i': /* Integral values */
+ shift = 0;
+ fmt++;
+ width = strtol(fmt, &intendp, 10);
+ fmt = intendp;
+ switch(width) {
+ case 1:
+ ARG_PUT(*databuf);
+ databuf++;
+ break;
+
+ case 2:
+ ARG_PUT((*databuf) << 8 | *(databuf + 1));
+ databuf += 2;
+ break;
+
+ case 3:
+ ARG_PUT((*databuf) << 16 |
+ (*(databuf + 1)) << 8 | *(databuf + 2));
+ databuf += 3;
+ break;
+
+ case 4:
+ ARG_PUT((*databuf) << 24 |
+ (*(databuf + 1)) << 16 |
+ (*(databuf + 2)) << 8 |
+ *(databuf + 3));
+ databuf += 4;
+ break;
+
+ default:
+ done = 1;
+ break;
+ }
+
+ break;
+
+ case 'c': /* Characters (i.e., not swapped) */
+ case 'z': /* Characters with zeroed trailing
+ spaces */
+ shift = 0;
+ fmt++;
+ width = strtol(fmt, &intendp, 10);
+ fmt = intendp;
+ if (!suppress) {
+ if (arg_put)
+ (*arg_put)(puthook,
+ (letter == 't' ? 'b' : letter),
+ databuf, width, field_name);
+ else {
+ char *dest;
+ dest = va_arg(ap, char *);
+ bcopy(databuf, dest, width);
+ if (letter == 'z') {
+ char *p;
+ for (p = dest + width - 1;
+ (p >= (char *)dest)
+ && (*p == ' '); p--)
+ *p = 0;
+ }
+ }
+ assigned++;
+ }
+ databuf += width;
+ field_name[0] = 0;
+ suppress = 0;
+ break;
+
+ case 's': /* Seek */
+ shift = 0;
+ fmt++;
+ if (*fmt == '+') {
+ plus = 1;
+ fmt++;
+ } else
+ plus = 0;
+
+ if (tolower(*fmt) == 'v') {
+ /*
+ * You can't suppress a seek value. You also
+ * can't have a variable seek when you are using
+ * "arg_put".
+ */
+ width = (arg_put) ? 0 : va_arg(ap, int);
+ fmt++;
+ } else {
+ width = strtol(fmt, &intendp, 10);
+ fmt = intendp;
+ }
+
+ if (plus)
+ databuf += width; /* Relative seek */
+ else
+ databuf = base + width; /* Absolute seek */
+
+ break;
+
+ case 0:
+ done = 1;
+ break;
+
+ default:
+ fprintf(stderr, "Unknown letter in format: %c\n",
+ letter);
+ fmt++;
+ break;
+ }
+ }
+
+ return (assigned);
+}
+
+/* next_field: Return the next field in a command specifier. This
+ * builds up a SCSI command using this trivial grammar:
+ *
+ * fields : field fields
+ * ;
+ *
+ * field : value
+ * | value ':' field_width
+ * ;
+ *
+ * field_width : digit
+ * | 'i' digit // i2 = 2 byte integer, i3 = 3 byte integer etc.
+ * ;
+ *
+ * value : HEX_NUMBER
+ * | 'v' // For indirection.
+ * ;
+ *
+ * Notes:
+ * Bit fields are specified MSB first to match the SCSI spec.
+ *
+ * Examples:
+ * TUR: "0 0 0 0 0 0"
+ * WRITE BUFFER: "38 v:3 0:2 0:3 v v:i3 v:i3 0", mode, buffer_id, list_length
+ *
+ * The function returns the value:
+ * 0: For reached end, with error_p set if an error was found
+ * 1: For valid stuff setup
+ * 2: For "v" was entered as the value (implies use varargs)
+ *
+ */
+
+static int
+next_field(const char **pp, char *fmt, int *width_p, int *value_p, char *name,
+ int n_name, int *error_p, int *suppress_p)
+{
+ const char *p = *pp;
+ char *intendp;
+
+ int something = 0;
+
+ enum {
+ BETWEEN_FIELDS,
+ START_FIELD,
+ GET_FIELD,
+ DONE,
+ } state;
+
+ int value = 0;
+ int field_size; /* Default to byte field type... */
+ int field_width; /* 1 byte wide */
+ int is_error = 0;
+ int suppress = 0;
+
+ field_size = 8; /* Default to byte field type... */
+ *fmt = 'i';
+ field_width = 1; /* 1 byte wide */
+ if (name)
+ *name = 0;
+
+ state = BETWEEN_FIELDS;
+
+ while (state != DONE) {
+ switch(state) {
+ case BETWEEN_FIELDS:
+ if (*p == 0)
+ state = DONE;
+ else if (isspace(*p))
+ p++;
+ else if (*p == '#') {
+ while (*p && *p != '\n')
+ p++;
+ if (p)
+ p++;
+ } else if (*p == '{') {
+ int i = 0;
+
+ p++;
+
+ while (*p && *p != '}') {
+ if(name && i < n_name) {
+ name[i] = *p;
+ i++;
+ }
+ p++;
+ }
+
+ if(name && i < n_name)
+ name[i] = 0;
+
+ if (*p == '}')
+ p++;
+ } else if (*p == '*') {
+ p++;
+ suppress = 1;
+ } else if (isxdigit(*p)) {
+ something = 1;
+ value = strtol(p, &intendp, 16);
+ p = intendp;
+ state = START_FIELD;
+ } else if (tolower(*p) == 'v') {
+ p++;
+ something = 2;
+ value = *value_p;
+ state = START_FIELD;
+ } else if (tolower(*p) == 'i') {
+ /*
+ * Try to work without the "v".
+ */
+ something = 2;
+ value = *value_p;
+ p++;
+
+ *fmt = 'i';
+ field_size = 8;
+ field_width = strtol(p, &intendp, 10);
+ p = intendp;
+ state = DONE;
+
+ } else if (tolower(*p) == 't') {
+ /*
+ * XXX: B can't work: Sees the 'b' as a
+ * hex digit in "isxdigit". try "t" for
+ * bit field.
+ */
+ something = 2;
+ value = *value_p;
+ p++;
+
+ *fmt = 'b';
+ field_size = 1;
+ field_width = strtol(p, &intendp, 10);
+ p = intendp;
+ state = DONE;
+ } else if (tolower(*p) == 's') {
+ /* Seek */
+ *fmt = 's';
+ p++;
+ if (tolower(*p) == 'v') {
+ p++;
+ something = 2;
+ value = *value_p;
+ } else {
+ something = 1;
+ value = strtol(p, &intendp, 0);
+ p = intendp;
+ }
+ state = DONE;
+ } else {
+ fprintf(stderr, "Invalid starting "
+ "character: %c\n", *p);
+ is_error = 1;
+ state = DONE;
+ }
+ break;
+
+ case START_FIELD:
+ if (*p == ':') {
+ p++;
+ field_size = 1; /* Default to bits
+ when specified */
+ state = GET_FIELD;
+ } else
+ state = DONE;
+ break;
+
+ case GET_FIELD:
+ if (isdigit(*p)) {
+ *fmt = 'b';
+ field_size = 1;
+ field_width = strtol(p, &intendp, 10);
+ p = intendp;
+ state = DONE;
+ } else if (*p == 'i') {
+
+ /* Integral (bytes) */
+ p++;
+
+ *fmt = 'i';
+ field_size = 8;
+ field_width = strtol(p, &intendp, 10);
+ p = intendp;
+ state = DONE;
+ } else if (*p == 'b') {
+
+ /* Bits */
+ p++;
+
+ *fmt = 'b';
+ field_size = 1;
+ field_width = strtol(p, &intendp, 10);
+ p = intendp;
+ state = DONE;
+ } else {
+ fprintf(stderr, "Invalid startfield %c "
+ "(%02x)\n", *p, *p);
+ is_error = 1;
+ state = DONE;
+ }
+ break;
+
+ case DONE:
+ break;
+ }
+ }
+
+ if (is_error) {
+ *error_p = 1;
+ return 0;
+ }
+
+ *error_p = 0;
+ *pp = p;
+ *width_p = field_width * field_size;
+ *value_p = value;
+ *suppress_p = suppress;
+
+ return (something);
+}
+
+static int
+do_encode(u_char *buff, size_t vec_max, size_t *used,
+ int (*arg_get)(void *, char *), void *gethook, const char *fmt,
+ va_list ap)
+{
+ int ind;
+ int shift;
+ u_char val;
+ int ret;
+ int width, value, error, suppress;
+ char c;
+ int encoded = 0;
+ char field_name[80];
+
+ ind = 0;
+ shift = 0;
+ val = 0;
+
+ while ((ret = next_field(&fmt, &c, &width, &value, field_name,
+ sizeof(field_name), &error, &suppress))) {
+ encoded++;
+
+ if (ret == 2) {
+ if (suppress)
+ value = 0;
+ else
+ value = arg_get ?
+ (*arg_get)(gethook, field_name) :
+ va_arg(ap, int);
+ }
+
+#if 0
+ printf(
+"do_encode: ret %d fmt %c width %d value %d name \"%s\" error %d suppress %d\n",
+ ret, c, width, value, field_name, error, suppress);
+#endif
+ /* Absolute seek */
+ if (c == 's') {
+ ind = value;
+ continue;
+ }
+
+ /* A width of < 8 is a bit field. */
+ if (width < 8) {
+
+ /* This is a bit field. We start with the high bits
+ * so it reads the same as the SCSI spec.
+ */
+
+ shift += width;
+
+ val |= (value << (8 - shift));
+
+ if (shift == 8) {
+ if (ind < vec_max) {
+ buff[ind++] = val;
+ val = 0;
+ }
+ shift = 0;
+ }
+ } else {
+ if (shift) {
+ if (ind < vec_max) {
+ buff[ind++] = val;
+ val = 0;
+ }
+ shift = 0;
+ }
+ switch(width) {
+ case 8: /* 1 byte integer */
+ if (ind < vec_max)
+ buff[ind++] = value;
+ break;
+
+ case 16: /* 2 byte integer */
+ if (ind < vec_max - 2 + 1) {
+ buff[ind++] = value >> 8;
+ buff[ind++] = value;
+ }
+ break;
+
+ case 24: /* 3 byte integer */
+ if (ind < vec_max - 3 + 1) {
+ buff[ind++] = value >> 16;
+ buff[ind++] = value >> 8;
+ buff[ind++] = value;
+ }
+ break;
+
+ case 32: /* 4 byte integer */
+ if (ind < vec_max - 4 + 1) {
+ buff[ind++] = value >> 24;
+ buff[ind++] = value >> 16;
+ buff[ind++] = value >> 8;
+ buff[ind++] = value;
+ }
+ break;
+
+ default:
+ fprintf(stderr, "do_encode: Illegal width\n");
+ break;
+ }
+ }
+ }
+
+ /* Flush out any remaining bits
+ */
+ if (shift && ind < vec_max) {
+ buff[ind++] = val;
+ val = 0;
+ }
+
+
+ if (used)
+ *used = ind;
+
+ if (error)
+ return -1;
+
+ return encoded;
+}
+
+int
+csio_decode(struct ccb_scsiio *csio, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ return(do_buff_decode(csio->data_ptr, (size_t)csio->dxfer_len,
+ 0, 0, fmt, ap));
+}
+
+int
+csio_decode_visit(struct ccb_scsiio *csio, const char *fmt,
+ void (*arg_put)(void *, int, void *, int, char *),
+ void *puthook)
+{
+ va_list ap;
+
+ /*
+ * We need some way to output things; we can't do it without
+ * the arg_put function.
+ */
+ if (arg_put == NULL)
+ return(-1);
+
+ bzero(&ap, sizeof(ap));
+
+ return(do_buff_decode(csio->data_ptr, (size_t)csio->dxfer_len,
+ arg_put, puthook, fmt, ap));
+}
+
+int
+buff_decode(u_int8_t *buff, size_t len, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ return(do_buff_decode(buff, len, 0, 0, fmt, ap));
+}
+
+int
+buff_decode_visit(u_int8_t *buff, size_t len, const char *fmt,
+ void (*arg_put)(void *, int, void *, int, char *),
+ void *puthook)
+{
+ va_list ap;
+
+ /*
+ * We need some way to output things; we can't do it without
+ * the arg_put function.
+ */
+ if (arg_put == NULL)
+ return(-1);
+
+ bzero(&ap, sizeof(ap));
+
+ return(do_buff_decode(buff, len, arg_put, puthook, fmt, ap));
+}
+
+/*
+ * Build a SCSI CCB, given the command and data pointers and a format
+ * string describing the
+ */
+int
+csio_build(struct ccb_scsiio *csio, u_int8_t *data_ptr, u_int32_t dxfer_len,
+ u_int32_t flags, int retry_count, int timeout, const char *cmd_spec,
+ ...)
+{
+ size_t cmdlen;
+ int retval;
+ va_list ap;
+
+ if (csio == NULL)
+ return(0);
+
+ bzero(csio, sizeof(struct ccb_scsiio));
+
+ va_start(ap, cmd_spec);
+
+ if ((retval = do_encode(csio->cdb_io.cdb_bytes, SCSI_MAX_CDBLEN,
+ &cmdlen, NULL, NULL, cmd_spec, ap)) == -1)
+ return(retval);
+
+ cam_fill_csio(csio,
+ /* retries */ retry_count,
+ /* cbfcnp */ NULL,
+ /* flags */ flags,
+ /* tag_action */ MSG_SIMPLE_Q_TAG,
+ /* data_ptr */ data_ptr,
+ /* dxfer_len */ dxfer_len,
+ /* sense_len */ SSD_FULL_SIZE,
+ /* cdb_len */ cmdlen,
+ /* timeout */ timeout ? timeout : 5000);
+
+ return(retval);
+}
+
+int
+csio_build_visit(struct ccb_scsiio *csio, u_int8_t *data_ptr,
+ u_int32_t dxfer_len, u_int32_t flags, int retry_count,
+ int timeout, const char *cmd_spec,
+ int (*arg_get)(void *hook, char *field_name), void *gethook)
+{
+ va_list ap;
+ size_t cmdlen;
+ int retval;
+
+ if (csio == NULL)
+ return(0);
+
+ /*
+ * We need something to encode, but we can't get it without the
+ * arg_get function.
+ */
+ if (arg_get == NULL)
+ return(-1);
+
+ bzero(&ap, sizeof(ap));
+
+ bzero(csio, sizeof(struct ccb_scsiio));
+
+ if ((retval = do_encode(csio->cdb_io.cdb_bytes, SCSI_MAX_CDBLEN,
+ &cmdlen, arg_get, gethook, cmd_spec, ap)) == -1)
+ return(retval);
+
+ cam_fill_csio(csio,
+ /* retries */ retry_count,
+ /* cbfcnp */ NULL,
+ /* flags */ flags,
+ /* tag_action */ MSG_SIMPLE_Q_TAG,
+ /* data_ptr */ data_ptr,
+ /* dxfer_len */ dxfer_len,
+ /* sense_len */ SSD_FULL_SIZE,
+ /* cdb_len */ cmdlen,
+ /* timeout */ timeout ? timeout : 5000);
+
+ return(retval);
+}
+
+int
+csio_encode(struct ccb_scsiio *csio, const char *fmt, ...)
+{
+ va_list ap;
+
+ if (csio == NULL)
+ return(0);
+
+ va_start(ap, fmt);
+
+ return(do_encode(csio->data_ptr, csio->dxfer_len, 0, 0, 0, fmt, ap));
+}
+
+int
+buff_encode_visit(u_int8_t *buff, size_t len, const char *fmt,
+ int (*arg_get)(void *hook, char *field_name), void *gethook)
+{
+ va_list ap;
+
+ /*
+ * We need something to encode, but we can't get it without the
+ * arg_get function.
+ */
+ if (arg_get == NULL)
+ return(-1);
+
+ bzero(&ap, sizeof(ap));
+
+ return(do_encode(buff, len, 0, arg_get, gethook, fmt, ap));
+}
+
+int
+csio_encode_visit(struct ccb_scsiio *csio, const char *fmt,
+ int (*arg_get)(void *hook, char *field_name), void *gethook)
+{
+ va_list ap;
+
+ /*
+ * We need something to encode, but we can't get it without the
+ * arg_get function.
+ */
+ if (arg_get == NULL)
+ return(-1);
+
+ bzero(&ap, sizeof(ap));
+
+ return(do_encode(csio->data_ptr, csio->dxfer_len, 0, arg_get,
+ gethook, fmt, ap));
+}
diff --git a/lib/libcom_err/Makefile b/lib/libcom_err/Makefile
new file mode 100644
index 0000000..65a3ffd
--- /dev/null
+++ b/lib/libcom_err/Makefile
@@ -0,0 +1,14 @@
+# $FreeBSD$
+
+LIB= com_err
+SRCS= com_err.c error.c
+INCS= ${COM_ERRDIR}/com_err.h ${COM_ERRDIR}/com_right.h
+MAN= com_err.3
+COM_ERRDIR= ${.CURDIR}/../../contrib/com_err
+CFLAGS+= -I${COM_ERRDIR}
+
+SUBDIR= doc
+
+.include <bsd.lib.mk>
+
+.PATH: ${COM_ERRDIR}
diff --git a/lib/libcom_err/doc/Makefile b/lib/libcom_err/doc/Makefile
new file mode 100644
index 0000000..4c3c0bb
--- /dev/null
+++ b/lib/libcom_err/doc/Makefile
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+INFO= com_err
+INFOSECTION= "Programming & development tools."
+INFOENTRY_com_err= "* libcom_err: (com_err). A Common Error Description Library for UNIX."
+
+.include <bsd.info.mk>
diff --git a/lib/libcom_err/doc/com_err.texinfo b/lib/libcom_err/doc/com_err.texinfo
new file mode 100644
index 0000000..6c71da8
--- /dev/null
+++ b/lib/libcom_err/doc/com_err.texinfo
@@ -0,0 +1,615 @@
+\input texinfo @c -*-texinfo-*-
+
+@c $FreeBSD$
+
+@c Note that although this source file is in texinfo format (more
+@c or less), it is not yet suitable for turning into an ``info''
+@c file. Sorry, maybe next time.
+@c
+@c In order to produce hardcopy documentation from a texinfo file,
+@c run ``tex com_err.texinfo'' which will load in texinfo.tex,
+@c provided in this distribution. (texinfo.tex is from the Free
+@c Software Foundation, and is under different copyright restrictions
+@c from the rest of this package.)
+
+@ifinfo
+@barfo
+@end ifinfo
+
+@iftex
+@tolerance 10000
+
+@c Mutate section headers...
+@begingroup
+ @catcode#=6
+ @gdef@secheading#1#2#3{@secheadingi {#3@enspace #1}}
+@endgroup
+@end iftex
+
+@c %**start of header (This is for running Texinfo on a region.)
+@setfilename com_err
+@settitle A Common Error Description Library for UNIX
+@c %**end of header (This is for running Texinfo on a region.)
+
+@ifinfo
+This file documents the use of the Common Error Description library.
+
+Copyright (C) 1987, 1988 Student Information Processing Board of 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 names of M.I.T. and the M.I.T. S.I.P.B. not be
+used in advertising or publicity pertaining to distribution of the software
+without specific, written prior permission. M.I.T. and the M.I.T. S.I.P.B.
+make no representations about the suitability of this software for any
+purpose. It is provided "as is" without express or implied warranty.
+
+Note that the file texinfo.tex, provided with this distribution, is from
+the Free Software Foundation, and is under different copyright restrictions
+from the remainder of this package.
+
+@end ifinfo
+
+@ignore
+Permission is granted to process this file through Tex and print the
+results, provided the printed document carries copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+
+@end ignore
+
+@setchapternewpage odd
+
+@titlepage
+@center @titlefont{A Common Error Description}
+@center @titlefont{Library for UNIX}
+@sp 2
+@center Ken Raeburn
+@center Bill Sommerfeld
+@sp 1
+@center MIT Student Information Processing Board
+@sp 3
+@center last updated 1 January 1989
+@center for version 1.2
+@center ***DRAFT COPY ONLY***
+
+@vskip 2in
+
+@center @b{Abstract}
+
+UNIX has always had a clean and simple system call interface, with a
+standard set of error codes passed between the kernel and user
+programs. Unfortunately, the same cannot be said of many of the
+libraries layered on top of the primitives provided by the kernel.
+Typically, each one has used a different style of indicating errors to
+their callers, leading to a total hodgepodge of error handling, and
+considerable amounts of work for the programmer. This paper describes
+a library and associated utilities which allows a more uniform way for
+libraries to return errors to their callers, and for programs to
+describe errors and exceptional conditions to their users.
+
+@page
+@vskip 0pt plus 1filll
+
+Copyright @copyright{} 1987, 1988 by the Student Information Processing
+Board of 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 names of M.I.T. and the M.I.T. S.I.P.B. not be
+used in advertising or publicity pertaining to distribution of the software
+without specific, written prior permission. M.I.T. and the M.I.T. S.I.P.B.
+make no representations about the suitability of this software for any
+purpose. It is provided "as is" without express or implied warranty.
+
+Note that the file texinfo.tex, provided with this distribution, is from
+the Free Software Foundation, and is under different copyright restrictions
+from the remainder of this package.
+
+@end titlepage
+
+@ifinfo
+@node Top, Why com_err?, (dir), (dir)
+@comment node-name, next, previous, up
+@top General Introduction
+
+@menu
+* Why com_err?:: What is all this for?
+* Error codes:: What's an error code, anyway?
+* Error table source file:: How to describe an error table.
+* The error-table compiler:: How to compile the table.
+* Run-time support routines:: How to use from within your program.
+* Coding Conventions:: Stylistic issues.
+* Building and Installation:: How to build and install.
+* Bug Reports:: You have found a bug? Report it.
+* Acknowledgements:: Whom to thank...
+
+@end menu
+
+@end ifinfo
+
+@page
+
+@ifinfo
+@node Why com_err?, Error codes, Top, (dir)
+@comment node-name, next, previous, up
+@end ifinfo
+
+@section Why com_err?
+
+In building application software packages, a programmer often has to
+deal with a number of libraries, each of which can use a different
+error-reporting mechanism. Sometimes one of two values is returned,
+indicating simply SUCCESS or FAILURE, with no description of errors
+encountered. Sometimes it is an index into a table of text strings,
+where the name of the table used is dependent on the library being
+used when the error is generated; since each table starts numbering at
+0 or 1, additional information as to the source of the error code is
+needed to determine which table to look at. Sometimes no text messages are
+supplied at all, and the programmer must supply them at any point at which
+he may wish to report error conditions.
+Often, a global variable is assigned some value describing the error, but
+the programmer has to know in each case whether to look at @code{errno},
+@code{h_errno}, the return value from @code{hes_err()}, or whatever other
+variables or routines are specified.
+And what happens if something
+in the procedure of
+examining or reporting the error changes the same variable?
+
+The package we have developed is an attempt to present a common
+error-handling mechanism to manipulate the most common form of error code
+in a fashion that does not have the problems listed above.
+
+A list of up to 256 text messages is supplied to a translator we have
+written, along with the three- to four-character ``name'' of the error
+table. The library using this error table need only call a routine
+generated from this error-table source to make the table ``known'' to the
+com_err library, and any error code the library generates can be converted
+to the corresponding error message. There is also a default format for
+error codes accidentally returned before making the table known, which is
+of the form @samp{unknown code foo 32}, where @samp{foo} would be the name
+of the table.
+
+@ifinfo
+@node Error codes, Error table source file, Why com_err?, (dir)
+@comment node-name, next, previous, up
+@end ifinfo
+
+@section Error codes
+
+Error codes themselves are 32 bit (signed) integers, of which the high
+order 24 bits are an identifier of which error table the error code is
+from, and the low order 8 bits are a sequential error number within
+the table. An error code may thus be easily decomposed into its component
+parts. Only the lowest 32 bits of an error code are considered significant
+on systems which support wider values.
+
+Error table 0 is defined to match the UNIX system call error table
+(@code{sys_errlist}); this allows @code{errno} values to be used directly
+in the library (assuming that @code{errno} is of a type with the same width
+as @t{long}). Other error table numbers are formed by compacting together
+the first four characters of the error table name. The mapping between
+characters in the name and numeric values in the error code are defined in
+a system-independent fashion, so that two systems that can pass integral
+values between them can reliably pass error codes without loss of meaning;
+this should work even if the character sets used are not the same.
+(However, if this is to be done, error table 0 should be avoided, since the
+local system call error tables may differ.)
+
+Any variable which is to contain an error code should be declared @t{long}.
+The draft proposed American National Standard for C (as of May, 1988)
+requires that @t{long} variables be at least 32 bits; any system which does
+not support 32-bit @t{long} values cannot make use of this package (nor
+much other software that assumes an ANSI-C environment base) without
+significant effort.
+
+@ifinfo
+@node Error table source file, The error-table compiler, Error codes, (dir)
+@comment node-name, next, previous, up
+@end ifinfo
+
+@section Error table source file
+
+The error table source file begins with the declaration of the table name,
+as
+
+@example
+error_table @var{tablename}
+@end example
+
+Individual error codes are
+specified with
+
+@example
+error_code @var{ERROR_NAME}, @var{"text message"}
+@end example
+
+where @samp{ec} can also be used as a short form of @samp{error_code}. To
+indicate the end of the table, use @samp{end}. Thus, a (short) sample
+error table might be:
+
+@example
+
+ error_table dsc
+
+ error_code DSC_DUP_MTG_NAME,
+ "Meeting already exists"
+
+ ec DSC_BAD_PATH,
+ "A bad meeting pathname was given"
+
+ ec DSC_BAD_MODES,
+ "Invalid mode for this access control list"
+
+ end
+
+@end example
+
+@ifinfo
+@node The error-table compiler, Run-time support routines, Error table source file, (dir)
+@comment node-name, next, previous, up
+@end ifinfo
+
+@section The error-table compiler
+
+The error table compiler is named @code{compile_et}. It takes one
+argument, the pathname of a file (ending in @samp{.et}, e.g.,
+@samp{dsc_err.et}) containing an error table source file. It parses the
+error table, and generates two output files -- a C header file
+(@samp{discuss_err.h}) which contains definitions of the numerical values
+of the error codes defined in the error table, and a C source file which
+should be compiled and linked with the executable. The header file must be
+included in the source of a module which wishes to reference the error
+codes defined; the object module generated from the C code may be linked in
+to a program which wishes to use the printed forms of the error codes.
+
+This translator accepts a @kbd{-language @var{lang}} argument, which
+determines for which language (or language variant) the output should be
+written. At the moment, @var{lang} is currently limited to @kbd{ANSI-C}
+and @kbd{K&R-C}, and some abbreviated forms of each. Eventually, this will
+be extended to include some support for C++. The default is currently
+@kbd{K&R-C}, though the generated sources will have ANSI-C code
+conditionalized on the symbol @t{__STDC__}.
+
+@ifinfo
+@node Run-time support routines, Coding Conventions, The error-table compiler, (dir)
+@comment node-name, next, previous, up
+@end ifinfo
+
+@section Run-time support routines
+
+Any source file which uses the routines supplied with or produced by the
+com_err package should include the header file @file{<com_err.h>}. It
+contains declarations and definitions which may be needed on some systems.
+(Some functions cannot be referenced properly without the return type
+declarations in this file. Some functions may work properly on most
+architectures even without the header file, but relying on this is not
+recommended.)
+
+The run-time support routines and variables provided via this package
+include the following:
+
+@example
+void initialize_@var{xxxx}_error_table (void);
+@end example
+
+One of these routines is built by the error compiler for each error table.
+It makes the @var{xxxx} error table ``known'' to the error reporting
+system. By convention, this routine should be called in the initialization
+routine of the @var{xxxx} library. If the library has no initialization
+routine, some combination of routines which form the core of the library
+should ensure that this routine is called. It is not advised to leave it
+the caller to make this call.
+
+There is no harm in calling this routine more than once.
+
+@example
+#define ERROR_TABLE_BASE_@var{xxxx} @var{nnnnn}L
+@end example
+
+This symbol contains the value of the first error code entry in the
+specified table.
+This rarely needs be used by the
+programmer.
+
+@example
+const char *error_message (long code);
+@end example
+
+This routine returns the character string error message associated
+with @code{code}; if this is associated with an unknown error table, or
+if the code is associated with a known error table but the code is not
+in the table, a string of the form @samp{Unknown code @var{xxxx nn}} is
+returned, where @var{xxxx} is the error table name produced by
+reversing the compaction performed on the error table number implied
+by that error code, and @var{nn} is the offset from that base value.
+
+Although this routine is available for use when needed, its use should be
+left to circumstances which render @code{com_err} (below) unusable.
+
+@example
+void com_err (const char *whoami, /* module reporting error */
+ long code, /* error code */
+ const char *format, /* format for additional detail */
+ ...); /* (extra parameters) */
+@end example
+
+This routine provides an alternate way to print error messages to
+standard error; it allows the error message to be passed in as a
+parameter, rather than in an external variable. @emph{Provide grammatical
+context for ``message.''}
+
+If @var{format} is @code{(char *)NULL}, the formatted message will not be
+printed. @var{format} may not be omitted.
+
+@example
+#include <stdarg.h>
+
+void com_err_va (const char *whoami,
+ long code,
+ const char *format,
+ va_list args);
+@end example
+
+This routine provides an interface, equivalent to @code{com_err} above,
+which may be used by higher-level variadic functions (functions which
+accept variable numbers of arguments).
+
+@example
+#include <stdarg.h>
+
+void (*set_com_err_hook (void (*proc) ())) ();
+
+void (*@var{proc}) (const char *whoami, long code, va_list args);
+
+void reset_com_err_hook ();
+@end example
+
+These two routines allow a routine to be dynamically substituted for
+@samp{com_err}. After @samp{set_com_err_hook} has been called,
+calls to @samp{com_err} will turn into calls to the new hook routine.
+@samp{reset_com_err_hook} turns off this hook. This may intended to
+be used in daemons (to use a routine which calls @var{syslog(3)}), or
+in a window system application (which could pop up a dialogue box).
+
+If a program is to be used in an environment in which simply printing
+messages to the @code{stderr} stream would be inappropriate (such as in a
+daemon program which runs without a terminal attached),
+@code{set_com_err_hook} may be used to redirect output from @code{com_err}.
+The following is an example of an error handler which uses @var{syslog(3)}
+as supplied in BSD 4.3:
+
+@example
+#include <stdio.h>
+#include <stdarg.h>
+#include <syslog.h>
+
+/* extern openlog (const char * name, int logopt, int facility); */
+/* extern syslog (int priority, char * message, ...); */
+
+void hook (const char * whoami, long code,
+ const char * format, va_list args)
+@{
+ char buffer[BUFSIZ];
+ static int initialized = 0;
+ if (!initialized) @{
+ openlog (whoami,
+ LOG_NOWAIT|LOG_CONS|LOG_PID|LOG_NDELAY,
+ LOG_DAEMON);
+ initialized = 1;
+ @}
+ vsprintf (buffer, format, args);
+ syslog (LOG_ERR, "%s %s", error_message (code), buffer);
+@}
+@end example
+
+After making the call
+@code{set_com_err_hook (hook);},
+any calls to @code{com_err} will result in messages being sent to the
+@var{syslogd} daemon for logging.
+The name of the program, @samp{whoami}, is supplied to the
+@samp{openlog()} call, and the message is formatted into a buffer and
+passed to @code{syslog}.
+
+Note that since the extra arguments to @code{com_err} are passed by
+reference via the @code{va_list} value @code{args}, the hook routine may
+place any form of interpretation on them, including ignoring them. For
+consistency, @code{printf}-style interpretation is suggested, via
+@code{vsprintf} (or @code{_doprnt} on BSD systems without full support for
+the ANSI C library).
+
+@ifinfo
+@node Coding Conventions, Building and Installation, Run-time support routines, (dir)
+@comment node-name, next, previous, up
+@end ifinfo
+
+@section Coding Conventions
+
+The following conventions are just some general stylistic conventions
+to follow when writing robust libraries and programs. Conventions
+similar to this are generally followed inside the UNIX kernel and most
+routines in the Multics operating system. In general, a routine
+either succeeds (returning a zero error code, and doing some side
+effects in the process), or it fails, doing minimal side effects; in
+any event, any invariant which the library assumes must be maintained.
+
+In general, it is not in the domain of non user-interface library
+routines to write error messages to the user's terminal, or halt the
+process. Such forms of ``error handling'' should be reserved for
+failures of internal invariants and consistancy checks only, as it
+provides the user of the library no way to clean up for himself in the
+event of total failure.
+
+Library routines which can fail should be set up to return an error
+code. This should usually be done as the return value of the
+function; if this is not acceptable, the routine should return a
+``null'' value, and put the error code into a parameter passed by
+reference.
+
+Routines which use the first style of interface can be used from
+user-interface levels of a program as follows:
+
+@example
+@{
+ if ((code = initialize_world(getuid(), random())) != 0) @{
+ com_err("demo", code,
+ "when trying to initialize world");
+ exit(1);
+ @}
+ if ((database = open_database("my_secrets", &code))==NULL) @{
+ com_err("demo", code,
+ "while opening my_secrets");
+ exit(1);
+ @}
+@}
+@end example
+
+A caller which fails to check the return status is in error. It is
+possible to look for code which ignores error returns by using lint;
+look for error messages of the form ``foobar returns value which is
+sometimes ignored'' or ``foobar returns value which is always
+ignored.''
+
+Since libraries may be built out of other libraries, it is often necessary
+for the success of one routine to depend on another. When a lower level
+routine returns an error code, the middle level routine has a few possible
+options. It can simply return the error code to its caller after doing
+some form of cleanup, it can substitute one of its own, or it can take
+corrective action of its own and continue normally. For instance, a
+library routine which makes a ``connect'' system call to make a network
+connection may reflect the system error code @code{ECONNREFUSED}
+(Connection refused) to its caller, or it may return a ``server not
+available, try again later,'' or it may try a different server.
+
+Cleanup which is typically necessary may include, but not be limited
+to, freeing allocated memory which will not be needed any more,
+unlocking concurrancy locks, dropping reference counts, closing file
+descriptors, or otherwise undoing anything which the procedure did up
+to this point. When there are a lot of things which can go wrong, it
+is generally good to write one block of error-handling code which is
+branched to, using a goto, in the event of failure. A common source
+of errors in UNIX programs is failing to close file descriptors on
+error returns; this leaves a number of ``zombied'' file descriptors
+open, which eventually causes the process to run out of file
+descriptors and fall over.
+
+@example
+@{
+ FILE *f1=NULL, *f2=NULL, *f3=NULL;
+ int status = 0;
+
+ if ( (f1 = fopen(FILE1, "r")) == NULL) @{
+ status = errno;
+ goto error;
+ @}
+
+ /*
+ * Crunch for a while
+ */
+
+ if ( (f2 = fopen(FILE2, "w")) == NULL) @{
+ status = errno;
+ goto error;
+ @}
+
+ if ( (f3 = fopen(FILE3, "a+")) == NULL) @{
+ status = errno;
+ goto error;
+ @}
+
+ /*
+ * Do more processing.
+ */
+ fclose(f1);
+ fclose(f2);
+ fclose(f3);
+ return 0;
+
+error:
+ if (f1) fclose(f1);
+ if (f2) fclose(f2);
+ if (f3) fclose(f3);
+ return status;
+@}
+@end example
+
+@ifinfo
+@node Building and Installation, Bug Reports, Coding Conventions, (dir)
+@comment node-name, next, previous, up
+@end ifinfo
+
+@section Building and Installation
+
+The distribution of this package will probably be done as a compressed
+``tar''-format file available via anonymous FTP from SIPB.MIT.EDU.
+Retrieve @samp{pub/com_err.tar.Z} and extract the contents. A subdirectory
+@t{profiled} should be created to hold objects compiled for profiling.
+Running ``make all'' should then be sufficient to build the library and
+error-table compiler. The files @samp{libcom_err.a},
+@samp{libcom_err_p.a}, @samp{com_err.h}, and @samp{compile_et} should be
+installed for use; @samp{com_err.3} and @samp{compile_et.1} can also be
+installed as manual pages.
+
+Potential problems:
+
+@itemize @bullet
+
+@item Use of @code{strcasecmp}, a routine provided in BSD for
+case-insensitive string comparisons. If an equivalent routine is
+available, you can modify @code{CFLAGS} in the makefile to define
+@code{strcasecmp} to the name of that routine.
+
+@item Compilers that defined @code{__STDC__} without providing the header
+file @code{<stdarg.h>}. One such example is Metaware's High ``C''
+compiler, as provided at Project Athena on the IBM RT/PC workstation; if
+@code{__HIGHC__} is defined, it is assumed that @code{<stdarg.h>} is not
+available, and therefore @code{<varargs.h>} must be used. If the symbol
+@code{VARARGS} is defined (e.g., in the makefile), @code{<varargs.h>} will
+be used.
+
+@item If your linker rejects symbols that are simultaneously defined in two
+library files, edit @samp{Makefile} to remove @samp{perror.c} from the
+library. This file contains a version of @var{perror(3)} which calls
+@code{com_err} instead of calling @code{write} directly.
+
+@end itemize
+
+As I do not have access to non-BSD systems, there are probably
+bugs present that may interfere with building or using this package on
+other systems. If they are reported to me, they can probably be fixed for
+the next version.
+
+@ifinfo
+@node Bug Reports, Acknowledgements, Building and Installation, (dir)
+@comment node-name, next, previous, up
+@end ifinfo
+
+@section Bug Reports
+
+Please send any comments or bug reports to the principal author: Ken
+Raeburn, @t{Raeburn@@Athena.MIT.EDU}.
+
+@ifinfo
+@node Acknowledgements, , Bug Reports, (dir)
+@comment node-name, next, previous, up
+@end ifinfo
+
+@section Acknowledgements
+
+I would like to thank: Bill Sommerfeld, for his help with some of this
+documentation, and catching some of the bugs the first time around;
+Honeywell Information Systems, for not killing off the @emph{Multics}
+operating system before I had an opportunity to use it; Honeywell's
+customers, who persuaded them not to do so, for a while; Ted Anderson of
+CMU, for catching some problems before version 1.2 left the nest; Stan
+Zanarotti and several others of MIT's Student Information Processing Board,
+for getting us started with ``discuss,'' for which this package was
+originally written; and everyone I've talked into --- I mean, asked to read
+this document and the ``man'' pages.
+
+@bye
diff --git a/lib/libcompat/4.1/ascftime.c b/lib/libcompat/4.1/ascftime.c
new file mode 100644
index 0000000..b3c15e4
--- /dev/null
+++ b/lib/libcompat/4.1/ascftime.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 1994 Joerg Wunsch
+ *
+ * All rights reserved.
+ *
+ * This program is free software.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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 Joerg Wunsch
+ * 4. The name of the developer may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * 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$
+ */
+
+#include <time.h>
+
+#define MAXLEN 1000 /* just a guess, only the user knows... */
+
+int
+ascftime(char *s, const char *format, const struct tm *tmptr)
+{
+ return strftime(s, MAXLEN, format? format: "%C", tmptr);
+}
diff --git a/lib/libcompat/4.1/cftime.3 b/lib/libcompat/4.1/cftime.3
new file mode 100644
index 0000000..116f5de
--- /dev/null
+++ b/lib/libcompat/4.1/cftime.3
@@ -0,0 +1,105 @@
+.\"
+.\" Copyright (c) 1994, 1995 Joerg Wunsch
+.\"
+.\" All rights reserved.
+.\"
+.\" This program is free software.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce 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 Joerg Wunsch
+.\" 4. The name of the developer may not be used to endorse or promote
+.\" products derived from this software without specific prior written
+.\" permission.
+.\"
+.\" 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 June 15, 1993
+.Os
+.Dt CFTIME 3
+.Sh NAME
+.Nm cftime ,
+.Nm ascftime
+.Nd convert date and time to string
+.Sh LIBRARY
+.Lb libcompat
+.Sh SYNOPSIS
+.In time.h
+.Ft int
+.Fn cftime "char *s" "char *format" "const time_t *clock"
+.Ft int
+.Fn ascftime "char *s" "const char *format" "const struct tm *tmptr"
+.Sh DESCRIPTION
+.Bf -symbolic
+The
+.Fn cftime
+and
+.Fn ascftime
+functions are made obsolete by
+.Xr strftime 3 .
+.Ef
+.Pp
+Use of the functions
+.Fn cftime
+and
+.Fn ascftime
+is strongly deprecated, since there is no way to check for a buffer
+overflow condition.
+Use
+.Xr strftime 3
+instead.
+.Pp
+The
+.Fn ascftime
+function is almost identical to
+.Xr strftime 3 ,
+with the only exception that there is no parameter to tell about the
+maximal buffer length, and the
+.Fa format
+parameter defaults to
+.Dq %C
+if a
+.Em NULL
+pointer is given.
+.Pp
+The
+.Fn cftime
+function does the same job, but it first invokes
+.Xr localtime 3
+in order to convert the given
+.Fa clock ,
+then also performs the conversions as requested by the
+.Fa format
+argument.
+.Sh RETURN VALUES
+The
+.Fn cftime
+and
+.Fn ascftime
+functions return the number of characters written to the output
+buffer
+.Fa s ,
+not counting the trailing null character.
+.Sh SEE ALSO
+.Xr localtime 3 ,
+.Xr strftime 3
diff --git a/lib/libcompat/4.1/cftime.c b/lib/libcompat/4.1/cftime.c
new file mode 100644
index 0000000..8033e44
--- /dev/null
+++ b/lib/libcompat/4.1/cftime.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 1994 Joerg Wunsch
+ *
+ * All rights reserved.
+ *
+ * This program is free software.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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 Joerg Wunsch
+ * 4. The name of the developer may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * 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$
+ */
+
+#include <time.h>
+
+#define MAXLEN 1000 /* just a guess, only the user knows... */
+
+int
+cftime(char *s, char *format, const time_t *clock)
+{
+ return strftime(s, MAXLEN, format? format: "%C", localtime(clock));
+}
+
diff --git a/lib/libcompat/4.1/ftime.3 b/lib/libcompat/4.1/ftime.3
new file mode 100644
index 0000000..87ee1b0
--- /dev/null
+++ b/lib/libcompat/4.1/ftime.3
@@ -0,0 +1,86 @@
+.\" 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. 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.
+.\"
+.\" @(#)ftime.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt FTIME 3
+.Os
+.Sh NAME
+.Nm ftime
+.Nd get date and time
+.Sh LIBRARY
+.Lb libcompat
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/timeb.h
+.Ft int
+.Fn ftime "struct timeb *tp"
+.Sh DESCRIPTION
+.Bf -symbolic
+This interface is obsoleted by
+.Xr gettimeofday 2 .
+.Ef
+.Pp
+The
+.Fn ftime
+routine fills in a structure pointed to by its argument,
+as defined by
+.In sys/timeb.h :
+.Bd -literal -offset indent
+/*
+ * Structure returned by ftime system call
+ */
+struct timeb
+{
+ time_t time;
+ unsigned short millitm;
+ short timezone;
+ short dstflag;
+};
+.Ed
+.Pp
+The structure contains the time since the epoch in seconds,
+up to 1000 milliseconds of more-precise interval,
+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.
+.Sh SEE ALSO
+.Xr gettimeofday 2 ,
+.Xr settimeofday 2 ,
+.Xr ctime 3 ,
+.Xr time 3
+.Sh HISTORY
+The
+.Nm
+function appeared in
+.Bx 4.2 .
diff --git a/lib/libcompat/4.1/ftime.c b/lib/libcompat/4.1/ftime.c
new file mode 100644
index 0000000..cc4a7f9
--- /dev/null
+++ b/lib/libcompat/4.1/ftime.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1994 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 by Christopher G. Demetriou.
+ * 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/timeb.h>
+
+int
+ftime(tbp)
+ struct timeb *tbp;
+{
+ struct timezone tz;
+ struct timeval t;
+
+ if (gettimeofday(&t, &tz) < 0)
+ return (-1);
+ tbp->millitm = t.tv_usec / 1000;
+ tbp->time = t.tv_sec;
+ tbp->timezone = tz.tz_minuteswest;
+ tbp->dstflag = tz.tz_dsttime;
+
+ return (0);
+}
diff --git a/lib/libcompat/4.1/getpw.3 b/lib/libcompat/4.1/getpw.3
new file mode 100644
index 0000000..3897136
--- /dev/null
+++ b/lib/libcompat/4.1/getpw.3
@@ -0,0 +1,92 @@
+.\" 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. 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.
+.\"
+.\" @(#)getpw.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt GETPW 3
+.Os
+.Sh NAME
+.Nm getpw
+.Nd get name from uid
+.Sh LIBRARY
+.Lb libcompat
+.Sh SYNOPSIS
+.In sys/types.h
+.Ft int
+.Fn getpw "uid_t uid" "char *buf"
+.Sh DESCRIPTION
+.Bf -symbolic
+The
+.Fn getpw
+function is made obsolete by
+.Xr getpwuid 3 .
+.Ef
+.Pp
+The
+.Fn getpw
+function reads the file
+.Pa /etc/passwd ,
+and if it finds
+the specified
+.Fa uid ,
+copies the password entry line into the string pointed to by
+.Fa buf .
+the null terminated entry line from the password database,
+and appends the
+.Dv NUL
+character.
+.Sh RETURN VALUES
+The
+.Fn getpw
+function returns the zero if successful, otherwise
+a non-zero if the entry does not exist.
+.Sh FILES
+.Bl -tag -width /etc/passwd -compact
+.It Pa /etc/passwd
+.El
+.Sh SEE ALSO
+.Xr getpwent 3 ,
+.Xr passwd 5
+.Sh HISTORY
+A
+.Fn getpw
+function appeared in
+.At v6 .
+.Sh BUGS
+The area pointed to by
+.Fa buf
+must be large enough to hold the user name.
+.Pp
+All of the bugs from
+.Xr getpwent 3
+hold valid as well.
diff --git a/lib/libcompat/4.1/getpw.c b/lib/libcompat/4.1/getpw.c
new file mode 100644
index 0000000..d6f4f8b
--- /dev/null
+++ b/lib/libcompat/4.1/getpw.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1995 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Joerg Wunsch
+ * 4. The name of the developer may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * 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$
+ */
+
+#include <sys/types.h>
+#include <pwd.h>
+#include <string.h>
+#include <stdio.h>
+
+int
+getpw(uid_t uid, char *buf)
+{
+ struct passwd *pw;
+
+ pw = getpwuid(uid);
+ endpwent();
+
+ if(pw == 0) return -1;
+
+ strncpy(buf, pw->pw_name, L_cuserid);
+ return 0;
+}
diff --git a/lib/libcompat/4.1/gtty.c b/lib/libcompat/4.1/gtty.c
new file mode 100644
index 0000000..524f1a6
--- /dev/null
+++ b/lib/libcompat/4.1/gtty.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1994 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 by Christopher G. Demetriou.
+ * 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif /* not lint */
+
+#include <sgtty.h>
+
+/*
+ * Get tty modes.
+ * This was defined in ioctl_compat.h as:
+ * #define gtty(fd, tty) ioctl(fd, TIOCGETP, tty)
+ */
+
+#undef gtty
+
+int
+gtty(fd, tty)
+ int fd;
+ struct sgttyb *tty;
+{
+
+ return (ioctl(fd, TIOCGETP, tty));
+}
diff --git a/lib/libcompat/4.1/stty.3 b/lib/libcompat/4.1/stty.3
new file mode 100644
index 0000000..71b4614
--- /dev/null
+++ b/lib/libcompat/4.1/stty.3
@@ -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.
+.\" 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.
+.\"
+.\" @(#)stty.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt STTY 3
+.Os
+.Sh NAME
+.Nm stty ,
+.Nm gtty
+.Nd set and get terminal state (defunct)
+.Sh LIBRARY
+.Lb libcompat
+.Sh SYNOPSIS
+.In sgtty.h
+.Ft int
+.Fn stty "int fd" "struct sgttyb *buf"
+.Ft int
+.Fn gtty "int fd" "struct sgttyb *buf"
+.Sh DESCRIPTION
+.Bf -symbolic
+These interfaces are obsoleted by
+.Xr ioctl 2 .
+.Ef
+.Pp
+The
+.Fn stty
+function
+sets the state of the terminal associated with
+.Fa fd .
+The
+.Fn gtty
+function
+retrieves the state of the terminal associated
+with
+.Fa fd .
+To set the state of a terminal the call must have
+write permission.
+.Pp
+The
+.Fn stty
+call is actually
+.Ql ioctl(fd, TIOCSETP, buf) ,
+while
+the
+.Fn gtty
+call is
+.Ql ioctl(fd, TIOCGETP, buf) .
+See
+.Xr ioctl 2
+and
+.Xr tty 4
+for an explanation.
+.Sh DIAGNOSTICS
+If the call is successful 0 is returned, otherwise \-1 is
+returned and the global variable
+.Va errno
+contains the reason for the failure.
+.Sh SEE ALSO
+.Xr ioctl 2 ,
+.Xr tty 4
+.Sh HISTORY
+The
+.Fn stty
+and
+.Fn gtty
+functions appeared in
+.Bx 4.2 .
diff --git a/lib/libcompat/4.1/stty.c b/lib/libcompat/4.1/stty.c
new file mode 100644
index 0000000..cf0137f
--- /dev/null
+++ b/lib/libcompat/4.1/stty.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1994 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 by Christopher G. Demetriou.
+ * 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif /* not lint */
+
+#include <sgtty.h>
+
+/*
+ * Set tty modes.
+ * This was defined in ioctl_compat.h as:
+ * #define stty(fd, tty) ioctl(fd, TIOCSETP, tty)
+ */
+
+#undef stty
+
+int
+stty(fd, tty)
+ int fd;
+ struct sgttyb *tty;
+{
+
+ return (ioctl(fd, TIOCSETP, tty));
+}
diff --git a/lib/libcompat/4.3/cfree.3 b/lib/libcompat/4.3/cfree.3
new file mode 100644
index 0000000..4d380e4
--- /dev/null
+++ b/lib/libcompat/4.3/cfree.3
@@ -0,0 +1,49 @@
+.\"
+.\" Copyright (c) 1995 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$
+.\" " <- this is for hilit19 :)
+.Dd November 23, 1995
+.Dt CFREE 3
+.Os
+.Sh NAME
+.Nm cfree
+.Nd free up allocated memory
+.Sh LIBRARY
+.Lb libcompat
+.Sh SYNOPSIS
+.Ft void
+.Fn cfree "void *"
+.Sh DESCRIPTION
+.Bf -symbolic
+The cfree function considered obsolete.
+.Ef
+.Pp
+The
+.Nm
+function is a synonym for
+.Xr free 3 .
+.Sh SEE ALSO
+.Xr free 3
diff --git a/lib/libcompat/4.3/cfree.c b/lib/libcompat/4.3/cfree.c
new file mode 100644
index 0000000..7f029ff
--- /dev/null
+++ b/lib/libcompat/4.3/cfree.c
@@ -0,0 +1,45 @@
+/*-
+ * 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. 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)cfree.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+#include <stdlib.h>
+
+void
+cfree(p)
+ void *p;
+{
+ free(p);
+}
diff --git a/lib/libcompat/4.3/re_comp.3 b/lib/libcompat/4.3/re_comp.3
new file mode 100644
index 0000000..902ef3d
--- /dev/null
+++ b/lib/libcompat/4.3/re_comp.3
@@ -0,0 +1,129 @@
+.\" 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. 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_comp.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt RE_COMP 3
+.Os
+.Sh NAME
+.Nm re_comp ,
+.Nm re_exec
+.Nd regular expression handler
+.Sh LIBRARY
+.Lb libcompat
+.Sh SYNOPSIS
+.In unistd.h
+.Ft char *
+.Fn re_comp "const char *s"
+.Ft int
+.Fn re_exec "const char *s"
+.Sh DESCRIPTION
+.Bf -symbolic
+This interface is made obsolete by
+.Xr regex 3 .
+.Ef
+.Pp
+The
+.Fn re_comp
+function
+compiles a string into an internal form suitable for pattern matching.
+The
+.Fn re_exec
+function
+checks the argument string against the last string passed to
+.Fn re_comp .
+.Pp
+The
+.Fn re_comp
+function
+returns 0 if the string
+.Fa s
+was compiled successfully; otherwise a string containing an
+error message is returned.
+If
+.Fn re_comp
+is passed 0 or a null string, it returns without changing the currently
+compiled regular expression.
+.Pp
+The
+.Fn re_exec
+function
+returns 1 if the string
+.Fa s
+matches the last compiled regular expression, 0 if the string
+.Fa s
+failed to match the last compiled regular expression, and \-1 if the compiled
+regular expression was invalid (indicating an internal error).
+.Pp
+The strings passed to both
+.Fn re_comp
+and
+.Fn re_exec
+may have trailing or embedded newline characters;
+they are terminated by
+.Dv NUL Ns s .
+The regular expressions recognized are described in the manual entry for
+.Xr ed 1 ,
+given the above difference.
+.Sh DIAGNOSTICS
+The
+.Fn re_exec
+function
+returns \-1 for an internal error.
+.Pp
+The
+.Fn re_comp
+function
+returns one of the following strings if an error occurs:
+.Bd -unfilled -offset indent
+No previous regular expression,
+Regular expression too long,
+unmatched \e(,
+missing ],
+too many \e(\e) pairs,
+unmatched \e).
+.Ed
+.Sh SEE ALSO
+.Xr ed 1 ,
+.Xr egrep 1 ,
+.Xr ex 1 ,
+.Xr fgrep 1 ,
+.Xr grep 1 ,
+.Xr regex 3
+.Sh HISTORY
+The
+.Fn re_comp
+and
+.Fn re_exec
+functions appeared in
+.Bx 4.0 .
diff --git a/lib/libcompat/4.3/regex.c b/lib/libcompat/4.3/regex.c
new file mode 100644
index 0000000..07566b5
--- /dev/null
+++ b/lib/libcompat/4.3/regex.c
@@ -0,0 +1,96 @@
+/*-
+ * Copyright (c) 1992 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * James da Silva at the University of Maryland at College Park.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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.
+ */
+
+/*
+ * Compatibility routines that implement the old re_comp/re_exec interface in
+ * terms of the regcomp/regexec interface. It's possible that some programs
+ * rely on dark corners of re_comp/re_exec and won't work with this version,
+ * but most programs should be fine.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)regex.c 5.1 (Berkeley) 3/29/92";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <stddef.h>
+#include <regexp.h>
+#include <string.h>
+#include <stdlib.h>
+#include <string.h>
+
+static regexp *re_regexp;
+static int re_goterr;
+static char *re_errstr;
+
+char *
+re_comp(s)
+ char *s;
+{
+ if (s == NULL || *s == '\0') {
+ if (re_regexp == NULL)
+ return "no previous regular expression";
+ return (NULL);
+ }
+ if (re_regexp)
+ free(re_regexp);
+ if (re_errstr)
+ free(re_errstr);
+ re_goterr = 0;
+ re_regexp = regcomp(s);
+ return (re_goterr ? re_errstr : NULL);
+}
+
+int
+re_exec(s)
+ char *s;
+{
+ int rc;
+
+ re_goterr = 0;
+ rc = regexec(re_regexp, s);
+ return (re_goterr ? -1 : rc);
+}
+
+void
+regerror(s)
+ const char *s;
+{
+ re_goterr = 1;
+ if (re_errstr)
+ free(re_errstr);
+ re_errstr = strdup(s);
+}
diff --git a/lib/libcompat/4.3/rexec.3 b/lib/libcompat/4.3/rexec.3
new file mode 100644
index 0000000..5faf8ea
--- /dev/null
+++ b/lib/libcompat/4.3/rexec.3
@@ -0,0 +1,135 @@
+.\" 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. 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.
+.\"
+.\" @(#)rexec.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt REXEC 3
+.Os
+.Sh NAME
+.Nm rexec
+.Nd return stream to a remote command
+.Sh LIBRARY
+.Lb libcompat
+.Sh SYNOPSIS
+.Ft int
+.Fn rexec "char **ahost" "int inport" "char *user" "char *passwd" "char *cmd" "int *fd2p"
+.Sh DESCRIPTION
+.Bf -symbolic
+This interface is obsoleted by
+.Xr rcmd 3 .
+.Ef
+.Pp
+The
+.Fn rexec
+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.
+If a username and password are both specified, then these
+are used to authenticate to the foreign host; otherwise
+the environment and then the user's
+.Pa .netrc
+file in his
+home directory are searched for appropriate information.
+If all this fails, the user is prompted for the information.
+.Pp
+The port
+.Fa inport
+specifies which well-known
+.Tn DARPA
+Internet port to use for
+the connection; the call
+.Fn getservbyname \*qexec\*q \*qtcp\*q
+(see
+.Xr getservent 3 )
+will return a pointer to a structure, which contains the
+necessary port.
+The protocol for connection is described in detail in
+.Xr rexecd 8 .
+.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 setup, 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.
+The diagnostic
+information returned does not include remote authorization failure,
+as the secondary connection is set up after authorization has been
+verified.
+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.
+.Sh SEE ALSO
+.Xr rcmd 3 ,
+.Xr rexecd 8
+.Sh HISTORY
+The
+.Fn rexec
+function appeared in
+.Bx 4.2 .
+.Sh BUGS
+The
+.Fn rexec
+function sends the unencrypted password across the network.
+.Pp
+The underlying service is considered a big security hole and therefore
+not enabled on many sites, see
+.Xr rexecd 8
+for explanations.
diff --git a/lib/libcompat/4.3/rexec.c b/lib/libcompat/4.3/rexec.c
new file mode 100644
index 0000000..2fc85da
--- /dev/null
+++ b/lib/libcompat/4.3/rexec.c
@@ -0,0 +1,393 @@
+/*
+ * 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.
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)rexec.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <netinet/in.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <netdb.h>
+#include <errno.h>
+#include <ctype.h>
+#include <err.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int rexecoptions;
+char *getpass(), *getlogin();
+
+/*
+ * Options and other state info.
+ */
+struct macel {
+ char mac_name[9]; /* macro name */
+ char *mac_start; /* start of macro in macbuf */
+ char *mac_end; /* end of macro in macbuf */
+};
+
+int macnum; /* number of defined macros */
+struct macel macros[16];
+char macbuf[4096];
+
+static FILE *cfile;
+
+#define DEFAULT 1
+#define LOGIN 2
+#define PASSWD 3
+#define ACCOUNT 4
+#define MACDEF 5
+#define ID 10
+#define MACH 11
+
+static char tokval[100];
+
+static struct toktab {
+ char *tokstr;
+ int tval;
+} toktab[]= {
+ { "default", DEFAULT },
+ { "login", LOGIN },
+ { "password", PASSWD },
+ { "passwd", PASSWD },
+ { "account", ACCOUNT },
+ { "machine", MACH },
+ { "macdef", MACDEF },
+ { NULL, 0 }
+};
+
+static int
+token()
+{
+ char *cp;
+ int c;
+ struct toktab *t;
+
+ if (feof(cfile) || ferror(cfile))
+ return (0);
+ while ((c = getc(cfile)) != EOF &&
+ (c == '\n' || c == '\t' || c == ' ' || c == ','))
+ continue;
+ if (c == EOF)
+ return (0);
+ cp = tokval;
+ if (c == '"') {
+ while ((c = getc(cfile)) != EOF && c != '"') {
+ if (c == '\\')
+ c = getc(cfile);
+ *cp++ = c;
+ }
+ } else {
+ *cp++ = c;
+ while ((c = getc(cfile)) != EOF
+ && c != '\n' && c != '\t' && c != ' ' && c != ',') {
+ if (c == '\\')
+ c = getc(cfile);
+ *cp++ = c;
+ }
+ }
+ *cp = 0;
+ if (tokval[0] == 0)
+ return (0);
+ for (t = toktab; t->tokstr; t++)
+ if (!strcmp(t->tokstr, tokval))
+ return (t->tval);
+ return (ID);
+}
+
+static int
+ruserpass(host, aname, apass, aacct)
+ char *host, **aname, **apass, **aacct;
+{
+ char *hdir, buf[BUFSIZ], *tmp;
+ char myname[MAXHOSTNAMELEN], *mydomain;
+ int t, i, c, usedefault = 0;
+ struct stat stb;
+
+ hdir = getenv("HOME");
+ if (hdir == NULL)
+ hdir = ".";
+ if (strlen(hdir) + 8 > sizeof(buf))
+ return (0);
+ (void) sprintf(buf, "%s/.netrc", hdir);
+ cfile = fopen(buf, "r");
+ if (cfile == NULL) {
+ if (errno != ENOENT)
+ warn("%s", buf);
+ return (0);
+ }
+ if (gethostname(myname, sizeof(myname)) < 0)
+ myname[0] = '\0';
+ if ((mydomain = strchr(myname, '.')) == NULL)
+ mydomain = "";
+next:
+ while ((t = token())) switch(t) {
+
+ case DEFAULT:
+ usedefault = 1;
+ /* FALL THROUGH */
+
+ case MACH:
+ if (!usedefault) {
+ if (token() != ID)
+ continue;
+ /*
+ * Allow match either for user's input host name
+ * or official hostname. Also allow match of
+ * incompletely-specified host in local domain.
+ */
+ if (strcasecmp(host, tokval) == 0)
+ goto match;
+ if ((tmp = strchr(host, '.')) != NULL &&
+ strcasecmp(tmp, mydomain) == 0 &&
+ strncasecmp(host, tokval, tmp - host) == 0 &&
+ tokval[tmp - host] == '\0')
+ goto match;
+ continue;
+ }
+ match:
+ while ((t = token()) && t != MACH && t != DEFAULT) switch(t) {
+
+ case LOGIN:
+ if (token())
+ if (*aname == 0) {
+ *aname = malloc((unsigned) strlen(tokval) + 1);
+ (void) strcpy(*aname, tokval);
+ } else {
+ if (strcmp(*aname, tokval))
+ goto next;
+ }
+ break;
+ case PASSWD:
+ if ((*aname == 0 || strcmp(*aname, "anonymous")) &&
+ fstat(fileno(cfile), &stb) >= 0 &&
+ (stb.st_mode & 077) != 0) {
+ warnx("Error: .netrc file is readable by others.");
+ warnx("Remove password or make file unreadable by others.");
+ goto bad;
+ }
+ if (token() && *apass == 0) {
+ *apass = malloc((unsigned) strlen(tokval) + 1);
+ (void) strcpy(*apass, tokval);
+ }
+ break;
+ case ACCOUNT:
+ if (fstat(fileno(cfile), &stb) >= 0
+ && (stb.st_mode & 077) != 0) {
+ warnx("Error: .netrc file is readable by others.");
+ warnx("Remove account or make file unreadable by others.");
+ goto bad;
+ }
+ if (token() && *aacct == 0) {
+ *aacct = malloc((unsigned) strlen(tokval) + 1);
+ (void) strcpy(*aacct, tokval);
+ }
+ break;
+ case MACDEF:
+ while ((c=getc(cfile)) != EOF &&
+ (c == ' ' || c == '\t'))
+ ;
+ if (c == EOF || c == '\n') {
+ printf("Missing macdef name argument.\n");
+ goto bad;
+ }
+ if (macnum == 16) {
+ printf("Limit of 16 macros have already been defined\n");
+ goto bad;
+ }
+ tmp = macros[macnum].mac_name;
+ *tmp++ = c;
+ for (i=0; i < 8 && (c=getc(cfile)) != EOF &&
+ !isspace(c); ++i) {
+ *tmp++ = c;
+ }
+ if (c == EOF) {
+ printf("Macro definition missing null line terminator.\n");
+ goto bad;
+ }
+ *tmp = '\0';
+ if (c != '\n') {
+ while ((c=getc(cfile)) != EOF && c != '\n');
+ }
+ if (c == EOF) {
+ printf("Macro definition missing null line terminator.\n");
+ goto bad;
+ }
+ if (macnum == 0) {
+ macros[macnum].mac_start = macbuf;
+ }
+ else {
+ macros[macnum].mac_start = macros[macnum-1].mac_end + 1;
+ }
+ tmp = macros[macnum].mac_start;
+ while (tmp != macbuf + 4096) {
+ if ((c=getc(cfile)) == EOF) {
+ printf("Macro definition missing null line terminator.\n");
+ goto bad;
+ }
+ *tmp = c;
+ if (*tmp == '\n') {
+ if (*(tmp-1) == '\0') {
+ macros[macnum++].mac_end = tmp - 1;
+ break;
+ }
+ *tmp = '\0';
+ }
+ tmp++;
+ }
+ if (tmp == macbuf + 4096) {
+ printf("4K macro buffer exceeded\n");
+ goto bad;
+ }
+ break;
+ default:
+ warnx("Unknown .netrc keyword %s", tokval);
+ break;
+ }
+ goto done;
+ }
+done:
+ (void) fclose(cfile);
+ return (0);
+bad:
+ (void) fclose(cfile);
+ return (-1);
+}
+
+int
+rexec(ahost, rport, name, pass, cmd, fd2p)
+ char **ahost;
+ int rport;
+ char *name, *pass, *cmd;
+ int *fd2p;
+{
+ struct sockaddr_in sin, sin2, from;
+ struct hostent *hp;
+ u_short port;
+ int s, timo = 1, s3;
+ char c;
+
+ hp = gethostbyname(*ahost);
+ if (hp == 0) {
+ herror(*ahost);
+ return (-1);
+ }
+ *ahost = hp->h_name;
+ ruserpass(hp->h_name, &name, &pass);
+retry:
+ s = socket(AF_INET, SOCK_STREAM, 0);
+ if (s < 0) {
+ perror("rexec: socket");
+ return (-1);
+ }
+ sin.sin_family = hp->h_addrtype;
+ sin.sin_port = rport;
+ bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
+ if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
+ if (errno == ECONNREFUSED && timo <= 16) {
+ (void) close(s);
+ sleep(timo);
+ timo *= 2;
+ goto retry;
+ }
+ perror(hp->h_name);
+ return (-1);
+ }
+ if (fd2p == 0) {
+ (void) write(s, "", 1);
+ port = 0;
+ } else {
+ char num[8];
+ int s2, sin2len;
+
+ s2 = socket(AF_INET, SOCK_STREAM, 0);
+ if (s2 < 0) {
+ (void) close(s);
+ return (-1);
+ }
+ listen(s2, 1);
+ sin2len = sizeof (sin2);
+ if (getsockname(s2, (struct sockaddr *)&sin2, &sin2len) < 0 ||
+ sin2len != sizeof (sin2)) {
+ perror("getsockname");
+ (void) close(s2);
+ goto bad;
+ }
+ port = ntohs((u_short)sin2.sin_port);
+ (void) sprintf(num, "%u", port);
+ (void) write(s, num, strlen(num)+1);
+ { int len = sizeof (from);
+ s3 = accept(s2, (struct sockaddr *)&from, &len);
+ close(s2);
+ if (s3 < 0) {
+ perror("accept");
+ port = 0;
+ goto bad;
+ }
+ }
+ *fd2p = s3;
+ }
+ (void) write(s, name, strlen(name) + 1);
+ /* should public key encypt the password here */
+ (void) write(s, pass, strlen(pass) + 1);
+ (void) write(s, cmd, strlen(cmd) + 1);
+ if (read(s, &c, 1) != 1) {
+ perror(*ahost);
+ goto bad;
+ }
+ if (c != 0) {
+ while (read(s, &c, 1) == 1) {
+ (void) write(2, &c, 1);
+ if (c == '\n')
+ break;
+ }
+ goto bad;
+ }
+ return (s);
+bad:
+ if (port)
+ (void) close(*fd2p);
+ (void) close(s);
+ return (-1);
+}
diff --git a/lib/libcompat/4.4/cuserid.3 b/lib/libcompat/4.4/cuserid.3
new file mode 100644
index 0000000..72811d5
--- /dev/null
+++ b/lib/libcompat/4.4/cuserid.3
@@ -0,0 +1,87 @@
+.\"
+.\" Copyright (c) 1995 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.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by Joerg Wunsch
+.\" 4. The name of the developer may not be used to endorse or promote
+.\" products derived from this software without specific prior written
+.\" permission.
+.\"
+.\" 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 April 10, 1995
+.Os
+.Dt CUSERID 3
+.Sh NAME
+.Nm cuserid
+.Nd get user name associated with effective UID
+.Sh LIBRARY
+.Lb libcompat
+.Sh SYNOPSIS
+.In stdio.h
+.Ft char *
+.Fn cuserid "char *s"
+.Sh DESCRIPTION
+.Bf -symbolic
+The
+.Fn cuserid
+function is made obsolete by
+.Xr getpwuid 3 .
+.Ef
+.Pp
+The function
+.Fn cuserid
+gets the user name associated with the effective UID of the current
+process.
+If the argument
+.Fa s
+is non-NULL, the name is copied to the buffer it points to,
+and that address is being returned.
+This buffer must provide space
+for at least
+.Em L_cuserid
+characters.
+The L_cuserid constant is defined in
+.In stdio.h .
+.Pp
+If
+.Fa s
+is NULL, an internal array is used and its address will be returned.
+.Sh RETURN VALUES
+The
+.Fn cuserid
+function returns the address of an array in which the name has been stored.
+.Pp
+If the name associated with the effective UID of the current process
+could not be found, either a null pointer will be returned, or
+(if
+.Fa s
+is non-NULL)
+the buffer
+.Fa s
+will be filled with a null string.
+.Sh SEE ALSO
+.Xr geteuid 2 ,
+.Xr getpwuid 3
diff --git a/lib/libcompat/4.4/cuserid.c b/lib/libcompat/4.4/cuserid.c
new file mode 100644
index 0000000..e2f0988f
--- /dev/null
+++ b/lib/libcompat/4.4/cuserid.c
@@ -0,0 +1,61 @@
+/*-
+ * 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. 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)cuserid.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <pwd.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+char *
+cuserid(s)
+ char *s;
+{
+ struct passwd *pwd;
+
+ if ((pwd = getpwuid(geteuid())) == NULL) {
+ if (s)
+ *s = '\0';
+ return (s);
+ }
+ if (s) {
+ (void)strncpy(s, pwd->pw_name, L_cuserid);
+ return (s);
+ }
+ return (pwd->pw_name);
+}
diff --git a/lib/libcompat/Makefile b/lib/libcompat/Makefile
new file mode 100644
index 0000000..b9b174d
--- /dev/null
+++ b/lib/libcompat/Makefile
@@ -0,0 +1,47 @@
+# @(#)Makefile 8.1 (Berkeley) 6/4/93
+# $FreeBSD$
+
+LIB=compat
+CFLAGS+=-DLIBC_SCCS -DSYSLIBC_SCCS -I${.CURDIR}/../libc/locale
+NO_PIC=
+
+.PATH: ${.CURDIR}/4.1/${MACHINE_ARCH} ${.CURDIR}/4.1 \
+ ${.CURDIR}/4.3/${MACHINE_ARCH} ${.CURDIR}/4.3 \
+ ${.CURDIR}/4.4/${MACHINE_ARCH} ${.CURDIR}/4.4 \
+ ${.CURDIR}/regexp
+
+# compat 4.1 sources
+# XXX MISSING: tell.c
+SRCS+= ascftime.c cftime.c ftime.c getpw.c gtty.c stty.c
+
+MAN+= 4.1/ftime.3 4.1/getpw.3 4.1/stty.3
+MAN+= 4.1/cftime.3
+
+MLINKS+=stty.3 gtty.3
+MLINKS+=cftime.3 ascftime.3
+
+# compat 4.3 sources
+# XXX MISSING: ecvt.c gcvt.c sibuf.c sobuf.c strout.c
+SRCS+= cfree.c regex.c rexec.c
+
+# XXX MISSING: ecvt.0
+MAN+= 4.3/cfree.3 4.3/re_comp.3 4.3/rexec.3
+
+# XXX MISSING: ecvt.3, so can't MLINK
+#MLINKS+=ecvt.3 fcvt.3 ecvt.3 gcvt.3
+MLINKS+=re_comp.3 re_exec.3
+
+# compat 4.4 sources
+SRCS+= cuserid.c
+MAN+= 4.4/cuserid.3
+
+# regexp sources
+SRCS+= regerror.c regexp.c regsub.c
+
+MAN+= regexp/regexp.3
+
+# XXX name clash with libc
+# MLINKS+=regexp.3 regcomp.3 regexp.3 regexec.3 regexp.3 regerror.3
+MLINKS+=regexp.3 regsub.3
+
+.include <bsd.lib.mk>
diff --git a/lib/libcompat/regexp/COPYRIGHT b/lib/libcompat/regexp/COPYRIGHT
new file mode 100644
index 0000000..48b3f43
--- /dev/null
+++ b/lib/libcompat/regexp/COPYRIGHT
@@ -0,0 +1,22 @@
+This entire subtree is copyright the University of Toronto.
+The following copyright notice applies to all files found here. None of
+these files contain AT&T proprietary source code.
+_____________________________________________________________________________
+
+ Copyright (c) 1986 by University of Toronto.
+ Written by Henry Spencer. Not derived from licensed software.
+
+ Permission is granted to anyone to use this software for any
+ purpose on any computer system, and to redistribute it freely,
+ 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 defects in it.
+
+ 2. The origin of this software must not be misrepresented, either
+ by explicit claim or by omission.
+
+ 3. Altered versions must be plainly marked as such, and must not
+ be misrepresented as being the original software.
+
diff --git a/lib/libcompat/regexp/README b/lib/libcompat/regexp/README
new file mode 100644
index 0000000..37d6f51
--- /dev/null
+++ b/lib/libcompat/regexp/README
@@ -0,0 +1,84 @@
+This is a nearly-public-domain reimplementation of the V8 regexp(3) package.
+It gives C programs the ability to use egrep-style regular expressions, and
+does it in a much cleaner fashion than the analogous routines in SysV.
+
+ Copyright (c) 1986 by University of Toronto.
+ Written by Henry Spencer. Not derived from licensed software.
+
+ Permission is granted to anyone to use this software for any
+ purpose on any computer system, and to redistribute it freely,
+ 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 defects in it.
+
+ 2. The origin of this software must not be misrepresented, either
+ by explicit claim or by omission.
+
+ 3. Altered versions must be plainly marked as such, and must not
+ be misrepresented as being the original software.
+
+Barring a couple of small items in the BUGS list, this implementation is
+believed 100% compatible with V8. It should even be binary-compatible,
+sort of, since the only fields in a "struct regexp" that other people have
+any business touching are declared in exactly the same way at the same
+location in the struct (the beginning).
+
+This implementation is *NOT* AT&T/Bell code, and is not derived from licensed
+software. Even though U of T is a V8 licensee. This software is based on
+a V8 manual page sent to me by Dennis Ritchie (the manual page enclosed
+here is a complete rewrite and hence is not covered by AT&T copyright).
+The software was nearly complete at the time of arrival of our V8 tape.
+I haven't even looked at V8 yet, although a friend elsewhere at U of T has
+been kind enough to run a few test programs using the V8 regexp(3) to resolve
+a few fine points. I admit to some familiarity with regular-expression
+implementations of the past, but the only one that this code traces any
+ancestry to is the one published in Kernighan & Plauger (from which this
+one draws ideas but not code).
+
+Simplistically: put this stuff into a source directory, copy regexp.h into
+/usr/include, inspect Makefile for compilation options that need changing
+to suit your local environment, and then do "make r". This compiles the
+regexp(3) functions, compiles a test program, and runs a large set of
+regression tests. If there are no complaints, then put regexp.o, regsub.o,
+and regerror.o into your C library, and regexp.3 into your manual-pages
+directory.
+
+Note that if you don't put regexp.h into /usr/include *before* compiling,
+you'll have to add "-I." to CFLAGS before compiling.
+
+The files are:
+
+Makefile instructions to make everything
+regexp.3 manual page
+regexp.h header file, for /usr/include
+regexp.c source for regcomp() and regexec()
+regsub.c source for regsub()
+regerror.c source for default regerror()
+regmagic.h internal header file
+try.c source for test program
+timer.c source for timing program
+tests test list for try and timer
+
+This implementation uses nondeterministic automata rather than the
+deterministic ones found in some other implementations, which makes it
+simpler, smaller, and faster at compiling regular expressions, but slower
+at executing them. In theory, anyway. This implementation does employ
+some special-case optimizations to make the simpler cases (which do make
+up the bulk of regular expressions actually used) run quickly. In general,
+if you want blazing speed you're in the wrong place. Replacing the insides
+of egrep with this stuff is probably a mistake; if you want your own egrep
+you're going to have to do a lot more work. But if you want to use regular
+expressions a little bit in something else, you're in luck. Note that many
+existing text editors use nondeterministic regular-expression implementations,
+so you're in good company.
+
+This stuff should be pretty portable, given appropriate option settings.
+If your chars have less than 8 bits, you're going to have to change the
+internal representation of the automaton, although knowledge of the details
+of this is fairly localized. There are no "reserved" char values except for
+NUL, and no special significance is attached to the top bit of chars.
+The string(3) functions are used a fair bit, on the grounds that they are
+probably faster than coding the operations in line. Some attempts at code
+tuning have been made, but this is invariably a bit machine-specific.
diff --git a/lib/libcompat/regexp/regerror.c b/lib/libcompat/regexp/regerror.c
new file mode 100644
index 0000000..6d0077d
--- /dev/null
+++ b/lib/libcompat/regexp/regerror.c
@@ -0,0 +1,18 @@
+#include <regexp.h>
+#include <stdio.h>
+
+void
+regerror(s)
+const char *s;
+{
+#ifdef ERRAVAIL
+ error("regexp: %s", s);
+#else
+/*
+ fprintf(stderr, "regexp(3): %s\n", s);
+ exit(1);
+*/
+ return; /* let std. egrep handle errors */
+#endif
+ /* NOTREACHED */
+}
diff --git a/lib/libcompat/regexp/regexp.3 b/lib/libcompat/regexp/regexp.3
new file mode 100644
index 0000000..7e30611
--- /dev/null
+++ b/lib/libcompat/regexp/regexp.3
@@ -0,0 +1,323 @@
+.\" 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. 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.
+.\"
+.\" @(#)regexp.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt REGEXP 3
+.Os
+.Sh NAME
+.Nm regcomp ,
+.Nm regexec ,
+.Nm regsub ,
+.Nm regerror
+.Nd regular expression handlers
+.Sh LIBRARY
+.Lb libcompat
+.Sh SYNOPSIS
+.In regexp.h
+.Ft regexp *
+.Fn regcomp "const char *exp"
+.Ft int
+.Fn regexec "const regexp *prog" "const char *string"
+.Ft void
+.Fn regsub "const regexp *prog" "const char *source" "char *dest"
+.Sh DESCRIPTION
+.Bf Sy
+This interface is made obsolete by
+.Xr regex 3 .
+.Ef
+.Pp
+The
+.Fn regcomp ,
+.Fn regexec ,
+.Fn regsub ,
+and
+.Fn regerror
+functions
+implement
+.Xr egrep 1 Ns -style
+regular expressions and supporting facilities.
+.Pp
+The
+.Fn regcomp
+function
+compiles a regular expression into a structure of type
+.Vt regexp ,
+and returns a pointer to it.
+The space has been allocated using
+.Xr malloc 3
+and may be released by
+.Xr free 3 .
+.Pp
+The
+.Fn regexec
+function
+matches a
+.Dv NUL Ns -terminated
+.Fa string
+against the compiled regular expression
+in
+.Fa prog .
+It returns 1 for success and 0 for failure, and adjusts the contents of
+.Fa prog Ns 's
+.Em startp
+and
+.Em endp
+(see below) accordingly.
+.Pp
+The members of a
+.Vt regexp
+structure include at least the following (not necessarily in order):
+.Bd -literal -offset indent
+char *startp[NSUBEXP];
+char *endp[NSUBEXP];
+.Ed
+.Pp
+where
+.Dv NSUBEXP
+is defined (as 10) in the header file.
+Once a successful
+.Fn regexec
+has been done using the
+.Fn regexp ,
+each
+.Em startp Ns - Em endp
+pair describes one substring
+within the
+.Fa string ,
+with the
+.Em startp
+pointing to the first character of the substring and
+the
+.Em endp
+pointing to the first character following the substring.
+The 0th substring is the substring of
+.Fa string
+that matched the whole
+regular expression.
+The others are those substrings that matched parenthesized expressions
+within the regular expression, with parenthesized expressions numbered
+in left-to-right order of their opening parentheses.
+.Pp
+The
+.Fn regsub
+function
+copies
+.Fa source
+to
+.Fa dest ,
+making substitutions according to the
+most recent
+.Fn regexec
+performed using
+.Fa prog .
+Each instance of `&' in
+.Fa source
+is replaced by the substring
+indicated by
+.Em startp Ns Bq
+and
+.Em endp Ns Bq .
+Each instance of
+.Sq \e Ns Em n ,
+where
+.Em n
+is a digit, is replaced by
+the substring indicated by
+.Em startp Ns Bq Em n
+and
+.Em endp Ns Bq Em n .
+To get a literal `&' or
+.Sq \e Ns Em n
+into
+.Fa dest ,
+prefix it with `\e';
+to get a literal `\e' preceding `&' or
+.Sq \e Ns Em n ,
+prefix it with
+another `\e'.
+.Pp
+The
+.Fn regerror
+function
+is called whenever an error is detected in
+.Fn regcomp ,
+.Fn regexec ,
+or
+.Fn regsub .
+The default
+.Fn regerror
+writes the string
+.Fa msg ,
+with a suitable indicator of origin,
+on the standard
+error output
+and invokes
+.Xr exit 3 .
+The
+.Fn regerror
+function
+can be replaced by the user if other actions are desirable.
+.Sh REGULAR EXPRESSION SYNTAX
+A regular expression is zero or more
+.Em branches ,
+separated by `|'.
+It matches anything that matches one of the branches.
+.Pp
+A branch is zero 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 `*', `+', or `?'.
+An atom followed by `*' matches a sequence of 0 or more matches of the atom.
+An atom followed by `+' matches a sequence of 1 or more matches of the atom.
+An atom followed by `?' matches a match of the atom, or the null string.
+.Pp
+An atom is a regular expression in parentheses (matching a match for the
+regular expression), a
+.Em range
+(see below), `.'
+(matching any single character), `^' (matching the null string at the
+beginning of the input string), `$' (matching the null string at the
+end of the input string), a `\e' followed by a single character (matching
+that character), or a single character with no other significance
+(matching that character).
+.Pp
+A
+.Em range
+is a sequence of characters enclosed in `[]'.
+It normally matches any single character from the sequence.
+If the sequence begins with `^',
+it matches any single character
+.Em not
+from the rest of the sequence.
+If two characters in the sequence are separated by `\-', this is shorthand
+for the full list of
+.Tn ASCII
+characters between them
+(e.g.\& `[0-9]' matches any decimal digit).
+To include a literal `]' in the sequence, make it the first character
+(following a possible `^').
+To include a literal `\-', make it the first or last character.
+.Sh AMBIGUITY
+If a regular expression could match two different parts of the input string,
+it will match the one which begins earliest.
+If both begin in the same place but match different lengths, or match
+the same length in different ways, life gets messier, as follows.
+.Pp
+In general, the possibilities in a list of branches are considered in
+left-to-right order, the possibilities for `*', `+', and `?' are
+considered longest-first, nested constructs are considered from the
+outermost in, and concatenated constructs are considered leftmost-first.
+The match that will be chosen is the one that uses the earliest
+possibility in the first choice that has to be made.
+If there is more than one choice, the next will be made in the same manner
+(earliest possibility) subject to the decision on the first choice.
+And so forth.
+.Pp
+For example,
+.Sq Li (ab|a)b*c
+could match
+`abc' in one of two ways.
+The first choice is between `ab' and `a'; since `ab' is earlier, and does
+lead to a successful overall match, it is chosen.
+Since the `b' is already spoken for,
+the `b*' must match its last possibility\(emthe empty string\(emsince
+it must respect the earlier choice.
+.Pp
+In the particular case where no `|'s are present and there is only one
+`*', `+', or `?', the net effect is that the longest possible
+match will be chosen.
+So
+.Sq Li ab* ,
+presented with `xabbbby', will match `abbbb'.
+Note that if
+.Sq Li ab* ,
+is tried against `xabyabbbz', it
+will match `ab' just after `x', due to the begins-earliest rule.
+(In effect, the decision on where to start the match is the first choice
+to be made, hence subsequent choices must respect it even if this leads them
+to less-preferred alternatives.)
+.Sh RETURN VALUES
+The
+.Fn regcomp
+function
+returns
+.Dv NULL
+for a failure
+.Pf ( Fn regerror
+permitting),
+where failures are syntax errors, exceeding implementation limits,
+or applying `+' or `*' to a possibly-null operand.
+.Sh SEE ALSO
+.Xr ed 1 ,
+.Xr egrep 1 ,
+.Xr ex 1 ,
+.Xr expr 1 ,
+.Xr fgrep 1 ,
+.Xr grep 1 ,
+.Xr regex 3
+.Sh HISTORY
+Both code and manual page for
+.Fn regcomp ,
+.Fn regexec ,
+.Fn regsub ,
+and
+.Fn regerror
+were written at the University of Toronto
+and appeared in
+.Bx 4.3 tahoe .
+They are intended to be compatible with the Bell V8
+.Xr regexp 3 ,
+but are not derived from Bell code.
+.Sh BUGS
+Empty branches and empty regular expressions are not portable to V8.
+.Pp
+The restriction against
+applying `*' or `+' to a possibly-null operand is an artifact of the
+simplistic implementation.
+.Pp
+Does not support
+.Xr egrep 1 Ns 's
+newline-separated branches;
+neither does the V8
+.Xr regexp 3 ,
+though.
+.Pp
+Due to emphasis on
+compactness and simplicity,
+it is not strikingly fast.
+It does give special attention to handling simple cases quickly.
diff --git a/lib/libcompat/regexp/regexp.c b/lib/libcompat/regexp/regexp.c
new file mode 100644
index 0000000..8276ffc
--- /dev/null
+++ b/lib/libcompat/regexp/regexp.c
@@ -0,0 +1,1337 @@
+/*
+ * regcomp and regexec -- regsub and regerror are elsewhere
+ *
+ * Copyright (c) 1986 by University of Toronto.
+ * Written by Henry Spencer. Not derived from licensed software.
+ *
+ * Permission is granted to anyone to use this software for any
+ * purpose on any computer system, and to redistribute it freely,
+ * 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 defects in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either
+ * by explicit claim or by omission.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not
+ * be misrepresented as being the original software.
+ *** THIS IS AN ALTERED VERSION. It was altered by John Gilmore,
+ *** hoptoad!gnu, on 27 Dec 1986, to add \n as an alternative to |
+ *** to assist in implementing egrep.
+ *** THIS IS AN ALTERED VERSION. It was altered by John Gilmore,
+ *** hoptoad!gnu, on 27 Dec 1986, to add \< and \> for word-matching
+ *** as in BSD grep and ex.
+ *** THIS IS AN ALTERED VERSION. It was altered by John Gilmore,
+ *** hoptoad!gnu, on 28 Dec 1986, to optimize characters quoted with \.
+ *** THIS IS AN ALTERED VERSION. It was altered by James A. Woods,
+ *** ames!jaw, on 19 June 1987, to quash a regcomp() redundancy.
+ *
+ * Beware that some of this code is subtly aware of the way operator
+ * precedence is structured in regular expressions. Serious changes in
+ * regular-expression syntax might require a total rethink.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <limits.h>
+#include <regexp.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include "collate.h"
+#include "regmagic.h"
+
+/*
+ * The "internal use only" fields in regexp.h are present to pass info from
+ * compile to execute that permits the execute phase to run lots faster on
+ * simple cases. They are:
+ *
+ * regstart char that must begin a match; '\0' if none obvious
+ * reganch is the match anchored (at beginning-of-line only)?
+ * regmust string (pointer into program) that match must include, or NULL
+ * regmlen length of regmust string
+ *
+ * Regstart and reganch permit very fast decisions on suitable starting points
+ * for a match, cutting down the work a lot. Regmust permits fast rejection
+ * of lines that cannot possibly match. The regmust tests are costly enough
+ * that regcomp() supplies a regmust only if the r.e. contains something
+ * potentially expensive (at present, the only such thing detected is * or +
+ * at the start of the r.e., which can involve a lot of backup). Regmlen is
+ * supplied because the test in regexec() needs it and regcomp() is computing
+ * it anyway.
+ */
+
+/*
+ * Structure for regexp "program". This is essentially a linear encoding
+ * of a nondeterministic finite-state machine (aka syntax charts or
+ * "railroad normal form" in parsing technology). Each node is an opcode
+ * plus a "next" pointer, possibly plus an operand. "Next" pointers of
+ * all nodes except BRANCH implement concatenation; a "next" pointer with
+ * a BRANCH on both ends of it is connecting two alternatives. (Here we
+ * have one of the subtle syntax dependencies: an individual BRANCH (as
+ * opposed to a collection of them) is never concatenated with anything
+ * because of operator precedence.) The operand of some types of node is
+ * a literal string; for others, it is a node leading into a sub-FSM. In
+ * particular, the operand of a BRANCH node is the first node of the branch.
+ * (NB this is *not* a tree structure: the tail of the branch connects
+ * to the thing following the set of BRANCHes.) The opcodes are:
+ */
+
+/* definition number opnd? meaning */
+#define END 0 /* no End of program. */
+#define BOL 1 /* no Match "" at beginning of line. */
+#define EOL 2 /* no Match "" at end of line. */
+#define ANY 3 /* no Match any one character. */
+#define ANYOF 4 /* str Match any character in this string. */
+#define ANYBUT 5 /* str Match any character not in this string. */
+#define BRANCH 6 /* node Match this alternative, or the next... */
+#define BACK 7 /* no Match "", "next" ptr points backward. */
+#define EXACTLY 8 /* str Match this string. */
+#define NOTHING 9 /* no Match empty string. */
+#define STAR 10 /* node Match this (simple) thing 0 or more times. */
+#define PLUS 11 /* node Match this (simple) thing 1 or more times. */
+#define WORDA 12 /* no Match "" at wordchar, where prev is nonword */
+#define WORDZ 13 /* no Match "" at nonwordchar, where prev is word */
+#define OPEN 20 /* no Mark this point in input as start of #n. */
+ /* OPEN+1 is number 1, etc. */
+#define CLOSE 30 /* no Analogous to OPEN. */
+
+/*
+ * Opcode notes:
+ *
+ * BRANCH The set of branches constituting a single choice are hooked
+ * together with their "next" pointers, since precedence prevents
+ * anything being concatenated to any individual branch. The
+ * "next" pointer of the last BRANCH in a choice points to the
+ * thing following the whole choice. This is also where the
+ * final "next" pointer of each individual branch points; each
+ * branch starts with the operand node of a BRANCH node.
+ *
+ * BACK Normal "next" pointers all implicitly point forward; BACK
+ * exists to make loop structures possible.
+ *
+ * STAR,PLUS '?', and complex '*' and '+', are implemented as circular
+ * BRANCH structures using BACK. Simple cases (one character
+ * per match) are implemented with STAR and PLUS for speed
+ * and to minimize recursive plunges.
+ *
+ * OPEN,CLOSE ...are numbered at compile time.
+ */
+
+/*
+ * A node is one char of opcode followed by two chars of "next" pointer.
+ * "Next" pointers are stored as two 8-bit pieces, high order first. The
+ * value is a positive offset from the opcode of the node containing it.
+ * An operand, if any, simply follows the node. (Note that much of the
+ * code generation knows about this implicit relationship.)
+ *
+ * Using two bytes for the "next" pointer is vast overkill for most things,
+ * but allows patterns to get big without disasters.
+ */
+#define OP(p) (*(p))
+#define NEXT(p) (((*((p)+1)&0377)<<8) + (*((p)+2)&0377))
+#define OPERAND(p) ((p) + 3)
+
+/*
+ * See regmagic.h for one further detail of program structure.
+ */
+
+
+/*
+ * Utility definitions.
+ */
+#ifndef CHARBITS
+#define UCHARAT(p) ((int)*(unsigned char *)(p))
+#else
+#define UCHARAT(p) ((int)*(p)&CHARBITS)
+#endif
+
+#define FAIL(m) { regerror(m); return(NULL); }
+#define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?')
+
+/*
+ * Flags to be passed up and down.
+ */
+#define HASWIDTH 01 /* Known never to match null string. */
+#define SIMPLE 02 /* Simple enough to be STAR/PLUS operand. */
+#define SPSTART 04 /* Starts with * or +. */
+#define WORST 0 /* Worst case. */
+
+/*
+ * Global work variables for regcomp().
+ */
+static char *regparse; /* Input-scan pointer. */
+static int regnpar; /* () count. */
+static char regdummy;
+static char *regcode; /* Code-emit pointer; &regdummy = don't. */
+static long regsize; /* Code size. */
+
+/*
+ * Forward declarations for regcomp()'s friends.
+ */
+#ifndef STATIC
+#define STATIC static
+#endif
+STATIC char *reg();
+STATIC char *regbranch();
+STATIC char *regpiece();
+STATIC char *regatom();
+STATIC char *regnode();
+STATIC char *regnext();
+STATIC void regc();
+STATIC void reginsert();
+STATIC void regtail();
+STATIC void regoptail();
+#ifdef STRCSPN
+STATIC int strcspn();
+#endif
+
+/*
+ - regcomp - compile a regular expression into internal code
+ *
+ * We can't allocate space until we know how big the compiled form will be,
+ * but we can't compile it (and thus know how big it is) until we've got a
+ * place to put the code. So we cheat: we compile it twice, once with code
+ * generation turned off and size counting turned on, and once "for real".
+ * This also means that we don't allocate space until we are sure that the
+ * thing really will compile successfully, and we never have to move the
+ * code and thus invalidate pointers into it. (Note that it has to be in
+ * one piece because free() must be able to free it all.)
+ *
+ * Beware that the optimization-preparation code in here knows about some
+ * of the structure of the compiled regexp.
+ */
+regexp *
+regcomp(exp)
+const char *exp;
+{
+ regexp *r;
+ char *scan;
+ char *longest;
+ int len;
+ int flags;
+
+ if (exp == NULL)
+ FAIL("NULL argument");
+
+ /* First pass: determine size, legality. */
+#ifdef notdef
+ if (exp[0] == '.' && exp[1] == '*') exp += 2; /* aid grep */
+#endif
+ regparse = (char *)exp;
+ regnpar = 1;
+ regsize = 0L;
+ regcode = &regdummy;
+ regc(MAGIC);
+ if (reg(0, &flags) == NULL)
+ return(NULL);
+
+ /* Small enough for pointer-storage convention? */
+ if (regsize >= 32767L) /* Probably could be 65535L. */
+ FAIL("regexp too big");
+
+ /* Allocate space. */
+ r = (regexp *)malloc(sizeof(regexp) + (unsigned)regsize);
+ if (r == NULL)
+ FAIL("out of space");
+
+ /* Second pass: emit code. */
+ regparse = (char *)exp;
+ regnpar = 1;
+ regcode = r->program;
+ regc(MAGIC);
+ if (reg(0, &flags) == NULL)
+ return(NULL);
+
+ /* Dig out information for optimizations. */
+ r->regstart = '\0'; /* Worst-case defaults. */
+ r->reganch = 0;
+ r->regmust = NULL;
+ r->regmlen = 0;
+ scan = r->program+1; /* First BRANCH. */
+ if (OP(regnext(scan)) == END) { /* Only one top-level choice. */
+ scan = OPERAND(scan);
+
+ /* Starting-point info. */
+ if (OP(scan) == EXACTLY)
+ r->regstart = *OPERAND(scan);
+ else if (OP(scan) == BOL)
+ r->reganch++;
+
+ /*
+ * If there's something expensive in the r.e., find the
+ * longest literal string that must appear and make it the
+ * regmust. Resolve ties in favor of later strings, since
+ * the regstart check works with the beginning of the r.e.
+ * and avoiding duplication strengthens checking. Not a
+ * strong reason, but sufficient in the absence of others.
+ */
+ if (flags&SPSTART) {
+ longest = NULL;
+ len = 0;
+ for (; scan != NULL; scan = regnext(scan))
+ if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) {
+ longest = OPERAND(scan);
+ len = strlen(OPERAND(scan));
+ }
+ r->regmust = longest;
+ r->regmlen = len;
+ }
+ }
+
+ return(r);
+}
+
+/*
+ - reg - regular expression, i.e. main body or parenthesized thing
+ *
+ * Caller must absorb opening parenthesis.
+ *
+ * Combining parenthesis handling with the base level of regular expression
+ * is a trifle forced, but the need to tie the tails of the branches to what
+ * follows makes it hard to avoid.
+ */
+static char *
+reg(paren, flagp)
+int paren; /* Parenthesized? */
+int *flagp;
+{
+ char *ret;
+ char *br;
+ char *ender;
+ int parno;
+ int flags;
+
+ *flagp = HASWIDTH; /* Tentatively. */
+
+ /* Make an OPEN node, if parenthesized. */
+ if (paren) {
+ if (regnpar >= NSUBEXP)
+ FAIL("too many ()");
+ parno = regnpar;
+ regnpar++;
+ ret = regnode(OPEN+parno);
+ } else
+ ret = NULL;
+
+ /* Pick up the branches, linking them together. */
+ br = regbranch(&flags);
+ if (br == NULL)
+ return(NULL);
+ if (ret != NULL)
+ regtail(ret, br); /* OPEN -> first. */
+ else
+ ret = br;
+ if (!(flags&HASWIDTH))
+ *flagp &= ~HASWIDTH;
+ *flagp |= flags&SPSTART;
+ while (*regparse == '|' || *regparse == '\n') {
+ regparse++;
+ br = regbranch(&flags);
+ if (br == NULL)
+ return(NULL);
+ regtail(ret, br); /* BRANCH -> BRANCH. */
+ if (!(flags&HASWIDTH))
+ *flagp &= ~HASWIDTH;
+ *flagp |= flags&SPSTART;
+ }
+
+ /* Make a closing node, and hook it on the end. */
+ ender = regnode((paren) ? CLOSE+parno : END);
+ regtail(ret, ender);
+
+ /* Hook the tails of the branches to the closing node. */
+ for (br = ret; br != NULL; br = regnext(br))
+ regoptail(br, ender);
+
+ /* Check for proper termination. */
+ if (paren && *regparse++ != ')') {
+ FAIL("unmatched ()");
+ } else if (!paren && *regparse != '\0') {
+ if (*regparse == ')') {
+ FAIL("unmatched ()");
+ } else
+ FAIL("junk on end"); /* "Can't happen". */
+ /* NOTREACHED */
+ }
+
+ return(ret);
+}
+
+/*
+ - regbranch - one alternative of an | operator
+ *
+ * Implements the concatenation operator.
+ */
+static char *
+regbranch(flagp)
+int *flagp;
+{
+ char *ret;
+ char *chain;
+ char *latest;
+ int flags;
+
+ *flagp = WORST; /* Tentatively. */
+
+ ret = regnode(BRANCH);
+ chain = NULL;
+ while (*regparse != '\0' && *regparse != ')' &&
+ *regparse != '\n' && *regparse != '|') {
+ latest = regpiece(&flags);
+ if (latest == NULL)
+ return(NULL);
+ *flagp |= flags&HASWIDTH;
+ if (chain == NULL) /* First piece. */
+ *flagp |= flags&SPSTART;
+ else
+ regtail(chain, latest);
+ chain = latest;
+ }
+ if (chain == NULL) /* Loop ran zero times. */
+ (void) regnode(NOTHING);
+
+ return(ret);
+}
+
+/*
+ - regpiece - something followed by possible [*+?]
+ *
+ * Note that the branching code sequences used for ? and the general cases
+ * of * and + are somewhat optimized: they use the same NOTHING node as
+ * both the endmarker for their branch list and the body of the last branch.
+ * It might seem that this node could be dispensed with entirely, but the
+ * endmarker role is not redundant.
+ */
+static char *
+regpiece(flagp)
+int *flagp;
+{
+ char *ret;
+ char op;
+ char *next;
+ int flags;
+
+ ret = regatom(&flags);
+ if (ret == NULL)
+ return(NULL);
+
+ op = *regparse;
+ if (!ISMULT(op)) {
+ *flagp = flags;
+ return(ret);
+ }
+
+ if (!(flags&HASWIDTH) && op != '?')
+ FAIL("*+ operand could be empty");
+ *flagp = (op != '+') ? (WORST|SPSTART) : (WORST|HASWIDTH);
+
+ if (op == '*' && (flags&SIMPLE))
+ reginsert(STAR, ret);
+ else if (op == '*') {
+ /* Emit x* as (x&|), where & means "self". */
+ reginsert(BRANCH, ret); /* Either x */
+ regoptail(ret, regnode(BACK)); /* and loop */
+ regoptail(ret, ret); /* back */
+ regtail(ret, regnode(BRANCH)); /* or */
+ regtail(ret, regnode(NOTHING)); /* null. */
+ } else if (op == '+' && (flags&SIMPLE))
+ reginsert(PLUS, ret);
+ else if (op == '+') {
+ /* Emit x+ as x(&|), where & means "self". */
+ next = regnode(BRANCH); /* Either */
+ regtail(ret, next);
+ regtail(regnode(BACK), ret); /* loop back */
+ regtail(next, regnode(BRANCH)); /* or */
+ regtail(ret, regnode(NOTHING)); /* null. */
+ } else if (op == '?') {
+ /* Emit x? as (x|) */
+ reginsert(BRANCH, ret); /* Either x */
+ regtail(ret, regnode(BRANCH)); /* or */
+ next = regnode(NOTHING); /* null. */
+ regtail(ret, next);
+ regoptail(ret, next);
+ }
+ regparse++;
+ if (ISMULT(*regparse))
+ FAIL("nested *?+");
+
+ return(ret);
+}
+
+/*
+ - regatom - the lowest level
+ *
+ * Optimization: gobbles an entire sequence of ordinary characters so that
+ * it can turn them into a single node, which is smaller to store and
+ * faster to run. Backslashed characters are exceptions, each becoming a
+ * separate node; the code is simpler that way and it's not worth fixing.
+ */
+static char *
+regatom(flagp)
+int *flagp;
+{
+ char *ret;
+ int flags;
+
+ *flagp = WORST; /* Tentatively. */
+
+ switch (*regparse++) {
+ /* FIXME: these chars only have meaning at beg/end of pat? */
+ case '^':
+ ret = regnode(BOL);
+ break;
+ case '$':
+ ret = regnode(EOL);
+ break;
+ case '.':
+ ret = regnode(ANY);
+ *flagp |= HASWIDTH|SIMPLE;
+ break;
+ case '[': {
+ int class;
+ int classend;
+ int i;
+
+ if (*regparse == '^') { /* Complement of range. */
+ ret = regnode(ANYBUT);
+ regparse++;
+ } else
+ ret = regnode(ANYOF);
+ if (*regparse == ']' || *regparse == '-')
+ regc(*regparse++);
+ while (*regparse != '\0' && *regparse != ']') {
+ if (*regparse == '-') {
+ regparse++;
+ if (*regparse == ']' || *regparse == '\0')
+ regc('-');
+ else {
+ class = UCHARAT(regparse-2);
+ classend = UCHARAT(regparse);
+ if (__collate_load_error) {
+ if (class > classend)
+ FAIL("invalid [] range");
+ for (class++; class <= classend; class++)
+ regc(class);
+ } else {
+ if (__collate_range_cmp(class, classend) > 0)
+ FAIL("invalid [] range");
+ for (i = 0; i <= UCHAR_MAX; i++)
+ if ( i != class
+ && __collate_range_cmp(class, i) <= 0
+ && __collate_range_cmp(i, classend) <= 0
+ )
+ regc(i);
+ }
+ regparse++;
+ }
+ } else
+ regc(*regparse++);
+ }
+ regc('\0');
+ if (*regparse != ']')
+ FAIL("unmatched []");
+ regparse++;
+ *flagp |= HASWIDTH|SIMPLE;
+ }
+ break;
+ case '(':
+ ret = reg(1, &flags);
+ if (ret == NULL)
+ return(NULL);
+ *flagp |= flags&(HASWIDTH|SPSTART);
+ break;
+ case '\0':
+ case '|':
+ case '\n':
+ case ')':
+ FAIL("internal urp"); /* Supposed to be caught earlier. */
+ break;
+ case '?':
+ case '+':
+ case '*':
+ FAIL("?+* follows nothing");
+ break;
+ case '\\':
+ switch (*regparse++) {
+ case '\0':
+ FAIL("trailing \\");
+ break;
+ case '<':
+ ret = regnode(WORDA);
+ break;
+ case '>':
+ ret = regnode(WORDZ);
+ break;
+ /* FIXME: Someday handle \1, \2, ... */
+ default:
+ /* Handle general quoted chars in exact-match routine */
+ goto de_fault;
+ }
+ break;
+ de_fault:
+ default:
+ /*
+ * Encode a string of characters to be matched exactly.
+ *
+ * This is a bit tricky due to quoted chars and due to
+ * '*', '+', and '?' taking the SINGLE char previous
+ * as their operand.
+ *
+ * On entry, the char at regparse[-1] is going to go
+ * into the string, no matter what it is. (It could be
+ * following a \ if we are entered from the '\' case.)
+ *
+ * Basic idea is to pick up a good char in ch and
+ * examine the next char. If it's *+? then we twiddle.
+ * If it's \ then we frozzle. If it's other magic char
+ * we push ch and terminate the string. If none of the
+ * above, we push ch on the string and go around again.
+ *
+ * regprev is used to remember where "the current char"
+ * starts in the string, if due to a *+? we need to back
+ * up and put the current char in a separate, 1-char, string.
+ * When regprev is NULL, ch is the only char in the
+ * string; this is used in *+? handling, and in setting
+ * flags |= SIMPLE at the end.
+ */
+ {
+ char *regprev;
+ char ch;
+
+ regparse--; /* Look at cur char */
+ ret = regnode(EXACTLY);
+ for ( regprev = 0 ; ; ) {
+ ch = *regparse++; /* Get current char */
+ switch (*regparse) { /* look at next one */
+
+ default:
+ regc(ch); /* Add cur to string */
+ break;
+
+ case '.': case '[': case '(':
+ case ')': case '|': case '\n':
+ case '$': case '^':
+ case '\0':
+ /* FIXME, $ and ^ should not always be magic */
+ magic:
+ regc(ch); /* dump cur char */
+ goto done; /* and we are done */
+
+ case '?': case '+': case '*':
+ if (!regprev) /* If just ch in str, */
+ goto magic; /* use it */
+ /* End mult-char string one early */
+ regparse = regprev; /* Back up parse */
+ goto done;
+
+ case '\\':
+ regc(ch); /* Cur char OK */
+ switch (regparse[1]){ /* Look after \ */
+ case '\0':
+ case '<':
+ case '>':
+ /* FIXME: Someday handle \1, \2, ... */
+ goto done; /* Not quoted */
+ default:
+ /* Backup point is \, scan * point is after it. */
+ regprev = regparse;
+ regparse++;
+ continue; /* NOT break; */
+ }
+ }
+ regprev = regparse; /* Set backup point */
+ }
+ done:
+ regc('\0');
+ *flagp |= HASWIDTH;
+ if (!regprev) /* One char? */
+ *flagp |= SIMPLE;
+ }
+ break;
+ }
+
+ return(ret);
+}
+
+/*
+ - regnode - emit a node
+ */
+static char * /* Location. */
+regnode(op)
+char op;
+{
+ char *ret;
+ char *ptr;
+
+ ret = regcode;
+ if (ret == &regdummy) {
+ regsize += 3;
+ return(ret);
+ }
+
+ ptr = ret;
+ *ptr++ = op;
+ *ptr++ = '\0'; /* Null "next" pointer. */
+ *ptr++ = '\0';
+ regcode = ptr;
+
+ return(ret);
+}
+
+/*
+ - regc - emit (if appropriate) a byte of code
+ */
+static void
+regc(b)
+char b;
+{
+ if (regcode != &regdummy)
+ *regcode++ = b;
+ else
+ regsize++;
+}
+
+/*
+ - reginsert - insert an operator in front of already-emitted operand
+ *
+ * Means relocating the operand.
+ */
+static void
+reginsert(op, opnd)
+char op;
+char *opnd;
+{
+ char *src;
+ char *dst;
+ char *place;
+
+ if (regcode == &regdummy) {
+ regsize += 3;
+ return;
+ }
+
+ src = regcode;
+ regcode += 3;
+ dst = regcode;
+ while (src > opnd)
+ *--dst = *--src;
+
+ place = opnd; /* Op node, where operand used to be. */
+ *place++ = op;
+ *place++ = '\0';
+ *place++ = '\0';
+}
+
+/*
+ - regtail - set the next-pointer at the end of a node chain
+ */
+static void
+regtail(p, val)
+char *p;
+char *val;
+{
+ char *scan;
+ char *temp;
+ int offset;
+
+ if (p == &regdummy)
+ return;
+
+ /* Find last node. */
+ scan = p;
+ for (;;) {
+ temp = regnext(scan);
+ if (temp == NULL)
+ break;
+ scan = temp;
+ }
+
+ if (OP(scan) == BACK)
+ offset = scan - val;
+ else
+ offset = val - scan;
+ *(scan+1) = (offset>>8)&0377;
+ *(scan+2) = offset&0377;
+}
+
+/*
+ - regoptail - regtail on operand of first argument; nop if operandless
+ */
+static void
+regoptail(p, val)
+char *p;
+char *val;
+{
+ /* "Operandless" and "op != BRANCH" are synonymous in practice. */
+ if (p == NULL || p == &regdummy || OP(p) != BRANCH)
+ return;
+ regtail(OPERAND(p), val);
+}
+
+/*
+ * regexec and friends
+ */
+
+/*
+ * Global work variables for regexec().
+ */
+static char *reginput; /* String-input pointer. */
+static char *regbol; /* Beginning of input, for ^ check. */
+static char **regstartp; /* Pointer to startp array. */
+static char **regendp; /* Ditto for endp. */
+
+/*
+ * Forwards.
+ */
+STATIC int regtry();
+STATIC int regmatch();
+STATIC int regrepeat();
+
+#ifdef DEBUG
+int regnarrate = 0;
+void regdump();
+STATIC char *regprop();
+#endif
+
+/*
+ - regexec - match a regexp against a string
+ */
+int
+regexec(prog, string)
+const regexp *prog;
+const char *string;
+{
+ char *s;
+ extern char *strchr();
+
+ /* Be paranoid... */
+ if (prog == NULL || string == NULL) {
+ regerror("NULL parameter");
+ return(0);
+ }
+
+ /* Check validity of program. */
+ if (UCHARAT(prog->program) != MAGIC) {
+ regerror("corrupted program");
+ return(0);
+ }
+
+ /* If there is a "must appear" string, look for it. */
+ if (prog->regmust != NULL) {
+ s = (char *)string;
+ while ((s = strchr(s, prog->regmust[0])) != NULL) {
+ if (strncmp(s, prog->regmust, prog->regmlen) == 0)
+ break; /* Found it. */
+ s++;
+ }
+ if (s == NULL) /* Not present. */
+ return(0);
+ }
+
+ /* Mark beginning of line for ^ . */
+ regbol = (char *)string;
+
+ /* Simplest case: anchored match need be tried only once. */
+ if (prog->reganch)
+ return(regtry(prog, string));
+
+ /* Messy cases: unanchored match. */
+ s = (char *)string;
+ if (prog->regstart != '\0')
+ /* We know what char it must start with. */
+ while ((s = strchr(s, prog->regstart)) != NULL) {
+ if (regtry(prog, s))
+ return(1);
+ s++;
+ }
+ else
+ /* We don't -- general case. */
+ do {
+ if (regtry(prog, s))
+ return(1);
+ } while (*s++ != '\0');
+
+ /* Failure. */
+ return(0);
+}
+
+/*
+ - regtry - try match at specific point
+ */
+static int /* 0 failure, 1 success */
+regtry(prog, string)
+regexp *prog;
+char *string;
+{
+ int i;
+ char **sp;
+ char **ep;
+
+ reginput = string;
+ regstartp = prog->startp;
+ regendp = prog->endp;
+
+ sp = prog->startp;
+ ep = prog->endp;
+ for (i = NSUBEXP; i > 0; i--) {
+ *sp++ = NULL;
+ *ep++ = NULL;
+ }
+ if (regmatch(prog->program + 1)) {
+ prog->startp[0] = string;
+ prog->endp[0] = reginput;
+ return(1);
+ } else
+ return(0);
+}
+
+/*
+ - regmatch - main matching routine
+ *
+ * Conceptually the strategy is simple: check to see whether the current
+ * node matches, call self recursively to see whether the rest matches,
+ * and then act accordingly. In practice we make some effort to avoid
+ * recursion, in particular by going through "ordinary" nodes (that don't
+ * need to know whether the rest of the match failed) by a loop instead of
+ * by recursion.
+ */
+static int /* 0 failure, 1 success */
+regmatch(prog)
+char *prog;
+{
+ char *scan; /* Current node. */
+ char *next; /* Next node. */
+
+ scan = prog;
+#ifdef DEBUG
+ if (scan != NULL && regnarrate)
+ fprintf(stderr, "%s(\n", regprop(scan));
+#endif
+ while (scan != NULL) {
+#ifdef DEBUG
+ if (regnarrate)
+ fprintf(stderr, "%s...\n", regprop(scan));
+#endif
+ next = regnext(scan);
+
+ switch (OP(scan)) {
+ case BOL:
+ if (reginput != regbol)
+ return(0);
+ break;
+ case EOL:
+ if (*reginput != '\0')
+ return(0);
+ break;
+ case WORDA:
+ /* Must be looking at a letter, digit, or _ */
+ if ((!isalnum((unsigned char)*reginput)) && *reginput != '_')
+ return(0);
+ /* Prev must be BOL or nonword */
+ if (reginput > regbol &&
+ (isalnum((unsigned char)reginput[-1]) || reginput[-1] == '_'))
+ return(0);
+ break;
+ case WORDZ:
+ /* Must be looking at non letter, digit, or _ */
+ if (isalnum((unsigned char)*reginput) || *reginput == '_')
+ return(0);
+ /* We don't care what the previous char was */
+ break;
+ case ANY:
+ if (*reginput == '\0')
+ return(0);
+ reginput++;
+ break;
+ case EXACTLY: {
+ int len;
+ char *opnd;
+
+ opnd = OPERAND(scan);
+ /* Inline the first character, for speed. */
+ if (*opnd != *reginput)
+ return(0);
+ len = strlen(opnd);
+ if (len > 1 && strncmp(opnd, reginput, len) != 0)
+ return(0);
+ reginput += len;
+ }
+ break;
+ case ANYOF:
+ if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) == NULL)
+ return(0);
+ reginput++;
+ break;
+ case ANYBUT:
+ if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) != NULL)
+ return(0);
+ reginput++;
+ break;
+ case NOTHING:
+ break;
+ case BACK:
+ break;
+ case OPEN+1:
+ case OPEN+2:
+ case OPEN+3:
+ case OPEN+4:
+ case OPEN+5:
+ case OPEN+6:
+ case OPEN+7:
+ case OPEN+8:
+ case OPEN+9: {
+ int no;
+ char *save;
+
+ no = OP(scan) - OPEN;
+ save = reginput;
+
+ if (regmatch(next)) {
+ /*
+ * Don't set startp if some later
+ * invocation of the same parentheses
+ * already has.
+ */
+ if (regstartp[no] == NULL)
+ regstartp[no] = save;
+ return(1);
+ } else
+ return(0);
+ }
+ break;
+ case CLOSE+1:
+ case CLOSE+2:
+ case CLOSE+3:
+ case CLOSE+4:
+ case CLOSE+5:
+ case CLOSE+6:
+ case CLOSE+7:
+ case CLOSE+8:
+ case CLOSE+9: {
+ int no;
+ char *save;
+
+ no = OP(scan) - CLOSE;
+ save = reginput;
+
+ if (regmatch(next)) {
+ /*
+ * Don't set endp if some later
+ * invocation of the same parentheses
+ * already has.
+ */
+ if (regendp[no] == NULL)
+ regendp[no] = save;
+ return(1);
+ } else
+ return(0);
+ }
+ break;
+ case BRANCH: {
+ char *save;
+
+ if (OP(next) != BRANCH) /* No choice. */
+ next = OPERAND(scan); /* Avoid recursion. */
+ else {
+ do {
+ save = reginput;
+ if (regmatch(OPERAND(scan)))
+ return(1);
+ reginput = save;
+ scan = regnext(scan);
+ } while (scan != NULL && OP(scan) == BRANCH);
+ return(0);
+ /* NOTREACHED */
+ }
+ }
+ break;
+ case STAR:
+ case PLUS: {
+ char nextch;
+ int no;
+ char *save;
+ int min;
+
+ /*
+ * Lookahead to avoid useless match attempts
+ * when we know what character comes next.
+ */
+ nextch = '\0';
+ if (OP(next) == EXACTLY)
+ nextch = *OPERAND(next);
+ min = (OP(scan) == STAR) ? 0 : 1;
+ save = reginput;
+ no = regrepeat(OPERAND(scan));
+ while (no >= min) {
+ /* If it could work, try it. */
+ if (nextch == '\0' || *reginput == nextch)
+ if (regmatch(next))
+ return(1);
+ /* Couldn't or didn't -- back up. */
+ no--;
+ reginput = save + no;
+ }
+ return(0);
+ }
+ break;
+ case END:
+ return(1); /* Success! */
+ break;
+ default:
+ regerror("memory corruption");
+ return(0);
+ break;
+ }
+
+ scan = next;
+ }
+
+ /*
+ * We get here only if there's trouble -- normally "case END" is
+ * the terminating point.
+ */
+ regerror("corrupted pointers");
+ return(0);
+}
+
+/*
+ - regrepeat - repeatedly match something simple, report how many
+ */
+static int
+regrepeat(p)
+char *p;
+{
+ int count = 0;
+ char *scan;
+ char *opnd;
+
+ scan = reginput;
+ opnd = OPERAND(p);
+ switch (OP(p)) {
+ case ANY:
+ count = strlen(scan);
+ scan += count;
+ break;
+ case EXACTLY:
+ while (*opnd == *scan) {
+ count++;
+ scan++;
+ }
+ break;
+ case ANYOF:
+ while (*scan != '\0' && strchr(opnd, *scan) != NULL) {
+ count++;
+ scan++;
+ }
+ break;
+ case ANYBUT:
+ while (*scan != '\0' && strchr(opnd, *scan) == NULL) {
+ count++;
+ scan++;
+ }
+ break;
+ default: /* Oh dear. Called inappropriately. */
+ regerror("internal foulup");
+ count = 0; /* Best compromise. */
+ break;
+ }
+ reginput = scan;
+
+ return(count);
+}
+
+/*
+ - regnext - dig the "next" pointer out of a node
+ */
+static char *
+regnext(p)
+char *p;
+{
+ int offset;
+
+ if (p == &regdummy)
+ return(NULL);
+
+ offset = NEXT(p);
+ if (offset == 0)
+ return(NULL);
+
+ if (OP(p) == BACK)
+ return(p-offset);
+ else
+ return(p+offset);
+}
+
+#ifdef DEBUG
+
+STATIC char *regprop();
+
+/*
+ - regdump - dump a regexp onto stdout in vaguely comprehensible form
+ */
+void
+regdump(r)
+regexp *r;
+{
+ char *s;
+ char op = EXACTLY; /* Arbitrary non-END op. */
+ char *next;
+ extern char *strchr();
+
+
+ s = r->program + 1;
+ while (op != END) { /* While that wasn't END last time... */
+ op = OP(s);
+ printf("%2d%s", s-r->program, regprop(s)); /* Where, what. */
+ next = regnext(s);
+ if (next == NULL) /* Next ptr. */
+ printf("(0)");
+ else
+ printf("(%d)", (s-r->program)+(next-s));
+ s += 3;
+ if (op == ANYOF || op == ANYBUT || op == EXACTLY) {
+ /* Literal string, where present. */
+ while (*s != '\0') {
+ putchar(*s);
+ s++;
+ }
+ s++;
+ }
+ putchar('\n');
+ }
+
+ /* Header fields of interest. */
+ if (r->regstart != '\0')
+ printf("start `%c' ", r->regstart);
+ if (r->reganch)
+ printf("anchored ");
+ if (r->regmust != NULL)
+ printf("must have \"%s\"", r->regmust);
+ printf("\n");
+}
+
+/*
+ - regprop - printable representation of opcode
+ */
+static char *
+regprop(op)
+char *op;
+{
+ char *p;
+ static char buf[50];
+
+ (void) strcpy(buf, ":");
+
+ switch (OP(op)) {
+ case BOL:
+ p = "BOL";
+ break;
+ case EOL:
+ p = "EOL";
+ break;
+ case ANY:
+ p = "ANY";
+ break;
+ case ANYOF:
+ p = "ANYOF";
+ break;
+ case ANYBUT:
+ p = "ANYBUT";
+ break;
+ case BRANCH:
+ p = "BRANCH";
+ break;
+ case EXACTLY:
+ p = "EXACTLY";
+ break;
+ case NOTHING:
+ p = "NOTHING";
+ break;
+ case BACK:
+ p = "BACK";
+ break;
+ case END:
+ p = "END";
+ break;
+ case OPEN+1:
+ case OPEN+2:
+ case OPEN+3:
+ case OPEN+4:
+ case OPEN+5:
+ case OPEN+6:
+ case OPEN+7:
+ case OPEN+8:
+ case OPEN+9:
+ sprintf(buf+strlen(buf), "OPEN%d", OP(op)-OPEN);
+ p = NULL;
+ break;
+ case CLOSE+1:
+ case CLOSE+2:
+ case CLOSE+3:
+ case CLOSE+4:
+ case CLOSE+5:
+ case CLOSE+6:
+ case CLOSE+7:
+ case CLOSE+8:
+ case CLOSE+9:
+ sprintf(buf+strlen(buf), "CLOSE%d", OP(op)-CLOSE);
+ p = NULL;
+ break;
+ case STAR:
+ p = "STAR";
+ break;
+ case PLUS:
+ p = "PLUS";
+ break;
+ case WORDA:
+ p = "WORDA";
+ break;
+ case WORDZ:
+ p = "WORDZ";
+ break;
+ default:
+ regerror("corrupted opcode");
+ break;
+ }
+ if (p != NULL)
+ (void) strcat(buf, p);
+ return(buf);
+}
+#endif
+
+/*
+ * The following is provided for those people who do not have strcspn() in
+ * their C libraries. They should get off their butts and do something
+ * about it; at least one public-domain implementation of those (highly
+ * useful) string routines has been published on Usenet.
+ */
+#ifdef STRCSPN
+/*
+ * strcspn - find length of initial segment of s1 consisting entirely
+ * of characters not from s2
+ */
+
+static int
+strcspn(s1, s2)
+char *s1;
+char *s2;
+{
+ char *scan1;
+ char *scan2;
+ int count;
+
+ count = 0;
+ for (scan1 = s1; *scan1 != '\0'; scan1++) {
+ for (scan2 = s2; *scan2 != '\0';) /* ++ moved down. */
+ if (*scan1 == *scan2++)
+ return(count);
+ count++;
+ }
+ return(count);
+}
+#endif
diff --git a/lib/libcompat/regexp/regmagic.h b/lib/libcompat/regexp/regmagic.h
new file mode 100644
index 0000000..5acf447
--- /dev/null
+++ b/lib/libcompat/regexp/regmagic.h
@@ -0,0 +1,5 @@
+/*
+ * The first byte of the regexp internal "program" is actually this magic
+ * number; the start node begins in the second byte.
+ */
+#define MAGIC 0234
diff --git a/lib/libcompat/regexp/regsub.c b/lib/libcompat/regexp/regsub.c
new file mode 100644
index 0000000..4ab921c
--- /dev/null
+++ b/lib/libcompat/regexp/regsub.c
@@ -0,0 +1,85 @@
+/*
+ * regsub
+ *
+ * Copyright (c) 1986 by University of Toronto.
+ * Written by Henry Spencer. Not derived from licensed software.
+ *
+ * Permission is granted to anyone to use this software for any
+ * purpose on any computer system, and to redistribute it freely,
+ * 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 defects in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either
+ * by explicit claim or by omission.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not
+ * be misrepresented as being the original software.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <regexp.h>
+#include <stdio.h>
+#include <string.h>
+#include "regmagic.h"
+
+#ifndef CHARBITS
+#define UCHARAT(p) ((int)*(unsigned char *)(p))
+#else
+#define UCHARAT(p) ((int)*(p)&CHARBITS)
+#endif
+
+/*
+ - regsub - perform substitutions after a regexp match
+ */
+void
+regsub(prog, source, dest)
+const regexp *prog;
+const char *source;
+char *dest;
+{
+ char *src;
+ char *dst;
+ char c;
+ int no;
+ int len;
+ extern char *strncpy();
+
+ if (prog == NULL || source == NULL || dest == NULL) {
+ regerror("NULL parm to regsub");
+ return;
+ }
+ if (UCHARAT(prog->program) != MAGIC) {
+ regerror("damaged regexp fed to regsub");
+ return;
+ }
+
+ src = (char *)source;
+ dst = dest;
+ while ((c = *src++) != '\0') {
+ if (c == '&')
+ no = 0;
+ else if (c == '\\' && '0' <= *src && *src <= '9')
+ no = *src++ - '0';
+ else
+ no = -1;
+ if (no < 0) { /* Ordinary character. */
+ if (c == '\\' && (*src == '\\' || *src == '&'))
+ c = *src++;
+ *dst++ = c;
+ } else if (prog->startp[no] != NULL && prog->endp[no] != NULL) {
+ len = prog->endp[no] - prog->startp[no];
+ (void) strncpy(dst, prog->startp[no], len);
+ dst += len;
+ if (len != 0 && *(dst-1) == '\0') { /* strncpy hit NUL. */
+ regerror("damaged match string");
+ return;
+ }
+ }
+ }
+ *dst++ = '\0';
+}
diff --git a/lib/libcrypt/Makefile b/lib/libcrypt/Makefile
new file mode 100644
index 0000000..3a27e70
--- /dev/null
+++ b/lib/libcrypt/Makefile
@@ -0,0 +1,38 @@
+#
+# $FreeBSD$
+#
+
+SHLIBDIR?= /lib
+
+.include <bsd.own.mk>
+
+SHLIB_MAJOR= 3
+LIB= crypt
+
+.PATH: ${.CURDIR}/../libmd
+SRCS= crypt.c misc.c \
+ crypt-md5.c md5c.c \
+ crypt-nthash.c md4c.c
+MAN= crypt.3
+MLINKS= crypt.3 crypt_get_format.3 crypt.3 crypt_set_format.3
+CFLAGS+= -I${.CURDIR}/../libmd -I${.CURDIR}/../libutil
+
+# Pull in the strong crypto, if it is present.
+.if exists(${.CURDIR}/../../secure/lib/libcrypt) && ${MK_CRYPT} != "no"
+.PATH: ${.CURDIR}/../../secure/lib/libcrypt
+SRCS+= crypt-des.c crypt-blowfish.c blowfish.c
+CFLAGS+= -I${.CURDIR} -DHAS_DES -DHAS_BLOWFISH
+.endif
+
+# And the auth_getval() code and support.
+.PATH: ${.CURDIR}/../libutil
+SRCS+= auth.c property.c
+.for sym in auth_getval property_find properties_read properties_free \
+ MD4Init MD4Final MD4Update MD4Pad \
+ MD5Init MD5Final MD5Update MD5Pad
+CFLAGS+= -D${sym}=__${sym}
+.endfor
+
+PRECIOUSLIB=
+
+.include <bsd.lib.mk>
diff --git a/lib/libcrypt/crypt-md5.c b/lib/libcrypt/crypt-md5.c
new file mode 100644
index 0000000..33186cd
--- /dev/null
+++ b/lib/libcrypt/crypt-md5.c
@@ -0,0 +1,153 @@
+/*-
+ * Copyright (c) 2003 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include <err.h>
+#include <md5.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "crypt.h"
+
+/*
+ * UNIX password
+ */
+
+char *
+crypt_md5(const char *pw, const char *salt)
+{
+ MD5_CTX ctx,ctx1;
+ unsigned long l;
+ int sl, pl;
+ u_int i;
+ u_char final[MD5_SIZE];
+ static const char *sp, *ep;
+ static char passwd[120], *p;
+ static const char *magic = "$1$";
+
+ /* Refine the Salt first */
+ sp = salt;
+
+ /* If it starts with the magic string, then skip that */
+ if(!strncmp(sp, magic, strlen(magic)))
+ sp += strlen(magic);
+
+ /* It stops at the first '$', max 8 chars */
+ for(ep = sp; *ep && *ep != '$' && ep < (sp + 8); ep++)
+ continue;
+
+ /* get the length of the true salt */
+ sl = ep - sp;
+
+ MD5Init(&ctx);
+
+ /* The password first, since that is what is most unknown */
+ MD5Update(&ctx, (const u_char *)pw, strlen(pw));
+
+ /* Then our magic string */
+ MD5Update(&ctx, (const u_char *)magic, strlen(magic));
+
+ /* Then the raw salt */
+ MD5Update(&ctx, (const u_char *)sp, (u_int)sl);
+
+ /* Then just as many characters of the MD5(pw,salt,pw) */
+ MD5Init(&ctx1);
+ MD5Update(&ctx1, (const u_char *)pw, strlen(pw));
+ MD5Update(&ctx1, (const u_char *)sp, (u_int)sl);
+ MD5Update(&ctx1, (const u_char *)pw, strlen(pw));
+ MD5Final(final, &ctx1);
+ for(pl = (int)strlen(pw); pl > 0; pl -= MD5_SIZE)
+ MD5Update(&ctx, (const u_char *)final,
+ (u_int)(pl > MD5_SIZE ? MD5_SIZE : pl));
+
+ /* Don't leave anything around in vm they could use. */
+ memset(final, 0, sizeof(final));
+
+ /* Then something really weird... */
+ for (i = strlen(pw); i; i >>= 1)
+ if(i & 1)
+ MD5Update(&ctx, (const u_char *)final, 1);
+ else
+ MD5Update(&ctx, (const u_char *)pw, 1);
+
+ /* Now make the output string */
+ strcpy(passwd, magic);
+ strncat(passwd, sp, (u_int)sl);
+ strcat(passwd, "$");
+
+ MD5Final(final, &ctx);
+
+ /*
+ * and now, just to make sure things don't run too fast
+ * On a 60 Mhz Pentium this takes 34 msec, so you would
+ * need 30 seconds to build a 1000 entry dictionary...
+ */
+ for(i = 0; i < 1000; i++) {
+ MD5Init(&ctx1);
+ if(i & 1)
+ MD5Update(&ctx1, (const u_char *)pw, strlen(pw));
+ else
+ MD5Update(&ctx1, (const u_char *)final, MD5_SIZE);
+
+ if(i % 3)
+ MD5Update(&ctx1, (const u_char *)sp, (u_int)sl);
+
+ if(i % 7)
+ MD5Update(&ctx1, (const u_char *)pw, strlen(pw));
+
+ if(i & 1)
+ MD5Update(&ctx1, (const u_char *)final, MD5_SIZE);
+ else
+ MD5Update(&ctx1, (const u_char *)pw, strlen(pw));
+ MD5Final(final, &ctx1);
+ }
+
+ p = passwd + strlen(passwd);
+
+ l = (final[ 0]<<16) | (final[ 6]<<8) | final[12];
+ _crypt_to64(p, l, 4); p += 4;
+ l = (final[ 1]<<16) | (final[ 7]<<8) | final[13];
+ _crypt_to64(p, l, 4); p += 4;
+ l = (final[ 2]<<16) | (final[ 8]<<8) | final[14];
+ _crypt_to64(p, l, 4); p += 4;
+ l = (final[ 3]<<16) | (final[ 9]<<8) | final[15];
+ _crypt_to64(p, l, 4); p += 4;
+ l = (final[ 4]<<16) | (final[10]<<8) | final[ 5];
+ _crypt_to64(p, l, 4); p += 4;
+ l = final[11];
+ _crypt_to64(p, l, 2); p += 2;
+ *p = '\0';
+
+ /* Don't leave anything around in vm they could use. */
+ memset(final, 0, sizeof(final));
+
+ return (passwd);
+}
diff --git a/lib/libcrypt/crypt-nthash.c b/lib/libcrypt/crypt-nthash.c
new file mode 100644
index 0000000..19b84ce
--- /dev/null
+++ b/lib/libcrypt/crypt-nthash.c
@@ -0,0 +1,88 @@
+/*-
+ * Copyright (c) 2003 Michael Bretterklieber
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 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>
+
+#include <ctype.h>
+#include <err.h>
+#include <md4.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "crypt.h"
+
+/*
+ * NT HASH = md4(str2unicode(pw))
+ */
+
+/* ARGSUSED */
+char *
+crypt_nthash(const char *pw, const char *salt __unused)
+{
+ size_t unipwLen;
+ int i, j;
+ static char hexconvtab[] = "0123456789abcdef";
+ static const char *magic = "$3$";
+ static char passwd[120];
+ u_int16_t unipw[128];
+ char final[MD4_SIZE*2 + 1];
+ u_char hash[MD4_SIZE];
+ const char *s;
+ MD4_CTX ctx;
+
+ bzero(unipw, sizeof(unipw));
+ /* convert to unicode (thanx Archie) */
+ unipwLen = 0;
+ for (s = pw; unipwLen < sizeof(unipw) / 2 && *s; s++)
+ unipw[unipwLen++] = htons(*s << 8);
+
+ /* Compute MD4 of Unicode password */
+ MD4Init(&ctx);
+ MD4Update(&ctx, (u_char *)unipw, unipwLen*sizeof(u_int16_t));
+ MD4Final(hash, &ctx);
+
+ for (i = j = 0; i < MD4_SIZE; i++) {
+ final[j++] = hexconvtab[hash[i] >> 4];
+ final[j++] = hexconvtab[hash[i] & 15];
+ }
+ final[j] = '\0';
+
+ strcpy(passwd, magic);
+ strcat(passwd, "$");
+ strncat(passwd, final, MD4_SIZE*2);
+
+ /* Don't leave anything around in vm they could use. */
+ memset(final, 0, sizeof(final));
+
+ return (passwd);
+}
diff --git a/lib/libcrypt/crypt.3 b/lib/libcrypt/crypt.3
new file mode 100644
index 0000000..27ff750
--- /dev/null
+++ b/lib/libcrypt/crypt.3
@@ -0,0 +1,307 @@
+.\" FreeSec: libcrypt for NetBSD
+.\"
+.\" Copyright (c) 1994 David Burren
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the author nor the names of other 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 19, 1997
+.Dt CRYPT 3
+.Os
+.Sh NAME
+.Nm crypt
+.Nd Trapdoor encryption
+.Sh LIBRARY
+.Lb libcrypt
+.Sh SYNOPSIS
+.In unistd.h
+.Ft char *
+.Fn crypt "const char *key" "const char *salt"
+.Ft const char *
+.Fn crypt_get_format "void"
+.Ft int
+.Fn crypt_set_format "const char *string"
+.Sh DESCRIPTION
+The
+.Fn crypt
+function performs password hashing with additional code added to
+deter key search attempts.
+Different algorithms can be used to
+in the hash.
+.\"
+.\" NOTICE:
+.\" If you add more algorithms, make sure to update this list
+.\" and the default used for the Traditional format, below.
+.\"
+Currently these include the
+.Tn NBS
+.Tn Data Encryption Standard (DES) ,
+.Tn MD5
+hash,
+.Tn NT-Hash
+(compatible with Microsoft's NT scheme)
+and
+.Tn Blowfish .
+The algorithm used will depend upon the format of the Salt (following
+the Modular Crypt Format (MCF)), if
+.Tn DES
+and/or
+.Tn Blowfish
+is installed or not, and whether
+.Fn crypt_set_format
+has been called to change the default.
+.Pp
+The first argument to
+.Nm
+is the data to hash (usually a password), in a
+.Dv null Ns -terminated
+string.
+The second is the salt, in one of three forms:
+.Pp
+.Bl -tag -width Traditional -compact -offset indent
+.It Extended
+If it begins with an underscore
+.Pq Dq _
+then the
+.Tn DES
+Extended Format
+is used in interpreting both the key and the salt, as outlined below.
+.It Modular
+If it begins with the string
+.Dq $digit$
+then the Modular Crypt Format is used, as outlined below.
+.It Traditional
+If neither of the above is true, it assumes the Traditional Format,
+using the entire string as the salt (or the first portion).
+.El
+.Pp
+All routines are designed to be time-consuming.
+A brief test on a
+.Tn Pentium
+166/MMX shows the
+.Tn DES
+crypt to do approximately 2640 crypts
+a CPU second and MD5 to do about 62 crypts a CPU second.
+.Ss DES Extended Format:
+.Pp
+The
+.Ar key
+is divided into groups of 8 characters (the last group is null-padded)
+and the low-order 7 bits of each character (56 bits per group) are
+used to form the
+.Tn DES
+key as follows:
+the first group of 56 bits becomes the initial
+.Tn DES
+key.
+For each additional group, the XOR of the encryption of the current
+.Tn DES
+key with itself and the group bits becomes the next
+.Tn DES
+key.
+.Pp
+The salt is a 9-character array consisting of an underscore followed
+by 4 bytes of iteration count and 4 bytes of salt.
+These are encoded as printable characters, 6 bits per character,
+least significant character first.
+The values 0 to 63 are encoded as ``./0-9A-Za-z''.
+This allows 24 bits for both
+.Fa count
+and
+.Fa salt .
+.Pp
+The
+.Fa salt
+introduces disorder in the
+.Tn DES
+algorithm in one of 16777216 or 4096 possible ways
+(i.e., with 24 or 12 bits: if bit
+.Em i
+of the
+.Ar salt
+is set, then bits
+.Em i
+and
+.Em i+24
+are swapped in the
+.Tn DES
+E-box output).
+.Pp
+The
+.Tn DES
+key is used to encrypt a 64-bit constant using
+.Ar count
+iterations of
+.Tn DES .
+The value returned is a
+.Dv null Ns -terminated
+string, 20 or 13 bytes (plus null) in length, consisting of the
+.Ar salt
+followed by the encoded 64-bit encryption.
+.Ss "Modular" crypt:
+.Pp
+If the salt begins with the string
+.Fa $digit$
+then the Modular Crypt Format is used.
+The
+.Fa digit
+represents which algorithm is used in encryption.
+Following the token is
+the actual salt to use in the encryption.
+The length of the salt is limited
+to 8 characters--because the length of the returned output is also limited
+(_PASSWORD_LEN).
+The salt must be terminated with the end of the string
+(NULL) or a dollar sign.
+Any characters after the dollar sign are ignored.
+.Pp
+Currently supported algorithms are:
+.Pp
+.Bl -enum -compact -offset indent
+.It
+MD5
+.It
+Blowfish
+.It
+NT-Hash
+.El
+.Pp
+Other crypt formats may be easily added.
+An example salt would be:
+.Bl -tag -offset indent
+.It Cm "$4$thesalt$rest"
+.El
+.Pp
+.Ss "Traditional" crypt:
+.Pp
+The algorithm used will depend upon whether
+.Fn crypt_set_format
+has been called and whether a global default format has been specified.
+Unless a global default has been specified or
+.Fn crypt_set_format
+has set the format to something else, the built-in default format is
+used.
+This is currently
+.\"
+.\" NOTICE: Also make sure to update this
+.\"
+DES
+if it is available, or MD5 if not.
+.Pp
+How the salt is used will depend upon the algorithm for the hash.
+For
+best results, specify at least two characters of salt.
+.Pp
+The
+.Fn crypt_get_format
+function returns a constant string that represents the name of the
+algorithm currently used.
+Valid values are
+.\"
+.\" NOTICE: Also make sure to update this, too, as well
+.\"
+.Ql des ,
+.Ql blf ,
+.Ql md5
+and
+.Ql nth .
+.Pp
+The
+.Fn crypt_set_format
+function sets the default encoding format according to the supplied
+.Fa string .
+.Pp
+The global default format can be set using the
+.Pa /etc/auth.conf
+file using the
+.Va crypt_default
+property.
+.Sh RETURN VALUES
+The
+.Fn crypt
+function returns a pointer to the encrypted value on success, and NULL on
+failure.
+Note: this is not a standard behaviour, AT&T
+.Fn crypt
+will always return a pointer to a string.
+.Pp
+The
+.Fn crypt_set_format
+function will return 1 if the supplied encoding format was valid.
+Otherwise, a value of 0 is returned.
+.Sh SEE ALSO
+.Xr login 1 ,
+.Xr passwd 1 ,
+.Xr auth_getval 3 ,
+.Xr cipher 3 ,
+.Xr getpass 3 ,
+.Xr auth.conf 5 ,
+.Xr passwd 5
+.Sh HISTORY
+A rotor-based
+.Fn crypt
+function appeared in
+.At v6 .
+The current style
+.Fn crypt
+first appeared in
+.At v7 .
+.Pp
+The
+.Tn DES
+section of the code (FreeSec 1.0) was developed outside the United
+States of America as an unencumbered replacement for the U.S.-only
+.Nx
+libcrypt encryption library.
+.Sh AUTHORS
+.An -nosplit
+Originally written by
+.An David Burren Aq davidb@werj.com.au ,
+later additions and changes by
+.An Poul-Henning Kamp ,
+.An Mark R V Murray ,
+.An Michael Bretterklieber ,
+.An Kris Kennaway ,
+.An Brian Feldman ,
+.An Paul Herman
+and
+.An Niels Provos .
+.Sh BUGS
+The
+.Fn crypt
+function returns a pointer to static data, and subsequent calls to
+.Fn crypt
+will modify the same data.
+Likewise,
+.Fn crypt_set_format
+modifies static data.
+.Pp
+The NT-hash scheme does not use a salt,
+and is not hard
+for a competent attacker
+to break.
+Its use is not recommended.
diff --git a/lib/libcrypt/crypt.c b/lib/libcrypt/crypt.c
new file mode 100644
index 0000000..a6b91f5
--- /dev/null
+++ b/lib/libcrypt/crypt.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 1999
+ * Mark Murray. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MARK MURRAY AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL MARK MURRAY OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 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 <string.h>
+#include <libutil.h>
+#include <unistd.h>
+#include "crypt.h"
+
+static const struct {
+ const char *const name;
+ char *(*const func)(const char *, const char *);
+ const char *const magic;
+} crypt_types[] = {
+#ifdef HAS_DES
+ {
+ "des",
+ crypt_des,
+ NULL
+ },
+#endif
+ {
+ "md5",
+ crypt_md5,
+ "$1$"
+ },
+#ifdef HAS_BLOWFISH
+ {
+ "blf",
+ crypt_blowfish,
+ "$2"
+ },
+#endif
+ {
+ "nth",
+ crypt_nthash,
+ "$3$"
+ },
+ {
+ NULL,
+ NULL,
+ NULL
+ }
+};
+
+static int crypt_type = -1;
+
+static void
+crypt_setdefault(void)
+{
+ char *def;
+ size_t i;
+
+ if (crypt_type != -1)
+ return;
+ def = auth_getval("crypt_default");
+ if (def == NULL) {
+ crypt_type = 0;
+ return;
+ }
+ for (i = 0; i < sizeof(crypt_types) / sizeof(crypt_types[0]) - 1; i++) {
+ if (strcmp(def, crypt_types[i].name) == 0) {
+ crypt_type = (int)i;
+ return;
+ }
+ }
+ crypt_type = 0;
+}
+
+const char *
+crypt_get_format(void)
+{
+
+ crypt_setdefault();
+ return (crypt_types[crypt_type].name);
+}
+
+int
+crypt_set_format(const char *type)
+{
+ size_t i;
+
+ crypt_setdefault();
+ for (i = 0; i < sizeof(crypt_types) / sizeof(crypt_types[0]) - 1; i++) {
+ if (strcmp(type, crypt_types[i].name) == 0) {
+ crypt_type = (int)i;
+ return (1);
+ }
+ }
+ return (0);
+}
+
+char *
+crypt(const char *passwd, const char *salt)
+{
+ size_t i;
+
+ crypt_setdefault();
+ for (i = 0; i < sizeof(crypt_types) / sizeof(crypt_types[0]) - 1; i++) {
+ if (crypt_types[i].magic != NULL && strncmp(salt,
+ crypt_types[i].magic, strlen(crypt_types[i].magic)) == 0)
+ return (crypt_types[i].func(passwd, salt));
+ }
+ return (crypt_types[crypt_type].func(passwd, salt));
+}
diff --git a/lib/libcrypt/crypt.h b/lib/libcrypt/crypt.h
new file mode 100644
index 0000000..c677160
--- /dev/null
+++ b/lib/libcrypt/crypt.h
@@ -0,0 +1,40 @@
+/* LINTLIBRARY */
+/*
+ * Copyright (c) 1999
+ * Mark Murray. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MARK MURRAY AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL MARK MURRAY OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ */
+
+/* magic sizes */
+#define MD4_SIZE 16
+#define MD5_SIZE 16
+
+char *crypt_des(const char *pw, const char *salt);
+char *crypt_md5(const char *pw, const char *salt);
+char *crypt_nthash(const char *pw, const char *salt);
+char *crypt_blowfish(const char *pw, const char *salt);
+
+extern void _crypt_to64(char *s, u_long v, int n);
diff --git a/lib/libcrypt/misc.c b/lib/libcrypt/misc.c
new file mode 100644
index 0000000..594c580
--- /dev/null
+++ b/lib/libcrypt/misc.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 1999
+ * University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this 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 CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY 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 "crypt.h"
+
+static char itoa64[] = /* 0 ... 63 => ascii - 64 */
+ "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+void
+_crypt_to64(char *s, u_long v, int n)
+{
+ while (--n >= 0) {
+ *s++ = itoa64[v&0x3f];
+ v >>= 6;
+ }
+}
diff --git a/lib/libdevinfo/Makefile b/lib/libdevinfo/Makefile
new file mode 100644
index 0000000..0615195
--- /dev/null
+++ b/lib/libdevinfo/Makefile
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+LIB= devinfo
+SRCS= devinfo.c
+INCS= devinfo.h
+MAN= devinfo.3
+
+.include <bsd.lib.mk>
diff --git a/lib/libdevinfo/devinfo.3 b/lib/libdevinfo/devinfo.3
new file mode 100644
index 0000000..49516cc
--- /dev/null
+++ b/lib/libdevinfo/devinfo.3
@@ -0,0 +1,247 @@
+.\"
+.\" Copyright (c) 2001 Michael Smith <msmith@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 19, 2001
+.Dt DEVINFO 3
+.Os
+.Sh NAME
+.Nm devinfo ,
+.Nm devinfo_init ,
+.Nm devinfo_free ,
+.Nm devinfo_handle_to_device ,
+.Nm devinfo_handle_to_resource ,
+.Nm devinfo_handle_to_rman ,
+.Nm devinfo_foreach_device_child ,
+.Nm devinfo_foreach_device_resource ,
+.Nm devinfo_foreach_rman_resource ,
+.Nm devinfo_foreach_rman
+.Nd device and resource information utility library
+.Sh LIBRARY
+.Lb libdevinfo
+.Sh SYNOPSIS
+.In devinfo.h
+.Ft int
+.Fn devinfo_init "void"
+.Ft void
+.Fn devinfo_free "void"
+.Ft struct devinfo_dev *
+.Fn devinfo_handle_to_device "devinfo_handle_t handle"
+.Ft struct devinfo_res *
+.Fn devinfo_handle_to_resource "devinfo_handle_t handle"
+.Ft struct devinfo_rman *
+.Fn devinfo_handle_to_rman "devinfo_handle_t handle"
+.Ft int
+.Fo devinfo_foreach_device_child
+.Fa "struct devinfo_dev *parent"
+.Fa "int \*[lp]*fn\*[rp]\*[lp]struct devinfo_dev *child, void *arg\*[rp]"
+.Fa "void *arg"
+.Fc
+.Ft int
+.Fo devinfo_foreach_device_resource
+.Fa "struct devinfo_dev *dev"
+.Fa "int \*[lp]*fn\*[rp]\*[lp]struct devinfo_dev *dev, struct devinfo_res *res, void *arg\*[rp]"
+.Fa "void *arg"
+.Fc
+.Ft int
+.Fo devinfo_foreach_rman_resource
+.Fa "struct devinfo_rman *rman"
+.Fa "int \*[lp]*fn\*[rp]\*[lp]struct devinfo_res *res, void *arg\*[rp]"
+.Fa "void *arg"
+.Fc
+.Ft int
+.Fo devinfo_foreach_rman
+.Fa "int \*[lp]*fn\*[rp]\*[lp]struct devinfo_rman *rman, void *arg\*[rp]"
+.Fa "void *arg"
+.Fc
+.Sh DESCRIPTION
+The
+.Nm
+library provides access to the kernel's internal device hierarchy
+and to the I/O resource manager.
+The library uses a
+.Xr sysctl 3
+interface to obtain a snapshot of the kernel's state,
+which is then made available to the application.
+.Pp
+Due to the fact that the information may be logically arranged
+in a number of different fashions,
+the library does not attempt to impose any structure on the data.
+.Pp
+Device, resource, and resource manager information is returned in
+data structures defined in
+.In devinfo.h :
+.Bd -literal -offset indent
+struct devinfo_dev {
+ devinfo_handle_t dd_handle; /* device handle */
+ devinfo_handle_t dd_parent; /* parent handle */
+ char *dd_name; /* name of device */
+ char *dd_desc; /* device description */
+ char *dd_drivername; /* name of attached driver */
+ char *dd_pnpinfo; /* pnp info from parent bus */
+ char *dd_location; /* Where bus thinks dev at */
+ uint32_t dd_devflags; /* API flags */
+ uint16_t dd_flags; /* internal dev flags */
+ device_state_t dd_state; /* attachment state of dev */
+};
+
+struct devinfo_rman {
+ devinfo_handle_t dm_handle; /* resource manager handle */
+ u_long dm_start; /* resource start */
+ u_long dm_size; /* resource size */
+ char *dm_desc; /* resource description */
+};
+
+struct devinfo_res {
+ devinfo_handle_t dr_handle; /* resource handle */
+ devinfo_handle_t dr_rman; /* resource manager handle */
+ devinfo_handle_t dr_device; /* owning device */
+ u_long dr_start; /* region start */
+ u_long dr_size; /* region size */
+};
+.Ed
+.Pp
+The
+.Vt devinfo_handle_t
+values can be used to look up the correspondingly referenced structures.
+.Pp
+.Fn devinfo_init
+takes a snapshot of the kernel's internal device and resource state.
+It returns nonzero
+if after a number of retries a consistent snapshot cannot be obtained.
+.Fn devinfo_init
+must be called before any other functions can be used.
+.Pp
+.Fn devinfo_free
+releases the memory associated with the snapshot.
+Any pointers returned by other functions are invalidated by this,
+and
+.Fn devinfo_init
+must be called again before using any other functions.
+.Pp
+.Fn devinfo_handle_to_device ,
+.Fn devinfo_handle_to_resource
+and
+.Fn devinfo_handle_to_rman
+return pointers to
+.Vt devinfo_dev ,
+.Vt devinfo_res
+and
+.Vt devinfo_rman
+structures respectively based on the
+.Vt devinfo_handle_t
+passed to them.
+These functions can be used to traverse the tree from any node to any
+other node.
+If
+.Fn devinfo_handle_to_device
+is passed the constant
+.Dv DEVINFO_ROOT_DEVICE
+it will return the handle to the root of the device tree.
+.Pp
+.Fn devinfo_foreach_device_child
+invokes its callback argument
+.Fa fn
+on every device which is an immediate child of
+.Fa device .
+The
+.Fa fn
+function is also passed
+.Fa arg ,
+allowing state to be passed to the callback function.
+If
+.Fa fn
+returns a nonzero error value the traversal is halted,
+and
+.Fn devinfo_foreach_device_child
+returns the error value to its caller.
+.Pp
+.Fn devinfo_foreach_device_resource
+invokes its callback argument
+.Fa fn
+on every resource which is owned by
+.Fa device .
+The
+.Fa fn
+function is also passed
+.Fa device
+and
+.Fa arg ,
+allowing state to be passed to the callback function.
+If
+.Fa fn
+returns a nonzero error value the traversal is halted,
+and
+.Fn devinfo_foreach_device_resource
+returns the error value to its caller.
+.Pp
+.Fn devinfo_foreach_rman_resource
+invokes its callback argument
+.Fa fn
+on every resource within the resource manager
+.Fa rman .
+The
+.Fa fn
+function is also passed
+.Fa arg ,
+allowing state to be passed to the callback function.
+If
+.Fa fn
+returns a nonzero error value the traversal is halted,
+and
+.Fn devinfo_foreach_rman_resource
+returns the error value to its caller.
+.Pp
+.Fn devinfo_foreach_rman
+invokes its callback argument
+.Fa fn
+on every resource manager.
+The
+.Fa fn
+function is also passed
+.Fa arg ,
+allowing state to be passed to the callback function.
+If
+.Fa fn
+returns a nonzero error value the traversal is halted,
+and
+.Fn devinfo_foreach_rman
+returns the error value to its caller.
+.Sh SEE ALSO
+.Xr devstat 3
+.Sh HISTORY
+The
+.Nm
+library first appeared in
+.Fx 5.0 .
+.Sh AUTHORS
+.An Michael Smith Aq msmith@FreeBSD.org
+.Sh BUGS
+This is the first implementation of the library,
+and the interface is still subject to refinement.
+.Pp
+The interface does not report device classes or drivers,
+making it hard to sort by class or driver.
diff --git a/lib/libdevinfo/devinfo.c b/lib/libdevinfo/devinfo.c
new file mode 100644
index 0000000..5ad68c3
--- /dev/null
+++ b/lib/libdevinfo/devinfo.c
@@ -0,0 +1,500 @@
+/*-
+ * Copyright (c) 2000 Michael Smith
+ * Copyright (c) 2000 BSDi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * An interface to the FreeBSD kernel's bus/device information interface.
+ *
+ * This interface is implemented with the
+ *
+ * hw.bus
+ * hw.bus.devices
+ * hw.bus.rman
+ *
+ * sysctls. The interface is not meant for general user application
+ * consumption.
+ *
+ * Device information is obtained by scanning a linear list of all devices
+ * maintained by the kernel. The actual device structure pointers are
+ * handed out as opaque handles in order to allow reconstruction of the
+ * logical toplogy in user space.
+ *
+ * Resource information is obtained by scanning the kernel's resource
+ * managers and fetching their contents. Ownership of resources is
+ * tracked using the device's structure pointer again as a handle.
+ *
+ * In order to ensure coherency of the library's picture of the kernel,
+ * a generation count is maintained by the kernel. The initial generation
+ * count is obtained (along with the interface version) from the hw.bus
+ * sysctl, and must be passed in with every request. If the generation
+ * number supplied by the library does not match the kernel's current
+ * generation number, the request is failed and the library must discard
+ * the data it has received and rescan.
+ *
+ * The information obtained from the kernel is exported to consumers of
+ * this library through a variety of interfaces.
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "devinfo.h"
+#include "devinfo_var.h"
+
+static int devinfo_init_devices(int generation);
+static int devinfo_init_resources(int generation);
+
+TAILQ_HEAD(,devinfo_i_dev) devinfo_dev;
+TAILQ_HEAD(,devinfo_i_rman) devinfo_rman;
+TAILQ_HEAD(,devinfo_i_res) devinfo_res;
+
+static int devinfo_initted = 0;
+static int devinfo_generation = 0;
+
+#if 0
+# define debug(fmt, args...) \
+ fprintf(stderr, "%s:" fmt "\n", __func__ , ##args)
+#else
+# define debug(fmt, args...)
+#endif
+
+/*
+ * Initialise our local database with the contents of the kernel's
+ * tables.
+ */
+int
+devinfo_init(void)
+{
+ struct u_businfo ubus;
+ size_t ub_size;
+ int error, retries;
+
+ if (!devinfo_initted) {
+ TAILQ_INIT(&devinfo_dev);
+ TAILQ_INIT(&devinfo_rman);
+ TAILQ_INIT(&devinfo_res);
+ }
+
+ /*
+ * Get the generation count and interface version, verify that we
+ * are compatible with the kernel.
+ */
+ for (retries = 0; retries < 10; retries++) {
+ debug("get interface version");
+ ub_size = sizeof(ubus);
+ if (sysctlbyname("hw.bus.info", &ubus,
+ &ub_size, NULL, 0) != 0) {
+ warn("sysctlbyname(\"hw.bus.info\", ...) failed");
+ return(EINVAL);
+ }
+ if ((ub_size != sizeof(ubus)) ||
+ (ubus.ub_version != BUS_USER_VERSION)) {
+ warn("kernel bus interface version mismatch");
+ return(EINVAL);
+ }
+ debug("generation count is %d", ubus.ub_generation);
+
+ /*
+ * Don't rescan if the generation count hasn't changed.
+ */
+ if (ubus.ub_generation == devinfo_generation)
+ return(0);
+
+ /*
+ * Generation count changed, rescan
+ */
+ devinfo_free();
+ devinfo_initted = 0;
+ devinfo_generation = 0;
+
+ if ((error = devinfo_init_devices(ubus.ub_generation)) != 0) {
+ devinfo_free();
+ if (error == EINVAL)
+ continue;
+ break;
+ }
+ if ((error = devinfo_init_resources(ubus.ub_generation)) != 0) {
+ devinfo_free();
+ if (error == EINVAL)
+ continue;
+ break;
+ }
+ devinfo_initted = 1;
+ devinfo_generation = ubus.ub_generation;
+ return(0);
+ }
+ debug("scan failed after %d retries", retries);
+ errno = error;
+ return(1);
+}
+
+static int
+devinfo_init_devices(int generation)
+{
+ struct u_device udev;
+ struct devinfo_i_dev *dd;
+ int dev_idx;
+ int dev_ptr;
+ int name2oid[2];
+ int oid[CTL_MAXNAME + 12];
+ size_t oidlen, rlen;
+ char *name;
+ int error;
+
+ /*
+ * Find the OID for the rman interface node.
+ * This is just the usual evil, undocumented sysctl juju.
+ */
+ name2oid[0] = 0;
+ name2oid[1] = 3;
+ oidlen = sizeof(oid);
+ name = "hw.bus.devices";
+ error = sysctl(name2oid, 2, oid, &oidlen, name, strlen(name));
+ if (error < 0) {
+ warnx("can't find hw.bus.devices sysctl node");
+ return(ENOENT);
+ }
+ oidlen /= sizeof(int);
+ if (oidlen > CTL_MAXNAME) {
+ warnx("hw.bus.devices oid is too large");
+ return(EINVAL);
+ }
+ oid[oidlen++] = generation;
+ dev_ptr = oidlen++;
+
+ /*
+ * Scan devices.
+ *
+ * Stop after a fairly insane number to avoid death in the case
+ * of kernel corruption.
+ */
+ for (dev_idx = 0; dev_idx < 1000; dev_idx++) {
+
+ /*
+ * Get the device information.
+ */
+ oid[dev_ptr] = dev_idx;
+ rlen = sizeof(udev);
+ error = sysctl(oid, oidlen, &udev, &rlen, NULL, 0);
+ if (error < 0) {
+ if (errno == ENOENT) /* end of list */
+ break;
+ if (errno != EINVAL) /* gen count skip, restart */
+ warn("sysctl hw.bus.devices.%d", dev_idx);
+ return(errno);
+ }
+ if ((dd = malloc(sizeof(*dd))) == NULL)
+ return(ENOMEM);
+ dd->dd_dev.dd_handle = udev.dv_handle;
+ dd->dd_dev.dd_parent = udev.dv_parent;
+ snprintf(dd->dd_name, sizeof(dd->dd_name), "%s", udev.dv_name);
+ dd->dd_dev.dd_name = &dd->dd_name[0];
+ snprintf(dd->dd_desc, sizeof(dd->dd_desc), "%s", udev.dv_desc);
+ dd->dd_dev.dd_desc = &dd->dd_desc[0];
+ snprintf(dd->dd_drivername, sizeof(dd->dd_drivername), "%s",
+ udev.dv_drivername);
+ dd->dd_dev.dd_drivername = &dd->dd_drivername[0];
+ snprintf(dd->dd_pnpinfo, sizeof(dd->dd_pnpinfo), "%s",
+ udev.dv_pnpinfo);
+ dd->dd_dev.dd_pnpinfo = &dd->dd_pnpinfo[0];
+ snprintf(dd->dd_location, sizeof(dd->dd_location), "%s",
+ udev.dv_location);
+ dd->dd_dev.dd_location = &dd->dd_location[0];
+ dd->dd_dev.dd_devflags = udev.dv_devflags;
+ dd->dd_dev.dd_flags = udev.dv_flags;
+ dd->dd_dev.dd_state = udev.dv_state;
+ TAILQ_INSERT_TAIL(&devinfo_dev, dd, dd_link);
+ }
+ debug("fetched %d devices", dev_idx);
+ return(0);
+}
+
+static int
+devinfo_init_resources(int generation)
+{
+ struct u_rman urman;
+ struct devinfo_i_rman *dm;
+ struct u_resource ures;
+ struct devinfo_i_res *dr;
+ int rman_idx, res_idx;
+ int rman_ptr, res_ptr;
+ int name2oid[2];
+ int oid[CTL_MAXNAME + 12];
+ size_t oidlen, rlen;
+ char *name;
+ int error;
+
+ /*
+ * Find the OID for the rman interface node.
+ * This is just the usual evil, undocumented sysctl juju.
+ */
+ name2oid[0] = 0;
+ name2oid[1] = 3;
+ oidlen = sizeof(oid);
+ name = "hw.bus.rman";
+ error = sysctl(name2oid, 2, oid, &oidlen, name, strlen(name));
+ if (error < 0) {
+ warnx("can't find hw.bus.rman sysctl node");
+ return(ENOENT);
+ }
+ oidlen /= sizeof(int);
+ if (oidlen > CTL_MAXNAME) {
+ warnx("hw.bus.rman oid is too large");
+ return(EINVAL);
+ }
+ oid[oidlen++] = generation;
+ rman_ptr = oidlen++;
+ res_ptr = oidlen++;
+
+ /*
+ * Scan resource managers.
+ *
+ * Stop after a fairly insane number to avoid death in the case
+ * of kernel corruption.
+ */
+ for (rman_idx = 0; rman_idx < 255; rman_idx++) {
+
+ /*
+ * Get the resource manager information.
+ */
+ oid[rman_ptr] = rman_idx;
+ oid[res_ptr] = -1;
+ rlen = sizeof(urman);
+ error = sysctl(oid, oidlen, &urman, &rlen, NULL, 0);
+ if (error < 0) {
+ if (errno == ENOENT) /* end of list */
+ break;
+ if (errno != EINVAL) /* gen count skip, restart */
+ warn("sysctl hw.bus.rman.%d", rman_idx);
+ return(errno);
+ }
+ if ((dm = malloc(sizeof(*dm))) == NULL)
+ return(ENOMEM);
+ dm->dm_rman.dm_handle = urman.rm_handle;
+ dm->dm_rman.dm_start = urman.rm_start;
+ dm->dm_rman.dm_size = urman.rm_size;
+ snprintf(dm->dm_desc, DEVINFO_STRLEN, "%s", urman.rm_descr);
+ dm->dm_rman.dm_desc = &dm->dm_desc[0];
+ TAILQ_INSERT_TAIL(&devinfo_rman, dm, dm_link);
+
+ /*
+ * Scan resources on this resource manager.
+ *
+ * Stop after a fairly insane number to avoid death in the case
+ * of kernel corruption.
+ */
+ for (res_idx = 0; res_idx < 1000; res_idx++) {
+ /*
+ * Get the resource information.
+ */
+ oid[res_ptr] = res_idx;
+ rlen = sizeof(ures);
+ error = sysctl(oid, oidlen, &ures, &rlen, NULL, 0);
+ if (error < 0) {
+ if (errno == ENOENT) /* end of list */
+ break;
+ if (errno != EINVAL) /* gen count skip */
+ warn("sysctl hw.bus.rman.%d.%d",
+ rman_idx, res_idx);
+ return(errno);
+ }
+ if ((dr = malloc(sizeof(*dr))) == NULL)
+ return(ENOMEM);
+ dr->dr_res.dr_handle = ures.r_handle;
+ dr->dr_res.dr_rman = ures.r_parent;
+ dr->dr_res.dr_device = ures.r_device;
+ dr->dr_res.dr_start = ures.r_start;
+ dr->dr_res.dr_size = ures.r_size;
+ TAILQ_INSERT_TAIL(&devinfo_res, dr, dr_link);
+ }
+ debug("fetched %d resources", res_idx);
+ }
+ debug("scanned %d resource managers", rman_idx);
+ return(0);
+}
+
+/*
+ * Free the list contents.
+ */
+void
+devinfo_free(void)
+{
+ struct devinfo_i_dev *dd;
+ struct devinfo_i_rman *dm;
+ struct devinfo_i_res *dr;
+
+ while ((dd = TAILQ_FIRST(&devinfo_dev)) != NULL) {
+ TAILQ_REMOVE(&devinfo_dev, dd, dd_link);
+ free(dd);
+ }
+ while ((dm = TAILQ_FIRST(&devinfo_rman)) != NULL) {
+ TAILQ_REMOVE(&devinfo_rman, dm, dm_link);
+ free(dm);
+ }
+ while ((dr = TAILQ_FIRST(&devinfo_res)) != NULL) {
+ TAILQ_REMOVE(&devinfo_res, dr, dr_link);
+ free(dr);
+ }
+ devinfo_initted = 0;
+ devinfo_generation = 0;
+}
+
+/*
+ * Find a device by its handle.
+ */
+struct devinfo_dev *
+devinfo_handle_to_device(devinfo_handle_t handle)
+{
+ struct devinfo_i_dev *dd;
+
+ /*
+ * Find the root device, whose parent is NULL
+ */
+ if (handle == DEVINFO_ROOT_DEVICE) {
+ TAILQ_FOREACH(dd, &devinfo_dev, dd_link)
+ if (dd->dd_dev.dd_parent == DEVINFO_ROOT_DEVICE)
+ return(&dd->dd_dev);
+ return(NULL);
+ }
+
+ /*
+ * Scan for the device
+ */
+ TAILQ_FOREACH(dd, &devinfo_dev, dd_link)
+ if (dd->dd_dev.dd_handle == handle)
+ return(&dd->dd_dev);
+ return(NULL);
+}
+
+/*
+ * Find a resource by its handle.
+ */
+struct devinfo_res *
+devinfo_handle_to_resource(devinfo_handle_t handle)
+{
+ struct devinfo_i_res *dr;
+
+ TAILQ_FOREACH(dr, &devinfo_res, dr_link)
+ if (dr->dr_res.dr_handle == handle)
+ return(&dr->dr_res);
+ return(NULL);
+}
+
+/*
+ * Find a resource manager by its handle.
+ */
+struct devinfo_rman *
+devinfo_handle_to_rman(devinfo_handle_t handle)
+{
+ struct devinfo_i_rman *dm;
+
+ TAILQ_FOREACH(dm, &devinfo_rman, dm_link)
+ if (dm->dm_rman.dm_handle == handle)
+ return(&dm->dm_rman);
+ return(NULL);
+}
+
+/*
+ * Iterate over the children of a device, calling (fn) on each. If
+ * (fn) returns nonzero, abort the scan and return.
+ */
+int
+devinfo_foreach_device_child(struct devinfo_dev *parent,
+ int (* fn)(struct devinfo_dev *child, void *arg),
+ void *arg)
+{
+ struct devinfo_i_dev *dd;
+ int error;
+
+ TAILQ_FOREACH(dd, &devinfo_dev, dd_link)
+ if (dd->dd_dev.dd_parent == parent->dd_handle)
+ if ((error = fn(&dd->dd_dev, arg)) != 0)
+ return(error);
+ return(0);
+}
+
+/*
+ * Iterate over all the resources owned by a device, calling (fn) on each.
+ * If (fn) returns nonzero, abort the scan and return.
+ */
+int
+devinfo_foreach_device_resource(struct devinfo_dev *dev,
+ int (* fn)(struct devinfo_dev *dev, struct devinfo_res *res, void *arg),
+ void *arg)
+{
+ struct devinfo_i_res *dr;
+ int error;
+
+ TAILQ_FOREACH(dr, &devinfo_res, dr_link)
+ if (dr->dr_res.dr_device == dev->dd_handle)
+ if ((error = fn(dev, &dr->dr_res, arg)) != 0)
+ return(error);
+ return(0);
+}
+
+/*
+ * Iterate over all the resources owned by a resource manager, calling (fn)
+ * on each. If (fn) returns nonzero, abort the scan and return.
+ */
+extern int
+devinfo_foreach_rman_resource(struct devinfo_rman *rman,
+ int (* fn)(struct devinfo_res *res, void *arg),
+ void *arg)
+{
+ struct devinfo_i_res *dr;
+ int error;
+
+ TAILQ_FOREACH(dr, &devinfo_res, dr_link)
+ if (dr->dr_res.dr_rman == rman->dm_handle)
+ if ((error = fn(&dr->dr_res, arg)) != 0)
+ return(error);
+ return(0);
+}
+
+/*
+ * Iterate over all the resource managers, calling (fn) on each. If (fn)
+ * returns nonzero, abort the scan and return.
+ */
+extern int
+devinfo_foreach_rman(int (* fn)(struct devinfo_rman *rman, void *arg),
+ void *arg)
+{
+ struct devinfo_i_rman *dm;
+ int error;
+
+ TAILQ_FOREACH(dm, &devinfo_rman, dm_link)
+ if ((error = fn(&dm->dm_rman, arg)) != 0)
+ return(error);
+ return(0);
+}
diff --git a/lib/libdevinfo/devinfo.h b/lib/libdevinfo/devinfo.h
new file mode 100644
index 0000000..91930a4
--- /dev/null
+++ b/lib/libdevinfo/devinfo.h
@@ -0,0 +1,147 @@
+/*-
+ * Copyright (c) 2000 Michael Smith
+ * Copyright (c) 2000 BSDi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 _DEVINFO_H_INCLUDED
+#define _DEVINFO_H_INCLUDED
+
+#include <sys/cdefs.h>
+#include <sys/_types.h>
+
+typedef __uintptr_t devinfo_handle_t;
+#define DEVINFO_ROOT_DEVICE ((devinfo_handle_t)0)
+
+/*
+ * State of the device.
+ */
+/* XXX not sure if I want a copy here, or expose sys/bus.h */
+typedef enum devinfo_state {
+ DIS_NOTPRESENT, /* not probed or probe failed */
+ DIS_ALIVE, /* probe succeeded */
+ DIS_ATTACHED, /* attach method called */
+ DIS_BUSY /* device is open */
+} devinfo_state_t;
+
+struct devinfo_dev {
+ devinfo_handle_t dd_handle; /* device handle */
+ devinfo_handle_t dd_parent; /* parent handle */
+
+ char *dd_name; /* name of device */
+ char *dd_desc; /* device description */
+ char *dd_drivername; /* name of attached driver*/
+ char *dd_pnpinfo; /* pnp info from parent bus */
+ char *dd_location; /* Where bus thinks dev at */
+ uint32_t dd_devflags; /* API flags */
+ uint16_t dd_flags; /* internal dev flags */
+ devinfo_state_t dd_state; /* attacement state of dev */
+};
+
+struct devinfo_rman {
+ devinfo_handle_t dm_handle; /* resource manager handle */
+
+ unsigned long dm_start; /* resource start */
+ unsigned long dm_size; /* resource size */
+
+ char *dm_desc; /* resource description */
+};
+
+struct devinfo_res {
+ devinfo_handle_t dr_handle; /* resource handle */
+ devinfo_handle_t dr_rman; /* resource manager handle */
+ devinfo_handle_t dr_device; /* owning device */
+
+ unsigned long dr_start; /* region start */
+ unsigned long dr_size; /* region size */
+ /* XXX add flags */
+};
+
+__BEGIN_DECLS
+
+/*
+ * Acquire a coherent copy of the kernel's device and resource tables.
+ * This must return success (zero) before any other interfaces will
+ * function. Sets errno on failure.
+ */
+extern int devinfo_init(void);
+
+/*
+ * Release the storage associated with the internal copy of the device
+ * and resource tables. devinfo_init must be called before any attempt
+ * is made to use any other interfaces.
+ */
+extern void devinfo_free(void);
+
+/*
+ * Find a device/resource/resource manager by its handle.
+ */
+extern struct devinfo_dev
+ *devinfo_handle_to_device(devinfo_handle_t handle);
+extern struct devinfo_res
+ *devinfo_handle_to_resource(devinfo_handle_t handle);
+extern struct devinfo_rman
+ *devinfo_handle_to_rman(devinfo_handle_t handle);
+
+/*
+ * Iterate over the children of a device, calling (fn) on each. If
+ * (fn) returns nonzero, abort the scan and return.
+ */
+extern int
+ devinfo_foreach_device_child(struct devinfo_dev *parent,
+ int (* fn)(struct devinfo_dev *child, void *arg),
+ void *arg);
+
+/*
+ * Iterate over all the resources owned by a device, calling (fn) on each.
+ * If (fn) returns nonzero, abort the scan and return.
+ */
+extern int
+ devinfo_foreach_device_resource(struct devinfo_dev *dev,
+ int (* fn)(struct devinfo_dev *dev,
+ struct devinfo_res *res, void *arg),
+ void *arg);
+
+/*
+ * Iterate over all the resources owned by a resource manager, calling (fn)
+ * on each. If (fn) returns nonzero, abort the scan and return.
+ */
+extern int
+ devinfo_foreach_rman_resource(struct devinfo_rman *rman,
+ int (* fn)(struct devinfo_res *res, void *arg),
+ void *arg);
+
+/*
+ * Iterate over all the resource managers, calling (fn) on each. If (fn)
+ * returns nonzero, abort the scan and return.
+ */
+extern int
+ devinfo_foreach_rman(int (* fn)(struct devinfo_rman *rman, void *arg),
+ void *arg);
+
+__END_DECLS
+
+#endif /* ! _DEVINFO_H_INCLUDED */
diff --git a/lib/libdevinfo/devinfo_var.h b/lib/libdevinfo/devinfo_var.h
new file mode 100644
index 0000000..b409671
--- /dev/null
+++ b/lib/libdevinfo/devinfo_var.h
@@ -0,0 +1,70 @@
+/*-
+ * Copyright (c) 2000 Michael Smith
+ * Copyright (c) 2000 BSDi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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/rman.h>
+#include <sys/bus.h>
+
+/*
+ * This is defined by the version 1 interface.
+ */
+#define DEVINFO_STRLEN 32
+
+/*
+ * Devices.
+ *
+ * Internal structure contains string buffers and list linkage;
+ */
+struct devinfo_i_dev {
+ struct devinfo_dev dd_dev;
+ char dd_name[DEVINFO_STRLEN];
+ char dd_desc[DEVINFO_STRLEN];
+ char dd_drivername[DEVINFO_STRLEN];
+ char dd_pnpinfo[DEVINFO_STRLEN * 4];
+ char dd_location[DEVINFO_STRLEN * 4];
+ uint32_t dd_devflags;
+ uint16_t dd_flags;
+ device_state_t dd_state;
+ TAILQ_ENTRY(devinfo_i_dev) dd_link;
+};
+
+/*
+ * Resources.
+ *
+ * Internal structures contain string buffers and list linkage;
+ */
+struct devinfo_i_rman {
+ struct devinfo_rman dm_rman;
+ char dm_desc[32];
+ TAILQ_ENTRY(devinfo_i_rman) dm_link;
+};
+
+struct devinfo_i_res {
+ struct devinfo_res dr_res;
+ TAILQ_ENTRY(devinfo_i_res) dr_link;
+};
diff --git a/lib/libdevstat/Makefile b/lib/libdevstat/Makefile
new file mode 100644
index 0000000..61b1994
--- /dev/null
+++ b/lib/libdevstat/Makefile
@@ -0,0 +1,38 @@
+# $FreeBSD$
+
+LIB= devstat
+SHLIBDIR?= /lib
+# Bump DEVSTAT_USER_API_VER in devstat.h every time this is incremented.
+SHLIB_MAJOR= 5
+SRCS= devstat.c
+INCS= devstat.h
+
+DPADD= ${LIBKVM}
+LDADD= -lkvm
+
+MAN= devstat.3
+
+MLINKS+=devstat.3 devstat_getnumdevs.3
+MLINKS+=devstat.3 devstat_getgeneration.3
+MLINKS+=devstat.3 devstat_getversion.3
+MLINKS+=devstat.3 devstat_checkversion.3
+MLINKS+=devstat.3 devstat_getdevs.3
+MLINKS+=devstat.3 devstat_selectdevs.3
+MLINKS+=devstat.3 devstat_buildmatch.3
+MLINKS+=devstat.3 devstat_compute_statistics.3
+MLINKS+=devstat.3 devstat_compute_etime.3
+MLINKS+=devstat.3 getnumdevs.3
+MLINKS+=devstat.3 getgeneration.3
+MLINKS+=devstat.3 getversion.3
+MLINKS+=devstat.3 checkversion.3
+MLINKS+=devstat.3 getdevs.3
+MLINKS+=devstat.3 selectdevs.3
+MLINKS+=devstat.3 buildmatch.3
+MLINKS+=devstat.3 compute_stats.3
+MLINKS+=devstat.3 compute_etime.3
+
+CFLAGS+=-I${.CURDIR}
+
+WARNS?= 2
+
+.include <bsd.lib.mk>
diff --git a/lib/libdevstat/devstat.3 b/lib/libdevstat/devstat.3
new file mode 100644
index 0000000..849a149
--- /dev/null
+++ b/lib/libdevstat/devstat.3
@@ -0,0 +1,795 @@
+.\"
+.\" Copyright (c) 1998, 1999, 2001 Kenneth D. Merry.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce 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 March 18, 2003
+.Dt DEVSTAT 3
+.Os
+.Sh NAME
+.Nm devstat ,
+.Nm devstat_getnumdevs ,
+.Nm devstat_getgeneration ,
+.Nm devstat_getversion ,
+.Nm devstat_checkversion ,
+.Nm devstat_getdevs ,
+.Nm devstat_selectdevs ,
+.Nm devstat_buildmatch ,
+.Nm devstat_compute_statistics ,
+.Nm devstat_compute_etime
+.Nd device statistics utility library
+.Sh LIBRARY
+.Lb libdevstat
+.Sh SYNOPSIS
+.In devstat.h
+.Ft int
+.Fn devstat_getnumdevs "kvm_t *kd"
+.Ft long
+.Fn devstat_getgeneration "kvm_t *kd"
+.Ft int
+.Fn devstat_getversion "kvm_t *kd"
+.Ft int
+.Fn devstat_checkversion "kvm_t *kd"
+.Ft int
+.Fn devstat_getdevs "kvm_t *kd" "struct statinfo *stats"
+.Ft int
+.Fo devstat_selectdevs
+.Fa "struct device_selection **dev_select"
+.Fa "int *num_selected"
+.Fa "int *num_selections"
+.Fa "long *select_generation"
+.Fa "long current_generation"
+.Fa "struct devstat *devices"
+.Fa "int numdevs"
+.Fa "struct devstat_match *matches"
+.Fa "int num_matches"
+.Fa "char **dev_selections"
+.Fa "int num_dev_selections"
+.Fa "devstat_select_mode select_mode"
+.Fa "int maxshowdevs"
+.Fa "int perf_select"
+.Fc
+.Ft int
+.Fo devstat_buildmatch
+.Fa "char *match_str"
+.Fa "struct devstat_match **matches"
+.Fa "int *num_matches"
+.Fc
+.Ft int
+.Fo devstat_compute_statistics
+.Fa "struct devstat *current"
+.Fa "struct devstat *previous"
+.Fa "long double etime"
+.Fa "..."
+.Fc
+.Ft "long double"
+.Fo devstat_compute_etime
+.Fa "struct bintime *cur_time"
+.Fa "struct bintime *prev_time"
+.Fc
+.Sh DESCRIPTION
+The
+.Nm
+library is a library of helper functions for dealing with the kernel
+.Xr devstat 9
+interface, which is accessible to users via
+.Xr sysctl 3
+and
+.Xr kvm 3 .
+All functions that take a
+.Vt "kvm_t *"
+as first argument can be passed
+.Dv NULL
+instead of a kvm handle as this argument,
+which causes the data to be read via
+.Xr sysctl 3 .
+Otherwise, it is read via
+.Xr kvm 3
+using the supplied handle.
+The
+.Fn devstat_checkversion
+function
+should be called with each kvm handle that is going to be used (or with
+.Dv NULL
+if
+.Xr sysctl 3
+is going to be used).
+.Pp
+The
+.Fn devstat_getnumdevs
+function
+returns the number of devices registered with the
+.Nm
+subsystem in the kernel.
+.Pp
+The
+.Fn devstat_getgeneration
+function
+returns the current generation of the
+.Nm
+list of devices in the kernel.
+.Pp
+The
+.Fn devstat_getversion
+function
+returns the current kernel
+.Nm
+version.
+.Pp
+The
+.Fn devstat_checkversion
+function
+checks the userland
+.Nm
+version against the kernel
+.Nm
+version.
+If the two are identical, it returns zero.
+Otherwise, it prints an appropriate error in
+.Va devstat_errbuf
+and returns \-1.
+.Pp
+The
+.Fn devstat_getdevs
+function
+fetches the current list of devices and statistics into the supplied
+.Vt statinfo
+structure.
+The
+.Vt statinfo
+structure can be found in
+.In devstat.h :
+.Bd -literal -offset indent
+struct statinfo {
+ long cp_time[CPUSTATES];
+ long tk_nin;
+ long tk_nout;
+ struct devinfo *dinfo;
+ long double snap_time;
+};
+.Ed
+.Pp
+The
+.Fn devstat_getdevs
+function
+expects the
+.Vt statinfo
+structure to be allocated, and it also expects the
+.Va dinfo
+subelement to be allocated and zeroed prior to the first invocation of
+.Fn devstat_getdevs .
+The
+.Va dinfo
+subelement is used to store state between calls, and should not be modified
+after the first call to
+.Fn devstat_getdevs .
+The
+.Va dinfo
+subelement contains the following elements:
+.Bd -literal -offset indent
+struct devinfo {
+ struct devstat *devices;
+ u_int8_t *mem_ptr;
+ long generation;
+ int numdevs;
+};
+.Ed
+.Pp
+The
+.Va kern.devstat.all
+.Xr sysctl 8
+variable contains an array of
+.Nm
+structures, but at the head of the array is the current
+.Nm
+generation.
+The reason the generation is at the head of the buffer is so that userland
+software accessing the
+.Nm
+statistics information can atomically get
+both the statistics information and the corresponding generation number.
+If client software were forced to get the generation number via a separate
+.Xr sysctl 8
+variable (which is available for convenience), the list of devices could
+change between the time the client gets the generation and the time the
+client gets the device list.
+.Pp
+The
+.Va mem_ptr
+subelement of the
+.Vt devinfo
+structure is a pointer to memory that is allocated, and resized if
+necessary, by
+.Fn devstat_getdevs .
+The devices subelement of the
+.Vt devinfo
+structure is basically a pointer to the beginning of the array of devstat
+structures from the
+.Va kern.devstat.all
+.Xr sysctl 8
+variable (or the corresponding values read via
+.Xr kvm 3 ) .
+The generation subelement of the
+.Vt devinfo
+structure contains the corresponding generation number.
+The
+.Va numdevs
+subelement of the
+.Vt devinfo
+structure contains the current
+number of devices registered with the kernel
+.Nm
+subsystem.
+.Pp
+The
+.Fn devstat_selectdevs
+function
+selects devices to display based upon a number of criteria:
+.Bl -tag -width indent
+.It specified devices
+Specified devices are the first selection priority.
+These are generally devices specified by name by the user e.g.\&
+.Li da0 , da1 , cd0 .
+.It match patterns
+These are pattern matching expressions generated by
+.Fn devstat_buildmatch
+from user input.
+.It performance
+If performance mode is enabled, devices will be sorted based on the
+.Va bytes
+field in the
+.Vt device_selection
+structure passed in to
+.Fn devstat_selectdevs .
+The
+.Va bytes
+value currently must be maintained by the user.
+In the future, this may be done for him in a
+.Nm
+library routine.
+If no devices have been selected by name or by pattern, the performance
+tracking code will select every device in the system, and sort them by
+performance.
+If devices have been selected by name or pattern, the performance tracking
+code will honor those selections and will only sort among the selected
+devices.
+.It order in the devstat list
+If the selection mode is set to
+.Dv DS_SELECT_ADD ,
+and if there are still less
+than
+.Fa maxshowdevs
+devices selected,
+.Fn devstat_selectdevs
+will automatically select up to
+.Fa maxshowdevs
+devices.
+.El
+.Pp
+The
+.Fn devstat_selectdevs
+function
+performs selections in four different modes:
+.Bl -tag -width ".Dv DS_SELECT_ADDONLY"
+.It Dv DS_SELECT_ADD
+In
+.Dq add
+mode,
+.Fn devstat_selectdevs
+will select any unselected devices specified by name or matching pattern.
+It will also select more devices, in devstat list order, until the number
+of selected devices is equal to
+.Fa maxshowdevs
+or until all devices are
+selected.
+.It Dv DS_SELECT_ONLY
+In
+.Dq only
+mode,
+.Fn devstat_selectdevs
+will clear all current selections, and will only select devices specified
+by name or by matching pattern.
+.It Dv DS_SELECT_REMOVE
+In
+.Dq remove
+mode,
+.Fn devstat_selectdevs
+will remove devices specified by name or by matching pattern.
+It will not select any additional devices.
+.It Dv DS_SELECT_ADDONLY
+In
+.Dq "add only"
+mode,
+.Fn devstat_selectdevs
+will select any unselected devices specified by name or matching pattern.
+In this respect it is identical to
+.Dq add
+mode.
+It will not, however, select any devices other than those specified.
+.El
+.Pp
+In all selection modes,
+.Fn devstat_selectdevs
+will not select any more than
+.Fa maxshowdevs
+devices.
+One exception to this is when you are in
+.Dq top
+mode and no devices have been selected.
+In this case,
+.Fn devstat_selectdevs
+will select every device in the system.
+Client programs must pay attention to selection order when deciding whether
+to pay attention to a particular device.
+This may be the wrong behavior, and probably requires additional thought.
+.Pp
+The
+.Fn devstat_selectdevs
+function
+handles allocation and resizing of the
+.Fa dev_select
+structure passed in
+by the client.
+The
+.Fn devstat_selectdevs
+function
+uses the
+.Fa numdevs
+and
+.Fa current_generation
+fields to track the
+current
+.Nm
+generation and number of devices.
+If
+.Fa num_selections
+is not the same
+as
+.Fa numdevs
+or if
+.Fa select_generation
+is not the same as
+.Fa current_generation ,
+.Fn devstat_selectdevs
+will resize the selection list as necessary, and re-initialize the
+selection array.
+.Pp
+The
+.Fn devstat_buildmatch
+function
+takes a comma separated match string and compiles it into a
+.Vt devstat_match
+structure that is understood by
+.Fn devstat_selectdevs .
+Match strings have the following format:
+.Pp
+.D1 Ar device , Ns Ar type , Ns Ar if
+.Pp
+The
+.Fn devstat_buildmatch
+function
+takes care of allocating and reallocating the match list as necessary.
+Currently known match types include:
+.Bl -tag -width indent
+.It device type:
+.Bl -tag -width ".Li enclosure" -compact
+.It Li da
+Direct Access devices
+.It Li sa
+Sequential Access devices
+.It Li printer
+Printers
+.It Li proc
+Processor devices
+.It Li worm
+Write Once Read Multiple devices
+.It Li cd
+CD devices
+.It Li scanner
+Scanner devices
+.It Li optical
+Optical Memory devices
+.It Li changer
+Medium Changer devices
+.It Li comm
+Communication devices
+.It Li array
+Storage Array devices
+.It Li enclosure
+Enclosure Services devices
+.It Li floppy
+Floppy devices
+.El
+.It interface:
+.Bl -tag -width ".Li enclosure" -compact
+.It Li IDE
+Integrated Drive Electronics devices
+.It Li SCSI
+Small Computer System Interface devices
+.It Li other
+Any other device interface
+.El
+.It passthrough:
+.Bl -tag -width ".Li enclosure" -compact
+.It Li pass
+Passthrough devices
+.El
+.El
+.Pp
+The
+.Fn devstat_compute_statistics
+function provides complete statistics calculation.
+There are four arguments for which values
+.Em must
+be supplied:
+.Fa current ,
+.Fa previous ,
+.Fa etime ,
+and the terminating argument for the varargs list,
+.Dv DSM_NONE .
+For most applications, the user will want to supply valid
+.Vt devstat
+structures for both
+.Fa current
+and
+.Fa previous .
+In some instances, for instance when calculating statistics since system
+boot, the user may pass in a
+.Dv NULL
+pointer for the
+.Fa previous
+argument.
+In that case,
+.Fn devstat_compute_statistics
+will use the total stats in the
+.Fa current
+structure to calculate statistics over
+.Fa etime .
+For each statistics to be calculated, the user should supply the proper
+enumerated type (listed below), and a variable of the indicated type.
+All statistics are either integer values, for which a
+.Vt u_int64_t
+is used,
+or floating point, for which a
+.Vt "long double"
+is used.
+The statistics that may be calculated are:
+.Bl -tag -width ".Dv DSM_TRANSFERS_PER_SECOND_OTHER"
+.It Dv DSM_NONE
+type: N/A
+.Pp
+This
+.Em must
+be the last argument passed to
+.Fn devstat_compute_statistics .
+It is an argument list terminator.
+.It Dv DSM_TOTAL_BYTES
+type:
+.Vt "u_int64_t *"
+.Pp
+The total number of bytes transferred between the acquisition of
+.Fa previous
+and
+.Fa current .
+.It Dv DSM_TOTAL_BYTES_READ
+.It Dv DSM_TOTAL_BYTES_WRITE
+.It Dv DSM_TOTAL_BYTES_FREE
+type:
+.Vt "u_int64_t *"
+.Pp
+The total number of bytes in transactions of the specified type
+between the acquisition of
+.Fa previous
+and
+.Fa current .
+.It Dv DSM_TOTAL_TRANSFERS
+type:
+.Vt "u_int64_t *"
+.Pp
+The total number of transfers between the acquisition of
+.Fa previous
+and
+.Fa current .
+.It Dv DSM_TOTAL_TRANSFERS_OTHER
+.It Dv DSM_TOTAL_TRANSFERS_READ
+.It Dv DSM_TOTAL_TRANSFERS_WRITE
+.It Dv DSM_TOTAL_TRANSFERS_FREE
+type:
+.Vt "u_int64_t *"
+.Pp
+The total number of transactions of the specified type between
+the acquisition of
+.Fa previous
+and
+.Fa current .
+.It Dv DSM_TOTAL_BLOCKS
+type:
+.Vt "u_int64_t *"
+.Pp
+The total number of blocks transferred between the acquisition of
+.Fa previous
+and
+.Fa current .
+This number is in terms of the blocksize reported by the device.
+If no blocksize has been reported (i.e., the block size is 0), a default
+blocksize of 512 bytes will be used in the calculation.
+.It Dv DSM_TOTAL_BLOCKS_READ
+.It Dv DSM_TOTAL_BLOCKS_WRITE
+.It Dv DSM_TOTAL_BLOCKS_FREE
+type:
+.Vt "u_int64_t *"
+.Pp
+The total number of blocks of the specified type between the acquisition of
+.Fa previous
+and
+.Fa current .
+This number is in terms of the blocksize reported by the device.
+If no blocksize has been reported (i.e., the block size is 0), a default
+blocksize of 512 bytes will be used in the calculation.
+.It Dv DSM_KB_PER_TRANSFER
+type:
+.Vt "long double *"
+.Pp
+The average number of kilobytes per transfer between the acquisition of
+.Fa previous
+and
+.Fa current .
+.It Dv DSM_KB_PER_TRANSFER_READ
+.It Dv DSM_KB_PER_TRANSFER_WRITE
+.It Dv DSM_KB_PER_TRANSFER_FREE
+type:
+.Vt "long double *"
+.Pp
+The average number of kilobytes in the specified type transaction between
+the acquisition of
+.Fa previous
+and
+.Fa current .
+.It Dv DSM_TRANSFERS_PER_SECOND
+type:
+.Vt "long double *"
+.Pp
+The average number of transfers per second between the acquisition of
+.Fa previous
+and
+.Fa current .
+.It Dv DSM_TRANSFERS_PER_SECOND_OTHER
+.It Dv DSM_TRANSFERS_PER_SECOND_READ
+.It Dv DSM_TRANSFERS_PER_SECOND_WRITE
+.It Dv DSM_TRANSFERS_PER_SECOND_FREE
+type:
+.Vt "long double *"
+.Pp
+The average number of transactions of the specified type per second
+between the acquisition of
+.Fa previous
+and
+.Fa current .
+.It Dv DSM_MB_PER_SECOND
+type:
+.Vt "long double *"
+.Pp
+The average number of megabytes transferred per second between the
+acquisition of
+.Fa previous
+and
+.Fa current .
+.It Dv DSM_MB_PER_SECOND_READ
+.It Dv DSM_MB_PER_SECOND_WRITE
+.It Dv DSM_MB_PER_SECOND_FREE
+type:
+.Vt "long double *"
+.Pp
+The average number of megabytes per second in the specified type of
+transaction between the acquisition of
+.Fa previous
+and
+.Fa current .
+.It Dv DSM_BLOCKS_PER_SECOND
+type:
+.Vt "long double *"
+.Pp
+The average number of blocks transferred per second between the acquisition of
+.Fa previous
+and
+.Fa current .
+This number is in terms of the blocksize reported by the device.
+If no blocksize has been reported (i.e., the block size is 0), a default
+blocksize of 512 bytes will be used in the calculation.
+.It Dv DSM_BLOCKS_PER_SECOND_READ
+.It Dv DSM_BLOCKS_PER_SECOND_WRITE
+.It Dv DSM_BLOCKS_PER_SECOND_FREE
+type:
+.Vt "long double *"
+.Pp
+The average number of blocks per second in the specificed type of transaction
+between the acquisition of
+.Fa previous
+and
+.Fa current .
+This number is in terms of the blocksize reported by the device.
+If no blocksize has been reported (i.e., the block size is 0), a default
+blocksize of 512 bytes will be used in the calculation.
+.It Dv DSM_MS_PER_TRANSACTION
+type:
+.Vt "long double *"
+.Pp
+The average duration of transactions between the acquisition of
+.Fa previous
+and
+.Fa current .
+.It Dv DSM_MS_PER_TRANSACTION_OTHER
+.It Dv DSM_MS_PER_TRANSACTION_READ
+.It Dv DSM_MS_PER_TRANSACTION_WRITE
+.It Dv DSM_MS_PER_TRANSACTION_FREE
+type:
+.Vt "long double *"
+.Pp
+The average duration of transactions of the specified type between the
+acquisition of
+.Fa previous
+and
+.Fa current .
+.It Dv DSM_BUSY_PCT
+type:
+.Vt "long double *"
+.Pp
+The percentage of time the device had one or more transactions outstanding
+between the acquisition of
+.Fa previous
+and
+.Fa current .
+.It Dv DSM_QUEUE_LENGTH
+type:
+.Vt "u_int64_t *"
+.Pp
+The number of not yet completed transactions at the time when
+.Fa current
+was acquired.
+.It Dv DSM_SKIP
+type: N/A
+.Pp
+If you do not need a result from
+.Fn devstat_compute_statistics ,
+just put
+.Dv DSM_SKIP
+as first (type) parameter and
+.Dv NULL
+as second parameter.
+This can be useful in scenarios where the statistics to be calculated
+are determined at run time.
+.El
+.Pp
+The
+.Fn devstat_compute_etime
+function
+provides an easy way to find the difference in seconds between two
+.Vt bintime
+structures.
+This is most commonly used in conjunction with the time recorded by the
+.Fn devstat_getdevs
+function (in
+.Vt "struct statinfo" )
+each time it fetches the current
+.Nm
+list.
+.Sh RETURN VALUES
+The
+.Fn devstat_getnumdevs ,
+.Fn devstat_getgeneration ,
+and
+.Fn devstat_getversion
+function
+return the indicated sysctl variable, or \-1 if there is an error
+fetching the variable.
+.Pp
+The
+.Fn devstat_checkversion
+function
+returns 0 if the kernel and userland
+.Nm
+versions match.
+If they do not match, it returns \-1.
+.Pp
+The
+.Fn devstat_getdevs
+and
+.Fn devstat_selectdevs
+functions
+return \-1 in case of an error, 0 if there is no error, and 1 if the device
+list or selected devices have changed.
+A return value of 1 from
+.Fn devstat_getdevs
+is usually a hint to re-run
+.Fn devstat_selectdevs
+because the device list has changed.
+.Pp
+The
+.Fn devstat_buildmatch
+function returns \-1 for error, and 0 if there is no error.
+.Pp
+The
+.Fn devstat_compute_etime
+function
+returns the computed elapsed time.
+.Pp
+The
+.Fn devstat_compute_statistics
+function returns \-1 for error, and 0 for success.
+.Pp
+If an error is returned from one of the
+.Nm
+library functions, the reason for the error is generally printed in
+the global string
+.Va devstat_errbuf
+which is
+.Dv DEVSTAT_ERRBUF_SIZE
+characters long.
+.Sh SEE ALSO
+.Xr systat 1 ,
+.Xr kvm 3 ,
+.Xr sysctl 3 ,
+.Xr iostat 8 ,
+.Xr rpc.rstatd 8 ,
+.Xr sysctl 8 ,
+.Xr vmstat 8 ,
+.Xr devstat 9
+.Sh HISTORY
+The
+.Nm
+statistics system first appeared in
+.Fx 3.0 .
+The new interface (the functions prefixed with
+.Li devstat_ )
+first appeared in
+.Fx 5.0 .
+.Sh AUTHORS
+.An Kenneth Merry Aq ken@FreeBSD.org
+.Sh BUGS
+There should probably be an interface to de-allocate memory allocated by
+.Fn devstat_getdevs ,
+.Fn devstat_selectdevs ,
+and
+.Fn devstat_buildmatch .
+.Pp
+The
+.Fn devstat_selectdevs
+function
+should probably not select more than
+.Fa maxshowdevs
+devices in
+.Dq top
+mode when no devices have been selected previously.
+.Pp
+There should probably be functions to perform the statistics buffer
+swapping that goes on in most of the clients of this library.
+.Pp
+The
+.Vt statinfo
+and
+.Vt devinfo
+structures should probably be cleaned up and thought out a little more.
diff --git a/lib/libdevstat/devstat.c b/lib/libdevstat/devstat.c
new file mode 100644
index 0000000..d0ba704
--- /dev/null
+++ b/lib/libdevstat/devstat.c
@@ -0,0 +1,1631 @@
+/*
+ * Copyright (c) 1997, 1998 Kenneth D. Merry.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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 <sys/types.h>
+#include <sys/sysctl.h>
+#include <sys/errno.h>
+#include <sys/resource.h>
+#include <sys/queue.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <kvm.h>
+#include <nlist.h>
+
+#include "devstat.h"
+
+int
+compute_stats(struct devstat *current, struct devstat *previous,
+ long double etime, u_int64_t *total_bytes,
+ u_int64_t *total_transfers, u_int64_t *total_blocks,
+ long double *kb_per_transfer, long double *transfers_per_second,
+ long double *mb_per_second, long double *blocks_per_second,
+ long double *ms_per_transaction);
+
+typedef enum {
+ DEVSTAT_ARG_NOTYPE,
+ DEVSTAT_ARG_UINT64,
+ DEVSTAT_ARG_LD,
+ DEVSTAT_ARG_SKIP
+} devstat_arg_type;
+
+char devstat_errbuf[DEVSTAT_ERRBUF_SIZE];
+
+/*
+ * Table to match descriptive strings with device types. These are in
+ * order from most common to least common to speed search time.
+ */
+struct devstat_match_table match_table[] = {
+ {"da", DEVSTAT_TYPE_DIRECT, DEVSTAT_MATCH_TYPE},
+ {"cd", DEVSTAT_TYPE_CDROM, DEVSTAT_MATCH_TYPE},
+ {"scsi", DEVSTAT_TYPE_IF_SCSI, DEVSTAT_MATCH_IF},
+ {"ide", DEVSTAT_TYPE_IF_IDE, DEVSTAT_MATCH_IF},
+ {"other", DEVSTAT_TYPE_IF_OTHER, DEVSTAT_MATCH_IF},
+ {"worm", DEVSTAT_TYPE_WORM, DEVSTAT_MATCH_TYPE},
+ {"sa", DEVSTAT_TYPE_SEQUENTIAL,DEVSTAT_MATCH_TYPE},
+ {"pass", DEVSTAT_TYPE_PASS, DEVSTAT_MATCH_PASS},
+ {"optical", DEVSTAT_TYPE_OPTICAL, DEVSTAT_MATCH_TYPE},
+ {"array", DEVSTAT_TYPE_STORARRAY, DEVSTAT_MATCH_TYPE},
+ {"changer", DEVSTAT_TYPE_CHANGER, DEVSTAT_MATCH_TYPE},
+ {"scanner", DEVSTAT_TYPE_SCANNER, DEVSTAT_MATCH_TYPE},
+ {"printer", DEVSTAT_TYPE_PRINTER, DEVSTAT_MATCH_TYPE},
+ {"floppy", DEVSTAT_TYPE_FLOPPY, DEVSTAT_MATCH_TYPE},
+ {"proc", DEVSTAT_TYPE_PROCESSOR, DEVSTAT_MATCH_TYPE},
+ {"comm", DEVSTAT_TYPE_COMM, DEVSTAT_MATCH_TYPE},
+ {"enclosure", DEVSTAT_TYPE_ENCLOSURE, DEVSTAT_MATCH_TYPE},
+ {NULL, 0, 0}
+};
+
+struct devstat_args {
+ devstat_metric metric;
+ devstat_arg_type argtype;
+} devstat_arg_list[] = {
+ { DSM_NONE, DEVSTAT_ARG_NOTYPE },
+ { DSM_TOTAL_BYTES, DEVSTAT_ARG_UINT64 },
+ { DSM_TOTAL_BYTES_READ, DEVSTAT_ARG_UINT64 },
+ { DSM_TOTAL_BYTES_WRITE, DEVSTAT_ARG_UINT64 },
+ { DSM_TOTAL_TRANSFERS, DEVSTAT_ARG_UINT64 },
+ { DSM_TOTAL_TRANSFERS_READ, DEVSTAT_ARG_UINT64 },
+ { DSM_TOTAL_TRANSFERS_WRITE, DEVSTAT_ARG_UINT64 },
+ { DSM_TOTAL_TRANSFERS_OTHER, DEVSTAT_ARG_UINT64 },
+ { DSM_TOTAL_BLOCKS, DEVSTAT_ARG_UINT64 },
+ { DSM_TOTAL_BLOCKS_READ, DEVSTAT_ARG_UINT64 },
+ { DSM_TOTAL_BLOCKS_WRITE, DEVSTAT_ARG_UINT64 },
+ { DSM_KB_PER_TRANSFER, DEVSTAT_ARG_LD },
+ { DSM_KB_PER_TRANSFER_READ, DEVSTAT_ARG_LD },
+ { DSM_KB_PER_TRANSFER_WRITE, DEVSTAT_ARG_LD },
+ { DSM_TRANSFERS_PER_SECOND, DEVSTAT_ARG_LD },
+ { DSM_TRANSFERS_PER_SECOND_READ, DEVSTAT_ARG_LD },
+ { DSM_TRANSFERS_PER_SECOND_WRITE, DEVSTAT_ARG_LD },
+ { DSM_TRANSFERS_PER_SECOND_OTHER, DEVSTAT_ARG_LD },
+ { DSM_MB_PER_SECOND, DEVSTAT_ARG_LD },
+ { DSM_MB_PER_SECOND_READ, DEVSTAT_ARG_LD },
+ { DSM_MB_PER_SECOND_WRITE, DEVSTAT_ARG_LD },
+ { DSM_BLOCKS_PER_SECOND, DEVSTAT_ARG_LD },
+ { DSM_BLOCKS_PER_SECOND_READ, DEVSTAT_ARG_LD },
+ { DSM_BLOCKS_PER_SECOND_WRITE, DEVSTAT_ARG_LD },
+ { DSM_MS_PER_TRANSACTION, DEVSTAT_ARG_LD },
+ { DSM_MS_PER_TRANSACTION_READ, DEVSTAT_ARG_LD },
+ { DSM_MS_PER_TRANSACTION_WRITE, DEVSTAT_ARG_LD },
+ { DSM_SKIP, DEVSTAT_ARG_SKIP },
+ { DSM_TOTAL_BYTES_FREE, DEVSTAT_ARG_UINT64 },
+ { DSM_TOTAL_TRANSFERS_FREE, DEVSTAT_ARG_UINT64 },
+ { DSM_TOTAL_BLOCKS_FREE, DEVSTAT_ARG_UINT64 },
+ { DSM_KB_PER_TRANSFER_FREE, DEVSTAT_ARG_LD },
+ { DSM_MB_PER_SECOND_FREE, DEVSTAT_ARG_LD },
+ { DSM_TRANSFERS_PER_SECOND_FREE, DEVSTAT_ARG_LD },
+ { DSM_BLOCKS_PER_SECOND_FREE, DEVSTAT_ARG_LD },
+ { DSM_MS_PER_TRANSACTION_OTHER, DEVSTAT_ARG_LD },
+ { DSM_MS_PER_TRANSACTION_FREE, DEVSTAT_ARG_LD },
+ { DSM_BUSY_PCT, DEVSTAT_ARG_LD },
+ { DSM_QUEUE_LENGTH, DEVSTAT_ARG_UINT64 },
+};
+
+static const char *namelist[] = {
+#define X_NUMDEVS 0
+ "_devstat_num_devs",
+#define X_GENERATION 1
+ "_devstat_generation",
+#define X_VERSION 2
+ "_devstat_version",
+#define X_DEVICE_STATQ 3
+ "_device_statq",
+#define X_END 4
+};
+
+/*
+ * Local function declarations.
+ */
+static int compare_select(const void *arg1, const void *arg2);
+static int readkmem(kvm_t *kd, unsigned long addr, void *buf, size_t nbytes);
+static int readkmem_nl(kvm_t *kd, const char *name, void *buf, size_t nbytes);
+static char *get_devstat_kvm(kvm_t *kd);
+
+#define KREADNL(kd, var, val) \
+ readkmem_nl(kd, namelist[var], &val, sizeof(val))
+
+int
+devstat_getnumdevs(kvm_t *kd)
+{
+ size_t numdevsize;
+ int numdevs;
+
+ numdevsize = sizeof(int);
+
+ /*
+ * Find out how many devices we have in the system.
+ */
+ if (kd == NULL) {
+ if (sysctlbyname("kern.devstat.numdevs", &numdevs,
+ &numdevsize, NULL, 0) == -1) {
+ snprintf(devstat_errbuf, sizeof(devstat_errbuf),
+ "%s: error getting number of devices\n"
+ "%s: %s", __func__, __func__,
+ strerror(errno));
+ return(-1);
+ } else
+ return(numdevs);
+ } else {
+
+ if (KREADNL(kd, X_NUMDEVS, numdevs) == -1)
+ return(-1);
+ else
+ return(numdevs);
+ }
+}
+
+/*
+ * This is an easy way to get the generation number, but the generation is
+ * supplied in a more atmoic manner by the kern.devstat.all sysctl.
+ * Because this generation sysctl is separate from the statistics sysctl,
+ * the device list and the generation could change between the time that
+ * this function is called and the device list is retreived.
+ */
+long
+devstat_getgeneration(kvm_t *kd)
+{
+ size_t gensize;
+ long generation;
+
+ gensize = sizeof(long);
+
+ /*
+ * Get the current generation number.
+ */
+ if (kd == NULL) {
+ if (sysctlbyname("kern.devstat.generation", &generation,
+ &gensize, NULL, 0) == -1) {
+ snprintf(devstat_errbuf, sizeof(devstat_errbuf),
+ "%s: error getting devstat generation\n%s: %s",
+ __func__, __func__, strerror(errno));
+ return(-1);
+ } else
+ return(generation);
+ } else {
+ if (KREADNL(kd, X_GENERATION, generation) == -1)
+ return(-1);
+ else
+ return(generation);
+ }
+}
+
+/*
+ * Get the current devstat version. The return value of this function
+ * should be compared with DEVSTAT_VERSION, which is defined in
+ * sys/devicestat.h. This will enable userland programs to determine
+ * whether they are out of sync with the kernel.
+ */
+int
+devstat_getversion(kvm_t *kd)
+{
+ size_t versize;
+ int version;
+
+ versize = sizeof(int);
+
+ /*
+ * Get the current devstat version.
+ */
+ if (kd == NULL) {
+ if (sysctlbyname("kern.devstat.version", &version, &versize,
+ NULL, 0) == -1) {
+ snprintf(devstat_errbuf, sizeof(devstat_errbuf),
+ "%s: error getting devstat version\n%s: %s",
+ __func__, __func__, strerror(errno));
+ return(-1);
+ } else
+ return(version);
+ } else {
+ if (KREADNL(kd, X_VERSION, version) == -1)
+ return(-1);
+ else
+ return(version);
+ }
+}
+
+/*
+ * Check the devstat version we know about against the devstat version the
+ * kernel knows about. If they don't match, print an error into the
+ * devstat error buffer, and return -1. If they match, return 0.
+ */
+int
+devstat_checkversion(kvm_t *kd)
+{
+ int buflen, res, retval = 0, version;
+
+ version = devstat_getversion(kd);
+
+ if (version != DEVSTAT_VERSION) {
+ /*
+ * If getversion() returns an error (i.e. -1), then it
+ * has printed an error message in the buffer. Therefore,
+ * we need to add a \n to the end of that message before we
+ * print our own message in the buffer.
+ */
+ if (version == -1)
+ buflen = strlen(devstat_errbuf);
+ else
+ buflen = 0;
+
+ res = snprintf(devstat_errbuf + buflen,
+ DEVSTAT_ERRBUF_SIZE - buflen,
+ "%s%s: userland devstat version %d is not "
+ "the same as the kernel\n%s: devstat "
+ "version %d\n", version == -1 ? "\n" : "",
+ __func__, DEVSTAT_VERSION, __func__, version);
+
+ if (res < 0)
+ devstat_errbuf[buflen] = '\0';
+
+ buflen = strlen(devstat_errbuf);
+ if (version < DEVSTAT_VERSION)
+ res = snprintf(devstat_errbuf + buflen,
+ DEVSTAT_ERRBUF_SIZE - buflen,
+ "%s: libdevstat newer than kernel\n",
+ __func__);
+ else
+ res = snprintf(devstat_errbuf + buflen,
+ DEVSTAT_ERRBUF_SIZE - buflen,
+ "%s: kernel newer than libdevstat\n",
+ __func__);
+
+ if (res < 0)
+ devstat_errbuf[buflen] = '\0';
+
+ retval = -1;
+ }
+
+ return(retval);
+}
+
+/*
+ * Get the current list of devices and statistics, and the current
+ * generation number.
+ *
+ * Return values:
+ * -1 -- error
+ * 0 -- device list is unchanged
+ * 1 -- device list has changed
+ */
+int
+devstat_getdevs(kvm_t *kd, struct statinfo *stats)
+{
+ int error;
+ size_t dssize;
+ int oldnumdevs;
+ long oldgeneration;
+ int retval = 0;
+ struct devinfo *dinfo;
+ struct timespec ts;
+
+ dinfo = stats->dinfo;
+
+ if (dinfo == NULL) {
+ snprintf(devstat_errbuf, sizeof(devstat_errbuf),
+ "%s: stats->dinfo was NULL", __func__);
+ return(-1);
+ }
+
+ oldnumdevs = dinfo->numdevs;
+ oldgeneration = dinfo->generation;
+
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ stats->snap_time = ts.tv_sec + ts.tv_nsec * 1e-9;
+
+ if (kd == NULL) {
+ /* If this is our first time through, mem_ptr will be null. */
+ if (dinfo->mem_ptr == NULL) {
+ /*
+ * Get the number of devices. If it's negative, it's an
+ * error. Don't bother setting the error string, since
+ * getnumdevs() has already done that for us.
+ */
+ if ((dinfo->numdevs = devstat_getnumdevs(kd)) < 0)
+ return(-1);
+
+ /*
+ * The kern.devstat.all sysctl returns the current
+ * generation number, as well as all the devices.
+ * So we need four bytes more.
+ */
+ dssize = (dinfo->numdevs * sizeof(struct devstat)) +
+ sizeof(long);
+ dinfo->mem_ptr = (u_int8_t *)malloc(dssize);
+ } else
+ dssize = (dinfo->numdevs * sizeof(struct devstat)) +
+ sizeof(long);
+
+ /*
+ * Request all of the devices. We only really allow for one
+ * ENOMEM failure. It would, of course, be possible to just go
+ * in a loop and keep reallocing the device structure until we
+ * don't get ENOMEM back. I'm not sure it's worth it, though.
+ * If devices are being added to the system that quickly, maybe
+ * the user can just wait until all devices are added.
+ */
+ for (;;) {
+ error = sysctlbyname("kern.devstat.all",
+ dinfo->mem_ptr,
+ &dssize, NULL, 0);
+ if (error != -1 || errno != EBUSY)
+ break;
+ }
+ if (error == -1) {
+ /*
+ * If we get ENOMEM back, that means that there are
+ * more devices now, so we need to allocate more
+ * space for the device array.
+ */
+ if (errno == ENOMEM) {
+ /*
+ * No need to set the error string here,
+ * devstat_getnumdevs() will do that if it fails.
+ */
+ if ((dinfo->numdevs = devstat_getnumdevs(kd)) < 0)
+ return(-1);
+
+ dssize = (dinfo->numdevs *
+ sizeof(struct devstat)) + sizeof(long);
+ dinfo->mem_ptr = (u_int8_t *)
+ realloc(dinfo->mem_ptr, dssize);
+ if ((error = sysctlbyname("kern.devstat.all",
+ dinfo->mem_ptr, &dssize, NULL, 0)) == -1) {
+ snprintf(devstat_errbuf,
+ sizeof(devstat_errbuf),
+ "%s: error getting device "
+ "stats\n%s: %s", __func__,
+ __func__, strerror(errno));
+ return(-1);
+ }
+ } else {
+ snprintf(devstat_errbuf, sizeof(devstat_errbuf),
+ "%s: error getting device stats\n"
+ "%s: %s", __func__, __func__,
+ strerror(errno));
+ return(-1);
+ }
+ }
+
+ } else {
+ /*
+ * This is of course non-atomic, but since we are working
+ * on a core dump, the generation is unlikely to change
+ */
+ if ((dinfo->numdevs = devstat_getnumdevs(kd)) == -1)
+ return(-1);
+ if ((dinfo->mem_ptr = (u_int8_t *)get_devstat_kvm(kd)) == NULL)
+ return(-1);
+ }
+ /*
+ * The sysctl spits out the generation as the first four bytes,
+ * then all of the device statistics structures.
+ */
+ dinfo->generation = *(long *)dinfo->mem_ptr;
+
+ /*
+ * If the generation has changed, and if the current number of
+ * devices is not the same as the number of devices recorded in the
+ * devinfo structure, it is likely that the device list has shrunk.
+ * The reason that it is likely that the device list has shrunk in
+ * this case is that if the device list has grown, the sysctl above
+ * will return an ENOMEM error, and we will reset the number of
+ * devices and reallocate the device array. If the second sysctl
+ * fails, we will return an error and therefore never get to this
+ * point. If the device list has shrunk, the sysctl will not
+ * return an error since we have more space allocated than is
+ * necessary. So, in the shrinkage case, we catch it here and
+ * reallocate the array so that we don't use any more space than is
+ * necessary.
+ */
+ if (oldgeneration != dinfo->generation) {
+ if (devstat_getnumdevs(kd) != dinfo->numdevs) {
+ if ((dinfo->numdevs = devstat_getnumdevs(kd)) < 0)
+ return(-1);
+ dssize = (dinfo->numdevs * sizeof(struct devstat)) +
+ sizeof(long);
+ dinfo->mem_ptr = (u_int8_t *)realloc(dinfo->mem_ptr,
+ dssize);
+ }
+ retval = 1;
+ }
+
+ dinfo->devices = (struct devstat *)(dinfo->mem_ptr + sizeof(long));
+
+ return(retval);
+}
+
+/*
+ * selectdevs():
+ *
+ * Devices are selected/deselected based upon the following criteria:
+ * - devices specified by the user on the command line
+ * - devices matching any device type expressions given on the command line
+ * - devices with the highest I/O, if 'top' mode is enabled
+ * - the first n unselected devices in the device list, if maxshowdevs
+ * devices haven't already been selected and if the user has not
+ * specified any devices on the command line and if we're in "add" mode.
+ *
+ * Input parameters:
+ * - device selection list (dev_select)
+ * - current number of devices selected (num_selected)
+ * - total number of devices in the selection list (num_selections)
+ * - devstat generation as of the last time selectdevs() was called
+ * (select_generation)
+ * - current devstat generation (current_generation)
+ * - current list of devices and statistics (devices)
+ * - number of devices in the current device list (numdevs)
+ * - compiled version of the command line device type arguments (matches)
+ * - This is optional. If the number of devices is 0, this will be ignored.
+ * - The matching code pays attention to the current selection mode. So
+ * if you pass in a matching expression, it will be evaluated based
+ * upon the selection mode that is passed in. See below for details.
+ * - number of device type matching expressions (num_matches)
+ * - Set to 0 to disable the matching code.
+ * - list of devices specified on the command line by the user (dev_selections)
+ * - number of devices selected on the command line by the user
+ * (num_dev_selections)
+ * - Our selection mode. There are four different selection modes:
+ * - add mode. (DS_SELECT_ADD) Any devices matching devices explicitly
+ * selected by the user or devices matching a pattern given by the
+ * user will be selected in addition to devices that are already
+ * selected. Additional devices will be selected, up to maxshowdevs
+ * number of devices.
+ * - only mode. (DS_SELECT_ONLY) Only devices matching devices
+ * explicitly given by the user or devices matching a pattern
+ * given by the user will be selected. No other devices will be
+ * selected.
+ * - addonly mode. (DS_SELECT_ADDONLY) This is similar to add and
+ * only. Basically, this will not de-select any devices that are
+ * current selected, as only mode would, but it will also not
+ * gratuitously select up to maxshowdevs devices as add mode would.
+ * - remove mode. (DS_SELECT_REMOVE) Any devices matching devices
+ * explicitly selected by the user or devices matching a pattern
+ * given by the user will be de-selected.
+ * - maximum number of devices we can select (maxshowdevs)
+ * - flag indicating whether or not we're in 'top' mode (perf_select)
+ *
+ * Output data:
+ * - the device selection list may be modified and passed back out
+ * - the number of devices selected and the total number of items in the
+ * device selection list may be changed
+ * - the selection generation may be changed to match the current generation
+ *
+ * Return values:
+ * -1 -- error
+ * 0 -- selected devices are unchanged
+ * 1 -- selected devices changed
+ */
+int
+devstat_selectdevs(struct device_selection **dev_select, int *num_selected,
+ int *num_selections, long *select_generation,
+ long current_generation, struct devstat *devices,
+ int numdevs, struct devstat_match *matches, int num_matches,
+ char **dev_selections, int num_dev_selections,
+ devstat_select_mode select_mode, int maxshowdevs,
+ int perf_select)
+{
+ int i, j, k;
+ int init_selections = 0, init_selected_var = 0;
+ struct device_selection *old_dev_select = NULL;
+ int old_num_selections = 0, old_num_selected;
+ int selection_number = 0;
+ int changed = 0, found = 0;
+
+ if ((dev_select == NULL) || (devices == NULL) || (numdevs < 0))
+ return(-1);
+
+ /*
+ * We always want to make sure that we have as many dev_select
+ * entries as there are devices.
+ */
+ /*
+ * In this case, we haven't selected devices before.
+ */
+ if (*dev_select == NULL) {
+ *dev_select = (struct device_selection *)malloc(numdevs *
+ sizeof(struct device_selection));
+ *select_generation = current_generation;
+ init_selections = 1;
+ changed = 1;
+ /*
+ * In this case, we have selected devices before, but the device
+ * list has changed since we last selected devices, so we need to
+ * either enlarge or reduce the size of the device selection list.
+ */
+ } else if (*num_selections != numdevs) {
+ *dev_select = (struct device_selection *)realloc(*dev_select,
+ numdevs * sizeof(struct device_selection));
+ *select_generation = current_generation;
+ init_selections = 1;
+ /*
+ * In this case, we've selected devices before, and the selection
+ * list is the same size as it was the last time, but the device
+ * list has changed.
+ */
+ } else if (*select_generation < current_generation) {
+ *select_generation = current_generation;
+ init_selections = 1;
+ }
+
+ /*
+ * If we're in "only" mode, we want to clear out the selected
+ * variable since we're going to select exactly what the user wants
+ * this time through.
+ */
+ if (select_mode == DS_SELECT_ONLY)
+ init_selected_var = 1;
+
+ /*
+ * In all cases, we want to back up the number of selected devices.
+ * It is a quick and accurate way to determine whether the selected
+ * devices have changed.
+ */
+ old_num_selected = *num_selected;
+
+ /*
+ * We want to make a backup of the current selection list if
+ * the list of devices has changed, or if we're in performance
+ * selection mode. In both cases, we don't want to make a backup
+ * if we already know for sure that the list will be different.
+ * This is certainly the case if this is our first time through the
+ * selection code.
+ */
+ if (((init_selected_var != 0) || (init_selections != 0)
+ || (perf_select != 0)) && (changed == 0)){
+ old_dev_select = (struct device_selection *)malloc(
+ *num_selections * sizeof(struct device_selection));
+ old_num_selections = *num_selections;
+ bcopy(*dev_select, old_dev_select,
+ sizeof(struct device_selection) * *num_selections);
+ }
+
+ if (init_selections != 0) {
+ bzero(*dev_select, sizeof(struct device_selection) * numdevs);
+
+ for (i = 0; i < numdevs; i++) {
+ (*dev_select)[i].device_number =
+ devices[i].device_number;
+ strncpy((*dev_select)[i].device_name,
+ devices[i].device_name,
+ DEVSTAT_NAME_LEN);
+ (*dev_select)[i].device_name[DEVSTAT_NAME_LEN - 1]='\0';
+ (*dev_select)[i].unit_number = devices[i].unit_number;
+ (*dev_select)[i].position = i;
+ }
+ *num_selections = numdevs;
+ } else if (init_selected_var != 0) {
+ for (i = 0; i < numdevs; i++)
+ (*dev_select)[i].selected = 0;
+ }
+
+ /* we haven't gotten around to selecting anything yet.. */
+ if ((select_mode == DS_SELECT_ONLY) || (init_selections != 0)
+ || (init_selected_var != 0))
+ *num_selected = 0;
+
+ /*
+ * Look through any devices the user specified on the command line
+ * and see if they match known devices. If so, select them.
+ */
+ for (i = 0; (i < *num_selections) && (num_dev_selections > 0); i++) {
+ char tmpstr[80];
+
+ snprintf(tmpstr, sizeof(tmpstr), "%s%d",
+ (*dev_select)[i].device_name,
+ (*dev_select)[i].unit_number);
+ for (j = 0; j < num_dev_selections; j++) {
+ if (strcmp(tmpstr, dev_selections[j]) == 0) {
+ /*
+ * Here we do different things based on the
+ * mode we're in. If we're in add or
+ * addonly mode, we only select this device
+ * if it hasn't already been selected.
+ * Otherwise, we would be unnecessarily
+ * changing the selection order and
+ * incrementing the selection count. If
+ * we're in only mode, we unconditionally
+ * select this device, since in only mode
+ * any previous selections are erased and
+ * manually specified devices are the first
+ * ones to be selected. If we're in remove
+ * mode, we de-select the specified device and
+ * decrement the selection count.
+ */
+ switch(select_mode) {
+ case DS_SELECT_ADD:
+ case DS_SELECT_ADDONLY:
+ if ((*dev_select)[i].selected)
+ break;
+ /* FALLTHROUGH */
+ case DS_SELECT_ONLY:
+ (*dev_select)[i].selected =
+ ++selection_number;
+ (*num_selected)++;
+ break;
+ case DS_SELECT_REMOVE:
+ (*dev_select)[i].selected = 0;
+ (*num_selected)--;
+ /*
+ * This isn't passed back out, we
+ * just use it to keep track of
+ * how many devices we've removed.
+ */
+ num_dev_selections--;
+ break;
+ }
+ break;
+ }
+ }
+ }
+
+ /*
+ * Go through the user's device type expressions and select devices
+ * accordingly. We only do this if the number of devices already
+ * selected is less than the maximum number we can show.
+ */
+ for (i = 0; (i < num_matches) && (*num_selected < maxshowdevs); i++) {
+ /* We should probably indicate some error here */
+ if ((matches[i].match_fields == DEVSTAT_MATCH_NONE)
+ || (matches[i].num_match_categories <= 0))
+ continue;
+
+ for (j = 0; j < numdevs; j++) {
+ int num_match_categories;
+
+ num_match_categories = matches[i].num_match_categories;
+
+ /*
+ * Determine whether or not the current device
+ * matches the given matching expression. This if
+ * statement consists of three components:
+ * - the device type check
+ * - the device interface check
+ * - the passthrough check
+ * If a the matching test is successful, it
+ * decrements the number of matching categories,
+ * and if we've reached the last element that
+ * needed to be matched, the if statement succeeds.
+ *
+ */
+ if ((((matches[i].match_fields & DEVSTAT_MATCH_TYPE)!=0)
+ && ((devices[j].device_type & DEVSTAT_TYPE_MASK) ==
+ (matches[i].device_type & DEVSTAT_TYPE_MASK))
+ &&(((matches[i].match_fields & DEVSTAT_MATCH_PASS)!=0)
+ || (((matches[i].match_fields &
+ DEVSTAT_MATCH_PASS) == 0)
+ && ((devices[j].device_type &
+ DEVSTAT_TYPE_PASS) == 0)))
+ && (--num_match_categories == 0))
+ || (((matches[i].match_fields & DEVSTAT_MATCH_IF) != 0)
+ && ((devices[j].device_type & DEVSTAT_TYPE_IF_MASK) ==
+ (matches[i].device_type & DEVSTAT_TYPE_IF_MASK))
+ &&(((matches[i].match_fields & DEVSTAT_MATCH_PASS)!=0)
+ || (((matches[i].match_fields &
+ DEVSTAT_MATCH_PASS) == 0)
+ && ((devices[j].device_type &
+ DEVSTAT_TYPE_PASS) == 0)))
+ && (--num_match_categories == 0))
+ || (((matches[i].match_fields & DEVSTAT_MATCH_PASS)!=0)
+ && ((devices[j].device_type & DEVSTAT_TYPE_PASS) != 0)
+ && (--num_match_categories == 0))) {
+
+ /*
+ * This is probably a non-optimal solution
+ * to the problem that the devices in the
+ * device list will not be in the same
+ * order as the devices in the selection
+ * array.
+ */
+ for (k = 0; k < numdevs; k++) {
+ if ((*dev_select)[k].position == j) {
+ found = 1;
+ break;
+ }
+ }
+
+ /*
+ * There shouldn't be a case where a device
+ * in the device list is not in the
+ * selection list...but it could happen.
+ */
+ if (found != 1) {
+ fprintf(stderr, "selectdevs: couldn't"
+ " find %s%d in selection "
+ "list\n",
+ devices[j].device_name,
+ devices[j].unit_number);
+ break;
+ }
+
+ /*
+ * We do different things based upon the
+ * mode we're in. If we're in add or only
+ * mode, we go ahead and select this device
+ * if it hasn't already been selected. If
+ * it has already been selected, we leave
+ * it alone so we don't mess up the
+ * selection ordering. Manually specified
+ * devices have already been selected, and
+ * they have higher priority than pattern
+ * matched devices. If we're in remove
+ * mode, we de-select the given device and
+ * decrement the selected count.
+ */
+ switch(select_mode) {
+ case DS_SELECT_ADD:
+ case DS_SELECT_ADDONLY:
+ case DS_SELECT_ONLY:
+ if ((*dev_select)[k].selected != 0)
+ break;
+ (*dev_select)[k].selected =
+ ++selection_number;
+ (*num_selected)++;
+ break;
+ case DS_SELECT_REMOVE:
+ (*dev_select)[k].selected = 0;
+ (*num_selected)--;
+ break;
+ }
+ }
+ }
+ }
+
+ /*
+ * Here we implement "top" mode. Devices are sorted in the
+ * selection array based on two criteria: whether or not they are
+ * selected (not selection number, just the fact that they are
+ * selected!) and the number of bytes in the "bytes" field of the
+ * selection structure. The bytes field generally must be kept up
+ * by the user. In the future, it may be maintained by library
+ * functions, but for now the user has to do the work.
+ *
+ * At first glance, it may seem wrong that we don't go through and
+ * select every device in the case where the user hasn't specified
+ * any devices or patterns. In fact, though, it won't make any
+ * difference in the device sorting. In that particular case (i.e.
+ * when we're in "add" or "only" mode, and the user hasn't
+ * specified anything) the first time through no devices will be
+ * selected, so the only criterion used to sort them will be their
+ * performance. The second time through, and every time thereafter,
+ * all devices will be selected, so again selection won't matter.
+ */
+ if (perf_select != 0) {
+
+ /* Sort the device array by throughput */
+ qsort(*dev_select, *num_selections,
+ sizeof(struct device_selection),
+ compare_select);
+
+ if (*num_selected == 0) {
+ /*
+ * Here we select every device in the array, if it
+ * isn't already selected. Because the 'selected'
+ * variable in the selection array entries contains
+ * the selection order, the devstats routine can show
+ * the devices that were selected first.
+ */
+ for (i = 0; i < *num_selections; i++) {
+ if ((*dev_select)[i].selected == 0) {
+ (*dev_select)[i].selected =
+ ++selection_number;
+ (*num_selected)++;
+ }
+ }
+ } else {
+ selection_number = 0;
+ for (i = 0; i < *num_selections; i++) {
+ if ((*dev_select)[i].selected != 0) {
+ (*dev_select)[i].selected =
+ ++selection_number;
+ }
+ }
+ }
+ }
+
+ /*
+ * If we're in the "add" selection mode and if we haven't already
+ * selected maxshowdevs number of devices, go through the array and
+ * select any unselected devices. If we're in "only" mode, we
+ * obviously don't want to select anything other than what the user
+ * specifies. If we're in "remove" mode, it probably isn't a good
+ * idea to go through and select any more devices, since we might
+ * end up selecting something that the user wants removed. Through
+ * more complicated logic, we could actually figure this out, but
+ * that would probably require combining this loop with the various
+ * selections loops above.
+ */
+ if ((select_mode == DS_SELECT_ADD) && (*num_selected < maxshowdevs)) {
+ for (i = 0; i < *num_selections; i++)
+ if ((*dev_select)[i].selected == 0) {
+ (*dev_select)[i].selected = ++selection_number;
+ (*num_selected)++;
+ }
+ }
+
+ /*
+ * Look at the number of devices that have been selected. If it
+ * has changed, set the changed variable. Otherwise, if we've
+ * made a backup of the selection list, compare it to the current
+ * selection list to see if the selected devices have changed.
+ */
+ if ((changed == 0) && (old_num_selected != *num_selected))
+ changed = 1;
+ else if ((changed == 0) && (old_dev_select != NULL)) {
+ /*
+ * Now we go through the selection list and we look at
+ * it three different ways.
+ */
+ for (i = 0; (i < *num_selections) && (changed == 0) &&
+ (i < old_num_selections); i++) {
+ /*
+ * If the device at index i in both the new and old
+ * selection arrays has the same device number and
+ * selection status, it hasn't changed. We
+ * continue on to the next index.
+ */
+ if (((*dev_select)[i].device_number ==
+ old_dev_select[i].device_number)
+ && ((*dev_select)[i].selected ==
+ old_dev_select[i].selected))
+ continue;
+
+ /*
+ * Now, if we're still going through the if
+ * statement, the above test wasn't true. So we
+ * check here to see if the device at index i in
+ * the current array is the same as the device at
+ * index i in the old array. If it is, that means
+ * that its selection number has changed. Set
+ * changed to 1 and exit the loop.
+ */
+ else if ((*dev_select)[i].device_number ==
+ old_dev_select[i].device_number) {
+ changed = 1;
+ break;
+ }
+ /*
+ * If we get here, then the device at index i in
+ * the current array isn't the same device as the
+ * device at index i in the old array.
+ */
+ else {
+ found = 0;
+
+ /*
+ * Search through the old selection array
+ * looking for a device with the same
+ * device number as the device at index i
+ * in the current array. If the selection
+ * status is the same, then we mark it as
+ * found. If the selection status isn't
+ * the same, we break out of the loop.
+ * Since found isn't set, changed will be
+ * set to 1 below.
+ */
+ for (j = 0; j < old_num_selections; j++) {
+ if (((*dev_select)[i].device_number ==
+ old_dev_select[j].device_number)
+ && ((*dev_select)[i].selected ==
+ old_dev_select[j].selected)){
+ found = 1;
+ break;
+ }
+ else if ((*dev_select)[i].device_number
+ == old_dev_select[j].device_number)
+ break;
+ }
+ if (found == 0)
+ changed = 1;
+ }
+ }
+ }
+ if (old_dev_select != NULL)
+ free(old_dev_select);
+
+ return(changed);
+}
+
+/*
+ * Comparison routine for qsort() above. Note that the comparison here is
+ * backwards -- generally, it should return a value to indicate whether
+ * arg1 is <, =, or > arg2. Instead, it returns the opposite. The reason
+ * it returns the opposite is so that the selection array will be sorted in
+ * order of decreasing performance. We sort on two parameters. The first
+ * sort key is whether or not one or the other of the devices in question
+ * has been selected. If one of them has, and the other one has not, the
+ * selected device is automatically more important than the unselected
+ * device. If neither device is selected, we judge the devices based upon
+ * performance.
+ */
+static int
+compare_select(const void *arg1, const void *arg2)
+{
+ if ((((const struct device_selection *)arg1)->selected)
+ && (((const struct device_selection *)arg2)->selected == 0))
+ return(-1);
+ else if ((((const struct device_selection *)arg1)->selected == 0)
+ && (((const struct device_selection *)arg2)->selected))
+ return(1);
+ else if (((const struct device_selection *)arg2)->bytes <
+ ((const struct device_selection *)arg1)->bytes)
+ return(-1);
+ else if (((const struct device_selection *)arg2)->bytes >
+ ((const struct device_selection *)arg1)->bytes)
+ return(1);
+ else
+ return(0);
+}
+
+/*
+ * Take a string with the general format "arg1,arg2,arg3", and build a
+ * device matching expression from it.
+ */
+int
+devstat_buildmatch(char *match_str, struct devstat_match **matches,
+ int *num_matches)
+{
+ char *tstr[5];
+ char **tempstr;
+ int num_args;
+ int i, j;
+
+ /* We can't do much without a string to parse */
+ if (match_str == NULL) {
+ snprintf(devstat_errbuf, sizeof(devstat_errbuf),
+ "%s: no match expression", __func__);
+ return(-1);
+ }
+
+ /*
+ * Break the (comma delimited) input string out into separate strings.
+ */
+ for (tempstr = tstr, num_args = 0;
+ (*tempstr = strsep(&match_str, ",")) != NULL && (num_args < 5);
+ num_args++)
+ if (**tempstr != '\0')
+ if (++tempstr >= &tstr[5])
+ break;
+
+ /* The user gave us too many type arguments */
+ if (num_args > 3) {
+ snprintf(devstat_errbuf, sizeof(devstat_errbuf),
+ "%s: too many type arguments", __func__);
+ return(-1);
+ }
+
+ /*
+ * Since you can't realloc a pointer that hasn't been malloced
+ * first, we malloc first and then realloc.
+ */
+ if (*num_matches == 0)
+ *matches = (struct devstat_match *)malloc(
+ sizeof(struct devstat_match));
+ else
+ *matches = (struct devstat_match *)realloc(*matches,
+ sizeof(struct devstat_match) * (*num_matches + 1));
+
+ /* Make sure the current entry is clear */
+ bzero(&matches[0][*num_matches], sizeof(struct devstat_match));
+
+ /*
+ * Step through the arguments the user gave us and build a device
+ * matching expression from them.
+ */
+ for (i = 0; i < num_args; i++) {
+ char *tempstr2, *tempstr3;
+
+ /*
+ * Get rid of leading white space.
+ */
+ tempstr2 = tstr[i];
+ while (isspace(*tempstr2) && (*tempstr2 != '\0'))
+ tempstr2++;
+
+ /*
+ * Get rid of trailing white space.
+ */
+ tempstr3 = &tempstr2[strlen(tempstr2) - 1];
+
+ while ((*tempstr3 != '\0') && (tempstr3 > tempstr2)
+ && (isspace(*tempstr3))) {
+ *tempstr3 = '\0';
+ tempstr3--;
+ }
+
+ /*
+ * Go through the match table comparing the user's
+ * arguments to known device types, interfaces, etc.
+ */
+ for (j = 0; match_table[j].match_str != NULL; j++) {
+ /*
+ * We do case-insensitive matching, in case someone
+ * wants to enter "SCSI" instead of "scsi" or
+ * something like that. Only compare as many
+ * characters as are in the string in the match
+ * table. This should help if someone tries to use
+ * a super-long match expression.
+ */
+ if (strncasecmp(tempstr2, match_table[j].match_str,
+ strlen(match_table[j].match_str)) == 0) {
+ /*
+ * Make sure the user hasn't specified two
+ * items of the same type, like "da" and
+ * "cd". One device cannot be both.
+ */
+ if (((*matches)[*num_matches].match_fields &
+ match_table[j].match_field) != 0) {
+ snprintf(devstat_errbuf,
+ sizeof(devstat_errbuf),
+ "%s: cannot have more than "
+ "one match item in a single "
+ "category", __func__);
+ return(-1);
+ }
+ /*
+ * If we've gotten this far, we have a
+ * winner. Set the appropriate fields in
+ * the match entry.
+ */
+ (*matches)[*num_matches].match_fields |=
+ match_table[j].match_field;
+ (*matches)[*num_matches].device_type |=
+ match_table[j].type;
+ (*matches)[*num_matches].num_match_categories++;
+ break;
+ }
+ }
+ /*
+ * We should have found a match in the above for loop. If
+ * not, that means the user entered an invalid device type
+ * or interface.
+ */
+ if ((*matches)[*num_matches].num_match_categories != (i + 1)) {
+ snprintf(devstat_errbuf, sizeof(devstat_errbuf),
+ "%s: unknown match item \"%s\"", __func__,
+ tstr[i]);
+ return(-1);
+ }
+ }
+
+ (*num_matches)++;
+
+ return(0);
+}
+
+/*
+ * Compute a number of device statistics. Only one field is mandatory, and
+ * that is "current". Everything else is optional. The caller passes in
+ * pointers to variables to hold the various statistics he desires. If he
+ * doesn't want a particular staistic, he should pass in a NULL pointer.
+ * Return values:
+ * 0 -- success
+ * -1 -- failure
+ */
+int
+compute_stats(struct devstat *current, struct devstat *previous,
+ long double etime, u_int64_t *total_bytes,
+ u_int64_t *total_transfers, u_int64_t *total_blocks,
+ long double *kb_per_transfer, long double *transfers_per_second,
+ long double *mb_per_second, long double *blocks_per_second,
+ long double *ms_per_transaction)
+{
+ return(devstat_compute_statistics(current, previous, etime,
+ total_bytes ? DSM_TOTAL_BYTES : DSM_SKIP,
+ total_bytes,
+ total_transfers ? DSM_TOTAL_TRANSFERS : DSM_SKIP,
+ total_transfers,
+ total_blocks ? DSM_TOTAL_BLOCKS : DSM_SKIP,
+ total_blocks,
+ kb_per_transfer ? DSM_KB_PER_TRANSFER : DSM_SKIP,
+ kb_per_transfer,
+ transfers_per_second ? DSM_TRANSFERS_PER_SECOND : DSM_SKIP,
+ transfers_per_second,
+ mb_per_second ? DSM_MB_PER_SECOND : DSM_SKIP,
+ mb_per_second,
+ blocks_per_second ? DSM_BLOCKS_PER_SECOND : DSM_SKIP,
+ blocks_per_second,
+ ms_per_transaction ? DSM_MS_PER_TRANSACTION : DSM_SKIP,
+ ms_per_transaction,
+ DSM_NONE));
+}
+
+
+/* This is 1/2^64 */
+#define BINTIME_SCALE 5.42101086242752217003726400434970855712890625e-20
+
+long double
+devstat_compute_etime(struct bintime *cur_time, struct bintime *prev_time)
+{
+ long double etime;
+
+ etime = cur_time->sec;
+ etime += cur_time->frac * BINTIME_SCALE;
+ if (prev_time != NULL) {
+ etime -= prev_time->sec;
+ etime -= prev_time->frac * BINTIME_SCALE;
+ }
+ return(etime);
+}
+
+#define DELTA(field, index) \
+ (current->field[(index)] - (previous ? previous->field[(index)] : 0))
+
+#define DELTA_T(field) \
+ devstat_compute_etime(&current->field, \
+ (previous ? &previous->field : NULL))
+
+int
+devstat_compute_statistics(struct devstat *current, struct devstat *previous,
+ long double etime, ...)
+{
+ u_int64_t totalbytes, totalbytesread, totalbyteswrite, totalbytesfree;
+ u_int64_t totaltransfers, totaltransfersread, totaltransferswrite;
+ u_int64_t totaltransfersother, totalblocks, totalblocksread;
+ u_int64_t totalblockswrite, totaltransfersfree, totalblocksfree;
+ va_list ap;
+ devstat_metric metric;
+ u_int64_t *destu64;
+ long double *destld;
+ int retval, i;
+
+ retval = 0;
+
+ /*
+ * current is the only mandatory field.
+ */
+ if (current == NULL) {
+ snprintf(devstat_errbuf, sizeof(devstat_errbuf),
+ "%s: current stats structure was NULL", __func__);
+ return(-1);
+ }
+
+ totalbytesread = DELTA(bytes, DEVSTAT_READ);
+ totalbyteswrite = DELTA(bytes, DEVSTAT_WRITE);
+ totalbytesfree = DELTA(bytes, DEVSTAT_FREE);
+ totalbytes = totalbytesread + totalbyteswrite + totalbytesfree;
+
+ totaltransfersread = DELTA(operations, DEVSTAT_READ);
+ totaltransferswrite = DELTA(operations, DEVSTAT_WRITE);
+ totaltransfersother = DELTA(operations, DEVSTAT_NO_DATA);
+ totaltransfersfree = DELTA(operations, DEVSTAT_FREE);
+ totaltransfers = totaltransfersread + totaltransferswrite +
+ totaltransfersother + totaltransfersfree;
+
+ totalblocks = totalbytes;
+ totalblocksread = totalbytesread;
+ totalblockswrite = totalbyteswrite;
+ totalblocksfree = totalbytesfree;
+
+ if (current->block_size > 0) {
+ totalblocks /= current->block_size;
+ totalblocksread /= current->block_size;
+ totalblockswrite /= current->block_size;
+ totalblocksfree /= current->block_size;
+ } else {
+ totalblocks /= 512;
+ totalblocksread /= 512;
+ totalblockswrite /= 512;
+ totalblocksfree /= 512;
+ }
+
+ va_start(ap, etime);
+
+ while ((metric = (devstat_metric)va_arg(ap, devstat_metric)) != 0) {
+
+ if (metric == DSM_NONE)
+ break;
+
+ if (metric >= DSM_MAX) {
+ snprintf(devstat_errbuf, sizeof(devstat_errbuf),
+ "%s: metric %d is out of range", __func__,
+ metric);
+ retval = -1;
+ goto bailout;
+ }
+
+ switch (devstat_arg_list[metric].argtype) {
+ case DEVSTAT_ARG_UINT64:
+ destu64 = (u_int64_t *)va_arg(ap, u_int64_t *);
+ break;
+ case DEVSTAT_ARG_LD:
+ destld = (long double *)va_arg(ap, long double *);
+ break;
+ case DEVSTAT_ARG_SKIP:
+ destld = (long double *)va_arg(ap, long double *);
+ break;
+ default:
+ retval = -1;
+ goto bailout;
+ break; /* NOTREACHED */
+ }
+
+ if (devstat_arg_list[metric].argtype == DEVSTAT_ARG_SKIP)
+ continue;
+
+ switch (metric) {
+ case DSM_TOTAL_BYTES:
+ *destu64 = totalbytes;
+ break;
+ case DSM_TOTAL_BYTES_READ:
+ *destu64 = totalbytesread;
+ break;
+ case DSM_TOTAL_BYTES_WRITE:
+ *destu64 = totalbyteswrite;
+ break;
+ case DSM_TOTAL_BYTES_FREE:
+ *destu64 = totalbytesfree;
+ break;
+ case DSM_TOTAL_TRANSFERS:
+ *destu64 = totaltransfers;
+ break;
+ case DSM_TOTAL_TRANSFERS_READ:
+ *destu64 = totaltransfersread;
+ break;
+ case DSM_TOTAL_TRANSFERS_WRITE:
+ *destu64 = totaltransferswrite;
+ break;
+ case DSM_TOTAL_TRANSFERS_FREE:
+ *destu64 = totaltransfersfree;
+ break;
+ case DSM_TOTAL_TRANSFERS_OTHER:
+ *destu64 = totaltransfersother;
+ break;
+ case DSM_TOTAL_BLOCKS:
+ *destu64 = totalblocks;
+ break;
+ case DSM_TOTAL_BLOCKS_READ:
+ *destu64 = totalblocksread;
+ break;
+ case DSM_TOTAL_BLOCKS_WRITE:
+ *destu64 = totalblockswrite;
+ break;
+ case DSM_TOTAL_BLOCKS_FREE:
+ *destu64 = totalblocksfree;
+ break;
+ case DSM_KB_PER_TRANSFER:
+ *destld = totalbytes;
+ *destld /= 1024;
+ if (totaltransfers > 0)
+ *destld /= totaltransfers;
+ else
+ *destld = 0.0;
+ break;
+ case DSM_KB_PER_TRANSFER_READ:
+ *destld = totalbytesread;
+ *destld /= 1024;
+ if (totaltransfersread > 0)
+ *destld /= totaltransfersread;
+ else
+ *destld = 0.0;
+ break;
+ case DSM_KB_PER_TRANSFER_WRITE:
+ *destld = totalbyteswrite;
+ *destld /= 1024;
+ if (totaltransferswrite > 0)
+ *destld /= totaltransferswrite;
+ else
+ *destld = 0.0;
+ break;
+ case DSM_KB_PER_TRANSFER_FREE:
+ *destld = totalbytesfree;
+ *destld /= 1024;
+ if (totaltransfersfree > 0)
+ *destld /= totaltransfersfree;
+ else
+ *destld = 0.0;
+ break;
+ case DSM_TRANSFERS_PER_SECOND:
+ if (etime > 0.0) {
+ *destld = totaltransfers;
+ *destld /= etime;
+ } else
+ *destld = 0.0;
+ break;
+ case DSM_TRANSFERS_PER_SECOND_READ:
+ if (etime > 0.0) {
+ *destld = totaltransfersread;
+ *destld /= etime;
+ } else
+ *destld = 0.0;
+ break;
+ case DSM_TRANSFERS_PER_SECOND_WRITE:
+ if (etime > 0.0) {
+ *destld = totaltransferswrite;
+ *destld /= etime;
+ } else
+ *destld = 0.0;
+ break;
+ case DSM_TRANSFERS_PER_SECOND_FREE:
+ if (etime > 0.0) {
+ *destld = totaltransfersfree;
+ *destld /= etime;
+ } else
+ *destld = 0.0;
+ break;
+ case DSM_TRANSFERS_PER_SECOND_OTHER:
+ if (etime > 0.0) {
+ *destld = totaltransfersother;
+ *destld /= etime;
+ } else
+ *destld = 0.0;
+ break;
+ case DSM_MB_PER_SECOND:
+ *destld = totalbytes;
+ *destld /= 1024 * 1024;
+ if (etime > 0.0)
+ *destld /= etime;
+ else
+ *destld = 0.0;
+ break;
+ case DSM_MB_PER_SECOND_READ:
+ *destld = totalbytesread;
+ *destld /= 1024 * 1024;
+ if (etime > 0.0)
+ *destld /= etime;
+ else
+ *destld = 0.0;
+ break;
+ case DSM_MB_PER_SECOND_WRITE:
+ *destld = totalbyteswrite;
+ *destld /= 1024 * 1024;
+ if (etime > 0.0)
+ *destld /= etime;
+ else
+ *destld = 0.0;
+ break;
+ case DSM_MB_PER_SECOND_FREE:
+ *destld = totalbytesfree;
+ *destld /= 1024 * 1024;
+ if (etime > 0.0)
+ *destld /= etime;
+ else
+ *destld = 0.0;
+ break;
+ case DSM_BLOCKS_PER_SECOND:
+ *destld = totalblocks;
+ if (etime > 0.0)
+ *destld /= etime;
+ else
+ *destld = 0.0;
+ break;
+ case DSM_BLOCKS_PER_SECOND_READ:
+ *destld = totalblocksread;
+ if (etime > 0.0)
+ *destld /= etime;
+ else
+ *destld = 0.0;
+ break;
+ case DSM_BLOCKS_PER_SECOND_WRITE:
+ *destld = totalblockswrite;
+ if (etime > 0.0)
+ *destld /= etime;
+ else
+ *destld = 0.0;
+ break;
+ case DSM_BLOCKS_PER_SECOND_FREE:
+ *destld = totalblocksfree;
+ if (etime > 0.0)
+ *destld /= etime;
+ else
+ *destld = 0.0;
+ break;
+ /*
+ * This calculation is somewhat bogus. It simply divides
+ * the elapsed time by the total number of transactions
+ * completed. While that does give the caller a good
+ * picture of the average rate of transaction completion,
+ * it doesn't necessarily give the caller a good view of
+ * how long transactions took to complete on average.
+ * Those two numbers will be different for a device that
+ * can handle more than one transaction at a time. e.g.
+ * SCSI disks doing tagged queueing.
+ *
+ * The only way to accurately determine the real average
+ * time per transaction would be to compute and store the
+ * time on a per-transaction basis. That currently isn't
+ * done in the kernel, and would only be desireable if it
+ * could be implemented in a somewhat non-intrusive and high
+ * performance way.
+ */
+ case DSM_MS_PER_TRANSACTION:
+ if (totaltransfers > 0) {
+ *destld = 0;
+ for (i = 0; i < DEVSTAT_N_TRANS_FLAGS; i++)
+ *destld += DELTA_T(duration[i]);
+ *destld /= totaltransfers;
+ *destld *= 1000;
+ } else
+ *destld = 0.0;
+ break;
+ /*
+ * As above, these next two really only give the average
+ * rate of completion for read and write transactions, not
+ * the average time the transaction took to complete.
+ */
+ case DSM_MS_PER_TRANSACTION_READ:
+ if (totaltransfersread > 0) {
+ *destld = DELTA_T(duration[DEVSTAT_READ]);
+ *destld /= totaltransfersread;
+ *destld *= 1000;
+ } else
+ *destld = 0.0;
+ break;
+ case DSM_MS_PER_TRANSACTION_WRITE:
+ if (totaltransferswrite > 0) {
+ *destld = DELTA_T(duration[DEVSTAT_WRITE]);
+ *destld /= totaltransferswrite;
+ *destld *= 1000;
+ } else
+ *destld = 0.0;
+ break;
+ case DSM_MS_PER_TRANSACTION_FREE:
+ if (totaltransfersfree > 0) {
+ *destld = DELTA_T(duration[DEVSTAT_FREE]);
+ *destld /= totaltransfersfree;
+ *destld *= 1000;
+ } else
+ *destld = 0.0;
+ break;
+ case DSM_MS_PER_TRANSACTION_OTHER:
+ if (totaltransfersother > 0) {
+ *destld = DELTA_T(duration[DEVSTAT_NO_DATA]);
+ *destld /= totaltransfersother;
+ *destld *= 1000;
+ } else
+ *destld = 0.0;
+ break;
+ case DSM_BUSY_PCT:
+ *destld = DELTA_T(busy_time);
+ if (*destld < 0)
+ *destld = 0;
+ *destld /= etime;
+ *destld *= 100;
+ if (*destld < 0)
+ *destld = 0;
+ break;
+ case DSM_QUEUE_LENGTH:
+ *destu64 = current->start_count - current->end_count;
+ break;
+/*
+ * XXX: comment out the default block to see if any case's are missing.
+ */
+#if 1
+ default:
+ /*
+ * This shouldn't happen, since we should have
+ * caught any out of range metrics at the top of
+ * the loop.
+ */
+ snprintf(devstat_errbuf, sizeof(devstat_errbuf),
+ "%s: unknown metric %d", __func__, metric);
+ retval = -1;
+ goto bailout;
+ break; /* NOTREACHED */
+#endif
+ }
+ }
+
+bailout:
+
+ va_end(ap);
+ return(retval);
+}
+
+static int
+readkmem(kvm_t *kd, unsigned long addr, void *buf, size_t nbytes)
+{
+
+ if (kvm_read(kd, addr, buf, nbytes) == -1) {
+ snprintf(devstat_errbuf, sizeof(devstat_errbuf),
+ "%s: error reading value (kvm_read): %s", __func__,
+ kvm_geterr(kd));
+ return(-1);
+ }
+ return(0);
+}
+
+static int
+readkmem_nl(kvm_t *kd, const char *name, void *buf, size_t nbytes)
+{
+ struct nlist nl[2];
+
+ nl[0].n_name = (char *)name;
+ nl[1].n_name = NULL;
+
+ if (kvm_nlist(kd, nl) == -1) {
+ snprintf(devstat_errbuf, sizeof(devstat_errbuf),
+ "%s: error getting name list (kvm_nlist): %s",
+ __func__, kvm_geterr(kd));
+ return(-1);
+ }
+ return(readkmem(kd, nl[0].n_value, buf, nbytes));
+}
+
+/*
+ * This duplicates the functionality of the kernel sysctl handler for poking
+ * through crash dumps.
+ */
+static char *
+get_devstat_kvm(kvm_t *kd)
+{
+ int i, wp;
+ long gen;
+ struct devstat *nds;
+ struct devstat ds;
+ struct devstatlist dhead;
+ int num_devs;
+ char *rv = NULL;
+
+ if ((num_devs = devstat_getnumdevs(kd)) <= 0)
+ return(NULL);
+ if (KREADNL(kd, X_DEVICE_STATQ, dhead) == -1)
+ return(NULL);
+
+ nds = STAILQ_FIRST(&dhead);
+
+ if ((rv = malloc(sizeof(gen))) == NULL) {
+ snprintf(devstat_errbuf, sizeof(devstat_errbuf),
+ "%s: out of memory (initial malloc failed)",
+ __func__);
+ return(NULL);
+ }
+ gen = devstat_getgeneration(kd);
+ memcpy(rv, &gen, sizeof(gen));
+ wp = sizeof(gen);
+ /*
+ * Now push out all the devices.
+ */
+ for (i = 0; (nds != NULL) && (i < num_devs);
+ nds = STAILQ_NEXT(nds, dev_links), i++) {
+ if (readkmem(kd, (long)nds, &ds, sizeof(ds)) == -1) {
+ free(rv);
+ return(NULL);
+ }
+ nds = &ds;
+ rv = (char *)reallocf(rv, sizeof(gen) +
+ sizeof(ds) * (i + 1));
+ if (rv == NULL) {
+ snprintf(devstat_errbuf, sizeof(devstat_errbuf),
+ "%s: out of memory (malloc failed)",
+ __func__);
+ return(NULL);
+ }
+ memcpy(rv + wp, &ds, sizeof(ds));
+ wp += sizeof(ds);
+ }
+ return(rv);
+}
diff --git a/lib/libdevstat/devstat.h b/lib/libdevstat/devstat.h
new file mode 100644
index 0000000..61b8ccb
--- /dev/null
+++ b/lib/libdevstat/devstat.h
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 1997, 1998 Kenneth D. Merry.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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$
+ */
+
+#ifndef _DEVSTAT_H
+#define _DEVSTAT_H
+#include <sys/cdefs.h>
+#include <sys/devicestat.h>
+
+#include <kvm.h>
+
+/*
+ * Bumped every time we change the userland API. Hopefully this doesn't
+ * happen very often! This should be bumped every time we have to
+ * increment SHLIB_MAJOR in the libdevstat Makefile (for non-backwards
+ * compatible API changes) and should also be bumped every time we make
+ * backwards-compatible API changes, so application writers have a way to
+ * determine when a particular feature is available.
+ */
+#define DEVSTAT_USER_API_VER 6
+
+#define DEVSTAT_ERRBUF_SIZE 2048 /* size of the devstat library error string */
+
+extern char devstat_errbuf[];
+
+typedef enum {
+ DEVSTAT_MATCH_NONE = 0x00,
+ DEVSTAT_MATCH_TYPE = 0x01,
+ DEVSTAT_MATCH_IF = 0x02,
+ DEVSTAT_MATCH_PASS = 0x04
+} devstat_match_flags;
+
+typedef enum {
+ DSM_NONE,
+ DSM_TOTAL_BYTES,
+ DSM_TOTAL_BYTES_READ,
+ DSM_TOTAL_BYTES_WRITE,
+ DSM_TOTAL_TRANSFERS,
+ DSM_TOTAL_TRANSFERS_READ,
+ DSM_TOTAL_TRANSFERS_WRITE,
+ DSM_TOTAL_TRANSFERS_OTHER,
+ DSM_TOTAL_BLOCKS,
+ DSM_TOTAL_BLOCKS_READ,
+ DSM_TOTAL_BLOCKS_WRITE,
+ DSM_KB_PER_TRANSFER,
+ DSM_KB_PER_TRANSFER_READ,
+ DSM_KB_PER_TRANSFER_WRITE,
+ DSM_TRANSFERS_PER_SECOND,
+ DSM_TRANSFERS_PER_SECOND_READ,
+ DSM_TRANSFERS_PER_SECOND_WRITE,
+ DSM_TRANSFERS_PER_SECOND_OTHER,
+ DSM_MB_PER_SECOND,
+ DSM_MB_PER_SECOND_READ,
+ DSM_MB_PER_SECOND_WRITE,
+ DSM_BLOCKS_PER_SECOND,
+ DSM_BLOCKS_PER_SECOND_READ,
+ DSM_BLOCKS_PER_SECOND_WRITE,
+ DSM_MS_PER_TRANSACTION,
+ DSM_MS_PER_TRANSACTION_READ,
+ DSM_MS_PER_TRANSACTION_WRITE,
+ DSM_SKIP,
+ DSM_TOTAL_BYTES_FREE,
+ DSM_TOTAL_TRANSFERS_FREE,
+ DSM_TOTAL_BLOCKS_FREE,
+ DSM_KB_PER_TRANSFER_FREE,
+ DSM_MB_PER_SECOND_FREE,
+ DSM_TRANSFERS_PER_SECOND_FREE,
+ DSM_BLOCKS_PER_SECOND_FREE,
+ DSM_MS_PER_TRANSACTION_OTHER,
+ DSM_MS_PER_TRANSACTION_FREE,
+ DSM_BUSY_PCT,
+ DSM_QUEUE_LENGTH,
+ DSM_MAX
+} devstat_metric;
+
+struct devstat_match {
+ devstat_match_flags match_fields;
+ devstat_type_flags device_type;
+ int num_match_categories;
+};
+
+struct devstat_match_table {
+ const char * match_str;
+ devstat_type_flags type;
+ devstat_match_flags match_field;
+};
+
+struct device_selection {
+ u_int32_t device_number;
+ char device_name[DEVSTAT_NAME_LEN];
+ int unit_number;
+ int selected;
+ u_int64_t bytes;
+ int position;
+};
+
+struct devinfo {
+ struct devstat *devices;
+ u_int8_t *mem_ptr;
+ long generation;
+ int numdevs;
+};
+
+struct statinfo {
+ long cp_time[CPUSTATES];
+ long tk_nin;
+ long tk_nout;
+ struct devinfo *dinfo;
+ long double snap_time;
+};
+
+typedef enum {
+ DS_SELECT_ADD,
+ DS_SELECT_ONLY,
+ DS_SELECT_REMOVE,
+ DS_SELECT_ADDONLY
+} devstat_select_mode;
+
+__BEGIN_DECLS
+
+int devstat_getnumdevs(kvm_t *kd);
+long devstat_getgeneration(kvm_t *kd);
+int devstat_getversion(kvm_t *kd);
+int devstat_checkversion(kvm_t *kd);
+int devstat_getdevs(kvm_t *kd, struct statinfo *stats);
+int devstat_selectdevs(struct device_selection **dev_select, int *num_selected,
+ int *num_selections, long *select_generation,
+ long current_generation, struct devstat *devices,
+ int numdevs, struct devstat_match *matches,
+ int num_matches, char **dev_selections,
+ int num_dev_selections, devstat_select_mode select_mode,
+ int maxshowdevs, int perf_select);
+int devstat_buildmatch(char *match_str, struct devstat_match **matches,
+ int *num_matches);
+int devstat_compute_statistics(struct devstat *current,
+ struct devstat *previous,
+ long double etime, ...);
+long double devstat_compute_etime(struct bintime *cur_time,
+ struct bintime *prev_time);
+__END_DECLS
+
+#endif /* _DEVSTAT_H */
diff --git a/lib/libdisk/Makefile b/lib/libdisk/Makefile
new file mode 100644
index 0000000..ebc5991
--- /dev/null
+++ b/lib/libdisk/Makefile
@@ -0,0 +1,41 @@
+# $FreeBSD$
+
+.if ${MACHINE_ARCH} == "ia64"
+_open_disk= open_ia64_disk.c
+.else
+_change = change.c
+_open_disk= open_disk.c
+.endif
+
+LIB= disk
+SRCS= blocks.c ${_change} chunk.c create_chunk.c disk.c ${_open_disk} \
+ rules.c write_disk.c write_${MACHINE}_disk.c
+INCS= libdisk.h
+
+WARNS?= 2
+
+CFLAGS+= -I${.CURDIR}/../../sys/geom
+
+.if ${MACHINE} == "pc98"
+CFLAGS+= -DPC98
+.endif
+
+CLEANFILES+= tmp.c tst01 tst01.o
+NO_PROFILE=
+NO_PIC=
+
+MAN= libdisk.3
+
+.include <bsd.lib.mk>
+
+tst01: tst01.o libdisk.a
+ cc ${CFLAGS} -static tst01.o -o tst01 libdisk.a
+
+ad0: all install tst01
+ ./tst01 ad0
+
+da0: all install tst01
+ ./tst01 da0
+
+da1: all install tst01
+ ./tst01 da1
diff --git a/lib/libdisk/blocks.c b/lib/libdisk/blocks.c
new file mode 100644
index 0000000..313c5cc
--- /dev/null
+++ b/lib/libdisk/blocks.c
@@ -0,0 +1,50 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "libdisk.h"
+
+void *
+read_block(int fd, daddr_t block, u_long sector_size)
+{
+ void *foo;
+ int i;
+
+ foo = malloc(sector_size);
+ if (foo == NULL)
+ return (NULL);
+ if (-1 == lseek(fd, (off_t)block * sector_size, SEEK_SET)) {
+ free (foo);
+ return (NULL);
+ }
+ i = read(fd, foo, sector_size);
+ if ((int)sector_size != i) {
+ free (foo);
+ return (NULL);
+ }
+ return foo;
+}
+
+int
+write_block(int fd, daddr_t block, const void *foo, u_long sector_size)
+{
+ int i;
+
+ if (-1 == lseek(fd, (off_t)block * sector_size, SEEK_SET))
+ return (-1);
+ i = write(fd, foo, sector_size);
+ if ((int)sector_size != i)
+ return (-1);
+ return 0;
+}
diff --git a/lib/libdisk/change.c b/lib/libdisk/change.c
new file mode 100644
index 0000000..7b63561
--- /dev/null
+++ b/lib/libdisk/change.c
@@ -0,0 +1,132 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/types.h>
+#include "libdisk.h"
+
+void
+Set_Bios_Geom(struct disk *disk, u_long cyl, u_long hd, u_long sect)
+{
+
+ disk->bios_cyl = cyl;
+ disk->bios_hd = hd;
+ disk->bios_sect = sect;
+}
+
+void
+Sanitize_Bios_Geom(struct disk *disk)
+{
+ int sane;
+
+ sane = 1;
+
+#ifdef PC98
+ if (disk->bios_cyl >= 65536)
+#else
+ if (disk->bios_cyl > 1024)
+#endif
+ sane = 0;
+#ifdef PC98
+ if (disk->bios_hd >= 256)
+#else
+ if (disk->bios_hd > 16)
+#endif
+ sane = 0;
+#ifdef PC98
+ if (disk->bios_sect >= 256)
+#else
+ if (disk->bios_sect > 63)
+#endif
+ sane = 0;
+ if (disk->bios_cyl * disk->bios_hd * disk->bios_sect !=
+ disk->chunks->size)
+ sane = 0;
+ if (sane)
+ return;
+
+ /* First try something that IDE can handle */
+ disk->bios_sect = 63;
+ disk->bios_hd = 16;
+ disk->bios_cyl = disk->chunks->size /
+ (disk->bios_sect * disk->bios_hd);
+
+#ifdef PC98
+ if (disk->bios_cyl < 65536)
+#else
+ if (disk->bios_cyl < 1024)
+#endif
+ return;
+
+ /* Hmm, try harder... */
+ /* Assume standard SCSI parameter */
+#ifdef PC98
+ disk->bios_sect = 128;
+ disk->bios_hd = 8;
+#else
+ disk->bios_hd = 255;
+#endif
+ disk->bios_cyl = disk->chunks->size /
+ (disk->bios_sect * disk->bios_hd);
+
+#ifdef PC98
+ if (disk->bios_cyl < 65536)
+ return;
+
+ /* Assume UIDE-133/98-A Challenger BIOS 0.9821C parameter */
+ disk->bios_sect = 255;
+ disk->bios_hd = 16;
+ disk->bios_cyl = disk->chunks->size /
+ (disk->bios_sect * disk->bios_hd);
+
+ if (disk->bios_cyl < 65536)
+ return;
+
+ /* BIG-na-Drive? */
+ disk->bios_hd = 255;
+ disk->bios_cyl = disk->chunks->size /
+ (disk->bios_sect * disk->bios_hd);
+#endif
+}
+
+void
+All_FreeBSD(struct disk *d, int force_all)
+{
+ struct chunk *c;
+ int type;
+
+#ifdef PC98
+ type = 0xc494;
+#else
+ type = 0xa5;
+#endif
+
+again:
+ for (c = d->chunks->part; c; c = c->next)
+ if (c->type != unused) {
+ Delete_Chunk(d, c);
+ goto again;
+ }
+ c = d->chunks;
+ if (force_all) {
+ Sanitize_Bios_Geom(d);
+ Create_Chunk(d, c->offset, c->size, freebsd, type,
+ CHUNK_FORCE_ALL, "FreeBSD");
+ } else {
+ Create_Chunk(d, c->offset, c->size, freebsd, type, 0,
+ "FreeBSD");
+ }
+}
diff --git a/lib/libdisk/chunk.c b/lib/libdisk/chunk.c
new file mode 100644
index 0000000..fb43ef5
--- /dev/null
+++ b/lib/libdisk/chunk.c
@@ -0,0 +1,595 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "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/stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <err.h>
+#include "libdisk.h"
+
+struct chunk *
+New_Chunk(void)
+{
+ struct chunk *c;
+
+ c = malloc(sizeof *c);
+ if (c != NULL)
+ memset(c, 0, sizeof *c);
+ return (c);
+}
+
+/* Is c2 completely inside c1 ? */
+
+static int
+Chunk_Inside(const struct chunk *c1, const struct chunk *c2)
+{
+ /* if c1 ends before c2 do */
+ if (c1->end < c2->end)
+ return 0;
+ /* if c1 starts after c2 do */
+ if (c1->offset > c2->offset)
+ return 0;
+ return 1;
+}
+
+static struct chunk *
+Find_Mother_Chunk(struct chunk *chunks, daddr_t offset, daddr_t end,
+ chunk_e type)
+{
+ struct chunk *c1, *c2, ct;
+
+ ct.offset = offset;
+ ct.end = end;
+ switch (type) {
+ case whole:
+ if (Chunk_Inside(chunks, &ct))
+ return chunks;
+ case extended:
+ for (c1 = chunks->part; c1; c1 = c1->next) {
+ if (c1->type != type)
+ continue;
+ if (Chunk_Inside(c1, &ct))
+ return c1;
+ }
+ return 0;
+ case freebsd:
+ for (c1 = chunks->part; c1; c1 = c1->next) {
+ if (c1->type == type)
+ if (Chunk_Inside(c1, &ct))
+ return c1;
+ if (c1->type != extended)
+ continue;
+ for (c2 = c1->part; c2; c2 = c2->next)
+ if (c2->type == type && Chunk_Inside(c2, &ct))
+ return c2;
+ }
+ return 0;
+#ifdef __powerpc__
+ case apple:
+ for (c1 = chunks->part; c1; c1 = c1->next) {
+ if (c1->type == type)
+ if (Chunk_Inside(c1, &ct))
+ return c1;
+ }
+ return 0;
+#endif
+ default:
+ warn("Unsupported mother type in Find_Mother_Chunk");
+ return 0;
+ }
+}
+
+void
+Free_Chunk(struct chunk *c1)
+{
+ if(c1 == NULL)
+ return;
+ if(c1->private_data && c1->private_free)
+ (*c1->private_free)(c1->private_data);
+ if(c1->part != NULL)
+ Free_Chunk(c1->part);
+ if(c1->next != NULL)
+ Free_Chunk(c1->next);
+ if (c1->name != NULL)
+ free(c1->name);
+ if (c1->sname != NULL)
+ free(c1->sname);
+ free(c1);
+}
+
+struct chunk *
+Clone_Chunk(const struct chunk *c1)
+{
+ struct chunk *c2;
+
+ if(!c1)
+ return NULL;
+ c2 = New_Chunk();
+ if (c2 == NULL)
+ return NULL;
+ *c2 = *c1;
+ if (c1->private_data && c1->private_clone)
+ c2->private_data = c2->private_clone(c2->private_data);
+ c2->name = strdup(c2->name);
+ if (c2->sname != NULL)
+ c2->sname = strdup(c2->sname);
+ c2->next = Clone_Chunk(c2->next);
+ c2->part = Clone_Chunk(c2->part);
+ return c2;
+}
+
+int
+Insert_Chunk(struct chunk *c2, daddr_t offset, daddr_t size, const char *name,
+ chunk_e type, int subtype, u_long flags, const char *sname)
+{
+ struct chunk *ct,*cs;
+
+ /* We will only insert into empty spaces */
+ if (c2->type != unused)
+ return __LINE__;
+
+ ct = New_Chunk();
+ if (ct == NULL)
+ return __LINE__;
+ ct->disk = c2->disk;
+ ct->offset = offset;
+ ct->size = size;
+ ct->end = offset + size - 1;
+ ct->type = type;
+ if (sname != NULL)
+ ct->sname = strdup(sname);
+ ct->name = strdup(name);
+ ct->subtype = subtype;
+ ct->flags = flags;
+
+ if (!Chunk_Inside(c2, ct)) {
+ Free_Chunk(ct);
+ return __LINE__;
+ }
+
+ if ((type == freebsd || type == extended || type == apple)) {
+ cs = New_Chunk();
+ if (cs == NULL)
+ return __LINE__;
+ cs->disk = c2->disk;
+ cs->offset = offset;
+ cs->size = size;
+ cs->end = offset + size - 1;
+ cs->type = unused;
+ if (sname != NULL)
+ cs->sname = strdup(sname);
+ cs->name = strdup("-");
+ ct->part = cs;
+ }
+
+ /* Make a new chunk for any trailing unused space */
+ if (c2->end > ct->end) {
+ cs = New_Chunk();
+ if (cs == NULL)
+ return __LINE__;
+ *cs = *c2;
+ cs->disk = c2->disk;
+ cs->offset = ct->end + 1;
+ cs->size = c2->end - ct->end;
+ if (c2->sname != NULL)
+ cs->sname = strdup(c2->sname);
+ if (c2->name)
+ cs->name = strdup(c2->name);
+ c2->next = cs;
+ c2->size -= c2->end - ct->end;
+ c2->end = ct->end;
+ }
+ /* If no leading unused space just occupy the old chunk */
+ if (c2->offset == ct->offset) {
+ c2->sname = ct->sname;
+ c2->name = ct->name;
+ c2->type = ct->type;
+ c2->part = ct->part;
+ c2->subtype = ct->subtype;
+ c2->flags = ct->flags;
+ ct->sname = NULL;
+ ct->name = NULL;
+ ct->part = 0;
+ Free_Chunk(ct);
+ return 0;
+ }
+ /* else insert new chunk and adjust old one */
+ c2->end = ct->offset - 1;
+ c2->size -= ct->size;
+ ct->next = c2->next;
+ c2->next = ct;
+ return 0;
+}
+
+int
+Add_Chunk(struct disk *d, daddr_t offset, daddr_t size, const char *name,
+ chunk_e type, int subtype, u_long flags, const char *sname)
+{
+ struct chunk *c1, *c2, ct;
+ daddr_t end = offset + size - 1;
+ ct.offset = offset;
+ ct.end = end;
+ ct.size = size;
+
+ if (type == whole) {
+ d->chunks = c1 = New_Chunk();
+ if (c1 == NULL)
+ return __LINE__;
+ c2 = c1->part = New_Chunk();
+ if (c2 == NULL)
+ return __LINE__;
+ c2->disk = c1->disk = d;
+ c2->offset = c1->offset = offset;
+ c2->size = c1->size = size;
+ c2->end = c1->end = end;
+ c1->sname = strdup(sname);
+ c2->sname = strdup("-");
+ c1->name = strdup(name);
+ c2->name = strdup("-");
+ c1->type = type;
+ c2->type = unused;
+ c1->flags = flags;
+ c1->subtype = subtype;
+ return 0;
+ }
+
+ c1 = 0;
+ /* PLATFORM POLICY BEGIN ------------------------------------- */
+ switch(platform) {
+ case p_i386:
+ case p_amd64:
+ switch (type) {
+ case fat:
+ case gpt:
+ case mbr:
+ case extended:
+ case freebsd:
+ c1 = Find_Mother_Chunk(d->chunks, offset, end, whole);
+ break;
+ case part:
+ c1 = Find_Mother_Chunk(d->chunks, offset, end, freebsd);
+ break;
+ default:
+ return(-1);
+ }
+ break;
+ case p_ia64:
+ switch (type) {
+ case freebsd:
+ subtype = 0xa5;
+ /* FALL THROUGH */
+ case fat:
+ case efi:
+ case mbr:
+ c1 = Find_Mother_Chunk(d->chunks, offset, end, whole);
+ break;
+ case part:
+ c1 = Find_Mother_Chunk(d->chunks, offset, end,
+ freebsd);
+ if (!c1)
+ c1 = Find_Mother_Chunk(d->chunks, offset, end,
+ whole);
+ break;
+ default:
+ return (-1);
+ }
+ break;
+ case p_pc98:
+ switch (type) {
+ case fat:
+ case pc98:
+ case freebsd:
+ c1 = Find_Mother_Chunk(d->chunks, offset, end, whole);
+ break;
+ case part:
+ c1 = Find_Mother_Chunk(d->chunks, offset, end, freebsd);
+ break;
+ default:
+ return(-1);
+ }
+ break;
+ case p_sparc64:
+ case p_alpha:
+ switch (type) {
+ case freebsd:
+ c1 = Find_Mother_Chunk(d->chunks, offset, end, whole);
+ break;
+ case part:
+ c1 = Find_Mother_Chunk(d->chunks, offset, end, freebsd);
+ break;
+ default:
+ return(-1);
+ }
+ break;
+ case p_ppc:
+ switch (type) {
+ case apple:
+ c1 = Find_Mother_Chunk(d->chunks, offset, end, whole);
+ break;
+ case part:
+ c1 = Find_Mother_Chunk(d->chunks, offset, end, apple);
+ break;
+ default:
+ return (-1);
+ }
+ break;
+ default:
+ return (-1);
+ }
+ /* PLATFORM POLICY END ---------------------------------------- */
+
+ if(!c1)
+ return __LINE__;
+ for(c2 = c1->part; c2; c2 = c2->next) {
+ if (c2->type != unused)
+ continue;
+ if(!Chunk_Inside(c2, &ct))
+ continue;
+/* PLATFORM POLICY BEGIN ------------------------------------- */
+ if (platform == p_sparc64) {
+ offset = Prev_Cyl_Aligned(d, offset);
+ size = Next_Cyl_Aligned(d, size);
+ } else if (platform == p_i386 || platform == p_pc98 ||
+ platform == p_amd64) {
+ if (type != freebsd)
+ break;
+ if (!(flags & CHUNK_ALIGN))
+ break;
+ if (offset == d->chunks->offset &&
+ end == d->chunks->end)
+ break;
+
+ /* Round down to prev cylinder */
+ offset = Prev_Cyl_Aligned(d,offset);
+ /* Stay inside the parent */
+ if (offset < c2->offset)
+ offset = c2->offset;
+ /* Round up to next cylinder */
+ offset = Next_Cyl_Aligned(d, offset);
+ /* Keep one track clear in front of parent */
+ if (offset == c1->offset)
+ offset = Next_Track_Aligned(d, offset + 1);
+ /* Work on the (end+1) */
+ size += offset;
+ /* Round up to cylinder */
+ size = Next_Cyl_Aligned(d, size);
+ /* Stay inside parent */
+ if ((size-1) > c2->end)
+ size = c2->end + 1;
+ /* Round down to cylinder */
+ size = Prev_Cyl_Aligned(d, size);
+
+ /* Convert back to size */
+ size -= offset;
+ }
+ break;
+
+/* PLATFORM POLICY END ------------------------------------- */
+ }
+ if (c2 == NULL)
+ return (__LINE__);
+ return Insert_Chunk(c2, offset, size, name, type, subtype, flags,
+ sname);
+}
+
+char *
+ShowChunkFlags(struct chunk *c)
+{
+ static char ret[10];
+ int i = 0;
+
+ if (c->flags & CHUNK_ACTIVE)
+ ret[i++] = 'A';
+ if (c->flags & CHUNK_ALIGN)
+ ret[i++] = '=';
+ if (c->flags & CHUNK_IS_ROOT)
+ ret[i++] = 'R';
+ ret[i++] = '\0';
+
+ return ret;
+}
+
+static void
+Print_Chunk(struct chunk *c1, int offset)
+{
+ int i;
+
+ if (!c1)
+ return;
+ for (i = 0; i < offset - 2; i++)
+ putchar(' ');
+ for (; i < offset; i++)
+ putchar('-');
+ putchar('>');
+ for (; i < 10; i++)
+ putchar(' ');
+#ifndef __ia64__
+ printf("%p ", c1);
+#endif
+ printf("%8jd %8jd %8jd %-8s %-16s %-8s 0x%02x %s",
+ (intmax_t)c1->offset, (intmax_t)c1->size, (intmax_t)c1->end,
+ c1->name, c1->sname, chunk_name(c1->type), c1->subtype,
+ ShowChunkFlags(c1));
+ putchar('\n');
+ Print_Chunk(c1->part, offset + 2);
+ Print_Chunk(c1->next, offset);
+}
+
+void
+Debug_Chunk(struct chunk *c1)
+{
+
+ Print_Chunk(c1, 2);
+}
+
+int
+Delete_Chunk(struct disk *d, struct chunk *c)
+{
+
+ return (Delete_Chunk2(d, c, 0));
+}
+
+int
+Delete_Chunk2(struct disk *d, struct chunk *c, int rflags)
+{
+ struct chunk *c1, *c2, *c3;
+ daddr_t offset = c->offset;
+
+ switch (c->type) {
+ case whole:
+ case unused:
+ return 1;
+ case extended:
+ c1 = Find_Mother_Chunk(d->chunks, c->offset, c->end, whole);
+ break;
+ case part:
+ c1 = Find_Mother_Chunk(d->chunks, c->offset, c->end, freebsd);
+#ifdef __ia64__
+ if (c1 == NULL)
+ c1 = Find_Mother_Chunk(d->chunks, c->offset, c->end,
+ whole);
+#endif
+#ifdef __powerpc__
+ if (c1 == NULL)
+ c1 = Find_Mother_Chunk(d->chunks, c->offset, c->end,
+ apple);
+#endif
+ break;
+ default:
+ c1 = Find_Mother_Chunk(d->chunks, c->offset, c->end, extended);
+ if (c1 == NULL)
+ c1 = Find_Mother_Chunk(d->chunks, c->offset, c->end,
+ whole);
+ break;
+ }
+ if (c1 == NULL)
+ return 1;
+ for (c2 = c1->part; c2; c2 = c2->next) {
+ if (c2 == c) {
+ c2->type = unused;
+ c2->subtype = 0;
+ c2->flags = 0;
+ if (c2->sname != NULL)
+ free(c2->sname);
+ c2->sname = strdup("-");
+ free(c2->name);
+ c2->name = strdup("-");
+ Free_Chunk(c2->part);
+ c2->part =0;
+ goto scan;
+ }
+ }
+ return 1;
+scan:
+ /*
+ * Collapse multiple unused elements together, and attempt
+ * to extend the previous chunk into the freed chunk.
+ *
+ * We only extend non-unused elements which are marked
+ * for newfs (we can't extend working filesystems), and
+ * only if we are called with DELCHUNK_RECOVER.
+ */
+ for (c2 = c1->part; c2; c2 = c2->next) {
+ if (c2->type != unused) {
+ if (c2->offset + c2->size != offset ||
+ (rflags & DELCHUNK_RECOVER) == 0 ||
+ (c2->flags & CHUNK_NEWFS) == 0) {
+ continue;
+ }
+ /* else extend into free area */
+ }
+ if (!c2->next)
+ continue;
+ if (c2->next->type != unused)
+ continue;
+ c3 = c2->next;
+ c2->size += c3->size;
+ c2->end = c3->end;
+ c2->next = c3->next;
+ c3->next = 0;
+ Free_Chunk(c3);
+ goto scan;
+ }
+ Fixup_Names(d);
+ return 0;
+}
+
+#if 0
+int
+Collapse_Chunk(struct disk *d, struct chunk *c1)
+{
+ struct chunk *c2, *c3;
+
+ if (c1->next && Collapse_Chunk(d, c1->next))
+ return 1;
+
+ if (c1->type == unused && c1->next && c1->next->type == unused) {
+ c3 = c1->next;
+ c1->size += c3->size;
+ c1->end = c3->end;
+ c1->next = c3->next;
+ c3->next = 0;
+ Free_Chunk(c3);
+ return 1;
+ }
+ c3 = c1->part;
+ if (!c3)
+ return 0;
+ if (Collapse_Chunk(d, c1->part))
+ return 1;
+
+ if (c1->type == whole)
+ return 0;
+
+ if (c3->type == unused && c3->size == c1->size) {
+ Delete_Chunk(d, c1);
+ return 1;
+ }
+ if (c3->type == unused) {
+ c2 = New_Chunk();
+ if (c2 == NULL)
+ barfout(1, "malloc failed");
+ *c2 = *c1;
+ c1->next = c2;
+ c1->disk = d;
+ c1->sname = strdup("-");
+ c1->name = strdup("-");
+ c1->part = 0;
+ c1->type = unused;
+ c1->flags = 0;
+ c1->subtype = 0;
+ c1->size = c3->size;
+ c1->end = c3->end;
+ c2->offset += c1->size;
+ c2->size -= c1->size;
+ c2->part = c3->next;
+ c3->next = 0;
+ Free_Chunk(c3);
+ return 1;
+ }
+ for (c2 = c3; c2->next; c2 = c2->next)
+ c3 = c2;
+ if (c2 && c2->type == unused) {
+ c3->next = 0;
+ c2->next = c1->next;
+ c1->next = c2;
+ c1->size -= c2->size;
+ c1->end -= c2->size;
+ return 1;
+ }
+
+ return 0;
+}
+#endif
diff --git a/lib/libdisk/create_chunk.c b/lib/libdisk/create_chunk.c
new file mode 100644
index 0000000..7f1453e
--- /dev/null
+++ b/lib/libdisk/create_chunk.c
@@ -0,0 +1,296 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <sys/param.h>
+#include <sys/disklabel.h>
+#ifdef PC98
+#include <sys/diskpc98.h>
+#else
+#include <sys/diskmbr.h>
+#endif
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <grp.h>
+#include <paths.h>
+#include <pwd.h>
+#include "libdisk.h"
+
+static int
+Fixup_FreeBSD_Names(struct chunk *c)
+{
+ struct chunk *c1, *c3;
+ uint j;
+
+ if (!strcmp(c->name, "X"))
+ return 0;
+
+ /* reset all names to "X" */
+ for (c1 = c->part; c1; c1 = c1->next) {
+ c1->oname = c1->name;
+ c1->name = malloc(12);
+ if (!c1->name)
+ return -1;
+ strcpy(c1->name,"X");
+ }
+
+ /* Allocate the first swap-partition we find */
+ for (c1 = c->part; c1; c1 = c1->next) {
+ if (c1->type == unused)
+ continue;
+ if (c1->subtype != FS_SWAP)
+ continue;
+ sprintf(c1->name, "%s%c", c->name, SWAP_PART + 'a');
+ break;
+ }
+
+ /* Allocate the first root-partition we find */
+ for (c1 = c->part; c1; c1 = c1->next) {
+ if (c1->type == unused)
+ continue;
+ if (!(c1->flags & CHUNK_IS_ROOT))
+ continue;
+ sprintf(c1->name, "%s%c", c->name, 0 + 'a');
+ break;
+ }
+
+ /* Try to give them the same as they had before */
+ for (c1 = c->part; c1; c1 = c1->next) {
+ if (strcmp(c1->name, "X"))
+ continue;
+ for (c3 = c->part; c3 ; c3 = c3->next)
+ if (c1 != c3 && !strcmp(c3->name, c1->oname))
+ goto newname;
+ strcpy(c1->name, c1->oname);
+ newname:
+ ;
+ }
+
+ /* Allocate the rest sequentially */
+ for (c1 = c->part; c1; c1 = c1->next) {
+ const char order[] = "defghab";
+
+ if (c1->type == unused)
+ continue;
+ if (strcmp("X", c1->name))
+ continue;
+
+ for (j = 0; j < strlen(order); j++) {
+ sprintf(c1->name, "%s%c", c->name, order[j]);
+ for (c3 = c->part; c3 ; c3 = c3->next)
+ if (c1 != c3 && !strcmp(c3->name, c1->name))
+ goto match;
+ break;
+ match:
+ strcpy(c1->name, "X");
+ continue;
+ }
+ }
+ for (c1 = c->part; c1; c1 = c1->next) {
+ free(c1->oname);
+ c1->oname = 0;
+ }
+ return 0;
+}
+
+#ifndef PC98
+static int
+Fixup_Extended_Names(struct chunk *c)
+{
+ struct chunk *c1;
+ int j = 5;
+
+ for (c1 = c->part; c1; c1 = c1->next) {
+ if (c1->type == unused)
+ continue;
+ free(c1->name);
+ c1->name = malloc(12);
+ if (!c1->name)
+ return -1;
+ sprintf(c1->name, "%ss%d", c->disk->chunks->name, j++);
+ if (c1->type == freebsd)
+ if (Fixup_FreeBSD_Names(c1) != 0)
+ return -1;
+ }
+ return 0;
+}
+#endif
+
+#ifdef __powerpc__
+static int
+Fixup_Apple_Names(struct chunk *c)
+{
+ struct chunk *c1;
+
+ for (c1 = c->part; c1; c1 = c1->next) {
+ if (c1->type == unused)
+ continue;
+ free(c1->name);
+ c1->name = strdup(c->name);
+ if (!c1->name)
+ return (-1);
+ }
+ return 0;
+}
+#endif
+
+int
+Fixup_Names(struct disk *d)
+{
+ struct chunk *c1, *c2;
+#if defined(__i386__) || defined(__ia64__) || defined(__amd64__)
+ struct chunk *c3;
+ int j, max;
+#endif
+
+ c1 = d->chunks;
+ for (c2 = c1->part; c2 ; c2 = c2->next) {
+ if (c2->type == unused)
+ continue;
+ if (strcmp(c2->name, "X"))
+ continue;
+#if defined(__i386__) || defined(__ia64__) || defined(__amd64__)
+ c2->oname = malloc(12);
+ if (!c2->oname)
+ return -1;
+#ifdef __ia64__
+ max = d->gpt_size;
+#else
+ max = NDOSPART;
+#endif
+ for (j = 1; j <= max; j++) {
+#ifdef __ia64__
+ sprintf(c2->oname, "%s%c%d", c1->name,
+ (c1->type == whole) ? 'p' : 's', j);
+#else
+ sprintf(c2->oname, "%ss%d", c1->name, j);
+#endif
+ for (c3 = c1->part; c3; c3 = c3->next)
+ if (c3 != c2 && !strcmp(c3->name, c2->oname))
+ goto match;
+ free(c2->name);
+ c2->name = c2->oname;
+ c2->oname = 0;
+ break;
+ match:
+ continue;
+ }
+ if (c2->oname)
+ free(c2->oname);
+#else
+ free(c2->name);
+ c2->name = strdup(c1->name);
+#endif /*__i386__*/
+ }
+ for (c2 = c1->part; c2; c2 = c2->next) {
+ if (c2->type == freebsd)
+ Fixup_FreeBSD_Names(c2);
+#ifdef __powerpc__
+ else if (c2->type == apple)
+ Fixup_Apple_Names(c2);
+#endif
+#ifndef PC98
+ else if (c2->type == extended)
+ Fixup_Extended_Names(c2);
+#endif
+ }
+ return 0;
+}
+
+int
+Create_Chunk(struct disk *d, daddr_t offset, daddr_t size, chunk_e type,
+ int subtype, u_long flags, const char *sname)
+{
+ int i;
+
+#ifndef __ia64__
+ if (!(flags & CHUNK_FORCE_ALL)) {
+ daddr_t l;
+#ifdef PC98
+ /* Never use the first cylinder */
+ if (!offset) {
+ offset += (d->bios_sect * d->bios_hd);
+ size -= (d->bios_sect * d->bios_hd);
+ }
+#else
+ /* Never use the first track */
+ if (!offset) {
+ offset += d->bios_sect;
+ size -= d->bios_sect;
+ }
+#endif /* PC98 */
+
+ /* Always end on cylinder boundary */
+ l = (offset + size) % (d->bios_sect * d->bios_hd);
+ size -= l;
+ }
+#endif
+
+ i = Add_Chunk(d, offset, size, "X", type, subtype, flags, sname);
+ Fixup_Names(d);
+ return i;
+}
+
+struct chunk *
+Create_Chunk_DWIM(struct disk *d, struct chunk *parent, daddr_t size,
+ chunk_e type, int subtype, u_long flags)
+{
+ int i;
+ struct chunk *c1;
+ daddr_t offset;
+
+ if (!parent)
+ parent = d->chunks;
+
+ if ((parent->type == freebsd && type == part && parent->part == NULL)
+ || (parent->type == apple && type == part && parent->part == NULL)) {
+ c1 = New_Chunk();
+ if (c1 == NULL)
+ return (NULL);
+ c1->disk = parent->disk;
+ c1->offset = parent->offset;
+ c1->size = parent->size;
+ c1->end = parent->offset + parent->size - 1;
+ c1->type = unused;
+ if (parent->sname != NULL)
+ c1->sname = strdup(parent->sname);
+ c1->name = strdup("-");
+ parent->part = c1;
+ }
+
+ for (c1 = parent->part; c1; c1 = c1->next) {
+ if (c1->type != unused)
+ continue;
+ if (c1->size < size)
+ continue;
+ offset = c1->offset;
+ goto found;
+ }
+ return 0;
+found:
+ i = Add_Chunk(d, offset, size, "X", type, subtype, flags, "-");
+ if (i)
+ return 0;
+ Fixup_Names(d);
+ for (c1 = parent->part; c1; c1 = c1->next)
+ if (c1->offset == offset)
+ return c1;
+ /* barfout(1, "Serious internal trouble"); */
+ return 0;
+}
diff --git a/lib/libdisk/disk.c b/lib/libdisk/disk.c
new file mode 100644
index 0000000..68be4ee
--- /dev/null
+++ b/lib/libdisk/disk.c
@@ -0,0 +1,400 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <inttypes.h>
+#include <err.h>
+#include <sys/sysctl.h>
+#include <sys/stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/disklabel.h>
+#include <sys/uuid.h>
+#include <sys/gpt.h>
+#include <paths.h>
+#include "libdisk.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include <assert.h>
+#include <uuid.h>
+
+const enum platform platform =
+#if defined (P_DEBUG)
+ P_DEBUG
+#elif defined (PC98)
+ p_pc98
+#elif defined(__i386__)
+ p_i386
+#elif defined(__alpha__)
+ p_alpha
+#elif defined(__sparc64__)
+ p_sparc64
+#elif defined(__ia64__)
+ p_ia64
+#elif defined(__ppc__)
+ p_ppc
+#elif defined(__amd64__)
+ p_amd64
+#elif defined(__arm__)
+ p_arm
+#else
+ IHAVENOIDEA
+#endif
+ ;
+
+const char *
+chunk_name(chunk_e type)
+{
+ switch(type) {
+ case unused: return ("unused");
+ case mbr: return ("mbr");
+ case part: return ("part");
+ case gpt: return ("gpt");
+ case pc98: return ("pc98");
+ case sun: return ("sun");
+ case freebsd: return ("freebsd");
+ case fat: return ("fat");
+ case spare: return ("spare");
+ case efi: return ("efi");
+ case apple: return ("apple");
+ default: return ("??");
+ }
+}
+
+struct disk *
+Open_Disk(const char *name)
+{
+ struct disk *d;
+ char *conftxt;
+ size_t txtsize;
+ int error;
+
+ error = sysctlbyname("kern.geom.conftxt", NULL, &txtsize, NULL, 0);
+ if (error) {
+ warn("kern.geom.conftxt sysctl not available, giving up!");
+ return (NULL);
+ }
+ conftxt = malloc(txtsize+1);
+ if (conftxt == NULL) {
+ warn("cannot malloc memory for conftxt");
+ return (NULL);
+ }
+ error = sysctlbyname("kern.geom.conftxt", conftxt, &txtsize, NULL, 0);
+ if (error) {
+ warn("error reading kern.geom.conftxt from the system");
+ free(conftxt);
+ return (NULL);
+ }
+ conftxt[txtsize] = '\0'; /* in case kernel bug is still there */
+ d = Int_Open_Disk(name, conftxt);
+ free(conftxt);
+
+ return (d);
+}
+
+void
+Debug_Disk(struct disk *d)
+{
+
+ printf("Debug_Disk(%s)", d->name);
+
+#ifndef __ia64__
+ printf(" bios_geom=%lu/%lu/%lu = %lu\n",
+ d->bios_cyl, d->bios_hd, d->bios_sect,
+ d->bios_cyl * d->bios_hd * d->bios_sect);
+#if defined(PC98)
+ printf(" boot1=%p, boot2=%p, bootipl=%p, bootmenu=%p\n",
+ d->boot1, d->boot2, d->bootipl, d->bootmenu);
+#elif defined(__i386__) || defined(__amd64__)
+ printf(" boot1=%p, boot2=%p, bootmgr=%p\n",
+ d->boot1, d->boot2, d->bootmgr);
+#elif defined(__alpha__)
+ printf(" boot1=%p, bootmgr=%p\n",
+ d->boot1, d->bootmgr);
+#else
+/* Should be: error "Debug_Disk: unknown arch"; */
+#endif
+#else /* __ia64__ */
+ printf(" media size=%lu, sector size=%lu\n", d->media_size,
+ d->sector_size);
+#endif
+
+ Debug_Chunk(d->chunks);
+}
+
+void
+Free_Disk(struct disk *d)
+{
+ if (d->chunks)
+ Free_Chunk(d->chunks);
+ if (d->name)
+ free(d->name);
+#ifdef PC98
+ if (d->bootipl)
+ free(d->bootipl);
+ if (d->bootmenu)
+ free(d->bootmenu);
+#else
+#if !defined(__ia64__)
+ if (d->bootmgr)
+ free(d->bootmgr);
+#endif
+#endif
+#if !defined(__ia64__)
+ if (d->boot1)
+ free(d->boot1);
+#endif
+#if defined(__i386__) || defined(__amd64__)
+ if (d->boot2)
+ free(d->boot2);
+#endif
+ free(d);
+}
+
+#if 0
+void
+Collapse_Disk(struct disk *d)
+{
+
+ while (Collapse_Chunk(d, d->chunks))
+ ;
+}
+#endif
+
+static int
+qstrcmp(const void* a, const void* b)
+{
+ const char *str1 = *(char* const*)a;
+ const char *str2 = *(char* const*)b;
+
+ return strcmp(str1, str2);
+}
+
+char **
+Disk_Names()
+{
+ int disk_cnt;
+ static char **disks;
+ int error;
+ size_t listsize;
+ char *disklist;
+
+ error = sysctlbyname("kern.disks", NULL, &listsize, NULL, 0);
+ if (error) {
+ warn("kern.disks sysctl not available");
+ return NULL;
+ }
+
+ if (listsize == 0)
+ return (NULL);
+
+ disks = malloc(sizeof *disks * (1 + MAX_NO_DISKS));
+ if (disks == NULL)
+ return NULL;
+ disklist = (char *)malloc(listsize + 1);
+ if (disklist == NULL) {
+ free(disks);
+ return NULL;
+ }
+ memset(disks,0,sizeof *disks * (1 + MAX_NO_DISKS));
+ memset(disklist, 0, listsize + 1);
+ error = sysctlbyname("kern.disks", disklist, &listsize, NULL, 0);
+ if (error || disklist[0] == 0) {
+ free(disklist);
+ free(disks);
+ return NULL;
+ }
+ for (disk_cnt = 0; disk_cnt < MAX_NO_DISKS; disk_cnt++) {
+ disks[disk_cnt] = strsep(&disklist, " ");
+ if (disks[disk_cnt] == NULL)
+ break;
+ }
+ qsort(disks, disk_cnt, sizeof(char*), qstrcmp);
+ return disks;
+}
+
+#ifdef PC98
+void
+Set_Boot_Mgr(struct disk *d, const u_char *bootipl, const size_t bootipl_size,
+ const u_char *bootmenu, const size_t bootmenu_size)
+#else
+void
+Set_Boot_Mgr(struct disk *d, const u_char *b, const size_t s)
+#endif
+{
+#if !defined(__ia64__)
+#ifdef PC98
+ if (d->sector_size == 0)
+ return;
+ if (bootipl_size % d->sector_size != 0)
+ return;
+ if (d->bootipl)
+ free(d->bootipl);
+ if (!bootipl) {
+ d->bootipl = NULL;
+ } else {
+ d->bootipl_size = bootipl_size;
+ d->bootipl = malloc(bootipl_size);
+ if (!d->bootipl)
+ return;
+ memcpy(d->bootipl, bootipl, bootipl_size);
+ }
+
+ if (bootmenu_size % d->sector_size != 0)
+ return;
+ if (d->bootmenu)
+ free(d->bootmenu);
+ if (!bootmenu) {
+ d->bootmenu = NULL;
+ } else {
+ d->bootmenu_size = bootmenu_size;
+ d->bootmenu = malloc(bootmenu_size);
+ if (!d->bootmenu)
+ return;
+ memcpy(d->bootmenu, bootmenu, bootmenu_size);
+ }
+#else
+ if (d->sector_size == 0)
+ return;
+ if (s % d->sector_size != 0)
+ return;
+ if (d->bootmgr)
+ free(d->bootmgr);
+ if (!b) {
+ d->bootmgr = NULL;
+ } else {
+ d->bootmgr_size = s;
+ d->bootmgr = malloc(s);
+ if (!d->bootmgr)
+ return;
+ memcpy(d->bootmgr, b, s);
+ }
+#endif
+#endif
+}
+
+int
+Set_Boot_Blocks(struct disk *d, const u_char *b1, const u_char *b2)
+{
+#if defined(__i386__) || defined(__amd64__)
+ if (d->boot1)
+ free(d->boot1);
+ d->boot1 = malloc(512);
+ if (!d->boot1)
+ return -1;
+ memcpy(d->boot1, b1, 512);
+ if (d->boot2)
+ free(d->boot2);
+ d->boot2 = malloc(15 * 512);
+ if (!d->boot2)
+ return -1;
+ memcpy(d->boot2, b2, 15 * 512);
+#elif defined(__alpha__)
+ if (d->boot1)
+ free(d->boot1);
+ d->boot1 = malloc(15 * 512);
+ if (!d->boot1)
+ return -1;
+ memcpy(d->boot1, b1, 15 * 512);
+#elif defined(__sparc64__)
+ if (d->boot1 != NULL)
+ free(d->boot1);
+ d->boot1 = malloc(16 * 512);
+ if (d->boot1 == NULL)
+ return (-1);
+ memcpy(d->boot1, b1, 16 * 512);
+#elif defined(__ia64__)
+ /* nothing */
+#else
+/* Should be: #error "Set_Boot_Blocks: unknown arch"; */
+#endif
+ return 0;
+}
+
+const char *
+slice_type_name( int type, int subtype )
+{
+
+ switch (type) {
+ case whole:
+ return "whole";
+ case mbr:
+ switch (subtype) {
+ case 1: return "fat (12-bit)";
+ case 2: return "XENIX /";
+ case 3: return "XENIX /usr";
+ case 4: return "fat (16-bit,<=32Mb)";
+ case 5: return "extended DOS";
+ case 6: return "fat (16-bit,>32Mb)";
+ case 7: return "NTFS/HPFS/QNX";
+ case 8: return "AIX bootable";
+ case 9: return "AIX data";
+ case 10: return "OS/2 bootmgr";
+ case 11: return "fat (32-bit)";
+ case 12: return "fat (32-bit,LBA)";
+ case 14: return "fat (16-bit,>32Mb,LBA)";
+ case 15: return "extended DOS, LBA";
+ case 18: return "Compaq Diagnostic";
+ case 57: return "Plan 9";
+ case 77: return "QNX 4.X";
+ case 78: return "QNX 4.X 2nd part";
+ case 79: return "QNX 4.X 3rd part";
+ case 84: return "OnTrack diskmgr";
+ case 100: return "Netware 2.x";
+ case 101: return "Netware 3.x";
+ case 115: return "SCO UnixWare";
+ case 128: return "Minix 1.1";
+ case 129: return "Minix 1.5";
+ case 130: return "linux_swap";
+ case 131: return "ext2fs";
+ case 133: return "linux extended";
+ case 166: return "OpenBSD FFS"; /* 0xA6 */
+ case 168: return "Mac OS-X";
+ case 169: return "NetBSD FFS"; /* 0xA9 */
+ case 171: return "Mac OS-X Boot";
+ case 182: return "OpenBSD"; /* dedicated */
+ case 183: return "bsd/os";
+ case 184: return "bsd/os swap";
+ case 191: return "Solaris (new)";
+ case 238: return "EFI GPT";
+ case 239: return "EFI Sys. Part.";
+ default: return "unknown";
+ }
+ case fat:
+ return "fat";
+ case freebsd:
+ switch (subtype) {
+#ifdef PC98
+ case 0xc494: return "freebsd";
+#else
+ case 165: return "freebsd";
+#endif
+ default: return "unknown";
+ }
+ case extended:
+ return "extended";
+ case part:
+ return "part";
+ case efi:
+ return "efi";
+ case unused:
+ return "unused";
+ default:
+ return "unknown";
+ }
+}
diff --git a/lib/libdisk/libdisk.3 b/lib/libdisk/libdisk.3
new file mode 100644
index 0000000..43e7ba1
--- /dev/null
+++ b/lib/libdisk/libdisk.3
@@ -0,0 +1,345 @@
+.\"
+.\" Copyright (c) 1996 Joerg Wunsch
+.\"
+.\" All rights reserved.
+.\"
+.\" This program is free software.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this 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 January 30, 2006
+.Dt LIBDISK 3
+.Os
+.Sh NAME
+.Nm Open_Disk ,
+.Nm Free_Disk ,
+.Nm Debug_Disk ,
+.Nm Set_Bios_Geom ,
+.Nm Delete_Chunk ,
+.Nm Collapse_Disk ,
+.Nm Collapse_Chunk ,
+.Nm Create_Chunk ,
+.Nm All_FreeBSD ,
+.Nm CheckRules ,
+.Nm Disk_Names ,
+.Nm Set_Boot_Mgr ,
+.Nm Set_Boot_Blocks ,
+.Nm Write_Disk ,
+.Nm Cyl_Aligned ,
+.Nm Next_Cyl_Aligned ,
+.Nm Prev_Cyl_Aligned ,
+.Nm Track_Aligned ,
+.Nm Next_Track_Aligned ,
+.Nm Prev_Track_Aligned ,
+.Nm Create_Chunk_DWIM ,
+.Nm MakeDev ,
+.Nm MakeDevDisk ,
+.Nm ShowChunkFlags ,
+.Nm chunk_name ,
+.Nm slice_type_name
+.Nd library interface to slice and partition labels
+.Sh LIBRARY
+.Lb libdisk
+.Sh SYNOPSIS
+.In sys/types.h
+.In libdisk.h
+.Pp
+.Ft struct disk *
+.Fn Open_Disk "const char *devname"
+.Ft void
+.Fn Free_Disk "struct disk *disk"
+.Ft void
+.Fn Debug_Disk "struct disk *disk"
+.Ft void
+.Fn Set_Bios_Geom "struct disk *disk" "u_long cyl" "u_long heads" "u_long sects"
+.Ft int
+.Fn Delete_Chunk "struct disk *disk" "struct chunk *"
+.Ft void
+.Fn Collapse_Disk "struct disk *disk"
+.Ft int
+.Fn Collapse_Chunk "struct disk *disk" "struct chunk *chunk"
+.Ft int
+.Fn Create_Chunk "struct disk *disk" "daddr_t offset" "daddr_t size" "chunk_e type" "int subtype" "u_long flags" "const char *sname"
+.Ft void
+.Fn All_FreeBSD "struct disk *d" "int force_all"
+.Ft char *
+.Fn CheckRules "const struct disk *"
+.Ft char **
+.Fn Disk_Names "void"
+.Ft void
+.Fn Set_Boot_Mgr "struct disk *d" "const u_char *bootmgr" "const size_t bootmgr_size"
+.Ft int
+.Fn Set_Boot_Blocks "struct disk *d" "const u_char *boot1" "const u_char *boot2"
+.Ft int
+.Fn Write_Disk "const struct disk *d"
+.Ft int
+.Fn Cyl_Aligned "struct disk *d" "daddr_t offset"
+.Ft daddr_t
+.Fn Next_Cyl_Aligned "const struct disk *d" "daddr_t offset"
+.Ft daddr_t
+.Fn Prev_Cyl_Aligned "const struct disk *d" "daddr_t offset"
+.Ft int
+.Fn Track_Aligned "const struct disk *d" "daddr_t offset"
+.Ft daddr_t
+.Fn Next_Track_Aligned "const struct disk *d" "daddr_t offset"
+.Ft daddr_t
+.Fn Prev_Track_Aligned "const struct disk *d" "daddr_t offset"
+.Ft struct chunk *
+.Fn Create_Chunk_DWIM "struct disk *d" "struct chunk *parent" "daddr_t size" "chunk_e type" "int subtype" "u_long flags"
+.Ft int
+.Fn MakeDev "struct chunk *c" "const char *path"
+.Ft int
+.Fn MakeDevDisk "struct disk *d" "const char *path"
+.Ft char *
+.Fn ShowChunkFlags "struct chunk *c"
+.Ft const char *
+.Fn chunk_name "chunk_e type"
+.Ft const char *
+.Fn slice_type_name "int type" "int subtype"
+.Sh DESCRIPTION
+.Bf Sy
+.Nm libdisk
+is just for the use of
+.Xr sysinstall 8 .
+You should consider using
+.Xr libgeom 3
+instead.
+.Ef
+.Pp
+The
+.Nm libdisk
+library provides an interface to the low-level disk slice and partition labels.
+Most functions operate with arguments of the types
+.Ql struct disk ,
+or
+.Ql struct chunk .
+.Pp
+While both types are mostly opaque to the programmer, the internal
+structure is mentioned below for the sake of completeness.
+.Bd -literal -offset indent
+struct disk {
+ char *name;
+ u_long flags;
+ u_long bios_cyl;
+ u_long bios_hd;
+ u_long bios_sect;
+ u_char *bootmgr;
+ u_char *boot1;
+ u_char *boot2;
+ struct chunk *chunks;
+ u_long sector_size;
+};
+.Ed
+The only flag value by now is
+.Ql DISK_ON_TRACK ,
+meaning that this disk is handled by the On-Track Disk Manager.
+.Pp
+.Bd -literal -offset indent
+struct chunk {
+ struct chunk *next;
+ struct chunk *part;
+ struct disk *disk;
+ daddr_t offset;
+ daddr_t size;
+ daddr_t end;
+ char *name;
+ char *oname;
+ chunk_e type;
+ int subtype;
+ u_long flags;
+ void (*private_free)(void*);
+ void *(*private_clone)(void*);
+ void *private_data;
+};
+.Ed
+The
+.Ql type
+field can be one of the following values:
+.Ql whole, unknown, fat, freebsd, extended, part, unused .
+.Pp
+These are the valid
+.Ql flags
+values for a
+.Ql struct chunk .
+.Bl -tag -offset indent -width CHUNK_BSD_COMPATXX
+.It CHUNK_PAST_1024
+This chunk cannot be booted from because it extends past cylinder 1024.
+.It CHUNK_BSD_COMPAT
+This chunk is in the
+.Bx Ns -compatibility ,
+and has a short name too, i.e.\&
+.Ql wd0s4f -> wd0f .
+.It CHUNK_ALIGN
+This chunk should be aligned.
+.It CHUNK_IS_ROOT
+This
+.Ql part
+is a rootfs, allocate partition
+.Sq a .
+.It CHUNK_ACTIVE
+This is the active slice in the MBR.
+.It CHUNK_FORCE_ALL
+Force a dedicated disk for
+.Fx ,
+bypassing all BIOS geometry considerations.
+.El
+.Pp
+The
+.Ql private_data ,
+.Ql private_free ,
+and
+.Ql private_clone
+fields are for data private to the application, and the management
+thereof.
+If the functions are not provided, no storage management is
+done, cloning will just copy the pointer and freeing will just forget
+it.
+.Pp
+.Fn Open_Disk
+will open the named disk, and return populated tree.
+.Pp
+.Fn Free_Disk
+frees a tree made with
+.Fn Open_Disk
+or
+.Fn Clone_Disk .
+.Pp
+.Fn Debug_Disk
+prints the content of the tree to
+.Dv stdout .
+.Pp
+.Fn Set_Bios_Geom
+sets the geometry the bios uses.
+.Pp
+.Fn Delete_Chunk
+frees a chunk of disk_space.
+.Pp
+.Fn Collapse_Disk
+and
+.Fn Collapse_Chunk
+are experimental, do not use.
+.Pp
+.Fn Create_Chunk
+creates a chunk with the specified parameters.
+.Pp
+.Fn All_FreeBSD
+makes one
+.Fx
+chunk covering the entire disk; if
+.Ql force_all
+is set, bypass all BIOS geometry considerations.
+.Pp
+.Fn CheckRules
+returns
+.Ql char*
+to warnings about broken design rules in this disklayout.
+.Pp
+.Fn Disk_Names
+returns
+.Ql char**
+with all disk's names (wd0, wd1 ...).
+You must free each pointer, as
+well as the array by hand.
+.Pp
+.Fn Set_Boot_Mgr
+sets this boot-manager for use on this disk.
+Gets written when
+.Fn Write_Disk
+is called.
+.Pp
+.Fn Set_Boot_Blocks
+sets the boot-blocks for use on this disk.
+Gets written when
+.Fn Write_Disk
+is called.
+.Pp
+.Fn Write_Disk
+writes all the MBRs, disklabels, bootblocks and boot managers.
+.Pp
+.Fn Cyl_Aligned
+checks if
+.Ql offset
+is aligned on a cylinder according to the BIOS geometry.
+.Pp
+.Fn Next_Cyl_Aligned
+rounds
+.Ql offset
+up to next cylinder according to the BIOS geometry.
+.Pp
+.Fn Prev_Cyl_Aligned
+rounds
+.Ql offset
+down to previous cylinder according to the BIOS geometry.
+.Pp
+.Fn Track_Aligned
+checks if
+.Ql offset
+is aligned on a track according to the BIOS geometry.
+.Pp
+.Fn Next_Track_Aligned
+rounds
+.Ql offset
+up to next track according to the BIOS geometry.
+.Pp
+.Fn Prev_Track_Aligned
+rounds
+.Ql offset
+up to previous track according to the BIOS geometry.
+.Pp
+.Fn Create_Chunk_DWIM
+creates a partition inside the given parent of the given size, and
+returns a pointer to it.
+The first unused chunk big enough is used.
+.Pp
+.Fn MakeDev
+makes the device nodes for this chunk.
+.Pp
+.Fn MakeDevDisk
+makes the device nodes for all chunks on this disk.
+.Pp
+.Fn ShowChunkFlags
+returns a string to show flags.
+.Pp
+The
+.Fn chunk_name
+function takes the enumerated chunk type and returns its name.
+.Fn chunk_name
+replaces the old external array
+.Va chunk_n .
+.Pp
+.Fn slice_type_name
+returns the name strings associated with the specified
+.Ql type .
+.Ql subtype .
+If
+.Fn slice_type_name
+returns "unknown" for slices it is not familiar with.
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm libdisk
+library was written by
+.An Poul-Henning Kamp .
+.Pp
+This manual page was written by
+.An J\(:org Wunsch .
diff --git a/lib/libdisk/libdisk.h b/lib/libdisk/libdisk.h
new file mode 100644
index 0000000..0a161cc
--- /dev/null
+++ b/lib/libdisk/libdisk.h
@@ -0,0 +1,364 @@
+/*
+* ----------------------------------------------------------------------------
+* "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
+* ----------------------------------------------------------------------------
+*
+* $FreeBSD$
+*
+*/
+
+/* #define DEBUG 1 */
+/* You can define a particular architecture here if you are debugging. */
+/* #define P_DEBUG p_sparc64 */
+
+#define MAX_NO_DISKS 32
+/* Max # of disks Disk_Names() will return */
+
+#define MAX_SEC_SIZE 2048 /* maximum sector size that is supported */
+#define MIN_SEC_SIZE 512 /* the sector size to end sensing at */
+
+enum platform {
+ p_any, /* for debugging ! */
+ p_alpha,
+ p_i386,
+ p_pc98,
+ p_sparc64,
+ p_ia64,
+ p_ppc,
+ p_amd64,
+ p_arm
+};
+extern const enum platform platform;
+
+typedef enum {
+ whole,
+ unknown,
+
+ sun,
+ pc98,
+ mbr,
+ gpt,
+
+ efi,
+ fat,
+ freebsd,
+ extended,
+ part,
+ spare,
+ unused,
+
+ apple
+} chunk_e;
+
+__BEGIN_DECLS
+#ifndef __ia64__
+struct disk {
+ char *name;
+ u_long bios_cyl;
+ u_long bios_hd;
+ u_long bios_sect;
+#ifdef PC98
+ u_char *bootipl;
+ size_t bootipl_size;
+ u_char *bootmenu;
+ size_t bootmenu_size;
+#else
+ u_char *bootmgr;
+ size_t bootmgr_size;
+#endif
+ u_char *boot1;
+#if defined(__i386__) || defined(__amd64__) /* the i386 needs extra help... */
+ u_char *boot2;
+#endif
+ struct chunk *chunks;
+ u_long sector_size; /* media sector size, a power of 2 */
+};
+#else /* !__ia64__ */
+struct disk {
+ char *name;
+ struct chunk *chunks;
+ u_long media_size;
+ u_long sector_size;
+ u_long lba_start;
+ u_long lba_end;
+ u_int gpt_size; /* Number of entries */
+};
+#endif
+
+struct chunk {
+ struct chunk *next;
+ struct chunk *part;
+ struct disk *disk;
+ daddr_t offset;
+ daddr_t size;
+ daddr_t end;
+ char *sname; /* PC98 field */
+ char *name;
+ char *oname;
+ /* Used during Fixup_Names() to avoid renaming more than
+ * absolutely needed.
+ */
+ chunk_e type;
+ int subtype;
+ u_long flags;
+ void (*private_free)(void*);
+ void *(*private_clone)(void*);
+ void *private_data;
+ /* For data private to the application, and the management
+ * thereof. If the functions are not provided, no storage
+ * management is done, Cloning will just copy the pointer
+ * and freeing will just forget it.
+ */
+};
+
+/*
+ * flags:
+ *
+ * ALIGN - This chunk should be aligned
+ * IS_ROOT - This 'part' is a rootfs, allocate 'a'
+ * ACTIVE - This is the active slice in the MBR
+ * FORCE_ALL - Force a dedicated disk for FreeBSD, bypassing
+ * all BIOS geometry considerations
+ * AUTO_SIZE - This chunk was auto-sized and can fill-out a
+ * following chunk if the following chunk is deleted.
+ * NEWFS - newfs pending, used to enable auto-resizing on
+ * delete (along with AUTO_SIZE).
+ */
+
+#define CHUNK_ALIGN 0x0008
+#define CHUNK_IS_ROOT 0x0010
+#define CHUNK_ACTIVE 0x0020
+#define CHUNK_FORCE_ALL 0x0040
+#define CHUNK_AUTO_SIZE 0x0080
+#define CHUNK_NEWFS 0x0100
+#define CHUNK_HAS_INDEX 0x0200
+#define CHUNK_ITOF(i) ((i & 0xFFFF) << 16)
+#define CHUNK_FTOI(f) ((f >> 16) & 0xFFFF)
+
+#define DELCHUNK_NORMAL 0x0000
+#define DELCHUNK_RECOVER 0x0001
+
+const char *chunk_name(chunk_e);
+
+const char *
+slice_type_name(int, int);
+/* "chunk_n" for subtypes too */
+
+struct disk *
+Open_Disk(const char *);
+/* Will open the named disk, and return populated tree. */
+
+void
+Free_Disk(struct disk *);
+/* Free a tree made with Open_Disk() or Clone_Disk() */
+
+void
+Debug_Disk(struct disk *);
+/* Print the content of the tree to stdout */
+
+void
+Set_Bios_Geom(struct disk *, u_long, u_long, u_long);
+/* Set the geometry the bios uses. */
+
+void
+Sanitize_Bios_Geom(struct disk *);
+/* Set the bios geometry to something sane */
+
+int
+Insert_Chunk(struct chunk *, daddr_t, daddr_t, const char *, chunk_e, int,
+ u_long, const char *);
+
+int
+Delete_Chunk2(struct disk *, struct chunk *, int);
+/* Free a chunk of disk_space modified by the passed flags. */
+
+int
+Delete_Chunk(struct disk *, struct chunk *);
+/* Free a chunk of disk_space */
+
+void
+Collapse_Disk(struct disk *);
+/* Experimental, do not use. */
+
+int
+Collapse_Chunk(struct disk *, struct chunk *);
+/* Experimental, do not use. */
+
+int
+Create_Chunk(struct disk *, daddr_t, daddr_t, chunk_e, int, u_long, const char *);
+/* Create a chunk with the specified paramters */
+
+void
+All_FreeBSD(struct disk *, int);
+/*
+ * Make one FreeBSD chunk covering the entire disk;
+ * if force_all is set, bypass all BIOS geometry
+ * considerations.
+ */
+
+char *
+CheckRules(const struct disk *);
+/* Return char* to warnings about broken design rules in this disklayout */
+
+char **
+Disk_Names(void);
+/*
+ * Return char** with all disk's names (wd0, wd1 ...). You must free
+ * each pointer, as well as the array by hand
+ */
+
+#ifdef PC98
+void
+Set_Boot_Mgr(struct disk *, const u_char *, const size_t, const u_char *,
+ const size_t);
+#else
+void
+Set_Boot_Mgr(struct disk *, const u_char *, const size_t);
+#endif
+/*
+ * Use this boot-manager on this disk. Gets written when Write_Disk()
+ * is called
+ */
+
+int
+Set_Boot_Blocks(struct disk *, const u_char *, const u_char *);
+/*
+ * Use these boot-blocks on this disk. Gets written when Write_Disk()
+ * is called. Returns nonzero upon failure.
+ */
+
+int
+Write_Disk(const struct disk *);
+/* Write all the MBRs, disklabels, bootblocks and boot managers */
+
+daddr_t
+Next_Cyl_Aligned(const struct disk *, daddr_t);
+/* Round offset up to next cylinder according to the bios-geometry */
+
+daddr_t
+Prev_Cyl_Aligned(const struct disk *, daddr_t);
+/* Round offset down to previous cylinder according to the bios-geometry */
+
+int
+Track_Aligned(const struct disk *, daddr_t);
+/* Check if offset is aligned on a track according to the bios geometry */
+
+daddr_t
+Next_Track_Aligned(const struct disk *, daddr_t);
+/* Round offset up to next track according to the bios-geometry */
+
+daddr_t
+Prev_Track_Aligned(const struct disk *, daddr_t);
+/* Check if offset is aligned on a track according to the bios geometry */
+
+struct chunk *
+Create_Chunk_DWIM(struct disk *, struct chunk *, daddr_t, chunk_e, int,
+ u_long);
+/*
+ * This one creates a partition inside the given parent of the given
+ * size, and returns a pointer to it. The first unused chunk big
+ * enough is used.
+ */
+
+char *
+ShowChunkFlags(struct chunk *);
+/* Return string to show flags. */
+
+/*
+ * Implementation details >>> DO NOT USE <<<
+ */
+
+struct disklabel;
+
+void Fill_Disklabel(struct disklabel *, const struct disk *,
+ const struct chunk *);
+void Debug_Chunk(struct chunk *);
+struct chunk *New_Chunk(void);
+void Free_Chunk(struct chunk *);
+struct chunk *Clone_Chunk(const struct chunk *);
+int Add_Chunk(struct disk *, daddr_t, daddr_t, const char *, chunk_e, int,
+ u_long, const char *);
+void *read_block(int, daddr_t, u_long);
+int write_block(int, daddr_t, const void *, u_long);
+struct disklabel *read_disklabel(int, daddr_t, u_long);
+struct disk *Int_Open_Disk(const char *, char *);
+int Fixup_Names(struct disk *);
+int MakeDevChunk(const struct chunk *, const char *);
+__END_DECLS
+
+#define dprintf printf
+
+/* TODO
+ *
+ * Need an error string mechanism from the functions instead of warn()
+ *
+ * Make sure only FreeBSD start at offset==0
+ *
+ * Collapse must align.
+ *
+ * Make Write_Disk(struct disk*)
+ *
+ * Consider booting from OnTrack'ed disks.
+ *
+ * Get Bios-geom, ST506 & OnTrack from driver (or otherwise)
+ *
+ * Make Create_DWIM().
+ *
+ * Make Is_Unchanged(struct disk *d1, struct chunk *c1)
+ *
+ * don't rename slices unless we have to
+ *
+ *Sample output from tst01:
+ *
+ * Debug_Disk(wd0) flags=0 bios_geom=0/0/0
+ * >> 0x3d040 0 1411200 1411199 wd0 0 whole 0 0
+ * >>>> 0x3d080 0 960120 960119 wd0s1 3 freebsd 0 8
+ * >>>>>> 0x3d100 0 40960 40959 wd0s1a 5 part 0 0
+ * >>>>>> 0x3d180 40960 131072 172031 wd0s1b 5 part 0 0
+ * >>>>>> 0x3d1c0 172032 409600 581631 wd0s1e 5 part 0 0
+ * >>>>>> 0x3d200 581632 378488 960119 wd0s1f 5 part 0 0
+ * >>>> 0x3d140 960120 5670 965789 wd0s2 4 extended 0 8
+ * >>>>>> 0x3d2c0 960120 63 960182 - 6 unused 0 0
+ * >>>>>> 0x3d0c0 960183 5607 965789 wd0s5 2 fat 0 8
+ * >>>> 0x3d280 965790 1890 967679 wd0s3 1 foo -2 8
+ * >>>> 0x3d300 967680 443520 1411199 wd0s4 3 freebsd 0 8
+ * >>>>>> 0x3d340 967680 443520 1411199 wd0s4a 5 part 0 0
+ *
+ * ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
+ * level chunkptr start size end name type subtype flags
+ *
+ * Underlying data structure:
+ *
+ * Legend:
+ * <struct chunk> --> part
+ * |
+ * v next
+ *
+ * <wd0> --> <wd0s1> --> <wd0s1a>
+ * | |
+ * | v
+ * | <wd0s1b>
+ * | |
+ * | v
+ * | <wd0s1e>
+ * | |
+ * | v
+ * | <wd0s1f>
+ * |
+ * v
+ * <wd0s2> --> <unused>
+ * | |
+ * | v
+ * | <wd0s5>
+ * |
+ * v
+ * <wd0s3>
+ * |
+ * v
+ * <wd0s4> --> <wd0s4a>
+ *
+ *
+ */
diff --git a/lib/libdisk/open_disk.c b/lib/libdisk/open_disk.c
new file mode 100644
index 0000000..7450652
--- /dev/null
+++ b/lib/libdisk/open_disk.c
@@ -0,0 +1,280 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <inttypes.h>
+#include <err.h>
+#include <sys/sysctl.h>
+#include <sys/stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/disklabel.h>
+#include <sys/gpt.h>
+#include <paths.h>
+#include "libdisk.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include <assert.h>
+
+#ifdef DEBUG
+#define DPRINT(x) warn x
+#define DPRINTX(x) warnx x
+#else
+#define DPRINT(x)
+#define DPRINTX(x)
+#endif
+
+struct disk *
+Int_Open_Disk(const char *name, char *conftxt)
+{
+ struct disk *d;
+ int i;
+ char *p, *q, *r, *a, *b, *n, *t, *sn;
+ daddr_t o, len, off;
+ u_int l, s, ty, sc, hd, alt;
+ daddr_t lo[10];
+
+ for (p = conftxt; p != NULL && *p; p = strchr(p, '\n')) {
+ if (*p == '\n')
+ p++;
+ a = strsep(&p, " ");
+ if (strcmp(a, "0"))
+ continue;
+
+ a = strsep(&p, " ");
+ if (strcmp(a, "DISK"))
+ continue;
+
+ a = strsep(&p, " ");
+ if (strcmp(a, name))
+ continue;
+ break;
+ }
+
+ q = strchr(p, '\n');
+ if (q != NULL)
+ *q++ = '\0';
+
+ d = (struct disk *)calloc(sizeof *d, 1);
+ if(d == NULL)
+ return NULL;
+
+ d->name = strdup(name);
+
+ a = strsep(&p, " "); /* length in bytes */
+ len = strtoimax(a, &r, 0);
+ if (*r) {
+ printf("BARF %d <%d>\n", __LINE__, *r);
+ exit (0);
+ }
+
+ a = strsep(&p, " "); /* sectorsize */
+ s = strtoul(a, &r, 0);
+ if (*r) {
+ printf("BARF %d <%d>\n", __LINE__, *r);
+ exit (0);
+ }
+
+ if (s == 0)
+ return (NULL);
+ d->sector_size = s;
+ len /= s; /* media size in number of sectors. */
+
+ if (Add_Chunk(d, 0, len, name, whole, 0, 0, "-")) {
+ DPRINT(("Failed to add 'whole' chunk"));
+ }
+
+ for (;;) {
+ a = strsep(&p, " ");
+ if (a == NULL)
+ break;
+ b = strsep(&p, " ");
+ o = strtoimax(b, &r, 0);
+ if (*r) {
+ printf("BARF %d <%d>\n", __LINE__, *r);
+ exit (0);
+ }
+ if (!strcmp(a, "hd"))
+ d->bios_hd = o;
+ else if (!strcmp(a, "sc"))
+ d->bios_sect = o;
+ else
+ printf("HUH ? <%s> <%s>\n", a, b);
+ }
+
+ /*
+ * Calculate the number of cylinders this disk must have. If we have
+ * an obvious insanity, we set the number of cylinders to zero.
+ */
+ o = d->bios_hd * d->bios_sect;
+ d->bios_cyl = (o != 0) ? len / o : 0;
+
+ p = q;
+ lo[0] = 0;
+
+ for (; p != NULL && *p; p = q) {
+ sn = NULL;
+ q = strchr(p, '\n');
+ if (q != NULL)
+ *q++ = '\0';
+ a = strsep(&p, " "); /* Index */
+ if (!strcmp(a, "0"))
+ break;
+ l = strtoimax(a, &r, 0);
+ if (*r) {
+ printf("BARF %d <%d>\n", __LINE__, *r);
+ exit (0);
+ }
+ t = strsep(&p, " "); /* Type {SUN, BSD, MBR, PC98, GPT} */
+ n = strsep(&p, " "); /* name */
+ a = strsep(&p, " "); /* len */
+ len = strtoimax(a, &r, 0);
+ if (*r) {
+ printf("BARF %d <%d>\n", __LINE__, *r);
+ exit (0);
+ }
+ a = strsep(&p, " "); /* secsize */
+ s = strtoimax(a, &r, 0);
+ if (*r) {
+ printf("BARF %d <%d>\n", __LINE__, *r);
+ exit (0);
+ }
+ for (;;) {
+ a = strsep(&p, " ");
+ if (a == NULL)
+ break;
+ /* XXX: Slice name may include a space. */
+ if (!strcmp(a, "sn")) {
+ sn = p;
+ break;
+ }
+ b = strsep(&p, " ");
+ o = strtoimax(b, &r, 0);
+ /* APPLE have ty as a string */
+ if ((*r) && (strcmp(t, "APPLE") && strcmp(t, "GPT"))) {
+ printf("BARF %d <%d>\n", __LINE__, *r);
+ exit (0);
+ }
+ if (!strcmp(a, "o"))
+ off = o;
+ else if (!strcmp(a, "i"))
+ i = o;
+ else if (!strcmp(a, "ty"))
+ ty = o;
+ else if (!strcmp(a, "sc"))
+ sc = o;
+ else if (!strcmp(a, "hd"))
+ hd = o;
+ else if (!strcmp(a, "alt"))
+ alt = o;
+ }
+
+ /* PLATFORM POLICY BEGIN ----------------------------------- */
+ if (platform == p_sparc64 && !strcmp(t, "SUN") && i == 2)
+ continue;
+ if (platform == p_sparc64 && !strcmp(t, "SUN") &&
+ d->chunks->part->part == NULL) {
+ d->bios_hd = hd;
+ d->bios_sect = sc;
+ o = d->chunks->size / (hd * sc);
+ o *= (hd * sc);
+ o -= alt * hd * sc;
+ if (Add_Chunk(d, 0, o, name, freebsd, 0, 0, "-")) {
+ DPRINT(("Failed to add 'freebsd' chunk"));
+ }
+ }
+ if (platform == p_alpha && !strcmp(t, "BSD") &&
+ d->chunks->part->part == NULL) {
+ if (Add_Chunk(d, 0, d->chunks->size, name, freebsd,
+ 0, 0, "-")) {
+ DPRINT(("Failed to add 'freebsd' chunk"));
+ }
+ }
+ if (!strcmp(t, "BSD") && i == RAW_PART)
+ continue;
+ /* PLATFORM POLICY END ------------------------------------- */
+
+ off /= s;
+ len /= s;
+ off += lo[l - 1];
+ lo[l] = off;
+ if (!strcmp(t, "SUN"))
+ i = Add_Chunk(d, off, len, n, part, 0, 0, 0);
+ else if (!strncmp(t, "MBR", 3)) {
+ switch (ty) {
+ case 0xa5:
+ i = Add_Chunk(d, off, len, n, freebsd, ty, 0, 0);
+ break;
+ case 0x01:
+ case 0x04:
+ case 0x06:
+ case 0x0b:
+ case 0x0c:
+ case 0x0e:
+ i = Add_Chunk(d, off, len, n, fat, ty, 0, 0);
+ break;
+ case 0xef: /* EFI */
+ i = Add_Chunk(d, off, len, n, efi, ty, 0, 0);
+ break;
+ default:
+ i = Add_Chunk(d, off, len, n, mbr, ty, 0, 0);
+ break;
+ }
+ } else if (!strcmp(t, "BSD"))
+ i = Add_Chunk(d, off, len, n, part, ty, 0, 0);
+ else if (!strcmp(t, "PC98")) {
+ switch (ty & 0x7f) {
+ case 0x14:
+ i = Add_Chunk(d, off, len, n, freebsd, ty, 0,
+ sn);
+ break;
+ case 0x20:
+ case 0x21:
+ case 0x22:
+ case 0x23:
+ case 0x24:
+ i = Add_Chunk(d, off, len, n, fat, ty, 0, sn);
+ break;
+ default:
+ i = Add_Chunk(d, off, len, n, pc98, ty, 0, sn);
+ break;
+ }
+ } else if (!strcmp(t, "GPT"))
+ i = Add_Chunk(d, off, len, n, gpt, 0, 0, b);
+ else if (!strcmp(t, "APPLE"))
+ i = Add_Chunk(d, off, len, n, apple, 0, 0, sn);
+ else
+ ; /* Ignore unknown classes. */
+ }
+ /* PLATFORM POLICY BEGIN ------------------------------------- */
+ /* We have a chance to do things on a blank disk here */
+ if (platform == p_sparc64 && d->chunks->part->part == NULL) {
+ hd = d->bios_hd;
+ sc = d->bios_sect;
+ o = d->chunks->size / (hd * sc);
+ o *= (hd * sc);
+ o -= 2 * hd * sc;
+ if (Add_Chunk(d, 0, o, name, freebsd, 0, 0, "-")) {
+ DPRINT(("Failed to add 'freebsd' chunk"));
+ }
+ }
+ /* PLATFORM POLICY END --------------------------------------- */
+
+ return (d);
+ i = 0;
+}
diff --git a/lib/libdisk/open_ia64_disk.c b/lib/libdisk/open_ia64_disk.c
new file mode 100644
index 0000000..8fc9f64
--- /dev/null
+++ b/lib/libdisk/open_ia64_disk.c
@@ -0,0 +1,273 @@
+/*
+ * 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/disklabel.h>
+#include <sys/diskmbr.h>
+#include <sys/gpt.h>
+#include <sys/uuid.h>
+
+#include <fcntl.h>
+#include <inttypes.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <uuid.h>
+
+#include "libdisk.h"
+
+static uuid_t _efi = GPT_ENT_TYPE_EFI;
+static uuid_t _mbr = GPT_ENT_TYPE_MBR;
+static uuid_t _fbsd = GPT_ENT_TYPE_FREEBSD;
+static uuid_t _swap = GPT_ENT_TYPE_FREEBSD_SWAP;
+static uuid_t _ufs = GPT_ENT_TYPE_FREEBSD_UFS;
+
+static struct disk *
+parse_disk(char *conftxt, const char *name)
+{
+ char devname[64];
+ struct disk *disk;
+ struct dos_partition *part;
+ struct gpt_hdr *gpt;
+ char *buffer, *p, *q;
+ int fd, i;
+
+ disk = (struct disk *)calloc(sizeof *disk, 1);
+ if (disk == NULL)
+ return (NULL);
+
+ disk->name = strdup(name);
+ p = strsep(&conftxt, " "); /* media size */
+ disk->media_size = strtoimax(p, &q, 0);
+ if (*q)
+ goto fail;
+
+ p = strsep(&conftxt, " "); /* sector size */
+ disk->sector_size = strtoul(p, &q, 0);
+ if (*q)
+ goto fail;
+
+ if (disk->sector_size == 0)
+ disk->sector_size = 512;
+
+ if (disk->media_size % disk->sector_size)
+ goto fail;
+
+ /*
+ * We need to read the disk to get GPT specific information.
+ */
+
+ snprintf(devname, sizeof(devname), "%s%s", _PATH_DEV, name);
+ fd = open(devname, O_RDONLY);
+ if (fd == -1)
+ goto fail;
+ buffer = malloc(2 * disk->sector_size);
+ if (buffer == NULL) {
+ close (fd);
+ goto fail;
+ }
+ if (read(fd, buffer, 2 * disk->sector_size) == -1) {
+ free(buffer);
+ close(fd);
+ goto fail;
+ }
+ close(fd);
+
+ gpt = (struct gpt_hdr *)(buffer + disk->sector_size);
+ if (memcmp(gpt->hdr_sig, GPT_HDR_SIG, sizeof(gpt->hdr_sig))) {
+ /*
+ * No GPT present. Check if the MBR is empty (if present)
+ * or is a PMBR before declaring this disk as empty. If
+ * the MBR isn't empty, bail out. Let's not risk nuking a
+ * disk.
+ */
+ if (*(u_short *)(buffer + DOSMAGICOFFSET) == DOSMAGIC) {
+ for (i = 0; i < 4; i++) {
+ part = (struct dos_partition *)
+ (buffer + DOSPARTOFF + i * DOSPARTSIZE);
+ if (part->dp_typ != 0 &&
+ part->dp_typ != DOSPTYP_PMBR)
+ break;
+ }
+ if (i < 4) {
+ free(buffer);
+ goto fail;
+ }
+ }
+ disk->gpt_size = 128;
+ disk->lba_start = (disk->gpt_size * sizeof(struct gpt_ent)) /
+ disk->sector_size + 2;
+ disk->lba_end = (disk->media_size / disk->sector_size) -
+ disk->lba_start;
+ } else {
+ disk->lba_start = gpt->hdr_lba_start;
+ disk->lba_end = gpt->hdr_lba_end;
+ disk->gpt_size = gpt->hdr_entries;
+ }
+ free(buffer);
+ Add_Chunk(disk, disk->lba_start, disk->lba_end - disk->lba_start + 1,
+ name, whole, 0, 0, "-");
+ return (disk);
+
+fail:
+ free(disk->name);
+ free(disk);
+ return (NULL);
+}
+
+struct disk *
+Int_Open_Disk(const char *name, char *conftxt)
+{
+ struct chunk chunk;
+ uuid_t uuid;
+ struct disk *disk;
+ char *p, *q, *r, *s, *sd, *type;
+ u_long i;
+ uint32_t status;
+
+ p = conftxt;
+ while (p != NULL && *p != 0) {
+ q = strsep(&p, " ");
+ if (strcmp(q, "0") == 0) {
+ q = strsep(&p, " ");
+ if (strcmp(q, "DISK") == 0) {
+ q = strsep(&p, " ");
+ if (strcmp(q, name) == 0)
+ break;
+ }
+ }
+ p = strchr(p, '\n');
+ if (p != NULL && *p == '\n')
+ p++;
+ conftxt = p;
+ }
+ if (p == NULL || *p == 0)
+ return (NULL);
+
+ conftxt = strchr(p, '\n');
+ if (conftxt != NULL)
+ *conftxt++ = '\0';
+
+ disk = parse_disk(p, name);
+ if (disk == NULL)
+ return (NULL);
+
+ while (conftxt != NULL && *conftxt != 0) {
+ p = conftxt;
+ conftxt = strchr(p, '\n');
+ if (conftxt != NULL)
+ *conftxt++ = '\0';
+
+ sd = strsep(&p, " "); /* depth */
+ if (strcmp(sd, "0") == 0)
+ break;
+
+ type = strsep(&p, " "); /* type */
+ chunk.name = strsep(&p, " "); /* name */
+ q = strsep(&p, " "); /* length */
+ i = strtoimax(q, &r, 0);
+ if (*r)
+ abort();
+ chunk.end = i / disk->sector_size;
+ q = strsep(&p, " "); /* sector size */
+
+ for (;;) {
+ q = strsep(&p, " ");
+ if (q == NULL)
+ break;
+ r = strsep(&p, " ");
+ i = strtoimax(r, &s, 0);
+ if (*s) {
+ uuid_from_string(r, &uuid, &status);
+ if (status != uuid_s_ok)
+ abort();
+ } else
+ status = uuid_s_invalid_string_uuid;
+ if (!strcmp(q, "o"))
+ chunk.offset = i / disk->sector_size;
+ else if (!strcmp(q, "i"))
+ chunk.flags = CHUNK_ITOF(i) | CHUNK_HAS_INDEX;
+ else if (!strcmp(q, "ty"))
+ chunk.subtype = i;
+ }
+
+ if (strncmp(type, "MBR", 3) == 0) {
+ switch (chunk.subtype) {
+ case 0xa5:
+ chunk.type = freebsd;
+ break;
+ case 0x01:
+ case 0x04:
+ case 0x06:
+ case 0x0b:
+ case 0x0c:
+ case 0x0e:
+ chunk.type = fat;
+ break;
+ case 0xef: /* EFI */
+ chunk.type = efi;
+ break;
+ default:
+ chunk.type = mbr;
+ break;
+ }
+ } else if (strcmp(type, "BSD") == 0) {
+ chunk.type = part;
+ } else if (strcmp(type, "GPT") == 0) {
+ chunk.subtype = 0;
+ if (status != uuid_s_ok)
+ abort();
+ if (uuid_is_nil(&uuid, NULL))
+ chunk.type = unused;
+ else if (uuid_equal(&uuid, &_efi, NULL))
+ chunk.type = efi;
+ else if (uuid_equal(&uuid, &_mbr, NULL))
+ chunk.type = mbr;
+ else if (uuid_equal(&uuid, &_fbsd, NULL)) {
+ chunk.type = freebsd;
+ chunk.subtype = 0xa5;
+ } else if (uuid_equal(&uuid, &_swap, NULL)) {
+ chunk.type = part;
+ chunk.subtype = FS_SWAP;
+ } else if (uuid_equal(&uuid, &_ufs, NULL)) {
+ chunk.type = part;
+ chunk.subtype = FS_BSDFFS;
+ } else
+ chunk.type = part;
+ } else
+ abort();
+
+ Add_Chunk(disk, chunk.offset, chunk.end, chunk.name,
+ chunk.type, chunk.subtype, chunk.flags, 0);
+ }
+
+ return (disk);
+}
diff --git a/lib/libdisk/rules.c b/lib/libdisk/rules.c
new file mode 100644
index 0000000..1f12f4c
--- /dev/null
+++ b/lib/libdisk/rules.c
@@ -0,0 +1,296 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "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/stdint.h>
+#include <sys/disklabel.h>
+#ifdef PC98
+#include <sys/diskpc98.h>
+#else
+#include <sys/diskmbr.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include "libdisk.h"
+
+int
+Track_Aligned(const struct disk *d, daddr_t offset)
+{
+#ifndef __ia64__
+ if (!d->bios_sect)
+ return 1;
+ if (offset % d->bios_sect)
+ return 0;
+#endif /* __ia64__ */
+ return 1;
+}
+
+daddr_t
+Prev_Track_Aligned(const struct disk *d, daddr_t offset)
+{
+#ifndef __ia64__
+ if (!d->bios_sect)
+ return offset;
+ return (offset / d->bios_sect) * d->bios_sect;
+#else
+ return 1;
+#endif
+}
+
+daddr_t
+Next_Track_Aligned(const struct disk *d, daddr_t offset)
+{
+#ifndef __ia64__
+ if (!d->bios_sect)
+ return offset;
+ return Prev_Track_Aligned(d, offset + d->bios_sect-1);
+#else
+ return 1;
+#endif
+}
+
+static int
+Cyl_Aligned(const struct disk *d, daddr_t offset)
+{
+#ifndef __ia64__
+ if (!d->bios_sect || !d->bios_hd)
+ return 1;
+ if (offset % (d->bios_sect * d->bios_hd))
+ return 0;
+#endif
+ return 1;
+}
+
+daddr_t
+Prev_Cyl_Aligned(const struct disk *d, daddr_t offset)
+{
+#ifndef __ia64__
+ if (!d->bios_sect || !d->bios_hd)
+ return offset;
+ return (offset / (d->bios_sect * d->bios_hd)) * d->bios_sect *
+ d->bios_hd;
+#else
+ return 1;
+#endif
+}
+
+daddr_t
+Next_Cyl_Aligned(const struct disk *d, daddr_t offset)
+{
+#ifndef __ia64__
+ if (!d->bios_sect || !d->bios_hd)
+ return offset;
+ return Prev_Cyl_Aligned(d,offset + (d->bios_sect * d->bios_hd) - 1);
+#else
+ return 1;
+#endif
+}
+
+/*
+ * Rule#0:
+ * Chunks of type 'whole' can have max NDOSPART children.
+ * Only one of them can have the "active" flag
+ */
+static void
+Rule_000(__unused const struct disk *d, const struct chunk *c, char *msg)
+{
+#ifdef PC98
+ int i = 0;
+#else
+ int i = 0, j = 0;
+#endif
+ struct chunk *c1;
+
+ if (c->type != whole)
+ return;
+ for (c1 = c->part; c1; c1 = c1->next) {
+ if (c1->type != unused)
+ continue;
+#ifndef PC98
+ if (c1->flags & CHUNK_ACTIVE)
+ j++;
+#endif
+ i++;
+ }
+ if (i > NDOSPART)
+ sprintf(msg + strlen(msg),
+ "%d is too many children of the 'whole' chunk."
+ " Max is %d\n", i, NDOSPART);
+#ifndef PC98
+ if (j > 1)
+ sprintf(msg + strlen(msg),
+ "Too many active children of 'whole'");
+#endif
+}
+
+/*
+ * Rule#1:
+ * All children of 'whole' and 'extended' must be track-aligned.
+ * Exception: the end can be unaligned if it matches the end of 'whole'
+ */
+static void
+Rule_001(const struct disk *d, const struct chunk *c, char *msg)
+{
+ struct chunk *c1;
+
+ if (c->type != whole && c->type != extended)
+ return;
+ for (c1 = c->part; c1; c1 = c1->next) {
+ if (c1->type == unused)
+ continue;
+ c1->flags |= CHUNK_ALIGN;
+#ifdef PC98
+ if (!Cyl_Aligned(d, c1->offset))
+#else
+ if (!Track_Aligned(d, c1->offset))
+#endif
+ sprintf(msg + strlen(msg),
+#ifdef PC98
+ "chunk '%s' [%jd..%jd] does not start"
+ " on a cylinder boundary\n",
+#else
+ "chunk '%s' [%jd..%jd] does not start"
+ " on a track boundary\n",
+#endif
+ c1->name, (intmax_t)c1->offset, (intmax_t)c1->end);
+ if ((c->type == whole || c->end == c1->end)
+ || Cyl_Aligned(d, c1->end + 1))
+ ;
+ else
+ sprintf(msg + strlen(msg),
+ "chunk '%s' [%jd..%jd] does not end"
+ " on a cylinder boundary\n",
+ c1->name, (intmax_t)c1->offset, (intmax_t)c1->end);
+ }
+}
+
+/*
+ * Rule#2:
+ * Max one 'fat' as child of 'whole'
+ */
+static void
+Rule_002(__unused const struct disk *d, const struct chunk *c, char *msg)
+{
+ int i;
+ struct chunk *c1;
+
+ if (c->type != whole)
+ return;
+ for (i = 0, c1 = c->part; c1; c1 = c1->next) {
+ if (c1->type != fat)
+ continue;
+ i++;
+ }
+ if (i > 1) {
+ sprintf(msg + strlen(msg),
+ "Max one 'fat' allowed as child of 'whole'\n");
+ }
+}
+
+/*
+ * Rule#3:
+ * Max one extended as child of 'whole'
+ */
+static void
+Rule_003(__unused const struct disk *d, const struct chunk *c, char *msg)
+{
+ int i;
+ struct chunk *c1;
+
+ if (c->type != whole)
+ return;
+ for (i = 0, c1 = c->part; c1; c1 = c1->next) {
+ if (c1->type != extended)
+ continue;
+ i++;
+ }
+ if (i > 1) {
+ sprintf(msg + strlen(msg),
+ "Max one 'extended' allowed as child of 'whole'\n");
+ }
+}
+
+/*
+ * Rule#4:
+ * Max seven 'part' as children of 'freebsd'
+ * Max one CHUNK_IS_ROOT child per 'freebsd'
+ */
+static void
+Rule_004(__unused const struct disk *d, const struct chunk *c, char *msg)
+{
+ int i = 0, k = 0;
+ struct chunk *c1;
+
+ if (c->type != freebsd)
+ return;
+
+ for (c1 = c->part; c1; c1 = c1->next) {
+ if (c1->type != part)
+ continue;
+ if (c1->flags & CHUNK_IS_ROOT)
+ k++;
+ i++;
+ }
+ if (i > 7) {
+ sprintf(msg + strlen(msg),
+ "Max seven partitions per freebsd slice\n");
+ }
+ if (k > 1) {
+ sprintf(msg + strlen(msg),
+ "Max one root partition child per freebsd slice\n");
+ }
+}
+
+static void
+Check_Chunk(const struct disk *d, const struct chunk *c, char *msg)
+{
+
+ switch (platform) {
+ case p_i386:
+ case p_amd64:
+ Rule_000(d, c, msg);
+ Rule_001(d, c, msg);
+ Rule_002(d, c, msg);
+ Rule_003(d, c, msg);
+ Rule_004(d, c, msg);
+ if (c->part)
+ Check_Chunk(d, c->part, msg);
+ if (c->next)
+ Check_Chunk(d, c->next, msg);
+ break;
+ case p_pc98:
+ Rule_000(d, c, msg);
+ Rule_001(d, c, msg);
+ Rule_004(d, c, msg);
+ if (c->part)
+ Check_Chunk(d, c->part, msg);
+ if (c->next)
+ Check_Chunk(d, c->next, msg);
+ break;
+ default:
+ break;
+ }
+}
+
+char *
+CheckRules(const struct disk *d)
+{
+ char msg[BUFSIZ];
+
+ *msg = '\0';
+ Check_Chunk(d, d->chunks, msg);
+ if (*msg)
+ return strdup(msg);
+ return 0;
+}
diff --git a/lib/libdisk/tst01.c b/lib/libdisk/tst01.c
new file mode 100644
index 0000000..7bb7579
--- /dev/null
+++ b/lib/libdisk/tst01.c
@@ -0,0 +1,323 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <err.h>
+#ifdef READLINE
+#include <readline/readline.h>
+#include <readline/history.h>
+#endif
+#include <sys/types.h>
+#include <paths.h>
+#include "libdisk.h"
+
+#ifndef PC98
+u_char mbrboot[] = {
+250,51,192,142,208,188,0,124,139,244,80,7,80,31,251,252,191,0,6,185,0,1,
+242,165,234,29,6,0,0,190,190,7,179,4,128,60,128,116,14,128,60,0,117,28,
+131,198,16,254,203,117,239,205,24,139,20,139,76,2,139,238,131,198,16,254,
+203,116,26,128,60,0,116,244,190,139,6,172,60,0,116,11,86,187,7,0,180,14,
+205,16,94,235,240,235,254,191,5,0,187,0,124,184,1,2,87,205,19,95,115,12,
+51,192,205,19,79,117,237,190,163,6,235,211,190,194,6,191,254,125,129,61,
+85,170,117,199,139,245,234,0,124,0,0,73,110,118,97,108,105,100,32,112,97,
+114,116,105,116,105,111,110,32,116,97,98,108,101,0,69,114,114,111,114,32,
+108,111,97,100,105,110,103,32,111,112,101,114,97,116,105,110,103,32,115,
+121,115,116,101,109,0,77,105,115,115,105,110,103,32,111,112,101,114,97,
+116,105,110,103,32,115,121,115,116,101,109,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,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,128,
+1,1,0,4,15,63,60,63,0,0,0,241,239,0,0,0,0,1,61,5,15,63,243,48,240,0,0,144,
+208,2,0,0,0,1,244,165,15,63,170,192,192,3,0,144,208,2,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,85,170
+};
+
+u_char bteasy17[] = {
+51,192,142,192,142,216,142,208,188,0,124,252,139,244,191,0,6,185,0,1,242,
+165,234,96,6,0,0,139,213,88,162,72,7,60,53,116,28,180,16,246,228,5,174,
+4,150,246,68,4,255,116,62,198,4,128,232,218,0,138,116,1,139,76,2,235,8,
+232,207,0,185,1,0,50,209,187,0,124,184,1,2,205,19,114,30,129,191,254,1,
+85,170,117,22,234,0,124,0,0,128,250,129,116,2,178,128,139,234,66,128,242,
+179,136,22,58,7,191,190,7,185,4,0,198,6,45,7,49,50,246,136,45,138,69,4,
+60,0,116,35,60,5,116,31,254,198,190,42,7,232,113,0,190,72,7,70,70,139,28,
+10,255,116,5,50,125,4,117,243,141,183,114,7,232,90,0,131,199,16,254,6,45,
+7,226,203,128,62,117,4,2,116,11,190,59,7,10,246,117,10,205,24,235,172,190,
+42,7,232,57,0,232,54,0,50,228,205,26,139,218,131,195,96,180,1,205,22,180,
+0,117,11,205,26,59,211,114,242,160,72,7,235,10,205,22,138,196,60,28,116,
+243,4,246,60,49,114,214,60,53,119,210,80,190,40,7,187,27,6,83,252,172,80,
+36,127,180,14,205,16,88,168,128,116,242,195,86,184,1,3,187,0,6,185,1,0,
+50,246,205,19,94,198,6,72,7,63,195,13,138,13,10,70,48,32,46,32,46,32,46,
+160,100,105,115,107,32,49,13,10,10,68,101,102,97,117,108,116,58,32,70,63,
+160,0,1,0,4,0,6,3,7,7,10,10,99,14,100,14,101,20,128,20,129,25,130,30,147,
+36,165,39,159,43,117,47,82,47,219,50,64,55,242,61,0,100,111,243,72,80,70,
+211,79,115,178,85,110,105,248,78,111,118,101,108,236,77,105,110,105,248,
+76,105,110,117,248,65,109,111,101,98,225,66,83,196,66,83,68,233,80,67,73,
+216,67,80,205,86,101,110,105,248,68,111,115,115,101,227,63,191,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,85,170
+};
+#endif
+
+int
+scan_block(int fd, daddr_t block)
+{
+ u_char foo[512];
+
+ if (-1 == lseek(fd, (off_t)block * 512, SEEK_SET))
+ err(1, "lseek");
+ if (512 != read(fd, foo, 512))
+ return 1;
+ return 0;
+}
+
+void
+Scan_Disk(struct disk *d)
+{
+ char device[64];
+ u_long l;
+ int i, j, fd;
+
+ strcpy(device, _PATH_DEV);
+ strcat(device, d->name);
+
+ fd = open(device, O_RDWR);
+ if (fd < 0) {
+ warn("open(%s) failed", device);
+ return;
+ }
+ for (i = -1, l = 0; ; l++) {
+ j = scan_block(fd, l);
+ if (j != i) {
+ if (i == -1) {
+ printf("%c: %lu.",j ? 'B' : 'G', l);
+ fflush(stdout);
+ } else if (i == 0) {
+ printf(".%lu\nB: %lu.", l - 1, l);
+ fflush(stdout);
+ } else {
+ printf(".%lu\nG: %lu.", l - 1, l);
+ fflush(stdout);
+ }
+ i = j;
+ }
+ }
+ close(fd);
+}
+
+int
+main(int argc, char **argv)
+{
+ struct disk *d,*db;
+ char myprompt[BUFSIZ];
+#ifndef READLINE
+ char input[BUFSIZ];
+#endif
+ char *p,*q = 0;
+ char **cp, *cmds[200];
+ int ncmd, i;
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage:\n\t%s diskname\n", argv[0]);
+ exit(1);
+ }
+ d = Open_Disk(argv[1]);
+ if (!d)
+ err(1, "Couldn't open disk %s", argv[1]);
+
+ sprintf(myprompt, "%s %s> ", argv[0], argv[1]);
+ while (1) {
+ printf("--==##==--\n");
+ p = CheckRules(d);
+ Debug_Disk(d);
+ if (p) {
+ printf("%s",p);
+ free(p);
+ }
+#ifdef READLINE
+ if (q)
+ free(q);
+ q = p = readline(myprompt);
+#else
+ printf("%s", myprompt);
+ fflush(stdout);
+ q = p = fgets(input, sizeof(input), stdin);
+#endif
+ if(!p)
+ break;
+ for (cp = cmds; (*cp = strsep(&p, " \t\n")) != NULL;)
+ if (**cp != '\0')
+ cp++;
+ ncmd = cp - cmds;
+ if (!ncmd)
+ continue;
+ if (!strcasecmp(*cmds, "quit"))
+ break;
+ if (!strcasecmp(*cmds, "exit"))
+ break;
+ if (!strcasecmp(*cmds, "q"))
+ break;
+ if (!strcasecmp(*cmds, "x"))
+ break;
+ if (!strcasecmp(*cmds, "dwim") && ncmd == 6) {
+ printf("dwim = %p\n",
+ Create_Chunk_DWIM(d,
+ (struct chunk *)strtol(cmds[1], 0, 0),
+ strtol(cmds[2], 0, 0),
+ strtol(cmds[3], 0, 0),
+ strtol(cmds[4], 0, 0),
+ strtol(cmds[5], 0, 0)));
+ continue;
+ }
+ if (!strcasecmp(*cmds, "delete") && ncmd == 2) {
+ printf("delete = %d\n",
+ Delete_Chunk(d,
+ (struct chunk *)strtol(cmds[1], 0, 0)));
+ continue;
+ }
+#ifndef __ia64__
+ if (!strcasecmp(*cmds, "allfreebsd")) {
+ All_FreeBSD(d, 0);
+ continue;
+ }
+ if (!strcasecmp(*cmds, "dedicate")) {
+ All_FreeBSD(d, 1);
+ continue;
+ }
+ if (!strcasecmp(*cmds, "sanitize")) {
+ Sanitize_Bios_Geom(d);
+ continue;
+ }
+ if (!strcasecmp(*cmds, "bios") && ncmd == 4) {
+ Set_Bios_Geom(d, strtol(cmds[1], 0, 0),
+ strtol(cmds[2], 0, 0),
+ strtol(cmds[3], 0, 0));
+ continue;
+ }
+#endif
+ if (!strcasecmp(*cmds, "list")) {
+ cp = Disk_Names();
+ printf("Disks:");
+ for (i = 0; cp[i]; i++) {
+ printf(" %s", cp[i]);
+ free(cp[i]);
+ }
+ free(cp);
+ continue;
+ }
+#ifdef PC98
+ if (!strcasecmp(*cmds, "create") && ncmd == 7) {
+#else
+ if (!strcasecmp(*cmds,"create") && ncmd == 6) {
+#endif
+
+ printf("Create=%d\n",
+ Create_Chunk(d,
+ strtol(cmds[1], 0, 0),
+ strtol(cmds[2], 0, 0),
+ strtol(cmds[3], 0, 0),
+ strtol(cmds[4], 0, 0),
+#ifdef PC98
+ strtol(cmds[5], 0, 0), cmds[6]));
+#else
+ strtol(cmds[5], 0, 0), NULL));
+#endif
+ continue;
+ }
+ if (!strcasecmp(*cmds,"read")) {
+ db = d;
+ if (ncmd > 1)
+ d = Open_Disk(cmds[1]);
+ else
+ d = Open_Disk(argv[1]);
+ if (d)
+ Free_Disk(db);
+ else
+ d = db;
+ continue;
+ }
+ if (!strcasecmp(*cmds,"scan")) {
+ Scan_Disk(d);
+ continue;
+ }
+#ifndef PC98
+ if (!strcasecmp(*cmds,"bteasy")) {
+ Set_Boot_Mgr(d, bteasy17, sizeof (bteasy17));
+ continue;
+ }
+ if (!strcasecmp(*cmds, "mbr")) {
+ Set_Boot_Mgr(d, mbrboot, sizeof (mbrboot));
+ continue;
+ }
+#endif
+#if 0 /* XXX boot1 undefined, fix me */
+ if (!strcasecmp(*cmds, "boot")) {
+ Set_Boot_Blocks(d, boot1, boot2);
+ continue;
+ }
+#endif
+ if (!strcasecmp(*cmds, "write")) {
+ printf("Write=%d\n",
+ Write_Disk(d));
+ Free_Disk(d);
+ d = Open_Disk(argv[1]);
+ continue;
+ }
+ if (strcasecmp(*cmds, "help"))
+ printf("\007ERROR\n");
+ printf("CMDS:\n");
+ printf("\tallfreebsd\n");
+ printf("\tdedicate\n");
+ printf("\tbios cyl hd sect\n");
+ printf("\tboot\n");
+#ifndef PC98
+ printf("\tbteasy17\n");
+#endif
+#if 0
+ printf("\tcollapse [pointer]\n");
+#endif
+#ifdef PC98
+ printf("\tcreate offset size enum subtype flags name\n");
+#else
+ printf("\tcreate offset size enum subtype flags\n");
+#endif
+ printf("\t\tsubtype(part): swap=1, ffs=7\n");
+ printf("\tdelete pointer\n");
+ printf("\tlist\n");
+#ifndef PC98
+ printf("\tmbr\n");
+#endif
+#if 0
+ printf("\tphys cyl hd sect\n");
+#endif
+ printf("\tquit\n");
+ printf("\tread [disk]\n");
+ printf("\tscan\n");
+ printf("\twrite\n");
+ printf("\nENUM:\n\t");
+#if 0
+ for (i = 0; chunk_n[i]; i++)
+ printf("%d = %s%s", i, chunk_n[i],
+ i == 4 ? "\n\t" : " ");
+#endif
+ printf("\n");
+
+ }
+ exit (0);
+}
diff --git a/lib/libdisk/write_alpha_disk.c b/lib/libdisk/write_alpha_disk.c
new file mode 100644
index 0000000..251282e
--- /dev/null
+++ b/lib/libdisk/write_alpha_disk.c
@@ -0,0 +1,88 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/disklabel.h>
+#include <paths.h>
+#include "libdisk.h"
+
+/*
+ * XXX: A lot of hardcoded 512s probably should be foo->sector_size;
+ * I'm not sure which, so I leave it like it worked before. --schweikh
+ */
+int
+Write_Disk(const struct disk *d1)
+{
+ u_char buf[BBSIZE];
+ char device[64];
+ struct chunk *c1;
+ struct disklabel *dl;
+ void *p;
+ uint64_t *lp, sum;
+ int fd, i;
+
+ strcpy(device, _PATH_DEV);
+ strcat(device, d1->name);
+
+ fd = open(device, O_RDWR);
+ if (fd < 0)
+ return (1);
+
+ c1 = d1->chunks->part;
+ if (!strcmp(c1->name, "X") || c1->type != freebsd) {
+ close (fd);
+ return (0);
+ }
+
+ for (i = 0; i < BBSIZE/512; i++) {
+ if (!(p = read_block(fd, i + c1->offset, 512))) {
+ close (fd);
+ return (1);
+ }
+ memcpy(buf + 512 * i, p, 512);
+ free(p);
+ }
+ if (d1->boot1)
+ memcpy(buf + 512, d1->boot1, BBSIZE - 512);
+
+ dl = (struct disklabel *)(buf + 512 * LABELSECTOR + LABELOFFSET);
+ Fill_Disklabel(dl, d1, c1);
+
+ /*
+ * Tell SRM where the bootstrap is.
+ */
+ lp = (uint64_t *)buf;
+ lp[60] = (BBSIZE - 512) / 512; /* Length */
+ lp[61] = 1; /* Start */
+ lp[62] = 0; /* Flags */
+
+ /*
+ * Generate the bootblock checksum for the SRM console.
+ */
+ sum = 0;
+ for (i = 0; i < 63; i++)
+ sum += lp[i];
+ lp[63] = sum;
+
+ for (i = 0; i < BBSIZE / 512; i++)
+ write_block(fd, i + c1->offset, buf + 512 * i, 512);
+ close(fd);
+
+ return (0);
+}
diff --git a/lib/libdisk/write_amd64_disk.c b/lib/libdisk/write_amd64_disk.c
new file mode 100644
index 0000000..9899258
--- /dev/null
+++ b/lib/libdisk/write_amd64_disk.c
@@ -0,0 +1,204 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/disklabel.h>
+#include <sys/diskmbr.h>
+#include <paths.h>
+#include "libdisk.h"
+
+/*
+ * XXX: A lot of hardcoded 512s probably should be foo->sector_size;
+ * I'm not sure which, so I leave it like it worked before. --schweikh
+ */
+static int
+Write_FreeBSD(int fd, const struct disk *new, const struct chunk *c1)
+{
+ struct disklabel *dl;
+ int i;
+ void *p;
+ u_char buf[BBSIZE];
+
+ for (i = 0; i < BBSIZE/512; i++) {
+ if (!(p = read_block(fd, i + c1->offset, 512)))
+ return (1);
+ memcpy(buf + 512 * i, p, 512);
+ free(p);
+ }
+ if (new->boot1)
+ memcpy(buf, new->boot1, 512);
+
+ if (new->boot2)
+ memcpy(buf + 512, new->boot2, BBSIZE - 512);
+
+ dl = (struct disklabel *)(buf + 512 * LABELSECTOR + LABELOFFSET);
+ Fill_Disklabel(dl, new, c1);
+
+ for (i = 0; i < BBSIZE / 512; i++)
+ write_block(fd, i + c1->offset, buf + 512 * i, 512);
+
+ return 0;
+}
+
+static void
+Write_Int32(u_int32_t *p, u_int32_t v)
+{
+ u_int8_t *bp = (u_int8_t *)p;
+
+ bp[0] = (v >> 0) & 0xff;
+ bp[1] = (v >> 8) & 0xff;
+ bp[2] = (v >> 16) & 0xff;
+ bp[3] = (v >> 24) & 0xff;
+}
+
+/*
+ * Special install-time configuration for the i386 boot0 boot manager.
+ */
+static void
+Cfg_Boot_Mgr(u_char *mbr, int edd)
+{
+
+ if (mbr[0x1b0] == 0x66 && mbr[0x1b1] == 0xbb) {
+ if (edd)
+ mbr[0x1bb] |= 0x80; /* Packet mode on */
+ else
+ mbr[0x1bb] &= 0x7f; /* Packet mode off */
+ }
+}
+
+int
+Write_Disk(const struct disk *d1)
+{
+ int fd, j;
+ uint i;
+ struct chunk *c1;
+ int ret = 0;
+ char device[64];
+ u_char *mbr;
+ struct dos_partition *dp,work[NDOSPART];
+ int s[4];
+ int need_edd = 0; /* Need EDD (packet interface) */
+
+ strcpy(device, _PATH_DEV);
+ strcat(device, d1->name);
+
+ fd = open(device, O_RDWR);
+ if (fd < 0)
+ return 1;
+
+ memset(s, 0, sizeof s);
+ if (!(mbr = read_block(fd, 0, d1->sector_size))) {
+ close (fd);
+ return (1);
+ }
+ dp = (struct dos_partition *)(mbr + DOSPARTOFF);
+ memcpy(work, dp, sizeof work);
+ dp = work;
+ free(mbr);
+ for (c1 = d1->chunks->part; c1; c1 = c1->next) {
+ if (c1->type == unused)
+ continue;
+ if (!strcmp(c1->name, "X"))
+ continue;
+ j = c1->name[strlen(d1->name) + 1] - '1';
+ if (j < 0 || j > 3)
+ continue;
+ s[j]++;
+ if (c1->type == freebsd)
+ ret += Write_FreeBSD(fd, d1, c1);
+
+ Write_Int32(&dp[j].dp_start, c1->offset);
+ Write_Int32(&dp[j].dp_size, c1->size);
+
+ i = c1->offset;
+ if (i >= 1024 * d1->bios_sect * d1->bios_hd) {
+ dp[j].dp_ssect = 0xff;
+ dp[j].dp_shd = 0xff;
+ dp[j].dp_scyl = 0xff;
+ need_edd++;
+ } else {
+ dp[j].dp_ssect = i % d1->bios_sect;
+ i -= dp[j].dp_ssect++;
+ i /= d1->bios_sect;
+ dp[j].dp_shd = i % d1->bios_hd;
+ i -= dp[j].dp_shd;
+ i /= d1->bios_hd;
+ dp[j].dp_scyl = i;
+ i -= dp[j].dp_scyl;
+ dp[j].dp_ssect |= i >> 2;
+ }
+#ifdef DEBUG
+ printf("S:%lu = (%x/%x/%x)", c1->offset,
+ dp[j].dp_scyl, dp[j].dp_shd, dp[j].dp_ssect);
+#endif
+
+ i = c1->end;
+ dp[j].dp_esect = i % d1->bios_sect;
+ i -= dp[j].dp_esect++;
+ i /= d1->bios_sect;
+ dp[j].dp_ehd = i % d1->bios_hd;
+ i -= dp[j].dp_ehd;
+ i /= d1->bios_hd;
+ if (i > 1023)
+ i = 1023;
+ dp[j].dp_ecyl = i;
+ i -= dp[j].dp_ecyl;
+ dp[j].dp_esect |= i >> 2;
+#ifdef DEBUG
+ printf(" E:%lu = (%x/%x/%x)\n", c1->end,
+ dp[j].dp_ecyl, dp[j].dp_ehd, dp[j].dp_esect);
+#endif
+
+ dp[j].dp_typ = c1->subtype;
+ if (c1->flags & CHUNK_ACTIVE)
+ dp[j].dp_flag = 0x80;
+ else
+ dp[j].dp_flag = 0;
+ }
+ j = 0;
+ for (i = 0; i < NDOSPART; i++) {
+ if (!s[i])
+ memset(dp + i, 0, sizeof *dp);
+ if (dp[i].dp_flag)
+ j++;
+ }
+ if (!j)
+ for(i = 0; i < NDOSPART; i++)
+ if (dp[i].dp_typ == 0xa5)
+ dp[i].dp_flag = 0x80;
+
+ if (!(mbr = read_block(fd, 0, d1->sector_size))) {
+ close (fd);
+ return (1);
+ }
+ if (d1->bootmgr) {
+ memcpy(mbr, d1->bootmgr, DOSPARTOFF);
+ Cfg_Boot_Mgr(mbr, need_edd);
+ }
+ memcpy(mbr + DOSPARTOFF, dp, sizeof *dp * NDOSPART);
+ mbr[512-2] = 0x55;
+ mbr[512-1] = 0xaa;
+ write_block(fd, 0, mbr, d1->sector_size);
+ if (d1->bootmgr && d1->bootmgr_size > d1->sector_size)
+ for (i = 1; i * d1->sector_size <= d1->bootmgr_size; i++)
+ write_block(fd, i, &d1->bootmgr[i * d1->sector_size],
+ d1->sector_size);
+
+ close(fd);
+ return 0;
+}
diff --git a/lib/libdisk/write_arm_disk.c b/lib/libdisk/write_arm_disk.c
new file mode 100644
index 0000000..5dbb0ad
--- /dev/null
+++ b/lib/libdisk/write_arm_disk.c
@@ -0,0 +1,47 @@
+/*-
+ * 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 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 <fcntl.h>
+#include <string.h>
+#include <err.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/disklabel.h>
+#include <paths.h>
+#include "libdisk.h"
+
+int
+Write_Disk(const struct disk *d1)
+{
+ return (0);
+}
diff --git a/lib/libdisk/write_disk.c b/lib/libdisk/write_disk.c
new file mode 100644
index 0000000..024981b
--- /dev/null
+++ b/lib/libdisk/write_disk.c
@@ -0,0 +1,76 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/disklabel.h>
+#include <paths.h>
+#include "libdisk.h"
+
+void
+Fill_Disklabel(struct disklabel *dl, const struct disk *new,
+ const struct chunk *c1)
+{
+ struct chunk *c2;
+ int j;
+
+ memset(dl, 0, sizeof *dl);
+
+ for (c2 = c1->part; c2; c2 = c2->next) {
+ if (c2->type == unused)
+ continue;
+ if (!strcmp(c2->name, "X"))
+ continue;
+ j = c2->name[strlen(c2->name) - 1] - 'a';
+ if (j < 0 || j >= MAXPARTITIONS || j == RAW_PART)
+ continue;
+ dl->d_partitions[j].p_size = c2->size;
+ dl->d_partitions[j].p_offset = c2->offset;
+ dl->d_partitions[j].p_fstype = c2->subtype;
+ }
+
+ dl->d_bbsize = BBSIZE;
+ /*
+ * Add in defaults for superblock size, interleave, and rpms
+ */
+ dl->d_sbsize = 0;
+
+ strcpy(dl->d_typename, c1->name);
+
+ dl->d_secsize = 512;
+ dl->d_secperunit = new->chunks->size;
+#ifndef __ia64__
+ dl->d_ncylinders = new->bios_cyl;
+ dl->d_ntracks = new->bios_hd;
+ dl->d_nsectors = new->bios_sect;
+#endif
+ dl->d_secpercyl = dl->d_ntracks * dl->d_nsectors;
+
+ dl->d_npartitions = MAXPARTITIONS;
+
+ dl->d_type = new->name[0] == 's' || new->name[0] == 'd' ||
+ new->name[0] == 'o' ? DTYPE_SCSI : DTYPE_ESDI;
+ dl->d_partitions[RAW_PART].p_size = c1->size;
+ dl->d_partitions[RAW_PART].p_offset = c1->offset;
+ dl->d_rpm = 3600;
+ dl->d_interleave = 1;
+
+ dl->d_magic = DISKMAGIC;
+ dl->d_magic2 = DISKMAGIC;
+ dl->d_checksum = dkcksum(dl);
+}
diff --git a/lib/libdisk/write_i386_disk.c b/lib/libdisk/write_i386_disk.c
new file mode 100644
index 0000000..15317d3
--- /dev/null
+++ b/lib/libdisk/write_i386_disk.c
@@ -0,0 +1,204 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/disklabel.h>
+#include <sys/diskmbr.h>
+#include <paths.h>
+#include "libdisk.h"
+
+/*
+ * XXX: A lot of hardcoded 512s probably should be foo->sector_size;
+ * I'm not sure which, so I leave it like it worked before. --schweikh
+ */
+static int
+Write_FreeBSD(int fd, const struct disk *new, const struct chunk *c1)
+{
+ struct disklabel *dl;
+ int i;
+ void *p;
+ u_char buf[BBSIZE];
+
+ for (i = 0; i < BBSIZE/512; i++) {
+ if (!(p = read_block(fd, i + c1->offset, 512)))
+ return (1);
+ memcpy(buf + 512 * i, p, 512);
+ free(p);
+ }
+ if (new->boot1)
+ memcpy(buf, new->boot1, 512);
+
+ if (new->boot2)
+ memcpy(buf + 512, new->boot2, BBSIZE - 512);
+
+ dl = (struct disklabel *)(buf + 512 * LABELSECTOR + LABELOFFSET);
+ Fill_Disklabel(dl, new, c1);
+
+ for (i = 0; i < BBSIZE / 512; i++)
+ write_block(fd, i + c1->offset, buf + 512 * i, 512);
+
+ return 0;
+}
+
+static void
+Write_Int32(u_int32_t *p, u_int32_t v)
+{
+ u_int8_t *bp = (u_int8_t *)p;
+
+ bp[0] = (v >> 0) & 0xff;
+ bp[1] = (v >> 8) & 0xff;
+ bp[2] = (v >> 16) & 0xff;
+ bp[3] = (v >> 24) & 0xff;
+}
+
+/*
+ * Special install-time configuration for the i386 boot0 boot manager.
+ */
+static void
+Cfg_Boot_Mgr(u_char *mbrblk, int edd)
+{
+
+ if (mbrblk[0x1b0] == 0x66 && mbrblk[0x1b1] == 0xbb) {
+ if (edd)
+ mbrblk[0x1bb] |= 0x80; /* Packet mode on */
+ else
+ mbrblk[0x1bb] &= 0x7f; /* Packet mode off */
+ }
+}
+
+int
+Write_Disk(const struct disk *d1)
+{
+ int fd, j;
+ uint i;
+ struct chunk *c1;
+ int ret = 0;
+ char device[64];
+ u_char *mbrblk;
+ struct dos_partition *dp,work[NDOSPART];
+ int s[4];
+ int need_edd = 0; /* Need EDD (packet interface) */
+
+ strcpy(device, _PATH_DEV);
+ strcat(device, d1->name);
+
+ fd = open(device, O_RDWR);
+ if (fd < 0)
+ return 1;
+
+ memset(s, 0, sizeof s);
+ if (!(mbrblk = read_block(fd, 0, d1->sector_size))) {
+ close (fd);
+ return (1);
+ }
+ dp = (struct dos_partition *)(mbrblk + DOSPARTOFF);
+ memcpy(work, dp, sizeof work);
+ dp = work;
+ free(mbrblk);
+ for (c1 = d1->chunks->part; c1; c1 = c1->next) {
+ if (c1->type == unused)
+ continue;
+ if (!strcmp(c1->name, "X"))
+ continue;
+ j = c1->name[strlen(d1->name) + 1] - '1';
+ if (j < 0 || j > 3)
+ continue;
+ s[j]++;
+ if (c1->type == freebsd)
+ ret += Write_FreeBSD(fd, d1, c1);
+
+ Write_Int32(&dp[j].dp_start, c1->offset);
+ Write_Int32(&dp[j].dp_size, c1->size);
+
+ i = c1->offset;
+ if (i >= 1024 * d1->bios_sect * d1->bios_hd) {
+ dp[j].dp_ssect = 0xff;
+ dp[j].dp_shd = 0xff;
+ dp[j].dp_scyl = 0xff;
+ need_edd++;
+ } else {
+ dp[j].dp_ssect = i % d1->bios_sect;
+ i -= dp[j].dp_ssect++;
+ i /= d1->bios_sect;
+ dp[j].dp_shd = i % d1->bios_hd;
+ i -= dp[j].dp_shd;
+ i /= d1->bios_hd;
+ dp[j].dp_scyl = i;
+ i -= dp[j].dp_scyl;
+ dp[j].dp_ssect |= i >> 2;
+ }
+#ifdef DEBUG
+ printf("S:%lu = (%x/%x/%x)", c1->offset,
+ dp[j].dp_scyl, dp[j].dp_shd, dp[j].dp_ssect);
+#endif
+
+ i = c1->end;
+ dp[j].dp_esect = i % d1->bios_sect;
+ i -= dp[j].dp_esect++;
+ i /= d1->bios_sect;
+ dp[j].dp_ehd = i % d1->bios_hd;
+ i -= dp[j].dp_ehd;
+ i /= d1->bios_hd;
+ if (i > 1023)
+ i = 1023;
+ dp[j].dp_ecyl = i;
+ i -= dp[j].dp_ecyl;
+ dp[j].dp_esect |= i >> 2;
+#ifdef DEBUG
+ printf(" E:%lu = (%x/%x/%x)\n", c1->end,
+ dp[j].dp_ecyl, dp[j].dp_ehd, dp[j].dp_esect);
+#endif
+
+ dp[j].dp_typ = c1->subtype;
+ if (c1->flags & CHUNK_ACTIVE)
+ dp[j].dp_flag = 0x80;
+ else
+ dp[j].dp_flag = 0;
+ }
+ j = 0;
+ for (i = 0; i < NDOSPART; i++) {
+ if (!s[i])
+ memset(dp + i, 0, sizeof *dp);
+ if (dp[i].dp_flag)
+ j++;
+ }
+ if (!j)
+ for(i = 0; i < NDOSPART; i++)
+ if (dp[i].dp_typ == 0xa5)
+ dp[i].dp_flag = 0x80;
+
+ if (!(mbrblk = read_block(fd, 0, d1->sector_size))) {
+ close (fd);
+ return (1);
+ }
+ if (d1->bootmgr) {
+ memcpy(mbrblk, d1->bootmgr, DOSPARTOFF);
+ Cfg_Boot_Mgr(mbrblk, need_edd);
+ }
+ memcpy(mbrblk + DOSPARTOFF, dp, sizeof *dp * NDOSPART);
+ mbrblk[512-2] = 0x55;
+ mbrblk[512-1] = 0xaa;
+ write_block(fd, 0, mbrblk, d1->sector_size);
+ if (d1->bootmgr && d1->bootmgr_size > d1->sector_size)
+ for (i = 1; i * d1->sector_size <= d1->bootmgr_size; i++)
+ write_block(fd, i, &d1->bootmgr[i * d1->sector_size],
+ d1->sector_size);
+
+ close(fd);
+ return 0;
+}
diff --git a/lib/libdisk/write_ia64_disk.c b/lib/libdisk/write_ia64_disk.c
new file mode 100644
index 0000000..0b57fdf
--- /dev/null
+++ b/lib/libdisk/write_ia64_disk.c
@@ -0,0 +1,421 @@
+/*
+ * 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.
+ *
+ * CRC32 code derived from work by Gary S. Brown.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/disklabel.h>
+#include <sys/diskmbr.h>
+#include <sys/gpt.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <uuid.h>
+
+#include "libdisk.h"
+
+static uuid_t _efi = GPT_ENT_TYPE_EFI;
+static uuid_t _fbsd = GPT_ENT_TYPE_FREEBSD;
+static uuid_t _swap = GPT_ENT_TYPE_FREEBSD_SWAP;
+static uuid_t _ufs = GPT_ENT_TYPE_FREEBSD_UFS;
+
+static uint32_t crc32_tab[] = {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
+ 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
+ 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
+ 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
+ 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
+ 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
+ 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
+ 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
+ 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
+ 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
+ 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
+ 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
+ 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
+ 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
+ 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
+ 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
+ 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
+ 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+};
+
+static uint32_t
+crc32(const void *buf, size_t size)
+{
+ const uint8_t *p;
+ uint32_t crc;
+
+ p = buf;
+ crc = ~0U;
+
+ while (size--)
+ crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
+
+ return (crc ^ ~0U);
+}
+
+static int
+write_pmbr(int fd, const struct disk *disk)
+{
+ struct dos_partition dp;
+ char *buffer;
+ u_long nsects;
+ int error;
+
+ error = 0;
+ nsects = disk->media_size / disk->sector_size;
+ buffer = calloc(disk->sector_size, 1);
+ if (buffer == NULL)
+ return (ENOMEM);
+ buffer[DOSMAGICOFFSET] = DOSMAGIC & 0xff;
+ buffer[DOSMAGICOFFSET + 1] = DOSMAGIC >> 8;
+
+ dp.dp_flag = 0;
+ dp.dp_shd = dp.dp_ssect = dp.dp_scyl = 0xff;
+ dp.dp_typ = DOSPTYP_PMBR;
+ dp.dp_ehd = dp.dp_esect = dp.dp_ecyl = 0xff;
+ dp.dp_start = 1;
+ dp.dp_size = (nsects > 0xffffffffu) ? ~0u : nsects;
+ memcpy(buffer + DOSPARTOFF, &dp, DOSPARTSIZE);
+
+ if (lseek(fd, 0L, SEEK_SET) != 0L ||
+ write(fd, buffer, disk->sector_size) != disk->sector_size)
+ error = (errno) ? errno : EAGAIN;
+
+ free(buffer);
+ return (error);
+}
+
+static int
+read_gpt(int fd, const struct disk *disk, struct gpt_hdr *hdr,
+ struct gpt_ent *tbl)
+{
+ char *buffer;
+ off_t off;
+ size_t nsects, sz;
+ int error, i;
+
+ error = 0;
+ nsects = disk->gpt_size * sizeof(struct gpt_ent) / disk->sector_size;
+ nsects++;
+ sz = nsects * disk->sector_size;
+ buffer = malloc(sz);
+ if (buffer == NULL)
+ return (ENOMEM);
+
+ if (lseek(fd, disk->sector_size, SEEK_SET) != disk->sector_size ||
+ read(fd, buffer, disk->sector_size) != disk->sector_size) {
+ error = (errno) ? errno : EAGAIN;
+ goto bail;
+ }
+ if (memcmp(buffer, GPT_HDR_SIG, sizeof(hdr->hdr_sig)) != 0) {
+ /*
+ * No GPT on disk. Create one out of thin air.
+ */
+ bzero(&hdr[0], sizeof(struct gpt_hdr));
+ memcpy(hdr[0].hdr_sig, GPT_HDR_SIG, sizeof(hdr[0].hdr_sig));
+ hdr[0].hdr_revision = GPT_HDR_REVISION;
+ hdr[0].hdr_size = offsetof(struct gpt_hdr, padding);
+ hdr[0].hdr_lba_self = 1;
+ hdr[0].hdr_lba_alt = disk->media_size / disk->sector_size - 1L;
+ hdr[0].hdr_lba_start = disk->lba_start;
+ hdr[0].hdr_lba_end = disk->lba_end;
+ uuid_create(&hdr[0].hdr_uuid, NULL);
+ hdr[0].hdr_lba_table = 2;
+ hdr[0].hdr_entries = disk->gpt_size;
+ hdr[0].hdr_entsz = sizeof(struct gpt_ent);
+ hdr[1] = hdr[0];
+ hdr[1].hdr_lba_self = hdr[0].hdr_lba_alt;
+ hdr[1].hdr_lba_alt = hdr[0].hdr_lba_self;
+ hdr[1].hdr_lba_table = disk->lba_end + 1;
+
+ for (i = 0; i < disk->gpt_size; i++) {
+ bzero(&tbl[i], sizeof(struct gpt_ent));
+ uuid_create(&tbl[i].ent_uuid, NULL);
+ }
+
+ goto bail;
+ }
+
+ /*
+ * We have a GPT on disk. Read it.
+ */
+ memcpy(&hdr[0], buffer, sizeof(struct gpt_hdr));
+ off = hdr->hdr_lba_table * disk->sector_size;
+ if (lseek(fd, off, SEEK_SET) != off ||
+ read(fd, buffer, sz) != sz) {
+ error = (errno) ? errno : EAGAIN;
+ goto bail;
+ }
+ memcpy(tbl, buffer, sizeof(struct gpt_ent) * disk->gpt_size);
+ off = hdr->hdr_lba_alt * disk->sector_size;
+ if (lseek(fd, off, SEEK_SET) != off ||
+ read(fd, buffer, disk->sector_size) != disk->sector_size) {
+ error = (errno) ? errno : EAGAIN;
+ goto bail;
+ }
+ memcpy(&hdr[1], buffer, sizeof(struct gpt_hdr));
+
+bail:
+ free(buffer);
+ return (error);
+}
+
+static int
+update_gpt(int fd, const struct disk *disk, struct gpt_hdr *hdr,
+ struct gpt_ent *tbl)
+{
+ struct gpt_ent *save;
+ char *buffer;
+ struct chunk *c;
+ off_t off;
+ size_t bufsz;
+ int error, idx, sav;
+
+ error = 0;
+
+ /*
+ * Save the entries of those chunks that have an index. They are
+ * the ones that exist on disk already.
+ */
+ sav = 0;
+ for (c = disk->chunks->part; c != NULL; c = c->next) {
+ if ((c->flags & CHUNK_HAS_INDEX))
+ sav++;
+ }
+ if (sav > 0) {
+ save = malloc(sav * sizeof(struct gpt_ent));
+ if (save == NULL)
+ abort();
+ sav = 0;
+ for (c = disk->chunks->part; c != NULL; c = c->next) {
+ if ((c->flags & CHUNK_HAS_INDEX)) {
+ idx = CHUNK_FTOI(c->flags);
+ save[sav] = tbl[idx];
+ c->flags ^= CHUNK_ITOF(idx);
+ c->flags |= CHUNK_ITOF(sav);
+ sav++;
+ }
+ }
+ } else
+ save = NULL;
+
+ /*
+ * Clear the table entries.
+ */
+ for (idx = 0; idx < disk->gpt_size; idx++) {
+ uuid_create_nil(&tbl[idx].ent_type, NULL);
+ tbl[idx].ent_lba_start = 0;
+ tbl[idx].ent_lba_end = 0;
+ tbl[idx].ent_attr = 0;
+ bzero(tbl[idx].ent_name, sizeof(tbl[idx].ent_name));
+ }
+
+ /*
+ * Repopulate the table from the chunks, possibly using saved
+ * information.
+ */
+ idx = 0;
+ for (c = disk->chunks->part; c != NULL; c = c->next) {
+ if (!(c->flags & CHUNK_HAS_INDEX)) {
+ switch (c->type) {
+ case freebsd:
+ tbl[idx].ent_type = _fbsd;
+ break;
+ case efi:
+ tbl[idx].ent_type = _efi;
+ break;
+ case part:
+ switch (c->subtype) {
+ case FS_SWAP:
+ tbl[idx].ent_type = _swap;
+ break;
+ case FS_BSDFFS:
+ tbl[idx].ent_type = _ufs;
+ break;
+ default:
+ return (EINVAL);
+ }
+ break;
+ default:
+ return (EINVAL);
+ }
+ } else {
+ sav = CHUNK_FTOI(c->flags);
+ tbl[idx].ent_type = save[sav].ent_type;
+ memcpy(tbl[idx].ent_name, save[sav].ent_name,
+ sizeof(tbl[idx].ent_name));
+ }
+ tbl[idx].ent_lba_start = c->offset;
+ tbl[idx].ent_lba_end = c->end;
+
+ idx++;
+ if (idx == disk->gpt_size)
+ return (ENOSPC);
+ }
+ if (save != NULL)
+ free(save);
+
+ hdr[0].hdr_crc_table = crc32(tbl,
+ disk->gpt_size * sizeof(struct gpt_ent));
+ hdr[0].hdr_crc_self = 0;
+ hdr[0].hdr_crc_self = crc32(&hdr[0], hdr[0].hdr_size);
+
+ hdr[1].hdr_crc_table = hdr[0].hdr_crc_table;
+ hdr[1].hdr_crc_self = 0;
+ hdr[1].hdr_crc_self = crc32(&hdr[1], hdr[1].hdr_size);
+
+ /*
+ * Write the new GPT back to the disk.
+ */
+ bufsz = disk->gpt_size * sizeof(struct gpt_ent);
+ if (bufsz == 0 || bufsz % disk->sector_size)
+ bufsz += disk->sector_size;
+ bufsz = (bufsz / disk->sector_size) * disk->sector_size;
+ buffer = calloc(1, bufsz);
+
+ memcpy(buffer, &hdr[0], sizeof(struct gpt_hdr));
+ off = hdr[0].hdr_lba_self * disk->sector_size;
+ if (lseek(fd, off, SEEK_SET) != off ||
+ write(fd, buffer, disk->sector_size) != disk->sector_size) {
+ error = (errno) ? errno : EAGAIN;
+ goto bail;
+ }
+ memcpy(buffer, &hdr[1], sizeof(struct gpt_hdr));
+ off = hdr[1].hdr_lba_self * disk->sector_size;
+ if (lseek(fd, off, SEEK_SET) != off ||
+ write(fd, buffer, disk->sector_size) != disk->sector_size) {
+ error = (errno) ? errno : EAGAIN;
+ goto bail;
+ }
+ memcpy(buffer, tbl, disk->gpt_size * sizeof(struct gpt_ent));
+ off = hdr[0].hdr_lba_table * disk->sector_size;
+ if (lseek(fd, off, SEEK_SET) != off ||
+ write(fd, buffer, bufsz) != bufsz) {
+ error = (errno) ? errno : EAGAIN;
+ goto bail;
+ }
+ off = hdr[1].hdr_lba_table * disk->sector_size;
+ if (lseek(fd, off, SEEK_SET) != off ||
+ write(fd, buffer, bufsz) != bufsz) {
+ error = (errno) ? errno : EAGAIN;
+ goto bail;
+ }
+
+bail:
+ free(buffer);
+ return (error);
+}
+
+int
+Write_Disk(const struct disk *disk)
+{
+ char devname[64];
+ struct gpt_hdr *hdr;
+ struct gpt_ent *tbl;
+ int error, fd;
+
+ hdr = malloc(sizeof(struct gpt_hdr) * 2);
+ if (hdr == NULL)
+ return (ENOMEM);
+ tbl = malloc(sizeof(struct gpt_ent) * disk->gpt_size);
+ if (tbl == NULL) {
+ free(hdr);
+ return (ENOMEM);
+ }
+
+ snprintf(devname, sizeof(devname), "%s%s", _PATH_DEV, disk->name);
+ fd = open(devname, O_RDWR);
+ if (fd == -1) {
+ free(tbl);
+ free(hdr);
+ return (errno);
+ }
+
+ /*
+ * We can always write the PMBR, because we reject disks that do not
+ * have a PMBR and are not virgin.
+ */
+ error = write_pmbr(fd, disk);
+ if (error)
+ goto bail;
+
+ /*
+ * Read the existing GPT from disk or otherwise create one out of
+ * thin air. This way we can preserve the UUIDs and the entry names
+ * when updating it.
+ */
+ error = read_gpt(fd, disk, hdr, tbl);
+ if (error)
+ goto bail;
+
+ /*
+ * Update and write the in-memory copy of the GPT.
+ */
+ error = update_gpt(fd, disk, hdr, tbl);
+
+bail:
+ close(fd);
+ free(tbl);
+ free(hdr);
+ return (error);
+}
diff --git a/lib/libdisk/write_pc98_disk.c b/lib/libdisk/write_pc98_disk.c
new file mode 100644
index 0000000..8f2a45d
--- /dev/null
+++ b/lib/libdisk/write_pc98_disk.c
@@ -0,0 +1,179 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <err.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/disklabel.h>
+#include <sys/diskpc98.h>
+#include <paths.h>
+#include "libdisk.h"
+
+/*
+ * XXX: A lot of hardcoded 512s probably should be foo->sector_size;
+ * I'm not sure which, so I leave it like it worked before. --schweikh
+ */
+static int
+Write_FreeBSD(int fd, const struct disk *new, const struct chunk *c1)
+{
+ struct disklabel *dl;
+ int i;
+ void *p;
+ u_char buf[BBSIZE];
+
+ for (i = 0; i < BBSIZE / 512; i++) {
+ if (!(p = read_block(fd, i + c1->offset, 512)))
+ return (1);
+ memcpy(buf + 512 * i, p, 512);
+ free(p);
+ }
+ if (new->boot1)
+ memcpy(buf, new->boot1, 512);
+
+ if (new->boot2)
+ memcpy(buf + 512, new->boot2, BBSIZE - 512);
+
+ dl = (struct disklabel *)(buf + 512 * LABELSECTOR + LABELOFFSET);
+ Fill_Disklabel(dl, new, c1);
+
+ for (i = 0; i < BBSIZE / 512; i++)
+ write_block(fd, i + c1->offset, buf + 512 * i, 512);
+
+ return 0;
+}
+
+
+int
+Write_Disk(const struct disk *d1)
+{
+ int fd, i, j;
+ struct chunk *c1;
+ int ret = 0;
+ char device[64];
+ u_char *mbrblk;
+ struct pc98_partition *dp, work[NDOSPART];
+ int s[7];
+ int PC98_EntireDisk = 0;
+
+ strcpy(device, _PATH_DEV);
+ strcat(device, d1->name);
+
+ /* XXX - for entire FreeBSD(98) */
+ for (c1 = d1->chunks->part; c1; c1 = c1->next) {
+ if ((c1->type == freebsd) || (c1->offset == 0))
+ device[9] = 0;
+ }
+
+ fd = open(device, O_RDWR);
+ if (fd < 0) {
+#ifdef DEBUG
+ warn("open(%s) failed", device);
+#endif
+ return 1;
+ }
+
+ memset(s, 0, sizeof s);
+ if (!(mbrblk = read_block(fd, 1, d1->sector_size))) {
+ close (fd);
+ return (1);
+ }
+ dp = (struct pc98_partition *)(mbrblk + DOSPARTOFF);
+ memcpy(work, dp, sizeof work);
+ dp = work;
+ free(mbrblk);
+ for (c1 = d1->chunks->part; c1; c1 = c1->next) {
+ if (c1->type == unused)
+ continue;
+ if (!strcmp(c1->name, "X"))
+ continue;
+ j = c1->name[strlen(d1->name) + 1] - '1';
+ if (j < 0 || j > 7)
+ continue;
+ s[j]++;
+ if (c1->type == freebsd)
+ ret += Write_FreeBSD(fd, d1, c1);
+
+ i = c1->offset;
+ dp[j].dp_ssect = dp[j].dp_ipl_sct = i % d1->bios_sect;
+ i -= dp[j].dp_ssect;
+ i /= d1->bios_sect;
+ dp[j].dp_shd = dp[j].dp_ipl_head = i % d1->bios_hd;
+ i -= dp[j].dp_shd;
+ i /= d1->bios_hd;
+ dp[j].dp_scyl = dp[j].dp_ipl_cyl = i;
+#ifdef DEBUG
+ printf("S:%lu = (%x/%x/%x)", c1->offset,
+ dp[j].dp_scyl, dp[j].dp_shd, dp[j].dp_ssect);
+#endif
+
+ i = c1->end;
+#if 1
+ dp[j].dp_esect = dp[j].dp_ehd = 0;
+ dp[j].dp_ecyl = i / (d1->bios_sect * d1->bios_hd);
+#else
+ dp[j].dp_esect = i % d1->bios_sect;
+ i -= dp[j].dp_esect;
+ i /= d1->bios_sect;
+ dp[j].dp_ehd = i % d1->bios_hd;
+ i -= dp[j].dp_ehd;
+ i /= d1->bios_hd;
+ dp[j].dp_ecyl = i;
+#endif
+#ifdef DEBUG
+ printf(" E:%lu = (%x/%x/%x)\n", c1->end,
+ dp[j].dp_ecyl, dp[j].dp_ehd, dp[j].dp_esect);
+#endif
+
+ dp[j].dp_mid = c1->subtype & 0xff;
+ dp[j].dp_sid = c1->subtype >> 8;
+ if (c1->flags & CHUNK_ACTIVE)
+ dp[j].dp_mid |= 0x80;
+
+ strncpy(dp[j].dp_name, c1->sname, 16);
+ }
+ j = 0;
+ for (i = 0; i < NDOSPART; i++) {
+ if (!s[i])
+ memset(dp + i, 0, sizeof *dp);
+ }
+
+ if (d1->bootipl)
+ write_block(fd, 0, d1->bootipl, d1->sector_size);
+
+ if (!(mbrblk = read_block(fd, 1, d1->sector_size))) {
+ close (fd);
+ return (1);
+ }
+ memcpy(mbrblk + DOSPARTOFF, dp, sizeof *dp * NDOSPART);
+ /* XXX - for entire FreeBSD(98) */
+ for (c1 = d1->chunks->part; c1; c1 = c1->next)
+ if (((c1->type == freebsd) || (c1->type == fat))
+ && (c1->offset == 0))
+ PC98_EntireDisk = 1;
+ if (PC98_EntireDisk == 0)
+ write_block(fd, 1, mbrblk, d1->sector_size);
+
+ if (d1->bootmenu)
+ for (i = 0; i * d1->sector_size < d1->bootmenu_size; i++)
+ write_block(fd, 2 + i,
+ &d1->bootmenu[i * d1->sector_size],
+ d1->sector_size);
+
+ close(fd);
+ return 0;
+}
diff --git a/lib/libdisk/write_powerpc_disk.c b/lib/libdisk/write_powerpc_disk.c
new file mode 100644
index 0000000..ec955e2
--- /dev/null
+++ b/lib/libdisk/write_powerpc_disk.c
@@ -0,0 +1,64 @@
+/*-
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <err.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/disklabel.h>
+#include <paths.h>
+#include "libdisk.h"
+
+int
+Write_Disk(const struct disk *d1)
+{
+ /*
+ * We don't have to write any label, so we only check that we can
+ * open the disk.
+ */
+ int fd;
+ char device[64];
+
+ strcpy(device, _PATH_DEV);
+ strcat(device, d1->name);
+
+ fd = open(device, O_RDWR);
+ if (fd < 0) {
+ close(fd);
+ return 1;
+ }
+
+ close(fd);
+ return 0;
+}
diff --git a/lib/libdisk/write_sparc64_disk.c b/lib/libdisk/write_sparc64_disk.c
new file mode 100644
index 0000000..9832b0d
--- /dev/null
+++ b/lib/libdisk/write_sparc64_disk.c
@@ -0,0 +1,106 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <err.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/sun_disklabel.h>
+#include <paths.h>
+#include <errno.h>
+#include "libdisk.h"
+
+#include "geom_sunlabel_enc.c"
+
+int
+Write_Disk(const struct disk *d1)
+{
+ struct sun_disklabel *sl;
+ struct chunk *c, *c1, *c2;
+ int i;
+ char *p;
+ u_long secpercyl;
+ char device[64];
+ u_char buf[SUN_SIZE];
+ int fd;
+
+ strcpy(device, _PATH_DEV);
+ strcat(device, d1->name);
+
+ fd = open(device, O_RDWR);
+ if (fd < 0) {
+ warn("open(%s) failed", device);
+ return (1);
+ }
+
+ sl = calloc(sizeof *sl, 1);
+ c = d1->chunks;
+ c2 = c->part;
+ secpercyl = d1->bios_sect * d1->bios_hd;
+ sl->sl_pcylinders = c->size / secpercyl;
+ sl->sl_ncylinders = c2->size / secpercyl;
+ sl->sl_acylinders = sl->sl_pcylinders - sl->sl_ncylinders;
+ sl->sl_magic = SUN_DKMAGIC;
+ sl->sl_nsectors = d1->bios_sect;
+ sl->sl_ntracks = d1->bios_hd;
+ if (c->size > 4999 * 1024 * 2) {
+ sprintf(sl->sl_text, "FreeBSD%luG cyl %u alt %u hd %u sec %u",
+ (c->size + 1024 * 1024) / (2 * 1024 * 1024),
+ sl->sl_ncylinders, sl->sl_acylinders,
+ sl->sl_ntracks, sl->sl_nsectors);
+ } else {
+ sprintf(sl->sl_text, "FreeBSD%luM cyl %u alt %u hd %u sec %u",
+ (c->size + 1024) / (2 * 1024),
+ sl->sl_ncylinders, sl->sl_acylinders,
+ sl->sl_ntracks, sl->sl_nsectors);
+ }
+ sl->sl_interleave = 1;
+ sl->sl_sparespercyl = 0;
+ sl->sl_rpm = 3600;
+
+ for (c1 = c2->part; c1 != NULL; c1 = c1->next) {
+ p = c1->name;
+ p += strlen(p);
+ p--;
+ if (*p < 'a')
+ continue;
+ i = *p - 'a';
+ if (i >= SUN_NPART)
+ continue;
+ sl->sl_part[i].sdkp_cyloffset = c1->offset / secpercyl;
+ sl->sl_part[i].sdkp_nsectors = c1->size;
+ for (i = 1; i < 16; i++) {
+ write_block(fd, c1->offset + i, d1->boot1 + (i * 512),
+ 512);
+ }
+ }
+
+ /*
+ * We need to fill in the "RAW" partition as well. Emperical data
+ * seems to indicate that this covers the "obviously" visible part
+ * of the disk, ie: sl->sl_ncylinders.
+ */
+ sl->sl_part[SUN_RAWPART].sdkp_cyloffset = 0;
+ sl->sl_part[SUN_RAWPART].sdkp_nsectors = sl->sl_ncylinders * secpercyl;
+
+ memset(buf, 0, sizeof buf);
+ sunlabel_enc(buf, sl);
+ write_block(fd, 0, buf, sizeof buf);
+
+ close(fd);
+ return 0;
+}
diff --git a/lib/libedit/Makefile b/lib/libedit/Makefile
new file mode 100644
index 0000000..5ec70ef
--- /dev/null
+++ b/lib/libedit/Makefile
@@ -0,0 +1,70 @@
+# $NetBSD: Makefile,v 1.34 2005/05/28 12:02:53 lukem Exp $
+# @(#)Makefile 8.1 (Berkeley) 6/4/93
+# $FreeBSD$
+
+LIB= edit
+SHLIB_MAJOR= 5
+SHLIBDIR?= /lib
+
+OSRCS= chared.c common.c el.c emacs.c fcns.c help.c hist.c key.c map.c \
+ parse.c prompt.c read.c refresh.c search.c sig.c term.c tty.c vi.c
+
+DPADD= ${LIBNCURSES}
+LDADD= -lncurses
+
+MAN= editline.3 editrc.5
+
+MLINKS= editline.3 el_deletestr.3 editline.3 el_end.3 editline.3 el_init.3 \
+ editline.3 el_get.3 editline.3 el_getc.3 editline.3 el_gets.3 \
+ editline.3 history.3 editline.3 history_end.3 \
+ editline.3 history_init.3 editline.3 el_insertstr.3 \
+ editline.3 el_line.3 editline.3 el_parse.3 editline.3 el_push.3 \
+ editline.3 el_reset.3 editline.3 el_resize.3 editline.3 el_set.3 \
+ editline.3 el_source.3 \
+ editline.3 tok_init.3 editline.3 tok_end.3 editline.3 tok_reset.3 \
+ editline.3 tok_line.3 editline.3 tok_str.3
+
+# For speed and debugging
+#SRCS= ${OSRCS} tokenizer.c history.c
+# For protection
+SRCS= editline.c tokenizer.c history.c
+SRCS+= common.h emacs.h fcns.h help.h vi.h
+CLEANFILES+= common.h editline.c emacs.h fcns.c fcns.h help.c help.h vi.h
+
+CFLAGS+= -I. -I${.CURDIR}
+CFLAGS+= #-DDEBUG_TTY -DDEBUG_KEY -DDEBUG_READ -DDEBUG -DDEBUG_REFRESH
+CFLAGS+= #-DDEBUG_PASTE -DDEBUG_EDIT
+
+AHDR= vi.h emacs.h common.h
+ASRC= ${.CURDIR}/vi.c ${.CURDIR}/emacs.c ${.CURDIR}/common.c
+
+.for hdr in vi emacs common
+${hdr}.h: ${hdr}.c makelist
+ sh ${.CURDIR}/makelist -h ${.CURDIR}/${hdr}.c > ${.TARGET}
+.endfor
+
+fcns.h: ${AHDR} makelist
+ sh ${.CURDIR}/makelist -fh ${AHDR} > ${.TARGET}
+
+fcns.c: ${AHDR} fcns.h makelist
+ sh ${.CURDIR}/makelist -fc ${AHDR} > ${.TARGET}
+
+help.c: ${ASRC} makelist
+ sh ${.CURDIR}/makelist -bc ${ASRC} > ${.TARGET}
+
+help.h: ${ASRC} makelist
+ sh ${.CURDIR}/makelist -bh ${ASRC} > ${.TARGET}
+
+editline.c: ${OSRCS}
+ sh ${.CURDIR}/makelist -e ${.ALLSRC:T} > ${.TARGET}
+
+# minimal dependency to make "make depend" optional
+editline.o editline.po editline.So editline.ln: \
+ common.h emacs.h fcns.c fcns.h help.c help.h vi.h
+
+test.o: ${.CURDIR}/TEST/test.c
+
+test: test.o libedit.a ${DPADD} ${LIBTERMCAP}
+ ${CC} ${CFLAGS} ${.ALLSRC} -o ${.TARGET} libedit.a ${LDADD}
+
+.include <bsd.lib.mk>
diff --git a/lib/libedit/TEST/test.c b/lib/libedit/TEST/test.c
new file mode 100644
index 0000000..facbdaa
--- /dev/null
+++ b/lib/libedit/TEST/test.c
@@ -0,0 +1,298 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell 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.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1992, 1993\n\
+ The Regents of the University of California. All rights reserved.\n");
+#endif /* not lint */
+
+#if !defined(lint) && !defined(SCCSID)
+static char sccsid[] = "@(#)test.c 8.1 (Berkeley) 6/4/93";
+#endif /* not lint && not SCCSID */
+__RCSID("$NetBSD: test.c,v 1.18 2005/06/01 11:37:52 lukem Exp $");
+__FBSDID("$FreeBSD$");
+
+/*
+ * test.c: A little test program
+ */
+#include "sys.h"
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <dirent.h>
+
+#include "histedit.h"
+
+static int continuation = 0;
+volatile sig_atomic_t gotsig = 0;
+
+static unsigned char complete(EditLine *, int);
+ int main(int, char **);
+static char *prompt(EditLine *);
+static void sig(int);
+
+static char *
+prompt(EditLine *el)
+{
+ static char a[] = "Edit$ ";
+ static char b[] = "Edit> ";
+
+ return (continuation ? b : a);
+}
+
+static void
+sig(int i)
+{
+ gotsig = i;
+}
+
+static unsigned char
+complete(EditLine *el, int ch)
+{
+ DIR *dd = opendir(".");
+ struct dirent *dp;
+ const char* ptr;
+ const LineInfo *lf = el_line(el);
+ int len;
+
+ /*
+ * Find the last word
+ */
+ for (ptr = lf->cursor - 1;
+ !isspace((unsigned char)*ptr) && ptr > lf->buffer; ptr--)
+ continue;
+ len = lf->cursor - ++ptr;
+
+ for (dp = readdir(dd); dp != NULL; dp = readdir(dd)) {
+ if (len > strlen(dp->d_name))
+ continue;
+ if (strncmp(dp->d_name, ptr, len) == 0) {
+ closedir(dd);
+ if (el_insertstr(el, &dp->d_name[len]) == -1)
+ return (CC_ERROR);
+ else
+ return (CC_REFRESH);
+ }
+ }
+
+ closedir(dd);
+ return (CC_ERROR);
+}
+
+int
+main(int argc, char *argv[])
+{
+ EditLine *el = NULL;
+ int num;
+ const char *buf;
+ Tokenizer *tok;
+#if 0
+ int lastevent = 0;
+#endif
+ int ncontinuation;
+ History *hist;
+ HistEvent ev;
+
+ (void) signal(SIGINT, sig);
+ (void) signal(SIGQUIT, sig);
+ (void) signal(SIGHUP, sig);
+ (void) signal(SIGTERM, sig);
+
+ hist = history_init(); /* Init the builtin history */
+ /* Remember 100 events */
+ history(hist, &ev, H_SETSIZE, 100);
+
+ tok = tok_init(NULL); /* Initialize the tokenizer */
+
+ /* Initialize editline */
+ el = el_init(*argv, stdin, stdout, stderr);
+
+ el_set(el, EL_EDITOR, "vi"); /* Default editor is vi */
+ el_set(el, EL_SIGNAL, 1); /* Handle signals gracefully */
+ el_set(el, EL_PROMPT, prompt); /* Set the prompt function */
+
+ /* Tell editline to use this history interface */
+ el_set(el, EL_HIST, history, hist);
+
+ /* Add a user-defined function */
+ el_set(el, EL_ADDFN, "ed-complete", "Complete argument", complete);
+
+ /* Bind tab to it */
+ el_set(el, EL_BIND, "^I", "ed-complete", NULL);
+
+ /*
+ * Bind j, k in vi command mode to previous and next line, instead
+ * of previous and next history.
+ */
+ el_set(el, EL_BIND, "-a", "k", "ed-prev-line", NULL);
+ el_set(el, EL_BIND, "-a", "j", "ed-next-line", NULL);
+
+ /*
+ * Source the user's defaults file.
+ */
+ el_source(el, NULL);
+
+ while ((buf = el_gets(el, &num)) != NULL && num != 0) {
+ int ac, cc, co;
+#ifdef DEBUG
+ int i;
+#endif
+ const char **av;
+ const LineInfo *li;
+ li = el_line(el);
+#ifdef DEBUG
+ (void) fprintf(stderr, "==> got %d %s", num, buf);
+ (void) fprintf(stderr, " > li `%.*s_%.*s'\n",
+ (li->cursor - li->buffer), li->buffer,
+ (li->lastchar - 1 - li->cursor),
+ (li->cursor >= li->lastchar) ? "" : li->cursor);
+
+#endif
+ if (gotsig) {
+ (void) fprintf(stderr, "Got signal %d.\n", gotsig);
+ gotsig = 0;
+ el_reset(el);
+ }
+
+ if (!continuation && num == 1)
+ continue;
+
+ ac = cc = co = 0;
+ ncontinuation = tok_line(tok, li, &ac, &av, &cc, &co);
+ if (ncontinuation < 0) {
+ (void) fprintf(stderr, "Internal error\n");
+ continuation = 0;
+ continue;
+ }
+#ifdef DEBUG
+ (void) fprintf(stderr, " > nc %d ac %d cc %d co %d\n",
+ ncontinuation, ac, cc, co);
+#endif
+#if 0
+ if (continuation) {
+ /*
+ * Append to the right event in case the user
+ * moved around in history.
+ */
+ if (history(hist, &ev, H_SET, lastevent) == -1)
+ err(1, "%d: %s", lastevent, ev.str);
+ history(hist, &ev, H_ADD , buf);
+ } else {
+ history(hist, &ev, H_ENTER, buf);
+ lastevent = ev.num;
+ }
+#else
+ /* Simpler */
+ history(hist, &ev, continuation ? H_APPEND : H_ENTER, buf);
+#endif
+
+ continuation = ncontinuation;
+ ncontinuation = 0;
+ if (continuation)
+ continue;
+#ifdef DEBUG
+ for (i = 0; i < ac; i++) {
+ (void) fprintf(stderr, " > arg# %2d ", i);
+ if (i != cc)
+ (void) fprintf(stderr, "`%s'\n", av[i]);
+ else
+ (void) fprintf(stderr, "`%.*s_%s'\n",
+ co, av[i], av[i] + co);
+ }
+#endif
+
+ if (strcmp(av[0], "history") == 0) {
+ int rv;
+
+ switch (ac) {
+ case 1:
+ for (rv = history(hist, &ev, H_LAST); rv != -1;
+ rv = history(hist, &ev, H_PREV))
+ (void) fprintf(stdout, "%4d %s",
+ ev.num, ev.str);
+ break;
+
+ case 2:
+ if (strcmp(av[1], "clear") == 0)
+ history(hist, &ev, H_CLEAR);
+ else
+ goto badhist;
+ break;
+
+ case 3:
+ if (strcmp(av[1], "load") == 0)
+ history(hist, &ev, H_LOAD, av[2]);
+ else if (strcmp(av[1], "save") == 0)
+ history(hist, &ev, H_SAVE, av[2]);
+ break;
+
+ badhist:
+ default:
+ (void) fprintf(stderr,
+ "Bad history arguments\n");
+ break;
+ }
+ } else if (el_parse(el, ac, av) == -1) {
+ switch (fork()) {
+ case 0:
+ execvp(av[0], __DECONST(char *const *, av));
+ perror(av[0]);
+ _exit(1);
+ /*NOTREACHED*/
+ break;
+
+ case -1:
+ perror("fork");
+ break;
+
+ default:
+ if (wait(&num) == -1)
+ perror("wait");
+ (void) fprintf(stderr, "Exit %x\n", num);
+ break;
+ }
+ }
+
+ tok_reset(tok);
+ }
+
+ el_end(el);
+ tok_end(tok);
+ history_end(hist);
+
+ return (0);
+}
diff --git a/lib/libedit/chared.c b/lib/libedit/chared.c
new file mode 100644
index 0000000..ffaaaa7
--- /dev/null
+++ b/lib/libedit/chared.c
@@ -0,0 +1,776 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell 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.
+ *
+ * $NetBSD: chared.c,v 1.25 2005/08/08 01:41:30 christos Exp $
+ */
+
+#if !defined(lint) && !defined(SCCSID)
+static char sccsid[] = "@(#)chared.c 8.1 (Berkeley) 6/4/93";
+#endif /* not lint && not SCCSID */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * chared.c: Character editor utilities
+ */
+#include "sys.h"
+
+#include <stdlib.h>
+#include "el.h"
+
+private void ch__clearmacro(EditLine *);
+
+/* value to leave unused in line buffer */
+#define EL_LEAVE 2
+
+/* cv_undo():
+ * Handle state for the vi undo command
+ */
+protected void
+cv_undo(EditLine *el)
+{
+ c_undo_t *vu = &el->el_chared.c_undo;
+ c_redo_t *r = &el->el_chared.c_redo;
+ unsigned int size;
+
+ /* Save entire line for undo */
+ size = el->el_line.lastchar - el->el_line.buffer;
+ vu->len = size;
+ vu->cursor = el->el_line.cursor - el->el_line.buffer;
+ memcpy(vu->buf, el->el_line.buffer, size);
+
+ /* save command info for redo */
+ r->count = el->el_state.doingarg ? el->el_state.argument : 0;
+ r->action = el->el_chared.c_vcmd.action;
+ r->pos = r->buf;
+ r->cmd = el->el_state.thiscmd;
+ r->ch = el->el_state.thisch;
+}
+
+/* cv_yank():
+ * Save yank/delete data for paste
+ */
+protected void
+cv_yank(EditLine *el, const char *ptr, int size)
+{
+ c_kill_t *k = &el->el_chared.c_kill;
+
+ memcpy(k->buf, ptr, size +0u);
+ k->last = k->buf + size;
+}
+
+
+/* c_insert():
+ * Insert num characters
+ */
+protected void
+c_insert(EditLine *el, int num)
+{
+ char *cp;
+
+ if (el->el_line.lastchar + num >= el->el_line.limit) {
+ if (!ch_enlargebufs(el, num +0u))
+ return; /* can't go past end of buffer */
+ }
+
+ if (el->el_line.cursor < el->el_line.lastchar) {
+ /* if I must move chars */
+ for (cp = el->el_line.lastchar; cp >= el->el_line.cursor; cp--)
+ cp[num] = *cp;
+ }
+ el->el_line.lastchar += num;
+}
+
+
+/* c_delafter():
+ * Delete num characters after the cursor
+ */
+protected void
+c_delafter(EditLine *el, int num)
+{
+
+ if (el->el_line.cursor + num > el->el_line.lastchar)
+ num = el->el_line.lastchar - el->el_line.cursor;
+
+ if (el->el_map.current != el->el_map.emacs) {
+ cv_undo(el);
+ cv_yank(el, el->el_line.cursor, num);
+ }
+
+ if (num > 0) {
+ char *cp;
+
+ for (cp = el->el_line.cursor; cp <= el->el_line.lastchar; cp++)
+ *cp = cp[num];
+
+ el->el_line.lastchar -= num;
+ }
+}
+
+
+/* c_delafter1():
+ * Delete the character after the cursor, do not yank
+ */
+protected void
+c_delafter1(EditLine *el)
+{
+ char *cp;
+
+ for (cp = el->el_line.cursor; cp <= el->el_line.lastchar; cp++)
+ *cp = cp[1];
+
+ el->el_line.lastchar--;
+}
+
+
+/* c_delbefore():
+ * Delete num characters before the cursor
+ */
+protected void
+c_delbefore(EditLine *el, int num)
+{
+
+ if (el->el_line.cursor - num < el->el_line.buffer)
+ num = el->el_line.cursor - el->el_line.buffer;
+
+ if (el->el_map.current != el->el_map.emacs) {
+ cv_undo(el);
+ cv_yank(el, el->el_line.cursor - num, num);
+ }
+
+ if (num > 0) {
+ char *cp;
+
+ for (cp = el->el_line.cursor - num;
+ cp <= el->el_line.lastchar;
+ cp++)
+ *cp = cp[num];
+
+ el->el_line.lastchar -= num;
+ }
+}
+
+
+/* c_delbefore1():
+ * Delete the character before the cursor, do not yank
+ */
+protected void
+c_delbefore1(EditLine *el)
+{
+ char *cp;
+
+ for (cp = el->el_line.cursor - 1; cp <= el->el_line.lastchar; cp++)
+ *cp = cp[1];
+
+ el->el_line.lastchar--;
+}
+
+
+/* ce__isword():
+ * Return if p is part of a word according to emacs
+ */
+protected int
+ce__isword(int p)
+{
+ return (isalnum(p) || strchr("*?_-.[]~=", p) != NULL);
+}
+
+
+/* cv__isword():
+ * Return if p is part of a word according to vi
+ */
+protected int
+cv__isword(int p)
+{
+ if (isalnum(p) || p == '_')
+ return 1;
+ if (isgraph(p))
+ return 2;
+ return 0;
+}
+
+
+/* cv__isWord():
+ * Return if p is part of a big word according to vi
+ */
+protected int
+cv__isWord(int p)
+{
+ return (!isspace(p));
+}
+
+
+/* c__prev_word():
+ * Find the previous word
+ */
+protected char *
+c__prev_word(char *p, char *low, int n, int (*wtest)(int))
+{
+ p--;
+
+ while (n--) {
+ while ((p >= low) && !(*wtest)((unsigned char) *p))
+ p--;
+ while ((p >= low) && (*wtest)((unsigned char) *p))
+ p--;
+ }
+
+ /* cp now points to one character before the word */
+ p++;
+ if (p < low)
+ p = low;
+ /* cp now points where we want it */
+ return (p);
+}
+
+
+/* c__next_word():
+ * Find the next word
+ */
+protected char *
+c__next_word(char *p, char *high, int n, int (*wtest)(int))
+{
+ while (n--) {
+ while ((p < high) && !(*wtest)((unsigned char) *p))
+ p++;
+ while ((p < high) && (*wtest)((unsigned char) *p))
+ p++;
+ }
+ if (p > high)
+ p = high;
+ /* p now points where we want it */
+ return (p);
+}
+
+/* cv_next_word():
+ * Find the next word vi style
+ */
+protected char *
+cv_next_word(EditLine *el, char *p, char *high, int n, int (*wtest)(int))
+{
+ int test;
+
+ while (n--) {
+ test = (*wtest)((unsigned char) *p);
+ while ((p < high) && (*wtest)((unsigned char) *p) == test)
+ p++;
+ /*
+ * vi historically deletes with cw only the word preserving the
+ * trailing whitespace! This is not what 'w' does..
+ */
+ if (n || el->el_chared.c_vcmd.action != (DELETE|INSERT))
+ while ((p < high) && isspace((unsigned char) *p))
+ p++;
+ }
+
+ /* p now points where we want it */
+ if (p > high)
+ return (high);
+ else
+ return (p);
+}
+
+
+/* cv_prev_word():
+ * Find the previous word vi style
+ */
+protected char *
+cv_prev_word(char *p, char *low, int n, int (*wtest)(int))
+{
+ int test;
+
+ p--;
+ while (n--) {
+ while ((p > low) && isspace((unsigned char) *p))
+ p--;
+ test = (*wtest)((unsigned char) *p);
+ while ((p >= low) && (*wtest)((unsigned char) *p) == test)
+ p--;
+ }
+ p++;
+
+ /* p now points where we want it */
+ if (p < low)
+ return (low);
+ else
+ return (p);
+}
+
+
+#ifdef notdef
+/* c__number():
+ * Ignore character p points to, return number appearing after that.
+ * A '$' by itself means a big number; "$-" is for negative; '^' means 1.
+ * Return p pointing to last char used.
+ */
+protected char *
+c__number(
+ char *p, /* character position */
+ int *num, /* Return value */
+ int dval) /* dval is the number to subtract from like $-3 */
+{
+ int i;
+ int sign = 1;
+
+ if (*++p == '^') {
+ *num = 1;
+ return (p);
+ }
+ if (*p == '$') {
+ if (*++p != '-') {
+ *num = 0x7fffffff; /* Handle $ */
+ return (--p);
+ }
+ sign = -1; /* Handle $- */
+ ++p;
+ }
+ for (i = 0; isdigit((unsigned char) *p); i = 10 * i + *p++ - '0')
+ continue;
+ *num = (sign < 0 ? dval - i : i);
+ return (--p);
+}
+#endif
+
+/* cv_delfini():
+ * Finish vi delete action
+ */
+protected void
+cv_delfini(EditLine *el)
+{
+ int size;
+ int action = el->el_chared.c_vcmd.action;
+
+ if (action & INSERT)
+ el->el_map.current = el->el_map.key;
+
+ if (el->el_chared.c_vcmd.pos == 0)
+ /* sanity */
+ return;
+
+ size = el->el_line.cursor - el->el_chared.c_vcmd.pos;
+ if (size == 0)
+ size = 1;
+ el->el_line.cursor = el->el_chared.c_vcmd.pos;
+ if (action & YANK) {
+ if (size > 0)
+ cv_yank(el, el->el_line.cursor, size);
+ else
+ cv_yank(el, el->el_line.cursor + size, -size);
+ } else {
+ if (size > 0) {
+ c_delafter(el, size);
+ re_refresh_cursor(el);
+ } else {
+ c_delbefore(el, -size);
+ el->el_line.cursor += size;
+ }
+ }
+ el->el_chared.c_vcmd.action = NOP;
+}
+
+
+#ifdef notdef
+/* ce__endword():
+ * Go to the end of this word according to emacs
+ */
+protected char *
+ce__endword(char *p, char *high, int n)
+{
+ p++;
+
+ while (n--) {
+ while ((p < high) && isspace((unsigned char) *p))
+ p++;
+ while ((p < high) && !isspace((unsigned char) *p))
+ p++;
+ }
+
+ p--;
+ return (p);
+}
+#endif
+
+
+/* cv__endword():
+ * Go to the end of this word according to vi
+ */
+protected char *
+cv__endword(char *p, char *high, int n, int (*wtest)(int))
+{
+ int test;
+
+ p++;
+
+ while (n--) {
+ while ((p < high) && isspace((unsigned char) *p))
+ p++;
+
+ test = (*wtest)((unsigned char) *p);
+ while ((p < high) && (*wtest)((unsigned char) *p) == test)
+ p++;
+ }
+ p--;
+ return (p);
+}
+
+/* ch_init():
+ * Initialize the character editor
+ */
+protected int
+ch_init(EditLine *el)
+{
+ c_macro_t *ma = &el->el_chared.c_macro;
+
+ el->el_line.buffer = (char *) el_malloc(EL_BUFSIZ);
+ if (el->el_line.buffer == NULL)
+ return (-1);
+
+ (void) memset(el->el_line.buffer, 0, EL_BUFSIZ);
+ el->el_line.cursor = el->el_line.buffer;
+ el->el_line.lastchar = el->el_line.buffer;
+ el->el_line.limit = &el->el_line.buffer[EL_BUFSIZ - EL_LEAVE];
+
+ el->el_chared.c_undo.buf = (char *) el_malloc(EL_BUFSIZ);
+ if (el->el_chared.c_undo.buf == NULL)
+ return (-1);
+ (void) memset(el->el_chared.c_undo.buf, 0, EL_BUFSIZ);
+ el->el_chared.c_undo.len = -1;
+ el->el_chared.c_undo.cursor = 0;
+ el->el_chared.c_redo.buf = (char *) el_malloc(EL_BUFSIZ);
+ if (el->el_chared.c_redo.buf == NULL)
+ return (-1);
+ el->el_chared.c_redo.pos = el->el_chared.c_redo.buf;
+ el->el_chared.c_redo.lim = el->el_chared.c_redo.buf + EL_BUFSIZ;
+ el->el_chared.c_redo.cmd = ED_UNASSIGNED;
+
+ el->el_chared.c_vcmd.action = NOP;
+ el->el_chared.c_vcmd.pos = el->el_line.buffer;
+
+ el->el_chared.c_kill.buf = (char *) el_malloc(EL_BUFSIZ);
+ if (el->el_chared.c_kill.buf == NULL)
+ return (-1);
+ (void) memset(el->el_chared.c_kill.buf, 0, EL_BUFSIZ);
+ el->el_chared.c_kill.mark = el->el_line.buffer;
+ el->el_chared.c_kill.last = el->el_chared.c_kill.buf;
+
+ el->el_map.current = el->el_map.key;
+
+ el->el_state.inputmode = MODE_INSERT; /* XXX: save a default */
+ el->el_state.doingarg = 0;
+ el->el_state.metanext = 0;
+ el->el_state.argument = 1;
+ el->el_state.lastcmd = ED_UNASSIGNED;
+
+ ma->level = -1;
+ ma->offset = 0;
+ ma->macro = (char **) el_malloc(EL_MAXMACRO * sizeof(char *));
+ if (ma->macro == NULL)
+ return (-1);
+ return (0);
+}
+
+/* ch_reset():
+ * Reset the character editor
+ */
+protected void
+ch_reset(EditLine *el, int mclear)
+{
+ el->el_line.cursor = el->el_line.buffer;
+ el->el_line.lastchar = el->el_line.buffer;
+
+ el->el_chared.c_undo.len = -1;
+ el->el_chared.c_undo.cursor = 0;
+
+ el->el_chared.c_vcmd.action = NOP;
+ el->el_chared.c_vcmd.pos = el->el_line.buffer;
+
+ el->el_chared.c_kill.mark = el->el_line.buffer;
+
+ el->el_map.current = el->el_map.key;
+
+ el->el_state.inputmode = MODE_INSERT; /* XXX: save a default */
+ el->el_state.doingarg = 0;
+ el->el_state.metanext = 0;
+ el->el_state.argument = 1;
+ el->el_state.lastcmd = ED_UNASSIGNED;
+
+ el->el_history.eventno = 0;
+
+ if (mclear)
+ ch__clearmacro(el);
+}
+
+private void
+ch__clearmacro(el)
+ EditLine *el;
+{
+ c_macro_t *ma = &el->el_chared.c_macro;
+ while (ma->level >= 0)
+ el_free((ptr_t)ma->macro[ma->level--]);
+}
+
+/* ch_enlargebufs():
+ * Enlarge line buffer to be able to hold twice as much characters.
+ * Returns 1 if successful, 0 if not.
+ */
+protected int
+ch_enlargebufs(el, addlen)
+ EditLine *el;
+ size_t addlen;
+{
+ size_t sz, newsz;
+ char *newbuffer, *oldbuf, *oldkbuf;
+
+ sz = el->el_line.limit - el->el_line.buffer + EL_LEAVE;
+ newsz = sz * 2;
+ /*
+ * If newly required length is longer than current buffer, we need
+ * to make the buffer big enough to hold both old and new stuff.
+ */
+ if (addlen > sz) {
+ while(newsz - sz < addlen)
+ newsz *= 2;
+ }
+
+ /*
+ * Reallocate line buffer.
+ */
+ newbuffer = el_realloc(el->el_line.buffer, newsz);
+ if (!newbuffer)
+ return 0;
+
+ /* zero the newly added memory, leave old data in */
+ (void) memset(&newbuffer[sz], 0, newsz - sz);
+
+ oldbuf = el->el_line.buffer;
+
+ el->el_line.buffer = newbuffer;
+ el->el_line.cursor = newbuffer + (el->el_line.cursor - oldbuf);
+ el->el_line.lastchar = newbuffer + (el->el_line.lastchar - oldbuf);
+ /* don't set new size until all buffers are enlarged */
+ el->el_line.limit = &newbuffer[sz - EL_LEAVE];
+
+ /*
+ * Reallocate kill buffer.
+ */
+ newbuffer = el_realloc(el->el_chared.c_kill.buf, newsz);
+ if (!newbuffer)
+ return 0;
+
+ /* zero the newly added memory, leave old data in */
+ (void) memset(&newbuffer[sz], 0, newsz - sz);
+
+ oldkbuf = el->el_chared.c_kill.buf;
+
+ el->el_chared.c_kill.buf = newbuffer;
+ el->el_chared.c_kill.last = newbuffer +
+ (el->el_chared.c_kill.last - oldkbuf);
+ el->el_chared.c_kill.mark = el->el_line.buffer +
+ (el->el_chared.c_kill.mark - oldbuf);
+
+ /*
+ * Reallocate undo buffer.
+ */
+ newbuffer = el_realloc(el->el_chared.c_undo.buf, newsz);
+ if (!newbuffer)
+ return 0;
+
+ /* zero the newly added memory, leave old data in */
+ (void) memset(&newbuffer[sz], 0, newsz - sz);
+ el->el_chared.c_undo.buf = newbuffer;
+
+ newbuffer = el_realloc(el->el_chared.c_redo.buf, newsz);
+ if (!newbuffer)
+ return 0;
+ el->el_chared.c_redo.pos = newbuffer +
+ (el->el_chared.c_redo.pos - el->el_chared.c_redo.buf);
+ el->el_chared.c_redo.lim = newbuffer +
+ (el->el_chared.c_redo.lim - el->el_chared.c_redo.buf);
+ el->el_chared.c_redo.buf = newbuffer;
+
+ if (!hist_enlargebuf(el, sz, newsz))
+ return 0;
+
+ /* Safe to set enlarged buffer size */
+ el->el_line.limit = &el->el_line.buffer[newsz - EL_LEAVE];
+ return 1;
+}
+
+/* ch_end():
+ * Free the data structures used by the editor
+ */
+protected void
+ch_end(EditLine *el)
+{
+ el_free((ptr_t) el->el_line.buffer);
+ el->el_line.buffer = NULL;
+ el->el_line.limit = NULL;
+ el_free((ptr_t) el->el_chared.c_undo.buf);
+ el->el_chared.c_undo.buf = NULL;
+ el_free((ptr_t) el->el_chared.c_redo.buf);
+ el->el_chared.c_redo.buf = NULL;
+ el->el_chared.c_redo.pos = NULL;
+ el->el_chared.c_redo.lim = NULL;
+ el->el_chared.c_redo.cmd = ED_UNASSIGNED;
+ el_free((ptr_t) el->el_chared.c_kill.buf);
+ el->el_chared.c_kill.buf = NULL;
+ ch_reset(el, 1);
+ el_free((ptr_t) el->el_chared.c_macro.macro);
+ el->el_chared.c_macro.macro = NULL;
+}
+
+
+/* el_insertstr():
+ * Insert string at cursorI
+ */
+public int
+el_insertstr(EditLine *el, const char *s)
+{
+ size_t len;
+
+ if ((len = strlen(s)) == 0)
+ return (-1);
+ if (el->el_line.lastchar + len >= el->el_line.limit) {
+ if (!ch_enlargebufs(el, len))
+ return (-1);
+ }
+
+ c_insert(el, (int)len);
+ while (*s)
+ *el->el_line.cursor++ = *s++;
+ return (0);
+}
+
+
+/* el_deletestr():
+ * Delete num characters before the cursor
+ */
+public void
+el_deletestr(EditLine *el, int n)
+{
+ if (n <= 0)
+ return;
+
+ if (el->el_line.cursor < &el->el_line.buffer[n])
+ return;
+
+ c_delbefore(el, n); /* delete before dot */
+ el->el_line.cursor -= n;
+ if (el->el_line.cursor < el->el_line.buffer)
+ el->el_line.cursor = el->el_line.buffer;
+}
+
+/* c_gets():
+ * Get a string
+ */
+protected int
+c_gets(EditLine *el, char *buf, const char *prompt)
+{
+ char ch;
+ int len;
+ char *cp = el->el_line.buffer;
+
+ if (prompt) {
+ len = strlen(prompt);
+ memcpy(cp, prompt, len + 0u);
+ cp += len;
+ }
+ len = 0;
+
+ for (;;) {
+ el->el_line.cursor = cp;
+ *cp = ' ';
+ el->el_line.lastchar = cp + 1;
+ re_refresh(el);
+
+ if (el_getc(el, &ch) != 1) {
+ ed_end_of_file(el, 0);
+ len = -1;
+ break;
+ }
+
+ switch (ch) {
+
+ case '\010': /* Delete and backspace */
+ case '\177':
+ if (len <= 0) {
+ len = -1;
+ break;
+ }
+ cp--;
+ continue;
+
+ case '\033': /* ESC */
+ case '\r': /* Newline */
+ case '\n':
+ buf[len] = ch;
+ break;
+
+ default:
+ if (len >= EL_BUFSIZ - 16)
+ term_beep(el);
+ else {
+ buf[len++] = ch;
+ *cp++ = ch;
+ }
+ continue;
+ }
+ break;
+ }
+
+ el->el_line.buffer[0] = '\0';
+ el->el_line.lastchar = el->el_line.buffer;
+ el->el_line.cursor = el->el_line.buffer;
+ return len;
+}
+
+
+/* c_hpos():
+ * Return the current horizontal position of the cursor
+ */
+protected int
+c_hpos(EditLine *el)
+{
+ char *ptr;
+
+ /*
+ * Find how many characters till the beginning of this line.
+ */
+ if (el->el_line.cursor == el->el_line.buffer)
+ return (0);
+ else {
+ for (ptr = el->el_line.cursor - 1;
+ ptr >= el->el_line.buffer && *ptr != '\n';
+ ptr--)
+ continue;
+ return (el->el_line.cursor - ptr - 1);
+ }
+}
diff --git a/lib/libedit/chared.h b/lib/libedit/chared.h
new file mode 100644
index 0000000..826c767
--- /dev/null
+++ b/lib/libedit/chared.h
@@ -0,0 +1,168 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell 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.
+ *
+ * @(#)chared.h 8.1 (Berkeley) 6/4/93
+ * $NetBSD: chared.h,v 1.16 2005/08/08 14:05:37 christos Exp $
+ * $FreeBSD$
+ */
+
+/*
+ * el.chared.h: Character editor interface
+ */
+#ifndef _h_el_chared
+#define _h_el_chared
+
+#include <ctype.h>
+#include <string.h>
+
+#include "histedit.h"
+
+#define EL_MAXMACRO 10
+
+/*
+ * This is an issue of basic "vi" look-and-feel. Defining VI_MOVE works
+ * like real vi: i.e. the transition from command<->insert modes moves
+ * the cursor.
+ *
+ * On the other hand we really don't want to move the cursor, because
+ * all the editing commands don't include the character under the cursor.
+ * Probably the best fix is to make all the editing commands aware of
+ * this fact.
+ */
+#define VI_MOVE
+
+
+typedef struct c_macro_t {
+ int level;
+ int offset;
+ char **macro;
+} c_macro_t;
+
+/*
+ * Undo information for vi - no undo in emacs (yet)
+ */
+typedef struct c_undo_t {
+ int len; /* length of saved line */
+ int cursor; /* position of saved cursor */
+ char *buf; /* full saved text */
+} c_undo_t;
+
+/* redo for vi */
+typedef struct c_redo_t {
+ char *buf; /* redo insert key sequence */
+ char *pos;
+ char *lim;
+ el_action_t cmd; /* command to redo */
+ char ch; /* char that invoked it */
+ int count;
+ int action; /* from cv_action() */
+} c_redo_t;
+
+/*
+ * Current action information for vi
+ */
+typedef struct c_vcmd_t {
+ int action;
+ char *pos;
+} c_vcmd_t;
+
+/*
+ * Kill buffer for emacs
+ */
+typedef struct c_kill_t {
+ char *buf;
+ char *last;
+ char *mark;
+} c_kill_t;
+
+/*
+ * Note that we use both data structures because the user can bind
+ * commands from both editors!
+ */
+typedef struct el_chared_t {
+ c_undo_t c_undo;
+ c_kill_t c_kill;
+ c_redo_t c_redo;
+ c_vcmd_t c_vcmd;
+ c_macro_t c_macro;
+} el_chared_t;
+
+
+#define STReof "^D\b\b"
+#define STRQQ "\"\""
+
+#define isglob(a) (strchr("*[]?", (a)) != NULL)
+#define isword(a) (isprint(a))
+
+#define NOP 0x00
+#define DELETE 0x01
+#define INSERT 0x02
+#define YANK 0x04
+
+#define CHAR_FWD (+1)
+#define CHAR_BACK (-1)
+
+#define MODE_INSERT 0
+#define MODE_REPLACE 1
+#define MODE_REPLACE_1 2
+
+#include "common.h"
+#include "vi.h"
+#include "emacs.h"
+#include "search.h"
+#include "fcns.h"
+
+
+protected int cv__isword(int);
+protected int cv__isWord(int);
+protected void cv_delfini(EditLine *);
+protected char *cv__endword(char *, char *, int, int (*)(int));
+protected int ce__isword(int);
+protected void cv_undo(EditLine *);
+protected void cv_yank(EditLine *, const char *, int);
+protected char *cv_next_word(EditLine*, char *, char *, int, int (*)(int));
+protected char *cv_prev_word(char *, char *, int, int (*)(int));
+protected char *c__next_word(char *, char *, int, int (*)(int));
+protected char *c__prev_word(char *, char *, int, int (*)(int));
+protected void c_insert(EditLine *, int);
+protected void c_delbefore(EditLine *, int);
+protected void c_delbefore1(EditLine *);
+protected void c_delafter(EditLine *, int);
+protected void c_delafter1(EditLine *);
+protected int c_gets(EditLine *, char *, const char *);
+protected int c_hpos(EditLine *);
+
+protected int ch_init(EditLine *);
+protected void ch_reset(EditLine *, int);
+protected int ch_enlargebufs(EditLine *, size_t);
+protected void ch_end(EditLine *);
+
+#endif /* _h_el_chared */
diff --git a/lib/libedit/common.c b/lib/libedit/common.c
new file mode 100644
index 0000000..3259f0a
--- /dev/null
+++ b/lib/libedit/common.c
@@ -0,0 +1,920 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell 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.
+ *
+ * $NetBSD: common.c,v 1.18 2005/08/08 14:05:37 christos Exp $
+ */
+
+#if !defined(lint) && !defined(SCCSID)
+static char sccsid[] = "@(#)common.c 8.1 (Berkeley) 6/4/93";
+#endif /* not lint && not SCCSID */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * common.c: Common Editor functions
+ */
+#include "sys.h"
+#include "el.h"
+
+/* ed_end_of_file():
+ * Indicate end of file
+ * [^D]
+ */
+protected el_action_t
+/*ARGSUSED*/
+ed_end_of_file(EditLine *el, int c __unused)
+{
+
+ re_goto_bottom(el);
+ *el->el_line.lastchar = '\0';
+ return (CC_EOF);
+}
+
+
+/* ed_insert():
+ * Add character to the line
+ * Insert a character [bound to all insert keys]
+ */
+protected el_action_t
+ed_insert(EditLine *el, int c)
+{
+ int count = el->el_state.argument;
+
+ if (c == '\0')
+ return (CC_ERROR);
+
+ if (el->el_line.lastchar + el->el_state.argument >=
+ el->el_line.limit) {
+ /* end of buffer space, try to allocate more */
+ if (!ch_enlargebufs(el, (size_t) count))
+ return CC_ERROR; /* error allocating more */
+ }
+
+ if (count == 1) {
+ if (el->el_state.inputmode == MODE_INSERT
+ || el->el_line.cursor >= el->el_line.lastchar)
+ c_insert(el, 1);
+
+ *el->el_line.cursor++ = c;
+ re_fastaddc(el); /* fast refresh for one char. */
+ } else {
+ if (el->el_state.inputmode != MODE_REPLACE_1)
+ c_insert(el, el->el_state.argument);
+
+ while (count-- && el->el_line.cursor < el->el_line.lastchar)
+ *el->el_line.cursor++ = c;
+ re_refresh(el);
+ }
+
+ if (el->el_state.inputmode == MODE_REPLACE_1)
+ return vi_command_mode(el, 0);
+
+ return (CC_NORM);
+}
+
+
+/* ed_delete_prev_word():
+ * Delete from beginning of current word to cursor
+ * [M-^?] [^W]
+ */
+protected el_action_t
+/*ARGSUSED*/
+ed_delete_prev_word(EditLine *el, int c __unused)
+{
+ char *cp, *p, *kp;
+
+ if (el->el_line.cursor == el->el_line.buffer)
+ return (CC_ERROR);
+
+ cp = c__prev_word(el->el_line.cursor, el->el_line.buffer,
+ el->el_state.argument, ce__isword);
+
+ for (p = cp, kp = el->el_chared.c_kill.buf; p < el->el_line.cursor; p++)
+ *kp++ = *p;
+ el->el_chared.c_kill.last = kp;
+
+ c_delbefore(el, el->el_line.cursor - cp); /* delete before dot */
+ el->el_line.cursor = cp;
+ if (el->el_line.cursor < el->el_line.buffer)
+ el->el_line.cursor = el->el_line.buffer; /* bounds check */
+ return (CC_REFRESH);
+}
+
+
+/* ed_delete_next_char():
+ * Delete character under cursor
+ * [^D] [x]
+ */
+protected el_action_t
+/*ARGSUSED*/
+ed_delete_next_char(EditLine *el, int c __unused)
+{
+#ifdef notdef /* XXX */
+#define EL el->el_line
+ (void) fprintf(el->el_errlfile,
+ "\nD(b: %x(%s) c: %x(%s) last: %x(%s) limit: %x(%s)\n",
+ EL.buffer, EL.buffer, EL.cursor, EL.cursor, EL.lastchar,
+ EL.lastchar, EL.limit, EL.limit);
+#endif
+ if (el->el_line.cursor == el->el_line.lastchar) {
+ /* if I'm at the end */
+ if (el->el_map.type == MAP_VI) {
+ if (el->el_line.cursor == el->el_line.buffer) {
+ /* if I'm also at the beginning */
+#ifdef KSHVI
+ return (CC_ERROR);
+#else
+ term_overwrite(el, STReof, 4);
+ /* then do an EOF */
+ term__flush();
+ return (CC_EOF);
+#endif
+ } else {
+#ifdef KSHVI
+ el->el_line.cursor--;
+#else
+ return (CC_ERROR);
+#endif
+ }
+ } else {
+ if (el->el_line.cursor != el->el_line.buffer)
+ el->el_line.cursor--;
+ else
+ return (CC_ERROR);
+ }
+ }
+ c_delafter(el, el->el_state.argument); /* delete after dot */
+ if (el->el_line.cursor >= el->el_line.lastchar &&
+ el->el_line.cursor > el->el_line.buffer)
+ /* bounds check */
+ el->el_line.cursor = el->el_line.lastchar - 1;
+ return (CC_REFRESH);
+}
+
+
+/* ed_kill_line():
+ * Cut to the end of line
+ * [^K] [^K]
+ */
+protected el_action_t
+/*ARGSUSED*/
+ed_kill_line(EditLine *el, int c __unused)
+{
+ char *kp, *cp;
+
+ cp = el->el_line.cursor;
+ kp = el->el_chared.c_kill.buf;
+ while (cp < el->el_line.lastchar)
+ *kp++ = *cp++; /* copy it */
+ el->el_chared.c_kill.last = kp;
+ /* zap! -- delete to end */
+ el->el_line.lastchar = el->el_line.cursor;
+ return (CC_REFRESH);
+}
+
+
+/* ed_move_to_end():
+ * Move cursor to the end of line
+ * [^E] [^E]
+ */
+protected el_action_t
+/*ARGSUSED*/
+ed_move_to_end(EditLine *el, int c __unused)
+{
+
+ el->el_line.cursor = el->el_line.lastchar;
+ if (el->el_map.type == MAP_VI) {
+#ifdef VI_MOVE
+ el->el_line.cursor--;
+#endif
+ if (el->el_chared.c_vcmd.action != NOP) {
+ cv_delfini(el);
+ return (CC_REFRESH);
+ }
+ }
+ return (CC_CURSOR);
+}
+
+
+/* ed_move_to_beg():
+ * Move cursor to the beginning of line
+ * [^A] [^A]
+ */
+protected el_action_t
+/*ARGSUSED*/
+ed_move_to_beg(EditLine *el, int c __unused)
+{
+
+ el->el_line.cursor = el->el_line.buffer;
+
+ if (el->el_map.type == MAP_VI) {
+ /* We want FIRST non space character */
+ while (isspace((unsigned char) *el->el_line.cursor))
+ el->el_line.cursor++;
+ if (el->el_chared.c_vcmd.action != NOP) {
+ cv_delfini(el);
+ return (CC_REFRESH);
+ }
+ }
+ return (CC_CURSOR);
+}
+
+
+/* ed_transpose_chars():
+ * Exchange the character to the left of the cursor with the one under it
+ * [^T] [^T]
+ */
+protected el_action_t
+ed_transpose_chars(EditLine *el, int c)
+{
+
+ if (el->el_line.cursor < el->el_line.lastchar) {
+ if (el->el_line.lastchar <= &el->el_line.buffer[1])
+ return (CC_ERROR);
+ else
+ el->el_line.cursor++;
+ }
+ if (el->el_line.cursor > &el->el_line.buffer[1]) {
+ /* must have at least two chars entered */
+ c = el->el_line.cursor[-2];
+ el->el_line.cursor[-2] = el->el_line.cursor[-1];
+ el->el_line.cursor[-1] = c;
+ return (CC_REFRESH);
+ } else
+ return (CC_ERROR);
+}
+
+
+/* ed_next_char():
+ * Move to the right one character
+ * [^F] [^F]
+ */
+protected el_action_t
+/*ARGSUSED*/
+ed_next_char(EditLine *el, int c __unused)
+{
+ char *lim = el->el_line.lastchar;
+
+ if (el->el_line.cursor >= lim ||
+ (el->el_line.cursor == lim - 1 &&
+ el->el_map.type == MAP_VI &&
+ el->el_chared.c_vcmd.action == NOP))
+ return (CC_ERROR);
+
+ el->el_line.cursor += el->el_state.argument;
+ if (el->el_line.cursor > lim)
+ el->el_line.cursor = lim;
+
+ if (el->el_map.type == MAP_VI)
+ if (el->el_chared.c_vcmd.action != NOP) {
+ cv_delfini(el);
+ return (CC_REFRESH);
+ }
+ return (CC_CURSOR);
+}
+
+
+/* ed_prev_word():
+ * Move to the beginning of the current word
+ * [M-b] [b]
+ */
+protected el_action_t
+/*ARGSUSED*/
+ed_prev_word(EditLine *el, int c __unused)
+{
+
+ if (el->el_line.cursor == el->el_line.buffer)
+ return (CC_ERROR);
+
+ el->el_line.cursor = c__prev_word(el->el_line.cursor,
+ el->el_line.buffer,
+ el->el_state.argument,
+ ce__isword);
+
+ if (el->el_map.type == MAP_VI)
+ if (el->el_chared.c_vcmd.action != NOP) {
+ cv_delfini(el);
+ return (CC_REFRESH);
+ }
+ return (CC_CURSOR);
+}
+
+
+/* ed_prev_char():
+ * Move to the left one character
+ * [^B] [^B]
+ */
+protected el_action_t
+/*ARGSUSED*/
+ed_prev_char(EditLine *el, int c __unused)
+{
+
+ if (el->el_line.cursor > el->el_line.buffer) {
+ el->el_line.cursor -= el->el_state.argument;
+ if (el->el_line.cursor < el->el_line.buffer)
+ el->el_line.cursor = el->el_line.buffer;
+
+ if (el->el_map.type == MAP_VI)
+ if (el->el_chared.c_vcmd.action != NOP) {
+ cv_delfini(el);
+ return (CC_REFRESH);
+ }
+ return (CC_CURSOR);
+ } else
+ return (CC_ERROR);
+}
+
+
+/* ed_quoted_insert():
+ * Add the next character typed verbatim
+ * [^V] [^V]
+ */
+protected el_action_t
+ed_quoted_insert(EditLine *el, int c)
+{
+ int num;
+ char tc;
+
+ tty_quotemode(el);
+ num = el_getc(el, &tc);
+ c = (unsigned char) tc;
+ tty_noquotemode(el);
+ if (num == 1)
+ return (ed_insert(el, c));
+ else
+ return (ed_end_of_file(el, 0));
+}
+
+
+/* ed_digit():
+ * Adds to argument or enters a digit
+ */
+protected el_action_t
+ed_digit(EditLine *el, int c)
+{
+
+ if (!isdigit((unsigned char) c))
+ return (CC_ERROR);
+
+ if (el->el_state.doingarg) {
+ /* if doing an arg, add this in... */
+ if (el->el_state.lastcmd == EM_UNIVERSAL_ARGUMENT)
+ el->el_state.argument = c - '0';
+ else {
+ if (el->el_state.argument > 1000000)
+ return (CC_ERROR);
+ el->el_state.argument =
+ (el->el_state.argument * 10) + (c - '0');
+ }
+ return (CC_ARGHACK);
+ }
+
+ return ed_insert(el, c);
+}
+
+
+/* ed_argument_digit():
+ * Digit that starts argument
+ * For ESC-n
+ */
+protected el_action_t
+ed_argument_digit(EditLine *el, int c)
+{
+
+ if (!isdigit((unsigned char) c))
+ return (CC_ERROR);
+
+ if (el->el_state.doingarg) {
+ if (el->el_state.argument > 1000000)
+ return (CC_ERROR);
+ el->el_state.argument = (el->el_state.argument * 10) +
+ (c - '0');
+ } else { /* else starting an argument */
+ el->el_state.argument = c - '0';
+ el->el_state.doingarg = 1;
+ }
+ return (CC_ARGHACK);
+}
+
+
+/* ed_unassigned():
+ * Indicates unbound character
+ * Bound to keys that are not assigned
+ */
+protected el_action_t
+/*ARGSUSED*/
+ed_unassigned(EditLine *el, int c __unused)
+{
+
+ return (CC_ERROR);
+}
+
+
+/**
+ ** TTY key handling.
+ **/
+
+/* ed_tty_sigint():
+ * Tty interrupt character
+ * [^C]
+ */
+protected el_action_t
+/*ARGSUSED*/
+ed_tty_sigint(EditLine *el __unused,
+ int c __unused)
+{
+
+ return (CC_NORM);
+}
+
+
+/* ed_tty_dsusp():
+ * Tty delayed suspend character
+ * [^Y]
+ */
+protected el_action_t
+/*ARGSUSED*/
+ed_tty_dsusp(EditLine *el __unused,
+ int c __unused)
+{
+
+ return (CC_NORM);
+}
+
+
+/* ed_tty_flush_output():
+ * Tty flush output characters
+ * [^O]
+ */
+protected el_action_t
+/*ARGSUSED*/
+ed_tty_flush_output(EditLine *el __unused,
+ int c __unused)
+{
+
+ return (CC_NORM);
+}
+
+
+/* ed_tty_sigquit():
+ * Tty quit character
+ * [^\]
+ */
+protected el_action_t
+/*ARGSUSED*/
+ed_tty_sigquit(EditLine *el __unused,
+ int c __unused)
+{
+
+ return (CC_NORM);
+}
+
+
+/* ed_tty_sigtstp():
+ * Tty suspend character
+ * [^Z]
+ */
+protected el_action_t
+/*ARGSUSED*/
+ed_tty_sigtstp(EditLine *el __unused,
+ int c __unused)
+{
+
+ return (CC_NORM);
+}
+
+
+/* ed_tty_stop_output():
+ * Tty disallow output characters
+ * [^S]
+ */
+protected el_action_t
+/*ARGSUSED*/
+ed_tty_stop_output(EditLine *el __unused,
+ int c __unused)
+{
+
+ return (CC_NORM);
+}
+
+
+/* ed_tty_start_output():
+ * Tty allow output characters
+ * [^Q]
+ */
+protected el_action_t
+/*ARGSUSED*/
+ed_tty_start_output(EditLine *el __unused,
+ int c __unused)
+{
+
+ return (CC_NORM);
+}
+
+
+/* ed_newline():
+ * Execute command
+ * [^J]
+ */
+protected el_action_t
+/*ARGSUSED*/
+ed_newline(EditLine *el, int c __unused)
+{
+
+ re_goto_bottom(el);
+ *el->el_line.lastchar++ = '\n';
+ *el->el_line.lastchar = '\0';
+ return (CC_NEWLINE);
+}
+
+
+/* ed_delete_prev_char():
+ * Delete the character to the left of the cursor
+ * [^?]
+ */
+protected el_action_t
+/*ARGSUSED*/
+ed_delete_prev_char(EditLine *el, int c __unused)
+{
+
+ if (el->el_line.cursor <= el->el_line.buffer)
+ return (CC_ERROR);
+
+ c_delbefore(el, el->el_state.argument);
+ el->el_line.cursor -= el->el_state.argument;
+ if (el->el_line.cursor < el->el_line.buffer)
+ el->el_line.cursor = el->el_line.buffer;
+ return (CC_REFRESH);
+}
+
+
+/* ed_clear_screen():
+ * Clear screen leaving current line at the top
+ * [^L]
+ */
+protected el_action_t
+/*ARGSUSED*/
+ed_clear_screen(EditLine *el, int c __unused)
+{
+
+ term_clear_screen(el); /* clear the whole real screen */
+ re_clear_display(el); /* reset everything */
+ return (CC_REFRESH);
+}
+
+
+/* ed_redisplay():
+ * Redisplay everything
+ * ^R
+ */
+protected el_action_t
+/*ARGSUSED*/
+ed_redisplay(EditLine *el __unused,
+ int c __unused)
+{
+
+ return (CC_REDISPLAY);
+}
+
+
+/* ed_start_over():
+ * Erase current line and start from scratch
+ * [^G]
+ */
+protected el_action_t
+/*ARGSUSED*/
+ed_start_over(EditLine *el, int c __unused)
+{
+
+ ch_reset(el, 0);
+ return (CC_REFRESH);
+}
+
+
+/* ed_sequence_lead_in():
+ * First character in a bound sequence
+ * Placeholder for external keys
+ */
+protected el_action_t
+/*ARGSUSED*/
+ed_sequence_lead_in(EditLine *el __unused,
+ int c __unused)
+{
+
+ return (CC_NORM);
+}
+
+
+/* ed_prev_history():
+ * Move to the previous history line
+ * [^P] [k]
+ */
+protected el_action_t
+/*ARGSUSED*/
+ed_prev_history(EditLine *el, int c __unused)
+{
+ char beep = 0;
+ int sv_event = el->el_history.eventno;
+
+ el->el_chared.c_undo.len = -1;
+ *el->el_line.lastchar = '\0'; /* just in case */
+
+ if (el->el_history.eventno == 0) { /* save the current buffer
+ * away */
+ (void) strncpy(el->el_history.buf, el->el_line.buffer,
+ EL_BUFSIZ);
+ el->el_history.last = el->el_history.buf +
+ (el->el_line.lastchar - el->el_line.buffer);
+ }
+ el->el_history.eventno += el->el_state.argument;
+
+ if (hist_get(el) == CC_ERROR) {
+ if (el->el_map.type == MAP_VI) {
+ el->el_history.eventno = sv_event;
+ return CC_ERROR;
+ }
+ beep = 1;
+ /* el->el_history.eventno was fixed by first call */
+ (void) hist_get(el);
+ }
+ if (beep)
+ return CC_REFRESH_BEEP;
+ return CC_REFRESH;
+}
+
+
+/* ed_next_history():
+ * Move to the next history line
+ * [^N] [j]
+ */
+protected el_action_t
+/*ARGSUSED*/
+ed_next_history(EditLine *el, int c __unused)
+{
+ el_action_t beep = CC_REFRESH, rval;
+
+ el->el_chared.c_undo.len = -1;
+ *el->el_line.lastchar = '\0'; /* just in case */
+
+ el->el_history.eventno -= el->el_state.argument;
+
+ if (el->el_history.eventno < 0) {
+ el->el_history.eventno = 0;
+ beep = CC_REFRESH_BEEP;
+ }
+ rval = hist_get(el);
+ if (rval == CC_REFRESH)
+ return beep;
+ return rval;
+
+}
+
+
+/* ed_search_prev_history():
+ * Search previous in history for a line matching the current
+ * next search history [M-P] [K]
+ */
+protected el_action_t
+/*ARGSUSED*/
+ed_search_prev_history(EditLine *el, int c __unused)
+{
+ const char *hp;
+ int h;
+ bool_t found = 0;
+
+ el->el_chared.c_vcmd.action = NOP;
+ el->el_chared.c_undo.len = -1;
+ *el->el_line.lastchar = '\0'; /* just in case */
+ if (el->el_history.eventno < 0) {
+#ifdef DEBUG_EDIT
+ (void) fprintf(el->el_errfile,
+ "e_prev_search_hist(): eventno < 0;\n");
+#endif
+ el->el_history.eventno = 0;
+ return (CC_ERROR);
+ }
+ if (el->el_history.eventno == 0) {
+ (void) strncpy(el->el_history.buf, el->el_line.buffer,
+ EL_BUFSIZ);
+ el->el_history.last = el->el_history.buf +
+ (el->el_line.lastchar - el->el_line.buffer);
+ }
+ if (el->el_history.ref == NULL)
+ return (CC_ERROR);
+
+ hp = HIST_FIRST(el);
+ if (hp == NULL)
+ return (CC_ERROR);
+
+ c_setpat(el); /* Set search pattern !! */
+
+ for (h = 1; h <= el->el_history.eventno; h++)
+ hp = HIST_NEXT(el);
+
+ while (hp != NULL) {
+#ifdef SDEBUG
+ (void) fprintf(el->el_errfile, "Comparing with \"%s\"\n", hp);
+#endif
+ if ((strncmp(hp, el->el_line.buffer, (size_t)
+ (el->el_line.lastchar - el->el_line.buffer)) ||
+ hp[el->el_line.lastchar - el->el_line.buffer]) &&
+ c_hmatch(el, hp)) {
+ found++;
+ break;
+ }
+ h++;
+ hp = HIST_NEXT(el);
+ }
+
+ if (!found) {
+#ifdef SDEBUG
+ (void) fprintf(el->el_errfile, "not found\n");
+#endif
+ return (CC_ERROR);
+ }
+ el->el_history.eventno = h;
+
+ return (hist_get(el));
+}
+
+
+/* ed_search_next_history():
+ * Search next in history for a line matching the current
+ * [M-N] [J]
+ */
+protected el_action_t
+/*ARGSUSED*/
+ed_search_next_history(EditLine *el, int c __unused)
+{
+ const char *hp;
+ int h;
+ bool_t found = 0;
+
+ el->el_chared.c_vcmd.action = NOP;
+ el->el_chared.c_undo.len = -1;
+ *el->el_line.lastchar = '\0'; /* just in case */
+
+ if (el->el_history.eventno == 0)
+ return (CC_ERROR);
+
+ if (el->el_history.ref == NULL)
+ return (CC_ERROR);
+
+ hp = HIST_FIRST(el);
+ if (hp == NULL)
+ return (CC_ERROR);
+
+ c_setpat(el); /* Set search pattern !! */
+
+ for (h = 1; h < el->el_history.eventno && hp; h++) {
+#ifdef SDEBUG
+ (void) fprintf(el->el_errfile, "Comparing with \"%s\"\n", hp);
+#endif
+ if ((strncmp(hp, el->el_line.buffer, (size_t)
+ (el->el_line.lastchar - el->el_line.buffer)) ||
+ hp[el->el_line.lastchar - el->el_line.buffer]) &&
+ c_hmatch(el, hp))
+ found = h;
+ hp = HIST_NEXT(el);
+ }
+
+ if (!found) { /* is it the current history number? */
+ if (!c_hmatch(el, el->el_history.buf)) {
+#ifdef SDEBUG
+ (void) fprintf(el->el_errfile, "not found\n");
+#endif
+ return (CC_ERROR);
+ }
+ }
+ el->el_history.eventno = found;
+
+ return (hist_get(el));
+}
+
+
+/* ed_prev_line():
+ * Move up one line
+ * Could be [k] [^p]
+ */
+protected el_action_t
+/*ARGSUSED*/
+ed_prev_line(EditLine *el, int c __unused)
+{
+ char *ptr;
+ int nchars = c_hpos(el);
+
+ /*
+ * Move to the line requested
+ */
+ if (*(ptr = el->el_line.cursor) == '\n')
+ ptr--;
+
+ for (; ptr >= el->el_line.buffer; ptr--)
+ if (*ptr == '\n' && --el->el_state.argument <= 0)
+ break;
+
+ if (el->el_state.argument > 0)
+ return (CC_ERROR);
+
+ /*
+ * Move to the beginning of the line
+ */
+ for (ptr--; ptr >= el->el_line.buffer && *ptr != '\n'; ptr--)
+ continue;
+
+ /*
+ * Move to the character requested
+ */
+ for (ptr++;
+ nchars-- > 0 && ptr < el->el_line.lastchar && *ptr != '\n';
+ ptr++)
+ continue;
+
+ el->el_line.cursor = ptr;
+ return (CC_CURSOR);
+}
+
+
+/* ed_next_line():
+ * Move down one line
+ * Could be [j] [^n]
+ */
+protected el_action_t
+/*ARGSUSED*/
+ed_next_line(EditLine *el, int c __unused)
+{
+ char *ptr;
+ int nchars = c_hpos(el);
+
+ /*
+ * Move to the line requested
+ */
+ for (ptr = el->el_line.cursor; ptr < el->el_line.lastchar; ptr++)
+ if (*ptr == '\n' && --el->el_state.argument <= 0)
+ break;
+
+ if (el->el_state.argument > 0)
+ return (CC_ERROR);
+
+ /*
+ * Move to the character requested
+ */
+ for (ptr++;
+ nchars-- > 0 && ptr < el->el_line.lastchar && *ptr != '\n';
+ ptr++)
+ continue;
+
+ el->el_line.cursor = ptr;
+ return (CC_CURSOR);
+}
+
+
+/* ed_command():
+ * Editline extended command
+ * [M-X] [:]
+ */
+protected el_action_t
+/*ARGSUSED*/
+ed_command(EditLine *el, int c __unused)
+{
+ char tmpbuf[EL_BUFSIZ];
+ int tmplen;
+
+ tmplen = c_gets(el, tmpbuf, "\n: ");
+ term__putc('\n');
+
+ if (tmplen < 0 || (tmpbuf[tmplen] = 0, parse_line(el, tmpbuf)) == -1)
+ term_beep(el);
+
+ el->el_map.current = el->el_map.key;
+ re_clear_display(el);
+ return CC_REFRESH;
+}
diff --git a/lib/libedit/editline.3 b/lib/libedit/editline.3
new file mode 100644
index 0000000..bbabf85
--- /dev/null
+++ b/lib/libedit/editline.3
@@ -0,0 +1,788 @@
+.\" $NetBSD: editline.3,v 1.50 2005/10/12 09:29:43 wiz Exp $
+.\"
+.\" Copyright (c) 1997-2003 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.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the NetBSD
+.\" Foundation, Inc. and its contributors.
+.\" 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 October 4, 2005
+.Os
+.Dt EDITLINE 3
+.Sh NAME
+.Nm editline ,
+.Nm el_init ,
+.Nm el_end ,
+.Nm el_reset ,
+.Nm el_gets ,
+.Nm el_getc ,
+.Nm el_push ,
+.Nm el_parse ,
+.Nm el_set ,
+.Nm el_get ,
+.Nm el_source ,
+.Nm el_resize ,
+.Nm el_line ,
+.Nm el_insertstr ,
+.Nm el_deletestr ,
+.Nm history_init ,
+.Nm history_end ,
+.Nm history ,
+.Nm tok_init ,
+.Nm tok_end ,
+.Nm tok_reset ,
+.Nm tok_line ,
+.Nm tok_str
+.Nd line editor, history and tokenization functions
+.Sh LIBRARY
+.Lb libedit
+.Sh SYNOPSIS
+.In histedit.h
+.Ft EditLine *
+.Fn el_init "const char *prog" "FILE *fin" "FILE *fout" "FILE *ferr"
+.Ft void
+.Fn el_end "EditLine *e"
+.Ft void
+.Fn el_reset "EditLine *e"
+.Ft const char *
+.Fn el_gets "EditLine *e" "int *count"
+.Ft int
+.Fn el_getc "EditLine *e" "char *ch"
+.Ft void
+.Fn el_push "EditLine *e" "char *str"
+.Ft int
+.Fn el_parse "EditLine *e" "int argc" "const char *argv[]"
+.Ft int
+.Fn el_set "EditLine *e" "int op" "..."
+.Ft int
+.Fn el_get "EditLine *e" "int op" "void *result"
+.Ft int
+.Fn el_source "EditLine *e" "const char *file"
+.Ft void
+.Fn el_resize "EditLine *e"
+.Ft const LineInfo *
+.Fn el_line "EditLine *e"
+.Ft int
+.Fn el_insertstr "EditLine *e" "const char *str"
+.Ft void
+.Fn el_deletestr "EditLine *e" "int count"
+.Ft History *
+.Fn history_init
+.Ft void
+.Fn history_end "History *h"
+.Ft int
+.Fn history "History *h" "HistEvent *ev" "int op" "..."
+.Ft Tokenizer *
+.Fn tok_init "const char *IFS"
+.Ft void
+.Fn tok_end "Tokenizer *t"
+.Ft void
+.Fn tok_reset "Tokenizer *t"
+.Ft int
+.Fo tok_line
+.Fa "Tokenizer *t" "const LineInfo *li" "int *argc" "const char **argv[]"
+.Fa "int *cursorc" "int *cursoro"
+.Fc
+.Ft int
+.Fn tok_str "Tokenizer *t" "const char *str" "int *argc" "const char **argv[]"
+.Sh DESCRIPTION
+The
+.Nm
+library provides generic line editing, history and tokenization functions,
+similar to those found in
+.Xr sh 1 .
+.Pp
+These functions are available in the
+.Nm libedit
+library (which needs the
+.Nm libtermcap
+library).
+Programs should be linked with
+.Fl ledit ltermcap .
+.Sh LINE EDITING FUNCTIONS
+The line editing functions use a common data structure,
+.Fa EditLine ,
+which is created by
+.Fn el_init
+and freed by
+.Fn el_end .
+.Pp
+The following functions are available:
+.Bl -tag -width 4n
+.It Fn el_init
+Initialise the line editor, and return a data structure
+to be used by all other line editing functions.
+.Fa prog
+is the name of the invoking program, used when reading the
+.Xr editrc 5
+file to determine which settings to use.
+.Fa fin ,
+.Fa fout
+and
+.Fa ferr
+are the input, output, and error streams (respectively) to use.
+In this documentation, references to
+.Dq the tty
+are actually to this input/output stream combination.
+.It Fn el_end
+Clean up and finish with
+.Fa e ,
+assumed to have been created with
+.Fn el_init .
+.It Fn el_reset
+Reset the tty and the parser.
+This should be called after an error which may have upset the tty's
+state.
+.It Fn el_gets
+Read a line from the tty.
+.Fa count
+is modified to contain the number of characters read.
+Returns the line read if successful, or
+.Dv NULL
+if no characters were read or if an error occurred.
+.It Fn el_getc
+Read a character from the tty.
+.Fa ch
+is modified to contain the character read.
+Returns the number of characters read if successful, \-1 otherwise.
+.It Fn el_push
+Pushes
+.Fa str
+back onto the input stream.
+This is used by the macro expansion mechanism.
+Refer to the description of
+.Ic bind
+.Fl s
+in
+.Xr editrc 5
+for more information.
+.It Fn el_parse
+Parses the
+.Fa argv
+array (which is
+.Fa argc
+elements in size)
+to execute builtin
+.Nm
+commands.
+If the command is prefixed with
+.Dq prog:
+then
+.Fn el_parse
+will only execute the command if
+.Dq prog
+matches the
+.Fa prog
+argument supplied to
+.Fn el_init .
+The return value is
+\-1 if the command is unknown,
+0 if there was no error or
+.Dq prog
+did not match, or
+1 if the command returned an error.
+Refer to
+.Xr editrc 5
+for more information.
+.It Fn el_set
+Set
+.Nm
+parameters.
+.Fa op
+determines which parameter to set, and each operation has its
+own parameter list.
+.Pp
+The following values for
+.Fa op
+are supported, along with the required argument list:
+.Bl -tag -width 4n
+.It Dv EL_PROMPT , Fa "char *(*f)(EditLine *)"
+Define prompt printing function as
+.Fa f ,
+which is to return a string that contains the prompt.
+.It Dv EL_RPROMPT , Fa "char *(*f)(EditLine *)"
+Define right side prompt printing function as
+.Fa f ,
+which is to return a string that contains the prompt.
+.It Dv EL_TERMINAL , Fa "const char *type"
+Define terminal type of the tty to be
+.Fa type ,
+or to
+.Ev TERM
+if
+.Fa type
+is
+.Dv NULL .
+.It Dv EL_EDITOR , Fa "const char *mode"
+Set editing mode to
+.Fa mode ,
+which must be one of
+.Dq emacs
+or
+.Dq vi .
+.It Dv EL_SIGNAL , Fa "int flag"
+If
+.Fa flag
+is non-zero,
+.Nm
+will install its own signal handler for the following signals when
+reading command input:
+.Dv SIGCONT ,
+.Dv SIGHUP ,
+.Dv SIGINT ,
+.Dv SIGQUIT ,
+.Dv SIGSTOP ,
+.Dv SIGTERM ,
+.Dv SIGTSTP ,
+and
+.Dv SIGWINCH .
+Otherwise, the current signal handlers will be used.
+.It Dv EL_BIND , Xo
+.Fa "const char *" ,
+.Fa "..." ,
+.Dv NULL
+.Xc
+Perform the
+.Ic bind
+builtin command.
+Refer to
+.Xr editrc 5
+for more information.
+.It Dv EL_ECHOTC , Xo
+.Fa "const char *" ,
+.Fa "..." ,
+.Dv NULL
+.Xc
+Perform the
+.Ic echotc
+builtin command.
+Refer to
+.Xr editrc 5
+for more information.
+.It Dv EL_SETTC , Xo
+.Fa "const char *" ,
+.Fa "..." ,
+.Dv NULL
+.Xc
+Perform the
+.Ic settc
+builtin command.
+Refer to
+.Xr editrc 5
+for more information.
+.It Dv EL_SETTY , Xo
+.Fa "const char *" ,
+.Fa "..." ,
+.Dv NULL
+.Xc
+Perform the
+.Ic setty
+builtin command.
+Refer to
+.Xr editrc 5
+for more information.
+.It Dv EL_TELLTC , Xo
+.Fa "const char *" ,
+.Fa "..." ,
+.Dv NULL
+.Xc
+Perform the
+.Ic telltc
+builtin command.
+Refer to
+.Xr editrc 5
+for more information.
+.It Dv EL_ADDFN , Xo
+.Fa "const char *name" ,
+.Fa "const char *help" ,
+.Fa "unsigned char (*func)(EditLine *e, int ch)"
+.Xc
+Add a user defined function,
+.Fn func ,
+referred to as
+.Fa name
+which is invoked when a key which is bound to
+.Fa name
+is entered.
+.Fa help
+is a description of
+.Fa name .
+At invocation time,
+.Fa ch
+is the key which caused the invocation.
+The return value of
+.Fn func
+should be one of:
+.Bl -tag -width "CC_REDISPLAY"
+.It Dv CC_NORM
+Add a normal character.
+.It Dv CC_NEWLINE
+End of line was entered.
+.It Dv CC_EOF
+EOF was entered.
+.It Dv CC_ARGHACK
+Expecting further command input as arguments, do nothing visually.
+.It Dv CC_REFRESH
+Refresh display.
+.It Dv CC_REFRESH_BEEP
+Refresh display, and beep.
+.It Dv CC_CURSOR
+Cursor moved, so update and perform
+.Dv CC_REFRESH .
+.It Dv CC_REDISPLAY
+Redisplay entire input line.
+This is useful if a key binding outputs extra information.
+.It Dv CC_ERROR
+An error occurred.
+Beep, and flush tty.
+.It Dv CC_FATAL
+Fatal error, reset tty to known state.
+.El
+.It Dv EL_HIST , Xo
+.Fa "History *(*func)(History *, int op, ...)" ,
+.Fa "const char *ptr"
+.Xc
+Defines which history function to use, which is usually
+.Fn history .
+.Fa ptr
+should be the value returned by
+.Fn history_init .
+.It Dv EL_EDITMODE , Fa "int flag"
+If
+.Fa flag
+is non-zero,
+editing is enabled (the default).
+Note that this is only an indication, and does not
+affect the operation of
+.Nm .
+At this time, it is the caller's responsibility to
+check this
+(using
+.Fn el_get )
+to determine if editing should be enabled or not.
+.It Dv EL_GETCFN , Fa "int (*f)(EditLine *, char *c)"
+Define the character reading function as
+.Fa f ,
+which is to return the number of characters read and store them in
+.Fa c .
+This function is called internally by
+.Fn el_gets
+and
+.Fn el_getc .
+The builtin function can be set or restored with the special function
+name
+.Dv EL_BUILTIN_GETCFN .
+.It Dv EL_CLIENTDATA , Fa "void *data"
+Register
+.Fa data
+to be associated with this EditLine structure.
+It can be retrieved with the corresponding
+.Fn el_get
+call.
+.El
+.It Fn el_get
+Get
+.Nm
+parameters.
+.Fa op
+determines which parameter to retrieve into
+.Fa result .
+Returns 0 if successful, \-1 otherwise.
+.Pp
+The following values for
+.Fa op
+are supported, along with actual type of
+.Fa result :
+.Bl -tag -width 4n
+.It Dv EL_PROMPT , Fa "char *(*f)(EditLine *)"
+Return a pointer to the function that displays the prompt.
+.It Dv EL_RPROMPT , Fa "char *(*f)(EditLine *)"
+Return a pointer to the function that displays the rightside prompt.
+.It Dv EL_EDITOR , Fa "const char *"
+Return the name of the editor, which will be one of
+.Dq emacs
+or
+.Dq vi .
+.It Dv EL_SIGNAL , Fa "int *"
+Return non-zero if
+.Nm
+has installed private signal handlers (see
+.Fn el_get
+above).
+.It Dv EL_EDITMODE, Fa "int *"
+Return non-zero if editing is enabled.
+.It Dv EL_GETCFN, Fa "int (**f)(EditLine *, char *)"
+Return a pointer to the function that read characters, which is equal to
+.Dv EL_BUILTIN_GETCFN
+in the case of the default builtin function.
+.It Dv EL_CLIENTDATA , Fa "void **data"
+Retrieve
+.Fa data
+previously registered with the corresponding
+.Fn el_set
+call.
+.It Dv EL_UNBUFFERED, Fa "int"
+Sets or clears unbuffered mode.
+In this mode,
+.Fn el_gets
+will return immediately after processing a single character.
+.It Dv EL_PREP_TERM, Fa "int"
+Sets or clears terminal editing mode.
+.El
+.It Fn el_source
+Initialise
+.Nm
+by reading the contents of
+.Fa file .
+.Fn el_parse
+is called for each line in
+.Fa file .
+If
+.Fa file
+is
+.Dv NULL ,
+try
+.Pa $PWD/.editrc
+then
+.Pa $HOME/.editrc .
+Refer to
+.Xr editrc 5
+for details on the format of
+.Fa file .
+.It Fn el_resize
+Must be called if the terminal size changes.
+If
+.Dv EL_SIGNAL
+has been set with
+.Fn el_set ,
+then this is done automatically.
+Otherwise, it is the responsibility of the application to call
+.Fn el_resize
+on the appropriate occasions.
+.It Fn el_line
+Return the editing information for the current line in a
+.Fa LineInfo
+structure, which is defined as follows:
+.Bd -literal
+typedef struct lineinfo {
+ const char *buffer; /* address of buffer */
+ const char *cursor; /* address of cursor */
+ const char *lastchar; /* address of last character */
+} LineInfo;
+.Ed
+.Pp
+.Fa buffer
+is not NUL terminated.
+This function may be called after
+.Fn el_gets
+to obtain the
+.Fa LineInfo
+structure pertaining to line returned by that function,
+and from within user defined functions added with
+.Dv EL_ADDFN .
+.It Fn el_insertstr
+Insert
+.Fa str
+into the line at the cursor.
+Returns \-1 if
+.Fa str
+is empty or will not fit, and 0 otherwise.
+.It Fn el_deletestr
+Delete
+.Fa num
+characters before the cursor.
+.El
+.Sh HISTORY LIST FUNCTIONS
+The history functions use a common data structure,
+.Fa History ,
+which is created by
+.Fn history_init
+and freed by
+.Fn history_end .
+.Pp
+The following functions are available:
+.Bl -tag -width 4n
+.It Fn history_init
+Initialise the history list, and return a data structure
+to be used by all other history list functions.
+.It Fn history_end
+Clean up and finish with
+.Fa h ,
+assumed to have been created with
+.Fn history_init .
+.It Fn history
+Perform operation
+.Fa op
+on the history list, with optional arguments as needed by the
+operation.
+.Fa ev
+is changed accordingly to operation.
+The following values for
+.Fa op
+are supported, along with the required argument list:
+.Bl -tag -width 4n
+.It Dv H_SETSIZE , Fa "int size"
+Set size of history to
+.Fa size
+elements.
+.It Dv H_GETSIZE
+Get number of events currently in history.
+.It Dv H_END
+Cleans up and finishes with
+.Fa h ,
+assumed to be created with
+.Fn history_init .
+.It Dv H_CLEAR
+Clear the history.
+.It Dv H_FUNC , Xo
+.Fa "void *ptr" ,
+.Fa "history_gfun_t first" ,
+.Fa "history_gfun_t next" ,
+.Fa "history_gfun_t last" ,
+.Fa "history_gfun_t prev" ,
+.Fa "history_gfun_t curr" ,
+.Fa "history_sfun_t set" ,
+.Fa "history_vfun_t clear" ,
+.Fa "history_efun_t enter" ,
+.Fa "history_efun_t add"
+.Xc
+Define functions to perform various history operations.
+.Fa ptr
+is the argument given to a function when it is invoked.
+.It Dv H_FIRST
+Return the first element in the history.
+.It Dv H_LAST
+Return the last element in the history.
+.It Dv H_PREV
+Return the previous element in the history.
+.It Dv H_NEXT
+Return the next element in the history.
+.It Dv H_CURR
+Return the current element in the history.
+.It Dv H_SET
+Set the cursor to point to the requested element.
+.It Dv H_ADD , Fa "const char *str"
+Append
+.Fa str
+to the current element of the history, or perform the
+.Dv H_ENTER
+operation with argument
+.Fa str
+if there is no current element.
+.It Dv H_APPEND , Fa "const char *str"
+Append
+.Fa str
+to the last new element of the history.
+.It Dv H_ENTER , Fa "const char *str"
+Add
+.Fa str
+as a new element to the history, and, if necessary,
+removing the oldest entry to keep the list to the created size.
+If
+.Dv H_SETUNIQUE
+was has been called with a non-zero arguments, the element
+will not be entered into the history if its contents match
+the ones of the current history element.
+If the element is entered
+.Fn history
+returns 1, if it is ignored as a duplicate returns 0.
+Finally
+.Fn history
+returns \-1 if an error occurred.
+.It Dv H_PREV_STR , Fa "const char *str"
+Return the closest previous event that starts with
+.Fa str .
+.It Dv H_NEXT_STR , Fa "const char *str"
+Return the closest next event that starts with
+.Fa str .
+.It Dv H_PREV_EVENT , Fa "int e"
+Return the previous event numbered
+.Fa e .
+.It Dv H_NEXT_EVENT , Fa "int e"
+Return the next event numbered
+.Fa e .
+.It Dv H_LOAD , Fa "const char *file"
+Load the history list stored in
+.Fa file .
+.It Dv H_SAVE , Fa "const char *file"
+Save the history list to
+.Fa file .
+.It Dv H_SETUNIQUE , Fa "int unique"
+Set flag that adjacent identical event strings should not be entered
+into the history.
+.It Dv H_GETUNIQUE
+Retrieve the current setting if adjacent identical elements should
+be entered into the history.
+.It Dv H_DEL , Fa "int num"
+Delete the event numbered
+.Fa e .
+This function is only provided for
+.Xr readline 3
+compatibility.
+The caller is responsible for free'ing the string in the returned
+.Fa HistEvent .
+.El
+.Pp
+The
+.Fn history
+function returns \*[Ge] 0 if the operation
+.Fa op
+succeeds.
+Otherwise, \-1 is returned and
+.Fa ev
+is updated to contain more details about the error.
+.El
+.Sh TOKENIZATION FUNCTIONS
+The tokenization functions use a common data structure,
+.Fa Tokenizer ,
+which is created by
+.Fn tok_init
+and freed by
+.Fn tok_end .
+.Pp
+The following functions are available:
+.Bl -tag -width 4n
+.It Fn tok_init
+Initialise the tokenizer, and return a data structure
+to be used by all other tokenizer functions.
+.Fa IFS
+contains the Input Field Separators, which defaults to
+.Aq space ,
+.Aq tab ,
+and
+.Aq newline
+if
+.Dv NULL .
+.It Fn tok_end
+Clean up and finish with
+.Fa t ,
+assumed to have been created with
+.Fn tok_init .
+.It Fn tok_reset
+Reset the tokenizer state.
+Use after a line has been successfully tokenized
+by
+.Fn tok_line
+or
+.Fn tok_str
+and before a new line is to be tokenized.
+.It Fn tok_line
+Tokenize
+.Fa li ,
+If successful, modify:
+.Fa argv
+to contain the words,
+.Fa argc
+to contain the number of words,
+.Fa cursorc
+(if not
+.Dv NULL )
+to contain the index of the word containing the cursor,
+and
+.Fa cursoro
+(if not
+.Dv NULL )
+to contain the offset within
+.Fa argv[cursorc]
+of the cursor.
+.Pp
+Returns
+0 if successful,
+\-1 for an internal error,
+1 for an unmatched single quote,
+2 for an unmatched double quote,
+and
+3 for a backslash quoted
+.Aq newline .
+A positive exit code indicates that another line should be read
+and tokenization attempted again.
+.It Fn tok_str
+A simpler form of
+.Fn tok_line ;
+.Fa str
+is a NUL terminated string to tokenize.
+.El
+.\"XXX.Sh EXAMPLES
+.\"XXX: provide some examples
+.Sh SEE ALSO
+.Xr sh 1 ,
+.Xr signal 3 ,
+.Xr termcap 3 ,
+.Xr editrc 5
+.Sh HISTORY
+The
+.Nm
+library first appeared in
+.Bx 4.4 .
+.Dv CC_REDISPLAY
+appeared in
+.Nx 1.3 .
+.Dv CC_REFRESH_BEEP
+and
+.Dv EL_EDITMODE
+appeared in
+.Nx 1.4 .
+.Dv EL_RPROMPT
+appeared in
+.Nx 1.5 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+library was written by
+.An Christos Zoulas .
+.An Luke Mewburn
+wrote this manual and implemented
+.Dv CC_REDISPLAY ,
+.Dv CC_REFRESH_BEEP ,
+.Dv EL_EDITMODE ,
+and
+.Dv EL_RPROMPT .
+.Sh BUGS
+At this time, it is the responsibility of the caller to
+check the result of the
+.Dv EL_EDITMODE
+operation of
+.Fn el_get
+(after an
+.Fn el_source
+or
+.Fn el_parse )
+to determine if
+.Nm
+should be used for further input.
+I.e.,
+.Dv EL_EDITMODE
+is purely an indication of the result of the most recent
+.Xr editrc 5
+.Ic edit
+command.
diff --git a/lib/libedit/editrc.5 b/lib/libedit/editrc.5
new file mode 100644
index 0000000..0624e18
--- /dev/null
+++ b/lib/libedit/editrc.5
@@ -0,0 +1,516 @@
+.\" $NetBSD: editrc.5,v 1.19 2003/11/01 23:35:33 christos Exp $
+.\"
+.\" Copyright (c) 1997-2000 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.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the NetBSD
+.\" Foundation, Inc. and its contributors.
+.\" 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 October 18, 2003
+.Os
+.Dt EDITRC 5
+.Sh NAME
+.Nm editrc
+.Nd configuration file for editline library
+.Sh SYNOPSIS
+.Nm
+.Sh DESCRIPTION
+The
+.Nm
+file defines various settings to be used by the
+.Xr editline 3
+library.
+.Pp
+The format of each line is:
+.Dl [prog:]command [arg [...]]
+.Pp
+.Ar command
+is one of the
+.Xr editline 3
+builtin commands.
+Refer to
+.Sx BUILTIN COMMANDS
+for more information.
+.Pp
+.Ar prog
+is the program name string that a program defines when it calls
+.Xr el_init 3
+to set up
+.Xr editline 3 ,
+which is usually
+.Va argv[0] .
+.Ar command
+will be executed for any program which matches
+.Ar prog .
+.Pp
+.Ar prog
+may also be a
+.Xr regex 3
+style
+regular expression, in which case
+.Ar command
+will be executed for any program that matches the regular expression.
+.Pp
+If
+.Ar prog
+is absent,
+.Ar command
+is executed for all programs.
+.Sh BUILTIN COMMANDS
+The
+.Nm editline
+library has some builtin commands, which affect the way
+that the line editing and history functions operate.
+These are based on similar named builtins present in the
+.Xr tcsh 1
+shell.
+.Pp
+The following builtin commands are available:
+.Bl -tag -width 4n
+.It Ic bind Xo
+.Op Fl a
+.Op Fl e
+.Op Fl k
+.Op Fl l
+.Op Fl r
+.Op Fl s
+.Op Fl v
+.Op Ar key Op Ar command
+.Xc
+Without options, list all bound keys, and the editor command to which
+each is bound.
+If
+.Ar key
+is supplied, show the bindings for
+.Ar key .
+If
+.Ar key command
+is supplied, bind
+.Ar command
+to
+.Ar key .
+Options include:
+.Bl -tag -width 4n
+.It Fl e
+Bind all keys to the standard GNU Emacs-like bindings.
+.It Fl v
+Bind all keys to the standard
+.Xr vi 1 Ns -like
+bindings.
+.It Fl a
+List or change key bindings in the
+.Xr vi 1
+mode alternate (command mode) key map.
+.It Fl k
+.Ar key
+is interpreted as a symbolic arrow key name, which may be one of
+.Sq up ,
+.Sq down ,
+.Sq left
+or
+.Sq right .
+.It Fl l
+List all editor commands and a short description of each.
+.It Fl r
+Remove a key's binding.
+.It Fl s
+.Ar command
+is taken as a literal string and treated as terminal input when
+.Ar key
+is typed.
+Bound keys in
+.Ar command
+are themselves reinterpreted, and this continues for ten levels of
+interpretation.
+.El
+.Pp
+.Ar command
+may be one of the commands documented in
+.Sx "EDITOR COMMANDS"
+below, or another key.
+.Pp
+.Ar key
+and
+.Ar command
+can contain control characters of the form
+.Sm off
+.Sq No ^ Ar character
+.Sm on
+(e.g.\&
+.Sq ^A ) ,
+and the following backslashed escape sequences:
+.Pp
+.Bl -tag -compact -offset indent -width 4n
+.It Ic \ea
+Bell
+.It Ic \eb
+Backspace
+.It Ic \ee
+Escape
+.It Ic \ef
+Formfeed
+.It Ic \en
+Newline
+.It Ic \er
+Carriage return
+.It Ic \et
+Horizontal tab
+.It Ic \ev
+Vertical tab
+.Sm off
+.It Sy \e Ar nnn
+.Sm on
+The ASCII character corresponding to the octal number
+.Ar nnn .
+.El
+.Pp
+.Sq \e
+nullifies the special meaning of the following character,
+if it has any, notably
+.Sq \e
+and
+.Sq ^ .
+.It Ic echotc Xo
+.Op Fl sv
+.Ar arg
+.Ar ...
+.Xc
+Exercise terminal capabilities given in
+.Ar arg Ar ... .
+If
+.Ar arg
+is
+.Sq baud ,
+.Sq cols ,
+.Sq lines ,
+.Sq rows ,
+.Sq meta or
+.Sq tabs ,
+the value of that capability is printed, with
+.Dq yes
+or
+.Dq no
+indicating that the terminal does or does not have that capability.
+.Pp
+.Fl s
+returns an empty string for non-existent capabilities, rather than
+causing an error.
+.Fl v
+causes messages to be verbose.
+.It Ic edit Op Cm on | off
+Enable or disable the
+.Nm editline
+functionality in a program.
+.It Ic history Ar list | Ar size Dv n | Ar unique Dv n
+The
+.Ar list
+command lists all entries in the history.
+The
+.Ar size
+command sets the history size to
+.Dv n
+entries.
+The
+.Ar unique
+command controls if history should keep duplicate entries.
+If
+.Dv n
+is non zero, only keep unique history entries.
+If
+.Dv n
+is zero, then keep all entries (the default).
+.It Ic telltc
+List the values of all the terminal capabilities (see
+.Xr termcap 5 ) .
+.It Ic settc Ar cap Ar val
+Set the terminal capability
+.Ar cap
+to
+.Ar val ,
+as defined in
+.Xr termcap 5 .
+No sanity checking is done.
+.It Ic setty Xo
+.Op Fl a
+.Op Fl d
+.Op Fl q
+.Op Fl x
+.Op Ar +mode
+.Op Ar -mode
+.Op Ar mode
+.Op Ar char=c
+.Xc
+Control which tty modes that
+.Nm
+will not allow the user to change.
+.Fl d ,
+.Fl q
+or
+.Fl x
+tells
+.Ic setty
+to act on the
+.Sq edit ,
+.Sq quote
+or
+.Sq execute
+set of tty modes respectively; defaulting to
+.Fl x .
+.Pp
+Without other arguments,
+.Ic setty
+lists the modes in the chosen set which are fixed on
+.Pq Sq +mode
+or off
+.Pq Sq -mode .
+.Fl a
+lists all tty modes in the chosen set regardless of the setting.
+With
+.Ar +mode ,
+.Ar -mode
+or
+.Ar mode ,
+fixes
+.Ar mode
+on or off or removes control of
+.Ar mode
+in the chosen set.
+.Pp
+.Ic Setty
+can also be used to set tty characters to particular values using
+.Ar char=value .
+If
+.Ar value
+is empty
+then the character is set to
+.Dv _POSIX_VDISABLE .
+.El
+.Sh EDITOR COMMANDS
+The following editor commands are available for use in key bindings:
+.\" Section automatically generated with makelist
+.Bl -tag -width 4n
+.It Ic vi-paste-next
+Vi paste previous deletion to the right of the cursor.
+.It Ic vi-paste-prev
+Vi paste previous deletion to the left of the cursor.
+.It Ic vi-prev-space-word
+Vi move to the previous space delimited word.
+.It Ic vi-prev-word
+Vi move to the previous word.
+.It Ic vi-next-space-word
+Vi move to the next space delimited word.
+.It Ic vi-next-word
+Vi move to the next word.
+.It Ic vi-change-case
+Vi change case of character under the cursor and advance one character.
+.It Ic vi-change-meta
+Vi change prefix command.
+.It Ic vi-insert-at-bol
+Vi enter insert mode at the beginning of line.
+.It Ic vi-replace-char
+Vi replace character under the cursor with the next character typed.
+.It Ic vi-replace-mode
+Vi enter replace mode.
+.It Ic vi-substitute-char
+Vi replace character under the cursor and enter insert mode.
+.It Ic vi-substitute-line
+Vi substitute entire line.
+.It Ic vi-change-to-eol
+Vi change to end of line.
+.It Ic vi-insert
+Vi enter insert mode.
+.It Ic vi-add
+Vi enter insert mode after the cursor.
+.It Ic vi-add-at-eol
+Vi enter insert mode at end of line.
+.It Ic vi-delete-meta
+Vi delete prefix command.
+.It Ic vi-end-word
+Vi move to the end of the current space delimited word.
+.It Ic vi-to-end-word
+Vi move to the end of the current word.
+.It Ic vi-undo
+Vi undo last change.
+.It Ic vi-command-mode
+Vi enter command mode (use alternative key bindings).
+.It Ic vi-zero
+Vi move to the beginning of line.
+.It Ic vi-delete-prev-char
+Vi move to previous character (backspace).
+.It Ic vi-list-or-eof
+Vi list choices for completion or indicate end of file if empty line.
+.It Ic vi-kill-line-prev
+Vi cut from beginning of line to cursor.
+.It Ic vi-search-prev
+Vi search history previous.
+.It Ic vi-search-next
+Vi search history next.
+.It Ic vi-repeat-search-next
+Vi repeat current search in the same search direction.
+.It Ic vi-repeat-search-prev
+Vi repeat current search in the opposite search direction.
+.It Ic vi-next-char
+Vi move to the character specified next.
+.It Ic vi-prev-char
+Vi move to the character specified previous.
+.It Ic vi-to-next-char
+Vi move up to the character specified next.
+.It Ic vi-to-prev-char
+Vi move up to the character specified previous.
+.It Ic vi-repeat-next-char
+Vi repeat current character search in the same search direction.
+.It Ic vi-repeat-prev-char
+Vi repeat current character search in the opposite search direction.
+.It Ic em-delete-or-list
+Delete character under cursor or list completions if at end of line.
+.It Ic em-delete-next-word
+Cut from cursor to end of current word.
+.It Ic em-yank
+Paste cut buffer at cursor position.
+.It Ic em-kill-line
+Cut the entire line and save in cut buffer.
+.It Ic em-kill-region
+Cut area between mark and cursor and save in cut buffer.
+.It Ic em-copy-region
+Copy area between mark and cursor to cut buffer.
+.It Ic em-gosmacs-transpose
+Exchange the two characters before the cursor.
+.It Ic em-next-word
+Move next to end of current word.
+.It Ic em-upper-case
+Uppercase the characters from cursor to end of current word.
+.It Ic em-capitol-case
+Capitalize the characters from cursor to end of current word.
+.It Ic em-lower-case
+Lowercase the characters from cursor to end of current word.
+.It Ic em-set-mark
+Set the mark at cursor.
+.It Ic em-exchange-mark
+Exchange the cursor and mark.
+.It Ic em-universal-argument
+Universal argument (argument times 4).
+.It Ic em-meta-next
+Add 8th bit to next character typed.
+.It Ic em-toggle-overwrite
+Switch from insert to overwrite mode or vice versa.
+.It Ic em-copy-prev-word
+Copy current word to cursor.
+.It Ic em-inc-search-next
+Emacs incremental next search.
+.It Ic em-inc-search-prev
+Emacs incremental reverse search.
+.It Ic ed-end-of-file
+Indicate end of file.
+.It Ic ed-insert
+Add character to the line.
+.It Ic ed-delete-prev-word
+Delete from beginning of current word to cursor.
+.It Ic ed-delete-next-char
+Delete character under cursor.
+.It Ic ed-kill-line
+Cut to the end of line.
+.It Ic ed-move-to-end
+Move cursor to the end of line.
+.It Ic ed-move-to-beg
+Move cursor to the beginning of line.
+.It Ic ed-transpose-chars
+Exchange the character to the left of the cursor with the one under it.
+.It Ic ed-next-char
+Move to the right one character.
+.It Ic ed-prev-word
+Move to the beginning of the current word.
+.It Ic ed-prev-char
+Move to the left one character.
+.It Ic ed-quoted-insert
+Add the next character typed verbatim.
+.It Ic ed-digit
+Adds to argument or enters a digit.
+.It Ic ed-argument-digit
+Digit that starts argument.
+.It Ic ed-unassigned
+Indicates unbound character.
+.It Ic ed-tty-sigint
+Tty interrupt character.
+.It Ic ed-tty-dsusp
+Tty delayed suspend character.
+.It Ic ed-tty-flush-output
+Tty flush output characters.
+.It Ic ed-tty-sigquit
+Tty quit character.
+.It Ic ed-tty-sigtstp
+Tty suspend character.
+.It Ic ed-tty-stop-output
+Tty disallow output characters.
+.It Ic ed-tty-start-output
+Tty allow output characters.
+.It Ic ed-newline
+Execute command.
+.It Ic ed-delete-prev-char
+Delete the character to the left of the cursor.
+.It Ic ed-clear-screen
+Clear screen leaving current line at the top.
+.It Ic ed-redisplay
+Redisplay everything.
+.It Ic ed-start-over
+Erase current line and start from scratch.
+.It Ic ed-sequence-lead-in
+First character in a bound sequence.
+.It Ic ed-prev-history
+Move to the previous history line.
+.It Ic ed-next-history
+Move to the next history line.
+.It Ic ed-search-prev-history
+Search previous in history for a line matching the current.
+.It Ic ed-search-next-history
+Search next in history for a line matching the current.
+.It Ic ed-prev-line
+Move up one line.
+.It Ic ed-next-line
+Move down one line.
+.It Ic ed-command
+Editline extended command.
+.El
+.\" End of section automatically generated with makelist
+.Sh SEE ALSO
+.Xr editline 3 ,
+.Xr regex 3 ,
+.Xr termcap 5
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm editline
+library was written by
+.An Christos Zoulas ,
+and this manual was written by
+.An Luke Mewburn ,
+with some sections inspired by
+.Xr tcsh 1 .
diff --git a/lib/libedit/el.c b/lib/libedit/el.c
new file mode 100644
index 0000000..4da3113
--- /dev/null
+++ b/lib/libedit/el.c
@@ -0,0 +1,562 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell 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.
+ *
+ * $NetBSD: el.c,v 1.41 2005/08/19 04:21:47 christos Exp $
+ */
+
+#if !defined(lint) && !defined(SCCSID)
+static char sccsid[] = "@(#)el.c 8.2 (Berkeley) 1/3/94";
+#endif /* not lint && not SCCSID */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * el.c: EditLine interface functions
+ */
+#include "sys.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include "el.h"
+
+#define HAVE_ISSETUGID
+
+/* el_init():
+ * Initialize editline and set default parameters.
+ */
+public EditLine *
+el_init(const char *prog, FILE *fin, FILE *fout, FILE *ferr)
+{
+
+ EditLine *el = (EditLine *) el_malloc(sizeof(EditLine));
+
+ if (el == NULL)
+ return (NULL);
+
+ memset(el, 0, sizeof(EditLine));
+
+ el->el_infd = fileno(fin);
+ el->el_outfile = fout;
+ el->el_errfile = ferr;
+ if ((el->el_prog = el_strdup(prog)) == NULL) {
+ el_free(el);
+ return NULL;
+ }
+
+ /*
+ * Initialize all the modules. Order is important!!!
+ */
+ el->el_flags = 0;
+
+ if (term_init(el) == -1) {
+ el_free(el->el_prog);
+ el_free(el);
+ return NULL;
+ }
+ (void) key_init(el);
+ (void) map_init(el);
+ if (tty_init(el) == -1)
+ el->el_flags |= NO_TTY;
+ (void) ch_init(el);
+ (void) search_init(el);
+ (void) hist_init(el);
+ (void) prompt_init(el);
+ (void) sig_init(el);
+ (void) read_init(el);
+
+ return (el);
+}
+
+
+/* el_end():
+ * Clean up.
+ */
+public void
+el_end(EditLine *el)
+{
+
+ if (el == NULL)
+ return;
+
+ el_reset(el);
+
+ term_end(el);
+ key_end(el);
+ map_end(el);
+ tty_end(el);
+ ch_end(el);
+ search_end(el);
+ hist_end(el);
+ prompt_end(el);
+ sig_end(el);
+
+ el_free((ptr_t) el->el_prog);
+ el_free((ptr_t) el);
+}
+
+
+/* el_reset():
+ * Reset the tty and the parser
+ */
+public void
+el_reset(EditLine *el)
+{
+
+ tty_cookedmode(el);
+ ch_reset(el, 0); /* XXX: Do we want that? */
+}
+
+
+/* el_set():
+ * set the editline parameters
+ */
+public int
+el_set(EditLine *el, int op, ...)
+{
+ va_list va;
+ int rv = 0;
+
+ if (el == NULL)
+ return (-1);
+ va_start(va, op);
+
+ switch (op) {
+ case EL_PROMPT:
+ case EL_RPROMPT:
+ rv = prompt_set(el, va_arg(va, el_pfunc_t), op);
+ break;
+
+ case EL_TERMINAL:
+ rv = term_set(el, va_arg(va, char *));
+ break;
+
+ case EL_EDITOR:
+ rv = map_set_editor(el, va_arg(va, char *));
+ break;
+
+ case EL_SIGNAL:
+ if (va_arg(va, int))
+ el->el_flags |= HANDLE_SIGNALS;
+ else
+ el->el_flags &= ~HANDLE_SIGNALS;
+ break;
+
+ case EL_BIND:
+ case EL_TELLTC:
+ case EL_SETTC:
+ case EL_ECHOTC:
+ case EL_SETTY:
+ {
+ const char *argv[20];
+ int i;
+
+ for (i = 1; i < 20; i++)
+ if ((argv[i] = va_arg(va, char *)) == NULL)
+ break;
+
+ switch (op) {
+ case EL_BIND:
+ argv[0] = "bind";
+ rv = map_bind(el, i, argv);
+ break;
+
+ case EL_TELLTC:
+ argv[0] = "telltc";
+ rv = term_telltc(el, i, argv);
+ break;
+
+ case EL_SETTC:
+ argv[0] = "settc";
+ rv = term_settc(el, i, argv);
+ break;
+
+ case EL_ECHOTC:
+ argv[0] = "echotc";
+ rv = term_echotc(el, i, argv);
+ break;
+
+ case EL_SETTY:
+ argv[0] = "setty";
+ rv = tty_stty(el, i, argv);
+ break;
+
+ default:
+ rv = -1;
+ EL_ABORT((el->el_errfile, "Bad op %d\n", op));
+ break;
+ }
+ break;
+ }
+
+ case EL_ADDFN:
+ {
+ char *name = va_arg(va, char *);
+ char *help = va_arg(va, char *);
+ el_func_t func = va_arg(va, el_func_t);
+
+ rv = map_addfunc(el, name, help, func);
+ break;
+ }
+
+ case EL_HIST:
+ {
+ hist_fun_t func = va_arg(va, hist_fun_t);
+ ptr_t ptr = va_arg(va, char *);
+
+ rv = hist_set(el, func, ptr);
+ break;
+ }
+
+ case EL_EDITMODE:
+ if (va_arg(va, int))
+ el->el_flags &= ~EDIT_DISABLED;
+ else
+ el->el_flags |= EDIT_DISABLED;
+ rv = 0;
+ break;
+
+ case EL_GETCFN:
+ {
+ el_rfunc_t rc = va_arg(va, el_rfunc_t);
+ rv = el_read_setfn(el, rc);
+ break;
+ }
+
+ case EL_CLIENTDATA:
+ el->el_data = va_arg(va, void *);
+ break;
+
+ case EL_UNBUFFERED:
+ rv = va_arg(va, int);
+ if (rv && !(el->el_flags & UNBUFFERED)) {
+ el->el_flags |= UNBUFFERED;
+ read_prepare(el);
+ } else if (!rv && (el->el_flags & UNBUFFERED)) {
+ el->el_flags &= ~UNBUFFERED;
+ read_finish(el);
+ }
+ rv = 0;
+ break;
+
+ case EL_PREP_TERM:
+ rv = va_arg(va, int);
+ if (rv)
+ (void) tty_rawmode(el);
+ else
+ (void) tty_cookedmode(el);
+ rv = 0;
+ break;
+
+ default:
+ rv = -1;
+ break;
+ }
+
+ va_end(va);
+ return (rv);
+}
+
+
+/* el_get():
+ * retrieve the editline parameters
+ */
+public int
+el_get(EditLine *el, int op, void *ret)
+{
+ int rv;
+
+ if (el == NULL || ret == NULL)
+ return (-1);
+ switch (op) {
+ case EL_PROMPT:
+ case EL_RPROMPT:
+ rv = prompt_get(el, (el_pfunc_t *) ret, op);
+ break;
+
+ case EL_EDITOR:
+ rv = map_get_editor(el, (const char **)ret);
+ break;
+
+ case EL_SIGNAL:
+ *((int *) ret) = (el->el_flags & HANDLE_SIGNALS);
+ rv = 0;
+ break;
+
+ case EL_EDITMODE:
+ *((int *) ret) = (!(el->el_flags & EDIT_DISABLED));
+ rv = 0;
+ break;
+
+ case EL_TERMINAL:
+ term_get(el, (const char **)ret);
+ rv = 0;
+ break;
+
+#if 0 /* XXX */
+ case EL_BIND:
+ case EL_TELLTC:
+ case EL_SETTC:
+ case EL_ECHOTC:
+ case EL_SETTY:
+ {
+ const char *argv[20];
+ int i;
+
+ for (i = 1; i < sizeof(argv) / sizeof(argv[0]); i++)
+ if ((argv[i] = va_arg(va, char *)) == NULL)
+ break;
+
+ switch (op) {
+ case EL_BIND:
+ argv[0] = "bind";
+ rv = map_bind(el, i, argv);
+ break;
+
+ case EL_TELLTC:
+ argv[0] = "telltc";
+ rv = term_telltc(el, i, argv);
+ break;
+
+ case EL_SETTC:
+ argv[0] = "settc";
+ rv = term_settc(el, i, argv);
+ break;
+
+ case EL_ECHOTC:
+ argv[0] = "echotc";
+ rv = term_echotc(el, i, argv);
+ break;
+
+ case EL_SETTY:
+ argv[0] = "setty";
+ rv = tty_stty(el, i, argv);
+ break;
+
+ default:
+ rv = -1;
+ EL_ABORT((el->errfile, "Bad op %d\n", op));
+ break;
+ }
+ break;
+ }
+
+ case EL_ADDFN:
+ {
+ char *name = va_arg(va, char *);
+ char *help = va_arg(va, char *);
+ el_func_t func = va_arg(va, el_func_t);
+
+ rv = map_addfunc(el, name, help, func);
+ break;
+ }
+
+ case EL_HIST:
+ {
+ hist_fun_t func = va_arg(va, hist_fun_t);
+ ptr_t ptr = va_arg(va, char *);
+ rv = hist_set(el, func, ptr);
+ }
+ break;
+#endif /* XXX */
+
+ case EL_GETCFN:
+ *((el_rfunc_t *)ret) = el_read_getfn(el);
+ rv = 0;
+ break;
+
+ case EL_CLIENTDATA:
+ *((void **)ret) = el->el_data;
+ rv = 0;
+ break;
+
+ case EL_UNBUFFERED:
+ *((int *) ret) = (!(el->el_flags & UNBUFFERED));
+ rv = 0;
+ break;
+
+ default:
+ rv = -1;
+ }
+
+ return (rv);
+}
+
+/* el_data_get():
+ * Set user private data.
+ */
+public void
+el_data_set (el, data)
+ EditLine *el;
+ void *data;
+{
+ el->el_data = data;
+
+ return;
+}
+
+/* el_data_get():
+ * Return user private data.
+ */
+public void *
+el_data_get (el)
+ EditLine *el;
+{
+ if (el->el_data)
+ return (el->el_data);
+ return (NULL);
+}
+
+/* el_line():
+ * Return editing info
+ */
+public const LineInfo *
+el_line(EditLine *el)
+{
+
+ return (const LineInfo *) (void *) &el->el_line;
+}
+
+
+/* el_source():
+ * Source a file
+ */
+public int
+el_source(EditLine *el, const char *fname)
+{
+ FILE *fp;
+ size_t len;
+ char *ptr;
+
+ fp = NULL;
+ if (fname == NULL) {
+#ifdef HAVE_ISSETUGID
+ static const char elpath[] = "/.editrc";
+ char path[MAXPATHLEN];
+
+ if (issetugid())
+ return (-1);
+ if ((ptr = getenv("HOME")) == NULL)
+ return (-1);
+ if (strlcpy(path, ptr, sizeof(path)) >= sizeof(path))
+ return (-1);
+ if (strlcat(path, elpath, sizeof(path)) >= sizeof(path))
+ return (-1);
+ fname = path;
+#else
+ /*
+ * If issetugid() is missing, always return an error, in order
+ * to keep from inadvertently opening up the user to a security
+ * hole.
+ */
+ return (-1);
+#endif
+ }
+ if (fp == NULL)
+ fp = fopen(fname, "r");
+ if (fp == NULL)
+ return (-1);
+
+ while ((ptr = fgetln(fp, &len)) != NULL) {
+ if (len > 0 && ptr[len - 1] == '\n')
+ --len;
+ ptr[len] = '\0';
+ if (parse_line(el, ptr) == -1) {
+ (void) fclose(fp);
+ return (-1);
+ }
+ }
+
+ (void) fclose(fp);
+ return (0);
+}
+
+
+/* el_resize():
+ * Called from program when terminal is resized
+ */
+public void
+el_resize(EditLine *el)
+{
+ int lins, cols;
+ sigset_t oset, nset;
+
+ (void) sigemptyset(&nset);
+ (void) sigaddset(&nset, SIGWINCH);
+ (void) sigprocmask(SIG_BLOCK, &nset, &oset);
+
+ /* get the correct window size */
+ if (term_get_size(el, &lins, &cols))
+ term_change_size(el, lins, cols);
+
+ (void) sigprocmask(SIG_SETMASK, &oset, NULL);
+}
+
+
+/* el_beep():
+ * Called from the program to beep
+ */
+public void
+el_beep(EditLine *el)
+{
+
+ term_beep(el);
+}
+
+
+/* el_editmode()
+ * Set the state of EDIT_DISABLED from the `edit' command.
+ */
+protected int
+/*ARGSUSED*/
+el_editmode(EditLine *el, int argc, const char **argv)
+{
+ const char *how;
+
+ if (argv == NULL || argc != 2 || argv[1] == NULL)
+ return (-1);
+
+ how = argv[1];
+ if (strcmp(how, "on") == 0) {
+ el->el_flags &= ~EDIT_DISABLED;
+ tty_rawmode(el);
+ } else if (strcmp(how, "off") == 0) {
+ tty_cookedmode(el);
+ el->el_flags |= EDIT_DISABLED;
+ }
+ else {
+ (void) fprintf(el->el_errfile, "edit: Bad value `%s'.\n", how);
+ return (-1);
+ }
+ return (0);
+}
diff --git a/lib/libedit/el.h b/lib/libedit/el.h
new file mode 100644
index 0000000..fb07e26
--- /dev/null
+++ b/lib/libedit/el.h
@@ -0,0 +1,149 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell 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.
+ *
+ * @(#)el.h 8.1 (Berkeley) 6/4/93
+ * $NetBSD: el.h,v 1.16 2003/10/18 23:48:42 christos Exp $
+ * $FreeBSD$
+ */
+
+/*
+ * el.h: Internal structures.
+ */
+#ifndef _h_el
+#define _h_el
+/*
+ * Local defaults
+ */
+#define KSHVI
+#define VIDEFAULT
+#define ANCHOR
+
+#include <stdio.h>
+#include <sys/types.h>
+
+#define EL_BUFSIZ 1024 /* Maximum line size */
+
+#define HANDLE_SIGNALS 0x01
+#define NO_TTY 0x02
+#define EDIT_DISABLED 0x04
+#define UNBUFFERED 0x08
+
+typedef int bool_t; /* True or not */
+
+typedef unsigned char el_action_t; /* Index to command array */
+
+typedef struct coord_t { /* Position on the screen */
+ int h;
+ int v;
+} coord_t;
+
+typedef struct el_line_t {
+ char *buffer; /* Input line */
+ char *cursor; /* Cursor position */
+ char *lastchar; /* Last character */
+ const char *limit; /* Max position */
+} el_line_t;
+
+/*
+ * Editor state
+ */
+typedef struct el_state_t {
+ int inputmode; /* What mode are we in? */
+ int doingarg; /* Are we getting an argument? */
+ int argument; /* Numeric argument */
+ int metanext; /* Is the next char a meta char */
+ el_action_t lastcmd; /* Previous command */
+ el_action_t thiscmd; /* this command */
+ char thisch; /* char that generated it */
+} el_state_t;
+
+/*
+ * Until we come up with something better...
+ */
+#define el_strdup(a) strdup(a)
+#define el_malloc(a) malloc(a)
+#define el_realloc(a,b) realloc(a, b)
+#define el_free(a) free(a)
+
+#include "tty.h"
+#include "prompt.h"
+#include "key.h"
+#include "term.h"
+#include "refresh.h"
+#include "chared.h"
+#include "common.h"
+#include "search.h"
+#include "hist.h"
+#include "map.h"
+#include "parse.h"
+#include "sig.h"
+#include "help.h"
+#include "read.h"
+
+struct editline {
+ char *el_prog; /* the program name */
+ FILE *el_outfile; /* Stdio stuff */
+ FILE *el_errfile; /* Stdio stuff */
+ int el_infd; /* Input file descriptor */
+ int el_flags; /* Various flags. */
+ coord_t el_cursor; /* Cursor location */
+ char **el_display; /* Real screen image = what is there */
+ char **el_vdisplay; /* Virtual screen image = what we see */
+ void *el_data; /* Client data */
+ el_line_t el_line; /* The current line information */
+ el_state_t el_state; /* Current editor state */
+ el_term_t el_term; /* Terminal dependent stuff */
+ el_tty_t el_tty; /* Tty dependent stuff */
+ el_refresh_t el_refresh; /* Refresh stuff */
+ el_prompt_t el_prompt; /* Prompt stuff */
+ el_prompt_t el_rprompt; /* Prompt stuff */
+ el_chared_t el_chared; /* Characted editor stuff */
+ el_map_t el_map; /* Key mapping stuff */
+ el_key_t el_key; /* Key binding stuff */
+ el_history_t el_history; /* History stuff */
+ el_search_t el_search; /* Search stuff */
+ el_signal_t el_signal; /* Signal handling stuff */
+ el_read_t el_read; /* Character reading stuff */
+};
+
+protected int el_editmode(EditLine *, int, const char **);
+
+#ifdef DEBUG
+#define EL_ABORT(a) do { \
+ fprintf(el->el_errfile, "%s, %d: ", \
+ __FILE__, __LINE__); \
+ fprintf a; \
+ abort(); \
+ } while( /*CONSTCOND*/0);
+#else
+#define EL_ABORT(a) abort()
+#endif
+#endif /* _h_el */
diff --git a/lib/libedit/emacs.c b/lib/libedit/emacs.c
new file mode 100644
index 0000000..c17788e
--- /dev/null
+++ b/lib/libedit/emacs.c
@@ -0,0 +1,506 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell 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.
+ *
+ * $NetBSD: emacs.c,v 1.20 2005/08/08 14:05:37 christos Exp $
+ */
+
+#if !defined(lint) && !defined(SCCSID)
+static char sccsid[] = "@(#)emacs.c 8.1 (Berkeley) 6/4/93";
+#endif /* not lint && not SCCSID */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * emacs.c: Emacs functions
+ */
+#include "sys.h"
+#include "el.h"
+
+/* em_delete_or_list():
+ * Delete character under cursor or list completions if at end of line
+ * [^D]
+ */
+protected el_action_t
+/*ARGSUSED*/
+em_delete_or_list(EditLine *el, int c __unused)
+{
+
+ if (el->el_line.cursor == el->el_line.lastchar) {
+ /* if I'm at the end */
+ if (el->el_line.cursor == el->el_line.buffer) {
+ /* and the beginning */
+ term_overwrite(el, STReof, 4); /* then do an EOF */
+ term__flush();
+ return (CC_EOF);
+ } else {
+ /*
+ * Here we could list completions, but it is an
+ * error right now
+ */
+ term_beep(el);
+ return (CC_ERROR);
+ }
+ } else {
+ if (el->el_state.doingarg)
+ c_delafter(el, el->el_state.argument);
+ else
+ c_delafter1(el);
+ if (el->el_line.cursor > el->el_line.lastchar)
+ el->el_line.cursor = el->el_line.lastchar;
+ /* bounds check */
+ return (CC_REFRESH);
+ }
+}
+
+
+/* em_delete_next_word():
+ * Cut from cursor to end of current word
+ * [M-d]
+ */
+protected el_action_t
+/*ARGSUSED*/
+em_delete_next_word(EditLine *el, int c __unused)
+{
+ char *cp, *p, *kp;
+
+ if (el->el_line.cursor == el->el_line.lastchar)
+ return (CC_ERROR);
+
+ cp = c__next_word(el->el_line.cursor, el->el_line.lastchar,
+ el->el_state.argument, ce__isword);
+
+ for (p = el->el_line.cursor, kp = el->el_chared.c_kill.buf; p < cp; p++)
+ /* save the text */
+ *kp++ = *p;
+ el->el_chared.c_kill.last = kp;
+
+ c_delafter(el, cp - el->el_line.cursor); /* delete after dot */
+ if (el->el_line.cursor > el->el_line.lastchar)
+ el->el_line.cursor = el->el_line.lastchar;
+ /* bounds check */
+ return (CC_REFRESH);
+}
+
+
+/* em_yank():
+ * Paste cut buffer at cursor position
+ * [^Y]
+ */
+protected el_action_t
+/*ARGSUSED*/
+em_yank(EditLine *el, int c __unused)
+{
+ char *kp, *cp;
+
+ if (el->el_chared.c_kill.last == el->el_chared.c_kill.buf)
+ return (CC_NORM);
+
+ if (el->el_line.lastchar +
+ (el->el_chared.c_kill.last - el->el_chared.c_kill.buf) >=
+ el->el_line.limit)
+ return (CC_ERROR);
+
+ el->el_chared.c_kill.mark = el->el_line.cursor;
+ cp = el->el_line.cursor;
+
+ /* open the space, */
+ c_insert(el, el->el_chared.c_kill.last - el->el_chared.c_kill.buf);
+ /* copy the chars */
+ for (kp = el->el_chared.c_kill.buf; kp < el->el_chared.c_kill.last; kp++)
+ *cp++ = *kp;
+
+ /* if an arg, cursor at beginning else cursor at end */
+ if (el->el_state.argument == 1)
+ el->el_line.cursor = cp;
+
+ return (CC_REFRESH);
+}
+
+
+/* em_kill_line():
+ * Cut the entire line and save in cut buffer
+ * [^U]
+ */
+protected el_action_t
+/*ARGSUSED*/
+em_kill_line(EditLine *el, int c __unused)
+{
+ char *kp, *cp;
+
+ cp = el->el_line.buffer;
+ kp = el->el_chared.c_kill.buf;
+ while (cp < el->el_line.lastchar)
+ *kp++ = *cp++; /* copy it */
+ el->el_chared.c_kill.last = kp;
+ /* zap! -- delete all of it */
+ el->el_line.lastchar = el->el_line.buffer;
+ el->el_line.cursor = el->el_line.buffer;
+ return (CC_REFRESH);
+}
+
+
+/* em_kill_region():
+ * Cut area between mark and cursor and save in cut buffer
+ * [^W]
+ */
+protected el_action_t
+/*ARGSUSED*/
+em_kill_region(EditLine *el, int c __unused)
+{
+ char *kp, *cp;
+
+ if (!el->el_chared.c_kill.mark)
+ return (CC_ERROR);
+
+ if (el->el_chared.c_kill.mark > el->el_line.cursor) {
+ cp = el->el_line.cursor;
+ kp = el->el_chared.c_kill.buf;
+ while (cp < el->el_chared.c_kill.mark)
+ *kp++ = *cp++; /* copy it */
+ el->el_chared.c_kill.last = kp;
+ c_delafter(el, cp - el->el_line.cursor);
+ } else { /* mark is before cursor */
+ cp = el->el_chared.c_kill.mark;
+ kp = el->el_chared.c_kill.buf;
+ while (cp < el->el_line.cursor)
+ *kp++ = *cp++; /* copy it */
+ el->el_chared.c_kill.last = kp;
+ c_delbefore(el, cp - el->el_chared.c_kill.mark);
+ el->el_line.cursor = el->el_chared.c_kill.mark;
+ }
+ return (CC_REFRESH);
+}
+
+
+/* em_copy_region():
+ * Copy area between mark and cursor to cut buffer
+ * [M-W]
+ */
+protected el_action_t
+/*ARGSUSED*/
+em_copy_region(EditLine *el, int c __unused)
+{
+ char *kp, *cp;
+
+ if (!el->el_chared.c_kill.mark)
+ return (CC_ERROR);
+
+ if (el->el_chared.c_kill.mark > el->el_line.cursor) {
+ cp = el->el_line.cursor;
+ kp = el->el_chared.c_kill.buf;
+ while (cp < el->el_chared.c_kill.mark)
+ *kp++ = *cp++; /* copy it */
+ el->el_chared.c_kill.last = kp;
+ } else {
+ cp = el->el_chared.c_kill.mark;
+ kp = el->el_chared.c_kill.buf;
+ while (cp < el->el_line.cursor)
+ *kp++ = *cp++; /* copy it */
+ el->el_chared.c_kill.last = kp;
+ }
+ return (CC_NORM);
+}
+
+
+/* em_gosmacs_transpose():
+ * Exchange the two characters before the cursor
+ * Gosling emacs transpose chars [^T]
+ */
+protected el_action_t
+em_gosmacs_transpose(EditLine *el, int c)
+{
+
+ if (el->el_line.cursor > &el->el_line.buffer[1]) {
+ /* must have at least two chars entered */
+ c = el->el_line.cursor[-2];
+ el->el_line.cursor[-2] = el->el_line.cursor[-1];
+ el->el_line.cursor[-1] = c;
+ return (CC_REFRESH);
+ } else
+ return (CC_ERROR);
+}
+
+
+/* em_next_word():
+ * Move next to end of current word
+ * [M-f]
+ */
+protected el_action_t
+/*ARGSUSED*/
+em_next_word(EditLine *el, int c __unused)
+{
+ if (el->el_line.cursor == el->el_line.lastchar)
+ return (CC_ERROR);
+
+ el->el_line.cursor = c__next_word(el->el_line.cursor,
+ el->el_line.lastchar,
+ el->el_state.argument,
+ ce__isword);
+
+ if (el->el_map.type == MAP_VI)
+ if (el->el_chared.c_vcmd.action != NOP) {
+ cv_delfini(el);
+ return (CC_REFRESH);
+ }
+ return (CC_CURSOR);
+}
+
+
+/* em_upper_case():
+ * Uppercase the characters from cursor to end of current word
+ * [M-u]
+ */
+protected el_action_t
+/*ARGSUSED*/
+em_upper_case(EditLine *el, int c __unused)
+{
+ char *cp, *ep;
+
+ ep = c__next_word(el->el_line.cursor, el->el_line.lastchar,
+ el->el_state.argument, ce__isword);
+
+ for (cp = el->el_line.cursor; cp < ep; cp++)
+ if (islower((unsigned char)*cp))
+ *cp = toupper((unsigned char)*cp);
+
+ el->el_line.cursor = ep;
+ if (el->el_line.cursor > el->el_line.lastchar)
+ el->el_line.cursor = el->el_line.lastchar;
+ return (CC_REFRESH);
+}
+
+
+/* em_capitol_case():
+ * Capitalize the characters from cursor to end of current word
+ * [M-c]
+ */
+protected el_action_t
+/*ARGSUSED*/
+em_capitol_case(EditLine *el, int c __unused)
+{
+ char *cp, *ep;
+
+ ep = c__next_word(el->el_line.cursor, el->el_line.lastchar,
+ el->el_state.argument, ce__isword);
+
+ for (cp = el->el_line.cursor; cp < ep; cp++) {
+ if (isalpha((unsigned char)*cp)) {
+ if (islower((unsigned char)*cp))
+ *cp = toupper((unsigned char)*cp);
+ cp++;
+ break;
+ }
+ }
+ for (; cp < ep; cp++)
+ if (isupper((unsigned char)*cp))
+ *cp = tolower((unsigned char)*cp);
+
+ el->el_line.cursor = ep;
+ if (el->el_line.cursor > el->el_line.lastchar)
+ el->el_line.cursor = el->el_line.lastchar;
+ return (CC_REFRESH);
+}
+
+
+/* em_lower_case():
+ * Lowercase the characters from cursor to end of current word
+ * [M-l]
+ */
+protected el_action_t
+/*ARGSUSED*/
+em_lower_case(EditLine *el, int c __unused)
+{
+ char *cp, *ep;
+
+ ep = c__next_word(el->el_line.cursor, el->el_line.lastchar,
+ el->el_state.argument, ce__isword);
+
+ for (cp = el->el_line.cursor; cp < ep; cp++)
+ if (isupper((unsigned char)*cp))
+ *cp = tolower((unsigned char)*cp);
+
+ el->el_line.cursor = ep;
+ if (el->el_line.cursor > el->el_line.lastchar)
+ el->el_line.cursor = el->el_line.lastchar;
+ return (CC_REFRESH);
+}
+
+
+/* em_set_mark():
+ * Set the mark at cursor
+ * [^@]
+ */
+protected el_action_t
+/*ARGSUSED*/
+em_set_mark(EditLine *el, int c __unused)
+{
+
+ el->el_chared.c_kill.mark = el->el_line.cursor;
+ return (CC_NORM);
+}
+
+
+/* em_exchange_mark():
+ * Exchange the cursor and mark
+ * [^X^X]
+ */
+protected el_action_t
+/*ARGSUSED*/
+em_exchange_mark(EditLine *el, int c __unused)
+{
+ char *cp;
+
+ cp = el->el_line.cursor;
+ el->el_line.cursor = el->el_chared.c_kill.mark;
+ el->el_chared.c_kill.mark = cp;
+ return (CC_CURSOR);
+}
+
+
+/* em_universal_argument():
+ * Universal argument (argument times 4)
+ * [^U]
+ */
+protected el_action_t
+/*ARGSUSED*/
+em_universal_argument(EditLine *el, int c __unused)
+{ /* multiply current argument by 4 */
+
+ if (el->el_state.argument > 1000000)
+ return (CC_ERROR);
+ el->el_state.doingarg = 1;
+ el->el_state.argument *= 4;
+ return (CC_ARGHACK);
+}
+
+
+/* em_meta_next():
+ * Add 8th bit to next character typed
+ * [<ESC>]
+ */
+protected el_action_t
+/*ARGSUSED*/
+em_meta_next(EditLine *el, int c __unused)
+{
+
+ el->el_state.metanext = 1;
+ return (CC_ARGHACK);
+}
+
+
+/* em_toggle_overwrite():
+ * Switch from insert to overwrite mode or vice versa
+ */
+protected el_action_t
+/*ARGSUSED*/
+em_toggle_overwrite(EditLine *el, int c __unused)
+{
+
+ el->el_state.inputmode = (el->el_state.inputmode == MODE_INSERT) ?
+ MODE_REPLACE : MODE_INSERT;
+ return (CC_NORM);
+}
+
+
+/* em_copy_prev_word():
+ * Copy current word to cursor
+ */
+protected el_action_t
+/*ARGSUSED*/
+em_copy_prev_word(EditLine *el, int c __unused)
+{
+ char *cp, *oldc, *dp;
+
+ if (el->el_line.cursor == el->el_line.buffer)
+ return (CC_ERROR);
+
+ oldc = el->el_line.cursor;
+ /* does a bounds check */
+ cp = c__prev_word(el->el_line.cursor, el->el_line.buffer,
+ el->el_state.argument, ce__isword);
+
+ c_insert(el, oldc - cp);
+ for (dp = oldc; cp < oldc && dp < el->el_line.lastchar; cp++)
+ *dp++ = *cp;
+
+ el->el_line.cursor = dp;/* put cursor at end */
+
+ return (CC_REFRESH);
+}
+
+
+/* em_inc_search_next():
+ * Emacs incremental next search
+ */
+protected el_action_t
+/*ARGSUSED*/
+em_inc_search_next(EditLine *el, int c __unused)
+{
+
+ el->el_search.patlen = 0;
+ return (ce_inc_search(el, ED_SEARCH_NEXT_HISTORY));
+}
+
+
+/* em_inc_search_prev():
+ * Emacs incremental reverse search
+ */
+protected el_action_t
+/*ARGSUSED*/
+em_inc_search_prev(EditLine *el, int c __unused)
+{
+
+ el->el_search.patlen = 0;
+ return (ce_inc_search(el, ED_SEARCH_PREV_HISTORY));
+}
+
+
+/* em_delete_prev_char():
+ * Delete the character to the left of the cursor
+ * [^?]
+ */
+protected el_action_t
+/*ARGSUSED*/
+em_delete_prev_char(EditLine *el, int c __unused)
+{
+
+ if (el->el_line.cursor <= el->el_line.buffer)
+ return (CC_ERROR);
+
+ if (el->el_state.doingarg)
+ c_delbefore(el, el->el_state.argument);
+ else
+ c_delbefore1(el);
+ el->el_line.cursor -= el->el_state.argument;
+ if (el->el_line.cursor < el->el_line.buffer)
+ el->el_line.cursor = el->el_line.buffer;
+ return (CC_REFRESH);
+}
diff --git a/lib/libedit/hist.c b/lib/libedit/hist.c
new file mode 100644
index 0000000..601e102
--- /dev/null
+++ b/lib/libedit/hist.c
@@ -0,0 +1,208 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell 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.
+ *
+ * $NetBSD: hist.c,v 1.15 2003/11/01 23:36:39 christos Exp $
+ */
+
+#if !defined(lint) && !defined(SCCSID)
+static char sccsid[] = "@(#)hist.c 8.1 (Berkeley) 6/4/93";
+#endif /* not lint && not SCCSID */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * hist.c: History access functions
+ */
+#include "sys.h"
+#include <stdlib.h>
+#include "el.h"
+
+/* hist_init():
+ * Initialization function.
+ */
+protected int
+hist_init(EditLine *el)
+{
+
+ el->el_history.fun = NULL;
+ el->el_history.ref = NULL;
+ el->el_history.buf = (char *) el_malloc(EL_BUFSIZ);
+ el->el_history.sz = EL_BUFSIZ;
+ if (el->el_history.buf == NULL)
+ return (-1);
+ el->el_history.last = el->el_history.buf;
+ return (0);
+}
+
+
+/* hist_end():
+ * clean up history;
+ */
+protected void
+hist_end(EditLine *el)
+{
+
+ el_free((ptr_t) el->el_history.buf);
+ el->el_history.buf = NULL;
+}
+
+
+/* hist_set():
+ * Set new history interface
+ */
+protected int
+hist_set(EditLine *el, hist_fun_t fun, ptr_t ptr)
+{
+
+ el->el_history.ref = ptr;
+ el->el_history.fun = fun;
+ return (0);
+}
+
+
+/* hist_get():
+ * Get a history line and update it in the buffer.
+ * eventno tells us the event to get.
+ */
+protected el_action_t
+hist_get(EditLine *el)
+{
+ const char *hp;
+ int h;
+
+ if (el->el_history.eventno == 0) { /* if really the current line */
+ (void) strncpy(el->el_line.buffer, el->el_history.buf,
+ el->el_history.sz);
+ el->el_line.lastchar = el->el_line.buffer +
+ (el->el_history.last - el->el_history.buf);
+
+#ifdef KSHVI
+ if (el->el_map.type == MAP_VI)
+ el->el_line.cursor = el->el_line.buffer;
+ else
+#endif /* KSHVI */
+ el->el_line.cursor = el->el_line.lastchar;
+
+ return (CC_REFRESH);
+ }
+ if (el->el_history.ref == NULL)
+ return (CC_ERROR);
+
+ hp = HIST_FIRST(el);
+
+ if (hp == NULL)
+ return (CC_ERROR);
+
+ for (h = 1; h < el->el_history.eventno; h++)
+ if ((hp = HIST_NEXT(el)) == NULL) {
+ el->el_history.eventno = h;
+ return (CC_ERROR);
+ }
+ (void) strlcpy(el->el_line.buffer, hp,
+ (size_t)(el->el_line.limit - el->el_line.buffer));
+ el->el_line.lastchar = el->el_line.buffer + strlen(el->el_line.buffer);
+
+ if (el->el_line.lastchar > el->el_line.buffer
+ && el->el_line.lastchar[-1] == '\n')
+ el->el_line.lastchar--;
+ if (el->el_line.lastchar > el->el_line.buffer
+ && el->el_line.lastchar[-1] == ' ')
+ el->el_line.lastchar--;
+#ifdef KSHVI
+ if (el->el_map.type == MAP_VI)
+ el->el_line.cursor = el->el_line.buffer;
+ else
+#endif /* KSHVI */
+ el->el_line.cursor = el->el_line.lastchar;
+
+ return (CC_REFRESH);
+}
+
+
+/* hist_command()
+ * process a history command
+ */
+protected int
+hist_command(EditLine *el, int argc, const char **argv)
+{
+ const char *str;
+ int num;
+ HistEvent ev;
+
+ if (el->el_history.ref == NULL)
+ return (-1);
+
+ if (argc == 1 || strcmp(argv[1], "list") == 0) {
+ /* List history entries */
+
+ for (str = HIST_LAST(el); str != NULL; str = HIST_PREV(el))
+ (void) fprintf(el->el_outfile, "%d %s",
+ el->el_history.ev.num, str);
+ return (0);
+ }
+
+ if (argc != 3)
+ return (-1);
+
+ num = (int)strtol(argv[2], NULL, 0);
+
+ if (strcmp(argv[1], "size") == 0)
+ return history(el->el_history.ref, &ev, H_SETSIZE, num);
+
+ if (strcmp(argv[1], "unique") == 0)
+ return history(el->el_history.ref, &ev, H_SETUNIQUE, num);
+
+ return -1;
+}
+
+/* hist_enlargebuf()
+ * Enlarge history buffer to specified value. Called from el_enlargebufs().
+ * Return 0 for failure, 1 for success.
+ */
+protected int
+/*ARGSUSED*/
+hist_enlargebuf(EditLine *el, size_t oldsz, size_t newsz)
+{
+ char *newbuf;
+
+ newbuf = realloc(el->el_history.buf, newsz);
+ if (!newbuf)
+ return 0;
+
+ (void) memset(&newbuf[oldsz], '\0', newsz - oldsz);
+
+ el->el_history.last = newbuf +
+ (el->el_history.last - el->el_history.buf);
+ el->el_history.buf = newbuf;
+ el->el_history.sz = newsz;
+
+ return 1;
+}
diff --git a/lib/libedit/hist.h b/lib/libedit/hist.h
new file mode 100644
index 0000000..4f2824a
--- /dev/null
+++ b/lib/libedit/hist.h
@@ -0,0 +1,76 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell 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.
+ *
+ * @(#)hist.h 8.1 (Berkeley) 6/4/93
+ * $NetBSD: hist.h,v 1.10 2003/08/07 16:44:31 agc Exp $
+ * $FreeBSD$
+ */
+
+/*
+ * el.hist.c: History functions
+ */
+#ifndef _h_el_hist
+#define _h_el_hist
+
+#include "histedit.h"
+
+typedef int (*hist_fun_t)(ptr_t, HistEvent *, int, ...);
+
+typedef struct el_history_t {
+ char *buf; /* The history buffer */
+ size_t sz; /* Size of history buffer */
+ char *last; /* The last character */
+ int eventno; /* Event we are looking for */
+ ptr_t ref; /* Argument for history fcns */
+ hist_fun_t fun; /* Event access */
+ HistEvent ev; /* Event cookie */
+} el_history_t;
+
+#define HIST_FUN(el, fn, arg) \
+ ((((*(el)->el_history.fun) ((el)->el_history.ref, &(el)->el_history.ev, \
+ fn, arg)) == -1) ? NULL : (el)->el_history.ev.str)
+
+#define HIST_NEXT(el) HIST_FUN(el, H_NEXT, NULL)
+#define HIST_FIRST(el) HIST_FUN(el, H_FIRST, NULL)
+#define HIST_LAST(el) HIST_FUN(el, H_LAST, NULL)
+#define HIST_PREV(el) HIST_FUN(el, H_PREV, NULL)
+#define HIST_SET(el, num) HIST_FUN(el, H_SET, num)
+#define HIST_LOAD(el, fname) HIST_FUN(el, H_LOAD fname)
+#define HIST_SAVE(el, fname) HIST_FUN(el, H_SAVE fname)
+
+protected int hist_init(EditLine *);
+protected void hist_end(EditLine *);
+protected el_action_t hist_get(EditLine *);
+protected int hist_set(EditLine *, hist_fun_t, ptr_t);
+protected int hist_command(EditLine *, int, const char **);
+protected int hist_enlargebuf(EditLine *, size_t, size_t);
+
+#endif /* _h_el_hist */
diff --git a/lib/libedit/history.c b/lib/libedit/history.c
new file mode 100644
index 0000000..af4892a
--- /dev/null
+++ b/lib/libedit/history.c
@@ -0,0 +1,985 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell 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.
+ *
+ * $NetBSD: history.c,v 1.31 2005/08/01 14:34:06 christos Exp $
+ */
+
+#if !defined(lint) && !defined(SCCSID)
+static char sccsid[] = "@(#)history.c 8.1 (Berkeley) 6/4/93";
+#endif /* not lint && not SCCSID */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * hist.c: History access functions
+ */
+#include "sys.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <vis.h>
+#include <sys/stat.h>
+
+static const char hist_cookie[] = "_HiStOrY_V2_\n";
+
+#include "histedit.h"
+
+typedef int (*history_gfun_t)(ptr_t, HistEvent *);
+typedef int (*history_efun_t)(ptr_t, HistEvent *, const char *);
+typedef void (*history_vfun_t)(ptr_t, HistEvent *);
+typedef int (*history_sfun_t)(ptr_t, HistEvent *, const int);
+
+struct history {
+ ptr_t h_ref; /* Argument for history fcns */
+ int h_ent; /* Last entry point for history */
+ history_gfun_t h_first; /* Get the first element */
+ history_gfun_t h_next; /* Get the next element */
+ history_gfun_t h_last; /* Get the last element */
+ history_gfun_t h_prev; /* Get the previous element */
+ history_gfun_t h_curr; /* Get the current element */
+ history_sfun_t h_set; /* Set the current element */
+ history_sfun_t h_del; /* Set the given element */
+ history_vfun_t h_clear; /* Clear the history list */
+ history_efun_t h_enter; /* Add an element */
+ history_efun_t h_add; /* Append to an element */
+};
+
+#define HNEXT(h, ev) (*(h)->h_next)((h)->h_ref, ev)
+#define HFIRST(h, ev) (*(h)->h_first)((h)->h_ref, ev)
+#define HPREV(h, ev) (*(h)->h_prev)((h)->h_ref, ev)
+#define HLAST(h, ev) (*(h)->h_last)((h)->h_ref, ev)
+#define HCURR(h, ev) (*(h)->h_curr)((h)->h_ref, ev)
+#define HSET(h, ev, n) (*(h)->h_set)((h)->h_ref, ev, n)
+#define HCLEAR(h, ev) (*(h)->h_clear)((h)->h_ref, ev)
+#define HENTER(h, ev, str) (*(h)->h_enter)((h)->h_ref, ev, str)
+#define HADD(h, ev, str) (*(h)->h_add)((h)->h_ref, ev, str)
+#define HDEL(h, ev, n) (*(h)->h_del)((h)->h_ref, ev, n)
+
+#define h_strdup(a) strdup(a)
+#define h_malloc(a) malloc(a)
+#define h_realloc(a, b) realloc((a), (b))
+#define h_free(a) free(a)
+
+typedef struct {
+ int num;
+ char *str;
+} HistEventPrivate;
+
+
+
+private int history_setsize(History *, HistEvent *, int);
+private int history_getsize(History *, HistEvent *);
+private int history_setunique(History *, HistEvent *, int);
+private int history_getunique(History *, HistEvent *);
+private int history_set_fun(History *, History *);
+private int history_load(History *, const char *);
+private int history_save(History *, const char *);
+private int history_prev_event(History *, HistEvent *, int);
+private int history_next_event(History *, HistEvent *, int);
+private int history_next_string(History *, HistEvent *, const char *);
+private int history_prev_string(History *, HistEvent *, const char *);
+
+
+/***********************************************************************/
+
+/*
+ * Builtin- history implementation
+ */
+typedef struct hentry_t {
+ HistEvent ev; /* What we return */
+ struct hentry_t *next; /* Next entry */
+ struct hentry_t *prev; /* Previous entry */
+} hentry_t;
+
+typedef struct history_t {
+ hentry_t list; /* Fake list header element */
+ hentry_t *cursor; /* Current element in the list */
+ int max; /* Maximum number of events */
+ int cur; /* Current number of events */
+ int eventid; /* For generation of unique event id */
+ int flags; /* History flags */
+#define H_UNIQUE 1 /* Store only unique elements */
+} history_t;
+
+private int history_def_next(ptr_t, HistEvent *);
+private int history_def_first(ptr_t, HistEvent *);
+private int history_def_prev(ptr_t, HistEvent *);
+private int history_def_last(ptr_t, HistEvent *);
+private int history_def_curr(ptr_t, HistEvent *);
+private int history_def_set(ptr_t, HistEvent *, const int);
+private void history_def_clear(ptr_t, HistEvent *);
+private int history_def_enter(ptr_t, HistEvent *, const char *);
+private int history_def_add(ptr_t, HistEvent *, const char *);
+private int history_def_del(ptr_t, HistEvent *, const int);
+
+private int history_def_init(ptr_t *, HistEvent *, int);
+private int history_def_insert(history_t *, HistEvent *, const char *);
+private void history_def_delete(history_t *, HistEvent *, hentry_t *);
+
+#define history_def_setsize(p, num)(void) (((history_t *)p)->max = (num))
+#define history_def_getsize(p) (((history_t *)p)->cur)
+#define history_def_getunique(p) (((((history_t *)p)->flags) & H_UNIQUE) != 0)
+#define history_def_setunique(p, uni) \
+ if (uni) \
+ (((history_t *)p)->flags) |= H_UNIQUE; \
+ else \
+ (((history_t *)p)->flags) &= ~H_UNIQUE
+
+#define he_strerror(code) he_errlist[code]
+#define he_seterrev(evp, code) {\
+ evp->num = code;\
+ evp->str = he_strerror(code);\
+ }
+
+/* error messages */
+static const char *const he_errlist[] = {
+ "OK",
+ "unknown error",
+ "malloc() failed",
+ "first event not found",
+ "last event not found",
+ "empty list",
+ "no next event",
+ "no previous event",
+ "current event is invalid",
+ "event not found",
+ "can't read history from file",
+ "can't write history",
+ "required parameter(s) not supplied",
+ "history size negative",
+ "function not allowed with other history-functions-set the default",
+ "bad parameters"
+};
+/* error codes */
+#define _HE_OK 0
+#define _HE_UNKNOWN 1
+#define _HE_MALLOC_FAILED 2
+#define _HE_FIRST_NOTFOUND 3
+#define _HE_LAST_NOTFOUND 4
+#define _HE_EMPTY_LIST 5
+#define _HE_END_REACHED 6
+#define _HE_START_REACHED 7
+#define _HE_CURR_INVALID 8
+#define _HE_NOT_FOUND 9
+#define _HE_HIST_READ 10
+#define _HE_HIST_WRITE 11
+#define _HE_PARAM_MISSING 12
+#define _HE_SIZE_NEGATIVE 13
+#define _HE_NOT_ALLOWED 14
+#define _HE_BAD_PARAM 15
+
+/* history_def_first():
+ * Default function to return the first event in the history.
+ */
+private int
+history_def_first(ptr_t p, HistEvent *ev)
+{
+ history_t *h = (history_t *) p;
+
+ h->cursor = h->list.next;
+ if (h->cursor != &h->list)
+ *ev = h->cursor->ev;
+ else {
+ he_seterrev(ev, _HE_FIRST_NOTFOUND);
+ return (-1);
+ }
+
+ return (0);
+}
+
+
+/* history_def_last():
+ * Default function to return the last event in the history.
+ */
+private int
+history_def_last(ptr_t p, HistEvent *ev)
+{
+ history_t *h = (history_t *) p;
+
+ h->cursor = h->list.prev;
+ if (h->cursor != &h->list)
+ *ev = h->cursor->ev;
+ else {
+ he_seterrev(ev, _HE_LAST_NOTFOUND);
+ return (-1);
+ }
+
+ return (0);
+}
+
+
+/* history_def_next():
+ * Default function to return the next event in the history.
+ */
+private int
+history_def_next(ptr_t p, HistEvent *ev)
+{
+ history_t *h = (history_t *) p;
+
+ if (h->cursor == &h->list) {
+ he_seterrev(ev, _HE_EMPTY_LIST);
+ return (-1);
+ }
+
+ if (h->cursor->next == &h->list) {
+ he_seterrev(ev, _HE_END_REACHED);
+ return (-1);
+ }
+
+ h->cursor = h->cursor->next;
+ *ev = h->cursor->ev;
+
+ return (0);
+}
+
+
+/* history_def_prev():
+ * Default function to return the previous event in the history.
+ */
+private int
+history_def_prev(ptr_t p, HistEvent *ev)
+{
+ history_t *h = (history_t *) p;
+
+ if (h->cursor == &h->list) {
+ he_seterrev(ev,
+ (h->cur > 0) ? _HE_END_REACHED : _HE_EMPTY_LIST);
+ return (-1);
+ }
+
+ if (h->cursor->prev == &h->list) {
+ he_seterrev(ev, _HE_START_REACHED);
+ return (-1);
+ }
+
+ h->cursor = h->cursor->prev;
+ *ev = h->cursor->ev;
+
+ return (0);
+}
+
+
+/* history_def_curr():
+ * Default function to return the current event in the history.
+ */
+private int
+history_def_curr(ptr_t p, HistEvent *ev)
+{
+ history_t *h = (history_t *) p;
+
+ if (h->cursor != &h->list)
+ *ev = h->cursor->ev;
+ else {
+ he_seterrev(ev,
+ (h->cur > 0) ? _HE_CURR_INVALID : _HE_EMPTY_LIST);
+ return (-1);
+ }
+
+ return (0);
+}
+
+
+/* history_def_set():
+ * Default function to set the current event in the history to the
+ * given one.
+ */
+private int
+history_def_set(ptr_t p, HistEvent *ev, const int n)
+{
+ history_t *h = (history_t *) p;
+
+ if (h->cur == 0) {
+ he_seterrev(ev, _HE_EMPTY_LIST);
+ return (-1);
+ }
+ if (h->cursor == &h->list || h->cursor->ev.num != n) {
+ for (h->cursor = h->list.next; h->cursor != &h->list;
+ h->cursor = h->cursor->next)
+ if (h->cursor->ev.num == n)
+ break;
+ }
+ if (h->cursor == &h->list) {
+ he_seterrev(ev, _HE_NOT_FOUND);
+ return (-1);
+ }
+ return (0);
+}
+
+
+/* history_def_add():
+ * Append string to element
+ */
+private int
+history_def_add(ptr_t p, HistEvent *ev, const char *str)
+{
+ history_t *h = (history_t *) p;
+ size_t len;
+ char *s;
+ HistEventPrivate *evp = (void *)&h->cursor->ev;
+
+ if (h->cursor == &h->list)
+ return (history_def_enter(p, ev, str));
+ len = strlen(evp->str) + strlen(str) + 1;
+ s = (char *) h_malloc(len);
+ if (s == NULL) {
+ he_seterrev(ev, _HE_MALLOC_FAILED);
+ return (-1);
+ }
+ (void) strlcpy(s, h->cursor->ev.str, len);
+ (void) strlcat(s, str, len);
+ h_free((ptr_t)evp->str);
+ evp->str = s;
+ *ev = h->cursor->ev;
+ return (0);
+}
+
+
+/* history_def_del():
+ * Delete element hp of the h list
+ */
+/* ARGSUSED */
+private int
+history_def_del(ptr_t p, HistEvent *ev __unused,
+ const int num)
+{
+ history_t *h = (history_t *) p;
+ if (history_def_set(h, ev, num) != 0)
+ return (-1);
+ ev->str = strdup(h->cursor->ev.str);
+ ev->num = h->cursor->ev.num;
+ history_def_delete(h, ev, h->cursor);
+ return (0);
+}
+
+
+/* history_def_delete():
+ * Delete element hp of the h list
+ */
+/* ARGSUSED */
+private void
+history_def_delete(history_t *h,
+ HistEvent *ev __unused, hentry_t *hp)
+{
+ HistEventPrivate *evp = (void *)&hp->ev;
+ if (hp == &h->list)
+ abort();
+ if (h->cursor == hp)
+ h->cursor = hp->prev;
+ hp->prev->next = hp->next;
+ hp->next->prev = hp->prev;
+ h_free((ptr_t) evp->str);
+ h_free(hp);
+ h->cur--;
+}
+
+
+/* history_def_insert():
+ * Insert element with string str in the h list
+ */
+private int
+history_def_insert(history_t *h, HistEvent *ev, const char *str)
+{
+
+ h->cursor = (hentry_t *) h_malloc(sizeof(hentry_t));
+ if (h->cursor == NULL)
+ goto oomem;
+ if ((h->cursor->ev.str = h_strdup(str)) == NULL) {
+ h_free((ptr_t)h->cursor);
+ goto oomem;
+ }
+ h->cursor->ev.num = ++h->eventid;
+ h->cursor->next = h->list.next;
+ h->cursor->prev = &h->list;
+ h->list.next->prev = h->cursor;
+ h->list.next = h->cursor;
+ h->cur++;
+
+ *ev = h->cursor->ev;
+ return (0);
+oomem:
+ he_seterrev(ev, _HE_MALLOC_FAILED);
+ return (-1);
+}
+
+
+/* history_def_enter():
+ * Default function to enter an item in the history
+ */
+private int
+history_def_enter(ptr_t p, HistEvent *ev, const char *str)
+{
+ history_t *h = (history_t *) p;
+
+ if ((h->flags & H_UNIQUE) != 0 && h->list.next != &h->list &&
+ strcmp(h->list.next->ev.str, str) == 0)
+ return (0);
+
+ if (history_def_insert(h, ev, str) == -1)
+ return (-1); /* error, keep error message */
+
+ /*
+ * Always keep at least one entry.
+ * This way we don't have to check for the empty list.
+ */
+ while (h->cur > h->max && h->cur > 0)
+ history_def_delete(h, ev, h->list.prev);
+
+ return (1);
+}
+
+
+/* history_def_init():
+ * Default history initialization function
+ */
+/* ARGSUSED */
+private int
+history_def_init(ptr_t *p, HistEvent *ev __unused, int n)
+{
+ history_t *h = (history_t *) h_malloc(sizeof(history_t));
+ if (h == NULL)
+ return -1;
+
+ if (n <= 0)
+ n = 0;
+ h->eventid = 0;
+ h->cur = 0;
+ h->max = n;
+ h->list.next = h->list.prev = &h->list;
+ h->list.ev.str = NULL;
+ h->list.ev.num = 0;
+ h->cursor = &h->list;
+ h->flags = 0;
+ *p = (ptr_t) h;
+ return 0;
+}
+
+
+/* history_def_clear():
+ * Default history cleanup function
+ */
+private void
+history_def_clear(ptr_t p, HistEvent *ev)
+{
+ history_t *h = (history_t *) p;
+
+ while (h->list.prev != &h->list)
+ history_def_delete(h, ev, h->list.prev);
+ h->eventid = 0;
+ h->cur = 0;
+}
+
+
+
+
+/************************************************************************/
+
+/* history_init():
+ * Initialization function.
+ */
+public History *
+history_init(void)
+{
+ HistEvent ev;
+ History *h = (History *) h_malloc(sizeof(History));
+ if (h == NULL)
+ return NULL;
+
+ if (history_def_init(&h->h_ref, &ev, 0) == -1) {
+ h_free((ptr_t)h);
+ return NULL;
+ }
+ h->h_ent = -1;
+ h->h_next = history_def_next;
+ h->h_first = history_def_first;
+ h->h_last = history_def_last;
+ h->h_prev = history_def_prev;
+ h->h_curr = history_def_curr;
+ h->h_set = history_def_set;
+ h->h_clear = history_def_clear;
+ h->h_enter = history_def_enter;
+ h->h_add = history_def_add;
+ h->h_del = history_def_del;
+
+ return (h);
+}
+
+
+/* history_end():
+ * clean up history;
+ */
+public void
+history_end(History *h)
+{
+ HistEvent ev;
+
+ if (h->h_next == history_def_next)
+ history_def_clear(h->h_ref, &ev);
+ h_free(h);
+}
+
+
+
+/* history_setsize():
+ * Set history number of events
+ */
+private int
+history_setsize(History *h, HistEvent *ev, int num)
+{
+
+ if (h->h_next != history_def_next) {
+ he_seterrev(ev, _HE_NOT_ALLOWED);
+ return (-1);
+ }
+ if (num < 0) {
+ he_seterrev(ev, _HE_BAD_PARAM);
+ return (-1);
+ }
+ history_def_setsize(h->h_ref, num);
+ return (0);
+}
+
+
+/* history_getsize():
+ * Get number of events currently in history
+ */
+private int
+history_getsize(History *h, HistEvent *ev)
+{
+ if (h->h_next != history_def_next) {
+ he_seterrev(ev, _HE_NOT_ALLOWED);
+ return (-1);
+ }
+ ev->num = history_def_getsize(h->h_ref);
+ if (ev->num < -1) {
+ he_seterrev(ev, _HE_SIZE_NEGATIVE);
+ return (-1);
+ }
+ return (0);
+}
+
+
+/* history_setunique():
+ * Set if adjacent equal events should not be entered in history.
+ */
+private int
+history_setunique(History *h, HistEvent *ev, int uni)
+{
+
+ if (h->h_next != history_def_next) {
+ he_seterrev(ev, _HE_NOT_ALLOWED);
+ return (-1);
+ }
+ history_def_setunique(h->h_ref, uni);
+ return (0);
+}
+
+
+/* history_getunique():
+ * Get if adjacent equal events should not be entered in history.
+ */
+private int
+history_getunique(History *h, HistEvent *ev)
+{
+ if (h->h_next != history_def_next) {
+ he_seterrev(ev, _HE_NOT_ALLOWED);
+ return (-1);
+ }
+ ev->num = history_def_getunique(h->h_ref);
+ return (0);
+}
+
+
+/* history_set_fun():
+ * Set history functions
+ */
+private int
+history_set_fun(History *h, History *nh)
+{
+ HistEvent ev;
+
+ if (nh->h_first == NULL || nh->h_next == NULL || nh->h_last == NULL ||
+ nh->h_prev == NULL || nh->h_curr == NULL || nh->h_set == NULL ||
+ nh->h_enter == NULL || nh->h_add == NULL || nh->h_clear == NULL ||
+ nh->h_del == NULL || nh->h_ref == NULL) {
+ if (h->h_next != history_def_next) {
+ history_def_init(&h->h_ref, &ev, 0);
+ h->h_first = history_def_first;
+ h->h_next = history_def_next;
+ h->h_last = history_def_last;
+ h->h_prev = history_def_prev;
+ h->h_curr = history_def_curr;
+ h->h_set = history_def_set;
+ h->h_clear = history_def_clear;
+ h->h_enter = history_def_enter;
+ h->h_add = history_def_add;
+ h->h_del = history_def_del;
+ }
+ return (-1);
+ }
+ if (h->h_next == history_def_next)
+ history_def_clear(h->h_ref, &ev);
+
+ h->h_ent = -1;
+ h->h_first = nh->h_first;
+ h->h_next = nh->h_next;
+ h->h_last = nh->h_last;
+ h->h_prev = nh->h_prev;
+ h->h_curr = nh->h_curr;
+ h->h_set = nh->h_set;
+ h->h_clear = nh->h_clear;
+ h->h_enter = nh->h_enter;
+ h->h_add = nh->h_add;
+ h->h_del = nh->h_del;
+
+ return (0);
+}
+
+
+/* history_load():
+ * History load function
+ */
+private int
+history_load(History *h, const char *fname)
+{
+ FILE *fp;
+ char *line;
+ size_t sz, max_size;
+ char *ptr;
+ int i = -1;
+ HistEvent ev;
+
+ if ((fp = fopen(fname, "r")) == NULL)
+ return (i);
+
+ if ((line = fgetln(fp, &sz)) == NULL)
+ goto done;
+
+ if (strncmp(line, hist_cookie, sz) != 0)
+ goto done;
+
+ ptr = h_malloc(max_size = 1024);
+ if (ptr == NULL)
+ goto done;
+ for (i = 0; (line = fgetln(fp, &sz)) != NULL; i++) {
+ char c = line[sz];
+
+ if (sz != 0 && line[sz - 1] == '\n')
+ line[--sz] = '\0';
+ else
+ line[sz] = '\0';
+
+ if (max_size < sz) {
+ char *nptr;
+ max_size = (sz + 1024) & ~1023;
+ nptr = h_realloc(ptr, max_size);
+ if (nptr == NULL) {
+ i = -1;
+ goto oomem;
+ }
+ ptr = nptr;
+ }
+ (void) strunvis(ptr, line);
+ line[sz] = c;
+ if (HENTER(h, &ev, ptr) == -1) {
+ h_free((ptr_t)ptr);
+ return -1;
+ }
+ }
+oomem:
+ h_free((ptr_t)ptr);
+done:
+ (void) fclose(fp);
+ return (i);
+}
+
+
+/* history_save():
+ * History save function
+ */
+private int
+history_save(History *h, const char *fname)
+{
+ FILE *fp;
+ HistEvent ev;
+ int i = -1, retval;
+ size_t len, max_size;
+ char *ptr;
+
+ if ((fp = fopen(fname, "w")) == NULL)
+ return (-1);
+
+ if (fchmod(fileno(fp), S_IRUSR|S_IWUSR) == -1)
+ goto done;
+ if (fputs(hist_cookie, fp) == EOF)
+ goto done;
+ ptr = h_malloc(max_size = 1024);
+ if (ptr == NULL)
+ goto done;
+ for (i = 0, retval = HLAST(h, &ev);
+ retval != -1;
+ retval = HPREV(h, &ev), i++) {
+ len = strlen(ev.str) * 4;
+ if (len >= max_size) {
+ char *nptr;
+ max_size = (len + 1024) & ~1023;
+ nptr = h_realloc(ptr, max_size);
+ if (nptr == NULL) {
+ i = -1;
+ goto oomem;
+ }
+ ptr = nptr;
+ }
+ (void) strvis(ptr, ev.str, VIS_WHITE);
+ (void) fprintf(fp, "%s\n", ptr);
+ }
+oomem:
+ h_free((ptr_t)ptr);
+done:
+ (void) fclose(fp);
+ return (i);
+}
+
+
+/* history_prev_event():
+ * Find the previous event, with number given
+ */
+private int
+history_prev_event(History *h, HistEvent *ev, int num)
+{
+ int retval;
+
+ for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
+ if (ev->num == num)
+ return (0);
+
+ he_seterrev(ev, _HE_NOT_FOUND);
+ return (-1);
+}
+
+
+/* history_next_event():
+ * Find the next event, with number given
+ */
+private int
+history_next_event(History *h, HistEvent *ev, int num)
+{
+ int retval;
+
+ for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
+ if (ev->num == num)
+ return (0);
+
+ he_seterrev(ev, _HE_NOT_FOUND);
+ return (-1);
+}
+
+
+/* history_prev_string():
+ * Find the previous event beginning with string
+ */
+private int
+history_prev_string(History *h, HistEvent *ev, const char *str)
+{
+ size_t len = strlen(str);
+ int retval;
+
+ for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
+ if (strncmp(str, ev->str, len) == 0)
+ return (0);
+
+ he_seterrev(ev, _HE_NOT_FOUND);
+ return (-1);
+}
+
+
+/* history_next_string():
+ * Find the next event beginning with string
+ */
+private int
+history_next_string(History *h, HistEvent *ev, const char *str)
+{
+ size_t len = strlen(str);
+ int retval;
+
+ for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
+ if (strncmp(str, ev->str, len) == 0)
+ return (0);
+
+ he_seterrev(ev, _HE_NOT_FOUND);
+ return (-1);
+}
+
+
+/* history():
+ * User interface to history functions.
+ */
+int
+history(History *h, HistEvent *ev, int fun, ...)
+{
+ va_list va;
+ const char *str;
+ int retval;
+
+ va_start(va, fun);
+
+ he_seterrev(ev, _HE_OK);
+
+ switch (fun) {
+ case H_GETSIZE:
+ retval = history_getsize(h, ev);
+ break;
+
+ case H_SETSIZE:
+ retval = history_setsize(h, ev, va_arg(va, int));
+ break;
+
+ case H_GETUNIQUE:
+ retval = history_getunique(h, ev);
+ break;
+
+ case H_SETUNIQUE:
+ retval = history_setunique(h, ev, va_arg(va, int));
+ break;
+
+ case H_ADD:
+ str = va_arg(va, const char *);
+ retval = HADD(h, ev, str);
+ break;
+
+ case H_DEL:
+ retval = HDEL(h, ev, va_arg(va, const int));
+ break;
+
+ case H_ENTER:
+ str = va_arg(va, const char *);
+ if ((retval = HENTER(h, ev, str)) != -1)
+ h->h_ent = ev->num;
+ break;
+
+ case H_APPEND:
+ str = va_arg(va, const char *);
+ if ((retval = HSET(h, ev, h->h_ent)) != -1)
+ retval = HADD(h, ev, str);
+ break;
+
+ case H_FIRST:
+ retval = HFIRST(h, ev);
+ break;
+
+ case H_NEXT:
+ retval = HNEXT(h, ev);
+ break;
+
+ case H_LAST:
+ retval = HLAST(h, ev);
+ break;
+
+ case H_PREV:
+ retval = HPREV(h, ev);
+ break;
+
+ case H_CURR:
+ retval = HCURR(h, ev);
+ break;
+
+ case H_SET:
+ retval = HSET(h, ev, va_arg(va, const int));
+ break;
+
+ case H_CLEAR:
+ HCLEAR(h, ev);
+ retval = 0;
+ break;
+
+ case H_LOAD:
+ retval = history_load(h, va_arg(va, const char *));
+ if (retval == -1)
+ he_seterrev(ev, _HE_HIST_READ);
+ break;
+
+ case H_SAVE:
+ retval = history_save(h, va_arg(va, const char *));
+ if (retval == -1)
+ he_seterrev(ev, _HE_HIST_WRITE);
+ break;
+
+ case H_PREV_EVENT:
+ retval = history_prev_event(h, ev, va_arg(va, int));
+ break;
+
+ case H_NEXT_EVENT:
+ retval = history_next_event(h, ev, va_arg(va, int));
+ break;
+
+ case H_PREV_STR:
+ retval = history_prev_string(h, ev, va_arg(va, const char *));
+ break;
+
+ case H_NEXT_STR:
+ retval = history_next_string(h, ev, va_arg(va, const char *));
+ break;
+
+ case H_FUNC:
+ {
+ History hf;
+
+ hf.h_ref = va_arg(va, ptr_t);
+ h->h_ent = -1;
+ hf.h_first = va_arg(va, history_gfun_t);
+ hf.h_next = va_arg(va, history_gfun_t);
+ hf.h_last = va_arg(va, history_gfun_t);
+ hf.h_prev = va_arg(va, history_gfun_t);
+ hf.h_curr = va_arg(va, history_gfun_t);
+ hf.h_set = va_arg(va, history_sfun_t);
+ hf.h_clear = va_arg(va, history_vfun_t);
+ hf.h_enter = va_arg(va, history_efun_t);
+ hf.h_add = va_arg(va, history_efun_t);
+ hf.h_del = va_arg(va, history_sfun_t);
+
+ if ((retval = history_set_fun(h, &hf)) == -1)
+ he_seterrev(ev, _HE_PARAM_MISSING);
+ break;
+ }
+
+ case H_END:
+ history_end(h);
+ retval = 0;
+ break;
+
+ default:
+ retval = -1;
+ he_seterrev(ev, _HE_UNKNOWN);
+ break;
+ }
+ va_end(va);
+ return (retval);
+}
diff --git a/lib/libedit/key.c b/lib/libedit/key.c
new file mode 100644
index 0000000..16bfde69
--- /dev/null
+++ b/lib/libedit/key.c
@@ -0,0 +1,690 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell 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.
+ *
+ * $NetBSD: key.c,v 1.17 2005/08/08 14:05:37 christos Exp $
+ */
+
+#if !defined(lint) && !defined(SCCSID)
+static char sccsid[] = "@(#)key.c 8.1 (Berkeley) 6/4/93";
+#endif /* not lint && not SCCSID */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * key.c: This module contains the procedures for maintaining
+ * the extended-key map.
+ *
+ * An extended-key (key) is a sequence of keystrokes introduced
+ * with a sequence introducer and consisting of an arbitrary
+ * number of characters. This module maintains a map (the el->el_key.map)
+ * to convert these extended-key sequences into input strs
+ * (XK_STR), editor functions (XK_CMD), or unix commands (XK_EXE).
+ *
+ * Warning:
+ * If key is a substr of some other keys, then the longer
+ * keys are lost!! That is, if the keys "abcd" and "abcef"
+ * are in el->el_key.map, adding the key "abc" will cause the first two
+ * definitions to be lost.
+ *
+ * Restrictions:
+ * -------------
+ * 1) It is not possible to have one key that is a
+ * substr of another.
+ */
+#include <string.h>
+#include <stdlib.h>
+
+#include "el.h"
+
+/*
+ * The Nodes of the el->el_key.map. The el->el_key.map is a linked list
+ * of these node elements
+ */
+struct key_node_t {
+ char ch; /* single character of key */
+ int type; /* node type */
+ key_value_t val; /* command code or pointer to str, */
+ /* if this is a leaf */
+ struct key_node_t *next; /* ptr to next char of this key */
+ struct key_node_t *sibling; /* ptr to another key with same prefix*/
+};
+
+private int node_trav(EditLine *, key_node_t *, char *,
+ key_value_t *);
+private int node__try(EditLine *, key_node_t *, const char *,
+ key_value_t *, int);
+private key_node_t *node__get(int);
+private void node__free(key_node_t *);
+private void node__put(EditLine *, key_node_t *);
+private int node__delete(EditLine *, key_node_t **, const char *);
+private int node_lookup(EditLine *, const char *, key_node_t *,
+ int);
+private int node_enum(EditLine *, key_node_t *, int);
+private int key__decode_char(char *, int, int);
+
+#define KEY_BUFSIZ EL_BUFSIZ
+
+
+/* key_init():
+ * Initialize the key maps
+ */
+protected int
+key_init(EditLine *el)
+{
+
+ el->el_key.buf = (char *) el_malloc(KEY_BUFSIZ);
+ if (el->el_key.buf == NULL)
+ return (-1);
+ el->el_key.map = NULL;
+ key_reset(el);
+ return (0);
+}
+
+/* key_end():
+ * Free the key maps
+ */
+protected void
+key_end(EditLine *el)
+{
+
+ el_free((ptr_t) el->el_key.buf);
+ el->el_key.buf = NULL;
+ node__free(el->el_key.map);
+}
+
+
+/* key_map_cmd():
+ * Associate cmd with a key value
+ */
+protected key_value_t *
+key_map_cmd(EditLine *el, int cmd)
+{
+
+ el->el_key.val.cmd = (el_action_t) cmd;
+ return (&el->el_key.val);
+}
+
+
+/* key_map_str():
+ * Associate str with a key value
+ */
+protected key_value_t *
+key_map_str(EditLine *el, char *str)
+{
+
+ el->el_key.val.str = str;
+ return (&el->el_key.val);
+}
+
+
+/* key_reset():
+ * Takes all nodes on el->el_key.map and puts them on free list. Then
+ * initializes el->el_key.map with arrow keys
+ * [Always bind the ansi arrow keys?]
+ */
+protected void
+key_reset(EditLine *el)
+{
+
+ node__put(el, el->el_key.map);
+ el->el_key.map = NULL;
+ return;
+}
+
+
+/* key_get():
+ * Calls the recursive function with entry point el->el_key.map
+ * Looks up *ch in map and then reads characters until a
+ * complete match is found or a mismatch occurs. Returns the
+ * type of the match found (XK_STR, XK_CMD, or XK_EXE).
+ * Returns NULL in val.str and XK_STR for no match.
+ * The last character read is returned in *ch.
+ */
+protected int
+key_get(EditLine *el, char *ch, key_value_t *val)
+{
+
+ return (node_trav(el, el->el_key.map, ch, val));
+}
+
+
+/* key_add():
+ * Adds key to the el->el_key.map and associates the value in val with it.
+ * If key is already is in el->el_key.map, the new code is applied to the
+ * existing key. Ntype specifies if code is a command, an
+ * out str or a unix command.
+ */
+protected void
+key_add(EditLine *el, const char *key, key_value_t *val, int ntype)
+{
+
+ if (key[0] == '\0') {
+ (void) fprintf(el->el_errfile,
+ "key_add: Null extended-key not allowed.\n");
+ return;
+ }
+ if (ntype == XK_CMD && val->cmd == ED_SEQUENCE_LEAD_IN) {
+ (void) fprintf(el->el_errfile,
+ "key_add: sequence-lead-in command not allowed\n");
+ return;
+ }
+ if (el->el_key.map == NULL)
+ /* tree is initially empty. Set up new node to match key[0] */
+ el->el_key.map = node__get(key[0]);
+ /* it is properly initialized */
+
+ /* Now recurse through el->el_key.map */
+ (void) node__try(el, el->el_key.map, key, val, ntype);
+ return;
+}
+
+
+/* key_clear():
+ *
+ */
+protected void
+key_clear(EditLine *el, el_action_t *map, const char *in)
+{
+
+ if ((map[(unsigned char)*in] == ED_SEQUENCE_LEAD_IN) &&
+ ((map == el->el_map.key &&
+ el->el_map.alt[(unsigned char)*in] != ED_SEQUENCE_LEAD_IN) ||
+ (map == el->el_map.alt &&
+ el->el_map.key[(unsigned char)*in] != ED_SEQUENCE_LEAD_IN)))
+ (void) key_delete(el, in);
+}
+
+
+/* key_delete():
+ * Delete the key and all longer keys staring with key, if
+ * they exists.
+ */
+protected int
+key_delete(EditLine *el, const char *key)
+{
+
+ if (key[0] == '\0') {
+ (void) fprintf(el->el_errfile,
+ "key_delete: Null extended-key not allowed.\n");
+ return (-1);
+ }
+ if (el->el_key.map == NULL)
+ return (0);
+
+ (void) node__delete(el, &el->el_key.map, key);
+ return (0);
+}
+
+
+/* key_print():
+ * Print the binding associated with key key.
+ * Print entire el->el_key.map if null
+ */
+protected void
+key_print(EditLine *el, const char *key)
+{
+
+ /* do nothing if el->el_key.map is empty and null key specified */
+ if (el->el_key.map == NULL && *key == 0)
+ return;
+
+ el->el_key.buf[0] = '"';
+ if (node_lookup(el, key, el->el_key.map, 1) <= -1)
+ /* key is not bound */
+ (void) fprintf(el->el_errfile, "Unbound extended key \"%s\"\n",
+ key);
+ return;
+}
+
+
+/* node_trav():
+ * recursively traverses node in tree until match or mismatch is
+ * found. May read in more characters.
+ */
+private int
+node_trav(EditLine *el, key_node_t *ptr, char *ch, key_value_t *val)
+{
+
+ if (ptr->ch == *ch) {
+ /* match found */
+ if (ptr->next) {
+ /* key not complete so get next char */
+ if (el_getc(el, ch) != 1) { /* if EOF or error */
+ val->cmd = ED_END_OF_FILE;
+ return (XK_CMD);
+ /* PWP: Pretend we just read an end-of-file */
+ }
+ return (node_trav(el, ptr->next, ch, val));
+ } else {
+ *val = ptr->val;
+ if (ptr->type != XK_CMD)
+ *ch = '\0';
+ return (ptr->type);
+ }
+ } else {
+ /* no match found here */
+ if (ptr->sibling) {
+ /* try next sibling */
+ return (node_trav(el, ptr->sibling, ch, val));
+ } else {
+ /* no next sibling -- mismatch */
+ val->str = NULL;
+ return (XK_STR);
+ }
+ }
+}
+
+
+/* node__try():
+ * Find a node that matches *str or allocate a new one
+ */
+private int
+node__try(EditLine *el, key_node_t *ptr, const char *str, key_value_t *val, int ntype)
+{
+
+ if (ptr->ch != *str) {
+ key_node_t *xm;
+
+ for (xm = ptr; xm->sibling != NULL; xm = xm->sibling)
+ if (xm->sibling->ch == *str)
+ break;
+ if (xm->sibling == NULL)
+ xm->sibling = node__get(*str); /* setup new node */
+ ptr = xm->sibling;
+ }
+ if (*++str == '\0') {
+ /* we're there */
+ if (ptr->next != NULL) {
+ node__put(el, ptr->next);
+ /* lose longer keys with this prefix */
+ ptr->next = NULL;
+ }
+ switch (ptr->type) {
+ case XK_CMD:
+ case XK_NOD:
+ break;
+ case XK_STR:
+ case XK_EXE:
+ if (ptr->val.str)
+ el_free((ptr_t) ptr->val.str);
+ break;
+ default:
+ EL_ABORT((el->el_errfile, "Bad XK_ type %d\n",
+ ptr->type));
+ break;
+ }
+
+ switch (ptr->type = ntype) {
+ case XK_CMD:
+ ptr->val = *val;
+ break;
+ case XK_STR:
+ case XK_EXE:
+ if ((ptr->val.str = el_strdup(val->str)) == NULL)
+ return -1;
+ break;
+ default:
+ EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", ntype));
+ break;
+ }
+ } else {
+ /* still more chars to go */
+ if (ptr->next == NULL)
+ ptr->next = node__get(*str); /* setup new node */
+ (void) node__try(el, ptr->next, str, val, ntype);
+ }
+ return (0);
+}
+
+
+/* node__delete():
+ * Delete node that matches str
+ */
+private int
+node__delete(EditLine *el, key_node_t **inptr, const char *str)
+{
+ key_node_t *ptr;
+ key_node_t *prev_ptr = NULL;
+
+ ptr = *inptr;
+
+ if (ptr->ch != *str) {
+ key_node_t *xm;
+
+ for (xm = ptr; xm->sibling != NULL; xm = xm->sibling)
+ if (xm->sibling->ch == *str)
+ break;
+ if (xm->sibling == NULL)
+ return (0);
+ prev_ptr = xm;
+ ptr = xm->sibling;
+ }
+ if (*++str == '\0') {
+ /* we're there */
+ if (prev_ptr == NULL)
+ *inptr = ptr->sibling;
+ else
+ prev_ptr->sibling = ptr->sibling;
+ ptr->sibling = NULL;
+ node__put(el, ptr);
+ return (1);
+ } else if (ptr->next != NULL &&
+ node__delete(el, &ptr->next, str) == 1) {
+ if (ptr->next != NULL)
+ return (0);
+ if (prev_ptr == NULL)
+ *inptr = ptr->sibling;
+ else
+ prev_ptr->sibling = ptr->sibling;
+ ptr->sibling = NULL;
+ node__put(el, ptr);
+ return (1);
+ } else {
+ return (0);
+ }
+}
+
+
+/* node__put():
+ * Puts a tree of nodes onto free list using free(3).
+ */
+private void
+node__put(EditLine *el, key_node_t *ptr)
+{
+ if (ptr == NULL)
+ return;
+
+ if (ptr->next != NULL) {
+ node__put(el, ptr->next);
+ ptr->next = NULL;
+ }
+ node__put(el, ptr->sibling);
+
+ switch (ptr->type) {
+ case XK_CMD:
+ case XK_NOD:
+ break;
+ case XK_EXE:
+ case XK_STR:
+ if (ptr->val.str != NULL)
+ el_free((ptr_t) ptr->val.str);
+ break;
+ default:
+ EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", ptr->type));
+ break;
+ }
+ el_free((ptr_t) ptr);
+}
+
+
+/* node__get():
+ * Returns pointer to a key_node_t for ch.
+ */
+private key_node_t *
+node__get(int ch)
+{
+ key_node_t *ptr;
+
+ ptr = (key_node_t *) el_malloc((size_t) sizeof(key_node_t));
+ if (ptr == NULL)
+ return NULL;
+ ptr->ch = ch;
+ ptr->type = XK_NOD;
+ ptr->val.str = NULL;
+ ptr->next = NULL;
+ ptr->sibling = NULL;
+ return (ptr);
+}
+
+private void
+node__free(key_node_t *k)
+{
+ if (k == NULL)
+ return;
+ node__free(k->sibling);
+ node__free(k->next);
+ el_free((ptr_t) k);
+}
+
+/* node_lookup():
+ * look for the str starting at node ptr.
+ * Print if last node
+ */
+private int
+node_lookup(EditLine *el, const char *str, key_node_t *ptr, int cnt)
+{
+ int ncnt;
+
+ if (ptr == NULL)
+ return (-1); /* cannot have null ptr */
+
+ if (*str == 0) {
+ /* no more chars in str. node_enum from here. */
+ (void) node_enum(el, ptr, cnt);
+ return (0);
+ } else {
+ /* If match put this char into el->el_key.buf. Recurse */
+ if (ptr->ch == *str) {
+ /* match found */
+ ncnt = key__decode_char(el->el_key.buf, cnt,
+ (unsigned char) ptr->ch);
+ if (ptr->next != NULL)
+ /* not yet at leaf */
+ return (node_lookup(el, str + 1, ptr->next,
+ ncnt + 1));
+ else {
+ /* next node is null so key should be complete */
+ if (str[1] == 0) {
+ el->el_key.buf[ncnt + 1] = '"';
+ el->el_key.buf[ncnt + 2] = '\0';
+ key_kprint(el, el->el_key.buf,
+ &ptr->val, ptr->type);
+ return (0);
+ } else
+ return (-1);
+ /* mismatch -- str still has chars */
+ }
+ } else {
+ /* no match found try sibling */
+ if (ptr->sibling)
+ return (node_lookup(el, str, ptr->sibling,
+ cnt));
+ else
+ return (-1);
+ }
+ }
+}
+
+
+/* node_enum():
+ * Traverse the node printing the characters it is bound in buffer
+ */
+private int
+node_enum(EditLine *el, key_node_t *ptr, int cnt)
+{
+ int ncnt;
+
+ if (cnt >= KEY_BUFSIZ - 5) { /* buffer too small */
+ el->el_key.buf[++cnt] = '"';
+ el->el_key.buf[++cnt] = '\0';
+ (void) fprintf(el->el_errfile,
+ "Some extended keys too long for internal print buffer");
+ (void) fprintf(el->el_errfile, " \"%s...\"\n", el->el_key.buf);
+ return (0);
+ }
+ if (ptr == NULL) {
+#ifdef DEBUG_EDIT
+ (void) fprintf(el->el_errfile,
+ "node_enum: BUG!! Null ptr passed\n!");
+#endif
+ return (-1);
+ }
+ /* put this char at end of str */
+ ncnt = key__decode_char(el->el_key.buf, cnt, (unsigned char) ptr->ch);
+ if (ptr->next == NULL) {
+ /* print this key and function */
+ el->el_key.buf[ncnt + 1] = '"';
+ el->el_key.buf[ncnt + 2] = '\0';
+ key_kprint(el, el->el_key.buf, &ptr->val, ptr->type);
+ } else
+ (void) node_enum(el, ptr->next, ncnt + 1);
+
+ /* go to sibling if there is one */
+ if (ptr->sibling)
+ (void) node_enum(el, ptr->sibling, cnt);
+ return (0);
+}
+
+
+/* key_kprint():
+ * Print the specified key and its associated
+ * function specified by val
+ */
+protected void
+key_kprint(EditLine *el, const char *key, key_value_t *val, int ntype)
+{
+ el_bindings_t *fp;
+ char unparsbuf[EL_BUFSIZ];
+ static const char fmt[] = "%-15s-> %s\n";
+
+ if (val != NULL)
+ switch (ntype) {
+ case XK_STR:
+ case XK_EXE:
+ (void) fprintf(el->el_outfile, fmt, key,
+ key__decode_str(val->str, unparsbuf,
+ ntype == XK_STR ? "\"\"" : "[]"));
+ break;
+ case XK_CMD:
+ for (fp = el->el_map.help; fp->name; fp++)
+ if (val->cmd == fp->func) {
+ (void) fprintf(el->el_outfile, fmt,
+ key, fp->name);
+ break;
+ }
+#ifdef DEBUG_KEY
+ if (fp->name == NULL)
+ (void) fprintf(el->el_outfile,
+ "BUG! Command not found.\n");
+#endif
+
+ break;
+ default:
+ EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", ntype));
+ break;
+ }
+ else
+ (void) fprintf(el->el_outfile, fmt, key, "no input");
+}
+
+
+/* key__decode_char():
+ * Put a printable form of char in buf.
+ */
+private int
+key__decode_char(char *buf, int cnt, int ch)
+{
+ ch = (unsigned char)ch;
+
+ if (ch == 0) {
+ buf[cnt++] = '^';
+ buf[cnt] = '@';
+ return (cnt);
+ }
+ if (iscntrl(ch)) {
+ buf[cnt++] = '^';
+ if (ch == 0177)
+ buf[cnt] = '?';
+ else
+ buf[cnt] = toascii(ch) | 0100;
+ } else if (ch == '^') {
+ buf[cnt++] = '\\';
+ buf[cnt] = '^';
+ } else if (ch == '\\') {
+ buf[cnt++] = '\\';
+ buf[cnt] = '\\';
+ } else if (ch == ' ' || (isprint(ch) && !isspace(ch))) {
+ buf[cnt] = ch;
+ } else {
+ buf[cnt++] = '\\';
+ buf[cnt++] = (((unsigned int) ch >> 6) & 7) + '0';
+ buf[cnt++] = (((unsigned int) ch >> 3) & 7) + '0';
+ buf[cnt] = (ch & 7) + '0';
+ }
+ return (cnt);
+}
+
+
+/* key__decode_str():
+ * Make a printable version of the ey
+ */
+protected char *
+key__decode_str(const char *str, char *buf, const char *sep)
+{
+ char *b;
+ const char *p;
+
+ b = buf;
+ if (sep[0] != '\0')
+ *b++ = sep[0];
+ if (*str == 0) {
+ *b++ = '^';
+ *b++ = '@';
+ if (sep[0] != '\0' && sep[1] != '\0')
+ *b++ = sep[1];
+ *b++ = 0;
+ return (buf);
+ }
+ for (p = str; *p != 0; p++) {
+ if (iscntrl((unsigned char) *p)) {
+ *b++ = '^';
+ if (*p == '\177')
+ *b++ = '?';
+ else
+ *b++ = toascii(*p) | 0100;
+ } else if (*p == '^' || *p == '\\') {
+ *b++ = '\\';
+ *b++ = *p;
+ } else if (*p == ' ' || (isprint((unsigned char) *p) &&
+ !isspace((unsigned char) *p))) {
+ *b++ = *p;
+ } else {
+ *b++ = '\\';
+ *b++ = (((unsigned int) *p >> 6) & 7) + '0';
+ *b++ = (((unsigned int) *p >> 3) & 7) + '0';
+ *b++ = (*p & 7) + '0';
+ }
+ }
+ if (sep[0] != '\0' && sep[1] != '\0')
+ *b++ = sep[1];
+ *b++ = 0;
+ return (buf); /* should check for overflow */
+}
diff --git a/lib/libedit/key.h b/lib/libedit/key.h
new file mode 100644
index 0000000..0301f92
--- /dev/null
+++ b/lib/libedit/key.h
@@ -0,0 +1,81 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell 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.
+ *
+ * @(#)key.h 8.1 (Berkeley) 6/4/93
+ * $NetBSD: key.h,v 1.8 2003/08/07 16:44:32 agc Exp $
+ * $FreeBSD$
+ */
+
+/*
+ * el.key.h: Key macro header
+ */
+#ifndef _h_el_key
+#define _h_el_key
+
+typedef union key_value_t {
+ el_action_t cmd; /* If it is a command the # */
+ char *str; /* If it is a string... */
+} key_value_t;
+
+typedef struct key_node_t key_node_t;
+
+typedef struct el_key_t {
+ char *buf; /* Key print buffer */
+ key_node_t *map; /* Key map */
+ key_value_t val; /* Local conversion buffer */
+} el_key_t;
+
+#define XK_CMD 0
+#define XK_STR 1
+#define XK_NOD 2
+#define XK_EXE 3
+
+#include <term.h>
+
+#undef key_end
+#undef key_clear
+#undef key_print
+
+protected int key_init(EditLine *);
+protected void key_end(EditLine *);
+protected key_value_t *key_map_cmd(EditLine *, int);
+protected key_value_t *key_map_str(EditLine *, char *);
+protected void key_reset(EditLine *);
+protected int key_get(EditLine *, char *, key_value_t *);
+protected void key_add(EditLine *, const char *, key_value_t *, int);
+protected void key_clear(EditLine *, el_action_t *, const char *);
+protected int key_delete(EditLine *, const char *);
+protected void key_print(EditLine *, const char *);
+protected void key_kprint(EditLine *, const char *, key_value_t *,
+ int);
+protected char *key__decode_str(const char *, char *, const char *);
+
+#endif /* _h_el_key */
diff --git a/lib/libedit/makelist b/lib/libedit/makelist
new file mode 100644
index 0000000..e44a0e7
--- /dev/null
+++ b/lib/libedit/makelist
@@ -0,0 +1,250 @@
+#!/bin/sh -
+# $NetBSD: makelist,v 1.10 2005/08/08 14:04:49 christos Exp $
+# $FreeBSD$
+#
+# Copyright (c) 1992, 1993
+# The Regents of the University of California. All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Christos Zoulas of Cornell 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.
+#
+# @(#)makelist 5.3 (Berkeley) 6/4/93
+
+# makelist.sh: Automatically generate header files...
+
+AWK=awk
+USAGE="usage: $0 -h|-e|-fc|-fh|-bc|-bh|-m <filenames>"
+
+if [ "x$1" = "x" ]
+then
+ echo $USAGE 1>&2
+ exit 1
+fi
+
+FLAG="$1"
+shift
+
+FILES="$@"
+
+case $FLAG in
+
+# generate foo.h file from foo.c
+#
+-h)
+ set - `echo $FILES | sed -e 's/\\./_/g'`
+ hdr="_h_`basename $1`"
+ cat $FILES | $AWK '
+ BEGIN {
+ printf("/* Automatically generated file, do not edit */\n");
+ printf("#ifndef %s\n#define %s\n", "'$hdr'", "'$hdr'");
+ }
+ /\(\):/ {
+ pr = substr($2, 1, 2);
+ if (pr == "vi" || pr == "em" || pr == "ed") {
+ name = substr($2, 1, length($2) - 3);
+#
+# XXX: need a space between name and prototype so that -fc and -fh
+# parsing is much easier
+#
+ printf("protected el_action_t\t%s (EditLine *, int);\n", name);
+ }
+ }
+ END {
+ printf("#endif /* %s */\n", "'$hdr'");
+ }'
+ ;;
+
+# generate help.c from various .c files
+#
+-bc)
+ cat $FILES | $AWK '
+ BEGIN {
+ printf("/* Automatically generated file, do not edit */\n");
+ printf("#include \"sys.h\"\n#include \"el.h\"\n");
+ printf("private const struct el_bindings_t el_func_help[] = {\n");
+ low = "abcdefghijklmnopqrstuvwxyz_";
+ high = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_";
+ for (i = 1; i <= length(low); i++)
+ tr[substr(low, i, 1)] = substr(high, i, 1);
+ }
+ /\(\):/ {
+ pr = substr($2, 1, 2);
+ if (pr == "vi" || pr == "em" || pr == "ed") {
+ name = substr($2, 1, length($2) - 3);
+ uname = "";
+ fname = "";
+ for (i = 1; i <= length(name); i++) {
+ s = substr(name, i, 1);
+ uname = uname tr[s];
+ if (s == "_")
+ s = "-";
+ fname = fname s;
+ }
+
+ printf(" { %-30.30s %-30.30s\n","\"" fname "\",", uname ",");
+ ok = 1;
+ }
+ }
+ /^ \*/ {
+ if (ok) {
+ printf(" \"");
+ for (i = 2; i < NF; i++)
+ printf("%s ", $i);
+ printf("%s\" },\n", $i);
+ ok = 0;
+ }
+ }
+ END {
+ printf("};\n");
+ printf("\nprotected const el_bindings_t* help__get()");
+ printf("{ return el_func_help; }\n");
+ }'
+ ;;
+
+# generate help.h from various .c files
+#
+-bh)
+ $AWK '
+ BEGIN {
+ printf("/* Automatically generated file, do not edit */\n");
+ printf("#ifndef _h_help_c\n#define _h_help_c\n");
+ printf("protected const el_bindings_t *help__get(void);\n");
+ printf("#endif /* _h_help_c */\n");
+ }' /dev/null
+ ;;
+
+# generate fcns.h from various .h files
+#
+-fh)
+ cat $FILES | $AWK '/el_action_t/ { print $3 }' | \
+ sort | LC_ALL=C tr 'a-z' 'A-Z' | $AWK '
+ BEGIN {
+ printf("/* Automatically generated file, do not edit */\n");
+ printf("#ifndef _h_fcns_c\n#define _h_fcns_c\n");
+ count = 0;
+ }
+ {
+ printf("#define\t%-30.30s\t%3d\n", $1, count++);
+ }
+ END {
+ printf("#define\t%-30.30s\t%3d\n", "EL_NUM_FCNS", count);
+
+ printf("typedef el_action_t (*el_func_t)(EditLine *, int);");
+ printf("\nprotected const el_func_t* func__get(void);\n");
+ printf("#endif /* _h_fcns_c */\n");
+ }'
+ ;;
+
+# generate fcns.c from various .h files
+#
+-fc)
+ cat $FILES | $AWK '/el_action_t/ { print $3 }' | sort | $AWK '
+ BEGIN {
+ printf("/* Automatically generated file, do not edit */\n");
+ printf("#include \"sys.h\"\n#include \"el.h\"\n");
+ printf("private const el_func_t el_func[] = {");
+ maxlen = 80;
+ needn = 1;
+ len = 0;
+ }
+ {
+ clen = 25 + 2;
+ len += clen;
+ if (len >= maxlen)
+ needn = 1;
+ if (needn) {
+ printf("\n ");
+ needn = 0;
+ len = 4 + clen;
+ }
+ s = $1 ",";
+ printf("%-26.26s ", s);
+ }
+ END {
+ printf("\n};\n");
+ printf("\nprotected const el_func_t* func__get() { return el_func; }\n");
+ }'
+ ;;
+
+# generate editline.c from various .c files
+#
+-e)
+ echo "$FILES" | tr ' ' '\012' | $AWK '
+ BEGIN {
+ printf("/* Automatically generated file, do not edit */\n");
+ printf("#define protected static\n");
+ printf("#define SCCSID\n");
+ }
+ {
+ printf("#include \"%s\"\n", $1);
+ }'
+ ;;
+
+# generate man page fragment from various .c files
+#
+-m)
+ cat $FILES | $AWK '
+ BEGIN {
+ printf(".\\\" Section automatically generated with makelist\n");
+ printf(".Bl -tag -width 4n\n");
+ }
+ /\(\):/ {
+ pr = substr($2, 1, 2);
+ if (pr == "vi" || pr == "em" || pr == "ed") {
+ name = substr($2, 1, length($2) - 3);
+ fname = "";
+ for (i = 1; i <= length(name); i++) {
+ s = substr(name, i, 1);
+ if (s == "_")
+ s = "-";
+ fname = fname s;
+ }
+
+ printf(".It Ic %s\n", fname);
+ ok = 1;
+ }
+ }
+ /^ \*/ {
+ if (ok) {
+ for (i = 2; i < NF; i++)
+ printf("%s ", $i);
+ printf("%s.\n", $i);
+ ok = 0;
+ }
+ }
+ END {
+ printf(".El\n");
+ printf(".\\\" End of section automatically generated with makelist\n");
+ }'
+ ;;
+
+*)
+ echo $USAGE 1>&2
+ exit 1
+ ;;
+
+esac
diff --git a/lib/libedit/map.c b/lib/libedit/map.c
new file mode 100644
index 0000000..76c9e4d
--- /dev/null
+++ b/lib/libedit/map.c
@@ -0,0 +1,1413 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell 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.
+ *
+ * $NetBSD: map.c,v 1.22 2005/08/09 13:58:44 christos Exp $
+ */
+
+#if !defined(lint) && !defined(SCCSID)
+static char sccsid[] = "@(#)map.c 8.1 (Berkeley) 6/4/93";
+#endif /* not lint && not SCCSID */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * map.c: Editor function definitions
+ */
+#include "sys.h"
+#include <stdlib.h>
+#include "el.h"
+
+#define N_KEYS 256
+
+private void map_print_key(EditLine *, el_action_t *, const char *);
+private void map_print_some_keys(EditLine *, el_action_t *, int, int);
+private void map_print_all_keys(EditLine *);
+private void map_init_nls(EditLine *);
+private void map_init_meta(EditLine *);
+
+/* keymap tables ; should be N_KEYS*sizeof(KEYCMD) bytes long */
+
+
+private const el_action_t el_map_emacs[] = {
+ /* 0 */ EM_SET_MARK, /* ^@ */
+ /* 1 */ ED_MOVE_TO_BEG, /* ^A */
+ /* 2 */ ED_PREV_CHAR, /* ^B */
+ /* 3 */ ED_TTY_SIGINT, /* ^C */
+ /* 4 */ EM_DELETE_OR_LIST, /* ^D */
+ /* 5 */ ED_MOVE_TO_END, /* ^E */
+ /* 6 */ ED_NEXT_CHAR, /* ^F */
+ /* 7 */ ED_UNASSIGNED, /* ^G */
+ /* 8 */ EM_DELETE_PREV_CHAR, /* ^H */
+ /* 9 */ ED_UNASSIGNED, /* ^I */
+ /* 10 */ ED_NEWLINE, /* ^J */
+ /* 11 */ ED_KILL_LINE, /* ^K */
+ /* 12 */ ED_CLEAR_SCREEN, /* ^L */
+ /* 13 */ ED_NEWLINE, /* ^M */
+ /* 14 */ ED_NEXT_HISTORY, /* ^N */
+ /* 15 */ ED_TTY_FLUSH_OUTPUT, /* ^O */
+ /* 16 */ ED_PREV_HISTORY, /* ^P */
+ /* 17 */ ED_TTY_START_OUTPUT, /* ^Q */
+ /* 18 */ ED_REDISPLAY, /* ^R */
+ /* 19 */ ED_TTY_STOP_OUTPUT, /* ^S */
+ /* 20 */ ED_TRANSPOSE_CHARS, /* ^T */
+ /* 21 */ EM_KILL_LINE, /* ^U */
+ /* 22 */ ED_QUOTED_INSERT, /* ^V */
+ /* 23 */ EM_KILL_REGION, /* ^W */
+ /* 24 */ ED_SEQUENCE_LEAD_IN, /* ^X */
+ /* 25 */ EM_YANK, /* ^Y */
+ /* 26 */ ED_TTY_SIGTSTP, /* ^Z */
+ /* 27 */ EM_META_NEXT, /* ^[ */
+ /* 28 */ ED_TTY_SIGQUIT, /* ^\ */
+ /* 29 */ ED_TTY_DSUSP, /* ^] */
+ /* 30 */ ED_UNASSIGNED, /* ^^ */
+ /* 31 */ ED_UNASSIGNED, /* ^_ */
+ /* 32 */ ED_INSERT, /* SPACE */
+ /* 33 */ ED_INSERT, /* ! */
+ /* 34 */ ED_INSERT, /* " */
+ /* 35 */ ED_INSERT, /* # */
+ /* 36 */ ED_INSERT, /* $ */
+ /* 37 */ ED_INSERT, /* % */
+ /* 38 */ ED_INSERT, /* & */
+ /* 39 */ ED_INSERT, /* ' */
+ /* 40 */ ED_INSERT, /* ( */
+ /* 41 */ ED_INSERT, /* ) */
+ /* 42 */ ED_INSERT, /* * */
+ /* 43 */ ED_INSERT, /* + */
+ /* 44 */ ED_INSERT, /* , */
+ /* 45 */ ED_INSERT, /* - */
+ /* 46 */ ED_INSERT, /* . */
+ /* 47 */ ED_INSERT, /* / */
+ /* 48 */ ED_DIGIT, /* 0 */
+ /* 49 */ ED_DIGIT, /* 1 */
+ /* 50 */ ED_DIGIT, /* 2 */
+ /* 51 */ ED_DIGIT, /* 3 */
+ /* 52 */ ED_DIGIT, /* 4 */
+ /* 53 */ ED_DIGIT, /* 5 */
+ /* 54 */ ED_DIGIT, /* 6 */
+ /* 55 */ ED_DIGIT, /* 7 */
+ /* 56 */ ED_DIGIT, /* 8 */
+ /* 57 */ ED_DIGIT, /* 9 */
+ /* 58 */ ED_INSERT, /* : */
+ /* 59 */ ED_INSERT, /* ; */
+ /* 60 */ ED_INSERT, /* < */
+ /* 61 */ ED_INSERT, /* = */
+ /* 62 */ ED_INSERT, /* > */
+ /* 63 */ ED_INSERT, /* ? */
+ /* 64 */ ED_INSERT, /* @ */
+ /* 65 */ ED_INSERT, /* A */
+ /* 66 */ ED_INSERT, /* B */
+ /* 67 */ ED_INSERT, /* C */
+ /* 68 */ ED_INSERT, /* D */
+ /* 69 */ ED_INSERT, /* E */
+ /* 70 */ ED_INSERT, /* F */
+ /* 71 */ ED_INSERT, /* G */
+ /* 72 */ ED_INSERT, /* H */
+ /* 73 */ ED_INSERT, /* I */
+ /* 74 */ ED_INSERT, /* J */
+ /* 75 */ ED_INSERT, /* K */
+ /* 76 */ ED_INSERT, /* L */
+ /* 77 */ ED_INSERT, /* M */
+ /* 78 */ ED_INSERT, /* N */
+ /* 79 */ ED_INSERT, /* O */
+ /* 80 */ ED_INSERT, /* P */
+ /* 81 */ ED_INSERT, /* Q */
+ /* 82 */ ED_INSERT, /* R */
+ /* 83 */ ED_INSERT, /* S */
+ /* 84 */ ED_INSERT, /* T */
+ /* 85 */ ED_INSERT, /* U */
+ /* 86 */ ED_INSERT, /* V */
+ /* 87 */ ED_INSERT, /* W */
+ /* 88 */ ED_INSERT, /* X */
+ /* 89 */ ED_INSERT, /* Y */
+ /* 90 */ ED_INSERT, /* Z */
+ /* 91 */ ED_INSERT, /* [ */
+ /* 92 */ ED_INSERT, /* \ */
+ /* 93 */ ED_INSERT, /* ] */
+ /* 94 */ ED_INSERT, /* ^ */
+ /* 95 */ ED_INSERT, /* _ */
+ /* 96 */ ED_INSERT, /* ` */
+ /* 97 */ ED_INSERT, /* a */
+ /* 98 */ ED_INSERT, /* b */
+ /* 99 */ ED_INSERT, /* c */
+ /* 100 */ ED_INSERT, /* d */
+ /* 101 */ ED_INSERT, /* e */
+ /* 102 */ ED_INSERT, /* f */
+ /* 103 */ ED_INSERT, /* g */
+ /* 104 */ ED_INSERT, /* h */
+ /* 105 */ ED_INSERT, /* i */
+ /* 106 */ ED_INSERT, /* j */
+ /* 107 */ ED_INSERT, /* k */
+ /* 108 */ ED_INSERT, /* l */
+ /* 109 */ ED_INSERT, /* m */
+ /* 110 */ ED_INSERT, /* n */
+ /* 111 */ ED_INSERT, /* o */
+ /* 112 */ ED_INSERT, /* p */
+ /* 113 */ ED_INSERT, /* q */
+ /* 114 */ ED_INSERT, /* r */
+ /* 115 */ ED_INSERT, /* s */
+ /* 116 */ ED_INSERT, /* t */
+ /* 117 */ ED_INSERT, /* u */
+ /* 118 */ ED_INSERT, /* v */
+ /* 119 */ ED_INSERT, /* w */
+ /* 120 */ ED_INSERT, /* x */
+ /* 121 */ ED_INSERT, /* y */
+ /* 122 */ ED_INSERT, /* z */
+ /* 123 */ ED_INSERT, /* { */
+ /* 124 */ ED_INSERT, /* | */
+ /* 125 */ ED_INSERT, /* } */
+ /* 126 */ ED_INSERT, /* ~ */
+ /* 127 */ EM_DELETE_PREV_CHAR, /* ^? */
+ /* 128 */ ED_UNASSIGNED, /* M-^@ */
+ /* 129 */ ED_UNASSIGNED, /* M-^A */
+ /* 130 */ ED_UNASSIGNED, /* M-^B */
+ /* 131 */ ED_UNASSIGNED, /* M-^C */
+ /* 132 */ ED_UNASSIGNED, /* M-^D */
+ /* 133 */ ED_UNASSIGNED, /* M-^E */
+ /* 134 */ ED_UNASSIGNED, /* M-^F */
+ /* 135 */ ED_UNASSIGNED, /* M-^G */
+ /* 136 */ ED_DELETE_PREV_WORD, /* M-^H */
+ /* 137 */ ED_UNASSIGNED, /* M-^I */
+ /* 138 */ ED_UNASSIGNED, /* M-^J */
+ /* 139 */ ED_UNASSIGNED, /* M-^K */
+ /* 140 */ ED_CLEAR_SCREEN, /* M-^L */
+ /* 141 */ ED_UNASSIGNED, /* M-^M */
+ /* 142 */ ED_UNASSIGNED, /* M-^N */
+ /* 143 */ ED_UNASSIGNED, /* M-^O */
+ /* 144 */ ED_UNASSIGNED, /* M-^P */
+ /* 145 */ ED_UNASSIGNED, /* M-^Q */
+ /* 146 */ ED_UNASSIGNED, /* M-^R */
+ /* 147 */ ED_UNASSIGNED, /* M-^S */
+ /* 148 */ ED_UNASSIGNED, /* M-^T */
+ /* 149 */ ED_UNASSIGNED, /* M-^U */
+ /* 150 */ ED_UNASSIGNED, /* M-^V */
+ /* 151 */ ED_UNASSIGNED, /* M-^W */
+ /* 152 */ ED_UNASSIGNED, /* M-^X */
+ /* 153 */ ED_UNASSIGNED, /* M-^Y */
+ /* 154 */ ED_UNASSIGNED, /* M-^Z */
+ /* 155 */ ED_UNASSIGNED, /* M-^[ */
+ /* 156 */ ED_UNASSIGNED, /* M-^\ */
+ /* 157 */ ED_UNASSIGNED, /* M-^] */
+ /* 158 */ ED_UNASSIGNED, /* M-^^ */
+ /* 159 */ EM_COPY_PREV_WORD, /* M-^_ */
+ /* 160 */ ED_UNASSIGNED, /* M-SPACE */
+ /* 161 */ ED_UNASSIGNED, /* M-! */
+ /* 162 */ ED_UNASSIGNED, /* M-" */
+ /* 163 */ ED_UNASSIGNED, /* M-# */
+ /* 164 */ ED_UNASSIGNED, /* M-$ */
+ /* 165 */ ED_UNASSIGNED, /* M-% */
+ /* 166 */ ED_UNASSIGNED, /* M-& */
+ /* 167 */ ED_UNASSIGNED, /* M-' */
+ /* 168 */ ED_UNASSIGNED, /* M-( */
+ /* 169 */ ED_UNASSIGNED, /* M-) */
+ /* 170 */ ED_UNASSIGNED, /* M-* */
+ /* 171 */ ED_UNASSIGNED, /* M-+ */
+ /* 172 */ ED_UNASSIGNED, /* M-, */
+ /* 173 */ ED_UNASSIGNED, /* M-- */
+ /* 174 */ ED_UNASSIGNED, /* M-. */
+ /* 175 */ ED_UNASSIGNED, /* M-/ */
+ /* 176 */ ED_ARGUMENT_DIGIT, /* M-0 */
+ /* 177 */ ED_ARGUMENT_DIGIT, /* M-1 */
+ /* 178 */ ED_ARGUMENT_DIGIT, /* M-2 */
+ /* 179 */ ED_ARGUMENT_DIGIT, /* M-3 */
+ /* 180 */ ED_ARGUMENT_DIGIT, /* M-4 */
+ /* 181 */ ED_ARGUMENT_DIGIT, /* M-5 */
+ /* 182 */ ED_ARGUMENT_DIGIT, /* M-6 */
+ /* 183 */ ED_ARGUMENT_DIGIT, /* M-7 */
+ /* 184 */ ED_ARGUMENT_DIGIT, /* M-8 */
+ /* 185 */ ED_ARGUMENT_DIGIT, /* M-9 */
+ /* 186 */ ED_UNASSIGNED, /* M-: */
+ /* 187 */ ED_UNASSIGNED, /* M-; */
+ /* 188 */ ED_UNASSIGNED, /* M-< */
+ /* 189 */ ED_UNASSIGNED, /* M-= */
+ /* 190 */ ED_UNASSIGNED, /* M-> */
+ /* 191 */ ED_UNASSIGNED, /* M-? */
+ /* 192 */ ED_UNASSIGNED, /* M-@ */
+ /* 193 */ ED_UNASSIGNED, /* M-A */
+ /* 194 */ ED_PREV_WORD, /* M-B */
+ /* 195 */ EM_CAPITOL_CASE, /* M-C */
+ /* 196 */ EM_DELETE_NEXT_WORD, /* M-D */
+ /* 197 */ ED_UNASSIGNED, /* M-E */
+ /* 198 */ EM_NEXT_WORD, /* M-F */
+ /* 199 */ ED_UNASSIGNED, /* M-G */
+ /* 200 */ ED_UNASSIGNED, /* M-H */
+ /* 201 */ ED_UNASSIGNED, /* M-I */
+ /* 202 */ ED_UNASSIGNED, /* M-J */
+ /* 203 */ ED_UNASSIGNED, /* M-K */
+ /* 204 */ EM_LOWER_CASE, /* M-L */
+ /* 205 */ ED_UNASSIGNED, /* M-M */
+ /* 206 */ ED_SEARCH_NEXT_HISTORY, /* M-N */
+ /* 207 */ ED_SEQUENCE_LEAD_IN, /* M-O */
+ /* 208 */ ED_SEARCH_PREV_HISTORY, /* M-P */
+ /* 209 */ ED_UNASSIGNED, /* M-Q */
+ /* 210 */ ED_UNASSIGNED, /* M-R */
+ /* 211 */ ED_UNASSIGNED, /* M-S */
+ /* 212 */ ED_UNASSIGNED, /* M-T */
+ /* 213 */ EM_UPPER_CASE, /* M-U */
+ /* 214 */ ED_UNASSIGNED, /* M-V */
+ /* 215 */ EM_COPY_REGION, /* M-W */
+ /* 216 */ ED_COMMAND, /* M-X */
+ /* 217 */ ED_UNASSIGNED, /* M-Y */
+ /* 218 */ ED_UNASSIGNED, /* M-Z */
+ /* 219 */ ED_SEQUENCE_LEAD_IN, /* M-[ */
+ /* 220 */ ED_UNASSIGNED, /* M-\ */
+ /* 221 */ ED_UNASSIGNED, /* M-] */
+ /* 222 */ ED_UNASSIGNED, /* M-^ */
+ /* 223 */ ED_UNASSIGNED, /* M-_ */
+ /* 223 */ ED_UNASSIGNED, /* M-` */
+ /* 224 */ ED_UNASSIGNED, /* M-a */
+ /* 225 */ ED_PREV_WORD, /* M-b */
+ /* 226 */ EM_CAPITOL_CASE, /* M-c */
+ /* 227 */ EM_DELETE_NEXT_WORD, /* M-d */
+ /* 228 */ ED_UNASSIGNED, /* M-e */
+ /* 229 */ EM_NEXT_WORD, /* M-f */
+ /* 230 */ ED_UNASSIGNED, /* M-g */
+ /* 231 */ ED_UNASSIGNED, /* M-h */
+ /* 232 */ ED_UNASSIGNED, /* M-i */
+ /* 233 */ ED_UNASSIGNED, /* M-j */
+ /* 234 */ ED_UNASSIGNED, /* M-k */
+ /* 235 */ EM_LOWER_CASE, /* M-l */
+ /* 236 */ ED_UNASSIGNED, /* M-m */
+ /* 237 */ ED_SEARCH_NEXT_HISTORY, /* M-n */
+ /* 238 */ ED_UNASSIGNED, /* M-o */
+ /* 239 */ ED_SEARCH_PREV_HISTORY, /* M-p */
+ /* 240 */ ED_UNASSIGNED, /* M-q */
+ /* 241 */ ED_UNASSIGNED, /* M-r */
+ /* 242 */ ED_UNASSIGNED, /* M-s */
+ /* 243 */ ED_UNASSIGNED, /* M-t */
+ /* 244 */ EM_UPPER_CASE, /* M-u */
+ /* 245 */ ED_UNASSIGNED, /* M-v */
+ /* 246 */ EM_COPY_REGION, /* M-w */
+ /* 247 */ ED_COMMAND, /* M-x */
+ /* 248 */ ED_UNASSIGNED, /* M-y */
+ /* 249 */ ED_UNASSIGNED, /* M-z */
+ /* 250 */ ED_UNASSIGNED, /* M-{ */
+ /* 251 */ ED_UNASSIGNED, /* M-| */
+ /* 252 */ ED_UNASSIGNED, /* M-} */
+ /* 253 */ ED_UNASSIGNED, /* M-~ */
+ /* 254 */ ED_DELETE_PREV_WORD /* M-^? */
+ /* 255 */
+};
+
+
+/*
+ * keymap table for vi. Each index into above tbl; should be
+ * N_KEYS entries long. Vi mode uses a sticky-extend to do command mode:
+ * insert mode characters are in the normal keymap, and command mode
+ * in the extended keymap.
+ */
+private const el_action_t el_map_vi_insert[] = {
+#ifdef KSHVI
+ /* 0 */ ED_UNASSIGNED, /* ^@ */
+ /* 1 */ ED_INSERT, /* ^A */
+ /* 2 */ ED_INSERT, /* ^B */
+ /* 3 */ ED_INSERT, /* ^C */
+ /* 4 */ VI_LIST_OR_EOF, /* ^D */
+ /* 5 */ ED_INSERT, /* ^E */
+ /* 6 */ ED_INSERT, /* ^F */
+ /* 7 */ ED_INSERT, /* ^G */
+ /* 8 */ VI_DELETE_PREV_CHAR, /* ^H */ /* BackSpace key */
+ /* 9 */ ED_INSERT, /* ^I */ /* Tab Key */
+ /* 10 */ ED_NEWLINE, /* ^J */
+ /* 11 */ ED_INSERT, /* ^K */
+ /* 12 */ ED_INSERT, /* ^L */
+ /* 13 */ ED_NEWLINE, /* ^M */
+ /* 14 */ ED_INSERT, /* ^N */
+ /* 15 */ ED_INSERT, /* ^O */
+ /* 16 */ ED_INSERT, /* ^P */
+ /* 17 */ ED_TTY_START_OUTPUT, /* ^Q */
+ /* 18 */ ED_INSERT, /* ^R */
+ /* 19 */ ED_TTY_STOP_OUTPUT, /* ^S */
+ /* 20 */ ED_INSERT, /* ^T */
+ /* 21 */ VI_KILL_LINE_PREV, /* ^U */
+ /* 22 */ ED_QUOTED_INSERT, /* ^V */
+ /* 23 */ ED_DELETE_PREV_WORD, /* ^W */
+ /* ED_DELETE_PREV_WORD: Only until strt edit pos */
+ /* 24 */ ED_INSERT, /* ^X */
+ /* 25 */ ED_INSERT, /* ^Y */
+ /* 26 */ ED_INSERT, /* ^Z */
+ /* 27 */ VI_COMMAND_MODE, /* ^[ */ /* [ Esc ] key */
+ /* 28 */ ED_TTY_SIGQUIT, /* ^\ */
+ /* 29 */ ED_INSERT, /* ^] */
+ /* 30 */ ED_INSERT, /* ^^ */
+ /* 31 */ ED_INSERT, /* ^_ */
+#else /* !KSHVI */
+ /*
+ * NOTE: These mappings do NOT Correspond well
+ * to the KSH VI editing assignments.
+ * On the other and they are convenient and
+ * many people have have gotten used to them.
+ */
+ /* 0 */ ED_UNASSIGNED, /* ^@ */
+ /* 1 */ ED_MOVE_TO_BEG, /* ^A */
+ /* 2 */ ED_PREV_CHAR, /* ^B */
+ /* 3 */ ED_TTY_SIGINT, /* ^C */
+ /* 4 */ VI_LIST_OR_EOF, /* ^D */
+ /* 5 */ ED_MOVE_TO_END, /* ^E */
+ /* 6 */ ED_NEXT_CHAR, /* ^F */
+ /* 7 */ ED_UNASSIGNED, /* ^G */
+ /* 8 */ VI_DELETE_PREV_CHAR, /* ^H */ /* BackSpace key */
+ /* 9 */ ED_UNASSIGNED, /* ^I */ /* Tab Key */
+ /* 10 */ ED_NEWLINE, /* ^J */
+ /* 11 */ ED_KILL_LINE, /* ^K */
+ /* 12 */ ED_CLEAR_SCREEN, /* ^L */
+ /* 13 */ ED_NEWLINE, /* ^M */
+ /* 14 */ ED_NEXT_HISTORY, /* ^N */
+ /* 15 */ ED_TTY_FLUSH_OUTPUT, /* ^O */
+ /* 16 */ ED_PREV_HISTORY, /* ^P */
+ /* 17 */ ED_TTY_START_OUTPUT, /* ^Q */
+ /* 18 */ ED_REDISPLAY, /* ^R */
+ /* 19 */ ED_TTY_STOP_OUTPUT, /* ^S */
+ /* 20 */ ED_TRANSPOSE_CHARS, /* ^T */
+ /* 21 */ VI_KILL_LINE_PREV, /* ^U */
+ /* 22 */ ED_QUOTED_INSERT, /* ^V */
+ /* 23 */ ED_DELETE_PREV_WORD, /* ^W */
+ /* 24 */ ED_UNASSIGNED, /* ^X */
+ /* 25 */ ED_TTY_DSUSP, /* ^Y */
+ /* 26 */ ED_TTY_SIGTSTP, /* ^Z */
+ /* 27 */ VI_COMMAND_MODE, /* ^[ */
+ /* 28 */ ED_TTY_SIGQUIT, /* ^\ */
+ /* 29 */ ED_UNASSIGNED, /* ^] */
+ /* 30 */ ED_UNASSIGNED, /* ^^ */
+ /* 31 */ ED_UNASSIGNED, /* ^_ */
+#endif /* KSHVI */
+ /* 32 */ ED_INSERT, /* SPACE */
+ /* 33 */ ED_INSERT, /* ! */
+ /* 34 */ ED_INSERT, /* " */
+ /* 35 */ ED_INSERT, /* # */
+ /* 36 */ ED_INSERT, /* $ */
+ /* 37 */ ED_INSERT, /* % */
+ /* 38 */ ED_INSERT, /* & */
+ /* 39 */ ED_INSERT, /* ' */
+ /* 40 */ ED_INSERT, /* ( */
+ /* 41 */ ED_INSERT, /* ) */
+ /* 42 */ ED_INSERT, /* * */
+ /* 43 */ ED_INSERT, /* + */
+ /* 44 */ ED_INSERT, /* , */
+ /* 45 */ ED_INSERT, /* - */
+ /* 46 */ ED_INSERT, /* . */
+ /* 47 */ ED_INSERT, /* / */
+ /* 48 */ ED_INSERT, /* 0 */
+ /* 49 */ ED_INSERT, /* 1 */
+ /* 50 */ ED_INSERT, /* 2 */
+ /* 51 */ ED_INSERT, /* 3 */
+ /* 52 */ ED_INSERT, /* 4 */
+ /* 53 */ ED_INSERT, /* 5 */
+ /* 54 */ ED_INSERT, /* 6 */
+ /* 55 */ ED_INSERT, /* 7 */
+ /* 56 */ ED_INSERT, /* 8 */
+ /* 57 */ ED_INSERT, /* 9 */
+ /* 58 */ ED_INSERT, /* : */
+ /* 59 */ ED_INSERT, /* ; */
+ /* 60 */ ED_INSERT, /* < */
+ /* 61 */ ED_INSERT, /* = */
+ /* 62 */ ED_INSERT, /* > */
+ /* 63 */ ED_INSERT, /* ? */
+ /* 64 */ ED_INSERT, /* @ */
+ /* 65 */ ED_INSERT, /* A */
+ /* 66 */ ED_INSERT, /* B */
+ /* 67 */ ED_INSERT, /* C */
+ /* 68 */ ED_INSERT, /* D */
+ /* 69 */ ED_INSERT, /* E */
+ /* 70 */ ED_INSERT, /* F */
+ /* 71 */ ED_INSERT, /* G */
+ /* 72 */ ED_INSERT, /* H */
+ /* 73 */ ED_INSERT, /* I */
+ /* 74 */ ED_INSERT, /* J */
+ /* 75 */ ED_INSERT, /* K */
+ /* 76 */ ED_INSERT, /* L */
+ /* 77 */ ED_INSERT, /* M */
+ /* 78 */ ED_INSERT, /* N */
+ /* 79 */ ED_INSERT, /* O */
+ /* 80 */ ED_INSERT, /* P */
+ /* 81 */ ED_INSERT, /* Q */
+ /* 82 */ ED_INSERT, /* R */
+ /* 83 */ ED_INSERT, /* S */
+ /* 84 */ ED_INSERT, /* T */
+ /* 85 */ ED_INSERT, /* U */
+ /* 86 */ ED_INSERT, /* V */
+ /* 87 */ ED_INSERT, /* W */
+ /* 88 */ ED_INSERT, /* X */
+ /* 89 */ ED_INSERT, /* Y */
+ /* 90 */ ED_INSERT, /* Z */
+ /* 91 */ ED_INSERT, /* [ */
+ /* 92 */ ED_INSERT, /* \ */
+ /* 93 */ ED_INSERT, /* ] */
+ /* 94 */ ED_INSERT, /* ^ */
+ /* 95 */ ED_INSERT, /* _ */
+ /* 96 */ ED_INSERT, /* ` */
+ /* 97 */ ED_INSERT, /* a */
+ /* 98 */ ED_INSERT, /* b */
+ /* 99 */ ED_INSERT, /* c */
+ /* 100 */ ED_INSERT, /* d */
+ /* 101 */ ED_INSERT, /* e */
+ /* 102 */ ED_INSERT, /* f */
+ /* 103 */ ED_INSERT, /* g */
+ /* 104 */ ED_INSERT, /* h */
+ /* 105 */ ED_INSERT, /* i */
+ /* 106 */ ED_INSERT, /* j */
+ /* 107 */ ED_INSERT, /* k */
+ /* 108 */ ED_INSERT, /* l */
+ /* 109 */ ED_INSERT, /* m */
+ /* 110 */ ED_INSERT, /* n */
+ /* 111 */ ED_INSERT, /* o */
+ /* 112 */ ED_INSERT, /* p */
+ /* 113 */ ED_INSERT, /* q */
+ /* 114 */ ED_INSERT, /* r */
+ /* 115 */ ED_INSERT, /* s */
+ /* 116 */ ED_INSERT, /* t */
+ /* 117 */ ED_INSERT, /* u */
+ /* 118 */ ED_INSERT, /* v */
+ /* 119 */ ED_INSERT, /* w */
+ /* 120 */ ED_INSERT, /* x */
+ /* 121 */ ED_INSERT, /* y */
+ /* 122 */ ED_INSERT, /* z */
+ /* 123 */ ED_INSERT, /* { */
+ /* 124 */ ED_INSERT, /* | */
+ /* 125 */ ED_INSERT, /* } */
+ /* 126 */ ED_INSERT, /* ~ */
+ /* 127 */ VI_DELETE_PREV_CHAR, /* ^? */
+ /* 128 */ ED_INSERT, /* M-^@ */
+ /* 129 */ ED_INSERT, /* M-^A */
+ /* 130 */ ED_INSERT, /* M-^B */
+ /* 131 */ ED_INSERT, /* M-^C */
+ /* 132 */ ED_INSERT, /* M-^D */
+ /* 133 */ ED_INSERT, /* M-^E */
+ /* 134 */ ED_INSERT, /* M-^F */
+ /* 135 */ ED_INSERT, /* M-^G */
+ /* 136 */ ED_INSERT, /* M-^H */
+ /* 137 */ ED_INSERT, /* M-^I */
+ /* 138 */ ED_INSERT, /* M-^J */
+ /* 139 */ ED_INSERT, /* M-^K */
+ /* 140 */ ED_INSERT, /* M-^L */
+ /* 141 */ ED_INSERT, /* M-^M */
+ /* 142 */ ED_INSERT, /* M-^N */
+ /* 143 */ ED_INSERT, /* M-^O */
+ /* 144 */ ED_INSERT, /* M-^P */
+ /* 145 */ ED_INSERT, /* M-^Q */
+ /* 146 */ ED_INSERT, /* M-^R */
+ /* 147 */ ED_INSERT, /* M-^S */
+ /* 148 */ ED_INSERT, /* M-^T */
+ /* 149 */ ED_INSERT, /* M-^U */
+ /* 150 */ ED_INSERT, /* M-^V */
+ /* 151 */ ED_INSERT, /* M-^W */
+ /* 152 */ ED_INSERT, /* M-^X */
+ /* 153 */ ED_INSERT, /* M-^Y */
+ /* 154 */ ED_INSERT, /* M-^Z */
+ /* 155 */ ED_INSERT, /* M-^[ */
+ /* 156 */ ED_INSERT, /* M-^\ */
+ /* 157 */ ED_INSERT, /* M-^] */
+ /* 158 */ ED_INSERT, /* M-^^ */
+ /* 159 */ ED_INSERT, /* M-^_ */
+ /* 160 */ ED_INSERT, /* M-SPACE */
+ /* 161 */ ED_INSERT, /* M-! */
+ /* 162 */ ED_INSERT, /* M-" */
+ /* 163 */ ED_INSERT, /* M-# */
+ /* 164 */ ED_INSERT, /* M-$ */
+ /* 165 */ ED_INSERT, /* M-% */
+ /* 166 */ ED_INSERT, /* M-& */
+ /* 167 */ ED_INSERT, /* M-' */
+ /* 168 */ ED_INSERT, /* M-( */
+ /* 169 */ ED_INSERT, /* M-) */
+ /* 170 */ ED_INSERT, /* M-* */
+ /* 171 */ ED_INSERT, /* M-+ */
+ /* 172 */ ED_INSERT, /* M-, */
+ /* 173 */ ED_INSERT, /* M-- */
+ /* 174 */ ED_INSERT, /* M-. */
+ /* 175 */ ED_INSERT, /* M-/ */
+ /* 176 */ ED_INSERT, /* M-0 */
+ /* 177 */ ED_INSERT, /* M-1 */
+ /* 178 */ ED_INSERT, /* M-2 */
+ /* 179 */ ED_INSERT, /* M-3 */
+ /* 180 */ ED_INSERT, /* M-4 */
+ /* 181 */ ED_INSERT, /* M-5 */
+ /* 182 */ ED_INSERT, /* M-6 */
+ /* 183 */ ED_INSERT, /* M-7 */
+ /* 184 */ ED_INSERT, /* M-8 */
+ /* 185 */ ED_INSERT, /* M-9 */
+ /* 186 */ ED_INSERT, /* M-: */
+ /* 187 */ ED_INSERT, /* M-; */
+ /* 188 */ ED_INSERT, /* M-< */
+ /* 189 */ ED_INSERT, /* M-= */
+ /* 190 */ ED_INSERT, /* M-> */
+ /* 191 */ ED_INSERT, /* M-? */
+ /* 192 */ ED_INSERT, /* M-@ */
+ /* 193 */ ED_INSERT, /* M-A */
+ /* 194 */ ED_INSERT, /* M-B */
+ /* 195 */ ED_INSERT, /* M-C */
+ /* 196 */ ED_INSERT, /* M-D */
+ /* 197 */ ED_INSERT, /* M-E */
+ /* 198 */ ED_INSERT, /* M-F */
+ /* 199 */ ED_INSERT, /* M-G */
+ /* 200 */ ED_INSERT, /* M-H */
+ /* 201 */ ED_INSERT, /* M-I */
+ /* 202 */ ED_INSERT, /* M-J */
+ /* 203 */ ED_INSERT, /* M-K */
+ /* 204 */ ED_INSERT, /* M-L */
+ /* 205 */ ED_INSERT, /* M-M */
+ /* 206 */ ED_INSERT, /* M-N */
+ /* 207 */ ED_INSERT, /* M-O */
+ /* 208 */ ED_INSERT, /* M-P */
+ /* 209 */ ED_INSERT, /* M-Q */
+ /* 210 */ ED_INSERT, /* M-R */
+ /* 211 */ ED_INSERT, /* M-S */
+ /* 212 */ ED_INSERT, /* M-T */
+ /* 213 */ ED_INSERT, /* M-U */
+ /* 214 */ ED_INSERT, /* M-V */
+ /* 215 */ ED_INSERT, /* M-W */
+ /* 216 */ ED_INSERT, /* M-X */
+ /* 217 */ ED_INSERT, /* M-Y */
+ /* 218 */ ED_INSERT, /* M-Z */
+ /* 219 */ ED_INSERT, /* M-[ */
+ /* 220 */ ED_INSERT, /* M-\ */
+ /* 221 */ ED_INSERT, /* M-] */
+ /* 222 */ ED_INSERT, /* M-^ */
+ /* 223 */ ED_INSERT, /* M-_ */
+ /* 224 */ ED_INSERT, /* M-` */
+ /* 225 */ ED_INSERT, /* M-a */
+ /* 226 */ ED_INSERT, /* M-b */
+ /* 227 */ ED_INSERT, /* M-c */
+ /* 228 */ ED_INSERT, /* M-d */
+ /* 229 */ ED_INSERT, /* M-e */
+ /* 230 */ ED_INSERT, /* M-f */
+ /* 231 */ ED_INSERT, /* M-g */
+ /* 232 */ ED_INSERT, /* M-h */
+ /* 233 */ ED_INSERT, /* M-i */
+ /* 234 */ ED_INSERT, /* M-j */
+ /* 235 */ ED_INSERT, /* M-k */
+ /* 236 */ ED_INSERT, /* M-l */
+ /* 237 */ ED_INSERT, /* M-m */
+ /* 238 */ ED_INSERT, /* M-n */
+ /* 239 */ ED_INSERT, /* M-o */
+ /* 240 */ ED_INSERT, /* M-p */
+ /* 241 */ ED_INSERT, /* M-q */
+ /* 242 */ ED_INSERT, /* M-r */
+ /* 243 */ ED_INSERT, /* M-s */
+ /* 244 */ ED_INSERT, /* M-t */
+ /* 245 */ ED_INSERT, /* M-u */
+ /* 246 */ ED_INSERT, /* M-v */
+ /* 247 */ ED_INSERT, /* M-w */
+ /* 248 */ ED_INSERT, /* M-x */
+ /* 249 */ ED_INSERT, /* M-y */
+ /* 250 */ ED_INSERT, /* M-z */
+ /* 251 */ ED_INSERT, /* M-{ */
+ /* 252 */ ED_INSERT, /* M-| */
+ /* 253 */ ED_INSERT, /* M-} */
+ /* 254 */ ED_INSERT, /* M-~ */
+ /* 255 */ ED_INSERT /* M-^? */
+};
+
+private const el_action_t el_map_vi_command[] = {
+ /* 0 */ ED_UNASSIGNED, /* ^@ */
+ /* 1 */ ED_MOVE_TO_BEG, /* ^A */
+ /* 2 */ ED_UNASSIGNED, /* ^B */
+ /* 3 */ ED_TTY_SIGINT, /* ^C */
+ /* 4 */ ED_UNASSIGNED, /* ^D */
+ /* 5 */ ED_MOVE_TO_END, /* ^E */
+ /* 6 */ ED_UNASSIGNED, /* ^F */
+ /* 7 */ ED_UNASSIGNED, /* ^G */
+ /* 8 */ ED_DELETE_PREV_CHAR, /* ^H */
+ /* 9 */ ED_UNASSIGNED, /* ^I */
+ /* 10 */ ED_NEWLINE, /* ^J */
+ /* 11 */ ED_KILL_LINE, /* ^K */
+ /* 12 */ ED_CLEAR_SCREEN, /* ^L */
+ /* 13 */ ED_NEWLINE, /* ^M */
+ /* 14 */ ED_NEXT_HISTORY, /* ^N */
+ /* 15 */ ED_TTY_FLUSH_OUTPUT, /* ^O */
+ /* 16 */ ED_PREV_HISTORY, /* ^P */
+ /* 17 */ ED_TTY_START_OUTPUT, /* ^Q */
+ /* 18 */ ED_REDISPLAY, /* ^R */
+ /* 19 */ ED_TTY_STOP_OUTPUT, /* ^S */
+ /* 20 */ ED_UNASSIGNED, /* ^T */
+ /* 21 */ VI_KILL_LINE_PREV, /* ^U */
+ /* 22 */ ED_UNASSIGNED, /* ^V */
+ /* 23 */ ED_DELETE_PREV_WORD, /* ^W */
+ /* 24 */ ED_UNASSIGNED, /* ^X */
+ /* 25 */ ED_UNASSIGNED, /* ^Y */
+ /* 26 */ ED_UNASSIGNED, /* ^Z */
+ /* 27 */ EM_META_NEXT, /* ^[ */
+ /* 28 */ ED_TTY_SIGQUIT, /* ^\ */
+ /* 29 */ ED_UNASSIGNED, /* ^] */
+ /* 30 */ ED_UNASSIGNED, /* ^^ */
+ /* 31 */ ED_UNASSIGNED, /* ^_ */
+ /* 32 */ ED_NEXT_CHAR, /* SPACE */
+ /* 33 */ ED_UNASSIGNED, /* ! */
+ /* 34 */ ED_UNASSIGNED, /* " */
+ /* 35 */ VI_COMMENT_OUT, /* # */
+ /* 36 */ ED_MOVE_TO_END, /* $ */
+ /* 37 */ VI_MATCH, /* % */
+ /* 38 */ ED_UNASSIGNED, /* & */
+ /* 39 */ ED_UNASSIGNED, /* ' */
+ /* 40 */ ED_UNASSIGNED, /* ( */
+ /* 41 */ ED_UNASSIGNED, /* ) */
+ /* 42 */ ED_UNASSIGNED, /* * */
+ /* 43 */ ED_NEXT_HISTORY, /* + */
+ /* 44 */ VI_REPEAT_PREV_CHAR, /* , */
+ /* 45 */ ED_PREV_HISTORY, /* - */
+ /* 46 */ VI_REDO, /* . */
+ /* 47 */ VI_SEARCH_PREV, /* / */
+ /* 48 */ VI_ZERO, /* 0 */
+ /* 49 */ ED_ARGUMENT_DIGIT, /* 1 */
+ /* 50 */ ED_ARGUMENT_DIGIT, /* 2 */
+ /* 51 */ ED_ARGUMENT_DIGIT, /* 3 */
+ /* 52 */ ED_ARGUMENT_DIGIT, /* 4 */
+ /* 53 */ ED_ARGUMENT_DIGIT, /* 5 */
+ /* 54 */ ED_ARGUMENT_DIGIT, /* 6 */
+ /* 55 */ ED_ARGUMENT_DIGIT, /* 7 */
+ /* 56 */ ED_ARGUMENT_DIGIT, /* 8 */
+ /* 57 */ ED_ARGUMENT_DIGIT, /* 9 */
+ /* 58 */ ED_COMMAND, /* : */
+ /* 59 */ VI_REPEAT_NEXT_CHAR, /* ; */
+ /* 60 */ ED_UNASSIGNED, /* < */
+ /* 61 */ ED_UNASSIGNED, /* = */
+ /* 62 */ ED_UNASSIGNED, /* > */
+ /* 63 */ VI_SEARCH_NEXT, /* ? */
+ /* 64 */ VI_ALIAS, /* @ */
+ /* 65 */ VI_ADD_AT_EOL, /* A */
+ /* 66 */ VI_PREV_BIG_WORD, /* B */
+ /* 67 */ VI_CHANGE_TO_EOL, /* C */
+ /* 68 */ ED_KILL_LINE, /* D */
+ /* 69 */ VI_END_BIG_WORD, /* E */
+ /* 70 */ VI_PREV_CHAR, /* F */
+ /* 71 */ VI_TO_HISTORY_LINE, /* G */
+ /* 72 */ ED_UNASSIGNED, /* H */
+ /* 73 */ VI_INSERT_AT_BOL, /* I */
+ /* 74 */ ED_SEARCH_NEXT_HISTORY, /* J */
+ /* 75 */ ED_SEARCH_PREV_HISTORY, /* K */
+ /* 76 */ ED_UNASSIGNED, /* L */
+ /* 77 */ ED_UNASSIGNED, /* M */
+ /* 78 */ VI_REPEAT_SEARCH_PREV, /* N */
+ /* 79 */ ED_SEQUENCE_LEAD_IN, /* O */
+ /* 80 */ VI_PASTE_PREV, /* P */
+ /* 81 */ ED_UNASSIGNED, /* Q */
+ /* 82 */ VI_REPLACE_MODE, /* R */
+ /* 83 */ VI_SUBSTITUTE_LINE, /* S */
+ /* 84 */ VI_TO_PREV_CHAR, /* T */
+ /* 85 */ VI_UNDO_LINE, /* U */
+ /* 86 */ ED_UNASSIGNED, /* V */
+ /* 87 */ VI_NEXT_BIG_WORD, /* W */
+ /* 88 */ ED_DELETE_PREV_CHAR, /* X */
+ /* 89 */ VI_YANK_END, /* Y */
+ /* 90 */ ED_UNASSIGNED, /* Z */
+ /* 91 */ ED_SEQUENCE_LEAD_IN, /* [ */
+ /* 92 */ ED_UNASSIGNED, /* \ */
+ /* 93 */ ED_UNASSIGNED, /* ] */
+ /* 94 */ ED_MOVE_TO_BEG, /* ^ */
+ /* 95 */ VI_HISTORY_WORD, /* _ */
+ /* 96 */ ED_UNASSIGNED, /* ` */
+ /* 97 */ VI_ADD, /* a */
+ /* 98 */ VI_PREV_WORD, /* b */
+ /* 99 */ VI_CHANGE_META, /* c */
+ /* 100 */ VI_DELETE_META, /* d */
+ /* 101 */ VI_END_WORD, /* e */
+ /* 102 */ VI_NEXT_CHAR, /* f */
+ /* 103 */ ED_UNASSIGNED, /* g */
+ /* 104 */ ED_PREV_CHAR, /* h */
+ /* 105 */ VI_INSERT, /* i */
+ /* 106 */ ED_NEXT_HISTORY, /* j */
+ /* 107 */ ED_PREV_HISTORY, /* k */
+ /* 108 */ ED_NEXT_CHAR, /* l */
+ /* 109 */ ED_UNASSIGNED, /* m */
+ /* 110 */ VI_REPEAT_SEARCH_NEXT, /* n */
+ /* 111 */ ED_UNASSIGNED, /* o */
+ /* 112 */ VI_PASTE_NEXT, /* p */
+ /* 113 */ ED_UNASSIGNED, /* q */
+ /* 114 */ VI_REPLACE_CHAR, /* r */
+ /* 115 */ VI_SUBSTITUTE_CHAR, /* s */
+ /* 116 */ VI_TO_NEXT_CHAR, /* t */
+ /* 117 */ VI_UNDO, /* u */
+ /* 118 */ VI_HISTEDIT, /* v */
+ /* 119 */ VI_NEXT_WORD, /* w */
+ /* 120 */ ED_DELETE_NEXT_CHAR, /* x */
+ /* 121 */ VI_YANK, /* y */
+ /* 122 */ ED_UNASSIGNED, /* z */
+ /* 123 */ ED_UNASSIGNED, /* { */
+ /* 124 */ VI_TO_COLUMN, /* | */
+ /* 125 */ ED_UNASSIGNED, /* } */
+ /* 126 */ VI_CHANGE_CASE, /* ~ */
+ /* 127 */ ED_DELETE_PREV_CHAR, /* ^? */
+ /* 128 */ ED_UNASSIGNED, /* M-^@ */
+ /* 129 */ ED_UNASSIGNED, /* M-^A */
+ /* 130 */ ED_UNASSIGNED, /* M-^B */
+ /* 131 */ ED_UNASSIGNED, /* M-^C */
+ /* 132 */ ED_UNASSIGNED, /* M-^D */
+ /* 133 */ ED_UNASSIGNED, /* M-^E */
+ /* 134 */ ED_UNASSIGNED, /* M-^F */
+ /* 135 */ ED_UNASSIGNED, /* M-^G */
+ /* 136 */ ED_UNASSIGNED, /* M-^H */
+ /* 137 */ ED_UNASSIGNED, /* M-^I */
+ /* 138 */ ED_UNASSIGNED, /* M-^J */
+ /* 139 */ ED_UNASSIGNED, /* M-^K */
+ /* 140 */ ED_UNASSIGNED, /* M-^L */
+ /* 141 */ ED_UNASSIGNED, /* M-^M */
+ /* 142 */ ED_UNASSIGNED, /* M-^N */
+ /* 143 */ ED_UNASSIGNED, /* M-^O */
+ /* 144 */ ED_UNASSIGNED, /* M-^P */
+ /* 145 */ ED_UNASSIGNED, /* M-^Q */
+ /* 146 */ ED_UNASSIGNED, /* M-^R */
+ /* 147 */ ED_UNASSIGNED, /* M-^S */
+ /* 148 */ ED_UNASSIGNED, /* M-^T */
+ /* 149 */ ED_UNASSIGNED, /* M-^U */
+ /* 150 */ ED_UNASSIGNED, /* M-^V */
+ /* 151 */ ED_UNASSIGNED, /* M-^W */
+ /* 152 */ ED_UNASSIGNED, /* M-^X */
+ /* 153 */ ED_UNASSIGNED, /* M-^Y */
+ /* 154 */ ED_UNASSIGNED, /* M-^Z */
+ /* 155 */ ED_UNASSIGNED, /* M-^[ */
+ /* 156 */ ED_UNASSIGNED, /* M-^\ */
+ /* 157 */ ED_UNASSIGNED, /* M-^] */
+ /* 158 */ ED_UNASSIGNED, /* M-^^ */
+ /* 159 */ ED_UNASSIGNED, /* M-^_ */
+ /* 160 */ ED_UNASSIGNED, /* M-SPACE */
+ /* 161 */ ED_UNASSIGNED, /* M-! */
+ /* 162 */ ED_UNASSIGNED, /* M-" */
+ /* 163 */ ED_UNASSIGNED, /* M-# */
+ /* 164 */ ED_UNASSIGNED, /* M-$ */
+ /* 165 */ ED_UNASSIGNED, /* M-% */
+ /* 166 */ ED_UNASSIGNED, /* M-& */
+ /* 167 */ ED_UNASSIGNED, /* M-' */
+ /* 168 */ ED_UNASSIGNED, /* M-( */
+ /* 169 */ ED_UNASSIGNED, /* M-) */
+ /* 170 */ ED_UNASSIGNED, /* M-* */
+ /* 171 */ ED_UNASSIGNED, /* M-+ */
+ /* 172 */ ED_UNASSIGNED, /* M-, */
+ /* 173 */ ED_UNASSIGNED, /* M-- */
+ /* 174 */ ED_UNASSIGNED, /* M-. */
+ /* 175 */ ED_UNASSIGNED, /* M-/ */
+ /* 176 */ ED_UNASSIGNED, /* M-0 */
+ /* 177 */ ED_UNASSIGNED, /* M-1 */
+ /* 178 */ ED_UNASSIGNED, /* M-2 */
+ /* 179 */ ED_UNASSIGNED, /* M-3 */
+ /* 180 */ ED_UNASSIGNED, /* M-4 */
+ /* 181 */ ED_UNASSIGNED, /* M-5 */
+ /* 182 */ ED_UNASSIGNED, /* M-6 */
+ /* 183 */ ED_UNASSIGNED, /* M-7 */
+ /* 184 */ ED_UNASSIGNED, /* M-8 */
+ /* 185 */ ED_UNASSIGNED, /* M-9 */
+ /* 186 */ ED_UNASSIGNED, /* M-: */
+ /* 187 */ ED_UNASSIGNED, /* M-; */
+ /* 188 */ ED_UNASSIGNED, /* M-< */
+ /* 189 */ ED_UNASSIGNED, /* M-= */
+ /* 190 */ ED_UNASSIGNED, /* M-> */
+ /* 191 */ ED_UNASSIGNED, /* M-? */
+ /* 192 */ ED_UNASSIGNED, /* M-@ */
+ /* 193 */ ED_UNASSIGNED, /* M-A */
+ /* 194 */ ED_UNASSIGNED, /* M-B */
+ /* 195 */ ED_UNASSIGNED, /* M-C */
+ /* 196 */ ED_UNASSIGNED, /* M-D */
+ /* 197 */ ED_UNASSIGNED, /* M-E */
+ /* 198 */ ED_UNASSIGNED, /* M-F */
+ /* 199 */ ED_UNASSIGNED, /* M-G */
+ /* 200 */ ED_UNASSIGNED, /* M-H */
+ /* 201 */ ED_UNASSIGNED, /* M-I */
+ /* 202 */ ED_UNASSIGNED, /* M-J */
+ /* 203 */ ED_UNASSIGNED, /* M-K */
+ /* 204 */ ED_UNASSIGNED, /* M-L */
+ /* 205 */ ED_UNASSIGNED, /* M-M */
+ /* 206 */ ED_UNASSIGNED, /* M-N */
+ /* 207 */ ED_SEQUENCE_LEAD_IN, /* M-O */
+ /* 208 */ ED_UNASSIGNED, /* M-P */
+ /* 209 */ ED_UNASSIGNED, /* M-Q */
+ /* 210 */ ED_UNASSIGNED, /* M-R */
+ /* 211 */ ED_UNASSIGNED, /* M-S */
+ /* 212 */ ED_UNASSIGNED, /* M-T */
+ /* 213 */ ED_UNASSIGNED, /* M-U */
+ /* 214 */ ED_UNASSIGNED, /* M-V */
+ /* 215 */ ED_UNASSIGNED, /* M-W */
+ /* 216 */ ED_UNASSIGNED, /* M-X */
+ /* 217 */ ED_UNASSIGNED, /* M-Y */
+ /* 218 */ ED_UNASSIGNED, /* M-Z */
+ /* 219 */ ED_SEQUENCE_LEAD_IN, /* M-[ */
+ /* 220 */ ED_UNASSIGNED, /* M-\ */
+ /* 221 */ ED_UNASSIGNED, /* M-] */
+ /* 222 */ ED_UNASSIGNED, /* M-^ */
+ /* 223 */ ED_UNASSIGNED, /* M-_ */
+ /* 224 */ ED_UNASSIGNED, /* M-` */
+ /* 225 */ ED_UNASSIGNED, /* M-a */
+ /* 226 */ ED_UNASSIGNED, /* M-b */
+ /* 227 */ ED_UNASSIGNED, /* M-c */
+ /* 228 */ ED_UNASSIGNED, /* M-d */
+ /* 229 */ ED_UNASSIGNED, /* M-e */
+ /* 230 */ ED_UNASSIGNED, /* M-f */
+ /* 231 */ ED_UNASSIGNED, /* M-g */
+ /* 232 */ ED_UNASSIGNED, /* M-h */
+ /* 233 */ ED_UNASSIGNED, /* M-i */
+ /* 234 */ ED_UNASSIGNED, /* M-j */
+ /* 235 */ ED_UNASSIGNED, /* M-k */
+ /* 236 */ ED_UNASSIGNED, /* M-l */
+ /* 237 */ ED_UNASSIGNED, /* M-m */
+ /* 238 */ ED_UNASSIGNED, /* M-n */
+ /* 239 */ ED_UNASSIGNED, /* M-o */
+ /* 240 */ ED_UNASSIGNED, /* M-p */
+ /* 241 */ ED_UNASSIGNED, /* M-q */
+ /* 242 */ ED_UNASSIGNED, /* M-r */
+ /* 243 */ ED_UNASSIGNED, /* M-s */
+ /* 244 */ ED_UNASSIGNED, /* M-t */
+ /* 245 */ ED_UNASSIGNED, /* M-u */
+ /* 246 */ ED_UNASSIGNED, /* M-v */
+ /* 247 */ ED_UNASSIGNED, /* M-w */
+ /* 248 */ ED_UNASSIGNED, /* M-x */
+ /* 249 */ ED_UNASSIGNED, /* M-y */
+ /* 250 */ ED_UNASSIGNED, /* M-z */
+ /* 251 */ ED_UNASSIGNED, /* M-{ */
+ /* 252 */ ED_UNASSIGNED, /* M-| */
+ /* 253 */ ED_UNASSIGNED, /* M-} */
+ /* 254 */ ED_UNASSIGNED, /* M-~ */
+ /* 255 */ ED_UNASSIGNED /* M-^? */
+};
+
+
+/* map_init():
+ * Initialize and allocate the maps
+ */
+protected int
+map_init(EditLine *el)
+{
+
+ /*
+ * Make sure those are correct before starting.
+ */
+#ifdef MAP_DEBUG
+ if (sizeof(el_map_emacs) != N_KEYS * sizeof(el_action_t))
+ EL_ABORT((el->errfile, "Emacs map incorrect\n"));
+ if (sizeof(el_map_vi_command) != N_KEYS * sizeof(el_action_t))
+ EL_ABORT((el->errfile, "Vi command map incorrect\n"));
+ if (sizeof(el_map_vi_insert) != N_KEYS * sizeof(el_action_t))
+ EL_ABORT((el->errfile, "Vi insert map incorrect\n"));
+#endif
+
+ el->el_map.alt = (el_action_t *)el_malloc(sizeof(el_action_t) * N_KEYS);
+ if (el->el_map.alt == NULL)
+ return (-1);
+ el->el_map.key = (el_action_t *)el_malloc(sizeof(el_action_t) * N_KEYS);
+ if (el->el_map.key == NULL)
+ return (-1);
+ el->el_map.emacs = el_map_emacs;
+ el->el_map.vic = el_map_vi_command;
+ el->el_map.vii = el_map_vi_insert;
+ el->el_map.help = (el_bindings_t *) el_malloc(sizeof(el_bindings_t) *
+ EL_NUM_FCNS);
+ if (el->el_map.help == NULL)
+ return (-1);
+ (void) memcpy(el->el_map.help, help__get(),
+ sizeof(el_bindings_t) * EL_NUM_FCNS);
+ el->el_map.func = (el_func_t *)el_malloc(sizeof(el_func_t) *
+ EL_NUM_FCNS);
+ if (el->el_map.func == NULL)
+ return (-1);
+ memcpy(el->el_map.func, func__get(), sizeof(el_func_t) * EL_NUM_FCNS);
+ el->el_map.nfunc = EL_NUM_FCNS;
+
+#ifdef VIDEFAULT
+ map_init_vi(el);
+#else
+ map_init_emacs(el);
+#endif /* VIDEFAULT */
+ return (0);
+}
+
+
+/* map_end():
+ * Free the space taken by the editor maps
+ */
+protected void
+map_end(EditLine *el)
+{
+
+ el_free((ptr_t) el->el_map.alt);
+ el->el_map.alt = NULL;
+ el_free((ptr_t) el->el_map.key);
+ el->el_map.key = NULL;
+ el->el_map.emacs = NULL;
+ el->el_map.vic = NULL;
+ el->el_map.vii = NULL;
+ el_free((ptr_t) el->el_map.help);
+ el->el_map.help = NULL;
+ el_free((ptr_t) el->el_map.func);
+ el->el_map.func = NULL;
+}
+
+
+/* map_init_nls():
+ * Find all the printable keys and bind them to self insert
+ */
+private void
+map_init_nls(EditLine *el)
+{
+ int i;
+
+ el_action_t *map = el->el_map.key;
+
+ for (i = 0200; i <= 0377; i++)
+ if (isprint(i))
+ map[i] = ED_INSERT;
+}
+
+
+/* map_init_meta():
+ * Bind all the meta keys to the appropriate ESC-<key> sequence
+ */
+private void
+map_init_meta(EditLine *el)
+{
+ char buf[3];
+ int i;
+ el_action_t *map = el->el_map.key;
+ el_action_t *alt = el->el_map.alt;
+
+ for (i = 0; i <= 0377 && map[i] != EM_META_NEXT; i++)
+ continue;
+
+ if (i > 0377) {
+ for (i = 0; i <= 0377 && alt[i] != EM_META_NEXT; i++)
+ continue;
+ if (i > 0377) {
+ i = 033;
+ if (el->el_map.type == MAP_VI)
+ map = alt;
+ } else
+ map = alt;
+ }
+ buf[0] = (char) i;
+ buf[2] = 0;
+ for (i = 0200; i <= 0377; i++)
+ switch (map[i]) {
+ case ED_INSERT:
+ case ED_UNASSIGNED:
+ case ED_SEQUENCE_LEAD_IN:
+ break;
+ default:
+ buf[1] = i & 0177;
+ key_add(el, buf, key_map_cmd(el, (int) map[i]), XK_CMD);
+ break;
+ }
+ map[(int) buf[0]] = ED_SEQUENCE_LEAD_IN;
+}
+
+
+/* map_init_vi():
+ * Initialize the vi bindings
+ */
+protected void
+map_init_vi(EditLine *el)
+{
+ int i;
+ el_action_t *key = el->el_map.key;
+ el_action_t *alt = el->el_map.alt;
+ const el_action_t *vii = el->el_map.vii;
+ const el_action_t *vic = el->el_map.vic;
+
+ el->el_map.type = MAP_VI;
+ el->el_map.current = el->el_map.key;
+
+ key_reset(el);
+
+ for (i = 0; i < N_KEYS; i++) {
+ key[i] = vii[i];
+ alt[i] = vic[i];
+ }
+
+ map_init_meta(el);
+ map_init_nls(el);
+
+ tty_bind_char(el, 1);
+ term_bind_arrow(el);
+}
+
+
+/* map_init_emacs():
+ * Initialize the emacs bindings
+ */
+protected void
+map_init_emacs(EditLine *el)
+{
+ int i;
+ char buf[3];
+ el_action_t *key = el->el_map.key;
+ el_action_t *alt = el->el_map.alt;
+ const el_action_t *emacs = el->el_map.emacs;
+
+ el->el_map.type = MAP_EMACS;
+ el->el_map.current = el->el_map.key;
+ key_reset(el);
+
+ for (i = 0; i < N_KEYS; i++) {
+ key[i] = emacs[i];
+ alt[i] = ED_UNASSIGNED;
+ }
+
+ map_init_meta(el);
+ map_init_nls(el);
+
+ buf[0] = CONTROL('X');
+ buf[1] = CONTROL('X');
+ buf[2] = 0;
+ key_add(el, buf, key_map_cmd(el, EM_EXCHANGE_MARK), XK_CMD);
+
+ tty_bind_char(el, 1);
+ term_bind_arrow(el);
+}
+
+
+/* map_set_editor():
+ * Set the editor
+ */
+protected int
+map_set_editor(EditLine *el, char *editor)
+{
+
+ if (strcmp(editor, "emacs") == 0) {
+ map_init_emacs(el);
+ return (0);
+ }
+ if (strcmp(editor, "vi") == 0) {
+ map_init_vi(el);
+ return (0);
+ }
+ return (-1);
+}
+
+
+/* map_get_editor():
+ * Retrieve the editor
+ */
+protected int
+map_get_editor(EditLine *el, const char **editor)
+{
+
+ if (editor == NULL)
+ return (-1);
+ switch (el->el_map.type) {
+ case MAP_EMACS:
+ *editor = "emacs";
+ return (0);
+ case MAP_VI:
+ *editor = "vi";
+ return (0);
+ }
+ return (-1);
+}
+
+
+/* map_print_key():
+ * Print the function description for 1 key
+ */
+private void
+map_print_key(EditLine *el, el_action_t *map, const char *in)
+{
+ char outbuf[EL_BUFSIZ];
+ el_bindings_t *bp, *ep;
+
+ if (in[0] == '\0' || in[1] == '\0') {
+ (void) key__decode_str(in, outbuf, "");
+ ep = &el->el_map.help[el->el_map.nfunc];
+ for (bp = el->el_map.help; bp < ep; bp++)
+ if (bp->func == map[(unsigned char) *in]) {
+ (void) fprintf(el->el_outfile,
+ "%s\t->\t%s\n", outbuf, bp->name);
+ return;
+ }
+ } else
+ key_print(el, in);
+}
+
+
+/* map_print_some_keys():
+ * Print keys from first to last
+ */
+private void
+map_print_some_keys(EditLine *el, el_action_t *map, int first, int last)
+{
+ el_bindings_t *bp, *ep;
+ char firstbuf[2], lastbuf[2];
+ char unparsbuf[EL_BUFSIZ], extrabuf[EL_BUFSIZ];
+
+ firstbuf[0] = first;
+ firstbuf[1] = 0;
+ lastbuf[0] = last;
+ lastbuf[1] = 0;
+ if (map[first] == ED_UNASSIGNED) {
+ if (first == last)
+ (void) fprintf(el->el_outfile,
+ "%-15s-> is undefined\n",
+ key__decode_str(firstbuf, unparsbuf, STRQQ));
+ return;
+ }
+ ep = &el->el_map.help[el->el_map.nfunc];
+ for (bp = el->el_map.help; bp < ep; bp++) {
+ if (bp->func == map[first]) {
+ if (first == last) {
+ (void) fprintf(el->el_outfile, "%-15s-> %s\n",
+ key__decode_str(firstbuf, unparsbuf, STRQQ),
+ bp->name);
+ } else {
+ (void) fprintf(el->el_outfile,
+ "%-4s to %-7s-> %s\n",
+ key__decode_str(firstbuf, unparsbuf, STRQQ),
+ key__decode_str(lastbuf, extrabuf, STRQQ),
+ bp->name);
+ }
+ return;
+ }
+ }
+#ifdef MAP_DEBUG
+ if (map == el->el_map.key) {
+ (void) fprintf(el->el_outfile,
+ "BUG!!! %s isn't bound to anything.\n",
+ key__decode_str(firstbuf, unparsbuf, STRQQ));
+ (void) fprintf(el->el_outfile, "el->el_map.key[%d] == %d\n",
+ first, el->el_map.key[first]);
+ } else {
+ (void) fprintf(el->el_outfile,
+ "BUG!!! %s isn't bound to anything.\n",
+ key__decode_str(firstbuf, unparsbuf, STRQQ));
+ (void) fprintf(el->el_outfile, "el->el_map.alt[%d] == %d\n",
+ first, el->el_map.alt[first]);
+ }
+#endif
+ EL_ABORT((el->el_errfile, "Error printing keys\n"));
+}
+
+
+/* map_print_all_keys():
+ * Print the function description for all keys.
+ */
+private void
+map_print_all_keys(EditLine *el)
+{
+ int prev, i;
+
+ (void) fprintf(el->el_outfile, "Standard key bindings\n");
+ prev = 0;
+ for (i = 0; i < N_KEYS; i++) {
+ if (el->el_map.key[prev] == el->el_map.key[i])
+ continue;
+ map_print_some_keys(el, el->el_map.key, prev, i - 1);
+ prev = i;
+ }
+ map_print_some_keys(el, el->el_map.key, prev, i - 1);
+
+ (void) fprintf(el->el_outfile, "Alternative key bindings\n");
+ prev = 0;
+ for (i = 0; i < N_KEYS; i++) {
+ if (el->el_map.alt[prev] == el->el_map.alt[i])
+ continue;
+ map_print_some_keys(el, el->el_map.alt, prev, i - 1);
+ prev = i;
+ }
+ map_print_some_keys(el, el->el_map.alt, prev, i - 1);
+
+ (void) fprintf(el->el_outfile, "Multi-character bindings\n");
+ key_print(el, "");
+ (void) fprintf(el->el_outfile, "Arrow key bindings\n");
+ term_print_arrow(el, "");
+}
+
+
+/* map_bind():
+ * Add/remove/change bindings
+ */
+protected int
+map_bind(EditLine *el, int argc, const char **argv)
+{
+ el_action_t *map;
+ int ntype, rem;
+ const char *p;
+ char inbuf[EL_BUFSIZ];
+ char outbuf[EL_BUFSIZ];
+ const char *in = NULL;
+ char *out = NULL;
+ el_bindings_t *bp, *ep;
+ int cmd;
+ int key;
+
+ if (argv == NULL)
+ return (-1);
+
+ map = el->el_map.key;
+ ntype = XK_CMD;
+ key = rem = 0;
+ for (argc = 1; (p = argv[argc]) != NULL; argc++)
+ if (p[0] == '-')
+ switch (p[1]) {
+ case 'a':
+ map = el->el_map.alt;
+ break;
+
+ case 's':
+ ntype = XK_STR;
+ break;
+#ifdef notyet
+ case 'c':
+ ntype = XK_EXE;
+ break;
+#endif
+ case 'k':
+ key = 1;
+ break;
+
+ case 'r':
+ rem = 1;
+ break;
+
+ case 'v':
+ map_init_vi(el);
+ return (0);
+
+ case 'e':
+ map_init_emacs(el);
+ return (0);
+
+ case 'l':
+ ep = &el->el_map.help[el->el_map.nfunc];
+ for (bp = el->el_map.help; bp < ep; bp++)
+ (void) fprintf(el->el_outfile,
+ "%s\n\t%s\n",
+ bp->name, bp->description);
+ return (0);
+ default:
+ (void) fprintf(el->el_errfile,
+ "%s: Invalid switch `%c'.\n",
+ argv[0], p[1]);
+ }
+ else
+ break;
+
+ if (argv[argc] == NULL) {
+ map_print_all_keys(el);
+ return (0);
+ }
+ if (key)
+ in = argv[argc++];
+ else if ((in = parse__string(inbuf, argv[argc++])) == NULL) {
+ (void) fprintf(el->el_errfile,
+ "%s: Invalid \\ or ^ in instring.\n",
+ argv[0]);
+ return (-1);
+ }
+ if (rem) {
+ if (key) {
+ (void) term_clear_arrow(el, in);
+ return (-1);
+ }
+ if (in[1])
+ (void) key_delete(el, in);
+ else if (map[(unsigned char) *in] == ED_SEQUENCE_LEAD_IN)
+ (void) key_delete(el, in);
+ else
+ map[(unsigned char) *in] = ED_UNASSIGNED;
+ return (0);
+ }
+ if (argv[argc] == NULL) {
+ if (key)
+ term_print_arrow(el, in);
+ else
+ map_print_key(el, map, in);
+ return (0);
+ }
+#ifdef notyet
+ if (argv[argc + 1] != NULL) {
+ bindkey_usage();
+ return (-1);
+ }
+#endif
+
+ switch (ntype) {
+ case XK_STR:
+ case XK_EXE:
+ if ((out = parse__string(outbuf, argv[argc])) == NULL) {
+ (void) fprintf(el->el_errfile,
+ "%s: Invalid \\ or ^ in outstring.\n", argv[0]);
+ return (-1);
+ }
+ if (key)
+ term_set_arrow(el, in, key_map_str(el, out), ntype);
+ else
+ key_add(el, in, key_map_str(el, out), ntype);
+ map[(unsigned char) *in] = ED_SEQUENCE_LEAD_IN;
+ break;
+
+ case XK_CMD:
+ if ((cmd = parse_cmd(el, argv[argc])) == -1) {
+ (void) fprintf(el->el_errfile,
+ "%s: Invalid command `%s'.\n", argv[0], argv[argc]);
+ return (-1);
+ }
+ if (key)
+ term_set_arrow(el, in, key_map_str(el, out), ntype);
+ else {
+ if (in[1]) {
+ key_add(el, in, key_map_cmd(el, cmd), ntype);
+ map[(unsigned char) *in] = ED_SEQUENCE_LEAD_IN;
+ } else {
+ key_clear(el, map, in);
+ map[(unsigned char) *in] = cmd;
+ }
+ }
+ break;
+
+ default:
+ EL_ABORT((el->el_errfile, "Bad XK_ type\n", ntype));
+ break;
+ }
+ return (0);
+}
+
+
+/* map_addfunc():
+ * add a user defined function
+ */
+protected int
+map_addfunc(EditLine *el, const char *name, const char *help, el_func_t func)
+{
+ void *p;
+ int nf = el->el_map.nfunc + 1;
+
+ if (name == NULL || help == NULL || func == NULL)
+ return (-1);
+
+ if ((p = el_realloc(el->el_map.func, nf * sizeof(el_func_t))) == NULL)
+ return (-1);
+ el->el_map.func = (el_func_t *) p;
+ if ((p = el_realloc(el->el_map.help, nf * sizeof(el_bindings_t)))
+ == NULL)
+ return (-1);
+ el->el_map.help = (el_bindings_t *) p;
+
+ nf = el->el_map.nfunc;
+ el->el_map.func[nf] = func;
+
+ el->el_map.help[nf].name = name;
+ el->el_map.help[nf].func = nf;
+ el->el_map.help[nf].description = help;
+ el->el_map.nfunc++;
+
+ return (0);
+}
diff --git a/lib/libedit/map.h b/lib/libedit/map.h
new file mode 100644
index 0000000..a76d872
--- /dev/null
+++ b/lib/libedit/map.h
@@ -0,0 +1,75 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell 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.
+ *
+ * @(#)map.h 8.1 (Berkeley) 6/4/93
+ * $NetBSD: map.h,v 1.8 2003/08/07 16:44:32 agc Exp $
+ * $FreeBSD$
+ */
+
+/*
+ * el.map.h: Editor maps
+ */
+#ifndef _h_el_map
+#define _h_el_map
+
+typedef struct el_bindings_t { /* for the "bind" shell command */
+ const char *name; /* function name for bind command */
+ int func; /* function numeric value */
+ const char *description; /* description of function */
+} el_bindings_t;
+
+
+typedef struct el_map_t {
+ el_action_t *alt; /* The current alternate key map */
+ el_action_t *key; /* The current normal key map */
+ el_action_t *current; /* The keymap we are using */
+ const el_action_t *emacs; /* The default emacs key map */
+ const el_action_t *vic; /* The vi command mode key map */
+ const el_action_t *vii; /* The vi insert mode key map */
+ int type; /* Emacs or vi */
+ el_bindings_t *help; /* The help for the editor functions */
+ el_func_t *func; /* List of available functions */
+ int nfunc; /* The number of functions/help items */
+} el_map_t;
+
+#define MAP_EMACS 0
+#define MAP_VI 1
+
+protected int map_bind(EditLine *, int, const char **);
+protected int map_init(EditLine *);
+protected void map_end(EditLine *);
+protected void map_init_vi(EditLine *);
+protected void map_init_emacs(EditLine *);
+protected int map_set_editor(EditLine *, char *);
+protected int map_get_editor(EditLine *, const char **);
+protected int map_addfunc(EditLine *, const char *, const char *, el_func_t);
+
+#endif /* _h_el_map */
diff --git a/lib/libedit/parse.c b/lib/libedit/parse.c
new file mode 100644
index 0000000..0ffe51d
--- /dev/null
+++ b/lib/libedit/parse.c
@@ -0,0 +1,261 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell 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.
+ *
+ * $NetBSD: parse.c,v 1.22 2005/05/29 04:58:15 lukem Exp $
+ */
+
+#if !defined(lint) && !defined(SCCSID)
+static char sccsid[] = "@(#)parse.c 8.1 (Berkeley) 6/4/93";
+#endif /* not lint && not SCCSID */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * parse.c: parse an editline extended command
+ *
+ * commands are:
+ *
+ * bind
+ * echotc
+ * edit
+ * gettc
+ * history
+ * settc
+ * setty
+ */
+#include "sys.h"
+#include "el.h"
+#include <stdlib.h>
+
+private const struct {
+ const char *name;
+ int (*func)(EditLine *, int, const char **);
+} cmds[] = {
+ { "bind", map_bind },
+ { "echotc", term_echotc },
+ { "edit", el_editmode },
+ { "history", hist_command },
+ { "telltc", term_telltc },
+ { "settc", term_settc },
+ { "setty", tty_stty },
+ { NULL, NULL }
+};
+
+
+/* parse_line():
+ * Parse a line and dispatch it
+ */
+protected int
+parse_line(EditLine *el, const char *line)
+{
+ const char **argv;
+ int argc;
+ Tokenizer *tok;
+
+ tok = tok_init(NULL);
+ tok_str(tok, line, &argc, &argv);
+ argc = el_parse(el, argc, argv);
+ tok_end(tok);
+ return (argc);
+}
+
+
+/* el_parse():
+ * Command dispatcher
+ */
+public int
+el_parse(EditLine *el, int argc, const char *argv[])
+{
+ const char *ptr;
+ int i;
+
+ if (argc < 1)
+ return (-1);
+ ptr = strchr(argv[0], ':');
+ if (ptr != NULL) {
+ char *tprog;
+ size_t l;
+
+ if (ptr == argv[0])
+ return (0);
+ l = ptr - argv[0] - 1;
+ tprog = (char *) el_malloc(l + 1);
+ if (tprog == NULL)
+ return (0);
+ (void) strncpy(tprog, argv[0], l);
+ tprog[l] = '\0';
+ ptr++;
+ l = el_match(el->el_prog, tprog);
+ el_free(tprog);
+ if (!l)
+ return (0);
+ } else
+ ptr = argv[0];
+
+ for (i = 0; cmds[i].name != NULL; i++)
+ if (strcmp(cmds[i].name, ptr) == 0) {
+ i = (*cmds[i].func) (el, argc, argv);
+ return (-i);
+ }
+ return (-1);
+}
+
+
+/* parse__escape():
+ * Parse a string of the form ^<char> \<odigit> \<char> and return
+ * the appropriate character or -1 if the escape is not valid
+ */
+protected int
+parse__escape(const char **ptr)
+{
+ const char *p;
+ int c;
+
+ p = *ptr;
+
+ if (p[1] == 0)
+ return (-1);
+
+ if (*p == '\\') {
+ p++;
+ switch (*p) {
+ case 'a':
+ c = '\007'; /* Bell */
+ break;
+ case 'b':
+ c = '\010'; /* Backspace */
+ break;
+ case 't':
+ c = '\011'; /* Horizontal Tab */
+ break;
+ case 'n':
+ c = '\012'; /* New Line */
+ break;
+ case 'v':
+ c = '\013'; /* Vertical Tab */
+ break;
+ case 'f':
+ c = '\014'; /* Form Feed */
+ break;
+ case 'r':
+ c = '\015'; /* Carriage Return */
+ break;
+ case 'e':
+ c = '\033'; /* Escape */
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ {
+ int cnt, ch;
+
+ for (cnt = 0, c = 0; cnt < 3; cnt++) {
+ ch = *p++;
+ if (ch < '0' || ch > '7') {
+ p--;
+ break;
+ }
+ c = (c << 3) | (ch - '0');
+ }
+ if ((c & 0xffffff00) != 0)
+ return (-1);
+ --p;
+ break;
+ }
+ default:
+ c = *p;
+ break;
+ }
+ } else if (*p == '^') {
+ p++;
+ c = (*p == '?') ? '\177' : (*p & 0237);
+ } else
+ c = *p;
+ *ptr = ++p;
+ return ((unsigned char)c);
+}
+
+/* parse__string():
+ * Parse the escapes from in and put the raw string out
+ */
+protected char *
+parse__string(char *out, const char *in)
+{
+ char *rv = out;
+ int n;
+
+ for (;;)
+ switch (*in) {
+ case '\0':
+ *out = '\0';
+ return (rv);
+
+ case '\\':
+ case '^':
+ if ((n = parse__escape(&in)) == -1)
+ return (NULL);
+ *out++ = n;
+ break;
+
+ case 'M':
+ if (in[1] == '-' && in[2] != '\0') {
+ *out++ = '\033';
+ in += 2;
+ break;
+ }
+ /*FALLTHROUGH*/
+
+ default:
+ *out++ = *in++;
+ break;
+ }
+}
+
+
+/* parse_cmd():
+ * Return the command number for the command string given
+ * or -1 if one is not found
+ */
+protected int
+parse_cmd(EditLine *el, const char *cmd)
+{
+ el_bindings_t *b;
+
+ for (b = el->el_map.help; b->name != NULL; b++)
+ if (strcmp(b->name, cmd) == 0)
+ return (b->func);
+ return (-1);
+}
diff --git a/lib/libedit/parse.h b/lib/libedit/parse.h
new file mode 100644
index 0000000..cca4abf
--- /dev/null
+++ b/lib/libedit/parse.h
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell 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.
+ *
+ * @(#)parse.h 8.1 (Berkeley) 6/4/93
+ * $NetBSD: parse.h,v 1.6 2005/05/29 04:58:15 lukem Exp $
+ * $FreeBSD$
+ */
+
+/*
+ * el.parse.h: Parser functions
+ */
+#ifndef _h_el_parse
+#define _h_el_parse
+
+protected int parse_line(EditLine *, const char *);
+protected int parse__escape(const char **);
+protected char *parse__string(char *, const char *);
+protected int parse_cmd(EditLine *, const char *);
+
+#endif /* _h_el_parse */
diff --git a/lib/libedit/prompt.c b/lib/libedit/prompt.c
new file mode 100644
index 0000000..3d72da7
--- /dev/null
+++ b/lib/libedit/prompt.c
@@ -0,0 +1,168 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell 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.
+ *
+ * $NetBSD: prompt.c,v 1.11 2003/08/07 16:44:32 agc Exp $
+ */
+
+#if !defined(lint) && !defined(SCCSID)
+static char sccsid[] = "@(#)prompt.c 8.1 (Berkeley) 6/4/93";
+#endif /* not lint && not SCCSID */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * prompt.c: Prompt printing functions
+ */
+#include "sys.h"
+#include <stdio.h>
+#include "el.h"
+
+private char *prompt_default(EditLine *);
+private char *prompt_default_r(EditLine *);
+
+/* prompt_default():
+ * Just a default prompt, in case the user did not provide one
+ */
+private char *
+/*ARGSUSED*/
+prompt_default(EditLine *el __unused)
+{
+ static char a[3] = {'?', ' ', '\0'};
+
+ return (a);
+}
+
+
+/* prompt_default_r():
+ * Just a default rprompt, in case the user did not provide one
+ */
+private char *
+/*ARGSUSED*/
+prompt_default_r(EditLine *el __unused)
+{
+ static char a[1] = {'\0'};
+
+ return (a);
+}
+
+
+/* prompt_print():
+ * Print the prompt and update the prompt position.
+ * We use an array of integers in case we want to pass
+ * literal escape sequences in the prompt and we want a
+ * bit to flag them
+ */
+protected void
+prompt_print(EditLine *el, int op)
+{
+ el_prompt_t *elp;
+ char *p;
+
+ if (op == EL_PROMPT)
+ elp = &el->el_prompt;
+ else
+ elp = &el->el_rprompt;
+ p = (elp->p_func) (el);
+ while (*p)
+ re_putc(el, *p++, 1);
+
+ elp->p_pos.v = el->el_refresh.r_cursor.v;
+ elp->p_pos.h = el->el_refresh.r_cursor.h;
+}
+
+
+/* prompt_init():
+ * Initialize the prompt stuff
+ */
+protected int
+prompt_init(EditLine *el)
+{
+
+ el->el_prompt.p_func = prompt_default;
+ el->el_prompt.p_pos.v = 0;
+ el->el_prompt.p_pos.h = 0;
+ el->el_rprompt.p_func = prompt_default_r;
+ el->el_rprompt.p_pos.v = 0;
+ el->el_rprompt.p_pos.h = 0;
+ return (0);
+}
+
+
+/* prompt_end():
+ * Clean up the prompt stuff
+ */
+protected void
+/*ARGSUSED*/
+prompt_end(EditLine *el __unused)
+{
+}
+
+
+/* prompt_set():
+ * Install a prompt printing function
+ */
+protected int
+prompt_set(EditLine *el, el_pfunc_t prf, int op)
+{
+ el_prompt_t *p;
+
+ if (op == EL_PROMPT)
+ p = &el->el_prompt;
+ else
+ p = &el->el_rprompt;
+ if (prf == NULL) {
+ if (op == EL_PROMPT)
+ p->p_func = prompt_default;
+ else
+ p->p_func = prompt_default_r;
+ } else
+ p->p_func = prf;
+ p->p_pos.v = 0;
+ p->p_pos.h = 0;
+ return (0);
+}
+
+
+/* prompt_get():
+ * Retrieve the prompt printing function
+ */
+protected int
+prompt_get(EditLine *el, el_pfunc_t *prf, int op)
+{
+
+ if (prf == NULL)
+ return (-1);
+ if (op == EL_PROMPT)
+ *prf = el->el_prompt.p_func;
+ else
+ *prf = el->el_rprompt.p_func;
+ return (0);
+}
diff --git a/lib/libedit/prompt.h b/lib/libedit/prompt.h
new file mode 100644
index 0000000..6523add
--- /dev/null
+++ b/lib/libedit/prompt.h
@@ -0,0 +1,58 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell 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.
+ *
+ * @(#)prompt.h 8.1 (Berkeley) 6/4/93
+ * $NetBSD: prompt.h,v 1.6 2003/08/07 16:44:32 agc Exp $
+ * $FreeBSD$
+ */
+
+/*
+ * el.prompt.h: Prompt printing stuff
+ */
+#ifndef _h_el_prompt
+#define _h_el_prompt
+
+#include "histedit.h"
+
+typedef char * (*el_pfunc_t)(EditLine*);
+
+typedef struct el_prompt_t {
+ el_pfunc_t p_func; /* Function to return the prompt */
+ coord_t p_pos; /* position in the line after prompt */
+} el_prompt_t;
+
+protected void prompt_print(EditLine *, int);
+protected int prompt_set(EditLine *, el_pfunc_t, int);
+protected int prompt_get(EditLine *, el_pfunc_t *, int);
+protected int prompt_init(EditLine *);
+protected void prompt_end(EditLine *);
+
+#endif /* _h_el_prompt */
diff --git a/lib/libedit/read.c b/lib/libedit/read.c
new file mode 100644
index 0000000..4d0b394
--- /dev/null
+++ b/lib/libedit/read.c
@@ -0,0 +1,610 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell 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.
+ *
+ * $NetBSD: read.c,v 1.39 2005/08/02 12:11:14 christos Exp $
+ */
+
+#if !defined(lint) && !defined(SCCSID)
+static char sccsid[] = "@(#)read.c 8.1 (Berkeley) 6/4/93";
+#endif /* not lint && not SCCSID */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * read.c: Clean this junk up! This is horrible code.
+ * Terminal read functions
+ */
+#include "sys.h"
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include "el.h"
+
+#define OKCMD -1
+
+private int read__fixio(int, int);
+private int read_preread(EditLine *);
+private int read_char(EditLine *, char *);
+private int read_getcmd(EditLine *, el_action_t *, char *);
+
+/* read_init():
+ * Initialize the read stuff
+ */
+protected int
+read_init(EditLine *el)
+{
+ /* builtin read_char */
+ el->el_read.read_char = read_char;
+ return 0;
+}
+
+
+/* el_read_setfn():
+ * Set the read char function to the one provided.
+ * If it is set to EL_BUILTIN_GETCFN, then reset to the builtin one.
+ */
+protected int
+el_read_setfn(EditLine *el, el_rfunc_t rc)
+{
+ el->el_read.read_char = (rc == EL_BUILTIN_GETCFN) ? read_char : rc;
+ return 0;
+}
+
+
+/* el_read_getfn():
+ * return the current read char function, or EL_BUILTIN_GETCFN
+ * if it is the default one
+ */
+protected el_rfunc_t
+el_read_getfn(EditLine *el)
+{
+ return (el->el_read.read_char == read_char) ?
+ EL_BUILTIN_GETCFN : el->el_read.read_char;
+}
+
+
+#ifndef MIN
+#define MIN(A,B) ((A) < (B) ? (A) : (B))
+#endif
+
+#ifdef DEBUG_EDIT
+private void
+read_debug(EditLine *el)
+{
+
+ if (el->el_line.cursor > el->el_line.lastchar)
+ (void) fprintf(el->el_errfile, "cursor > lastchar\r\n");
+ if (el->el_line.cursor < el->el_line.buffer)
+ (void) fprintf(el->el_errfile, "cursor < buffer\r\n");
+ if (el->el_line.cursor > el->el_line.limit)
+ (void) fprintf(el->el_errfile, "cursor > limit\r\n");
+ if (el->el_line.lastchar > el->el_line.limit)
+ (void) fprintf(el->el_errfile, "lastchar > limit\r\n");
+ if (el->el_line.limit != &el->el_line.buffer[EL_BUFSIZ - 2])
+ (void) fprintf(el->el_errfile, "limit != &buffer[EL_BUFSIZ-2]\r\n");
+}
+#endif /* DEBUG_EDIT */
+
+
+/* read__fixio():
+ * Try to recover from a read error
+ */
+/* ARGSUSED */
+private int
+read__fixio(int fd __unused, int e)
+{
+
+ switch (e) {
+ case -1: /* Make sure that the code is reachable */
+
+#ifdef EWOULDBLOCK
+ case EWOULDBLOCK:
+#ifndef TRY_AGAIN
+#define TRY_AGAIN
+#endif
+#endif /* EWOULDBLOCK */
+
+#if defined(POSIX) && defined(EAGAIN)
+#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
+ case EAGAIN:
+#ifndef TRY_AGAIN
+#define TRY_AGAIN
+#endif
+#endif /* EWOULDBLOCK && EWOULDBLOCK != EAGAIN */
+#endif /* POSIX && EAGAIN */
+
+ e = 0;
+#ifdef TRY_AGAIN
+#if defined(F_SETFL) && defined(O_NDELAY)
+ if ((e = fcntl(fd, F_GETFL, 0)) == -1)
+ return (-1);
+
+ if (fcntl(fd, F_SETFL, e & ~O_NDELAY) == -1)
+ return (-1);
+ else
+ e = 1;
+#endif /* F_SETFL && O_NDELAY */
+
+#ifdef FIONBIO
+ {
+ int zero = 0;
+
+ if (ioctl(fd, FIONBIO, (ioctl_t) & zero) == -1)
+ return (-1);
+ else
+ e = 1;
+ }
+#endif /* FIONBIO */
+
+#endif /* TRY_AGAIN */
+ return (e ? 0 : -1);
+
+ case EINTR:
+ return (0);
+
+ default:
+ return (-1);
+ }
+}
+
+
+/* read_preread():
+ * Try to read the stuff in the input queue;
+ */
+private int
+read_preread(EditLine *el)
+{
+ int chrs = 0;
+
+ if (el->el_tty.t_mode == ED_IO)
+ return (0);
+
+#ifdef FIONREAD
+ (void) ioctl(el->el_infd, FIONREAD, (ioctl_t) & chrs);
+ if (chrs > 0) {
+ char buf[EL_BUFSIZ];
+
+ chrs = read(el->el_infd, buf,
+ (size_t) MIN(chrs, EL_BUFSIZ - 1));
+ if (chrs > 0) {
+ buf[chrs] = '\0';
+ el_push(el, buf);
+ }
+ }
+#endif /* FIONREAD */
+
+ return (chrs > 0);
+}
+
+
+/* el_push():
+ * Push a macro
+ */
+public void
+el_push(EditLine *el, char *str)
+{
+ c_macro_t *ma = &el->el_chared.c_macro;
+
+ if (str != NULL && ma->level + 1 < EL_MAXMACRO) {
+ ma->level++;
+ if ((ma->macro[ma->level] = el_strdup(str)) != NULL)
+ return;
+ ma->level--;
+ }
+ term_beep(el);
+ term__flush();
+}
+
+
+/* read_getcmd():
+ * Return next command from the input stream.
+ */
+private int
+read_getcmd(EditLine *el, el_action_t *cmdnum, char *ch)
+{
+ el_action_t cmd;
+ int num;
+
+ do {
+ if ((num = el_getc(el, ch)) != 1) /* if EOF or error */
+ return (num);
+
+#ifdef KANJI
+ if ((*ch & 0200)) {
+ el->el_state.metanext = 0;
+ cmd = CcViMap[' '];
+ break;
+ } else
+#endif /* KANJI */
+
+ if (el->el_state.metanext) {
+ el->el_state.metanext = 0;
+ *ch |= 0200;
+ }
+ cmd = el->el_map.current[(unsigned char) *ch];
+ if (cmd == ED_SEQUENCE_LEAD_IN) {
+ key_value_t val;
+ switch (key_get(el, ch, &val)) {
+ case XK_CMD:
+ cmd = val.cmd;
+ break;
+ case XK_STR:
+ el_push(el, val.str);
+ break;
+#ifdef notyet
+ case XK_EXE:
+ /* XXX: In the future to run a user function */
+ RunCommand(val.str);
+ break;
+#endif
+ default:
+ EL_ABORT((el->el_errfile, "Bad XK_ type \n"));
+ break;
+ }
+ }
+ if (el->el_map.alt == NULL)
+ el->el_map.current = el->el_map.key;
+ } while (cmd == ED_SEQUENCE_LEAD_IN);
+ *cmdnum = cmd;
+ return (OKCMD);
+}
+
+
+/* read_char():
+ * Read a character from the tty.
+ */
+private int
+read_char(EditLine *el, char *cp)
+{
+ int num_read;
+ int tried = 0;
+
+ while ((num_read = read(el->el_infd, cp, 1)) == -1)
+ if (!tried && read__fixio(el->el_infd, errno) == 0)
+ tried = 1;
+ else {
+ *cp = '\0';
+ return (-1);
+ }
+
+ return (num_read);
+}
+
+
+/* el_getc():
+ * Read a character
+ */
+public int
+el_getc(EditLine *el, char *cp)
+{
+ int num_read;
+ c_macro_t *ma = &el->el_chared.c_macro;
+
+ term__flush();
+ for (;;) {
+ if (ma->level < 0) {
+ if (!read_preread(el))
+ break;
+ }
+ if (ma->level < 0)
+ break;
+
+ if (ma->macro[ma->level][ma->offset] == '\0') {
+ el_free(ma->macro[ma->level--]);
+ ma->offset = 0;
+ continue;
+ }
+ *cp = ma->macro[ma->level][ma->offset++] & 0377;
+ if (ma->macro[ma->level][ma->offset] == '\0') {
+ /* Needed for QuoteMode On */
+ el_free(ma->macro[ma->level--]);
+ ma->offset = 0;
+ }
+ return (1);
+ }
+
+#ifdef DEBUG_READ
+ (void) fprintf(el->el_errfile, "Turning raw mode on\n");
+#endif /* DEBUG_READ */
+ if (tty_rawmode(el) < 0)/* make sure the tty is set up correctly */
+ return (0);
+
+#ifdef DEBUG_READ
+ (void) fprintf(el->el_errfile, "Reading a character\n");
+#endif /* DEBUG_READ */
+ num_read = (*el->el_read.read_char)(el, cp);
+#ifdef DEBUG_READ
+ (void) fprintf(el->el_errfile, "Got it %c\n", *cp);
+#endif /* DEBUG_READ */
+ return (num_read);
+}
+
+protected void
+read_prepare(EditLine *el)
+{
+ if (el->el_flags & HANDLE_SIGNALS)
+ sig_set(el);
+ if (el->el_flags & NO_TTY)
+ return;
+ if ((el->el_flags & (UNBUFFERED|EDIT_DISABLED)) == UNBUFFERED)
+ tty_rawmode(el);
+
+ /* This is relatively cheap, and things go terribly wrong if
+ we have the wrong size. */
+ el_resize(el);
+ re_clear_display(el); /* reset the display stuff */
+ ch_reset(el, 0);
+ re_refresh(el); /* print the prompt */
+
+ if (el->el_flags & UNBUFFERED)
+ term__flush();
+}
+
+protected void
+read_finish(EditLine *el)
+{
+ if ((el->el_flags & UNBUFFERED) == 0)
+ (void) tty_cookedmode(el);
+ if (el->el_flags & HANDLE_SIGNALS)
+ sig_clr(el);
+}
+
+public const char *
+el_gets(EditLine *el, int *nread)
+{
+ int retval;
+ el_action_t cmdnum = 0;
+ int num; /* how many chars we have read at NL */
+ char ch;
+ int crlf = 0;
+#ifdef FIONREAD
+ c_macro_t *ma = &el->el_chared.c_macro;
+#endif /* FIONREAD */
+
+ if (el->el_flags & NO_TTY) {
+ char *cp = el->el_line.buffer;
+ size_t idx;
+
+ while ((*el->el_read.read_char)(el, cp) == 1) {
+ /* make sure there is space for next character */
+ if (cp + 1 >= el->el_line.limit) {
+ idx = (cp - el->el_line.buffer);
+ if (!ch_enlargebufs(el, 2))
+ break;
+ cp = &el->el_line.buffer[idx];
+ }
+ cp++;
+ if (el->el_flags & UNBUFFERED)
+ break;
+ if (cp[-1] == '\r' || cp[-1] == '\n')
+ break;
+ }
+
+ el->el_line.cursor = el->el_line.lastchar = cp;
+ *cp = '\0';
+ if (nread)
+ *nread = el->el_line.cursor - el->el_line.buffer;
+ return (el->el_line.buffer);
+ }
+
+
+#ifdef FIONREAD
+ if (el->el_tty.t_mode == EX_IO && ma->level < 0) {
+ long chrs = 0;
+
+ (void) ioctl(el->el_infd, FIONREAD, (ioctl_t) & chrs);
+ if (chrs == 0) {
+ if (tty_rawmode(el) < 0) {
+ if (nread)
+ *nread = 0;
+ return (NULL);
+ }
+ }
+ }
+#endif /* FIONREAD */
+
+ if ((el->el_flags & UNBUFFERED) == 0)
+ read_prepare(el);
+
+ if (el->el_flags & EDIT_DISABLED) {
+ char *cp;
+ size_t idx;
+ if ((el->el_flags & UNBUFFERED) == 0)
+ cp = el->el_line.buffer;
+ else
+ cp = el->el_line.lastchar;
+
+ term__flush();
+
+ while ((*el->el_read.read_char)(el, cp) == 1) {
+ /* make sure there is space next character */
+ if (cp + 1 >= el->el_line.limit) {
+ idx = (cp - el->el_line.buffer);
+ if (!ch_enlargebufs(el, 2))
+ break;
+ cp = &el->el_line.buffer[idx];
+ }
+ if (*cp == 4) /* ought to be stty eof */
+ break;
+ cp++;
+ crlf = cp[-1] == '\r' || cp[-1] == '\n';
+ if (el->el_flags & UNBUFFERED)
+ break;
+ if (crlf)
+ break;
+ }
+
+ el->el_line.cursor = el->el_line.lastchar = cp;
+ *cp = '\0';
+ if (nread)
+ *nread = el->el_line.cursor - el->el_line.buffer;
+ return (el->el_line.buffer);
+ }
+
+ for (num = OKCMD; num == OKCMD;) { /* while still editing this
+ * line */
+#ifdef DEBUG_EDIT
+ read_debug(el);
+#endif /* DEBUG_EDIT */
+ /* if EOF or error */
+ if ((num = read_getcmd(el, &cmdnum, &ch)) != OKCMD) {
+#ifdef DEBUG_READ
+ (void) fprintf(el->el_errfile,
+ "Returning from el_gets %d\n", num);
+#endif /* DEBUG_READ */
+ break;
+ }
+ if ((unsigned int)cmdnum >= el->el_map.nfunc) { /* BUG CHECK command */
+#ifdef DEBUG_EDIT
+ (void) fprintf(el->el_errfile,
+ "ERROR: illegal command from key 0%o\r\n", ch);
+#endif /* DEBUG_EDIT */
+ continue; /* try again */
+ }
+ /* now do the real command */
+#ifdef DEBUG_READ
+ {
+ el_bindings_t *b;
+ for (b = el->el_map.help; b->name; b++)
+ if (b->func == cmdnum)
+ break;
+ if (b->name)
+ (void) fprintf(el->el_errfile,
+ "Executing %s\n", b->name);
+ else
+ (void) fprintf(el->el_errfile,
+ "Error command = %d\n", cmdnum);
+ }
+#endif /* DEBUG_READ */
+ /* vi redo needs these way down the levels... */
+ el->el_state.thiscmd = cmdnum;
+ el->el_state.thisch = ch;
+ if (el->el_map.type == MAP_VI &&
+ el->el_map.current == el->el_map.key &&
+ el->el_chared.c_redo.pos < el->el_chared.c_redo.lim) {
+ if (cmdnum == VI_DELETE_PREV_CHAR &&
+ el->el_chared.c_redo.pos != el->el_chared.c_redo.buf
+ && isprint((unsigned char)el->el_chared.c_redo.pos[-1]))
+ el->el_chared.c_redo.pos--;
+ else
+ *el->el_chared.c_redo.pos++ = ch;
+ }
+ retval = (*el->el_map.func[cmdnum]) (el, ch);
+#ifdef DEBUG_READ
+ (void) fprintf(el->el_errfile,
+ "Returned state %d\n", retval );
+#endif /* DEBUG_READ */
+
+ /* save the last command here */
+ el->el_state.lastcmd = cmdnum;
+
+ /* use any return value */
+ switch (retval) {
+ case CC_CURSOR:
+ re_refresh_cursor(el);
+ break;
+
+ case CC_REDISPLAY:
+ re_clear_lines(el);
+ re_clear_display(el);
+ /* FALLTHROUGH */
+
+ case CC_REFRESH:
+ re_refresh(el);
+ break;
+
+ case CC_REFRESH_BEEP:
+ re_refresh(el);
+ term_beep(el);
+ break;
+
+ case CC_NORM: /* normal char */
+ break;
+
+ case CC_ARGHACK: /* Suggested by Rich Salz */
+ /* <rsalz@pineapple.bbn.com> */
+ continue; /* keep going... */
+
+ case CC_EOF: /* end of file typed */
+ if ((el->el_flags & UNBUFFERED) == 0)
+ num = 0;
+ else if (num == -1) {
+ *el->el_line.lastchar++ = CONTROL('d');
+ el->el_line.cursor = el->el_line.lastchar;
+ num = 1;
+ }
+ break;
+
+ case CC_NEWLINE: /* normal end of line */
+ num = el->el_line.lastchar - el->el_line.buffer;
+ break;
+
+ case CC_FATAL: /* fatal error, reset to known state */
+#ifdef DEBUG_READ
+ (void) fprintf(el->el_errfile,
+ "*** editor fatal ERROR ***\r\n\n");
+#endif /* DEBUG_READ */
+ /* put (real) cursor in a known place */
+ re_clear_display(el); /* reset the display stuff */
+ ch_reset(el, 1); /* reset the input pointers */
+ re_refresh(el); /* print the prompt again */
+ break;
+
+ case CC_ERROR:
+ default: /* functions we don't know about */
+#ifdef DEBUG_READ
+ (void) fprintf(el->el_errfile,
+ "*** editor ERROR ***\r\n\n");
+#endif /* DEBUG_READ */
+ term_beep(el);
+ term__flush();
+ break;
+ }
+ el->el_state.argument = 1;
+ el->el_state.doingarg = 0;
+ el->el_chared.c_vcmd.action = NOP;
+ if (el->el_flags & UNBUFFERED)
+ break;
+ }
+
+ term__flush(); /* flush any buffered output */
+ /* make sure the tty is set up correctly */
+ if ((el->el_flags & UNBUFFERED) == 0) {
+ read_finish(el);
+ if (nread)
+ *nread = num;
+ } else {
+ if (nread)
+ *nread = el->el_line.lastchar - el->el_line.buffer;
+ }
+ return (num ? el->el_line.buffer : NULL);
+}
diff --git a/lib/libedit/read.h b/lib/libedit/read.h
new file mode 100644
index 0000000..e4a8799
--- /dev/null
+++ b/lib/libedit/read.h
@@ -0,0 +1,58 @@
+/*-
+ * Copyright (c) 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Anthony Mallet.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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 NetBSD
+ * Foundation, Inc. and its contributors.
+ * 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.
+ *
+ * $NetBSD: read.h,v 1.4 2004/02/27 14:52:18 christos Exp $
+ * $FreeBSD$
+ */
+
+/*
+ * el.read.h: Character reading functions
+ */
+#ifndef _h_el_read
+#define _h_el_read
+
+typedef int (*el_rfunc_t)(EditLine *, char *);
+
+typedef struct el_read_t {
+ el_rfunc_t read_char; /* Function to read a character */
+} el_read_t;
+
+protected int read_init(EditLine *);
+protected void read_prepare(EditLine *);
+protected void read_finish(EditLine *);
+protected int el_read_setfn(EditLine *, el_rfunc_t);
+protected el_rfunc_t el_read_getfn(EditLine *);
+
+#endif /* _h_el_read */
diff --git a/lib/libedit/refresh.c b/lib/libedit/refresh.c
new file mode 100644
index 0000000..22e1de4
--- /dev/null
+++ b/lib/libedit/refresh.c
@@ -0,0 +1,1137 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell 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.
+ *
+ * $NetBSD: refresh.c,v 1.27 2005/11/09 22:11:10 christos Exp $
+ */
+
+#if !defined(lint) && !defined(SCCSID)
+static char sccsid[] = "@(#)refresh.c 8.1 (Berkeley) 6/4/93";
+#endif /* not lint && not SCCSID */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * refresh.c: Lower level screen refreshing functions
+ */
+#include "sys.h"
+#include <stdio.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "el.h"
+
+private void re_addc(EditLine *, int);
+private void re_update_line(EditLine *, char *, char *, int);
+private void re_insert (EditLine *, char *, int, int, char *, int);
+private void re_delete(EditLine *, char *, int, int, int);
+private void re_fastputc(EditLine *, int);
+private void re_clear_eol(EditLine *, int, int, int);
+private void re__strncopy(char *, char *, size_t);
+private void re__copy_and_pad(char *, const char *, size_t);
+
+#ifdef DEBUG_REFRESH
+private void re_printstr(EditLine *, const char *, char *, char *);
+#define __F el->el_errfile
+#define ELRE_ASSERT(a, b, c) do \
+ if (/*CONSTCOND*/ a) { \
+ (void) fprintf b; \
+ c; \
+ } \
+ while (/*CONSTCOND*/0)
+#define ELRE_DEBUG(a, b) ELRE_ASSERT(a,b,;)
+
+/* re_printstr():
+ * Print a string on the debugging pty
+ */
+private void
+re_printstr(EditLine *el, const char *str, char *f, char *t)
+{
+
+ ELRE_DEBUG(1, (__F, "%s:\"", str));
+ while (f < t)
+ ELRE_DEBUG(1, (__F, "%c", *f++ & 0177));
+ ELRE_DEBUG(1, (__F, "\"\r\n"));
+}
+#else
+#define ELRE_ASSERT(a, b, c)
+#define ELRE_DEBUG(a, b)
+#endif
+
+
+/* re_addc():
+ * Draw c, expanding tabs, control chars etc.
+ */
+private void
+re_addc(EditLine *el, int c)
+{
+
+ if (isprint(c)) {
+ re_putc(el, c, 1);
+ return;
+ }
+ if (c == '\n') { /* expand the newline */
+ int oldv = el->el_refresh.r_cursor.v;
+ re_putc(el, '\0', 0); /* assure end of line */
+ if (oldv == el->el_refresh.r_cursor.v) { /* XXX */
+ el->el_refresh.r_cursor.h = 0; /* reset cursor pos */
+ el->el_refresh.r_cursor.v++;
+ }
+ return;
+ }
+ if (c == '\t') { /* expand the tab */
+ for (;;) {
+ re_putc(el, ' ', 1);
+ if ((el->el_refresh.r_cursor.h & 07) == 0)
+ break; /* go until tab stop */
+ }
+ } else if (iscntrl(c)) {
+ re_putc(el, '^', 1);
+ if (c == 0177)
+ re_putc(el, '?', 1);
+ else
+ /* uncontrolify it; works only for iso8859-1 like sets */
+ re_putc(el, (toascii(c) | 0100), 1);
+ } else {
+ re_putc(el, '\\', 1);
+ re_putc(el, (int) ((((unsigned int) c >> 6) & 07) + '0'), 1);
+ re_putc(el, (int) ((((unsigned int) c >> 3) & 07) + '0'), 1);
+ re_putc(el, (c & 07) + '0', 1);
+ }
+}
+
+
+/* re_putc():
+ * Draw the character given
+ */
+protected void
+re_putc(EditLine *el, int c, int shift)
+{
+
+ ELRE_DEBUG(1, (__F, "printing %3.3o '%c'\r\n", c, c));
+
+ el->el_vdisplay[el->el_refresh.r_cursor.v][el->el_refresh.r_cursor.h] = c;
+ if (!shift)
+ return;
+
+ el->el_refresh.r_cursor.h++; /* advance to next place */
+ if (el->el_refresh.r_cursor.h >= el->el_term.t_size.h) {
+ el->el_vdisplay[el->el_refresh.r_cursor.v][el->el_term.t_size.h] = '\0';
+ /* assure end of line */
+ el->el_refresh.r_cursor.h = 0; /* reset it. */
+
+ /*
+ * If we would overflow (input is longer than terminal size),
+ * emulate scroll by dropping first line and shuffling the rest.
+ * We do this via pointer shuffling - it's safe in this case
+ * and we avoid memcpy().
+ */
+ if (el->el_refresh.r_cursor.v + 1 >= el->el_term.t_size.v) {
+ int i, lins = el->el_term.t_size.v;
+ char *firstline = el->el_vdisplay[0];
+
+ for(i=1; i < lins; i++)
+ el->el_vdisplay[i-1] = el->el_vdisplay[i];
+
+ firstline[0] = '\0'; /* empty the string */
+ el->el_vdisplay[i-1] = firstline;
+ } else
+ el->el_refresh.r_cursor.v++;
+
+ ELRE_ASSERT(el->el_refresh.r_cursor.v >= el->el_term.t_size.v,
+ (__F, "\r\nre_putc: overflow! r_cursor.v == %d > %d\r\n",
+ el->el_refresh.r_cursor.v, el->el_term.t_size.v),
+ abort());
+ }
+}
+
+
+/* re_refresh():
+ * draws the new virtual screen image from the current input
+ * line, then goes line-by-line changing the real image to the new
+ * virtual image. The routine to re-draw a line can be replaced
+ * easily in hopes of a smarter one being placed there.
+ */
+protected void
+re_refresh(EditLine *el)
+{
+ int i, rhdiff;
+ char *cp, *st;
+ coord_t cur;
+#ifdef notyet
+ size_t termsz;
+#endif
+
+ ELRE_DEBUG(1, (__F, "el->el_line.buffer = :%s:\r\n",
+ el->el_line.buffer));
+
+ /* reset the Drawing cursor */
+ el->el_refresh.r_cursor.h = 0;
+ el->el_refresh.r_cursor.v = 0;
+
+ /* temporarily draw rprompt to calculate its size */
+ prompt_print(el, EL_RPROMPT);
+
+ /* reset the Drawing cursor */
+ el->el_refresh.r_cursor.h = 0;
+ el->el_refresh.r_cursor.v = 0;
+
+ if (el->el_line.cursor >= el->el_line.lastchar) {
+ if (el->el_map.current == el->el_map.alt
+ && el->el_line.lastchar != el->el_line.buffer)
+ el->el_line.cursor = el->el_line.lastchar - 1;
+ else
+ el->el_line.cursor = el->el_line.lastchar;
+ }
+
+ cur.h = -1; /* set flag in case I'm not set */
+ cur.v = 0;
+
+ prompt_print(el, EL_PROMPT);
+
+ /* draw the current input buffer */
+#if notyet
+ termsz = el->el_term.t_size.h * el->el_term.t_size.v;
+ if (el->el_line.lastchar - el->el_line.buffer > termsz) {
+ /*
+ * If line is longer than terminal, process only part
+ * of line which would influence display.
+ */
+ size_t rem = (el->el_line.lastchar-el->el_line.buffer)%termsz;
+
+ st = el->el_line.lastchar - rem
+ - (termsz - (((rem / el->el_term.t_size.v) - 1)
+ * el->el_term.t_size.v));
+ } else
+#endif
+ st = el->el_line.buffer;
+
+ for (cp = st; cp < el->el_line.lastchar; cp++) {
+ if (cp == el->el_line.cursor) {
+ /* save for later */
+ cur.h = el->el_refresh.r_cursor.h;
+ cur.v = el->el_refresh.r_cursor.v;
+ }
+ re_addc(el, (unsigned char) *cp);
+ }
+
+ if (cur.h == -1) { /* if I haven't been set yet, I'm at the end */
+ cur.h = el->el_refresh.r_cursor.h;
+ cur.v = el->el_refresh.r_cursor.v;
+ }
+ rhdiff = el->el_term.t_size.h - el->el_refresh.r_cursor.h -
+ el->el_rprompt.p_pos.h;
+ if (el->el_rprompt.p_pos.h && !el->el_rprompt.p_pos.v &&
+ !el->el_refresh.r_cursor.v && rhdiff > 1) {
+ /*
+ * have a right-hand side prompt that will fit
+ * on the end of the first line with at least
+ * one character gap to the input buffer.
+ */
+ while (--rhdiff > 0) /* pad out with spaces */
+ re_putc(el, ' ', 1);
+ prompt_print(el, EL_RPROMPT);
+ } else {
+ el->el_rprompt.p_pos.h = 0; /* flag "not using rprompt" */
+ el->el_rprompt.p_pos.v = 0;
+ }
+
+ re_putc(el, '\0', 0); /* make line ended with NUL, no cursor shift */
+
+ el->el_refresh.r_newcv = el->el_refresh.r_cursor.v;
+
+ ELRE_DEBUG(1, (__F,
+ "term.h=%d vcur.h=%d vcur.v=%d vdisplay[0]=\r\n:%80.80s:\r\n",
+ el->el_term.t_size.h, el->el_refresh.r_cursor.h,
+ el->el_refresh.r_cursor.v, el->el_vdisplay[0]));
+
+ ELRE_DEBUG(1, (__F, "updating %d lines.\r\n", el->el_refresh.r_newcv));
+ for (i = 0; i <= el->el_refresh.r_newcv; i++) {
+ /* NOTE THAT re_update_line MAY CHANGE el_display[i] */
+ re_update_line(el, el->el_display[i], el->el_vdisplay[i], i);
+
+ /*
+ * Copy the new line to be the current one, and pad out with
+ * spaces to the full width of the terminal so that if we try
+ * moving the cursor by writing the character that is at the
+ * end of the screen line, it won't be a NUL or some old
+ * leftover stuff.
+ */
+ re__copy_and_pad(el->el_display[i], el->el_vdisplay[i],
+ (size_t) el->el_term.t_size.h);
+ }
+ ELRE_DEBUG(1, (__F,
+ "\r\nel->el_refresh.r_cursor.v=%d,el->el_refresh.r_oldcv=%d i=%d\r\n",
+ el->el_refresh.r_cursor.v, el->el_refresh.r_oldcv, i));
+
+ if (el->el_refresh.r_oldcv > el->el_refresh.r_newcv)
+ for (; i <= el->el_refresh.r_oldcv; i++) {
+ term_move_to_line(el, i);
+ term_move_to_char(el, 0);
+ term_clear_EOL(el, (int) strlen(el->el_display[i]));
+#ifdef DEBUG_REFRESH
+ term_overwrite(el, "C\b", 2);
+#endif /* DEBUG_REFRESH */
+ el->el_display[i][0] = '\0';
+ }
+
+ el->el_refresh.r_oldcv = el->el_refresh.r_newcv; /* set for next time */
+ ELRE_DEBUG(1, (__F,
+ "\r\ncursor.h = %d, cursor.v = %d, cur.h = %d, cur.v = %d\r\n",
+ el->el_refresh.r_cursor.h, el->el_refresh.r_cursor.v,
+ cur.h, cur.v));
+ term_move_to_line(el, cur.v); /* go to where the cursor is */
+ term_move_to_char(el, cur.h);
+}
+
+
+/* re_goto_bottom():
+ * used to go to last used screen line
+ */
+protected void
+re_goto_bottom(EditLine *el)
+{
+
+ term_move_to_line(el, el->el_refresh.r_oldcv);
+ term__putc('\n');
+ re_clear_display(el);
+ term__flush();
+}
+
+
+/* re_insert():
+ * insert num characters of s into d (in front of the character)
+ * at dat, maximum length of d is dlen
+ */
+private void
+/*ARGSUSED*/
+re_insert(EditLine *el __unused,
+ char *d, int dat, int dlen, char *s, int num)
+{
+ char *a, *b;
+
+ if (num <= 0)
+ return;
+ if (num > dlen - dat)
+ num = dlen - dat;
+
+ ELRE_DEBUG(1,
+ (__F, "re_insert() starting: %d at %d max %d, d == \"%s\"\n",
+ num, dat, dlen, d));
+ ELRE_DEBUG(1, (__F, "s == \"%s\"\n", s));
+
+ /* open up the space for num chars */
+ if (num > 0) {
+ b = d + dlen - 1;
+ a = b - num;
+ while (a >= &d[dat])
+ *b-- = *a--;
+ d[dlen] = '\0'; /* just in case */
+ }
+ ELRE_DEBUG(1, (__F,
+ "re_insert() after insert: %d at %d max %d, d == \"%s\"\n",
+ num, dat, dlen, d));
+ ELRE_DEBUG(1, (__F, "s == \"%s\"\n", s));
+
+ /* copy the characters */
+ for (a = d + dat; (a < d + dlen) && (num > 0); num--)
+ *a++ = *s++;
+
+ ELRE_DEBUG(1,
+ (__F, "re_insert() after copy: %d at %d max %d, %s == \"%s\"\n",
+ num, dat, dlen, d, s));
+ ELRE_DEBUG(1, (__F, "s == \"%s\"\n", s));
+}
+
+
+/* re_delete():
+ * delete num characters d at dat, maximum length of d is dlen
+ */
+private void
+/*ARGSUSED*/
+re_delete(EditLine *el __unused,
+ char *d, int dat, int dlen, int num)
+{
+ char *a, *b;
+
+ if (num <= 0)
+ return;
+ if (dat + num >= dlen) {
+ d[dat] = '\0';
+ return;
+ }
+ ELRE_DEBUG(1,
+ (__F, "re_delete() starting: %d at %d max %d, d == \"%s\"\n",
+ num, dat, dlen, d));
+
+ /* open up the space for num chars */
+ if (num > 0) {
+ b = d + dat;
+ a = b + num;
+ while (a < &d[dlen])
+ *b++ = *a++;
+ d[dlen] = '\0'; /* just in case */
+ }
+ ELRE_DEBUG(1,
+ (__F, "re_delete() after delete: %d at %d max %d, d == \"%s\"\n",
+ num, dat, dlen, d));
+}
+
+
+/* re__strncopy():
+ * Like strncpy without padding.
+ */
+private void
+re__strncopy(char *a, char *b, size_t n)
+{
+
+ while (n-- && *b)
+ *a++ = *b++;
+}
+
+/* re_clear_eol():
+ * Find the number of characters we need to clear till the end of line
+ * in order to make sure that we have cleared the previous contents of
+ * the line. fx and sx is the number of characters inserted or deleted
+ * int the first or second diff, diff is the difference between the
+ * number of characters between the new and old line.
+ */
+private void
+re_clear_eol(EditLine *el, int fx, int sx, int diff)
+{
+
+ ELRE_DEBUG(1, (__F, "re_clear_eol sx %d, fx %d, diff %d\n",
+ sx, fx, diff));
+
+ if (fx < 0)
+ fx = -fx;
+ if (sx < 0)
+ sx = -sx;
+ if (fx > diff)
+ diff = fx;
+ if (sx > diff)
+ diff = sx;
+
+ ELRE_DEBUG(1, (__F, "re_clear_eol %d\n", diff));
+ term_clear_EOL(el, diff);
+}
+
+/*****************************************************************
+ re_update_line() is based on finding the middle difference of each line
+ on the screen; vis:
+
+ /old first difference
+ /beginning of line | /old last same /old EOL
+ v v v v
+old: eddie> Oh, my little gruntle-buggy is to me, as lurgid as
+new: eddie> Oh, my little buggy says to me, as lurgid as
+ ^ ^ ^ ^
+ \beginning of line | \new last same \new end of line
+ \new first difference
+
+ all are character pointers for the sake of speed. Special cases for
+ no differences, as well as for end of line additions must be handled.
+**************************************************************** */
+
+/* Minimum at which doing an insert it "worth it". This should be about
+ * half the "cost" of going into insert mode, inserting a character, and
+ * going back out. This should really be calculated from the termcap
+ * data... For the moment, a good number for ANSI terminals.
+ */
+#define MIN_END_KEEP 4
+
+private void
+re_update_line(EditLine *el, char *old, char *new, int i)
+{
+ char *o, *n, *p, c;
+ char *ofd, *ols, *oe, *nfd, *nls, *ne;
+ char *osb, *ose, *nsb, *nse;
+ int fx, sx;
+
+ /*
+ * find first diff
+ */
+ for (o = old, n = new; *o && (*o == *n); o++, n++)
+ continue;
+ ofd = o;
+ nfd = n;
+
+ /*
+ * Find the end of both old and new
+ */
+ while (*o)
+ o++;
+ /*
+ * Remove any trailing blanks off of the end, being careful not to
+ * back up past the beginning.
+ */
+ while (ofd < o) {
+ if (o[-1] != ' ')
+ break;
+ o--;
+ }
+ oe = o;
+ *oe = '\0';
+
+ while (*n)
+ n++;
+
+ /* remove blanks from end of new */
+ while (nfd < n) {
+ if (n[-1] != ' ')
+ break;
+ n--;
+ }
+ ne = n;
+ *ne = '\0';
+
+ /*
+ * if no diff, continue to next line of redraw
+ */
+ if (*ofd == '\0' && *nfd == '\0') {
+ ELRE_DEBUG(1, (__F, "no difference.\r\n"));
+ return;
+ }
+ /*
+ * find last same pointer
+ */
+ while ((o > ofd) && (n > nfd) && (*--o == *--n))
+ continue;
+ ols = ++o;
+ nls = ++n;
+
+ /*
+ * find same begining and same end
+ */
+ osb = ols;
+ nsb = nls;
+ ose = ols;
+ nse = nls;
+
+ /*
+ * case 1: insert: scan from nfd to nls looking for *ofd
+ */
+ if (*ofd) {
+ for (c = *ofd, n = nfd; n < nls; n++) {
+ if (c == *n) {
+ for (o = ofd, p = n;
+ p < nls && o < ols && *o == *p;
+ o++, p++)
+ continue;
+ /*
+ * if the new match is longer and it's worth
+ * keeping, then we take it
+ */
+ if (((nse - nsb) < (p - n)) &&
+ (2 * (p - n) > n - nfd)) {
+ nsb = n;
+ nse = p;
+ osb = ofd;
+ ose = o;
+ }
+ }
+ }
+ }
+ /*
+ * case 2: delete: scan from ofd to ols looking for *nfd
+ */
+ if (*nfd) {
+ for (c = *nfd, o = ofd; o < ols; o++) {
+ if (c == *o) {
+ for (n = nfd, p = o;
+ p < ols && n < nls && *p == *n;
+ p++, n++)
+ continue;
+ /*
+ * if the new match is longer and it's worth
+ * keeping, then we take it
+ */
+ if (((ose - osb) < (p - o)) &&
+ (2 * (p - o) > o - ofd)) {
+ nsb = nfd;
+ nse = n;
+ osb = o;
+ ose = p;
+ }
+ }
+ }
+ }
+ /*
+ * Pragmatics I: If old trailing whitespace or not enough characters to
+ * save to be worth it, then don't save the last same info.
+ */
+ if ((oe - ols) < MIN_END_KEEP) {
+ ols = oe;
+ nls = ne;
+ }
+ /*
+ * Pragmatics II: if the terminal isn't smart enough, make the data
+ * dumber so the smart update doesn't try anything fancy
+ */
+
+ /*
+ * fx is the number of characters we need to insert/delete: in the
+ * beginning to bring the two same begins together
+ */
+ fx = (nsb - nfd) - (osb - ofd);
+ /*
+ * sx is the number of characters we need to insert/delete: in the
+ * end to bring the two same last parts together
+ */
+ sx = (nls - nse) - (ols - ose);
+
+ if (!EL_CAN_INSERT) {
+ if (fx > 0) {
+ osb = ols;
+ ose = ols;
+ nsb = nls;
+ nse = nls;
+ }
+ if (sx > 0) {
+ ols = oe;
+ nls = ne;
+ }
+ if ((ols - ofd) < (nls - nfd)) {
+ ols = oe;
+ nls = ne;
+ }
+ }
+ if (!EL_CAN_DELETE) {
+ if (fx < 0) {
+ osb = ols;
+ ose = ols;
+ nsb = nls;
+ nse = nls;
+ }
+ if (sx < 0) {
+ ols = oe;
+ nls = ne;
+ }
+ if ((ols - ofd) > (nls - nfd)) {
+ ols = oe;
+ nls = ne;
+ }
+ }
+ /*
+ * Pragmatics III: make sure the middle shifted pointers are correct if
+ * they don't point to anything (we may have moved ols or nls).
+ */
+ /* if the change isn't worth it, don't bother */
+ /* was: if (osb == ose) */
+ if ((ose - osb) < MIN_END_KEEP) {
+ osb = ols;
+ ose = ols;
+ nsb = nls;
+ nse = nls;
+ }
+ /*
+ * Now that we are done with pragmatics we recompute fx, sx
+ */
+ fx = (nsb - nfd) - (osb - ofd);
+ sx = (nls - nse) - (ols - ose);
+
+ ELRE_DEBUG(1, (__F, "fx %d, sx %d\n", fx, sx));
+ ELRE_DEBUG(1, (__F, "ofd %d, osb %d, ose %d, ols %d, oe %d\n",
+ ofd - old, osb - old, ose - old, ols - old, oe - old));
+ ELRE_DEBUG(1, (__F, "nfd %d, nsb %d, nse %d, nls %d, ne %d\n",
+ nfd - new, nsb - new, nse - new, nls - new, ne - new));
+ ELRE_DEBUG(1, (__F,
+ "xxx-xxx:\"00000000001111111111222222222233333333334\"\r\n"));
+ ELRE_DEBUG(1, (__F,
+ "xxx-xxx:\"01234567890123456789012345678901234567890\"\r\n"));
+#ifdef DEBUG_REFRESH
+ re_printstr(el, "old- oe", old, oe);
+ re_printstr(el, "new- ne", new, ne);
+ re_printstr(el, "old-ofd", old, ofd);
+ re_printstr(el, "new-nfd", new, nfd);
+ re_printstr(el, "ofd-osb", ofd, osb);
+ re_printstr(el, "nfd-nsb", nfd, nsb);
+ re_printstr(el, "osb-ose", osb, ose);
+ re_printstr(el, "nsb-nse", nsb, nse);
+ re_printstr(el, "ose-ols", ose, ols);
+ re_printstr(el, "nse-nls", nse, nls);
+ re_printstr(el, "ols- oe", ols, oe);
+ re_printstr(el, "nls- ne", nls, ne);
+#endif /* DEBUG_REFRESH */
+
+ /*
+ * el_cursor.v to this line i MUST be in this routine so that if we
+ * don't have to change the line, we don't move to it. el_cursor.h to
+ * first diff char
+ */
+ term_move_to_line(el, i);
+
+ /*
+ * at this point we have something like this:
+ *
+ * /old /ofd /osb /ose /ols /oe
+ * v.....................v v..................v v........v
+ * eddie> Oh, my fredded gruntle-buggy is to me, as foo var lurgid as
+ * eddie> Oh, my fredded quiux buggy is to me, as gruntle-lurgid as
+ * ^.....................^ ^..................^ ^........^
+ * \new \nfd \nsb \nse \nls \ne
+ *
+ * fx is the difference in length between the chars between nfd and
+ * nsb, and the chars between ofd and osb, and is thus the number of
+ * characters to delete if < 0 (new is shorter than old, as above),
+ * or insert (new is longer than short).
+ *
+ * sx is the same for the second differences.
+ */
+
+ /*
+ * if we have a net insert on the first difference, AND inserting the
+ * net amount ((nsb-nfd) - (osb-ofd)) won't push the last useful
+ * character (which is ne if nls != ne, otherwise is nse) off the edge
+ * of the screen (el->el_term.t_size.h) else we do the deletes first
+ * so that we keep everything we need to.
+ */
+
+ /*
+ * if the last same is the same like the end, there is no last same
+ * part, otherwise we want to keep the last same part set p to the
+ * last useful old character
+ */
+ p = (ols != oe) ? oe : ose;
+
+ /*
+ * if (There is a diffence in the beginning) && (we need to insert
+ * characters) && (the number of characters to insert is less than
+ * the term width)
+ * We need to do an insert!
+ * else if (we need to delete characters)
+ * We need to delete characters!
+ * else
+ * No insert or delete
+ */
+ if ((nsb != nfd) && fx > 0 &&
+ ((p - old) + fx <= el->el_term.t_size.h)) {
+ ELRE_DEBUG(1,
+ (__F, "first diff insert at %d...\r\n", nfd - new));
+ /*
+ * Move to the first char to insert, where the first diff is.
+ */
+ term_move_to_char(el, nfd - new);
+ /*
+ * Check if we have stuff to keep at end
+ */
+ if (nsb != ne) {
+ ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n"));
+ /*
+ * insert fx chars of new starting at nfd
+ */
+ if (fx > 0) {
+ ELRE_DEBUG(!EL_CAN_INSERT, (__F,
+ "ERROR: cannot insert in early first diff\n"));
+ term_insertwrite(el, nfd, fx);
+ re_insert(el, old, ofd - old,
+ el->el_term.t_size.h, nfd, fx);
+ }
+ /*
+ * write (nsb-nfd) - fx chars of new starting at
+ * (nfd + fx)
+ */
+ term_overwrite(el, nfd + fx, (nsb - nfd) - fx);
+ re__strncopy(ofd + fx, nfd + fx,
+ (size_t) ((nsb - nfd) - fx));
+ } else {
+ ELRE_DEBUG(1, (__F, "without anything to save\r\n"));
+ term_overwrite(el, nfd, (nsb - nfd));
+ re__strncopy(ofd, nfd, (size_t) (nsb - nfd));
+ /*
+ * Done
+ */
+ return;
+ }
+ } else if (fx < 0) {
+ ELRE_DEBUG(1,
+ (__F, "first diff delete at %d...\r\n", ofd - old));
+ /*
+ * move to the first char to delete where the first diff is
+ */
+ term_move_to_char(el, ofd - old);
+ /*
+ * Check if we have stuff to save
+ */
+ if (osb != oe) {
+ ELRE_DEBUG(1, (__F, "with stuff to save at end\r\n"));
+ /*
+ * fx is less than zero *always* here but we check
+ * for code symmetry
+ */
+ if (fx < 0) {
+ ELRE_DEBUG(!EL_CAN_DELETE, (__F,
+ "ERROR: cannot delete in first diff\n"));
+ term_deletechars(el, -fx);
+ re_delete(el, old, ofd - old,
+ el->el_term.t_size.h, -fx);
+ }
+ /*
+ * write (nsb-nfd) chars of new starting at nfd
+ */
+ term_overwrite(el, nfd, (nsb - nfd));
+ re__strncopy(ofd, nfd, (size_t) (nsb - nfd));
+
+ } else {
+ ELRE_DEBUG(1, (__F,
+ "but with nothing left to save\r\n"));
+ /*
+ * write (nsb-nfd) chars of new starting at nfd
+ */
+ term_overwrite(el, nfd, (nsb - nfd));
+ re_clear_eol(el, fx, sx, (oe - old) - (ne - new));
+ /*
+ * Done
+ */
+ return;
+ }
+ } else
+ fx = 0;
+
+ if (sx < 0 && (ose - old) + fx < el->el_term.t_size.h) {
+ ELRE_DEBUG(1, (__F,
+ "second diff delete at %d...\r\n", (ose - old) + fx));
+ /*
+ * Check if we have stuff to delete
+ */
+ /*
+ * fx is the number of characters inserted (+) or deleted (-)
+ */
+
+ term_move_to_char(el, (ose - old) + fx);
+ /*
+ * Check if we have stuff to save
+ */
+ if (ols != oe) {
+ ELRE_DEBUG(1, (__F, "with stuff to save at end\r\n"));
+ /*
+ * Again a duplicate test.
+ */
+ if (sx < 0) {
+ ELRE_DEBUG(!EL_CAN_DELETE, (__F,
+ "ERROR: cannot delete in second diff\n"));
+ term_deletechars(el, -sx);
+ }
+ /*
+ * write (nls-nse) chars of new starting at nse
+ */
+ term_overwrite(el, nse, (nls - nse));
+ } else {
+ ELRE_DEBUG(1, (__F,
+ "but with nothing left to save\r\n"));
+ term_overwrite(el, nse, (nls - nse));
+ re_clear_eol(el, fx, sx, (oe - old) - (ne - new));
+ }
+ }
+ /*
+ * if we have a first insert AND WE HAVEN'T ALREADY DONE IT...
+ */
+ if ((nsb != nfd) && (osb - ofd) <= (nsb - nfd) && (fx == 0)) {
+ ELRE_DEBUG(1, (__F, "late first diff insert at %d...\r\n",
+ nfd - new));
+
+ term_move_to_char(el, nfd - new);
+ /*
+ * Check if we have stuff to keep at the end
+ */
+ if (nsb != ne) {
+ ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n"));
+ /*
+ * We have to recalculate fx here because we set it
+ * to zero above as a flag saying that we hadn't done
+ * an early first insert.
+ */
+ fx = (nsb - nfd) - (osb - ofd);
+ if (fx > 0) {
+ /*
+ * insert fx chars of new starting at nfd
+ */
+ ELRE_DEBUG(!EL_CAN_INSERT, (__F,
+ "ERROR: cannot insert in late first diff\n"));
+ term_insertwrite(el, nfd, fx);
+ re_insert(el, old, ofd - old,
+ el->el_term.t_size.h, nfd, fx);
+ }
+ /*
+ * write (nsb-nfd) - fx chars of new starting at
+ * (nfd + fx)
+ */
+ term_overwrite(el, nfd + fx, (nsb - nfd) - fx);
+ re__strncopy(ofd + fx, nfd + fx,
+ (size_t) ((nsb - nfd) - fx));
+ } else {
+ ELRE_DEBUG(1, (__F, "without anything to save\r\n"));
+ term_overwrite(el, nfd, (nsb - nfd));
+ re__strncopy(ofd, nfd, (size_t) (nsb - nfd));
+ }
+ }
+ /*
+ * line is now NEW up to nse
+ */
+ if (sx >= 0) {
+ ELRE_DEBUG(1, (__F,
+ "second diff insert at %d...\r\n", nse - new));
+ term_move_to_char(el, nse - new);
+ if (ols != oe) {
+ ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n"));
+ if (sx > 0) {
+ /* insert sx chars of new starting at nse */
+ ELRE_DEBUG(!EL_CAN_INSERT, (__F,
+ "ERROR: cannot insert in second diff\n"));
+ term_insertwrite(el, nse, sx);
+ }
+ /*
+ * write (nls-nse) - sx chars of new starting at
+ * (nse + sx)
+ */
+ term_overwrite(el, nse + sx, (nls - nse) - sx);
+ } else {
+ ELRE_DEBUG(1, (__F, "without anything to save\r\n"));
+ term_overwrite(el, nse, (nls - nse));
+
+ /*
+ * No need to do a clear-to-end here because we were
+ * doing a second insert, so we will have over
+ * written all of the old string.
+ */
+ }
+ }
+ ELRE_DEBUG(1, (__F, "done.\r\n"));
+}
+
+
+/* re__copy_and_pad():
+ * Copy string and pad with spaces
+ */
+private void
+re__copy_and_pad(char *dst, const char *src, size_t width)
+{
+ size_t i;
+
+ for (i = 0; i < width; i++) {
+ if (*src == '\0')
+ break;
+ *dst++ = *src++;
+ }
+
+ for (; i < width; i++)
+ *dst++ = ' ';
+
+ *dst = '\0';
+}
+
+
+/* re_refresh_cursor():
+ * Move to the new cursor position
+ */
+protected void
+re_refresh_cursor(EditLine *el)
+{
+ char *cp, c;
+ int h, v, th;
+
+ if (el->el_line.cursor >= el->el_line.lastchar) {
+ if (el->el_map.current == el->el_map.alt
+ && el->el_line.lastchar != el->el_line.buffer)
+ el->el_line.cursor = el->el_line.lastchar - 1;
+ else
+ el->el_line.cursor = el->el_line.lastchar;
+ }
+
+ /* first we must find where the cursor is... */
+ h = el->el_prompt.p_pos.h;
+ v = el->el_prompt.p_pos.v;
+ th = el->el_term.t_size.h; /* optimize for speed */
+
+ /* do input buffer to el->el_line.cursor */
+ for (cp = el->el_line.buffer; cp < el->el_line.cursor; cp++) {
+ c = *cp;
+ h++; /* all chars at least this long */
+
+ if (c == '\n') {/* handle newline in data part too */
+ h = 0;
+ v++;
+ } else {
+ if (c == '\t') { /* if a tab, to next tab stop */
+ while (h & 07) {
+ h++;
+ }
+ } else if (iscntrl((unsigned char) c)) {
+ /* if control char */
+ h++;
+ if (h > th) { /* if overflow, compensate */
+ h = 1;
+ v++;
+ }
+ } else if (!isprint((unsigned char) c)) {
+ h += 3;
+ if (h > th) { /* if overflow, compensate */
+ h = h - th;
+ v++;
+ }
+ }
+ }
+
+ if (h >= th) { /* check, extra long tabs picked up here also */
+ h = 0;
+ v++;
+ }
+ }
+
+ /* now go there */
+ term_move_to_line(el, v);
+ term_move_to_char(el, h);
+ term__flush();
+}
+
+
+/* re_fastputc():
+ * Add a character fast.
+ */
+private void
+re_fastputc(EditLine *el, int c)
+{
+
+ term__putc(c);
+ el->el_display[el->el_cursor.v][el->el_cursor.h++] = c;
+ if (el->el_cursor.h >= el->el_term.t_size.h) {
+ /* if we must overflow */
+ el->el_cursor.h = 0;
+
+ /*
+ * If we would overflow (input is longer than terminal size),
+ * emulate scroll by dropping first line and shuffling the rest.
+ * We do this via pointer shuffling - it's safe in this case
+ * and we avoid memcpy().
+ */
+ if (el->el_cursor.v + 1 >= el->el_term.t_size.v) {
+ int i, lins = el->el_term.t_size.v;
+ char *firstline = el->el_display[0];
+
+ for(i=1; i < lins; i++)
+ el->el_display[i-1] = el->el_display[i];
+
+ re__copy_and_pad(firstline, "", 0);
+ el->el_display[i-1] = firstline;
+ } else {
+ el->el_cursor.v++;
+ el->el_refresh.r_oldcv++;
+ }
+ if (EL_HAS_AUTO_MARGINS) {
+ if (EL_HAS_MAGIC_MARGINS) {
+ term__putc(' ');
+ term__putc('\b');
+ }
+ } else {
+ term__putc('\r');
+ term__putc('\n');
+ }
+ }
+}
+
+
+/* re_fastaddc():
+ * we added just one char, handle it fast.
+ * Assumes that screen cursor == real cursor
+ */
+protected void
+re_fastaddc(EditLine *el)
+{
+ char c;
+ int rhdiff;
+
+ c = (unsigned char)el->el_line.cursor[-1];
+
+ if (c == '\t' || el->el_line.cursor != el->el_line.lastchar) {
+ re_refresh(el); /* too hard to handle */
+ return;
+ }
+ rhdiff = el->el_term.t_size.h - el->el_cursor.h -
+ el->el_rprompt.p_pos.h;
+ if (el->el_rprompt.p_pos.h && rhdiff < 3) {
+ re_refresh(el); /* clear out rprompt if less than 1 char gap */
+ return;
+ } /* else (only do at end of line, no TAB) */
+ if (iscntrl((unsigned char) c)) { /* if control char, do caret */
+ char mc = (c == 0177) ? '?' : (toascii(c) | 0100);
+ re_fastputc(el, '^');
+ re_fastputc(el, mc);
+ } else if (isprint((unsigned char) c)) { /* normal char */
+ re_fastputc(el, c);
+ } else {
+ re_fastputc(el, '\\');
+ re_fastputc(el, (int)(((((unsigned int)c) >> 6) & 3) + '0'));
+ re_fastputc(el, (int)(((((unsigned int)c) >> 3) & 7) + '0'));
+ re_fastputc(el, (c & 7) + '0');
+ }
+ term__flush();
+}
+
+
+/* re_clear_display():
+ * clear the screen buffers so that new new prompt starts fresh.
+ */
+protected void
+re_clear_display(EditLine *el)
+{
+ int i;
+
+ el->el_cursor.v = 0;
+ el->el_cursor.h = 0;
+ for (i = 0; i < el->el_term.t_size.v; i++)
+ el->el_display[i][0] = '\0';
+ el->el_refresh.r_oldcv = 0;
+}
+
+
+/* re_clear_lines():
+ * Make sure all lines are *really* blank
+ */
+protected void
+re_clear_lines(EditLine *el)
+{
+
+ if (EL_CAN_CEOL) {
+ int i;
+ term_move_to_char(el, 0);
+ for (i = 0; i <= el->el_refresh.r_oldcv; i++) {
+ /* for each line on the screen */
+ term_move_to_line(el, i);
+ term_clear_EOL(el, el->el_term.t_size.h);
+ }
+ term_move_to_line(el, 0);
+ } else {
+ term_move_to_line(el, el->el_refresh.r_oldcv);
+ /* go to last line */
+ term__putc('\r'); /* go to BOL */
+ term__putc('\n'); /* go to new line */
+ }
+}
diff --git a/lib/libedit/refresh.h b/lib/libedit/refresh.h
new file mode 100644
index 0000000..e44ef9c
--- /dev/null
+++ b/lib/libedit/refresh.h
@@ -0,0 +1,59 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell 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.
+ *
+ * @(#)refresh.h 8.1 (Berkeley) 6/4/93
+ * $NetBSD: refresh.h,v 1.5 2003/08/07 16:44:33 agc Exp $
+ * $FreeBSD$
+ */
+
+/*
+ * el.refresh.h: Screen refresh functions
+ */
+#ifndef _h_el_refresh
+#define _h_el_refresh
+
+#include "histedit.h"
+
+typedef struct {
+ coord_t r_cursor; /* Refresh cursor position */
+ int r_oldcv; /* Vertical locations */
+ int r_newcv;
+} el_refresh_t;
+
+protected void re_putc(EditLine *, int, int);
+protected void re_clear_lines(EditLine *);
+protected void re_clear_display(EditLine *);
+protected void re_refresh(EditLine *);
+protected void re_refresh_cursor(EditLine *);
+protected void re_fastaddc(EditLine *);
+protected void re_goto_bottom(EditLine *);
+
+#endif /* _h_el_refresh */
diff --git a/lib/libedit/search.c b/lib/libedit/search.c
new file mode 100644
index 0000000..991bad2
--- /dev/null
+++ b/lib/libedit/search.c
@@ -0,0 +1,631 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell 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.
+ *
+ * $NetBSD: search.c,v 1.20 2004/11/04 01:16:03 christos Exp $
+ */
+
+#if !defined(lint) && !defined(SCCSID)
+static char sccsid[] = "@(#)search.c 8.1 (Berkeley) 6/4/93";
+#endif /* not lint && not SCCSID */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * search.c: History and character search functions
+ */
+#include "sys.h"
+#include <stdlib.h>
+#if defined(REGEX)
+#include <regex.h>
+#elif defined(REGEXP)
+#include <regexp.h>
+#endif
+#include "el.h"
+
+/*
+ * Adjust cursor in vi mode to include the character under it
+ */
+#define EL_CURSOR(el) \
+ ((el)->el_line.cursor + (((el)->el_map.type == MAP_VI) && \
+ ((el)->el_map.current == (el)->el_map.alt)))
+
+/* search_init():
+ * Initialize the search stuff
+ */
+protected int
+search_init(EditLine *el)
+{
+
+ el->el_search.patbuf = (char *) el_malloc(EL_BUFSIZ);
+ if (el->el_search.patbuf == NULL)
+ return (-1);
+ el->el_search.patlen = 0;
+ el->el_search.patdir = -1;
+ el->el_search.chacha = '\0';
+ el->el_search.chadir = CHAR_FWD;
+ el->el_search.chatflg = 0;
+ return (0);
+}
+
+
+/* search_end():
+ * Initialize the search stuff
+ */
+protected void
+search_end(EditLine *el)
+{
+
+ el_free((ptr_t) el->el_search.patbuf);
+ el->el_search.patbuf = NULL;
+}
+
+
+#ifdef REGEXP
+/* regerror():
+ * Handle regular expression errors
+ */
+public void
+/*ARGSUSED*/
+regerror(const char *msg)
+{
+}
+#endif
+
+
+/* el_match():
+ * Return if string matches pattern
+ */
+protected int
+el_match(const char *str, const char *pat)
+{
+#if defined (REGEX)
+ regex_t re;
+ int rv;
+#elif defined (REGEXP)
+ regexp *rp;
+ int rv;
+#else
+ extern char *re_comp(const char *);
+ extern int re_exec(const char *);
+#endif
+
+ if (strstr(str, pat) != NULL)
+ return (1);
+
+#if defined(REGEX)
+ if (regcomp(&re, pat, 0) == 0) {
+ rv = regexec(&re, str, 0, NULL, 0) == 0;
+ regfree(&re);
+ } else {
+ rv = 0;
+ }
+ return (rv);
+#elif defined(REGEXP)
+ if ((re = regcomp(pat)) != NULL) {
+ rv = regexec(re, str);
+ free((ptr_t) re);
+ } else {
+ rv = 0;
+ }
+ return (rv);
+#else
+ if (re_comp(pat) != NULL)
+ return (0);
+ else
+ return (re_exec(str) == 1);
+#endif
+}
+
+
+/* c_hmatch():
+ * return True if the pattern matches the prefix
+ */
+protected int
+c_hmatch(EditLine *el, const char *str)
+{
+#ifdef SDEBUG
+ (void) fprintf(el->el_errfile, "match `%s' with `%s'\n",
+ el->el_search.patbuf, str);
+#endif /* SDEBUG */
+
+ return (el_match(str, el->el_search.patbuf));
+}
+
+
+/* c_setpat():
+ * Set the history seatch pattern
+ */
+protected void
+c_setpat(EditLine *el)
+{
+ if (el->el_state.lastcmd != ED_SEARCH_PREV_HISTORY &&
+ el->el_state.lastcmd != ED_SEARCH_NEXT_HISTORY) {
+ el->el_search.patlen = EL_CURSOR(el) - el->el_line.buffer;
+ if (el->el_search.patlen >= EL_BUFSIZ)
+ el->el_search.patlen = EL_BUFSIZ - 1;
+ if (el->el_search.patlen != 0) {
+ (void) strncpy(el->el_search.patbuf, el->el_line.buffer,
+ el->el_search.patlen);
+ el->el_search.patbuf[el->el_search.patlen] = '\0';
+ } else
+ el->el_search.patlen = strlen(el->el_search.patbuf);
+ }
+#ifdef SDEBUG
+ (void) fprintf(el->el_errfile, "\neventno = %d\n",
+ el->el_history.eventno);
+ (void) fprintf(el->el_errfile, "patlen = %d\n", el->el_search.patlen);
+ (void) fprintf(el->el_errfile, "patbuf = \"%s\"\n",
+ el->el_search.patbuf);
+ (void) fprintf(el->el_errfile, "cursor %d lastchar %d\n",
+ EL_CURSOR(el) - el->el_line.buffer,
+ el->el_line.lastchar - el->el_line.buffer);
+#endif
+}
+
+
+/* ce_inc_search():
+ * Emacs incremental search
+ */
+protected el_action_t
+ce_inc_search(EditLine *el, int dir)
+{
+ static const char STRfwd[] = {'f', 'w', 'd', '\0'},
+ STRbck[] = {'b', 'c', 'k', '\0'};
+ static char pchar = ':';/* ':' = normal, '?' = failed */
+ static char endcmd[2] = {'\0', '\0'};
+ char ch, *ocursor = el->el_line.cursor, oldpchar = pchar;
+ const char *cp;
+
+ el_action_t ret = CC_NORM;
+
+ int ohisteventno = el->el_history.eventno;
+ int oldpatlen = el->el_search.patlen;
+ int newdir = dir;
+ int done, redo;
+
+ if (el->el_line.lastchar + sizeof(STRfwd) / sizeof(char) + 2 +
+ el->el_search.patlen >= el->el_line.limit)
+ return (CC_ERROR);
+
+ for (;;) {
+
+ if (el->el_search.patlen == 0) { /* first round */
+ pchar = ':';
+#ifdef ANCHOR
+#define LEN 2
+ el->el_search.patbuf[el->el_search.patlen++] = '.';
+ el->el_search.patbuf[el->el_search.patlen++] = '*';
+#else
+#define LEN 0
+#endif
+ }
+ done = redo = 0;
+ *el->el_line.lastchar++ = '\n';
+ for (cp = (newdir == ED_SEARCH_PREV_HISTORY) ? STRbck : STRfwd;
+ *cp; *el->el_line.lastchar++ = *cp++)
+ continue;
+ *el->el_line.lastchar++ = pchar;
+ for (cp = &el->el_search.patbuf[LEN];
+ cp < &el->el_search.patbuf[el->el_search.patlen];
+ *el->el_line.lastchar++ = *cp++)
+ continue;
+ *el->el_line.lastchar = '\0';
+ re_refresh(el);
+
+ if (el_getc(el, &ch) != 1)
+ return (ed_end_of_file(el, 0));
+
+ switch (el->el_map.current[(unsigned char) ch]) {
+ case ED_INSERT:
+ case ED_DIGIT:
+ if (el->el_search.patlen >= EL_BUFSIZ - LEN)
+ term_beep(el);
+ else {
+ el->el_search.patbuf[el->el_search.patlen++] =
+ ch;
+ *el->el_line.lastchar++ = ch;
+ *el->el_line.lastchar = '\0';
+ re_refresh(el);
+ }
+ break;
+
+ case EM_INC_SEARCH_NEXT:
+ newdir = ED_SEARCH_NEXT_HISTORY;
+ redo++;
+ break;
+
+ case EM_INC_SEARCH_PREV:
+ newdir = ED_SEARCH_PREV_HISTORY;
+ redo++;
+ break;
+
+ case EM_DELETE_PREV_CHAR:
+ case ED_DELETE_PREV_CHAR:
+ if (el->el_search.patlen > LEN)
+ done++;
+ else
+ term_beep(el);
+ break;
+
+ default:
+ switch (ch) {
+ case 0007: /* ^G: Abort */
+ ret = CC_ERROR;
+ done++;
+ break;
+
+ case 0027: /* ^W: Append word */
+ /* No can do if globbing characters in pattern */
+ for (cp = &el->el_search.patbuf[LEN];; cp++)
+ if (cp >= &el->el_search.patbuf[
+ el->el_search.patlen]) {
+ el->el_line.cursor +=
+ el->el_search.patlen - LEN - 1;
+ cp = c__next_word(el->el_line.cursor,
+ el->el_line.lastchar, 1,
+ ce__isword);
+ while (el->el_line.cursor < cp &&
+ *el->el_line.cursor != '\n') {
+ if (el->el_search.patlen >=
+ EL_BUFSIZ - LEN) {
+ term_beep(el);
+ break;
+ }
+ el->el_search.patbuf[el->el_search.patlen++] =
+ *el->el_line.cursor;
+ *el->el_line.lastchar++ =
+ *el->el_line.cursor++;
+ }
+ el->el_line.cursor = ocursor;
+ *el->el_line.lastchar = '\0';
+ re_refresh(el);
+ break;
+ } else if (isglob(*cp)) {
+ term_beep(el);
+ break;
+ }
+ break;
+
+ default: /* Terminate and execute cmd */
+ endcmd[0] = ch;
+ el_push(el, endcmd);
+ /* FALLTHROUGH */
+
+ case 0033: /* ESC: Terminate */
+ ret = CC_REFRESH;
+ done++;
+ break;
+ }
+ break;
+ }
+
+ while (el->el_line.lastchar > el->el_line.buffer &&
+ *el->el_line.lastchar != '\n')
+ *el->el_line.lastchar-- = '\0';
+ *el->el_line.lastchar = '\0';
+
+ if (!done) {
+
+ /* Can't search if unmatched '[' */
+ for (cp = &el->el_search.patbuf[el->el_search.patlen-1],
+ ch = ']';
+ cp >= &el->el_search.patbuf[LEN];
+ cp--)
+ if (*cp == '[' || *cp == ']') {
+ ch = *cp;
+ break;
+ }
+ if (el->el_search.patlen > LEN && ch != '[') {
+ if (redo && newdir == dir) {
+ if (pchar == '?') { /* wrap around */
+ el->el_history.eventno =
+ newdir == ED_SEARCH_PREV_HISTORY ? 0 : 0x7fffffff;
+ if (hist_get(el) == CC_ERROR)
+ /* el->el_history.event
+ * no was fixed by
+ * first call */
+ (void) hist_get(el);
+ el->el_line.cursor = newdir ==
+ ED_SEARCH_PREV_HISTORY ?
+ el->el_line.lastchar :
+ el->el_line.buffer;
+ } else
+ el->el_line.cursor +=
+ newdir ==
+ ED_SEARCH_PREV_HISTORY ?
+ -1 : 1;
+ }
+#ifdef ANCHOR
+ el->el_search.patbuf[el->el_search.patlen++] =
+ '.';
+ el->el_search.patbuf[el->el_search.patlen++] =
+ '*';
+#endif
+ el->el_search.patbuf[el->el_search.patlen] =
+ '\0';
+ if (el->el_line.cursor < el->el_line.buffer ||
+ el->el_line.cursor > el->el_line.lastchar ||
+ (ret = ce_search_line(el, newdir))
+ == CC_ERROR) {
+ /* avoid c_setpat */
+ el->el_state.lastcmd =
+ (el_action_t) newdir;
+ ret = newdir == ED_SEARCH_PREV_HISTORY ?
+ ed_search_prev_history(el, 0) :
+ ed_search_next_history(el, 0);
+ if (ret != CC_ERROR) {
+ el->el_line.cursor = newdir ==
+ ED_SEARCH_PREV_HISTORY ?
+ el->el_line.lastchar :
+ el->el_line.buffer;
+ (void) ce_search_line(el,
+ newdir);
+ }
+ }
+ el->el_search.patlen -= LEN;
+ el->el_search.patbuf[el->el_search.patlen] =
+ '\0';
+ if (ret == CC_ERROR) {
+ term_beep(el);
+ if (el->el_history.eventno !=
+ ohisteventno) {
+ el->el_history.eventno =
+ ohisteventno;
+ if (hist_get(el) == CC_ERROR)
+ return (CC_ERROR);
+ }
+ el->el_line.cursor = ocursor;
+ pchar = '?';
+ } else {
+ pchar = ':';
+ }
+ }
+ ret = ce_inc_search(el, newdir);
+
+ if (ret == CC_ERROR && pchar == '?' && oldpchar == ':')
+ /*
+ * break abort of failed search at last
+ * non-failed
+ */
+ ret = CC_NORM;
+
+ }
+ if (ret == CC_NORM || (ret == CC_ERROR && oldpatlen == 0)) {
+ /* restore on normal return or error exit */
+ pchar = oldpchar;
+ el->el_search.patlen = oldpatlen;
+ if (el->el_history.eventno != ohisteventno) {
+ el->el_history.eventno = ohisteventno;
+ if (hist_get(el) == CC_ERROR)
+ return (CC_ERROR);
+ }
+ el->el_line.cursor = ocursor;
+ if (ret == CC_ERROR)
+ re_refresh(el);
+ }
+ if (done || ret != CC_NORM)
+ return (ret);
+ }
+}
+
+
+/* cv_search():
+ * Vi search.
+ */
+protected el_action_t
+cv_search(EditLine *el, int dir)
+{
+ char ch;
+ char tmpbuf[EL_BUFSIZ];
+ int tmplen;
+
+#ifdef ANCHOR
+ tmpbuf[0] = '.';
+ tmpbuf[1] = '*';
+#endif
+ tmplen = LEN;
+
+ el->el_search.patdir = dir;
+
+ tmplen = c_gets(el, &tmpbuf[LEN],
+ dir == ED_SEARCH_PREV_HISTORY ? "\n/" : "\n?" );
+ if (tmplen == -1)
+ return CC_REFRESH;
+
+ tmplen += LEN;
+ ch = tmpbuf[tmplen];
+ tmpbuf[tmplen] = '\0';
+
+ if (tmplen == LEN) {
+ /*
+ * Use the old pattern, but wild-card it.
+ */
+ if (el->el_search.patlen == 0) {
+ re_refresh(el);
+ return (CC_ERROR);
+ }
+#ifdef ANCHOR
+ if (el->el_search.patbuf[0] != '.' &&
+ el->el_search.patbuf[0] != '*') {
+ (void) strncpy(tmpbuf, el->el_search.patbuf,
+ sizeof(tmpbuf) - 1);
+ el->el_search.patbuf[0] = '.';
+ el->el_search.patbuf[1] = '*';
+ (void) strncpy(&el->el_search.patbuf[2], tmpbuf,
+ EL_BUFSIZ - 3);
+ el->el_search.patlen++;
+ el->el_search.patbuf[el->el_search.patlen++] = '.';
+ el->el_search.patbuf[el->el_search.patlen++] = '*';
+ el->el_search.patbuf[el->el_search.patlen] = '\0';
+ }
+#endif
+ } else {
+#ifdef ANCHOR
+ tmpbuf[tmplen++] = '.';
+ tmpbuf[tmplen++] = '*';
+#endif
+ tmpbuf[tmplen] = '\0';
+ (void) strncpy(el->el_search.patbuf, tmpbuf, EL_BUFSIZ - 1);
+ el->el_search.patlen = tmplen;
+ }
+ el->el_state.lastcmd = (el_action_t) dir; /* avoid c_setpat */
+ el->el_line.cursor = el->el_line.lastchar = el->el_line.buffer;
+ if ((dir == ED_SEARCH_PREV_HISTORY ? ed_search_prev_history(el, 0) :
+ ed_search_next_history(el, 0)) == CC_ERROR) {
+ re_refresh(el);
+ return (CC_ERROR);
+ }
+ if (ch == 0033) {
+ re_refresh(el);
+ return ed_newline(el, 0);
+ }
+ return (CC_REFRESH);
+}
+
+
+/* ce_search_line():
+ * Look for a pattern inside a line
+ */
+protected el_action_t
+ce_search_line(EditLine *el, int dir)
+{
+ char *cp = el->el_line.cursor;
+ char *pattern = el->el_search.patbuf;
+ char oc, *ocp;
+#ifdef ANCHOR
+ ocp = &pattern[1];
+ oc = *ocp;
+ *ocp = '^';
+#else
+ ocp = pattern;
+ oc = *ocp;
+#endif
+
+ if (dir == ED_SEARCH_PREV_HISTORY) {
+ for (; cp >= el->el_line.buffer; cp--) {
+ if (el_match(cp, ocp)) {
+ *ocp = oc;
+ el->el_line.cursor = cp;
+ return (CC_NORM);
+ }
+ }
+ *ocp = oc;
+ return (CC_ERROR);
+ } else {
+ for (; *cp != '\0' && cp < el->el_line.limit; cp++) {
+ if (el_match(cp, ocp)) {
+ *ocp = oc;
+ el->el_line.cursor = cp;
+ return (CC_NORM);
+ }
+ }
+ *ocp = oc;
+ return (CC_ERROR);
+ }
+}
+
+
+/* cv_repeat_srch():
+ * Vi repeat search
+ */
+protected el_action_t
+cv_repeat_srch(EditLine *el, int c)
+{
+
+#ifdef SDEBUG
+ (void) fprintf(el->el_errfile, "dir %d patlen %d patbuf %s\n",
+ c, el->el_search.patlen, el->el_search.patbuf);
+#endif
+
+ el->el_state.lastcmd = (el_action_t) c; /* Hack to stop c_setpat */
+ el->el_line.lastchar = el->el_line.buffer;
+
+ switch (c) {
+ case ED_SEARCH_NEXT_HISTORY:
+ return (ed_search_next_history(el, 0));
+ case ED_SEARCH_PREV_HISTORY:
+ return (ed_search_prev_history(el, 0));
+ default:
+ return (CC_ERROR);
+ }
+}
+
+
+/* cv_csearch():
+ * Vi character search
+ */
+protected el_action_t
+cv_csearch(EditLine *el, int direction, int ch, int count, int tflag)
+{
+ char *cp;
+
+ if (ch == 0)
+ return CC_ERROR;
+
+ if (ch == -1) {
+ char c;
+ if (el_getc(el, &c) != 1)
+ return ed_end_of_file(el, 0);
+ ch = c;
+ }
+
+ /* Save for ';' and ',' commands */
+ el->el_search.chacha = ch;
+ el->el_search.chadir = direction;
+ el->el_search.chatflg = tflag;
+
+ cp = el->el_line.cursor;
+ while (count--) {
+ if (*cp == ch)
+ cp += direction;
+ for (;;cp += direction) {
+ if (cp >= el->el_line.lastchar)
+ return CC_ERROR;
+ if (cp < el->el_line.buffer)
+ return CC_ERROR;
+ if (*cp == ch)
+ break;
+ }
+ }
+
+ if (tflag)
+ cp -= direction;
+
+ el->el_line.cursor = cp;
+
+ if (el->el_chared.c_vcmd.action != NOP) {
+ if (direction > 0)
+ el->el_line.cursor++;
+ cv_delfini(el);
+ return CC_REFRESH;
+ }
+ return CC_CURSOR;
+}
diff --git a/lib/libedit/search.h b/lib/libedit/search.h
new file mode 100644
index 0000000..725af7c
--- /dev/null
+++ b/lib/libedit/search.h
@@ -0,0 +1,66 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell 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.
+ *
+ * @(#)search.h 8.1 (Berkeley) 6/4/93
+ * $NetBSD: search.h,v 1.8 2003/10/18 23:27:36 christos Exp $
+ * $FreeBSD$
+ */
+
+/*
+ * el.search.h: Line and history searching utilities
+ */
+#ifndef _h_el_search
+#define _h_el_search
+
+#include "histedit.h"
+
+typedef struct el_search_t {
+ char *patbuf; /* The pattern buffer */
+ size_t patlen; /* Length of the pattern buffer */
+ int patdir; /* Direction of the last search */
+ int chadir; /* Character search direction */
+ char chacha; /* Character we are looking for */
+ char chatflg; /* 0 if f, 1 if t */
+} el_search_t;
+
+
+protected int el_match(const char *, const char *);
+protected int search_init(EditLine *);
+protected void search_end(EditLine *);
+protected int c_hmatch(EditLine *, const char *);
+protected void c_setpat(EditLine *);
+protected el_action_t ce_inc_search(EditLine *, int);
+protected el_action_t cv_search(EditLine *, int);
+protected el_action_t ce_search_line(EditLine *, int);
+protected el_action_t cv_repeat_srch(EditLine *, int);
+protected el_action_t cv_csearch(EditLine *, int, int, int, int);
+
+#endif /* _h_el_search */
diff --git a/lib/libedit/sig.c b/lib/libedit/sig.c
new file mode 100644
index 0000000..a895aea
--- /dev/null
+++ b/lib/libedit/sig.c
@@ -0,0 +1,192 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell 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.
+ *
+ * $NetBSD: sig.c,v 1.11 2003/08/07 16:44:33 agc Exp $
+ */
+
+#if !defined(lint) && !defined(SCCSID)
+static char sccsid[] = "@(#)sig.c 8.1 (Berkeley) 6/4/93";
+#endif /* not lint && not SCCSID */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * sig.c: Signal handling stuff.
+ * our policy is to trap all signals, set a good state
+ * and pass the ball to our caller.
+ */
+#include "sys.h"
+#include "el.h"
+#include <stdlib.h>
+
+private EditLine *sel = NULL;
+
+private const int sighdl[] = {
+#define _DO(a) (a),
+ ALLSIGS
+#undef _DO
+ - 1
+};
+
+private void sig_handler(int);
+
+/* sig_handler():
+ * This is the handler called for all signals
+ * XXX: we cannot pass any data so we just store the old editline
+ * state in a private variable
+ */
+private void
+sig_handler(int signo)
+{
+ int i;
+ sigset_t nset, oset;
+
+ (void) sigemptyset(&nset);
+ (void) sigaddset(&nset, signo);
+ (void) sigprocmask(SIG_BLOCK, &nset, &oset);
+
+ switch (signo) {
+ case SIGCONT:
+ tty_rawmode(sel);
+ if (ed_redisplay(sel, 0) == CC_REFRESH)
+ re_refresh(sel);
+ term__flush();
+ break;
+
+ case SIGWINCH:
+ el_resize(sel);
+ break;
+
+ default:
+ tty_cookedmode(sel);
+ break;
+ }
+
+ for (i = 0; sighdl[i] != -1; i++)
+ if (signo == sighdl[i])
+ break;
+
+ (void) signal(signo, sel->el_signal[i]);
+ (void) sigprocmask(SIG_SETMASK, &oset, NULL);
+ (void) kill(0, signo);
+}
+
+
+/* sig_init():
+ * Initialize all signal stuff
+ */
+protected int
+sig_init(EditLine *el)
+{
+ int i;
+ sigset_t nset, oset;
+
+ (void) sigemptyset(&nset);
+#define _DO(a) (void) sigaddset(&nset, a);
+ ALLSIGS
+#undef _DO
+ (void) sigprocmask(SIG_BLOCK, &nset, &oset);
+
+#define SIGSIZE (sizeof(sighdl) / sizeof(sighdl[0]) * sizeof(el_signalhandler_t))
+
+ el->el_signal = (el_signalhandler_t *) el_malloc(SIGSIZE);
+ if (el->el_signal == NULL)
+ return (-1);
+ for (i = 0; sighdl[i] != -1; i++)
+ el->el_signal[i] = SIG_ERR;
+
+ (void) sigprocmask(SIG_SETMASK, &oset, NULL);
+
+ return (0);
+}
+
+
+/* sig_end():
+ * Clear all signal stuff
+ */
+protected void
+sig_end(EditLine *el)
+{
+
+ el_free((ptr_t) el->el_signal);
+ el->el_signal = NULL;
+}
+
+
+/* sig_set():
+ * set all the signal handlers
+ */
+protected void
+sig_set(EditLine *el)
+{
+ int i;
+ sigset_t nset, oset;
+
+ (void) sigemptyset(&nset);
+#define _DO(a) (void) sigaddset(&nset, a);
+ ALLSIGS
+#undef _DO
+ (void) sigprocmask(SIG_BLOCK, &nset, &oset);
+
+ for (i = 0; sighdl[i] != -1; i++) {
+ el_signalhandler_t s;
+ /* This could happen if we get interrupted */
+ if ((s = signal(sighdl[i], sig_handler)) != sig_handler)
+ el->el_signal[i] = s;
+ }
+ sel = el;
+ (void) sigprocmask(SIG_SETMASK, &oset, NULL);
+}
+
+
+/* sig_clr():
+ * clear all the signal handlers
+ */
+protected void
+sig_clr(EditLine *el)
+{
+ int i;
+ sigset_t nset, oset;
+
+ (void) sigemptyset(&nset);
+#define _DO(a) (void) sigaddset(&nset, a);
+ ALLSIGS
+#undef _DO
+ (void) sigprocmask(SIG_BLOCK, &nset, &oset);
+
+ for (i = 0; sighdl[i] != -1; i++)
+ if (el->el_signal[i] != SIG_ERR)
+ (void) signal(sighdl[i], el->el_signal[i]);
+
+ sel = NULL; /* we are going to die if the handler is
+ * called */
+ (void) sigprocmask(SIG_SETMASK, &oset, NULL);
+}
diff --git a/lib/libedit/sig.h b/lib/libedit/sig.h
new file mode 100644
index 0000000..b1ce14b
--- /dev/null
+++ b/lib/libedit/sig.h
@@ -0,0 +1,69 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell 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.
+ *
+ * @(#)sig.h 8.1 (Berkeley) 6/4/93
+ * $NetBSD: sig.h,v 1.5 2003/08/07 16:44:33 agc Exp $
+ * $FreeBSD$
+ */
+
+/*
+ * el.sig.h: Signal handling functions
+ */
+#ifndef _h_el_sig
+#define _h_el_sig
+
+#include <signal.h>
+
+#include "histedit.h"
+
+/*
+ * Define here all the signals we are going to handle
+ * The _DO macro is used to iterate in the source code
+ */
+#define ALLSIGS \
+ _DO(SIGINT) \
+ _DO(SIGTSTP) \
+ _DO(SIGSTOP) \
+ _DO(SIGQUIT) \
+ _DO(SIGHUP) \
+ _DO(SIGTERM) \
+ _DO(SIGCONT) \
+ _DO(SIGWINCH)
+
+typedef void (*el_signalhandler_t)(int);
+typedef el_signalhandler_t *el_signal_t;
+
+protected void sig_end(EditLine*);
+protected int sig_init(EditLine*);
+protected void sig_set(EditLine*);
+protected void sig_clr(EditLine*);
+
+#endif /* _h_el_sig */
diff --git a/lib/libedit/sys.h b/lib/libedit/sys.h
new file mode 100644
index 0000000..9b1f040
--- /dev/null
+++ b/lib/libedit/sys.h
@@ -0,0 +1,109 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell 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.
+ *
+ * @(#)sys.h 8.1 (Berkeley) 6/4/93
+ * $NetBSD: sys.h,v 1.9 2004/01/17 17:57:40 christos Exp $
+ * $FreeBSD$
+ */
+
+/*
+ * sys.h: Put all the stupid compiler and system dependencies here...
+ */
+#ifndef _h_sys
+#define _h_sys
+
+#include <sys/cdefs.h>
+
+#ifndef public
+# define public /* Externally visible functions/variables */
+#endif
+
+#ifndef private
+# define private static /* Always hidden internals */
+#endif
+
+#ifndef protected
+# define protected /* Redefined from elsewhere to "static" */
+ /* When we want to hide everything */
+#endif
+
+#ifndef _PTR_T
+# define _PTR_T
+typedef void *ptr_t;
+#endif
+
+#ifndef _IOCTL_T
+# define _IOCTL_T
+typedef void *ioctl_t;
+#endif
+
+#include <stdio.h>
+
+#define REGEX /* Use POSIX.2 regular expression functions */
+#undef REGEXP /* Use UNIX V8 regular expression functions */
+
+#ifdef notdef
+# undef REGEX
+# undef REGEXP
+# include <malloc.h>
+# ifdef __GNUC__
+/*
+ * Broken hdrs.
+ */
+extern int tgetent(const char *bp, char *name);
+extern int tgetflag(const char *id);
+extern int tgetnum(const char *id);
+extern char *tgetstr(const char *id, char **area);
+extern char *tgoto(const char *cap, int col, int row);
+extern int tputs(const char *str, int affcnt, int (*putc)(int));
+extern char *getenv(const char *);
+extern int fprintf(FILE *, const char *, ...);
+extern int sigsetmask(int);
+extern int sigblock(int);
+extern int fputc(int, FILE *);
+extern int fgetc(FILE *);
+extern int fflush(FILE *);
+extern int tolower(int);
+extern int toupper(int);
+extern int errno, sys_nerr;
+extern char *sys_errlist[];
+extern void perror(const char *);
+# include <string.h>
+# define strerror(e) sys_errlist[e]
+# endif
+# ifdef SABER
+extern ptr_t memcpy(ptr_t, const ptr_t, size_t);
+extern ptr_t memset(ptr_t, int, size_t);
+# endif
+extern char *fgetline(FILE *, int *);
+#endif
+
+#endif /* _h_sys */
diff --git a/lib/libedit/term.c b/lib/libedit/term.c
new file mode 100644
index 0000000..6cd0e14
--- /dev/null
+++ b/lib/libedit/term.c
@@ -0,0 +1,1588 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell 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.
+ *
+ * $NetBSD: term.c,v 1.41 2005/08/08 14:05:37 christos Exp $
+ */
+
+#if !defined(lint) && !defined(SCCSID)
+static char sccsid[] = "@(#)term.c 8.2 (Berkeley) 4/30/95";
+#endif /* not lint && not SCCSID */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * term.c: Editor/termcap-curses interface
+ * We have to declare a static variable here, since the
+ * termcap putchar routine does not take an argument!
+ */
+#include <stdio.h>
+#include <signal.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <termcap.h>
+#include <curses.h>
+#include <ncurses.h>
+#include <term.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+
+#include "el.h"
+
+/*
+ * IMPORTANT NOTE: these routines are allowed to look at the current screen
+ * and the current possition assuming that it is correct. If this is not
+ * true, then the update will be WRONG! This is (should be) a valid
+ * assumption...
+ */
+
+#define TC_BUFSIZE 2048
+
+#define GoodStr(a) (el->el_term.t_str[a] != NULL && \
+ el->el_term.t_str[a][0] != '\0')
+#define Str(a) el->el_term.t_str[a]
+#define Val(a) el->el_term.t_val[a]
+
+#ifdef notdef
+private const struct {
+ const char *b_name;
+ int b_rate;
+} baud_rate[] = {
+#ifdef B0
+ { "0", B0 },
+#endif
+#ifdef B50
+ { "50", B50 },
+#endif
+#ifdef B75
+ { "75", B75 },
+#endif
+#ifdef B110
+ { "110", B110 },
+#endif
+#ifdef B134
+ { "134", B134 },
+#endif
+#ifdef B150
+ { "150", B150 },
+#endif
+#ifdef B200
+ { "200", B200 },
+#endif
+#ifdef B300
+ { "300", B300 },
+#endif
+#ifdef B600
+ { "600", B600 },
+#endif
+#ifdef B900
+ { "900", B900 },
+#endif
+#ifdef B1200
+ { "1200", B1200 },
+#endif
+#ifdef B1800
+ { "1800", B1800 },
+#endif
+#ifdef B2400
+ { "2400", B2400 },
+#endif
+#ifdef B3600
+ { "3600", B3600 },
+#endif
+#ifdef B4800
+ { "4800", B4800 },
+#endif
+#ifdef B7200
+ { "7200", B7200 },
+#endif
+#ifdef B9600
+ { "9600", B9600 },
+#endif
+#ifdef EXTA
+ { "19200", EXTA },
+#endif
+#ifdef B19200
+ { "19200", B19200 },
+#endif
+#ifdef EXTB
+ { "38400", EXTB },
+#endif
+#ifdef B38400
+ { "38400", B38400 },
+#endif
+ { NULL, 0 }
+};
+#endif
+
+private const struct termcapstr {
+ const char *name;
+ const char *long_name;
+} tstr[] = {
+#define T_al 0
+ { "al", "add new blank line" },
+#define T_bl 1
+ { "bl", "audible bell" },
+#define T_cd 2
+ { "cd", "clear to bottom" },
+#define T_ce 3
+ { "ce", "clear to end of line" },
+#define T_ch 4
+ { "ch", "cursor to horiz pos" },
+#define T_cl 5
+ { "cl", "clear screen" },
+#define T_dc 6
+ { "dc", "delete a character" },
+#define T_dl 7
+ { "dl", "delete a line" },
+#define T_dm 8
+ { "dm", "start delete mode" },
+#define T_ed 9
+ { "ed", "end delete mode" },
+#define T_ei 10
+ { "ei", "end insert mode" },
+#define T_fs 11
+ { "fs", "cursor from status line" },
+#define T_ho 12
+ { "ho", "home cursor" },
+#define T_ic 13
+ { "ic", "insert character" },
+#define T_im 14
+ { "im", "start insert mode" },
+#define T_ip 15
+ { "ip", "insert padding" },
+#define T_kd 16
+ { "kd", "sends cursor down" },
+#define T_kl 17
+ { "kl", "sends cursor left" },
+#define T_kr 18
+ { "kr", "sends cursor right" },
+#define T_ku 19
+ { "ku", "sends cursor up" },
+#define T_md 20
+ { "md", "begin bold" },
+#define T_me 21
+ { "me", "end attributes" },
+#define T_nd 22
+ { "nd", "non destructive space" },
+#define T_se 23
+ { "se", "end standout" },
+#define T_so 24
+ { "so", "begin standout" },
+#define T_ts 25
+ { "ts", "cursor to status line" },
+#define T_up 26
+ { "up", "cursor up one" },
+#define T_us 27
+ { "us", "begin underline" },
+#define T_ue 28
+ { "ue", "end underline" },
+#define T_vb 29
+ { "vb", "visible bell" },
+#define T_DC 30
+ { "DC", "delete multiple chars" },
+#define T_DO 31
+ { "DO", "cursor down multiple" },
+#define T_IC 32
+ { "IC", "insert multiple chars" },
+#define T_LE 33
+ { "LE", "cursor left multiple" },
+#define T_RI 34
+ { "RI", "cursor right multiple" },
+#define T_UP 35
+ { "UP", "cursor up multiple" },
+#define T_kh 36
+ { "kh", "send cursor home" },
+#define T_at7 37
+ { "@7", "send cursor end" },
+#define T_str 38
+ { NULL, NULL }
+};
+
+private const struct termcapval {
+ const char *name;
+ const char *long_name;
+} tval[] = {
+#define T_am 0
+ { "am", "has automatic margins" },
+#define T_pt 1
+ { "pt", "has physical tabs" },
+#define T_li 2
+ { "li", "Number of lines" },
+#define T_co 3
+ { "co", "Number of columns" },
+#define T_km 4
+ { "km", "Has meta key" },
+#define T_xt 5
+ { "xt", "Tab chars destructive" },
+#define T_xn 6
+ { "xn", "newline ignored at right margin" },
+#define T_MT 7
+ { "MT", "Has meta key" }, /* XXX? */
+#define T_val 8
+ { NULL, NULL, }
+};
+/* do two or more of the attributes use me */
+
+private void term_setflags(EditLine *);
+private int term_rebuffer_display(EditLine *);
+private void term_free_display(EditLine *);
+private int term_alloc_display(EditLine *);
+private void term_alloc(EditLine *, const struct termcapstr *, const char *);
+private void term_init_arrow(EditLine *);
+private void term_reset_arrow(EditLine *);
+
+
+private FILE *term_outfile = NULL; /* XXX: How do we fix that? */
+
+
+/* term_setflags():
+ * Set the terminal capability flags
+ */
+private void
+term_setflags(EditLine *el)
+{
+ EL_FLAGS = 0;
+ if (el->el_tty.t_tabs)
+ EL_FLAGS |= (Val(T_pt) && !Val(T_xt)) ? TERM_CAN_TAB : 0;
+
+ EL_FLAGS |= (Val(T_km) || Val(T_MT)) ? TERM_HAS_META : 0;
+ EL_FLAGS |= GoodStr(T_ce) ? TERM_CAN_CEOL : 0;
+ EL_FLAGS |= (GoodStr(T_dc) || GoodStr(T_DC)) ? TERM_CAN_DELETE : 0;
+ EL_FLAGS |= (GoodStr(T_im) || GoodStr(T_ic) || GoodStr(T_IC)) ?
+ TERM_CAN_INSERT : 0;
+ EL_FLAGS |= (GoodStr(T_up) || GoodStr(T_UP)) ? TERM_CAN_UP : 0;
+ EL_FLAGS |= Val(T_am) ? TERM_HAS_AUTO_MARGINS : 0;
+ EL_FLAGS |= Val(T_xn) ? TERM_HAS_MAGIC_MARGINS : 0;
+
+ if (GoodStr(T_me) && GoodStr(T_ue))
+ EL_FLAGS |= (strcmp(Str(T_me), Str(T_ue)) == 0) ?
+ TERM_CAN_ME : 0;
+ else
+ EL_FLAGS &= ~TERM_CAN_ME;
+ if (GoodStr(T_me) && GoodStr(T_se))
+ EL_FLAGS |= (strcmp(Str(T_me), Str(T_se)) == 0) ?
+ TERM_CAN_ME : 0;
+
+
+#ifdef DEBUG_SCREEN
+ if (!EL_CAN_UP) {
+ (void) fprintf(el->el_errfile,
+ "WARNING: Your terminal cannot move up.\n");
+ (void) fprintf(el->el_errfile,
+ "Editing may be odd for long lines.\n");
+ }
+ if (!EL_CAN_CEOL)
+ (void) fprintf(el->el_errfile, "no clear EOL capability.\n");
+ if (!EL_CAN_DELETE)
+ (void) fprintf(el->el_errfile, "no delete char capability.\n");
+ if (!EL_CAN_INSERT)
+ (void) fprintf(el->el_errfile, "no insert char capability.\n");
+#endif /* DEBUG_SCREEN */
+}
+
+
+/* term_init():
+ * Initialize the terminal stuff
+ */
+protected int
+term_init(EditLine *el)
+{
+
+ el->el_term.t_buf = (char *) el_malloc(TC_BUFSIZE);
+ if (el->el_term.t_buf == NULL)
+ return (-1);
+ el->el_term.t_cap = (char *) el_malloc(TC_BUFSIZE);
+ if (el->el_term.t_cap == NULL)
+ return (-1);
+ el->el_term.t_fkey = (fkey_t *) el_malloc(A_K_NKEYS * sizeof(fkey_t));
+ if (el->el_term.t_fkey == NULL)
+ return (-1);
+ el->el_term.t_loc = 0;
+ el->el_term.t_str = (char **) el_malloc(T_str * sizeof(char *));
+ if (el->el_term.t_str == NULL)
+ return (-1);
+ (void) memset(el->el_term.t_str, 0, T_str * sizeof(char *));
+ el->el_term.t_val = (int *) el_malloc(T_val * sizeof(int));
+ if (el->el_term.t_val == NULL)
+ return (-1);
+ (void) memset(el->el_term.t_val, 0, T_val * sizeof(int));
+ term_outfile = el->el_outfile;
+ term_init_arrow(el);
+ (void) term_set(el, NULL);
+ return (0);
+}
+
+/* term_end():
+ * Clean up the terminal stuff
+ */
+protected void
+term_end(EditLine *el)
+{
+
+ el_free((ptr_t) el->el_term.t_buf);
+ el->el_term.t_buf = NULL;
+ el_free((ptr_t) el->el_term.t_cap);
+ el->el_term.t_cap = NULL;
+ el->el_term.t_loc = 0;
+ el_free((ptr_t) el->el_term.t_str);
+ el->el_term.t_str = NULL;
+ el_free((ptr_t) el->el_term.t_val);
+ el->el_term.t_val = NULL;
+ el_free((ptr_t) el->el_term.t_fkey);
+ el->el_term.t_fkey = NULL;
+ term_free_display(el);
+}
+
+
+/* term_alloc():
+ * Maintain a string pool for termcap strings
+ */
+private void
+term_alloc(EditLine *el, const struct termcapstr *t, const char *cap)
+{
+ char termbuf[TC_BUFSIZE];
+ int tlen, clen;
+ char **tlist = el->el_term.t_str;
+ char **tmp, **str = &tlist[t - tstr];
+
+ if (cap == NULL || *cap == '\0') {
+ *str = NULL;
+ return;
+ } else
+ clen = strlen(cap);
+
+ tlen = *str == NULL ? 0 : strlen(*str);
+
+ /*
+ * New string is shorter; no need to allocate space
+ */
+ if (clen <= tlen) {
+ (void) strcpy(*str, cap); /* XXX strcpy is safe */
+ return;
+ }
+ /*
+ * New string is longer; see if we have enough space to append
+ */
+ if (el->el_term.t_loc + 3 < TC_BUFSIZE) {
+ /* XXX strcpy is safe */
+ (void) strcpy(*str = &el->el_term.t_buf[el->el_term.t_loc],
+ cap);
+ el->el_term.t_loc += clen + 1; /* one for \0 */
+ return;
+ }
+ /*
+ * Compact our buffer; no need to check compaction, cause we know it
+ * fits...
+ */
+ tlen = 0;
+ for (tmp = tlist; tmp < &tlist[T_str]; tmp++)
+ if (*tmp != NULL && *tmp != '\0' && *tmp != *str) {
+ char *ptr;
+
+ for (ptr = *tmp; *ptr != '\0'; termbuf[tlen++] = *ptr++)
+ continue;
+ termbuf[tlen++] = '\0';
+ }
+ memcpy(el->el_term.t_buf, termbuf, TC_BUFSIZE);
+ el->el_term.t_loc = tlen;
+ if (el->el_term.t_loc + 3 >= TC_BUFSIZE) {
+ (void) fprintf(el->el_errfile,
+ "Out of termcap string space.\n");
+ return;
+ }
+ /* XXX strcpy is safe */
+ (void) strcpy(*str = &el->el_term.t_buf[el->el_term.t_loc], cap);
+ el->el_term.t_loc += clen + 1; /* one for \0 */
+ return;
+}
+
+
+/* term_rebuffer_display():
+ * Rebuffer the display after the screen changed size
+ */
+private int
+term_rebuffer_display(EditLine *el)
+{
+ coord_t *c = &el->el_term.t_size;
+
+ term_free_display(el);
+
+ c->h = Val(T_co);
+ c->v = Val(T_li);
+
+ if (term_alloc_display(el) == -1)
+ return (-1);
+ return (0);
+}
+
+
+/* term_alloc_display():
+ * Allocate a new display.
+ */
+private int
+term_alloc_display(EditLine *el)
+{
+ int i;
+ char **b;
+ coord_t *c = &el->el_term.t_size;
+
+ b = (char **) el_malloc((size_t) (sizeof(char *) * (c->v + 1)));
+ if (b == NULL)
+ return (-1);
+ for (i = 0; i < c->v; i++) {
+ b[i] = (char *) el_malloc((size_t) (sizeof(char) * (c->h + 1)));
+ if (b[i] == NULL)
+ return (-1);
+ }
+ b[c->v] = NULL;
+ el->el_display = b;
+
+ b = (char **) el_malloc((size_t) (sizeof(char *) * (c->v + 1)));
+ if (b == NULL)
+ return (-1);
+ for (i = 0; i < c->v; i++) {
+ b[i] = (char *) el_malloc((size_t) (sizeof(char) * (c->h + 1)));
+ if (b[i] == NULL)
+ return (-1);
+ }
+ b[c->v] = NULL;
+ el->el_vdisplay = b;
+ return (0);
+}
+
+
+/* term_free_display():
+ * Free the display buffers
+ */
+private void
+term_free_display(EditLine *el)
+{
+ char **b;
+ char **bufp;
+
+ b = el->el_display;
+ el->el_display = NULL;
+ if (b != NULL) {
+ for (bufp = b; *bufp != NULL; bufp++)
+ el_free((ptr_t) * bufp);
+ el_free((ptr_t) b);
+ }
+ b = el->el_vdisplay;
+ el->el_vdisplay = NULL;
+ if (b != NULL) {
+ for (bufp = b; *bufp != NULL; bufp++)
+ el_free((ptr_t) * bufp);
+ el_free((ptr_t) b);
+ }
+}
+
+
+/* term_move_to_line():
+ * move to line <where> (first line == 0)
+ * as efficiently as possible
+ */
+protected void
+term_move_to_line(EditLine *el, int where)
+{
+ int del;
+
+ if (where == el->el_cursor.v)
+ return;
+
+ if (where > el->el_term.t_size.v) {
+#ifdef DEBUG_SCREEN
+ (void) fprintf(el->el_errfile,
+ "term_move_to_line: where is ridiculous: %d\r\n", where);
+#endif /* DEBUG_SCREEN */
+ return;
+ }
+ if ((del = where - el->el_cursor.v) > 0) {
+ while (del > 0) {
+ if (EL_HAS_AUTO_MARGINS &&
+ el->el_display[el->el_cursor.v][0] != '\0') {
+ /* move without newline */
+ term_move_to_char(el, el->el_term.t_size.h - 1);
+ term_overwrite(el,
+ &el->el_display[el->el_cursor.v][el->el_cursor.h],
+ 1);
+ /* updates Cursor */
+ del--;
+ } else {
+ if ((del > 1) && GoodStr(T_DO)) {
+ (void) tputs(tgoto(Str(T_DO), del, del),
+ del, term__putc);
+ del = 0;
+ } else {
+ for (; del > 0; del--)
+ term__putc('\n');
+ /* because the \n will become \r\n */
+ el->el_cursor.h = 0;
+ }
+ }
+ }
+ } else { /* del < 0 */
+ if (GoodStr(T_UP) && (-del > 1 || !GoodStr(T_up)))
+ (void) tputs(tgoto(Str(T_UP), -del, -del), -del,
+ term__putc);
+ else {
+ if (GoodStr(T_up))
+ for (; del < 0; del++)
+ (void) tputs(Str(T_up), 1, term__putc);
+ }
+ }
+ el->el_cursor.v = where;/* now where is here */
+}
+
+
+/* term_move_to_char():
+ * Move to the character position specified
+ */
+protected void
+term_move_to_char(EditLine *el, int where)
+{
+ int del, i;
+
+mc_again:
+ if (where == el->el_cursor.h)
+ return;
+
+ if (where > el->el_term.t_size.h) {
+#ifdef DEBUG_SCREEN
+ (void) fprintf(el->el_errfile,
+ "term_move_to_char: where is riduculous: %d\r\n", where);
+#endif /* DEBUG_SCREEN */
+ return;
+ }
+ if (!where) { /* if where is first column */
+ term__putc('\r'); /* do a CR */
+ el->el_cursor.h = 0;
+ return;
+ }
+ del = where - el->el_cursor.h;
+
+ if ((del < -4 || del > 4) && GoodStr(T_ch))
+ /* go there directly */
+ (void) tputs(tgoto(Str(T_ch), where, where), where, term__putc);
+ else {
+ if (del > 0) { /* moving forward */
+ if ((del > 4) && GoodStr(T_RI))
+ (void) tputs(tgoto(Str(T_RI), del, del),
+ del, term__putc);
+ else {
+ /* if I can do tabs, use them */
+ if (EL_CAN_TAB) {
+ if ((el->el_cursor.h & 0370) !=
+ (where & 0370)) {
+ /* if not within tab stop */
+ for (i =
+ (el->el_cursor.h & 0370);
+ i < (where & 0370);
+ i += 8)
+ term__putc('\t');
+ /* then tab over */
+ el->el_cursor.h = where & 0370;
+ }
+ }
+ /*
+ * it's usually cheaper to just write the
+ * chars, so we do.
+ */
+ /*
+ * NOTE THAT term_overwrite() WILL CHANGE
+ * el->el_cursor.h!!!
+ */
+ term_overwrite(el,
+ &el->el_display[el->el_cursor.v][el->el_cursor.h],
+ where - el->el_cursor.h);
+
+ }
+ } else { /* del < 0 := moving backward */
+ if ((-del > 4) && GoodStr(T_LE))
+ (void) tputs(tgoto(Str(T_LE), -del, -del),
+ -del, term__putc);
+ else { /* can't go directly there */
+ /*
+ * if the "cost" is greater than the "cost"
+ * from col 0
+ */
+ if (EL_CAN_TAB ?
+ ((unsigned int)-del >
+ (((unsigned int) where >> 3) +
+ (where & 07)))
+ : (-del > where)) {
+ term__putc('\r'); /* do a CR */
+ el->el_cursor.h = 0;
+ goto mc_again; /* and try again */
+ }
+ for (i = 0; i < -del; i++)
+ term__putc('\b');
+ }
+ }
+ }
+ el->el_cursor.h = where; /* now where is here */
+}
+
+
+/* term_overwrite():
+ * Overstrike num characters
+ */
+protected void
+term_overwrite(EditLine *el, const char *cp, int n)
+{
+ if (n <= 0)
+ return; /* catch bugs */
+
+ if (n > el->el_term.t_size.h) {
+#ifdef DEBUG_SCREEN
+ (void) fprintf(el->el_errfile,
+ "term_overwrite: n is riduculous: %d\r\n", n);
+#endif /* DEBUG_SCREEN */
+ return;
+ }
+ do {
+ term__putc(*cp++);
+ el->el_cursor.h++;
+ } while (--n);
+
+ if (el->el_cursor.h >= el->el_term.t_size.h) { /* wrap? */
+ if (EL_HAS_AUTO_MARGINS) { /* yes */
+ el->el_cursor.h = 0;
+ el->el_cursor.v++;
+ if (EL_HAS_MAGIC_MARGINS) {
+ /* force the wrap to avoid the "magic"
+ * situation */
+ char c;
+ if ((c = el->el_display[el->el_cursor.v][el->el_cursor.h])
+ != '\0')
+ term_overwrite(el, &c, 1);
+ else
+ term__putc(' ');
+ el->el_cursor.h = 1;
+ }
+ } else /* no wrap, but cursor stays on screen */
+ el->el_cursor.h = el->el_term.t_size.h;
+ }
+}
+
+
+/* term_deletechars():
+ * Delete num characters
+ */
+protected void
+term_deletechars(EditLine *el, int num)
+{
+ if (num <= 0)
+ return;
+
+ if (!EL_CAN_DELETE) {
+#ifdef DEBUG_EDIT
+ (void) fprintf(el->el_errfile, " ERROR: cannot delete \n");
+#endif /* DEBUG_EDIT */
+ return;
+ }
+ if (num > el->el_term.t_size.h) {
+#ifdef DEBUG_SCREEN
+ (void) fprintf(el->el_errfile,
+ "term_deletechars: num is riduculous: %d\r\n", num);
+#endif /* DEBUG_SCREEN */
+ return;
+ }
+ if (GoodStr(T_DC)) /* if I have multiple delete */
+ if ((num > 1) || !GoodStr(T_dc)) { /* if dc would be more
+ * expen. */
+ (void) tputs(tgoto(Str(T_DC), num, num),
+ num, term__putc);
+ return;
+ }
+ if (GoodStr(T_dm)) /* if I have delete mode */
+ (void) tputs(Str(T_dm), 1, term__putc);
+
+ if (GoodStr(T_dc)) /* else do one at a time */
+ while (num--)
+ (void) tputs(Str(T_dc), 1, term__putc);
+
+ if (GoodStr(T_ed)) /* if I have delete mode */
+ (void) tputs(Str(T_ed), 1, term__putc);
+}
+
+
+/* term_insertwrite():
+ * Puts terminal in insert character mode or inserts num
+ * characters in the line
+ */
+protected void
+term_insertwrite(EditLine *el, char *cp, int num)
+{
+ if (num <= 0)
+ return;
+ if (!EL_CAN_INSERT) {
+#ifdef DEBUG_EDIT
+ (void) fprintf(el->el_errfile, " ERROR: cannot insert \n");
+#endif /* DEBUG_EDIT */
+ return;
+ }
+ if (num > el->el_term.t_size.h) {
+#ifdef DEBUG_SCREEN
+ (void) fprintf(el->el_errfile,
+ "StartInsert: num is riduculous: %d\r\n", num);
+#endif /* DEBUG_SCREEN */
+ return;
+ }
+ if (GoodStr(T_IC)) /* if I have multiple insert */
+ if ((num > 1) || !GoodStr(T_ic)) {
+ /* if ic would be more expensive */
+ (void) tputs(tgoto(Str(T_IC), num, num),
+ num, term__putc);
+ term_overwrite(el, cp, num);
+ /* this updates el_cursor.h */
+ return;
+ }
+ if (GoodStr(T_im) && GoodStr(T_ei)) { /* if I have insert mode */
+ (void) tputs(Str(T_im), 1, term__putc);
+
+ el->el_cursor.h += num;
+ do
+ term__putc(*cp++);
+ while (--num);
+
+ if (GoodStr(T_ip)) /* have to make num chars insert */
+ (void) tputs(Str(T_ip), 1, term__putc);
+
+ (void) tputs(Str(T_ei), 1, term__putc);
+ return;
+ }
+ do {
+ if (GoodStr(T_ic)) /* have to make num chars insert */
+ (void) tputs(Str(T_ic), 1, term__putc);
+ /* insert a char */
+
+ term__putc(*cp++);
+
+ el->el_cursor.h++;
+
+ if (GoodStr(T_ip)) /* have to make num chars insert */
+ (void) tputs(Str(T_ip), 1, term__putc);
+ /* pad the inserted char */
+
+ } while (--num);
+}
+
+
+/* term_clear_EOL():
+ * clear to end of line. There are num characters to clear
+ */
+protected void
+term_clear_EOL(EditLine *el, int num)
+{
+ int i;
+
+ if (EL_CAN_CEOL && GoodStr(T_ce))
+ (void) tputs(Str(T_ce), 1, term__putc);
+ else {
+ for (i = 0; i < num; i++)
+ term__putc(' ');
+ el->el_cursor.h += num; /* have written num spaces */
+ }
+}
+
+
+/* term_clear_screen():
+ * Clear the screen
+ */
+protected void
+term_clear_screen(EditLine *el)
+{ /* clear the whole screen and home */
+
+ if (GoodStr(T_cl))
+ /* send the clear screen code */
+ (void) tputs(Str(T_cl), Val(T_li), term__putc);
+ else if (GoodStr(T_ho) && GoodStr(T_cd)) {
+ (void) tputs(Str(T_ho), Val(T_li), term__putc); /* home */
+ /* clear to bottom of screen */
+ (void) tputs(Str(T_cd), Val(T_li), term__putc);
+ } else {
+ term__putc('\r');
+ term__putc('\n');
+ }
+}
+
+
+/* term_beep():
+ * Beep the way the terminal wants us
+ */
+protected void
+term_beep(EditLine *el)
+{
+ if (GoodStr(T_bl))
+ /* what termcap says we should use */
+ (void) tputs(Str(T_bl), 1, term__putc);
+ else
+ term__putc('\007'); /* an ASCII bell; ^G */
+}
+
+
+#ifdef notdef
+/* term_clear_to_bottom():
+ * Clear to the bottom of the screen
+ */
+protected void
+term_clear_to_bottom(EditLine *el)
+{
+ if (GoodStr(T_cd))
+ (void) tputs(Str(T_cd), Val(T_li), term__putc);
+ else if (GoodStr(T_ce))
+ (void) tputs(Str(T_ce), Val(T_li), term__putc);
+}
+#endif
+
+protected void
+term_get(EditLine *el, const char **term)
+{
+ *term = el->el_term.t_name;
+}
+
+
+/* term_set():
+ * Read in the terminal capabilities from the requested terminal
+ */
+protected int
+term_set(EditLine *el, const char *term)
+{
+ int i;
+ char buf[TC_BUFSIZE];
+ char *area;
+ const struct termcapstr *t;
+ sigset_t oset, nset;
+ int lins, cols;
+
+ (void) sigemptyset(&nset);
+ (void) sigaddset(&nset, SIGWINCH);
+ (void) sigprocmask(SIG_BLOCK, &nset, &oset);
+
+ area = buf;
+
+
+ if (term == NULL)
+ term = getenv("TERM");
+
+ if (!term || !term[0])
+ term = "dumb";
+
+ if (strcmp(term, "emacs") == 0)
+ el->el_flags |= EDIT_DISABLED;
+
+ memset(el->el_term.t_cap, 0, TC_BUFSIZE);
+
+ i = tgetent(el->el_term.t_cap, term);
+
+ if (i <= 0) {
+ if (i == -1)
+ (void) fprintf(el->el_errfile,
+ "Cannot read termcap database;\n");
+ else if (i == 0)
+ (void) fprintf(el->el_errfile,
+ "No entry for terminal type \"%s\";\n", term);
+ (void) fprintf(el->el_errfile,
+ "using dumb terminal settings.\n");
+ Val(T_co) = 80; /* do a dumb terminal */
+ Val(T_pt) = Val(T_km) = Val(T_li) = 0;
+ Val(T_xt) = Val(T_MT);
+ for (t = tstr; t->name != NULL; t++)
+ term_alloc(el, t, NULL);
+ } else {
+ /* auto/magic margins */
+ Val(T_am) = tgetflag("am");
+ Val(T_xn) = tgetflag("xn");
+ /* Can we tab */
+ Val(T_pt) = tgetflag("pt");
+ Val(T_xt) = tgetflag("xt");
+ /* do we have a meta? */
+ Val(T_km) = tgetflag("km");
+ Val(T_MT) = tgetflag("MT");
+ /* Get the size */
+ Val(T_co) = tgetnum("co");
+ Val(T_li) = tgetnum("li");
+ for (t = tstr; t->name != NULL; t++) {
+ /* XXX: some systems' tgetstr needs non const */
+ term_alloc(el, t, tgetstr(strchr(t->name, *t->name),
+ &area));
+ }
+ }
+
+ if (Val(T_co) < 2)
+ Val(T_co) = 80; /* just in case */
+ if (Val(T_li) < 1)
+ Val(T_li) = 24;
+
+ el->el_term.t_size.v = Val(T_co);
+ el->el_term.t_size.h = Val(T_li);
+
+ term_setflags(el);
+
+ /* get the correct window size */
+ (void) term_get_size(el, &lins, &cols);
+ if (term_change_size(el, lins, cols) == -1)
+ return (-1);
+ (void) sigprocmask(SIG_SETMASK, &oset, NULL);
+ term_bind_arrow(el);
+ el->el_term.t_name = term;
+ return (i <= 0 ? -1 : 0);
+}
+
+
+/* term_get_size():
+ * Return the new window size in lines and cols, and
+ * true if the size was changed.
+ */
+protected int
+term_get_size(EditLine *el, int *lins, int *cols)
+{
+
+ *cols = Val(T_co);
+ *lins = Val(T_li);
+
+#ifdef TIOCGWINSZ
+ {
+ struct winsize ws;
+ if (ioctl(el->el_infd, TIOCGWINSZ, (ioctl_t) & ws) != -1) {
+ if (ws.ws_col)
+ *cols = ws.ws_col;
+ if (ws.ws_row)
+ *lins = ws.ws_row;
+ }
+ }
+#endif
+#ifdef TIOCGSIZE
+ {
+ struct ttysize ts;
+ if (ioctl(el->el_infd, TIOCGSIZE, (ioctl_t) & ts) != -1) {
+ if (ts.ts_cols)
+ *cols = ts.ts_cols;
+ if (ts.ts_lines)
+ *lins = ts.ts_lines;
+ }
+ }
+#endif
+ return (Val(T_co) != *cols || Val(T_li) != *lins);
+}
+
+
+/* term_change_size():
+ * Change the size of the terminal
+ */
+protected int
+term_change_size(EditLine *el, int lins, int cols)
+{
+ /*
+ * Just in case
+ */
+ Val(T_co) = (cols < 2) ? 80 : cols;
+ Val(T_li) = (lins < 1) ? 24 : lins;
+
+ /* re-make display buffers */
+ if (term_rebuffer_display(el) == -1)
+ return (-1);
+ re_clear_display(el);
+ return (0);
+}
+
+
+/* term_init_arrow():
+ * Initialize the arrow key bindings from termcap
+ */
+private void
+term_init_arrow(EditLine *el)
+{
+ fkey_t *arrow = el->el_term.t_fkey;
+
+ arrow[A_K_DN].name = "down";
+ arrow[A_K_DN].key = T_kd;
+ arrow[A_K_DN].fun.cmd = ED_NEXT_HISTORY;
+ arrow[A_K_DN].type = XK_CMD;
+
+ arrow[A_K_UP].name = "up";
+ arrow[A_K_UP].key = T_ku;
+ arrow[A_K_UP].fun.cmd = ED_PREV_HISTORY;
+ arrow[A_K_UP].type = XK_CMD;
+
+ arrow[A_K_LT].name = "left";
+ arrow[A_K_LT].key = T_kl;
+ arrow[A_K_LT].fun.cmd = ED_PREV_CHAR;
+ arrow[A_K_LT].type = XK_CMD;
+
+ arrow[A_K_RT].name = "right";
+ arrow[A_K_RT].key = T_kr;
+ arrow[A_K_RT].fun.cmd = ED_NEXT_CHAR;
+ arrow[A_K_RT].type = XK_CMD;
+
+ arrow[A_K_HO].name = "home";
+ arrow[A_K_HO].key = T_kh;
+ arrow[A_K_HO].fun.cmd = ED_MOVE_TO_BEG;
+ arrow[A_K_HO].type = XK_CMD;
+
+ arrow[A_K_EN].name = "end";
+ arrow[A_K_EN].key = T_at7;
+ arrow[A_K_EN].fun.cmd = ED_MOVE_TO_END;
+ arrow[A_K_EN].type = XK_CMD;
+}
+
+
+/* term_reset_arrow():
+ * Reset arrow key bindings
+ */
+private void
+term_reset_arrow(EditLine *el)
+{
+ fkey_t *arrow = el->el_term.t_fkey;
+ static const char strA[] = {033, '[', 'A', '\0'};
+ static const char strB[] = {033, '[', 'B', '\0'};
+ static const char strC[] = {033, '[', 'C', '\0'};
+ static const char strD[] = {033, '[', 'D', '\0'};
+ static const char strH[] = {033, '[', 'H', '\0'};
+ static const char strF[] = {033, '[', 'F', '\0'};
+ static const char str1[] = {033, '[', '1', '~', '\0'};
+ static const char str4[] = {033, '[', '4', '~', '\0'};
+ static const char stOA[] = {033, 'O', 'A', '\0'};
+ static const char stOB[] = {033, 'O', 'B', '\0'};
+ static const char stOC[] = {033, 'O', 'C', '\0'};
+ static const char stOD[] = {033, 'O', 'D', '\0'};
+ static const char stOH[] = {033, 'O', 'H', '\0'};
+ static const char stOF[] = {033, 'O', 'F', '\0'};
+
+ key_add(el, strA, &arrow[A_K_UP].fun, arrow[A_K_UP].type);
+ key_add(el, strB, &arrow[A_K_DN].fun, arrow[A_K_DN].type);
+ key_add(el, strC, &arrow[A_K_RT].fun, arrow[A_K_RT].type);
+ key_add(el, strD, &arrow[A_K_LT].fun, arrow[A_K_LT].type);
+ key_add(el, strH, &arrow[A_K_HO].fun, arrow[A_K_HO].type);
+ key_add(el, strF, &arrow[A_K_EN].fun, arrow[A_K_EN].type);
+ key_add(el, str1, &arrow[A_K_HO].fun, arrow[A_K_HO].type);
+ key_add(el, str4, &arrow[A_K_EN].fun, arrow[A_K_EN].type);
+ key_add(el, stOA, &arrow[A_K_UP].fun, arrow[A_K_UP].type);
+ key_add(el, stOB, &arrow[A_K_DN].fun, arrow[A_K_DN].type);
+ key_add(el, stOC, &arrow[A_K_RT].fun, arrow[A_K_RT].type);
+ key_add(el, stOD, &arrow[A_K_LT].fun, arrow[A_K_LT].type);
+ key_add(el, stOH, &arrow[A_K_HO].fun, arrow[A_K_HO].type);
+ key_add(el, stOF, &arrow[A_K_EN].fun, arrow[A_K_EN].type);
+
+ if (el->el_map.type == MAP_VI) {
+ key_add(el, &strA[1], &arrow[A_K_UP].fun, arrow[A_K_UP].type);
+ key_add(el, &strB[1], &arrow[A_K_DN].fun, arrow[A_K_DN].type);
+ key_add(el, &strC[1], &arrow[A_K_RT].fun, arrow[A_K_RT].type);
+ key_add(el, &strD[1], &arrow[A_K_LT].fun, arrow[A_K_LT].type);
+ key_add(el, &strH[1], &arrow[A_K_HO].fun, arrow[A_K_HO].type);
+ key_add(el, &strF[1], &arrow[A_K_EN].fun, arrow[A_K_EN].type);
+ key_add(el, &str1[1], &arrow[A_K_HO].fun, arrow[A_K_HO].type);
+ key_add(el, &str4[1], &arrow[A_K_EN].fun, arrow[A_K_EN].type);
+ key_add(el, &stOA[1], &arrow[A_K_UP].fun, arrow[A_K_UP].type);
+ key_add(el, &stOB[1], &arrow[A_K_DN].fun, arrow[A_K_DN].type);
+ key_add(el, &stOC[1], &arrow[A_K_RT].fun, arrow[A_K_RT].type);
+ key_add(el, &stOD[1], &arrow[A_K_LT].fun, arrow[A_K_LT].type);
+ key_add(el, &stOH[1], &arrow[A_K_HO].fun, arrow[A_K_HO].type);
+ key_add(el, &stOF[1], &arrow[A_K_EN].fun, arrow[A_K_EN].type);
+ }
+}
+
+
+/* term_set_arrow():
+ * Set an arrow key binding
+ */
+protected int
+term_set_arrow(EditLine *el, const char *name, key_value_t *fun, int type)
+{
+ fkey_t *arrow = el->el_term.t_fkey;
+ int i;
+
+ for (i = 0; i < A_K_NKEYS; i++)
+ if (strcmp(name, arrow[i].name) == 0) {
+ arrow[i].fun = *fun;
+ arrow[i].type = type;
+ return (0);
+ }
+ return (-1);
+}
+
+
+/* term_clear_arrow():
+ * Clear an arrow key binding
+ */
+protected int
+term_clear_arrow(EditLine *el, const char *name)
+{
+ fkey_t *arrow = el->el_term.t_fkey;
+ int i;
+
+ for (i = 0; i < A_K_NKEYS; i++)
+ if (strcmp(name, arrow[i].name) == 0) {
+ arrow[i].type = XK_NOD;
+ return (0);
+ }
+ return (-1);
+}
+
+
+/* term_print_arrow():
+ * Print the arrow key bindings
+ */
+protected void
+term_print_arrow(EditLine *el, const char *name)
+{
+ int i;
+ fkey_t *arrow = el->el_term.t_fkey;
+
+ for (i = 0; i < A_K_NKEYS; i++)
+ if (*name == '\0' || strcmp(name, arrow[i].name) == 0)
+ if (arrow[i].type != XK_NOD)
+ key_kprint(el, arrow[i].name, &arrow[i].fun,
+ arrow[i].type);
+}
+
+
+/* term_bind_arrow():
+ * Bind the arrow keys
+ */
+protected void
+term_bind_arrow(EditLine *el)
+{
+ el_action_t *map;
+ const el_action_t *dmap;
+ int i, j;
+ char *p;
+ fkey_t *arrow = el->el_term.t_fkey;
+
+ /* Check if the components needed are initialized */
+ if (el->el_term.t_buf == NULL || el->el_map.key == NULL)
+ return;
+
+ map = el->el_map.type == MAP_VI ? el->el_map.alt : el->el_map.key;
+ dmap = el->el_map.type == MAP_VI ? el->el_map.vic : el->el_map.emacs;
+
+ term_reset_arrow(el);
+
+ for (i = 0; i < A_K_NKEYS; i++) {
+ p = el->el_term.t_str[arrow[i].key];
+ if (p && *p) {
+ j = (unsigned char) *p;
+ /*
+ * Assign the arrow keys only if:
+ *
+ * 1. They are multi-character arrow keys and the user
+ * has not re-assigned the leading character, or
+ * has re-assigned the leading character to be
+ * ED_SEQUENCE_LEAD_IN
+ * 2. They are single arrow keys pointing to an
+ * unassigned key.
+ */
+ if (arrow[i].type == XK_NOD)
+ key_clear(el, map, p);
+ else {
+ if (p[1] && (dmap[j] == map[j] ||
+ map[j] == ED_SEQUENCE_LEAD_IN)) {
+ key_add(el, p, &arrow[i].fun,
+ arrow[i].type);
+ map[j] = ED_SEQUENCE_LEAD_IN;
+ } else if (map[j] == ED_UNASSIGNED) {
+ key_clear(el, map, p);
+ if (arrow[i].type == XK_CMD)
+ map[j] = arrow[i].fun.cmd;
+ else
+ key_add(el, p, &arrow[i].fun,
+ arrow[i].type);
+ }
+ }
+ }
+ }
+}
+
+
+/* term__putc():
+ * Add a character
+ */
+protected int
+term__putc(int c)
+{
+
+ return (fputc(c, term_outfile));
+}
+
+
+/* term__flush():
+ * Flush output
+ */
+protected void
+term__flush(void)
+{
+
+ (void) fflush(term_outfile);
+}
+
+
+/* term_telltc():
+ * Print the current termcap characteristics
+ */
+protected int
+/*ARGSUSED*/
+term_telltc(EditLine *el, int argc __unused,
+ const char **argv __unused)
+{
+ const struct termcapstr *t;
+ char **ts;
+ char upbuf[EL_BUFSIZ];
+
+ (void) fprintf(el->el_outfile, "\n\tYour terminal has the\n");
+ (void) fprintf(el->el_outfile, "\tfollowing characteristics:\n\n");
+ (void) fprintf(el->el_outfile, "\tIt has %d columns and %d lines\n",
+ Val(T_co), Val(T_li));
+ (void) fprintf(el->el_outfile,
+ "\tIt has %s meta key\n", EL_HAS_META ? "a" : "no");
+ (void) fprintf(el->el_outfile,
+ "\tIt can%suse tabs\n", EL_CAN_TAB ? " " : "not ");
+ (void) fprintf(el->el_outfile, "\tIt %s automatic margins\n",
+ EL_HAS_AUTO_MARGINS ? "has" : "does not have");
+ if (EL_HAS_AUTO_MARGINS)
+ (void) fprintf(el->el_outfile, "\tIt %s magic margins\n",
+ EL_HAS_MAGIC_MARGINS ? "has" : "does not have");
+
+ for (t = tstr, ts = el->el_term.t_str; t->name != NULL; t++, ts++)
+ (void) fprintf(el->el_outfile, "\t%25s (%s) == %s\n",
+ t->long_name,
+ t->name, *ts && **ts ?
+ key__decode_str(*ts, upbuf, "") : "(empty)");
+ (void) fputc('\n', el->el_outfile);
+ return (0);
+}
+
+
+/* term_settc():
+ * Change the current terminal characteristics
+ */
+protected int
+/*ARGSUSED*/
+term_settc(EditLine *el, int argc __unused,
+ const char **argv)
+{
+ const struct termcapstr *ts;
+ const struct termcapval *tv;
+ const char *what, *how;
+
+ if (argv == NULL || argv[1] == NULL || argv[2] == NULL)
+ return (-1);
+
+ what = argv[1];
+ how = argv[2];
+
+ /*
+ * Do the strings first
+ */
+ for (ts = tstr; ts->name != NULL; ts++)
+ if (strcmp(ts->name, what) == 0)
+ break;
+
+ if (ts->name != NULL) {
+ term_alloc(el, ts, how);
+ term_setflags(el);
+ return (0);
+ }
+ /*
+ * Do the numeric ones second
+ */
+ for (tv = tval; tv->name != NULL; tv++)
+ if (strcmp(tv->name, what) == 0)
+ break;
+
+ if (tv->name != NULL) {
+ if (tv == &tval[T_pt] || tv == &tval[T_km] ||
+ tv == &tval[T_am] || tv == &tval[T_xn]) {
+ if (strcmp(how, "yes") == 0)
+ el->el_term.t_val[tv - tval] = 1;
+ else if (strcmp(how, "no") == 0)
+ el->el_term.t_val[tv - tval] = 0;
+ else {
+ (void) fprintf(el->el_errfile,
+ "settc: Bad value `%s'.\n", how);
+ return (-1);
+ }
+ term_setflags(el);
+ if (term_change_size(el, Val(T_li), Val(T_co)) == -1)
+ return (-1);
+ return (0);
+ } else {
+ long i;
+ char *ep;
+
+ i = strtol(how, &ep, 10);
+ if (*ep != '\0') {
+ (void) fprintf(el->el_errfile,
+ "settc: Bad value `%s'.\n", how);
+ return (-1);
+ }
+ el->el_term.t_val[tv - tval] = (int) i;
+ el->el_term.t_size.v = Val(T_co);
+ el->el_term.t_size.h = Val(T_li);
+ if (tv == &tval[T_co] || tv == &tval[T_li])
+ if (term_change_size(el, Val(T_li), Val(T_co))
+ == -1)
+ return (-1);
+ return (0);
+ }
+ }
+ return (-1);
+}
+
+
+/* term_echotc():
+ * Print the termcap string out with variable substitution
+ */
+protected int
+/*ARGSUSED*/
+term_echotc(EditLine *el, int argc __unused,
+ const char **argv)
+{
+ char *cap, *scap, *ep;
+ int arg_need, arg_cols, arg_rows;
+ int verbose = 0, silent = 0;
+ char *area;
+ static const char fmts[] = "%s\n", fmtd[] = "%d\n";
+ const struct termcapstr *t;
+ char buf[TC_BUFSIZE];
+ long i;
+
+ area = buf;
+
+ if (argv == NULL || argv[1] == NULL)
+ return (-1);
+ argv++;
+
+ if (argv[0][0] == '-') {
+ switch (argv[0][1]) {
+ case 'v':
+ verbose = 1;
+ break;
+ case 's':
+ silent = 1;
+ break;
+ default:
+ /* stderror(ERR_NAME | ERR_TCUSAGE); */
+ break;
+ }
+ argv++;
+ }
+ if (!*argv || *argv[0] == '\0')
+ return (0);
+ if (strcmp(*argv, "tabs") == 0) {
+ (void) fprintf(el->el_outfile, fmts, EL_CAN_TAB ? "yes" : "no");
+ return (0);
+ } else if (strcmp(*argv, "meta") == 0) {
+ (void) fprintf(el->el_outfile, fmts, Val(T_km) ? "yes" : "no");
+ return (0);
+ } else if (strcmp(*argv, "xn") == 0) {
+ (void) fprintf(el->el_outfile, fmts, EL_HAS_MAGIC_MARGINS ?
+ "yes" : "no");
+ return (0);
+ } else if (strcmp(*argv, "am") == 0) {
+ (void) fprintf(el->el_outfile, fmts, EL_HAS_AUTO_MARGINS ?
+ "yes" : "no");
+ return (0);
+ } else if (strcmp(*argv, "baud") == 0) {
+#ifdef notdef
+ int i;
+
+ for (i = 0; baud_rate[i].b_name != NULL; i++)
+ if (el->el_tty.t_speed == baud_rate[i].b_rate) {
+ (void) fprintf(el->el_outfile, fmts,
+ baud_rate[i].b_name);
+ return (0);
+ }
+ (void) fprintf(el->el_outfile, fmtd, 0);
+#else
+ (void) fprintf(el->el_outfile, fmtd, (int)el->el_tty.t_speed);
+#endif
+ return (0);
+ } else if (strcmp(*argv, "rows") == 0 || strcmp(*argv, "lines") == 0) {
+ (void) fprintf(el->el_outfile, fmtd, Val(T_li));
+ return (0);
+ } else if (strcmp(*argv, "cols") == 0) {
+ (void) fprintf(el->el_outfile, fmtd, Val(T_co));
+ return (0);
+ }
+ /*
+ * Try to use our local definition first
+ */
+ scap = NULL;
+ for (t = tstr; t->name != NULL; t++)
+ if (strcmp(t->name, *argv) == 0) {
+ scap = el->el_term.t_str[t - tstr];
+ break;
+ }
+ if (t->name == NULL) {
+ /* XXX: some systems' tgetstr needs non const */
+ scap = tgetstr(strchr(*argv, **argv), &area);
+ }
+ if (!scap || scap[0] == '\0') {
+ if (!silent)
+ (void) fprintf(el->el_errfile,
+ "echotc: Termcap parameter `%s' not found.\n",
+ *argv);
+ return (-1);
+ }
+ /*
+ * Count home many values we need for this capability.
+ */
+ for (cap = scap, arg_need = 0; *cap; cap++)
+ if (*cap == '%')
+ switch (*++cap) {
+ case 'd':
+ case '2':
+ case '3':
+ case '.':
+ case '+':
+ arg_need++;
+ break;
+ case '%':
+ case '>':
+ case 'i':
+ case 'r':
+ case 'n':
+ case 'B':
+ case 'D':
+ break;
+ default:
+ /*
+ * hpux has lot's of them...
+ */
+ if (verbose)
+ (void) fprintf(el->el_errfile,
+ "echotc: Warning: unknown termcap %% `%c'.\n",
+ *cap);
+ /* This is bad, but I won't complain */
+ break;
+ }
+
+ switch (arg_need) {
+ case 0:
+ argv++;
+ if (*argv && *argv[0]) {
+ if (!silent)
+ (void) fprintf(el->el_errfile,
+ "echotc: Warning: Extra argument `%s'.\n",
+ *argv);
+ return (-1);
+ }
+ (void) tputs(scap, 1, term__putc);
+ break;
+ case 1:
+ argv++;
+ if (!*argv || *argv[0] == '\0') {
+ if (!silent)
+ (void) fprintf(el->el_errfile,
+ "echotc: Warning: Missing argument.\n");
+ return (-1);
+ }
+ arg_cols = 0;
+ i = strtol(*argv, &ep, 10);
+ if (*ep != '\0' || i < 0) {
+ if (!silent)
+ (void) fprintf(el->el_errfile,
+ "echotc: Bad value `%s' for rows.\n",
+ *argv);
+ return (-1);
+ }
+ arg_rows = (int) i;
+ argv++;
+ if (*argv && *argv[0]) {
+ if (!silent)
+ (void) fprintf(el->el_errfile,
+ "echotc: Warning: Extra argument `%s'.\n",
+ *argv);
+ return (-1);
+ }
+ (void) tputs(tgoto(scap, arg_cols, arg_rows), 1, term__putc);
+ break;
+ default:
+ /* This is wrong, but I will ignore it... */
+ if (verbose)
+ (void) fprintf(el->el_errfile,
+ "echotc: Warning: Too many required arguments (%d).\n",
+ arg_need);
+ /* FALLTHROUGH */
+ case 2:
+ argv++;
+ if (!*argv || *argv[0] == '\0') {
+ if (!silent)
+ (void) fprintf(el->el_errfile,
+ "echotc: Warning: Missing argument.\n");
+ return (-1);
+ }
+ i = strtol(*argv, &ep, 10);
+ if (*ep != '\0' || i < 0) {
+ if (!silent)
+ (void) fprintf(el->el_errfile,
+ "echotc: Bad value `%s' for cols.\n",
+ *argv);
+ return (-1);
+ }
+ arg_cols = (int) i;
+ argv++;
+ if (!*argv || *argv[0] == '\0') {
+ if (!silent)
+ (void) fprintf(el->el_errfile,
+ "echotc: Warning: Missing argument.\n");
+ return (-1);
+ }
+ i = strtol(*argv, &ep, 10);
+ if (*ep != '\0' || i < 0) {
+ if (!silent)
+ (void) fprintf(el->el_errfile,
+ "echotc: Bad value `%s' for rows.\n",
+ *argv);
+ return (-1);
+ }
+ arg_rows = (int) i;
+ if (*ep != '\0') {
+ if (!silent)
+ (void) fprintf(el->el_errfile,
+ "echotc: Bad value `%s'.\n", *argv);
+ return (-1);
+ }
+ argv++;
+ if (*argv && *argv[0]) {
+ if (!silent)
+ (void) fprintf(el->el_errfile,
+ "echotc: Warning: Extra argument `%s'.\n",
+ *argv);
+ return (-1);
+ }
+ (void) tputs(tgoto(scap, arg_cols, arg_rows), arg_rows,
+ term__putc);
+ break;
+ }
+ return (0);
+}
diff --git a/lib/libedit/term.h b/lib/libedit/term.h
new file mode 100644
index 0000000..d97b46d
--- /dev/null
+++ b/lib/libedit/term.h
@@ -0,0 +1,123 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell 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.
+ *
+ * @(#)term.h 8.1 (Berkeley) 6/4/93
+ * $NetBSD: term.h,v 1.16 2005/03/15 00:10:40 christos Exp $
+ * $FreeBSD$
+ */
+
+/*
+ * el.term.h: Termcap header
+ */
+#ifndef _h_el_term
+#define _h_el_term
+
+#include "histedit.h"
+
+typedef struct { /* Symbolic function key bindings */
+ const char *name; /* name of the key */
+ int key; /* Index in termcap table */
+ key_value_t fun; /* Function bound to it */
+ int type; /* Type of function */
+} fkey_t;
+
+typedef struct {
+ const char *t_name; /* the terminal name */
+ coord_t t_size; /* # lines and cols */
+ int t_flags;
+#define TERM_CAN_INSERT 0x001 /* Has insert cap */
+#define TERM_CAN_DELETE 0x002 /* Has delete cap */
+#define TERM_CAN_CEOL 0x004 /* Has CEOL cap */
+#define TERM_CAN_TAB 0x008 /* Can use tabs */
+#define TERM_CAN_ME 0x010 /* Can turn all attrs. */
+#define TERM_CAN_UP 0x020 /* Can move up */
+#define TERM_HAS_META 0x040 /* Has a meta key */
+#define TERM_HAS_AUTO_MARGINS 0x080 /* Has auto margins */
+#define TERM_HAS_MAGIC_MARGINS 0x100 /* Has magic margins */
+ char *t_buf; /* Termcap buffer */
+ int t_loc; /* location used */
+ char **t_str; /* termcap strings */
+ int *t_val; /* termcap values */
+ char *t_cap; /* Termcap buffer */
+ fkey_t *t_fkey; /* Array of keys */
+} el_term_t;
+
+/*
+ * fKey indexes
+ */
+#define A_K_DN 0
+#define A_K_UP 1
+#define A_K_LT 2
+#define A_K_RT 3
+#define A_K_HO 4
+#define A_K_EN 5
+#define A_K_NKEYS 6
+
+protected void term_move_to_line(EditLine *, int);
+protected void term_move_to_char(EditLine *, int);
+protected void term_clear_EOL(EditLine *, int);
+protected void term_overwrite(EditLine *, const char *, int);
+protected void term_insertwrite(EditLine *, char *, int);
+protected void term_deletechars(EditLine *, int);
+protected void term_clear_screen(EditLine *);
+protected void term_beep(EditLine *);
+protected int term_change_size(EditLine *, int, int);
+protected int term_get_size(EditLine *, int *, int *);
+protected int term_init(EditLine *);
+protected void term_bind_arrow(EditLine *);
+protected void term_print_arrow(EditLine *, const char *);
+protected int term_clear_arrow(EditLine *, const char *);
+protected int term_set_arrow(EditLine *, const char *, key_value_t *, int);
+protected void term_end(EditLine *);
+protected void term_get(EditLine *, const char **);
+protected int term_set(EditLine *, const char *);
+protected int term_settc(EditLine *, int, const char **);
+protected int term_telltc(EditLine *, int, const char **);
+protected int term_echotc(EditLine *, int, const char **);
+protected int term__putc(int);
+protected void term__flush(void);
+
+/*
+ * Easy access macros
+ */
+#define EL_FLAGS (el)->el_term.t_flags
+
+#define EL_CAN_INSERT (EL_FLAGS & TERM_CAN_INSERT)
+#define EL_CAN_DELETE (EL_FLAGS & TERM_CAN_DELETE)
+#define EL_CAN_CEOL (EL_FLAGS & TERM_CAN_CEOL)
+#define EL_CAN_TAB (EL_FLAGS & TERM_CAN_TAB)
+#define EL_CAN_ME (EL_FLAGS & TERM_CAN_ME)
+#define EL_CAN_UP (EL_FLAGS & TERM_CAN_UP)
+#define EL_HAS_META (EL_FLAGS & TERM_HAS_META)
+#define EL_HAS_AUTO_MARGINS (EL_FLAGS & TERM_HAS_AUTO_MARGINS)
+#define EL_HAS_MAGIC_MARGINS (EL_FLAGS & TERM_HAS_MAGIC_MARGINS)
+
+#endif /* _h_el_term */
diff --git a/lib/libedit/tokenizer.c b/lib/libedit/tokenizer.c
new file mode 100644
index 0000000..8e3100d
--- /dev/null
+++ b/lib/libedit/tokenizer.c
@@ -0,0 +1,445 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell 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.
+ *
+ * $NetBSD: tokenizer.c,v 1.14 2003/12/05 13:37:48 lukem Exp $
+ */
+
+#if !defined(lint) && !defined(SCCSID)
+static char sccsid[] = "@(#)tokenizer.c 8.1 (Berkeley) 6/4/93";
+#endif /* not lint && not SCCSID */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * tokenize.c: Bourne shell like tokenizer
+ */
+#include "sys.h"
+#include <string.h>
+#include <stdlib.h>
+#include "histedit.h"
+
+typedef enum {
+ Q_none, Q_single, Q_double, Q_one, Q_doubleone
+} quote_t;
+
+#define IFS "\t \n"
+
+#define TOK_KEEP 1
+#define TOK_EAT 2
+
+#define WINCR 20
+#define AINCR 10
+
+#define tok_strdup(a) strdup(a)
+#define tok_malloc(a) malloc(a)
+#define tok_free(a) free(a)
+#define tok_realloc(a, b) realloc(a, b)
+
+
+struct tokenizer {
+ char *ifs; /* In field separator */
+ int argc, amax; /* Current and maximum number of args */
+ char **argv; /* Argument list */
+ char *wptr, *wmax; /* Space and limit on the word buffer */
+ char *wstart; /* Beginning of next word */
+ char *wspace; /* Space of word buffer */
+ quote_t quote; /* Quoting state */
+ int flags; /* flags; */
+};
+
+
+private void tok_finish(Tokenizer *);
+
+
+/* tok_finish():
+ * Finish a word in the tokenizer.
+ */
+private void
+tok_finish(Tokenizer *tok)
+{
+
+ *tok->wptr = '\0';
+ if ((tok->flags & TOK_KEEP) || tok->wptr != tok->wstart) {
+ tok->argv[tok->argc++] = tok->wstart;
+ tok->argv[tok->argc] = NULL;
+ tok->wstart = ++tok->wptr;
+ }
+ tok->flags &= ~TOK_KEEP;
+}
+
+
+/* tok_init():
+ * Initialize the tokenizer
+ */
+public Tokenizer *
+tok_init(const char *ifs)
+{
+ Tokenizer *tok = (Tokenizer *) tok_malloc(sizeof(Tokenizer));
+
+ if (tok == NULL)
+ return NULL;
+ tok->ifs = tok_strdup(ifs ? ifs : IFS);
+ if (tok->ifs == NULL) {
+ tok_free((ptr_t)tok);
+ return NULL;
+ }
+ tok->argc = 0;
+ tok->amax = AINCR;
+ tok->argv = (char **) tok_malloc(sizeof(char *) * tok->amax);
+ if (tok->argv == NULL) {
+ tok_free((ptr_t)tok->ifs);
+ tok_free((ptr_t)tok);
+ return NULL;
+ }
+ tok->argv[0] = NULL;
+ tok->wspace = (char *) tok_malloc(WINCR);
+ if (tok->wspace == NULL) {
+ tok_free((ptr_t)tok->argv);
+ tok_free((ptr_t)tok->ifs);
+ tok_free((ptr_t)tok);
+ return NULL;
+ }
+ tok->wmax = tok->wspace + WINCR;
+ tok->wstart = tok->wspace;
+ tok->wptr = tok->wspace;
+ tok->flags = 0;
+ tok->quote = Q_none;
+
+ return (tok);
+}
+
+
+/* tok_reset():
+ * Reset the tokenizer
+ */
+public void
+tok_reset(Tokenizer *tok)
+{
+
+ tok->argc = 0;
+ tok->wstart = tok->wspace;
+ tok->wptr = tok->wspace;
+ tok->flags = 0;
+ tok->quote = Q_none;
+}
+
+
+/* tok_end():
+ * Clean up
+ */
+public void
+tok_end(Tokenizer *tok)
+{
+
+ tok_free((ptr_t) tok->ifs);
+ tok_free((ptr_t) tok->wspace);
+ tok_free((ptr_t) tok->argv);
+ tok_free((ptr_t) tok);
+}
+
+
+
+/* tok_line():
+ * Bourne shell (sh(1)) like tokenizing
+ * Arguments:
+ * tok current tokenizer state (setup with tok_init())
+ * line line to parse
+ * Returns:
+ * -1 Internal error
+ * 3 Quoted return
+ * 2 Unmatched double quote
+ * 1 Unmatched single quote
+ * 0 Ok
+ * Modifies (if return value is 0):
+ * argc number of arguments
+ * argv argument array
+ * cursorc if !NULL, argv element containing cursor
+ * cursorv if !NULL, offset in argv[cursorc] of cursor
+ */
+public int
+tok_line(Tokenizer *tok, const LineInfo *line,
+ int *argc, const char ***argv, int *cursorc, int *cursoro)
+{
+ const char *ptr;
+ int cc, co;
+
+ cc = co = -1;
+ ptr = line->buffer;
+ for (ptr = line->buffer; ;ptr++) {
+ if (ptr >= line->lastchar)
+ ptr = "";
+ if (ptr == line->cursor) {
+ cc = tok->argc;
+ co = tok->wptr - tok->wstart;
+ }
+ switch (*ptr) {
+ case '\'':
+ tok->flags |= TOK_KEEP;
+ tok->flags &= ~TOK_EAT;
+ switch (tok->quote) {
+ case Q_none:
+ tok->quote = Q_single; /* Enter single quote
+ * mode */
+ break;
+
+ case Q_single: /* Exit single quote mode */
+ tok->quote = Q_none;
+ break;
+
+ case Q_one: /* Quote this ' */
+ tok->quote = Q_none;
+ *tok->wptr++ = *ptr;
+ break;
+
+ case Q_double: /* Stay in double quote mode */
+ *tok->wptr++ = *ptr;
+ break;
+
+ case Q_doubleone: /* Quote this ' */
+ tok->quote = Q_double;
+ *tok->wptr++ = *ptr;
+ break;
+
+ default:
+ return (-1);
+ }
+ break;
+
+ case '"':
+ tok->flags &= ~TOK_EAT;
+ tok->flags |= TOK_KEEP;
+ switch (tok->quote) {
+ case Q_none: /* Enter double quote mode */
+ tok->quote = Q_double;
+ break;
+
+ case Q_double: /* Exit double quote mode */
+ tok->quote = Q_none;
+ break;
+
+ case Q_one: /* Quote this " */
+ tok->quote = Q_none;
+ *tok->wptr++ = *ptr;
+ break;
+
+ case Q_single: /* Stay in single quote mode */
+ *tok->wptr++ = *ptr;
+ break;
+
+ case Q_doubleone: /* Quote this " */
+ tok->quote = Q_double;
+ *tok->wptr++ = *ptr;
+ break;
+
+ default:
+ return (-1);
+ }
+ break;
+
+ case '\\':
+ tok->flags |= TOK_KEEP;
+ tok->flags &= ~TOK_EAT;
+ switch (tok->quote) {
+ case Q_none: /* Quote next character */
+ tok->quote = Q_one;
+ break;
+
+ case Q_double: /* Quote next character */
+ tok->quote = Q_doubleone;
+ break;
+
+ case Q_one: /* Quote this, restore state */
+ *tok->wptr++ = *ptr;
+ tok->quote = Q_none;
+ break;
+
+ case Q_single: /* Stay in single quote mode */
+ *tok->wptr++ = *ptr;
+ break;
+
+ case Q_doubleone: /* Quote this \ */
+ tok->quote = Q_double;
+ *tok->wptr++ = *ptr;
+ break;
+
+ default:
+ return (-1);
+ }
+ break;
+
+ case '\n':
+ tok->flags &= ~TOK_EAT;
+ switch (tok->quote) {
+ case Q_none:
+ goto tok_line_outok;
+
+ case Q_single:
+ case Q_double:
+ *tok->wptr++ = *ptr; /* Add the return */
+ break;
+
+ case Q_doubleone: /* Back to double, eat the '\n' */
+ tok->flags |= TOK_EAT;
+ tok->quote = Q_double;
+ break;
+
+ case Q_one: /* No quote, more eat the '\n' */
+ tok->flags |= TOK_EAT;
+ tok->quote = Q_none;
+ break;
+
+ default:
+ return (0);
+ }
+ break;
+
+ case '\0':
+ switch (tok->quote) {
+ case Q_none:
+ /* Finish word and return */
+ if (tok->flags & TOK_EAT) {
+ tok->flags &= ~TOK_EAT;
+ return (3);
+ }
+ goto tok_line_outok;
+
+ case Q_single:
+ return (1);
+
+ case Q_double:
+ return (2);
+
+ case Q_doubleone:
+ tok->quote = Q_double;
+ *tok->wptr++ = *ptr;
+ break;
+
+ case Q_one:
+ tok->quote = Q_none;
+ *tok->wptr++ = *ptr;
+ break;
+
+ default:
+ return (-1);
+ }
+ break;
+
+ default:
+ tok->flags &= ~TOK_EAT;
+ switch (tok->quote) {
+ case Q_none:
+ if (strchr(tok->ifs, *ptr) != NULL)
+ tok_finish(tok);
+ else
+ *tok->wptr++ = *ptr;
+ break;
+
+ case Q_single:
+ case Q_double:
+ *tok->wptr++ = *ptr;
+ break;
+
+
+ case Q_doubleone:
+ *tok->wptr++ = '\\';
+ tok->quote = Q_double;
+ *tok->wptr++ = *ptr;
+ break;
+
+ case Q_one:
+ tok->quote = Q_none;
+ *tok->wptr++ = *ptr;
+ break;
+
+ default:
+ return (-1);
+
+ }
+ break;
+ }
+
+ if (tok->wptr >= tok->wmax - 4) {
+ size_t size = tok->wmax - tok->wspace + WINCR;
+ char *s = (char *) tok_realloc(tok->wspace, size);
+ if (s == NULL)
+ return (-1);
+
+ if (s != tok->wspace) {
+ int i;
+ for (i = 0; i < tok->argc; i++) {
+ tok->argv[i] =
+ (tok->argv[i] - tok->wspace) + s;
+ }
+ tok->wptr = (tok->wptr - tok->wspace) + s;
+ tok->wstart = (tok->wstart - tok->wspace) + s;
+ tok->wspace = s;
+ }
+ tok->wmax = s + size;
+ }
+ if (tok->argc >= tok->amax - 4) {
+ char **p;
+ tok->amax += AINCR;
+ p = (char **) tok_realloc(tok->argv,
+ tok->amax * sizeof(char *));
+ if (p == NULL)
+ return (-1);
+ tok->argv = p;
+ }
+ }
+ tok_line_outok:
+ if (cc == -1 && co == -1) {
+ cc = tok->argc;
+ co = tok->wptr - tok->wstart;
+ }
+ if (cursorc != NULL)
+ *cursorc = cc;
+ if (cursoro != NULL)
+ *cursoro = co;
+ tok_finish(tok);
+ *argv = (const char **)tok->argv;
+ *argc = tok->argc;
+ return (0);
+}
+
+/* tok_str():
+ * Simpler version of tok_line, taking a NUL terminated line
+ * and splitting into words, ignoring cursor state.
+ */
+public int
+tok_str(Tokenizer *tok, const char *line, int *argc, const char ***argv)
+{
+ LineInfo li;
+
+ memset(&li, 0, sizeof(li));
+ li.buffer = line;
+ li.cursor = li.lastchar = strchr(line, '\0');
+ return (tok_line(tok, &li, argc, argv, NULL, NULL));
+}
diff --git a/lib/libedit/tty.c b/lib/libedit/tty.c
new file mode 100644
index 0000000..e2b9932
--- /dev/null
+++ b/lib/libedit/tty.c
@@ -0,0 +1,1254 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell 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.
+ *
+ * $NetBSD: tty.c,v 1.23 2005/06/01 11:37:52 lukem Exp $
+ */
+
+#if !defined(lint) && !defined(SCCSID)
+static char sccsid[] = "@(#)tty.c 8.1 (Berkeley) 6/4/93";
+#endif /* not lint && not SCCSID */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * tty.c: tty interface stuff
+ */
+#include <assert.h>
+#include "sys.h"
+#include "tty.h"
+#include "el.h"
+
+typedef struct ttymodes_t {
+ const char *m_name;
+ unsigned int m_value;
+ int m_type;
+} ttymodes_t;
+
+typedef struct ttymap_t {
+ int nch, och; /* Internal and termio rep of chars */
+ el_action_t bind[3]; /* emacs, vi, and vi-cmd */
+} ttymap_t;
+
+
+private const ttyperm_t ttyperm = {
+ {
+ {"iflag:", ICRNL, (INLCR | IGNCR)},
+ {"oflag:", (OPOST | ONLCR), ONLRET},
+ {"cflag:", 0, 0},
+ {"lflag:", (ISIG | ICANON | ECHO | ECHOE | ECHOCTL | IEXTEN),
+ (NOFLSH | ECHONL | EXTPROC | FLUSHO)},
+ {"chars:", 0, 0},
+ },
+ {
+ {"iflag:", (INLCR | ICRNL), IGNCR},
+ {"oflag:", (OPOST | ONLCR), ONLRET},
+ {"cflag:", 0, 0},
+ {"lflag:", ISIG,
+ (NOFLSH | ICANON | ECHO | ECHOK | ECHONL | EXTPROC | IEXTEN | FLUSHO)},
+ {"chars:", (C_SH(C_MIN) | C_SH(C_TIME) | C_SH(C_SWTCH) | C_SH(C_DSWTCH) |
+ C_SH(C_SUSP) | C_SH(C_DSUSP) | C_SH(C_EOL) | C_SH(C_DISCARD) |
+ C_SH(C_PGOFF) | C_SH(C_PAGE) | C_SH(C_STATUS)), 0}
+ },
+ {
+ {"iflag:", 0, IXON | IXOFF | INLCR | ICRNL},
+ {"oflag:", 0, 0},
+ {"cflag:", 0, 0},
+ {"lflag:", 0, ISIG | IEXTEN},
+ {"chars:", 0, 0},
+ }
+};
+
+private const ttychar_t ttychar = {
+ {
+ CINTR, CQUIT, CERASE, CKILL,
+ CEOF, CEOL, CEOL2, CSWTCH,
+ CDSWTCH, CERASE2, CSTART, CSTOP,
+ CWERASE, CSUSP, CDSUSP, CREPRINT,
+ CDISCARD, CLNEXT, CSTATUS, CPAGE,
+ CPGOFF, CKILL2, CBRK, CMIN,
+ CTIME
+ },
+ {
+ CINTR, CQUIT, CERASE, CKILL,
+ _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE,
+ _POSIX_VDISABLE, CERASE2, CSTART, CSTOP,
+ _POSIX_VDISABLE, CSUSP, _POSIX_VDISABLE, _POSIX_VDISABLE,
+ CDISCARD, _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE,
+ _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE, 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
+ }
+};
+
+private const ttymap_t tty_map[] = {
+#ifdef VERASE
+ {C_ERASE, VERASE,
+ {EM_DELETE_PREV_CHAR, VI_DELETE_PREV_CHAR, ED_PREV_CHAR}},
+#endif /* VERASE */
+#ifdef VERASE2
+ {C_ERASE2, VERASE2,
+ {EM_DELETE_PREV_CHAR, VI_DELETE_PREV_CHAR, ED_PREV_CHAR}},
+#endif /* VERASE2 */
+#ifdef VKILL
+ {C_KILL, VKILL,
+ {EM_KILL_LINE, VI_KILL_LINE_PREV, ED_UNASSIGNED}},
+#endif /* VKILL */
+#ifdef VKILL2
+ {C_KILL2, VKILL2,
+ {EM_KILL_LINE, VI_KILL_LINE_PREV, ED_UNASSIGNED}},
+#endif /* VKILL2 */
+#ifdef VEOF
+ {C_EOF, VEOF,
+ {EM_DELETE_OR_LIST, VI_LIST_OR_EOF, ED_UNASSIGNED}},
+#endif /* VEOF */
+#ifdef VWERASE
+ {C_WERASE, VWERASE,
+ {ED_DELETE_PREV_WORD, ED_DELETE_PREV_WORD, ED_PREV_WORD}},
+#endif /* VWERASE */
+#ifdef VREPRINT
+ {C_REPRINT, VREPRINT,
+ {ED_REDISPLAY, ED_INSERT, ED_REDISPLAY}},
+#endif /* VREPRINT */
+#ifdef VLNEXT
+ {C_LNEXT, VLNEXT,
+ {ED_QUOTED_INSERT, ED_QUOTED_INSERT, ED_UNASSIGNED}},
+#endif /* VLNEXT */
+ {-1, -1,
+ {ED_UNASSIGNED, ED_UNASSIGNED, ED_UNASSIGNED}}
+};
+
+private const ttymodes_t ttymodes[] = {
+#ifdef IGNBRK
+ {"ignbrk", IGNBRK, MD_INP},
+#endif /* IGNBRK */
+#ifdef BRKINT
+ {"brkint", BRKINT, MD_INP},
+#endif /* BRKINT */
+#ifdef IGNPAR
+ {"ignpar", IGNPAR, MD_INP},
+#endif /* IGNPAR */
+#ifdef PARMRK
+ {"parmrk", PARMRK, MD_INP},
+#endif /* PARMRK */
+#ifdef INPCK
+ {"inpck", INPCK, MD_INP},
+#endif /* INPCK */
+#ifdef ISTRIP
+ {"istrip", ISTRIP, MD_INP},
+#endif /* ISTRIP */
+#ifdef INLCR
+ {"inlcr", INLCR, MD_INP},
+#endif /* INLCR */
+#ifdef IGNCR
+ {"igncr", IGNCR, MD_INP},
+#endif /* IGNCR */
+#ifdef ICRNL
+ {"icrnl", ICRNL, MD_INP},
+#endif /* ICRNL */
+#ifdef IUCLC
+ {"iuclc", IUCLC, MD_INP},
+#endif /* IUCLC */
+#ifdef IXON
+ {"ixon", IXON, MD_INP},
+#endif /* IXON */
+#ifdef IXANY
+ {"ixany", IXANY, MD_INP},
+#endif /* IXANY */
+#ifdef IXOFF
+ {"ixoff", IXOFF, MD_INP},
+#endif /* IXOFF */
+#ifdef IMAXBEL
+ {"imaxbel", IMAXBEL, MD_INP},
+#endif /* IMAXBEL */
+
+#ifdef OPOST
+ {"opost", OPOST, MD_OUT},
+#endif /* OPOST */
+#ifdef OLCUC
+ {"olcuc", OLCUC, MD_OUT},
+#endif /* OLCUC */
+#ifdef ONLCR
+ {"onlcr", ONLCR, MD_OUT},
+#endif /* ONLCR */
+#ifdef OCRNL
+ {"ocrnl", OCRNL, MD_OUT},
+#endif /* OCRNL */
+#ifdef ONOCR
+ {"onocr", ONOCR, MD_OUT},
+#endif /* ONOCR */
+#ifdef ONOEOT
+ {"onoeot", ONOEOT, MD_OUT},
+#endif /* ONOEOT */
+#ifdef ONLRET
+ {"onlret", ONLRET, MD_OUT},
+#endif /* ONLRET */
+#ifdef OFILL
+ {"ofill", OFILL, MD_OUT},
+#endif /* OFILL */
+#ifdef OFDEL
+ {"ofdel", OFDEL, MD_OUT},
+#endif /* OFDEL */
+#ifdef NLDLY
+ {"nldly", NLDLY, MD_OUT},
+#endif /* NLDLY */
+#ifdef CRDLY
+ {"crdly", CRDLY, MD_OUT},
+#endif /* CRDLY */
+#ifdef TABDLY
+ {"tabdly", TABDLY, MD_OUT},
+#endif /* TABDLY */
+#ifdef XTABS
+ {"xtabs", XTABS, MD_OUT},
+#endif /* XTABS */
+#ifdef BSDLY
+ {"bsdly", BSDLY, MD_OUT},
+#endif /* BSDLY */
+#ifdef VTDLY
+ {"vtdly", VTDLY, MD_OUT},
+#endif /* VTDLY */
+#ifdef FFDLY
+ {"ffdly", FFDLY, MD_OUT},
+#endif /* FFDLY */
+#ifdef PAGEOUT
+ {"pageout", PAGEOUT, MD_OUT},
+#endif /* PAGEOUT */
+#ifdef WRAP
+ {"wrap", WRAP, MD_OUT},
+#endif /* WRAP */
+
+#ifdef CIGNORE
+ {"cignore", CIGNORE, MD_CTL},
+#endif /* CBAUD */
+#ifdef CBAUD
+ {"cbaud", CBAUD, MD_CTL},
+#endif /* CBAUD */
+#ifdef CSTOPB
+ {"cstopb", CSTOPB, MD_CTL},
+#endif /* CSTOPB */
+#ifdef CREAD
+ {"cread", CREAD, MD_CTL},
+#endif /* CREAD */
+#ifdef PARENB
+ {"parenb", PARENB, MD_CTL},
+#endif /* PARENB */
+#ifdef PARODD
+ {"parodd", PARODD, MD_CTL},
+#endif /* PARODD */
+#ifdef HUPCL
+ {"hupcl", HUPCL, MD_CTL},
+#endif /* HUPCL */
+#ifdef CLOCAL
+ {"clocal", CLOCAL, MD_CTL},
+#endif /* CLOCAL */
+#ifdef LOBLK
+ {"loblk", LOBLK, MD_CTL},
+#endif /* LOBLK */
+#ifdef CIBAUD
+ {"cibaud", CIBAUD, MD_CTL},
+#endif /* CIBAUD */
+#ifdef CRTSCTS
+#ifdef CCTS_OFLOW
+ {"ccts_oflow", CCTS_OFLOW, MD_CTL},
+#else
+ {"crtscts", CRTSCTS, MD_CTL},
+#endif /* CCTS_OFLOW */
+#endif /* CRTSCTS */
+#ifdef CRTS_IFLOW
+ {"crts_iflow", CRTS_IFLOW, MD_CTL},
+#endif /* CRTS_IFLOW */
+#ifdef CDTRCTS
+ {"cdtrcts", CDTRCTS, MD_CTL},
+#endif /* CDTRCTS */
+#ifdef MDMBUF
+ {"mdmbuf", MDMBUF, MD_CTL},
+#endif /* MDMBUF */
+#ifdef RCV1EN
+ {"rcv1en", RCV1EN, MD_CTL},
+#endif /* RCV1EN */
+#ifdef XMT1EN
+ {"xmt1en", XMT1EN, MD_CTL},
+#endif /* XMT1EN */
+
+#ifdef ISIG
+ {"isig", ISIG, MD_LIN},
+#endif /* ISIG */
+#ifdef ICANON
+ {"icanon", ICANON, MD_LIN},
+#endif /* ICANON */
+#ifdef XCASE
+ {"xcase", XCASE, MD_LIN},
+#endif /* XCASE */
+#ifdef ECHO
+ {"echo", ECHO, MD_LIN},
+#endif /* ECHO */
+#ifdef ECHOE
+ {"echoe", ECHOE, MD_LIN},
+#endif /* ECHOE */
+#ifdef ECHOK
+ {"echok", ECHOK, MD_LIN},
+#endif /* ECHOK */
+#ifdef ECHONL
+ {"echonl", ECHONL, MD_LIN},
+#endif /* ECHONL */
+#ifdef NOFLSH
+ {"noflsh", NOFLSH, MD_LIN},
+#endif /* NOFLSH */
+#ifdef TOSTOP
+ {"tostop", TOSTOP, MD_LIN},
+#endif /* TOSTOP */
+#ifdef ECHOCTL
+ {"echoctl", ECHOCTL, MD_LIN},
+#endif /* ECHOCTL */
+#ifdef ECHOPRT
+ {"echoprt", ECHOPRT, MD_LIN},
+#endif /* ECHOPRT */
+#ifdef ECHOKE
+ {"echoke", ECHOKE, MD_LIN},
+#endif /* ECHOKE */
+#ifdef DEFECHO
+ {"defecho", DEFECHO, MD_LIN},
+#endif /* DEFECHO */
+#ifdef FLUSHO
+ {"flusho", FLUSHO, MD_LIN},
+#endif /* FLUSHO */
+#ifdef PENDIN
+ {"pendin", PENDIN, MD_LIN},
+#endif /* PENDIN */
+#ifdef IEXTEN
+ {"iexten", IEXTEN, MD_LIN},
+#endif /* IEXTEN */
+#ifdef NOKERNINFO
+ {"nokerninfo", NOKERNINFO, MD_LIN},
+#endif /* NOKERNINFO */
+#ifdef ALTWERASE
+ {"altwerase", ALTWERASE, MD_LIN},
+#endif /* ALTWERASE */
+#ifdef EXTPROC
+ {"extproc", EXTPROC, MD_LIN},
+#endif /* EXTPROC */
+
+#if defined(VINTR)
+ {"intr", C_SH(C_INTR), MD_CHAR},
+#endif /* VINTR */
+#if defined(VQUIT)
+ {"quit", C_SH(C_QUIT), MD_CHAR},
+#endif /* VQUIT */
+#if defined(VERASE)
+ {"erase", C_SH(C_ERASE), MD_CHAR},
+#endif /* VERASE */
+#if defined(VKILL)
+ {"kill", C_SH(C_KILL), MD_CHAR},
+#endif /* VKILL */
+#if defined(VEOF)
+ {"eof", C_SH(C_EOF), MD_CHAR},
+#endif /* VEOF */
+#if defined(VEOL)
+ {"eol", C_SH(C_EOL), MD_CHAR},
+#endif /* VEOL */
+#if defined(VEOL2)
+ {"eol2", C_SH(C_EOL2), MD_CHAR},
+#endif /* VEOL2 */
+#if defined(VSWTCH)
+ {"swtch", C_SH(C_SWTCH), MD_CHAR},
+#endif /* VSWTCH */
+#if defined(VDSWTCH)
+ {"dswtch", C_SH(C_DSWTCH), MD_CHAR},
+#endif /* VDSWTCH */
+#if defined(VERASE2)
+ {"erase2", C_SH(C_ERASE2), MD_CHAR},
+#endif /* VERASE2 */
+#if defined(VSTART)
+ {"start", C_SH(C_START), MD_CHAR},
+#endif /* VSTART */
+#if defined(VSTOP)
+ {"stop", C_SH(C_STOP), MD_CHAR},
+#endif /* VSTOP */
+#if defined(VWERASE)
+ {"werase", C_SH(C_WERASE), MD_CHAR},
+#endif /* VWERASE */
+#if defined(VSUSP)
+ {"susp", C_SH(C_SUSP), MD_CHAR},
+#endif /* VSUSP */
+#if defined(VDSUSP)
+ {"dsusp", C_SH(C_DSUSP), MD_CHAR},
+#endif /* VDSUSP */
+#if defined(VREPRINT)
+ {"reprint", C_SH(C_REPRINT), MD_CHAR},
+#endif /* VREPRINT */
+#if defined(VDISCARD)
+ {"discard", C_SH(C_DISCARD), MD_CHAR},
+#endif /* VDISCARD */
+#if defined(VLNEXT)
+ {"lnext", C_SH(C_LNEXT), MD_CHAR},
+#endif /* VLNEXT */
+#if defined(VSTATUS)
+ {"status", C_SH(C_STATUS), MD_CHAR},
+#endif /* VSTATUS */
+#if defined(VPAGE)
+ {"page", C_SH(C_PAGE), MD_CHAR},
+#endif /* VPAGE */
+#if defined(VPGOFF)
+ {"pgoff", C_SH(C_PGOFF), MD_CHAR},
+#endif /* VPGOFF */
+#if defined(VKILL2)
+ {"kill2", C_SH(C_KILL2), MD_CHAR},
+#endif /* VKILL2 */
+#if defined(VBRK)
+ {"brk", C_SH(C_BRK), MD_CHAR},
+#endif /* VBRK */
+#if defined(VMIN)
+ {"min", C_SH(C_MIN), MD_CHAR},
+#endif /* VMIN */
+#if defined(VTIME)
+ {"time", C_SH(C_TIME), MD_CHAR},
+#endif /* VTIME */
+ {NULL, 0, -1},
+};
+
+
+
+#define tty_getty(el, td) tcgetattr((el)->el_infd, (td))
+#define tty_setty(el, td) tcsetattr((el)->el_infd, TCSADRAIN, (td))
+
+#define tty__gettabs(td) ((((td)->c_oflag & TAB3) == TAB3) ? 0 : 1)
+#define tty__geteightbit(td) (((td)->c_cflag & CSIZE) == CS8)
+#define tty__cooked_mode(td) ((td)->c_lflag & ICANON)
+
+private int tty__getcharindex(int);
+private void tty__getchar(struct termios *, unsigned char *);
+private void tty__setchar(struct termios *, unsigned char *);
+private speed_t tty__getspeed(struct termios *);
+private int tty_setup(EditLine *);
+
+#define t_qu t_ts
+
+
+/* tty_setup():
+ * Get the tty parameters and initialize the editing state
+ */
+private int
+tty_setup(EditLine *el)
+{
+ int rst = 1;
+
+ if (el->el_flags & EDIT_DISABLED)
+ return (0);
+
+ if (tty_getty(el, &el->el_tty.t_ed) == -1) {
+#ifdef DEBUG_TTY
+ (void) fprintf(el->el_errfile,
+ "tty_setup: tty_getty: %s\n", strerror(errno));
+#endif /* DEBUG_TTY */
+ return (-1);
+ }
+ el->el_tty.t_ts = el->el_tty.t_ex = el->el_tty.t_ed;
+
+ el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ex);
+ el->el_tty.t_tabs = tty__gettabs(&el->el_tty.t_ex);
+ el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ex);
+
+ /*
+ * Reset the tty chars to reasonable defaults
+ * If they are disabled, then enable them.
+ */
+ if (rst) {
+ if (tty__cooked_mode(&el->el_tty.t_ts)) {
+ tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]);
+ /*
+ * Don't affect CMIN and CTIME for the editor mode
+ */
+ for (rst = 0; rst < C_NCC - 2; rst++)
+ if (el->el_tty.t_c[TS_IO][rst] !=
+ el->el_tty.t_vdisable
+ && el->el_tty.t_c[ED_IO][rst] !=
+ el->el_tty.t_vdisable)
+ el->el_tty.t_c[ED_IO][rst] =
+ el->el_tty.t_c[TS_IO][rst];
+ for (rst = 0; rst < C_NCC; rst++)
+ if (el->el_tty.t_c[TS_IO][rst] !=
+ el->el_tty.t_vdisable)
+ el->el_tty.t_c[EX_IO][rst] =
+ el->el_tty.t_c[TS_IO][rst];
+ }
+ }
+
+ el->el_tty.t_ed.c_iflag &= ~el->el_tty.t_t[ED_IO][MD_INP].t_clrmask;
+ el->el_tty.t_ed.c_iflag |= el->el_tty.t_t[ED_IO][MD_INP].t_setmask;
+
+ el->el_tty.t_ed.c_oflag &= ~el->el_tty.t_t[ED_IO][MD_OUT].t_clrmask;
+ el->el_tty.t_ed.c_oflag |= el->el_tty.t_t[ED_IO][MD_OUT].t_setmask;
+
+ el->el_tty.t_ed.c_cflag &= ~el->el_tty.t_t[ED_IO][MD_CTL].t_clrmask;
+ el->el_tty.t_ed.c_cflag |= el->el_tty.t_t[ED_IO][MD_CTL].t_setmask;
+
+ el->el_tty.t_ed.c_lflag &= ~el->el_tty.t_t[ED_IO][MD_LIN].t_clrmask;
+ el->el_tty.t_ed.c_lflag |= el->el_tty.t_t[ED_IO][MD_LIN].t_setmask;
+
+ tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]);
+ tty_bind_char(el, 1);
+ return (0);
+}
+
+protected int
+tty_init(EditLine *el)
+{
+
+ el->el_tty.t_mode = EX_IO;
+ el->el_tty.t_vdisable = _POSIX_VDISABLE;
+ (void) memcpy(el->el_tty.t_t, ttyperm, sizeof(ttyperm_t));
+ (void) memcpy(el->el_tty.t_c, ttychar, sizeof(ttychar_t));
+ return (tty_setup(el));
+}
+
+
+/* tty_end():
+ * Restore the tty to its original settings
+ */
+protected void
+/*ARGSUSED*/
+tty_end(EditLine *el __unused)
+{
+
+ /* XXX: Maybe reset to an initial state? */
+}
+
+
+/* tty__getspeed():
+ * Get the tty speed
+ */
+private speed_t
+tty__getspeed(struct termios *td)
+{
+ speed_t spd;
+
+ if ((spd = cfgetispeed(td)) == 0)
+ spd = cfgetospeed(td);
+ return (spd);
+}
+
+/* tty__getspeed():
+ * Return the index of the asked char in the c_cc array
+ */
+private int
+tty__getcharindex(int i)
+{
+ switch (i) {
+#ifdef VINTR
+ case C_INTR:
+ return VINTR;
+#endif /* VINTR */
+#ifdef VQUIT
+ case C_QUIT:
+ return VQUIT;
+#endif /* VQUIT */
+#ifdef VERASE
+ case C_ERASE:
+ return VERASE;
+#endif /* VERASE */
+#ifdef VKILL
+ case C_KILL:
+ return VKILL;
+#endif /* VKILL */
+#ifdef VEOF
+ case C_EOF:
+ return VEOF;
+#endif /* VEOF */
+#ifdef VEOL
+ case C_EOL:
+ return VEOL;
+#endif /* VEOL */
+#ifdef VEOL2
+ case C_EOL2:
+ return VEOL2;
+#endif /* VEOL2 */
+#ifdef VSWTCH
+ case C_SWTCH:
+ return VSWTCH;
+#endif /* VSWTCH */
+#ifdef VDSWTCH
+ case C_DSWTCH:
+ return VDSWTCH;
+#endif /* VDSWTCH */
+#ifdef VERASE2
+ case C_ERASE2:
+ return VERASE2;
+#endif /* VERASE2 */
+#ifdef VSTART
+ case C_START:
+ return VSTART;
+#endif /* VSTART */
+#ifdef VSTOP
+ case C_STOP:
+ return VSTOP;
+#endif /* VSTOP */
+#ifdef VWERASE
+ case C_WERASE:
+ return VWERASE;
+#endif /* VWERASE */
+#ifdef VSUSP
+ case C_SUSP:
+ return VSUSP;
+#endif /* VSUSP */
+#ifdef VDSUSP
+ case C_DSUSP:
+ return VDSUSP;
+#endif /* VDSUSP */
+#ifdef VREPRINT
+ case C_REPRINT:
+ return VREPRINT;
+#endif /* VREPRINT */
+#ifdef VDISCARD
+ case C_DISCARD:
+ return VDISCARD;
+#endif /* VDISCARD */
+#ifdef VLNEXT
+ case C_LNEXT:
+ return VLNEXT;
+#endif /* VLNEXT */
+#ifdef VSTATUS
+ case C_STATUS:
+ return VSTATUS;
+#endif /* VSTATUS */
+#ifdef VPAGE
+ case C_PAGE:
+ return VPAGE;
+#endif /* VPAGE */
+#ifdef VPGOFF
+ case C_PGOFF:
+ return VPGOFF;
+#endif /* VPGOFF */
+#ifdef VKILL2
+ case C_KILL2:
+ return VKILL2;
+#endif /* KILL2 */
+#ifdef VMIN
+ case C_MIN:
+ return VMIN;
+#endif /* VMIN */
+#ifdef VTIME
+ case C_TIME:
+ return VTIME;
+#endif /* VTIME */
+ default:
+ return -1;
+ }
+}
+
+/* tty__getchar():
+ * Get the tty characters
+ */
+private void
+tty__getchar(struct termios *td, unsigned char *s)
+{
+
+#ifdef VINTR
+ s[C_INTR] = td->c_cc[VINTR];
+#endif /* VINTR */
+#ifdef VQUIT
+ s[C_QUIT] = td->c_cc[VQUIT];
+#endif /* VQUIT */
+#ifdef VERASE
+ s[C_ERASE] = td->c_cc[VERASE];
+#endif /* VERASE */
+#ifdef VKILL
+ s[C_KILL] = td->c_cc[VKILL];
+#endif /* VKILL */
+#ifdef VEOF
+ s[C_EOF] = td->c_cc[VEOF];
+#endif /* VEOF */
+#ifdef VEOL
+ s[C_EOL] = td->c_cc[VEOL];
+#endif /* VEOL */
+#ifdef VEOL2
+ s[C_EOL2] = td->c_cc[VEOL2];
+#endif /* VEOL2 */
+#ifdef VSWTCH
+ s[C_SWTCH] = td->c_cc[VSWTCH];
+#endif /* VSWTCH */
+#ifdef VDSWTCH
+ s[C_DSWTCH] = td->c_cc[VDSWTCH];
+#endif /* VDSWTCH */
+#ifdef VERASE2
+ s[C_ERASE2] = td->c_cc[VERASE2];
+#endif /* VERASE2 */
+#ifdef VSTART
+ s[C_START] = td->c_cc[VSTART];
+#endif /* VSTART */
+#ifdef VSTOP
+ s[C_STOP] = td->c_cc[VSTOP];
+#endif /* VSTOP */
+#ifdef VWERASE
+ s[C_WERASE] = td->c_cc[VWERASE];
+#endif /* VWERASE */
+#ifdef VSUSP
+ s[C_SUSP] = td->c_cc[VSUSP];
+#endif /* VSUSP */
+#ifdef VDSUSP
+ s[C_DSUSP] = td->c_cc[VDSUSP];
+#endif /* VDSUSP */
+#ifdef VREPRINT
+ s[C_REPRINT] = td->c_cc[VREPRINT];
+#endif /* VREPRINT */
+#ifdef VDISCARD
+ s[C_DISCARD] = td->c_cc[VDISCARD];
+#endif /* VDISCARD */
+#ifdef VLNEXT
+ s[C_LNEXT] = td->c_cc[VLNEXT];
+#endif /* VLNEXT */
+#ifdef VSTATUS
+ s[C_STATUS] = td->c_cc[VSTATUS];
+#endif /* VSTATUS */
+#ifdef VPAGE
+ s[C_PAGE] = td->c_cc[VPAGE];
+#endif /* VPAGE */
+#ifdef VPGOFF
+ s[C_PGOFF] = td->c_cc[VPGOFF];
+#endif /* VPGOFF */
+#ifdef VKILL2
+ s[C_KILL2] = td->c_cc[VKILL2];
+#endif /* KILL2 */
+#ifdef VMIN
+ s[C_MIN] = td->c_cc[VMIN];
+#endif /* VMIN */
+#ifdef VTIME
+ s[C_TIME] = td->c_cc[VTIME];
+#endif /* VTIME */
+} /* tty__getchar */
+
+
+/* tty__setchar():
+ * Set the tty characters
+ */
+private void
+tty__setchar(struct termios *td, unsigned char *s)
+{
+
+#ifdef VINTR
+ td->c_cc[VINTR] = s[C_INTR];
+#endif /* VINTR */
+#ifdef VQUIT
+ td->c_cc[VQUIT] = s[C_QUIT];
+#endif /* VQUIT */
+#ifdef VERASE
+ td->c_cc[VERASE] = s[C_ERASE];
+#endif /* VERASE */
+#ifdef VKILL
+ td->c_cc[VKILL] = s[C_KILL];
+#endif /* VKILL */
+#ifdef VEOF
+ td->c_cc[VEOF] = s[C_EOF];
+#endif /* VEOF */
+#ifdef VEOL
+ td->c_cc[VEOL] = s[C_EOL];
+#endif /* VEOL */
+#ifdef VEOL2
+ td->c_cc[VEOL2] = s[C_EOL2];
+#endif /* VEOL2 */
+#ifdef VSWTCH
+ td->c_cc[VSWTCH] = s[C_SWTCH];
+#endif /* VSWTCH */
+#ifdef VDSWTCH
+ td->c_cc[VDSWTCH] = s[C_DSWTCH];
+#endif /* VDSWTCH */
+#ifdef VERASE2
+ td->c_cc[VERASE2] = s[C_ERASE2];
+#endif /* VERASE2 */
+#ifdef VSTART
+ td->c_cc[VSTART] = s[C_START];
+#endif /* VSTART */
+#ifdef VSTOP
+ td->c_cc[VSTOP] = s[C_STOP];
+#endif /* VSTOP */
+#ifdef VWERASE
+ td->c_cc[VWERASE] = s[C_WERASE];
+#endif /* VWERASE */
+#ifdef VSUSP
+ td->c_cc[VSUSP] = s[C_SUSP];
+#endif /* VSUSP */
+#ifdef VDSUSP
+ td->c_cc[VDSUSP] = s[C_DSUSP];
+#endif /* VDSUSP */
+#ifdef VREPRINT
+ td->c_cc[VREPRINT] = s[C_REPRINT];
+#endif /* VREPRINT */
+#ifdef VDISCARD
+ td->c_cc[VDISCARD] = s[C_DISCARD];
+#endif /* VDISCARD */
+#ifdef VLNEXT
+ td->c_cc[VLNEXT] = s[C_LNEXT];
+#endif /* VLNEXT */
+#ifdef VSTATUS
+ td->c_cc[VSTATUS] = s[C_STATUS];
+#endif /* VSTATUS */
+#ifdef VPAGE
+ td->c_cc[VPAGE] = s[C_PAGE];
+#endif /* VPAGE */
+#ifdef VPGOFF
+ td->c_cc[VPGOFF] = s[C_PGOFF];
+#endif /* VPGOFF */
+#ifdef VKILL2
+ td->c_cc[VKILL2] = s[C_KILL2];
+#endif /* VKILL2 */
+#ifdef VMIN
+ td->c_cc[VMIN] = s[C_MIN];
+#endif /* VMIN */
+#ifdef VTIME
+ td->c_cc[VTIME] = s[C_TIME];
+#endif /* VTIME */
+} /* tty__setchar */
+
+
+/* tty_bind_char():
+ * Rebind the editline functions
+ */
+protected void
+tty_bind_char(EditLine *el, int force)
+{
+
+ unsigned char *t_n = el->el_tty.t_c[ED_IO];
+ unsigned char *t_o = el->el_tty.t_ed.c_cc;
+ unsigned char new[2], old[2];
+ const ttymap_t *tp;
+ el_action_t *map, *alt;
+ const el_action_t *dmap, *dalt;
+ new[1] = old[1] = '\0';
+
+ map = el->el_map.key;
+ alt = el->el_map.alt;
+ if (el->el_map.type == MAP_VI) {
+ dmap = el->el_map.vii;
+ dalt = el->el_map.vic;
+ } else {
+ dmap = el->el_map.emacs;
+ dalt = NULL;
+ }
+
+ for (tp = tty_map; tp->nch != -1; tp++) {
+ new[0] = t_n[tp->nch];
+ old[0] = t_o[tp->och];
+ if (new[0] == old[0] && !force)
+ continue;
+ /* Put the old default binding back, and set the new binding */
+ key_clear(el, map, (char *)old);
+ map[old[0]] = dmap[old[0]];
+ key_clear(el, map, (char *)new);
+ /* MAP_VI == 1, MAP_EMACS == 0... */
+ map[new[0]] = tp->bind[el->el_map.type];
+ if (dalt) {
+ key_clear(el, alt, (char *)old);
+ alt[old[0]] = dalt[old[0]];
+ key_clear(el, alt, (char *)new);
+ alt[new[0]] = tp->bind[el->el_map.type + 1];
+ }
+ }
+}
+
+
+/* tty_rawmode():
+ * Set terminal into 1 character at a time mode.
+ */
+protected int
+tty_rawmode(EditLine *el)
+{
+
+ if (el->el_tty.t_mode == ED_IO || el->el_tty.t_mode == QU_IO)
+ return (0);
+
+ if (el->el_flags & EDIT_DISABLED)
+ return (0);
+
+ if (tty_getty(el, &el->el_tty.t_ts) == -1) {
+#ifdef DEBUG_TTY
+ (void) fprintf(el->el_errfile, "tty_rawmode: tty_getty: %s\n",
+ strerror(errno));
+#endif /* DEBUG_TTY */
+ return (-1);
+ }
+ /*
+ * We always keep up with the eight bit setting and the speed of the
+ * tty. But only we only believe changes that are made to cooked mode!
+ */
+ el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ts);
+ el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ts);
+
+ if (tty__getspeed(&el->el_tty.t_ed) != el->el_tty.t_speed) {
+ (void) cfsetispeed(&el->el_tty.t_ed, el->el_tty.t_speed);
+ (void) cfsetospeed(&el->el_tty.t_ed, el->el_tty.t_speed);
+ }
+ if (tty__cooked_mode(&el->el_tty.t_ts)) {
+ if ((el->el_tty.t_ts.c_cflag != el->el_tty.t_ex.c_cflag) &&
+ (el->el_tty.t_ts.c_cflag != el->el_tty.t_ed.c_cflag)) {
+ el->el_tty.t_ed.c_cflag =
+ el->el_tty.t_ts.c_cflag;
+ el->el_tty.t_ed.c_cflag &=
+ ~el->el_tty.t_t[ED_IO][MD_CTL].t_clrmask;
+ el->el_tty.t_ed.c_cflag |=
+ el->el_tty.t_t[ED_IO][MD_CTL].t_setmask;
+ }
+ if ((el->el_tty.t_ts.c_lflag != el->el_tty.t_ex.c_lflag) &&
+ (el->el_tty.t_ts.c_lflag != el->el_tty.t_ed.c_lflag)) {
+ el->el_tty.t_ed.c_lflag =
+ el->el_tty.t_ts.c_lflag;
+ el->el_tty.t_ed.c_lflag &=
+ ~el->el_tty.t_t[ED_IO][MD_LIN].t_clrmask;
+ el->el_tty.t_ed.c_lflag |=
+ el->el_tty.t_t[ED_IO][MD_LIN].t_setmask;
+ }
+ if ((el->el_tty.t_ts.c_iflag != el->el_tty.t_ex.c_iflag) &&
+ (el->el_tty.t_ts.c_iflag != el->el_tty.t_ed.c_iflag)) {
+ el->el_tty.t_ed.c_iflag =
+ el->el_tty.t_ts.c_iflag;
+ el->el_tty.t_ed.c_iflag &=
+ ~el->el_tty.t_t[ED_IO][MD_INP].t_clrmask;
+ el->el_tty.t_ed.c_iflag |=
+ el->el_tty.t_t[ED_IO][MD_INP].t_setmask;
+ }
+ if ((el->el_tty.t_ts.c_oflag != el->el_tty.t_ex.c_oflag) &&
+ (el->el_tty.t_ts.c_oflag != el->el_tty.t_ed.c_oflag)) {
+ el->el_tty.t_ed.c_oflag =
+ el->el_tty.t_ts.c_oflag;
+ el->el_tty.t_ed.c_oflag &=
+ ~el->el_tty.t_t[ED_IO][MD_OUT].t_clrmask;
+ el->el_tty.t_ed.c_oflag |=
+ el->el_tty.t_t[ED_IO][MD_OUT].t_setmask;
+ }
+ if (tty__gettabs(&el->el_tty.t_ex) == 0)
+ el->el_tty.t_tabs = 0;
+ else
+ el->el_tty.t_tabs = EL_CAN_TAB ? 1 : 0;
+
+ {
+ int i;
+
+ tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]);
+ /*
+ * Check if the user made any changes.
+ * If he did, then propagate the changes to the
+ * edit and execute data structures.
+ */
+ for (i = 0; i < C_NCC; i++)
+ if (el->el_tty.t_c[TS_IO][i] !=
+ el->el_tty.t_c[EX_IO][i])
+ break;
+
+ if (i != C_NCC) {
+ /*
+ * Propagate changes only to the unprotected
+ * chars that have been modified just now.
+ */
+ for (i = 0; i < C_NCC; i++) {
+ if (!((el->el_tty.t_t[ED_IO][MD_CHAR].t_setmask & C_SH(i)))
+ && (el->el_tty.t_c[TS_IO][i] != el->el_tty.t_c[EX_IO][i]))
+ el->el_tty.t_c[ED_IO][i] = el->el_tty.t_c[TS_IO][i];
+ if (el->el_tty.t_t[ED_IO][MD_CHAR].t_clrmask & C_SH(i))
+ el->el_tty.t_c[ED_IO][i] = el->el_tty.t_vdisable;
+ }
+ tty_bind_char(el, 0);
+ tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]);
+
+ for (i = 0; i < C_NCC; i++) {
+ if (!((el->el_tty.t_t[EX_IO][MD_CHAR].t_setmask & C_SH(i)))
+ && (el->el_tty.t_c[TS_IO][i] != el->el_tty.t_c[EX_IO][i]))
+ el->el_tty.t_c[EX_IO][i] = el->el_tty.t_c[TS_IO][i];
+ if (el->el_tty.t_t[EX_IO][MD_CHAR].t_clrmask & C_SH(i))
+ el->el_tty.t_c[EX_IO][i] = el->el_tty.t_vdisable;
+ }
+ }
+ }
+ }
+
+ if (el->el_tty.t_mode == EX_IO)
+ el->el_tty.t_ex = el->el_tty.t_ts;
+
+ if (tty_setty(el, &el->el_tty.t_ed) == -1) {
+#ifdef DEBUG_TTY
+ (void) fprintf(el->el_errfile, "tty_rawmode: tty_setty: %s\n",
+ strerror(errno));
+#endif /* DEBUG_TTY */
+ return (-1);
+ }
+ el->el_tty.t_mode = ED_IO;
+ return (0);
+}
+
+
+/* tty_cookedmode():
+ * Set the tty back to normal mode
+ */
+protected int
+tty_cookedmode(EditLine *el)
+{ /* set tty in normal setup */
+
+ if (el->el_tty.t_mode == EX_IO)
+ return (0);
+
+ if (el->el_flags & EDIT_DISABLED)
+ return (0);
+
+ if (tty_setty(el, &el->el_tty.t_ex) == -1) {
+#ifdef DEBUG_TTY
+ (void) fprintf(el->el_errfile,
+ "tty_cookedmode: tty_setty: %s\n",
+ strerror(errno));
+#endif /* DEBUG_TTY */
+ return (-1);
+ }
+ el->el_tty.t_mode = EX_IO;
+ return (0);
+}
+
+
+/* tty_quotemode():
+ * Turn on quote mode
+ */
+protected int
+tty_quotemode(EditLine *el)
+{
+ if (el->el_tty.t_mode == QU_IO)
+ return (0);
+
+ el->el_tty.t_qu = el->el_tty.t_ed;
+
+ el->el_tty.t_qu.c_iflag &= ~el->el_tty.t_t[QU_IO][MD_INP].t_clrmask;
+ el->el_tty.t_qu.c_iflag |= el->el_tty.t_t[QU_IO][MD_INP].t_setmask;
+
+ el->el_tty.t_qu.c_oflag &= ~el->el_tty.t_t[QU_IO][MD_OUT].t_clrmask;
+ el->el_tty.t_qu.c_oflag |= el->el_tty.t_t[QU_IO][MD_OUT].t_setmask;
+
+ el->el_tty.t_qu.c_cflag &= ~el->el_tty.t_t[QU_IO][MD_CTL].t_clrmask;
+ el->el_tty.t_qu.c_cflag |= el->el_tty.t_t[QU_IO][MD_CTL].t_setmask;
+
+ el->el_tty.t_qu.c_lflag &= ~el->el_tty.t_t[QU_IO][MD_LIN].t_clrmask;
+ el->el_tty.t_qu.c_lflag |= el->el_tty.t_t[QU_IO][MD_LIN].t_setmask;
+
+ if (tty_setty(el, &el->el_tty.t_qu) == -1) {
+#ifdef DEBUG_TTY
+ (void) fprintf(el->el_errfile, "QuoteModeOn: tty_setty: %s\n",
+ strerror(errno));
+#endif /* DEBUG_TTY */
+ return (-1);
+ }
+ el->el_tty.t_mode = QU_IO;
+ return (0);
+}
+
+
+/* tty_noquotemode():
+ * Turn off quote mode
+ */
+protected int
+tty_noquotemode(EditLine *el)
+{
+
+ if (el->el_tty.t_mode != QU_IO)
+ return (0);
+ if (tty_setty(el, &el->el_tty.t_ed) == -1) {
+#ifdef DEBUG_TTY
+ (void) fprintf(el->el_errfile, "QuoteModeOff: tty_setty: %s\n",
+ strerror(errno));
+#endif /* DEBUG_TTY */
+ return (-1);
+ }
+ el->el_tty.t_mode = ED_IO;
+ return (0);
+}
+
+
+/* tty_stty():
+ * Stty builtin
+ */
+protected int
+/*ARGSUSED*/
+tty_stty(EditLine *el, int argc __unused, const char **argv)
+{
+ const ttymodes_t *m;
+ char x;
+ int aflag = 0;
+ const char *s, *d;
+ const char *name;
+ struct termios *tios = &el->el_tty.t_ex;
+ int z = EX_IO;
+
+ if (argv == NULL)
+ return (-1);
+ name = *argv++;
+
+ while (argv && *argv && argv[0][0] == '-' && argv[0][2] == '\0')
+ switch (argv[0][1]) {
+ case 'a':
+ aflag++;
+ argv++;
+ break;
+ case 'd':
+ argv++;
+ tios = &el->el_tty.t_ed;
+ z = ED_IO;
+ break;
+ case 'x':
+ argv++;
+ tios = &el->el_tty.t_ex;
+ z = EX_IO;
+ break;
+ case 'q':
+ argv++;
+ tios = &el->el_tty.t_ts;
+ z = QU_IO;
+ break;
+ default:
+ (void) fprintf(el->el_errfile,
+ "%s: Unknown switch `%c'.\n",
+ name, argv[0][1]);
+ return (-1);
+ }
+
+ if (!argv || !*argv) {
+ int i = -1;
+ int len = 0, st = 0, cu;
+ for (m = ttymodes; m->m_name; m++) {
+ if (m->m_type != i) {
+ (void) fprintf(el->el_outfile, "%s%s",
+ i != -1 ? "\n" : "",
+ el->el_tty.t_t[z][m->m_type].t_name);
+ i = m->m_type;
+ st = len =
+ strlen(el->el_tty.t_t[z][m->m_type].t_name);
+ }
+ x = (el->el_tty.t_t[z][i].t_setmask & m->m_value)
+ ? '+' : '\0';
+ x = (el->el_tty.t_t[z][i].t_clrmask & m->m_value)
+ ? '-' : x;
+
+ if (x != '\0' || aflag) {
+
+ cu = strlen(m->m_name) + (x != '\0') + 1;
+
+ if (len + cu >= el->el_term.t_size.h) {
+ (void) fprintf(el->el_outfile, "\n%*s",
+ st, "");
+ len = st + cu;
+ } else
+ len += cu;
+
+ if (x != '\0')
+ (void) fprintf(el->el_outfile, "%c%s ",
+ x, m->m_name);
+ else
+ (void) fprintf(el->el_outfile, "%s ",
+ m->m_name);
+ }
+ }
+ (void) fprintf(el->el_outfile, "\n");
+ return (0);
+ }
+ while (argv && (s = *argv++)) {
+ const char *p;
+ switch (*s) {
+ case '+':
+ case '-':
+ x = *s++;
+ break;
+ default:
+ x = '\0';
+ break;
+ }
+ d = s;
+ p = strchr(s, '=');
+ for (m = ttymodes; m->m_name; m++)
+ if ((p ? strncmp(m->m_name, d, (size_t)(p - d)) :
+ strcmp(m->m_name, d)) == 0 &&
+ (p == NULL || m->m_type == MD_CHAR))
+ break;
+
+ if (!m->m_name) {
+ (void) fprintf(el->el_errfile,
+ "%s: Invalid argument `%s'.\n", name, d);
+ return (-1);
+ }
+ if (p) {
+ int c = ffs((int)m->m_value);
+ int v = *++p ? parse__escape((const char **) &p) :
+ el->el_tty.t_vdisable;
+ assert(c-- != 0);
+ c = tty__getcharindex(c);
+ assert(c != -1);
+ tios->c_cc[c] = v;
+ continue;
+ }
+ switch (x) {
+ case '+':
+ el->el_tty.t_t[z][m->m_type].t_setmask |= m->m_value;
+ el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value;
+ break;
+ case '-':
+ el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value;
+ el->el_tty.t_t[z][m->m_type].t_clrmask |= m->m_value;
+ break;
+ default:
+ el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value;
+ el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value;
+ break;
+ }
+ }
+ return (0);
+}
+
+
+#ifdef notyet
+/* tty_printchar():
+ * DEbugging routine to print the tty characters
+ */
+private void
+tty_printchar(EditLine *el, unsigned char *s)
+{
+ ttyperm_t *m;
+ int i;
+
+ for (i = 0; i < C_NCC; i++) {
+ for (m = el->el_tty.t_t; m->m_name; m++)
+ if (m->m_type == MD_CHAR && C_SH(i) == m->m_value)
+ break;
+ if (m->m_name)
+ (void) fprintf(el->el_errfile, "%s ^%c ",
+ m->m_name, s[i] + 'A' - 1);
+ if (i % 5 == 0)
+ (void) fprintf(el->el_errfile, "\n");
+ }
+ (void) fprintf(el->el_errfile, "\n");
+}
+#endif /* notyet */
diff --git a/lib/libedit/tty.h b/lib/libedit/tty.h
new file mode 100644
index 0000000..3a4e94a
--- /dev/null
+++ b/lib/libedit/tty.h
@@ -0,0 +1,480 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell 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.
+ *
+ * @(#)tty.h 8.1 (Berkeley) 6/4/93
+ * $NetBSD: tty.h,v 1.11 2005/06/01 11:37:52 lukem Exp $
+ * $FreeBSD$
+ */
+
+/*
+ * el.tty.h: Local terminal header
+ */
+#ifndef _h_el_tty
+#define _h_el_tty
+
+#include "histedit.h"
+#include <termios.h>
+#include <unistd.h>
+
+/* Define our own since everyone gets it wrong! */
+#define CONTROL(A) ((A) & 037)
+
+/*
+ * Aix compatible names
+ */
+# if defined(VWERSE) && !defined(VWERASE)
+# define VWERASE VWERSE
+# endif /* VWERSE && !VWERASE */
+
+# if defined(VDISCRD) && !defined(VDISCARD)
+# define VDISCARD VDISCRD
+# endif /* VDISCRD && !VDISCARD */
+
+# if defined(VFLUSHO) && !defined(VDISCARD)
+# define VDISCARD VFLUSHO
+# endif /* VFLUSHO && VDISCARD */
+
+# if defined(VSTRT) && !defined(VSTART)
+# define VSTART VSTRT
+# endif /* VSTRT && ! VSTART */
+
+# if defined(VSTAT) && !defined(VSTATUS)
+# define VSTATUS VSTAT
+# endif /* VSTAT && ! VSTATUS */
+
+# ifndef ONLRET
+# define ONLRET 0
+# endif /* ONLRET */
+
+# ifndef TAB3
+# ifdef OXTABS
+# define TAB3 OXTABS
+# else
+# define TAB3 0
+# endif /* OXTABS */
+# endif /* !TAB3 */
+
+# if defined(OXTABS) && !defined(XTABS)
+# define XTABS OXTABS
+# endif /* OXTABS && !XTABS */
+
+# ifndef ONLCR
+# define ONLCR 0
+# endif /* ONLCR */
+
+# ifndef IEXTEN
+# define IEXTEN 0
+# endif /* IEXTEN */
+
+# ifndef ECHOCTL
+# define ECHOCTL 0
+# endif /* ECHOCTL */
+
+# ifndef PARENB
+# define PARENB 0
+# endif /* PARENB */
+
+# ifndef EXTPROC
+# define EXTPROC 0
+# endif /* EXTPROC */
+
+# ifndef FLUSHO
+# define FLUSHO 0
+# endif /* FLUSHO */
+
+
+# if defined(VDISABLE) && !defined(_POSIX_VDISABLE)
+# define _POSIX_VDISABLE VDISABLE
+# endif /* VDISABLE && ! _POSIX_VDISABLE */
+
+/*
+ * Work around ISC's definition of IEXTEN which is
+ * XCASE!
+ */
+# ifdef ISC
+# if defined(IEXTEN) && defined(XCASE)
+# if IEXTEN == XCASE
+# undef IEXTEN
+# define IEXTEN 0
+# endif /* IEXTEN == XCASE */
+# endif /* IEXTEN && XCASE */
+# if defined(IEXTEN) && !defined(XCASE)
+# define XCASE IEXTEN
+# undef IEXTEN
+# define IEXTEN 0
+# endif /* IEXTEN && !XCASE */
+# endif /* ISC */
+
+/*
+ * Work around convex weirdness where turning off IEXTEN makes us
+ * lose all postprocessing!
+ */
+#if defined(convex) || defined(__convex__)
+# if defined(IEXTEN) && IEXTEN != 0
+# undef IEXTEN
+# define IEXTEN 0
+# endif /* IEXTEN != 0 */
+#endif /* convex || __convex__ */
+
+/*
+ * So that we don't lose job control.
+ */
+#ifdef __SVR4
+# undef CSWTCH
+#endif
+
+#ifndef _POSIX_VDISABLE
+# define _POSIX_VDISABLE ((unsigned char) -1)
+#endif /* _POSIX_VDISABLE */
+
+#if !defined(CREPRINT) && defined(CRPRNT)
+# define CREPRINT CRPRNT
+#endif /* !CREPRINT && CRPRNT */
+#if !defined(CDISCARD) && defined(CFLUSH)
+# define CDISCARD CFLUSH
+#endif /* !CDISCARD && CFLUSH */
+
+#ifndef CINTR
+# define CINTR CONTROL('c')
+#endif /* CINTR */
+#ifndef CQUIT
+# define CQUIT 034 /* ^\ */
+#endif /* CQUIT */
+#ifndef CERASE
+# define CERASE 0177 /* ^? */
+#endif /* CERASE */
+#ifndef CKILL
+# define CKILL CONTROL('u')
+#endif /* CKILL */
+#ifndef CEOF
+# define CEOF CONTROL('d')
+#endif /* CEOF */
+#ifndef CEOL
+# define CEOL _POSIX_VDISABLE
+#endif /* CEOL */
+#ifndef CEOL2
+# define CEOL2 _POSIX_VDISABLE
+#endif /* CEOL2 */
+#ifndef CSWTCH
+# define CSWTCH _POSIX_VDISABLE
+#endif /* CSWTCH */
+#ifndef CDSWTCH
+# define CDSWTCH _POSIX_VDISABLE
+#endif /* CDSWTCH */
+#ifndef CERASE2
+# define CERASE2 _POSIX_VDISABLE
+#endif /* CERASE2 */
+#ifndef CSTART
+# define CSTART CONTROL('q')
+#endif /* CSTART */
+#ifndef CSTOP
+# define CSTOP CONTROL('s')
+#endif /* CSTOP */
+#ifndef CSUSP
+# define CSUSP CONTROL('z')
+#endif /* CSUSP */
+#ifndef CDSUSP
+# define CDSUSP CONTROL('y')
+#endif /* CDSUSP */
+
+#ifdef hpux
+
+# ifndef CREPRINT
+# define CREPRINT _POSIX_VDISABLE
+# endif /* CREPRINT */
+# ifndef CDISCARD
+# define CDISCARD _POSIX_VDISABLE
+# endif /* CDISCARD */
+# ifndef CLNEXT
+# define CLNEXT _POSIX_VDISABLE
+# endif /* CLNEXT */
+# ifndef CWERASE
+# define CWERASE _POSIX_VDISABLE
+# endif /* CWERASE */
+
+#else /* !hpux */
+
+# ifndef CREPRINT
+# define CREPRINT CONTROL('r')
+# endif /* CREPRINT */
+# ifndef CDISCARD
+# define CDISCARD CONTROL('o')
+# endif /* CDISCARD */
+# ifndef CLNEXT
+# define CLNEXT CONTROL('v')
+# endif /* CLNEXT */
+# ifndef CWERASE
+# define CWERASE CONTROL('w')
+# endif /* CWERASE */
+
+#endif /* hpux */
+
+#ifndef CSTATUS
+# define CSTATUS CONTROL('t')
+#endif /* CSTATUS */
+#ifndef CPAGE
+# define CPAGE ' '
+#endif /* CPAGE */
+#ifndef CPGOFF
+# define CPGOFF CONTROL('m')
+#endif /* CPGOFF */
+#ifndef CKILL2
+# define CKILL2 _POSIX_VDISABLE
+#endif /* CKILL2 */
+#ifndef CBRK
+# ifndef masscomp
+# define CBRK 0377
+# else
+# define CBRK '\0'
+# endif /* masscomp */
+#endif /* CBRK */
+#ifndef CMIN
+# define CMIN CEOF
+#endif /* CMIN */
+#ifndef CTIME
+# define CTIME CEOL
+#endif /* CTIME */
+
+/*
+ * Fix for sun inconsistency. On termio VSUSP and the rest of the
+ * ttychars > NCC are defined. So we undefine them.
+ */
+#if defined(TERMIO) || defined(POSIX)
+# if defined(POSIX) && defined(NCCS)
+# define NUMCC NCCS
+# else
+# ifdef NCC
+# define NUMCC NCC
+# endif /* NCC */
+# endif /* POSIX && NCCS */
+# ifdef NUMCC
+# ifdef VINTR
+# if NUMCC <= VINTR
+# undef VINTR
+# endif /* NUMCC <= VINTR */
+# endif /* VINTR */
+# ifdef VQUIT
+# if NUMCC <= VQUIT
+# undef VQUIT
+# endif /* NUMCC <= VQUIT */
+# endif /* VQUIT */
+# ifdef VERASE
+# if NUMCC <= VERASE
+# undef VERASE
+# endif /* NUMCC <= VERASE */
+# endif /* VERASE */
+# ifdef VKILL
+# if NUMCC <= VKILL
+# undef VKILL
+# endif /* NUMCC <= VKILL */
+# endif /* VKILL */
+# ifdef VEOF
+# if NUMCC <= VEOF
+# undef VEOF
+# endif /* NUMCC <= VEOF */
+# endif /* VEOF */
+# ifdef VEOL
+# if NUMCC <= VEOL
+# undef VEOL
+# endif /* NUMCC <= VEOL */
+# endif /* VEOL */
+# ifdef VEOL2
+# if NUMCC <= VEOL2
+# undef VEOL2
+# endif /* NUMCC <= VEOL2 */
+# endif /* VEOL2 */
+# ifdef VSWTCH
+# if NUMCC <= VSWTCH
+# undef VSWTCH
+# endif /* NUMCC <= VSWTCH */
+# endif /* VSWTCH */
+# ifdef VDSWTCH
+# if NUMCC <= VDSWTCH
+# undef VDSWTCH
+# endif /* NUMCC <= VDSWTCH */
+# endif /* VDSWTCH */
+# ifdef VERASE2
+# if NUMCC <= VERASE2
+# undef VERASE2
+# endif /* NUMCC <= VERASE2 */
+# endif /* VERASE2 */
+# ifdef VSTART
+# if NUMCC <= VSTART
+# undef VSTART
+# endif /* NUMCC <= VSTART */
+# endif /* VSTART */
+# ifdef VSTOP
+# if NUMCC <= VSTOP
+# undef VSTOP
+# endif /* NUMCC <= VSTOP */
+# endif /* VSTOP */
+# ifdef VWERASE
+# if NUMCC <= VWERASE
+# undef VWERASE
+# endif /* NUMCC <= VWERASE */
+# endif /* VWERASE */
+# ifdef VSUSP
+# if NUMCC <= VSUSP
+# undef VSUSP
+# endif /* NUMCC <= VSUSP */
+# endif /* VSUSP */
+# ifdef VDSUSP
+# if NUMCC <= VDSUSP
+# undef VDSUSP
+# endif /* NUMCC <= VDSUSP */
+# endif /* VDSUSP */
+# ifdef VREPRINT
+# if NUMCC <= VREPRINT
+# undef VREPRINT
+# endif /* NUMCC <= VREPRINT */
+# endif /* VREPRINT */
+# ifdef VDISCARD
+# if NUMCC <= VDISCARD
+# undef VDISCARD
+# endif /* NUMCC <= VDISCARD */
+# endif /* VDISCARD */
+# ifdef VLNEXT
+# if NUMCC <= VLNEXT
+# undef VLNEXT
+# endif /* NUMCC <= VLNEXT */
+# endif /* VLNEXT */
+# ifdef VSTATUS
+# if NUMCC <= VSTATUS
+# undef VSTATUS
+# endif /* NUMCC <= VSTATUS */
+# endif /* VSTATUS */
+# ifdef VPAGE
+# if NUMCC <= VPAGE
+# undef VPAGE
+# endif /* NUMCC <= VPAGE */
+# endif /* VPAGE */
+# ifdef VPGOFF
+# if NUMCC <= VPGOFF
+# undef VPGOFF
+# endif /* NUMCC <= VPGOFF */
+# endif /* VPGOFF */
+# ifdef VKILL2
+# if NUMCC <= VKILL2
+# undef VKILL2
+# endif /* NUMCC <= VKILL2 */
+# endif /* VKILL2 */
+# ifdef VBRK
+# if NUMCC <= VBRK
+# undef VBRK
+# endif /* NUMCC <= VBRK */
+# endif /* VBRK */
+# ifdef VMIN
+# if NUMCC <= VMIN
+# undef VMIN
+# endif /* NUMCC <= VMIN */
+# endif /* VMIN */
+# ifdef VTIME
+# if NUMCC <= VTIME
+# undef VTIME
+# endif /* NUMCC <= VTIME */
+# endif /* VTIME */
+# endif /* NUMCC */
+#endif /* !POSIX */
+
+#define C_INTR 0
+#define C_QUIT 1
+#define C_ERASE 2
+#define C_KILL 3
+#define C_EOF 4
+#define C_EOL 5
+#define C_EOL2 6
+#define C_SWTCH 7
+#define C_DSWTCH 8
+#define C_ERASE2 9
+#define C_START 10
+#define C_STOP 11
+#define C_WERASE 12
+#define C_SUSP 13
+#define C_DSUSP 14
+#define C_REPRINT 15
+#define C_DISCARD 16
+#define C_LNEXT 17
+#define C_STATUS 18
+#define C_PAGE 19
+#define C_PGOFF 20
+#define C_KILL2 21
+#define C_BRK 22
+#define C_MIN 23
+#define C_TIME 24
+#define C_NCC 25
+#define C_SH(A) (1 << (A))
+
+/*
+ * Terminal dependend data structures
+ */
+#define EX_IO 0 /* while we are executing */
+#define ED_IO 1 /* while we are editing */
+#define TS_IO 2 /* new mode from terminal */
+#define QU_IO 2 /* used only for quoted chars */
+#define NN_IO 3 /* The number of entries */
+
+#define MD_INP 0
+#define MD_OUT 1
+#define MD_CTL 2
+#define MD_LIN 3
+#define MD_CHAR 4
+#define MD_NN 5
+
+typedef struct {
+ const char *t_name;
+ unsigned int t_setmask;
+ unsigned int t_clrmask;
+} ttyperm_t[NN_IO][MD_NN];
+
+typedef unsigned char ttychar_t[NN_IO][C_NCC];
+
+protected int tty_init(EditLine *);
+protected void tty_end(EditLine *);
+protected int tty_stty(EditLine *, int, const char **);
+protected int tty_rawmode(EditLine *);
+protected int tty_cookedmode(EditLine *);
+protected int tty_quotemode(EditLine *);
+protected int tty_noquotemode(EditLine *);
+protected void tty_bind_char(EditLine *, int);
+
+typedef struct {
+ ttyperm_t t_t;
+ ttychar_t t_c;
+ struct termios t_ex, t_ed, t_ts;
+ int t_tabs;
+ int t_eight;
+ speed_t t_speed;
+ int t_mode;
+ unsigned char t_vdisable;
+} el_tty_t;
+
+
+#endif /* _h_el_tty */
diff --git a/lib/libedit/vi.c b/lib/libedit/vi.c
new file mode 100644
index 0000000..2d611fb
--- /dev/null
+++ b/lib/libedit/vi.c
@@ -0,0 +1,1120 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Christos Zoulas of Cornell 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.
+ *
+ * $NetBSD: vi.c,v 1.24 2005/08/10 12:46:24 christos Exp $
+ */
+
+#if !defined(lint) && !defined(SCCSID)
+static char sccsid[] = "@(#)vi.c 8.1 (Berkeley) 6/4/93";
+#endif /* not lint && not SCCSID */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * vi.c: Vi mode commands.
+ */
+#include <sys/wait.h>
+#include "sys.h"
+#include "el.h"
+
+private el_action_t cv_action(EditLine *, int);
+private el_action_t cv_paste(EditLine *, int);
+
+/* cv_action():
+ * Handle vi actions.
+ */
+private el_action_t
+cv_action(EditLine *el, int c)
+{
+
+ if (el->el_chared.c_vcmd.action != NOP) {
+ /* 'cc', 'dd' and (possibly) friends */
+ if (c != el->el_chared.c_vcmd.action)
+ return CC_ERROR;
+
+ if (!(c & YANK))
+ cv_undo(el);
+ cv_yank(el, el->el_line.buffer,
+ el->el_line.lastchar - el->el_line.buffer);
+ el->el_chared.c_vcmd.action = NOP;
+ el->el_chared.c_vcmd.pos = 0;
+ if (!(c & YANK)) {
+ el->el_line.lastchar = el->el_line.buffer;
+ el->el_line.cursor = el->el_line.buffer;
+ }
+ if (c & INSERT)
+ el->el_map.current = el->el_map.key;
+
+ return (CC_REFRESH);
+ }
+ el->el_chared.c_vcmd.pos = el->el_line.cursor;
+ el->el_chared.c_vcmd.action = c;
+ return (CC_ARGHACK);
+}
+
+/* cv_paste():
+ * Paste previous deletion before or after the cursor
+ */
+private el_action_t
+cv_paste(EditLine *el, int c)
+{
+ c_kill_t *k = &el->el_chared.c_kill;
+ int len = k->last - k->buf;
+
+ if (k->buf == NULL || len == 0)
+ return (CC_ERROR);
+#ifdef DEBUG_PASTE
+ (void) fprintf(el->el_errfile, "Paste: \"%.*s\"\n", len, k->buf);
+#endif
+
+ cv_undo(el);
+
+ if (!c && el->el_line.cursor < el->el_line.lastchar)
+ el->el_line.cursor++;
+
+ c_insert(el, len);
+ if (el->el_line.cursor + len > el->el_line.lastchar)
+ return (CC_ERROR);
+ (void) memcpy(el->el_line.cursor, k->buf, len +0u);
+
+ return (CC_REFRESH);
+}
+
+
+/* vi_paste_next():
+ * Vi paste previous deletion to the right of the cursor
+ * [p]
+ */
+protected el_action_t
+/*ARGSUSED*/
+vi_paste_next(EditLine *el, int c __unused)
+{
+
+ return (cv_paste(el, 0));
+}
+
+
+/* vi_paste_prev():
+ * Vi paste previous deletion to the left of the cursor
+ * [P]
+ */
+protected el_action_t
+/*ARGSUSED*/
+vi_paste_prev(EditLine *el, int c __unused)
+{
+
+ return (cv_paste(el, 1));
+}
+
+
+/* vi_prev_big_word():
+ * Vi move to the previous space delimited word
+ * [B]
+ */
+protected el_action_t
+/*ARGSUSED*/
+vi_prev_big_word(EditLine *el, int c)
+{
+
+ if (el->el_line.cursor == el->el_line.buffer)
+ return (CC_ERROR);
+
+ el->el_line.cursor = cv_prev_word(el->el_line.cursor,
+ el->el_line.buffer,
+ el->el_state.argument,
+ cv__isWord);
+
+ if (el->el_chared.c_vcmd.action != NOP) {
+ cv_delfini(el);
+ return (CC_REFRESH);
+ }
+ return (CC_CURSOR);
+}
+
+
+/* vi_prev_word():
+ * Vi move to the previous word
+ * [b]
+ */
+protected el_action_t
+/*ARGSUSED*/
+vi_prev_word(EditLine *el, int c __unused)
+{
+
+ if (el->el_line.cursor == el->el_line.buffer)
+ return (CC_ERROR);
+
+ el->el_line.cursor = cv_prev_word(el->el_line.cursor,
+ el->el_line.buffer,
+ el->el_state.argument,
+ cv__isword);
+
+ if (el->el_chared.c_vcmd.action != NOP) {
+ cv_delfini(el);
+ return (CC_REFRESH);
+ }
+ return (CC_CURSOR);
+}
+
+
+/* vi_next_big_word():
+ * Vi move to the next space delimited word
+ * [W]
+ */
+protected el_action_t
+/*ARGSUSED*/
+vi_next_big_word(EditLine *el, int c)
+{
+
+ if (el->el_line.cursor >= el->el_line.lastchar - 1)
+ return (CC_ERROR);
+
+ el->el_line.cursor = cv_next_word(el, el->el_line.cursor,
+ el->el_line.lastchar, el->el_state.argument, cv__isWord);
+
+ if (el->el_map.type == MAP_VI)
+ if (el->el_chared.c_vcmd.action != NOP) {
+ cv_delfini(el);
+ return (CC_REFRESH);
+ }
+ return (CC_CURSOR);
+}
+
+
+/* vi_next_word():
+ * Vi move to the next word
+ * [w]
+ */
+protected el_action_t
+/*ARGSUSED*/
+vi_next_word(EditLine *el, int c __unused)
+{
+
+ if (el->el_line.cursor >= el->el_line.lastchar - 1)
+ return (CC_ERROR);
+
+ el->el_line.cursor = cv_next_word(el, el->el_line.cursor,
+ el->el_line.lastchar, el->el_state.argument, cv__isword);
+
+ if (el->el_map.type == MAP_VI)
+ if (el->el_chared.c_vcmd.action != NOP) {
+ cv_delfini(el);
+ return (CC_REFRESH);
+ }
+ return (CC_CURSOR);
+}
+
+
+/* vi_change_case():
+ * Vi change case of character under the cursor and advance one character
+ * [~]
+ */
+protected el_action_t
+vi_change_case(EditLine *el, int c)
+{
+ int i;
+
+ if (el->el_line.cursor >= el->el_line.lastchar)
+ return (CC_ERROR);
+ cv_undo(el);
+ for (i = 0; i < el->el_state.argument; i++) {
+
+ c = *(unsigned char *)el->el_line.cursor;
+ if (isupper(c))
+ *el->el_line.cursor = tolower(c);
+ else if (islower(c))
+ *el->el_line.cursor = toupper(c);
+
+ if (++el->el_line.cursor >= el->el_line.lastchar) {
+ el->el_line.cursor--;
+ re_fastaddc(el);
+ break;
+ }
+ re_fastaddc(el);
+ }
+ return CC_NORM;
+}
+
+
+/* vi_change_meta():
+ * Vi change prefix command
+ * [c]
+ */
+protected el_action_t
+/*ARGSUSED*/
+vi_change_meta(EditLine *el, int c __unused)
+{
+
+ /*
+ * Delete with insert == change: first we delete and then we leave in
+ * insert mode.
+ */
+ return (cv_action(el, DELETE | INSERT));
+}
+
+
+/* vi_insert_at_bol():
+ * Vi enter insert mode at the beginning of line
+ * [I]
+ */
+protected el_action_t
+/*ARGSUSED*/
+vi_insert_at_bol(EditLine *el, int c __unused)
+{
+
+ el->el_line.cursor = el->el_line.buffer;
+ cv_undo(el);
+ el->el_map.current = el->el_map.key;
+ return (CC_CURSOR);
+}
+
+
+/* vi_replace_char():
+ * Vi replace character under the cursor with the next character typed
+ * [r]
+ */
+protected el_action_t
+/*ARGSUSED*/
+vi_replace_char(EditLine *el, int c __unused)
+{
+
+ if (el->el_line.cursor >= el->el_line.lastchar)
+ return CC_ERROR;
+
+ el->el_map.current = el->el_map.key;
+ el->el_state.inputmode = MODE_REPLACE_1;
+ cv_undo(el);
+ return (CC_ARGHACK);
+}
+
+
+/* vi_replace_mode():
+ * Vi enter replace mode
+ * [R]
+ */
+protected el_action_t
+/*ARGSUSED*/
+vi_replace_mode(EditLine *el, int c __unused)
+{
+
+ el->el_map.current = el->el_map.key;
+ el->el_state.inputmode = MODE_REPLACE;
+ cv_undo(el);
+ return (CC_NORM);
+}
+
+
+/* vi_substitute_char():
+ * Vi replace character under the cursor and enter insert mode
+ * [s]
+ */
+protected el_action_t
+/*ARGSUSED*/
+vi_substitute_char(EditLine *el, int c __unused)
+{
+
+ c_delafter(el, el->el_state.argument);
+ el->el_map.current = el->el_map.key;
+ return (CC_REFRESH);
+}
+
+
+/* vi_substitute_line():
+ * Vi substitute entire line
+ * [S]
+ */
+protected el_action_t
+/*ARGSUSED*/
+vi_substitute_line(EditLine *el, int c __unused)
+{
+
+ cv_undo(el);
+ cv_yank(el, el->el_line.buffer,
+ el->el_line.lastchar - el->el_line.buffer);
+ (void) em_kill_line(el, 0);
+ el->el_map.current = el->el_map.key;
+ return (CC_REFRESH);
+}
+
+
+/* vi_change_to_eol():
+ * Vi change to end of line
+ * [C]
+ */
+protected el_action_t
+/*ARGSUSED*/
+vi_change_to_eol(EditLine *el, int c __unused)
+{
+
+ cv_undo(el);
+ cv_yank(el, el->el_line.cursor,
+ el->el_line.lastchar - el->el_line.cursor);
+ (void) ed_kill_line(el, 0);
+ el->el_map.current = el->el_map.key;
+ return (CC_REFRESH);
+}
+
+
+/* vi_insert():
+ * Vi enter insert mode
+ * [i]
+ */
+protected el_action_t
+/*ARGSUSED*/
+vi_insert(EditLine *el, int c __unused)
+{
+
+ el->el_map.current = el->el_map.key;
+ cv_undo(el);
+ return (CC_NORM);
+}
+
+
+/* vi_add():
+ * Vi enter insert mode after the cursor
+ * [a]
+ */
+protected el_action_t
+/*ARGSUSED*/
+vi_add(EditLine *el, int c __unused)
+{
+ int ret;
+
+ el->el_map.current = el->el_map.key;
+ if (el->el_line.cursor < el->el_line.lastchar) {
+ el->el_line.cursor++;
+ if (el->el_line.cursor > el->el_line.lastchar)
+ el->el_line.cursor = el->el_line.lastchar;
+ ret = CC_CURSOR;
+ } else
+ ret = CC_NORM;
+
+ cv_undo(el);
+
+ return (ret);
+}
+
+
+/* vi_add_at_eol():
+ * Vi enter insert mode at end of line
+ * [A]
+ */
+protected el_action_t
+/*ARGSUSED*/
+vi_add_at_eol(EditLine *el, int c __unused)
+{
+
+ el->el_map.current = el->el_map.key;
+ el->el_line.cursor = el->el_line.lastchar;
+ cv_undo(el);
+ return (CC_CURSOR);
+}
+
+
+/* vi_delete_meta():
+ * Vi delete prefix command
+ * [d]
+ */
+protected el_action_t
+/*ARGSUSED*/
+vi_delete_meta(EditLine *el, int c __unused)
+{
+
+ return (cv_action(el, DELETE));
+}
+
+
+/* vi_end_big_word():
+ * Vi move to the end of the current space delimited word
+ * [E]
+ */
+protected el_action_t
+/*ARGSUSED*/
+vi_end_big_word(EditLine *el, int c)
+{
+
+ if (el->el_line.cursor == el->el_line.lastchar)
+ return (CC_ERROR);
+
+ el->el_line.cursor = cv__endword(el->el_line.cursor,
+ el->el_line.lastchar, el->el_state.argument, cv__isWord);
+
+ if (el->el_chared.c_vcmd.action != NOP) {
+ el->el_line.cursor++;
+ cv_delfini(el);
+ return (CC_REFRESH);
+ }
+ return (CC_CURSOR);
+}
+
+
+/* vi_end_word():
+ * Vi move to the end of the current word
+ * [e]
+ */
+protected el_action_t
+/*ARGSUSED*/
+vi_end_word(EditLine *el, int c __unused)
+{
+
+ if (el->el_line.cursor == el->el_line.lastchar)
+ return (CC_ERROR);
+
+ el->el_line.cursor = cv__endword(el->el_line.cursor,
+ el->el_line.lastchar, el->el_state.argument, cv__isword);
+
+ if (el->el_chared.c_vcmd.action != NOP) {
+ el->el_line.cursor++;
+ cv_delfini(el);
+ return (CC_REFRESH);
+ }
+ return (CC_CURSOR);
+}
+
+
+/* vi_undo():
+ * Vi undo last change
+ * [u]
+ */
+protected el_action_t
+/*ARGSUSED*/
+vi_undo(EditLine *el, int c __unused)
+{
+ c_undo_t un = el->el_chared.c_undo;
+
+ if (un.len == -1)
+ return CC_ERROR;
+
+ /* switch line buffer and undo buffer */
+ el->el_chared.c_undo.buf = el->el_line.buffer;
+ el->el_chared.c_undo.len = el->el_line.lastchar - el->el_line.buffer;
+ el->el_chared.c_undo.cursor = el->el_line.cursor - el->el_line.buffer;
+ el->el_line.limit = un.buf + (el->el_line.limit - el->el_line.buffer);
+ el->el_line.buffer = un.buf;
+ el->el_line.cursor = un.buf + un.cursor;
+ el->el_line.lastchar = un.buf + un.len;
+
+ return (CC_REFRESH);
+}
+
+
+/* vi_command_mode():
+ * Vi enter command mode (use alternative key bindings)
+ * [<ESC>]
+ */
+protected el_action_t
+/*ARGSUSED*/
+vi_command_mode(EditLine *el, int c __unused)
+{
+
+ /* [Esc] cancels pending action */
+ el->el_chared.c_vcmd.action = NOP;
+ el->el_chared.c_vcmd.pos = 0;
+
+ el->el_state.doingarg = 0;
+
+ el->el_state.inputmode = MODE_INSERT;
+ el->el_map.current = el->el_map.alt;
+#ifdef VI_MOVE
+ if (el->el_line.cursor > el->el_line.buffer)
+ el->el_line.cursor--;
+#endif
+ return (CC_CURSOR);
+}
+
+
+/* vi_zero():
+ * Vi move to the beginning of line
+ * [0]
+ */
+protected el_action_t
+vi_zero(EditLine *el, int c)
+{
+
+ if (el->el_state.doingarg)
+ return ed_argument_digit(el, c);
+
+ el->el_line.cursor = el->el_line.buffer;
+ if (el->el_chared.c_vcmd.action != NOP) {
+ cv_delfini(el);
+ return (CC_REFRESH);
+ }
+ return (CC_CURSOR);
+}
+
+
+/* vi_delete_prev_char():
+ * Vi move to previous character (backspace)
+ * [^H] in insert mode only
+ */
+protected el_action_t
+/*ARGSUSED*/
+vi_delete_prev_char(EditLine *el, int c __unused)
+{
+
+ if (el->el_line.cursor <= el->el_line.buffer)
+ return (CC_ERROR);
+
+ c_delbefore1(el);
+ el->el_line.cursor--;
+ return (CC_REFRESH);
+}
+
+
+/* vi_list_or_eof():
+ * Vi list choices for completion or indicate end of file if empty line
+ * [^D]
+ */
+protected el_action_t
+/*ARGSUSED*/
+vi_list_or_eof(EditLine *el, int c __unused)
+{
+
+ if (el->el_line.cursor == el->el_line.lastchar) {
+ if (el->el_line.cursor == el->el_line.buffer) {
+ term_overwrite(el, STReof, 4); /* then do a EOF */
+ term__flush();
+ return (CC_EOF);
+ } else {
+ /*
+ * Here we could list completions, but it is an
+ * error right now
+ */
+ term_beep(el);
+ return (CC_ERROR);
+ }
+ } else {
+#ifdef notyet
+ re_goto_bottom(el);
+ *el->el_line.lastchar = '\0'; /* just in case */
+ return (CC_LIST_CHOICES);
+#else
+ /*
+ * Just complain for now.
+ */
+ term_beep(el);
+ return (CC_ERROR);
+#endif
+ }
+}
+
+
+/* vi_kill_line_prev():
+ * Vi cut from beginning of line to cursor
+ * [^U]
+ */
+protected el_action_t
+/*ARGSUSED*/
+vi_kill_line_prev(EditLine *el, int c __unused)
+{
+ char *kp, *cp;
+
+ cp = el->el_line.buffer;
+ kp = el->el_chared.c_kill.buf;
+ while (cp < el->el_line.cursor)
+ *kp++ = *cp++; /* copy it */
+ el->el_chared.c_kill.last = kp;
+ c_delbefore(el, el->el_line.cursor - el->el_line.buffer);
+ el->el_line.cursor = el->el_line.buffer; /* zap! */
+ return (CC_REFRESH);
+}
+
+
+/* vi_search_prev():
+ * Vi search history previous
+ * [?]
+ */
+protected el_action_t
+/*ARGSUSED*/
+vi_search_prev(EditLine *el, int c __unused)
+{
+
+ return (cv_search(el, ED_SEARCH_PREV_HISTORY));
+}
+
+
+/* vi_search_next():
+ * Vi search history next
+ * [/]
+ */
+protected el_action_t
+/*ARGSUSED*/
+vi_search_next(EditLine *el, int c __unused)
+{
+
+ return (cv_search(el, ED_SEARCH_NEXT_HISTORY));
+}
+
+
+/* vi_repeat_search_next():
+ * Vi repeat current search in the same search direction
+ * [n]
+ */
+protected el_action_t
+/*ARGSUSED*/
+vi_repeat_search_next(EditLine *el, int c __unused)
+{
+
+ if (el->el_search.patlen == 0)
+ return (CC_ERROR);
+ else
+ return (cv_repeat_srch(el, el->el_search.patdir));
+}
+
+
+/* vi_repeat_search_prev():
+ * Vi repeat current search in the opposite search direction
+ * [N]
+ */
+/*ARGSUSED*/
+protected el_action_t
+vi_repeat_search_prev(EditLine *el, int c __unused)
+{
+
+ if (el->el_search.patlen == 0)
+ return (CC_ERROR);
+ else
+ return (cv_repeat_srch(el,
+ el->el_search.patdir == ED_SEARCH_PREV_HISTORY ?
+ ED_SEARCH_NEXT_HISTORY : ED_SEARCH_PREV_HISTORY));
+}
+
+
+/* vi_next_char():
+ * Vi move to the character specified next
+ * [f]
+ */
+protected el_action_t
+/*ARGSUSED*/
+vi_next_char(EditLine *el, int c __unused)
+{
+ return cv_csearch(el, CHAR_FWD, -1, el->el_state.argument, 0);
+}
+
+
+/* vi_prev_char():
+ * Vi move to the character specified previous
+ * [F]
+ */
+protected el_action_t
+/*ARGSUSED*/
+vi_prev_char(EditLine *el, int c __unused)
+{
+ return cv_csearch(el, CHAR_BACK, -1, el->el_state.argument, 0);
+}
+
+
+/* vi_to_next_char():
+ * Vi move up to the character specified next
+ * [t]
+ */
+protected el_action_t
+/*ARGSUSED*/
+vi_to_next_char(EditLine *el, int c __unused)
+{
+ return cv_csearch(el, CHAR_FWD, -1, el->el_state.argument, 1);
+}
+
+
+/* vi_to_prev_char():
+ * Vi move up to the character specified previous
+ * [T]
+ */
+protected el_action_t
+/*ARGSUSED*/
+vi_to_prev_char(EditLine *el, int c __unused)
+{
+ return cv_csearch(el, CHAR_BACK, -1, el->el_state.argument, 1);
+}
+
+
+/* vi_repeat_next_char():
+ * Vi repeat current character search in the same search direction
+ * [;]
+ */
+protected el_action_t
+/*ARGSUSED*/
+vi_repeat_next_char(EditLine *el, int c __unused)
+{
+
+ return cv_csearch(el, el->el_search.chadir, el->el_search.chacha,
+ el->el_state.argument, el->el_search.chatflg);
+}
+
+
+/* vi_repeat_prev_char():
+ * Vi repeat current character search in the opposite search direction
+ * [,]
+ */
+protected el_action_t
+/*ARGSUSED*/
+vi_repeat_prev_char(EditLine *el, int c __unused)
+{
+ el_action_t r;
+ int dir = el->el_search.chadir;
+
+ r = cv_csearch(el, -dir, el->el_search.chacha,
+ el->el_state.argument, el->el_search.chatflg);
+ el->el_search.chadir = dir;
+ return r;
+}
+
+
+/* vi_match():
+ * Vi go to matching () {} or []
+ * [%]
+ */
+protected el_action_t
+/*ARGSUSED*/
+vi_match(EditLine *el, int c)
+{
+ const char match_chars[] = "()[]{}";
+ char *cp;
+ int delta, i, count;
+ char o_ch, c_ch;
+
+ *el->el_line.lastchar = '\0'; /* just in case */
+
+ i = strcspn(el->el_line.cursor, match_chars);
+ o_ch = el->el_line.cursor[i];
+ if (o_ch == 0)
+ return CC_ERROR;
+ delta = strchr(match_chars, o_ch) - match_chars;
+ c_ch = match_chars[delta ^ 1];
+ count = 1;
+ delta = 1 - (delta & 1) * 2;
+
+ for (cp = &el->el_line.cursor[i]; count; ) {
+ cp += delta;
+ if (cp < el->el_line.buffer || cp >= el->el_line.lastchar)
+ return CC_ERROR;
+ if (*cp == o_ch)
+ count++;
+ else if (*cp == c_ch)
+ count--;
+ }
+
+ el->el_line.cursor = cp;
+
+ if (el->el_chared.c_vcmd.action != NOP) {
+ /* NB posix says char under cursor should NOT be deleted
+ for -ve delta - this is different to netbsd vi. */
+ if (delta > 0)
+ el->el_line.cursor++;
+ cv_delfini(el);
+ return (CC_REFRESH);
+ }
+ return (CC_CURSOR);
+}
+
+/* vi_undo_line():
+ * Vi undo all changes to line
+ * [U]
+ */
+protected el_action_t
+/*ARGSUSED*/
+vi_undo_line(EditLine *el, int c)
+{
+
+ cv_undo(el);
+ return hist_get(el);
+}
+
+/* vi_to_column():
+ * Vi go to specified column
+ * [|]
+ * NB netbsd vi goes to screen column 'n', posix says nth character
+ */
+protected el_action_t
+/*ARGSUSED*/
+vi_to_column(EditLine *el, int c)
+{
+
+ el->el_line.cursor = el->el_line.buffer;
+ el->el_state.argument--;
+ return ed_next_char(el, 0);
+}
+
+/* vi_yank_end():
+ * Vi yank to end of line
+ * [Y]
+ */
+protected el_action_t
+/*ARGSUSED*/
+vi_yank_end(EditLine *el, int c)
+{
+
+ cv_yank(el, el->el_line.cursor,
+ el->el_line.lastchar - el->el_line.cursor);
+ return CC_REFRESH;
+}
+
+/* vi_yank():
+ * Vi yank
+ * [y]
+ */
+protected el_action_t
+/*ARGSUSED*/
+vi_yank(EditLine *el, int c)
+{
+
+ return cv_action(el, YANK);
+}
+
+/* vi_comment_out():
+ * Vi comment out current command
+ * [#]
+ */
+protected el_action_t
+/*ARGSUSED*/
+vi_comment_out(EditLine *el, int c)
+{
+
+ el->el_line.cursor = el->el_line.buffer;
+ c_insert(el, 1);
+ *el->el_line.cursor = '#';
+ re_refresh(el);
+ return ed_newline(el, 0);
+}
+
+/* vi_alias():
+ * Vi include shell alias
+ * [@]
+ * NB: posix implies that we should enter insert mode, however
+ * this is against historical precedent...
+ */
+protected el_action_t
+/*ARGSUSED*/
+vi_alias(EditLine *el, int c)
+{
+#ifdef __weak_extern
+ char alias_name[3];
+ char *alias_text;
+ extern char *get_alias_text(const char *);
+ __weak_extern(get_alias_text);
+
+ if (get_alias_text == 0) {
+ return CC_ERROR;
+ }
+
+ alias_name[0] = '_';
+ alias_name[2] = 0;
+ if (el_getc(el, &alias_name[1]) != 1)
+ return CC_ERROR;
+
+ alias_text = get_alias_text(alias_name);
+ if (alias_text != NULL)
+ el_push(el, alias_text);
+ return CC_NORM;
+#else
+ return CC_ERROR;
+#endif
+}
+
+/* vi_to_history_line():
+ * Vi go to specified history file line.
+ * [G]
+ */
+protected el_action_t
+/*ARGSUSED*/
+vi_to_history_line(EditLine *el, int c)
+{
+ int sv_event_no = el->el_history.eventno;
+ el_action_t rval;
+
+
+ if (el->el_history.eventno == 0) {
+ (void) strncpy(el->el_history.buf, el->el_line.buffer,
+ EL_BUFSIZ);
+ el->el_history.last = el->el_history.buf +
+ (el->el_line.lastchar - el->el_line.buffer);
+ }
+
+ /* Lack of a 'count' means oldest, not 1 */
+ if (!el->el_state.doingarg) {
+ el->el_history.eventno = 0x7fffffff;
+ hist_get(el);
+ } else {
+ /* This is brain dead, all the rest of this code counts
+ * upwards going into the past. Here we need count in the
+ * other direction (to match the output of fc -l).
+ * I could change the world, but this seems to suffice.
+ */
+ el->el_history.eventno = 1;
+ if (hist_get(el) == CC_ERROR)
+ return CC_ERROR;
+ el->el_history.eventno = 1 + el->el_history.ev.num
+ - el->el_state.argument;
+ if (el->el_history.eventno < 0) {
+ el->el_history.eventno = sv_event_no;
+ return CC_ERROR;
+ }
+ }
+ rval = hist_get(el);
+ if (rval == CC_ERROR)
+ el->el_history.eventno = sv_event_no;
+ return rval;
+}
+
+/* vi_histedit():
+ * Vi edit history line with vi
+ * [v]
+ */
+protected el_action_t
+/*ARGSUSED*/
+vi_histedit(EditLine *el, int c)
+{
+ int fd;
+ pid_t pid;
+ int st;
+ char tempfile[] = "/tmp/histedit.XXXXXXXXXX";
+ char *cp;
+
+ if (el->el_state.doingarg) {
+ if (vi_to_history_line(el, 0) == CC_ERROR)
+ return CC_ERROR;
+ }
+
+ fd = mkstemp(tempfile);
+ if (fd < 0)
+ return CC_ERROR;
+ cp = el->el_line.buffer;
+ write(fd, cp, el->el_line.lastchar - cp +0u);
+ write(fd, "\n", 1);
+ pid = fork();
+ switch (pid) {
+ case -1:
+ close(fd);
+ unlink(tempfile);
+ return CC_ERROR;
+ case 0:
+ close(fd);
+ execlp("vi", "vi", tempfile, NULL);
+ exit(0);
+ /*NOTREACHED*/
+ default:
+ while (waitpid(pid, &st, 0) != pid)
+ continue;
+ lseek(fd, 0ll, SEEK_SET);
+ st = read(fd, cp, el->el_line.limit - cp +0u);
+ if (st > 0 && cp[st - 1] == '\n')
+ st--;
+ el->el_line.cursor = cp;
+ el->el_line.lastchar = cp + st;
+ break;
+ }
+
+ close(fd);
+ unlink(tempfile);
+ /* return CC_REFRESH; */
+ return ed_newline(el, 0);
+}
+
+/* vi_history_word():
+ * Vi append word from previous input line
+ * [_]
+ * Who knows where this one came from!
+ * '_' in vi means 'entire current line', so 'cc' is a synonym for 'c_'
+ */
+protected el_action_t
+/*ARGSUSED*/
+vi_history_word(EditLine *el, int c)
+{
+ const char *wp = HIST_FIRST(el);
+ const char *wep, *wsp;
+ int len;
+ char *cp;
+ const char *lim;
+
+ if (wp == NULL)
+ return CC_ERROR;
+
+ wep = wsp = 0;
+ do {
+ while (isspace((unsigned char)*wp))
+ wp++;
+ if (*wp == 0)
+ break;
+ wsp = wp;
+ while (*wp && !isspace((unsigned char)*wp))
+ wp++;
+ wep = wp;
+ } while ((!el->el_state.doingarg || --el->el_state.argument > 0) && *wp != 0);
+
+ if (wsp == 0 || (el->el_state.doingarg && el->el_state.argument != 0))
+ return CC_ERROR;
+
+ cv_undo(el);
+ len = wep - wsp;
+ if (el->el_line.cursor < el->el_line.lastchar)
+ el->el_line.cursor++;
+ c_insert(el, len + 1);
+ cp = el->el_line.cursor;
+ lim = el->el_line.limit;
+ if (cp < lim)
+ *cp++ = ' ';
+ while (wsp < wep && cp < lim)
+ *cp++ = *wsp++;
+ el->el_line.cursor = cp;
+
+ el->el_map.current = el->el_map.key;
+ return CC_REFRESH;
+}
+
+/* vi_redo():
+ * Vi redo last non-motion command
+ * [.]
+ */
+protected el_action_t
+/*ARGSUSED*/
+vi_redo(EditLine *el, int c)
+{
+ c_redo_t *r = &el->el_chared.c_redo;
+
+ if (!el->el_state.doingarg && r->count) {
+ el->el_state.doingarg = 1;
+ el->el_state.argument = r->count;
+ }
+
+ el->el_chared.c_vcmd.pos = el->el_line.cursor;
+ el->el_chared.c_vcmd.action = r->action;
+ if (r->pos != r->buf) {
+ if (r->pos + 1 > r->lim)
+ /* sanity */
+ r->pos = r->lim - 1;
+ r->pos[0] = 0;
+ el_push(el, r->buf);
+ }
+
+ el->el_state.thiscmd = r->cmd;
+ el->el_state.thisch = r->ch;
+ return (*el->el_map.func[r->cmd])(el, r->ch);
+}
diff --git a/lib/libexpat/Makefile b/lib/libexpat/Makefile
new file mode 100644
index 0000000..cac2fcc
--- /dev/null
+++ b/lib/libexpat/Makefile
@@ -0,0 +1,27 @@
+# $FreeBSD$
+
+EXPAT= ${.CURDIR}/../../contrib/expat
+
+LIB= bsdxml
+SHLIBDIR?= /lib
+SHLIB_MAJOR= 2
+SRCS= xmlparse.c xmlrole.c xmltok.c
+INCS= bsdxml.h
+MAN= libbsdxml.3
+
+.PATH: ${EXPAT}/lib
+
+CFLAGS+= -I${.CURDIR}
+CLEANFILES= bsdxml.h
+
+# OK, so it is not entirely unadultered: we ammend the COPYING
+# to point people to the right place, get rid of some VMS stuff
+# and use FreeBSD style indempotency #ifndefs.
+#
+bsdxml.h: expat.h
+ unifdef -U__VMS < ${.ALLSRC} | \
+ sed -e 's/XmlParse_INCLUDED/_BSD_XML_H_/' \
+ -e 's/COPYING/src\/contrib\/expat\/COPYING/' \
+ > ${.TARGET}
+
+.include <bsd.lib.mk>
diff --git a/lib/libexpat/expat_config.h b/lib/libexpat/expat_config.h
new file mode 100644
index 0000000..036c4d3
--- /dev/null
+++ b/lib/libexpat/expat_config.h
@@ -0,0 +1,89 @@
+/* $FreeBSD$ */
+
+/* 1234 = LIL_ENDIAN, 4321 = BIGENDIAN */
+#define BYTEORDER 1234
+
+/* Define to 1 if you have the `bcopy' function. */
+#define HAVE_BCOPY 1
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have the `getpagesize' function. */
+#define HAVE_GETPAGESIZE 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `memmove' function. */
+#define HAVE_MEMMOVE 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have a working `mmap' system call. */
+#define HAVE_MMAP 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "expat-bugs@mail.libexpat.org"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "expat"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "expat 1.95.5"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "expat"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "1.95.5"
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* whether byteorder is bigendian */
+/* #undef WORDS_BIGENDIAN */
+
+/* Define to specify how much context to retain around the current parse
+ point. */
+#define XML_CONTEXT_BYTES 1024
+
+/* Define to make parameter entity parsing functionality available. */
+#define XML_DTD 1
+
+/* Define to make XML Namespaces functionality available. */
+#define XML_NS 1
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to `long' if <sys/types.h> does not define. */
+/* #undef off_t */
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+/* #undef size_t */
diff --git a/lib/libexpat/libbsdxml.3 b/lib/libexpat/libbsdxml.3
new file mode 100644
index 0000000..2d5fc3e
--- /dev/null
+++ b/lib/libexpat/libbsdxml.3
@@ -0,0 +1,60 @@
+.\"-
+.\" Copyright (c) 2002 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$
+.\"/
+.Dd October 4, 2002
+.Dt LIBBSDXML 3
+.Os
+.Sh NAME
+.Nm libbsdxml
+.Nd eXpat XML parser library
+.Sh SYNOPSIS
+.In bsdxml.h
+.Sh DESCRIPTION
+The
+.Nm
+library is a verbatim copy of the eXpat XML library version 1.95.5.
+.Pp
+To avoid version and autoconfiguration issues, the library has been
+renamed to
+.Nm
+rather than retain the original eXpat library and include file names
+to prevent confusion and autoconfiguration issues for 3rd party
+software.
+.Sh SEE ALSO
+For full documentation, please see the eXpat webpage at
+.Pa http://www.libexpat.org/ .
+.Sh AUTHORS
+.An -nosplit
+The original eXpat was written by
+.An James Clark Aq jjc@jclark.com .
+.Pp
+Subsequently eXpat maintenance and development been taken up by a group
+of people under the leadership of
+.An Fred Drake Aq fdrake@acm.com ,
+.An Paul Prescod ,
+and
+.An Clark Cooper .
diff --git a/lib/libfetch/Makefile b/lib/libfetch/Makefile
new file mode 100644
index 0000000..bcd5214
--- /dev/null
+++ b/lib/libfetch/Makefile
@@ -0,0 +1,76 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+LIB= fetch
+CFLAGS+= -I.
+CFLAGS+= -DINET6
+SRCS= fetch.c common.c ftp.c http.c file.c \
+ ftperr.h httperr.h
+INCS= fetch.h
+MAN= fetch.3
+CLEANFILES= ftperr.h httperr.h
+
+.if ${MK_OPENSSL} != "no"
+CFLAGS+= -DWITH_SSL
+DPADD= ${LIBSSL} ${LIBCRYPTO}
+LDADD= -lssl -lcrypto
+.endif
+
+CSTD?= c99
+WARNS?= 2
+
+SHLIB_MAJOR= 4
+
+ftperr.h: ftp.errors
+ @echo "static struct fetcherr _ftp_errlist[] = {" > ${.TARGET}
+ @cat ${.ALLSRC} \
+ | grep -v ^# \
+ | sort \
+ | while read NUM CAT STRING; do \
+ echo " { $${NUM}, FETCH_$${CAT}, \"$${STRING}\" },"; \
+ done >> ${.TARGET}
+ @echo " { -1, FETCH_UNKNOWN, \"Unknown FTP error\" }" >> ${.TARGET}
+ @echo "};" >> ${.TARGET}
+
+httperr.h: http.errors
+ @echo "static struct fetcherr _http_errlist[] = {" > ${.TARGET}
+ @cat ${.ALLSRC} \
+ | grep -v ^# \
+ | sort \
+ | while read NUM CAT STRING; do \
+ echo " { $${NUM}, FETCH_$${CAT}, \"$${STRING}\" },"; \
+ done >> ${.TARGET}
+ @echo " { -1, FETCH_UNKNOWN, \"Unknown HTTP error\" }" >> ${.TARGET}
+ @echo "};" >> ${.TARGET}
+
+MLINKS+= fetch.3 fetchFreeURL.3
+MLINKS+= fetch.3 fetchGet.3
+MLINKS+= fetch.3 fetchGetFTP.3
+MLINKS+= fetch.3 fetchGetFile.3
+MLINKS+= fetch.3 fetchGetHTTP.3
+MLINKS+= fetch.3 fetchGetURL.3
+MLINKS+= fetch.3 fetchList.3
+MLINKS+= fetch.3 fetchListFTP.3
+MLINKS+= fetch.3 fetchListFile.3
+MLINKS+= fetch.3 fetchListHTTP.3
+MLINKS+= fetch.3 fetchListURL.3
+MLINKS+= fetch.3 fetchMakeURL.3
+MLINKS+= fetch.3 fetchParseURL.3
+MLINKS+= fetch.3 fetchPut.3
+MLINKS+= fetch.3 fetchPutFTP.3
+MLINKS+= fetch.3 fetchPutFile.3
+MLINKS+= fetch.3 fetchPutHTTP.3
+MLINKS+= fetch.3 fetchPutURL.3
+MLINKS+= fetch.3 fetchStat.3
+MLINKS+= fetch.3 fetchStatFTP.3
+MLINKS+= fetch.3 fetchStatFile.3
+MLINKS+= fetch.3 fetchStatHTTP.3
+MLINKS+= fetch.3 fetchStatURL.3
+MLINKS+= fetch.3 fetchXGet.3
+MLINKS+= fetch.3 fetchXGetFTP.3
+MLINKS+= fetch.3 fetchXGetFile.3
+MLINKS+= fetch.3 fetchXGetHTTP.3
+MLINKS+= fetch.3 fetchXGetURL.3
+
+.include <bsd.lib.mk>
diff --git a/lib/libfetch/common.c b/lib/libfetch/common.c
new file mode 100644
index 0000000..ba0d711
--- /dev/null
+++ b/lib/libfetch/common.c
@@ -0,0 +1,736 @@
+/*-
+ * Copyright (c) 1998-2004 Dag-Erling Coïdan Smørgrav
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 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/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+#include <netinet/in.h>
+
+#include <errno.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "fetch.h"
+#include "common.h"
+
+
+/*** Local data **************************************************************/
+
+/*
+ * Error messages for resolver errors
+ */
+static struct fetcherr _netdb_errlist[] = {
+#ifdef EAI_NODATA
+ { EAI_NODATA, FETCH_RESOLV, "Host not found" },
+#endif
+ { EAI_AGAIN, FETCH_TEMP, "Transient resolver failure" },
+ { EAI_FAIL, FETCH_RESOLV, "Non-recoverable resolver failure" },
+ { EAI_NONAME, FETCH_RESOLV, "No address record" },
+ { -1, FETCH_UNKNOWN, "Unknown resolver error" }
+};
+
+/* End-of-Line */
+static const char ENDL[2] = "\r\n";
+
+
+/*** Error-reporting functions ***********************************************/
+
+/*
+ * Map error code to string
+ */
+static struct fetcherr *
+_fetch_finderr(struct fetcherr *p, int e)
+{
+ while (p->num != -1 && p->num != e)
+ p++;
+ return (p);
+}
+
+/*
+ * Set error code
+ */
+void
+_fetch_seterr(struct fetcherr *p, int e)
+{
+ p = _fetch_finderr(p, e);
+ fetchLastErrCode = p->cat;
+ snprintf(fetchLastErrString, MAXERRSTRING, "%s", p->string);
+}
+
+/*
+ * Set error code according to errno
+ */
+void
+_fetch_syserr(void)
+{
+ switch (errno) {
+ case 0:
+ fetchLastErrCode = FETCH_OK;
+ break;
+ case EPERM:
+ case EACCES:
+ case EROFS:
+ case EAUTH:
+ case ENEEDAUTH:
+ fetchLastErrCode = FETCH_AUTH;
+ break;
+ case ENOENT:
+ case EISDIR: /* XXX */
+ fetchLastErrCode = FETCH_UNAVAIL;
+ break;
+ case ENOMEM:
+ fetchLastErrCode = FETCH_MEMORY;
+ break;
+ case EBUSY:
+ case EAGAIN:
+ fetchLastErrCode = FETCH_TEMP;
+ break;
+ case EEXIST:
+ fetchLastErrCode = FETCH_EXISTS;
+ break;
+ case ENOSPC:
+ fetchLastErrCode = FETCH_FULL;
+ break;
+ case EADDRINUSE:
+ case EADDRNOTAVAIL:
+ case ENETDOWN:
+ case ENETUNREACH:
+ case ENETRESET:
+ case EHOSTUNREACH:
+ fetchLastErrCode = FETCH_NETWORK;
+ break;
+ case ECONNABORTED:
+ case ECONNRESET:
+ fetchLastErrCode = FETCH_ABORT;
+ break;
+ case ETIMEDOUT:
+ fetchLastErrCode = FETCH_TIMEOUT;
+ break;
+ case ECONNREFUSED:
+ case EHOSTDOWN:
+ fetchLastErrCode = FETCH_DOWN;
+ break;
+default:
+ fetchLastErrCode = FETCH_UNKNOWN;
+ }
+ snprintf(fetchLastErrString, MAXERRSTRING, "%s", strerror(errno));
+}
+
+
+/*
+ * Emit status message
+ */
+void
+_fetch_info(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fputc('\n', stderr);
+}
+
+
+/*** Network-related utility functions ***************************************/
+
+/*
+ * Return the default port for a scheme
+ */
+int
+_fetch_default_port(const char *scheme)
+{
+ struct servent *se;
+
+ if ((se = getservbyname(scheme, "tcp")) != NULL)
+ return (ntohs(se->s_port));
+ if (strcasecmp(scheme, SCHEME_FTP) == 0)
+ return (FTP_DEFAULT_PORT);
+ if (strcasecmp(scheme, SCHEME_HTTP) == 0)
+ return (HTTP_DEFAULT_PORT);
+ return (0);
+}
+
+/*
+ * Return the default proxy port for a scheme
+ */
+int
+_fetch_default_proxy_port(const char *scheme)
+{
+ if (strcasecmp(scheme, SCHEME_FTP) == 0)
+ return (FTP_DEFAULT_PROXY_PORT);
+ if (strcasecmp(scheme, SCHEME_HTTP) == 0)
+ return (HTTP_DEFAULT_PROXY_PORT);
+ return (0);
+}
+
+
+/*
+ * Create a connection for an existing descriptor.
+ */
+conn_t *
+_fetch_reopen(int sd)
+{
+ conn_t *conn;
+
+ /* allocate and fill connection structure */
+ if ((conn = calloc(1, sizeof(*conn))) == NULL)
+ return (NULL);
+ conn->sd = sd;
+ ++conn->ref;
+ return (conn);
+}
+
+
+/*
+ * Bump a connection's reference count.
+ */
+conn_t *
+_fetch_ref(conn_t *conn)
+{
+
+ ++conn->ref;
+ return (conn);
+}
+
+
+/*
+ * Bind a socket to a specific local address
+ */
+int
+_fetch_bind(int sd, int af, const char *addr)
+{
+ struct addrinfo hints, *res, *res0;
+ int err;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = af;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = 0;
+ if ((err = getaddrinfo(addr, NULL, &hints, &res0)) != 0)
+ return (-1);
+ for (res = res0; res; res = res->ai_next)
+ if (bind(sd, res->ai_addr, res->ai_addrlen) == 0)
+ return (0);
+ return (-1);
+}
+
+
+/*
+ * Establish a TCP connection to the specified port on the specified host.
+ */
+conn_t *
+_fetch_connect(const char *host, int port, int af, int verbose)
+{
+ conn_t *conn;
+ char pbuf[10];
+ const char *bindaddr;
+ struct addrinfo hints, *res, *res0;
+ int sd, err;
+
+ DEBUG(fprintf(stderr, "---> %s:%d\n", host, port));
+
+ if (verbose)
+ _fetch_info("looking up %s", host);
+
+ /* look up host name and set up socket address structure */
+ snprintf(pbuf, sizeof(pbuf), "%d", port);
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = af;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = 0;
+ if ((err = getaddrinfo(host, pbuf, &hints, &res0)) != 0) {
+ _netdb_seterr(err);
+ return (NULL);
+ }
+ bindaddr = getenv("FETCH_BIND_ADDRESS");
+
+ if (verbose)
+ _fetch_info("connecting to %s:%d", host, port);
+
+ /* try to connect */
+ for (sd = -1, res = res0; res; sd = -1, res = res->ai_next) {
+ if ((sd = socket(res->ai_family, res->ai_socktype,
+ res->ai_protocol)) == -1)
+ continue;
+ if (bindaddr != NULL && *bindaddr != '\0' &&
+ _fetch_bind(sd, res->ai_family, bindaddr) != 0) {
+ _fetch_info("failed to bind to '%s'", bindaddr);
+ close(sd);
+ continue;
+ }
+ if (connect(sd, res->ai_addr, res->ai_addrlen) == 0)
+ break;
+ close(sd);
+ }
+ freeaddrinfo(res0);
+ if (sd == -1) {
+ _fetch_syserr();
+ return (NULL);
+ }
+
+ if ((conn = _fetch_reopen(sd)) == NULL) {
+ _fetch_syserr();
+ close(sd);
+ }
+ return (conn);
+}
+
+
+/*
+ * Enable SSL on a connection.
+ */
+int
+_fetch_ssl(conn_t *conn, int verbose)
+{
+
+#ifdef WITH_SSL
+ /* Init the SSL library and context */
+ if (!SSL_library_init()){
+ fprintf(stderr, "SSL library init failed\n");
+ return (-1);
+ }
+
+ SSL_load_error_strings();
+
+ conn->ssl_meth = SSLv23_client_method();
+ conn->ssl_ctx = SSL_CTX_new(conn->ssl_meth);
+ SSL_CTX_set_mode(conn->ssl_ctx, SSL_MODE_AUTO_RETRY);
+
+ conn->ssl = SSL_new(conn->ssl_ctx);
+ if (conn->ssl == NULL){
+ fprintf(stderr, "SSL context creation failed\n");
+ return (-1);
+ }
+ SSL_set_fd(conn->ssl, conn->sd);
+ if (SSL_connect(conn->ssl) == -1){
+ ERR_print_errors_fp(stderr);
+ return (-1);
+ }
+
+ if (verbose) {
+ X509_NAME *name;
+ char *str;
+
+ fprintf(stderr, "SSL connection established using %s\n",
+ SSL_get_cipher(conn->ssl));
+ conn->ssl_cert = SSL_get_peer_certificate(conn->ssl);
+ name = X509_get_subject_name(conn->ssl_cert);
+ str = X509_NAME_oneline(name, 0, 0);
+ printf("Certificate subject: %s\n", str);
+ free(str);
+ name = X509_get_issuer_name(conn->ssl_cert);
+ str = X509_NAME_oneline(name, 0, 0);
+ printf("Certificate issuer: %s\n", str);
+ free(str);
+ }
+
+ return (0);
+#else
+ (void)conn;
+ (void)verbose;
+ fprintf(stderr, "SSL support disabled\n");
+ return (-1);
+#endif
+}
+
+
+/*
+ * Read a character from a connection w/ timeout
+ */
+ssize_t
+_fetch_read(conn_t *conn, char *buf, size_t len)
+{
+ struct timeval now, timeout, wait;
+ fd_set readfds;
+ ssize_t rlen, total;
+ int r;
+
+ if (fetchTimeout) {
+ FD_ZERO(&readfds);
+ gettimeofday(&timeout, NULL);
+ timeout.tv_sec += fetchTimeout;
+ }
+
+ total = 0;
+ while (len > 0) {
+ while (fetchTimeout && !FD_ISSET(conn->sd, &readfds)) {
+ FD_SET(conn->sd, &readfds);
+ gettimeofday(&now, NULL);
+ wait.tv_sec = timeout.tv_sec - now.tv_sec;
+ wait.tv_usec = timeout.tv_usec - now.tv_usec;
+ if (wait.tv_usec < 0) {
+ wait.tv_usec += 1000000;
+ wait.tv_sec--;
+ }
+ if (wait.tv_sec < 0) {
+ errno = ETIMEDOUT;
+ _fetch_syserr();
+ return (-1);
+ }
+ errno = 0;
+ r = select(conn->sd + 1, &readfds, NULL, NULL, &wait);
+ if (r == -1) {
+ if (errno == EINTR && fetchRestartCalls)
+ continue;
+ _fetch_syserr();
+ return (-1);
+ }
+ }
+#ifdef WITH_SSL
+ if (conn->ssl != NULL)
+ rlen = SSL_read(conn->ssl, buf, len);
+ else
+#endif
+ rlen = read(conn->sd, buf, len);
+ if (rlen == 0)
+ break;
+ if (rlen < 0) {
+ if (errno == EINTR && fetchRestartCalls)
+ continue;
+ return (-1);
+ }
+ len -= rlen;
+ buf += rlen;
+ total += rlen;
+ }
+ return (total);
+}
+
+
+/*
+ * Read a line of text from a connection w/ timeout
+ */
+#define MIN_BUF_SIZE 1024
+
+int
+_fetch_getln(conn_t *conn)
+{
+ char *tmp;
+ size_t tmpsize;
+ ssize_t len;
+ char c;
+
+ if (conn->buf == NULL) {
+ if ((conn->buf = malloc(MIN_BUF_SIZE)) == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ conn->bufsize = MIN_BUF_SIZE;
+ }
+
+ conn->buf[0] = '\0';
+ conn->buflen = 0;
+
+ do {
+ len = _fetch_read(conn, &c, 1);
+ if (len == -1)
+ return (-1);
+ if (len == 0)
+ break;
+ conn->buf[conn->buflen++] = c;
+ if (conn->buflen == conn->bufsize) {
+ tmp = conn->buf;
+ tmpsize = conn->bufsize * 2 + 1;
+ if ((tmp = realloc(tmp, tmpsize)) == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ conn->buf = tmp;
+ conn->bufsize = tmpsize;
+ }
+ } while (c != '\n');
+
+ conn->buf[conn->buflen] = '\0';
+ DEBUG(fprintf(stderr, "<<< %s", conn->buf));
+ return (0);
+}
+
+
+/*
+ * Write to a connection w/ timeout
+ */
+ssize_t
+_fetch_write(conn_t *conn, const char *buf, size_t len)
+{
+ struct iovec iov;
+
+ iov.iov_base = __DECONST(char *, buf);
+ iov.iov_len = len;
+ return _fetch_writev(conn, &iov, 1);
+}
+
+/*
+ * Write a vector to a connection w/ timeout
+ * Note: can modify the iovec.
+ */
+ssize_t
+_fetch_writev(conn_t *conn, struct iovec *iov, int iovcnt)
+{
+ struct timeval now, timeout, wait;
+ fd_set writefds;
+ ssize_t wlen, total;
+ int r;
+
+ if (fetchTimeout) {
+ FD_ZERO(&writefds);
+ gettimeofday(&timeout, NULL);
+ timeout.tv_sec += fetchTimeout;
+ }
+
+ total = 0;
+ while (iovcnt > 0) {
+ while (fetchTimeout && !FD_ISSET(conn->sd, &writefds)) {
+ FD_SET(conn->sd, &writefds);
+ gettimeofday(&now, NULL);
+ wait.tv_sec = timeout.tv_sec - now.tv_sec;
+ wait.tv_usec = timeout.tv_usec - now.tv_usec;
+ if (wait.tv_usec < 0) {
+ wait.tv_usec += 1000000;
+ wait.tv_sec--;
+ }
+ if (wait.tv_sec < 0) {
+ errno = ETIMEDOUT;
+ _fetch_syserr();
+ return (-1);
+ }
+ errno = 0;
+ r = select(conn->sd + 1, NULL, &writefds, NULL, &wait);
+ if (r == -1) {
+ if (errno == EINTR && fetchRestartCalls)
+ continue;
+ return (-1);
+ }
+ }
+ errno = 0;
+#ifdef WITH_SSL
+ if (conn->ssl != NULL)
+ wlen = SSL_write(conn->ssl,
+ iov->iov_base, iov->iov_len);
+ else
+#endif
+ wlen = writev(conn->sd, iov, iovcnt);
+ if (wlen == 0) {
+ /* we consider a short write a failure */
+ errno = EPIPE;
+ _fetch_syserr();
+ return (-1);
+ }
+ if (wlen < 0) {
+ if (errno == EINTR && fetchRestartCalls)
+ continue;
+ return (-1);
+ }
+ total += wlen;
+ while (iovcnt > 0 && wlen >= (ssize_t)iov->iov_len) {
+ wlen -= iov->iov_len;
+ iov++;
+ iovcnt--;
+ }
+ if (iovcnt > 0) {
+ iov->iov_len -= wlen;
+ iov->iov_base = __DECONST(char *, iov->iov_base) + wlen;
+ }
+ }
+ return (total);
+}
+
+
+/*
+ * Write a line of text to a connection w/ timeout
+ */
+int
+_fetch_putln(conn_t *conn, const char *str, size_t len)
+{
+ struct iovec iov[2];
+ int ret;
+
+ DEBUG(fprintf(stderr, ">>> %s\n", str));
+ iov[0].iov_base = __DECONST(char *, str);
+ iov[0].iov_len = len;
+ iov[1].iov_base = __DECONST(char *, ENDL);
+ iov[1].iov_len = sizeof(ENDL);
+ if (len == 0)
+ ret = _fetch_writev(conn, &iov[1], 1);
+ else
+ ret = _fetch_writev(conn, iov, 2);
+ if (ret == -1)
+ return (-1);
+ return (0);
+}
+
+
+/*
+ * Close connection
+ */
+int
+_fetch_close(conn_t *conn)
+{
+ int ret;
+
+ if (--conn->ref > 0)
+ return (0);
+ ret = close(conn->sd);
+ free(conn->buf);
+ free(conn);
+ return (ret);
+}
+
+
+/*** Directory-related utility functions *************************************/
+
+int
+_fetch_add_entry(struct url_ent **p, int *size, int *len,
+ const char *name, struct url_stat *us)
+{
+ struct url_ent *tmp;
+
+ if (*p == NULL) {
+ *size = 0;
+ *len = 0;
+ }
+
+ if (*len >= *size - 1) {
+ tmp = realloc(*p, (*size * 2 + 1) * sizeof(**p));
+ if (tmp == NULL) {
+ errno = ENOMEM;
+ _fetch_syserr();
+ return (-1);
+ }
+ *size = (*size * 2 + 1);
+ *p = tmp;
+ }
+
+ tmp = *p + *len;
+ snprintf(tmp->name, PATH_MAX, "%s", name);
+ bcopy(us, &tmp->stat, sizeof(*us));
+
+ (*len)++;
+ (++tmp)->name[0] = 0;
+
+ return (0);
+}
+
+
+/*** Authentication-related utility functions ********************************/
+
+static const char *
+_fetch_read_word(FILE *f)
+{
+ static char word[1024];
+
+ if (fscanf(f, " %1024s ", word) != 1)
+ return (NULL);
+ return (word);
+}
+
+/*
+ * Get authentication data for a URL from .netrc
+ */
+int
+_fetch_netrc_auth(struct url *url)
+{
+ char fn[PATH_MAX];
+ const char *word;
+ char *p;
+ FILE *f;
+
+ if ((p = getenv("NETRC")) != NULL) {
+ if (snprintf(fn, sizeof(fn), "%s", p) >= (int)sizeof(fn)) {
+ _fetch_info("$NETRC specifies a file name "
+ "longer than PATH_MAX");
+ return (-1);
+ }
+ } else {
+ if ((p = getenv("HOME")) != NULL) {
+ struct passwd *pwd;
+
+ if ((pwd = getpwuid(getuid())) == NULL ||
+ (p = pwd->pw_dir) == NULL)
+ return (-1);
+ }
+ if (snprintf(fn, sizeof(fn), "%s/.netrc", p) >= (int)sizeof(fn))
+ return (-1);
+ }
+
+ if ((f = fopen(fn, "r")) == NULL)
+ return (-1);
+ while ((word = _fetch_read_word(f)) != NULL) {
+ if (strcmp(word, "default") == 0) {
+ DEBUG(_fetch_info("Using default .netrc settings"));
+ break;
+ }
+ if (strcmp(word, "machine") == 0 &&
+ (word = _fetch_read_word(f)) != NULL &&
+ strcasecmp(word, url->host) == 0) {
+ DEBUG(_fetch_info("Using .netrc settings for %s", word));
+ break;
+ }
+ }
+ if (word == NULL)
+ goto ferr;
+ while ((word = _fetch_read_word(f)) != NULL) {
+ if (strcmp(word, "login") == 0) {
+ if ((word = _fetch_read_word(f)) == NULL)
+ goto ferr;
+ if (snprintf(url->user, sizeof(url->user),
+ "%s", word) > (int)sizeof(url->user)) {
+ _fetch_info("login name in .netrc is too long");
+ url->user[0] = '\0';
+ }
+ } else if (strcmp(word, "password") == 0) {
+ if ((word = _fetch_read_word(f)) == NULL)
+ goto ferr;
+ if (snprintf(url->pwd, sizeof(url->pwd),
+ "%s", word) > (int)sizeof(url->pwd)) {
+ _fetch_info("password in .netrc is too long");
+ url->pwd[0] = '\0';
+ }
+ } else if (strcmp(word, "account") == 0) {
+ if ((word = _fetch_read_word(f)) == NULL)
+ goto ferr;
+ /* XXX not supported! */
+ } else {
+ break;
+ }
+ }
+ fclose(f);
+ return (0);
+ ferr:
+ fclose(f);
+ return (-1);
+}
diff --git a/lib/libfetch/common.h b/lib/libfetch/common.h
new file mode 100644
index 0000000..62e0846
--- /dev/null
+++ b/lib/libfetch/common.h
@@ -0,0 +1,124 @@
+/*-
+ * Copyright (c) 1998-2004 Dag-Erling Coïdan Smørgrav
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 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$
+ */
+
+#ifndef _COMMON_H_INCLUDED
+#define _COMMON_H_INCLUDED
+
+#define FTP_DEFAULT_PORT 21
+#define HTTP_DEFAULT_PORT 80
+#define FTP_DEFAULT_PROXY_PORT 21
+#define HTTP_DEFAULT_PROXY_PORT 3128
+
+#ifdef WITH_SSL
+#include <openssl/crypto.h>
+#include <openssl/x509.h>
+#include <openssl/pem.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#endif
+
+/* Connection */
+typedef struct fetchconn conn_t;
+struct fetchconn {
+ int sd; /* socket descriptor */
+ char *buf; /* buffer */
+ size_t bufsize; /* buffer size */
+ size_t buflen; /* length of buffer contents */
+ int err; /* last protocol reply code */
+#ifdef WITH_SSL
+ SSL *ssl; /* SSL handle */
+ SSL_CTX *ssl_ctx; /* SSL context */
+ X509 *ssl_cert; /* server certificate */
+ SSL_METHOD *ssl_meth; /* SSL method */
+#endif
+ int ref; /* reference count */
+};
+
+/* Structure used for error message lists */
+struct fetcherr {
+ const int num;
+ const int cat;
+ const char *string;
+};
+
+/* for _fetch_writev */
+struct iovec;
+
+void _fetch_seterr(struct fetcherr *, int);
+void _fetch_syserr(void);
+void _fetch_info(const char *, ...);
+int _fetch_default_port(const char *);
+int _fetch_default_proxy_port(const char *);
+int _fetch_bind(int, int, const char *);
+conn_t *_fetch_connect(const char *, int, int, int);
+conn_t *_fetch_reopen(int);
+conn_t *_fetch_ref(conn_t *);
+int _fetch_ssl(conn_t *, int);
+ssize_t _fetch_read(conn_t *, char *, size_t);
+int _fetch_getln(conn_t *);
+ssize_t _fetch_write(conn_t *, const char *, size_t);
+ssize_t _fetch_writev(conn_t *, struct iovec *, int);
+int _fetch_putln(conn_t *, const char *, size_t);
+int _fetch_close(conn_t *);
+int _fetch_add_entry(struct url_ent **, int *, int *,
+ const char *, struct url_stat *);
+int _fetch_netrc_auth(struct url *url);
+
+#define _ftp_seterr(n) _fetch_seterr(_ftp_errlist, n)
+#define _http_seterr(n) _fetch_seterr(_http_errlist, n)
+#define _netdb_seterr(n) _fetch_seterr(_netdb_errlist, n)
+#define _url_seterr(n) _fetch_seterr(_url_errlist, n)
+
+#ifndef NDEBUG
+#define DEBUG(x) do { if (fetchDebug) { x; } } while (0)
+#else
+#define DEBUG(x) do { } while (0)
+#endif
+
+/*
+ * I don't really like exporting _http_request() and _ftp_request(),
+ * but the HTTP and FTP code occasionally needs to cross-call
+ * eachother, and this saves me from adding a lot of special-case code
+ * to handle those cases.
+ *
+ * Note that _*_request() free purl, which is way ugly but saves us a
+ * whole lot of trouble.
+ */
+FILE *_http_request(struct url *, const char *,
+ struct url_stat *, struct url *, const char *);
+FILE *_ftp_request(struct url *, const char *,
+ struct url_stat *, struct url *, const char *);
+
+/*
+ * Check whether a particular flag is set
+ */
+#define CHECK_FLAG(x) (flags && strchr(flags, (x)))
+
+#endif
diff --git a/lib/libfetch/fetch.3 b/lib/libfetch/fetch.3
new file mode 100644
index 0000000..4c399b7
--- /dev/null
+++ b/lib/libfetch/fetch.3
@@ -0,0 +1,668 @@
+.\"-
+.\" Copyright (c) 1998-2004 Dag-Erling Coïdan Smørgrav
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING 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 1, 1998
+.Dt FETCH 3
+.Os
+.Sh NAME
+.Nm fetchMakeURL ,
+.Nm fetchParseURL ,
+.Nm fetchFreeURL ,
+.Nm fetchXGetURL ,
+.Nm fetchGetURL ,
+.Nm fetchPutURL ,
+.Nm fetchStatURL ,
+.Nm fetchListURL ,
+.Nm fetchXGet ,
+.Nm fetchGet ,
+.Nm fetchPut ,
+.Nm fetchStat ,
+.Nm fetchList ,
+.Nm fetchXGetFile ,
+.Nm fetchGetFile ,
+.Nm fetchPutFile ,
+.Nm fetchStatFile ,
+.Nm fetchListFile ,
+.Nm fetchXGetHTTP ,
+.Nm fetchGetHTTP ,
+.Nm fetchPutHTTP ,
+.Nm fetchStatHTTP ,
+.Nm fetchListHTTP ,
+.Nm fetchXGetFTP ,
+.Nm fetchGetFTP ,
+.Nm fetchPutFTP ,
+.Nm fetchStatFTP ,
+.Nm fetchListFTP
+.Nd file transfer functions
+.Sh LIBRARY
+.Lb libfetch
+.Sh SYNOPSIS
+.In sys/param.h
+.In stdio.h
+.In fetch.h
+.Ft struct url *
+.Fn fetchMakeURL "const char *scheme" "const char *host" "int port" "const char *doc" "const char *user" "const char *pwd"
+.Ft struct url *
+.Fn fetchParseURL "const char *URL"
+.Ft void
+.Fn fetchFreeURL "struct url *u"
+.Ft FILE *
+.Fn fetchXGetURL "const char *URL" "struct url_stat *us" "const char *flags"
+.Ft FILE *
+.Fn fetchGetURL "const char *URL" "const char *flags"
+.Ft FILE *
+.Fn fetchPutURL "const char *URL" "const char *flags"
+.Ft int
+.Fn fetchStatURL "const char *URL" "struct url_stat *us" "const char *flags"
+.Ft struct url_ent *
+.Fn fetchListURL "const char *URL" "const char *flags"
+.Ft FILE *
+.Fn fetchXGet "struct url *u" "struct url_stat *us" "const char *flags"
+.Ft FILE *
+.Fn fetchGet "struct url *u" "const char *flags"
+.Ft FILE *
+.Fn fetchPut "struct url *u" "const char *flags"
+.Ft int
+.Fn fetchStat "struct url *u" "struct url_stat *us" "const char *flags"
+.Ft struct url_ent *
+.Fn fetchList "struct url *u" "const char *flags"
+.Ft FILE *
+.Fn fetchXGetFile "struct url *u" "struct url_stat *us" "const char *flags"
+.Ft FILE *
+.Fn fetchGetFile "struct url *u" "const char *flags"
+.Ft FILE *
+.Fn fetchPutFile "struct url *u" "const char *flags"
+.Ft int
+.Fn fetchStatFile "struct url *u" "struct url_stat *us" "const char *flags"
+.Ft struct url_ent *
+.Fn fetchListFile "struct url *u" "const char *flags"
+.Ft FILE *
+.Fn fetchXGetHTTP "struct url *u" "struct url_stat *us" "const char *flags"
+.Ft FILE *
+.Fn fetchGetHTTP "struct url *u" "const char *flags"
+.Ft FILE *
+.Fn fetchPutHTTP "struct url *u" "const char *flags"
+.Ft int
+.Fn fetchStatHTTP "struct url *u" "struct url_stat *us" "const char *flags"
+.Ft struct url_ent *
+.Fn fetchListHTTP "struct url *u" "const char *flags"
+.Ft FILE *
+.Fn fetchXGetFTP "struct url *u" "struct url_stat *us" "const char *flags"
+.Ft FILE *
+.Fn fetchGetFTP "struct url *u" "const char *flags"
+.Ft FILE *
+.Fn fetchPutFTP "struct url *u" "const char *flags"
+.Ft int
+.Fn fetchStatFTP "struct url *u" "struct url_stat *us" "const char *flags"
+.Ft struct url_ent *
+.Fn fetchListFTP "struct url *u" "const char *flags"
+.Sh DESCRIPTION
+These functions implement a high-level library for retrieving and
+uploading files using Uniform Resource Locators (URLs).
+.Pp
+.Fn fetchParseURL
+takes a URL in the form of a null-terminated string and splits it into
+its components function according to the Common Internet Scheme Syntax
+detailed in RFC1738.
+A regular expression which produces this syntax is:
+.Bd -literal
+ <scheme>:(//(<user>(:<pwd>)?@)?<host>(:<port>)?)?/(<document>)?
+.Ed
+.Pp
+If the URL does not seem to begin with a scheme name, the following
+syntax is assumed:
+.Bd -literal
+ ((<user>(:<pwd>)?@)?<host>(:<port>)?)?/(<document>)?
+.Ed
+.Pp
+Note that some components of the URL are not necessarily relevant to
+all URL schemes.
+For instance, the file scheme only needs the <scheme> and <document>
+components.
+.Pp
+.Fn fetchMakeURL
+and
+.Fn fetchParseURL
+return a pointer to a
+.Vt url
+structure, which is defined as follows in
+.In fetch.h :
+.Bd -literal
+#define URL_SCHEMELEN 16
+#define URL_USERLEN 256
+#define URL_PWDLEN 256
+
+struct url {
+ char scheme[URL_SCHEMELEN+1];
+ char user[URL_USERLEN+1];
+ char pwd[URL_PWDLEN+1];
+ char host[MAXHOSTNAMELEN+1];
+ int port;
+ char *doc;
+ off_t offset;
+ size_t length;
+};
+.Ed
+.Pp
+The pointer returned by
+.Fn fetchMakeURL
+or
+.Fn fetchParseURL
+should be freed using
+.Fn fetchFreeURL .
+.Pp
+.Fn fetchXGetURL ,
+.Fn fetchGetURL ,
+and
+.Fn fetchPutURL
+constitute the recommended interface to the
+.Nm fetch
+library.
+They examine the URL passed to them to determine the transfer
+method, and call the appropriate lower-level functions to perform the
+actual transfer.
+.Fn fetchXGetURL
+also returns the remote document's metadata in the
+.Vt url_stat
+structure pointed to by the
+.Fa us
+argument.
+.Pp
+The
+.Fa flags
+argument is a string of characters which specify transfer options.
+The
+meaning of the individual flags is scheme-dependent, and is detailed
+in the appropriate section below.
+.Pp
+.Fn fetchStatURL
+attempts to obtain the requested document's metadata and fill in the
+structure pointed to by its second argument.
+The
+.Vt url_stat
+structure is defined as follows in
+.In fetch.h :
+.Bd -literal
+struct url_stat {
+ off_t size;
+ time_t atime;
+ time_t mtime;
+};
+.Ed
+.Pp
+If the size could not be obtained from the server, the
+.Fa size
+field is set to -1.
+If the modification time could not be obtained from the server, the
+.Fa mtime
+field is set to the epoch.
+If the access time could not be obtained from the server, the
+.Fa atime
+field is set to the modification time.
+.Pp
+.Fn fetchListURL
+attempts to list the contents of the directory pointed to by the URL
+provided.
+If successful, it returns a malloced array of
+.Vt url_ent
+structures.
+The
+.Vt url_ent
+structure is defined as follows in
+.In fetch.h :
+.Bd -literal
+struct url_ent {
+ char name[MAXPATHLEN];
+ struct url_stat stat;
+};
+.Ed
+.Pp
+The list is terminated by an entry with an empty name.
+.Pp
+The pointer returned by
+.Fn fetchListURL
+should be freed using
+.Fn free .
+.Pp
+.Fn fetchXGet ,
+.Fn fetchGet ,
+.Fn fetchPut
+and
+.Fn fetchStat
+are similar to
+.Fn fetchXGetURL ,
+.Fn fetchGetURL ,
+.Fn fetchPutURL
+and
+.Fn fetchStatURL ,
+except that they expect a pre-parsed URL in the form of a pointer to
+a
+.Vt struct url
+rather than a string.
+.Pp
+All of the
+.Fn fetchXGetXXX ,
+.Fn fetchGetXXX
+and
+.Fn fetchPutXXX
+functions return a pointer to a stream which can be used to read or
+write data from or to the requested document, respectively.
+Note that
+although the implementation details of the individual access methods
+vary, it can generally be assumed that a stream returned by one of the
+.Fn fetchXGetXXX
+or
+.Fn fetchGetXXX
+functions is read-only, and that a stream returned by one of the
+.Fn fetchPutXXX
+functions is write-only.
+.Sh FILE SCHEME
+.Fn fetchXGetFile ,
+.Fn fetchGetFile
+and
+.Fn fetchPutFile
+provide access to documents which are files in a locally mounted file
+system.
+Only the <document> component of the URL is used.
+.Pp
+.Fn fetchXGetFile
+and
+.Fn fetchGetFile
+do not accept any flags.
+.Pp
+.Fn fetchPutFile
+accepts the
+.Ql a
+(append to file) flag.
+If that flag is specified, the data written to
+the stream returned by
+.Fn fetchPutFile
+will be appended to the previous contents of the file, instead of
+replacing them.
+.Sh FTP SCHEME
+.Fn fetchXGetFTP ,
+.Fn fetchGetFTP
+and
+.Fn fetchPutFTP
+implement the FTP protocol as described in RFC959.
+.Pp
+If the
+.Ql p
+(passive) flag is specified, a passive (rather than active) connection
+will be attempted.
+.Pp
+If the
+.Ql l
+(low) flag is specified, data sockets will be allocated in the low (or
+default) port range instead of the high port range (see
+.Xr ip 4 ) .
+.Pp
+If the
+.Ql d
+(direct) flag is specified,
+.Fn fetchXGetFTP ,
+.Fn fetchGetFTP
+and
+.Fn fetchPutFTP
+will use a direct connection even if a proxy server is defined.
+.Pp
+If no user name or password is given, the
+.Nm fetch
+library will attempt an anonymous login, with user name "anonymous"
+and password "anonymous@<hostname>".
+.Sh HTTP SCHEME
+The
+.Fn fetchXGetHTTP ,
+.Fn fetchGetHTTP
+and
+.Fn fetchPutHTTP
+functions implement the HTTP/1.1 protocol.
+With a little luck, there is
+even a chance that they comply with RFC2616 and RFC2617.
+.Pp
+If the
+.Ql d
+(direct) flag is specified,
+.Fn fetchXGetHTTP ,
+.Fn fetchGetHTTP
+and
+.Fn fetchPutHTTP
+will use a direct connection even if a proxy server is defined.
+.Pp
+Since there seems to be no good way of implementing the HTTP PUT
+method in a manner consistent with the rest of the
+.Nm fetch
+library,
+.Fn fetchPutHTTP
+is currently unimplemented.
+.Sh AUTHENTICATION
+Apart from setting the appropriate environment variables and
+specifying the user name and password in the URL or the
+.Vt struct url ,
+the calling program has the option of defining an authentication
+function with the following prototype:
+.Pp
+.Ft int
+.Fn myAuthMethod "struct url *u"
+.Pp
+The callback function should fill in the
+.Fa user
+and
+.Fa pwd
+fields in the provided
+.Vt struct url
+and return 0 on success, or any other value to indicate failure.
+.Pp
+To register the authentication callback, simply set
+.Va fetchAuthMethod
+to point at it.
+The callback will be used whenever a site requires authentication and
+the appropriate environment variables are not set.
+.Pp
+This interface is experimental and may be subject to change.
+.Sh RETURN VALUES
+.Fn fetchParseURL
+returns a pointer to a
+.Vt struct url
+containing the individual components of the URL.
+If it is
+unable to allocate memory, or the URL is syntactically incorrect,
+.Fn fetchParseURL
+returns a NULL pointer.
+.Pp
+The
+.Fn fetchStat
+functions return 0 on success and -1 on failure.
+.Pp
+All other functions return a stream pointer which may be used to
+access the requested document, or NULL if an error occurred.
+.Pp
+The following error codes are defined in
+.In fetch.h :
+.Bl -tag -width 18n
+.It Bq Er FETCH_ABORT
+Operation aborted
+.It Bq Er FETCH_AUTH
+Authentication failed
+.It Bq Er FETCH_DOWN
+Service unavailable
+.It Bq Er FETCH_EXISTS
+File exists
+.It Bq Er FETCH_FULL
+File system full
+.It Bq Er FETCH_INFO
+Informational response
+.It Bq Er FETCH_MEMORY
+Insufficient memory
+.It Bq Er FETCH_MOVED
+File has moved
+.It Bq Er FETCH_NETWORK
+Network error
+.It Bq Er FETCH_OK
+No error
+.It Bq Er FETCH_PROTO
+Protocol error
+.It Bq Er FETCH_RESOLV
+Resolver error
+.It Bq Er FETCH_SERVER
+Server error
+.It Bq Er FETCH_TEMP
+Temporary error
+.It Bq Er FETCH_TIMEOUT
+Operation timed out
+.It Bq Er FETCH_UNAVAIL
+File is not available
+.It Bq Er FETCH_UNKNOWN
+Unknown error
+.It Bq Er FETCH_URL
+Invalid URL
+.El
+.Pp
+The accompanying error message includes a protocol-specific error code
+and message, e.g.\& "File is not available (404 Not Found)"
+.Sh ENVIRONMENT
+.Bl -tag -width ".Ev FETCH_BIND_ADDRESS"
+.It Ev FETCH_BIND_ADDRESS
+Specifies a hostname or IP address to which sockets used for outgoing
+connections will be bound.
+.It Ev FTP_LOGIN
+Default FTP login if none was provided in the URL.
+.It Ev FTP_PASSIVE_MODE
+If set to anything but
+.Ql no ,
+forces the FTP code to use passive mode.
+.It Ev FTP_PASSWORD
+Default FTP password if the remote server requests one and none was
+provided in the URL.
+.It Ev FTP_PROXY
+URL of the proxy to use for FTP requests.
+The document part is ignored.
+FTP and HTTP proxies are supported; if no scheme is specified, FTP is
+assumed.
+If the proxy is an FTP proxy,
+.Nm libfetch
+will send
+.Ql user@host
+as user name to the proxy, where
+.Ql user
+is the real user name, and
+.Ql host
+is the name of the FTP server.
+.Pp
+If this variable is set to an empty string, no proxy will be used for
+FTP requests, even if the
+.Ev HTTP_PROXY
+variable is set.
+.It Ev ftp_proxy
+Same as
+.Ev FTP_PROXY ,
+for compatibility.
+.It Ev HTTP_AUTH
+Specifies HTTP authorization parameters as a colon-separated list of
+items.
+The first and second item are the authorization scheme and realm
+respectively; further items are scheme-dependent.
+Currently, only basic authorization is supported.
+.Pp
+Basic authorization requires two parameters: the user name and
+password, in that order.
+.Pp
+This variable is only used if the server requires authorization and
+no user name or password was specified in the URL.
+.It Ev HTTP_PROXY
+URL of the proxy to use for HTTP requests.
+The document part is ignored.
+Only HTTP proxies are supported for HTTP requests.
+If no port number is specified, the default is 3128.
+.Pp
+Note that this proxy will also be used for FTP documents, unless the
+.Ev FTP_PROXY
+variable is set.
+.It Ev http_proxy
+Same as
+.Ev HTTP_PROXY ,
+for compatibility.
+.It Ev HTTP_PROXY_AUTH
+Specifies authorization parameters for the HTTP proxy in the same
+format as the
+.Ev HTTP_AUTH
+variable.
+.Pp
+This variable is used if and only if connected to an HTTP proxy, and
+is ignored if a user and/or a password were specified in the proxy
+URL.
+.It Ev HTTP_REFERER
+Specifies the referrer URL to use for HTTP requests.
+If set to
+.Dq auto ,
+the document URL will be used as referrer URL.
+.It Ev HTTP_USER_AGENT
+Specifies the User-Agent string to use for HTTP requests.
+This can be useful when working with HTTP origin or proxy servers that
+differentiate between user agents.
+.It Ev NETRC
+Specifies a file to use instead of
+.Pa ~/.netrc
+to look up login names and passwords for FTP sites.
+See
+.Xr ftp 1
+for a description of the file format.
+This feature is experimental.
+.El
+.Sh EXAMPLES
+To access a proxy server on
+.Pa proxy.example.com
+port 8080, set the
+.Ev HTTP_PROXY
+environment variable in a manner similar to this:
+.Pp
+.Dl HTTP_PROXY=http://proxy.example.com:8080
+.Pp
+If the proxy server requires authentication, there are
+two options available for passing the authentication data.
+The first method is by using the proxy URL:
+.Pp
+.Dl HTTP_PROXY=http://<user>:<pwd>@proxy.example.com:8080
+.Pp
+The second method is by using the
+.Ev HTTP_PROXY_AUTH
+environment variable:
+.Bd -literal -offset indent
+HTTP_PROXY=http://proxy.example.com:8080
+HTTP_PROXY_AUTH=basic:*:<user>:<pwd>
+.Ed
+.Sh SEE ALSO
+.Xr fetch 1 ,
+.Xr ftpio 3 ,
+.Xr ip 4
+.Rs
+.%A J. Postel
+.%A J. K. Reynolds
+.%D October 1985
+.%B File Transfer Protocol
+.%O RFC959
+.Re
+.Rs
+.%A P. Deutsch
+.%A A. Emtage
+.%A A. Marine.
+.%D May 1994
+.%T How to Use Anonymous FTP
+.%O RFC1635
+.Re
+.Rs
+.%A T. Berners-Lee
+.%A L. Masinter
+.%A M. McCahill
+.%D December 1994
+.%T Uniform Resource Locators (URL)
+.%O RFC1738
+.Re
+.Rs
+.%A R. Fielding
+.%A J. Gettys
+.%A J. Mogul
+.%A H. Frystyk
+.%A L. Masinter
+.%A P. Leach
+.%A T. Berners-Lee
+.%D January 1999
+.%B Hypertext Transfer Protocol -- HTTP/1.1
+.%O RFC2616
+.Re
+.Rs
+.%A J. Franks
+.%A P. Hallam-Baker
+.%A J. Hostetler
+.%A S. Lawrence
+.%A P. Leach
+.%A A. Luotonen
+.%A L. Stewart
+.%D June 1999
+.%B HTTP Authentication: Basic and Digest Access Authentication
+.%O RFC2617
+.Re
+.Sh HISTORY
+The
+.Nm fetch
+library first appeared in
+.Fx 3.0 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm fetch
+library was mostly written by
+.An Dag-Erling Sm\(/orgrav Aq des@FreeBSD.org
+with numerous suggestions from
+.An Jordan K. Hubbard Aq jkh@FreeBSD.org ,
+.An Eugene Skepner Aq eu@qub.com
+and other
+.Fx
+developers.
+It replaces the older
+.Nm ftpio
+library written by
+.An Poul-Henning Kamp Aq phk@FreeBSD.org
+and
+.An Jordan K. Hubbard Aq jkh@FreeBSD.org .
+.Pp
+This manual page was written by
+.An Dag-Erling Sm\(/orgrav Aq des@FreeBSD.org .
+.Sh BUGS
+Some parts of the library are not yet implemented.
+The most notable
+examples of this are
+.Fn fetchPutHTTP ,
+.Fn fetchListHTTP ,
+.Fn fetchListFTP
+and FTP proxy support.
+.Pp
+There is no way to select a proxy at run-time other than setting the
+.Ev HTTP_PROXY
+or
+.Ev FTP_PROXY
+environment variables as appropriate.
+.Pp
+.Nm libfetch
+does not understand or obey 305 (Use Proxy) replies.
+.Pp
+Error numbers are unique only within a certain context; the error
+codes used for FTP and HTTP overlap, as do those used for resolver and
+system errors.
+For instance, error code 202 means "Command not
+implemented, superfluous at this site" in an FTP context and
+"Accepted" in an HTTP context.
+.Pp
+.Fn fetchStatFTP
+does not check that the result of an MDTM command is a valid date.
+.Pp
+The man page is incomplete, poorly written and produces badly
+formatted text.
+.Pp
+The error reporting mechanism is unsatisfactory.
+.Pp
+Some parts of the code are not fully reentrant.
diff --git a/lib/libfetch/fetch.c b/lib/libfetch/fetch.c
new file mode 100644
index 0000000..403a2dba
--- /dev/null
+++ b/lib/libfetch/fetch.c
@@ -0,0 +1,438 @@
+/*-
+ * Copyright (c) 1998-2004 Dag-Erling Coïdan Smørgrav
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 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/param.h>
+#include <sys/errno.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "fetch.h"
+#include "common.h"
+
+auth_t fetchAuthMethod;
+int fetchLastErrCode;
+char fetchLastErrString[MAXERRSTRING];
+int fetchTimeout;
+int fetchRestartCalls = 1;
+int fetchDebug;
+
+
+/*** Local data **************************************************************/
+
+/*
+ * Error messages for parser errors
+ */
+#define URL_MALFORMED 1
+#define URL_BAD_SCHEME 2
+#define URL_BAD_PORT 3
+static struct fetcherr _url_errlist[] = {
+ { URL_MALFORMED, FETCH_URL, "Malformed URL" },
+ { URL_BAD_SCHEME, FETCH_URL, "Invalid URL scheme" },
+ { URL_BAD_PORT, FETCH_URL, "Invalid server port" },
+ { -1, FETCH_UNKNOWN, "Unknown parser error" }
+};
+
+
+/*** Public API **************************************************************/
+
+/*
+ * Select the appropriate protocol for the URL scheme, and return a
+ * read-only stream connected to the document referenced by the URL.
+ * Also fill out the struct url_stat.
+ */
+FILE *
+fetchXGet(struct url *URL, struct url_stat *us, const char *flags)
+{
+ int direct;
+
+ direct = CHECK_FLAG('d');
+ if (us != NULL) {
+ us->size = -1;
+ us->atime = us->mtime = 0;
+ }
+ if (strcasecmp(URL->scheme, SCHEME_FILE) == 0)
+ return (fetchXGetFile(URL, us, flags));
+ else if (strcasecmp(URL->scheme, SCHEME_FTP) == 0)
+ return (fetchXGetFTP(URL, us, flags));
+ else if (strcasecmp(URL->scheme, SCHEME_HTTP) == 0)
+ return (fetchXGetHTTP(URL, us, flags));
+ else if (strcasecmp(URL->scheme, SCHEME_HTTPS) == 0)
+ return (fetchXGetHTTP(URL, us, flags));
+ _url_seterr(URL_BAD_SCHEME);
+ return (NULL);
+}
+
+/*
+ * Select the appropriate protocol for the URL scheme, and return a
+ * read-only stream connected to the document referenced by the URL.
+ */
+FILE *
+fetchGet(struct url *URL, const char *flags)
+{
+ return (fetchXGet(URL, NULL, flags));
+}
+
+/*
+ * Select the appropriate protocol for the URL scheme, and return a
+ * write-only stream connected to the document referenced by the URL.
+ */
+FILE *
+fetchPut(struct url *URL, const char *flags)
+{
+ int direct;
+
+ direct = CHECK_FLAG('d');
+ if (strcasecmp(URL->scheme, SCHEME_FILE) == 0)
+ return (fetchPutFile(URL, flags));
+ else if (strcasecmp(URL->scheme, SCHEME_FTP) == 0)
+ return (fetchPutFTP(URL, flags));
+ else if (strcasecmp(URL->scheme, SCHEME_HTTP) == 0)
+ return (fetchPutHTTP(URL, flags));
+ else if (strcasecmp(URL->scheme, SCHEME_HTTPS) == 0)
+ return (fetchPutHTTP(URL, flags));
+ _url_seterr(URL_BAD_SCHEME);
+ return (NULL);
+}
+
+/*
+ * Select the appropriate protocol for the URL scheme, and return the
+ * size of the document referenced by the URL if it exists.
+ */
+int
+fetchStat(struct url *URL, struct url_stat *us, const char *flags)
+{
+ int direct;
+
+ direct = CHECK_FLAG('d');
+ if (us != NULL) {
+ us->size = -1;
+ us->atime = us->mtime = 0;
+ }
+ if (strcasecmp(URL->scheme, SCHEME_FILE) == 0)
+ return (fetchStatFile(URL, us, flags));
+ else if (strcasecmp(URL->scheme, SCHEME_FTP) == 0)
+ return (fetchStatFTP(URL, us, flags));
+ else if (strcasecmp(URL->scheme, SCHEME_HTTP) == 0)
+ return (fetchStatHTTP(URL, us, flags));
+ else if (strcasecmp(URL->scheme, SCHEME_HTTPS) == 0)
+ return (fetchStatHTTP(URL, us, flags));
+ _url_seterr(URL_BAD_SCHEME);
+ return (-1);
+}
+
+/*
+ * Select the appropriate protocol for the URL scheme, and return a
+ * list of files in the directory pointed to by the URL.
+ */
+struct url_ent *
+fetchList(struct url *URL, const char *flags)
+{
+ int direct;
+
+ direct = CHECK_FLAG('d');
+ if (strcasecmp(URL->scheme, SCHEME_FILE) == 0)
+ return (fetchListFile(URL, flags));
+ else if (strcasecmp(URL->scheme, SCHEME_FTP) == 0)
+ return (fetchListFTP(URL, flags));
+ else if (strcasecmp(URL->scheme, SCHEME_HTTP) == 0)
+ return (fetchListHTTP(URL, flags));
+ else if (strcasecmp(URL->scheme, SCHEME_HTTPS) == 0)
+ return (fetchListHTTP(URL, flags));
+ _url_seterr(URL_BAD_SCHEME);
+ return (NULL);
+}
+
+/*
+ * Attempt to parse the given URL; if successful, call fetchXGet().
+ */
+FILE *
+fetchXGetURL(const char *URL, struct url_stat *us, const char *flags)
+{
+ struct url *u;
+ FILE *f;
+
+ if ((u = fetchParseURL(URL)) == NULL)
+ return (NULL);
+
+ f = fetchXGet(u, us, flags);
+
+ fetchFreeURL(u);
+ return (f);
+}
+
+/*
+ * Attempt to parse the given URL; if successful, call fetchGet().
+ */
+FILE *
+fetchGetURL(const char *URL, const char *flags)
+{
+ return (fetchXGetURL(URL, NULL, flags));
+}
+
+/*
+ * Attempt to parse the given URL; if successful, call fetchPut().
+ */
+FILE *
+fetchPutURL(const char *URL, const char *flags)
+{
+ struct url *u;
+ FILE *f;
+
+ if ((u = fetchParseURL(URL)) == NULL)
+ return (NULL);
+
+ f = fetchPut(u, flags);
+
+ fetchFreeURL(u);
+ return (f);
+}
+
+/*
+ * Attempt to parse the given URL; if successful, call fetchStat().
+ */
+int
+fetchStatURL(const char *URL, struct url_stat *us, const char *flags)
+{
+ struct url *u;
+ int s;
+
+ if ((u = fetchParseURL(URL)) == NULL)
+ return (-1);
+
+ s = fetchStat(u, us, flags);
+
+ fetchFreeURL(u);
+ return (s);
+}
+
+/*
+ * Attempt to parse the given URL; if successful, call fetchList().
+ */
+struct url_ent *
+fetchListURL(const char *URL, const char *flags)
+{
+ struct url *u;
+ struct url_ent *ue;
+
+ if ((u = fetchParseURL(URL)) == NULL)
+ return (NULL);
+
+ ue = fetchList(u, flags);
+
+ fetchFreeURL(u);
+ return (ue);
+}
+
+/*
+ * Make a URL
+ */
+struct url *
+fetchMakeURL(const char *scheme, const char *host, int port, const char *doc,
+ const char *user, const char *pwd)
+{
+ struct url *u;
+
+ if (!scheme || (!host && !doc)) {
+ _url_seterr(URL_MALFORMED);
+ return (NULL);
+ }
+
+ if (port < 0 || port > 65535) {
+ _url_seterr(URL_BAD_PORT);
+ return (NULL);
+ }
+
+ /* allocate struct url */
+ if ((u = calloc(1, sizeof(*u))) == NULL) {
+ _fetch_syserr();
+ return (NULL);
+ }
+
+ if ((u->doc = strdup(doc ? doc : "/")) == NULL) {
+ _fetch_syserr();
+ free(u);
+ return (NULL);
+ }
+
+#define seturl(x) snprintf(u->x, sizeof(u->x), "%s", x)
+ seturl(scheme);
+ seturl(host);
+ seturl(user);
+ seturl(pwd);
+#undef seturl
+ u->port = port;
+
+ return (u);
+}
+
+/*
+ * Split an URL into components. URL syntax is:
+ * [method:/][/[user[:pwd]@]host[:port]/][document]
+ * This almost, but not quite, RFC1738 URL syntax.
+ */
+struct url *
+fetchParseURL(const char *URL)
+{
+ char *doc;
+ const char *p, *q;
+ struct url *u;
+ int i;
+
+ /* allocate struct url */
+ if ((u = calloc(1, sizeof(*u))) == NULL) {
+ _fetch_syserr();
+ return (NULL);
+ }
+
+ /* scheme name */
+ if ((p = strstr(URL, ":/"))) {
+ snprintf(u->scheme, URL_SCHEMELEN+1,
+ "%.*s", (int)(p - URL), URL);
+ URL = ++p;
+ /*
+ * Only one slash: no host, leave slash as part of document
+ * Two slashes: host follows, strip slashes
+ */
+ if (URL[1] == '/')
+ URL = (p += 2);
+ } else {
+ p = URL;
+ }
+ if (!*URL || *URL == '/' || *URL == '.' ||
+ (u->scheme[0] == '\0' &&
+ strchr(URL, '/') == NULL && strchr(URL, ':') == NULL))
+ goto nohost;
+
+ p = strpbrk(URL, "/@");
+ if (p && *p == '@') {
+ /* username */
+ for (q = URL, i = 0; (*q != ':') && (*q != '@'); q++)
+ if (i < URL_USERLEN)
+ u->user[i++] = *q;
+
+ /* password */
+ if (*q == ':')
+ for (q++, i = 0; (*q != ':') && (*q != '@'); q++)
+ if (i < URL_PWDLEN)
+ u->pwd[i++] = *q;
+
+ p++;
+ } else {
+ p = URL;
+ }
+
+ /* hostname */
+#ifdef INET6
+ if (*p == '[' && (q = strchr(p + 1, ']')) != NULL &&
+ (*++q == '\0' || *q == '/' || *q == ':')) {
+ if ((i = q - p - 2) > MAXHOSTNAMELEN)
+ i = MAXHOSTNAMELEN;
+ strncpy(u->host, ++p, i);
+ p = q;
+ } else
+#endif
+ for (i = 0; *p && (*p != '/') && (*p != ':'); p++)
+ if (i < MAXHOSTNAMELEN)
+ u->host[i++] = *p;
+
+ /* port */
+ if (*p == ':') {
+ for (q = ++p; *q && (*q != '/'); q++)
+ if (isdigit(*q))
+ u->port = u->port * 10 + (*q - '0');
+ else {
+ /* invalid port */
+ _url_seterr(URL_BAD_PORT);
+ goto ouch;
+ }
+ p = q;
+ }
+
+nohost:
+ /* document */
+ if (!*p)
+ p = "/";
+
+ if (strcasecmp(u->scheme, SCHEME_HTTP) == 0 ||
+ strcasecmp(u->scheme, SCHEME_HTTPS) == 0) {
+ const char hexnums[] = "0123456789abcdef";
+
+ /* percent-escape whitespace. */
+ if ((doc = malloc(strlen(p) * 3 + 1)) == NULL) {
+ _fetch_syserr();
+ goto ouch;
+ }
+ u->doc = doc;
+ while (*p != '\0') {
+ if (!isspace(*p)) {
+ *doc++ = *p++;
+ } else {
+ *doc++ = '%';
+ *doc++ = hexnums[((unsigned int)*p) >> 4];
+ *doc++ = hexnums[((unsigned int)*p) & 0xf];
+ p++;
+ }
+ }
+ *doc = '\0';
+ } else if ((u->doc = strdup(p)) == NULL) {
+ _fetch_syserr();
+ goto ouch;
+ }
+
+ DEBUG(fprintf(stderr,
+ "scheme: [%s]\n"
+ "user: [%s]\n"
+ "password: [%s]\n"
+ "host: [%s]\n"
+ "port: [%d]\n"
+ "document: [%s]\n",
+ u->scheme, u->user, u->pwd,
+ u->host, u->port, u->doc));
+
+ return (u);
+
+ouch:
+ free(u);
+ return (NULL);
+}
+
+/*
+ * Free a URL
+ */
+void
+fetchFreeURL(struct url *u)
+{
+ free(u->doc);
+ free(u);
+}
diff --git a/lib/libfetch/fetch.h b/lib/libfetch/fetch.h
new file mode 100644
index 0000000..10d911a
--- /dev/null
+++ b/lib/libfetch/fetch.h
@@ -0,0 +1,150 @@
+/*-
+ * Copyright (c) 1998-2004 Dag-Erling Coïdan Smørgrav
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 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$
+ */
+
+#ifndef _FETCH_H_INCLUDED
+#define _FETCH_H_INCLUDED
+
+#define _LIBFETCH_VER "libfetch/2.0"
+
+#define URL_SCHEMELEN 16
+#define URL_USERLEN 256
+#define URL_PWDLEN 256
+
+struct url {
+ char scheme[URL_SCHEMELEN+1];
+ char user[URL_USERLEN+1];
+ char pwd[URL_PWDLEN+1];
+ char host[MAXHOSTNAMELEN+1];
+ int port;
+ char *doc;
+ off_t offset;
+ size_t length;
+};
+
+struct url_stat {
+ off_t size;
+ time_t atime;
+ time_t mtime;
+};
+
+struct url_ent {
+ char name[PATH_MAX];
+ struct url_stat stat;
+};
+
+/* Recognized schemes */
+#define SCHEME_FTP "ftp"
+#define SCHEME_HTTP "http"
+#define SCHEME_HTTPS "https"
+#define SCHEME_FILE "file"
+
+/* Error codes */
+#define FETCH_ABORT 1
+#define FETCH_AUTH 2
+#define FETCH_DOWN 3
+#define FETCH_EXISTS 4
+#define FETCH_FULL 5
+#define FETCH_INFO 6
+#define FETCH_MEMORY 7
+#define FETCH_MOVED 8
+#define FETCH_NETWORK 9
+#define FETCH_OK 10
+#define FETCH_PROTO 11
+#define FETCH_RESOLV 12
+#define FETCH_SERVER 13
+#define FETCH_TEMP 14
+#define FETCH_TIMEOUT 15
+#define FETCH_UNAVAIL 16
+#define FETCH_UNKNOWN 17
+#define FETCH_URL 18
+#define FETCH_VERBOSE 19
+
+__BEGIN_DECLS
+
+/* FILE-specific functions */
+FILE *fetchXGetFile(struct url *, struct url_stat *, const char *);
+FILE *fetchGetFile(struct url *, const char *);
+FILE *fetchPutFile(struct url *, const char *);
+int fetchStatFile(struct url *, struct url_stat *, const char *);
+struct url_ent *fetchListFile(struct url *, const char *);
+
+/* HTTP-specific functions */
+FILE *fetchXGetHTTP(struct url *, struct url_stat *, const char *);
+FILE *fetchGetHTTP(struct url *, const char *);
+FILE *fetchPutHTTP(struct url *, const char *);
+int fetchStatHTTP(struct url *, struct url_stat *, const char *);
+struct url_ent *fetchListHTTP(struct url *, const char *);
+
+/* FTP-specific functions */
+FILE *fetchXGetFTP(struct url *, struct url_stat *, const char *);
+FILE *fetchGetFTP(struct url *, const char *);
+FILE *fetchPutFTP(struct url *, const char *);
+int fetchStatFTP(struct url *, struct url_stat *, const char *);
+struct url_ent *fetchListFTP(struct url *, const char *);
+
+/* Generic functions */
+FILE *fetchXGetURL(const char *, struct url_stat *, const char *);
+FILE *fetchGetURL(const char *, const char *);
+FILE *fetchPutURL(const char *, const char *);
+int fetchStatURL(const char *, struct url_stat *, const char *);
+struct url_ent *fetchListURL(const char *, const char *);
+FILE *fetchXGet(struct url *, struct url_stat *, const char *);
+FILE *fetchGet(struct url *, const char *);
+FILE *fetchPut(struct url *, const char *);
+int fetchStat(struct url *, struct url_stat *, const char *);
+struct url_ent *fetchList(struct url *, const char *);
+
+/* URL parsing */
+struct url *fetchMakeURL(const char *, const char *, int,
+ const char *, const char *, const char *);
+struct url *fetchParseURL(const char *);
+void fetchFreeURL(struct url *);
+
+__END_DECLS
+
+/* Authentication */
+typedef int (*auth_t)(struct url *);
+extern auth_t fetchAuthMethod;
+
+/* Last error code */
+extern int fetchLastErrCode;
+#define MAXERRSTRING 256
+extern char fetchLastErrString[MAXERRSTRING];
+
+/* I/O timeout */
+extern int fetchTimeout;
+
+/* Restart interrupted syscalls */
+extern int fetchRestartCalls;
+
+/* Extra verbosity */
+extern int fetchDebug;
+
+#endif
diff --git a/lib/libfetch/file.c b/lib/libfetch/file.c
new file mode 100644
index 0000000..42ce68d
--- /dev/null
+++ b/lib/libfetch/file.c
@@ -0,0 +1,146 @@
+/*-
+ * Copyright (c) 1998-2004 Dag-Erling Coïdan Smørgrav
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 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/param.h>
+#include <sys/stat.h>
+
+#include <dirent.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "fetch.h"
+#include "common.h"
+
+FILE *
+fetchXGetFile(struct url *u, struct url_stat *us, const char *flags)
+{
+ FILE *f;
+
+ if (us && fetchStatFile(u, us, flags) == -1)
+ return (NULL);
+
+ f = fopen(u->doc, "r");
+
+ if (f == NULL)
+ _fetch_syserr();
+
+ if (u->offset && fseeko(f, u->offset, SEEK_SET) == -1) {
+ fclose(f);
+ _fetch_syserr();
+ }
+
+ return (f);
+}
+
+FILE *
+fetchGetFile(struct url *u, const char *flags)
+{
+ return (fetchXGetFile(u, NULL, flags));
+}
+
+FILE *
+fetchPutFile(struct url *u, const char *flags)
+{
+ FILE *f;
+
+ if (CHECK_FLAG('a'))
+ f = fopen(u->doc, "a");
+ else
+ f = fopen(u->doc, "w+");
+
+ if (f == NULL)
+ _fetch_syserr();
+
+ if (u->offset && fseeko(f, u->offset, SEEK_SET) == -1) {
+ fclose(f);
+ _fetch_syserr();
+ }
+
+ return (f);
+}
+
+static int
+_fetch_stat_file(const char *fn, struct url_stat *us)
+{
+ struct stat sb;
+
+ us->size = -1;
+ us->atime = us->mtime = 0;
+ if (stat(fn, &sb) == -1) {
+ _fetch_syserr();
+ return (-1);
+ }
+ us->size = sb.st_size;
+ us->atime = sb.st_atime;
+ us->mtime = sb.st_mtime;
+ return (0);
+}
+
+int
+fetchStatFile(struct url *u, struct url_stat *us, const char *flags __unused)
+{
+ return (_fetch_stat_file(u->doc, us));
+}
+
+struct url_ent *
+fetchListFile(struct url *u, const char *flags __unused)
+{
+ struct dirent *de;
+ struct url_stat us;
+ struct url_ent *ue;
+ int size, len;
+ char fn[PATH_MAX], *p;
+ DIR *dir;
+ int l;
+
+ if ((dir = opendir(u->doc)) == NULL) {
+ _fetch_syserr();
+ return (NULL);
+ }
+
+ ue = NULL;
+ strncpy(fn, u->doc, sizeof(fn) - 2);
+ fn[sizeof(fn) - 2] = 0;
+ strcat(fn, "/");
+ p = strchr(fn, 0);
+ l = sizeof(fn) - strlen(fn) - 1;
+
+ while ((de = readdir(dir)) != NULL) {
+ strncpy(p, de->d_name, l - 1);
+ p[l - 1] = 0;
+ if (_fetch_stat_file(fn, &us) == -1)
+ /* should I return a partial result, or abort? */
+ break;
+ _fetch_add_entry(&ue, &size, &len, de->d_name, &us);
+ }
+
+ return (ue);
+}
diff --git a/lib/libfetch/ftp.c b/lib/libfetch/ftp.c
new file mode 100644
index 0000000..cd8ff0d
--- /dev/null
+++ b/lib/libfetch/ftp.c
@@ -0,0 +1,1159 @@
+/*-
+ * Copyright (c) 1998-2004 Dag-Erling Coïdan Smørgrav
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 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$");
+
+/*
+ * Portions of this code were taken from or based on ftpio.c:
+ *
+ * ----------------------------------------------------------------------------
+ * "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
+ * ----------------------------------------------------------------------------
+ *
+ * Major Changelog:
+ *
+ * Dag-Erling Coïdan Smørgrav
+ * 9 Jun 1998
+ *
+ * Incorporated into libfetch
+ *
+ * Jordan K. Hubbard
+ * 17 Jan 1996
+ *
+ * Turned inside out. Now returns xfers as new file ids, not as a special
+ * `state' of FTP_t
+ *
+ * $ftpioId: ftpio.c,v 1.30 1998/04/11 07:28:53 phk Exp $
+ *
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "fetch.h"
+#include "common.h"
+#include "ftperr.h"
+
+#define FTP_ANONYMOUS_USER "anonymous"
+
+#define FTP_CONNECTION_ALREADY_OPEN 125
+#define FTP_OPEN_DATA_CONNECTION 150
+#define FTP_OK 200
+#define FTP_FILE_STATUS 213
+#define FTP_SERVICE_READY 220
+#define FTP_TRANSFER_COMPLETE 226
+#define FTP_PASSIVE_MODE 227
+#define FTP_LPASSIVE_MODE 228
+#define FTP_EPASSIVE_MODE 229
+#define FTP_LOGGED_IN 230
+#define FTP_FILE_ACTION_OK 250
+#define FTP_DIRECTORY_CREATED 257 /* multiple meanings */
+#define FTP_FILE_CREATED 257 /* multiple meanings */
+#define FTP_WORKING_DIRECTORY 257 /* multiple meanings */
+#define FTP_NEED_PASSWORD 331
+#define FTP_NEED_ACCOUNT 332
+#define FTP_FILE_OK 350
+#define FTP_SYNTAX_ERROR 500
+#define FTP_PROTOCOL_ERROR 999
+
+static struct url cached_host;
+static conn_t *cached_connection;
+
+#define isftpreply(foo) (isdigit(foo[0]) && isdigit(foo[1]) \
+ && isdigit(foo[2]) \
+ && (foo[3] == ' ' || foo[3] == '\0'))
+#define isftpinfo(foo) (isdigit(foo[0]) && isdigit(foo[1]) \
+ && isdigit(foo[2]) && foo[3] == '-')
+
+/*
+ * Translate IPv4 mapped IPv6 address to IPv4 address
+ */
+static void
+unmappedaddr(struct sockaddr_in6 *sin6)
+{
+ struct sockaddr_in *sin4;
+ u_int32_t addr;
+ int port;
+
+ if (sin6->sin6_family != AF_INET6 ||
+ !IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
+ return;
+ sin4 = (struct sockaddr_in *)sin6;
+ addr = *(u_int32_t *)&sin6->sin6_addr.s6_addr[12];
+ port = sin6->sin6_port;
+ memset(sin4, 0, sizeof(struct sockaddr_in));
+ sin4->sin_addr.s_addr = addr;
+ sin4->sin_port = port;
+ sin4->sin_family = AF_INET;
+ sin4->sin_len = sizeof(struct sockaddr_in);
+}
+
+/*
+ * Get server response
+ */
+static int
+_ftp_chkerr(conn_t *conn)
+{
+ if (_fetch_getln(conn) == -1) {
+ _fetch_syserr();
+ return (-1);
+ }
+ if (isftpinfo(conn->buf)) {
+ while (conn->buflen && !isftpreply(conn->buf)) {
+ if (_fetch_getln(conn) == -1) {
+ _fetch_syserr();
+ return (-1);
+ }
+ }
+ }
+
+ while (conn->buflen && isspace(conn->buf[conn->buflen - 1]))
+ conn->buflen--;
+ conn->buf[conn->buflen] = '\0';
+
+ if (!isftpreply(conn->buf)) {
+ _ftp_seterr(FTP_PROTOCOL_ERROR);
+ return (-1);
+ }
+
+ conn->err = (conn->buf[0] - '0') * 100
+ + (conn->buf[1] - '0') * 10
+ + (conn->buf[2] - '0');
+
+ return (conn->err);
+}
+
+/*
+ * Send a command and check reply
+ */
+static int
+_ftp_cmd(conn_t *conn, const char *fmt, ...)
+{
+ va_list ap;
+ size_t len;
+ char *msg;
+ int r;
+
+ va_start(ap, fmt);
+ len = vasprintf(&msg, fmt, ap);
+ va_end(ap);
+
+ if (msg == NULL) {
+ errno = ENOMEM;
+ _fetch_syserr();
+ return (-1);
+ }
+
+ r = _fetch_putln(conn, msg, len);
+ free(msg);
+
+ if (r == -1) {
+ _fetch_syserr();
+ return (-1);
+ }
+
+ return (_ftp_chkerr(conn));
+}
+
+/*
+ * Return a pointer to the filename part of a path
+ */
+static const char *
+_ftp_filename(const char *file, int *len, int *type)
+{
+ const char *s;
+
+ if ((s = strrchr(file, '/')) == NULL)
+ s = file;
+ else
+ s = s + 1;
+ *len = strlen(s);
+ if (*len > 7 && strncmp(s + *len - 7, ";type=", 6) == 0) {
+ *type = s[*len - 1];
+ *len -= 7;
+ } else {
+ *type = '\0';
+ }
+ return (s);
+}
+
+/*
+ * Get current working directory from the reply to a CWD, PWD or CDUP
+ * command.
+ */
+static int
+_ftp_pwd(conn_t *conn, char *pwd, size_t pwdlen)
+{
+ char *src, *dst, *end;
+ int q;
+
+ if (conn->err != FTP_WORKING_DIRECTORY &&
+ conn->err != FTP_FILE_ACTION_OK)
+ return (FTP_PROTOCOL_ERROR);
+ end = conn->buf + conn->buflen;
+ src = conn->buf + 4;
+ if (src >= end || *src++ != '"')
+ return (FTP_PROTOCOL_ERROR);
+ for (q = 0, dst = pwd; src < end && pwdlen--; ++src) {
+ if (!q && *src == '"')
+ q = 1;
+ else if (q && *src != '"')
+ break;
+ else if (q)
+ *dst++ = '"', q = 0;
+ else
+ *dst++ = *src;
+ }
+ if (!pwdlen)
+ return (FTP_PROTOCOL_ERROR);
+ *dst = '\0';
+#if 0
+ DEBUG(fprintf(stderr, "pwd: [%s]\n", pwd));
+#endif
+ return (FTP_OK);
+}
+
+/*
+ * Change working directory to the directory that contains the specified
+ * file.
+ */
+static int
+_ftp_cwd(conn_t *conn, const char *file)
+{
+ const char *beg, *end;
+ char pwd[PATH_MAX];
+ int e, i, len;
+
+ if ((end = strrchr(file, '/')) == NULL)
+ return (0);
+ if ((e = _ftp_cmd(conn, "PWD")) != FTP_WORKING_DIRECTORY ||
+ (e = _ftp_pwd(conn, pwd, sizeof(pwd))) != FTP_OK) {
+ _ftp_seterr(e);
+ return (-1);
+ }
+ for (;;) {
+ len = strlen(pwd);
+ /* look for a common prefix */
+ for (i = 0; i <= len && i <= end - file; ++i)
+ if (pwd[i] != file[i])
+ break;
+#if 0
+ DEBUG(fprintf(stderr, "have: [%.*s|%s]\n", i, pwd, pwd + i));
+ DEBUG(fprintf(stderr, "want: [%.*s|%s]\n", i, file, file + i));
+#endif
+ if (pwd[i] == '\0' && (file[i - 1] == '/' || file[i] == '/'))
+ break;
+ if ((e = _ftp_cmd(conn, "CDUP")) != FTP_FILE_ACTION_OK ||
+ (e = _ftp_cmd(conn, "PWD")) != FTP_WORKING_DIRECTORY ||
+ (e = _ftp_pwd(conn, pwd, sizeof(pwd))) != FTP_OK) {
+ _ftp_seterr(e);
+ return (-1);
+ }
+ }
+ for (beg = file + i; beg < end; beg = file + i + 1) {
+ for (++i; file + i < end && file[i] != '/'; ++i)
+ /* nothing */ ;
+ e = _ftp_cmd(conn, "CWD %.*s", file + i - beg, beg);
+ if (e != FTP_FILE_ACTION_OK) {
+ _ftp_seterr(e);
+ return (-1);
+ }
+ }
+ return (0);
+}
+
+/*
+ * Set transfer mode and data type
+ */
+static int
+_ftp_mode_type(conn_t *conn, int mode, int type)
+{
+ int e;
+
+ switch (mode) {
+ case 0:
+ case 's':
+ mode = 'S';
+ case 'S':
+ break;
+ default:
+ return (FTP_PROTOCOL_ERROR);
+ }
+ if ((e = _ftp_cmd(conn, "MODE %c", mode)) != FTP_OK) {
+ if (mode == 'S') {
+ /*
+ * Stream mode is supposed to be the default - so
+ * much so that some servers not only do not
+ * support any other mode, but do not support the
+ * MODE command at all.
+ *
+ * If "MODE S" fails, it is unlikely that we
+ * previously succeeded in setting a different
+ * mode. Therefore, we simply hope that the
+ * server is already in the correct mode, and
+ * silently ignore the failure.
+ */
+ } else {
+ return (e);
+ }
+ }
+
+ switch (type) {
+ case 0:
+ case 'i':
+ type = 'I';
+ case 'I':
+ break;
+ case 'a':
+ type = 'A';
+ case 'A':
+ break;
+ case 'd':
+ type = 'D';
+ case 'D':
+ /* can't handle yet */
+ default:
+ return (FTP_PROTOCOL_ERROR);
+ }
+ if ((e = _ftp_cmd(conn, "TYPE %c", type)) != FTP_OK)
+ return (e);
+
+ return (FTP_OK);
+}
+
+/*
+ * Request and parse file stats
+ */
+static int
+_ftp_stat(conn_t *conn, const char *file, struct url_stat *us)
+{
+ char *ln;
+ const char *filename;
+ int filenamelen, type;
+ struct tm tm;
+ time_t t;
+ int e;
+
+ us->size = -1;
+ us->atime = us->mtime = 0;
+
+ filename = _ftp_filename(file, &filenamelen, &type);
+
+ if ((e = _ftp_mode_type(conn, 0, type)) != FTP_OK) {
+ _ftp_seterr(e);
+ return (-1);
+ }
+
+ e = _ftp_cmd(conn, "SIZE %.*s", filenamelen, filename);
+ if (e != FTP_FILE_STATUS) {
+ _ftp_seterr(e);
+ return (-1);
+ }
+ for (ln = conn->buf + 4; *ln && isspace(*ln); ln++)
+ /* nothing */ ;
+ for (us->size = 0; *ln && isdigit(*ln); ln++)
+ us->size = us->size * 10 + *ln - '0';
+ if (*ln && !isspace(*ln)) {
+ _ftp_seterr(FTP_PROTOCOL_ERROR);
+ us->size = -1;
+ return (-1);
+ }
+ if (us->size == 0)
+ us->size = -1;
+ DEBUG(fprintf(stderr, "size: [%lld]\n", (long long)us->size));
+
+ e = _ftp_cmd(conn, "MDTM %.*s", filenamelen, filename);
+ if (e != FTP_FILE_STATUS) {
+ _ftp_seterr(e);
+ return (-1);
+ }
+ for (ln = conn->buf + 4; *ln && isspace(*ln); ln++)
+ /* nothing */ ;
+ switch (strspn(ln, "0123456789")) {
+ case 14:
+ break;
+ case 15:
+ ln++;
+ ln[0] = '2';
+ ln[1] = '0';
+ break;
+ default:
+ _ftp_seterr(FTP_PROTOCOL_ERROR);
+ return (-1);
+ }
+ if (sscanf(ln, "%04d%02d%02d%02d%02d%02d",
+ &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
+ &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
+ _ftp_seterr(FTP_PROTOCOL_ERROR);
+ return (-1);
+ }
+ tm.tm_mon--;
+ tm.tm_year -= 1900;
+ tm.tm_isdst = -1;
+ t = timegm(&tm);
+ if (t == (time_t)-1)
+ t = time(NULL);
+ us->mtime = t;
+ us->atime = t;
+ DEBUG(fprintf(stderr,
+ "last modified: [%04d-%02d-%02d %02d:%02d:%02d]\n",
+ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
+ tm.tm_hour, tm.tm_min, tm.tm_sec));
+ return (0);
+}
+
+/*
+ * I/O functions for FTP
+ */
+struct ftpio {
+ conn_t *cconn; /* Control connection */
+ conn_t *dconn; /* Data connection */
+ int dir; /* Direction */
+ int eof; /* EOF reached */
+ int err; /* Error code */
+};
+
+static int _ftp_readfn(void *, char *, int);
+static int _ftp_writefn(void *, const char *, int);
+static fpos_t _ftp_seekfn(void *, fpos_t, int);
+static int _ftp_closefn(void *);
+
+static int
+_ftp_readfn(void *v, char *buf, int len)
+{
+ struct ftpio *io;
+ int r;
+
+ io = (struct ftpio *)v;
+ if (io == NULL) {
+ errno = EBADF;
+ return (-1);
+ }
+ if (io->cconn == NULL || io->dconn == NULL || io->dir == O_WRONLY) {
+ errno = EBADF;
+ return (-1);
+ }
+ if (io->err) {
+ errno = io->err;
+ return (-1);
+ }
+ if (io->eof)
+ return (0);
+ r = _fetch_read(io->dconn, buf, len);
+ if (r > 0)
+ return (r);
+ if (r == 0) {
+ io->eof = 1;
+ return (0);
+ }
+ if (errno != EINTR)
+ io->err = errno;
+ return (-1);
+}
+
+static int
+_ftp_writefn(void *v, const char *buf, int len)
+{
+ struct ftpio *io;
+ int w;
+
+ io = (struct ftpio *)v;
+ if (io == NULL) {
+ errno = EBADF;
+ return (-1);
+ }
+ if (io->cconn == NULL || io->dconn == NULL || io->dir == O_RDONLY) {
+ errno = EBADF;
+ return (-1);
+ }
+ if (io->err) {
+ errno = io->err;
+ return (-1);
+ }
+ w = _fetch_write(io->dconn, buf, len);
+ if (w >= 0)
+ return (w);
+ if (errno != EINTR)
+ io->err = errno;
+ return (-1);
+}
+
+static fpos_t
+_ftp_seekfn(void *v, fpos_t pos __unused, int whence __unused)
+{
+ struct ftpio *io;
+
+ io = (struct ftpio *)v;
+ if (io == NULL) {
+ errno = EBADF;
+ return (-1);
+ }
+ errno = ESPIPE;
+ return (-1);
+}
+
+static int
+_ftp_closefn(void *v)
+{
+ struct ftpio *io;
+ int r;
+
+ io = (struct ftpio *)v;
+ if (io == NULL) {
+ errno = EBADF;
+ return (-1);
+ }
+ if (io->dir == -1)
+ return (0);
+ if (io->cconn == NULL || io->dconn == NULL) {
+ errno = EBADF;
+ return (-1);
+ }
+ _fetch_close(io->dconn);
+ io->dir = -1;
+ io->dconn = NULL;
+ DEBUG(fprintf(stderr, "Waiting for final status\n"));
+ r = _ftp_chkerr(io->cconn);
+ if (io->cconn == cached_connection && io->cconn->ref == 1)
+ cached_connection = NULL;
+ _fetch_close(io->cconn);
+ free(io);
+ return (r == FTP_TRANSFER_COMPLETE) ? 0 : -1;
+}
+
+static FILE *
+_ftp_setup(conn_t *cconn, conn_t *dconn, int mode)
+{
+ struct ftpio *io;
+ FILE *f;
+
+ if (cconn == NULL || dconn == NULL)
+ return (NULL);
+ if ((io = malloc(sizeof(*io))) == NULL)
+ return (NULL);
+ io->cconn = cconn;
+ io->dconn = dconn;
+ io->dir = mode;
+ io->eof = io->err = 0;
+ f = funopen(io, _ftp_readfn, _ftp_writefn, _ftp_seekfn, _ftp_closefn);
+ if (f == NULL)
+ free(io);
+ return (f);
+}
+
+/*
+ * Transfer file
+ */
+static FILE *
+_ftp_transfer(conn_t *conn, const char *oper, const char *file,
+ int mode, off_t offset, const char *flags)
+{
+ struct sockaddr_storage sa;
+ struct sockaddr_in6 *sin6;
+ struct sockaddr_in *sin4;
+ const char *filename;
+ int filenamelen, type;
+ int low, pasv, verbose;
+ int e, sd = -1;
+ socklen_t l;
+ char *s;
+ FILE *df;
+
+ /* check flags */
+ low = CHECK_FLAG('l');
+ pasv = CHECK_FLAG('p');
+ verbose = CHECK_FLAG('v');
+
+ /* passive mode */
+ if (!pasv)
+ pasv = ((s = getenv("FTP_PASSIVE_MODE")) != NULL &&
+ strncasecmp(s, "no", 2) != 0);
+
+ /* isolate filename */
+ filename = _ftp_filename(file, &filenamelen, &type);
+
+ /* set transfer mode and data type */
+ if ((e = _ftp_mode_type(conn, 0, type)) != FTP_OK)
+ goto ouch;
+
+ /* find our own address, bind, and listen */
+ l = sizeof(sa);
+ if (getsockname(conn->sd, (struct sockaddr *)&sa, &l) == -1)
+ goto sysouch;
+ if (sa.ss_family == AF_INET6)
+ unmappedaddr((struct sockaddr_in6 *)&sa);
+
+ /* open data socket */
+ if ((sd = socket(sa.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
+ _fetch_syserr();
+ return (NULL);
+ }
+
+ if (pasv) {
+ u_char addr[64];
+ char *ln, *p;
+ unsigned int i;
+ int port;
+
+ /* send PASV command */
+ if (verbose)
+ _fetch_info("setting passive mode");
+ switch (sa.ss_family) {
+ case AF_INET:
+ if ((e = _ftp_cmd(conn, "PASV")) != FTP_PASSIVE_MODE)
+ goto ouch;
+ break;
+ case AF_INET6:
+ if ((e = _ftp_cmd(conn, "EPSV")) != FTP_EPASSIVE_MODE) {
+ if (e == -1)
+ goto ouch;
+ if ((e = _ftp_cmd(conn, "LPSV")) !=
+ FTP_LPASSIVE_MODE)
+ goto ouch;
+ }
+ break;
+ default:
+ e = FTP_PROTOCOL_ERROR; /* XXX: error code should be prepared */
+ goto ouch;
+ }
+
+ /*
+ * Find address and port number. The reply to the PASV command
+ * is IMHO the one and only weak point in the FTP protocol.
+ */
+ ln = conn->buf;
+ switch (e) {
+ case FTP_PASSIVE_MODE:
+ case FTP_LPASSIVE_MODE:
+ for (p = ln + 3; *p && !isdigit(*p); p++)
+ /* nothing */ ;
+ if (!*p) {
+ e = FTP_PROTOCOL_ERROR;
+ goto ouch;
+ }
+ l = (e == FTP_PASSIVE_MODE ? 6 : 21);
+ for (i = 0; *p && i < l; i++, p++)
+ addr[i] = strtol(p, &p, 10);
+ if (i < l) {
+ e = FTP_PROTOCOL_ERROR;
+ goto ouch;
+ }
+ break;
+ case FTP_EPASSIVE_MODE:
+ for (p = ln + 3; *p && *p != '('; p++)
+ /* nothing */ ;
+ if (!*p) {
+ e = FTP_PROTOCOL_ERROR;
+ goto ouch;
+ }
+ ++p;
+ if (sscanf(p, "%c%c%c%d%c", &addr[0], &addr[1], &addr[2],
+ &port, &addr[3]) != 5 ||
+ addr[0] != addr[1] ||
+ addr[0] != addr[2] || addr[0] != addr[3]) {
+ e = FTP_PROTOCOL_ERROR;
+ goto ouch;
+ }
+ break;
+ }
+
+ /* seek to required offset */
+ if (offset)
+ if (_ftp_cmd(conn, "REST %lu", (u_long)offset) != FTP_FILE_OK)
+ goto sysouch;
+
+ /* construct sockaddr for data socket */
+ l = sizeof(sa);
+ if (getpeername(conn->sd, (struct sockaddr *)&sa, &l) == -1)
+ goto sysouch;
+ if (sa.ss_family == AF_INET6)
+ unmappedaddr((struct sockaddr_in6 *)&sa);
+ switch (sa.ss_family) {
+ case AF_INET6:
+ sin6 = (struct sockaddr_in6 *)&sa;
+ if (e == FTP_EPASSIVE_MODE)
+ sin6->sin6_port = htons(port);
+ else {
+ bcopy(addr + 2, (char *)&sin6->sin6_addr, 16);
+ bcopy(addr + 19, (char *)&sin6->sin6_port, 2);
+ }
+ break;
+ case AF_INET:
+ sin4 = (struct sockaddr_in *)&sa;
+ if (e == FTP_EPASSIVE_MODE)
+ sin4->sin_port = htons(port);
+ else {
+ bcopy(addr, (char *)&sin4->sin_addr, 4);
+ bcopy(addr + 4, (char *)&sin4->sin_port, 2);
+ }
+ break;
+ default:
+ e = FTP_PROTOCOL_ERROR; /* XXX: error code should be prepared */
+ break;
+ }
+
+ /* connect to data port */
+ if (verbose)
+ _fetch_info("opening data connection");
+ if (connect(sd, (struct sockaddr *)&sa, sa.ss_len) == -1)
+ goto sysouch;
+
+ /* make the server initiate the transfer */
+ if (verbose)
+ _fetch_info("initiating transfer");
+ e = _ftp_cmd(conn, "%s %.*s", oper, filenamelen, filename);
+ if (e != FTP_CONNECTION_ALREADY_OPEN && e != FTP_OPEN_DATA_CONNECTION)
+ goto ouch;
+
+ } else {
+ u_int32_t a;
+ u_short p;
+ int arg, d;
+ char *ap;
+ char hname[INET6_ADDRSTRLEN];
+
+ switch (sa.ss_family) {
+ case AF_INET6:
+ ((struct sockaddr_in6 *)&sa)->sin6_port = 0;
+#ifdef IPV6_PORTRANGE
+ arg = low ? IPV6_PORTRANGE_DEFAULT : IPV6_PORTRANGE_HIGH;
+ if (setsockopt(sd, IPPROTO_IPV6, IPV6_PORTRANGE,
+ (char *)&arg, sizeof(arg)) == -1)
+ goto sysouch;
+#endif
+ break;
+ case AF_INET:
+ ((struct sockaddr_in *)&sa)->sin_port = 0;
+ arg = low ? IP_PORTRANGE_DEFAULT : IP_PORTRANGE_HIGH;
+ if (setsockopt(sd, IPPROTO_IP, IP_PORTRANGE,
+ (char *)&arg, sizeof(arg)) == -1)
+ goto sysouch;
+ break;
+ }
+ if (verbose)
+ _fetch_info("binding data socket");
+ if (bind(sd, (struct sockaddr *)&sa, sa.ss_len) == -1)
+ goto sysouch;
+ if (listen(sd, 1) == -1)
+ goto sysouch;
+
+ /* find what port we're on and tell the server */
+ if (getsockname(sd, (struct sockaddr *)&sa, &l) == -1)
+ goto sysouch;
+ switch (sa.ss_family) {
+ case AF_INET:
+ sin4 = (struct sockaddr_in *)&sa;
+ a = ntohl(sin4->sin_addr.s_addr);
+ p = ntohs(sin4->sin_port);
+ e = _ftp_cmd(conn, "PORT %d,%d,%d,%d,%d,%d",
+ (a >> 24) & 0xff, (a >> 16) & 0xff,
+ (a >> 8) & 0xff, a & 0xff,
+ (p >> 8) & 0xff, p & 0xff);
+ break;
+ case AF_INET6:
+#define UC(b) (((int)b)&0xff)
+ e = -1;
+ sin6 = (struct sockaddr_in6 *)&sa;
+ sin6->sin6_scope_id = 0;
+ if (getnameinfo((struct sockaddr *)&sa, sa.ss_len,
+ hname, sizeof(hname),
+ NULL, 0, NI_NUMERICHOST) == 0) {
+ e = _ftp_cmd(conn, "EPRT |%d|%s|%d|", 2, hname,
+ htons(sin6->sin6_port));
+ if (e == -1)
+ goto ouch;
+ }
+ if (e != FTP_OK) {
+ ap = (char *)&sin6->sin6_addr;
+ e = _ftp_cmd(conn,
+ "LPRT %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
+ 6, 16,
+ UC(ap[0]), UC(ap[1]), UC(ap[2]), UC(ap[3]),
+ UC(ap[4]), UC(ap[5]), UC(ap[6]), UC(ap[7]),
+ UC(ap[8]), UC(ap[9]), UC(ap[10]), UC(ap[11]),
+ UC(ap[12]), UC(ap[13]), UC(ap[14]), UC(ap[15]),
+ 2,
+ (ntohs(sin6->sin6_port) >> 8) & 0xff,
+ ntohs(sin6->sin6_port) & 0xff);
+ }
+ break;
+ default:
+ e = FTP_PROTOCOL_ERROR; /* XXX: error code should be prepared */
+ goto ouch;
+ }
+ if (e != FTP_OK)
+ goto ouch;
+
+ /* seek to required offset */
+ if (offset)
+ if (_ftp_cmd(conn, "REST %ju", (uintmax_t)offset) != FTP_FILE_OK)
+ goto sysouch;
+
+ /* make the server initiate the transfer */
+ if (verbose)
+ _fetch_info("initiating transfer");
+ e = _ftp_cmd(conn, "%s %.*s", oper, filenamelen, filename);
+ if (e != FTP_CONNECTION_ALREADY_OPEN && e != FTP_OPEN_DATA_CONNECTION)
+ goto ouch;
+
+ /* accept the incoming connection and go to town */
+ if ((d = accept(sd, NULL, NULL)) == -1)
+ goto sysouch;
+ close(sd);
+ sd = d;
+ }
+
+ if ((df = _ftp_setup(conn, _fetch_reopen(sd), mode)) == NULL)
+ goto sysouch;
+ return (df);
+
+sysouch:
+ _fetch_syserr();
+ if (sd >= 0)
+ close(sd);
+ return (NULL);
+
+ouch:
+ if (e != -1)
+ _ftp_seterr(e);
+ if (sd >= 0)
+ close(sd);
+ return (NULL);
+}
+
+/*
+ * Authenticate
+ */
+static int
+_ftp_authenticate(conn_t *conn, struct url *url, struct url *purl)
+{
+ const char *user, *pwd, *logname;
+ char pbuf[MAXHOSTNAMELEN + MAXLOGNAME + 1];
+ int e, len;
+
+ /* XXX FTP_AUTH, and maybe .netrc */
+
+ /* send user name and password */
+ if (url->user[0] == '\0')
+ _fetch_netrc_auth(url);
+ user = url->user;
+ if (*user == '\0')
+ user = getenv("FTP_LOGIN");
+ if (user == NULL || *user == '\0')
+ user = FTP_ANONYMOUS_USER;
+ if (purl && url->port == _fetch_default_port(url->scheme))
+ e = _ftp_cmd(conn, "USER %s@%s", user, url->host);
+ else if (purl)
+ e = _ftp_cmd(conn, "USER %s@%s@%d", user, url->host, url->port);
+ else
+ e = _ftp_cmd(conn, "USER %s", user);
+
+ /* did the server request a password? */
+ if (e == FTP_NEED_PASSWORD) {
+ pwd = url->pwd;
+ if (*pwd == '\0')
+ pwd = getenv("FTP_PASSWORD");
+ if (pwd == NULL || *pwd == '\0') {
+ if ((logname = getlogin()) == 0)
+ logname = FTP_ANONYMOUS_USER;
+ if ((len = snprintf(pbuf, MAXLOGNAME + 1, "%s@", logname)) < 0)
+ len = 0;
+ else if (len > MAXLOGNAME)
+ len = MAXLOGNAME;
+ gethostname(pbuf + len, sizeof(pbuf) - len);
+ pwd = pbuf;
+ }
+ e = _ftp_cmd(conn, "PASS %s", pwd);
+ }
+
+ return (e);
+}
+
+/*
+ * Log on to FTP server
+ */
+static conn_t *
+_ftp_connect(struct url *url, struct url *purl, const char *flags)
+{
+ conn_t *conn;
+ int e, direct, verbose;
+#ifdef INET6
+ int af = AF_UNSPEC;
+#else
+ int af = AF_INET;
+#endif
+
+ direct = CHECK_FLAG('d');
+ verbose = CHECK_FLAG('v');
+ if (CHECK_FLAG('4'))
+ af = AF_INET;
+ else if (CHECK_FLAG('6'))
+ af = AF_INET6;
+
+ if (direct)
+ purl = NULL;
+
+ /* check for proxy */
+ if (purl) {
+ /* XXX proxy authentication! */
+ conn = _fetch_connect(purl->host, purl->port, af, verbose);
+ } else {
+ /* no proxy, go straight to target */
+ conn = _fetch_connect(url->host, url->port, af, verbose);
+ purl = NULL;
+ }
+
+ /* check connection */
+ if (conn == NULL)
+ /* _fetch_connect() has already set an error code */
+ return (NULL);
+
+ /* expect welcome message */
+ if ((e = _ftp_chkerr(conn)) != FTP_SERVICE_READY)
+ goto fouch;
+
+ /* authenticate */
+ if ((e = _ftp_authenticate(conn, url, purl)) != FTP_LOGGED_IN)
+ goto fouch;
+
+ /* done */
+ return (conn);
+
+fouch:
+ if (e != -1)
+ _ftp_seterr(e);
+ _fetch_close(conn);
+ return (NULL);
+}
+
+/*
+ * Disconnect from server
+ */
+static void
+_ftp_disconnect(conn_t *conn)
+{
+ (void)_ftp_cmd(conn, "QUIT");
+ if (conn == cached_connection && conn->ref == 1)
+ cached_connection = NULL;
+ _fetch_close(conn);
+}
+
+/*
+ * Check if we're already connected
+ */
+static int
+_ftp_isconnected(struct url *url)
+{
+ return (cached_connection
+ && (strcmp(url->host, cached_host.host) == 0)
+ && (strcmp(url->user, cached_host.user) == 0)
+ && (strcmp(url->pwd, cached_host.pwd) == 0)
+ && (url->port == cached_host.port));
+}
+
+/*
+ * Check the cache, reconnect if no luck
+ */
+static conn_t *
+_ftp_cached_connect(struct url *url, struct url *purl, const char *flags)
+{
+ conn_t *conn;
+ int e;
+
+ /* set default port */
+ if (!url->port)
+ url->port = _fetch_default_port(url->scheme);
+
+ /* try to use previously cached connection */
+ if (_ftp_isconnected(url)) {
+ e = _ftp_cmd(cached_connection, "NOOP");
+ if (e == FTP_OK || e == FTP_SYNTAX_ERROR)
+ return (_fetch_ref(cached_connection));
+ }
+
+ /* connect to server */
+ if ((conn = _ftp_connect(url, purl, flags)) == NULL)
+ return (NULL);
+ if (cached_connection)
+ _ftp_disconnect(cached_connection);
+ cached_connection = _fetch_ref(conn);
+ memcpy(&cached_host, url, sizeof(*url));
+ return (conn);
+}
+
+/*
+ * Check the proxy settings
+ */
+static struct url *
+_ftp_get_proxy(const char *flags)
+{
+ struct url *purl;
+ char *p;
+
+ if (flags != NULL && strchr(flags, 'd') != NULL)
+ return (NULL);
+ if (((p = getenv("FTP_PROXY")) || (p = getenv("ftp_proxy")) ||
+ (p = getenv("HTTP_PROXY")) || (p = getenv("http_proxy"))) &&
+ *p && (purl = fetchParseURL(p)) != NULL) {
+ if (!*purl->scheme) {
+ if (getenv("FTP_PROXY") || getenv("ftp_proxy"))
+ strcpy(purl->scheme, SCHEME_FTP);
+ else
+ strcpy(purl->scheme, SCHEME_HTTP);
+ }
+ if (!purl->port)
+ purl->port = _fetch_default_proxy_port(purl->scheme);
+ if (strcasecmp(purl->scheme, SCHEME_FTP) == 0 ||
+ strcasecmp(purl->scheme, SCHEME_HTTP) == 0)
+ return (purl);
+ fetchFreeURL(purl);
+ }
+ return (NULL);
+}
+
+/*
+ * Process an FTP request
+ */
+FILE *
+_ftp_request(struct url *url, const char *op, struct url_stat *us,
+ struct url *purl, const char *flags)
+{
+ conn_t *conn;
+ int oflag;
+
+ /* check if we should use HTTP instead */
+ if (purl && strcasecmp(purl->scheme, SCHEME_HTTP) == 0) {
+ if (strcmp(op, "STAT") == 0)
+ return (_http_request(url, "HEAD", us, purl, flags));
+ else if (strcmp(op, "RETR") == 0)
+ return (_http_request(url, "GET", us, purl, flags));
+ /*
+ * Our HTTP code doesn't support PUT requests yet, so try
+ * a direct connection.
+ */
+ }
+
+ /* connect to server */
+ conn = _ftp_cached_connect(url, purl, flags);
+ if (purl)
+ fetchFreeURL(purl);
+ if (conn == NULL)
+ return (NULL);
+
+ /* change directory */
+ if (_ftp_cwd(conn, url->doc) == -1)
+ return (NULL);
+
+ /* stat file */
+ if (us && _ftp_stat(conn, url->doc, us) == -1
+ && fetchLastErrCode != FETCH_PROTO
+ && fetchLastErrCode != FETCH_UNAVAIL)
+ return (NULL);
+
+ /* just a stat */
+ if (strcmp(op, "STAT") == 0)
+ return (FILE *)1; /* bogus return value */
+ if (strcmp(op, "STOR") == 0 || strcmp(op, "APPE") == 0)
+ oflag = O_WRONLY;
+ else
+ oflag = O_RDONLY;
+
+ /* initiate the transfer */
+ return (_ftp_transfer(conn, op, url->doc, oflag, url->offset, flags));
+}
+
+/*
+ * Get and stat file
+ */
+FILE *
+fetchXGetFTP(struct url *url, struct url_stat *us, const char *flags)
+{
+ return (_ftp_request(url, "RETR", us, _ftp_get_proxy(flags), flags));
+}
+
+/*
+ * Get file
+ */
+FILE *
+fetchGetFTP(struct url *url, const char *flags)
+{
+ return (fetchXGetFTP(url, NULL, flags));
+}
+
+/*
+ * Put file
+ */
+FILE *
+fetchPutFTP(struct url *url, const char *flags)
+{
+
+ return (_ftp_request(url, CHECK_FLAG('a') ? "APPE" : "STOR", NULL,
+ _ftp_get_proxy(flags), flags));
+}
+
+/*
+ * Get file stats
+ */
+int
+fetchStatFTP(struct url *url, struct url_stat *us, const char *flags)
+{
+ FILE *f;
+
+ f = _ftp_request(url, "STAT", us, _ftp_get_proxy(flags), flags);
+ if (f == NULL)
+ return (-1);
+ return (0);
+}
+
+/*
+ * List a directory
+ */
+struct url_ent *
+fetchListFTP(struct url *url __unused, const char *flags __unused)
+{
+ warnx("fetchListFTP(): not implemented");
+ return (NULL);
+}
diff --git a/lib/libfetch/ftp.errors b/lib/libfetch/ftp.errors
new file mode 100644
index 0000000..9a4a11e
--- /dev/null
+++ b/lib/libfetch/ftp.errors
@@ -0,0 +1,47 @@
+# $FreeBSD$
+#
+# This list is taken from RFC 959.
+# It probably needs a going over.
+#
+110 OK Restart marker reply
+120 TEMP Service ready in a few minutes
+125 OK Data connection already open; transfer starting
+150 OK File status okay; about to open data connection
+200 OK Command okay
+202 PROTO Command not implemented, superfluous at this site
+211 INFO System status, or system help reply
+212 INFO Directory status
+213 INFO File status
+214 INFO Help message
+215 INFO Set system type
+220 OK Service ready for new user
+221 OK Service closing control connection
+225 OK Data connection open; no transfer in progress
+226 OK Requested file action successful
+227 OK Entering Passive Mode
+229 OK Entering Extended Passive Mode
+230 OK User logged in, proceed
+250 OK Requested file action okay, completed
+257 OK File/directory created
+331 AUTH User name okay, need password
+332 AUTH Need account for login
+350 OK Requested file action pending further information
+421 DOWN Service not available, closing control connection
+425 NETWORK Can't open data connection
+426 ABORT Connection closed; transfer aborted
+450 UNAVAIL File unavailable (e.g., file busy)
+451 SERVER Requested action aborted: local error in processing
+452 FULL Insufficient storage space in system
+500 PROTO Syntax error, command unrecognized
+501 PROTO Syntax error in parameters or arguments
+502 PROTO Command not implemented
+503 PROTO Bad sequence of commands
+504 PROTO Command not implemented for that parameter
+530 AUTH Not logged in
+532 AUTH Need account for storing files
+535 PROTO Bug in MediaHawk Video Kernel FTP server
+550 UNAVAIL File unavailable (e.g., file not found, no access)
+551 PROTO Requested action aborted. Page type unknown
+552 FULL Exceeded storage allocation
+553 EXISTS File name not allowed
+999 PROTO Protocol error
diff --git a/lib/libfetch/http.c b/lib/libfetch/http.c
new file mode 100644
index 0000000..1af13ab
--- /dev/null
+++ b/lib/libfetch/http.c
@@ -0,0 +1,1213 @@
+/*-
+ * Copyright (c) 2000-2004 Dag-Erling Coïdan Smørgrav
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 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$");
+
+/*
+ * The following copyright applies to the base64 code:
+ *
+ *-
+ * Copyright 1997 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/param.h>
+#include <sys/socket.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <locale.h>
+#include <netdb.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+#include "fetch.h"
+#include "common.h"
+#include "httperr.h"
+
+/* Maximum number of redirects to follow */
+#define MAX_REDIRECT 5
+
+/* Symbolic names for reply codes we care about */
+#define HTTP_OK 200
+#define HTTP_PARTIAL 206
+#define HTTP_MOVED_PERM 301
+#define HTTP_MOVED_TEMP 302
+#define HTTP_SEE_OTHER 303
+#define HTTP_NEED_AUTH 401
+#define HTTP_NEED_PROXY_AUTH 407
+#define HTTP_BAD_RANGE 416
+#define HTTP_PROTOCOL_ERROR 999
+
+#define HTTP_REDIRECT(xyz) ((xyz) == HTTP_MOVED_PERM \
+ || (xyz) == HTTP_MOVED_TEMP \
+ || (xyz) == HTTP_SEE_OTHER)
+
+#define HTTP_ERROR(xyz) ((xyz) > 400 && (xyz) < 599)
+
+
+/*****************************************************************************
+ * I/O functions for decoding chunked streams
+ */
+
+struct httpio
+{
+ conn_t *conn; /* connection */
+ int chunked; /* chunked mode */
+ char *buf; /* chunk buffer */
+ size_t bufsize; /* size of chunk buffer */
+ ssize_t buflen; /* amount of data currently in buffer */
+ int bufpos; /* current read offset in buffer */
+ int eof; /* end-of-file flag */
+ int error; /* error flag */
+ size_t chunksize; /* remaining size of current chunk */
+#ifndef NDEBUG
+ size_t total;
+#endif
+};
+
+/*
+ * Get next chunk header
+ */
+static int
+_http_new_chunk(struct httpio *io)
+{
+ char *p;
+
+ if (_fetch_getln(io->conn) == -1)
+ return (-1);
+
+ if (io->conn->buflen < 2 || !ishexnumber(*io->conn->buf))
+ return (-1);
+
+ for (p = io->conn->buf; *p && !isspace(*p); ++p) {
+ if (*p == ';')
+ break;
+ if (!ishexnumber(*p))
+ return (-1);
+ if (isdigit(*p)) {
+ io->chunksize = io->chunksize * 16 +
+ *p - '0';
+ } else {
+ io->chunksize = io->chunksize * 16 +
+ 10 + tolower(*p) - 'a';
+ }
+ }
+
+#ifndef NDEBUG
+ if (fetchDebug) {
+ io->total += io->chunksize;
+ if (io->chunksize == 0)
+ fprintf(stderr, "%s(): end of last chunk\n", __func__);
+ else
+ fprintf(stderr, "%s(): new chunk: %lu (%lu)\n",
+ __func__, (unsigned long)io->chunksize,
+ (unsigned long)io->total);
+ }
+#endif
+
+ return (io->chunksize);
+}
+
+/*
+ * Grow the input buffer to at least len bytes
+ */
+static inline int
+_http_growbuf(struct httpio *io, size_t len)
+{
+ char *tmp;
+
+ if (io->bufsize >= len)
+ return (0);
+
+ if ((tmp = realloc(io->buf, len)) == NULL)
+ return (-1);
+ io->buf = tmp;
+ io->bufsize = len;
+ return (0);
+}
+
+/*
+ * Fill the input buffer, do chunk decoding on the fly
+ */
+static int
+_http_fillbuf(struct httpio *io, size_t len)
+{
+ if (io->error)
+ return (-1);
+ if (io->eof)
+ return (0);
+
+ if (io->chunked == 0) {
+ if (_http_growbuf(io, len) == -1)
+ return (-1);
+ if ((io->buflen = _fetch_read(io->conn, io->buf, len)) == -1) {
+ io->error = 1;
+ return (-1);
+ }
+ io->bufpos = 0;
+ return (io->buflen);
+ }
+
+ if (io->chunksize == 0) {
+ switch (_http_new_chunk(io)) {
+ case -1:
+ io->error = 1;
+ return (-1);
+ case 0:
+ io->eof = 1;
+ return (0);
+ }
+ }
+
+ if (len > io->chunksize)
+ len = io->chunksize;
+ if (_http_growbuf(io, len) == -1)
+ return (-1);
+ if ((io->buflen = _fetch_read(io->conn, io->buf, len)) == -1) {
+ io->error = 1;
+ return (-1);
+ }
+ io->chunksize -= io->buflen;
+
+ if (io->chunksize == 0) {
+ char endl[2];
+
+ if (_fetch_read(io->conn, endl, 2) != 2 ||
+ endl[0] != '\r' || endl[1] != '\n')
+ return (-1);
+ }
+
+ io->bufpos = 0;
+
+ return (io->buflen);
+}
+
+/*
+ * Read function
+ */
+static int
+_http_readfn(void *v, char *buf, int len)
+{
+ struct httpio *io = (struct httpio *)v;
+ int l, pos;
+
+ if (io->error)
+ return (-1);
+ if (io->eof)
+ return (0);
+
+ for (pos = 0; len > 0; pos += l, len -= l) {
+ /* empty buffer */
+ if (!io->buf || io->bufpos == io->buflen)
+ if (_http_fillbuf(io, len) < 1)
+ break;
+ l = io->buflen - io->bufpos;
+ if (len < l)
+ l = len;
+ bcopy(io->buf + io->bufpos, buf + pos, l);
+ io->bufpos += l;
+ }
+
+ if (!pos && io->error)
+ return (-1);
+ return (pos);
+}
+
+/*
+ * Write function
+ */
+static int
+_http_writefn(void *v, const char *buf, int len)
+{
+ struct httpio *io = (struct httpio *)v;
+
+ return (_fetch_write(io->conn, buf, len));
+}
+
+/*
+ * Close function
+ */
+static int
+_http_closefn(void *v)
+{
+ struct httpio *io = (struct httpio *)v;
+ int r;
+
+ r = _fetch_close(io->conn);
+ if (io->buf)
+ free(io->buf);
+ free(io);
+ return (r);
+}
+
+/*
+ * Wrap a file descriptor up
+ */
+static FILE *
+_http_funopen(conn_t *conn, int chunked)
+{
+ struct httpio *io;
+ FILE *f;
+
+ if ((io = calloc(1, sizeof(*io))) == NULL) {
+ _fetch_syserr();
+ return (NULL);
+ }
+ io->conn = conn;
+ io->chunked = chunked;
+ f = funopen(io, _http_readfn, _http_writefn, NULL, _http_closefn);
+ if (f == NULL) {
+ _fetch_syserr();
+ free(io);
+ return (NULL);
+ }
+ return (f);
+}
+
+
+/*****************************************************************************
+ * Helper functions for talking to the server and parsing its replies
+ */
+
+/* Header types */
+typedef enum {
+ hdr_syserror = -2,
+ hdr_error = -1,
+ hdr_end = 0,
+ hdr_unknown = 1,
+ hdr_content_length,
+ hdr_content_range,
+ hdr_last_modified,
+ hdr_location,
+ hdr_transfer_encoding,
+ hdr_www_authenticate
+} hdr_t;
+
+/* Names of interesting headers */
+static struct {
+ hdr_t num;
+ const char *name;
+} hdr_names[] = {
+ { hdr_content_length, "Content-Length" },
+ { hdr_content_range, "Content-Range" },
+ { hdr_last_modified, "Last-Modified" },
+ { hdr_location, "Location" },
+ { hdr_transfer_encoding, "Transfer-Encoding" },
+ { hdr_www_authenticate, "WWW-Authenticate" },
+ { hdr_unknown, NULL },
+};
+
+/*
+ * Send a formatted line; optionally echo to terminal
+ */
+static int
+_http_cmd(conn_t *conn, const char *fmt, ...)
+{
+ va_list ap;
+ size_t len;
+ char *msg;
+ int r;
+
+ va_start(ap, fmt);
+ len = vasprintf(&msg, fmt, ap);
+ va_end(ap);
+
+ if (msg == NULL) {
+ errno = ENOMEM;
+ _fetch_syserr();
+ return (-1);
+ }
+
+ r = _fetch_putln(conn, msg, len);
+ free(msg);
+
+ if (r == -1) {
+ _fetch_syserr();
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * Get and parse status line
+ */
+static int
+_http_get_reply(conn_t *conn)
+{
+ char *p;
+
+ if (_fetch_getln(conn) == -1)
+ return (-1);
+ /*
+ * A valid status line looks like "HTTP/m.n xyz reason" where m
+ * and n are the major and minor protocol version numbers and xyz
+ * is the reply code.
+ * Unfortunately, there are servers out there (NCSA 1.5.1, to name
+ * just one) that do not send a version number, so we can't rely
+ * on finding one, but if we do, insist on it being 1.0 or 1.1.
+ * We don't care about the reason phrase.
+ */
+ if (strncmp(conn->buf, "HTTP", 4) != 0)
+ return (HTTP_PROTOCOL_ERROR);
+ p = conn->buf + 4;
+ if (*p == '/') {
+ if (p[1] != '1' || p[2] != '.' || (p[3] != '0' && p[3] != '1'))
+ return (HTTP_PROTOCOL_ERROR);
+ p += 4;
+ }
+ if (*p != ' ' || !isdigit(p[1]) || !isdigit(p[2]) || !isdigit(p[3]))
+ return (HTTP_PROTOCOL_ERROR);
+
+ conn->err = (p[1] - '0') * 100 + (p[2] - '0') * 10 + (p[3] - '0');
+ return (conn->err);
+}
+
+/*
+ * Check a header; if the type matches the given string, return a pointer
+ * to the beginning of the value.
+ */
+static const char *
+_http_match(const char *str, const char *hdr)
+{
+ while (*str && *hdr && tolower(*str++) == tolower(*hdr++))
+ /* nothing */;
+ if (*str || *hdr != ':')
+ return (NULL);
+ while (*hdr && isspace(*++hdr))
+ /* nothing */;
+ return (hdr);
+}
+
+/*
+ * Get the next header and return the appropriate symbolic code.
+ */
+static hdr_t
+_http_next_header(conn_t *conn, const char **p)
+{
+ int i;
+
+ if (_fetch_getln(conn) == -1)
+ return (hdr_syserror);
+ while (conn->buflen && isspace(conn->buf[conn->buflen - 1]))
+ conn->buflen--;
+ conn->buf[conn->buflen] = '\0';
+ if (conn->buflen == 0)
+ return (hdr_end);
+ /*
+ * We could check for malformed headers but we don't really care.
+ * A valid header starts with a token immediately followed by a
+ * colon; a token is any sequence of non-control, non-whitespace
+ * characters except "()<>@,;:\\\"{}".
+ */
+ for (i = 0; hdr_names[i].num != hdr_unknown; i++)
+ if ((*p = _http_match(hdr_names[i].name, conn->buf)) != NULL)
+ return (hdr_names[i].num);
+ return (hdr_unknown);
+}
+
+/*
+ * Parse a last-modified header
+ */
+static int
+_http_parse_mtime(const char *p, time_t *mtime)
+{
+ char locale[64], *r;
+ struct tm tm;
+
+ strncpy(locale, setlocale(LC_TIME, NULL), sizeof(locale));
+ setlocale(LC_TIME, "C");
+ r = strptime(p, "%a, %d %b %Y %H:%M:%S GMT", &tm);
+ /* XXX should add support for date-2 and date-3 */
+ setlocale(LC_TIME, locale);
+ if (r == NULL)
+ return (-1);
+ DEBUG(fprintf(stderr, "last modified: [%04d-%02d-%02d "
+ "%02d:%02d:%02d]\n",
+ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
+ tm.tm_hour, tm.tm_min, tm.tm_sec));
+ *mtime = timegm(&tm);
+ return (0);
+}
+
+/*
+ * Parse a content-length header
+ */
+static int
+_http_parse_length(const char *p, off_t *length)
+{
+ off_t len;
+
+ for (len = 0; *p && isdigit(*p); ++p)
+ len = len * 10 + (*p - '0');
+ if (*p)
+ return (-1);
+ DEBUG(fprintf(stderr, "content length: [%lld]\n",
+ (long long)len));
+ *length = len;
+ return (0);
+}
+
+/*
+ * Parse a content-range header
+ */
+static int
+_http_parse_range(const char *p, off_t *offset, off_t *length, off_t *size)
+{
+ off_t first, last, len;
+
+ if (strncasecmp(p, "bytes ", 6) != 0)
+ return (-1);
+ p += 6;
+ if (*p == '*') {
+ first = last = -1;
+ ++p;
+ } else {
+ for (first = 0; *p && isdigit(*p); ++p)
+ first = first * 10 + *p - '0';
+ if (*p != '-')
+ return (-1);
+ for (last = 0, ++p; *p && isdigit(*p); ++p)
+ last = last * 10 + *p - '0';
+ }
+ if (first > last || *p != '/')
+ return (-1);
+ for (len = 0, ++p; *p && isdigit(*p); ++p)
+ len = len * 10 + *p - '0';
+ if (*p || len < last - first + 1)
+ return (-1);
+ if (first == -1) {
+ DEBUG(fprintf(stderr, "content range: [*/%lld]\n",
+ (long long)len));
+ *length = 0;
+ } else {
+ DEBUG(fprintf(stderr, "content range: [%lld-%lld/%lld]\n",
+ (long long)first, (long long)last, (long long)len));
+ *length = last - first + 1;
+ }
+ *offset = first;
+ *size = len;
+ return (0);
+}
+
+
+/*****************************************************************************
+ * Helper functions for authorization
+ */
+
+/*
+ * Base64 encoding
+ */
+static char *
+_http_base64(const char *src)
+{
+ static const char base64[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789+/";
+ char *str, *dst;
+ size_t l;
+ int t, r;
+
+ l = strlen(src);
+ if ((str = malloc(((l + 2) / 3) * 4 + 1)) == NULL)
+ return (NULL);
+ dst = str;
+ r = 0;
+
+ while (l >= 3) {
+ t = (src[0] << 16) | (src[1] << 8) | src[2];
+ dst[0] = base64[(t >> 18) & 0x3f];
+ dst[1] = base64[(t >> 12) & 0x3f];
+ dst[2] = base64[(t >> 6) & 0x3f];
+ dst[3] = base64[(t >> 0) & 0x3f];
+ src += 3; l -= 3;
+ dst += 4; r += 4;
+ }
+
+ switch (l) {
+ case 2:
+ t = (src[0] << 16) | (src[1] << 8);
+ dst[0] = base64[(t >> 18) & 0x3f];
+ dst[1] = base64[(t >> 12) & 0x3f];
+ dst[2] = base64[(t >> 6) & 0x3f];
+ dst[3] = '=';
+ dst += 4;
+ r += 4;
+ break;
+ case 1:
+ t = src[0] << 16;
+ dst[0] = base64[(t >> 18) & 0x3f];
+ dst[1] = base64[(t >> 12) & 0x3f];
+ dst[2] = dst[3] = '=';
+ dst += 4;
+ r += 4;
+ break;
+ case 0:
+ break;
+ }
+
+ *dst = 0;
+ return (str);
+}
+
+/*
+ * Encode username and password
+ */
+static int
+_http_basic_auth(conn_t *conn, const char *hdr, const char *usr, const char *pwd)
+{
+ char *upw, *auth;
+ int r;
+
+ DEBUG(fprintf(stderr, "usr: [%s]\n", usr));
+ DEBUG(fprintf(stderr, "pwd: [%s]\n", pwd));
+ if (asprintf(&upw, "%s:%s", usr, pwd) == -1)
+ return (-1);
+ auth = _http_base64(upw);
+ free(upw);
+ if (auth == NULL)
+ return (-1);
+ r = _http_cmd(conn, "%s: Basic %s", hdr, auth);
+ free(auth);
+ return (r);
+}
+
+/*
+ * Send an authorization header
+ */
+static int
+_http_authorize(conn_t *conn, const char *hdr, const char *p)
+{
+ /* basic authorization */
+ if (strncasecmp(p, "basic:", 6) == 0) {
+ char *user, *pwd, *str;
+ int r;
+
+ /* skip realm */
+ for (p += 6; *p && *p != ':'; ++p)
+ /* nothing */ ;
+ if (!*p || strchr(++p, ':') == NULL)
+ return (-1);
+ if ((str = strdup(p)) == NULL)
+ return (-1); /* XXX */
+ user = str;
+ pwd = strchr(str, ':');
+ *pwd++ = '\0';
+ r = _http_basic_auth(conn, hdr, user, pwd);
+ free(str);
+ return (r);
+ }
+ return (-1);
+}
+
+
+/*****************************************************************************
+ * Helper functions for connecting to a server or proxy
+ */
+
+/*
+ * Connect to the correct HTTP server or proxy.
+ */
+static conn_t *
+_http_connect(struct url *URL, struct url *purl, const char *flags)
+{
+ conn_t *conn;
+ int verbose;
+ int af, val;
+
+#ifdef INET6
+ af = AF_UNSPEC;
+#else
+ af = AF_INET;
+#endif
+
+ verbose = CHECK_FLAG('v');
+ if (CHECK_FLAG('4'))
+ af = AF_INET;
+#ifdef INET6
+ else if (CHECK_FLAG('6'))
+ af = AF_INET6;
+#endif
+
+ if (purl && strcasecmp(URL->scheme, SCHEME_HTTPS) != 0) {
+ URL = purl;
+ } else if (strcasecmp(URL->scheme, SCHEME_FTP) == 0) {
+ /* can't talk http to an ftp server */
+ /* XXX should set an error code */
+ return (NULL);
+ }
+
+ if ((conn = _fetch_connect(URL->host, URL->port, af, verbose)) == NULL)
+ /* _fetch_connect() has already set an error code */
+ return (NULL);
+ if (strcasecmp(URL->scheme, SCHEME_HTTPS) == 0 &&
+ _fetch_ssl(conn, verbose) == -1) {
+ _fetch_close(conn);
+ /* grrr */
+ errno = EAUTH;
+ _fetch_syserr();
+ return (NULL);
+ }
+
+ val = 1;
+ setsockopt(conn->sd, IPPROTO_TCP, TCP_NOPUSH, &val, sizeof(val));
+
+ return (conn);
+}
+
+static struct url *
+_http_get_proxy(const char *flags)
+{
+ struct url *purl;
+ char *p;
+
+ if (flags != NULL && strchr(flags, 'd') != NULL)
+ return (NULL);
+ if (((p = getenv("HTTP_PROXY")) || (p = getenv("http_proxy"))) &&
+ *p && (purl = fetchParseURL(p))) {
+ if (!*purl->scheme)
+ strcpy(purl->scheme, SCHEME_HTTP);
+ if (!purl->port)
+ purl->port = _fetch_default_proxy_port(purl->scheme);
+ if (strcasecmp(purl->scheme, SCHEME_HTTP) == 0)
+ return (purl);
+ fetchFreeURL(purl);
+ }
+ return (NULL);
+}
+
+static void
+_http_print_html(FILE *out, FILE *in)
+{
+ size_t len;
+ char *line, *p, *q;
+ int comment, tag;
+
+ comment = tag = 0;
+ while ((line = fgetln(in, &len)) != NULL) {
+ while (len && isspace(line[len - 1]))
+ --len;
+ for (p = q = line; q < line + len; ++q) {
+ if (comment && *q == '-') {
+ if (q + 2 < line + len &&
+ strcmp(q, "-->") == 0) {
+ tag = comment = 0;
+ q += 2;
+ }
+ } else if (tag && !comment && *q == '>') {
+ p = q + 1;
+ tag = 0;
+ } else if (!tag && *q == '<') {
+ if (q > p)
+ fwrite(p, q - p, 1, out);
+ tag = 1;
+ if (q + 3 < line + len &&
+ strcmp(q, "<!--") == 0) {
+ comment = 1;
+ q += 3;
+ }
+ }
+ }
+ if (!tag && q > p)
+ fwrite(p, q - p, 1, out);
+ fputc('\n', out);
+ }
+}
+
+
+/*****************************************************************************
+ * Core
+ */
+
+/*
+ * Send a request and process the reply
+ *
+ * XXX This function is way too long, the do..while loop should be split
+ * XXX off into a separate function.
+ */
+FILE *
+_http_request(struct url *URL, const char *op, struct url_stat *us,
+ struct url *purl, const char *flags)
+{
+ conn_t *conn;
+ struct url *url, *new;
+ int chunked, direct, need_auth, noredirect, verbose;
+ int e, i, n, val;
+ off_t offset, clength, length, size;
+ time_t mtime;
+ const char *p;
+ FILE *f;
+ hdr_t h;
+ char hbuf[MAXHOSTNAMELEN + 7], *host;
+
+ direct = CHECK_FLAG('d');
+ noredirect = CHECK_FLAG('A');
+ verbose = CHECK_FLAG('v');
+
+ if (direct && purl) {
+ fetchFreeURL(purl);
+ purl = NULL;
+ }
+
+ /* try the provided URL first */
+ url = URL;
+
+ /* if the A flag is set, we only get one try */
+ n = noredirect ? 1 : MAX_REDIRECT;
+ i = 0;
+
+ e = HTTP_PROTOCOL_ERROR;
+ need_auth = 0;
+ do {
+ new = NULL;
+ chunked = 0;
+ offset = 0;
+ clength = -1;
+ length = -1;
+ size = -1;
+ mtime = 0;
+
+ /* check port */
+ if (!url->port)
+ url->port = _fetch_default_port(url->scheme);
+
+ /* were we redirected to an FTP URL? */
+ if (purl == NULL && strcmp(url->scheme, SCHEME_FTP) == 0) {
+ if (strcmp(op, "GET") == 0)
+ return (_ftp_request(url, "RETR", us, purl, flags));
+ else if (strcmp(op, "HEAD") == 0)
+ return (_ftp_request(url, "STAT", us, purl, flags));
+ }
+
+ /* connect to server or proxy */
+ if ((conn = _http_connect(url, purl, flags)) == NULL)
+ goto ouch;
+
+ host = url->host;
+#ifdef INET6
+ if (strchr(url->host, ':')) {
+ snprintf(hbuf, sizeof(hbuf), "[%s]", url->host);
+ host = hbuf;
+ }
+#endif
+ if (url->port != _fetch_default_port(url->scheme)) {
+ if (host != hbuf) {
+ strcpy(hbuf, host);
+ host = hbuf;
+ }
+ snprintf(hbuf + strlen(hbuf),
+ sizeof(hbuf) - strlen(hbuf), ":%d", url->port);
+ }
+
+ /* send request */
+ if (verbose)
+ _fetch_info("requesting %s://%s%s",
+ url->scheme, host, url->doc);
+ if (purl) {
+ _http_cmd(conn, "%s %s://%s%s HTTP/1.1",
+ op, url->scheme, host, url->doc);
+ } else {
+ _http_cmd(conn, "%s %s HTTP/1.1",
+ op, url->doc);
+ }
+
+ /* virtual host */
+ _http_cmd(conn, "Host: %s", host);
+
+ /* proxy authorization */
+ if (purl) {
+ if (*purl->user || *purl->pwd)
+ _http_basic_auth(conn, "Proxy-Authorization",
+ purl->user, purl->pwd);
+ else if ((p = getenv("HTTP_PROXY_AUTH")) != NULL && *p != '\0')
+ _http_authorize(conn, "Proxy-Authorization", p);
+ }
+
+ /* server authorization */
+ if (need_auth || *url->user || *url->pwd) {
+ if (*url->user || *url->pwd)
+ _http_basic_auth(conn, "Authorization", url->user, url->pwd);
+ else if ((p = getenv("HTTP_AUTH")) != NULL && *p != '\0')
+ _http_authorize(conn, "Authorization", p);
+ else if (fetchAuthMethod && fetchAuthMethod(url) == 0) {
+ _http_basic_auth(conn, "Authorization", url->user, url->pwd);
+ } else {
+ _http_seterr(HTTP_NEED_AUTH);
+ goto ouch;
+ }
+ }
+
+ /* other headers */
+ if ((p = getenv("HTTP_REFERER")) != NULL && *p != '\0') {
+ if (strcasecmp(p, "auto") == 0)
+ _http_cmd(conn, "Referer: %s://%s%s",
+ url->scheme, host, url->doc);
+ else
+ _http_cmd(conn, "Referer: %s", p);
+ }
+ if ((p = getenv("HTTP_USER_AGENT")) != NULL && *p != '\0')
+ _http_cmd(conn, "User-Agent: %s", p);
+ else
+ _http_cmd(conn, "User-Agent: %s " _LIBFETCH_VER, getprogname());
+ if (url->offset > 0)
+ _http_cmd(conn, "Range: bytes=%lld-", (long long)url->offset);
+ _http_cmd(conn, "Connection: close");
+ _http_cmd(conn, "");
+
+ /*
+ * Force the queued request to be dispatched. Normally, one
+ * would do this with shutdown(2) but squid proxies can be
+ * configured to disallow such half-closed connections. To
+ * be compatible with such configurations, fiddle with socket
+ * options to force the pending data to be written.
+ */
+ val = 0;
+ setsockopt(conn->sd, IPPROTO_TCP, TCP_NOPUSH, &val,
+ sizeof(val));
+ val = 1;
+ setsockopt(conn->sd, IPPROTO_TCP, TCP_NODELAY, &val,
+ sizeof(val));
+
+ /* get reply */
+ switch (_http_get_reply(conn)) {
+ case HTTP_OK:
+ case HTTP_PARTIAL:
+ /* fine */
+ break;
+ case HTTP_MOVED_PERM:
+ case HTTP_MOVED_TEMP:
+ case HTTP_SEE_OTHER:
+ /*
+ * Not so fine, but we still have to read the
+ * headers to get the new location.
+ */
+ break;
+ case HTTP_NEED_AUTH:
+ if (need_auth) {
+ /*
+ * We already sent out authorization code,
+ * so there's nothing more we can do.
+ */
+ _http_seterr(conn->err);
+ goto ouch;
+ }
+ /* try again, but send the password this time */
+ if (verbose)
+ _fetch_info("server requires authorization");
+ break;
+ case HTTP_NEED_PROXY_AUTH:
+ /*
+ * If we're talking to a proxy, we already sent
+ * our proxy authorization code, so there's
+ * nothing more we can do.
+ */
+ _http_seterr(conn->err);
+ goto ouch;
+ case HTTP_BAD_RANGE:
+ /*
+ * This can happen if we ask for 0 bytes because
+ * we already have the whole file. Consider this
+ * a success for now, and check sizes later.
+ */
+ break;
+ case HTTP_PROTOCOL_ERROR:
+ /* fall through */
+ case -1:
+ _fetch_syserr();
+ goto ouch;
+ default:
+ _http_seterr(conn->err);
+ if (!verbose)
+ goto ouch;
+ /* fall through so we can get the full error message */
+ }
+
+ /* get headers */
+ do {
+ switch ((h = _http_next_header(conn, &p))) {
+ case hdr_syserror:
+ _fetch_syserr();
+ goto ouch;
+ case hdr_error:
+ _http_seterr(HTTP_PROTOCOL_ERROR);
+ goto ouch;
+ case hdr_content_length:
+ _http_parse_length(p, &clength);
+ break;
+ case hdr_content_range:
+ _http_parse_range(p, &offset, &length, &size);
+ break;
+ case hdr_last_modified:
+ _http_parse_mtime(p, &mtime);
+ break;
+ case hdr_location:
+ if (!HTTP_REDIRECT(conn->err))
+ break;
+ if (new)
+ free(new);
+ if (verbose)
+ _fetch_info("%d redirect to %s", conn->err, p);
+ if (*p == '/')
+ /* absolute path */
+ new = fetchMakeURL(url->scheme, url->host, url->port, p,
+ url->user, url->pwd);
+ else
+ new = fetchParseURL(p);
+ if (new == NULL) {
+ /* XXX should set an error code */
+ DEBUG(fprintf(stderr, "failed to parse new URL\n"));
+ goto ouch;
+ }
+ if (!*new->user && !*new->pwd) {
+ strcpy(new->user, url->user);
+ strcpy(new->pwd, url->pwd);
+ }
+ new->offset = url->offset;
+ new->length = url->length;
+ break;
+ case hdr_transfer_encoding:
+ /* XXX weak test*/
+ chunked = (strcasecmp(p, "chunked") == 0);
+ break;
+ case hdr_www_authenticate:
+ if (conn->err != HTTP_NEED_AUTH)
+ break;
+ /* if we were smarter, we'd check the method and realm */
+ break;
+ case hdr_end:
+ /* fall through */
+ case hdr_unknown:
+ /* ignore */
+ break;
+ }
+ } while (h > hdr_end);
+
+ /* we need to provide authentication */
+ if (conn->err == HTTP_NEED_AUTH) {
+ e = conn->err;
+ need_auth = 1;
+ _fetch_close(conn);
+ conn = NULL;
+ continue;
+ }
+
+ /* requested range not satisfiable */
+ if (conn->err == HTTP_BAD_RANGE) {
+ if (url->offset == size && url->length == 0) {
+ /* asked for 0 bytes; fake it */
+ offset = url->offset;
+ conn->err = HTTP_OK;
+ break;
+ } else {
+ _http_seterr(conn->err);
+ goto ouch;
+ }
+ }
+
+ /* we have a hit or an error */
+ if (conn->err == HTTP_OK || conn->err == HTTP_PARTIAL || HTTP_ERROR(conn->err))
+ break;
+
+ /* all other cases: we got a redirect */
+ e = conn->err;
+ need_auth = 0;
+ _fetch_close(conn);
+ conn = NULL;
+ if (!new) {
+ DEBUG(fprintf(stderr, "redirect with no new location\n"));
+ break;
+ }
+ if (url != URL)
+ fetchFreeURL(url);
+ url = new;
+ } while (++i < n);
+
+ /* we failed, or ran out of retries */
+ if (conn == NULL) {
+ _http_seterr(e);
+ goto ouch;
+ }
+
+ DEBUG(fprintf(stderr, "offset %lld, length %lld,"
+ " size %lld, clength %lld\n",
+ (long long)offset, (long long)length,
+ (long long)size, (long long)clength));
+
+ /* check for inconsistencies */
+ if (clength != -1 && length != -1 && clength != length) {
+ _http_seterr(HTTP_PROTOCOL_ERROR);
+ goto ouch;
+ }
+ if (clength == -1)
+ clength = length;
+ if (clength != -1)
+ length = offset + clength;
+ if (length != -1 && size != -1 && length != size) {
+ _http_seterr(HTTP_PROTOCOL_ERROR);
+ goto ouch;
+ }
+ if (size == -1)
+ size = length;
+
+ /* fill in stats */
+ if (us) {
+ us->size = size;
+ us->atime = us->mtime = mtime;
+ }
+
+ /* too far? */
+ if (URL->offset > 0 && offset > URL->offset) {
+ _http_seterr(HTTP_PROTOCOL_ERROR);
+ goto ouch;
+ }
+
+ /* report back real offset and size */
+ URL->offset = offset;
+ URL->length = clength;
+
+ /* wrap it up in a FILE */
+ if ((f = _http_funopen(conn, chunked)) == NULL) {
+ _fetch_syserr();
+ goto ouch;
+ }
+
+ if (url != URL)
+ fetchFreeURL(url);
+ if (purl)
+ fetchFreeURL(purl);
+
+ if (HTTP_ERROR(conn->err)) {
+ _http_print_html(stderr, f);
+ fclose(f);
+ f = NULL;
+ }
+
+ return (f);
+
+ouch:
+ if (url != URL)
+ fetchFreeURL(url);
+ if (purl)
+ fetchFreeURL(purl);
+ if (conn != NULL)
+ _fetch_close(conn);
+ return (NULL);
+}
+
+
+/*****************************************************************************
+ * Entry points
+ */
+
+/*
+ * Retrieve and stat a file by HTTP
+ */
+FILE *
+fetchXGetHTTP(struct url *URL, struct url_stat *us, const char *flags)
+{
+ return (_http_request(URL, "GET", us, _http_get_proxy(flags), flags));
+}
+
+/*
+ * Retrieve a file by HTTP
+ */
+FILE *
+fetchGetHTTP(struct url *URL, const char *flags)
+{
+ return (fetchXGetHTTP(URL, NULL, flags));
+}
+
+/*
+ * Store a file by HTTP
+ */
+FILE *
+fetchPutHTTP(struct url *URL __unused, const char *flags __unused)
+{
+ warnx("fetchPutHTTP(): not implemented");
+ return (NULL);
+}
+
+/*
+ * Get an HTTP document's metadata
+ */
+int
+fetchStatHTTP(struct url *URL, struct url_stat *us, const char *flags)
+{
+ FILE *f;
+
+ f = _http_request(URL, "HEAD", us, _http_get_proxy(flags), flags);
+ if (f == NULL)
+ return (-1);
+ fclose(f);
+ return (0);
+}
+
+/*
+ * List a directory
+ */
+struct url_ent *
+fetchListHTTP(struct url *url __unused, const char *flags __unused)
+{
+ warnx("fetchListHTTP(): not implemented");
+ return (NULL);
+}
diff --git a/lib/libfetch/http.errors b/lib/libfetch/http.errors
new file mode 100644
index 0000000..1f38574
--- /dev/null
+++ b/lib/libfetch/http.errors
@@ -0,0 +1,45 @@
+# $FreeBSD$
+#
+# This list is taken from RFC 2068.
+#
+100 OK Continue
+101 OK Switching Protocols
+200 OK OK
+201 OK Created
+202 OK Accepted
+203 INFO Non-Authoritative Information
+204 OK No Content
+205 OK Reset Content
+206 OK Partial Content
+300 MOVED Multiple Choices
+301 MOVED Moved Permanently
+302 MOVED Moved Temporarily
+303 MOVED See Other
+304 OK Not Modified
+305 INFO Use Proxy
+307 MOVED Temporary Redirect
+400 PROTO Bad Request
+401 AUTH Unauthorized
+402 AUTH Payment Required
+403 AUTH Forbidden
+404 UNAVAIL Not Found
+405 PROTO Method Not Allowed
+406 PROTO Not Acceptable
+407 AUTH Proxy Authentication Required
+408 TIMEOUT Request Time-out
+409 EXISTS Conflict
+410 UNAVAIL Gone
+411 PROTO Length Required
+412 SERVER Precondition Failed
+413 PROTO Request Entity Too Large
+414 PROTO Request-URI Too Large
+415 PROTO Unsupported Media Type
+416 UNAVAIL Requested Range Not Satisfiable
+417 SERVER Expectation Failed
+500 SERVER Internal Server Error
+501 PROTO Not Implemented
+502 SERVER Bad Gateway
+503 TEMP Service Unavailable
+504 TIMEOUT Gateway Time-out
+505 PROTO HTTP Version not supported
+999 PROTO Protocol error
diff --git a/lib/libform/Makefile b/lib/libform/Makefile
new file mode 100644
index 0000000..027be49
--- /dev/null
+++ b/lib/libform/Makefile
@@ -0,0 +1,100 @@
+# Makefile for libform
+# $FreeBSD$
+
+NCURSES=${.CURDIR}/../../contrib/ncurses
+
+.PATH: ${NCURSES}/form
+.PATH: ${NCURSES}/include
+.PATH: ${NCURSES}/man
+
+LIB= form
+DPADD= ${LIBNCURSES}
+LDADD= -lncurses
+
+AWK?= awk
+
+SRCS= ncurses_def.h \
+ fld_arg.c fld_attr.c fld_current.c fld_def.c fld_dup.c fld_ftchoice.c \
+ fld_ftlink.c fld_info.c fld_just.c fld_link.c fld_max.c fld_move.c \
+ fld_newftyp.c fld_opts.c fld_pad.c fld_page.c fld_stat.c fld_type.c \
+ fld_user.c frm_cursor.c frm_data.c frm_def.c frm_driver.c frm_hook.c \
+ frm_opts.c frm_page.c frm_post.c frm_req_name.c frm_scale.c frm_sub.c \
+ frm_user.c frm_win.c fty_alnum.c fty_alpha.c fty_enum.c fty_int.c \
+ fty_ipv4.c fty_num.c fty_regex.c
+INCS= ${NCURSES}/form/form.h
+
+CLEANFILES+= ncurses_def.h
+CFLAGS+= -I.
+.if exists(${.OBJDIR}/../libncurses)
+CFLAGS+= -I${.OBJDIR}/../libncurses
+.endif
+CFLAGS+=-I${.CURDIR}/../libncurses -I${NCURSES}/form -I${NCURSES}/menu \
+ -I${NCURSES}/include -Wall -DNDEBUG -DHAVE_CONFIG_H
+
+ncurses_def.h: MKncurses_def.sh ncurses_defs
+ AWK=${AWK} sh ${NCURSES}/include/MKncurses_def.sh \
+ ${NCURSES}/include/ncurses_defs > ncurses_def.h
+
+MANx= form.3x form_cursor.3x form_data.3x form_driver.3x \
+ form_field.3x form_field_attributes.3x form_field_buffer.3x \
+ form_field_info.3x form_field_just.3x form_field_new.3x \
+ form_field_opts.3x form_field_userptr.3x \
+ form_field_validation.3x form_fieldtype.3x form_hook.3x \
+ form_new.3x form_new_page.3x form_opts.3x form_page.3x \
+ form_post.3x form_requestname.3x form_userptr.3x form_win.3x
+
+# Generate the MAN list from MANx
+.for page in ${MANx}
+CLEANFILES+=${page:T:S/x$//g}
+MAN+=${page:T:S/x$//g}
+${page:T:S/x$//g}: ${page}
+ cat ${.ALLSRC} > ${.TARGET}
+.endfor
+
+MLINKS+=form_cursor.3 pos_form_cursor.3
+MLINKS+=form_data.3 data_ahead.3 form_data.3 data_behind.3
+MLINKS+=form_field.3 field_count.3 form_field.3 form_fields.3 \
+ form_field.3 move_field.3 form_field.3 set_form_fields.3
+MLINKS+=form_field_attributes.3 field_back.3 \
+ form_field_attributes.3 field_fore.3 \
+ form_field_attributes.3 field_pad.3 \
+ form_field_attributes.3 set_field_back.3 \
+ form_field_attributes.3 set_field_fore.3 \
+ form_field_attributes.3 set_field_pad.3
+MLINKS+=form_field_buffer.3 field_buffer.3 \
+ form_field_buffer.3 field_status.3 \
+ form_field_buffer.3 set_field_buffer.3 \
+ form_field_buffer.3 set_field_status.3 \
+ form_field_buffer.3 set_max_field.3
+MLINKS+=form_field_info.3 dynamic_fieldinfo.3 form_field_info.3 field_info.3
+MLINKS+=form_field_just.3 field_just.3 form_field_just.3 set_field_just.3
+MLINKS+=form_field_new.3 dup_field.3 form_field_new.3 free_field.3 \
+ form_field_new.3 link_field.3 form_field_new.3 new_field.3
+MLINKS+=form_field_opts.3 field_opts.3 form_field_opts.3 field_opts_off.3 \
+ form_field_opts.3 field_opts_on.3 form_field_opts.3 set_field_opts.3 \
+ form_field_opts.3 set_form_opts.3
+MLINKS+=form_field_userptr.3 field_userptr.3 \
+ form_field_userptr.3 set_field_userptr.3
+MLINKS+=form_field_validation.3 field_arg.3 \
+ form_field_validation.3 field_type.3 \
+ form_field_validation.3 set_field_type.3
+MLINKS+=form_fieldtype.3 link_fieldtype.3 \
+ form_fieldtype.3 set_fieldtype_arg.3 \
+ form_fieldtype.3 set_fieldtype_choice.3
+MLINKS+=form_hook.3 field_init.3 form_hook.3 field_term.3 \
+ form_hook.3 form_init.3 form_hook.3 form_term.3 \
+ form_hook.3 set_field_init.3 form_hook.3 set_field_term.3 \
+ form_hook.3 set_form_init.3 form_hook.3 set_form_term.3
+MLINKS+=form_new.3 free_form.3 form_new.3 new_form.3
+MLINKS+=form_new_page.3 new_page.3 form_new_page.3 set_new_page.3
+MLINKS+=form_opts.3 form_opts_off.3 form_opts.3 form_opts_on.3
+MLINKS+=form_page.3 current_field.3 form_page.3 field_index.3 \
+ form_page.3 set_current_field.3 form_page.3 set_form_page.3
+MLINKS+=form_post.3 post_form.3 form_post.3 unpost_form.3
+MLINKS+=form_requestname.3 form_request_by_name.3 \
+ form_requestname.3 form_request_name.3
+MLINKS+=form_userptr.3 set_form_userptr.3
+MLINKS+=form_win.3 form_sub.3 form_win.3 scale_form.3 \
+ form_win.3 set_form_sub.3 form_win.3 set_form_win.3
+
+.include <bsd.lib.mk>
diff --git a/lib/libftpio/Makefile b/lib/libftpio/Makefile
new file mode 100644
index 0000000..b803db8
--- /dev/null
+++ b/lib/libftpio/Makefile
@@ -0,0 +1,27 @@
+# $FreeBSD$
+
+LIB= ftpio
+SHLIB_MAJOR= 6
+
+SRCS= ftpio.c ftperr.c
+INCS= ftpio.h
+CFLAGS+= -I${.CURDIR} -Wall
+CFLAGS+= -DINET6
+MAN= ftpio.3
+CLEANFILES= ftperr.c
+
+ftperr.c: ftp.errors
+ @echo '#include <stdio.h>' > ${.TARGET}
+ @echo '#include "ftpio.h"' >> ${.TARGET}
+ @echo "struct ftperr ftpErrList[] = {" \ >> ${.TARGET}
+ @cat ${.ALLSRC} \
+ | grep -v ^# \
+ | sort \
+ | while read NUM STRING; do \
+ echo " { $${NUM}, \"$${STRING}\" },"; \
+ done >> ${.TARGET}
+ @echo "};" >> ${.TARGET}
+ @echo -n "int const ftpErrListLength = " >> ${.TARGET}
+ @echo "sizeof(ftpErrList) / sizeof(*ftpErrList);" >> ${.TARGET}
+
+.include <bsd.lib.mk>
diff --git a/lib/libftpio/ftp.errors b/lib/libftpio/ftp.errors
new file mode 100644
index 0000000..c03eeac
--- /dev/null
+++ b/lib/libftpio/ftp.errors
@@ -0,0 +1,45 @@
+# $FreeBSD$
+#
+# This list is taken from RFC 959.
+# It probably needs a going over.
+#
+110 Restart marker reply
+120 Service ready in a few minutes
+125 Data connection already open; transfer starting
+150 File status okay; about to open data connection
+200 Command okay
+202 Command not implemented, superfluous at this site
+211 System status, or system help reply
+212 Directory status
+213 File status
+214 Help message
+215 Set system type
+220 Service ready for new user
+221 Service closing control connection
+225 Data connection open; no transfer in progress
+226 Requested file action successful
+227 Entering Passive Mode
+229 Entering Extended Passive Mode
+230 User logged in, proceed
+250 Requested file action okay, completed
+257 File/directory created
+331 User name okay, need password
+332 Need account for login
+350 Requested file action pending further information
+421 Service not available, closing control connection
+425 Can't open data connection
+426 Connection closed; transfer aborted
+450 File unavailable (e.g., file busy)
+451 Requested action aborted: local error in processing
+452 Insufficient storage space in system
+500 Syntax error, command unrecognized
+501 Syntax error in parameters or arguments
+502 Command not implemented
+503 Bad sequence of commands
+504 Command not implemented for that parameter
+530 Not logged in
+532 Need account for storing files
+550 File unavailable (e.g., file not found, no access)
+551 Requested action aborted. Page type unknown
+552 Exceeded storage allocation
+553 File name not allowed
diff --git a/lib/libftpio/ftpio.3 b/lib/libftpio/ftpio.3
new file mode 100644
index 0000000..64378c2
--- /dev/null
+++ b/lib/libftpio/ftpio.3
@@ -0,0 +1,260 @@
+.\" Copyright (c) 1996 Jordan Hubbard (jkh@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 JORDAN HUBBARD ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING 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 17, 1996
+.Dt FTPIO 3
+.Os
+.Sh NAME
+.Nm ftpLogin ,
+.Nm ftpChdir ,
+.Nm ftpErrno ,
+.Nm ftpGetModtime ,
+.Nm ftpGetSize ,
+.Nm ftpGet ,
+.Nm ftpPut ,
+.Nm ftpBinary ,
+.Nm ftpPassive ,
+.Nm ftpVerbose ,
+.Nm ftpGetURL ,
+.Nm ftpPutURL ,
+.Nm ftpLoginAf ,
+.Nm ftpGetURLAf ,
+.Nm ftpPutURLAf
+.Nd FTPIO user library
+.Sh SYNOPSIS
+.In ftpio.h
+.Ft FILE *
+.Fn ftpLogin "char *host" "char *user" "char *passwd" "int ftp_port" "int verbose" "int *retcode"
+.Ft int
+.Fn ftpChdir "FILE *stream" "char *dirname"
+.Ft int
+.Fn ftpErrno "FILE *stream"
+.Ft const char *
+.Fn ftpErrString "int errno"
+.Ft time_t
+.Fn ftpGetModtime "FILE *stream" "char *file"
+.Ft off_t
+.Fn ftpGetSize "FILE *stream" "char *file"
+.Ft FILE *
+.Fn ftpGet "FILE *stream" "char *file" "off_t *seekto"
+.Ft FILE *
+.Fn ftpPut "FILE *stream" "char *file"
+.Ft int
+.Fn ftpAscii "FILE *stream"
+.Ft int
+.Fn ftpBinary "FILE *stream"
+.Ft int
+.Fn ftpPassive "FILE *stream" "int status"
+.Ft void
+.Fn ftpVerbose "FILE *stream" "int status"
+.Ft FILE *
+.Fn ftpGetURL "char *url" "char *user" "char *passwd" "int *retcode"
+.Ft FILE *
+.Fn ftpPutURL "char *url" "char *user" "char *passwd" "int *retcode"
+.Ft FILE *
+.Fn ftpLoginAf "char *host" "int af" "char *user" "char *passwd" "int ftp_port" "int verbose" "int *retcode"
+.Ft FILE *
+.Fn ftpGetURLAf "char *url" "int af" "char *user" "char *passwd" "int *retcode"
+.Ft FILE *
+.Fn ftpPutURLAf "char *url" "int af" "char *user" "char *passwd" "int *retcode"
+.Sh DESCRIPTION
+These functions implement a high-level library for managing FTP connections.
+.Pp
+The
+.Fn ftpLogin
+function attempts to log in using the supplied
+.Fa user ,
+.Fa passwd ,
+.Fa ftp_port
+(if passed as 0,
+.Fa ftp_port
+defaults to the standard ftp port of 21) and
+.Fa verbose
+fields.
+If it is successful, a
+standard stream descriptor is returned which should be passed to
+subsequent FTP operations.
+On failure, NULL is returned and
+.Fa retcode
+will have the error code returned by the foreign server.
+.Pp
+The
+.Fn ftpChdir
+function attempts to issue a server CD command to the directory named in
+.Fa dir .
+On success, zero is returned.
+On failure, the error code from the server.
+.Pp
+The
+.Fn ftpErrno
+function returns the server failure code for the last operation (useful for
+seeing more about what happened if you are familiar with FTP error codes).
+The
+.Fn ftpErrString
+function returns a human readable version of the supplied server failure code.
+.Pp
+The
+.Fn ftpGet
+function attempts to retrieve the file named by the
+.Fa file
+argument (which is assumed to be relative to the FTP server's current directory,
+see
+.Fn ftpChdir )
+and returns a new FILE* pointer for the file or NULL on failure.
+If
+.Fa seekto
+is non-NULL, the contents of the integer it points to will be used
+as a restart point for the file, that is to say that the stream
+returned will point
+.Fa *seekto
+bytes into the file gotten (this is handy for restarting failed
+transfers efficiently).
+If the seek operation fails, the value
+of
+.Fa *seekto
+will be zero'd.
+.Pp
+The
+.Fn ftpGetModtime
+function returns the last modification time of the file named by the
+.Fa file
+argument.
+If the file could not be opened or stat'd, 0 is returned.
+.Pp
+The
+.Fn ftpGetSize
+function returns the size in bytes of the file named by the
+.Fa file
+argument.
+If the file could not be opened or stat'd, -1 is returned.
+.Pp
+The
+.Fn ftpPut
+function attempts to create a new file named by the
+.Fa file
+argument (which is assumed to be relative to the FTP server's current directory,
+see
+.Fn ftpChdir )
+and returns a new
+.Fa stream
+pointer for the file or NULL on failure.
+.Pp
+The
+.Fn ftpAscii
+function sets
+.Tn ASCII
+mode for the current server connection named by
+.Fa stream .
+.Pp
+The
+.Fn ftpBinary
+function sets binary mode for the current server connection named by
+.Fa stream .
+.Pp
+The
+.Fn ftpPassive
+function sets passive mode (for firewalls) for the current server connection
+named by
+.Fa stream
+to boolean value
+.Fa status .
+.Pp
+The
+.Fn ftpVerbose
+function sets the verbosity mode for the current server connection named by
+.Fa stream
+to boolean value
+.Fa status .
+.Pp
+The
+.Fn ftpGetURL
+function attempts to retrieve the file named by the supplied
+.Fa URL
+and can be considered equivalent to the combined
+.Fn ftpLogin ,
+.Fn ftpChdir
+and
+.Fn ftpGet
+operations except that no server
+.Fa stream
+is ever returned - the connection to the server closes when
+the file has been completely read.
+Use the lower-level routines
+if multiple gets are required as it will be far more efficient.
+.Pp
+The
+.Fn ftpPutURL
+function attempts to create the file named by the supplied
+.Fa URL
+and can be considered equivalent to the combined
+.Fn ftpLogin ,
+.Fn ftpChdir
+and
+.Fn ftpPut
+operations except that no server stream is ever returned - the connection
+to the server closes when the file has been completely written.
+Use the
+lower-level routines if multiple puts are required as it will be far more
+efficient.
+.Pp
+The
+.Fn ftpLoginAf ,
+.Fn ftpGetURLAf ,
+.Fn ftpPutURLAf
+functions are same as
+.Fn ftpLogin ,
+.Fn ftpGetURL ,
+.Fn ftpPutURL
+except that they are able to specify address family
+.Fa af .
+.Sh ENVIRONMENT
+.Bl -tag -width FTP_PASSIVE_MODE -offset 3n
+.It Ev FTP_TIMEOUT
+Maximum time, in seconds, to wait for a response
+from the peer before aborting an
+.Tn FTP
+connection.
+.It Ev FTP_PASSIVE_MODE
+If defined, forces the use of passive mode, unless equal
+to ``NO'' or ``no'' in which case active mode is forced.
+If defined, the setting of this variable always overrides any calls to
+.Fn ftpPassive .
+.El
+.Sh HISTORY
+Started life as Poul-Henning Kamp's ftp driver for the system installation
+utility, later significantly mutated into a more general form as an
+extension of stdio by Jordan Hubbard.
+Also incorporates some ideas and
+extensions from Jean-Marc Zucconi.
+.Sh AUTHORS
+.An Jordan Hubbard ,
+.An Poul-Henning Kamp
+and
+.An Jean-Marc Zucconi
+.Sh BUGS
+I am sure you can get this thing's internal state machine confused if
+you really work at it, but so far it has proven itself pretty robust in
+all my tests.
diff --git a/lib/libftpio/ftpio.c b/lib/libftpio/ftpio.c
new file mode 100644
index 0000000..f990d4d
--- /dev/null
+++ b/lib/libftpio/ftpio.c
@@ -0,0 +1,1070 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "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
+ * ----------------------------------------------------------------------------
+ *
+ * Major Changelog:
+ *
+ * Jordan K. Hubbard
+ * 17 Jan 1996
+ *
+ * Turned inside out. Now returns xfers as new file ids, not as a special
+ * `state' of FTP_t
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <ftpio.h>
+#include <netdb.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define SUCCESS 0
+#define FAILURE -1
+
+#ifndef TRUE
+#define TRUE (1)
+#define FALSE (0)
+#endif
+
+/* How to see by a given code whether or not the connection has timed out */
+#define FTP_TIMEOUT(code) (FtpTimedOut || code == FTP_TIMED_OUT)
+
+/* Internal routines - deal only with internal FTP_t type */
+static FTP_t ftp_new(void);
+static void check_passive(FILE *fp);
+static int ftp_read_method(void *n, char *buf, int nbytes);
+static int ftp_write_method(void *n, const char *buf, int nbytes);
+static int ftp_close_method(void *n);
+static int writes(int fd, char *s);
+static __inline char *get_a_line(FTP_t ftp);
+static int get_a_number(FTP_t ftp, char **q);
+static int botch(char *func, char *botch_state);
+static int cmd(FTP_t ftp, const char *fmt, ...);
+static int ftp_login_session(FTP_t ftp, char *host, int af, char *user, char *passwd, int port, int verbose);
+static int ftp_file_op(FTP_t ftp, char *operation, char *file, FILE **fp, char *mode, off_t *seekto);
+static int ftp_close(FTP_t ftp);
+static int get_url_info(char *url_in, char *host_ret, int *port_ret, char *name_ret);
+static void ftp_timeout(int sig);
+static void ftp_set_timeout(void);
+static void ftp_clear_timeout(void);
+static void ai_unmapped(struct addrinfo *);
+
+
+/* Global status variable - ick */
+int FtpTimedOut;
+
+/* FTP happy status codes */
+#define FTP_GENERALLY_HAPPY 200
+#define FTP_ASCII_HAPPY FTP_GENERALLY_HAPPY
+#define FTP_BINARY_HAPPY FTP_GENERALLY_HAPPY
+#define FTP_PORT_HAPPY FTP_GENERALLY_HAPPY
+#define FTP_HAPPY_COMMENT 220
+#define FTP_QUIT_HAPPY 221
+#define FTP_TRANSFER_HAPPY 226
+#define FTP_PASSIVE_HAPPY 227
+#define FTP_LPASSIVE_HAPPY 228
+#define FTP_EPASSIVE_HAPPY 229
+#define FTP_CHDIR_HAPPY 250
+
+/* FTP unhappy status codes */
+#define FTP_TIMED_OUT 421
+
+/*
+ * XXX
+ * gross! evil! bad! We really need an access primitive for cookie in stdio itself.
+ * it's too convenient a hook to bury and it's already exported through funopen as it is, so...
+ * XXX
+ */
+#define fcookie(fp) ((fp)->_cookie)
+
+/* Placeholder in case we want to do any pre-init stuff at some point */
+int
+networkInit()
+{
+ return SUCCESS; /* XXX dummy function for now XXX */
+}
+
+/* Check a return code with some lenience for back-dated garbage that might be in the buffer */
+static int
+check_code(FTP_t ftp, int var, int preferred)
+{
+ ftp->error = 0;
+ while (1) {
+ if (var == preferred)
+ return 0;
+ else if (var == FTP_TRANSFER_HAPPY) /* last operation succeeded */
+ var = get_a_number(ftp, NULL);
+ else if (var == FTP_HAPPY_COMMENT) /* chit-chat */
+ var = get_a_number(ftp, NULL);
+ else if (var == FTP_GENERALLY_HAPPY) /* general success code */
+ var = get_a_number(ftp, NULL);
+ else {
+ ftp->error = var;
+ return 1;
+ }
+ }
+}
+
+int
+ftpAscii(FILE *fp)
+{
+ FTP_t ftp = fcookie(fp);
+ int i;
+
+ if (!ftp->is_binary)
+ return SUCCESS;
+ i = cmd(ftp, "TYPE A");
+ if (i < 0 || check_code(ftp, i, FTP_ASCII_HAPPY))
+ return i;
+ ftp->is_binary = FALSE;
+ return SUCCESS;
+}
+
+int
+ftpBinary(FILE *fp)
+{
+ FTP_t ftp = fcookie(fp);
+ int i;
+
+ if (ftp->is_binary)
+ return SUCCESS;
+ i = cmd(ftp, "TYPE I");
+ if (i < 0 || check_code(ftp, i, FTP_BINARY_HAPPY))
+ return i;
+ ftp->is_binary = TRUE;
+ return SUCCESS;
+}
+void
+ftpVerbose(FILE *fp, int status)
+{
+ FTP_t ftp = fcookie(fp);
+ ftp->is_verbose = status;
+}
+
+int
+ftpChdir(FILE *fp, char *dir)
+{
+ int i;
+ FTP_t ftp = fcookie(fp);
+
+ i = cmd(ftp, "CWD %s", dir);
+ if (i < 0 || check_code(ftp, i, FTP_CHDIR_HAPPY))
+ return i;
+ return SUCCESS;
+}
+
+int
+ftpErrno(FILE *fp)
+{
+ FTP_t ftp = fcookie(fp);
+ return ftp->error;
+}
+
+const char *
+ftpErrString(int error)
+{
+ int k;
+
+ if (error == -1)
+ return("connection in wrong state");
+ if (error < 100)
+ /* XXX soon UNIX errnos will catch up with FTP protocol errnos */
+ return strerror(error);
+ for (k = 0; k < ftpErrListLength; k++)
+ if (ftpErrList[k].num == error)
+ return(ftpErrList[k].string);
+ return("Unknown error");
+}
+
+off_t
+ftpGetSize(FILE *fp, char *name)
+{
+ int i;
+ char p[BUFSIZ], *cp, *ep;
+ FTP_t ftp = fcookie(fp);
+ off_t size;
+
+ check_passive(fp);
+ sprintf(p, "SIZE %s\r\n", name);
+ if (ftp->is_verbose)
+ fprintf(stderr, "Sending %s", p);
+ if (writes(ftp->fd_ctrl, p))
+ return (off_t)-1;
+ i = get_a_number(ftp, &cp);
+ if (check_code(ftp, i, 213))
+ return (off_t)-1;
+
+ errno = 0; /* to check for ERANGE */
+ size = (off_t)strtoq(cp, &ep, 10);
+ if (*ep != '\0' || errno == ERANGE)
+ return (off_t)-1;
+ return size;
+}
+
+time_t
+ftpGetModtime(FILE *fp, char *name)
+{
+ char p[BUFSIZ], *cp;
+ struct tm t;
+ time_t t0 = time (0);
+ FTP_t ftp = fcookie(fp);
+ int i;
+
+ check_passive(fp);
+ sprintf(p, "MDTM %s\r\n", name);
+ if (ftp->is_verbose)
+ fprintf(stderr, "Sending %s", p);
+ if (writes(ftp->fd_ctrl, p))
+ return (time_t)0;
+ i = get_a_number(ftp, &cp);
+ if (check_code(ftp, i, 213))
+ return (time_t)0;
+ while (*cp && !isdigit(*cp))
+ cp++;
+ if (!*cp)
+ return (time_t)0;
+ t0 = localtime (&t0)->tm_gmtoff;
+ sscanf(cp, "%04d%02d%02d%02d%02d%02d", &t.tm_year, &t.tm_mon, &t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec);
+ t.tm_mon--;
+ t.tm_year -= 1900;
+ t.tm_isdst=-1;
+ t.tm_gmtoff = 0;
+ t0 += mktime (&t);
+ return t0;
+}
+
+FILE *
+ftpGet(FILE *fp, char *file, off_t *seekto)
+{
+ FILE *fp2;
+ FTP_t ftp = fcookie(fp);
+
+ check_passive(fp);
+ if (ftpBinary(fp) != SUCCESS)
+ return NULL;
+
+ if (ftp_file_op(ftp, "RETR", file, &fp2, "r", seekto) == SUCCESS)
+ return fp2;
+ return NULL;
+}
+
+/* Returns a standard FILE pointer type representing an open control connection */
+FILE *
+ftpLogin(char *host, char *user, char *passwd, int port, int verbose, int *retcode)
+{
+#ifdef INET6
+ return ftpLoginAf(host, AF_UNSPEC, user, passwd, port, verbose, retcode);
+#else
+ return ftpLoginAf(host, AF_INET, user, passwd, port, verbose, retcode);
+#endif
+}
+
+FILE *
+ftpLoginAf(char *host, int af, char *user, char *passwd, int port, int verbose, int *retcode)
+{
+ FTP_t n;
+ FILE *fp;
+
+ if (retcode)
+ *retcode = 0;
+ if (networkInit() != SUCCESS)
+ return NULL;
+
+ n = ftp_new();
+ fp = NULL;
+ if (n && ftp_login_session(n, host, af, user, passwd, port, verbose) == SUCCESS) {
+ fp = funopen(n, ftp_read_method, ftp_write_method, NULL, ftp_close_method); /* BSD 4.4 function! */
+ fp->_file = n->fd_ctrl;
+ }
+ if (retcode) {
+ if (!n)
+ *retcode = (FtpTimedOut ? FTP_TIMED_OUT : -1);
+ /* Poor attempt at mapping real errnos to FTP error codes */
+ else switch(n->error) {
+ case EADDRNOTAVAIL:
+ *retcode = FTP_TIMED_OUT; /* Actually no such host, but we have no way of saying that. :-( */
+ break;
+
+ case ETIMEDOUT:
+ *retcode = FTP_TIMED_OUT;
+ break;
+
+ default:
+ *retcode = n->error;
+ break;
+ }
+ }
+ return fp;
+}
+
+FILE *
+ftpPut(FILE *fp, char *file)
+{
+ FILE *fp2;
+ FTP_t ftp = fcookie(fp);
+
+ check_passive(fp);
+ if (ftp_file_op(ftp, "STOR", file, &fp2, "w", NULL) == SUCCESS)
+ return fp2;
+ return NULL;
+}
+
+int
+ftpPassive(FILE *fp, int st)
+{
+ FTP_t ftp = fcookie(fp);
+
+ ftp->is_passive = !!st; /* normalize "st" to zero or one */
+ return SUCCESS;
+}
+
+FILE *
+ftpGetURL(char *url, char *user, char *passwd, int *retcode)
+{
+#ifdef INET6
+ return ftpGetURLAf(url, AF_UNSPEC, user, passwd, retcode);
+#else
+ return ftpGetURLAf(url, AF_INET, user, passwd, retcode);
+#endif
+}
+
+FILE *
+ftpGetURLAf(char *url, int af, char *user, char *passwd, int *retcode)
+{
+ char host[255], name[255];
+ int port;
+ FILE *fp2;
+ static FILE *fp = NULL;
+ static char *prev_host;
+
+ if (retcode)
+ *retcode = 0;
+ if (get_url_info(url, host, &port, name) == SUCCESS) {
+ if (fp && prev_host) {
+ if (!strcmp(prev_host, host)) {
+ /* Try to use cached connection */
+ fp2 = ftpGet(fp, name, NULL);
+ if (!fp2) {
+ /* Connection timed out or was no longer valid */
+ fclose(fp);
+ free(prev_host);
+ prev_host = NULL;
+ }
+ else
+ return fp2;
+ }
+ else {
+ /* It's a different host now, flush old */
+ fclose(fp);
+ free(prev_host);
+ prev_host = NULL;
+ }
+ }
+ fp = ftpLoginAf(host, af, user, passwd, port, 0, retcode);
+ if (fp) {
+ fp2 = ftpGet(fp, name, NULL);
+ if (!fp2) {
+ /* Connection timed out or was no longer valid */
+ if (retcode)
+ *retcode = ftpErrno(fp);
+ fclose(fp);
+ fp = NULL;
+ }
+ else
+ prev_host = strdup(host);
+ return fp2;
+ }
+ }
+ return NULL;
+}
+
+FILE *
+ftpPutURL(char *url, char *user, char *passwd, int *retcode)
+{
+#ifdef INET6
+ return ftpPutURLAf(url, AF_UNSPEC, user, passwd, retcode);
+#else
+ return ftpPutURLAf(url, AF_INET, user, passwd, retcode);
+#endif
+
+}
+
+FILE *
+ftpPutURLAf(char *url, int af, char *user, char *passwd, int *retcode)
+{
+ char host[255], name[255];
+ int port;
+ static FILE *fp = NULL;
+ FILE *fp2;
+
+ if (retcode)
+ *retcode = 0;
+ if (fp) { /* Close previous managed connection */
+ fclose(fp);
+ fp = NULL;
+ }
+ if (get_url_info(url, host, &port, name) == SUCCESS) {
+ fp = ftpLoginAf(host, af, user, passwd, port, 0, retcode);
+ if (fp) {
+ fp2 = ftpPut(fp, name);
+ if (!fp2) {
+ if (retcode)
+ *retcode = ftpErrno(fp);
+ fclose(fp);
+ fp = NULL;
+ }
+ return fp2;
+ }
+ }
+ return NULL;
+}
+
+/* Internal workhorse function for dissecting URLs. Takes a URL as the first argument and returns the
+ result of such disection in the host, user, passwd, port and name variables. */
+static int
+get_url_info(char *url_in, char *host_ret, int *port_ret, char *name_ret)
+{
+ char *name, *host, *cp, url[BUFSIZ];
+ int port;
+
+ name = host = NULL;
+ /* XXX add http:// here or somewhere reasonable at some point XXX */
+ if (strncmp("ftp://", url_in, 6) != 0)
+ return FAILURE;
+ /* We like to stomp a lot on the URL string in dissecting it, so copy it first */
+ strncpy(url, url_in, BUFSIZ);
+ host = url + 6;
+ if ((cp = index(host, ':')) != NULL) {
+ *(cp++) = '\0';
+ port = strtol(cp, 0, 0);
+ }
+ else
+ port = 0; /* use default */
+ if (port_ret)
+ *port_ret = port;
+
+ if ((name = index(cp ? cp : host, '/')) != NULL)
+ *(name++) = '\0';
+ if (host_ret)
+ strcpy(host_ret, host);
+ if (name && name_ret)
+ strcpy(name_ret, name);
+ return SUCCESS;
+}
+
+static FTP_t
+ftp_new(void)
+{
+ FTP_t ftp;
+
+ ftp = (FTP_t)malloc(sizeof *ftp);
+ if (!ftp)
+ return NULL;
+ memset(ftp, 0, sizeof *ftp);
+ ftp->fd_ctrl = -1;
+ ftp->con_state = init;
+ ftp->is_binary = FALSE;
+ ftp->is_passive = FALSE;
+ ftp->is_verbose = FALSE;
+ ftp->error = 0;
+ return ftp;
+}
+
+static int
+ftp_read_method(void *vp, char *buf, int nbytes)
+{
+ int i, fd;
+ FTP_t n = (FTP_t)vp;
+
+ fd = n->fd_ctrl;
+ i = (fd >= 0) ? read(fd, buf, nbytes) : EOF;
+ return i;
+}
+
+static int
+ftp_write_method(void *vp, const char *buf, int nbytes)
+{
+ int i, fd;
+ FTP_t n = (FTP_t)vp;
+
+ fd = n->fd_ctrl;
+ i = (fd >= 0) ? write(fd, buf, nbytes) : EOF;
+ return i;
+}
+
+static int
+ftp_close_method(void *n)
+{
+ int i;
+
+ i = ftp_close((FTP_t)n);
+ free(n);
+ return i;
+}
+
+/*
+ * This function checks whether the FTP_PASSIVE_MODE environment
+ * variable is set, and, if so, enforces the desired mode.
+ */
+static void
+check_passive(FILE *fp)
+{
+ const char *cp = getenv("FTP_PASSIVE_MODE");
+
+ if (cp != NULL)
+ ftpPassive(fp, strncasecmp(cp, "no", 2));
+}
+
+static void
+ftp_timeout(int sig)
+{
+ FtpTimedOut = TRUE;
+ /* Debug("ftp_pkg: ftp_timeout called - operation timed out"); */
+}
+
+static void
+ftp_set_timeout(void)
+{
+ struct sigaction new;
+ char *cp;
+ int ival;
+
+ FtpTimedOut = FALSE;
+ sigemptyset(&new.sa_mask);
+ new.sa_flags = 0;
+ new.sa_handler = ftp_timeout;
+ sigaction(SIGALRM, &new, NULL);
+ cp = getenv("FTP_TIMEOUT");
+ if (!cp || !(ival = atoi(cp)))
+ ival = 120;
+ alarm(ival);
+}
+
+static void
+ftp_clear_timeout(void)
+{
+ struct sigaction new;
+
+ alarm(0);
+ sigemptyset(&new.sa_mask);
+ new.sa_flags = 0;
+ new.sa_handler = SIG_DFL;
+ sigaction(SIGALRM, &new, NULL);
+}
+
+static int
+writes(int fd, char *s)
+{
+ int n, i = strlen(s);
+
+ ftp_set_timeout();
+ n = write(fd, s, i);
+ ftp_clear_timeout();
+ if (FtpTimedOut || i != n)
+ return TRUE;
+ return FALSE;
+}
+
+static __inline char *
+get_a_line(FTP_t ftp)
+{
+ static char buf[BUFSIZ];
+ int i,j;
+
+ /* Debug("ftp_pkg: trying to read a line from %d", ftp->fd_ctrl); */
+ for(i = 0; i < BUFSIZ;) {
+ ftp_set_timeout();
+ j = read(ftp->fd_ctrl, buf + i, 1);
+ ftp_clear_timeout();
+ if (FtpTimedOut || j != 1)
+ return NULL;
+ if (buf[i] == '\r' || buf[i] == '\n') {
+ if (!i)
+ continue;
+ buf[i] = '\0';
+ if (ftp->is_verbose == TRUE)
+ fprintf(stderr, "%s\n",buf+4);
+ return buf;
+ }
+ i++;
+ }
+ /* Debug("ftp_pkg: read string \"%s\" from %d", buf, ftp->fd_ctrl); */
+ return buf;
+}
+
+static int
+get_a_number(FTP_t ftp, char **q)
+{
+ char *p;
+ int i = -1, j;
+
+ while(1) {
+ p = get_a_line(ftp);
+ if (!p) {
+ ftp_close(ftp);
+ if (FtpTimedOut)
+ return FTP_TIMED_OUT;
+ return FAILURE;
+ }
+ if (!(isdigit(p[0]) && isdigit(p[1]) && isdigit(p[2])))
+ continue;
+ if (i == -1 && p[3] == '-') {
+ i = strtol(p, 0, 0);
+ continue;
+ }
+ if (p[3] != ' ' && p[3] != '\t')
+ continue;
+ j = strtol(p, 0, 0);
+ if (i == -1) {
+ if (q) *q = p+4;
+ /* Debug("ftp_pkg: read reply %d from server (%s)", j, p); */
+ return j;
+ } else if (j == i) {
+ if (q) *q = p+4;
+ /* Debug("ftp_pkg: read reply %d from server (%s)", j, p); */
+ return j;
+ }
+ }
+}
+
+static int
+ftp_close(FTP_t ftp)
+{
+ int i, rcode;
+
+ rcode = FAILURE;
+ if (ftp->con_state == isopen) {
+ ftp->con_state = quit;
+ /* If last operation timed out, don't try to quit - just close */
+ if (ftp->error != FTP_TIMED_OUT)
+ i = cmd(ftp, "QUIT");
+ else
+ i = FTP_QUIT_HAPPY;
+ if (!check_code(ftp, i, FTP_QUIT_HAPPY))
+ rcode = SUCCESS;
+ close(ftp->fd_ctrl);
+ ftp->fd_ctrl = -1;
+ }
+ else if (ftp->con_state == quit)
+ rcode = SUCCESS;
+ return rcode;
+}
+
+static int
+botch(char *func, char *botch_state)
+{
+ /* Debug("ftp_pkg: botch: %s(%s)", func, botch_state); */
+ return FAILURE;
+}
+
+static int
+cmd(FTP_t ftp, const char *fmt, ...)
+{
+ char p[BUFSIZ];
+ int i;
+
+ va_list ap;
+ va_start(ap, fmt);
+ (void)vsnprintf(p, sizeof p, fmt, ap);
+ va_end(ap);
+
+ if (ftp->con_state == init)
+ return botch("cmd", "open");
+
+ strcat(p, "\r\n");
+ if (ftp->is_verbose)
+ fprintf(stderr, "Sending: %s", p);
+ if (writes(ftp->fd_ctrl, p)) {
+ if (FtpTimedOut)
+ return FTP_TIMED_OUT;
+ return FAILURE;
+ }
+ while ((i = get_a_number(ftp, NULL)) == FTP_HAPPY_COMMENT);
+ return i;
+}
+
+static int
+ftp_login_session(FTP_t ftp, char *host, int af,
+ char *user, char *passwd, int port, int verbose)
+{
+ char pbuf[10];
+ struct addrinfo hints, *res, *res0;
+ int err;
+ int s;
+ int i;
+
+ if (networkInit() != SUCCESS)
+ return FAILURE;
+
+ if (ftp->con_state != init) {
+ ftp_close(ftp);
+ ftp->error = -1;
+ return FAILURE;
+ }
+
+ if (!user)
+ user = "ftp";
+
+ if (!passwd)
+ passwd = "setup@";
+
+ if (!port)
+ port = 21;
+
+ snprintf(pbuf, sizeof(pbuf), "%d", port);
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = af;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = 0;
+ err = getaddrinfo(host, pbuf, &hints, &res0);
+ if (err) {
+ ftp->error = 0;
+ return FAILURE;
+ }
+
+ s = -1;
+ for (res = res0; res; res = res->ai_next) {
+ ai_unmapped(res);
+ ftp->addrtype = res->ai_family;
+
+ if ((s = socket(res->ai_family, res->ai_socktype,
+ res->ai_protocol)) < 0)
+ continue;
+
+ if (connect(s, res->ai_addr, res->ai_addrlen) < 0) {
+ (void)close(s);
+ s = -1;
+ continue;
+ }
+
+ break;
+ }
+ freeaddrinfo(res0);
+ if (s < 0) {
+ ftp->error = errno;
+ return FAILURE;
+ }
+
+ ftp->fd_ctrl = s;
+ ftp->con_state = isopen;
+ ftp->is_verbose = verbose;
+
+ i = cmd(ftp, "USER %s", user);
+ if (i >= 300 && i < 400)
+ i = cmd(ftp, "PASS %s", passwd);
+ if (i >= 299 || i < 0) {
+ ftp_close(ftp);
+ if (i > 0)
+ ftp->error = i;
+ return FAILURE;
+ }
+ return SUCCESS;
+}
+
+static int
+ftp_file_op(FTP_t ftp, char *operation, char *file, FILE **fp, char *mode, off_t *seekto)
+{
+ socklen_t sinlen;
+ int i,l,s;
+ char *q;
+ unsigned char addr[64];
+ union sockaddr_cmn {
+ struct sockaddr_in sin4;
+ struct sockaddr_in6 sin6;
+ } sin;
+ char *cmdstr;
+
+ if (!fp)
+ return FAILURE;
+ *fp = NULL;
+
+ if (ftp->con_state != isopen)
+ return botch("ftp_file_op", "open");
+
+ if ((s = socket(ftp->addrtype, SOCK_STREAM, 0)) < 0) {
+ ftp->error = errno;
+ return FAILURE;
+ }
+
+ if (ftp->is_passive) {
+ if (ftp->addrtype == AF_INET) {
+ if (ftp->is_verbose)
+ fprintf(stderr, "Sending PASV\n");
+ if (writes(ftp->fd_ctrl, "PASV\r\n")) {
+ ftp_close(ftp);
+ if (FtpTimedOut)
+ ftp->error = FTP_TIMED_OUT;
+ return FTP_TIMED_OUT;
+ }
+ i = get_a_number(ftp, &q);
+ if (check_code(ftp, i, FTP_PASSIVE_HAPPY)) {
+ ftp_close(ftp);
+ return i;
+ }
+ cmdstr = "PASV";
+ } else {
+ if (ftp->is_verbose)
+ fprintf(stderr, "Sending EPSV\n");
+ if (writes(ftp->fd_ctrl, "EPSV\r\n")) {
+ ftp_close(ftp);
+ if (FtpTimedOut)
+ ftp->error = FTP_TIMED_OUT;
+ return FTP_TIMED_OUT;
+ }
+ i = get_a_number(ftp, &q);
+ if (check_code(ftp, i, FTP_EPASSIVE_HAPPY)) {
+ if (ftp->is_verbose)
+ fprintf(stderr, "Sending LPSV\n");
+ if (writes(ftp->fd_ctrl, "LPSV\r\n")) {
+ ftp_close(ftp);
+ if (FtpTimedOut)
+ ftp->error = FTP_TIMED_OUT;
+ return FTP_TIMED_OUT;
+ }
+ i = get_a_number(ftp, &q);
+ if (check_code(ftp, i, FTP_LPASSIVE_HAPPY)) {
+ ftp_close(ftp);
+ return i;
+ }
+ cmdstr = "LPSV";
+ } else
+ cmdstr = "EPSV";
+ }
+ if (strcmp(cmdstr, "PASV") == 0 || strcmp(cmdstr, "LPSV") == 0) {
+ while (*q && !isdigit(*q))
+ q++;
+ if (!*q) {
+ ftp_close(ftp);
+ return FAILURE;
+ }
+ q--;
+ l = (ftp->addrtype == AF_INET ? 6 : 21);
+ for (i = 0; i < l; i++) {
+ q++;
+ addr[i] = strtol(q, &q, 10);
+ }
+
+ sin.sin4.sin_family = ftp->addrtype;
+ if (ftp->addrtype == AF_INET6) {
+ sin.sin6.sin6_len = sizeof(struct sockaddr_in6);
+ bcopy(addr + 2, (char *)&sin.sin6.sin6_addr, 16);
+ bcopy(addr + 19, (char *)&sin.sin6.sin6_port, 2);
+ } else {
+ sin.sin4.sin_len = sizeof(struct sockaddr_in);
+ bcopy(addr, (char *)&sin.sin4.sin_addr, 4);
+ bcopy(addr + 4, (char *)&sin.sin4.sin_port, 2);
+ }
+ } else if (strcmp(cmdstr, "EPSV") == 0) {
+ int port;
+ while (*q && *q != '(') /* ) */
+ q++;
+ if (!*q) {
+ ftp_close(ftp);
+ return FAILURE;
+ }
+ q++;
+ if (sscanf(q, "%c%c%c%d%c", &addr[0], &addr[1], &addr[2],
+ &port, &addr[3]) != 5
+ || addr[0] != addr[1] || addr[0] != addr[2] || addr[0] != addr[3]) {
+ ftp_close(ftp);
+ return FAILURE;
+ }
+ sinlen = sizeof(sin);
+ if (getpeername(ftp->fd_ctrl, (struct sockaddr *)&sin, &sinlen) < 0) {
+ ftp_close(ftp);
+ return FAILURE;
+ }
+ switch (sin.sin4.sin_family) {
+ case AF_INET:
+ sin.sin4.sin_port = htons(port);
+ break;
+ case AF_INET6:
+ sin.sin6.sin6_port = htons(port);
+ break;
+ default:
+ ftp_close(ftp);
+ return FAILURE;
+ }
+ }
+
+ if (connect(s, (struct sockaddr *)&sin, sin.sin4.sin_len) < 0) {
+ (void)close(s);
+ return FAILURE;
+ }
+
+ if (seekto && *seekto) {
+ i = cmd(ftp, "REST %d", *seekto);
+ if (i < 0 || FTP_TIMEOUT(i)) {
+ close(s);
+ ftp->error = i;
+ *seekto = (off_t)0;
+ return i;
+ }
+ }
+ i = cmd(ftp, "%s %s", operation, file);
+ if (i < 0 || i > 299) {
+ close(s);
+ ftp->error = i;
+ return i;
+ }
+ *fp = fdopen(s, mode);
+ }
+ else {
+ int fd,portrange;
+
+#ifdef IPV6_PORTRANGE
+ if (ftp->addrtype == AF_INET6) {
+ portrange = IPV6_PORTRANGE_HIGH;
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_PORTRANGE, (char *)
+ &portrange, sizeof(portrange)) < 0) {
+ close(s);
+ return FAILURE;
+ }
+ }
+#endif
+#ifdef IP_PORTRANGE
+ if (ftp->addrtype == AF_INET) {
+ portrange = IP_PORTRANGE_HIGH;
+ if (setsockopt(s, IPPROTO_IP, IP_PORTRANGE, (char *)
+ &portrange, sizeof(portrange)) < 0) {
+ close(s);
+ return FAILURE;
+ }
+ }
+#endif
+
+ sinlen = sizeof sin;
+ getsockname(ftp->fd_ctrl, (struct sockaddr *)&sin, &sinlen);
+ sin.sin4.sin_port = 0;
+ i = ((struct sockaddr *)&sin)->sa_len;
+ if (bind(s, (struct sockaddr *)&sin, i) < 0) {
+ close(s);
+ return FAILURE;
+ }
+ sinlen = sizeof sin;
+ getsockname(s, (struct sockaddr *)&sin, &sinlen);
+ if (listen(s, 1) < 0) {
+ close(s);
+ return FAILURE;
+ }
+ if (sin.sin4.sin_family == AF_INET) {
+ u_long a;
+ a = ntohl(sin.sin4.sin_addr.s_addr);
+ i = cmd(ftp, "PORT %d,%d,%d,%d,%d,%d",
+ (a >> 24) & 0xff,
+ (a >> 16) & 0xff,
+ (a >> 8) & 0xff,
+ a & 0xff,
+ (ntohs(sin.sin4.sin_port) >> 8) & 0xff,
+ ntohs(sin.sin4.sin_port) & 0xff);
+ if (check_code(ftp, i, FTP_PORT_HAPPY)) {
+ close(s);
+ return i;
+ }
+ } else {
+#define UC(b) (((int)b)&0xff)
+ char *a;
+ char hname[INET6_ADDRSTRLEN];
+
+ sin.sin6.sin6_scope_id = 0;
+ if (getnameinfo((struct sockaddr *)&sin, sin.sin6.sin6_len,
+ hname, sizeof(hname),
+ NULL, 0, NI_NUMERICHOST) != 0) {
+ goto try_lprt;
+ }
+ i = cmd(ftp, "EPRT |%d|%s|%d|", 2, hname,
+ htons(sin.sin6.sin6_port));
+ if (check_code(ftp, i, FTP_PORT_HAPPY)) {
+try_lprt:
+ a = (char *)&sin.sin6.sin6_addr;
+ i = cmd(ftp,
+"LPRT %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
+ 6, 16,
+ UC(a[0]),UC(a[1]),UC(a[2]),UC(a[3]),
+ UC(a[4]),UC(a[5]),UC(a[6]),UC(a[7]),
+ UC(a[8]),UC(a[9]),UC(a[10]),UC(a[11]),
+ UC(a[12]),UC(a[13]),UC(a[14]),UC(a[15]),
+ 2,
+ (ntohs(sin.sin4.sin_port) >> 8) & 0xff,
+ ntohs(sin.sin4.sin_port) & 0xff);
+ if (check_code(ftp, i, FTP_PORT_HAPPY)) {
+ close(s);
+ return i;
+ }
+ }
+ }
+ if (seekto && *seekto) {
+ i = cmd(ftp, "REST %d", *seekto);
+ if (i < 0 || FTP_TIMEOUT(i)) {
+ close(s);
+ ftp->error = i;
+ return i;
+ }
+ else if (i != 350)
+ *seekto = (off_t)0;
+ }
+ i = cmd(ftp, "%s %s", operation, file);
+ if (i < 0 || i > 299) {
+ close(s);
+ ftp->error = i;
+ return FAILURE;
+ }
+ fd = accept(s, 0, 0);
+ if (fd < 0) {
+ close(s);
+ ftp->error = 401;
+ return FAILURE;
+ }
+ close(s);
+ *fp = fdopen(fd, mode);
+ }
+ if (*fp)
+ return SUCCESS;
+ else
+ return FAILURE;
+}
+
+static void
+ai_unmapped(struct addrinfo *ai)
+{
+ struct sockaddr_in6 *sin6;
+ struct sockaddr_in sin;
+
+ if (ai->ai_family != AF_INET6)
+ return;
+ if (ai->ai_addrlen != sizeof(struct sockaddr_in6) ||
+ sizeof(sin) > ai->ai_addrlen)
+ return;
+ sin6 = (struct sockaddr_in6 *)ai->ai_addr;
+ if (!IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
+ return;
+
+ 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));
+ sin.sin_port = sin6->sin6_port;
+
+ ai->ai_family = AF_INET;
+ memcpy(ai->ai_addr, &sin, sin.sin_len);
+ ai->ai_addrlen = sin.sin_len;
+}
diff --git a/lib/libftpio/ftpio.h b/lib/libftpio/ftpio.h
new file mode 100644
index 0000000..879abea
--- /dev/null
+++ b/lib/libftpio/ftpio.h
@@ -0,0 +1,71 @@
+#ifndef _FTP_H_INCLUDE
+#define _FTP_H_INCLUDE
+
+#include <sys/types.h>
+#include <sys/cdefs.h>
+#include <stdio.h>
+#include <time.h>
+
+/*
+ * ----------------------------------------------------------------------------
+ * "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
+ * ----------------------------------------------------------------------------
+ *
+ * Major Changelog:
+ *
+ * Jordan K. Hubbard
+ * 17 Jan 1996
+ *
+ * Turned inside out. Now returns xfers as new file ids, not as a special
+ * `state' of FTP_t
+ *
+ * $FreeBSD$
+ */
+
+/* Internal housekeeping data structure for FTP sessions */
+typedef struct {
+ enum { init, isopen, quit } con_state;
+ int fd_ctrl;
+ int addrtype;
+ char *host;
+ char *file;
+ int error;
+ int is_binary;
+ int is_passive;
+ int is_verbose;
+} *FTP_t;
+
+/* Structure we use to match FTP error codes with readable strings */
+struct ftperr {
+ const int num;
+ const char *string;
+};
+
+__BEGIN_DECLS
+extern struct ftperr ftpErrList[];
+extern int const ftpErrListLength;
+
+/* Exported routines - deal only with FILE* type */
+extern FILE *ftpLogin(char *host, char *user, char *passwd, int port, int verbose, int *retcode);
+extern int ftpChdir(FILE *fp, char *dir);
+extern int ftpErrno(FILE *fp);
+extern off_t ftpGetSize(FILE *fp, char *file);
+extern FILE *ftpGet(FILE *fp, char *file, off_t *seekto);
+extern FILE *ftpPut(FILE *fp, char *file);
+extern int ftpAscii(FILE *fp);
+extern int ftpBinary(FILE *fp);
+extern int ftpPassive(FILE *fp, int status);
+extern void ftpVerbose(FILE *fp, int status);
+extern FILE *ftpGetURL(char *url, char *user, char *passwd, int *retcode);
+extern FILE *ftpPutURL(char *url, char *user, char *passwd, int *retcode);
+extern time_t ftpGetModtime(FILE *fp, char *s);
+extern const char *ftpErrString(int error);
+extern FILE *ftpLoginAf(char *host, int af, char *user, char *passwd, int port, int verbose, int *retcode);
+extern FILE *ftpGetURLAf(char *url, int af, char *user, char *passwd, int *retcode);
+extern FILE *ftpPutURLAf(char *url, int af, char *user, char *passwd, int *retcode);
+__END_DECLS
+
+#endif /* _FTP_H_INCLUDE */
diff --git a/lib/libgeom/Makefile b/lib/libgeom/Makefile
new file mode 100644
index 0000000..c64ce50
--- /dev/null
+++ b/lib/libgeom/Makefile
@@ -0,0 +1,36 @@
+# $FreeBSD$
+
+LIB= geom
+SHLIBDIR?= /lib
+SRCS+= geom_getxml.c
+SRCS+= geom_stats.c
+SRCS+= geom_xml2tree.c
+SRCS+= geom_ctl.c
+INCS= libgeom.h
+
+CFLAGS += -I${.CURDIR}
+
+WARNS?= 3
+
+DPADD= ${LIBBSDXML} ${LIBSBUF}
+LDADD= -lbsdxml -lsbuf
+
+MAN= libgeom.3
+
+MLINKS+= \
+ libgeom.3 geom_stats_open.3 \
+ libgeom.3 geom_stats_close.3 \
+ libgeom.3 geom_stats_resync.3 \
+ libgeom.3 geom_stats_snapshot_get.3 \
+ libgeom.3 geom_stats_snapshot_free.3 \
+ libgeom.3 geom_stats_snapshot_timestamp.3 \
+ libgeom.3 geom_stats_snapshot_reset.3 \
+ libgeom.3 geom_stats_snapshot_next.3 \
+ libgeom.3 gctl_get_handle.3 \
+ libgeom.3 gctl_ro_param.3 \
+ libgeom.3 gctl_rw_param.3 \
+ libgeom.3 gctl_issue.3 \
+ libgeom.3 gctl_free.3 \
+ libgeom.3 gctl_dump.3
+
+.include <bsd.lib.mk>
diff --git a/lib/libgeom/geom_ctl.c b/lib/libgeom/geom_ctl.c
new file mode 100644
index 0000000..d308849
--- /dev/null
+++ b/lib/libgeom/geom_ctl.c
@@ -0,0 +1,238 @@
+/*-
+ * Copyright (c) 2003 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.
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <paths.h>
+
+#include <sys/queue.h>
+
+#define GCTL_TABLE 1
+#include <libgeom.h>
+
+void
+gctl_dump(struct gctl_req *req, FILE *f)
+{
+ u_int i;
+ int j;
+ struct gctl_req_arg *ap;
+
+ if (req == NULL) {
+ fprintf(f, "Dump of gctl request at NULL\n");
+ return;
+ }
+ fprintf(f, "Dump of gctl request at %p:\n", req);
+ if (req->error != NULL)
+ fprintf(f, " error:\t\"%s\"\n", req->error);
+ else
+ fprintf(f, " error:\tNULL\n");
+ for (i = 0; i < req->narg; i++) {
+ ap = &req->arg[i];
+ fprintf(f, " param:\t\"%s\" (%d)", ap->name, ap->nlen);
+ fprintf(f, " [%s%s",
+ ap->flag & GCTL_PARAM_RD ? "R" : "",
+ ap->flag & GCTL_PARAM_WR ? "W" : "");
+ fflush(f);
+ if (ap->flag & GCTL_PARAM_ASCII)
+ fprintf(f, "%d] = \"%s\"", ap->len, (char *)ap->value);
+ else if (ap->len > 0) {
+ fprintf(f, "%d] = ", ap->len);
+ fflush(f);
+ for (j = 0; j < ap->len; j++) {
+ fprintf(f, " %02x", ((u_char *)ap->value)[j]);
+ }
+ } else {
+ fprintf(f, "0] = %p", ap->value);
+ }
+ fprintf(f, "\n");
+ }
+}
+
+/*
+ * Set an error message, if one does not already exist.
+ */
+static void
+gctl_set_error(struct gctl_req *req, const char *error, ...)
+{
+ va_list ap;
+
+ if (req->error != NULL)
+ return;
+ va_start(ap, error);
+ vasprintf(&req->error, error, ap);
+ va_end(ap);
+}
+
+/*
+ * Check that a malloc operation succeeded, and set a consistent error
+ * message if not.
+ */
+static void
+gctl_check_alloc(struct gctl_req *req, void *ptr)
+{
+ if (ptr != NULL)
+ return;
+ gctl_set_error(req, "Could not allocate memory");
+ if (req->error == NULL)
+ req->error = "Could not allocate memory";
+}
+
+/*
+ * Allocate a new request handle of the specified type.
+ * XXX: Why bother checking the type ?
+ */
+struct gctl_req *
+gctl_get_handle(void)
+{
+ struct gctl_req *rp;
+
+ rp = calloc(1, sizeof *rp);
+ return (rp);
+}
+
+/*
+ * Allocate space for another argument.
+ */
+static struct gctl_req_arg *
+gctl_new_arg(struct gctl_req *req)
+{
+ struct gctl_req_arg *ap;
+
+ req->narg++;
+ req->arg = realloc(req->arg, sizeof *ap * req->narg);
+ gctl_check_alloc(req, req->arg);
+ if (req->arg == NULL) {
+ req->narg = 0;
+ return (NULL);
+ }
+ ap = req->arg + (req->narg - 1);
+ memset(ap, 0, sizeof *ap);
+ return (ap);
+}
+
+void
+gctl_ro_param(struct gctl_req *req, const char *name, int len, const void* value)
+{
+ struct gctl_req_arg *ap;
+
+ if (req == NULL || req->error != NULL)
+ return;
+ ap = gctl_new_arg(req);
+ if (ap == NULL)
+ return;
+ ap->name = strdup(name);
+ gctl_check_alloc(req, ap->name);
+ ap->nlen = strlen(ap->name) + 1;
+ ap->value = __DECONST(void *, value);
+ ap->flag = GCTL_PARAM_RD;
+ if (len >= 0)
+ ap->len = len;
+ else if (len < 0) {
+ ap->flag |= GCTL_PARAM_ASCII;
+ ap->len = strlen(value) + 1;
+ }
+}
+
+void
+gctl_rw_param(struct gctl_req *req, const char *name, int len, void* value)
+{
+ struct gctl_req_arg *ap;
+
+ if (req == NULL || req->error != NULL)
+ return;
+ ap = gctl_new_arg(req);
+ if (ap == NULL)
+ return;
+ ap->name = strdup(name);
+ gctl_check_alloc(req, ap->name);
+ ap->nlen = strlen(ap->name) + 1;
+ ap->value = value;
+ ap->flag = GCTL_PARAM_RW;
+ if (len >= 0)
+ ap->len = len;
+ else if (len < 0)
+ ap->len = strlen(value) + 1;
+}
+
+const char *
+gctl_issue(struct gctl_req *req)
+{
+ int fd, error;
+
+ if (req == NULL)
+ return ("NULL request pointer");
+ if (req->error != NULL)
+ return (req->error);
+
+ req->version = GCTL_VERSION;
+ req->lerror = BUFSIZ; /* XXX: arbitrary number */
+ req->error = malloc(req->lerror);
+ if (req->error == NULL) {
+ gctl_check_alloc(req, req->error);
+ return (req->error);
+ }
+ memset(req->error, 0, req->lerror);
+ req->lerror--;
+ fd = open(_PATH_DEV PATH_GEOM_CTL, O_RDONLY);
+ if (fd < 0)
+ return(strerror(errno));
+ error = ioctl(fd, GEOM_CTL, req);
+ close(fd);
+ if (req->error[0] != '\0')
+ return (req->error);
+ if (error != 0)
+ return(strerror(errno));
+ return (NULL);
+}
+
+void
+gctl_free(struct gctl_req *req)
+{
+ u_int i;
+
+ if (req == NULL)
+ return;
+ for (i = 0; i < req->narg; i++) {
+ if (req->arg[i].name != NULL)
+ free(req->arg[i].name);
+ }
+ free(req->arg);
+ if (req->error != NULL)
+ free(req->error);
+ free(req);
+}
diff --git a/lib/libgeom/geom_getxml.c b/lib/libgeom/geom_getxml.c
new file mode 100644
index 0000000..fbc9cb8
--- /dev/null
+++ b/lib/libgeom/geom_getxml.c
@@ -0,0 +1,66 @@
+/*-
+ * Copyright (c) 2003 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.
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <stdlib.h>
+#include <string.h>
+#include "libgeom.h"
+
+char *
+geom_getxml()
+{
+ char *p;
+ size_t l;
+ int i;
+
+ l = 1024 * 1024; /* Start big, realloc back */
+ p = malloc(l);
+ if (p) {
+ i = sysctlbyname("kern.geom.confxml", p, &l, NULL, 0);
+ if (i == 0) {
+ p = realloc(p, strlen(p) + 1);
+ return (p);
+ }
+ free(p);
+ }
+ l = 0;
+ i = sysctlbyname("kern.geom.confxml", p, &l, NULL, 0);
+ if (i != 0)
+ return (NULL);
+ p = malloc(l + 4096);
+ i = sysctlbyname("kern.geom.confxml", p, &l, NULL, 0);
+ if (i == 0) {
+ p = realloc(p, strlen(p) + 1);
+ return (p);
+ }
+ return (NULL);
+}
diff --git a/lib/libgeom/geom_stats.c b/lib/libgeom/geom_stats.c
new file mode 100644
index 0000000..14f9b22
--- /dev/null
+++ b/lib/libgeom/geom_stats.c
@@ -0,0 +1,185 @@
+/*-
+ * Copyright (c) 2003 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.
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <paths.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <libgeom.h>
+
+#include <sys/mman.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/devicestat.h>
+
+
+/************************************************************/
+static uint npages, pagesize, spp;
+static int statsfd = -1;
+static u_char *statp;
+
+void
+geom_stats_close(void)
+{
+ if (statsfd == -1)
+ return;
+ munmap(statp, npages *pagesize);
+ statp = NULL;
+ close (statsfd);
+ statsfd = -1;
+}
+
+void
+geom_stats_resync(void)
+{
+ void *p;
+
+ if (statsfd == -1)
+ return;
+ for (;;) {
+ p = mmap(statp, (npages + 1) * pagesize,
+ PROT_READ, 0, statsfd, 0);
+ if (p == MAP_FAILED)
+ break;
+ else
+ statp = p;
+ npages++;
+ }
+}
+
+int
+geom_stats_open(void)
+{
+ int error;
+ void *p;
+
+ if (statsfd != -1)
+ return (EBUSY);
+ statsfd = open(_PATH_DEV DEVSTAT_DEVICE_NAME, O_RDONLY);
+ if (statsfd < 0)
+ return (errno);
+ pagesize = getpagesize();
+ spp = pagesize / sizeof(struct devstat);
+ p = mmap(NULL, pagesize, PROT_READ, 0, statsfd, 0);
+ if (p == MAP_FAILED) {
+ error = errno;
+ close(statsfd);
+ statsfd = -1;
+ errno = error;
+ return (error);
+ }
+ statp = p;
+ npages = 1;
+ geom_stats_resync();
+ return (0);
+}
+
+struct snapshot {
+ u_char *ptr;
+ uint pages;
+ uint pagesize;
+ uint perpage;
+ struct timespec time;
+ /* used by getnext: */
+ uint u, v;
+};
+
+void *
+geom_stats_snapshot_get(void)
+{
+ struct snapshot *sp;
+
+ sp = malloc(sizeof *sp);
+ if (sp == NULL)
+ return (NULL);
+ memset(sp, 0, sizeof *sp);
+ sp->ptr = malloc(pagesize * npages);
+ if (sp->ptr == NULL) {
+ free(sp);
+ return (NULL);
+ }
+ memset(sp->ptr, 0, pagesize * npages); /* page in, cache */
+ clock_gettime(CLOCK_REALTIME, &sp->time);
+ memset(sp->ptr, 0, pagesize * npages); /* page in, cache */
+ memcpy(sp->ptr, statp, pagesize * npages);
+ sp->pages = npages;
+ sp->perpage = spp;
+ sp->pagesize = pagesize;
+ return (sp);
+}
+
+void
+geom_stats_snapshot_free(void *arg)
+{
+ struct snapshot *sp;
+
+ sp = arg;
+ free(sp->ptr);
+ free(sp);
+}
+
+void
+geom_stats_snapshot_timestamp(void *arg, struct timespec *tp)
+{
+ struct snapshot *sp;
+
+ sp = arg;
+ *tp = sp->time;
+}
+
+void
+geom_stats_snapshot_reset(void *arg)
+{
+ struct snapshot *sp;
+
+ sp = arg;
+ sp->u = sp->v = 0;
+}
+
+struct devstat *
+geom_stats_snapshot_next(void *arg)
+{
+ struct devstat *gsp;
+ struct snapshot *sp;
+
+ sp = arg;
+ gsp = (struct devstat *)
+ (sp->ptr + sp->u * pagesize + sp->v * sizeof *gsp);
+ if (++sp->v >= sp->perpage) {
+ if (++sp->u >= sp->pages)
+ return (NULL);
+ else
+ sp->v = 0;
+ }
+ return (gsp);
+}
diff --git a/lib/libgeom/geom_xml2tree.c b/lib/libgeom/geom_xml2tree.c
new file mode 100644
index 0000000..7798f44
--- /dev/null
+++ b/lib/libgeom/geom_xml2tree.c
@@ -0,0 +1,441 @@
+/*-
+ * Copyright (c) 2003 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.
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <stdio.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/queue.h>
+#include <sys/sbuf.h>
+#include <sys/sysctl.h>
+#include <err.h>
+#include <bsdxml.h>
+#include <libgeom.h>
+
+struct mystate {
+ struct gmesh *mesh;
+ struct gclass *class;
+ struct ggeom *geom;
+ struct gprovider *provider;
+ struct gconsumer *consumer;
+ int level;
+ struct sbuf *sbuf[20];
+ struct gconf *config;
+ int nident;
+};
+
+static void
+StartElement(void *userData, const char *name, const char **attr)
+{
+ struct mystate *mt;
+ void *id;
+ void *ref;
+ int i;
+
+ mt = userData;
+ mt->level++;
+ mt->sbuf[mt->level] = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
+ id = NULL;
+ ref = NULL;
+ for (i = 0; attr[i] != NULL; i += 2) {
+ if (!strcmp(attr[i], "id")) {
+ id = (void *)strtoul(attr[i + 1], NULL, 0);
+ mt->nident++;
+ } else if (!strcmp(attr[i], "ref")) {
+ ref = (void *)strtoul(attr[i + 1], NULL, 0);
+ } else
+ printf("%*.*s[%s = %s]\n",
+ mt->level + 1, mt->level + 1, "",
+ attr[i], attr[i + 1]);
+ }
+ if (!strcmp(name, "class") && mt->class == NULL) {
+ mt->class = calloc(1, sizeof *mt->class);
+ mt->class->lg_id = id;
+ LIST_INSERT_HEAD(&mt->mesh->lg_class, mt->class, lg_class);
+ LIST_INIT(&mt->class->lg_geom);
+ LIST_INIT(&mt->class->lg_config);
+ return;
+ }
+ if (!strcmp(name, "geom") && mt->geom == NULL) {
+ mt->geom = calloc(1, sizeof *mt->geom);
+ mt->geom->lg_id = id;
+ LIST_INSERT_HEAD(&mt->class->lg_geom, mt->geom, lg_geom);
+ LIST_INIT(&mt->geom->lg_provider);
+ LIST_INIT(&mt->geom->lg_consumer);
+ LIST_INIT(&mt->geom->lg_config);
+ return;
+ }
+ if (!strcmp(name, "class") && mt->geom != NULL) {
+ mt->geom->lg_class = ref;
+ return;
+ }
+ if (!strcmp(name, "consumer") && mt->consumer == NULL) {
+ mt->consumer = calloc(1, sizeof *mt->consumer);
+ mt->consumer->lg_id = id;
+ LIST_INSERT_HEAD(&mt->geom->lg_consumer, mt->consumer,
+ lg_consumer);
+ LIST_INIT(&mt->consumer->lg_config);
+ return;
+ }
+ if (!strcmp(name, "geom") && mt->consumer != NULL) {
+ mt->consumer->lg_geom = ref;
+ return;
+ }
+ if (!strcmp(name, "provider") && mt->consumer != NULL) {
+ mt->consumer->lg_provider = ref;
+ return;
+ }
+ if (!strcmp(name, "provider") && mt->provider == NULL) {
+ mt->provider = calloc(1, sizeof *mt->provider);
+ mt->provider->lg_id = id;
+ LIST_INSERT_HEAD(&mt->geom->lg_provider, mt->provider,
+ lg_provider);
+ LIST_INIT(&mt->provider->lg_consumers);
+ LIST_INIT(&mt->provider->lg_config);
+ return;
+ }
+ if (!strcmp(name, "geom") && mt->provider != NULL) {
+ mt->provider->lg_geom = ref;
+ return;
+ }
+ if (!strcmp(name, "config")) {
+ if (mt->provider != NULL) {
+ mt->config = &mt->provider->lg_config;
+ return;
+ }
+ if (mt->consumer != NULL) {
+ mt->config = &mt->consumer->lg_config;
+ return;
+ }
+ if (mt->geom != NULL) {
+ mt->config = &mt->geom->lg_config;
+ return;
+ }
+ if (mt->class != NULL) {
+ mt->config = &mt->class->lg_config;
+ return;
+ }
+ }
+}
+
+static void
+EndElement(void *userData, const char *name)
+{
+ struct mystate *mt;
+ struct gconfig *gc;
+ char *p;
+
+ mt = userData;
+ sbuf_finish(mt->sbuf[mt->level]);
+ p = strdup(sbuf_data(mt->sbuf[mt->level]));
+ sbuf_delete(mt->sbuf[mt->level]);
+ mt->sbuf[mt->level] = NULL;
+ mt->level--;
+ if (strlen(p) == 0) {
+ free(p);
+ p = NULL;
+ }
+
+ if (!strcmp(name, "name")) {
+ if (mt->provider != NULL) {
+ mt->provider->lg_name = p;
+ return;
+ } else if (mt->geom != NULL) {
+ mt->geom->lg_name = p;
+ return;
+ } else if (mt->class != NULL) {
+ mt->class->lg_name = p;
+ return;
+ }
+ }
+ if (!strcmp(name, "rank") && mt->geom != NULL) {
+ mt->geom->lg_rank = strtoul(p, NULL, 0);
+ free(p);
+ return;
+ }
+ if (!strcmp(name, "mode") && mt->provider != NULL) {
+ mt->provider->lg_mode = p;
+ return;
+ }
+ if (!strcmp(name, "mode") && mt->consumer != NULL) {
+ mt->consumer->lg_mode = p;
+ return;
+ }
+ if (!strcmp(name, "mediasize") && mt->provider != NULL) {
+ mt->provider->lg_mediasize = strtoumax(p, NULL, 0);
+ free(p);
+ return;
+ }
+ if (!strcmp(name, "sectorsize") && mt->provider != NULL) {
+ mt->provider->lg_sectorsize = strtoul(p, NULL, 0);
+ free(p);
+ return;
+ }
+
+ if (!strcmp(name, "config")) {
+ mt->config = NULL;
+ return;
+ }
+
+ if (mt->config != NULL) {
+ gc = calloc(sizeof *gc, 1);
+ gc->lg_name = strdup(name);
+ gc->lg_val = p;
+ LIST_INSERT_HEAD(mt->config, gc, lg_config);
+ return;
+ }
+
+ if (p != NULL) {
+ printf("Unexpected XML: name=%s data=\"%s\"\n", name, p);
+ free(p);
+ }
+
+ if (!strcmp(name, "consumer") && mt->consumer != NULL) {
+ mt->consumer = NULL;
+ return;
+ }
+ if (!strcmp(name, "provider") && mt->provider != NULL) {
+ mt->provider = NULL;
+ return;
+ }
+ if (!strcmp(name, "geom") && mt->consumer != NULL) {
+ return;
+ }
+ if (!strcmp(name, "geom") && mt->provider != NULL) {
+ return;
+ }
+ if (!strcmp(name, "geom") && mt->geom != NULL) {
+ mt->geom = NULL;
+ return;
+ }
+ if (!strcmp(name, "class") && mt->geom != NULL) {
+ return;
+ }
+ if (!strcmp(name, "class") && mt->class != NULL) {
+ mt->class = NULL;
+ return;
+ }
+}
+
+static void
+CharData(void *userData , const XML_Char *s , int len)
+{
+ struct mystate *mt;
+ const char *b, *e;
+
+ mt = userData;
+
+ b = s;
+ e = s + len - 1;
+ while (isspace(*b) && b < e)
+ b++;
+ while (isspace(*e) && e > b)
+ e--;
+ if (e != b || (*b && !isspace(*b)))
+ sbuf_bcat(mt->sbuf[mt->level], b, e - b + 1);
+}
+
+struct gident *
+geom_lookupid(struct gmesh *gmp, const void *id)
+{
+ struct gident *gip;
+
+ for (gip = gmp->lg_ident; gip->lg_id != NULL; gip++)
+ if (gip->lg_id == id)
+ return (gip);
+ return (NULL);
+}
+
+int
+geom_xml2tree(struct gmesh *gmp, char *p)
+{
+ XML_Parser parser;
+ struct mystate *mt;
+ struct gclass *cl;
+ struct ggeom *ge;
+ struct gprovider *pr;
+ struct gconsumer *co;
+ int i;
+
+ memset(gmp, 0, sizeof *gmp);
+ LIST_INIT(&gmp->lg_class);
+ parser = XML_ParserCreate(NULL);
+ mt = calloc(1, sizeof *mt);
+ if (mt == NULL)
+ return (ENOMEM);
+ mt->mesh = gmp;
+ XML_SetUserData(parser, mt);
+ XML_SetElementHandler(parser, StartElement, EndElement);
+ XML_SetCharacterDataHandler(parser, CharData);
+ i = XML_Parse(parser, p, strlen(p), 1);
+ if (i != 1)
+ return (-1);
+ XML_ParserFree(parser);
+ gmp->lg_ident = calloc(sizeof *gmp->lg_ident, mt->nident + 1);
+ if (gmp->lg_ident == NULL)
+ return (ENOMEM);
+ free(mt);
+ i = 0;
+ /* Collect all identifiers */
+ LIST_FOREACH(cl, &gmp->lg_class, lg_class) {
+ gmp->lg_ident[i].lg_id = cl->lg_id;
+ gmp->lg_ident[i].lg_ptr = cl;
+ gmp->lg_ident[i].lg_what = ISCLASS;
+ i++;
+ LIST_FOREACH(ge, &cl->lg_geom, lg_geom) {
+ gmp->lg_ident[i].lg_id = ge->lg_id;
+ gmp->lg_ident[i].lg_ptr = ge;
+ gmp->lg_ident[i].lg_what = ISGEOM;
+ i++;
+ LIST_FOREACH(pr, &ge->lg_provider, lg_provider) {
+ gmp->lg_ident[i].lg_id = pr->lg_id;
+ gmp->lg_ident[i].lg_ptr = pr;
+ gmp->lg_ident[i].lg_what = ISPROVIDER;
+ i++;
+ }
+ LIST_FOREACH(co, &ge->lg_consumer, lg_consumer) {
+ gmp->lg_ident[i].lg_id = co->lg_id;
+ gmp->lg_ident[i].lg_ptr = co;
+ gmp->lg_ident[i].lg_what = ISCONSUMER;
+ i++;
+ }
+ }
+ }
+ /* Substitute all identifiers */
+ LIST_FOREACH(cl, &gmp->lg_class, lg_class) {
+ LIST_FOREACH(ge, &cl->lg_geom, lg_geom) {
+ ge->lg_class =
+ geom_lookupid(gmp, ge->lg_class)->lg_ptr;
+ LIST_FOREACH(pr, &ge->lg_provider, lg_provider) {
+ pr->lg_geom =
+ geom_lookupid(gmp, pr->lg_geom)->lg_ptr;
+ }
+ LIST_FOREACH(co, &ge->lg_consumer, lg_consumer) {
+ co->lg_geom =
+ geom_lookupid(gmp, co->lg_geom)->lg_ptr;
+ if (co->lg_provider != NULL) {
+ co->lg_provider =
+ geom_lookupid(gmp,
+ co->lg_provider)->lg_ptr;
+ LIST_INSERT_HEAD(
+ &co->lg_provider->lg_consumers,
+ co, lg_consumers);
+ }
+ }
+ }
+ }
+ return (0);
+}
+
+int
+geom_gettree(struct gmesh *gmp)
+{
+ char *p;
+ int error;
+
+ p = geom_getxml();
+ if (p == NULL)
+ return (errno);
+ error = geom_xml2tree(gmp, p);
+ free(p);
+ return (error);
+}
+
+static void
+delete_config(struct gconf *gp)
+{
+ struct gconfig *cf;
+
+ for (;;) {
+ cf = LIST_FIRST(gp);
+ if (cf == NULL)
+ return;
+ LIST_REMOVE(cf, lg_config);
+ free(cf->lg_name);
+ free(cf->lg_val);
+ free(cf);
+ }
+}
+
+void
+geom_deletetree(struct gmesh *gmp)
+{
+ struct gclass *cl;
+ struct ggeom *ge;
+ struct gprovider *pr;
+ struct gconsumer *co;
+
+ free(gmp->lg_ident);
+ gmp->lg_ident = NULL;
+ for (;;) {
+ cl = LIST_FIRST(&gmp->lg_class);
+ if (cl == NULL)
+ break;
+ LIST_REMOVE(cl, lg_class);
+ delete_config(&cl->lg_config);
+ if (cl->lg_name) free(cl->lg_name);
+ for (;;) {
+ ge = LIST_FIRST(&cl->lg_geom);
+ if (ge == NULL)
+ break;
+ LIST_REMOVE(ge, lg_geom);
+ delete_config(&ge->lg_config);
+ if (ge->lg_name) free(ge->lg_name);
+ for (;;) {
+ pr = LIST_FIRST(&ge->lg_provider);
+ if (pr == NULL)
+ break;
+ LIST_REMOVE(pr, lg_provider);
+ delete_config(&pr->lg_config);
+ if (pr->lg_name) free(pr->lg_name);
+ if (pr->lg_mode) free(pr->lg_mode);
+ free(pr);
+ }
+ for (;;) {
+ co = LIST_FIRST(&ge->lg_consumer);
+ if (co == NULL)
+ break;
+ LIST_REMOVE(co, lg_consumer);
+ delete_config(&co->lg_config);
+ if (co->lg_mode) free(co->lg_mode);
+ free(co);
+ }
+ free(ge);
+ }
+ free(cl);
+ }
+}
diff --git a/lib/libgeom/libgeom.3 b/lib/libgeom/libgeom.3
new file mode 100644
index 0000000..9172a00
--- /dev/null
+++ b/lib/libgeom/libgeom.3
@@ -0,0 +1,258 @@
+.\" Copyright (c) 2003 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.
+.\" 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd March 7, 2004
+.Dt LIBGEOM 3
+.Os
+.Sh NAME
+.Nm geom_stats_open ,
+.Nm geom_stats_close ,
+.Nm geom_stats_resync ,
+.Nm geom_stats_snapshot_get ,
+.Nm geom_stats_snapshot_free ,
+.Nm geom_stats_snapshot_timestamp ,
+.Nm geom_stats_snapshot_reset ,
+.Nm geom_stats_snapshot_next ,
+.Nm gctl_get_handle ,
+.Nm gctl_ro_param ,
+.Nm gctl_rw_param ,
+.Nm gctl_issue ,
+.Nm gctl_free ,
+.Nm gctl_dump
+.Nd userland API library for kernel GEOM subsystem
+.Sh LIBRARY
+.Lb libgeom
+.Sh SYNOPSIS
+.In libgeom.h
+.Ss "Statistics Functions"
+.Ft void
+.Fn geom_stats_close void
+.Ft int
+.Fn geom_stats_open void
+.Ft void
+.Fn geom_stats_resync void
+.Ft "void *"
+.Fn geom_stats_snapshot_get void
+.Ft void
+.Fn geom_stats_snapshot_free "void *arg"
+.Ft void
+.Fn geom_stats_snapshot_timestamp "void *arg" "struct timespec *tp"
+.Ft void
+.Fn geom_stats_snapshot_reset "void *arg"
+.Ft "struct devstat *"
+.Fn geom_stats_snapshot_next "void *arg"
+.Ss "Control Functions"
+.Ft "struct gctl_req *"
+.Fn gctl_get_handle "void"
+.Ft void
+.Fn gctl_ro_param "struct gctl_req *req" "const char *name" "int len" "const void *value"
+.Ft void
+.Fn gctl_rw_param "struct gctl_req *req" "const char *name" "int len" "void *value"
+.Ft "const char *"
+.Fn gctl_issue "struct gctl_req *req"
+.Ft void
+.Fn gctl_free "struct gctl_req *req"
+.Ft void
+.Fn gctl_dump "struct gctl_req *req" "FILE *f"
+.Sh DESCRIPTION
+The
+.Nm geom
+library contains the official and publicized API for
+interacting with the GEOM subsystem in the kernel.
+.Ss "Statistics Functions"
+GEOM collects statistics data for all consumers and providers, but does
+not perform any normalization or presentation on the raw data, this is
+left as an excercize for user-land presentation utilities.
+.Pp
+The
+.Fn geom_stats_open
+and
+.Fn geom_stats_close
+functions open and close the necessary pathways to access the raw
+statistics information in the kernel.
+These functions are likely to
+open one or more files and cache the file descriptors locally.
+The
+.Fn geom_stats_open
+function returns zero on success, and sets
+.Va errno
+if not.
+.Pp
+The
+.Fn geom_stats_resync
+function will check if more statistics collection points have been
+added in the kernel since
+.Fn geom_stats_open
+or the previous call to
+.Fn geom_stats_resync .
+.Pp
+The
+.Fn geom_stats_snapshot_get
+function
+will acquire a snapshot of the raw data from the kernel, and while a
+reasonable effort is made to make this snapshot as atomic and consistent
+as possible, no guarantee is given that it will actually be so.
+The snapshot must be freed again using the
+.Fn geom_stats_snapshot_free
+function.
+The
+.Fn geom_stats_snapshot_get
+function returns
+.Dv NULL
+on failure.
+.Pp
+The
+.Fn geom_stats_snapshot_timestamp
+function
+provides access to the timestamp acquired in the snapshot.
+.Pp
+The
+.Fn geom_stats_snapshot_reset
+and
+.Fn geom_stats_snapshot_next
+functions
+provide an iterator over the statistics slots in the snapshot.
+The
+.Fn geom_stats_snapshot_reset
+function
+forces the internal pointer in the snapshot back to before the first item.
+The
+.Fn geom_stats_snapshot_next
+function
+returns the next item, and
+.Dv NULL
+if there are no more items in the snapshot.
+.Ss "Control Functions"
+The
+.Fn gctl_*
+functions are used to send requests to GEOM classes.
+In order for a GEOM
+class to actually be able to receive these requests, it must have defined a
+"ctlreq" method.
+.Pp
+A
+.Vt "struct gctl_req *" ,
+obtained with
+.Fn gctl_get_handle ,
+can hold any number of parameters, which must be added to it with
+.Fn gctl_ro_param
+(for read-only parameters) or
+.Fn gctl_rw_param
+(for read/write parameters).
+.Pp
+Both
+.Fn gctl_ro_param
+and
+.Fn gctl_rw_param
+take a string
+.Fa name ,
+which is used to identify the parameter, and a
+.Fa value ,
+which contains, in the read-only case, the data to be passed to the
+GEOM class, or, in the read/write case, a pointer to preallocated memory
+that the GEOM class should fill with the desired data.
+If
+.Fa len
+is negative, it is assumed that
+.Fa value
+is an
+.Tn ASCII
+string and the actual length is taken from the string length of
+.Fa value ;
+otherwise it must hold the size of
+.Fa value .
+.Pp
+A parameter with a
+.Fa name
+containing the string
+.Qq Li class
+is mandatory for each request, and the
+corresponding
+.Fa value
+must hold the name of the GEOM class where the request should be sent to.
+.Pp
+Also mandatory for each request is a parameter with a
+.Fa name
+called
+.Qq Li verb ,
+and the corresponding
+.Fa value
+needs to hold the command string that the GEOM class should react upon.
+.Pp
+Once all desired parameters are filled in, the request must be sent to
+the GEOM subsystem with
+.Fn gctl_issue ,
+which returns
+.Dv NULL
+on success, or a string containing the error message
+on failure.
+.Pp
+After the request is finished, the allocated memory should be released with
+.Fn gctl_free .
+.Pp
+The
+.Fn gctl_dump
+function
+can be used to format the contents of
+.Fa req
+to the open file handle pointed to by
+.Fa f ,
+for debugging purposes.
+.Pp
+Error handling for the control functions is postponed until the call
+to
+.Fn gctl_issue ,
+which returns
+.Dv NULL
+on success, or an error message corresponding to the
+first error which happened.
+.Sh EXAMPLES
+Create a request that is to be sent to the CCD class, and tell
+it to destroy a specific geom:
+.Bd -literal -offset indent
+H = gctl_get_handle();
+gctl_ro_param(H, "verb", -1, "destroy geom");
+gctl_ro_param(H, "class", -1, "CCD");
+sprintf(buf, "ccd%d", ccd);
+gctl_ro_param(H, "geom", -1, buf);
+errstr = gctl_issue(H);
+if (errstr != NULL)
+ err(1, "could not destroy ccd: %s", errstr);
+gctl_free(H);
+.Ed
+.Sh SEE ALSO
+.Pa http://ezine.daemonnews.org/200308/blueprints.html
+.Sh HISTORY
+The
+.Nm geom
+library appeared in
+.Fx 5.1 .
+.Sh AUTHORS
+.An Poul-Henning Kamp Aq phk@FreeBSD.org
+.An Lukas Ertl Aq le@FreeBSD.org
diff --git a/lib/libgeom/libgeom.h b/lib/libgeom/libgeom.h
new file mode 100644
index 0000000..2cdb037
--- /dev/null
+++ b/lib/libgeom/libgeom.h
@@ -0,0 +1,149 @@
+/*-
+ * Copyright (c) 2003 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.
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LIBGEOM_H_
+#define _LIBGEOM_H_
+
+#include <sys/cdefs.h>
+
+#include <sys/queue.h>
+#include <sys/time.h>
+
+#include <geom/geom_ctl.h>
+
+__BEGIN_DECLS
+
+void geom_stats_close(void);
+void geom_stats_resync(void);
+int geom_stats_open(void);
+void *geom_stats_snapshot_get(void);
+void geom_stats_snapshot_free(void *arg);
+void geom_stats_snapshot_timestamp(void *arg, struct timespec *tp);
+void geom_stats_snapshot_reset(void *arg);
+struct devstat *geom_stats_snapshot_next(void *arg);
+
+char *geom_getxml(void);
+
+/* geom_xml2tree.c */
+
+/*
+ * These structs are used to build the tree based on the XML.
+ * they're named as the kernel variant without the first '_'.
+ */
+
+struct gclass;
+struct ggeom;
+struct gconsumer;
+struct gprovider;
+
+LIST_HEAD(gconf, gconfig);
+
+struct gident {
+ void *lg_id;
+ void *lg_ptr;
+ enum { ISCLASS,
+ ISGEOM,
+ ISPROVIDER,
+ ISCONSUMER } lg_what;
+};
+
+struct gmesh {
+ LIST_HEAD(, gclass) lg_class;
+ struct gident *lg_ident;
+};
+
+struct gconfig {
+ LIST_ENTRY(gconfig) lg_config;
+ char *lg_name;
+ char *lg_val;
+};
+
+struct gclass {
+ void *lg_id;
+ char *lg_name;
+ LIST_ENTRY(gclass) lg_class;
+ LIST_HEAD(, ggeom) lg_geom;
+ struct gconf lg_config;
+};
+
+struct ggeom {
+ void *lg_id;
+ struct gclass *lg_class;
+ char *lg_name;
+ u_int lg_rank;
+ LIST_ENTRY(ggeom) lg_geom;
+ LIST_HEAD(, gconsumer) lg_consumer;
+ LIST_HEAD(, gprovider) lg_provider;
+ struct gconf lg_config;
+};
+
+struct gconsumer {
+ void *lg_id;
+ struct ggeom *lg_geom;
+ LIST_ENTRY(gconsumer) lg_consumer;
+ struct gprovider *lg_provider;
+ LIST_ENTRY(gconsumer) lg_consumers;
+ char *lg_mode;
+ struct gconf lg_config;
+};
+
+struct gprovider {
+ void *lg_id;
+ char *lg_name;
+ struct ggeom *lg_geom;
+ LIST_ENTRY(gprovider) lg_provider;
+ LIST_HEAD(, gconsumer) lg_consumers;
+ char *lg_mode;
+ off_t lg_mediasize;
+ u_int lg_sectorsize;
+ struct gconf lg_config;
+};
+
+struct gident * geom_lookupid(struct gmesh *gmp, const void *id);
+int geom_xml2tree(struct gmesh *gmp, char *p);
+int geom_gettree(struct gmesh *gmp);
+void geom_deletetree(struct gmesh *gmp);
+
+/* geom_ctl.c */
+
+struct gctl_req;
+
+#ifdef _STDIO_H_ /* limit #include pollution */
+void gctl_dump(struct gctl_req *req, FILE *f);
+#endif
+void gctl_free(struct gctl_req *req);
+struct gctl_req *gctl_get_handle(void);
+const char *gctl_issue(struct gctl_req *req);
+void gctl_ro_param(struct gctl_req *req, const char *name, int len, const void* val);
+void gctl_rw_param(struct gctl_req *req, const char *name, int len, void* val);
+
+__END_DECLS
+
+#endif /* _LIBGEOM_H_ */
diff --git a/lib/libgpib/Makefile b/lib/libgpib/Makefile
new file mode 100644
index 0000000..e6c06d9
--- /dev/null
+++ b/lib/libgpib/Makefile
@@ -0,0 +1,10 @@
+# $FreeBSD$
+
+LIB= gpib
+SHLIB_MAJOR= 1
+INCS= gpib.h
+INCSDIR= ${INCLUDEDIR}/gpib
+SRCS= ibfoo.c
+WARNS?= 6
+
+.include <bsd.lib.mk>
diff --git a/lib/libgpib/gpib.h b/lib/libgpib/gpib.h
new file mode 100644
index 0000000..d3144b5
--- /dev/null
+++ b/lib/libgpib/gpib.h
@@ -0,0 +1,33 @@
+/*-
+ * 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.
+ *
+ * This file merely redirects to the file in <dev/ieee488/ugpib.h>
+ *
+ * $FreeBSD$
+ */
+
+#include <dev/ieee488/ugpib.h>
+
+#define ibcntl ibcnt
diff --git a/lib/libgpib/ibfoo.c b/lib/libgpib/ibfoo.c
new file mode 100644
index 0000000..e88563a
--- /dev/null
+++ b/lib/libgpib/ibfoo.c
@@ -0,0 +1,647 @@
+/*-
+ * 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.
+ *
+ * This file merely redirects to the file in <dev/ieee488/ugpib.h>
+ *
+ * $FreeBSD$
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <err.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+#include <dev/ieee488/ugpib.h>
+#include <dev/ieee488/ibfoo_int.h>
+
+int ibcnt, iberr, ibsta;
+
+static int fd = -1;
+
+static int
+__ibsubmit(struct ibarg *ap)
+{
+ int i;
+
+ if (fd < 0)
+ fd = open("/dev/gpib0ib", O_RDWR);
+ if (fd < 0)
+ err(1, "Could not open /dev/gpib0ib");
+ i = ioctl(fd, GPIB_IBFOO, ap);
+ if (i)
+ err(1, "GPIB_IBFOO(%d, 0x%x) failed", ap->__ident, ap->__field);
+ ibcnt = ap->__ibcnt;
+ iberr = ap->__iberr;
+ ibsta = ap->__ibsta;
+ return (ap->__retval);
+}
+
+int
+ibask (int handle, int option, int * retval)
+{
+ struct ibarg io;
+
+ io.__ident = __ID_IBASK;
+ io.handle = handle;
+ io.option = option;
+ io.retval = retval;
+ io.__field = __F_HANDLE | __F_OPTION | __F_RETVAL;
+ return (__ibsubmit(&io));
+}
+
+int
+ibbna (int handle, char * bdname)
+{
+ struct ibarg io;
+
+ io.__ident = __ID_IBBNA;
+ io.handle = handle;
+ io.bdname = bdname;
+ io.__field = __F_HANDLE | __F_BDNAME;
+ return (__ibsubmit(&io));
+}
+
+int
+ibcac (int handle, int v)
+{
+ struct ibarg io;
+
+ io.__ident = __ID_IBCAC;
+ io.handle = handle;
+ io.v = v;
+ io.__field = __F_HANDLE | __F_V;
+ return (__ibsubmit(&io));
+}
+
+int
+ibclr (int handle)
+{
+ struct ibarg io;
+
+ io.__ident = __ID_IBCLR;
+ io.handle = handle;
+ io.__field = __F_HANDLE;
+ return (__ibsubmit(&io));
+}
+
+int
+ibcmd (int handle, void * buffer, long cnt)
+{
+ struct ibarg io;
+
+ io.__ident = __ID_IBCMD;
+ io.handle = handle;
+ io.buffer = buffer;
+ io.cnt = cnt;
+ io.__field = __F_HANDLE | __F_BUFFER | __F_CNT;
+ return (__ibsubmit(&io));
+}
+
+int
+ibcmda (int handle, void * buffer, long cnt)
+{
+ struct ibarg io;
+
+ io.__ident = __ID_IBCMDA;
+ io.handle = handle;
+ io.buffer = buffer;
+ io.cnt = cnt;
+ io.__field = __F_HANDLE | __F_BUFFER | __F_CNT;
+ return (__ibsubmit(&io));
+}
+
+int
+ibconfig (int handle, int option, int value)
+{
+ struct ibarg io;
+
+ io.__ident = __ID_IBCONFIG;
+ io.handle = handle;
+ io.option = option;
+ io.value = value;
+ io.__field = __F_HANDLE | __F_OPTION | __F_VALUE;
+ return (__ibsubmit(&io));
+}
+
+int
+ibdev (int boardID, int pad, int sad, int tmo, int eot, int eos)
+{
+ struct ibarg io;
+
+ io.__ident = __ID_IBDEV;
+ io.boardID = boardID;
+ io.pad = pad;
+ io.sad = sad;
+ io.tmo = tmo;
+ io.eot = eot;
+ io.eos = eos;
+ io.__field = __F_BOARDID | __F_PAD | __F_SAD | __F_TMO | __F_EOT | __F_EOS;
+ return (__ibsubmit(&io));
+}
+
+int
+ibdiag (int handle, void * buffer, long cnt)
+{
+ struct ibarg io;
+
+ io.__ident = __ID_IBDIAG;
+ io.handle = handle;
+ io.buffer = buffer;
+ io.cnt = cnt;
+ io.__field = __F_HANDLE | __F_BUFFER | __F_CNT;
+ return (__ibsubmit(&io));
+}
+
+int
+ibdma (int handle, int v)
+{
+ struct ibarg io;
+
+ io.__ident = __ID_IBDMA;
+ io.handle = handle;
+ io.v = v;
+ io.__field = __F_HANDLE | __F_V;
+ return (__ibsubmit(&io));
+}
+
+int
+ibeos (int handle, int eos)
+{
+ struct ibarg io;
+
+ io.__ident = __ID_IBEOS;
+ io.handle = handle;
+ io.eos = eos;
+ io.__field = __F_HANDLE | __F_EOS;
+ return (__ibsubmit(&io));
+}
+
+int
+ibeot (int handle, int eot)
+{
+ struct ibarg io;
+
+ io.__ident = __ID_IBEOT;
+ io.handle = handle;
+ io.eot = eot;
+ io.__field = __F_HANDLE | __F_EOT;
+ return (__ibsubmit(&io));
+}
+
+int
+ibevent (int handle, short * event)
+{
+ struct ibarg io;
+
+ io.__ident = __ID_IBEVENT;
+ io.handle = handle;
+ io.event = event;
+ io.__field = __F_HANDLE | __F_EVENT;
+ return (__ibsubmit(&io));
+}
+
+int
+ibfind (char * bdname)
+{
+ struct ibarg io;
+
+ io.__ident = __ID_IBFIND;
+ io.bdname = bdname;
+ io.__field = __F_BDNAME;
+ return (__ibsubmit(&io));
+}
+
+int
+ibgts (int handle, int v)
+{
+ struct ibarg io;
+
+ io.__ident = __ID_IBGTS;
+ io.handle = handle;
+ io.v = v;
+ io.__field = __F_HANDLE | __F_V;
+ return (__ibsubmit(&io));
+}
+
+int
+ibist (int handle, int v)
+{
+ struct ibarg io;
+
+ io.__ident = __ID_IBIST;
+ io.handle = handle;
+ io.v = v;
+ io.__field = __F_HANDLE | __F_V;
+ return (__ibsubmit(&io));
+}
+
+int
+iblines (int handle, short * lines)
+{
+ struct ibarg io;
+
+ io.__ident = __ID_IBLINES;
+ io.handle = handle;
+ io.lines = lines;
+ io.__field = __F_HANDLE | __F_LINES;
+ return (__ibsubmit(&io));
+}
+
+int
+ibllo (int handle)
+{
+ struct ibarg io;
+
+ io.__ident = __ID_IBLLO;
+ io.handle = handle;
+ io.__field = __F_HANDLE;
+ return (__ibsubmit(&io));
+}
+
+int
+ibln (int handle, int padval, int sadval, short * listenflag)
+{
+ struct ibarg io;
+
+ io.__ident = __ID_IBLN;
+ io.handle = handle;
+ io.padval = padval;
+ io.sadval = sadval;
+ io.listenflag = listenflag;
+ io.__field = __F_HANDLE | __F_PADVAL | __F_SADVAL | __F_LISTENFLAG;
+ return (__ibsubmit(&io));
+}
+
+int
+ibloc (int handle)
+{
+ struct ibarg io;
+
+ io.__ident = __ID_IBLOC;
+ io.handle = handle;
+ io.__field = __F_HANDLE;
+ return (__ibsubmit(&io));
+}
+
+int
+ibonl (int handle, int v)
+{
+ struct ibarg io;
+
+ io.__ident = __ID_IBONL;
+ io.handle = handle;
+ io.v = v;
+ io.__field = __F_HANDLE | __F_V;
+ return (__ibsubmit(&io));
+}
+
+int
+ibpad (int handle, int v)
+{
+ struct ibarg io;
+
+ io.__ident = __ID_IBPAD;
+ io.handle = handle;
+ io.v = v;
+ io.__field = __F_HANDLE | __F_V;
+ return (__ibsubmit(&io));
+}
+
+int
+ibpct (int handle)
+{
+ struct ibarg io;
+
+ io.__ident = __ID_IBPCT;
+ io.handle = handle;
+ io.__field = __F_HANDLE;
+ return (__ibsubmit(&io));
+}
+
+int
+ibpoke (int handle, int option, int value)
+{
+ struct ibarg io;
+
+ io.__ident = __ID_IBPOKE;
+ io.handle = handle;
+ io.option = option;
+ io.value = value;
+ io.__field = __F_HANDLE | __F_OPTION | __F_VALUE;
+ return (__ibsubmit(&io));
+}
+
+int
+ibppc (int handle, int v)
+{
+ struct ibarg io;
+
+ io.__ident = __ID_IBPPC;
+ io.handle = handle;
+ io.v = v;
+ io.__field = __F_HANDLE | __F_V;
+ return (__ibsubmit(&io));
+}
+
+int
+ibrd (int handle, void * buffer, long cnt)
+{
+ struct ibarg io;
+
+ io.__ident = __ID_IBRD;
+ io.handle = handle;
+ io.buffer = buffer;
+ io.cnt = cnt;
+ io.__field = __F_HANDLE | __F_BUFFER | __F_CNT;
+ return (__ibsubmit(&io));
+}
+
+int
+ibrda (int handle, void * buffer, long cnt)
+{
+ struct ibarg io;
+
+ io.__ident = __ID_IBRDA;
+ io.handle = handle;
+ io.buffer = buffer;
+ io.cnt = cnt;
+ io.__field = __F_HANDLE | __F_BUFFER | __F_CNT;
+ return (__ibsubmit(&io));
+}
+
+int
+ibrdf (int handle, char * flname)
+{
+ struct ibarg io;
+
+ io.__ident = __ID_IBRDF;
+ io.handle = handle;
+ io.flname = flname;
+ io.__field = __F_HANDLE | __F_FLNAME;
+ return (__ibsubmit(&io));
+}
+
+int
+ibrdkey (int handle, void * buffer, int cnt)
+{
+ struct ibarg io;
+
+ io.__ident = __ID_IBRDKEY;
+ io.handle = handle;
+ io.buffer = buffer;
+ io.cnt = cnt;
+ io.__field = __F_HANDLE | __F_BUFFER | __F_CNT;
+ return (__ibsubmit(&io));
+}
+
+int
+ibrpp (int handle, char * ppr)
+{
+ struct ibarg io;
+
+ io.__ident = __ID_IBRPP;
+ io.handle = handle;
+ io.ppr = ppr;
+ io.__field = __F_HANDLE | __F_PPR;
+ return (__ibsubmit(&io));
+}
+
+int
+ibrsc (int handle, int v)
+{
+ struct ibarg io;
+
+ io.__ident = __ID_IBRSC;
+ io.handle = handle;
+ io.v = v;
+ io.__field = __F_HANDLE | __F_V;
+ return (__ibsubmit(&io));
+}
+
+int
+ibrsp (int handle, char * spr)
+{
+ struct ibarg io;
+
+ io.__ident = __ID_IBRSP;
+ io.handle = handle;
+ io.spr = spr;
+ io.__field = __F_HANDLE | __F_SPR;
+ return (__ibsubmit(&io));
+}
+
+int
+ibrsv (int handle, int v)
+{
+ struct ibarg io;
+
+ io.__ident = __ID_IBRSV;
+ io.handle = handle;
+ io.v = v;
+ io.__field = __F_HANDLE | __F_V;
+ return (__ibsubmit(&io));
+}
+
+int
+ibsad (int handle, int sad)
+{
+ struct ibarg io;
+
+ io.__ident = __ID_IBSAD;
+ io.handle = handle;
+ io.sad = sad;
+ io.__field = __F_HANDLE | __F_SAD;
+ return (__ibsubmit(&io));
+}
+
+int
+ibsgnl (int handle, int v)
+{
+ struct ibarg io;
+
+ io.__ident = __ID_IBSGNL;
+ io.handle = handle;
+ io.v = v;
+ io.__field = __F_HANDLE | __F_V;
+ return (__ibsubmit(&io));
+}
+
+int
+ibsic (int handle)
+{
+ struct ibarg io;
+
+ io.__ident = __ID_IBSIC;
+ io.handle = handle;
+ io.__field = __F_HANDLE;
+ return (__ibsubmit(&io));
+}
+
+int
+ibsre (int handle, int v)
+{
+ struct ibarg io;
+
+ io.__ident = __ID_IBSRE;
+ io.handle = handle;
+ io.v = v;
+ io.__field = __F_HANDLE | __F_V;
+ return (__ibsubmit(&io));
+}
+
+int
+ibsrq (ibsrq_t * func)
+{
+ struct ibarg io;
+
+ io.__ident = __ID_IBSRQ;
+ io.func = func;
+ io.__field = __F_FUNC;
+ return (__ibsubmit(&io));
+}
+
+int
+ibstop (int handle)
+{
+ struct ibarg io;
+
+ io.__ident = __ID_IBSTOP;
+ io.handle = handle;
+ io.__field = __F_HANDLE;
+ return (__ibsubmit(&io));
+}
+
+int
+ibtmo (int handle, int tmo)
+{
+ struct ibarg io;
+
+ io.__ident = __ID_IBTMO;
+ io.handle = handle;
+ io.tmo = tmo;
+ io.__field = __F_HANDLE | __F_TMO;
+ return (__ibsubmit(&io));
+}
+
+int
+ibtrap (int mask, int mode)
+{
+ struct ibarg io;
+
+ io.__ident = __ID_IBTRAP;
+ io.mask = mask;
+ io.mode = mode;
+ io.__field = __F_MASK | __F_MODE;
+ return (__ibsubmit(&io));
+}
+
+int
+ibtrg (int handle)
+{
+ struct ibarg io;
+
+ io.__ident = __ID_IBTRG;
+ io.handle = handle;
+ io.__field = __F_HANDLE;
+ return (__ibsubmit(&io));
+}
+
+int
+ibwait (int handle, int mask)
+{
+ struct ibarg io;
+
+ io.__ident = __ID_IBWAIT;
+ io.handle = handle;
+ io.mask = mask;
+ io.__field = __F_HANDLE | __F_MASK;
+ return (__ibsubmit(&io));
+}
+
+int
+ibwrt (int handle, const void *buffer, long cnt)
+{
+ struct ibarg io;
+
+ io.__ident = __ID_IBWRT;
+ io.handle = handle;
+ io.buffer = __DECONST(void *, buffer);
+ io.cnt = cnt;
+ io.__field = __F_HANDLE | __F_BUFFER | __F_CNT;
+ return (__ibsubmit(&io));
+}
+
+int
+ibwrta (int handle, const void * buffer, long cnt)
+{
+ struct ibarg io;
+
+ io.__ident = __ID_IBWRTA;
+ io.handle = handle;
+ io.buffer = __DECONST(void *, buffer);
+ io.cnt = cnt;
+ io.__field = __F_HANDLE | __F_BUFFER | __F_CNT;
+ return (__ibsubmit(&io));
+}
+
+int
+ibwrtf (int handle, const char *flname)
+{
+ struct ibarg io;
+
+ io.__ident = __ID_IBWRTF;
+ io.handle = handle;
+ io.flname = __DECONST(void *, flname);
+ io.__field = __F_HANDLE | __F_FLNAME;
+ return (__ibsubmit(&io));
+}
+
+int
+ibwrtkey (int handle, const void *buffer, int cnt)
+{
+ struct ibarg io;
+
+ io.__ident = __ID_IBWRTKEY;
+ io.handle = handle;
+ io.buffer = __DECONST(void *, buffer);
+ io.cnt = cnt;
+ io.__field = __F_HANDLE | __F_BUFFER | __F_CNT;
+ return (__ibsubmit(&io));
+}
+
+int
+ibxtrc (int handle, void * buffer, long cnt)
+{
+ struct ibarg io;
+
+ io.__ident = __ID_IBXTRC;
+ io.handle = handle;
+ io.buffer = buffer;
+ io.cnt = cnt;
+ io.__field = __F_HANDLE | __F_BUFFER | __F_CNT;
+ return (__ibsubmit(&io));
+}
+
diff --git a/lib/libgssapi/Makefile b/lib/libgssapi/Makefile
new file mode 100644
index 0000000..7cec126
--- /dev/null
+++ b/lib/libgssapi/Makefile
@@ -0,0 +1,95 @@
+# $FreeBSD$
+
+LIB= gssapi
+SHLIB_MAJOR= 8
+
+SRCS=
+SRCS+= gss_utils.c
+SRCS+= gss_mech_switch.c
+SRCS+= gss_names.c
+SRCS+= gss_acquire_cred.c
+SRCS+= gss_release_cred.c
+SRCS+= gss_init_sec_context.c
+SRCS+= gss_accept_sec_context.c
+SRCS+= gss_process_context_token.c
+SRCS+= gss_delete_sec_context.c
+SRCS+= gss_context_time.c
+SRCS+= gss_get_mic.c
+SRCS+= gss_verify_mic.c
+SRCS+= gss_wrap.c
+SRCS+= gss_unwrap.c
+SRCS+= gss_display_status.c
+SRCS+= gss_indicate_mechs.c
+SRCS+= gss_compare_name.c
+SRCS+= gss_display_name.c
+SRCS+= gss_import_name.c
+SRCS+= gss_export_name.c
+SRCS+= gss_release_name.c
+SRCS+= gss_inquire_cred.c
+SRCS+= gss_inquire_context.c
+SRCS+= gss_wrap_size_limit.c
+SRCS+= gss_add_cred.c
+SRCS+= gss_inquire_cred_by_mech.c
+SRCS+= gss_export_sec_context.c
+SRCS+= gss_import_sec_context.c
+SRCS+= gss_inquire_names_for_mech.c
+SRCS+= gss_inquire_mechs_for_name.c
+SRCS+= gss_canonicalize_name.c
+SRCS+= gss_duplicate_name.c
+SRCS+= gss_sign.c
+SRCS+= gss_verify.c
+SRCS+= gss_seal.c
+SRCS+= gss_unseal.c
+SRCS+= gss_krb5.c
+SRCS+= gss_create_empty_oid_set.c
+SRCS+= gss_add_oid_set_member.c
+SRCS+= gss_test_oid_set_member.c
+SRCS+= gss_release_oid_set.c
+SRCS+= gss_release_buffer.c
+
+MAN=
+MAN+= gssapi.3
+MAN+= gss_accept_sec_context.3
+MAN+= gss_acquire_cred.3
+MAN+= gss_add_cred.3
+MAN+= gss_add_oid_set_member.3
+MAN+= gss_canonicalize_name.3
+MAN+= gss_compare_name.3
+MAN+= gss_context_time.3
+MAN+= gss_create_empty_oid_set.3
+MAN+= gss_delete_sec_context.3
+MAN+= gss_display_name.3
+MAN+= gss_display_status.3
+MAN+= gss_duplicate_name.3
+MAN+= gss_export_name.3
+MAN+= gss_export_sec_context.3
+MAN+= gss_get_mic.3
+MAN+= gss_import_name.3
+MAN+= gss_import_sec_context.3
+MAN+= gss_indicate_mechs.3
+MAN+= gss_init_sec_context.3
+MAN+= gss_inquire_context.3
+MAN+= gss_inquire_cred.3
+MAN+= gss_inquire_cred_by_mech.3
+MAN+= gss_inquire_mechs_for_name.3
+MAN+= gss_inquire_names_for_mech.3
+MAN+= gss_process_context_token.3
+MAN+= gss_release_buffer.3
+MAN+= gss_release_cred.3
+MAN+= gss_release_name.3
+MAN+= gss_release_oid_set.3
+MAN+= gss_test_oid_set_member.3
+MAN+= gss_unwrap.3
+MAN+= gss_verify_mic.3
+MAN+= gss_wrap.3
+MAN+= gss_wrap_size_limit.3
+MAN+= mech.5
+
+MLINKS=
+MLINKS+= gss_get_mic.3 gss_sign.3
+MLINKS+= gss_unwrap.3 gss_unseal.3
+MLINKS+= gss_verify_mic.3 gss_verify.3
+MLINKS+= gss_wrap.3 gss_seal.3
+MLINKS+= mech.5 qop.5
+
+.include <bsd.lib.mk>
diff --git a/lib/libgssapi/context.h b/lib/libgssapi/context.h
new file mode 100644
index 0000000..403b390
--- /dev/null
+++ b/lib/libgssapi/context.h
@@ -0,0 +1,32 @@
+/*-
+ * Copyright (c) 2005 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$
+ */
+
+struct _gss_context {
+ struct _gss_mech_switch *gc_mech;
+ gss_ctx_id_t gc_ctx;
+};
diff --git a/lib/libgssapi/cred.h b/lib/libgssapi/cred.h
new file mode 100644
index 0000000..6301b89
--- /dev/null
+++ b/lib/libgssapi/cred.h
@@ -0,0 +1,43 @@
+/*-
+ * Copyright (c) 2005 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 <sys/queue.h>
+
+struct _gss_mechanism_cred {
+ SLIST_ENTRY(_gss_mechanism_cred) gmc_link;
+ struct _gss_mech_switch *gmc_mech; /* mechanism ops for MC */
+ gss_OID gmc_mech_oid; /* mechanism oid for MC */
+ gss_cred_id_t gmc_cred; /* underlying MC */
+};
+SLIST_HEAD(_gss_mechanism_cred_list, _gss_mechanism_cred);
+
+struct _gss_cred {
+ gss_cred_usage_t gc_usage;
+ struct _gss_mechanism_cred_list gc_mc;
+};
+
diff --git a/lib/libgssapi/gss_accept_sec_context.3 b/lib/libgssapi/gss_accept_sec_context.3
new file mode 100644
index 0000000..43c9576
--- /dev/null
+++ b/lib/libgssapi/gss_accept_sec_context.3
@@ -0,0 +1,484 @@
+.\" -*- nroff -*-
+.\"
+.\" Copyright (c) 2005 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$
+.\"
+.\" The following commands are required for all man pages.
+.Dd November 12, 2005
+.Os
+.Dt GSS_ACCEPT_SEC_CONTEXT 3 PRM
+.Sh NAME
+.Nm gss_accept_sec_context
+.Nd Accept a security context initiated by a peer application
+.\" This next command is for sections 2 and 3 only.
+.\" .Sh LIBRARY
+.Sh SYNOPSIS
+.In "gssapi/gssapi.h"
+.Ft OM_uint32
+.Fo gss_accept_sec_context
+.Fa "OM_uint32 *minor_status
+.Fa "gss_ctx_id_t *context_handle"
+.Fa "const gss_cred_id_t acceptor_cred_handle"
+.Fa "const gss_buffer_t input_token_buffer"
+.Fa "const gss_channel_bindings_t input_chan_bindings"
+.Fa "const gss_name_t *src_name"
+.Fa "gss_OID *mech_type"
+.Fa "gss_buffer_t output_token"
+.Fa "OM_uint32 *ret_flags"
+.Fa "OM_uint32 *time_rec"
+.Fa "gss_cred_id_t *delegated_cred_handle"
+.Fc
+.Sh DESCRIPTION
+Allows a remotely initiated security context between the application
+and a remote peer to be established. The routine may return a
+.Fa output_token
+which should be transferred to the peer application,
+where the peer application will present it to
+.Xr gss_init_sec_context 3 .
+If no token need be sent,
+.Fn gss_accept_sec_context
+will indicate this
+by setting the length field of the
+.Fa output_token
+argument to zero.
+To complete the context establishment, one or more reply tokens may be
+required from the peer application; if so,
+.Fn gss_accept_sec_context
+will return a status flag of
+.Dv GSS_S_CONTINUE_NEEDED , in which case it
+should be called again when the reply token is received from the peer
+application, passing the token to
+.Fn gss_accept_sec_context
+via the
+.Fa input_token
+parameters.
+.Pp
+Portable applications should be constructed to use the token length
+and return status to determine whether a token needs to be sent or
+waited for. Thus a typical portable caller should always invoke
+.Fn gss_accept_sec_context
+within a loop:
+.Bd -literal
+gss_ctx_id_t context_hdl = GSS_C_NO_CONTEXT;
+
+do {
+ receive_token_from_peer(input_token);
+ maj_stat = gss_accept_sec_context(&min_stat,
+ &context_hdl,
+ cred_hdl,
+ input_token,
+ input_bindings,
+ &client_name,
+ &mech_type,
+ output_token,
+ &ret_flags,
+ &time_rec,
+ &deleg_cred);
+ if (GSS_ERROR(maj_stat)) {
+ report_error(maj_stat, min_stat);
+ };
+ if (output_token->length != 0) {
+ send_token_to_peer(output_token);
+
+ gss_release_buffer(&min_stat, output_token);
+ };
+ if (GSS_ERROR(maj_stat)) {
+ if (context_hdl != GSS_C_NO_CONTEXT)
+ gss_delete_sec_context(&min_stat,
+ &context_hdl,
+ GSS_C_NO_BUFFER);
+ break;
+ };
+} while (maj_stat & GSS_S_CONTINUE_NEEDED);
+.Ed
+.Pp
+Whenever the routine returns a major status that includes the value
+.Dv GSS_S_CONTINUE_NEEDED , the context is not fully established and the
+following restrictions apply to the output parameters:
+.Pp
+The value returned via the
+.Fa time_rec
+parameter is undefined Unless the
+accompanying
+.Fa ret_flags
+parameter contains the bit
+.Dv GSS_C_PROT_READY_FLAG , indicating that per-message services may be
+applied in advance of a successful completion status, the value
+returned via the
+.Fa mech_type
+parameter may be undefined until the
+routine returns a major status value of
+.Dv GSS_S_COMPLETE .
+.Pp
+The values of the
+.Dv GSS_C_DELEG_FLAG ,
+.Dv GSS_C_MUTUAL_FLAG ,
+.Dv GSS_C_REPLAY_FLAG ,
+.Dv GSS_C_SEQUENCE_FLAG ,
+.Dv GSS_C_CONF_FLAG ,
+.Dv GSS_C_INTEG_FLAG
+and
+.Dv GSS_C_ANON_FLAG bits returned
+via the
+.Fa ret_flags
+parameter should contain the values that the
+implementation expects would be valid if context establishment were
+to succeed.
+.Pp
+The values of the
+.Dv GSS_C_PROT_READY_FLAG
+and
+.Dv GSS_C_TRANS_FLAG bits
+within
+.Fa ret_flags
+should indicate the actual state at the time
+.Fn gss_accept_sec_context
+returns, whether or not the context is fully established.
+.Pp
+Although this requires that GSS-API implementations set the
+.Dv GSS_C_PROT_READY_FLAG
+in the final
+.Fa ret_flags
+returned to a caller
+(i.e. when accompanied by a
+.Dv GSS_S_COMPLETE
+status code), applications
+should not rely on this behavior as the flag was not defined in
+Version 1 of the GSS-API. Instead, applications should be prepared to
+use per-message services after a successful context establishment,
+according to the
+.Dv GSS_C_INTEG_FLAG
+and
+.Dv GSS_C_CONF_FLAG values.
+.Pp
+All other bits within the
+.Fa ret_flags
+argument should be set to zero.
+While the routine returns
+.Dv GSS_S_CONTINUE_NEEDED , the values returned
+via the
+.Fa ret_flags
+argument indicate the services that the
+implementation expects to be available from the established context.
+.Pp
+If the initial call of
+.Fn gss_accept_sec_context
+fails, the
+implementation should not create a context object, and should leave
+the value of the context_handle parameter set to
+.Dv GSS_C_NO_CONTEXT to
+indicate this. In the event of a failure on a subsequent call, the
+implementation is permitted to delete the "half-built" security
+context (in which case it should set the
+.Fa context_handle
+parameter to
+.Dv GSS_C_NO_CONTEXT ), but the preferred behavior is to leave the
+security context (and the context_handle parameter) untouched for the
+application to delete (using
+.Xr gss_delete_sec_context 3 ).
+.Pp
+During context establishment, the informational status bits
+.Dv GSS_S_OLD_TOKEN
+and
+.Dv GSS_S_DUPLICATE_TOKEN
+indicate fatal errors, and
+GSS-API mechanisms should always return them in association with a
+routine error of
+.Dv GSS_S_FAILURE . This requirement for pairing did not
+exist in version 1 of the GSS-API specification, so applications that
+wish to run over version 1 implementations must special-case these
+codes.
+.Sh PARAMETERS
+.Bl -tag
+.It context_handle
+Context handle for new context.
+Supply
+.Dv GSS_C_NO_CONTEXT for first
+call; use value returned in subsequent calls.
+Once
+.Fn gss_accept_sec_context
+has returned a
+value via this parameter, resources have been
+assigned to the corresponding context, and must
+be freed by the application after use with a
+call to
+.Xr gss_delete_sec_context 3 .
+.It acceptor_cred_handle
+Credential handle claimed by context acceptor.
+Specify
+.Dv GSS_C_NO_CREDENTIAL to accept the context as a
+default principal.
+If
+.Dv GSS_C_NO_CREDENTIAL is
+specified, but no default acceptor principal is
+defined,
+.Dv GSS_S_NO_CRED will be returned.
+.It input_token_buffer
+Token obtained from remote application.
+.It input_chan_bindings
+Application-specified bindings.
+Allows application to securely bind channel identification information
+to the security context.
+If channel bindings are not used, specify
+.Dv GSS_C_NO_CHANNEL_BINDINGS .
+.It src_name
+Authenticated name of context initiator.
+After use, this name should be deallocated by passing it to
+.Xr gss_release_name 3 .
+If not required, specify
+.Dv NULL .
+.It mech_type
+Security mechanism used.
+The returned OID value will be a pointer into static storage,
+and should be treated as read-only by the caller
+(in particular, it does not need to be freed).
+If not required, specify
+.Dv NULL .
+.It output_token
+Token to be passed to peer application.
+If the length field of the returned token buffer is 0,
+then no token need be passed to the peer application.
+If a non-zero length field is returned,
+the associated storage must be freed after use by the
+application with a call to
+.Xr gss_release_buffer 3 .
+.It ret_flags
+Contains various independent flags,
+each of which indicates that the context supports a specific service option.
+If not needed, specify
+.Dv NULL .
+Symbolic names are provided for each flag,
+and the symbolic names corresponding to the required flags should be
+logically-ANDed with the
+.Fa ret_flags
+value to test whether a given option is supported by the context.
+The flags are:
+.Bl -tag -width "WW"
+.It GSS_C_DELEG_FLAG
+.Bl -tag -width "False"
+.It True
+Delegated credentials are available via the delegated_cred_handle parameter
+.It False
+No credentials were delegated
+.El
+.It GSS_C_MUTUAL_FLAG
+.Bl -tag -width "False"
+.It True
+Remote peer asked for mutual authentication
+.It False
+Remote peer did not ask for mutual authentication
+.El
+.It GSS_C_REPLAY_FLAG
+.Bl -tag -width "False"
+.It True
+Replay of protected messages will be detected
+.It False
+Replayed messages will not be detected
+.El
+.It GSS_C_SEQUENCE_FLAG
+.Bl -tag -width "False"
+.It True
+Out-of-sequence protected messages will be detected
+.It False
+Out-of-sequence messages will not be detected
+.El
+.It GSS_C_CONF_FLAG
+.Bl -tag -width "False"
+.It True
+Confidentiality service may be invoked by calling the
+.Xr gss_wrap 3
+routine
+.It False
+No confidentiality service (via
+.Xr gss_wrap 3 )
+available.
+.Xr gss_wrap 3
+will provide message encapsulation,
+data-origin authentication and integrity services only.
+.El
+.It GSS_C_INTEG_FLAG
+.Bl -tag -width "False"
+.It True
+Integrity service may be invoked by calling either
+.Xr gss_get_mic 3
+or
+.Xr gss_wrap 3
+routines.
+.It False
+Per-message integrity service unavailable.
+.El
+.It GSS_C_ANON_FLAG
+.Bl -tag -width "False"
+.It True
+The initiator does not wish to be authenticated; the
+.Fa src_name
+parameter (if requested) contains an anonymous internal name.
+.It False
+The initiator has been authenticated normally.
+.El
+.It GSS_C_PROT_READY_FLAG
+.Bl -tag -width "False"
+.It True
+Protection services (as specified by the states of the
+.Dv GSS_C_CONF_FLAG
+and
+.Dv GSS_C_INTEG_FLAG )
+are available if the accompanying major status return value is either
+.Dv GSS_S_COMPLETE
+or
+.Dv GSS_S_CONTINUE_NEEDED.
+.It False
+Protection services (as specified by the states of the
+.Dv GSS_C_CONF_FLAG
+and
+.Dv GSS_C_INTEG_FLAG )
+are available only if the accompanying major status return value is
+.Dv GSS_S_COMPLETE .
+.El
+.It GSS_C_TRANS_FLAG
+.Bl -tag -width "False"
+.It True
+The resultant security context may be transferred to other processes
+via a call to
+.Xr gss_export_sec_context 3 .
+.It False
+The security context is not transferable.
+.El
+.El
+.Pp
+All other bits should be set to zero.
+.It time_rec
+Number of seconds for which the context will remain valid.
+Specify
+.Dv NULL
+if not required.
+.It delegated_cred_handle
+Credential
+handle for credentials received from context initiator.
+Only valid if
+.Dv GSS_C_DELEG_FLAG
+in
+.Fa ret_flags
+is true,
+in which case an explicit credential handle
+(i.e. not
+.Dv GSS_C_NO_CREDENTIAL )
+will be returned; if false,
+.Fn gss_accept_context
+will set this parameter to
+.Dv GSS_C_NO_CREDENTIAL .
+If a credential handle is returned,
+the associated resources must be released by the application after use
+with a call to
+.Xr gss_release_cred 3 .
+Specify
+.Dv NULL if not required.
+.It minor_status
+Mechanism specific status code.
+.El
+.Sh RETURN VALUES
+.Bl -tag
+.It GSS_S_CONTINUE_NEEDED
+Indicates that a token from the peer application is required to
+complete the context,
+and that gss_accept_sec_context must be called again with that token.
+.It GSS_S_DEFECTIVE_TOKEN
+Indicates that consistency checks performed on the input_token failed.
+.It GSS_S_DEFECTIVE_CREDENTIAL
+Indicates that consistency checks performed on the credential failed.
+.It GSS_S_NO_CRED
+The supplied credentials were not valid for context acceptance,
+or the credential handle did not reference any credentials.
+.It GSS_S_CREDENTIALS_EXPIRED
+The referenced credentials have expired.
+.It GSS_S_BAD_BINDINGS
+The input_token contains different channel bindings to those specified via the
+input_chan_bindings parameter.
+.It GSS_S_NO_CONTEXT
+Indicates that the supplied context handle did not refer to a valid context.
+.It GSS_S_BAD_SIG
+The input_token contains an invalid MIC.
+.It GSS_S_OLD_TOKEN
+The input_token was too old.
+This is a fatal error during context establishment.
+.It GSS_S_DUPLICATE_TOKEN
+The input_token is valid,
+but is a duplicate of a token already processed.
+This is a fatal error during context establishment.
+.It GSS_S_BAD_MECH
+The received token specified a mechanism that is not supported by
+the implementation or the provided credential.
+.El
+.Sh SEE ALSO
+.Xr gss_delete_sec_context 3 ,
+.Xr gss_export_sec_context 3 ,
+.Xr gss_get_mic 3 ,
+.Xr gss_init_sec_context 3 ,
+.Xr gss_release_buffer 3 ,
+.Xr gss_release_cred 3 ,
+.Xr gss_release_name 3 ,
+.Xr gss_wrap 3
+.Sh STANDARDS
+.Bl -tag
+.It RFC 2743
+Generic Security Service Application Program Interface Version 2, Update 1
+.It RFC 2744
+Generic Security Service API Version 2 : C-bindings
+.El
+.\" .Sh HISTORY
+.Sh HISTORY
+The
+.Nm
+manual page example first appeared in
+.Fx 7.0 .
+.Sh AUTHORS
+John Wray, Iris Associates
+.Sh COPYRIGHT
+Copyright (C) The Internet Society (2000). All Rights Reserved.
+.Pp
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it
+or assist in its implementation may be prepared, copied, published
+and distributed, in whole or in part, without restriction of any
+kind, provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing
+the copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of
+developing Internet standards in which case the procedures for
+copyrights defined in the Internet Standards process must be
+followed, or as required to translate it into languages other than
+English.
+.Pp
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+.Pp
+This document and the information contained herein is provided on an
+"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/lib/libgssapi/gss_accept_sec_context.c b/lib/libgssapi/gss_accept_sec_context.c
new file mode 100644
index 0000000..9bc57ca
--- /dev/null
+++ b/lib/libgssapi/gss_accept_sec_context.c
@@ -0,0 +1,221 @@
+/*-
+ * Copyright (c) 2005 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 <gssapi/gssapi.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "mech_switch.h"
+#include "context.h"
+#include "cred.h"
+#include "name.h"
+
+OM_uint32 gss_accept_sec_context(OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handle,
+ const gss_cred_id_t acceptor_cred_handle,
+ const gss_buffer_t input_token,
+ const gss_channel_bindings_t input_chan_bindings,
+ gss_name_t *src_name,
+ gss_OID *mech_type,
+ gss_buffer_t output_token,
+ OM_uint32 *ret_flags,
+ OM_uint32 *time_rec,
+ gss_cred_id_t *delegated_cred_handle)
+{
+ OM_uint32 major_status;
+ struct _gss_mech_switch *m;
+ struct _gss_context *ctx = (struct _gss_context *) *context_handle;
+ struct _gss_cred *cred = (struct _gss_cred *) acceptor_cred_handle;
+ struct _gss_mechanism_cred *mc;
+ gss_cred_id_t acceptor_mc, delegated_mc;
+ gss_name_t src_mn;
+ int allocated_ctx;
+
+ *minor_status = 0;
+ if (src_name) *src_name = 0;
+ if (mech_type) *mech_type = 0;
+ if (ret_flags) *ret_flags = 0;
+ if (time_rec) *time_rec = 0;
+ if (delegated_cred_handle) *delegated_cred_handle = 0;
+ output_token->length = 0;
+ output_token->value = 0;
+
+ /*
+ * If this is the first call (*context_handle is NULL), we must
+ * parse the input token to figure out the mechanism to use.
+ */
+ if (*context_handle == GSS_C_NO_CONTEXT) {
+ unsigned char *p = input_token->value;
+ size_t len = input_token->length;
+ size_t a, b;
+ gss_OID_desc mech_oid;
+
+ /*
+ * Token must start with [APPLICATION 0] SEQUENCE.
+ */
+ if (len == 0 || *p != 0x60)
+ return (GSS_S_DEFECTIVE_TOKEN);
+ p++;
+ len--;
+
+ /*
+ * Decode the length and make sure it agrees with the
+ * token length.
+ */
+ if (len == 0)
+ return (GSS_S_DEFECTIVE_TOKEN);
+ if ((*p & 0x80) == 0) {
+ a = *p;
+ p++;
+ len--;
+ } else {
+ b = *p & 0x7f;
+ p++;
+ len--;
+ if (len < b)
+ return (GSS_S_DEFECTIVE_TOKEN);
+ a = 0;
+ while (b) {
+ a = (a << 8) | *p;
+ p++;
+ len--;
+ b--;
+ }
+ }
+ if (a != len)
+ return (GSS_S_DEFECTIVE_TOKEN);
+
+ /*
+ * Decode the OID for the mechanism. Simplify life by
+ * assuming that the OID length is less than 128 bytes.
+ */
+ if (len < 2 || *p != 0x06)
+ return (GSS_S_DEFECTIVE_TOKEN);
+ if ((p[1] & 0x80) || p[1] > (len - 2))
+ return (GSS_S_DEFECTIVE_TOKEN);
+ mech_oid.length = p[1];
+ p += 2;
+ len -= 2;
+ mech_oid.elements = p;
+
+ /*
+ * Now that we have a mechanism, we can find the
+ * implementation.
+ */
+ ctx = malloc(sizeof(struct _gss_context));
+ if (!ctx) {
+ *minor_status = ENOMEM;
+ return (GSS_S_DEFECTIVE_TOKEN);
+ }
+ memset(ctx, 0, sizeof(struct _gss_context));
+ m = ctx->gc_mech = _gss_find_mech_switch(&mech_oid);
+ if (!m) {
+ free(ctx);
+ return (GSS_S_BAD_MECH);
+ }
+ allocated_ctx = 1;
+ } else {
+ m = ctx->gc_mech;
+ allocated_ctx = 0;
+ }
+
+ if (cred) {
+ SLIST_FOREACH(mc, &cred->gc_mc, gmc_link)
+ if (mc->gmc_mech == m)
+ break;
+ if (!mc)
+ return (GSS_S_BAD_MECH);
+ acceptor_mc = mc->gmc_cred;
+ } else {
+ acceptor_mc = GSS_C_NO_CREDENTIAL;
+ }
+ delegated_mc = GSS_C_NO_CREDENTIAL;
+
+ major_status = m->gm_accept_sec_context(minor_status,
+ &ctx->gc_ctx,
+ acceptor_mc,
+ input_token,
+ input_chan_bindings,
+ &src_mn,
+ mech_type,
+ output_token,
+ ret_flags,
+ time_rec,
+ &delegated_mc);
+ if (major_status != GSS_S_COMPLETE &&
+ major_status != GSS_S_CONTINUE_NEEDED)
+ return (major_status);
+
+ if (!src_name) {
+ m->gm_release_name(minor_status, &src_mn);
+ } else {
+ /*
+ * Make a new name and mark it as an MN.
+ */
+ struct _gss_name *name = _gss_make_name(m, src_mn);
+
+ if (!name) {
+ m->gm_release_name(minor_status, &src_mn);
+ return (GSS_S_FAILURE);
+ }
+ *src_name = (gss_name_t) name;
+ }
+
+ if (*ret_flags & GSS_C_DELEG_FLAG) {
+ if (!delegated_cred_handle) {
+ m->gm_release_cred(minor_status, &delegated_mc);
+ *ret_flags &= ~GSS_C_DELEG_FLAG;
+ } else {
+ struct _gss_cred *cred;
+ struct _gss_mechanism_cred *mc;
+
+ cred = malloc(sizeof(struct _gss_cred));
+ if (!cred) {
+ *minor_status = ENOMEM;
+ return (GSS_S_FAILURE);
+ }
+ mc = malloc(sizeof(struct _gss_mechanism_cred));
+ if (!mc) {
+ free(cred);
+ *minor_status = ENOMEM;
+ return (GSS_S_FAILURE);
+ }
+ m->gm_inquire_cred(minor_status, delegated_mc,
+ 0, 0, &cred->gc_usage, 0);
+ mc->gmc_mech = m;
+ mc->gmc_mech_oid = &m->gm_mech_oid;
+ mc->gmc_cred = delegated_mc;
+ SLIST_INSERT_HEAD(&cred->gc_mc, mc, gmc_link);
+
+ *delegated_cred_handle = (gss_cred_id_t) cred;
+ }
+ }
+
+ *context_handle = (gss_ctx_id_t) ctx;
+ return (major_status);
+}
diff --git a/lib/libgssapi/gss_acquire_cred.3 b/lib/libgssapi/gss_acquire_cred.3
new file mode 100644
index 0000000..7462dc0
--- /dev/null
+++ b/lib/libgssapi/gss_acquire_cred.3
@@ -0,0 +1,238 @@
+.\" -*- nroff -*-
+.\"
+.\" Copyright (c) 2005 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$
+.\"
+.\" The following commands are required for all man pages.
+.Dd November 12, 2005
+.Os
+.Dt GSS_ACQUIRE_CRED 3 PRM
+.Sh NAME
+.Nm gss_acquire_cred
+.Nd Obtain a GSS-API credential handle for pre-existing credentials
+.\" This next command is for sections 2 and 3 only.
+.\" .Sh LIBRARY
+.Sh SYNOPSIS
+.In "gssapi/gssapi.h"
+.Ft OM_uint32
+.Fo gss_acquire_cred
+.Fa "OM_uint32 *minor_status"
+.Fa "const gss_name_t desired_name"
+.Fa "OM_uint32 time_req"
+.Fa "const gss_OID_set desired_mechs"
+.Fa "gss_cred_usage_t cred_usage"
+.Fa "gss_cred_id_t *output_cred_handle"
+.Fa "gss_OID_set *actual_mechs"
+.Fa "OM_uint32 *time_rec"
+.Fc
+.Sh DESCRIPTION
+Allows an application to acquire a handle for a pre-existing
+credential by name.
+GSS-API implementations must impose a local
+access-control policy on callers of this routine to prevent
+unauthorized callers from acquiring credentials to which they are not
+entitled.
+This routine is not intended to provide a "login to the
+network" function, as such a function would involve the creation of
+new credentials rather than merely acquiring a handle to existing
+credentials.
+Such functions, if required, should be defined in
+implementation-specific extensions to the API.
+.Pp
+If desired_name is
+.Dv GSS_C_NO_NAME ,
+the call is interpreted as a
+request for a credential handle that will invoke default behavior
+when passed to
+.Fn gss_init_sec_context
+(if cred_usage is
+.Dv GSS_C_INITIATE
+or
+.Dv GSS_C_BOTH )
+or
+.Fn gss_accept_sec_context
+(if cred_usage is
+.Dv GSS_C_ACCEPT
+or
+.Dv GSS_C_BOTH ).
+.Pp
+Mechanisms should honor the
+.Fa desired_mechs
+parameter,
+and return a credential that is suitable to use only with the
+requested mechanisms.
+An exception to this is the case where one underlying credential
+element can be shared by multiple mechanisms;
+in this case it is permissible for an implementation to indicate all
+mechanisms with which the credential element may be used.
+If
+.Fa desired_mechs
+is an empty set, behavior is undefined.
+.Pp
+This routine is expected to be used primarily by context acceptors,
+since implementations are likely to provide mechanism-specific ways
+of obtaining GSS-API initiator credentials from the system login
+process.
+Some implementations may therefore not support the acquisition of
+.Dv GSS_C_INITIATE
+or
+.Dv GSS_C_BOTH
+credentials via
+.Fn gss_acquire_cred
+for any name other than
+.Dv GSS_C_NO_NAME ,
+or a name produced by applying either
+.Fn gss_inquire_cred
+to a valid credential, or
+.Fn gss_inquire_context
+to an active context.
+.Pp
+If credential acquisition is time-consuming for a mechanism,
+the mechanism may choose to delay the actual acquisition until the
+credential is required
+(e.g. by
+.Fn gss_init_sec_context
+or
+.Fn gss_accept_sec_context ).
+Such mechanism-specific implementation
+decisions should be invisible to the calling application;
+thus a call of
+.Fn gss_inquire_cred
+immediately following the call of
+.Fn gss_acquire_cred
+must return valid credential data,
+and may therefore incur the overhead of a deferred credential acquisition.
+.Sh PARAMETERS
+.Bl -tag
+.It desired_name
+Name of principal whose credential should be acquired.
+.It time_req
+Number of seconds that credentials should remain valid.
+Specify
+.Dv GSS_C_INDEFINITE
+to request that the credentials have the maximum
+permitted lifetime.
+.It desired_mechs
+Set of underlying security mechanisms that may be used.
+.Dv GSS_C_NO_OID_SET
+may be used to obtain an implementation-specific default.
+.It cred_usage
+.Bl -tag -width "GSS_C_INITIATE"
+.It GSS_C_BOTH
+Credentials may be used either to initiate or accept security
+contexts.
+.It GSS_C_INITIATE
+Credentials will only be used to initiate security contexts.
+.It GSS_C_ACCEPT
+Credentials will only be used to accept security contexts.
+.El
+.It output_cred_handle
+The returned credential handle.
+Resources
+associated with this credential handle must be released by
+the application after use with a call to
+.Fn gss_release_cred .
+.It actual_mechs
+The set of mechanisms for which the credential is valid.
+Storage associated with the returned OID-set must be released by the
+application after use with a call to
+.Fn gss_release_oid_set .
+Specify
+.Dv NULL if not required.
+.It time_rec
+Actual number of seconds for which the returned credentials will
+remain valid.
+If the implementation does not support expiration of credentials,
+the value
+.Dv GSS_C_INDEFINITE
+will be returned.
+Specify NULL if not required.
+.It minor_status
+Mechanism specific status code.
+.El
+.Sh RETURN VALUES
+.Bl -tag
+.It GSS_S_COMPLETE
+Successful completion.
+.It GSS_S_BAD_MECH
+Unavailable mechanism requested.
+.It GSS_S_BAD_NAMETYPE
+Type contained within desired_name parameter is not supported.
+.It GSS_S_BAD_NAME
+Value supplied for desired_name parameter is ill formed.
+.It GSS_S_CREDENTIALS_EXPIRED
+The credentials could not be acquired Because they have expired.
+.It GSS_S_NO_CRED
+No credentials were found for the specified name.
+.El
+.Sh SEE ALSO
+.Xr gss_init_sec_context 3 ,
+.Xr gss_accept_sec_context 3 ,
+.Xr gss_inquire_cred 3 ,
+.Xr gss_inquire_context 3 ,
+.Xr gss_release_cred 3 ,
+.Xr gss_release_oid_set 3
+.Sh STANDARDS
+.Bl -tag
+.It RFC 2743
+Generic Security Service Application Program Interface Version 2, Update 1
+.It RFC 2744
+Generic Security Service API Version 2 : C-bindings
+.\" .Sh HISTORY
+.El
+.Sh HISTORY
+The
+.Nm
+manual page example first appeared in
+.Fx 7.0 .
+.Sh AUTHORS
+John Wray, Iris Associates
+.Sh COPYRIGHT
+Copyright (C) The Internet Society (2000). All Rights Reserved.
+.Pp
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it
+or assist in its implementation may be prepared, copied, published
+and distributed, in whole or in part, without restriction of any
+kind, provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing
+the copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of
+developing Internet standards in which case the procedures for
+copyrights defined in the Internet Standards process must be
+followed, or as required to translate it into languages other than
+English.
+.Pp
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+.Pp
+This document and the information contained herein is provided on an
+"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/lib/libgssapi/gss_acquire_cred.c b/lib/libgssapi/gss_acquire_cred.c
new file mode 100644
index 0000000..e65bb27
--- /dev/null
+++ b/lib/libgssapi/gss_acquire_cred.c
@@ -0,0 +1,166 @@
+/*-
+ * Copyright (c) 2005 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 <gssapi/gssapi.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "mech_switch.h"
+#include "name.h"
+#include "cred.h"
+
+OM_uint32
+gss_acquire_cred(OM_uint32 *minor_status,
+ const gss_name_t desired_name,
+ OM_uint32 time_req,
+ const gss_OID_set desired_mechs,
+ gss_cred_usage_t cred_usage,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *time_rec)
+{
+ OM_uint32 major_status;
+ gss_OID_set mechs = desired_mechs;
+ gss_OID_set_desc set;
+ struct _gss_name *name = (struct _gss_name *) desired_name;
+ struct _gss_mech_switch *m;
+ struct _gss_cred *cred;
+ struct _gss_mechanism_cred *mc;
+ struct _gss_mechanism_name *mn;
+ OM_uint32 min_time, time;
+ int i;
+
+ /*
+ * First make sure that at least one of the requested
+ * mechanisms is one that we support.
+ */
+ if (mechs) {
+ _gss_load_mech();
+ for (i = 0; i < mechs->count; i++) {
+ int t;
+ gss_test_oid_set_member(minor_status,
+ &mechs->elements[i], _gss_mech_oids, &t);
+ if (t)
+ break;
+ }
+ if (i == mechs->count) {
+ *output_cred_handle = 0;
+ *minor_status = 0;
+ return (GSS_S_BAD_MECH);
+ }
+ }
+
+ if (actual_mechs) {
+ major_status = gss_create_empty_oid_set(minor_status,
+ actual_mechs);
+ if (major_status)
+ return (major_status);
+ }
+
+ cred = malloc(sizeof(struct _gss_cred));
+ if (!cred) {
+ if (actual_mechs)
+ gss_release_oid_set(minor_status, actual_mechs);
+ *minor_status = ENOMEM;
+ return (GSS_S_FAILURE);
+ }
+ cred->gc_usage = cred_usage;
+ SLIST_INIT(&cred->gc_mc);
+
+ if (mechs == GSS_C_NO_OID_SET)
+ mechs = _gss_mech_oids;
+
+ set.count = 1;
+ min_time = GSS_C_INDEFINITE;
+ for (i = 0; i < mechs->count; i++) {
+ m = _gss_find_mech_switch(&mechs->elements[i]);
+ if (!m)
+ continue;
+
+ if (desired_name != GSS_C_NO_NAME) {
+ mn = _gss_find_mn(name, &mechs->elements[i]);
+ if (!mn)
+ continue;
+ }
+
+ mc = malloc(sizeof(struct _gss_mechanism_cred));
+ if (!mc) {
+ continue;
+ }
+ mc->gmc_mech = m;
+ mc->gmc_mech_oid = &m->gm_mech_oid;
+
+ /*
+ * XXX Probably need to do something with actual_mechs.
+ */
+ set.elements = &mechs->elements[i];
+ major_status = m->gm_acquire_cred(minor_status,
+ (desired_name != GSS_C_NO_NAME
+ ? mn->gmn_name : GSS_C_NO_NAME),
+ time_req, &set, cred_usage,
+ &mc->gmc_cred, NULL, &time);
+ if (major_status) {
+ free(mc);
+ continue;
+ }
+ if (time < min_time)
+ min_time = time;
+
+ if (actual_mechs) {
+ major_status = gss_add_oid_set_member(minor_status,
+ mc->gmc_mech_oid, actual_mechs);
+ if (major_status) {
+ m->gm_release_cred(minor_status,
+ &mc->gmc_cred);
+ free(mc);
+ continue;
+ }
+ }
+
+ SLIST_INSERT_HEAD(&cred->gc_mc, mc, gmc_link);
+ }
+
+ /*
+ * If we didn't manage to create a single credential, return
+ * an error.
+ */
+ if (!SLIST_FIRST(&cred->gc_mc)) {
+ free(cred);
+ if (actual_mechs)
+ gss_release_oid_set(minor_status, actual_mechs);
+ *output_cred_handle = 0;
+ *minor_status = 0;
+ return (GSS_S_NO_CRED);
+ }
+
+ if (time_rec)
+ *time_rec = min_time;
+ *output_cred_handle = (gss_cred_id_t) cred;
+ *minor_status = 0;
+ return (GSS_S_COMPLETE);
+}
diff --git a/lib/libgssapi/gss_add_cred.3 b/lib/libgssapi/gss_add_cred.3
new file mode 100644
index 0000000..612d0f9
--- /dev/null
+++ b/lib/libgssapi/gss_add_cred.3
@@ -0,0 +1,338 @@
+.\" -*- nroff -*-
+.\"
+.\" Copyright (c) 2005 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$
+.\"
+.\" The following commands are required for all man pages.
+.Dd November 12, 2005
+.Os
+.Dt GSS_ADD_CRED 3 PRM
+.Sh NAME
+.Nm gss_add_cred
+.Nd Construct credentials incrementally
+.\" This next command is for sections 2 and 3 only.
+.\" .Sh LIBRARY
+.Sh SYNOPSIS
+.In "gssapi/gssapi.h"
+.Ft OM_uint32
+.Fo gss_add_cred
+.Fa "OM_uint32 *minor_status"
+.Fa "const gss_cred_id_t input_cred_handle"
+.Fa "const gss_name_t desired_name"
+.Fa "const gss_OID desired_mech"
+.Fa "gss_cred_usage_t cred_usage"
+.Fa "OM_uint32 initiator_time_req"
+.Fa "OM_uint32 acceptor_time_req"
+.Fa "gss_cred_id_t *output_cred_handle"
+.Fa "gss_OID_set *actual_mechs"
+.Fa "OM_uint32 *initiator_time_rec"
+.Fa "OM_uint32 *acceptor_time_rec"
+.Fc
+.Sh DESCRIPTION
+Adds a credential-element to a credential.
+The credential-element is identified by the name of the principal to
+which it refers.
+GSS-API implementations must impose a local access-control policy on
+callers of this routine to prevent unauthorized callers from acquiring
+credential-elements to which they are not entitled.
+This routine is not intended to provide a "login to the network"
+function,
+as such a function would involve the creation of new
+mechanism-specific authentication data,
+rather than merely acquiring a GSS-API handle to existing data.
+Such functions,
+if required,
+should be defined in implementation-specific extensions to the API.
+.Pp
+If
+.Fa desired_name
+is
+.Dv GSS_C_NO_NAME ,
+the call is interpreted as a request to add a credential element that
+will invoke default behavior when passed to
+.Fn gss_init_sec_context
+(if cred_usage is
+.Dv GSS_C_INITIATE
+or
+.Dv GSS_C_BOTH )
+or
+.Fn gss_accept_sec_context
+(if
+.Fa cred_usage
+is
+.Dv GSS_C_ACCEPT
+or
+.Dv GSS_C_BOTH ).
+.PP
+This routine is expected to be used primarily by context acceptors,
+since implementations are likely to provide mechanism-specific ways of
+obtaining GSS-API initiator credentials from the system login process.
+Some implementations may therefore not support the acquisition of
+.Dv GSS_C_INITIATE
+or
+.Dv GSS_C_BOTH
+credentials via
+.Fn gss_acquire_cred
+for any name other than
+.Dv GSS_C_NO_NAME ,
+or a name produced by applying either
+.Fn gss_inquire_cred
+to a valid credential,
+or
+.Fn gss_inquire_context
+to an active context.
+.Pp
+If credential acquisition is time-consuming for a mechanism,
+the mechanism may choose to delay the actual acquisition until the
+credential is required (e.g. by
+.Fn gss_init_sec_context
+or
+.Fn gss_accept_sec_context ).
+Such mechanism-specific implementation decisions should be invisible
+to the calling application;
+thus a call of
+.Fn gss_inquire_cred
+immediately following the call of
+.Fn gss_add_cred
+must return valid credential data,
+and may therefore incur the overhead of a deferred credential acquisition.
+.Pp
+This routine can be used to either compose a new credential containing
+all credential-elements of the original in addition to the
+newly-acquire credential-element,
+or to add the new credential-element to an existing credential.
+If
+.Dv NULL
+is specified for the
+.Fa output_cred_handle
+parameter argument,
+the new credential-element will be added to the credential identified
+by
+.Fa input_cred_handle ;
+if a valid pointer is specified for the
+.Fa output_cred_handle
+parameter,
+a new credential handle will be created.
+.Pp
+If
+.Dv GSS_C_NO_CREDENTIAL
+is specified as the
+.Fa input_cred_handle ,
+.Fn gss_add_cred
+will compose a credential (and set the
+.Fa output_cred_handle
+parameter accordingly) based on default behavior.
+That is, the call will have the same effect as if the application had
+first made a call to
+.Fn gss_acquire_cred ,
+specifying the same usage and passing
+.Dv GSS_C_NO_NAME
+as the
+.Fa desired_name
+parameter to obtain an explicit credential handle embodying default
+behavior,
+passed this credential handle to
+.Fn gss_add_cred ,
+and finally called
+.Fn gss_release_cred
+on the first credential handle.
+.Pp
+If
+.Dv GSS_C_NO_CREDENTIAL
+is specified as the
+.Fa input_cred_handle
+parameter,
+a non-
+.Dv NULL
+.Fa output_cred_handle
+must be supplied.
+.Sh PARAMETERS
+.Bl -tag
+.It minor_status
+Mechanism specific status code.
+.It input_cred_handle
+The credential to which a credential-element will be added.
+If
+.Dv GSS_C_NO_CREDENTIAL
+is specified, the routine will compose the new credential based on
+default behavior (see description above).
+Note that, while the credential-handle is not modified by
+.Fn gss_add_cred ,
+the underlying credential will be modified if
+.Fa output_credential_handle
+is
+.Dv NULL .
+.It desired_name
+Name of principal whose credential should be acquired.
+.It desired_mech
+Underlying security mechanism with which the credential may be used.
+.It cred_usage
+.Bl -tag -width "GSS_C_INITIATE"
+.It GSS_C_BOTH
+Credential may be used either to initiate or accept security
+contexts.
+.It GSS_C_INITIATE
+Credential will only be used to initiate security contexts.
+.It GSS_C_ACCEPT
+Credential will only be used to accept security contexts.
+.El
+.It initiator_time_req
+Number of seconds that the credential should remain valid for
+initiating security contexts.
+This argument is ignored if the composed credentials are of type
+.Dv GSS_C_ACCEPT .
+Specify
+.Dv GSS_C_INDEFINITE
+to request that the credentials have the maximum permitted initiator lifetime.
+.It acceptor_time_req
+Number of seconds that the credential should remain valid for
+accepting security contexts.
+This argument is ignored if the composed credentials are of type
+.Dv GSS_C_INITIATE .
+Specify
+.Dv GSS_C_INDEFINITE
+to request that the credentials have the maximum permitted initiator lifetime.
+.It output_cred_handle
+The returned credential handle,
+containing
+the new credential-element and all the credential-elements from
+.Fa input_cred_handle .
+If a valid pointer to a
+.Fa gss_cred_id_t
+is supplied for this parameter,
+.Fn gss_add_cred
+creates a new credential handle containing all credential-elements
+from the
+.Fa input_cred_handle
+and the newly acquired credential-element;
+if
+.Dv NULL
+is specified for this parameter,
+the newly acquired credential-element will be added to the credential
+identified by
+.Fa input_cred_handle .
+.Pp
+The resources associated with any credential handle returned via this
+parameter must be released by the application after use with a call to
+.Fn gss_release_cred .
+.It actual_mechs
+The complete set of mechanisms for which the new credential is valid.
+Storage for the returned OID-set must be freed by the application
+after use with a call to
+.Fn gss_release_oid_set .
+Specify
+.Dv NULL if not required.
+.It initiator_time_rec
+Actual number of seconds for which the returned credentials will
+remain valid for initiating contexts using the specified mechanism.
+If the implementation or mechanism does not support expiration of
+credentials,
+the value
+.Dv GSS_C_INDEFINITE
+will be returned.
+Specify
+.Dv NULL
+if not required.
+.It acceptor_time_rec
+Actual number of seconds for which the returned credentials will
+remain valid for accepting security contexts using the specified
+mechanism.
+If the implementation or mechanism does not support expiration of
+credentials,
+the value
+.Dv GSS_C_INDEFINITE
+will be returned.
+Specify
+.Dv NULL
+if not required.
+.El
+.Sh RETURN VALUES
+.Bl -tag
+.It GSS_S_COMPLETE
+Successful completion.
+.It GSS_S_BAD_MECH
+Unavailable mechanism requested.
+.It GSS_S_BAD_NAMETYPE
+Type contained within desired_name parameter is not supported
+.It GSS_S_BAD_NAME
+Value supplied for desired_name parameter is ill-formed.
+.It GSS_S_DUPLICATE_ELEMENT
+The credential already contains an element for the requested mechanism
+with overlapping usage and validity period.
+.It GSS_S_CREDENTIALS_EXPIRED
+The required credentials could not be added because they have expired.
+.It GSS_S_NO_CRED
+No credentials were found for the specified name.
+.El
+.Sh SEE ALSO
+.Xr gss_init_sec_context 3 ,
+.Xr gss_accept_sec_context 3 ,
+.Xr gss_acquire_cred 3 ,
+.Xr gss_inquire_cred 3 ,
+.Xr gss_inquire_context 3 ,
+.Xr gss_release_cred 3 ,
+.Xr gss_release_oid_set 3
+.Sh STANDARDS
+.Bl -tag
+.It RFC 2743
+Generic Security Service Application Program Interface Version 2, Update 1
+.It RFC 2744
+Generic Security Service API Version 2 : C-bindings
+.\" .Sh HISTORY
+.El
+.Sh HISTORY
+The
+.Nm
+manual page example first appeared in
+.Fx 7.0 .
+.Sh AUTHORS
+John Wray, Iris Associates
+.Sh COPYRIGHT
+Copyright (C) The Internet Society (2000). All Rights Reserved.
+.Pp
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it
+or assist in its implementation may be prepared, copied, published
+and distributed, in whole or in part, without restriction of any
+kind, provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing
+the copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of
+developing Internet standards in which case the procedures for
+copyrights defined in the Internet Standards process must be
+followed, or as required to translate it into languages other than
+English.
+.Pp
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+.Pp
+This document and the information contained herein is provided on an
+"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/lib/libgssapi/gss_add_cred.c b/lib/libgssapi/gss_add_cred.c
new file mode 100644
index 0000000..aec4464
--- /dev/null
+++ b/lib/libgssapi/gss_add_cred.c
@@ -0,0 +1,178 @@
+/*-
+ * Copyright (c) 2005 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 <gssapi/gssapi.h>
+#include <errno.h>
+
+#include "mech_switch.h"
+#include "cred.h"
+#include "name.h"
+
+static struct _gss_mechanism_cred *
+_gss_copy_cred(struct _gss_mechanism_cred *mc)
+{
+ struct _gss_mechanism_cred *new_mc;
+ struct _gss_mech_switch *m = mc->gmc_mech;
+ OM_uint32 major_status, minor_status;
+ gss_name_t name;
+ gss_cred_id_t cred;
+ OM_uint32 initiator_lifetime, acceptor_lifetime;
+ gss_cred_usage_t cred_usage;
+
+ major_status = m->gm_inquire_cred_by_mech(&minor_status,
+ mc->gmc_cred, mc->gmc_mech_oid,
+ &name, &initiator_lifetime, &acceptor_lifetime, &cred_usage);
+ if (major_status)
+ return (0);
+
+ major_status = m->gm_add_cred(&minor_status,
+ GSS_C_NO_CREDENTIAL, name, mc->gmc_mech_oid,
+ cred_usage, initiator_lifetime, acceptor_lifetime,
+ &cred, 0, 0, 0);
+ m->gm_release_name(&minor_status, &name);
+
+ if (major_status)
+ return (0);
+
+ new_mc = malloc(sizeof(struct _gss_mechanism_cred));
+ if (!new_mc) {
+ m->gm_release_cred(&minor_status, &cred);
+ return (0);
+ }
+ new_mc->gmc_mech = m;
+ new_mc->gmc_mech_oid = &m->gm_mech_oid;
+ new_mc->gmc_cred = cred;
+
+ return (new_mc);
+}
+
+OM_uint32
+gss_add_cred(OM_uint32 *minor_status,
+ const gss_cred_id_t input_cred_handle,
+ const gss_name_t desired_name,
+ const gss_OID desired_mech,
+ gss_cred_usage_t cred_usage,
+ OM_uint32 initiator_time_req,
+ OM_uint32 acceptor_time_req,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *initiator_time_rec,
+ OM_uint32 *acceptor_time_rec)
+{
+ OM_uint32 major_status;
+ struct _gss_mech_switch *m;
+ gss_OID_set_desc set;
+ struct _gss_name *name = (struct _gss_name *) desired_name;
+ struct _gss_cred *cred = (struct _gss_cred *) input_cred_handle;
+ struct _gss_cred *new_cred;
+ struct _gss_mechanism_cred *mc, *target_mc, *copy_mc;
+ struct _gss_mechanism_name *mn;
+ OM_uint32 min_time, time, junk;
+ int i;
+
+ *output_cred_handle = 0;
+ *minor_status = 0;
+
+ new_cred = malloc(sizeof(struct _gss_cred));
+ if (!new_cred) {
+ *minor_status = ENOMEM;
+ return (GSS_S_FAILURE);
+ }
+ new_cred->gc_usage = cred_usage;
+ SLIST_INIT(&new_cred->gc_mc);
+
+ /*
+ * We go through all the mc attached to the input_cred_handle
+ * and check the mechanism. If it matches, we call
+ * gss_add_cred for that mechanism, otherwise we copy the mc
+ * to new_cred.
+ */
+ target_mc = 0;
+ if (cred) {
+ SLIST_FOREACH(mc, &cred->gc_mc, gmc_link) {
+ if (_gss_oid_equal(mc->gmc_mech, desired_mech)) {
+ target_mc = mc;
+ }
+ copy_mc = _gss_copy_cred(mc);
+ if (!copy_mc) {
+ gss_release_cred(&junk, (gss_cred_id_t*) &new_cred);
+ *minor_status = ENOMEM;
+ return (GSS_S_FAILURE);
+ }
+ SLIST_INSERT_HEAD(&new_cred->gc_mc, copy_mc, gmc_link);
+ }
+ }
+
+ /*
+ * Figure out a suitable mn, if any.
+ */
+ if (desired_name) {
+ mn = _gss_find_mn((struct _gss_name *) desired_name,
+ desired_mech);
+ if (!mn) {
+ free(new_cred);
+ return (GSS_S_BAD_NAME);
+ }
+ } else {
+ mn = 0;
+ }
+
+ m = _gss_find_mech_switch(desired_mech);
+
+ mc = malloc(sizeof(struct _gss_mechanism_cred));
+ if (!mc) {
+ gss_release_cred(&junk, (gss_cred_id_t*) &new_cred);
+ *minor_status = ENOMEM;
+ return (GSS_S_FAILURE);
+ }
+ mc->gmc_mech = m;
+ mc->gmc_mech_oid = &m->gm_mech_oid;
+
+ major_status = m->gm_add_cred(minor_status,
+ target_mc ? target_mc->gmc_cred : GSS_C_NO_CREDENTIAL,
+ desired_name ? mn->gmn_name : GSS_C_NO_NAME,
+ desired_mech,
+ cred_usage,
+ initiator_time_req,
+ acceptor_time_req,
+ &mc->gmc_cred,
+ actual_mechs,
+ initiator_time_rec,
+ acceptor_time_rec);
+
+ if (major_status) {
+ gss_release_cred(&junk, (gss_cred_id_t*) &new_cred);
+ free(mc);
+ return (major_status);
+ }
+ SLIST_INSERT_HEAD(&new_cred->gc_mc, mc, gmc_link);
+ *output_cred_handle = (gss_cred_id_t) new_cred;
+
+ return (GSS_S_COMPLETE);
+}
+
diff --git a/lib/libgssapi/gss_add_oid_set_member.3 b/lib/libgssapi/gss_add_oid_set_member.3
new file mode 100644
index 0000000..94661d2
--- /dev/null
+++ b/lib/libgssapi/gss_add_oid_set_member.3
@@ -0,0 +1,130 @@
+.\" -*- nroff -*-
+.\"
+.\" Copyright (c) 2005 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$
+.\"
+.\" The following commands are required for all man pages.
+.Dd November 12, 2005
+.Os
+.Dt GSS_ADD_OID_SET_MEMBER 3 PRM
+.Sh NAME
+.Nm gss_add_oid_set_member
+.Nd Add an object identifier to a set
+.\" This next command is for sections 2 and 3 only.
+.\" .Sh LIBRARY
+.Sh SYNOPSIS
+.In "gssapi/gssapi.h"
+.Ft OM_uint32
+.Fo gss_add_oid_set_member
+.Fa "OM_uint32 *minor_status"
+.Fa "const gss_OID member_oid"
+.Fa "gss_OID_set *oid_set"
+.Fc
+.Sh DESCRIPTION
+Add an Object Identifier to an Object Identifier set.
+This routine is intended for use in conjunction with
+.Fn gss_create_empty_oid_set
+when constructing a set of mechanism OIDs for input to
+.Fn gss_acquire_cred .
+The
+.Fa oid_set
+parameter must refer to an OID-set that was created by GSS-API
+(e.g. a set returned by
+.Fn gss_create_empty_oid_set ).
+GSS-API creates a copy of the
+.Fa member_oid
+and inserts this copy into the set,
+expanding the storage allocated to the OID-set's elements array if
+necessary.
+The routine may add the new member OID anywhere within the elements
+array,
+and implementations should verify that the new
+.Fa member_oid
+is not already contained within the elements array;
+if the
+.Fa member_oid
+is already present,
+the
+.Fa oid_set
+should remain unchanged.
+.Sh PARAMETERS
+.Bl -tag
+.It minor_status
+Mechanism specific status code.
+.It member_oid
+The object identifier to copied into the set.
+.It oid_set
+The set in which the object identifier should be inserted.
+.El
+.Sh RETURN VALUES
+.Bl -tag
+.It GSS_S_COMPLETE
+Successful completion
+.El
+.Sh SEE ALSO
+.Xr gss_create_empty_oid_set 3 ,
+.Xr gss_acquire_cred 3
+.Sh STANDARDS
+.Bl -tag
+.It RFC 2743
+Generic Security Service Application Program Interface Version 2, Update 1
+.It RFC 2744
+Generic Security Service API Version 2 : C-bindings
+.\" .Sh HISTORY
+.El
+.Sh HISTORY
+The
+.Nm
+manual page example first appeared in
+.Fx 7.0 .
+.Sh AUTHORS
+John Wray, Iris Associates
+.Sh COPYRIGHT
+Copyright (C) The Internet Society (2000). All Rights Reserved.
+.Pp
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it
+or assist in its implementation may be prepared, copied, published
+and distributed, in whole or in part, without restriction of any
+kind, provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing
+the copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of
+developing Internet standards in which case the procedures for
+copyrights defined in the Internet Standards process must be
+followed, or as required to translate it into languages other than
+English.
+.Pp
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+.Pp
+This document and the information contained herein is provided on an
+"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/lib/libgssapi/gss_add_oid_set_member.c b/lib/libgssapi/gss_add_oid_set_member.c
new file mode 100644
index 0000000..f1f8214
--- /dev/null
+++ b/lib/libgssapi/gss_add_oid_set_member.c
@@ -0,0 +1,77 @@
+/*-
+ * Copyright (c) 2005 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 <gssapi/gssapi.h>
+#include <stdlib.h>
+#include <errno.h>
+
+OM_uint32
+gss_add_oid_set_member(OM_uint32 *minor_status,
+ const gss_OID member_oid,
+ gss_OID_set *oid_set)
+{
+ OM_uint32 major_status;
+ gss_OID_set set = *oid_set;
+ gss_OID new_elements;
+ gss_OID new_oid;
+ int t;
+
+ *minor_status = 0;
+
+ major_status = gss_test_oid_set_member(minor_status,
+ member_oid, *oid_set, &t);
+ if (major_status)
+ return (major_status);
+ if (t)
+ return (GSS_S_COMPLETE);
+
+ new_elements = malloc((set->count + 1) * sizeof(gss_OID_desc));
+ if (!new_elements) {
+ *minor_status = ENOMEM;
+ return (GSS_S_FAILURE);
+ }
+
+ new_oid = &new_elements[set->count];
+ new_oid->elements = malloc(member_oid->length);
+ if (!new_oid->elements) {
+ free(new_elements);
+ return (GSS_S_FAILURE);
+ }
+ new_oid->length = member_oid->length;
+ memcpy(new_oid->elements, member_oid->elements, member_oid->length);
+
+ if (set->elements) {
+ memcpy(new_elements, set->elements,
+ set->count * sizeof(gss_OID_desc));
+ free(set->elements);
+ }
+ set->elements = new_elements;
+ set->count++;
+
+ return (GSS_S_COMPLETE);
+}
diff --git a/lib/libgssapi/gss_canonicalize_name.3 b/lib/libgssapi/gss_canonicalize_name.3
new file mode 100644
index 0000000..78ddd4c
--- /dev/null
+++ b/lib/libgssapi/gss_canonicalize_name.3
@@ -0,0 +1,137 @@
+.\" -*- nroff -*-
+.\"
+.\" Copyright (c) 2005 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$
+.\"
+.\" The following commands are required for all man pages.
+.Dd November 12, 2005
+.Os
+.Dt GSS_CANONICALIZE_NAME 3 PRM
+.Sh NAME
+.Nm gss_canonicalize_name
+.Nd Convert an internal name to an MN
+.\" This next command is for sections 2 and 3 only.
+.\" .Sh LIBRARY
+.Sh SYNOPSIS
+.In "gssapi/gssapi.h"
+.Ft OM_uint32
+.Fo gss_canonicalize_name
+.Fa "OM_uint32 *minor_status"
+.Fa "const gss_name_t input_name"
+.Fa "const gss_OID mech_type"
+.Fa "gss_name_t *output_name"
+.Fc
+.Sh DESCRIPTION
+Generate a canonical mechanism name (MN) from an arbitrary internal
+name.
+The mechanism name is the name that would be returned to a context
+acceptor on successful authentication of a context where the initiator
+used the
+.Fa input_name
+in a successful call to
+.Fn gss_acquire_cred ,
+specifying an OID set containing
+.Fa mech_type
+as its only member,
+followed by a call to
+.Fn gss_init_sec_context ,
+specifying
+.Fa mech_type
+as the authentication mechanism.
+.Sh PARAMETERS
+.Bl -tag
+.It minor_status
+Mechanism specific status code.
+.It input_name
+The name for which a canonical form is desired.
+.It mech_type
+The authentication mechanism for which the canonical form of the name
+is desired.
+The desired mechanism must be specified explicitly;
+ no default is provided.
+.It output_name
+The resultant canonical name.
+Storage associated with this name must be freed by the application
+after use with a call to
+.Fn gss_release_name .
+.El
+.Sh RETURN VALUES
+.Bl -tag
+.It GSS_S_COMPLETE
+Successful completion.
+.It GSS_S_BAD_MECH
+The identified mechanism is not supported.
+.It GSS_S_BAD_NAMETYPE
+The provided internal name contains no elements that could be
+processed by the specified mechanism.
+.It GSS_S_BAD_NAME
+The provided internal name was ill-formed.
+.El
+.Sh SEE ALSO
+.Xr gss_acquire_cred 3 ,
+.Xr gss_init_sec_context 3 ,
+.Xr gss_release_name 3
+.Sh STANDARDS
+.Bl -tag
+.It RFC 2743
+Generic Security Service Application Program Interface Version 2, Update 1
+.It RFC 2744
+Generic Security Service API Version 2 : C-bindings
+.\" .Sh HISTORY
+.El
+.Sh HISTORY
+The
+.Nm
+manual page example first appeared in
+.Fx 7.0 .
+.Sh AUTHORS
+John Wray, Iris Associates
+.Sh COPYRIGHT
+Copyright (C) The Internet Society (2000). All Rights Reserved.
+.Pp
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it
+or assist in its implementation may be prepared, copied, published
+and distributed, in whole or in part, without restriction of any
+kind, provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing
+the copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of
+developing Internet standards in which case the procedures for
+copyrights defined in the Internet Standards process must be
+followed, or as required to translate it into languages other than
+English.
+.Pp
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+.Pp
+This document and the information contained herein is provided on an
+"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/lib/libgssapi/gss_canonicalize_name.c b/lib/libgssapi/gss_canonicalize_name.c
new file mode 100644
index 0000000..5fbcbe5
--- /dev/null
+++ b/lib/libgssapi/gss_canonicalize_name.c
@@ -0,0 +1,91 @@
+/*-
+ * Copyright (c) 2005 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 <gssapi/gssapi.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "mech_switch.h"
+#include "name.h"
+
+OM_uint32
+gss_canonicalize_name(OM_uint32 *minor_status,
+ const gss_name_t input_name,
+ const gss_OID mech_type,
+ gss_name_t *output_name)
+{
+ OM_uint32 major_status;
+ struct _gss_name *name = (struct _gss_name *) input_name;
+ struct _gss_mechanism_name *mn;
+ struct _gss_mech_switch *m = _gss_find_mech_switch(mech_type);
+ gss_name_t new_canonical_name;
+
+ *minor_status = 0;
+ *output_name = 0;
+
+ mn = _gss_find_mn(name, mech_type);
+ if (!mn) {
+ return (GSS_S_BAD_MECH);
+ }
+
+ m = mn->gmn_mech;
+ major_status = m->gm_canonicalize_name(minor_status,
+ mn->gmn_name, mech_type, &new_canonical_name);
+ if (major_status)
+ return (major_status);
+
+ /*
+ * Now we make a new name and mark it as an MN.
+ */
+ *minor_status = 0;
+ name = malloc(sizeof(struct _gss_name));
+ if (!name) {
+ m->gm_release_name(minor_status, &new_canonical_name);
+ *minor_status = ENOMEM;
+ return (GSS_S_FAILURE);
+ }
+ memset(name, 0, sizeof(struct _gss_name));
+
+ mn = malloc(sizeof(struct _gss_mechanism_name));
+ if (!mn) {
+ m->gm_release_name(minor_status, &new_canonical_name);
+ free(name);
+ *minor_status = ENOMEM;
+ return (GSS_S_FAILURE);
+ }
+
+ SLIST_INIT(&name->gn_mn);
+ mn->gmn_mech = m;
+ mn->gmn_mech_oid = &m->gm_mech_oid;
+ mn->gmn_name = new_canonical_name;
+ SLIST_INSERT_HEAD(&name->gn_mn, mn, gmn_link);
+
+ *output_name = (gss_name_t) name;
+
+ return (GSS_S_COMPLETE);
+}
diff --git a/lib/libgssapi/gss_compare_name.3 b/lib/libgssapi/gss_compare_name.3
new file mode 100644
index 0000000..34caaad
--- /dev/null
+++ b/lib/libgssapi/gss_compare_name.3
@@ -0,0 +1,122 @@
+.\" -*- nroff -*-
+.\"
+.\" Copyright (c) 2005 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$
+.\"
+.\" The following commands are required for all man pages.
+.Dd November 12, 2005
+.Os
+.Dt GSS_COMPARE_NAME PRM
+.Sh NAME
+.Nm gss_compare_name
+.Nd Compare two internal-form names
+.\" This next command is for sections 2 and 3 only.
+.\" .Sh LIBRARY
+.Sh SYNOPSIS
+.In "gssapi/gssapi.h"
+.Ft OM_uint32
+.Fo gss_compare_name
+.Fa "OM_uint32 *minor_status"
+.Fa "const gss_name_t name1"
+.Fa "const gss_name_t name2"
+.Fa "int *name_equal"
+.Fc
+.Sh DESCRIPTION
+Allows an application to compare two internal-form names to determine
+whether they refer to the same entity.
+.Pp
+If either name presented to
+.Fn gss_compare_name
+denotes an anonymous principal,
+the routines should indicate that the two names do not refer to the
+same identity.
+.Sh PARAMETERS
+.Bl -tag
+.It minor_status
+Mechanism specific status code.
+.It name1
+Internal-form name.
+.It name2
+Internal-form name.
+.It name_equal
+.Bl -tag
+.It non-zero
+Names refer to same entity
+.It zero
+Names refer to different entities (strictly, the names are not known
+to refer to the same identity).
+.El
+.El
+.Sh RETURN VALUES
+.Bl -tag
+.It GSS_S_COMPLETE
+Successful completion
+.It GSS_S_BAD_NAMETYPE
+The two names were of incomparable types.
+.It GSS_S_BAD_NAME
+One or both of name1 or name2 was ill-formed.
+.El
+.Sh STANDARDS
+.Bl -tag
+.It RFC 2743
+Generic Security Service Application Program Interface Version 2, Update 1
+.It RFC 2744
+Generic Security Service API Version 2 : C-bindings
+.\" .Sh HISTORY
+.El
+.Sh HISTORY
+The
+.Nm
+manual page example first appeared in
+.Fx 7.0 .
+.Sh AUTHORS
+John Wray, Iris Associates
+.Sh COPYRIGHT
+Copyright (C) The Internet Society (2000). All Rights Reserved.
+.Pp
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it
+or assist in its implementation may be prepared, copied, published
+and distributed, in whole or in part, without restriction of any
+kind, provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing
+the copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of
+developing Internet standards in which case the procedures for
+copyrights defined in the Internet Standards process must be
+followed, or as required to translate it into languages other than
+English.
+.Pp
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+.Pp
+This document and the information contained herein is provided on an
+"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/lib/libgssapi/gss_compare_name.c b/lib/libgssapi/gss_compare_name.c
new file mode 100644
index 0000000..644b4a6
--- /dev/null
+++ b/lib/libgssapi/gss_compare_name.c
@@ -0,0 +1,76 @@
+/*-
+ * Copyright (c) 2005 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 <gssapi/gssapi.h>
+
+#include "mech_switch.h"
+#include "name.h"
+
+OM_uint32
+gss_compare_name(OM_uint32 *minor_status,
+ const gss_name_t name1_arg,
+ const gss_name_t name2_arg,
+ int *name_equal)
+{
+ struct _gss_name *name1 = (struct _gss_name *) name1_arg;
+ struct _gss_name *name2 = (struct _gss_name *) name2_arg;
+
+ /*
+ * First check the implementation-independant name if both
+ * names have one. Otherwise, try to find common mechanism
+ * names and compare them.
+ */
+ if (name1->gn_value.value && name2->gn_value.value) {
+ *name_equal = 1;
+ if (!_gss_oid_equal(name1->gn_type, name2->gn_type)) {
+ *name_equal = 0;
+ } else if (name1->gn_value.length != name2->gn_value.length ||
+ memcmp(name1->gn_value.value, name1->gn_value.value,
+ name1->gn_value.length)) {
+ *name_equal = 0;
+ }
+ } else {
+ struct _gss_mechanism_name *mn1;
+ struct _gss_mechanism_name *mn2;
+
+ SLIST_FOREACH(mn1, &name1->gn_mn, gmn_link) {
+ mn2 = _gss_find_mn(name2, mn1->gmn_mech_oid);
+ if (mn2) {
+ return (mn1->gmn_mech->gm_compare_name(
+ minor_status,
+ mn1->gmn_name,
+ mn2->gmn_name,
+ name_equal));
+ }
+ }
+ *name_equal = 0;
+ }
+
+ *minor_status = 0;
+ return (GSS_S_COMPLETE);
+}
diff --git a/lib/libgssapi/gss_context_time.3 b/lib/libgssapi/gss_context_time.3
new file mode 100644
index 0000000..edfc852
--- /dev/null
+++ b/lib/libgssapi/gss_context_time.3
@@ -0,0 +1,108 @@
+.\" -*- nroff -*-
+.\"
+.\" Copyright (c) 2005 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$
+.\"
+.\" The following commands are required for all man pages.
+.Dd November 12, 2005
+.Os
+.Dt GSS_CONTEXT_TIME 3 PRM
+.Sh NAME
+.Nm gss_context_time
+.Nd Determine for how long a context will remain valid
+.\" This next command is for sections 2 and 3 only.
+.\" .Sh LIBRARY
+.Sh SYNOPSIS
+.In "gssapi/gssapi.h"
+.Ft OM_uint32
+.Fo gss_context_time
+.Fa "OM_uint32 *minor_status"
+.Fa "const gss_ctx_id_t context_handle"
+.Fa "OM_uint32 *time_rec"
+.Fc
+.Sh DESCRIPTION
+Determines the number of seconds for which the specified context will
+remain valid.
+.Sh PARAMETERS
+.Bl -tag
+.It minor_status
+Mechanism specific status code.
+.It context_handle
+Identifies the context to be interrogated.
+.It time_rec
+Number of seconds that the context will remain valid.
+If the context has already expired, zero will be returned.
+.El
+.Sh RETURN VALUES
+.Bl -tag
+.It GSS_S_COMPLETE
+Successful completion
+.It GSS_S_CONTEXT_EXPIRED
+The context has already expired
+.It GSS_S_NO_CONTEXT
+The context_handle parameter did not identify a valid context
+.El
+.Sh STANDARDS
+.Bl -tag
+.It RFC 2743
+Generic Security Service Application Program Interface Version 2, Update 1
+.It RFC 2744
+Generic Security Service API Version 2 : C-bindings
+.\" .Sh HISTORY
+.El
+.Sh HISTORY
+The
+.Nm
+manual page example first appeared in
+.Fx 7.0 .
+.Sh AUTHORS
+John Wray, Iris Associates
+.Sh COPYRIGHT
+Copyright (C) The Internet Society (2000). All Rights Reserved.
+.Pp
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it
+or assist in its implementation may be prepared, copied, published
+and distributed, in whole or in part, without restriction of any
+kind, provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing
+the copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of
+developing Internet standards in which case the procedures for
+copyrights defined in the Internet Standards process must be
+followed, or as required to translate it into languages other than
+English.
+.Pp
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+.Pp
+This document and the information contained herein is provided on an
+"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/lib/libgssapi/gss_context_time.c b/lib/libgssapi/gss_context_time.c
new file mode 100644
index 0000000..585ebd6
--- /dev/null
+++ b/lib/libgssapi/gss_context_time.c
@@ -0,0 +1,43 @@
+/*-
+ * Copyright (c) 2005 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 <gssapi/gssapi.h>
+
+#include "mech_switch.h"
+#include "context.h"
+
+OM_uint32
+gss_context_time(OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ OM_uint32 *time_rec)
+{
+ struct _gss_context *ctx = (struct _gss_context *) context_handle;
+ struct _gss_mech_switch *m = ctx->gc_mech;
+
+ return (m->gm_context_time(minor_status, ctx->gc_ctx, time_rec));
+}
diff --git a/lib/libgssapi/gss_create_empty_oid_set.3 b/lib/libgssapi/gss_create_empty_oid_set.3
new file mode 100644
index 0000000..3aa0158
--- /dev/null
+++ b/lib/libgssapi/gss_create_empty_oid_set.3
@@ -0,0 +1,112 @@
+.\" -*- nroff -*-
+.\"
+.\" Copyright (c) 2005 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$
+.\"
+.\" The following commands are required for all man pages.
+.Dd November 12, 2005
+.Os
+.Dt GSS_CREATE_EMPTY_OID_SET 3 PRM
+.Sh NAME
+.Nm gss_create_empty_oid_set
+.Nd Create a set containing no object identifiers
+.\" This next command is for sections 2 and 3 only.
+.\" .Sh LIBRARY
+.Sh SYNOPSIS
+.In "gssapi/gssapi.h"
+.Ft OM_uint32
+.Fo gss_create_empty_oid_set
+.Fa "OM_uint32 *minor_status"
+.Fa "gss_OID_set *oid_set"
+.Fc
+.Sh DESCRIPTION
+Create an object-identifier set containing no object identifiers,
+to which members may be subsequently added using the
+.Fn gss_add_oid_set_member
+routine.
+These routines are intended to be used to construct sets of mechanism
+object identifiers for input to
+.Fn gss_acquire_cred .
+.Sh PARAMETERS
+.Bl -tag
+.It minor_status
+Mechanism specific status code.
+.It oid_set
+
+The empty object identifier set.
+The routine will allocate the gss_OID_set_desc object,
+which the application must free after use with a call to
+.Fn gss_release_oid_set .
+.El
+.Sh RETURN VALUES
+.Bl -tag
+.It GSS_S_COMPLETE
+Successful completion
+.El
+.Sh SEE ALSO
+.Xr gss_add_oid_set_member 3 ,
+.Xr gss_acquire_cred 3
+.Sh STANDARDS
+.Bl -tag
+.It RFC 2743
+Generic Security Service Application Program Interface Version 2, Update 1
+.It RFC 2744
+Generic Security Service API Version 2 : C-bindings
+.\" .Sh HISTORY
+.El
+.Sh HISTORY
+The
+.Nm
+manual page example first appeared in
+.Fx 7.0 .
+.Sh AUTHORS
+John Wray, Iris Associates
+.Sh COPYRIGHT
+Copyright (C) The Internet Society (2000). All Rights Reserved.
+.Pp
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it
+or assist in its implementation may be prepared, copied, published
+and distributed, in whole or in part, without restriction of any
+kind, provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing
+the copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of
+developing Internet standards in which case the procedures for
+copyrights defined in the Internet Standards process must be
+followed, or as required to translate it into languages other than
+English.
+.Pp
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+.Pp
+This document and the information contained herein is provided on an
+"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/lib/libgssapi/gss_create_empty_oid_set.c b/lib/libgssapi/gss_create_empty_oid_set.c
new file mode 100644
index 0000000..0412817
--- /dev/null
+++ b/lib/libgssapi/gss_create_empty_oid_set.c
@@ -0,0 +1,53 @@
+/*-
+ * Copyright (c) 2005 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 <gssapi/gssapi.h>
+#include <stdlib.h>
+#include <errno.h>
+
+OM_uint32
+gss_create_empty_oid_set(OM_uint32 *minor_status,
+ gss_OID_set *oid_set)
+{
+ gss_OID_set set;
+
+ *minor_status = 0;
+ *oid_set = 0;
+
+ set = malloc(sizeof(gss_OID_set_desc));
+ if (!set) {
+ *minor_status = ENOMEM;
+ return (GSS_S_FAILURE);
+ }
+
+ set->count = 0;
+ set->elements = 0;
+ *oid_set = set;
+
+ return (GSS_S_COMPLETE);
+}
diff --git a/lib/libgssapi/gss_delete_sec_context.3 b/lib/libgssapi/gss_delete_sec_context.3
new file mode 100644
index 0000000..16466be
--- /dev/null
+++ b/lib/libgssapi/gss_delete_sec_context.3
@@ -0,0 +1,163 @@
+.\" -*- nroff -*-
+.\"
+.\" Copyright (c) 2005 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$
+.\"
+.\" The following commands are required for all man pages.
+.Dd November 12, 2005
+.Os
+.Dt GSS_DELETE_SEC_CONTEXT 3 PRM
+.Sh NAME
+.Nm gss_delete_sec_context
+.Nd Discard a security context
+.\" This next command is for sections 2 and 3 only.
+.\" .Sh LIBRARY
+.Sh SYNOPSIS
+.In "gssapi/gssapi.h"
+.Ft OM_uint32
+.Fo gss_delete_sec_context
+.Fa "OM_uint32 *minor_status"
+.Fa "gss_ctx_id_t *context_handle"
+.Fa "gss_buffer_t output_token"
+.Fc
+.Sh DESCRIPTION
+Delete a security context.
+.Fn gss_delete_sec_context
+will delete the local data structures associated with the specified
+security context,
+and may generate an output_token,
+which when passed to the peer
+.Fn gss_process_context_token
+will instruct it to do likewise.
+If no token is required by the mechanism,
+the GSS-API should set the length field of the output_token (if
+provided) to zero.
+No further security services may be obtained using the context
+specified by
+.Fa context_handle .
+.Pp
+In addition to deleting established security contexts,
+.Fn gss_delete_sec_context
+must also be able to delete "half-built" security contexts resulting
+from an incomplete sequence of
+.Fn gss_init_sec_context
+/
+.Fn gss_accept_sec_context
+calls.
+.Pp
+The
+.Fa output_token
+parameter is retained for compatibility with version 1 of the GSS-API.
+It is recommended that both peer applications invoke
+.Fn gss_delete_sec_context
+passing the value
+.Dv GSS_C_NO_BUFFER
+for the
+.Fa output_token
+parameter,
+indicating that no token is required,
+and that
+.Fn gss_delete_sec_context
+should simply delete local context data structures.
+If the application does pass a valid buffer to
+.Fn gss_delete_sec_context ,
+mechanisms are encouraged to return a zero-length token,
+indicating that no peer action is necessary,
+and that no token should be transferred by the application.
+.Sh PARAMETERS
+.Bl -tag
+.It minor_status
+Mechanism specific status code.
+.It context_handle
+Context handle identifying context to delete.
+After deleting the context,
+the GSS-API will set this context handle to
+.Dv GSS_C_NO_CONTEXT .
+.It output_token
+Token to be sent to remote application to instruct it to also delete
+the context.
+It is recommended that applications specify
+.Dv GSS_C_NO_BUFFER
+for this parameter,
+requesting local deletion only.
+If a buffer parameter is provided by the application,
+the mechanism may return a token in it;
+mechanisms that implement only local deletion should set the length
+field of this token to zero to indicate to the application that no
+token is to be sent to the peer.
+.El
+.Sh RETURN VALUES
+.Bl -tag
+.It GSS_S_COMPLETE
+Successful completion
+.It GSS_S_NO_CONTEXT
+No valid context was supplied
+.El
+.Sh SEE ALSO
+.Xr gss_process_context_token 3 ,
+.Xr gss_init_sec_context 3 ,
+.Xr gss_accept_sec_context 3
+.Sh STANDARDS
+.Bl -tag
+.It RFC 2743
+Generic Security Service Application Program Interface Version 2, Update 1
+.It RFC 2744
+Generic Security Service API Version 2 : C-bindings
+.\" .Sh HISTORY
+.El
+.Sh HISTORY
+The
+.Nm
+manual page example first appeared in
+.Fx 7.0 .
+.Sh AUTHORS
+John Wray, Iris Associates
+.Sh COPYRIGHT
+Copyright (C) The Internet Society (2000). All Rights Reserved.
+.Pp
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it
+or assist in its implementation may be prepared, copied, published
+and distributed, in whole or in part, without restriction of any
+kind, provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing
+the copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of
+developing Internet standards in which case the procedures for
+copyrights defined in the Internet Standards process must be
+followed, or as required to translate it into languages other than
+English.
+.Pp
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+.Pp
+This document and the information contained herein is provided on an
+"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/lib/libgssapi/gss_delete_sec_context.c b/lib/libgssapi/gss_delete_sec_context.c
new file mode 100644
index 0000000..b1f39c2
--- /dev/null
+++ b/lib/libgssapi/gss_delete_sec_context.c
@@ -0,0 +1,62 @@
+/*-
+ * Copyright (c) 2005 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 <gssapi/gssapi.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "mech_switch.h"
+#include "context.h"
+
+OM_uint32
+gss_delete_sec_context(OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handle,
+ gss_buffer_t output_token)
+{
+ OM_uint32 major_status;
+ struct _gss_context *ctx = (struct _gss_context *) *context_handle;
+
+ *minor_status = 0;
+ if (ctx) {
+ /*
+ * If we have an implementation ctx, delete it,
+ * otherwise fake an empty token.
+ */
+ if (ctx->gc_ctx) {
+ major_status = ctx->gc_mech->gm_delete_sec_context(
+ minor_status, &ctx->gc_ctx, output_token);
+ } else if (output_token != GSS_C_NO_BUFFER) {
+ output_token->length = 0;
+ output_token->value = 0;
+ }
+ free(ctx);
+ *context_handle = 0;
+ }
+
+ return (GSS_S_COMPLETE);
+}
diff --git a/lib/libgssapi/gss_display_name.3 b/lib/libgssapi/gss_display_name.3
new file mode 100644
index 0000000..24e6370
--- /dev/null
+++ b/lib/libgssapi/gss_display_name.3
@@ -0,0 +1,151 @@
+.\" -*- nroff -*-
+.\"
+.\" Copyright (c) 2005 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$
+.\"
+.\" The following commands are required for all man pages.
+.Dd November 12, 2005
+.Os
+.Dt GSS_DISPLAY_NAME 3 PRM
+.Sh NAME
+.Nm gss_display_name
+.Nd Convert internal-form name to text
+.\" This next command is for sections 2 and 3 only.
+.\" .Sh LIBRARY
+.Sh SYNOPSIS
+.In "gssapi/gssapi.h"
+.Ft OM_uint32
+.Fo gss_display_name
+.Fa "OM_uint32 *minor_status"
+.Fa "const gss_name_t input_name"
+.Fa "gss_buffer_t output_name_buffer"
+.Fa "gss_OID *output_name_type"
+.Fc
+.Sh DESCRIPTION
+Allows an application to obtain a textual representation of an opaque
+internal-form name for display purposes.
+The syntax of a printable name is defined by the GSS-API implementation.
+.Pp
+If
+.Fa input_name
+denotes an anonymous principal,
+the implementation should return the
+.Fa gss_OID
+value
+.Dv GSS_C_NT_ANONYMOUS
+as the
+.Fa output_name_type ,
+and a textual name that is syntactically distinct from all valid
+supported printable names in
+.Fa output_name_buffer .
+.Pp
+If
+.Fa input_name
+was created by a call to
+.Fn gss_import_name ,
+specifying
+.Dv GSS_C_NO_OID
+as the name-type,
+implementations that employ lazy conversion between name types may
+return
+.Dv GSS_C_NO_OID
+via the
+.Fa output_name_type
+parameter.
+.Sh PARAMETERS
+.Bl -tag
+.It minor_status
+Mechanism specific status code.
+.It input_name
+Name to be displayed.
+.It output_name_buffer
+Buffer to receive textual name string.
+The application must free storage associated with this name after use
+with a call to
+.Fn gss_release_buffer .
+.It output_name_type
+The type of the returned name.
+The returned
+.Fa gss_OID
+will be a pointer into static storage,
+and should be treated as read-only by the caller
+(in particular, the application should not attempt to free it).
+Specify
+.Dv NULL
+if not required.
+.El
+.Sh RETURN VALUES
+.Bl -tag
+.It GSS_S_COMPLETE
+Successful completion
+.It GSS_S_BAD_NAME
+.Fa input_name
+was ill-formed
+.El
+.Sh SEE ALSO
+.Xr gss_import_name 3 ,
+.Xr gss_release_buffer 3
+.Sh STANDARDS
+.Bl -tag
+.It RFC 2743
+Generic Security Service Application Program Interface Version 2, Update 1
+.It RFC 2744
+Generic Security Service API Version 2 : C-bindings
+.\" .Sh HISTORY
+.El
+.Sh HISTORY
+The
+.Nm
+manual page example first appeared in
+.Fx 7.0 .
+.Sh AUTHORS
+John Wray, Iris Associates
+.Sh COPYRIGHT
+Copyright (C) The Internet Society (2000). All Rights Reserved.
+.Pp
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it
+or assist in its implementation may be prepared, copied, published
+and distributed, in whole or in part, without restriction of any
+kind, provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing
+the copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of
+developing Internet standards in which case the procedures for
+copyrights defined in the Internet Standards process must be
+followed, or as required to translate it into languages other than
+English.
+.Pp
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+.Pp
+This document and the information contained herein is provided on an
+"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/lib/libgssapi/gss_display_name.c b/lib/libgssapi/gss_display_name.c
new file mode 100644
index 0000000..a5c3e5e
--- /dev/null
+++ b/lib/libgssapi/gss_display_name.c
@@ -0,0 +1,78 @@
+/*-
+ * Copyright (c) 2005 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 <gssapi/gssapi.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "mech_switch.h"
+#include "name.h"
+
+OM_uint32
+gss_display_name(OM_uint32 *minor_status,
+ const gss_name_t input_name,
+ gss_buffer_t output_name_buffer,
+ gss_OID *output_name_type)
+{
+ OM_uint32 major_status;
+ struct _gss_name *name = (struct _gss_name *) input_name;
+ struct _gss_mechanism_name *mn;
+
+ /*
+ * If we know it, copy the buffer used to import the name in
+ * the first place. Otherwise, ask all the MNs in turn if
+ * they can display the thing.
+ */
+ if (name->gn_value.value) {
+ output_name_buffer->value = malloc(name->gn_value.length);
+ if (!output_name_buffer->value) {
+ *minor_status = ENOMEM;
+ return (GSS_S_FAILURE);
+ }
+ output_name_buffer->length = name->gn_value.length;
+ memcpy(output_name_buffer->value, name->gn_value.value,
+ output_name_buffer->length);
+ if (output_name_type)
+ *output_name_type = &name->gn_type;
+
+ *minor_status = 0;
+ return (GSS_S_COMPLETE);
+ } else {
+ SLIST_FOREACH(mn, &name->gn_mn, gmn_link) {
+ major_status = mn->gmn_mech->gm_display_name(
+ minor_status, mn->gmn_name,
+ output_name_buffer,
+ output_name_type);
+ if (major_status == GSS_S_COMPLETE)
+ return (GSS_S_COMPLETE);
+ }
+ }
+
+ *minor_status = 0;
+ return (GSS_S_FAILURE);
+}
diff --git a/lib/libgssapi/gss_display_status.3 b/lib/libgssapi/gss_display_status.3
new file mode 100644
index 0000000..dacf963
--- /dev/null
+++ b/lib/libgssapi/gss_display_status.3
@@ -0,0 +1,210 @@
+.\" -*- nroff -*-
+.\"
+.\" Copyright (c) 2005 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$
+.\"
+.\" The following commands are required for all man pages.
+.Dd November 12, 2005
+.Os
+.Dt GSS_DISPLAY_STATUS 3 PRM
+.Sh NAME
+.Nm gss_display_status
+.Nd Convert a GSS-API status code to text
+.\" This next command is for sections 2 and 3 only.
+.\" .Sh LIBRARY
+.Sh SYNOPSIS
+.In "gssapi/gssapi.h"
+.Ft OM_uint32
+.Fo gss_display_status
+.Fa "OM_uint32 *minor_status"
+.Fa "OM_uint32 status_value"
+.Fa "int status_type"
+.Fa "const gss_OID mech_type"
+.Fa "OM_uint32 *message_context"
+.Fa "gss_buffer_t status_string"
+.Fc
+.Sh DESCRIPTION
+Allows an application to obtain a textual representation of a GSS-API
+status code,
+for display to the user or for logging purposes.
+Since some status values may indicate multiple conditions,
+applications may need to call
+.Fn gss_display_status
+multiple times,
+each call generating a single text string.
+The
+.Fa message_context
+parameter is used by
+.Fn gss_display_status
+to store state information about which error messages have already
+been extracted from a given
+.Fa status_value ;
+.Fa message_context
+must be initialized to zero by the application prior to the first call,
+and
+.Fn gss_display_status
+will return a non-zero value in this parameter if there are further
+messages to extract.
+.Pp
+The
+.Fa message_context
+parameter contains all state information required by
+.Fn gss_display_status
+in order to extract further messages from the
+.Fa status_value ;
+even when a non-zero value is returned in this parameter,
+the application is not required to call
+.Fn gss_display_status
+again unless subsequent messages are desired.
+The following code extracts all messages from a given status code and prints them to stderr:
+.Bd -literal
+OM_uint32 message_context;
+OM_uint32 status_code;
+OM_uint32 maj_status;
+OM_uint32 min_status;
+gss_buffer_desc status_string;
+
+ ...
+
+message_context = 0;
+
+do {
+
+ maj_status = gss_display_status (
+ &min_status,
+ status_code,
+ GSS_C_GSS_CODE,
+ GSS_C_NO_OID,
+ &message_context,
+ &status_string)
+
+ fprintf(stderr,
+ "%.*s\\n",
+ (int)status_string.length,
+ (char *)status_string.value);
+
+ gss_release_buffer(&min_status, &status_string);
+
+} while (message_context != 0);
+.Ed
+.Sh PARAMETERS
+.Bl -tag
+.It minor_status
+Mechanism specific status code.
+.It status_value
+Status value to be converted
+.It status_type
+.Bl -tag
+.It GSS_C_GSS_CODE
+.Fa status_value
+is a GSS status code
+.It GSS_C_MECH_CODE
+.Fa status_value
+is a mechanism status code
+.El
+.It mech_type
+Underlying mechanism (used to interpret a minor status value).
+Supply
+.Dv GSS_C_NO_OID
+to obtain the system default.
+.It message_context
+Should be initialized to zero by the application prior to the first
+call.
+On return from
+.Fn gss_display_status ,
+a non-zero status_value parameter indicates that additional messages
+may be extracted from the status code via subsequent calls to
+.Fn gss_display_status ,
+passing the same
+.Fa status_value ,
+.Fa status_type ,
+.Fa mech_type ,
+and
+.Fa message_context
+parameters.
+.It status_string
+Textual interpretation of the
+.Fa status_value .
+Storage associated with this parameter must be freed by the
+application after use with a call to
+.Fn gss_release_buffer .
+.El
+.Sh RETURN VALUES
+.Bl -tag
+.It GSS_S_COMPLETE
+Successful completion
+.It GSS_S_BAD_MECH
+Indicates that translation in accordance with an unsupported mechanism
+type was requested
+.It GSS_S_BAD_STATUS
+The status value was not recognized, or the status type was neither
+.Dv GSS_C_GSS_CODE
+nor
+.Dv GSS_C_MECH_CODE .
+.El
+.Sh SEE ALSO
+.Xr gss_release_buffer 3
+.Sh STANDARDS
+.Bl -tag
+.It RFC 2743
+Generic Security Service Application Program Interface Version 2, Update 1
+.It RFC 2744
+Generic Security Service API Version 2 : C-bindings
+.\" .Sh HISTORY
+.El
+.Sh HISTORY
+The
+.Nm
+manual page example first appeared in
+.Fx 7.0 .
+.Sh AUTHORS
+John Wray, Iris Associates
+.Sh COPYRIGHT
+Copyright (C) The Internet Society (2000). All Rights Reserved.
+.Pp
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it
+or assist in its implementation may be prepared, copied, published
+and distributed, in whole or in part, without restriction of any
+kind, provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing
+the copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of
+developing Internet standards in which case the procedures for
+copyrights defined in the Internet Standards process must be
+followed, or as required to translate it into languages other than
+English.
+.Pp
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+.Pp
+This document and the information contained herein is provided on an
+"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/lib/libgssapi/gss_display_status.c b/lib/libgssapi/gss_display_status.c
new file mode 100644
index 0000000..04cf4c7
--- /dev/null
+++ b/lib/libgssapi/gss_display_status.c
@@ -0,0 +1,110 @@
+/*-
+ * Copyright (c) 2005 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 <gssapi/gssapi.h>
+#include <string.h>
+
+#include "mech_switch.h"
+
+struct _gss_status_desc {
+ OM_uint32 gs_status;
+ const char* gs_desc;
+};
+
+static struct _gss_status_desc _gss_status_descs[] = {
+ GSS_S_BAD_MECH, "An unsupported mechanism was requested",
+ GSS_S_BAD_NAME, "An invalid name was supplied",
+ GSS_S_BAD_NAMETYPE, "A supplied name was of an unsupported type",
+ GSS_S_BAD_BINDINGS, "Incorrect channel bindings were supplied",
+ GSS_S_BAD_STATUS, "An invalid status code was supplied",
+ GSS_S_BAD_MIC, "A token had an invalid MIC",
+ GSS_S_NO_CRED, "No credentials were supplied, or the "
+ "credentials were unavailable or inaccessible",
+ GSS_S_NO_CONTEXT, "No context has been established",
+ GSS_S_DEFECTIVE_TOKEN, "A token was invalid",
+ GSS_S_DEFECTIVE_CREDENTIAL, "A credential was invalid",
+ GSS_S_CREDENTIALS_EXPIRED, "The referenced credentials have expired",
+ GSS_S_CONTEXT_EXPIRED, "The context has expired",
+ GSS_S_FAILURE, "Miscellaneous failure",
+ GSS_S_BAD_QOP, "The quality-of-protection requested could "
+ "not be provided",
+ GSS_S_UNAUTHORIZED, "The operation is forbidden by local security "
+ "policy",
+ GSS_S_UNAVAILABLE, "The operation or option is unavailable",
+ GSS_S_DUPLICATE_ELEMENT, "The requested credential element already "
+ "exists",
+ GSS_S_NAME_NOT_MN, "The provided name was not a mechanism name"
+};
+#define _gss_status_desc_count \
+ sizeof(_gss_status_descs) / sizeof(_gss_status_descs[0])
+
+
+OM_uint32
+gss_display_status(OM_uint32 *minor_status,
+ OM_uint32 status_value,
+ int status_type,
+ const gss_OID mech_type,
+ OM_uint32 *message_content,
+ gss_buffer_t status_string)
+{
+ OM_uint32 major_status;
+ struct _gss_mech_switch *m;
+ int i;
+ const char *message;
+
+ *minor_status = 0;
+ switch (status_type) {
+ case GSS_C_GSS_CODE:
+ for (i = 0; i < _gss_status_desc_count; i++) {
+ if (_gss_status_descs[i].gs_status == status_value) {
+ message = _gss_status_descs[i].gs_desc;
+ status_string->length = strlen(message);
+ status_string->value = strdup(message);
+ return (GSS_S_COMPLETE);
+ }
+ }
+
+ /*
+ * Fall through to attempt to get some underlying
+ * implementation to describe the value.
+ */
+ case GSS_C_MECH_CODE:
+ SLIST_FOREACH(m, &_gss_mechs, gm_link) {
+ if (mech_type &&
+ !_gss_oid_equal(&m->gm_mech_oid, mech_type))
+ continue;
+ major_status = m->gm_display_status(minor_status,
+ status_value, status_type, mech_type,
+ message_content, status_string);
+ if (major_status == GSS_S_COMPLETE)
+ return (GSS_S_COMPLETE);
+ }
+ }
+
+ return (GSS_S_BAD_STATUS);
+}
diff --git a/lib/libgssapi/gss_duplicate_name.3 b/lib/libgssapi/gss_duplicate_name.3
new file mode 100644
index 0000000..c5b6854
--- /dev/null
+++ b/lib/libgssapi/gss_duplicate_name.3
@@ -0,0 +1,123 @@
+.\" -*- nroff -*-
+.\"
+.\" Copyright (c) 2005 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$
+.\"
+.\" The following commands are required for all man pages.
+.Dd November 12, 2005
+.Os
+.Dt GSS_DUPLICATE_NAME 3 PRM
+.Sh NAME
+.Nm gss_duplicate_name
+.Nd Create a copy of an internal name
+.\" This next command is for sections 2 and 3 only.
+.\" .Sh LIBRARY
+.Sh SYNOPSIS
+.In "gssapi/gssapi.h"
+.Ft OM_uint32
+.Fo gss_duplicate_name
+.Fa "OM_uint32 *minor_status"
+.Fa "const gss_name_t src_name"
+.Fa "gss_name_t *dest_name"
+.Fc
+.Sh DESCRIPTION
+Create an exact duplicate of the existing internal name
+.Fa src_name .
+The new
+.Fa dest_name
+will be independent of
+.Fa src_name
+(i.e.
+.Fa src_name
+and
+.Fa dest_name
+must both be released,
+and the release of one shall not affect the validity of the other).
+.Sh PARAMETERS
+.Bl -tag
+.It minor_status
+Mechanism specific status code.
+.It src_name
+Internal name to be duplicated.
+.It dest_name
+The resultant copy of
+.Fa src_name.
+Storage associated with this name must be freed by the application
+after use with a call to
+.Fn gss_release_name .
+.El
+.Sh RETURN VALUES
+.Bl -tag
+.It GSS_S_COMPLETE
+Successful completion
+.It GSS_S_BAD_NAME
+The
+.Fa src_name
+parameter was ill-formed
+.El
+.Sh SEE ALSO
+.Xr gss_release_name 3
+.Sh STANDARDS
+.Bl -tag
+.It RFC 2743
+Generic Security Service Application Program Interface Version 2, Update 1
+.It RFC 2744
+Generic Security Service API Version 2 : C-bindings
+.\" .Sh HISTORY
+.El
+.Sh HISTORY
+The
+.Nm
+manual page example first appeared in
+.Fx 7.0 .
+.Sh AUTHORS
+John Wray, Iris Associates
+.Sh COPYRIGHT
+Copyright (C) The Internet Society (2000). All Rights Reserved.
+.Pp
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it
+or assist in its implementation may be prepared, copied, published
+and distributed, in whole or in part, without restriction of any
+kind, provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing
+the copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of
+developing Internet standards in which case the procedures for
+copyrights defined in the Internet Standards process must be
+followed, or as required to translate it into languages other than
+English.
+.Pp
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+.Pp
+This document and the information contained herein is provided on an
+"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/lib/libgssapi/gss_duplicate_name.c b/lib/libgssapi/gss_duplicate_name.c
new file mode 100644
index 0000000..b7be182
--- /dev/null
+++ b/lib/libgssapi/gss_duplicate_name.c
@@ -0,0 +1,78 @@
+/*-
+ * Copyright (c) 2005 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 <gssapi/gssapi.h>
+#include <errno.h>
+
+#include "mech_switch.h"
+#include "name.h"
+
+OM_uint32 gss_duplicate_name(OM_uint32 *minor_status,
+ const gss_name_t src_name,
+ gss_name_t *dest_name)
+{
+ OM_uint32 major_status;
+ struct _gss_name *name = (struct _gss_name *) src_name;
+ struct _gss_name *new_name;
+ struct _gss_mechanism_name *mn;
+
+ *minor_status = 0;
+
+ /*
+ * If this name has a value (i.e. it didn't come from
+ * gss_canonicalize_name(), we re-import the thing. Otherwise,
+ * we make an empty name to hold the MN copy.
+ */
+ if (name->gn_value.value) {
+ major_status = gss_import_name(minor_status,
+ &name->gn_value, &name->gn_type, dest_name);
+ if (major_status != GSS_S_COMPLETE)
+ return (major_status);
+ new_name = (struct _gss_name *) *dest_name;
+ } else {
+ new_name = malloc(sizeof(struct _gss_name));
+ if (!new_name) {
+ *minor_status = ENOMEM;
+ return (GSS_S_FAILURE);
+ }
+ memset(new_name, 0, sizeof(struct _gss_name));
+ SLIST_INIT(&name->gn_mn);
+ *dest_name = (gss_name_t) new_name;
+ }
+
+ /*
+ * Import the new name into any mechanisms listed in the
+ * original name. We could probably get away with only doing
+ * this if the original was canonical.
+ */
+ SLIST_FOREACH(mn, &name->gn_mn, gmn_link) {
+ _gss_find_mn(new_name, mn->gmn_mech_oid);
+ }
+
+ return (GSS_S_COMPLETE);
+}
diff --git a/lib/libgssapi/gss_export_name.3 b/lib/libgssapi/gss_export_name.3
new file mode 100644
index 0000000..629e446
--- /dev/null
+++ b/lib/libgssapi/gss_export_name.3
@@ -0,0 +1,128 @@
+.\" -*- nroff -*-
+.\"
+.\" Copyright (c) 2005 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$
+.\"
+.\" The following commands are required for all man pages.
+.Dd November 12, 2005
+.Os
+.Dt GSS_EXPORT_NAME 3 PRM
+.Sh NAME
+.Nm gss_export_name
+.Nd Convert an MN to export form
+.\" This next command is for sections 2 and 3 only.
+.\" .Sh LIBRARY
+.Sh SYNOPSIS
+.In "gssapi/gssapi.h"
+.Ft OM_uint32
+.Fo gss_export_name
+.Fa "OM_uint32 *minor_status"
+.Fa "const gss_name_t input_name"
+.Fa "gss_buffer_t exported_name"
+.Fc
+.Sh DESCRIPTION
+To produce a canonical contiguous string representation of a mechanism
+name (MN),
+suitable for direct comparison
+(e.g. with memcmp)
+for use in authorization functions
+(e.g. matching entries in an access-control list).
+The
+.Fa input_name
+parameter must specify a valid MN
+(i.e. an internal name generated by
+.Fn gss_accept_sec_context
+or by
+.Fn gss_canonicalize_name ).
+.Sh PARAMETERS
+.Bl -tag
+.It minor_status
+Mechanism specific status code.
+.It input_name
+The MN to be exported.
+.It exported_name
+The canonical contiguous string form of
+.Fa input_name .
+Storage associated with this string must freed by the application
+after use with
+.Fn gss_release_buffer .
+.El
+.Sh RETURN VALUES
+.Bl -tag
+.It GSS_S_COMPLETE
+Successful completion
+.It GSS_S_NAME_NOT_MN
+The provided internal name was not a mechanism name.
+.It GSS_S_BAD_NAME
+The provided internal name was ill-formed.
+.It GSS_S_BAD_NAMETYPE
+The internal name was of a type not supported by the GSS-API implementation.
+.El
+.Sh SEE ALSO
+.Xr gss_accept_sec_context 3 ,
+.Xr gss_canonicalize_name 3 ,
+.Xr gss_release_buffer 3
+.Sh STANDARDS
+.Bl -tag
+.It RFC 2743
+Generic Security Service Application Program Interface Version 2, Update 1
+.It RFC 2744
+Generic Security Service API Version 2 : C-bindings
+.\" .Sh HISTORY
+.El
+.Sh HISTORY
+The
+.Nm
+manual page example first appeared in
+.Fx 7.0 .
+.Sh AUTHORS
+John Wray, Iris Associates
+.Sh COPYRIGHT
+Copyright (C) The Internet Society (2000). All Rights Reserved.
+.Pp
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it
+or assist in its implementation may be prepared, copied, published
+and distributed, in whole or in part, without restriction of any
+kind, provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing
+the copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of
+developing Internet standards in which case the procedures for
+copyrights defined in the Internet Standards process must be
+followed, or as required to translate it into languages other than
+English.
+.Pp
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+.Pp
+This document and the information contained herein is provided on an
+"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/lib/libgssapi/gss_export_name.c b/lib/libgssapi/gss_export_name.c
new file mode 100644
index 0000000..f504333
--- /dev/null
+++ b/lib/libgssapi/gss_export_name.c
@@ -0,0 +1,58 @@
+/*-
+ * Copyright (c) 2005 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 <gssapi/gssapi.h>
+
+#include "mech_switch.h"
+#include "name.h"
+
+OM_uint32
+gss_export_name(OM_uint32 *minor_status,
+ const gss_name_t input_name,
+ gss_buffer_t exported_name)
+{
+ struct _gss_name *name = (struct _gss_name *) input_name;
+ struct _gss_mechanism_name *mn;
+
+ /*
+ * If this name already has any attached MNs, export the first
+ * one, otherwise export based on the first mechanism in our
+ * list.
+ */
+ mn = SLIST_FIRST(&name->gn_mn);
+ if (!mn)
+ mn = _gss_find_mn(name,
+ &SLIST_FIRST(&_gss_mechs)->gm_mech_oid);
+ if (!mn) {
+ *minor_status = 0;
+ return (GSS_S_BAD_MECH);
+ }
+
+ return mn->gmn_mech->gm_export_name(minor_status,
+ mn->gmn_name, exported_name);
+}
diff --git a/lib/libgssapi/gss_export_sec_context.3 b/lib/libgssapi/gss_export_sec_context.3
new file mode 100644
index 0000000..7cc3464
--- /dev/null
+++ b/lib/libgssapi/gss_export_sec_context.3
@@ -0,0 +1,168 @@
+.\" -*- nroff -*-
+.\"
+.\" Copyright (c) 2005 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$
+.\"
+.\" The following commands are required for all man pages.
+.Dd November 12, 2005
+.Os
+.Dt GSS_EXPORT_SEC_CONTEXT 3 PRM
+.Sh NAME
+.Nm gss_export_sec_context
+.Nd Transfer a security context to another process
+.\" This next command is for sections 2 and 3 only.
+.\" .Sh LIBRARY
+.Sh SYNOPSIS
+.In "gssapi/gssapi.h"
+.Ft OM_uint32
+.Fo gss_export_sec_context
+.Fa "OM_uint32 *minor_status"
+.Fa "gss_ctx_id_t *context_handle"
+.Fa "gss_buffer_t interprocess_token"
+.Fc
+.Sh DESCRIPTION
+Provided to support the sharing of work between multiple processes.
+This routine will typically be used by the context-acceptor,
+in an application where a single process receives incoming connection
+requests and accepts security contexts over them,
+then passes the established context to one or more other processes for
+message exchange.
+.Fn gss_export_sec_context
+deactivates the security context for the calling process and creates
+an interprocess token which,
+when passed to
+.Fn gss_import_sec_context
+in another process,
+will re-activate the context in the second process.
+Only a single instantiation of a given context may be active at any
+one time;
+a subsequent attempt by a context exporter to access the exported security context will fail.
+.Pp
+The implementation may constrain the set of processes by which the
+interprocess token may be imported,
+either as a function of local security policy,
+or as a result of implementation decisions.
+For example,
+some implementations may constrain contexts to be passed only between
+processes that run under the same account,
+or which are part of the same process group.
+.Pp
+The interprocess token may contain security-sensitive information
+(for example cryptographic keys).
+While mechanisms are encouraged to either avoid placing such sensitive
+information within interprocess tokens,
+or to encrypt the token before returning it to the application,
+in a typical object-library GSS-API implementation this may not be
+possible.
+Thus the application must take care to protect the interprocess token,
+and ensure that any process to which the token is transferred is
+trustworthy.
+.Pp
+If creation of the interprocess token is successful,
+the implementation shall deallocate all process-wide resources
+associated with the security context,
+and set the context_handle to
+.Dv GSS_C_NO_CONTEXT .
+In the event of an error that makes it impossible to complete the
+export of the security context,
+the implementation must not return an interprocess token,
+and should strive to leave the security context referenced by the
+.Fa context_handle
+parameter untouched.
+If this is impossible,
+it is permissible for the implementation to delete the security
+context,
+providing it also sets the
+.Fa context_handle
+parameter to
+.Dv GSS_C_NO_CONTEXT .
+.Sh PARAMETERS
+.Bl -tag
+.It minor_status
+Mechanism specific status code.
+.It context_handle
+Context handle identifying the context to transfer.
+.It interprocess_token
+Token to be transferred to target process.
+Storage associated with this token must be freed by the application
+after use with a call to
+.Fn gss_release_buffer .
+.El
+.Sh RETURN VALUES
+.Bl -tag
+.It GSS_S_COMPLETE
+Successful completion
+.It GSS_S_CONTEXT_EXPIRED
+The context has expired
+.It GSS_S_NO_CONTEXT
+The context was invalid
+.It GSS_S_UNAVAILABLE
+The operation is not supported
+.El
+.Sh SEE ALSO
+.Xr gss_import_sec_context 3 ,
+.Xr gss_release_buffer 3
+.Sh STANDARDS
+.Bl -tag
+.It RFC 2743
+Generic Security Service Application Program Interface Version 2, Update 1
+.It RFC 2744
+Generic Security Service API Version 2 : C-bindings
+.\" .Sh HISTORY
+.El
+.Sh HISTORY
+The
+.Nm
+manual page example first appeared in
+.Fx 7.0 .
+.Sh AUTHORS
+John Wray, Iris Associates
+.Sh COPYRIGHT
+Copyright (C) The Internet Society (2000). All Rights Reserved.
+.Pp
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it
+or assist in its implementation may be prepared, copied, published
+and distributed, in whole or in part, without restriction of any
+kind, provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing
+the copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of
+developing Internet standards in which case the procedures for
+copyrights defined in the Internet Standards process must be
+followed, or as required to translate it into languages other than
+English.
+.Pp
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+.Pp
+This document and the information contained herein is provided on an
+"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/lib/libgssapi/gss_export_sec_context.c b/lib/libgssapi/gss_export_sec_context.c
new file mode 100644
index 0000000..a7e9b8a
--- /dev/null
+++ b/lib/libgssapi/gss_export_sec_context.c
@@ -0,0 +1,77 @@
+/*-
+ * Copyright (c) 2005 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 <gssapi/gssapi.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "mech_switch.h"
+#include "context.h"
+
+OM_uint32
+gss_export_sec_context(OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handle,
+ gss_buffer_t interprocess_token)
+{
+ OM_uint32 major_status;
+ struct _gss_context *ctx = (struct _gss_context *) *context_handle;
+ struct _gss_mech_switch *m = ctx->gc_mech;
+ gss_buffer_desc buf;
+
+ major_status = m->gm_export_sec_context(minor_status,
+ &ctx->gc_ctx, &buf);
+
+ if (major_status == GSS_S_COMPLETE) {
+ unsigned char *p;
+
+ free(ctx);
+ *context_handle = GSS_C_NO_CONTEXT;
+ interprocess_token->length = buf.length
+ + 2 + m->gm_mech_oid.length;
+ interprocess_token->value = malloc(interprocess_token->length);
+ if (!interprocess_token->value) {
+ /*
+ * We are in trouble here - the context is
+ * already gone. This is allowed as long as we
+ * set the caller's context_handle to
+ * GSS_C_NO_CONTEXT, which we did above.
+ * Return GSS_S_FAILURE.
+ */
+ *minor_status = ENOMEM;
+ return (GSS_S_FAILURE);
+ }
+ p = interprocess_token->value;
+ p[0] = m->gm_mech_oid.length >> 8;
+ p[1] = m->gm_mech_oid.length;
+ memcpy(p + 2, m->gm_mech_oid.elements, m->gm_mech_oid.length);
+ memcpy(p + 2 + m->gm_mech_oid.length, buf.value, buf.length);
+ gss_release_buffer(minor_status, &buf);
+ }
+
+ return (major_status);
+}
diff --git a/lib/libgssapi/gss_get_mic.3 b/lib/libgssapi/gss_get_mic.3
new file mode 100644
index 0000000..b259f36
--- /dev/null
+++ b/lib/libgssapi/gss_get_mic.3
@@ -0,0 +1,165 @@
+.\" -*- nroff -*-
+.\"
+.\" Copyright (c) 2005 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$
+.\"
+.\" The following commands are required for all man pages.
+.Dd November 12, 2005
+.Os
+.Dt GSS_GET_MIC 3 PRM
+.Sh NAME
+.Nm gss_get_mic ,
+.Nm gss_sign
+.Nd Calculate a cryptographic message integrity code (MIC) for a
+message; integrity service
+.\" This next command is for sections 2 and 3 only.
+.\" .Sh LIBRARY
+.Sh SYNOPSIS
+.In "gssapi/gssapi.h"
+.Ft OM_uint32
+.Fo gss_get_mic
+.Fa "OM_uint32 *minor_status"
+.Fa "const gss_ctx_id_t context_handle"
+.Fa "gss_qop_t qop_req"
+.Fa "const gss_buffer_t message_buffer"
+.Fa "gss_buffer_t msg_token"
+.Fc
+.Ft OM_uint32
+.Fo gss_sign
+.Fa "OM_uint32 *minor_status"
+.Fa "const gss_ctx_id_t context_handle"
+.Fa "gss_qop_t qop_req"
+.Fa "gss_buffer_t message_buffer"
+.Fa "gss_buffer_t msg_token"
+.Fc
+.Sh DESCRIPTION
+Generates a cryptographic MIC for the supplied message,
+and places the MIC in a token for transfer to the peer application.
+The
+.Fa qop_req
+parameter allows a choice between several cryptographic algorithms,
+if supported by the chosen mechanism.
+.Pp
+Since some application-level protocols may wish to use tokens emitted
+by
+.Fn gss_wrap
+to provide "secure framing",
+implementations must support derivation of MICs from zero-length messages.
+.Pp
+The
+.Fn gss_sign
+routine is an obsolete variant of
+.Fn gss_get_mic .
+It is
+provided for backwards
+compatibility with applications using the GSS-API V1 interface.
+A distinct entrypoint (as opposed to #define) is provided,
+both to allow GSS-API V1 applications to link
+and to retain the slight parameter type differences between the
+obsolete versions of this routine and its current form.
+.Sh PARAMETERS
+.Bl -tag
+.It minor_status
+Mechanism specific status code.
+.It context_handle
+Identifies the context on which the message will be sent.
+.It qop_req
+Specifies requested quality of protection.
+Callers are encouraged, on portability grounds,
+to accept the default quality of protection offered by the chosen
+mechanism,
+which may be requested by specifying
+.Dv GSS_C_QOP_DEFAULT
+for this parameter.
+If an unsupported protection strength is requested,
+.Fn gss_get_mic
+will return a
+.Fa major_status
+of
+.Dv GSS_S_BAD_QOP .
+.It message_buffer
+Message to be protected.
+.It msg_token
+Buffer to receive token.
+The application must free storage associated with this buffer after
+use with a call to
+.Fn gss_release_buffer .
+.El
+.Sh RETURN VALUES
+.Bl -tag
+.It GSS_S_COMPLETE
+Successful completion
+.It GSS_S_CONTEXT_EXPIRED
+The context has already expired
+.It GSS_S_NO_CONTEXT
+The context_handle parameter did not identify a valid context
+.It GSS_S_BAD_QOP
+The specified QOP is not supported by the mechanism
+.El
+.Sh SEE ALSO
+.Xr gss_wrap 3 ,
+.Xr gss_release_buffer 3
+.Sh STANDARDS
+.Bl -tag
+.It RFC 2743
+Generic Security Service Application Program Interface Version 2, Update 1
+.It RFC 2744
+Generic Security Service API Version 2 : C-bindings
+.\" .Sh HISTORY
+.El
+.Sh HISTORY
+The
+.Nm
+manual page example first appeared in
+.Fx 7.0 .
+.Sh AUTHORS
+John Wray, Iris Associates
+.Sh COPYRIGHT
+Copyright (C) The Internet Society (2000). All Rights Reserved.
+.Pp
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it
+or assist in its implementation may be prepared, copied, published
+and distributed, in whole or in part, without restriction of any
+kind, provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing
+the copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of
+developing Internet standards in which case the procedures for
+copyrights defined in the Internet Standards process must be
+followed, or as required to translate it into languages other than
+English.
+.Pp
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+.Pp
+This document and the information contained herein is provided on an
+"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/lib/libgssapi/gss_get_mic.c b/lib/libgssapi/gss_get_mic.c
new file mode 100644
index 0000000..a3495ec
--- /dev/null
+++ b/lib/libgssapi/gss_get_mic.c
@@ -0,0 +1,46 @@
+/*-
+ * Copyright (c) 2005 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 <gssapi/gssapi.h>
+
+#include "mech_switch.h"
+#include "context.h"
+
+OM_uint32
+gss_get_mic(OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ gss_qop_t qop_req,
+ const gss_buffer_t message_buffer,
+ gss_buffer_t message_token)
+{
+ struct _gss_context *ctx = (struct _gss_context *) context_handle;
+ struct _gss_mech_switch *m = ctx->gc_mech;
+
+ return (m->gm_get_mic(minor_status, ctx->gc_ctx, qop_req,
+ message_buffer, message_token));
+}
diff --git a/lib/libgssapi/gss_import_name.3 b/lib/libgssapi/gss_import_name.3
new file mode 100644
index 0000000..931bf44
--- /dev/null
+++ b/lib/libgssapi/gss_import_name.3
@@ -0,0 +1,139 @@
+.\" -*- nroff -*-
+.\"
+.\" Copyright (c) 2005 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$
+.\"
+.\" The following commands are required for all man pages.
+.Dd November 12, 2005
+.Os
+.Dt GSS_IMPORT_NAME 3 PRM
+.Sh NAME
+.Nm gss_import_name
+.Nd Convert a contiguous string name to internal-form
+.\" This next command is for sections 2 and 3 only.
+.\" .Sh LIBRARY
+.Sh SYNOPSIS
+.In "gssapi/gssapi.h"
+.Ft OM_uint32
+.Fo gss_import_name
+.Fa "OM_uint32 *minor_status"
+.Fa "const gss_buffer_t input_name_buffer"
+.Fa "const gss_OID input_name_type"
+.Fa "gss_name_t *output_name"
+.Fc
+.Sh DESCRIPTION
+Convert a contiguous string name to internal form.
+In general,
+the internal name returned (via the
+.Fa output_name
+parameter) will not be an MN;
+the exception to this is if the
+.Fa input_name_type
+indicates that the contiguous string provided via the
+.Fa input_name_buffer
+parameter is of type
+.Dv GSS_C_NT_EXPORT_NAME ,
+in which case the returned internal name will be an MN for the
+mechanism that exported the name.
+.Sh PARAMETERS
+.Bl -tag
+.It minor_status
+Mechanism specific status code.
+.It input_name_buffer
+Buffer containing contiguous string name to convert.
+.It input_name_type
+Object ID specifying type of printable name.
+Applications may specify either
+.Dv GSS_C_NO_OID
+to use a mechanism-specific default printable syntax,
+or an OID recognized by the GSS-API implementation to name a specific
+namespace.
+.It output_name
+Returned name in internal form.
+Storage associated with this name must be freed by the application
+after use with a call to
+.Fn gss_release_name .
+.El
+.Sh RETURN VALUES
+.Bl -tag
+.It GSS_S_COMPLETE
+Successful completion
+.It GSS_S_BAD_NAMETYPE
+The
+.Fa input_name_type
+was unrecognized
+.It GSS_S_BAD_NAME
+The
+.Fa input_name
+parameter could not be interpreted as a name of the specified type
+.It GSS_S_BAD_MECH
+The input name-type was
+.Dv GSS_C_NT_EXPORT_NAME ,
+but the mechanism contained within the input-name is not supported
+.El
+.Sh SEE ALSO
+.Xr gss_release_name 3
+.Sh STANDARDS
+.Bl -tag
+.It RFC 2743
+Generic Security Service Application Program Interface Version 2, Update 1
+.It RFC 2744
+Generic Security Service API Version 2 : C-bindings
+.\" .Sh HISTORY
+.El
+.Sh HISTORY
+The
+.Nm
+manual page example first appeared in
+.Fx 7.0 .
+.Sh AUTHORS
+John Wray, Iris Associates
+.Sh COPYRIGHT
+Copyright (C) The Internet Society (2000). All Rights Reserved.
+.Pp
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it
+or assist in its implementation may be prepared, copied, published
+and distributed, in whole or in part, without restriction of any
+kind, provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing
+the copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of
+developing Internet standards in which case the procedures for
+copyrights defined in the Internet Standards process must be
+followed, or as required to translate it into languages other than
+English.
+.Pp
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+.Pp
+This document and the information contained herein is provided on an
+"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/lib/libgssapi/gss_import_name.c b/lib/libgssapi/gss_import_name.c
new file mode 100644
index 0000000..638df25
--- /dev/null
+++ b/lib/libgssapi/gss_import_name.c
@@ -0,0 +1,219 @@
+/*-
+ * Copyright (c) 2005 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 <gssapi/gssapi.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "mech_switch.h"
+#include "utils.h"
+#include "name.h"
+
+static OM_uint32
+_gss_import_export_name(OM_uint32 *minor_status,
+ const gss_buffer_t input_name_buffer,
+ gss_name_t *output_name)
+{
+ OM_uint32 major_status;
+ unsigned char *p = input_name_buffer->value;
+ size_t len = input_name_buffer->length;
+ size_t t;
+ gss_OID_desc mech_oid;
+ struct _gss_mech_switch *m;
+ struct _gss_name *name;
+ struct _gss_mechanism_name *mn;
+ gss_name_t new_canonical_name;
+
+ *minor_status = 0;
+ *output_name = 0;
+
+ /*
+ * Make sure that TOK_ID is {4, 1}.
+ */
+ if (len < 2)
+ return (GSS_S_BAD_NAME);
+ if (p[0] != 4 || p[1] != 1)
+ return (GSS_S_BAD_NAME);
+ p += 2;
+ len -= 2;
+
+ /*
+ * Get the mech length and the name length and sanity
+ * check the size of of the buffer.
+ */
+ if (len < 2)
+ return (GSS_S_BAD_NAME);
+ t = (p[0] << 8) + p[1];
+ p += 2;
+ len -= 2;
+
+ /*
+ * Check the DER encoded OID to make sure it agrees with the
+ * length we just decoded.
+ */
+ if (p[0] != 6) /* 6=OID */
+ return (GSS_S_BAD_NAME);
+ p++;
+ len--;
+ t--;
+ if (p[0] & 0x80) {
+ int digits = p[0];
+ p++;
+ len--;
+ t--;
+ mech_oid.length = 0;
+ while (digits--) {
+ mech_oid.length = (mech_oid.length << 8) | p[0];
+ p++;
+ len--;
+ t--;
+ }
+ } else {
+ mech_oid.length = p[0];
+ p++;
+ len--;
+ t--;
+ }
+ if (mech_oid.length != t)
+ return (GSS_S_BAD_NAME);
+
+ mech_oid.elements = p;
+
+ if (len < t + 4)
+ return (GSS_S_BAD_NAME);
+ p += t;
+ len -= t;
+
+ t = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
+ p += 4;
+ len -= 4;
+
+ if (len != t)
+ return (GSS_S_BAD_NAME);
+
+ m = _gss_find_mech_switch(&mech_oid);
+ if (!m)
+ return (GSS_S_BAD_MECH);
+
+ /*
+ * Ask the mechanism to import the name.
+ */
+ major_status = m->gm_import_name(minor_status,
+ input_name_buffer, GSS_C_NT_EXPORT_NAME, &new_canonical_name);
+
+ /*
+ * Now we make a new name and mark it as an MN.
+ */
+ name = _gss_make_name(m, new_canonical_name);
+ if (!name) {
+ m->gm_release_name(minor_status, &new_canonical_name);
+ return (GSS_S_FAILURE);
+ }
+
+ *output_name = (gss_name_t) name;
+
+ *minor_status = 0;
+ return (GSS_S_COMPLETE);
+}
+
+OM_uint32
+gss_import_name(OM_uint32 *minor_status,
+ const gss_buffer_t input_name_buffer,
+ const gss_OID input_name_type,
+ gss_name_t *output_name)
+{
+ gss_OID name_type = input_name_type;
+ OM_uint32 major_status;
+ struct _gss_name *name;
+
+ if (input_name_buffer->length == 0) {
+ *minor_status = 0;
+ *output_name = 0;
+ return (GSS_S_BAD_NAME);
+ }
+
+ /*
+ * Use GSS_NT_USER_NAME as default name type.
+ */
+ if (name_type == GSS_C_NO_OID)
+ name_type = GSS_C_NT_USER_NAME;
+
+ /*
+ * If this is an exported name, we need to parse it to find
+ * the mechanism and then import it as an MN. See RFC 2743
+ * section 3.2 for a description of the format.
+ */
+ if (_gss_oid_equal(name_type, GSS_C_NT_EXPORT_NAME)) {
+ return _gss_import_export_name(minor_status,
+ input_name_buffer, output_name);
+ }
+
+ /*
+ * Only allow certain name types. This is pretty bogus - we
+ * should figure out the list of supported name types using
+ * gss_inquire_names_for_mech.
+ */
+ if (!_gss_oid_equal(name_type, GSS_C_NT_USER_NAME)
+ && !_gss_oid_equal(name_type, GSS_C_NT_MACHINE_UID_NAME)
+ && !_gss_oid_equal(name_type, GSS_C_NT_STRING_UID_NAME)
+ && !_gss_oid_equal(name_type, GSS_C_NT_HOSTBASED_SERVICE_X)
+ && !_gss_oid_equal(name_type, GSS_C_NT_HOSTBASED_SERVICE)
+ && !_gss_oid_equal(name_type, GSS_C_NT_ANONYMOUS)
+ && !_gss_oid_equal(name_type, GSS_KRB5_NT_PRINCIPAL_NAME)) {
+ *minor_status = 0;
+ *output_name = 0;
+ return (GSS_S_BAD_NAMETYPE);
+ }
+
+ *minor_status = 0;
+ name = malloc(sizeof(struct _gss_name));
+ if (!name) {
+ *minor_status = ENOMEM;
+ return (GSS_S_FAILURE);
+ }
+ memset(name, 0, sizeof(struct _gss_name));
+
+ major_status = _gss_copy_oid(minor_status,
+ name_type, &name->gn_type);
+ if (major_status) {
+ free(name);
+ return (GSS_S_FAILURE);
+ }
+
+ major_status = _gss_copy_buffer(minor_status,
+ input_name_buffer, &name->gn_value);
+ if (major_status) {
+ gss_release_name(minor_status, (gss_name_t*) &name);
+ return (GSS_S_FAILURE);
+ }
+
+ SLIST_INIT(&name->gn_mn);
+
+ *output_name = (gss_name_t) name;
+ return (GSS_S_COMPLETE);
+}
diff --git a/lib/libgssapi/gss_import_sec_context.3 b/lib/libgssapi/gss_import_sec_context.3
new file mode 100644
index 0000000..07b5e19
--- /dev/null
+++ b/lib/libgssapi/gss_import_sec_context.3
@@ -0,0 +1,120 @@
+.\" -*- nroff -*-
+.\"
+.\" Copyright (c) 2005 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$
+.\"
+.\" The following commands are required for all man pages.
+.Dd November 12, 2005
+.Os
+.Dt GSS_IMPORT_SEC_CONTEXT 3 PRM
+.Sh NAME
+.Nm gss_import_sec_context
+.Nd Import a transferred context
+.\" This next command is for sections 2 and 3 only.
+.\" .Sh LIBRARY
+.Sh SYNOPSIS
+.In "gssapi/gssapi.h"
+.Ft OM_uint32
+.Fo gss_import_sec_context
+.Fa "OM_uint32 *minor_status"
+.Fa "const gss_buffer_t interprocess_token"
+.Fa "gss_ctx_id_t *context_handle"
+.Fc
+.Sh DESCRIPTION
+Allows a process to import a security context established by another
+process.
+A given interprocess token may be imported only once.
+See
+.Fn gss_export_sec_context .
+.Sh PARAMETERS
+.Bl -tag
+.It minor_status
+Mechanism specific status code.
+.It interprocess_token
+Token received from exporting process.
+.It context_handle
+Context handle of newly reactivated context.
+Resources associated with this context handle must be released by the
+application after use with a call to
+.Fn gss_delete_sec_context .
+.El
+.Sh RETURN VALUES
+.Bl -tag
+.It GSS_S_COMPLETE
+Successful completion
+.It GSS_S_NO_CONTEXT
+The token did not contain a valid context reference
+.It GSS_S_DEFECTIVE_TOKEN
+The token was invalid
+.It GSS_S_UNAVAILABLE
+The operation is unavailable
+.It GSS_S_UNAUTHORIZED
+Local policy prevents the import of this context by the current process
+.El
+.Sh SEE ALSO
+.Xr gss_export_sec_context 3 ,
+.Xr gss_delete_sec_context 3
+.Sh STANDARDS
+.Bl -tag
+.It RFC 2743
+Generic Security Service Application Program Interface Version 2, Update 1
+.It RFC 2744
+Generic Security Service API Version 2 : C-bindings
+.\" .Sh HISTORY
+.El
+.Sh HISTORY
+The
+.Nm
+manual page example first appeared in
+.Fx 7.0 .
+.Sh AUTHORS
+John Wray, Iris Associates
+.Sh COPYRIGHT
+Copyright (C) The Internet Society (2000). All Rights Reserved.
+.Pp
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it
+or assist in its implementation may be prepared, copied, published
+and distributed, in whole or in part, without restriction of any
+kind, provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing
+the copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of
+developing Internet standards in which case the procedures for
+copyrights defined in the Internet Standards process must be
+followed, or as required to translate it into languages other than
+English.
+.Pp
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+.Pp
+This document and the information contained herein is provided on an
+"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/lib/libgssapi/gss_import_sec_context.c b/lib/libgssapi/gss_import_sec_context.c
new file mode 100644
index 0000000..ce3ddd1
--- /dev/null
+++ b/lib/libgssapi/gss_import_sec_context.c
@@ -0,0 +1,86 @@
+/*-
+ * Copyright (c) 2005 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 <gssapi/gssapi.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "mech_switch.h"
+#include "context.h"
+
+OM_uint32
+gss_import_sec_context(OM_uint32 *minor_status,
+ const gss_buffer_t interprocess_token,
+ gss_ctx_id_t *context_handle)
+{
+ OM_uint32 major_status;
+ struct _gss_mech_switch *m;
+ struct _gss_context *ctx;
+ gss_OID_desc mech_oid;
+ gss_buffer_desc buf;
+ unsigned char *p;
+ size_t len;
+
+ *minor_status = 0;
+ *context_handle = 0;
+
+ /*
+ * We added an oid to the front of the token in
+ * gss_export_sec_context.
+ */
+ p = interprocess_token->value;
+ len = interprocess_token->length;
+ if (len < 2)
+ return (GSS_S_DEFECTIVE_TOKEN);
+ mech_oid.length = (p[0] << 8) | p[1];
+ if (len < mech_oid.length + 2)
+ return (GSS_S_DEFECTIVE_TOKEN);
+ mech_oid.elements = p + 2;
+ buf.length = len - 2 - mech_oid.length;
+ buf.value = p + 2 + mech_oid.length;
+
+ m = _gss_find_mech_switch(&mech_oid);
+ if (!m)
+ return (GSS_S_DEFECTIVE_TOKEN);
+
+ ctx = malloc(sizeof(struct _gss_context));
+ if (!ctx) {
+ *minor_status = ENOMEM;
+ return (GSS_S_FAILURE);
+ }
+ ctx->gc_mech = m;
+ major_status = m->gm_import_sec_context(minor_status,
+ &buf, &ctx->gc_ctx);
+ if (major_status != GSS_S_COMPLETE) {
+ free(ctx);
+ } else {
+ *context_handle = (gss_ctx_id_t) ctx;
+ }
+
+ return (major_status);
+}
diff --git a/lib/libgssapi/gss_indicate_mechs.3 b/lib/libgssapi/gss_indicate_mechs.3
new file mode 100644
index 0000000..5245857
--- /dev/null
+++ b/lib/libgssapi/gss_indicate_mechs.3
@@ -0,0 +1,107 @@
+.\" -*- nroff -*-
+.\"
+.\" Copyright (c) 2005 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$
+.\"
+.\" The following commands are required for all man pages.
+.Dd November 12, 2005
+.Os
+.Dt GSS_INDICATE_MECHS 3 PRM
+.Sh NAME
+.Nm gss_indicate_mechs
+.Nd Determine available underlying authentication mechanisms
+.\" This next command is for sections 2 and 3 only.
+.\" .Sh LIBRARY
+.Sh SYNOPSIS
+.In "gssapi/gssapi.h"
+.Ft OM_uint32
+.Fo gss_indicate_mechs
+.Fa "OM_uint32 *minor_status"
+.Fa "gss_OID_set *mech_set"
+.Fc
+.Sh DESCRIPTION
+Allows an application to determine which underlying security
+mechanisms are available.
+.Sh PARAMETERS
+.Bl -tag
+.It minor_status
+Mechanism specific status code.
+.It mech_set
+Set of implementation-supported mechanisms.
+The returned
+.Fa mech_set
+value will be a dynamically-allocated OID set,
+that should be released by the caller after use with a call to
+.Fn gss_release_oid_set .
+.El
+.Sh RETURN VALUES
+.Bl -tag
+.It GSS_S_COMPLETE
+Successful completion
+.El
+.Sh SEE ALSO
+.Xr gss_release_oid_set 3
+.Sh STANDARDS
+.Bl -tag
+.It RFC 2743
+Generic Security Service Application Program Interface Version 2, Update 1
+.It RFC 2744
+Generic Security Service API Version 2 : C-bindings
+.\" .Sh HISTORY
+.El
+.Sh HISTORY
+The
+.Nm
+manual page example first appeared in
+.Fx 7.0 .
+.Sh AUTHORS
+John Wray, Iris Associates
+.Sh COPYRIGHT
+Copyright (C) The Internet Society (2000). All Rights Reserved.
+.Pp
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it
+or assist in its implementation may be prepared, copied, published
+and distributed, in whole or in part, without restriction of any
+kind, provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing
+the copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of
+developing Internet standards in which case the procedures for
+copyrights defined in the Internet Standards process must be
+followed, or as required to translate it into languages other than
+English.
+.Pp
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+.Pp
+This document and the information contained herein is provided on an
+"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/lib/libgssapi/gss_indicate_mechs.c b/lib/libgssapi/gss_indicate_mechs.c
new file mode 100644
index 0000000..7abab20
--- /dev/null
+++ b/lib/libgssapi/gss_indicate_mechs.c
@@ -0,0 +1,60 @@
+/*-
+ * Copyright (c) 2005 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 <gssapi/gssapi.h>
+
+#include "mech_switch.h"
+
+OM_uint32
+gss_indicate_mechs(OM_uint32 *minor_status,
+ gss_OID_set *mech_set)
+{
+ struct _gss_mech_switch *m;
+ OM_uint32 major_status;
+ gss_OID_set set;
+ int i;
+
+ _gss_load_mech();
+
+ major_status = gss_create_empty_oid_set(minor_status, mech_set);
+ if (major_status)
+ return (major_status);
+
+ SLIST_FOREACH(m, &_gss_mechs, gm_link) {
+ major_status = m->gm_indicate_mechs(minor_status, &set);
+ if (major_status)
+ continue;
+ for (i = 0; i < set->count; i++)
+ major_status = gss_add_oid_set_member(minor_status,
+ &set->elements[i], mech_set);
+ gss_release_oid_set(minor_status, &set);
+ }
+
+ *minor_status = 0;
+ return (GSS_S_COMPLETE);
+}
diff --git a/lib/libgssapi/gss_init_sec_context.3 b/lib/libgssapi/gss_init_sec_context.3
new file mode 100644
index 0000000..9e019cf
--- /dev/null
+++ b/lib/libgssapi/gss_init_sec_context.3
@@ -0,0 +1,571 @@
+.\" -*- nroff -*-
+.\"
+.\" Copyright (c) 2005 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$
+.\"
+.\" The following commands are required for all man pages.
+.Dd November 12, 2005
+.Os
+.Dt GSS_INIT_SEC_CONTEXT 3 PRM
+.Sh NAME
+.Nm gss_init_sec_context
+.Nd Initiate a security context with a peer application
+.\" This next command is for sections 2 and 3 only.
+.\" .Sh LIBRARY
+.Sh SYNOPSIS
+.In "gssapi/gssapi.h"
+.Ft OM_uint32
+.Fo gss_init_sec_context
+.Fa "OM_uint32 *minor_status"
+.Fa "const gss_cred_id_t initiator_cred_handle"
+.Fa "gss_ctx_id_t *context_handle"
+.Fa "const gss_name_t target_name"
+.Fa "const gss_OID mech_type"
+.Fa "OM_uint32 req_flags"
+.Fa "OM_uint32 time_req"
+.Fa "const gss_channel_bindings_t input_chan_bindings"
+.Fa "const gss_buffer_t input_token"
+.Fa "gss_OID *actual_mech_type"
+.Fa "gss_buffer_t output_token"
+.Fa "OM_uint32 *ret_flags"
+.Fa "OM_uint32 *time_rec"
+.Fc
+.Sh DESCRIPTION
+Initiates the establishment of a security context between the
+application and a remote peer.
+Initially, the input_token parameter should be specified either as
+.Dv GSS_C_NO_BUFFER, or as a pointer to a
+gss_buffer_desc object whose length field contains the value zero.
+The routine may return a output_token which should be transferred to
+the peer application, where the peer application will present it to
+.Xr gss_accept_sec_context 3 . If no token need be sent,
+.Fn gss_init_sec_context
+will indicate this by setting the
+.Dv length field
+of the output_token argument to zero. To complete the context
+establishment, one or more reply tokens may be required from the peer
+application; if so,
+.Fn gss_init_sec_context
+will return a status
+containing the supplementary information bit
+.Dv GSS_S_CONTINUE_NEEDED.
+In this case,
+.Fn gss_init_sec_context
+should be called again when the reply token is received from the peer
+application, passing the reply token to
+.Fn gss_init_sec_context
+via the input_token parameters.
+.Pp
+Portable applications should be constructed to use the token length
+and return status to determine whether a token needs to be sent or
+waited for. Thus a typical portable caller should always invoke
+.Fn gss_init_sec_context
+within a loop:
+.Bd -literal
+int context_established = 0;
+gss_ctx_id_t context_hdl = GSS_C_NO_CONTEXT;
+ ...
+input_token->length = 0;
+
+while (!context_established) {
+ maj_stat = gss_init_sec_context(&min_stat,
+ cred_hdl,
+ &context_hdl,
+ target_name,
+ desired_mech,
+ desired_services,
+ desired_time,
+ input_bindings,
+ input_token,
+ &actual_mech,
+ output_token,
+ &actual_services,
+ &actual_time);
+ if (GSS_ERROR(maj_stat)) {
+ report_error(maj_stat, min_stat);
+ };
+
+ if (output_token->length != 0) {
+ send_token_to_peer(output_token);
+ gss_release_buffer(&min_stat, output_token)
+ };
+ if (GSS_ERROR(maj_stat)) {
+
+ if (context_hdl != GSS_C_NO_CONTEXT)
+ gss_delete_sec_context(&min_stat,
+ &context_hdl,
+ GSS_C_NO_BUFFER);
+ break;
+ };
+
+ if (maj_stat & GSS_S_CONTINUE_NEEDED) {
+ receive_token_from_peer(input_token);
+ } else {
+ context_established = 1;
+ };
+};
+.Ed
+.Pp
+Whenever the routine returns a major status that includes the value
+.Dv GSS_S_CONTINUE_NEEDED, the context is not fully established and the
+following restrictions apply to the output parameters:
+.Bl -bullet
+.It
+The value returned via the
+.Fa time_rec
+parameter is undefined Unless
+the accompanying
+.Fa ret_flags
+parameter contains the bit
+.Dv GSS_C_PROT_READY_FLAG, indicating that per-message services may be
+applied in advance of a successful completion status, the value
+returned via the
+.Fa actual_mech_type
+parameter is undefined until the
+routine returns a major status value of
+.Dv GSS_S_COMPLETE.
+.It
+The values of the
+.Dv GSS_C_DELEG_FLAG ,
+.Dv GSS_C_MUTUAL_FLAG ,
+.Dv GSS_C_REPLAY_FLAG ,
+.Dv GSS_C_SEQUENCE_FLAG ,
+.Fv GSS_C_CONF_FLAG ,
+.Dv GSS_C_INTEG_FLAG and
+.Dv GSS_C_ANON_FLAG bits returned via the
+.Fa ret_flags
+parameter should contain the values that the
+implementation expects would be valid if context establishment
+were to succeed. In particular, if the application has requested
+a service such as delegation or anonymous authentication via the
+.Fa req_flags
+argument, and such a service is unavailable from the
+underlying mechanism,
+.Fn gss_init_sec_context
+should generate a token
+that will not provide the service, and indicate via the
+.Fa ret_flags
+argument that the service will not be supported. The application
+may choose to abort the context establishment by calling
+.Xr gss_delete_sec_context 3
+(if it cannot continue in the absence of
+the service), or it may choose to transmit the token and continue
+context establishment (if the service was merely desired but not
+mandatory).
+.It
+The values of the
+.Dv GSS_C_PROT_READY_FLAG and
+.Dv GSS_C_TRANS_FLAG bits
+within
+.Fa ret_flags
+should indicate the actual state at the time
+.Fn gss_init_sec_context
+returns, whether or not the context is fully established.
+.It
+GSS-API implementations that support per-message protection are
+encouraged to set the
+.Dv GSS_C_PROT_READY_FLAG in the final
+.Fa ret_flags
+returned to a caller (i.e. when accompanied by a
+.Dv GSS_S_COMPLETE
+status code). However, applications should not rely on this
+behavior as the flag was not defined in Version 1 of the GSS-API.
+Instead, applications should determine what per-message services
+are available after a successful context establishment according
+to the
+.Dv GSS_C_INTEG_FLAG and
+.Dv GSS_C_CONF_FLAG values.
+.It
+All other bits within the
+.Fa ret_flags
+argument should be set to
+zero.
+.El
+.Pp
+If the initial call of
+.Fn gss_init_sec_context
+fails, the
+implementation should not create a context object, and should leave
+the value of the
+.Fa context_handle
+parameter set to
+.Dv GSS_C_NO_CONTEXT to
+indicate this. In the event of a failure on a subsequent call, the
+implementation is permitted to delete the "half-built" security
+context (in which case it should set the
+.Fa context_handle
+parameter to
+.Dv GSS_C_NO_CONTEXT ), but the preferred behavior is to leave the
+security context untouched for the application to delete (using
+.Xr gss_delete_sec_context 3 ).
+.Pp
+During context establishment, the informational status bits
+.Dv GSS_S_OLD_TOKEN and
+.Dv GSS_S_DUPLICATE_TOKEN indicate fatal errors, and
+GSS-API mechanisms should always return them in association with a
+routine error of
+.Dv GSS_S_FAILURE .
+This requirement for pairing did not
+exist in version 1 of the GSS-API specification, so applications that
+wish to run over version 1 implementations must special-case these
+codes.
+.Sh PARAMETERS
+.Bl -tag
+.It minor_status
+Mechanism specific status code.
+.It initiator_cred_handle
+handle for credentials claimed. Supply
+.Dv GSS_C_NO_CREDENTIAL to act as a default
+initiator principal. If no default
+initiator is defined, the function will
+return
+.Dv GSS_S_NO_CRED.
+.It context_handle
+context handle for new context. Supply
+.Dv GSS_C_NO_CONTEXT for first call; use value
+returned by first call in continuation calls.
+Resources associated with this context-handle
+must be released by the application after use
+with a call to
+.Fn gss_delete_sec_context .
+.It target_name
+Name of target
+.It mech_type
+Object ID of desired mechanism. Supply
+.Dv GSS_C_NO_OID to obtain an implementation
+specific default
+.It req_flags
+Contains various independent flags, each of
+which requests that the context support a
+specific service option. Symbolic
+names are provided for each flag, and the
+symbolic names corresponding to the required
+flags should be logically-ORed
+together to form the bit-mask value. The
+flags are:
+.Bl -tag -width "WW"
+.It GSS_C_DELEG_FLAG
+.Bl -tag -width "False"
+.It True
+Delegate credentials to remote peer
+.It False
+Don't delegate
+.El
+.It GSS_C_MUTUAL_FLAG
+.Bl -tag -width "False"
+.It True
+Request that remote peer authenticate itself
+.It False
+Authenticate self to remote peer only
+.El
+.It GSS_C_REPLAY_FLAG
+.Bl -tag -width "False"
+.It True
+Enable replay detection for messages protected with
+.Xr gss_wrap 3
+or
+.Xr gss_get_mic 3
+.It False
+Don't attempt to detect replayed messages
+.El
+.It GSS_C_SEQUENCE_FLAG
+.Bl -tag -width "False"
+.It True
+Enable detection of out-of-sequence protected messages
+.It False
+Don't attempt to detect out-of-sequence messages
+.El
+.It GSS_C_CONF_FLAG
+.Bl -tag -width "False"
+.It True
+Request that confidentiality service be made available (via
+.Xr gss_wrap 3 )
+.It False
+No per-message confidentiality service is required.
+.El
+.It GSS_C_INTEG_FLAG
+.Bl -tag -width "False"
+.It True
+Request that integrity service be made available (via
+.Xr gss_wrap 3
+or
+.Xr gss_get_mic 3 )
+.It False
+No per-message integrity service is required.
+.El
+.It GSS_C_ANON_FLAG
+.Bl -tag -width "False"
+.It True
+Do not reveal the initiator's identity to the acceptor.
+.It False
+Authenticate normally.
+.El
+.El
+.It time_req
+Desired number of seconds for which context
+should remain valid. Supply 0 to request a
+default validity period.
+.It input_chan_bindings
+Application-specified bindings. Allows
+application to securely bind channel
+identification information to the security
+context. Specify
+.Dv GSS_C_NO_CHANNEL_BINDINGS
+if channel bindings are not used.
+.It input_token
+Token received from peer application.
+Supply
+.Dv GSS_C_NO_BUFFER, or a pointer to
+a buffer containing the value
+.Dv GSS_C_EMPTY_BUFFER
+on initial call.
+.It actual_mech_type
+Actual mechanism used. The OID returned via
+this parameter will be a pointer to static
+storage that should be treated as read-only;
+In particular the application should not attempt
+to free it. Specify
+.Dv NULL if not required.
+.It output_token
+token to be sent to peer application. If
+the length field of the returned buffer is
+zero, no token need be sent to the peer
+application. Storage associated with this
+buffer must be freed by the application
+after use with a call to
+.Xr gss_release_buffer 3 .
+.It ret_flags
+Contains various independent flags, each of which
+indicates that the context supports a specific
+service option. Specify
+.Dv NULL if not
+required. Symbolic names are provided
+for each flag, and the symbolic names
+corresponding to the required flags should be
+logically-ANDed with the
+.Fa ret_flags
+value to test
+whether a given option is supported by the
+context. The flags are:
+.Bl -tag -width "WW"
+.It GSS_C_DELEG_FLAG
+.Bl -tag -width "False"
+.It True
+Credentials were delegated to the remote peer
+.It False
+No credentials were delegated
+.El
+.It GSS_C_MUTUAL_FLAG
+.Bl -tag -width "False"
+.It True
+The remote peer has authenticated itself.
+.It False
+Remote peer has not authenticated itself.
+.El
+.It GSS_C_REPLAY_FLAG
+.Bl -tag -width "False"
+.It True
+Replay of protected messages will be detected
+.It False
+Replayed messages will not be detected
+.El
+.It GSS_C_SEQUENCE_FLAG
+.Bl -tag -width "False"
+.It True
+Out-of-sequence protected messages will be detected
+.It False
+Out-of-sequence messages will not be detected
+.El
+.It GSS_C_CONF_FLAG
+.Bl -tag -width "False"
+.It True
+Confidentiality service may be invoked by calling
+.Xr gss_wrap 3
+routine
+.It False
+No confidentiality service (via
+.Xr gss_wrap 3 ) available.
+.Xr gss_wrap 3 will
+provide message encapsulation,
+data-origin authentication and
+integrity services only.
+.El
+.It GSS_C_INTEG_FLAG
+.Bl -tag -width "False"
+.It True
+Integrity service may be invoked by calling either
+.Xr gss_get_mic 3
+or
+.Xr gss_wrap 3
+routines.
+.It False
+Per-message integrity service unavailable.
+.El
+.It GSS_C_ANON_FLAG
+.Bl -tag -width "False"
+.It True
+The initiator's identity has not been
+revealed, and will not be revealed if
+any emitted token is passed to the
+acceptor.
+.It False
+The initiator's identity has been or will be authenticated normally.
+.El
+.It GSS_C_PROT_READY_FLAG
+.Bl -tag -width "False"
+.It True
+Protection services (as specified by the states of the
+.Dv GSS_C_CONF_FLAG
+and
+.Dv GSS_C_INTEG_FLAG ) are available for
+use if the accompanying major status
+return value is either
+.Dv GSS_S_COMPLETE
+or
+.Dv GSS_S_CONTINUE_NEEDED.
+.It False
+Protection services (as specified by the states of the
+.Dv GSS_C_CONF_FLAG
+and
+.Dv GSS_C_INTEG_FLAG ) are available
+only if the accompanying major status
+return value is
+.Dv GSS_S_COMPLETE.
+.El
+.It GSS_C_TRANS_FLAG
+.Bl -tag -width "False"
+.It True
+The resultant security context may be transferred to other processes via
+a call to
+.Fn gss_export_sec_context .
+.It False
+The security context is not transferable.
+.El
+.El
+.Pp
+All other bits should be set to zero.
+.It time_rec
+Number of seconds for which the context
+will remain valid. If the implementation does
+not support context expiration, the value
+.Dv GSS_C_INDEFINITE will be returned. Specify
+.Dv NULL if not required.
+.El
+.Sh RETURN VALUES
+.Bl -tag
+.It GSS_S_COMPLETE
+Successful completion
+.It GSS_S_CONTINUE_NEEDED
+Indicates that a token from the peer
+application is required to complete the
+context, and that gss_init_sec_context
+must be called again with that token.
+.It GSS_S_DEFECTIVE_TOKEN
+Indicates that consistency checks performed
+on the input_token failed
+.It GSS_S_DEFECTIVE_CREDENTIAL
+Indicates that consistency checks
+performed on the credential failed.
+.It GSS_S_NO_CRED
+The supplied credentials were not valid for
+context initiation, or the credential handle
+did not reference any credentials.
+.It GSS_S_CREDENTIALS_EXPIRED
+The referenced credentials have expired
+.It GSS_S_BAD_BINDINGS
+The input_token contains different channel
+bindings to those specified via the
+input_chan_bindings parameter
+.It GSS_S_BAD_SIG
+The input_token contains an invalid MIC, or a MIC
+that could not be verified
+.It GSS_S_OLD_TOKEN
+The input_token was too old. This is a fatal
+error during context establishment
+.It GSS_S_DUPLICATE_TOKEN
+The input_token is valid, but is a duplicate
+of a token already processed. This is a
+fatal error during context establishment.
+.It GSS_S_NO_CONTEXT
+Indicates that the supplied context handle did
+not refer to a valid context
+.It GSS_S_BAD_NAMETYPE
+The provided target_name parameter contained an
+invalid or unsupported type of name
+.It GSS_S_BAD_NAME
+The provided target_name parameter was ill-formed.
+.It GSS_S_BAD_MECH
+The specified mechanism is not supported by the
+provided credential, or is unrecognized by the
+implementation.
+.El
+.Sh SEE ALSO
+.Xr gss_accept_sec_context 3 ,
+.Xr gss_delete_sec_context 3 ,
+.Xr gss_get_mic 3 ,
+.Xr gss_release_buffer 3 ,
+.Xr gss_wrap 3
+.Sh STANDARDS
+.Bl -tag
+.It RFC 2743
+Generic Security Service Application Program Interface Version 2, Update 1
+.It RFC 2744
+Generic Security Service API Version 2 : C-bindings
+.El
+.\" .Sh HISTORY
+.Sh HISTORY
+The
+.Nm
+manual page example first appeared in
+.Fx 7.0 .
+.Sh AUTHORS
+John Wray, Iris Associates
+.Sh COPYRIGHT
+Copyright (C) The Internet Society (2000). All Rights Reserved.
+.Pp
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it
+or assist in its implementation may be prepared, copied, published
+and distributed, in whole or in part, without restriction of any
+kind, provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing
+the copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of
+developing Internet standards in which case the procedures for
+copyrights defined in the Internet Standards process must be
+followed, or as required to translate it into languages other than
+English.
+.Pp
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+.Pp
+This document and the information contained herein is provided on an
+"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/lib/libgssapi/gss_init_sec_context.c b/lib/libgssapi/gss_init_sec_context.c
new file mode 100644
index 0000000..46e3213
--- /dev/null
+++ b/lib/libgssapi/gss_init_sec_context.c
@@ -0,0 +1,129 @@
+/*-
+ * Copyright (c) 2005 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 <gssapi/gssapi.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "mech_switch.h"
+#include "name.h"
+#include "cred.h"
+#include "context.h"
+
+OM_uint32
+gss_init_sec_context(OM_uint32 * minor_status,
+ const gss_cred_id_t initiator_cred_handle,
+ gss_ctx_id_t * context_handle,
+ const gss_name_t target_name,
+ const gss_OID mech_type,
+ OM_uint32 req_flags,
+ OM_uint32 time_req,
+ const gss_channel_bindings_t input_chan_bindings,
+ const gss_buffer_t input_token,
+ gss_OID * actual_mech_type,
+ gss_buffer_t output_token,
+ OM_uint32 * ret_flags,
+ OM_uint32 * time_rec)
+{
+ OM_uint32 major_status;
+ struct _gss_mech_switch *m;
+ struct _gss_name *name = (struct _gss_name *) target_name;
+ struct _gss_mechanism_name *mn;
+ struct _gss_context *ctx = (struct _gss_context *) *context_handle;
+ struct _gss_cred *cred = (struct _gss_cred *) initiator_cred_handle;
+ struct _gss_mechanism_cred *mc;
+ gss_cred_id_t cred_handle;
+ int allocated_ctx;
+
+ *minor_status = 0;
+
+ /*
+ * If we haven't allocated a context yet, do so now and lookup
+ * the mechanism switch table. If we have one already, make
+ * sure we use the same mechanism switch as before.
+ */
+ if (!ctx) {
+ ctx = malloc(sizeof(struct _gss_context));
+ if (!ctx) {
+ *minor_status = ENOMEM;
+ return (GSS_S_FAILURE);
+ }
+ memset(ctx, 0, sizeof(struct _gss_context));
+ m = ctx->gc_mech = _gss_find_mech_switch(mech_type);
+ if (!m) {
+ free(ctx);
+ return (GSS_S_BAD_MECH);
+ }
+ allocated_ctx = 1;
+ } else {
+ m = ctx->gc_mech;
+ allocated_ctx = 0;
+ }
+
+ /*
+ * Find the MN for this mechanism.
+ */
+ mn = _gss_find_mn(name, mech_type);
+
+ /*
+ * If we have a cred, find the cred for this mechanism.
+ */
+ cred_handle = GSS_C_NO_CREDENTIAL;
+ if (cred) {
+ SLIST_FOREACH(mc, &cred->gc_mc, gmc_link) {
+ if (_gss_oid_equal(mech_type, mc->gmc_mech_oid)) {
+ cred_handle = mc->gmc_cred;
+ break;
+ }
+ }
+ }
+
+ major_status = m->gm_init_sec_context(minor_status,
+ cred_handle,
+ &ctx->gc_ctx,
+ mn->gmn_name,
+ mech_type,
+ req_flags,
+ time_req,
+ input_chan_bindings,
+ input_token,
+ actual_mech_type,
+ output_token,
+ ret_flags,
+ time_rec);
+
+ if (major_status != GSS_S_COMPLETE
+ && major_status != GSS_S_CONTINUE_NEEDED) {
+ if (allocated_ctx)
+ free(ctx);
+ } else {
+ *context_handle = (gss_ctx_id_t) ctx;
+ }
+
+ return (major_status);
+}
diff --git a/lib/libgssapi/gss_inquire_context.3 b/lib/libgssapi/gss_inquire_context.3
new file mode 100644
index 0000000..a527b56
--- /dev/null
+++ b/lib/libgssapi/gss_inquire_context.3
@@ -0,0 +1,284 @@
+.\" -*- nroff -*-
+.\"
+.\" Copyright (c) 2005 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$
+.\"
+.\" The following commands are required for all man pages.
+.Dd November 12, 2005
+.Os
+.Dt GSS_INQUIRE_CONTEXT 3 PRM
+.Sh NAME
+.Nm gss_inquire_context
+.Nd Obtain information about a security context
+.\" This next command is for sections 2 and 3 only.
+.\" .Sh LIBRARY
+.Sh SYNOPSIS
+.In "gssapi/gssapi.h"
+.Ft OM_uint32
+.Fo gss_inquire_context
+.Fa "OM_uint32 *minor_status"
+.Fa "const gss_ctx_id_t context_handle"
+.Fa "gss_name_t *src_name"
+.Fa "gss_name_t *targ_name"
+.Fa "OM_uint32 *lifetime_rec"
+.Fa "gss_OID *mech_type"
+.Fa "OM_uint32 *ctx_flags"
+.Fa "int *locally_initiated"
+.Fa "int *open"
+.Fc
+.Sh DESCRIPTION
+Obtains information about a security context.
+The caller must already have obtained a handle that refers to the
+context,
+although the context need not be fully established.
+.Sh PARAMETERS
+.Bl -tag
+.It minor_status
+Mechanism specific status code.
+.It context_handle
+A handle that refers to the security context.
+.It src_name
+The name of the context initiator.
+If the context was established using anonymous authentication,
+and if the application invoking
+.Fn gss_inquire_context
+is the context acceptor,
+an anonymous name will be returned.
+Storage associated with this name must be freed by the application
+after use with a call to
+.Fn gss_release_name .
+Specify
+.Dv NULL
+if not required.
+.It targ_name
+The name of the context acceptor.
+Storage associated with this name must be freed by the application
+after use with a call to
+.Fn gss_release_name .
+If the context acceptor did not authenticate itself,
+and if the initiator did not specify a target name in its call to
+.Fn gss_init_sec_context ,
+the value
+.Dv GSS_C_NO_NAME
+will be returned.
+Specify
+.Dv NULL
+if not required.
+.It lifetime_rec
+The number of seconds for which the context will remain valid.
+If the context has expired,
+this parameter will be set to zero.
+If the implementation does not support context expiration,
+the value
+.Dv GSS_C_INDEFINITE
+will be returned.
+Specify
+.Dv NULL
+if not required.
+.It mech_type
+The security mechanism providing the context.
+The returned OID will be a pointer to static storage that should be
+treated as read-only by the application;
+in particular the application should not attempt to free it.
+Specify
+.Dv NULL
+if not required.
+.It ctx_flags
+Contains various independent flags,
+each of which indicates that the context supports
+(or is expected to support, if
+.Fa open
+is false)
+a specific service option.
+If not needed, specify
+.Dv NULL .
+Symbolic names are provided for each flag,
+and the symbolic names corresponding to the required flags should be
+logically-ANDed with the
+.Fa ctx_flags
+value to test whether a given option is supported by the context.
+The flags are:
+.Bl -tag -width "WW"
+.It GSS_C_DELEG_FLAG
+.Bl -tag -width "False"
+.It True
+Credentials were delegated from the initiator to the acceptor.
+.It False
+No credentials were delegated.
+.El
+.It GSS_C_MUTUAL_FLAG
+.Bl -tag -width "False"
+.It True
+The acceptor was authenticated to the initiator.
+.It False
+The acceptor did not authenticate itself.
+.El
+.It GSS_C_REPLAY_FLAG
+.Bl -tag -width "False"
+.It True
+Replay of protected messages will be detected.
+.It False
+Replayed messages will not be detected.
+.El
+.It GSS_C_SEQUENCE_FLAG
+.Bl -tag -width "False"
+.It True
+Out-of-sequence protected messages will be detected.
+.It False
+Out-of-sequence messages will not be detected.
+.El
+.It GSS_C_CONF_FLAG
+.Bl -tag -width "False"
+.It True
+Confidentiality service may be invoked by calling
+.Fn gss_wrap
+routine.
+.It False
+No confidentiality service
+(via
+.Fn gss_wrap )
+available.
+.Fn gss_wrap
+will provide message encapsulation,
+data-origin authentication and integrity services only.
+.El
+.It GSS_C_INTEG_FLAG
+.Bl -tag -width "False"
+.It True
+Integrity service may be invoked by calling either
+.Fn gss_get_mic
+or
+.Fn gss_wrap
+routines.
+.It False
+Per-message integrity service unavailable.
+.El
+.It GSS_C_ANON_FLAG
+.Bl -tag -width "False"
+.It True
+The initiator's identity will not be revealed to the acceptor.
+The
+.Fa src_name
+parameter (if requested) contains an anonymous internal name.
+.It False
+The initiator has been authenticated normally.
+.El
+.It GSS_C_PROT_READY_FLAG
+.Bl -tag -width "False"
+.It True
+Protection services
+(as specified by the states of the
+.Dv GSS_C_CONF_FLAG
+and
+.Dv GSS_C_INTEG_FLAG )
+are available for use.
+.It False
+Protection services
+(as specified by the states of the
+.Dv GSS_C_CONF_FLAG
+and
+.Dv GSS_C_INTEG_FLAG )
+are available only if the context is fully established
+(i.e. if the
+.Fa open
+parameter is non-zero).
+.El
+.It GSS_C_TRANS_FLAG
+.Bl -tag -width "False"
+.It True
+The security context may be transferred to other processes via a call to
+.Fn gss_export_sec_context .
+.It False
+The security context is not transferable.
+.El
+.El
+.It locally_initiated
+Non-zero if the invoking application is the context initiator.
+Specify
+.Dv NULL
+if not required.
+.It open
+Non-zero if the context is fully established;
+Zero if a context-establishment token is expected from the peer
+application.
+Specify
+.Dv NULL
+if not required.
+.El
+.Sh RETURN VALUES
+.Bl -tag
+.It GSS_S_COMPLETE
+Successful completion
+.It GSS_S_NO_CONTEXT
+The referenced context could not be accessed
+.El
+.Sh SEE ALSO
+.Xr gss_release_name 3 ,
+.Xr gss_init_sec_context 3 ,
+.Xr gss_wrap 3 ,
+.Xr gss_get_mic 3 ,
+.Xr gss_export_sec_context 3
+.Sh STANDARDS
+.Bl -tag
+.It RFC 2743
+Generic Security Service Application Program Interface Version 2, Update 1
+.It RFC 2744
+Generic Security Service API Version 2 : C-bindings
+.\" .Sh HISTORY
+.El
+.Sh HISTORY
+The
+.Nm
+manual page example first appeared in
+.Fx 7.0 .
+.Sh AUTHORS
+John Wray, Iris Associates
+.Sh COPYRIGHT
+Copyright (C) The Internet Society (2000). All Rights Reserved.
+.Pp
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it
+or assist in its implementation may be prepared, copied, published
+and distributed, in whole or in part, without restriction of any
+kind, provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing
+the copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of
+developing Internet standards in which case the procedures for
+copyrights defined in the Internet Standards process must be
+followed, or as required to translate it into languages other than
+English.
+.Pp
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+.Pp
+This document and the information contained herein is provided on an
+"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/lib/libgssapi/gss_inquire_context.c b/lib/libgssapi/gss_inquire_context.c
new file mode 100644
index 0000000..3f4531d
--- /dev/null
+++ b/lib/libgssapi/gss_inquire_context.c
@@ -0,0 +1,88 @@
+/*-
+ * Copyright (c) 2005 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 <gssapi/gssapi.h>
+
+#include "mech_switch.h"
+#include "context.h"
+#include "name.h"
+
+OM_uint32
+gss_inquire_context(OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ gss_name_t *src_name,
+ gss_name_t *targ_name,
+ OM_uint32 *lifetime_rec,
+ gss_OID *mech_type,
+ OM_uint32 *ctx_flags,
+ int *locally_initiated,
+ int *open)
+{
+ OM_uint32 major_status;
+ struct _gss_context *ctx = (struct _gss_context *) context_handle;
+ struct _gss_mech_switch *m = ctx->gc_mech;
+ struct _gss_name *name;
+ gss_name_t src_mn, targ_mn;
+
+ major_status = m->gm_inquire_context(minor_status,
+ ctx->gc_ctx,
+ src_name ? &src_mn : 0,
+ targ_name ? &targ_mn : 0,
+ lifetime_rec,
+ mech_type,
+ ctx_flags,
+ locally_initiated,
+ open);
+
+ if (src_name) *src_name = 0;
+ if (targ_name) *targ_name = 0;
+
+ if (major_status != GSS_S_COMPLETE) {
+ return (major_status);
+ }
+
+ if (src_name) {
+ name = _gss_make_name(m, src_mn);
+ if (!name) {
+ minor_status = 0;
+ return (GSS_S_FAILURE);
+ }
+ *src_name = (gss_name_t) name;
+ }
+
+ if (targ_name) {
+ name = _gss_make_name(m, targ_mn);
+ if (!name) {
+ minor_status = 0;
+ return (GSS_S_FAILURE);
+ }
+ *targ_name = (gss_name_t) name;
+ }
+
+ return (GSS_S_COMPLETE);
+}
diff --git a/lib/libgssapi/gss_inquire_cred.3 b/lib/libgssapi/gss_inquire_cred.3
new file mode 100644
index 0000000..021bc9c
--- /dev/null
+++ b/lib/libgssapi/gss_inquire_cred.3
@@ -0,0 +1,158 @@
+.\" -*- nroff -*-
+.\"
+.\" Copyright (c) 2005 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$
+.\"
+.\" The following commands are required for all man pages.
+.Dd November 12, 2005
+.Os
+.Dt GSS_INQUIRE_CRED 3 PRM
+.Sh NAME
+.Nm gss_inquire_cred
+.Nd Obtain information about a credential
+.\" This next command is for sections 2 and 3 only.
+.\" .Sh LIBRARY
+.Sh SYNOPSIS
+.In "gssapi/gssapi.h"
+.Ft OM_uint32
+.Fo gss_inquire_cred
+.Fa "OM_uint32 *minor_status"
+.Fa "const gss_cred_id_t cred_handle"
+.Fa "gss_ctx_id_t *context_handle"
+.Fa "gss_name_t *name"
+.Fa "OM_uint32 *lifetime"
+.Fa "gss_cred_usage_t *cred_usage"
+.Fa "gss_OID_set *mechanisms"
+.Fc
+.Sh DESCRIPTION
+Obtains information about a credential.
+.Sh PARAMETERS
+.Bl -tag
+.It minor_status
+Mechanism specific status code.
+.It cred_handle
+A handle that refers to the target credential.
+Specify
+.Dv GSS_C_NO_CREDENTIAL
+to inquire about the default initiator principal.
+.It name
+The name whose identity the credential asserts.
+Storage associated with this name should be freed by the application
+after use with a call to
+.Fn gss_release_name .
+Specify
+.Dv NULL
+if not required.
+.It lifetime
+The number of seconds for which the credential will remain valid.
+If the credential has expired,
+this parameter will be set to zero.
+If the implementation does not support credential expiration,
+the value GSS_C_INDEFINITE will be returned.
+Specify
+.Dv NULL
+if not required.
+.It cred_usage
+How the credential may be used.
+One of the following:
+.Bl -item -offset indent -compact
+.It
+.Dv GSS_C_INITIATE
+.It
+.Dv GSS_C_ACCEPT
+.It
+.Dv GSS_C_BOTH
+.El
+Specify
+.Dv NULL
+if not required.
+.It mechanisms
+Set of mechanisms supported by the credential.
+Storage associated with this OID set must be freed by the application
+after use with a call to
+.Fn gss_release_oid_set .
+Specify
+.Dv NULL
+if not required.
+.El
+.Sh RETURN VALUES
+.Bl -tag
+.It GSS_S_COMPLETE
+Successful completion
+.It GSS_S_NO_CRED
+The referenced credentials could not be accessed
+.It GSS_S_DEFECTIVE_CREDENTIAL
+The referenced credentials were invalid
+.It GSS_S_CREDENTIALS_EXPIRED
+The referenced credentials have expired.
+If the lifetime parameter was not passed as
+.Dv NULL ,
+it will be set to 0
+.El
+.Sh SEE ALSO
+.Xr gss_release_name 3 ,
+.Xr gss_release_oid_set 3
+.Sh STANDARDS
+.Bl -tag
+.It RFC 2743
+Generic Security Service Application Program Interface Version 2, Update 1
+.It RFC 2744
+Generic Security Service API Version 2 : C-bindings
+.\" .Sh HISTORY
+.El
+.Sh HISTORY
+The
+.Nm
+manual page example first appeared in
+.Fx 7.0 .
+.Sh AUTHORS
+John Wray, Iris Associates
+.Sh COPYRIGHT
+Copyright (C) The Internet Society (2000). All Rights Reserved.
+.Pp
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it
+or assist in its implementation may be prepared, copied, published
+and distributed, in whole or in part, without restriction of any
+kind, provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing
+the copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of
+developing Internet standards in which case the procedures for
+copyrights defined in the Internet Standards process must be
+followed, or as required to translate it into languages other than
+English.
+.Pp
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+.Pp
+This document and the information contained herein is provided on an
+"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/lib/libgssapi/gss_inquire_cred.c b/lib/libgssapi/gss_inquire_cred.c
new file mode 100644
index 0000000..6f598b7
--- /dev/null
+++ b/lib/libgssapi/gss_inquire_cred.c
@@ -0,0 +1,167 @@
+/*-
+ * Copyright (c) 2005 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 <gssapi/gssapi.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "mech_switch.h"
+#include "name.h"
+#include "cred.h"
+
+OM_uint32
+gss_inquire_cred(OM_uint32 *minor_status,
+ const gss_cred_id_t cred_handle,
+ gss_name_t *name_ret,
+ OM_uint32 *lifetime,
+ gss_cred_usage_t *cred_usage,
+ gss_OID_set *mechanisms)
+{
+ OM_uint32 major_status;
+ struct _gss_mech_switch *m;
+ struct _gss_cred *cred = (struct _gss_cred *) cred_handle;
+ struct _gss_mechanism_cred *mc;
+ struct _gss_name *name;
+ struct _gss_mechanism_name *mn;
+ OM_uint32 min_lifetime;
+
+ *minor_status = 0;
+ if (name_ret)
+ *name_ret = 0;
+ if (lifetime)
+ *lifetime = 0;
+ if (cred_usage)
+ *cred_usage = 0;
+
+ if (name_ret) {
+ name = malloc(sizeof(struct _gss_name));
+ if (!name) {
+ *minor_status = ENOMEM;
+ return (GSS_S_FAILURE);
+ }
+ memset(name, 0, sizeof(struct _gss_name));
+ SLIST_INIT(&name->gn_mn);
+ } else {
+ name = 0;
+ }
+
+ if (mechanisms) {
+ major_status = gss_create_empty_oid_set(minor_status,
+ mechanisms);
+ if (major_status) {
+ if (name) free(name);
+ return (major_status);
+ }
+ }
+
+ min_lifetime = GSS_C_INDEFINITE;
+ if (cred) {
+ SLIST_FOREACH(mc, &cred->gc_mc, gmc_link) {
+ gss_name_t mc_name;
+ OM_uint32 mc_lifetime;
+
+ major_status = mc->gmc_mech->gm_inquire_cred(minor_status,
+ mc->gmc_cred, &mc_name, &mc_lifetime, NULL, NULL);
+ if (major_status)
+ continue;
+
+ if (name) {
+ mn = malloc(sizeof(struct _gss_mechanism_name));
+ if (!mn) {
+ mc->gmc_mech->gm_release_name(minor_status,
+ &mc_name);
+ continue;
+ }
+ mn->gmn_mech = mc->gmc_mech;
+ mn->gmn_mech_oid = mc->gmc_mech_oid;
+ mn->gmn_name = mc_name;
+ SLIST_INSERT_HEAD(&name->gn_mn, mn, gmn_link);
+ } else {
+ mc->gmc_mech->gm_release_name(minor_status,
+ &mc_name);
+ }
+
+ if (mc_lifetime < min_lifetime)
+ min_lifetime = mc_lifetime;
+
+ if (mechanisms)
+ gss_add_oid_set_member(minor_status,
+ mc->gmc_mech_oid, mechanisms);
+ }
+ } else {
+ SLIST_FOREACH(m, &_gss_mechs, gm_link) {
+ gss_name_t mc_name;
+ OM_uint32 mc_lifetime;
+
+ major_status = m->gm_inquire_cred(minor_status,
+ GSS_C_NO_CREDENTIAL, &mc_name, &mc_lifetime,
+ cred_usage, NULL);
+ if (major_status)
+ continue;
+
+ if (name && mc_name) {
+ mn = malloc(
+ sizeof(struct _gss_mechanism_name));
+ if (!mn) {
+ mc->gmc_mech->gm_release_name(
+ minor_status, &mc_name);
+ continue;
+ }
+ mn->gmn_mech = mc->gmc_mech;
+ mn->gmn_mech_oid = mc->gmc_mech_oid;
+ mn->gmn_name = mc_name;
+ SLIST_INSERT_HEAD(&name->gn_mn, mn, gmn_link);
+ } else if (mc_name) {
+ mc->gmc_mech->gm_release_name(minor_status,
+ &mc_name);
+ }
+
+ if (mc_lifetime < min_lifetime)
+ min_lifetime = mc_lifetime;
+
+ if (mechanisms)
+ gss_add_oid_set_member(minor_status,
+ &m->gm_mech_oid, mechanisms);
+ }
+
+ if ((*mechanisms)->count == 0) {
+ gss_release_oid_set(minor_status, mechanisms);
+ *minor_status = 0;
+ return (GSS_S_NO_CRED);
+ }
+ }
+
+ *minor_status = 0;
+ if (name_ret)
+ *name_ret = (gss_name_t) name;
+ if (lifetime)
+ *lifetime = min_lifetime;
+ if (cred && cred_usage)
+ *cred_usage = cred->gc_usage;
+ return (GSS_S_COMPLETE);
+}
diff --git a/lib/libgssapi/gss_inquire_cred_by_mech.3 b/lib/libgssapi/gss_inquire_cred_by_mech.3
new file mode 100644
index 0000000..15acc0c
--- /dev/null
+++ b/lib/libgssapi/gss_inquire_cred_by_mech.3
@@ -0,0 +1,173 @@
+.\" -*- nroff -*-
+.\"
+.\" Copyright (c) 2005 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$
+.\"
+.\" The following commands are required for all man pages.
+.Dd November 12, 2005
+.Os
+.Dt GSS_INQUIRE_CRED_BY_MECH 3 PRM
+.Sh NAME
+.Nm gss_inquire_cred_by_mech
+.Nd Obtain per-mechanism information about a credential
+.\" This next command is for sections 2 and 3 only.
+.\" .Sh LIBRARY
+.Sh SYNOPSIS
+.In "gssapi/gssapi.h"
+.Ft OM_uint32
+.Fo gss_inquire_cred_by_mech
+.Fa "OM_uint32 *minor_status"
+.Fa "const gss_cred_id_t cred_handle"
+.Fa "const gss_OID mech_type"
+.Fa "gss_name_t *name"
+.Fa "OM_uint32 *initiator_lifetime"
+.Fa "OM_uint32 *acceptor_lifetime"
+.Fa "gss_cred_usage_t *cred_usage"
+.Fc
+.Sh DESCRIPTION
+Obtains per-mechanism information about a credential.
+.Sh PARAMETERS
+.Bl -tag
+.It minor_status
+Mechanism specific status code.
+.It cred_handle
+A handle that refers to the target credential.
+Specify
+.Dv GSS_C_NO_CREDENTIAL
+to inquire about the default initiator principal.
+.It mech_type
+The mechanism for which information should be returned.
+.It name
+The name whose identity the credential asserts.
+Storage associated with this name must be freed by the application
+after use with a call to
+.Fn gss_release_name .
+Specify
+.Dv NULL
+if not required.
+.It initiator_lifetime
+
+The number of seconds for which the credential will remain capable of
+initiating security contexts under the specified mechanism.
+If the credential can no longer be used to initiate contexts,
+or if the credential usage for this mechanism is
+.Dv GSS_C_ACCEPT ,
+this parameter will be set to zero.
+If the implementation does not support expiration of initiator
+credentials,
+the value
+.Dv GSS_C_INDEFINITE
+will be returned.
+Specify
+.Dv NULL
+if not required.
+.It acceptor_lifetime
+The number of seconds for which the credential will remain capable of
+accepting security contexts under the specified mechanism.
+If the credential can no longer be used to accept contexts,
+or if the credential usage for this mechanism is
+.Dv GSS_C_INITIATE ,
+this parameter will be set to zero.
+If the implementation does not support expiration of acceptor
+credentials,
+the value
+.Dv GSS_C_INDEFINITE
+will be returned.
+Specify
+.Dv NULL
+if not required.
+.It cred_usage
+How the credential may be used with the specified mechanism.
+One of the following:
+.Bl -item -offset indent -compact
+.It
+.Dv GSS_C_INITIATE
+.It
+.Dv GSS_C_ACCEPT
+.It
+.Dv GSS_C_BOTH
+.El
+Specify
+.Dv NULL
+if not required.
+.El
+.Sh RETURN VALUES
+.Bl -tag
+.It GSS_S_COMPLETE
+Successful completion
+.It GSS_S_NO_CRED
+The referenced credentials could not be accessed
+.It GSS_S_DEFECTIVE_CREDENTIAL
+The referenced credentials were invalid
+.It GSS_S_CREDENTIALS_EXPIRED
+The referenced credentials have expired.
+If the lifetime parameter was not passed as
+.Dv NULL ,
+it will be set to 0.
+.El
+.Sh SEE ALSO
+.Xr gss_release_name 3
+.Sh STANDARDS
+.Bl -tag
+.It RFC 2743
+Generic Security Service Application Program Interface Version 2, Update 1
+.It RFC 2744
+Generic Security Service API Version 2 : C-bindings
+.\" .Sh HISTORY
+.El
+.Sh HISTORY
+The
+.Nm
+manual page example first appeared in
+.Fx 7.0 .
+.Sh AUTHORS
+John Wray, Iris Associates
+.Sh COPYRIGHT
+Copyright (C) The Internet Society (2000). All Rights Reserved.
+.Pp
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it
+or assist in its implementation may be prepared, copied, published
+and distributed, in whole or in part, without restriction of any
+kind, provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing
+the copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of
+developing Internet standards in which case the procedures for
+copyrights defined in the Internet Standards process must be
+followed, or as required to translate it into languages other than
+English.
+.Pp
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+.Pp
+This document and the information contained herein is provided on an
+"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/lib/libgssapi/gss_inquire_cred_by_mech.c b/lib/libgssapi/gss_inquire_cred_by_mech.c
new file mode 100644
index 0000000..2896f77
--- /dev/null
+++ b/lib/libgssapi/gss_inquire_cred_by_mech.c
@@ -0,0 +1,82 @@
+/*-
+ * Copyright (c) 2005 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 <gssapi/gssapi.h>
+
+#include "mech_switch.h"
+#include "cred.h"
+#include "name.h"
+
+OM_uint32
+gss_inquire_cred_by_mech(OM_uint32 *minor_status,
+ const gss_cred_id_t cred_handle,
+ const gss_OID mech_type,
+ gss_name_t *cred_name,
+ OM_uint32 *initiator_lifetime,
+ OM_uint32 *acceptor_lifetime,
+ gss_cred_usage_t *cred_usage)
+{
+ OM_uint32 major_status;
+ struct _gss_mech_switch *m;
+ struct _gss_mechanism_cred *mcp;
+ gss_cred_id_t mc;
+ gss_name_t mn;
+ struct _gss_name *name;
+
+ *minor_status = 0;
+
+ m = _gss_find_mech_switch(mech_type);
+ if (!m)
+ return (GSS_S_NO_CRED);
+
+ if (cred_handle != GSS_C_NO_CREDENTIAL) {
+ struct _gss_cred *cred = (struct _gss_cred *) cred_handle;
+ SLIST_FOREACH(mcp, &cred->gc_mc, gmc_link)
+ if (mcp->gmc_mech == m)
+ break;
+ if (!mcp)
+ return (GSS_S_NO_CRED);
+ mc = mcp->gmc_cred;
+ } else {
+ mc = GSS_C_NO_CREDENTIAL;
+ }
+
+ major_status = m->gm_inquire_cred_by_mech(minor_status, mc, mech_type,
+ &mn, initiator_lifetime, acceptor_lifetime, cred_usage);
+ if (major_status != GSS_S_COMPLETE)
+ return (major_status);
+
+ name = _gss_make_name(m, mn);
+ if (!name) {
+ m->gm_release_name(minor_status, &mn);
+ return (GSS_S_NO_CRED);
+ }
+
+ *cred_name = (gss_name_t) name;
+ return (GSS_S_COMPLETE);
+}
diff --git a/lib/libgssapi/gss_inquire_mechs_for_name.3 b/lib/libgssapi/gss_inquire_mechs_for_name.3
new file mode 100644
index 0000000..1427a31
--- /dev/null
+++ b/lib/libgssapi/gss_inquire_mechs_for_name.3
@@ -0,0 +1,134 @@
+.\" -*- nroff -*-
+.\"
+.\" Copyright (c) 2005 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$
+.\"
+.\" The following commands are required for all man pages.
+.Dd November 12, 2005
+.Os
+.Dt GSS_INQUIRE_MECHS_FOR_NAME 3 PRM
+.Sh NAME
+.Nm gss_inquire_mechs_for_name
+.Nd List mechanisms that support the specified name-type
+.\" This next command is for sections 2 and 3 only.
+.\" .Sh LIBRARY
+.Sh SYNOPSIS
+.In "gssapi/gssapi.h"
+.Ft OM_uint32
+.Fo gss_inquire_mechs_for_name
+.Fa "OM_uint32 *minor_status"
+.Fa "const gss_name_t input_name"
+.Fa "gss_OID_set *mech_types"
+.Fc
+.Sh DESCRIPTION
+Returns the set of mechanisms supported by the GSS-API implementation
+that may be able to process the specified name.
+.Pp
+
+Each mechanism returned will recognize at least one element within the
+name.
+It is permissible for this routine to be implemented within a
+mechanism-independent GSS-API layer,
+using the type information contained within the presented name,
+and based on registration information provided by individual mechanism
+implementations.
+This means that the returned
+.Fa mech_types
+set may indicate that a particular mechanism will understand the name
+when in fact it would refuse to accept the name as input to
+.Fn gss_canonicalize_name ,
+.Fn gss_init_sec_context ,
+.Fn gss_acquire_cred
+or
+.Fn gss_add_cred
+(due to some property of the specific name, as opposed to the name
+type).
+Thus this routine should be used only as a pre-filter for a call to a
+subsequent mechanism-specific routine.
+.Sh PARAMETERS
+.Bl -tag
+.It minor_status
+Mechanism specific status code.
+.It input_name
+The name to which the inquiry relates.
+.It mech_types
+Set of mechanisms that may support the specified name.
+The returned OID set must be freed by the caller after use with a call
+to
+.Fn gss_release_oid_set .
+.El
+.Sh RETURN VALUES
+.Bl -tag
+.It GSS_S_COMPLETE
+Successful completion
+.It GSS_S_BAD_NAME
+The
+.Fa input_name
+parameter was ill-formed
+.El
+.Sh SEE ALSO
+.Xr gss_release_oid_set 3
+.Sh STANDARDS
+.Bl -tag
+.It RFC 2743
+Generic Security Service Application Program Interface Version 2, Update 1
+.It RFC 2744
+Generic Security Service API Version 2 : C-bindings
+.\" .Sh HISTORY
+.El
+.Sh HISTORY
+The
+.Nm
+manual page example first appeared in
+.Fx 7.0 .
+.Sh AUTHORS
+John Wray, Iris Associates
+.Sh COPYRIGHT
+Copyright (C) The Internet Society (2000). All Rights Reserved.
+.Pp
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it
+or assist in its implementation may be prepared, copied, published
+and distributed, in whole or in part, without restriction of any
+kind, provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing
+the copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of
+developing Internet standards in which case the procedures for
+copyrights defined in the Internet Standards process must be
+followed, or as required to translate it into languages other than
+English.
+.Pp
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+.Pp
+This document and the information contained herein is provided on an
+"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/lib/libgssapi/gss_inquire_mechs_for_name.c b/lib/libgssapi/gss_inquire_mechs_for_name.c
new file mode 100644
index 0000000..10bdd7f
--- /dev/null
+++ b/lib/libgssapi/gss_inquire_mechs_for_name.c
@@ -0,0 +1,77 @@
+/*-
+ * Copyright (c) 2005 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 <gssapi/gssapi.h>
+
+#include "mech_switch.h"
+#include "name.h"
+
+OM_uint32
+gss_inquire_mechs_for_name(OM_uint32 *minor_status,
+ const gss_name_t input_name,
+ gss_OID_set *mech_types)
+{
+ OM_uint32 major_status;
+ struct _gss_name *name = (struct _gss_name *) input_name;
+ struct _gss_mech_switch *m;
+ gss_OID_set name_types;
+ int present;
+
+ *minor_status = 0;
+
+ major_status = gss_create_empty_oid_set(minor_status, mech_types);
+ if (major_status)
+ return (major_status);
+
+ /*
+ * We go through all the loaded mechanisms and see if this
+ * name's type is supported by the mechanism. If it is, add
+ * the mechanism to the set.
+ */
+ SLIST_FOREACH(m, &_gss_mechs, gm_link) {
+ major_status = gss_inquire_names_for_mech(minor_status,
+ &m->gm_mech_oid, &name_types);
+ if (major_status) {
+ gss_release_oid_set(minor_status, mech_types);
+ return (major_status);
+ }
+ gss_test_oid_set_member(minor_status,
+ &name->gn_type, name_types, &present);
+ gss_release_oid_set(minor_status, &name_types);
+ if (present) {
+ major_status = gss_add_oid_set_member(minor_status,
+ &m->gm_mech_oid, mech_types);
+ if (major_status) {
+ gss_release_oid_set(minor_status, mech_types);
+ return (major_status);
+ }
+ }
+ }
+
+ return (GSS_S_COMPLETE);
+}
diff --git a/lib/libgssapi/gss_inquire_names_for_mech.3 b/lib/libgssapi/gss_inquire_names_for_mech.3
new file mode 100644
index 0000000..247f93e
--- /dev/null
+++ b/lib/libgssapi/gss_inquire_names_for_mech.3
@@ -0,0 +1,107 @@
+.\" -*- nroff -*-
+.\"
+.\" Copyright (c) 2005 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$
+.\"
+.\" The following commands are required for all man pages.
+.Dd November 12, 2005
+.Os
+.Dt GSS_INQUIRE_NAMES_FOR_MECH 3 PRM
+.Sh NAME
+.Nm gss_inquire_names_for_mech
+.Nd List the name-types supported by the specified mechanism
+.\" This next command is for sections 2 and 3 only.
+.\" .Sh LIBRARY
+.Sh SYNOPSIS
+.In "gssapi/gssapi.h"
+.Ft OM_uint32
+.Fo gss_inquire_names_for_mech
+.Fa "OM_uint32 *minor_status"
+.Fa "const gss_OID mechanism"
+.Fa "gss_OID_set *name_types"
+.Fc
+.Sh DESCRIPTION
+Returns the set of name-types supported by the specified mechanism.
+.Sh PARAMETERS
+.Bl -tag
+.It minor_status
+Mechanism specific status code.
+.It mechanism
+The mechanism to be interrogated.
+.It name_types
+Set of name-types supported by the specified mechanism.
+The returned OID set must be freed by the application after use with a
+call to
+.Fn gss_release_oid_set .
+.El
+.Sh RETURN VALUES
+.Bl -tag
+.It GSS_S_COMPLETE
+Successful completion
+.El
+.Sh SEE ALSO
+.Xr gss_release_oid_set 3
+.Sh STANDARDS
+.Bl -tag
+.It RFC 2743
+Generic Security Service Application Program Interface Version 2, Update 1
+.It RFC 2744
+Generic Security Service API Version 2 : C-bindings
+.\" .Sh HISTORY
+.El
+.Sh HISTORY
+The
+.Nm
+manual page example first appeared in
+.Fx 7.0 .
+.Sh AUTHORS
+John Wray, Iris Associates
+.Sh COPYRIGHT
+Copyright (C) The Internet Society (2000). All Rights Reserved.
+.Pp
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it
+or assist in its implementation may be prepared, copied, published
+and distributed, in whole or in part, without restriction of any
+kind, provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing
+the copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of
+developing Internet standards in which case the procedures for
+copyrights defined in the Internet Standards process must be
+followed, or as required to translate it into languages other than
+English.
+.Pp
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+.Pp
+This document and the information contained herein is provided on an
+"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/lib/libgssapi/gss_inquire_names_for_mech.c b/lib/libgssapi/gss_inquire_names_for_mech.c
new file mode 100644
index 0000000..3ebb632
--- /dev/null
+++ b/lib/libgssapi/gss_inquire_names_for_mech.c
@@ -0,0 +1,74 @@
+/*-
+ * Copyright (c) 2005 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 <gssapi/gssapi.h>
+
+#include "mech_switch.h"
+
+OM_uint32
+gss_inquire_names_for_mech(OM_uint32 *minor_status,
+ const gss_OID mechanism,
+ gss_OID_set *name_types)
+{
+ OM_uint32 major_status;
+ struct _gss_mech_switch *m = _gss_find_mech_switch(mechanism);
+
+ *minor_status = 0;
+ if (!m)
+ return (GSS_S_BAD_MECH);
+
+ /*
+ * If the implementation can do it, ask it for a list of
+ * names, otherwise fake it.
+ */
+ if (m->gm_inquire_names_for_mech) {
+ return (m->gm_inquire_names_for_mech(minor_status,
+ mechanism, name_types));
+ } else {
+ major_status = gss_create_empty_oid_set(minor_status,
+ name_types);
+ if (major_status)
+ return (major_status);
+ major_status = gss_add_oid_set_member(minor_status,
+ GSS_C_NT_HOSTBASED_SERVICE, name_types);
+ if (major_status) {
+ OM_uint32 ms;
+ gss_release_oid_set(&ms, name_types);
+ return (major_status);
+ }
+ major_status = gss_add_oid_set_member(minor_status,
+ GSS_C_NT_USER_NAME, name_types);
+ if (major_status) {
+ OM_uint32 ms;
+ gss_release_oid_set(&ms, name_types);
+ return (major_status);
+ }
+ }
+
+ return (GSS_S_COMPLETE);
+}
diff --git a/lib/libgssapi/gss_krb5.c b/lib/libgssapi/gss_krb5.c
new file mode 100644
index 0000000..5150f85
--- /dev/null
+++ b/lib/libgssapi/gss_krb5.c
@@ -0,0 +1,87 @@
+/*-
+ * Copyright (c) 2005 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 <gssapi/gssapi.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "mech_switch.h"
+#include "context.h"
+#include "cred.h"
+
+OM_uint32
+gsskrb5_register_acceptor_identity(const char *identity)
+{
+ struct _gss_mech_switch *m;
+
+ _gss_load_mech();
+ SLIST_FOREACH(m, &_gss_mechs, gm_link) {
+ if (m->gm_krb5_register_acceptor_identity)
+ m->gm_krb5_register_acceptor_identity(identity);
+ }
+
+ return (GSS_S_COMPLETE);
+}
+
+OM_uint32
+gss_krb5_copy_ccache(OM_uint32 *minor_status,
+ gss_cred_id_t cred_handle,
+ struct krb5_ccache_data *out)
+{
+ struct _gss_mechanism_cred *mcp;
+ struct _gss_cred *cred = (struct _gss_cred *) cred_handle;
+ struct _gss_mech_switch *m;
+
+ *minor_status = 0;
+
+ SLIST_FOREACH(mcp, &cred->gc_mc, gmc_link) {
+ m = mcp->gmc_mech;
+ if (m->gm_krb5_copy_ccache)
+ return (m->gm_krb5_copy_ccache(minor_status,
+ mcp->gmc_cred, out));
+ }
+
+ return (GSS_S_FAILURE);
+}
+
+OM_uint32
+gss_krb5_compat_des3_mic(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle, int flag)
+{
+ struct _gss_context *ctx = (struct _gss_context *) context_handle;
+ struct _gss_mech_switch *m = ctx->gc_mech;
+
+ *minor_status = 0;
+
+ if (m->gm_krb5_compat_des3_mic)
+ return (m->gm_krb5_compat_des3_mic(minor_status,
+ ctx->gc_ctx, flag));
+
+ return (GSS_S_FAILURE);
+}
+
diff --git a/lib/libgssapi/gss_mech_switch.c b/lib/libgssapi/gss_mech_switch.c
new file mode 100644
index 0000000..a7528a4
--- /dev/null
+++ b/lib/libgssapi/gss_mech_switch.c
@@ -0,0 +1,301 @@
+/*-
+ * Copyright (c) 2005 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 <gssapi/gssapi.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "mech_switch.h"
+#include "utils.h"
+
+#ifndef _PATH_GSS_MECH
+#define _PATH_GSS_MECH "/etc/gss/mech"
+#endif
+
+struct _gss_mech_switch_list _gss_mechs =
+ SLIST_HEAD_INITIALIZER(&_gss_mechs);
+gss_OID_set _gss_mech_oids;
+
+/*
+ * Convert a string containing an OID in 'dot' form
+ * (e.g. 1.2.840.113554.1.2.2) to a gss_OID.
+ */
+static int
+_gss_string_to_oid(const char* s, gss_OID oid)
+{
+ int number_count, i, j;
+ int byte_count;
+ const char *p, *q;
+ char *res;
+
+ /*
+ * First figure out how many numbers in the oid, then
+ * calculate the compiled oid size.
+ */
+ number_count = 0;
+ for (p = s; p; p = q) {
+ q = strchr(p, '.');
+ if (q) q = q + 1;
+ number_count++;
+ }
+
+ /*
+ * The first two numbers are in the first byte and each
+ * subsequent number is encoded in a variable byte sequence.
+ */
+ if (number_count < 2)
+ return (EINVAL);
+
+ /*
+ * We do this in two passes. The first pass, we just figure
+ * out the size. Second time around, we actually encode the
+ * number.
+ */
+ res = 0;
+ for (i = 0; i < 2; i++) {
+ byte_count = 0;
+ for (p = s, j = 0; p; p = q, j++) {
+ unsigned int number = 0;
+
+ /*
+ * Find the end of this number.
+ */
+ q = strchr(p, '.');
+ if (q) q = q + 1;
+
+ /*
+ * Read the number of of the string. Don't
+ * bother with anything except base ten.
+ */
+ while (*p && *p != '.') {
+ number = 10 * number + (*p - '0');
+ p++;
+ }
+
+ /*
+ * Encode the number. The first two numbers
+ * are packed into the first byte. Subsequent
+ * numbers are encoded in bytes seven bits at
+ * a time with the last byte having the high
+ * bit set.
+ */
+ if (j == 0) {
+ if (res)
+ *res = number * 40;
+ } else if (j == 1) {
+ if (res) {
+ *res += number;
+ res++;
+ }
+ byte_count++;
+ } else if (j >= 2) {
+ /*
+ * The number is encoded in seven bit chunks.
+ */
+ unsigned int t;
+ int bytes;
+
+ bytes = 0;
+ for (t = number; t; t >>= 7)
+ bytes++;
+ if (bytes == 0) bytes = 1;
+ while (bytes) {
+ if (res) {
+ int bit = 7*(bytes-1);
+
+ *res = (number >> bit) & 0x7f;
+ if (bytes != 1)
+ *res |= 0x80;
+ res++;
+ }
+ byte_count++;
+ bytes--;
+ }
+ }
+ }
+ if (!res) {
+ res = malloc(byte_count);
+ if (!res)
+ return (ENOMEM);
+ oid->length = byte_count;
+ oid->elements = res;
+ }
+ }
+
+ return (0);
+}
+
+#define SYM(name) \
+do { \
+ m->gm_ ## name = dlsym(so, "gss_" #name); \
+ if (!m->gm_ ## name) { \
+ fprintf(stderr, "can't find symbol gss_" #name "\n"); \
+ goto bad; \
+ } \
+} while (0)
+
+#define OPTSYM(name) \
+do { \
+ m->gm_ ## name = dlsym(so, "gss_" #name); \
+} while (0)
+
+#define OPTSYM2(symname, ourname) \
+do { \
+ m->ourname = dlsym(so, #symname); \
+} while (0)
+
+/*
+ * Load the mechanisms file (/etc/gss/mech).
+ */
+void
+_gss_load_mech(void)
+{
+ OM_uint32 major_status, minor_status;
+ FILE *fp;
+ char buf[256];
+ char *p;
+ char *name, *oid, *lib, *kobj;
+ struct _gss_mech_switch *m;
+ int count;
+ char **pp;
+ void *so;
+
+ if (SLIST_FIRST(&_gss_mechs))
+ return;
+
+ major_status = gss_create_empty_oid_set(&minor_status,
+ &_gss_mech_oids);
+ if (major_status)
+ return;
+
+ fp = fopen(_PATH_GSS_MECH, "r");
+ if (!fp) {
+ perror(_PATH_GSS_MECH);
+ return;
+ }
+
+ count = 0;
+ while (fgets(buf, sizeof(buf), fp)) {
+ if (*buf == '#')
+ continue;
+ p = buf;
+ name = strsep(&p, "\t\n ");
+ if (p) while (isspace(*p)) p++;
+ oid = strsep(&p, "\t\n ");
+ if (p) while (isspace(*p)) p++;
+ lib = strsep(&p, "\t\n ");
+ if (p) while (isspace(*p)) p++;
+ kobj = strsep(&p, "\t\n ");
+ if (!name || !oid || !lib || !kobj)
+ continue;
+
+ so = dlopen(lib, RTLD_LOCAL);
+ if (!so) {
+ fprintf(stderr, "dlopen: %s\n", dlerror());
+ continue;
+ }
+
+ m = malloc(sizeof(struct _gss_mech_switch));
+ if (!m)
+ break;
+ m->gm_so = so;
+ if (_gss_string_to_oid(oid, &m->gm_mech_oid)) {
+ free(m);
+ continue;
+ }
+
+ major_status = gss_add_oid_set_member(&minor_status,
+ &m->gm_mech_oid, &_gss_mech_oids);
+ if (major_status) {
+ free(m->gm_mech_oid.elements);
+ free(m);
+ continue;
+ }
+
+ SYM(acquire_cred);
+ SYM(release_cred);
+ SYM(init_sec_context);
+ SYM(accept_sec_context);
+ SYM(process_context_token);
+ SYM(delete_sec_context);
+ SYM(context_time);
+ SYM(get_mic);
+ SYM(verify_mic);
+ SYM(wrap);
+ SYM(unwrap);
+ SYM(display_status);
+ SYM(indicate_mechs);
+ SYM(compare_name);
+ SYM(display_name);
+ SYM(import_name);
+ SYM(export_name);
+ SYM(release_name);
+ SYM(inquire_cred);
+ SYM(inquire_context);
+ SYM(wrap_size_limit);
+ SYM(add_cred);
+ SYM(inquire_cred_by_mech);
+ SYM(export_sec_context);
+ SYM(import_sec_context);
+ SYM(inquire_names_for_mech);
+ SYM(inquire_mechs_for_name);
+ SYM(canonicalize_name);
+ SYM(duplicate_name);
+ OPTSYM2(gsskrb5_register_acceptor_identity,
+ gm_krb5_register_acceptor_identity);
+ OPTSYM(krb5_copy_ccache);
+ OPTSYM(krb5_compat_des3_mic);
+
+ SLIST_INSERT_HEAD(&_gss_mechs, m, gm_link);
+ count++;
+ continue;
+
+ bad:
+ free(m->gm_mech_oid.elements);
+ free(m);
+ dlclose(so);
+ continue;
+ }
+ fclose(fp);
+}
+
+struct _gss_mech_switch *
+_gss_find_mech_switch(gss_OID mech)
+{
+ struct _gss_mech_switch *m;
+
+ _gss_load_mech();
+ SLIST_FOREACH(m, &_gss_mechs, gm_link) {
+ if (_gss_oid_equal(&m->gm_mech_oid, mech))
+ return m;
+ }
+ return (0);
+}
diff --git a/lib/libgssapi/gss_names.c b/lib/libgssapi/gss_names.c
new file mode 100644
index 0000000..e2fa4cc
--- /dev/null
+++ b/lib/libgssapi/gss_names.c
@@ -0,0 +1,253 @@
+/*-
+ * Copyright (c) 2005 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 <gssapi/gssapi.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "mech_switch.h"
+#include "name.h"
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {10, (void *)"\x2a\x86\x48\x86\xf7\x12"
+ * "\x01\x02\x01\x01"},
+ * corresponding to an object-identifier value of
+ * {iso(1) member-body(2) United States(840) mit(113554)
+ * infosys(1) gssapi(2) generic(1) user_name(1)}. The constant
+ * GSS_C_NT_USER_NAME should be initialized to point
+ * to that gss_OID_desc.
+ */
+static gss_OID_desc GSS_C_NT_USER_NAME_storage =
+ {10, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x01"};
+gss_OID GSS_C_NT_USER_NAME = &GSS_C_NT_USER_NAME_storage;
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {10, (void *)"\x2a\x86\x48\x86\xf7\x12"
+ * "\x01\x02\x01\x02"},
+ * corresponding to an object-identifier value of
+ * {iso(1) member-body(2) United States(840) mit(113554)
+ * infosys(1) gssapi(2) generic(1) machine_uid_name(2)}.
+ * The constant GSS_C_NT_MACHINE_UID_NAME should be
+ * initialized to point to that gss_OID_desc.
+ */
+static gss_OID_desc GSS_C_NT_MACHINE_UID_NAME_storage =
+ {10, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x02"};
+gss_OID GSS_C_NT_MACHINE_UID_NAME = &GSS_C_NT_MACHINE_UID_NAME_storage;
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {10, (void *)"\x2a\x86\x48\x86\xf7\x12"
+ * "\x01\x02\x01\x03"},
+ * corresponding to an object-identifier value of
+ * {iso(1) member-body(2) United States(840) mit(113554)
+ * infosys(1) gssapi(2) generic(1) string_uid_name(3)}.
+ * The constant GSS_C_NT_STRING_UID_NAME should be
+ * initialized to point to that gss_OID_desc.
+ */
+static gss_OID_desc GSS_C_NT_STRING_UID_NAME_storage =
+ {10, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x03"};
+gss_OID GSS_C_NT_STRING_UID_NAME = &GSS_C_NT_STRING_UID_NAME_storage;
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {6, (void *)"\x2b\x06\x01\x05\x06\x02"},
+ * corresponding to an object-identifier value of
+ * {iso(1) org(3) dod(6) internet(1) security(5)
+ * nametypes(6) gss-host-based-services(2)). The constant
+ * GSS_C_NT_HOSTBASED_SERVICE_X should be initialized to point
+ * to that gss_OID_desc. This is a deprecated OID value, and
+ * implementations wishing to support hostbased-service names
+ * should instead use the GSS_C_NT_HOSTBASED_SERVICE OID,
+ * defined below, to identify such names;
+ * GSS_C_NT_HOSTBASED_SERVICE_X should be accepted a synonym
+ * for GSS_C_NT_HOSTBASED_SERVICE when presented as an input
+ * parameter, but should not be emitted by GSS-API
+ * implementations
+ */
+static gss_OID_desc GSS_C_NT_HOSTBASED_SERVICE_X_storage =
+ {6, (void *)"\x2b\x06\x01\x05\x06\x02"};
+gss_OID GSS_C_NT_HOSTBASED_SERVICE_X = &GSS_C_NT_HOSTBASED_SERVICE_X_storage;
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {10, (void *)"\x2a\x86\x48\x86\xf7\x12"
+ * "\x01\x02\x01\x04"}, corresponding to an
+ * object-identifier value of {iso(1) member-body(2)
+ * Unites States(840) mit(113554) infosys(1) gssapi(2)
+ * generic(1) service_name(4)}. The constant
+ * GSS_C_NT_HOSTBASED_SERVICE should be initialized
+ * to point to that gss_OID_desc.
+ */
+static gss_OID_desc GSS_C_NT_HOSTBASED_SERVICE_storage =
+ {10, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x04"};
+gss_OID GSS_C_NT_HOSTBASED_SERVICE = &GSS_C_NT_HOSTBASED_SERVICE_storage;
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {6, (void *)"\x2b\x06\01\x05\x06\x03"},
+ * corresponding to an object identifier value of
+ * {1(iso), 3(org), 6(dod), 1(internet), 5(security),
+ * 6(nametypes), 3(gss-anonymous-name)}. The constant
+ * and GSS_C_NT_ANONYMOUS should be initialized to point
+ * to that gss_OID_desc.
+ */
+static gss_OID_desc GSS_C_NT_ANONYMOUS_storage =
+ {6, (void *)"\x2b\x06\01\x05\x06\x03"};
+gss_OID GSS_C_NT_ANONYMOUS = &GSS_C_NT_ANONYMOUS_storage;
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {6, (void *)"\x2b\x06\x01\x05\x06\x04"},
+ * corresponding to an object-identifier value of
+ * {1(iso), 3(org), 6(dod), 1(internet), 5(security),
+ * 6(nametypes), 4(gss-api-exported-name)}. The constant
+ * GSS_C_NT_EXPORT_NAME should be initialized to point
+ * to that gss_OID_desc.
+ */
+static gss_OID_desc GSS_C_NT_EXPORT_NAME_storage =
+ {6, (void *)"\x2b\x06\x01\x05\x06\x04"};
+gss_OID GSS_C_NT_EXPORT_NAME = &GSS_C_NT_EXPORT_NAME_storage;
+
+/*
+ * This name form shall be represented by the Object Identifier {iso(1)
+ * member-body(2) United States(840) mit(113554) infosys(1) gssapi(2)
+ * krb5(2) krb5_name(1)}. The recommended symbolic name for this type
+ * is "GSS_KRB5_NT_PRINCIPAL_NAME".
+ */
+static gss_OID_desc GSS_KRB5_NT_PRINCIPAL_NAME_storage =
+ {10, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01"};
+gss_OID GSS_KRB5_NT_PRINCIPAL_NAME = &GSS_KRB5_NT_PRINCIPAL_NAME_storage;
+
+/*
+ * This name form shall be represented by the Object Identifier {iso(1)
+ * member-body(2) United States(840) mit(113554) infosys(1) gssapi(2)
+ * generic(1) user_name(1)}. The recommended symbolic name for this
+ * type is "GSS_KRB5_NT_USER_NAME".
+ */
+gss_OID GSS_KRB5_NT_USER_NAME = &GSS_C_NT_USER_NAME_storage;
+
+/*
+ * This name form shall be represented by the Object Identifier {iso(1)
+ * member-body(2) United States(840) mit(113554) infosys(1) gssapi(2)
+ * generic(1) machine_uid_name(2)}. The recommended symbolic name for
+ * this type is "GSS_KRB5_NT_MACHINE_UID_NAME".
+ */
+gss_OID GSS_KRB5_NT_MACHINE_UID_NAME = &GSS_C_NT_MACHINE_UID_NAME_storage;
+
+/*
+ * This name form shall be represented by the Object Identifier {iso(1)
+ * member-body(2) United States(840) mit(113554) infosys(1) gssapi(2)
+ * generic(1) string_uid_name(3)}. The recommended symbolic name for
+ * this type is "GSS_KRB5_NT_STRING_UID_NAME".
+ */
+gss_OID GSS_KRB5_NT_STRING_UID_NAME = &GSS_C_NT_STRING_UID_NAME_storage;
+
+struct _gss_mechanism_name *
+_gss_find_mn(struct _gss_name *name, gss_OID mech)
+{
+ OM_uint32 major_status, minor_status;
+ struct _gss_mech_switch *m;
+ struct _gss_mechanism_name *mn;
+
+ SLIST_FOREACH(mn, &name->gn_mn, gmn_link) {
+ if (_gss_oid_equal(mech, mn->gmn_mech_oid))
+ break;
+ }
+
+ if (!mn) {
+ /*
+ * If this name is canonical (i.e. there is only an
+ * MN but it is from a different mech), give up now.
+ */
+ if (!name->gn_value.value)
+ return (0);
+
+ m = _gss_find_mech_switch(mech);
+ if (!m)
+ return (0);
+
+ mn = malloc(sizeof(struct _gss_mechanism_name));
+ if (!mn)
+ return (0);
+
+ major_status = m->gm_import_name(&minor_status,
+ &name->gn_value,
+ (name->gn_type.elements
+ ? &name->gn_type : GSS_C_NO_OID),
+ &mn->gmn_name);
+ if (major_status) {
+ free(mn);
+ return (0);
+ }
+
+ mn->gmn_mech = m;
+ mn->gmn_mech_oid = &m->gm_mech_oid;
+ SLIST_INSERT_HEAD(&name->gn_mn, mn, gmn_link);
+ }
+ return (mn);
+}
+
+/*
+ * Make a name from an MN.
+ */
+struct _gss_name *
+_gss_make_name(struct _gss_mech_switch *m, gss_name_t new_mn)
+{
+ OM_uint32 minor_status;
+ struct _gss_name *name;
+ struct _gss_mechanism_name *mn;
+
+ name = malloc(sizeof(struct _gss_name));
+ if (!name)
+ return (0);
+ memset(name, 0, sizeof(struct _gss_name));
+
+ mn = malloc(sizeof(struct _gss_mechanism_name));
+ if (!mn) {
+ free(name);
+ return (0);
+ }
+
+ SLIST_INIT(&name->gn_mn);
+ mn->gmn_mech = m;
+ mn->gmn_mech_oid = &m->gm_mech_oid;
+ mn->gmn_name = new_mn;
+ SLIST_INSERT_HEAD(&name->gn_mn, mn, gmn_link);
+
+ return (name);
+}
+
diff --git a/lib/libgssapi/gss_process_context_token.3 b/lib/libgssapi/gss_process_context_token.3
new file mode 100644
index 0000000..3459f0f
--- /dev/null
+++ b/lib/libgssapi/gss_process_context_token.3
@@ -0,0 +1,136 @@
+.\" -*- nroff -*-
+.\"
+.\" Copyright (c) 2005 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$
+.\"
+.\" The following commands are required for all man pages.
+.Dd November 12, 2005
+.Os
+.Dt GSS_PROCESS_CONTEXT_TOKEN 3 PRM
+.Sh NAME
+.Nm gss_process_context_token
+.Nd Process a token on a security context from a peer application
+.\" This next command is for sections 2 and 3 only.
+.\" .Sh LIBRARY
+.Sh SYNOPSIS
+.In "gssapi/gssapi.h"
+.Ft OM_uint32
+.Fo gss_process_context_token
+.Fa "OM_uint32 *minor_status"
+.Fa "const gss_ctx_id_t context_handle"
+.Fa "const gss_buffer_t token_buffer"
+.Fc
+.Sh DESCRIPTION
+Provides a way to pass an asynchronous token to the security service.
+Most context-level tokens are emitted and processed synchronously by
+.Fn gss_init_sec_context
+and
+.Fn gss_accept_sec_context ,
+and the application is informed as to whether further tokens are
+expected by the
+.Dv GSS_C_CONTINUE_NEEDED
+major status bit.
+Occasionally,
+a mechanism may need to emit a context-level token at a point when the
+peer entity is not expecting a token.
+For example,
+the initiator's final call to
+.Fn gss_init_sec_context
+may emit a token and return a status of
+.Dv GSS_S_COMPLETE ,
+but the acceptor's call to
+.Fn gss_accept_sec_context
+may fail.
+The acceptor's mechanism may wish to send a token containing an error
+indication to the initiator,
+but the initiator is not expecting a token at this point,
+believing that the context is fully established.
+.Fn gss_process_context_token
+provides a way to pass such a token to the mechanism at any time.
+.Sh PARAMETERS
+.Bl -tag
+.It minor_status
+Mechanism specific status code.
+.It context_handle
+Context handle of context on which token is to be processed.
+.It token_buffer
+Token to process.
+.El
+.Sh RETURN VALUES
+.Bl -tag
+.It GSS_S_COMPLETE
+Successful completion
+.It GSS_S_DEFECTIVE_TOKEN
+Indicates that consistency checks performed on the token failed
+.It GSS_S_NO_CONTEXT
+The
+.Fa context_handle
+did not refer to a valid context
+.El
+.Sh SEE ALSO
+.Xr gss_init_sec_context 3 ,
+.Xr gss_accept_sec_context 3
+.Sh STANDARDS
+.Bl -tag
+.It RFC 2743
+Generic Security Service Application Program Interface Version 2, Update 1
+.It RFC 2744
+Generic Security Service API Version 2 : C-bindings
+.\" .Sh HISTORY
+.El
+.Sh HISTORY
+The
+.Nm
+manual page example first appeared in
+.Fx 7.0 .
+.Sh AUTHORS
+John Wray, Iris Associates
+.Sh COPYRIGHT
+Copyright (C) The Internet Society (2000). All Rights Reserved.
+.Pp
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it
+or assist in its implementation may be prepared, copied, published
+and distributed, in whole or in part, without restriction of any
+kind, provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing
+the copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of
+developing Internet standards in which case the procedures for
+copyrights defined in the Internet Standards process must be
+followed, or as required to translate it into languages other than
+English.
+.Pp
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+.Pp
+This document and the information contained herein is provided on an
+"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/lib/libgssapi/gss_process_context_token.c b/lib/libgssapi/gss_process_context_token.c
new file mode 100644
index 0000000..0b4d7ec
--- /dev/null
+++ b/lib/libgssapi/gss_process_context_token.c
@@ -0,0 +1,44 @@
+/*-
+ * Copyright (c) 2005 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 <gssapi/gssapi.h>
+
+#include "mech_switch.h"
+#include "context.h"
+
+OM_uint32
+gss_process_context_token(OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_buffer_t token_buffer)
+{
+ struct _gss_context *ctx = (struct _gss_context *) context_handle;
+ struct _gss_mech_switch *m = ctx->gc_mech;
+
+ return (m->gm_process_context_token(minor_status, ctx->gc_ctx,
+ token_buffer));
+}
diff --git a/lib/libgssapi/gss_release_buffer.3 b/lib/libgssapi/gss_release_buffer.3
new file mode 100644
index 0000000..4b43837
--- /dev/null
+++ b/lib/libgssapi/gss_release_buffer.3
@@ -0,0 +1,111 @@
+.\" -*- nroff -*-
+.\"
+.\" Copyright (c) 2005 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$
+.\"
+.\" The following commands are required for all man pages.
+.Dd November 12, 2005
+.Os
+.Dt GSS_RELEASE_BUFFER 3 PRM
+.Sh NAME
+.Nm gss_release_buffer
+.Nd Discard a buffer
+.\" This next command is for sections 2 and 3 only.
+.\" .Sh LIBRARY
+.Sh SYNOPSIS
+.In "gssapi/gssapi.h"
+.Ft OM_uint32
+.Fo gss_release_buffer
+.Fa "OM_uint32 *minor_status"
+.Fa "gss_buffer_t buffer"
+.Fc
+.Sh DESCRIPTION
+Free storage associated with a buffer.
+The storage must have been allocated by a GSS-API routine.
+In addition to freeing the associated storage,
+the routine will zero the length field in the descriptor to which the
+buffer parameter refers,
+and implementations are encouraged to additionally set the pointer
+field in the descriptor to
+.Dv NULL .
+Any buffer object returned by a GSS-API routine may be passed to
+.Fn gss_release_buffer
+(even if there is no storage associated with the buffer).
+.Sh PARAMETERS
+.Bl -tag
+.It minor_status
+Mechanism specific status code.
+.It buffer
+The storage associated with the buffer will be deleted.
+The gss_buffer_desc object will not be freed,
+but its length field will be zeroed.
+.El
+.Sh RETURN VALUES
+.Bl -tag
+.It GSS_S_COMPLETE
+Successful completion
+.El
+.Sh STANDARDS
+.Bl -tag
+.It RFC 2743
+Generic Security Service Application Program Interface Version 2, Update 1
+.It RFC 2744
+Generic Security Service API Version 2 : C-bindings
+.\" .Sh HISTORY
+.El
+.Sh HISTORY
+The
+.Nm
+manual page example first appeared in
+.Fx 7.0 .
+.Sh AUTHORS
+John Wray, Iris Associates
+.Sh COPYRIGHT
+Copyright (C) The Internet Society (2000). All Rights Reserved.
+.Pp
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it
+or assist in its implementation may be prepared, copied, published
+and distributed, in whole or in part, without restriction of any
+kind, provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing
+the copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of
+developing Internet standards in which case the procedures for
+copyrights defined in the Internet Standards process must be
+followed, or as required to translate it into languages other than
+English.
+.Pp
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+.Pp
+This document and the information contained herein is provided on an
+"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/lib/libgssapi/gss_release_buffer.c b/lib/libgssapi/gss_release_buffer.c
new file mode 100644
index 0000000..8e7fa60
--- /dev/null
+++ b/lib/libgssapi/gss_release_buffer.c
@@ -0,0 +1,43 @@
+/*-
+ * Copyright (c) 2005 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 <gssapi/gssapi.h>
+
+OM_uint32
+gss_release_buffer(OM_uint32 *minor_status,
+ gss_buffer_t buffer)
+{
+
+ *minor_status = 0;
+ if (buffer->value)
+ free(buffer->value);
+ buffer->length = 0;
+ buffer->value = 0;
+
+ return (GSS_S_COMPLETE);
+}
diff --git a/lib/libgssapi/gss_release_cred.3 b/lib/libgssapi/gss_release_cred.3
new file mode 100644
index 0000000..1154b89
--- /dev/null
+++ b/lib/libgssapi/gss_release_cred.3
@@ -0,0 +1,108 @@
+.\" -*- nroff -*-
+.\"
+.\" Copyright (c) 2005 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$
+.\"
+.\" The following commands are required for all man pages.
+.Dd November 12, 2005
+.Os
+.Dt GSS_RELEASE_CRED 3 PRM
+.Sh NAME
+.Nm gss_release_cred
+.Nd Discard a credential handle
+.\" This next command is for sections 2 and 3 only.
+.\" .Sh LIBRARY
+.Sh SYNOPSIS
+.In "gssapi/gssapi.h"
+.Ft OM_uint32
+.Fo gss_release_cred
+.Fa "OM_uint32 *minor_status"
+.Fa "gss_cred_id_t *cred_handle"
+.Fc
+.Sh DESCRIPTION
+Informs GSS-API that the specified credential handle is no longer
+required by the application,
+and frees associated resources.
+Implementations are encouraged to set the cred_handle to
+.Dv GSS_C_NO_CREDENTIAL
+on successful completion of this call.
+.Sh PARAMETERS
+.Bl -tag
+.It minor_status
+Mechanism specific status code.
+.It cred_handle
+Opaque handle identifying credential to be released.
+If GSS_C_NO_CREDENTIAL is supplied,
+the routine will complete successfully, but will do nothing.
+.El
+.Sh RETURN VALUES
+.Bl -tag
+.It GSS_S_COMPLETE
+Successful completion
+.It GSS_S_NO_CRED
+Credentials could not be accessed
+.El
+.Sh STANDARDS
+.Bl -tag
+.It RFC 2743
+Generic Security Service Application Program Interface Version 2, Update 1
+.It RFC 2744
+Generic Security Service API Version 2 : C-bindings
+.\" .Sh HISTORY
+.El
+.Sh HISTORY
+The
+.Nm
+manual page example first appeared in
+.Fx 7.0 .
+.Sh AUTHORS
+John Wray, Iris Associates
+.Sh COPYRIGHT
+Copyright (C) The Internet Society (2000). All Rights Reserved.
+.Pp
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it
+or assist in its implementation may be prepared, copied, published
+and distributed, in whole or in part, without restriction of any
+kind, provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing
+the copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of
+developing Internet standards in which case the procedures for
+copyrights defined in the Internet Standards process must be
+followed, or as required to translate it into languages other than
+English.
+.Pp
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+.Pp
+This document and the information contained herein is provided on an
+"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/lib/libgssapi/gss_release_cred.c b/lib/libgssapi/gss_release_cred.c
new file mode 100644
index 0000000..cec814c
--- /dev/null
+++ b/lib/libgssapi/gss_release_cred.c
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 2005 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 <gssapi/gssapi.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "mech_switch.h"
+#include "cred.h"
+
+OM_uint32
+gss_release_cred(OM_uint32 *minor_status, gss_cred_id_t *cred_handle)
+{
+ struct _gss_cred *cred = (struct _gss_cred *) *cred_handle;
+ struct _gss_mechanism_cred *mc;
+
+ if (*cred_handle == GSS_C_NO_CREDENTIAL)
+ return (GSS_S_COMPLETE);
+
+ while (SLIST_FIRST(&cred->gc_mc)) {
+ mc = SLIST_FIRST(&cred->gc_mc);
+ SLIST_REMOVE_HEAD(&cred->gc_mc, gmc_link);
+ mc->gmc_mech->gm_release_cred(minor_status, &mc->gmc_cred);
+ free(mc);
+ }
+ free(cred);
+
+ *minor_status = 0;
+ *cred_handle = 0;
+ return (GSS_S_COMPLETE);
+}
diff --git a/lib/libgssapi/gss_release_name.3 b/lib/libgssapi/gss_release_name.3
new file mode 100644
index 0000000..8c696f8
--- /dev/null
+++ b/lib/libgssapi/gss_release_name.3
@@ -0,0 +1,104 @@
+.\" -*- nroff -*-
+.\"
+.\" Copyright (c) 2005 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$
+.\"
+.\" The following commands are required for all man pages.
+.Dd November 12, 2005
+.Os
+.Dt GSS_RELEASE_NAME 3 PRM
+.Sh NAME
+.Nm gss_release_name
+.Nd Discard an internal-form name
+.\" This next command is for sections 2 and 3 only.
+.\" .Sh LIBRARY
+.Sh SYNOPSIS
+.In "gssapi/gssapi.h"
+.Ft OM_uint32
+.Fo gss_release_name
+.Fa "OM_uint32 *minor_status"
+.Fa "gss_name_t *name"
+.Fc
+.Sh DESCRIPTION
+Free GSS-API allocated storage associated with an internal-form name.
+Implementations are encouraged to set the name to
+.Dv GSS_C_NO_NAME
+on successful completion of this call.
+.Sh PARAMETERS
+.Bl -tag
+.It minor_status
+Mechanism specific status code.
+.It name
+The name to be deleted.
+.El
+.Sh RETURN VALUES
+.Bl -tag
+.It GSS_S_COMPLETE
+Successful completion
+.It GSS_S_BAD_NAME
+The name parameter did not contain a valid name
+.El
+.Sh STANDARDS
+.Bl -tag
+.It RFC 2743
+Generic Security Service Application Program Interface Version 2, Update 1
+.It RFC 2744
+Generic Security Service API Version 2 : C-bindings
+.\" .Sh HISTORY
+.El
+.Sh HISTORY
+The
+.Nm
+manual page example first appeared in
+.Fx 7.0 .
+.Sh AUTHORS
+John Wray, Iris Associates
+.Sh COPYRIGHT
+Copyright (C) The Internet Society (2000). All Rights Reserved.
+.Pp
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it
+or assist in its implementation may be prepared, copied, published
+and distributed, in whole or in part, without restriction of any
+kind, provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing
+the copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of
+developing Internet standards in which case the procedures for
+copyrights defined in the Internet Standards process must be
+followed, or as required to translate it into languages other than
+English.
+.Pp
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+.Pp
+This document and the information contained herein is provided on an
+"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/lib/libgssapi/gss_release_name.c b/lib/libgssapi/gss_release_name.c
new file mode 100644
index 0000000..4294ad7
--- /dev/null
+++ b/lib/libgssapi/gss_release_name.c
@@ -0,0 +1,59 @@
+/*-
+ * Copyright (c) 2005 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 <gssapi/gssapi.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "mech_switch.h"
+#include "name.h"
+
+OM_uint32
+gss_release_name(OM_uint32 *minor_status,
+ gss_name_t *input_name)
+{
+ struct _gss_name *name = (struct _gss_name *) *input_name;
+ struct _gss_mech_switch *m;
+
+ *minor_status = 0;
+ if (name) {
+ if (name->gn_type.elements)
+ free(name->gn_type.elements);
+ while (SLIST_FIRST(&name->gn_mn)) {
+ struct _gss_mechanism_name *mn;
+ mn = SLIST_FIRST(&name->gn_mn);
+ SLIST_REMOVE_HEAD(&name->gn_mn, gmn_link);
+ mn->gmn_mech->gm_release_name(minor_status,
+ &mn->gmn_name);
+ free(mn);
+ }
+ gss_release_buffer(minor_status, &name->gn_value);
+ *input_name = 0;
+ }
+ return (GSS_S_COMPLETE);
+}
diff --git a/lib/libgssapi/gss_release_oid_set.3 b/lib/libgssapi/gss_release_oid_set.3
new file mode 100644
index 0000000..0f17628
--- /dev/null
+++ b/lib/libgssapi/gss_release_oid_set.3
@@ -0,0 +1,109 @@
+.\" -*- nroff -*-
+.\"
+.\" Copyright (c) 2005 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$
+.\"
+.\" The following commands are required for all man pages.
+.Dd November 12, 2005
+.Os
+.Dt GSS_RELEASE_OID_SET 3 PRM
+.Sh NAME
+.Nm gss_release_oid_set
+.Nd Discard a set of object identifiers
+.\" This next command is for sections 2 and 3 only.
+.\" .Sh LIBRARY
+.Sh SYNOPSIS
+.In "gssapi/gssapi.h"
+.Ft OM_uint32
+.Fo gss_release_oid_set
+.Fa "OM_uint32 *minor_status"
+.Fa "gss_OID_set *set"
+.Fc
+.Sh DESCRIPTION
+Free storage associated with a GSS-API generated gss_OID_set object.
+The set parameter must refer to an OID-set that was returned from a
+GSS-API routine.
+.Fn gss_release_oid_set
+will free the storage associated with each individual member OID,
+the OID set's elements array,
+and the gss_OID_set_desc itself.
+.Pp
+Implementations are encouraged to set the gss_OID_set parameter to
+.Dv GSS_C_NO_OID_SET
+on successful completion of this routine.
+.Sh PARAMETERS
+.Bl -tag
+.It minor_status
+Mechanism specific status code.
+.It set
+The storage associated with the gss_OID_set will be deleted.
+.El
+.Sh RETURN VALUES
+.Bl -tag
+.It GSS_S_COMPLETE
+Successful completion
+.El
+.Sh STANDARDS
+.Bl -tag
+.It RFC 2743
+Generic Security Service Application Program Interface Version 2, Update 1
+.It RFC 2744
+Generic Security Service API Version 2 : C-bindings
+.\" .Sh HISTORY
+.El
+.Sh HISTORY
+The
+.Nm
+manual page example first appeared in
+.Fx 7.0 .
+.Sh AUTHORS
+John Wray, Iris Associates
+.Sh COPYRIGHT
+Copyright (C) The Internet Society (2000). All Rights Reserved.
+.Pp
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it
+or assist in its implementation may be prepared, copied, published
+and distributed, in whole or in part, without restriction of any
+kind, provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing
+the copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of
+developing Internet standards in which case the procedures for
+copyrights defined in the Internet Standards process must be
+followed, or as required to translate it into languages other than
+English.
+.Pp
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+.Pp
+This document and the information contained herein is provided on an
+"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/lib/libgssapi/gss_release_oid_set.c b/lib/libgssapi/gss_release_oid_set.c
new file mode 100644
index 0000000..49c17ab
--- /dev/null
+++ b/lib/libgssapi/gss_release_oid_set.c
@@ -0,0 +1,46 @@
+/*-
+ * Copyright (c) 2005 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 <gssapi/gssapi.h>
+#include <stdlib.h>
+#include <errno.h>
+
+OM_uint32
+gss_release_oid_set(OM_uint32 *minor_status,
+ gss_OID_set *set)
+{
+
+ *minor_status = 0;
+ if (*set) {
+ if ((*set)->elements)
+ free((*set)->elements);
+ free(*set);
+ *set = 0;
+ }
+ return (GSS_S_COMPLETE);
+}
diff --git a/lib/libgssapi/gss_seal.c b/lib/libgssapi/gss_seal.c
new file mode 100644
index 0000000..c3e3f7a
--- /dev/null
+++ b/lib/libgssapi/gss_seal.c
@@ -0,0 +1,45 @@
+/*-
+ * Copyright (c) 2005 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 <gssapi/gssapi.h>
+
+OM_uint32
+gss_seal(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ int qop_req,
+ gss_buffer_t input_message_buffer,
+ int *conf_state,
+ gss_buffer_t output_message_buffer)
+{
+
+ return (gss_wrap(minor_status,
+ context_handle, conf_req_flag, qop_req,
+ input_message_buffer, conf_state,
+ output_message_buffer));
+}
diff --git a/lib/libgssapi/gss_sign.c b/lib/libgssapi/gss_sign.c
new file mode 100644
index 0000000..c521a7e
--- /dev/null
+++ b/lib/libgssapi/gss_sign.c
@@ -0,0 +1,41 @@
+/*-
+ * Copyright (c) 2005 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 <gssapi/gssapi.h>
+
+OM_uint32
+gss_sign(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ int qop_req,
+ gss_buffer_t message_buffer,
+ gss_buffer_t message_token)
+{
+
+ return gss_get_mic(minor_status,
+ context_handle, qop_req, message_buffer, message_token);
+}
diff --git a/lib/libgssapi/gss_test_oid_set_member.3 b/lib/libgssapi/gss_test_oid_set_member.3
new file mode 100644
index 0000000..8269637
--- /dev/null
+++ b/lib/libgssapi/gss_test_oid_set_member.3
@@ -0,0 +1,116 @@
+.\" -*- nroff -*-
+.\"
+.\" Copyright (c) 2005 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$
+.\"
+.\" The following commands are required for all man pages.
+.Dd November 12, 2005
+.Os
+.Dt GSS_TEST_OID_SET_MEMBER 3 PRM
+.Sh NAME
+.Nm gss_test_oid_set_member
+.Nd Determines whether an object identifier is a member of a set
+.\" This next command is for sections 2 and 3 only.
+.\" .Sh LIBRARY
+.Sh SYNOPSIS
+.In "gssapi/gssapi.h"
+.Ft OM_uint32
+.Fo gss_test_oid_set_member
+.Fa "OM_uint32 *minor_status"
+.Fa "const gss_OID member"
+.Fa "const gss_OID_set set"
+.Fa "int *present"
+.Fc
+.Sh DESCRIPTION
+Interrogate an Object Identifier set to determine whether a specified
+Object Identifier is a member.
+This routine is intended to be used with OID sets returned by
+.Fn gss_indicate_mechs ,
+.Fn gss_acquire_cred ,
+and
+.Fn gss_inquire_cred ,
+but will also work with user-generated sets.
+.Sh PARAMETERS
+.Bl -tag
+.It minor_status
+Mechanism specific status code.
+.It member
+The object identifier whose presence is to be tested.
+.It set
+The Object Identifier set.
+.It present
+Non-zero if the specified OID is a member of the set, zero if not.
+.El
+.Sh RETURN VALUES
+.Bl -tag
+.It GSS_S_COMPLETE
+Successful completion
+.El
+.Sh SEE ALSO
+.Xr gss_indicate_mechs 3 ,
+.Xr gss_acquire_cred 3 ,
+.Xr gss_inquire_cred 3
+.Sh STANDARDS
+.Bl -tag
+.It RFC 2743
+Generic Security Service Application Program Interface Version 2, Update 1
+.It RFC 2744
+Generic Security Service API Version 2 : C-bindings
+.\" .Sh HISTORY
+.El
+.Sh HISTORY
+The
+.Nm
+manual page example first appeared in
+.Fx 7.0 .
+.Sh AUTHORS
+John Wray, Iris Associates
+.Sh COPYRIGHT
+Copyright (C) The Internet Society (2000). All Rights Reserved.
+.Pp
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it
+or assist in its implementation may be prepared, copied, published
+and distributed, in whole or in part, without restriction of any
+kind, provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing
+the copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of
+developing Internet standards in which case the procedures for
+copyrights defined in the Internet Standards process must be
+followed, or as required to translate it into languages other than
+English.
+.Pp
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+.Pp
+This document and the information contained herein is provided on an
+"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/lib/libgssapi/gss_test_oid_set_member.c b/lib/libgssapi/gss_test_oid_set_member.c
new file mode 100644
index 0000000..1a09540
--- /dev/null
+++ b/lib/libgssapi/gss_test_oid_set_member.c
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 2005 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 <gssapi/gssapi.h>
+
+static int
+_gss_oid_equal(const gss_OID oid1, const gss_OID oid2)
+{
+ if (oid1->length != oid2->length)
+ return (0);
+ if (memcmp(oid1->elements, oid2->elements, oid1->length))
+ return (0);
+ return (1);
+}
+
+OM_uint32
+gss_test_oid_set_member(OM_uint32 *minor_status,
+ const gss_OID member,
+ const gss_OID_set set,
+ int *present)
+{
+ int i;
+
+ *present = 0;
+ for (i = 0; i < set->count; i++)
+ if (_gss_oid_equal(member, &set->elements[i]))
+ *present = 1;
+
+ *minor_status = 0;
+ return (GSS_S_COMPLETE);
+}
diff --git a/lib/libgssapi/gss_unseal.c b/lib/libgssapi/gss_unseal.c
new file mode 100644
index 0000000..bc7dc26
--- /dev/null
+++ b/lib/libgssapi/gss_unseal.c
@@ -0,0 +1,43 @@
+/*-
+ * Copyright (c) 2005 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 <gssapi/gssapi.h>
+
+OM_uint32
+gss_unseal(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ gss_buffer_t input_message_buffer,
+ gss_buffer_t output_message_buffer,
+ int *conf_state,
+ int *qop_state)
+{
+
+ return (gss_unwrap(minor_status,
+ context_handle, input_message_buffer,
+ output_message_buffer, conf_state, qop_state));
+}
diff --git a/lib/libgssapi/gss_unwrap.3 b/lib/libgssapi/gss_unwrap.3
new file mode 100644
index 0000000..d422ae5
--- /dev/null
+++ b/lib/libgssapi/gss_unwrap.3
@@ -0,0 +1,191 @@
+.\" -*- nroff -*-
+.\"
+.\" Copyright (c) 2005 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$
+.\"
+.\" The following commands are required for all man pages.
+.Dd November 12, 2005
+.Os
+.Dt GSS_UNWRAP 3 PRM
+.Sh NAME
+.Nm gss_unwrap ,
+.Nm gss_unseal
+.Nd Convert a message previously protected by
+.Xr gss_wrap 3
+back to a usable form
+.\" This next command is for sections 2 and 3 only.
+.\" .Sh LIBRARY
+.Sh SYNOPSIS
+.In "gssapi/gssapi.h"
+.Ft OM_uint32
+.Fo gss_unwrap
+.Fa "OM_uint32 *minor_status"
+.Fa "const gss_ctx_id_t context_handle"
+.Fa "const gss_buffer_t input_message_buffer"
+.Fa "gss_buffer_t output_message_buffer"
+.Fa "int *conf_state"
+.Fa "gss_qop_t *qop_state"
+.Fc
+.Ft OM_uint32
+.Fo gss_unseal
+.Fa "OM_uint32 *minor_status"
+.Fa "gss_ctx_id_t context_handle"
+.Fa "gss_buffer_t input_message_buffer"
+.Fa "gss_buffer_t output_message_buffer"
+.Fa "int *conf_state"
+.Fa "gss_qop_t *qop_state"
+.Fc
+.Sh DESCRIPTION
+Converts a message previously protected by
+.Xr gss_wrap 3
+back to a usable form,
+verifying the embedded MIC.
+The
+.Dv conf_state
+parameter indicates whether the message was encrypted;
+the
+.Dv qop_state
+parameter indicates the strength of protection that was used to provide the
+confidentiality and integrity services.
+.Pp
+Since some application-level protocols may wish to use tokens emitted
+by
+.Xr gss_wrap 3
+to provide "secure framing",
+implementations must support the wrapping and unwrapping of
+zero-length messages.
+.Pp
+The
+.Fn gss_unseal
+routine is an obsolete variant of
+.Fn gss_unwrap .
+It is
+provided for backwards
+compatibility with applications using the GSS-API V1 interface.
+A distinct entrypoint (as opposed to #define) is provided,
+both to allow GSS-API V1 applications to link
+and to retain the slight parameter type differences between the
+obsolete versions of this routine and its current form.
+.Sh PARAMETERS
+.Bl -tag
+.It minor_status
+Mechanism specific status code.
+.It context_handle
+Identifies the context on which the message arrived.
+.It input_message_buffer
+Protected message.
+.It output_message_buffer
+Buffer to receive unwrapped message.
+Storage associated with this buffer must
+be freed by the application after use use
+with a call to
+.Xr gss_release_buffer 3 .
+.It conf_state
+.Bl -tag -width "Non-zero"
+.It Non-zero
+Confidentiality and integrity protection were used.
+.It Zero
+Integrity service only was used.
+.El
+.Pp
+Specify NULL if not required.
+.It qop_state
+Quality of protection provided. Specify NULL if not required.
+.El
+.Sh RETURN VALUES
+.Bl -tag
+.It GSS_S_COMPLETE
+Successful completion.
+.It GSS_S_DEFECTIVE_TOKEN
+The token failed consistency checks.
+.It GSS_S_BAD_SIG
+The MIC was incorrect
+.It GSS_S_DUPLICATE_TOKEN
+The token was valid, and contained a correct
+MIC for the message, but it had already been
+processed.
+.It GSS_S_OLD_TOKEN
+The token was valid, and contained a correct MIC
+for the message, but it is too old to check for
+duplication.
+.It GSS_S_UNSEQ_TOKEN
+The token was valid, and contained a correct MIC
+for the message, but has been verified out of
+sequence; a later token has already been
+received.
+.It GSS_S_GAP_TOKEN
+The token was valid, and contained a correct MIC
+for the message, but has been verified out of
+sequence; an earlier expected token has not yet
+been received.
+.It GSS_S_CONTEXT_EXPIRED
+The context has already expired.
+.It GSS_S_NO_CONTEXT
+The context_handle parameter did not identify a valid context.
+.El
+.Sh SEE ALSO
+.Xr gss_wrap 3 ,
+.Xr gss_release_buffer 3
+.Sh STANDARDS
+.Bl -tag
+.It RFC 2743
+Generic Security Service Application Program Interface Version 2, Update 1
+.It RFC 2744
+Generic Security Service API Version 2 : C-bindings
+.\" .Sh HISTORY
+.Sh HISTORY
+The
+.Nm
+manual page example first appeared in
+.Fx 7.0 .
+.Sh AUTHORS
+John Wray, Iris Associates
+.Sh COPYRIGHT
+Copyright (C) The Internet Society (2000). All Rights Reserved.
+.Pp
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it
+or assist in its implementation may be prepared, copied, published
+and distributed, in whole or in part, without restriction of any
+kind, provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing
+the copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of
+developing Internet standards in which case the procedures for
+copyrights defined in the Internet Standards process must be
+followed, or as required to translate it into languages other than
+English.
+.Pp
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+.Pp
+This document and the information contained herein is provided on an
+"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/lib/libgssapi/gss_unwrap.c b/lib/libgssapi/gss_unwrap.c
new file mode 100644
index 0000000..9ccc848
--- /dev/null
+++ b/lib/libgssapi/gss_unwrap.c
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 2005 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 <gssapi/gssapi.h>
+
+#include "mech_switch.h"
+#include "context.h"
+
+OM_uint32
+gss_unwrap(OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_buffer_t input_message_buffer,
+ gss_buffer_t output_message_buffer,
+ int *conf_state,
+ gss_qop_t *qop_state)
+{
+ struct _gss_context *ctx = (struct _gss_context *) context_handle;
+ struct _gss_mech_switch *m = ctx->gc_mech;
+
+ return (m->gm_unwrap(minor_status, ctx->gc_ctx,
+ input_message_buffer, output_message_buffer,
+ conf_state, qop_state));
+}
diff --git a/lib/libgssapi/gss_utils.c b/lib/libgssapi/gss_utils.c
new file mode 100644
index 0000000..d9f3e89
--- /dev/null
+++ b/lib/libgssapi/gss_utils.c
@@ -0,0 +1,79 @@
+/*-
+ * Copyright (c) 2005 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 <gssapi/gssapi.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "utils.h"
+
+int
+_gss_oid_equal(const gss_OID oid1, const gss_OID oid2)
+{
+ if (oid1->length != oid2->length)
+ return (0);
+ if (memcmp(oid1->elements, oid2->elements, oid1->length))
+ return (0);
+ return (1);
+}
+
+OM_uint32
+_gss_copy_oid(OM_uint32 *minor_status,
+ const gss_OID from_oid, gss_OID to_oid)
+{
+ size_t len = from_oid->length;
+
+ *minor_status = 0;
+ to_oid->elements = malloc(len);
+ if (!to_oid->elements) {
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+ to_oid->length = len;
+ memcpy(to_oid->elements, from_oid->elements, len);
+ return (GSS_S_COMPLETE);
+}
+
+
+OM_uint32
+_gss_copy_buffer(OM_uint32 *minor_status,
+ const gss_buffer_t from_buf, gss_buffer_t to_buf)
+{
+ size_t len = from_buf->length;
+
+ *minor_status = 0;
+ to_buf->value = malloc(len);
+ if (!to_buf->value) {
+ *minor_status = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+ to_buf->length = len;
+ memcpy(to_buf->value, from_buf->value, len);
+ return (GSS_S_COMPLETE);
+}
+
diff --git a/lib/libgssapi/gss_verify.c b/lib/libgssapi/gss_verify.c
new file mode 100644
index 0000000..3110875
--- /dev/null
+++ b/lib/libgssapi/gss_verify.c
@@ -0,0 +1,41 @@
+/*-
+ * Copyright (c) 2005 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 <gssapi/gssapi.h>
+
+OM_uint32
+gss_verify(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ gss_buffer_t message_buffer,
+ gss_buffer_t token_buffer,
+ int *qop_state)
+{
+
+ return (gss_verify_mic(minor_status,
+ context_handle, message_buffer, token_buffer, qop_state));
+}
diff --git a/lib/libgssapi/gss_verify_mic.3 b/lib/libgssapi/gss_verify_mic.3
new file mode 100644
index 0000000..ab63706
--- /dev/null
+++ b/lib/libgssapi/gss_verify_mic.3
@@ -0,0 +1,172 @@
+.\" -*- nroff -*-
+.\"
+.\" Copyright (c) 2005 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$
+.\"
+.\" The following commands are required for all man pages.
+.Dd November 12, 2005
+.Os
+.Dt GSS_VERIFY_MIC 3 PRM
+.Sh NAME
+.Nm gss_verify_mic ,
+.Nm gss_verify
+.Nd Check a MIC against a message; verify integrity of a received message
+.\" This next command is for sections 2 and 3 only.
+.\" .Sh LIBRARY
+.Sh SYNOPSIS
+.In "gssapi/gssapi.h"
+.Ft OM_uint32
+.Fo gss_verify_mic
+.Fa "OM_uint32 *minor_status"
+.Fa "const gss_ctx_id_t context_handle"
+.Fa "const gss_buffer_t message_buffer"
+.Fa "const gss_buffer_t token_buffer"
+.Fa "gss_qop_t *qop_state"
+.Fc
+.Ft OM_uint32
+.Fo gss_verify
+.Fa "OM_uint32 *minor_status"
+.Fa "gss_ctx_id_t context_handle"
+.Fa "gss_buffer_t message_buffer"
+.Fa "gss_buffer_t token_buffer"
+.Fa "gss_qop_t *qop_state"
+.Fc
+.Sh DESCRIPTION
+Verifies that a cryptographic MIC,
+contained in the token parameter,
+fits the supplied message.
+The
+.Fa qop_state
+parameter allows a message recipient to determine the strength of
+protection that was applied to the message.
+.Pp
+Since some application-level protocols may wish to use tokens emitted
+by
+.Fn gss_wrap
+to provide "secure framing",
+implementations must support the calculation and verification of MICs
+over zero-length messages.
+.Pp
+The
+.Fn gss_verify
+routine is an obsolete variant of
+.Fn gss_verify_mic .
+It is provided for backwards
+compatibility with applications using the GSS-API V1 interface.
+A distinct entrypoint (as opposed to #define) is provided,
+both to allow GSS-API V1 applications to link
+and to retain the slight parameter type differences between the
+obsolete versions of this routine and its current form.
+.Sh PARAMETERS
+.Bl -tag
+.It minor_status
+Mechanism specific status code.
+.It context_handle
+Identifies the context on which the message arrived.
+.It message_buffer
+Message to be verified.
+.It token_buffer
+Token associated with message.
+.It qop_state
+Quality of protection gained from MIC.
+Specify
+.Dv NULL
+if not required.
+.El
+.Sh RETURN VALUES
+.Bl -tag
+.It GSS_S_COMPLETE
+Successful completion
+.It GSS_S_DEFECTIVE_TOKEN
+The token failed consistency checks
+.It GSS_S_BAD_SIG
+The MIC was incorrect
+.It GSS_S_DUPLICATE_TOKEN
+The token was valid,
+and contained a correct MIC for the message,
+but it had already been processed
+.It GSS_S_OLD_TOKEN
+The token was valid,
+and contained a correct MIC for the message,
+but it is too old to check for duplication
+.It GSS_S_UNSEQ_TOKEN
+The token was valid,
+and contained a correct MIC for the message,
+but has been verified out of sequence;
+a later token has already been received.
+.It GSS_S_GAP_TOKEN
+The token was valid,
+and contained a correct MIC for the message,
+but has been verified out of sequence;
+an earlier expected token has not yet been received
+.It GSS_S_CONTEXT_EXPIRED
+The context has already expired
+.It GSS_S_NO_CONTEXT
+The context_handle parameter did not identify a valid context
+.El
+.Sh SEE ALSO
+.Xr gss_wrap 3
+.Sh STANDARDS
+.Bl -tag
+.It RFC 2743
+Generic Security Service Application Program Interface Version 2, Update 1
+.It RFC 2744
+Generic Security Service API Version 2 : C-bindings
+.\" .Sh HISTORY
+.El
+.Sh HISTORY
+The
+.Nm
+manual page example first appeared in
+.Fx 7.0 .
+.Sh AUTHORS
+John Wray, Iris Associates
+.Sh COPYRIGHT
+Copyright (C) The Internet Society (2000). All Rights Reserved.
+.Pp
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it
+or assist in its implementation may be prepared, copied, published
+and distributed, in whole or in part, without restriction of any
+kind, provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing
+the copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of
+developing Internet standards in which case the procedures for
+copyrights defined in the Internet Standards process must be
+followed, or as required to translate it into languages other than
+English.
+.Pp
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+.Pp
+This document and the information contained herein is provided on an
+"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/lib/libgssapi/gss_verify_mic.c b/lib/libgssapi/gss_verify_mic.c
new file mode 100644
index 0000000..4e11ab1
--- /dev/null
+++ b/lib/libgssapi/gss_verify_mic.c
@@ -0,0 +1,46 @@
+/*-
+ * Copyright (c) 2005 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 <gssapi/gssapi.h>
+
+#include "mech_switch.h"
+#include "context.h"
+
+OM_uint32
+gss_verify_mic(OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ const gss_buffer_t message_buffer,
+ const gss_buffer_t token_buffer,
+ gss_qop_t *qop_state)
+{
+ struct _gss_context *ctx = (struct _gss_context *) context_handle;
+ struct _gss_mech_switch *m = ctx->gc_mech;
+
+ return (m->gm_verify_mic(minor_status, ctx->gc_ctx,
+ message_buffer, token_buffer, qop_state));
+}
diff --git a/lib/libgssapi/gss_wrap.3 b/lib/libgssapi/gss_wrap.3
new file mode 100644
index 0000000..3b81c68
--- /dev/null
+++ b/lib/libgssapi/gss_wrap.3
@@ -0,0 +1,178 @@
+.\" -*- nroff -*-
+.\"
+.\" Copyright (c) 2005 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$
+.\"
+.\" The following commands are required for all man pages.
+.Dd November 12, 2005
+.Os
+.Dt GSS_WRAP 3 PRM
+.Sh NAME
+.Nm gss_wrap ,
+.Nm gss_seal
+.Nd Attach a cryptographic MIC and optionally encrypt a message
+.\" This next command is for sections 2 and 3 only.
+.\" .Sh LIBRARY
+.Sh SYNOPSIS
+.In "gssapi/gssapi.h"
+.Ft OM_uint32
+.Fo gss_wrap
+.Fa "OM_uint32 *minor_status"
+.Fa "const gss_ctx_id_t context_handle"
+.Fa "int conf_req_flag"
+.Fa "gss_qop_t qop_req"
+.Fa "const gss_buffer_t input_message_buffer"
+.Fa "int *conf_state"
+.Fa "gss_buffer_t output_message_buffer"
+.Fc
+.Ft OM_uint32
+.Fo gss_seal
+.Fa "OM_uint32 *minor_status"
+.Fa "gss_ctx_id_t context_handle"
+.Fa "int conf_req_flag"
+.Fa "gss_qop_t qop_req"
+.Fa "gss_buffer_t input_message_buffer"
+.Fa "int *conf_state"
+.Fa "gss_buffer_t output_message_buffer"
+.Fc
+.Sh DESCRIPTION
+Attaches a cryptographic MIC and optionally encrypts the specified
+.Dv input_message .
+The output_message contains both the MIC and the message.
+The
+.Dv qop_req
+parameter allows a choice between several cryptographic algorithms,
+if supported by the chosen mechanism.
+.Pp
+Since some application-level protocols may wish to use tokens emitted
+by
+.Fn gss_wrap
+to provide "secure framing",
+implementations must support the wrapping of zero-length messages.
+.Pp
+The
+.Fn gss_seal
+routine is an obsolete variant of
+.Fn gss_wrap .
+It is
+provided for backwards
+compatibility with applications using the GSS-API V1 interface.
+A distinct entrypoint (as opposed to #define) is provided,
+both to allow GSS-API V1 applications to link
+and to retain the slight parameter type differences between the
+obsolete versions of this routine and its current form.
+.Sh PARAMETERS
+.Bl -tag
+.It minor_status
+Mechanism specific status code.
+.It context_handle
+Identifies the context on which the message will be sent.
+.It conf_req_flag
+.Bl -tag -width "Non-zero"
+.It Non-zero
+Both confidentiality and integrity services are requested.
+.It Zero
+Only integrity service is requested.
+.El
+.It qop_req
+Specifies required quality of protection.
+A mechanism-specific default may be requested by setting qop_req to
+.Dv GSS_C_QOP_DEFAULT .
+If an unsupported protection strength is requested,
+.Fn gss_wrap
+will return a major_status of
+.Dv GSS_S_BAD_QOP .
+.It input_message_buffer
+Message to be protected.
+.It conf_state
+.Bl -tag -width "Non-zero"
+.It Non-zero
+Confidentiality, data origin authentication and integrity services
+have been applied.
+.It Zero
+Integrity and data origin services only has been applied.
+.El
+.It output_message_buffer
+Buffer to receive protected message.
+Storage associated with this buffer must
+be freed by the application after use use
+with a call to
+.Xr gss_release_buffer 3 .
+.El
+.Sh RETURN VALUES
+.Bl -tag
+.It GSS_S_COMPLETE
+Successful completion.
+.It GSS_S_CONTEXT_EXPIRED
+The context has already expired
+.It GSS_S_NO_CONTEXT
+The context_handle parameter did not identify a valid context.
+.It GSS_S_BAD_QOP
+The specified QOP is not supported by the mechanism.
+.El
+.Sh SEE ALSO
+.Xr gss_unwrap 3 ,
+.Xr gss_release_buffer 3
+.Sh STANDARDS
+.Bl -tag
+.It RFC 2743
+Generic Security Service Application Program Interface Version 2, Update 1
+.It RFC 2744
+Generic Security Service API Version 2 : C-bindings
+.\" .Sh HISTORY
+.Sh HISTORY
+The
+.Nm
+manual page example first appeared in
+.Fx 7.0 .
+.Sh AUTHORS
+John Wray, Iris Associates
+.Sh COPYRIGHT
+Copyright (C) The Internet Society (2000). All Rights Reserved.
+.Pp
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it
+or assist in its implementation may be prepared, copied, published
+and distributed, in whole or in part, without restriction of any
+kind, provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing
+the copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of
+developing Internet standards in which case the procedures for
+copyrights defined in the Internet Standards process must be
+followed, or as required to translate it into languages other than
+English.
+.Pp
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+.Pp
+This document and the information contained herein is provided on an
+"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/lib/libgssapi/gss_wrap.c b/lib/libgssapi/gss_wrap.c
new file mode 100644
index 0000000..0d7c749
--- /dev/null
+++ b/lib/libgssapi/gss_wrap.c
@@ -0,0 +1,49 @@
+/*-
+ * Copyright (c) 2005 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 <gssapi/gssapi.h>
+
+#include "mech_switch.h"
+#include "context.h"
+
+OM_uint32
+gss_wrap(OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ const gss_buffer_t input_message_buffer,
+ int *conf_state,
+ gss_buffer_t output_message_buffer)
+{
+ struct _gss_context *ctx = (struct _gss_context *) context_handle;
+ struct _gss_mech_switch *m = ctx->gc_mech;
+
+ return (m->gm_wrap(minor_status, ctx->gc_ctx,
+ conf_req_flag, qop_req, input_message_buffer,
+ conf_state, output_message_buffer));
+}
diff --git a/lib/libgssapi/gss_wrap_size_limit.3 b/lib/libgssapi/gss_wrap_size_limit.3
new file mode 100644
index 0000000..fe93ca6
--- /dev/null
+++ b/lib/libgssapi/gss_wrap_size_limit.3
@@ -0,0 +1,163 @@
+.\" -*- nroff -*-
+.\"
+.\" Copyright (c) 2005 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$
+.\"
+.\" The following commands are required for all man pages.
+.Dd November 12, 2005
+.Os
+.Dt GSS_WRAP_SIZE_LIMIT 3 PRM
+.Sh NAME
+.Nm gss_wrap_size_limit
+.Nd Determine maximum message sizes
+.\" This next command is for sections 2 and 3 only.
+.\" .Sh LIBRARY
+.Sh SYNOPSIS
+.In "gssapi/gssapi.h"
+.Ft OM_uint32
+.Fo gss_wrap_size_limit
+.Fa "OM_uint32 *minor_status"
+.Fa "const gss_ctx_id_t context_handle"
+.Fa "int conf_req_flag"
+.Fa "gss_qop_t qop_req"
+.Fa "OM_uint32 req_output_size"
+.Fa "OM_uint32 *max_input_size"
+.Fc
+.Sh DESCRIPTION
+Allows an application to determine the maximum message size that,
+if presented to
+.Xr gss_wrap 3
+with the same
+.Dv conf_req_flag
+and
+.Dv qop_req
+parameters,
+will result in an output token containing no more than
+.Dv req_output_size
+bytes.
+.Pp
+This call is intended for use by applications that
+communicate over protocols that impose a maximum message size.
+It enables the application to fragment messages prior to applying protection.
+.Pp
+GSS-API implementations are recommended but not required to detect
+invalid QOP values when
+.Fn gss_wrap_size_limit
+is called.
+This routine guarantees only a maximum message size,
+not the availability of specific QOP values for message protection.
+.Pp
+Successful completion of this call does not guarantee that
+.Xr gss_wrap 3
+will be able to protect a message of length max_input_size bytes,
+since this ability may depend on the availability of system resources
+at the time that
+.Xr gss_wrap 3
+is called.
+However, if the implementation itself imposes an upper limit on
+the length of messages that may be processed by gss_wrap,
+the implementation should not return a value via
+.Dv max_input_bytes
+that is greater than this length.
+.Sh PARAMETERS
+.Bl -tag
+.It minor_status
+Mechanism specific status code.
+.It context_handle
+A handle that refers to the security over which the messages will be sent.
+.It conf_req_flag
+Indicates whether
+.Xr gss_wrap 3
+will be asked to apply confidentiality protection
+in addition to integrity protection.
+.It qop_req
+Indicates the level of protection that
+.Xr gss_wrap 3
+will be asked to provide.
+.It req_output_size
+The desired maximum size for tokens emitted by
+.Xr gss_wrap 3 .
+.It max_input_size
+The maximum input message size that may be presented to
+.Xr gss_wrap 3
+in order to guarantee that the emitted token shall
+be no larger than
+.Dv req_output_size
+bytes.
+.El
+.Sh RETURN VALUES
+.Bl -tag
+.It GSS_S_COMPLETE
+Successful completion.
+.It GSS_S_NO_CONTEXT
+The referenced context could not be accessed.
+.It GSS_S_CONTEXT_EXPIRED
+The context has expired.
+.It GSS_S_BAD_QOP
+The specified QOP is not supported by the mechanism.
+.El
+.Sh SEE ALSO
+.Xr gss_wrap 3
+.Sh STANDARDS
+.Bl -tag
+.It RFC 2743
+Generic Security Service Application Program Interface Version 2, Update 1
+.It RFC 2744
+Generic Security Service API Version 2 : C-bindings
+.\" .Sh HISTORY
+.Sh HISTORY
+The
+.Nm
+manual page example first appeared in
+.Fx 7.0 .
+.Sh AUTHORS
+John Wray, Iris Associates
+.Sh COPYRIGHT
+Copyright (C) The Internet Society (2000). All Rights Reserved.
+.Pp
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it
+or assist in its implementation may be prepared, copied, published
+and distributed, in whole or in part, without restriction of any
+kind, provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing
+the copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of
+developing Internet standards in which case the procedures for
+copyrights defined in the Internet Standards process must be
+followed, or as required to translate it into languages other than
+English.
+.Pp
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+.Pp
+This document and the information contained herein is provided on an
+"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/lib/libgssapi/gss_wrap_size_limit.c b/lib/libgssapi/gss_wrap_size_limit.c
new file mode 100644
index 0000000..8abd52a
--- /dev/null
+++ b/lib/libgssapi/gss_wrap_size_limit.c
@@ -0,0 +1,47 @@
+/*-
+ * Copyright (c) 2005 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 <gssapi/gssapi.h>
+
+#include "mech_switch.h"
+#include "context.h"
+
+OM_uint32
+gss_wrap_size_limit(OM_uint32 *minor_status,
+ const gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ OM_uint32 req_output_size,
+ OM_uint32 *max_input_size)
+{
+ struct _gss_context *ctx = (struct _gss_context *) context_handle;
+ struct _gss_mech_switch *m = ctx->gc_mech;
+
+ return (m->gm_wrap_size_limit(minor_status, ctx->gc_ctx,
+ conf_req_flag, qop_req, req_output_size, max_input_size));
+}
diff --git a/lib/libgssapi/gssapi.3 b/lib/libgssapi/gssapi.3
new file mode 100644
index 0000000..ce26e7e
--- /dev/null
+++ b/lib/libgssapi/gssapi.3
@@ -0,0 +1,261 @@
+.\" -*- nroff -*-
+.\"
+.\" Copyright (c) 2005 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$
+.\"
+.Dd November 30, 2005
+.Dt GSSAPI 3
+.Os
+.Sh NAME
+.Nm gssapi
+.Nd "Generic Security Services API"
+.Sh LIBRARY
+GSS-API Library (libgssapi, -lgssapi)
+.Sh SYNOPSIS
+.In gssapi/gssapi.h
+.Sh DESCRIPTION
+The Generic Security Service Application Programming Interface
+provides security services to its callers,
+and is intended for implementation atop a variety of underlying
+cryptographic mechanisms.
+Typically, GSS-API callers will be application protocols into which
+security enhancements are integrated through invocation of services
+provided by the GSS-API.
+The GSS-API allows a caller application to authenticate a principal
+identity associated with a peer application, to delegate rights to a
+peer,
+and to apply security services such as confidentiality and integrity
+on a per-message basis.
+.Pp
+There are four stages to using the GSS-API:
+.Pp
+.Bl -tag -width "a)"
+.It a)
+The application acquires a set of credentials with which it may prove
+its identity to other processes.
+The application's credentials vouch for its global identity,
+which may or may not be related to any local username under which it
+may be running.
+.It b)
+A pair of communicating applications establish a joint security
+context using their credentials.
+The security context is a pair of GSS-API data structures that contain
+shared state information, which is required in order that per-message
+security services may be provided.
+Examples of state that might be shared between applications as part of
+a security context are cryptographic keys,
+and message sequence numbers.
+As part of the establishment of a security context,
+the context initiator is authenticated to the responder,
+and may require that the responder is authenticated in turn.
+The initiator may optionally give the responder the right to initiate
+further security contexts,
+acting as an agent or delegate of the initiator.
+This transfer of rights is termed delegation,
+and is achieved by creating a set of credentials,
+similar to those used by the initiating application,
+but which may be used by the responder.
+.Pp
+To establish and maintain the shared information that makes up the
+security context,
+certain GSS-API calls will return a token data structure,
+which is an opaque data type that may contain cryptographically
+protected data.
+The caller of such a GSS-API routine is responsible for transferring
+the token to the peer application,
+encapsulated if necessary in an application protocol.
+On receipt of such a token, the peer application should pass it to a
+corresponding GSS-API routine which will decode the token and extract
+the information,
+updating the security context state information accordingly.
+.It c)
+Per-message services are invoked to apply either:
+.Pp
+integrity and data origin authentication, or confidentiality,
+integrity and data origin authentication to application data,
+which are treated by GSS-API as arbitrary octet-strings.
+An application transmitting a message that it wishes to protect will
+call the appropriate GSS-API routine (gss_get_mic or gss_wrap) to
+apply protection,
+specifying the appropriate security context,
+and send the resulting token to the receiving application.
+The receiver will pass the received token (and, in the case of data
+protected by gss_get_mic, the accompanying message-data) to the
+corresponding decoding routine (gss_verify_mic or gss_unwrap) to
+remove the protection and validate the data.
+.It d)
+At the completion of a communications session (which may extend across
+several transport connections),
+each application calls a GSS-API routine to delete the security
+context.
+Multiple contexts may also be used (either successively or
+simultaneously) within a single communications association, at the
+option of the applications.
+.El
+.Sh GSS-API ROUTINES
+This section lists the routines that make up the GSS-API,
+and offers a brief description of the purpose of each routine.
+.Pp
+GSS-API Credential-management Routines:
+.Bl -tag -width "gss_inquire_cred_by_mech"
+.It gss_acquire_cred
+Assume a global identity; Obtain a GSS-API credential handle for
+pre-existing credentials.
+.It gss_add_cred
+Construct credentials incrementally
+.It gss_inquire_cred
+Obtain information about a credential
+.It gss_inquire_cred_by_mech
+Obtain per-mechanism information about a credential.
+.It gss_release_cred
+Discard a credential handle.
+.El
+.Pp
+GSS-API Context-Level Routines:
+.Bl -tag -width "gss_inquire_cred_by_mech"
+.It gss_init_sec_context
+Initiate a security context with a peer application
+.It gss_accept_sec_context
+ Accept a security context initiated by a peer application
+.It gss_delete_sec_context
+Discard a security context
+.It gss_process_context_token
+Process a token on a security context from a peer application
+.It gss_context_time
+Determine for how long a context will remain valid
+.It gss_inquire_context
+Obtain information about a security context
+.It gss_wrap_size_limit
+Determine token-size limit for
+.Xr gss_wrap 3
+on a context
+.It gss_export_sec_context
+Transfer a security context to another process
+.It gss_import_sec_context
+Import a transferred context
+.El
+.Pp
+GSS-API Per-message Routines:
+.Bl -tag -width "gss_inquire_cred_by_mech"
+.It gss_get_mic
+Calculate a cryptographic message integrity code (MIC) for a message;
+integrity service
+.It gss_verify_mic
+Check a MIC against a message;
+verify integrity of a received message
+.It gss_wrap
+Attach a MIC to a message, and optionally encrypt the message content;
+confidentiality service
+.It gss_unwrap
+Verify a message with attached MIC, and decrypt message content if
+necessary.
+.El
+.Pp
+GSS-API Name manipulation Routines:
+.Bl -tag -width "gss_inquire_cred_by_mech"
+.It gss_import_name
+Convert a contiguous string name to internal-form
+.It gss_display_name
+Convert internal-form name to text
+.It gss_compare_name
+Compare two internal-form names
+.It gss_release_name
+Discard an internal-form name
+.It gss_inquire_names_for_mech
+List the name-types supported by the specified mechanism
+.It gss_inquire_mechs_for_name
+List mechanisms that support the specified name-type
+.It gss_canonicalize_name
+Convert an internal name to an MN
+.It gss_export_name
+Convert an MN to export form
+.It gss_duplicate_name
+Create a copy of an internal name
+.El
+.Pp
+GSS-API Miscellaneous Routines
+.Bl -tag -width "gss_inquire_cred_by_mech"
+.It gss_add_oid_set_member
+Add an object identifier to a set
+.It gss_display_status
+Convert a GSS-API status code to text
+.It gss_indicate_mechs
+Determine available underlying authentication mechanisms
+.It gss_release_buffer
+Discard a buffer
+.It gss_release_oid_set
+Discard a set of object identifiers
+.It gss_create_empty_oid_set
+Create a set containing no object identifiers
+.It gss_test_oid_set_member
+Determines whether an object identifier is a member of a set.
+.El
+.Pp
+Individual GSS-API implementations may augment these routines by
+providing additional mechanism-specific routines if required
+functionality is not available from the generic forms.
+Applications are encouraged to use the generic routines wherever
+possible on portability grounds.
+.Sh STANDARDS
+.Bl -tag
+.It RFC 2743
+Generic Security Service Application Program Interface Version 2, Update 1
+.It RFC 2744
+Generic Security Service API Version 2 : C-bindings
+.El
+.Sh HISTORY
+The
+.Nm
+manual page first appeared in
+.Fx 7.0 .
+.Sh AUTHORS
+John Wray, Iris Associates
+.Sh COPYRIGHT
+Copyright (C) The Internet Society (2000). All Rights Reserved.
+.Pp
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it
+or assist in its implementation may be prepared, copied, published
+and distributed, in whole or in part, without restriction of any
+kind, provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing
+the copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of
+developing Internet standards in which case the procedures for
+copyrights defined in the Internet Standards process must be
+followed, or as required to translate it into languages other than
+English.
+.Pp
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+.Pp
+This document and the information contained herein is provided on an
+"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/lib/libgssapi/mech.5 b/lib/libgssapi/mech.5
new file mode 100644
index 0000000..1edcc1a
--- /dev/null
+++ b/lib/libgssapi/mech.5
@@ -0,0 +1,94 @@
+.\" Copyright (c) 2005 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$
+.Dd November 14, 2005
+.Dt MECH 5
+.Os
+.Sh NAME
+.Nm mech ,
+.Nm qop
+.Nd "GSS-API Mechanism and QOP files"
+.Sh SYNOPSIS
+.Pa "/etc/gss/mech"
+.Pa "/etc/gss/qop"
+.Sh DESCRIPTION
+The
+.Pa "/etc/gss/mech"
+file contains a list of installed GSS-API security mechanisms.
+Each line of the file either contains a comment if the first character
+is '#' or it contains five fields with the following meanings:
+.Bl -tag
+.It Name
+The name of this GSS-API mechanism.
+.It Object identifier
+The OID for this mechanism.
+.It Library
+A shared library containing the implementation of this mechanism.
+.It Kernel module (optional)
+A kernel module containing the implementation of this mechanism (not
+yet supported in FreeBSD).
+.It Library options (optional)
+Optionsal parameters interpreted by the mechanism. Library options
+must be enclosed in brackets ([ ]) to differentiate them from the
+optional kernel module entry.
+.El
+.Pp
+The
+.Pa "/etc/gss/qop"
+file contains a list of Quality of Protection values for use with
+GSS-API.
+Each line of the file either contains a comment if the first character
+is '#' or it contains three fields with the following meanings:
+.Bl -tag
+.It QOP string
+The name of this Quality of Protection algorithm.
+.It QOP value
+The numeric value used to select this algorithm for use with GSS-API
+functions such as
+.Xr gss_get_mic 3 .
+.It Mechanism name
+The GSS-API mechanism name that corresponds to this algorithm.
+.El
+.Sh EXAMPLES
+This is a typical entry from
+.Pa "/etc/gss/mech" :
+.Bd -literal
+kerberosv5 1.2.840.113554.1.2.2 /usr/lib/libgssapi_krb5.so.8 -
+.Ed
+.Pp
+This is a typical entry from
+.Pa "/etc/gss/qop" :
+.Bd -literal
+GSS_KRB5_CONF_C_QOP_DES 0x0100 kerberosv5
+.Ed
+.Sh HISTORY
+The
+.Nm
+manual page example first appeared in
+.Fx 7.0 .
+.Sh AUTHORS
+This
+manual page was written by
+.An Doug Rabson Aq dfr@FreeBSD.org .
diff --git a/lib/libgssapi/mech_switch.h b/lib/libgssapi/mech_switch.h
new file mode 100644
index 0000000..4add12d
--- /dev/null
+++ b/lib/libgssapi/mech_switch.h
@@ -0,0 +1,327 @@
+/*-
+ * Copyright (c) 2005 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 <sys/queue.h>
+
+typedef OM_uint32 _gss_acquire_cred_t
+ (OM_uint32 *, /* minor_status */
+ const gss_name_t, /* desired_name */
+ OM_uint32, /* time_req */
+ const gss_OID_set, /* desired_mechs */
+ gss_cred_usage_t, /* cred_usage */
+ gss_cred_id_t *, /* output_cred_handle */
+ gss_OID_set *, /* actual_mechs */
+ OM_uint32 * /* time_rec */
+ );
+
+typedef OM_uint32 _gss_release_cred_t
+ (OM_uint32 *, /* minor_status */
+ gss_cred_id_t * /* cred_handle */
+ );
+
+typedef OM_uint32 _gss_init_sec_context_t
+ (OM_uint32 *, /* minor_status */
+ const gss_cred_id_t, /* initiator_cred_handle */
+ gss_ctx_id_t *, /* context_handle */
+ const gss_name_t, /* target_name */
+ const gss_OID, /* mech_type */
+ OM_uint32, /* req_flags */
+ OM_uint32, /* time_req */
+ const gss_channel_bindings_t,
+ /* input_chan_bindings */
+ const gss_buffer_t, /* input_token */
+ gss_OID *, /* actual_mech_type */
+ gss_buffer_t, /* output_token */
+ OM_uint32 *, /* ret_flags */
+ OM_uint32 * /* time_rec */
+ );
+
+typedef OM_uint32 _gss_accept_sec_context_t
+ (OM_uint32 *, /* minor_status */
+ gss_ctx_id_t *, /* context_handle */
+ const gss_cred_id_t, /* acceptor_cred_handle */
+ const gss_buffer_t, /* input_token_buffer */
+ const gss_channel_bindings_t,
+ /* input_chan_bindings */
+ gss_name_t *, /* src_name */
+ gss_OID *, /* mech_type */
+ gss_buffer_t, /* output_token */
+ OM_uint32 *, /* ret_flags */
+ OM_uint32 *, /* time_rec */
+ gss_cred_id_t * /* delegated_cred_handle */
+ );
+
+typedef OM_uint32 _gss_process_context_token_t
+ (OM_uint32 *, /* minor_status */
+ const gss_ctx_id_t, /* context_handle */
+ const gss_buffer_t /* token_buffer */
+ );
+
+typedef OM_uint32 _gss_delete_sec_context_t
+ (OM_uint32 *, /* minor_status */
+ gss_ctx_id_t *, /* context_handle */
+ gss_buffer_t /* output_token */
+ );
+
+typedef OM_uint32 _gss_context_time_t
+ (OM_uint32 *, /* minor_status */
+ const gss_ctx_id_t, /* context_handle */
+ OM_uint32 * /* time_rec */
+ );
+
+typedef OM_uint32 _gss_get_mic_t
+ (OM_uint32 *, /* minor_status */
+ const gss_ctx_id_t, /* context_handle */
+ gss_qop_t, /* qop_req */
+ const gss_buffer_t, /* message_buffer */
+ gss_buffer_t /* message_token */
+ );
+
+typedef OM_uint32 _gss_verify_mic_t
+ (OM_uint32 *, /* minor_status */
+ const gss_ctx_id_t, /* context_handle */
+ const gss_buffer_t, /* message_buffer */
+ const gss_buffer_t, /* token_buffer */
+ gss_qop_t * /* qop_state */
+ );
+
+typedef OM_uint32 _gss_wrap_t
+ (OM_uint32 *, /* minor_status */
+ const gss_ctx_id_t, /* context_handle */
+ int, /* conf_req_flag */
+ gss_qop_t, /* qop_req */
+ const gss_buffer_t, /* input_message_buffer */
+ int *, /* conf_state */
+ gss_buffer_t /* output_message_buffer */
+ );
+
+typedef OM_uint32 _gss_unwrap_t
+ (OM_uint32 *, /* minor_status */
+ const gss_ctx_id_t, /* context_handle */
+ const gss_buffer_t, /* input_message_buffer */
+ gss_buffer_t, /* output_message_buffer */
+ int *, /* conf_state */
+ gss_qop_t * /* qop_state */
+ );
+
+typedef OM_uint32 _gss_display_status_t
+ (OM_uint32 *, /* minor_status */
+ OM_uint32, /* status_value */
+ int, /* status_type */
+ const gss_OID, /* mech_type */
+ OM_uint32 *, /* message_context */
+ gss_buffer_t /* status_string */
+ );
+
+typedef OM_uint32 _gss_indicate_mechs_t
+ (OM_uint32 *, /* minor_status */
+ gss_OID_set * /* mech_set */
+ );
+
+typedef OM_uint32 _gss_compare_name_t
+ (OM_uint32 *, /* minor_status */
+ const gss_name_t, /* name1 */
+ const gss_name_t, /* name2 */
+ int * /* name_equal */
+ );
+
+typedef OM_uint32 _gss_display_name_t
+ (OM_uint32 *, /* minor_status */
+ const gss_name_t, /* input_name */
+ gss_buffer_t, /* output_name_buffer */
+ gss_OID * /* output_name_type */
+ );
+
+typedef OM_uint32 _gss_import_name_t
+ (OM_uint32 *, /* minor_status */
+ const gss_buffer_t, /* input_name_buffer */
+ const gss_OID, /* input_name_type */
+ gss_name_t * /* output_name */
+ );
+
+typedef OM_uint32 _gss_export_name_t
+ (OM_uint32 *, /* minor_status */
+ const gss_name_t, /* input_name */
+ gss_buffer_t /* exported_name */
+ );
+
+typedef OM_uint32 _gss_release_name_t
+ (OM_uint32 *, /* minor_status */
+ gss_name_t * /* input_name */
+ );
+
+typedef OM_uint32 _gss_inquire_cred_t
+ (OM_uint32 *, /* minor_status */
+ const gss_cred_id_t, /* cred_handle */
+ gss_name_t *, /* name */
+ OM_uint32 *, /* lifetime */
+ gss_cred_usage_t *, /* cred_usage */
+ gss_OID_set * /* mechanisms */
+ );
+
+typedef OM_uint32 _gss_inquire_context_t
+ (OM_uint32 *, /* minor_status */
+ const gss_ctx_id_t, /* context_handle */
+ gss_name_t *, /* src_name */
+ gss_name_t *, /* targ_name */
+ OM_uint32 *, /* lifetime_rec */
+ gss_OID *, /* mech_type */
+ OM_uint32 *, /* ctx_flags */
+ int *, /* locally_initiated */
+ int * /* open */
+ );
+
+typedef OM_uint32 _gss_wrap_size_limit_t
+ (OM_uint32 *, /* minor_status */
+ const gss_ctx_id_t, /* context_handle */
+ int, /* conf_req_flag */
+ gss_qop_t, /* qop_req */
+ OM_uint32, /* req_output_size */
+ OM_uint32 * /* max_input_size */
+ );
+
+typedef OM_uint32 _gss_add_cred_t (
+ OM_uint32 *, /* minor_status */
+ const gss_cred_id_t, /* input_cred_handle */
+ const gss_name_t, /* desired_name */
+ const gss_OID, /* desired_mech */
+ gss_cred_usage_t, /* cred_usage */
+ OM_uint32, /* initiator_time_req */
+ OM_uint32, /* acceptor_time_req */
+ gss_cred_id_t *, /* output_cred_handle */
+ gss_OID_set *, /* actual_mechs */
+ OM_uint32 *, /* initiator_time_rec */
+ OM_uint32 * /* acceptor_time_rec */
+ );
+
+typedef OM_uint32 _gss_inquire_cred_by_mech_t (
+ OM_uint32 *, /* minor_status */
+ const gss_cred_id_t, /* cred_handle */
+ const gss_OID, /* mech_type */
+ gss_name_t *, /* name */
+ OM_uint32 *, /* initiator_lifetime */
+ OM_uint32 *, /* acceptor_lifetime */
+ gss_cred_usage_t * /* cred_usage */
+ );
+
+typedef OM_uint32 _gss_export_sec_context_t (
+ OM_uint32 *, /* minor_status */
+ gss_ctx_id_t *, /* context_handle */
+ gss_buffer_t /* interprocess_token */
+ );
+
+typedef OM_uint32 _gss_import_sec_context_t (
+ OM_uint32 *, /* minor_status */
+ const gss_buffer_t, /* interprocess_token */
+ gss_ctx_id_t * /* context_handle */
+ );
+
+typedef OM_uint32 _gss_inquire_names_for_mech_t (
+ OM_uint32 *, /* minor_status */
+ const gss_OID, /* mechanism */
+ gss_OID_set * /* name_types */
+ );
+
+typedef OM_uint32 _gss_inquire_mechs_for_name_t (
+ OM_uint32 *, /* minor_status */
+ const gss_name_t, /* input_name */
+ gss_OID_set * /* mech_types */
+ );
+
+typedef OM_uint32 _gss_canonicalize_name_t (
+ OM_uint32 *, /* minor_status */
+ const gss_name_t, /* input_name */
+ const gss_OID, /* mech_type */
+ gss_name_t * /* output_name */
+ );
+
+typedef OM_uint32 _gss_duplicate_name_t (
+ OM_uint32 *, /* minor_status */
+ const gss_name_t, /* src_name */
+ gss_name_t * /* dest_name */
+ );
+
+typedef OM_uint32 _gsskrb5_register_acceptor_identity (
+ const char * /* identity */
+ );
+
+typedef OM_uint32 _gss_krb5_copy_ccache (
+ OM_uint32 *, /* minor_status */
+ gss_cred_id_t, /* cred_handle */
+ struct krb5_ccache_data * /* out */
+ );
+
+typedef OM_uint32 _gss_krb5_compat_des3_mic (
+ OM_uint32 *, /* minor_status */
+ gss_ctx_id_t, /* context_handle */
+ int /* flag */
+ );
+
+struct _gss_mech_switch {
+ SLIST_ENTRY(_gss_mech_switch) gm_link;
+ gss_OID_desc gm_mech_oid;
+ void *gm_so;
+ _gss_acquire_cred_t *gm_acquire_cred;
+ _gss_release_cred_t *gm_release_cred;
+ _gss_init_sec_context_t *gm_init_sec_context;
+ _gss_accept_sec_context_t *gm_accept_sec_context;
+ _gss_process_context_token_t *gm_process_context_token;
+ _gss_delete_sec_context_t *gm_delete_sec_context;
+ _gss_context_time_t *gm_context_time;
+ _gss_get_mic_t *gm_get_mic;
+ _gss_verify_mic_t *gm_verify_mic;
+ _gss_wrap_t *gm_wrap;
+ _gss_unwrap_t *gm_unwrap;
+ _gss_display_status_t *gm_display_status;
+ _gss_indicate_mechs_t *gm_indicate_mechs;
+ _gss_compare_name_t *gm_compare_name;
+ _gss_display_name_t *gm_display_name;
+ _gss_import_name_t *gm_import_name;
+ _gss_export_name_t *gm_export_name;
+ _gss_release_name_t *gm_release_name;
+ _gss_inquire_cred_t *gm_inquire_cred;
+ _gss_inquire_context_t *gm_inquire_context;
+ _gss_wrap_size_limit_t *gm_wrap_size_limit;
+ _gss_add_cred_t *gm_add_cred;
+ _gss_inquire_cred_by_mech_t *gm_inquire_cred_by_mech;
+ _gss_export_sec_context_t *gm_export_sec_context;
+ _gss_import_sec_context_t *gm_import_sec_context;
+ _gss_inquire_names_for_mech_t *gm_inquire_names_for_mech;
+ _gss_inquire_mechs_for_name_t *gm_inquire_mechs_for_name;
+ _gss_canonicalize_name_t *gm_canonicalize_name;
+ _gss_duplicate_name_t *gm_duplicate_name;
+ _gsskrb5_register_acceptor_identity *gm_krb5_register_acceptor_identity;
+ _gss_krb5_copy_ccache *gm_krb5_copy_ccache;
+ _gss_krb5_compat_des3_mic *gm_krb5_compat_des3_mic;
+};
+SLIST_HEAD(_gss_mech_switch_list, _gss_mech_switch);
+extern struct _gss_mech_switch_list _gss_mechs;
+extern gss_OID_set _gss_mech_oids;
+
+extern void _gss_load_mech(void);
+extern struct _gss_mech_switch *_gss_find_mech_switch(gss_OID);
diff --git a/lib/libgssapi/name.h b/lib/libgssapi/name.h
new file mode 100644
index 0000000..a64d5d9
--- /dev/null
+++ b/lib/libgssapi/name.h
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 2005 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 <sys/queue.h>
+
+struct _gss_mechanism_name {
+ SLIST_ENTRY(_gss_mechanism_name) gmn_link;
+ struct _gss_mech_switch *gmn_mech; /* mechanism ops for MN */
+ gss_OID gmn_mech_oid; /* mechanism oid for MN */
+ gss_name_t gmn_name; /* underlying MN */
+};
+SLIST_HEAD(_gss_mechanism_name_list, _gss_mechanism_name);
+
+struct _gss_name {
+ gss_OID_desc gn_type; /* type of name */
+ gss_buffer_desc gn_value; /* value (as imported) */
+ struct _gss_mechanism_name_list gn_mn; /* list of MNs */
+};
+
+extern struct _gss_mechanism_name *
+ _gss_find_mn(struct _gss_name *name, gss_OID mech);
+struct _gss_name *
+ _gss_make_name(struct _gss_mech_switch *m, gss_name_t new_mn);
diff --git a/lib/libgssapi/spnego.h b/lib/libgssapi/spnego.h
new file mode 100644
index 0000000..8b2e22d
--- /dev/null
+++ b/lib/libgssapi/spnego.h
@@ -0,0 +1,34 @@
+/*-
+ * Copyright (c) 2005 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$
+ */
+
+typedef xder_OID MechType;
+
+typedef struct {
+ size_t MechTypeList_len;
+ MechType *MechTypeList_val;
+} MechTypeList;
diff --git a/lib/libgssapi/utils.h b/lib/libgssapi/utils.h
new file mode 100644
index 0000000..46edb9d
--- /dev/null
+++ b/lib/libgssapi/utils.h
@@ -0,0 +1,32 @@
+/*-
+ * Copyright (c) 2005 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$
+ */
+
+extern int _gss_oid_equal(const gss_OID, const gss_OID);
+extern OM_uint32 _gss_copy_oid(OM_uint32 *, const gss_OID, gss_OID);
+extern OM_uint32 _gss_copy_buffer(OM_uint32 *minor_status,
+ const gss_buffer_t from_buf, gss_buffer_t to_buf);
diff --git a/lib/libio/Makefile b/lib/libio/Makefile
new file mode 100644
index 0000000..bbbd72d
--- /dev/null
+++ b/lib/libio/Makefile
@@ -0,0 +1,9 @@
+# $FreeBSD$
+
+LIB= io
+SHLIB_MAJOR= 1
+SRCS= io.c swiz.c bwx.c alpha_sethae.c
+
+CFLAGS+= -Wall -Wa,-mev56
+
+.include <bsd.lib.mk>
diff --git a/lib/libio/alpha_sethae.c b/lib/libio/alpha_sethae.c
new file mode 100644
index 0000000..206b6dd
--- /dev/null
+++ b/lib/libio/alpha_sethae.c
@@ -0,0 +1,46 @@
+/*-
+ * Copyright (c) 1998 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$");
+
+#include <sys/types.h>
+#include <machine/sysarch.h>
+
+struct parms {
+ u_int64_t hae;
+};
+
+int
+alpha_sethae(u_int64_t hae)
+{
+ struct parms p;
+
+ p.hae = hae;
+
+ return (sysarch(ALPHA_SETHAE, &p));
+}
diff --git a/lib/libio/bwx.c b/lib/libio/bwx.c
new file mode 100644
index 0000000..5b47968
--- /dev/null
+++ b/lib/libio/bwx.c
@@ -0,0 +1,244 @@
+/*-
+ * Copyright (c) 1998 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$");
+
+#include <sys/param.h>
+#include <sys/mman.h>
+#include <sys/fcntl.h>
+#include <sys/sysctl.h>
+#include <err.h>
+#include <paths.h>
+#include <machine/bwx.h>
+#include <machine/sysarch.h>
+#include <stdlib.h>
+#include "io.h"
+
+#define mb() __asm__ __volatile__("mb" : : : "memory")
+#define wmb() __asm__ __volatile__("wmb" : : : "memory")
+
+static int mem_fd; /* file descriptor to /dev/mem */
+static void *bwx_int1_ports; /* mapped int1 io ports */
+static void *bwx_int2_ports; /* mapped int2 io ports */
+static void *bwx_int4_ports; /* mapped int4 io ports */
+static u_int64_t bwx_io_base; /* physical address of ports */
+static u_int64_t bwx_mem_base; /* physical address of bwx mem */
+
+static void
+bwx_init()
+{
+ size_t len = sizeof(u_int64_t);
+ int error;
+
+ mem_fd = open(_PATH_MEM, O_RDWR);
+ if (mem_fd < 0)
+ err(1, _PATH_MEM);
+ bwx_int1_ports = mmap(0, 1L<<32, PROT_READ, MAP_ANON, -1, 0);
+ bwx_int2_ports = mmap(0, 1L<<32, PROT_READ, MAP_ANON, -1, 0);
+ bwx_int4_ports = mmap(0, 1L<<32, PROT_READ, MAP_ANON, -1, 0);
+
+ if ((error = sysctlbyname("hw.chipset.ports", &bwx_io_base, &len,
+ 0, 0)) < 0)
+ err(1, "hw.chipset.ports");
+ if ((error = sysctlbyname("hw.chipset.memory", &bwx_mem_base, &len,
+ 0, 0)) < 0)
+ err(1, "hw.chipset.memory");
+}
+
+static int
+bwx_ioperm(u_int32_t from, u_int32_t num, int on)
+{
+ u_int32_t start, end;
+
+ if (!bwx_int1_ports)
+ bwx_init();
+
+ if (!on)
+ return -1; /* XXX can't unmap yet */
+
+ start = trunc_page(from);
+ end = round_page(from + num);
+
+ munmap(bwx_int1_ports + start, end-start);
+ munmap(bwx_int2_ports + start, end-start);
+ munmap(bwx_int4_ports + start, end-start);
+ mmap(bwx_int1_ports + start, end-start, PROT_READ|PROT_WRITE, MAP_SHARED,
+ mem_fd, bwx_io_base + BWX_EV56_INT1 + start);
+ mmap(bwx_int2_ports + start, end-start, PROT_READ|PROT_WRITE, MAP_SHARED,
+ mem_fd, bwx_io_base + BWX_EV56_INT2 + start);
+ mmap(bwx_int4_ports + start, end-start, PROT_READ|PROT_WRITE, MAP_SHARED,
+ mem_fd, bwx_io_base + BWX_EV56_INT4 + start);
+ return 0;
+}
+
+static u_int8_t
+bwx_inb(u_int32_t port)
+{
+ mb();
+ return ldbu((vm_offset_t)bwx_int1_ports + port);
+}
+
+static u_int16_t
+bwx_inw(u_int32_t port)
+{
+ mb();
+ return ldwu((vm_offset_t)bwx_int2_ports + port);
+}
+
+static u_int32_t
+bwx_inl(u_int32_t port)
+{
+ mb();
+ return ldl((vm_offset_t)bwx_int4_ports + port);
+}
+
+static void
+bwx_outb(u_int32_t port, u_int8_t val)
+{
+ stb((vm_offset_t)bwx_int1_ports + port, val);
+ wmb();
+}
+
+static void
+bwx_outw(u_int32_t port, u_int16_t val)
+{
+ stw((vm_offset_t)bwx_int2_ports + port, val);
+ wmb();
+}
+
+static void
+bwx_outl(u_int32_t port, u_int32_t val)
+{
+ stl((vm_offset_t)bwx_int4_ports + port, val);
+ wmb();
+}
+
+struct bwx_mem_handle {
+ void *virt1; /* int1 address in user address-space */
+ void *virt2; /* int2 address in user address-space */
+ void *virt4; /* int4 address in user address-space */
+};
+
+static void *
+bwx_map_memory(u_int32_t address, u_int32_t size)
+{
+ struct bwx_mem_handle *h;
+ h = malloc(sizeof(struct bwx_mem_handle));
+ if (!h) return 0;
+ h->virt1 = mmap(0, size << 5, PROT_READ|PROT_WRITE, MAP_SHARED,
+ mem_fd, bwx_mem_base + BWX_EV56_INT1 + address);
+ if ((long) h->virt1 == -1) {
+ free(h);
+ return 0;
+ }
+ h->virt2 = mmap(0, size << 5, PROT_READ|PROT_WRITE, MAP_SHARED,
+ mem_fd, bwx_mem_base + BWX_EV56_INT2 + address);
+ if ((long) h->virt2 == -1) {
+ munmap(h->virt1, size);
+ free(h);
+ return 0;
+ }
+ h->virt4 = mmap(0, size << 5, PROT_READ|PROT_WRITE, MAP_SHARED,
+ mem_fd, bwx_mem_base + BWX_EV56_INT4 + address);
+ if ((long) h->virt4 == -1) {
+ munmap(h->virt1, size);
+ munmap(h->virt2, size);
+ free(h);
+ return 0;
+ }
+ return h;
+}
+
+static void
+bwx_unmap_memory(void *handle, u_int32_t size)
+{
+ struct bwx_mem_handle *h = handle;
+ munmap(h->virt1, size);
+ munmap(h->virt2, size);
+ munmap(h->virt4, size);
+ free(h);
+}
+
+static u_int8_t
+bwx_readb(void *handle, u_int32_t offset)
+{
+ struct bwx_mem_handle *h = handle;
+ return ldbu((vm_offset_t)h->virt1 + offset);
+}
+
+static u_int16_t
+bwx_readw(void *handle, u_int32_t offset)
+{
+ struct bwx_mem_handle *h = handle;
+ return ldwu((vm_offset_t)h->virt2 + offset);
+}
+
+static u_int32_t
+bwx_readl(void *handle, u_int32_t offset)
+{
+ struct bwx_mem_handle *h = handle;
+ return ldl((vm_offset_t)h->virt4 + offset);
+}
+
+static void
+bwx_writeb(void *handle, u_int32_t offset, u_int8_t val)
+{
+ struct bwx_mem_handle *h = handle;
+ stb_nb((vm_offset_t)h->virt1 + offset, val);
+}
+
+static void
+bwx_writew(void *handle, u_int32_t offset, u_int16_t val)
+{
+ struct bwx_mem_handle *h = handle;
+ stw_nb((vm_offset_t)h->virt2 + offset, val);
+}
+
+static void
+bwx_writel(void *handle, u_int32_t offset, u_int32_t val)
+{
+ struct bwx_mem_handle *h = handle;
+ stl_nb((vm_offset_t)h->virt4 + offset, val);
+}
+
+struct io_ops bwx_io_ops = {
+ bwx_ioperm,
+ bwx_inb,
+ bwx_inw,
+ bwx_inl,
+ bwx_outb,
+ bwx_outw,
+ bwx_outl,
+ bwx_map_memory,
+ bwx_unmap_memory,
+ bwx_readb,
+ bwx_readw,
+ bwx_readl,
+ bwx_writeb,
+ bwx_writew,
+ bwx_writel,
+};
diff --git a/lib/libio/io.c b/lib/libio/io.c
new file mode 100644
index 0000000..a963349
--- /dev/null
+++ b/lib/libio/io.c
@@ -0,0 +1,173 @@
+/*-
+ * Copyright (c) 1998 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$");
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <err.h>
+#include "io.h"
+
+static struct io_ops *ops;
+
+int
+ioperm(unsigned long from, unsigned long num, int on)
+{
+ int error;
+ int bwx;
+ size_t len = sizeof(bwx);
+
+ if ((error = sysctlbyname("hw.chipset.bwx", &bwx, &len, 0, 0)) < 0)
+ return error;
+ if (bwx)
+ ops = &bwx_io_ops;
+ else
+ ops = &swiz_io_ops;
+
+ return ops->ioperm(from, num, on);
+}
+
+u_int8_t
+inb(u_int32_t port)
+{
+ return ops->inb(port);
+}
+
+u_int16_t
+inw(u_int32_t port)
+{
+ return ops->inw(port);
+}
+
+u_int32_t
+inl(u_int32_t port)
+{
+ return ops->inl(port);
+}
+
+void
+outb(u_int32_t port, u_int8_t val)
+{
+ ops->outb(port, val);
+}
+
+void
+outw(u_int32_t port, u_int16_t val)
+{
+ ops->outw(port, val);
+}
+
+void
+outl(u_int32_t port, u_int32_t val)
+{
+ ops->outl(port, val);
+}
+
+void *
+map_memory(u_int32_t address, u_int32_t size)
+{
+ return ops->map_memory(address, size);
+}
+
+void
+unmap_memory(void *handle, u_int32_t size)
+{
+ ops->unmap_memory(handle, size);
+}
+
+u_int8_t
+readb(void *handle, u_int32_t offset)
+{
+ return ops->readb(handle, offset);
+}
+
+u_int16_t
+readw(void *handle, u_int32_t offset)
+{
+ return ops->readw(handle, offset);
+}
+
+u_int32_t
+readl(void *handle, u_int32_t offset)
+{
+ return ops->readl(handle, offset);
+}
+
+void
+writeb(void *handle, u_int32_t offset, u_int8_t val)
+{
+ ops->writeb(handle, offset, val);
+ __asm__ __volatile__ ("mb");
+}
+
+void
+writew(void *handle, u_int32_t offset, u_int16_t val)
+{
+ ops->writew(handle, offset, val);
+ __asm__ __volatile__ ("mb");
+}
+
+void
+writel(void *handle, u_int32_t offset, u_int32_t val)
+{
+ ops->writel(handle, offset, val);
+ __asm__ __volatile__ ("mb");
+}
+
+void
+writeb_nb(void *handle, u_int32_t offset, u_int8_t val)
+{
+ return ops->writeb(handle, offset, val);
+}
+
+void
+writew_nb(void *handle, u_int32_t offset, u_int16_t val)
+{
+ return ops->writew(handle, offset, val);
+}
+
+void
+writel_nb(void *handle, u_int32_t offset, u_int32_t val)
+{
+ return ops->writel(handle, offset, val);
+}
+
+u_int64_t
+dense_base(void)
+{
+ static u_int64_t base = 0;
+
+ if (base == 0) {
+ size_t len = sizeof(base);
+ int error;
+ if ((error = sysctlbyname("hw.chipset.dense", &base, &len,
+ 0, 0)) < 0)
+ err(1, "hw.chipset.dense");
+ }
+
+ return base;
+}
diff --git a/lib/libio/io.h b/lib/libio/io.h
new file mode 100644
index 0000000..1f4c620
--- /dev/null
+++ b/lib/libio/io.h
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 1998 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$
+ */
+
+struct io_ops {
+ int (*ioperm)(u_int32_t, u_int32_t, int);
+ u_int8_t (*inb)(u_int32_t);
+ u_int16_t (*inw)(u_int32_t);
+ u_int32_t (*inl)(u_int32_t);
+ void (*outb)(u_int32_t, u_int8_t);
+ void (*outw)(u_int32_t, u_int16_t);
+ void (*outl)(u_int32_t, u_int32_t);
+ void * (*map_memory)(u_int32_t, u_int32_t);
+ void (*unmap_memory)(void *, u_int32_t);
+ u_int8_t (*readb)(void *, u_int32_t);
+ u_int16_t (*readw)(void *, u_int32_t);
+ u_int32_t (*readl)(void *, u_int32_t);
+ void (*writeb)(void *, u_int32_t, u_int8_t);
+ void (*writew)(void *, u_int32_t, u_int16_t);
+ void (*writel)(void *, u_int32_t, u_int32_t);
+};
+
+extern struct io_ops swiz_io_ops;
+extern struct io_ops bwx_io_ops;
diff --git a/lib/libio/swiz.c b/lib/libio/swiz.c
new file mode 100644
index 0000000..eab2a03
--- /dev/null
+++ b/lib/libio/swiz.c
@@ -0,0 +1,248 @@
+/*-
+ * Copyright (c) 1998 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$");
+
+#include <sys/param.h>
+#include <sys/mman.h>
+#include <sys/fcntl.h>
+#include <sys/sysctl.h>
+#include <err.h>
+#include <paths.h>
+#include <machine/swiz.h>
+#include <machine/sysarch.h>
+#include <stdlib.h>
+#include "io.h"
+
+#define mb() __asm__ __volatile__("mb" : : : "memory")
+#define wmb() __asm__ __volatile__("wmb" : : : "memory")
+
+static int mem_fd; /* file descriptor to /dev/mem */
+static void *swiz_ports; /* mapped io ports */
+static u_int64_t swiz_io_base; /* physical address of ports */
+static u_int64_t swiz_mem_base; /* physical address of sparse mem */
+static u_int64_t swiz_dense_base; /* physical address of dense mem */
+static u_int64_t swiz_hae_mask; /* mask address bits for hae */
+static u_int32_t swiz_hae; /* cache of current hae */
+
+static void
+swiz_init()
+{
+
+ size_t len = sizeof(u_int64_t);
+ int error;
+
+ mem_fd = open(_PATH_MEM, O_RDWR);
+ if (mem_fd < 0)
+ err(1, _PATH_MEM);
+ swiz_ports = mmap(0, 1L<<32, PROT_READ, MAP_ANON, -1, 0);
+
+ if ((error = sysctlbyname("hw.chipset.ports", &swiz_io_base, &len,
+ 0, 0)) < 0)
+ err(1, "hw.chipset.ports");
+ if ((error = sysctlbyname("hw.chipset.memory", &swiz_mem_base, &len,
+ 0, 0)) < 0)
+ err(1, "hw.chipset.memory");
+ if ((error = sysctlbyname("hw.chipset.dense", &swiz_dense_base, &len,
+ 0, 0)) < 0)
+ err(1, "hw.chipset.memory");
+ if ((error = sysctlbyname("hw.chipset.hae_mask", &swiz_hae_mask, &len,
+ 0, 0)) < 0)
+ err(1, "hw.chipset.memory");
+
+}
+
+static int
+swiz_ioperm(u_int32_t from, u_int32_t num, int on)
+{
+ u_int64_t start, end;
+ void *addr;
+
+ if (!swiz_ports)
+ swiz_init();
+
+ if (!on)
+ return -1; /* XXX can't unmap yet */
+
+ start = trunc_page(from << 5);
+ end = round_page((from + num) << 5);
+ addr = swiz_ports + start;
+ munmap(addr, end - start);
+ mmap(addr, end - start, PROT_READ|PROT_WRITE, MAP_SHARED,
+ mem_fd, swiz_io_base + start);
+ return 0;
+}
+
+static u_int8_t
+swiz_inb(u_int32_t port)
+{
+ mb();
+ return SPARSE_READ_BYTE(swiz_ports, port);
+}
+
+static u_int16_t
+swiz_inw(u_int32_t port)
+{
+ mb();
+ return SPARSE_READ_WORD(swiz_ports, port);
+}
+
+static u_int32_t
+swiz_inl(u_int32_t port)
+{
+ mb();
+ return SPARSE_READ_LONG(swiz_ports, port);
+}
+
+static void
+swiz_outb(u_int32_t port, u_int8_t val)
+{
+ SPARSE_WRITE_BYTE(swiz_ports, port, val);
+ wmb();
+}
+
+static void
+swiz_outw(u_int32_t port, u_int16_t val)
+{
+ SPARSE_WRITE_WORD(swiz_ports, port, val);
+ wmb();
+}
+
+static void
+swiz_outl(u_int32_t port, u_int32_t val)
+{
+ SPARSE_WRITE_LONG(swiz_ports, port, val);
+ wmb();
+}
+
+struct swiz_mem_handle {
+ u_int32_t phys; /* address in PCI address-space */
+ void *virt; /* address in user address-space */
+ u_int32_t size; /* size of mapped region */
+};
+
+static void *
+swiz_map_memory(u_int32_t address, u_int32_t size)
+{
+ struct swiz_mem_handle *h;
+ h = malloc(sizeof(struct swiz_mem_handle));
+ if (!h) return 0;
+ h->phys = address;
+ h->virt = mmap(0, size << 5, PROT_READ|PROT_WRITE, MAP_SHARED,
+ mem_fd,
+ swiz_mem_base + ((address & ~swiz_hae_mask) << 5));
+ if ((long) h->virt == -1) {
+ free(h);
+ return 0;
+ }
+ h->size = size << 5;
+ return h;
+}
+
+static void
+swiz_unmap_memory(void *handle, u_int32_t size)
+{
+ struct swiz_mem_handle *h = handle;
+ munmap(h->virt, h->size);
+ free(h);
+}
+
+static void
+swiz_sethae(vm_offset_t phys)
+{
+ u_int32_t hae = phys & swiz_hae_mask;
+ if (hae != swiz_hae) {
+ alpha_sethae(hae);
+ swiz_hae = hae;
+ }
+}
+
+static u_int8_t
+swiz_readb(void *handle, u_int32_t offset)
+{
+ struct swiz_mem_handle *h = handle;
+ swiz_sethae(h->phys + offset);
+ return SPARSE_READ_BYTE(h->virt, offset);
+}
+
+static u_int16_t
+swiz_readw(void *handle, u_int32_t offset)
+{
+ struct swiz_mem_handle *h = handle;
+ swiz_sethae(h->phys + offset);
+ return SPARSE_READ_WORD(h->virt, offset);
+}
+
+static u_int32_t
+swiz_readl(void *handle, u_int32_t offset)
+{
+ struct swiz_mem_handle *h = handle;
+ swiz_sethae(h->phys + offset);
+ return SPARSE_READ_LONG(h->virt, offset);
+}
+
+static void
+swiz_writeb(void *handle, u_int32_t offset, u_int8_t val)
+{
+ struct swiz_mem_handle *h = handle;
+ swiz_sethae(h->phys + offset);
+ SPARSE_WRITE_BYTE(h->virt, offset, val);
+}
+
+static void
+swiz_writew(void *handle, u_int32_t offset, u_int16_t val)
+{
+ struct swiz_mem_handle *h = handle;
+ swiz_sethae(h->phys + offset);
+ SPARSE_WRITE_WORD(h->virt, offset, val);
+}
+
+static void
+swiz_writel(void *handle, u_int32_t offset, u_int32_t val)
+{
+ struct swiz_mem_handle *h = handle;
+ swiz_sethae(h->phys + offset);
+ SPARSE_WRITE_LONG(h->virt, offset, val);
+}
+
+struct io_ops swiz_io_ops = {
+ swiz_ioperm,
+ swiz_inb,
+ swiz_inw,
+ swiz_inl,
+ swiz_outb,
+ swiz_outw,
+ swiz_outl,
+ swiz_map_memory,
+ swiz_unmap_memory,
+ swiz_readb,
+ swiz_readw,
+ swiz_readl,
+ swiz_writeb,
+ swiz_writew,
+ swiz_writel,
+};
diff --git a/lib/libipsec/Makefile b/lib/libipsec/Makefile
new file mode 100644
index 0000000..62562cd
--- /dev/null
+++ b/lib/libipsec/Makefile
@@ -0,0 +1,58 @@
+# 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.
+#
+# $FreeBSD$
+
+SHLIBDIR?= /lib
+
+.include <bsd.own.mk>
+
+LIB= ipsec
+SHLIB_MAJOR= 2
+CFLAGS+=-I. -I${.CURDIR}
+CFLAGS+=-DIPSEC_DEBUG -DIPSEC
+.if ${MK_INET6_SUPPORT} != "no"
+CFLAGS+=-DINET6
+.endif
+
+#.PATH: ${.CURDIR}/../../sys/netkey
+#SRCS= pfkey.c pfkey_dump.c
+SRCS+= ipsec_strerror.c policy_parse.y policy_token.l
+SRCS+= ipsec_dump_policy.c ipsec_get_policylen.c
+#SRCS+= key_debug.c
+CLEANFILES+= y.tab.c y.tab.h
+YFLAGS+=-d -p __libipsecyy
+LFLAGS+=-P__libipsecyy
+
+MAN= ipsec_set_policy.3 ipsec_strerror.3
+MLINKS+=ipsec_set_policy.3 ipsec_get_policylen.3 \
+ ipsec_set_policy.3 ipsec_dump_policy.3
+
+SRCS+= y.tab.h
+y.tab.h: policy_parse.y
+
+.include <bsd.lib.mk>
diff --git a/lib/libipsec/ipsec_dump_policy.c b/lib/libipsec/ipsec_dump_policy.c
new file mode 100644
index 0000000..3ce525b
--- /dev/null
+++ b/lib/libipsec/ipsec_dump_policy.c
@@ -0,0 +1,306 @@
+/* $KAME: ipsec_dump_policy.c,v 1.13 2002/06/27 14:35:11 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netkey/key_var.h>
+#include <netinet/in.h>
+#include <netinet6/ipsec.h>
+
+#include <arpa/inet.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netdb.h>
+
+#include "ipsec_strerror.h"
+
+static const char *ipsp_dir_strs[] = {
+ "any", "in", "out",
+};
+
+static const char *ipsp_policy_strs[] = {
+ "discard", "none", "ipsec", "entrust", "bypass",
+};
+
+static char *ipsec_dump_ipsecrequest(char *, size_t,
+ struct sadb_x_ipsecrequest *, size_t);
+static int set_addresses(char *, size_t, struct sockaddr *, struct sockaddr *);
+static char *set_address(char *, size_t, struct sockaddr *);
+
+/*
+ * policy is sadb_x_policy buffer.
+ * Must call free() later.
+ * When delimiter == NULL, alternatively ' '(space) is applied.
+ */
+char *
+ipsec_dump_policy(policy, delimiter)
+ caddr_t policy;
+ char *delimiter;
+{
+ struct sadb_x_policy *xpl = (struct sadb_x_policy *)policy;
+ struct sadb_x_ipsecrequest *xisr;
+ size_t off, buflen;
+ char *buf;
+ char isrbuf[1024];
+ char *newbuf;
+
+ /* sanity check */
+ if (policy == NULL)
+ return NULL;
+ if (xpl->sadb_x_policy_exttype != SADB_X_EXT_POLICY) {
+ __ipsec_errcode = EIPSEC_INVAL_EXTTYPE;
+ return NULL;
+ }
+
+ /* set delimiter */
+ if (delimiter == NULL)
+ delimiter = " ";
+
+ switch (xpl->sadb_x_policy_dir) {
+ case IPSEC_DIR_ANY:
+ case IPSEC_DIR_INBOUND:
+ case IPSEC_DIR_OUTBOUND:
+ break;
+ default:
+ __ipsec_errcode = EIPSEC_INVAL_DIR;
+ return NULL;
+ }
+
+ switch (xpl->sadb_x_policy_type) {
+ case IPSEC_POLICY_DISCARD:
+ case IPSEC_POLICY_NONE:
+ case IPSEC_POLICY_IPSEC:
+ case IPSEC_POLICY_BYPASS:
+ case IPSEC_POLICY_ENTRUST:
+ break;
+ default:
+ __ipsec_errcode = EIPSEC_INVAL_POLICY;
+ return NULL;
+ }
+
+ buflen = strlen(ipsp_dir_strs[xpl->sadb_x_policy_dir])
+ + 1 /* space */
+ + strlen(ipsp_policy_strs[xpl->sadb_x_policy_type])
+ + 1; /* NUL */
+
+ if ((buf = malloc(buflen)) == NULL) {
+ __ipsec_errcode = EIPSEC_NO_BUFS;
+ return NULL;
+ }
+ snprintf(buf, buflen, "%s %s", ipsp_dir_strs[xpl->sadb_x_policy_dir],
+ ipsp_policy_strs[xpl->sadb_x_policy_type]);
+
+ if (xpl->sadb_x_policy_type != IPSEC_POLICY_IPSEC) {
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return buf;
+ }
+
+ /* count length of buffer for use */
+ off = sizeof(*xpl);
+ while (off < PFKEY_EXTLEN(xpl)) {
+ xisr = (struct sadb_x_ipsecrequest *)((caddr_t)xpl + off);
+ off += xisr->sadb_x_ipsecrequest_len;
+ }
+
+ /* validity check */
+ if (off != PFKEY_EXTLEN(xpl)) {
+ __ipsec_errcode = EIPSEC_INVAL_SADBMSG;
+ free(buf);
+ return NULL;
+ }
+
+ off = sizeof(*xpl);
+ while (off < PFKEY_EXTLEN(xpl)) {
+ xisr = (struct sadb_x_ipsecrequest *)((caddr_t)xpl + off);
+
+ if (ipsec_dump_ipsecrequest(isrbuf, sizeof(isrbuf), xisr,
+ PFKEY_EXTLEN(xpl) - off) == NULL) {
+ free(buf);
+ return NULL;
+ }
+
+ buflen = strlen(buf) + strlen(delimiter) + strlen(isrbuf) + 1;
+ newbuf = (char *)realloc(buf, buflen);
+ if (newbuf == NULL) {
+ __ipsec_errcode = EIPSEC_NO_BUFS;
+ free(buf);
+ return NULL;
+ }
+ buf = newbuf;
+ snprintf(buf, buflen, "%s%s%s", buf, delimiter, isrbuf);
+
+ off += xisr->sadb_x_ipsecrequest_len;
+ }
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return buf;
+}
+
+static char *
+ipsec_dump_ipsecrequest(buf, len, xisr, bound)
+ char *buf;
+ size_t len;
+ struct sadb_x_ipsecrequest *xisr;
+ size_t bound; /* boundary */
+{
+ const char *proto, *mode, *level;
+ char abuf[NI_MAXHOST * 2 + 2];
+
+ if (xisr->sadb_x_ipsecrequest_len > bound) {
+ __ipsec_errcode = EIPSEC_INVAL_PROTO;
+ return NULL;
+ }
+
+ switch (xisr->sadb_x_ipsecrequest_proto) {
+ case IPPROTO_ESP:
+ proto = "esp";
+ break;
+ case IPPROTO_AH:
+ proto = "ah";
+ break;
+ case IPPROTO_IPCOMP:
+ proto = "ipcomp";
+ break;
+ case IPPROTO_TCP:
+ proto = "tcp";
+ default:
+ __ipsec_errcode = EIPSEC_INVAL_PROTO;
+ return NULL;
+ }
+
+ switch (xisr->sadb_x_ipsecrequest_mode) {
+ case IPSEC_MODE_ANY:
+ mode = "any";
+ break;
+ case IPSEC_MODE_TRANSPORT:
+ mode = "transport";
+ break;
+ case IPSEC_MODE_TUNNEL:
+ mode = "tunnel";
+ break;
+ default:
+ __ipsec_errcode = EIPSEC_INVAL_MODE;
+ return NULL;
+ }
+
+ abuf[0] = '\0';
+ if (xisr->sadb_x_ipsecrequest_len > sizeof(*xisr)) {
+ struct sockaddr *sa1, *sa2;
+ caddr_t p;
+
+ p = (caddr_t)(xisr + 1);
+ sa1 = (struct sockaddr *)p;
+ sa2 = (struct sockaddr *)(p + sa1->sa_len);
+ if (sizeof(*xisr) + sa1->sa_len + sa2->sa_len !=
+ xisr->sadb_x_ipsecrequest_len) {
+ __ipsec_errcode = EIPSEC_INVAL_ADDRESS;
+ return NULL;
+ }
+ if (set_addresses(abuf, sizeof(abuf), sa1, sa2) != 0) {
+ __ipsec_errcode = EIPSEC_INVAL_ADDRESS;
+ return NULL;
+ }
+ }
+
+ switch (xisr->sadb_x_ipsecrequest_level) {
+ case IPSEC_LEVEL_DEFAULT:
+ level = "default";
+ break;
+ case IPSEC_LEVEL_USE:
+ level = "use";
+ break;
+ case IPSEC_LEVEL_REQUIRE:
+ level = "require";
+ break;
+ case IPSEC_LEVEL_UNIQUE:
+ level = "unique";
+ break;
+ default:
+ __ipsec_errcode = EIPSEC_INVAL_LEVEL;
+ return NULL;
+ }
+
+ if (xisr->sadb_x_ipsecrequest_reqid == 0)
+ snprintf(buf, len, "%s/%s/%s/%s", proto, mode, abuf, level);
+ else {
+ int ch;
+
+ if (xisr->sadb_x_ipsecrequest_reqid > IPSEC_MANUAL_REQID_MAX)
+ ch = '#';
+ else
+ ch = ':';
+ snprintf(buf, len, "%s/%s/%s/%s%c%u", proto, mode, abuf, level,
+ ch, xisr->sadb_x_ipsecrequest_reqid);
+ }
+
+ return buf;
+}
+
+static int
+set_addresses(buf, len, sa1, sa2)
+ char *buf;
+ size_t len;
+ struct sockaddr *sa1;
+ struct sockaddr *sa2;
+{
+ char tmp1[NI_MAXHOST], tmp2[NI_MAXHOST];
+
+ if (set_address(tmp1, sizeof(tmp1), sa1) == NULL ||
+ set_address(tmp2, sizeof(tmp2), sa2) == NULL)
+ return -1;
+ if (strlen(tmp1) + 1 + strlen(tmp2) + 1 > len)
+ return -1;
+ snprintf(buf, len, "%s-%s", tmp1, tmp2);
+ return 0;
+}
+
+static char *
+set_address(buf, len, sa)
+ char *buf;
+ size_t len;
+ struct sockaddr *sa;
+{
+ const int niflags = NI_NUMERICHOST;
+
+ if (len < 1)
+ return NULL;
+ buf[0] = '\0';
+ if (getnameinfo(sa, sa->sa_len, buf, len, NULL, 0, niflags) != 0)
+ return NULL;
+ return buf;
+}
diff --git a/lib/libipsec/ipsec_get_policylen.c b/lib/libipsec/ipsec_get_policylen.c
new file mode 100644
index 0000000..911b2ce
--- /dev/null
+++ b/lib/libipsec/ipsec_get_policylen.c
@@ -0,0 +1,49 @@
+/* $KAME: ipsec_get_policylen.c,v 1.5 2000/05/07 05:25:03 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <netinet6/ipsec.h>
+
+#include <net/pfkeyv2.h>
+
+#include "ipsec_strerror.h"
+
+int
+ipsec_get_policylen(policy)
+ caddr_t policy;
+{
+ return policy ? PFKEY_EXTLEN(policy) : -1;
+}
diff --git a/lib/libipsec/ipsec_set_policy.3 b/lib/libipsec/ipsec_set_policy.3
new file mode 100644
index 0000000..8be32f5
--- /dev/null
+++ b/lib/libipsec/ipsec_set_policy.3
@@ -0,0 +1,335 @@
+.\" $KAME: ipsec_set_policy.3,v 1.15 2001/08/17 07:21:36 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd February 14, 2006
+.Dt IPSEC_SET_POLICY 3
+.Os
+.Sh NAME
+.Nm ipsec_set_policy ,
+.Nm ipsec_get_policylen ,
+.Nm ipsec_dump_policy
+.Nd create an IPsec policy structure from a human readable string
+.\"
+.Sh LIBRARY
+.Lb libipsec
+.Sh SYNOPSIS
+.In netinet6/ipsec.h
+.Ft "char *"
+.Fn ipsec_set_policy "char *policy" "int len"
+.Ft int
+.Fn ipsec_get_policylen "char *buf"
+.Ft "char *"
+.Fn ipsec_dump_policy "char *buf" "char *delim"
+.Sh DESCRIPTION
+The
+.Fn ipsec_set_policy
+function generates an IPsec policy specification structure,
+.Li struct sadb_x_policy
+and/or
+.Li struct sadb_x_ipsecrequest
+from a human-readable policy specification.
+The policy specification must be given as a C string,
+passed in the
+.Fa policy
+argument and the length of the string, given as
+.Fa len .
+The
+.Fn ipsec_set_policy
+function returns pointer to a buffer which contains a properly formed
+IPsec policy specification structure.
+The buffer is dynamically allocated, and must be freed by using the
+.Xr free 3
+library function.
+.Pp
+The
+.Fn ipsec_get_policylen
+function will returns the of the buffer which is needed when passing
+the specification structure to the
+.Xr setsockopt 2
+system call.
+.Pp
+The
+.Fn ipsec_dump_policy
+function converts an IPsec policy structure into a human readable form.
+The
+.Fa buf
+argument points to an IPsec policy structure,
+.Li struct sadb_x_policy .
+.Fa delim
+is a delimiter string, which is usually a blank character.
+If you set
+.Fa delim
+to
+.Dv NULL ,
+a single white space is assumed.
+The
+.Fn ipsec_dump_policy
+function returns a pointer to dynamically allocated string.
+It is the caller's responsibility to free the returned pointer using the
+.Xr free 3
+library call.
+.Pp
+A
+.Fa policy
+is given in the following way:
+.Bl -tag -width "discard"
+.It Ar direction Li discard
+The
+.Ar direction
+must be
+.Li in
+or
+.Li out
+and
+specifies which direction the policy needs to be applied, either on
+inbound or outbound packets.
+When the
+.Li discard
+policy is selected, packets will be dropped if they match the policy.
+.It Ar direction Li entrust
+.Li entrust
+means to consult the security policy database
+(SPD)
+in the kernel, as controlled by
+.Xr setkey 8 .
+.It Ar direction Li bypass
+A direction of
+.Li bypass
+indicates that IPsec processing should not occur and that the
+packet will be transmitted in clear. The bypass option is only
+available to privileged sockets.
+.It Xo
+.Ar direction
+.Li ipsec
+.Ar request ...
+.Xc
+A direction of
+.Li ipsec
+means that matching packets are processed by IPsec.
+.Li ipsec
+can be followed by one or more
+.Ar request
+string, which is formatted as:
+.Bl -tag -width "discard"
+.It Xo
+.Ar protocol
+.Li /
+.Ar mode
+.Li /
+.Ar src
+.Li -
+.Ar dst
+.Op Ar /level
+.Xc
+The
+.Ar protocol
+is one of:
+.Li ah ,
+.Li esp
+or
+.Li ipcomp
+indicating Authentication Header, Encapsulating Security Protocol or
+IP Compression protocol is used.
+.Pp
+The
+.Ar mode
+is either
+.Li transport
+or
+.Li tunnel
+the meanings of both modes are described in
+.Xr ipsec 4 .
+.Pp
+The
+.Ar src
+and
+.Ar dst
+specify the IP address, either v4 or v6, of the source and destination systems.
+The
+.Ar src
+always stands for the
+.Dq sending node
+and
+.Ar dst
+always stands for the
+.Dq receiving node .
+When
+.Ar direction
+is
+.Li in ,
+.Ar dst
+is this local node
+and
+.Ar src
+is the remote node or peer.
+If
+.Ar mode
+is
+.Li transport ,
+both
+.Ar src
+and
+.Ar dst
+can be omitted.
+.Pp
+The
+.Ar level
+must be set to one of the following:
+.Li default , use , require
+or
+.Li unique .
+.Li default
+means that the kernel should consult the default security policies as
+defined by a set of
+.Xr sysctl 8 ,
+variables. The relevant
+.Xr sysctl 8
+variables are described in
+.Xr ipsec 4 .
+.Pp
+When
+.Li use
+is selected a relevant security association
+(SA)
+can be used when available but is not necessary.
+If the SA is available then packets will be handled by IPsec,
+i.e. encrypted and/or authenticated but if an SA is not available then
+packets will be transmitted in the clear. The
+.Li use
+option is not recommended because it allows for accidental
+mis-configurations where encrypted or authenticated link becomes
+unencrypted or unauthenticated, the
+.Li require
+keyword is recommended instead of
+.Li use
+where possible.
+Using the
+.Li require
+keyword means that a relevant SA is required,
+and that the kernel must perform IPsec processing on all matching
+packets.
+.Pp
+The
+.Li unique
+keyword has the same effect as
+.Li require ,
+but adds the restriction that the SA for outbound traffic is used
+only for this policy.
+You may need the identifier in order to relate the policy and the SA
+when you define the SA by manual keying using
+.Xr setkey 8 .
+Put the decimal number as the identifier after the
+.Li unique
+keyword in this way:
+.Li unique : number ,
+where
+.Li number
+must be between 1 and 32767.
+.Pp
+If the
+.Ar request
+string is kept unambiguous,
+.Ar level
+and the slash prior to
+.Ar level
+can be omitted but you are encouraged to specify them explicitly
+to avoid unintended behaviors.
+If
+.Ar level
+is omitted, it will be interpreted as
+.Li default .
+.El
+.El
+.Pp
+Note that there is a difference between the specification allowed here
+and in
+.Xr setkey 8 .
+When specifying security policies with
+.Xr setkey 8 ,
+neither entrust nor bypass are used.
+Refer to
+.Xr setkey 8
+for details.
+.Sh EXAMPLES
+Set a policy that all inbound packets are discarded.
+.Bd -literal -offset indent
+in discard
+
+.Ed
+.\"
+All outbound packets are required to be processed by IPsec and
+transported using ESP.
+.Bd -literal -offset indent
+out ipsec esp/transport//require
+
+.Ed
+.\"
+All inbound packets are required to be authenticated using the AH protocol.
+.Bd -literal -offset indent
+in ipsec ah/transport//require
+
+.Ed
+.\"
+Tunnel packets outbound through the endpoints at 10.1.1.2 and 10.1.1.1.
+.Bd -literal -offset indent
+out ipsec esp/tunnel/10.1.1.2-10.1.1.1/require
+
+.Ed
+.\"
+.Sh RETURN VALUES
+The
+.Fn ipsec_set_policy
+function returns a pointer to the allocated buffer containing a the
+policy specification if successful; otherwise a NULL pointer is
+returned.
+.Pp
+The
+.Fn ipsec_get_policylen
+function returns a positive value,
+indicating the buffer size,
+on success, and a negative value on error.
+.Pp
+The
+.Fn ipsec_dump_policy
+function returns a pointer to a dynamically allocated region
+containing a human readable security policy on success, and
+.Dv NULL
+on error.
+.Sh SEE ALSO
+.Xr ipsec_strerror 3 ,
+.Xr ipsec 4 ,
+.Xr setkey 8
+.Sh HISTORY
+These functions first appeared in WIDE/KAME IPv6 protocol stack kit.
+.Pp
+IPv6 and IPsec support based on the KAME Project (http://www.kame.net/) stack
+was initially integrated into
+.Fx 4.0
diff --git a/lib/libipsec/ipsec_strerror.3 b/lib/libipsec/ipsec_strerror.3
new file mode 100644
index 0000000..d162fa6
--- /dev/null
+++ b/lib/libipsec/ipsec_strerror.3
@@ -0,0 +1,90 @@
+.\" $KAME: ipsec_strerror.3,v 1.9 2001/08/17 07:21:36 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd February 14, 2006
+.Dt IPSEC_STRERROR 3
+.Os
+.\"
+.Sh NAME
+.Nm ipsec_strerror
+.Nd error messages for the IPsec policy manipulation library
+.\"
+.Sh SYNOPSIS
+.In netinet6/ipsec.h
+.Ft "const char *"
+.Fn ipsec_strerror
+.\"
+.Sh DESCRIPTION
+.In netinet6/ipsec.h
+declares
+.Pp
+.Dl extern int ipsec_errcode;
+.Pp
+which is used to pass an error code from IPsec policy manipulation library
+to a user program.
+The
+.Fn ipsec_strerror
+function can be used to obtain the error message string for the error code.
+.Pp
+The array pointed to is not to be modified by the program.
+Since
+.Fn ipsec_strerror
+uses
+.Xr strerror 3
+as an underlying function, calling
+.Xr strerror 3
+after
+.Fn ipsec_strerror
+would overwrite the the return value from
+.Fn ipsec_strerror
+and make it invalid.
+.\"
+.Sh RETURN VALUES
+The
+.Fn ipsec_strerror
+function always returns a pointer to C string.
+The C string must not be overwritten by the caller.
+.\"
+.Sh SEE ALSO
+.Xr ipsec_set_policy 3
+.\"
+.Sh HISTORY
+The
+.Fn ipsec_strerror
+function first appeared in WIDE/KAME IPv6 protocol stack kit.
+.\"
+.Sh BUGS
+The
+.Fn ipsec_strerror
+function will return its result which may be overwritten by subsequent calls.
+.Pp
+.Va ipsec_errcode
+is not thread safe.
diff --git a/lib/libipsec/ipsec_strerror.c b/lib/libipsec/ipsec_strerror.c
new file mode 100644
index 0000000..203b651
--- /dev/null
+++ b/lib/libipsec/ipsec_strerror.c
@@ -0,0 +1,90 @@
+/* $KAME: ipsec_strerror.c,v 1.7 2000/07/30 00:45:12 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <string.h>
+#include <netinet6/ipsec.h>
+
+#include "ipsec_strerror.h"
+
+int __ipsec_errcode;
+
+static const char *ipsec_errlist[] = {
+"Success", /*EIPSEC_NO_ERROR*/
+"Not supported", /*EIPSEC_NOT_SUPPORTED*/
+"Invalid argument", /*EIPSEC_INVAL_ARGUMENT*/
+"Invalid sadb message", /*EIPSEC_INVAL_SADBMSG*/
+"Invalid version", /*EIPSEC_INVAL_VERSION*/
+"Invalid security policy", /*EIPSEC_INVAL_POLICY*/
+"Invalid address specification", /*EIPSEC_INVAL_ADDRESS*/
+"Invalid ipsec protocol", /*EIPSEC_INVAL_PROTO*/
+"Invalid ipsec mode", /*EIPSEC_INVAL_MODE*/
+"Invalid ipsec level", /*EIPSEC_INVAL_LEVEL*/
+"Invalid SA type", /*EIPSEC_INVAL_SATYPE*/
+"Invalid message type", /*EIPSEC_INVAL_MSGTYPE*/
+"Invalid extension type", /*EIPSEC_INVAL_EXTTYPE*/
+"Invalid algorithm type", /*EIPSEC_INVAL_ALGS*/
+"Invalid key length", /*EIPSEC_INVAL_KEYLEN*/
+"Invalid address family", /*EIPSEC_INVAL_FAMILY*/
+"Invalid prefix length", /*EIPSEC_INVAL_PREFIXLEN*/
+"Invalid direciton", /*EIPSEC_INVAL_DIR*/
+"SPI range violation", /*EIPSEC_INVAL_SPI*/
+"No protocol specified", /*EIPSEC_NO_PROTO*/
+"No algorithm specified", /*EIPSEC_NO_ALGS*/
+"No buffers available", /*EIPSEC_NO_BUFS*/
+"Must get supported algorithms list first", /*EIPSEC_DO_GET_SUPP_LIST*/
+"Protocol mismatch", /*EIPSEC_PROTO_MISMATCH*/
+"Family mismatch", /*EIPSEC_FAMILY_MISMATCH*/
+"Too few arguments", /*EIPSEC_FEW_ARGUMENTS*/
+NULL, /*EIPSEC_SYSTEM_ERROR*/
+"Unknown error", /*EIPSEC_MAX*/
+};
+
+const char *ipsec_strerror(void)
+{
+ if (__ipsec_errcode < 0 || __ipsec_errcode > EIPSEC_MAX)
+ __ipsec_errcode = EIPSEC_MAX;
+
+ return ipsec_errlist[__ipsec_errcode];
+}
+
+void __ipsec_set_strerror(const char *str)
+{
+ __ipsec_errcode = EIPSEC_SYSTEM_ERROR;
+ ipsec_errlist[EIPSEC_SYSTEM_ERROR] = str;
+
+ return;
+}
diff --git a/lib/libipsec/ipsec_strerror.h b/lib/libipsec/ipsec_strerror.h
new file mode 100644
index 0000000..d9a1f0d
--- /dev/null
+++ b/lib/libipsec/ipsec_strerror.h
@@ -0,0 +1,63 @@
+/* $FreeBSD$ */
+/* $KAME: ipsec_strerror.h,v 1.8 2000/07/30 00:45:12 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.
+ */
+
+extern int __ipsec_errcode;
+extern void __ipsec_set_strerror(const char *);
+
+#define EIPSEC_NO_ERROR 0 /*success*/
+#define EIPSEC_NOT_SUPPORTED 1 /*not supported*/
+#define EIPSEC_INVAL_ARGUMENT 2 /*invalid argument*/
+#define EIPSEC_INVAL_SADBMSG 3 /*invalid sadb message*/
+#define EIPSEC_INVAL_VERSION 4 /*invalid version*/
+#define EIPSEC_INVAL_POLICY 5 /*invalid security policy*/
+#define EIPSEC_INVAL_ADDRESS 6 /*invalid address specification*/
+#define EIPSEC_INVAL_PROTO 7 /*invalid ipsec protocol*/
+#define EIPSEC_INVAL_MODE 8 /*Invalid ipsec mode*/
+#define EIPSEC_INVAL_LEVEL 9 /*invalid ipsec level*/
+#define EIPSEC_INVAL_SATYPE 10 /*invalid SA type*/
+#define EIPSEC_INVAL_MSGTYPE 11 /*invalid message type*/
+#define EIPSEC_INVAL_EXTTYPE 12 /*invalid extension type*/
+#define EIPSEC_INVAL_ALGS 13 /*Invalid algorithm type*/
+#define EIPSEC_INVAL_KEYLEN 14 /*invalid key length*/
+#define EIPSEC_INVAL_FAMILY 15 /*invalid address family*/
+#define EIPSEC_INVAL_PREFIXLEN 16 /*SPI range violation*/
+#define EIPSEC_INVAL_DIR 17 /*Invalid direciton*/
+#define EIPSEC_INVAL_SPI 18 /*invalid prefixlen*/
+#define EIPSEC_NO_PROTO 19 /*no protocol specified*/
+#define EIPSEC_NO_ALGS 20 /*No algorithm specified*/
+#define EIPSEC_NO_BUFS 21 /*no buffers available*/
+#define EIPSEC_DO_GET_SUPP_LIST 22 /*must get supported algorithm first*/
+#define EIPSEC_PROTO_MISMATCH 23 /*protocol mismatch*/
+#define EIPSEC_FAMILY_MISMATCH 24 /*family mismatch*/
+#define EIPSEC_FEW_ARGUMENTS 25 /*Too few arguments*/
+#define EIPSEC_SYSTEM_ERROR 26 /*system error*/
+#define EIPSEC_MAX 27 /*unknown error*/
diff --git a/lib/libipsec/libpfkey.h b/lib/libipsec/libpfkey.h
new file mode 100644
index 0000000..07ff582
--- /dev/null
+++ b/lib/libipsec/libpfkey.h
@@ -0,0 +1,86 @@
+/* $FreeBSD$ */
+/* $KAME: libpfkey.h,v 1.6 2001/03/05 18:22:17 thorpej 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.
+ */
+
+struct sadb_msg;
+extern void pfkey_sadump(struct sadb_msg *);
+extern void pfkey_spdump(struct sadb_msg *);
+
+struct sockaddr;
+struct sadb_alg;
+int ipsec_check_keylen(u_int, u_int, u_int);
+int ipsec_check_keylen2(u_int, u_int, u_int);
+int ipsec_get_keylen(u_int, u_int, struct sadb_alg *);
+u_int pfkey_set_softrate(u_int, u_int);
+u_int pfkey_get_softrate(u_int);
+int pfkey_send_getspi(int, u_int, u_int, struct sockaddr *, struct sockaddr *,
+ u_int32_t, u_int32_t, u_int32_t, u_int32_t);
+int pfkey_send_update(int, u_int, u_int, struct sockaddr *, struct sockaddr *,
+ u_int32_t, u_int32_t, u_int, caddr_t, u_int, u_int, u_int, u_int,
+ u_int, u_int32_t, u_int64_t, u_int64_t, u_int64_t, u_int32_t);
+int pfkey_send_add(int, u_int, u_int, struct sockaddr *, struct sockaddr *,
+ u_int32_t, u_int32_t, u_int, caddr_t, u_int, u_int, u_int, u_int,
+ u_int, u_int32_t, u_int64_t, u_int64_t, u_int64_t, u_int32_t);
+int pfkey_send_delete(int, u_int, u_int, struct sockaddr *, struct sockaddr *,
+ u_int32_t);
+int pfkey_send_delete_all(int, u_int, u_int, struct sockaddr *,
+ struct sockaddr *);
+int pfkey_send_get(int, u_int, u_int, struct sockaddr *, struct sockaddr *,
+ u_int32_t);
+int pfkey_send_register(int, u_int);
+int pfkey_recv_register(int);
+int pfkey_set_supported(struct sadb_msg *, int);
+int pfkey_send_flush(int, u_int);
+int pfkey_send_dump(int, u_int);
+int pfkey_send_promisc_toggle(int, int);
+int pfkey_send_spdadd(int, struct sockaddr *, u_int, struct sockaddr *, u_int,
+ u_int, caddr_t, int, u_int32_t);
+int pfkey_send_spdadd2(int, struct sockaddr *, u_int, struct sockaddr *, u_int,
+ u_int, u_int64_t, u_int64_t, caddr_t, int, u_int32_t);
+int pfkey_send_spdupdate(int, struct sockaddr *, u_int, struct sockaddr *,
+ u_int, u_int, caddr_t, int, u_int32_t);
+int pfkey_send_spdupdate2(int, struct sockaddr *, u_int, struct sockaddr *,
+ u_int, u_int, u_int64_t, u_int64_t, caddr_t, int, u_int32_t);
+int pfkey_send_spddelete(int, struct sockaddr *, u_int, struct sockaddr *,
+ u_int, u_int, caddr_t, int, u_int32_t);
+int pfkey_send_spddelete2(int, u_int32_t);
+int pfkey_send_spdget(int, u_int32_t);
+int pfkey_send_spdsetidx(int, struct sockaddr *, u_int, struct sockaddr *,
+ u_int, u_int, caddr_t, int, u_int32_t);
+int pfkey_send_spdflush(int);
+int pfkey_send_spddump(int);
+
+int pfkey_open(void);
+void pfkey_close(int);
+struct sadb_msg *pfkey_recv(int);
+int pfkey_send(int, struct sadb_msg *, int);
+int pfkey_align(struct sadb_msg *, caddr_t *);
+int pfkey_check(caddr_t *);
diff --git a/lib/libipsec/pfkey.c b/lib/libipsec/pfkey.c
new file mode 100644
index 0000000..ca75df4
--- /dev/null
+++ b/lib/libipsec/pfkey.c
@@ -0,0 +1,2125 @@
+/* $KAME: pfkey.c,v 1.46 2003/08/26 03:37:06 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <net/pfkeyv2.h>
+#include <netkey/key_var.h>
+#include <netinet/in.h>
+#include <netinet6/ipsec.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include "ipsec_strerror.h"
+#include "libpfkey.h"
+
+#define CALLOC(size, cast) (cast)calloc(1, (size))
+
+static int findsupportedmap(int);
+static int setsupportedmap(struct sadb_supported *);
+static struct sadb_alg *findsupportedalg(u_int, u_int);
+static int pfkey_send_x1(int, u_int, u_int, u_int, struct sockaddr *,
+ struct sockaddr *, u_int32_t, u_int32_t, u_int, caddr_t,
+ u_int, u_int, u_int, u_int, u_int, u_int32_t, u_int32_t,
+ u_int32_t, u_int32_t, u_int32_t);
+static int pfkey_send_x2(int, u_int, u_int, u_int,
+ struct sockaddr *, struct sockaddr *, u_int32_t);
+static int pfkey_send_x3(int, u_int, u_int);
+static int pfkey_send_x4(int, u_int, struct sockaddr *, u_int,
+ struct sockaddr *, u_int, u_int, u_int64_t, u_int64_t,
+ char *, int, u_int32_t);
+static int pfkey_send_x5(int, u_int, u_int32_t);
+
+static caddr_t pfkey_setsadbmsg(caddr_t, caddr_t, u_int, u_int,
+ u_int, u_int32_t, pid_t);
+static caddr_t pfkey_setsadbsa(caddr_t, caddr_t, u_int32_t, u_int,
+ u_int, u_int, u_int32_t);
+static caddr_t pfkey_setsadbaddr(caddr_t, caddr_t, u_int,
+ struct sockaddr *, u_int, u_int);
+static caddr_t pfkey_setsadbkey(caddr_t, caddr_t, u_int, caddr_t, u_int);
+static caddr_t pfkey_setsadblifetime(caddr_t, caddr_t, u_int, u_int32_t,
+ u_int32_t, u_int32_t, u_int32_t);
+static caddr_t pfkey_setsadbxsa2(caddr_t, caddr_t, u_int32_t, u_int32_t);
+
+/*
+ * make and search supported algorithm structure.
+ */
+static struct sadb_supported *ipsec_supported[] = { NULL, NULL, NULL, NULL };
+
+static int supported_map[] = {
+ SADB_SATYPE_AH,
+ SADB_SATYPE_ESP,
+ SADB_X_SATYPE_IPCOMP,
+ SADB_X_SATYPE_TCPSIGNATURE
+};
+
+static int
+findsupportedmap(satype)
+ int satype;
+{
+ int i;
+
+ for (i = 0; i < sizeof(supported_map)/sizeof(supported_map[0]); i++)
+ if (supported_map[i] == satype)
+ return i;
+ return -1;
+}
+
+static struct sadb_alg *
+findsupportedalg(satype, alg_id)
+ u_int satype, alg_id;
+{
+ int algno;
+ int tlen;
+ caddr_t p;
+
+ /* validity check */
+ algno = findsupportedmap(satype);
+ if (algno == -1) {
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return NULL;
+ }
+ if (ipsec_supported[algno] == NULL) {
+ __ipsec_errcode = EIPSEC_DO_GET_SUPP_LIST;
+ return NULL;
+ }
+
+ tlen = ipsec_supported[algno]->sadb_supported_len
+ - sizeof(struct sadb_supported);
+ p = (caddr_t)(ipsec_supported[algno] + 1);
+ while (tlen > 0) {
+ if (tlen < sizeof(struct sadb_alg)) {
+ /* invalid format */
+ break;
+ }
+ if (((struct sadb_alg *)p)->sadb_alg_id == alg_id)
+ return (struct sadb_alg *)p;
+
+ tlen -= sizeof(struct sadb_alg);
+ p += sizeof(struct sadb_alg);
+ }
+
+ __ipsec_errcode = EIPSEC_NOT_SUPPORTED;
+ return NULL;
+}
+
+static int
+setsupportedmap(sup)
+ struct sadb_supported *sup;
+{
+ struct sadb_supported **ipsup;
+
+ switch (sup->sadb_supported_exttype) {
+ case SADB_EXT_SUPPORTED_AUTH:
+ ipsup = &ipsec_supported[findsupportedmap(SADB_SATYPE_AH)];
+ break;
+ case SADB_EXT_SUPPORTED_ENCRYPT:
+ ipsup = &ipsec_supported[findsupportedmap(SADB_SATYPE_ESP)];
+ break;
+ default:
+ __ipsec_errcode = EIPSEC_INVAL_SATYPE;
+ return -1;
+ }
+
+ if (*ipsup)
+ free(*ipsup);
+
+ *ipsup = malloc(sup->sadb_supported_len);
+ if (!*ipsup) {
+ __ipsec_set_strerror(strerror(errno));
+ return -1;
+ }
+ memcpy(*ipsup, sup, sup->sadb_supported_len);
+
+ return 0;
+}
+
+/*
+ * check key length against algorithm specified.
+ * This function is called with SADB_EXT_SUPPORTED_{AUTH,ENCRYPT} as the
+ * augument, and only calls to ipsec_check_keylen2();
+ * keylen is the unit of bit.
+ * OUT:
+ * -1: invalid.
+ * 0: valid.
+ */
+int
+ipsec_check_keylen(supported, alg_id, keylen)
+ u_int supported;
+ u_int alg_id;
+ u_int keylen;
+{
+ int satype;
+
+ /* validity check */
+ switch (supported) {
+ case SADB_EXT_SUPPORTED_AUTH:
+ satype = SADB_SATYPE_AH;
+ break;
+ case SADB_EXT_SUPPORTED_ENCRYPT:
+ satype = SADB_SATYPE_ESP;
+ break;
+ default:
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+
+ return ipsec_check_keylen2(satype, alg_id, keylen);
+}
+
+/*
+ * check key length against algorithm specified.
+ * satype is one of satype defined at pfkeyv2.h.
+ * keylen is the unit of bit.
+ * OUT:
+ * -1: invalid.
+ * 0: valid.
+ */
+int
+ipsec_check_keylen2(satype, alg_id, keylen)
+ u_int satype;
+ u_int alg_id;
+ u_int keylen;
+{
+ struct sadb_alg *alg;
+
+ alg = findsupportedalg(satype, alg_id);
+ if (!alg)
+ return -1;
+
+ if (keylen < alg->sadb_alg_minbits || keylen > alg->sadb_alg_maxbits) {
+ __ipsec_errcode = EIPSEC_INVAL_KEYLEN;
+ return -1;
+ }
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return 0;
+}
+
+/*
+ * get max/min key length against algorithm specified.
+ * satype is one of satype defined at pfkeyv2.h.
+ * keylen is the unit of bit.
+ * OUT:
+ * -1: invalid.
+ * 0: valid.
+ */
+int
+ipsec_get_keylen(supported, alg_id, alg0)
+ u_int supported, alg_id;
+ struct sadb_alg *alg0;
+{
+ struct sadb_alg *alg;
+ u_int satype;
+
+ /* validity check */
+ if (!alg0) {
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+
+ switch (supported) {
+ case SADB_EXT_SUPPORTED_AUTH:
+ satype = SADB_SATYPE_AH;
+ break;
+ case SADB_EXT_SUPPORTED_ENCRYPT:
+ satype = SADB_SATYPE_ESP;
+ break;
+ default:
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+
+ alg = findsupportedalg(satype, alg_id);
+ if (!alg)
+ return -1;
+
+ memcpy(alg0, alg, sizeof(*alg0));
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return 0;
+}
+
+/*
+ * set the rate for SOFT lifetime against HARD one.
+ * If rate is more than 100 or equal to zero, then set to 100.
+ */
+static u_int soft_lifetime_allocations_rate = PFKEY_SOFT_LIFETIME_RATE;
+static u_int soft_lifetime_bytes_rate = PFKEY_SOFT_LIFETIME_RATE;
+static u_int soft_lifetime_addtime_rate = PFKEY_SOFT_LIFETIME_RATE;
+static u_int soft_lifetime_usetime_rate = PFKEY_SOFT_LIFETIME_RATE;
+
+u_int
+pfkey_set_softrate(type, rate)
+ u_int type, rate;
+{
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+
+ if (rate > 100 || rate == 0)
+ rate = 100;
+
+ switch (type) {
+ case SADB_X_LIFETIME_ALLOCATIONS:
+ soft_lifetime_allocations_rate = rate;
+ return 0;
+ case SADB_X_LIFETIME_BYTES:
+ soft_lifetime_bytes_rate = rate;
+ return 0;
+ case SADB_X_LIFETIME_ADDTIME:
+ soft_lifetime_addtime_rate = rate;
+ return 0;
+ case SADB_X_LIFETIME_USETIME:
+ soft_lifetime_usetime_rate = rate;
+ return 0;
+ }
+
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return 1;
+}
+
+/*
+ * get current rate for SOFT lifetime against HARD one.
+ * ATTENTION: ~0 is returned if invalid type was passed.
+ */
+u_int
+pfkey_get_softrate(type)
+ u_int type;
+{
+ switch (type) {
+ case SADB_X_LIFETIME_ALLOCATIONS:
+ return soft_lifetime_allocations_rate;
+ case SADB_X_LIFETIME_BYTES:
+ return soft_lifetime_bytes_rate;
+ case SADB_X_LIFETIME_ADDTIME:
+ return soft_lifetime_addtime_rate;
+ case SADB_X_LIFETIME_USETIME:
+ return soft_lifetime_usetime_rate;
+ }
+
+ return ~0;
+}
+
+/*
+ * sending SADB_GETSPI message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_getspi(so, satype, mode, src, dst, min, max, reqid, seq)
+ int so;
+ u_int satype, mode;
+ struct sockaddr *src, *dst;
+ u_int32_t min, max, reqid, seq;
+{
+ struct sadb_msg *newmsg;
+ caddr_t ep;
+ int len;
+ int need_spirange = 0;
+ caddr_t p;
+ int plen;
+
+ /* validity check */
+ if (src == NULL || dst == NULL) {
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+ if (src->sa_family != dst->sa_family) {
+ __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
+ return -1;
+ }
+ if (min > max || (min > 0 && min <= 255)) {
+ __ipsec_errcode = EIPSEC_INVAL_SPI;
+ return -1;
+ }
+ switch (src->sa_family) {
+ case AF_INET:
+ plen = sizeof(struct in_addr) << 3;
+ break;
+ case AF_INET6:
+ plen = sizeof(struct in6_addr) << 3;
+ break;
+ default:
+ __ipsec_errcode = EIPSEC_INVAL_FAMILY;
+ return -1;
+ }
+
+ /* create new sadb_msg to send. */
+ len = sizeof(struct sadb_msg)
+ + sizeof(struct sadb_x_sa2)
+ + sizeof(struct sadb_address)
+ + PFKEY_ALIGN8(src->sa_len)
+ + sizeof(struct sadb_address)
+ + PFKEY_ALIGN8(dst->sa_len);
+
+ if (min > 255 && max < ~0) {
+ need_spirange++;
+ len += sizeof(struct sadb_spirange);
+ }
+
+ if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) {
+ __ipsec_set_strerror(strerror(errno));
+ return -1;
+ }
+ ep = ((caddr_t)newmsg) + len;
+
+ p = pfkey_setsadbmsg((caddr_t)newmsg, ep, SADB_GETSPI,
+ len, satype, seq, getpid());
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+
+ p = pfkey_setsadbxsa2(p, ep, mode, reqid);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+
+ /* set sadb_address for source */
+ p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen,
+ IPSEC_ULPROTO_ANY);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+
+ /* set sadb_address for destination */
+ p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen,
+ IPSEC_ULPROTO_ANY);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+
+ /* proccessing spi range */
+ if (need_spirange) {
+ struct sadb_spirange spirange;
+
+ if (p + sizeof(spirange) > ep) {
+ free(newmsg);
+ return -1;
+ }
+
+ memset(&spirange, 0, sizeof(spirange));
+ spirange.sadb_spirange_len = PFKEY_UNIT64(sizeof(spirange));
+ spirange.sadb_spirange_exttype = SADB_EXT_SPIRANGE;
+ spirange.sadb_spirange_min = min;
+ spirange.sadb_spirange_max = max;
+
+ memcpy(p, &spirange, sizeof(spirange));
+
+ p += sizeof(spirange);
+ }
+ if (p != ep) {
+ free(newmsg);
+ return -1;
+ }
+
+ /* send message */
+ len = pfkey_send(so, newmsg, len);
+ free(newmsg);
+
+ if (len < 0)
+ return -1;
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return len;
+}
+
+/*
+ * sending SADB_UPDATE message to the kernel.
+ * The length of key material is a_keylen + e_keylen.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_update(so, satype, mode, src, dst, spi, reqid, wsize,
+ keymat, e_type, e_keylen, a_type, a_keylen, flags,
+ l_alloc, l_bytes, l_addtime, l_usetime, seq)
+ int so;
+ u_int satype, mode, wsize;
+ struct sockaddr *src, *dst;
+ u_int32_t spi, reqid;
+ caddr_t keymat;
+ u_int e_type, e_keylen, a_type, a_keylen, flags;
+ u_int32_t l_alloc;
+ u_int64_t l_bytes, l_addtime, l_usetime;
+ u_int32_t seq;
+{
+ int len;
+ if ((len = pfkey_send_x1(so, SADB_UPDATE, satype, mode, src, dst, spi,
+ reqid, wsize,
+ keymat, e_type, e_keylen, a_type, a_keylen, flags,
+ l_alloc, l_bytes, l_addtime, l_usetime, seq)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_ADD message to the kernel.
+ * The length of key material is a_keylen + e_keylen.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_add(so, satype, mode, src, dst, spi, reqid, wsize,
+ keymat, e_type, e_keylen, a_type, a_keylen, flags,
+ l_alloc, l_bytes, l_addtime, l_usetime, seq)
+ int so;
+ u_int satype, mode, wsize;
+ struct sockaddr *src, *dst;
+ u_int32_t spi, reqid;
+ caddr_t keymat;
+ u_int e_type, e_keylen, a_type, a_keylen, flags;
+ u_int32_t l_alloc;
+ u_int64_t l_bytes, l_addtime, l_usetime;
+ u_int32_t seq;
+{
+ int len;
+ if ((len = pfkey_send_x1(so, SADB_ADD, satype, mode, src, dst, spi,
+ reqid, wsize,
+ keymat, e_type, e_keylen, a_type, a_keylen, flags,
+ l_alloc, l_bytes, l_addtime, l_usetime, seq)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_DELETE message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_delete(so, satype, mode, src, dst, spi)
+ int so;
+ u_int satype, mode;
+ struct sockaddr *src, *dst;
+ u_int32_t spi;
+{
+ int len;
+ if ((len = pfkey_send_x2(so, SADB_DELETE, satype, mode, src, dst, spi)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_DELETE without spi to the kernel. This is
+ * the "delete all" request (an extension also present in
+ * Solaris).
+ *
+ * OUT:
+ * positive: success and return length sent
+ * -1 : error occured, and set errno
+ */
+int
+pfkey_send_delete_all(so, satype, mode, src, dst)
+ int so;
+ u_int satype, mode;
+ struct sockaddr *src, *dst;
+{
+ struct sadb_msg *newmsg;
+ int len;
+ caddr_t p;
+ int plen;
+ caddr_t ep;
+
+ /* validity check */
+ if (src == NULL || dst == NULL) {
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+ if (src->sa_family != dst->sa_family) {
+ __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
+ return -1;
+ }
+ switch (src->sa_family) {
+ case AF_INET:
+ plen = sizeof(struct in_addr) << 3;
+ break;
+ case AF_INET6:
+ plen = sizeof(struct in6_addr) << 3;
+ break;
+ default:
+ __ipsec_errcode = EIPSEC_INVAL_FAMILY;
+ return -1;
+ }
+
+ /* create new sadb_msg to reply. */
+ len = sizeof(struct sadb_msg)
+ + sizeof(struct sadb_address)
+ + PFKEY_ALIGN8(src->sa_len)
+ + sizeof(struct sadb_address)
+ + PFKEY_ALIGN8(dst->sa_len);
+
+ if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) {
+ __ipsec_set_strerror(strerror(errno));
+ return -1;
+ }
+ ep = ((caddr_t)newmsg) + len;
+
+ p = pfkey_setsadbmsg((caddr_t)newmsg, ep, SADB_DELETE, len, satype, 0,
+ getpid());
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen,
+ IPSEC_ULPROTO_ANY);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen,
+ IPSEC_ULPROTO_ANY);
+ if (!p || p != ep) {
+ free(newmsg);
+ return -1;
+ }
+
+ /* send message */
+ len = pfkey_send(so, newmsg, len);
+ free(newmsg);
+
+ if (len < 0)
+ return -1;
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return len;
+}
+
+/*
+ * sending SADB_GET message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_get(so, satype, mode, src, dst, spi)
+ int so;
+ u_int satype, mode;
+ struct sockaddr *src, *dst;
+ u_int32_t spi;
+{
+ int len;
+ if ((len = pfkey_send_x2(so, SADB_GET, satype, mode, src, dst, spi)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_REGISTER message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_register(so, satype)
+ int so;
+ u_int satype;
+{
+ int len, algno;
+
+ if (satype == PF_UNSPEC) {
+ for (algno = 0;
+ algno < sizeof(supported_map)/sizeof(supported_map[0]);
+ algno++) {
+ if (ipsec_supported[algno]) {
+ free(ipsec_supported[algno]);
+ ipsec_supported[algno] = NULL;
+ }
+ }
+ } else {
+ algno = findsupportedmap(satype);
+ if (algno == -1) {
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+
+ if (ipsec_supported[algno]) {
+ free(ipsec_supported[algno]);
+ ipsec_supported[algno] = NULL;
+ }
+ }
+
+ if ((len = pfkey_send_x3(so, SADB_REGISTER, satype)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * receiving SADB_REGISTER message from the kernel, and copy buffer for
+ * sadb_supported returned into ipsec_supported.
+ * OUT:
+ * 0: success and return length sent.
+ * -1: error occured, and set errno.
+ */
+int
+pfkey_recv_register(so)
+ int so;
+{
+ pid_t pid = getpid();
+ struct sadb_msg *newmsg;
+ int error = -1;
+
+ /* receive message */
+ for (;;) {
+ if ((newmsg = pfkey_recv(so)) == NULL)
+ return -1;
+ if (newmsg->sadb_msg_type == SADB_REGISTER &&
+ newmsg->sadb_msg_pid == pid)
+ break;
+ free(newmsg);
+ }
+
+ /* check and fix */
+ newmsg->sadb_msg_len = PFKEY_UNUNIT64(newmsg->sadb_msg_len);
+
+ error = pfkey_set_supported(newmsg, newmsg->sadb_msg_len);
+ free(newmsg);
+
+ if (error == 0)
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+
+ return error;
+}
+
+/*
+ * receiving SADB_REGISTER message from the kernel, and copy buffer for
+ * sadb_supported returned into ipsec_supported.
+ * NOTE: sadb_msg_len must be host order.
+ * IN:
+ * tlen: msg length, it's to makeing sure.
+ * OUT:
+ * 0: success and return length sent.
+ * -1: error occured, and set errno.
+ */
+int
+pfkey_set_supported(msg, tlen)
+ struct sadb_msg *msg;
+ int tlen;
+{
+ struct sadb_supported *sup;
+ caddr_t p;
+ caddr_t ep;
+
+ /* validity */
+ if (msg->sadb_msg_len != tlen) {
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+
+ p = (caddr_t)msg;
+ ep = p + tlen;
+
+ p += sizeof(struct sadb_msg);
+
+ while (p < ep) {
+ sup = (struct sadb_supported *)p;
+ if (ep < p + sizeof(*sup) ||
+ PFKEY_EXTLEN(sup) < sizeof(*sup) ||
+ ep < p + sup->sadb_supported_len) {
+ /* invalid format */
+ break;
+ }
+
+ switch (sup->sadb_supported_exttype) {
+ case SADB_EXT_SUPPORTED_AUTH:
+ case SADB_EXT_SUPPORTED_ENCRYPT:
+ break;
+ default:
+ __ipsec_errcode = EIPSEC_INVAL_SATYPE;
+ return -1;
+ }
+
+ /* fixed length */
+ sup->sadb_supported_len = PFKEY_EXTLEN(sup);
+
+ /* set supported map */
+ if (setsupportedmap(sup) != 0)
+ return -1;
+
+ p += sup->sadb_supported_len;
+ }
+
+ if (p != ep) {
+ __ipsec_errcode = EIPSEC_INVAL_SATYPE;
+ return -1;
+ }
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+
+ return 0;
+}
+
+/*
+ * sending SADB_FLUSH message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_flush(so, satype)
+ int so;
+ u_int satype;
+{
+ int len;
+
+ if ((len = pfkey_send_x3(so, SADB_FLUSH, satype)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_DUMP message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_dump(so, satype)
+ int so;
+ u_int satype;
+{
+ int len;
+
+ if ((len = pfkey_send_x3(so, SADB_DUMP, satype)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_X_PROMISC message to the kernel.
+ * NOTE that this function handles promisc mode toggle only.
+ * IN:
+ * flag: set promisc off if zero, set promisc on if non-zero.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ * 0 : error occured, and set errno.
+ * others: a pointer to new allocated buffer in which supported
+ * algorithms is.
+ */
+int
+pfkey_send_promisc_toggle(so, flag)
+ int so;
+ int flag;
+{
+ int len;
+
+ if ((len = pfkey_send_x3(so, SADB_X_PROMISC, (flag ? 1 : 0))) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_X_SPDADD message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_spdadd(so, src, prefs, dst, prefd, proto, policy, policylen, seq)
+ int so;
+ struct sockaddr *src, *dst;
+ u_int prefs, prefd, proto;
+ caddr_t policy;
+ int policylen;
+ u_int32_t seq;
+{
+ int len;
+
+ if ((len = pfkey_send_x4(so, SADB_X_SPDADD,
+ src, prefs, dst, prefd, proto,
+ 0, 0,
+ policy, policylen, seq)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_X_SPDADD message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_spdadd2(so, src, prefs, dst, prefd, proto, ltime, vtime,
+ policy, policylen, seq)
+ int so;
+ struct sockaddr *src, *dst;
+ u_int prefs, prefd, proto;
+ u_int64_t ltime, vtime;
+ caddr_t policy;
+ int policylen;
+ u_int32_t seq;
+{
+ int len;
+
+ if ((len = pfkey_send_x4(so, SADB_X_SPDADD,
+ src, prefs, dst, prefd, proto,
+ ltime, vtime,
+ policy, policylen, seq)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_X_SPDUPDATE message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_spdupdate(so, src, prefs, dst, prefd, proto, policy, policylen, seq)
+ int so;
+ struct sockaddr *src, *dst;
+ u_int prefs, prefd, proto;
+ caddr_t policy;
+ int policylen;
+ u_int32_t seq;
+{
+ int len;
+
+ if ((len = pfkey_send_x4(so, SADB_X_SPDUPDATE,
+ src, prefs, dst, prefd, proto,
+ 0, 0,
+ policy, policylen, seq)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_X_SPDUPDATE message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_spdupdate2(so, src, prefs, dst, prefd, proto, ltime, vtime,
+ policy, policylen, seq)
+ int so;
+ struct sockaddr *src, *dst;
+ u_int prefs, prefd, proto;
+ u_int64_t ltime, vtime;
+ caddr_t policy;
+ int policylen;
+ u_int32_t seq;
+{
+ int len;
+
+ if ((len = pfkey_send_x4(so, SADB_X_SPDUPDATE,
+ src, prefs, dst, prefd, proto,
+ ltime, vtime,
+ policy, policylen, seq)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_X_SPDDELETE message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_spddelete(so, src, prefs, dst, prefd, proto, policy, policylen, seq)
+ int so;
+ struct sockaddr *src, *dst;
+ u_int prefs, prefd, proto;
+ caddr_t policy;
+ int policylen;
+ u_int32_t seq;
+{
+ int len;
+
+ if (policylen != sizeof(struct sadb_x_policy)) {
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+
+ if ((len = pfkey_send_x4(so, SADB_X_SPDDELETE,
+ src, prefs, dst, prefd, proto,
+ 0, 0,
+ policy, policylen, seq)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_X_SPDDELETE message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_spddelete2(so, spid)
+ int so;
+ u_int32_t spid;
+{
+ int len;
+
+ if ((len = pfkey_send_x5(so, SADB_X_SPDDELETE2, spid)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_X_SPDGET message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_spdget(so, spid)
+ int so;
+ u_int32_t spid;
+{
+ int len;
+
+ if ((len = pfkey_send_x5(so, SADB_X_SPDGET, spid)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_X_SPDSETIDX message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_spdsetidx(so, src, prefs, dst, prefd, proto, policy, policylen, seq)
+ int so;
+ struct sockaddr *src, *dst;
+ u_int prefs, prefd, proto;
+ caddr_t policy;
+ int policylen;
+ u_int32_t seq;
+{
+ int len;
+
+ if (policylen != sizeof(struct sadb_x_policy)) {
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+
+ if ((len = pfkey_send_x4(so, SADB_X_SPDSETIDX,
+ src, prefs, dst, prefd, proto,
+ 0, 0,
+ policy, policylen, seq)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_SPDFLUSH message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_spdflush(so)
+ int so;
+{
+ int len;
+
+ if ((len = pfkey_send_x3(so, SADB_X_SPDFLUSH, SADB_SATYPE_UNSPEC)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_SPDDUMP message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_spddump(so)
+ int so;
+{
+ int len;
+
+ if ((len = pfkey_send_x3(so, SADB_X_SPDDUMP, SADB_SATYPE_UNSPEC)) < 0)
+ return -1;
+
+ return len;
+}
+
+/* sending SADB_ADD or SADB_UPDATE message to the kernel */
+static int
+pfkey_send_x1(so, type, satype, mode, src, dst, spi, reqid, wsize,
+ keymat, e_type, e_keylen, a_type, a_keylen, flags,
+ l_alloc, l_bytes, l_addtime, l_usetime, seq)
+ int so;
+ u_int type, satype, mode;
+ struct sockaddr *src, *dst;
+ u_int32_t spi, reqid;
+ u_int wsize;
+ caddr_t keymat;
+ u_int e_type, e_keylen, a_type, a_keylen, flags;
+ u_int32_t l_alloc, l_bytes, l_addtime, l_usetime, seq;
+{
+ struct sadb_msg *newmsg;
+ int len;
+ caddr_t p;
+ int plen;
+ caddr_t ep;
+
+ /* validity check */
+ if (src == NULL || dst == NULL) {
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+ if (src->sa_family != dst->sa_family) {
+ __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
+ return -1;
+ }
+ switch (src->sa_family) {
+ case AF_INET:
+ plen = sizeof(struct in_addr) << 3;
+ break;
+ case AF_INET6:
+ plen = sizeof(struct in6_addr) << 3;
+ break;
+ default:
+ __ipsec_errcode = EIPSEC_INVAL_FAMILY;
+ return -1;
+ }
+
+ switch (satype) {
+ case SADB_SATYPE_ESP:
+ if (e_type == SADB_EALG_NONE) {
+ __ipsec_errcode = EIPSEC_NO_ALGS;
+ return -1;
+ }
+ break;
+ case SADB_SATYPE_AH:
+ if (e_type != SADB_EALG_NONE) {
+ __ipsec_errcode = EIPSEC_INVAL_ALGS;
+ return -1;
+ }
+ if (a_type == SADB_AALG_NONE) {
+ __ipsec_errcode = EIPSEC_NO_ALGS;
+ return -1;
+ }
+ break;
+ case SADB_X_SATYPE_IPCOMP:
+ if (e_type == SADB_X_CALG_NONE) {
+ __ipsec_errcode = EIPSEC_INVAL_ALGS;
+ return -1;
+ }
+ if (a_type != SADB_AALG_NONE) {
+ __ipsec_errcode = EIPSEC_NO_ALGS;
+ return -1;
+ }
+ break;
+ case SADB_X_SATYPE_TCPSIGNATURE:
+ if (e_type != SADB_EALG_NONE) {
+ __ipsec_errcode = EIPSEC_INVAL_ALGS;
+ return -1;
+ }
+ if (a_type != SADB_X_AALG_TCP_MD5) {
+ __ipsec_errcode = EIPSEC_INVAL_ALGS;
+ return -1;
+ }
+ break;
+ default:
+ __ipsec_errcode = EIPSEC_INVAL_SATYPE;
+ return -1;
+ }
+
+ /* create new sadb_msg to reply. */
+ len = sizeof(struct sadb_msg)
+ + sizeof(struct sadb_sa)
+ + sizeof(struct sadb_x_sa2)
+ + sizeof(struct sadb_address)
+ + PFKEY_ALIGN8(src->sa_len)
+ + sizeof(struct sadb_address)
+ + PFKEY_ALIGN8(dst->sa_len)
+ + sizeof(struct sadb_lifetime)
+ + sizeof(struct sadb_lifetime);
+
+ if (e_type != SADB_EALG_NONE)
+ len += (sizeof(struct sadb_key) + PFKEY_ALIGN8(e_keylen));
+ if (a_type != SADB_AALG_NONE)
+ len += (sizeof(struct sadb_key) + PFKEY_ALIGN8(a_keylen));
+
+ if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) {
+ __ipsec_set_strerror(strerror(errno));
+ return -1;
+ }
+ ep = ((caddr_t)newmsg) + len;
+
+ p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len,
+ satype, seq, getpid());
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadbsa(p, ep, spi, wsize, a_type, e_type, flags);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadbxsa2(p, ep, mode, reqid);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen,
+ IPSEC_ULPROTO_ANY);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen,
+ IPSEC_ULPROTO_ANY);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+
+ if (e_type != SADB_EALG_NONE) {
+ p = pfkey_setsadbkey(p, ep, SADB_EXT_KEY_ENCRYPT,
+ keymat, e_keylen);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ }
+ if (a_type != SADB_AALG_NONE) {
+ p = pfkey_setsadbkey(p, ep, SADB_EXT_KEY_AUTH,
+ keymat + e_keylen, a_keylen);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ }
+
+ /* set sadb_lifetime for destination */
+ p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_HARD,
+ l_alloc, l_bytes, l_addtime, l_usetime);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_SOFT,
+ l_alloc, l_bytes, l_addtime, l_usetime);
+ if (!p || p != ep) {
+ free(newmsg);
+ return -1;
+ }
+
+ /* send message */
+ len = pfkey_send(so, newmsg, len);
+ free(newmsg);
+
+ if (len < 0)
+ return -1;
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return len;
+}
+
+/* sending SADB_DELETE or SADB_GET message to the kernel */
+static int
+pfkey_send_x2(so, type, satype, mode, src, dst, spi)
+ int so;
+ u_int type, satype, mode;
+ struct sockaddr *src, *dst;
+ u_int32_t spi;
+{
+ struct sadb_msg *newmsg;
+ int len;
+ caddr_t p;
+ int plen;
+ caddr_t ep;
+
+ /* validity check */
+ if (src == NULL || dst == NULL) {
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+ if (src->sa_family != dst->sa_family) {
+ __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
+ return -1;
+ }
+ switch (src->sa_family) {
+ case AF_INET:
+ plen = sizeof(struct in_addr) << 3;
+ break;
+ case AF_INET6:
+ plen = sizeof(struct in6_addr) << 3;
+ break;
+ default:
+ __ipsec_errcode = EIPSEC_INVAL_FAMILY;
+ return -1;
+ }
+
+ /* create new sadb_msg to reply. */
+ len = sizeof(struct sadb_msg)
+ + sizeof(struct sadb_sa)
+ + sizeof(struct sadb_address)
+ + PFKEY_ALIGN8(src->sa_len)
+ + sizeof(struct sadb_address)
+ + PFKEY_ALIGN8(dst->sa_len);
+
+ if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) {
+ __ipsec_set_strerror(strerror(errno));
+ return -1;
+ }
+ ep = ((caddr_t)newmsg) + len;
+
+ p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len, satype, 0,
+ getpid());
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadbsa(p, ep, spi, 0, 0, 0, 0);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen,
+ IPSEC_ULPROTO_ANY);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen,
+ IPSEC_ULPROTO_ANY);
+ if (!p || p != ep) {
+ free(newmsg);
+ return -1;
+ }
+
+ /* send message */
+ len = pfkey_send(so, newmsg, len);
+ free(newmsg);
+
+ if (len < 0)
+ return -1;
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return len;
+}
+
+/*
+ * sending SADB_REGISTER, SADB_FLUSH, SADB_DUMP or SADB_X_PROMISC message
+ * to the kernel
+ */
+static int
+pfkey_send_x3(so, type, satype)
+ int so;
+ u_int type, satype;
+{
+ struct sadb_msg *newmsg;
+ int len;
+ caddr_t p;
+ caddr_t ep;
+
+ /* validity check */
+ switch (type) {
+ case SADB_X_PROMISC:
+ if (satype != 0 && satype != 1) {
+ __ipsec_errcode = EIPSEC_INVAL_SATYPE;
+ return -1;
+ }
+ break;
+ default:
+ switch (satype) {
+ case SADB_SATYPE_UNSPEC:
+ case SADB_SATYPE_AH:
+ case SADB_SATYPE_ESP:
+ case SADB_X_SATYPE_IPCOMP:
+ case SADB_X_SATYPE_TCPSIGNATURE:
+ break;
+ default:
+ __ipsec_errcode = EIPSEC_INVAL_SATYPE;
+ return -1;
+ }
+ }
+
+ /* create new sadb_msg to send. */
+ len = sizeof(struct sadb_msg);
+
+ if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) {
+ __ipsec_set_strerror(strerror(errno));
+ return -1;
+ }
+ ep = ((caddr_t)newmsg) + len;
+
+ p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len, satype, 0,
+ getpid());
+ if (!p || p != ep) {
+ free(newmsg);
+ return -1;
+ }
+
+ /* send message */
+ len = pfkey_send(so, newmsg, len);
+ free(newmsg);
+
+ if (len < 0)
+ return -1;
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return len;
+}
+
+/* sending SADB_X_SPDADD message to the kernel */
+static int
+pfkey_send_x4(so, type, src, prefs, dst, prefd, proto,
+ ltime, vtime, policy, policylen, seq)
+ int so;
+ struct sockaddr *src, *dst;
+ u_int type, prefs, prefd, proto;
+ u_int64_t ltime, vtime;
+ char *policy;
+ int policylen;
+ u_int32_t seq;
+{
+ struct sadb_msg *newmsg;
+ int len;
+ caddr_t p;
+ int plen;
+ caddr_t ep;
+
+ /* validity check */
+ if (src == NULL || dst == NULL) {
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+ if (src->sa_family != dst->sa_family) {
+ __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
+ return -1;
+ }
+
+ switch (src->sa_family) {
+ case AF_INET:
+ plen = sizeof(struct in_addr) << 3;
+ break;
+ case AF_INET6:
+ plen = sizeof(struct in6_addr) << 3;
+ break;
+ default:
+ __ipsec_errcode = EIPSEC_INVAL_FAMILY;
+ return -1;
+ }
+ if (prefs > plen || prefd > plen) {
+ __ipsec_errcode = EIPSEC_INVAL_PREFIXLEN;
+ return -1;
+ }
+
+ /* create new sadb_msg to reply. */
+ len = sizeof(struct sadb_msg)
+ + sizeof(struct sadb_address)
+ + PFKEY_ALIGN8(src->sa_len)
+ + sizeof(struct sadb_address)
+ + PFKEY_ALIGN8(src->sa_len)
+ + sizeof(struct sadb_lifetime)
+ + policylen;
+
+ if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) {
+ __ipsec_set_strerror(strerror(errno));
+ return -1;
+ }
+ ep = ((caddr_t)newmsg) + len;
+
+ p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len,
+ SADB_SATYPE_UNSPEC, seq, getpid());
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, prefs, proto);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, prefd, proto);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_HARD,
+ 0, 0, ltime, vtime);
+ if (!p || p + policylen != ep) {
+ free(newmsg);
+ return -1;
+ }
+ memcpy(p, policy, policylen);
+
+ /* send message */
+ len = pfkey_send(so, newmsg, len);
+ free(newmsg);
+
+ if (len < 0)
+ return -1;
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return len;
+}
+
+/* sending SADB_X_SPDGET or SADB_X_SPDDELETE message to the kernel */
+static int
+pfkey_send_x5(so, type, spid)
+ int so;
+ u_int type;
+ u_int32_t spid;
+{
+ struct sadb_msg *newmsg;
+ struct sadb_x_policy xpl;
+ int len;
+ caddr_t p;
+ caddr_t ep;
+
+ /* create new sadb_msg to reply. */
+ len = sizeof(struct sadb_msg)
+ + sizeof(xpl);
+
+ if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) {
+ __ipsec_set_strerror(strerror(errno));
+ return -1;
+ }
+ ep = ((caddr_t)newmsg) + len;
+
+ p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len,
+ SADB_SATYPE_UNSPEC, 0, getpid());
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+
+ if (p + sizeof(xpl) != ep) {
+ free(newmsg);
+ return -1;
+ }
+ memset(&xpl, 0, sizeof(xpl));
+ xpl.sadb_x_policy_len = PFKEY_UNIT64(sizeof(xpl));
+ xpl.sadb_x_policy_exttype = SADB_X_EXT_POLICY;
+ xpl.sadb_x_policy_id = spid;
+ memcpy(p, &xpl, sizeof(xpl));
+
+ /* send message */
+ len = pfkey_send(so, newmsg, len);
+ free(newmsg);
+
+ if (len < 0)
+ return -1;
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return len;
+}
+
+/*
+ * open a socket.
+ * OUT:
+ * -1: fail.
+ * others : success and return value of socket.
+ */
+int
+pfkey_open()
+{
+ int so;
+ const int bufsiz = 128 * 1024; /*is 128K enough?*/
+
+ if ((so = socket(PF_KEY, SOCK_RAW, PF_KEY_V2)) < 0) {
+ __ipsec_set_strerror(strerror(errno));
+ return -1;
+ }
+
+ /*
+ * This is a temporary workaround for KAME PR 154.
+ * Don't really care even if it fails.
+ */
+ (void)setsockopt(so, SOL_SOCKET, SO_SNDBUF, &bufsiz, sizeof(bufsiz));
+ (void)setsockopt(so, SOL_SOCKET, SO_RCVBUF, &bufsiz, sizeof(bufsiz));
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return so;
+}
+
+/*
+ * close a socket.
+ * OUT:
+ * 0: success.
+ * -1: fail.
+ */
+void
+pfkey_close(so)
+ int so;
+{
+ (void)close(so);
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return;
+}
+
+/*
+ * receive sadb_msg data, and return pointer to new buffer allocated.
+ * Must free this buffer later.
+ * OUT:
+ * NULL : error occured.
+ * others : a pointer to sadb_msg structure.
+ *
+ * XXX should be rewritten to pass length explicitly
+ */
+struct sadb_msg *
+pfkey_recv(so)
+ int so;
+{
+ struct sadb_msg buf, *newmsg;
+ int len, reallen;
+
+ while ((len = recv(so, (caddr_t)&buf, sizeof(buf), MSG_PEEK)) < 0) {
+ if (errno == EINTR)
+ continue;
+ __ipsec_set_strerror(strerror(errno));
+ return NULL;
+ }
+
+ if (len < sizeof(buf)) {
+ recv(so, (caddr_t)&buf, sizeof(buf), 0);
+ __ipsec_errcode = EIPSEC_MAX;
+ return NULL;
+ }
+
+ /* read real message */
+ reallen = PFKEY_UNUNIT64(buf.sadb_msg_len);
+ if ((newmsg = CALLOC(reallen, struct sadb_msg *)) == 0) {
+ __ipsec_set_strerror(strerror(errno));
+ return NULL;
+ }
+
+ while ((len = recv(so, (caddr_t)newmsg, reallen, 0)) < 0) {
+ if (errno == EINTR)
+ continue;
+ __ipsec_set_strerror(strerror(errno));
+ free(newmsg);
+ return NULL;
+ }
+
+ if (len != reallen) {
+ __ipsec_errcode = EIPSEC_SYSTEM_ERROR;
+ free(newmsg);
+ return NULL;
+ }
+
+ /* don't trust what the kernel says, validate! */
+ if (PFKEY_UNUNIT64(newmsg->sadb_msg_len) != len) {
+ __ipsec_errcode = EIPSEC_SYSTEM_ERROR;
+ free(newmsg);
+ return NULL;
+ }
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return newmsg;
+}
+
+/*
+ * send message to a socket.
+ * OUT:
+ * others: success and return length sent.
+ * -1 : fail.
+ */
+int
+pfkey_send(so, msg, len)
+ int so;
+ struct sadb_msg *msg;
+ int len;
+{
+ if ((len = send(so, (caddr_t)msg, len, 0)) < 0) {
+ __ipsec_set_strerror(strerror(errno));
+ return -1;
+ }
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return len;
+}
+
+/*
+ * %%% Utilities
+ * NOTE: These functions are derived from netkey/key.c in KAME.
+ */
+/*
+ * set the pointer to each header in this message buffer.
+ * IN: msg: pointer to message buffer.
+ * mhp: pointer to the buffer initialized like below:
+ * caddr_t mhp[SADB_EXT_MAX + 1];
+ * OUT: -1: invalid.
+ * 0: valid.
+ *
+ * XXX should be rewritten to obtain length explicitly
+ */
+int
+pfkey_align(msg, mhp)
+ struct sadb_msg *msg;
+ caddr_t *mhp;
+{
+ struct sadb_ext *ext;
+ int i;
+ caddr_t p;
+ caddr_t ep; /* XXX should be passed from upper layer */
+
+ /* validity check */
+ if (msg == NULL || mhp == NULL) {
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+
+ /* initialize */
+ for (i = 0; i < SADB_EXT_MAX + 1; i++)
+ mhp[i] = NULL;
+
+ mhp[0] = (caddr_t)msg;
+
+ /* initialize */
+ p = (caddr_t) msg;
+ ep = p + PFKEY_UNUNIT64(msg->sadb_msg_len);
+
+ /* skip base header */
+ p += sizeof(struct sadb_msg);
+
+ while (p < ep) {
+ ext = (struct sadb_ext *)p;
+ if (ep < p + sizeof(*ext) || PFKEY_EXTLEN(ext) < sizeof(*ext) ||
+ ep < p + PFKEY_EXTLEN(ext)) {
+ /* invalid format */
+ break;
+ }
+
+ /* duplicate check */
+ /* XXX Are there duplication either KEY_AUTH or KEY_ENCRYPT ?*/
+ if (mhp[ext->sadb_ext_type] != NULL) {
+ __ipsec_errcode = EIPSEC_INVAL_EXTTYPE;
+ return -1;
+ }
+
+ /* set pointer */
+ switch (ext->sadb_ext_type) {
+ case SADB_EXT_SA:
+ case SADB_EXT_LIFETIME_CURRENT:
+ case SADB_EXT_LIFETIME_HARD:
+ case SADB_EXT_LIFETIME_SOFT:
+ case SADB_EXT_ADDRESS_SRC:
+ case SADB_EXT_ADDRESS_DST:
+ case SADB_EXT_ADDRESS_PROXY:
+ case SADB_EXT_KEY_AUTH:
+ /* XXX should to be check weak keys. */
+ case SADB_EXT_KEY_ENCRYPT:
+ /* XXX should to be check weak keys. */
+ case SADB_EXT_IDENTITY_SRC:
+ case SADB_EXT_IDENTITY_DST:
+ case SADB_EXT_SENSITIVITY:
+ case SADB_EXT_PROPOSAL:
+ case SADB_EXT_SUPPORTED_AUTH:
+ case SADB_EXT_SUPPORTED_ENCRYPT:
+ case SADB_EXT_SPIRANGE:
+ case SADB_X_EXT_POLICY:
+ case SADB_X_EXT_SA2:
+ mhp[ext->sadb_ext_type] = (caddr_t)ext;
+ break;
+ default:
+ __ipsec_errcode = EIPSEC_INVAL_EXTTYPE;
+ return -1;
+ }
+
+ p += PFKEY_EXTLEN(ext);
+ }
+
+ if (p != ep) {
+ __ipsec_errcode = EIPSEC_INVAL_SADBMSG;
+ return -1;
+ }
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return 0;
+}
+
+/*
+ * check basic usage for sadb_msg,
+ * NOTE: This routine is derived from netkey/key.c in KAME.
+ * IN: msg: pointer to message buffer.
+ * mhp: pointer to the buffer initialized like below:
+ *
+ * caddr_t mhp[SADB_EXT_MAX + 1];
+ *
+ * OUT: -1: invalid.
+ * 0: valid.
+ */
+int
+pfkey_check(mhp)
+ caddr_t *mhp;
+{
+ struct sadb_msg *msg;
+
+ /* validity check */
+ if (mhp == NULL || mhp[0] == NULL) {
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+
+ msg = (struct sadb_msg *)mhp[0];
+
+ /* check version */
+ if (msg->sadb_msg_version != PF_KEY_V2) {
+ __ipsec_errcode = EIPSEC_INVAL_VERSION;
+ return -1;
+ }
+
+ /* check type */
+ if (msg->sadb_msg_type > SADB_MAX) {
+ __ipsec_errcode = EIPSEC_INVAL_MSGTYPE;
+ return -1;
+ }
+
+ /* check SA type */
+ switch (msg->sadb_msg_satype) {
+ case SADB_SATYPE_UNSPEC:
+ switch (msg->sadb_msg_type) {
+ case SADB_GETSPI:
+ case SADB_UPDATE:
+ case SADB_ADD:
+ case SADB_DELETE:
+ case SADB_GET:
+ case SADB_ACQUIRE:
+ case SADB_EXPIRE:
+ __ipsec_errcode = EIPSEC_INVAL_SATYPE;
+ return -1;
+ }
+ break;
+ case SADB_SATYPE_ESP:
+ case SADB_SATYPE_AH:
+ case SADB_X_SATYPE_IPCOMP:
+ case SADB_X_SATYPE_TCPSIGNATURE:
+ switch (msg->sadb_msg_type) {
+ case SADB_X_SPDADD:
+ case SADB_X_SPDDELETE:
+ case SADB_X_SPDGET:
+ case SADB_X_SPDDUMP:
+ case SADB_X_SPDFLUSH:
+ __ipsec_errcode = EIPSEC_INVAL_SATYPE;
+ return -1;
+ }
+ break;
+ case SADB_SATYPE_RSVP:
+ case SADB_SATYPE_OSPFV2:
+ case SADB_SATYPE_RIPV2:
+ case SADB_SATYPE_MIP:
+ __ipsec_errcode = EIPSEC_NOT_SUPPORTED;
+ return -1;
+ case 1: /* XXX: What does it do ? */
+ if (msg->sadb_msg_type == SADB_X_PROMISC)
+ break;
+ /*FALLTHROUGH*/
+ default:
+ __ipsec_errcode = EIPSEC_INVAL_SATYPE;
+ return -1;
+ }
+
+ /* check field of upper layer protocol and address family */
+ if (mhp[SADB_EXT_ADDRESS_SRC] != NULL
+ && mhp[SADB_EXT_ADDRESS_DST] != NULL) {
+ struct sadb_address *src0, *dst0;
+
+ src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]);
+ dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]);
+
+ if (src0->sadb_address_proto != dst0->sadb_address_proto) {
+ __ipsec_errcode = EIPSEC_PROTO_MISMATCH;
+ return -1;
+ }
+
+ if (PFKEY_ADDR_SADDR(src0)->sa_family
+ != PFKEY_ADDR_SADDR(dst0)->sa_family) {
+ __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
+ return -1;
+ }
+
+ switch (PFKEY_ADDR_SADDR(src0)->sa_family) {
+ case AF_INET:
+ case AF_INET6:
+ break;
+ default:
+ __ipsec_errcode = EIPSEC_INVAL_FAMILY;
+ return -1;
+ }
+
+ /*
+ * prefixlen == 0 is valid because there must be the case
+ * all addresses are matched.
+ */
+ }
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return 0;
+}
+
+/*
+ * set data into sadb_msg.
+ * `buf' must has been allocated sufficiently.
+ */
+static caddr_t
+pfkey_setsadbmsg(buf, lim, type, tlen, satype, seq, pid)
+ caddr_t buf;
+ caddr_t lim;
+ u_int type, satype;
+ u_int tlen;
+ u_int32_t seq;
+ pid_t pid;
+{
+ struct sadb_msg *p;
+ u_int len;
+
+ p = (struct sadb_msg *)buf;
+ len = sizeof(struct sadb_msg);
+
+ if (buf + len > lim)
+ return NULL;
+
+ memset(p, 0, len);
+ p->sadb_msg_version = PF_KEY_V2;
+ p->sadb_msg_type = type;
+ p->sadb_msg_errno = 0;
+ p->sadb_msg_satype = satype;
+ p->sadb_msg_len = PFKEY_UNIT64(tlen);
+ p->sadb_msg_reserved = 0;
+ p->sadb_msg_seq = seq;
+ p->sadb_msg_pid = (u_int32_t)pid;
+
+ return(buf + len);
+}
+
+/*
+ * copy secasvar data into sadb_address.
+ * `buf' must has been allocated sufficiently.
+ */
+static caddr_t
+pfkey_setsadbsa(buf, lim, spi, wsize, auth, enc, flags)
+ caddr_t buf;
+ caddr_t lim;
+ u_int32_t spi, flags;
+ u_int wsize, auth, enc;
+{
+ struct sadb_sa *p;
+ u_int len;
+
+ p = (struct sadb_sa *)buf;
+ len = sizeof(struct sadb_sa);
+
+ if (buf + len > lim)
+ return NULL;
+
+ memset(p, 0, len);
+ p->sadb_sa_len = PFKEY_UNIT64(len);
+ p->sadb_sa_exttype = SADB_EXT_SA;
+ p->sadb_sa_spi = spi;
+ p->sadb_sa_replay = wsize;
+ p->sadb_sa_state = SADB_SASTATE_LARVAL;
+ p->sadb_sa_auth = auth;
+ p->sadb_sa_encrypt = enc;
+ p->sadb_sa_flags = flags;
+
+ return(buf + len);
+}
+
+/*
+ * set data into sadb_address.
+ * `buf' must has been allocated sufficiently.
+ * prefixlen is in bits.
+ */
+static caddr_t
+pfkey_setsadbaddr(buf, lim, exttype, saddr, prefixlen, ul_proto)
+ caddr_t buf;
+ caddr_t lim;
+ u_int exttype;
+ struct sockaddr *saddr;
+ u_int prefixlen;
+ u_int ul_proto;
+{
+ struct sadb_address *p;
+ u_int len;
+
+ p = (struct sadb_address *)buf;
+ len = sizeof(struct sadb_address) + PFKEY_ALIGN8(saddr->sa_len);
+
+ if (buf + len > lim)
+ return NULL;
+
+ memset(p, 0, len);
+ p->sadb_address_len = PFKEY_UNIT64(len);
+ p->sadb_address_exttype = exttype & 0xffff;
+ p->sadb_address_proto = ul_proto & 0xff;
+ p->sadb_address_prefixlen = prefixlen;
+ p->sadb_address_reserved = 0;
+
+ memcpy(p + 1, saddr, saddr->sa_len);
+
+ return(buf + len);
+}
+
+/*
+ * set sadb_key structure after clearing buffer with zero.
+ * OUT: the pointer of buf + len.
+ */
+static caddr_t
+pfkey_setsadbkey(buf, lim, type, key, keylen)
+ caddr_t buf;
+ caddr_t lim;
+ caddr_t key;
+ u_int type, keylen;
+{
+ struct sadb_key *p;
+ u_int len;
+
+ p = (struct sadb_key *)buf;
+ len = sizeof(struct sadb_key) + PFKEY_ALIGN8(keylen);
+
+ if (buf + len > lim)
+ return NULL;
+
+ memset(p, 0, len);
+ p->sadb_key_len = PFKEY_UNIT64(len);
+ p->sadb_key_exttype = type;
+ p->sadb_key_bits = keylen << 3;
+ p->sadb_key_reserved = 0;
+
+ memcpy(p + 1, key, keylen);
+
+ return buf + len;
+}
+
+/*
+ * set sadb_lifetime structure after clearing buffer with zero.
+ * OUT: the pointer of buf + len.
+ */
+static caddr_t
+pfkey_setsadblifetime(buf, lim, type, l_alloc, l_bytes, l_addtime, l_usetime)
+ caddr_t buf;
+ caddr_t lim;
+ u_int type;
+ u_int32_t l_alloc, l_bytes, l_addtime, l_usetime;
+{
+ struct sadb_lifetime *p;
+ u_int len;
+
+ p = (struct sadb_lifetime *)buf;
+ len = sizeof(struct sadb_lifetime);
+
+ if (buf + len > lim)
+ return NULL;
+
+ memset(p, 0, len);
+ p->sadb_lifetime_len = PFKEY_UNIT64(len);
+ p->sadb_lifetime_exttype = type;
+
+ switch (type) {
+ case SADB_EXT_LIFETIME_SOFT:
+ p->sadb_lifetime_allocations
+ = (l_alloc * soft_lifetime_allocations_rate) /100;
+ p->sadb_lifetime_bytes
+ = (l_bytes * soft_lifetime_bytes_rate) /100;
+ p->sadb_lifetime_addtime
+ = (l_addtime * soft_lifetime_addtime_rate) /100;
+ p->sadb_lifetime_usetime
+ = (l_usetime * soft_lifetime_usetime_rate) /100;
+ break;
+ case SADB_EXT_LIFETIME_HARD:
+ p->sadb_lifetime_allocations = l_alloc;
+ p->sadb_lifetime_bytes = l_bytes;
+ p->sadb_lifetime_addtime = l_addtime;
+ p->sadb_lifetime_usetime = l_usetime;
+ break;
+ }
+
+ return buf + len;
+}
+
+/*
+ * copy secasvar data into sadb_address.
+ * `buf' must has been allocated sufficiently.
+ */
+static caddr_t
+pfkey_setsadbxsa2(buf, lim, mode0, reqid)
+ caddr_t buf;
+ caddr_t lim;
+ u_int32_t mode0;
+ u_int32_t reqid;
+{
+ struct sadb_x_sa2 *p;
+ u_int8_t mode = mode0 & 0xff;
+ u_int len;
+
+ p = (struct sadb_x_sa2 *)buf;
+ len = sizeof(struct sadb_x_sa2);
+
+ if (buf + len > lim)
+ return NULL;
+
+ memset(p, 0, len);
+ p->sadb_x_sa2_len = PFKEY_UNIT64(len);
+ p->sadb_x_sa2_exttype = SADB_X_EXT_SA2;
+ p->sadb_x_sa2_mode = mode;
+ p->sadb_x_sa2_reqid = reqid;
+
+ return(buf + len);
+}
diff --git a/lib/libipsec/pfkey_dump.c b/lib/libipsec/pfkey_dump.c
new file mode 100644
index 0000000..d8d4676
--- /dev/null
+++ b/lib/libipsec/pfkey_dump.c
@@ -0,0 +1,632 @@
+/* $KAME: pfkey_dump.c,v 1.45 2003/09/08 10:14:56 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet6/ipsec.h>
+#include <net/pfkeyv2.h>
+#include <netkey/key_var.h>
+#include <netkey/key_debug.h>
+
+#include <netinet/in.h>
+#include <netinet6/ipsec.h>
+#include <arpa/inet.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <netdb.h>
+
+#include "ipsec_strerror.h"
+#include "libpfkey.h"
+
+/* cope with old kame headers - ugly */
+#ifndef SADB_X_AALG_MD5
+#define SADB_X_AALG_MD5 SADB_AALG_MD5
+#endif
+#ifndef SADB_X_AALG_SHA
+#define SADB_X_AALG_SHA SADB_AALG_SHA
+#endif
+#ifndef SADB_X_AALG_NULL
+#define SADB_X_AALG_NULL SADB_AALG_NULL
+#endif
+
+#ifndef SADB_X_EALG_BLOWFISHCBC
+#define SADB_X_EALG_BLOWFISHCBC SADB_EALG_BLOWFISHCBC
+#endif
+#ifndef SADB_X_EALG_CAST128CBC
+#define SADB_X_EALG_CAST128CBC SADB_EALG_CAST128CBC
+#endif
+#ifndef SADB_X_EALG_RC5CBC
+#ifdef SADB_EALG_RC5CBC
+#define SADB_X_EALG_RC5CBC SADB_EALG_RC5CBC
+#endif
+#endif
+
+#define GETMSGSTR(str, num) \
+do { \
+ if (sizeof((str)[0]) == 0 \
+ || num >= sizeof(str)/sizeof((str)[0])) \
+ printf("%u ", (num)); \
+ else if (strlen((str)[(num)]) == 0) \
+ printf("%u ", (num)); \
+ else \
+ printf("%s ", (str)[(num)]); \
+} while (0)
+
+#define GETMSGV2S(v2s, num) \
+do { \
+ struct val2str *p; \
+ for (p = (v2s); p && p->str; p++) { \
+ if (p->val == (num)) \
+ break; \
+ } \
+ if (p && p->str) \
+ printf("%s ", p->str); \
+ else \
+ printf("%u ", (num)); \
+} while (0)
+
+static char *str_ipaddr(struct sockaddr *);
+static char *str_prefport(u_int, u_int, u_int, u_int);
+static void str_upperspec(u_int, u_int, u_int);
+static char *str_time(time_t);
+static void str_lifetime_byte(struct sadb_lifetime *, char *);
+
+struct val2str {
+ int val;
+ const char *str;
+};
+
+/*
+ * Must to be re-written about following strings.
+ */
+static char *str_satype[] = {
+ "unspec",
+ "unknown",
+ "ah",
+ "esp",
+ "unknown",
+ "rsvp",
+ "ospfv2",
+ "ripv2",
+ "mip",
+ "ipcomp",
+ "policy",
+ "tcp"
+};
+
+static char *str_mode[] = {
+ "any",
+ "transport",
+ "tunnel",
+};
+
+static char *str_state[] = {
+ "larval",
+ "mature",
+ "dying",
+ "dead",
+};
+
+static struct val2str str_alg_auth[] = {
+ { SADB_AALG_NONE, "none", },
+ { SADB_AALG_MD5HMAC, "hmac-md5", },
+ { SADB_AALG_SHA1HMAC, "hmac-sha1", },
+ { SADB_X_AALG_MD5, "md5", },
+ { SADB_X_AALG_SHA, "sha", },
+ { SADB_X_AALG_NULL, "null", },
+ { SADB_X_AALG_TCP_MD5, "tcp-md5", },
+#ifdef SADB_X_AALG_SHA2_256
+ { SADB_X_AALG_SHA2_256, "hmac-sha2-256", },
+#endif
+#ifdef SADB_X_AALG_SHA2_384
+ { SADB_X_AALG_SHA2_384, "hmac-sha2-384", },
+#endif
+#ifdef SADB_X_AALG_SHA2_512
+ { SADB_X_AALG_SHA2_512, "hmac-sha2-512", },
+#endif
+#ifdef SADB_X_AALG_RIPEMD160HMAC
+ { SADB_X_AALG_RIPEMD160HMAC, "hmac-ripemd160", },
+#endif
+#ifdef SADB_X_AALG_AES_XCBC_MAC
+ { SADB_X_AALG_AES_XCBC_MAC, "aes-xcbc-mac", },
+#endif
+ { -1, NULL, },
+};
+
+static struct val2str str_alg_enc[] = {
+ { SADB_EALG_NONE, "none", },
+ { SADB_EALG_DESCBC, "des-cbc", },
+ { SADB_EALG_3DESCBC, "3des-cbc", },
+ { SADB_EALG_NULL, "null", },
+#ifdef SADB_X_EALG_RC5CBC
+ { SADB_X_EALG_RC5CBC, "rc5-cbc", },
+#endif
+ { SADB_X_EALG_CAST128CBC, "cast128-cbc", },
+ { SADB_X_EALG_BLOWFISHCBC, "blowfish-cbc", },
+#ifdef SADB_X_EALG_RIJNDAELCBC
+ { SADB_X_EALG_RIJNDAELCBC, "rijndael-cbc", },
+#endif
+#ifdef SADB_X_EALG_TWOFISHCBC
+ { SADB_X_EALG_TWOFISHCBC, "twofish-cbc", },
+#endif
+#ifdef SADB_X_EALG_AESCTR
+ { SADB_X_EALG_AESCTR, "aes-ctr", },
+#endif
+ { -1, NULL, },
+};
+
+static struct val2str str_alg_comp[] = {
+ { SADB_X_CALG_NONE, "none", },
+ { SADB_X_CALG_OUI, "oui", },
+ { SADB_X_CALG_DEFLATE, "deflate", },
+ { SADB_X_CALG_LZS, "lzs", },
+ { -1, NULL, },
+};
+
+/*
+ * dump SADB_MSG formated. For debugging, you should use kdebug_sadb().
+ */
+void
+pfkey_sadump(m)
+ struct sadb_msg *m;
+{
+ caddr_t mhp[SADB_EXT_MAX + 1];
+ struct sadb_sa *m_sa;
+ struct sadb_x_sa2 *m_sa2;
+ struct sadb_lifetime *m_lftc, *m_lfth, *m_lfts;
+ struct sadb_address *m_saddr, *m_daddr, *m_paddr;
+ struct sadb_key *m_auth, *m_enc;
+ struct sadb_ident *m_sid, *m_did;
+ struct sadb_sens *m_sens;
+
+ /* check pfkey message. */
+ if (pfkey_align(m, mhp)) {
+ printf("%s\n", ipsec_strerror());
+ return;
+ }
+ if (pfkey_check(mhp)) {
+ printf("%s\n", ipsec_strerror());
+ return;
+ }
+
+ m_sa = (struct sadb_sa *)mhp[SADB_EXT_SA];
+ m_sa2 = (struct sadb_x_sa2 *)mhp[SADB_X_EXT_SA2];
+ m_lftc = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_CURRENT];
+ m_lfth = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_HARD];
+ m_lfts = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_SOFT];
+ m_saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC];
+ m_daddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST];
+ m_paddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_PROXY];
+ m_auth = (struct sadb_key *)mhp[SADB_EXT_KEY_AUTH];
+ m_enc = (struct sadb_key *)mhp[SADB_EXT_KEY_ENCRYPT];
+ m_sid = (struct sadb_ident *)mhp[SADB_EXT_IDENTITY_SRC];
+ m_did = (struct sadb_ident *)mhp[SADB_EXT_IDENTITY_DST];
+ m_sens = (struct sadb_sens *)mhp[SADB_EXT_SENSITIVITY];
+
+ /* source address */
+ if (m_saddr == NULL) {
+ printf("no ADDRESS_SRC extension.\n");
+ return;
+ }
+ printf("%s ", str_ipaddr((struct sockaddr *)(m_saddr + 1)));
+
+ /* destination address */
+ if (m_daddr == NULL) {
+ printf("no ADDRESS_DST extension.\n");
+ return;
+ }
+ printf("%s ", str_ipaddr((struct sockaddr *)(m_daddr + 1)));
+
+ /* SA type */
+ if (m_sa == NULL) {
+ printf("no SA extension.\n");
+ return;
+ }
+ if (m_sa2 == NULL) {
+ printf("no SA2 extension.\n");
+ return;
+ }
+ printf("\n\t");
+
+ GETMSGSTR(str_satype, m->sadb_msg_satype);
+
+ printf("mode=");
+ GETMSGSTR(str_mode, m_sa2->sadb_x_sa2_mode);
+
+ printf("spi=%u(0x%08x) reqid=%u(0x%08x)\n",
+ (u_int32_t)ntohl(m_sa->sadb_sa_spi),
+ (u_int32_t)ntohl(m_sa->sadb_sa_spi),
+ (u_int32_t)m_sa2->sadb_x_sa2_reqid,
+ (u_int32_t)m_sa2->sadb_x_sa2_reqid);
+
+ /* encryption key */
+ if (m->sadb_msg_satype == SADB_X_SATYPE_IPCOMP) {
+ printf("\tC: ");
+ GETMSGV2S(str_alg_comp, m_sa->sadb_sa_encrypt);
+ } else if (m->sadb_msg_satype == SADB_SATYPE_ESP) {
+ if (m_enc != NULL) {
+ printf("\tE: ");
+ GETMSGV2S(str_alg_enc, m_sa->sadb_sa_encrypt);
+ ipsec_hexdump((caddr_t)m_enc + sizeof(*m_enc),
+ m_enc->sadb_key_bits / 8);
+ printf("\n");
+ }
+ }
+
+ /* authentication key */
+ if (m_auth != NULL) {
+ printf("\tA: ");
+ GETMSGV2S(str_alg_auth, m_sa->sadb_sa_auth);
+ ipsec_hexdump((caddr_t)m_auth + sizeof(*m_auth),
+ m_auth->sadb_key_bits / 8);
+ printf("\n");
+ }
+
+ /* replay windoe size & flags */
+ printf("\tseq=0x%08x replay=%u flags=0x%08x ",
+ m_sa2->sadb_x_sa2_sequence,
+ m_sa->sadb_sa_replay,
+ m_sa->sadb_sa_flags);
+
+ /* state */
+ printf("state=");
+ GETMSGSTR(str_state, m_sa->sadb_sa_state);
+ printf("\n");
+
+ /* lifetime */
+ if (m_lftc != NULL) {
+ time_t tmp_time = time(0);
+
+ printf("\tcreated: %s",
+ str_time(m_lftc->sadb_lifetime_addtime));
+ printf("\tcurrent: %s\n", str_time(tmp_time));
+ printf("\tdiff: %lu(s)",
+ (u_long)(m_lftc->sadb_lifetime_addtime == 0 ?
+ 0 : (tmp_time - m_lftc->sadb_lifetime_addtime)));
+
+ printf("\thard: %lu(s)",
+ (u_long)(m_lfth == NULL ?
+ 0 : m_lfth->sadb_lifetime_addtime));
+ printf("\tsoft: %lu(s)\n",
+ (u_long)(m_lfts == NULL ?
+ 0 : m_lfts->sadb_lifetime_addtime));
+
+ printf("\tlast: %s",
+ str_time(m_lftc->sadb_lifetime_usetime));
+ printf("\thard: %lu(s)",
+ (u_long)(m_lfth == NULL ?
+ 0 : m_lfth->sadb_lifetime_usetime));
+ printf("\tsoft: %lu(s)\n",
+ (u_long)(m_lfts == NULL ?
+ 0 : m_lfts->sadb_lifetime_usetime));
+
+ str_lifetime_byte(m_lftc, "current");
+ str_lifetime_byte(m_lfth, "hard");
+ str_lifetime_byte(m_lfts, "soft");
+ printf("\n");
+
+ printf("\tallocated: %lu",
+ (unsigned long)m_lftc->sadb_lifetime_allocations);
+ printf("\thard: %lu",
+ (u_long)(m_lfth == NULL ?
+ 0 : m_lfth->sadb_lifetime_allocations));
+ printf("\tsoft: %lu\n",
+ (u_long)(m_lfts == NULL ?
+ 0 : m_lfts->sadb_lifetime_allocations));
+ }
+
+ printf("\tsadb_seq=%lu pid=%lu ",
+ (u_long)m->sadb_msg_seq,
+ (u_long)m->sadb_msg_pid);
+
+ /* XXX DEBUG */
+ printf("refcnt=%u\n", m->sadb_msg_reserved);
+
+ return;
+}
+
+void
+pfkey_spdump(m)
+ struct sadb_msg *m;
+{
+ char pbuf[NI_MAXSERV];
+ caddr_t mhp[SADB_EXT_MAX + 1];
+ struct sadb_address *m_saddr, *m_daddr;
+ struct sadb_x_policy *m_xpl;
+ struct sadb_lifetime *m_lftc = NULL, *m_lfth = NULL;
+ struct sockaddr *sa;
+ u_int16_t sport = 0, dport = 0;
+
+ /* check pfkey message. */
+ if (pfkey_align(m, mhp)) {
+ printf("%s\n", ipsec_strerror());
+ return;
+ }
+ if (pfkey_check(mhp)) {
+ printf("%s\n", ipsec_strerror());
+ return;
+ }
+
+ m_saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC];
+ m_daddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST];
+ m_xpl = (struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY];
+ m_lftc = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_CURRENT];
+ m_lfth = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_HARD];
+
+ if (m_saddr && m_daddr) {
+ /* source address */
+ sa = (struct sockaddr *)(m_saddr + 1);
+ switch (sa->sa_family) {
+ case AF_INET:
+ case AF_INET6:
+ if (getnameinfo(sa, sa->sa_len, NULL, 0,
+ pbuf, sizeof(pbuf), NI_NUMERICSERV) != 0)
+ sport = 0; /*XXX*/
+ else
+ sport = atoi(pbuf);
+ printf("%s%s ", str_ipaddr(sa),
+ str_prefport(sa->sa_family,
+ m_saddr->sadb_address_prefixlen, sport,
+ m_saddr->sadb_address_proto));
+ break;
+ default:
+ printf("unknown-af ");
+ break;
+ }
+
+ /* destination address */
+ sa = (struct sockaddr *)(m_daddr + 1);
+ switch (sa->sa_family) {
+ case AF_INET:
+ case AF_INET6:
+ if (getnameinfo(sa, sa->sa_len, NULL, 0,
+ pbuf, sizeof(pbuf), NI_NUMERICSERV) != 0)
+ dport = 0; /*XXX*/
+ else
+ dport = atoi(pbuf);
+ printf("%s%s ", str_ipaddr(sa),
+ str_prefport(sa->sa_family,
+ m_daddr->sadb_address_prefixlen, dport,
+ m_saddr->sadb_address_proto));
+ break;
+ default:
+ printf("unknown-af ");
+ break;
+ }
+
+ /* upper layer protocol */
+ if (m_saddr->sadb_address_proto !=
+ m_daddr->sadb_address_proto) {
+ printf("upper layer protocol mismatched.\n");
+ return;
+ }
+ str_upperspec(m_saddr->sadb_address_proto, sport, dport);
+ }
+ else
+ printf("(no selector, probably per-socket policy) ");
+
+ /* policy */
+ {
+ char *d_xpl;
+
+ if (m_xpl == NULL) {
+ printf("no X_POLICY extension.\n");
+ return;
+ }
+ d_xpl = ipsec_dump_policy((char *)m_xpl, "\n\t");
+
+ /* dump SPD */
+ printf("\n\t%s\n", d_xpl);
+ free(d_xpl);
+ }
+
+ /* lifetime */
+ if (m_lftc) {
+ printf("\tcreated: %s ",
+ str_time(m_lftc->sadb_lifetime_addtime));
+ printf("lastused: %s\n",
+ str_time(m_lftc->sadb_lifetime_usetime));
+ }
+ if (m_lfth) {
+ printf("\tlifetime: %lu(s) ",
+ (u_long)m_lfth->sadb_lifetime_addtime);
+ printf("validtime: %lu(s)\n",
+ (u_long)m_lfth->sadb_lifetime_usetime);
+ }
+
+
+ printf("\tspid=%ld seq=%ld pid=%ld\n",
+ (u_long)m_xpl->sadb_x_policy_id,
+ (u_long)m->sadb_msg_seq,
+ (u_long)m->sadb_msg_pid);
+
+ /* XXX TEST */
+ printf("\trefcnt=%u\n", m->sadb_msg_reserved);
+
+ return;
+}
+
+/*
+ * set "ipaddress" to buffer.
+ */
+static char *
+str_ipaddr(sa)
+ struct sockaddr *sa;
+{
+ static char buf[NI_MAXHOST];
+ const int niflag = NI_NUMERICHOST;
+
+ if (sa == NULL)
+ return "";
+
+ if (getnameinfo(sa, sa->sa_len, buf, sizeof(buf), NULL, 0, niflag) == 0)
+ return buf;
+ return NULL;
+}
+
+/*
+ * set "/prefix[port number]" to buffer.
+ */
+static char *
+str_prefport(family, pref, port, ulp)
+ u_int family, pref, port, ulp;
+{
+ static char buf[128];
+ char prefbuf[128];
+ char portbuf[128];
+ int plen;
+
+ switch (family) {
+ case AF_INET:
+ plen = sizeof(struct in_addr) << 3;
+ break;
+ case AF_INET6:
+ plen = sizeof(struct in6_addr) << 3;
+ break;
+ default:
+ return "?";
+ }
+
+ if (pref == plen)
+ prefbuf[0] = '\0';
+ else
+ snprintf(prefbuf, sizeof(prefbuf), "/%u", pref);
+
+ if (ulp == IPPROTO_ICMPV6)
+ memset(portbuf, 0, sizeof(portbuf));
+ else {
+ if (port == IPSEC_PORT_ANY)
+ snprintf(portbuf, sizeof(portbuf), "[%s]", "any");
+ else
+ snprintf(portbuf, sizeof(portbuf), "[%u]", port);
+ }
+
+ snprintf(buf, sizeof(buf), "%s%s", prefbuf, portbuf);
+
+ return buf;
+}
+
+static void
+str_upperspec(ulp, p1, p2)
+ u_int ulp, p1, p2;
+{
+ if (ulp == IPSEC_ULPROTO_ANY)
+ printf("any");
+ else if (ulp == IPPROTO_ICMPV6) {
+ printf("icmp6");
+ if (!(p1 == IPSEC_PORT_ANY && p2 == IPSEC_PORT_ANY))
+ printf(" %u,%u", p1, p2);
+ } else {
+ struct protoent *ent;
+
+ switch (ulp) {
+ case IPPROTO_IPV4:
+ printf("ip4");
+ break;
+ default:
+ ent = getprotobynumber(ulp);
+ if (ent)
+ printf("%s", ent->p_name);
+ else
+ printf("%u", ulp);
+
+ endprotoent();
+ break;
+ }
+ }
+}
+
+/*
+ * set "Mon Day Time Year" to buffer
+ */
+static char *
+str_time(t)
+ time_t t;
+{
+ static char buf[128];
+
+ if (t == 0) {
+ int i = 0;
+ for (;i < 20;) buf[i++] = ' ';
+ } else {
+ char *t0;
+ t0 = ctime(&t);
+ memcpy(buf, t0 + 4, 20);
+ }
+
+ buf[20] = '\0';
+
+ return(buf);
+}
+
+static void
+str_lifetime_byte(x, str)
+ struct sadb_lifetime *x;
+ char *str;
+{
+ double y;
+ char *unit;
+ int w;
+
+ if (x == NULL) {
+ printf("\t%s: 0(bytes)", str);
+ return;
+ }
+
+#if 0
+ if ((x->sadb_lifetime_bytes) / 1024 / 1024) {
+ y = (x->sadb_lifetime_bytes) * 1.0 / 1024 / 1024;
+ unit = "M";
+ w = 1;
+ } else if ((x->sadb_lifetime_bytes) / 1024) {
+ y = (x->sadb_lifetime_bytes) * 1.0 / 1024;
+ unit = "K";
+ w = 1;
+ } else {
+ y = (x->sadb_lifetime_bytes) * 1.0;
+ unit = "";
+ w = 0;
+ }
+#else
+ y = (x->sadb_lifetime_bytes) * 1.0;
+ unit = "";
+ w = 0;
+#endif
+ printf("\t%s: %.*f(%sbytes)", str, w, y, unit);
+}
diff --git a/lib/libipsec/policy_parse.y b/lib/libipsec/policy_parse.y
new file mode 100644
index 0000000..ae25958
--- /dev/null
+++ b/lib/libipsec/policy_parse.y
@@ -0,0 +1,439 @@
+/* $KAME: policy_parse.y,v 1.14 2003/06/27 03:39:20 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.
+ */
+
+/*
+ * IN/OUT bound policy configuration take place such below:
+ * in <policy>
+ * out <policy>
+ *
+ * <policy> is one of following:
+ * "discard", "none", "ipsec <requests>", "entrust", "bypass",
+ *
+ * The following requests are accepted as <requests>:
+ *
+ * protocol/mode/src-dst/level
+ * protocol/mode/src-dst parsed as protocol/mode/src-dst/default
+ * protocol/mode/src-dst/ parsed as protocol/mode/src-dst/default
+ * protocol/transport parsed as protocol/mode/any-any/default
+ * protocol/transport//level parsed as protocol/mode/any-any/level
+ *
+ * You can concatenate these requests with either ' '(single space) or '\n'.
+ */
+
+%{
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <netinet6/ipsec.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <netdb.h>
+
+#include "ipsec_strerror.h"
+
+#define ATOX(c) \
+ (isdigit(c) ? (c - '0') : (isupper(c) ? (c - 'A' + 10) : (c - 'a' + 10) ))
+
+static caddr_t pbuf = NULL; /* sadb_x_policy buffer */
+static int tlen = 0; /* total length of pbuf */
+static int offset = 0; /* offset of pbuf */
+static int p_dir, p_type, p_protocol, p_mode, p_level, p_reqid;
+static struct sockaddr *p_src = NULL;
+static struct sockaddr *p_dst = NULL;
+
+struct _val;
+extern void yyerror(char *msg);
+static struct sockaddr *parse_sockaddr(struct _val *buf);
+static int rule_check(void);
+static int init_x_policy(void);
+static int set_x_request(struct sockaddr *src, struct sockaddr *dst);
+static int set_sockaddr(struct sockaddr *addr);
+static void policy_parse_request_init(void);
+static caddr_t policy_parse(char *msg, int msglen);
+
+extern void __policy__strbuffer__init__(char *msg);
+extern void __policy__strbuffer__free__(void);
+extern int yyparse(void);
+extern int yylex(void);
+
+extern char *__libipsecyytext; /*XXX*/
+
+%}
+
+%union {
+ u_int num;
+ struct _val {
+ int len;
+ char *buf;
+ } val;
+}
+
+%token DIR ACTION PROTOCOL MODE LEVEL LEVEL_SPECIFY
+%token IPADDRESS
+%token ME ANY
+%token SLASH HYPHEN
+%type <num> DIR ACTION PROTOCOL MODE LEVEL
+%type <val> IPADDRESS LEVEL_SPECIFY
+
+%%
+policy_spec
+ : DIR ACTION
+ {
+ p_dir = $1;
+ p_type = $2;
+
+ if (init_x_policy())
+ return -1;
+ }
+ rules
+ | DIR
+ {
+ p_dir = $1;
+ p_type = 0; /* ignored it by kernel */
+
+ if (init_x_policy())
+ return -1;
+ }
+ ;
+
+rules
+ : /*NOTHING*/
+ | rules rule {
+ if (rule_check() < 0)
+ return -1;
+
+ if (set_x_request(p_src, p_dst) < 0)
+ return -1;
+
+ policy_parse_request_init();
+ }
+ ;
+
+rule
+ : protocol SLASH mode SLASH addresses SLASH level
+ | protocol SLASH mode SLASH addresses SLASH
+ | protocol SLASH mode SLASH addresses
+ | protocol SLASH mode SLASH
+ | protocol SLASH mode SLASH SLASH level
+ | protocol SLASH mode
+ | protocol SLASH {
+ __ipsec_errcode = EIPSEC_FEW_ARGUMENTS;
+ return -1;
+ }
+ | protocol {
+ __ipsec_errcode = EIPSEC_FEW_ARGUMENTS;
+ return -1;
+ }
+ ;
+
+protocol
+ : PROTOCOL { p_protocol = $1; }
+ ;
+
+mode
+ : MODE { p_mode = $1; }
+ ;
+
+level
+ : LEVEL {
+ p_level = $1;
+ p_reqid = 0;
+ }
+ | LEVEL_SPECIFY {
+ p_level = IPSEC_LEVEL_UNIQUE;
+ p_reqid = atol($1.buf); /* atol() is good. */
+ }
+ ;
+
+addresses
+ : IPADDRESS {
+ p_src = parse_sockaddr(&$1);
+ if (p_src == NULL)
+ return -1;
+ }
+ HYPHEN
+ IPADDRESS {
+ p_dst = parse_sockaddr(&$4);
+ if (p_dst == NULL)
+ return -1;
+ }
+ | ME HYPHEN ANY {
+ if (p_dir != IPSEC_DIR_OUTBOUND) {
+ __ipsec_errcode = EIPSEC_INVAL_DIR;
+ return -1;
+ }
+ }
+ | ANY HYPHEN ME {
+ if (p_dir != IPSEC_DIR_INBOUND) {
+ __ipsec_errcode = EIPSEC_INVAL_DIR;
+ return -1;
+ }
+ }
+ /*
+ | ME HYPHEN ME
+ */
+ ;
+
+%%
+
+void
+yyerror(msg)
+ char *msg;
+{
+ fprintf(stderr, "libipsec: %s while parsing \"%s\"\n",
+ msg, __libipsecyytext);
+
+ return;
+}
+
+static struct sockaddr *
+parse_sockaddr(buf)
+ struct _val *buf;
+{
+ struct addrinfo hints, *res;
+ char *serv = NULL;
+ int error;
+ struct sockaddr *newaddr = NULL;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_flags = AI_NUMERICHOST;
+ error = getaddrinfo(buf->buf, serv, &hints, &res);
+ if (error != 0) {
+ yyerror("invalid IP address");
+ __ipsec_set_strerror(gai_strerror(error));
+ return NULL;
+ }
+
+ if (res->ai_addr == NULL) {
+ yyerror("invalid IP address");
+ __ipsec_set_strerror(gai_strerror(error));
+ return NULL;
+ }
+
+ newaddr = malloc(res->ai_addr->sa_len);
+ if (newaddr == NULL) {
+ __ipsec_errcode = EIPSEC_NO_BUFS;
+ freeaddrinfo(res);
+ return NULL;
+ }
+ memcpy(newaddr, res->ai_addr, res->ai_addr->sa_len);
+
+ freeaddrinfo(res);
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return newaddr;
+}
+
+static int
+rule_check()
+{
+ if (p_type == IPSEC_POLICY_IPSEC) {
+ if (p_protocol == IPPROTO_IP) {
+ __ipsec_errcode = EIPSEC_NO_PROTO;
+ return -1;
+ }
+
+ if (p_mode != IPSEC_MODE_TRANSPORT
+ && p_mode != IPSEC_MODE_TUNNEL) {
+ __ipsec_errcode = EIPSEC_INVAL_MODE;
+ return -1;
+ }
+
+ if (p_src == NULL && p_dst == NULL) {
+ if (p_mode != IPSEC_MODE_TRANSPORT) {
+ __ipsec_errcode = EIPSEC_INVAL_ADDRESS;
+ return -1;
+ }
+ }
+ else if (p_src->sa_family != p_dst->sa_family) {
+ __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
+ return -1;
+ }
+ }
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return 0;
+}
+
+static int
+init_x_policy()
+{
+ struct sadb_x_policy *p;
+
+ tlen = sizeof(struct sadb_x_policy);
+
+ pbuf = malloc(tlen);
+ if (pbuf == NULL) {
+ __ipsec_errcode = EIPSEC_NO_BUFS;
+ return -1;
+ }
+ memset(pbuf, 0, tlen);
+ p = (struct sadb_x_policy *)pbuf;
+ p->sadb_x_policy_len = 0; /* must update later */
+ p->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
+ p->sadb_x_policy_type = p_type;
+ p->sadb_x_policy_dir = p_dir;
+ p->sadb_x_policy_id = 0;
+
+ offset = tlen;
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return 0;
+}
+
+static int
+set_x_request(src, dst)
+ struct sockaddr *src, *dst;
+{
+ struct sadb_x_ipsecrequest *p;
+ int reqlen;
+
+ reqlen = sizeof(*p)
+ + (src ? src->sa_len : 0)
+ + (dst ? dst->sa_len : 0);
+ tlen += reqlen; /* increment to total length */
+
+ pbuf = realloc(pbuf, tlen);
+ if (pbuf == NULL) {
+ __ipsec_errcode = EIPSEC_NO_BUFS;
+ return -1;
+ }
+ p = (struct sadb_x_ipsecrequest *)&pbuf[offset];
+ p->sadb_x_ipsecrequest_len = reqlen;
+ p->sadb_x_ipsecrequest_proto = p_protocol;
+ p->sadb_x_ipsecrequest_mode = p_mode;
+ p->sadb_x_ipsecrequest_level = p_level;
+ p->sadb_x_ipsecrequest_reqid = p_reqid;
+ offset += sizeof(*p);
+
+ if (set_sockaddr(src) || set_sockaddr(dst))
+ return -1;
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return 0;
+}
+
+static int
+set_sockaddr(addr)
+ struct sockaddr *addr;
+{
+ if (addr == NULL) {
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return 0;
+ }
+
+ /* tlen has already incremented */
+
+ memcpy(&pbuf[offset], addr, addr->sa_len);
+
+ offset += addr->sa_len;
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return 0;
+}
+
+static void
+policy_parse_request_init()
+{
+ p_protocol = IPPROTO_IP;
+ p_mode = IPSEC_MODE_ANY;
+ p_level = IPSEC_LEVEL_DEFAULT;
+ p_reqid = 0;
+ if (p_src != NULL) {
+ free(p_src);
+ p_src = NULL;
+ }
+ if (p_dst != NULL) {
+ free(p_dst);
+ p_dst = NULL;
+ }
+
+ return;
+}
+
+static caddr_t
+policy_parse(msg, msglen)
+ char *msg;
+ int msglen;
+{
+ int error;
+ pbuf = NULL;
+ tlen = 0;
+
+ /* initialize */
+ p_dir = IPSEC_DIR_INVALID;
+ p_type = IPSEC_POLICY_DISCARD;
+ policy_parse_request_init();
+ __policy__strbuffer__init__(msg);
+
+ error = yyparse(); /* it must be set errcode. */
+ __policy__strbuffer__free__();
+
+ if (error) {
+ if (pbuf != NULL)
+ free(pbuf);
+ return NULL;
+ }
+
+ /* update total length */
+ ((struct sadb_x_policy *)pbuf)->sadb_x_policy_len = PFKEY_UNIT64(tlen);
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+
+ return pbuf;
+}
+
+caddr_t
+ipsec_set_policy(msg, msglen)
+ char *msg;
+ int msglen;
+{
+ caddr_t policy;
+
+ policy = policy_parse(msg, msglen);
+ if (policy == NULL) {
+ if (__ipsec_errcode == EIPSEC_NO_ERROR)
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return NULL;
+ }
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return policy;
+}
+
diff --git a/lib/libipsec/policy_token.l b/lib/libipsec/policy_token.l
new file mode 100644
index 0000000..f957569
--- /dev/null
+++ b/lib/libipsec/policy_token.l
@@ -0,0 +1,155 @@
+/* $FreeBSD$ */
+/* $KAME: policy_token.l,v 1.13 2003/05/09 05:19:55 sakane 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.
+ */
+
+%{
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <net/route.h>
+#include <net/pfkeyv2.h>
+#include <netkey/keydb.h>
+#include <netinet/in.h>
+#include <netinet6/ipsec.h>
+
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "y.tab.h"
+#define yylval __libipsecyylval /* XXX */
+
+int yylex(void);
+%}
+
+%option noyywrap
+%option nounput
+
+/* common section */
+nl \n
+ws [ \t]+
+digit [0-9]
+hexdigit [0-9A-Fa-f]
+special [()+\|\?\*,]
+dot \.
+comma \,
+hyphen \-
+colon \:
+slash \/
+bcl \{
+ecl \}
+blcl \[
+elcl \]
+percent \%
+semi \;
+usec {dot}{digit}{1,6}
+comment \#.*
+ccomment "/*"
+bracketstring \<[^>]*\>
+quotedstring \"[^"]*\"
+decstring {digit}+
+hexpair {hexdigit}{hexdigit}
+hexstring 0[xX]{hexdigit}+
+octetstring {octet}({dot}{octet})+
+ipaddress [a-zA-Z0-9:\._][a-zA-Z0-9:\._]*(%[a-zA-Z0-9]+)?
+
+%%
+
+in { yylval.num = IPSEC_DIR_INBOUND; return(DIR); }
+out { yylval.num = IPSEC_DIR_OUTBOUND; return(DIR); }
+
+discard { yylval.num = IPSEC_POLICY_DISCARD; return(ACTION); }
+none { yylval.num = IPSEC_POLICY_NONE; return(ACTION); }
+ipsec { yylval.num = IPSEC_POLICY_IPSEC; return(ACTION); }
+bypass { yylval.num = IPSEC_POLICY_BYPASS; return(ACTION); }
+entrust { yylval.num = IPSEC_POLICY_ENTRUST; return(ACTION); }
+
+esp { yylval.num = IPPROTO_ESP; return(PROTOCOL); }
+ah { yylval.num = IPPROTO_AH; return(PROTOCOL); }
+ipcomp { yylval.num = IPPROTO_IPCOMP; return(PROTOCOL); }
+tcp { yylval.num = IPPROTO_TCP; return(PROTOCOL); }
+
+transport { yylval.num = IPSEC_MODE_TRANSPORT; return(MODE); }
+tunnel { yylval.num = IPSEC_MODE_TUNNEL; return(MODE); }
+
+me { return(ME); }
+any { return(ANY); }
+
+default { yylval.num = IPSEC_LEVEL_DEFAULT; return(LEVEL); }
+use { yylval.num = IPSEC_LEVEL_USE; return(LEVEL); }
+require { yylval.num = IPSEC_LEVEL_REQUIRE; return(LEVEL); }
+unique{colon}{decstring} {
+ yylval.val.len = strlen(yytext + 7);
+ yylval.val.buf = yytext + 7;
+ return(LEVEL_SPECIFY);
+ }
+unique { yylval.num = IPSEC_LEVEL_UNIQUE; return(LEVEL); }
+{slash} { return(SLASH); }
+
+{ipaddress} {
+ yylval.val.len = strlen(yytext);
+ yylval.val.buf = yytext;
+ return(IPADDRESS);
+ }
+
+{hyphen} { return(HYPHEN); }
+
+{ws} { ; }
+{nl} { ; }
+
+%%
+
+void __policy__strbuffer__init__(char *);
+void __policy__strbuffer__free__(void);
+
+static YY_BUFFER_STATE strbuffer;
+
+void
+__policy__strbuffer__init__(msg)
+ char *msg;
+{
+ if (yy_current_buffer)
+ yy_delete_buffer(yy_current_buffer);
+ strbuffer = (YY_BUFFER_STATE)yy_scan_string(msg);
+ yy_switch_to_buffer(strbuffer);
+
+ return;
+}
+
+void
+__policy__strbuffer__free__()
+{
+ yy_delete_buffer(strbuffer);
+
+ return;
+}
diff --git a/lib/libipsec/test-policy.c b/lib/libipsec/test-policy.c
new file mode 100644
index 0000000..65c111d
--- /dev/null
+++ b/lib/libipsec/test-policy.c
@@ -0,0 +1,334 @@
+/* $KAME: test-policy.c,v 1.16 2003/08/26 03:24:08 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <net/pfkeyv2.h>
+#include <netkey/key_debug.h>
+#include <netinet6/ipsec.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <err.h>
+
+#include "libpfkey.h"
+
+struct req_t {
+ int result; /* expected result; 0:ok 1:ng */
+ char *str;
+} reqs[] = {
+{ 0, "out ipsec" },
+{ 1, "must_error" },
+{ 1, "in ipsec must_error" },
+{ 1, "out ipsec esp/must_error" },
+{ 1, "out discard" },
+{ 1, "out none" },
+{ 0, "in entrust" },
+{ 0, "out entrust" },
+{ 1, "out ipsec esp" },
+{ 0, "in ipsec ah/transport" },
+{ 1, "in ipsec ah/tunnel" },
+{ 0, "out ipsec ah/transport/" },
+{ 1, "out ipsec ah/tunnel/" },
+{ 0, "in ipsec esp / transport / 10.0.0.1-10.0.0.2" },
+{ 0, "in ipsec esp/tunnel/::1-::2" },
+{ 1, "in ipsec esp/tunnel/10.0.0.1-::2" },
+{ 0, "in ipsec esp/tunnel/::1-::2/require" },
+{ 0, "out ipsec ah/transport//use" },
+{ 1, "out ipsec ah/transport esp/use" },
+{ 1, "in ipsec ah/transport esp/tunnel" },
+{ 0, "in ipsec ah/transport esp/tunnel/::1-::1" },
+{ 0, "in ipsec
+ ah / transport
+ esp / tunnel / ::1-::2" },
+{ 0, "out ipsec
+ ah/transport/::1-::2 esp/tunnel/::3-::4/use ah/transport/::5-::6/require
+ ah/transport/::1-::2 esp/tunnel/::3-::4/use ah/transport/::5-::6/require
+ ah/transport/::1-::2 esp/tunnel/::3-::4/use ah/transport/::5-::6/require
+ " },
+{ 0, "out ipsec esp/transport/fec0::10-fec0::11/use" },
+};
+
+int test1(void);
+int test1sub1(struct req_t *);
+int test1sub2(char *, int);
+int test2(void);
+int test2sub(int);
+
+int
+main(ac, av)
+ int ac;
+ char **av;
+{
+ test1();
+ test2();
+
+ exit(0);
+}
+
+int
+test1()
+{
+ int i;
+ int result;
+
+ printf("TEST1\n");
+ for (i = 0; i < sizeof(reqs)/sizeof(reqs[0]); i++) {
+ printf("#%d [%s]\n", i + 1, reqs[i].str);
+
+ result = test1sub1(&reqs[i]);
+ if (result == 0 && reqs[i].result == 1) {
+ warnx("ERROR: expecting failure.");
+ } else if (result == 1 && reqs[i].result == 0) {
+ warnx("ERROR: expecting success.");
+ }
+ }
+
+ return 0;
+}
+
+int
+test1sub1(req)
+ struct req_t *req;
+{
+ char *buf;
+
+ buf = ipsec_set_policy(req->str, strlen(req->str));
+ if (buf == NULL) {
+ printf("ipsec_set_policy: %s\n", ipsec_strerror());
+ return 1;
+ }
+
+ if (test1sub2(buf, PF_INET) != 0
+ || test1sub2(buf, PF_INET6) != 0) {
+ free(buf);
+ return 1;
+ }
+#if 0
+ kdebug_sadb_x_policy((struct sadb_ext *)buf);
+#endif
+
+ free(buf);
+ return 0;
+}
+
+int
+test1sub2(policy, family)
+ char *policy;
+ int family;
+{
+ int so;
+ int proto = 0, optname = 0;
+ int len;
+ char getbuf[1024];
+
+ switch (family) {
+ case PF_INET:
+ proto = IPPROTO_IP;
+ optname = IP_IPSEC_POLICY;
+ break;
+ case PF_INET6:
+ proto = IPPROTO_IPV6;
+ optname = IPV6_IPSEC_POLICY;
+ break;
+ }
+
+ if ((so = socket(family, SOCK_DGRAM, 0)) < 0)
+ err(1, "socket");
+
+ len = ipsec_get_policylen(policy);
+#if 0
+ printf("\tsetlen:%d\n", len);
+#endif
+
+ if (setsockopt(so, proto, optname, policy, len) < 0) {
+ printf("fail to set sockopt; %s\n", strerror(errno));
+ close(so);
+ return 1;
+ }
+
+ memset(getbuf, 0, sizeof(getbuf));
+ memcpy(getbuf, policy, sizeof(struct sadb_x_policy));
+ if (getsockopt(so, proto, optname, getbuf, &len) < 0) {
+ printf("fail to get sockopt; %s\n", strerror(errno));
+ close(so);
+ return 1;
+ }
+
+ {
+ char *buf = NULL;
+
+#if 0
+ printf("\tgetlen:%d\n", len);
+#endif
+
+ if ((buf = ipsec_dump_policy(getbuf, NULL)) == NULL) {
+ printf("%s\n", ipsec_strerror());
+ close(so);
+ return 1;
+ }
+#if 0
+ printf("\t[%s]\n", buf);
+#endif
+ free(buf);
+ }
+
+ close (so);
+ return 0;
+}
+
+char addr[] = {
+ 28, 28, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+ 0, 0, 0, 0,
+};
+
+int
+test2()
+{
+ int so;
+ char *pol1 = "out ipsec";
+ char *pol2 = "out ipsec ah/transport//use";
+ char *sp1, *sp2;
+ int splen1, splen2;
+ int spid;
+ struct sadb_msg *m;
+
+ printf("TEST2\n");
+ if (getuid() != 0)
+ errx(1, "root privilege required.");
+
+ sp1 = ipsec_set_policy(pol1, strlen(pol1));
+ splen1 = ipsec_get_policylen(sp1);
+ sp2 = ipsec_set_policy(pol2, strlen(pol2));
+ splen2 = ipsec_get_policylen(sp2);
+
+ if ((so = pfkey_open()) < 0)
+ errx(1, "ERROR: %s", ipsec_strerror());
+
+ printf("spdflush()\n");
+ if (pfkey_send_spdflush(so) < 0)
+ errx(1, "ERROR: %s", ipsec_strerror());
+ m = pfkey_recv(so);
+ free(m);
+
+ printf("spdsetidx()\n");
+ if (pfkey_send_spdsetidx(so, (struct sockaddr *)addr, 128,
+ (struct sockaddr *)addr, 128,
+ 255, sp1, splen1, 0) < 0)
+ errx(1, "ERROR: %s", ipsec_strerror());
+ m = pfkey_recv(so);
+ free(m);
+
+ printf("spdupdate()\n");
+ if (pfkey_send_spdupdate(so, (struct sockaddr *)addr, 128,
+ (struct sockaddr *)addr, 128,
+ 255, sp2, splen2, 0) < 0)
+ errx(1, "ERROR: %s", ipsec_strerror());
+ m = pfkey_recv(so);
+ free(m);
+
+ printf("sleep(4)\n");
+ sleep(4);
+
+ printf("spddelete()\n");
+ if (pfkey_send_spddelete(so, (struct sockaddr *)addr, 128,
+ (struct sockaddr *)addr, 128,
+ 255, sp1, splen1, 0) < 0)
+ errx(1, "ERROR: %s", ipsec_strerror());
+ m = pfkey_recv(so);
+ free(m);
+
+ printf("spdadd()\n");
+ if (pfkey_send_spdadd(so, (struct sockaddr *)addr, 128,
+ (struct sockaddr *)addr, 128,
+ 255, sp2, splen2, 0) < 0)
+ errx(1, "ERROR: %s", ipsec_strerror());
+ spid = test2sub(so);
+
+ printf("spdget(%u)\n", spid);
+ if (pfkey_send_spdget(so, spid) < 0)
+ errx(1, "ERROR: %s", ipsec_strerror());
+ m = pfkey_recv(so);
+ free(m);
+
+ printf("sleep(4)\n");
+ sleep(4);
+
+ printf("spddelete2()\n");
+ if (pfkey_send_spddelete2(so, spid) < 0)
+ errx(1, "ERROR: %s", ipsec_strerror());
+ m = pfkey_recv(so);
+ free(m);
+
+ printf("spdadd() with lifetime's 10(s)\n");
+ if (pfkey_send_spdadd2(so, (struct sockaddr *)addr, 128,
+ (struct sockaddr *)addr, 128,
+ 255, 0, 10, sp2, splen2, 0) < 0)
+ errx(1, "ERROR: %s", ipsec_strerror());
+ spid = test2sub(so);
+
+ /* expecting failure */
+ printf("spdupdate()\n");
+ if (pfkey_send_spdupdate(so, (struct sockaddr *)addr, 128,
+ (struct sockaddr *)addr, 128,
+ 255, sp2, splen2, 0) == 0) {
+ warnx("ERROR: expecting failure.");
+ }
+
+ return 0;
+}
+
+int
+test2sub(so)
+ int so;
+{
+ struct sadb_msg *msg;
+ caddr_t mhp[SADB_EXT_MAX + 1];
+
+ if ((msg = pfkey_recv(so)) == NULL)
+ errx(1, "ERROR: pfkey_recv failure.");
+ if (pfkey_align(msg, mhp) < 0)
+ errx(1, "ERROR: pfkey_align failure.");
+
+ return ((struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY])->sadb_x_policy_id;
+}
+
diff --git a/lib/libipx/Makefile b/lib/libipx/Makefile
new file mode 100644
index 0000000..66f566a
--- /dev/null
+++ b/lib/libipx/Makefile
@@ -0,0 +1,9 @@
+# $FreeBSD$
+
+LIB= ipx
+SHLIBDIR?= /lib
+SRCS= ipx_addr.c ipx_ntoa.c
+MAN= ipx.3
+MLINKS+=ipx.3 ipx_addr.3 ipx.3 ipx_ntoa.3
+
+.include <bsd.lib.mk>
diff --git a/lib/libipx/ipx.3 b/lib/libipx/ipx.3
new file mode 100644
index 0000000..d3a295b
--- /dev/null
+++ b/lib/libipx/ipx.3
@@ -0,0 +1,129 @@
+.\" 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.
+.\" 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt IPX 3
+.Os
+.Sh NAME
+.Nm ipx_addr ,
+.Nm ipx_ntoa
+.Nd IPX address conversion routines
+.Sh LIBRARY
+.Lb libipx
+.Sh SYNOPSIS
+.In sys/types.h
+.In netipx/ipx.h
+.Ft struct ipx_addr
+.Fn ipx_addr "const char *cp"
+.Ft char *
+.Fn ipx_ntoa "struct ipx_addr ipx"
+.Sh DESCRIPTION
+The routine
+.Fn ipx_addr
+interprets character strings representing
+.Tn IPX
+addresses, returning binary information suitable
+for use in system calls.
+The routine
+.Fn ipx_ntoa
+takes
+.Tn IPX
+addresses and returns
+.Tn ASCII
+strings representing the address in a
+notation in common use:
+.Bd -ragged -offset indent
+<network number>.<host number>.<port number>
+.Ed
+.Pp
+Trailing zero fields are suppressed, and each number is printed in hexadecimal,
+in a format suitable for input to
+.Fn ipx_addr .
+Any fields lacking super-decimal digits will have a
+trailing
+.Ql H
+appended.
+.Pp
+An effort has been made to insure that
+.Fn ipx_addr
+be compatible with most formats in common use.
+It will first separate an address into 1 to 3 fields using a single delimiter
+chosen from
+period
+.Ql \&. ,
+colon
+.Ql \&:
+or pound-sign
+.Ql \&# .
+Each field is then examined for byte separators (colon or period).
+If there are byte separators, each subfield separated is taken to be
+a small hexadecimal number, and the entirety is taken as a network-byte-ordered
+quantity to be zero extended in the high-network-order bytes.
+Next, the field is inspected for hyphens, in which case
+the field is assumed to be a number in decimal notation
+with hyphens separating the millennia.
+Next, the field is assumed to be a number:
+It is interpreted
+as hexadecimal if there is a leading
+.Ql 0x
+(as in C),
+a trailing
+.Ql H
+(as in Mesa), or there are any super-decimal digits present.
+It is interpreted as octal if there is a leading
+.Ql 0
+and there are no super-octal digits.
+Otherwise, it is converted as a decimal number.
+.Sh RETURN VALUES
+None.
+(See
+.Sx BUGS . )
+.Sh SEE ALSO
+.\" .Xr ns 4 ,
+.Xr hosts 5 ,
+.Xr networks 5
+.Sh HISTORY
+The precursor
+.Fn ns_addr
+and
+.Fn ns_toa
+functions appeared in
+.Bx 4.3 .
+.Sh BUGS
+The string returned by
+.Fn ipx_ntoa
+resides in a static memory area.
+The function
+.Fn ipx_addr
+should diagnose improperly formed input, and there should be an unambiguous
+way to recognize this.
diff --git a/lib/libipx/ipx_addr.c b/lib/libipx/ipx_addr.c
new file mode 100644
index 0000000..99da440
--- /dev/null
+++ b/lib/libipx/ipx_addr.c
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 1986, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * J.Q. Johnson.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)ipx_addr.c";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/param.h>
+#include <arpa/inet.h>
+#include <netipx/ipx.h>
+#include <stdio.h>
+#include <string.h>
+
+static struct ipx_addr addr, zero_addr;
+
+static void Field(), cvtbase();
+
+struct ipx_addr
+ipx_addr(name)
+ const char *name;
+{
+ char separator;
+ char *hostname, *socketname, *cp;
+ char buf[50];
+
+ (void)strncpy(buf, name, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = '\0';
+
+ /*
+ * First, figure out what he intends as a field separator.
+ * Despite the way this routine is written, the preferred
+ * form 2-272.AA001234H.01777, i.e. XDE standard.
+ * Great efforts are made to ensure backwards compatibility.
+ */
+ if ( (hostname = strchr(buf, '#')) )
+ separator = '#';
+ else {
+ hostname = strchr(buf, '.');
+ if ((cp = strchr(buf, ':')) &&
+ ((hostname && cp < hostname) || (hostname == 0))) {
+ hostname = cp;
+ separator = ':';
+ } else
+ separator = '.';
+ }
+ if (hostname)
+ *hostname++ = 0;
+
+ addr = zero_addr;
+ Field(buf, addr.x_net.c_net, 4);
+ if (hostname == 0)
+ return (addr); /* No separator means net only */
+
+ socketname = strchr(hostname, separator);
+ if (socketname) {
+ *socketname++ = 0;
+ Field(socketname, (u_char *)&addr.x_port, 2);
+ }
+
+ Field(hostname, addr.x_host.c_host, 6);
+
+ return (addr);
+}
+
+static void
+Field(buf, out, len)
+ char *buf;
+ u_char *out;
+ int len;
+{
+ char *bp = buf;
+ int i, ibase, base16 = 0, base10 = 0, clen = 0;
+ int hb[6], *hp;
+ char *fmt;
+
+ /*
+ * first try 2-273#2-852-151-014#socket
+ */
+ if ((*buf != '-') &&
+ (1 < (i = sscanf(buf, "%d-%d-%d-%d-%d",
+ &hb[0], &hb[1], &hb[2], &hb[3], &hb[4])))) {
+ cvtbase(1000L, 256, hb, i, out, len);
+ return;
+ }
+ /*
+ * try form 8E1#0.0.AA.0.5E.E6#socket
+ */
+ if (1 < (i = sscanf(buf,"%x.%x.%x.%x.%x.%x",
+ &hb[0], &hb[1], &hb[2], &hb[3], &hb[4], &hb[5]))) {
+ cvtbase(256L, 256, hb, i, out, len);
+ return;
+ }
+ /*
+ * try form 8E1#0:0:AA:0:5E:E6#socket
+ */
+ if (1 < (i = sscanf(buf,"%x:%x:%x:%x:%x:%x",
+ &hb[0], &hb[1], &hb[2], &hb[3], &hb[4], &hb[5]))) {
+ cvtbase(256L, 256, hb, i, out, len);
+ return;
+ }
+ /*
+ * This is REALLY stretching it but there was a
+ * comma notation separating shorts -- definitely non-standard
+ */
+ if (1 < (i = sscanf(buf,"%x,%x,%x",
+ &hb[0], &hb[1], &hb[2]))) {
+ hb[0] = htons(hb[0]); hb[1] = htons(hb[1]);
+ hb[2] = htons(hb[2]);
+ cvtbase(65536L, 256, hb, i, out, len);
+ return;
+ }
+
+ /* Need to decide if base 10, 16 or 8 */
+ while (*bp) switch (*bp++) {
+
+ case '0': case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '-':
+ break;
+
+ case '8': case '9':
+ base10 = 1;
+ break;
+
+ case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+ base16 = 1;
+ break;
+
+ case 'x': case 'X':
+ *--bp = '0';
+ base16 = 1;
+ break;
+
+ case 'h': case 'H':
+ base16 = 1;
+ /* FALLTHROUGH */
+
+ default:
+ *--bp = 0; /* Ends Loop */
+ }
+ if (base16) {
+ fmt = "%3x";
+ ibase = 4096;
+ } else if (base10 == 0 && *buf == '0') {
+ fmt = "%3o";
+ ibase = 512;
+ } else {
+ fmt = "%3d";
+ ibase = 1000;
+ }
+
+ for (bp = buf; *bp++; ) clen++;
+ if (clen == 0) clen++;
+ if (clen > 18) clen = 18;
+ i = ((clen - 1) / 3) + 1;
+ bp = clen + buf - 3;
+ hp = hb + i - 1;
+
+ while (hp > hb) {
+ (void)sscanf(bp, fmt, hp);
+ bp[0] = 0;
+ hp--;
+ bp -= 3;
+ }
+ (void)sscanf(buf, fmt, hp);
+ cvtbase((long)ibase, 256, hb, i, out, len);
+}
+
+static void
+cvtbase(oldbase,newbase,input,inlen,result,reslen)
+ long oldbase;
+ int newbase;
+ int input[];
+ int inlen;
+ unsigned char result[];
+ int reslen;
+{
+ int d, e;
+ long sum;
+
+ e = 1;
+ while (e > 0 && reslen > 0) {
+ d = 0; e = 0; sum = 0;
+ /* long division: input=input/newbase */
+ while (d < inlen) {
+ sum = sum*oldbase + (long) input[d];
+ e += (sum > 0);
+ input[d++] = sum / newbase;
+ sum %= newbase;
+ }
+ result[--reslen] = sum; /* accumulate remainder */
+ }
+ for (d=0; d < reslen; d++)
+ result[d] = 0;
+}
diff --git a/lib/libipx/ipx_ntoa.c b/lib/libipx/ipx_ntoa.c
new file mode 100644
index 0000000..0864bde
--- /dev/null
+++ b/lib/libipx/ipx_ntoa.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 1986, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)ipx_ntoa.c";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/param.h>
+#include <arpa/inet.h>
+#include <netipx/ipx.h>
+#include <stdio.h>
+
+static char *spectHex(char *);
+
+char *
+ipx_ntoa(addr)
+ struct ipx_addr addr;
+{
+ static char obuf[40];
+ union { union ipx_net net_e; u_long long_e; } net;
+ u_short port = htons(addr.x_port);
+ char *cp;
+ char *cp2;
+ u_char *up = addr.x_host.c_host;
+ u_char *uplim = up + 6;
+
+ net.net_e = addr.x_net;
+ sprintf(obuf, "%lx", (u_long)ntohl(net.long_e));
+ cp = spectHex(obuf);
+ cp2 = cp + 1;
+ while (*up==0 && up < uplim) up++;
+ if (up == uplim) {
+ if (port) {
+ sprintf(cp, ".0");
+ cp += 2;
+ }
+ } else {
+ sprintf(cp, ".%x", *up++);
+ while (up < uplim) {
+ while (*cp) cp++;
+ sprintf(cp, "%02x", *up++);
+ }
+ cp = spectHex(cp2);
+ }
+ if (port) {
+ sprintf(cp, ".%x", port);
+ spectHex(cp + 1);
+ }
+ return (obuf);
+}
+
+static char *
+spectHex(p0)
+ char *p0;
+{
+ int ok = 0;
+ int nonzero = 0;
+ char *p = p0;
+ for (; *p; p++) switch (*p) {
+
+ case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+ ok = 1;
+ case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9':
+ nonzero = 1;
+ }
+ if (nonzero && !ok) { *p++ = 'H'; *p = 0; }
+ return (p);
+}
diff --git a/lib/libkiconv/Makefile b/lib/libkiconv/Makefile
new file mode 100644
index 0000000..ad4f2f0
--- /dev/null
+++ b/lib/libkiconv/Makefile
@@ -0,0 +1,18 @@
+# $FreeBSD$
+
+LIB= kiconv
+SHLIBDIR?= /lib
+SRCS= xlat16_iconv.c xlat16_sysctl.c
+SRCS+= quirks.c
+
+SHLIB_MAJOR= 2
+
+MAN= kiconv.3
+
+MLINKS+= kiconv.3 kiconv_add_xlat16_cspair.3 \
+ kiconv.3 kiconv_add_xlat16_cspairs.3 \
+ kiconv.3 kiconv_add_xlat16_table.3
+
+CFLAGS+= -I${.CURDIR}/../../sys
+
+.include <bsd.lib.mk>
diff --git a/lib/libkiconv/kiconv.3 b/lib/libkiconv/kiconv.3
new file mode 100644
index 0000000..affacf1
--- /dev/null
+++ b/lib/libkiconv/kiconv.3
@@ -0,0 +1,130 @@
+.\"
+.\" Copyright (c) 2003 Ryuichiro Imura
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING 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 17, 2003
+.Dt KICONV 3
+.Os
+.Sh NAME
+.Nm kiconv_add_xlat16_cspair ,
+.Nm kiconv_add_xlat16_cspairs ,
+.Nm kiconv_add_xlat16_table
+.Nd kernel side iconv library
+.Sh LIBRARY
+.Lb libkiconv
+.Sh SYNOPSIS
+.In sys/iconv.h
+.Ft int
+.Fo kiconv_add_xlat16_cspair
+.Fa "const char *tocode"
+.Fa "const char *fromcode"
+.Fa "int flag"
+.Fc
+.Ft int
+.Fo kiconv_add_xlat16_cspairs
+.Fa "const char *foreigncode"
+.Fa "const char *localcode"
+.Fc
+.Ft int
+.Fo kiconv_add_xlat16_table
+.Fa "const char *tocode"
+.Fa "const char *fromcode"
+.Fa "const void *data"
+.Fa "int datalen"
+.Fc
+.Sh DESCRIPTION
+The
+.Nm kiconv
+library provides multi-byte character conversion tables for kernel side
+iconv service.
+.Pp
+The
+.Fn kiconv_add_xlat16_cspair
+function
+defines a conversion table using
+.Xr iconv 3
+between
+.Fa fromcode
+charset and
+.Fa tocode
+charset.
+You can specify
+.Fa flag
+to determine if
+.Xr tolower 3
+/
+.Xr toupper 3
+conversion is included in the table.
+The
+.Fa flag
+has following values.
+.Pp
+.Bl -tag -width ".Dv KICONV_FROM_LOWER" -compact
+.It Dv KICONV_LOWER
+.It Dv KICONV_FROM_LOWER
+It generates a tolower table in addition to a character conversion table.
+The difference between two is tolower
+.Fa tocode
+or tolower
+.Fa fromcode .
+.It Dv KICONV_UPPER
+.It Dv KICONV_FROM_UPPER
+It generates a toupper table in addition to a character conversion table.
+The difference between two is toupper
+.Fa tocode
+or toupper
+.Fa fromcode .
+.El
+.Pp
+A tolower/toupper conversion is limited to single-byte characters.
+.Pp
+The
+.Fn kiconv_add_xlat16_cspairs
+function
+defines two conversion tables which are from
+.Fa localcode
+to
+.Fa foreigncode
+and from
+.Fa foreigncode
+to
+.Fa localcode .
+These conversion tables also contain both tolower and toupper tables.
+.Pp
+The
+.Fn kiconv_add_xlat16_table
+function
+defines a conversion table directly pointed by
+.Fa data
+whose length is
+.Fa datalen ,
+not using
+.Xr iconv 3 .
+.Sh SEE ALSO
+.Xr iconv 3 ,
+.Xr tolower 3 ,
+.Xr toupper 3 ,
+.Xr iconv 9
diff --git a/lib/libkiconv/quirks.c b/lib/libkiconv/quirks.c
new file mode 100644
index 0000000..d9a80ee
--- /dev/null
+++ b/lib/libkiconv/quirks.c
@@ -0,0 +1,192 @@
+/*-
+ * Copyright (c) 2003 Ryuichiro Imura
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * kiconv(3) requires shared linked, and reduce module size
+ * when statically linked.
+ */
+
+#ifdef PIC
+
+/*
+ * Why do we need quirks?
+ * Since each vendors has their own Unicode mapping rules,
+ * we need some quirks until iconv(3) supports them.
+ * We can define Microsoft mappings here.
+ *
+ * For example, the eucJP and Unocode mapping rule is based on
+ * the JIS standard. Since Microsoft uses cp932 for Unicode mapping
+ * witch is not truly based on the JIS standard, reading a file
+ * system created by Microsoft Windows family using eucJP/Unicode
+ * mapping rule will cause a problem. That's why we define eucJP-ms here.
+ * The eucJP-ms has been defined by The Open Group Japan Vendor Coucil.
+ *
+ * Well, Apple Mac OS also has their own Unicode mappings,
+ * but we won't require these quirks here, because HFS doesn't have
+ * Unicode and HFS+ has decomposed Unicode which can not be
+ * handled by this xlat16 converter.
+ */
+
+#include <sys/types.h>
+#include <sys/iconv.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include "quirks.h"
+
+/*
+ * All lists of quirk character set
+ */
+static struct {
+ int vendor; /* reserved for non MS mapping */
+ const char *base_codeset, *quirk_codeset;
+} quirk_list[] = {
+ { KICONV_VENDOR_MICSFT, "eucJP", "eucJP-ms" },
+ { KICONV_VENDOR_MICSFT, "EUC-JP", "eucJP-ms" },
+ { KICONV_VENDOR_MICSFT, "SJIS", "SJIS-ms" },
+ { KICONV_VENDOR_MICSFT, "Shift_JIS", "SJIS-ms" },
+ { KICONV_VENDOR_MICSFT, "Big5", "Big5-ms" }
+};
+
+/*
+ * The character list to replace for Japanese MS-Windows.
+ */
+static struct quirk_replace_list quirk_jis_cp932[] = {
+ { 0x00a2, 0xffe0 }, /* Cent Sign, Fullwidth Cent Sign */
+ { 0x00a3, 0xffe1 }, /* Pound Sign, Fullwidth Pound Sign */
+ { 0x00ac, 0xffe2 }, /* Not Sign, Fullwidth Not Sign */
+ { 0x2016, 0x2225 }, /* Double Vertical Line, Parallel To */
+ { 0x203e, 0x007e }, /* Overline, Tilde */
+ { 0x2212, 0xff0d }, /* Minus Sign, Fullwidth Hyphenminus */
+ { 0x301c, 0xff5e } /* Wave Dash, Fullwidth Tilde */
+};
+
+/*
+ * All entries of quirks
+ */
+#define NumOf(n) (sizeof((n)) / sizeof((n)[0]))
+static struct {
+ const char *quirk_codeset, *iconv_codeset, *pair_codeset;
+ struct quirk_replace_list (*replace_list)[];
+ size_t num_of_replaces;
+} quirk_table[] = {
+ {
+ "eucJP-ms", "eucJP", ENCODING_UNICODE,
+ (struct quirk_replace_list (*)[])&quirk_jis_cp932,
+ NumOf(quirk_jis_cp932)
+ },
+ {
+ "SJIS-ms", "CP932", ENCODING_UNICODE,
+ /* XXX - quirk_replace_list should be NULL */
+ (struct quirk_replace_list (*)[])&quirk_jis_cp932,
+ NumOf(quirk_jis_cp932)
+ },
+ {
+ "Big5-ms", "CP950", ENCODING_UNICODE,
+ NULL, 0
+ }
+};
+
+
+const char *
+kiconv_quirkcs(const char* base, int vendor)
+{
+ size_t i;
+
+ /*
+ * We should compare codeset names ignoring case here,
+ * so that quirk could be used for all of the user input
+ * patterns.
+ */
+ for (i = 0; i < NumOf(quirk_list); i++)
+ if (quirk_list[i].vendor == vendor &&
+ strcasecmp(quirk_list[i].base_codeset, base) == 0)
+ return (quirk_list[i].quirk_codeset);
+
+ return (base);
+}
+
+/*
+ * Internal Functions
+ */
+const char *
+search_quirk(const char *given_codeset,
+ const char *pair_codeset,
+ struct quirk_replace_list **replace_list,
+ size_t *num_of_replaces)
+{
+ size_t i;
+
+ *replace_list = NULL;
+ *num_of_replaces = 0;
+ for (i = 0; i < NumOf(quirk_table); i++)
+ if (strcmp(quirk_table[i].quirk_codeset, given_codeset) == 0) {
+ if (strcmp(quirk_table[i].pair_codeset, pair_codeset) == 0) {
+ *replace_list = *quirk_table[i].replace_list;
+ *num_of_replaces = quirk_table[i].num_of_replaces;
+ }
+ return (quirk_table[i].iconv_codeset);
+ }
+
+ return (given_codeset);
+}
+
+uint16_t
+quirk_vendor2unix(uint16_t c, struct quirk_replace_list *replace_list, size_t num)
+{
+ size_t i;
+
+ for (i = 0; i < num; i++)
+ if (replace_list[i].vendor_code == c)
+ return (replace_list[i].standard_code);
+
+ return (c);
+}
+
+uint16_t
+quirk_unix2vendor(uint16_t c, struct quirk_replace_list *replace_list, size_t num)
+{
+ size_t i;
+
+ for (i = 0; i < num; i++)
+ if (replace_list[i].standard_code == c)
+ return (replace_list[i].vendor_code);
+
+ return (c);
+}
+
+#else /* statically linked */
+
+const char *
+kiconv_quirkcs(const char* base, int vendor)
+{
+ return (base);
+}
+
+#endif /* PIC */
diff --git a/lib/libkiconv/quirks.h b/lib/libkiconv/quirks.h
new file mode 100644
index 0000000..682d2cd
--- /dev/null
+++ b/lib/libkiconv/quirks.h
@@ -0,0 +1,45 @@
+/*-
+ * Copyright (c) 2003 Ryuichiro Imura
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 _KICONV_QUIRKS_H_
+#define _KICONV_QUIRKS_H_
+
+struct quirk_replace_list {
+ uint16_t standard_code, vendor_code;
+};
+
+const char *search_quirk(const char *, const char *,
+ struct quirk_replace_list **, size_t *);
+uint16_t quirk_vendor2unix(uint16_t,
+ struct quirk_replace_list *,
+ size_t);
+uint16_t quirk_unix2vendor(uint16_t,
+ struct quirk_replace_list *,
+ size_t);
+
+#endif /* _KICONV_QUIRKS_H_ */
diff --git a/lib/libkiconv/xlat16_iconv.c b/lib/libkiconv/xlat16_iconv.c
new file mode 100644
index 0000000..db304c3
--- /dev/null
+++ b/lib/libkiconv/xlat16_iconv.c
@@ -0,0 +1,399 @@
+/*-
+ * Copyright (c) 2003 Ryuichiro Imura
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * kiconv(3) requires shared linked, and reduce module size
+ * when statically linked.
+ */
+
+#ifdef PIC
+
+#include <sys/types.h>
+#include <sys/iconv.h>
+#include <sys/sysctl.h>
+
+#include <ctype.h>
+#include <dlfcn.h>
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "quirks.h"
+
+typedef void *iconv_t;
+
+struct xlat16_table {
+ uint32_t * idx[0x200];
+ void * data;
+ size_t size;
+};
+
+static struct xlat16_table kiconv_xlat16_open(const char *, const char *, int);
+
+static int my_iconv_init(void);
+static iconv_t (*my_iconv_open)(const char *, const char *);
+static size_t (*my_iconv)(iconv_t, const char **, size_t *, char **, size_t *);
+static int (*my_iconv_close)(iconv_t);
+static size_t my_iconv_char(iconv_t, const u_char **, size_t *, u_char **, size_t *);
+
+int
+kiconv_add_xlat16_cspair(const char *tocode, const char *fromcode, int flag)
+{
+ int error;
+ size_t i, size, idxsize;
+ struct iconv_cspair_info *csi;
+ struct xlat16_table xt;
+ void *data;
+ char *p;
+
+ if (sysctlbyname("kern.iconv.cslist", NULL, &size, NULL, 0) == -1)
+ return (-1);
+ if (size > 0) {
+ csi = malloc(size);
+ if (csi == NULL)
+ return (-1);
+ if (sysctlbyname("kern.iconv.cslist", csi, &size, NULL, 0) == -1) {
+ free(csi);
+ return (-1);
+ }
+ for (i = 0; i < (size/sizeof(*csi)); i++, csi++){
+ if (strcmp(csi->cs_to, tocode) == 0 &&
+ strcmp(csi->cs_from, fromcode) == 0)
+ return (0);
+ }
+ }
+
+ xt = kiconv_xlat16_open(tocode, fromcode, flag);
+ if (xt.size == 0)
+ return (-1);
+
+ idxsize = sizeof(xt.idx);
+
+ if ((idxsize + xt.size) > ICONV_CSMAXDATALEN) {
+ errno = E2BIG;
+ return (-1);
+ }
+
+ if ((data = malloc(idxsize + xt.size)) != NULL) {
+ p = data;
+ memcpy(p, xt.idx, idxsize);
+ p += idxsize;
+ memcpy(p, xt.data, xt.size);
+ error = kiconv_add_xlat16_table(tocode, fromcode, data,
+ (int)(idxsize + xt.size));
+ return (error);
+ }
+
+ return (-1);
+}
+
+int
+kiconv_add_xlat16_cspairs(const char *foreigncode, const char *localcode)
+{
+ int error;
+
+ error = kiconv_add_xlat16_cspair(foreigncode, localcode,
+ KICONV_FROM_LOWER | KICONV_FROM_UPPER);
+ if (error)
+ return (error);
+ error = kiconv_add_xlat16_cspair(localcode, foreigncode,
+ KICONV_LOWER | KICONV_UPPER);
+ if (error)
+ return (error);
+
+ return (0);
+}
+
+static struct xlat16_table
+kiconv_xlat16_open(const char *tocode, const char *fromcode, int lcase)
+{
+ u_char src[3], dst[4], *srcp, *dstp, ud, ld;
+ int us, ls, ret;
+ uint16_t c;
+ uint32_t table[0x80];
+ size_t inbytesleft, outbytesleft, pre_q_size, post_q_size;
+ struct xlat16_table xt;
+ struct quirk_replace_list *pre_q_list, *post_q_list;
+ iconv_t cd;
+ char *p;
+
+ xt.data = NULL;
+ xt.size = 0;
+
+ src[2] = '\0';
+ dst[3] = '\0';
+
+ ret = my_iconv_init();
+ if (ret)
+ return (xt);
+
+ cd = my_iconv_open(search_quirk(tocode, fromcode, &pre_q_list, &pre_q_size),
+ search_quirk(fromcode, tocode, &post_q_list, &post_q_size));
+ if (cd == (iconv_t) (-1))
+ return (xt);
+
+ if ((xt.data = malloc(0x200 * 0x80 * sizeof(uint32_t))) == NULL)
+ return (xt);
+
+ p = xt.data;
+
+ for (ls = 0 ; ls < 0x200 ; ls++) {
+ xt.idx[ls] = NULL;
+ for (us = 0 ; us < 0x80 ; us++) {
+ srcp = src;
+ dstp = dst;
+
+ inbytesleft = 2;
+ outbytesleft = 3;
+ bzero(dst, outbytesleft);
+
+ c = ((ls & 0x100 ? us | 0x80 : us) << 8) | (u_char)ls;
+ c = quirk_vendor2unix(c, pre_q_list, pre_q_size);
+ src[0] = (u_char)(c >> 8);
+ src[1] = (u_char)c;
+
+ ret = my_iconv_char(cd, (const u_char **)&srcp,
+ &inbytesleft, &dstp, &outbytesleft);
+ if (ret == -1) {
+ table[us] = 0;
+ continue;
+ }
+
+ ud = (u_char)dst[0];
+ ld = (u_char)dst[1];
+
+ switch(outbytesleft) {
+ case 0:
+#ifdef XLAT16_ACCEPT_3BYTE_CHR
+ table[us] = (ud << 8) | ld;
+ table[us] |= (u_char)dst[2] << 16;
+ table[us] |= XLAT16_IS_3BYTE_CHR;
+#else
+ table[us] = 0;
+ continue;
+#endif
+ break;
+ case 1:
+ table[us] = quirk_unix2vendor((ud << 8) | ld,
+ post_q_list, post_q_size);
+ if ((table[us] >> 8) == 0)
+ table[us] |= XLAT16_ACCEPT_NULL_OUT;
+ break;
+ case 2:
+ table[us] = ud;
+ if (lcase & KICONV_LOWER && ud != tolower(ud)) {
+ table[us] |= (u_char)tolower(ud) << 16;
+ table[us] |= XLAT16_HAS_LOWER_CASE;
+ }
+ if (lcase & KICONV_UPPER && ud != toupper(ud)) {
+ table[us] |= (u_char)toupper(ud) << 16;
+ table[us] |= XLAT16_HAS_UPPER_CASE;
+ }
+ break;
+ }
+
+ switch(inbytesleft) {
+ case 0:
+ if ((ls & 0xff) == 0)
+ table[us] |= XLAT16_ACCEPT_NULL_IN;
+ break;
+ case 1:
+ c = ls > 0xff ? us | 0x80 : us;
+ if (lcase & KICONV_FROM_LOWER && c != tolower(c)) {
+ table[us] |= (u_char)tolower(c) << 16;
+ table[us] |= XLAT16_HAS_FROM_LOWER_CASE;
+ }
+ if (lcase & KICONV_FROM_UPPER && c != toupper(c)) {
+ table[us] |= (u_char)toupper(c) << 16;
+ table[us] |= XLAT16_HAS_FROM_UPPER_CASE;
+ }
+ break;
+ }
+
+ if (table[us] == 0)
+ continue;
+
+ /*
+ * store not NULL
+ */
+ xt.idx[ls] = table;
+ }
+ if (xt.idx[ls]) {
+ memcpy(p, table, sizeof(table));
+ p += sizeof(table);
+ }
+ }
+ my_iconv_close(cd);
+
+ xt.size = p - (char *)xt.data;
+ xt.data = realloc(xt.data, xt.size);
+ return (xt);
+}
+
+static int
+my_iconv_init(void)
+{
+ void *iconv_lib;
+
+ iconv_lib = dlopen("libiconv.so", RTLD_LAZY | RTLD_GLOBAL);
+ if (iconv_lib == NULL) {
+ warn("Unable to load iconv library: %s\n", dlerror());
+ errno = ENOENT;
+ return (-1);
+ }
+ my_iconv_open = dlsym(iconv_lib, "iconv_open");
+ my_iconv = dlsym(iconv_lib, "iconv");
+ my_iconv_close = dlsym(iconv_lib, "iconv_close");
+
+ return (0);
+}
+
+static size_t
+my_iconv_char(iconv_t cd, const u_char **ibuf, size_t * ilen, u_char **obuf,
+ size_t * olen)
+{
+ const u_char *sp;
+ u_char *dp, ilocal[3], olocal[3];
+ u_char c1, c2;
+ int ret;
+ size_t ir, or;
+
+ sp = *ibuf;
+ dp = *obuf;
+ ir = *ilen;
+
+ bzero(*obuf, *olen);
+ ret = my_iconv(cd, (const char **)&sp, ilen, (char **)&dp, olen);
+ c1 = (*obuf)[0];
+ c2 = (*obuf)[1];
+
+ if (ret == -1) {
+ if (*ilen == ir - 1 && (*ibuf)[1] == '\0' && (c1 || c2))
+ return (0);
+ else
+ return (-1);
+ }
+
+ /*
+ * We must judge if inbuf is a single byte char or double byte char.
+ * Here, to judge, try first byte(*sp) conversion and compare.
+ */
+ ir = 1;
+ or = 3;
+
+ bzero(olocal, or);
+ memcpy(ilocal, *ibuf, sizeof(ilocal));
+ sp = ilocal;
+ dp = olocal;
+
+ if ((my_iconv(cd,(const char **)&sp, &ir, (char **)&dp, &or)) != -1) {
+ if (olocal[0] != c1)
+ return (ret);
+
+ if (olocal[1] == c2 && (*ibuf)[1] == '\0') {
+ /*
+ * inbuf is a single byte char
+ */
+ *ilen = 1;
+ *olen = or;
+ return (ret);
+ }
+
+ switch(or) {
+ case 0:
+ case 1:
+ if (olocal[1] == c2) {
+ /*
+ * inbuf is a single byte char,
+ * so return false here.
+ */
+ return (-1);
+ } else {
+ /*
+ * inbuf is a double byte char
+ */
+ return (ret);
+ }
+ break;
+ case 2:
+ /*
+ * should compare second byte of inbuf
+ */
+ break;
+ }
+ } else {
+ /*
+ * inbuf clould not be splitted, so inbuf is
+ * a double byte char.
+ */
+ return (ret);
+ }
+
+ /*
+ * try second byte(*(sp+1)) conversion, and compare
+ */
+ ir = 1;
+ or = 3;
+
+ bzero(olocal, or);
+
+ sp = ilocal + 1;
+ dp = olocal;
+
+ if ((my_iconv(cd,(const char **)&sp, &ir, (char **)&dp, &or)) != -1) {
+ if (olocal[0] == c2)
+ /*
+ * inbuf is a single byte char
+ */
+ return (-1);
+ }
+
+ return (ret);
+}
+
+#else /* statically linked */
+
+#include <errno.h>
+
+int
+kiconv_add_xlat16_cspair(const char *tocode, const char *fromcode, int flag)
+{
+ errno = EINVAL;
+ return (-1);
+}
+
+int
+kiconv_add_xlat16_cspairs(const char *tocode, const char *fromcode)
+{
+ errno = EINVAL;
+ return (-1);
+}
+
+#endif /* PIC */
diff --git a/lib/libkiconv/xlat16_sysctl.c b/lib/libkiconv/xlat16_sysctl.c
new file mode 100644
index 0000000..28420d9
--- /dev/null
+++ b/lib/libkiconv/xlat16_sysctl.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2000-2001, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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 Boris Popov.
+ * 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 THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * kiconv(3) requires shared linked, and reduce module size
+ * when statically linked.
+ */
+
+#ifdef PIC
+
+#include <sys/types.h>
+#include <sys/iconv.h>
+#include <sys/sysctl.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+
+int
+kiconv_add_xlat16_table(const char *to, const char *from, const void *data, int datalen)
+{
+ struct iconv_add_in din;
+ struct iconv_add_out dout;
+ size_t olen;
+
+ if (strlen(from) >= ICONV_CSNMAXLEN || strlen(to) >= ICONV_CSNMAXLEN)
+ return (EINVAL);
+ din.ia_version = ICONV_ADD_VER;
+ strcpy(din.ia_converter, "xlat16");
+ strcpy(din.ia_from, from);
+ strcpy(din.ia_to, to);
+ din.ia_data = data;
+ din.ia_datalen = datalen;
+ olen = sizeof(dout);
+ if (sysctlbyname("kern.iconv.add", &dout, &olen, &din, sizeof(din)) == -1)
+ return (errno);
+ return (0);
+}
+
+#else /* statically linked */
+
+#include <errno.h>
+
+int
+kiconv_add_xlat16_table(const char *to, const char *from, const void *data, int datalen)
+{
+ return (EINVAL);
+}
+
+#endif /* PIC */
diff --git a/lib/libkse/Makefile b/lib/libkse/Makefile
new file mode 100644
index 0000000..17b46b9
--- /dev/null
+++ b/lib/libkse/Makefile
@@ -0,0 +1,54 @@
+# $FreeBSD$
+#
+# 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 included legacy CSRG sccsid strings, add -DLIBC_SCCS and -DSYSLIBC_SCCS
+# (for system call stubs) to CFLAGS below. -DSYSLIBC_SCCS affects just the
+# system call stubs.
+.if ${MACHINE_ARCH} == "alpha" || ${MACHINE_ARCH} == "sparc64"
+LIB=kse
+.else
+LIB=pthread
+SHLIBDIR?= /lib
+.endif
+SHLIB_MAJOR= 2
+CFLAGS+=-DPTHREAD_KERNEL
+CFLAGS+=-I${.CURDIR}/../libc/include -I${.CURDIR}/thread \
+ -I${.CURDIR}/../../include
+CFLAGS+=-I${.CURDIR}/arch/${MACHINE_ARCH}/include
+CFLAGS+=-I${.CURDIR}/sys
+CFLAGS+=-I${.CURDIR}/../../libexec/rtld-elf
+CFLAGS+=-I${.CURDIR}/../../libexec/rtld-elf/${MACHINE_ARCH}
+CFLAGS+=-fno-builtin
+
+# Uncomment this if you want libpthread to contain debug information for
+# thread locking.
+CFLAGS+=-D_LOCK_DEBUG
+WARNS?=2
+
+# Uncomment this if you want to build a 1:1 threading mode library
+# however it is no longer strictly conformed to POSIX
+# CFLAGS+=-DSYSTEM_SCOPE_ONLY
+
+# Enable extra internal consistancy checks.
+CFLAGS+=-D_PTHREADS_INVARIANTS -Wall
+
+VERSION_MAP=${.CURDIR}/pthread.map
+
+.if defined(SYMVER_ENABLED)
+# Remove this if library version is bumped and LIBPTHREAD_1_0
+# compatability hacks are removed (see thread/thr_private.h).
+LDFLAGS+=-Wl,-zmuldefs
+CFLAGS+=-DSYMBOL_VERSIONING
+.endif
+
+PRECIOUSLIB=
+
+.include "${.CURDIR}/arch/${MACHINE_ARCH}/Makefile.inc"
+.include "${.CURDIR}/support/Makefile.inc"
+.include "${.CURDIR}/sys/Makefile.inc"
+.include "${.CURDIR}/thread/Makefile.inc"
+
+.include <bsd.lib.mk>
diff --git a/lib/libkse/arch/amd64/Makefile.inc b/lib/libkse/arch/amd64/Makefile.inc
new file mode 100644
index 0000000..c8b0362
--- /dev/null
+++ b/lib/libkse/arch/amd64/Makefile.inc
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}/${MACHINE_ARCH}
+
+SRCS+= context.S enter_uts.S pthread_md.c
diff --git a/lib/libkse/arch/amd64/amd64/context.S b/lib/libkse/arch/amd64/amd64/context.S
new file mode 100644
index 0000000..6a6b558
--- /dev/null
+++ b/lib/libkse/arch/amd64/amd64/context.S
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2003 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 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 <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * The following notes ("cheat sheet") was provided by Peter Wemm.
+ *
+ * scratch:
+ * rax (1st return)
+ * rcx (4th arg)
+ * rdx (3rd arg, 2nd return)
+ * rsi (2nd arg)
+ * rdi (1st arg)
+ * r8 (5th arg)
+ * r9 (6th arg)
+ * r10 (temp, static chain?)
+ * r11 (temp)
+ *
+ * preserved:
+ * rbx (base pointer)
+ * rsp (stack)
+ * rbp (frame)
+ * r12-r15 (general)
+ *
+ * calls:
+ * rdi 1
+ * rsi 2
+ * rdx 3
+ * rcx 4
+ * r8 5
+ * r9 6
+ *
+ * return:
+ * rax 1
+ * rdx 2
+ *
+ * This means:
+ * arg1 goes in %rdi, arg2 in %rsi, etc. return value is %rax (and
+ * secondary return, eg: pipe(2), in %rdx) %rcx,%rsi,%rdi etc are
+ * trashed by making a call to something. %rbx,%rbp,%r12-15 are the
+ * only registers preserved across a call. Note that unlike i386,
+ * %rsi and %rdi are scratch rather than preserved. FPU is
+ * different, args are in SSE registers rather than the x87 stack.
+ *
+ * Aside from the register calling conventions, amd64 can be treated
+ * very much like i386. Things like setjmp/longjmp etc were literal
+ * translations from i386 but with the register names updated, etc.
+ * The main gotcha is that FPU save/restore is in SSE format, which
+ * means a sparse 512 byte FPU context.
+ */
+
+
+/*
+ * Where do we define these?
+ */
+#define MC_SIZE 800 /* sizeof mcontext_t */
+#define MC_LEN_OFFSET (25*8) /* offset to mc_len from mcontext */
+#define MC_FPFMT_OFFSET (26*8) /* offset to mc_fpformat from mcontext */
+#define MC_FPFMT_NODEV 0x10000
+#define MC_OWNEDFP_OFFSET (27*8) /* offset to mc_ownedfp from mcontext */
+#define MC_OWNEDFP_NONE 0x20000
+#define MC_OWNEDFP_FPU 0x20001
+#define MC_OWNEDFP_PCB 0x20002
+#define MC_FPREGS_OFFSET (28*8) /* offset to FP registers */
+#define MC_FP_CW_OFFSET (28*8) /* offset to FP control word */
+
+#define MC_RDI (1 * 8)
+#define MC_RSI (2 * 8)
+#define MC_RDX (3 * 8)
+#define MC_RCX (4 * 8)
+#define MC_R8 (5 * 8)
+#define MC_R9 (6 * 8)
+#define MC_RAX (7 * 8)
+#define MC_RBX (8 * 8)
+#define MC_RBP (9 * 8)
+#define MC_R10 (10 * 8)
+#define MC_R11 (11 * 8)
+#define MC_R12 (12 * 8)
+#define MC_R13 (13 * 8)
+#define MC_R14 (14 * 8)
+#define MC_R15 (15 * 8)
+#define MC_FLAGS (18 * 8)
+#define MC_RIP (20 * 8)
+#define MC_CS (21 * 8)
+#define MC_RFLAGS (22 * 8)
+#define MC_RSP (23 * 8)
+#define MC_SS (24 * 8)
+
+#define REDZONE 128 /* size of the red zone */
+
+/*
+ * _amd64_ctx_save(mcontext_t *mcp)
+ *
+ * No values are saved to mc_trapno, mc_addr, mc_err and mc_cs.
+ * For the FPU state, only the floating point control word is stored.
+ */
+ENTRY(_amd64_save_context)
+ cmpq $0, %rdi /* check for null pointer */
+ jne 1f
+ movq $-1, %rax
+ jmp 2f
+1: movq %rdi, MC_RDI(%rdi)
+ movq %rsi, MC_RSI(%rdi)
+ movq %rdx, MC_RDX(%rdi)
+ movq %rcx, MC_RCX(%rdi)
+ movq %r8, MC_R8(%rdi)
+ movq %r9, MC_R9(%rdi)
+ movq $1, MC_RAX(%rdi) /* return 1 when restored */
+ movq %rbx, MC_RBX(%rdi)
+ movq %rbp, MC_RBP(%rdi)
+ movq %r10, MC_R10(%rdi)
+ movq %r11, MC_R11(%rdi)
+ movq %r12, MC_R12(%rdi)
+ movq %r13, MC_R13(%rdi)
+ movq %r14, MC_R14(%rdi)
+ movq %r15, MC_R15(%rdi)
+ movq (%rsp), %rax /* get return address */
+ movq %rax, MC_RIP(%rdi) /* save return address (%rip) */
+ pushfq /* get flags */
+ popq %rax
+ movq %rax, MC_RFLAGS(%rdi) /* save flags */
+ movq %rsp, %rax /* setcontext pushes the return */
+ addq $8, %rax /* address onto the stack; */
+ movq %rax, MC_RSP(%rdi) /* account for this -- ???. */
+ movw %ss, MC_SS(%rdi)
+ fnstcw MC_FP_CW_OFFSET(%rdi) /* save FPU control word */
+ movq $MC_OWNEDFP_NONE, MC_OWNEDFP_OFFSET(%rdi) /* no FP */
+ movq $MC_FPFMT_NODEV, MC_FPFMT_OFFSET(%rdi)
+ movq $MC_SIZE, MC_LEN_OFFSET(%rdi)
+ xorq %rax, %rax /* return 0 */
+2: ret
+
+/*
+ * _amd64_ctx_restore(mcontext_t *mcp, intptr_t val, intptr_t *loc);
+ */
+ENTRY(_amd64_restore_context)
+ cmpq $0, %rdi /* check for null pointer */
+ jne 1f
+ movq $-1, %rax
+ jmp 2f
+1: cmpq $MC_SIZE, MC_LEN_OFFSET(%rdi) /* is context valid? */
+ je 2f
+ movq $-1, %rax /* bzzzt, invalid context */
+ ret
+2: movq MC_RCX(%rdi), %rcx
+ movq MC_R8(%rdi), %r8
+ movq MC_R9(%rdi), %r9
+ movq MC_RBX(%rdi), %rbx
+ movq MC_RBP(%rdi), %rbp
+ movq MC_R10(%rdi), %r10
+ movq MC_R11(%rdi), %r11
+ movq MC_R12(%rdi), %r12
+ movq MC_R13(%rdi), %r13
+ movq MC_R14(%rdi), %r14
+ movq MC_R15(%rdi), %r15
+ /*
+ * if (mc_fpowned == MC_OWNEDFP_FPU || mc_fpowned == MC_OWNEDFP_PCB)
+ * restore XMM/SSE FP register format
+ */
+ cmpq $MC_OWNEDFP_NONE, MC_OWNEDFP_OFFSET(%rdi)
+ je 4f
+ cmpq $MC_OWNEDFP_PCB, MC_OWNEDFP_OFFSET(%rdi)
+ je 3f
+ cmpq $MC_OWNEDFP_FPU, MC_OWNEDFP_OFFSET(%rdi)
+ jne 4f
+3: fxrstor MC_FPREGS_OFFSET(%rdi) /* restore XMM FP regs */
+ jmp 5f
+4: fninit
+ fldcw MC_FP_CW_OFFSET(%rdi)
+5: movq MC_RSP(%rdi), %rsp /* switch to context stack */
+ subq $REDZONE, %rsp
+ movq MC_RIP(%rdi), %rax /* return address on stack */
+ pushq %rax
+ movq MC_RDI(%rdi), %rax /* rdi on stack */
+ pushq %rax
+ movq MC_RDX(%rdi), %rax /* rdx on stack */
+ pushq %rax
+ movq MC_RSI(%rdi), %rax /* rsi on stack */
+ pushq %rax
+ movq MC_RFLAGS(%rdi), %rax /* flags on stack*/
+ pushq %rax
+ movq MC_RAX(%rdi), %rax /* restore rax */
+ /* At this point we're done with the context. */
+ cmpq $0, %rdx /* set *loc to val */
+ je 6f
+ movq %rsi, (%rdx)
+6: popfq /* restore flags */
+ popq %rsi /* restore rsi, rdx, and rdi */
+ popq %rdx
+ popq %rdi
+ ret $REDZONE
+
diff --git a/lib/libkse/arch/amd64/amd64/enter_uts.S b/lib/libkse/arch/amd64/amd64/enter_uts.S
new file mode 100644
index 0000000..fb0df87
--- /dev/null
+++ b/lib/libkse/arch/amd64/amd64/enter_uts.S
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2003 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 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 <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+
+/*
+ * _amd64_enter_uts(struct kse_mailbox *km, kse_func_t uts, void *stack,
+ * size_t stacksz);
+ */
+ENTRY(_amd64_enter_uts)
+ addq %rcx, %rdx /* get stack base */
+ andq $~0xf, %rdx /* align to 16 bytes */
+ movq %rdx, %rsp /* switch to UTS stack */
+ movq %rdx, %rbp /* set frame */
+ callq *%rsi
+ ret
diff --git a/lib/libkse/arch/amd64/amd64/pthread_md.c b/lib/libkse/arch/amd64/amd64/pthread_md.c
new file mode 100644
index 0000000..3aceec7
--- /dev/null
+++ b/lib/libkse/arch/amd64/amd64/pthread_md.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2003 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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, 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$
+ */
+
+#include <stdlib.h>
+#include <strings.h>
+#include "rtld_tls.h"
+#include "pthread_md.h"
+
+/*
+ * The constructors.
+ */
+struct tcb *
+_tcb_ctor(struct pthread *thread, int initial)
+{
+ struct tcb *tcb;
+ void *oldtls;
+
+ if (initial) {
+ __asm __volatile("movq %%fs:0, %0" : "=r" (oldtls));
+ } else {
+ oldtls = NULL;
+ }
+
+ tcb = _rtld_allocate_tls(oldtls, sizeof(struct tcb), 16);
+ if (tcb) {
+ tcb->tcb_thread = thread;
+ bzero(&tcb->tcb_tmbx, sizeof(tcb->tcb_tmbx));
+ }
+
+ return (tcb);
+}
+
+void
+_tcb_dtor(struct tcb *tcb)
+{
+ _rtld_free_tls(tcb, sizeof(struct tcb), 16);
+}
+
+struct kcb *
+_kcb_ctor(struct kse *kse)
+{
+ struct kcb *kcb;
+
+ kcb = malloc(sizeof(struct kcb));
+ if (kcb != NULL) {
+ bzero(kcb, sizeof(struct kcb));
+ kcb->kcb_self = kcb;
+ kcb->kcb_kse = kse;
+ }
+ return (kcb);
+}
+
+void
+_kcb_dtor(struct kcb *kcb)
+{
+ free(kcb);
+}
diff --git a/lib/libkse/arch/amd64/include/atomic_ops.h b/lib/libkse/arch/amd64/include/atomic_ops.h
new file mode 100644
index 0000000..980eb8e
--- /dev/null
+++ b/lib/libkse/arch/amd64/include/atomic_ops.h
@@ -0,0 +1,57 @@
+/*-
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _ATOMIC_OPS_H_
+#define _ATOMIC_OPS_H_
+
+/*
+ * Atomic swap:
+ * Atomic (tmp = *dst, *dst = val), then *res = tmp
+ *
+ * void atomic_swap64(intptr_t *dst, intptr_t val, intptr_t *res);
+ */
+static inline void
+atomic_swap64(intptr_t *dst, intptr_t val, intptr_t *res)
+{
+ __asm __volatile(
+ "xchgq %2, %1; movq %2, %0"
+ : "=m" (*res) : "m" (*dst), "r" (val) : "memory");
+}
+
+static inline void
+atomic_swap_int(int *dst, int val, int *res)
+{
+ __asm __volatile(
+ "xchgl %2, %1; movl %2, %0"
+ : "=m" (*res) : "m" (*dst), "r" (val) : "memory");
+}
+
+#define atomic_swap_ptr(d, v, r) \
+ atomic_swap64((intptr_t *)(d), (intptr_t)(v), (intptr_t *)(r))
+
+#endif
diff --git a/lib/libkse/arch/amd64/include/pthread_md.h b/lib/libkse/arch/amd64/include/pthread_md.h
new file mode 100644
index 0000000..a7da5df
--- /dev/null
+++ b/lib/libkse/arch/amd64/include/pthread_md.h
@@ -0,0 +1,268 @@
+/*-
+ * Copyright (C) 2003 David Xu <davidxu@freebsd.org>
+ * 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.
+ *
+ * $FreeBSD$
+ */
+/*
+ * Machine-dependent thread prototypes/definitions for the thread kernel.
+ */
+#ifndef _PTHREAD_MD_H_
+#define _PTHREAD_MD_H_
+
+#include <stddef.h>
+#include <sys/types.h>
+#include <sys/kse.h>
+#include <machine/sysarch.h>
+#include <ucontext.h>
+
+#define KSE_STACKSIZE 16384
+#define DTV_OFFSET offsetof(struct tcb, tcb_dtv)
+
+#define THR_GETCONTEXT(ucp) \
+ (void)_amd64_save_context(&(ucp)->uc_mcontext)
+#define THR_SETCONTEXT(ucp) \
+ (void)_amd64_restore_context(&(ucp)->uc_mcontext, 0, NULL)
+
+#define PER_KSE
+#undef PER_THREAD
+
+struct kse;
+struct pthread;
+struct tdv;
+
+/*
+ * %fs points to a struct kcb.
+ */
+struct kcb {
+ struct tcb *kcb_curtcb;
+ struct kcb *kcb_self; /* self reference */
+ struct kse *kcb_kse;
+ struct kse_mailbox kcb_kmbx;
+};
+
+struct tcb {
+ struct tcb *tcb_self; /* required by rtld */
+ void *tcb_dtv; /* required by rtld */
+ struct pthread *tcb_thread;
+ void *tcb_spare[1]; /* align tcb_tmbx to 16 bytes */
+ struct kse_thr_mailbox tcb_tmbx;
+};
+
+/*
+ * Evaluates to the byte offset of the per-kse variable name.
+ */
+#define __kcb_offset(name) __offsetof(struct kcb, name)
+
+/*
+ * Evaluates to the type of the per-kse variable name.
+ */
+#define __kcb_type(name) __typeof(((struct kcb *)0)->name)
+
+/*
+ * Evaluates to the value of the per-kse variable name.
+ */
+#define KCB_GET64(name) ({ \
+ __kcb_type(name) __result; \
+ \
+ u_long __i; \
+ __asm __volatile("movq %%fs:%1, %0" \
+ : "=r" (__i) \
+ : "m" (*(u_long *)(__kcb_offset(name)))); \
+ __result = (__kcb_type(name))__i; \
+ \
+ __result; \
+})
+
+/*
+ * Sets the value of the per-kse variable name to value val.
+ */
+#define KCB_SET64(name, val) ({ \
+ __kcb_type(name) __val = (val); \
+ \
+ u_long __i; \
+ __i = (u_long)__val; \
+ __asm __volatile("movq %1,%%fs:%0" \
+ : "=m" (*(u_long *)(__kcb_offset(name))) \
+ : "r" (__i)); \
+})
+
+static __inline u_long
+__kcb_readandclear64(volatile u_long *addr)
+{
+ u_long result;
+
+ __asm __volatile (
+ " xorq %0, %0;"
+ " xchgq %%fs:%1, %0;"
+ "# __kcb_readandclear64"
+ : "=&r" (result)
+ : "m" (*addr));
+ return (result);
+}
+
+#define KCB_READANDCLEAR64(name) ({ \
+ __kcb_type(name) __result; \
+ \
+ __result = (__kcb_type(name)) \
+ __kcb_readandclear64((u_long *)__kcb_offset(name)); \
+ __result; \
+})
+
+
+#define _kcb_curkcb() KCB_GET64(kcb_self)
+#define _kcb_curtcb() KCB_GET64(kcb_curtcb)
+#define _kcb_curkse() ((struct kse *)KCB_GET64(kcb_kmbx.km_udata))
+#define _kcb_get_tmbx() KCB_GET64(kcb_kmbx.km_curthread)
+#define _kcb_set_tmbx(value) KCB_SET64(kcb_kmbx.km_curthread, (void *)value)
+#define _kcb_readandclear_tmbx() KCB_READANDCLEAR64(kcb_kmbx.km_curthread)
+
+/*
+ * The constructors.
+ */
+struct tcb *_tcb_ctor(struct pthread *, int);
+void _tcb_dtor(struct tcb *tcb);
+struct kcb *_kcb_ctor(struct kse *);
+void _kcb_dtor(struct kcb *);
+
+/* Called from the KSE to set its private data. */
+static __inline void
+_kcb_set(struct kcb *kcb)
+{
+ amd64_set_fsbase(kcb);
+}
+
+/* Get the current kcb. */
+static __inline struct kcb *
+_kcb_get(void)
+{
+ return (_kcb_curkcb());
+}
+
+static __inline struct kse_thr_mailbox *
+_kcb_critical_enter(void)
+{
+ struct kse_thr_mailbox *crit;
+
+ crit = _kcb_readandclear_tmbx();
+ return (crit);
+}
+
+static __inline void
+_kcb_critical_leave(struct kse_thr_mailbox *crit)
+{
+ _kcb_set_tmbx(crit);
+}
+
+static __inline int
+_kcb_in_critical(void)
+{
+ return (_kcb_get_tmbx() == NULL);
+}
+
+static __inline void
+_tcb_set(struct kcb *kcb, struct tcb *tcb)
+{
+ kcb->kcb_curtcb = tcb;
+}
+
+static __inline struct tcb *
+_tcb_get(void)
+{
+ return (_kcb_curtcb());
+}
+
+static __inline struct pthread *
+_get_curthread(void)
+{
+ struct tcb *tcb;
+
+ tcb = _kcb_curtcb();
+ if (tcb != NULL)
+ return (tcb->tcb_thread);
+ else
+ return (NULL);
+}
+
+static __inline struct kse *
+_get_curkse(void)
+{
+ return ((struct kse *)_kcb_curkse());
+}
+
+void _amd64_enter_uts(struct kse_mailbox *km, kse_func_t uts, void *stack,
+ size_t stacksz);
+int _amd64_restore_context(mcontext_t *mc, intptr_t val, intptr_t *loc);
+int _amd64_save_context(mcontext_t *mc);
+
+static __inline int
+_thread_enter_uts(struct tcb *tcb, struct kcb *kcb)
+{
+ int ret;
+
+ ret = _amd64_save_context(&tcb->tcb_tmbx.tm_context.uc_mcontext);
+ if (ret == 0) {
+ _amd64_enter_uts(&kcb->kcb_kmbx, kcb->kcb_kmbx.km_func,
+ kcb->kcb_kmbx.km_stack.ss_sp,
+ kcb->kcb_kmbx.km_stack.ss_size);
+ /* We should not reach here. */
+ return (-1);
+ }
+ else if (ret < 0)
+ return (-1);
+ return (0);
+}
+
+static __inline int
+_thread_switch(struct kcb *kcb, struct tcb *tcb, int setmbox)
+{
+ extern int _libkse_debug;
+
+ if ((kcb == NULL) || (tcb == NULL))
+ return (-1);
+ kcb->kcb_curtcb = tcb;
+
+ if (_libkse_debug == 0) {
+ tcb->tcb_tmbx.tm_lwp = kcb->kcb_kmbx.km_lwp;
+ if (setmbox != 0)
+ _amd64_restore_context(
+ &tcb->tcb_tmbx.tm_context.uc_mcontext,
+ (intptr_t)&tcb->tcb_tmbx,
+ (intptr_t *)&kcb->kcb_kmbx.km_curthread);
+ else
+ _amd64_restore_context(
+ &tcb->tcb_tmbx.tm_context.uc_mcontext,
+ 0, NULL);
+ /* We should not reach here. */
+ } else {
+ if (setmbox)
+ kse_switchin(&tcb->tcb_tmbx, KSE_SWITCHIN_SETTMBX);
+ else
+ kse_switchin(&tcb->tcb_tmbx, 0);
+ }
+
+ return (-1);
+}
+#endif
diff --git a/lib/libkse/arch/arm/Makefile.inc b/lib/libkse/arch/arm/Makefile.inc
new file mode 100644
index 0000000..ced7063
--- /dev/null
+++ b/lib/libkse/arch/arm/Makefile.inc
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}/${MACHINE_ARCH}
+
+CFLAGS+=-DSYSTEM_SCOPE_ONLY
+
+SRCS+= pthread_md.c context.S
diff --git a/lib/libkse/arch/arm/arm/context.S b/lib/libkse/arch/arm/arm/context.S
new file mode 100644
index 0000000..c638804
--- /dev/null
+++ b/lib/libkse/arch/arm/arm/context.S
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 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. 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$");
+
+/*
+ * int thr_setcontext(mcontext_t *mcp, intptr_t val, intptr_t *loc)
+ *
+ * Restores the context in mcp.
+ *
+ * Returns 0 if there are no errors; -1 otherwise
+ */
+
+.weak _C_LABEL(_thr_setcontext)
+.set _C_LABEL(_thr_setcontext), _C_LABEL(__thr_setcontext)
+
+ENTRY(__thr_setcontext)
+/* Check for NULL pointer. */
+ cmp r0, #0
+ moveq r0, #-1
+ moveq pc, lr
+ cmp r2, #0
+ strne r1, [r2]
+ ldr r1, [r0, #(16 * 4)] /* CPSR */
+ msr cpsr, r1
+ ldmia r0, {r0-r15}
+ mov pc, lr
+ /* XXX: FP bits ? */
+
+/*
+ * int thr_getcontext(mcontext_t *mcp);
+ *
+ * Returns -1 if there is an error, 0 no errors; 1 upon return
+ * from a setcontext().
+ */
+.weak _C_LABEL(_thr_getcontext)
+.set _C_LABEL(_thr_getcontext), _C_LABEL(__thr_getcontext)
+
+ENTRY(__thr_getcontext)
+/* Check for NULL pointer. */
+ cmp r0, #0
+ moveq r0, #-1
+ moveq pc, lr
+ stmia r0, {r1-r14}
+ mov r1, #1
+ str r1, [r0] /* Return 1 from setcontext */
+ str lr, [r0, #(15 * 4)] /* PC */
+ mrs r1, cpsr
+ str r1, [r0, #(16 * 4)] /* CPSR */
+ mov r0, #0 /* Return 0. */
+ mov pc, lr
+
+ENTRY(_arm_enter_uts)
+ add sp, r2, r3 /* Stack addr + size. */
+ mov pc, r1
diff --git a/lib/libkse/arch/arm/arm/pthread_md.c b/lib/libkse/arch/arm/arm/pthread_md.c
new file mode 100644
index 0000000..72426d4
--- /dev/null
+++ b/lib/libkse/arch/arm/arm/pthread_md.c
@@ -0,0 +1,86 @@
+/*-
+ * Copyright (C) 2003 Jake Burkholder <jake@freebsd.org>
+ * Copyright (C) 2003 David Xu <davidxu@freebsd.org>
+ * Copyright (c) 2001,2003 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include <unistd.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ucontext.h>
+
+#include <machine/sysarch.h>
+
+#include "pthread_md.h"
+
+struct arm_tp **arm_tp = (struct arm_tp **)ARM_TP_ADDRESS;
+
+struct tcb *
+_tcb_ctor(struct pthread *thread, int initial)
+{
+ struct tcb *tcb;
+
+ if ((tcb = malloc(sizeof(struct tcb)))) {
+ bzero(tcb, sizeof(struct tcb));
+ tcb->tcb_thread = thread;
+ /* XXX - Allocate tdv/tls */
+ }
+ return (tcb);
+}
+
+void
+_tcb_dtor(struct tcb *tcb)
+{
+
+ free(tcb);
+}
+
+struct kcb *
+_kcb_ctor(struct kse *kse)
+{
+ struct kcb *kcb;
+
+ kcb = malloc(sizeof(struct kcb));
+ if (kcb != NULL) {
+ bzero(kcb, sizeof(struct kcb));
+ kcb->kcb_faketcb.tcb_isfake = 1;
+ kcb->kcb_faketcb.tcb_tmbx.tm_flags = TMF_NOUPCALL;
+ kcb->kcb_curtcb = &kcb->kcb_faketcb;
+ kcb->kcb_kse = kse;
+ }
+ return (kcb);
+}
+
+void
+_kcb_dtor(struct kcb *kcb)
+{
+ free(kcb);
+}
diff --git a/lib/libkse/arch/arm/include/atomic_ops.h b/lib/libkse/arch/arm/include/atomic_ops.h
new file mode 100644
index 0000000..3a209b3
--- /dev/null
+++ b/lib/libkse/arch/arm/include/atomic_ops.h
@@ -0,0 +1,53 @@
+/*-
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _ATOMIC_OPS_H_
+#define _ATOMIC_OPS_H_
+
+#include <machine/atomic.h>
+#include "thr_private.h"
+
+/*
+ * Atomic swap:
+ * Atomic (tmp = *dst, *dst = val), then *res = tmp
+ *
+ * void atomic_swap32(intptr_t *dst, intptr_t val, intptr_t *res);
+ */
+static inline void
+atomic_swap32(intptr_t *dst, intptr_t val, intptr_t *res)
+{
+ *res = __swp(val, dst);
+}
+
+#define atomic_swap_ptr(d, v, r) \
+ atomic_swap32((intptr_t *)d, (intptr_t)v, (intptr_t *)r)
+
+#define atomic_swap_int(d, v, r) \
+ atomic_swap32((intptr_t *)d, (intptr_t)v, (intptr_t *)r)
+#endif
+
diff --git a/lib/libkse/arch/arm/include/pthread_md.h b/lib/libkse/arch/arm/include/pthread_md.h
new file mode 100644
index 0000000..857fa1b
--- /dev/null
+++ b/lib/libkse/arch/arm/include/pthread_md.h
@@ -0,0 +1,257 @@
+/*-
+ * Copyright (c) 2003 Jake Burkholder <jake@freebsd.org>.
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Machine-dependent thread prototypes/definitions for the thread kernel.
+ */
+#ifndef _PTHREAD_MD_H_
+#define _PTHREAD_MD_H_
+
+#include <sys/kse.h>
+#include <stddef.h>
+#include <ucontext.h>
+
+#define KSE_STACKSIZE 16384
+#define DTV_OFFSET offsetof(struct tcb, tcb_tp.tp_tdv)
+
+int _thr_setcontext(mcontext_t *, intptr_t, intptr_t *);
+int _thr_getcontext(mcontext_t *);
+
+#define THR_GETCONTEXT(ucp) _thr_getcontext(&(ucp)->uc_mcontext)
+#define THR_SETCONTEXT(ucp) _thr_setcontext(&(ucp)->uc_mcontext, 0, NULL)
+
+#define PER_THREAD
+
+struct kcb;
+struct kse;
+struct pthread;
+struct tcb;
+struct tdv; /* We don't know what this is yet? */
+
+
+/*
+ * %r6 points to one of these. We define the static TLS as an array
+ * of long double to enforce 16-byte alignment of the TLS memory.
+ *
+ * XXX - Both static and dynamic allocation of any of these structures
+ * will result in a valid, well-aligned thread pointer???
+ */
+struct arm_tp {
+ struct tdv *tp_tdv; /* dynamic TLS */
+};
+
+struct tcb {
+ struct pthread *tcb_thread;
+ struct kcb *tcb_curkcb;
+ uint32_t tcb_isfake;
+ struct kse_thr_mailbox tcb_tmbx; /* needs 32-byte alignment */
+ struct arm_tp tcb_tp;
+};
+
+struct kcb {
+ struct kse_mailbox kcb_kmbx;
+ struct tcb kcb_faketcb;
+ struct tcb *kcb_curtcb;
+ struct kse *kcb_kse;
+};
+
+extern struct arm_tp **arm_tp;
+#define _tp (*arm_tp)
+
+#define _tcb ((struct tcb*)((char*)(_tp) - offsetof(struct tcb, tcb_tp)))
+
+/*
+ * The kcb and tcb constructors.
+ */
+struct tcb *_tcb_ctor(struct pthread *, int);
+void _tcb_dtor(struct tcb *);
+struct kcb *_kcb_ctor(struct kse *kse);
+void _kcb_dtor(struct kcb *);
+
+static __inline uint32_t
+__kcb_swp(uint32_t val, void *ptr)
+{
+
+ __asm __volatile("swp %0, %1, [%2]"
+ : "=r" (val) : "r" (val) , "r" (ptr) : "memory");
+ return (val);
+}
+
+/* Called from the KSE to set its private data. */
+static __inline void
+_kcb_set(struct kcb *kcb)
+{
+ /* There is no thread yet; use the fake tcb. */
+ __kcb_swp((uint32_t)&kcb->kcb_faketcb.tcb_tp, &_tp);
+}
+
+/*
+ * Get the current kcb.
+ *
+ * This can only be called while in a critical region; don't
+ * worry about having the kcb changed out from under us.
+ */
+static __inline struct kcb *
+_kcb_get(void)
+{
+ return (_tcb->tcb_curkcb);
+}
+
+/*
+ * Enter a critical region.
+ *
+ * Read and clear km_curthread in the kse mailbox.
+ */
+static __inline struct kse_thr_mailbox *
+_kcb_critical_enter(void)
+{
+ struct kse_thr_mailbox *crit;
+
+ if (_tcb->tcb_isfake)
+ return (NULL);
+ crit = (struct kse_thr_mailbox *)__kcb_swp((uint32_t)NULL,
+ &_tcb->tcb_curkcb->kcb_kmbx.km_curthread);
+ return (crit);
+}
+
+static __inline void
+_kcb_critical_leave(struct kse_thr_mailbox *crit)
+{
+
+ if (_tcb->tcb_isfake == 0)
+ __kcb_swp((uint32_t)crit,
+ &_tcb->tcb_curkcb->kcb_kmbx.km_curthread);
+}
+
+static __inline int
+_kcb_in_critical(void)
+{
+ uint32_t flags;
+ int ret;
+
+ return (_tcb->tcb_curkcb->kcb_kmbx.km_curthread == NULL);
+ if (_tcb->tcb_isfake != 0) {
+ /*
+ * We are in a critical region since there is no
+ * current thread.
+ */
+ ret = 1;
+ } else {
+ flags = _tcb->tcb_tmbx.tm_flags;
+ _tcb->tcb_tmbx.tm_flags |= TMF_NOUPCALL;
+ ret = (_tcb->tcb_curkcb->kcb_kmbx.km_curthread == NULL);
+ _tcb->tcb_tmbx.tm_flags = flags;
+ }
+ return (ret);
+}
+
+static __inline void
+_tcb_set(struct kcb *kcb, struct tcb *tcb)
+{
+ if (tcb == NULL)
+ tcb = &kcb->kcb_faketcb;
+ __kcb_swp((uint32_t)&tcb->tcb_tp, &_tp);
+ kcb->kcb_curtcb = tcb;
+ tcb->tcb_curkcb = kcb;
+}
+
+static __inline struct tcb *
+_tcb_get(void)
+{
+ return (_tcb);
+}
+
+static __inline struct pthread *
+_get_curthread(void)
+{
+ return (_tcb->tcb_thread);
+}
+
+/*
+ * Get the current kse.
+ *
+ * Like _kcb_get(), this can only be called while in a critical region.
+ */
+static __inline struct kse *
+_get_curkse(void)
+{
+ return (_tcb->tcb_curkcb->kcb_kse);
+}
+
+void _arm_enter_uts(struct kse_mailbox *km, kse_func_t uts, void *stack,
+ size_t stacksz);
+
+static __inline int
+_thread_enter_uts(struct tcb *tcb, struct kcb *kcb)
+{
+ int ret;
+
+ if ((ret = _thr_getcontext(&tcb->tcb_tmbx.tm_context.uc_mcontext))
+ == 0) {
+ kcb->kcb_curtcb = &kcb->kcb_faketcb;
+ __kcb_swp((int)&kcb->kcb_faketcb.tcb_tp, &_tp);
+ _arm_enter_uts(&kcb->kcb_kmbx, kcb->kcb_kmbx.km_func,
+ kcb->kcb_kmbx.km_stack.ss_sp,
+ kcb->kcb_kmbx.km_stack.ss_size);
+ /* We should not reach here. */
+ return (-1);
+ } else if (ret < 0)
+ return (-1);
+ return (0);
+}
+
+static __inline int
+_thread_switch(struct kcb *kcb, struct tcb *tcb, int setmbox)
+{
+ extern int _libkse_debug;
+ mcontext_t *mc;
+
+ if (!tcb || !kcb)
+ return (-1);
+ _tcb_set(kcb, tcb);
+ mc = &tcb->tcb_tmbx.tm_context.uc_mcontext;
+ if (_libkse_debug == 0) {
+ tcb->tcb_tmbx.tm_lwp = kcb->kcb_kmbx.km_lwp;
+ if (setmbox)
+ _thr_setcontext(mc, (intptr_t)&tcb->tcb_tmbx,
+ (intptr_t *)&kcb->kcb_kmbx.km_curthread);
+ else
+ _thr_setcontext(mc, 0, NULL);
+ } else {
+ if (setmbox)
+ kse_switchin(&tcb->tcb_tmbx, KSE_SWITCHIN_SETTMBX);
+ else
+ kse_switchin(&tcb->tcb_tmbx, 0);
+ }
+
+ /* We should not reach here. */
+ return (-1);
+}
+
+#endif /* _PTHREAD_MD_H_ */
diff --git a/lib/libkse/arch/i386/Makefile.inc b/lib/libkse/arch/i386/Makefile.inc
new file mode 100644
index 0000000..73a9a8a
--- /dev/null
+++ b/lib/libkse/arch/i386/Makefile.inc
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}/${MACHINE_ARCH}
+
+SRCS+= thr_enter_uts.S thr_getcontext.S pthread_md.c
diff --git a/lib/libkse/arch/i386/i386/pthread_md.c b/lib/libkse/arch/i386/i386/pthread_md.c
new file mode 100644
index 0000000..cbea6d4
--- /dev/null
+++ b/lib/libkse/arch/i386/i386/pthread_md.c
@@ -0,0 +1,100 @@
+/*-
+ * Copyright (C) 2003 David Xu <davidxu@freebsd.org>
+ * Copyright (c) 2001,2003 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <machine/cpufunc.h>
+#include <machine/sysarch.h>
+
+#include <unistd.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ucontext.h>
+
+#include "rtld_tls.h"
+#include "pthread_md.h"
+
+struct tcb *
+_tcb_ctor(struct pthread *thread, int initial)
+{
+ struct tcb *tcb;
+ void *oldtls;
+
+ if (initial) {
+ __asm __volatile("movl %%gs:0, %0" : "=r" (oldtls));
+ } else {
+ oldtls = NULL;
+ }
+
+ tcb = _rtld_allocate_tls(oldtls, sizeof(struct tcb), 16);
+ if (tcb) {
+ tcb->tcb_thread = thread;
+ tcb->tcb_spare = 0;
+ bzero(&tcb->tcb_tmbx, sizeof(tcb->tcb_tmbx));
+ }
+
+ return (tcb);
+}
+
+void
+_tcb_dtor(struct tcb *tcb)
+{
+ _rtld_free_tls(tcb, sizeof(struct tcb), 16);
+}
+
+/*
+ * Initialize KSD. This also includes setting up the LDT.
+ */
+struct kcb *
+_kcb_ctor(struct kse *kse)
+{
+ struct kcb *kcb;
+
+ kcb = malloc(sizeof(struct kcb));
+ if (kcb != NULL) {
+ bzero(kcb, sizeof(struct kcb));
+ kcb->kcb_self = kcb;
+ kcb->kcb_kse = kse;
+ }
+ return (kcb);
+}
+
+void
+_kcb_dtor(struct kcb *kcb)
+{
+ free(kcb);
+}
+
+int
+i386_set_gsbase(void *addr)
+{
+
+ return (sysarch(I386_SET_GSBASE, &addr));
+}
diff --git a/lib/libkse/arch/i386/i386/thr_enter_uts.S b/lib/libkse/arch/i386/i386/thr_enter_uts.S
new file mode 100644
index 0000000..bf6df8f
--- /dev/null
+++ b/lib/libkse/arch/i386/i386/thr_enter_uts.S
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2002 Jonathan Mini <mini@freebsd.org>.
+ * 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 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 <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+
+/*
+ * _i386_enter_uts(struct kse_mailbox *km, kse_func_t uts, void *stack,
+ * long stacksz);
+ * +4 = km, +8 = uts, +12 = stack, +16 = size
+ */
+ENTRY(_i386_enter_uts)
+ movl %esp, %edx /* save stack */
+ movl 12(%edx), %eax /* get bottom of stack */
+ addl 16(%edx), %eax /* add length */
+ movl %eax, %esp /* switch to uts stack */
+ pushl 4(%edx) /* push the address of the mailbox */
+ call *8(%edx)
+ ret
diff --git a/lib/libkse/arch/i386/i386/thr_getcontext.S b/lib/libkse/arch/i386/i386/thr_getcontext.S
new file mode 100644
index 0000000..d9d300f
--- /dev/null
+++ b/lib/libkse/arch/i386/i386/thr_getcontext.S
@@ -0,0 +1,156 @@
+/*-
+ * 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 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 <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Where do we define these?
+ */
+#define MC_LEN_OFFSET 80 /* offset to mc_len from mcontext */
+#define MC_LEN 640 /* mc_len <machine/ucontext.h> */
+#define MC_FPFMT_OFFSET 84
+#define MC_FPFMT_NODEV 0x10000
+#define MC_FPFMT_387 0x10001
+#define MC_FPFMT_XMM 0x10002
+#define MC_OWNEDFP_OFFSET 88
+#define MC_OWNEDFP_NONE 0x20000
+#define MC_OWNEDFP_FPU 0x20001
+#define MC_OWNEDFP_PCB 0x20002
+#define MC_FPREGS_OFFSET 96 /* offset to FP regs from mcontext */
+#define MC_FP_CW_OFFSET 96 /* offset to FP control word */
+
+/*
+ * int thr_setcontext(mcontext_t *mcp, intptr_t val, intptr_t *loc)
+ *
+ * Restores the context in mcp.
+ *
+ * Returns 0 if there are no errors; -1 otherwise
+ */
+ .weak CNAME(_thr_setcontext)
+ .set CNAME(_thr_setcontext),CNAME(__thr_setcontext)
+ENTRY(__thr_setcontext)
+ movl 4(%esp), %edx /* get address of mcontext */
+ cmpl $0, %edx /* check for null pointer */
+ jne 1f
+ movl $-1, %eax
+ jmp 8f
+1: cmpl $MC_LEN, MC_LEN_OFFSET(%edx) /* is context valid? */
+ je 2f
+ movl $-1, %eax /* bzzzt, invalid context */
+ jmp 8f
+2: /*movl 4(%edx), %gs*/ /* we don't touch %gs */
+ movw 8(%edx), %fs
+ movw 12(%edx), %es
+ movw 16(%edx), %ds
+ movw 76(%edx), %ss
+ movl 20(%edx), %edi
+ movl 24(%edx), %esi
+ movl 28(%edx), %ebp
+ movl %esp, %ecx /* save current stack in ecx */
+ movl 72(%edx), %esp /* switch to context defined stack */
+ pushl 60(%edx) /* push return address on stack */
+ pushl 44(%edx) /* push ecx on stack */
+ pushl 48(%edx) /* push eax on stack */
+ /*
+ * if (mc_fpowned == MC_OWNEDFP_FPU || mc_fpowned == MC_OWNEDFP_PCB) {
+ * if (mc_fpformat == MC_FPFMT_387)
+ * restore 387 FP register format
+ * else if (mc_fpformat == MC_FPFMT_XMM)
+ * restore XMM/SSE FP register format
+ * }
+ */
+ cmpl $MC_OWNEDFP_FPU, MC_OWNEDFP_OFFSET(%edx)
+ je 3f
+ cmpl $MC_OWNEDFP_PCB, MC_OWNEDFP_OFFSET(%edx)
+ jne 5f
+3: cmpl $MC_FPFMT_387, MC_FPFMT_OFFSET(%edx)
+ jne 4f
+ frstor MC_FPREGS_OFFSET(%edx) /* restore 387 FP regs */
+ jmp 6f
+4: cmpl $MC_FPFMT_XMM, MC_FPFMT_OFFSET(%edx)
+ jne 5f
+ fxrstor MC_FPREGS_OFFSET(%edx) /* restore XMM FP regs */
+ jmp 6f
+5: fninit
+ fldcw MC_FP_CW_OFFSET(%edx)
+6: pushl 68(%edx) /* push flags register on stack*/
+ movl 36(%edx), %ebx /* restore ebx and edx */
+ movl 40(%edx), %edx
+ movl 12(%ecx), %eax /* get 3rd arg (loc) */
+ cmpl $0, %eax /* do nothing if loc == null */
+ je 7f
+ movl 8(%ecx), %ecx /* get 2nd arg (val) */
+ movl %ecx, (%eax) /* set loc = val */
+7: popfl /* restore flags after test */
+ popl %eax /* restore eax and ecx last */
+ popl %ecx
+8: ret
+
+/*
+ * int thr_getcontext(mcontext_t *mcp);
+ *
+ * Returns -1 if there is an error, 0 no errors; 1 upon return
+ * from a setcontext().
+ */
+ .weak CNAME(_thr_getcontext)
+ .set CNAME(_thr_getcontext),CNAME(__thr_getcontext)
+ENTRY(__thr_getcontext)
+ pushl %edx /* save edx */
+ movl 8(%esp), %edx /* get address of mcontext */
+ cmpl $0, %edx /* check for null pointer */
+ jne 1f
+ popl %edx /* restore edx and stack */
+ movl $-1, %eax
+ jmp 2f
+1: /*movw %gs, 4(%edx)*/ /* we don't touch %gs */
+ movw %fs, 8(%edx)
+ movw %es, 12(%edx)
+ movw %ds, 16(%edx)
+ movw %ss, 76(%edx)
+ movl %edi, 20(%edx)
+ movl %esi, 24(%edx)
+ movl %ebp, 28(%edx)
+ movl %ebx, 36(%edx)
+ movl $1, 48(%edx) /* store successful return in eax */
+ popl %eax /* get saved value of edx */
+ movl %eax, 40(%edx) /* save edx */
+ movl %ecx, 44(%edx)
+ movl (%esp), %eax /* get return address */
+ movl %eax, 60(%edx) /* save return address */
+ fnstcw MC_FP_CW_OFFSET(%edx)
+ movl $MC_LEN, MC_LEN_OFFSET(%edx)
+ movl $MC_FPFMT_NODEV, MC_FPFMT_OFFSET(%edx) /* no FP */
+ movl $MC_OWNEDFP_NONE, MC_OWNEDFP_OFFSET(%edx) /* no FP */
+ pushfl
+ popl %eax /* get eflags */
+ movl %eax, 68(%edx) /* store eflags */
+ movl %esp, %eax /* setcontext pushes the return */
+ addl $4, %eax /* address onto the top of the */
+ movl %eax, 72(%edx) /* stack; account for this */
+ movl 40(%edx), %edx /* restore edx -- is this needed? */
+ xorl %eax, %eax /* return 0 */
+2: ret
diff --git a/lib/libkse/arch/i386/include/atomic_ops.h b/lib/libkse/arch/i386/include/atomic_ops.h
new file mode 100644
index 0000000..7bc3d1b
--- /dev/null
+++ b/lib/libkse/arch/i386/include/atomic_ops.h
@@ -0,0 +1,51 @@
+/*-
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _ATOMIC_OPS_H_
+#define _ATOMIC_OPS_H_
+
+/*
+ * Atomic swap:
+ * Atomic (tmp = *dst, *dst = val), then *res = tmp
+ *
+ * void atomic_swap32(intptr_t *dst, intptr_t val, intptr_t *res);
+ */
+static inline void
+atomic_swap32(intptr_t *dst, intptr_t val, intptr_t *res)
+{
+ __asm __volatile(
+ "xchgl %2, %1; movl %2, %0"
+ : "=m" (*res) : "m" (*dst), "r" (val) : "memory");
+}
+
+#define atomic_swap_ptr(d, v, r) \
+ atomic_swap32((intptr_t *)d, (intptr_t)v, (intptr_t *)r)
+
+#define atomic_swap_int(d, v, r) \
+ atomic_swap32((intptr_t *)d, (intptr_t)v, (intptr_t *)r)
+#endif
diff --git a/lib/libkse/arch/i386/include/pthread_md.h b/lib/libkse/arch/i386/include/pthread_md.h
new file mode 100644
index 0000000..52afd6a
--- /dev/null
+++ b/lib/libkse/arch/i386/include/pthread_md.h
@@ -0,0 +1,264 @@
+/*-
+ * Copyright (c) 2002 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+/*
+ * Machine-dependent thread prototypes/definitions for the thread kernel.
+ */
+#ifndef _PTHREAD_MD_H_
+#define _PTHREAD_MD_H_
+
+#include <stddef.h>
+#include <sys/types.h>
+#include <sys/kse.h>
+#include <machine/sysarch.h>
+#include <ucontext.h>
+
+extern int _thr_setcontext(mcontext_t *, intptr_t, intptr_t *);
+extern int _thr_getcontext(mcontext_t *);
+
+#define KSE_STACKSIZE 16384
+#define DTV_OFFSET offsetof(struct tcb, tcb_dtv)
+
+#define THR_GETCONTEXT(ucp) _thr_getcontext(&(ucp)->uc_mcontext)
+#define THR_SETCONTEXT(ucp) _thr_setcontext(&(ucp)->uc_mcontext, 0, NULL)
+
+#define PER_KSE
+#undef PER_THREAD
+
+struct kse;
+struct pthread;
+
+/*
+ * %gs points to a struct kcb.
+ */
+struct kcb {
+ struct tcb *kcb_curtcb;
+ struct kcb *kcb_self; /* self reference */
+ struct kse *kcb_kse;
+ struct kse_mailbox kcb_kmbx;
+};
+
+struct tcb {
+ struct tcb *tcb_self; /* required by rtld */
+ void *tcb_dtv; /* required by rtld */
+ struct pthread *tcb_thread;
+ void *tcb_spare; /* align tcb_tmbx to 16 bytes */
+ struct kse_thr_mailbox tcb_tmbx;
+};
+
+/*
+ * Evaluates to the byte offset of the per-kse variable name.
+ */
+#define __kcb_offset(name) __offsetof(struct kcb, name)
+
+/*
+ * Evaluates to the type of the per-kse variable name.
+ */
+#define __kcb_type(name) __typeof(((struct kcb *)0)->name)
+
+/*
+ * Evaluates to the value of the per-kse variable name.
+ */
+#define KCB_GET32(name) ({ \
+ __kcb_type(name) __result; \
+ \
+ u_int __i; \
+ __asm __volatile("movl %%gs:%1, %0" \
+ : "=r" (__i) \
+ : "m" (*(u_int *)(__kcb_offset(name)))); \
+ __result = (__kcb_type(name))__i; \
+ \
+ __result; \
+})
+
+/*
+ * Sets the value of the per-kse variable name to value val.
+ */
+#define KCB_SET32(name, val) ({ \
+ __kcb_type(name) __val = (val); \
+ \
+ u_int __i; \
+ __i = (u_int)__val; \
+ __asm __volatile("movl %1,%%gs:%0" \
+ : "=m" (*(u_int *)(__kcb_offset(name))) \
+ : "r" (__i)); \
+})
+
+static __inline u_long
+__kcb_readandclear32(volatile u_long *addr)
+{
+ u_long result;
+
+ __asm __volatile (
+ " xorl %0, %0;"
+ " xchgl %%gs:%1, %0;"
+ "# __kcb_readandclear32"
+ : "=&r" (result)
+ : "m" (*addr));
+ return (result);
+}
+
+#define KCB_READANDCLEAR32(name) ({ \
+ __kcb_type(name) __result; \
+ \
+ __result = (__kcb_type(name)) \
+ __kcb_readandclear32((u_long *)__kcb_offset(name)); \
+ __result; \
+})
+
+
+#define _kcb_curkcb() KCB_GET32(kcb_self)
+#define _kcb_curtcb() KCB_GET32(kcb_curtcb)
+#define _kcb_curkse() ((struct kse *)KCB_GET32(kcb_kmbx.km_udata))
+#define _kcb_get_tmbx() KCB_GET32(kcb_kmbx.km_curthread)
+#define _kcb_set_tmbx(value) KCB_SET32(kcb_kmbx.km_curthread, (void *)value)
+#define _kcb_readandclear_tmbx() KCB_READANDCLEAR32(kcb_kmbx.km_curthread)
+
+
+/*
+ * The constructors.
+ */
+struct tcb *_tcb_ctor(struct pthread *, int);
+void _tcb_dtor(struct tcb *tcb);
+struct kcb *_kcb_ctor(struct kse *);
+void _kcb_dtor(struct kcb *);
+
+/* Called from the KSE to set its private data. */
+static __inline void
+_kcb_set(struct kcb *kcb)
+{
+ i386_set_gsbase(kcb);
+}
+
+/* Get the current kcb. */
+static __inline struct kcb *
+_kcb_get(void)
+{
+ return (_kcb_curkcb());
+}
+
+static __inline struct kse_thr_mailbox *
+_kcb_critical_enter(void)
+{
+ struct kse_thr_mailbox *crit;
+
+ crit = _kcb_readandclear_tmbx();
+ return (crit);
+}
+
+static __inline void
+_kcb_critical_leave(struct kse_thr_mailbox *crit)
+{
+ _kcb_set_tmbx(crit);
+}
+
+static __inline int
+_kcb_in_critical(void)
+{
+ return (_kcb_get_tmbx() == NULL);
+}
+
+static __inline void
+_tcb_set(struct kcb *kcb, struct tcb *tcb)
+{
+ kcb->kcb_curtcb = tcb;
+}
+
+static __inline struct tcb *
+_tcb_get(void)
+{
+ return (_kcb_curtcb());
+}
+
+static __inline struct pthread *
+_get_curthread(void)
+{
+ struct tcb *tcb;
+
+ tcb = _kcb_curtcb();
+ if (tcb != NULL)
+ return (tcb->tcb_thread);
+ else
+ return (NULL);
+}
+
+static __inline struct kse *
+_get_curkse(void)
+{
+ return ((struct kse *)_kcb_curkse());
+}
+
+void _i386_enter_uts(struct kse_mailbox *km, kse_func_t uts, void *stack,
+ size_t stacksz);
+
+static __inline int
+_thread_enter_uts(struct tcb *tcb, struct kcb *kcb)
+{
+ int ret;
+
+ ret = _thr_getcontext(&tcb->tcb_tmbx.tm_context.uc_mcontext);
+ if (ret == 0) {
+ _i386_enter_uts(&kcb->kcb_kmbx, kcb->kcb_kmbx.km_func,
+ kcb->kcb_kmbx.km_stack.ss_sp,
+ kcb->kcb_kmbx.km_stack.ss_size);
+ /* We should not reach here. */
+ return (-1);
+ }
+ else if (ret < 0)
+ return (-1);
+ return (0);
+}
+
+static __inline int
+_thread_switch(struct kcb *kcb, struct tcb *tcb, int setmbox)
+{
+ extern int _libkse_debug;
+
+ if ((kcb == NULL) || (tcb == NULL))
+ return (-1);
+ kcb->kcb_curtcb = tcb;
+ if (_libkse_debug == 0) {
+ tcb->tcb_tmbx.tm_lwp = kcb->kcb_kmbx.km_lwp;
+ if (setmbox != 0)
+ _thr_setcontext(&tcb->tcb_tmbx.tm_context.uc_mcontext,
+ (intptr_t)&tcb->tcb_tmbx,
+ (intptr_t *)&kcb->kcb_kmbx.km_curthread);
+ else
+ _thr_setcontext(&tcb->tcb_tmbx.tm_context.uc_mcontext,
+ 0, NULL);
+ } else {
+ if (setmbox)
+ kse_switchin(&tcb->tcb_tmbx, KSE_SWITCHIN_SETTMBX);
+ else
+ kse_switchin(&tcb->tcb_tmbx, 0);
+ }
+
+ /* We should not reach here. */
+ return (-1);
+}
+
+#endif
diff --git a/lib/libkse/arch/ia64/Makefile.inc b/lib/libkse/arch/ia64/Makefile.inc
new file mode 100644
index 0000000..c8b0362
--- /dev/null
+++ b/lib/libkse/arch/ia64/Makefile.inc
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}/${MACHINE_ARCH}
+
+SRCS+= context.S enter_uts.S pthread_md.c
diff --git a/lib/libkse/arch/ia64/ia64/context.S b/lib/libkse/arch/ia64/ia64/context.S
new file mode 100644
index 0000000..9411293
--- /dev/null
+++ b/lib/libkse/arch/ia64/ia64/context.S
@@ -0,0 +1,351 @@
+/*
+ * 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 <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/syscall.h>
+
+#define SIZEOF_SPECIAL (18*8)
+
+/*
+ * int _ia64_restore_context(mcontext_t *mc, intptr_t val, intptr_t *loc);
+ */
+ENTRY(_ia64_restore_context, 3)
+{ .mmi
+ invala
+ mov ar.rsc=0xc
+ add r32=16,r32
+ ;;
+}
+{ .mmi
+ loadrs
+ ld8 r12=[r32] // sp
+ add r31=8,r32
+ ;;
+}
+{ .mii
+ ld8 r16=[r31],16 // unat (before)
+ add r30=16,r32
+ add r14=SIZEOF_SPECIAL,r32
+ ;;
+}
+{ .mmi
+ ld8 r17=[r30],16 // rp
+ ld8 r18=[r31],16 // pr
+ mov r2=r33
+ ;;
+}
+{ .mmi
+ ld8 r19=[r30],16 // pfs
+ ld8 r20=[r31],32 // bspstore
+ mov rp=r17
+ ;;
+}
+{ .mmi
+ ld8 r21=[r30],32 // rnat
+ ld8 r22=[r31],16 // rsc
+ mov pr=r18,0x1fffe
+ ;;
+}
+{ .mmi
+ ld8 r23=[r30] // fpsr
+ ld8 r24=[r31] // psr -- not used
+ mov r3=r34
+ ;;
+}
+{ .mmi
+ ld8 r17=[r14],8 // unat (after)
+ mov ar.bspstore=r20
+ cmp.ne p15,p0=r0,r3
+ ;;
+}
+{ .mmi
+ mov ar.rnat=r21
+ mov ar.unat=r17
+ add r15=8,r14
+ ;;
+}
+{ .mmi
+ ld8.fill r4=[r14],16 // r4
+ ld8.fill r5=[r15],16 // r5
+ mov ar.pfs=r19
+ ;;
+}
+{ .mmi
+ ld8.fill r6=[r14],16 // r6
+ ld8.fill r7=[r15],16 // r7
+ nop 0
+ ;;
+}
+{ .mmi
+ mov ar.unat=r16
+ mov ar.rsc=r22
+ nop 0
+}
+{ .mmi
+ ld8 r17=[r14],16 // b1
+ ld8 r18=[r15],16 // b2
+ nop 0
+ ;;
+}
+{ .mmi
+ ld8 r19=[r14],16 // b3
+ ld8 r20=[r15],16 // b4
+ mov b1=r17
+ ;;
+}
+{ .mmi
+ ld8 r16=[r14],24 // b5
+ ld8 r17=[r15],32 // lc
+ mov b2=r18
+ ;;
+}
+{ .mmi
+ ldf.fill f2=[r14],32
+ ldf.fill f3=[r15],32
+ mov b3=r19
+ ;;
+}
+{ .mmi
+ ldf.fill f4=[r14],32
+ ldf.fill f5=[r15],32
+ mov b4=r20
+ ;;
+}
+{ .mmi
+ ldf.fill f16=[r14],32
+ ldf.fill f17=[r15],32
+ mov b5=r16
+ ;;
+}
+{ .mmi
+ ldf.fill f18=[r14],32
+ ldf.fill f19=[r15],32
+ mov ar.lc=r17
+ ;;
+}
+ ldf.fill f20=[r14],32
+ ldf.fill f21=[r15],32
+ ;;
+ ldf.fill f22=[r14],32
+ ldf.fill f23=[r15],32
+ ;;
+ ldf.fill f24=[r14],32
+ ldf.fill f25=[r15],32
+ ;;
+ ldf.fill f26=[r14],32
+ ldf.fill f27=[r15],32
+ ;;
+ ldf.fill f28=[r14],32
+ ldf.fill f29=[r15],32
+ ;;
+ ldf.fill f30=[r14],32+24
+ ldf.fill f31=[r15],24+24
+ ;;
+ ld8 r8=[r14],16
+ ld8 r9=[r15],16
+ ;;
+ ld8 r10=[r14]
+ ld8 r11=[r15]
+ ;;
+{ .mmb
+(p15) st8 [r3]=r2
+ mov ar.fpsr=r23
+ br.ret.sptk rp
+ ;;
+}
+END(_ia64_restore_context)
+
+/*
+ * int _ia64_save_context(mcontext_t *mc);
+ */
+ENTRY(_ia64_save_context, 1)
+{ .mmi
+ mov r14=ar.rsc
+ mov r15=ar.fpsr
+ add r31=8,r32
+ ;;
+}
+{ .mmi
+ st8 [r32]=r0,16
+ st8 [r31]=r0,16
+ nop 0
+ ;;
+}
+{ .mmi
+ mov ar.rsc=0xc
+ mov r16=ar.unat
+ nop 0
+ ;;
+}
+{ .mmi
+ flushrs
+ st8 [r32]=sp,16 // sp
+ mov r17=rp
+ ;;
+}
+{ .mmi
+ st8 [r31]=r16,16 // unat (before)
+ st8 [r32]=r17,16 // rp
+ mov r16=pr
+ ;;
+}
+{ .mmi
+ st8 [r31]=r16,16 // pr
+ mov r17=ar.bsp
+ mov r16=ar.pfs
+ ;;
+}
+{ .mmi
+ st8 [r32]=r16,16 // pfs
+ st8 [r31]=r17,16 // bspstore
+ nop 0
+ ;;
+}
+{ .mmi
+ mov r16=ar.rnat
+ mov ar.rsc=r14
+ add r30=SIZEOF_SPECIAL-(6*8),r32
+ ;;
+}
+{ .mmi
+ st8 [r32]=r16,16 // rnat
+ st8 [r31]=r0,16 // __spare
+ nop 0
+ ;;
+}
+{ .mmi
+ st8 [r32]=r13,16 // tp -- not used
+ st8 [r31]=r14,16 // rsc
+ mov r16=b1
+ ;;
+}
+{ .mmi
+ st8 [r32]=r15,10*8 // fpr
+ st8 [r31]=r0,8*8 // psr
+ nop 0
+ ;;
+}
+ /* callee_saved */
+{ .mmi
+ .mem.offset 8,0
+ st8.spill [r31]=r4,16 // r4
+ .mem.offset 16,0
+ st8.spill [r32]=r5,16 // r5
+ mov r17=b2
+ ;;
+}
+{ .mmi
+ .mem.offset 24,0
+ st8.spill [r31]=r6,16 // r6
+ .mem.offset 32,0
+ st8.spill [r32]=r7,16 // r7
+ mov r18=b3
+ ;;
+}
+{ .mmi
+ st8 [r31]=r16,16 // b1
+ mov r16=ar.unat
+ mov r19=b4
+ ;;
+}
+{ .mmi
+ st8 [r30]=r16 // unat (after)
+ st8 [r32]=r17,16 // b2
+ mov r16=b5
+ ;;
+}
+{ .mmi
+ st8 [r31]=r18,16 // b3
+ st8 [r32]=r19,16 // b4
+ mov r17=ar.lc
+ ;;
+}
+ st8 [r31]=r16,16 // b5
+ st8 [r32]=r17,16 // lc
+ ;;
+ st8 [r31]=r0,24 // __spare
+ stf.spill [r32]=f2,32
+ ;;
+ stf.spill [r31]=f3,32
+ stf.spill [r32]=f4,32
+ ;;
+ stf.spill [r31]=f5,32
+ stf.spill [r32]=f16,32
+ ;;
+ stf.spill [r31]=f17,32
+ stf.spill [r32]=f18,32
+ ;;
+ stf.spill [r31]=f19,32
+ stf.spill [r32]=f20,32
+ ;;
+ stf.spill [r31]=f21,32
+ stf.spill [r32]=f22,32
+ ;;
+ stf.spill [r31]=f23,32
+ stf.spill [r32]=f24,32
+ ;;
+ stf.spill [r31]=f25,32
+ stf.spill [r32]=f26,32
+ ;;
+ stf.spill [r31]=f27,32
+ stf.spill [r32]=f28,32
+ ;;
+{ .mmi
+ stf.spill [r31]=f29,32
+ stf.spill [r32]=f30,32+24
+ add r14=1,r0
+ ;;
+}
+{ .mmi
+ stf.spill [r31]=f31,24+24
+ st8 [r32]=r14,16 // r8
+ add r8=0,r0
+ ;;
+}
+ st8 [r31]=r0,16 // r9
+ st8 [r32]=r0 // r10
+ ;;
+{ .mmb
+ st8 [r31]=r0 // r11
+ mf
+ br.ret.sptk rp
+ ;;
+}
+END(_ia64_save_context)
+
+/*
+ * void _ia64_break_setcontext(mcontext_t *mc);
+ */
+ENTRY(_ia64_break_setcontext, 1)
+{ .mmi
+ mov r8=r32
+ break 0x180000
+ nop 0
+ ;;
+}
+END(_ia64_break_setcontext)
diff --git a/lib/libkse/arch/ia64/ia64/enter_uts.S b/lib/libkse/arch/ia64/ia64/enter_uts.S
new file mode 100644
index 0000000..5df4d93
--- /dev/null
+++ b/lib/libkse/arch/ia64/ia64/enter_uts.S
@@ -0,0 +1,60 @@
+/*
+ * 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 <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * void _ia64_enter_uts(kse_func_t uts, struct kse_mailbox *km, void *stack,
+ * size_t stacksz);
+ */
+ENTRY(_ia64_enter_uts, 4)
+{ .mmi
+ ld8 r14=[in0],8
+ mov ar.rsc=0xc
+ add r15=in2,in3
+ ;;
+}
+{ .mmi
+ flushrs
+ ld8 r1=[in0]
+ mov b7=r14
+ ;;
+}
+{ .mii
+ mov ar.bspstore=in2
+ add sp=-16,r15
+ mov rp=r14
+ ;;
+}
+{ .mib
+ mov ar.rsc=0xf
+ mov in0=in1
+ br.cond.sptk b7
+ ;;
+}
+1: br.cond.sptk 1b
+END(_ia64_enter_uts)
diff --git a/lib/libkse/arch/ia64/ia64/pthread_md.c b/lib/libkse/arch/ia64/ia64/pthread_md.c
new file mode 100644
index 0000000..00e9a40
--- /dev/null
+++ b/lib/libkse/arch/ia64/ia64/pthread_md.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2003 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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, 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$
+ */
+
+#include <stdlib.h>
+#include <strings.h>
+#include "pthread_md.h"
+
+/*
+ * The constructors.
+ */
+struct tcb *
+_tcb_ctor(struct pthread *thread, int initial)
+{
+ struct tcb *tcb;
+
+ if ((tcb = malloc(sizeof(struct tcb))) != NULL) {
+ bzero(tcb, sizeof(struct tcb));
+ tcb->tcb_thread = thread;
+ /* Allocate TDV */
+ }
+ return (tcb);
+}
+
+void
+_tcb_dtor(struct tcb *tcb)
+{
+ /* Free TDV */
+ free(tcb);
+}
+
+struct kcb *
+_kcb_ctor(struct kse *kse)
+{
+ struct kcb *kcb;
+
+ if ((kcb = malloc(sizeof(struct kcb))) != NULL) {
+ bzero(kcb, sizeof(struct kcb));
+ kcb->kcb_faketcb.tcb_isfake = 1;
+ kcb->kcb_faketcb.tcb_tmbx.tm_flags = TMF_NOUPCALL;
+ kcb->kcb_curtcb = &kcb->kcb_faketcb;
+ kcb->kcb_kse = kse;
+ }
+ return (kcb);
+}
+
+void
+_kcb_dtor(struct kcb *kcb)
+{
+ free(kcb);
+}
diff --git a/lib/libkse/arch/ia64/include/atomic_ops.h b/lib/libkse/arch/ia64/include/atomic_ops.h
new file mode 100644
index 0000000..483c905
--- /dev/null
+++ b/lib/libkse/arch/ia64/include/atomic_ops.h
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _ATOMIC_OPS_H_
+#define _ATOMIC_OPS_H_
+
+static inline void
+atomic_swap_int(int *dst, int val, int *res)
+{
+ __asm("xchg4 %0=[%2],%1" : "=r"(*res) : "r"(val), "r"(dst));
+}
+
+static inline void
+atomic_swap_long(long *dst, long val, long *res)
+{
+ __asm("xchg8 %0=[%2],%1" : "=r"(*res) : "r"(val), "r"(dst));
+}
+
+#define atomic_swap_ptr(d,v,r) \
+ atomic_swap_long((long*)d, (long)v, (long*)r)
+
+#endif /* _ATOMIC_OPS_H_ */
diff --git a/lib/libkse/arch/ia64/include/pthread_md.h b/lib/libkse/arch/ia64/include/pthread_md.h
new file mode 100644
index 0000000..1df5046
--- /dev/null
+++ b/lib/libkse/arch/ia64/include/pthread_md.h
@@ -0,0 +1,252 @@
+/*
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _PTHREAD_MD_H_
+#define _PTHREAD_MD_H_
+
+#include <sys/kse.h>
+#include <stddef.h>
+#include <ucontext.h>
+
+#define KSE_STACKSIZE 16384
+#define DTV_OFFSET offsetof(struct tcb, tcb_tp.tp_tdv)
+
+#define THR_GETCONTEXT(ucp) _ia64_save_context(&(ucp)->uc_mcontext)
+#define THR_SETCONTEXT(ucp) PANIC("THR_SETCONTEXT() now in use!\n")
+
+#define PER_THREAD
+
+struct kcb;
+struct kse;
+struct pthread;
+struct tcb;
+struct tdv; /* We don't know what this is yet? */
+
+/*
+ * tp points to one of these. We define the static TLS as an array
+ * of long double to enforce 16-byte alignment of the TLS memory,
+ * struct ia64_tp, struct tcb and also struct kcb. Both static and
+ * dynamic allocation of any of these structures will result in a
+ * valid, well-aligned thread pointer.
+ */
+struct ia64_tp {
+ struct tdv *tp_tdv; /* dynamic TLS */
+ uint64_t _reserved_;
+ long double tp_tls[0]; /* static TLS */
+};
+
+struct tcb {
+ struct kse_thr_mailbox tcb_tmbx;
+ struct pthread *tcb_thread;
+ struct kcb *tcb_curkcb;
+ long tcb_isfake;
+ struct ia64_tp tcb_tp;
+};
+
+struct kcb {
+ struct kse_mailbox kcb_kmbx;
+ struct tcb kcb_faketcb;
+ struct tcb *kcb_curtcb;
+ struct kse *kcb_kse;
+};
+
+register struct ia64_tp *_tp __asm("%r13");
+
+#define _tcb ((struct tcb*)((char*)(_tp) - offsetof(struct tcb, tcb_tp)))
+
+/*
+ * The kcb and tcb constructors.
+ */
+struct tcb *_tcb_ctor(struct pthread *, int);
+void _tcb_dtor(struct tcb *);
+struct kcb *_kcb_ctor(struct kse *kse);
+void _kcb_dtor(struct kcb *);
+
+/* Called from the KSE to set its private data. */
+static __inline void
+_kcb_set(struct kcb *kcb)
+{
+ /* There is no thread yet; use the fake tcb. */
+ _tp = &kcb->kcb_faketcb.tcb_tp;
+}
+
+/*
+ * Get the current kcb.
+ *
+ * This can only be called while in a critical region; don't
+ * worry about having the kcb changed out from under us.
+ */
+static __inline struct kcb *
+_kcb_get(void)
+{
+ return (_tcb->tcb_curkcb);
+}
+
+/*
+ * Enter a critical region.
+ *
+ * Read and clear km_curthread in the kse mailbox.
+ */
+static __inline struct kse_thr_mailbox *
+_kcb_critical_enter(void)
+{
+ struct kse_thr_mailbox *crit;
+ uint32_t flags;
+
+ if (_tcb->tcb_isfake != 0) {
+ /*
+ * We already are in a critical region since
+ * there is no current thread.
+ */
+ crit = NULL;
+ } else {
+ flags = _tcb->tcb_tmbx.tm_flags;
+ _tcb->tcb_tmbx.tm_flags |= TMF_NOUPCALL;
+ crit = _tcb->tcb_curkcb->kcb_kmbx.km_curthread;
+ _tcb->tcb_curkcb->kcb_kmbx.km_curthread = NULL;
+ _tcb->tcb_tmbx.tm_flags = flags;
+ }
+ return (crit);
+}
+
+static __inline void
+_kcb_critical_leave(struct kse_thr_mailbox *crit)
+{
+ /* No need to do anything if this is a fake tcb. */
+ if (_tcb->tcb_isfake == 0)
+ _tcb->tcb_curkcb->kcb_kmbx.km_curthread = crit;
+}
+
+static __inline int
+_kcb_in_critical(void)
+{
+ uint32_t flags;
+ int ret;
+
+ if (_tcb->tcb_isfake != 0) {
+ /*
+ * We are in a critical region since there is no
+ * current thread.
+ */
+ ret = 1;
+ } else {
+ flags = _tcb->tcb_tmbx.tm_flags;
+ _tcb->tcb_tmbx.tm_flags |= TMF_NOUPCALL;
+ ret = (_tcb->tcb_curkcb->kcb_kmbx.km_curthread == NULL);
+ _tcb->tcb_tmbx.tm_flags = flags;
+ }
+ return (ret);
+}
+
+static __inline void
+_tcb_set(struct kcb *kcb, struct tcb *tcb)
+{
+ if (tcb == NULL)
+ tcb = &kcb->kcb_faketcb;
+ kcb->kcb_curtcb = tcb;
+ tcb->tcb_curkcb = kcb;
+ _tp = &tcb->tcb_tp;
+}
+
+static __inline struct tcb *
+_tcb_get(void)
+{
+ return (_tcb);
+}
+
+static __inline struct pthread *
+_get_curthread(void)
+{
+ return (_tcb->tcb_thread);
+}
+
+/*
+ * Get the current kse.
+ *
+ * Like _kcb_get(), this can only be called while in a critical region.
+ */
+static __inline struct kse *
+_get_curkse(void)
+{
+ return (_tcb->tcb_curkcb->kcb_kse);
+}
+
+void _ia64_break_setcontext(mcontext_t *mc);
+void _ia64_enter_uts(kse_func_t uts, struct kse_mailbox *km, void *stack,
+ size_t stacksz);
+int _ia64_restore_context(mcontext_t *mc, intptr_t val, intptr_t *loc);
+int _ia64_save_context(mcontext_t *mc);
+
+static __inline int
+_thread_enter_uts(struct tcb *tcb, struct kcb *kcb)
+{
+ if (_ia64_save_context(&tcb->tcb_tmbx.tm_context.uc_mcontext) == 0) {
+ /* Make the fake tcb the current thread. */
+ kcb->kcb_curtcb = &kcb->kcb_faketcb;
+ _tp = &kcb->kcb_faketcb.tcb_tp;
+ _ia64_enter_uts(kcb->kcb_kmbx.km_func, &kcb->kcb_kmbx,
+ kcb->kcb_kmbx.km_stack.ss_sp,
+ kcb->kcb_kmbx.km_stack.ss_size);
+ /* We should not reach here. */
+ return (-1);
+ }
+ return (0);
+}
+
+static __inline int
+_thread_switch(struct kcb *kcb, struct tcb *tcb, int setmbox)
+{
+ mcontext_t *mc;
+
+ _tcb_set(kcb, tcb);
+ mc = &tcb->tcb_tmbx.tm_context.uc_mcontext;
+ if (mc->mc_flags & _MC_FLAGS_ASYNC_CONTEXT) {
+ if (setmbox) {
+ mc->mc_flags |= _MC_FLAGS_KSE_SET_MBOX;
+ mc->mc_special.ifa =
+ (intptr_t)&kcb->kcb_kmbx.km_curthread;
+ mc->mc_special.isr = (intptr_t)&tcb->tcb_tmbx;
+ }
+ _ia64_break_setcontext(mc);
+ } else if (mc->mc_flags & _MC_FLAGS_SYSCALL_CONTEXT) {
+ if (setmbox)
+ kse_switchin(&tcb->tcb_tmbx, KSE_SWITCHIN_SETTMBX);
+ else
+ kse_switchin(&tcb->tcb_tmbx, 0);
+ } else {
+ if (setmbox)
+ _ia64_restore_context(mc, (intptr_t)&tcb->tcb_tmbx,
+ (intptr_t *)&kcb->kcb_kmbx.km_curthread);
+ else
+ _ia64_restore_context(mc, 0, NULL);
+ }
+ /* We should not reach here. */
+ return (-1);
+}
+
+#endif /* _PTHREAD_MD_H_ */
diff --git a/lib/libkse/arch/powerpc/Makefile.inc b/lib/libkse/arch/powerpc/Makefile.inc
new file mode 100644
index 0000000..f4417a6
--- /dev/null
+++ b/lib/libkse/arch/powerpc/Makefile.inc
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+# XXX temporary
+CFLAGS+=-DSYSTEM_SCOPE_ONLY
+
+.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}/${MACHINE_ARCH}
+
+SRCS+= enter_uts.S context.S pthread_md.c
diff --git a/lib/libkse/arch/powerpc/include/atomic_ops.h b/lib/libkse/arch/powerpc/include/atomic_ops.h
new file mode 100644
index 0000000..8068e6f
--- /dev/null
+++ b/lib/libkse/arch/powerpc/include/atomic_ops.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2004 by 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.
+ * 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$
+ */
+
+#ifndef _ATOMIC_OPS_H_
+#define _ATOMIC_OPS_H_
+
+/*
+ * Atomic swap:
+ * Atomic (tmp = *dst, *dst = val), then *res = tmp
+ *
+ * void atomic_swap32(intptr_t *dst, intptr_t val, intptr_t *res);
+ */
+static inline void
+atomic_swap32(intptr_t *dst, intptr_t val, intptr_t *res)
+{
+ int tmp;
+
+ tmp = 0; /* should be a better way to quieten cc1... */
+#ifdef __GNUC__
+ __asm __volatile(
+ "1: lwarx %0, 0, %4\n" /* load with reservation */
+ " stwcx. %3, 0, %4\n" /* attempt to store val */
+ " bne- 1b\n" /* interrupted? retry */
+ " stw %0, %1\n" /* else, *dst -> *res */
+ : "=&r" (tmp), "=m" (*res), "+m" (*dst)
+ : "r" (val), "r" (dst)
+ : "cc", "memory");
+#endif
+}
+
+#define atomic_swap_ptr(d, v, r) \
+ atomic_swap32((intptr_t *)d, (intptr_t)v, (intptr_t *)r)
+
+#define atomic_swap_int(d, v, r) \
+ atomic_swap32((intptr_t *)d, (intptr_t)v, (intptr_t *)r)
+#endif
diff --git a/lib/libkse/arch/powerpc/include/pthread_md.h b/lib/libkse/arch/powerpc/include/pthread_md.h
new file mode 100644
index 0000000..33a58b5
--- /dev/null
+++ b/lib/libkse/arch/powerpc/include/pthread_md.h
@@ -0,0 +1,258 @@
+/*
+ * Copyright 2004 by 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.
+ * 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$
+ */
+
+/*
+ * Machine-dependent thread prototypes/definitions for the thread kernel.
+ */
+#ifndef _PTHREAD_MD_H_
+#define _PTHREAD_MD_H_
+
+#include <sys/kse.h>
+#include <stddef.h>
+#include <ucontext.h>
+
+extern void _ppc32_enter_uts(struct kse_mailbox *, kse_func_t, void *, size_t);
+extern int _ppc32_setcontext(mcontext_t *, intptr_t, intptr_t *);
+extern int _ppc32_getcontext(mcontext_t *);
+
+#define KSE_STACKSIZE 16384
+#define DTV_OFFSET offsetof(struct tcb, tcb_tp.tp_tdv)
+
+#define THR_GETCONTEXT(ucp) _ppc32_getcontext(&(ucp)->uc_mcontext)
+#define THR_SETCONTEXT(ucp) _ppc32_setcontext(&(ucp)->uc_mcontext, 0, NULL)
+
+#define PER_THREAD
+
+struct kcb;
+struct kse;
+struct pthread;
+struct tcb;
+struct tdv;
+
+/*
+ * %r2 points to a struct kcb.
+ */
+struct ppc32_tp {
+ struct tdv *tp_tdv; /* dynamic TLS */
+ uint32_t _reserved_;
+ long double tp_tls[0]; /* static TLS */
+};
+
+struct tcb {
+ struct kse_thr_mailbox tcb_tmbx;
+ struct pthread *tcb_thread;
+ struct kcb *tcb_curkcb;
+ long tcb_isfake;
+ struct ppc32_tp tcb_tp;
+};
+
+struct kcb {
+ struct kse_mailbox kcb_kmbx;
+ struct tcb kcb_faketcb;
+ struct tcb *kcb_curtcb;
+ struct kse *kcb_kse;
+};
+
+/*
+ * From the PowerPC32 TLS spec:
+ *
+ * "r2 is the thread pointer, and points 0x7000 past the end of the
+ * thread control block." Or, 0x7008 past the start of the 8-byte tcb
+ */
+#define TP_OFFSET 0x7008
+register uint8_t *_tpr __asm("%r2");
+
+#define _tcb ((struct tcb *)(_tpr - TP_OFFSET - offsetof(struct tcb, tcb_tp)))
+
+/*
+ * The kcb and tcb constructors.
+ */
+struct tcb *_tcb_ctor(struct pthread *, int);
+void _tcb_dtor(struct tcb *);
+struct kcb *_kcb_ctor(struct kse *kse);
+void _kcb_dtor(struct kcb *);
+
+/* Called from the KSE to set its private data. */
+static __inline void
+_kcb_set(struct kcb *kcb)
+{
+ /* There is no thread yet; use the fake tcb. */
+ _tpr = (uint8_t *)&kcb->kcb_faketcb.tcb_tp + TP_OFFSET;
+}
+
+/*
+ * Get the current kcb.
+ *
+ * This can only be called while in a critical region; don't
+ * worry about having the kcb changed out from under us.
+ */
+static __inline struct kcb *
+_kcb_get(void)
+{
+ return (_tcb->tcb_curkcb);
+}
+
+/*
+ * Enter a critical region.
+ *
+ * Read and clear km_curthread in the kse mailbox.
+ */
+static __inline struct kse_thr_mailbox *
+_kcb_critical_enter(void)
+{
+ struct kse_thr_mailbox *crit;
+ uint32_t flags;
+
+ if (_tcb->tcb_isfake != 0) {
+ /*
+ * We already are in a critical region since
+ * there is no current thread.
+ */
+ crit = NULL;
+ } else {
+ flags = _tcb->tcb_tmbx.tm_flags;
+ _tcb->tcb_tmbx.tm_flags |= TMF_NOUPCALL;
+ crit = _tcb->tcb_curkcb->kcb_kmbx.km_curthread;
+ _tcb->tcb_curkcb->kcb_kmbx.km_curthread = NULL;
+ _tcb->tcb_tmbx.tm_flags = flags;
+ }
+ return (crit);
+}
+
+static __inline void
+_kcb_critical_leave(struct kse_thr_mailbox *crit)
+{
+ /* No need to do anything if this is a fake tcb. */
+ if (_tcb->tcb_isfake == 0)
+ _tcb->tcb_curkcb->kcb_kmbx.km_curthread = crit;
+}
+
+static __inline int
+_kcb_in_critical(void)
+{
+ uint32_t flags;
+ int ret;
+
+ if (_tcb->tcb_isfake != 0) {
+ /*
+ * We are in a critical region since there is no
+ * current thread.
+ */
+ ret = 1;
+ } else {
+ flags = _tcb->tcb_tmbx.tm_flags;
+ _tcb->tcb_tmbx.tm_flags |= TMF_NOUPCALL;
+ ret = (_tcb->tcb_curkcb->kcb_kmbx.km_curthread == NULL);
+ _tcb->tcb_tmbx.tm_flags = flags;
+ }
+ return (ret);
+}
+
+static __inline void
+_tcb_set(struct kcb *kcb, struct tcb *tcb)
+{
+ if (tcb == NULL)
+ tcb = &kcb->kcb_faketcb;
+ kcb->kcb_curtcb = tcb;
+ tcb->tcb_curkcb = kcb;
+ _tpr = (uint8_t *)&tcb->tcb_tp + TP_OFFSET;
+}
+
+static __inline struct tcb *
+_tcb_get(void)
+{
+ return (_tcb);
+}
+
+static __inline struct pthread *
+_get_curthread(void)
+{
+ return (_tcb->tcb_thread);
+}
+
+/*
+ * Get the current kse.
+ *
+ * Like _kcb_get(), this can only be called while in a critical region.
+ */
+static __inline struct kse *
+_get_curkse(void)
+{
+ return (_tcb->tcb_curkcb->kcb_kse);
+}
+
+static __inline int
+_thread_enter_uts(struct tcb *tcb, struct kcb *kcb)
+{
+ if (_ppc32_getcontext(&tcb->tcb_tmbx.tm_context.uc_mcontext) == 0) {
+ /* Make the fake tcb the current thread. */
+ kcb->kcb_curtcb = &kcb->kcb_faketcb;
+ _tpr = (uint8_t *)&kcb->kcb_faketcb.tcb_tp + TP_OFFSET;
+ _ppc32_enter_uts(&kcb->kcb_kmbx, kcb->kcb_kmbx.km_func,
+ kcb->kcb_kmbx.km_stack.ss_sp,
+ kcb->kcb_kmbx.km_stack.ss_size - 32);
+ /* We should not reach here. */
+ return (-1);
+ }
+ return (0);
+}
+
+static __inline int
+_thread_switch(struct kcb *kcb, struct tcb *tcb, int setmbox)
+{
+ mcontext_t *mc;
+ extern int _libkse_debug;
+
+ _tcb_set(kcb, tcb);
+ mc = &tcb->tcb_tmbx.tm_context.uc_mcontext;
+
+ /*
+ * A full context needs a system call to restore, so use
+ * kse_switchin. Otherwise, the partial context can be
+ * restored with _ppc32_setcontext
+ */
+ if (mc->mc_vers != _MC_VERSION_KSE && _libkse_debug != 0) {
+ if (setmbox)
+ kse_switchin(&tcb->tcb_tmbx, KSE_SWITCHIN_SETTMBX);
+ else
+ kse_switchin(&tcb->tcb_tmbx, 0);
+ } else {
+ tcb->tcb_tmbx.tm_lwp = kcb->kcb_kmbx.km_lwp;
+ if (setmbox)
+ _ppc32_setcontext(mc, (intptr_t)&tcb->tcb_tmbx,
+ (intptr_t *)&kcb->kcb_kmbx.km_curthread);
+ else
+ _ppc32_setcontext(mc, 0, NULL);
+ }
+
+ /* We should not reach here. */
+ return (-1);
+}
+
+#endif /* _PTHREAD_MD_H_ */
diff --git a/lib/libkse/arch/powerpc/powerpc/assym.c b/lib/libkse/arch/powerpc/powerpc/assym.c
new file mode 100644
index 0000000..a8479e7
--- /dev/null
+++ b/lib/libkse/arch/powerpc/powerpc/assym.c
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+/* Used to generate mcontext_t offsets */
+
+#include <sys/types.h>
+#include <sys/assym.h>
+#include <sys/ucontext.h>
+
+#include <stddef.h>
+
+ASSYM(_MC_VERSION, _MC_VERSION);
+ASSYM(_MC_VERSION_KSE, _MC_VERSION_KSE);
+ASSYM(_MC_FP_VALID, _MC_FP_VALID);
+
+ASSYM(_MC_VERS, offsetof(mcontext_t, mc_vers));
+ASSYM(_MC_FLAGS, offsetof(mcontext_t, mc_flags));
+
+ASSYM(_MC_R0, offsetof(mcontext_t, mc_frame[0]));
+ASSYM(_MC_R1, offsetof(mcontext_t, mc_frame[1]));
+ASSYM(_MC_R2, offsetof(mcontext_t, mc_frame[2]));
+ASSYM(_MC_R3, offsetof(mcontext_t, mc_frame[3]));
+ASSYM(_MC_R4, offsetof(mcontext_t, mc_frame[4]));
+ASSYM(_MC_R5, offsetof(mcontext_t, mc_frame[5]));
+ASSYM(_MC_R6, offsetof(mcontext_t, mc_frame[6]));
+ASSYM(_MC_R7, offsetof(mcontext_t, mc_frame[7]));
+ASSYM(_MC_R8, offsetof(mcontext_t, mc_frame[8]));
+ASSYM(_MC_R9, offsetof(mcontext_t, mc_frame[9]));
+ASSYM(_MC_R10, offsetof(mcontext_t, mc_frame[10]));
+ASSYM(_MC_R11, offsetof(mcontext_t, mc_frame[11]));
+ASSYM(_MC_R12, offsetof(mcontext_t, mc_frame[12]));
+ASSYM(_MC_R13, offsetof(mcontext_t, mc_frame[13]));
+ASSYM(_MC_R14, offsetof(mcontext_t, mc_frame[14]));
+ASSYM(_MC_R15, offsetof(mcontext_t, mc_frame[15]));
+ASSYM(_MC_R16, offsetof(mcontext_t, mc_frame[16]));
+ASSYM(_MC_R17, offsetof(mcontext_t, mc_frame[17]));
+ASSYM(_MC_R18, offsetof(mcontext_t, mc_frame[18]));
+ASSYM(_MC_R19, offsetof(mcontext_t, mc_frame[19]));
+ASSYM(_MC_R20, offsetof(mcontext_t, mc_frame[20]));
+ASSYM(_MC_R21, offsetof(mcontext_t, mc_frame[21]));
+ASSYM(_MC_R22, offsetof(mcontext_t, mc_frame[22]));
+ASSYM(_MC_R23, offsetof(mcontext_t, mc_frame[23]));
+ASSYM(_MC_R24, offsetof(mcontext_t, mc_frame[24]));
+ASSYM(_MC_R25, offsetof(mcontext_t, mc_frame[25]));
+ASSYM(_MC_R26, offsetof(mcontext_t, mc_frame[26]));
+ASSYM(_MC_R27, offsetof(mcontext_t, mc_frame[27]));
+ASSYM(_MC_R28, offsetof(mcontext_t, mc_frame[28]));
+ASSYM(_MC_R29, offsetof(mcontext_t, mc_frame[29]));
+ASSYM(_MC_R30, offsetof(mcontext_t, mc_frame[30]));
+ASSYM(_MC_R31, offsetof(mcontext_t, mc_frame[31]));
+ASSYM(_MC_LR, offsetof(mcontext_t, mc_frame[32]));
+ASSYM(_MC_CR, offsetof(mcontext_t, mc_frame[33]));
+ASSYM(_MC_XER, offsetof(mcontext_t, mc_frame[34]));
+ASSYM(_MC_CTR, offsetof(mcontext_t, mc_frame[35]));
+
+ASSYM(_MC_FPSCR, offsetof(mcontext_t, mc_fpreg[32]));
+ASSYM(_MC_F0, offsetof(mcontext_t, mc_fpreg[0]));
+ASSYM(_MC_F1, offsetof(mcontext_t, mc_fpreg[1]));
+ASSYM(_MC_F2, offsetof(mcontext_t, mc_fpreg[2]));
+ASSYM(_MC_F3, offsetof(mcontext_t, mc_fpreg[3]));
+ASSYM(_MC_F4, offsetof(mcontext_t, mc_fpreg[4]));
+ASSYM(_MC_F5, offsetof(mcontext_t, mc_fpreg[5]));
+ASSYM(_MC_F6, offsetof(mcontext_t, mc_fpreg[6]));
+ASSYM(_MC_F7, offsetof(mcontext_t, mc_fpreg[7]));
+ASSYM(_MC_F8, offsetof(mcontext_t, mc_fpreg[8]));
+ASSYM(_MC_F9, offsetof(mcontext_t, mc_fpreg[9]));
+ASSYM(_MC_F10, offsetof(mcontext_t, mc_fpreg[10]));
+ASSYM(_MC_F11, offsetof(mcontext_t, mc_fpreg[11]));
+ASSYM(_MC_F12, offsetof(mcontext_t, mc_fpreg[12]));
+ASSYM(_MC_F13, offsetof(mcontext_t, mc_fpreg[13]));
+ASSYM(_MC_F14, offsetof(mcontext_t, mc_fpreg[14]));
+ASSYM(_MC_F15, offsetof(mcontext_t, mc_fpreg[15]));
+ASSYM(_MC_F16, offsetof(mcontext_t, mc_fpreg[16]));
+ASSYM(_MC_F17, offsetof(mcontext_t, mc_fpreg[17]));
+ASSYM(_MC_F18, offsetof(mcontext_t, mc_fpreg[18]));
+ASSYM(_MC_F19, offsetof(mcontext_t, mc_fpreg[19]));
+ASSYM(_MC_F20, offsetof(mcontext_t, mc_fpreg[20]));
+ASSYM(_MC_F21, offsetof(mcontext_t, mc_fpreg[21]));
+ASSYM(_MC_F22, offsetof(mcontext_t, mc_fpreg[22]));
+ASSYM(_MC_F23, offsetof(mcontext_t, mc_fpreg[23]));
+ASSYM(_MC_F24, offsetof(mcontext_t, mc_fpreg[24]));
+ASSYM(_MC_F25, offsetof(mcontext_t, mc_fpreg[25]));
+ASSYM(_MC_F26, offsetof(mcontext_t, mc_fpreg[26]));
+ASSYM(_MC_F27, offsetof(mcontext_t, mc_fpreg[27]));
+ASSYM(_MC_F28, offsetof(mcontext_t, mc_fpreg[28]));
+ASSYM(_MC_F29, offsetof(mcontext_t, mc_fpreg[29]));
+ASSYM(_MC_F30, offsetof(mcontext_t, mc_fpreg[30]));
+ASSYM(_MC_F31, offsetof(mcontext_t, mc_fpreg[31]));
diff --git a/lib/libkse/arch/powerpc/powerpc/assym.s b/lib/libkse/arch/powerpc/powerpc/assym.s
new file mode 100644
index 0000000..7017c15
--- /dev/null
+++ b/lib/libkse/arch/powerpc/powerpc/assym.s
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Struct offsets for version 0x1 of the mcontext struct.
+ * Generated with
+ * cc -c assym.c
+ * ${SYSSRC}/kern/genassym.sh assym.o > assym_syms.s
+ * hand-edit output
+ */
+#define _MC_VERSION 0x1
+#define _MC_VERSION_KSE 0xee
+#define _MC_FP_VALID 0x1
+
+#define _MC_VERS 0x0
+#define _MC_FLAGS 0x4
+
+#define _MC_R0 0x298
+#define _MC_R1 0x21c
+#define _MC_R2 0x220
+#define _MC_R3 0x224
+#define _MC_R4 0x228
+#define _MC_R5 0x22c
+#define _MC_R6 0x230
+#define _MC_R7 0x234
+#define _MC_R8 0x238
+#define _MC_R9 0x23c
+#define _MC_R10 0x240
+#define _MC_R11 0x244
+#define _MC_R12 0x248
+#define _MC_R13 0x24c
+#define _MC_R14 0x250
+#define _MC_R15 0x254
+#define _MC_R16 0x258
+#define _MC_R17 0x25c
+#define _MC_R18 0x260
+#define _MC_R19 0x264
+#define _MC_R20 0x268
+#define _MC_R21 0x26c
+#define _MC_R22 0x270
+#define _MC_R23 0x274
+#define _MC_R24 0x278
+#define _MC_R25 0x27c
+#define _MC_R26 0x280
+#define _MC_R27 0x284
+#define _MC_R28 0x288
+#define _MC_R29 0x28c
+#define _MC_R30 0x290
+#define _MC_R31 0x294
+#define _MC_LR 0x298
+#define _MC_CR 0x29c
+#define _MC_XER 0x2a0
+#define _MC_CTR 0x2a4
+
+#define _MC_FPSCR 0x3c0
+#define _MC_F0 0x2c0
+#define _MC_F1 0x2c8
+#define _MC_F2 0x2d0
+#define _MC_F3 0x2d8
+#define _MC_F4 0x2e0
+#define _MC_F5 0x2e8
+#define _MC_F6 0x2f0
+#define _MC_F7 0x2f8
+#define _MC_F8 0x300
+#define _MC_F9 0x308
+#define _MC_F10 0x310
+#define _MC_F11 0x318
+#define _MC_F12 0x320
+#define _MC_F13 0x328
+#define _MC_F14 0x330
+#define _MC_F15 0x338
+#define _MC_F16 0x340
+#define _MC_F17 0x348
+#define _MC_F18 0x350
+#define _MC_F19 0x358
+#define _MC_F20 0x360
+#define _MC_F21 0x368
+#define _MC_F22 0x370
+#define _MC_F23 0x378
+#define _MC_F24 0x380
+#define _MC_F25 0x388
+#define _MC_F26 0x390
+#define _MC_F27 0x398
+#define _MC_F28 0x3a0
+#define _MC_F29 0x3a8
+#define _MC_F30 0x3b0
+#define _MC_F31 0x3b8
+
diff --git a/lib/libkse/arch/powerpc/powerpc/context.S b/lib/libkse/arch/powerpc/powerpc/context.S
new file mode 100644
index 0000000..34d175a
--- /dev/null
+++ b/lib/libkse/arch/powerpc/powerpc/context.S
@@ -0,0 +1,151 @@
+/*
+ * 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$");
+
+#include "assym.s"
+
+/*
+ * int _ppc32_getcontext(mcontext_t *mcp)
+ *
+ * Save register state from a voluntary context switch.
+ * Only volatile registers, and those needed to complete
+ * a setcontext call, need to be saved.
+ *
+ * r1
+ * r14-31
+ * f14-31 XXX
+ * lr
+ *
+ * Return 0 for this call, and set up the context so it will return
+ * 1 when restored with _ppc32_setcontext().
+ *
+ * XXX XXX
+ * Floating-point is a big issue. Since there's no way to determine
+ * if the caller has used FP, all volatile register need to be saved.
+ * If FP hasn't been used, this results in a lazy FP exception in
+ * the kernel and from that point on FP is always switched in/out
+ * for the thread, which may be a big performance drag for the system.
+ * An alternative is to use a system call to get the context, which
+ * will do the right thing for floating point, but will save all
+ * registers rather than the caller-saved subset, and has the overhead
+ * of a syscall.
+ * Maybe another option would be to give a light-weight way for a
+ * thread to determine if FP is in used: perhaps a syscall that
+ * returns in the asm traphandler, or an OSX-style read-only page
+ * with a flag to indicate FP state.
+ *
+ * For now, punt the issue ala Alpha 1:1 model and fix in the future.
+ */
+ENTRY(_ppc32_getcontext)
+ stw %r1, _MC_R1(%r3)
+ stw %r13, _MC_R13(%r3)
+ stw %r14, _MC_R14(%r3)
+ stw %r15, _MC_R15(%r3)
+ stw %r16, _MC_R16(%r3)
+ stw %r17, _MC_R17(%r3)
+ stw %r18, _MC_R18(%r3)
+ stw %r19, _MC_R19(%r3)
+ stw %r20, _MC_R20(%r3)
+ stw %r21, _MC_R21(%r3)
+ stw %r22, _MC_R22(%r3)
+ stw %r23, _MC_R23(%r3)
+ stw %r24, _MC_R24(%r3)
+ stw %r25, _MC_R25(%r3)
+ stw %r26, _MC_R26(%r3)
+ stw %r27, _MC_R27(%r3)
+ stw %r28, _MC_R28(%r3)
+ stw %r29, _MC_R28(%r3)
+ stw %r30, _MC_R30(%r3)
+ stw %r31, _MC_R31(%r3)
+ mflr %r4
+ stw %r4, _MC_LR(%r3)
+ mfcr %r4
+ stw %r4, _MC_CR(%r3)
+
+ /* XXX f14-31 ? */
+
+ li %r4, _MC_VERSION_KSE /* partial ucontext version */
+ stw %r4, _MC_VERS(%r3)
+
+ /* Return 0 */
+ li %r3, 0
+ blr
+
+/*
+ * int _ppc32_setcontext(const mcontext_t *mcp, intptr_t val,
+ * intptr_t *loc);
+ *
+ * Should only be called for partial KSE contexts. The full context
+ * case is handled by kse_switchin() in _thread_switch()
+ *
+ * Returns -1 on error and 1 for return from a saved context
+ */
+
+ENTRY(_ppc32_setcontext)
+ lwz %r6, _MC_VERS(%r3)
+ cmpwi %r6, _MC_VERSION_KSE /* KSE partial context ? */
+ beq 1f
+ li %r3, -1 /* invalid context type, return -1 */
+ blr
+
+1: /* partial format, callee-saved regs assumed */
+ lwz %r1, _MC_R1(%r3)
+ lwz %r13, _MC_R13(%r3)
+ lwz %r14, _MC_R14(%r3)
+ lwz %r15, _MC_R15(%r3)
+ lwz %r16, _MC_R16(%r3)
+ lwz %r17, _MC_R17(%r3)
+ lwz %r18, _MC_R18(%r3)
+ lwz %r19, _MC_R19(%r3)
+ lwz %r20, _MC_R20(%r3)
+ lwz %r21, _MC_R21(%r3)
+ lwz %r22, _MC_R22(%r3)
+ lwz %r23, _MC_R23(%r3)
+ lwz %r24, _MC_R24(%r3)
+ lwz %r25, _MC_R25(%r3)
+ lwz %r26, _MC_R26(%r3)
+ lwz %r27, _MC_R27(%r3)
+ lwz %r28, _MC_R28(%r3)
+ lwz %r29, _MC_R28(%r3)
+ lwz %r30, _MC_R30(%r3)
+ lwz %r31, _MC_R31(%r3)
+ lwz %r6, _MC_LR(%r3)
+ mtlr %r6
+ lwz %r6, _MC_CR(%r3)
+ mtcr %r6
+
+ /* XXX f14-31 ? */
+
+ /* if (loc != NULL) *loc = val */
+ cmpwi %r5, 0
+ beq 2f
+ stw %r4, 0(%r5)
+
+ /* Return 1 */
+2: li %r3, 1
+ blr
diff --git a/lib/libkse/arch/powerpc/powerpc/enter_uts.S b/lib/libkse/arch/powerpc/powerpc/enter_uts.S
new file mode 100644
index 0000000..7cc4d7f
--- /dev/null
+++ b/lib/libkse/arch/powerpc/powerpc/enter_uts.S
@@ -0,0 +1,40 @@
+/*
+ * 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$");
+
+/*
+ * _ppc32_enter_uts(struct kse_mailbox *km, kse_func_t uts, void *stack,
+ * long stacksz);
+ *
+ * Call (*uts)(km) on the requested stack. This function doesn't
+ * return. The km parameter stays in %r3.
+ */
+ENTRY(_ppc32_enter_uts)
+ add %r1,%r5,%r6 /* new stack = stack + stacksz */
+ mtlr %r4 /* link register = uts */
+ blrl /* (*uts)(km) */
diff --git a/lib/libkse/arch/powerpc/powerpc/pthread_md.c b/lib/libkse/arch/powerpc/powerpc/pthread_md.c
new file mode 100644
index 0000000..c8445b1
--- /dev/null
+++ b/lib/libkse/arch/powerpc/powerpc/pthread_md.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2003 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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, 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 <strings.h>
+#include "pthread_md.h"
+
+/*
+ * The constructors.
+ */
+struct tcb *
+_tcb_ctor(struct pthread *thread, int initial)
+{
+ struct tcb *tcb;
+
+ if ((tcb = malloc(sizeof(struct tcb))) != NULL) {
+ bzero(tcb, sizeof(struct tcb));
+ tcb->tcb_thread = thread;
+ /* Allocate TDV */
+ }
+ return (tcb);
+}
+
+void
+_tcb_dtor(struct tcb *tcb)
+{
+ /* Free TDV */
+ free(tcb);
+}
+
+struct kcb *
+_kcb_ctor(struct kse *kse)
+{
+ struct kcb *kcb;
+
+ if ((kcb = malloc(sizeof(struct kcb))) != NULL) {
+ bzero(kcb, sizeof(struct kcb));
+ kcb->kcb_faketcb.tcb_isfake = 1;
+ kcb->kcb_faketcb.tcb_tmbx.tm_flags = TMF_NOUPCALL;
+ kcb->kcb_curtcb = &kcb->kcb_faketcb;
+ kcb->kcb_kse = kse;
+ }
+ return (kcb);
+}
+
+void
+_kcb_dtor(struct kcb *kcb)
+{
+ free(kcb);
+}
diff --git a/lib/libkse/arch/sparc64/Makefile.inc b/lib/libkse/arch/sparc64/Makefile.inc
new file mode 100644
index 0000000..07107b4
--- /dev/null
+++ b/lib/libkse/arch/sparc64/Makefile.inc
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}/${MACHINE_ARCH}
+
+SRCS+= pthread_md.c thr_getcontext.S
diff --git a/lib/libkse/arch/sparc64/include/atomic_ops.h b/lib/libkse/arch/sparc64/include/atomic_ops.h
new file mode 100644
index 0000000..4f4d8af
--- /dev/null
+++ b/lib/libkse/arch/sparc64/include/atomic_ops.h
@@ -0,0 +1,75 @@
+/*-
+ * Copyright (c) 2003 Jake Burkholder <jake@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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _ATOMIC_OPS_H_
+#define _ATOMIC_OPS_H_
+
+#include <machine/atomic.h>
+
+/*
+ * Atomic swap:
+ * Atomic (tmp = *dst, *dst = val), then *res = tmp
+ *
+ * void atomic_swap_long(long *dst, long val, long *res);
+ */
+static __inline void
+atomic_swap_long(long *dst, long val, long *res)
+{
+ long tmp;
+ long r;
+
+ tmp = *dst;
+ for (;;) {
+ r = atomic_cas_64(dst, tmp, val);
+ if (r == tmp)
+ break;
+ tmp = r;
+ }
+ *res = tmp;
+}
+
+static __inline void
+atomic_swap_int(int *dst, int val, int *res)
+{
+ int tmp;
+ int r;
+
+ tmp = *dst;
+ for (;;) {
+ r = atomic_cas_32(dst, tmp, val);
+ if (r == tmp)
+ break;
+ tmp = r;
+ }
+ *res = tmp;
+}
+
+#define atomic_swap_ptr(dst, val, res) \
+ atomic_swap_long((long *)dst, (long)val, (long *)res)
+
+#endif
diff --git a/lib/libkse/arch/sparc64/include/pthread_md.h b/lib/libkse/arch/sparc64/include/pthread_md.h
new file mode 100644
index 0000000..fac62c2
--- /dev/null
+++ b/lib/libkse/arch/sparc64/include/pthread_md.h
@@ -0,0 +1,254 @@
+/*-
+ * Copyright (c) 2003 Jake Burkholder <jake@freebsd.org>.
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Machine-dependent thread prototypes/definitions for the thread kernel.
+ */
+#ifndef _PTHREAD_MD_H_
+#define _PTHREAD_MD_H_
+
+#include <sys/kse.h>
+#include <stddef.h>
+#include <ucontext.h>
+
+#define KSE_STACKSIZE 16384
+#define DTV_OFFSET offsetof(struct tcb, tcb_tp.tp_tdv)
+
+int _thr_setcontext(mcontext_t *, intptr_t, intptr_t *);
+int _thr_getcontext(mcontext_t *);
+
+#define THR_GETCONTEXT(ucp) _thr_getcontext(&(ucp)->uc_mcontext)
+#define THR_SETCONTEXT(ucp) _thr_setcontext(&(ucp)->uc_mcontext, 0, NULL)
+
+#define PER_THREAD
+
+struct kcb;
+struct kse;
+struct pthread;
+struct tcb;
+struct tdv; /* We don't know what this is yet? */
+
+
+/*
+ * %g6 points to one of these. We define the static TLS as an array
+ * of long double to enforce 16-byte alignment of the TLS memory.
+ *
+ * XXX - Both static and dynamic allocation of any of these structures
+ * will result in a valid, well-aligned thread pointer???
+ */
+struct sparc64_tp {
+ struct tdv *tp_tdv; /* dynamic TLS */
+ uint64_t _reserved_;
+ long double tp_tls[0]; /* static TLS */
+};
+
+struct tcb {
+ struct pthread *tcb_thread;
+ void *tcb_addr; /* allocated tcb address */
+ struct kcb *tcb_curkcb;
+ uint64_t tcb_isfake;
+ uint64_t tcb_spare[4];
+ struct kse_thr_mailbox tcb_tmbx; /* needs 64-byte alignment */
+ struct sparc64_tp tcb_tp;
+} __aligned(64);
+
+struct kcb {
+ struct kse_mailbox kcb_kmbx;
+ struct tcb kcb_faketcb;
+ struct tcb *kcb_curtcb;
+ struct kse *kcb_kse;
+};
+
+register struct sparc64_tp *_tp __asm("%g6");
+
+#define _tcb ((struct tcb*)((char*)(_tp) - offsetof(struct tcb, tcb_tp)))
+
+/*
+ * The kcb and tcb constructors.
+ */
+struct tcb *_tcb_ctor(struct pthread *, int);
+void _tcb_dtor(struct tcb *);
+struct kcb *_kcb_ctor(struct kse *kse);
+void _kcb_dtor(struct kcb *);
+
+/* Called from the KSE to set its private data. */
+static __inline void
+_kcb_set(struct kcb *kcb)
+{
+ /* There is no thread yet; use the fake tcb. */
+ _tp = &kcb->kcb_faketcb.tcb_tp;
+}
+
+/*
+ * Get the current kcb.
+ *
+ * This can only be called while in a critical region; don't
+ * worry about having the kcb changed out from under us.
+ */
+static __inline struct kcb *
+_kcb_get(void)
+{
+ return (_tcb->tcb_curkcb);
+}
+
+/*
+ * Enter a critical region.
+ *
+ * Read and clear km_curthread in the kse mailbox.
+ */
+static __inline struct kse_thr_mailbox *
+_kcb_critical_enter(void)
+{
+ struct kse_thr_mailbox *crit;
+ uint32_t flags;
+
+ if (_tcb->tcb_isfake != 0) {
+ /*
+ * We already are in a critical region since
+ * there is no current thread.
+ */
+ crit = NULL;
+ } else {
+ flags = _tcb->tcb_tmbx.tm_flags;
+ _tcb->tcb_tmbx.tm_flags |= TMF_NOUPCALL;
+ crit = _tcb->tcb_curkcb->kcb_kmbx.km_curthread;
+ _tcb->tcb_curkcb->kcb_kmbx.km_curthread = NULL;
+ _tcb->tcb_tmbx.tm_flags = flags;
+ }
+ return (crit);
+}
+
+static __inline void
+_kcb_critical_leave(struct kse_thr_mailbox *crit)
+{
+ /* No need to do anything if this is a fake tcb. */
+ if (_tcb->tcb_isfake == 0)
+ _tcb->tcb_curkcb->kcb_kmbx.km_curthread = crit;
+}
+
+static __inline int
+_kcb_in_critical(void)
+{
+ uint32_t flags;
+ int ret;
+
+ if (_tcb->tcb_isfake != 0) {
+ /*
+ * We are in a critical region since there is no
+ * current thread.
+ */
+ ret = 1;
+ } else {
+ flags = _tcb->tcb_tmbx.tm_flags;
+ _tcb->tcb_tmbx.tm_flags |= TMF_NOUPCALL;
+ ret = (_tcb->tcb_curkcb->kcb_kmbx.km_curthread == NULL);
+ _tcb->tcb_tmbx.tm_flags = flags;
+ }
+ return (ret);
+}
+
+static __inline void
+_tcb_set(struct kcb *kcb, struct tcb *tcb)
+{
+ if (tcb == NULL)
+ tcb = &kcb->kcb_faketcb;
+ kcb->kcb_curtcb = tcb;
+ tcb->tcb_curkcb = kcb;
+ _tp = &tcb->tcb_tp;
+}
+
+static __inline struct tcb *
+_tcb_get(void)
+{
+ return (_tcb);
+}
+
+static __inline struct pthread *
+_get_curthread(void)
+{
+ return (_tcb->tcb_thread);
+}
+
+/*
+ * Get the current kse.
+ *
+ * Like _kcb_get(), this can only be called while in a critical region.
+ */
+static __inline struct kse *
+_get_curkse(void)
+{
+ return (_tcb->tcb_curkcb->kcb_kse);
+}
+
+void _sparc64_enter_uts(kse_func_t uts, struct kse_mailbox *km, void *stack,
+ size_t stacksz);
+
+static __inline int
+_thread_enter_uts(struct tcb *tcb, struct kcb *kcb)
+{
+ if (_thr_getcontext(&tcb->tcb_tmbx.tm_context.uc_mcontext) == 0) {
+ /* Make the fake tcb the current thread. */
+ kcb->kcb_curtcb = &kcb->kcb_faketcb;
+ _tp = &kcb->kcb_faketcb.tcb_tp;
+ _sparc64_enter_uts(kcb->kcb_kmbx.km_func, &kcb->kcb_kmbx,
+ kcb->kcb_kmbx.km_stack.ss_sp,
+ kcb->kcb_kmbx.km_stack.ss_size);
+ /* We should not reach here. */
+ return (-1);
+ }
+ return (0);
+}
+
+static __inline int
+_thread_switch(struct kcb *kcb, struct tcb *tcb, int setmbox)
+{
+ extern int _libkse_debug;
+ mcontext_t *mc;
+
+ _tcb_set(kcb, tcb);
+ mc = &tcb->tcb_tmbx.tm_context.uc_mcontext;
+ if (_libkse_debug == 0) {
+ tcb->tcb_tmbx.tm_lwp = kcb->kcb_kmbx.km_lwp;
+ if (setmbox)
+ _thr_setcontext(mc, (intptr_t)&tcb->tcb_tmbx,
+ (intptr_t *)&kcb->kcb_kmbx.km_curthread);
+ else
+ _thr_setcontext(mc, 0, NULL);
+ } else {
+ if (setmbox)
+ kse_switchin(&tcb->tcb_tmbx, KSE_SWITCHIN_SETTMBX);
+ else
+ kse_switchin(&tcb->tcb_tmbx, 0);
+ }
+
+ /* We should not reach here. */
+ return (-1);
+}
+
+#endif /* _PTHREAD_MD_H_ */
diff --git a/lib/libkse/arch/sparc64/sparc64/assym.s b/lib/libkse/arch/sparc64/sparc64/assym.s
new file mode 100644
index 0000000..3e22c9f
--- /dev/null
+++ b/lib/libkse/arch/sparc64/sparc64/assym.s
@@ -0,0 +1,15 @@
+/*
+ * Offsets into structures used from asm. Must be kept in sync with
+ * appropriate headers.
+ *
+ * $FreeBSD$
+ */
+
+#define UC_MCONTEXT 0x40
+
+#define MC_FLAGS 0x0
+#define MC_VALID_FLAGS 0x1
+#define MC_GLOBAL 0x0
+#define MC_OUT 0x40
+#define MC_TPC 0xc8
+#define MC_TNPC 0xc0
diff --git a/lib/libkse/arch/sparc64/sparc64/pthread_md.c b/lib/libkse/arch/sparc64/sparc64/pthread_md.c
new file mode 100644
index 0000000..d6bf95d
--- /dev/null
+++ b/lib/libkse/arch/sparc64/sparc64/pthread_md.c
@@ -0,0 +1,91 @@
+/*-
+ * Copyright (C) 2003 Jake Burkholder <jake@freebsd.org>
+ * Copyright (C) 2003 David Xu <davidxu@freebsd.org>
+ * Copyright (c) 2001,2003 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include <unistd.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ucontext.h>
+
+#include "pthread_md.h"
+
+struct tcb *
+_tcb_ctor(struct pthread *thread, int initial)
+{
+ struct tcb *tcb;
+ void *addr;
+
+ addr = malloc(sizeof(struct tcb) + 63);
+ if (addr == NULL)
+ tcb = NULL;
+ else {
+ tcb = (struct tcb *)(((uintptr_t)(addr) + 63) & ~63);
+ bzero(tcb, sizeof(struct tcb));
+ tcb->tcb_addr = addr;
+ tcb->tcb_thread = thread;
+ /* XXX - Allocate tdv/tls */
+ }
+ return (tcb);
+}
+
+void
+_tcb_dtor(struct tcb *tcb)
+{
+ void *addr;
+
+ addr = tcb->tcb_addr;
+ tcb->tcb_addr = NULL;
+ free(addr);
+}
+
+struct kcb *
+_kcb_ctor(struct kse *kse)
+{
+ struct kcb *kcb;
+
+ kcb = malloc(sizeof(struct kcb));
+ if (kcb != NULL) {
+ bzero(kcb, sizeof(struct kcb));
+ kcb->kcb_faketcb.tcb_isfake = 1;
+ kcb->kcb_faketcb.tcb_tmbx.tm_flags = TMF_NOUPCALL;
+ kcb->kcb_curtcb = &kcb->kcb_faketcb;
+ kcb->kcb_kse = kse;
+ }
+ return (kcb);
+}
+
+void
+_kcb_dtor(struct kcb *kcb)
+{
+ free(kcb);
+}
diff --git a/lib/libkse/arch/sparc64/sparc64/thr_getcontext.S b/lib/libkse/arch/sparc64/sparc64/thr_getcontext.S
new file mode 100644
index 0000000..ca6473a
--- /dev/null
+++ b/lib/libkse/arch/sparc64/sparc64/thr_getcontext.S
@@ -0,0 +1,87 @@
+/*-
+ * Copyright (C) 2003 Jake Burkholder <jake@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$");
+
+#include "assym.s"
+
+ .weak CNAME(_thr_getcontext)
+ .set CNAME(_thr_getcontext),CNAME(__thr_getcontext)
+ENTRY(__thr_getcontext)
+ add %o7, 8, %o1
+ add %o1, 4, %o2
+ stx %sp, [%o0 + MC_OUT + (6 * 8)]
+ stx %o1, [%o0 + MC_TPC]
+ stx %o2, [%o0 + MC_TNPC]
+ mov MC_VALID_FLAGS, %l0 /* Validate the context. */
+ stx %l0, [%o0 + MC_FLAGS]
+ mov 1, %l0
+ stx %l0, [%o0 + MC_OUT + (0 * 8)] /* return 1 when resumed */
+ retl
+ mov 0, %o0 /* return 0 */
+END(__thr_getcontext)
+
+ .weak CNAME(_thr_setcontext)
+ .set CNAME(_thr_setcontext),CNAME(__thr_setcontext)
+ENTRY(__thr_setcontext)
+ save %sp, -CCFSZ, %sp
+ flushw
+ mov %i0, %l0
+ mov %i1, %l1
+ mov %i2, %l2
+ ldx [%l0 + MC_GLOBAL + (1 * 8)], %g1
+ ldx [%l0 + MC_GLOBAL + (2 * 8)], %g2
+ ldx [%l0 + MC_GLOBAL + (3 * 8)], %g3
+ ldx [%l0 + MC_GLOBAL + (4 * 8)], %g4
+ ldx [%l0 + MC_GLOBAL + (5 * 8)], %g5
+ ldx [%l0 + MC_GLOBAL + (6 * 8)], %g6
+ ldx [%l0 + MC_GLOBAL + (7 * 8)], %g7
+ ldx [%l0 + MC_OUT + (0 * 8)], %i0
+ ldx [%l0 + MC_OUT + (1 * 8)], %i1
+ ldx [%l0 + MC_OUT + (2 * 8)], %i2
+ ldx [%l0 + MC_OUT + (3 * 8)], %i3
+ ldx [%l0 + MC_OUT + (4 * 8)], %i4
+ ldx [%l0 + MC_OUT + (5 * 8)], %i5
+ ldx [%l0 + MC_OUT + (6 * 8)], %i6
+ ldx [%l0 + MC_OUT + (7 * 8)], %i7
+ ldx [%l0 + MC_TPC], %l4
+ ldx [%l0 + MC_TNPC], %l3
+ brz %l2, 1f
+ nop
+ stx %l1, [%l2]
+1: jmpl %l3, %g0
+ return %l4
+END(__thr_setcontext)
+
+ENTRY(_sparc64_enter_uts)
+ save %sp, -CCFSZ, %sp
+ flushw
+ add %i2, %i3, %i2
+ sub %i2, SPOFF + CCFSZ, %sp
+ jmpl %i0, %g0
+ mov %i1, %o0
+END(_sparc64_enter_uts)
diff --git a/lib/libkse/support/Makefile.inc b/lib/libkse/support/Makefile.inc
new file mode 100644
index 0000000..956667f
--- /dev/null
+++ b/lib/libkse/support/Makefile.inc
@@ -0,0 +1,40 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/support ${.CURDIR}/../libc/gen ${.CURDIR}/../libc/string
+.PATH: ${.CURDIR}/../libc/${MACHINE_ARCH}/sys
+
+CFLAGS+= -I${.CURDIR}/../libc/${MACHINE_ARCH}
+
+SYSCALLS= clock_gettime \
+ kse_create \
+ kse_exit \
+ kse_release \
+ kse_switchin \
+ kse_thr_interrupt \
+ kse_wakeup \
+ sigaction \
+ sigprocmask \
+ sigtimedwait \
+ write
+
+SYSCALL_SRC= ${SYSCALLS:S/$/.S/}
+SYSCALL_OBJ= ${SYSCALLS:S/$/.So/}
+
+${SYSCALL_SRC}:
+ printf '#include "SYS.h"\nRSYSCALL(${.PREFIX})\n' > ${.TARGET}
+
+LIBC_OBJS= sigsetops.So \
+ bcopy.So \
+ bzero.So \
+ cerror.So \
+ memcpy.So \
+ memset.So \
+ strcpy.So \
+ strlen.So
+
+SOBJS+= thr_libc.So
+CLEANFILES+= ${SYSCALL_SRC} ${SYSCALL_OBJ} ${LIBC_OBJS}
+
+thr_libc.So: ${SYSCALL_OBJ} ${LIBC_OBJS}
+ ${CC} -fPIC -nostdlib -o ${.TARGET} -r ${.ALLSRC}
+
diff --git a/lib/libkse/support/thr_support.c b/lib/libkse/support/thr_support.c
new file mode 100644
index 0000000..2956e07
--- /dev/null
+++ b/lib/libkse/support/thr_support.c
@@ -0,0 +1,62 @@
+/*-
+ * Copyright 2003 Alexander Kabaev.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list 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$
+ */
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/kse.h>
+#include <signal.h>
+#include <string.h>
+
+#include "thr_private.h"
+
+__strong_reference(clock_gettime, _thr_clock_gettime);
+__strong_reference(kse_exit, _thr_kse_exit);
+__strong_reference(kse_wakeup, _thr_kse_wakeup);
+__strong_reference(kse_create, _thr_kse_create);
+__strong_reference(kse_thr_interrupt, _thr_kse_thr_interrupt);
+__strong_reference(kse_release, _thr_kse_release);
+__strong_reference(kse_switchin, _thr_kse_switchin);
+
+__strong_reference(sigaction, _thr_sigaction);
+__strong_reference(sigprocmask, _thr_sigprocmask);
+__strong_reference(sigemptyset, _thr_sigemptyset);
+__strong_reference(sigaddset, _thr_sigaddset);
+__strong_reference(sigfillset, _thr_sigfillset);
+__strong_reference(sigismember, _thr_sigismember);
+__strong_reference(sigdelset, _thr_sigdelset);
+
+__strong_reference(memset, _thr_memset);
+__strong_reference(memcpy, _thr_memcpy);
+__strong_reference(strcpy, _thr_strcpy);
+__strong_reference(strlen, _thr_strlen);
+__strong_reference(bzero, _thr_bzero);
+__strong_reference(bcopy, _thr_bcopy);
+
+__strong_reference(__sys_write, _thr__sys_write);
+__strong_reference(__sys_sigtimedwait, _thr__sys_sigtimedwait);
+
diff --git a/lib/libkse/sys/Makefile.inc b/lib/libkse/sys/Makefile.inc
new file mode 100644
index 0000000..fb4a108
--- /dev/null
+++ b/lib/libkse/sys/Makefile.inc
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/sys
+
+SRCS+= lock.c thr_error.c
diff --git a/lib/libkse/sys/lock.c b/lib/libkse/sys/lock.c
new file mode 100644
index 0000000..2ac8c0c
--- /dev/null
+++ b/lib/libkse/sys/lock.c
@@ -0,0 +1,351 @@
+/*-
+ * Copyright (c) 2001, 2003 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <machine/atomic.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#include "atomic_ops.h"
+#include "lock.h"
+
+#ifdef _LOCK_DEBUG
+#define LCK_ASSERT(e) assert(e)
+#else
+#define LCK_ASSERT(e)
+#endif
+
+#define MAX_SPINS 500
+
+void
+_lock_destroy(struct lock *lck)
+{
+ if ((lck != NULL) && (lck->l_head != NULL)) {
+ free(lck->l_head);
+ lck->l_head = NULL;
+ lck->l_tail = NULL;
+ }
+}
+
+int
+_lock_init(struct lock *lck, enum lock_type ltype,
+ lock_handler_t *waitfunc, lock_handler_t *wakeupfunc)
+{
+ if (lck == NULL)
+ return (-1);
+ else if ((lck->l_head = malloc(sizeof(struct lockreq))) == NULL)
+ return (-1);
+ else {
+ lck->l_type = ltype;
+ lck->l_wait = waitfunc;
+ lck->l_wakeup = wakeupfunc;
+ lck->l_head->lr_locked = 0;
+ lck->l_head->lr_watcher = NULL;
+ lck->l_head->lr_owner = NULL;
+ lck->l_head->lr_active = 1;
+ lck->l_tail = lck->l_head;
+ }
+ return (0);
+}
+
+int
+_lock_reinit(struct lock *lck, enum lock_type ltype,
+ lock_handler_t *waitfunc, lock_handler_t *wakeupfunc)
+{
+ if (lck == NULL)
+ return (-1);
+ else if (lck->l_head == NULL)
+ return (_lock_init(lck, ltype, waitfunc, wakeupfunc));
+ else {
+ lck->l_head->lr_locked = 0;
+ lck->l_head->lr_watcher = NULL;
+ lck->l_head->lr_owner = NULL;
+ lck->l_head->lr_active = 1;
+ lck->l_tail = lck->l_head;
+ }
+ return (0);
+}
+
+int
+_lockuser_init(struct lockuser *lu, void *priv)
+{
+ if (lu == NULL)
+ return (-1);
+ else if ((lu->lu_myreq == NULL) &&
+ ((lu->lu_myreq = malloc(sizeof(struct lockreq))) == NULL))
+ return (-1);
+ else {
+ lu->lu_myreq->lr_locked = 1;
+ lu->lu_myreq->lr_watcher = NULL;
+ lu->lu_myreq->lr_owner = lu;
+ lu->lu_myreq->lr_active = 0;
+ lu->lu_watchreq = NULL;
+ lu->lu_priority = 0;
+ lu->lu_private = priv;
+ lu->lu_private2 = NULL;
+ }
+ return (0);
+}
+
+int
+_lockuser_reinit(struct lockuser *lu, void *priv)
+{
+ if (lu == NULL)
+ return (-1);
+ /*
+ * All lockusers keep their watch request and drop their
+ * own (lu_myreq) request. Their own request is either
+ * some other lockuser's watch request or is the head of
+ * the lock.
+ */
+ lu->lu_myreq = lu->lu_watchreq;
+ if (lu->lu_myreq == NULL)
+ return (_lockuser_init(lu, priv));
+ else {
+ lu->lu_myreq->lr_locked = 1;
+ lu->lu_myreq->lr_watcher = NULL;
+ lu->lu_myreq->lr_owner = lu;
+ lu->lu_myreq->lr_active = 0;
+ lu->lu_watchreq = NULL;
+ lu->lu_priority = 0;
+ lu->lu_private = priv;
+ lu->lu_private2 = NULL;
+ }
+ return (0);
+}
+
+void
+_lockuser_destroy(struct lockuser *lu)
+{
+ if ((lu != NULL) && (lu->lu_myreq != NULL))
+ free(lu->lu_myreq);
+}
+
+/*
+ * Acquire a lock waiting (spin or sleep) for it to become available.
+ */
+void
+_lock_acquire(struct lock *lck, struct lockuser *lu, int prio)
+{
+ int i;
+ int lval;
+
+ /**
+ * XXX - We probably want to remove these checks to optimize
+ * performance. It is also a bug if any one of the
+ * checks fail, so it's probably better to just let it
+ * SEGV and fix it.
+ */
+#if 0
+ if (lck == NULL || lu == NULL || lck->l_head == NULL)
+ return;
+#endif
+ if ((lck->l_type & LCK_PRIORITY) != 0) {
+ LCK_ASSERT(lu->lu_myreq->lr_locked == 1);
+ LCK_ASSERT(lu->lu_myreq->lr_watcher == NULL);
+ LCK_ASSERT(lu->lu_myreq->lr_owner == lu);
+ LCK_ASSERT(lu->lu_watchreq == NULL);
+
+ lu->lu_priority = prio;
+ }
+ /*
+ * Atomically swap the head of the lock request with
+ * this request.
+ */
+ atomic_swap_ptr(&lck->l_head, lu->lu_myreq, &lu->lu_watchreq);
+
+ if (lu->lu_watchreq->lr_locked != 0) {
+ atomic_store_rel_ptr
+ ((volatile uintptr_t *)&lu->lu_watchreq->lr_watcher,
+ (uintptr_t)lu);
+ if ((lck->l_wait == NULL) ||
+ ((lck->l_type & LCK_ADAPTIVE) == 0)) {
+ while (lu->lu_watchreq->lr_locked != 0)
+ ; /* spin, then yield? */
+ } else {
+ /*
+ * Spin for a bit before invoking the wait function.
+ *
+ * We should be a little smarter here. If we're
+ * running on a single processor, then the lock
+ * owner got preempted and spinning will accomplish
+ * nothing but waste time. If we're running on
+ * multiple processors, the owner could be running
+ * on another CPU and we might acquire the lock if
+ * we spin for a bit.
+ *
+ * The other thing to keep in mind is that threads
+ * acquiring these locks are considered to be in
+ * critical regions; they will not be preempted by
+ * the _UTS_ until they release the lock. It is
+ * therefore safe to assume that if a lock can't
+ * be acquired, it is currently held by a thread
+ * running in another KSE.
+ */
+ for (i = 0; i < MAX_SPINS; i++) {
+ if (lu->lu_watchreq->lr_locked == 0)
+ return;
+ if (lu->lu_watchreq->lr_active == 0)
+ break;
+ }
+ atomic_swap_int((int *)&lu->lu_watchreq->lr_locked,
+ 2, &lval);
+ if (lval == 0)
+ lu->lu_watchreq->lr_locked = 0;
+ else
+ lck->l_wait(lck, lu);
+
+ }
+ }
+ lu->lu_myreq->lr_active = 1;
+}
+
+/*
+ * Release a lock.
+ */
+void
+_lock_release(struct lock *lck, struct lockuser *lu)
+{
+ struct lockuser *lu_tmp, *lu_h;
+ struct lockreq *myreq;
+ int prio_h;
+ int lval;
+
+ /**
+ * XXX - We probably want to remove these checks to optimize
+ * performance. It is also a bug if any one of the
+ * checks fail, so it's probably better to just let it
+ * SEGV and fix it.
+ */
+#if 0
+ if ((lck == NULL) || (lu == NULL))
+ return;
+#endif
+ if ((lck->l_type & LCK_PRIORITY) != 0) {
+ prio_h = 0;
+ lu_h = NULL;
+
+ /* Update tail if our request is last. */
+ if (lu->lu_watchreq->lr_owner == NULL) {
+ atomic_store_rel_ptr((volatile uintptr_t *)&lck->l_tail,
+ (uintptr_t)lu->lu_myreq);
+ atomic_store_rel_ptr
+ ((volatile uintptr_t *)&lu->lu_myreq->lr_owner,
+ (uintptr_t)NULL);
+ } else {
+ /* Remove ourselves from the list. */
+ atomic_store_rel_ptr((volatile uintptr_t *)
+ &lu->lu_myreq->lr_owner,
+ (uintptr_t)lu->lu_watchreq->lr_owner);
+ atomic_store_rel_ptr((volatile uintptr_t *)
+ &lu->lu_watchreq->lr_owner->lu_myreq,
+ (uintptr_t)lu->lu_myreq);
+ }
+ /*
+ * The watch request now becomes our own because we've
+ * traded away our previous request. Save our previous
+ * request so that we can grant the lock.
+ */
+ myreq = lu->lu_myreq;
+ lu->lu_myreq = lu->lu_watchreq;
+ lu->lu_watchreq = NULL;
+ lu->lu_myreq->lr_locked = 1;
+ lu->lu_myreq->lr_owner = lu;
+ lu->lu_myreq->lr_watcher = NULL;
+ /*
+ * Traverse the list of lock requests in reverse order
+ * looking for the user with the highest priority.
+ */
+ for (lu_tmp = lck->l_tail->lr_watcher; lu_tmp != NULL;
+ lu_tmp = lu_tmp->lu_myreq->lr_watcher) {
+ if (lu_tmp->lu_priority > prio_h) {
+ lu_h = lu_tmp;
+ prio_h = lu_tmp->lu_priority;
+ }
+ }
+ if (lu_h != NULL) {
+ /* Give the lock to the highest priority user. */
+ if (lck->l_wakeup != NULL) {
+ atomic_swap_int(
+ (int *)&lu_h->lu_watchreq->lr_locked,
+ 0, &lval);
+ if (lval == 2)
+ /* Notify the sleeper */
+ lck->l_wakeup(lck,
+ lu_h->lu_myreq->lr_watcher);
+ }
+ else
+ atomic_store_rel_int(
+ &lu_h->lu_watchreq->lr_locked, 0);
+ } else {
+ if (lck->l_wakeup != NULL) {
+ atomic_swap_int((int *)&myreq->lr_locked,
+ 0, &lval);
+ if (lval == 2)
+ /* Notify the sleeper */
+ lck->l_wakeup(lck, myreq->lr_watcher);
+ }
+ else
+ /* Give the lock to the previous request. */
+ atomic_store_rel_int(&myreq->lr_locked, 0);
+ }
+ } else {
+ /*
+ * The watch request now becomes our own because we've
+ * traded away our previous request. Save our previous
+ * request so that we can grant the lock.
+ */
+ myreq = lu->lu_myreq;
+ lu->lu_myreq = lu->lu_watchreq;
+ lu->lu_watchreq = NULL;
+ lu->lu_myreq->lr_locked = 1;
+ if (lck->l_wakeup) {
+ atomic_swap_int((int *)&myreq->lr_locked, 0, &lval);
+ if (lval == 2)
+ /* Notify the sleeper */
+ lck->l_wakeup(lck, myreq->lr_watcher);
+ }
+ else
+ /* Give the lock to the previous request. */
+ atomic_store_rel_int(&myreq->lr_locked, 0);
+ }
+ lu->lu_myreq->lr_active = 0;
+}
+
+void
+_lock_grant(struct lock *lck /* unused */, struct lockuser *lu)
+{
+ atomic_store_rel_int(&lu->lu_watchreq->lr_locked, 3);
+}
+
+void
+_lockuser_setactive(struct lockuser *lu, int active)
+{
+ lu->lu_myreq->lr_active = active;
+}
+
diff --git a/lib/libkse/sys/lock.h b/lib/libkse/sys/lock.h
new file mode 100644
index 0000000..6102a0b
--- /dev/null
+++ b/lib/libkse/sys/lock.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2001, 2003 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 _LOCK_H_
+#define _LOCK_H_
+
+struct lockreq;
+struct lockuser;
+struct lock;
+
+enum lock_type {
+ LCK_DEFAULT = 0x0000, /* default is FIFO spin locks */
+ LCK_PRIORITY = 0x0001,
+ LCK_ADAPTIVE = 0x0002 /* call user-supplied handlers */
+};
+
+typedef void lock_handler_t(struct lock *, struct lockuser *);
+
+struct lock {
+ struct lockreq *l_head;
+ struct lockreq *l_tail; /* only used for priority locks */
+ enum lock_type l_type;
+ lock_handler_t *l_wait; /* only used for adaptive locks */
+ lock_handler_t *l_wakeup; /* only used for adaptive locks */
+};
+
+/* Try to make this >= CACHELINESIZE */
+struct lockreq {
+ struct lockuser *lr_watcher; /* only used for priority locks */
+ struct lockuser *lr_owner; /* only used for priority locks */
+ volatile int lr_locked; /* lock granted = 0, busy otherwise */
+ volatile int lr_active; /* non-zero if the lock is last lock for thread */
+};
+
+struct lockuser {
+ struct lockreq *lu_myreq; /* request to give up/trade */
+ struct lockreq *lu_watchreq; /* watch this request */
+ int lu_priority; /* only used for priority locks */
+ void *lu_private1; /* private{1,2} are initialized to */
+ void *lu_private2; /* NULL and can be used by caller */
+#define lu_private lu_private1
+};
+
+#define _LCK_INITIALIZER(lck_req) { &lck_req, NULL, LCK_DEFAULT, \
+ NULL, NULL }
+#define _LCK_REQUEST_INITIALIZER { 0, NULL, NULL, 0 }
+
+#define _LCK_BUSY(lu) ((lu)->lu_watchreq->lr_locked != 0)
+#define _LCK_ACTIVE(lu) ((lu)->lu_watchreq->lr_active != 0)
+#define _LCK_GRANTED(lu) ((lu)->lu_watchreq->lr_locked == 3)
+
+#define _LCK_SET_PRIVATE(lu, p) (lu)->lu_private = (void *)(p)
+#define _LCK_GET_PRIVATE(lu) (lu)->lu_private
+#define _LCK_SET_PRIVATE2(lu, p) (lu)->lu_private2 = (void *)(p)
+#define _LCK_GET_PRIVATE2(lu) (lu)->lu_private2
+
+void _lock_acquire(struct lock *, struct lockuser *, int);
+void _lock_destroy(struct lock *);
+void _lock_grant(struct lock *, struct lockuser *);
+int _lock_init(struct lock *, enum lock_type,
+ lock_handler_t *, lock_handler_t *);
+int _lock_reinit(struct lock *, enum lock_type,
+ lock_handler_t *, lock_handler_t *);
+void _lock_release(struct lock *, struct lockuser *);
+int _lockuser_init(struct lockuser *lu, void *priv);
+void _lockuser_destroy(struct lockuser *lu);
+int _lockuser_reinit(struct lockuser *lu, void *priv);
+void _lockuser_setactive(struct lockuser *lu, int active);
+
+#endif
diff --git a/lib/libkse/sys/thr_error.c b/lib/libkse/sys/thr_error.c
new file mode 100644
index 0000000..0ba34e0
--- /dev/null
+++ b/lib/libkse/sys/thr_error.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.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 John Birrell
+ * and Chris Provenzano.
+ * 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 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$
+ */
+#include <pthread.h>
+#include "libc_private.h"
+#include "thr_private.h"
+
+#undef errno
+extern int errno;
+
+LT10_COMPAT_DEFAULT(__error);
+
+int *
+__error(void)
+{
+ struct pthread *curthread;
+
+ if (__isthreaded == 0)
+ return (&errno);
+ else if (_kse_in_critical())
+ return &(_get_curkse()->k_error);
+ else {
+ curthread = _get_curthread();
+ if ((curthread == NULL) || (curthread == _thr_initial))
+ return (&errno);
+ else
+ return (&curthread->error);
+ }
+}
diff --git a/lib/libkse/test/Makefile b/lib/libkse/test/Makefile
new file mode 100644
index 0000000..5b5eb3c
--- /dev/null
+++ b/lib/libkse/test/Makefile
@@ -0,0 +1,116 @@
+#
+# $FreeBSD$
+#
+# Automated test suite for libpthread (pthreads).
+#
+
+# File lists.
+
+# Tests written in C.
+CTESTS := hello_d.c hello_s.c join_leak_d.c mutex_d.c sem_d.c sigsuspend_d.c \
+ sigwait_d.c
+
+# C programs that are used internally by the tests. The build system merely
+# compiles these.
+BTESTS := guard_b.c hello_b.c
+
+# Tests written in perl.
+PTESTS := guard_s.pl propagate_s.pl
+
+# Munge the file lists to their final executable names (strip the .c).
+CTESTS := $(CTESTS:R)
+BTESTS := $(BTESTS:R)
+
+CPPFLAGS := -D_LIBC_R_ -D_REENTRANT
+CFLAGS := -Wall -pipe -g3
+LDFLAGS_A := -static
+LDFLAGS_P := -pg
+LDFLAGS_S :=
+LIBS := -lpthread
+
+# Flags passed to verify. "-v" or "-u" may be useful.
+VERIFY = perl verify
+VFLAGS :=
+
+all : default
+
+# Only use the following suffixes, in order to avoid any strange built-in rules.
+.SUFFIXES :
+.SUFFIXES : .c .o .d .pl
+
+# Clear out all paths, then set just one (default path) for the main build
+# directory.
+.PATH :
+.PATH : .
+
+# Build the C programs.
+.for bin in $(CTESTS) $(BTESTS)
+$(bin)_a : $(bin:S/$/&.c/)
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c $(bin:S/$/&.c/) -o $(@:S/$/&.o/)
+ $(CC) -o $@ $(@:S/$/&.o/) $(LDFLAGS_A) $(LIBS)
+ @$(SHELL) -ec "$(CC) -M $(CPPFLAGS) $(bin:S/$/&.c/) | sed \"s/\($(bin:T)\)\.o\([ :]*\)/$(bin:H:S!/!\\/!g)\/\1_a.o \2/g\" > $(@:R:S/$/&.d/)"
+
+$(bin)_p : $(bin:S/$/&.c/)
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c $(bin:S/$/&.c/) -o $(@:S/$/&.o/)
+ $(CC) -o $@ $(@:S/$/&.o/) $(LDFLAGS_P) $(LIBS)
+ @$(SHELL) -ec "$(CC) -M $(CPPFLAGS) $(bin:S/$/&.c/) | sed \"s/\($(bin:T)\)\.o\([ :]*\)/$(bin:H:S!/!\\/!g)\/\1_p.o \2/g\" > $(@:R:S/$/&.d/)"
+
+$(bin)_s : $(bin:S/$/&.c/)
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c $(bin:S/$/&.c/) -o $(@:S/$/&.o/)
+ $(CC) -o $@ $(@:S/$/&.o/) $(LDFLAGS_S) $(LIBS)
+ @$(SHELL) -ec "$(CC) -M $(CPPFLAGS) $(bin:S/$/&.c/) | sed \"s/\($(bin:T)\)\.o\([ :]*\)/$(bin:H:S!/!\\/!g)\/\1_s.o \2/g\" > $(@:R:S/$/&.d/)"
+.endfor
+
+# Dependency file inclusion.
+.for depfile in $(CTESTS:R:S/$/&_a.d/) $(BTESTS:R:S/$/&_a.d/) \
+ $(CTESTS:R:S/$/&_p.d/) $(BTESTS:R:S/$/&_p.d/) \
+ $(CTESTS:R:S/$/&_s.d/) $(BTESTS:R:S/$/&_s.d/)
+.if exists($(depfile))
+.include "$(depfile)"
+.endif
+.endfor
+
+default : check
+
+tests_a : $(CTESTS:S/$/&_a/) $(BTESTS:S/$/&_a/)
+tests_p : $(CTESTS:S/$/&_p/) $(BTESTS:S/$/&_p/)
+tests_s : $(CTESTS:S/$/&_s/) $(BTESTS:S/$/&_s/)
+
+tests : tests_a tests_p tests_s
+
+check_a : tests_a
+.for bin in $(CTESTS) $(BTESTS)
+ @cp $(bin)_a $(bin)
+.endfor
+ @echo "Test static library:"
+ @$(VERIFY) $(VFLAGS) $(CTESTS) $(PTESTS)
+
+check_p : tests_p
+.for bin in $(CTESTS) $(BTESTS)
+ @cp $(bin)_p $(bin)
+.endfor
+ @echo "Test profile library:"
+ @$(VERIFY) $(VFLAGS) $(CTESTS) $(PTESTS)
+
+check_s : tests_s
+.for bin in $(CTESTS) $(BTESTS)
+ @cp $(bin)_s $(bin)
+.endfor
+ @echo "Test shared library:"
+ @$(VERIFY) $(VFLAGS) $(CTESTS) $(PTESTS)
+
+check : check_a check_p check_s
+
+clean :
+ rm -f *~
+ rm -f *.core
+ rm -f *.out
+ rm -f *.perf
+ rm -f *.diff
+ rm -f *.gmon
+ rm -f $(CTESTS) $(BTESTS)
+ rm -f $(CTESTS:S/$/&_a/) $(BTESTS:S/$/&_a/)
+ rm -f $(CTESTS:S/$/&_p/) $(BTESTS:S/$/&_p/)
+ rm -f $(CTESTS:S/$/&_s/) $(BTESTS:S/$/&_s/)
+ rm -f *.d
+ rm -f *.o
diff --git a/lib/libkse/test/README b/lib/libkse/test/README
new file mode 100644
index 0000000..8f625a1
--- /dev/null
+++ b/lib/libkse/test/README
@@ -0,0 +1,28 @@
+$FreeBSD$
+
+This test suite is meant to test general functionality of pthreads, as well as
+provide a simple framework for regression tests. In general, this test suite
+can be used with any pthreads library, but in reality there are a number of
+libpthread-specific aspects to this test suite which would require some
+effort to get around if testing another pthreads library.
+
+This test suite assumes that libpthread is installed.
+
+There are two forms of test that the 'verify' script understands. The simpler
+form is the diff format, where the output of the test program is diff'ed with
+the correspondingly named .exp file. If there is diff output, the test fails.
+The sequence test format is somewhat more complex, and is documented in the
+command line usage output for verify. The advantage of this format is that it
+allows multiple tests to pass/fail within one program.
+
+There is no driving need for test naming consistency, but the existing tests
+generally follow these conventions:
+
+<name>_d.c <name>_d.exp : Diff mode C test and expected output file.
+<name>_s.c : Sequence mode C test.
+<name>_b*.c : Back end C program used by perl tests.
+<name>_d.pl <name>_d.pl.exp : Diff mode perl test and expected output file.
+<name>_s.pl : Sequence mode perl test.
+
+<name> is something descriptive, such as "pr14685" in the case of a PR-related
+regression test, or "mutex" in the case of a test of mutexes.
diff --git a/lib/libkse/test/guard_b.c b/lib/libkse/test/guard_b.c
new file mode 100644
index 0000000..2e27031
--- /dev/null
+++ b/lib/libkse/test/guard_b.c
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2001 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
+ * unmodified other than the allowable 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$
+ *
+ * Test thread stack guard functionality.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <pthread.h>
+
+#define FRAME_SIZE 1024
+#define FRAME_OVERHEAD 40
+
+struct args
+{
+ void *top; /* Top of thread's initial stack frame. */
+ int cur; /* Recursion depth. */
+ int max; /* Maximum recursion depth. */
+};
+
+void *
+recurse(void *args)
+{
+ int top;
+ struct args *parms = (struct args *)args;
+ char filler[FRAME_SIZE - FRAME_OVERHEAD];
+
+ /* Touch the memory in this stack frame. */
+ top = 0xa5;
+ memset(filler, 0xa5, sizeof(filler));
+
+ if (parms->top == NULL) {
+ /* Initial stack frame. */
+ parms->top = (void*)&top;
+ }
+
+ /*
+ * Make sure frame size is what we expect. Getting this right involves
+ * hand tweaking, so just print a warning rather than aborting.
+ */
+ if (parms->top - (void *)&top != FRAME_SIZE * parms->cur) {
+ fprintf(stderr,
+ "Stack size (%ld) != expected (%ld), frame %ld\n",
+ (long)parms->top - (long)&top,
+ (long)(FRAME_SIZE * parms->cur), (long)parms->cur);
+ }
+
+ parms->cur++;
+ if (parms->cur < parms->max)
+ recurse(args);
+
+ return NULL;
+}
+
+
+int
+main(int argc, char **argv)
+{
+ size_t def_stacksize, def_guardsize;
+ size_t stacksize, guardsize;
+ pthread_t thread;
+ pthread_attr_t attr;
+ struct args args;
+
+ if (argc != 3) {
+ fprintf(stderr, "usage: guard_b <stacksize> <guardsize>\n");
+ exit(1);
+ }
+ fprintf(stderr, "Test begin\n");
+
+ stacksize = strtoul(argv[1], NULL, 10);
+ guardsize = strtoul(argv[2], NULL, 10);
+
+ assert(pthread_attr_init(&attr) == 0);
+ /*
+ * Exercise the attribute APIs more thoroughly than is strictly
+ * necessary for the meat of this test program.
+ */
+ assert(pthread_attr_getstacksize(&attr, &def_stacksize) == 0);
+ assert(pthread_attr_getguardsize(&attr, &def_guardsize) == 0);
+ if (def_stacksize != stacksize) {
+ assert(pthread_attr_setstacksize(&attr, stacksize) == 0);
+ assert(pthread_attr_getstacksize(&attr, &def_stacksize) == 0);
+ assert(def_stacksize == stacksize);
+ }
+ if (def_guardsize != guardsize) {
+ assert(pthread_attr_setguardsize(&attr, guardsize) == 0);
+ assert(pthread_attr_getguardsize(&attr, &def_guardsize) == 0);
+ assert(def_guardsize >= guardsize);
+ }
+
+ /*
+ * Create a thread that will come just short of overflowing the thread
+ * stack. We need to leave a bit of breathing room in case the thread
+ * is context switched, and we also have to take care not to call any
+ * functions in the deepest stack frame.
+ */
+ args.top = NULL;
+ args.cur = 0;
+ args.max = (stacksize / FRAME_SIZE) - 1;
+ fprintf(stderr, "No overflow:\n");
+ assert(pthread_create(&thread, &attr, recurse, &args) == 0);
+ assert(pthread_join(thread, NULL) == 0);
+
+ /*
+ * Create a thread that will barely of overflow the thread stack. This
+ * should cause a segfault.
+ */
+ args.top = NULL;
+ args.cur = 0;
+ args.max = (stacksize / FRAME_SIZE) + 1;
+ fprintf(stderr, "Overflow:\n");
+ assert(pthread_create(&thread, &attr, recurse, &args) == 0);
+ assert(pthread_join(thread, NULL) == 0);
+
+ /* Not reached. */
+ fprintf(stderr, "Unexpected success\n");
+ abort();
+
+ return 0;
+}
diff --git a/lib/libkse/test/guard_b.exp b/lib/libkse/test/guard_b.exp
new file mode 100644
index 0000000..8e5b9e4
--- /dev/null
+++ b/lib/libkse/test/guard_b.exp
@@ -0,0 +1,3 @@
+Test begin
+No overflow:
+Overflow:
diff --git a/lib/libkse/test/guard_s.pl b/lib/libkse/test/guard_s.pl
new file mode 100644
index 0000000..7802ff3
--- /dev/null
+++ b/lib/libkse/test/guard_s.pl
@@ -0,0 +1,69 @@
+#!/usr/bin/perl -w
+#
+# Copyright (C) 2001 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
+# unmodified other than the allowable 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$
+#
+# Test thread stack guard functionality. The C test program needs to be driven
+# by this script because it segfaults when the stack guard is hit.
+#
+
+print "1..30\n";
+
+$i = 0;
+# Iterates 10 times.
+for ($stacksize = 65536; $stacksize < 131072; $stacksize += 7168)
+{
+ # Iterates 3 times (1024, 4096, 7168).
+ for ($guardsize = 1024; $guardsize < 8192; $guardsize += 3072)
+ {
+ $i++;
+
+ print "stacksize: $stacksize, guardsize: $guardsize\n";
+
+ `./guard_b $stacksize $guardsize >guard_b.out 2>&1`;
+
+ if (! -f "./guard_b.out")
+ {
+ print "not ok $i\n";
+ }
+ else
+ {
+ `diff guard_b.exp guard_b.out >guard_b.diff 2>&1`;
+ if ($?)
+ {
+ # diff returns non-zero if there is a difference.
+ print "not ok $i\n";
+ }
+ else
+ {
+ print "ok $i\n";
+ }
+ }
+ }
+}
diff --git a/lib/libkse/test/hello_b.c b/lib/libkse/test/hello_b.c
new file mode 100644
index 0000000..2eefa7f
--- /dev/null
+++ b/lib/libkse/test/hello_b.c
@@ -0,0 +1,13 @@
+/****************************************************************************
+ *
+ * Back end C programs can be anything compilable.
+ *
+ * $FreeBSD$
+ *
+ ****************************************************************************/
+
+int
+main()
+{
+ return 0;
+}
diff --git a/lib/libkse/test/hello_d.c b/lib/libkse/test/hello_d.c
new file mode 100644
index 0000000..6d77526
--- /dev/null
+++ b/lib/libkse/test/hello_d.c
@@ -0,0 +1,38 @@
+/****************************************************************************
+ *
+ * Simple diff mode test.
+ *
+ * $FreeBSD$
+ *
+ ****************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <pthread.h>
+
+void *
+entry(void * a_arg)
+{
+ fprintf(stderr, "Hello world\n");
+
+ return NULL;
+}
+
+int
+main()
+{
+ pthread_t thread;
+ int error;
+
+ error = pthread_create(&thread, NULL, entry, NULL);
+ if (error)
+ fprintf(stderr, "Error in pthread_create(): %s\n",
+ strerror(error));
+
+ error = pthread_join(thread, NULL);
+ if (error)
+ fprintf(stderr, "Error in pthread_join(): %s\n",
+ strerror(error));
+
+ return 0;
+}
diff --git a/lib/libkse/test/hello_d.exp b/lib/libkse/test/hello_d.exp
new file mode 100644
index 0000000..802992c
--- /dev/null
+++ b/lib/libkse/test/hello_d.exp
@@ -0,0 +1 @@
+Hello world
diff --git a/lib/libkse/test/hello_s.c b/lib/libkse/test/hello_s.c
new file mode 100644
index 0000000..942bf2d
--- /dev/null
+++ b/lib/libkse/test/hello_s.c
@@ -0,0 +1,47 @@
+/****************************************************************************
+ *
+ * Simple sequence mode test.
+ *
+ * $FreeBSD$
+ *
+ ****************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <pthread.h>
+
+void *
+entry(void * a_arg)
+{
+ fprintf(stderr, "ok 1\n");
+ fprintf(stderr, "ok \n");
+ fprintf(stderr, "ok 3\n");
+
+ return NULL;
+}
+
+int
+main()
+{
+ pthread_t thread;
+ int error;
+
+ fprintf(stderr, "1..3\n");
+
+ fprintf(stderr, "Some random text\n");
+
+ error = pthread_create(&thread, NULL, entry, NULL);
+ fprintf(stderr, "More unimportant text\n");
+ if (error)
+ fprintf(stderr,"Error in pthread_create(): %s\n",
+ strerror(error));
+
+ error = pthread_join(thread, NULL);
+ if (error)
+ fprintf(stderr, "Error in pthread_join(): %s\n",
+ strerror(error));
+
+ fprintf(stderr, "Hello world\n");
+
+ return 0;
+}
diff --git a/lib/libkse/test/join_leak_d.c b/lib/libkse/test/join_leak_d.c
new file mode 100644
index 0000000..6532ca5
--- /dev/null
+++ b/lib/libkse/test/join_leak_d.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2001 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$
+ *
+ * Test for leaked joined threads.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <errno.h>
+#include <string.h>
+#include <pthread.h>
+
+#define NITERATIONS 16384
+#define MAXGROWTH 16384
+
+void *
+thread_entry(void *a_arg)
+{
+ return NULL;
+}
+
+int
+main(void)
+{
+ pthread_t thread;
+ int i, error;
+ char *brk, *nbrk;
+ unsigned growth;
+
+ fprintf(stderr, "Test begin\n");
+
+ /* Get an initial brk value. */
+ brk = sbrk(0);
+
+ /* Create threads and join them, one at a time. */
+ for (i = 0; i < NITERATIONS; i++) {
+ if ((error = pthread_create(&thread, NULL, thread_entry, NULL))
+ != 0) {
+ fprintf(stderr, "Error in pthread_create(): %s\n",
+ strerror(error));
+ exit(1);
+ }
+ if ((error = pthread_join(thread, NULL)) != 0) {
+ fprintf(stderr, "Error in pthread_join(): %s\n",
+ strerror(error));
+ exit(1);
+ }
+ }
+
+ /* Get a final brk value. */
+ nbrk = sbrk(0);
+
+ /*
+ * Check that the amount of heap space allocated is below an acceptable
+ * threshold. We could just compare brk and nbrk, but the test could
+ * conceivably break if the internals of the threads library changes.
+ */
+ if (nbrk > brk) {
+ /* Heap grows up. */
+ growth = nbrk - brk;
+ } else if (nbrk <= brk) {
+ /* Heap grows down, or no growth. */
+ growth = brk - nbrk;
+ }
+
+ if (growth > MAXGROWTH) {
+ fprintf(stderr, "Heap growth exceeded maximum (%u > %u)\n",
+ growth, MAXGROWTH);
+ }
+#if (0)
+ else {
+ fprintf(stderr, "Heap growth acceptable (%u <= %u)\n",
+ growth, MAXGROWTH);
+ }
+#endif
+
+ fprintf(stderr, "Test end\n");
+ return 0;
+}
diff --git a/lib/libkse/test/join_leak_d.exp b/lib/libkse/test/join_leak_d.exp
new file mode 100644
index 0000000..369a88d
--- /dev/null
+++ b/lib/libkse/test/join_leak_d.exp
@@ -0,0 +1,2 @@
+Test begin
+Test end
diff --git a/lib/libkse/test/mutex_d.c b/lib/libkse/test/mutex_d.c
new file mode 100644
index 0000000..2aa3b1d
--- /dev/null
+++ b/lib/libkse/test/mutex_d.c
@@ -0,0 +1,1558 @@
+/*
+ * Copyright (c) 1998 Daniel M. Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel M. Eischen.
+ * 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 DANIEL M. 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <assert.h>
+#include <errno.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <sysexits.h>
+#include "pthread.h"
+
+#if defined(_LIBC_R_)
+#include <pthread_np.h>
+#endif
+
+#ifndef NELEMENTS
+#define NELEMENTS(arr) (sizeof (arr) / sizeof (arr[0]))
+#endif
+
+#ifndef NUM_THREADS
+#define NUM_THREADS 10
+#endif
+
+#define MAX_THREAD_CMDS 10
+
+static void log_error(const char *, ...) __printflike(1, 2);
+static void log_trace (const char *, ...) __printflike(1, 2);
+static void log (const char *, ...) __printflike(1, 2);
+
+/*------------------------------------------------------------
+ * Types
+ *----------------------------------------------------------*/
+
+typedef enum {
+ STAT_INITIAL, /* initial state */
+ STAT_WAITCONDVAR, /* waiting for condition variable signal */
+ STAT_WAITMUTEX /* waiting for mutex lock */
+} thread_status_t;
+
+typedef enum {
+ FLAGS_REPORT_WAITCONDMUTEX = 0x01,
+ FLAGS_REPORT_WAITCONDVAR = 0x02,
+ FLAGS_REPORT_WAITMUTEX = 0x04,
+ FLAGS_REPORT_BUSY_LOOP = 0x08,
+ FLAGS_IS_BUSY = 0x10,
+ FLAGS_WAS_BUSY = 0x20
+} thread_flags_t;
+
+typedef enum {
+ CMD_NONE,
+ CMD_TAKE_MUTEX,
+ CMD_RELEASE_MUTEX,
+ CMD_WAIT_FOR_SIGNAL,
+ CMD_BUSY_LOOP,
+ CMD_PROTECTED_OP,
+ CMD_RELEASE_ALL
+} thread_cmd_id_t;
+
+typedef struct {
+ thread_cmd_id_t cmd_id;
+ pthread_mutex_t *mutex;
+ pthread_cond_t *cond;
+} thread_cmd_t;
+
+typedef struct {
+ pthread_cond_t cond_var;
+ thread_status_t status;
+ thread_cmd_t cmd;
+ int flags;
+ int priority;
+ int ret;
+ pthread_t tid;
+ u_int8_t id;
+} thread_state_t;
+
+typedef enum {
+ M_POSIX,
+ M_SS2_DEFAULT,
+ M_SS2_ERRORCHECK,
+ M_SS2_NORMAL,
+ M_SS2_RECURSIVE
+} mutex_kind_t;
+
+
+/*------------------------------------------------------------
+ * Constants
+ *----------------------------------------------------------*/
+
+const char *protocol_strs[] = {
+ "PTHREAD_PRIO_NONE",
+ "PTHREAD_PRIO_INHERIT",
+ "PTHREAD_PRIO_PROTECT"
+};
+
+const int protocols[] = {
+ PTHREAD_PRIO_NONE,
+ PTHREAD_PRIO_INHERIT,
+ PTHREAD_PRIO_PROTECT
+};
+
+const char *mutextype_strs[] = {
+ "POSIX (type not specified)",
+ "SS2 PTHREAD_MUTEX_DEFAULT",
+ "SS2 PTHREAD_MUTEX_ERRORCHECK",
+ "SS2 PTHREAD_MUTEX_NORMAL",
+ "SS2 PTHREAD_MUTEX_RECURSIVE"
+};
+
+const int mutex_types[] = {
+ 0, /* M_POSIX */
+ PTHREAD_MUTEX_DEFAULT, /* M_SS2_DEFAULT */
+ PTHREAD_MUTEX_ERRORCHECK, /* M_SS2_ERRORCHECK */
+ PTHREAD_MUTEX_NORMAL, /* M_SS2_NORMAL */
+ PTHREAD_MUTEX_RECURSIVE /* M_SS2_RECURSIVE */
+};
+
+
+/*------------------------------------------------------------
+ * Objects
+ *----------------------------------------------------------*/
+
+static int done = 0;
+static int trace_enabled = 0;
+static int use_global_condvar = 0;
+static thread_state_t states[NUM_THREADS];
+static int pipefd[2];
+
+static pthread_mutex_t waiter_mutex;
+static pthread_mutex_t cond_mutex;
+static pthread_cond_t cond_var;
+
+static FILE *logfile;
+static int error_count = 0, pass_count = 0, total = 0;
+
+
+/*------------------------------------------------------------
+ * Prototypes
+ *----------------------------------------------------------*/
+extern char *strtok_r(char *str, const char *sep, char **last);
+
+
+/*------------------------------------------------------------
+ * Functions
+ *----------------------------------------------------------*/
+
+#if defined(_LIBC_R_) && defined(DEBUG)
+static void
+kern_switch (pthread_t pthread_out, pthread_t pthread_in)
+{
+ if (pthread_out != NULL)
+ printf ("Swapping out thread 0x%lx, ", (long) pthread_out);
+ else
+ printf ("Swapping out kernel thread, ");
+
+ if (pthread_in != NULL)
+ printf ("swapping in thread 0x%lx\n", (long) pthread_in);
+ else
+ printf ("swapping in kernel thread.\n");
+}
+#endif
+
+
+static void
+log_error (const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start (ap, fmt);
+ fprintf (logfile, "FAIL: ");
+ vfprintf (logfile, fmt, ap);
+ error_count = error_count + 1;
+ total = total + 1;
+}
+
+
+static void
+log_pass (void)
+{
+ fprintf (logfile, "PASS\n");
+ pass_count = pass_count + 1;
+ total = total + 1;
+}
+
+
+static void
+log_trace (const char *fmt, ...)
+{
+ va_list ap;
+
+ if (trace_enabled) {
+ va_start (ap, fmt);
+ vfprintf (logfile, fmt, ap);
+ }
+}
+
+
+static void
+log (const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start (ap, fmt);
+ vfprintf (logfile, fmt, ap);
+}
+
+
+static void
+check_result (int expected, int actual)
+{
+ if (expected != actual)
+ log_error ("expected %d, returned %d\n", expected, actual);
+ else
+ log_pass ();
+}
+
+
+/*
+ * Check to see that the threads ran in the specified order.
+ */
+static void
+check_run_order (char *order)
+{
+ const char *sep = ":,";
+ char *tok, *last, *idstr, *endptr;
+ int expected_id, bytes, count = 0, errors = 0;
+ u_int8_t id;
+
+ assert ((tok = (char *) malloc (strlen(order) + 1)) != NULL);
+ strcpy (tok, order); /* tok has to be larger than order */
+ assert (ioctl (pipefd[0], FIONREAD, &bytes) == 0);
+ log_trace ("%d bytes read from FIFO.\n", bytes);
+
+ for (idstr = strtok_r (tok, sep, &last);
+ (idstr != NULL) && (count < bytes);
+ idstr = strtok_r (NULL, sep, &last)) {
+
+ /* Get the expected id: */
+ expected_id = (int) strtol (idstr, &endptr, 10);
+ assert ((endptr != NULL) && (*endptr == '\0'));
+
+ /* Read the actual id from the pipe: */
+ assert (read (pipefd[0], &id, sizeof (id)) == sizeof (id));
+ count = count + sizeof (id);
+
+ if (id != expected_id) {
+ log_trace ("Thread %d ran out of order.\n", id);
+ errors = errors + 1;
+ }
+ else {
+ log_trace ("Thread %d at priority %d reporting.\n",
+ (int) id, states[id].priority);
+ }
+ }
+
+ if (count < bytes) {
+ /* Clear the pipe: */
+ while (count < bytes) {
+ read (pipefd[0], &id, sizeof (id));
+ count = count + 1;
+ errors = errors + 1;
+ }
+ }
+ else if (bytes < count)
+ errors = errors + count - bytes;
+
+ if (errors == 0)
+ log_pass ();
+ else
+ log_error ("%d threads ran out of order", errors);
+}
+
+
+static void *
+waiter (void *arg)
+{
+ thread_state_t *statep = (thread_state_t *) arg;
+ pthread_mutex_t *held_mutex[MAX_THREAD_CMDS];
+ int held_mutex_owned[MAX_THREAD_CMDS];
+ sigset_t mask;
+ struct timeval tv1, tv2;
+ thread_cmd_t cmd;
+ int i, mutex_count = 0;
+
+ statep->status = STAT_INITIAL;
+
+ /* Block all signals except for interrupt.*/
+ sigfillset (&mask);
+ sigdelset (&mask, SIGINT);
+ sigprocmask (SIG_BLOCK, &mask, NULL);
+
+ while (done == 0) {
+ /* Wait for signal from the main thread to continue. */
+ statep->status = STAT_WAITMUTEX;
+ log_trace ("Thread %d: locking cond_mutex.\n",
+ (int) statep->id);
+ pthread_mutex_lock (&cond_mutex);
+
+ /* Do we report our status. */
+ if (statep->flags & FLAGS_REPORT_WAITCONDMUTEX)
+ write (pipefd[1], &statep->id, sizeof (statep->id));
+ log_trace ("Thread %d: waiting for cond_var.\n",
+ (int) statep->id);
+
+ /* Wait for a command. */
+ statep->status = STAT_WAITCONDVAR;
+
+ /*
+ * The threads are allowed commanded to wait either on
+ * their own unique condition variable (so they may be
+ * separately signaled) or on one global condition variable
+ * (so they may be signaled together).
+ */
+ if (use_global_condvar != 0)
+ pthread_cond_wait (&cond_var, &cond_mutex);
+ else
+ pthread_cond_wait (&statep->cond_var, &cond_mutex);
+
+ /* Do we report our status? */
+ if (statep->flags & FLAGS_REPORT_WAITCONDVAR) {
+ write (pipefd[1], &statep->id, sizeof (statep->id));
+ log_trace ("Thread %d: wrote to pipe.\n",
+ (int) statep->id);
+ }
+ log_trace ("Thread %d: received cond_var signal.\n",
+ (int) statep->id);
+
+ /* Get a copy of the command before releasing the mutex. */
+ cmd = statep->cmd;
+
+ /* Clear the command after copying it. */
+ statep->cmd.cmd_id = CMD_NONE;
+
+ /* Unlock the condition variable mutex. */
+ assert (pthread_mutex_unlock (&cond_mutex) == 0);
+
+ /* Peform the command.*/
+ switch (cmd.cmd_id) {
+ case CMD_TAKE_MUTEX:
+ statep->ret = pthread_mutex_lock (cmd.mutex);
+ if (statep->ret == 0) {
+ assert (mutex_count < sizeof (held_mutex));
+ held_mutex[mutex_count] = cmd.mutex;
+ held_mutex_owned[mutex_count] = 1;
+ mutex_count++;
+ }
+ else {
+ held_mutex_owned[mutex_count] = 0;
+ log_trace ("Thread id %d unable to lock mutex, "
+ "error = %d\n", (int) statep->id,
+ statep->ret);
+ }
+ break;
+
+ case CMD_RELEASE_MUTEX:
+ assert ((mutex_count <= sizeof (held_mutex)) &&
+ (mutex_count > 0));
+ mutex_count--;
+ if (held_mutex_owned[mutex_count] != 0)
+ assert (pthread_mutex_unlock
+ (held_mutex[mutex_count]) == 0);
+ break;
+
+ case CMD_WAIT_FOR_SIGNAL:
+ assert (pthread_mutex_lock (cmd.mutex) == 0);
+ assert (pthread_cond_wait (cmd.cond, cmd.mutex) == 0);
+ assert (pthread_mutex_unlock (cmd.mutex) == 0);
+ break;
+
+ case CMD_BUSY_LOOP:
+ log_trace ("Thread %d: Entering busy loop.\n",
+ (int) statep->id);
+ /* Spin for 15 seconds. */
+ assert (gettimeofday (&tv2, NULL) == 0);
+ tv1.tv_sec = tv2.tv_sec + 5;
+ tv1.tv_usec = tv2.tv_usec;
+ statep->flags |= FLAGS_IS_BUSY;
+ while (timercmp (&tv2, &tv1,<)) {
+ assert (gettimeofday (&tv2, NULL) == 0);
+ }
+ statep->flags &= ~FLAGS_IS_BUSY;
+ statep->flags |= FLAGS_WAS_BUSY;
+
+ /* Do we report our status? */
+ if (statep->flags & FLAGS_REPORT_BUSY_LOOP)
+ write (pipefd[1], &statep->id,
+ sizeof (statep->id));
+
+ log_trace ("Thread %d: Leaving busy loop.\n",
+ (int) statep->id);
+ break;
+
+ case CMD_PROTECTED_OP:
+ assert (pthread_mutex_lock (cmd.mutex) == 0);
+ statep->flags |= FLAGS_WAS_BUSY;
+ /* Do we report our status? */
+ if (statep->flags & FLAGS_REPORT_BUSY_LOOP)
+ write (pipefd[1], &statep->id,
+ sizeof (statep->id));
+
+ assert (pthread_mutex_unlock (cmd.mutex) == 0);
+ break;
+
+ case CMD_RELEASE_ALL:
+ assert ((mutex_count <= sizeof (held_mutex)) &&
+ (mutex_count > 0));
+ for (i = mutex_count - 1; i >= 0; i--) {
+ if (held_mutex_owned[i] != 0)
+ assert (pthread_mutex_unlock
+ (held_mutex[i]) == 0);
+ }
+ mutex_count = 0;
+ break;
+
+ case CMD_NONE:
+ default:
+ break;
+ }
+
+ /* Wait for the big giant waiter lock. */
+ statep->status = STAT_WAITMUTEX;
+ log_trace ("Thread %d: waiting for big giant lock.\n",
+ (int) statep->id);
+ pthread_mutex_lock (&waiter_mutex);
+ if (statep->flags & FLAGS_REPORT_WAITMUTEX)
+ write (pipefd[1], &statep->id, sizeof (statep->id));
+ log_trace ("Thread %d: got big giant lock.\n",
+ (int) statep->id);
+ statep->status = STAT_INITIAL;
+ pthread_mutex_unlock (&waiter_mutex);
+ }
+
+ log_trace ("Thread %ld: Exiting thread 0x%lx\n", (long) statep->id,
+ (long) pthread_self());
+ pthread_exit (arg);
+ return (NULL);
+}
+
+
+static void *
+lock_twice (void *arg)
+{
+ thread_state_t *statep = (thread_state_t *) arg;
+ sigset_t mask;
+
+ statep->status = STAT_INITIAL;
+
+ /* Block all signals except for interrupt.*/
+ sigfillset (&mask);
+ sigdelset (&mask, SIGINT);
+ sigprocmask (SIG_BLOCK, &mask, NULL);
+
+ /* Wait for a signal to continue. */
+ log_trace ("Thread %d: locking cond_mutex.\n", (int) statep->id);
+ pthread_mutex_lock (&cond_mutex);
+
+ log_trace ("Thread %d: waiting for cond_var.\n", (int) statep->id);
+ statep->status = STAT_WAITCONDVAR;
+ pthread_cond_wait (&cond_var, &cond_mutex);
+
+ log_trace ("Thread %d: received cond_var signal.\n", (int) statep->id);
+
+ /* Unlock the condition variable mutex. */
+ assert (pthread_mutex_unlock (&cond_mutex) == 0);
+
+ statep->status = STAT_WAITMUTEX;
+ /* Lock the mutex once. */
+ assert (pthread_mutex_lock (statep->cmd.mutex) == 0);
+
+ /* Lock it again and capture the error. */
+ statep->ret = pthread_mutex_lock (statep->cmd.mutex);
+ statep->status = 0;
+
+ assert (pthread_mutex_unlock (statep->cmd.mutex) == 0);
+
+ /* Unlock it again if it is locked recursively. */
+ if (statep->ret == 0)
+ pthread_mutex_unlock (statep->cmd.mutex);
+
+ log_trace ("Thread %ld: Exiting thread 0x%lx\n", (long) statep->id,
+ (long) pthread_self());
+ pthread_exit (arg);
+ return (NULL);
+}
+
+
+static void
+sighandler (int signo)
+{
+ log ("Signal handler caught signal %d, thread id 0x%lx\n",
+ signo, (long) pthread_self());
+
+ if (signo == SIGINT)
+ done = 1;
+}
+
+
+static void
+send_cmd (int id, thread_cmd_id_t cmd)
+{
+ assert (pthread_mutex_lock (&cond_mutex) == 0);
+ assert (states[id].status == STAT_WAITCONDVAR);
+ states[id].cmd.cmd_id = cmd;
+ states[id].cmd.mutex = NULL;
+ states[id].cmd.cond = NULL;
+ /* Clear the busy flags. */
+ states[id].flags &= ~(FLAGS_WAS_BUSY | FLAGS_IS_BUSY);
+ assert (pthread_cond_signal (&states[id].cond_var) == 0);
+ assert (pthread_mutex_unlock (&cond_mutex) == 0);
+}
+
+
+static void
+send_mutex_cmd (int id, thread_cmd_id_t cmd, pthread_mutex_t *m)
+{
+ assert (pthread_mutex_lock (&cond_mutex) == 0);
+ assert (states[id].status == STAT_WAITCONDVAR);
+ states[id].cmd.cmd_id = cmd;
+ states[id].cmd.mutex = m;
+ states[id].cmd.cond = NULL;
+ /* Clear the busy flags. */
+ states[id].flags &= ~(FLAGS_WAS_BUSY | FLAGS_IS_BUSY);
+ assert (pthread_cond_signal (&states[id].cond_var) == 0);
+ assert (pthread_mutex_unlock (&cond_mutex) == 0);
+}
+
+
+static void
+send_mutex_cv_cmd (int id, thread_cmd_id_t cmd, pthread_mutex_t *m,
+ pthread_cond_t *cv)
+{
+ assert (pthread_mutex_lock (&cond_mutex) == 0);
+ assert (states[id].status == STAT_WAITCONDVAR);
+ states[id].cmd.cmd_id = cmd;
+ states[id].cmd.mutex = m;
+ states[id].cmd.cond = cv;
+ /* Clear the busy flags. */
+ states[id].flags &= ~(FLAGS_WAS_BUSY | FLAGS_IS_BUSY);
+ assert (pthread_cond_signal (&states[id].cond_var) == 0);
+ assert (pthread_mutex_unlock (&cond_mutex) == 0);
+}
+
+
+static void
+mutex_init_test (void)
+{
+ pthread_mutexattr_t mattr;
+ pthread_mutex_t mutex;
+ mutex_kind_t mkind;
+ int mproto, ret;
+
+ /*
+ * Initialize a mutex attribute.
+ *
+ * pthread_mutexattr_init not tested for: ENOMEM
+ */
+ assert (pthread_mutexattr_init (&mattr) == 0);
+
+ /*
+ * Initialize a mutex.
+ *
+ * pthread_mutex_init not tested for: EAGAIN ENOMEM EPERM EBUSY
+ */
+ log ("Testing pthread_mutex_init\n");
+ log ("--------------------------\n");
+
+ for (mproto = 0; mproto < NELEMENTS(protocols); mproto++) {
+ for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) {
+ /* Initialize the mutex attribute. */
+ assert (pthread_mutexattr_init (&mattr) == 0);
+ assert (pthread_mutexattr_setprotocol (&mattr,
+ protocols[mproto]) == 0);
+
+ /*
+ * Ensure that the first mutex type is a POSIX
+ * compliant mutex.
+ */
+ if (mkind != M_POSIX) {
+ assert (pthread_mutexattr_settype (&mattr,
+ mutex_types[mkind]) == 0);
+ }
+
+ log (" Protocol %s, Type %s - ",
+ protocol_strs[mproto], mutextype_strs[mkind]);
+ ret = pthread_mutex_init (&mutex, &mattr);
+ check_result (/* expected */ 0, ret);
+ assert (pthread_mutex_destroy (&mutex) == 0);
+
+ /*
+ * Destroy a mutex attribute.
+ *
+ * XXX - There should probably be a magic number
+ * associated with a mutex attribute so that
+ * destroy can be reasonably sure the attribute
+ * is valid.
+ *
+ * pthread_mutexattr_destroy not tested for: EINVAL
+ */
+ assert (pthread_mutexattr_destroy (&mattr) == 0);
+ }
+ }
+}
+
+
+static void
+mutex_destroy_test (void)
+{
+ pthread_mutexattr_t mattr;
+ pthread_mutex_t mutex;
+ pthread_condattr_t cattr;
+ pthread_cond_t cv;
+ pthread_attr_t pattr;
+ int mproto, ret;
+ mutex_kind_t mkind;
+ thread_state_t state;
+
+ /*
+ * Destroy a mutex.
+ *
+ * XXX - There should probably be a magic number associated
+ * with a mutex so that destroy can be reasonably sure
+ * the mutex is valid.
+ *
+ * pthread_mutex_destroy not tested for:
+ */
+ log ("Testing pthread_mutex_destroy\n");
+ log ("-----------------------------\n");
+
+ assert (pthread_attr_init (&pattr) == 0);
+ assert (pthread_attr_setdetachstate (&pattr,
+ PTHREAD_CREATE_DETACHED) == 0);
+ state.flags = 0; /* No flags yet. */
+
+ for (mproto = 0; mproto < NELEMENTS(protocols); mproto++) {
+ for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) {
+ /* Initialize the mutex attribute. */
+ assert (pthread_mutexattr_init (&mattr) == 0);
+ assert (pthread_mutexattr_setprotocol (&mattr,
+ protocols[mproto]) == 0);
+
+ /*
+ * Ensure that the first mutex type is a POSIX
+ * compliant mutex.
+ */
+ if (mkind != M_POSIX) {
+ assert (pthread_mutexattr_settype (&mattr,
+ mutex_types[mkind]) == 0);
+ }
+
+ /* Create the mutex. */
+ assert (pthread_mutex_init (&mutex, &mattr) == 0);
+
+ log (" Protocol %s, Type %s\n",
+ protocol_strs[mproto], mutextype_strs[mkind]);
+
+ log (" Destruction of unused mutex - ");
+ assert (pthread_mutex_init (&mutex, &mattr) == 0);
+ ret = pthread_mutex_destroy (&mutex);
+ check_result (/* expected */ 0, ret);
+
+ log (" Destruction of mutex locked by self - ");
+ assert (pthread_mutex_init (&mutex, &mattr) == 0);
+ assert (pthread_mutex_lock (&mutex) == 0);
+ ret = pthread_mutex_destroy (&mutex);
+ check_result (/* expected */ EBUSY, ret);
+ assert (pthread_mutex_unlock (&mutex) == 0);
+ assert (pthread_mutex_destroy (&mutex) == 0);
+
+ log (" Destruction of mutex locked by another "
+ "thread - ");
+ assert (pthread_mutex_init (&mutex, &mattr) == 0);
+ send_mutex_cmd (0, CMD_TAKE_MUTEX, &mutex);
+ sleep (1);
+ ret = pthread_mutex_destroy (&mutex);
+ check_result (/* expected */ EBUSY, ret);
+ send_cmd (0, CMD_RELEASE_ALL);
+ sleep (1);
+ assert (pthread_mutex_destroy (&mutex) == 0);
+
+ log (" Destruction of mutex while being used in "
+ "cond_wait - ");
+ assert (pthread_mutex_init (&mutex, &mattr) == 0);
+ assert (pthread_condattr_init (&cattr) == 0);
+ assert (pthread_cond_init (&cv, &cattr) == 0);
+ send_mutex_cv_cmd (0, CMD_WAIT_FOR_SIGNAL, &mutex, &cv);
+ sleep (1);
+ ret = pthread_mutex_destroy (&mutex);
+ check_result (/* expected */ EBUSY, ret);
+ pthread_cond_signal (&cv);
+ sleep (1);
+ assert (pthread_mutex_destroy (&mutex) == 0);
+ }
+ }
+}
+
+
+static void
+mutex_lock_test (void)
+{
+ pthread_mutexattr_t mattr;
+ pthread_mutex_t mutex;
+ pthread_attr_t pattr;
+ int mproto, ret;
+ mutex_kind_t mkind;
+ thread_state_t state;
+
+ /*
+ * Lock a mutex.
+ *
+ * pthread_lock not tested for:
+ */
+ log ("Testing pthread_mutex_lock\n");
+ log ("--------------------------\n");
+
+ assert (pthread_attr_init (&pattr) == 0);
+ assert (pthread_attr_setdetachstate (&pattr,
+ PTHREAD_CREATE_DETACHED) == 0);
+ state.flags = 0; /* No flags yet. */
+
+ for (mproto = 0; mproto < NELEMENTS(protocols); mproto++) {
+ for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) {
+ /* Initialize the mutex attribute. */
+ assert (pthread_mutexattr_init (&mattr) == 0);
+ assert (pthread_mutexattr_setprotocol (&mattr,
+ protocols[mproto]) == 0);
+
+ /*
+ * Ensure that the first mutex type is a POSIX
+ * compliant mutex.
+ */
+ if (mkind != M_POSIX) {
+ assert (pthread_mutexattr_settype (&mattr,
+ mutex_types[mkind]) == 0);
+ }
+
+ /* Create the mutex. */
+ assert (pthread_mutex_init (&mutex, &mattr) == 0);
+
+ log (" Protocol %s, Type %s\n",
+ protocol_strs[mproto], mutextype_strs[mkind]);
+
+ log (" Lock on unlocked mutex - ");
+ ret = pthread_mutex_lock (&mutex);
+ check_result (/* expected */ 0, ret);
+ pthread_mutex_unlock (&mutex);
+
+ log (" Lock on invalid mutex - ");
+ ret = pthread_mutex_lock (NULL);
+ check_result (/* expected */ EINVAL, ret);
+
+ log (" Lock on mutex held by self - ");
+ assert (pthread_create (&state.tid, &pattr, lock_twice,
+ (void *) &state) == 0);
+ /* Let the thread start. */
+ sleep (1);
+ state.cmd.mutex = &mutex;
+ state.ret = 0xdeadbeef;
+ assert (pthread_mutex_lock (&cond_mutex) == 0);
+ assert (pthread_cond_signal (&cond_var) == 0);
+ assert (pthread_mutex_unlock (&cond_mutex) == 0);
+ /* Let the thread receive and process the command. */
+ sleep (1);
+
+ switch (mkind) {
+ case M_POSIX:
+ check_result (/* expected */ EDEADLK,
+ state.ret);
+ break;
+ case M_SS2_DEFAULT:
+ check_result (/* expected */ EDEADLK,
+ state.ret);
+ break;
+ case M_SS2_ERRORCHECK:
+ check_result (/* expected */ EDEADLK,
+ state.ret);
+ break;
+ case M_SS2_NORMAL:
+ check_result (/* expected */ 0xdeadbeef,
+ state.ret);
+ break;
+ case M_SS2_RECURSIVE:
+ check_result (/* expected */ 0, state.ret);
+ break;
+ }
+ pthread_mutex_destroy (&mutex);
+ pthread_mutexattr_destroy (&mattr);
+ }
+ }
+}
+
+
+static void
+mutex_unlock_test (void)
+{
+ const int test_thread_id = 0; /* ID of test thread */
+ pthread_mutexattr_t mattr;
+ pthread_mutex_t mutex;
+ int mproto, ret;
+ mutex_kind_t mkind;
+
+ /*
+ * Unlock a mutex.
+ *
+ * pthread_unlock not tested for:
+ */
+ log ("Testing pthread_mutex_unlock\n");
+ log ("----------------------------\n");
+
+ for (mproto = 0; mproto < NELEMENTS(protocols); mproto++) {
+ for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) {
+ /* Initialize the mutex attribute. */
+ assert (pthread_mutexattr_init (&mattr) == 0);
+ assert (pthread_mutexattr_setprotocol (&mattr,
+ protocols[mproto]) == 0);
+
+ /*
+ * Ensure that the first mutex type is a POSIX
+ * compliant mutex.
+ */
+ if (mkind != M_POSIX) {
+ assert (pthread_mutexattr_settype (&mattr,
+ mutex_types[mkind]) == 0);
+ }
+
+ /* Create the mutex. */
+ assert (pthread_mutex_init (&mutex, &mattr) == 0);
+
+ log (" Protocol %s, Type %s\n",
+ protocol_strs[mproto], mutextype_strs[mkind]);
+
+ log (" Unlock on mutex held by self - ");
+ assert (pthread_mutex_lock (&mutex) == 0);
+ ret = pthread_mutex_unlock (&mutex);
+ check_result (/* expected */ 0, ret);
+
+ log (" Unlock on invalid mutex - ");
+ ret = pthread_mutex_unlock (NULL);
+ check_result (/* expected */ EINVAL, ret);
+
+ log (" Unlock on mutex locked by another thread - ");
+ send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &mutex);
+ sleep (1);
+ ret = pthread_mutex_unlock (&mutex);
+ switch (mkind) {
+ case M_POSIX:
+ check_result (/* expected */ EPERM, ret);
+ break;
+ case M_SS2_DEFAULT:
+ check_result (/* expected */ EPERM, ret);
+ break;
+ case M_SS2_ERRORCHECK:
+ check_result (/* expected */ EPERM, ret);
+ break;
+ case M_SS2_NORMAL:
+ check_result (/* expected */ EPERM, ret);
+ break;
+ case M_SS2_RECURSIVE:
+ check_result (/* expected */ EPERM, ret);
+ break;
+ }
+ if (ret == 0) {
+ /*
+ * If for some reason we were able to unlock
+ * the mutex, relock it so that the test
+ * thread has no problems releasing the mutex.
+ */
+ pthread_mutex_lock (&mutex);
+ }
+ send_cmd (test_thread_id, CMD_RELEASE_ALL);
+ sleep (1);
+
+ pthread_mutex_destroy (&mutex);
+ pthread_mutexattr_destroy (&mattr);
+ }
+ }
+}
+
+
+static void
+queueing_order_test (void)
+{
+ int i;
+
+ log ("Testing queueing order\n");
+ log ("----------------------\n");
+ assert (pthread_mutex_lock (&waiter_mutex) == 0);
+ /*
+ * Tell the threads to report when they take the waiters mutex.
+ */
+ assert (pthread_mutex_lock (&cond_mutex) == 0);
+ for (i = 0; i < NUM_THREADS; i++) {
+ states[i].flags = FLAGS_REPORT_WAITMUTEX;
+ assert (pthread_cond_signal (&states[i].cond_var) == 0);
+ }
+ assert (pthread_mutex_unlock (&cond_mutex) == 0);
+
+ /* Signal the threads to continue. */
+ sleep (1);
+
+ /* Use the global condition variable next time. */
+ use_global_condvar = 1;
+
+ /* Release the waiting threads and allow them to run again. */
+ assert (pthread_mutex_unlock (&waiter_mutex) == 0);
+ sleep (1);
+
+ log (" Queueing order on a mutex - ");
+ check_run_order ("9,8,7,6,5,4,3,2,1,0");
+ for (i = 0; i < NUM_THREADS; i = i + 1) {
+ /* Tell the threads to report when they've been signaled. */
+ states[i].flags = FLAGS_REPORT_WAITCONDVAR;
+ }
+
+ /*
+ * Prevent the threads from continuing their loop after we
+ * signal them.
+ */
+ assert (pthread_mutex_lock (&waiter_mutex) == 0);
+
+
+ log (" Queueing order on a condition variable - ");
+ /*
+ * Signal one thread to run and see that the highest priority
+ * thread executes.
+ */
+ assert (pthread_mutex_lock (&cond_mutex) == 0);
+ assert (pthread_cond_signal (&cond_var) == 0);
+ assert (pthread_mutex_unlock (&cond_mutex) == 0);
+ sleep (1);
+ if (states[NUM_THREADS - 1].status != STAT_WAITMUTEX)
+ log_error ("highest priority thread does not run.\n");
+
+ /* Signal the remaining threads. */
+ assert (pthread_mutex_lock (&cond_mutex) == 0);
+ assert (pthread_cond_broadcast (&cond_var) == 0);
+ assert (pthread_mutex_unlock (&cond_mutex) == 0);
+ sleep (1);
+
+ check_run_order ("9,8,7,6,5,4,3,2,1,0");
+ for (i = 0; i < NUM_THREADS; i = i + 1) {
+ /* Tell the threads not to report anything. */
+ states[i].flags = 0;
+ }
+
+ /* Use the thread unique condition variable next time. */
+ use_global_condvar = 0;
+
+ /* Allow the threads to continue their loop. */
+ assert (pthread_mutex_unlock (&waiter_mutex) == 0);
+ sleep (1);
+}
+
+
+static void
+mutex_prioceiling_test (void)
+{
+ const int test_thread_id = 0; /* ID of test thread */
+ pthread_mutexattr_t mattr;
+ struct sched_param param;
+ pthread_mutex_t m[3];
+ mutex_kind_t mkind;
+ int i, ret, policy, my_prio, old_ceiling;
+
+ log ("Testing priority ceilings\n");
+ log ("-------------------------\n");
+ for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) {
+
+ log (" Protype PTHREAD_PRIO_PROTECT, Type %s\n",
+ mutextype_strs[mkind]);
+
+ /*
+ * Initialize and create a mutex.
+ */
+ assert (pthread_mutexattr_init (&mattr) == 0);
+
+ /* Get this threads current priority. */
+ assert (pthread_getschedparam (pthread_self(), &policy,
+ &param) == 0);
+ my_prio = param.sched_priority; /* save for later use */
+ log_trace ("Current scheduling policy %d, priority %d\n",
+ policy, my_prio);
+
+ /*
+ * Initialize and create 3 priority protection mutexes with
+ * default (max priority) ceilings.
+ */
+ assert (pthread_mutexattr_setprotocol(&mattr,
+ PTHREAD_PRIO_PROTECT) == 0);
+
+ /*
+ * Ensure that the first mutex type is a POSIX
+ * compliant mutex.
+ */
+ if (mkind != M_POSIX) {
+ assert (pthread_mutexattr_settype (&mattr,
+ mutex_types[mkind]) == 0);
+ }
+
+ for (i = 0; i < 3; i++)
+ assert (pthread_mutex_init (&m[i], &mattr) == 0);
+
+ /*
+ * Set the ceiling priorities for the 3 priority protection
+ * mutexes to, 5 less than, equal to, and 5 greater than,
+ * this threads current priority.
+ */
+ for (i = 0; i < 3; i++)
+ assert (pthread_mutex_setprioceiling (&m[i],
+ my_prio - 5 + 5*i, &old_ceiling) == 0);
+
+ /*
+ * Check that if we attempt to take a mutex whose priority
+ * ceiling is lower than our priority, we get an error.
+ */
+ log (" Lock with ceiling priority < thread priority - ");
+ ret = pthread_mutex_lock (&m[0]);
+ check_result (/* expected */ EINVAL, ret);
+ if (ret == 0)
+ pthread_mutex_unlock (&m[0]);
+
+ /*
+ * Check that we can take a mutex whose priority ceiling
+ * is equal to our priority.
+ */
+ log (" Lock with ceiling priority = thread priority - ");
+ ret = pthread_mutex_lock (&m[1]);
+ check_result (/* expected */ 0, ret);
+ if (ret == 0)
+ pthread_mutex_unlock (&m[1]);
+
+ /*
+ * Check that we can take a mutex whose priority ceiling
+ * is higher than our priority.
+ */
+ log (" Lock with ceiling priority > thread priority - ");
+ ret = pthread_mutex_lock (&m[2]);
+ check_result (/* expected */ 0, ret);
+ if (ret == 0)
+ pthread_mutex_unlock (&m[2]);
+
+ /*
+ * Have the test thread go into a busy loop for 5 seconds
+ * and see that it doesn't block this thread (since the
+ * priority ceiling of mutex 0 and the priority of the test
+ * thread are both less than the priority of this thread).
+ */
+ log (" Preemption with ceiling priority < thread "
+ "priority - ");
+ /* Have the test thread take mutex 0. */
+ send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &m[0]);
+ sleep (1);
+
+ log_trace ("Sending busy command.\n");
+ send_cmd (test_thread_id, CMD_BUSY_LOOP);
+ log_trace ("Busy sent, yielding\n");
+ pthread_yield ();
+ log_trace ("Returned from yield.\n");
+ if (states[test_thread_id].flags &
+ (FLAGS_IS_BUSY | FLAGS_WAS_BUSY))
+ log_error ("test thread inproperly preempted us.\n");
+ else {
+ /* Let the thread finish its busy loop. */
+ sleep (6);
+ if ((states[test_thread_id].flags & FLAGS_WAS_BUSY) == 0)
+ log_error ("test thread never finished.\n");
+ else
+ log_pass ();
+ }
+ states[test_thread_id].flags &= ~FLAGS_WAS_BUSY;
+
+ /* Have the test thread release mutex 0. */
+ send_cmd (test_thread_id, CMD_RELEASE_ALL);
+ sleep (1);
+
+ /*
+ * Have the test thread go into a busy loop for 5 seconds
+ * and see that it preempts this thread (since the priority
+ * ceiling of mutex 1 is the same as the priority of this
+ * thread). The test thread should not run to completion
+ * as its time quantum should expire before the 5 seconds
+ * are up.
+ */
+ log (" Preemption with ceiling priority = thread "
+ "priority - ");
+
+ /* Have the test thread take mutex 1. */
+ send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &m[1]);
+ sleep (1);
+
+ log_trace ("Sending busy\n");
+ send_cmd (test_thread_id, CMD_BUSY_LOOP);
+ log_trace ("Busy sent, yielding\n");
+ pthread_yield ();
+ log_trace ("Returned from yield.\n");
+ if ((states[test_thread_id].flags & FLAGS_IS_BUSY) == 0)
+ log_error ("test thread did not switch in on yield.\n");
+ else if (states[test_thread_id].flags & FLAGS_WAS_BUSY)
+ log_error ("test thread ran to completion.\n");
+ else {
+ /* Let the thread finish its busy loop. */
+ sleep (6);
+ if ((states[test_thread_id].flags & FLAGS_WAS_BUSY) == 0)
+ log_error ("test thread never finished.\n");
+ else
+ log_pass ();
+ }
+ states[test_thread_id].flags &= ~FLAGS_WAS_BUSY;
+
+ /* Have the test thread release mutex 1. */
+ send_cmd (test_thread_id, CMD_RELEASE_ALL);
+ sleep (1);
+
+ /*
+ * Set the scheduling policy of the test thread to SCHED_FIFO
+ * and have it go into a busy loop for 5 seconds. This
+ * thread is SCHED_RR, and since the priority ceiling of
+ * mutex 1 is the same as the priority of this thread, the
+ * test thread should run to completion once it is switched
+ * in.
+ */
+ log (" SCHED_FIFO scheduling and ceiling priority = "
+ "thread priority - ");
+ param.sched_priority = states[test_thread_id].priority;
+ assert (pthread_setschedparam (states[test_thread_id].tid,
+ SCHED_FIFO, &param) == 0);
+
+ /* Have the test thread take mutex 1. */
+ send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &m[1]);
+ sleep (1);
+
+ log_trace ("Sending busy\n");
+ send_cmd (test_thread_id, CMD_BUSY_LOOP);
+ log_trace ("Busy sent, yielding\n");
+ pthread_yield ();
+ log_trace ("Returned from yield.\n");
+ if ((states[test_thread_id].flags & FLAGS_WAS_BUSY) == 0) {
+ log_error ("test thread did not run to completion.\n");
+ /* Let the thread finish it's busy loop. */
+ sleep (6);
+ }
+ else
+ log_pass ();
+ states[test_thread_id].flags &= ~FLAGS_WAS_BUSY;
+
+ /* Restore the test thread scheduling parameters. */
+ param.sched_priority = states[test_thread_id].priority;
+ assert (pthread_setschedparam (states[test_thread_id].tid,
+ SCHED_RR, &param) == 0);
+
+ /* Have the test thread release mutex 1. */
+ send_cmd (test_thread_id, CMD_RELEASE_ALL);
+ sleep (1);
+
+ /*
+ * Have the test thread go into a busy loop for 5 seconds
+ * and see that it preempts this thread (since the priority
+ * ceiling of mutex 2 is the greater than the priority of
+ * this thread). The test thread should run to completion
+ * and block this thread because its active priority is
+ * higher.
+ */
+ log (" SCHED_FIFO scheduling and ceiling priority > "
+ "thread priority - ");
+ /* Have the test thread take mutex 2. */
+ send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &m[2]);
+ sleep (1);
+
+ log_trace ("Sending busy\n");
+ send_cmd (test_thread_id, CMD_BUSY_LOOP);
+ log_trace ("Busy sent, yielding\n");
+ pthread_yield ();
+ log_trace ("Returned from yield.\n");
+ if ((states[test_thread_id].flags & FLAGS_IS_BUSY) != 0) {
+ log_error ("test thread did not run to completion.\n");
+ /* Let the thread finish it's busy loop. */
+ sleep (6);
+ }
+ else if ((states[test_thread_id].flags & FLAGS_WAS_BUSY) == 0)
+ log_error ("test thread never finished.\n");
+ else
+ log_pass ();
+ states[test_thread_id].flags &= ~FLAGS_WAS_BUSY;
+
+ /* Have the test thread release mutex 2. */
+ send_cmd (test_thread_id, CMD_RELEASE_ALL);
+ sleep (1);
+
+ /* Destroy the mutexes. */
+ for (i = 0; i < 3; i++)
+ assert (pthread_mutex_destroy (&m[i]) == 0);
+ }
+}
+
+
+static void
+mutex_prioinherit_test (void)
+{
+ pthread_mutexattr_t mattr;
+ struct sched_param param;
+ pthread_mutex_t m[3];
+ mutex_kind_t mkind;
+ int i, policy, my_prio;
+
+ /* Get this threads current priority. */
+ assert (pthread_getschedparam (pthread_self(), &policy,
+ &param) == 0);
+ my_prio = param.sched_priority; /* save for later use */
+ log_trace ("Current scheduling policy %d, priority %d\n",
+ policy, my_prio);
+
+ log ("Testing priority inheritence\n");
+ log ("----------------------------\n");
+ for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) {
+
+ log (" Protype PTHREAD_PRIO_INHERIT, Type %s\n",
+ mutextype_strs[mkind]);
+
+ /*
+ * Initialize and create a mutex.
+ */
+ assert (pthread_mutexattr_init (&mattr) == 0);
+
+ /*
+ * Initialize and create 3 priority inheritence mutexes with
+ * default (max priority) ceilings.
+ */
+ assert (pthread_mutexattr_setprotocol(&mattr,
+ PTHREAD_PRIO_INHERIT) == 0);
+
+ /*
+ * Ensure that the first mutex type is a POSIX
+ * compliant mutex.
+ */
+ if (mkind != M_POSIX) {
+ assert (pthread_mutexattr_settype (&mattr,
+ mutex_types[mkind]) == 0);
+ }
+
+ for (i = 0; i < 3; i++)
+ assert (pthread_mutex_init (&m[i], &mattr) == 0);
+
+ /*
+ * Test setup:
+ * Thread 4 - take mutex 0, 1
+ * Thread 2 - enter protected busy loop with mutex 0
+ * Thread 3 - enter protected busy loop with mutex 1
+ * Thread 4 - enter protected busy loop with mutex 2
+ * Thread 5 - enter busy loop
+ * Thread 6 - enter protected busy loop with mutex 0
+ * Thread 4 - releases mutexes 1 and 0.
+ *
+ * Expected results:
+ * Threads complete in order 4, 6, 5, 3, 2
+ */
+ log (" Simple inheritence test - ");
+
+ /*
+ * Command thread 4 to take mutexes 0 and 1.
+ */
+ send_mutex_cmd (4, CMD_TAKE_MUTEX, &m[0]);
+ sleep (1); /* Allow command to be received. */
+ send_mutex_cmd (4, CMD_TAKE_MUTEX, &m[1]);
+ sleep (1);
+
+ /*
+ * Tell the threads to report themselves when they are
+ * at the bottom of their loop (waiting on wait_mutex).
+ */
+ for (i = 0; i < NUM_THREADS; i++)
+ states[i].flags |= FLAGS_REPORT_WAITMUTEX;
+
+ /*
+ * Command thread 2 to take mutex 0 and thread 3 to take
+ * mutex 1, both via a protected operation command. Since
+ * thread 4 owns mutexes 0 and 1, both threads 2 and 3
+ * will block until the mutexes are released by thread 4.
+ */
+ log_trace ("Commanding protected operation to thread 2.\n");
+ send_mutex_cmd (2, CMD_PROTECTED_OP, &m[0]);
+ log_trace ("Commanding protected operation to thread 3.\n");
+ send_mutex_cmd (3, CMD_PROTECTED_OP, &m[1]);
+ sleep (1);
+
+ /*
+ * Command thread 4 to take mutex 2 via a protected operation
+ * and thread 5 to enter a busy loop for 5 seconds. Since
+ * thread 5 has higher priority than thread 4, thread 5 will
+ * enter the busy loop before thread 4 is activated.
+ */
+ log_trace ("Commanding protected operation to thread 4.\n");
+ send_mutex_cmd (4, CMD_PROTECTED_OP, &m[2]);
+ log_trace ("Commanding busy loop to thread 5.\n");
+ send_cmd (5, CMD_BUSY_LOOP);
+ sleep (1);
+ if ((states[5].flags & FLAGS_IS_BUSY) == 0)
+ log_error ("thread 5 is not running.\n");
+ log_trace ("Commanding protected operation thread 6.\n");
+ send_mutex_cmd (6, CMD_PROTECTED_OP, &m[0]);
+ sleep (1);
+ if ((states[4].flags & FLAGS_WAS_BUSY) == 0)
+ log_error ("thread 4 failed to inherit priority.\n");
+ states[4].flags = 0;
+ send_cmd (4, CMD_RELEASE_ALL);
+ sleep (5);
+ check_run_order ("4,6,5,3,2");
+
+ /*
+ * Clear the flags.
+ */
+ for (i = 0; i < NUM_THREADS; i++)
+ states[i].flags = 0;
+
+ /*
+ * Test setup:
+ * Thread 2 - enter busy loop (SCHED_FIFO)
+ * Thread 4 - take mutex 0
+ * Thread 4 - priority change to same priority as thread 2
+ * Thread 4 - release mutex 0
+ *
+ * Expected results:
+ * Since thread 4 owns a priority mutex, it should be
+ * placed at the front of the run queue (for its new
+ * priority slot) when its priority is lowered to the
+ * same priority as thread 2. If thread 4 did not own
+ * a priority mutex, then it would have been added to
+ * the end of the run queue and thread 2 would have
+ * executed until it blocked (because it's scheduling
+ * policy is SCHED_FIFO).
+ *
+ */
+ log (" Inheritence test with change of priority - ");
+
+ /*
+ * Change threads 2 and 4 scheduling policies to be
+ * SCHED_FIFO.
+ */
+ param.sched_priority = states[2].priority;
+ assert (pthread_setschedparam (states[2].tid, SCHED_FIFO,
+ &param) == 0);
+ param.sched_priority = states[4].priority;
+ assert (pthread_setschedparam (states[4].tid, SCHED_FIFO,
+ &param) == 0);
+
+ /*
+ * Command thread 4 to take mutex 0.
+ */
+ send_mutex_cmd (4, CMD_TAKE_MUTEX, &m[0]);
+ sleep (1);
+
+ /*
+ * Command thread 2 to enter busy loop.
+ */
+ send_cmd (2, CMD_BUSY_LOOP);
+ sleep (1); /* Allow command to be received. */
+
+ /*
+ * Command thread 4 to enter busy loop.
+ */
+ send_cmd (4, CMD_BUSY_LOOP);
+ sleep (1); /* Allow command to be received. */
+
+ /* Have threads 2 and 4 report themselves. */
+ states[2].flags = FLAGS_REPORT_WAITMUTEX;
+ states[4].flags = FLAGS_REPORT_WAITMUTEX;
+
+ /* Change the priority of thread 4. */
+ param.sched_priority = states[2].priority;
+ assert (pthread_setschedparam (states[4].tid, SCHED_FIFO,
+ &param) == 0);
+ sleep (5);
+ check_run_order ("4,2");
+
+ /* Clear the flags */
+ states[2].flags = 0;
+ states[4].flags = 0;
+
+ /* Reset the policies. */
+ param.sched_priority = states[2].priority;
+ assert (pthread_setschedparam (states[2].tid, SCHED_RR,
+ &param) == 0);
+ param.sched_priority = states[4].priority;
+ assert (pthread_setschedparam (states[4].tid, SCHED_RR,
+ &param) == 0);
+
+ send_cmd (4, CMD_RELEASE_MUTEX);
+ sleep (1);
+
+ /* Destroy the mutexes. */
+ for (i = 0; i < 3; i++)
+ assert (pthread_mutex_destroy (&m[i]) == 0);
+ }
+}
+
+
+int main (int argc, char *argv[])
+{
+ pthread_mutexattr_t mattr;
+ pthread_condattr_t cattr;
+ pthread_attr_t pattr;
+ int i, policy, main_prio;
+ void * exit_status;
+ sigset_t mask;
+ struct sigaction act;
+ struct sched_param param;
+
+ logfile = stdout;
+
+ assert (pthread_getschedparam (pthread_self (), &policy, &param) == 0);
+ main_prio = param.sched_priority;
+
+ /* Setupt our signal mask. */
+ sigfillset (&mask);
+ sigdelset (&mask, SIGINT);
+ sigprocmask (SIG_SETMASK, &mask, NULL);
+
+ /* Install a signal handler for SIGINT */
+ sigemptyset (&act.sa_mask);
+ sigaddset (&act.sa_mask, SIGINT);
+ act.sa_handler = sighandler;
+ act.sa_flags = SA_RESTART;
+ sigaction (SIGINT, &act, NULL);
+
+ /* This test relies on the concurrency level being 1. */
+ pthread_setconcurrency(1);
+
+ /*
+ * Initialize the thread attribute.
+ */
+ assert (pthread_attr_init (&pattr) == 0);
+ assert (pthread_attr_setdetachstate (&pattr,
+ PTHREAD_CREATE_JOINABLE) == 0);
+
+ /*
+ * Initialize and create the waiter and condvar mutexes.
+ */
+ assert (pthread_mutexattr_init (&mattr) == 0);
+ assert (pthread_mutex_init (&waiter_mutex, &mattr) == 0);
+ assert (pthread_mutex_init (&cond_mutex, &mattr) == 0);
+
+ /*
+ * Initialize and create a condition variable.
+ */
+ assert (pthread_condattr_init (&cattr) == 0);
+ assert (pthread_cond_init (&cond_var, &cattr) == 0);
+
+ /* Create a pipe to catch the results of thread wakeups. */
+ assert (pipe (pipefd) == 0);
+
+#if defined(_LIBC_R_) && defined(DEBUG)
+ assert (pthread_switch_add_np (kern_switch) == 0);
+#endif
+
+ /*
+ * Create the waiting threads.
+ */
+ for (i = 0; i < NUM_THREADS; i++) {
+ assert (pthread_cond_init (&states[i].cond_var, &cattr) == 0);
+ states[i].id = (u_int8_t) i; /* NUM_THREADS must be <= 256 */
+ states[i].status = 0;
+ states[i].cmd.cmd_id = CMD_NONE;
+ states[i].flags = 0; /* No flags yet. */
+ assert (pthread_create (&states[i].tid, &pattr, waiter,
+ (void *) &states[i]) == 0);
+ param.sched_priority = main_prio - 10 + i;
+ states[i].priority = param.sched_priority;
+ assert (pthread_setschedparam (states[i].tid, SCHED_OTHER,
+ &param) == 0);
+#if defined(_LIBC_R_)
+ {
+ char buf[30];
+
+ snprintf (buf, sizeof(buf), "waiter_%d", i);
+ pthread_set_name_np (states[i].tid, buf);
+ }
+#endif
+ }
+
+ /* Allow the threads to start. */
+ sleep (1);
+ log_trace ("Done creating threads.\n");
+
+ log ("\n");
+ mutex_init_test ();
+ log ("\n");
+ mutex_destroy_test ();
+ log ("\n");
+ mutex_lock_test ();
+ log ("\n");
+ mutex_unlock_test ();
+ log ("\n");
+ queueing_order_test ();
+ log ("\n");
+ mutex_prioinherit_test ();
+ log ("\n");
+ mutex_prioceiling_test ();
+ log ("\n");
+
+ log ("Total tests %d, passed %d, failed %d\n",
+ total, pass_count, error_count);
+
+ /* Set the done flag and signal the threads to exit. */
+ log_trace ("Setting done flag.\n");
+ done = 1;
+
+ /*
+ * Wait for the threads to finish.
+ */
+ log_trace ("Trying to join threads.\n");
+ for (i = 0; i < NUM_THREADS; i++) {
+ send_cmd (i, CMD_NONE);
+ assert (pthread_join (states[i].tid, &exit_status) == 0);
+ }
+
+ /* Clean up after ourselves. */
+ close (pipefd[0]);
+ close (pipefd[1]);
+
+ if (error_count != 0)
+ exit (EX_OSERR); /* any better ideas??? */
+ else
+ exit (EX_OK);
+}
diff --git a/lib/libkse/test/mutex_d.exp b/lib/libkse/test/mutex_d.exp
new file mode 100644
index 0000000..de8a4e4
--- /dev/null
+++ b/lib/libkse/test/mutex_d.exp
@@ -0,0 +1,290 @@
+
+Testing pthread_mutex_init
+--------------------------
+ Protocol PTHREAD_PRIO_NONE, Type POSIX (type not specified) - PASS
+ Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_DEFAULT - PASS
+ Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_ERRORCHECK - PASS
+ Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_NORMAL - PASS
+ Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_RECURSIVE - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type POSIX (type not specified) - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_DEFAULT - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_ERRORCHECK - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_NORMAL - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_RECURSIVE - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type POSIX (type not specified) - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_DEFAULT - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_ERRORCHECK - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_NORMAL - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_RECURSIVE - PASS
+
+Testing pthread_mutex_destroy
+-----------------------------
+ Protocol PTHREAD_PRIO_NONE, Type POSIX (type not specified)
+ Destruction of unused mutex - PASS
+ Destruction of mutex locked by self - PASS
+ Destruction of mutex locked by another thread - PASS
+ Destruction of mutex while being used in cond_wait - PASS
+ Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_DEFAULT
+ Destruction of unused mutex - PASS
+ Destruction of mutex locked by self - PASS
+ Destruction of mutex locked by another thread - PASS
+ Destruction of mutex while being used in cond_wait - PASS
+ Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_ERRORCHECK
+ Destruction of unused mutex - PASS
+ Destruction of mutex locked by self - PASS
+ Destruction of mutex locked by another thread - PASS
+ Destruction of mutex while being used in cond_wait - PASS
+ Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_NORMAL
+ Destruction of unused mutex - PASS
+ Destruction of mutex locked by self - PASS
+ Destruction of mutex locked by another thread - PASS
+ Destruction of mutex while being used in cond_wait - PASS
+ Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_RECURSIVE
+ Destruction of unused mutex - PASS
+ Destruction of mutex locked by self - PASS
+ Destruction of mutex locked by another thread - PASS
+ Destruction of mutex while being used in cond_wait - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type POSIX (type not specified)
+ Destruction of unused mutex - PASS
+ Destruction of mutex locked by self - PASS
+ Destruction of mutex locked by another thread - PASS
+ Destruction of mutex while being used in cond_wait - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_DEFAULT
+ Destruction of unused mutex - PASS
+ Destruction of mutex locked by self - PASS
+ Destruction of mutex locked by another thread - PASS
+ Destruction of mutex while being used in cond_wait - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_ERRORCHECK
+ Destruction of unused mutex - PASS
+ Destruction of mutex locked by self - PASS
+ Destruction of mutex locked by another thread - PASS
+ Destruction of mutex while being used in cond_wait - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_NORMAL
+ Destruction of unused mutex - PASS
+ Destruction of mutex locked by self - PASS
+ Destruction of mutex locked by another thread - PASS
+ Destruction of mutex while being used in cond_wait - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_RECURSIVE
+ Destruction of unused mutex - PASS
+ Destruction of mutex locked by self - PASS
+ Destruction of mutex locked by another thread - PASS
+ Destruction of mutex while being used in cond_wait - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type POSIX (type not specified)
+ Destruction of unused mutex - PASS
+ Destruction of mutex locked by self - PASS
+ Destruction of mutex locked by another thread - PASS
+ Destruction of mutex while being used in cond_wait - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_DEFAULT
+ Destruction of unused mutex - PASS
+ Destruction of mutex locked by self - PASS
+ Destruction of mutex locked by another thread - PASS
+ Destruction of mutex while being used in cond_wait - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_ERRORCHECK
+ Destruction of unused mutex - PASS
+ Destruction of mutex locked by self - PASS
+ Destruction of mutex locked by another thread - PASS
+ Destruction of mutex while being used in cond_wait - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_NORMAL
+ Destruction of unused mutex - PASS
+ Destruction of mutex locked by self - PASS
+ Destruction of mutex locked by another thread - PASS
+ Destruction of mutex while being used in cond_wait - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_RECURSIVE
+ Destruction of unused mutex - PASS
+ Destruction of mutex locked by self - PASS
+ Destruction of mutex locked by another thread - PASS
+ Destruction of mutex while being used in cond_wait - PASS
+
+Testing pthread_mutex_lock
+--------------------------
+ Protocol PTHREAD_PRIO_NONE, Type POSIX (type not specified)
+ Lock on unlocked mutex - PASS
+ Lock on invalid mutex - PASS
+ Lock on mutex held by self - PASS
+ Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_DEFAULT
+ Lock on unlocked mutex - PASS
+ Lock on invalid mutex - PASS
+ Lock on mutex held by self - PASS
+ Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_ERRORCHECK
+ Lock on unlocked mutex - PASS
+ Lock on invalid mutex - PASS
+ Lock on mutex held by self - PASS
+ Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_NORMAL
+ Lock on unlocked mutex - PASS
+ Lock on invalid mutex - PASS
+ Lock on mutex held by self - PASS
+ Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_RECURSIVE
+ Lock on unlocked mutex - PASS
+ Lock on invalid mutex - PASS
+ Lock on mutex held by self - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type POSIX (type not specified)
+ Lock on unlocked mutex - PASS
+ Lock on invalid mutex - PASS
+ Lock on mutex held by self - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_DEFAULT
+ Lock on unlocked mutex - PASS
+ Lock on invalid mutex - PASS
+ Lock on mutex held by self - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_ERRORCHECK
+ Lock on unlocked mutex - PASS
+ Lock on invalid mutex - PASS
+ Lock on mutex held by self - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_NORMAL
+ Lock on unlocked mutex - PASS
+ Lock on invalid mutex - PASS
+ Lock on mutex held by self - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_RECURSIVE
+ Lock on unlocked mutex - PASS
+ Lock on invalid mutex - PASS
+ Lock on mutex held by self - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type POSIX (type not specified)
+ Lock on unlocked mutex - PASS
+ Lock on invalid mutex - PASS
+ Lock on mutex held by self - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_DEFAULT
+ Lock on unlocked mutex - PASS
+ Lock on invalid mutex - PASS
+ Lock on mutex held by self - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_ERRORCHECK
+ Lock on unlocked mutex - PASS
+ Lock on invalid mutex - PASS
+ Lock on mutex held by self - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_NORMAL
+ Lock on unlocked mutex - PASS
+ Lock on invalid mutex - PASS
+ Lock on mutex held by self - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_RECURSIVE
+ Lock on unlocked mutex - PASS
+ Lock on invalid mutex - PASS
+ Lock on mutex held by self - PASS
+
+Testing pthread_mutex_unlock
+----------------------------
+ Protocol PTHREAD_PRIO_NONE, Type POSIX (type not specified)
+ Unlock on mutex held by self - PASS
+ Unlock on invalid mutex - PASS
+ Unlock on mutex locked by another thread - PASS
+ Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_DEFAULT
+ Unlock on mutex held by self - PASS
+ Unlock on invalid mutex - PASS
+ Unlock on mutex locked by another thread - PASS
+ Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_ERRORCHECK
+ Unlock on mutex held by self - PASS
+ Unlock on invalid mutex - PASS
+ Unlock on mutex locked by another thread - PASS
+ Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_NORMAL
+ Unlock on mutex held by self - PASS
+ Unlock on invalid mutex - PASS
+ Unlock on mutex locked by another thread - PASS
+ Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_RECURSIVE
+ Unlock on mutex held by self - PASS
+ Unlock on invalid mutex - PASS
+ Unlock on mutex locked by another thread - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type POSIX (type not specified)
+ Unlock on mutex held by self - PASS
+ Unlock on invalid mutex - PASS
+ Unlock on mutex locked by another thread - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_DEFAULT
+ Unlock on mutex held by self - PASS
+ Unlock on invalid mutex - PASS
+ Unlock on mutex locked by another thread - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_ERRORCHECK
+ Unlock on mutex held by self - PASS
+ Unlock on invalid mutex - PASS
+ Unlock on mutex locked by another thread - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_NORMAL
+ Unlock on mutex held by self - PASS
+ Unlock on invalid mutex - PASS
+ Unlock on mutex locked by another thread - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_RECURSIVE
+ Unlock on mutex held by self - PASS
+ Unlock on invalid mutex - PASS
+ Unlock on mutex locked by another thread - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type POSIX (type not specified)
+ Unlock on mutex held by self - PASS
+ Unlock on invalid mutex - PASS
+ Unlock on mutex locked by another thread - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_DEFAULT
+ Unlock on mutex held by self - PASS
+ Unlock on invalid mutex - PASS
+ Unlock on mutex locked by another thread - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_ERRORCHECK
+ Unlock on mutex held by self - PASS
+ Unlock on invalid mutex - PASS
+ Unlock on mutex locked by another thread - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_NORMAL
+ Unlock on mutex held by self - PASS
+ Unlock on invalid mutex - PASS
+ Unlock on mutex locked by another thread - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_RECURSIVE
+ Unlock on mutex held by self - PASS
+ Unlock on invalid mutex - PASS
+ Unlock on mutex locked by another thread - PASS
+
+Testing queueing order
+----------------------
+ Queueing order on a mutex - PASS
+ Queueing order on a condition variable - PASS
+
+Testing priority inheritence
+----------------------------
+ Protype PTHREAD_PRIO_INHERIT, Type POSIX (type not specified)
+ Simple inheritence test - PASS
+ Inheritence test with change of priority - PASS
+ Protype PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_DEFAULT
+ Simple inheritence test - PASS
+ Inheritence test with change of priority - PASS
+ Protype PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_ERRORCHECK
+ Simple inheritence test - PASS
+ Inheritence test with change of priority - PASS
+ Protype PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_NORMAL
+ Simple inheritence test - PASS
+ Inheritence test with change of priority - PASS
+ Protype PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_RECURSIVE
+ Simple inheritence test - PASS
+ Inheritence test with change of priority - PASS
+
+Testing priority ceilings
+-------------------------
+ Protype PTHREAD_PRIO_PROTECT, Type POSIX (type not specified)
+ Lock with ceiling priority < thread priority - PASS
+ Lock with ceiling priority = thread priority - PASS
+ Lock with ceiling priority > thread priority - PASS
+ Preemption with ceiling priority < thread priority - PASS
+ Preemption with ceiling priority = thread priority - PASS
+ SCHED_FIFO scheduling and ceiling priority = thread priority - PASS
+ SCHED_FIFO scheduling and ceiling priority > thread priority - PASS
+ Protype PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_DEFAULT
+ Lock with ceiling priority < thread priority - PASS
+ Lock with ceiling priority = thread priority - PASS
+ Lock with ceiling priority > thread priority - PASS
+ Preemption with ceiling priority < thread priority - PASS
+ Preemption with ceiling priority = thread priority - PASS
+ SCHED_FIFO scheduling and ceiling priority = thread priority - PASS
+ SCHED_FIFO scheduling and ceiling priority > thread priority - PASS
+ Protype PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_ERRORCHECK
+ Lock with ceiling priority < thread priority - PASS
+ Lock with ceiling priority = thread priority - PASS
+ Lock with ceiling priority > thread priority - PASS
+ Preemption with ceiling priority < thread priority - PASS
+ Preemption with ceiling priority = thread priority - PASS
+ SCHED_FIFO scheduling and ceiling priority = thread priority - PASS
+ SCHED_FIFO scheduling and ceiling priority > thread priority - PASS
+ Protype PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_NORMAL
+ Lock with ceiling priority < thread priority - PASS
+ Lock with ceiling priority = thread priority - PASS
+ Lock with ceiling priority > thread priority - PASS
+ Preemption with ceiling priority < thread priority - PASS
+ Preemption with ceiling priority = thread priority - PASS
+ SCHED_FIFO scheduling and ceiling priority = thread priority - PASS
+ SCHED_FIFO scheduling and ceiling priority > thread priority - PASS
+ Protype PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_RECURSIVE
+ Lock with ceiling priority < thread priority - PASS
+ Lock with ceiling priority = thread priority - PASS
+ Lock with ceiling priority > thread priority - PASS
+ Preemption with ceiling priority < thread priority - PASS
+ Preemption with ceiling priority = thread priority - PASS
+ SCHED_FIFO scheduling and ceiling priority = thread priority - PASS
+ SCHED_FIFO scheduling and ceiling priority > thread priority - PASS
+
+Total tests 212, passed 212, failed 0
diff --git a/lib/libkse/test/propagate_s.pl b/lib/libkse/test/propagate_s.pl
new file mode 100644
index 0000000..6b85090
--- /dev/null
+++ b/lib/libkse/test/propagate_s.pl
@@ -0,0 +1,74 @@
+#!/usr/bin/perl -w
+#
+# 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.
+#
+###########################################################################
+#
+# Verify that no cancellation points are propagated inside of libpthread.
+#
+# $FreeBSD$
+#
+
+@CPOINTS = ("aio_suspend", "close", "creat", "fcntl", "fsync", "mq_receive",
+ "mq_send", "msync", "nanosleep", "open", "pause",
+ "pthread_cond_timedwait", "pthread_cond_wait", "pthread_join",
+ "pthread_testcancel", "read", "sem_wait", "sigsuspend",
+ "sigtimedwait", "sigwait", "sigwaitinfo", "sleep", "system",
+ "tcdrain", "wait", "waitpid", "write");
+
+print "1..1\n";
+
+$cpoints = join '\|', @CPOINTS;
+$regexp = "\" U \\(" . $cpoints . "\\\)\$\"";
+
+`nm -a /usr/lib/libc.a |grep $regexp >propagate_s.out`;
+if (!open (NMOUT, "<./propagate_s.out"))
+{
+ print "not ok 1\n";
+}
+else
+{
+ $propagations = 0;
+
+ while (<NMOUT>)
+ {
+ $propagations++;
+ print "$_\n";
+ }
+ if ($propagations != 0)
+ {
+ print "$propagations propagation(s)\n";
+ print "not ok 1\n";
+ }
+ else
+ {
+ print "ok 1\n";
+ }
+ close NMOUT;
+ unlink "propagate_s.out";
+}
diff --git a/lib/libkse/test/sem_d.c b/lib/libkse/test/sem_d.c
new file mode 100644
index 0000000..b834591
--- /dev/null
+++ b/lib/libkse/test/sem_d.c
@@ -0,0 +1,133 @@
+/****************************************************************************
+ *
+ * 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.
+ *
+ ****************************************************************************
+ *
+ * sem test.
+ *
+ * $FreeBSD$
+ *
+ ****************************************************************************/
+
+#include <assert.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <semaphore.h>
+#include <pthread.h>
+
+#define NTHREADS 10
+
+void *
+entry(void * a_arg)
+{
+ sem_t * sem = (sem_t *) a_arg;
+
+ sem_wait(sem);
+ fprintf(stderr, "Got semaphore\n");
+
+ return NULL;
+}
+
+int
+main()
+{
+ sem_t sem_a, sem_b;
+ pthread_t threads[NTHREADS];
+ unsigned i;
+ int val;
+
+ fprintf(stderr, "Test begin\n");
+
+#ifdef _LIBC_R_
+ assert(-1 == sem_init(&sem_b, 1, 0));
+ assert(EPERM == errno);
+#endif
+
+ assert(0 == sem_init(&sem_b, 0, 0));
+ assert(0 == sem_getvalue(&sem_b, &val));
+ assert(0 == val);
+
+ assert(0 == sem_post(&sem_b));
+ assert(0 == sem_getvalue(&sem_b, &val));
+ assert(1 == val);
+
+ assert(0 == sem_wait(&sem_b));
+ assert(-1 == sem_trywait(&sem_b));
+ assert(EAGAIN == errno);
+ assert(0 == sem_post(&sem_b));
+ assert(0 == sem_trywait(&sem_b));
+ assert(0 == sem_post(&sem_b));
+ assert(0 == sem_wait(&sem_b));
+ assert(0 == sem_post(&sem_b));
+
+#ifdef _LIBC_R_
+ assert(SEM_FAILED == sem_open("/foo", O_CREAT | O_EXCL, 0644, 0));
+ assert(ENOSYS == errno);
+
+ assert(-1 == sem_close(&sem_b));
+ assert(ENOSYS == errno);
+
+ assert(-1 == sem_unlink("/foo"));
+ assert(ENOSYS == errno);
+#endif
+
+ assert(0 == sem_destroy(&sem_b));
+
+ assert(0 == sem_init(&sem_a, 0, 0));
+
+ for (i = 0; i < NTHREADS; i++) {
+ pthread_create(&threads[i], NULL, entry, (void *) &sem_a);
+ }
+
+ for (i = 0; i < NTHREADS; i++) {
+ assert(0 == sem_post(&sem_a));
+ }
+
+ for (i = 0; i < NTHREADS; i++) {
+ pthread_join(threads[i], NULL);
+ }
+
+ for (i = 0; i < NTHREADS; i++) {
+ pthread_create(&threads[i], NULL, entry, (void *) &sem_a);
+ }
+
+ for (i = 0; i < NTHREADS; i++) {
+ assert(0 == sem_post(&sem_a));
+ }
+
+ for (i = 0; i < NTHREADS; i++) {
+ pthread_join(threads[i], NULL);
+ }
+
+ assert(0 == sem_destroy(&sem_a));
+
+ fprintf(stderr, "Test end\n");
+ return 0;
+}
diff --git a/lib/libkse/test/sem_d.exp b/lib/libkse/test/sem_d.exp
new file mode 100644
index 0000000..b0de3da
--- /dev/null
+++ b/lib/libkse/test/sem_d.exp
@@ -0,0 +1,22 @@
+Test begin
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Test end
diff --git a/lib/libkse/test/sigsuspend_d.c b/lib/libkse/test/sigsuspend_d.c
new file mode 100644
index 0000000..d405e3d
--- /dev/null
+++ b/lib/libkse/test/sigsuspend_d.c
@@ -0,0 +1,290 @@
+/*
+ * Copyright (c) 1998 Daniel M. Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel M. Eischen.
+ * 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 DANIEL M. 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 REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <unistd.h>
+
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+
+#if defined(_LIBC_R_)
+#include <pthread_np.h>
+#endif
+
+static int sigcounts[NSIG + 1];
+static int sigfifo[NSIG + 1];
+static int fifo_depth = 0;
+static sigset_t suspender_mask;
+static pthread_t suspender_tid;
+
+
+static void *
+sigsuspender (void *arg)
+{
+ int save_count, status, i;
+ sigset_t run_mask;
+
+ /* Run with all signals blocked. */
+ sigfillset (&run_mask);
+ sigprocmask (SIG_SETMASK, &run_mask, NULL);
+
+ /* Allow these signals to wake us up during a sigsuspend. */
+ sigfillset (&suspender_mask); /* Default action */
+ sigdelset (&suspender_mask, SIGKILL); /* Cannot catch */
+ sigdelset (&suspender_mask, SIGSTOP); /* Cannot catch */
+ sigdelset (&suspender_mask, SIGINT); /* terminate */
+ sigdelset (&suspender_mask, SIGHUP); /* terminate */
+ sigdelset (&suspender_mask, SIGQUIT); /* create core image */
+ sigdelset (&suspender_mask, SIGURG); /* ignore */
+ sigdelset (&suspender_mask, SIGIO); /* ignore */
+ sigdelset (&suspender_mask, SIGUSR2); /* terminate */
+
+ while (sigcounts[SIGINT] == 0) {
+ save_count = sigcounts[SIGUSR2];
+
+ status = sigsuspend (&suspender_mask);
+ if ((status == 0) || (errno != EINTR)) {
+ fprintf (stderr, "Unable to suspend for signals, "
+ "errno %d, return value %d\n",
+ errno, status);
+ exit (1);
+ }
+ for (i = 0; i < fifo_depth; i++)
+ fprintf (stderr, "Sigsuspend woke up by signal %d\n",
+ sigfifo[i]);
+ fifo_depth = 0;
+ }
+
+ pthread_exit (arg);
+ return (NULL);
+}
+
+
+static void
+sighandler (int signo)
+{
+ sigset_t set, suspend_set;
+ pthread_t self;
+
+ if ((signo >= 0) && (signo <= NSIG))
+ sigcounts[signo]++;
+
+ /*
+ * If we are running on behalf of the suspender thread,
+ * ensure that we have the correct mask set.
+ */
+ self = pthread_self ();
+ if (self == suspender_tid) {
+ sigfifo[fifo_depth] = signo;
+ fifo_depth++;
+ fprintf (stderr,
+ " -> Suspender thread signal handler caught signal %d\n",
+ signo);
+
+ /* Get the current signal mask. */
+ sigprocmask (SIG_SETMASK, NULL, &set);
+
+ /* The handler should run with the current signal masked. */
+ suspend_set = suspender_mask;
+ sigaddset(&suspend_set, signo);
+
+ if (memcmp(&set, &suspend_set, sizeof(set)))
+ fprintf (stderr,
+ " >>> FAIL: sigsuspender signal handler running "
+ "with incorrect mask.\n");
+ }
+ else
+ fprintf (stderr,
+ " -> Main thread signal handler caught signal %d\n",
+ signo);
+}
+
+
+static void
+send_thread_signal (pthread_t tid, int signo)
+{
+ if (pthread_kill (tid, signo) != 0) {
+ fprintf (stderr, "Unable to send thread signal, errno %d.\n",
+ errno);
+ exit (1);
+ }
+}
+
+
+static void
+send_process_signal (int signo)
+{
+ if (kill (getpid (), signo) != 0) {
+ fprintf (stderr, "Unable to send process signal, errno %d.\n",
+ errno);
+ exit (1);
+ }
+}
+
+
+int main (int argc, char *argv[])
+{
+ pthread_attr_t pattr;
+ void * exit_status;
+ struct sigaction act;
+ sigset_t oldset;
+ sigset_t newset;
+
+ /* Initialize our signal counts. */
+ memset ((void *) sigcounts, 0, NSIG * sizeof (int));
+
+ /* Ignore signal SIGIO. */
+ sigemptyset (&act.sa_mask);
+ sigaddset (&act.sa_mask, SIGIO);
+ act.sa_handler = SIG_IGN;
+ act.sa_flags = 0;
+ sigaction (SIGIO, &act, NULL);
+
+ /* Install a signal handler for SIGURG. */
+ sigemptyset (&act.sa_mask);
+ sigaddset (&act.sa_mask, SIGURG);
+ act.sa_handler = sighandler;
+ act.sa_flags = SA_RESTART;
+ sigaction (SIGURG, &act, NULL);
+
+ /* Install a signal handler for SIGXCPU */
+ sigemptyset (&act.sa_mask);
+ sigaddset (&act.sa_mask, SIGXCPU);
+ sigaction (SIGXCPU, &act, NULL);
+
+ /* Get our current signal mask. */
+ sigprocmask (SIG_SETMASK, NULL, &oldset);
+
+ /* Mask out SIGUSR1 and SIGUSR2. */
+ newset = oldset;
+ sigaddset (&newset, SIGUSR1);
+ sigaddset (&newset, SIGUSR2);
+ sigprocmask (SIG_SETMASK, &newset, NULL);
+
+ /* Install a signal handler for SIGUSR1 */
+ sigemptyset (&act.sa_mask);
+ sigaddset (&act.sa_mask, SIGUSR1);
+ sigaction (SIGUSR1, &act, NULL);
+
+ /* Install a signal handler for SIGUSR2 */
+ sigemptyset (&act.sa_mask);
+ sigaddset (&act.sa_mask, SIGUSR2);
+ sigaction (SIGUSR2, &act, NULL);
+
+ /*
+ * Initialize the thread attribute.
+ */
+ if ((pthread_attr_init (&pattr) != 0) ||
+ (pthread_attr_setdetachstate (&pattr,
+ PTHREAD_CREATE_JOINABLE) != 0)) {
+ fprintf (stderr, "Unable to initialize thread attributes.\n");
+ exit (1);
+ }
+
+ /*
+ * Create the sigsuspender thread.
+ */
+ if (pthread_create (&suspender_tid, &pattr, sigsuspender, NULL) != 0) {
+ fprintf (stderr, "Unable to create thread, errno %d.\n", errno);
+ exit (1);
+ }
+#if defined(_LIBC_R_)
+ pthread_set_name_np (suspender_tid, "sigsuspender");
+#endif
+
+ /*
+ * Verify that an ignored signal doesn't cause a wakeup.
+ * We don't have a handler installed for SIGIO.
+ */
+ send_thread_signal (suspender_tid, SIGIO);
+ sleep (1);
+ send_process_signal (SIGIO);
+ sleep (1);
+ if (sigcounts[SIGIO] != 0)
+ fprintf (stderr, "FAIL: sigsuspend wakes up for ignored signal "
+ "SIGIO.\n");
+
+ /*
+ * Verify that a signal with a default action of ignore, for
+ * which we have a signal handler installed, will release a
+ * sigsuspend.
+ */
+ send_thread_signal (suspender_tid, SIGURG);
+ sleep (1);
+ send_process_signal (SIGURG);
+ sleep (1);
+ if (sigcounts[SIGURG] != 2)
+ fprintf (stderr,
+ "FAIL: sigsuspend doesn't wake up for SIGURG.\n");
+
+ /*
+ * Verify that a SIGUSR2 signal will release a sigsuspended
+ * thread.
+ */
+ send_thread_signal (suspender_tid, SIGUSR2);
+ sleep (1);
+ send_process_signal (SIGUSR2);
+ sleep (1);
+ if (sigcounts[SIGUSR2] != 2)
+ fprintf (stderr,
+ "FAIL: sigsuspend doesn't wake up for SIGUSR2.\n");
+
+ /*
+ * Verify that a signal, blocked in both the main and
+ * sigsuspender threads, does not cause the signal handler
+ * to be called.
+ */
+ send_thread_signal (suspender_tid, SIGUSR1);
+ sleep (1);
+ send_process_signal (SIGUSR1);
+ sleep (1);
+ if (sigcounts[SIGUSR1] != 0)
+ fprintf (stderr, "FAIL: signal hander called for SIGUSR1.\n");
+
+ /*
+ * Verify that we can still kill the process for a signal
+ * not being waited on by sigwait.
+ */
+ send_process_signal (SIGPIPE);
+ fprintf (stderr, "FAIL: SIGPIPE did not terminate process.\n");
+
+ /*
+ * Wait for the thread to finish.
+ */
+ pthread_join (suspender_tid, &exit_status);
+
+ return (0);
+}
diff --git a/lib/libkse/test/sigsuspend_d.exp b/lib/libkse/test/sigsuspend_d.exp
new file mode 100644
index 0000000..901fa50
--- /dev/null
+++ b/lib/libkse/test/sigsuspend_d.exp
@@ -0,0 +1,8 @@
+ -> Suspender thread signal handler caught signal 16
+Sigsuspend woke up by signal 16
+ -> Suspender thread signal handler caught signal 16
+Sigsuspend woke up by signal 16
+ -> Suspender thread signal handler caught signal 31
+Sigsuspend woke up by signal 31
+ -> Suspender thread signal handler caught signal 31
+Sigsuspend woke up by signal 31
diff --git a/lib/libkse/test/sigwait_d.c b/lib/libkse/test/sigwait_d.c
new file mode 100644
index 0000000..f3ccd6b
--- /dev/null
+++ b/lib/libkse/test/sigwait_d.c
@@ -0,0 +1,304 @@
+/*
+ * Copyright (c) 1998 Daniel M. Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel M. Eischen.
+ * 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 DANIEL M. 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 REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <unistd.h>
+
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+
+#if defined(_LIBC_R_)
+#include <pthread_np.h>
+#endif
+
+static int sigcounts[NSIG + 1];
+static sigset_t wait_mask;
+static pthread_mutex_t waiter_mutex;
+
+
+static void *
+sigwaiter (void *arg)
+{
+ int signo;
+ sigset_t mask;
+
+ /* Block SIGHUP */
+ sigemptyset (&mask);
+ sigaddset (&mask, SIGHUP);
+ sigprocmask (SIG_BLOCK, &mask, NULL);
+
+ while (sigcounts[SIGINT] == 0) {
+ if (sigwait (&wait_mask, &signo) != 0) {
+ fprintf (stderr,
+ "Unable to wait for signal, errno %d\n",
+ errno);
+ exit (1);
+ }
+ sigcounts[signo]++;
+ fprintf (stderr, "Sigwait caught signal %d\n", signo);
+
+ /* Allow the main thread to prevent the sigwait. */
+ pthread_mutex_lock (&waiter_mutex);
+ pthread_mutex_unlock (&waiter_mutex);
+ }
+
+ pthread_exit (arg);
+ return (NULL);
+}
+
+
+static void
+sighandler (int signo)
+{
+ fprintf (stderr, " -> Signal handler caught signal %d\n", signo);
+
+ if ((signo >= 0) && (signo <= NSIG))
+ sigcounts[signo]++;
+}
+
+static void
+send_thread_signal (pthread_t tid, int signo)
+{
+ if (pthread_kill (tid, signo) != 0) {
+ fprintf (stderr, "Unable to send thread signal, errno %d.\n",
+ errno);
+ exit (1);
+ }
+}
+
+static void
+send_process_signal (int signo)
+{
+ if (kill (getpid (), signo) != 0) {
+ fprintf (stderr, "Unable to send process signal, errno %d.\n",
+ errno);
+ exit (1);
+ }
+}
+
+
+int main (int argc, char *argv[])
+{
+ pthread_mutexattr_t mattr;
+ pthread_attr_t pattr;
+ pthread_t tid;
+ void * exit_status;
+ struct sigaction act;
+
+ /* Initialize our signal counts. */
+ memset ((void *) sigcounts, 0, NSIG * sizeof (int));
+
+ /* Setup our wait mask. */
+ sigemptyset (&wait_mask); /* Default action */
+ sigaddset (&wait_mask, SIGHUP); /* terminate */
+ sigaddset (&wait_mask, SIGINT); /* terminate */
+ sigaddset (&wait_mask, SIGQUIT); /* create core image */
+ sigaddset (&wait_mask, SIGURG); /* ignore */
+ sigaddset (&wait_mask, SIGIO); /* ignore */
+ sigaddset (&wait_mask, SIGUSR1); /* terminate */
+
+ /* Ignore signals SIGHUP and SIGIO. */
+ sigemptyset (&act.sa_mask);
+ sigaddset (&act.sa_mask, SIGHUP);
+ sigaddset (&act.sa_mask, SIGIO);
+ act.sa_handler = SIG_IGN;
+ act.sa_flags = 0;
+ sigaction (SIGHUP, &act, NULL);
+ sigaction (SIGIO, &act, NULL);
+
+ /* Install a signal handler for SIGURG */
+ sigemptyset (&act.sa_mask);
+ sigaddset (&act.sa_mask, SIGURG);
+ act.sa_handler = sighandler;
+ act.sa_flags = SA_RESTART;
+ sigaction (SIGURG, &act, NULL);
+
+ /* Install a signal handler for SIGXCPU */
+ sigemptyset (&act.sa_mask);
+ sigaddset (&act.sa_mask, SIGXCPU);
+ sigaction (SIGXCPU, &act, NULL);
+
+ /*
+ * Initialize the thread attribute.
+ */
+ if ((pthread_attr_init (&pattr) != 0) ||
+ (pthread_attr_setdetachstate (&pattr,
+ PTHREAD_CREATE_JOINABLE) != 0)) {
+ fprintf (stderr, "Unable to initialize thread attributes.\n");
+ exit (1);
+ }
+
+ /*
+ * Initialize and create a mutex.
+ */
+ if ((pthread_mutexattr_init (&mattr) != 0) ||
+ (pthread_mutex_init (&waiter_mutex, &mattr) != 0)) {
+ fprintf (stderr, "Unable to create waiter mutex.\n");
+ exit (1);
+ }
+
+ /*
+ * Create the sigwaiter thread.
+ */
+ if (pthread_create (&tid, &pattr, sigwaiter, NULL) != 0) {
+ fprintf (stderr, "Unable to create thread.\n");
+ exit (1);
+ }
+#if defined(_LIBC_R_)
+ pthread_set_name_np (tid, "sigwaiter");
+#endif
+
+ /*
+ * Verify that an ignored signal doesn't cause a wakeup.
+ * We don't have a handler installed for SIGIO.
+ */
+ send_thread_signal (tid, SIGIO);
+ sleep (1);
+ send_process_signal (SIGIO);
+ sleep (1);
+ if (sigcounts[SIGIO] != 0)
+ fprintf (stderr,
+ "FAIL: sigwait wakes up for ignored signal SIGIO.\n");
+
+ /*
+ * Verify that a signal with a default action of ignore, for
+ * which we have a signal handler installed, will release a sigwait.
+ */
+ send_thread_signal (tid, SIGURG);
+ sleep (1);
+ send_process_signal (SIGURG);
+ sleep (1);
+ if (sigcounts[SIGURG] != 2)
+ fprintf (stderr, "FAIL: sigwait doesn't wake up for SIGURG.\n");
+
+ /*
+ * Verify that a signal with a default action that terminates
+ * the process will release a sigwait.
+ */
+ send_thread_signal (tid, SIGUSR1);
+ sleep (1);
+ send_process_signal (SIGUSR1);
+ sleep (1);
+ if (sigcounts[SIGUSR1] != 2)
+ fprintf (stderr,
+ "FAIL: sigwait doesn't wake up for SIGUSR1.\n");
+
+ /*
+ * Verify that if we install a signal handler for a previously
+ * ignored signal, an occurrence of this signal will release
+ * the (already waiting) sigwait.
+ */
+
+ /* Install a signal handler for SIGHUP. */
+ sigemptyset (&act.sa_mask);
+ sigaddset (&act.sa_mask, SIGHUP);
+ act.sa_handler = sighandler;
+ act.sa_flags = SA_RESTART;
+ sigaction (SIGHUP, &act, NULL);
+
+ /* Sending SIGHUP should release the sigwait. */
+ send_process_signal (SIGHUP);
+ sleep (1);
+ send_thread_signal (tid, SIGHUP);
+ sleep (1);
+ if (sigcounts[SIGHUP] != 2)
+ fprintf (stderr, "FAIL: sigwait doesn't wake up for SIGHUP.\n");
+
+ /*
+ * Verify that a pending signal in the waiters mask will
+ * cause sigwait to return the pending signal. We do this
+ * by taking the waiters mutex and signaling the waiter to
+ * release him from the sigwait. The waiter will block
+ * on taking the mutex, and we can then send the waiter a
+ * signal which should be added to his pending signals.
+ * The next time the waiter does a sigwait, he should
+ * return with the pending signal.
+ */
+ sigcounts[SIGHUP] = 0;
+ pthread_mutex_lock (&waiter_mutex);
+ /* Release the waiter from sigwait. */
+ send_process_signal (SIGHUP);
+ sleep (1);
+ if (sigcounts[SIGHUP] != 1)
+ fprintf (stderr, "FAIL: sigwait doesn't wake up for SIGHUP.\n");
+ /*
+ * Add SIGHUP to the process pending signals. Since there is
+ * a signal handler installed for SIGHUP and this signal is
+ * blocked from the waiter thread and unblocked in the main
+ * thread, the signal handler should be called once for SIGHUP.
+ */
+ send_process_signal (SIGHUP);
+ /* Release the waiter thread and allow him to run. */
+ pthread_mutex_unlock (&waiter_mutex);
+ sleep (1);
+ if (sigcounts[SIGHUP] != 2)
+ fprintf (stderr,
+ "FAIL: sigwait doesn't return for pending SIGHUP.\n");
+
+ /*
+ * Repeat the above test using pthread_kill and SIGUSR1.
+ */
+ sigcounts[SIGUSR1] = 0;
+ pthread_mutex_lock (&waiter_mutex);
+ /* Release the waiter from sigwait. */
+ send_thread_signal (tid, SIGUSR1);
+ sleep (1);
+ if (sigcounts[SIGUSR1] != 1)
+ fprintf (stderr,
+ "FAIL: sigwait doesn't wake up for SIGUSR1.\n");
+ /* Add SIGUSR1 to the waiters pending signals. */
+ send_thread_signal (tid, SIGUSR1);
+ /* Release the waiter thread and allow him to run. */
+ pthread_mutex_unlock (&waiter_mutex);
+ sleep (1);
+ if (sigcounts[SIGUSR1] != 2)
+ fprintf (stderr,
+ "FAIL: sigwait doesn't return for pending SIGUSR1.\n");
+
+ /*
+ * Verify that we can still kill the process for a signal
+ * not being waited on by sigwait.
+ */
+ send_process_signal (SIGPIPE);
+ fprintf (stderr, "FAIL: SIGPIPE did not terminate process.\n");
+
+ /*
+ * Wait for the thread to finish.
+ */
+ pthread_join (tid, &exit_status);
+
+ return (0);
+}
diff --git a/lib/libkse/test/sigwait_d.exp b/lib/libkse/test/sigwait_d.exp
new file mode 100644
index 0000000..2e9b2c4
--- /dev/null
+++ b/lib/libkse/test/sigwait_d.exp
@@ -0,0 +1,10 @@
+Sigwait caught signal 16
+Sigwait caught signal 16
+Sigwait caught signal 30
+Sigwait caught signal 30
+Sigwait caught signal 1
+Sigwait caught signal 1
+Sigwait caught signal 1
+ -> Signal handler caught signal 1
+Sigwait caught signal 30
+Sigwait caught signal 30
diff --git a/lib/libkse/test/verify b/lib/libkse/test/verify
new file mode 100644
index 0000000..2863e5c
--- /dev/null
+++ b/lib/libkse/test/verify
@@ -0,0 +1,474 @@
+#!/usr/bin/perl -w
+#-*-mode:perl-*-
+#############################################################################
+#
+# Copyright (C) 1999-2001 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.
+#
+#############################################################################
+#
+# Test harness.
+#
+# $FreeBSD$
+#
+#############################################################################
+
+# Shut off buffering.
+select(STDOUT);
+$| = 1;
+
+#
+# Parse command-line arguments.
+#
+use Getopt::Long;
+Getopt::Long::config("bundling"); # Allow -hv rather than forcing -h -v.
+
+# Set option defaults for optional arguments.
+$opt_help = 0;
+$opt_verbose = 0;
+$opt_quiet = 0;
+$opt_srcdir = ".";
+$opt_objdir = ".";
+$opt_ustats = 0;
+$opt_zero = 0;
+
+$opt_retval =
+&GetOptions("h|help" => \$opt_help,
+ "v|verbose" => \$opt_verbose,
+ "q|quiet" => \$opt_quiet,
+ "s|srcdir=s" => \$opt_srcdir,
+ "o|objdir=s" => \$opt_objdir,
+ "u|ustats" => \$opt_ustats,
+ "z|zero" => \$opt_zero
+ );
+
+if ($opt_help)
+{
+ &usage();
+ exit(0);
+}
+
+if ($opt_retval == 0)
+{
+ &usage();
+ exit 1;
+}
+
+if ($opt_verbose && $opt_quiet)
+{
+ print STDERR "-v and -q are incompatible\n";
+ &usage();
+ exit 1;
+}
+
+if ($#ARGV + 1 == 0)
+{
+ print STDERR "No tests specified\n";
+ &usage();
+ exit 1;
+}
+
+if ($opt_verbose)
+{
+ print STDERR "Option values: h:$opt_help, v:$opt_verbose, "
+ . "s:\"$opt_srcdir\", o:\"$opt_objdir\" "
+ . "q:$opt_quiet, u:$opt_ustats, z:$opt_zero\n";
+ printf STDERR "Tests (%d total): @ARGV\n", $#ARGV + 1;
+}
+
+#
+# Create and print header.
+#
+@TSTATS =
+(
+ "--------------------------------------------------------------------------\n",
+ "Test c_user c_system c_total chng\n",
+ " passed/FAILED h_user h_system h_total %% chng\n"
+ );
+
+if (!$opt_quiet)
+{
+ foreach $line (@TSTATS)
+ {
+ printf STDOUT "$line";
+ }
+}
+
+#
+# Run sequence test(s).
+#
+$total_utime = 0.0; # Total user time.
+$total_stime = 0.0; # Total system time.
+$total_hutime = 0.0; # Total historical user time.
+$total_hstime = 0.0; # Total historical system time.
+$total_ntime = 0.0; # Total time for tests that have historical data.
+
+foreach $test (@ARGV)
+{
+ # Strip out any whitespace in $test.
+ $test =~ s/^\s*(.*)\s*$/$1/;
+
+ $okay = 1;
+
+ if (-e "$opt_srcdir/$test.exp")
+ {
+ # Diff mode.
+
+ ($okay, $utime, $stime) = &run_test($test);
+
+ if (-e "$opt_objdir/$test.out")
+ {
+ `diff $opt_srcdir/$test.exp $opt_objdir/$test.out > $opt_objdir/$test.diff 2>&1`;
+ if ($?)
+ {
+ # diff returns non-zero if there is a difference.
+ $okay = 0;
+ }
+ }
+ else
+ {
+ $okay = 0;
+ if ($opt_verbose)
+ {
+ print STDERR
+ "Nonexistent output file \"$opt_objdir/$test.out\"\n";
+ }
+ }
+
+ ($hutime, $hstime) = &print_stats($test, $okay, 0, 0, $utime, $stime);
+ }
+ else
+ {
+ # Sequence mode.
+
+ ($okay, $utime, $stime) = &run_test($test);
+
+ if (open (STEST_OUT, "<$opt_objdir/$test.out"))
+ {
+ $num_subtests = 0;
+ $num_failed_subtests = 0;
+
+ while (defined($line = <STEST_OUT>))
+ {
+ if ($line =~ /1\.\.(\d+)/)
+ {
+ $num_subtests = $1;
+ last;
+ }
+ }
+ if ($num_subtests == 0)
+ {
+ $okay = 0;
+ if ($opt_verbose)
+ {
+ print STDERR "Malformed or missing 1..n line\n";
+ }
+ }
+ else
+ {
+ for ($subtest = 1; $subtest <= $num_subtests; $subtest++)
+ {
+ while (defined($line = <STEST_OUT>))
+ {
+ if ($line =~ /^not\s+ok\s+(\d+)?/)
+ {
+ $not = 1;
+ $test_num = $1;
+ last;
+ }
+ elsif ($line =~ /^ok\s+(\d+)?/)
+ {
+ $not = 0;
+ $test_num = $1;
+ last;
+ }
+ }
+ if (defined($line))
+ {
+ if (defined($test_num) && ($test_num != $subtest))
+ {
+ # There was no output printed for one or more tests.
+ for (; $subtest < $test_num; $subtest++)
+ {
+ $num_failed_subtests++;
+ }
+ }
+ if ($not)
+ {
+ $num_failed_subtests++;
+ }
+ }
+ else
+ {
+ for (; $subtest <= $num_subtests; $subtest++)
+ {
+ $num_failed_subtests++;
+ }
+ }
+ }
+
+ if (0 < $num_failed_subtests)
+ {
+ $okay = 0;
+ }
+ }
+ }
+ else
+ {
+ if (!$opt_quiet)
+ {
+ print STDERR "Cannot open output file \"$opt_objdir/$test.out\"\n";
+ }
+ exit 1;
+ }
+
+ ($hutime, $hstime) = &print_stats($test, $okay,
+ $num_failed_subtests, $num_subtests,
+ $utime, $stime);
+ }
+
+ $total_hutime += $hutime;
+ $total_hstime += $hstime;
+
+ if ($okay)
+ {
+ $total_utime += $utime;
+ $total_stime += $stime;
+ }
+ else
+ {
+ @FAILED_TESTS = (@FAILED_TESTS, $test);
+ }
+
+ # If there were historical data, add the run time to the total time to
+ # compare against the historical run time.
+ if (0 < ($hutime + $hstime))
+ {
+ $total_ntime += $utime + $stime;
+ }
+}
+
+# Print summary stats.
+$tt_str = sprintf ("%d / %d passed (%5.2f%%%%)",
+ ($#ARGV + 1) - ($#FAILED_TESTS + 1),
+ $#ARGV + 1,
+ (($#ARGV + 1) - ($#FAILED_TESTS + 1))
+ / ($#ARGV + 1) * 100);
+
+$t_str = sprintf ("Totals %7.2f %7.2f %7.2f"
+ . " %7.2f\n"
+ . " %s %7.2f %7.2f %7.2f %7.2f%%%%\n",
+ $total_utime, $total_stime, $total_utime + $total_stime,
+ ($total_ntime - ($total_hutime + $total_hstime)),
+ $tt_str . ' ' x (40 - length($tt_str)),
+ $total_hutime, $total_hstime, $total_hutime + $total_hstime,
+ ($total_hutime + $total_hstime == 0.0) ? 0.0 :
+ (($total_ntime
+ - ($total_hutime + $total_hstime))
+ / ($total_hutime + $total_hstime) * 100));
+
+@TSTATS = ("--------------------------------------------------------------------------\n",
+ $t_str,
+ "--------------------------------------------------------------------------\n"
+ );
+if (!$opt_quiet)
+{
+ foreach $line (@TSTATS)
+ {
+ printf STDOUT "$line";
+ }
+}
+
+if ($#FAILED_TESTS >= 0)
+{
+ # One or more tests failed, so return an error.
+ exit 1;
+}
+# End of main execution.
+
+sub run_test
+{
+ my ($test) = @_;
+ my ($okay) = 1;
+ my ($tutime, $tstime);
+ my ($utime, $stime, $cutime, $cstime);
+ my (@TSTATS, @TPATH);
+ my ($t_str);
+ my ($srcdir, $objdir);
+
+ # Get the path component of $test, if any.
+ @TPATH = split(/\//, $test);
+ pop(@TPATH);
+ $srcdir = join('/', ($opt_srcdir, @TPATH));
+ $objdir = join('/', ($opt_objdir, @TPATH));
+
+ @TSTATS = ("--------------------------------------------------------------------------\n");
+
+ $t_str = sprintf ("%s%s", $test, ' ' x (40 - length($test)));
+ @TSTATS = (@TSTATS, $t_str);
+ @STATS = (@STATS, @TSTATS);
+ if (!$opt_quiet)
+ {
+ foreach $line (@TSTATS)
+ {
+ printf STDOUT "$line";
+ }
+ }
+
+ ($utime, $stime, $cutime, $cstime) = times;
+ `$opt_objdir/$test $srcdir $objdir > $opt_objdir/$test.out 2>&1`;
+ ($utime, $stime, $tutime, $tstime) = times;
+
+ # Subtract the before time from the after time.
+ $tutime -= $cutime;
+ $tstime -= $cstime;
+
+ if ($opt_zero)
+ {
+ if ($?)
+ {
+ $okay = 0;
+ if ($opt_verbose)
+ {
+ print STDERR
+ "\"$opt_objdir/$test > $opt_objdir/$test.out 2>&1\" returned $?\n";
+ }
+ }
+ }
+
+ return ($okay, $tutime, $tstime);
+}
+
+sub print_stats
+{
+ my ($test, $okay, $failed_subtests, $subtests, $utime, $stime) = @_;
+ my ($hutime, $hstime);
+# my (TEST_PERF);
+ my (@TSTATS);
+ my ($t_str, $pass_str);
+
+ $pass_str = $okay ? "passed" : "*** FAILED ***";
+ if ((0 != $subtests) && (!$okay))
+ {
+ $pass_str = $pass_str . " ($failed_subtests/$subtests failed)";
+ }
+ $pass_str = $pass_str . ' ' x (39 - length($pass_str));
+
+ if (-r "$test.perf")
+ {
+ if (!open (TEST_PERF, "<$opt_objdir/$test.perf"))
+ {
+ print STDERR "Unable to open \"$opt_objdir/$test.perf\"\n";
+ exit 1;
+ }
+ $_ = <TEST_PERF>;
+
+ ($hutime, $hstime) = split;
+ close TEST_PERF;
+
+ $t_str = sprintf (" %7.2f %7.2f %7.2f %7.2f\n"
+ . " %s %7.2f %7.2f %7.2f %7.2f%%%%\n",
+ $utime, $stime, $utime + $stime,
+ ($utime + $stime) - ($hutime + $hstime),
+ $pass_str,
+ $hutime, $hstime, $hutime + $hstime,
+ (($hutime + $hstime) == 0.0) ? 0.0 :
+ ((($utime + $stime) - ($hutime + $hstime))
+ / ($hutime + $hstime) * 100));
+ }
+ else
+ {
+ $hutime = 0.0;
+ $hstime = 0.0;
+
+ $t_str = sprintf (" %7.2f %7.2f %7.2f \n"
+ . " %s\n",
+ $utime, $stime, $utime + $stime,
+ $pass_str);
+ }
+ @TSTATS = ($t_str);
+ if (!$opt_quiet)
+ {
+ foreach $line (@TSTATS)
+ {
+ printf STDOUT "$line";
+ }
+ }
+
+ if ($okay && $opt_ustats)
+ {
+ if (!open (TEST_PERF, ">$opt_objdir/$test.perf"))
+ {
+ if (!$opt_quiet)
+ {
+ print STDERR "Unable to update \"$opt_objdir/$test.perf\"\n";
+ }
+ }
+ else
+ {
+ print TEST_PERF "$utime $stime\n";
+ close TEST_PERF;
+ }
+ }
+
+ return ($hutime, $hstime);
+}
+
+sub usage
+{
+ print <<EOF;
+$0 usage:
+ $0 [<options>] <test>+
+
+ Option | Description
+ --------------+-------------------------------------------------------------
+ -h --help | Print usage and exit.
+ -v --verbose | Verbose (incompatible with quiet).
+ -q --quiet | Quiet (incompatible with verbose).
+ -s --srcdir | Path to source tree (default is ".").
+ -o --objdir | Path to object tree (default is ".").
+ -u --ustats | Update historical statistics (stored in "<test>.perf".
+ -z --zero | Consider non-zero exit code to be an error.
+ --------------+-------------------------------------------------------------
+
+ If <test>.exp exists, <test>'s output is diff'ed with <test>.exp. Any
+ difference is considered failure.
+
+ If <test>.exp does not exist, output to stdout of the following form is
+ expected:
+
+ 1..<n>
+ {not }ok[ 1]
+ {not }ok[ 2]
+ ...
+ {not }ok[ n]
+
+ 1 <= <n> < 2^31
+
+ Lines which do not match the patterns shown above are ignored.
+EOF
+}
diff --git a/lib/libkse/thread/Makefile.inc b/lib/libkse/thread/Makefile.inc
new file mode 100644
index 0000000..561be93
--- /dev/null
+++ b/lib/libkse/thread/Makefile.inc
@@ -0,0 +1,117 @@
+# $FreeBSD$
+
+# thr sources
+.PATH: ${.CURDIR}/thread
+
+SRCS+= \
+ thr_accept.c \
+ thr_aio_suspend.c \
+ thr_atfork.c \
+ thr_attr_destroy.c \
+ thr_attr_init.c \
+ thr_attr_get_np.c \
+ thr_attr_getdetachstate.c \
+ thr_attr_getguardsize.c \
+ thr_attr_getinheritsched.c \
+ thr_attr_getschedparam.c \
+ thr_attr_getschedpolicy.c \
+ thr_attr_getscope.c \
+ thr_attr_getstack.c \
+ thr_attr_getstackaddr.c \
+ thr_attr_getstacksize.c \
+ thr_attr_setcreatesuspend_np.c \
+ thr_attr_setdetachstate.c \
+ thr_attr_setguardsize.c \
+ thr_attr_setinheritsched.c \
+ thr_attr_setschedparam.c \
+ thr_attr_setschedpolicy.c \
+ thr_attr_setscope.c \
+ thr_attr_setstack.c \
+ thr_attr_setstackaddr.c \
+ thr_attr_setstacksize.c \
+ thr_autoinit.c \
+ thr_barrier.c \
+ thr_barrierattr.c \
+ thr_cancel.c \
+ thr_clean.c \
+ thr_close.c \
+ thr_concurrency.c \
+ thr_cond.c \
+ thr_condattr_destroy.c \
+ thr_condattr_init.c \
+ thr_condattr_pshared.c \
+ thr_connect.c \
+ thr_creat.c \
+ thr_create.c \
+ thr_detach.c \
+ thr_equal.c \
+ thr_execve.c \
+ thr_exit.c \
+ thr_fcntl.c \
+ thr_find_thread.c \
+ thr_fork.c \
+ thr_fsync.c \
+ thr_getprio.c \
+ thr_getschedparam.c \
+ thr_info.c \
+ thr_init.c \
+ thr_join.c \
+ thr_kern.c \
+ thr_kill.c \
+ thr_main_np.c \
+ thr_mattr_init.c \
+ thr_mattr_kind_np.c \
+ thr_mattr_pshared.c \
+ thr_msync.c \
+ thr_multi_np.c \
+ thr_mutex.c \
+ thr_mutex_prioceiling.c \
+ thr_mutex_protocol.c \
+ thr_mutexattr_destroy.c \
+ thr_nanosleep.c \
+ thr_once.c \
+ thr_open.c \
+ thr_pause.c \
+ thr_poll.c \
+ thr_printf.c \
+ thr_priority_queue.c \
+ thr_pselect.c \
+ thr_pspinlock.c \
+ thr_raise.c \
+ thr_read.c \
+ thr_readv.c \
+ thr_resume_np.c \
+ thr_rtld.c \
+ thr_rwlock.c \
+ thr_rwlockattr.c \
+ thr_select.c \
+ thr_self.c \
+ thr_sem.c \
+ thr_seterrno.c \
+ thr_setprio.c \
+ thr_setschedparam.c \
+ thr_sig.c \
+ thr_sigaction.c \
+ thr_sigaltstack.c \
+ thr_sigmask.c \
+ thr_sigpending.c \
+ thr_sigprocmask.c \
+ thr_sigsuspend.c \
+ thr_sigwait.c \
+ thr_single_np.c \
+ thr_sleep.c \
+ thr_spec.c \
+ thr_spinlock.c \
+ thr_stack.c \
+ thr_suspend_np.c \
+ thr_switch_np.c \
+ thr_system.c \
+ thr_symbols.c \
+ thr_tcdrain.c \
+ thr_vfork.c \
+ thr_wait.c \
+ thr_wait4.c \
+ thr_waitpid.c \
+ thr_write.c \
+ thr_writev.c \
+ thr_yield.c
diff --git a/lib/libkse/thread/thr_accept.c b/lib/libkse/thread/thr_accept.c
new file mode 100644
index 0000000..fc60fb4
--- /dev/null
+++ b/lib/libkse/thread/thr_accept.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2003 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 THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 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 <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__accept);
+LT10_COMPAT_DEFAULT(accept);
+
+__weak_reference(__accept, accept);
+
+int
+__accept(int s, struct sockaddr *addr, socklen_t *addrlen)
+{
+ struct pthread *curthread;
+ int ret;
+
+ curthread = _get_curthread();
+ _thr_cancel_enter(curthread);
+ ret = __sys_accept(s, addr, addrlen);
+ _thr_cancel_leave(curthread, ret == -1);
+
+ return (ret);
+}
diff --git a/lib/libkse/thread/thr_aio_suspend.c b/lib/libkse/thread/thr_aio_suspend.c
new file mode 100644
index 0000000..43a2414
--- /dev/null
+++ b/lib/libkse/thread/thr_aio_suspend.c
@@ -0,0 +1,54 @@
+/*
+ * 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$
+ */
+
+#include <aio.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_aio_suspend);
+LT10_COMPAT_DEFAULT(aio_suspend);
+
+__weak_reference(_aio_suspend, aio_suspend);
+
+int
+_aio_suspend(const struct aiocb * const iocbs[], int niocb, const struct
+ timespec *timeout)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ _thr_cancel_enter(curthread);
+ ret = __sys_aio_suspend(iocbs, niocb, timeout);
+ _thr_cancel_leave(curthread, 1);
+
+ return (ret);
+}
+
diff --git a/lib/libkse/thread/thr_atfork.c b/lib/libkse/thread/thr_atfork.c
new file mode 100644
index 0000000..a741329
--- /dev/null
+++ b/lib/libkse/thread/thr_atfork.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2003 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 THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <sys/queue.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_atfork);
+LT10_COMPAT_DEFAULT(pthread_atfork);
+
+__weak_reference(_pthread_atfork, pthread_atfork);
+
+int
+_pthread_atfork(void (*prepare)(void), void (*parent)(void),
+ void (*child)(void))
+{
+ struct pthread_atfork *af;
+
+ if (_thr_initial == NULL)
+ _libpthread_init(NULL);
+
+ if ((af = malloc(sizeof(struct pthread_atfork))) == NULL)
+ return (ENOMEM);
+
+ af->prepare = prepare;
+ af->parent = parent;
+ af->child = child;
+ _pthread_mutex_lock(&_thr_atfork_mutex);
+ TAILQ_INSERT_TAIL(&_thr_atfork_list, af, qe);
+ _pthread_mutex_unlock(&_thr_atfork_mutex);
+ return (0);
+}
+
diff --git a/lib/libkse/thread/thr_attr_destroy.c b/lib/libkse/thread/thr_attr_destroy.c
new file mode 100644
index 0000000..4442584
--- /dev/null
+++ b/lib/libkse/thread/thr_attr_destroy.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 1996 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_destroy);
+LT10_COMPAT_DEFAULT(pthread_attr_destroy);
+
+__weak_reference(_pthread_attr_destroy, pthread_attr_destroy);
+
+int
+_pthread_attr_destroy(pthread_attr_t *attr)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL)
+ /* Invalid argument: */
+ ret = EINVAL;
+ else {
+ /* Free the memory allocated to the attribute object: */
+ free(*attr);
+
+ /*
+ * Leave the attribute pointer NULL now that the memory
+ * has been freed:
+ */
+ *attr = NULL;
+ ret = 0;
+ }
+ return(ret);
+}
diff --git a/lib/libkse/thread/thr_attr_get_np.c b/lib/libkse/thread/thr_attr_get_np.c
new file mode 100644
index 0000000..a63088f
--- /dev/null
+++ b/lib/libkse/thread/thr_attr_get_np.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2002,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$
+ */
+#include <errno.h>
+#include <string.h>
+#include <pthread.h>
+#include <pthread_np.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_get_np);
+LT10_COMPAT_DEFAULT(pthread_attr_get_np);
+
+__weak_reference(_pthread_attr_get_np, pthread_attr_get_np);
+
+int
+_pthread_attr_get_np(pthread_t pid, pthread_attr_t *dst)
+{
+ struct pthread *curthread;
+ struct pthread_attr attr;
+ int ret;
+
+ if (pid == NULL || dst == NULL || *dst == NULL)
+ return (EINVAL);
+
+ curthread = _get_curthread();
+ if ((ret = _thr_ref_add(curthread, pid, /*include dead*/0)) != 0)
+ return (ret);
+ attr = pid->attr;
+ _thr_ref_delete(curthread, pid);
+ memcpy(*dst, &attr, sizeof(struct pthread_attr));
+
+ return (0);
+}
diff --git a/lib/libkse/thread/thr_attr_getdetachstate.c b/lib/libkse/thread/thr_attr_getdetachstate.c
new file mode 100644
index 0000000..e2ff6bd
--- /dev/null
+++ b/lib/libkse/thread/thr_attr_getdetachstate.c
@@ -0,0 +1,62 @@
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_getdetachstate);
+LT10_COMPAT_DEFAULT(pthread_attr_getdetachstate);
+
+__weak_reference(_pthread_attr_getdetachstate, pthread_attr_getdetachstate);
+
+int
+_pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL || detachstate == NULL)
+ ret = EINVAL;
+ else {
+ /* Check if the detached flag is set: */
+ if ((*attr)->flags & PTHREAD_DETACHED)
+ /* Return detached: */
+ *detachstate = PTHREAD_CREATE_DETACHED;
+ else
+ /* Return joinable: */
+ *detachstate = PTHREAD_CREATE_JOINABLE;
+ ret = 0;
+ }
+ return(ret);
+}
diff --git a/lib/libkse/thread/thr_attr_getguardsize.c b/lib/libkse/thread/thr_attr_getguardsize.c
new file mode 100644
index 0000000..351015c
--- /dev/null
+++ b/lib/libkse/thread/thr_attr_getguardsize.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2001 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
+ * unmodified other than the allowable 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 <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_getguardsize);
+LT10_COMPAT_DEFAULT(pthread_attr_getguardsize);
+
+__weak_reference(_pthread_attr_getguardsize, pthread_attr_getguardsize);
+
+int
+_pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL || guardsize == NULL)
+ ret = EINVAL;
+ else {
+ /* Return the guard size: */
+ *guardsize = (*attr)->guardsize_attr;
+ ret = 0;
+ }
+ return(ret);
+}
diff --git a/lib/libkse/thread/thr_attr_getinheritsched.c b/lib/libkse/thread/thr_attr_getinheritsched.c
new file mode 100644
index 0000000..eab19e3
--- /dev/null
+++ b/lib/libkse/thread/thr_attr_getinheritsched.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_getinheritsched);
+LT10_COMPAT_DEFAULT(pthread_attr_getinheritsched);
+
+__weak_reference(_pthread_attr_getinheritsched, pthread_attr_getinheritsched);
+
+int
+_pthread_attr_getinheritsched(const pthread_attr_t *attr, int *sched_inherit)
+{
+ int ret = 0;
+
+ if ((attr == NULL) || (*attr == NULL))
+ ret = EINVAL;
+ else
+ *sched_inherit = (*attr)->sched_inherit;
+
+ return(ret);
+}
diff --git a/lib/libkse/thread/thr_attr_getschedparam.c b/lib/libkse/thread/thr_attr_getschedparam.c
new file mode 100644
index 0000000..ca2eed3
--- /dev/null
+++ b/lib/libkse/thread/thr_attr_getschedparam.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_getschedparam);
+LT10_COMPAT_DEFAULT(pthread_attr_getschedparam);
+
+__weak_reference(_pthread_attr_getschedparam, pthread_attr_getschedparam);
+
+int
+_pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param)
+{
+ int ret = 0;
+
+ if ((attr == NULL) || (*attr == NULL) || (param == NULL))
+ ret = EINVAL;
+ else
+ param->sched_priority = (*attr)->prio;
+
+ return(ret);
+}
diff --git a/lib/libkse/thread/thr_attr_getschedpolicy.c b/lib/libkse/thread/thr_attr_getschedpolicy.c
new file mode 100644
index 0000000..dc952bd
--- /dev/null
+++ b/lib/libkse/thread/thr_attr_getschedpolicy.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_getschedpolicy);
+LT10_COMPAT_DEFAULT(pthread_attr_getschedpolicy);
+
+__weak_reference(_pthread_attr_getschedpolicy, pthread_attr_getschedpolicy);
+
+int
+_pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy)
+{
+ int ret = 0;
+
+ if ((attr == NULL) || (*attr == NULL) || (policy == NULL))
+ ret = EINVAL;
+ else
+ *policy = (*attr)->sched_policy;
+
+ return(ret);
+}
diff --git a/lib/libkse/thread/thr_attr_getscope.c b/lib/libkse/thread/thr_attr_getscope.c
new file mode 100644
index 0000000..ceb198f
--- /dev/null
+++ b/lib/libkse/thread/thr_attr_getscope.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_getscope);
+LT10_COMPAT_DEFAULT(pthread_attr_getscope);
+
+__weak_reference(_pthread_attr_getscope, pthread_attr_getscope);
+
+int
+_pthread_attr_getscope(const pthread_attr_t *attr, int *contentionscope)
+{
+ int ret = 0;
+
+ if ((attr == NULL) || (*attr == NULL) || (contentionscope == NULL))
+ /* Return an invalid argument: */
+ ret = EINVAL;
+
+ else
+ *contentionscope = (*attr)->flags & PTHREAD_SCOPE_SYSTEM ?
+ PTHREAD_SCOPE_SYSTEM : PTHREAD_SCOPE_PROCESS;
+
+ return(ret);
+}
diff --git a/lib/libkse/thread/thr_attr_getstack.c b/lib/libkse/thread/thr_attr_getstack.c
new file mode 100644
index 0000000..79a92cb
--- /dev/null
+++ b/lib/libkse/thread/thr_attr_getstack.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2003 Craig Rodrigues <rodrigc@attbi.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Craig Rodrigues.
+ * 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 CRAIG RODRIGUES AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_getstack);
+LT10_COMPAT_DEFAULT(pthread_attr_getstack);
+
+__weak_reference(_pthread_attr_getstack, pthread_attr_getstack);
+
+int
+_pthread_attr_getstack(const pthread_attr_t * __restrict attr,
+ void ** __restrict stackaddr,
+ size_t * __restrict stacksize)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL || stackaddr == NULL
+ || stacksize == NULL )
+ ret = EINVAL;
+ else {
+ /* Return the stack address and size */
+ *stackaddr = (*attr)->stackaddr_attr;
+ *stacksize = (*attr)->stacksize_attr;
+ ret = 0;
+ }
+ return(ret);
+}
+
diff --git a/lib/libkse/thread/thr_attr_getstackaddr.c b/lib/libkse/thread/thr_attr_getstackaddr.c
new file mode 100644
index 0000000..0d5c87c
--- /dev/null
+++ b/lib/libkse/thread/thr_attr_getstackaddr.c
@@ -0,0 +1,57 @@
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_getstackaddr);
+LT10_COMPAT_DEFAULT(pthread_attr_getstackaddr);
+
+__weak_reference(_pthread_attr_getstackaddr, pthread_attr_getstackaddr);
+
+int
+_pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL || stackaddr == NULL)
+ ret = EINVAL;
+ else {
+ /* Return the stack address: */
+ *stackaddr = (*attr)->stackaddr_attr;
+ ret = 0;
+ }
+ return(ret);
+}
diff --git a/lib/libkse/thread/thr_attr_getstacksize.c b/lib/libkse/thread/thr_attr_getstacksize.c
new file mode 100644
index 0000000..2636e97
--- /dev/null
+++ b/lib/libkse/thread/thr_attr_getstacksize.c
@@ -0,0 +1,57 @@
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_getstacksize);
+LT10_COMPAT_DEFAULT(pthread_attr_getstacksize);
+
+__weak_reference(_pthread_attr_getstacksize, pthread_attr_getstacksize);
+
+int
+_pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL || stacksize == NULL)
+ ret = EINVAL;
+ else {
+ /* Return the stack size: */
+ *stacksize = (*attr)->stacksize_attr;
+ ret = 0;
+ }
+ return(ret);
+}
diff --git a/lib/libkse/thread/thr_attr_init.c b/lib/libkse/thread/thr_attr_init.c
new file mode 100644
index 0000000..77f3f24
--- /dev/null
+++ b/lib/libkse/thread/thr_attr_init.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 1996 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_init);
+LT10_COMPAT_DEFAULT(pthread_attr_init);
+
+__weak_reference(_pthread_attr_init, pthread_attr_init);
+
+int
+_pthread_attr_init(pthread_attr_t *attr)
+{
+ int ret;
+ pthread_attr_t pattr;
+
+ /* Allocate memory for the attribute object: */
+ if ((pattr = (pthread_attr_t) malloc(sizeof(struct pthread_attr))) == NULL)
+ /* Insufficient memory: */
+ ret = ENOMEM;
+ else {
+ /* Initialise the attribute object with the defaults: */
+ memcpy(pattr, &_pthread_attr_default,
+ sizeof(struct pthread_attr));
+ pattr->guardsize_attr = _thr_guard_default;
+ pattr->stacksize_attr = _thr_stack_default;
+
+ /* Return a pointer to the attribute object: */
+ *attr = pattr;
+ ret = 0;
+ }
+ return(ret);
+}
diff --git a/lib/libkse/thread/thr_attr_setcreatesuspend_np.c b/lib/libkse/thread/thr_attr_setcreatesuspend_np.c
new file mode 100644
index 0000000..aa5f878
--- /dev/null
+++ b/lib/libkse/thread/thr_attr_setcreatesuspend_np.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_setcreatesuspend_np);
+LT10_COMPAT_DEFAULT(pthread_attr_setcreatesuspend_np);
+
+__weak_reference(_pthread_attr_setcreatesuspend_np, pthread_attr_setcreatesuspend_np);
+
+int
+_pthread_attr_setcreatesuspend_np(pthread_attr_t *attr)
+{
+ int ret;
+
+ if (attr == NULL || *attr == NULL) {
+ ret = EINVAL;
+ } else {
+ (*attr)->suspend = THR_CREATE_SUSPENDED;
+ ret = 0;
+ }
+ return(ret);
+}
diff --git a/lib/libkse/thread/thr_attr_setdetachstate.c b/lib/libkse/thread/thr_attr_setdetachstate.c
new file mode 100644
index 0000000..b17680b
--- /dev/null
+++ b/lib/libkse/thread/thr_attr_setdetachstate.c
@@ -0,0 +1,64 @@
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_setdetachstate);
+LT10_COMPAT_DEFAULT(pthread_attr_setdetachstate);
+
+__weak_reference(_pthread_attr_setdetachstate, pthread_attr_setdetachstate);
+
+int
+_pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL ||
+ (detachstate != PTHREAD_CREATE_DETACHED &&
+ detachstate != PTHREAD_CREATE_JOINABLE))
+ ret = EINVAL;
+ else {
+ /* Check if detached state: */
+ if (detachstate == PTHREAD_CREATE_DETACHED)
+ /* Set the detached flag: */
+ (*attr)->flags |= PTHREAD_DETACHED;
+ else
+ /* Reset the detached flag: */
+ (*attr)->flags &= ~PTHREAD_DETACHED;
+ ret = 0;
+ }
+ return(ret);
+}
diff --git a/lib/libkse/thread/thr_attr_setguardsize.c b/lib/libkse/thread/thr_attr_setguardsize.c
new file mode 100644
index 0000000..dedee8b
--- /dev/null
+++ b/lib/libkse/thread/thr_attr_setguardsize.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2001 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
+ * unmodified other than the allowable 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 <sys/param.h>
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_setguardsize);
+LT10_COMPAT_DEFAULT(pthread_attr_setguardsize);
+
+__weak_reference(_pthread_attr_setguardsize, pthread_attr_setguardsize);
+
+int
+_pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize)
+{
+ int ret;
+
+ /* Check for invalid arguments. */
+ if (attr == NULL || *attr == NULL)
+ ret = EINVAL;
+ else {
+ /* Save the stack size. */
+ (*attr)->guardsize_attr = guardsize;
+ ret = 0;
+ }
+ return(ret);
+}
diff --git a/lib/libkse/thread/thr_attr_setinheritsched.c b/lib/libkse/thread/thr_attr_setinheritsched.c
new file mode 100644
index 0000000..5182b7d
--- /dev/null
+++ b/lib/libkse/thread/thr_attr_setinheritsched.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_setinheritsched);
+LT10_COMPAT_DEFAULT(pthread_attr_setinheritsched);
+
+__weak_reference(_pthread_attr_setinheritsched, pthread_attr_setinheritsched);
+
+int
+_pthread_attr_setinheritsched(pthread_attr_t *attr, int sched_inherit)
+{
+ int ret = 0;
+
+ if ((attr == NULL) || (*attr == NULL))
+ ret = EINVAL;
+ else if (sched_inherit != PTHREAD_INHERIT_SCHED &&
+ sched_inherit != PTHREAD_EXPLICIT_SCHED)
+ ret = ENOTSUP;
+ else
+ (*attr)->sched_inherit = sched_inherit;
+
+ return(ret);
+}
diff --git a/lib/libkse/thread/thr_attr_setschedparam.c b/lib/libkse/thread/thr_attr_setschedparam.c
new file mode 100644
index 0000000..61d741d
--- /dev/null
+++ b/lib/libkse/thread/thr_attr_setschedparam.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_setschedparam);
+LT10_COMPAT_DEFAULT(pthread_attr_setschedparam);
+
+__weak_reference(_pthread_attr_setschedparam, pthread_attr_setschedparam);
+
+int
+_pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param)
+{
+ int ret = 0;
+
+ if ((attr == NULL) || (*attr == NULL))
+ ret = EINVAL;
+ else if (param == NULL) {
+ ret = ENOTSUP;
+ } else if ((param->sched_priority < THR_MIN_PRIORITY) ||
+ (param->sched_priority > THR_MAX_PRIORITY)) {
+ /* Return an unsupported value error. */
+ ret = ENOTSUP;
+ } else
+ (*attr)->prio = param->sched_priority;
+
+ return(ret);
+}
diff --git a/lib/libkse/thread/thr_attr_setschedpolicy.c b/lib/libkse/thread/thr_attr_setschedpolicy.c
new file mode 100644
index 0000000..fb24cb1
--- /dev/null
+++ b/lib/libkse/thread/thr_attr_setschedpolicy.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_setschedpolicy);
+LT10_COMPAT_DEFAULT(pthread_attr_setschedpolicy);
+
+__weak_reference(_pthread_attr_setschedpolicy, pthread_attr_setschedpolicy);
+
+int
+_pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
+{
+ int ret = 0;
+
+ if ((attr == NULL) || (*attr == NULL))
+ ret = EINVAL;
+ else if ((policy < SCHED_FIFO) || (policy > SCHED_RR)) {
+ ret = ENOTSUP;
+ } else
+ (*attr)->sched_policy = policy;
+
+ return(ret);
+}
diff --git a/lib/libkse/thread/thr_attr_setscope.c b/lib/libkse/thread/thr_attr_setscope.c
new file mode 100644
index 0000000..3cc7f16
--- /dev/null
+++ b/lib/libkse/thread/thr_attr_setscope.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_setscope);
+LT10_COMPAT_DEFAULT(pthread_attr_setscope);
+
+__weak_reference(_pthread_attr_setscope, pthread_attr_setscope);
+
+int
+_pthread_attr_setscope(pthread_attr_t *attr, int contentionscope)
+{
+ int ret = 0;
+
+ if ((attr == NULL) || (*attr == NULL)) {
+ /* Return an invalid argument: */
+ ret = EINVAL;
+ } else if ((contentionscope != PTHREAD_SCOPE_PROCESS) &&
+ (contentionscope != PTHREAD_SCOPE_SYSTEM)) {
+ ret = EINVAL;
+ } else if (contentionscope == PTHREAD_SCOPE_SYSTEM) {
+ (*attr)->flags |= contentionscope;
+ } else {
+ (*attr)->flags &= ~PTHREAD_SCOPE_SYSTEM;
+ }
+ return (ret);
+}
diff --git a/lib/libkse/thread/thr_attr_setstack.c b/lib/libkse/thread/thr_attr_setstack.c
new file mode 100644
index 0000000..bdccfd8
--- /dev/null
+++ b/lib/libkse/thread/thr_attr_setstack.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2003 Craig Rodrigues <rodrigc@attbi.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Craig Rodrigues.
+ * 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 CRAIG RODRIGUES AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_setstack);
+LT10_COMPAT_DEFAULT(pthread_attr_setstack);
+
+__weak_reference(_pthread_attr_setstack, pthread_attr_setstack);
+
+int
+_pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr,
+ size_t stacksize)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL || stackaddr == NULL
+ || stacksize < PTHREAD_STACK_MIN )
+ ret = EINVAL;
+ else {
+ /* Save the stack address and stack size */
+ (*attr)->stackaddr_attr = stackaddr;
+ (*attr)->stacksize_attr = stacksize;
+ ret = 0;
+ }
+ return(ret);
+}
+
diff --git a/lib/libkse/thread/thr_attr_setstackaddr.c b/lib/libkse/thread/thr_attr_setstackaddr.c
new file mode 100644
index 0000000..5f0a903
--- /dev/null
+++ b/lib/libkse/thread/thr_attr_setstackaddr.c
@@ -0,0 +1,57 @@
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_setstackaddr);
+LT10_COMPAT_DEFAULT(pthread_attr_setstackaddr);
+
+__weak_reference(_pthread_attr_setstackaddr, pthread_attr_setstackaddr);
+
+int
+_pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL || stackaddr == NULL)
+ ret = EINVAL;
+ else {
+ /* Save the stack address: */
+ (*attr)->stackaddr_attr = stackaddr;
+ ret = 0;
+ }
+ return(ret);
+}
diff --git a/lib/libkse/thread/thr_attr_setstacksize.c b/lib/libkse/thread/thr_attr_setstacksize.c
new file mode 100644
index 0000000..6fa9760
--- /dev/null
+++ b/lib/libkse/thread/thr_attr_setstacksize.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 1996 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_setstacksize);
+LT10_COMPAT_DEFAULT(pthread_attr_setstacksize);
+
+__weak_reference(_pthread_attr_setstacksize, pthread_attr_setstacksize);
+
+int
+_pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL || stacksize < PTHREAD_STACK_MIN)
+ ret = EINVAL;
+ else {
+ /* Save the stack size: */
+ (*attr)->stacksize_attr = stacksize;
+ ret = 0;
+ }
+ return(ret);
+}
diff --git a/lib/libkse/thread/thr_autoinit.c b/lib/libkse/thread/thr_autoinit.c
new file mode 100644
index 0000000..95b2a85
--- /dev/null
+++ b/lib/libkse/thread/thr_autoinit.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2002 Alfred Perlstein <alfred@freebsd.org>.
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 module uses GCC extentions to initialize the
+ * threads package at program start-up time.
+ */
+
+#include <pthread.h>
+#include "thr_private.h"
+
+void _thread_init_hack(void) __attribute__ ((constructor));
+
+void
+_thread_init_hack(void)
+{
+
+ _libpthread_init(NULL);
+}
+
+/*
+ * For the shared version of the threads library, the above is sufficient.
+ * But for the archive version of the library, we need a little bit more.
+ * Namely, we must arrange for this particular module to be pulled in from
+ * the archive library at link time. To accomplish that, we define and
+ * initialize a variable, "_thread_autoinit_dummy_decl". This variable is
+ * referenced (as an extern) from libc/stdlib/exit.c. This will always
+ * create a need for this module, ensuring that it is present in the
+ * executable.
+ */
+extern int _thread_autoinit_dummy_decl;
+int _thread_autoinit_dummy_decl = 0;
diff --git a/lib/libkse/thread/thr_barrier.c b/lib/libkse/thread/thr_barrier.c
new file mode 100644
index 0000000..c8be343
--- /dev/null
+++ b/lib/libkse/thread/thr_barrier.c
@@ -0,0 +1,129 @@
+/*-
+ * Copyright (c) 2003 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include "namespace.h"
+#include <pthread.h>
+#include "un-namespace.h"
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_barrier_init);
+LT10_COMPAT_DEFAULT(pthread_barrier_init);
+LT10_COMPAT_PRIVATE(_pthread_barrier_wait);
+LT10_COMPAT_DEFAULT(pthread_barrier_wait);
+LT10_COMPAT_PRIVATE(_pthread_barrier_destroy);
+LT10_COMPAT_DEFAULT(pthread_barrier_destroy);
+
+__weak_reference(_pthread_barrier_init, pthread_barrier_init);
+__weak_reference(_pthread_barrier_wait, pthread_barrier_wait);
+__weak_reference(_pthread_barrier_destroy, pthread_barrier_destroy);
+
+int
+_pthread_barrier_destroy(pthread_barrier_t *barrier)
+{
+ pthread_barrier_t bar;
+ int ret, ret2;
+
+ if (barrier == NULL || *barrier == NULL)
+ return (EINVAL);
+
+ bar = *barrier;
+ if (bar->b_waiters > 0)
+ return (EBUSY);
+ *barrier = NULL;
+ ret = _pthread_mutex_destroy(&bar->b_lock);
+ ret2 = _pthread_cond_destroy(&bar->b_cond);
+ free(bar);
+ return (ret ? ret : ret2);
+}
+
+int
+_pthread_barrier_init(pthread_barrier_t *barrier,
+ const pthread_barrierattr_t *attr, unsigned count)
+{
+ pthread_barrier_t bar;
+ int ret;
+
+ if (barrier == NULL || count <= 0)
+ return (EINVAL);
+
+ bar = malloc(sizeof(struct pthread_barrier));
+ if (bar == NULL)
+ return (ENOMEM);
+
+ if ((ret = _pthread_mutex_init(&bar->b_lock, NULL)) != 0) {
+ free(bar);
+ return (ret);
+ }
+
+ if ((ret = _pthread_cond_init(&bar->b_cond, NULL)) != 0) {
+ _pthread_mutex_destroy(&bar->b_lock);
+ free(bar);
+ return (ret);
+ }
+
+ bar->b_waiters = 0;
+ bar->b_count = count;
+ bar->b_generation = 0;
+ *barrier = bar;
+
+ return (0);
+}
+
+int
+_pthread_barrier_wait(pthread_barrier_t *barrier)
+{
+ int ret, gen;
+ pthread_barrier_t bar;
+
+ if (barrier == NULL || *barrier == NULL)
+ return (EINVAL);
+
+ bar = *barrier;
+ if ((ret = _pthread_mutex_lock(&bar->b_lock)) != 0)
+ return (ret);
+
+ if (++bar->b_waiters == bar->b_count) {
+ /* Current thread is lastest thread */
+ bar->b_generation++;
+ bar->b_waiters = 0;
+ ret = _pthread_cond_broadcast(&bar->b_cond);
+ if (ret == 0)
+ ret = PTHREAD_BARRIER_SERIAL_THREAD;
+ } else {
+ gen = bar->b_generation;
+ do {
+ ret = _pthread_cond_wait(
+ &bar->b_cond, &bar->b_lock);
+ /* test generation to avoid bogus wakeup */
+ } while (ret == 0 && gen == bar->b_generation);
+ }
+ _pthread_mutex_unlock(&bar->b_lock);
+ return (ret);
+}
diff --git a/lib/libkse/thread/thr_barrierattr.c b/lib/libkse/thread/thr_barrierattr.c
new file mode 100644
index 0000000..3384aee
--- /dev/null
+++ b/lib/libkse/thread/thr_barrierattr.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2003 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 <errno.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_barrierattr_destroy);
+LT10_COMPAT_DEFAULT(pthread_barrierattr_destroy);
+LT10_COMPAT_PRIVATE(_pthread_barrierattr_init);
+LT10_COMPAT_DEFAULT(pthread_barrierattr_init);
+LT10_COMPAT_PRIVATE(_pthread_barrierattr_setpshared);
+LT10_COMPAT_DEFAULT(pthread_barrierattr_setpshared);
+LT10_COMPAT_PRIVATE(_pthread_barrierattr_getpshared);
+LT10_COMPAT_DEFAULT(pthread_barrierattr_getpshared);
+
+__weak_reference(_pthread_barrierattr_destroy, pthread_barrierattr_destroy);
+__weak_reference(_pthread_barrierattr_init, pthread_barrierattr_init);
+__weak_reference(_pthread_barrierattr_setpshared,
+ pthread_barrierattr_setpshared);
+__weak_reference(_pthread_barrierattr_getpshared,
+ pthread_barrierattr_getpshared);
+
+int
+_pthread_barrierattr_destroy(pthread_barrierattr_t *attr)
+{
+
+ if (attr == NULL || *attr == NULL)
+ return (EINVAL);
+
+ free(*attr);
+ return (0);
+}
+
+int
+_pthread_barrierattr_getpshared(const pthread_barrierattr_t *attr,
+ int *pshared)
+{
+
+ if (attr == NULL || *attr == NULL)
+ return (EINVAL);
+
+ *pshared = (*attr)->pshared;
+ return (0);
+}
+
+int
+_pthread_barrierattr_init(pthread_barrierattr_t *attr)
+{
+
+ if (attr == NULL)
+ return (EINVAL);
+
+ if ((*attr = malloc(sizeof(struct pthread_barrierattr))) == NULL)
+ return (ENOMEM);
+
+ (*attr)->pshared = PTHREAD_PROCESS_PRIVATE;
+ return (0);
+}
+
+int
+_pthread_barrierattr_setpshared(pthread_barrierattr_t *attr, int pshared)
+{
+
+ if (attr == NULL || *attr == NULL)
+ return (EINVAL);
+
+ /* Only PTHREAD_PROCESS_PRIVATE is supported. */
+ if (pshared != PTHREAD_PROCESS_PRIVATE)
+ return (EINVAL);
+
+ (*attr)->pshared = pshared;
+ return (0);
+}
diff --git a/lib/libkse/thread/thr_cancel.c b/lib/libkse/thread/thr_cancel.c
new file mode 100644
index 0000000..bbf6fdf
--- /dev/null
+++ b/lib/libkse/thread/thr_cancel.c
@@ -0,0 +1,311 @@
+/*
+ * David Leonard <d@openbsd.org>, 1999. Public domain.
+ * $FreeBSD$
+ */
+#include <sys/errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_cancel);
+LT10_COMPAT_DEFAULT(pthread_cancel);
+LT10_COMPAT_PRIVATE(_pthread_setcancelstate);
+LT10_COMPAT_DEFAULT(pthread_setcancelstate);
+LT10_COMPAT_PRIVATE(_pthread_setcanceltype);
+LT10_COMPAT_DEFAULT(pthread_setcanceltype);
+LT10_COMPAT_PRIVATE(_pthread_testcancel);
+LT10_COMPAT_DEFAULT(pthread_testcancel);
+
+__weak_reference(_pthread_cancel, pthread_cancel);
+__weak_reference(_pthread_setcancelstate, pthread_setcancelstate);
+__weak_reference(_pthread_setcanceltype, pthread_setcanceltype);
+__weak_reference(_pthread_testcancel, pthread_testcancel);
+
+static inline int
+checkcancel(struct pthread *curthread)
+{
+ if ((curthread->cancelflags & THR_CANCELLING) != 0) {
+ /*
+ * It is possible for this thread to be swapped out
+ * while performing cancellation; do not allow it
+ * to be cancelled again.
+ */
+ if ((curthread->flags & THR_FLAGS_EXITING) != 0) {
+ /*
+ * This may happen once, but after this, it
+ * shouldn't happen again.
+ */
+ curthread->cancelflags &= ~THR_CANCELLING;
+ return (0);
+ }
+ if ((curthread->cancelflags & PTHREAD_CANCEL_DISABLE) == 0) {
+ curthread->cancelflags &= ~THR_CANCELLING;
+ return (1);
+ }
+ }
+ return (0);
+}
+
+static inline void
+testcancel(struct pthread *curthread)
+{
+ if (checkcancel(curthread) != 0) {
+ /* Unlock before exiting: */
+ THR_THREAD_UNLOCK(curthread, curthread);
+
+ _thr_exit_cleanup();
+ pthread_exit(PTHREAD_CANCELED);
+ PANIC("cancel");
+ }
+}
+
+int
+_pthread_cancel(pthread_t pthread)
+{
+ struct pthread *curthread = _get_curthread();
+ struct pthread *joinee = NULL;
+ struct kse_mailbox *kmbx = NULL;
+ int ret;
+
+ if ((ret = _thr_ref_add(curthread, pthread, /*include dead*/0)) == 0) {
+ /*
+ * Take the thread's lock while we change the cancel flags.
+ */
+ THR_THREAD_LOCK(curthread, pthread);
+ THR_SCHED_LOCK(curthread, pthread);
+ if (pthread->flags & THR_FLAGS_EXITING) {
+ THR_SCHED_UNLOCK(curthread, pthread);
+ THR_THREAD_UNLOCK(curthread, pthread);
+ _thr_ref_delete(curthread, pthread);
+ return (ESRCH);
+ }
+ if (((pthread->cancelflags & PTHREAD_CANCEL_DISABLE) != 0) ||
+ (((pthread->cancelflags & THR_AT_CANCEL_POINT) == 0) &&
+ ((pthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) == 0)))
+ /* Just mark it for cancellation: */
+ pthread->cancelflags |= THR_CANCELLING;
+ else {
+ /*
+ * Check if we need to kick it back into the
+ * run queue:
+ */
+ switch (pthread->state) {
+ case PS_RUNNING:
+ /* No need to resume: */
+ pthread->cancelflags |= THR_CANCELLING;
+ break;
+
+ case PS_LOCKWAIT:
+ /*
+ * These can't be removed from the queue.
+ * Just mark it as cancelling and tell it
+ * to yield once it leaves the critical
+ * region.
+ */
+ pthread->cancelflags |= THR_CANCELLING;
+ pthread->critical_yield = 1;
+ break;
+
+ case PS_SLEEP_WAIT:
+ case PS_SIGSUSPEND:
+ case PS_SIGWAIT:
+ /* Interrupt and resume: */
+ pthread->interrupted = 1;
+ pthread->cancelflags |= THR_CANCELLING;
+ kmbx = _thr_setrunnable_unlocked(pthread);
+ break;
+
+ case PS_JOIN:
+ /* Disconnect the thread from the joinee: */
+ joinee = pthread->join_status.thread;
+ pthread->join_status.thread = NULL;
+ pthread->cancelflags |= THR_CANCELLING;
+ kmbx = _thr_setrunnable_unlocked(pthread);
+ if ((joinee != NULL) &&
+ (pthread->kseg == joinee->kseg)) {
+ /* Remove the joiner from the joinee. */
+ joinee->joiner = NULL;
+ joinee = NULL;
+ }
+ break;
+
+ case PS_SUSPENDED:
+ case PS_MUTEX_WAIT:
+ case PS_COND_WAIT:
+ /*
+ * Threads in these states may be in queues.
+ * In order to preserve queue integrity, the
+ * cancelled thread must remove itself from the
+ * queue. Mark the thread as interrupted and
+ * needing cancellation, and set the state to
+ * running. When the thread resumes, it will
+ * remove itself from the queue and call the
+ * cancellation completion routine.
+ */
+ pthread->interrupted = 1;
+ pthread->cancelflags |= THR_CANCEL_NEEDED;
+ kmbx = _thr_setrunnable_unlocked(pthread);
+ pthread->continuation =
+ _thr_finish_cancellation;
+ break;
+
+ case PS_DEAD:
+ case PS_DEADLOCK:
+ case PS_STATE_MAX:
+ /* Ignore - only here to silence -Wall: */
+ break;
+ }
+ if ((pthread->cancelflags & THR_AT_CANCEL_POINT) &&
+ (pthread->blocked != 0 ||
+ pthread->attr.flags & PTHREAD_SCOPE_SYSTEM))
+ kse_thr_interrupt(&pthread->tcb->tcb_tmbx,
+ KSE_INTR_INTERRUPT, 0);
+ }
+
+ /*
+ * Release the thread's lock and remove the
+ * reference:
+ */
+ THR_SCHED_UNLOCK(curthread, pthread);
+ THR_THREAD_UNLOCK(curthread, pthread);
+ _thr_ref_delete(curthread, pthread);
+ if (kmbx != NULL)
+ kse_wakeup(kmbx);
+
+ if ((joinee != NULL) &&
+ (_thr_ref_add(curthread, joinee, /* include dead */1) == 0)) {
+ /* Remove the joiner from the joinee. */
+ THR_SCHED_LOCK(curthread, joinee);
+ joinee->joiner = NULL;
+ THR_SCHED_UNLOCK(curthread, joinee);
+ _thr_ref_delete(curthread, joinee);
+ }
+ }
+ return (ret);
+}
+
+int
+_pthread_setcancelstate(int state, int *oldstate)
+{
+ struct pthread *curthread = _get_curthread();
+ int ostate;
+ int ret;
+ int need_exit = 0;
+
+ /* Take the thread's lock while fiddling with the state: */
+ THR_THREAD_LOCK(curthread, curthread);
+
+ ostate = curthread->cancelflags & PTHREAD_CANCEL_DISABLE;
+
+ switch (state) {
+ case PTHREAD_CANCEL_ENABLE:
+ curthread->cancelflags &= ~PTHREAD_CANCEL_DISABLE;
+ if ((curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0)
+ need_exit = checkcancel(curthread);
+ ret = 0;
+ break;
+ case PTHREAD_CANCEL_DISABLE:
+ curthread->cancelflags |= PTHREAD_CANCEL_DISABLE;
+ ret = 0;
+ break;
+ default:
+ ret = EINVAL;
+ }
+
+ THR_THREAD_UNLOCK(curthread, curthread);
+ if (need_exit != 0) {
+ _thr_exit_cleanup();
+ pthread_exit(PTHREAD_CANCELED);
+ PANIC("cancel");
+ }
+ if (ret == 0 && oldstate != NULL)
+ *oldstate = ostate;
+
+ return (ret);
+}
+
+int
+_pthread_setcanceltype(int type, int *oldtype)
+{
+ struct pthread *curthread = _get_curthread();
+ int otype;
+ int ret;
+ int need_exit = 0;
+
+ /* Take the thread's lock while fiddling with the state: */
+ THR_THREAD_LOCK(curthread, curthread);
+
+ otype = curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS;
+ switch (type) {
+ case PTHREAD_CANCEL_ASYNCHRONOUS:
+ curthread->cancelflags |= PTHREAD_CANCEL_ASYNCHRONOUS;
+ need_exit = checkcancel(curthread);
+ ret = 0;
+ break;
+ case PTHREAD_CANCEL_DEFERRED:
+ curthread->cancelflags &= ~PTHREAD_CANCEL_ASYNCHRONOUS;
+ ret = 0;
+ break;
+ default:
+ ret = EINVAL;
+ }
+
+ THR_THREAD_UNLOCK(curthread, curthread);
+ if (need_exit != 0) {
+ _thr_exit_cleanup();
+ pthread_exit(PTHREAD_CANCELED);
+ PANIC("cancel");
+ }
+ if (ret == 0 && oldtype != NULL)
+ *oldtype = otype;
+
+ return (ret);
+}
+
+void
+_pthread_testcancel(void)
+{
+ struct pthread *curthread = _get_curthread();
+
+ THR_THREAD_LOCK(curthread, curthread);
+ testcancel(curthread);
+ THR_THREAD_UNLOCK(curthread, curthread);
+}
+
+void
+_thr_cancel_enter(struct pthread *thread)
+{
+ /* Look for a cancellation before we block: */
+ THR_THREAD_LOCK(thread, thread);
+ testcancel(thread);
+ thread->cancelflags |= THR_AT_CANCEL_POINT;
+ THR_THREAD_UNLOCK(thread, thread);
+}
+
+void
+_thr_cancel_leave(struct pthread *thread, int check)
+{
+ THR_THREAD_LOCK(thread, thread);
+ thread->cancelflags &= ~THR_AT_CANCEL_POINT;
+ /* Look for a cancellation after we unblock: */
+ if (check)
+ testcancel(thread);
+ THR_THREAD_UNLOCK(thread, thread);
+}
+
+void
+_thr_finish_cancellation(void *arg)
+{
+ struct pthread *curthread = _get_curthread();
+
+ curthread->continuation = NULL;
+ curthread->interrupted = 0;
+
+ THR_THREAD_LOCK(curthread, curthread);
+ if ((curthread->cancelflags & THR_CANCEL_NEEDED) != 0) {
+ curthread->cancelflags &= ~THR_CANCEL_NEEDED;
+ THR_THREAD_UNLOCK(curthread, curthread);
+ _thr_exit_cleanup();
+ pthread_exit(PTHREAD_CANCELED);
+ }
+ THR_THREAD_UNLOCK(curthread, curthread);
+}
diff --git a/lib/libkse/thread/thr_clean.c b/lib/libkse/thread/thr_clean.c
new file mode 100644
index 0000000..4db5c93
--- /dev/null
+++ b/lib/libkse/thread/thr_clean.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <signal.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_cleanup_push);
+LT10_COMPAT_DEFAULT(pthread_cleanup_push);
+LT10_COMPAT_PRIVATE(_pthread_cleanup_pop);
+LT10_COMPAT_DEFAULT(pthread_cleanup_pop);
+
+__weak_reference(_pthread_cleanup_push, pthread_cleanup_push);
+__weak_reference(_pthread_cleanup_pop, pthread_cleanup_pop);
+
+void
+_pthread_cleanup_push(void (*routine) (void *), void *routine_arg)
+{
+ struct pthread *curthread = _get_curthread();
+ struct pthread_cleanup *new;
+
+ if ((new = (struct pthread_cleanup *)
+ malloc(sizeof(struct pthread_cleanup))) != NULL) {
+ new->routine = routine;
+ new->routine_arg = routine_arg;
+ new->onstack = 0;
+ new->next = curthread->cleanup;
+
+ curthread->cleanup = new;
+ }
+}
+
+void
+_pthread_cleanup_pop(int execute)
+{
+ struct pthread *curthread = _get_curthread();
+ struct pthread_cleanup *old;
+
+ if ((old = curthread->cleanup) != NULL) {
+ curthread->cleanup = old->next;
+ if (execute) {
+ old->routine(old->routine_arg);
+ }
+ if (old->onstack == 0)
+ free(old);
+ }
+}
diff --git a/lib/libkse/thread/thr_close.c b/lib/libkse/thread/thr_close.c
new file mode 100644
index 0000000..7b4fe72
--- /dev/null
+++ b/lib/libkse/thread/thr_close.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__close);
+LT10_COMPAT_DEFAULT(close);
+
+__weak_reference(__close, close);
+
+int
+__close(int fd)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ _thr_cancel_enter(curthread);
+ ret = __sys_close(fd);
+ _thr_cancel_leave(curthread, 1);
+
+ return (ret);
+}
diff --git a/lib/libkse/thread/thr_concurrency.c b/lib/libkse/thread/thr_concurrency.c
new file mode 100644
index 0000000..74e0e11
--- /dev/null
+++ b/lib/libkse/thread/thr_concurrency.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2003 Daniel M. Eischen <deischen@freebsd.org>
+ * Copyright (c) 2003 Sergey Osokin <osa@freebsd.org.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. 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_getconcurrency);
+LT10_COMPAT_DEFAULT(pthread_getconcurrency);
+LT10_COMPAT_PRIVATE(_pthread_setconcurrency);
+LT10_COMPAT_DEFAULT(pthread_setconcurrency);
+
+/*#define DEBUG_CONCURRENCY */
+#ifdef DEBUG_CONCURRENCY
+#define DBG_MSG stdout_debug
+#else
+#define DBG_MSG(x...)
+#endif
+
+static int level = 0;
+
+__weak_reference(_pthread_getconcurrency, pthread_getconcurrency);
+__weak_reference(_pthread_setconcurrency, pthread_setconcurrency);
+
+int
+_pthread_getconcurrency(void)
+{
+ return (level);
+}
+
+int
+_pthread_setconcurrency(int new_level)
+{
+ int ret;
+
+ if (new_level < 0)
+ ret = EINVAL;
+ else if (new_level == level)
+ ret = 0;
+ else if (new_level == 0) {
+ level = 0;
+ ret = 0;
+ } else if ((_kse_isthreaded() == 0) && (_kse_setthreaded(1) != 0)) {
+ DBG_MSG("Can't enable threading.\n");
+ ret = EAGAIN;
+ } else {
+ ret = _thr_setconcurrency(new_level);
+ if (ret == 0)
+ level = new_level;
+ }
+ return (ret);
+}
+
+int
+_thr_setconcurrency(int new_level)
+{
+ struct pthread *curthread;
+ struct kse *newkse, *kse;
+ kse_critical_t crit;
+ int kse_count;
+ int i;
+ int ret;
+
+ /*
+ * Turn on threaded mode, if failed, it is unnecessary to
+ * do further work.
+ */
+ if (_kse_isthreaded() == 0 && _kse_setthreaded(1))
+ return (EAGAIN);
+
+ ret = 0;
+ curthread = _get_curthread();
+ /* Race condition, but so what. */
+ kse_count = _kse_initial->k_kseg->kg_ksecount;
+ if (new_level > kse_count) {
+ for (i = kse_count; i < new_level; i++) {
+ newkse = _kse_alloc(curthread, 0);
+ if (newkse == NULL) {
+ DBG_MSG("Can't alloc new KSE.\n");
+ ret = EAGAIN;
+ break;
+ }
+ newkse->k_kseg = _kse_initial->k_kseg;
+ newkse->k_schedq = _kse_initial->k_schedq;
+ newkse->k_curthread = NULL;
+ crit = _kse_critical_enter();
+ KSE_SCHED_LOCK(curthread->kse, newkse->k_kseg);
+ TAILQ_INSERT_TAIL(&newkse->k_kseg->kg_kseq,
+ newkse, k_kgqe);
+ newkse->k_kseg->kg_ksecount++;
+ newkse->k_flags |= KF_STARTED;
+ KSE_SCHED_UNLOCK(curthread->kse, newkse->k_kseg);
+ if (kse_create(&newkse->k_kcb->kcb_kmbx, 0) != 0) {
+ KSE_SCHED_LOCK(curthread->kse, newkse->k_kseg);
+ TAILQ_REMOVE(&newkse->k_kseg->kg_kseq,
+ newkse, k_kgqe);
+ newkse->k_kseg->kg_ksecount--;
+ KSE_SCHED_UNLOCK(curthread->kse,
+ newkse->k_kseg);
+ _kse_critical_leave(crit);
+ _kse_free(curthread, newkse);
+ DBG_MSG("kse_create syscall failed.\n");
+ ret = EAGAIN;
+ break;
+ } else {
+ _kse_critical_leave(crit);
+ }
+ }
+ } else if (new_level < kse_count) {
+ kse_count = 0;
+ crit = _kse_critical_enter();
+ KSE_SCHED_LOCK(curthread->kse, _kse_initial->k_kseg);
+ /* Count the number of active KSEs */
+ TAILQ_FOREACH(kse, &_kse_initial->k_kseg->kg_kseq, k_kgqe) {
+ if ((kse->k_flags & KF_TERMINATED) == 0)
+ kse_count++;
+ }
+ /* Reduce the number of active KSEs appropriately. */
+ kse = TAILQ_FIRST(&_kse_initial->k_kseg->kg_kseq);
+ while ((kse != NULL) && (kse_count > new_level)) {
+ if ((kse != _kse_initial) &&
+ ((kse->k_flags & KF_TERMINATED) == 0)) {
+ kse->k_flags |= KF_TERMINATED;
+ kse_count--;
+ /* Wakup the KSE in case it is idle. */
+ kse_wakeup(&kse->k_kcb->kcb_kmbx);
+ }
+ kse = TAILQ_NEXT(kse, k_kgqe);
+ }
+ KSE_SCHED_UNLOCK(curthread->kse, _kse_initial->k_kseg);
+ _kse_critical_leave(crit);
+ }
+ return (ret);
+}
+
+int
+_thr_setmaxconcurrency(void)
+{
+ int vcpu;
+ size_t len;
+ int ret;
+
+ len = sizeof(vcpu);
+ ret = sysctlbyname("kern.threads.virtual_cpu", &vcpu, &len, NULL, 0);
+ if (ret == 0 && vcpu > 0)
+ ret = _thr_setconcurrency(vcpu);
+ return (ret);
+}
+
diff --git a/lib/libkse/thread/thr_cond.c b/lib/libkse/thread/thr_cond.c
new file mode 100644
index 0000000..e39ae63
--- /dev/null
+++ b/lib/libkse/thread/thr_cond.c
@@ -0,0 +1,847 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <errno.h>
+#include <string.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__pthread_cond_wait);
+LT10_COMPAT_PRIVATE(_pthread_cond_wait);
+LT10_COMPAT_DEFAULT(pthread_cond_wait);
+LT10_COMPAT_PRIVATE(__pthread_cond_timedwait);
+LT10_COMPAT_PRIVATE(_pthread_cond_timedwait);
+LT10_COMPAT_DEFAULT(pthread_cond_timedwait);
+LT10_COMPAT_PRIVATE(_pthread_cond_init);
+LT10_COMPAT_DEFAULT(pthread_cond_init);
+LT10_COMPAT_PRIVATE(_pthread_cond_destroy);
+LT10_COMPAT_DEFAULT(pthread_cond_destroy);
+LT10_COMPAT_PRIVATE(_pthread_cond_signal);
+LT10_COMPAT_DEFAULT(pthread_cond_signal);
+LT10_COMPAT_PRIVATE(_pthread_cond_broadcast);
+LT10_COMPAT_DEFAULT(pthread_cond_broadcast);
+
+#define THR_IN_CONDQ(thr) (((thr)->sflags & THR_FLAGS_IN_SYNCQ) != 0)
+#define THR_CONDQ_SET(thr) (thr)->sflags |= THR_FLAGS_IN_SYNCQ
+#define THR_CONDQ_CLEAR(thr) (thr)->sflags &= ~THR_FLAGS_IN_SYNCQ
+
+/*
+ * Prototypes
+ */
+static inline struct pthread *cond_queue_deq(pthread_cond_t);
+static inline void cond_queue_remove(pthread_cond_t, pthread_t);
+static inline void cond_queue_enq(pthread_cond_t, pthread_t);
+static void cond_wait_backout(void *);
+static inline void check_continuation(struct pthread *,
+ struct pthread_cond *, pthread_mutex_t *);
+
+/*
+ * Double underscore versions are cancellation points. Single underscore
+ * versions are not and are provided for libc internal usage (which
+ * shouldn't introduce cancellation points).
+ */
+__weak_reference(__pthread_cond_wait, pthread_cond_wait);
+__weak_reference(__pthread_cond_timedwait, pthread_cond_timedwait);
+
+__weak_reference(_pthread_cond_init, pthread_cond_init);
+__weak_reference(_pthread_cond_destroy, pthread_cond_destroy);
+__weak_reference(_pthread_cond_signal, pthread_cond_signal);
+__weak_reference(_pthread_cond_broadcast, pthread_cond_broadcast);
+
+
+int
+_pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr)
+{
+ enum pthread_cond_type type;
+ pthread_cond_t pcond;
+ int flags;
+ int rval = 0;
+
+ if (cond == NULL)
+ rval = EINVAL;
+ else {
+ /*
+ * Check if a pointer to a condition variable attribute
+ * structure was passed by the caller:
+ */
+ if (cond_attr != NULL && *cond_attr != NULL) {
+ /* Default to a fast condition variable: */
+ type = (*cond_attr)->c_type;
+ flags = (*cond_attr)->c_flags;
+ } else {
+ /* Default to a fast condition variable: */
+ type = COND_TYPE_FAST;
+ flags = 0;
+ }
+
+ /* Process according to condition variable type: */
+ switch (type) {
+ /* Fast condition variable: */
+ case COND_TYPE_FAST:
+ /* Nothing to do here. */
+ break;
+
+ /* Trap invalid condition variable types: */
+ default:
+ /* Return an invalid argument error: */
+ rval = EINVAL;
+ break;
+ }
+
+ /* Check for no errors: */
+ if (rval == 0) {
+ if ((pcond = (pthread_cond_t)
+ malloc(sizeof(struct pthread_cond))) == NULL) {
+ rval = ENOMEM;
+ } else if (_lock_init(&pcond->c_lock, LCK_ADAPTIVE,
+ _thr_lock_wait, _thr_lock_wakeup) != 0) {
+ free(pcond);
+ rval = ENOMEM;
+ } else {
+ /*
+ * Initialise the condition variable
+ * structure:
+ */
+ TAILQ_INIT(&pcond->c_queue);
+ pcond->c_flags = COND_FLAGS_INITED;
+ pcond->c_type = type;
+ pcond->c_mutex = NULL;
+ pcond->c_seqno = 0;
+ *cond = pcond;
+ }
+ }
+ }
+ /* Return the completion status: */
+ return (rval);
+}
+
+int
+_pthread_cond_destroy(pthread_cond_t *cond)
+{
+ struct pthread_cond *cv;
+ struct pthread *curthread = _get_curthread();
+ int rval = 0;
+
+ if (cond == NULL || *cond == NULL)
+ rval = EINVAL;
+ else {
+ /* Lock the condition variable structure: */
+ THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
+
+ /*
+ * NULL the caller's pointer now that the condition
+ * variable has been destroyed:
+ */
+ cv = *cond;
+ *cond = NULL;
+
+ /* Unlock the condition variable structure: */
+ THR_LOCK_RELEASE(curthread, &cv->c_lock);
+
+ /* Free the cond lock structure: */
+ _lock_destroy(&cv->c_lock);
+
+ /*
+ * Free the memory allocated for the condition
+ * variable structure:
+ */
+ free(cv);
+
+ }
+ /* Return the completion status: */
+ return (rval);
+}
+
+int
+_pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
+{
+ struct pthread *curthread = _get_curthread();
+ int rval = 0;
+ int done = 0;
+ int mutex_locked = 1;
+ int seqno;
+
+ if (cond == NULL)
+ return (EINVAL);
+
+ /*
+ * If the condition variable is statically initialized,
+ * perform the dynamic initialization:
+ */
+ if (*cond == NULL &&
+ (rval = pthread_cond_init(cond, NULL)) != 0)
+ return (rval);
+
+ if (!_kse_isthreaded())
+ _kse_setthreaded(1);
+
+ /*
+ * Enter a loop waiting for a condition signal or broadcast
+ * to wake up this thread. A loop is needed in case the waiting
+ * thread is interrupted by a signal to execute a signal handler.
+ * It is not (currently) possible to remain in the waiting queue
+ * while running a handler. Instead, the thread is interrupted
+ * and backed out of the waiting queue prior to executing the
+ * signal handler.
+ */
+
+ /* Lock the condition variable structure: */
+ THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
+ seqno = (*cond)->c_seqno;
+ do {
+ /*
+ * If the condvar was statically allocated, properly
+ * initialize the tail queue.
+ */
+ if (((*cond)->c_flags & COND_FLAGS_INITED) == 0) {
+ TAILQ_INIT(&(*cond)->c_queue);
+ (*cond)->c_flags |= COND_FLAGS_INITED;
+ }
+
+ /* Process according to condition variable type: */
+ switch ((*cond)->c_type) {
+ /* Fast condition variable: */
+ case COND_TYPE_FAST:
+ if ((mutex == NULL) || (((*cond)->c_mutex != NULL) &&
+ ((*cond)->c_mutex != *mutex))) {
+ /* Return invalid argument error: */
+ rval = EINVAL;
+ } else {
+ /* Reset the timeout and interrupted flags: */
+ curthread->timeout = 0;
+ curthread->interrupted = 0;
+
+ /*
+ * Queue the running thread for the condition
+ * variable:
+ */
+ cond_queue_enq(*cond, curthread);
+
+ /* Wait forever: */
+ curthread->wakeup_time.tv_sec = -1;
+
+ /* Unlock the mutex: */
+ if (mutex_locked &&
+ ((rval = _mutex_cv_unlock(mutex)) != 0)) {
+ /*
+ * Cannot unlock the mutex, so remove
+ * the running thread from the condition
+ * variable queue:
+ */
+ cond_queue_remove(*cond, curthread);
+ }
+ else {
+ /* Remember the mutex: */
+ (*cond)->c_mutex = *mutex;
+
+ /*
+ * Don't unlock the mutex the next
+ * time through the loop (if the
+ * thread has to be requeued after
+ * handling a signal).
+ */
+ mutex_locked = 0;
+
+ /*
+ * This thread is active and is in a
+ * critical region (holding the cv
+ * lock); we should be able to safely
+ * set the state.
+ */
+ THR_SCHED_LOCK(curthread, curthread);
+ THR_SET_STATE(curthread, PS_COND_WAIT);
+
+ /* Remember the CV: */
+ curthread->data.cond = *cond;
+ curthread->sigbackout = cond_wait_backout;
+ THR_SCHED_UNLOCK(curthread, curthread);
+
+ /* Unlock the CV structure: */
+ THR_LOCK_RELEASE(curthread,
+ &(*cond)->c_lock);
+
+ /* Schedule the next thread: */
+ _thr_sched_switch(curthread);
+
+ /*
+ * XXX - This really isn't a good check
+ * since there can be more than one
+ * thread waiting on the CV. Signals
+ * sent to threads waiting on mutexes
+ * or CVs should really be deferred
+ * until the threads are no longer
+ * waiting, but POSIX says that signals
+ * should be sent "as soon as possible".
+ */
+ done = (seqno != (*cond)->c_seqno);
+ if (done && !THR_IN_CONDQ(curthread)) {
+ /*
+ * The thread is dequeued, so
+ * it is safe to clear these.
+ */
+ curthread->data.cond = NULL;
+ curthread->sigbackout = NULL;
+ check_continuation(curthread,
+ NULL, mutex);
+ return (_mutex_cv_lock(mutex));
+ }
+
+ /* Relock the CV structure: */
+ THR_LOCK_ACQUIRE(curthread,
+ &(*cond)->c_lock);
+
+ /*
+ * Clear these after taking the lock to
+ * prevent a race condition where a
+ * signal can arrive before dequeueing
+ * the thread.
+ */
+ curthread->data.cond = NULL;
+ curthread->sigbackout = NULL;
+ done = (seqno != (*cond)->c_seqno);
+
+ if (THR_IN_CONDQ(curthread)) {
+ cond_queue_remove(*cond,
+ curthread);
+
+ /* Check for no more waiters: */
+ if (TAILQ_EMPTY(&(*cond)->c_queue))
+ (*cond)->c_mutex = NULL;
+ }
+ }
+ }
+ break;
+
+ /* Trap invalid condition variable types: */
+ default:
+ /* Return an invalid argument error: */
+ rval = EINVAL;
+ break;
+ }
+
+ check_continuation(curthread, *cond,
+ mutex_locked ? NULL : mutex);
+ } while ((done == 0) && (rval == 0));
+
+ /* Unlock the condition variable structure: */
+ THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
+
+ if (mutex_locked == 0)
+ _mutex_cv_lock(mutex);
+
+ /* Return the completion status: */
+ return (rval);
+}
+
+__strong_reference(_pthread_cond_wait, _thr_cond_wait);
+
+int
+__pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ _thr_cancel_enter(curthread);
+ ret = _pthread_cond_wait(cond, mutex);
+ _thr_cancel_leave(curthread, 1);
+ return (ret);
+}
+
+int
+_pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
+ const struct timespec * abstime)
+{
+ struct pthread *curthread = _get_curthread();
+ int rval = 0;
+ int done = 0;
+ int mutex_locked = 1;
+ int seqno;
+
+ THR_ASSERT(curthread->locklevel == 0,
+ "cv_timedwait: locklevel is not zero!");
+
+ if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 ||
+ abstime->tv_nsec >= 1000000000)
+ return (EINVAL);
+ /*
+ * If the condition variable is statically initialized, perform dynamic
+ * initialization.
+ */
+ if (*cond == NULL && (rval = pthread_cond_init(cond, NULL)) != 0)
+ return (rval);
+
+ if (!_kse_isthreaded())
+ _kse_setthreaded(1);
+
+ /*
+ * Enter a loop waiting for a condition signal or broadcast
+ * to wake up this thread. A loop is needed in case the waiting
+ * thread is interrupted by a signal to execute a signal handler.
+ * It is not (currently) possible to remain in the waiting queue
+ * while running a handler. Instead, the thread is interrupted
+ * and backed out of the waiting queue prior to executing the
+ * signal handler.
+ */
+
+ /* Lock the condition variable structure: */
+ THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
+ seqno = (*cond)->c_seqno;
+ do {
+ /*
+ * If the condvar was statically allocated, properly
+ * initialize the tail queue.
+ */
+ if (((*cond)->c_flags & COND_FLAGS_INITED) == 0) {
+ TAILQ_INIT(&(*cond)->c_queue);
+ (*cond)->c_flags |= COND_FLAGS_INITED;
+ }
+
+ /* Process according to condition variable type: */
+ switch ((*cond)->c_type) {
+ /* Fast condition variable: */
+ case COND_TYPE_FAST:
+ if ((mutex == NULL) || (((*cond)->c_mutex != NULL) &&
+ ((*cond)->c_mutex != *mutex))) {
+ /* Return invalid argument error: */
+ rval = EINVAL;
+ } else {
+ /* Reset the timeout and interrupted flags: */
+ curthread->timeout = 0;
+ curthread->interrupted = 0;
+
+ /*
+ * Queue the running thread for the condition
+ * variable:
+ */
+ cond_queue_enq(*cond, curthread);
+
+ /* Unlock the mutex: */
+ if (mutex_locked &&
+ ((rval = _mutex_cv_unlock(mutex)) != 0)) {
+ /*
+ * Cannot unlock the mutex; remove the
+ * running thread from the condition
+ * variable queue:
+ */
+ cond_queue_remove(*cond, curthread);
+ } else {
+ /* Remember the mutex: */
+ (*cond)->c_mutex = *mutex;
+
+ /*
+ * Don't unlock the mutex the next
+ * time through the loop (if the
+ * thread has to be requeued after
+ * handling a signal).
+ */
+ mutex_locked = 0;
+
+ /*
+ * This thread is active and is in a
+ * critical region (holding the cv
+ * lock); we should be able to safely
+ * set the state.
+ */
+ THR_SCHED_LOCK(curthread, curthread);
+ /* Set the wakeup time: */
+ curthread->wakeup_time.tv_sec =
+ abstime->tv_sec;
+ curthread->wakeup_time.tv_nsec =
+ abstime->tv_nsec;
+ THR_SET_STATE(curthread, PS_COND_WAIT);
+
+ /* Remember the CV: */
+ curthread->data.cond = *cond;
+ curthread->sigbackout = cond_wait_backout;
+ THR_SCHED_UNLOCK(curthread, curthread);
+
+ /* Unlock the CV structure: */
+ THR_LOCK_RELEASE(curthread,
+ &(*cond)->c_lock);
+
+ /* Schedule the next thread: */
+ _thr_sched_switch(curthread);
+
+ /*
+ * XXX - This really isn't a good check
+ * since there can be more than one
+ * thread waiting on the CV. Signals
+ * sent to threads waiting on mutexes
+ * or CVs should really be deferred
+ * until the threads are no longer
+ * waiting, but POSIX says that signals
+ * should be sent "as soon as possible".
+ */
+ done = (seqno != (*cond)->c_seqno);
+ if (done && !THR_IN_CONDQ(curthread)) {
+ /*
+ * The thread is dequeued, so
+ * it is safe to clear these.
+ */
+ curthread->data.cond = NULL;
+ curthread->sigbackout = NULL;
+ check_continuation(curthread,
+ NULL, mutex);
+ return (_mutex_cv_lock(mutex));
+ }
+
+ /* Relock the CV structure: */
+ THR_LOCK_ACQUIRE(curthread,
+ &(*cond)->c_lock);
+
+ /*
+ * Clear these after taking the lock to
+ * prevent a race condition where a
+ * signal can arrive before dequeueing
+ * the thread.
+ */
+ curthread->data.cond = NULL;
+ curthread->sigbackout = NULL;
+
+ done = (seqno != (*cond)->c_seqno);
+
+ if (THR_IN_CONDQ(curthread)) {
+ cond_queue_remove(*cond,
+ curthread);
+
+ /* Check for no more waiters: */
+ if (TAILQ_EMPTY(&(*cond)->c_queue))
+ (*cond)->c_mutex = NULL;
+ }
+
+ if (curthread->timeout != 0) {
+ /* The wait timedout. */
+ rval = ETIMEDOUT;
+ }
+ }
+ }
+ break;
+
+ /* Trap invalid condition variable types: */
+ default:
+ /* Return an invalid argument error: */
+ rval = EINVAL;
+ break;
+ }
+
+ check_continuation(curthread, *cond,
+ mutex_locked ? NULL : mutex);
+ } while ((done == 0) && (rval == 0));
+
+ /* Unlock the condition variable structure: */
+ THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
+
+ if (mutex_locked == 0)
+ _mutex_cv_lock(mutex);
+
+ /* Return the completion status: */
+ return (rval);
+}
+
+int
+__pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
+ const struct timespec *abstime)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ _thr_cancel_enter(curthread);
+ ret = _pthread_cond_timedwait(cond, mutex, abstime);
+ _thr_cancel_leave(curthread, 1);
+ return (ret);
+}
+
+
+int
+_pthread_cond_signal(pthread_cond_t * cond)
+{
+ struct pthread *curthread = _get_curthread();
+ struct pthread *pthread;
+ struct kse_mailbox *kmbx;
+ int rval = 0;
+
+ THR_ASSERT(curthread->locklevel == 0,
+ "cv_timedwait: locklevel is not zero!");
+ if (cond == NULL)
+ rval = EINVAL;
+ /*
+ * If the condition variable is statically initialized, perform dynamic
+ * initialization.
+ */
+ else if (*cond != NULL || (rval = pthread_cond_init(cond, NULL)) == 0) {
+ /* Lock the condition variable structure: */
+ THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
+
+ /* Process according to condition variable type: */
+ switch ((*cond)->c_type) {
+ /* Fast condition variable: */
+ case COND_TYPE_FAST:
+ /* Increment the sequence number: */
+ (*cond)->c_seqno++;
+
+ /*
+ * Wakeups have to be done with the CV lock held;
+ * otherwise there is a race condition where the
+ * thread can timeout, run on another KSE, and enter
+ * another blocking state (including blocking on a CV).
+ */
+ if ((pthread = TAILQ_FIRST(&(*cond)->c_queue))
+ != NULL) {
+ THR_SCHED_LOCK(curthread, pthread);
+ cond_queue_remove(*cond, pthread);
+ pthread->sigbackout = NULL;
+ if ((pthread->kseg == curthread->kseg) &&
+ (pthread->active_priority >
+ curthread->active_priority))
+ curthread->critical_yield = 1;
+ kmbx = _thr_setrunnable_unlocked(pthread);
+ THR_SCHED_UNLOCK(curthread, pthread);
+ if (kmbx != NULL)
+ kse_wakeup(kmbx);
+ }
+ /* Check for no more waiters: */
+ if (TAILQ_EMPTY(&(*cond)->c_queue))
+ (*cond)->c_mutex = NULL;
+ break;
+
+ /* Trap invalid condition variable types: */
+ default:
+ /* Return an invalid argument error: */
+ rval = EINVAL;
+ break;
+ }
+
+ /* Unlock the condition variable structure: */
+ THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
+ }
+
+ /* Return the completion status: */
+ return (rval);
+}
+
+__strong_reference(_pthread_cond_signal, _thr_cond_signal);
+
+int
+_pthread_cond_broadcast(pthread_cond_t * cond)
+{
+ struct pthread *curthread = _get_curthread();
+ struct pthread *pthread;
+ struct kse_mailbox *kmbx;
+ int rval = 0;
+
+ THR_ASSERT(curthread->locklevel == 0,
+ "cv_timedwait: locklevel is not zero!");
+ if (cond == NULL)
+ rval = EINVAL;
+ /*
+ * If the condition variable is statically initialized, perform dynamic
+ * initialization.
+ */
+ else if (*cond != NULL || (rval = pthread_cond_init(cond, NULL)) == 0) {
+ /* Lock the condition variable structure: */
+ THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
+
+ /* Process according to condition variable type: */
+ switch ((*cond)->c_type) {
+ /* Fast condition variable: */
+ case COND_TYPE_FAST:
+ /* Increment the sequence number: */
+ (*cond)->c_seqno++;
+
+ /*
+ * Enter a loop to bring all threads off the
+ * condition queue:
+ */
+ while ((pthread = TAILQ_FIRST(&(*cond)->c_queue))
+ != NULL) {
+ THR_SCHED_LOCK(curthread, pthread);
+ cond_queue_remove(*cond, pthread);
+ pthread->sigbackout = NULL;
+ if ((pthread->kseg == curthread->kseg) &&
+ (pthread->active_priority >
+ curthread->active_priority))
+ curthread->critical_yield = 1;
+ kmbx = _thr_setrunnable_unlocked(pthread);
+ THR_SCHED_UNLOCK(curthread, pthread);
+ if (kmbx != NULL)
+ kse_wakeup(kmbx);
+ }
+
+ /* There are no more waiting threads: */
+ (*cond)->c_mutex = NULL;
+ break;
+
+ /* Trap invalid condition variable types: */
+ default:
+ /* Return an invalid argument error: */
+ rval = EINVAL;
+ break;
+ }
+
+ /* Unlock the condition variable structure: */
+ THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
+ }
+
+ /* Return the completion status: */
+ return (rval);
+}
+
+__strong_reference(_pthread_cond_broadcast, _thr_cond_broadcast);
+
+static inline void
+check_continuation(struct pthread *curthread, struct pthread_cond *cond,
+ pthread_mutex_t *mutex)
+{
+ if ((curthread->interrupted != 0) &&
+ (curthread->continuation != NULL)) {
+ if (cond != NULL)
+ /* Unlock the condition variable structure: */
+ THR_LOCK_RELEASE(curthread, &cond->c_lock);
+ /*
+ * Note that even though this thread may have been
+ * canceled, POSIX requires that the mutex be
+ * reaquired prior to cancellation.
+ */
+ if (mutex != NULL)
+ _mutex_cv_lock(mutex);
+ curthread->continuation((void *) curthread);
+ PANIC("continuation returned in pthread_cond_wait.\n");
+ }
+}
+
+static void
+cond_wait_backout(void *arg)
+{
+ struct pthread *curthread = (struct pthread *)arg;
+ pthread_cond_t cond;
+
+ cond = curthread->data.cond;
+ if (cond != NULL) {
+ /* Lock the condition variable structure: */
+ THR_LOCK_ACQUIRE(curthread, &cond->c_lock);
+
+ /* Process according to condition variable type: */
+ switch (cond->c_type) {
+ /* Fast condition variable: */
+ case COND_TYPE_FAST:
+ cond_queue_remove(cond, curthread);
+
+ /* Check for no more waiters: */
+ if (TAILQ_EMPTY(&cond->c_queue))
+ cond->c_mutex = NULL;
+ break;
+
+ default:
+ break;
+ }
+
+ /* Unlock the condition variable structure: */
+ THR_LOCK_RELEASE(curthread, &cond->c_lock);
+ }
+ /* No need to call this again. */
+ curthread->sigbackout = NULL;
+}
+
+/*
+ * Dequeue a waiting thread from the head of a condition queue in
+ * descending priority order.
+ */
+static inline struct pthread *
+cond_queue_deq(pthread_cond_t cond)
+{
+ struct pthread *pthread;
+
+ while ((pthread = TAILQ_FIRST(&cond->c_queue)) != NULL) {
+ TAILQ_REMOVE(&cond->c_queue, pthread, sqe);
+ THR_CONDQ_CLEAR(pthread);
+ if ((pthread->timeout == 0) && (pthread->interrupted == 0))
+ /*
+ * Only exit the loop when we find a thread
+ * that hasn't timed out or been canceled;
+ * those threads are already running and don't
+ * need their run state changed.
+ */
+ break;
+ }
+
+ return (pthread);
+}
+
+/*
+ * Remove a waiting thread from a condition queue in descending priority
+ * order.
+ */
+static inline void
+cond_queue_remove(pthread_cond_t cond, struct pthread *pthread)
+{
+ /*
+ * Because pthread_cond_timedwait() can timeout as well
+ * as be signaled by another thread, it is necessary to
+ * guard against removing the thread from the queue if
+ * it isn't in the queue.
+ */
+ if (THR_IN_CONDQ(pthread)) {
+ TAILQ_REMOVE(&cond->c_queue, pthread, sqe);
+ THR_CONDQ_CLEAR(pthread);
+ }
+}
+
+/*
+ * Enqueue a waiting thread to a condition queue in descending priority
+ * order.
+ */
+static inline void
+cond_queue_enq(pthread_cond_t cond, struct pthread *pthread)
+{
+ struct pthread *tid = TAILQ_LAST(&cond->c_queue, cond_head);
+
+ THR_ASSERT(!THR_IN_SYNCQ(pthread),
+ "cond_queue_enq: thread already queued!");
+
+ /*
+ * For the common case of all threads having equal priority,
+ * we perform a quick check against the priority of the thread
+ * at the tail of the queue.
+ */
+ if ((tid == NULL) || (pthread->active_priority <= tid->active_priority))
+ TAILQ_INSERT_TAIL(&cond->c_queue, pthread, sqe);
+ else {
+ tid = TAILQ_FIRST(&cond->c_queue);
+ while (pthread->active_priority <= tid->active_priority)
+ tid = TAILQ_NEXT(tid, sqe);
+ TAILQ_INSERT_BEFORE(tid, pthread, sqe);
+ }
+ THR_CONDQ_SET(pthread);
+ pthread->data.cond = cond;
+}
diff --git a/lib/libkse/thread/thr_condattr_destroy.c b/lib/libkse/thread/thr_condattr_destroy.c
new file mode 100644
index 0000000..4e2c337
--- /dev/null
+++ b/lib/libkse/thread/thr_condattr_destroy.c
@@ -0,0 +1,56 @@
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_condattr_destroy);
+LT10_COMPAT_DEFAULT(pthread_condattr_destroy);
+
+__weak_reference(_pthread_condattr_destroy, pthread_condattr_destroy);
+
+int
+_pthread_condattr_destroy(pthread_condattr_t *attr)
+{
+ int ret;
+ if (attr == NULL || *attr == NULL) {
+ ret = EINVAL;
+ } else {
+ free(*attr);
+ *attr = NULL;
+ ret = 0;
+ }
+ return(ret);
+}
diff --git a/lib/libkse/thread/thr_condattr_init.c b/lib/libkse/thread/thr_condattr_init.c
new file mode 100644
index 0000000..e553839
--- /dev/null
+++ b/lib/libkse/thread/thr_condattr_init.c
@@ -0,0 +1,61 @@
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_condattr_init);
+LT10_COMPAT_DEFAULT(pthread_condattr_init);
+
+__weak_reference(_pthread_condattr_init, pthread_condattr_init);
+
+int
+_pthread_condattr_init(pthread_condattr_t *attr)
+{
+ int ret;
+ pthread_condattr_t pattr;
+
+ if ((pattr = (pthread_condattr_t)
+ malloc(sizeof(struct pthread_cond_attr))) == NULL) {
+ ret = ENOMEM;
+ } else {
+ memcpy(pattr, &_pthread_condattr_default,
+ sizeof(struct pthread_cond_attr));
+ *attr = pattr;
+ ret = 0;
+ }
+ return (ret);
+}
diff --git a/lib/libkse/thread/thr_condattr_pshared.c b/lib/libkse/thread/thr_condattr_pshared.c
new file mode 100644
index 0000000..7cef4d9
--- /dev/null
+++ b/lib/libkse/thread/thr_condattr_pshared.c
@@ -0,0 +1,56 @@
+/*
+ * 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 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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, 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$
+ *
+ */
+
+#include <errno.h>
+#include "thr_private.h"
+
+__weak_reference(_pthread_condattr_getpshared, pthread_condattr_getpshared);
+__weak_reference(_pthread_condattr_setpshared, pthread_condattr_setpshared);
+
+int
+_pthread_condattr_getpshared(const pthread_condattr_t *attr,
+ int *pshared)
+{
+ if (attr == NULL || *attr == NULL)
+ return (EINVAL);
+
+ pshared = PTHREAD_PROCESS_PRIVATE;
+ return (0);
+}
+
+int
+_pthread_condattr_setpshared(pthread_condattr_t *attr, int pshared)
+{
+ if (attr == NULL || *attr == NULL)
+ return (EINVAL);
+
+ if (pshared != PTHREAD_PROCESS_PRIVATE)
+ return (EINVAL);
+ return (0);
+}
diff --git a/lib/libkse/thread/thr_connect.c b/lib/libkse/thread/thr_connect.c
new file mode 100644
index 0000000..225d8b9
--- /dev/null
+++ b/lib/libkse/thread/thr_connect.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2003 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 THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 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 <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__connect);
+LT10_COMPAT_DEFAULT(connect);
+
+__weak_reference(__connect, connect);
+
+int
+__connect(int fd, const struct sockaddr *name, socklen_t namelen)
+{
+ struct pthread *curthread;
+ int ret;
+
+ curthread = _get_curthread();
+ _thr_cancel_enter(curthread);
+ ret = __sys_connect(fd, name, namelen);
+ _thr_cancel_leave(curthread, ret == -1);
+
+ return (ret);
+}
diff --git a/lib/libkse/thread/thr_creat.c b/lib/libkse/thread/thr_creat.c
new file mode 100644
index 0000000..7528f0b
--- /dev/null
+++ b/lib/libkse/thread/thr_creat.c
@@ -0,0 +1,58 @@
+/*
+ * 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$
+ */
+
+#include <fcntl.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(___creat);
+LT10_COMPAT_DEFAULT(creat);
+
+extern int __creat(const char *, mode_t);
+
+__weak_reference(___creat, creat);
+
+int
+___creat(const char *path, mode_t mode)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ _thr_cancel_enter(curthread);
+ ret = __creat(path, mode);
+ /*
+ * To avoid possible file handle leak,
+ * only check cancellation point if it is failure
+ */
+ _thr_cancel_leave(curthread, (ret == -1));
+
+ return ret;
+}
diff --git a/lib/libkse/thread/thr_create.c b/lib/libkse/thread/thr_create.c
new file mode 100644
index 0000000..98edb71
--- /dev/null
+++ b/lib/libkse/thread/thr_create.c
@@ -0,0 +1,348 @@
+/*
+ * Copyright (c) 2003 Daniel M. Eischen <deischen@gdeb.com>
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <sys/time.h>
+#include <machine/reg.h>
+#include <pthread.h>
+#include "thr_private.h"
+#include "libc_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_create);
+LT10_COMPAT_DEFAULT(pthread_create);
+
+static void free_thread(struct pthread *curthread, struct pthread *thread);
+static int create_stack(struct pthread_attr *pattr);
+static void free_stack(struct pthread_attr *pattr);
+static void thread_start(struct pthread *curthread,
+ void *(*start_routine) (void *), void *arg);
+
+__weak_reference(_pthread_create, pthread_create);
+
+/*
+ * Some notes on new thread creation and first time initializion
+ * to enable multi-threading.
+ *
+ * There are basically two things that need to be done.
+ *
+ * 1) The internal library variables must be initialized.
+ * 2) Upcalls need to be enabled to allow multiple threads
+ * to be run.
+ *
+ * The first may be done as a result of other pthread functions
+ * being called. When _thr_initial is null, _libpthread_init is
+ * called to initialize the internal variables; this also creates
+ * or sets the initial thread. It'd be nice to automatically
+ * have _libpthread_init called on program execution so we don't
+ * have to have checks throughout the library.
+ *
+ * The second part is only triggered by the creation of the first
+ * thread (other than the initial/main thread). If the thread
+ * being created is a scope system thread, then a new KSE/KSEG
+ * pair needs to be allocated. Also, if upcalls haven't been
+ * enabled on the initial thread's KSE, they must be now that
+ * there is more than one thread; this could be delayed until
+ * the initial KSEG has more than one thread.
+ */
+int
+_pthread_create(pthread_t * thread, const pthread_attr_t * attr,
+ void *(*start_routine) (void *), void *arg)
+{
+ struct pthread *curthread, *new_thread;
+ struct kse *kse = NULL;
+ struct kse_group *kseg = NULL;
+ kse_critical_t crit;
+ int ret = 0;
+
+ if (_thr_initial == NULL)
+ _libpthread_init(NULL);
+
+ /*
+ * Turn on threaded mode, if failed, it is unnecessary to
+ * do further work.
+ */
+ if (_kse_isthreaded() == 0 && _kse_setthreaded(1)) {
+ return (EAGAIN);
+ }
+ curthread = _get_curthread();
+
+ /*
+ * Allocate memory for the thread structure.
+ * Some functions use malloc, so don't put it
+ * in a critical region.
+ */
+ if ((new_thread = _thr_alloc(curthread)) == NULL) {
+ /* Insufficient memory to create a thread: */
+ ret = EAGAIN;
+ } else {
+ /* Check if default thread attributes are required: */
+ if (attr == NULL || *attr == NULL)
+ /* Use the default thread attributes: */
+ new_thread->attr = _pthread_attr_default;
+ else {
+ new_thread->attr = *(*attr);
+ if ((*attr)->sched_inherit == PTHREAD_INHERIT_SCHED) {
+ /* inherit scheduling contention scop */
+ if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
+ new_thread->attr.flags |= PTHREAD_SCOPE_SYSTEM;
+ else
+ new_thread->attr.flags &= ~PTHREAD_SCOPE_SYSTEM;
+ /*
+ * scheduling policy and scheduling parameters will be
+ * inherited in following code.
+ */
+ }
+ }
+ if (_thread_scope_system > 0)
+ new_thread->attr.flags |= PTHREAD_SCOPE_SYSTEM;
+ else if ((_thread_scope_system < 0)
+ && (thread != &_thr_sig_daemon))
+ new_thread->attr.flags &= ~PTHREAD_SCOPE_SYSTEM;
+ if (create_stack(&new_thread->attr) != 0) {
+ /* Insufficient memory to create a stack: */
+ ret = EAGAIN;
+ _thr_free(curthread, new_thread);
+ }
+ else if (((new_thread->attr.flags & PTHREAD_SCOPE_SYSTEM) != 0) &&
+ (((kse = _kse_alloc(curthread, 1)) == NULL)
+ || ((kseg = _kseg_alloc(curthread)) == NULL))) {
+ /* Insufficient memory to create a new KSE/KSEG: */
+ ret = EAGAIN;
+ if (kse != NULL) {
+ kse->k_kcb->kcb_kmbx.km_flags |= KMF_DONE;
+ _kse_free(curthread, kse);
+ }
+ free_stack(&new_thread->attr);
+ _thr_free(curthread, new_thread);
+ }
+ else {
+ if (kseg != NULL) {
+ /* Add the KSE to the KSEG's list of KSEs. */
+ TAILQ_INSERT_HEAD(&kseg->kg_kseq, kse, k_kgqe);
+ kseg->kg_ksecount = 1;
+ kse->k_kseg = kseg;
+ kse->k_schedq = &kseg->kg_schedq;
+ }
+ /*
+ * Write a magic value to the thread structure
+ * to help identify valid ones:
+ */
+ new_thread->magic = THR_MAGIC;
+
+ new_thread->slice_usec = -1;
+ new_thread->start_routine = start_routine;
+ new_thread->arg = arg;
+ new_thread->cancelflags = PTHREAD_CANCEL_ENABLE |
+ PTHREAD_CANCEL_DEFERRED;
+
+ /* No thread is wanting to join to this one: */
+ new_thread->joiner = NULL;
+
+ /*
+ * Initialize the machine context.
+ * Enter a critical region to get consistent context.
+ */
+ crit = _kse_critical_enter();
+ THR_GETCONTEXT(&new_thread->tcb->tcb_tmbx.tm_context);
+ /* Initialize the thread for signals: */
+ new_thread->sigmask = curthread->sigmask;
+ _kse_critical_leave(crit);
+
+ new_thread->tcb->tcb_tmbx.tm_udata = new_thread;
+ new_thread->tcb->tcb_tmbx.tm_context.uc_sigmask =
+ new_thread->sigmask;
+ new_thread->tcb->tcb_tmbx.tm_context.uc_stack.ss_size =
+ new_thread->attr.stacksize_attr;
+ new_thread->tcb->tcb_tmbx.tm_context.uc_stack.ss_sp =
+ new_thread->attr.stackaddr_attr;
+ makecontext(&new_thread->tcb->tcb_tmbx.tm_context,
+ (void (*)(void))thread_start, 3, new_thread,
+ start_routine, arg);
+ /*
+ * Check if this thread is to inherit the scheduling
+ * attributes from its parent:
+ */
+ if (new_thread->attr.sched_inherit == PTHREAD_INHERIT_SCHED) {
+ /*
+ * Copy the scheduling attributes.
+ * Lock the scheduling lock to get consistent
+ * scheduling parameters.
+ */
+ THR_SCHED_LOCK(curthread, curthread);
+ new_thread->base_priority =
+ curthread->base_priority &
+ ~THR_SIGNAL_PRIORITY;
+ new_thread->attr.prio =
+ curthread->base_priority &
+ ~THR_SIGNAL_PRIORITY;
+ new_thread->attr.sched_policy =
+ curthread->attr.sched_policy;
+ THR_SCHED_UNLOCK(curthread, curthread);
+ } else {
+ /*
+ * Use just the thread priority, leaving the
+ * other scheduling attributes as their
+ * default values:
+ */
+ new_thread->base_priority =
+ new_thread->attr.prio;
+ }
+ new_thread->active_priority = new_thread->base_priority;
+ new_thread->inherited_priority = 0;
+
+ /* Initialize the mutex queue: */
+ TAILQ_INIT(&new_thread->mutexq);
+
+ /* Initialise hooks in the thread structure: */
+ new_thread->specific = NULL;
+ new_thread->specific_data_count = 0;
+ new_thread->cleanup = NULL;
+ new_thread->flags = 0;
+ new_thread->tlflags = 0;
+ new_thread->sigbackout = NULL;
+ new_thread->continuation = NULL;
+ new_thread->wakeup_time.tv_sec = -1;
+ new_thread->lock_switch = 0;
+ sigemptyset(&new_thread->sigpend);
+ new_thread->check_pending = 0;
+ new_thread->locklevel = 0;
+ new_thread->rdlock_count = 0;
+ new_thread->sigstk.ss_sp = 0;
+ new_thread->sigstk.ss_size = 0;
+ new_thread->sigstk.ss_flags = SS_DISABLE;
+ new_thread->oldsigmask = NULL;
+
+ if (new_thread->attr.suspend == THR_CREATE_SUSPENDED) {
+ new_thread->state = PS_SUSPENDED;
+ new_thread->flags = THR_FLAGS_SUSPENDED;
+ }
+ else
+ new_thread->state = PS_RUNNING;
+
+ /*
+ * System scope threads have their own kse and
+ * kseg. Process scope threads are all hung
+ * off the main process kseg.
+ */
+ if ((new_thread->attr.flags & PTHREAD_SCOPE_SYSTEM) == 0) {
+ new_thread->kseg = _kse_initial->k_kseg;
+ new_thread->kse = _kse_initial;
+ }
+ else {
+ kse->k_curthread = NULL;
+ kse->k_kseg->kg_flags |= KGF_SINGLE_THREAD;
+ new_thread->kse = kse;
+ new_thread->kseg = kse->k_kseg;
+ kse->k_kcb->kcb_kmbx.km_udata = kse;
+ kse->k_kcb->kcb_kmbx.km_curthread = NULL;
+ }
+
+ /*
+ * Schedule the new thread starting a new KSEG/KSE
+ * pair if necessary.
+ */
+ ret = _thr_schedule_add(curthread, new_thread);
+ if (ret != 0)
+ free_thread(curthread, new_thread);
+ else {
+ /* Return a pointer to the thread structure: */
+ (*thread) = new_thread;
+ }
+ }
+ }
+
+ /* Return the status: */
+ return (ret);
+}
+
+static void
+free_thread(struct pthread *curthread, struct pthread *thread)
+{
+ free_stack(&thread->attr);
+ if ((thread->attr.flags & PTHREAD_SCOPE_SYSTEM) != 0) {
+ /* Free the KSE and KSEG. */
+ _kseg_free(thread->kseg);
+ _kse_free(curthread, thread->kse);
+ }
+ _thr_free(curthread, thread);
+}
+
+static int
+create_stack(struct pthread_attr *pattr)
+{
+ int ret;
+
+ /* Check if a stack was specified in the thread attributes: */
+ if ((pattr->stackaddr_attr) != NULL) {
+ pattr->guardsize_attr = 0;
+ pattr->flags |= THR_STACK_USER;
+ ret = 0;
+ }
+ else
+ ret = _thr_stack_alloc(pattr);
+ return (ret);
+}
+
+static void
+free_stack(struct pthread_attr *pattr)
+{
+ struct kse *curkse;
+ kse_critical_t crit;
+
+ if ((pattr->flags & THR_STACK_USER) == 0) {
+ crit = _kse_critical_enter();
+ curkse = _get_curkse();
+ KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock);
+ /* Stack routines don't use malloc/free. */
+ _thr_stack_free(pattr);
+ KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
+ _kse_critical_leave(crit);
+ }
+}
+
+static void
+thread_start(struct pthread *curthread, void *(*start_routine) (void *),
+ void *arg)
+{
+ /* Run the current thread's start routine with argument: */
+ pthread_exit(start_routine(arg));
+
+ /* This point should never be reached. */
+ PANIC("Thread has resumed after exit");
+}
diff --git a/lib/libkse/thread/thr_detach.c b/lib/libkse/thread/thr_detach.c
new file mode 100644
index 0000000..2ae95df
--- /dev/null
+++ b/lib/libkse/thread/thr_detach.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <machine/atomic.h>
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_detach);
+LT10_COMPAT_DEFAULT(pthread_detach);
+
+__weak_reference(_pthread_detach, pthread_detach);
+
+int
+_pthread_detach(pthread_t pthread)
+{
+ struct pthread *curthread = _get_curthread();
+ struct kse_mailbox *kmbx = NULL;
+ struct pthread *joiner;
+ int rval = 0;
+
+ /* Check for invalid calling parameters: */
+ if (pthread == NULL || pthread->magic != THR_MAGIC)
+ /* Return an invalid argument error: */
+ rval = EINVAL;
+
+ else if ((rval = _thr_ref_add(curthread, pthread,
+ /*include dead*/1)) != 0) {
+ /* Return an error: */
+ }
+
+ /* Check if the thread is already detached: */
+ else if ((pthread->attr.flags & PTHREAD_DETACHED) != 0) {
+ /* Return an error: */
+ _thr_ref_delete(curthread, pthread);
+ rval = EINVAL;
+ } else {
+ /* Lock the detached thread: */
+ THR_SCHED_LOCK(curthread, pthread);
+
+ /* Flag the thread as detached: */
+ pthread->attr.flags |= PTHREAD_DETACHED;
+
+ /* Retrieve any joining thread and remove it: */
+ joiner = pthread->joiner;
+ if ((joiner != NULL) && (joiner->kseg == pthread->kseg)) {
+ /*
+ * We already own the scheduler lock for the joiner.
+ * Take advantage of that and make the joiner runnable.
+ */
+ if (joiner->join_status.thread == pthread) {
+ /*
+ * Set the return value for the woken thread:
+ */
+ joiner->join_status.error = ESRCH;
+ joiner->join_status.ret = NULL;
+ joiner->join_status.thread = NULL;
+
+ kmbx = _thr_setrunnable_unlocked(joiner);
+ }
+ joiner = NULL;
+ }
+ THR_SCHED_UNLOCK(curthread, pthread);
+ /* See if there is a thread waiting in pthread_join(): */
+ if ((joiner != NULL) &&
+ (_thr_ref_add(curthread, joiner, 0) == 0)) {
+ /* Lock the joiner before fiddling with it. */
+ THR_SCHED_LOCK(curthread, joiner);
+ if (joiner->join_status.thread == pthread) {
+ /*
+ * Set the return value for the woken thread:
+ */
+ joiner->join_status.error = ESRCH;
+ joiner->join_status.ret = NULL;
+ joiner->join_status.thread = NULL;
+
+ kmbx = _thr_setrunnable_unlocked(joiner);
+ }
+ THR_SCHED_UNLOCK(curthread, joiner);
+ _thr_ref_delete(curthread, joiner);
+ }
+ _thr_ref_delete(curthread, pthread);
+ if (kmbx != NULL)
+ kse_wakeup(kmbx);
+ }
+
+ /* Return the completion status: */
+ return (rval);
+}
diff --git a/lib/libkse/thread/thr_equal.c b/lib/libkse/thread/thr_equal.c
new file mode 100644
index 0000000..95a3b65
--- /dev/null
+++ b/lib/libkse/thread/thr_equal.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_equal);
+LT10_COMPAT_DEFAULT(pthread_equal);
+
+__weak_reference(_pthread_equal, pthread_equal);
+
+int
+_pthread_equal(pthread_t t1, pthread_t t2)
+{
+ /* Compare the two thread pointers: */
+ return (t1 == t2);
+}
diff --git a/lib/libkse/thread/thr_execve.c b/lib/libkse/thread/thr_execve.c
new file mode 100644
index 0000000..b902981
--- /dev/null
+++ b/lib/libkse/thread/thr_execve.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2004 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(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 <errno.h>
+#include <pthread.h>
+#include <unistd.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_execve);
+LT10_COMPAT_DEFAULT(execve);
+
+__weak_reference(_execve, execve);
+
+int
+_execve(const char *name, char *const *argv, char *const *envp)
+{
+ struct kse_execve_args args;
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
+ ret = __sys_execve(name, argv, envp);
+ else {
+ /*
+ * When exec'ing, set the kernel signal mask to the thread's
+ * signal mask to satisfy POSIX requirements.
+ */
+ args.sigmask = curthread->sigmask;
+ args.sigpend = curthread->sigpend;
+ args.path = (char *)name;
+ args.argv = (char **)argv;
+ args.envp = (char **)envp;
+ args.reserved = NULL;
+ ret = kse_thr_interrupt(NULL, KSE_INTR_EXECVE, (long)&args);
+ }
+
+ return (ret);
+}
diff --git a/lib/libkse/thread/thr_exit.c b/lib/libkse/thread/thr_exit.c
new file mode 100644
index 0000000..1b2f84e
--- /dev/null
+++ b/lib/libkse/thread/thr_exit.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_exit);
+LT10_COMPAT_DEFAULT(pthread_exit);
+
+void _pthread_exit(void *status);
+
+__weak_reference(_pthread_exit, pthread_exit);
+
+void
+_thr_exit(char *fname, int lineno, char *msg)
+{
+
+ /* Write an error message to the standard error file descriptor: */
+ _thread_printf(2,
+ "Fatal error '%s' at line %d in file %s (errno = %d)\n",
+ msg, lineno, fname, errno);
+
+ abort();
+}
+
+/*
+ * Only called when a thread is cancelled. It may be more useful
+ * to call it from pthread_exit() if other ways of asynchronous or
+ * abnormal thread termination can be found.
+ */
+void
+_thr_exit_cleanup(void)
+{
+ struct pthread *curthread = _get_curthread();
+
+ /*
+ * POSIX states that cancellation/termination of a thread should
+ * not release any visible resources (such as mutexes) and that
+ * it is the applications responsibility. Resources that are
+ * internal to the threads library, including file and fd locks,
+ * are not visible to the application and need to be released.
+ */
+ /* Unlock all private mutexes: */
+ _mutex_unlock_private(curthread);
+
+ /*
+ * This still isn't quite correct because we don't account
+ * for held spinlocks (see libc/stdlib/malloc.c).
+ */
+}
+
+void
+_pthread_exit(void *status)
+{
+ struct pthread *curthread = _get_curthread();
+ kse_critical_t crit;
+ struct kse *curkse;
+
+ /* Check if this thread is already in the process of exiting: */
+ if ((curthread->flags & THR_FLAGS_EXITING) != 0) {
+ char msg[128];
+ snprintf(msg, sizeof(msg), "Thread %p has called "
+ "pthread_exit() from a destructor. POSIX 1003.1 "
+ "1996 s16.2.5.2 does not allow this!", curthread);
+ PANIC(msg);
+ }
+
+ /*
+ * Flag this thread as exiting. Threads should now be prevented
+ * from joining to this thread.
+ */
+ THR_SCHED_LOCK(curthread, curthread);
+ curthread->flags |= THR_FLAGS_EXITING;
+ THR_SCHED_UNLOCK(curthread, curthread);
+
+ /*
+ * To avoid signal-lost problem, if signals had already been
+ * delivered to us, handle it. we have already set EXITING flag
+ * so no new signals should be delivered to us.
+ * XXX this is not enough if signal was delivered just before
+ * thread called sigprocmask and masked it! in this case, we
+ * might have to re-post the signal by kill() if the signal
+ * is targeting process (not for a specified thread).
+ * Kernel has same signal-lost problem, a signal may be delivered
+ * to a thread which is on the way to call sigprocmask or thr_exit()!
+ */
+ if (curthread->check_pending)
+ _thr_sig_check_pending(curthread);
+ /* Save the return value: */
+ curthread->ret = status;
+ while (curthread->cleanup != NULL) {
+ pthread_cleanup_pop(1);
+ }
+ if (curthread->attr.cleanup_attr != NULL) {
+ curthread->attr.cleanup_attr(curthread->attr.arg_attr);
+ }
+ /* Check if there is thread specific data: */
+ if (curthread->specific != NULL) {
+ /* Run the thread-specific data destructors: */
+ _thread_cleanupspecific();
+ }
+ if (!_kse_isthreaded())
+ exit(0);
+ crit = _kse_critical_enter();
+ curkse = _get_curkse();
+ KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock);
+ /* Use thread_list_lock */
+ _thread_active_threads--;
+ if ((_thread_scope_system <= 0 && _thread_active_threads == 1) ||
+ (_thread_scope_system > 0 && _thread_active_threads == 0)) {
+ KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
+ _kse_critical_leave(crit);
+ exit(0);
+ /* Never reach! */
+ }
+ KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
+
+ /* This thread will never be re-scheduled. */
+ KSE_LOCK(curkse);
+ THR_SET_STATE(curthread, PS_DEAD);
+ _thr_sched_switch_unlocked(curthread);
+ /* Never reach! */
+
+ /* This point should not be reached. */
+ PANIC("Dead thread has resumed");
+}
diff --git a/lib/libkse/thread/thr_fcntl.c b/lib/libkse/thread/thr_fcntl.c
new file mode 100644
index 0000000..d59dfd7
--- /dev/null
+++ b/lib/libkse/thread/thr_fcntl.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <stdarg.h>
+#include "namespace.h"
+#include <fcntl.h>
+#include "un-namespace.h"
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__fcntl);
+LT10_COMPAT_DEFAULT(fcntl);
+
+__weak_reference(__fcntl, fcntl);
+
+int
+__fcntl(int fd, int cmd,...)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret, check = 1;
+ va_list ap;
+
+ _thr_cancel_enter(curthread);
+
+ va_start(ap, cmd);
+ switch (cmd) {
+ case F_DUPFD:
+ ret = __sys_fcntl(fd, cmd, va_arg(ap, int));
+ /*
+ * To avoid possible file handle leak,
+ * only check cancellation point if it is failure
+ */
+ check = (ret == -1);
+ break;
+ case F_SETFD:
+ case F_SETFL:
+ ret = __sys_fcntl(fd, cmd, va_arg(ap, int));
+ break;
+ case F_GETFD:
+ case F_GETFL:
+ ret = __sys_fcntl(fd, cmd);
+ break;
+ default:
+ ret = __sys_fcntl(fd, cmd, va_arg(ap, void *));
+ }
+ va_end(ap);
+
+ _thr_cancel_leave(curthread, check);
+
+ return (ret);
+}
diff --git a/lib/libkse/thread/thr_find_thread.c b/lib/libkse/thread/thr_find_thread.c
new file mode 100644
index 0000000..5a64640
--- /dev/null
+++ b/lib/libkse/thread/thr_find_thread.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2003 Daniel Eischen <deischen@freebsd.org>
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+/*
+ * Find a thread in the linked list of active threads and add a reference
+ * to it. Threads with positive reference counts will not be deallocated
+ * until all references are released.
+ */
+int
+_thr_ref_add(struct pthread *curthread, struct pthread *thread,
+ int include_dead)
+{
+ kse_critical_t crit;
+ struct pthread *pthread;
+ struct kse *curkse;
+
+ if (thread == NULL)
+ /* Invalid thread: */
+ return (EINVAL);
+
+ crit = _kse_critical_enter();
+ curkse = _get_curkse();
+ KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock);
+ pthread = _thr_hash_find(thread);
+ if (pthread) {
+ if ((include_dead == 0) &&
+ ((pthread->state == PS_DEAD) ||
+ ((pthread->state == PS_DEADLOCK) ||
+ ((pthread->flags & THR_FLAGS_EXITING) != 0))))
+ pthread = NULL;
+ else {
+ pthread->refcount++;
+ if (curthread != NULL)
+ curthread->critical_count++;
+ }
+ }
+ KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
+ _kse_critical_leave(crit);
+
+ /* Return zero if the thread exists: */
+ return ((pthread != NULL) ? 0 : ESRCH);
+}
+
+void
+_thr_ref_delete(struct pthread *curthread, struct pthread *thread)
+{
+ kse_critical_t crit;
+ struct kse *curkse;
+
+ if (thread != NULL) {
+ crit = _kse_critical_enter();
+ curkse = _get_curkse();
+ KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock);
+ thread->refcount--;
+ if (curthread != NULL)
+ curthread->critical_count--;
+ if ((thread->refcount == 0) &&
+ (thread->tlflags & TLFLAGS_GC_SAFE) != 0)
+ THR_GCLIST_ADD(thread);
+ KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
+ _kse_critical_leave(crit);
+ }
+}
diff --git a/lib/libkse/thread/thr_fork.c b/lib/libkse/thread/thr_fork.c
new file mode 100644
index 0000000..4dfa487
--- /dev/null
+++ b/lib/libkse/thread/thr_fork.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <spinlock.h>
+#include <sys/signalvar.h>
+
+#include "libc_private.h"
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_fork);
+LT10_COMPAT_DEFAULT(fork);
+
+__weak_reference(_fork, fork);
+
+pid_t
+_fork(void)
+{
+ sigset_t sigset, oldset;
+ struct pthread *curthread;
+ struct pthread_atfork *af;
+ pid_t ret;
+ int errsave;
+
+ curthread = _get_curthread();
+
+ if (!_kse_isthreaded()) {
+ SIGFILLSET(sigset);
+ __sys_sigprocmask(SIG_SETMASK, &sigset, &oldset);
+ ret = __sys_fork();
+ if (ret == 0)
+ /* Child */
+ __sys_sigprocmask(SIG_SETMASK, &curthread->sigmask,
+ NULL);
+ else
+ __sys_sigprocmask(SIG_SETMASK, &oldset, NULL);
+ return (ret);
+ }
+
+ /*
+ * Masks all signals until we reach a safe point in
+ * _kse_single_thread, and the signal masks will be
+ * restored in that function, for M:N thread, all
+ * signals were already masked in kernel atomically,
+ * we only need to do this for bound thread.
+ */
+ if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) {
+ SIGFILLSET(sigset);
+ __sys_sigprocmask(SIG_SETMASK, &sigset, &oldset);
+ }
+
+ _pthread_mutex_lock(&_thr_atfork_mutex);
+
+ /* Run down atfork prepare handlers. */
+ TAILQ_FOREACH_REVERSE(af, &_thr_atfork_list, atfork_head, qe) {
+ if (af->prepare != NULL)
+ af->prepare();
+ }
+
+ /* Fork a new process: */
+ if (_kse_isthreaded() != 0) {
+ _malloc_prefork();
+ }
+ if ((ret = __sys_fork()) == 0) {
+ /* Child process */
+ errsave = errno;
+
+ /* Kernel signal mask is restored in _kse_single_thread */
+ _kse_single_thread(curthread);
+
+ /* Run down atfork child handlers. */
+ TAILQ_FOREACH(af, &_thr_atfork_list, qe) {
+ if (af->child != NULL)
+ af->child();
+ }
+ _thr_mutex_reinit(&_thr_atfork_mutex);
+ } else {
+ if (_kse_isthreaded() != 0) {
+ _malloc_postfork();
+ }
+ errsave = errno;
+ if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) {
+ __sys_sigprocmask(SIG_SETMASK, &oldset, NULL);
+ }
+ /* Run down atfork parent handlers. */
+ TAILQ_FOREACH(af, &_thr_atfork_list, qe) {
+ if (af->parent != NULL)
+ af->parent();
+ }
+ _pthread_mutex_unlock(&_thr_atfork_mutex);
+ }
+ errno = errsave;
+
+ /* Return the process ID: */
+ return (ret);
+}
diff --git a/lib/libkse/thread/thr_fsync.c b/lib/libkse/thread/thr_fsync.c
new file mode 100644
index 0000000..fc6360a
--- /dev/null
+++ b/lib/libkse/thread/thr_fsync.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <unistd.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__fsync);
+LT10_COMPAT_DEFAULT(fsync);
+
+__weak_reference(__fsync, fsync);
+
+int
+__fsync(int fd)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ _thr_cancel_enter(curthread);
+ ret = __sys_fsync(fd);
+ _thr_cancel_leave(curthread, 1);
+
+ return (ret);
+}
diff --git a/lib/libkse/thread/thr_getprio.c b/lib/libkse/thread/thr_getprio.c
new file mode 100644
index 0000000..875c1b3
--- /dev/null
+++ b/lib/libkse/thread/thr_getprio.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <errno.h>
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_getprio);
+LT10_COMPAT_DEFAULT(pthread_getprio);
+
+__weak_reference(_pthread_getprio, pthread_getprio);
+
+int
+_pthread_getprio(pthread_t pthread)
+{
+ int policy, ret;
+ struct sched_param param;
+
+ if ((ret = _pthread_getschedparam(pthread, &policy, &param)) == 0)
+ ret = param.sched_priority;
+ else {
+ /* Invalid thread: */
+ errno = ret;
+ ret = -1;
+ }
+
+ /* Return the thread priority or an error status: */
+ return (ret);
+}
diff --git a/lib/libkse/thread/thr_getschedparam.c b/lib/libkse/thread/thr_getschedparam.c
new file mode 100644
index 0000000..dca342f
--- /dev/null
+++ b/lib/libkse/thread/thr_getschedparam.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_getschedparam);
+LT10_COMPAT_DEFAULT(pthread_getschedparam);
+
+__weak_reference(_pthread_getschedparam, pthread_getschedparam);
+
+int
+_pthread_getschedparam(pthread_t pthread, int *policy,
+ struct sched_param *param)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret, tmp;
+
+ if ((param == NULL) || (policy == NULL))
+ /* Return an invalid argument error: */
+ ret = EINVAL;
+ else if (pthread == curthread) {
+ /*
+ * Avoid searching the thread list when it is the current
+ * thread.
+ */
+ THR_SCHED_LOCK(curthread, curthread);
+ param->sched_priority =
+ THR_BASE_PRIORITY(pthread->base_priority);
+ tmp = pthread->attr.sched_policy;
+ THR_SCHED_UNLOCK(curthread, curthread);
+ *policy = tmp;
+ ret = 0;
+ }
+ /* Find the thread in the list of active threads. */
+ else if ((ret = _thr_ref_add(curthread, pthread, /*include dead*/0))
+ == 0) {
+ THR_SCHED_LOCK(curthread, pthread);
+ param->sched_priority =
+ THR_BASE_PRIORITY(pthread->base_priority);
+ tmp = pthread->attr.sched_policy;
+ THR_SCHED_UNLOCK(curthread, pthread);
+ _thr_ref_delete(curthread, pthread);
+ *policy = tmp;
+ }
+ return (ret);
+}
diff --git a/lib/libkse/thread/thr_info.c b/lib/libkse/thread/thr_info.c
new file mode 100644
index 0000000..ab5320f
--- /dev/null
+++ b/lib/libkse/thread/thr_info.c
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <errno.h>
+#include "thr_private.h"
+
+#ifndef NELEMENTS
+#define NELEMENTS(arr) (sizeof(arr) / sizeof(arr[0]))
+#endif
+
+LT10_COMPAT_PRIVATE(_pthread_set_name_np);
+LT10_COMPAT_DEFAULT(pthread_set_name_np);
+
+static void dump_thread(int fd, pthread_t pthread, int long_version);
+
+__weak_reference(_pthread_set_name_np, pthread_set_name_np);
+
+struct s_thread_info {
+ enum pthread_state state;
+ char *name;
+};
+
+/* Static variables: */
+static const struct s_thread_info thread_info[] = {
+ {PS_RUNNING , "Running"},
+ {PS_LOCKWAIT , "Waiting on an internal lock"},
+ {PS_MUTEX_WAIT , "Waiting on a mutex"},
+ {PS_COND_WAIT , "Waiting on a condition variable"},
+ {PS_SLEEP_WAIT , "Sleeping"},
+ {PS_SIGSUSPEND , "Suspended, waiting for a signal"},
+ {PS_SIGWAIT , "Waiting for a signal"},
+ {PS_JOIN , "Waiting to join"},
+ {PS_SUSPENDED , "Suspended"},
+ {PS_DEAD , "Dead"},
+ {PS_DEADLOCK , "Deadlocked"},
+ {PS_STATE_MAX , "Not a real state!"}
+};
+
+void
+_thread_dump_info(void)
+{
+ char s[512], tmpfile[128];
+ pthread_t pthread;
+ int fd, i;
+
+ for (i = 0; i < 100000; i++) {
+ snprintf(tmpfile, sizeof(tmpfile), "/tmp/pthread.dump.%u.%i",
+ getpid(), i);
+ /* Open the dump file for append and create it if necessary: */
+ if ((fd = __sys_open(tmpfile, O_RDWR | O_CREAT | O_EXCL,
+ 0666)) < 0) {
+ /* Can't open the dump file. */
+ if (errno == EEXIST)
+ continue;
+ /*
+ * We only need to continue in case of
+ * EEXIT error. Most other error
+ * codes means that we will fail all
+ * the times.
+ */
+ return;
+ } else {
+ break;
+ }
+ }
+ if (i==100000) {
+ /* all 100000 possibilities are in use :( */
+ return;
+ } else {
+ /* Dump the active threads. */
+ strcpy(s, "\n\n========\nACTIVE THREADS\n\n");
+ __sys_write(fd, s, strlen(s));
+
+ /* Enter a loop to report each thread in the global list: */
+ TAILQ_FOREACH(pthread, &_thread_list, tle) {
+ if (pthread->state != PS_DEAD)
+ dump_thread(fd, pthread, /*long_verson*/ 1);
+ }
+
+ /*
+ * Dump the ready threads.
+ * XXX - We can't easily do this because the run queues
+ * are per-KSEG.
+ */
+ strcpy(s, "\n\n========\nREADY THREADS - unimplemented\n\n");
+ __sys_write(fd, s, strlen(s));
+
+
+ /*
+ * Dump the waiting threads.
+ * XXX - We can't easily do this because the wait queues
+ * are per-KSEG.
+ */
+ strcpy(s, "\n\n========\nWAITING THREADS - unimplemented\n\n");
+ __sys_write(fd, s, strlen(s));
+
+ /* Close the dump file. */
+ __sys_close(fd);
+ }
+}
+
+static void
+dump_thread(int fd, pthread_t pthread, int long_version)
+{
+ struct pthread *curthread = _get_curthread();
+ char s[512];
+ int i;
+
+ /* Find the state: */
+ for (i = 0; i < NELEMENTS(thread_info) - 1; i++)
+ if (thread_info[i].state == pthread->state)
+ break;
+
+ /* Output a record for the thread: */
+ snprintf(s, sizeof(s),
+ "--------------------\n"
+ "Thread %p (%s), scope %s, prio %3d, blocked %s, state %s [%s:%d]\n",
+ pthread, (pthread->name == NULL) ? "" : pthread->name,
+ pthread->attr.flags & PTHREAD_SCOPE_SYSTEM ? "system" : "process",
+ pthread->active_priority, (pthread->blocked != 0) ? "yes" : "no",
+ thread_info[i].name, pthread->fname, pthread->lineno);
+ __sys_write(fd, s, strlen(s));
+
+ if (long_version != 0) {
+ /* Check if this is the running thread: */
+ if (pthread == curthread) {
+ /* Output a record for the running thread: */
+ strcpy(s, "This is the running thread\n");
+ __sys_write(fd, s, strlen(s));
+ }
+ /* Check if this is the initial thread: */
+ if (pthread == _thr_initial) {
+ /* Output a record for the initial thread: */
+ strcpy(s, "This is the initial thread\n");
+ __sys_write(fd, s, strlen(s));
+ }
+
+ /* Process according to thread state: */
+ switch (pthread->state) {
+ case PS_SIGWAIT:
+ snprintf(s, sizeof(s), "sigmask (hi) ");
+ __sys_write(fd, s, strlen(s));
+ for (i = _SIG_WORDS - 1; i >= 0; i--) {
+ snprintf(s, sizeof(s), "%08x ",
+ pthread->sigmask.__bits[i]);
+ __sys_write(fd, s, strlen(s));
+ }
+ snprintf(s, sizeof(s), "(lo)\n");
+ __sys_write(fd, s, strlen(s));
+
+ snprintf(s, sizeof(s), "waitset (hi) ");
+ __sys_write(fd, s, strlen(s));
+ for (i = _SIG_WORDS - 1; i >= 0; i--) {
+ snprintf(s, sizeof(s), "%08x ",
+ pthread->data.sigwait->waitset->__bits[i]);
+ __sys_write(fd, s, strlen(s));
+ }
+ snprintf(s, sizeof(s), "(lo)\n");
+ __sys_write(fd, s, strlen(s));
+ break;
+ /*
+ * Trap other states that are not explicitly
+ * coded to dump information:
+ */
+ default:
+ snprintf(s, sizeof(s), "sigmask (hi) ");
+ __sys_write(fd, s, strlen(s));
+ for (i = _SIG_WORDS - 1; i >= 0; i--) {
+ snprintf(s, sizeof(s), "%08x ",
+ pthread->sigmask.__bits[i]);
+ __sys_write(fd, s, strlen(s));
+ }
+ snprintf(s, sizeof(s), "(lo)\n");
+ __sys_write(fd, s, strlen(s));
+ break;
+ }
+ }
+}
+
+/* Set the thread name for debug: */
+void
+_pthread_set_name_np(pthread_t thread, char *name)
+{
+ /* Check if the caller has specified a valid thread: */
+ if (thread != NULL && thread->magic == THR_MAGIC) {
+ if (thread->name != NULL) {
+ /* Free space for previous name. */
+ free(thread->name);
+ }
+ thread->name = strdup(name);
+ }
+}
diff --git a/lib/libkse/thread/thr_init.c b/lib/libkse/thread/thr_init.c
new file mode 100644
index 0000000..35c4ee3
--- /dev/null
+++ b/lib/libkse/thread/thr_init.c
@@ -0,0 +1,533 @@
+/*
+ * Copyright (c) 2003 Daniel M. Eischen <deischen@freebsd.org>
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/* Allocate space for global thread variables here: */
+#define GLOBAL_PTHREAD_PRIVATE
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/signalvar.h>
+#include <machine/reg.h>
+
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <sys/event.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+#include <sys/ttycom.h>
+#include <sys/wait.h>
+#include <sys/mman.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <pthread.h>
+#include <pthread_np.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 "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_libkse_debug);
+LT10_COMPAT_PRIVATE(_thread_activated);
+LT10_COMPAT_PRIVATE(_thread_active_threads);
+LT10_COMPAT_PRIVATE(_thread_list);
+
+int __pthread_cond_wait(pthread_cond_t *, pthread_mutex_t *);
+int __pthread_mutex_lock(pthread_mutex_t *);
+int __pthread_mutex_trylock(pthread_mutex_t *);
+void _thread_init_hack(void);
+extern int _thread_state_running;
+
+static void init_private(void);
+static void init_main_thread(struct pthread *thread);
+
+/*
+ * All weak references used within libc should be in this table.
+ * This is so that static libraries will work.
+ */
+static void *references[] = {
+ &_accept,
+ &_bind,
+ &_close,
+ &_connect,
+ &_dup,
+ &_dup2,
+ &_execve,
+ &_fcntl,
+ &_flock,
+ &_flockfile,
+ &_fstat,
+ &_fstatfs,
+ &_fsync,
+ &_funlockfile,
+ &_getdirentries,
+ &_getlogin,
+ &_getpeername,
+ &_getsockname,
+ &_getsockopt,
+ &_ioctl,
+ &_kevent,
+ &_listen,
+ &_nanosleep,
+ &_open,
+ &_pthread_getspecific,
+ &_pthread_key_create,
+ &_pthread_key_delete,
+ &_pthread_mutex_destroy,
+ &_pthread_mutex_init,
+ &_pthread_mutex_lock,
+ &_pthread_mutex_trylock,
+ &_pthread_mutex_unlock,
+ &_pthread_mutexattr_init,
+ &_pthread_mutexattr_destroy,
+ &_pthread_mutexattr_settype,
+ &_pthread_once,
+ &_pthread_setspecific,
+ &_read,
+ &_readv,
+ &_recvfrom,
+ &_recvmsg,
+ &_select,
+ &_sendmsg,
+ &_sendto,
+ &_setsockopt,
+ &_sigaction,
+ &_sigprocmask,
+ &_sigsuspend,
+ &_socket,
+ &_socketpair,
+ &_thread_init_hack,
+ &_wait4,
+ &_write,
+ &_writev
+};
+
+/*
+ * These are needed when linking statically. All references within
+ * libgcc (and in the future libc) to these routines are weak, but
+ * if they are not (strongly) referenced by the application or other
+ * libraries, then the actual functions will not be loaded.
+ */
+static void *libgcc_references[] = {
+ &_pthread_once,
+ &_pthread_key_create,
+ &_pthread_key_delete,
+ &_pthread_getspecific,
+ &_pthread_setspecific,
+ &_pthread_mutex_init,
+ &_pthread_mutex_destroy,
+ &_pthread_mutex_lock,
+ &_pthread_mutex_trylock,
+ &_pthread_mutex_unlock
+};
+
+#define DUAL_ENTRY(entry) \
+ (pthread_func_t)entry, (pthread_func_t)entry
+
+static pthread_func_t jmp_table[][2] = {
+ {DUAL_ENTRY(_pthread_atfork)}, /* PJT_ATFORK */
+ {DUAL_ENTRY(_pthread_attr_destroy)}, /* PJT_ATTR_DESTROY */
+ {DUAL_ENTRY(_pthread_attr_getdetachstate)}, /* PJT_ATTR_GETDETACHSTATE */
+ {DUAL_ENTRY(_pthread_attr_getguardsize)}, /* PJT_ATTR_GETGUARDSIZE */
+ {DUAL_ENTRY(_pthread_attr_getinheritsched)}, /* PJT_ATTR_GETINHERITSCHED */
+ {DUAL_ENTRY(_pthread_attr_getschedparam)}, /* PJT_ATTR_GETSCHEDPARAM */
+ {DUAL_ENTRY(_pthread_attr_getschedpolicy)}, /* PJT_ATTR_GETSCHEDPOLICY */
+ {DUAL_ENTRY(_pthread_attr_getscope)}, /* PJT_ATTR_GETSCOPE */
+ {DUAL_ENTRY(_pthread_attr_getstackaddr)}, /* PJT_ATTR_GETSTACKADDR */
+ {DUAL_ENTRY(_pthread_attr_getstacksize)}, /* PJT_ATTR_GETSTACKSIZE */
+ {DUAL_ENTRY(_pthread_attr_init)}, /* PJT_ATTR_INIT */
+ {DUAL_ENTRY(_pthread_attr_setdetachstate)}, /* PJT_ATTR_SETDETACHSTATE */
+ {DUAL_ENTRY(_pthread_attr_setguardsize)}, /* PJT_ATTR_SETGUARDSIZE */
+ {DUAL_ENTRY(_pthread_attr_setinheritsched)}, /* PJT_ATTR_SETINHERITSCHED */
+ {DUAL_ENTRY(_pthread_attr_setschedparam)}, /* PJT_ATTR_SETSCHEDPARAM */
+ {DUAL_ENTRY(_pthread_attr_setschedpolicy)}, /* PJT_ATTR_SETSCHEDPOLICY */
+ {DUAL_ENTRY(_pthread_attr_setscope)}, /* PJT_ATTR_SETSCOPE */
+ {DUAL_ENTRY(_pthread_attr_setstackaddr)}, /* PJT_ATTR_SETSTACKADDR */
+ {DUAL_ENTRY(_pthread_attr_setstacksize)}, /* PJT_ATTR_SETSTACKSIZE */
+ {DUAL_ENTRY(_pthread_cancel)}, /* PJT_CANCEL */
+ {DUAL_ENTRY(_pthread_cleanup_pop)}, /* PJT_CLEANUP_POP */
+ {DUAL_ENTRY(_pthread_cleanup_push)}, /* PJT_CLEANUP_PUSH */
+ {DUAL_ENTRY(_pthread_cond_broadcast)}, /* PJT_COND_BROADCAST */
+ {DUAL_ENTRY(_pthread_cond_destroy)}, /* PJT_COND_DESTROY */
+ {DUAL_ENTRY(_pthread_cond_init)}, /* PJT_COND_INIT */
+ {DUAL_ENTRY(_pthread_cond_signal)}, /* PJT_COND_SIGNAL */
+ {DUAL_ENTRY(_pthread_cond_timedwait)}, /* PJT_COND_TIMEDWAIT */
+ {(pthread_func_t)__pthread_cond_wait,
+ (pthread_func_t)_pthread_cond_wait}, /* PJT_COND_WAIT */
+ {DUAL_ENTRY(_pthread_detach)}, /* PJT_DETACH */
+ {DUAL_ENTRY(_pthread_equal)}, /* PJT_EQUAL */
+ {DUAL_ENTRY(_pthread_exit)}, /* PJT_EXIT */
+ {DUAL_ENTRY(_pthread_getspecific)}, /* PJT_GETSPECIFIC */
+ {DUAL_ENTRY(_pthread_join)}, /* PJT_JOIN */
+ {DUAL_ENTRY(_pthread_key_create)}, /* PJT_KEY_CREATE */
+ {DUAL_ENTRY(_pthread_key_delete)}, /* PJT_KEY_DELETE*/
+ {DUAL_ENTRY(_pthread_kill)}, /* PJT_KILL */
+ {DUAL_ENTRY(_pthread_main_np)}, /* PJT_MAIN_NP */
+ {DUAL_ENTRY(_pthread_mutexattr_destroy)}, /* PJT_MUTEXATTR_DESTROY */
+ {DUAL_ENTRY(_pthread_mutexattr_init)}, /* PJT_MUTEXATTR_INIT */
+ {DUAL_ENTRY(_pthread_mutexattr_settype)}, /* PJT_MUTEXATTR_SETTYPE */
+ {DUAL_ENTRY(_pthread_mutex_destroy)}, /* PJT_MUTEX_DESTROY */
+ {DUAL_ENTRY(_pthread_mutex_init)}, /* PJT_MUTEX_INIT */
+ {(pthread_func_t)__pthread_mutex_lock,
+ (pthread_func_t)_pthread_mutex_lock}, /* PJT_MUTEX_LOCK */
+ {(pthread_func_t)__pthread_mutex_trylock,
+ (pthread_func_t)_pthread_mutex_trylock},/* PJT_MUTEX_TRYLOCK */
+ {DUAL_ENTRY(_pthread_mutex_unlock)}, /* PJT_MUTEX_UNLOCK */
+ {DUAL_ENTRY(_pthread_once)}, /* PJT_ONCE */
+ {DUAL_ENTRY(_pthread_rwlock_destroy)}, /* PJT_RWLOCK_DESTROY */
+ {DUAL_ENTRY(_pthread_rwlock_init)}, /* PJT_RWLOCK_INIT */
+ {DUAL_ENTRY(_pthread_rwlock_rdlock)}, /* PJT_RWLOCK_RDLOCK */
+ {DUAL_ENTRY(_pthread_rwlock_tryrdlock)},/* PJT_RWLOCK_TRYRDLOCK */
+ {DUAL_ENTRY(_pthread_rwlock_trywrlock)},/* PJT_RWLOCK_TRYWRLOCK */
+ {DUAL_ENTRY(_pthread_rwlock_unlock)}, /* PJT_RWLOCK_UNLOCK */
+ {DUAL_ENTRY(_pthread_rwlock_wrlock)}, /* PJT_RWLOCK_WRLOCK */
+ {DUAL_ENTRY(_pthread_self)}, /* PJT_SELF */
+ {DUAL_ENTRY(_pthread_setcancelstate)}, /* PJT_SETCANCELSTATE */
+ {DUAL_ENTRY(_pthread_setcanceltype)}, /* PJT_SETCANCELTYPE */
+ {DUAL_ENTRY(_pthread_setspecific)}, /* PJT_SETSPECIFIC */
+ {DUAL_ENTRY(_pthread_sigmask)}, /* PJT_SIGMASK */
+ {DUAL_ENTRY(_pthread_testcancel)} /* PJT_TESTCANCEL */
+};
+
+static int init_once = 0;
+
+/*
+ * Threaded process initialization.
+ *
+ * This is only called under two conditions:
+ *
+ * 1) Some thread routines have detected that the library hasn't yet
+ * been initialized (_thr_initial == NULL && curthread == NULL), or
+ *
+ * 2) An explicit call to reinitialize after a fork (indicated
+ * by curthread != NULL)
+ */
+void
+_libpthread_init(struct pthread *curthread)
+{
+ int fd;
+
+ /* Check if this function has already been called: */
+ if ((_thr_initial != NULL) && (curthread == NULL))
+ /* Only initialize the threaded application once. */
+ return;
+
+ /*
+ * Make gcc quiescent about {,libgcc_}references not being
+ * referenced:
+ */
+ if ((references[0] == NULL) || (libgcc_references[0] == NULL))
+ PANIC("Failed loading mandatory references in _thread_init");
+
+ /* Pull debug symbols in for static binary */
+ _thread_state_running = PS_RUNNING;
+
+ /*
+ * Check the size of the jump table to make sure it is preset
+ * with the correct number of entries.
+ */
+ if (sizeof(jmp_table) != (sizeof(pthread_func_t) * PJT_MAX * 2))
+ PANIC("Thread jump table not properly initialized");
+ memcpy(__thr_jtable, jmp_table, sizeof(jmp_table));
+
+ /*
+ * Check for the special case of this process running as
+ * or in place of init as pid = 1:
+ */
+ if ((_thr_pid = getpid()) == 1) {
+ /*
+ * Setup a new session for this process which is
+ * assumed to be running as root.
+ */
+ if (setsid() == -1)
+ PANIC("Can't set session ID");
+ if (revoke(_PATH_CONSOLE) != 0)
+ PANIC("Can't revoke console");
+ if ((fd = __sys_open(_PATH_CONSOLE, O_RDWR)) < 0)
+ PANIC("Can't open console");
+ if (setlogin("root") == -1)
+ PANIC("Can't set login to root");
+ if (__sys_ioctl(fd, TIOCSCTTY, (char *) NULL) == -1)
+ PANIC("Can't set controlling terminal");
+ }
+
+ /* Initialize pthread private data. */
+ init_private();
+ _kse_init();
+
+ /* Initialize the initial kse and kseg. */
+ _kse_initial = _kse_alloc(NULL, _thread_scope_system > 0);
+ if (_kse_initial == NULL)
+ PANIC("Can't allocate initial kse.");
+ _kse_initial->k_kseg = _kseg_alloc(NULL);
+ if (_kse_initial->k_kseg == NULL)
+ PANIC("Can't allocate initial kseg.");
+ _kse_initial->k_kseg->kg_flags |= KGF_SINGLE_THREAD;
+ _kse_initial->k_schedq = &_kse_initial->k_kseg->kg_schedq;
+
+ TAILQ_INSERT_TAIL(&_kse_initial->k_kseg->kg_kseq, _kse_initial, k_kgqe);
+ _kse_initial->k_kseg->kg_ksecount = 1;
+
+ /* Set the initial thread. */
+ if (curthread == NULL) {
+ /* Create and initialize the initial thread. */
+ curthread = _thr_alloc(NULL);
+ if (curthread == NULL)
+ PANIC("Can't allocate initial thread");
+ _thr_initial = curthread;
+ init_main_thread(curthread);
+ } else {
+ /*
+ * The initial thread is the current thread. It is
+ * assumed that the current thread is already initialized
+ * because it is left over from a fork().
+ */
+ _thr_initial = curthread;
+ }
+ _kse_initial->k_kseg->kg_threadcount = 0;
+ _thr_initial->kse = _kse_initial;
+ _thr_initial->kseg = _kse_initial->k_kseg;
+ _thr_initial->active = 1;
+
+ /*
+ * Add the thread to the thread list and to the KSEG's thread
+ * queue.
+ */
+ THR_LIST_ADD(_thr_initial);
+ KSEG_THRQ_ADD(_kse_initial->k_kseg, _thr_initial);
+
+ /* Setup the KSE/thread specific data for the current KSE/thread. */
+ _thr_initial->kse->k_curthread = _thr_initial;
+ _kcb_set(_thr_initial->kse->k_kcb);
+ _tcb_set(_thr_initial->kse->k_kcb, _thr_initial->tcb);
+ _thr_initial->kse->k_flags |= KF_INITIALIZED;
+
+ _thr_signal_init();
+ _kse_critical_leave(&_thr_initial->tcb->tcb_tmbx);
+ /*
+ * activate threaded mode as soon as possible if we are
+ * being debugged
+ */
+ if (_libkse_debug)
+ _kse_setthreaded(1);
+}
+
+/*
+ * This function and pthread_create() do a lot of the same things.
+ * It'd be nice to consolidate the common stuff in one place.
+ */
+static void
+init_main_thread(struct pthread *thread)
+{
+ /* Setup the thread attributes. */
+ thread->attr = _pthread_attr_default;
+ thread->attr.flags |= PTHREAD_SCOPE_SYSTEM;
+ /*
+ * Set up the thread stack.
+ *
+ * Create a red zone below the main stack. All other stacks
+ * are constrained to a maximum size by the parameters
+ * passed to mmap(), but this stack is only limited by
+ * resource limits, so this stack needs an explicitly mapped
+ * red zone to protect the thread stack that is just beyond.
+ */
+ if (mmap((void *)_usrstack - _thr_stack_initial -
+ _thr_guard_default, _thr_guard_default, 0, MAP_ANON,
+ -1, 0) == MAP_FAILED)
+ PANIC("Cannot allocate red zone for initial thread");
+
+ /*
+ * Mark the stack as an application supplied stack so that it
+ * isn't deallocated.
+ *
+ * XXX - I'm not sure it would hurt anything to deallocate
+ * the main thread stack because deallocation doesn't
+ * actually free() it; it just puts it in the free
+ * stack queue for later reuse.
+ */
+ thread->attr.stackaddr_attr = (void *)_usrstack - _thr_stack_initial;
+ thread->attr.stacksize_attr = _thr_stack_initial;
+ thread->attr.guardsize_attr = _thr_guard_default;
+ thread->attr.flags |= THR_STACK_USER;
+
+ /*
+ * Write a magic value to the thread structure
+ * to help identify valid ones:
+ */
+ thread->magic = THR_MAGIC;
+
+ thread->slice_usec = -1;
+ thread->cancelflags = PTHREAD_CANCEL_ENABLE | PTHREAD_CANCEL_DEFERRED;
+ thread->name = strdup("initial thread");
+
+ /* Initialize the thread for signals: */
+ SIGEMPTYSET(thread->sigmask);
+
+ /*
+ * Set up the thread mailbox. The threads saved context
+ * is also in the mailbox.
+ */
+ thread->tcb->tcb_tmbx.tm_udata = thread;
+ thread->tcb->tcb_tmbx.tm_context.uc_stack.ss_size =
+ thread->attr.stacksize_attr;
+ thread->tcb->tcb_tmbx.tm_context.uc_stack.ss_sp =
+ thread->attr.stackaddr_attr;
+
+ /* Default the priority of the initial thread: */
+ thread->base_priority = THR_DEFAULT_PRIORITY;
+ thread->active_priority = THR_DEFAULT_PRIORITY;
+ thread->inherited_priority = 0;
+
+ /* Initialize the mutex queue: */
+ TAILQ_INIT(&thread->mutexq);
+
+ /* Initialize hooks in the thread structure: */
+ thread->specific = NULL;
+ thread->cleanup = NULL;
+ thread->flags = 0;
+ thread->sigbackout = NULL;
+ thread->continuation = NULL;
+
+ thread->state = PS_RUNNING;
+ thread->uniqueid = 0;
+}
+
+static void
+init_private(void)
+{
+ struct clockinfo clockinfo;
+ size_t len;
+ int mib[2];
+
+ /*
+ * Avoid reinitializing some things if they don't need to be,
+ * e.g. after a fork().
+ */
+ if (init_once == 0) {
+ /* Find the stack top */
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_USRSTACK;
+ len = sizeof (_usrstack);
+ if (sysctl(mib, 2, &_usrstack, &len, NULL, 0) == -1)
+ PANIC("Cannot get kern.usrstack from sysctl");
+ /* Get the kernel clockrate: */
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_CLOCKRATE;
+ len = sizeof (struct clockinfo);
+ if (sysctl(mib, 2, &clockinfo, &len, NULL, 0) == 0)
+ _clock_res_usec = 1000000 / clockinfo.stathz;
+ else
+ _clock_res_usec = CLOCK_RES_USEC;
+
+ _thr_page_size = getpagesize();
+ _thr_guard_default = _thr_page_size;
+ if (sizeof(void *) == 8) {
+ _thr_stack_default = THR_STACK64_DEFAULT;
+ _thr_stack_initial = THR_STACK64_INITIAL;
+ }
+ else {
+ _thr_stack_default = THR_STACK32_DEFAULT;
+ _thr_stack_initial = THR_STACK32_INITIAL;
+ }
+ _pthread_attr_default.guardsize_attr = _thr_guard_default;
+ _pthread_attr_default.stacksize_attr = _thr_stack_default;
+ TAILQ_INIT(&_thr_atfork_list);
+ init_once = 1; /* Don't do this again. */
+ } else {
+ /*
+ * Destroy the locks before creating them. We don't
+ * know what state they are in so it is better to just
+ * recreate them.
+ */
+ _lock_destroy(&_thread_signal_lock);
+ _lock_destroy(&_mutex_static_lock);
+ _lock_destroy(&_rwlock_static_lock);
+ _lock_destroy(&_keytable_lock);
+ }
+
+ /* Initialize everything else. */
+ TAILQ_INIT(&_thread_list);
+ TAILQ_INIT(&_thread_gc_list);
+ _pthread_mutex_init(&_thr_atfork_mutex, NULL);
+
+ /*
+ * Initialize the lock for temporary installation of signal
+ * handlers (to support sigwait() semantics) and for the
+ * process signal mask and pending signal sets.
+ */
+ if (_lock_init(&_thread_signal_lock, LCK_ADAPTIVE,
+ _kse_lock_wait, _kse_lock_wakeup) != 0)
+ PANIC("Cannot initialize _thread_signal_lock");
+ if (_lock_init(&_mutex_static_lock, LCK_ADAPTIVE,
+ _thr_lock_wait, _thr_lock_wakeup) != 0)
+ PANIC("Cannot initialize mutex static init lock");
+ if (_lock_init(&_rwlock_static_lock, LCK_ADAPTIVE,
+ _thr_lock_wait, _thr_lock_wakeup) != 0)
+ PANIC("Cannot initialize rwlock static init lock");
+ if (_lock_init(&_keytable_lock, LCK_ADAPTIVE,
+ _thr_lock_wait, _thr_lock_wakeup) != 0)
+ PANIC("Cannot initialize thread specific keytable lock");
+ _thr_spinlock_init();
+
+ /* Clear pending signals and get the process signal mask. */
+ SIGEMPTYSET(_thr_proc_sigpending);
+
+ /* Are we in M:N mode (default) or 1:1 mode? */
+#ifdef SYSTEM_SCOPE_ONLY
+ _thread_scope_system = 1;
+#else
+ if (getenv("LIBPTHREAD_SYSTEM_SCOPE") != NULL)
+ _thread_scope_system = 1;
+ else if (getenv("LIBPTHREAD_PROCESS_SCOPE") != NULL)
+ _thread_scope_system = -1;
+#endif
+ if (getenv("LIBPTHREAD_DEBUG") != NULL)
+ _thr_debug_flags |= DBG_INFO_DUMP;
+
+ /*
+ * _thread_list_lock and _kse_count are initialized
+ * by _kse_init()
+ */
+}
diff --git a/lib/libkse/thread/thr_join.c b/lib/libkse/thread/thr_join.c
new file mode 100644
index 0000000..1a3452e
--- /dev/null
+++ b/lib/libkse/thread/thr_join.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_join);
+LT10_COMPAT_DEFAULT(pthread_join);
+
+__weak_reference(_pthread_join, pthread_join);
+
+int
+_pthread_join(pthread_t pthread, void **thread_return)
+{
+ struct pthread *curthread = _get_curthread();
+ void *tmp;
+ kse_critical_t crit;
+ int ret = 0;
+
+ _thr_cancel_enter(curthread);
+
+ /* Check if the caller has specified an invalid thread: */
+ if (pthread == NULL || pthread->magic != THR_MAGIC) {
+ /* Invalid thread: */
+ _thr_cancel_leave(curthread, 1);
+ return (EINVAL);
+ }
+
+ /* Check if the caller has specified itself: */
+ if (pthread == curthread) {
+ /* Avoid a deadlock condition: */
+ _thr_cancel_leave(curthread, 1);
+ return (EDEADLK);
+ }
+
+ /*
+ * Find the thread in the list of active threads or in the
+ * list of dead threads:
+ */
+ if ((ret = _thr_ref_add(curthread, pthread, /*include dead*/1)) != 0) {
+ /* Return an error: */
+ _thr_cancel_leave(curthread, 1);
+ return (ESRCH);
+ }
+
+ THR_SCHED_LOCK(curthread, pthread);
+ /* Check if this thread has been detached: */
+ if ((pthread->attr.flags & PTHREAD_DETACHED) != 0) {
+ THR_SCHED_UNLOCK(curthread, pthread);
+ /* Remove the reference and return an error: */
+ _thr_ref_delete(curthread, pthread);
+ ret = ESRCH;
+ } else {
+ /* Lock the target thread while checking its state. */
+ if (pthread->state == PS_DEAD) {
+ /* Return the thread's return value: */
+ tmp = pthread->ret;
+
+ /* Detach the thread. */
+ pthread->attr.flags |= PTHREAD_DETACHED;
+
+ /* Unlock the thread. */
+ THR_SCHED_UNLOCK(curthread, pthread);
+
+ /*
+ * Remove the thread from the list of active
+ * threads and add it to the GC list.
+ */
+ crit = _kse_critical_enter();
+ KSE_LOCK_ACQUIRE(curthread->kse, &_thread_list_lock);
+ THR_LIST_REMOVE(pthread);
+ THR_GCLIST_ADD(pthread);
+ KSE_LOCK_RELEASE(curthread->kse, &_thread_list_lock);
+ _kse_critical_leave(crit);
+
+ /* Remove the reference. */
+ _thr_ref_delete(curthread, pthread);
+ if (thread_return != NULL)
+ *thread_return = tmp;
+ }
+ else if (pthread->joiner != NULL) {
+ /* Unlock the thread and remove the reference. */
+ THR_SCHED_UNLOCK(curthread, pthread);
+ _thr_ref_delete(curthread, pthread);
+
+ /* Multiple joiners are not supported. */
+ ret = ENOTSUP;
+ }
+ else {
+ /* Set the running thread to be the joiner: */
+ pthread->joiner = curthread;
+
+ /* Keep track of which thread we're joining to: */
+ curthread->join_status.thread = pthread;
+
+ /* Unlock the thread and remove the reference. */
+ THR_SCHED_UNLOCK(curthread, pthread);
+ _thr_ref_delete(curthread, pthread);
+
+ THR_SCHED_LOCK(curthread, curthread);
+ while (curthread->join_status.thread == pthread) {
+ THR_SET_STATE(curthread, PS_JOIN);
+ THR_SCHED_UNLOCK(curthread, curthread);
+ /* Schedule the next thread: */
+ _thr_sched_switch(curthread);
+ THR_SCHED_LOCK(curthread, curthread);
+ }
+ THR_SCHED_UNLOCK(curthread, curthread);
+
+ if ((curthread->cancelflags & THR_CANCELLING) &&
+ !(curthread->cancelflags & PTHREAD_CANCEL_DISABLE)) {
+ if (_thr_ref_add(curthread, pthread, 1) == 0) {
+ THR_SCHED_LOCK(curthread, pthread);
+ pthread->joiner = NULL;
+ THR_SCHED_UNLOCK(curthread, pthread);
+ _thr_ref_delete(curthread, pthread);
+ }
+ pthread_exit(PTHREAD_CANCELED);
+ }
+
+ /*
+ * The thread return value and error are set by the
+ * thread we're joining to when it exits or detaches:
+ */
+ ret = curthread->join_status.error;
+ if ((ret == 0) && (thread_return != NULL))
+ *thread_return = curthread->join_status.ret;
+ }
+ }
+ _thr_cancel_leave(curthread, 1);
+
+ /* Return the completion status: */
+ return (ret);
+}
diff --git a/lib/libkse/thread/thr_kern.c b/lib/libkse/thread/thr_kern.c
new file mode 100644
index 0000000..f1b28c0
--- /dev/null
+++ b/lib/libkse/thread/thr_kern.c
@@ -0,0 +1,2551 @@
+/*
+ * Copyright (C) 2003 Daniel M. Eischen <deischen@freebsd.org>
+ * Copyright (C) 2002 Jonathon Mini <mini@freebsd.org>
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 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/kse.h>
+#include <sys/ptrace.h>
+#include <sys/signalvar.h>
+#include <sys/queue.h>
+#include <machine/atomic.h>
+#include <machine/sigframe.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <ucontext.h>
+#include <unistd.h>
+
+#include "atomic_ops.h"
+#include "thr_private.h"
+#include "libc_private.h"
+#ifdef NOTYET
+#include "spinlock.h"
+#endif
+
+/* #define DEBUG_THREAD_KERN */
+#ifdef DEBUG_THREAD_KERN
+#define DBG_MSG stdout_debug
+#else
+#define DBG_MSG(x...)
+#endif
+
+/*
+ * Define a high water mark for the maximum number of threads that
+ * will be cached. Once this level is reached, any extra threads
+ * will be free()'d.
+ */
+#define MAX_CACHED_THREADS 100
+/*
+ * Define high water marks for the maximum number of KSEs and KSE groups
+ * that will be cached. Because we support 1:1 threading, there could have
+ * same number of KSEs and KSE groups as threads. Once these levels are
+ * reached, any extra KSE and KSE groups will be free()'d.
+ */
+#define MAX_CACHED_KSES ((_thread_scope_system <= 0) ? 50 : 100)
+#define MAX_CACHED_KSEGS ((_thread_scope_system <= 0) ? 50 : 100)
+
+#define KSE_SET_MBOX(kse, thrd) \
+ (kse)->k_kcb->kcb_kmbx.km_curthread = &(thrd)->tcb->tcb_tmbx
+
+#define KSE_SET_EXITED(kse) (kse)->k_flags |= KF_EXITED
+
+/*
+ * Macros for manipulating the run queues. The priority queue
+ * routines use the thread's pqe link and also handle the setting
+ * and clearing of the thread's THR_FLAGS_IN_RUNQ flag.
+ */
+#define KSE_RUNQ_INSERT_HEAD(kse, thrd) \
+ _pq_insert_head(&(kse)->k_schedq->sq_runq, thrd)
+#define KSE_RUNQ_INSERT_TAIL(kse, thrd) \
+ _pq_insert_tail(&(kse)->k_schedq->sq_runq, thrd)
+#define KSE_RUNQ_REMOVE(kse, thrd) \
+ _pq_remove(&(kse)->k_schedq->sq_runq, thrd)
+#define KSE_RUNQ_FIRST(kse) \
+ ((_libkse_debug == 0) ? \
+ _pq_first(&(kse)->k_schedq->sq_runq) : \
+ _pq_first_debug(&(kse)->k_schedq->sq_runq))
+
+#define KSE_RUNQ_THREADS(kse) ((kse)->k_schedq->sq_runq.pq_threads)
+
+#define THR_NEED_CANCEL(thrd) \
+ (((thrd)->cancelflags & THR_CANCELLING) != 0 && \
+ ((thrd)->cancelflags & PTHREAD_CANCEL_DISABLE) == 0 && \
+ (((thrd)->cancelflags & THR_AT_CANCEL_POINT) != 0 || \
+ ((thrd)->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0))
+
+#define THR_NEED_ASYNC_CANCEL(thrd) \
+ (((thrd)->cancelflags & THR_CANCELLING) != 0 && \
+ ((thrd)->cancelflags & PTHREAD_CANCEL_DISABLE) == 0 && \
+ (((thrd)->cancelflags & THR_AT_CANCEL_POINT) == 0 && \
+ ((thrd)->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0))
+
+/*
+ * We've got to keep track of everything that is allocated, not only
+ * to have a speedy free list, but also so they can be deallocated
+ * after a fork().
+ */
+static TAILQ_HEAD(, kse) active_kseq;
+static TAILQ_HEAD(, kse) free_kseq;
+static TAILQ_HEAD(, kse_group) free_kse_groupq;
+static TAILQ_HEAD(, kse_group) active_kse_groupq;
+static TAILQ_HEAD(, kse_group) gc_ksegq;
+static struct lock kse_lock; /* also used for kseg queue */
+static int free_kse_count = 0;
+static int free_kseg_count = 0;
+static TAILQ_HEAD(, pthread) free_threadq;
+static struct lock thread_lock;
+static int free_thread_count = 0;
+static int inited = 0;
+static int active_kse_count = 0;
+static int active_kseg_count = 0;
+static u_int64_t next_uniqueid = 1;
+
+LIST_HEAD(thread_hash_head, pthread);
+#define THREAD_HASH_QUEUES 127
+static struct thread_hash_head thr_hashtable[THREAD_HASH_QUEUES];
+#define THREAD_HASH(thrd) ((unsigned long)thrd % THREAD_HASH_QUEUES)
+
+/* Lock for thread tcb constructor/destructor */
+static pthread_mutex_t _tcb_mutex;
+
+#ifdef DEBUG_THREAD_KERN
+static void dump_queues(struct kse *curkse);
+#endif
+static void kse_check_completed(struct kse *kse);
+static void kse_check_waitq(struct kse *kse);
+static void kse_fini(struct kse *curkse);
+static void kse_reinit(struct kse *kse, int sys_scope);
+static void kse_sched_multi(struct kse_mailbox *kmbx);
+static void kse_sched_single(struct kse_mailbox *kmbx);
+static void kse_switchout_thread(struct kse *kse, struct pthread *thread);
+static void kse_wait(struct kse *kse, struct pthread *td_wait, int sigseq);
+static void kse_free_unlocked(struct kse *kse);
+static void kse_destroy(struct kse *kse);
+static void kseg_free_unlocked(struct kse_group *kseg);
+static void kseg_init(struct kse_group *kseg);
+static void kseg_reinit(struct kse_group *kseg);
+static void kseg_destroy(struct kse_group *kseg);
+static void kse_waitq_insert(struct pthread *thread);
+static void kse_wakeup_multi(struct kse *curkse);
+static struct kse_mailbox *kse_wakeup_one(struct pthread *thread);
+static void thr_cleanup(struct kse *kse, struct pthread *curthread);
+static void thr_link(struct pthread *thread);
+static void thr_resume_wrapper(int sig, siginfo_t *, ucontext_t *);
+static void thr_resume_check(struct pthread *curthread, ucontext_t *ucp);
+static int thr_timedout(struct pthread *thread, struct timespec *curtime);
+static void thr_unlink(struct pthread *thread);
+static void thr_destroy(struct pthread *curthread, struct pthread *thread);
+static void thread_gc(struct pthread *thread);
+static void kse_gc(struct pthread *thread);
+static void kseg_gc(struct pthread *thread);
+
+static void __inline
+thr_accounting(struct pthread *thread)
+{
+ if ((thread->slice_usec != -1) &&
+ (thread->slice_usec <= TIMESLICE_USEC) &&
+ (thread->attr.sched_policy != SCHED_FIFO)) {
+ thread->slice_usec += (thread->tcb->tcb_tmbx.tm_uticks
+ + thread->tcb->tcb_tmbx.tm_sticks) * _clock_res_usec;
+ /* Check for time quantum exceeded: */
+ if (thread->slice_usec > TIMESLICE_USEC)
+ thread->slice_usec = -1;
+ }
+ thread->tcb->tcb_tmbx.tm_uticks = 0;
+ thread->tcb->tcb_tmbx.tm_sticks = 0;
+}
+
+/*
+ * This is called after a fork().
+ * No locks need to be taken here since we are guaranteed to be
+ * single threaded.
+ *
+ * XXX
+ * POSIX says for threaded process, fork() function is used
+ * only to run new programs, and the effects of calling functions
+ * that require certain resources between the call to fork() and
+ * the call to an exec function are undefined.
+ *
+ * It is not safe to free memory after fork(), because these data
+ * structures may be in inconsistent state.
+ */
+void
+_kse_single_thread(struct pthread *curthread)
+{
+#ifdef NOTYET
+ struct kse *kse;
+ struct kse_group *kseg;
+ struct pthread *thread;
+
+ _thr_spinlock_init();
+ *__malloc_lock = (spinlock_t)_SPINLOCK_INITIALIZER;
+ if (__isthreaded) {
+ _thr_rtld_fini();
+ _thr_signal_deinit();
+ }
+ __isthreaded = 0;
+ /*
+ * Restore signal mask early, so any memory problems could
+ * dump core.
+ */
+ __sys_sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL);
+ _thread_active_threads = 1;
+
+ /*
+ * Enter a loop to remove and free all threads other than
+ * the running thread from the active thread list:
+ */
+ while ((thread = TAILQ_FIRST(&_thread_list)) != NULL) {
+ THR_GCLIST_REMOVE(thread);
+ /*
+ * Remove this thread from the list (the current
+ * thread will be removed but re-added by libpthread
+ * initialization.
+ */
+ TAILQ_REMOVE(&_thread_list, thread, tle);
+ /* Make sure this isn't the running thread: */
+ if (thread != curthread) {
+ _thr_stack_free(&thread->attr);
+ if (thread->specific != NULL)
+ free(thread->specific);
+ thr_destroy(curthread, thread);
+ }
+ }
+
+ TAILQ_INIT(&curthread->mutexq); /* initialize mutex queue */
+ curthread->joiner = NULL; /* no joining threads yet */
+ curthread->refcount = 0;
+ SIGEMPTYSET(curthread->sigpend); /* clear pending signals */
+
+ /* Don't free thread-specific data as the caller may require it */
+
+ /* Free the free KSEs: */
+ while ((kse = TAILQ_FIRST(&free_kseq)) != NULL) {
+ TAILQ_REMOVE(&free_kseq, kse, k_qe);
+ kse_destroy(kse);
+ }
+ free_kse_count = 0;
+
+ /* Free the active KSEs: */
+ while ((kse = TAILQ_FIRST(&active_kseq)) != NULL) {
+ TAILQ_REMOVE(&active_kseq, kse, k_qe);
+ kse_destroy(kse);
+ }
+ active_kse_count = 0;
+
+ /* Free the free KSEGs: */
+ while ((kseg = TAILQ_FIRST(&free_kse_groupq)) != NULL) {
+ TAILQ_REMOVE(&free_kse_groupq, kseg, kg_qe);
+ kseg_destroy(kseg);
+ }
+ free_kseg_count = 0;
+
+ /* Free the active KSEGs: */
+ while ((kseg = TAILQ_FIRST(&active_kse_groupq)) != NULL) {
+ TAILQ_REMOVE(&active_kse_groupq, kseg, kg_qe);
+ kseg_destroy(kseg);
+ }
+ active_kseg_count = 0;
+
+ /* Free the free threads. */
+ while ((thread = TAILQ_FIRST(&free_threadq)) != NULL) {
+ TAILQ_REMOVE(&free_threadq, thread, tle);
+ thr_destroy(curthread, thread);
+ }
+ free_thread_count = 0;
+
+ /* Free the to-be-gc'd threads. */
+ while ((thread = TAILQ_FIRST(&_thread_gc_list)) != NULL) {
+ TAILQ_REMOVE(&_thread_gc_list, thread, gcle);
+ thr_destroy(curthread, thread);
+ }
+ TAILQ_INIT(&gc_ksegq);
+ _gc_count = 0;
+
+ if (inited != 0) {
+ /*
+ * Destroy these locks; they'll be recreated to assure they
+ * are in the unlocked state.
+ */
+ _lock_destroy(&kse_lock);
+ _lock_destroy(&thread_lock);
+ _lock_destroy(&_thread_list_lock);
+ inited = 0;
+ }
+
+ /*
+ * After a fork(), the leftover thread goes back to being
+ * scope process.
+ */
+ curthread->attr.flags &= ~PTHREAD_SCOPE_SYSTEM;
+ curthread->attr.flags |= PTHREAD_SCOPE_PROCESS;
+
+ /* We're no longer part of any lists */
+ curthread->tlflags = 0;
+
+ /*
+ * After a fork, we are still operating on the thread's original
+ * stack. Don't clear the THR_FLAGS_USER from the thread's
+ * attribute flags.
+ */
+
+ /* Initialize the threads library. */
+ curthread->kse = NULL;
+ curthread->kseg = NULL;
+ _kse_initial = NULL;
+ _libpthread_init(curthread);
+#else
+ int i;
+
+ /* Reset the current thread and KSE lock data. */
+ for (i = 0; i < curthread->locklevel; i++) {
+ _lockuser_reinit(&curthread->lockusers[i], (void *)curthread);
+ }
+ curthread->locklevel = 0;
+ for (i = 0; i < curthread->kse->k_locklevel; i++) {
+ _lockuser_reinit(&curthread->kse->k_lockusers[i],
+ (void *)curthread->kse);
+ _LCK_SET_PRIVATE2(&curthread->kse->k_lockusers[i], NULL);
+ }
+ curthread->kse->k_locklevel = 0;
+ _thr_spinlock_init();
+ if (__isthreaded) {
+ _thr_rtld_fini();
+ _thr_signal_deinit();
+ }
+ __isthreaded = 0;
+ curthread->kse->k_kcb->kcb_kmbx.km_curthread = NULL;
+ curthread->attr.flags |= PTHREAD_SCOPE_SYSTEM;
+
+ /* After a fork(), there child should have no pending signals. */
+ sigemptyset(&curthread->sigpend);
+
+ /*
+ * Restore signal mask early, so any memory problems could
+ * dump core.
+ */
+ sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL);
+ _thread_active_threads = 1;
+#endif
+}
+
+/*
+ * This is used to initialize housekeeping and to initialize the
+ * KSD for the KSE.
+ */
+void
+_kse_init(void)
+{
+ if (inited == 0) {
+ TAILQ_INIT(&active_kseq);
+ TAILQ_INIT(&active_kse_groupq);
+ TAILQ_INIT(&free_kseq);
+ TAILQ_INIT(&free_kse_groupq);
+ TAILQ_INIT(&free_threadq);
+ TAILQ_INIT(&gc_ksegq);
+ if (_lock_init(&kse_lock, LCK_ADAPTIVE,
+ _kse_lock_wait, _kse_lock_wakeup) != 0)
+ PANIC("Unable to initialize free KSE queue lock");
+ if (_lock_init(&thread_lock, LCK_ADAPTIVE,
+ _kse_lock_wait, _kse_lock_wakeup) != 0)
+ PANIC("Unable to initialize free thread queue lock");
+ if (_lock_init(&_thread_list_lock, LCK_ADAPTIVE,
+ _kse_lock_wait, _kse_lock_wakeup) != 0)
+ PANIC("Unable to initialize thread list lock");
+ _pthread_mutex_init(&_tcb_mutex, NULL);
+ active_kse_count = 0;
+ active_kseg_count = 0;
+ _gc_count = 0;
+ inited = 1;
+ }
+}
+
+/*
+ * This is called when the first thread (other than the initial
+ * thread) is created.
+ */
+int
+_kse_setthreaded(int threaded)
+{
+ sigset_t sigset;
+
+ if ((threaded != 0) && (__isthreaded == 0)) {
+ SIGFILLSET(sigset);
+ __sys_sigprocmask(SIG_SETMASK, &sigset, &_thr_initial->sigmask);
+
+ /*
+ * Tell the kernel to create a KSE for the initial thread
+ * and enable upcalls in it.
+ */
+ _kse_initial->k_flags |= KF_STARTED;
+
+ if (_thread_scope_system <= 0) {
+ _thr_initial->attr.flags &= ~PTHREAD_SCOPE_SYSTEM;
+ _kse_initial->k_kseg->kg_flags &= ~KGF_SINGLE_THREAD;
+ _kse_initial->k_kcb->kcb_kmbx.km_curthread = NULL;
+ }
+ else {
+ /*
+ * For bound thread, kernel reads mailbox pointer
+ * once, we'd set it here before calling kse_create.
+ */
+ _tcb_set(_kse_initial->k_kcb, _thr_initial->tcb);
+ KSE_SET_MBOX(_kse_initial, _thr_initial);
+ _kse_initial->k_kcb->kcb_kmbx.km_flags |= KMF_BOUND;
+ }
+
+ /*
+ * Locking functions in libc are required when there are
+ * threads other than the initial thread.
+ */
+ _thr_rtld_init();
+
+ __isthreaded = 1;
+ if (kse_create(&_kse_initial->k_kcb->kcb_kmbx, 0) != 0) {
+ _kse_initial->k_flags &= ~KF_STARTED;
+ __isthreaded = 0;
+ PANIC("kse_create() failed\n");
+ return (-1);
+ }
+ _thr_initial->tcb->tcb_tmbx.tm_lwp =
+ _kse_initial->k_kcb->kcb_kmbx.km_lwp;
+ _thread_activated = 1;
+
+#ifndef SYSTEM_SCOPE_ONLY
+ if (_thread_scope_system <= 0) {
+ /* Set current thread to initial thread */
+ _tcb_set(_kse_initial->k_kcb, _thr_initial->tcb);
+ KSE_SET_MBOX(_kse_initial, _thr_initial);
+ _thr_start_sig_daemon();
+ _thr_setmaxconcurrency();
+ }
+ else
+#endif
+ __sys_sigprocmask(SIG_SETMASK, &_thr_initial->sigmask,
+ NULL);
+ }
+ return (0);
+}
+
+/*
+ * Lock wait and wakeup handlers for KSE locks. These are only used by
+ * KSEs, and should never be used by threads. KSE locks include the
+ * KSE group lock (used for locking the scheduling queue) and the
+ * kse_lock defined above.
+ *
+ * When a KSE lock attempt blocks, the entire KSE blocks allowing another
+ * KSE to run. For the most part, it doesn't make much sense to try and
+ * schedule another thread because you need to lock the scheduling queue
+ * in order to do that. And since the KSE lock is used to lock the scheduling
+ * queue, you would just end up blocking again.
+ */
+void
+_kse_lock_wait(struct lock *lock, struct lockuser *lu)
+{
+ struct kse *curkse = (struct kse *)_LCK_GET_PRIVATE(lu);
+ struct timespec ts;
+ int saved_flags;
+
+ if (curkse->k_kcb->kcb_kmbx.km_curthread != NULL)
+ PANIC("kse_lock_wait does not disable upcall.\n");
+ /*
+ * Enter a loop to wait until we get the lock.
+ */
+ ts.tv_sec = 0;
+ ts.tv_nsec = 1000000; /* 1 sec */
+ while (!_LCK_GRANTED(lu)) {
+ /*
+ * Yield the kse and wait to be notified when the lock
+ * is granted.
+ */
+ saved_flags = curkse->k_kcb->kcb_kmbx.km_flags;
+ curkse->k_kcb->kcb_kmbx.km_flags |= KMF_NOUPCALL |
+ KMF_NOCOMPLETED;
+ kse_release(&ts);
+ curkse->k_kcb->kcb_kmbx.km_flags = saved_flags;
+ }
+}
+
+void
+_kse_lock_wakeup(struct lock *lock, struct lockuser *lu)
+{
+ struct kse *curkse;
+ struct kse *kse;
+ struct kse_mailbox *mbx;
+
+ curkse = _get_curkse();
+ kse = (struct kse *)_LCK_GET_PRIVATE(lu);
+
+ if (kse == curkse)
+ PANIC("KSE trying to wake itself up in lock");
+ else {
+ mbx = &kse->k_kcb->kcb_kmbx;
+ _lock_grant(lock, lu);
+ /*
+ * Notify the owning kse that it has the lock.
+ * It is safe to pass invalid address to kse_wakeup
+ * even if the mailbox is not in kernel at all,
+ * and waking up a wrong kse is also harmless.
+ */
+ kse_wakeup(mbx);
+ }
+}
+
+/*
+ * Thread wait and wakeup handlers for thread locks. These are only used
+ * by threads, never by KSEs. Thread locks include the per-thread lock
+ * (defined in its structure), and condition variable and mutex locks.
+ */
+void
+_thr_lock_wait(struct lock *lock, struct lockuser *lu)
+{
+ struct pthread *curthread = (struct pthread *)lu->lu_private;
+
+ do {
+ THR_LOCK_SWITCH(curthread);
+ THR_SET_STATE(curthread, PS_LOCKWAIT);
+ _thr_sched_switch_unlocked(curthread);
+ } while (!_LCK_GRANTED(lu));
+}
+
+void
+_thr_lock_wakeup(struct lock *lock, struct lockuser *lu)
+{
+ struct pthread *thread;
+ struct pthread *curthread;
+ struct kse_mailbox *kmbx;
+
+ curthread = _get_curthread();
+ thread = (struct pthread *)_LCK_GET_PRIVATE(lu);
+
+ THR_SCHED_LOCK(curthread, thread);
+ _lock_grant(lock, lu);
+ kmbx = _thr_setrunnable_unlocked(thread);
+ THR_SCHED_UNLOCK(curthread, thread);
+ if (kmbx != NULL)
+ kse_wakeup(kmbx);
+}
+
+kse_critical_t
+_kse_critical_enter(void)
+{
+ kse_critical_t crit;
+
+ crit = (kse_critical_t)_kcb_critical_enter();
+ return (crit);
+}
+
+void
+_kse_critical_leave(kse_critical_t crit)
+{
+ struct pthread *curthread;
+
+ _kcb_critical_leave((struct kse_thr_mailbox *)crit);
+ if ((crit != NULL) && ((curthread = _get_curthread()) != NULL))
+ THR_YIELD_CHECK(curthread);
+}
+
+int
+_kse_in_critical(void)
+{
+ return (_kcb_in_critical());
+}
+
+void
+_thr_critical_enter(struct pthread *thread)
+{
+ thread->critical_count++;
+}
+
+void
+_thr_critical_leave(struct pthread *thread)
+{
+ thread->critical_count--;
+ THR_YIELD_CHECK(thread);
+}
+
+void
+_thr_sched_switch(struct pthread *curthread)
+{
+ struct kse *curkse;
+
+ (void)_kse_critical_enter();
+ curkse = _get_curkse();
+ KSE_SCHED_LOCK(curkse, curkse->k_kseg);
+ _thr_sched_switch_unlocked(curthread);
+}
+
+/*
+ * XXX - We may need to take the scheduling lock before calling
+ * this, or perhaps take the lock within here before
+ * doing anything else.
+ */
+void
+_thr_sched_switch_unlocked(struct pthread *curthread)
+{
+ struct kse *curkse;
+ volatile int resume_once = 0;
+ ucontext_t *uc;
+
+ /* We're in the scheduler, 5 by 5: */
+ curkse = curthread->kse;
+
+ curthread->need_switchout = 1; /* The thread yielded on its own. */
+ curthread->critical_yield = 0; /* No need to yield anymore. */
+
+ /* Thread can unlock the scheduler lock. */
+ curthread->lock_switch = 1;
+
+ if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
+ kse_sched_single(&curkse->k_kcb->kcb_kmbx);
+ else {
+ if (__predict_false(_libkse_debug != 0)) {
+ /*
+ * Because debugger saves single step status in thread
+ * mailbox's tm_dflags, we can safely clear single
+ * step status here. the single step status will be
+ * restored by kse_switchin when the thread is
+ * switched in again. This also lets uts run in full
+ * speed.
+ */
+ ptrace(PT_CLEARSTEP, curkse->k_kcb->kcb_kmbx.km_lwp,
+ (caddr_t) 1, 0);
+ }
+
+ KSE_SET_SWITCH(curkse);
+ _thread_enter_uts(curthread->tcb, curkse->k_kcb);
+ }
+
+ /*
+ * Unlock the scheduling queue and leave the
+ * critical region.
+ */
+ /* Don't trust this after a switch! */
+ curkse = curthread->kse;
+
+ curthread->lock_switch = 0;
+ KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
+ _kse_critical_leave(&curthread->tcb->tcb_tmbx);
+
+ /*
+ * This thread is being resumed; check for cancellations.
+ */
+ if (THR_NEED_ASYNC_CANCEL(curthread) && !THR_IN_CRITICAL(curthread)) {
+ uc = alloca(sizeof(ucontext_t));
+ resume_once = 0;
+ THR_GETCONTEXT(uc);
+ if (resume_once == 0) {
+ resume_once = 1;
+ curthread->check_pending = 0;
+ thr_resume_check(curthread, uc);
+ }
+ }
+ THR_ACTIVATE_LAST_LOCK(curthread);
+}
+
+/*
+ * This is the scheduler for a KSE which runs a scope system thread.
+ * The multi-thread KSE scheduler should also work for a single threaded
+ * KSE, but we use a separate scheduler so that it can be fine-tuned
+ * to be more efficient (and perhaps not need a separate stack for
+ * the KSE, allowing it to use the thread's stack).
+ */
+
+static void
+kse_sched_single(struct kse_mailbox *kmbx)
+{
+ struct kse *curkse;
+ struct pthread *curthread;
+ struct timespec ts;
+ sigset_t sigmask;
+ int i, sigseqno, level, first = 0;
+
+ curkse = (struct kse *)kmbx->km_udata;
+ curthread = curkse->k_curthread;
+
+ if (__predict_false((curkse->k_flags & KF_INITIALIZED) == 0)) {
+ /* Setup this KSEs specific data. */
+ _kcb_set(curkse->k_kcb);
+ _tcb_set(curkse->k_kcb, curthread->tcb);
+ curkse->k_flags |= KF_INITIALIZED;
+ first = 1;
+ curthread->active = 1;
+
+ /* Setup kernel signal masks for new thread. */
+ __sys_sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL);
+ /*
+ * Enter critical region, this is meanless for bound thread,
+ * It is used to let other code work, those code want mailbox
+ * to be cleared.
+ */
+ (void)_kse_critical_enter();
+ } else {
+ /*
+ * Bound thread always has tcb set, this prevent some
+ * code from blindly setting bound thread tcb to NULL,
+ * buggy code ?
+ */
+ _tcb_set(curkse->k_kcb, curthread->tcb);
+ }
+
+ curthread->critical_yield = 0;
+ curthread->need_switchout = 0;
+
+ /*
+ * Lock the scheduling queue.
+ *
+ * There is no scheduling queue for single threaded KSEs,
+ * but we need a lock for protection regardless.
+ */
+ if (curthread->lock_switch == 0)
+ KSE_SCHED_LOCK(curkse, curkse->k_kseg);
+
+ /*
+ * This has to do the job of kse_switchout_thread(), only
+ * for a single threaded KSE/KSEG.
+ */
+
+ switch (curthread->state) {
+ case PS_MUTEX_WAIT:
+ case PS_COND_WAIT:
+ if (THR_NEED_CANCEL(curthread)) {
+ curthread->interrupted = 1;
+ curthread->continuation = _thr_finish_cancellation;
+ THR_SET_STATE(curthread, PS_RUNNING);
+ }
+ break;
+
+ case PS_LOCKWAIT:
+ /*
+ * This state doesn't timeout.
+ */
+ curthread->wakeup_time.tv_sec = -1;
+ curthread->wakeup_time.tv_nsec = -1;
+ level = curthread->locklevel - 1;
+ if (_LCK_GRANTED(&curthread->lockusers[level]))
+ THR_SET_STATE(curthread, PS_RUNNING);
+ break;
+
+ case PS_DEAD:
+ curthread->check_pending = 0;
+ /* Unlock the scheduling queue and exit the KSE and thread. */
+ thr_cleanup(curkse, curthread);
+ KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
+ PANIC("bound thread shouldn't get here\n");
+ break;
+
+ case PS_JOIN:
+ if (THR_NEED_CANCEL(curthread)) {
+ curthread->join_status.thread = NULL;
+ THR_SET_STATE(curthread, PS_RUNNING);
+ } else {
+ /*
+ * This state doesn't timeout.
+ */
+ curthread->wakeup_time.tv_sec = -1;
+ curthread->wakeup_time.tv_nsec = -1;
+ }
+ break;
+
+ case PS_SUSPENDED:
+ if (THR_NEED_CANCEL(curthread)) {
+ curthread->interrupted = 1;
+ THR_SET_STATE(curthread, PS_RUNNING);
+ } else {
+ /*
+ * These states don't timeout.
+ */
+ curthread->wakeup_time.tv_sec = -1;
+ curthread->wakeup_time.tv_nsec = -1;
+ }
+ break;
+
+ case PS_RUNNING:
+ if ((curthread->flags & THR_FLAGS_SUSPENDED) != 0 &&
+ !THR_NEED_CANCEL(curthread)) {
+ THR_SET_STATE(curthread, PS_SUSPENDED);
+ /*
+ * These states don't timeout.
+ */
+ curthread->wakeup_time.tv_sec = -1;
+ curthread->wakeup_time.tv_nsec = -1;
+ }
+ break;
+
+ case PS_SIGWAIT:
+ PANIC("bound thread does not have SIGWAIT state\n");
+
+ case PS_SLEEP_WAIT:
+ PANIC("bound thread does not have SLEEP_WAIT state\n");
+
+ case PS_SIGSUSPEND:
+ PANIC("bound thread does not have SIGSUSPEND state\n");
+
+ case PS_DEADLOCK:
+ /*
+ * These states don't timeout and don't need
+ * to be in the waiting queue.
+ */
+ curthread->wakeup_time.tv_sec = -1;
+ curthread->wakeup_time.tv_nsec = -1;
+ break;
+
+ default:
+ PANIC("Unknown state\n");
+ break;
+ }
+
+ while (curthread->state != PS_RUNNING) {
+ sigseqno = curkse->k_sigseqno;
+ if (curthread->check_pending != 0) {
+ /*
+ * Install pending signals into the frame, possible
+ * cause mutex or condvar backout.
+ */
+ curthread->check_pending = 0;
+ SIGFILLSET(sigmask);
+
+ /*
+ * Lock out kernel signal code when we are processing
+ * signals, and get a fresh copy of signal mask.
+ */
+ __sys_sigprocmask(SIG_SETMASK, &sigmask,
+ &curthread->sigmask);
+ for (i = 1; i <= _SIG_MAXSIG; i++) {
+ if (SIGISMEMBER(curthread->sigmask, i))
+ continue;
+ if (SIGISMEMBER(curthread->sigpend, i))
+ (void)_thr_sig_add(curthread, i,
+ &curthread->siginfo[i-1]);
+ }
+ __sys_sigprocmask(SIG_SETMASK, &curthread->sigmask,
+ NULL);
+ /* The above code might make thread runnable */
+ if (curthread->state == PS_RUNNING)
+ break;
+ }
+ THR_DEACTIVATE_LAST_LOCK(curthread);
+ kse_wait(curkse, curthread, sigseqno);
+ THR_ACTIVATE_LAST_LOCK(curthread);
+ if (curthread->wakeup_time.tv_sec >= 0) {
+ KSE_GET_TOD(curkse, &ts);
+ if (thr_timedout(curthread, &ts)) {
+ /* Indicate the thread timedout: */
+ curthread->timeout = 1;
+ /* Make the thread runnable. */
+ THR_SET_STATE(curthread, PS_RUNNING);
+ }
+ }
+ }
+
+ if (curthread->lock_switch == 0) {
+ /* Unlock the scheduling queue. */
+ KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
+ }
+
+ DBG_MSG("Continuing bound thread %p\n", curthread);
+ if (first) {
+ _kse_critical_leave(&curthread->tcb->tcb_tmbx);
+ pthread_exit(curthread->start_routine(curthread->arg));
+ }
+}
+
+#ifdef DEBUG_THREAD_KERN
+static void
+dump_queues(struct kse *curkse)
+{
+ struct pthread *thread;
+
+ DBG_MSG("Threads in waiting queue:\n");
+ TAILQ_FOREACH(thread, &curkse->k_kseg->kg_schedq.sq_waitq, pqe) {
+ DBG_MSG(" thread %p, state %d, blocked %d\n",
+ thread, thread->state, thread->blocked);
+ }
+}
+#endif
+
+/*
+ * This is the scheduler for a KSE which runs multiple threads.
+ */
+static void
+kse_sched_multi(struct kse_mailbox *kmbx)
+{
+ struct kse *curkse;
+ struct pthread *curthread, *td_wait;
+ int ret;
+
+ curkse = (struct kse *)kmbx->km_udata;
+ THR_ASSERT(curkse->k_kcb->kcb_kmbx.km_curthread == NULL,
+ "Mailbox not null in kse_sched_multi");
+
+ /* Check for first time initialization: */
+ if (__predict_false((curkse->k_flags & KF_INITIALIZED) == 0)) {
+ /* Setup this KSEs specific data. */
+ _kcb_set(curkse->k_kcb);
+
+ /* Set this before grabbing the context. */
+ curkse->k_flags |= KF_INITIALIZED;
+ }
+
+ /*
+ * No current thread anymore, calling _get_curthread in UTS
+ * should dump core
+ */
+ _tcb_set(curkse->k_kcb, NULL);
+
+ /* If this is an upcall; take the scheduler lock. */
+ if (!KSE_IS_SWITCH(curkse))
+ KSE_SCHED_LOCK(curkse, curkse->k_kseg);
+ else
+ KSE_CLEAR_SWITCH(curkse);
+
+ if (KSE_IS_IDLE(curkse)) {
+ KSE_CLEAR_IDLE(curkse);
+ curkse->k_kseg->kg_idle_kses--;
+ }
+
+ /*
+ * Now that the scheduler lock is held, get the current
+ * thread. The KSE's current thread cannot be safely
+ * examined without the lock because it could have returned
+ * as completed on another KSE. See kse_check_completed().
+ */
+ curthread = curkse->k_curthread;
+
+ /*
+ * If the current thread was completed in another KSE, then
+ * it will be in the run queue. Don't mark it as being blocked.
+ */
+ if ((curthread != NULL) &&
+ ((curthread->flags & THR_FLAGS_IN_RUNQ) == 0) &&
+ (curthread->need_switchout == 0)) {
+ /*
+ * Assume the current thread is blocked; when the
+ * completed threads are checked and if the current
+ * thread is among the completed, the blocked flag
+ * will be cleared.
+ */
+ curthread->blocked = 1;
+ DBG_MSG("Running thread %p is now blocked in kernel.\n",
+ curthread);
+ }
+
+ /* Check for any unblocked threads in the kernel. */
+ kse_check_completed(curkse);
+
+ /*
+ * Check for threads that have timed-out.
+ */
+ kse_check_waitq(curkse);
+
+ /*
+ * Switchout the current thread, if necessary, as the last step
+ * so that it is inserted into the run queue (if it's runnable)
+ * _after_ any other threads that were added to it above.
+ */
+ if (curthread == NULL)
+ ; /* Nothing to do here. */
+ else if ((curthread->need_switchout == 0) && DBG_CAN_RUN(curthread) &&
+ (curthread->blocked == 0) && (THR_IN_CRITICAL(curthread))) {
+ /*
+ * Resume the thread and tell it to yield when
+ * it leaves the critical region.
+ */
+ curthread->critical_yield = 1;
+ curthread->active = 1;
+ if ((curthread->flags & THR_FLAGS_IN_RUNQ) != 0)
+ KSE_RUNQ_REMOVE(curkse, curthread);
+ curkse->k_curthread = curthread;
+ curthread->kse = curkse;
+ DBG_MSG("Continuing thread %p in critical region\n",
+ curthread);
+ kse_wakeup_multi(curkse);
+ KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
+ ret = _thread_switch(curkse->k_kcb, curthread->tcb, 1);
+ if (ret != 0)
+ PANIC("Can't resume thread in critical region\n");
+ }
+ else if ((curthread->flags & THR_FLAGS_IN_RUNQ) == 0) {
+ curthread->tcb->tcb_tmbx.tm_lwp = 0;
+ kse_switchout_thread(curkse, curthread);
+ }
+ curkse->k_curthread = NULL;
+
+#ifdef DEBUG_THREAD_KERN
+ dump_queues(curkse);
+#endif
+
+ /* Check if there are no threads ready to run: */
+ while (((curthread = KSE_RUNQ_FIRST(curkse)) == NULL) &&
+ (curkse->k_kseg->kg_threadcount != 0) &&
+ ((curkse->k_flags & KF_TERMINATED) == 0)) {
+ /*
+ * Wait for a thread to become active or until there are
+ * no more threads.
+ */
+ td_wait = KSE_WAITQ_FIRST(curkse);
+ kse_wait(curkse, td_wait, 0);
+ kse_check_completed(curkse);
+ kse_check_waitq(curkse);
+ }
+
+ /* Check for no more threads: */
+ if ((curkse->k_kseg->kg_threadcount == 0) ||
+ ((curkse->k_flags & KF_TERMINATED) != 0)) {
+ /*
+ * Normally this shouldn't return, but it will if there
+ * are other KSEs running that create new threads that
+ * are assigned to this KSE[G]. For instance, if a scope
+ * system thread were to create a scope process thread
+ * and this kse[g] is the initial kse[g], then that newly
+ * created thread would be assigned to us (the initial
+ * kse[g]).
+ */
+ kse_wakeup_multi(curkse);
+ KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
+ kse_fini(curkse);
+ /* never returns */
+ }
+
+ THR_ASSERT(curthread != NULL,
+ "Return from kse_wait/fini without thread.");
+ THR_ASSERT(curthread->state != PS_DEAD,
+ "Trying to resume dead thread!");
+ KSE_RUNQ_REMOVE(curkse, curthread);
+
+ /*
+ * Make the selected thread the current thread.
+ */
+ curkse->k_curthread = curthread;
+
+ /*
+ * Make sure the current thread's kse points to this kse.
+ */
+ curthread->kse = curkse;
+
+ /*
+ * Reset the time slice if this thread is running for the first
+ * time or running again after using its full time slice allocation.
+ */
+ if (curthread->slice_usec == -1)
+ curthread->slice_usec = 0;
+
+ /* Mark the thread active. */
+ curthread->active = 1;
+
+ /*
+ * The thread's current signal frame will only be NULL if it
+ * is being resumed after being blocked in the kernel. In
+ * this case, and if the thread needs to run down pending
+ * signals or needs a cancellation check, we need to add a
+ * signal frame to the thread's context.
+ */
+ if (curthread->lock_switch == 0 && curthread->state == PS_RUNNING &&
+ (curthread->check_pending != 0 ||
+ THR_NEED_ASYNC_CANCEL(curthread)) &&
+ !THR_IN_CRITICAL(curthread)) {
+ curthread->check_pending = 0;
+ signalcontext(&curthread->tcb->tcb_tmbx.tm_context, 0,
+ (__sighandler_t *)thr_resume_wrapper);
+ }
+ kse_wakeup_multi(curkse);
+ /*
+ * Continue the thread at its current frame:
+ */
+ if (curthread->lock_switch != 0) {
+ /*
+ * This thread came from a scheduler switch; it will
+ * unlock the scheduler lock and set the mailbox.
+ */
+ ret = _thread_switch(curkse->k_kcb, curthread->tcb, 0);
+ } else {
+ /* This thread won't unlock the scheduler lock. */
+ KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
+ ret = _thread_switch(curkse->k_kcb, curthread->tcb, 1);
+ }
+ if (ret != 0)
+ PANIC("Thread has returned from _thread_switch");
+
+ /* This point should not be reached. */
+ PANIC("Thread has returned from _thread_switch");
+}
+
+static void
+thr_resume_wrapper(int sig, siginfo_t *siginfo, ucontext_t *ucp)
+{
+ struct pthread *curthread = _get_curthread();
+ struct kse *curkse;
+ int ret, err_save = errno;
+
+ DBG_MSG(">>> sig wrapper\n");
+ if (curthread->lock_switch)
+ PANIC("thr_resume_wrapper, lock_switch != 0\n");
+ thr_resume_check(curthread, ucp);
+ errno = err_save;
+ _kse_critical_enter();
+ curkse = curthread->kse;
+ curthread->tcb->tcb_tmbx.tm_context = *ucp;
+ ret = _thread_switch(curkse->k_kcb, curthread->tcb, 1);
+ if (ret != 0)
+ PANIC("thr_resume_wrapper: thread has returned "
+ "from _thread_switch");
+ /* THR_SETCONTEXT(ucp); */ /* not work, why ? */
+}
+
+static void
+thr_resume_check(struct pthread *curthread, ucontext_t *ucp)
+{
+ _thr_sig_rundown(curthread, ucp);
+
+ if (THR_NEED_ASYNC_CANCEL(curthread))
+ pthread_testcancel();
+}
+
+/*
+ * Clean up a thread. This must be called with the thread's KSE
+ * scheduling lock held. The thread must be a thread from the
+ * KSE's group.
+ */
+static void
+thr_cleanup(struct kse *curkse, struct pthread *thread)
+{
+ struct pthread *joiner;
+ struct kse_mailbox *kmbx = NULL;
+ int sys_scope;
+
+ if ((joiner = thread->joiner) != NULL) {
+ /* Joinee scheduler lock held; joiner won't leave. */
+ if (joiner->kseg == curkse->k_kseg) {
+ if (joiner->join_status.thread == thread) {
+ joiner->join_status.thread = NULL;
+ joiner->join_status.ret = thread->ret;
+ (void)_thr_setrunnable_unlocked(joiner);
+ }
+ } else {
+ KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
+ /* The joiner may have removed itself and exited. */
+ if (_thr_ref_add(thread, joiner, 0) == 0) {
+ KSE_SCHED_LOCK(curkse, joiner->kseg);
+ if (joiner->join_status.thread == thread) {
+ joiner->join_status.thread = NULL;
+ joiner->join_status.ret = thread->ret;
+ kmbx = _thr_setrunnable_unlocked(joiner);
+ }
+ KSE_SCHED_UNLOCK(curkse, joiner->kseg);
+ _thr_ref_delete(thread, joiner);
+ if (kmbx != NULL)
+ kse_wakeup(kmbx);
+ }
+ KSE_SCHED_LOCK(curkse, curkse->k_kseg);
+ }
+ thread->attr.flags |= PTHREAD_DETACHED;
+ }
+
+ if (!(sys_scope = (thread->attr.flags & PTHREAD_SCOPE_SYSTEM))) {
+ /*
+ * Remove the thread from the KSEG's list of threads.
+ */
+ KSEG_THRQ_REMOVE(thread->kseg, thread);
+ /*
+ * Migrate the thread to the main KSE so that this
+ * KSE and KSEG can be cleaned when their last thread
+ * exits.
+ */
+ thread->kseg = _kse_initial->k_kseg;
+ thread->kse = _kse_initial;
+ }
+
+ /*
+ * We can't hold the thread list lock while holding the
+ * scheduler lock.
+ */
+ KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
+ DBG_MSG("Adding thread %p to GC list\n", thread);
+ KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock);
+ thread->tlflags |= TLFLAGS_GC_SAFE;
+ THR_GCLIST_ADD(thread);
+ KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
+ if (sys_scope) {
+ /*
+ * System scope thread is single thread group,
+ * when thread is exited, its kse and ksegrp should
+ * be recycled as well.
+ * kse upcall stack belongs to thread, clear it here.
+ */
+ curkse->k_stack.ss_sp = 0;
+ curkse->k_stack.ss_size = 0;
+ kse_exit();
+ PANIC("kse_exit() failed for system scope thread");
+ }
+ KSE_SCHED_LOCK(curkse, curkse->k_kseg);
+}
+
+void
+_thr_gc(struct pthread *curthread)
+{
+ thread_gc(curthread);
+ kse_gc(curthread);
+ kseg_gc(curthread);
+}
+
+static void
+thread_gc(struct pthread *curthread)
+{
+ struct pthread *td, *td_next;
+ kse_critical_t crit;
+ TAILQ_HEAD(, pthread) worklist;
+
+ TAILQ_INIT(&worklist);
+ crit = _kse_critical_enter();
+ KSE_LOCK_ACQUIRE(curthread->kse, &_thread_list_lock);
+
+ /* Check the threads waiting for GC. */
+ for (td = TAILQ_FIRST(&_thread_gc_list); td != NULL; td = td_next) {
+ td_next = TAILQ_NEXT(td, gcle);
+ if ((td->tlflags & TLFLAGS_GC_SAFE) == 0)
+ continue;
+ else if (((td->attr.flags & PTHREAD_SCOPE_SYSTEM) != 0) &&
+ ((td->kse->k_kcb->kcb_kmbx.km_flags & KMF_DONE) == 0)) {
+ /*
+ * The thread and KSE are operating on the same
+ * stack. Wait for the KSE to exit before freeing
+ * the thread's stack as well as everything else.
+ */
+ continue;
+ }
+ /*
+ * Remove the thread from the GC list. If the thread
+ * isn't yet detached, it will get added back to the
+ * GC list at a later time.
+ */
+ THR_GCLIST_REMOVE(td);
+ DBG_MSG("Freeing thread %p stack\n", td);
+ /*
+ * We can free the thread stack since it's no longer
+ * in use.
+ */
+ _thr_stack_free(&td->attr);
+ if (((td->attr.flags & PTHREAD_DETACHED) != 0) &&
+ (td->refcount == 0)) {
+ /*
+ * The thread has detached and is no longer
+ * referenced. It is safe to remove all
+ * remnants of the thread.
+ */
+ THR_LIST_REMOVE(td);
+ TAILQ_INSERT_HEAD(&worklist, td, gcle);
+ }
+ }
+ KSE_LOCK_RELEASE(curthread->kse, &_thread_list_lock);
+ _kse_critical_leave(crit);
+
+ while ((td = TAILQ_FIRST(&worklist)) != NULL) {
+ TAILQ_REMOVE(&worklist, td, gcle);
+ /*
+ * XXX we don't free initial thread and its kse
+ * (if thread is a bound thread), because there might
+ * have some code referencing initial thread and kse.
+ */
+ if (td == _thr_initial) {
+ DBG_MSG("Initial thread won't be freed\n");
+ continue;
+ }
+
+ if ((td->attr.flags & PTHREAD_SCOPE_SYSTEM) != 0) {
+ crit = _kse_critical_enter();
+ KSE_LOCK_ACQUIRE(curthread->kse, &kse_lock);
+ kse_free_unlocked(td->kse);
+ kseg_free_unlocked(td->kseg);
+ KSE_LOCK_RELEASE(curthread->kse, &kse_lock);
+ _kse_critical_leave(crit);
+ }
+ DBG_MSG("Freeing thread %p\n", td);
+ _thr_free(curthread, td);
+ }
+}
+
+static void
+kse_gc(struct pthread *curthread)
+{
+ kse_critical_t crit;
+ TAILQ_HEAD(, kse) worklist;
+ struct kse *kse;
+
+ if (free_kse_count <= MAX_CACHED_KSES)
+ return;
+ TAILQ_INIT(&worklist);
+ crit = _kse_critical_enter();
+ KSE_LOCK_ACQUIRE(curthread->kse, &kse_lock);
+ while (free_kse_count > MAX_CACHED_KSES) {
+ kse = TAILQ_FIRST(&free_kseq);
+ TAILQ_REMOVE(&free_kseq, kse, k_qe);
+ TAILQ_INSERT_HEAD(&worklist, kse, k_qe);
+ free_kse_count--;
+ }
+ KSE_LOCK_RELEASE(curthread->kse, &kse_lock);
+ _kse_critical_leave(crit);
+
+ while ((kse = TAILQ_FIRST(&worklist))) {
+ TAILQ_REMOVE(&worklist, kse, k_qe);
+ kse_destroy(kse);
+ }
+}
+
+static void
+kseg_gc(struct pthread *curthread)
+{
+ kse_critical_t crit;
+ TAILQ_HEAD(, kse_group) worklist;
+ struct kse_group *kseg;
+
+ if (free_kseg_count <= MAX_CACHED_KSEGS)
+ return;
+ TAILQ_INIT(&worklist);
+ crit = _kse_critical_enter();
+ KSE_LOCK_ACQUIRE(curthread->kse, &kse_lock);
+ while (free_kseg_count > MAX_CACHED_KSEGS) {
+ kseg = TAILQ_FIRST(&free_kse_groupq);
+ TAILQ_REMOVE(&free_kse_groupq, kseg, kg_qe);
+ free_kseg_count--;
+ TAILQ_INSERT_HEAD(&worklist, kseg, kg_qe);
+ }
+ KSE_LOCK_RELEASE(curthread->kse, &kse_lock);
+ _kse_critical_leave(crit);
+
+ while ((kseg = TAILQ_FIRST(&worklist))) {
+ TAILQ_REMOVE(&worklist, kseg, kg_qe);
+ kseg_destroy(kseg);
+ }
+}
+
+/*
+ * Only new threads that are running or suspended may be scheduled.
+ */
+int
+_thr_schedule_add(struct pthread *curthread, struct pthread *newthread)
+{
+ kse_critical_t crit;
+ int ret;
+
+ /* Add the new thread. */
+ thr_link(newthread);
+
+ /*
+ * If this is the first time creating a thread, make sure
+ * the mailbox is set for the current thread.
+ */
+ if ((newthread->attr.flags & PTHREAD_SCOPE_SYSTEM) != 0) {
+ /* We use the thread's stack as the KSE's stack. */
+ newthread->kse->k_kcb->kcb_kmbx.km_stack.ss_sp =
+ newthread->attr.stackaddr_attr;
+ newthread->kse->k_kcb->kcb_kmbx.km_stack.ss_size =
+ newthread->attr.stacksize_attr;
+
+ /*
+ * No need to lock the scheduling queue since the
+ * KSE/KSEG pair have not yet been started.
+ */
+ KSEG_THRQ_ADD(newthread->kseg, newthread);
+ /* this thread never gives up kse */
+ newthread->active = 1;
+ newthread->kse->k_curthread = newthread;
+ newthread->kse->k_kcb->kcb_kmbx.km_flags = KMF_BOUND;
+ newthread->kse->k_kcb->kcb_kmbx.km_func =
+ (kse_func_t *)kse_sched_single;
+ newthread->kse->k_kcb->kcb_kmbx.km_quantum = 0;
+ KSE_SET_MBOX(newthread->kse, newthread);
+ /*
+ * This thread needs a new KSE and KSEG.
+ */
+ newthread->kse->k_flags &= ~KF_INITIALIZED;
+ newthread->kse->k_flags |= KF_STARTED;
+ /* Fire up! */
+ ret = kse_create(&newthread->kse->k_kcb->kcb_kmbx, 1);
+ if (ret != 0)
+ ret = errno;
+ }
+ else {
+ /*
+ * Lock the KSE and add the new thread to its list of
+ * assigned threads. If the new thread is runnable, also
+ * add it to the KSE's run queue.
+ */
+ crit = _kse_critical_enter();
+ KSE_SCHED_LOCK(curthread->kse, newthread->kseg);
+ KSEG_THRQ_ADD(newthread->kseg, newthread);
+ if (newthread->state == PS_RUNNING)
+ THR_RUNQ_INSERT_TAIL(newthread);
+ if ((newthread->kse->k_flags & KF_STARTED) == 0) {
+ /*
+ * This KSE hasn't been started yet. Start it
+ * outside of holding the lock.
+ */
+ newthread->kse->k_flags |= KF_STARTED;
+ newthread->kse->k_kcb->kcb_kmbx.km_func =
+ (kse_func_t *)kse_sched_multi;
+ newthread->kse->k_kcb->kcb_kmbx.km_flags = 0;
+ kse_create(&newthread->kse->k_kcb->kcb_kmbx, 0);
+ } else if ((newthread->state == PS_RUNNING) &&
+ KSE_IS_IDLE(newthread->kse)) {
+ /*
+ * The thread is being scheduled on another KSEG.
+ */
+ kse_wakeup_one(newthread);
+ }
+ KSE_SCHED_UNLOCK(curthread->kse, newthread->kseg);
+ _kse_critical_leave(crit);
+ ret = 0;
+ }
+ if (ret != 0)
+ thr_unlink(newthread);
+
+ return (ret);
+}
+
+void
+kse_waitq_insert(struct pthread *thread)
+{
+ struct pthread *td;
+
+ if (thread->wakeup_time.tv_sec == -1)
+ TAILQ_INSERT_TAIL(&thread->kse->k_schedq->sq_waitq, thread,
+ pqe);
+ else {
+ td = TAILQ_FIRST(&thread->kse->k_schedq->sq_waitq);
+ while ((td != NULL) && (td->wakeup_time.tv_sec != -1) &&
+ ((td->wakeup_time.tv_sec < thread->wakeup_time.tv_sec) ||
+ ((td->wakeup_time.tv_sec == thread->wakeup_time.tv_sec) &&
+ (td->wakeup_time.tv_nsec <= thread->wakeup_time.tv_nsec))))
+ td = TAILQ_NEXT(td, pqe);
+ if (td == NULL)
+ TAILQ_INSERT_TAIL(&thread->kse->k_schedq->sq_waitq,
+ thread, pqe);
+ else
+ TAILQ_INSERT_BEFORE(td, thread, pqe);
+ }
+ thread->flags |= THR_FLAGS_IN_WAITQ;
+}
+
+/*
+ * This must be called with the scheduling lock held.
+ */
+static void
+kse_check_completed(struct kse *kse)
+{
+ struct pthread *thread;
+ struct kse_thr_mailbox *completed;
+ int sig;
+
+ if ((completed = kse->k_kcb->kcb_kmbx.km_completed) != NULL) {
+ kse->k_kcb->kcb_kmbx.km_completed = NULL;
+ while (completed != NULL) {
+ thread = completed->tm_udata;
+ DBG_MSG("Found completed thread %p, name %s\n",
+ thread,
+ (thread->name == NULL) ? "none" : thread->name);
+ thread->blocked = 0;
+ if (thread != kse->k_curthread) {
+ thr_accounting(thread);
+ if ((thread->flags & THR_FLAGS_SUSPENDED) != 0)
+ THR_SET_STATE(thread, PS_SUSPENDED);
+ else
+ KSE_RUNQ_INSERT_TAIL(kse, thread);
+ if ((thread->kse != kse) &&
+ (thread->kse->k_curthread == thread)) {
+ /*
+ * Remove this thread from its
+ * previous KSE so that it (the KSE)
+ * doesn't think it is still active.
+ */
+ thread->kse->k_curthread = NULL;
+ thread->active = 0;
+ }
+ }
+ if ((sig = thread->tcb->tcb_tmbx.tm_syncsig.si_signo)
+ != 0) {
+ if (SIGISMEMBER(thread->sigmask, sig))
+ SIGADDSET(thread->sigpend, sig);
+ else if (THR_IN_CRITICAL(thread))
+ kse_thr_interrupt(NULL, KSE_INTR_SIGEXIT, sig);
+ else
+ (void)_thr_sig_add(thread, sig,
+ &thread->tcb->tcb_tmbx.tm_syncsig);
+ thread->tcb->tcb_tmbx.tm_syncsig.si_signo = 0;
+ }
+ completed = completed->tm_next;
+ }
+ }
+}
+
+/*
+ * This must be called with the scheduling lock held.
+ */
+static void
+kse_check_waitq(struct kse *kse)
+{
+ struct pthread *pthread;
+ struct timespec ts;
+
+ KSE_GET_TOD(kse, &ts);
+
+ /*
+ * Wake up threads that have timedout. This has to be
+ * done before adding the current thread to the run queue
+ * so that a CPU intensive thread doesn't get preference
+ * over waiting threads.
+ */
+ while (((pthread = KSE_WAITQ_FIRST(kse)) != NULL) &&
+ thr_timedout(pthread, &ts)) {
+ /* Remove the thread from the wait queue: */
+ KSE_WAITQ_REMOVE(kse, pthread);
+ DBG_MSG("Found timedout thread %p in waitq\n", pthread);
+
+ /* Indicate the thread timedout: */
+ pthread->timeout = 1;
+
+ /* Add the thread to the priority queue: */
+ if ((pthread->flags & THR_FLAGS_SUSPENDED) != 0)
+ THR_SET_STATE(pthread, PS_SUSPENDED);
+ else {
+ THR_SET_STATE(pthread, PS_RUNNING);
+ KSE_RUNQ_INSERT_TAIL(kse, pthread);
+ }
+ }
+}
+
+static int
+thr_timedout(struct pthread *thread, struct timespec *curtime)
+{
+ if (thread->wakeup_time.tv_sec < 0)
+ return (0);
+ else if (thread->wakeup_time.tv_sec > curtime->tv_sec)
+ return (0);
+ else if ((thread->wakeup_time.tv_sec == curtime->tv_sec) &&
+ (thread->wakeup_time.tv_nsec > curtime->tv_nsec))
+ return (0);
+ else
+ return (1);
+}
+
+/*
+ * This must be called with the scheduling lock held.
+ *
+ * Each thread has a time slice, a wakeup time (used when it wants
+ * to wait for a specified amount of time), a run state, and an
+ * active flag.
+ *
+ * When a thread gets run by the scheduler, the active flag is
+ * set to non-zero (1). When a thread performs an explicit yield
+ * or schedules a state change, it enters the scheduler and the
+ * active flag is cleared. When the active flag is still seen
+ * set in the scheduler, that means that the thread is blocked in
+ * the kernel (because it is cleared before entering the scheduler
+ * in all other instances).
+ *
+ * The wakeup time is only set for those states that can timeout.
+ * It is set to (-1, -1) for all other instances.
+ *
+ * The thread's run state, aside from being useful when debugging,
+ * is used to place the thread in an appropriate queue. There
+ * are 2 basic queues:
+ *
+ * o run queue - queue ordered by priority for all threads
+ * that are runnable
+ * o waiting queue - queue sorted by wakeup time for all threads
+ * that are not otherwise runnable (not blocked
+ * in kernel, not waiting for locks)
+ *
+ * The thread's time slice is used for round-robin scheduling
+ * (the default scheduling policy). While a SCHED_RR thread
+ * is runnable it's time slice accumulates. When it reaches
+ * the time slice interval, it gets reset and added to the end
+ * of the queue of threads at its priority. When a thread no
+ * longer becomes runnable (blocks in kernel, waits, etc), its
+ * time slice is reset.
+ *
+ * The job of kse_switchout_thread() is to handle all of the above.
+ */
+static void
+kse_switchout_thread(struct kse *kse, struct pthread *thread)
+{
+ int level;
+ int i;
+ int restart;
+ siginfo_t siginfo;
+
+ /*
+ * Place the currently running thread into the
+ * appropriate queue(s).
+ */
+ DBG_MSG("Switching out thread %p, state %d\n", thread, thread->state);
+
+ THR_DEACTIVATE_LAST_LOCK(thread);
+ if (thread->blocked != 0) {
+ thread->active = 0;
+ thread->need_switchout = 0;
+ /* This thread must have blocked in the kernel. */
+ /*
+ * Check for pending signals and cancellation for
+ * this thread to see if we need to interrupt it
+ * in the kernel.
+ */
+ if (THR_NEED_CANCEL(thread)) {
+ kse_thr_interrupt(&thread->tcb->tcb_tmbx,
+ KSE_INTR_INTERRUPT, 0);
+ } else if (thread->check_pending != 0) {
+ for (i = 1; i <= _SIG_MAXSIG; ++i) {
+ if (SIGISMEMBER(thread->sigpend, i) &&
+ !SIGISMEMBER(thread->sigmask, i)) {
+ restart = _thread_sigact[i - 1].sa_flags & SA_RESTART;
+ kse_thr_interrupt(&thread->tcb->tcb_tmbx,
+ restart ? KSE_INTR_RESTART : KSE_INTR_INTERRUPT, 0);
+ break;
+ }
+ }
+ }
+ }
+ else {
+ switch (thread->state) {
+ case PS_MUTEX_WAIT:
+ case PS_COND_WAIT:
+ if (THR_NEED_CANCEL(thread)) {
+ thread->interrupted = 1;
+ thread->continuation = _thr_finish_cancellation;
+ THR_SET_STATE(thread, PS_RUNNING);
+ } else {
+ /* Insert into the waiting queue: */
+ KSE_WAITQ_INSERT(kse, thread);
+ }
+ break;
+
+ case PS_LOCKWAIT:
+ /*
+ * This state doesn't timeout.
+ */
+ thread->wakeup_time.tv_sec = -1;
+ thread->wakeup_time.tv_nsec = -1;
+ level = thread->locklevel - 1;
+ if (!_LCK_GRANTED(&thread->lockusers[level]))
+ KSE_WAITQ_INSERT(kse, thread);
+ else
+ THR_SET_STATE(thread, PS_RUNNING);
+ break;
+
+ case PS_SLEEP_WAIT:
+ case PS_SIGWAIT:
+ if (THR_NEED_CANCEL(thread)) {
+ thread->interrupted = 1;
+ THR_SET_STATE(thread, PS_RUNNING);
+ } else {
+ KSE_WAITQ_INSERT(kse, thread);
+ }
+ break;
+
+ case PS_JOIN:
+ if (THR_NEED_CANCEL(thread)) {
+ thread->join_status.thread = NULL;
+ THR_SET_STATE(thread, PS_RUNNING);
+ } else {
+ /*
+ * This state doesn't timeout.
+ */
+ thread->wakeup_time.tv_sec = -1;
+ thread->wakeup_time.tv_nsec = -1;
+
+ /* Insert into the waiting queue: */
+ KSE_WAITQ_INSERT(kse, thread);
+ }
+ break;
+
+ case PS_SIGSUSPEND:
+ case PS_SUSPENDED:
+ if (THR_NEED_CANCEL(thread)) {
+ thread->interrupted = 1;
+ THR_SET_STATE(thread, PS_RUNNING);
+ } else {
+ /*
+ * These states don't timeout.
+ */
+ thread->wakeup_time.tv_sec = -1;
+ thread->wakeup_time.tv_nsec = -1;
+
+ /* Insert into the waiting queue: */
+ KSE_WAITQ_INSERT(kse, thread);
+ }
+ break;
+
+ case PS_DEAD:
+ /*
+ * The scheduler is operating on a different
+ * stack. It is safe to do garbage collecting
+ * here.
+ */
+ thread->active = 0;
+ thread->need_switchout = 0;
+ thread->lock_switch = 0;
+ thr_cleanup(kse, thread);
+ return;
+ break;
+
+ case PS_RUNNING:
+ if ((thread->flags & THR_FLAGS_SUSPENDED) != 0 &&
+ !THR_NEED_CANCEL(thread))
+ THR_SET_STATE(thread, PS_SUSPENDED);
+ break;
+
+ case PS_DEADLOCK:
+ /*
+ * These states don't timeout.
+ */
+ thread->wakeup_time.tv_sec = -1;
+ thread->wakeup_time.tv_nsec = -1;
+
+ /* Insert into the waiting queue: */
+ KSE_WAITQ_INSERT(kse, thread);
+ break;
+
+ default:
+ PANIC("Unknown state\n");
+ break;
+ }
+
+ thr_accounting(thread);
+ if (thread->state == PS_RUNNING) {
+ if (thread->slice_usec == -1) {
+ /*
+ * The thread exceeded its time quantum or
+ * it yielded the CPU; place it at the tail
+ * of the queue for its priority.
+ */
+ KSE_RUNQ_INSERT_TAIL(kse, thread);
+ } else {
+ /*
+ * The thread hasn't exceeded its interval
+ * Place it at the head of the queue for its
+ * priority.
+ */
+ KSE_RUNQ_INSERT_HEAD(kse, thread);
+ }
+ }
+ }
+ thread->active = 0;
+ thread->need_switchout = 0;
+ if (thread->check_pending != 0) {
+ /* Install pending signals into the frame. */
+ thread->check_pending = 0;
+ KSE_LOCK_ACQUIRE(kse, &_thread_signal_lock);
+ for (i = 1; i <= _SIG_MAXSIG; i++) {
+ if (SIGISMEMBER(thread->sigmask, i))
+ continue;
+ if (SIGISMEMBER(thread->sigpend, i))
+ (void)_thr_sig_add(thread, i,
+ &thread->siginfo[i-1]);
+ else if (SIGISMEMBER(_thr_proc_sigpending, i) &&
+ _thr_getprocsig_unlocked(i, &siginfo)) {
+ (void)_thr_sig_add(thread, i, &siginfo);
+ }
+ }
+ KSE_LOCK_RELEASE(kse, &_thread_signal_lock);
+ }
+}
+
+/*
+ * This function waits for the smallest timeout value of any waiting
+ * thread, or until it receives a message from another KSE.
+ *
+ * This must be called with the scheduling lock held.
+ */
+static void
+kse_wait(struct kse *kse, struct pthread *td_wait, int sigseqno)
+{
+ struct timespec ts, ts_sleep;
+ int saved_flags;
+
+ if ((td_wait == NULL) || (td_wait->wakeup_time.tv_sec < 0)) {
+ /* Limit sleep to no more than 1 minute. */
+ ts_sleep.tv_sec = 60;
+ ts_sleep.tv_nsec = 0;
+ } else {
+ KSE_GET_TOD(kse, &ts);
+ TIMESPEC_SUB(&ts_sleep, &td_wait->wakeup_time, &ts);
+ if (ts_sleep.tv_sec > 60) {
+ ts_sleep.tv_sec = 60;
+ ts_sleep.tv_nsec = 0;
+ }
+ }
+ /* Don't sleep for negative times. */
+ if ((ts_sleep.tv_sec >= 0) && (ts_sleep.tv_nsec >= 0)) {
+ KSE_SET_IDLE(kse);
+ kse->k_kseg->kg_idle_kses++;
+ KSE_SCHED_UNLOCK(kse, kse->k_kseg);
+ if ((kse->k_kseg->kg_flags & KGF_SINGLE_THREAD) &&
+ (kse->k_sigseqno != sigseqno))
+ ; /* don't sleep */
+ else {
+ saved_flags = kse->k_kcb->kcb_kmbx.km_flags;
+ kse->k_kcb->kcb_kmbx.km_flags |= KMF_NOUPCALL;
+ kse_release(&ts_sleep);
+ kse->k_kcb->kcb_kmbx.km_flags = saved_flags;
+ }
+ KSE_SCHED_LOCK(kse, kse->k_kseg);
+ if (KSE_IS_IDLE(kse)) {
+ KSE_CLEAR_IDLE(kse);
+ kse->k_kseg->kg_idle_kses--;
+ }
+ }
+}
+
+/*
+ * Avoid calling this kse_exit() so as not to confuse it with the
+ * system call of the same name.
+ */
+static void
+kse_fini(struct kse *kse)
+{
+ /* struct kse_group *free_kseg = NULL; */
+ struct timespec ts;
+ struct pthread *td;
+
+ /*
+ * Check to see if this is one of the main kses.
+ */
+ if (kse->k_kseg != _kse_initial->k_kseg) {
+ PANIC("shouldn't get here");
+ /* This is for supporting thread groups. */
+#ifdef NOT_YET
+ /* Remove this KSE from the KSEG's list of KSEs. */
+ KSE_SCHED_LOCK(kse, kse->k_kseg);
+ TAILQ_REMOVE(&kse->k_kseg->kg_kseq, kse, k_kgqe);
+ kse->k_kseg->kg_ksecount--;
+ if (TAILQ_EMPTY(&kse->k_kseg->kg_kseq))
+ free_kseg = kse->k_kseg;
+ KSE_SCHED_UNLOCK(kse, kse->k_kseg);
+
+ /*
+ * Add this KSE to the list of free KSEs along with
+ * the KSEG if is now orphaned.
+ */
+ KSE_LOCK_ACQUIRE(kse, &kse_lock);
+ if (free_kseg != NULL)
+ kseg_free_unlocked(free_kseg);
+ kse_free_unlocked(kse);
+ KSE_LOCK_RELEASE(kse, &kse_lock);
+ kse_exit();
+ /* Never returns. */
+ PANIC("kse_exit()");
+#endif
+ } else {
+ /*
+ * We allow program to kill kse in initial group (by
+ * lowering the concurrency).
+ */
+ if ((kse != _kse_initial) &&
+ ((kse->k_flags & KF_TERMINATED) != 0)) {
+ KSE_SCHED_LOCK(kse, kse->k_kseg);
+ TAILQ_REMOVE(&kse->k_kseg->kg_kseq, kse, k_kgqe);
+ kse->k_kseg->kg_ksecount--;
+ /*
+ * Migrate thread to _kse_initial if its lastest
+ * kse it ran on is the kse.
+ */
+ td = TAILQ_FIRST(&kse->k_kseg->kg_threadq);
+ while (td != NULL) {
+ if (td->kse == kse)
+ td->kse = _kse_initial;
+ td = TAILQ_NEXT(td, kle);
+ }
+ KSE_SCHED_UNLOCK(kse, kse->k_kseg);
+ KSE_LOCK_ACQUIRE(kse, &kse_lock);
+ kse_free_unlocked(kse);
+ KSE_LOCK_RELEASE(kse, &kse_lock);
+ /* Make sure there is always at least one is awake */
+ KSE_WAKEUP(_kse_initial);
+ kse_exit();
+ /* Never returns. */
+ PANIC("kse_exit() failed for initial kseg");
+ }
+ KSE_SCHED_LOCK(kse, kse->k_kseg);
+ KSE_SET_IDLE(kse);
+ kse->k_kseg->kg_idle_kses++;
+ KSE_SCHED_UNLOCK(kse, kse->k_kseg);
+ ts.tv_sec = 120;
+ ts.tv_nsec = 0;
+ kse->k_kcb->kcb_kmbx.km_flags = 0;
+ kse_release(&ts);
+ /* Never reach */
+ }
+}
+
+void
+_thr_set_timeout(const struct timespec *timeout)
+{
+ struct pthread *curthread = _get_curthread();
+ struct timespec ts;
+
+ /* Reset the timeout flag for the running thread: */
+ curthread->timeout = 0;
+
+ /* Check if the thread is to wait forever: */
+ if (timeout == NULL) {
+ /*
+ * Set the wakeup time to something that can be recognised as
+ * different to an actual time of day:
+ */
+ curthread->wakeup_time.tv_sec = -1;
+ curthread->wakeup_time.tv_nsec = -1;
+ }
+ /* Check if no waiting is required: */
+ else if ((timeout->tv_sec == 0) && (timeout->tv_nsec == 0)) {
+ /* Set the wake up time to 'immediately': */
+ curthread->wakeup_time.tv_sec = 0;
+ curthread->wakeup_time.tv_nsec = 0;
+ } else {
+ /* Calculate the time for the current thread to wakeup: */
+ KSE_GET_TOD(curthread->kse, &ts);
+ TIMESPEC_ADD(&curthread->wakeup_time, &ts, timeout);
+ }
+}
+
+void
+_thr_panic_exit(char *file, int line, char *msg)
+{
+ char buf[256];
+
+ snprintf(buf, sizeof(buf), "(%s:%d) %s\n", file, line, msg);
+ __sys_write(2, buf, strlen(buf));
+ abort();
+}
+
+void
+_thr_setrunnable(struct pthread *curthread, struct pthread *thread)
+{
+ kse_critical_t crit;
+ struct kse_mailbox *kmbx;
+
+ crit = _kse_critical_enter();
+ KSE_SCHED_LOCK(curthread->kse, thread->kseg);
+ kmbx = _thr_setrunnable_unlocked(thread);
+ KSE_SCHED_UNLOCK(curthread->kse, thread->kseg);
+ _kse_critical_leave(crit);
+ if ((kmbx != NULL) && (__isthreaded != 0))
+ kse_wakeup(kmbx);
+}
+
+struct kse_mailbox *
+_thr_setrunnable_unlocked(struct pthread *thread)
+{
+ struct kse_mailbox *kmbx = NULL;
+
+ if ((thread->kseg->kg_flags & KGF_SINGLE_THREAD) != 0) {
+ /* No silly queues for these threads. */
+ if ((thread->flags & THR_FLAGS_SUSPENDED) != 0)
+ THR_SET_STATE(thread, PS_SUSPENDED);
+ else {
+ THR_SET_STATE(thread, PS_RUNNING);
+ kmbx = kse_wakeup_one(thread);
+ }
+
+ } else if (thread->state != PS_RUNNING) {
+ if ((thread->flags & THR_FLAGS_IN_WAITQ) != 0)
+ KSE_WAITQ_REMOVE(thread->kse, thread);
+ if ((thread->flags & THR_FLAGS_SUSPENDED) != 0)
+ THR_SET_STATE(thread, PS_SUSPENDED);
+ else {
+ THR_SET_STATE(thread, PS_RUNNING);
+ if ((thread->blocked == 0) && (thread->active == 0) &&
+ (thread->flags & THR_FLAGS_IN_RUNQ) == 0)
+ THR_RUNQ_INSERT_TAIL(thread);
+ /*
+ * XXX - Threads are not yet assigned to specific
+ * KSEs; they are assigned to the KSEG. So
+ * the fact that a thread's KSE is waiting
+ * doesn't necessarily mean that it will be
+ * the KSE that runs the thread after the
+ * lock is granted. But we don't know if the
+ * other KSEs within the same KSEG are also
+ * in a waiting state or not so we err on the
+ * side of caution and wakeup the thread's
+ * last known KSE. We ensure that the
+ * threads KSE doesn't change while it's
+ * scheduling lock is held so it is safe to
+ * reference it (the KSE). If the KSE wakes
+ * up and doesn't find any more work it will
+ * again go back to waiting so no harm is
+ * done.
+ */
+ kmbx = kse_wakeup_one(thread);
+ }
+ }
+ return (kmbx);
+}
+
+static struct kse_mailbox *
+kse_wakeup_one(struct pthread *thread)
+{
+ struct kse *ke;
+
+ if (KSE_IS_IDLE(thread->kse)) {
+ KSE_CLEAR_IDLE(thread->kse);
+ thread->kseg->kg_idle_kses--;
+ return (&thread->kse->k_kcb->kcb_kmbx);
+ } else {
+ TAILQ_FOREACH(ke, &thread->kseg->kg_kseq, k_kgqe) {
+ if (KSE_IS_IDLE(ke)) {
+ KSE_CLEAR_IDLE(ke);
+ ke->k_kseg->kg_idle_kses--;
+ return (&ke->k_kcb->kcb_kmbx);
+ }
+ }
+ }
+ return (NULL);
+}
+
+static void
+kse_wakeup_multi(struct kse *curkse)
+{
+ struct kse *ke;
+ int tmp;
+
+ if ((tmp = KSE_RUNQ_THREADS(curkse)) && curkse->k_kseg->kg_idle_kses) {
+ TAILQ_FOREACH(ke, &curkse->k_kseg->kg_kseq, k_kgqe) {
+ if (KSE_IS_IDLE(ke)) {
+ KSE_CLEAR_IDLE(ke);
+ ke->k_kseg->kg_idle_kses--;
+ KSE_WAKEUP(ke);
+ if (--tmp == 0)
+ break;
+ }
+ }
+ }
+}
+
+/*
+ * Allocate a new KSEG.
+ *
+ * We allow the current thread to be NULL in the case that this
+ * is the first time a KSEG is being created (library initialization).
+ * In this case, we don't need to (and can't) take any locks.
+ */
+struct kse_group *
+_kseg_alloc(struct pthread *curthread)
+{
+ struct kse_group *kseg = NULL;
+ kse_critical_t crit;
+
+ if ((curthread != NULL) && (free_kseg_count > 0)) {
+ /* Use the kse lock for the kseg queue. */
+ crit = _kse_critical_enter();
+ KSE_LOCK_ACQUIRE(curthread->kse, &kse_lock);
+ if ((kseg = TAILQ_FIRST(&free_kse_groupq)) != NULL) {
+ TAILQ_REMOVE(&free_kse_groupq, kseg, kg_qe);
+ free_kseg_count--;
+ active_kseg_count++;
+ TAILQ_INSERT_TAIL(&active_kse_groupq, kseg, kg_qe);
+ }
+ KSE_LOCK_RELEASE(curthread->kse, &kse_lock);
+ _kse_critical_leave(crit);
+ if (kseg)
+ kseg_reinit(kseg);
+ }
+
+ /*
+ * If requested, attempt to allocate a new KSE group only if the
+ * KSE allocation was successful and a KSE group wasn't found in
+ * the free list.
+ */
+ if ((kseg == NULL) &&
+ ((kseg = (struct kse_group *)malloc(sizeof(*kseg))) != NULL)) {
+ if (_pq_alloc(&kseg->kg_schedq.sq_runq,
+ THR_MIN_PRIORITY, THR_LAST_PRIORITY) != 0) {
+ free(kseg);
+ kseg = NULL;
+ } else {
+ kseg_init(kseg);
+ /* Add the KSEG to the list of active KSEGs. */
+ if (curthread != NULL) {
+ crit = _kse_critical_enter();
+ KSE_LOCK_ACQUIRE(curthread->kse, &kse_lock);
+ active_kseg_count++;
+ TAILQ_INSERT_TAIL(&active_kse_groupq,
+ kseg, kg_qe);
+ KSE_LOCK_RELEASE(curthread->kse, &kse_lock);
+ _kse_critical_leave(crit);
+ } else {
+ active_kseg_count++;
+ TAILQ_INSERT_TAIL(&active_kse_groupq,
+ kseg, kg_qe);
+ }
+ }
+ }
+ return (kseg);
+}
+
+static void
+kseg_init(struct kse_group *kseg)
+{
+ kseg_reinit(kseg);
+ _lock_init(&kseg->kg_lock, LCK_ADAPTIVE, _kse_lock_wait,
+ _kse_lock_wakeup);
+}
+
+static void
+kseg_reinit(struct kse_group *kseg)
+{
+ TAILQ_INIT(&kseg->kg_kseq);
+ TAILQ_INIT(&kseg->kg_threadq);
+ TAILQ_INIT(&kseg->kg_schedq.sq_waitq);
+ kseg->kg_threadcount = 0;
+ kseg->kg_ksecount = 0;
+ kseg->kg_idle_kses = 0;
+ kseg->kg_flags = 0;
+}
+
+/*
+ * This must be called with the kse lock held and when there are
+ * no more threads that reference it.
+ */
+static void
+kseg_free_unlocked(struct kse_group *kseg)
+{
+ TAILQ_REMOVE(&active_kse_groupq, kseg, kg_qe);
+ TAILQ_INSERT_HEAD(&free_kse_groupq, kseg, kg_qe);
+ free_kseg_count++;
+ active_kseg_count--;
+}
+
+void
+_kseg_free(struct kse_group *kseg)
+{
+ struct kse *curkse;
+ kse_critical_t crit;
+
+ crit = _kse_critical_enter();
+ curkse = _get_curkse();
+ KSE_LOCK_ACQUIRE(curkse, &kse_lock);
+ kseg_free_unlocked(kseg);
+ KSE_LOCK_RELEASE(curkse, &kse_lock);
+ _kse_critical_leave(crit);
+}
+
+static void
+kseg_destroy(struct kse_group *kseg)
+{
+ _lock_destroy(&kseg->kg_lock);
+ _pq_free(&kseg->kg_schedq.sq_runq);
+ free(kseg);
+}
+
+/*
+ * Allocate a new KSE.
+ *
+ * We allow the current thread to be NULL in the case that this
+ * is the first time a KSE is being created (library initialization).
+ * In this case, we don't need to (and can't) take any locks.
+ */
+struct kse *
+_kse_alloc(struct pthread *curthread, int sys_scope)
+{
+ struct kse *kse = NULL;
+ char *stack;
+ kse_critical_t crit;
+ int i;
+
+ if ((curthread != NULL) && (free_kse_count > 0)) {
+ crit = _kse_critical_enter();
+ KSE_LOCK_ACQUIRE(curthread->kse, &kse_lock);
+ /* Search for a finished KSE. */
+ kse = TAILQ_FIRST(&free_kseq);
+ while ((kse != NULL) &&
+ ((kse->k_kcb->kcb_kmbx.km_flags & KMF_DONE) == 0)) {
+ kse = TAILQ_NEXT(kse, k_qe);
+ }
+ if (kse != NULL) {
+ DBG_MSG("found an unused kse.\n");
+ TAILQ_REMOVE(&free_kseq, kse, k_qe);
+ free_kse_count--;
+ TAILQ_INSERT_TAIL(&active_kseq, kse, k_qe);
+ active_kse_count++;
+ }
+ KSE_LOCK_RELEASE(curthread->kse, &kse_lock);
+ _kse_critical_leave(crit);
+ if (kse != NULL)
+ kse_reinit(kse, sys_scope);
+ }
+ if ((kse == NULL) &&
+ ((kse = (struct kse *)malloc(sizeof(*kse))) != NULL)) {
+ if (sys_scope != 0)
+ stack = NULL;
+ else if ((stack = malloc(KSE_STACKSIZE)) == NULL) {
+ free(kse);
+ return (NULL);
+ }
+ bzero(kse, sizeof(*kse));
+
+ /* Initialize KCB without the lock. */
+ if ((kse->k_kcb = _kcb_ctor(kse)) == NULL) {
+ if (stack != NULL)
+ free(stack);
+ free(kse);
+ return (NULL);
+ }
+
+ /* Initialize the lockusers. */
+ for (i = 0; i < MAX_KSE_LOCKLEVEL; i++) {
+ _lockuser_init(&kse->k_lockusers[i], (void *)kse);
+ _LCK_SET_PRIVATE2(&kse->k_lockusers[i], NULL);
+ }
+ /* _lock_init(kse->k_lock, ...) */
+
+ if (curthread != NULL) {
+ crit = _kse_critical_enter();
+ KSE_LOCK_ACQUIRE(curthread->kse, &kse_lock);
+ }
+ kse->k_flags = 0;
+ TAILQ_INSERT_TAIL(&active_kseq, kse, k_qe);
+ active_kse_count++;
+ if (curthread != NULL) {
+ KSE_LOCK_RELEASE(curthread->kse, &kse_lock);
+ _kse_critical_leave(crit);
+ }
+ /*
+ * Create the KSE context.
+ * Scope system threads (one thread per KSE) are not required
+ * to have a stack for an unneeded kse upcall.
+ */
+ if (!sys_scope) {
+ kse->k_kcb->kcb_kmbx.km_func = (kse_func_t *)kse_sched_multi;
+ kse->k_stack.ss_sp = stack;
+ kse->k_stack.ss_size = KSE_STACKSIZE;
+ } else {
+ kse->k_kcb->kcb_kmbx.km_func = (kse_func_t *)kse_sched_single;
+ kse->k_stack.ss_sp = NULL;
+ kse->k_stack.ss_size = 0;
+ }
+ kse->k_kcb->kcb_kmbx.km_udata = (void *)kse;
+ kse->k_kcb->kcb_kmbx.km_quantum = 20000;
+ /*
+ * We need to keep a copy of the stack in case it
+ * doesn't get used; a KSE running a scope system
+ * thread will use that thread's stack.
+ */
+ kse->k_kcb->kcb_kmbx.km_stack = kse->k_stack;
+ }
+ return (kse);
+}
+
+static void
+kse_reinit(struct kse *kse, int sys_scope)
+{
+ if (!sys_scope) {
+ kse->k_kcb->kcb_kmbx.km_func = (kse_func_t *)kse_sched_multi;
+ if (kse->k_stack.ss_sp == NULL) {
+ /* XXX check allocation failure */
+ kse->k_stack.ss_sp = (char *) malloc(KSE_STACKSIZE);
+ kse->k_stack.ss_size = KSE_STACKSIZE;
+ }
+ kse->k_kcb->kcb_kmbx.km_quantum = 20000;
+ } else {
+ kse->k_kcb->kcb_kmbx.km_func = (kse_func_t *)kse_sched_single;
+ if (kse->k_stack.ss_sp)
+ free(kse->k_stack.ss_sp);
+ kse->k_stack.ss_sp = NULL;
+ kse->k_stack.ss_size = 0;
+ kse->k_kcb->kcb_kmbx.km_quantum = 0;
+ }
+ kse->k_kcb->kcb_kmbx.km_stack = kse->k_stack;
+ kse->k_kcb->kcb_kmbx.km_udata = (void *)kse;
+ kse->k_kcb->kcb_kmbx.km_curthread = NULL;
+ kse->k_kcb->kcb_kmbx.km_flags = 0;
+ kse->k_curthread = NULL;
+ kse->k_kseg = 0;
+ kse->k_schedq = 0;
+ kse->k_locklevel = 0;
+ kse->k_flags = 0;
+ kse->k_error = 0;
+ kse->k_cpu = 0;
+ kse->k_sigseqno = 0;
+}
+
+void
+kse_free_unlocked(struct kse *kse)
+{
+ TAILQ_REMOVE(&active_kseq, kse, k_qe);
+ active_kse_count--;
+ kse->k_kseg = NULL;
+ kse->k_kcb->kcb_kmbx.km_quantum = 20000;
+ kse->k_flags = 0;
+ TAILQ_INSERT_HEAD(&free_kseq, kse, k_qe);
+ free_kse_count++;
+}
+
+void
+_kse_free(struct pthread *curthread, struct kse *kse)
+{
+ kse_critical_t crit;
+
+ if (curthread == NULL)
+ kse_free_unlocked(kse);
+ else {
+ crit = _kse_critical_enter();
+ KSE_LOCK_ACQUIRE(curthread->kse, &kse_lock);
+ kse_free_unlocked(kse);
+ KSE_LOCK_RELEASE(curthread->kse, &kse_lock);
+ _kse_critical_leave(crit);
+ }
+}
+
+static void
+kse_destroy(struct kse *kse)
+{
+ int i;
+
+ if (kse->k_stack.ss_sp != NULL)
+ free(kse->k_stack.ss_sp);
+ _kcb_dtor(kse->k_kcb);
+ for (i = 0; i < MAX_KSE_LOCKLEVEL; ++i)
+ _lockuser_destroy(&kse->k_lockusers[i]);
+ _lock_destroy(&kse->k_lock);
+ free(kse);
+}
+
+struct pthread *
+_thr_alloc(struct pthread *curthread)
+{
+ kse_critical_t crit;
+ struct pthread *thread = NULL;
+ int i;
+
+ if (curthread != NULL) {
+ if (GC_NEEDED())
+ _thr_gc(curthread);
+ if (free_thread_count > 0) {
+ crit = _kse_critical_enter();
+ KSE_LOCK_ACQUIRE(curthread->kse, &thread_lock);
+ if ((thread = TAILQ_FIRST(&free_threadq)) != NULL) {
+ TAILQ_REMOVE(&free_threadq, thread, tle);
+ free_thread_count--;
+ }
+ KSE_LOCK_RELEASE(curthread->kse, &thread_lock);
+ _kse_critical_leave(crit);
+ }
+ }
+ if ((thread == NULL) &&
+ ((thread = malloc(sizeof(struct pthread))) != NULL)) {
+ bzero(thread, sizeof(struct pthread));
+ thread->siginfo = calloc(_SIG_MAXSIG, sizeof(siginfo_t));
+ if (thread->siginfo == NULL) {
+ free(thread);
+ return (NULL);
+ }
+ if (curthread) {
+ _pthread_mutex_lock(&_tcb_mutex);
+ thread->tcb = _tcb_ctor(thread, 0 /* not initial tls */);
+ _pthread_mutex_unlock(&_tcb_mutex);
+ } else {
+ thread->tcb = _tcb_ctor(thread, 1 /* initial tls */);
+ }
+ if (thread->tcb == NULL) {
+ free(thread->siginfo);
+ free(thread);
+ return (NULL);
+ }
+ /*
+ * Initialize thread locking.
+ * Lock initializing needs malloc, so don't
+ * enter critical region before doing this!
+ */
+ if (_lock_init(&thread->lock, LCK_ADAPTIVE,
+ _thr_lock_wait, _thr_lock_wakeup) != 0)
+ PANIC("Cannot initialize thread lock");
+ for (i = 0; i < MAX_THR_LOCKLEVEL; i++) {
+ _lockuser_init(&thread->lockusers[i], (void *)thread);
+ _LCK_SET_PRIVATE2(&thread->lockusers[i],
+ (void *)thread);
+ }
+ }
+ return (thread);
+}
+
+void
+_thr_free(struct pthread *curthread, struct pthread *thread)
+{
+ kse_critical_t crit;
+
+ DBG_MSG("Freeing thread %p\n", thread);
+ if (thread->name) {
+ free(thread->name);
+ thread->name = NULL;
+ }
+ if ((curthread == NULL) || (free_thread_count >= MAX_CACHED_THREADS)) {
+ thr_destroy(curthread, thread);
+ } else {
+ /* Add the thread to the free thread list. */
+ crit = _kse_critical_enter();
+ KSE_LOCK_ACQUIRE(curthread->kse, &thread_lock);
+ TAILQ_INSERT_TAIL(&free_threadq, thread, tle);
+ free_thread_count++;
+ KSE_LOCK_RELEASE(curthread->kse, &thread_lock);
+ _kse_critical_leave(crit);
+ }
+}
+
+static void
+thr_destroy(struct pthread *curthread, struct pthread *thread)
+{
+ int i;
+
+ for (i = 0; i < MAX_THR_LOCKLEVEL; i++)
+ _lockuser_destroy(&thread->lockusers[i]);
+ _lock_destroy(&thread->lock);
+ if (curthread) {
+ _pthread_mutex_lock(&_tcb_mutex);
+ _tcb_dtor(thread->tcb);
+ _pthread_mutex_unlock(&_tcb_mutex);
+ } else {
+ _tcb_dtor(thread->tcb);
+ }
+ free(thread->siginfo);
+ free(thread);
+}
+
+/*
+ * Add an active thread:
+ *
+ * o Assign the thread a unique id (which GDB uses to track
+ * threads.
+ * o Add the thread to the list of all threads and increment
+ * number of active threads.
+ */
+static void
+thr_link(struct pthread *thread)
+{
+ kse_critical_t crit;
+ struct kse *curkse;
+
+ crit = _kse_critical_enter();
+ curkse = _get_curkse();
+ KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock);
+ /*
+ * Initialize the unique id (which GDB uses to track
+ * threads), add the thread to the list of all threads,
+ * and
+ */
+ thread->uniqueid = next_uniqueid++;
+ THR_LIST_ADD(thread);
+ _thread_active_threads++;
+ KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
+ _kse_critical_leave(crit);
+}
+
+/*
+ * Remove an active thread.
+ */
+static void
+thr_unlink(struct pthread *thread)
+{
+ kse_critical_t crit;
+ struct kse *curkse;
+
+ crit = _kse_critical_enter();
+ curkse = _get_curkse();
+ KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock);
+ THR_LIST_REMOVE(thread);
+ _thread_active_threads--;
+ KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
+ _kse_critical_leave(crit);
+}
+
+void
+_thr_hash_add(struct pthread *thread)
+{
+ struct thread_hash_head *head;
+
+ head = &thr_hashtable[THREAD_HASH(thread)];
+ LIST_INSERT_HEAD(head, thread, hle);
+}
+
+void
+_thr_hash_remove(struct pthread *thread)
+{
+ LIST_REMOVE(thread, hle);
+}
+
+struct pthread *
+_thr_hash_find(struct pthread *thread)
+{
+ struct pthread *td;
+ struct thread_hash_head *head;
+
+ head = &thr_hashtable[THREAD_HASH(thread)];
+ LIST_FOREACH(td, head, hle) {
+ if (td == thread)
+ return (thread);
+ }
+ return (NULL);
+}
+
+void
+_thr_debug_check_yield(struct pthread *curthread)
+{
+ /*
+ * Note that TMDF_SUSPEND is set after process is suspended.
+ * When we are being debugged, every suspension in process
+ * will cause all KSEs to schedule an upcall in kernel, unless the
+ * KSE is in critical region.
+ * If the function is being called, it means the KSE is no longer
+ * in critical region, if the TMDF_SUSPEND is set by debugger
+ * before KSE leaves critical region, we will catch it here, else
+ * if the flag is changed during testing, it also not a problem,
+ * because the change only occurs after a process suspension event
+ * occurs. A suspension event will always cause KSE to schedule an
+ * upcall, in the case, because we are not in critical region,
+ * upcall will be scheduled sucessfully, the flag will be checked
+ * again in kse_sched_multi, we won't back until the flag
+ * is cleared by debugger, the flag will be cleared in next
+ * suspension event.
+ */
+ if (!DBG_CAN_RUN(curthread)) {
+ if ((curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) == 0)
+ _thr_sched_switch(curthread);
+ else
+ kse_thr_interrupt(&curthread->tcb->tcb_tmbx,
+ KSE_INTR_DBSUSPEND, 0);
+ }
+}
diff --git a/lib/libkse/thread/thr_kill.c b/lib/libkse/thread/thr_kill.c
new file mode 100644
index 0000000..a03ec38
--- /dev/null
+++ b/lib/libkse/thread/thr_kill.c
@@ -0,0 +1,69 @@
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <signal.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_kill);
+LT10_COMPAT_DEFAULT(pthread_kill);
+
+__weak_reference(_pthread_kill, pthread_kill);
+
+int
+_pthread_kill(pthread_t pthread, int sig)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ /* Check for invalid signal numbers: */
+ if (sig < 0 || sig > _SIG_MAXSIG)
+ /* Invalid signal: */
+ ret = EINVAL;
+ /*
+ * Ensure the thread is in the list of active threads, and the
+ * signal is valid (signal 0 specifies error checking only) and
+ * not being ignored:
+ */
+ else if ((ret = _thr_ref_add(curthread, pthread, /*include dead*/0))
+ == 0) {
+ if ((sig > 0) &&
+ (_thread_sigact[sig - 1].sa_handler != SIG_IGN))
+ _thr_sig_send(pthread, sig);
+ _thr_ref_delete(curthread, pthread);
+ }
+
+ /* Return the completion status: */
+ return (ret);
+}
diff --git a/lib/libkse/thread/thr_main_np.c b/lib/libkse/thread/thr_main_np.c
new file mode 100644
index 0000000..50fb9c8
--- /dev/null
+++ b/lib/libkse/thread/thr_main_np.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2001 Alfred Perlstein
+ * Author: Alfred Perlstein <alfred@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 <pthread.h>
+#include <pthread_np.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_main_np);
+LT10_COMPAT_DEFAULT(pthread_main_np);
+
+__weak_reference(_pthread_main_np, pthread_main_np);
+
+/*
+ * Provide the equivelant to Solaris thr_main() function
+ */
+int
+_pthread_main_np()
+{
+
+ if (!_thr_initial)
+ return (-1);
+ else
+ return (pthread_equal(pthread_self(), _thr_initial) ? 1 : 0);
+}
diff --git a/lib/libkse/thread/thr_mattr_init.c b/lib/libkse/thread/thr_mattr_init.c
new file mode 100644
index 0000000..b273bab
--- /dev/null
+++ b/lib/libkse/thread/thr_mattr_init.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1996 Jeffrey Hsu <hsu@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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_mutexattr_init);
+LT10_COMPAT_DEFAULT(pthread_mutexattr_init);
+
+__weak_reference(_pthread_mutexattr_init, pthread_mutexattr_init);
+
+int
+_pthread_mutexattr_init(pthread_mutexattr_t *attr)
+{
+ int ret;
+ pthread_mutexattr_t pattr;
+
+ if ((pattr = (pthread_mutexattr_t)
+ malloc(sizeof(struct pthread_mutex_attr))) == NULL) {
+ ret = ENOMEM;
+ } else {
+ memcpy(pattr, &_pthread_mutexattr_default,
+ sizeof(struct pthread_mutex_attr));
+ *attr = pattr;
+ ret = 0;
+ }
+ return (ret);
+}
diff --git a/lib/libkse/thread/thr_mattr_kind_np.c b/lib/libkse/thread/thr_mattr_kind_np.c
new file mode 100644
index 0000000..12cd775
--- /dev/null
+++ b/lib/libkse/thread/thr_mattr_kind_np.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 1996 Jeffrey Hsu <hsu@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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_mutexattr_setkind_np);
+LT10_COMPAT_DEFAULT(pthread_mutexattr_setkind_np);
+LT10_COMPAT_PRIVATE(_pthread_mutexattr_getkind_np);
+LT10_COMPAT_DEFAULT(pthread_mutexattr_getkind_np);
+LT10_COMPAT_PRIVATE(_pthread_mutexattr_gettype);
+LT10_COMPAT_DEFAULT(pthread_mutexattr_gettype);
+LT10_COMPAT_PRIVATE(_pthread_mutexattr_settype);
+LT10_COMPAT_DEFAULT(pthread_mutexattr_settype);
+
+__weak_reference(_pthread_mutexattr_setkind_np, pthread_mutexattr_setkind_np);
+__weak_reference(_pthread_mutexattr_getkind_np, pthread_mutexattr_getkind_np);
+__weak_reference(_pthread_mutexattr_gettype, pthread_mutexattr_gettype);
+__weak_reference(_pthread_mutexattr_settype, pthread_mutexattr_settype);
+
+int
+_pthread_mutexattr_setkind_np(pthread_mutexattr_t *attr, int kind)
+{
+ int ret;
+ if (attr == NULL || *attr == NULL) {
+ errno = EINVAL;
+ ret = -1;
+ } else {
+ (*attr)->m_type = kind;
+ ret = 0;
+ }
+ return(ret);
+}
+
+int
+_pthread_mutexattr_getkind_np(pthread_mutexattr_t attr)
+{
+ int ret;
+ if (attr == NULL) {
+ errno = EINVAL;
+ ret = -1;
+ } else {
+ ret = attr->m_type;
+ }
+ return(ret);
+}
+
+int
+_pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
+{
+ int ret;
+ if (attr == NULL || *attr == NULL || type >= PTHREAD_MUTEX_TYPE_MAX) {
+ errno = EINVAL;
+ ret = -1;
+ } else {
+ (*attr)->m_type = type;
+ ret = 0;
+ }
+ return(ret);
+}
+
+int
+_pthread_mutexattr_gettype(pthread_mutexattr_t *attr, int *type)
+{
+ int ret;
+
+ if (attr == NULL || *attr == NULL || (*attr)->m_type >=
+ PTHREAD_MUTEX_TYPE_MAX) {
+ ret = EINVAL;
+ } else {
+ *type = (*attr)->m_type;
+ ret = 0;
+ }
+ return ret;
+}
diff --git a/lib/libkse/thread/thr_mattr_pshared.c b/lib/libkse/thread/thr_mattr_pshared.c
new file mode 100644
index 0000000..03aff41
--- /dev/null
+++ b/lib/libkse/thread/thr_mattr_pshared.c
@@ -0,0 +1,56 @@
+/*
+ * 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 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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, 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$
+ *
+ */
+
+#include <errno.h>
+#include "thr_private.h"
+
+__weak_reference(_pthread_mutexattr_getpshared, pthread_mutexattr_getpshared);
+__weak_reference(_pthread_mutexattr_setpshared, pthread_mutexattr_setpshared);
+
+int
+_pthread_mutexattr_getpshared(const pthread_mutexattr_t *attr,
+ int *pshared)
+{
+ if (attr == NULL || *attr == NULL)
+ return (EINVAL);
+
+ pshared = PTHREAD_PROCESS_PRIVATE;
+ return (0);
+}
+
+int
+_pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared)
+{
+ if (attr == NULL || *attr == NULL)
+ return (EINVAL);
+
+ if (pshared != PTHREAD_PROCESS_PRIVATE)
+ return (EINVAL);
+ return (0);
+}
diff --git a/lib/libkse/thread/thr_msync.c b/lib/libkse/thread/thr_msync.c
new file mode 100644
index 0000000..66e88c5
--- /dev/null
+++ b/lib/libkse/thread/thr_msync.c
@@ -0,0 +1,36 @@
+/*
+ * David Leonard <d@openbsd.org>, 1999. Public Domain.
+ *
+ * $OpenBSD: uthread_msync.c,v 1.2 1999/06/09 07:16:17 d Exp $
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__msync);
+LT10_COMPAT_DEFAULT(msync);
+
+__weak_reference(__msync, msync);
+
+int
+__msync(void *addr, size_t len, int flags)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ /*
+ * XXX This is quite pointless unless we know how to get the
+ * file descriptor associated with the memory, and lock it for
+ * write. The only real use of this wrapper is to guarantee
+ * a cancellation point, as per the standard. sigh.
+ */
+ _thr_cancel_enter(curthread);
+ ret = __sys_msync(addr, len, flags);
+ _thr_cancel_leave(curthread, 1);
+
+ return ret;
+}
diff --git a/lib/libkse/thread/thr_multi_np.c b/lib/libkse/thread/thr_multi_np.c
new file mode 100644
index 0000000..54ce22c
--- /dev/null
+++ b/lib/libkse/thread/thr_multi_np.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 1996 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <pthread_np.h>
+
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_multi_np);
+LT10_COMPAT_DEFAULT(pthread_multi_np);
+
+__weak_reference(_pthread_multi_np, pthread_multi_np);
+
+int
+_pthread_multi_np()
+{
+
+ /* Return to multi-threaded scheduling mode: */
+ /*
+ * XXX - Do we want to do this?
+ * __is_threaded = 1;
+ */
+ pthread_resume_all_np();
+ return (0);
+}
diff --git a/lib/libkse/thread/thr_mutex.c b/lib/libkse/thread/thr_mutex.c
new file mode 100644
index 0000000..6383cd8
--- /dev/null
+++ b/lib/libkse/thread/thr_mutex.c
@@ -0,0 +1,1832 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <errno.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+#if defined(_PTHREADS_INVARIANTS)
+#define MUTEX_INIT_LINK(m) do { \
+ (m)->m_qe.tqe_prev = NULL; \
+ (m)->m_qe.tqe_next = NULL; \
+} while (0)
+#define MUTEX_ASSERT_IS_OWNED(m) do { \
+ if ((m)->m_qe.tqe_prev == NULL) \
+ PANIC("mutex is not on list"); \
+} while (0)
+#define MUTEX_ASSERT_NOT_OWNED(m) do { \
+ if (((m)->m_qe.tqe_prev != NULL) || \
+ ((m)->m_qe.tqe_next != NULL)) \
+ PANIC("mutex is on list"); \
+} while (0)
+#define THR_ASSERT_NOT_IN_SYNCQ(thr) do { \
+ THR_ASSERT(((thr)->sflags & THR_FLAGS_IN_SYNCQ) == 0, \
+ "thread in syncq when it shouldn't be."); \
+} while (0);
+#else
+#define MUTEX_INIT_LINK(m)
+#define MUTEX_ASSERT_IS_OWNED(m)
+#define MUTEX_ASSERT_NOT_OWNED(m)
+#define THR_ASSERT_NOT_IN_SYNCQ(thr)
+#endif
+
+#define THR_IN_MUTEXQ(thr) (((thr)->sflags & THR_FLAGS_IN_SYNCQ) != 0)
+#define MUTEX_DESTROY(m) do { \
+ _lock_destroy(&(m)->m_lock); \
+ free(m); \
+} while (0)
+
+
+/*
+ * Prototypes
+ */
+static struct kse_mailbox *mutex_handoff(struct pthread *,
+ struct pthread_mutex *);
+static inline int mutex_self_trylock(struct pthread *, pthread_mutex_t);
+static inline int mutex_self_lock(struct pthread *, pthread_mutex_t);
+static int mutex_unlock_common(pthread_mutex_t *, int);
+static void mutex_priority_adjust(struct pthread *, pthread_mutex_t);
+static void mutex_rescan_owned (struct pthread *, struct pthread *,
+ struct pthread_mutex *);
+static inline pthread_t mutex_queue_deq(pthread_mutex_t);
+static inline void mutex_queue_remove(pthread_mutex_t, pthread_t);
+static inline void mutex_queue_enq(pthread_mutex_t, pthread_t);
+static void mutex_lock_backout(void *arg);
+
+static struct pthread_mutex_attr static_mutex_attr =
+ PTHREAD_MUTEXATTR_STATIC_INITIALIZER;
+static pthread_mutexattr_t static_mattr = &static_mutex_attr;
+
+LT10_COMPAT_PRIVATE(__pthread_mutex_init);
+LT10_COMPAT_PRIVATE(_pthread_mutex_init);
+LT10_COMPAT_DEFAULT(pthread_mutex_init);
+LT10_COMPAT_PRIVATE(__pthread_mutex_lock);
+LT10_COMPAT_PRIVATE(_pthread_mutex_lock);
+LT10_COMPAT_DEFAULT(pthread_mutex_lock);
+LT10_COMPAT_PRIVATE(__pthread_mutex_timedlock);
+LT10_COMPAT_PRIVATE(_pthread_mutex_timedlock);
+LT10_COMPAT_DEFAULT(pthread_mutex_timedlock);
+LT10_COMPAT_PRIVATE(__pthread_mutex_trylock);
+LT10_COMPAT_PRIVATE(_pthread_mutex_trylock);
+LT10_COMPAT_DEFAULT(pthread_mutex_trylock);
+LT10_COMPAT_PRIVATE(_pthread_mutex_destroy);
+LT10_COMPAT_DEFAULT(pthread_mutex_destroy);
+LT10_COMPAT_PRIVATE(_pthread_mutex_unlock);
+LT10_COMPAT_DEFAULT(pthread_mutex_unlock);
+
+/* Single underscore versions provided for libc internal usage: */
+__weak_reference(__pthread_mutex_init, pthread_mutex_init);
+__weak_reference(__pthread_mutex_lock, pthread_mutex_lock);
+__weak_reference(__pthread_mutex_timedlock, pthread_mutex_timedlock);
+__weak_reference(__pthread_mutex_trylock, pthread_mutex_trylock);
+
+/* No difference between libc and application usage of these: */
+__weak_reference(_pthread_mutex_destroy, pthread_mutex_destroy);
+__weak_reference(_pthread_mutex_unlock, pthread_mutex_unlock);
+
+
+
+int
+__pthread_mutex_init(pthread_mutex_t *mutex,
+ const pthread_mutexattr_t *mutex_attr)
+{
+ struct pthread_mutex *pmutex;
+ enum pthread_mutextype type;
+ int protocol;
+ int ceiling;
+ int flags;
+ int ret = 0;
+
+ if (mutex == NULL)
+ ret = EINVAL;
+
+ /* Check if default mutex attributes: */
+ else if (mutex_attr == NULL || *mutex_attr == NULL) {
+ /* Default to a (error checking) POSIX mutex: */
+ type = PTHREAD_MUTEX_ERRORCHECK;
+ protocol = PTHREAD_PRIO_NONE;
+ ceiling = THR_MAX_PRIORITY;
+ flags = 0;
+ }
+
+ /* Check mutex type: */
+ else if (((*mutex_attr)->m_type < PTHREAD_MUTEX_ERRORCHECK) ||
+ ((*mutex_attr)->m_type >= PTHREAD_MUTEX_TYPE_MAX))
+ /* Return an invalid argument error: */
+ ret = EINVAL;
+
+ /* Check mutex protocol: */
+ else if (((*mutex_attr)->m_protocol < PTHREAD_PRIO_NONE) ||
+ ((*mutex_attr)->m_protocol > PTHREAD_MUTEX_RECURSIVE))
+ /* Return an invalid argument error: */
+ ret = EINVAL;
+
+ else {
+ /* Use the requested mutex type and protocol: */
+ type = (*mutex_attr)->m_type;
+ protocol = (*mutex_attr)->m_protocol;
+ ceiling = (*mutex_attr)->m_ceiling;
+ flags = (*mutex_attr)->m_flags;
+ }
+
+ /* Check no errors so far: */
+ if (ret == 0) {
+ if ((pmutex = (pthread_mutex_t)
+ malloc(sizeof(struct pthread_mutex))) == NULL)
+ ret = ENOMEM;
+ else if (_lock_init(&pmutex->m_lock, LCK_ADAPTIVE,
+ _thr_lock_wait, _thr_lock_wakeup) != 0) {
+ free(pmutex);
+ *mutex = NULL;
+ ret = ENOMEM;
+ } else {
+ /* Set the mutex flags: */
+ pmutex->m_flags = flags;
+
+ /* Process according to mutex type: */
+ switch (type) {
+ /* case PTHREAD_MUTEX_DEFAULT: */
+ case PTHREAD_MUTEX_ERRORCHECK:
+ case PTHREAD_MUTEX_NORMAL:
+ /* Nothing to do here. */
+ break;
+
+ /* Single UNIX Spec 2 recursive mutex: */
+ case PTHREAD_MUTEX_RECURSIVE:
+ /* Reset the mutex count: */
+ pmutex->m_count = 0;
+ break;
+
+ /* Trap invalid mutex types: */
+ default:
+ /* Return an invalid argument error: */
+ ret = EINVAL;
+ break;
+ }
+ if (ret == 0) {
+ /* Initialise the rest of the mutex: */
+ TAILQ_INIT(&pmutex->m_queue);
+ pmutex->m_flags |= MUTEX_FLAGS_INITED;
+ pmutex->m_owner = NULL;
+ pmutex->m_type = type;
+ pmutex->m_protocol = protocol;
+ pmutex->m_refcount = 0;
+ if (protocol == PTHREAD_PRIO_PROTECT)
+ pmutex->m_prio = ceiling;
+ else
+ pmutex->m_prio = -1;
+ pmutex->m_saved_prio = 0;
+ MUTEX_INIT_LINK(pmutex);
+ *mutex = pmutex;
+ } else {
+ /* Free the mutex lock structure: */
+ MUTEX_DESTROY(pmutex);
+ *mutex = NULL;
+ }
+ }
+ }
+ /* Return the completion status: */
+ return (ret);
+}
+
+int
+_pthread_mutex_init(pthread_mutex_t *mutex,
+ const pthread_mutexattr_t *mutex_attr)
+{
+ struct pthread_mutex_attr mattr, *mattrp;
+
+ if ((mutex_attr == NULL) || (*mutex_attr == NULL))
+ return (__pthread_mutex_init(mutex, &static_mattr));
+ else {
+ mattr = **mutex_attr;
+ mattr.m_flags |= MUTEX_FLAGS_PRIVATE;
+ mattrp = &mattr;
+ return (__pthread_mutex_init(mutex, &mattrp));
+ }
+}
+
+void
+_thr_mutex_reinit(pthread_mutex_t *mutex)
+{
+ _lock_reinit(&(*mutex)->m_lock, LCK_ADAPTIVE,
+ _thr_lock_wait, _thr_lock_wakeup);
+ TAILQ_INIT(&(*mutex)->m_queue);
+ (*mutex)->m_owner = NULL;
+ (*mutex)->m_count = 0;
+ (*mutex)->m_refcount = 0;
+ (*mutex)->m_prio = 0;
+ (*mutex)->m_saved_prio = 0;
+}
+
+int
+_pthread_mutex_destroy(pthread_mutex_t *mutex)
+{
+ struct pthread *curthread = _get_curthread();
+ pthread_mutex_t m;
+ int ret = 0;
+
+ if (mutex == NULL || *mutex == NULL)
+ ret = EINVAL;
+ else {
+ /* Lock the mutex structure: */
+ THR_LOCK_ACQUIRE(curthread, &(*mutex)->m_lock);
+
+ /*
+ * Check to see if this mutex is in use:
+ */
+ if (((*mutex)->m_owner != NULL) ||
+ (!TAILQ_EMPTY(&(*mutex)->m_queue)) ||
+ ((*mutex)->m_refcount != 0)) {
+ ret = EBUSY;
+
+ /* Unlock the mutex structure: */
+ THR_LOCK_RELEASE(curthread, &(*mutex)->m_lock);
+ } else {
+ /*
+ * Save a pointer to the mutex so it can be free'd
+ * and set the caller's pointer to NULL:
+ */
+ m = *mutex;
+ *mutex = NULL;
+
+ /* Unlock the mutex structure: */
+ THR_LOCK_RELEASE(curthread, &m->m_lock);
+
+ /*
+ * Free the memory allocated for the mutex
+ * structure:
+ */
+ MUTEX_ASSERT_NOT_OWNED(m);
+ MUTEX_DESTROY(m);
+ }
+ }
+
+ /* Return the completion status: */
+ return (ret);
+}
+
+static int
+init_static(struct pthread *thread, pthread_mutex_t *mutex)
+{
+ int ret;
+
+ THR_LOCK_ACQUIRE(thread, &_mutex_static_lock);
+
+ if (*mutex == NULL)
+ ret = pthread_mutex_init(mutex, NULL);
+ else
+ ret = 0;
+
+ THR_LOCK_RELEASE(thread, &_mutex_static_lock);
+
+ return (ret);
+}
+
+static int
+init_static_private(struct pthread *thread, pthread_mutex_t *mutex)
+{
+ int ret;
+
+ THR_LOCK_ACQUIRE(thread, &_mutex_static_lock);
+
+ if (*mutex == NULL)
+ ret = pthread_mutex_init(mutex, &static_mattr);
+ else
+ ret = 0;
+
+ THR_LOCK_RELEASE(thread, &_mutex_static_lock);
+
+ return (ret);
+}
+
+static int
+mutex_trylock_common(struct pthread *curthread, pthread_mutex_t *mutex)
+{
+ int private;
+ int ret = 0;
+
+ THR_ASSERT((mutex != NULL) && (*mutex != NULL),
+ "Uninitialized mutex in pthread_mutex_trylock_basic");
+
+ /* Lock the mutex structure: */
+ THR_LOCK_ACQUIRE(curthread, &(*mutex)->m_lock);
+ private = (*mutex)->m_flags & MUTEX_FLAGS_PRIVATE;
+
+ /*
+ * If the mutex was statically allocated, properly
+ * initialize the tail queue.
+ */
+ if (((*mutex)->m_flags & MUTEX_FLAGS_INITED) == 0) {
+ TAILQ_INIT(&(*mutex)->m_queue);
+ MUTEX_INIT_LINK(*mutex);
+ (*mutex)->m_flags |= MUTEX_FLAGS_INITED;
+ }
+
+ /* Process according to mutex type: */
+ switch ((*mutex)->m_protocol) {
+ /* Default POSIX mutex: */
+ case PTHREAD_PRIO_NONE:
+ /* Check if this mutex is not locked: */
+ if ((*mutex)->m_owner == NULL) {
+ /* Lock the mutex for the running thread: */
+ (*mutex)->m_owner = curthread;
+
+ /* Add to the list of owned mutexes: */
+ MUTEX_ASSERT_NOT_OWNED(*mutex);
+ TAILQ_INSERT_TAIL(&curthread->mutexq,
+ (*mutex), m_qe);
+ } else if ((*mutex)->m_owner == curthread)
+ ret = mutex_self_trylock(curthread, *mutex);
+ else
+ /* Return a busy error: */
+ ret = EBUSY;
+ break;
+
+ /* POSIX priority inheritence mutex: */
+ case PTHREAD_PRIO_INHERIT:
+ /* Check if this mutex is not locked: */
+ if ((*mutex)->m_owner == NULL) {
+ /* Lock the mutex for the running thread: */
+ (*mutex)->m_owner = curthread;
+
+ THR_SCHED_LOCK(curthread, curthread);
+ /* Track number of priority mutexes owned: */
+ curthread->priority_mutex_count++;
+
+ /*
+ * The mutex takes on the attributes of the
+ * running thread when there are no waiters.
+ */
+ (*mutex)->m_prio = curthread->active_priority;
+ (*mutex)->m_saved_prio =
+ curthread->inherited_priority;
+ curthread->inherited_priority = (*mutex)->m_prio;
+ THR_SCHED_UNLOCK(curthread, curthread);
+
+ /* Add to the list of owned mutexes: */
+ MUTEX_ASSERT_NOT_OWNED(*mutex);
+ TAILQ_INSERT_TAIL(&curthread->mutexq,
+ (*mutex), m_qe);
+ } else if ((*mutex)->m_owner == curthread)
+ ret = mutex_self_trylock(curthread, *mutex);
+ else
+ /* Return a busy error: */
+ ret = EBUSY;
+ break;
+
+ /* POSIX priority protection mutex: */
+ case PTHREAD_PRIO_PROTECT:
+ /* Check for a priority ceiling violation: */
+ if (curthread->active_priority > (*mutex)->m_prio)
+ ret = EINVAL;
+
+ /* Check if this mutex is not locked: */
+ else if ((*mutex)->m_owner == NULL) {
+ /* Lock the mutex for the running thread: */
+ (*mutex)->m_owner = curthread;
+
+ THR_SCHED_LOCK(curthread, curthread);
+ /* Track number of priority mutexes owned: */
+ curthread->priority_mutex_count++;
+
+ /*
+ * The running thread inherits the ceiling
+ * priority of the mutex and executes at that
+ * priority.
+ */
+ curthread->active_priority = (*mutex)->m_prio;
+ (*mutex)->m_saved_prio =
+ curthread->inherited_priority;
+ curthread->inherited_priority =
+ (*mutex)->m_prio;
+ THR_SCHED_UNLOCK(curthread, curthread);
+ /* Add to the list of owned mutexes: */
+ MUTEX_ASSERT_NOT_OWNED(*mutex);
+ TAILQ_INSERT_TAIL(&curthread->mutexq,
+ (*mutex), m_qe);
+ } else if ((*mutex)->m_owner == curthread)
+ ret = mutex_self_trylock(curthread, *mutex);
+ else
+ /* Return a busy error: */
+ ret = EBUSY;
+ break;
+
+ /* Trap invalid mutex types: */
+ default:
+ /* Return an invalid argument error: */
+ ret = EINVAL;
+ break;
+ }
+
+ if (ret == 0 && private)
+ THR_CRITICAL_ENTER(curthread);
+
+ /* Unlock the mutex structure: */
+ THR_LOCK_RELEASE(curthread, &(*mutex)->m_lock);
+
+ /* Return the completion status: */
+ return (ret);
+}
+
+int
+__pthread_mutex_trylock(pthread_mutex_t *mutex)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret = 0;
+
+ if (mutex == NULL)
+ ret = EINVAL;
+
+ /*
+ * If the mutex is statically initialized, perform the dynamic
+ * initialization:
+ */
+ else if ((*mutex != NULL) ||
+ ((ret = init_static(curthread, mutex)) == 0))
+ ret = mutex_trylock_common(curthread, mutex);
+
+ return (ret);
+}
+
+int
+_pthread_mutex_trylock(pthread_mutex_t *mutex)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret = 0;
+
+ if (mutex == NULL)
+ ret = EINVAL;
+
+ /*
+ * If the mutex is statically initialized, perform the dynamic
+ * initialization marking the mutex private (delete safe):
+ */
+ else if ((*mutex != NULL) ||
+ ((ret = init_static_private(curthread, mutex)) == 0))
+ ret = mutex_trylock_common(curthread, mutex);
+
+ return (ret);
+}
+
+static int
+mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m,
+ const struct timespec * abstime)
+{
+ int private;
+ int ret = 0;
+
+ THR_ASSERT((m != NULL) && (*m != NULL),
+ "Uninitialized mutex in pthread_mutex_trylock_basic");
+
+ if (abstime != NULL && (abstime->tv_sec < 0 || abstime->tv_nsec < 0 ||
+ abstime->tv_nsec >= 1000000000))
+ return (EINVAL);
+
+ /* Reset the interrupted flag: */
+ curthread->interrupted = 0;
+ curthread->timeout = 0;
+ curthread->wakeup_time.tv_sec = -1;
+
+ private = (*m)->m_flags & MUTEX_FLAGS_PRIVATE;
+
+ /*
+ * Enter a loop waiting to become the mutex owner. We need a
+ * loop in case the waiting thread is interrupted by a signal
+ * to execute a signal handler. It is not (currently) possible
+ * to remain in the waiting queue while running a handler.
+ * Instead, the thread is interrupted and backed out of the
+ * waiting queue prior to executing the signal handler.
+ */
+ do {
+ /* Lock the mutex structure: */
+ THR_LOCK_ACQUIRE(curthread, &(*m)->m_lock);
+
+ /*
+ * If the mutex was statically allocated, properly
+ * initialize the tail queue.
+ */
+ if (((*m)->m_flags & MUTEX_FLAGS_INITED) == 0) {
+ TAILQ_INIT(&(*m)->m_queue);
+ (*m)->m_flags |= MUTEX_FLAGS_INITED;
+ MUTEX_INIT_LINK(*m);
+ }
+
+ /* Process according to mutex type: */
+ switch ((*m)->m_protocol) {
+ /* Default POSIX mutex: */
+ case PTHREAD_PRIO_NONE:
+ if ((*m)->m_owner == NULL) {
+ /* Lock the mutex for this thread: */
+ (*m)->m_owner = curthread;
+
+ /* Add to the list of owned mutexes: */
+ MUTEX_ASSERT_NOT_OWNED(*m);
+ TAILQ_INSERT_TAIL(&curthread->mutexq,
+ (*m), m_qe);
+ if (private)
+ THR_CRITICAL_ENTER(curthread);
+
+ /* Unlock the mutex structure: */
+ THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+ } else if ((*m)->m_owner == curthread) {
+ ret = mutex_self_lock(curthread, *m);
+
+ /* Unlock the mutex structure: */
+ THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+ } else {
+ /*
+ * Join the queue of threads waiting to lock
+ * the mutex and save a pointer to the mutex.
+ */
+ mutex_queue_enq(*m, curthread);
+ curthread->data.mutex = *m;
+ curthread->sigbackout = mutex_lock_backout;
+ /*
+ * This thread is active and is in a critical
+ * region (holding the mutex lock); we should
+ * be able to safely set the state.
+ */
+ THR_SCHED_LOCK(curthread, curthread);
+ /* Set the wakeup time: */
+ if (abstime) {
+ curthread->wakeup_time.tv_sec =
+ abstime->tv_sec;
+ curthread->wakeup_time.tv_nsec =
+ abstime->tv_nsec;
+ }
+
+ THR_SET_STATE(curthread, PS_MUTEX_WAIT);
+ THR_SCHED_UNLOCK(curthread, curthread);
+
+ /* Unlock the mutex structure: */
+ THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+
+ /* Schedule the next thread: */
+ _thr_sched_switch(curthread);
+
+ if (THR_IN_MUTEXQ(curthread)) {
+ THR_LOCK_ACQUIRE(curthread, &(*m)->m_lock);
+ mutex_queue_remove(*m, curthread);
+ THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+ }
+ /*
+ * Only clear these after assuring the
+ * thread is dequeued.
+ */
+ curthread->data.mutex = NULL;
+ curthread->sigbackout = NULL;
+ }
+ break;
+
+ /* POSIX priority inheritence mutex: */
+ case PTHREAD_PRIO_INHERIT:
+ /* Check if this mutex is not locked: */
+ if ((*m)->m_owner == NULL) {
+ /* Lock the mutex for this thread: */
+ (*m)->m_owner = curthread;
+
+ THR_SCHED_LOCK(curthread, curthread);
+ /* Track number of priority mutexes owned: */
+ curthread->priority_mutex_count++;
+
+ /*
+ * The mutex takes on attributes of the
+ * running thread when there are no waiters.
+ * Make sure the thread's scheduling lock is
+ * held while priorities are adjusted.
+ */
+ (*m)->m_prio = curthread->active_priority;
+ (*m)->m_saved_prio =
+ curthread->inherited_priority;
+ curthread->inherited_priority = (*m)->m_prio;
+ THR_SCHED_UNLOCK(curthread, curthread);
+
+ /* Add to the list of owned mutexes: */
+ MUTEX_ASSERT_NOT_OWNED(*m);
+ TAILQ_INSERT_TAIL(&curthread->mutexq,
+ (*m), m_qe);
+ if (private)
+ THR_CRITICAL_ENTER(curthread);
+
+ /* Unlock the mutex structure: */
+ THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+ } else if ((*m)->m_owner == curthread) {
+ ret = mutex_self_lock(curthread, *m);
+
+ /* Unlock the mutex structure: */
+ THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+ } else {
+ /*
+ * Join the queue of threads waiting to lock
+ * the mutex and save a pointer to the mutex.
+ */
+ mutex_queue_enq(*m, curthread);
+ curthread->data.mutex = *m;
+ curthread->sigbackout = mutex_lock_backout;
+
+ /*
+ * This thread is active and is in a critical
+ * region (holding the mutex lock); we should
+ * be able to safely set the state.
+ */
+ if (curthread->active_priority > (*m)->m_prio)
+ /* Adjust priorities: */
+ mutex_priority_adjust(curthread, *m);
+
+ THR_SCHED_LOCK(curthread, curthread);
+ /* Set the wakeup time: */
+ if (abstime) {
+ curthread->wakeup_time.tv_sec =
+ abstime->tv_sec;
+ curthread->wakeup_time.tv_nsec =
+ abstime->tv_nsec;
+ }
+ THR_SET_STATE(curthread, PS_MUTEX_WAIT);
+ THR_SCHED_UNLOCK(curthread, curthread);
+
+ /* Unlock the mutex structure: */
+ THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+
+ /* Schedule the next thread: */
+ _thr_sched_switch(curthread);
+
+ if (THR_IN_MUTEXQ(curthread)) {
+ THR_LOCK_ACQUIRE(curthread, &(*m)->m_lock);
+ mutex_queue_remove(*m, curthread);
+ THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+ }
+ /*
+ * Only clear these after assuring the
+ * thread is dequeued.
+ */
+ curthread->data.mutex = NULL;
+ curthread->sigbackout = NULL;
+ }
+ break;
+
+ /* POSIX priority protection mutex: */
+ case PTHREAD_PRIO_PROTECT:
+ /* Check for a priority ceiling violation: */
+ if (curthread->active_priority > (*m)->m_prio) {
+ /* Unlock the mutex structure: */
+ THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+ ret = EINVAL;
+ }
+ /* Check if this mutex is not locked: */
+ else if ((*m)->m_owner == NULL) {
+ /*
+ * Lock the mutex for the running
+ * thread:
+ */
+ (*m)->m_owner = curthread;
+
+ THR_SCHED_LOCK(curthread, curthread);
+ /* Track number of priority mutexes owned: */
+ curthread->priority_mutex_count++;
+
+ /*
+ * The running thread inherits the ceiling
+ * priority of the mutex and executes at that
+ * priority. Make sure the thread's
+ * scheduling lock is held while priorities
+ * are adjusted.
+ */
+ curthread->active_priority = (*m)->m_prio;
+ (*m)->m_saved_prio =
+ curthread->inherited_priority;
+ curthread->inherited_priority = (*m)->m_prio;
+ THR_SCHED_UNLOCK(curthread, curthread);
+
+ /* Add to the list of owned mutexes: */
+ MUTEX_ASSERT_NOT_OWNED(*m);
+ TAILQ_INSERT_TAIL(&curthread->mutexq,
+ (*m), m_qe);
+ if (private)
+ THR_CRITICAL_ENTER(curthread);
+
+ /* Unlock the mutex structure: */
+ THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+ } else if ((*m)->m_owner == curthread) {
+ ret = mutex_self_lock(curthread, *m);
+
+ /* Unlock the mutex structure: */
+ THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+ } else {
+ /*
+ * Join the queue of threads waiting to lock
+ * the mutex and save a pointer to the mutex.
+ */
+ mutex_queue_enq(*m, curthread);
+ curthread->data.mutex = *m;
+ curthread->sigbackout = mutex_lock_backout;
+
+ /* Clear any previous error: */
+ curthread->error = 0;
+
+ /*
+ * This thread is active and is in a critical
+ * region (holding the mutex lock); we should
+ * be able to safely set the state.
+ */
+
+ THR_SCHED_LOCK(curthread, curthread);
+ /* Set the wakeup time: */
+ if (abstime) {
+ curthread->wakeup_time.tv_sec =
+ abstime->tv_sec;
+ curthread->wakeup_time.tv_nsec =
+ abstime->tv_nsec;
+ }
+ THR_SET_STATE(curthread, PS_MUTEX_WAIT);
+ THR_SCHED_UNLOCK(curthread, curthread);
+
+ /* Unlock the mutex structure: */
+ THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+
+ /* Schedule the next thread: */
+ _thr_sched_switch(curthread);
+
+ if (THR_IN_MUTEXQ(curthread)) {
+ THR_LOCK_ACQUIRE(curthread, &(*m)->m_lock);
+ mutex_queue_remove(*m, curthread);
+ THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+ }
+ /*
+ * Only clear these after assuring the
+ * thread is dequeued.
+ */
+ curthread->data.mutex = NULL;
+ curthread->sigbackout = NULL;
+
+ /*
+ * The threads priority may have changed while
+ * waiting for the mutex causing a ceiling
+ * violation.
+ */
+ ret = curthread->error;
+ curthread->error = 0;
+ }
+ break;
+
+ /* Trap invalid mutex types: */
+ default:
+ /* Unlock the mutex structure: */
+ THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+
+ /* Return an invalid argument error: */
+ ret = EINVAL;
+ break;
+ }
+
+ } while (((*m)->m_owner != curthread) && (ret == 0) &&
+ (curthread->interrupted == 0) && (curthread->timeout == 0));
+
+ if (ret == 0 && (*m)->m_owner != curthread && curthread->timeout)
+ ret = ETIMEDOUT;
+
+ /*
+ * Check to see if this thread was interrupted and
+ * is still in the mutex queue of waiting threads:
+ */
+ if (curthread->interrupted != 0) {
+ /* Remove this thread from the mutex queue. */
+ THR_LOCK_ACQUIRE(curthread, &(*m)->m_lock);
+ if (THR_IN_SYNCQ(curthread))
+ mutex_queue_remove(*m, curthread);
+ THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+
+ /* Check for asynchronous cancellation. */
+ if (curthread->continuation != NULL)
+ curthread->continuation((void *) curthread);
+ }
+
+ /* Return the completion status: */
+ return (ret);
+}
+
+int
+__pthread_mutex_lock(pthread_mutex_t *m)
+{
+ struct pthread *curthread;
+ int ret = 0;
+
+ if (_thr_initial == NULL)
+ _libpthread_init(NULL);
+
+ curthread = _get_curthread();
+ if (m == NULL)
+ ret = EINVAL;
+
+ /*
+ * If the mutex is statically initialized, perform the dynamic
+ * initialization:
+ */
+ else if ((*m != NULL) || ((ret = init_static(curthread, m)) == 0))
+ ret = mutex_lock_common(curthread, m, NULL);
+
+ return (ret);
+}
+
+__strong_reference(__pthread_mutex_lock, _thr_mutex_lock);
+
+int
+_pthread_mutex_lock(pthread_mutex_t *m)
+{
+ struct pthread *curthread;
+ int ret = 0;
+
+ if (_thr_initial == NULL)
+ _libpthread_init(NULL);
+ curthread = _get_curthread();
+
+ if (m == NULL)
+ ret = EINVAL;
+
+ /*
+ * If the mutex is statically initialized, perform the dynamic
+ * initialization marking it private (delete safe):
+ */
+ else if ((*m != NULL) ||
+ ((ret = init_static_private(curthread, m)) == 0))
+ ret = mutex_lock_common(curthread, m, NULL);
+
+ return (ret);
+}
+
+int
+__pthread_mutex_timedlock(pthread_mutex_t *m,
+ const struct timespec *abs_timeout)
+{
+ struct pthread *curthread;
+ int ret = 0;
+
+ if (_thr_initial == NULL)
+ _libpthread_init(NULL);
+
+ curthread = _get_curthread();
+ if (m == NULL)
+ ret = EINVAL;
+
+ /*
+ * If the mutex is statically initialized, perform the dynamic
+ * initialization:
+ */
+ else if ((*m != NULL) || ((ret = init_static(curthread, m)) == 0))
+ ret = mutex_lock_common(curthread, m, abs_timeout);
+
+ return (ret);
+}
+
+int
+_pthread_mutex_timedlock(pthread_mutex_t *m,
+ const struct timespec *abs_timeout)
+{
+ struct pthread *curthread;
+ int ret = 0;
+
+ if (_thr_initial == NULL)
+ _libpthread_init(NULL);
+ curthread = _get_curthread();
+
+ if (m == NULL)
+ ret = EINVAL;
+
+ /*
+ * If the mutex is statically initialized, perform the dynamic
+ * initialization marking it private (delete safe):
+ */
+ else if ((*m != NULL) ||
+ ((ret = init_static_private(curthread, m)) == 0))
+ ret = mutex_lock_common(curthread, m, abs_timeout);
+
+ return (ret);
+}
+
+int
+_pthread_mutex_unlock(pthread_mutex_t *m)
+{
+ return (mutex_unlock_common(m, /* add reference */ 0));
+}
+
+__strong_reference(_pthread_mutex_unlock, _thr_mutex_unlock);
+
+int
+_mutex_cv_unlock(pthread_mutex_t *m)
+{
+ return (mutex_unlock_common(m, /* add reference */ 1));
+}
+
+int
+_mutex_cv_lock(pthread_mutex_t *m)
+{
+ struct pthread *curthread;
+ int ret;
+
+ curthread = _get_curthread();
+ if ((ret = _pthread_mutex_lock(m)) == 0) {
+ THR_LOCK_ACQUIRE(curthread, &(*m)->m_lock);
+ (*m)->m_refcount--;
+ THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+ }
+ return (ret);
+}
+
+static inline int
+mutex_self_trylock(struct pthread *curthread, pthread_mutex_t m)
+{
+ int ret = 0;
+
+ switch (m->m_type) {
+ /* case PTHREAD_MUTEX_DEFAULT: */
+ case PTHREAD_MUTEX_ERRORCHECK:
+ case PTHREAD_MUTEX_NORMAL:
+ ret = EBUSY;
+ break;
+
+ case PTHREAD_MUTEX_RECURSIVE:
+ /* Increment the lock count: */
+ m->m_count++;
+ break;
+
+ default:
+ /* Trap invalid mutex types; */
+ ret = EINVAL;
+ }
+
+ return (ret);
+}
+
+static inline int
+mutex_self_lock(struct pthread *curthread, pthread_mutex_t m)
+{
+ int ret = 0;
+
+ /*
+ * Don't allow evil recursive mutexes for private use
+ * in libc and libpthread.
+ */
+ if (m->m_flags & MUTEX_FLAGS_PRIVATE)
+ PANIC("Recurse on a private mutex.");
+
+ switch (m->m_type) {
+ /* case PTHREAD_MUTEX_DEFAULT: */
+ case PTHREAD_MUTEX_ERRORCHECK:
+ /*
+ * POSIX specifies that mutexes should return EDEADLK if a
+ * recursive lock is detected.
+ */
+ ret = EDEADLK;
+ break;
+
+ case PTHREAD_MUTEX_NORMAL:
+ /*
+ * What SS2 define as a 'normal' mutex. Intentionally
+ * deadlock on attempts to get a lock you already own.
+ */
+
+ THR_SCHED_LOCK(curthread, curthread);
+ THR_SET_STATE(curthread, PS_DEADLOCK);
+ THR_SCHED_UNLOCK(curthread, curthread);
+
+ /* Unlock the mutex structure: */
+ THR_LOCK_RELEASE(curthread, &m->m_lock);
+
+ /* Schedule the next thread: */
+ _thr_sched_switch(curthread);
+ break;
+
+ case PTHREAD_MUTEX_RECURSIVE:
+ /* Increment the lock count: */
+ m->m_count++;
+ break;
+
+ default:
+ /* Trap invalid mutex types; */
+ ret = EINVAL;
+ }
+
+ return (ret);
+}
+
+static int
+mutex_unlock_common(pthread_mutex_t *m, int add_reference)
+{
+ struct pthread *curthread = _get_curthread();
+ struct kse_mailbox *kmbx = NULL;
+ int ret = 0;
+
+ if (m == NULL || *m == NULL)
+ ret = EINVAL;
+ else {
+ /* Lock the mutex structure: */
+ THR_LOCK_ACQUIRE(curthread, &(*m)->m_lock);
+
+ /* Process according to mutex type: */
+ switch ((*m)->m_protocol) {
+ /* Default POSIX mutex: */
+ case PTHREAD_PRIO_NONE:
+ /*
+ * Check if the running thread is not the owner of the
+ * mutex:
+ */
+ if ((*m)->m_owner != curthread)
+ ret = EPERM;
+ else if (((*m)->m_type == PTHREAD_MUTEX_RECURSIVE) &&
+ ((*m)->m_count > 0))
+ /* Decrement the count: */
+ (*m)->m_count--;
+ else {
+ /*
+ * Clear the count in case this is a recursive
+ * mutex.
+ */
+ (*m)->m_count = 0;
+
+ /* Remove the mutex from the threads queue. */
+ MUTEX_ASSERT_IS_OWNED(*m);
+ TAILQ_REMOVE(&(*m)->m_owner->mutexq,
+ (*m), m_qe);
+ MUTEX_INIT_LINK(*m);
+
+ /*
+ * Hand off the mutex to the next waiting
+ * thread:
+ */
+ kmbx = mutex_handoff(curthread, *m);
+ }
+ break;
+
+ /* POSIX priority inheritence mutex: */
+ case PTHREAD_PRIO_INHERIT:
+ /*
+ * Check if the running thread is not the owner of the
+ * mutex:
+ */
+ if ((*m)->m_owner != curthread)
+ ret = EPERM;
+ else if (((*m)->m_type == PTHREAD_MUTEX_RECURSIVE) &&
+ ((*m)->m_count > 0))
+ /* Decrement the count: */
+ (*m)->m_count--;
+ else {
+ /*
+ * Clear the count in case this is recursive
+ * mutex.
+ */
+ (*m)->m_count = 0;
+
+ /*
+ * Restore the threads inherited priority and
+ * recompute the active priority (being careful
+ * not to override changes in the threads base
+ * priority subsequent to locking the mutex).
+ */
+ THR_SCHED_LOCK(curthread, curthread);
+ curthread->inherited_priority =
+ (*m)->m_saved_prio;
+ curthread->active_priority =
+ MAX(curthread->inherited_priority,
+ curthread->base_priority);
+
+ /*
+ * This thread now owns one less priority mutex.
+ */
+ curthread->priority_mutex_count--;
+ THR_SCHED_UNLOCK(curthread, curthread);
+
+ /* Remove the mutex from the threads queue. */
+ MUTEX_ASSERT_IS_OWNED(*m);
+ TAILQ_REMOVE(&(*m)->m_owner->mutexq,
+ (*m), m_qe);
+ MUTEX_INIT_LINK(*m);
+
+ /*
+ * Hand off the mutex to the next waiting
+ * thread:
+ */
+ kmbx = mutex_handoff(curthread, *m);
+ }
+ break;
+
+ /* POSIX priority ceiling mutex: */
+ case PTHREAD_PRIO_PROTECT:
+ /*
+ * Check if the running thread is not the owner of the
+ * mutex:
+ */
+ if ((*m)->m_owner != curthread)
+ ret = EPERM;
+ else if (((*m)->m_type == PTHREAD_MUTEX_RECURSIVE) &&
+ ((*m)->m_count > 0))
+ /* Decrement the count: */
+ (*m)->m_count--;
+ else {
+ /*
+ * Clear the count in case this is a recursive
+ * mutex.
+ */
+ (*m)->m_count = 0;
+
+ /*
+ * Restore the threads inherited priority and
+ * recompute the active priority (being careful
+ * not to override changes in the threads base
+ * priority subsequent to locking the mutex).
+ */
+ THR_SCHED_LOCK(curthread, curthread);
+ curthread->inherited_priority =
+ (*m)->m_saved_prio;
+ curthread->active_priority =
+ MAX(curthread->inherited_priority,
+ curthread->base_priority);
+
+ /*
+ * This thread now owns one less priority mutex.
+ */
+ curthread->priority_mutex_count--;
+ THR_SCHED_UNLOCK(curthread, curthread);
+
+ /* Remove the mutex from the threads queue. */
+ MUTEX_ASSERT_IS_OWNED(*m);
+ TAILQ_REMOVE(&(*m)->m_owner->mutexq,
+ (*m), m_qe);
+ MUTEX_INIT_LINK(*m);
+
+ /*
+ * Hand off the mutex to the next waiting
+ * thread:
+ */
+ kmbx = mutex_handoff(curthread, *m);
+ }
+ break;
+
+ /* Trap invalid mutex types: */
+ default:
+ /* Return an invalid argument error: */
+ ret = EINVAL;
+ break;
+ }
+
+ if ((ret == 0) && (add_reference != 0))
+ /* Increment the reference count: */
+ (*m)->m_refcount++;
+
+ /* Leave the critical region if this is a private mutex. */
+ if ((ret == 0) && ((*m)->m_flags & MUTEX_FLAGS_PRIVATE))
+ THR_CRITICAL_LEAVE(curthread);
+
+ /* Unlock the mutex structure: */
+ THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+
+ if (kmbx != NULL)
+ kse_wakeup(kmbx);
+ }
+
+ /* Return the completion status: */
+ return (ret);
+}
+
+
+/*
+ * This function is called when a change in base priority occurs for
+ * a thread that is holding or waiting for a priority protection or
+ * inheritence mutex. A change in a threads base priority can effect
+ * changes to active priorities of other threads and to the ordering
+ * of mutex locking by waiting threads.
+ *
+ * This must be called without the target thread's scheduling lock held.
+ */
+void
+_mutex_notify_priochange(struct pthread *curthread, struct pthread *pthread,
+ int propagate_prio)
+{
+ struct pthread_mutex *m;
+
+ /* Adjust the priorites of any owned priority mutexes: */
+ if (pthread->priority_mutex_count > 0) {
+ /*
+ * Rescan the mutexes owned by this thread and correct
+ * their priorities to account for this threads change
+ * in priority. This has the side effect of changing
+ * the threads active priority.
+ *
+ * Be sure to lock the first mutex in the list of owned
+ * mutexes. This acts as a barrier against another
+ * simultaneous call to change the threads priority
+ * and from the owning thread releasing the mutex.
+ */
+ m = TAILQ_FIRST(&pthread->mutexq);
+ if (m != NULL) {
+ THR_LOCK_ACQUIRE(curthread, &m->m_lock);
+ /*
+ * Make sure the thread still owns the lock.
+ */
+ if (m == TAILQ_FIRST(&pthread->mutexq))
+ mutex_rescan_owned(curthread, pthread,
+ /* rescan all owned */ NULL);
+ THR_LOCK_RELEASE(curthread, &m->m_lock);
+ }
+ }
+
+ /*
+ * If this thread is waiting on a priority inheritence mutex,
+ * check for priority adjustments. A change in priority can
+ * also cause a ceiling violation(*) for a thread waiting on
+ * a priority protection mutex; we don't perform the check here
+ * as it is done in pthread_mutex_unlock.
+ *
+ * (*) It should be noted that a priority change to a thread
+ * _after_ taking and owning a priority ceiling mutex
+ * does not affect ownership of that mutex; the ceiling
+ * priority is only checked before mutex ownership occurs.
+ */
+ if (propagate_prio != 0) {
+ /*
+ * Lock the thread's scheduling queue. This is a bit
+ * convoluted; the "in synchronization queue flag" can
+ * only be cleared with both the thread's scheduling and
+ * mutex locks held. The thread's pointer to the wanted
+ * mutex is guaranteed to be valid during this time.
+ */
+ THR_SCHED_LOCK(curthread, pthread);
+
+ if (((pthread->sflags & THR_FLAGS_IN_SYNCQ) == 0) ||
+ ((m = pthread->data.mutex) == NULL))
+ THR_SCHED_UNLOCK(curthread, pthread);
+ else {
+ /*
+ * This thread is currently waiting on a mutex; unlock
+ * the scheduling queue lock and lock the mutex. We
+ * can't hold both at the same time because the locking
+ * order could cause a deadlock.
+ */
+ THR_SCHED_UNLOCK(curthread, pthread);
+ THR_LOCK_ACQUIRE(curthread, &m->m_lock);
+
+ /*
+ * Check to make sure this thread is still in the
+ * same state (the lock above can yield the CPU to
+ * another thread or the thread may be running on
+ * another CPU).
+ */
+ if (((pthread->sflags & THR_FLAGS_IN_SYNCQ) != 0) &&
+ (pthread->data.mutex == m)) {
+ /*
+ * Remove and reinsert this thread into
+ * the list of waiting threads to preserve
+ * decreasing priority order.
+ */
+ mutex_queue_remove(m, pthread);
+ mutex_queue_enq(m, pthread);
+
+ if (m->m_protocol == PTHREAD_PRIO_INHERIT)
+ /* Adjust priorities: */
+ mutex_priority_adjust(curthread, m);
+ }
+
+ /* Unlock the mutex structure: */
+ THR_LOCK_RELEASE(curthread, &m->m_lock);
+ }
+ }
+}
+
+/*
+ * Called when a new thread is added to the mutex waiting queue or
+ * when a threads priority changes that is already in the mutex
+ * waiting queue.
+ *
+ * This must be called with the mutex locked by the current thread.
+ */
+static void
+mutex_priority_adjust(struct pthread *curthread, pthread_mutex_t mutex)
+{
+ pthread_mutex_t m = mutex;
+ struct pthread *pthread_next, *pthread = mutex->m_owner;
+ int done, temp_prio;
+
+ /*
+ * Calculate the mutex priority as the maximum of the highest
+ * active priority of any waiting threads and the owning threads
+ * active priority(*).
+ *
+ * (*) Because the owning threads current active priority may
+ * reflect priority inherited from this mutex (and the mutex
+ * priority may have changed) we must recalculate the active
+ * priority based on the threads saved inherited priority
+ * and its base priority.
+ */
+ pthread_next = TAILQ_FIRST(&m->m_queue); /* should never be NULL */
+ temp_prio = MAX(pthread_next->active_priority,
+ MAX(m->m_saved_prio, pthread->base_priority));
+
+ /* See if this mutex really needs adjusting: */
+ if (temp_prio == m->m_prio)
+ /* No need to propagate the priority: */
+ return;
+
+ /* Set new priority of the mutex: */
+ m->m_prio = temp_prio;
+
+ /*
+ * Don't unlock the mutex passed in as an argument. It is
+ * expected to be locked and unlocked by the caller.
+ */
+ done = 1;
+ do {
+ /*
+ * Save the threads priority before rescanning the
+ * owned mutexes:
+ */
+ temp_prio = pthread->active_priority;
+
+ /*
+ * Fix the priorities for all mutexes held by the owning
+ * thread since taking this mutex. This also has a
+ * potential side-effect of changing the threads priority.
+ *
+ * At this point the mutex is locked by the current thread.
+ * The owning thread can't release the mutex until it is
+ * unlocked, so we should be able to safely walk its list
+ * of owned mutexes.
+ */
+ mutex_rescan_owned(curthread, pthread, m);
+
+ /*
+ * If this isn't the first time through the loop,
+ * the current mutex needs to be unlocked.
+ */
+ if (done == 0)
+ THR_LOCK_RELEASE(curthread, &m->m_lock);
+
+ /* Assume we're done unless told otherwise: */
+ done = 1;
+
+ /*
+ * If the thread is currently waiting on a mutex, check
+ * to see if the threads new priority has affected the
+ * priority of the mutex.
+ */
+ if ((temp_prio != pthread->active_priority) &&
+ ((pthread->sflags & THR_FLAGS_IN_SYNCQ) != 0) &&
+ ((m = pthread->data.mutex) != NULL) &&
+ (m->m_protocol == PTHREAD_PRIO_INHERIT)) {
+ /* Lock the mutex structure: */
+ THR_LOCK_ACQUIRE(curthread, &m->m_lock);
+
+ /*
+ * Make sure the thread is still waiting on the
+ * mutex:
+ */
+ if (((pthread->sflags & THR_FLAGS_IN_SYNCQ) != 0) &&
+ (m == pthread->data.mutex)) {
+ /*
+ * The priority for this thread has changed.
+ * Remove and reinsert this thread into the
+ * list of waiting threads to preserve
+ * decreasing priority order.
+ */
+ mutex_queue_remove(m, pthread);
+ mutex_queue_enq(m, pthread);
+
+ /*
+ * Grab the waiting thread with highest
+ * priority:
+ */
+ pthread_next = TAILQ_FIRST(&m->m_queue);
+
+ /*
+ * Calculate the mutex priority as the maximum
+ * of the highest active priority of any
+ * waiting threads and the owning threads
+ * active priority.
+ */
+ temp_prio = MAX(pthread_next->active_priority,
+ MAX(m->m_saved_prio,
+ m->m_owner->base_priority));
+
+ if (temp_prio != m->m_prio) {
+ /*
+ * The priority needs to be propagated
+ * to the mutex this thread is waiting
+ * on and up to the owner of that mutex.
+ */
+ m->m_prio = temp_prio;
+ pthread = m->m_owner;
+
+ /* We're not done yet: */
+ done = 0;
+ }
+ }
+ /* Only release the mutex if we're done: */
+ if (done != 0)
+ THR_LOCK_RELEASE(curthread, &m->m_lock);
+ }
+ } while (done == 0);
+}
+
+static void
+mutex_rescan_owned(struct pthread *curthread, struct pthread *pthread,
+ struct pthread_mutex *mutex)
+{
+ struct pthread_mutex *m;
+ struct pthread *pthread_next;
+ int active_prio, inherited_prio;
+
+ /*
+ * Start walking the mutexes the thread has taken since
+ * taking this mutex.
+ */
+ if (mutex == NULL) {
+ /*
+ * A null mutex means start at the beginning of the owned
+ * mutex list.
+ */
+ m = TAILQ_FIRST(&pthread->mutexq);
+
+ /* There is no inherited priority yet. */
+ inherited_prio = 0;
+ } else {
+ /*
+ * The caller wants to start after a specific mutex. It
+ * is assumed that this mutex is a priority inheritence
+ * mutex and that its priority has been correctly
+ * calculated.
+ */
+ m = TAILQ_NEXT(mutex, m_qe);
+
+ /* Start inheriting priority from the specified mutex. */
+ inherited_prio = mutex->m_prio;
+ }
+ active_prio = MAX(inherited_prio, pthread->base_priority);
+
+ for (; m != NULL; m = TAILQ_NEXT(m, m_qe)) {
+ /*
+ * We only want to deal with priority inheritence
+ * mutexes. This might be optimized by only placing
+ * priority inheritence mutexes into the owned mutex
+ * list, but it may prove to be useful having all
+ * owned mutexes in this list. Consider a thread
+ * exiting while holding mutexes...
+ */
+ if (m->m_protocol == PTHREAD_PRIO_INHERIT) {
+ /*
+ * Fix the owners saved (inherited) priority to
+ * reflect the priority of the previous mutex.
+ */
+ m->m_saved_prio = inherited_prio;
+
+ if ((pthread_next = TAILQ_FIRST(&m->m_queue)) != NULL)
+ /* Recalculate the priority of the mutex: */
+ m->m_prio = MAX(active_prio,
+ pthread_next->active_priority);
+ else
+ m->m_prio = active_prio;
+
+ /* Recalculate new inherited and active priorities: */
+ inherited_prio = m->m_prio;
+ active_prio = MAX(m->m_prio, pthread->base_priority);
+ }
+ }
+
+ /*
+ * Fix the threads inherited priority and recalculate its
+ * active priority.
+ */
+ pthread->inherited_priority = inherited_prio;
+ active_prio = MAX(inherited_prio, pthread->base_priority);
+
+ if (active_prio != pthread->active_priority) {
+ /* Lock the thread's scheduling queue: */
+ THR_SCHED_LOCK(curthread, pthread);
+
+ if ((pthread->flags & THR_FLAGS_IN_RUNQ) == 0) {
+ /*
+ * This thread is not in a run queue. Just set
+ * its active priority.
+ */
+ pthread->active_priority = active_prio;
+ }
+ else {
+ /*
+ * This thread is in a run queue. Remove it from
+ * the queue before changing its priority:
+ */
+ THR_RUNQ_REMOVE(pthread);
+
+ /*
+ * POSIX states that if the priority is being
+ * lowered, the thread must be inserted at the
+ * head of the queue for its priority if it owns
+ * any priority protection or inheritence mutexes.
+ */
+ if ((active_prio < pthread->active_priority) &&
+ (pthread->priority_mutex_count > 0)) {
+ /* Set the new active priority. */
+ pthread->active_priority = active_prio;
+
+ THR_RUNQ_INSERT_HEAD(pthread);
+ } else {
+ /* Set the new active priority. */
+ pthread->active_priority = active_prio;
+
+ THR_RUNQ_INSERT_TAIL(pthread);
+ }
+ }
+ THR_SCHED_UNLOCK(curthread, pthread);
+ }
+}
+
+void
+_mutex_unlock_private(pthread_t pthread)
+{
+ struct pthread_mutex *m, *m_next;
+
+ for (m = TAILQ_FIRST(&pthread->mutexq); m != NULL; m = m_next) {
+ m_next = TAILQ_NEXT(m, m_qe);
+ if ((m->m_flags & MUTEX_FLAGS_PRIVATE) != 0)
+ pthread_mutex_unlock(&m);
+ }
+}
+
+/*
+ * This is called by the current thread when it wants to back out of a
+ * mutex_lock in order to run a signal handler.
+ */
+static void
+mutex_lock_backout(void *arg)
+{
+ struct pthread *curthread = (struct pthread *)arg;
+ struct pthread_mutex *m;
+
+ if ((curthread->sflags & THR_FLAGS_IN_SYNCQ) != 0) {
+ /*
+ * Any other thread may clear the "in sync queue flag",
+ * but only the current thread can clear the pointer
+ * to the mutex. So if the flag is set, we can
+ * guarantee that the pointer to the mutex is valid.
+ * The only problem may be if the mutex is destroyed
+ * out from under us, but that should be considered
+ * an application bug.
+ */
+ m = curthread->data.mutex;
+
+ /* Lock the mutex structure: */
+ THR_LOCK_ACQUIRE(curthread, &m->m_lock);
+
+
+ /*
+ * Check to make sure this thread doesn't already own
+ * the mutex. Since mutexes are unlocked with direct
+ * handoffs, it is possible the previous owner gave it
+ * to us after we checked the sync queue flag and before
+ * we locked the mutex structure.
+ */
+ if (m->m_owner == curthread) {
+ THR_LOCK_RELEASE(curthread, &m->m_lock);
+ mutex_unlock_common(&m, /* add_reference */ 0);
+ } else {
+ /*
+ * Remove ourselves from the mutex queue and
+ * clear the pointer to the mutex. We may no
+ * longer be in the mutex queue, but the removal
+ * function will DTRT.
+ */
+ mutex_queue_remove(m, curthread);
+ curthread->data.mutex = NULL;
+ THR_LOCK_RELEASE(curthread, &m->m_lock);
+ }
+ }
+ /* No need to call this again. */
+ curthread->sigbackout = NULL;
+}
+
+/*
+ * Dequeue a waiting thread from the head of a mutex queue in descending
+ * priority order.
+ *
+ * In order to properly dequeue a thread from the mutex queue and
+ * make it runnable without the possibility of errant wakeups, it
+ * is necessary to lock the thread's scheduling queue while also
+ * holding the mutex lock.
+ */
+static struct kse_mailbox *
+mutex_handoff(struct pthread *curthread, struct pthread_mutex *mutex)
+{
+ struct kse_mailbox *kmbx = NULL;
+ struct pthread *pthread;
+
+ /* Keep dequeueing until we find a valid thread: */
+ mutex->m_owner = NULL;
+ pthread = TAILQ_FIRST(&mutex->m_queue);
+ while (pthread != NULL) {
+ /* Take the thread's scheduling lock: */
+ THR_SCHED_LOCK(curthread, pthread);
+
+ /* Remove the thread from the mutex queue: */
+ TAILQ_REMOVE(&mutex->m_queue, pthread, sqe);
+ pthread->sflags &= ~THR_FLAGS_IN_SYNCQ;
+
+ /*
+ * Only exit the loop if the thread hasn't been
+ * cancelled.
+ */
+ switch (mutex->m_protocol) {
+ case PTHREAD_PRIO_NONE:
+ /*
+ * Assign the new owner and add the mutex to the
+ * thread's list of owned mutexes.
+ */
+ mutex->m_owner = pthread;
+ TAILQ_INSERT_TAIL(&pthread->mutexq, mutex, m_qe);
+ break;
+
+ case PTHREAD_PRIO_INHERIT:
+ /*
+ * Assign the new owner and add the mutex to the
+ * thread's list of owned mutexes.
+ */
+ mutex->m_owner = pthread;
+ TAILQ_INSERT_TAIL(&pthread->mutexq, mutex, m_qe);
+
+ /* Track number of priority mutexes owned: */
+ pthread->priority_mutex_count++;
+
+ /*
+ * Set the priority of the mutex. Since our waiting
+ * threads are in descending priority order, the
+ * priority of the mutex becomes the active priority
+ * of the thread we just dequeued.
+ */
+ mutex->m_prio = pthread->active_priority;
+
+ /* Save the owning threads inherited priority: */
+ mutex->m_saved_prio = pthread->inherited_priority;
+
+ /*
+ * The owning threads inherited priority now becomes
+ * his active priority (the priority of the mutex).
+ */
+ pthread->inherited_priority = mutex->m_prio;
+ break;
+
+ case PTHREAD_PRIO_PROTECT:
+ if (pthread->active_priority > mutex->m_prio) {
+ /*
+ * Either the mutex ceiling priority has
+ * been lowered and/or this threads priority
+ * has been raised subsequent to the thread
+ * being queued on the waiting list.
+ */
+ pthread->error = EINVAL;
+ }
+ else {
+ /*
+ * Assign the new owner and add the mutex
+ * to the thread's list of owned mutexes.
+ */
+ mutex->m_owner = pthread;
+ TAILQ_INSERT_TAIL(&pthread->mutexq,
+ mutex, m_qe);
+
+ /* Track number of priority mutexes owned: */
+ pthread->priority_mutex_count++;
+
+ /*
+ * Save the owning threads inherited
+ * priority:
+ */
+ mutex->m_saved_prio =
+ pthread->inherited_priority;
+
+ /*
+ * The owning thread inherits the ceiling
+ * priority of the mutex and executes at
+ * that priority:
+ */
+ pthread->inherited_priority = mutex->m_prio;
+ pthread->active_priority = mutex->m_prio;
+
+ }
+ break;
+ }
+
+ /* Make the thread runnable and unlock the scheduling queue: */
+ kmbx = _thr_setrunnable_unlocked(pthread);
+
+ /* Add a preemption point. */
+ if ((curthread->kseg == pthread->kseg) &&
+ (pthread->active_priority > curthread->active_priority))
+ curthread->critical_yield = 1;
+
+ if (mutex->m_owner == pthread) {
+ /* We're done; a valid owner was found. */
+ if (mutex->m_flags & MUTEX_FLAGS_PRIVATE)
+ THR_CRITICAL_ENTER(pthread);
+ THR_SCHED_UNLOCK(curthread, pthread);
+ break;
+ }
+ THR_SCHED_UNLOCK(curthread, pthread);
+ /* Get the next thread from the waiting queue: */
+ pthread = TAILQ_NEXT(pthread, sqe);
+ }
+
+ if ((pthread == NULL) && (mutex->m_protocol == PTHREAD_PRIO_INHERIT))
+ /* This mutex has no priority: */
+ mutex->m_prio = 0;
+ return (kmbx);
+}
+
+/*
+ * Dequeue a waiting thread from the head of a mutex queue in descending
+ * priority order.
+ */
+static inline pthread_t
+mutex_queue_deq(struct pthread_mutex *mutex)
+{
+ pthread_t pthread;
+
+ while ((pthread = TAILQ_FIRST(&mutex->m_queue)) != NULL) {
+ TAILQ_REMOVE(&mutex->m_queue, pthread, sqe);
+ pthread->sflags &= ~THR_FLAGS_IN_SYNCQ;
+
+ /*
+ * Only exit the loop if the thread hasn't been
+ * cancelled.
+ */
+ if (pthread->interrupted == 0)
+ break;
+ }
+
+ return (pthread);
+}
+
+/*
+ * Remove a waiting thread from a mutex queue in descending priority order.
+ */
+static inline void
+mutex_queue_remove(pthread_mutex_t mutex, pthread_t pthread)
+{
+ if ((pthread->sflags & THR_FLAGS_IN_SYNCQ) != 0) {
+ TAILQ_REMOVE(&mutex->m_queue, pthread, sqe);
+ pthread->sflags &= ~THR_FLAGS_IN_SYNCQ;
+ }
+}
+
+/*
+ * Enqueue a waiting thread to a queue in descending priority order.
+ */
+static inline void
+mutex_queue_enq(pthread_mutex_t mutex, pthread_t pthread)
+{
+ pthread_t tid = TAILQ_LAST(&mutex->m_queue, mutex_head);
+
+ THR_ASSERT_NOT_IN_SYNCQ(pthread);
+ /*
+ * For the common case of all threads having equal priority,
+ * we perform a quick check against the priority of the thread
+ * at the tail of the queue.
+ */
+ if ((tid == NULL) || (pthread->active_priority <= tid->active_priority))
+ TAILQ_INSERT_TAIL(&mutex->m_queue, pthread, sqe);
+ else {
+ tid = TAILQ_FIRST(&mutex->m_queue);
+ while (pthread->active_priority <= tid->active_priority)
+ tid = TAILQ_NEXT(tid, sqe);
+ TAILQ_INSERT_BEFORE(tid, pthread, sqe);
+ }
+ pthread->sflags |= THR_FLAGS_IN_SYNCQ;
+}
diff --git a/lib/libkse/thread/thr_mutex_prioceiling.c b/lib/libkse/thread/thr_mutex_prioceiling.c
new file mode 100644
index 0000000..f254346
--- /dev/null
+++ b/lib/libkse/thread/thr_mutex_prioceiling.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_mutexattr_getprioceiling);
+LT10_COMPAT_DEFAULT(pthread_mutexattr_getprioceiling);
+LT10_COMPAT_PRIVATE(_pthread_mutexattr_setprioceiling);
+LT10_COMPAT_DEFAULT(pthread_mutexattr_setprioceiling);
+LT10_COMPAT_PRIVATE(_pthread_mutex_getprioceiling);
+LT10_COMPAT_DEFAULT(pthread_mutex_getprioceiling);
+LT10_COMPAT_PRIVATE(_pthread_mutex_setprioceiling);
+LT10_COMPAT_DEFAULT(pthread_mutex_setprioceiling);
+
+__weak_reference(_pthread_mutexattr_getprioceiling, pthread_mutexattr_getprioceiling);
+__weak_reference(_pthread_mutexattr_setprioceiling, pthread_mutexattr_setprioceiling);
+__weak_reference(_pthread_mutex_getprioceiling, pthread_mutex_getprioceiling);
+__weak_reference(_pthread_mutex_setprioceiling, pthread_mutex_setprioceiling);
+
+int
+_pthread_mutexattr_getprioceiling(pthread_mutexattr_t *mattr, int *prioceiling)
+{
+ int ret = 0;
+
+ if ((mattr == NULL) || (*mattr == NULL))
+ ret = EINVAL;
+ else if ((*mattr)->m_protocol != PTHREAD_PRIO_PROTECT)
+ ret = EINVAL;
+ else
+ *prioceiling = (*mattr)->m_ceiling;
+
+ return(ret);
+}
+
+int
+_pthread_mutexattr_setprioceiling(pthread_mutexattr_t *mattr, int prioceiling)
+{
+ int ret = 0;
+
+ if ((mattr == NULL) || (*mattr == NULL))
+ ret = EINVAL;
+ else if ((*mattr)->m_protocol != PTHREAD_PRIO_PROTECT)
+ ret = EINVAL;
+ else
+ (*mattr)->m_ceiling = prioceiling;
+
+ return(ret);
+}
+
+int
+_pthread_mutex_getprioceiling(pthread_mutex_t *mutex,
+ int *prioceiling)
+{
+ int ret;
+
+ if ((mutex == NULL) || (*mutex == NULL))
+ ret = EINVAL;
+ else if ((*mutex)->m_protocol != PTHREAD_PRIO_PROTECT)
+ ret = EINVAL;
+ else
+ ret = (*mutex)->m_prio;
+
+ return(ret);
+}
+
+int
+_pthread_mutex_setprioceiling(pthread_mutex_t *mutex,
+ int prioceiling, int *old_ceiling)
+{
+ int ret = 0;
+ int tmp;
+
+ if ((mutex == NULL) || (*mutex == NULL))
+ ret = EINVAL;
+ else if ((*mutex)->m_protocol != PTHREAD_PRIO_PROTECT)
+ ret = EINVAL;
+ /* Lock the mutex: */
+ else if ((ret = pthread_mutex_lock(mutex)) == 0) {
+ tmp = (*mutex)->m_prio;
+ /* Set the new ceiling: */
+ (*mutex)->m_prio = prioceiling;
+
+ /* Unlock the mutex: */
+ ret = pthread_mutex_unlock(mutex);
+
+ /* Return the old ceiling: */
+ *old_ceiling = tmp;
+ }
+ return(ret);
+}
diff --git a/lib/libkse/thread/thr_mutex_protocol.c b/lib/libkse/thread/thr_mutex_protocol.c
new file mode 100644
index 0000000..9e3e46b
--- /dev/null
+++ b/lib/libkse/thread/thr_mutex_protocol.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_mutexattr_getprotocol);
+LT10_COMPAT_DEFAULT(pthread_mutexattr_getprotocol);
+LT10_COMPAT_PRIVATE(_pthread_mutexattr_setprotocol);
+LT10_COMPAT_DEFAULT(pthread_mutexattr_setprotocol);
+
+__weak_reference(_pthread_mutexattr_getprotocol, pthread_mutexattr_getprotocol);
+__weak_reference(_pthread_mutexattr_setprotocol, pthread_mutexattr_setprotocol);
+
+int
+_pthread_mutexattr_getprotocol(pthread_mutexattr_t *mattr, int *protocol)
+{
+ int ret = 0;
+
+ if ((mattr == NULL) || (*mattr == NULL))
+ ret = EINVAL;
+ else
+ *protocol = (*mattr)->m_protocol;
+
+ return(ret);
+}
+
+int
+_pthread_mutexattr_setprotocol(pthread_mutexattr_t *mattr, int protocol)
+{
+ int ret = 0;
+
+ if ((mattr == NULL) || (*mattr == NULL) ||
+ (protocol < PTHREAD_PRIO_NONE) || (protocol > PTHREAD_PRIO_PROTECT))
+ ret = EINVAL;
+ else {
+ (*mattr)->m_protocol = protocol;
+ (*mattr)->m_ceiling = THR_MAX_PRIORITY;
+ }
+ return(ret);
+}
+
diff --git a/lib/libkse/thread/thr_mutexattr_destroy.c b/lib/libkse/thread/thr_mutexattr_destroy.c
new file mode 100644
index 0000000..2ae34a8
--- /dev/null
+++ b/lib/libkse/thread/thr_mutexattr_destroy.c
@@ -0,0 +1,56 @@
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_mutexattr_destroy);
+LT10_COMPAT_DEFAULT(pthread_mutexattr_destroy);
+
+__weak_reference(_pthread_mutexattr_destroy, pthread_mutexattr_destroy);
+
+int
+_pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
+{
+ int ret;
+ if (attr == NULL || *attr == NULL) {
+ ret = EINVAL;
+ } else {
+ free(*attr);
+ *attr = NULL;
+ ret = 0;
+ }
+ return(ret);
+}
diff --git a/lib/libkse/thread/thr_nanosleep.c b/lib/libkse/thread/thr_nanosleep.c
new file mode 100644
index 0000000..72f85b2
--- /dev/null
+++ b/lib/libkse/thread/thr_nanosleep.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__nanosleep);
+LT10_COMPAT_PRIVATE(_nanosleep);
+LT10_COMPAT_DEFAULT(nanosleep);
+
+__weak_reference(__nanosleep, nanosleep);
+
+int
+_nanosleep(const struct timespec *time_to_sleep,
+ struct timespec *time_remaining)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret = 0;
+ struct timespec ts, ts1;
+ struct timespec remaining_time;
+ struct timespec wakeup_time;
+
+ /* Check if the time to sleep is legal: */
+ if ((time_to_sleep == NULL) || (time_to_sleep->tv_sec < 0) ||
+ (time_to_sleep->tv_nsec < 0) ||
+ (time_to_sleep->tv_nsec >= 1000000000)) {
+ /* Return an EINVAL error : */
+ errno = EINVAL;
+ ret = -1;
+ } else {
+ if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
+ return (__sys_nanosleep(time_to_sleep, time_remaining));
+
+ KSE_GET_TOD(curthread->kse, &ts);
+
+ /* Calculate the time for the current thread to wake up: */
+ TIMESPEC_ADD(&wakeup_time, &ts, time_to_sleep);
+
+ THR_LOCK_SWITCH(curthread);
+ curthread->interrupted = 0;
+ curthread->wakeup_time = wakeup_time;
+ THR_SET_STATE(curthread, PS_SLEEP_WAIT);
+
+ /* Reschedule the current thread to sleep: */
+ _thr_sched_switch_unlocked(curthread);
+
+ /* Calculate the remaining time to sleep: */
+ KSE_GET_TOD(curthread->kse, &ts1);
+ remaining_time.tv_sec = time_to_sleep->tv_sec
+ + ts.tv_sec - ts1.tv_sec;
+ remaining_time.tv_nsec = time_to_sleep->tv_nsec
+ + ts.tv_nsec - ts1.tv_nsec;
+
+ /* Check if the nanosecond field has underflowed: */
+ if (remaining_time.tv_nsec < 0) {
+ /* Handle the underflow: */
+ remaining_time.tv_sec -= 1;
+ remaining_time.tv_nsec += 1000000000;
+ }
+ /* Check if the nanosecond field has overflowed: */
+ else if (remaining_time.tv_nsec >= 1000000000) {
+ /* Handle the overflow: */
+ remaining_time.tv_sec += 1;
+ remaining_time.tv_nsec -= 1000000000;
+ }
+
+ /* Check if the sleep was longer than the required time: */
+ if (remaining_time.tv_sec < 0) {
+ /* Reset the time left: */
+ remaining_time.tv_sec = 0;
+ remaining_time.tv_nsec = 0;
+ }
+
+ /* Check if the time remaining is to be returned: */
+ if (time_remaining != NULL) {
+ /* Return the actual time slept: */
+ time_remaining->tv_sec = remaining_time.tv_sec;
+ time_remaining->tv_nsec = remaining_time.tv_nsec;
+ }
+
+ /* Check if the sleep was interrupted: */
+ if (curthread->interrupted) {
+ /* Return an EINTR error : */
+ errno = EINTR;
+ ret = -1;
+ }
+ }
+ return (ret);
+}
+
+int
+__nanosleep(const struct timespec *time_to_sleep,
+ struct timespec *time_remaining)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ _thr_cancel_enter(curthread);
+ ret = _nanosleep(time_to_sleep, time_remaining);
+ _thr_cancel_leave(curthread, 1);
+
+ return (ret);
+}
diff --git a/lib/libkse/thread/thr_once.c b/lib/libkse/thread/thr_once.c
new file mode 100644
index 0000000..f93800f
--- /dev/null
+++ b/lib/libkse/thread/thr_once.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <pthread.h>
+#include "un-namespace.h"
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_once);
+LT10_COMPAT_DEFAULT(pthread_once);
+
+__weak_reference(_pthread_once, pthread_once);
+
+#define ONCE_NEVER_DONE PTHREAD_NEEDS_INIT
+#define ONCE_DONE PTHREAD_DONE_INIT
+#define ONCE_IN_PROGRESS 0x02
+#define ONCE_MASK 0x03
+
+static pthread_mutex_t once_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t once_cv = PTHREAD_COND_INITIALIZER;
+
+/*
+ * POSIX:
+ * The pthread_once() function is not a cancellation point. However,
+ * if init_routine is a cancellation point and is canceled, the effect
+ * on once_control shall be as if pthread_once() was never called.
+ */
+
+static void
+once_cancel_handler(void *arg)
+{
+ pthread_once_t *once_control = arg;
+
+ _pthread_mutex_lock(&once_lock);
+ once_control->state = ONCE_NEVER_DONE;
+ _pthread_mutex_unlock(&once_lock);
+ _pthread_cond_broadcast(&once_cv);
+}
+
+int
+_pthread_once(pthread_once_t *once_control, void (*init_routine) (void))
+{
+ struct pthread *curthread;
+ int wakeup = 0;
+
+ if (once_control->state == ONCE_DONE)
+ return (0);
+ _pthread_mutex_lock(&once_lock);
+ while (*(volatile int *)&(once_control->state) == ONCE_IN_PROGRESS)
+ _pthread_cond_wait(&once_cv, &once_lock);
+ /*
+ * If previous thread was canceled, then the state still
+ * could be ONCE_NEVER_DONE, we need to check it again.
+ */
+ if (*(volatile int *)&(once_control->state) == ONCE_NEVER_DONE) {
+ once_control->state = ONCE_IN_PROGRESS;
+ _pthread_mutex_unlock(&once_lock);
+ curthread = _get_curthread();
+ THR_CLEANUP_PUSH(curthread, once_cancel_handler, once_control);
+ init_routine();
+ THR_CLEANUP_POP(curthread, 0);
+ _pthread_mutex_lock(&once_lock);
+ once_control->state = ONCE_DONE;
+ wakeup = 1;
+ }
+ _pthread_mutex_unlock(&once_lock);
+ if (wakeup)
+ _pthread_cond_broadcast(&once_cv);
+ return (0);
+}
+
diff --git a/lib/libkse/thread/thr_open.c b/lib/libkse/thread/thr_open.c
new file mode 100644
index 0000000..63b5f4a
--- /dev/null
+++ b/lib/libkse/thread/thr_open.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <stdarg.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__open);
+LT10_COMPAT_DEFAULT(open);
+
+__weak_reference(__open, open);
+
+int
+__open(const char *path, int flags,...)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+ int mode = 0;
+ va_list ap;
+
+ _thr_cancel_enter(curthread);
+
+ /* Check if the file is being created: */
+ if (flags & O_CREAT) {
+ /* Get the creation mode: */
+ va_start(ap, flags);
+ mode = va_arg(ap, int);
+ va_end(ap);
+ }
+
+ ret = __sys_open(path, flags, mode);
+ /*
+ * To avoid possible file handle leak,
+ * only check cancellation point if it is failure
+ */
+ _thr_cancel_leave(curthread, (ret == -1));
+
+ return ret;
+}
diff --git a/lib/libkse/thread/thr_pause.c b/lib/libkse/thread/thr_pause.c
new file mode 100644
index 0000000..b3f0fe5
--- /dev/null
+++ b/lib/libkse/thread/thr_pause.c
@@ -0,0 +1,54 @@
+/*
+ * 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$
+ */
+
+#include <unistd.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+extern int __pause(void);
+
+LT10_COMPAT_PRIVATE(_pause);
+LT10_COMPAT_DEFAULT(pause);
+
+__weak_reference(_pause, pause);
+
+int
+_pause(void)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ _thr_cancel_enter(curthread);
+ ret = __pause();
+ _thr_cancel_leave(curthread, 1);
+
+ return ret;
+}
diff --git a/lib/libkse/thread/thr_poll.c b/lib/libkse/thread/thr_poll.c
new file mode 100644
index 0000000..5e3890b
--- /dev/null
+++ b/lib/libkse/thread/thr_poll.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 1999 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <poll.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/fcntl.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__poll);
+LT10_COMPAT_DEFAULT(poll);
+
+__weak_reference(__poll, poll);
+
+int
+__poll(struct pollfd *fds, unsigned int nfds, int timeout)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ _thr_cancel_enter(curthread);
+ ret = __sys_poll(fds, nfds, timeout);
+ _thr_cancel_leave(curthread, 1);
+
+ return ret;
+}
diff --git a/lib/libkse/thread/thr_printf.c b/lib/libkse/thread/thr_printf.c
new file mode 100644
index 0000000..2a4b12b
--- /dev/null
+++ b/lib/libkse/thread/thr_printf.c
@@ -0,0 +1,135 @@
+/*-
+ * 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 <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "thr_private.h"
+
+static void pchar(int fd, char c);
+static void pstr(int fd, const char *s);
+
+/*
+ * Write formatted output to stdout, in a thread-safe manner.
+ *
+ * Recognises the following conversions:
+ * %c -> char
+ * %d -> signed int (base 10)
+ * %s -> string
+ * %u -> unsigned int (base 10)
+ * %x -> unsigned int (base 16)
+ * %p -> unsigned int (base 16)
+ */
+void
+_thread_printf(int fd, const char *fmt, ...)
+{
+ static const char digits[16] = "0123456789abcdef";
+ va_list ap;
+ char buf[20];
+ char *s;
+ unsigned long r, u;
+ int c;
+ long d;
+ int islong;
+
+ va_start(ap, fmt);
+ while ((c = *fmt++)) {
+ islong = 0;
+ if (c == '%') {
+next: c = *fmt++;
+ if (c == '\0')
+ goto out;
+ switch (c) {
+ case 'c':
+ pchar(fd, va_arg(ap, int));
+ continue;
+ case 's':
+ pstr(fd, va_arg(ap, char *));
+ continue;
+ case 'l':
+ islong = 1;
+ goto next;
+ case 'p':
+ islong = 1;
+ case 'd':
+ case 'u':
+ case 'x':
+ r = ((c == 'u') || (c == 'd')) ? 10 : 16;
+ if (c == 'd') {
+ if (islong)
+ d = va_arg(ap, unsigned long);
+ else
+ d = va_arg(ap, unsigned);
+ if (d < 0) {
+ pchar(fd, '-');
+ u = (unsigned long)(d * -1);
+ } else
+ u = (unsigned long)d;
+ } else {
+ if (islong)
+ u = va_arg(ap, unsigned long);
+ else
+ u = va_arg(ap, unsigned);
+ }
+ s = buf;
+ do {
+ *s++ = digits[u % r];
+ } while (u /= r);
+ while (--s >= buf)
+ pchar(fd, *s);
+ continue;
+ }
+ }
+ pchar(fd, c);
+ }
+out:
+ va_end(ap);
+}
+
+/*
+ * Write a single character to stdout, in a thread-safe manner.
+ */
+static void
+pchar(int fd, char c)
+{
+
+ __sys_write(fd, &c, 1);
+}
+
+/*
+ * Write a string to stdout, in a thread-safe manner.
+ */
+static void
+pstr(int fd, const char *s)
+{
+
+ __sys_write(fd, s, strlen(s));
+}
+
diff --git a/lib/libkse/thread/thr_priority_queue.c b/lib/libkse/thread/thr_priority_queue.c
new file mode 100644
index 0000000..f750a01
--- /dev/null
+++ b/lib/libkse/thread/thr_priority_queue.c
@@ -0,0 +1,324 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+#include <stdlib.h>
+#include <sys/queue.h>
+#include <string.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+/* Prototypes: */
+static void pq_insert_prio_list(pq_queue_t *pq, int prio);
+
+#if defined(_PTHREADS_INVARIANTS)
+
+#define PQ_IN_SCHEDQ (THR_FLAGS_IN_RUNQ | THR_FLAGS_IN_WAITQ)
+
+#define PQ_SET_ACTIVE(pq) (pq)->pq_flags |= PQF_ACTIVE
+#define PQ_CLEAR_ACTIVE(pq) (pq)->pq_flags &= ~PQF_ACTIVE
+#define PQ_ASSERT_ACTIVE(pq, msg) do { \
+ if (((pq)->pq_flags & PQF_ACTIVE) == 0) \
+ PANIC(msg); \
+} while (0)
+#define PQ_ASSERT_INACTIVE(pq, msg) do { \
+ if (((pq)->pq_flags & PQF_ACTIVE) != 0) \
+ PANIC(msg); \
+} while (0)
+#define PQ_ASSERT_IN_WAITQ(thrd, msg) do { \
+ if (((thrd)->flags & THR_FLAGS_IN_WAITQ) == 0) \
+ PANIC(msg); \
+} while (0)
+#define PQ_ASSERT_IN_RUNQ(thrd, msg) do { \
+ if (((thrd)->flags & THR_FLAGS_IN_RUNQ) == 0) \
+ PANIC(msg); \
+} while (0)
+#define PQ_ASSERT_NOT_QUEUED(thrd, msg) do { \
+ if (((thrd)->flags & PQ_IN_SCHEDQ) != 0) \
+ PANIC(msg); \
+} while (0)
+
+#else
+
+#define PQ_SET_ACTIVE(pq)
+#define PQ_CLEAR_ACTIVE(pq)
+#define PQ_ASSERT_ACTIVE(pq, msg)
+#define PQ_ASSERT_INACTIVE(pq, msg)
+#define PQ_ASSERT_IN_WAITQ(thrd, msg)
+#define PQ_ASSERT_IN_RUNQ(thrd, msg)
+#define PQ_ASSERT_NOT_QUEUED(thrd, msg)
+
+#endif
+
+int
+_pq_alloc(pq_queue_t *pq, int minprio, int maxprio)
+{
+ int ret = 0;
+ int prioslots = maxprio - minprio + 1;
+
+ if (pq == NULL)
+ ret = -1;
+
+ /* Create the priority queue with (maxprio - minprio + 1) slots: */
+ else if ((pq->pq_lists =
+ (pq_list_t *) malloc(sizeof(pq_list_t) * prioslots)) == NULL)
+ ret = -1;
+
+ else {
+ /* Remember the queue size: */
+ pq->pq_size = prioslots;
+ ret = _pq_init(pq);
+ }
+ return (ret);
+}
+
+void
+_pq_free(pq_queue_t *pq)
+{
+ if ((pq != NULL) && (pq->pq_lists != NULL))
+ free(pq->pq_lists);
+}
+
+int
+_pq_init(pq_queue_t *pq)
+{
+ int i, ret = 0;
+
+ if ((pq == NULL) || (pq->pq_lists == NULL))
+ ret = -1;
+
+ else {
+ /* Initialize the queue for each priority slot: */
+ for (i = 0; i < pq->pq_size; i++) {
+ TAILQ_INIT(&pq->pq_lists[i].pl_head);
+ pq->pq_lists[i].pl_prio = i;
+ pq->pq_lists[i].pl_queued = 0;
+ }
+ /* Initialize the priority queue: */
+ TAILQ_INIT(&pq->pq_queue);
+ pq->pq_flags = 0;
+ pq->pq_threads = 0;
+ }
+ return (ret);
+}
+
+void
+_pq_remove(pq_queue_t *pq, pthread_t pthread)
+{
+ int prio = pthread->active_priority;
+
+ /*
+ * Make some assertions when debugging is enabled:
+ */
+ PQ_ASSERT_INACTIVE(pq, "_pq_remove: pq_active");
+ PQ_SET_ACTIVE(pq);
+ PQ_ASSERT_IN_RUNQ(pthread, "_pq_remove: Not in priority queue");
+
+ /*
+ * Remove this thread from priority list. Note that if
+ * the priority list becomes empty, it is not removed
+ * from the priority queue because another thread may be
+ * added to the priority list (resulting in a needless
+ * removal/insertion). Priority lists are only removed
+ * from the priority queue when _pq_first is called.
+ */
+ TAILQ_REMOVE(&pq->pq_lists[prio].pl_head, pthread, pqe);
+ pq->pq_threads--;
+ /* This thread is now longer in the priority queue. */
+ pthread->flags &= ~THR_FLAGS_IN_RUNQ;
+
+ PQ_CLEAR_ACTIVE(pq);
+}
+
+
+void
+_pq_insert_head(pq_queue_t *pq, pthread_t pthread)
+{
+ int prio;
+
+ /*
+ * Make some assertions when debugging is enabled:
+ */
+ PQ_ASSERT_INACTIVE(pq, "_pq_insert_head: pq_active");
+ PQ_SET_ACTIVE(pq);
+ PQ_ASSERT_NOT_QUEUED(pthread,
+ "_pq_insert_head: Already in priority queue");
+
+ prio = pthread->active_priority;
+ TAILQ_INSERT_HEAD(&pq->pq_lists[prio].pl_head, pthread, pqe);
+ if (pq->pq_lists[prio].pl_queued == 0)
+ /* Insert the list into the priority queue: */
+ pq_insert_prio_list(pq, prio);
+ pq->pq_threads++;
+ /* Mark this thread as being in the priority queue. */
+ pthread->flags |= THR_FLAGS_IN_RUNQ;
+
+ PQ_CLEAR_ACTIVE(pq);
+}
+
+
+void
+_pq_insert_tail(pq_queue_t *pq, pthread_t pthread)
+{
+ int prio;
+
+ /*
+ * Make some assertions when debugging is enabled:
+ */
+ PQ_ASSERT_INACTIVE(pq, "_pq_insert_tail: pq_active");
+ PQ_SET_ACTIVE(pq);
+ PQ_ASSERT_NOT_QUEUED(pthread,
+ "_pq_insert_tail: Already in priority queue");
+
+ prio = pthread->active_priority;
+ TAILQ_INSERT_TAIL(&pq->pq_lists[prio].pl_head, pthread, pqe);
+ if (pq->pq_lists[prio].pl_queued == 0)
+ /* Insert the list into the priority queue: */
+ pq_insert_prio_list(pq, prio);
+ pq->pq_threads++;
+ /* Mark this thread as being in the priority queue. */
+ pthread->flags |= THR_FLAGS_IN_RUNQ;
+
+ PQ_CLEAR_ACTIVE(pq);
+}
+
+
+pthread_t
+_pq_first(pq_queue_t *pq)
+{
+ pq_list_t *pql;
+ pthread_t pthread = NULL;
+
+ /*
+ * Make some assertions when debugging is enabled:
+ */
+ PQ_ASSERT_INACTIVE(pq, "_pq_first: pq_active");
+ PQ_SET_ACTIVE(pq);
+
+ while (((pql = TAILQ_FIRST(&pq->pq_queue)) != NULL) &&
+ (pthread == NULL)) {
+ if ((pthread = TAILQ_FIRST(&pql->pl_head)) == NULL) {
+ /*
+ * The priority list is empty; remove the list
+ * from the queue.
+ */
+ TAILQ_REMOVE(&pq->pq_queue, pql, pl_link);
+
+ /* Mark the list as not being in the queue: */
+ pql->pl_queued = 0;
+ }
+ }
+
+ PQ_CLEAR_ACTIVE(pq);
+ return (pthread);
+}
+
+/*
+ * Select a thread which is allowed to run by debugger, we probably
+ * should merge the function into _pq_first if that function is only
+ * used by scheduler to select a thread.
+ */
+pthread_t
+_pq_first_debug(pq_queue_t *pq)
+{
+ pq_list_t *pql, *pqlnext = NULL;
+ pthread_t pthread = NULL;
+
+ /*
+ * Make some assertions when debugging is enabled:
+ */
+ PQ_ASSERT_INACTIVE(pq, "_pq_first: pq_active");
+ PQ_SET_ACTIVE(pq);
+
+ for (pql = TAILQ_FIRST(&pq->pq_queue);
+ pql != NULL && pthread == NULL; pql = pqlnext) {
+ if ((pthread = TAILQ_FIRST(&pql->pl_head)) == NULL) {
+ /*
+ * The priority list is empty; remove the list
+ * from the queue.
+ */
+ pqlnext = TAILQ_NEXT(pql, pl_link);
+ TAILQ_REMOVE(&pq->pq_queue, pql, pl_link);
+
+ /* Mark the list as not being in the queue: */
+ pql->pl_queued = 0;
+ } else {
+ /*
+ * note there may be a suspension event during this
+ * test, If TMDF_SUSPEND is set after we tested it,
+ * we will run the thread, this seems be a problem,
+ * fortunatly, when we are being debugged, all context
+ * switch will be done by kse_switchin, that is a
+ * syscall, kse_switchin will check the flag again,
+ * the thread will be returned via upcall, so next
+ * time, UTS won't run the thread.
+ */
+ while (pthread != NULL && !DBG_CAN_RUN(pthread)) {
+ pthread = TAILQ_NEXT(pthread, pqe);
+ }
+ if (pthread == NULL)
+ pqlnext = TAILQ_NEXT(pql, pl_link);
+ }
+ }
+
+ PQ_CLEAR_ACTIVE(pq);
+ return (pthread);
+}
+
+static void
+pq_insert_prio_list(pq_queue_t *pq, int prio)
+{
+ pq_list_t *pql;
+
+ /*
+ * Make some assertions when debugging is enabled:
+ */
+ PQ_ASSERT_ACTIVE(pq, "pq_insert_prio_list: pq_active");
+
+ /*
+ * The priority queue is in descending priority order. Start at
+ * the beginning of the queue and find the list before which the
+ * new list should be inserted.
+ */
+ pql = TAILQ_FIRST(&pq->pq_queue);
+ while ((pql != NULL) && (pql->pl_prio > prio))
+ pql = TAILQ_NEXT(pql, pl_link);
+
+ /* Insert the list: */
+ if (pql == NULL)
+ TAILQ_INSERT_TAIL(&pq->pq_queue, &pq->pq_lists[prio], pl_link);
+ else
+ TAILQ_INSERT_BEFORE(pql, &pq->pq_lists[prio], pl_link);
+
+ /* Mark this list as being in the queue: */
+ pq->pq_lists[prio].pl_queued = 1;
+}
diff --git a/lib/libkse/thread/thr_private.h b/lib/libkse/thread/thr_private.h
new file mode 100644
index 0000000..f839960
--- /dev/null
+++ b/lib/libkse/thread/thr_private.h
@@ -0,0 +1,1320 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Private thread definitions for the uthread kernel.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _THR_PRIVATE_H
+#define _THR_PRIVATE_H
+
+/*
+ * Include files.
+ */
+#include <setjmp.h>
+#include <signal.h>
+#include <stdio.h>
+#include <sys/queue.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/cdefs.h>
+#include <sys/kse.h>
+#include <sched.h>
+#include <ucontext.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <pthread_np.h>
+
+#ifndef LIBTHREAD_DB
+#include "lock.h"
+#include "pthread_md.h"
+#endif
+
+/*
+ * Unfortunately, libpthread had symbol versioning before libc.
+ * But now libc has symbol versioning, we need to occupy the
+ * same version namespace in order to override some libc functions.
+ * So in order to avoid breaking binaries requiring symbols from
+ * LIBTHREAD_1_0, we need to provide a compatible interface for
+ * those symbols.
+ */
+#if defined(SYMBOL_VERSIONING) && defined(PIC)
+#define SYM_LT10(sym) __CONCAT(sym, _lt10)
+#define SYM_FB10(sym) __CONCAT(sym, _fb10)
+#define SYM_FBP10(sym) __CONCAT(sym, _fbp10)
+#define WEAK_REF(sym, alias) __weak_reference(sym, alias)
+#define SYM_COMPAT(sym, impl, ver) __sym_compat(sym, impl, ver)
+#define SYM_DEFAULT(sym, impl, ver) __sym_default(sym, impl, ver)
+
+#define LT10_COMPAT(sym) \
+ WEAK_REF(sym, SYM_LT10(sym)); \
+ SYM_COMPAT(sym, SYM_LT10(sym), LIBTHREAD_1_0)
+
+#define LT10_COMPAT_DEFAULT(sym) \
+ LT10_COMPAT(sym); \
+ WEAK_REF(sym, SYM_FB10(sym)); \
+ SYM_DEFAULT(sym, SYM_FB10(sym), FBSD_1.0)
+
+#define LT10_COMPAT_PRIVATE(sym) \
+ LT10_COMPAT(sym); \
+ WEAK_REF(sym, SYM_FBP10(sym)); \
+ SYM_DEFAULT(sym, SYM_FBP10(sym), FBSDprivate)
+#else
+#define LT10_COMPAT_DEFAULT(sym)
+#define LT10_COMPAT_PRIVATE(sym)
+#endif
+
+/*
+ * Evaluate the storage class specifier.
+ */
+#ifdef GLOBAL_PTHREAD_PRIVATE
+#define SCLASS
+#define SCLASS_PRESET(x...) = x
+#else
+#define SCLASS extern
+#define SCLASS_PRESET(x...)
+#endif
+
+/*
+ * Kernel fatal error handler macro.
+ */
+#define PANIC(string) _thr_exit(__FILE__, __LINE__, string)
+
+
+/* Output debug messages like this: */
+#ifdef STDOUT_FILENO
+#define stdout_debug(...) _thread_printf(STDOUT_FILENO, __VA_ARGS__)
+#endif
+#ifdef STDERR_FILENO
+#define stderr_debug(...) _thread_printf(STDERR_FILENO, __VA_ARGS__)
+#endif
+
+#define DBG_MUTEX 0x0001
+#define DBG_SIG 0x0002
+#define DBG_INFO_DUMP 0x0004
+
+#ifdef _PTHREADS_INVARIANTS
+#define THR_ASSERT(cond, msg) do { \
+ if (!(cond)) \
+ PANIC(msg); \
+} while (0)
+#else
+#define THR_ASSERT(cond, msg)
+#endif
+
+/*
+ * State change macro without scheduling queue change:
+ */
+#define THR_SET_STATE(thrd, newstate) do { \
+ (thrd)->state = newstate; \
+ (thrd)->fname = __FILE__; \
+ (thrd)->lineno = __LINE__; \
+} while (0)
+
+
+#define TIMESPEC_ADD(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 >= 1000000000) { \
+ (dst)->tv_sec++; \
+ (dst)->tv_nsec -= 1000000000; \
+ } \
+ } while (0)
+
+#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)
+
+/*
+ * Priority queues.
+ *
+ * XXX It'd be nice if these were contained in uthread_priority_queue.[ch].
+ */
+typedef struct pq_list {
+ TAILQ_HEAD(, pthread) pl_head; /* list of threads at this priority */
+ TAILQ_ENTRY(pq_list) pl_link; /* link for queue of priority lists */
+ int pl_prio; /* the priority of this list */
+ int pl_queued; /* is this in the priority queue */
+} pq_list_t;
+
+typedef struct pq_queue {
+ TAILQ_HEAD(, pq_list) pq_queue; /* queue of priority lists */
+ pq_list_t *pq_lists; /* array of all priority lists */
+ int pq_size; /* number of priority lists */
+#define PQF_ACTIVE 0x0001
+ int pq_flags;
+ int pq_threads;
+} pq_queue_t;
+
+/*
+ * Each KSEG has a scheduling queue. For now, threads that exist in their
+ * own KSEG (system scope) will get a full priority queue. In the future
+ * this can be optimized for the single thread per KSEG case.
+ */
+struct sched_queue {
+ pq_queue_t sq_runq;
+ TAILQ_HEAD(, pthread) sq_waitq; /* waiting in userland */
+};
+
+typedef struct kse_thr_mailbox *kse_critical_t;
+
+struct kse_group;
+
+#define MAX_KSE_LOCKLEVEL 5
+struct kse {
+ /* -- location and order specific items for gdb -- */
+ struct kcb *k_kcb;
+ struct pthread *k_curthread; /* current thread */
+ struct kse_group *k_kseg; /* parent KSEG */
+ struct sched_queue *k_schedq; /* scheduling queue */
+ /* -- end of location and order specific items -- */
+ TAILQ_ENTRY(kse) k_qe; /* KSE list link entry */
+ TAILQ_ENTRY(kse) k_kgqe; /* KSEG's KSE list entry */
+ /*
+ * Items that are only modified by the kse, or that otherwise
+ * don't need to be locked when accessed
+ */
+ struct lock k_lock;
+ struct lockuser k_lockusers[MAX_KSE_LOCKLEVEL];
+ int k_locklevel;
+ stack_t k_stack;
+ int k_flags;
+#define KF_STARTED 0x0001 /* kernel kse created */
+#define KF_INITIALIZED 0x0002 /* initialized on 1st upcall */
+#define KF_TERMINATED 0x0004 /* kse is terminated */
+#define KF_IDLE 0x0008 /* kse is idle */
+#define KF_SWITCH 0x0010 /* thread switch in UTS */
+ int k_error; /* syscall errno in critical */
+ int k_cpu; /* CPU ID when bound */
+ int k_sigseqno; /* signal buffered count */
+};
+
+#define KSE_SET_IDLE(kse) ((kse)->k_flags |= KF_IDLE)
+#define KSE_CLEAR_IDLE(kse) ((kse)->k_flags &= ~KF_IDLE)
+#define KSE_IS_IDLE(kse) (((kse)->k_flags & KF_IDLE) != 0)
+#define KSE_SET_SWITCH(kse) ((kse)->k_flags |= KF_SWITCH)
+#define KSE_CLEAR_SWITCH(kse) ((kse)->k_flags &= ~KF_SWITCH)
+#define KSE_IS_SWITCH(kse) (((kse)->k_flags & KF_SWITCH) != 0)
+
+/*
+ * Each KSE group contains one or more KSEs in which threads can run.
+ * At least for now, there is one scheduling queue per KSE group; KSEs
+ * within the same KSE group compete for threads from the same scheduling
+ * queue. A scope system thread has one KSE in one KSE group; the group
+ * does not use its scheduling queue.
+ */
+struct kse_group {
+ TAILQ_HEAD(, kse) kg_kseq; /* list of KSEs in group */
+ TAILQ_HEAD(, pthread) kg_threadq; /* list of threads in group */
+ TAILQ_ENTRY(kse_group) kg_qe; /* link entry */
+ struct sched_queue kg_schedq; /* scheduling queue */
+ struct lock kg_lock;
+ int kg_threadcount; /* # of assigned threads */
+ int kg_ksecount; /* # of assigned KSEs */
+ int kg_idle_kses;
+ int kg_flags;
+#define KGF_SINGLE_THREAD 0x0001 /* scope system kse group */
+#define KGF_SCHEDQ_INITED 0x0002 /* has an initialized schedq */
+};
+
+/*
+ * Add/remove threads from a KSE's scheduling queue.
+ * For now the scheduling queue is hung off the KSEG.
+ */
+#define KSEG_THRQ_ADD(kseg, thr) \
+do { \
+ TAILQ_INSERT_TAIL(&(kseg)->kg_threadq, thr, kle);\
+ (kseg)->kg_threadcount++; \
+} while (0)
+
+#define KSEG_THRQ_REMOVE(kseg, thr) \
+do { \
+ TAILQ_REMOVE(&(kseg)->kg_threadq, thr, kle); \
+ (kseg)->kg_threadcount--; \
+} while (0)
+
+
+/*
+ * Lock acquire and release for KSEs.
+ */
+#define KSE_LOCK_ACQUIRE(kse, lck) \
+do { \
+ if ((kse)->k_locklevel < MAX_KSE_LOCKLEVEL) { \
+ (kse)->k_locklevel++; \
+ _lock_acquire((lck), \
+ &(kse)->k_lockusers[(kse)->k_locklevel - 1], 0); \
+ } \
+ else \
+ PANIC("Exceeded maximum lock level"); \
+} while (0)
+
+#define KSE_LOCK_RELEASE(kse, lck) \
+do { \
+ if ((kse)->k_locklevel > 0) { \
+ _lock_release((lck), \
+ &(kse)->k_lockusers[(kse)->k_locklevel - 1]); \
+ (kse)->k_locklevel--; \
+ } \
+} while (0)
+
+/*
+ * Lock our own KSEG.
+ */
+#define KSE_LOCK(curkse) \
+ KSE_LOCK_ACQUIRE(curkse, &(curkse)->k_kseg->kg_lock)
+#define KSE_UNLOCK(curkse) \
+ KSE_LOCK_RELEASE(curkse, &(curkse)->k_kseg->kg_lock)
+
+/*
+ * Lock a potentially different KSEG.
+ */
+#define KSE_SCHED_LOCK(curkse, kseg) \
+ KSE_LOCK_ACQUIRE(curkse, &(kseg)->kg_lock)
+#define KSE_SCHED_UNLOCK(curkse, kseg) \
+ KSE_LOCK_RELEASE(curkse, &(kseg)->kg_lock)
+
+/*
+ * Waiting queue manipulation macros (using pqe link):
+ */
+#define KSE_WAITQ_REMOVE(kse, thrd) \
+do { \
+ if (((thrd)->flags & THR_FLAGS_IN_WAITQ) != 0) { \
+ TAILQ_REMOVE(&(kse)->k_schedq->sq_waitq, thrd, pqe); \
+ (thrd)->flags &= ~THR_FLAGS_IN_WAITQ; \
+ } \
+} while (0)
+#define KSE_WAITQ_INSERT(kse, thrd) kse_waitq_insert(thrd)
+#define KSE_WAITQ_FIRST(kse) TAILQ_FIRST(&(kse)->k_schedq->sq_waitq)
+
+#define KSE_WAKEUP(kse) kse_wakeup(&(kse)->k_kcb->kcb_kmbx)
+
+/*
+ * TailQ initialization values.
+ */
+#define TAILQ_INITIALIZER { NULL, NULL }
+
+/*
+ * lock initialization values.
+ */
+#define LCK_INITIALIZER { NULL, NULL, LCK_DEFAULT }
+
+struct pthread_mutex {
+ /*
+ * Lock for accesses to this structure.
+ */
+ struct lock m_lock;
+ enum pthread_mutextype m_type;
+ int m_protocol;
+ TAILQ_HEAD(mutex_head, pthread) m_queue;
+ struct pthread *m_owner;
+ long m_flags;
+ int m_count;
+ int m_refcount;
+
+ /*
+ * Used for priority inheritence and protection.
+ *
+ * m_prio - For priority inheritence, the highest active
+ * priority (threads locking the mutex inherit
+ * this priority). For priority protection, the
+ * ceiling priority of this mutex.
+ * m_saved_prio - mutex owners inherited priority before
+ * taking the mutex, restored when the owner
+ * unlocks the mutex.
+ */
+ int m_prio;
+ int m_saved_prio;
+
+ /*
+ * Link for list of all mutexes a thread currently owns.
+ */
+ TAILQ_ENTRY(pthread_mutex) m_qe;
+};
+
+/*
+ * Flags for mutexes.
+ */
+#define MUTEX_FLAGS_PRIVATE 0x01
+#define MUTEX_FLAGS_INITED 0x02
+#define MUTEX_FLAGS_BUSY 0x04
+
+/*
+ * Static mutex initialization values.
+ */
+#define PTHREAD_MUTEX_STATIC_INITIALIZER \
+ { LCK_INITIALIZER, PTHREAD_MUTEX_DEFAULT, PTHREAD_PRIO_NONE, \
+ TAILQ_INITIALIZER, NULL, MUTEX_FLAGS_PRIVATE, 0, 0, 0, 0, \
+ TAILQ_INITIALIZER }
+
+struct pthread_mutex_attr {
+ enum pthread_mutextype m_type;
+ int m_protocol;
+ int m_ceiling;
+ long m_flags;
+};
+
+#define PTHREAD_MUTEXATTR_STATIC_INITIALIZER \
+ { PTHREAD_MUTEX_DEFAULT, PTHREAD_PRIO_NONE, 0, MUTEX_FLAGS_PRIVATE }
+
+/*
+ * Condition variable definitions.
+ */
+enum pthread_cond_type {
+ COND_TYPE_FAST,
+ COND_TYPE_MAX
+};
+
+struct pthread_cond {
+ /*
+ * Lock for accesses to this structure.
+ */
+ struct lock c_lock;
+ enum pthread_cond_type c_type;
+ TAILQ_HEAD(cond_head, pthread) c_queue;
+ struct pthread_mutex *c_mutex;
+ long c_flags;
+ long c_seqno;
+};
+
+struct pthread_cond_attr {
+ enum pthread_cond_type c_type;
+ long c_flags;
+};
+
+struct pthread_barrier {
+ pthread_mutex_t b_lock;
+ pthread_cond_t b_cond;
+ int b_count;
+ int b_waiters;
+ int b_generation;
+};
+
+struct pthread_barrierattr {
+ int pshared;
+};
+
+struct pthread_spinlock {
+ volatile int s_lock;
+ pthread_t s_owner;
+};
+
+/*
+ * Flags for condition variables.
+ */
+#define COND_FLAGS_PRIVATE 0x01
+#define COND_FLAGS_INITED 0x02
+#define COND_FLAGS_BUSY 0x04
+
+/*
+ * Static cond initialization values.
+ */
+#define PTHREAD_COND_STATIC_INITIALIZER \
+ { LCK_INITIALIZER, COND_TYPE_FAST, TAILQ_INITIALIZER, \
+ NULL, NULL, 0, 0 }
+
+/*
+ * Cleanup definitions.
+ */
+struct pthread_cleanup {
+ struct pthread_cleanup *next;
+ void (*routine) (void *);
+ void *routine_arg;
+ int onstack;
+};
+
+#define THR_CLEANUP_PUSH(td, func, arg) { \
+ struct pthread_cleanup __cup; \
+ \
+ __cup.routine = func; \
+ __cup.routine_arg = arg; \
+ __cup.onstack = 1; \
+ __cup.next = (td)->cleanup; \
+ (td)->cleanup = &__cup;
+
+#define THR_CLEANUP_POP(td, exec) \
+ (td)->cleanup = __cup.next; \
+ if ((exec) != 0) \
+ __cup.routine(__cup.routine_arg); \
+}
+
+struct pthread_atfork {
+ TAILQ_ENTRY(pthread_atfork) qe;
+ void (*prepare)(void);
+ void (*parent)(void);
+ void (*child)(void);
+};
+
+struct pthread_attr {
+ int sched_policy;
+ int sched_inherit;
+ int sched_interval;
+ int prio;
+ int suspend;
+#define THR_STACK_USER 0x100 /* 0xFF reserved for <pthread.h> */
+#define THR_SIGNAL_THREAD 0x200 /* This is a signal thread */
+ int flags;
+ void *arg_attr;
+ void (*cleanup_attr) (void *);
+ void *stackaddr_attr;
+ size_t stacksize_attr;
+ size_t guardsize_attr;
+};
+
+/*
+ * Thread creation state attributes.
+ */
+#define THR_CREATE_RUNNING 0
+#define THR_CREATE_SUSPENDED 1
+
+/*
+ * Miscellaneous definitions.
+ */
+#define THR_STACK32_DEFAULT (1 * 1024 * 1024)
+#define THR_STACK64_DEFAULT (2 * 1024 * 1024)
+
+/*
+ * Maximum size of initial thread's stack. This perhaps deserves to be larger
+ * than the stacks of other threads, since many applications are likely to run
+ * almost entirely on this stack.
+ */
+#define THR_STACK32_INITIAL (2 * 1024 * 1024)
+#define THR_STACK64_INITIAL (4 * 1024 * 1024)
+
+/*
+ * Define the different priority ranges. All applications have thread
+ * priorities constrained within 0-31. The threads library raises the
+ * priority when delivering signals in order to ensure that signal
+ * delivery happens (from the POSIX spec) "as soon as possible".
+ * In the future, the threads library will also be able to map specific
+ * threads into real-time (cooperating) processes or kernel threads.
+ * The RT and SIGNAL priorities will be used internally and added to
+ * thread base priorities so that the scheduling queue can handle both
+ * normal and RT priority threads with and without signal handling.
+ *
+ * The approach taken is that, within each class, signal delivery
+ * always has priority over thread execution.
+ */
+#define THR_DEFAULT_PRIORITY 15
+#define THR_MIN_PRIORITY 0
+#define THR_MAX_PRIORITY 31 /* 0x1F */
+#define THR_SIGNAL_PRIORITY 32 /* 0x20 */
+#define THR_RT_PRIORITY 64 /* 0x40 */
+#define THR_FIRST_PRIORITY THR_MIN_PRIORITY
+#define THR_LAST_PRIORITY \
+ (THR_MAX_PRIORITY + THR_SIGNAL_PRIORITY + THR_RT_PRIORITY)
+#define THR_BASE_PRIORITY(prio) ((prio) & THR_MAX_PRIORITY)
+
+/*
+ * Clock resolution in microseconds.
+ */
+#define CLOCK_RES_USEC 10000
+
+/*
+ * Time slice period in microseconds.
+ */
+#define TIMESLICE_USEC 20000
+
+/*
+ * XXX - Define a thread-safe macro to get the current time of day
+ * which is updated at regular intervals by something.
+ *
+ * For now, we just make the system call to get the time.
+ */
+#define KSE_GET_TOD(curkse, tsp) \
+do { \
+ *tsp = (curkse)->k_kcb->kcb_kmbx.km_timeofday; \
+ if ((tsp)->tv_sec == 0) \
+ clock_gettime(CLOCK_REALTIME, tsp); \
+} while (0)
+
+struct pthread_rwlockattr {
+ int pshared;
+};
+
+struct pthread_rwlock {
+ pthread_mutex_t lock; /* monitor lock */
+ pthread_cond_t read_signal;
+ pthread_cond_t write_signal;
+ int state; /* 0 = idle >0 = # of readers -1 = writer */
+ int blocked_writers;
+};
+
+/*
+ * Thread states.
+ */
+enum pthread_state {
+ PS_RUNNING,
+ PS_LOCKWAIT,
+ PS_MUTEX_WAIT,
+ PS_COND_WAIT,
+ PS_SLEEP_WAIT,
+ PS_SIGSUSPEND,
+ PS_SIGWAIT,
+ PS_JOIN,
+ PS_SUSPENDED,
+ PS_DEAD,
+ PS_DEADLOCK,
+ PS_STATE_MAX
+};
+
+struct sigwait_data {
+ sigset_t *waitset;
+ siginfo_t *siginfo; /* used to save siginfo for sigwaitinfo() */
+};
+
+union pthread_wait_data {
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+ struct lock *lock;
+ struct sigwait_data *sigwait;
+};
+
+/*
+ * Define a continuation routine that can be used to perform a
+ * transfer of control:
+ */
+typedef void (*thread_continuation_t) (void *);
+
+/*
+ * This stores a thread's state prior to running a signal handler.
+ * It is used when a signal is delivered to a thread blocked in
+ * userland. If the signal handler returns normally, the thread's
+ * state is restored from here.
+ */
+struct pthread_sigframe {
+ int psf_valid;
+ int psf_flags;
+ int psf_cancelflags;
+ int psf_interrupted;
+ int psf_timeout;
+ int psf_signo;
+ enum pthread_state psf_state;
+ union pthread_wait_data psf_wait_data;
+ struct timespec psf_wakeup_time;
+ sigset_t psf_sigset;
+ sigset_t psf_sigmask;
+ int psf_seqno;
+ thread_continuation_t psf_continuation;
+};
+
+struct join_status {
+ struct pthread *thread;
+ void *ret;
+ int error;
+};
+
+struct pthread_specific_elem {
+ const void *data;
+ int seqno;
+};
+
+struct pthread_key {
+ volatile int allocated;
+ volatile int count;
+ int seqno;
+ void (*destructor) (void *);
+};
+
+#define MAX_THR_LOCKLEVEL 5
+/*
+ * Thread structure.
+ */
+struct pthread {
+ /* Thread control block */
+ struct tcb *tcb;
+
+ /*
+ * Magic value to help recognize a valid thread structure
+ * from an invalid one:
+ */
+#define THR_MAGIC ((u_int32_t) 0xd09ba115)
+ u_int32_t magic;
+ char *name;
+ u_int64_t uniqueid; /* for gdb */
+
+ /* Queue entry for list of all threads: */
+ TAILQ_ENTRY(pthread) tle; /* link for all threads in process */
+ TAILQ_ENTRY(pthread) kle; /* link for all threads in KSE/KSEG */
+
+ /* Queue entry for GC lists: */
+ TAILQ_ENTRY(pthread) gcle;
+
+ /* Hash queue entry */
+ LIST_ENTRY(pthread) hle;
+
+ /*
+ * Lock for accesses to this thread structure.
+ */
+ struct lock lock;
+ struct lockuser lockusers[MAX_THR_LOCKLEVEL];
+ int locklevel;
+ kse_critical_t critical[MAX_KSE_LOCKLEVEL];
+ struct kse *kse;
+ struct kse_group *kseg;
+
+ /*
+ * Thread start routine, argument, stack pointer and thread
+ * attributes.
+ */
+ void *(*start_routine)(void *);
+ void *arg;
+ struct pthread_attr attr;
+
+ int active; /* thread running */
+ int blocked; /* thread blocked in kernel */
+ int need_switchout;
+
+ /*
+ * Used for tracking delivery of signal handlers.
+ */
+ siginfo_t *siginfo;
+ thread_continuation_t sigbackout;
+
+ /*
+ * Cancelability flags - the lower 2 bits are used by cancel
+ * definitions in pthread.h
+ */
+#define THR_AT_CANCEL_POINT 0x0004
+#define THR_CANCELLING 0x0008
+#define THR_CANCEL_NEEDED 0x0010
+ int cancelflags;
+
+ thread_continuation_t continuation;
+
+ /*
+ * The thread's base and pending signal masks. The active
+ * signal mask is stored in the thread's context (in mailbox).
+ */
+ sigset_t sigmask;
+ sigset_t sigpend;
+ sigset_t *oldsigmask;
+ volatile int check_pending;
+ int refcount;
+
+ /* Thread state: */
+ enum pthread_state state;
+ volatile int lock_switch;
+
+ /*
+ * Number of microseconds accumulated by this thread when
+ * time slicing is active.
+ */
+ long slice_usec;
+
+ /*
+ * Time to wake up thread. This is used for sleeping threads and
+ * for any operation which may time out (such as select).
+ */
+ struct timespec wakeup_time;
+
+ /* TRUE if operation has timed out. */
+ int timeout;
+
+ /*
+ * Error variable used instead of errno. The function __error()
+ * returns a pointer to this.
+ */
+ int error;
+
+ /*
+ * The joiner is the thread that is joining to this thread. The
+ * join status keeps track of a join operation to another thread.
+ */
+ struct pthread *joiner;
+ struct join_status join_status;
+
+ /*
+ * The current thread can belong to only one scheduling queue at
+ * a time (ready or waiting queue). It can also belong to:
+ *
+ * o A queue of threads waiting for a mutex
+ * o A queue of threads waiting for a condition variable
+ *
+ * It is possible for a thread to belong to more than one of the
+ * above queues if it is handling a signal. A thread may only
+ * enter a mutex or condition variable queue when it is not
+ * being called from a signal handler. If a thread is a member
+ * of one of these queues when a signal handler is invoked, it
+ * must be removed from the queue before invoking the handler
+ * and then added back to the queue after return from the handler.
+ *
+ * Use pqe for the scheduling queue link (both ready and waiting),
+ * sqe for synchronization (mutex, condition variable, and join)
+ * queue links, and qe for all other links.
+ */
+ TAILQ_ENTRY(pthread) pqe; /* priority, wait queues link */
+ TAILQ_ENTRY(pthread) sqe; /* synchronization queue link */
+
+ /* Wait data. */
+ union pthread_wait_data data;
+
+ /*
+ * Set to TRUE if a blocking operation was
+ * interrupted by a signal:
+ */
+ int interrupted;
+
+ /*
+ * Set to non-zero when this thread has entered a critical
+ * region. We allow for recursive entries into critical regions.
+ */
+ int critical_count;
+
+ /*
+ * Set to TRUE if this thread should yield after leaving a
+ * critical region to check for signals, messages, etc.
+ */
+ int critical_yield;
+
+ int sflags;
+#define THR_FLAGS_IN_SYNCQ 0x0001
+
+ /* Miscellaneous flags; only set with scheduling lock held. */
+ int flags;
+#define THR_FLAGS_PRIVATE 0x0001
+#define THR_FLAGS_IN_WAITQ 0x0002 /* in waiting queue using pqe link */
+#define THR_FLAGS_IN_RUNQ 0x0004 /* in run queue using pqe link */
+#define THR_FLAGS_EXITING 0x0008 /* thread is exiting */
+#define THR_FLAGS_SUSPENDED 0x0010 /* thread is suspended */
+
+ /* Thread list flags; only set with thread list lock held. */
+#define TLFLAGS_GC_SAFE 0x0001 /* thread safe for cleaning */
+#define TLFLAGS_IN_TDLIST 0x0002 /* thread in all thread list */
+#define TLFLAGS_IN_GCLIST 0x0004 /* thread in gc list */
+ int tlflags;
+
+ /*
+ * Base priority is the user setable and retrievable priority
+ * of the thread. It is only affected by explicit calls to
+ * set thread priority and upon thread creation via a thread
+ * attribute or default priority.
+ */
+ char base_priority;
+
+ /*
+ * Inherited priority is the priority a thread inherits by
+ * taking a priority inheritence or protection mutex. It
+ * is not affected by base priority changes. Inherited
+ * priority defaults to and remains 0 until a mutex is taken
+ * that is being waited on by any other thread whose priority
+ * is non-zero.
+ */
+ char inherited_priority;
+
+ /*
+ * Active priority is always the maximum of the threads base
+ * priority and inherited priority. When there is a change
+ * in either the base or inherited priority, the active
+ * priority must be recalculated.
+ */
+ char active_priority;
+
+ /* Number of priority ceiling or protection mutexes owned. */
+ int priority_mutex_count;
+
+ /* Number rwlocks rdlocks held. */
+ int rdlock_count;
+
+ /*
+ * Queue of currently owned mutexes.
+ */
+ TAILQ_HEAD(, pthread_mutex) mutexq;
+
+ void *ret;
+ struct pthread_specific_elem *specific;
+ int specific_data_count;
+
+ /* Alternative stack for sigaltstack() */
+ stack_t sigstk;
+
+ /*
+ * Current locks bitmap for rtld.
+ */
+ int rtld_bits;
+
+ /* Cleanup handlers Link List */
+ struct pthread_cleanup *cleanup;
+ char *fname; /* Ptr to source file name */
+ int lineno; /* Source line number. */
+};
+
+/*
+ * Critical regions can also be detected by looking at the threads
+ * current lock level. Ensure these macros increment and decrement
+ * the lock levels such that locks can not be held with a lock level
+ * of 0.
+ */
+#define THR_IN_CRITICAL(thrd) \
+ (((thrd)->locklevel > 0) || \
+ ((thrd)->critical_count > 0))
+
+#define THR_YIELD_CHECK(thrd) \
+do { \
+ if (!THR_IN_CRITICAL(thrd)) { \
+ if (__predict_false(_libkse_debug)) \
+ _thr_debug_check_yield(thrd); \
+ if ((thrd)->critical_yield != 0) \
+ _thr_sched_switch(thrd); \
+ if ((thrd)->check_pending != 0) \
+ _thr_sig_check_pending(thrd); \
+ } \
+} while (0)
+
+#define THR_LOCK_ACQUIRE(thrd, lck) \
+do { \
+ if ((thrd)->locklevel < MAX_THR_LOCKLEVEL) { \
+ THR_DEACTIVATE_LAST_LOCK(thrd); \
+ (thrd)->locklevel++; \
+ _lock_acquire((lck), \
+ &(thrd)->lockusers[(thrd)->locklevel - 1], \
+ (thrd)->active_priority); \
+ } else \
+ PANIC("Exceeded maximum lock level"); \
+} while (0)
+
+#define THR_LOCK_RELEASE(thrd, lck) \
+do { \
+ if ((thrd)->locklevel > 0) { \
+ _lock_release((lck), \
+ &(thrd)->lockusers[(thrd)->locklevel - 1]); \
+ (thrd)->locklevel--; \
+ THR_ACTIVATE_LAST_LOCK(thrd); \
+ if ((thrd)->locklevel == 0) \
+ THR_YIELD_CHECK(thrd); \
+ } \
+} while (0)
+
+#define THR_ACTIVATE_LAST_LOCK(thrd) \
+do { \
+ if ((thrd)->locklevel > 0) \
+ _lockuser_setactive( \
+ &(thrd)->lockusers[(thrd)->locklevel - 1], 1); \
+} while (0)
+
+#define THR_DEACTIVATE_LAST_LOCK(thrd) \
+do { \
+ if ((thrd)->locklevel > 0) \
+ _lockuser_setactive( \
+ &(thrd)->lockusers[(thrd)->locklevel - 1], 0); \
+} while (0)
+
+/*
+ * For now, threads will have their own lock separate from their
+ * KSE scheduling lock.
+ */
+#define THR_LOCK(thr) THR_LOCK_ACQUIRE(thr, &(thr)->lock)
+#define THR_UNLOCK(thr) THR_LOCK_RELEASE(thr, &(thr)->lock)
+#define THR_THREAD_LOCK(curthrd, thr) THR_LOCK_ACQUIRE(curthrd, &(thr)->lock)
+#define THR_THREAD_UNLOCK(curthrd, thr) THR_LOCK_RELEASE(curthrd, &(thr)->lock)
+
+/*
+ * Priority queue manipulation macros (using pqe link). We use
+ * the thread's kseg link instead of the kse link because a thread
+ * does not (currently) have a statically assigned kse.
+ */
+#define THR_RUNQ_INSERT_HEAD(thrd) \
+ _pq_insert_head(&(thrd)->kseg->kg_schedq.sq_runq, thrd)
+#define THR_RUNQ_INSERT_TAIL(thrd) \
+ _pq_insert_tail(&(thrd)->kseg->kg_schedq.sq_runq, thrd)
+#define THR_RUNQ_REMOVE(thrd) \
+ _pq_remove(&(thrd)->kseg->kg_schedq.sq_runq, thrd)
+
+/*
+ * Macros to insert/remove threads to the all thread list and
+ * the gc list.
+ */
+#define THR_LIST_ADD(thrd) do { \
+ if (((thrd)->tlflags & TLFLAGS_IN_TDLIST) == 0) { \
+ TAILQ_INSERT_HEAD(&_thread_list, thrd, tle); \
+ _thr_hash_add(thrd); \
+ (thrd)->tlflags |= TLFLAGS_IN_TDLIST; \
+ } \
+} while (0)
+#define THR_LIST_REMOVE(thrd) do { \
+ if (((thrd)->tlflags & TLFLAGS_IN_TDLIST) != 0) { \
+ TAILQ_REMOVE(&_thread_list, thrd, tle); \
+ _thr_hash_remove(thrd); \
+ (thrd)->tlflags &= ~TLFLAGS_IN_TDLIST; \
+ } \
+} while (0)
+#define THR_GCLIST_ADD(thrd) do { \
+ if (((thrd)->tlflags & TLFLAGS_IN_GCLIST) == 0) { \
+ TAILQ_INSERT_HEAD(&_thread_gc_list, thrd, gcle);\
+ (thrd)->tlflags |= TLFLAGS_IN_GCLIST; \
+ _gc_count++; \
+ } \
+} while (0)
+#define THR_GCLIST_REMOVE(thrd) do { \
+ if (((thrd)->tlflags & TLFLAGS_IN_GCLIST) != 0) { \
+ TAILQ_REMOVE(&_thread_gc_list, thrd, gcle); \
+ (thrd)->tlflags &= ~TLFLAGS_IN_GCLIST; \
+ _gc_count--; \
+ } \
+} while (0)
+
+#define GC_NEEDED() (atomic_load_acq_int(&_gc_count) >= 5)
+
+/*
+ * Locking the scheduling queue for another thread uses that thread's
+ * KSEG lock.
+ */
+#define THR_SCHED_LOCK(curthr, thr) do { \
+ (curthr)->critical[(curthr)->locklevel] = _kse_critical_enter(); \
+ (curthr)->locklevel++; \
+ KSE_SCHED_LOCK((curthr)->kse, (thr)->kseg); \
+} while (0)
+
+#define THR_SCHED_UNLOCK(curthr, thr) do { \
+ KSE_SCHED_UNLOCK((curthr)->kse, (thr)->kseg); \
+ (curthr)->locklevel--; \
+ _kse_critical_leave((curthr)->critical[(curthr)->locklevel]); \
+} while (0)
+
+/* Take the scheduling lock with the intent to call the scheduler. */
+#define THR_LOCK_SWITCH(curthr) do { \
+ (void)_kse_critical_enter(); \
+ KSE_SCHED_LOCK((curthr)->kse, (curthr)->kseg); \
+} while (0)
+#define THR_UNLOCK_SWITCH(curthr) do { \
+ KSE_SCHED_UNLOCK((curthr)->kse, (curthr)->kseg);\
+} while (0)
+
+#define THR_CRITICAL_ENTER(thr) (thr)->critical_count++
+#define THR_CRITICAL_LEAVE(thr) do { \
+ (thr)->critical_count--; \
+ if (((thr)->critical_yield != 0) && \
+ ((thr)->critical_count == 0)) { \
+ (thr)->critical_yield = 0; \
+ _thr_sched_switch(thr); \
+ } \
+} while (0)
+
+#define THR_IS_ACTIVE(thrd) \
+ ((thrd)->kse != NULL) && ((thrd)->kse->k_curthread == (thrd))
+
+#define THR_IN_SYNCQ(thrd) (((thrd)->sflags & THR_FLAGS_IN_SYNCQ) != 0)
+
+#define THR_IS_SUSPENDED(thrd) \
+ (((thrd)->state == PS_SUSPENDED) || \
+ (((thrd)->flags & THR_FLAGS_SUSPENDED) != 0))
+#define THR_IS_EXITING(thrd) (((thrd)->flags & THR_FLAGS_EXITING) != 0)
+#define DBG_CAN_RUN(thrd) (((thrd)->tcb->tcb_tmbx.tm_dflags & \
+ TMDF_SUSPEND) == 0)
+
+extern int __isthreaded;
+
+static inline int
+_kse_isthreaded(void)
+{
+ return (__isthreaded != 0);
+}
+
+/*
+ * Global variables for the pthread kernel.
+ */
+
+SCLASS void *_usrstack SCLASS_PRESET(NULL);
+SCLASS struct kse *_kse_initial SCLASS_PRESET(NULL);
+SCLASS struct pthread *_thr_initial SCLASS_PRESET(NULL);
+/* For debugger */
+SCLASS int _libkse_debug SCLASS_PRESET(0);
+SCLASS int _thread_activated SCLASS_PRESET(0);
+SCLASS int _thread_scope_system SCLASS_PRESET(0);
+
+/* List of all threads: */
+SCLASS TAILQ_HEAD(, pthread) _thread_list
+ SCLASS_PRESET(TAILQ_HEAD_INITIALIZER(_thread_list));
+
+/* List of threads needing GC: */
+SCLASS TAILQ_HEAD(, pthread) _thread_gc_list
+ SCLASS_PRESET(TAILQ_HEAD_INITIALIZER(_thread_gc_list));
+
+SCLASS int _thread_active_threads SCLASS_PRESET(1);
+
+SCLASS TAILQ_HEAD(atfork_head, pthread_atfork) _thr_atfork_list;
+SCLASS pthread_mutex_t _thr_atfork_mutex;
+
+/* Default thread attributes: */
+SCLASS struct pthread_attr _pthread_attr_default
+ SCLASS_PRESET({
+ SCHED_RR, 0, TIMESLICE_USEC, THR_DEFAULT_PRIORITY,
+ THR_CREATE_RUNNING, PTHREAD_CREATE_JOINABLE, NULL,
+ NULL, NULL, /* stacksize */0, /* guardsize */0
+ });
+
+/* Default mutex attributes: */
+SCLASS struct pthread_mutex_attr _pthread_mutexattr_default
+ SCLASS_PRESET({PTHREAD_MUTEX_DEFAULT, PTHREAD_PRIO_NONE, 0, 0 });
+
+/* Default condition variable attributes: */
+SCLASS struct pthread_cond_attr _pthread_condattr_default
+ SCLASS_PRESET({COND_TYPE_FAST, 0});
+
+/* Clock resolution in usec. */
+SCLASS int _clock_res_usec SCLASS_PRESET(CLOCK_RES_USEC);
+
+/* Array of signal actions for this process: */
+SCLASS struct sigaction _thread_sigact[_SIG_MAXSIG];
+
+/*
+ * Lock for above count of dummy handlers and for the process signal
+ * mask and pending signal sets.
+ */
+SCLASS struct lock _thread_signal_lock;
+
+/* Pending signals and mask for this process: */
+SCLASS sigset_t _thr_proc_sigpending;
+SCLASS siginfo_t _thr_proc_siginfo[_SIG_MAXSIG];
+
+SCLASS pid_t _thr_pid SCLASS_PRESET(0);
+
+/* Garbage collector lock. */
+SCLASS struct lock _gc_lock;
+SCLASS int _gc_check SCLASS_PRESET(0);
+SCLASS int _gc_count SCLASS_PRESET(0);
+
+SCLASS struct lock _mutex_static_lock;
+SCLASS struct lock _rwlock_static_lock;
+SCLASS struct lock _keytable_lock;
+SCLASS struct lock _thread_list_lock;
+SCLASS int _thr_guard_default;
+SCLASS int _thr_stack_default;
+SCLASS int _thr_stack_initial;
+SCLASS int _thr_page_size;
+SCLASS pthread_t _thr_sig_daemon;
+SCLASS int _thr_debug_flags SCLASS_PRESET(0);
+
+/* Undefine the storage class and preset specifiers: */
+#undef SCLASS
+#undef SCLASS_PRESET
+
+
+/*
+ * Function prototype definitions.
+ */
+__BEGIN_DECLS
+int _cond_reinit(pthread_cond_t *);
+struct kse *_kse_alloc(struct pthread *, int sys_scope);
+kse_critical_t _kse_critical_enter(void);
+void _kse_critical_leave(kse_critical_t);
+int _kse_in_critical(void);
+void _kse_free(struct pthread *, struct kse *);
+void _kse_init(void);
+struct kse_group *_kseg_alloc(struct pthread *);
+void _kse_lock_wait(struct lock *, struct lockuser *lu);
+void _kse_lock_wakeup(struct lock *, struct lockuser *lu);
+void _kse_single_thread(struct pthread *);
+int _kse_setthreaded(int);
+void _kseg_free(struct kse_group *);
+int _mutex_cv_lock(pthread_mutex_t *);
+int _mutex_cv_unlock(pthread_mutex_t *);
+void _mutex_notify_priochange(struct pthread *, struct pthread *, int);
+int _mutex_reinit(struct pthread_mutex *);
+void _mutex_unlock_private(struct pthread *);
+void _libpthread_init(struct pthread *);
+int _pq_alloc(struct pq_queue *, int, int);
+void _pq_free(struct pq_queue *);
+int _pq_init(struct pq_queue *);
+void _pq_remove(struct pq_queue *pq, struct pthread *);
+void _pq_insert_head(struct pq_queue *pq, struct pthread *);
+void _pq_insert_tail(struct pq_queue *pq, struct pthread *);
+struct pthread *_pq_first(struct pq_queue *pq);
+struct pthread *_pq_first_debug(struct pq_queue *pq);
+void *_pthread_getspecific(pthread_key_t);
+int _pthread_key_create(pthread_key_t *, void (*) (void *));
+int _pthread_key_delete(pthread_key_t);
+int _pthread_mutex_destroy(pthread_mutex_t *);
+int _pthread_mutex_init(pthread_mutex_t *, const pthread_mutexattr_t *);
+int _pthread_mutex_lock(pthread_mutex_t *);
+int _pthread_mutex_trylock(pthread_mutex_t *);
+int _pthread_mutex_unlock(pthread_mutex_t *);
+int _pthread_mutexattr_init(pthread_mutexattr_t *);
+int _pthread_mutexattr_destroy(pthread_mutexattr_t *);
+int _pthread_mutexattr_settype(pthread_mutexattr_t *, int);
+int _pthread_once(pthread_once_t *, void (*) (void));
+int _pthread_rwlock_init(pthread_rwlock_t *, const pthread_rwlockattr_t *);
+int _pthread_rwlock_destroy (pthread_rwlock_t *);
+struct pthread *_pthread_self(void);
+int _pthread_setspecific(pthread_key_t, const void *);
+void _pthread_yield(void);
+void _pthread_cleanup_push(void (*routine) (void *), void *routine_arg);
+void _pthread_cleanup_pop(int execute);
+struct pthread *_thr_alloc(struct pthread *);
+void _thr_exit(char *, int, char *);
+void _thr_exit_cleanup(void);
+void _thr_lock_wait(struct lock *lock, struct lockuser *lu);
+void _thr_lock_wakeup(struct lock *lock, struct lockuser *lu);
+void _thr_mutex_reinit(pthread_mutex_t *);
+int _thr_ref_add(struct pthread *, struct pthread *, int);
+void _thr_ref_delete(struct pthread *, struct pthread *);
+void _thr_rtld_init(void);
+void _thr_rtld_fini(void);
+int _thr_schedule_add(struct pthread *, struct pthread *);
+void _thr_schedule_remove(struct pthread *, struct pthread *);
+void _thr_setrunnable(struct pthread *curthread, struct pthread *thread);
+struct kse_mailbox *_thr_setrunnable_unlocked(struct pthread *thread);
+struct kse_mailbox *_thr_sig_add(struct pthread *, int, siginfo_t *);
+void _thr_sig_dispatch(struct kse *, int, siginfo_t *);
+int _thr_stack_alloc(struct pthread_attr *);
+void _thr_stack_free(struct pthread_attr *);
+void _thr_exit_cleanup(void);
+void _thr_free(struct pthread *, struct pthread *);
+void _thr_gc(struct pthread *);
+void _thr_panic_exit(char *, int, char *);
+void _thread_cleanupspecific(void);
+void _thread_dump_info(void);
+void _thread_printf(int, const char *, ...);
+void _thr_sched_switch(struct pthread *);
+void _thr_sched_switch_unlocked(struct pthread *);
+void _thr_set_timeout(const struct timespec *);
+void _thr_seterrno(struct pthread *, int);
+void _thr_sig_handler(int, siginfo_t *, ucontext_t *);
+void _thr_sig_check_pending(struct pthread *);
+void _thr_sig_rundown(struct pthread *, ucontext_t *);
+void _thr_sig_send(struct pthread *pthread, int sig);
+void _thr_sigframe_restore(struct pthread *thread, struct pthread_sigframe *psf);
+void _thr_spinlock_init(void);
+void _thr_cancel_enter(struct pthread *);
+void _thr_cancel_leave(struct pthread *, int);
+int _thr_setconcurrency(int new_level);
+int _thr_setmaxconcurrency(void);
+void _thr_critical_enter(struct pthread *);
+void _thr_critical_leave(struct pthread *);
+int _thr_start_sig_daemon(void);
+int _thr_getprocsig(int sig, siginfo_t *siginfo);
+int _thr_getprocsig_unlocked(int sig, siginfo_t *siginfo);
+void _thr_signal_init(void);
+void _thr_signal_deinit(void);
+void _thr_hash_add(struct pthread *);
+void _thr_hash_remove(struct pthread *);
+struct pthread *_thr_hash_find(struct pthread *);
+void _thr_finish_cancellation(void *arg);
+int _thr_sigonstack(void *sp);
+void _thr_debug_check_yield(struct pthread *);
+
+/*
+ * Aliases for _pthread functions. Should be called instead of
+ * originals if PLT replocation is unwanted at runtme.
+ */
+int _thr_cond_broadcast(pthread_cond_t *);
+int _thr_cond_signal(pthread_cond_t *);
+int _thr_cond_wait(pthread_cond_t *, pthread_mutex_t *);
+int _thr_mutex_lock(pthread_mutex_t *);
+int _thr_mutex_unlock(pthread_mutex_t *);
+int _thr_rwlock_rdlock (pthread_rwlock_t *);
+int _thr_rwlock_wrlock (pthread_rwlock_t *);
+int _thr_rwlock_unlock (pthread_rwlock_t *);
+
+/* #include <sys/aio.h> */
+#ifdef _SYS_AIO_H_
+int __sys_aio_suspend(const struct aiocb * const[], int, const struct timespec *);
+#endif
+
+/* #include <fcntl.h> */
+#ifdef _SYS_FCNTL_H_
+int __sys_fcntl(int, int, ...);
+int __sys_open(const char *, int, ...);
+#endif
+
+/* #include <sys/ioctl.h> */
+#ifdef _SYS_IOCTL_H_
+int __sys_ioctl(int, unsigned long, ...);
+#endif
+
+/* #inclde <sched.h> */
+#ifdef _SCHED_H_
+int __sys_sched_yield(void);
+#endif
+
+/* #include <signal.h> */
+#ifdef _SIGNAL_H_
+int __sys_kill(pid_t, int);
+int __sys_sigaction(int, const struct sigaction *, struct sigaction *);
+int __sys_sigpending(sigset_t *);
+int __sys_sigprocmask(int, const sigset_t *, sigset_t *);
+int __sys_sigsuspend(const sigset_t *);
+int __sys_sigreturn(ucontext_t *);
+int __sys_sigaltstack(const struct sigaltstack *, struct sigaltstack *);
+#endif
+
+/* #include <sys/socket.h> */
+#ifdef _SYS_SOCKET_H_
+int __sys_accept(int, struct sockaddr *, socklen_t *);
+int __sys_connect(int, const struct sockaddr *, socklen_t);
+int __sys_sendfile(int, int, off_t, size_t, struct sf_hdtr *,
+ off_t *, int);
+#endif
+
+/* #include <sys/uio.h> */
+#ifdef _SYS_UIO_H_
+ssize_t __sys_readv(int, const struct iovec *, int);
+ssize_t __sys_writev(int, const struct iovec *, int);
+#endif
+
+/* #include <time.h> */
+#ifdef _TIME_H_
+int __sys_nanosleep(const struct timespec *, struct timespec *);
+#endif
+
+/* #include <unistd.h> */
+#ifdef _UNISTD_H_
+int __sys_close(int);
+int __sys_execve(const char *, char * const *, char * const *);
+int __sys_fork(void);
+int __sys_fsync(int);
+pid_t __sys_getpid(void);
+int __sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
+ssize_t __sys_read(int, void *, size_t);
+ssize_t __sys_write(int, const void *, size_t);
+void __sys_exit(int);
+int __sys_sigwait(const sigset_t *, int *);
+int __sys_sigtimedwait(sigset_t *, siginfo_t *, struct timespec *);
+#endif
+
+/* #include <poll.h> */
+#ifdef _SYS_POLL_H_
+int __sys_poll(struct pollfd *, unsigned, int);
+#endif
+
+/* #include <sys/mman.h> */
+#ifdef _SYS_MMAN_H_
+int __sys_msync(void *, size_t, int);
+#endif
+
+#endif /* !_THR_PRIVATE_H */
diff --git a/lib/libkse/thread/thr_pselect.c b/lib/libkse/thread/thr_pselect.c
new file mode 100644
index 0000000..a0e9410
--- /dev/null
+++ b/lib/libkse/thread/thr_pselect.c
@@ -0,0 +1,60 @@
+/*-
+ * Copyright (c) 2002 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. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 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/select.h>
+#include <sys/time.h>
+
+#include <errno.h>
+#include <signal.h>
+#include <pthread.h>
+
+#include "thr_private.h"
+
+extern int __pselect(int count, fd_set *rfds, fd_set *wfds, fd_set *efds,
+ const struct timespec *timo, const sigset_t *mask);
+
+LT10_COMPAT_PRIVATE(_pselect);
+LT10_COMPAT_DEFAULT(pselect);
+
+__weak_reference(_pselect, pselect);
+
+int
+_pselect(int count, fd_set *rfds, fd_set *wfds, fd_set *efds,
+ const struct timespec *timo, const sigset_t *mask)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ _thr_cancel_enter(curthread);
+ ret = __pselect(count, rfds, wfds, efds, timo, mask);
+ _thr_cancel_leave(curthread, 1);
+
+ return (ret);
+}
diff --git a/lib/libkse/thread/thr_pspinlock.c b/lib/libkse/thread/thr_pspinlock.c
new file mode 100644
index 0000000..5836fde
--- /dev/null
+++ b/lib/libkse/thread/thr_pspinlock.c
@@ -0,0 +1,174 @@
+/*-
+ * Copyright (c) 2003 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <errno.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "atomic_ops.h"
+#include "thr_private.h"
+
+#define SPIN_COUNT 10000
+
+LT10_COMPAT_PRIVATE(_pthread_spin_init);
+LT10_COMPAT_DEFAULT(pthread_spin_init);
+LT10_COMPAT_PRIVATE(_pthread_spin_destroy);
+LT10_COMPAT_DEFAULT(pthread_spin_destroy);
+LT10_COMPAT_PRIVATE(_pthread_spin_trylock);
+LT10_COMPAT_DEFAULT(pthread_spin_trylock);
+LT10_COMPAT_PRIVATE(_pthread_spin_lock);
+LT10_COMPAT_DEFAULT(pthread_spin_lock);
+LT10_COMPAT_PRIVATE(_pthread_spin_unlock);
+LT10_COMPAT_DEFAULT(pthread_spin_unlock);
+
+__weak_reference(_pthread_spin_init, pthread_spin_init);
+__weak_reference(_pthread_spin_destroy, pthread_spin_destroy);
+__weak_reference(_pthread_spin_trylock, pthread_spin_trylock);
+__weak_reference(_pthread_spin_lock, pthread_spin_lock);
+__weak_reference(_pthread_spin_unlock, pthread_spin_unlock);
+
+int
+_pthread_spin_init(pthread_spinlock_t *lock, int pshared)
+{
+ struct pthread_spinlock *lck;
+ int ret;
+
+ if (lock == NULL || pshared != PTHREAD_PROCESS_PRIVATE)
+ ret = EINVAL;
+ else if ((lck = malloc(sizeof(struct pthread_spinlock))) == NULL)
+ ret = ENOMEM;
+ else {
+ lck->s_lock = 0;
+ lck->s_owner= NULL;
+ *lock = lck;
+ ret = 0;
+ }
+
+ return (ret);
+}
+
+int
+_pthread_spin_destroy(pthread_spinlock_t *lock)
+{
+ int ret;
+
+ if (lock == NULL || *lock == NULL)
+ ret = EINVAL;
+ else if ((*lock)->s_owner != NULL)
+ ret = EBUSY;
+ else {
+ free(*lock);
+ *lock = NULL;
+ ret = 0;
+ }
+
+ return (ret);
+}
+
+int
+_pthread_spin_trylock(pthread_spinlock_t *lock)
+{
+ struct pthread_spinlock *lck;
+ struct pthread *self = _pthread_self();
+ int oldval, ret;
+
+ if (lock == NULL || (lck = *lock) == NULL)
+ ret = EINVAL;
+ else if (lck->s_owner == self)
+ ret = EDEADLK;
+ else if (lck->s_lock != 0)
+ ret = EBUSY;
+ else {
+ atomic_swap_int((int *)&(lck)->s_lock, 1, &oldval);
+ if (oldval)
+ ret = EBUSY;
+ else {
+ lck->s_owner = _pthread_self();
+ ret = 0;
+ }
+ }
+ return (ret);
+}
+
+int
+_pthread_spin_lock(pthread_spinlock_t *lock)
+{
+ struct pthread_spinlock *lck;
+ struct pthread *self = _pthread_self();
+ int count, oldval, ret;
+
+ if (lock == NULL || (lck = *lock) == NULL)
+ ret = EINVAL;
+ else if (lck->s_owner == self)
+ ret = EDEADLK;
+ else {
+ do {
+ count = SPIN_COUNT;
+ while (lck->s_lock) {
+#ifdef __i386__
+ /* tell cpu we are spinning */
+ __asm __volatile("pause");
+#endif
+ if (--count <= 0) {
+ count = SPIN_COUNT;
+ _pthread_yield();
+ }
+ }
+ atomic_swap_int((int *)&(lck)->s_lock, 1, &oldval);
+ } while (oldval);
+
+ lck->s_owner = self;
+ ret = 0;
+ }
+
+ return (ret);
+}
+
+int
+_pthread_spin_unlock(pthread_spinlock_t *lock)
+{
+ struct pthread_spinlock *lck;
+ int ret;
+
+ if (lock == NULL || (lck = *lock) == NULL)
+ ret = EINVAL;
+ else {
+ if (lck->s_owner != _pthread_self())
+ ret = EPERM;
+ else {
+ lck->s_owner = NULL;
+ atomic_swap_int((int *)&lck->s_lock, 0, &ret);
+ ret = 0;
+ }
+ }
+
+ return (ret);
+}
+
diff --git a/lib/libkse/thread/thr_raise.c b/lib/libkse/thread/thr_raise.c
new file mode 100644
index 0000000..ad4aa39
--- /dev/null
+++ b/lib/libkse/thread/thr_raise.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2003 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 <pthread.h>
+#include <errno.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_raise);
+LT10_COMPAT_DEFAULT(raise);
+
+__weak_reference(_raise, raise);
+
+int
+_raise(int sig)
+{
+ int ret;
+
+ if (!_kse_isthreaded())
+ ret = kill(getpid(), sig);
+ else {
+ ret = pthread_kill(pthread_self(), sig);
+ if (ret != 0) {
+ errno = ret;
+ ret = -1;
+ }
+ }
+ return (ret);
+}
diff --git a/lib/libkse/thread/thr_read.c b/lib/libkse/thread/thr_read.c
new file mode 100644
index 0000000..dc29d1b
--- /dev/null
+++ b/lib/libkse/thread/thr_read.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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/fcntl.h>
+#include <sys/uio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__read);
+LT10_COMPAT_DEFAULT(read);
+
+__weak_reference(__read, read);
+
+ssize_t
+__read(int fd, void *buf, size_t nbytes)
+{
+ struct pthread *curthread = _get_curthread();
+ ssize_t ret;
+
+ _thr_cancel_enter(curthread);
+ ret = __sys_read(fd, buf, nbytes);
+ _thr_cancel_leave(curthread, 1);
+
+ return ret;
+}
diff --git a/lib/libkse/thread/thr_readv.c b/lib/libkse/thread/thr_readv.c
new file mode 100644
index 0000000..c2d9360
--- /dev/null
+++ b/lib/libkse/thread/thr_readv.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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/fcntl.h>
+#include <sys/uio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__readv);
+LT10_COMPAT_DEFAULT(readv);
+
+__weak_reference(__readv, readv);
+
+ssize_t
+__readv(int fd, const struct iovec *iov, int iovcnt)
+{
+ struct pthread *curthread = _get_curthread();
+ ssize_t ret;
+
+ _thr_cancel_enter(curthread);
+ ret = __sys_readv(fd, iov, iovcnt);
+ _thr_cancel_leave(curthread, 1);
+
+ return ret;
+}
diff --git a/lib/libkse/thread/thr_resume_np.c b/lib/libkse/thread/thr_resume_np.c
new file mode 100644
index 0000000..70c5f17
--- /dev/null
+++ b/lib/libkse/thread/thr_resume_np.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+static struct kse_mailbox *resume_common(struct pthread *);
+
+LT10_COMPAT_PRIVATE(_pthread_resume_np);
+LT10_COMPAT_DEFAULT(pthread_resume_np);
+LT10_COMPAT_PRIVATE(_pthread_resume_all_np);
+LT10_COMPAT_DEFAULT(pthread_resume_all_np);
+
+__weak_reference(_pthread_resume_np, pthread_resume_np);
+__weak_reference(_pthread_resume_all_np, pthread_resume_all_np);
+
+
+/* Resume a thread: */
+int
+_pthread_resume_np(pthread_t thread)
+{
+ struct pthread *curthread = _get_curthread();
+ struct kse_mailbox *kmbx;
+ int ret;
+
+ /* Add a reference to the thread: */
+ if ((ret = _thr_ref_add(curthread, thread, /*include dead*/0)) == 0) {
+ /* Lock the threads scheduling queue: */
+ THR_SCHED_LOCK(curthread, thread);
+ kmbx = resume_common(thread);
+ THR_SCHED_UNLOCK(curthread, thread);
+ _thr_ref_delete(curthread, thread);
+ if (kmbx != NULL)
+ kse_wakeup(kmbx);
+ }
+ return (ret);
+}
+
+void
+_pthread_resume_all_np(void)
+{
+ struct pthread *curthread = _get_curthread();
+ struct pthread *thread;
+ struct kse_mailbox *kmbx;
+ kse_critical_t crit;
+
+ /* Take the thread list lock: */
+ crit = _kse_critical_enter();
+ KSE_LOCK_ACQUIRE(curthread->kse, &_thread_list_lock);
+
+ TAILQ_FOREACH(thread, &_thread_list, tle) {
+ if (thread != curthread) {
+ THR_SCHED_LOCK(curthread, thread);
+ kmbx = resume_common(thread);
+ THR_SCHED_UNLOCK(curthread, thread);
+ if (kmbx != NULL)
+ kse_wakeup(kmbx);
+ }
+ }
+
+ /* Release the thread list lock: */
+ KSE_LOCK_RELEASE(curthread->kse, &_thread_list_lock);
+ _kse_critical_leave(crit);
+}
+
+static struct kse_mailbox *
+resume_common(struct pthread *thread)
+{
+ /* Clear the suspend flag: */
+ thread->flags &= ~THR_FLAGS_SUSPENDED;
+
+ /*
+ * If the thread's state is suspended, that means it is
+ * now runnable but not in any scheduling queue. Set the
+ * state to running and insert it into the run queue.
+ */
+ if (thread->state == PS_SUSPENDED)
+ return (_thr_setrunnable_unlocked(thread));
+ else
+ return (NULL);
+}
diff --git a/lib/libkse/thread/thr_rtld.c b/lib/libkse/thread/thr_rtld.c
new file mode 100644
index 0000000..e813073
--- /dev/null
+++ b/lib/libkse/thread/thr_rtld.c
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 2001 Alexander Kabaev
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 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$
+ */
+#include <sys/cdefs.h>
+#include <stdlib.h>
+
+#include "rtld_lock.h"
+#include "thr_private.h"
+
+static int _thr_rtld_clr_flag(int);
+static void *_thr_rtld_lock_create(void);
+static void _thr_rtld_lock_destroy(void *);
+static void _thr_rtld_lock_release(void *);
+static void _thr_rtld_rlock_acquire(void *);
+static int _thr_rtld_set_flag(int);
+static void _thr_rtld_wlock_acquire(void *);
+
+#ifdef NOTYET
+static void *
+_thr_rtld_lock_create(void)
+{
+ pthread_rwlock_t prwlock;
+ if (_pthread_rwlock_init(&prwlock, NULL))
+ return (NULL);
+ return (prwlock);
+}
+
+static void
+_thr_rtld_lock_destroy(void *lock)
+{
+ pthread_rwlock_t prwlock;
+
+ prwlock = (pthread_rwlock_t)lock;
+ if (prwlock != NULL)
+ _pthread_rwlock_destroy(&prwlock);
+}
+
+static void
+_thr_rtld_rlock_acquire(void *lock)
+{
+ pthread_rwlock_t prwlock;
+
+ prwlock = (pthread_rwlock_t)lock;
+ _thr_rwlock_rdlock(&prwlock);
+}
+
+static void
+_thr_rtld_wlock_acquire(void *lock)
+{
+ pthread_rwlock_t prwlock;
+
+ prwlock = (pthread_rwlock_t)lock;
+ _thr_rwlock_wrlock(&prwlock);
+}
+
+static void
+_thr_rtld_lock_release(void *lock)
+{
+ pthread_rwlock_t prwlock;
+
+ prwlock = (pthread_rwlock_t)lock;
+ _thr_rwlock_unlock(&prwlock);
+}
+
+
+static int
+_thr_rtld_set_flag(int mask)
+{
+ struct pthread *curthread;
+ int bits;
+
+ curthread = _get_curthread();
+ if (curthread != NULL) {
+ bits = curthread->rtld_bits;
+ curthread->rtld_bits |= mask;
+ } else {
+ bits = 0;
+ PANIC("No current thread in rtld call");
+ }
+
+ return (bits);
+}
+
+static int
+_thr_rtld_clr_flag(int mask)
+{
+ struct pthread *curthread;
+ int bits;
+
+ curthread = _get_curthread();
+ if (curthread != NULL) {
+ bits = curthread->rtld_bits;
+ curthread->rtld_bits &= ~mask;
+ } else {
+ bits = 0;
+ PANIC("No current thread in rtld call");
+ }
+ return (bits);
+}
+
+void
+_thr_rtld_init(void)
+{
+ struct RtldLockInfo li;
+
+ li.lock_create = _thr_rtld_lock_create;
+ li.lock_destroy = _thr_rtld_lock_destroy;
+ li.rlock_acquire = _thr_rtld_rlock_acquire;
+ li.wlock_acquire = _thr_rtld_wlock_acquire;
+ li.lock_release = _thr_rtld_lock_release;
+ li.thread_set_flag = _thr_rtld_set_flag;
+ li.thread_clr_flag = _thr_rtld_clr_flag;
+ li.at_fork = NULL;
+ _rtld_thread_init(&li);
+}
+
+void
+_thr_rtld_fini(void)
+{
+ _rtld_thread_init(NULL);
+}
+#endif
+
+struct rtld_kse_lock {
+ struct lock lck;
+ struct kse *owner;
+ kse_critical_t crit;
+ int count;
+ int write;
+};
+
+static void *
+_thr_rtld_lock_create(void)
+{
+ struct rtld_kse_lock *l;
+
+ if ((l = malloc(sizeof(struct rtld_kse_lock))) != NULL) {
+ _lock_init(&l->lck, LCK_ADAPTIVE, _kse_lock_wait,
+ _kse_lock_wakeup);
+ l->owner = NULL;
+ l->count = 0;
+ l->write = 0;
+ }
+ return (l);
+}
+
+static void
+_thr_rtld_lock_destroy(void *lock)
+{
+ /* XXX We really can not free memory after a fork() */
+#if 0
+ struct rtld_kse_lock *l;
+
+ l = (struct rtld_kse_lock *)lock;
+ _lock_destroy(&l->lck);
+ free(l);
+#endif
+ return;
+}
+
+static void
+_thr_rtld_rlock_acquire(void *lock)
+{
+ struct rtld_kse_lock *l;
+ kse_critical_t crit;
+ struct kse *curkse;
+
+ l = (struct rtld_kse_lock *)lock;
+ crit = _kse_critical_enter();
+ curkse = _get_curkse();
+ if (l->owner == curkse) {
+ l->count++;
+ _kse_critical_leave(crit); /* probably not necessary */
+ } else {
+ KSE_LOCK_ACQUIRE(curkse, &l->lck);
+ l->crit = crit;
+ l->owner = curkse;
+ l->count = 1;
+ l->write = 0;
+ }
+}
+
+static void
+_thr_rtld_wlock_acquire(void *lock)
+{
+ struct rtld_kse_lock *l;
+ kse_critical_t crit;
+ struct kse *curkse;
+
+ l = (struct rtld_kse_lock *)lock;
+ crit = _kse_critical_enter();
+ curkse = _get_curkse();
+ if (l->owner == curkse) {
+ _kse_critical_leave(crit);
+ PANIC("Recursive write lock attempt on rtld lock");
+ } else {
+ KSE_LOCK_ACQUIRE(curkse, &l->lck);
+ l->crit = crit;
+ l->owner = curkse;
+ l->count = 1;
+ l->write = 1;
+ }
+}
+
+static void
+_thr_rtld_lock_release(void *lock)
+{
+ struct rtld_kse_lock *l;
+ kse_critical_t crit;
+ struct kse *curkse;
+
+ l = (struct rtld_kse_lock *)lock;
+ crit = _kse_critical_enter();
+ curkse = _get_curkse();
+ if (l->owner != curkse) {
+ /*
+ * We might want to forcibly unlock the rtld lock
+ * and/or disable threaded mode so there is better
+ * chance that the panic will work. Otherwise,
+ * we could end up trying to take the rtld lock
+ * again.
+ */
+ _kse_critical_leave(crit);
+ PANIC("Attempt to unlock rtld lock when not owner.");
+ } else {
+ l->count--;
+ if (l->count == 0) {
+ /*
+ * If there ever is a count associated with
+ * _kse_critical_leave(), we'll need to add
+ * another call to it here with the crit
+ * value from above.
+ */
+ crit = l->crit;
+ l->owner = NULL;
+ l->write = 0;
+ KSE_LOCK_RELEASE(curkse, &l->lck);
+ }
+ _kse_critical_leave(crit);
+ }
+}
+
+
+static int
+_thr_rtld_set_flag(int mask)
+{
+ return (0);
+}
+
+static int
+_thr_rtld_clr_flag(int mask)
+{
+ return (0);
+}
+
+void
+_thr_rtld_init(void)
+{
+ struct RtldLockInfo li;
+
+ li.lock_create = _thr_rtld_lock_create;
+ li.lock_destroy = _thr_rtld_lock_destroy;
+ li.rlock_acquire = _thr_rtld_rlock_acquire;
+ li.wlock_acquire = _thr_rtld_wlock_acquire;
+ li.lock_release = _thr_rtld_lock_release;
+ li.thread_set_flag = _thr_rtld_set_flag;
+ li.thread_clr_flag = _thr_rtld_clr_flag;
+ li.at_fork = NULL;
+ _rtld_thread_init(&li);
+}
+
+void
+_thr_rtld_fini(void)
+{
+ _rtld_thread_init(NULL);
+}
diff --git a/lib/libkse/thread/thr_rwlock.c b/lib/libkse/thread/thr_rwlock.c
new file mode 100644
index 0000000..a0b36de
--- /dev/null
+++ b/lib/libkse/thread/thr_rwlock.c
@@ -0,0 +1,438 @@
+/*-
+ * Copyright (c) 1998 Alex Nash
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#include "namespace.h"
+#include <pthread.h>
+#include "un-namespace.h"
+#include "thr_private.h"
+
+/* maximum number of times a read lock may be obtained */
+#define MAX_READ_LOCKS (INT_MAX - 1)
+
+LT10_COMPAT_PRIVATE(_pthread_rwlock_destroy);
+LT10_COMPAT_DEFAULT(pthread_rwlock_destroy);
+LT10_COMPAT_PRIVATE(_pthread_rwlock_init);
+LT10_COMPAT_DEFAULT(pthread_rwlock_init);
+LT10_COMPAT_PRIVATE(_pthread_rwlock_rdlock);
+LT10_COMPAT_DEFAULT(pthread_rwlock_rdlock);
+LT10_COMPAT_PRIVATE(_pthread_rwlock_timedrdlock);
+LT10_COMPAT_DEFAULT(pthread_rwlock_timedrdlock);
+LT10_COMPAT_PRIVATE(_pthread_rwlock_tryrdlock);
+LT10_COMPAT_DEFAULT(pthread_rwlock_tryrdlock);
+LT10_COMPAT_PRIVATE(_pthread_rwlock_trywrlock);
+LT10_COMPAT_DEFAULT(pthread_rwlock_trywrlock);
+LT10_COMPAT_PRIVATE(_pthread_rwlock_unlock);
+LT10_COMPAT_DEFAULT(pthread_rwlock_unlock);
+LT10_COMPAT_PRIVATE(_pthread_rwlock_wrlock);
+LT10_COMPAT_DEFAULT(pthread_rwlock_wrlock);
+LT10_COMPAT_PRIVATE(_pthread_rwlock_timedwrlock);
+LT10_COMPAT_DEFAULT(pthread_rwlock_timedwrlock);
+
+__weak_reference(_pthread_rwlock_destroy, pthread_rwlock_destroy);
+__weak_reference(_pthread_rwlock_init, pthread_rwlock_init);
+__weak_reference(_pthread_rwlock_rdlock, pthread_rwlock_rdlock);
+__weak_reference(_pthread_rwlock_timedrdlock, pthread_rwlock_timedrdlock);
+__weak_reference(_pthread_rwlock_tryrdlock, pthread_rwlock_tryrdlock);
+__weak_reference(_pthread_rwlock_trywrlock, pthread_rwlock_trywrlock);
+__weak_reference(_pthread_rwlock_unlock, pthread_rwlock_unlock);
+__weak_reference(_pthread_rwlock_wrlock, pthread_rwlock_wrlock);
+__weak_reference(_pthread_rwlock_timedwrlock, pthread_rwlock_timedwrlock);
+
+/*
+ * Prototypes
+ */
+static int init_static(pthread_rwlock_t *rwlock);
+
+
+static int
+init_static(pthread_rwlock_t *rwlock)
+{
+ struct pthread *thread = _get_curthread();
+ int ret;
+
+ THR_LOCK_ACQUIRE(thread, &_rwlock_static_lock);
+
+ if (*rwlock == NULL)
+ ret = _pthread_rwlock_init(rwlock, NULL);
+ else
+ ret = 0;
+
+ THR_LOCK_RELEASE(thread, &_rwlock_static_lock);
+ return (ret);
+}
+
+int
+_pthread_rwlock_destroy (pthread_rwlock_t *rwlock)
+{
+ int ret;
+
+ if (rwlock == NULL)
+ ret = EINVAL;
+ else {
+ pthread_rwlock_t prwlock;
+
+ prwlock = *rwlock;
+
+ _pthread_mutex_destroy(&prwlock->lock);
+ _pthread_cond_destroy(&prwlock->read_signal);
+ _pthread_cond_destroy(&prwlock->write_signal);
+ free(prwlock);
+
+ *rwlock = NULL;
+
+ ret = 0;
+ }
+ return (ret);
+}
+
+int
+_pthread_rwlock_init (pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr)
+{
+ pthread_rwlock_t prwlock;
+ int ret;
+
+ /* allocate rwlock object */
+ prwlock = (pthread_rwlock_t)malloc(sizeof(struct pthread_rwlock));
+
+ if (prwlock == NULL)
+ return (ENOMEM);
+
+ /* initialize the lock */
+ if ((ret = _pthread_mutex_init(&prwlock->lock, NULL)) != 0)
+ free(prwlock);
+ else {
+ /* initialize the read condition signal */
+ ret = _pthread_cond_init(&prwlock->read_signal, NULL);
+
+ if (ret != 0) {
+ _pthread_mutex_destroy(&prwlock->lock);
+ free(prwlock);
+ } else {
+ /* initialize the write condition signal */
+ ret = _pthread_cond_init(&prwlock->write_signal, NULL);
+
+ if (ret != 0) {
+ _pthread_cond_destroy(&prwlock->read_signal);
+ _pthread_mutex_destroy(&prwlock->lock);
+ free(prwlock);
+ } else {
+ /* success */
+ prwlock->state = 0;
+ prwlock->blocked_writers = 0;
+
+ *rwlock = prwlock;
+ }
+ }
+ }
+
+ return (ret);
+}
+
+static int
+rwlock_rdlock_common (pthread_rwlock_t *rwlock, const struct timespec *abstime)
+{
+ pthread_rwlock_t prwlock;
+ struct pthread *curthread;
+ int ret;
+
+ if (rwlock == NULL)
+ return (EINVAL);
+
+ prwlock = *rwlock;
+
+ /* check for static initialization */
+ if (prwlock == NULL) {
+ if ((ret = init_static(rwlock)) != 0)
+ return (ret);
+
+ prwlock = *rwlock;
+ }
+
+ /* grab the monitor lock */
+ if ((ret = _thr_mutex_lock(&prwlock->lock)) != 0)
+ return (ret);
+
+ /* check lock count */
+ if (prwlock->state == MAX_READ_LOCKS) {
+ _thr_mutex_unlock(&prwlock->lock);
+ return (EAGAIN);
+ }
+
+ curthread = _get_curthread();
+ if ((curthread->rdlock_count > 0) && (prwlock->state > 0)) {
+ /*
+ * To avoid having to track all the rdlocks held by
+ * a thread or all of the threads that hold a rdlock,
+ * we keep a simple count of all the rdlocks held by
+ * a thread. If a thread holds any rdlocks it is
+ * possible that it is attempting to take a recursive
+ * rdlock. If there are blocked writers and precedence
+ * is given to them, then that would result in the thread
+ * deadlocking. So allowing a thread to take the rdlock
+ * when it already has one or more rdlocks avoids the
+ * deadlock. I hope the reader can follow that logic ;-)
+ */
+ ; /* nothing needed */
+ } else {
+ /* give writers priority over readers */
+ while (prwlock->blocked_writers || prwlock->state < 0) {
+ if (abstime)
+ ret = _pthread_cond_timedwait
+ (&prwlock->read_signal,
+ &prwlock->lock, abstime);
+ else
+ ret = _thr_cond_wait(&prwlock->read_signal,
+ &prwlock->lock);
+ if (ret != 0) {
+ /* can't do a whole lot if this fails */
+ _thr_mutex_unlock(&prwlock->lock);
+ return (ret);
+ }
+ }
+ }
+
+ curthread->rdlock_count++;
+ prwlock->state++; /* indicate we are locked for reading */
+
+ /*
+ * Something is really wrong if this call fails. Returning
+ * error won't do because we've already obtained the read
+ * lock. Decrementing 'state' is no good because we probably
+ * don't have the monitor lock.
+ */
+ _thr_mutex_unlock(&prwlock->lock);
+
+ return (ret);
+}
+
+int
+_pthread_rwlock_rdlock (pthread_rwlock_t *rwlock)
+{
+ return (rwlock_rdlock_common(rwlock, NULL));
+}
+
+__strong_reference(_pthread_rwlock_rdlock, _thr_rwlock_rdlock);
+
+int
+_pthread_rwlock_timedrdlock (pthread_rwlock_t *rwlock,
+ const struct timespec *abstime)
+{
+ return (rwlock_rdlock_common(rwlock, abstime));
+}
+
+int
+_pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock)
+{
+ struct pthread *curthread;
+ pthread_rwlock_t prwlock;
+ int ret;
+
+ if (rwlock == NULL)
+ return (EINVAL);
+
+ prwlock = *rwlock;
+
+ /* check for static initialization */
+ if (prwlock == NULL) {
+ if ((ret = init_static(rwlock)) != 0)
+ return (ret);
+
+ prwlock = *rwlock;
+ }
+
+ /* grab the monitor lock */
+ if ((ret = _pthread_mutex_lock(&prwlock->lock)) != 0)
+ return (ret);
+
+ curthread = _get_curthread();
+ if (prwlock->state == MAX_READ_LOCKS)
+ ret = EAGAIN;
+ else if ((curthread->rdlock_count > 0) && (prwlock->state > 0)) {
+ /* see comment for pthread_rwlock_rdlock() */
+ curthread->rdlock_count++;
+ prwlock->state++;
+ }
+ /* give writers priority over readers */
+ else if (prwlock->blocked_writers || prwlock->state < 0)
+ ret = EBUSY;
+ else {
+ curthread->rdlock_count++;
+ prwlock->state++; /* indicate we are locked for reading */
+ }
+
+ /* see the comment on this in pthread_rwlock_rdlock */
+ _pthread_mutex_unlock(&prwlock->lock);
+
+ return (ret);
+}
+
+int
+_pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock)
+{
+ pthread_rwlock_t prwlock;
+ int ret;
+
+ if (rwlock == NULL)
+ return (EINVAL);
+
+ prwlock = *rwlock;
+
+ /* check for static initialization */
+ if (prwlock == NULL) {
+ if ((ret = init_static(rwlock)) != 0)
+ return (ret);
+
+ prwlock = *rwlock;
+ }
+
+ /* grab the monitor lock */
+ if ((ret = _pthread_mutex_lock(&prwlock->lock)) != 0)
+ return (ret);
+
+ if (prwlock->state != 0)
+ ret = EBUSY;
+ else
+ /* indicate we are locked for writing */
+ prwlock->state = -1;
+
+ /* see the comment on this in pthread_rwlock_rdlock */
+ _pthread_mutex_unlock(&prwlock->lock);
+
+ return (ret);
+}
+
+int
+_pthread_rwlock_unlock (pthread_rwlock_t *rwlock)
+{
+ struct pthread *curthread;
+ pthread_rwlock_t prwlock;
+ int ret;
+
+ if (rwlock == NULL)
+ return (EINVAL);
+
+ prwlock = *rwlock;
+
+ if (prwlock == NULL)
+ return (EINVAL);
+
+ /* grab the monitor lock */
+ if ((ret = _thr_mutex_lock(&prwlock->lock)) != 0)
+ return (ret);
+
+ curthread = _get_curthread();
+ if (prwlock->state > 0) {
+ curthread->rdlock_count--;
+ prwlock->state--;
+ if (prwlock->state == 0 && prwlock->blocked_writers)
+ ret = _thr_cond_signal(&prwlock->write_signal);
+ } else if (prwlock->state < 0) {
+ prwlock->state = 0;
+
+ if (prwlock->blocked_writers)
+ ret = _thr_cond_signal(&prwlock->write_signal);
+ else
+ ret = _thr_cond_broadcast(&prwlock->read_signal);
+ } else
+ ret = EINVAL;
+
+ /* see the comment on this in pthread_rwlock_rdlock */
+ _thr_mutex_unlock(&prwlock->lock);
+
+ return (ret);
+}
+
+__strong_reference(_pthread_rwlock_unlock, _thr_rwlock_unlock);
+
+static int
+rwlock_wrlock_common (pthread_rwlock_t *rwlock, const struct timespec *abstime)
+{
+ pthread_rwlock_t prwlock;
+ int ret;
+
+ if (rwlock == NULL)
+ return (EINVAL);
+
+ prwlock = *rwlock;
+
+ /* check for static initialization */
+ if (prwlock == NULL) {
+ if ((ret = init_static(rwlock)) != 0)
+ return (ret);
+
+ prwlock = *rwlock;
+ }
+
+ /* grab the monitor lock */
+ if ((ret = _thr_mutex_lock(&prwlock->lock)) != 0)
+ return (ret);
+
+ while (prwlock->state != 0) {
+ prwlock->blocked_writers++;
+
+ if (abstime != NULL)
+ ret = _pthread_cond_timedwait(&prwlock->write_signal,
+ &prwlock->lock, abstime);
+ else
+ ret = _thr_cond_wait(&prwlock->write_signal,
+ &prwlock->lock);
+ if (ret != 0) {
+ prwlock->blocked_writers--;
+ _thr_mutex_unlock(&prwlock->lock);
+ return (ret);
+ }
+
+ prwlock->blocked_writers--;
+ }
+
+ /* indicate we are locked for writing */
+ prwlock->state = -1;
+
+ /* see the comment on this in pthread_rwlock_rdlock */
+ _thr_mutex_unlock(&prwlock->lock);
+
+ return (ret);
+}
+
+int
+_pthread_rwlock_wrlock (pthread_rwlock_t *rwlock)
+{
+ return (rwlock_wrlock_common (rwlock, NULL));
+}
+__strong_reference(_pthread_rwlock_wrlock, _thr_rwlock_wrlock);
+
+int
+_pthread_rwlock_timedwrlock (pthread_rwlock_t *rwlock,
+ const struct timespec *abstime)
+{
+ return (rwlock_wrlock_common (rwlock, abstime));
+}
diff --git a/lib/libkse/thread/thr_rwlockattr.c b/lib/libkse/thread/thr_rwlockattr.c
new file mode 100644
index 0000000..174b28f
--- /dev/null
+++ b/lib/libkse/thread/thr_rwlockattr.c
@@ -0,0 +1,107 @@
+/*-
+ * Copyright (c) 1998 Alex Nash
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_rwlockattr_destroy);
+LT10_COMPAT_DEFAULT(pthread_rwlockattr_destroy);
+LT10_COMPAT_PRIVATE(_pthread_rwlockattr_getpshared);
+LT10_COMPAT_DEFAULT(pthread_rwlockattr_getpshared);
+LT10_COMPAT_PRIVATE(_pthread_rwlockattr_init);
+LT10_COMPAT_DEFAULT(pthread_rwlockattr_init);
+LT10_COMPAT_PRIVATE(_pthread_rwlockattr_setpshared);
+LT10_COMPAT_DEFAULT(pthread_rwlockattr_setpshared);
+
+__weak_reference(_pthread_rwlockattr_destroy, pthread_rwlockattr_destroy);
+__weak_reference(_pthread_rwlockattr_getpshared, pthread_rwlockattr_getpshared);
+__weak_reference(_pthread_rwlockattr_init, pthread_rwlockattr_init);
+__weak_reference(_pthread_rwlockattr_setpshared, pthread_rwlockattr_setpshared);
+
+int
+_pthread_rwlockattr_destroy(pthread_rwlockattr_t *rwlockattr)
+{
+ pthread_rwlockattr_t prwlockattr;
+
+ if (rwlockattr == NULL)
+ return(EINVAL);
+
+ prwlockattr = *rwlockattr;
+
+ if (prwlockattr == NULL)
+ return(EINVAL);
+
+ free(prwlockattr);
+
+ return(0);
+}
+
+int
+_pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *rwlockattr,
+ int *pshared)
+{
+ *pshared = (*rwlockattr)->pshared;
+
+ return(0);
+}
+
+int
+_pthread_rwlockattr_init(pthread_rwlockattr_t *rwlockattr)
+{
+ pthread_rwlockattr_t prwlockattr;
+
+ if (rwlockattr == NULL)
+ return(EINVAL);
+
+ prwlockattr = (pthread_rwlockattr_t)
+ malloc(sizeof(struct pthread_rwlockattr));
+
+ if (prwlockattr == NULL)
+ return(ENOMEM);
+
+ prwlockattr->pshared = PTHREAD_PROCESS_PRIVATE;
+ *rwlockattr = prwlockattr;
+
+ return(0);
+}
+
+int
+_pthread_rwlockattr_setpshared(pthread_rwlockattr_t *rwlockattr, int pshared)
+{
+ /* Only PTHREAD_PROCESS_PRIVATE is supported. */
+ if (pshared != PTHREAD_PROCESS_PRIVATE)
+ return(EINVAL);
+
+ (*rwlockattr)->pshared = pshared;
+
+ return(0);
+}
+
diff --git a/lib/libkse/thread/thr_select.c b/lib/libkse/thread/thr_select.c
new file mode 100644
index 0000000..97bcc37
--- /dev/null
+++ b/lib/libkse/thread/thr_select.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <unistd.h>
+#include <errno.h>
+#include <poll.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/fcntl.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__select);
+LT10_COMPAT_DEFAULT(select);
+
+__weak_reference(__select, select);
+
+int
+__select(int numfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+ struct timeval *timeout)
+{
+ struct pthread *curthread = _get_curthread();
+ struct timespec ts;
+ int ret;
+
+ if (numfds == 0 && timeout != NULL) {
+ TIMEVAL_TO_TIMESPEC(timeout, &ts);
+ return nanosleep(&ts, NULL);
+ } else {
+ _thr_cancel_enter(curthread);
+ ret = __sys_select(numfds, readfds, writefds, exceptfds, timeout);
+ _thr_cancel_leave(curthread, 1);
+ }
+ return ret;
+}
diff --git a/lib/libkse/thread/thr_self.c b/lib/libkse/thread/thr_self.c
new file mode 100644
index 0000000..28ac613
--- /dev/null
+++ b/lib/libkse/thread/thr_self.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_self);
+LT10_COMPAT_DEFAULT(pthread_self);
+
+__weak_reference(_pthread_self, pthread_self);
+
+pthread_t
+_pthread_self(void)
+{
+ if (_thr_initial == NULL)
+ _libpthread_init(NULL);
+
+ /* Return the running thread pointer: */
+ return (_get_curthread());
+}
diff --git a/lib/libkse/thread/thr_sem.c b/lib/libkse/thread/thr_sem.c
new file mode 100644
index 0000000..21746bbe
--- /dev/null
+++ b/lib/libkse/thread/thr_sem.c
@@ -0,0 +1,267 @@
+/*
+ * 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$
+ */
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <stdlib.h>
+#include <time.h>
+#include <_semaphore.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_sem_init);
+LT10_COMPAT_DEFAULT(sem_init);
+LT10_COMPAT_PRIVATE(_sem_wait);
+LT10_COMPAT_DEFAULT(sem_wait);
+LT10_COMPAT_PRIVATE(_sem_timedwait);
+LT10_COMPAT_DEFAULT(sem_timedwait);
+LT10_COMPAT_PRIVATE(_sem_post);
+LT10_COMPAT_DEFAULT(sem_post);
+
+__weak_reference(_sem_init, sem_init);
+__weak_reference(_sem_wait, sem_wait);
+__weak_reference(_sem_timedwait, sem_timedwait);
+__weak_reference(_sem_post, sem_post);
+
+
+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
+decrease_nwaiters(void *arg)
+{
+ sem_t *sem = (sem_t *)arg;
+
+ (*sem)->nwaiters--;
+ /*
+ * this function is called from cancellation point,
+ * the mutex should already be hold.
+ */
+ _pthread_mutex_unlock(&(*sem)->lock);
+}
+
+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);
+ }
+
+ /*
+ * Initialize the semaphore.
+ */
+ if (_pthread_mutex_init(&sem->lock, NULL) != 0) {
+ free(sem);
+ errno = ENOSPC;
+ return (NULL);
+ }
+
+ if (_pthread_cond_init(&sem->gtzero, NULL) != 0) {
+ _pthread_mutex_destroy(&sem->lock);
+ free(sem);
+ 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
+_sem_init(sem_t *sem, int pshared, unsigned int value)
+{
+ semid_t semid;
+
+ 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
+_sem_wait(sem_t *sem)
+{
+ struct pthread *curthread;
+ int retval;
+
+ if (sem_check_validity(sem) != 0)
+ return (-1);
+
+ curthread = _get_curthread();
+ if ((*sem)->syssem != 0) {
+ _thr_cancel_enter(curthread);
+ retval = ksem_wait((*sem)->semid);
+ _thr_cancel_leave(curthread, retval != 0);
+ }
+ else {
+ _pthread_testcancel();
+ _pthread_mutex_lock(&(*sem)->lock);
+
+ while ((*sem)->count <= 0) {
+ (*sem)->nwaiters++;
+ THR_CLEANUP_PUSH(curthread, decrease_nwaiters, sem);
+ _pthread_cond_wait(&(*sem)->gtzero, &(*sem)->lock);
+ THR_CLEANUP_POP(curthread, 0);
+ (*sem)->nwaiters--;
+ }
+ (*sem)->count--;
+
+ _pthread_mutex_unlock(&(*sem)->lock);
+
+ retval = 0;
+ }
+ return (retval);
+}
+
+int
+_sem_timedwait(sem_t * __restrict sem,
+ const struct timespec * __restrict abs_timeout)
+{
+ struct pthread *curthread;
+ int retval;
+ int timeout_invalid;
+
+ if (sem_check_validity(sem) != 0)
+ return (-1);
+
+ if ((*sem)->syssem != 0) {
+ curthread = _get_curthread();
+ _thr_cancel_enter(curthread);
+ retval = ksem_timedwait((*sem)->semid, abs_timeout);
+ _thr_cancel_leave(curthread, retval != 0);
+ }
+ else {
+ /*
+ * The timeout argument is only supposed to
+ * be checked if the thread would have blocked.
+ * This is checked outside of the lock so a
+ * segfault on an invalid address doesn't end
+ * up leaving the mutex locked.
+ */
+ _pthread_testcancel();
+ timeout_invalid = (abs_timeout->tv_nsec >= 1000000000) ||
+ (abs_timeout->tv_nsec < 0);
+ _pthread_mutex_lock(&(*sem)->lock);
+
+ if ((*sem)->count <= 0) {
+ if (timeout_invalid) {
+ _pthread_mutex_unlock(&(*sem)->lock);
+ errno = EINVAL;
+ return (-1);
+ }
+ (*sem)->nwaiters++;
+ _pthread_cleanup_push(decrease_nwaiters, sem);
+ _pthread_cond_timedwait(&(*sem)->gtzero,
+ &(*sem)->lock, abs_timeout);
+ _pthread_cleanup_pop(0);
+ (*sem)->nwaiters--;
+ }
+ if ((*sem)->count == 0) {
+ errno = ETIMEDOUT;
+ retval = -1;
+ }
+ else {
+ (*sem)->count--;
+ retval = 0;
+ }
+
+ _pthread_mutex_unlock(&(*sem)->lock);
+ }
+
+ return (retval);
+}
+
+int
+_sem_post(sem_t *sem)
+{
+ struct pthread *curthread;
+ int retval;
+
+ if (sem_check_validity(sem) != 0)
+ return (-1);
+
+ if ((*sem)->syssem != 0)
+ retval = ksem_post((*sem)->semid);
+ else {
+ /*
+ * sem_post() is required to be safe to call from within
+ * signal handlers. Thus, we must enter a critical region.
+ */
+ curthread = _get_curthread();
+ _thr_critical_enter(curthread);
+ _pthread_mutex_lock(&(*sem)->lock);
+
+ (*sem)->count++;
+ if ((*sem)->nwaiters > 0)
+ _pthread_cond_signal(&(*sem)->gtzero);
+
+ _pthread_mutex_unlock(&(*sem)->lock);
+ _thr_critical_leave(curthread);
+ retval = 0;
+ }
+
+ return (retval);
+}
diff --git a/lib/libkse/thread/thr_seterrno.c b/lib/libkse/thread/thr_seterrno.c
new file mode 100644
index 0000000..245d43f
--- /dev/null
+++ b/lib/libkse/thread/thr_seterrno.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 "thr_private.h"
+
+/*
+ * This function needs to reference the global error variable which is
+ * normally hidden from the user.
+ */
+#ifdef errno
+#undef errno;
+#endif
+extern int errno;
+
+void
+_thread_seterrno(pthread_t thread, int error)
+{
+ /* Check for the initial thread: */
+ if (thread == _thr_initial)
+ /* The initial thread always uses the global error variable: */
+ errno = error;
+ else
+ /*
+ * Threads other than the initial thread always use the error
+ * field in the thread structureL
+ */
+ thread->error = error;
+}
diff --git a/lib/libkse/thread/thr_setprio.c b/lib/libkse/thread/thr_setprio.c
new file mode 100644
index 0000000..3b7796a
--- /dev/null
+++ b/lib/libkse/thread/thr_setprio.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_setprio);
+LT10_COMPAT_DEFAULT(pthread_setprio);
+
+__weak_reference(_pthread_setprio, pthread_setprio);
+
+int
+_pthread_setprio(pthread_t pthread, int prio)
+{
+ int ret, policy;
+ struct sched_param param;
+
+ if ((ret = pthread_getschedparam(pthread, &policy, &param)) == 0) {
+ param.sched_priority = prio;
+ ret = pthread_setschedparam(pthread, policy, &param);
+ }
+
+ /* Return the error status: */
+ return (ret);
+}
diff --git a/lib/libkse/thread/thr_setschedparam.c b/lib/libkse/thread/thr_setschedparam.c
new file mode 100644
index 0000000..8f5154c
--- /dev/null
+++ b/lib/libkse/thread/thr_setschedparam.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <sys/param.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_setschedparam);
+LT10_COMPAT_DEFAULT(pthread_setschedparam);
+
+__weak_reference(_pthread_setschedparam, pthread_setschedparam);
+
+int
+_pthread_setschedparam(pthread_t pthread, int policy,
+ const struct sched_param *param)
+{
+ struct pthread *curthread = _get_curthread();
+ int in_syncq;
+ int in_readyq = 0;
+ int old_prio;
+ int ret = 0;
+
+ if ((param == NULL) || (policy < SCHED_FIFO) || (policy > SCHED_RR)) {
+ /* Return an invalid argument error: */
+ ret = EINVAL;
+ } else if ((param->sched_priority < THR_MIN_PRIORITY) ||
+ (param->sched_priority > THR_MAX_PRIORITY)) {
+ /* Return an unsupported value error. */
+ ret = ENOTSUP;
+
+ /* Find the thread in the list of active threads: */
+ } else if ((ret = _thr_ref_add(curthread, pthread, /*include dead*/0))
+ == 0) {
+ /*
+ * Lock the threads scheduling queue while we change
+ * its priority:
+ */
+ THR_SCHED_LOCK(curthread, pthread);
+ if ((pthread->state == PS_DEAD) ||
+ (pthread->state == PS_DEADLOCK) ||
+ ((pthread->flags & THR_FLAGS_EXITING) != 0)) {
+ THR_SCHED_UNLOCK(curthread, pthread);
+ _thr_ref_delete(curthread, pthread);
+ return (ESRCH);
+ }
+ in_syncq = pthread->sflags & THR_FLAGS_IN_SYNCQ;
+
+ /* Set the scheduling policy: */
+ pthread->attr.sched_policy = policy;
+
+ if (param->sched_priority ==
+ THR_BASE_PRIORITY(pthread->base_priority))
+ /*
+ * There is nothing to do; unlock the threads
+ * scheduling queue.
+ */
+ THR_SCHED_UNLOCK(curthread, pthread);
+ else {
+ /*
+ * Remove the thread from its current priority
+ * queue before any adjustments are made to its
+ * active priority:
+ */
+ old_prio = pthread->active_priority;
+ if ((pthread->flags & THR_FLAGS_IN_RUNQ) != 0) {
+ in_readyq = 1;
+ THR_RUNQ_REMOVE(pthread);
+ }
+
+ /* Set the thread base priority: */
+ pthread->base_priority &=
+ (THR_SIGNAL_PRIORITY | THR_RT_PRIORITY);
+ pthread->base_priority = param->sched_priority;
+
+ /* Recalculate the active priority: */
+ pthread->active_priority = MAX(pthread->base_priority,
+ pthread->inherited_priority);
+
+ if (in_readyq) {
+ if ((pthread->priority_mutex_count > 0) &&
+ (old_prio > pthread->active_priority)) {
+ /*
+ * POSIX states that if the priority is
+ * being lowered, the thread must be
+ * inserted at the head of the queue for
+ * its priority if it owns any priority
+ * protection or inheritence mutexes.
+ */
+ THR_RUNQ_INSERT_HEAD(pthread);
+ }
+ else
+ THR_RUNQ_INSERT_TAIL(pthread);
+ }
+
+ /* Unlock the threads scheduling queue: */
+ THR_SCHED_UNLOCK(curthread, pthread);
+
+ /*
+ * Check for any mutex priority adjustments. This
+ * includes checking for a priority mutex on which
+ * this thread is waiting.
+ */
+ _mutex_notify_priochange(curthread, pthread, in_syncq);
+ }
+ _thr_ref_delete(curthread, pthread);
+ }
+ return (ret);
+}
diff --git a/lib/libkse/thread/thr_sig.c b/lib/libkse/thread/thr_sig.c
new file mode 100644
index 0000000..f53b87f
--- /dev/null
+++ b/lib/libkse/thread/thr_sig.c
@@ -0,0 +1,1259 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/signalvar.h>
+#include <signal.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+/* Prototypes: */
+static inline void build_siginfo(siginfo_t *info, int signo);
+#ifndef SYSTEM_SCOPE_ONLY
+static struct pthread *thr_sig_find(struct kse *curkse, int sig,
+ siginfo_t *info);
+#endif
+static inline void thr_sigframe_restore(struct pthread *thread,
+ struct pthread_sigframe *psf);
+static inline void thr_sigframe_save(struct pthread *thread,
+ struct pthread_sigframe *psf);
+
+#define SA_KILL 0x01 /* terminates process by default */
+#define SA_STOP 0x02
+#define SA_CONT 0x04
+
+static int sigproptbl[NSIG] = {
+ SA_KILL, /* SIGHUP */
+ SA_KILL, /* SIGINT */
+ SA_KILL, /* SIGQUIT */
+ SA_KILL, /* SIGILL */
+ SA_KILL, /* SIGTRAP */
+ SA_KILL, /* SIGABRT */
+ SA_KILL, /* SIGEMT */
+ SA_KILL, /* SIGFPE */
+ SA_KILL, /* SIGKILL */
+ SA_KILL, /* SIGBUS */
+ SA_KILL, /* SIGSEGV */
+ SA_KILL, /* SIGSYS */
+ SA_KILL, /* SIGPIPE */
+ SA_KILL, /* SIGALRM */
+ SA_KILL, /* SIGTERM */
+ 0, /* SIGURG */
+ SA_STOP, /* SIGSTOP */
+ SA_STOP, /* SIGTSTP */
+ SA_CONT, /* SIGCONT */
+ 0, /* SIGCHLD */
+ SA_STOP, /* SIGTTIN */
+ SA_STOP, /* SIGTTOU */
+ 0, /* SIGIO */
+ SA_KILL, /* SIGXCPU */
+ SA_KILL, /* SIGXFSZ */
+ SA_KILL, /* SIGVTALRM */
+ SA_KILL, /* SIGPROF */
+ 0, /* SIGWINCH */
+ 0, /* SIGINFO */
+ SA_KILL, /* SIGUSR1 */
+ SA_KILL /* SIGUSR2 */
+};
+
+/* #define DEBUG_SIGNAL */
+#ifdef DEBUG_SIGNAL
+#define DBG_MSG stdout_debug
+#else
+#define DBG_MSG(x...)
+#endif
+
+static __inline int
+_thr_dump_enabled(void)
+{
+ return ((_thr_debug_flags & DBG_INFO_DUMP) != 0);
+}
+
+/*
+ * Signal setup and delivery.
+ *
+ * 1) Delivering signals to threads in the same KSE.
+ * These signals are sent by upcall events and are set in the
+ * km_sigscaught field of the KSE mailbox. Since these signals
+ * are received while operating on the KSE stack, they can be
+ * delivered either by using signalcontext() to add a stack frame
+ * to the target thread's stack, or by adding them in the thread's
+ * pending set and having the thread run them down after it
+ * 2) Delivering signals to threads in other KSEs/KSEGs.
+ * 3) Delivering signals to threads in critical regions.
+ * 4) Delivering signals to threads after they change their signal masks.
+ *
+ * Methods of delivering signals.
+ *
+ * 1) Add a signal frame to the thread's saved context.
+ * 2) Add the signal to the thread structure, mark the thread as
+ * having signals to handle, and let the thread run them down
+ * after it resumes from the KSE scheduler.
+ *
+ * Problem with 1). You can't do this to a running thread or a
+ * thread in a critical region.
+ *
+ * Problem with 2). You can't do this to a thread that doesn't
+ * yield in some way (explicitly enters the scheduler). A thread
+ * blocked in the kernel or a CPU hungry thread will not see the
+ * signal without entering the scheduler.
+ *
+ * The solution is to use both 1) and 2) to deliver signals:
+ *
+ * o Thread in critical region - use 2). When the thread
+ * leaves the critical region it will check to see if it
+ * has pending signals and run them down.
+ *
+ * o Thread enters scheduler explicitly - use 2). The thread
+ * can check for pending signals after it returns from the
+ * the scheduler.
+ *
+ * o Thread is running and not current thread - use 2). When the
+ * thread hits a condition specified by one of the other bullets,
+ * the signal will be delivered.
+ *
+ * o Thread is running and is current thread (e.g., the thread
+ * has just changed its signal mask and now sees that it has
+ * pending signals) - just run down the pending signals.
+ *
+ * o Thread is swapped out due to quantum expiration - use 1)
+ *
+ * o Thread is blocked in kernel - kse_thr_wakeup() and then
+ * use 1)
+ */
+
+/*
+ * Rules for selecting threads for signals received:
+ *
+ * 1) If the signal is a sychronous signal, it is delivered to
+ * the generating (current thread). If the thread has the
+ * signal masked, it is added to the threads pending signal
+ * set until the thread unmasks it.
+ *
+ * 2) A thread in sigwait() where the signal is in the thread's
+ * waitset.
+ *
+ * 3) A thread in sigsuspend() where the signal is not in the
+ * thread's suspended signal mask.
+ *
+ * 4) Any thread (first found/easiest to deliver) that has the
+ * signal unmasked.
+ */
+
+#ifndef SYSTEM_SCOPE_ONLY
+
+static void *
+sig_daemon(void *arg /* Unused */)
+{
+ int i;
+ kse_critical_t crit;
+ struct timespec ts;
+ sigset_t set;
+ struct kse *curkse;
+ struct pthread *curthread = _get_curthread();
+
+ DBG_MSG("signal daemon started(%p)\n", curthread);
+
+ curthread->name = strdup("signal thread");
+ crit = _kse_critical_enter();
+ curkse = _get_curkse();
+
+ /*
+ * Daemon thread is a bound thread and we must be created with
+ * all signals masked
+ */
+#if 0
+ SIGFILLSET(set);
+ __sys_sigprocmask(SIG_SETMASK, &set, NULL);
+#endif
+ __sys_sigpending(&set);
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+ while (1) {
+ KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock);
+ _thr_proc_sigpending = set;
+ KSE_LOCK_RELEASE(curkse, &_thread_signal_lock);
+ for (i = 1; i <= _SIG_MAXSIG; i++) {
+ if (SIGISMEMBER(set, i) != 0)
+ _thr_sig_dispatch(curkse, i,
+ NULL /* no siginfo */);
+ }
+ ts.tv_sec = 30;
+ ts.tv_nsec = 0;
+ curkse->k_kcb->kcb_kmbx.km_flags =
+ KMF_NOUPCALL | KMF_NOCOMPLETED | KMF_WAITSIGEVENT;
+ kse_release(&ts);
+ curkse->k_kcb->kcb_kmbx.km_flags = 0;
+ set = curkse->k_kcb->kcb_kmbx.km_sigscaught;
+ }
+ return (0);
+}
+
+
+/* Utility function to create signal daemon thread */
+int
+_thr_start_sig_daemon(void)
+{
+ pthread_attr_t attr;
+ sigset_t sigset, oldset;
+
+ SIGFILLSET(sigset);
+ pthread_sigmask(SIG_SETMASK, &sigset, &oldset);
+ pthread_attr_init(&attr);
+ pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
+ attr->flags |= THR_SIGNAL_THREAD;
+ /* sigmask will be inherited */
+ if (pthread_create(&_thr_sig_daemon, &attr, sig_daemon, NULL))
+ PANIC("can not create signal daemon thread!\n");
+ pthread_attr_destroy(&attr);
+ pthread_sigmask(SIG_SETMASK, &oldset, NULL);
+ return (0);
+}
+
+/*
+ * This signal handler only delivers asynchronous signals.
+ * This must be called with upcalls disabled and without
+ * holding any locks.
+ */
+void
+_thr_sig_dispatch(struct kse *curkse, int sig, siginfo_t *info)
+{
+ struct kse_mailbox *kmbx;
+ struct pthread *thread;
+
+ DBG_MSG(">>> _thr_sig_dispatch(%d)\n", sig);
+
+ /* Check if the signal requires a dump of thread information: */
+ if (_thr_dump_enabled() && (sig == SIGINFO)) {
+ /* Dump thread information to file: */
+ _thread_dump_info();
+ }
+
+ while ((thread = thr_sig_find(curkse, sig, info)) != NULL) {
+ /*
+ * Setup the target thread to receive the signal:
+ */
+ DBG_MSG("Got signal %d, selecting thread %p\n", sig, thread);
+ KSE_SCHED_LOCK(curkse, thread->kseg);
+ if ((thread->state == PS_DEAD) ||
+ (thread->state == PS_DEADLOCK) ||
+ THR_IS_EXITING(thread) || THR_IS_SUSPENDED(thread)) {
+ KSE_SCHED_UNLOCK(curkse, thread->kseg);
+ _thr_ref_delete(NULL, thread);
+ } else if (SIGISMEMBER(thread->sigmask, sig)) {
+ KSE_SCHED_UNLOCK(curkse, thread->kseg);
+ _thr_ref_delete(NULL, thread);
+ } else {
+ kmbx = _thr_sig_add(thread, sig, info);
+ KSE_SCHED_UNLOCK(curkse, thread->kseg);
+ _thr_ref_delete(NULL, thread);
+ if (kmbx != NULL)
+ kse_wakeup(kmbx);
+ break;
+ }
+ }
+ DBG_MSG("<<< _thr_sig_dispatch\n");
+}
+
+#endif /* ! SYSTEM_SCOPE_ONLY */
+
+static __inline int
+sigprop(int sig)
+{
+
+ if (sig > 0 && sig < NSIG)
+ return (sigproptbl[_SIG_IDX(sig)]);
+ return (0);
+}
+
+typedef void (*ohandler)(int sig, int code,
+ struct sigcontext *scp, char *addr, __sighandler_t *catcher);
+
+void
+_thr_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
+{
+ struct pthread_sigframe psf;
+ __siginfohandler_t *sigfunc;
+ struct pthread *curthread;
+ struct kse *curkse;
+ struct sigaction act;
+ int sa_flags, err_save;
+
+ err_save = errno;
+
+ DBG_MSG(">>> _thr_sig_handler(%d)\n", sig);
+
+ curthread = _get_curthread();
+ if (curthread == NULL)
+ PANIC("No current thread.\n");
+ if (!(curthread->attr.flags & PTHREAD_SCOPE_SYSTEM))
+ PANIC("Thread is not system scope.\n");
+ if (curthread->flags & THR_FLAGS_EXITING) {
+ errno = err_save;
+ return;
+ }
+
+ curkse = _get_curkse();
+ /*
+ * If thread is in critical region or if thread is on
+ * the way of state transition, then latch signal into buffer.
+ */
+ if (_kse_in_critical() || THR_IN_CRITICAL(curthread) ||
+ curthread->state != PS_RUNNING) {
+ DBG_MSG(">>> _thr_sig_handler(%d) in critical\n", sig);
+ curthread->siginfo[sig-1] = *info;
+ curthread->check_pending = 1;
+ curkse->k_sigseqno++;
+ SIGADDSET(curthread->sigpend, sig);
+ /*
+ * If the kse is on the way to idle itself, but
+ * we have signal ready, we should prevent it
+ * to sleep, kernel will latch the wakeup request,
+ * so kse_release will return from kernel immediately.
+ */
+ if (KSE_IS_IDLE(curkse))
+ kse_wakeup(&curkse->k_kcb->kcb_kmbx);
+ errno = err_save;
+ return;
+ }
+
+ /* Check if the signal requires a dump of thread information: */
+ if (_thr_dump_enabled() && (sig == SIGINFO)) {
+ /* Dump thread information to file: */
+ _thread_dump_info();
+ }
+
+ /* Check the threads previous state: */
+ curthread->critical_count++;
+ if (curthread->sigbackout != NULL)
+ curthread->sigbackout((void *)curthread);
+ curthread->critical_count--;
+ thr_sigframe_save(curthread, &psf);
+ THR_ASSERT(!(curthread->sigbackout), "sigbackout was not cleared.");
+
+ _kse_critical_enter();
+ /* Get a fresh copy of signal mask */
+ __sys_sigprocmask(SIG_BLOCK, NULL, &curthread->sigmask);
+ KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock);
+ sigfunc = _thread_sigact[sig - 1].sa_sigaction;
+ sa_flags = _thread_sigact[sig - 1].sa_flags;
+ if (sa_flags & SA_RESETHAND) {
+ act.sa_handler = SIG_DFL;
+ act.sa_flags = SA_RESTART;
+ SIGEMPTYSET(act.sa_mask);
+ __sys_sigaction(sig, &act, NULL);
+ __sys_sigaction(sig, NULL, &_thread_sigact[sig - 1]);
+ }
+ KSE_LOCK_RELEASE(curkse, &_thread_signal_lock);
+ _kse_critical_leave(&curthread->tcb->tcb_tmbx);
+
+ /* Now invoke real handler */
+ if (((__sighandler_t *)sigfunc != SIG_DFL) &&
+ ((__sighandler_t *)sigfunc != SIG_IGN) &&
+ (sigfunc != (__siginfohandler_t *)_thr_sig_handler)) {
+ if ((sa_flags & SA_SIGINFO) != 0 || info == NULL)
+ (*(sigfunc))(sig, info, ucp);
+ else {
+ ((ohandler)(*sigfunc))(
+ sig, info->si_code, (struct sigcontext *)ucp,
+ info->si_addr, (__sighandler_t *)sigfunc);
+ }
+ } else {
+ if ((__sighandler_t *)sigfunc == SIG_DFL) {
+ if (sigprop(sig) & SA_KILL) {
+ if (_kse_isthreaded())
+ kse_thr_interrupt(NULL,
+ KSE_INTR_SIGEXIT, sig);
+ else
+ kill(getpid(), sig);
+ }
+#ifdef NOTYET
+ else if (sigprop(sig) & SA_STOP)
+ kse_thr_interrupt(NULL, KSE_INTR_JOBSTOP, sig);
+#endif
+ }
+ }
+ _kse_critical_enter();
+ curthread->sigmask = ucp->uc_sigmask;
+ SIG_CANTMASK(curthread->sigmask);
+ _kse_critical_leave(&curthread->tcb->tcb_tmbx);
+
+ thr_sigframe_restore(curthread, &psf);
+
+ DBG_MSG("<<< _thr_sig_handler(%d)\n", sig);
+
+ errno = err_save;
+}
+
+struct sighandle_info {
+ __siginfohandler_t *sigfunc;
+ int sa_flags;
+ int sig;
+ siginfo_t *info;
+ ucontext_t *ucp;
+};
+
+static void handle_signal(struct pthread *curthread,
+ struct sighandle_info *shi);
+static void handle_signal_altstack(struct pthread *curthread,
+ struct sighandle_info *shi);
+
+/* Must be called with signal lock and schedule lock held in order */
+static void
+thr_sig_invoke_handler(struct pthread *curthread, int sig, siginfo_t *info,
+ ucontext_t *ucp)
+{
+ __siginfohandler_t *sigfunc;
+ sigset_t sigmask;
+ int sa_flags;
+ int onstack;
+ struct sigaction act;
+ struct kse *curkse;
+ struct sighandle_info shi;
+
+ /*
+ * Invoke the signal handler without going through the scheduler:
+ */
+ DBG_MSG("Got signal %d, calling handler for current thread %p\n",
+ sig, curthread);
+
+ if (!_kse_in_critical())
+ PANIC("thr_sig_invoke_handler without in critical\n");
+ curkse = curthread->kse;
+ /*
+ * Check that a custom handler is installed and if
+ * the signal is not blocked:
+ */
+ sigfunc = _thread_sigact[sig - 1].sa_sigaction;
+ sa_flags = _thread_sigact[sig - 1].sa_flags;
+ sigmask = curthread->sigmask;
+ SIGSETOR(curthread->sigmask, _thread_sigact[sig - 1].sa_mask);
+ if (!(sa_flags & (SA_NODEFER | SA_RESETHAND)))
+ SIGADDSET(curthread->sigmask, sig);
+ if ((sig != SIGILL) && (sa_flags & SA_RESETHAND)) {
+ act.sa_handler = SIG_DFL;
+ act.sa_flags = SA_RESTART;
+ SIGEMPTYSET(act.sa_mask);
+ __sys_sigaction(sig, &act, NULL);
+ __sys_sigaction(sig, NULL, &_thread_sigact[sig - 1]);
+ }
+ KSE_LOCK_RELEASE(curkse, &_thread_signal_lock);
+ KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
+ /*
+ * We are processing buffered signals, synchronize working
+ * signal mask into kernel.
+ */
+ if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
+ __sys_sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL);
+ onstack = _thr_sigonstack(&sigfunc);
+ ucp->uc_stack = curthread->sigstk;
+ ucp->uc_stack.ss_flags = (curthread->sigstk.ss_flags & SS_DISABLE)
+ ? SS_DISABLE : ((onstack) ? SS_ONSTACK : 0);
+ if (curthread->oldsigmask) {
+ ucp->uc_sigmask = *(curthread->oldsigmask);
+ curthread->oldsigmask = NULL;
+ } else
+ ucp->uc_sigmask = sigmask;
+ shi.sigfunc = sigfunc;
+ shi.sig = sig;
+ shi.sa_flags = sa_flags;
+ shi.info = info;
+ shi.ucp = ucp;
+ if ((curthread->sigstk.ss_flags & SS_DISABLE) == 0) {
+ /* Deliver signal on alternative stack */
+ if (sa_flags & SA_ONSTACK && !onstack)
+ handle_signal_altstack(curthread, &shi);
+ else
+ handle_signal(curthread, &shi);
+ } else {
+ handle_signal(curthread, &shi);
+ }
+
+ _kse_critical_enter();
+ /* Don't trust after critical leave/enter */
+ curkse = curthread->kse;
+
+ /*
+ * Restore the thread's signal mask.
+ */
+ curthread->sigmask = ucp->uc_sigmask;
+ SIG_CANTMASK(curthread->sigmask);
+ if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
+ __sys_sigprocmask(SIG_SETMASK, &ucp->uc_sigmask, NULL);
+ KSE_SCHED_LOCK(curkse, curkse->k_kseg);
+ KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock);
+
+ DBG_MSG("Got signal %d, handler returned %p\n", sig, curthread);
+}
+
+static void
+handle_signal(struct pthread *curthread, struct sighandle_info *shi)
+{
+ _kse_critical_leave(&curthread->tcb->tcb_tmbx);
+
+ /* Check if the signal requires a dump of thread information: */
+ if (_thr_dump_enabled() && (shi->sig == SIGINFO)) {
+ /* Dump thread information to file: */
+ _thread_dump_info();
+ }
+
+ if (((__sighandler_t *)shi->sigfunc != SIG_DFL) &&
+ ((__sighandler_t *)shi->sigfunc != SIG_IGN)) {
+ if ((shi->sa_flags & SA_SIGINFO) != 0 || shi->info == NULL)
+ (*(shi->sigfunc))(shi->sig, shi->info, shi->ucp);
+ else {
+ ((ohandler)(*shi->sigfunc))(
+ shi->sig, shi->info->si_code,
+ (struct sigcontext *)shi->ucp,
+ shi->info->si_addr,
+ (__sighandler_t *)shi->sigfunc);
+ }
+ } else {
+ if ((__sighandler_t *)shi->sigfunc == SIG_DFL) {
+ if (sigprop(shi->sig) & SA_KILL) {
+ if (_kse_isthreaded())
+ kse_thr_interrupt(NULL,
+ KSE_INTR_SIGEXIT, shi->sig);
+ else
+ kill(getpid(), shi->sig);
+ }
+#ifdef NOTYET
+ else if (sigprop(shi->sig) & SA_STOP)
+ kse_thr_interrupt(NULL, KSE_INTR_JOBSTOP,
+ shi->sig);
+#endif
+ }
+ }
+}
+
+static void
+handle_signal_wrapper(struct pthread *curthread, ucontext_t *ret_uc,
+ struct sighandle_info *shi)
+{
+ shi->ucp->uc_stack.ss_flags = SS_ONSTACK;
+ handle_signal(curthread, shi);
+ if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
+ setcontext(ret_uc);
+ else {
+ /* Work around for ia64, THR_SETCONTEXT does not work */
+ _kse_critical_enter();
+ curthread->tcb->tcb_tmbx.tm_context = *ret_uc;
+ _thread_switch(curthread->kse->k_kcb, curthread->tcb, 1);
+ /* THR_SETCONTEXT */
+ }
+}
+
+/*
+ * Jump to stack set by sigaltstack before invoking signal handler
+ */
+static void
+handle_signal_altstack(struct pthread *curthread, struct sighandle_info *shi)
+{
+ volatile int once;
+ ucontext_t uc1, *uc2;
+
+ THR_ASSERT(_kse_in_critical(), "Not in critical");
+
+ once = 0;
+ THR_GETCONTEXT(&uc1);
+ if (once == 0) {
+ once = 1;
+ /* XXX
+ * We are still in critical region, it is safe to operate thread
+ * context
+ */
+ uc2 = &curthread->tcb->tcb_tmbx.tm_context;
+ uc2->uc_stack = curthread->sigstk;
+ makecontext(uc2, (void (*)(void))handle_signal_wrapper,
+ 3, curthread, &uc1, shi);
+ if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
+ setcontext(uc2);
+ else {
+ _thread_switch(curthread->kse->k_kcb, curthread->tcb, 1);
+ /* THR_SETCONTEXT(uc2); */
+ }
+ }
+}
+
+int
+_thr_getprocsig(int sig, siginfo_t *siginfo)
+{
+ kse_critical_t crit;
+ struct kse *curkse;
+ int ret;
+
+ DBG_MSG(">>> _thr_getprocsig\n");
+
+ crit = _kse_critical_enter();
+ curkse = _get_curkse();
+ KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock);
+ ret = _thr_getprocsig_unlocked(sig, siginfo);
+ KSE_LOCK_RELEASE(curkse, &_thread_signal_lock);
+ _kse_critical_leave(crit);
+
+ DBG_MSG("<<< _thr_getprocsig\n");
+ return (ret);
+}
+
+int
+_thr_getprocsig_unlocked(int sig, siginfo_t *siginfo)
+{
+ sigset_t sigset;
+ struct timespec ts;
+
+ /* try to retrieve signal from kernel */
+ SIGEMPTYSET(sigset);
+ SIGADDSET(sigset, sig);
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+ SIGDELSET(_thr_proc_sigpending, sig);
+ if (__sys_sigtimedwait(&sigset, siginfo, &ts) > 0)
+ return (sig);
+ return (0);
+}
+
+#ifndef SYSTEM_SCOPE_ONLY
+/*
+ * Find a thread that can handle the signal. This must be called
+ * with upcalls disabled.
+ */
+struct pthread *
+thr_sig_find(struct kse *curkse, int sig, siginfo_t *info)
+{
+ struct kse_mailbox *kmbx = NULL;
+ struct pthread *pthread;
+ struct pthread *suspended_thread, *signaled_thread;
+ __siginfohandler_t *sigfunc;
+ siginfo_t si;
+
+ DBG_MSG("Looking for thread to handle signal %d\n", sig);
+
+ /*
+ * Enter a loop to look for threads that have the signal
+ * unmasked. POSIX specifies that a thread in a sigwait
+ * will get the signal over any other threads. Second
+ * preference will be threads in in a sigsuspend. Third
+ * preference will be the current thread. If none of the
+ * above, then the signal is delivered to the first thread
+ * that is found. Note that if a custom handler is not
+ * installed, the signal only affects threads in sigwait.
+ */
+ suspended_thread = NULL;
+ signaled_thread = NULL;
+
+ KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock);
+ TAILQ_FOREACH(pthread, &_thread_list, tle) {
+ if (pthread == _thr_sig_daemon)
+ continue;
+ /* Signal delivering to bound thread is done by kernel */
+ if (pthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
+ continue;
+ /* Take the scheduling lock. */
+ KSE_SCHED_LOCK(curkse, pthread->kseg);
+ if ((pthread->state == PS_DEAD) ||
+ (pthread->state == PS_DEADLOCK) ||
+ THR_IS_EXITING(pthread) ||
+ THR_IS_SUSPENDED(pthread)) {
+ ; /* Skip this thread. */
+ } else if (pthread->state == PS_SIGWAIT &&
+ SIGISMEMBER(*(pthread->data.sigwait->waitset), sig)) {
+ /*
+ * retrieve signal from kernel, if it is job control
+ * signal, and sigaction is SIG_DFL, then we will
+ * be stopped in kernel, we hold lock here, but that
+ * does not matter, because that's job control, and
+ * whole process should be stopped.
+ */
+ if (_thr_getprocsig(sig, &si)) {
+ DBG_MSG("Waking thread %p in sigwait"
+ " with signal %d\n", pthread, sig);
+ /* where to put siginfo ? */
+ *(pthread->data.sigwait->siginfo) = si;
+ kmbx = _thr_setrunnable_unlocked(pthread);
+ }
+ KSE_SCHED_UNLOCK(curkse, pthread->kseg);
+ /*
+ * POSIX doesn't doesn't specify which thread
+ * will get the signal if there are multiple
+ * waiters, so we give it to the first thread
+ * we find.
+ *
+ * Do not attempt to deliver this signal
+ * to other threads and do not add the signal
+ * to the process pending set.
+ */
+ KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
+ if (kmbx != NULL)
+ kse_wakeup(kmbx);
+ if (suspended_thread != NULL)
+ _thr_ref_delete(NULL, suspended_thread);
+ if (signaled_thread != NULL)
+ _thr_ref_delete(NULL, signaled_thread);
+ return (NULL);
+ } else if (!SIGISMEMBER(pthread->sigmask, sig)) {
+ /*
+ * If debugger is running, we don't quick exit,
+ * and give it a chance to check the signal.
+ */
+ if (_libkse_debug == 0) {
+ sigfunc = _thread_sigact[sig - 1].sa_sigaction;
+ if ((__sighandler_t *)sigfunc == SIG_DFL) {
+ if (sigprop(sig) & SA_KILL) {
+ kse_thr_interrupt(NULL,
+ KSE_INTR_SIGEXIT, sig);
+ /* Never reach */
+ }
+ }
+ }
+ if (pthread->state == PS_SIGSUSPEND) {
+ if (suspended_thread == NULL) {
+ suspended_thread = pthread;
+ suspended_thread->refcount++;
+ }
+ } else if (signaled_thread == NULL) {
+ signaled_thread = pthread;
+ signaled_thread->refcount++;
+ }
+ }
+ KSE_SCHED_UNLOCK(curkse, pthread->kseg);
+ }
+ KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
+
+ if (suspended_thread != NULL) {
+ pthread = suspended_thread;
+ if (signaled_thread)
+ _thr_ref_delete(NULL, signaled_thread);
+ } else if (signaled_thread) {
+ pthread = signaled_thread;
+ } else {
+ pthread = NULL;
+ }
+ return (pthread);
+}
+#endif /* ! SYSTEM_SCOPE_ONLY */
+
+static inline void
+build_siginfo(siginfo_t *info, int signo)
+{
+ bzero(info, sizeof(*info));
+ info->si_signo = signo;
+ info->si_pid = _thr_pid;
+}
+
+/*
+ * This is called by a thread when it has pending signals to deliver.
+ * It should only be called from the context of the thread.
+ */
+void
+_thr_sig_rundown(struct pthread *curthread, ucontext_t *ucp)
+{
+ struct pthread_sigframe psf;
+ siginfo_t siginfo;
+ int i, err_save;
+ kse_critical_t crit;
+ struct kse *curkse;
+ sigset_t sigmask;
+
+ err_save = errno;
+
+ DBG_MSG(">>> thr_sig_rundown (%p)\n", curthread);
+
+ /* Check the threads previous state: */
+ curthread->critical_count++;
+ if (curthread->sigbackout != NULL)
+ curthread->sigbackout((void *)curthread);
+ curthread->critical_count--;
+
+ THR_ASSERT(!(curthread->sigbackout), "sigbackout was not cleared.");
+ THR_ASSERT((curthread->state == PS_RUNNING), "state is not PS_RUNNING");
+
+ thr_sigframe_save(curthread, &psf);
+ /*
+ * Lower the priority before calling the handler in case
+ * it never returns (longjmps back):
+ */
+ crit = _kse_critical_enter();
+ curkse = curthread->kse;
+ KSE_SCHED_LOCK(curkse, curkse->k_kseg);
+ KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock);
+ curthread->active_priority &= ~THR_SIGNAL_PRIORITY;
+ SIGFILLSET(sigmask);
+ while (1) {
+ /*
+ * For bound thread, we mask all signals and get a fresh
+ * copy of signal mask from kernel
+ */
+ if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) {
+ __sys_sigprocmask(SIG_SETMASK, &sigmask,
+ &curthread->sigmask);
+ }
+ for (i = 1; i <= _SIG_MAXSIG; i++) {
+ if (SIGISMEMBER(curthread->sigmask, i))
+ continue;
+ if (SIGISMEMBER(curthread->sigpend, i)) {
+ SIGDELSET(curthread->sigpend, i);
+ siginfo = curthread->siginfo[i-1];
+ break;
+ }
+ if (!(curthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
+ && SIGISMEMBER(_thr_proc_sigpending, i)) {
+ if (_thr_getprocsig_unlocked(i, &siginfo))
+ break;
+ }
+ }
+ if (i <= _SIG_MAXSIG)
+ thr_sig_invoke_handler(curthread, i, &siginfo, ucp);
+ else {
+ if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) {
+ __sys_sigprocmask(SIG_SETMASK,
+ &curthread->sigmask, NULL);
+ }
+ break;
+ }
+ }
+
+ /* Don't trust after signal handling */
+ curkse = curthread->kse;
+ KSE_LOCK_RELEASE(curkse, &_thread_signal_lock);
+ KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
+ _kse_critical_leave(&curthread->tcb->tcb_tmbx);
+ /* repost masked signal to kernel, it hardly happens in real world */
+ if ((curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) &&
+ !SIGISEMPTY(curthread->sigpend)) { /* dirty read */
+ __sys_sigprocmask(SIG_SETMASK, &sigmask, &curthread->sigmask);
+ for (i = 1; i <= _SIG_MAXSIG; ++i) {
+ if (SIGISMEMBER(curthread->sigpend, i)) {
+ SIGDELSET(curthread->sigpend, i);
+ if (!_kse_isthreaded())
+ kill(getpid(), i);
+ else
+ kse_thr_interrupt(
+ &curthread->tcb->tcb_tmbx,
+ KSE_INTR_SENDSIG,
+ i);
+ }
+ }
+ __sys_sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL);
+ }
+ DBG_MSG("<<< thr_sig_rundown (%p)\n", curthread);
+
+ thr_sigframe_restore(curthread, &psf);
+ errno = err_save;
+}
+
+/*
+ * This checks pending signals for the current thread. It should be
+ * called whenever a thread changes its signal mask. Note that this
+ * is called from a thread (using its stack).
+ *
+ * XXX - We might want to just check to see if there are pending
+ * signals for the thread here, but enter the UTS scheduler
+ * to actually install the signal handler(s).
+ */
+void
+_thr_sig_check_pending(struct pthread *curthread)
+{
+ ucontext_t uc;
+ volatile int once;
+ int errsave;
+
+ /*
+ * If the thread is in critical region, delay processing signals.
+ * If the thread state is not PS_RUNNING, it might be switching
+ * into UTS and but a THR_LOCK_RELEASE saw check_pending, and it
+ * goes here, in the case we delay processing signals, lets UTS
+ * process complicated things, normally UTS will call _thr_sig_add
+ * to resume the thread, so we needn't repeat doing it here.
+ */
+ if (THR_IN_CRITICAL(curthread) || curthread->state != PS_RUNNING)
+ return;
+
+ errsave = errno;
+ once = 0;
+ THR_GETCONTEXT(&uc);
+ if (once == 0) {
+ once = 1;
+ curthread->check_pending = 0;
+ _thr_sig_rundown(curthread, &uc);
+ }
+ errno = errsave;
+}
+
+/*
+ * Perform thread specific actions in response to a signal.
+ * This function is only called if there is a handler installed
+ * for the signal, and if the target thread has the signal
+ * unmasked.
+ *
+ * This must be called with the thread's scheduling lock held.
+ */
+struct kse_mailbox *
+_thr_sig_add(struct pthread *pthread, int sig, siginfo_t *info)
+{
+ siginfo_t siginfo;
+ struct kse *curkse;
+ struct kse_mailbox *kmbx = NULL;
+ struct pthread *curthread = _get_curthread();
+ int restart;
+ int suppress_handler = 0;
+ int fromproc = 0;
+ __sighandler_t *sigfunc;
+
+ DBG_MSG(">>> _thr_sig_add %p (%d)\n", pthread, sig);
+
+ curkse = _get_curkse();
+ restart = _thread_sigact[sig - 1].sa_flags & SA_RESTART;
+ sigfunc = _thread_sigact[sig - 1].sa_handler;
+ fromproc = (curthread == _thr_sig_daemon);
+
+ if (pthread->state == PS_DEAD || pthread->state == PS_DEADLOCK ||
+ pthread->state == PS_STATE_MAX)
+ return (NULL); /* return false */
+
+ if ((pthread->attr.flags & PTHREAD_SCOPE_SYSTEM) &&
+ (curthread != pthread)) {
+ PANIC("Please use _thr_send_sig for bound thread");
+ return (NULL);
+ }
+
+ if (pthread->state != PS_SIGWAIT &&
+ SIGISMEMBER(pthread->sigmask, sig)) {
+ /* signal is masked, just add signal to thread. */
+ if (!fromproc) {
+ SIGADDSET(pthread->sigpend, sig);
+ if (info == NULL)
+ build_siginfo(&pthread->siginfo[sig-1], sig);
+ else if (info != &pthread->siginfo[sig-1])
+ memcpy(&pthread->siginfo[sig-1], info,
+ sizeof(*info));
+ } else {
+ if (!_thr_getprocsig(sig, &pthread->siginfo[sig-1]))
+ return (NULL);
+ SIGADDSET(pthread->sigpend, sig);
+ }
+ }
+ else {
+ /* if process signal not exists, just return */
+ if (fromproc) {
+ if (!_thr_getprocsig(sig, &siginfo))
+ return (NULL);
+ info = &siginfo;
+ }
+
+ if (pthread->state != PS_SIGWAIT && sigfunc == SIG_DFL &&
+ (sigprop(sig) & SA_KILL)) {
+ kse_thr_interrupt(NULL, KSE_INTR_SIGEXIT, sig);
+ /* Never reach */
+ }
+
+ /*
+ * Process according to thread state:
+ */
+ switch (pthread->state) {
+ case PS_DEAD:
+ case PS_DEADLOCK:
+ case PS_STATE_MAX:
+ return (NULL); /* XXX return false */
+ case PS_LOCKWAIT:
+ case PS_SUSPENDED:
+ /*
+ * You can't call a signal handler for threads in these
+ * states.
+ */
+ suppress_handler = 1;
+ break;
+ case PS_RUNNING:
+ if ((pthread->flags & THR_FLAGS_IN_RUNQ)) {
+ THR_RUNQ_REMOVE(pthread);
+ pthread->active_priority |= THR_SIGNAL_PRIORITY;
+ THR_RUNQ_INSERT_TAIL(pthread);
+ } else {
+ /* Possible not in RUNQ and has curframe ? */
+ pthread->active_priority |= THR_SIGNAL_PRIORITY;
+ }
+ break;
+ /*
+ * States which cannot be interrupted but still require the
+ * signal handler to run:
+ */
+ case PS_COND_WAIT:
+ case PS_MUTEX_WAIT:
+ break;
+
+ case PS_SLEEP_WAIT:
+ /*
+ * Unmasked signals always cause sleep to terminate
+ * early regardless of SA_RESTART:
+ */
+ pthread->interrupted = 1;
+ break;
+
+ case PS_JOIN:
+ break;
+
+ case PS_SIGSUSPEND:
+ pthread->interrupted = 1;
+ break;
+
+ case PS_SIGWAIT:
+ if (info == NULL)
+ build_siginfo(&pthread->siginfo[sig-1], sig);
+ else if (info != &pthread->siginfo[sig-1])
+ memcpy(&pthread->siginfo[sig-1], info,
+ sizeof(*info));
+ /*
+ * The signal handler is not called for threads in
+ * SIGWAIT.
+ */
+ suppress_handler = 1;
+ /* Wake up the thread if the signal is not blocked. */
+ if (SIGISMEMBER(*(pthread->data.sigwait->waitset), sig)) {
+ /* Return the signal number: */
+ *(pthread->data.sigwait->siginfo) = pthread->siginfo[sig-1];
+ /* Make the thread runnable: */
+ kmbx = _thr_setrunnable_unlocked(pthread);
+ } else {
+ /* Increment the pending signal count. */
+ SIGADDSET(pthread->sigpend, sig);
+ if (!SIGISMEMBER(pthread->sigmask, sig)) {
+ if (sigfunc == SIG_DFL &&
+ sigprop(sig) & SA_KILL) {
+ kse_thr_interrupt(NULL,
+ KSE_INTR_SIGEXIT,
+ sig);
+ /* Never reach */
+ }
+ pthread->check_pending = 1;
+ pthread->interrupted = 1;
+ kmbx = _thr_setrunnable_unlocked(pthread);
+ }
+ }
+ return (kmbx);
+ }
+
+ SIGADDSET(pthread->sigpend, sig);
+ if (info == NULL)
+ build_siginfo(&pthread->siginfo[sig-1], sig);
+ else if (info != &pthread->siginfo[sig-1])
+ memcpy(&pthread->siginfo[sig-1], info, sizeof(*info));
+ pthread->check_pending = 1;
+ if (!(pthread->attr.flags & PTHREAD_SCOPE_SYSTEM) &&
+ (pthread->blocked != 0) && !THR_IN_CRITICAL(pthread))
+ kse_thr_interrupt(&pthread->tcb->tcb_tmbx,
+ restart ? KSE_INTR_RESTART : KSE_INTR_INTERRUPT, 0);
+ if (suppress_handler == 0) {
+ /*
+ * Setup a signal frame and save the current threads
+ * state:
+ */
+ if (pthread->state != PS_RUNNING) {
+ if (pthread->flags & THR_FLAGS_IN_RUNQ)
+ THR_RUNQ_REMOVE(pthread);
+ pthread->active_priority |= THR_SIGNAL_PRIORITY;
+ kmbx = _thr_setrunnable_unlocked(pthread);
+ }
+ }
+ }
+ return (kmbx);
+}
+
+/*
+ * Send a signal to a specific thread (ala pthread_kill):
+ */
+void
+_thr_sig_send(struct pthread *pthread, int sig)
+{
+ struct pthread *curthread = _get_curthread();
+ struct kse_mailbox *kmbx;
+
+ if (pthread->attr.flags & PTHREAD_SCOPE_SYSTEM) {
+ kse_thr_interrupt(&pthread->tcb->tcb_tmbx, KSE_INTR_SENDSIG, sig);
+ return;
+ }
+
+ /* Lock the scheduling queue of the target thread. */
+ THR_SCHED_LOCK(curthread, pthread);
+ if (_thread_sigact[sig - 1].sa_handler != SIG_IGN) {
+ kmbx = _thr_sig_add(pthread, sig, NULL);
+ /* Add a preemption point. */
+ if (kmbx == NULL && (curthread->kseg == pthread->kseg) &&
+ (pthread->active_priority > curthread->active_priority))
+ curthread->critical_yield = 1;
+ THR_SCHED_UNLOCK(curthread, pthread);
+ if (kmbx != NULL)
+ kse_wakeup(kmbx);
+ /* XXX
+ * If thread sent signal to itself, check signals now.
+ * It is not really needed, _kse_critical_leave should
+ * have already checked signals.
+ */
+ if (pthread == curthread && curthread->check_pending)
+ _thr_sig_check_pending(curthread);
+
+ } else {
+ THR_SCHED_UNLOCK(curthread, pthread);
+ }
+}
+
+static inline void
+thr_sigframe_restore(struct pthread *curthread, struct pthread_sigframe *psf)
+{
+ kse_critical_t crit;
+ struct kse *curkse;
+
+ THR_THREAD_LOCK(curthread, curthread);
+ curthread->cancelflags = psf->psf_cancelflags;
+ crit = _kse_critical_enter();
+ curkse = curthread->kse;
+ KSE_SCHED_LOCK(curkse, curthread->kseg);
+ curthread->flags = psf->psf_flags;
+ curthread->interrupted = psf->psf_interrupted;
+ curthread->timeout = psf->psf_timeout;
+ curthread->data = psf->psf_wait_data;
+ curthread->wakeup_time = psf->psf_wakeup_time;
+ curthread->continuation = psf->psf_continuation;
+ KSE_SCHED_UNLOCK(curkse, curthread->kseg);
+ _kse_critical_leave(crit);
+ THR_THREAD_UNLOCK(curthread, curthread);
+}
+
+static inline void
+thr_sigframe_save(struct pthread *curthread, struct pthread_sigframe *psf)
+{
+ kse_critical_t crit;
+ struct kse *curkse;
+
+ THR_THREAD_LOCK(curthread, curthread);
+ psf->psf_cancelflags = curthread->cancelflags;
+ crit = _kse_critical_enter();
+ curkse = curthread->kse;
+ KSE_SCHED_LOCK(curkse, curthread->kseg);
+ /* This has to initialize all members of the sigframe. */
+ psf->psf_flags = (curthread->flags & (THR_FLAGS_PRIVATE | THR_FLAGS_EXITING));
+ psf->psf_interrupted = curthread->interrupted;
+ psf->psf_timeout = curthread->timeout;
+ psf->psf_wait_data = curthread->data;
+ psf->psf_wakeup_time = curthread->wakeup_time;
+ psf->psf_continuation = curthread->continuation;
+ KSE_SCHED_UNLOCK(curkse, curthread->kseg);
+ _kse_critical_leave(crit);
+ THR_THREAD_UNLOCK(curthread, curthread);
+}
+
+void
+_thr_signal_init(void)
+{
+ struct sigaction act;
+ __siginfohandler_t *sigfunc;
+ int i;
+ sigset_t sigset;
+
+ SIGFILLSET(sigset);
+ __sys_sigprocmask(SIG_SETMASK, &sigset, &_thr_initial->sigmask);
+ /* Enter a loop to get the existing signal status: */
+ for (i = 1; i <= _SIG_MAXSIG; i++) {
+ /* Get the signal handler details: */
+ if (__sys_sigaction(i, NULL, &_thread_sigact[i - 1]) != 0) {
+ /*
+ * Abort this process if signal
+ * initialisation fails:
+ */
+ PANIC("Cannot read signal handler info");
+ }
+ /* Intall wrapper if handler was set */
+ sigfunc = _thread_sigact[i - 1].sa_sigaction;
+ if (((__sighandler_t *)sigfunc) != SIG_DFL &&
+ ((__sighandler_t *)sigfunc) != SIG_IGN) {
+ act = _thread_sigact[i - 1];
+ act.sa_flags |= SA_SIGINFO;
+ act.sa_sigaction =
+ (__siginfohandler_t *)_thr_sig_handler;
+ __sys_sigaction(i, &act, NULL);
+ }
+ }
+ if (_thr_dump_enabled()) {
+ /*
+ * Install the signal handler for SIGINFO. It isn't
+ * really needed, but it is nice to have for debugging
+ * purposes.
+ */
+ _thread_sigact[SIGINFO - 1].sa_flags = SA_SIGINFO | SA_RESTART;
+ SIGEMPTYSET(act.sa_mask);
+ act.sa_flags = SA_SIGINFO | SA_RESTART;
+ act.sa_sigaction = (__siginfohandler_t *)&_thr_sig_handler;
+ if (__sys_sigaction(SIGINFO, &act, NULL) != 0) {
+ __sys_sigprocmask(SIG_SETMASK, &_thr_initial->sigmask,
+ NULL);
+ /*
+ * Abort this process if signal initialisation fails:
+ */
+ PANIC("Cannot initialize signal handler");
+ }
+ }
+ __sys_sigprocmask(SIG_SETMASK, &_thr_initial->sigmask, NULL);
+ __sys_sigaltstack(NULL, &_thr_initial->sigstk);
+}
+
+void
+_thr_signal_deinit(void)
+{
+ int i;
+ struct pthread *curthread = _get_curthread();
+
+ /* Clear process pending signals. */
+ sigemptyset(&_thr_proc_sigpending);
+
+ /* Enter a loop to get the existing signal status: */
+ for (i = 1; i <= _SIG_MAXSIG; i++) {
+ /* Check for signals which cannot be trapped: */
+ if (i == SIGKILL || i == SIGSTOP) {
+ }
+
+ /* Set the signal handler details: */
+ else if (__sys_sigaction(i, &_thread_sigact[i - 1],
+ NULL) != 0) {
+ /*
+ * Abort this process if signal
+ * initialisation fails:
+ */
+ PANIC("Cannot set signal handler info");
+ }
+ }
+ __sys_sigaltstack(&curthread->sigstk, NULL);
+}
+
diff --git a/lib/libkse/thread/thr_sigaction.c b/lib/libkse/thread/thr_sigaction.c
new file mode 100644
index 0000000..7ee0ce6
--- /dev/null
+++ b/lib/libkse/thread/thr_sigaction.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <signal.h>
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_sigaction);
+LT10_COMPAT_DEFAULT(sigaction);
+
+__weak_reference(_sigaction, sigaction);
+
+int
+_sigaction(int sig, const struct sigaction * act, struct sigaction * oact)
+{
+ int ret = 0;
+ int err = 0;
+ struct sigaction newact, oldact;
+ struct pthread *curthread;
+ kse_critical_t crit;
+
+ /* Check if the signal number is out of range: */
+ if (sig < 1 || sig > _SIG_MAXSIG) {
+ /* Return an invalid argument: */
+ errno = EINVAL;
+ ret = -1;
+ } else {
+ if (act)
+ newact = *act;
+
+ crit = _kse_critical_enter();
+ curthread = _get_curthread();
+ KSE_LOCK_ACQUIRE(curthread->kse, &_thread_signal_lock);
+
+ oldact = _thread_sigact[sig - 1];
+
+ /* Check if a signal action was supplied: */
+ if (act != NULL) {
+ /* Set the new signal handler: */
+ _thread_sigact[sig - 1] = newact;
+ }
+
+ /*
+ * Check if the kernel needs to be advised of a change
+ * in signal action:
+ */
+ if (act != NULL && sig != SIGINFO) {
+
+ newact.sa_flags |= SA_SIGINFO;
+
+ /*
+ * Check if the signal handler is being set to
+ * the default or ignore handlers:
+ */
+ if (newact.sa_handler != SIG_DFL &&
+ newact.sa_handler != SIG_IGN) {
+ /*
+ * Specify the thread kernel signal
+ * handler:
+ */
+ newact.sa_handler = (void (*) ())_thr_sig_handler;
+ }
+ /* Change the signal action in the kernel: */
+ if (__sys_sigaction(sig, &newact, NULL) != 0) {
+ _thread_sigact[sig - 1] = oldact;
+ /* errno is in kse, will copy it to thread */
+ err = errno;
+ ret = -1;
+ }
+ }
+ KSE_LOCK_RELEASE(curthread->kse, &_thread_signal_lock);
+ _kse_critical_leave(crit);
+ /*
+ * Check if the existing signal action structure contents are
+ * to be returned:
+ */
+ if (oact != NULL) {
+ /* Return the existing signal action contents: */
+ *oact = oldact;
+ }
+ if (ret != 0) {
+ /* Return errno to thread */
+ errno = err;
+ }
+ }
+
+ /* Return the completion status: */
+ return (ret);
+}
diff --git a/lib/libkse/thread/thr_sigaltstack.c b/lib/libkse/thread/thr_sigaltstack.c
new file mode 100644
index 0000000..8ebbdee
--- /dev/null
+++ b/lib/libkse/thread/thr_sigaltstack.c
@@ -0,0 +1,110 @@
+/*-
+ * Copyright (c) 2003 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <signal.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_sigaltstack);
+LT10_COMPAT_DEFAULT(sigaltstack);
+
+__weak_reference(_sigaltstack, sigaltstack);
+
+int
+_sigaltstack(stack_t *_ss, stack_t *_oss)
+{
+ struct pthread *curthread = _get_curthread();
+ stack_t ss, oss;
+ int oonstack, errsave, ret;
+ kse_critical_t crit;
+
+ if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) {
+ crit = _kse_critical_enter();
+ ret = __sys_sigaltstack(_ss, _oss);
+ errsave = errno;
+ /* Get a copy */
+ if (ret == 0 && _ss != NULL)
+ curthread->sigstk = *_ss;
+ _kse_critical_leave(crit);
+ errno = errsave;
+ return (ret);
+ }
+
+ if (_ss)
+ ss = *_ss;
+ if (_oss)
+ oss = *_oss;
+
+ /* Should get and set stack in atomic way */
+ crit = _kse_critical_enter();
+ oonstack = _thr_sigonstack(&ss);
+ if (_oss != NULL) {
+ oss = curthread->sigstk;
+ oss.ss_flags = (curthread->sigstk.ss_flags & SS_DISABLE)
+ ? SS_DISABLE : ((oonstack) ? SS_ONSTACK : 0);
+ }
+
+ if (_ss != NULL) {
+ if (oonstack) {
+ _kse_critical_leave(crit);
+ errno = EPERM;
+ return (-1);
+ }
+ if ((ss.ss_flags & ~SS_DISABLE) != 0) {
+ _kse_critical_leave(crit);
+ errno = EINVAL;
+ return (-1);
+ }
+ if (!(ss.ss_flags & SS_DISABLE)) {
+ if (ss.ss_size < MINSIGSTKSZ) {
+ _kse_critical_leave(crit);
+ errno = ENOMEM;
+ return (-1);
+ }
+ curthread->sigstk = ss;
+ } else {
+ curthread->sigstk.ss_flags |= SS_DISABLE;
+ }
+ }
+ _kse_critical_leave(crit);
+ if (_oss != NULL)
+ *_oss = oss;
+ return (0);
+}
+
+int
+_thr_sigonstack(void *sp)
+{
+ struct pthread *curthread = _get_curthread();
+
+ return ((curthread->sigstk.ss_flags & SS_DISABLE) == 0 ?
+ (((size_t)sp - (size_t)curthread->sigstk.ss_sp) < curthread->sigstk.ss_size)
+ : 0);
+}
+
diff --git a/lib/libkse/thread/thr_sigmask.c b/lib/libkse/thread/thr_sigmask.c
new file mode 100644
index 0000000..05f5ae1
--- /dev/null
+++ b/lib/libkse/thread/thr_sigmask.c
@@ -0,0 +1,116 @@
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/signalvar.h>
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_sigmask);
+LT10_COMPAT_DEFAULT(pthread_sigmask);
+
+__weak_reference(_pthread_sigmask, pthread_sigmask);
+
+int
+_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
+{
+ struct pthread *curthread = _get_curthread();
+ sigset_t oldset, newset;
+ int ret;
+
+ if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) {
+ ret = __sys_sigprocmask(how, set, oset);
+ if (ret != 0)
+ ret = errno;
+ /* Get a fresh copy */
+ __sys_sigprocmask(SIG_SETMASK, NULL, &curthread->sigmask);
+ return (ret);
+ }
+
+ if (set)
+ newset = *set;
+
+ THR_SCHED_LOCK(curthread, curthread);
+
+ ret = 0;
+ if (oset != NULL)
+ /* Return the current mask: */
+ oldset = curthread->sigmask;
+
+ /* Check if a new signal set was provided by the caller: */
+ if (set != NULL) {
+ /* Process according to what to do: */
+ switch (how) {
+ /* Block signals: */
+ case SIG_BLOCK:
+ /* Add signals to the existing mask: */
+ SIGSETOR(curthread->sigmask, newset);
+ break;
+
+ /* Unblock signals: */
+ case SIG_UNBLOCK:
+ /* Clear signals from the existing mask: */
+ SIGSETNAND(curthread->sigmask, newset);
+ break;
+
+ /* Set the signal process mask: */
+ case SIG_SETMASK:
+ /* Set the new mask: */
+ curthread->sigmask = newset;
+ break;
+
+ /* Trap invalid actions: */
+ default:
+ /* Return an invalid argument: */
+ ret = EINVAL;
+ break;
+ }
+ SIG_CANTMASK(curthread->sigmask);
+ THR_SCHED_UNLOCK(curthread, curthread);
+
+ /*
+ * Run down any pending signals:
+ */
+ if (ret == 0)
+ _thr_sig_check_pending(curthread);
+ } else
+ THR_SCHED_UNLOCK(curthread, curthread);
+
+ if (ret == 0 && oset != NULL)
+ *oset = oldset;
+ return (ret);
+}
diff --git a/lib/libkse/thread/thr_sigpending.c b/lib/libkse/thread/thr_sigpending.c
new file mode 100644
index 0000000..5c666bf
--- /dev/null
+++ b/lib/libkse/thread/thr_sigpending.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 1999 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/signalvar.h>
+#include <signal.h>
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_sigpending);
+LT10_COMPAT_DEFAULT(sigpending);
+
+__weak_reference(_sigpending, sigpending);
+
+int
+_sigpending(sigset_t *set)
+{
+ struct pthread *curthread = _get_curthread();
+ kse_critical_t crit;
+ sigset_t sigset;
+ int ret = 0;
+
+ /* Check for a null signal set pointer: */
+ if (set == NULL) {
+ /* Return an invalid argument: */
+ ret = EINVAL;
+ }
+ else {
+ if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
+ return (__sys_sigpending(set));
+
+ crit = _kse_critical_enter();
+ KSE_SCHED_LOCK(curthread->kse, curthread->kseg);
+ sigset = curthread->sigpend;
+ KSE_SCHED_UNLOCK(curthread->kse, curthread->kseg);
+ KSE_LOCK_ACQUIRE(curthread->kse, &_thread_signal_lock);
+ SIGSETOR(sigset, _thr_proc_sigpending);
+ KSE_LOCK_RELEASE(curthread->kse, &_thread_signal_lock);
+ _kse_critical_leave(crit);
+ *set = sigset;
+ }
+ /* Return the completion status: */
+ return (ret);
+}
diff --git a/lib/libkse/thread/thr_sigprocmask.c b/lib/libkse/thread/thr_sigprocmask.c
new file mode 100644
index 0000000..d2a20dd
--- /dev/null
+++ b/lib/libkse/thread/thr_sigprocmask.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/signalvar.h>
+#include <signal.h>
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_sigprocmask);
+LT10_COMPAT_DEFAULT(sigprocmask);
+
+__weak_reference(_sigprocmask, sigprocmask);
+
+int
+_sigprocmask(int how, const sigset_t *set, sigset_t *oset)
+{
+ int ret;
+
+ ret = pthread_sigmask(how, set, oset);
+ if (ret) {
+ errno = ret;
+ ret = -1;
+ }
+ return (ret);
+}
diff --git a/lib/libkse/thread/thr_sigsuspend.c b/lib/libkse/thread/thr_sigsuspend.c
new file mode 100644
index 0000000..2f3ed5d
--- /dev/null
+++ b/lib/libkse/thread/thr_sigsuspend.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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/signalvar.h>
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <string.h>
+
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__sigsuspend);
+LT10_COMPAT_PRIVATE(_sigsuspend);
+LT10_COMPAT_DEFAULT(sigsuspend);
+
+__weak_reference(__sigsuspend, sigsuspend);
+
+int
+_sigsuspend(const sigset_t *set)
+{
+ struct pthread *curthread = _get_curthread();
+ sigset_t oldmask, newmask, tempset;
+ int ret = -1;
+
+ if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
+ return (__sys_sigsuspend(set));
+
+ /* Check if a new signal set was provided by the caller: */
+ if (set != NULL) {
+ newmask = *set;
+ SIG_CANTMASK(newmask);
+ THR_LOCK_SWITCH(curthread);
+
+ /* Save current sigmask: */
+ oldmask = curthread->sigmask;
+ curthread->oldsigmask = &oldmask;
+
+ /* Change the caller's mask: */
+ curthread->sigmask = newmask;
+ tempset = curthread->sigpend;
+ SIGSETNAND(tempset, newmask);
+ if (SIGISEMPTY(tempset)) {
+ THR_SET_STATE(curthread, PS_SIGSUSPEND);
+ /* Wait for a signal: */
+ _thr_sched_switch_unlocked(curthread);
+ } else {
+ curthread->check_pending = 1;
+ THR_UNLOCK_SWITCH(curthread);
+ /* check pending signal I can handle: */
+ _thr_sig_check_pending(curthread);
+ }
+ if ((curthread->cancelflags & THR_CANCELLING) != 0)
+ curthread->oldsigmask = NULL;
+ else {
+ THR_ASSERT(curthread->oldsigmask == NULL,
+ "oldsigmask is not cleared");
+ }
+
+ /* Always return an interrupted error: */
+ errno = EINTR;
+ } else {
+ /* Return an invalid argument error: */
+ errno = EINVAL;
+ }
+
+ /* Return the completion status: */
+ return (ret);
+}
+
+int
+__sigsuspend(const sigset_t * set)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ _thr_cancel_enter(curthread);
+ ret = _sigsuspend(set);
+ _thr_cancel_leave(curthread, 1);
+
+ return (ret);
+}
diff --git a/lib/libkse/thread/thr_sigwait.c b/lib/libkse/thread/thr_sigwait.c
new file mode 100644
index 0000000..cd7ac22
--- /dev/null
+++ b/lib/libkse/thread/thr_sigwait.c
@@ -0,0 +1,212 @@
+//depot/projects/kse/lib/libpthread/thread/thr_sigwait.c#1 - branch change 15154 (text+ko)
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <signal.h>
+#include <sys/param.h>
+#include <sys/signalvar.h>
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__sigwait);
+LT10_COMPAT_PRIVATE(_sigwait);
+LT10_COMPAT_DEFAULT(sigwait);
+LT10_COMPAT_PRIVATE(__sigtimedwait);
+LT10_COMPAT_PRIVATE(_sigtimedwait);
+LT10_COMPAT_DEFAULT(sigtimedwait);
+LT10_COMPAT_PRIVATE(__sigwaitinfo);
+LT10_COMPAT_PRIVATE(_sigwaitinfo);
+LT10_COMPAT_DEFAULT(sigwaitinfo);
+
+__weak_reference(__sigwait, sigwait);
+__weak_reference(__sigtimedwait, sigtimedwait);
+__weak_reference(__sigwaitinfo, sigwaitinfo);
+
+static int
+lib_sigtimedwait(const sigset_t *set, siginfo_t *info,
+ const struct timespec * timeout)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret = 0;
+ int i;
+ struct sigwait_data waitdata;
+ sigset_t waitset;
+ kse_critical_t crit;
+ siginfo_t siginfo;
+
+ if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) {
+ if (info == NULL)
+ info = &siginfo;
+ return (__sys_sigtimedwait((sigset_t *)set, info,
+ (struct timespec *)timeout));
+ }
+
+ /*
+ * Initialize the set of signals that will be waited on:
+ */
+ waitset = *set;
+
+ /* These signals can't be waited on. */
+ SIGDELSET(waitset, SIGKILL);
+ SIGDELSET(waitset, SIGSTOP);
+
+ /*
+ * POSIX says that the _application_ must explicitly install
+ * a dummy handler for signals that are SIG_IGN in order
+ * to sigwait on them. Note that SIG_IGN signals are left in
+ * the mask because a subsequent sigaction could enable an
+ * ignored signal.
+ */
+
+ crit = _kse_critical_enter();
+ KSE_SCHED_LOCK(curthread->kse, curthread->kseg);
+ for (i = 1; i <= _SIG_MAXSIG; ++i) {
+ if (SIGISMEMBER(waitset, i) &&
+ SIGISMEMBER(curthread->sigpend, i)) {
+ SIGDELSET(curthread->sigpend, i);
+ siginfo = curthread->siginfo[i - 1];
+ KSE_SCHED_UNLOCK(curthread->kse,
+ curthread->kseg);
+ _kse_critical_leave(crit);
+ ret = i;
+ goto OUT;
+ }
+ }
+ curthread->timeout = 0;
+ curthread->interrupted = 0;
+ _thr_set_timeout(timeout);
+ /* Wait for a signal: */
+ siginfo.si_signo = 0;
+ waitdata.waitset = &waitset;
+ waitdata.siginfo = &siginfo;
+ curthread->data.sigwait = &waitdata;
+ THR_SET_STATE(curthread, PS_SIGWAIT);
+ _thr_sched_switch_unlocked(curthread);
+ /*
+ * Return the signal number to the caller:
+ */
+ if (siginfo.si_signo > 0) {
+ ret = siginfo.si_signo;
+ } else {
+ if (curthread->interrupted)
+ errno = EINTR;
+ else if (curthread->timeout)
+ errno = EAGAIN;
+ ret = -1;
+ }
+ curthread->timeout = 0;
+ curthread->interrupted = 0;
+ /*
+ * Probably unnecessary, but since it's in a union struct
+ * we don't know how it could be used in the future.
+ */
+ curthread->data.sigwait = NULL;
+
+OUT:
+ if (ret > 0 && info != NULL)
+ *info = siginfo;
+
+ return (ret);
+}
+
+int
+__sigtimedwait(const sigset_t *set, siginfo_t *info,
+ const struct timespec * timeout)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ _thr_cancel_enter(curthread);
+ ret = lib_sigtimedwait(set, info, timeout);
+ _thr_cancel_leave(curthread, 1);
+ return (ret);
+}
+
+int _sigtimedwait(const sigset_t *set, siginfo_t *info,
+ const struct timespec * timeout)
+{
+ return lib_sigtimedwait(set, info, timeout);
+}
+
+int
+__sigwaitinfo(const sigset_t *set, siginfo_t *info)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ _thr_cancel_enter(curthread);
+ ret = lib_sigtimedwait(set, info, NULL);
+ _thr_cancel_leave(curthread, 1);
+ return (ret);
+}
+
+int
+_sigwaitinfo(const sigset_t *set, siginfo_t *info)
+{
+ return lib_sigtimedwait(set, info, NULL);
+}
+
+int
+__sigwait(const sigset_t *set, int *sig)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ _thr_cancel_enter(curthread);
+ ret = lib_sigtimedwait(set, NULL, NULL);
+ if (ret > 0) {
+ *sig = ret;
+ ret = 0;
+ } else {
+ ret = errno;
+ }
+ _thr_cancel_leave(curthread, 1);
+ return (ret);
+}
+
+int
+_sigwait(const sigset_t *set, int *sig)
+{
+ int ret;
+
+ ret = lib_sigtimedwait(set, NULL, NULL);
+ if (ret > 0) {
+ *sig = ret;
+ ret = 0;
+ } else {
+ ret = errno;
+ }
+ return (ret);
+}
+
diff --git a/lib/libkse/thread/thr_single_np.c b/lib/libkse/thread/thr_single_np.c
new file mode 100644
index 0000000..882f6aa
--- /dev/null
+++ b/lib/libkse/thread/thr_single_np.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1996 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <pthread_np.h>
+
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_single_np);
+LT10_COMPAT_DEFAULT(pthread_single_np);
+
+__weak_reference(_pthread_single_np, pthread_single_np);
+
+int _pthread_single_np()
+{
+
+ /* Enter single-threaded (non-POSIX) scheduling mode: */
+ pthread_suspend_all_np();
+ /*
+ * XXX - Do we want to do this?
+ * __is_threaded = 0;
+ */
+ return (0);
+}
diff --git a/lib/libkse/thread/thr_sleep.c b/lib/libkse/thread/thr_sleep.c
new file mode 100644
index 0000000..0a11876
--- /dev/null
+++ b/lib/libkse/thread/thr_sleep.c
@@ -0,0 +1,71 @@
+/*
+ * 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$
+ */
+
+#include <unistd.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+extern unsigned int __sleep(unsigned int);
+extern int __usleep(useconds_t);
+
+LT10_COMPAT_PRIVATE(_sleep);
+LT10_COMPAT_DEFAULT(sleep);
+LT10_COMPAT_PRIVATE(_usleep);
+LT10_COMPAT_DEFAULT(usleep);
+
+__weak_reference(_sleep, sleep);
+__weak_reference(_usleep, usleep);
+
+unsigned int
+_sleep(unsigned int seconds)
+{
+ struct pthread *curthread = _get_curthread();
+ unsigned int ret;
+
+ _thr_cancel_enter(curthread);
+ ret = __sleep(seconds);
+ _thr_cancel_leave(curthread, 1);
+
+ return (ret);
+}
+
+int
+_usleep(useconds_t useconds)
+{
+ struct pthread *curthread = _get_curthread();
+ unsigned int ret;
+
+ _thr_cancel_enter(curthread);
+ ret = __usleep(useconds);
+ _thr_cancel_leave(curthread, 1);
+
+ return (ret);
+}
diff --git a/lib/libkse/thread/thr_spec.c b/lib/libkse/thread/thr_spec.c
new file mode 100644
index 0000000..f6e8861
--- /dev/null
+++ b/lib/libkse/thread/thr_spec.c
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <pthread.h>
+
+#include "thr_private.h"
+
+
+struct pthread_key _thread_keytable[PTHREAD_KEYS_MAX];
+
+/*
+ * XXX - This breaks the linker if LT10_COMPAT_DEFAULT doesn't
+ * also include a weak reference to the default symbol.
+ */
+LT10_COMPAT_PRIVATE(_thread_keytable);
+
+LT10_COMPAT_PRIVATE(_pthread_key_create);
+LT10_COMPAT_DEFAULT(pthread_key_create);
+LT10_COMPAT_PRIVATE(_pthread_key_delete);
+LT10_COMPAT_DEFAULT(pthread_key_delete);
+LT10_COMPAT_PRIVATE(_pthread_getspecific);
+LT10_COMPAT_DEFAULT(pthread_getspecific);
+LT10_COMPAT_PRIVATE(_pthread_setspecific);
+LT10_COMPAT_DEFAULT(pthread_setspecific);
+
+__weak_reference(_pthread_key_create, pthread_key_create);
+__weak_reference(_pthread_key_delete, pthread_key_delete);
+__weak_reference(_pthread_getspecific, pthread_getspecific);
+__weak_reference(_pthread_setspecific, pthread_setspecific);
+
+
+int
+_pthread_key_create(pthread_key_t *key, void (*destructor) (void *))
+{
+ struct pthread *curthread = _get_curthread();
+ int i;
+
+ /* Lock the key table: */
+ THR_LOCK_ACQUIRE(curthread, &_keytable_lock);
+ for (i = 0; i < PTHREAD_KEYS_MAX; i++) {
+
+ if (_thread_keytable[i].allocated == 0) {
+ _thread_keytable[i].allocated = 1;
+ _thread_keytable[i].destructor = destructor;
+ _thread_keytable[i].seqno++;
+
+ /* Unlock the key table: */
+ THR_LOCK_RELEASE(curthread, &_keytable_lock);
+ *key = i;
+ return (0);
+ }
+
+ }
+ /* Unlock the key table: */
+ THR_LOCK_RELEASE(curthread, &_keytable_lock);
+ return (EAGAIN);
+}
+
+int
+_pthread_key_delete(pthread_key_t key)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret = 0;
+
+ if ((unsigned int)key < PTHREAD_KEYS_MAX) {
+ /* Lock the key table: */
+ THR_LOCK_ACQUIRE(curthread, &_keytable_lock);
+
+ if (_thread_keytable[key].allocated)
+ _thread_keytable[key].allocated = 0;
+ else
+ ret = EINVAL;
+
+ /* Unlock the key table: */
+ THR_LOCK_RELEASE(curthread, &_keytable_lock);
+ } else
+ ret = EINVAL;
+ return (ret);
+}
+
+void
+_thread_cleanupspecific(void)
+{
+ struct pthread *curthread = _get_curthread();
+ void (*destructor)( void *);
+ void *data = NULL;
+ int key;
+ int i;
+
+ if (curthread->specific == NULL)
+ return;
+
+ /* Lock the key table: */
+ THR_LOCK_ACQUIRE(curthread, &_keytable_lock);
+ for (i = 0; (i < PTHREAD_DESTRUCTOR_ITERATIONS) &&
+ (curthread->specific_data_count > 0); i++) {
+ for (key = 0; (key < PTHREAD_KEYS_MAX) &&
+ (curthread->specific_data_count > 0); key++) {
+ destructor = NULL;
+
+ if (_thread_keytable[key].allocated &&
+ (curthread->specific[key].data != NULL)) {
+ if (curthread->specific[key].seqno ==
+ _thread_keytable[key].seqno) {
+ data = (void *)
+ curthread->specific[key].data;
+ destructor = _thread_keytable[key].destructor;
+ }
+ curthread->specific[key].data = NULL;
+ curthread->specific_data_count--;
+ }
+
+ /*
+ * If there is a destructore, call it
+ * with the key table entry unlocked:
+ */
+ if (destructor != NULL) {
+ /*
+ * Don't hold the lock while calling the
+ * destructor:
+ */
+ THR_LOCK_RELEASE(curthread, &_keytable_lock);
+ destructor(data);
+ THR_LOCK_ACQUIRE(curthread, &_keytable_lock);
+ }
+ }
+ }
+ THR_LOCK_RELEASE(curthread, &_keytable_lock);
+ free(curthread->specific);
+ curthread->specific = NULL;
+ if (curthread->specific_data_count > 0)
+ stderr_debug("Thread %p has exited with leftover "
+ "thread-specific data after %d destructor iterations\n",
+ curthread, PTHREAD_DESTRUCTOR_ITERATIONS);
+}
+
+static inline struct pthread_specific_elem *
+pthread_key_allocate_data(void)
+{
+ struct pthread_specific_elem *new_data;
+
+ new_data = (struct pthread_specific_elem *)
+ malloc(sizeof(struct pthread_specific_elem) * PTHREAD_KEYS_MAX);
+ if (new_data != NULL) {
+ memset((void *) new_data, 0,
+ sizeof(struct pthread_specific_elem) * PTHREAD_KEYS_MAX);
+ }
+ return (new_data);
+}
+
+int
+_pthread_setspecific(pthread_key_t key, const void *value)
+{
+ struct pthread *pthread;
+ int ret = 0;
+
+ /* Point to the running thread: */
+ pthread = _get_curthread();
+
+ if ((pthread->specific) ||
+ (pthread->specific = pthread_key_allocate_data())) {
+ if ((unsigned int)key < PTHREAD_KEYS_MAX) {
+ if (_thread_keytable[key].allocated) {
+ if (pthread->specific[key].data == NULL) {
+ if (value != NULL)
+ pthread->specific_data_count++;
+ } else if (value == NULL)
+ pthread->specific_data_count--;
+ pthread->specific[key].data = value;
+ pthread->specific[key].seqno =
+ _thread_keytable[key].seqno;
+ ret = 0;
+ } else
+ ret = EINVAL;
+ } else
+ ret = EINVAL;
+ } else
+ ret = ENOMEM;
+ return (ret);
+}
+
+void *
+_pthread_getspecific(pthread_key_t key)
+{
+ struct pthread *pthread;
+ void *data;
+
+ /* Point to the running thread: */
+ pthread = _get_curthread();
+
+ /* Check if there is specific data: */
+ if (pthread->specific != NULL && (unsigned int)key < PTHREAD_KEYS_MAX) {
+ /* Check if this key has been used before: */
+ if (_thread_keytable[key].allocated &&
+ (pthread->specific[key].seqno == _thread_keytable[key].seqno)) {
+ /* Return the value: */
+ data = (void *) pthread->specific[key].data;
+ } else {
+ /*
+ * This key has not been used before, so return NULL
+ * instead:
+ */
+ data = NULL;
+ }
+ } else
+ /* No specific data has been created, so just return NULL: */
+ data = NULL;
+ return (data);
+}
diff --git a/lib/libkse/thread/thr_spinlock.c b/lib/libkse/thread/thr_spinlock.c
new file mode 100644
index 0000000..d187439
--- /dev/null
+++ b/lib/libkse/thread/thr_spinlock.c
@@ -0,0 +1,152 @@
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <machine/atomic.h>
+
+#include <libc_private.h>
+#include "spinlock.h"
+#include "thr_private.h"
+
+#define MAX_SPINLOCKS 72
+
+struct spinlock_extra {
+ spinlock_t *owner;
+ pthread_mutex_t lock;
+};
+
+static void init_spinlock(spinlock_t *lck);
+
+static struct pthread_mutex_attr static_mutex_attr =
+ PTHREAD_MUTEXATTR_STATIC_INITIALIZER;
+static pthread_mutexattr_t static_mattr = &static_mutex_attr;
+
+static pthread_mutex_t spinlock_static_lock;
+static struct spinlock_extra extra[MAX_SPINLOCKS];
+static int spinlock_count = 0;
+static int initialized = 0;
+
+LT10_COMPAT_PRIVATE(_spinlock);
+LT10_COMPAT_PRIVATE(_spinlock_debug);
+LT10_COMPAT_PRIVATE(_spinunlock);
+
+/*
+ * These are for compatability only. Spinlocks of this type
+ * are deprecated.
+ */
+
+void
+_spinunlock(spinlock_t *lck)
+{
+ struct spinlock_extra *extra;
+
+ extra = (struct spinlock_extra *)lck->fname;
+ _pthread_mutex_unlock(&extra->lock);
+}
+
+/*
+ * Lock a location for the running thread. Yield to allow other
+ * threads to run if this thread is blocked because the lock is
+ * not available. Note that this function does not sleep. It
+ * assumes that the lock will be available very soon.
+ */
+void
+_spinlock(spinlock_t *lck)
+{
+ struct spinlock_extra *extra;
+
+ if (!__isthreaded)
+ PANIC("Spinlock called when not threaded.");
+ if (!initialized)
+ PANIC("Spinlocks not initialized.");
+ /*
+ * Try to grab the lock and loop if another thread grabs
+ * it before we do.
+ */
+ if (lck->fname == NULL)
+ init_spinlock(lck);
+ extra = (struct spinlock_extra *)lck->fname;
+ _pthread_mutex_lock(&extra->lock);
+}
+
+/*
+ * Lock a location for the running thread. Yield to allow other
+ * threads to run if this thread is blocked because the lock is
+ * not available. Note that this function does not sleep. It
+ * assumes that the lock will be available very soon.
+ *
+ * This function checks if the running thread has already locked the
+ * location, warns if this occurs and creates a thread dump before
+ * returning.
+ */
+void
+_spinlock_debug(spinlock_t *lck, char *fname, int lineno)
+{
+ _spinlock(lck);
+}
+
+static void
+init_spinlock(spinlock_t *lck)
+{
+ _pthread_mutex_lock(&spinlock_static_lock);
+ if ((lck->fname == NULL) && (spinlock_count < MAX_SPINLOCKS)) {
+ lck->fname = (char *)&extra[spinlock_count];
+ extra[spinlock_count].owner = lck;
+ spinlock_count++;
+ }
+ _pthread_mutex_unlock(&spinlock_static_lock);
+ if (lck->fname == NULL)
+ PANIC("Exceeded max spinlocks");
+}
+
+void
+_thr_spinlock_init(void)
+{
+ int i;
+
+ if (initialized != 0) {
+ _thr_mutex_reinit(&spinlock_static_lock);
+ for (i = 0; i < spinlock_count; i++)
+ _thr_mutex_reinit(&extra[i].lock);
+ } else {
+ if (_pthread_mutex_init(&spinlock_static_lock, &static_mattr))
+ PANIC("Cannot initialize spinlock_static_lock");
+ for (i = 0; i < MAX_SPINLOCKS; i++) {
+ if (_pthread_mutex_init(&extra[i].lock, &static_mattr))
+ PANIC("Cannot initialize spinlock extra");
+ }
+ initialized = 1;
+ }
+}
diff --git a/lib/libkse/thread/thr_stack.c b/lib/libkse/thread/thr_stack.c
new file mode 100644
index 0000000..f634055
--- /dev/null
+++ b/lib/libkse/thread/thr_stack.c
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2001 Daniel Eischen <deischen@freebsd.org>
+ * Copyright (c) 2000-2001 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, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/queue.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+/* Spare thread stack. */
+struct stack {
+ LIST_ENTRY(stack) qe; /* Stack queue linkage. */
+ size_t stacksize; /* Stack size (rounded up). */
+ size_t guardsize; /* Guard size. */
+ void *stackaddr; /* Stack address. */
+};
+
+/*
+ * Default sized (stack and guard) spare stack queue. Stacks are cached
+ * to avoid additional complexity managing mmap()ed stack regions. Spare
+ * stacks are used in LIFO order to increase cache locality.
+ */
+static LIST_HEAD(, stack) dstackq = LIST_HEAD_INITIALIZER(dstackq);
+
+/*
+ * Miscellaneous sized (non-default stack and/or guard) spare stack queue.
+ * Stacks are cached to avoid additional complexity managing mmap()ed
+ * stack regions. This list is unordered, since ordering on both stack
+ * size and guard size would be more trouble than it's worth. Stacks are
+ * allocated from this cache on a first size match basis.
+ */
+static LIST_HEAD(, stack) mstackq = LIST_HEAD_INITIALIZER(mstackq);
+
+/**
+ * Base address of the last stack allocated (including its red zone, if
+ * there is one). Stacks are allocated contiguously, starting beyond the
+ * top of the main stack. When a new stack is created, a red zone is
+ * typically created (actually, the red zone is mapped with PROT_NONE) above
+ * the top of the stack, such that the stack will not be able to grow all
+ * the way to the bottom of the next stack. This isn't fool-proof. It is
+ * possible for a stack to grow by a large amount, such that it grows into
+ * the next stack, and as long as the memory within the red zone is never
+ * accessed, nothing will prevent one thread stack from trouncing all over
+ * the next.
+ *
+ * low memory
+ * . . . . . . . . . . . . . . . . . .
+ * | |
+ * | stack 3 | start of 3rd thread stack
+ * +-----------------------------------+
+ * | |
+ * | Red Zone (guard page) | red zone for 2nd thread
+ * | |
+ * +-----------------------------------+
+ * | stack 2 - PTHREAD_STACK_DEFAULT | top of 2nd thread stack
+ * | |
+ * | |
+ * | |
+ * | |
+ * | stack 2 |
+ * +-----------------------------------+ <-- start of 2nd thread stack
+ * | |
+ * | Red Zone | red zone for 1st thread
+ * | |
+ * +-----------------------------------+
+ * | stack 1 - PTHREAD_STACK_DEFAULT | top of 1st thread stack
+ * | |
+ * | |
+ * | |
+ * | |
+ * | stack 1 |
+ * +-----------------------------------+ <-- start of 1st thread stack
+ * | | (initial value of last_stack)
+ * | Red Zone |
+ * | | red zone for main thread
+ * +-----------------------------------+
+ * | USRSTACK - PTHREAD_STACK_INITIAL | top of main thread stack
+ * | | ^
+ * | | |
+ * | | |
+ * | | | stack growth
+ * | |
+ * +-----------------------------------+ <-- start of main thread stack
+ * (USRSTACK)
+ * high memory
+ *
+ */
+static void *last_stack = NULL;
+
+/*
+ * Round size up to the nearest multiple of
+ * _thr_page_size.
+ */
+static inline size_t
+round_up(size_t size)
+{
+ if (size % _thr_page_size != 0)
+ size = ((size / _thr_page_size) + 1) *
+ _thr_page_size;
+ return size;
+}
+
+int
+_thr_stack_alloc(struct pthread_attr *attr)
+{
+ struct stack *spare_stack;
+ struct kse *curkse;
+ kse_critical_t crit;
+ size_t stacksize;
+ size_t guardsize;
+ char *stackaddr;
+
+ /*
+ * Round up stack size to nearest multiple of _thr_page_size so
+ * that mmap() * will work. If the stack size is not an even
+ * multiple, we end up initializing things such that there is
+ * unused space above the beginning of the stack, so the stack
+ * sits snugly against its guard.
+ */
+ stacksize = round_up(attr->stacksize_attr);
+ guardsize = round_up(attr->guardsize_attr);
+
+ attr->stackaddr_attr = NULL;
+ attr->flags &= ~THR_STACK_USER;
+
+ /*
+ * Use the garbage collector lock for synchronization of the
+ * spare stack lists and allocations from usrstack.
+ */
+ crit = _kse_critical_enter();
+ curkse = _get_curkse();
+ KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock);
+ /*
+ * If the stack and guard sizes are default, try to allocate a stack
+ * from the default-size stack cache:
+ */
+ if ((stacksize == _thr_stack_default) &&
+ (guardsize == _thr_guard_default)) {
+ if ((spare_stack = LIST_FIRST(&dstackq)) != NULL) {
+ /* Use the spare stack. */
+ LIST_REMOVE(spare_stack, qe);
+ attr->stackaddr_attr = spare_stack->stackaddr;
+ }
+ }
+ /*
+ * The user specified a non-default stack and/or guard size, so try to
+ * allocate a stack from the non-default size stack cache, using the
+ * rounded up stack size (stack_size) in the search:
+ */
+ else {
+ LIST_FOREACH(spare_stack, &mstackq, qe) {
+ if (spare_stack->stacksize == stacksize &&
+ spare_stack->guardsize == guardsize) {
+ LIST_REMOVE(spare_stack, qe);
+ attr->stackaddr_attr = spare_stack->stackaddr;
+ break;
+ }
+ }
+ }
+ if (attr->stackaddr_attr != NULL) {
+ /* A cached stack was found. Release the lock. */
+ KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
+ _kse_critical_leave(crit);
+ }
+ else {
+ /* Allocate a stack from usrstack. */
+ if (last_stack == NULL)
+ last_stack = _usrstack - _thr_stack_initial -
+ _thr_guard_default;
+
+ /* Allocate a new stack. */
+ stackaddr = last_stack - stacksize - guardsize;
+
+ /*
+ * Even if stack allocation fails, we don't want to try to
+ * use this location again, so unconditionally decrement
+ * last_stack. Under normal operating conditions, the most
+ * likely reason for an mmap() error is a stack overflow of
+ * the adjacent thread stack.
+ */
+ last_stack -= (stacksize + guardsize);
+
+ /* Release the lock before mmap'ing it. */
+ KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
+ _kse_critical_leave(crit);
+
+ /* Map the stack and guard page together, and split guard
+ page from allocated space: */
+ if ((stackaddr = mmap(stackaddr, stacksize+guardsize,
+ PROT_READ | PROT_WRITE, MAP_STACK,
+ -1, 0)) != MAP_FAILED &&
+ (guardsize == 0 ||
+ mprotect(stackaddr, guardsize, PROT_NONE) == 0)) {
+ stackaddr += guardsize;
+ } else {
+ if (stackaddr != MAP_FAILED)
+ munmap(stackaddr, stacksize + guardsize);
+ stackaddr = NULL;
+ }
+ attr->stackaddr_attr = stackaddr;
+ }
+ if (attr->stackaddr_attr != NULL)
+ return (0);
+ else
+ return (-1);
+}
+
+/* This function must be called with _thread_list_lock held. */
+void
+_thr_stack_free(struct pthread_attr *attr)
+{
+ struct stack *spare_stack;
+
+ if ((attr != NULL) && ((attr->flags & THR_STACK_USER) == 0)
+ && (attr->stackaddr_attr != NULL)) {
+ spare_stack = (attr->stackaddr_attr + attr->stacksize_attr
+ - sizeof(struct stack));
+ spare_stack->stacksize = round_up(attr->stacksize_attr);
+ spare_stack->guardsize = round_up(attr->guardsize_attr);
+ spare_stack->stackaddr = attr->stackaddr_attr;
+
+ if (spare_stack->stacksize == _thr_stack_default &&
+ spare_stack->guardsize == _thr_guard_default) {
+ /* Default stack/guard size. */
+ LIST_INSERT_HEAD(&dstackq, spare_stack, qe);
+ } else {
+ /* Non-default stack/guard size. */
+ LIST_INSERT_HEAD(&mstackq, spare_stack, qe);
+ }
+ attr->stackaddr_attr = NULL;
+ }
+}
diff --git a/lib/libkse/thread/thr_suspend_np.c b/lib/libkse/thread/thr_suspend_np.c
new file mode 100644
index 0000000..16c129c
--- /dev/null
+++ b/lib/libkse/thread/thr_suspend_np.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+static void suspend_common(struct pthread *thread);
+
+LT10_COMPAT_PRIVATE(_pthread_suspend_np);
+LT10_COMPAT_DEFAULT(pthread_suspend_np);
+LT10_COMPAT_PRIVATE(_pthread_suspend_all_np);
+LT10_COMPAT_DEFAULT(pthread_suspend_all_np);
+
+__weak_reference(_pthread_suspend_np, pthread_suspend_np);
+__weak_reference(_pthread_suspend_all_np, pthread_suspend_all_np);
+
+/* Suspend a thread: */
+int
+_pthread_suspend_np(pthread_t thread)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ /* Suspending the current thread doesn't make sense. */
+ if (thread == _get_curthread())
+ ret = EDEADLK;
+
+ /* Add a reference to the thread: */
+ else if ((ret = _thr_ref_add(curthread, thread, /*include dead*/0))
+ == 0) {
+ /* Lock the threads scheduling queue: */
+ THR_SCHED_LOCK(curthread, thread);
+ suspend_common(thread);
+ /* Unlock the threads scheduling queue: */
+ THR_SCHED_UNLOCK(curthread, thread);
+
+ /* Don't forget to remove the reference: */
+ _thr_ref_delete(curthread, thread);
+ }
+ return (ret);
+}
+
+void
+_pthread_suspend_all_np(void)
+{
+ struct pthread *curthread = _get_curthread();
+ struct pthread *thread;
+ kse_critical_t crit;
+
+ /* Take the thread list lock: */
+ crit = _kse_critical_enter();
+ KSE_LOCK_ACQUIRE(curthread->kse, &_thread_list_lock);
+
+ TAILQ_FOREACH(thread, &_thread_list, tle) {
+ if (thread != curthread) {
+ THR_SCHED_LOCK(curthread, thread);
+ suspend_common(thread);
+ THR_SCHED_UNLOCK(curthread, thread);
+ }
+ }
+
+ /* Release the thread list lock: */
+ KSE_LOCK_RELEASE(curthread->kse, &_thread_list_lock);
+ _kse_critical_leave(crit);
+}
+
+void
+suspend_common(struct pthread *thread)
+{
+ if ((thread->state != PS_DEAD) &&
+ (thread->state != PS_DEADLOCK) &&
+ ((thread->flags & THR_FLAGS_EXITING) == 0)) {
+ thread->flags |= THR_FLAGS_SUSPENDED;
+ if ((thread->flags & THR_FLAGS_IN_RUNQ) != 0) {
+ THR_RUNQ_REMOVE(thread);
+ THR_SET_STATE(thread, PS_SUSPENDED);
+ }
+#ifdef NOT_YET
+ if ((thread->attr.flags & PTHREAD_SCOPE_SYSTEM) != 0)
+ /* ??? */
+#endif
+ }
+}
diff --git a/lib/libkse/thread/thr_switch_np.c b/lib/libkse/thread/thr_switch_np.c
new file mode 100644
index 0000000..247b879
--- /dev/null
+++ b/lib/libkse/thread/thr_switch_np.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include <pthread_np.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_switch_add_np);
+LT10_COMPAT_DEFAULT(pthread_switch_add_np);
+LT10_COMPAT_PRIVATE(_pthread_switch_delete_np);
+LT10_COMPAT_DEFAULT(pthread_switch_delete_np);
+
+__weak_reference(_pthread_switch_add_np, pthread_switch_add_np);
+__weak_reference(_pthread_switch_delete_np, pthread_switch_delete_np);
+
+int
+_pthread_switch_add_np(pthread_switch_routine_t routine)
+{
+ return (ENOTSUP);
+}
+
+int
+_pthread_switch_delete_np(pthread_switch_routine_t routine)
+{
+ return (ENOTSUP);
+}
diff --git a/lib/libkse/thread/thr_symbols.c b/lib/libkse/thread/thr_symbols.c
new file mode 100644
index 0000000..2b9639b
--- /dev/null
+++ b/lib/libkse/thread/thr_symbols.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2004 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <stddef.h>
+#include <pthread.h>
+#include <rtld.h>
+
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_thread_off_tcb);
+LT10_COMPAT_PRIVATE(_thread_off_tmbx);
+LT10_COMPAT_PRIVATE(_thread_off_next);
+LT10_COMPAT_PRIVATE(_thread_off_attr_flags);
+LT10_COMPAT_PRIVATE(_thread_off_kse);
+LT10_COMPAT_PRIVATE(_thread_off_kse_locklevel);
+LT10_COMPAT_PRIVATE(_thread_off_thr_locklevel);
+LT10_COMPAT_PRIVATE(_thread_off_linkmap);
+LT10_COMPAT_PRIVATE(_thread_off_tlsindex);
+LT10_COMPAT_PRIVATE(_thread_size_key);
+LT10_COMPAT_PRIVATE(_thread_off_key_allocated);
+LT10_COMPAT_PRIVATE(_thread_off_key_destructor);
+LT10_COMPAT_PRIVATE(_thread_max_keys);
+LT10_COMPAT_PRIVATE(_thread_off_dtv);
+LT10_COMPAT_PRIVATE(_thread_off_state);
+LT10_COMPAT_PRIVATE(_thread_state_running);
+LT10_COMPAT_PRIVATE(_thread_state_zoombie);
+
+/* A collection of symbols needed by debugger */
+
+/* int _libkse_debug */
+int _thread_off_tcb = offsetof(struct pthread, tcb);
+int _thread_off_tmbx = offsetof(struct tcb, tcb_tmbx);
+int _thread_off_next = offsetof(struct pthread, tle.tqe_next);
+int _thread_off_attr_flags = offsetof(struct pthread, attr.flags);
+int _thread_off_kse = offsetof(struct pthread, kse);
+int _thread_off_kse_locklevel = offsetof(struct kse, k_locklevel);
+int _thread_off_thr_locklevel = offsetof(struct pthread, locklevel);
+int _thread_off_linkmap = offsetof(Obj_Entry, linkmap);
+int _thread_off_tlsindex = offsetof(Obj_Entry, tlsindex);
+int _thread_size_key = sizeof(struct pthread_key);
+int _thread_off_key_allocated = offsetof(struct pthread_key, allocated);
+int _thread_off_key_destructor = offsetof(struct pthread_key, destructor);
+int _thread_max_keys = PTHREAD_KEYS_MAX;
+int _thread_off_dtv = DTV_OFFSET;
+int _thread_off_state = offsetof(struct pthread, state);
+int _thread_state_running = PS_RUNNING;
+int _thread_state_zoombie = PS_DEAD;
+int _thread_off_sigmask = offsetof(struct pthread, sigmask);
+int _thread_off_sigpend = offsetof(struct pthread, sigpend);
diff --git a/lib/libkse/thread/thr_system.c b/lib/libkse/thread/thr_system.c
new file mode 100644
index 0000000..5e4fe1c
--- /dev/null
+++ b/lib/libkse/thread/thr_system.c
@@ -0,0 +1,54 @@
+/*
+ * 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$
+ */
+
+#include <stdlib.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+extern int __system(const char *);
+
+LT10_COMPAT_PRIVATE(_system);
+LT10_COMPAT_DEFAULT(system);
+
+__weak_reference(_system, system);
+
+int
+_system(const char *string)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ _thr_cancel_enter(curthread);
+ ret = __system(string);
+ _thr_cancel_leave(curthread, 1);
+
+ return ret;
+}
diff --git a/lib/libkse/thread/thr_tcdrain.c b/lib/libkse/thread/thr_tcdrain.c
new file mode 100644
index 0000000..e231d52
--- /dev/null
+++ b/lib/libkse/thread/thr_tcdrain.c
@@ -0,0 +1,54 @@
+/*
+ * 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$
+ */
+
+#include <termios.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+extern int __tcdrain(int);
+
+LT10_COMPAT_PRIVATE(_tcdrain);
+LT10_COMPAT_DEFAULT(tcdrain);
+
+__weak_reference(_tcdrain, tcdrain);
+
+int
+_tcdrain(int fd)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ _thr_cancel_enter(curthread);
+ ret = __tcdrain(fd);
+ _thr_cancel_leave(curthread, 1);
+
+ return (ret);
+}
diff --git a/lib/libkse/thread/thr_vfork.c b/lib/libkse/thread/thr_vfork.c
new file mode 100644
index 0000000..428c129
--- /dev/null
+++ b/lib/libkse/thread/thr_vfork.c
@@ -0,0 +1,17 @@
+/*
+ * $FreeBSD$
+ */
+#include <unistd.h>
+
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_vfork);
+LT10_COMPAT_DEFAULT(vfork);
+
+__weak_reference(_vfork, vfork);
+
+int
+_vfork(void)
+{
+ return (fork());
+}
diff --git a/lib/libkse/thread/thr_wait.c b/lib/libkse/thread/thr_wait.c
new file mode 100644
index 0000000..8f61a0c
--- /dev/null
+++ b/lib/libkse/thread/thr_wait.c
@@ -0,0 +1,53 @@
+/*
+ * 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$
+ */
+
+#include <pthread.h>
+#include "thr_private.h"
+
+extern int __wait(int *);
+
+LT10_COMPAT_PRIVATE(_wait);
+LT10_COMPAT_DEFAULT(wait);
+
+__weak_reference(_wait, wait);
+
+pid_t
+_wait(int *istat)
+{
+ struct pthread *curthread = _get_curthread();
+ pid_t ret;
+
+ _thr_cancel_enter(curthread);
+ ret = __wait(istat);
+ _thr_cancel_leave(curthread, 1);
+
+ return ret;
+}
diff --git a/lib/libkse/thread/thr_wait4.c b/lib/libkse/thread/thr_wait4.c
new file mode 100644
index 0000000..fae0fed
--- /dev/null
+++ b/lib/libkse/thread/thr_wait4.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 "namespace.h"
+#include <errno.h>
+#include <sys/wait.h>
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__wait4);
+LT10_COMPAT_DEFAULT(wait4);
+
+__weak_reference(__wait4, wait4);
+
+pid_t
+__wait4(pid_t pid, int *istat, int options, struct rusage *rusage)
+{
+ struct pthread *curthread = _get_curthread();
+ pid_t ret;
+
+ _thr_cancel_enter(curthread);
+ ret = _wait4(pid, istat, options, rusage);
+ _thr_cancel_leave(curthread, 1);
+
+ return ret;
+}
diff --git a/lib/libkse/thread/thr_waitpid.c b/lib/libkse/thread/thr_waitpid.c
new file mode 100644
index 0000000..1244c12
--- /dev/null
+++ b/lib/libkse/thread/thr_waitpid.c
@@ -0,0 +1,55 @@
+/*
+ * 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$
+ */
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_waitpid);
+LT10_COMPAT_DEFAULT(waitpid);
+
+extern int __waitpid(pid_t, int *, int);
+
+__weak_reference(_waitpid, waitpid);
+
+pid_t
+_waitpid(pid_t wpid, int *status, int options)
+{
+ struct pthread *curthread = _get_curthread();
+ pid_t ret;
+
+ _thr_cancel_enter(curthread);
+ ret = __waitpid(wpid, status, options);
+ _thr_cancel_leave(curthread, 1);
+
+ return ret;
+}
diff --git a/lib/libkse/thread/thr_write.c b/lib/libkse/thread/thr_write.c
new file mode 100644
index 0000000..00ad990
--- /dev/null
+++ b/lib/libkse/thread/thr_write.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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/fcntl.h>
+#include <sys/uio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__write);
+LT10_COMPAT_DEFAULT(write);
+
+__weak_reference(__write, write);
+
+ssize_t
+__write(int fd, const void *buf, size_t nbytes)
+{
+ struct pthread *curthread = _get_curthread();
+ ssize_t ret;
+
+ _thr_cancel_enter(curthread);
+ ret = __sys_write(fd, buf, nbytes);
+ _thr_cancel_leave(curthread, 1);
+
+ return ret;
+}
diff --git a/lib/libkse/thread/thr_writev.c b/lib/libkse/thread/thr_writev.c
new file mode 100644
index 0000000..a05159f
--- /dev/null
+++ b/lib/libkse/thread/thr_writev.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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/fcntl.h>
+#include <sys/uio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__writev);
+LT10_COMPAT_DEFAULT(writev);
+
+__weak_reference(__writev, writev);
+
+ssize_t
+__writev(int fd, const struct iovec *iov, int iovcnt)
+{
+ struct pthread *curthread = _get_curthread();
+ ssize_t ret;
+
+ _thr_cancel_enter(curthread);
+ ret = __sys_writev(fd, iov, iovcnt);
+ _thr_cancel_leave(curthread, 1);
+
+ return ret;
+}
diff --git a/lib/libkse/thread/thr_yield.c b/lib/libkse/thread/thr_yield.c
new file mode 100644
index 0000000..6ba77f8
--- /dev/null
+++ b/lib/libkse/thread/thr_yield.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_sched_yield);
+LT10_COMPAT_DEFAULT(sched_yield);
+LT10_COMPAT_PRIVATE(_pthread_yield);
+LT10_COMPAT_DEFAULT(pthread_yield);
+
+__weak_reference(_sched_yield, sched_yield);
+__weak_reference(_pthread_yield, pthread_yield);
+
+int
+_sched_yield(void)
+{
+ struct pthread *curthread = _get_curthread();
+
+ if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
+ return (__sys_sched_yield());
+
+ /* Reset the accumulated time slice value for the current thread: */
+ curthread->slice_usec = -1;
+
+ /* Schedule the next thread: */
+ _thr_sched_switch(curthread);
+ /* Always return no error. */
+ return(0);
+}
+
+/* Draft 4 yield */
+void
+_pthread_yield(void)
+{
+ struct pthread *curthread = _get_curthread();
+
+ if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) {
+ __sys_sched_yield();
+ return;
+ }
+
+ /* Reset the accumulated time slice value for the current thread: */
+ curthread->slice_usec = -1;
+
+ /* Schedule the next thread: */
+ _thr_sched_switch(curthread);
+}
diff --git a/lib/libkvm/Makefile b/lib/libkvm/Makefile
new file mode 100644
index 0000000..8008c89
--- /dev/null
+++ b/lib/libkvm/Makefile
@@ -0,0 +1,21 @@
+# @(#)Makefile 8.1 (Berkeley) 6/4/93
+# $FreeBSD$
+
+LIB= kvm
+SHLIBDIR?= /lib
+CFLAGS+=-DLIBC_SCCS -I${.CURDIR}
+SRCS= kvm.c kvm_${MACHINE_ARCH}.c kvm_file.c kvm_getloadavg.c \
+ kvm_getswapinfo.c kvm_proc.c
+.if ${MACHINE_ARCH} == "amd64" || ${MACHINE_ARCH} == "i386"
+SRCS+= kvm_minidump_${MACHINE_ARCH}.c
+.endif
+INCS= kvm.h
+
+MAN= kvm.3 kvm_geterr.3 kvm_getfiles.3 kvm_getloadavg.3 kvm_getprocs.3 \
+ kvm_getswapinfo.3 kvm_nlist.3 kvm_open.3 kvm_read.3
+
+MLINKS+=kvm_getprocs.3 kvm_getargv.3 kvm_getprocs.3 kvm_getenvv.3
+MLINKS+=kvm_open.3 kvm_close.3 kvm_open.3 kvm_openfiles.3
+MLINKS+=kvm_read.3 kvm_write.3
+
+.include <bsd.lib.mk>
diff --git a/lib/libkvm/kvm.3 b/lib/libkvm/kvm.3
new file mode 100644
index 0000000..1d3c5eb
--- /dev/null
+++ b/lib/libkvm/kvm.3
@@ -0,0 +1,120 @@
+.\" Copyright (c) 1992, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software 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.
+.\" 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.
+.\"
+.\" @(#)kvm.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd January 29, 2004
+.Dt KVM 3
+.Os
+.Sh NAME
+.Nm kvm
+.Nd kernel memory interface
+.Sh LIBRARY
+.Lb libkvm
+.Sh DESCRIPTION
+The
+.Nm
+library provides a uniform interface for accessing kernel virtual memory
+images, including live systems and crash dumps.
+Access to live systems is via
+.Xr mem 4
+and
+.Xr kmem 4
+while crash dumps can be examined via the core file generated by
+.Xr savecore 8 .
+The interface behaves identically in both cases.
+Memory can be read and written, kernel symbol addresses can be
+looked up efficiently, and information about user processes can
+be gathered.
+.Pp
+The
+.Fn kvm_open
+function is first called to obtain a descriptor for all subsequent calls.
+.Sh COMPATIBILITY
+The kvm interface was first introduced in SunOS.
+A considerable
+number of programs have been developed that use this interface,
+making backward compatibility highly desirable.
+In most respects, the Sun kvm interface is consistent and clean.
+Accordingly, the generic portion of the interface (i.e.,
+.Fn kvm_open ,
+.Fn kvm_close ,
+.Fn kvm_read ,
+.Fn kvm_write ,
+and
+.Fn kvm_nlist )
+has been incorporated into the
+.Bx
+interface.
+Indeed, many kvm
+applications (i.e., debuggers and statistical monitors) use only
+this subset of the interface.
+.Pp
+The process interface was not kept.
+This is not a portability
+issue since any code that manipulates processes is inherently
+machine dependent.
+.Pp
+Finally, the Sun kvm error reporting semantics are poorly defined.
+The library can be configured either to print errors to
+.Dv stderr
+automatically,
+or to print no error messages at all.
+In the latter case, the nature of the error cannot be determined.
+To overcome this, the
+.Bx
+interface includes a
+routine,
+.Xr kvm_geterr 3 ,
+to return (not print out) the error message
+corresponding to the most recent error condition on the
+given descriptor.
+.Sh SEE ALSO
+.Xr kvm_close 3 ,
+.Xr kvm_getargv 3 ,
+.Xr kvm_getenvv 3 ,
+.Xr kvm_geterr 3 ,
+.Xr kvm_getfiles 3 ,
+.Xr kvm_getloadavg 3 ,
+.Xr kvm_getprocs 3 ,
+.Xr kvm_getswapinfo 3 ,
+.Xr kvm_nlist 3 ,
+.Xr kvm_open 3 ,
+.Xr kvm_openfiles 3 ,
+.Xr kvm_read 3 ,
+.Xr kvm_write 3 ,
+.Xr kmem 4 ,
+.Xr mem 4
diff --git a/lib/libkvm/kvm.c b/lib/libkvm/kvm.c
new file mode 100644
index 0000000..1bea13c
--- /dev/null
+++ b/lib/libkvm/kvm.c
@@ -0,0 +1,442 @@
+/*-
+ * Copyright (c) 1989, 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software 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.
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)kvm.c 8.2 (Berkeley) 2/13/94";
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/param.h>
+#include <sys/user.h>
+#include <sys/proc.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/linker.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+
+#include <machine/vmparam.h>
+
+#include <ctype.h>
+#include <fcntl.h>
+#include <kvm.h>
+#include <limits.h>
+#include <nlist.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "kvm_private.h"
+
+/* from src/lib/libc/gen/nlist.c */
+int __fdnlist(int, struct nlist *);
+
+char *
+kvm_geterr(kd)
+ kvm_t *kd;
+{
+ return (kd->errbuf);
+}
+
+#include <stdarg.h>
+
+/*
+ * Report an error using printf style arguments. "program" is kd->program
+ * on hard errors, and 0 on soft errors, so that under sun error emulation,
+ * only hard errors are printed out (otherwise, programs like gdb will
+ * generate tons of error messages when trying to access bogus pointers).
+ */
+void
+_kvm_err(kvm_t *kd, const char *program, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ if (program != NULL) {
+ (void)fprintf(stderr, "%s: ", program);
+ (void)vfprintf(stderr, fmt, ap);
+ (void)fputc('\n', stderr);
+ } else
+ (void)vsnprintf(kd->errbuf,
+ sizeof(kd->errbuf), (char *)fmt, ap);
+
+ va_end(ap);
+}
+
+void
+_kvm_syserr(kvm_t *kd, const char *program, const char *fmt, ...)
+{
+ va_list ap;
+ int n;
+
+ va_start(ap, fmt);
+ if (program != NULL) {
+ (void)fprintf(stderr, "%s: ", program);
+ (void)vfprintf(stderr, fmt, ap);
+ (void)fprintf(stderr, ": %s\n", strerror(errno));
+ } else {
+ char *cp = kd->errbuf;
+
+ (void)vsnprintf(cp, sizeof(kd->errbuf), (char *)fmt, ap);
+ n = strlen(cp);
+ (void)snprintf(&cp[n], sizeof(kd->errbuf) - n, ": %s",
+ strerror(errno));
+ }
+ va_end(ap);
+}
+
+void *
+_kvm_malloc(kd, n)
+ kvm_t *kd;
+ size_t n;
+{
+ void *p;
+
+ if ((p = calloc(n, sizeof(char))) == NULL)
+ _kvm_err(kd, kd->program, "can't allocate %u bytes: %s",
+ n, strerror(errno));
+ return (p);
+}
+
+static kvm_t *
+_kvm_open(kd, uf, mf, flag, errout)
+ kvm_t *kd;
+ const char *uf;
+ const char *mf;
+ int flag;
+ char *errout;
+{
+ struct stat st;
+
+ kd->vmfd = -1;
+ kd->pmfd = -1;
+ kd->nlfd = -1;
+ kd->vmst = 0;
+ kd->procbase = 0;
+ kd->argspc = 0;
+ kd->argv = 0;
+
+ if (uf == 0)
+ uf = getbootfile();
+ else if (strlen(uf) >= MAXPATHLEN) {
+ _kvm_err(kd, kd->program, "exec file name too long");
+ goto failed;
+ }
+ if (flag & ~O_RDWR) {
+ _kvm_err(kd, kd->program, "bad flags arg");
+ goto failed;
+ }
+ if (mf == 0)
+ mf = _PATH_MEM;
+
+ if ((kd->pmfd = open(mf, flag, 0)) < 0) {
+ _kvm_syserr(kd, kd->program, "%s", mf);
+ goto failed;
+ }
+ if (fstat(kd->pmfd, &st) < 0) {
+ _kvm_syserr(kd, kd->program, "%s", mf);
+ goto failed;
+ }
+ if (S_ISREG(st.st_mode) && st.st_size <= 0) {
+ errno = EINVAL;
+ _kvm_syserr(kd, kd->program, "empty file");
+ goto failed;
+ }
+ if (fcntl(kd->pmfd, F_SETFD, FD_CLOEXEC) < 0) {
+ _kvm_syserr(kd, kd->program, "%s", mf);
+ goto failed;
+ }
+ if (S_ISCHR(st.st_mode)) {
+ /*
+ * If this is a character special device, then check that
+ * it's /dev/mem. If so, open kmem too. (Maybe we should
+ * make it work for either /dev/mem or /dev/kmem -- in either
+ * case you're working with a live kernel.)
+ */
+ if (strcmp(mf, _PATH_DEVNULL) == 0) {
+ kd->vmfd = open(_PATH_DEVNULL, O_RDONLY);
+ return (kd);
+ } else if (strcmp(mf, _PATH_MEM) == 0) {
+ if ((kd->vmfd = open(_PATH_KMEM, flag)) < 0) {
+ _kvm_syserr(kd, kd->program, "%s", _PATH_KMEM);
+ goto failed;
+ }
+ if (fcntl(kd->vmfd, F_SETFD, FD_CLOEXEC) < 0) {
+ _kvm_syserr(kd, kd->program, "%s", _PATH_KMEM);
+ goto failed;
+ }
+ return (kd);
+ }
+ }
+ /*
+ * This is a crash dump.
+ * Initialize the virtual address translation machinery,
+ * but first setup the namelist fd.
+ */
+ if ((kd->nlfd = open(uf, O_RDONLY, 0)) < 0) {
+ _kvm_syserr(kd, kd->program, "%s", uf);
+ goto failed;
+ }
+ if (fcntl(kd->nlfd, F_SETFD, FD_CLOEXEC) < 0) {
+ _kvm_syserr(kd, kd->program, "%s", uf);
+ goto failed;
+ }
+ if (_kvm_initvtop(kd) < 0)
+ goto failed;
+ return (kd);
+failed:
+ /*
+ * Copy out the error if doing sane error semantics.
+ */
+ if (errout != 0)
+ strlcpy(errout, kd->errbuf, _POSIX2_LINE_MAX);
+ (void)kvm_close(kd);
+ return (0);
+}
+
+kvm_t *
+kvm_openfiles(uf, mf, sf, flag, errout)
+ const char *uf;
+ const char *mf;
+ const char *sf __unused;
+ int flag;
+ char *errout;
+{
+ kvm_t *kd;
+
+ if ((kd = malloc(sizeof(*kd))) == NULL) {
+ (void)strlcpy(errout, strerror(errno), _POSIX2_LINE_MAX);
+ return (0);
+ }
+ memset(kd, 0, sizeof(*kd));
+ kd->program = 0;
+ return (_kvm_open(kd, uf, mf, flag, errout));
+}
+
+kvm_t *
+kvm_open(uf, mf, sf, flag, errstr)
+ const char *uf;
+ const char *mf;
+ const char *sf __unused;
+ int flag;
+ const char *errstr;
+{
+ kvm_t *kd;
+
+ if ((kd = malloc(sizeof(*kd))) == NULL) {
+ if (errstr != NULL)
+ (void)fprintf(stderr, "%s: %s\n",
+ errstr, strerror(errno));
+ return (0);
+ }
+ memset(kd, 0, sizeof(*kd));
+ kd->program = errstr;
+ return (_kvm_open(kd, uf, mf, flag, NULL));
+}
+
+int
+kvm_close(kd)
+ kvm_t *kd;
+{
+ int error = 0;
+
+ if (kd->pmfd >= 0)
+ error |= close(kd->pmfd);
+ if (kd->vmfd >= 0)
+ error |= close(kd->vmfd);
+ if (kd->nlfd >= 0)
+ error |= close(kd->nlfd);
+ if (kd->vmst)
+ _kvm_freevtop(kd);
+ if (kd->procbase != 0)
+ free((void *)kd->procbase);
+ if (kd->argv != 0)
+ free((void *)kd->argv);
+ free((void *)kd);
+
+ return (0);
+}
+
+int
+kvm_nlist(kd, nl)
+ kvm_t *kd;
+ struct nlist *nl;
+{
+ struct nlist *p;
+ int nvalid;
+ struct kld_sym_lookup lookup;
+
+ /*
+ * If we can't use the kld symbol lookup, revert to the
+ * slow library call.
+ */
+ if (!ISALIVE(kd))
+ return (__fdnlist(kd->nlfd, nl));
+
+ /*
+ * We can use the kld lookup syscall. Go through each nlist entry
+ * and look it up with a kldsym(2) syscall.
+ */
+ nvalid = 0;
+ for (p = nl; p->n_name && p->n_name[0]; ++p) {
+ lookup.version = sizeof(lookup);
+ lookup.symname = p->n_name;
+ lookup.symvalue = 0;
+ lookup.symsize = 0;
+
+ if (lookup.symname[0] == '_')
+ lookup.symname++;
+
+ if (kldsym(0, KLDSYM_LOOKUP, &lookup) != -1) {
+ p->n_type = N_TEXT;
+ p->n_other = 0;
+ p->n_desc = 0;
+ p->n_value = lookup.symvalue;
+ ++nvalid;
+ /* lookup.symsize */
+ }
+ }
+ /*
+ * Return the number of entries that weren't found.
+ */
+ return ((p - nl) - nvalid);
+}
+
+ssize_t
+kvm_read(kd, kva, buf, len)
+ kvm_t *kd;
+ u_long kva;
+ void *buf;
+ size_t len;
+{
+ int cc;
+ char *cp;
+
+ if (ISALIVE(kd)) {
+ /*
+ * We're using /dev/kmem. Just read straight from the
+ * device and let the active kernel do the address translation.
+ */
+ errno = 0;
+ if (lseek(kd->vmfd, (off_t)kva, 0) == -1 && errno != 0) {
+ _kvm_err(kd, 0, "invalid address (%x)", kva);
+ return (-1);
+ }
+ cc = read(kd->vmfd, buf, len);
+ if (cc < 0) {
+ _kvm_syserr(kd, 0, "kvm_read");
+ return (-1);
+ } else if (cc < len)
+ _kvm_err(kd, kd->program, "short read");
+ return (cc);
+ } else {
+ cp = buf;
+ while (len > 0) {
+ off_t pa;
+
+ cc = _kvm_kvatop(kd, kva, &pa);
+ if (cc == 0)
+ return (-1);
+ if (cc > len)
+ cc = len;
+ errno = 0;
+ if (lseek(kd->pmfd, pa, 0) == -1 && errno != 0) {
+ _kvm_syserr(kd, 0, _PATH_MEM);
+ break;
+ }
+ cc = read(kd->pmfd, cp, cc);
+ if (cc < 0) {
+ _kvm_syserr(kd, kd->program, "kvm_read");
+ break;
+ }
+ /*
+ * If kvm_kvatop returns a bogus value or our core
+ * file is truncated, we might wind up seeking beyond
+ * the end of the core file in which case the read will
+ * return 0 (EOF).
+ */
+ if (cc == 0)
+ break;
+ cp += cc;
+ kva += cc;
+ len -= cc;
+ }
+ return (cp - (char *)buf);
+ }
+ /* NOTREACHED */
+}
+
+ssize_t
+kvm_write(kd, kva, buf, len)
+ kvm_t *kd;
+ u_long kva;
+ const void *buf;
+ size_t len;
+{
+ int cc;
+
+ if (ISALIVE(kd)) {
+ /*
+ * Just like kvm_read, only we write.
+ */
+ errno = 0;
+ if (lseek(kd->vmfd, (off_t)kva, 0) == -1 && errno != 0) {
+ _kvm_err(kd, 0, "invalid address (%x)", kva);
+ return (-1);
+ }
+ cc = write(kd->vmfd, buf, len);
+ if (cc < 0) {
+ _kvm_syserr(kd, 0, "kvm_write");
+ return (-1);
+ } else if (cc < len)
+ _kvm_err(kd, kd->program, "short write");
+ return (cc);
+ } else {
+ _kvm_err(kd, kd->program,
+ "kvm_write not implemented for dead kernels");
+ return (-1);
+ }
+ /* NOTREACHED */
+}
diff --git a/lib/libkvm/kvm.h b/lib/libkvm/kvm.h
new file mode 100644
index 0000000..0886c77
--- /dev/null
+++ b/lib/libkvm/kvm.h
@@ -0,0 +1,95 @@
+/*-
+ * 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. 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.
+ *
+ * @(#)kvm.h 8.1 (Berkeley) 6/2/93
+ * $FreeBSD$
+ */
+
+#ifndef _KVM_H_
+#define _KVM_H_
+
+#include <sys/cdefs.h>
+#include <sys/_types.h>
+#include <nlist.h>
+
+/* Default version symbol. */
+#define VRS_SYM "_version"
+#define VRS_KEY "VERSION"
+
+#ifndef _SIZE_T_DECLARED
+typedef __size_t size_t;
+#define _SIZE_T_DECLARED
+#endif
+
+#ifndef _SSIZE_T_DECLARED
+typedef __ssize_t ssize_t;
+#define _SSIZE_T_DECLARED
+#endif
+
+typedef struct __kvm kvm_t;
+
+struct kinfo_proc;
+struct proc;
+
+struct kvm_swap {
+ char ksw_devname[32];
+ int ksw_used;
+ int ksw_total;
+ int ksw_flags;
+ int ksw_reserved1;
+ int ksw_reserved2;
+};
+
+#define SWIF_DEV_PREFIX 0x0002
+
+__BEGIN_DECLS
+int kvm_close(kvm_t *);
+char **kvm_getargv(kvm_t *, const struct kinfo_proc *, int);
+char **kvm_getenvv(kvm_t *, const struct kinfo_proc *, int);
+char *kvm_geterr(kvm_t *);
+char *kvm_getfiles(kvm_t *, int, int, int *);
+int kvm_getloadavg(kvm_t *, double [], int);
+struct kinfo_proc *
+ kvm_getprocs(kvm_t *, int, int, int *);
+int kvm_getswapinfo(kvm_t *, struct kvm_swap *, int, int);
+int kvm_nlist(kvm_t *, struct nlist *);
+kvm_t *kvm_open
+ (const char *, const char *, const char *, int, const char *);
+kvm_t *kvm_openfiles
+ (const char *, const char *, const char *, int, char *);
+ssize_t kvm_read(kvm_t *, unsigned long, void *, size_t);
+ssize_t kvm_uread
+ (kvm_t *, struct kinfo_proc *, unsigned long, char *, size_t);
+ssize_t kvm_write(kvm_t *, unsigned long, const void *, size_t);
+__END_DECLS
+
+#endif /* !_KVM_H_ */
diff --git a/lib/libkvm/kvm_alpha.c b/lib/libkvm/kvm_alpha.c
new file mode 100644
index 0000000..011c397
--- /dev/null
+++ b/lib/libkvm/kvm_alpha.c
@@ -0,0 +1,213 @@
+/* $NetBSD: kvm_alpha.c,v 1.7.2.1 1997/11/02 20:34:26 mellon Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/user.h>
+#include <sys/proc.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#include <nlist.h>
+#include <kvm.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+
+#include <limits.h>
+#include <stdlib.h>
+#include <machine/pmap.h>
+#include "kvm_private.h"
+
+static off_t _kvm_pa2off(kvm_t *kd, u_long pa);
+
+struct vmstate {
+ u_int64_t lev1map_pa; /* PA of Lev1map */
+ u_int64_t page_size; /* Page size */
+ u_int64_t nmemsegs; /* Number of RAM segm */
+};
+
+void
+_kvm_freevtop(kd)
+ kvm_t *kd;
+{
+
+ /* Not actually used for anything right now, but safe. */
+ if (kd->vmst != 0)
+ free(kd->vmst);
+}
+
+int
+_kvm_initvtop(kd)
+ kvm_t *kd;
+{
+ struct vmstate *vm;
+ struct nlist nlist[2];
+ u_long pa;
+
+ vm = (struct vmstate *)_kvm_malloc(kd, sizeof(*vm));
+ if (vm == 0) {
+ _kvm_err(kd, kd->program, "cannot allocate vm");
+ return (-1);
+ }
+ kd->vmst = vm;
+ vm->page_size = ALPHA_PGBYTES;
+
+ nlist[0].n_name = "_Lev1map";
+ nlist[1].n_name = 0;
+
+ if (kvm_nlist(kd, nlist) != 0) {
+ _kvm_err(kd, kd->program, "bad namelist");
+ return (-1);
+ }
+
+ if(!ISALIVE(kd)) {
+ if (kvm_read(kd, (nlist[0].n_value), &pa, sizeof(pa)) != sizeof(pa)) {
+ _kvm_err(kd, kd->program, "cannot read Lev1map");
+ return (-1);
+ }
+ } else
+ if (kvm_read(kd, (nlist[0].n_value), &pa, sizeof(pa)) != sizeof(pa)) {
+ _kvm_err(kd, kd->program, "cannot read Lev1map");
+ return (-1);
+ }
+ vm->lev1map_pa = pa;
+ return (0);
+
+}
+
+int
+_kvm_kvatop(kd, va, pa)
+ kvm_t *kd;
+ u_long va;
+ off_t *pa;
+{
+ u_int64_t lev1map_pa; /* PA of Lev1map */
+ u_int64_t page_size;
+ int rv, page_off;
+ alpha_pt_entry_t pte;
+ off_t pteoff;
+ struct vmstate *vm;
+ vm = kd->vmst ;
+
+
+ if (ISALIVE(kd)) {
+ _kvm_err(kd, 0, "vatop called in live kernel!");
+ return(0);
+ }
+ lev1map_pa = vm->lev1map_pa;
+ page_size = vm->page_size;
+
+ page_off = va & (page_size - 1);
+ if (va >= ALPHA_K0SEG_BASE && va <= ALPHA_K0SEG_END) {
+ /*
+ * Direct-mapped address: just convert it.
+ */
+
+ *pa = ALPHA_K0SEG_TO_PHYS(va);
+ rv = page_size - page_off;
+ } else if (va >= ALPHA_K1SEG_BASE && va <= ALPHA_K1SEG_END) {
+ /*
+ * Real kernel virtual address: do the translation.
+ */
+#define PTMASK ((1 << ALPHA_PTSHIFT) - 1)
+#define pmap_lev1_index(va) (((va) >> ALPHA_L1SHIFT) & PTMASK)
+#define pmap_lev2_index(va) (((va) >> ALPHA_L2SHIFT) & PTMASK)
+#define pmap_lev3_index(va) (((va) >> ALPHA_L3SHIFT) & PTMASK)
+
+ /* Find and read the L1 PTE. */
+ pteoff = lev1map_pa +
+ pmap_lev1_index(va) * sizeof(alpha_pt_entry_t);
+ if (lseek(kd->pmfd, _kvm_pa2off(kd, pteoff), 0) == -1 ||
+ read(kd->pmfd, (char *)&pte, sizeof(pte)) != sizeof(pte)) {
+ _kvm_syserr(kd, 0, "could not read L1 PTE");
+ goto lose;
+ }
+
+ /* Find and read the L2 PTE. */
+ if ((pte & ALPHA_PTE_VALID) == 0) {
+ _kvm_err(kd, 0, "invalid translation (invalid L1 PTE)");
+ goto lose;
+ }
+ pteoff = ALPHA_PTE_TO_PFN(pte) * page_size +
+ pmap_lev2_index(va) * sizeof(alpha_pt_entry_t);
+ if (lseek(kd->pmfd, _kvm_pa2off(kd, pteoff), 0) == -1 ||
+ read(kd->pmfd, (char *)&pte, sizeof(pte)) != sizeof(pte)) {
+ _kvm_syserr(kd, 0, "could not read L2 PTE");
+ goto lose;
+ }
+
+ /* Find and read the L3 PTE. */
+ if ((pte & ALPHA_PTE_VALID) == 0) {
+ _kvm_err(kd, 0, "invalid translation (invalid L2 PTE)");
+ goto lose;
+ }
+ pteoff = ALPHA_PTE_TO_PFN(pte) * page_size +
+ pmap_lev3_index(va) * sizeof(alpha_pt_entry_t);
+ if (lseek(kd->pmfd, _kvm_pa2off(kd, pteoff), 0) == -1 ||
+ read(kd->pmfd, (char *)&pte, sizeof(pte)) != sizeof(pte)) {
+ _kvm_syserr(kd, 0, "could not read L3 PTE");
+ goto lose;
+ }
+
+ /* Fill in the PA. */
+ if ((pte & ALPHA_PTE_VALID) == 0) {
+ _kvm_err(kd, 0, "invalid translation (invalid L3 PTE)");
+ goto lose;
+ }
+ *pa = ALPHA_PTE_TO_PFN(pte) * page_size + page_off;
+ rv = page_size - page_off;
+ } else {
+ /*
+ * Bogus address (not in KV space): punt.
+ */
+
+ _kvm_err(kd, 0, "invalid kernel virtual address");
+lose:
+ *pa = -1;
+ rv = 0;
+ }
+
+ return (rv);
+}
+
+/*
+ * Translate a physical address to a file-offset in the crash-dump.
+ */
+off_t
+_kvm_pa2off(kd, pa)
+ kvm_t *kd;
+ u_long pa;
+{
+ return ALPHA_K0SEG_TO_PHYS(pa);
+}
+
diff --git a/lib/libkvm/kvm_amd64.c b/lib/libkvm/kvm_amd64.c
new file mode 100644
index 0000000..af5eb28
--- /dev/null
+++ b/lib/libkvm/kvm_amd64.c
@@ -0,0 +1,352 @@
+/*-
+ * Copyright (c) 1989, 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software 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.
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)kvm_hp300.c 8.1 (Berkeley) 6/4/93";
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * AMD64 machine dependent routines for kvm. Hopefully, the forthcoming
+ * vm code will one day obsolete this module.
+ */
+
+#include <sys/param.h>
+#include <sys/user.h>
+#include <sys/proc.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <nlist.h>
+#include <kvm.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+
+#include <machine/elf.h>
+
+#include <limits.h>
+
+#include "kvm_private.h"
+
+#ifndef btop
+#define btop(x) (amd64_btop(x))
+#define ptob(x) (amd64_ptob(x))
+#endif
+
+/* minidump must be the first item! */
+struct vmstate {
+ int minidump; /* 1 = minidump mode */
+ void *mmapbase;
+ size_t mmapsize;
+ pml4_entry_t *PML4;
+};
+
+/*
+ * Map the ELF headers into the process' address space. We do this in two
+ * steps: first the ELF header itself and using that information the whole
+ * set of headers. (Taken from kvm_ia64.c)
+ */
+static int
+_kvm_maphdrs(kvm_t *kd, size_t sz)
+{
+ struct vmstate *vm = kd->vmst;
+
+ /* munmap() previous mmap(). */
+ if (vm->mmapbase != NULL) {
+ munmap(vm->mmapbase, vm->mmapsize);
+ vm->mmapbase = NULL;
+ }
+
+ vm->mmapsize = sz;
+ vm->mmapbase = mmap(NULL, sz, PROT_READ, MAP_PRIVATE, kd->pmfd, 0);
+ if (vm->mmapbase == MAP_FAILED) {
+ _kvm_err(kd, kd->program, "cannot mmap corefile");
+ return (-1);
+ }
+ return (0);
+}
+
+/*
+ * Translate a physical memory address to a file-offset in the crash-dump.
+ * (Taken from kvm_ia64.c)
+ */
+static size_t
+_kvm_pa2off(kvm_t *kd, uint64_t pa, off_t *ofs)
+{
+ Elf_Ehdr *e = kd->vmst->mmapbase;
+ Elf_Phdr *p = (Elf_Phdr*)((char*)e + e->e_phoff);
+ int n = e->e_phnum;
+
+ while (n && (pa < p->p_paddr || pa >= p->p_paddr + p->p_memsz))
+ p++, n--;
+ if (n == 0)
+ return (0);
+ *ofs = (pa - p->p_paddr) + p->p_offset;
+ return (PAGE_SIZE - ((size_t)pa & PAGE_MASK));
+}
+
+void
+_kvm_freevtop(kvm_t *kd)
+{
+ struct vmstate *vm = kd->vmst;
+
+ if (kd->vmst->minidump)
+ return (_kvm_minidump_freevtop(kd));
+ if (vm->mmapbase != NULL)
+ munmap(vm->mmapbase, vm->mmapsize);
+ if (vm->PML4)
+ free(vm->PML4);
+ free(vm);
+ kd->vmst = NULL;
+}
+
+int
+_kvm_initvtop(kvm_t *kd)
+{
+ struct nlist nlist[2];
+ u_long pa;
+ u_long kernbase;
+ pml4_entry_t *PML4;
+ Elf_Ehdr *ehdr;
+ size_t hdrsz;
+ char minihdr[8];
+
+ if (pread(kd->pmfd, &minihdr, 8, 0) == 8)
+ if (memcmp(&minihdr, "minidump", 8) == 0)
+ return (_kvm_minidump_initvtop(kd));
+
+ kd->vmst = (struct vmstate *)_kvm_malloc(kd, sizeof(*kd->vmst));
+ if (kd->vmst == 0) {
+ _kvm_err(kd, kd->program, "cannot allocate vm");
+ return (-1);
+ }
+ kd->vmst->PML4 = 0;
+
+ if (_kvm_maphdrs(kd, sizeof(Elf_Ehdr)) == -1)
+ return (-1);
+
+ ehdr = kd->vmst->mmapbase;
+ hdrsz = ehdr->e_phoff + ehdr->e_phentsize * ehdr->e_phnum;
+ if (_kvm_maphdrs(kd, hdrsz) == -1)
+ return (-1);
+
+ nlist[0].n_name = "kernbase";
+ nlist[1].n_name = 0;
+
+ if (kvm_nlist(kd, nlist) != 0) {
+ _kvm_err(kd, kd->program, "bad namelist - no kernbase");
+ return (-1);
+ }
+ kernbase = nlist[0].n_value;
+
+ nlist[0].n_name = "KPML4phys";
+ nlist[1].n_name = 0;
+
+ if (kvm_nlist(kd, nlist) != 0) {
+ _kvm_err(kd, kd->program, "bad namelist - no KPML4phys");
+ return (-1);
+ }
+ if (kvm_read(kd, (nlist[0].n_value - kernbase), &pa, sizeof(pa)) !=
+ sizeof(pa)) {
+ _kvm_err(kd, kd->program, "cannot read KPML4phys");
+ return (-1);
+ }
+ PML4 = _kvm_malloc(kd, PAGE_SIZE);
+ if (kvm_read(kd, pa, PML4, PAGE_SIZE) != PAGE_SIZE) {
+ _kvm_err(kd, kd->program, "cannot read KPML4phys");
+ return (-1);
+ }
+ kd->vmst->PML4 = PML4;
+ return (0);
+}
+
+static int
+_kvm_vatop(kvm_t *kd, u_long va, off_t *pa)
+{
+ struct vmstate *vm;
+ u_long offset;
+ u_long pdpe_pa;
+ u_long pde_pa;
+ u_long pte_pa;
+ pml4_entry_t pml4e;
+ pdp_entry_t pdpe;
+ pd_entry_t pde;
+ pt_entry_t pte;
+ u_long pml4eindex;
+ u_long pdpeindex;
+ u_long pdeindex;
+ u_long pteindex;
+ int i;
+ u_long a;
+ off_t ofs;
+ size_t s;
+
+ vm = kd->vmst;
+ offset = va & (PAGE_SIZE - 1);
+
+ /*
+ * If we are initializing (kernel page table descriptor pointer
+ * not yet set) then return pa == va to avoid infinite recursion.
+ */
+ if (vm->PML4 == 0) {
+ s = _kvm_pa2off(kd, va, pa);
+ if (s == 0) {
+ _kvm_err(kd, kd->program,
+ "_kvm_vatop: bootstrap data not in dump");
+ goto invalid;
+ } else
+ return (PAGE_SIZE - offset);
+ }
+
+ pml4eindex = (va >> PML4SHIFT) & (NPML4EPG - 1);
+ pml4e = vm->PML4[pml4eindex];
+ if (((u_long)pml4e & PG_V) == 0) {
+ _kvm_err(kd, kd->program, "_kvm_vatop: pml4e not valid");
+ goto invalid;
+ }
+
+ pdpeindex = (va >> PDPSHIFT) & (NPDPEPG-1);
+ pdpe_pa = ((u_long)pml4e & PG_FRAME) +
+ (pdpeindex * sizeof(pdp_entry_t));
+
+ s = _kvm_pa2off(kd, pdpe_pa, &ofs);
+ if (s < sizeof pdpe) {
+ _kvm_err(kd, kd->program, "_kvm_vatop: pdpe_pa not found");
+ goto invalid;
+ }
+ if (lseek(kd->pmfd, ofs, 0) == -1) {
+ _kvm_syserr(kd, kd->program, "_kvm_vatop: lseek pdpe_pa");
+ goto invalid;
+ }
+ if (read(kd->pmfd, &pdpe, sizeof pdpe) != sizeof pdpe) {
+ _kvm_syserr(kd, kd->program, "_kvm_vatop: read pdpe");
+ goto invalid;
+ }
+ if (((u_long)pdpe & PG_V) == 0) {
+ _kvm_err(kd, kd->program, "_kvm_vatop: pdpe not valid");
+ goto invalid;
+ }
+
+ pdeindex = (va >> PDRSHIFT) & (NPDEPG-1);
+ pde_pa = ((u_long)pdpe & PG_FRAME) + (pdeindex * sizeof(pd_entry_t));
+
+ s = _kvm_pa2off(kd, pde_pa, &ofs);
+ if (s < sizeof pde) {
+ _kvm_syserr(kd, kd->program, "_kvm_vatop: pde_pa not found");
+ goto invalid;
+ }
+ if (lseek(kd->pmfd, ofs, 0) == -1) {
+ _kvm_err(kd, kd->program, "_kvm_vatop: lseek pde_pa");
+ goto invalid;
+ }
+ if (read(kd->pmfd, &pde, sizeof pde) != sizeof pde) {
+ _kvm_syserr(kd, kd->program, "_kvm_vatop: read pde");
+ goto invalid;
+ }
+ if (((u_long)pde & PG_V) == 0) {
+ _kvm_err(kd, kd->program, "_kvm_vatop: pde not valid");
+ goto invalid;
+ }
+
+ if ((u_long)pde & PG_PS) {
+ /*
+ * No final-level page table; ptd describes one 2MB page.
+ */
+#define PAGE2M_MASK (NBPDR - 1)
+#define PG_FRAME2M (~PAGE2M_MASK)
+ a = ((u_long)pde & PG_FRAME2M) + (va & PAGE2M_MASK);
+ s = _kvm_pa2off(kd, a, pa);
+ if (s == 0) {
+ _kvm_err(kd, kd->program,
+ "_kvm_vatop: 2MB page address not in dump");
+ goto invalid;
+ } else
+ return (NBPDR - (va & PAGE2M_MASK));
+ }
+
+ pteindex = (va >> PAGE_SHIFT) & (NPTEPG-1);
+ pte_pa = ((u_long)pde & PG_FRAME) + (pteindex * sizeof(pt_entry_t));
+
+ s = _kvm_pa2off(kd, pte_pa, &ofs);
+ if (s < sizeof pte) {
+ _kvm_err(kd, kd->program, "_kvm_vatop: pte_pa not found");
+ goto invalid;
+ }
+ if (lseek(kd->pmfd, ofs, 0) == -1) {
+ _kvm_syserr(kd, kd->program, "_kvm_vatop: lseek");
+ goto invalid;
+ }
+ if (read(kd->pmfd, &pte, sizeof pte) != sizeof pte) {
+ _kvm_syserr(kd, kd->program, "_kvm_vatop: read");
+ goto invalid;
+ }
+ if (((u_long)pte & PG_V) == 0) {
+ _kvm_err(kd, kd->program, "_kvm_vatop: pte not valid");
+ goto invalid;
+ }
+
+ a = ((u_long)pte & PG_FRAME) + offset;
+ s = _kvm_pa2off(kd, a, pa);
+ if (s == 0) {
+ _kvm_err(kd, kd->program, "_kvm_vatop: address not in dump");
+ goto invalid;
+ } else
+ return (PAGE_SIZE - offset);
+
+invalid:
+ _kvm_err(kd, 0, "invalid address (0x%lx)", va);
+ return (0);
+}
+
+int
+_kvm_kvatop(kvm_t *kd, u_long va, off_t *pa)
+{
+
+ if (kd->vmst->minidump)
+ return (_kvm_minidump_kvatop(kd, va, pa));
+ if (ISALIVE(kd)) {
+ _kvm_err(kd, 0, "kvm_kvatop called in live kernel!");
+ return (0);
+ }
+ return (_kvm_vatop(kd, va, pa));
+}
diff --git a/lib/libkvm/kvm_arm.c b/lib/libkvm/kvm_arm.c
new file mode 100644
index 0000000..0bde0bf
--- /dev/null
+++ b/lib/libkvm/kvm_arm.c
@@ -0,0 +1,247 @@
+/* $NetBSD: kvm_powerpc.c,v 1.4 1998/02/03 06:50:07 mycroft Exp $ */
+
+/*-
+ * Copyright (C) 1996 Wolfgang Solfrank.
+ * Copyright (C) 1996 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.
+ */
+
+/*
+ * ARM machine dependent routines for kvm.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/elf32.h>
+#include <sys/mman.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/pmap.h>
+
+#include <machine/pmap.h>
+
+#include <db.h>
+#include <limits.h>
+#include <kvm.h>
+#include <stdlib.h>
+
+#include "kvm_private.h"
+
+struct vmstate {
+ pd_entry_t *l1pt;
+ void *mmapbase;
+ size_t mmapsize;
+};
+
+static int
+_kvm_maphdrs(kvm_t *kd, size_t sz)
+{
+ struct vmstate *vm = kd->vmst;
+
+ /* munmap() previous mmap(). */
+ if (vm->mmapbase != NULL) {
+ munmap(vm->mmapbase, vm->mmapsize);
+ vm->mmapbase = NULL;
+ }
+
+ vm->mmapsize = sz;
+ vm->mmapbase = mmap(NULL, sz, PROT_READ, MAP_PRIVATE, kd->pmfd, 0);
+ if (vm->mmapbase == MAP_FAILED) {
+ _kvm_err(kd, kd->program, "cannot mmap corefile");
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * Translate a physical memory address to a file-offset in the crash-dump.
+ */
+static size_t
+_kvm_pa2off(kvm_t *kd, uint64_t pa, off_t *ofs, size_t pgsz)
+{
+ Elf32_Ehdr *e = kd->vmst->mmapbase;
+ Elf32_Phdr *p = (Elf32_Phdr*)((char*)e + e->e_phoff);
+ int n = e->e_phnum;
+
+ while (n && (pa < p->p_paddr || pa >= p->p_paddr + p->p_memsz))
+ p++, n--;
+ if (n == 0)
+ return (0);
+
+ *ofs = (pa - p->p_paddr) + p->p_offset;
+ if (pgsz == 0)
+ return (p->p_memsz - (pa - p->p_paddr));
+ return (pgsz - ((size_t)pa & (pgsz - 1)));
+}
+
+void
+_kvm_freevtop(kvm_t *kd)
+{
+ if (kd->vmst != 0) {
+ if (kd->vmst->mmapbase != NULL)
+ munmap(kd->vmst->mmapbase, kd->vmst->mmapsize);
+ free(kd->vmst);
+ kd->vmst = NULL;
+ }
+}
+
+int
+_kvm_initvtop(kvm_t *kd)
+{
+ struct vmstate *vm = _kvm_malloc(kd, sizeof(*vm));
+ struct nlist nlist[2];
+ u_long kernbase, physaddr, pa;
+ pd_entry_t *l1pt;
+ Elf32_Ehdr *ehdr;
+ size_t hdrsz;
+
+ if (vm == 0) {
+ _kvm_err(kd, kd->program, "cannot allocate vm");
+ return (-1);
+ }
+ kd->vmst = vm;
+ vm->l1pt = NULL;
+ if (_kvm_maphdrs(kd, sizeof(Elf32_Ehdr)) == -1)
+ return (-1);
+ ehdr = kd->vmst->mmapbase;
+ hdrsz = ehdr->e_phoff + ehdr->e_phentsize * ehdr->e_phnum;
+ if (_kvm_maphdrs(kd, hdrsz) == -1)
+ return (-1);
+ nlist[0].n_name = "kernbase";
+ nlist[1].n_name = NULL;
+ if (kvm_nlist(kd, nlist) != 0)
+ kernbase = KERNBASE;
+ else
+ kernbase = nlist[0].n_value;
+
+ nlist[0].n_name = "physaddr";
+ if (kvm_nlist(kd, nlist) != 0) {
+ _kvm_err(kd, kd->program, "couldn't get phys addr");
+ return (-1);
+ }
+ physaddr = nlist[0].n_value;
+ nlist[0].n_name = "kernel_l1pa";
+ if (kvm_nlist(kd, nlist) != 0) {
+ _kvm_err(kd, kd->program, "bad namelist");
+ return (-1);
+ }
+ if (kvm_read(kd, (nlist[0].n_value - kernbase + physaddr), &pa,
+ sizeof(pa)) != sizeof(pa)) {
+ _kvm_err(kd, kd->program, "cannot read kernel_l1pa");
+ return (-1);
+ }
+ l1pt = _kvm_malloc(kd, L1_TABLE_SIZE);
+ if (kvm_read(kd, pa, l1pt, L1_TABLE_SIZE) != L1_TABLE_SIZE) {
+ _kvm_err(kd, kd->program, "cannot read l1pt");
+ free(l1pt);
+ return (-1);
+ }
+ vm->l1pt = l1pt;
+ return 0;
+}
+
+/* from arm/pmap.c */
+#define L1_IDX(va) (((vm_offset_t)(va)) >> L1_S_SHIFT)
+/* from arm/pmap.h */
+#define L1_TYPE_INV 0x00 /* Invalid (fault) */
+#define L1_TYPE_C 0x01 /* Coarse L2 */
+#define L1_TYPE_S 0x02 /* Section */
+#define L1_TYPE_F 0x03 /* Fine L2 */
+#define L1_TYPE_MASK 0x03 /* mask of type bits */
+
+#define l1pte_section_p(pde) (((pde) & L1_TYPE_MASK) == L1_TYPE_S)
+#define l1pte_valid(pde) ((pde) != 0)
+#define l2pte_valid(pte) ((pte) != 0)
+#define l2pte_index(v) (((v) & L2_ADDR_BITS) >> L2_S_SHIFT)
+
+
+int
+_kvm_kvatop(kvm_t *kd, u_long va, off_t *pa)
+{
+ u_long offset = va & (PAGE_SIZE - 1);
+ struct vmstate *vm = kd->vmst;
+ pd_entry_t pd;
+ pt_entry_t pte;
+ u_long pte_pa;
+
+ if (vm->l1pt == NULL)
+ return (_kvm_pa2off(kd, va, pa, PAGE_SIZE));
+ pd = vm->l1pt[L1_IDX(va)];
+ if (!l1pte_valid(pd))
+ goto invalid;
+ if (l1pte_section_p(pd)) {
+ /* 1MB section mapping. */
+ *pa = ((u_long)pd & L1_S_ADDR_MASK) + (va & L1_S_OFFSET);
+ return (_kvm_pa2off(kd, *pa, pa, L1_S_SIZE));
+ }
+ pte_pa = (pd & L1_ADDR_MASK) + l2pte_index(va) * sizeof(pte);
+ _kvm_pa2off(kd, pte_pa, (off_t *)&pte_pa, L1_S_SIZE);
+ if (lseek(kd->pmfd, pte_pa, 0) == -1) {
+ _kvm_syserr(kd, kd->program, "_kvm_kvatop: lseek");
+ goto invalid;
+ }
+ if (read(kd->pmfd, &pte, sizeof(pte)) != sizeof (pte)) {
+ _kvm_syserr(kd, kd->program, "_kvm_kvatop: read");
+ goto invalid;
+ }
+ if (!l2pte_valid(pte)) {
+ goto invalid;
+ }
+ if ((pte & L2_TYPE_MASK) == L2_TYPE_L) {
+ *pa = (pte & L2_L_FRAME) | (va & L2_L_OFFSET);
+ return (_kvm_pa2off(kd, *pa, pa, L2_L_SIZE));
+ }
+ *pa = (pte & L2_S_FRAME) | (va & L2_S_OFFSET);
+ return (_kvm_pa2off(kd, *pa, pa, PAGE_SIZE));
+invalid:
+ _kvm_err(kd, 0, "Invalid address (%x)", va);
+ return 0;
+}
+
+/*
+ * Machine-dependent initialization for ALL open kvm descriptors,
+ * not just those for a kernel crash dump. Some architectures
+ * have to deal with these NOT being constants! (i.e. m68k)
+ */
+int
+_kvm_mdopen(kd)
+ kvm_t *kd;
+{
+
+#ifdef FBSD_NOT_YET
+ kd->usrstack = USRSTACK;
+ kd->min_uva = VM_MIN_ADDRESS;
+ kd->max_uva = VM_MAXUSER_ADDRESS;
+#endif
+
+ return (0);
+}
diff --git a/lib/libkvm/kvm_file.c b/lib/libkvm/kvm_file.c
new file mode 100644
index 0000000..4a2e20c
--- /dev/null
+++ b/lib/libkvm/kvm_file.c
@@ -0,0 +1,192 @@
+/*-
+ * Copyright (c) 1989, 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. 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)kvm_file.c 8.1 (Berkeley) 6/4/93";
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * File list interface for kvm. pstat, fstat and netstat are
+ * users of this code, so we've factored it out into a separate module.
+ * Thus, we keep this grunge out of the other kvm applications (i.e.,
+ * most other applications are interested only in open/close/read/nlist).
+ */
+
+#include <sys/param.h>
+#include <sys/user.h>
+#include <sys/proc.h>
+#define _KERNEL
+#include <sys/file.h>
+#undef _KERNEL
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <nlist.h>
+#include <kvm.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+
+#include <sys/sysctl.h>
+
+#include <limits.h>
+#include <ndbm.h>
+#include <paths.h>
+
+#include "kvm_private.h"
+
+#define KREAD(kd, addr, obj) \
+ (kvm_read(kd, addr, obj, sizeof(*obj)) != sizeof(*obj))
+
+/*
+ * Get file structures.
+ */
+static int
+kvm_deadfiles(kd, op, arg, filehead_o, nfiles)
+ kvm_t *kd;
+ int op, arg, nfiles;
+ long filehead_o;
+{
+ int buflen = kd->arglen, n = 0;
+ struct file *fp;
+ char *where = kd->argspc;
+ struct filelist filehead;
+
+ /*
+ * first copyout filehead
+ */
+ if (buflen > sizeof (filehead)) {
+ if (KREAD(kd, filehead_o, &filehead)) {
+ _kvm_err(kd, kd->program, "can't read filehead");
+ return (0);
+ }
+ buflen -= sizeof (filehead);
+ where += sizeof (filehead);
+ *(struct filelist *)kd->argspc = filehead;
+ }
+ /*
+ * followed by an array of file structures
+ */
+ LIST_FOREACH(fp, &filehead, f_list) {
+ if (buflen > sizeof (struct file)) {
+ if (KREAD(kd, (long)fp, ((struct file *)where))) {
+ _kvm_err(kd, kd->program, "can't read kfp");
+ return (0);
+ }
+ buflen -= sizeof (struct file);
+ fp = (struct file *)where;
+ where += sizeof (struct file);
+ n++;
+ }
+ }
+ if (n != nfiles) {
+ _kvm_err(kd, kd->program, "inconsistant nfiles");
+ return (0);
+ }
+ return (nfiles);
+}
+
+char *
+kvm_getfiles(kd, op, arg, cnt)
+ kvm_t *kd;
+ int op, arg;
+ int *cnt;
+{
+ int mib[2], st, nfiles;
+ size_t size;
+ struct file *fp, *fplim;
+ struct filelist filehead;
+
+ if (ISALIVE(kd)) {
+ size = 0;
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_FILE;
+ st = sysctl(mib, 2, NULL, &size, NULL, 0);
+ if (st == -1) {
+ _kvm_syserr(kd, kd->program, "kvm_getfiles");
+ return (0);
+ }
+ if (kd->argspc == 0)
+ kd->argspc = (char *)_kvm_malloc(kd, size);
+ else if (kd->arglen < size)
+ kd->argspc = (char *)_kvm_realloc(kd, kd->argspc, size);
+ if (kd->argspc == 0)
+ return (0);
+ kd->arglen = size;
+ st = sysctl(mib, 2, kd->argspc, &size, NULL, 0);
+ if (st == -1 || size < sizeof(filehead)) {
+ _kvm_syserr(kd, kd->program, "kvm_getfiles");
+ return (0);
+ }
+ filehead = *(struct filelist *)kd->argspc;
+ fp = (struct file *)(kd->argspc + sizeof (filehead));
+ fplim = (struct file *)(kd->argspc + size);
+ for (nfiles = 0; LIST_FIRST(&filehead) && (fp < fplim); nfiles++, fp++)
+ LIST_FIRST(&filehead) = LIST_NEXT(fp, f_list);
+ } else {
+ struct nlist nl[3], *p;
+
+ nl[0].n_name = "_filehead";
+ nl[1].n_name = "_nfiles";
+ nl[2].n_name = 0;
+
+ if (kvm_nlist(kd, nl) != 0) {
+ for (p = nl; p->n_type != 0; ++p)
+ ;
+ _kvm_err(kd, kd->program,
+ "%s: no such symbol", p->n_name);
+ return (0);
+ }
+ if (KREAD(kd, nl[0].n_value, &nfiles)) {
+ _kvm_err(kd, kd->program, "can't read nfiles");
+ return (0);
+ }
+ size = sizeof(filehead) + (nfiles + 10) * sizeof(struct file);
+ if (kd->argspc == 0)
+ kd->argspc = (char *)_kvm_malloc(kd, size);
+ else if (kd->arglen < size)
+ kd->argspc = (char *)_kvm_realloc(kd, kd->argspc, size);
+ if (kd->argspc == 0)
+ return (0);
+ kd->arglen = size;
+ nfiles = kvm_deadfiles(kd, op, arg, nl[1].n_value, nfiles);
+ if (nfiles == 0)
+ return (0);
+ }
+ *cnt = nfiles;
+ return (kd->argspc);
+}
diff --git a/lib/libkvm/kvm_geterr.3 b/lib/libkvm/kvm_geterr.3
new file mode 100644
index 0000000..49c6420
--- /dev/null
+++ b/lib/libkvm/kvm_geterr.3
@@ -0,0 +1,82 @@
+.\" Copyright (c) 1992, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software 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.
+.\" 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.
+.\"
+.\" @(#)kvm_geterr.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt KVM_GETERR 3
+.Os
+.Sh NAME
+.Nm kvm_geterr
+.Nd get error message on kvm descriptor
+.Sh LIBRARY
+.Lb libkvm
+.Sh SYNOPSIS
+.In kvm.h
+.Ft char *
+.Fn kvm_geterr "kvm_t *kd"
+.Sh DESCRIPTION
+This function returns a string describing the most recent error condition
+on the descriptor
+.Fa kd .
+The results are undefined if the most recent
+.Xr kvm 3
+library call did not produce an error.
+The string returned is stored in memory owned by
+.Xr kvm 3
+so the message should be copied out and saved elsewhere if necessary.
+.Sh SEE ALSO
+.Xr kvm 3 ,
+.Xr kvm_close 3 ,
+.Xr kvm_getargv 3 ,
+.Xr kvm_getenvv 3 ,
+.Xr kvm_getprocs 3 ,
+.Xr kvm_nlist 3 ,
+.Xr kvm_open 3 ,
+.Xr kvm_openfiles 3 ,
+.Xr kvm_read 3 ,
+.Xr kvm_write 3
+.Sh BUGS
+This routine cannot be used to access error conditions due to a failed
+.Fn kvm_openfiles
+call, since failure is indicated by returning a
+.Dv NULL
+descriptor.
+Therefore, errors on open are output to the special error buffer
+passed to
+.Fn kvm_openfiles .
+This option is not available to
+.Fn kvm_open .
diff --git a/lib/libkvm/kvm_getfiles.3 b/lib/libkvm/kvm_getfiles.3
new file mode 100644
index 0000000..b13fede
--- /dev/null
+++ b/lib/libkvm/kvm_getfiles.3
@@ -0,0 +1,91 @@
+.\" Copyright (c) 1992, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software 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.
+.\" 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.
+.\"
+.\" @(#)kvm_getfiles.3 8.2 (Berkeley) 4/19/94
+.\" $FreeBSD$
+.\"
+.Dd April 19, 1994
+.Dt KVM_GETFILES 3
+.Os
+.Sh NAME
+.Nm kvm_getfiles
+.Nd survey open files
+.Sh LIBRARY
+.Lb libkvm
+.Sh SYNOPSIS
+.In kvm.h
+.In sys/types.h
+.Fd #define _KERNEL
+.In sys/file.h
+.Fd #undef _KERNEL
+.\" .Fa kvm_t *kd
+.Ft char *
+.Fn kvm_getfiles "kvm_t *kd" "int op" "int arg" "int *cnt"
+.Sh DESCRIPTION
+The
+.Fn kvm_getfiles
+function returns a (sub-)set of the open files in the kernel indicated by
+.Fa kd .
+The
+.Fa op
+and
+.Fa arg
+arguments constitute a predicate which limits the set of files
+returned.
+No predicates are currently defined.
+.Pp
+The number of files found is returned in the reference parameter
+.Fa cnt .
+The files are returned as a contiguous array of file structures,
+preceded by the address of the first file entry in the kernel.
+This memory is owned by kvm and is not guaranteed to be persistent across
+subsequent kvm library calls.
+Data should be copied out if it needs to be
+saved.
+.Sh RETURN VALUES
+The
+.Fn kvm_getfiles
+function will return NULL on failure.
+.Sh SEE ALSO
+.Xr kvm 3 ,
+.Xr kvm_close 3 ,
+.Xr kvm_geterr 3 ,
+.Xr kvm_nlist 3 ,
+.Xr kvm_open 3 ,
+.Xr kvm_openfiles 3 ,
+.Xr kvm_read 3 ,
+.Xr kvm_write 3
+.Sh BUGS
+This routine does not belong in the kvm interface.
diff --git a/lib/libkvm/kvm_getloadavg.3 b/lib/libkvm/kvm_getloadavg.3
new file mode 100644
index 0000000..23310bc
--- /dev/null
+++ b/lib/libkvm/kvm_getloadavg.3
@@ -0,0 +1,66 @@
+.\" 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. 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.
+.\"
+.\" @(#)kvm_getloadavg.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt KVM_GETLOADAVG 3
+.Os
+.Sh NAME
+.Nm kvm_getloadavg
+.Nd get load average of the system
+.Sh LIBRARY
+.Lb libkvm
+.Sh SYNOPSIS
+.In kvm.h
+.Ft int
+.Fn kvm_getloadavg "kvm_t *kd" "double loadavg[]" "int nelem"
+.Sh DESCRIPTION
+The
+.Fn kvm_getloadavg
+function returns the number of processes in the system run queue
+of the kernel indicated by
+.Fa kd ,
+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 getloadavg 3 ,
+.Xr kvm 3
diff --git a/lib/libkvm/kvm_getloadavg.c b/lib/libkvm/kvm_getloadavg.c
new file mode 100644
index 0000000..72d59cd
--- /dev/null
+++ b/lib/libkvm/kvm_getloadavg.c
@@ -0,0 +1,106 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)kvm_getloadavg.c 8.1 (Berkeley) 6/4/93";
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#include <stdlib.h>
+#include <limits.h>
+#include <nlist.h>
+#include <kvm.h>
+
+#include "kvm_private.h"
+
+static struct nlist nl[] = {
+ { "_averunnable" },
+#define X_AVERUNNABLE 0
+ { "_fscale" },
+#define X_FSCALE 1
+ { "" },
+};
+
+/*
+ * kvm_getloadavg() -- Get system load averages, from live or dead kernels.
+ *
+ * Put `nelem' samples into `loadavg' array.
+ * Return number of samples retrieved, or -1 on error.
+ */
+int
+kvm_getloadavg(kd, loadavg, nelem)
+ kvm_t *kd;
+ double loadavg[];
+ int nelem;
+{
+ struct loadavg loadinfo;
+ struct nlist *p;
+ int fscale, i;
+
+ if (ISALIVE(kd))
+ return (getloadavg(loadavg, nelem));
+
+ if (kvm_nlist(kd, nl) != 0) {
+ for (p = nl; p->n_type != 0; ++p);
+ _kvm_err(kd, kd->program,
+ "%s: no such symbol", p->n_name);
+ return (-1);
+ }
+
+#define KREAD(kd, addr, obj) \
+ (kvm_read(kd, addr, (char *)(obj), sizeof(*obj)) != sizeof(*obj))
+ if (KREAD(kd, nl[X_AVERUNNABLE].n_value, &loadinfo)) {
+ _kvm_err(kd, kd->program, "can't read averunnable");
+ return (-1);
+ }
+
+ /*
+ * Old kernels have fscale separately; if not found assume
+ * running new format.
+ */
+ if (!KREAD(kd, nl[X_FSCALE].n_value, &fscale))
+ loadinfo.fscale = fscale;
+
+ 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/libkvm/kvm_getprocs.3 b/lib/libkvm/kvm_getprocs.3
new file mode 100644
index 0000000..107f6a8
--- /dev/null
+++ b/lib/libkvm/kvm_getprocs.3
@@ -0,0 +1,185 @@
+.\" Copyright (c) 1992, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software 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.
+.\" 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.
+.\"
+.\" @(#)kvm_getprocs.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd September 27, 2003
+.Dt KVM_GETPROCS 3
+.Os
+.Sh NAME
+.Nm kvm_getprocs ,
+.Nm kvm_getargv ,
+.Nm kvm_getenvv
+.Nd access user process state
+.Sh LIBRARY
+.Lb libkvm
+.Sh SYNOPSIS
+.In kvm.h
+.In sys/param.h
+.In sys/sysctl.h
+.In sys/user.h
+.\" .Fa kvm_t *kd
+.Ft struct kinfo_proc *
+.Fn kvm_getprocs "kvm_t *kd" "int op" "int arg" "int *cnt"
+.Ft char **
+.Fn kvm_getargv "kvm_t *kd" "const struct kinfo_proc *p" "int nchr"
+.Ft char **
+.Fn kvm_getenvv "kvm_t *kd" "const struct kinfo_proc *p" "int nchr"
+.Sh DESCRIPTION
+The
+.Fn kvm_getprocs
+function returns a (sub-)set of active processes in the kernel indicated by
+.Fa kd .
+The
+.Fa op
+and
+.Fa arg
+arguments constitute a predicate which limits the set of processes
+returned.
+The value of
+.Fa op
+describes the filtering predicate as follows:
+.Pp
+.Bl -tag -width 20n -offset indent -compact
+.It Dv KERN_PROC_ALL
+all processes and kernel visible threads
+.It Dv KERN_PROC_PROC
+all processes, without threads
+.It Dv KERN_PROC_PID
+processes with process ID
+.Fa arg
+.It Dv KERN_PROC_PGRP
+processes with process group
+.Fa arg
+.It Dv KERN_PROC_SESSION
+processes with session
+.Fa arg
+.It Dv KERN_PROC_TTY
+processes with TTY
+.Fa arg
+.It Dv KERN_PROC_UID
+processes with effective user ID
+.Fa arg
+.It Dv KERN_PROC_RUID
+processes with real user ID
+.Fa arg
+.It Dv KERN_PROC_INC_THREAD
+modifier to return all kernel visible threads when filtering
+by process ID, process group, TTY, user ID, and real user ID
+.El
+.Pp
+The number of processes found is returned in the reference parameter
+.Fa cnt .
+The processes are returned as a contiguous array of kinfo_proc structures.
+This memory is locally allocated, and subsequent calls to
+.Fn kvm_getprocs
+and
+.Fn kvm_close
+will overwrite this storage.
+.Pp
+The
+.Fn kvm_getargv
+function returns a null-terminated argument vector that corresponds to the
+command line arguments passed to process indicated by
+.Fa p .
+Most likely, these arguments correspond to the values passed to
+.Xr exec 3
+on process creation.
+This information is, however,
+deliberately under control of the process itself.
+Note that the original command name can be found, unaltered,
+in the p_comm field of the process structure returned by
+.Fn kvm_getprocs .
+.Pp
+The
+.Fa nchr
+argument indicates the maximum number of characters, including null bytes,
+to use in building the strings.
+If this amount is exceeded, the string
+causing the overflow is truncated and the partial result is returned.
+This is handy for programs like
+.Xr ps 1
+and
+.Xr w 1
+that print only a one line summary of a command and should not copy
+out large amounts of text only to ignore it.
+If
+.Fa nchr
+is zero, no limit is imposed and all argument strings are returned in
+their entirety.
+.Pp
+The memory allocated to the argv pointers and string storage
+is owned by the kvm library.
+Subsequent
+.Fn kvm_getprocs
+and
+.Xr kvm_close 3
+calls will clobber this storage.
+.Pp
+The
+.Fn kvm_getenvv
+function is similar to
+.Fn kvm_getargv
+but returns the vector of environment strings.
+This data is
+also alterable by the process.
+.Sh RETURN VALUES
+The
+.Fn kvm_getprocs ,
+.Fn kvm_getargv ,
+and
+.Fn kvm_getenvv
+functions return
+.Dv NULL
+on failure.
+.Sh SEE ALSO
+.Xr kvm 3 ,
+.Xr kvm_close 3 ,
+.Xr kvm_geterr 3 ,
+.Xr kvm_nlist 3 ,
+.Xr kvm_open 3 ,
+.Xr kvm_openfiles 3 ,
+.Xr kvm_read 3 ,
+.Xr kvm_write 3
+.Sh BUGS
+These routines do not belong in the kvm interface.
+.Pp
+In order for
+.Xr kvm_getenvv 3
+to function correctly,
+.Xr procfs 5
+must be mounted on
+.Pa /proc .
diff --git a/lib/libkvm/kvm_getswapinfo.3 b/lib/libkvm/kvm_getswapinfo.3
new file mode 100644
index 0000000..edd2068
--- /dev/null
+++ b/lib/libkvm/kvm_getswapinfo.3
@@ -0,0 +1,111 @@
+.\" Copyright (C) 1999 Matthew Dillon. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, 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$
+.\"
+.Dd January 22, 1999
+.Dt KVM_SWAPINFO 3
+.Os
+.Sh NAME
+.Nm kvm_getswapinfo
+.Nd return swap summary statistics for the system
+.Sh LIBRARY
+.Lb libkvm
+.Sh SYNOPSIS
+.In kvm.h
+.Ft int
+.Fn kvm_getswapinfo "kvm_t *kd" "struct kvm_swap *" "int maxswap" "int flags"
+.Sh DESCRIPTION
+The
+.Fn kvm_getswapinfo
+function fills an array of
+.Vt kvm_swap
+structures with swap summary
+information for each swap device, for up to
+.Fa maxswap
+\- 1 devices.
+The number of devices, up to
+.Fa maxswap
+\- 1, is returned.
+A grand
+total of all swap devices (including any devices that go beyond
+.Fa maxswap
+\- 1) is returned in one additional array entry.
+This
+entry is not counted in the return value.
+Thus, if you specify a
+.Fa maxswap
+value of 1, the function will typically return the
+value 0 and the single
+.Vt kvm_swap
+structure will be filled with
+the grand total over all swap devices.
+The grand total is calculated
+from all available swap devices whether or not you made room
+for them all in the array.
+The grand total is returned.
+.Pp
+The flags argument is currently unused and must be passed as 0.
+.Pp
+If an error occurs, -1 is returned.
+.Pp
+Each swap partition and the grand total is summarized in the
+.Vt kvm_swap
+structure.
+This structure contains the following fields:
+.Pp
+.Bl -item -offset indent -compact
+.It
+.Va char ksw_devname[] ;
+.It
+.Va int ksw_total ;
+.It
+.Va int ksw_used ;
+.It
+.Va int ksw_flags ;
+.El
+.Pp
+Values are in
+.Dv PAGE_SIZE Ns 'd
+chunks (see
+.Xr getpagesize 3 ) .
+.Va ksw_flags
+contains
+a copy of the swap device flags.
+.Sh CACHING
+This function caches the nlist values for various kernel variables which
+it reuses in successive calls.
+You may call the function with
+.Fa kd
+==
+.Dv NULL
+to clear the cache.
+.Sh DIAGNOSTICS
+If the load average was unobtainable, \-1 is returned; otherwise,
+the number of swap devices actually retrieved is returned.
+.Pp
+If the name of the swap device does not fit in the static char buffer
+in the structure, it is truncated.
+The buffer is always zero terminated.
+.Sh SEE ALSO
+.Xr kvm 3
diff --git a/lib/libkvm/kvm_getswapinfo.c b/lib/libkvm/kvm_getswapinfo.c
new file mode 100644
index 0000000..9ba7a5c
--- /dev/null
+++ b/lib/libkvm/kvm_getswapinfo.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 1999, Matthew Dillon. All Rights Reserved.
+ * Copyright (c) 2001, Thomas Moestl. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/blist.h>
+#include <sys/sysctl.h>
+
+#include <vm/vm_param.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <kvm.h>
+#include <nlist.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+
+#include "kvm_private.h"
+
+#define NL_SWAPBLIST 0
+#define NL_SWDEVT 1
+#define NL_NSWDEV 2
+#define NL_DMMAX 3
+
+static int kvm_swap_nl_cached = 0;
+static int unswdev; /* number of found swap dev's */
+static int dmmax;
+
+static int kvm_getswapinfo_sysctl(kvm_t *, struct kvm_swap *, int, int);
+static int getsysctl(kvm_t *, char *, void *, size_t);
+
+#define GETSWDEVNAME(dev, str, flags) \
+ if (dev == NODEV) { \
+ strlcpy(str, "[NFS swap]", sizeof(str)); \
+ } else { \
+ snprintf( \
+ str, sizeof(str),"%s%s", \
+ ((flags & SWIF_DEV_PREFIX) ? _PATH_DEV : ""), \
+ devname(dev, S_IFCHR) \
+ ); \
+ }
+
+int
+kvm_getswapinfo(
+ kvm_t *kd,
+ struct kvm_swap *swap_ary,
+ int swap_max,
+ int flags
+) {
+
+ /*
+ * clear cache
+ */
+ if (kd == NULL) {
+ kvm_swap_nl_cached = 0;
+ return(0);
+ }
+
+ if (ISALIVE(kd)) {
+ return kvm_getswapinfo_sysctl(kd, swap_ary, swap_max, flags);
+ } else {
+ return -1;
+ }
+}
+
+#define GETSYSCTL(kd, name, var) \
+ getsysctl(kd, name, &(var), sizeof(var))
+
+/* The maximum MIB length for vm.swap_info and an additional device number */
+#define SWI_MAXMIB 3
+
+int
+kvm_getswapinfo_sysctl(
+ kvm_t *kd,
+ struct kvm_swap *swap_ary,
+ int swap_max,
+ int flags
+) {
+ int ti, ttl;
+ size_t mibi, len;
+ int soid[SWI_MAXMIB];
+ struct xswdev xsd;
+ struct kvm_swap tot;
+
+ if (!GETSYSCTL(kd, "vm.dmmax", dmmax))
+ return -1;
+
+ mibi = SWI_MAXMIB - 1;
+ if (sysctlnametomib("vm.swap_info", soid, &mibi) == -1) {
+ _kvm_err(kd, kd->program, "sysctlnametomib failed: %s",
+ strerror(errno));
+ return -1;
+ }
+ bzero(&tot, sizeof(tot));
+ for (unswdev = 0;; unswdev++) {
+ soid[mibi] = unswdev;
+ len = sizeof(xsd);
+ if (sysctl(soid, mibi + 1, &xsd, &len, NULL, 0) == -1) {
+ if (errno == ENOENT)
+ break;
+ _kvm_err(kd, kd->program, "cannot read sysctl: %s.",
+ strerror(errno));
+ return -1;
+ }
+ if (len != sizeof(xsd)) {
+ _kvm_err(kd, kd->program, "struct xswdev has unexpected "
+ "size; kernel and libkvm out of sync?");
+ return -1;
+ }
+ if (xsd.xsw_version != XSWDEV_VERSION) {
+ _kvm_err(kd, kd->program, "struct xswdev version "
+ "mismatch; kernel and libkvm out of sync?");
+ return -1;
+ }
+
+ ttl = xsd.xsw_nblks - dmmax;
+ if (unswdev < swap_max - 1) {
+ bzero(&swap_ary[unswdev], sizeof(swap_ary[unswdev]));
+ swap_ary[unswdev].ksw_total = ttl;
+ swap_ary[unswdev].ksw_used = xsd.xsw_used;
+ swap_ary[unswdev].ksw_flags = xsd.xsw_flags;
+ GETSWDEVNAME(xsd.xsw_dev, swap_ary[unswdev].ksw_devname,
+ flags);
+ }
+ tot.ksw_total += ttl;
+ tot.ksw_used += xsd.xsw_used;
+ }
+
+ ti = unswdev;
+ if (ti >= swap_max)
+ ti = swap_max - 1;
+ if (ti >= 0)
+ swap_ary[ti] = tot;
+
+ return(ti);
+}
+
+static int
+getsysctl (
+ kvm_t *kd,
+ char *name,
+ void *ptr,
+ size_t len
+) {
+ size_t nlen = len;
+ if (sysctlbyname(name, ptr, &nlen, NULL, 0) == -1) {
+ _kvm_err(kd, kd->program, "cannot read sysctl %s:%s", name,
+ strerror(errno));
+ return (0);
+ }
+ if (nlen != len) {
+ _kvm_err(kd, kd->program, "sysctl %s has unexpected size", name);
+ return (0);
+ }
+ return (1);
+}
diff --git a/lib/libkvm/kvm_i386.c b/lib/libkvm/kvm_i386.c
new file mode 100644
index 0000000..9560cc9
--- /dev/null
+++ b/lib/libkvm/kvm_i386.c
@@ -0,0 +1,448 @@
+/*-
+ * Copyright (c) 1989, 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software 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.
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)kvm_hp300.c 8.1 (Berkeley) 6/4/93";
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * i386 machine dependent routines for kvm. Hopefully, the forthcoming
+ * vm code will one day obsolete this module.
+ */
+
+#include <sys/param.h>
+#include <sys/user.h>
+#include <sys/proc.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <nlist.h>
+#include <kvm.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+
+#include <machine/elf.h>
+
+#include <limits.h>
+
+#include "kvm_private.h"
+
+#ifndef btop
+#define btop(x) (i386_btop(x))
+#define ptob(x) (i386_ptob(x))
+#endif
+
+#define PG_FRAME_PAE (~((uint64_t)PAGE_MASK))
+#define PDRSHIFT_PAE 21
+#define NPTEPG_PAE (PAGE_SIZE/sizeof(uint64_t))
+#define NBPDR_PAE (1<<PDRSHIFT_PAE)
+
+/* minidump must be the first item! */
+struct vmstate {
+ int minidump; /* 1 = minidump mode */
+ void *mmapbase;
+ size_t mmapsize;
+ void *PTD;
+ int pae;
+};
+
+/*
+ * Map the ELF headers into the process' address space. We do this in two
+ * steps: first the ELF header itself and using that information the whole
+ * set of headers. (Taken from kvm_ia64.c)
+ */
+static int
+_kvm_maphdrs(kvm_t *kd, size_t sz)
+{
+ struct vmstate *vm = kd->vmst;
+
+ /* munmap() previous mmap(). */
+ if (vm->mmapbase != NULL) {
+ munmap(vm->mmapbase, vm->mmapsize);
+ vm->mmapbase = NULL;
+ }
+
+ vm->mmapsize = sz;
+ vm->mmapbase = mmap(NULL, sz, PROT_READ, MAP_PRIVATE, kd->pmfd, 0);
+ if (vm->mmapbase == MAP_FAILED) {
+ _kvm_err(kd, kd->program, "cannot mmap corefile");
+ return (-1);
+ }
+ return (0);
+}
+
+/*
+ * Translate a physical memory address to a file-offset in the crash-dump.
+ * (Taken from kvm_ia64.c)
+ */
+static size_t
+_kvm_pa2off(kvm_t *kd, uint64_t pa, off_t *ofs)
+{
+ Elf_Ehdr *e = kd->vmst->mmapbase;
+ Elf_Phdr *p = (Elf_Phdr*)((char*)e + e->e_phoff);
+ int n = e->e_phnum;
+
+ while (n && (pa < p->p_paddr || pa >= p->p_paddr + p->p_memsz))
+ p++, n--;
+ if (n == 0)
+ return (0);
+ *ofs = (pa - p->p_paddr) + p->p_offset;
+ return (PAGE_SIZE - ((size_t)pa & PAGE_MASK));
+}
+
+void
+_kvm_freevtop(kvm_t *kd)
+{
+ struct vmstate *vm = kd->vmst;
+
+ if (kd->vmst->minidump)
+ return (_kvm_minidump_freevtop(kd));
+ if (vm->mmapbase != NULL)
+ munmap(vm->mmapbase, vm->mmapsize);
+ if (vm->PTD)
+ free(vm->PTD);
+ free(vm);
+ kd->vmst = NULL;
+}
+
+int
+_kvm_initvtop(kvm_t *kd)
+{
+ struct nlist nlist[2];
+ u_long pa;
+ u_long kernbase;
+ char *PTD;
+ Elf_Ehdr *ehdr;
+ size_t hdrsz;
+ int i;
+ char minihdr[8];
+
+ if (pread(kd->pmfd, &minihdr, 8, 0) == 8)
+ if (memcmp(&minihdr, "minidump", 8) == 0)
+ return (_kvm_minidump_initvtop(kd));
+
+ kd->vmst = (struct vmstate *)_kvm_malloc(kd, sizeof(*kd->vmst));
+ if (kd->vmst == 0) {
+ _kvm_err(kd, kd->program, "cannot allocate vm");
+ return (-1);
+ }
+ kd->vmst->PTD = 0;
+
+ if (_kvm_maphdrs(kd, sizeof(Elf_Ehdr)) == -1)
+ return (-1);
+
+ ehdr = kd->vmst->mmapbase;
+ hdrsz = ehdr->e_phoff + ehdr->e_phentsize * ehdr->e_phnum;
+ if (_kvm_maphdrs(kd, hdrsz) == -1)
+ return (-1);
+
+ nlist[0].n_name = "kernbase";
+ nlist[1].n_name = 0;
+
+ if (kvm_nlist(kd, nlist) != 0)
+ kernbase = KERNBASE; /* for old kernels */
+ else
+ kernbase = nlist[0].n_value;
+
+ nlist[0].n_name = "IdlePDPT";
+ nlist[1].n_name = 0;
+
+ if (kvm_nlist(kd, nlist) == 0) {
+ uint64_t pa64;
+
+ if (kvm_read(kd, (nlist[0].n_value - kernbase), &pa,
+ sizeof(pa)) != sizeof(pa)) {
+ _kvm_err(kd, kd->program, "cannot read IdlePDPT");
+ return (-1);
+ }
+ PTD = _kvm_malloc(kd, 4 * PAGE_SIZE);
+ for (i = 0; i < 4; i++) {
+ if (kvm_read(kd, pa + (i * sizeof(pa64)), &pa64,
+ sizeof(pa64)) != sizeof(pa64)) {
+ _kvm_err(kd, kd->program, "Cannot read PDPT");
+ free(PTD);
+ return (-1);
+ }
+ if (kvm_read(kd, pa64 & PG_FRAME_PAE,
+ PTD + (i * PAGE_SIZE), PAGE_SIZE) != (PAGE_SIZE)) {
+ _kvm_err(kd, kd->program, "cannot read PDPT");
+ free(PTD);
+ return (-1);
+ }
+ }
+ kd->vmst->PTD = PTD;
+ kd->vmst->pae = 1;
+ } else {
+ nlist[0].n_name = "IdlePTD";
+ nlist[1].n_name = 0;
+
+ if (kvm_nlist(kd, nlist) != 0) {
+ _kvm_err(kd, kd->program, "bad namelist");
+ return (-1);
+ }
+ if (kvm_read(kd, (nlist[0].n_value - kernbase), &pa,
+ sizeof(pa)) != sizeof(pa)) {
+ _kvm_err(kd, kd->program, "cannot read IdlePTD");
+ return (-1);
+ }
+ PTD = _kvm_malloc(kd, PAGE_SIZE);
+ if (kvm_read(kd, pa, PTD, PAGE_SIZE) != PAGE_SIZE) {
+ _kvm_err(kd, kd->program, "cannot read PTD");
+ return (-1);
+ }
+ kd->vmst->PTD = PTD;
+ return (0);
+ kd->vmst->pae = 0;
+ }
+ return (0);
+}
+
+static int
+_kvm_vatop(kvm_t *kd, u_long va, off_t *pa)
+{
+ struct vmstate *vm;
+ u_long offset;
+ u_long pte_pa;
+ u_long pde_pa;
+ pd_entry_t pde;
+ pt_entry_t pte;
+ u_long pdeindex;
+ u_long pteindex;
+ size_t s;
+ u_long a;
+ off_t ofs;
+ uint32_t *PTD;
+
+ vm = kd->vmst;
+ PTD = (uint32_t *)vm->PTD;
+ offset = va & (PAGE_SIZE - 1);
+
+ /*
+ * If we are initializing (kernel page table descriptor pointer
+ * not yet set) then return pa == va to avoid infinite recursion.
+ */
+ if (PTD == 0) {
+ s = _kvm_pa2off(kd, va, pa);
+ if (s == 0) {
+ _kvm_err(kd, kd->program,
+ "_kvm_vatop: bootstrap data not in dump");
+ goto invalid;
+ } else
+ return (PAGE_SIZE - offset);
+ }
+
+ pdeindex = va >> PDRSHIFT;
+ pde = PTD[pdeindex];
+ if (((u_long)pde & PG_V) == 0) {
+ _kvm_err(kd, kd->program, "_kvm_vatop: pde not valid");
+ goto invalid;
+ }
+
+ if ((u_long)pde & PG_PS) {
+ /*
+ * No second-level page table; ptd describes one 4MB page.
+ * (We assume that the kernel wouldn't set PG_PS without enabling
+ * it cr0).
+ */
+#define PAGE4M_MASK (NBPDR - 1)
+#define PG_FRAME4M (~PAGE4M_MASK)
+ pde_pa = ((u_long)pde & PG_FRAME4M) + (va & PAGE4M_MASK);
+ s = _kvm_pa2off(kd, pde_pa, &ofs);
+ if (s < sizeof pde) {
+ _kvm_syserr(kd, kd->program,
+ "_kvm_vatop: pde_pa not found");
+ goto invalid;
+ }
+ *pa = ofs;
+ return (NBPDR - (va & PAGE4M_MASK));
+ }
+
+ pteindex = (va >> PAGE_SHIFT) & (NPTEPG-1);
+ pte_pa = ((u_long)pde & PG_FRAME) + (pteindex * sizeof(pde));
+
+ s = _kvm_pa2off(kd, pte_pa, &ofs);
+ if (s < sizeof pte) {
+ _kvm_err(kd, kd->program, "_kvm_vatop: pdpe_pa not found");
+ goto invalid;
+ }
+
+ /* XXX This has to be a physical address read, kvm_read is virtual */
+ if (lseek(kd->pmfd, ofs, 0) == -1) {
+ _kvm_syserr(kd, kd->program, "_kvm_vatop: lseek");
+ goto invalid;
+ }
+ if (read(kd->pmfd, &pte, sizeof pte) != sizeof pte) {
+ _kvm_syserr(kd, kd->program, "_kvm_vatop: read");
+ goto invalid;
+ }
+ if (((u_long)pte & PG_V) == 0) {
+ _kvm_err(kd, kd->program, "_kvm_kvatop: pte not valid");
+ goto invalid;
+ }
+
+ a = ((u_long)pte & PG_FRAME) + offset;
+ s =_kvm_pa2off(kd, a, pa);
+ if (s == 0) {
+ _kvm_err(kd, kd->program, "_kvm_vatop: address not in dump");
+ goto invalid;
+ } else
+ return (PAGE_SIZE - offset);
+
+invalid:
+ _kvm_err(kd, 0, "invalid address (0x%lx)", va);
+ return (0);
+}
+
+static int
+_kvm_vatop_pae(kvm_t *kd, u_long va, off_t *pa)
+{
+ struct vmstate *vm;
+ uint64_t offset;
+ uint64_t pte_pa;
+ uint64_t pde_pa;
+ uint64_t pde;
+ uint64_t pte;
+ u_long pdeindex;
+ u_long pteindex;
+ size_t s;
+ uint64_t a;
+ off_t ofs;
+ uint64_t *PTD;
+
+ vm = kd->vmst;
+ PTD = (uint64_t *)vm->PTD;
+ offset = va & (PAGE_SIZE - 1);
+
+ /*
+ * If we are initializing (kernel page table descriptor pointer
+ * not yet set) then return pa == va to avoid infinite recursion.
+ */
+ if (PTD == 0) {
+ s = _kvm_pa2off(kd, va, pa);
+ if (s == 0) {
+ _kvm_err(kd, kd->program,
+ "_kvm_vatop_pae: bootstrap data not in dump");
+ goto invalid;
+ } else
+ return (PAGE_SIZE - offset);
+ }
+
+ pdeindex = va >> PDRSHIFT_PAE;
+ pde = PTD[pdeindex];
+ if (((u_long)pde & PG_V) == 0) {
+ _kvm_err(kd, kd->program, "_kvm_kvatop_pae: pde not valid");
+ goto invalid;
+ }
+
+ if ((u_long)pde & PG_PS) {
+ /*
+ * No second-level page table; ptd describes one 2MB page.
+ * (We assume that the kernel wouldn't set PG_PS without enabling
+ * it cr0).
+ */
+#define PAGE2M_MASK (NBPDR_PAE - 1)
+#define PG_FRAME2M (~PAGE2M_MASK)
+ pde_pa = ((u_long)pde & PG_FRAME2M) + (va & PAGE2M_MASK);
+ s = _kvm_pa2off(kd, pde_pa, &ofs);
+ if (s < sizeof pde) {
+ _kvm_syserr(kd, kd->program,
+ "_kvm_vatop_pae: pde_pa not found");
+ goto invalid;
+ }
+ *pa = ofs;
+ return (NBPDR_PAE - (va & PAGE2M_MASK));
+ }
+
+ pteindex = (va >> PAGE_SHIFT) & (NPTEPG_PAE-1);
+ pte_pa = ((uint64_t)pde & PG_FRAME_PAE) + (pteindex * sizeof(pde));
+
+ s = _kvm_pa2off(kd, pte_pa, &ofs);
+ if (s < sizeof pte) {
+ _kvm_err(kd, kd->program, "_kvm_vatop_pae: pdpe_pa not found");
+ goto invalid;
+ }
+
+ /* XXX This has to be a physical address read, kvm_read is virtual */
+ if (lseek(kd->pmfd, ofs, 0) == -1) {
+ _kvm_syserr(kd, kd->program, "_kvm_vatop_pae: lseek");
+ goto invalid;
+ }
+ if (read(kd->pmfd, &pte, sizeof pte) != sizeof pte) {
+ _kvm_syserr(kd, kd->program, "_kvm_vatop_pae: read");
+ goto invalid;
+ }
+ if (((uint64_t)pte & PG_V) == 0) {
+ _kvm_err(kd, kd->program, "_kvm_vatop_pae: pte not valid");
+ goto invalid;
+ }
+
+ a = ((uint64_t)pte & PG_FRAME_PAE) + offset;
+ s =_kvm_pa2off(kd, a, pa);
+ if (s == 0) {
+ _kvm_err(kd, kd->program,
+ "_kvm_vatop_pae: address not in dump");
+ goto invalid;
+ } else
+ return (PAGE_SIZE - offset);
+
+invalid:
+ _kvm_err(kd, 0, "invalid address (0x%lx)", va);
+ return (0);
+}
+
+int
+_kvm_kvatop(kvm_t *kd, u_long va, off_t *pa)
+{
+
+ if (kd->vmst->minidump)
+ return (_kvm_minidump_kvatop(kd, va, pa));
+ if (ISALIVE(kd)) {
+ _kvm_err(kd, 0, "vatop called in live kernel!");
+ return (0);
+ }
+ if (kd->vmst->pae)
+ return (_kvm_vatop_pae(kd, va, pa));
+ else
+ return (_kvm_vatop(kd, va, pa));
+}
diff --git a/lib/libkvm/kvm_ia64.c b/lib/libkvm/kvm_ia64.c
new file mode 100644
index 0000000..fbee551
--- /dev/null
+++ b/lib/libkvm/kvm_ia64.c
@@ -0,0 +1,209 @@
+/* $FreeBSD$ */
+/* $NetBSD: kvm_alpha.c,v 1.7.2.1 1997/11/02 20:34:26 mellon Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <sys/types.h>
+#include <sys/elf64.h>
+#include <sys/mman.h>
+
+#include <machine/pte.h>
+
+#include <kvm.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "kvm_private.h"
+
+#define REGION_BASE(n) (((uint64_t)(n)) << 61)
+#define REGION_ADDR(x) ((x) & ((1LL<<61)-1LL))
+
+#define NKPTEPG(ps) ((ps) / sizeof(struct ia64_lpte))
+#define KPTE_PTE_INDEX(va,ps) (((va)/(ps)) % NKPTEPG(ps))
+#define KPTE_DIR_INDEX(va,ps) (((va)/(ps)) / NKPTEPG(ps))
+
+struct vmstate {
+ void *mmapbase;
+ size_t mmapsize;
+ size_t pagesize;
+ u_long kptdir;
+};
+
+/*
+ * Map the ELF headers into the process' address space. We do this in two
+ * steps: first the ELF header itself and using that information the whole
+ * set of headers.
+ */
+static int
+_kvm_maphdrs(kvm_t *kd, size_t sz)
+{
+ struct vmstate *vm = kd->vmst;
+
+ /* munmap() previous mmap(). */
+ if (vm->mmapbase != NULL) {
+ munmap(vm->mmapbase, vm->mmapsize);
+ vm->mmapbase = NULL;
+ }
+
+ vm->mmapsize = sz;
+ vm->mmapbase = mmap(NULL, sz, PROT_READ, MAP_PRIVATE, kd->pmfd, 0);
+ if (vm->mmapbase == MAP_FAILED) {
+ _kvm_err(kd, kd->program, "cannot mmap corefile");
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * Translate a physical memory address to a file-offset in the crash-dump.
+ */
+static size_t
+_kvm_pa2off(kvm_t *kd, uint64_t pa, off_t *ofs, size_t pgsz)
+{
+ Elf64_Ehdr *e = kd->vmst->mmapbase;
+ Elf64_Phdr *p = (Elf64_Phdr*)((char*)e + e->e_phoff);
+ int n = e->e_phnum;
+
+ if (pa != REGION_ADDR(pa)) {
+ _kvm_err(kd, kd->program, "internal error");
+ return (0);
+ }
+
+ while (n && (pa < p->p_paddr || pa >= p->p_paddr + p->p_memsz))
+ p++, n--;
+ if (n == 0)
+ return (0);
+
+ *ofs = (pa - p->p_paddr) + p->p_offset;
+ if (pgsz == 0)
+ return (p->p_memsz - (pa - p->p_paddr));
+ return (pgsz - ((size_t)pa & (pgsz - 1)));
+}
+
+void
+_kvm_freevtop(kvm_t *kd)
+{
+ struct vmstate *vm = kd->vmst;
+
+ if (vm->mmapbase != NULL)
+ munmap(vm->mmapbase, vm->mmapsize);
+ free(vm);
+ kd->vmst = NULL;
+}
+
+int
+_kvm_initvtop(kvm_t *kd)
+{
+ struct nlist nlist[2];
+ uint64_t va;
+ Elf64_Ehdr *ehdr;
+ size_t hdrsz;
+
+ kd->vmst = (struct vmstate *)_kvm_malloc(kd, sizeof(*kd->vmst));
+ if (kd->vmst == NULL) {
+ _kvm_err(kd, kd->program, "cannot allocate vm");
+ return (-1);
+ }
+
+ kd->vmst->pagesize = getpagesize();
+
+ if (_kvm_maphdrs(kd, sizeof(Elf64_Ehdr)) == -1)
+ return (-1);
+
+ ehdr = kd->vmst->mmapbase;
+ hdrsz = ehdr->e_phoff + ehdr->e_phentsize * ehdr->e_phnum;
+ if (_kvm_maphdrs(kd, hdrsz) == -1)
+ return (-1);
+
+ /*
+ * At this point we've got enough information to use kvm_read() for
+ * direct mapped (ie region 6 and region 7) address, such as symbol
+ * addresses/values.
+ */
+
+ nlist[0].n_name = "ia64_kptdir";
+ nlist[1].n_name = 0;
+
+ if (kvm_nlist(kd, nlist) != 0) {
+ _kvm_err(kd, kd->program, "bad namelist");
+ return (-1);
+ }
+
+ if (kvm_read(kd, (nlist[0].n_value), &va, sizeof(va)) != sizeof(va)) {
+ _kvm_err(kd, kd->program, "cannot read kptdir");
+ return (-1);
+ }
+
+ if (va < REGION_BASE(6)) {
+ _kvm_err(kd, kd->program, "kptdir is itself virtual");
+ return (-1);
+ }
+
+ kd->vmst->kptdir = va;
+ return (0);
+}
+
+int
+_kvm_kvatop(kvm_t *kd, u_long va, off_t *pa)
+{
+ struct ia64_lpte pte;
+ uint64_t pgaddr, ptaddr;
+ size_t pgno, pgsz, ptno;
+
+ if (va >= REGION_BASE(6)) {
+ /* Regions 6 and 7: direct mapped. */
+ return (_kvm_pa2off(kd, REGION_ADDR(va), pa, 0));
+ } else if (va >= REGION_BASE(5)) {
+ /* Region 5: virtual. */
+ va = REGION_ADDR(va);
+ pgsz = kd->vmst->pagesize;
+ ptno = KPTE_DIR_INDEX(va, pgsz);
+ pgno = KPTE_PTE_INDEX(va, pgsz);
+ if (ptno >= (pgsz >> 3))
+ goto fail;
+ ptaddr = kd->vmst->kptdir + (ptno << 3);
+ if (kvm_read(kd, ptaddr, &pgaddr, 8) != 8)
+ goto fail;
+ if (pgaddr == 0)
+ goto fail;
+ pgaddr += (pgno * sizeof(pte));
+ if (kvm_read(kd, pgaddr, &pte, sizeof(pte)) != sizeof(pte))
+ goto fail;
+ if (!(pte.pte & PTE_PRESENT))
+ goto fail;
+ va = (pte.pte & PTE_PPN_MASK) + (va & (pgsz - 1));
+ return (_kvm_pa2off(kd, va, pa, pgsz));
+ }
+
+ fail:
+ _kvm_err(kd, kd->program, "invalid kernel virtual address");
+ *pa = ~0UL;
+ return (0);
+}
diff --git a/lib/libkvm/kvm_minidump_amd64.c b/lib/libkvm/kvm_minidump_amd64.c
new file mode 100644
index 0000000..c431756
--- /dev/null
+++ b/lib/libkvm/kvm_minidump_amd64.c
@@ -0,0 +1,255 @@
+/*-
+ * Copyright (c) 2006 Peter Wemm
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * AMD64 machine dependent routines for kvm and minidumps.
+ */
+
+#include <sys/param.h>
+#include <sys/user.h>
+#include <sys/proc.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/fnv_hash.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <nlist.h>
+#include <kvm.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+
+#include <machine/elf.h>
+#include <machine/cpufunc.h>
+#include <machine/minidump.h>
+
+#include <limits.h>
+
+#include "kvm_private.h"
+
+struct hpte {
+ struct hpte *next;
+ vm_paddr_t pa;
+ int64_t off;
+};
+
+#define HPT_SIZE 1024
+
+/* minidump must be the first item! */
+struct vmstate {
+ int minidump; /* 1 = minidump mode */
+ struct minidumphdr hdr;
+ void *hpt_head[HPT_SIZE];
+ uint64_t *bitmap;
+ uint64_t *ptemap;
+};
+
+static void
+hpt_insert(kvm_t *kd, vm_paddr_t pa, int64_t off)
+{
+ struct hpte *hpte;
+ uint32_t fnv = FNV1_32_INIT;
+
+ fnv = fnv_32_buf(&pa, sizeof(pa), fnv);
+ fnv &= (HPT_SIZE - 1);
+ hpte = malloc(sizeof(*hpte));
+ hpte->pa = pa;
+ hpte->off = off;
+ hpte->next = kd->vmst->hpt_head[fnv];
+ kd->vmst->hpt_head[fnv] = hpte;
+}
+
+static int64_t
+hpt_find(kvm_t *kd, vm_paddr_t pa)
+{
+ struct hpte *hpte;
+ uint32_t fnv = FNV1_32_INIT;
+
+ fnv = fnv_32_buf(&pa, sizeof(pa), fnv);
+ fnv &= (HPT_SIZE - 1);
+ for (hpte = kd->vmst->hpt_head[fnv]; hpte != NULL; hpte = hpte->next) {
+ if (pa == hpte->pa)
+ return (hpte->off);
+ }
+ return (-1);
+}
+
+static int
+inithash(kvm_t *kd, uint64_t *base, int len, off_t off)
+{
+ uint64_t idx;
+ uint64_t bit, bits;
+ vm_paddr_t pa;
+
+ for (idx = 0; idx < len / sizeof(*base); idx++) {
+ bits = base[idx];
+ while (bits) {
+ bit = bsfq(bits);
+ bits &= ~(1ul << bit);
+ pa = (idx * sizeof(*base) * NBBY + bit) * PAGE_SIZE;
+ hpt_insert(kd, pa, off);
+ off += PAGE_SIZE;
+ }
+ }
+ return (off);
+}
+
+void
+_kvm_minidump_freevtop(kvm_t *kd)
+{
+ struct vmstate *vm = kd->vmst;
+
+ if (vm->bitmap)
+ free(vm->bitmap);
+ if (vm->ptemap)
+ free(vm->ptemap);
+ free(vm);
+ kd->vmst = NULL;
+}
+
+int
+_kvm_minidump_initvtop(kvm_t *kd)
+{
+ u_long pa;
+ struct vmstate *vmst;
+ off_t off;
+
+ vmst = _kvm_malloc(kd, sizeof(*vmst));
+ if (vmst == 0) {
+ _kvm_err(kd, kd->program, "cannot allocate vm");
+ return (-1);
+ }
+ kd->vmst = vmst;
+ bzero(vmst, sizeof(*vmst));
+ vmst->minidump = 1;
+ if (pread(kd->pmfd, &vmst->hdr, sizeof(vmst->hdr), 0) !=
+ sizeof(vmst->hdr)) {
+ _kvm_err(kd, kd->program, "cannot read dump header");
+ return (-1);
+ }
+ if (strncmp(MINIDUMP_MAGIC, vmst->hdr.magic, sizeof(vmst->hdr.magic)) != 0) {
+ _kvm_err(kd, kd->program, "not a minidump for this platform");
+ return (-1);
+ }
+ if (vmst->hdr.version != MINIDUMP_VERSION) {
+ _kvm_err(kd, kd->program, "wrong minidump version. expected %d got %d",
+ MINIDUMP_VERSION, vmst->hdr.version);
+ return (-1);
+ }
+
+ /* Skip header and msgbuf */
+ off = PAGE_SIZE + round_page(vmst->hdr.msgbufsize);
+
+ vmst->bitmap = _kvm_malloc(kd, vmst->hdr.bitmapsize);
+ if (vmst->bitmap == NULL) {
+ _kvm_err(kd, kd->program, "cannot allocate %d bytes for bitmap", vmst->hdr.bitmapsize);
+ return (-1);
+ }
+ if (pread(kd->pmfd, vmst->bitmap, vmst->hdr.bitmapsize, off) !=
+ vmst->hdr.bitmapsize) {
+ _kvm_err(kd, kd->program, "cannot read %d bytes for page bitmap", vmst->hdr.bitmapsize);
+ return (-1);
+ }
+ off += round_page(vmst->hdr.bitmapsize);
+
+ vmst->ptemap = _kvm_malloc(kd, vmst->hdr.ptesize);
+ if (vmst->ptemap == NULL) {
+ _kvm_err(kd, kd->program, "cannot allocate %d bytes for ptemap", vmst->hdr.ptesize);
+ return (-1);
+ }
+ if (pread(kd->pmfd, vmst->ptemap, vmst->hdr.ptesize, off) !=
+ vmst->hdr.ptesize) {
+ _kvm_err(kd, kd->program, "cannot read %d bytes for ptemap", vmst->hdr.ptesize);
+ return (-1);
+ }
+ off += vmst->hdr.ptesize;
+
+ /* build physical address hash table for sparse pages */
+ inithash(kd, vmst->bitmap, vmst->hdr.bitmapsize, off);
+
+ return (0);
+}
+
+static int
+_kvm_minidump_vatop(kvm_t *kd, u_long va, off_t *pa)
+{
+ struct vmstate *vm;
+ u_long offset;
+ pt_entry_t pte;
+ u_long pteindex;
+ int i;
+ u_long a;
+ off_t ofs;
+
+ vm = kd->vmst;
+ offset = va & (PAGE_SIZE - 1);
+
+ if (va >= vm->hdr.kernbase) {
+ pteindex = (va - vm->hdr.kernbase) >> PAGE_SHIFT;
+ pte = vm->ptemap[pteindex];
+ if (((u_long)pte & PG_V) == 0) {
+ _kvm_err(kd, kd->program, "_kvm_vatop: pte not valid");
+ goto invalid;
+ }
+ a = pte & PG_FRAME;
+ ofs = hpt_find(kd, a);
+ if (ofs == -1) {
+ _kvm_err(kd, kd->program, "_kvm_vatop: physical address 0x%lx not in minidump", a);
+ goto invalid;
+ }
+ *pa = ofs + offset;
+ return (PAGE_SIZE - offset);
+ } else if (va >= vm->hdr.dmapbase && va < vm->hdr.dmapend) {
+ a = (va - vm->hdr.dmapbase) & ~PAGE_MASK;
+ ofs = hpt_find(kd, a);
+ if (ofs == -1) {
+ _kvm_err(kd, kd->program, "_kvm_vatop: direct map address 0x%lx not in minidump", va);
+ goto invalid;
+ }
+ *pa = ofs + offset;
+ return (PAGE_SIZE - offset);
+ } else {
+ _kvm_err(kd, kd->program, "_kvm_vatop: virtual address 0x%lx not minidumped", va);
+ goto invalid;
+ }
+
+invalid:
+ _kvm_err(kd, 0, "invalid address (0x%lx)", va);
+ return (0);
+}
+
+int
+_kvm_minidump_kvatop(kvm_t *kd, u_long va, off_t *pa)
+{
+
+ if (ISALIVE(kd)) {
+ _kvm_err(kd, 0, "kvm_kvatop called in live kernel!");
+ return (0);
+ }
+ return (_kvm_minidump_vatop(kd, va, pa));
+}
diff --git a/lib/libkvm/kvm_minidump_i386.c b/lib/libkvm/kvm_minidump_i386.c
new file mode 100644
index 0000000..c7d1f91
--- /dev/null
+++ b/lib/libkvm/kvm_minidump_i386.c
@@ -0,0 +1,294 @@
+/*-
+ * Copyright (c) 2006 Peter Wemm
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * AMD64 machine dependent routines for kvm and minidumps.
+ */
+
+#include <sys/param.h>
+#include <sys/user.h>
+#include <sys/proc.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/fnv_hash.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <nlist.h>
+#include <kvm.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+
+#include <machine/elf.h>
+#include <machine/cpufunc.h>
+#include <machine/minidump.h>
+
+#include <limits.h>
+
+#include "kvm_private.h"
+
+#define PG_FRAME_PAE (~((uint64_t)PAGE_MASK))
+
+struct hpte {
+ struct hpte *next;
+ uint64_t pa;
+ int64_t off;
+};
+
+#define HPT_SIZE 1024
+
+/* minidump must be the first item! */
+struct vmstate {
+ int minidump; /* 1 = minidump mode */
+ struct minidumphdr hdr;
+ void *hpt_head[HPT_SIZE];
+ uint32_t *bitmap;
+ void *ptemap;
+};
+
+static void
+hpt_insert(kvm_t *kd, uint64_t pa, int64_t off)
+{
+ struct hpte *hpte;
+ uint32_t fnv = FNV1_32_INIT;
+
+ fnv = fnv_32_buf(&pa, sizeof(pa), fnv);
+ fnv &= (HPT_SIZE - 1);
+ hpte = malloc(sizeof(*hpte));
+ hpte->pa = pa;
+ hpte->off = off;
+ hpte->next = kd->vmst->hpt_head[fnv];
+ kd->vmst->hpt_head[fnv] = hpte;
+}
+
+static int64_t
+hpt_find(kvm_t *kd, uint64_t pa)
+{
+ struct hpte *hpte;
+ uint32_t fnv = FNV1_32_INIT;
+
+ fnv = fnv_32_buf(&pa, sizeof(pa), fnv);
+ fnv &= (HPT_SIZE - 1);
+ for (hpte = kd->vmst->hpt_head[fnv]; hpte != NULL; hpte = hpte->next) {
+ if (pa == hpte->pa)
+ return (hpte->off);
+ }
+ return (-1);
+}
+
+static int
+inithash(kvm_t *kd, uint32_t *base, int len, off_t off)
+{
+ uint64_t idx;
+ uint32_t bit, bits;
+ uint64_t pa;
+
+ for (idx = 0; idx < len / sizeof(*base); idx++) {
+ bits = base[idx];
+ while (bits) {
+ bit = bsfl(bits);
+ bits &= ~(1ul << bit);
+ pa = (idx * sizeof(*base) * NBBY + bit) * PAGE_SIZE;
+ hpt_insert(kd, pa, off);
+ off += PAGE_SIZE;
+ }
+ }
+ return (off);
+}
+
+void
+_kvm_minidump_freevtop(kvm_t *kd)
+{
+ struct vmstate *vm = kd->vmst;
+
+ if (vm->bitmap)
+ free(vm->bitmap);
+ if (vm->ptemap)
+ free(vm->ptemap);
+ free(vm);
+ kd->vmst = NULL;
+}
+
+int
+_kvm_minidump_initvtop(kvm_t *kd)
+{
+ u_long pa;
+ struct vmstate *vmst;
+ off_t off;
+
+ vmst = _kvm_malloc(kd, sizeof(*vmst));
+ if (vmst == 0) {
+ _kvm_err(kd, kd->program, "cannot allocate vm");
+ return (-1);
+ }
+ kd->vmst = vmst;
+ bzero(vmst, sizeof(*vmst));
+ vmst->minidump = 1;
+ if (pread(kd->pmfd, &vmst->hdr, sizeof(vmst->hdr), 0) !=
+ sizeof(vmst->hdr)) {
+ _kvm_err(kd, kd->program, "cannot read dump header");
+ return (-1);
+ }
+ if (strncmp(MINIDUMP_MAGIC, vmst->hdr.magic, sizeof(vmst->hdr.magic)) != 0) {
+ _kvm_err(kd, kd->program, "not a minidump for this platform");
+ return (-1);
+ }
+ if (vmst->hdr.version != MINIDUMP_VERSION) {
+ _kvm_err(kd, kd->program, "wrong minidump version. expected %d got %d",
+ MINIDUMP_VERSION, vmst->hdr.version);
+ return (-1);
+ }
+
+ /* Skip header and msgbuf */
+ off = PAGE_SIZE + round_page(vmst->hdr.msgbufsize);
+
+ vmst->bitmap = _kvm_malloc(kd, vmst->hdr.bitmapsize);
+ if (vmst->bitmap == NULL) {
+ _kvm_err(kd, kd->program, "cannot allocate %d bytes for bitmap", vmst->hdr.bitmapsize);
+ return (-1);
+ }
+ if (pread(kd->pmfd, vmst->bitmap, vmst->hdr.bitmapsize, off) !=
+ vmst->hdr.bitmapsize) {
+ _kvm_err(kd, kd->program, "cannot read %d bytes for page bitmap", vmst->hdr.bitmapsize);
+ return (-1);
+ }
+ off += round_page(vmst->hdr.bitmapsize);
+
+ vmst->ptemap = _kvm_malloc(kd, vmst->hdr.ptesize);
+ if (vmst->ptemap == NULL) {
+ _kvm_err(kd, kd->program, "cannot allocate %d bytes for ptemap", vmst->hdr.ptesize);
+ return (-1);
+ }
+ if (pread(kd->pmfd, vmst->ptemap, vmst->hdr.ptesize, off) !=
+ vmst->hdr.ptesize) {
+ _kvm_err(kd, kd->program, "cannot read %d bytes for ptemap", vmst->hdr.ptesize);
+ return (-1);
+ }
+ off += vmst->hdr.ptesize;
+
+ /* build physical address hash table for sparse pages */
+ inithash(kd, vmst->bitmap, vmst->hdr.bitmapsize, off);
+
+ return (0);
+}
+
+static int
+_kvm_minidump_vatop_pae(kvm_t *kd, u_long va, off_t *pa)
+{
+ struct vmstate *vm;
+ uint64_t offset;
+ uint64_t pte;
+ u_long pteindex;
+ int i;
+ uint64_t a;
+ off_t ofs;
+ uint64_t *ptemap;
+
+ vm = kd->vmst;
+ ptemap = vm->ptemap;
+ offset = va & (PAGE_SIZE - 1);
+
+ if (va >= vm->hdr.kernbase) {
+ pteindex = (va - vm->hdr.kernbase) >> PAGE_SHIFT;
+ pte = ptemap[pteindex];
+ if ((pte & PG_V) == 0) {
+ _kvm_err(kd, kd->program, "_kvm_vatop: pte not valid");
+ goto invalid;
+ }
+ a = pte & PG_FRAME_PAE;
+ ofs = hpt_find(kd, a);
+ if (ofs == -1) {
+ _kvm_err(kd, kd->program, "_kvm_vatop: physical address 0x%llx not in minidump", a);
+ goto invalid;
+ }
+ *pa = ofs + offset;
+ return (PAGE_SIZE - offset);
+ } else {
+ _kvm_err(kd, kd->program, "_kvm_vatop: virtual address 0x%lx not minidumped", va);
+ goto invalid;
+ }
+
+invalid:
+ _kvm_err(kd, 0, "invalid address (0x%lx)", va);
+ return (0);
+}
+
+static int
+_kvm_minidump_vatop(kvm_t *kd, u_long va, off_t *pa)
+{
+ struct vmstate *vm;
+ u_long offset;
+ pt_entry_t pte;
+ u_long pteindex;
+ int i;
+ u_long a;
+ off_t ofs;
+ uint32_t *ptemap;
+
+ vm = kd->vmst;
+ ptemap = vm->ptemap;
+ offset = va & (PAGE_SIZE - 1);
+
+ if (va >= vm->hdr.kernbase) {
+ pteindex = (va - vm->hdr.kernbase) >> PAGE_SHIFT;
+ pte = ptemap[pteindex];
+ if ((pte & PG_V) == 0) {
+ _kvm_err(kd, kd->program, "_kvm_vatop: pte not valid");
+ goto invalid;
+ }
+ a = pte & PG_FRAME;
+ ofs = hpt_find(kd, a);
+ if (ofs == -1) {
+ _kvm_err(kd, kd->program, "_kvm_vatop: physical address 0x%lx not in minidump", a);
+ goto invalid;
+ }
+ *pa = ofs + offset;
+ return (PAGE_SIZE - offset);
+ } else {
+ _kvm_err(kd, kd->program, "_kvm_vatop: virtual address 0x%lx not minidumped", va);
+ goto invalid;
+ }
+
+invalid:
+ _kvm_err(kd, 0, "invalid address (0x%lx)", va);
+ return (0);
+}
+
+int
+_kvm_minidump_kvatop(kvm_t *kd, u_long va, off_t *pa)
+{
+
+ if (ISALIVE(kd)) {
+ _kvm_err(kd, 0, "kvm_kvatop called in live kernel!");
+ return (0);
+ }
+ if (kd->vmst->hdr.paemode)
+ return (_kvm_minidump_vatop_pae(kd, va, pa));
+ else
+ return (_kvm_minidump_vatop(kd, va, pa));
+}
diff --git a/lib/libkvm/kvm_nlist.3 b/lib/libkvm/kvm_nlist.3
new file mode 100644
index 0000000..c1dd8b7
--- /dev/null
+++ b/lib/libkvm/kvm_nlist.3
@@ -0,0 +1,89 @@
+.\" Copyright (c) 1992, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software 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.
+.\" 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.
+.\"
+.\" @(#)kvm_nlist.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt KVM_NLIST 3
+.Os
+.Sh NAME
+.Nm kvm_nlist
+.Nd retrieve symbol table names from a kernel image
+.Sh LIBRARY
+.Lb libkvm
+.Sh SYNOPSIS
+.In kvm.h
+.In nlist.h
+.Ft int
+.Fn kvm_nlist "kvm_t *kd" "struct nlist *nl"
+.Sh DESCRIPTION
+The
+.Fn kvm_nlist
+function retrieves the symbol table entries indicated by the name list argument
+.Fa \&nl .
+This argument points to an array of nlist structures, terminated by
+an entry whose n_name field is
+.Dv NULL
+(see
+.Xr nlist 3 ) .
+Each symbol is looked up using the n_name field, and if found, the
+corresponding n_type and n_value fields are filled in.
+These fields are set
+to 0 if the symbol is not found.
+.Pp
+The
+.Xr kldsym 2
+system call is used to locate the symbol.
+This is a less than perfect
+emulation of the nlist values but has the advantage of being aware of kernel
+modules and is reasonably fast.
+.Sh RETURN VALUES
+The
+.Fn kvm_nlist
+function returns the number of invalid entries found.
+If the kernel symbol table was unreadable, -1 is returned.
+.Sh SEE ALSO
+.Xr kldsym 2 ,
+.Xr kvm 3 ,
+.Xr kvm_close 3 ,
+.Xr kvm_getargv 3 ,
+.Xr kvm_getenvv 3 ,
+.Xr kvm_geterr 3 ,
+.Xr kvm_getprocs 3 ,
+.Xr kvm_open 3 ,
+.Xr kvm_openfiles 3 ,
+.Xr kvm_read 3 ,
+.Xr kvm_write 3
diff --git a/lib/libkvm/kvm_open.3 b/lib/libkvm/kvm_open.3
new file mode 100644
index 0000000..f9fa557
--- /dev/null
+++ b/lib/libkvm/kvm_open.3
@@ -0,0 +1,209 @@
+.\" Copyright (c) 1992, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software 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.
+.\" 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.
+.\"
+.\" @(#)kvm_open.3 8.3 (Berkeley) 4/19/94
+.\" $FreeBSD$
+.\"
+.Dd January 29, 2004
+.Dt KVM_OPEN 3
+.Os
+.Sh NAME
+.Nm kvm_open ,
+.Nm kvm_openfiles ,
+.Nm kvm_close
+.Nd initialize kernel virtual memory access
+.Sh LIBRARY
+.Lb libkvm
+.Sh SYNOPSIS
+.In fcntl.h
+.In kvm.h
+.Ft kvm_t *
+.Fn kvm_open "const char *execfile" "const char *corefile" "const char *swapfile" "int flags" "const char *errstr"
+.Ft kvm_t *
+.Fn kvm_openfiles "const char *execfile" "const char *corefile" "const char *swapfile" "int flags" "char *errbuf"
+.Ft int
+.Fn kvm_close "kvm_t *kd"
+.Sh DESCRIPTION
+The functions
+.Fn kvm_open
+and
+.Fn kvm_openfiles
+return a descriptor used to access kernel virtual memory
+via the
+.Xr kvm 3
+library routines.
+Both active kernels and crash dumps are accessible
+through this interface.
+.Pp
+The
+.Fa execfile
+argument is the executable image of the kernel being examined.
+This file must contain a symbol table.
+If this argument is
+.Dv NULL ,
+the currently running system is assumed,
+as determined from
+.Xr getbootfile 3 .
+.Pp
+The
+.Fa corefile
+argument is the kernel memory device file.
+It can be either
+.Pa /dev/mem
+or a crash dump core generated by
+.Xr savecore 8 .
+If
+.Fa corefile
+is
+.Dv NULL ,
+the default indicated by
+.Dv _PATH_MEM
+from
+.In paths.h
+is used.
+It can also be set to a special value
+.Pa /dev/null
+by utilities like
+.Xr ps 1
+that do not directly access kernel memory.
+.Pp
+The
+.Fa swapfile
+argument is currently unused.
+.Pp
+The
+.Fa flags
+argument indicates read/write access as in
+.Xr open 2
+and applies only to the core file.
+Only
+.Dv O_RDONLY ,
+.Dv O_WRONLY ,
+and
+.Dv O_RDWR
+are permitted.
+.Pp
+There are two open routines which differ only with respect to
+the error mechanism.
+One provides backward compatibility with the SunOS kvm library, while the
+other provides an improved error reporting framework.
+.Pp
+The
+.Fn kvm_open
+function is the Sun kvm compatible open call.
+Here, the
+.Fa errstr
+argument indicates how errors should be handled.
+If it is
+.Dv NULL ,
+no errors are reported and the application cannot know the
+specific nature of the failed kvm call.
+If it is not
+.Dv NULL ,
+errors are printed to
+.Dv stderr
+with
+.Fa errstr
+prepended to the message, as in
+.Xr perror 3 .
+Normally, the name of the program is used here.
+The string is assumed to persist at least until the corresponding
+.Fn kvm_close
+call.
+.Pp
+The
+.Fn kvm_openfiles
+function provides
+.Bx
+style error reporting.
+Here, error messages are not printed out by the library.
+Instead, the application obtains the error message
+corresponding to the most recent kvm library call using
+.Fn kvm_geterr
+(see
+.Xr kvm_geterr 3 ) .
+The results are undefined if the most recent kvm call did not produce
+an error.
+Since
+.Fn kvm_geterr
+requires a kvm descriptor, but the open routines return
+.Dv NULL
+on failure,
+.Fn kvm_geterr
+cannot be used to get the error message if open fails.
+Thus,
+.Fn kvm_openfiles
+will place any error message in the
+.Fa errbuf
+argument.
+This buffer should be _POSIX2_LINE_MAX characters large (from
+<limits.h>).
+.Sh RETURN VALUES
+The
+.Fn kvm_open
+and
+.Fn kvm_openfiles
+functions both return a descriptor to be used
+in all subsequent kvm library calls.
+The library is fully re-entrant.
+On failure,
+.Dv NULL
+is returned, in which case
+.Fn kvm_openfiles
+writes the error message into
+.Fa errbuf .
+.Pp
+The
+.Fn kvm_close
+function returns 0 on success and -1 on failure.
+.Sh SEE ALSO
+.Xr open 2 ,
+.Xr kvm 3 ,
+.Xr kvm_getargv 3 ,
+.Xr kvm_getenvv 3 ,
+.Xr kvm_geterr 3 ,
+.Xr kvm_getprocs 3 ,
+.Xr kvm_nlist 3 ,
+.Xr kvm_read 3 ,
+.Xr kvm_write 3 ,
+.Xr kmem 4 ,
+.Xr mem 4
+.Sh BUGS
+There should not be two open calls.
+The ill-defined error semantics
+of the Sun library and the desire to have a backward-compatible library
+for
+.Bx
+left little choice.
diff --git a/lib/libkvm/kvm_powerpc.c b/lib/libkvm/kvm_powerpc.c
new file mode 100644
index 0000000..24ab7fb
--- /dev/null
+++ b/lib/libkvm/kvm_powerpc.c
@@ -0,0 +1,103 @@
+/* $NetBSD: kvm_powerpc.c,v 1.4 1998/02/03 06:50:07 mycroft Exp $ */
+
+/*-
+ * Copyright (C) 1996 Wolfgang Solfrank.
+ * Copyright (C) 1996 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.
+ */
+
+/*
+ * PowerPC machine dependent routines for kvm.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+
+#include <vm/vm.h>
+
+#include <db.h>
+#include <limits.h>
+#include <kvm.h>
+#include <stdlib.h>
+
+#include "kvm_private.h"
+
+void
+_kvm_freevtop(kd)
+ kvm_t *kd;
+{
+ if (kd->vmst != 0)
+ free(kd->vmst);
+}
+
+int
+_kvm_initvtop(kd)
+ kvm_t *kd;
+{
+ return 0;
+}
+
+int
+_kvm_kvatop(kd, va, pa)
+ kvm_t *kd;
+ u_long va;
+ off_t *pa;
+{
+ _kvm_err(kd, 0, "vatop not yet implemented!");
+ return 0;
+}
+
+off_t
+_kvm_pa2off(kd, pa)
+ kvm_t *kd;
+ u_long pa;
+{
+ _kvm_err(kd, 0, "pa2off not yet implemented!");
+ return 0;
+}
+
+/*
+ * Machine-dependent initialization for ALL open kvm descriptors,
+ * not just those for a kernel crash dump. Some architectures
+ * have to deal with these NOT being constants! (i.e. m68k)
+ */
+int
+_kvm_mdopen(kd)
+ kvm_t *kd;
+{
+
+#ifdef FBSD_NOT_YET
+ kd->usrstack = USRSTACK;
+ kd->min_uva = VM_MIN_ADDRESS;
+ kd->max_uva = VM_MAXUSER_ADDRESS;
+#endif
+
+ return (0);
+}
diff --git a/lib/libkvm/kvm_private.h b/lib/libkvm/kvm_private.h
new file mode 100644
index 0000000..9bbeb43
--- /dev/null
+++ b/lib/libkvm/kvm_private.h
@@ -0,0 +1,89 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software 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.
+ * 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.
+ *
+ * @(#)kvm_private.h 8.1 (Berkeley) 6/4/93
+ * $FreeBSD$
+ */
+
+struct __kvm {
+ /*
+ * a string to be prepended to error messages
+ * provided for compatibility with sun's interface
+ * if this value is null, errors are saved in errbuf[]
+ */
+ const char *program;
+ char *errp; /* XXX this can probably go away */
+ char errbuf[_POSIX2_LINE_MAX];
+#define ISALIVE(kd) ((kd)->vmfd >= 0)
+ int pmfd; /* physical memory file (or crashdump) */
+ int vmfd; /* virtual memory file (-1 if crashdump) */
+ int unused; /* was: swap file (e.g., /dev/drum) */
+ int nlfd; /* namelist file (e.g., /kernel) */
+ struct kinfo_proc *procbase;
+ char *argspc; /* (dynamic) storage for argv strings */
+ int arglen; /* length of the above */
+ char **argv; /* (dynamic) storage for argv pointers */
+ int argc; /* length of above (not actual # present) */
+ char *argbuf; /* (dynamic) temporary storage */
+ /*
+ * Kernel virtual address translation state. This only gets filled
+ * in for dead kernels; otherwise, the running kernel (i.e. kmem)
+ * will do the translations for us. It could be big, so we
+ * only allocate it if necessary.
+ */
+ struct vmstate *vmst;
+};
+
+/*
+ * Functions used internally by kvm, but across kvm modules.
+ */
+void _kvm_err(kvm_t *kd, const char *program, const char *fmt, ...)
+ __printflike(3, 4);
+void _kvm_freeprocs(kvm_t *kd);
+void _kvm_freevtop(kvm_t *);
+int _kvm_initvtop(kvm_t *);
+int _kvm_kvatop(kvm_t *, u_long, off_t *);
+void *_kvm_malloc(kvm_t *kd, size_t);
+void *_kvm_realloc(kvm_t *kd, void *, size_t);
+void _kvm_syserr (kvm_t *kd, const char *program, const char *fmt, ...)
+ __printflike(3, 4);
+int _kvm_uvatop(kvm_t *, const struct proc *, u_long, u_long *);
+
+#if defined(__amd64__) || defined(__i386__)
+void _kvm_minidump_freevtop(kvm_t *);
+int _kvm_minidump_initvtop(kvm_t *);
+int _kvm_minidump_kvatop(kvm_t *, u_long, off_t *);
+#endif
diff --git a/lib/libkvm/kvm_proc.c b/lib/libkvm/kvm_proc.c
new file mode 100644
index 0000000..250cb44
--- /dev/null
+++ b/lib/libkvm/kvm_proc.c
@@ -0,0 +1,1024 @@
+/*-
+ * Copyright (c) 1989, 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software 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.
+ * 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.
+ */
+
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)kvm_proc.c 8.3 (Berkeley) 9/23/93";
+#endif /* LIBC_SCCS and not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Proc traversal interface for kvm. ps and w are (probably) the exclusive
+ * users of this code, so we've factored it out into a separate module.
+ * Thus, we keep this grunge out of the other kvm applications (i.e.,
+ * most other applications are interested only in open/close/read/nlist).
+ */
+
+#include <sys/param.h>
+#define _WANT_UCRED /* make ucred.h give us 'struct ucred' */
+#include <sys/ucred.h>
+#include <sys/queue.h>
+#include <sys/_lock.h>
+#include <sys/_mutex.h>
+#include <sys/_task.h>
+#define _WANT_PRISON /* make jail.h give us 'struct prison' */
+#include <sys/jail.h>
+#include <sys/user.h>
+#include <sys/proc.h>
+#include <sys/exec.h>
+#include <sys/stat.h>
+#include <sys/sysent.h>
+#include <sys/ioctl.h>
+#include <sys/tty.h>
+#include <sys/file.h>
+#include <sys/conf.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <nlist.h>
+#include <kvm.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+
+#include <sys/sysctl.h>
+
+#include <limits.h>
+#include <memory.h>
+#include <paths.h>
+
+#include "kvm_private.h"
+
+#define KREAD(kd, addr, obj) \
+ (kvm_read(kd, addr, (char *)(obj), sizeof(*obj)) != sizeof(*obj))
+
+/*
+ * Read proc's from memory file into buffer bp, which has space to hold
+ * at most maxcnt procs.
+ */
+static int
+kvm_proclist(kd, what, arg, p, bp, maxcnt)
+ kvm_t *kd;
+ int what, arg;
+ struct proc *p;
+ struct kinfo_proc *bp;
+ int maxcnt;
+{
+ int cnt = 0;
+ struct kinfo_proc kinfo_proc, *kp;
+ struct pgrp pgrp;
+ struct session sess;
+ struct cdev t_cdev;
+ struct tty tty;
+ struct vmspace vmspace;
+ struct sigacts sigacts;
+ struct pstats pstats;
+ struct ucred ucred;
+ struct prison pr;
+ struct thread mtd;
+ /*struct kse mke;*/
+ struct ksegrp mkg;
+ struct proc proc;
+ struct proc pproc;
+ struct timeval tv;
+ struct sysentvec sysent;
+ char svname[KI_EMULNAMELEN];
+
+ kp = &kinfo_proc;
+ kp->ki_structsize = sizeof(kinfo_proc);
+ for (; cnt < maxcnt && p != NULL; p = LIST_NEXT(&proc, p_list)) {
+ memset(kp, 0, sizeof *kp);
+ if (KREAD(kd, (u_long)p, &proc)) {
+ _kvm_err(kd, kd->program, "can't read proc at %x", p);
+ return (-1);
+ }
+ if (proc.p_state != PRS_ZOMBIE) {
+ if (KREAD(kd, (u_long)TAILQ_FIRST(&proc.p_threads),
+ &mtd)) {
+ _kvm_err(kd, kd->program,
+ "can't read thread at %x",
+ TAILQ_FIRST(&proc.p_threads));
+ return (-1);
+ }
+ if ((proc.p_flag & P_SA) == 0) {
+ if (KREAD(kd,
+ (u_long)TAILQ_FIRST(&proc.p_ksegrps),
+ &mkg)) {
+ _kvm_err(kd, kd->program,
+ "can't read ksegrp at %x",
+ TAILQ_FIRST(&proc.p_ksegrps));
+ return (-1);
+ }
+#if 0
+ if (KREAD(kd,
+ (u_long)TAILQ_FIRST(&mkg.kg_kseq), &mke)) {
+ _kvm_err(kd, kd->program,
+ "can't read kse at %x",
+ TAILQ_FIRST(&mkg.kg_kseq));
+ return (-1);
+ }
+#endif
+ }
+ }
+ if (KREAD(kd, (u_long)proc.p_ucred, &ucred) == 0) {
+ kp->ki_ruid = ucred.cr_ruid;
+ kp->ki_svuid = ucred.cr_svuid;
+ kp->ki_rgid = ucred.cr_rgid;
+ kp->ki_svgid = ucred.cr_svgid;
+ kp->ki_ngroups = ucred.cr_ngroups;
+ bcopy(ucred.cr_groups, kp->ki_groups,
+ NGROUPS * sizeof(gid_t));
+ kp->ki_uid = ucred.cr_uid;
+ if (ucred.cr_prison != NULL) {
+ if (KREAD(kd, (u_long)ucred.cr_prison, &pr)) {
+ _kvm_err(kd, kd->program,
+ "can't read prison at %x",
+ ucred.cr_prison);
+ return (-1);
+ }
+ kp->ki_jid = pr.pr_id;
+ }
+ }
+
+ switch(what & ~KERN_PROC_INC_THREAD) {
+
+ case KERN_PROC_GID:
+ if (kp->ki_groups[0] != (gid_t)arg)
+ continue;
+ break;
+
+ case KERN_PROC_PID:
+ if (proc.p_pid != (pid_t)arg)
+ continue;
+ break;
+
+ case KERN_PROC_RGID:
+ if (kp->ki_rgid != (gid_t)arg)
+ continue;
+ break;
+
+ case KERN_PROC_UID:
+ if (kp->ki_uid != (uid_t)arg)
+ continue;
+ break;
+
+ case KERN_PROC_RUID:
+ if (kp->ki_ruid != (uid_t)arg)
+ continue;
+ break;
+ }
+ /*
+ * We're going to add another proc to the set. If this
+ * will overflow the buffer, assume the reason is because
+ * nprocs (or the proc list) is corrupt and declare an error.
+ */
+ if (cnt >= maxcnt) {
+ _kvm_err(kd, kd->program, "nprocs corrupt");
+ return (-1);
+ }
+ /*
+ * gather kinfo_proc
+ */
+ kp->ki_paddr = p;
+ kp->ki_addr = 0; /* XXX uarea */
+ /* kp->ki_kstack = proc.p_thread.td_kstack; XXXKSE */
+ kp->ki_args = proc.p_args;
+ kp->ki_tracep = proc.p_tracevp;
+ kp->ki_textvp = proc.p_textvp;
+ kp->ki_fd = proc.p_fd;
+ kp->ki_vmspace = proc.p_vmspace;
+ if (proc.p_sigacts != NULL) {
+ if (KREAD(kd, (u_long)proc.p_sigacts, &sigacts)) {
+ _kvm_err(kd, kd->program,
+ "can't read sigacts at %x", proc.p_sigacts);
+ return (-1);
+ }
+ kp->ki_sigignore = sigacts.ps_sigignore;
+ kp->ki_sigcatch = sigacts.ps_sigcatch;
+ }
+ if ((proc.p_sflag & PS_INMEM) && proc.p_stats != NULL) {
+ if (KREAD(kd, (u_long)proc.p_stats, &pstats)) {
+ _kvm_err(kd, kd->program,
+ "can't read stats at %x", proc.p_stats);
+ return (-1);
+ }
+ kp->ki_start = pstats.p_start;
+
+ /*
+ * XXX: The times here are probably zero and need
+ * to be calculated from the raw data in p_rux and
+ * p_crux.
+ */
+ kp->ki_rusage = pstats.p_ru;
+ kp->ki_childstime = pstats.p_cru.ru_stime;
+ kp->ki_childutime = pstats.p_cru.ru_utime;
+ /* Some callers want child-times in a single value */
+ timeradd(&kp->ki_childstime, &kp->ki_childutime,
+ &kp->ki_childtime);
+ }
+ if (proc.p_oppid)
+ kp->ki_ppid = proc.p_oppid;
+ else if (proc.p_pptr) {
+ if (KREAD(kd, (u_long)proc.p_pptr, &pproc)) {
+ _kvm_err(kd, kd->program,
+ "can't read pproc at %x", proc.p_pptr);
+ return (-1);
+ }
+ kp->ki_ppid = pproc.p_pid;
+ } else
+ kp->ki_ppid = 0;
+ if (proc.p_pgrp == NULL)
+ goto nopgrp;
+ if (KREAD(kd, (u_long)proc.p_pgrp, &pgrp)) {
+ _kvm_err(kd, kd->program, "can't read pgrp at %x",
+ proc.p_pgrp);
+ return (-1);
+ }
+ kp->ki_pgid = pgrp.pg_id;
+ kp->ki_jobc = pgrp.pg_jobc;
+ if (KREAD(kd, (u_long)pgrp.pg_session, &sess)) {
+ _kvm_err(kd, kd->program, "can't read session at %x",
+ pgrp.pg_session);
+ return (-1);
+ }
+ kp->ki_sid = sess.s_sid;
+ (void)memcpy(kp->ki_login, sess.s_login,
+ sizeof(kp->ki_login));
+ kp->ki_kiflag = sess.s_ttyvp ? KI_CTTY : 0;
+ if (sess.s_leader == p)
+ kp->ki_kiflag |= KI_SLEADER;
+ if ((proc.p_flag & P_CONTROLT) && sess.s_ttyp != NULL) {
+ if (KREAD(kd, (u_long)sess.s_ttyp, &tty)) {
+ _kvm_err(kd, kd->program,
+ "can't read tty at %x", sess.s_ttyp);
+ return (-1);
+ }
+ if (tty.t_dev != NULL) {
+ if (KREAD(kd, (u_long)tty.t_dev, &t_cdev)) {
+ _kvm_err(kd, kd->program,
+ "can't read cdev at %x",
+ tty.t_dev);
+ return (-1);
+ }
+#if 0
+ kp->ki_tdev = t_cdev.si_udev;
+#else
+ kp->ki_tdev = NODEV;
+#endif
+ }
+ if (tty.t_pgrp != NULL) {
+ if (KREAD(kd, (u_long)tty.t_pgrp, &pgrp)) {
+ _kvm_err(kd, kd->program,
+ "can't read tpgrp at %x",
+ tty.t_pgrp);
+ return (-1);
+ }
+ kp->ki_tpgid = pgrp.pg_id;
+ } else
+ kp->ki_tpgid = -1;
+ if (tty.t_session != NULL) {
+ if (KREAD(kd, (u_long)tty.t_session, &sess)) {
+ _kvm_err(kd, kd->program,
+ "can't read session at %x",
+ tty.t_session);
+ return (-1);
+ }
+ kp->ki_tsid = sess.s_sid;
+ }
+ } else {
+nopgrp:
+ kp->ki_tdev = NODEV;
+ }
+ if ((proc.p_state != PRS_ZOMBIE) && mtd.td_wmesg)
+ (void)kvm_read(kd, (u_long)mtd.td_wmesg,
+ kp->ki_wmesg, WMESGLEN);
+
+ (void)kvm_read(kd, (u_long)proc.p_vmspace,
+ (char *)&vmspace, sizeof(vmspace));
+ kp->ki_size = vmspace.vm_map.size;
+ kp->ki_rssize = vmspace.vm_swrss; /* XXX */
+ kp->ki_swrss = vmspace.vm_swrss;
+ kp->ki_tsize = vmspace.vm_tsize;
+ kp->ki_dsize = vmspace.vm_dsize;
+ kp->ki_ssize = vmspace.vm_ssize;
+
+ switch (what & ~KERN_PROC_INC_THREAD) {
+
+ case KERN_PROC_PGRP:
+ if (kp->ki_pgid != (pid_t)arg)
+ continue;
+ break;
+
+ case KERN_PROC_SESSION:
+ if (kp->ki_sid != (pid_t)arg)
+ continue;
+ break;
+
+ case KERN_PROC_TTY:
+ if ((proc.p_flag & P_CONTROLT) == 0 ||
+ kp->ki_tdev != (dev_t)arg)
+ continue;
+ break;
+ }
+ if (proc.p_comm[0] != 0)
+ strlcpy(kp->ki_comm, proc.p_comm, MAXCOMLEN);
+ (void)kvm_read(kd, (u_long)proc.p_sysent, (char *)&sysent,
+ sizeof(sysent));
+ (void)kvm_read(kd, (u_long)sysent.sv_name, (char *)&svname,
+ sizeof(svname));
+ if (svname[0] != 0)
+ strlcpy(kp->ki_emul, svname, KI_EMULNAMELEN);
+ if ((proc.p_state != PRS_ZOMBIE) &&
+ (mtd.td_blocked != 0)) {
+ kp->ki_kiflag |= KI_LOCKBLOCK;
+ if (mtd.td_lockname)
+ (void)kvm_read(kd,
+ (u_long)mtd.td_lockname,
+ kp->ki_lockname, LOCKNAMELEN);
+ kp->ki_lockname[LOCKNAMELEN] = 0;
+ }
+ bintime2timeval(&proc.p_rux.rux_runtime, &tv);
+ kp->ki_runtime = (u_int64_t)tv.tv_sec * 1000000 + tv.tv_usec;
+ kp->ki_pid = proc.p_pid;
+ kp->ki_siglist = proc.p_siglist;
+ SIGSETOR(kp->ki_siglist, mtd.td_siglist);
+ kp->ki_sigmask = mtd.td_sigmask;
+ kp->ki_xstat = proc.p_xstat;
+ kp->ki_acflag = proc.p_acflag;
+ kp->ki_lock = proc.p_lock;
+ if (proc.p_state != PRS_ZOMBIE) {
+ kp->ki_swtime = proc.p_swtime;
+ kp->ki_flag = proc.p_flag;
+ kp->ki_sflag = proc.p_sflag;
+ kp->ki_nice = proc.p_nice;
+ kp->ki_traceflag = proc.p_traceflag;
+ if (proc.p_state == PRS_NORMAL) {
+ if (TD_ON_RUNQ(&mtd) ||
+ TD_CAN_RUN(&mtd) ||
+ TD_IS_RUNNING(&mtd)) {
+ kp->ki_stat = SRUN;
+ } else if (mtd.td_state ==
+ TDS_INHIBITED) {
+ if (P_SHOULDSTOP(&proc)) {
+ kp->ki_stat = SSTOP;
+ } else if (
+ TD_IS_SLEEPING(&mtd)) {
+ kp->ki_stat = SSLEEP;
+ } else if (TD_ON_LOCK(&mtd)) {
+ kp->ki_stat = SLOCK;
+ } else {
+ kp->ki_stat = SWAIT;
+ }
+ }
+ } else {
+ kp->ki_stat = SIDL;
+ }
+ /* Stuff from the thread */
+ kp->ki_pri.pri_level = mtd.td_priority;
+ kp->ki_pri.pri_native = mtd.td_base_pri;
+ kp->ki_lastcpu = mtd.td_lastcpu;
+ kp->ki_wchan = mtd.td_wchan;
+ kp->ki_oncpu = mtd.td_oncpu;
+
+ if (!(proc.p_flag & P_SA)) {
+ /* stuff from the ksegrp */
+ kp->ki_slptime = mkg.kg_slptime;
+ kp->ki_pri.pri_class = mkg.kg_pri_class;
+ kp->ki_pri.pri_user = mkg.kg_user_pri;
+ kp->ki_estcpu = mkg.kg_estcpu;
+
+#if 0
+ /* Stuff from the kse */
+ kp->ki_pctcpu = mke.ke_pctcpu;
+ kp->ki_rqindex = mke.ke_rqindex;
+#else
+ kp->ki_pctcpu = 0;
+ kp->ki_rqindex = 0;
+#endif
+ } else {
+ kp->ki_tdflags = -1;
+ /* All the rest are 0 for now */
+ }
+ } else {
+ kp->ki_stat = SZOMB;
+ }
+ bcopy(&kinfo_proc, bp, sizeof(kinfo_proc));
+ ++bp;
+ ++cnt;
+ }
+ return (cnt);
+}
+
+/*
+ * Build proc info array by reading in proc list from a crash dump.
+ * Return number of procs read. maxcnt is the max we will read.
+ */
+static int
+kvm_deadprocs(kd, what, arg, a_allproc, a_zombproc, maxcnt)
+ kvm_t *kd;
+ int what, arg;
+ u_long a_allproc;
+ u_long a_zombproc;
+ int maxcnt;
+{
+ struct kinfo_proc *bp = kd->procbase;
+ int acnt, zcnt;
+ struct proc *p;
+
+ if (KREAD(kd, a_allproc, &p)) {
+ _kvm_err(kd, kd->program, "cannot read allproc");
+ return (-1);
+ }
+ acnt = kvm_proclist(kd, what, arg, p, bp, maxcnt);
+ if (acnt < 0)
+ return (acnt);
+
+ if (KREAD(kd, a_zombproc, &p)) {
+ _kvm_err(kd, kd->program, "cannot read zombproc");
+ return (-1);
+ }
+ zcnt = kvm_proclist(kd, what, arg, p, bp + acnt, maxcnt - acnt);
+ if (zcnt < 0)
+ zcnt = 0;
+
+ return (acnt + zcnt);
+}
+
+struct kinfo_proc *
+kvm_getprocs(kd, op, arg, cnt)
+ kvm_t *kd;
+ int op, arg;
+ int *cnt;
+{
+ int mib[4], st, nprocs;
+ size_t size;
+ int temp_op;
+
+ if (kd->procbase != 0) {
+ free((void *)kd->procbase);
+ /*
+ * Clear this pointer in case this call fails. Otherwise,
+ * kvm_close() will free it again.
+ */
+ kd->procbase = 0;
+ }
+ if (ISALIVE(kd)) {
+ size = 0;
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = op;
+ mib[3] = arg;
+ temp_op = op & ~KERN_PROC_INC_THREAD;
+ st = sysctl(mib,
+ temp_op == KERN_PROC_ALL || temp_op == KERN_PROC_PROC ?
+ 3 : 4, NULL, &size, NULL, 0);
+ if (st == -1) {
+ _kvm_syserr(kd, kd->program, "kvm_getprocs");
+ return (0);
+ }
+ /*
+ * We can't continue with a size of 0 because we pass
+ * it to realloc() (via _kvm_realloc()), and passing 0
+ * to realloc() results in undefined behavior.
+ */
+ if (size == 0) {
+ /*
+ * XXX: We should probably return an invalid,
+ * but non-NULL, pointer here so any client
+ * program trying to dereference it will
+ * crash. However, _kvm_freeprocs() calls
+ * free() on kd->procbase if it isn't NULL,
+ * and free()'ing a junk pointer isn't good.
+ * Then again, _kvm_freeprocs() isn't used
+ * anywhere . . .
+ */
+ kd->procbase = _kvm_malloc(kd, 1);
+ goto liveout;
+ }
+ do {
+ size += size / 10;
+ kd->procbase = (struct kinfo_proc *)
+ _kvm_realloc(kd, kd->procbase, size);
+ if (kd->procbase == 0)
+ return (0);
+ st = sysctl(mib, temp_op == KERN_PROC_ALL ||
+ temp_op == KERN_PROC_PROC ? 3 : 4,
+ kd->procbase, &size, NULL, 0);
+ } while (st == -1 && errno == ENOMEM);
+ if (st == -1) {
+ _kvm_syserr(kd, kd->program, "kvm_getprocs");
+ return (0);
+ }
+ /*
+ * We have to check the size again because sysctl()
+ * may "round up" oldlenp if oldp is NULL; hence it
+ * might've told us that there was data to get when
+ * there really isn't any.
+ */
+ if (size > 0 &&
+ kd->procbase->ki_structsize != sizeof(struct kinfo_proc)) {
+ _kvm_err(kd, kd->program,
+ "kinfo_proc size mismatch (expected %d, got %d)",
+ sizeof(struct kinfo_proc),
+ kd->procbase->ki_structsize);
+ return (0);
+ }
+liveout:
+ nprocs = size == 0 ? 0 : size / kd->procbase->ki_structsize;
+ } else {
+ struct nlist nl[4], *p;
+
+ nl[0].n_name = "_nprocs";
+ nl[1].n_name = "_allproc";
+ nl[2].n_name = "_zombproc";
+ nl[3].n_name = 0;
+
+ if (kvm_nlist(kd, nl) != 0) {
+ for (p = nl; p->n_type != 0; ++p)
+ ;
+ _kvm_err(kd, kd->program,
+ "%s: no such symbol", p->n_name);
+ return (0);
+ }
+ if (KREAD(kd, nl[0].n_value, &nprocs)) {
+ _kvm_err(kd, kd->program, "can't read nprocs");
+ return (0);
+ }
+ size = nprocs * sizeof(struct kinfo_proc);
+ kd->procbase = (struct kinfo_proc *)_kvm_malloc(kd, size);
+ if (kd->procbase == 0)
+ return (0);
+
+ nprocs = kvm_deadprocs(kd, op, arg, nl[1].n_value,
+ nl[2].n_value, nprocs);
+#ifdef notdef
+ size = nprocs * sizeof(struct kinfo_proc);
+ (void)realloc(kd->procbase, size);
+#endif
+ }
+ *cnt = nprocs;
+ return (kd->procbase);
+}
+
+void
+_kvm_freeprocs(kd)
+ kvm_t *kd;
+{
+ if (kd->procbase) {
+ free(kd->procbase);
+ kd->procbase = 0;
+ }
+}
+
+void *
+_kvm_realloc(kd, p, n)
+ kvm_t *kd;
+ void *p;
+ size_t n;
+{
+ void *np = (void *)realloc(p, n);
+
+ if (np == 0) {
+ free(p);
+ _kvm_err(kd, kd->program, "out of memory");
+ }
+ return (np);
+}
+
+#ifndef MAX
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
+/*
+ * Read in an argument vector from the user address space of process kp.
+ * addr if the user-space base address of narg null-terminated contiguous
+ * strings. This is used to read in both the command arguments and
+ * environment strings. Read at most maxcnt characters of strings.
+ */
+static char **
+kvm_argv(kd, kp, addr, narg, maxcnt)
+ kvm_t *kd;
+ struct kinfo_proc *kp;
+ u_long addr;
+ int narg;
+ int maxcnt;
+{
+ char *np, *cp, *ep, *ap;
+ u_long oaddr = -1;
+ int len, cc;
+ char **argv;
+
+ /*
+ * Check that there aren't an unreasonable number of agruments,
+ * and that the address is in user space.
+ */
+ if (narg > 512 || addr < VM_MIN_ADDRESS || addr >= VM_MAXUSER_ADDRESS)
+ return (0);
+
+ /*
+ * kd->argv : work space for fetching the strings from the target
+ * process's space, and is converted for returning to caller
+ */
+ if (kd->argv == 0) {
+ /*
+ * Try to avoid reallocs.
+ */
+ kd->argc = MAX(narg + 1, 32);
+ kd->argv = (char **)_kvm_malloc(kd, kd->argc *
+ sizeof(*kd->argv));
+ if (kd->argv == 0)
+ return (0);
+ } else if (narg + 1 > kd->argc) {
+ kd->argc = MAX(2 * kd->argc, narg + 1);
+ kd->argv = (char **)_kvm_realloc(kd, kd->argv, kd->argc *
+ sizeof(*kd->argv));
+ if (kd->argv == 0)
+ return (0);
+ }
+ /*
+ * kd->argspc : returned to user, this is where the kd->argv
+ * arrays are left pointing to the collected strings.
+ */
+ if (kd->argspc == 0) {
+ kd->argspc = (char *)_kvm_malloc(kd, PAGE_SIZE);
+ if (kd->argspc == 0)
+ return (0);
+ kd->arglen = PAGE_SIZE;
+ }
+ /*
+ * kd->argbuf : used to pull in pages from the target process.
+ * the strings are copied out of here.
+ */
+ if (kd->argbuf == 0) {
+ kd->argbuf = (char *)_kvm_malloc(kd, PAGE_SIZE);
+ if (kd->argbuf == 0)
+ return (0);
+ }
+
+ /* Pull in the target process'es argv vector */
+ cc = sizeof(char *) * narg;
+ if (kvm_uread(kd, kp, addr, (char *)kd->argv, cc) != cc)
+ return (0);
+ /*
+ * ap : saved start address of string we're working on in kd->argspc
+ * np : pointer to next place to write in kd->argspc
+ * len: length of data in kd->argspc
+ * argv: pointer to the argv vector that we are hunting around the
+ * target process space for, and converting to addresses in
+ * our address space (kd->argspc).
+ */
+ ap = np = kd->argspc;
+ argv = kd->argv;
+ len = 0;
+ /*
+ * Loop over pages, filling in the argument vector.
+ * Note that the argv strings could be pointing *anywhere* in
+ * the user address space and are no longer contiguous.
+ * Note that *argv is modified when we are going to fetch a string
+ * that crosses a page boundary. We copy the next part of the string
+ * into to "np" and eventually convert the pointer.
+ */
+ while (argv < kd->argv + narg && *argv != 0) {
+
+ /* get the address that the current argv string is on */
+ addr = (u_long)*argv & ~(PAGE_SIZE - 1);
+
+ /* is it the same page as the last one? */
+ if (addr != oaddr) {
+ if (kvm_uread(kd, kp, addr, kd->argbuf, PAGE_SIZE) !=
+ PAGE_SIZE)
+ return (0);
+ oaddr = addr;
+ }
+
+ /* offset within the page... kd->argbuf */
+ addr = (u_long)*argv & (PAGE_SIZE - 1);
+
+ /* cp = start of string, cc = count of chars in this chunk */
+ cp = kd->argbuf + addr;
+ cc = PAGE_SIZE - addr;
+
+ /* dont get more than asked for by user process */
+ if (maxcnt > 0 && cc > maxcnt - len)
+ cc = maxcnt - len;
+
+ /* pointer to end of string if we found it in this page */
+ ep = memchr(cp, '\0', cc);
+ if (ep != 0)
+ cc = ep - cp + 1;
+ /*
+ * at this point, cc is the count of the chars that we are
+ * going to retrieve this time. we may or may not have found
+ * the end of it. (ep points to the null if the end is known)
+ */
+
+ /* will we exceed the malloc/realloced buffer? */
+ if (len + cc > kd->arglen) {
+ int off;
+ char **pp;
+ char *op = kd->argspc;
+
+ kd->arglen *= 2;
+ kd->argspc = (char *)_kvm_realloc(kd, kd->argspc,
+ kd->arglen);
+ if (kd->argspc == 0)
+ return (0);
+ /*
+ * Adjust argv pointers in case realloc moved
+ * the string space.
+ */
+ off = kd->argspc - op;
+ for (pp = kd->argv; pp < argv; pp++)
+ *pp += off;
+ ap += off;
+ np += off;
+ }
+ /* np = where to put the next part of the string in kd->argspc*/
+ /* np is kinda redundant.. could use "kd->argspc + len" */
+ memcpy(np, cp, cc);
+ np += cc; /* inc counters */
+ len += cc;
+
+ /*
+ * if end of string found, set the *argv pointer to the
+ * saved beginning of string, and advance. argv points to
+ * somewhere in kd->argv.. This is initially relative
+ * to the target process, but when we close it off, we set
+ * it to point in our address space.
+ */
+ if (ep != 0) {
+ *argv++ = ap;
+ ap = np;
+ } else {
+ /* update the address relative to the target process */
+ *argv += cc;
+ }
+
+ if (maxcnt > 0 && len >= maxcnt) {
+ /*
+ * We're stopping prematurely. Terminate the
+ * current string.
+ */
+ if (ep == 0) {
+ *np = '\0';
+ *argv++ = ap;
+ }
+ break;
+ }
+ }
+ /* Make sure argv is terminated. */
+ *argv = 0;
+ return (kd->argv);
+}
+
+static void
+ps_str_a(p, addr, n)
+ struct ps_strings *p;
+ u_long *addr;
+ int *n;
+{
+ *addr = (u_long)p->ps_argvstr;
+ *n = p->ps_nargvstr;
+}
+
+static void
+ps_str_e(p, addr, n)
+ struct ps_strings *p;
+ u_long *addr;
+ int *n;
+{
+ *addr = (u_long)p->ps_envstr;
+ *n = p->ps_nenvstr;
+}
+
+/*
+ * Determine if the proc indicated by p is still active.
+ * This test is not 100% foolproof in theory, but chances of
+ * being wrong are very low.
+ */
+static int
+proc_verify(curkp)
+ struct kinfo_proc *curkp;
+{
+ struct kinfo_proc newkp;
+ int mib[4];
+ size_t len;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_PID;
+ mib[3] = curkp->ki_pid;
+ len = sizeof(newkp);
+ if (sysctl(mib, 4, &newkp, &len, NULL, 0) == -1)
+ return (0);
+ return (curkp->ki_pid == newkp.ki_pid &&
+ (newkp.ki_stat != SZOMB || curkp->ki_stat == SZOMB));
+}
+
+static char **
+kvm_doargv(kd, kp, nchr, info)
+ kvm_t *kd;
+ struct kinfo_proc *kp;
+ int nchr;
+ void (*info)(struct ps_strings *, u_long *, int *);
+{
+ char **ap;
+ u_long addr;
+ int cnt;
+ static struct ps_strings arginfo;
+ static u_long ps_strings;
+ size_t len;
+
+ if (ps_strings == 0) {
+ len = sizeof(ps_strings);
+ if (sysctlbyname("kern.ps_strings", &ps_strings, &len, NULL,
+ 0) == -1)
+ ps_strings = PS_STRINGS;
+ }
+
+ /*
+ * Pointers are stored at the top of the user stack.
+ */
+ if (kp->ki_stat == SZOMB ||
+ kvm_uread(kd, kp, ps_strings, (char *)&arginfo,
+ sizeof(arginfo)) != sizeof(arginfo))
+ return (0);
+
+ (*info)(&arginfo, &addr, &cnt);
+ if (cnt == 0)
+ return (0);
+ ap = kvm_argv(kd, kp, addr, cnt, nchr);
+ /*
+ * For live kernels, make sure this process didn't go away.
+ */
+ if (ap != 0 && ISALIVE(kd) && !proc_verify(kp))
+ ap = 0;
+ return (ap);
+}
+
+/*
+ * Get the command args. This code is now machine independent.
+ */
+char **
+kvm_getargv(kd, kp, nchr)
+ kvm_t *kd;
+ const struct kinfo_proc *kp;
+ int nchr;
+{
+ int oid[4];
+ int i;
+ size_t bufsz;
+ static unsigned long buflen;
+ static char *buf, *p;
+ static char **bufp;
+ static int argc;
+
+ if (!ISALIVE(kd)) {
+ _kvm_err(kd, kd->program,
+ "cannot read user space from dead kernel");
+ return (0);
+ }
+
+ if (!buflen) {
+ bufsz = sizeof(buflen);
+ i = sysctlbyname("kern.ps_arg_cache_limit",
+ &buflen, &bufsz, NULL, 0);
+ if (i == -1) {
+ buflen = 0;
+ } else {
+ buf = malloc(buflen);
+ if (buf == NULL)
+ buflen = 0;
+ argc = 32;
+ bufp = malloc(sizeof(char *) * argc);
+ }
+ }
+ if (buf != NULL) {
+ oid[0] = CTL_KERN;
+ oid[1] = KERN_PROC;
+ oid[2] = KERN_PROC_ARGS;
+ oid[3] = kp->ki_pid;
+ bufsz = buflen;
+ i = sysctl(oid, 4, buf, &bufsz, 0, 0);
+ if (i == 0 && bufsz > 0) {
+ i = 0;
+ p = buf;
+ do {
+ bufp[i++] = p;
+ p += strlen(p) + 1;
+ if (i >= argc) {
+ argc += argc;
+ bufp = realloc(bufp,
+ sizeof(char *) * argc);
+ }
+ } while (p < buf + bufsz);
+ bufp[i++] = 0;
+ return (bufp);
+ }
+ }
+ if (kp->ki_flag & P_SYSTEM)
+ return (NULL);
+ return (kvm_doargv(kd, kp, nchr, ps_str_a));
+}
+
+char **
+kvm_getenvv(kd, kp, nchr)
+ kvm_t *kd;
+ const struct kinfo_proc *kp;
+ int nchr;
+{
+ return (kvm_doargv(kd, kp, nchr, ps_str_e));
+}
+
+/*
+ * Read from user space. The user context is given by p.
+ */
+ssize_t
+kvm_uread(kd, kp, uva, buf, len)
+ kvm_t *kd;
+ struct kinfo_proc *kp;
+ u_long uva;
+ char *buf;
+ size_t len;
+{
+ char *cp;
+ char procfile[MAXPATHLEN];
+ ssize_t amount;
+ int fd;
+
+ if (!ISALIVE(kd)) {
+ _kvm_err(kd, kd->program,
+ "cannot read user space from dead kernel");
+ return (0);
+ }
+
+ sprintf(procfile, "/proc/%d/mem", kp->ki_pid);
+ fd = open(procfile, O_RDONLY, 0);
+ if (fd < 0) {
+ _kvm_err(kd, kd->program, "cannot open %s", procfile);
+ return (0);
+ }
+
+ cp = buf;
+ while (len > 0) {
+ errno = 0;
+ if (lseek(fd, (off_t)uva, 0) == -1 && errno != 0) {
+ _kvm_err(kd, kd->program, "invalid address (%x) in %s",
+ uva, procfile);
+ break;
+ }
+ amount = read(fd, cp, len);
+ if (amount < 0) {
+ _kvm_syserr(kd, kd->program, "error reading %s",
+ procfile);
+ break;
+ }
+ if (amount == 0) {
+ _kvm_err(kd, kd->program, "EOF reading %s", procfile);
+ break;
+ }
+ cp += amount;
+ uva += amount;
+ len -= amount;
+ }
+
+ close(fd);
+ return ((ssize_t)(cp - buf));
+}
diff --git a/lib/libkvm/kvm_read.3 b/lib/libkvm/kvm_read.3
new file mode 100644
index 0000000..a2a2485
--- /dev/null
+++ b/lib/libkvm/kvm_read.3
@@ -0,0 +1,96 @@
+.\" Copyright (c) 1992, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software 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.
+.\" 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.
+.\"
+.\" @(#)kvm_read.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt KVM_READ 3
+.Os
+.Sh NAME
+.Nm kvm_read ,
+.Nm kvm_write
+.Nd read or write kernel virtual memory
+.Sh LIBRARY
+.Lb libkvm
+.Sh SYNOPSIS
+.In kvm.h
+.Ft ssize_t
+.Fn kvm_read "kvm_t *kd" "unsigned long addr" "void *buf" "size_t nbytes"
+.Ft ssize_t
+.Fn kvm_write "kvm_t *kd" "unsigned long addr" "const void *buf" "size_t nbytes"
+.Sh DESCRIPTION
+The
+.Fn kvm_read
+and
+.Fn kvm_write
+functions are used to read and write kernel virtual memory (or a crash
+dump file).
+See
+.Fn kvm_open 3
+or
+.Fn kvm_openfiles 3
+for information regarding opening kernel virtual memory and crash dumps.
+.Pp
+The
+.Fn kvm_read
+function transfers
+.Fa nbytes
+bytes of data from
+the kernel space address
+.Fa addr
+to
+.Fa buf .
+Conversely,
+.Fn kvm_write
+transfers data from
+.Fa buf
+to
+.Fa addr .
+Unlike their SunOS counterparts, these functions cannot be used to
+read or write process address spaces.
+.Sh RETURN VALUES
+Upon success, the number of bytes actually transferred is returned.
+Otherwise, -1 is returned.
+.Sh SEE ALSO
+.Xr kvm 3 ,
+.Xr kvm_close 3 ,
+.Xr kvm_getargv 3 ,
+.Xr kvm_getenvv 3 ,
+.Xr kvm_geterr 3 ,
+.Xr kvm_getprocs 3 ,
+.Xr kvm_nlist 3 ,
+.Xr kvm_open 3 ,
+.Xr kvm_openfiles 3
diff --git a/lib/libkvm/kvm_sparc.c b/lib/libkvm/kvm_sparc.c
new file mode 100644
index 0000000..57b881d
--- /dev/null
+++ b/lib/libkvm/kvm_sparc.c
@@ -0,0 +1,240 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software 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.
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)kvm_sparc.c 8.1 (Berkeley) 6/4/93";
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * Sparc machine dependent routines for kvm. Hopefully, the forthcoming
+ * vm code will one day obsolete this module.
+ */
+
+#include <sys/param.h>
+#include <sys/user.h>
+#include <sys/proc.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <nlist.h>
+#include <kvm.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+
+#include <limits.h>
+
+#include "kvm_private.h"
+
+#define NPMEG 128
+
+/* XXX from sparc/pmap.c */
+#define MAXMEM (128 * 1024 * 1024) /* no more than 128 MB phys mem */
+#define NPGBANK 16 /* 2^4 pages per bank (64K / bank) */
+#define BSHIFT 4 /* log2(NPGBANK) */
+#define BOFFSET (NPGBANK - 1)
+#define BTSIZE (MAXMEM / NBPG / NPGBANK)
+#define HWTOSW(pmap_stod, pg) (pmap_stod[(pg) >> BSHIFT] | ((pg) & BOFFSET))
+
+struct vmstate {
+ pmeg_t segmap[NKSEG];
+ int pmeg[NPMEG][NPTESG];
+ int pmap_stod[BTSIZE]; /* dense to sparse */
+};
+
+void
+_kvm_freevtop(kd)
+ kvm_t *kd;
+{
+ if (kd->vmst != 0)
+ free(kd->vmst);
+}
+
+int
+_kvm_initvtop(kd)
+ kvm_t *kd;
+{
+ int i;
+ int off;
+ struct vmstate *vm;
+ struct stat st;
+ struct nlist nlist[2];
+
+ vm = (struct vmstate *)_kvm_malloc(kd, sizeof(*vm));
+ if (vm == 0)
+ return (-1);
+
+ kd->vmst = vm;
+
+ if (fstat(kd->pmfd, &st) < 0)
+ return (-1);
+ /*
+ * Read segment table.
+ */
+ off = st.st_size - ctob(btoc(sizeof(vm->segmap)));
+ errno = 0;
+ if (lseek(kd->pmfd, (off_t)off, 0) == -1 && errno != 0 ||
+ read(kd->pmfd, (char *)vm->segmap, sizeof(vm->segmap)) < 0) {
+ _kvm_err(kd, kd->program, "cannot read segment map");
+ return (-1);
+ }
+ /*
+ * Read PMEGs.
+ */
+ off = st.st_size - ctob(btoc(sizeof(vm->pmeg)) +
+ btoc(sizeof(vm->segmap)));
+ errno = 0;
+ if (lseek(kd->pmfd, (off_t)off, 0) == -1 && errno != 0 ||
+ read(kd->pmfd, (char *)vm->pmeg, sizeof(vm->pmeg)) < 0) {
+ _kvm_err(kd, kd->program, "cannot read PMEG table");
+ return (-1);
+ }
+ /*
+ * Make pmap_stod be an identity map so we can bootstrap it in.
+ * We assume it's in the first contiguous chunk of physical memory.
+ */
+ for (i = 0; i < BTSIZE; ++i)
+ vm->pmap_stod[i] = i << 4;
+
+ /*
+ * It's okay to do this nlist separately from the one kvm_getprocs()
+ * does, since the only time we could gain anything by combining
+ * them is if we do a kvm_getprocs() on a dead kernel, which is
+ * not too common.
+ */
+ nlist[0].n_name = "_pmap_stod";
+ nlist[1].n_name = 0;
+ if (kvm_nlist(kd, nlist) != 0) {
+ _kvm_err(kd, kd->program, "pmap_stod: no such symbol");
+ return (-1);
+ }
+ if (kvm_read(kd, (u_long)nlist[0].n_value,
+ (char *)vm->pmap_stod, sizeof(vm->pmap_stod))
+ != sizeof(vm->pmap_stod)) {
+ _kvm_err(kd, kd->program, "cannot read pmap_stod");
+ return (-1);
+ }
+ return (0);
+}
+
+#define VA_OFF(va) (va & (NBPG - 1))
+
+/*
+ * Translate a user virtual address to a physical address.
+ */
+int
+_kvm_uvatop(kd, p, va, pa)
+ kvm_t *kd;
+ const struct proc *p;
+ u_long va;
+ u_long *pa;
+{
+ int kva, pte;
+ int off, frame;
+ struct vmspace *vms = p->p_vmspace;
+
+ if ((u_long)vms < KERNBASE) {
+ _kvm_err(kd, kd->program, "_kvm_uvatop: corrupt proc");
+ return (0);
+ }
+ if (va >= KERNBASE)
+ return (0);
+ /*
+ * Get the PTE. This takes two steps. We read the
+ * base address of the table, then we index it.
+ * Note that the index pte table is indexed by
+ * virtual segment rather than physical segment.
+ */
+ kva = (u_long)&vms->vm_pmap.pm_rpte[VA_VSEG(va)];
+ if (kvm_read(kd, kva, (char *)&kva, 4) != 4 || kva == 0)
+ goto invalid;
+ kva += sizeof(vms->vm_pmap.pm_rpte[0]) * VA_VPG(va);
+ if (kvm_read(kd, kva, (char *)&pte, 4) == 4 && (pte & PG_V)) {
+ off = VA_OFF(va);
+ /*
+ * /dev/mem adheres to the hardware model of physical memory
+ * (with holes in the address space), while crashdumps
+ * adhere to the contiguous software model.
+ */
+ if (ISALIVE(kd))
+ frame = pte & PG_PFNUM;
+ else
+ frame = HWTOSW(kd->vmst->pmap_stod, pte & PG_PFNUM);
+ *pa = (frame << PGSHIFT) | off;
+ return (NBPG - off);
+ }
+invalid:
+ _kvm_err(kd, 0, "invalid address (%x)", va);
+ return (0);
+}
+
+/*
+ * Translate a kernel virtual address to a physical address using the
+ * mapping information in kd->vm. Returns the result in pa, and returns
+ * the number of bytes that are contiguously available from this
+ * physical address. This routine is used only for crashdumps.
+ */
+int
+_kvm_kvatop(kd, va, pa)
+ kvm_t *kd;
+ u_long va;
+ uint64_t *pa;
+{
+ struct vmstate *vm;
+ int s;
+ int pte;
+ int off;
+
+ if (va >= KERNBASE) {
+ vm = kd->vmst;
+ s = vm->segmap[VA_VSEG(va) - NUSEG];
+ pte = vm->pmeg[s][VA_VPG(va)];
+ if ((pte & PG_V) != 0) {
+ off = VA_OFF(va);
+ *pa = (HWTOSW(vm->pmap_stod, pte & PG_PFNUM)
+ << PGSHIFT) | off;
+
+ return (NBPG - off);
+ }
+ }
+ _kvm_err(kd, 0, "invalid address (%x)", va);
+ return (0);
+}
diff --git a/lib/libkvm/kvm_sparc64.c b/lib/libkvm/kvm_sparc64.c
new file mode 100644
index 0000000..6e0cd37
--- /dev/null
+++ b/lib/libkvm/kvm_sparc64.c
@@ -0,0 +1,225 @@
+/*-
+ * Copyright (c) 1989, 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software 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.
+ * 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.
+ *
+ * from: FreeBSD: src/lib/libkvm/kvm_i386.c,v 1.15 2001/10/10 17:48:43
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)kvm_hp300.c 8.1 (Berkeley) 6/4/93";
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * sparc64 machine dependent routines for kvm.
+ */
+
+#include <sys/param.h>
+#include <sys/user.h>
+#include <sys/proc.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <nlist.h>
+#include <kvm.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+
+#include <machine/kerneldump.h>
+#include <machine/tte.h>
+#include <machine/tlb.h>
+#include <machine/tsb.h>
+
+#include <limits.h>
+
+#include "kvm_private.h"
+
+#ifndef btop
+#define btop(x) (sparc64_btop(x))
+#define ptob(x) (sparc64_ptob(x))
+#endif
+
+struct vmstate {
+ off_t vm_tsb_off;
+ vm_size_t vm_tsb_mask;
+ int vm_nregions;
+ struct sparc64_dump_reg *vm_regions;
+};
+
+void
+_kvm_freevtop(kvm_t *kd)
+{
+ if (kd->vmst != 0) {
+ free(kd->vmst->vm_regions);
+ free(kd->vmst);
+ }
+}
+
+static int
+_kvm_read_phys(kvm_t *kd, off_t pos, void *buf, size_t size)
+{
+
+ /* XXX This has to be a raw file read, kvm_read is virtual. */
+ if (lseek(kd->pmfd, pos, SEEK_SET) == -1) {
+ _kvm_syserr(kd, kd->program, "_kvm_read_phys: lseek");
+ return (0);
+ }
+ if (read(kd->pmfd, buf, size) != size) {
+ _kvm_syserr(kd, kd->program, "_kvm_read_phys: read");
+ return (0);
+ }
+ return (1);
+}
+
+static int
+_kvm_reg_cmp(const void *a, const void *b)
+{
+ const struct sparc64_dump_reg *ra, *rb;
+
+ ra = a;
+ rb = b;
+ if (ra->dr_pa < rb->dr_pa)
+ return (-1);
+ else if (ra->dr_pa >= rb->dr_pa + rb->dr_size)
+ return (1);
+ else
+ return (0);
+}
+
+#define KVM_OFF_NOTFOUND 0
+
+static off_t
+_kvm_find_off(struct vmstate *vm, vm_offset_t pa, vm_size_t size)
+{
+ struct sparc64_dump_reg *reg, key;
+ vm_offset_t o;
+
+ key.dr_pa = pa;
+ reg = bsearch(&key, vm->vm_regions, vm->vm_nregions,
+ sizeof(*vm->vm_regions), _kvm_reg_cmp);
+ if (reg == NULL)
+ return (KVM_OFF_NOTFOUND);
+ o = pa - reg->dr_pa;
+ if (o + size > reg->dr_size)
+ return (KVM_OFF_NOTFOUND);
+ return (reg->dr_offs + o);
+}
+
+int
+_kvm_initvtop(kvm_t *kd)
+{
+ struct sparc64_dump_hdr hdr;
+ struct sparc64_dump_reg *regs;
+ struct vmstate *vm;
+ size_t regsz;
+ vm_offset_t pa;
+ vm_size_t mask;
+
+ vm = (struct vmstate *)_kvm_malloc(kd, sizeof(*vm));
+ if (vm == NULL) {
+ _kvm_err(kd, kd->program, "cannot allocate vm");
+ return (-1);
+ }
+ kd->vmst = vm;
+
+ if (!_kvm_read_phys(kd, 0, &hdr, sizeof(hdr)))
+ goto fail_vm;
+ pa = hdr.dh_tsb_pa;
+
+ regsz = hdr.dh_nregions * sizeof(*regs);
+ regs = _kvm_malloc(kd, regsz);
+ if (regs == NULL) {
+ _kvm_err(kd, kd->program, "cannot allocate regions");
+ goto fail_vm;
+ }
+ if (!_kvm_read_phys(kd, sizeof(hdr), regs, regsz))
+ goto fail_regs;
+ qsort(regs, hdr.dh_nregions, sizeof(*regs), _kvm_reg_cmp);
+
+ vm->vm_tsb_mask = hdr.dh_tsb_mask;
+ vm->vm_regions = regs;
+ vm->vm_nregions = hdr.dh_nregions;
+ vm->vm_tsb_off = _kvm_find_off(vm, hdr.dh_tsb_pa, hdr.dh_tsb_size);
+ if (vm->vm_tsb_off == KVM_OFF_NOTFOUND) {
+ _kvm_err(kd, kd->program, "tsb not found in dump");
+ goto fail_regs;
+ }
+ return (0);
+
+fail_regs:
+ free(regs);
+fail_vm:
+ free(vm);
+ return (-1);
+}
+
+int
+_kvm_kvatop(kvm_t *kd, u_long va, off_t *pa)
+{
+ struct vmstate *vm;
+ struct tte tte;
+ off_t tte_off, pa_off;
+ u_long pg_off, vpn;
+ int rest;
+
+ pg_off = va & PAGE_MASK;
+ if (va >= VM_MIN_DIRECT_ADDRESS)
+ pa_off = TLB_DIRECT_TO_PHYS(va) & ~PAGE_MASK;
+ else {
+ vpn = btop(va);
+ tte_off = kd->vmst->vm_tsb_off +
+ ((vpn & kd->vmst->vm_tsb_mask) << TTE_SHIFT);
+ if (!_kvm_read_phys(kd, tte_off, &tte, sizeof(tte)))
+ goto invalid;
+ if (!tte_match(&tte, va))
+ goto invalid;
+ pa_off = TTE_GET_PA(&tte);
+ }
+ rest = PAGE_SIZE - pg_off;
+ pa_off = _kvm_find_off(kd->vmst, pa_off, rest);
+ if (pa_off == KVM_OFF_NOTFOUND)
+ goto invalid;
+ *pa = pa_off + pg_off;
+ return (rest);
+
+invalid:
+ _kvm_err(kd, 0, "invalid address (%x)", va);
+ return (0);
+}
diff --git a/lib/libmagic/Makefile b/lib/libmagic/Makefile
new file mode 100644
index 0000000..c04c811
--- /dev/null
+++ b/lib/libmagic/Makefile
@@ -0,0 +1,56 @@
+# $FreeBSD$
+# Copyright (c) David E. O'Brien, 2000-2004
+
+CONTRDIR= ${.CURDIR}/../../contrib/file
+.PATH: ${CONTRDIR}
+
+LIB= magic
+SHLIB_MAJOR= 2
+DPADD= ${LIBZ}
+LDADD= -lz
+MAN= libmagic.3 magic.5
+
+SRCS= apprentice.c apptype.c ascmagic.c compress.c fsmagic.c funcs.c \
+ is_tar.c magic.c print.c readelf.c softmagic.c
+INCS= magic.h
+
+MAGICPATH?= /usr/share/misc
+
+CFLAGS+= -DMAGIC='"${MAGICPATH}/magic"' -DBUILTIN_ELF -DELFCORE -DHAVE_CONFIG_H
+CFLAGS+= -I${.CURDIR} -I${CONTRDIR}
+
+CLEANFILES+= magic magic.mgc magic.mime.mgc
+
+FILES= magic magic.mgc ${CONTRDIR}/magic.mime magic.mime.mgc
+FILESDIR= ${MAGICPATH}
+
+MAGFILES= ${CONTRDIR}/Header\
+ ${CONTRDIR}/Localstuff\
+ ${CONTRDIR}/Magdir/[a-z]*
+
+magic: ${MAGFILES}
+ cat ${.ALLSRC} > ${.TARGET}
+
+magic.mgc: mkmagic magic
+ ./mkmagic magic
+
+magic.mime.mgc: mkmagic magic.mime
+ ./mkmagic ${CONTRDIR}/magic.mime
+
+CLEANFILES+= mkmagic
+build-tools: mkmagic
+mkmagic: apprentice.c funcs.c magic.c print.c
+ ${CC} -DHAVE_CONFIG_H -DCOMPILE_ONLY \
+ -I${.CURDIR} -I${CONTRDIR} -o ${.TARGET} ${.ALLSRC}
+
+FILEVER!= awk '$$1 == "\#define" && $$2 == "VERSION" { print $$3; exit }' \
+ ${.CURDIR}/config.h
+CLEANFILES+= ${MAN}
+.for mp in ${MAN}
+${mp}: ${mp:C/[0-9]/man/}
+ sed -e 's/__FSECTION__/5/g' -e 's/__CSECTION__/1/g' \
+ -e 's/__VERSION__/${FILEVER}/g' \
+ -e 's,__MAGIC__,${MAGICPATH}/magic,g' ${.ALLSRC} > ${.TARGET}
+.endfor
+
+.include <bsd.lib.mk>
diff --git a/lib/libmagic/config.h b/lib/libmagic/config.h
new file mode 100644
index 0000000..1863903
--- /dev/null
+++ b/lib/libmagic/config.h
@@ -0,0 +1,215 @@
+/* $FreeBSD$ */
+
+#include <osreldate.h>
+
+/* config.h. Generated by configure. */
+/* config.h.in. Generated from configure.in by autoheader. */
+/* Autoheader needs me */
+#define PACKAGE "file"
+
+/* Autoheader needs me */
+#define VERSION "4.12"
+
+/* Define if builtin ELF support is enabled. */
+#define BUILTIN_ELF 1
+
+/* Define if ELF core file support is enabled. */
+#define ELFCORE 1
+
+/* Define if the `long long' type works. */
+#define HAVE_LONG_LONG 1
+
+/* Define if we have "tm_zone" in "struct tm". */
+#define HAVE_TM_ZONE 1
+
+/* Define if we have a global "char * []" "tzname" variable. */
+#define HAVE_TZNAME 1
+
+/* Define if we have "tm_isdst" in "struct tm". */
+#define HAVE_TM_ISDST 1
+
+/* Define if we have a global "int" variable "daylight". */
+/* #undef HAVE_DAYLIGHT */
+
+/* Define if we have a mkstemp */
+#define HAVE_MKSTEMP 1
+
+/* Define to `unsigned char' if standard headers don't define. */
+/* #undef uint8_t */
+
+/* Define to `unsigned short' if standard headers don't define. */
+/* #undef uint16_t */
+
+/* Define to `unsigned int' if standard headers don't define. */
+/* #undef uint32_t */
+
+/* Define to `unsigned long long', if available, or `unsigned long', if
+ standard headers don't define. */
+/* #undef uint64_t */
+
+/* Define to `int' if standard headers don't define. */
+/* #undef int32_t */
+
+/* FIXME: These have to be added manually because autoheader doesn't know
+ about AC_CHECK_SIZEOF_INCLUDES. */
+
+/* The number of bytes in a uint8_t. */
+#define SIZEOF_UINT8_T 1
+
+/* The number of bytes in a uint16_t. */
+#define SIZEOF_UINT16_T 2
+
+/* The number of bytes in a uint32_t. */
+#define SIZEOF_UINT32_T 4
+
+/* The number of bytes in a uint64_t. */
+#define SIZEOF_UINT64_T 8
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have the <getopt.h> header file. */
+#define HAVE_GETOPT_H 1
+
+/* Define to 1 if you have the `getopt_long' function. */
+#define HAVE_GETOPT_LONG 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `z' library (-lz). */
+#define HAVE_LIBZ 1
+
+/* Define to 1 if you have the <locale.h> header file. */
+#define HAVE_LOCALE_H 1
+
+/* Define to 1 if you have the `mbrtowc' function. */
+#define HAVE_MBRTOWC 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `mkstemp' function. */
+#define HAVE_MKSTEMP 1
+
+/* Define to 1 if you have the `mmap' function. */
+#define HAVE_MMAP 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#if __FreeBSD_version >= 500019
+#define HAVE_STDINT_H 1
+#endif
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the `strerror' function. */
+#define HAVE_STRERROR 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strtoul' function. */
+#define HAVE_STRTOUL 1
+
+/* Define to 1 if `st_rdev' is member of `struct stat'. */
+#define HAVE_STRUCT_STAT_ST_RDEV 1
+
+/* Define to 1 if your `struct stat' has `st_rdev'. Deprecated, use
+ `HAVE_STRUCT_STAT_ST_RDEV' instead. */
+#define HAVE_ST_RDEV 1
+
+/* Define to 1 if you have the <sys/mman.h> header file. */
+#define HAVE_SYS_MMAN_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/utime.h> header file. */
+/* #undef HAVE_SYS_UTIME_H */
+
+/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
+#define HAVE_SYS_WAIT_H 1
+
+/* HAVE_TM_ZONE */
+#define HAVE_TM_ZONE 1
+
+/* HAVE_TZNAME */
+#define HAVE_TZNAME 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `utime' function. */
+#define HAVE_UTIME 1
+
+/* Define to 1 if you have the `utimes' function. */
+#define HAVE_UTIMES 1
+
+/* Define to 1 if you have the <utime.h> header file. */
+#define HAVE_UTIME_H 1
+
+/* Define to 1 if you have the <wchar.h> header file. */
+#define HAVE_WCHAR_H 1
+
+/* Define to 1 if you have the `wcwidth' function. */
+#define HAVE_WCWIDTH 1
+
+/* Define to 1 if `major', `minor', and `makedev' are declared in <mkdev.h>.
+ */
+/* #undef MAJOR_IN_MKDEV */
+
+/* Define to 1 if `major', `minor', and `makedev' are declared in
+ <sysmacros.h>. */
+/* #undef MAJOR_IN_SYSMACROS */
+
+/* Name of package */
+#define PACKAGE "file"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME ""
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING ""
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION ""
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if your <sys/time.h> declares `struct tm'. */
+/* #undef TM_IN_SYS_TIME */
+
+/* Version number of package */
+#define VERSION "4.12"
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+/* #undef _FILE_OFFSET_BITS */
+
+/* Define for large files, on AIX-style hosts. */
+/* #undef _LARGE_FILES */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to a type if <wchar.h> does not define. */
+/* #undef mbstate_t */
+
+/* Define to `long' if <sys/types.h> does not define. */
+/* #undef off_t */
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+/* #undef size_t */
diff --git a/lib/libmd/Makefile b/lib/libmd/Makefile
new file mode 100644
index 0000000..a98b409
--- /dev/null
+++ b/lib/libmd/Makefile
@@ -0,0 +1,197 @@
+# $FreeBSD$
+
+LIB= md
+SHLIBDIR?= /lib
+SRCS= md2c.c md4c.c md5c.c md2hl.c md4hl.c md5hl.c \
+ rmd160c.c rmd160hl.c \
+ sha0c.c sha0hl.c sha1c.c sha1hl.c \
+ sha256c.c sha256hl.c
+INCS= md2.h md4.h md5.h ripemd.h sha.h sha256.h
+
+MAN+= md2.3 md4.3 md5.3 ripemd.3 sha.3 sha256.3
+MLINKS+=md2.3 MD2Init.3 md2.3 MD2Update.3 md2.3 MD2Final.3
+MLINKS+=md2.3 MD2End.3 md2.3 MD2File.3 md2.3 MD2FileChunk.3
+MLINKS+=md2.3 MD2Data.3
+MLINKS+=md4.3 MD4Init.3 md4.3 MD4Update.3 md4.3 MD4Final.3
+MLINKS+=md4.3 MD4End.3 md4.3 MD4File.3 md4.3 MD4FileChunk.3
+MLINKS+=md4.3 MD4Data.3
+MLINKS+=md5.3 MD5Init.3 md5.3 MD5Update.3 md5.3 MD5Final.3
+MLINKS+=md5.3 MD5End.3 md5.3 MD5File.3 md5.3 MD5FileChunk.3
+MLINKS+=md5.3 MD5Data.3
+MLINKS+=ripemd.3 RIPEMD160_Init.3 ripemd.3 RIPEMD160_Update.3
+MLINKS+=ripemd.3 RIPEMD160_Final.3 ripemd.3 RIPEMD160_Data.3
+MLINKS+=ripemd.3 RIPEMD160_End.3 ripemd.3 RIPEMD160_File.3
+MLINKS+=ripemd.3 RIPEMD160_FileChunk.3
+MLINKS+=sha.3 SHA_Init.3 sha.3 SHA_Update.3 sha.3 SHA_Final.3
+MLINKS+=sha.3 SHA_End.3 sha.3 SHA_File.3 sha.3 SHA_FileChunk.3
+MLINKS+=sha.3 SHA_Data.3
+MLINKS+=sha.3 SHA1_Init.3 sha.3 SHA1_Update.3 sha.3 SHA1_Final.3
+MLINKS+=sha.3 SHA1_End.3 sha.3 SHA1_File.3 sha.3 SHA1_FileChunk.3
+MLINKS+=sha.3 SHA1_Data.3
+MLINKS+=sha256.3 SHA256_Init.3 sha256.3 SHA256_Update.3
+MLINKS+=sha256.3 SHA256_Final.3 sha256.3 SHA256_End.3
+MLINKS+=sha256.3 SHA256_File.3 sha256.3 SHA256_FileChunk.3
+MLINKS+=sha256.3 SHA256_Data.3
+CLEANFILES+= md[245]hl.c md[245].ref md[245].3 mddriver \
+ rmd160.ref rmd160hl.c rmddriver \
+ sha0.ref sha0hl.c sha1.ref sha1hl.c shadriver \
+ sha256.ref sha256hl.c
+CFLAGS+= -I${.CURDIR}
+.PATH: ${.CURDIR}/${MACHINE_ARCH}
+
+.if exists(${MACHINE_ARCH}/sha.S)
+SRCS+= sha.S
+CFLAGS+= -DSHA1_ASM -DELF
+.endif
+.if exists(${MACHINE_ARCH}/rmd160.S)
+SRCS+= rmd160.S
+CFLAGS+= -DRMD160_ASM -DELF
+.endif
+
+md2hl.c: mdXhl.c
+ (echo '#define LENGTH 16'; \
+ sed -e 's/mdX/md2/g' -e 's/MDX/MD2/g' ${.ALLSRC}) > ${.TARGET}
+
+md4hl.c: mdXhl.c
+ (echo '#define LENGTH 16'; \
+ sed -e 's/mdX/md4/g' -e 's/MDX/MD4/g' ${.ALLSRC}) > ${.TARGET}
+
+md5hl.c: mdXhl.c
+ (echo '#define LENGTH 16'; \
+ sed -e 's/mdX/md5/g' -e 's/MDX/MD5/g' ${.ALLSRC}) > ${.TARGET}
+
+sha0hl.c: mdXhl.c
+ (echo '#define LENGTH 20'; \
+ sed -e 's/mdX/sha/g' -e 's/MDX/SHA_/g' -e 's/SHA__/SHA_/g' \
+ ${.ALLSRC}) > ${.TARGET}
+
+sha1hl.c: mdXhl.c
+ (echo '#define LENGTH 20'; \
+ sed -e 's/mdX/sha/g' -e 's/MDX/SHA1_/g' -e 's/SHA1__/SHA1_/g' \
+ ${.ALLSRC}) > ${.TARGET}
+
+sha256hl.c: mdXhl.c
+ (echo '#define LENGTH 32'; \
+ sed -e 's/mdX/sha256/g' -e 's/MDX/SHA256_/g' \
+ -e 's/SHA256__/SHA256_/g' \
+ ${.ALLSRC}) > ${.TARGET}
+
+rmd160hl.c: mdXhl.c
+ (echo '#define LENGTH 20'; \
+ sed -e 's/mdX/ripemd/g' -e 's/MDX/RIPEMD160_/g' \
+ -e 's/RIPEMD160__/RIPEMD160_/g' \
+ ${.ALLSRC}) > ${.TARGET}
+
+.for i in 2 4 5
+md${i}.3: ${.CURDIR}/mdX.3
+ sed -e "s/mdX/md${i}/g" -e "s/MDX/MD${i}/g" ${.ALLSRC} > ${.TARGET}
+ cat ${.CURDIR}/md${i}.copyright >> ${.TARGET}
+.endfor
+
+md2.ref:
+ echo 'MD2 test suite:' > ${.TARGET}
+ @echo 'MD2 ("") = 8350e5a3e24c153df2275c9f80692773' >> ${.TARGET}
+ @echo 'MD2 ("a") = 32ec01ec4a6dac72c0ab96fb34c0b5d1' >> ${.TARGET}
+ @echo 'MD2 ("abc") = da853b0d3f88d99b30283a69e6ded6bb' >> ${.TARGET}
+ @echo 'MD2 ("message digest") = ab4f496bfb2a530b219ff33031fe06b0' >> ${.TARGET}
+ @echo 'MD2 ("abcdefghijklmnopqrstuvwxyz") = 4e8ddff3650292ab5a4108c3aa47940b' >> ${.TARGET}
+ @echo 'MD2 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") = da33def2a42df13975352846c30338cd' >> ${.TARGET}
+ @echo 'MD2 ("12345678901234567890123456789012345678901234567890123456789012345678901234567890") = d5976f79d83d3a0dc9806c3c66f3efd8' >> ${.TARGET}
+
+md4.ref:
+ echo 'MD4 test suite:' > ${.TARGET}
+ @echo 'MD4 ("") = 31d6cfe0d16ae931b73c59d7e0c089c0' >> ${.TARGET}
+ @echo 'MD4 ("a") = bde52cb31de33e46245e05fbdbd6fb24' >> ${.TARGET}
+ @echo 'MD4 ("abc") = a448017aaf21d8525fc10ae87aa6729d' >> ${.TARGET}
+ @echo 'MD4 ("message digest") = d9130a8164549fe818874806e1c7014b' >> ${.TARGET}
+ @echo 'MD4 ("abcdefghijklmnopqrstuvwxyz") = d79e1c308aa5bbcdeea8ed63df412da9' >> ${.TARGET}
+ @echo 'MD4 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") = 043f8582f241db351ce627e153e7f0e4' >> ${.TARGET}
+ @echo 'MD4 ("12345678901234567890123456789012345678901234567890123456789012345678901234567890") = e33b4ddc9c38f2199c3e7b164fcc0536' >> ${.TARGET}
+
+md5.ref:
+ echo 'MD5 test suite:' > ${.TARGET}
+ @echo 'MD5 ("") = d41d8cd98f00b204e9800998ecf8427e' >> ${.TARGET}
+ @echo 'MD5 ("a") = 0cc175b9c0f1b6a831c399e269772661' >> ${.TARGET}
+ @echo 'MD5 ("abc") = 900150983cd24fb0d6963f7d28e17f72' >> ${.TARGET}
+ @echo 'MD5 ("message digest") = f96b697d7cb7938d525a2f31aaf161d0' >> ${.TARGET}
+ @echo 'MD5 ("abcdefghijklmnopqrstuvwxyz") = c3fcd3d76192e4007dfb496cca67e13b' >> ${.TARGET}
+ @echo 'MD5 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") = d174ab98d277d9f5a5611c2c9f419d9f' >> ${.TARGET}
+ @echo 'MD5 ("12345678901234567890123456789012345678901234567890123456789012345678901234567890") = 57edf4a22be3c955ac49da2e2107b67a' >> ${.TARGET}
+
+sha0.ref:
+ (echo 'SHA-0 test suite:'; \
+ echo 'SHA-0 ("") = f96cea198ad1dd5617ac084a3d92c6107708c0ef'; \
+ echo 'SHA-0 ("abc") = 0164b8a914cd2a5e74c4f7ff082c4d97f1edf880'; \
+ echo 'SHA-0 ("message digest") =' \
+ 'c1b0f222d150ebb9aa36a40cafdc8bcbed830b14'; \
+ echo 'SHA-0 ("abcdefghijklmnopqrstuvwxyz") =' \
+ 'b40ce07a430cfd3c033039b9fe9afec95dc1bdcd'; \
+ echo 'SHA-0 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") =' \
+ '79e966f7a3a990df33e40e3d7f8f18d2caebadfa'; \
+ echo 'SHA-0 ("12345678901234567890123456789012345678901234567890123456789012345678901234567890") =' \
+ '4aa29d14d171522ece47bee8957e35a41f3e9cff' ) > ${.TARGET}
+
+sha1.ref:
+ (echo 'SHA-1 test suite:'; \
+ echo 'SHA-1 ("") = da39a3ee5e6b4b0d3255bfef95601890afd80709'; \
+ echo 'SHA-1 ("abc") = a9993e364706816aba3e25717850c26c9cd0d89d'; \
+ echo 'SHA-1 ("message digest") =' \
+ 'c12252ceda8be8994d5fa0290a47231c1d16aae3'; \
+ echo 'SHA-1 ("abcdefghijklmnopqrstuvwxyz") =' \
+ '32d10c7b8cf96570ca04ce37f2a19d84240d3a89'; \
+ echo 'SHA-1 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") =' \
+ '761c457bf73b14d27e9e9265c46f4b4dda11f940'; \
+ echo 'SHA-1 ("12345678901234567890123456789012345678901234567890123456789012345678901234567890") =' \
+ '50abf5706a150990a08b2c5ea40fa0e585554732' ) > ${.TARGET}
+
+sha256.ref:
+ echo 'SHA-256 test suite:' > ${.TARGET}
+ @echo 'SHA-256 ("") = e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855' >> ${.TARGET}
+ @echo 'SHA-256 ("abc") = ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad' >> ${.TARGET}
+ @echo 'SHA-256 ("message digest") = f7846f55cf23e14eebeab5b4e1550cad5b509e3348fbc4efa3a1413d393cb650' >> ${.TARGET}
+ @echo 'SHA-256 ("abcdefghijklmnopqrstuvwxyz") = 71c480df93d6ae2f1efad1447c66c9525e316218cf51fc8d9ed832f2daf18b73' >> ${.TARGET}
+ @echo 'SHA-256 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") = db4bfcbd4da0cd85a60c3c37d3fbd8805c77f15fc6b1fdfe614ee0a7c8fdb4c0' >> ${.TARGET}
+ @echo 'SHA-256 ("12345678901234567890123456789012345678901234567890123456789012345678901234567890") = f371bc4a311f2b009eef952dd83ca80e2b60026c8e935592d0f9c308453c813e' >> ${.TARGET}
+
+rmd160.ref:
+ (echo 'RIPEMD160 test suite:'; \
+ echo 'RIPEMD160 ("") = 9c1185a5c5e9fc54612808977ee8f548b2258d31'; \
+ echo 'RIPEMD160 ("abc") = 8eb208f7e05d987a9b044a8e98c6b087f15a0bfc'; \
+ echo 'RIPEMD160 ("message digest") =' \
+ '5d0689ef49d2fae572b881b123a85ffa21595f36'; \
+ echo 'RIPEMD160 ("abcdefghijklmnopqrstuvwxyz") =' \
+ 'f71c27109c692c1b56bbdceb5b9d2865b3708dbc'; \
+ echo 'RIPEMD160 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") =' \
+ 'b0e20b6e3116640286ed3a87a5713079b21f5189'; \
+ echo 'RIPEMD160 ("12345678901234567890123456789012345678901234567890123456789012345678901234567890") =' \
+ '9b752e45573d4b39f4dbd3323cab82bf63326bfb' ) > ${.TARGET}
+
+test: md2.ref md4.ref md5.ref sha0.ref rmd160.ref sha1.ref sha256.ref
+ @${ECHO} if any of these test fail, the code produces wrong results
+ @${ECHO} and should NOT be used.
+ ${CC} ${CFLAGS} ${LDFLAGS} -DMD=2 -o mddriver ${.CURDIR}/mddriver.c -L. -lmd
+ ./mddriver | cmp md2.ref -
+ @${ECHO} MD2 passed test
+ ${CC} ${CFLAGS} ${LDFLAGS} -DMD=4 -o mddriver ${.CURDIR}/mddriver.c -L. -lmd
+ ./mddriver | cmp md4.ref -
+ @${ECHO} MD4 passed test
+ ${CC} ${CFLAGS} ${LDFLAGS} -DMD=5 -o mddriver ${.CURDIR}/mddriver.c -L. -lmd
+ ./mddriver | cmp md5.ref -
+ @${ECHO} MD5 passed test
+ -rm -f mddriver
+ ${CC} ${CFLAGS} ${LDFLAGS} -o rmddriver ${.CURDIR}/rmddriver.c -L. -lmd
+ ./rmddriver | cmp rmd160.ref -
+ @${ECHO} RIPEMD160 passed test
+ -rm -f rmddriver
+ ${CC} ${CFLAGS} ${LDFLAGS} -DSHA=0 -o shadriver ${.CURDIR}/shadriver.c -L. -lmd
+ ./shadriver | cmp sha0.ref -
+ @${ECHO} SHA-0 passed test
+ ${CC} ${CFLAGS} ${LDFLAGS} -DSHA=1 -o shadriver ${.CURDIR}/shadriver.c -L. -lmd
+ ./shadriver | cmp sha1.ref -
+ @${ECHO} SHA-1 passed test
+ ${CC} ${CFLAGS} ${LDFLAGS} -DSHA=256 -o shadriver ${.CURDIR}/shadriver.c -L. -lmd
+ ./shadriver | cmp sha256.ref -
+ @${ECHO} SHA-256 passed test
+ -rm -f shadriver
+
+.include <bsd.lib.mk>
diff --git a/lib/libmd/i386/rmd160.S b/lib/libmd/i386/rmd160.S
new file mode 100644
index 0000000..97193e9
--- /dev/null
+++ b/lib/libmd/i386/rmd160.S
@@ -0,0 +1,2018 @@
+/* Run the C pre-processor over this file with one of the following defined
+ * ELF - elf object files,
+ * OUT - a.out object files,
+ * BSDI - BSDI style a.out object files
+ * SOL - Solaris style elf
+ */
+
+#ifndef PIC
+#define TYPE(a,b) .type a,b
+#define SIZE(a,b) .size a,b
+
+#if defined(OUT) || defined(BSDI)
+#define ripemd160_block_x86 _ripemd160_block_x86
+
+#endif
+
+#ifdef OUT
+#define OK 1
+#define ALIGN 4
+#endif
+
+#ifdef BSDI
+#define OK 1
+#define ALIGN 4
+#undef SIZE
+#undef TYPE
+#define SIZE(a,b)
+#define TYPE(a,b)
+#endif
+
+#if defined(ELF) || defined(SOL)
+#define OK 1
+#define ALIGN 4
+#endif
+
+#ifndef OK
+You need to define one of
+ELF - elf systems - linux-elf, NetBSD and DG-UX
+OUT - a.out systems - linux-a.out and FreeBSD
+SOL - solaris systems, which are elf with strange comment lines
+BSDI - a.out with a very primative version of as.
+#endif
+
+/* Let the Assembler begin :-) */
+ /* Don't even think of reading this code */
+ /* It was automatically generated by rmd-586.pl */
+ /* Which is a perl program used to generate the x86 assember for */
+ /* any of elf, a.out, BSDI,Win32, or Solaris */
+ /* eric <eay@cryptsoft.com> */
+
+ .file "rmd-586.s"
+ .version "01.01"
+gcc2_compiled.:
+.text
+ .p2align ALIGN
+.globl ripemd160_block_x86
+ TYPE(ripemd160_block_x86,@function)
+ripemd160_block_x86:
+ pushl %esi
+ movl 16(%esp), %ecx
+ pushl %edi
+ movl 16(%esp), %esi
+ pushl %ebp
+ addl %esi, %ecx
+ pushl %ebx
+ subl $64, %ecx
+ subl $88, %esp
+ movl %ecx, (%esp)
+ movl 108(%esp), %edi
+.L000start:
+
+ movl (%esi), %eax
+ movl 4(%esi), %ebx
+ movl %eax, 4(%esp)
+ movl %ebx, 8(%esp)
+ movl 8(%esi), %eax
+ movl 12(%esi), %ebx
+ movl %eax, 12(%esp)
+ movl %ebx, 16(%esp)
+ movl 16(%esi), %eax
+ movl 20(%esi), %ebx
+ movl %eax, 20(%esp)
+ movl %ebx, 24(%esp)
+ movl 24(%esi), %eax
+ movl 28(%esi), %ebx
+ movl %eax, 28(%esp)
+ movl %ebx, 32(%esp)
+ movl 32(%esi), %eax
+ movl 36(%esi), %ebx
+ movl %eax, 36(%esp)
+ movl %ebx, 40(%esp)
+ movl 40(%esi), %eax
+ movl 44(%esi), %ebx
+ movl %eax, 44(%esp)
+ movl %ebx, 48(%esp)
+ movl 48(%esi), %eax
+ movl 52(%esi), %ebx
+ movl %eax, 52(%esp)
+ movl %ebx, 56(%esp)
+ movl 56(%esi), %eax
+ movl 60(%esi), %ebx
+ movl %eax, 60(%esp)
+ movl %ebx, 64(%esp)
+ addl $64, %esi
+ movl (%edi), %eax
+ movl %esi, 112(%esp)
+ movl 4(%edi), %ebx
+ movl 8(%edi), %ecx
+ movl 12(%edi), %edx
+ movl 16(%edi), %ebp
+ /* 0 */
+ movl %ecx, %esi
+ xorl %edx, %esi
+ movl 4(%esp), %edi
+ xorl %ebx, %esi
+ addl %edi, %eax
+ roll $10, %ecx
+ addl %esi, %eax
+ movl %ebx, %esi
+ roll $11, %eax
+ addl %ebp, %eax
+ /* 1 */
+ xorl %ecx, %esi
+ movl 8(%esp), %edi
+ xorl %eax, %esi
+ addl %esi, %ebp
+ movl %eax, %esi
+ roll $10, %ebx
+ addl %edi, %ebp
+ xorl %ebx, %esi
+ roll $14, %ebp
+ addl %edx, %ebp
+ /* 2 */
+ movl 12(%esp), %edi
+ xorl %ebp, %esi
+ addl %edi, %edx
+ roll $10, %eax
+ addl %esi, %edx
+ movl %ebp, %esi
+ roll $15, %edx
+ addl %ecx, %edx
+ /* 3 */
+ xorl %eax, %esi
+ movl 16(%esp), %edi
+ xorl %edx, %esi
+ addl %esi, %ecx
+ movl %edx, %esi
+ roll $10, %ebp
+ addl %edi, %ecx
+ xorl %ebp, %esi
+ roll $12, %ecx
+ addl %ebx, %ecx
+ /* 4 */
+ movl 20(%esp), %edi
+ xorl %ecx, %esi
+ addl %edi, %ebx
+ roll $10, %edx
+ addl %esi, %ebx
+ movl %ecx, %esi
+ roll $5, %ebx
+ addl %eax, %ebx
+ /* 5 */
+ xorl %edx, %esi
+ movl 24(%esp), %edi
+ xorl %ebx, %esi
+ addl %esi, %eax
+ movl %ebx, %esi
+ roll $10, %ecx
+ addl %edi, %eax
+ xorl %ecx, %esi
+ roll $8, %eax
+ addl %ebp, %eax
+ /* 6 */
+ movl 28(%esp), %edi
+ xorl %eax, %esi
+ addl %edi, %ebp
+ roll $10, %ebx
+ addl %esi, %ebp
+ movl %eax, %esi
+ roll $7, %ebp
+ addl %edx, %ebp
+ /* 7 */
+ xorl %ebx, %esi
+ movl 32(%esp), %edi
+ xorl %ebp, %esi
+ addl %esi, %edx
+ movl %ebp, %esi
+ roll $10, %eax
+ addl %edi, %edx
+ xorl %eax, %esi
+ roll $9, %edx
+ addl %ecx, %edx
+ /* 8 */
+ movl 36(%esp), %edi
+ xorl %edx, %esi
+ addl %edi, %ecx
+ roll $10, %ebp
+ addl %esi, %ecx
+ movl %edx, %esi
+ roll $11, %ecx
+ addl %ebx, %ecx
+ /* 9 */
+ xorl %ebp, %esi
+ movl 40(%esp), %edi
+ xorl %ecx, %esi
+ addl %esi, %ebx
+ movl %ecx, %esi
+ roll $10, %edx
+ addl %edi, %ebx
+ xorl %edx, %esi
+ roll $13, %ebx
+ addl %eax, %ebx
+ /* 10 */
+ movl 44(%esp), %edi
+ xorl %ebx, %esi
+ addl %edi, %eax
+ roll $10, %ecx
+ addl %esi, %eax
+ movl %ebx, %esi
+ roll $14, %eax
+ addl %ebp, %eax
+ /* 11 */
+ xorl %ecx, %esi
+ movl 48(%esp), %edi
+ xorl %eax, %esi
+ addl %esi, %ebp
+ movl %eax, %esi
+ roll $10, %ebx
+ addl %edi, %ebp
+ xorl %ebx, %esi
+ roll $15, %ebp
+ addl %edx, %ebp
+ /* 12 */
+ movl 52(%esp), %edi
+ xorl %ebp, %esi
+ addl %edi, %edx
+ roll $10, %eax
+ addl %esi, %edx
+ movl %ebp, %esi
+ roll $6, %edx
+ addl %ecx, %edx
+ /* 13 */
+ xorl %eax, %esi
+ movl 56(%esp), %edi
+ xorl %edx, %esi
+ addl %esi, %ecx
+ movl %edx, %esi
+ roll $10, %ebp
+ addl %edi, %ecx
+ xorl %ebp, %esi
+ roll $7, %ecx
+ addl %ebx, %ecx
+ /* 14 */
+ movl 60(%esp), %edi
+ xorl %ecx, %esi
+ addl %edi, %ebx
+ roll $10, %edx
+ addl %esi, %ebx
+ movl %ecx, %esi
+ roll $9, %ebx
+ addl %eax, %ebx
+ /* 15 */
+ xorl %edx, %esi
+ movl 64(%esp), %edi
+ xorl %ebx, %esi
+ addl %esi, %eax
+ movl $-1, %esi
+ roll $10, %ecx
+ addl %edi, %eax
+ movl 32(%esp), %edi
+ roll $8, %eax
+ addl %ebp, %eax
+ /* 16 */
+ addl %edi, %ebp
+ movl %ebx, %edi
+ subl %eax, %esi
+ andl %eax, %edi
+ andl %ecx, %esi
+ orl %esi, %edi
+ movl 20(%esp), %esi
+ roll $10, %ebx
+ leal 1518500249(%ebp,%edi,1),%ebp
+ movl $-1, %edi
+ roll $7, %ebp
+ addl %edx, %ebp
+ /* 17 */
+ addl %esi, %edx
+ movl %eax, %esi
+ subl %ebp, %edi
+ andl %ebp, %esi
+ andl %ebx, %edi
+ orl %edi, %esi
+ movl 56(%esp), %edi
+ roll $10, %eax
+ leal 1518500249(%edx,%esi,1),%edx
+ movl $-1, %esi
+ roll $6, %edx
+ addl %ecx, %edx
+ /* 18 */
+ addl %edi, %ecx
+ movl %ebp, %edi
+ subl %edx, %esi
+ andl %edx, %edi
+ andl %eax, %esi
+ orl %esi, %edi
+ movl 8(%esp), %esi
+ roll $10, %ebp
+ leal 1518500249(%ecx,%edi,1),%ecx
+ movl $-1, %edi
+ roll $8, %ecx
+ addl %ebx, %ecx
+ /* 19 */
+ addl %esi, %ebx
+ movl %edx, %esi
+ subl %ecx, %edi
+ andl %ecx, %esi
+ andl %ebp, %edi
+ orl %edi, %esi
+ movl 44(%esp), %edi
+ roll $10, %edx
+ leal 1518500249(%ebx,%esi,1),%ebx
+ movl $-1, %esi
+ roll $13, %ebx
+ addl %eax, %ebx
+ /* 20 */
+ addl %edi, %eax
+ movl %ecx, %edi
+ subl %ebx, %esi
+ andl %ebx, %edi
+ andl %edx, %esi
+ orl %esi, %edi
+ movl 28(%esp), %esi
+ roll $10, %ecx
+ leal 1518500249(%eax,%edi,1),%eax
+ movl $-1, %edi
+ roll $11, %eax
+ addl %ebp, %eax
+ /* 21 */
+ addl %esi, %ebp
+ movl %ebx, %esi
+ subl %eax, %edi
+ andl %eax, %esi
+ andl %ecx, %edi
+ orl %edi, %esi
+ movl 64(%esp), %edi
+ roll $10, %ebx
+ leal 1518500249(%ebp,%esi,1),%ebp
+ movl $-1, %esi
+ roll $9, %ebp
+ addl %edx, %ebp
+ /* 22 */
+ addl %edi, %edx
+ movl %eax, %edi
+ subl %ebp, %esi
+ andl %ebp, %edi
+ andl %ebx, %esi
+ orl %esi, %edi
+ movl 16(%esp), %esi
+ roll $10, %eax
+ leal 1518500249(%edx,%edi,1),%edx
+ movl $-1, %edi
+ roll $7, %edx
+ addl %ecx, %edx
+ /* 23 */
+ addl %esi, %ecx
+ movl %ebp, %esi
+ subl %edx, %edi
+ andl %edx, %esi
+ andl %eax, %edi
+ orl %edi, %esi
+ movl 52(%esp), %edi
+ roll $10, %ebp
+ leal 1518500249(%ecx,%esi,1),%ecx
+ movl $-1, %esi
+ roll $15, %ecx
+ addl %ebx, %ecx
+ /* 24 */
+ addl %edi, %ebx
+ movl %edx, %edi
+ subl %ecx, %esi
+ andl %ecx, %edi
+ andl %ebp, %esi
+ orl %esi, %edi
+ movl 4(%esp), %esi
+ roll $10, %edx
+ leal 1518500249(%ebx,%edi,1),%ebx
+ movl $-1, %edi
+ roll $7, %ebx
+ addl %eax, %ebx
+ /* 25 */
+ addl %esi, %eax
+ movl %ecx, %esi
+ subl %ebx, %edi
+ andl %ebx, %esi
+ andl %edx, %edi
+ orl %edi, %esi
+ movl 40(%esp), %edi
+ roll $10, %ecx
+ leal 1518500249(%eax,%esi,1),%eax
+ movl $-1, %esi
+ roll $12, %eax
+ addl %ebp, %eax
+ /* 26 */
+ addl %edi, %ebp
+ movl %ebx, %edi
+ subl %eax, %esi
+ andl %eax, %edi
+ andl %ecx, %esi
+ orl %esi, %edi
+ movl 24(%esp), %esi
+ roll $10, %ebx
+ leal 1518500249(%ebp,%edi,1),%ebp
+ movl $-1, %edi
+ roll $15, %ebp
+ addl %edx, %ebp
+ /* 27 */
+ addl %esi, %edx
+ movl %eax, %esi
+ subl %ebp, %edi
+ andl %ebp, %esi
+ andl %ebx, %edi
+ orl %edi, %esi
+ movl 12(%esp), %edi
+ roll $10, %eax
+ leal 1518500249(%edx,%esi,1),%edx
+ movl $-1, %esi
+ roll $9, %edx
+ addl %ecx, %edx
+ /* 28 */
+ addl %edi, %ecx
+ movl %ebp, %edi
+ subl %edx, %esi
+ andl %edx, %edi
+ andl %eax, %esi
+ orl %esi, %edi
+ movl 60(%esp), %esi
+ roll $10, %ebp
+ leal 1518500249(%ecx,%edi,1),%ecx
+ movl $-1, %edi
+ roll $11, %ecx
+ addl %ebx, %ecx
+ /* 29 */
+ addl %esi, %ebx
+ movl %edx, %esi
+ subl %ecx, %edi
+ andl %ecx, %esi
+ andl %ebp, %edi
+ orl %edi, %esi
+ movl 48(%esp), %edi
+ roll $10, %edx
+ leal 1518500249(%ebx,%esi,1),%ebx
+ movl $-1, %esi
+ roll $7, %ebx
+ addl %eax, %ebx
+ /* 30 */
+ addl %edi, %eax
+ movl %ecx, %edi
+ subl %ebx, %esi
+ andl %ebx, %edi
+ andl %edx, %esi
+ orl %esi, %edi
+ movl 36(%esp), %esi
+ roll $10, %ecx
+ leal 1518500249(%eax,%edi,1),%eax
+ movl $-1, %edi
+ roll $13, %eax
+ addl %ebp, %eax
+ /* 31 */
+ addl %esi, %ebp
+ movl %ebx, %esi
+ subl %eax, %edi
+ andl %eax, %esi
+ andl %ecx, %edi
+ orl %edi, %esi
+ movl $-1, %edi
+ roll $10, %ebx
+ leal 1518500249(%ebp,%esi,1),%ebp
+ subl %eax, %edi
+ roll $12, %ebp
+ addl %edx, %ebp
+ /* 32 */
+ movl 16(%esp), %esi
+ orl %ebp, %edi
+ addl %esi, %edx
+ xorl %ebx, %edi
+ movl $-1, %esi
+ roll $10, %eax
+ leal 1859775393(%edx,%edi,1),%edx
+ subl %ebp, %esi
+ roll $11, %edx
+ addl %ecx, %edx
+ /* 33 */
+ movl 44(%esp), %edi
+ orl %edx, %esi
+ addl %edi, %ecx
+ xorl %eax, %esi
+ movl $-1, %edi
+ roll $10, %ebp
+ leal 1859775393(%ecx,%esi,1),%ecx
+ subl %edx, %edi
+ roll $13, %ecx
+ addl %ebx, %ecx
+ /* 34 */
+ movl 60(%esp), %esi
+ orl %ecx, %edi
+ addl %esi, %ebx
+ xorl %ebp, %edi
+ movl $-1, %esi
+ roll $10, %edx
+ leal 1859775393(%ebx,%edi,1),%ebx
+ subl %ecx, %esi
+ roll $6, %ebx
+ addl %eax, %ebx
+ /* 35 */
+ movl 20(%esp), %edi
+ orl %ebx, %esi
+ addl %edi, %eax
+ xorl %edx, %esi
+ movl $-1, %edi
+ roll $10, %ecx
+ leal 1859775393(%eax,%esi,1),%eax
+ subl %ebx, %edi
+ roll $7, %eax
+ addl %ebp, %eax
+ /* 36 */
+ movl 40(%esp), %esi
+ orl %eax, %edi
+ addl %esi, %ebp
+ xorl %ecx, %edi
+ movl $-1, %esi
+ roll $10, %ebx
+ leal 1859775393(%ebp,%edi,1),%ebp
+ subl %eax, %esi
+ roll $14, %ebp
+ addl %edx, %ebp
+ /* 37 */
+ movl 64(%esp), %edi
+ orl %ebp, %esi
+ addl %edi, %edx
+ xorl %ebx, %esi
+ movl $-1, %edi
+ roll $10, %eax
+ leal 1859775393(%edx,%esi,1),%edx
+ subl %ebp, %edi
+ roll $9, %edx
+ addl %ecx, %edx
+ /* 38 */
+ movl 36(%esp), %esi
+ orl %edx, %edi
+ addl %esi, %ecx
+ xorl %eax, %edi
+ movl $-1, %esi
+ roll $10, %ebp
+ leal 1859775393(%ecx,%edi,1),%ecx
+ subl %edx, %esi
+ roll $13, %ecx
+ addl %ebx, %ecx
+ /* 39 */
+ movl 8(%esp), %edi
+ orl %ecx, %esi
+ addl %edi, %ebx
+ xorl %ebp, %esi
+ movl $-1, %edi
+ roll $10, %edx
+ leal 1859775393(%ebx,%esi,1),%ebx
+ subl %ecx, %edi
+ roll $15, %ebx
+ addl %eax, %ebx
+ /* 40 */
+ movl 12(%esp), %esi
+ orl %ebx, %edi
+ addl %esi, %eax
+ xorl %edx, %edi
+ movl $-1, %esi
+ roll $10, %ecx
+ leal 1859775393(%eax,%edi,1),%eax
+ subl %ebx, %esi
+ roll $14, %eax
+ addl %ebp, %eax
+ /* 41 */
+ movl 32(%esp), %edi
+ orl %eax, %esi
+ addl %edi, %ebp
+ xorl %ecx, %esi
+ movl $-1, %edi
+ roll $10, %ebx
+ leal 1859775393(%ebp,%esi,1),%ebp
+ subl %eax, %edi
+ roll $8, %ebp
+ addl %edx, %ebp
+ /* 42 */
+ movl 4(%esp), %esi
+ orl %ebp, %edi
+ addl %esi, %edx
+ xorl %ebx, %edi
+ movl $-1, %esi
+ roll $10, %eax
+ leal 1859775393(%edx,%edi,1),%edx
+ subl %ebp, %esi
+ roll $13, %edx
+ addl %ecx, %edx
+ /* 43 */
+ movl 28(%esp), %edi
+ orl %edx, %esi
+ addl %edi, %ecx
+ xorl %eax, %esi
+ movl $-1, %edi
+ roll $10, %ebp
+ leal 1859775393(%ecx,%esi,1),%ecx
+ subl %edx, %edi
+ roll $6, %ecx
+ addl %ebx, %ecx
+ /* 44 */
+ movl 56(%esp), %esi
+ orl %ecx, %edi
+ addl %esi, %ebx
+ xorl %ebp, %edi
+ movl $-1, %esi
+ roll $10, %edx
+ leal 1859775393(%ebx,%edi,1),%ebx
+ subl %ecx, %esi
+ roll $5, %ebx
+ addl %eax, %ebx
+ /* 45 */
+ movl 48(%esp), %edi
+ orl %ebx, %esi
+ addl %edi, %eax
+ xorl %edx, %esi
+ movl $-1, %edi
+ roll $10, %ecx
+ leal 1859775393(%eax,%esi,1),%eax
+ subl %ebx, %edi
+ roll $12, %eax
+ addl %ebp, %eax
+ /* 46 */
+ movl 24(%esp), %esi
+ orl %eax, %edi
+ addl %esi, %ebp
+ xorl %ecx, %edi
+ movl $-1, %esi
+ roll $10, %ebx
+ leal 1859775393(%ebp,%edi,1),%ebp
+ subl %eax, %esi
+ roll $7, %ebp
+ addl %edx, %ebp
+ /* 47 */
+ movl 52(%esp), %edi
+ orl %ebp, %esi
+ addl %edi, %edx
+ xorl %ebx, %esi
+ movl $-1, %edi
+ roll $10, %eax
+ leal 1859775393(%edx,%esi,1),%edx
+ movl %eax, %esi
+ roll $5, %edx
+ addl %ecx, %edx
+ /* 48 */
+ subl %eax, %edi
+ andl %edx, %esi
+ andl %ebp, %edi
+ orl %esi, %edi
+ movl 8(%esp), %esi
+ roll $10, %ebp
+ leal 2400959708(%ecx,%edi,),%ecx
+ movl $-1, %edi
+ addl %esi, %ecx
+ movl %ebp, %esi
+ roll $11, %ecx
+ addl %ebx, %ecx
+ /* 49 */
+ subl %ebp, %edi
+ andl %ecx, %esi
+ andl %edx, %edi
+ orl %esi, %edi
+ movl 40(%esp), %esi
+ roll $10, %edx
+ leal 2400959708(%ebx,%edi,),%ebx
+ movl $-1, %edi
+ addl %esi, %ebx
+ movl %edx, %esi
+ roll $12, %ebx
+ addl %eax, %ebx
+ /* 50 */
+ subl %edx, %edi
+ andl %ebx, %esi
+ andl %ecx, %edi
+ orl %esi, %edi
+ movl 48(%esp), %esi
+ roll $10, %ecx
+ leal 2400959708(%eax,%edi,),%eax
+ movl $-1, %edi
+ addl %esi, %eax
+ movl %ecx, %esi
+ roll $14, %eax
+ addl %ebp, %eax
+ /* 51 */
+ subl %ecx, %edi
+ andl %eax, %esi
+ andl %ebx, %edi
+ orl %esi, %edi
+ movl 44(%esp), %esi
+ roll $10, %ebx
+ leal 2400959708(%ebp,%edi,),%ebp
+ movl $-1, %edi
+ addl %esi, %ebp
+ movl %ebx, %esi
+ roll $15, %ebp
+ addl %edx, %ebp
+ /* 52 */
+ subl %ebx, %edi
+ andl %ebp, %esi
+ andl %eax, %edi
+ orl %esi, %edi
+ movl 4(%esp), %esi
+ roll $10, %eax
+ leal 2400959708(%edx,%edi,),%edx
+ movl $-1, %edi
+ addl %esi, %edx
+ movl %eax, %esi
+ roll $14, %edx
+ addl %ecx, %edx
+ /* 53 */
+ subl %eax, %edi
+ andl %edx, %esi
+ andl %ebp, %edi
+ orl %esi, %edi
+ movl 36(%esp), %esi
+ roll $10, %ebp
+ leal 2400959708(%ecx,%edi,),%ecx
+ movl $-1, %edi
+ addl %esi, %ecx
+ movl %ebp, %esi
+ roll $15, %ecx
+ addl %ebx, %ecx
+ /* 54 */
+ subl %ebp, %edi
+ andl %ecx, %esi
+ andl %edx, %edi
+ orl %esi, %edi
+ movl 52(%esp), %esi
+ roll $10, %edx
+ leal 2400959708(%ebx,%edi,),%ebx
+ movl $-1, %edi
+ addl %esi, %ebx
+ movl %edx, %esi
+ roll $9, %ebx
+ addl %eax, %ebx
+ /* 55 */
+ subl %edx, %edi
+ andl %ebx, %esi
+ andl %ecx, %edi
+ orl %esi, %edi
+ movl 20(%esp), %esi
+ roll $10, %ecx
+ leal 2400959708(%eax,%edi,),%eax
+ movl $-1, %edi
+ addl %esi, %eax
+ movl %ecx, %esi
+ roll $8, %eax
+ addl %ebp, %eax
+ /* 56 */
+ subl %ecx, %edi
+ andl %eax, %esi
+ andl %ebx, %edi
+ orl %esi, %edi
+ movl 56(%esp), %esi
+ roll $10, %ebx
+ leal 2400959708(%ebp,%edi,),%ebp
+ movl $-1, %edi
+ addl %esi, %ebp
+ movl %ebx, %esi
+ roll $9, %ebp
+ addl %edx, %ebp
+ /* 57 */
+ subl %ebx, %edi
+ andl %ebp, %esi
+ andl %eax, %edi
+ orl %esi, %edi
+ movl 16(%esp), %esi
+ roll $10, %eax
+ leal 2400959708(%edx,%edi,),%edx
+ movl $-1, %edi
+ addl %esi, %edx
+ movl %eax, %esi
+ roll $14, %edx
+ addl %ecx, %edx
+ /* 58 */
+ subl %eax, %edi
+ andl %edx, %esi
+ andl %ebp, %edi
+ orl %esi, %edi
+ movl 32(%esp), %esi
+ roll $10, %ebp
+ leal 2400959708(%ecx,%edi,),%ecx
+ movl $-1, %edi
+ addl %esi, %ecx
+ movl %ebp, %esi
+ roll $5, %ecx
+ addl %ebx, %ecx
+ /* 59 */
+ subl %ebp, %edi
+ andl %ecx, %esi
+ andl %edx, %edi
+ orl %esi, %edi
+ movl 64(%esp), %esi
+ roll $10, %edx
+ leal 2400959708(%ebx,%edi,),%ebx
+ movl $-1, %edi
+ addl %esi, %ebx
+ movl %edx, %esi
+ roll $6, %ebx
+ addl %eax, %ebx
+ /* 60 */
+ subl %edx, %edi
+ andl %ebx, %esi
+ andl %ecx, %edi
+ orl %esi, %edi
+ movl 60(%esp), %esi
+ roll $10, %ecx
+ leal 2400959708(%eax,%edi,),%eax
+ movl $-1, %edi
+ addl %esi, %eax
+ movl %ecx, %esi
+ roll $8, %eax
+ addl %ebp, %eax
+ /* 61 */
+ subl %ecx, %edi
+ andl %eax, %esi
+ andl %ebx, %edi
+ orl %esi, %edi
+ movl 24(%esp), %esi
+ roll $10, %ebx
+ leal 2400959708(%ebp,%edi,),%ebp
+ movl $-1, %edi
+ addl %esi, %ebp
+ movl %ebx, %esi
+ roll $6, %ebp
+ addl %edx, %ebp
+ /* 62 */
+ subl %ebx, %edi
+ andl %ebp, %esi
+ andl %eax, %edi
+ orl %esi, %edi
+ movl 28(%esp), %esi
+ roll $10, %eax
+ leal 2400959708(%edx,%edi,),%edx
+ movl $-1, %edi
+ addl %esi, %edx
+ movl %eax, %esi
+ roll $5, %edx
+ addl %ecx, %edx
+ /* 63 */
+ subl %eax, %edi
+ andl %edx, %esi
+ andl %ebp, %edi
+ orl %esi, %edi
+ movl 12(%esp), %esi
+ roll $10, %ebp
+ leal 2400959708(%ecx,%edi,),%ecx
+ movl $-1, %edi
+ addl %esi, %ecx
+ subl %ebp, %edi
+ roll $12, %ecx
+ addl %ebx, %ecx
+ /* 64 */
+ movl 20(%esp), %esi
+ orl %edx, %edi
+ addl %esi, %ebx
+ xorl %ecx, %edi
+ movl $-1, %esi
+ roll $10, %edx
+ leal 2840853838(%ebx,%edi,1),%ebx
+ subl %edx, %esi
+ roll $9, %ebx
+ addl %eax, %ebx
+ /* 65 */
+ movl 4(%esp), %edi
+ orl %ecx, %esi
+ addl %edi, %eax
+ xorl %ebx, %esi
+ movl $-1, %edi
+ roll $10, %ecx
+ leal 2840853838(%eax,%esi,1),%eax
+ subl %ecx, %edi
+ roll $15, %eax
+ addl %ebp, %eax
+ /* 66 */
+ movl 24(%esp), %esi
+ orl %ebx, %edi
+ addl %esi, %ebp
+ xorl %eax, %edi
+ movl $-1, %esi
+ roll $10, %ebx
+ leal 2840853838(%ebp,%edi,1),%ebp
+ subl %ebx, %esi
+ roll $5, %ebp
+ addl %edx, %ebp
+ /* 67 */
+ movl 40(%esp), %edi
+ orl %eax, %esi
+ addl %edi, %edx
+ xorl %ebp, %esi
+ movl $-1, %edi
+ roll $10, %eax
+ leal 2840853838(%edx,%esi,1),%edx
+ subl %eax, %edi
+ roll $11, %edx
+ addl %ecx, %edx
+ /* 68 */
+ movl 32(%esp), %esi
+ orl %ebp, %edi
+ addl %esi, %ecx
+ xorl %edx, %edi
+ movl $-1, %esi
+ roll $10, %ebp
+ leal 2840853838(%ecx,%edi,1),%ecx
+ subl %ebp, %esi
+ roll $6, %ecx
+ addl %ebx, %ecx
+ /* 69 */
+ movl 52(%esp), %edi
+ orl %edx, %esi
+ addl %edi, %ebx
+ xorl %ecx, %esi
+ movl $-1, %edi
+ roll $10, %edx
+ leal 2840853838(%ebx,%esi,1),%ebx
+ subl %edx, %edi
+ roll $8, %ebx
+ addl %eax, %ebx
+ /* 70 */
+ movl 12(%esp), %esi
+ orl %ecx, %edi
+ addl %esi, %eax
+ xorl %ebx, %edi
+ movl $-1, %esi
+ roll $10, %ecx
+ leal 2840853838(%eax,%edi,1),%eax
+ subl %ecx, %esi
+ roll $13, %eax
+ addl %ebp, %eax
+ /* 71 */
+ movl 44(%esp), %edi
+ orl %ebx, %esi
+ addl %edi, %ebp
+ xorl %eax, %esi
+ movl $-1, %edi
+ roll $10, %ebx
+ leal 2840853838(%ebp,%esi,1),%ebp
+ subl %ebx, %edi
+ roll $12, %ebp
+ addl %edx, %ebp
+ /* 72 */
+ movl 60(%esp), %esi
+ orl %eax, %edi
+ addl %esi, %edx
+ xorl %ebp, %edi
+ movl $-1, %esi
+ roll $10, %eax
+ leal 2840853838(%edx,%edi,1),%edx
+ subl %eax, %esi
+ roll $5, %edx
+ addl %ecx, %edx
+ /* 73 */
+ movl 8(%esp), %edi
+ orl %ebp, %esi
+ addl %edi, %ecx
+ xorl %edx, %esi
+ movl $-1, %edi
+ roll $10, %ebp
+ leal 2840853838(%ecx,%esi,1),%ecx
+ subl %ebp, %edi
+ roll $12, %ecx
+ addl %ebx, %ecx
+ /* 74 */
+ movl 16(%esp), %esi
+ orl %edx, %edi
+ addl %esi, %ebx
+ xorl %ecx, %edi
+ movl $-1, %esi
+ roll $10, %edx
+ leal 2840853838(%ebx,%edi,1),%ebx
+ subl %edx, %esi
+ roll $13, %ebx
+ addl %eax, %ebx
+ /* 75 */
+ movl 36(%esp), %edi
+ orl %ecx, %esi
+ addl %edi, %eax
+ xorl %ebx, %esi
+ movl $-1, %edi
+ roll $10, %ecx
+ leal 2840853838(%eax,%esi,1),%eax
+ subl %ecx, %edi
+ roll $14, %eax
+ addl %ebp, %eax
+ /* 76 */
+ movl 48(%esp), %esi
+ orl %ebx, %edi
+ addl %esi, %ebp
+ xorl %eax, %edi
+ movl $-1, %esi
+ roll $10, %ebx
+ leal 2840853838(%ebp,%edi,1),%ebp
+ subl %ebx, %esi
+ roll $11, %ebp
+ addl %edx, %ebp
+ /* 77 */
+ movl 28(%esp), %edi
+ orl %eax, %esi
+ addl %edi, %edx
+ xorl %ebp, %esi
+ movl $-1, %edi
+ roll $10, %eax
+ leal 2840853838(%edx,%esi,1),%edx
+ subl %eax, %edi
+ roll $8, %edx
+ addl %ecx, %edx
+ /* 78 */
+ movl 64(%esp), %esi
+ orl %ebp, %edi
+ addl %esi, %ecx
+ xorl %edx, %edi
+ movl $-1, %esi
+ roll $10, %ebp
+ leal 2840853838(%ecx,%edi,1),%ecx
+ subl %ebp, %esi
+ roll $5, %ecx
+ addl %ebx, %ecx
+ /* 79 */
+ movl 56(%esp), %edi
+ orl %edx, %esi
+ addl %edi, %ebx
+ xorl %ecx, %esi
+ movl 108(%esp), %edi
+ roll $10, %edx
+ leal 2840853838(%ebx,%esi,1),%ebx
+ movl %eax, 68(%esp)
+ roll $6, %ebx
+ addl %eax, %ebx
+ movl (%edi), %eax
+ movl %ebx, 72(%esp)
+ movl %ecx, 76(%esp)
+ movl 4(%edi), %ebx
+ movl %edx, 80(%esp)
+ movl 8(%edi), %ecx
+ movl %ebp, 84(%esp)
+ movl 12(%edi), %edx
+ movl 16(%edi), %ebp
+ /* 80 */
+ movl $-1, %edi
+ subl %edx, %edi
+ movl 24(%esp), %esi
+ orl %ecx, %edi
+ addl %esi, %eax
+ xorl %ebx, %edi
+ movl $-1, %esi
+ roll $10, %ecx
+ leal 1352829926(%eax,%edi,1),%eax
+ subl %ecx, %esi
+ roll $8, %eax
+ addl %ebp, %eax
+ /* 81 */
+ movl 60(%esp), %edi
+ orl %ebx, %esi
+ addl %edi, %ebp
+ xorl %eax, %esi
+ movl $-1, %edi
+ roll $10, %ebx
+ leal 1352829926(%ebp,%esi,1),%ebp
+ subl %ebx, %edi
+ roll $9, %ebp
+ addl %edx, %ebp
+ /* 82 */
+ movl 32(%esp), %esi
+ orl %eax, %edi
+ addl %esi, %edx
+ xorl %ebp, %edi
+ movl $-1, %esi
+ roll $10, %eax
+ leal 1352829926(%edx,%edi,1),%edx
+ subl %eax, %esi
+ roll $9, %edx
+ addl %ecx, %edx
+ /* 83 */
+ movl 4(%esp), %edi
+ orl %ebp, %esi
+ addl %edi, %ecx
+ xorl %edx, %esi
+ movl $-1, %edi
+ roll $10, %ebp
+ leal 1352829926(%ecx,%esi,1),%ecx
+ subl %ebp, %edi
+ roll $11, %ecx
+ addl %ebx, %ecx
+ /* 84 */
+ movl 40(%esp), %esi
+ orl %edx, %edi
+ addl %esi, %ebx
+ xorl %ecx, %edi
+ movl $-1, %esi
+ roll $10, %edx
+ leal 1352829926(%ebx,%edi,1),%ebx
+ subl %edx, %esi
+ roll $13, %ebx
+ addl %eax, %ebx
+ /* 85 */
+ movl 12(%esp), %edi
+ orl %ecx, %esi
+ addl %edi, %eax
+ xorl %ebx, %esi
+ movl $-1, %edi
+ roll $10, %ecx
+ leal 1352829926(%eax,%esi,1),%eax
+ subl %ecx, %edi
+ roll $15, %eax
+ addl %ebp, %eax
+ /* 86 */
+ movl 48(%esp), %esi
+ orl %ebx, %edi
+ addl %esi, %ebp
+ xorl %eax, %edi
+ movl $-1, %esi
+ roll $10, %ebx
+ leal 1352829926(%ebp,%edi,1),%ebp
+ subl %ebx, %esi
+ roll $15, %ebp
+ addl %edx, %ebp
+ /* 87 */
+ movl 20(%esp), %edi
+ orl %eax, %esi
+ addl %edi, %edx
+ xorl %ebp, %esi
+ movl $-1, %edi
+ roll $10, %eax
+ leal 1352829926(%edx,%esi,1),%edx
+ subl %eax, %edi
+ roll $5, %edx
+ addl %ecx, %edx
+ /* 88 */
+ movl 56(%esp), %esi
+ orl %ebp, %edi
+ addl %esi, %ecx
+ xorl %edx, %edi
+ movl $-1, %esi
+ roll $10, %ebp
+ leal 1352829926(%ecx,%edi,1),%ecx
+ subl %ebp, %esi
+ roll $7, %ecx
+ addl %ebx, %ecx
+ /* 89 */
+ movl 28(%esp), %edi
+ orl %edx, %esi
+ addl %edi, %ebx
+ xorl %ecx, %esi
+ movl $-1, %edi
+ roll $10, %edx
+ leal 1352829926(%ebx,%esi,1),%ebx
+ subl %edx, %edi
+ roll $7, %ebx
+ addl %eax, %ebx
+ /* 90 */
+ movl 64(%esp), %esi
+ orl %ecx, %edi
+ addl %esi, %eax
+ xorl %ebx, %edi
+ movl $-1, %esi
+ roll $10, %ecx
+ leal 1352829926(%eax,%edi,1),%eax
+ subl %ecx, %esi
+ roll $8, %eax
+ addl %ebp, %eax
+ /* 91 */
+ movl 36(%esp), %edi
+ orl %ebx, %esi
+ addl %edi, %ebp
+ xorl %eax, %esi
+ movl $-1, %edi
+ roll $10, %ebx
+ leal 1352829926(%ebp,%esi,1),%ebp
+ subl %ebx, %edi
+ roll $11, %ebp
+ addl %edx, %ebp
+ /* 92 */
+ movl 8(%esp), %esi
+ orl %eax, %edi
+ addl %esi, %edx
+ xorl %ebp, %edi
+ movl $-1, %esi
+ roll $10, %eax
+ leal 1352829926(%edx,%edi,1),%edx
+ subl %eax, %esi
+ roll $14, %edx
+ addl %ecx, %edx
+ /* 93 */
+ movl 44(%esp), %edi
+ orl %ebp, %esi
+ addl %edi, %ecx
+ xorl %edx, %esi
+ movl $-1, %edi
+ roll $10, %ebp
+ leal 1352829926(%ecx,%esi,1),%ecx
+ subl %ebp, %edi
+ roll $14, %ecx
+ addl %ebx, %ecx
+ /* 94 */
+ movl 16(%esp), %esi
+ orl %edx, %edi
+ addl %esi, %ebx
+ xorl %ecx, %edi
+ movl $-1, %esi
+ roll $10, %edx
+ leal 1352829926(%ebx,%edi,1),%ebx
+ subl %edx, %esi
+ roll $12, %ebx
+ addl %eax, %ebx
+ /* 95 */
+ movl 52(%esp), %edi
+ orl %ecx, %esi
+ addl %edi, %eax
+ xorl %ebx, %esi
+ movl $-1, %edi
+ roll $10, %ecx
+ leal 1352829926(%eax,%esi,1),%eax
+ movl %ecx, %esi
+ roll $6, %eax
+ addl %ebp, %eax
+ /* 96 */
+ subl %ecx, %edi
+ andl %eax, %esi
+ andl %ebx, %edi
+ orl %esi, %edi
+ movl 28(%esp), %esi
+ roll $10, %ebx
+ leal 1548603684(%ebp,%edi,),%ebp
+ movl $-1, %edi
+ addl %esi, %ebp
+ movl %ebx, %esi
+ roll $9, %ebp
+ addl %edx, %ebp
+ /* 97 */
+ subl %ebx, %edi
+ andl %ebp, %esi
+ andl %eax, %edi
+ orl %esi, %edi
+ movl 48(%esp), %esi
+ roll $10, %eax
+ leal 1548603684(%edx,%edi,),%edx
+ movl $-1, %edi
+ addl %esi, %edx
+ movl %eax, %esi
+ roll $13, %edx
+ addl %ecx, %edx
+ /* 98 */
+ subl %eax, %edi
+ andl %edx, %esi
+ andl %ebp, %edi
+ orl %esi, %edi
+ movl 16(%esp), %esi
+ roll $10, %ebp
+ leal 1548603684(%ecx,%edi,),%ecx
+ movl $-1, %edi
+ addl %esi, %ecx
+ movl %ebp, %esi
+ roll $15, %ecx
+ addl %ebx, %ecx
+ /* 99 */
+ subl %ebp, %edi
+ andl %ecx, %esi
+ andl %edx, %edi
+ orl %esi, %edi
+ movl 32(%esp), %esi
+ roll $10, %edx
+ leal 1548603684(%ebx,%edi,),%ebx
+ movl $-1, %edi
+ addl %esi, %ebx
+ movl %edx, %esi
+ roll $7, %ebx
+ addl %eax, %ebx
+ /* 100 */
+ subl %edx, %edi
+ andl %ebx, %esi
+ andl %ecx, %edi
+ orl %esi, %edi
+ movl 4(%esp), %esi
+ roll $10, %ecx
+ leal 1548603684(%eax,%edi,),%eax
+ movl $-1, %edi
+ addl %esi, %eax
+ movl %ecx, %esi
+ roll $12, %eax
+ addl %ebp, %eax
+ /* 101 */
+ subl %ecx, %edi
+ andl %eax, %esi
+ andl %ebx, %edi
+ orl %esi, %edi
+ movl 56(%esp), %esi
+ roll $10, %ebx
+ leal 1548603684(%ebp,%edi,),%ebp
+ movl $-1, %edi
+ addl %esi, %ebp
+ movl %ebx, %esi
+ roll $8, %ebp
+ addl %edx, %ebp
+ /* 102 */
+ subl %ebx, %edi
+ andl %ebp, %esi
+ andl %eax, %edi
+ orl %esi, %edi
+ movl 24(%esp), %esi
+ roll $10, %eax
+ leal 1548603684(%edx,%edi,),%edx
+ movl $-1, %edi
+ addl %esi, %edx
+ movl %eax, %esi
+ roll $9, %edx
+ addl %ecx, %edx
+ /* 103 */
+ subl %eax, %edi
+ andl %edx, %esi
+ andl %ebp, %edi
+ orl %esi, %edi
+ movl 44(%esp), %esi
+ roll $10, %ebp
+ leal 1548603684(%ecx,%edi,),%ecx
+ movl $-1, %edi
+ addl %esi, %ecx
+ movl %ebp, %esi
+ roll $11, %ecx
+ addl %ebx, %ecx
+ /* 104 */
+ subl %ebp, %edi
+ andl %ecx, %esi
+ andl %edx, %edi
+ orl %esi, %edi
+ movl 60(%esp), %esi
+ roll $10, %edx
+ leal 1548603684(%ebx,%edi,),%ebx
+ movl $-1, %edi
+ addl %esi, %ebx
+ movl %edx, %esi
+ roll $7, %ebx
+ addl %eax, %ebx
+ /* 105 */
+ subl %edx, %edi
+ andl %ebx, %esi
+ andl %ecx, %edi
+ orl %esi, %edi
+ movl 64(%esp), %esi
+ roll $10, %ecx
+ leal 1548603684(%eax,%edi,),%eax
+ movl $-1, %edi
+ addl %esi, %eax
+ movl %ecx, %esi
+ roll $7, %eax
+ addl %ebp, %eax
+ /* 106 */
+ subl %ecx, %edi
+ andl %eax, %esi
+ andl %ebx, %edi
+ orl %esi, %edi
+ movl 36(%esp), %esi
+ roll $10, %ebx
+ leal 1548603684(%ebp,%edi,),%ebp
+ movl $-1, %edi
+ addl %esi, %ebp
+ movl %ebx, %esi
+ roll $12, %ebp
+ addl %edx, %ebp
+ /* 107 */
+ subl %ebx, %edi
+ andl %ebp, %esi
+ andl %eax, %edi
+ orl %esi, %edi
+ movl 52(%esp), %esi
+ roll $10, %eax
+ leal 1548603684(%edx,%edi,),%edx
+ movl $-1, %edi
+ addl %esi, %edx
+ movl %eax, %esi
+ roll $7, %edx
+ addl %ecx, %edx
+ /* 108 */
+ subl %eax, %edi
+ andl %edx, %esi
+ andl %ebp, %edi
+ orl %esi, %edi
+ movl 20(%esp), %esi
+ roll $10, %ebp
+ leal 1548603684(%ecx,%edi,),%ecx
+ movl $-1, %edi
+ addl %esi, %ecx
+ movl %ebp, %esi
+ roll $6, %ecx
+ addl %ebx, %ecx
+ /* 109 */
+ subl %ebp, %edi
+ andl %ecx, %esi
+ andl %edx, %edi
+ orl %esi, %edi
+ movl 40(%esp), %esi
+ roll $10, %edx
+ leal 1548603684(%ebx,%edi,),%ebx
+ movl $-1, %edi
+ addl %esi, %ebx
+ movl %edx, %esi
+ roll $15, %ebx
+ addl %eax, %ebx
+ /* 110 */
+ subl %edx, %edi
+ andl %ebx, %esi
+ andl %ecx, %edi
+ orl %esi, %edi
+ movl 8(%esp), %esi
+ roll $10, %ecx
+ leal 1548603684(%eax,%edi,),%eax
+ movl $-1, %edi
+ addl %esi, %eax
+ movl %ecx, %esi
+ roll $13, %eax
+ addl %ebp, %eax
+ /* 111 */
+ subl %ecx, %edi
+ andl %eax, %esi
+ andl %ebx, %edi
+ orl %esi, %edi
+ movl 12(%esp), %esi
+ roll $10, %ebx
+ leal 1548603684(%ebp,%edi,),%ebp
+ movl $-1, %edi
+ addl %esi, %ebp
+ subl %eax, %edi
+ roll $11, %ebp
+ addl %edx, %ebp
+ /* 112 */
+ movl 64(%esp), %esi
+ orl %ebp, %edi
+ addl %esi, %edx
+ xorl %ebx, %edi
+ movl $-1, %esi
+ roll $10, %eax
+ leal 1836072691(%edx,%edi,1),%edx
+ subl %ebp, %esi
+ roll $9, %edx
+ addl %ecx, %edx
+ /* 113 */
+ movl 24(%esp), %edi
+ orl %edx, %esi
+ addl %edi, %ecx
+ xorl %eax, %esi
+ movl $-1, %edi
+ roll $10, %ebp
+ leal 1836072691(%ecx,%esi,1),%ecx
+ subl %edx, %edi
+ roll $7, %ecx
+ addl %ebx, %ecx
+ /* 114 */
+ movl 8(%esp), %esi
+ orl %ecx, %edi
+ addl %esi, %ebx
+ xorl %ebp, %edi
+ movl $-1, %esi
+ roll $10, %edx
+ leal 1836072691(%ebx,%edi,1),%ebx
+ subl %ecx, %esi
+ roll $15, %ebx
+ addl %eax, %ebx
+ /* 115 */
+ movl 16(%esp), %edi
+ orl %ebx, %esi
+ addl %edi, %eax
+ xorl %edx, %esi
+ movl $-1, %edi
+ roll $10, %ecx
+ leal 1836072691(%eax,%esi,1),%eax
+ subl %ebx, %edi
+ roll $11, %eax
+ addl %ebp, %eax
+ /* 116 */
+ movl 32(%esp), %esi
+ orl %eax, %edi
+ addl %esi, %ebp
+ xorl %ecx, %edi
+ movl $-1, %esi
+ roll $10, %ebx
+ leal 1836072691(%ebp,%edi,1),%ebp
+ subl %eax, %esi
+ roll $8, %ebp
+ addl %edx, %ebp
+ /* 117 */
+ movl 60(%esp), %edi
+ orl %ebp, %esi
+ addl %edi, %edx
+ xorl %ebx, %esi
+ movl $-1, %edi
+ roll $10, %eax
+ leal 1836072691(%edx,%esi,1),%edx
+ subl %ebp, %edi
+ roll $6, %edx
+ addl %ecx, %edx
+ /* 118 */
+ movl 28(%esp), %esi
+ orl %edx, %edi
+ addl %esi, %ecx
+ xorl %eax, %edi
+ movl $-1, %esi
+ roll $10, %ebp
+ leal 1836072691(%ecx,%edi,1),%ecx
+ subl %edx, %esi
+ roll $6, %ecx
+ addl %ebx, %ecx
+ /* 119 */
+ movl 40(%esp), %edi
+ orl %ecx, %esi
+ addl %edi, %ebx
+ xorl %ebp, %esi
+ movl $-1, %edi
+ roll $10, %edx
+ leal 1836072691(%ebx,%esi,1),%ebx
+ subl %ecx, %edi
+ roll $14, %ebx
+ addl %eax, %ebx
+ /* 120 */
+ movl 48(%esp), %esi
+ orl %ebx, %edi
+ addl %esi, %eax
+ xorl %edx, %edi
+ movl $-1, %esi
+ roll $10, %ecx
+ leal 1836072691(%eax,%edi,1),%eax
+ subl %ebx, %esi
+ roll $12, %eax
+ addl %ebp, %eax
+ /* 121 */
+ movl 36(%esp), %edi
+ orl %eax, %esi
+ addl %edi, %ebp
+ xorl %ecx, %esi
+ movl $-1, %edi
+ roll $10, %ebx
+ leal 1836072691(%ebp,%esi,1),%ebp
+ subl %eax, %edi
+ roll $13, %ebp
+ addl %edx, %ebp
+ /* 122 */
+ movl 52(%esp), %esi
+ orl %ebp, %edi
+ addl %esi, %edx
+ xorl %ebx, %edi
+ movl $-1, %esi
+ roll $10, %eax
+ leal 1836072691(%edx,%edi,1),%edx
+ subl %ebp, %esi
+ roll $5, %edx
+ addl %ecx, %edx
+ /* 123 */
+ movl 12(%esp), %edi
+ orl %edx, %esi
+ addl %edi, %ecx
+ xorl %eax, %esi
+ movl $-1, %edi
+ roll $10, %ebp
+ leal 1836072691(%ecx,%esi,1),%ecx
+ subl %edx, %edi
+ roll $14, %ecx
+ addl %ebx, %ecx
+ /* 124 */
+ movl 44(%esp), %esi
+ orl %ecx, %edi
+ addl %esi, %ebx
+ xorl %ebp, %edi
+ movl $-1, %esi
+ roll $10, %edx
+ leal 1836072691(%ebx,%edi,1),%ebx
+ subl %ecx, %esi
+ roll $13, %ebx
+ addl %eax, %ebx
+ /* 125 */
+ movl 4(%esp), %edi
+ orl %ebx, %esi
+ addl %edi, %eax
+ xorl %edx, %esi
+ movl $-1, %edi
+ roll $10, %ecx
+ leal 1836072691(%eax,%esi,1),%eax
+ subl %ebx, %edi
+ roll $13, %eax
+ addl %ebp, %eax
+ /* 126 */
+ movl 20(%esp), %esi
+ orl %eax, %edi
+ addl %esi, %ebp
+ xorl %ecx, %edi
+ movl $-1, %esi
+ roll $10, %ebx
+ leal 1836072691(%ebp,%edi,1),%ebp
+ subl %eax, %esi
+ roll $7, %ebp
+ addl %edx, %ebp
+ /* 127 */
+ movl 56(%esp), %edi
+ orl %ebp, %esi
+ addl %edi, %edx
+ xorl %ebx, %esi
+ movl 36(%esp), %edi
+ roll $10, %eax
+ leal 1836072691(%edx,%esi,1),%edx
+ movl $-1, %esi
+ roll $5, %edx
+ addl %ecx, %edx
+ /* 128 */
+ addl %edi, %ecx
+ movl %ebp, %edi
+ subl %edx, %esi
+ andl %edx, %edi
+ andl %eax, %esi
+ orl %esi, %edi
+ movl 28(%esp), %esi
+ roll $10, %ebp
+ leal 2053994217(%ecx,%edi,1),%ecx
+ movl $-1, %edi
+ roll $15, %ecx
+ addl %ebx, %ecx
+ /* 129 */
+ addl %esi, %ebx
+ movl %edx, %esi
+ subl %ecx, %edi
+ andl %ecx, %esi
+ andl %ebp, %edi
+ orl %edi, %esi
+ movl 20(%esp), %edi
+ roll $10, %edx
+ leal 2053994217(%ebx,%esi,1),%ebx
+ movl $-1, %esi
+ roll $5, %ebx
+ addl %eax, %ebx
+ /* 130 */
+ addl %edi, %eax
+ movl %ecx, %edi
+ subl %ebx, %esi
+ andl %ebx, %edi
+ andl %edx, %esi
+ orl %esi, %edi
+ movl 8(%esp), %esi
+ roll $10, %ecx
+ leal 2053994217(%eax,%edi,1),%eax
+ movl $-1, %edi
+ roll $8, %eax
+ addl %ebp, %eax
+ /* 131 */
+ addl %esi, %ebp
+ movl %ebx, %esi
+ subl %eax, %edi
+ andl %eax, %esi
+ andl %ecx, %edi
+ orl %edi, %esi
+ movl 16(%esp), %edi
+ roll $10, %ebx
+ leal 2053994217(%ebp,%esi,1),%ebp
+ movl $-1, %esi
+ roll $11, %ebp
+ addl %edx, %ebp
+ /* 132 */
+ addl %edi, %edx
+ movl %eax, %edi
+ subl %ebp, %esi
+ andl %ebp, %edi
+ andl %ebx, %esi
+ orl %esi, %edi
+ movl 48(%esp), %esi
+ roll $10, %eax
+ leal 2053994217(%edx,%edi,1),%edx
+ movl $-1, %edi
+ roll $14, %edx
+ addl %ecx, %edx
+ /* 133 */
+ addl %esi, %ecx
+ movl %ebp, %esi
+ subl %edx, %edi
+ andl %edx, %esi
+ andl %eax, %edi
+ orl %edi, %esi
+ movl 64(%esp), %edi
+ roll $10, %ebp
+ leal 2053994217(%ecx,%esi,1),%ecx
+ movl $-1, %esi
+ roll $14, %ecx
+ addl %ebx, %ecx
+ /* 134 */
+ addl %edi, %ebx
+ movl %edx, %edi
+ subl %ecx, %esi
+ andl %ecx, %edi
+ andl %ebp, %esi
+ orl %esi, %edi
+ movl 4(%esp), %esi
+ roll $10, %edx
+ leal 2053994217(%ebx,%edi,1),%ebx
+ movl $-1, %edi
+ roll $6, %ebx
+ addl %eax, %ebx
+ /* 135 */
+ addl %esi, %eax
+ movl %ecx, %esi
+ subl %ebx, %edi
+ andl %ebx, %esi
+ andl %edx, %edi
+ orl %edi, %esi
+ movl 24(%esp), %edi
+ roll $10, %ecx
+ leal 2053994217(%eax,%esi,1),%eax
+ movl $-1, %esi
+ roll $14, %eax
+ addl %ebp, %eax
+ /* 136 */
+ addl %edi, %ebp
+ movl %ebx, %edi
+ subl %eax, %esi
+ andl %eax, %edi
+ andl %ecx, %esi
+ orl %esi, %edi
+ movl 52(%esp), %esi
+ roll $10, %ebx
+ leal 2053994217(%ebp,%edi,1),%ebp
+ movl $-1, %edi
+ roll $6, %ebp
+ addl %edx, %ebp
+ /* 137 */
+ addl %esi, %edx
+ movl %eax, %esi
+ subl %ebp, %edi
+ andl %ebp, %esi
+ andl %ebx, %edi
+ orl %edi, %esi
+ movl 12(%esp), %edi
+ roll $10, %eax
+ leal 2053994217(%edx,%esi,1),%edx
+ movl $-1, %esi
+ roll $9, %edx
+ addl %ecx, %edx
+ /* 138 */
+ addl %edi, %ecx
+ movl %ebp, %edi
+ subl %edx, %esi
+ andl %edx, %edi
+ andl %eax, %esi
+ orl %esi, %edi
+ movl 56(%esp), %esi
+ roll $10, %ebp
+ leal 2053994217(%ecx,%edi,1),%ecx
+ movl $-1, %edi
+ roll $12, %ecx
+ addl %ebx, %ecx
+ /* 139 */
+ addl %esi, %ebx
+ movl %edx, %esi
+ subl %ecx, %edi
+ andl %ecx, %esi
+ andl %ebp, %edi
+ orl %edi, %esi
+ movl 40(%esp), %edi
+ roll $10, %edx
+ leal 2053994217(%ebx,%esi,1),%ebx
+ movl $-1, %esi
+ roll $9, %ebx
+ addl %eax, %ebx
+ /* 140 */
+ addl %edi, %eax
+ movl %ecx, %edi
+ subl %ebx, %esi
+ andl %ebx, %edi
+ andl %edx, %esi
+ orl %esi, %edi
+ movl 32(%esp), %esi
+ roll $10, %ecx
+ leal 2053994217(%eax,%edi,1),%eax
+ movl $-1, %edi
+ roll $12, %eax
+ addl %ebp, %eax
+ /* 141 */
+ addl %esi, %ebp
+ movl %ebx, %esi
+ subl %eax, %edi
+ andl %eax, %esi
+ andl %ecx, %edi
+ orl %edi, %esi
+ movl 44(%esp), %edi
+ roll $10, %ebx
+ leal 2053994217(%ebp,%esi,1),%ebp
+ movl $-1, %esi
+ roll $5, %ebp
+ addl %edx, %ebp
+ /* 142 */
+ addl %edi, %edx
+ movl %eax, %edi
+ subl %ebp, %esi
+ andl %ebp, %edi
+ andl %ebx, %esi
+ orl %esi, %edi
+ movl 60(%esp), %esi
+ roll $10, %eax
+ leal 2053994217(%edx,%edi,1),%edx
+ movl $-1, %edi
+ roll $15, %edx
+ addl %ecx, %edx
+ /* 143 */
+ addl %esi, %ecx
+ movl %ebp, %esi
+ subl %edx, %edi
+ andl %edx, %esi
+ andl %eax, %edi
+ orl %esi, %edi
+ movl %edx, %esi
+ roll $10, %ebp
+ leal 2053994217(%ecx,%edi,1),%ecx
+ xorl %ebp, %esi
+ roll $8, %ecx
+ addl %ebx, %ecx
+ /* 144 */
+ movl 52(%esp), %edi
+ xorl %ecx, %esi
+ addl %edi, %ebx
+ roll $10, %edx
+ addl %esi, %ebx
+ movl %ecx, %esi
+ roll $8, %ebx
+ addl %eax, %ebx
+ /* 145 */
+ xorl %edx, %esi
+ movl 64(%esp), %edi
+ xorl %ebx, %esi
+ addl %esi, %eax
+ movl %ebx, %esi
+ roll $10, %ecx
+ addl %edi, %eax
+ xorl %ecx, %esi
+ roll $5, %eax
+ addl %ebp, %eax
+ /* 146 */
+ movl 44(%esp), %edi
+ xorl %eax, %esi
+ addl %edi, %ebp
+ roll $10, %ebx
+ addl %esi, %ebp
+ movl %eax, %esi
+ roll $12, %ebp
+ addl %edx, %ebp
+ /* 147 */
+ xorl %ebx, %esi
+ movl 20(%esp), %edi
+ xorl %ebp, %esi
+ addl %esi, %edx
+ movl %ebp, %esi
+ roll $10, %eax
+ addl %edi, %edx
+ xorl %eax, %esi
+ roll $9, %edx
+ addl %ecx, %edx
+ /* 148 */
+ movl 8(%esp), %edi
+ xorl %edx, %esi
+ addl %edi, %ecx
+ roll $10, %ebp
+ addl %esi, %ecx
+ movl %edx, %esi
+ roll $12, %ecx
+ addl %ebx, %ecx
+ /* 149 */
+ xorl %ebp, %esi
+ movl 24(%esp), %edi
+ xorl %ecx, %esi
+ addl %esi, %ebx
+ movl %ecx, %esi
+ roll $10, %edx
+ addl %edi, %ebx
+ xorl %edx, %esi
+ roll $5, %ebx
+ addl %eax, %ebx
+ /* 150 */
+ movl 36(%esp), %edi
+ xorl %ebx, %esi
+ addl %edi, %eax
+ roll $10, %ecx
+ addl %esi, %eax
+ movl %ebx, %esi
+ roll $14, %eax
+ addl %ebp, %eax
+ /* 151 */
+ xorl %ecx, %esi
+ movl 32(%esp), %edi
+ xorl %eax, %esi
+ addl %esi, %ebp
+ movl %eax, %esi
+ roll $10, %ebx
+ addl %edi, %ebp
+ xorl %ebx, %esi
+ roll $6, %ebp
+ addl %edx, %ebp
+ /* 152 */
+ movl 28(%esp), %edi
+ xorl %ebp, %esi
+ addl %edi, %edx
+ roll $10, %eax
+ addl %esi, %edx
+ movl %ebp, %esi
+ roll $8, %edx
+ addl %ecx, %edx
+ /* 153 */
+ xorl %eax, %esi
+ movl 12(%esp), %edi
+ xorl %edx, %esi
+ addl %esi, %ecx
+ movl %edx, %esi
+ roll $10, %ebp
+ addl %edi, %ecx
+ xorl %ebp, %esi
+ roll $13, %ecx
+ addl %ebx, %ecx
+ /* 154 */
+ movl 56(%esp), %edi
+ xorl %ecx, %esi
+ addl %edi, %ebx
+ roll $10, %edx
+ addl %esi, %ebx
+ movl %ecx, %esi
+ roll $6, %ebx
+ addl %eax, %ebx
+ /* 155 */
+ xorl %edx, %esi
+ movl 60(%esp), %edi
+ xorl %ebx, %esi
+ addl %esi, %eax
+ movl %ebx, %esi
+ roll $10, %ecx
+ addl %edi, %eax
+ xorl %ecx, %esi
+ roll $5, %eax
+ addl %ebp, %eax
+ /* 156 */
+ movl 4(%esp), %edi
+ xorl %eax, %esi
+ addl %edi, %ebp
+ roll $10, %ebx
+ addl %esi, %ebp
+ movl %eax, %esi
+ roll $15, %ebp
+ addl %edx, %ebp
+ /* 157 */
+ xorl %ebx, %esi
+ movl 16(%esp), %edi
+ xorl %ebp, %esi
+ addl %esi, %edx
+ movl %ebp, %esi
+ roll $10, %eax
+ addl %edi, %edx
+ xorl %eax, %esi
+ roll $13, %edx
+ addl %ecx, %edx
+ /* 158 */
+ movl 40(%esp), %edi
+ xorl %edx, %esi
+ addl %edi, %ecx
+ roll $10, %ebp
+ addl %esi, %ecx
+ movl %edx, %esi
+ roll $11, %ecx
+ addl %ebx, %ecx
+ /* 159 */
+ xorl %ebp, %esi
+ movl 48(%esp), %edi
+ xorl %ecx, %esi
+ addl %esi, %ebx
+ roll $10, %edx
+ addl %edi, %ebx
+ movl 108(%esp), %edi
+ roll $11, %ebx
+ addl %eax, %ebx
+ movl 4(%edi), %esi
+ addl %esi, %edx
+ movl 76(%esp), %esi
+ addl %esi, %edx
+ movl 8(%edi), %esi
+ addl %esi, %ebp
+ movl 80(%esp), %esi
+ addl %esi, %ebp
+ movl 12(%edi), %esi
+ addl %esi, %eax
+ movl 84(%esp), %esi
+ addl %esi, %eax
+ movl 16(%edi), %esi
+ addl %esi, %ebx
+ movl 68(%esp), %esi
+ addl %esi, %ebx
+ movl (%edi), %esi
+ addl %esi, %ecx
+ movl 72(%esp), %esi
+ addl %esi, %ecx
+ movl %edx, (%edi)
+ movl %ebp, 4(%edi)
+ movl %eax, 8(%edi)
+ movl %ebx, 12(%edi)
+ movl %ecx, 16(%edi)
+ movl (%esp), %edi
+ movl 112(%esp), %esi
+ cmpl %esi, %edi
+ movl 108(%esp), %edi
+ jge .L000start
+ addl $88, %esp
+ popl %ebx
+ popl %ebp
+ popl %edi
+ popl %esi
+ ret
+.ripemd160_block_x86_end:
+ SIZE(ripemd160_block_x86,.ripemd160_block_x86_end-ripemd160_block_x86)
+.ident "desasm.pl"
+#endif /* not PIC */
diff --git a/lib/libmd/i386/sha.S b/lib/libmd/i386/sha.S
new file mode 100644
index 0000000..ae8f89e
--- /dev/null
+++ b/lib/libmd/i386/sha.S
@@ -0,0 +1,1951 @@
+/* -*- Fundamental -*- Emacs' assembler mode hoses this file */
+#ifndef PIC
+/* Run the C pre-processor over this file with one of the following defined
+ * ELF - elf object files,
+ * OUT - a.out object files,
+ * BSDI - BSDI style a.out object files
+ * SOL - Solaris style elf
+ */
+
+#define TYPE(a,b) .type a,b
+#define SIZE(a,b) .size a,b
+
+#if defined(OUT) || defined(BSDI)
+#define sha1_block_x86 _sha1_block_x86
+
+#endif
+
+#ifdef OUT
+#define OK 1
+#define ALIGN 4
+#endif
+
+#ifdef BSDI
+#define OK 1
+#define ALIGN 4
+#undef SIZE
+#undef TYPE
+#define SIZE(a,b)
+#define TYPE(a,b)
+#endif
+
+#if defined(ELF) || defined(SOL)
+#define OK 1
+#define ALIGN 4
+#endif
+
+#ifndef OK
+You need to define one of
+ELF - elf systems - linux-elf, NetBSD and DG-UX
+OUT - a.out systems - linux-a.out and FreeBSD
+SOL - solaris systems, which are elf with strange comment lines
+BSDI - a.out with a very primative version of as.
+#endif
+
+/* Let the Assembler begin :-) */
+ /* Don't even think of reading this code */
+ /* It was automatically generated by sha1-586.pl */
+ /* Which is a perl program used to generate the x86 assember for */
+ /* any of elf, a.out, BSDI,Win32, or Solaris */
+ /* eric <eay@cryptsoft.com> */
+
+ .file "sha1-586.s"
+ .version "01.01"
+gcc2_compiled.:
+.text
+ .p2align ALIGN
+.globl sha1_block_x86
+ TYPE(sha1_block_x86,@function)
+sha1_block_x86:
+ pushl %esi
+ pushl %ebp
+ movl 20(%esp), %eax
+ movl 16(%esp), %esi
+ addl %esi, %eax
+ movl 12(%esp), %ebp
+ pushl %ebx
+ subl $64, %eax
+ pushl %edi
+ movl 4(%ebp), %ebx
+ subl $72, %esp
+ movl 12(%ebp), %edx
+ movl 16(%ebp), %edi
+ movl 8(%ebp), %ecx
+ movl %eax, 68(%esp)
+ /* First we need to setup the X array */
+ movl (%esi), %eax
+.L000start:
+ /* First, load the words onto the stack in network byte order */
+.byte 15
+.byte 200 /* bswapl %eax */
+ movl %eax, (%esp)
+ movl 4(%esi), %eax
+.byte 15
+.byte 200 /* bswapl %eax */
+ movl %eax, 4(%esp)
+ movl 8(%esi), %eax
+.byte 15
+.byte 200 /* bswapl %eax */
+ movl %eax, 8(%esp)
+ movl 12(%esi), %eax
+.byte 15
+.byte 200 /* bswapl %eax */
+ movl %eax, 12(%esp)
+ movl 16(%esi), %eax
+.byte 15
+.byte 200 /* bswapl %eax */
+ movl %eax, 16(%esp)
+ movl 20(%esi), %eax
+.byte 15
+.byte 200 /* bswapl %eax */
+ movl %eax, 20(%esp)
+ movl 24(%esi), %eax
+.byte 15
+.byte 200 /* bswapl %eax */
+ movl %eax, 24(%esp)
+ movl 28(%esi), %eax
+.byte 15
+.byte 200 /* bswapl %eax */
+ movl %eax, 28(%esp)
+ movl 32(%esi), %eax
+.byte 15
+.byte 200 /* bswapl %eax */
+ movl %eax, 32(%esp)
+ movl 36(%esi), %eax
+.byte 15
+.byte 200 /* bswapl %eax */
+ movl %eax, 36(%esp)
+ movl 40(%esi), %eax
+.byte 15
+.byte 200 /* bswapl %eax */
+ movl %eax, 40(%esp)
+ movl 44(%esi), %eax
+.byte 15
+.byte 200 /* bswapl %eax */
+ movl %eax, 44(%esp)
+ movl 48(%esi), %eax
+.byte 15
+.byte 200 /* bswapl %eax */
+ movl %eax, 48(%esp)
+ movl 52(%esi), %eax
+.byte 15
+.byte 200 /* bswapl %eax */
+ movl %eax, 52(%esp)
+ movl 56(%esi), %eax
+.byte 15
+.byte 200 /* bswapl %eax */
+ movl %eax, 56(%esp)
+ movl 60(%esi), %eax
+.byte 15
+.byte 200 /* bswapl %eax */
+ movl %eax, 60(%esp)
+ /* We now have the X array on the stack */
+ /* starting at sp-4 */
+ movl %esi, 64(%esp)
+
+ /* Start processing */
+ movl (%ebp), %eax
+ /* 00_15 0 */
+ movl %ecx, %esi
+ movl %eax, %ebp
+ xorl %edx, %esi
+ roll $5, %ebp
+ andl %ebx, %esi
+ addl %edi, %ebp
+.byte 209
+.byte 203 /* rorl $1 %ebx */
+ movl (%esp), %edi
+.byte 209
+.byte 203 /* rorl $1 %ebx */
+ xorl %edx, %esi
+ leal 1518500249(%ebp,%edi,1),%ebp
+ movl %ebx, %edi
+ addl %ebp, %esi
+ xorl %ecx, %edi
+ movl %esi, %ebp
+ andl %eax, %edi
+ roll $5, %ebp
+ addl %edx, %ebp
+ movl 4(%esp), %edx
+.byte 209
+.byte 200 /* rorl $1 %eax */
+ xorl %ecx, %edi
+.byte 209
+.byte 200 /* rorl $1 %eax */
+ leal 1518500249(%ebp,%edx,1),%ebp
+ addl %ebp, %edi
+ /* 00_15 2 */
+ movl %eax, %edx
+ movl %edi, %ebp
+ xorl %ebx, %edx
+ roll $5, %ebp
+ andl %esi, %edx
+ addl %ecx, %ebp
+.byte 209
+.byte 206 /* rorl $1 %esi */
+ movl 8(%esp), %ecx
+.byte 209
+.byte 206 /* rorl $1 %esi */
+ xorl %ebx, %edx
+ leal 1518500249(%ebp,%ecx,1),%ebp
+ movl %esi, %ecx
+ addl %ebp, %edx
+ xorl %eax, %ecx
+ movl %edx, %ebp
+ andl %edi, %ecx
+ roll $5, %ebp
+ addl %ebx, %ebp
+ movl 12(%esp), %ebx
+.byte 209
+.byte 207 /* rorl $1 %edi */
+ xorl %eax, %ecx
+.byte 209
+.byte 207 /* rorl $1 %edi */
+ leal 1518500249(%ebp,%ebx,1),%ebp
+ addl %ebp, %ecx
+ /* 00_15 4 */
+ movl %edi, %ebx
+ movl %ecx, %ebp
+ xorl %esi, %ebx
+ roll $5, %ebp
+ andl %edx, %ebx
+ addl %eax, %ebp
+.byte 209
+.byte 202 /* rorl $1 %edx */
+ movl 16(%esp), %eax
+.byte 209
+.byte 202 /* rorl $1 %edx */
+ xorl %esi, %ebx
+ leal 1518500249(%ebp,%eax,1),%ebp
+ movl %edx, %eax
+ addl %ebp, %ebx
+ xorl %edi, %eax
+ movl %ebx, %ebp
+ andl %ecx, %eax
+ roll $5, %ebp
+ addl %esi, %ebp
+ movl 20(%esp), %esi
+.byte 209
+.byte 201 /* rorl $1 %ecx */
+ xorl %edi, %eax
+.byte 209
+.byte 201 /* rorl $1 %ecx */
+ leal 1518500249(%ebp,%esi,1),%ebp
+ addl %ebp, %eax
+ /* 00_15 6 */
+ movl %ecx, %esi
+ movl %eax, %ebp
+ xorl %edx, %esi
+ roll $5, %ebp
+ andl %ebx, %esi
+ addl %edi, %ebp
+.byte 209
+.byte 203 /* rorl $1 %ebx */
+ movl 24(%esp), %edi
+.byte 209
+.byte 203 /* rorl $1 %ebx */
+ xorl %edx, %esi
+ leal 1518500249(%ebp,%edi,1),%ebp
+ movl %ebx, %edi
+ addl %ebp, %esi
+ xorl %ecx, %edi
+ movl %esi, %ebp
+ andl %eax, %edi
+ roll $5, %ebp
+ addl %edx, %ebp
+ movl 28(%esp), %edx
+.byte 209
+.byte 200 /* rorl $1 %eax */
+ xorl %ecx, %edi
+.byte 209
+.byte 200 /* rorl $1 %eax */
+ leal 1518500249(%ebp,%edx,1),%ebp
+ addl %ebp, %edi
+ /* 00_15 8 */
+ movl %eax, %edx
+ movl %edi, %ebp
+ xorl %ebx, %edx
+ roll $5, %ebp
+ andl %esi, %edx
+ addl %ecx, %ebp
+.byte 209
+.byte 206 /* rorl $1 %esi */
+ movl 32(%esp), %ecx
+.byte 209
+.byte 206 /* rorl $1 %esi */
+ xorl %ebx, %edx
+ leal 1518500249(%ebp,%ecx,1),%ebp
+ movl %esi, %ecx
+ addl %ebp, %edx
+ xorl %eax, %ecx
+ movl %edx, %ebp
+ andl %edi, %ecx
+ roll $5, %ebp
+ addl %ebx, %ebp
+ movl 36(%esp), %ebx
+.byte 209
+.byte 207 /* rorl $1 %edi */
+ xorl %eax, %ecx
+.byte 209
+.byte 207 /* rorl $1 %edi */
+ leal 1518500249(%ebp,%ebx,1),%ebp
+ addl %ebp, %ecx
+ /* 00_15 10 */
+ movl %edi, %ebx
+ movl %ecx, %ebp
+ xorl %esi, %ebx
+ roll $5, %ebp
+ andl %edx, %ebx
+ addl %eax, %ebp
+.byte 209
+.byte 202 /* rorl $1 %edx */
+ movl 40(%esp), %eax
+.byte 209
+.byte 202 /* rorl $1 %edx */
+ xorl %esi, %ebx
+ leal 1518500249(%ebp,%eax,1),%ebp
+ movl %edx, %eax
+ addl %ebp, %ebx
+ xorl %edi, %eax
+ movl %ebx, %ebp
+ andl %ecx, %eax
+ roll $5, %ebp
+ addl %esi, %ebp
+ movl 44(%esp), %esi
+.byte 209
+.byte 201 /* rorl $1 %ecx */
+ xorl %edi, %eax
+.byte 209
+.byte 201 /* rorl $1 %ecx */
+ leal 1518500249(%ebp,%esi,1),%ebp
+ addl %ebp, %eax
+ /* 00_15 12 */
+ movl %ecx, %esi
+ movl %eax, %ebp
+ xorl %edx, %esi
+ roll $5, %ebp
+ andl %ebx, %esi
+ addl %edi, %ebp
+.byte 209
+.byte 203 /* rorl $1 %ebx */
+ movl 48(%esp), %edi
+.byte 209
+.byte 203 /* rorl $1 %ebx */
+ xorl %edx, %esi
+ leal 1518500249(%ebp,%edi,1),%ebp
+ movl %ebx, %edi
+ addl %ebp, %esi
+ xorl %ecx, %edi
+ movl %esi, %ebp
+ andl %eax, %edi
+ roll $5, %ebp
+ addl %edx, %ebp
+ movl 52(%esp), %edx
+.byte 209
+.byte 200 /* rorl $1 %eax */
+ xorl %ecx, %edi
+.byte 209
+.byte 200 /* rorl $1 %eax */
+ leal 1518500249(%ebp,%edx,1),%ebp
+ addl %ebp, %edi
+ /* 00_15 14 */
+ movl %eax, %edx
+ movl %edi, %ebp
+ xorl %ebx, %edx
+ roll $5, %ebp
+ andl %esi, %edx
+ addl %ecx, %ebp
+.byte 209
+.byte 206 /* rorl $1 %esi */
+ movl 56(%esp), %ecx
+.byte 209
+.byte 206 /* rorl $1 %esi */
+ xorl %ebx, %edx
+ leal 1518500249(%ebp,%ecx,1),%ebp
+ movl %esi, %ecx
+ addl %ebp, %edx
+ xorl %eax, %ecx
+ movl %edx, %ebp
+ andl %edi, %ecx
+ roll $5, %ebp
+ addl %ebx, %ebp
+ movl 60(%esp), %ebx
+.byte 209
+.byte 207 /* rorl $1 %edi */
+ xorl %eax, %ecx
+.byte 209
+.byte 207 /* rorl $1 %edi */
+ leal 1518500249(%ebp,%ebx,1),%ebp
+ addl %ebp, %ecx
+ /* 16_19 16 */
+ nop
+ movl (%esp), %ebp
+ movl 8(%esp), %ebx
+ xorl %ebp, %ebx
+ movl 32(%esp), %ebp
+ xorl %ebp, %ebx
+ movl 52(%esp), %ebp
+ xorl %ebp, %ebx
+ movl %edi, %ebp
+.byte 209
+.byte 195 /* roll $1 %ebx */
+ xorl %esi, %ebp
+ movl %ebx, (%esp)
+ andl %edx, %ebp
+ leal 1518500249(%ebx,%eax,1),%ebx
+ xorl %esi, %ebp
+ movl %ecx, %eax
+ addl %ebp, %ebx
+ roll $5, %eax
+.byte 209
+.byte 202 /* rorl $1 %edx */
+ addl %eax, %ebx
+ movl 4(%esp), %eax
+ movl 12(%esp), %ebp
+ xorl %ebp, %eax
+ movl 36(%esp), %ebp
+ xorl %ebp, %eax
+ movl 56(%esp), %ebp
+.byte 209
+.byte 202 /* rorl $1 %edx */
+ xorl %ebp, %eax
+.byte 209
+.byte 192 /* roll $1 %eax */
+ movl %edx, %ebp
+ xorl %edi, %ebp
+ movl %eax, 4(%esp)
+ andl %ecx, %ebp
+ leal 1518500249(%eax,%esi,1),%eax
+ xorl %edi, %ebp
+ movl %ebx, %esi
+ roll $5, %esi
+.byte 209
+.byte 201 /* rorl $1 %ecx */
+ addl %esi, %eax
+.byte 209
+.byte 201 /* rorl $1 %ecx */
+ addl %ebp, %eax
+ /* 16_19 18 */
+ movl 8(%esp), %ebp
+ movl 16(%esp), %esi
+ xorl %ebp, %esi
+ movl 40(%esp), %ebp
+ xorl %ebp, %esi
+ movl 60(%esp), %ebp
+ xorl %ebp, %esi
+ movl %ecx, %ebp
+.byte 209
+.byte 198 /* roll $1 %esi */
+ xorl %edx, %ebp
+ movl %esi, 8(%esp)
+ andl %ebx, %ebp
+ leal 1518500249(%esi,%edi,1),%esi
+ xorl %edx, %ebp
+ movl %eax, %edi
+ addl %ebp, %esi
+ roll $5, %edi
+.byte 209
+.byte 203 /* rorl $1 %ebx */
+ addl %edi, %esi
+ movl 12(%esp), %edi
+ movl 20(%esp), %ebp
+ xorl %ebp, %edi
+ movl 44(%esp), %ebp
+ xorl %ebp, %edi
+ movl (%esp), %ebp
+.byte 209
+.byte 203 /* rorl $1 %ebx */
+ xorl %ebp, %edi
+.byte 209
+.byte 199 /* roll $1 %edi */
+ movl %ebx, %ebp
+ xorl %ecx, %ebp
+ movl %edi, 12(%esp)
+ andl %eax, %ebp
+ leal 1518500249(%edi,%edx,1),%edi
+ xorl %ecx, %ebp
+ movl %esi, %edx
+ roll $5, %edx
+.byte 209
+.byte 200 /* rorl $1 %eax */
+ addl %edx, %edi
+.byte 209
+.byte 200 /* rorl $1 %eax */
+ addl %ebp, %edi
+ /* 20_39 20 */
+ movl 16(%esp), %edx
+ movl 24(%esp), %ebp
+ xorl %ebp, %edx
+ movl 48(%esp), %ebp
+ xorl %ebp, %edx
+ movl 4(%esp), %ebp
+ xorl %ebp, %edx
+ movl %esi, %ebp
+.byte 209
+.byte 194 /* roll $1 %edx */
+ xorl %eax, %ebp
+ movl %edx, 16(%esp)
+ xorl %ebx, %ebp
+ leal 1859775393(%edx,%ecx,1),%edx
+ movl %edi, %ecx
+ roll $5, %ecx
+.byte 209
+.byte 206 /* rorl $1 %esi */
+ addl %ebp, %ecx
+.byte 209
+.byte 206 /* rorl $1 %esi */
+ addl %ecx, %edx
+ /* 20_39 21 */
+ movl 20(%esp), %ecx
+ movl 28(%esp), %ebp
+ xorl %ebp, %ecx
+ movl 52(%esp), %ebp
+ xorl %ebp, %ecx
+ movl 8(%esp), %ebp
+ xorl %ebp, %ecx
+ movl %edi, %ebp
+.byte 209
+.byte 193 /* roll $1 %ecx */
+ xorl %esi, %ebp
+ movl %ecx, 20(%esp)
+ xorl %eax, %ebp
+ leal 1859775393(%ecx,%ebx,1),%ecx
+ movl %edx, %ebx
+ roll $5, %ebx
+.byte 209
+.byte 207 /* rorl $1 %edi */
+ addl %ebp, %ebx
+.byte 209
+.byte 207 /* rorl $1 %edi */
+ addl %ebx, %ecx
+ /* 20_39 22 */
+ movl 24(%esp), %ebx
+ movl 32(%esp), %ebp
+ xorl %ebp, %ebx
+ movl 56(%esp), %ebp
+ xorl %ebp, %ebx
+ movl 12(%esp), %ebp
+ xorl %ebp, %ebx
+ movl %edx, %ebp
+.byte 209
+.byte 195 /* roll $1 %ebx */
+ xorl %edi, %ebp
+ movl %ebx, 24(%esp)
+ xorl %esi, %ebp
+ leal 1859775393(%ebx,%eax,1),%ebx
+ movl %ecx, %eax
+ roll $5, %eax
+.byte 209
+.byte 202 /* rorl $1 %edx */
+ addl %ebp, %eax
+.byte 209
+.byte 202 /* rorl $1 %edx */
+ addl %eax, %ebx
+ /* 20_39 23 */
+ movl 28(%esp), %eax
+ movl 36(%esp), %ebp
+ xorl %ebp, %eax
+ movl 60(%esp), %ebp
+ xorl %ebp, %eax
+ movl 16(%esp), %ebp
+ xorl %ebp, %eax
+ movl %ecx, %ebp
+.byte 209
+.byte 192 /* roll $1 %eax */
+ xorl %edx, %ebp
+ movl %eax, 28(%esp)
+ xorl %edi, %ebp
+ leal 1859775393(%eax,%esi,1),%eax
+ movl %ebx, %esi
+ roll $5, %esi
+.byte 209
+.byte 201 /* rorl $1 %ecx */
+ addl %ebp, %esi
+.byte 209
+.byte 201 /* rorl $1 %ecx */
+ addl %esi, %eax
+ /* 20_39 24 */
+ movl 32(%esp), %esi
+ movl 40(%esp), %ebp
+ xorl %ebp, %esi
+ movl (%esp), %ebp
+ xorl %ebp, %esi
+ movl 20(%esp), %ebp
+ xorl %ebp, %esi
+ movl %ebx, %ebp
+.byte 209
+.byte 198 /* roll $1 %esi */
+ xorl %ecx, %ebp
+ movl %esi, 32(%esp)
+ xorl %edx, %ebp
+ leal 1859775393(%esi,%edi,1),%esi
+ movl %eax, %edi
+ roll $5, %edi
+.byte 209
+.byte 203 /* rorl $1 %ebx */
+ addl %ebp, %edi
+.byte 209
+.byte 203 /* rorl $1 %ebx */
+ addl %edi, %esi
+ /* 20_39 25 */
+ movl 36(%esp), %edi
+ movl 44(%esp), %ebp
+ xorl %ebp, %edi
+ movl 4(%esp), %ebp
+ xorl %ebp, %edi
+ movl 24(%esp), %ebp
+ xorl %ebp, %edi
+ movl %eax, %ebp
+.byte 209
+.byte 199 /* roll $1 %edi */
+ xorl %ebx, %ebp
+ movl %edi, 36(%esp)
+ xorl %ecx, %ebp
+ leal 1859775393(%edi,%edx,1),%edi
+ movl %esi, %edx
+ roll $5, %edx
+.byte 209
+.byte 200 /* rorl $1 %eax */
+ addl %ebp, %edx
+.byte 209
+.byte 200 /* rorl $1 %eax */
+ addl %edx, %edi
+ /* 20_39 26 */
+ movl 40(%esp), %edx
+ movl 48(%esp), %ebp
+ xorl %ebp, %edx
+ movl 8(%esp), %ebp
+ xorl %ebp, %edx
+ movl 28(%esp), %ebp
+ xorl %ebp, %edx
+ movl %esi, %ebp
+.byte 209
+.byte 194 /* roll $1 %edx */
+ xorl %eax, %ebp
+ movl %edx, 40(%esp)
+ xorl %ebx, %ebp
+ leal 1859775393(%edx,%ecx,1),%edx
+ movl %edi, %ecx
+ roll $5, %ecx
+.byte 209
+.byte 206 /* rorl $1 %esi */
+ addl %ebp, %ecx
+.byte 209
+.byte 206 /* rorl $1 %esi */
+ addl %ecx, %edx
+ /* 20_39 27 */
+ movl 44(%esp), %ecx
+ movl 52(%esp), %ebp
+ xorl %ebp, %ecx
+ movl 12(%esp), %ebp
+ xorl %ebp, %ecx
+ movl 32(%esp), %ebp
+ xorl %ebp, %ecx
+ movl %edi, %ebp
+.byte 209
+.byte 193 /* roll $1 %ecx */
+ xorl %esi, %ebp
+ movl %ecx, 44(%esp)
+ xorl %eax, %ebp
+ leal 1859775393(%ecx,%ebx,1),%ecx
+ movl %edx, %ebx
+ roll $5, %ebx
+.byte 209
+.byte 207 /* rorl $1 %edi */
+ addl %ebp, %ebx
+.byte 209
+.byte 207 /* rorl $1 %edi */
+ addl %ebx, %ecx
+ /* 20_39 28 */
+ movl 48(%esp), %ebx
+ movl 56(%esp), %ebp
+ xorl %ebp, %ebx
+ movl 16(%esp), %ebp
+ xorl %ebp, %ebx
+ movl 36(%esp), %ebp
+ xorl %ebp, %ebx
+ movl %edx, %ebp
+.byte 209
+.byte 195 /* roll $1 %ebx */
+ xorl %edi, %ebp
+ movl %ebx, 48(%esp)
+ xorl %esi, %ebp
+ leal 1859775393(%ebx,%eax,1),%ebx
+ movl %ecx, %eax
+ roll $5, %eax
+.byte 209
+.byte 202 /* rorl $1 %edx */
+ addl %ebp, %eax
+.byte 209
+.byte 202 /* rorl $1 %edx */
+ addl %eax, %ebx
+ /* 20_39 29 */
+ movl 52(%esp), %eax
+ movl 60(%esp), %ebp
+ xorl %ebp, %eax
+ movl 20(%esp), %ebp
+ xorl %ebp, %eax
+ movl 40(%esp), %ebp
+ xorl %ebp, %eax
+ movl %ecx, %ebp
+.byte 209
+.byte 192 /* roll $1 %eax */
+ xorl %edx, %ebp
+ movl %eax, 52(%esp)
+ xorl %edi, %ebp
+ leal 1859775393(%eax,%esi,1),%eax
+ movl %ebx, %esi
+ roll $5, %esi
+.byte 209
+.byte 201 /* rorl $1 %ecx */
+ addl %ebp, %esi
+.byte 209
+.byte 201 /* rorl $1 %ecx */
+ addl %esi, %eax
+ /* 20_39 30 */
+ movl 56(%esp), %esi
+ movl (%esp), %ebp
+ xorl %ebp, %esi
+ movl 24(%esp), %ebp
+ xorl %ebp, %esi
+ movl 44(%esp), %ebp
+ xorl %ebp, %esi
+ movl %ebx, %ebp
+.byte 209
+.byte 198 /* roll $1 %esi */
+ xorl %ecx, %ebp
+ movl %esi, 56(%esp)
+ xorl %edx, %ebp
+ leal 1859775393(%esi,%edi,1),%esi
+ movl %eax, %edi
+ roll $5, %edi
+.byte 209
+.byte 203 /* rorl $1 %ebx */
+ addl %ebp, %edi
+.byte 209
+.byte 203 /* rorl $1 %ebx */
+ addl %edi, %esi
+ /* 20_39 31 */
+ movl 60(%esp), %edi
+ movl 4(%esp), %ebp
+ xorl %ebp, %edi
+ movl 28(%esp), %ebp
+ xorl %ebp, %edi
+ movl 48(%esp), %ebp
+ xorl %ebp, %edi
+ movl %eax, %ebp
+.byte 209
+.byte 199 /* roll $1 %edi */
+ xorl %ebx, %ebp
+ movl %edi, 60(%esp)
+ xorl %ecx, %ebp
+ leal 1859775393(%edi,%edx,1),%edi
+ movl %esi, %edx
+ roll $5, %edx
+.byte 209
+.byte 200 /* rorl $1 %eax */
+ addl %ebp, %edx
+.byte 209
+.byte 200 /* rorl $1 %eax */
+ addl %edx, %edi
+ /* 20_39 32 */
+ movl (%esp), %edx
+ movl 8(%esp), %ebp
+ xorl %ebp, %edx
+ movl 32(%esp), %ebp
+ xorl %ebp, %edx
+ movl 52(%esp), %ebp
+ xorl %ebp, %edx
+ movl %esi, %ebp
+.byte 209
+.byte 194 /* roll $1 %edx */
+ xorl %eax, %ebp
+ movl %edx, (%esp)
+ xorl %ebx, %ebp
+ leal 1859775393(%edx,%ecx,1),%edx
+ movl %edi, %ecx
+ roll $5, %ecx
+.byte 209
+.byte 206 /* rorl $1 %esi */
+ addl %ebp, %ecx
+.byte 209
+.byte 206 /* rorl $1 %esi */
+ addl %ecx, %edx
+ /* 20_39 33 */
+ movl 4(%esp), %ecx
+ movl 12(%esp), %ebp
+ xorl %ebp, %ecx
+ movl 36(%esp), %ebp
+ xorl %ebp, %ecx
+ movl 56(%esp), %ebp
+ xorl %ebp, %ecx
+ movl %edi, %ebp
+.byte 209
+.byte 193 /* roll $1 %ecx */
+ xorl %esi, %ebp
+ movl %ecx, 4(%esp)
+ xorl %eax, %ebp
+ leal 1859775393(%ecx,%ebx,1),%ecx
+ movl %edx, %ebx
+ roll $5, %ebx
+.byte 209
+.byte 207 /* rorl $1 %edi */
+ addl %ebp, %ebx
+.byte 209
+.byte 207 /* rorl $1 %edi */
+ addl %ebx, %ecx
+ /* 20_39 34 */
+ movl 8(%esp), %ebx
+ movl 16(%esp), %ebp
+ xorl %ebp, %ebx
+ movl 40(%esp), %ebp
+ xorl %ebp, %ebx
+ movl 60(%esp), %ebp
+ xorl %ebp, %ebx
+ movl %edx, %ebp
+.byte 209
+.byte 195 /* roll $1 %ebx */
+ xorl %edi, %ebp
+ movl %ebx, 8(%esp)
+ xorl %esi, %ebp
+ leal 1859775393(%ebx,%eax,1),%ebx
+ movl %ecx, %eax
+ roll $5, %eax
+.byte 209
+.byte 202 /* rorl $1 %edx */
+ addl %ebp, %eax
+.byte 209
+.byte 202 /* rorl $1 %edx */
+ addl %eax, %ebx
+ /* 20_39 35 */
+ movl 12(%esp), %eax
+ movl 20(%esp), %ebp
+ xorl %ebp, %eax
+ movl 44(%esp), %ebp
+ xorl %ebp, %eax
+ movl (%esp), %ebp
+ xorl %ebp, %eax
+ movl %ecx, %ebp
+.byte 209
+.byte 192 /* roll $1 %eax */
+ xorl %edx, %ebp
+ movl %eax, 12(%esp)
+ xorl %edi, %ebp
+ leal 1859775393(%eax,%esi,1),%eax
+ movl %ebx, %esi
+ roll $5, %esi
+.byte 209
+.byte 201 /* rorl $1 %ecx */
+ addl %ebp, %esi
+.byte 209
+.byte 201 /* rorl $1 %ecx */
+ addl %esi, %eax
+ /* 20_39 36 */
+ movl 16(%esp), %esi
+ movl 24(%esp), %ebp
+ xorl %ebp, %esi
+ movl 48(%esp), %ebp
+ xorl %ebp, %esi
+ movl 4(%esp), %ebp
+ xorl %ebp, %esi
+ movl %ebx, %ebp
+.byte 209
+.byte 198 /* roll $1 %esi */
+ xorl %ecx, %ebp
+ movl %esi, 16(%esp)
+ xorl %edx, %ebp
+ leal 1859775393(%esi,%edi,1),%esi
+ movl %eax, %edi
+ roll $5, %edi
+.byte 209
+.byte 203 /* rorl $1 %ebx */
+ addl %ebp, %edi
+.byte 209
+.byte 203 /* rorl $1 %ebx */
+ addl %edi, %esi
+ /* 20_39 37 */
+ movl 20(%esp), %edi
+ movl 28(%esp), %ebp
+ xorl %ebp, %edi
+ movl 52(%esp), %ebp
+ xorl %ebp, %edi
+ movl 8(%esp), %ebp
+ xorl %ebp, %edi
+ movl %eax, %ebp
+.byte 209
+.byte 199 /* roll $1 %edi */
+ xorl %ebx, %ebp
+ movl %edi, 20(%esp)
+ xorl %ecx, %ebp
+ leal 1859775393(%edi,%edx,1),%edi
+ movl %esi, %edx
+ roll $5, %edx
+.byte 209
+.byte 200 /* rorl $1 %eax */
+ addl %ebp, %edx
+.byte 209
+.byte 200 /* rorl $1 %eax */
+ addl %edx, %edi
+ /* 20_39 38 */
+ movl 24(%esp), %edx
+ movl 32(%esp), %ebp
+ xorl %ebp, %edx
+ movl 56(%esp), %ebp
+ xorl %ebp, %edx
+ movl 12(%esp), %ebp
+ xorl %ebp, %edx
+ movl %esi, %ebp
+.byte 209
+.byte 194 /* roll $1 %edx */
+ xorl %eax, %ebp
+ movl %edx, 24(%esp)
+ xorl %ebx, %ebp
+ leal 1859775393(%edx,%ecx,1),%edx
+ movl %edi, %ecx
+ roll $5, %ecx
+.byte 209
+.byte 206 /* rorl $1 %esi */
+ addl %ebp, %ecx
+.byte 209
+.byte 206 /* rorl $1 %esi */
+ addl %ecx, %edx
+ /* 20_39 39 */
+ movl 28(%esp), %ecx
+ movl 36(%esp), %ebp
+ xorl %ebp, %ecx
+ movl 60(%esp), %ebp
+ xorl %ebp, %ecx
+ movl 16(%esp), %ebp
+ xorl %ebp, %ecx
+ movl %edi, %ebp
+.byte 209
+.byte 193 /* roll $1 %ecx */
+ xorl %esi, %ebp
+ movl %ecx, 28(%esp)
+ xorl %eax, %ebp
+ leal 1859775393(%ecx,%ebx,1),%ecx
+ movl %edx, %ebx
+ roll $5, %ebx
+.byte 209
+.byte 207 /* rorl $1 %edi */
+ addl %ebp, %ebx
+.byte 209
+.byte 207 /* rorl $1 %edi */
+ addl %ebx, %ecx
+ /* 40_59 40 */
+ movl 32(%esp), %ebx
+ movl 40(%esp), %ebp
+ xorl %ebp, %ebx
+ movl (%esp), %ebp
+ xorl %ebp, %ebx
+ movl 20(%esp), %ebp
+ xorl %ebp, %ebx
+ movl %edx, %ebp
+.byte 209
+.byte 195 /* roll $1 %ebx */
+ orl %edi, %ebp
+ movl %ebx, 32(%esp)
+ andl %esi, %ebp
+ leal 2400959708(%ebx,%eax,1),%ebx
+ movl %edx, %eax
+.byte 209
+.byte 202 /* rorl $1 %edx */
+ andl %edi, %eax
+ orl %eax, %ebp
+ movl %ecx, %eax
+ roll $5, %eax
+ addl %eax, %ebp
+ movl 36(%esp), %eax
+ addl %ebp, %ebx
+ movl 44(%esp), %ebp
+ xorl %ebp, %eax
+ movl 4(%esp), %ebp
+ xorl %ebp, %eax
+ movl 24(%esp), %ebp
+.byte 209
+.byte 202 /* rorl $1 %edx */
+ xorl %ebp, %eax
+.byte 209
+.byte 192 /* roll $1 %eax */
+ movl %ecx, %ebp
+ movl %eax, 36(%esp)
+ orl %edx, %ebp
+ leal 2400959708(%eax,%esi,1),%eax
+ movl %ecx, %esi
+ andl %edi, %ebp
+ andl %edx, %esi
+ orl %esi, %ebp
+ movl %ebx, %esi
+ roll $5, %esi
+.byte 209
+.byte 201 /* rorl $1 %ecx */
+ addl %esi, %ebp
+.byte 209
+.byte 201 /* rorl $1 %ecx */
+ addl %ebp, %eax
+ /* 40_59 41 */
+ /* 40_59 42 */
+ movl 40(%esp), %esi
+ movl 48(%esp), %ebp
+ xorl %ebp, %esi
+ movl 8(%esp), %ebp
+ xorl %ebp, %esi
+ movl 28(%esp), %ebp
+ xorl %ebp, %esi
+ movl %ebx, %ebp
+.byte 209
+.byte 198 /* roll $1 %esi */
+ orl %ecx, %ebp
+ movl %esi, 40(%esp)
+ andl %edx, %ebp
+ leal 2400959708(%esi,%edi,1),%esi
+ movl %ebx, %edi
+.byte 209
+.byte 203 /* rorl $1 %ebx */
+ andl %ecx, %edi
+ orl %edi, %ebp
+ movl %eax, %edi
+ roll $5, %edi
+ addl %edi, %ebp
+ movl 44(%esp), %edi
+ addl %ebp, %esi
+ movl 52(%esp), %ebp
+ xorl %ebp, %edi
+ movl 12(%esp), %ebp
+ xorl %ebp, %edi
+ movl 32(%esp), %ebp
+.byte 209
+.byte 203 /* rorl $1 %ebx */
+ xorl %ebp, %edi
+.byte 209
+.byte 199 /* roll $1 %edi */
+ movl %eax, %ebp
+ movl %edi, 44(%esp)
+ orl %ebx, %ebp
+ leal 2400959708(%edi,%edx,1),%edi
+ movl %eax, %edx
+ andl %ecx, %ebp
+ andl %ebx, %edx
+ orl %edx, %ebp
+ movl %esi, %edx
+ roll $5, %edx
+.byte 209
+.byte 200 /* rorl $1 %eax */
+ addl %edx, %ebp
+.byte 209
+.byte 200 /* rorl $1 %eax */
+ addl %ebp, %edi
+ /* 40_59 43 */
+ /* 40_59 44 */
+ movl 48(%esp), %edx
+ movl 56(%esp), %ebp
+ xorl %ebp, %edx
+ movl 16(%esp), %ebp
+ xorl %ebp, %edx
+ movl 36(%esp), %ebp
+ xorl %ebp, %edx
+ movl %esi, %ebp
+.byte 209
+.byte 194 /* roll $1 %edx */
+ orl %eax, %ebp
+ movl %edx, 48(%esp)
+ andl %ebx, %ebp
+ leal 2400959708(%edx,%ecx,1),%edx
+ movl %esi, %ecx
+.byte 209
+.byte 206 /* rorl $1 %esi */
+ andl %eax, %ecx
+ orl %ecx, %ebp
+ movl %edi, %ecx
+ roll $5, %ecx
+ addl %ecx, %ebp
+ movl 52(%esp), %ecx
+ addl %ebp, %edx
+ movl 60(%esp), %ebp
+ xorl %ebp, %ecx
+ movl 20(%esp), %ebp
+ xorl %ebp, %ecx
+ movl 40(%esp), %ebp
+.byte 209
+.byte 206 /* rorl $1 %esi */
+ xorl %ebp, %ecx
+.byte 209
+.byte 193 /* roll $1 %ecx */
+ movl %edi, %ebp
+ movl %ecx, 52(%esp)
+ orl %esi, %ebp
+ leal 2400959708(%ecx,%ebx,1),%ecx
+ movl %edi, %ebx
+ andl %eax, %ebp
+ andl %esi, %ebx
+ orl %ebx, %ebp
+ movl %edx, %ebx
+ roll $5, %ebx
+.byte 209
+.byte 207 /* rorl $1 %edi */
+ addl %ebx, %ebp
+.byte 209
+.byte 207 /* rorl $1 %edi */
+ addl %ebp, %ecx
+ /* 40_59 45 */
+ /* 40_59 46 */
+ movl 56(%esp), %ebx
+ movl (%esp), %ebp
+ xorl %ebp, %ebx
+ movl 24(%esp), %ebp
+ xorl %ebp, %ebx
+ movl 44(%esp), %ebp
+ xorl %ebp, %ebx
+ movl %edx, %ebp
+.byte 209
+.byte 195 /* roll $1 %ebx */
+ orl %edi, %ebp
+ movl %ebx, 56(%esp)
+ andl %esi, %ebp
+ leal 2400959708(%ebx,%eax,1),%ebx
+ movl %edx, %eax
+.byte 209
+.byte 202 /* rorl $1 %edx */
+ andl %edi, %eax
+ orl %eax, %ebp
+ movl %ecx, %eax
+ roll $5, %eax
+ addl %eax, %ebp
+ movl 60(%esp), %eax
+ addl %ebp, %ebx
+ movl 4(%esp), %ebp
+ xorl %ebp, %eax
+ movl 28(%esp), %ebp
+ xorl %ebp, %eax
+ movl 48(%esp), %ebp
+.byte 209
+.byte 202 /* rorl $1 %edx */
+ xorl %ebp, %eax
+.byte 209
+.byte 192 /* roll $1 %eax */
+ movl %ecx, %ebp
+ movl %eax, 60(%esp)
+ orl %edx, %ebp
+ leal 2400959708(%eax,%esi,1),%eax
+ movl %ecx, %esi
+ andl %edi, %ebp
+ andl %edx, %esi
+ orl %esi, %ebp
+ movl %ebx, %esi
+ roll $5, %esi
+.byte 209
+.byte 201 /* rorl $1 %ecx */
+ addl %esi, %ebp
+.byte 209
+.byte 201 /* rorl $1 %ecx */
+ addl %ebp, %eax
+ /* 40_59 47 */
+ /* 40_59 48 */
+ movl (%esp), %esi
+ movl 8(%esp), %ebp
+ xorl %ebp, %esi
+ movl 32(%esp), %ebp
+ xorl %ebp, %esi
+ movl 52(%esp), %ebp
+ xorl %ebp, %esi
+ movl %ebx, %ebp
+.byte 209
+.byte 198 /* roll $1 %esi */
+ orl %ecx, %ebp
+ movl %esi, (%esp)
+ andl %edx, %ebp
+ leal 2400959708(%esi,%edi,1),%esi
+ movl %ebx, %edi
+.byte 209
+.byte 203 /* rorl $1 %ebx */
+ andl %ecx, %edi
+ orl %edi, %ebp
+ movl %eax, %edi
+ roll $5, %edi
+ addl %edi, %ebp
+ movl 4(%esp), %edi
+ addl %ebp, %esi
+ movl 12(%esp), %ebp
+ xorl %ebp, %edi
+ movl 36(%esp), %ebp
+ xorl %ebp, %edi
+ movl 56(%esp), %ebp
+.byte 209
+.byte 203 /* rorl $1 %ebx */
+ xorl %ebp, %edi
+.byte 209
+.byte 199 /* roll $1 %edi */
+ movl %eax, %ebp
+ movl %edi, 4(%esp)
+ orl %ebx, %ebp
+ leal 2400959708(%edi,%edx,1),%edi
+ movl %eax, %edx
+ andl %ecx, %ebp
+ andl %ebx, %edx
+ orl %edx, %ebp
+ movl %esi, %edx
+ roll $5, %edx
+.byte 209
+.byte 200 /* rorl $1 %eax */
+ addl %edx, %ebp
+.byte 209
+.byte 200 /* rorl $1 %eax */
+ addl %ebp, %edi
+ /* 40_59 49 */
+ /* 40_59 50 */
+ movl 8(%esp), %edx
+ movl 16(%esp), %ebp
+ xorl %ebp, %edx
+ movl 40(%esp), %ebp
+ xorl %ebp, %edx
+ movl 60(%esp), %ebp
+ xorl %ebp, %edx
+ movl %esi, %ebp
+.byte 209
+.byte 194 /* roll $1 %edx */
+ orl %eax, %ebp
+ movl %edx, 8(%esp)
+ andl %ebx, %ebp
+ leal 2400959708(%edx,%ecx,1),%edx
+ movl %esi, %ecx
+.byte 209
+.byte 206 /* rorl $1 %esi */
+ andl %eax, %ecx
+ orl %ecx, %ebp
+ movl %edi, %ecx
+ roll $5, %ecx
+ addl %ecx, %ebp
+ movl 12(%esp), %ecx
+ addl %ebp, %edx
+ movl 20(%esp), %ebp
+ xorl %ebp, %ecx
+ movl 44(%esp), %ebp
+ xorl %ebp, %ecx
+ movl (%esp), %ebp
+.byte 209
+.byte 206 /* rorl $1 %esi */
+ xorl %ebp, %ecx
+.byte 209
+.byte 193 /* roll $1 %ecx */
+ movl %edi, %ebp
+ movl %ecx, 12(%esp)
+ orl %esi, %ebp
+ leal 2400959708(%ecx,%ebx,1),%ecx
+ movl %edi, %ebx
+ andl %eax, %ebp
+ andl %esi, %ebx
+ orl %ebx, %ebp
+ movl %edx, %ebx
+ roll $5, %ebx
+.byte 209
+.byte 207 /* rorl $1 %edi */
+ addl %ebx, %ebp
+.byte 209
+.byte 207 /* rorl $1 %edi */
+ addl %ebp, %ecx
+ /* 40_59 51 */
+ /* 40_59 52 */
+ movl 16(%esp), %ebx
+ movl 24(%esp), %ebp
+ xorl %ebp, %ebx
+ movl 48(%esp), %ebp
+ xorl %ebp, %ebx
+ movl 4(%esp), %ebp
+ xorl %ebp, %ebx
+ movl %edx, %ebp
+.byte 209
+.byte 195 /* roll $1 %ebx */
+ orl %edi, %ebp
+ movl %ebx, 16(%esp)
+ andl %esi, %ebp
+ leal 2400959708(%ebx,%eax,1),%ebx
+ movl %edx, %eax
+.byte 209
+.byte 202 /* rorl $1 %edx */
+ andl %edi, %eax
+ orl %eax, %ebp
+ movl %ecx, %eax
+ roll $5, %eax
+ addl %eax, %ebp
+ movl 20(%esp), %eax
+ addl %ebp, %ebx
+ movl 28(%esp), %ebp
+ xorl %ebp, %eax
+ movl 52(%esp), %ebp
+ xorl %ebp, %eax
+ movl 8(%esp), %ebp
+.byte 209
+.byte 202 /* rorl $1 %edx */
+ xorl %ebp, %eax
+.byte 209
+.byte 192 /* roll $1 %eax */
+ movl %ecx, %ebp
+ movl %eax, 20(%esp)
+ orl %edx, %ebp
+ leal 2400959708(%eax,%esi,1),%eax
+ movl %ecx, %esi
+ andl %edi, %ebp
+ andl %edx, %esi
+ orl %esi, %ebp
+ movl %ebx, %esi
+ roll $5, %esi
+.byte 209
+.byte 201 /* rorl $1 %ecx */
+ addl %esi, %ebp
+.byte 209
+.byte 201 /* rorl $1 %ecx */
+ addl %ebp, %eax
+ /* 40_59 53 */
+ /* 40_59 54 */
+ movl 24(%esp), %esi
+ movl 32(%esp), %ebp
+ xorl %ebp, %esi
+ movl 56(%esp), %ebp
+ xorl %ebp, %esi
+ movl 12(%esp), %ebp
+ xorl %ebp, %esi
+ movl %ebx, %ebp
+.byte 209
+.byte 198 /* roll $1 %esi */
+ orl %ecx, %ebp
+ movl %esi, 24(%esp)
+ andl %edx, %ebp
+ leal 2400959708(%esi,%edi,1),%esi
+ movl %ebx, %edi
+.byte 209
+.byte 203 /* rorl $1 %ebx */
+ andl %ecx, %edi
+ orl %edi, %ebp
+ movl %eax, %edi
+ roll $5, %edi
+ addl %edi, %ebp
+ movl 28(%esp), %edi
+ addl %ebp, %esi
+ movl 36(%esp), %ebp
+ xorl %ebp, %edi
+ movl 60(%esp), %ebp
+ xorl %ebp, %edi
+ movl 16(%esp), %ebp
+.byte 209
+.byte 203 /* rorl $1 %ebx */
+ xorl %ebp, %edi
+.byte 209
+.byte 199 /* roll $1 %edi */
+ movl %eax, %ebp
+ movl %edi, 28(%esp)
+ orl %ebx, %ebp
+ leal 2400959708(%edi,%edx,1),%edi
+ movl %eax, %edx
+ andl %ecx, %ebp
+ andl %ebx, %edx
+ orl %edx, %ebp
+ movl %esi, %edx
+ roll $5, %edx
+.byte 209
+.byte 200 /* rorl $1 %eax */
+ addl %edx, %ebp
+.byte 209
+.byte 200 /* rorl $1 %eax */
+ addl %ebp, %edi
+ /* 40_59 55 */
+ /* 40_59 56 */
+ movl 32(%esp), %edx
+ movl 40(%esp), %ebp
+ xorl %ebp, %edx
+ movl (%esp), %ebp
+ xorl %ebp, %edx
+ movl 20(%esp), %ebp
+ xorl %ebp, %edx
+ movl %esi, %ebp
+.byte 209
+.byte 194 /* roll $1 %edx */
+ orl %eax, %ebp
+ movl %edx, 32(%esp)
+ andl %ebx, %ebp
+ leal 2400959708(%edx,%ecx,1),%edx
+ movl %esi, %ecx
+.byte 209
+.byte 206 /* rorl $1 %esi */
+ andl %eax, %ecx
+ orl %ecx, %ebp
+ movl %edi, %ecx
+ roll $5, %ecx
+ addl %ecx, %ebp
+ movl 36(%esp), %ecx
+ addl %ebp, %edx
+ movl 44(%esp), %ebp
+ xorl %ebp, %ecx
+ movl 4(%esp), %ebp
+ xorl %ebp, %ecx
+ movl 24(%esp), %ebp
+.byte 209
+.byte 206 /* rorl $1 %esi */
+ xorl %ebp, %ecx
+.byte 209
+.byte 193 /* roll $1 %ecx */
+ movl %edi, %ebp
+ movl %ecx, 36(%esp)
+ orl %esi, %ebp
+ leal 2400959708(%ecx,%ebx,1),%ecx
+ movl %edi, %ebx
+ andl %eax, %ebp
+ andl %esi, %ebx
+ orl %ebx, %ebp
+ movl %edx, %ebx
+ roll $5, %ebx
+.byte 209
+.byte 207 /* rorl $1 %edi */
+ addl %ebx, %ebp
+.byte 209
+.byte 207 /* rorl $1 %edi */
+ addl %ebp, %ecx
+ /* 40_59 57 */
+ /* 40_59 58 */
+ movl 40(%esp), %ebx
+ movl 48(%esp), %ebp
+ xorl %ebp, %ebx
+ movl 8(%esp), %ebp
+ xorl %ebp, %ebx
+ movl 28(%esp), %ebp
+ xorl %ebp, %ebx
+ movl %edx, %ebp
+.byte 209
+.byte 195 /* roll $1 %ebx */
+ orl %edi, %ebp
+ movl %ebx, 40(%esp)
+ andl %esi, %ebp
+ leal 2400959708(%ebx,%eax,1),%ebx
+ movl %edx, %eax
+.byte 209
+.byte 202 /* rorl $1 %edx */
+ andl %edi, %eax
+ orl %eax, %ebp
+ movl %ecx, %eax
+ roll $5, %eax
+ addl %eax, %ebp
+ movl 44(%esp), %eax
+ addl %ebp, %ebx
+ movl 52(%esp), %ebp
+ xorl %ebp, %eax
+ movl 12(%esp), %ebp
+ xorl %ebp, %eax
+ movl 32(%esp), %ebp
+.byte 209
+.byte 202 /* rorl $1 %edx */
+ xorl %ebp, %eax
+.byte 209
+.byte 192 /* roll $1 %eax */
+ movl %ecx, %ebp
+ movl %eax, 44(%esp)
+ orl %edx, %ebp
+ leal 2400959708(%eax,%esi,1),%eax
+ movl %ecx, %esi
+ andl %edi, %ebp
+ andl %edx, %esi
+ orl %esi, %ebp
+ movl %ebx, %esi
+ roll $5, %esi
+.byte 209
+.byte 201 /* rorl $1 %ecx */
+ addl %esi, %ebp
+.byte 209
+.byte 201 /* rorl $1 %ecx */
+ addl %ebp, %eax
+ /* 40_59 59 */
+ /* 20_39 60 */
+ movl 48(%esp), %esi
+ movl 56(%esp), %ebp
+ xorl %ebp, %esi
+ movl 16(%esp), %ebp
+ xorl %ebp, %esi
+ movl 36(%esp), %ebp
+ xorl %ebp, %esi
+ movl %ebx, %ebp
+.byte 209
+.byte 198 /* roll $1 %esi */
+ xorl %ecx, %ebp
+ movl %esi, 48(%esp)
+ xorl %edx, %ebp
+ leal 3395469782(%esi,%edi,1),%esi
+ movl %eax, %edi
+ roll $5, %edi
+.byte 209
+.byte 203 /* rorl $1 %ebx */
+ addl %ebp, %edi
+.byte 209
+.byte 203 /* rorl $1 %ebx */
+ addl %edi, %esi
+ /* 20_39 61 */
+ movl 52(%esp), %edi
+ movl 60(%esp), %ebp
+ xorl %ebp, %edi
+ movl 20(%esp), %ebp
+ xorl %ebp, %edi
+ movl 40(%esp), %ebp
+ xorl %ebp, %edi
+ movl %eax, %ebp
+.byte 209
+.byte 199 /* roll $1 %edi */
+ xorl %ebx, %ebp
+ movl %edi, 52(%esp)
+ xorl %ecx, %ebp
+ leal 3395469782(%edi,%edx,1),%edi
+ movl %esi, %edx
+ roll $5, %edx
+.byte 209
+.byte 200 /* rorl $1 %eax */
+ addl %ebp, %edx
+.byte 209
+.byte 200 /* rorl $1 %eax */
+ addl %edx, %edi
+ /* 20_39 62 */
+ movl 56(%esp), %edx
+ movl (%esp), %ebp
+ xorl %ebp, %edx
+ movl 24(%esp), %ebp
+ xorl %ebp, %edx
+ movl 44(%esp), %ebp
+ xorl %ebp, %edx
+ movl %esi, %ebp
+.byte 209
+.byte 194 /* roll $1 %edx */
+ xorl %eax, %ebp
+ movl %edx, 56(%esp)
+ xorl %ebx, %ebp
+ leal 3395469782(%edx,%ecx,1),%edx
+ movl %edi, %ecx
+ roll $5, %ecx
+.byte 209
+.byte 206 /* rorl $1 %esi */
+ addl %ebp, %ecx
+.byte 209
+.byte 206 /* rorl $1 %esi */
+ addl %ecx, %edx
+ /* 20_39 63 */
+ movl 60(%esp), %ecx
+ movl 4(%esp), %ebp
+ xorl %ebp, %ecx
+ movl 28(%esp), %ebp
+ xorl %ebp, %ecx
+ movl 48(%esp), %ebp
+ xorl %ebp, %ecx
+ movl %edi, %ebp
+.byte 209
+.byte 193 /* roll $1 %ecx */
+ xorl %esi, %ebp
+ movl %ecx, 60(%esp)
+ xorl %eax, %ebp
+ leal 3395469782(%ecx,%ebx,1),%ecx
+ movl %edx, %ebx
+ roll $5, %ebx
+.byte 209
+.byte 207 /* rorl $1 %edi */
+ addl %ebp, %ebx
+.byte 209
+.byte 207 /* rorl $1 %edi */
+ addl %ebx, %ecx
+ /* 20_39 64 */
+ movl (%esp), %ebx
+ movl 8(%esp), %ebp
+ xorl %ebp, %ebx
+ movl 32(%esp), %ebp
+ xorl %ebp, %ebx
+ movl 52(%esp), %ebp
+ xorl %ebp, %ebx
+ movl %edx, %ebp
+.byte 209
+.byte 195 /* roll $1 %ebx */
+ xorl %edi, %ebp
+ movl %ebx, (%esp)
+ xorl %esi, %ebp
+ leal 3395469782(%ebx,%eax,1),%ebx
+ movl %ecx, %eax
+ roll $5, %eax
+.byte 209
+.byte 202 /* rorl $1 %edx */
+ addl %ebp, %eax
+.byte 209
+.byte 202 /* rorl $1 %edx */
+ addl %eax, %ebx
+ /* 20_39 65 */
+ movl 4(%esp), %eax
+ movl 12(%esp), %ebp
+ xorl %ebp, %eax
+ movl 36(%esp), %ebp
+ xorl %ebp, %eax
+ movl 56(%esp), %ebp
+ xorl %ebp, %eax
+ movl %ecx, %ebp
+.byte 209
+.byte 192 /* roll $1 %eax */
+ xorl %edx, %ebp
+ movl %eax, 4(%esp)
+ xorl %edi, %ebp
+ leal 3395469782(%eax,%esi,1),%eax
+ movl %ebx, %esi
+ roll $5, %esi
+.byte 209
+.byte 201 /* rorl $1 %ecx */
+ addl %ebp, %esi
+.byte 209
+.byte 201 /* rorl $1 %ecx */
+ addl %esi, %eax
+ /* 20_39 66 */
+ movl 8(%esp), %esi
+ movl 16(%esp), %ebp
+ xorl %ebp, %esi
+ movl 40(%esp), %ebp
+ xorl %ebp, %esi
+ movl 60(%esp), %ebp
+ xorl %ebp, %esi
+ movl %ebx, %ebp
+.byte 209
+.byte 198 /* roll $1 %esi */
+ xorl %ecx, %ebp
+ movl %esi, 8(%esp)
+ xorl %edx, %ebp
+ leal 3395469782(%esi,%edi,1),%esi
+ movl %eax, %edi
+ roll $5, %edi
+.byte 209
+.byte 203 /* rorl $1 %ebx */
+ addl %ebp, %edi
+.byte 209
+.byte 203 /* rorl $1 %ebx */
+ addl %edi, %esi
+ /* 20_39 67 */
+ movl 12(%esp), %edi
+ movl 20(%esp), %ebp
+ xorl %ebp, %edi
+ movl 44(%esp), %ebp
+ xorl %ebp, %edi
+ movl (%esp), %ebp
+ xorl %ebp, %edi
+ movl %eax, %ebp
+.byte 209
+.byte 199 /* roll $1 %edi */
+ xorl %ebx, %ebp
+ movl %edi, 12(%esp)
+ xorl %ecx, %ebp
+ leal 3395469782(%edi,%edx,1),%edi
+ movl %esi, %edx
+ roll $5, %edx
+.byte 209
+.byte 200 /* rorl $1 %eax */
+ addl %ebp, %edx
+.byte 209
+.byte 200 /* rorl $1 %eax */
+ addl %edx, %edi
+ /* 20_39 68 */
+ movl 16(%esp), %edx
+ movl 24(%esp), %ebp
+ xorl %ebp, %edx
+ movl 48(%esp), %ebp
+ xorl %ebp, %edx
+ movl 4(%esp), %ebp
+ xorl %ebp, %edx
+ movl %esi, %ebp
+.byte 209
+.byte 194 /* roll $1 %edx */
+ xorl %eax, %ebp
+ movl %edx, 16(%esp)
+ xorl %ebx, %ebp
+ leal 3395469782(%edx,%ecx,1),%edx
+ movl %edi, %ecx
+ roll $5, %ecx
+.byte 209
+.byte 206 /* rorl $1 %esi */
+ addl %ebp, %ecx
+.byte 209
+.byte 206 /* rorl $1 %esi */
+ addl %ecx, %edx
+ /* 20_39 69 */
+ movl 20(%esp), %ecx
+ movl 28(%esp), %ebp
+ xorl %ebp, %ecx
+ movl 52(%esp), %ebp
+ xorl %ebp, %ecx
+ movl 8(%esp), %ebp
+ xorl %ebp, %ecx
+ movl %edi, %ebp
+.byte 209
+.byte 193 /* roll $1 %ecx */
+ xorl %esi, %ebp
+ movl %ecx, 20(%esp)
+ xorl %eax, %ebp
+ leal 3395469782(%ecx,%ebx,1),%ecx
+ movl %edx, %ebx
+ roll $5, %ebx
+.byte 209
+.byte 207 /* rorl $1 %edi */
+ addl %ebp, %ebx
+.byte 209
+.byte 207 /* rorl $1 %edi */
+ addl %ebx, %ecx
+ /* 20_39 70 */
+ movl 24(%esp), %ebx
+ movl 32(%esp), %ebp
+ xorl %ebp, %ebx
+ movl 56(%esp), %ebp
+ xorl %ebp, %ebx
+ movl 12(%esp), %ebp
+ xorl %ebp, %ebx
+ movl %edx, %ebp
+.byte 209
+.byte 195 /* roll $1 %ebx */
+ xorl %edi, %ebp
+ movl %ebx, 24(%esp)
+ xorl %esi, %ebp
+ leal 3395469782(%ebx,%eax,1),%ebx
+ movl %ecx, %eax
+ roll $5, %eax
+.byte 209
+.byte 202 /* rorl $1 %edx */
+ addl %ebp, %eax
+.byte 209
+.byte 202 /* rorl $1 %edx */
+ addl %eax, %ebx
+ /* 20_39 71 */
+ movl 28(%esp), %eax
+ movl 36(%esp), %ebp
+ xorl %ebp, %eax
+ movl 60(%esp), %ebp
+ xorl %ebp, %eax
+ movl 16(%esp), %ebp
+ xorl %ebp, %eax
+ movl %ecx, %ebp
+.byte 209
+.byte 192 /* roll $1 %eax */
+ xorl %edx, %ebp
+ movl %eax, 28(%esp)
+ xorl %edi, %ebp
+ leal 3395469782(%eax,%esi,1),%eax
+ movl %ebx, %esi
+ roll $5, %esi
+.byte 209
+.byte 201 /* rorl $1 %ecx */
+ addl %ebp, %esi
+.byte 209
+.byte 201 /* rorl $1 %ecx */
+ addl %esi, %eax
+ /* 20_39 72 */
+ movl 32(%esp), %esi
+ movl 40(%esp), %ebp
+ xorl %ebp, %esi
+ movl (%esp), %ebp
+ xorl %ebp, %esi
+ movl 20(%esp), %ebp
+ xorl %ebp, %esi
+ movl %ebx, %ebp
+.byte 209
+.byte 198 /* roll $1 %esi */
+ xorl %ecx, %ebp
+ movl %esi, 32(%esp)
+ xorl %edx, %ebp
+ leal 3395469782(%esi,%edi,1),%esi
+ movl %eax, %edi
+ roll $5, %edi
+.byte 209
+.byte 203 /* rorl $1 %ebx */
+ addl %ebp, %edi
+.byte 209
+.byte 203 /* rorl $1 %ebx */
+ addl %edi, %esi
+ /* 20_39 73 */
+ movl 36(%esp), %edi
+ movl 44(%esp), %ebp
+ xorl %ebp, %edi
+ movl 4(%esp), %ebp
+ xorl %ebp, %edi
+ movl 24(%esp), %ebp
+ xorl %ebp, %edi
+ movl %eax, %ebp
+.byte 209
+.byte 199 /* roll $1 %edi */
+ xorl %ebx, %ebp
+ movl %edi, 36(%esp)
+ xorl %ecx, %ebp
+ leal 3395469782(%edi,%edx,1),%edi
+ movl %esi, %edx
+ roll $5, %edx
+.byte 209
+.byte 200 /* rorl $1 %eax */
+ addl %ebp, %edx
+.byte 209
+.byte 200 /* rorl $1 %eax */
+ addl %edx, %edi
+ /* 20_39 74 */
+ movl 40(%esp), %edx
+ movl 48(%esp), %ebp
+ xorl %ebp, %edx
+ movl 8(%esp), %ebp
+ xorl %ebp, %edx
+ movl 28(%esp), %ebp
+ xorl %ebp, %edx
+ movl %esi, %ebp
+.byte 209
+.byte 194 /* roll $1 %edx */
+ xorl %eax, %ebp
+ movl %edx, 40(%esp)
+ xorl %ebx, %ebp
+ leal 3395469782(%edx,%ecx,1),%edx
+ movl %edi, %ecx
+ roll $5, %ecx
+.byte 209
+.byte 206 /* rorl $1 %esi */
+ addl %ebp, %ecx
+.byte 209
+.byte 206 /* rorl $1 %esi */
+ addl %ecx, %edx
+ /* 20_39 75 */
+ movl 44(%esp), %ecx
+ movl 52(%esp), %ebp
+ xorl %ebp, %ecx
+ movl 12(%esp), %ebp
+ xorl %ebp, %ecx
+ movl 32(%esp), %ebp
+ xorl %ebp, %ecx
+ movl %edi, %ebp
+.byte 209
+.byte 193 /* roll $1 %ecx */
+ xorl %esi, %ebp
+ movl %ecx, 44(%esp)
+ xorl %eax, %ebp
+ leal 3395469782(%ecx,%ebx,1),%ecx
+ movl %edx, %ebx
+ roll $5, %ebx
+.byte 209
+.byte 207 /* rorl $1 %edi */
+ addl %ebp, %ebx
+.byte 209
+.byte 207 /* rorl $1 %edi */
+ addl %ebx, %ecx
+ /* 20_39 76 */
+ movl 48(%esp), %ebx
+ movl 56(%esp), %ebp
+ xorl %ebp, %ebx
+ movl 16(%esp), %ebp
+ xorl %ebp, %ebx
+ movl 36(%esp), %ebp
+ xorl %ebp, %ebx
+ movl %edx, %ebp
+.byte 209
+.byte 195 /* roll $1 %ebx */
+ xorl %edi, %ebp
+ movl %ebx, 48(%esp)
+ xorl %esi, %ebp
+ leal 3395469782(%ebx,%eax,1),%ebx
+ movl %ecx, %eax
+ roll $5, %eax
+.byte 209
+.byte 202 /* rorl $1 %edx */
+ addl %ebp, %eax
+.byte 209
+.byte 202 /* rorl $1 %edx */
+ addl %eax, %ebx
+ /* 20_39 77 */
+ movl 52(%esp), %eax
+ movl 60(%esp), %ebp
+ xorl %ebp, %eax
+ movl 20(%esp), %ebp
+ xorl %ebp, %eax
+ movl 40(%esp), %ebp
+ xorl %ebp, %eax
+ movl %ecx, %ebp
+.byte 209
+.byte 192 /* roll $1 %eax */
+ xorl %edx, %ebp
+ movl %eax, 52(%esp)
+ xorl %edi, %ebp
+ leal 3395469782(%eax,%esi,1),%eax
+ movl %ebx, %esi
+ roll $5, %esi
+.byte 209
+.byte 201 /* rorl $1 %ecx */
+ addl %ebp, %esi
+.byte 209
+.byte 201 /* rorl $1 %ecx */
+ addl %esi, %eax
+ /* 20_39 78 */
+ movl 56(%esp), %esi
+ movl (%esp), %ebp
+ xorl %ebp, %esi
+ movl 24(%esp), %ebp
+ xorl %ebp, %esi
+ movl 44(%esp), %ebp
+ xorl %ebp, %esi
+ movl %ebx, %ebp
+.byte 209
+.byte 198 /* roll $1 %esi */
+ xorl %ecx, %ebp
+ movl %esi, 56(%esp)
+ xorl %edx, %ebp
+ leal 3395469782(%esi,%edi,1),%esi
+ movl %eax, %edi
+ roll $5, %edi
+.byte 209
+.byte 203 /* rorl $1 %ebx */
+ addl %ebp, %edi
+.byte 209
+.byte 203 /* rorl $1 %ebx */
+ addl %edi, %esi
+ /* 20_39 79 */
+ movl 60(%esp), %edi
+ movl 4(%esp), %ebp
+ xorl %ebp, %edi
+ movl 28(%esp), %ebp
+ xorl %ebp, %edi
+ movl 48(%esp), %ebp
+ xorl %ebp, %edi
+ movl %eax, %ebp
+.byte 209
+.byte 199 /* roll $1 %edi */
+ xorl %ebx, %ebp
+ movl %edi, 60(%esp)
+ xorl %ecx, %ebp
+ leal 3395469782(%edi,%edx,1),%edi
+ movl %esi, %edx
+ roll $5, %edx
+ addl %ebp, %edx
+ movl 92(%esp), %ebp
+.byte 209
+.byte 200 /* rorl $1 %eax */
+ addl %edx, %edi
+.byte 209
+.byte 200 /* rorl $1 %eax */
+ /* End processing */
+
+ movl 12(%ebp), %edx
+ addl %ebx, %edx
+ movl 4(%ebp), %ebx
+ addl %esi, %ebx
+ movl %eax, %esi
+ movl (%ebp), %eax
+ movl %edx, 12(%ebp)
+ addl %edi, %eax
+ movl 16(%ebp), %edi
+ addl %ecx, %edi
+ movl 8(%ebp), %ecx
+ addl %esi, %ecx
+ movl %eax, (%ebp)
+ movl 64(%esp), %esi
+ movl %ecx, 8(%ebp)
+ addl $64, %esi
+ movl 68(%esp), %eax
+ movl %edi, 16(%ebp)
+ cmpl %esi, %eax
+ movl %ebx, 4(%ebp)
+ jl .L001end
+ movl (%esi), %eax
+ jmp .L000start
+.L001end:
+ addl $72, %esp
+ popl %edi
+ popl %ebx
+ popl %ebp
+ popl %esi
+ ret
+.sha1_block_x86_end:
+ SIZE(sha1_block_x86,.sha1_block_x86_end-sha1_block_x86)
+.ident "desasm.pl"
+#endif
diff --git a/lib/libmd/md2.copyright b/lib/libmd/md2.copyright
new file mode 100644
index 0000000..acef7ba
--- /dev/null
+++ b/lib/libmd/md2.copyright
@@ -0,0 +1,17 @@
+.\" $FreeBSD$
+Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All
+rights reserved.
+.Pp
+License to copy and use this software is granted for
+non-commercial Internet Privacy-Enhanced Mail provided that it is
+identified as the "RSA Data Security, Inc. MD2 Message Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+.Pp
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+.Pp
+These notices must be retained in any copies of any part of this
+documentation and/or software.
diff --git a/lib/libmd/md2.h b/lib/libmd/md2.h
new file mode 100644
index 0000000..f0229f5
--- /dev/null
+++ b/lib/libmd/md2.h
@@ -0,0 +1,46 @@
+/* MD2.H - header file for MD2C.C
+ * $FreeBSD$
+ */
+
+/* Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All
+ rights reserved.
+
+ License to copy and use this software is granted for
+ non-commercial Internet Privacy-Enhanced Mail provided that it is
+ identified as the "RSA Data Security, Inc. MD2 Message Digest
+ Algorithm" in all material mentioning or referencing this software
+ or this function.
+
+ RSA Data Security, Inc. makes no representations concerning either
+ the merchantability of this software or the suitability of this
+ software for any particular purpose. It is provided "as is"
+ without express or implied warranty of any kind.
+
+ These notices must be retained in any copies of any part of this
+ documentation and/or software.
+ */
+
+#ifndef _MD2_H_
+#define _MD2_H_
+
+typedef struct MD2Context {
+ unsigned char state[16]; /* state */
+ unsigned char checksum[16]; /* checksum */
+ unsigned int count; /* number of bytes, modulo 16 */
+ unsigned char buffer[16]; /* input buffer */
+} MD2_CTX;
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+void MD2Init(MD2_CTX *);
+void MD2Update(MD2_CTX *, const void *, unsigned int);
+void MD2Pad(MD2_CTX *);
+void MD2Final(unsigned char [16], MD2_CTX *);
+char * MD2End(MD2_CTX *, char *);
+char * MD2File(const char *, char *);
+char * MD2FileChunk(const char *, char *, off_t, off_t);
+char * MD2Data(const void *, unsigned int, char *);
+__END_DECLS
+
+#endif /* _MD2_H_ */
diff --git a/lib/libmd/md2c.c b/lib/libmd/md2c.c
new file mode 100644
index 0000000..4799457
--- /dev/null
+++ b/lib/libmd/md2c.c
@@ -0,0 +1,211 @@
+/* MD2C.C - RSA Data Security, Inc., MD2 message-digest algorithm
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/* Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All
+ rights reserved.
+
+ License to copy and use this software is granted for
+ non-commercial Internet Privacy-Enhanced Mail provided that it is
+ identified as the "RSA Data Security, Inc. MD2 Message Digest
+ Algorithm" in all material mentioning or referencing this software
+ or this function.
+
+ RSA Data Security, Inc. makes no representations concerning either
+ the merchantability of this software or the suitability of this
+ software for any particular purpose. It is provided "as is"
+ without express or implied warranty of any kind.
+
+ These notices must be retained in any copies of any part of this
+ documentation and/or software.
+ */
+
+#include <sys/types.h>
+#include <string.h>
+#include "md2.h"
+
+
+typedef unsigned char *POINTER;
+typedef u_int16_t UINT2;
+typedef u_int32_t UINT4;
+
+#define PROTO_LIST(list) list
+
+static void MD2Transform PROTO_LIST
+ ((unsigned char [16], unsigned char [16], const unsigned char [16]));
+
+/* Permutation of 0..255 constructed from the digits of pi. It gives a
+ "random" nonlinear byte substitution operation.
+ */
+static unsigned char PI_SUBST[256] = {
+ 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6,
+ 19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188,
+ 76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24,
+ 138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251,
+ 245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63,
+ 148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50,
+ 39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165,
+ 181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210,
+ 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157,
+ 112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27,
+ 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15,
+ 85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197,
+ 234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65,
+ 129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123,
+ 8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233,
+ 203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228,
+ 166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237,
+ 31, 26, 219, 153, 141, 51, 159, 17, 131, 20
+};
+
+static unsigned char *PADDING[] = {
+ (unsigned char *)"",
+ (unsigned char *)"\001",
+ (unsigned char *)"\002\002",
+ (unsigned char *)"\003\003\003",
+ (unsigned char *)"\004\004\004\004",
+ (unsigned char *)"\005\005\005\005\005",
+ (unsigned char *)"\006\006\006\006\006\006",
+ (unsigned char *)"\007\007\007\007\007\007\007",
+ (unsigned char *)"\010\010\010\010\010\010\010\010",
+ (unsigned char *)"\011\011\011\011\011\011\011\011\011",
+ (unsigned char *)"\012\012\012\012\012\012\012\012\012\012",
+ (unsigned char *)"\013\013\013\013\013\013\013\013\013\013\013",
+ (unsigned char *)"\014\014\014\014\014\014\014\014\014\014\014\014",
+ (unsigned char *)
+ "\015\015\015\015\015\015\015\015\015\015\015\015\015",
+ (unsigned char *)
+ "\016\016\016\016\016\016\016\016\016\016\016\016\016\016",
+ (unsigned char *)
+ "\017\017\017\017\017\017\017\017\017\017\017\017\017\017\017",
+ (unsigned char *)
+ "\020\020\020\020\020\020\020\020\020\020\020\020\020\020\020\020"
+};
+
+/* MD2 initialization. Begins an MD2 operation, writing a new context.
+ */
+void MD2Init (context)
+MD2_CTX *context; /* context */
+{
+ context->count = 0;
+ memset ((POINTER)context->state, 0, sizeof (context->state));
+ memset
+ ((POINTER)context->checksum, 0, sizeof (context->checksum));
+}
+
+/* MD2 block update operation. Continues an MD2 message-digest
+ operation, processing another message block, and updating the
+ context.
+ */
+void MD2Update (context, in, inputLen)
+MD2_CTX *context; /* context */
+const void *in; /* input block */
+unsigned int inputLen; /* length of input block */
+{
+ unsigned int i, idx, partLen;
+ const unsigned char *input = in;
+
+ /* Update number of bytes mod 16 */
+ idx = context->count;
+ context->count = (idx + inputLen) & 0xf;
+
+ partLen = 16 - idx;
+
+ /* Transform as many times as possible.
+ */
+ if (inputLen >= partLen) {
+ memcpy
+ ((POINTER)&context->buffer[idx], (POINTER)input, partLen);
+ MD2Transform (context->state, context->checksum, context->buffer);
+
+ for (i = partLen; i + 15 < inputLen; i += 16)
+ MD2Transform (context->state, context->checksum, &input[i]);
+
+ idx = 0;
+ }
+ else
+ i = 0;
+
+ /* Buffer remaining input */
+ memcpy
+ ((POINTER)&context->buffer[idx], (POINTER)&input[i],
+ inputLen-i);
+}
+
+/* MD2 padding.
+ */
+void MD2Pad (context)
+MD2_CTX *context; /* context */
+{
+ unsigned int idx, padLen;
+
+ /* Pad out to multiple of 16.
+ */
+ idx = context->count;
+ padLen = 16 - idx;
+ MD2Update (context, PADDING[padLen], padLen);
+
+ /* Extend with checksum */
+ MD2Update (context, context->checksum, 16);
+}
+
+/* MD2 finalization. Ends an MD2 message-digest operation, writing the
+ message digest and zeroizing the context.
+ */
+void MD2Final (digest, context)
+unsigned char digest[16]; /* message digest */
+MD2_CTX *context; /* context */
+{
+ /* Do padding */
+ MD2Pad (context);
+
+ /* Store state in digest */
+ memcpy ((POINTER)digest, (POINTER)context->state, 16);
+
+ /* Zeroize sensitive information.
+ */
+ memset ((POINTER)context, 0, sizeof (*context));
+}
+
+/* MD2 basic transformation. Transforms state and updates checksum
+ based on block.
+ */
+static void MD2Transform (state, checksum, block)
+unsigned char state[16];
+unsigned char checksum[16];
+const unsigned char block[16];
+{
+ unsigned int i, j, t;
+ unsigned char x[48];
+
+ /* Form encryption block from state, block, state ^ block.
+ */
+ memcpy ((POINTER)x, (POINTER)state, 16);
+ memcpy ((POINTER)x+16, (POINTER)block, 16);
+ for (i = 0; i < 16; i++)
+ x[i+32] = state[i] ^ block[i];
+
+ /* Encrypt block (18 rounds).
+ */
+ t = 0;
+ for (i = 0; i < 18; i++) {
+ for (j = 0; j < 48; j++)
+ t = x[j] ^= PI_SUBST[t];
+ t = (t + i) & 0xff;
+ }
+
+ /* Save new state */
+ memcpy ((POINTER)state, (POINTER)x, 16);
+
+ /* Update checksum.
+ */
+ t = checksum[15];
+ for (i = 0; i < 16; i++)
+ t = checksum[i] ^= PI_SUBST[block[i] ^ t];
+
+ /* Zeroize sensitive information.
+ */
+ memset ((POINTER)x, 0, sizeof (x));
+}
diff --git a/lib/libmd/md4.copyright b/lib/libmd/md4.copyright
new file mode 100644
index 0000000..e450207
--- /dev/null
+++ b/lib/libmd/md4.copyright
@@ -0,0 +1,20 @@
+.\" $FreeBSD$
+Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+.Pp
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD4 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD4 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+.Pp
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+.Pp
+These notices must be retained in any copies of any part of this
+documentation and/or software.
diff --git a/lib/libmd/md4.h b/lib/libmd/md4.h
new file mode 100644
index 0000000..4773513
--- /dev/null
+++ b/lib/libmd/md4.h
@@ -0,0 +1,48 @@
+/* MD4.H - header file for MD4C.C
+ * $FreeBSD$
+ */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+ rights reserved.
+
+ License to copy and use this software is granted provided that it
+ is identified as the "RSA Data Security, Inc. MD4 Message-Digest
+ Algorithm" in all material mentioning or referencing this software
+ or this function.
+ License is also granted to make and use derivative works provided
+ that such works are identified as "derived from the RSA Data
+ Security, Inc. MD4 Message-Digest Algorithm" in all material
+ mentioning or referencing the derived work.
+
+ RSA Data Security, Inc. makes no representations concerning either
+ the merchantability of this software or the suitability of this
+ software for any particular purpose. It is provided "as is"
+ without express or implied warranty of any kind.
+
+ These notices must be retained in any copies of any part of this
+ documentation and/or software.
+ */
+
+#ifndef _MD4_H_
+#define _MD4_H_
+/* MD4 context. */
+typedef struct MD4Context {
+ u_int32_t state[4]; /* state (ABCD) */
+ u_int32_t count[2]; /* number of bits, modulo 2^64 (lsb first) */
+ unsigned char buffer[64]; /* input buffer */
+} MD4_CTX;
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+void MD4Init(MD4_CTX *);
+void MD4Update(MD4_CTX *, const void *, unsigned int);
+void MD4Pad(MD4_CTX *);
+void MD4Final(unsigned char [16], MD4_CTX *);
+char * MD4End(MD4_CTX *, char *);
+char * MD4File(const char *, char *);
+char * MD4FileChunk(const char *, char *, off_t, off_t);
+char * MD4Data(const void *, unsigned int, char *);
+__END_DECLS
+
+#endif /* _MD4_H_ */
diff --git a/lib/libmd/md4c.c b/lib/libmd/md4c.c
new file mode 100644
index 0000000..1211a98
--- /dev/null
+++ b/lib/libmd/md4c.c
@@ -0,0 +1,292 @@
+/* MD4C.C - RSA Data Security, Inc., MD4 message-digest algorithm
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/* Copyright (C) 1990-2, RSA Data Security, Inc. All rights reserved.
+
+ License to copy and use this software is granted provided that it
+ is identified as the "RSA Data Security, Inc. MD4 Message-Digest
+ Algorithm" in all material mentioning or referencing this software
+ or this function.
+
+ License is also granted to make and use derivative works provided
+ that such works are identified as "derived from the RSA Data
+ Security, Inc. MD4 Message-Digest Algorithm" in all material
+ mentioning or referencing the derived work.
+
+ RSA Data Security, Inc. makes no representations concerning either
+ the merchantability of this software or the suitability of this
+ software for any particular purpose. It is provided "as is"
+ without express or implied warranty of any kind.
+
+ These notices must be retained in any copies of any part of this
+ documentation and/or software.
+ */
+
+#include <sys/types.h>
+#include <string.h>
+#include "md4.h"
+
+typedef unsigned char *POINTER;
+typedef const unsigned char *CONST_POINTER;
+typedef u_int16_t UINT2;
+typedef u_int32_t UINT4;
+
+#define PROTO_LIST(list) list
+
+/* Constants for MD4Transform routine.
+ */
+#define S11 3
+#define S12 7
+#define S13 11
+#define S14 19
+#define S21 3
+#define S22 5
+#define S23 9
+#define S24 13
+#define S31 3
+#define S32 9
+#define S33 11
+#define S34 15
+
+static void MD4Transform PROTO_LIST ((UINT4 [4], const unsigned char [64]));
+static void Encode PROTO_LIST
+ ((unsigned char *, UINT4 *, unsigned int));
+static void Decode PROTO_LIST
+ ((UINT4 *, const unsigned char *, unsigned int));
+
+static unsigned char PADDING[64] = {
+ 0x80, 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
+};
+
+/* F, G and H are basic MD4 functions.
+ */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+
+/* ROTATE_LEFT rotates x left n bits.
+ */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG and HH are transformations for rounds 1, 2 and 3 */
+/* Rotation is separate from addition to prevent recomputation */
+#define FF(a, b, c, d, x, s) { \
+ (a) += F ((b), (c), (d)) + (x); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ }
+#define GG(a, b, c, d, x, s) { \
+ (a) += G ((b), (c), (d)) + (x) + (UINT4)0x5a827999; \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ }
+#define HH(a, b, c, d, x, s) { \
+ (a) += H ((b), (c), (d)) + (x) + (UINT4)0x6ed9eba1; \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ }
+
+/* MD4 initialization. Begins an MD4 operation, writing a new context.
+ */
+void MD4Init (context)
+MD4_CTX *context; /* context */
+{
+ context->count[0] = context->count[1] = 0;
+
+ /* Load magic initialization constants.
+ */
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xefcdab89;
+ context->state[2] = 0x98badcfe;
+ context->state[3] = 0x10325476;
+}
+
+/* MD4 block update operation. Continues an MD4 message-digest
+ operation, processing another message block, and updating the
+ context.
+ */
+void MD4Update (context, in, inputLen)
+MD4_CTX *context; /* context */
+const void *in; /* input block */
+unsigned int inputLen; /* length of input block */
+{
+ unsigned int i, idx, partLen;
+ const unsigned char *input = in;
+
+ /* Compute number of bytes mod 64 */
+ idx = (unsigned int)((context->count[0] >> 3) & 0x3F);
+ /* Update number of bits */
+ if ((context->count[0] += ((UINT4)inputLen << 3))
+ < ((UINT4)inputLen << 3))
+ context->count[1]++;
+ context->count[1] += ((UINT4)inputLen >> 29);
+
+ partLen = 64 - idx;
+ /* Transform as many times as possible.
+ */
+ if (inputLen >= partLen) {
+ memcpy
+ ((POINTER)&context->buffer[idx], (CONST_POINTER)input, partLen);
+ MD4Transform (context->state, context->buffer);
+
+ for (i = partLen; i + 63 < inputLen; i += 64)
+ MD4Transform (context->state, &input[i]);
+
+ idx = 0;
+ }
+ else
+ i = 0;
+
+ /* Buffer remaining input */
+ memcpy
+ ((POINTER)&context->buffer[idx], (CONST_POINTER)&input[i],
+ inputLen-i);
+}
+
+/* MD4 padding. */
+void MD4Pad (context)
+MD4_CTX *context; /* context */
+{
+ unsigned char bits[8];
+ unsigned int idx, padLen;
+
+ /* Save number of bits */
+ Encode (bits, context->count, 8);
+
+ /* Pad out to 56 mod 64.
+ */
+ idx = (unsigned int)((context->count[0] >> 3) & 0x3f);
+ padLen = (idx < 56) ? (56 - idx) : (120 - idx);
+ MD4Update (context, PADDING, padLen);
+
+ /* Append length (before padding) */
+ MD4Update (context, bits, 8);
+}
+
+/* MD4 finalization. Ends an MD4 message-digest operation, writing the
+ the message digest and zeroizing the context.
+ */
+void MD4Final (digest, context)
+unsigned char digest[16]; /* message digest */
+MD4_CTX *context; /* context */
+{
+ /* Do padding */
+ MD4Pad (context);
+
+ /* Store state in digest */
+ Encode (digest, context->state, 16);
+
+ /* Zeroize sensitive information.
+ */
+ memset ((POINTER)context, 0, sizeof (*context));
+}
+
+/* MD4 basic transformation. Transforms state based on block.
+ */
+static void MD4Transform (state, block)
+UINT4 state[4];
+const unsigned char block[64];
+{
+ UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+ Decode (x, block, 64);
+
+ /* Round 1 */
+ FF (a, b, c, d, x[ 0], S11); /* 1 */
+ FF (d, a, b, c, x[ 1], S12); /* 2 */
+ FF (c, d, a, b, x[ 2], S13); /* 3 */
+ FF (b, c, d, a, x[ 3], S14); /* 4 */
+ FF (a, b, c, d, x[ 4], S11); /* 5 */
+ FF (d, a, b, c, x[ 5], S12); /* 6 */
+ FF (c, d, a, b, x[ 6], S13); /* 7 */
+ FF (b, c, d, a, x[ 7], S14); /* 8 */
+ FF (a, b, c, d, x[ 8], S11); /* 9 */
+ FF (d, a, b, c, x[ 9], S12); /* 10 */
+ FF (c, d, a, b, x[10], S13); /* 11 */
+ FF (b, c, d, a, x[11], S14); /* 12 */
+ FF (a, b, c, d, x[12], S11); /* 13 */
+ FF (d, a, b, c, x[13], S12); /* 14 */
+ FF (c, d, a, b, x[14], S13); /* 15 */
+ FF (b, c, d, a, x[15], S14); /* 16 */
+
+ /* Round 2 */
+ GG (a, b, c, d, x[ 0], S21); /* 17 */
+ GG (d, a, b, c, x[ 4], S22); /* 18 */
+ GG (c, d, a, b, x[ 8], S23); /* 19 */
+ GG (b, c, d, a, x[12], S24); /* 20 */
+ GG (a, b, c, d, x[ 1], S21); /* 21 */
+ GG (d, a, b, c, x[ 5], S22); /* 22 */
+ GG (c, d, a, b, x[ 9], S23); /* 23 */
+ GG (b, c, d, a, x[13], S24); /* 24 */
+ GG (a, b, c, d, x[ 2], S21); /* 25 */
+ GG (d, a, b, c, x[ 6], S22); /* 26 */
+ GG (c, d, a, b, x[10], S23); /* 27 */
+ GG (b, c, d, a, x[14], S24); /* 28 */
+ GG (a, b, c, d, x[ 3], S21); /* 29 */
+ GG (d, a, b, c, x[ 7], S22); /* 30 */
+ GG (c, d, a, b, x[11], S23); /* 31 */
+ GG (b, c, d, a, x[15], S24); /* 32 */
+
+ /* Round 3 */
+ HH (a, b, c, d, x[ 0], S31); /* 33 */
+ HH (d, a, b, c, x[ 8], S32); /* 34 */
+ HH (c, d, a, b, x[ 4], S33); /* 35 */
+ HH (b, c, d, a, x[12], S34); /* 36 */
+ HH (a, b, c, d, x[ 2], S31); /* 37 */
+ HH (d, a, b, c, x[10], S32); /* 38 */
+ HH (c, d, a, b, x[ 6], S33); /* 39 */
+ HH (b, c, d, a, x[14], S34); /* 40 */
+ HH (a, b, c, d, x[ 1], S31); /* 41 */
+ HH (d, a, b, c, x[ 9], S32); /* 42 */
+ HH (c, d, a, b, x[ 5], S33); /* 43 */
+ HH (b, c, d, a, x[13], S34); /* 44 */
+ HH (a, b, c, d, x[ 3], S31); /* 45 */
+ HH (d, a, b, c, x[11], S32); /* 46 */
+ HH (c, d, a, b, x[ 7], S33); /* 47 */
+ HH (b, c, d, a, x[15], S34); /* 48 */
+
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+
+ /* Zeroize sensitive information.
+ */
+ memset ((POINTER)x, 0, sizeof (x));
+}
+
+/* Encodes input (UINT4) into output (unsigned char). Assumes len is
+ a multiple of 4.
+ */
+static void Encode (output, input, len)
+unsigned char *output;
+UINT4 *input;
+unsigned int len;
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4) {
+ output[j] = (unsigned char)(input[i] & 0xff);
+ output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
+ output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
+ output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
+ }
+}
+
+/* Decodes input (unsigned char) into output (UINT4). Assumes len is
+ a multiple of 4.
+ */
+static void Decode (output, input, len)
+
+UINT4 *output;
+const unsigned char *input;
+unsigned int len;
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4)
+ output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
+ (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
+}
diff --git a/lib/libmd/md5.copyright b/lib/libmd/md5.copyright
new file mode 100644
index 0000000..b718bf8
--- /dev/null
+++ b/lib/libmd/md5.copyright
@@ -0,0 +1,21 @@
+.\" $FreeBSD$
+Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+.Pp
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+.Pp
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+.Pp
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+.Pp
+These notices must be retained in any copies of any part of this
+documentation and/or software.
diff --git a/lib/libmd/md5.h b/lib/libmd/md5.h
new file mode 100644
index 0000000..803a88f
--- /dev/null
+++ b/lib/libmd/md5.h
@@ -0,0 +1,4 @@
+#ifndef _MD5_H_
+#define _MD5_H_
+#include <sys/md5.h>
+#endif /* _MD5_H_ */
diff --git a/lib/libmd/md5c.c b/lib/libmd/md5c.c
new file mode 100644
index 0000000..d097390
--- /dev/null
+++ b/lib/libmd/md5c.c
@@ -0,0 +1,337 @@
+/*
+ * MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
+ *
+ * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+ * rights reserved.
+ *
+ * License to copy and use this software is granted provided that it
+ * is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+ * Algorithm" in all material mentioning or referencing this software
+ * or this function.
+ *
+ * License is also granted to make and use derivative works provided
+ * that such works are identified as "derived from the RSA Data
+ * Security, Inc. MD5 Message-Digest Algorithm" in all material
+ * mentioning or referencing the derived work.
+ *
+ * RSA Data Security, Inc. makes no representations concerning either
+ * the merchantability of this software or the suitability of this
+ * software for any particular purpose. It is provided "as is"
+ * without express or implied warranty of any kind.
+ *
+ * These notices must be retained in any copies of any part of this
+ * documentation and/or software.
+ *
+ * This code is the same as the code published by RSA Inc. It has been
+ * edited for clarity and style only.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#ifdef _KERNEL
+#include <sys/systm.h>
+#else
+#include <string.h>
+#endif
+
+#include <machine/endian.h>
+#include <sys/endian.h>
+#include <sys/md5.h>
+
+static void MD5Transform(u_int32_t [4], const unsigned char [64]);
+
+#ifdef _KERNEL
+#define memset(x,y,z) bzero(x,z);
+#define memcpy(x,y,z) bcopy(y, x, z)
+#endif
+
+#if (BYTE_ORDER == LITTLE_ENDIAN)
+#define Encode memcpy
+#define Decode memcpy
+#else
+
+/*
+ * Encodes input (u_int32_t) into output (unsigned char). Assumes len is
+ * a multiple of 4.
+ */
+
+static void
+Encode (unsigned char *output, u_int32_t *input, unsigned int len)
+{
+ unsigned int i;
+ u_int32_t *op = (u_int32_t *)output;
+
+ for (i = 0; i < len / 4; i++)
+ op[i] = htole32(input[i]);
+}
+
+/*
+ * Decodes input (unsigned char) into output (u_int32_t). Assumes len is
+ * a multiple of 4.
+ */
+
+static void
+Decode (u_int32_t *output, const unsigned char *input, unsigned int len)
+{
+ unsigned int i;
+ const u_int32_t *ip = (const u_int32_t *)input;
+
+ for (i = 0; i < len / 4; i++)
+ output[i] = le32toh(ip[i]);
+}
+#endif
+
+static unsigned char PADDING[64] = {
+ 0x80, 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
+};
+
+/* F, G, H and I are basic MD5 functions. */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits. */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/*
+ * FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+ * Rotation is separate from addition to prevent recomputation.
+ */
+#define FF(a, b, c, d, x, s, ac) { \
+ (a) += F ((b), (c), (d)) + (x) + (u_int32_t)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define GG(a, b, c, d, x, s, ac) { \
+ (a) += G ((b), (c), (d)) + (x) + (u_int32_t)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define HH(a, b, c, d, x, s, ac) { \
+ (a) += H ((b), (c), (d)) + (x) + (u_int32_t)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define II(a, b, c, d, x, s, ac) { \
+ (a) += I ((b), (c), (d)) + (x) + (u_int32_t)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+
+/* MD5 initialization. Begins an MD5 operation, writing a new context. */
+
+void
+MD5Init (context)
+ MD5_CTX *context;
+{
+
+ context->count[0] = context->count[1] = 0;
+
+ /* Load magic initialization constants. */
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xefcdab89;
+ context->state[2] = 0x98badcfe;
+ context->state[3] = 0x10325476;
+}
+
+/*
+ * MD5 block update operation. Continues an MD5 message-digest
+ * operation, processing another message block, and updating the
+ * context.
+ */
+
+void
+MD5Update (context, in, inputLen)
+ MD5_CTX *context;
+ const void *in;
+ unsigned int inputLen;
+{
+ unsigned int i, idx, partLen;
+ const unsigned char *input = in;
+
+ /* Compute number of bytes mod 64 */
+ idx = (unsigned int)((context->count[0] >> 3) & 0x3F);
+
+ /* Update number of bits */
+ if ((context->count[0] += ((u_int32_t)inputLen << 3))
+ < ((u_int32_t)inputLen << 3))
+ context->count[1]++;
+ context->count[1] += ((u_int32_t)inputLen >> 29);
+
+ partLen = 64 - idx;
+
+ /* Transform as many times as possible. */
+ if (inputLen >= partLen) {
+ memcpy((void *)&context->buffer[idx], (const void *)input,
+ partLen);
+ MD5Transform (context->state, context->buffer);
+
+ for (i = partLen; i + 63 < inputLen; i += 64)
+ MD5Transform (context->state, &input[i]);
+
+ idx = 0;
+ }
+ else
+ i = 0;
+
+ /* Buffer remaining input */
+ memcpy ((void *)&context->buffer[idx], (const void *)&input[i],
+ inputLen-i);
+}
+
+/*
+ * MD5 padding. Adds padding followed by original length.
+ */
+
+void
+MD5Pad (context)
+ MD5_CTX *context;
+{
+ unsigned char bits[8];
+ unsigned int idx, padLen;
+
+ /* Save number of bits */
+ Encode (bits, context->count, 8);
+
+ /* Pad out to 56 mod 64. */
+ idx = (unsigned int)((context->count[0] >> 3) & 0x3f);
+ padLen = (idx < 56) ? (56 - idx) : (120 - idx);
+ MD5Update (context, PADDING, padLen);
+
+ /* Append length (before padding) */
+ MD5Update (context, bits, 8);
+}
+
+/*
+ * MD5 finalization. Ends an MD5 message-digest operation, writing the
+ * the message digest and zeroizing the context.
+ */
+
+void
+MD5Final (digest, context)
+ unsigned char digest[16];
+ MD5_CTX *context;
+{
+ /* Do padding. */
+ MD5Pad (context);
+
+ /* Store state in digest */
+ Encode (digest, context->state, 16);
+
+ /* Zeroize sensitive information. */
+ memset ((void *)context, 0, sizeof (*context));
+}
+
+/* MD5 basic transformation. Transforms state based on block. */
+
+static void
+MD5Transform (state, block)
+ u_int32_t state[4];
+ const unsigned char block[64];
+{
+ u_int32_t a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+ Decode (x, block, 64);
+
+ /* Round 1 */
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+ FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
+ FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
+ FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
+ FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
+ FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
+ FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
+ FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
+ FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
+ FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
+ FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
+ FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+ FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+ FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+ FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+ FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+ FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+ /* Round 2 */
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+ GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
+ GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
+ GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+ GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
+ GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
+ GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
+ GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+ GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
+ GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
+ GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+ GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
+ GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
+ GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+ GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
+ GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
+ GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+ /* Round 3 */
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+ HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
+ HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
+ HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+ HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+ HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
+ HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
+ HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
+ HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+ HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+ HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
+ HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
+ HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
+ HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
+ HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+ HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+ HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+
+ /* Round 4 */
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+ II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
+ II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
+ II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+ II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
+ II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+ II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
+ II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+ II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
+ II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
+ II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+ II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
+ II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+ II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
+ II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+ II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
+ II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+
+ /* Zeroize sensitive information. */
+ memset ((void *)x, 0, sizeof (x));
+}
diff --git a/lib/libmd/mdX.3 b/lib/libmd/mdX.3
new file mode 100644
index 0000000..c0567c5
--- /dev/null
+++ b/lib/libmd/mdX.3
@@ -0,0 +1,202 @@
+.\"
+.\" ----------------------------------------------------------------------------
+.\" "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
+.\" ----------------------------------------------------------------------------
+.\"
+.\" $FreeBSD$
+.\"
+.Dd February 11, 1999
+.Dt MDX 3
+.Os
+.Sh NAME
+.Nm MDXInit ,
+.Nm MDXUpdate ,
+.Nm MDXPad ,
+.Nm MDXFinal ,
+.Nm MDXEnd ,
+.Nm MDXFile ,
+.Nm MDXFileChunk ,
+.Nm MDXData
+.Nd calculate the RSA Data Security, Inc., ``MDX'' message digest
+.Sh LIBRARY
+.Lb libmd
+.Sh SYNOPSIS
+.In sys/types.h
+.In mdX.h
+.Ft void
+.Fn MDXInit "MDX_CTX *context"
+.Ft void
+.Fn MDXUpdate "MDX_CTX *context" "const void *data" "unsigned int len"
+.Ft void
+.Fn MDXPad "MDX_CTX *context"
+.Ft void
+.Fn MDXFinal "unsigned char digest[16]" "MDX_CTX *context"
+.Ft "char *"
+.Fn MDXEnd "MDX_CTX *context" "char *buf"
+.Ft "char *"
+.Fn MDXFile "const char *filename" "char *buf"
+.Ft "char *"
+.Fn MDXFileChunk "const char *filename" "char *buf" "off_t offset" "off_t length"
+.Ft "char *"
+.Fn MDXData "const void *data" "unsigned int len" "char *buf"
+.Sh DESCRIPTION
+The MDX functions calculate a 128-bit cryptographic checksum (digest)
+for any number of input bytes.
+A cryptographic checksum is a one-way
+hash-function, that is, you cannot find (except by exhaustive search)
+the input corresponding to a particular output.
+This net result is a
+.Dq fingerprint
+of the input-data, which does not disclose the actual input.
+.Pp
+MD2 is the slowest, MD4 is the fastest and MD5 is somewhere in the middle.
+MD2 can only be used for Privacy-Enhanced Mail.
+MD4 has now been broken; it should only be used where necessary for
+backward compatibility.
+MD5 has not yet (1999-02-11) been broken, but sufficient attacks have been
+made that its security is in some doubt.
+The attacks on both MD4 and MD5
+are both in the nature of finding
+.Dq collisions
+\[en]
+that is, multiple
+inputs which hash to the same value; it is still unlikely for an attacker
+to be able to determine the exact original input given a hash value.
+.Pp
+The
+.Fn MDXInit ,
+.Fn MDXUpdate ,
+and
+.Fn MDXFinal
+functions are the core functions.
+Allocate an
+.Vt MDX_CTX ,
+initialize it with
+.Fn MDXInit ,
+run over the data with
+.Fn MDXUpdate ,
+and finally extract the result using
+.Fn MDXFinal .
+.Pp
+The
+.Fn MDXPad
+function can be used to pad message data in same way
+as done by
+.Fn MDXFinal
+without terminating calculation.
+.Pp
+The
+.Fn MDXEnd
+function is a wrapper for
+.Fn MDXFinal
+which converts the return value to a 33-character
+(including the terminating '\e0')
+.Tn ASCII
+string which represents the 128 bits in hexadecimal.
+.Pp
+The
+.Fn MDXFile
+function calculates the digest of a file, and uses
+.Fn MDXEnd
+to return the result.
+If the file cannot be opened, a null pointer is returned.
+The
+.Fn MDXFileChunk
+function is similar to
+.Fn MDXFile ,
+but it only calculates the digest over a byte-range of the file specified,
+starting at
+.Fa offset
+and spanning
+.Fa length
+bytes.
+If the
+.Fa length
+parameter is specified as 0, or more than the length of the remaining part
+of the file,
+.Fn MDXFileChunk
+calculates the digest from
+.Fa offset
+to the end of file.
+The
+.Fn MDXData
+function calculates the digest of a chunk of data in memory, and uses
+.Fn MDXEnd
+to return the result.
+.Pp
+When using
+.Fn MDXEnd ,
+.Fn MDXFile ,
+or
+.Fn MDXData ,
+the
+.Fa buf
+argument can be a null pointer, in which case the returned string
+is allocated with
+.Xr malloc 3
+and subsequently must be explicitly deallocated using
+.Xr free 3
+after use.
+If the
+.Fa buf
+argument is non-null it must point to at least 33 characters of buffer space.
+.Sh SEE ALSO
+.Xr md2 3 ,
+.Xr md4 3 ,
+.Xr md5 3 ,
+.Xr sha 3
+.Rs
+.%A B. Kaliski
+.%T The MD2 Message-Digest Algorithm
+.%O RFC 1319
+.Re
+.Rs
+.%A R. Rivest
+.%T The MD4 Message-Digest Algorithm
+.%O RFC 1186
+.Re
+.Rs
+.%A R. Rivest
+.%T The MD5 Message-Digest Algorithm
+.%O RFC 1321
+.Re
+.Rs
+.%A RSA Laboratories
+.%T Frequently Asked Questions About today's Cryptography
+.%O \&<http://www.rsa.com/rsalabs/faq/>
+.Re
+.Rs
+.%A H. Dobbertin
+.%T Alf Swindles Ann
+.%J CryptoBytes
+.%N 1(3):5
+.%D 1995
+.Re
+.Rs
+.%A MJ. B. Robshaw
+.%T On Recent Results for MD2, MD4 and MD5
+.%J RSA Laboratories Bulletin
+.%N 4
+.%D November 12, 1996
+.Re
+.Sh HISTORY
+These functions appeared in
+.Fx 2.0 .
+.Sh AUTHORS
+The original MDX routines were developed by
+.Tn RSA
+Data Security, Inc., and published in the above references.
+This code is derived directly from these implementations by
+.An Poul-Henning Kamp Aq phk@FreeBSD.org
+.Pp
+Phk ristede runen.
+.Sh BUGS
+No method is known to exist which finds two files having the same hash value,
+nor to find a file with a specific hash value.
+There is on the other hand no guarantee that such a method does not exist.
+.Pp
+MD2 has only been licensed for use in Privacy Enhanced Mail.
+Use MD4 or MD5 if that is not what you are doing.
diff --git a/lib/libmd/mdXhl.c b/lib/libmd/mdXhl.c
new file mode 100644
index 0000000..e69e5e5
--- /dev/null
+++ b/lib/libmd/mdXhl.c
@@ -0,0 +1,98 @@
+/* mdXhl.c * ----------------------------------------------------------------------------
+ * "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/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "mdX.h"
+
+char *
+MDXEnd(MDX_CTX *ctx, char *buf)
+{
+ int i;
+ unsigned char digest[LENGTH];
+ static const char hex[]="0123456789abcdef";
+
+ if (!buf)
+ buf = malloc(2*LENGTH + 1);
+ if (!buf)
+ return 0;
+ MDXFinal(digest, ctx);
+ for (i = 0; i < LENGTH; i++) {
+ buf[i+i] = hex[digest[i] >> 4];
+ buf[i+i+1] = hex[digest[i] & 0x0f];
+ }
+ buf[i+i] = '\0';
+ return buf;
+}
+
+char *
+MDXFile(const char *filename, char *buf)
+{
+ return (MDXFileChunk(filename, buf, 0, 0));
+}
+
+char *
+MDXFileChunk(const char *filename, char *buf, off_t ofs, off_t len)
+{
+ unsigned char buffer[BUFSIZ];
+ MDX_CTX ctx;
+ struct stat stbuf;
+ int f, i, e;
+ off_t n;
+
+ MDXInit(&ctx);
+ f = open(filename, O_RDONLY);
+ if (f < 0)
+ return 0;
+ if (fstat(f, &stbuf) < 0)
+ return 0;
+ if (ofs > stbuf.st_size)
+ ofs = stbuf.st_size;
+ if ((len == 0) || (len > stbuf.st_size - ofs))
+ len = stbuf.st_size - ofs;
+ if (lseek(f, ofs, SEEK_SET) < 0)
+ return 0;
+ n = len;
+ i = 0;
+ while (n > 0) {
+ if (n > sizeof(buffer))
+ i = read(f, buffer, sizeof(buffer));
+ else
+ i = read(f, buffer, n);
+ if (i < 0)
+ break;
+ MDXUpdate(&ctx, buffer, i);
+ n -= i;
+ }
+ e = errno;
+ close(f);
+ errno = e;
+ if (i < 0)
+ return 0;
+ return (MDXEnd(&ctx, buf));
+}
+
+char *
+MDXData (const void *data, unsigned int len, char *buf)
+{
+ MDX_CTX ctx;
+
+ MDXInit(&ctx);
+ MDXUpdate(&ctx,data,len);
+ return (MDXEnd(&ctx, buf));
+}
diff --git a/lib/libmd/mddriver.c b/lib/libmd/mddriver.c
new file mode 100644
index 0000000..c12c5fb
--- /dev/null
+++ b/lib/libmd/mddriver.c
@@ -0,0 +1,72 @@
+/* MDDRIVER.C - test driver for MD2, MD4 and MD5
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/* Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All
+ rights reserved.
+
+ RSA Data Security, Inc. makes no representations concerning either
+ the merchantability of this software or the suitability of this
+ software for any particular purpose. It is provided "as is"
+ without express or implied warranty of any kind.
+
+ These notices must be retained in any copies of any part of this
+ documentation and/or software.
+ */
+
+/* The following makes MD default to MD5 if it has not already been
+ defined with C compiler flags.
+ */
+#ifndef MD
+#define MD 5
+#endif
+
+#include <sys/types.h>
+
+#include <stdio.h>
+#include <time.h>
+#include <string.h>
+#if MD == 2
+#include "md2.h"
+#define MDData MD2Data
+#endif
+#if MD == 4
+#include "md4.h"
+#define MDData MD4Data
+#endif
+#if MD == 5
+#include "md5.h"
+#define MDData MD5Data
+#endif
+
+/* Digests a string and prints the result.
+ */
+static void MDString (string)
+char *string;
+{
+ char buf[33];
+
+ printf ("MD%d (\"%s\") = %s\n",
+ MD, string, MDData(string,strlen(string),buf));
+}
+
+/* Digests a reference suite of strings and prints the results.
+ */
+main()
+{
+ printf ("MD%d test suite:\n", MD);
+
+ MDString ("");
+ MDString ("a");
+ MDString ("abc");
+ MDString ("message digest");
+ MDString ("abcdefghijklmnopqrstuvwxyz");
+ MDString
+ ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
+ MDString
+ ("1234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890");
+ return 0;
+}
diff --git a/lib/libmd/ripemd.3 b/lib/libmd/ripemd.3
new file mode 100644
index 0000000..6c2f21c
--- /dev/null
+++ b/lib/libmd/ripemd.3
@@ -0,0 +1,141 @@
+.\"
+.\" ----------------------------------------------------------------------------
+.\" "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
+.\" ----------------------------------------------------------------------------
+.\"
+.\" From: Id: mdX.3,v 1.14 1999/02/11 20:31:49 wollman Exp
+.\" $FreeBSD$
+.\"
+.Dd February 26, 1999
+.Dt RIPEMD 3
+.Os
+.Sh NAME
+.Nm RIPEMD160_Init ,
+.Nm RIPEMD160_Update ,
+.Nm RIPEMD160_Final ,
+.Nm RIPEMD160_End ,
+.Nm RIPEMD160_File ,
+.Nm RIPEMD160_FileChunk ,
+.Nm RIPEMD160_Data
+.Nd calculate the RIPEMD160 message digest
+.Sh LIBRARY
+.Lb libmd
+.Sh SYNOPSIS
+.In sys/types.h
+.In ripemd.h
+.Ft void
+.Fn RIPEMD160_Init "RIPEMD160_CTX *context"
+.Ft void
+.Fn RIPEMD160_Update "RIPEMD160_CTX *context" "const unsigned char *data" "unsigned int len"
+.Ft void
+.Fn RIPEMD160_Final "unsigned char digest[20]" "RIPEMD160_CTX *context"
+.Ft "char *"
+.Fn RIPEMD160_End "RIPEMD160_CTX *context" "char *buf"
+.Ft "char *"
+.Fn RIPEMD160_File "const char *filename" "char *buf"
+.Ft "char *"
+.Fn RIPEMD160_FileChunk "const char *filename" "char *buf" "off_t offset" "off_t length"
+.Ft "char *"
+.Fn RIPEMD160_Data "const unsigned char *data" "unsigned int len" "char *buf"
+.Sh DESCRIPTION
+The
+.Li RIPEMD160_
+functions calculate a 160-bit cryptographic checksum (digest)
+for any number of input bytes.
+A cryptographic checksum is a one-way
+hash function; that is, it is computationally impractical to find
+the input corresponding to a particular output.
+This net result is a
+.Dq fingerprint
+of the input-data, which does not disclose the actual input.
+.Pp
+The
+.Fn RIPEMD160_Init ,
+.Fn RIPEMD160_Update ,
+and
+.Fn RIPEMD160_Final
+functions are the core functions.
+Allocate an
+.Vt RIPEMD160_CTX ,
+initialize it with
+.Fn RIPEMD160_Init ,
+run over the data with
+.Fn RIPEMD160_Update ,
+and finally extract the result using
+.Fn RIPEMD160_Final .
+.Pp
+The
+.Fn RIPEMD160_End
+function is a wrapper for
+.Fn RIPEMD160_Final
+which converts the return value to a 41-character
+(including the terminating '\e0')
+.Tn ASCII
+string which represents the 160 bits in hexadecimal.
+.Pp
+The
+.Fn RIPEMD160_File
+function calculates the digest of a file, and uses
+.Fn RIPEMD160_End
+to return the result.
+If the file cannot be opened, a null pointer is returned.
+The
+.Fn RIPEMD160_FileChunk
+function is similar to
+.Fn RIPEMD160_File ,
+but it only calculates the digest over a byte-range of the file specified,
+starting at
+.Fa offset
+and spanning
+.Fa length
+bytes.
+If the
+.Fa length
+parameter is specified as 0, or more than the length of the remaining part
+of the file,
+.Fn RIPEMD160_FileChunk
+calculates the digest from
+.Fa offset
+to the end of file.
+The
+.Fn RIPEMD160_Data
+function calculates the digest of a chunk of data in memory, and uses
+.Fn RIPEMD160_End
+to return the result.
+.Pp
+When using
+.Fn RIPEMD160_End ,
+.Fn RIPEMD160_File ,
+or
+.Fn RIPEMD160_Data ,
+the
+.Fa buf
+argument can be a null pointer, in which case the returned string
+is allocated with
+.Xr malloc 3
+and subsequently must be explicitly deallocated using
+.Xr free 3
+after use.
+If the
+.Fa buf
+argument is non-null it must point to at least 41 characters of buffer space.
+.Sh SEE ALSO
+.Xr md2 3 ,
+.Xr md4 3 ,
+.Xr md5 3 ,
+.Xr sha 3
+.Sh HISTORY
+These functions appeared in
+.Fx 4.0 .
+.Sh AUTHORS
+The core hash routines were implemented by Eric Young based on the
+published
+.Tn RIPEMD160
+specification.
+.Sh BUGS
+No method is known to exist which finds two files having the same hash value,
+nor to find a file with a specific hash value.
+There is on the other hand no guarantee that such a method does not exist.
diff --git a/lib/libmd/ripemd.h b/lib/libmd/ripemd.h
new file mode 100644
index 0000000..2ff35cc
--- /dev/null
+++ b/lib/libmd/ripemd.h
@@ -0,0 +1,94 @@
+/* crypto/ripemd/ripemd.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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 cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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 licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+/*
+ * $FreeBSD$
+ */
+
+#ifndef HEADER_RIPEMD_H
+#define HEADER_RIPEMD_H
+
+#include <sys/cdefs.h>
+#include <sys/types.h> /* XXX switch to machine/ansi.h and __ types */
+
+#define RIPEMD160_CBLOCK 64
+#define RIPEMD160_LBLOCK 16
+#define RIPEMD160_BLOCK 16
+#define RIPEMD160_LAST_BLOCK 56
+#define RIPEMD160_LENGTH_BLOCK 8
+#define RIPEMD160_DIGEST_LENGTH 20
+
+typedef struct RIPEMD160state_st {
+ u_int32_t A,B,C,D,E;
+ u_int32_t Nl,Nh;
+ u_int32_t data[RIPEMD160_LBLOCK];
+ int num;
+} RIPEMD160_CTX;
+
+__BEGIN_DECLS
+void RIPEMD160_Init(RIPEMD160_CTX *c);
+void RIPEMD160_Update(RIPEMD160_CTX *c, const void *data,
+ size_t len);
+void RIPEMD160_Final(unsigned char *md, RIPEMD160_CTX *c);
+char *RIPEMD160_End(RIPEMD160_CTX *, char *);
+char *RIPEMD160_File(const char *, char *);
+char *RIPEMD160_FileChunk(const char *, char *, off_t, off_t);
+char *RIPEMD160_Data(const void *, unsigned int, char *);
+__END_DECLS
+
+#endif
diff --git a/lib/libmd/rmd160c.c b/lib/libmd/rmd160c.c
new file mode 100644
index 0000000..e01f1e0
--- /dev/null
+++ b/lib/libmd/rmd160c.c
@@ -0,0 +1,547 @@
+/* crypto/ripemd/rmd_dgst.c */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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 cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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 licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#if 0
+#include <machine/ansi.h> /* we use the __ variants of bit-sized types */
+#endif
+#include <machine/endian.h>
+
+#include "rmd_locl.h"
+
+/*
+ * The assembly-language code is not position-independent, so don't
+ * try to use it in a shared library.
+ */
+#ifdef PIC
+#undef RMD160_ASM
+#endif
+
+char *RMD160_version="RIPEMD160 part of SSLeay 0.9.0b 11-Oct-1998";
+
+#ifdef RMD160_ASM
+void ripemd160_block_x86(RIPEMD160_CTX *c, const u_int32_t *p,int num);
+#define ripemd160_block ripemd160_block_x86
+#else
+void ripemd160_block(RIPEMD160_CTX *c, const u_int32_t *p,int num);
+#endif
+
+void RIPEMD160_Init(c)
+RIPEMD160_CTX *c;
+ {
+ c->A=RIPEMD160_A;
+ c->B=RIPEMD160_B;
+ c->C=RIPEMD160_C;
+ c->D=RIPEMD160_D;
+ c->E=RIPEMD160_E;
+ c->Nl=0;
+ c->Nh=0;
+ c->num=0;
+ }
+
+void RIPEMD160_Update(c, in, len)
+RIPEMD160_CTX *c;
+const void *in;
+size_t len;
+ {
+ u_int32_t *p;
+ int sw,sc;
+ u_int32_t l;
+ const unsigned char *data = in;
+
+ if (len == 0) return;
+
+ l=(c->Nl+(len<<3))&0xffffffffL;
+ if (l < c->Nl) /* overflow */
+ c->Nh++;
+ c->Nh+=(len>>29);
+ c->Nl=l;
+
+ if (c->num != 0)
+ {
+ p=c->data;
+ sw=c->num>>2;
+ sc=c->num&0x03;
+
+ if ((c->num+len) >= RIPEMD160_CBLOCK)
+ {
+ l= p[sw];
+ p_c2l(data,l,sc);
+ p[sw++]=l;
+ for (; sw<RIPEMD160_LBLOCK; sw++)
+ {
+ c2l(data,l);
+ p[sw]=l;
+ }
+ len-=(RIPEMD160_CBLOCK-c->num);
+
+ ripemd160_block(c,p,64);
+ c->num=0;
+ /* drop through and do the rest */
+ }
+ else
+ {
+ int ew,ec;
+
+ c->num+=(int)len;
+ if ((sc+len) < 4) /* ugly, add char's to a word */
+ {
+ l= p[sw];
+ p_c2l_p(data,l,sc,len);
+ p[sw]=l;
+ }
+ else
+ {
+ ew=(c->num>>2);
+ ec=(c->num&0x03);
+ l= p[sw];
+ p_c2l(data,l,sc);
+ p[sw++]=l;
+ for (; sw < ew; sw++)
+ { c2l(data,l); p[sw]=l; }
+ if (ec)
+ {
+ c2l_p(data,l,ec);
+ p[sw]=l;
+ }
+ }
+ return;
+ }
+ }
+ /* we now can process the input data in blocks of RIPEMD160_CBLOCK
+ * chars and save the leftovers to c->data. */
+#if BYTE_ORDER == LITTLE_ENDIAN
+ if ((((unsigned long)data)%sizeof(u_int32_t)) == 0)
+ {
+ sw=(int)len/RIPEMD160_CBLOCK;
+ if (sw > 0)
+ {
+ sw*=RIPEMD160_CBLOCK;
+ ripemd160_block(c,(u_int32_t *)data,sw);
+ data+=sw;
+ len-=sw;
+ }
+ }
+#endif
+ p=c->data;
+ while (len >= RIPEMD160_CBLOCK)
+ {
+#if BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == BIG_ENDIAN
+ if (p != (u_int32_t *)data)
+ memcpy(p,data,RIPEMD160_CBLOCK);
+ data+=RIPEMD160_CBLOCK;
+#if BYTE_ORDER == BIG_ENDIAN
+ for (sw=(RIPEMD160_LBLOCK/4); sw; sw--)
+ {
+ Endian_Reverse32(p[0]);
+ Endian_Reverse32(p[1]);
+ Endian_Reverse32(p[2]);
+ Endian_Reverse32(p[3]);
+ p+=4;
+ }
+#endif
+#else
+ for (sw=(RIPEMD160_LBLOCK/4); sw; sw--)
+ {
+ c2l(data,l); *(p++)=l;
+ c2l(data,l); *(p++)=l;
+ c2l(data,l); *(p++)=l;
+ c2l(data,l); *(p++)=l;
+ }
+#endif
+ p=c->data;
+ ripemd160_block(c,p,64);
+ len-=RIPEMD160_CBLOCK;
+ }
+ sc=(int)len;
+ c->num=sc;
+ if (sc)
+ {
+ sw=sc>>2; /* words to copy */
+#if BYTE_ORDER == LITTLE_ENDIAN
+ p[sw]=0;
+ memcpy(p,data,sc);
+#else
+ sc&=0x03;
+ for ( ; sw; sw--)
+ { c2l(data,l); *(p++)=l; }
+ c2l_p(data,l,sc);
+ *p=l;
+#endif
+ }
+ }
+
+void RIPEMD160_Transform(c,b)
+RIPEMD160_CTX *c;
+unsigned char *b;
+ {
+ u_int32_t p[16];
+#if BYTE_ORDER != LITTLE_ENDIAN
+ u_int32_t *q;
+ int i;
+#endif
+
+#if BYTE_ORDER == BIG_ENDIAN || BYTE_ORDER == LITTLE_ENDIAN
+ memcpy(p,b,64);
+#if BYTE_ORDER == BIG_ENDIAN
+ q=p;
+ for (i=(RIPEMD160_LBLOCK/4); i; i--)
+ {
+ Endian_Reverse32(q[0]);
+ Endian_Reverse32(q[1]);
+ Endian_Reverse32(q[2]);
+ Endian_Reverse32(q[3]);
+ q+=4;
+ }
+#endif
+#else
+ q=p;
+ for (i=(RIPEMD160_LBLOCK/4); i; i--)
+ {
+ u_int32_t l;
+ c2l(b,l); *(q++)=l;
+ c2l(b,l); *(q++)=l;
+ c2l(b,l); *(q++)=l;
+ c2l(b,l); *(q++)=l;
+ }
+#endif
+ ripemd160_block(c,p,64);
+ }
+
+#ifndef RMD160_ASM
+
+void ripemd160_block(ctx, X, num)
+RIPEMD160_CTX *ctx;
+const u_int32_t *X;
+int num;
+ {
+ u_int32_t A,B,C,D,E;
+ u_int32_t a,b,c,d,e;
+
+ for (;;)
+ {
+ A=ctx->A; B=ctx->B; C=ctx->C; D=ctx->D; E=ctx->E;
+
+ RIP1(A,B,C,D,E,WL00,SL00);
+ RIP1(E,A,B,C,D,WL01,SL01);
+ RIP1(D,E,A,B,C,WL02,SL02);
+ RIP1(C,D,E,A,B,WL03,SL03);
+ RIP1(B,C,D,E,A,WL04,SL04);
+ RIP1(A,B,C,D,E,WL05,SL05);
+ RIP1(E,A,B,C,D,WL06,SL06);
+ RIP1(D,E,A,B,C,WL07,SL07);
+ RIP1(C,D,E,A,B,WL08,SL08);
+ RIP1(B,C,D,E,A,WL09,SL09);
+ RIP1(A,B,C,D,E,WL10,SL10);
+ RIP1(E,A,B,C,D,WL11,SL11);
+ RIP1(D,E,A,B,C,WL12,SL12);
+ RIP1(C,D,E,A,B,WL13,SL13);
+ RIP1(B,C,D,E,A,WL14,SL14);
+ RIP1(A,B,C,D,E,WL15,SL15);
+
+ RIP2(E,A,B,C,D,WL16,SL16,KL1);
+ RIP2(D,E,A,B,C,WL17,SL17,KL1);
+ RIP2(C,D,E,A,B,WL18,SL18,KL1);
+ RIP2(B,C,D,E,A,WL19,SL19,KL1);
+ RIP2(A,B,C,D,E,WL20,SL20,KL1);
+ RIP2(E,A,B,C,D,WL21,SL21,KL1);
+ RIP2(D,E,A,B,C,WL22,SL22,KL1);
+ RIP2(C,D,E,A,B,WL23,SL23,KL1);
+ RIP2(B,C,D,E,A,WL24,SL24,KL1);
+ RIP2(A,B,C,D,E,WL25,SL25,KL1);
+ RIP2(E,A,B,C,D,WL26,SL26,KL1);
+ RIP2(D,E,A,B,C,WL27,SL27,KL1);
+ RIP2(C,D,E,A,B,WL28,SL28,KL1);
+ RIP2(B,C,D,E,A,WL29,SL29,KL1);
+ RIP2(A,B,C,D,E,WL30,SL30,KL1);
+ RIP2(E,A,B,C,D,WL31,SL31,KL1);
+
+ RIP3(D,E,A,B,C,WL32,SL32,KL2);
+ RIP3(C,D,E,A,B,WL33,SL33,KL2);
+ RIP3(B,C,D,E,A,WL34,SL34,KL2);
+ RIP3(A,B,C,D,E,WL35,SL35,KL2);
+ RIP3(E,A,B,C,D,WL36,SL36,KL2);
+ RIP3(D,E,A,B,C,WL37,SL37,KL2);
+ RIP3(C,D,E,A,B,WL38,SL38,KL2);
+ RIP3(B,C,D,E,A,WL39,SL39,KL2);
+ RIP3(A,B,C,D,E,WL40,SL40,KL2);
+ RIP3(E,A,B,C,D,WL41,SL41,KL2);
+ RIP3(D,E,A,B,C,WL42,SL42,KL2);
+ RIP3(C,D,E,A,B,WL43,SL43,KL2);
+ RIP3(B,C,D,E,A,WL44,SL44,KL2);
+ RIP3(A,B,C,D,E,WL45,SL45,KL2);
+ RIP3(E,A,B,C,D,WL46,SL46,KL2);
+ RIP3(D,E,A,B,C,WL47,SL47,KL2);
+
+ RIP4(C,D,E,A,B,WL48,SL48,KL3);
+ RIP4(B,C,D,E,A,WL49,SL49,KL3);
+ RIP4(A,B,C,D,E,WL50,SL50,KL3);
+ RIP4(E,A,B,C,D,WL51,SL51,KL3);
+ RIP4(D,E,A,B,C,WL52,SL52,KL3);
+ RIP4(C,D,E,A,B,WL53,SL53,KL3);
+ RIP4(B,C,D,E,A,WL54,SL54,KL3);
+ RIP4(A,B,C,D,E,WL55,SL55,KL3);
+ RIP4(E,A,B,C,D,WL56,SL56,KL3);
+ RIP4(D,E,A,B,C,WL57,SL57,KL3);
+ RIP4(C,D,E,A,B,WL58,SL58,KL3);
+ RIP4(B,C,D,E,A,WL59,SL59,KL3);
+ RIP4(A,B,C,D,E,WL60,SL60,KL3);
+ RIP4(E,A,B,C,D,WL61,SL61,KL3);
+ RIP4(D,E,A,B,C,WL62,SL62,KL3);
+ RIP4(C,D,E,A,B,WL63,SL63,KL3);
+
+ RIP5(B,C,D,E,A,WL64,SL64,KL4);
+ RIP5(A,B,C,D,E,WL65,SL65,KL4);
+ RIP5(E,A,B,C,D,WL66,SL66,KL4);
+ RIP5(D,E,A,B,C,WL67,SL67,KL4);
+ RIP5(C,D,E,A,B,WL68,SL68,KL4);
+ RIP5(B,C,D,E,A,WL69,SL69,KL4);
+ RIP5(A,B,C,D,E,WL70,SL70,KL4);
+ RIP5(E,A,B,C,D,WL71,SL71,KL4);
+ RIP5(D,E,A,B,C,WL72,SL72,KL4);
+ RIP5(C,D,E,A,B,WL73,SL73,KL4);
+ RIP5(B,C,D,E,A,WL74,SL74,KL4);
+ RIP5(A,B,C,D,E,WL75,SL75,KL4);
+ RIP5(E,A,B,C,D,WL76,SL76,KL4);
+ RIP5(D,E,A,B,C,WL77,SL77,KL4);
+ RIP5(C,D,E,A,B,WL78,SL78,KL4);
+ RIP5(B,C,D,E,A,WL79,SL79,KL4);
+
+ a=A; b=B; c=C; d=D; e=E;
+ /* Do other half */
+ A=ctx->A; B=ctx->B; C=ctx->C; D=ctx->D; E=ctx->E;
+
+ RIP5(A,B,C,D,E,WR00,SR00,KR0);
+ RIP5(E,A,B,C,D,WR01,SR01,KR0);
+ RIP5(D,E,A,B,C,WR02,SR02,KR0);
+ RIP5(C,D,E,A,B,WR03,SR03,KR0);
+ RIP5(B,C,D,E,A,WR04,SR04,KR0);
+ RIP5(A,B,C,D,E,WR05,SR05,KR0);
+ RIP5(E,A,B,C,D,WR06,SR06,KR0);
+ RIP5(D,E,A,B,C,WR07,SR07,KR0);
+ RIP5(C,D,E,A,B,WR08,SR08,KR0);
+ RIP5(B,C,D,E,A,WR09,SR09,KR0);
+ RIP5(A,B,C,D,E,WR10,SR10,KR0);
+ RIP5(E,A,B,C,D,WR11,SR11,KR0);
+ RIP5(D,E,A,B,C,WR12,SR12,KR0);
+ RIP5(C,D,E,A,B,WR13,SR13,KR0);
+ RIP5(B,C,D,E,A,WR14,SR14,KR0);
+ RIP5(A,B,C,D,E,WR15,SR15,KR0);
+
+ RIP4(E,A,B,C,D,WR16,SR16,KR1);
+ RIP4(D,E,A,B,C,WR17,SR17,KR1);
+ RIP4(C,D,E,A,B,WR18,SR18,KR1);
+ RIP4(B,C,D,E,A,WR19,SR19,KR1);
+ RIP4(A,B,C,D,E,WR20,SR20,KR1);
+ RIP4(E,A,B,C,D,WR21,SR21,KR1);
+ RIP4(D,E,A,B,C,WR22,SR22,KR1);
+ RIP4(C,D,E,A,B,WR23,SR23,KR1);
+ RIP4(B,C,D,E,A,WR24,SR24,KR1);
+ RIP4(A,B,C,D,E,WR25,SR25,KR1);
+ RIP4(E,A,B,C,D,WR26,SR26,KR1);
+ RIP4(D,E,A,B,C,WR27,SR27,KR1);
+ RIP4(C,D,E,A,B,WR28,SR28,KR1);
+ RIP4(B,C,D,E,A,WR29,SR29,KR1);
+ RIP4(A,B,C,D,E,WR30,SR30,KR1);
+ RIP4(E,A,B,C,D,WR31,SR31,KR1);
+
+ RIP3(D,E,A,B,C,WR32,SR32,KR2);
+ RIP3(C,D,E,A,B,WR33,SR33,KR2);
+ RIP3(B,C,D,E,A,WR34,SR34,KR2);
+ RIP3(A,B,C,D,E,WR35,SR35,KR2);
+ RIP3(E,A,B,C,D,WR36,SR36,KR2);
+ RIP3(D,E,A,B,C,WR37,SR37,KR2);
+ RIP3(C,D,E,A,B,WR38,SR38,KR2);
+ RIP3(B,C,D,E,A,WR39,SR39,KR2);
+ RIP3(A,B,C,D,E,WR40,SR40,KR2);
+ RIP3(E,A,B,C,D,WR41,SR41,KR2);
+ RIP3(D,E,A,B,C,WR42,SR42,KR2);
+ RIP3(C,D,E,A,B,WR43,SR43,KR2);
+ RIP3(B,C,D,E,A,WR44,SR44,KR2);
+ RIP3(A,B,C,D,E,WR45,SR45,KR2);
+ RIP3(E,A,B,C,D,WR46,SR46,KR2);
+ RIP3(D,E,A,B,C,WR47,SR47,KR2);
+
+ RIP2(C,D,E,A,B,WR48,SR48,KR3);
+ RIP2(B,C,D,E,A,WR49,SR49,KR3);
+ RIP2(A,B,C,D,E,WR50,SR50,KR3);
+ RIP2(E,A,B,C,D,WR51,SR51,KR3);
+ RIP2(D,E,A,B,C,WR52,SR52,KR3);
+ RIP2(C,D,E,A,B,WR53,SR53,KR3);
+ RIP2(B,C,D,E,A,WR54,SR54,KR3);
+ RIP2(A,B,C,D,E,WR55,SR55,KR3);
+ RIP2(E,A,B,C,D,WR56,SR56,KR3);
+ RIP2(D,E,A,B,C,WR57,SR57,KR3);
+ RIP2(C,D,E,A,B,WR58,SR58,KR3);
+ RIP2(B,C,D,E,A,WR59,SR59,KR3);
+ RIP2(A,B,C,D,E,WR60,SR60,KR3);
+ RIP2(E,A,B,C,D,WR61,SR61,KR3);
+ RIP2(D,E,A,B,C,WR62,SR62,KR3);
+ RIP2(C,D,E,A,B,WR63,SR63,KR3);
+
+ RIP1(B,C,D,E,A,WR64,SR64);
+ RIP1(A,B,C,D,E,WR65,SR65);
+ RIP1(E,A,B,C,D,WR66,SR66);
+ RIP1(D,E,A,B,C,WR67,SR67);
+ RIP1(C,D,E,A,B,WR68,SR68);
+ RIP1(B,C,D,E,A,WR69,SR69);
+ RIP1(A,B,C,D,E,WR70,SR70);
+ RIP1(E,A,B,C,D,WR71,SR71);
+ RIP1(D,E,A,B,C,WR72,SR72);
+ RIP1(C,D,E,A,B,WR73,SR73);
+ RIP1(B,C,D,E,A,WR74,SR74);
+ RIP1(A,B,C,D,E,WR75,SR75);
+ RIP1(E,A,B,C,D,WR76,SR76);
+ RIP1(D,E,A,B,C,WR77,SR77);
+ RIP1(C,D,E,A,B,WR78,SR78);
+ RIP1(B,C,D,E,A,WR79,SR79);
+
+ D =ctx->B+c+D;
+ ctx->B=ctx->C+d+E;
+ ctx->C=ctx->D+e+A;
+ ctx->D=ctx->E+a+B;
+ ctx->E=ctx->A+b+C;
+ ctx->A=D;
+
+ X+=16;
+ num-=64;
+ if (num <= 0) break;
+ }
+ }
+#endif
+
+void RIPEMD160_Final(md, c)
+unsigned char *md;
+RIPEMD160_CTX *c;
+ {
+ int i,j;
+ u_int32_t l;
+ u_int32_t *p;
+ static unsigned char end[4]={0x80,0x00,0x00,0x00};
+ unsigned char *cp=end;
+
+ /* c->num should definitly have room for at least one more byte. */
+ p=c->data;
+ j=c->num;
+ i=j>>2;
+
+ /* purify often complains about the following line as an
+ * Uninitialized Memory Read. While this can be true, the
+ * following p_c2l macro will reset l when that case is true.
+ * This is because j&0x03 contains the number of 'valid' bytes
+ * already in p[i]. If and only if j&0x03 == 0, the UMR will
+ * occur but this is also the only time p_c2l will do
+ * l= *(cp++) instead of l|= *(cp++)
+ * Many thanks to Alex Tang <altitude@cic.net> for pickup this
+ * 'potential bug' */
+#ifdef PURIFY
+ if ((j&0x03) == 0) p[i]=0;
+#endif
+ l=p[i];
+ p_c2l(cp,l,j&0x03);
+ p[i]=l;
+ i++;
+ /* i is the next 'undefined word' */
+ if (c->num >= RIPEMD160_LAST_BLOCK)
+ {
+ for (; i<RIPEMD160_LBLOCK; i++)
+ p[i]=0;
+ ripemd160_block(c,p,64);
+ i=0;
+ }
+ for (; i<(RIPEMD160_LBLOCK-2); i++)
+ p[i]=0;
+ p[RIPEMD160_LBLOCK-2]=c->Nl;
+ p[RIPEMD160_LBLOCK-1]=c->Nh;
+ ripemd160_block(c,p,64);
+ cp=md;
+ l=c->A; l2c(l,cp);
+ l=c->B; l2c(l,cp);
+ l=c->C; l2c(l,cp);
+ l=c->D; l2c(l,cp);
+ l=c->E; l2c(l,cp);
+
+ /* clear stuff, ripemd160_block may be leaving some stuff on the stack
+ * but I'm not worried :-) */
+ c->num=0;
+/* memset((char *)&c,0,sizeof(c));*/
+ }
+
+#ifdef undef
+int printit(l)
+unsigned long *l;
+ {
+ int i,ii;
+
+ for (i=0; i<2; i++)
+ {
+ for (ii=0; ii<8; ii++)
+ {
+ fprintf(stderr,"%08lx ",l[i*8+ii]);
+ }
+ fprintf(stderr,"\n");
+ }
+ }
+#endif
diff --git a/lib/libmd/rmd_locl.h b/lib/libmd/rmd_locl.h
new file mode 100644
index 0000000..49f054c
--- /dev/null
+++ b/lib/libmd/rmd_locl.h
@@ -0,0 +1,216 @@
+/* crypto/ripemd/rmd_locl.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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 cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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 licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include "ripemd.h"
+
+#undef c2nl
+#define c2nl(c,l) (l =(((u_int32_t)(*((c)++)))<<24), \
+ l|=(((u_int32_t)(*((c)++)))<<16), \
+ l|=(((u_int32_t)(*((c)++)))<< 8), \
+ l|=(((u_int32_t)(*((c)++))) ))
+
+#undef p_c2nl
+#define p_c2nl(c,l,n) { \
+ switch (n) { \
+ case 0: l =((u_int32_t)(*((c)++)))<<24; \
+ case 1: l|=((u_int32_t)(*((c)++)))<<16; \
+ case 2: l|=((u_int32_t)(*((c)++)))<< 8; \
+ case 3: l|=((u_int32_t)(*((c)++))); \
+ } \
+ }
+
+#undef c2nl_p
+/* NOTE the pointer is not incremented at the end of this */
+#define c2nl_p(c,l,n) { \
+ l=0; \
+ (c)+=n; \
+ switch (n) { \
+ case 3: l =((u_int32_t)(*(--(c))))<< 8; \
+ case 2: l|=((u_int32_t)(*(--(c))))<<16; \
+ case 1: l|=((u_int32_t)(*(--(c))))<<24; \
+ } \
+ }
+
+#undef p_c2nl_p
+#define p_c2nl_p(c,l,sc,len) { \
+ switch (sc) \
+ { \
+ case 0: l =((u_int32_t)(*((c)++)))<<24; \
+ if (--len == 0) break; \
+ case 1: l|=((u_int32_t)(*((c)++)))<<16; \
+ if (--len == 0) break; \
+ case 2: l|=((u_int32_t)(*((c)++)))<< 8; \
+ } \
+ }
+
+#undef nl2c
+#define nl2c(l,c) (*((c)++)=(unsigned char)(((l)>>24)&0xff), \
+ *((c)++)=(unsigned char)(((l)>>16)&0xff), \
+ *((c)++)=(unsigned char)(((l)>> 8)&0xff), \
+ *((c)++)=(unsigned char)(((l) )&0xff))
+
+#undef c2l
+#define c2l(c,l) (l =(((u_int32_t)(*((c)++))) ), \
+ l|=(((u_int32_t)(*((c)++)))<< 8), \
+ l|=(((u_int32_t)(*((c)++)))<<16), \
+ l|=(((u_int32_t)(*((c)++)))<<24))
+
+#undef p_c2l
+#define p_c2l(c,l,n) { \
+ switch (n) { \
+ case 0: l =((u_int32_t)(*((c)++))); \
+ case 1: l|=((u_int32_t)(*((c)++)))<< 8; \
+ case 2: l|=((u_int32_t)(*((c)++)))<<16; \
+ case 3: l|=((u_int32_t)(*((c)++)))<<24; \
+ } \
+ }
+
+#undef c2l_p
+/* NOTE the pointer is not incremented at the end of this */
+#define c2l_p(c,l,n) { \
+ l=0; \
+ (c)+=n; \
+ switch (n) { \
+ case 3: l =((u_int32_t)(*(--(c))))<<16; \
+ case 2: l|=((u_int32_t)(*(--(c))))<< 8; \
+ case 1: l|=((u_int32_t)(*(--(c)))); \
+ } \
+ }
+
+#undef p_c2l_p
+#define p_c2l_p(c,l,sc,len) { \
+ switch (sc) \
+ { \
+ case 0: l =((u_int32_t)(*((c)++))); \
+ if (--len == 0) break; \
+ case 1: l|=((u_int32_t)(*((c)++)))<< 8; \
+ if (--len == 0) break; \
+ case 2: l|=((u_int32_t)(*((c)++)))<<16; \
+ } \
+ }
+
+#undef l2c
+#define l2c(l,c) (*((c)++)=(unsigned char)(((l) )&0xff), \
+ *((c)++)=(unsigned char)(((l)>> 8)&0xff), \
+ *((c)++)=(unsigned char)(((l)>>16)&0xff), \
+ *((c)++)=(unsigned char)(((l)>>24)&0xff))
+
+#undef ROTATE
+#if defined(WIN32)
+#define ROTATE(a,n) _lrotl(a,n)
+#else
+#define ROTATE(a,n) (((a)<<(n))|(((a)&0xffffffff)>>(32-(n))))
+#endif
+
+/* A nice byte order reversal from Wei Dai <weidai@eskimo.com> */
+#if defined(WIN32)
+/* 5 instructions with rotate instruction, else 9 */
+#define Endian_Reverse32(a) \
+ { \
+ u_int32_t l=(a); \
+ (a)=((ROTATE(l,8)&0x00FF00FF)|(ROTATE(l,24)&0xFF00FF00)); \
+ }
+#else
+/* 6 instructions with rotate instruction, else 8 */
+#define Endian_Reverse32(a) \
+ { \
+ u_int32_t l=(a); \
+ l=(((l&0xFF00FF00)>>8L)|((l&0x00FF00FF)<<8L)); \
+ (a)=ROTATE(l,16L); \
+ }
+#endif
+
+#define F1(x,y,z) ((x)^(y)^(z))
+#define F2(x,y,z) (((x)&(y))|((~x)&z))
+#define F3(x,y,z) (((x)|(~y))^(z))
+#define F4(x,y,z) (((x)&(z))|((y)&(~(z))))
+#define F5(x,y,z) ((x)^((y)|(~(z))))
+
+#define RIPEMD160_A 0x67452301L
+#define RIPEMD160_B 0xEFCDAB89L
+#define RIPEMD160_C 0x98BADCFEL
+#define RIPEMD160_D 0x10325476L
+#define RIPEMD160_E 0xC3D2E1F0L
+
+#include "rmdconst.h"
+
+#define RIP1(a,b,c,d,e,w,s) { \
+ a+=F1(b,c,d)+X[w]; \
+ a=ROTATE(a,s)+e; \
+ c=ROTATE(c,10); }
+
+#define RIP2(a,b,c,d,e,w,s,K) { \
+ a+=F2(b,c,d)+X[w]+K; \
+ a=ROTATE(a,s)+e; \
+ c=ROTATE(c,10); }
+
+#define RIP3(a,b,c,d,e,w,s,K) { \
+ a+=F3(b,c,d)+X[w]+K; \
+ a=ROTATE(a,s)+e; \
+ c=ROTATE(c,10); }
+
+#define RIP4(a,b,c,d,e,w,s,K) { \
+ a+=F4(b,c,d)+X[w]+K; \
+ a=ROTATE(a,s)+e; \
+ c=ROTATE(c,10); }
+
+#define RIP5(a,b,c,d,e,w,s,K) { \
+ a+=F5(b,c,d)+X[w]+K; \
+ a=ROTATE(a,s)+e; \
+ c=ROTATE(c,10); }
+
diff --git a/lib/libmd/rmdconst.h b/lib/libmd/rmdconst.h
new file mode 100644
index 0000000..59c48de
--- /dev/null
+++ b/lib/libmd/rmdconst.h
@@ -0,0 +1,399 @@
+/* crypto/ripemd/rmdconst.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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 cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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 licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+#define KL0 0x00000000L
+#define KL1 0x5A827999L
+#define KL2 0x6ED9EBA1L
+#define KL3 0x8F1BBCDCL
+#define KL4 0xA953FD4EL
+
+#define KR0 0x50A28BE6L
+#define KR1 0x5C4DD124L
+#define KR2 0x6D703EF3L
+#define KR3 0x7A6D76E9L
+#define KR4 0x00000000L
+
+#define WL00 0
+#define SL00 11
+#define WL01 1
+#define SL01 14
+#define WL02 2
+#define SL02 15
+#define WL03 3
+#define SL03 12
+#define WL04 4
+#define SL04 5
+#define WL05 5
+#define SL05 8
+#define WL06 6
+#define SL06 7
+#define WL07 7
+#define SL07 9
+#define WL08 8
+#define SL08 11
+#define WL09 9
+#define SL09 13
+#define WL10 10
+#define SL10 14
+#define WL11 11
+#define SL11 15
+#define WL12 12
+#define SL12 6
+#define WL13 13
+#define SL13 7
+#define WL14 14
+#define SL14 9
+#define WL15 15
+#define SL15 8
+
+#define WL16 7
+#define SL16 7
+#define WL17 4
+#define SL17 6
+#define WL18 13
+#define SL18 8
+#define WL19 1
+#define SL19 13
+#define WL20 10
+#define SL20 11
+#define WL21 6
+#define SL21 9
+#define WL22 15
+#define SL22 7
+#define WL23 3
+#define SL23 15
+#define WL24 12
+#define SL24 7
+#define WL25 0
+#define SL25 12
+#define WL26 9
+#define SL26 15
+#define WL27 5
+#define SL27 9
+#define WL28 2
+#define SL28 11
+#define WL29 14
+#define SL29 7
+#define WL30 11
+#define SL30 13
+#define WL31 8
+#define SL31 12
+
+#define WL32 3
+#define SL32 11
+#define WL33 10
+#define SL33 13
+#define WL34 14
+#define SL34 6
+#define WL35 4
+#define SL35 7
+#define WL36 9
+#define SL36 14
+#define WL37 15
+#define SL37 9
+#define WL38 8
+#define SL38 13
+#define WL39 1
+#define SL39 15
+#define WL40 2
+#define SL40 14
+#define WL41 7
+#define SL41 8
+#define WL42 0
+#define SL42 13
+#define WL43 6
+#define SL43 6
+#define WL44 13
+#define SL44 5
+#define WL45 11
+#define SL45 12
+#define WL46 5
+#define SL46 7
+#define WL47 12
+#define SL47 5
+
+#define WL48 1
+#define SL48 11
+#define WL49 9
+#define SL49 12
+#define WL50 11
+#define SL50 14
+#define WL51 10
+#define SL51 15
+#define WL52 0
+#define SL52 14
+#define WL53 8
+#define SL53 15
+#define WL54 12
+#define SL54 9
+#define WL55 4
+#define SL55 8
+#define WL56 13
+#define SL56 9
+#define WL57 3
+#define SL57 14
+#define WL58 7
+#define SL58 5
+#define WL59 15
+#define SL59 6
+#define WL60 14
+#define SL60 8
+#define WL61 5
+#define SL61 6
+#define WL62 6
+#define SL62 5
+#define WL63 2
+#define SL63 12
+
+#define WL64 4
+#define SL64 9
+#define WL65 0
+#define SL65 15
+#define WL66 5
+#define SL66 5
+#define WL67 9
+#define SL67 11
+#define WL68 7
+#define SL68 6
+#define WL69 12
+#define SL69 8
+#define WL70 2
+#define SL70 13
+#define WL71 10
+#define SL71 12
+#define WL72 14
+#define SL72 5
+#define WL73 1
+#define SL73 12
+#define WL74 3
+#define SL74 13
+#define WL75 8
+#define SL75 14
+#define WL76 11
+#define SL76 11
+#define WL77 6
+#define SL77 8
+#define WL78 15
+#define SL78 5
+#define WL79 13
+#define SL79 6
+
+#define WR00 5
+#define SR00 8
+#define WR01 14
+#define SR01 9
+#define WR02 7
+#define SR02 9
+#define WR03 0
+#define SR03 11
+#define WR04 9
+#define SR04 13
+#define WR05 2
+#define SR05 15
+#define WR06 11
+#define SR06 15
+#define WR07 4
+#define SR07 5
+#define WR08 13
+#define SR08 7
+#define WR09 6
+#define SR09 7
+#define WR10 15
+#define SR10 8
+#define WR11 8
+#define SR11 11
+#define WR12 1
+#define SR12 14
+#define WR13 10
+#define SR13 14
+#define WR14 3
+#define SR14 12
+#define WR15 12
+#define SR15 6
+
+#define WR16 6
+#define SR16 9
+#define WR17 11
+#define SR17 13
+#define WR18 3
+#define SR18 15
+#define WR19 7
+#define SR19 7
+#define WR20 0
+#define SR20 12
+#define WR21 13
+#define SR21 8
+#define WR22 5
+#define SR22 9
+#define WR23 10
+#define SR23 11
+#define WR24 14
+#define SR24 7
+#define WR25 15
+#define SR25 7
+#define WR26 8
+#define SR26 12
+#define WR27 12
+#define SR27 7
+#define WR28 4
+#define SR28 6
+#define WR29 9
+#define SR29 15
+#define WR30 1
+#define SR30 13
+#define WR31 2
+#define SR31 11
+
+#define WR32 15
+#define SR32 9
+#define WR33 5
+#define SR33 7
+#define WR34 1
+#define SR34 15
+#define WR35 3
+#define SR35 11
+#define WR36 7
+#define SR36 8
+#define WR37 14
+#define SR37 6
+#define WR38 6
+#define SR38 6
+#define WR39 9
+#define SR39 14
+#define WR40 11
+#define SR40 12
+#define WR41 8
+#define SR41 13
+#define WR42 12
+#define SR42 5
+#define WR43 2
+#define SR43 14
+#define WR44 10
+#define SR44 13
+#define WR45 0
+#define SR45 13
+#define WR46 4
+#define SR46 7
+#define WR47 13
+#define SR47 5
+
+#define WR48 8
+#define SR48 15
+#define WR49 6
+#define SR49 5
+#define WR50 4
+#define SR50 8
+#define WR51 1
+#define SR51 11
+#define WR52 3
+#define SR52 14
+#define WR53 11
+#define SR53 14
+#define WR54 15
+#define SR54 6
+#define WR55 0
+#define SR55 14
+#define WR56 5
+#define SR56 6
+#define WR57 12
+#define SR57 9
+#define WR58 2
+#define SR58 12
+#define WR59 13
+#define SR59 9
+#define WR60 9
+#define SR60 12
+#define WR61 7
+#define SR61 5
+#define WR62 10
+#define SR62 15
+#define WR63 14
+#define SR63 8
+
+#define WR64 12
+#define SR64 8
+#define WR65 15
+#define SR65 5
+#define WR66 10
+#define SR66 12
+#define WR67 4
+#define SR67 9
+#define WR68 1
+#define SR68 12
+#define WR69 5
+#define SR69 5
+#define WR70 8
+#define SR70 14
+#define WR71 7
+#define SR71 6
+#define WR72 6
+#define SR72 8
+#define WR73 2
+#define SR73 13
+#define WR74 13
+#define SR74 6
+#define WR75 14
+#define SR75 5
+#define WR76 0
+#define SR76 15
+#define WR77 3
+#define SR77 13
+#define WR78 9
+#define SR78 11
+#define WR79 11
+#define SR79 11
+
diff --git a/lib/libmd/rmddriver.c b/lib/libmd/rmddriver.c
new file mode 100644
index 0000000..29084a9
--- /dev/null
+++ b/lib/libmd/rmddriver.c
@@ -0,0 +1,53 @@
+/* RIPEMD160DRIVER.C - test driver for RIPEMD160
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/* Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All
+ rights reserved.
+
+ RSA Data Security, Inc. makes no representations concerning either
+ the merchantability of this software or the suitability of this
+ software for any particular purpose. It is provided "as is"
+ without express or implied warranty of any kind.
+
+ These notices must be retained in any copies of any part of this
+ documentation and/or software.
+ */
+
+#include <sys/types.h>
+
+#include <stdio.h>
+#include <time.h>
+#include <string.h>
+#include "ripemd.h"
+
+/* Digests a string and prints the result.
+ */
+static void RIPEMD160String (string)
+char *string;
+{
+ char buf[2*20+1];
+
+ printf ("RIPEMD160 (\"%s\") = %s\n",
+ string, RIPEMD160_Data(string,strlen(string),buf));
+}
+
+/* Digests a reference suite of strings and prints the results.
+ */
+main()
+{
+ printf ("RIPEMD160 test suite:\n");
+
+ RIPEMD160String ("");
+ RIPEMD160String ("abc");
+ RIPEMD160String ("message digest");
+ RIPEMD160String ("abcdefghijklmnopqrstuvwxyz");
+ RIPEMD160String
+ ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
+ RIPEMD160String
+ ("1234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890");
+ return 0;
+}
diff --git a/lib/libmd/sha.3 b/lib/libmd/sha.3
new file mode 100644
index 0000000..f4e2f19
--- /dev/null
+++ b/lib/libmd/sha.3
@@ -0,0 +1,185 @@
+.\"
+.\" ----------------------------------------------------------------------------
+.\" "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
+.\" ----------------------------------------------------------------------------
+.\"
+.\" From: Id: mdX.3,v 1.14 1999/02/11 20:31:49 wollman Exp
+.\" $FreeBSD$
+.\"
+.Dd February 25, 1999
+.Dt SHA 3
+.Os
+.Sh NAME
+.Nm SHA_Init ,
+.Nm SHA_Update ,
+.Nm SHA_Final ,
+.Nm SHA_End ,
+.Nm SHA_File ,
+.Nm SHA_FileChunk ,
+.Nm SHA_Data ,
+.Nm SHA1_Init ,
+.Nm SHA1_Update ,
+.Nm SHA1_Final ,
+.Nm SHA1_End ,
+.Nm SHA1_File ,
+.Nm SHA1_FileChunk ,
+.Nm SHA1_Data
+.Nd calculate the FIPS 160 and 160-1 ``SHA'' message digests
+.Sh LIBRARY
+.Lb libmd
+.Sh SYNOPSIS
+.In sys/types.h
+.In sha.h
+.Ft void
+.Fn SHA_Init "SHA_CTX *context"
+.Ft void
+.Fn SHA_Update "SHA_CTX *context" "const unsigned char *data" "size_t len"
+.Ft void
+.Fn SHA_Final "unsigned char digest[20]" "SHA_CTX *context"
+.Ft "char *"
+.Fn SHA_End "SHA_CTX *context" "char *buf"
+.Ft "char *"
+.Fn SHA_File "const char *filename" "char *buf"
+.Ft "char *"
+.Fn SHA_FileChunk "const char *filename" "char *buf" "off_t offset" "off_t length"
+.Ft "char *"
+.Fn SHA_Data "const unsigned char *data" "unsigned int len" "char *buf"
+.Ft void
+.Fn SHA1_Init "SHA_CTX *context"
+.Ft void
+.Fn SHA1_Update "SHA_CTX *context" "const unsigned char *data" "size_t len"
+.Ft void
+.Fn SHA1_Final "unsigned char digest[20]" "SHA_CTX *context"
+.Ft "char *"
+.Fn SHA1_End "SHA_CTX *context" "char *buf"
+.Ft "char *"
+.Fn SHA1_File "const char *filename" "char *buf"
+.Ft "char *"
+.Fn SHA1_FileChunk "const char *filename" "char *buf" "off_t offset" "off_t length"
+.Ft "char *"
+.Fn SHA1_Data "const unsigned char *data" "unsigned int len" "char *buf"
+.Sh DESCRIPTION
+The
+.Li SHA_
+and
+.Li SHA1_
+functions calculate a 160-bit cryptographic checksum (digest)
+for any number of input bytes.
+A cryptographic checksum is a one-way
+hash function; that is, it is computationally impractical to find
+the input corresponding to a particular output.
+This net result is
+a
+.Dq fingerprint
+of the input-data, which does not disclose the actual input.
+.Pp
+.Tn SHA
+(or
+.Tn SHA-0 )
+is the original Secure Hash Algorithm specified in
+.Tn FIPS
+160.
+It was quickly proven insecure, and has been superseded by
+.Tn SHA-1 .
+.Tn SHA-0
+is included for compatibility purposes only.
+.Pp
+The
+.Fn SHA1_Init ,
+.Fn SHA1_Update ,
+and
+.Fn SHA1_Final
+functions are the core functions.
+Allocate an
+.Vt SHA_CTX ,
+initialize it with
+.Fn SHA1_Init ,
+run over the data with
+.Fn SHA1_Update ,
+and finally extract the result using
+.Fn SHA1_Final .
+.Pp
+.Fn SHA1_End
+is a wrapper for
+.Fn SHA1_Final
+which converts the return value to a 41-character
+(including the terminating '\e0')
+.Tn ASCII
+string which represents the 160 bits in hexadecimal.
+.Pp
+.Fn SHA1_File
+calculates the digest of a file, and uses
+.Fn SHA1_End
+to return the result.
+If the file cannot be opened, a null pointer is returned.
+.Fn SHA1_FileChunk
+is similar to
+.Fn SHA1_File ,
+but it only calculates the digest over a byte-range of the file specified,
+starting at
+.Fa offset
+and spanning
+.Fa length
+bytes.
+If the
+.Fa length
+parameter is specified as 0, or more than the length of the remaining part
+of the file,
+.Fn SHA1_FileChunk
+calculates the digest from
+.Fa offset
+to the end of file.
+.Fn SHA1_Data
+calculates the digest of a chunk of data in memory, and uses
+.Fn SHA1_End
+to return the result.
+.Pp
+When using
+.Fn SHA1_End ,
+.Fn SHA1_File ,
+or
+.Fn SHA1_Data ,
+the
+.Fa buf
+argument can be a null pointer, in which case the returned string
+is allocated with
+.Xr malloc 3
+and subsequently must be explicitly deallocated using
+.Xr free 3
+after use.
+If the
+.Fa buf
+argument is non-null it must point to at least 41 characters of buffer space.
+.Sh SEE ALSO
+.Xr md2 3 ,
+.Xr md4 3 ,
+.Xr md5 3 ,
+.Xr ripemd 3 ,
+.Xr sha256 3
+.Sh HISTORY
+These functions appeared in
+.Fx 4.0 .
+.Sh AUTHORS
+The core hash routines were implemented by Eric Young based on the
+published
+.Tn FIPS
+standards.
+.Sh BUGS
+No method is known to exist which finds two files having the same hash value,
+nor to find a file with a specific hash value.
+There is on the other hand no guarantee that such a method does not exist.
+.Pp
+The
+.Tn IA32
+(Intel) implementation of
+.Tn SHA-1
+makes heavy use of the
+.Ql bswapl
+instruction, which is not present on the original 80386.
+Attempts to use
+.Tn SHA-1
+on those processors will cause an illegal instruction trap.
+(Arguably, the kernel should simply emulate this instruction.)
diff --git a/lib/libmd/sha.h b/lib/libmd/sha.h
new file mode 100644
index 0000000..8a0b7c2
--- /dev/null
+++ b/lib/libmd/sha.h
@@ -0,0 +1,98 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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 cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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 licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _SHA_H_
+#define _SHA_H_ 1
+
+#include <sys/cdefs.h>
+#include <sys/types.h> /* XXX switch to machine/ansi.h and __ types */
+
+#define SHA_CBLOCK 64
+#define SHA_LBLOCK 16
+#define SHA_BLOCK 16
+#define SHA_LAST_BLOCK 56
+#define SHA_LENGTH_BLOCK 8
+#define SHA_DIGEST_LENGTH 20
+
+typedef struct SHAstate_st {
+ u_int32_t h0, h1, h2, h3, h4;
+ u_int32_t Nl, Nh;
+ u_int32_t data[SHA_LBLOCK];
+ int num;
+} SHA_CTX;
+#define SHA1_CTX SHA_CTX
+
+__BEGIN_DECLS
+void SHA_Init(SHA_CTX *c);
+void SHA_Update(SHA_CTX *c, const void *data, size_t len);
+void SHA_Final(unsigned char *md, SHA_CTX *c);
+char *SHA_End(SHA_CTX *, char *);
+char *SHA_File(const char *, char *);
+char *SHA_FileChunk(const char *, char *, off_t, off_t);
+char *SHA_Data(const void *, unsigned int, char *);
+void SHA1_Init(SHA_CTX *c);
+void SHA1_Update(SHA_CTX *c, const void *data, size_t len);
+void SHA1_Final(unsigned char *md, SHA_CTX *c);
+char *SHA1_End(SHA_CTX *, char *);
+char *SHA1_File(const char *, char *);
+char *SHA1_FileChunk(const char *, char *, off_t, off_t);
+char *SHA1_Data(const void *, unsigned int, char *);
+__END_DECLS
+
+#endif /* !_SHA_H_ */
diff --git a/lib/libmd/sha0c.c b/lib/libmd/sha0c.c
new file mode 100644
index 0000000..b35b7f2
--- /dev/null
+++ b/lib/libmd/sha0c.c
@@ -0,0 +1,454 @@
+/* crypto/sha/sha_dgst.c */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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 cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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 licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#if 0
+#include <machine/ansi.h> /* we use the __ variants of bit-sized types */
+#endif
+#include <machine/endian.h>
+
+#define SHA_0
+#undef SHA_1
+#include "sha.h"
+#include "sha_locl.h"
+
+char *SHA_version="SHA part of SSLeay 0.9.0b 11-Oct-1998";
+
+/* Implemented from SHA-0 document - The Secure Hash Algorithm
+ */
+
+#define INIT_DATA_h0 (unsigned long)0x67452301L
+#define INIT_DATA_h1 (unsigned long)0xefcdab89L
+#define INIT_DATA_h2 (unsigned long)0x98badcfeL
+#define INIT_DATA_h3 (unsigned long)0x10325476L
+#define INIT_DATA_h4 (unsigned long)0xc3d2e1f0L
+
+#define K_00_19 0x5a827999L
+#define K_20_39 0x6ed9eba1L
+#define K_40_59 0x8f1bbcdcL
+#define K_60_79 0xca62c1d6L
+
+#ifndef NOPROTO
+ void sha_block(SHA_CTX *c, const u_int32_t *p, int num);
+#else
+ void sha_block();
+#endif
+
+#define M_c2nl c2nl
+#define M_p_c2nl p_c2nl
+#define M_c2nl_p c2nl_p
+#define M_p_c2nl_p p_c2nl_p
+#define M_nl2c nl2c
+
+void SHA_Init(c)
+SHA_CTX *c;
+ {
+ c->h0=INIT_DATA_h0;
+ c->h1=INIT_DATA_h1;
+ c->h2=INIT_DATA_h2;
+ c->h3=INIT_DATA_h3;
+ c->h4=INIT_DATA_h4;
+ c->Nl=0;
+ c->Nh=0;
+ c->num=0;
+ }
+
+void SHA_Update(c, in, len)
+SHA_CTX *c;
+const void *in;
+size_t len;
+ {
+ u_int32_t *p;
+ int ew,ec,sw,sc;
+ u_int32_t l;
+ const unsigned char *data = in;
+
+ if (len == 0) return;
+
+ l=(c->Nl+(len<<3))&0xffffffffL;
+ if (l < c->Nl) /* overflow */
+ c->Nh++;
+ c->Nh+=(len>>29);
+ c->Nl=l;
+
+ if (c->num != 0)
+ {
+ p=c->data;
+ sw=c->num>>2;
+ sc=c->num&0x03;
+
+ if ((c->num+len) >= SHA_CBLOCK)
+ {
+ l= p[sw];
+ M_p_c2nl(data,l,sc);
+ p[sw++]=l;
+ for (; sw<SHA_LBLOCK; sw++)
+ {
+ M_c2nl(data,l);
+ p[sw]=l;
+ }
+ len-=(SHA_CBLOCK-c->num);
+
+ sha_block(c,p,64);
+ c->num=0;
+ /* drop through and do the rest */
+ }
+ else
+ {
+ c->num+=(int)len;
+ if ((sc+len) < 4) /* ugly, add char's to a word */
+ {
+ l= p[sw];
+ M_p_c2nl_p(data,l,sc,len);
+ p[sw]=l;
+ }
+ else
+ {
+ ew=(c->num>>2);
+ ec=(c->num&0x03);
+ l= p[sw];
+ M_p_c2nl(data,l,sc);
+ p[sw++]=l;
+ for (; sw < ew; sw++)
+ { M_c2nl(data,l); p[sw]=l; }
+ if (ec)
+ {
+ M_c2nl_p(data,l,ec);
+ p[sw]=l;
+ }
+ }
+ return;
+ }
+ }
+ /* We can only do the following code for assember, the reason
+ * being that the sha_block 'C' version changes the values
+ * in the 'data' array. The assember code avoids this and
+ * copies it to a local array. I should be able to do this for
+ * the C version as well....
+ */
+#if 1
+#if BYTE_ORDER == BIG_ENDIAN || defined(SHA_ASM)
+ if ((((unsigned int)data)%sizeof(u_int32_t)) == 0)
+ {
+ sw=len/SHA_CBLOCK;
+ if (sw)
+ {
+ sw*=SHA_CBLOCK;
+ sha_block(c,(u_int32_t *)data,sw);
+ data+=sw;
+ len-=sw;
+ }
+ }
+#endif
+#endif
+ /* we now can process the input data in blocks of SHA_CBLOCK
+ * chars and save the leftovers to c->data. */
+ p=c->data;
+ while (len >= SHA_CBLOCK)
+ {
+#if BYTE_ORDER == BIG_ENDIAN || BYTE_ORDER == LITTLE_ENDIAN
+ if (p != (u_int32_t *)data)
+ memcpy(p,data,SHA_CBLOCK);
+ data+=SHA_CBLOCK;
+# if BYTE_ORDER == LITTLE_ENDIAN
+# ifndef SHA_ASM /* Will not happen */
+ for (sw=(SHA_LBLOCK/4); sw; sw--)
+ {
+ Endian_Reverse32(p[0]);
+ Endian_Reverse32(p[1]);
+ Endian_Reverse32(p[2]);
+ Endian_Reverse32(p[3]);
+ p+=4;
+ }
+ p=c->data;
+# endif
+# endif
+#else
+ for (sw=(SHA_BLOCK/4); sw; sw--)
+ {
+ M_c2nl(data,l); *(p++)=l;
+ M_c2nl(data,l); *(p++)=l;
+ M_c2nl(data,l); *(p++)=l;
+ M_c2nl(data,l); *(p++)=l;
+ }
+ p=c->data;
+#endif
+ sha_block(c,p,64);
+ len-=SHA_CBLOCK;
+ }
+ ec=(int)len;
+ c->num=ec;
+ ew=(ec>>2);
+ ec&=0x03;
+
+ for (sw=0; sw < ew; sw++)
+ { M_c2nl(data,l); p[sw]=l; }
+ M_c2nl_p(data,l,ec);
+ p[sw]=l;
+ }
+
+void SHA_Transform(c,b)
+SHA_CTX *c;
+unsigned char *b;
+ {
+ u_int32_t p[16];
+#if BYTE_ORDER == LITTLE_ENDIAN
+ u_int32_t *q;
+ int i;
+#endif
+
+#if BYTE_ORDER == BIG_ENDIAN || BYTE_ORDER == LITTLE_ENDIAN
+ memcpy(p,b,64);
+#if BYTE_ORDER == LITTLE_ENDIAN
+ q=p;
+ for (i=(SHA_LBLOCK/4); i; i--)
+ {
+ Endian_Reverse32(q[0]);
+ Endian_Reverse32(q[1]);
+ Endian_Reverse32(q[2]);
+ Endian_Reverse32(q[3]);
+ q+=4;
+ }
+#endif
+#else
+ q=p;
+ for (i=(SHA_LBLOCK/4); i; i--)
+ {
+ u_int32_t l;
+ c2nl(b,l); *(q++)=l;
+ c2nl(b,l); *(q++)=l;
+ c2nl(b,l); *(q++)=l;
+ c2nl(b,l); *(q++)=l;
+ }
+#endif
+ sha_block(c,p,64);
+ }
+
+void sha_block(c, W, num)
+SHA_CTX *c;
+const u_int32_t *W;
+int num;
+ {
+ u_int32_t A,B,C,D,E,T;
+ u_int32_t X[16];
+
+ A=c->h0;
+ B=c->h1;
+ C=c->h2;
+ D=c->h3;
+ E=c->h4;
+
+ for (;;)
+ {
+ BODY_00_15( 0,A,B,C,D,E,T,W);
+ BODY_00_15( 1,T,A,B,C,D,E,W);
+ BODY_00_15( 2,E,T,A,B,C,D,W);
+ BODY_00_15( 3,D,E,T,A,B,C,W);
+ BODY_00_15( 4,C,D,E,T,A,B,W);
+ BODY_00_15( 5,B,C,D,E,T,A,W);
+ BODY_00_15( 6,A,B,C,D,E,T,W);
+ BODY_00_15( 7,T,A,B,C,D,E,W);
+ BODY_00_15( 8,E,T,A,B,C,D,W);
+ BODY_00_15( 9,D,E,T,A,B,C,W);
+ BODY_00_15(10,C,D,E,T,A,B,W);
+ BODY_00_15(11,B,C,D,E,T,A,W);
+ BODY_00_15(12,A,B,C,D,E,T,W);
+ BODY_00_15(13,T,A,B,C,D,E,W);
+ BODY_00_15(14,E,T,A,B,C,D,W);
+ BODY_00_15(15,D,E,T,A,B,C,W);
+ BODY_16_19(16,C,D,E,T,A,B,W,W,W,W);
+ BODY_16_19(17,B,C,D,E,T,A,W,W,W,W);
+ BODY_16_19(18,A,B,C,D,E,T,W,W,W,W);
+ BODY_16_19(19,T,A,B,C,D,E,W,W,W,X);
+
+ BODY_20_31(20,E,T,A,B,C,D,W,W,W,X);
+ BODY_20_31(21,D,E,T,A,B,C,W,W,W,X);
+ BODY_20_31(22,C,D,E,T,A,B,W,W,W,X);
+ BODY_20_31(23,B,C,D,E,T,A,W,W,W,X);
+ BODY_20_31(24,A,B,C,D,E,T,W,W,X,X);
+ BODY_20_31(25,T,A,B,C,D,E,W,W,X,X);
+ BODY_20_31(26,E,T,A,B,C,D,W,W,X,X);
+ BODY_20_31(27,D,E,T,A,B,C,W,W,X,X);
+ BODY_20_31(28,C,D,E,T,A,B,W,W,X,X);
+ BODY_20_31(29,B,C,D,E,T,A,W,W,X,X);
+ BODY_20_31(30,A,B,C,D,E,T,W,X,X,X);
+ BODY_20_31(31,T,A,B,C,D,E,W,X,X,X);
+ BODY_32_39(32,E,T,A,B,C,D,X);
+ BODY_32_39(33,D,E,T,A,B,C,X);
+ BODY_32_39(34,C,D,E,T,A,B,X);
+ BODY_32_39(35,B,C,D,E,T,A,X);
+ BODY_32_39(36,A,B,C,D,E,T,X);
+ BODY_32_39(37,T,A,B,C,D,E,X);
+ BODY_32_39(38,E,T,A,B,C,D,X);
+ BODY_32_39(39,D,E,T,A,B,C,X);
+
+ BODY_40_59(40,C,D,E,T,A,B,X);
+ BODY_40_59(41,B,C,D,E,T,A,X);
+ BODY_40_59(42,A,B,C,D,E,T,X);
+ BODY_40_59(43,T,A,B,C,D,E,X);
+ BODY_40_59(44,E,T,A,B,C,D,X);
+ BODY_40_59(45,D,E,T,A,B,C,X);
+ BODY_40_59(46,C,D,E,T,A,B,X);
+ BODY_40_59(47,B,C,D,E,T,A,X);
+ BODY_40_59(48,A,B,C,D,E,T,X);
+ BODY_40_59(49,T,A,B,C,D,E,X);
+ BODY_40_59(50,E,T,A,B,C,D,X);
+ BODY_40_59(51,D,E,T,A,B,C,X);
+ BODY_40_59(52,C,D,E,T,A,B,X);
+ BODY_40_59(53,B,C,D,E,T,A,X);
+ BODY_40_59(54,A,B,C,D,E,T,X);
+ BODY_40_59(55,T,A,B,C,D,E,X);
+ BODY_40_59(56,E,T,A,B,C,D,X);
+ BODY_40_59(57,D,E,T,A,B,C,X);
+ BODY_40_59(58,C,D,E,T,A,B,X);
+ BODY_40_59(59,B,C,D,E,T,A,X);
+
+ BODY_60_79(60,A,B,C,D,E,T,X);
+ BODY_60_79(61,T,A,B,C,D,E,X);
+ BODY_60_79(62,E,T,A,B,C,D,X);
+ BODY_60_79(63,D,E,T,A,B,C,X);
+ BODY_60_79(64,C,D,E,T,A,B,X);
+ BODY_60_79(65,B,C,D,E,T,A,X);
+ BODY_60_79(66,A,B,C,D,E,T,X);
+ BODY_60_79(67,T,A,B,C,D,E,X);
+ BODY_60_79(68,E,T,A,B,C,D,X);
+ BODY_60_79(69,D,E,T,A,B,C,X);
+ BODY_60_79(70,C,D,E,T,A,B,X);
+ BODY_60_79(71,B,C,D,E,T,A,X);
+ BODY_60_79(72,A,B,C,D,E,T,X);
+ BODY_60_79(73,T,A,B,C,D,E,X);
+ BODY_60_79(74,E,T,A,B,C,D,X);
+ BODY_60_79(75,D,E,T,A,B,C,X);
+ BODY_60_79(76,C,D,E,T,A,B,X);
+ BODY_60_79(77,B,C,D,E,T,A,X);
+ BODY_60_79(78,A,B,C,D,E,T,X);
+ BODY_60_79(79,T,A,B,C,D,E,X);
+
+ c->h0=(c->h0+E)&0xffffffffL;
+ c->h1=(c->h1+T)&0xffffffffL;
+ c->h2=(c->h2+A)&0xffffffffL;
+ c->h3=(c->h3+B)&0xffffffffL;
+ c->h4=(c->h4+C)&0xffffffffL;
+
+ num-=64;
+ if (num <= 0) break;
+
+ A=c->h0;
+ B=c->h1;
+ C=c->h2;
+ D=c->h3;
+ E=c->h4;
+
+ W+=16;
+ }
+ }
+
+void SHA_Final(md, c)
+unsigned char *md;
+SHA_CTX *c;
+ {
+ int i,j;
+ u_int32_t l;
+ u_int32_t *p;
+ static unsigned char end[4]={0x80,0x00,0x00,0x00};
+ unsigned char *cp=end;
+
+ /* c->num should definitly have room for at least one more byte. */
+ p=c->data;
+ j=c->num;
+ i=j>>2;
+#ifdef PURIFY
+ if ((j&0x03) == 0) p[i]=0;
+#endif
+ l=p[i];
+ M_p_c2nl(cp,l,j&0x03);
+ p[i]=l;
+ i++;
+ /* i is the next 'undefined word' */
+ if (c->num >= SHA_LAST_BLOCK)
+ {
+ for (; i<SHA_LBLOCK; i++)
+ p[i]=0;
+ sha_block(c,p,64);
+ i=0;
+ }
+ for (; i<(SHA_LBLOCK-2); i++)
+ p[i]=0;
+ p[SHA_LBLOCK-2]=c->Nh;
+ p[SHA_LBLOCK-1]=c->Nl;
+ sha_block(c,p,64);
+ cp=md;
+ l=c->h0; nl2c(l,cp);
+ l=c->h1; nl2c(l,cp);
+ l=c->h2; nl2c(l,cp);
+ l=c->h3; nl2c(l,cp);
+ l=c->h4; nl2c(l,cp);
+
+ /* clear stuff, sha_block may be leaving some stuff on the stack
+ * but I'm not worried :-) */
+ c->num=0;
+/* memset((char *)&c,0,sizeof(c));*/
+ }
+
diff --git a/lib/libmd/sha1c.c b/lib/libmd/sha1c.c
new file mode 100644
index 0000000..ba3278a
--- /dev/null
+++ b/lib/libmd/sha1c.c
@@ -0,0 +1,490 @@
+/* crypto/sha/sha1dgst.c */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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 cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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 licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#if 0
+#include <machine/ansi.h> /* we use the __ variants of bit-sized types */
+#endif
+#include <machine/endian.h>
+
+#undef SHA_0
+#define SHA_1
+#include "sha.h"
+#include "sha_locl.h"
+
+/*
+ * The assembly-language code is not position-independent, so don't
+ * try to use it in a shared library.
+ */
+#ifdef PIC
+#undef SHA1_ASM
+#endif
+
+char *SHA1_version="SHA1 part of SSLeay 0.9.0b 11-Oct-1998";
+
+/* Implemented from SHA-1 document - The Secure Hash Algorithm
+ */
+
+#define INIT_DATA_h0 (unsigned long)0x67452301L
+#define INIT_DATA_h1 (unsigned long)0xefcdab89L
+#define INIT_DATA_h2 (unsigned long)0x98badcfeL
+#define INIT_DATA_h3 (unsigned long)0x10325476L
+#define INIT_DATA_h4 (unsigned long)0xc3d2e1f0L
+
+#define K_00_19 0x5a827999L
+#define K_20_39 0x6ed9eba1L
+#define K_40_59 0x8f1bbcdcL
+#define K_60_79 0xca62c1d6L
+
+#ifndef NOPROTO
+# ifdef SHA1_ASM
+ void sha1_block_x86(SHA_CTX *c, const u_int32_t *p, int num);
+# define sha1_block sha1_block_x86
+# else
+ void sha1_block(SHA_CTX *c, const u_int32_t *p, int num);
+# endif
+#else
+# ifdef SHA1_ASM
+ void sha1_block_x86();
+# define sha1_block sha1_block_x86
+# else
+ void sha1_block();
+# endif
+#endif
+
+
+#if BYTE_ORDER == LITTLE_ENDIAN && defined(SHA1_ASM)
+# define M_c2nl c2l
+# define M_p_c2nl p_c2l
+# define M_c2nl_p c2l_p
+# define M_p_c2nl_p p_c2l_p
+# define M_nl2c l2c
+#else
+# define M_c2nl c2nl
+# define M_p_c2nl p_c2nl
+# define M_c2nl_p c2nl_p
+# define M_p_c2nl_p p_c2nl_p
+# define M_nl2c nl2c
+#endif
+
+void SHA1_Init(c)
+SHA_CTX *c;
+ {
+ c->h0=INIT_DATA_h0;
+ c->h1=INIT_DATA_h1;
+ c->h2=INIT_DATA_h2;
+ c->h3=INIT_DATA_h3;
+ c->h4=INIT_DATA_h4;
+ c->Nl=0;
+ c->Nh=0;
+ c->num=0;
+ }
+
+void
+SHA1_Update(c, in, len)
+ SHA_CTX *c;
+ const void *in;
+ size_t len;
+{
+ u_int32_t *p;
+ int ew,ec,sw,sc;
+ u_int32_t l;
+ const unsigned char *data = in;
+
+ if (len == 0) return;
+
+ l=(c->Nl+(len<<3))&0xffffffffL;
+ if (l < c->Nl) /* overflow */
+ c->Nh++;
+ c->Nh+=(len>>29);
+ c->Nl=l;
+
+ if (c->num != 0)
+ {
+ p=c->data;
+ sw=c->num>>2;
+ sc=c->num&0x03;
+
+ if ((c->num+len) >= SHA_CBLOCK)
+ {
+ l= p[sw];
+ M_p_c2nl(data,l,sc);
+ p[sw++]=l;
+ for (; sw<SHA_LBLOCK; sw++)
+ {
+ M_c2nl(data,l);
+ p[sw]=l;
+ }
+ len-=(SHA_CBLOCK-c->num);
+
+ sha1_block(c,p,64);
+ c->num=0;
+ /* drop through and do the rest */
+ }
+ else
+ {
+ c->num+=(int)len;
+ if ((sc+len) < 4) /* ugly, add char's to a word */
+ {
+ l= p[sw];
+ M_p_c2nl_p(data,l,sc,len);
+ p[sw]=l;
+ }
+ else
+ {
+ ew=(c->num>>2);
+ ec=(c->num&0x03);
+ l= p[sw];
+ M_p_c2nl(data,l,sc);
+ p[sw++]=l;
+ for (; sw < ew; sw++)
+ { M_c2nl(data,l); p[sw]=l; }
+ if (ec)
+ {
+ M_c2nl_p(data,l,ec);
+ p[sw]=l;
+ }
+ }
+ return;
+ }
+ }
+ /* We can only do the following code for assember, the reason
+ * being that the sha1_block 'C' version changes the values
+ * in the 'data' array. The assember code avoids this and
+ * copies it to a local array. I should be able to do this for
+ * the C version as well....
+ */
+#if 1
+#if BYTE_ORDER == BIG_ENDIAN || defined(SHA1_ASM)
+ if ((((unsigned int)data)%sizeof(u_int32_t)) == 0)
+ {
+ sw=len/SHA_CBLOCK;
+ if (sw)
+ {
+ sw*=SHA_CBLOCK;
+ sha1_block(c,(u_int32_t *)data,sw);
+ data+=sw;
+ len-=sw;
+ }
+ }
+#endif
+#endif
+ /* we now can process the input data in blocks of SHA_CBLOCK
+ * chars and save the leftovers to c->data. */
+ p=c->data;
+ while (len >= SHA_CBLOCK)
+ {
+#if BYTE_ORDER == BIG_ENDIAN || BYTE_ORDER == LITTLE_ENDIAN
+ if (p != (u_int32_t *)data)
+ memcpy(p,data,SHA_CBLOCK);
+ data+=SHA_CBLOCK;
+# if BYTE_ORDER == LITTLE_ENDIAN
+# ifndef SHA1_ASM /* Will not happen */
+ for (sw=(SHA_LBLOCK/4); sw; sw--)
+ {
+ Endian_Reverse32(p[0]);
+ Endian_Reverse32(p[1]);
+ Endian_Reverse32(p[2]);
+ Endian_Reverse32(p[3]);
+ p+=4;
+ }
+ p=c->data;
+# endif
+# endif
+#else
+ for (sw=(SHA_BLOCK/4); sw; sw--)
+ {
+ M_c2nl(data,l); *(p++)=l;
+ M_c2nl(data,l); *(p++)=l;
+ M_c2nl(data,l); *(p++)=l;
+ M_c2nl(data,l); *(p++)=l;
+ }
+ p=c->data;
+#endif
+ sha1_block(c,p,64);
+ len-=SHA_CBLOCK;
+ }
+ ec=(int)len;
+ c->num=ec;
+ ew=(ec>>2);
+ ec&=0x03;
+
+ for (sw=0; sw < ew; sw++)
+ { M_c2nl(data,l); p[sw]=l; }
+ M_c2nl_p(data,l,ec);
+ p[sw]=l;
+ }
+
+void SHA1_Transform(c,b)
+SHA_CTX *c;
+unsigned char *b;
+ {
+ u_int32_t p[16];
+#if BYTE_ORDER != BIG_ENDIAN
+ u_int32_t *q;
+ int i;
+#endif
+
+#if BYTE_ORDER == BIG_ENDIAN || BYTE_ORDER == LITTLE_ENDIAN
+ memcpy(p,b,64);
+#if BYTE_ORDER == LITTLE_ENDIAN
+ q=p;
+ for (i=(SHA_LBLOCK/4); i; i--)
+ {
+ Endian_Reverse32(q[0]);
+ Endian_Reverse32(q[1]);
+ Endian_Reverse32(q[2]);
+ Endian_Reverse32(q[3]);
+ q+=4;
+ }
+#endif
+#else
+ q=p;
+ for (i=(SHA_LBLOCK/4); i; i--)
+ {
+ u_int32_t l;
+ c2nl(b,l); *(q++)=l;
+ c2nl(b,l); *(q++)=l;
+ c2nl(b,l); *(q++)=l;
+ c2nl(b,l); *(q++)=l;
+ }
+#endif
+ sha1_block(c,p,64);
+ }
+
+#ifndef SHA1_ASM
+
+void
+sha1_block(c, W, num)
+ SHA_CTX *c;
+ const u_int32_t *W;
+ int num;
+{
+ u_int32_t A,B,C,D,E,T;
+ u_int32_t X[16];
+
+ A=c->h0;
+ B=c->h1;
+ C=c->h2;
+ D=c->h3;
+ E=c->h4;
+
+ for (;;)
+ {
+ BODY_00_15( 0,A,B,C,D,E,T,W);
+ BODY_00_15( 1,T,A,B,C,D,E,W);
+ BODY_00_15( 2,E,T,A,B,C,D,W);
+ BODY_00_15( 3,D,E,T,A,B,C,W);
+ BODY_00_15( 4,C,D,E,T,A,B,W);
+ BODY_00_15( 5,B,C,D,E,T,A,W);
+ BODY_00_15( 6,A,B,C,D,E,T,W);
+ BODY_00_15( 7,T,A,B,C,D,E,W);
+ BODY_00_15( 8,E,T,A,B,C,D,W);
+ BODY_00_15( 9,D,E,T,A,B,C,W);
+ BODY_00_15(10,C,D,E,T,A,B,W);
+ BODY_00_15(11,B,C,D,E,T,A,W);
+ BODY_00_15(12,A,B,C,D,E,T,W);
+ BODY_00_15(13,T,A,B,C,D,E,W);
+ BODY_00_15(14,E,T,A,B,C,D,W);
+ BODY_00_15(15,D,E,T,A,B,C,W);
+ BODY_16_19(16,C,D,E,T,A,B,W,W,W,W);
+ BODY_16_19(17,B,C,D,E,T,A,W,W,W,W);
+ BODY_16_19(18,A,B,C,D,E,T,W,W,W,W);
+ BODY_16_19(19,T,A,B,C,D,E,W,W,W,X);
+
+ BODY_20_31(20,E,T,A,B,C,D,W,W,W,X);
+ BODY_20_31(21,D,E,T,A,B,C,W,W,W,X);
+ BODY_20_31(22,C,D,E,T,A,B,W,W,W,X);
+ BODY_20_31(23,B,C,D,E,T,A,W,W,W,X);
+ BODY_20_31(24,A,B,C,D,E,T,W,W,X,X);
+ BODY_20_31(25,T,A,B,C,D,E,W,W,X,X);
+ BODY_20_31(26,E,T,A,B,C,D,W,W,X,X);
+ BODY_20_31(27,D,E,T,A,B,C,W,W,X,X);
+ BODY_20_31(28,C,D,E,T,A,B,W,W,X,X);
+ BODY_20_31(29,B,C,D,E,T,A,W,W,X,X);
+ BODY_20_31(30,A,B,C,D,E,T,W,X,X,X);
+ BODY_20_31(31,T,A,B,C,D,E,W,X,X,X);
+ BODY_32_39(32,E,T,A,B,C,D,X);
+ BODY_32_39(33,D,E,T,A,B,C,X);
+ BODY_32_39(34,C,D,E,T,A,B,X);
+ BODY_32_39(35,B,C,D,E,T,A,X);
+ BODY_32_39(36,A,B,C,D,E,T,X);
+ BODY_32_39(37,T,A,B,C,D,E,X);
+ BODY_32_39(38,E,T,A,B,C,D,X);
+ BODY_32_39(39,D,E,T,A,B,C,X);
+
+ BODY_40_59(40,C,D,E,T,A,B,X);
+ BODY_40_59(41,B,C,D,E,T,A,X);
+ BODY_40_59(42,A,B,C,D,E,T,X);
+ BODY_40_59(43,T,A,B,C,D,E,X);
+ BODY_40_59(44,E,T,A,B,C,D,X);
+ BODY_40_59(45,D,E,T,A,B,C,X);
+ BODY_40_59(46,C,D,E,T,A,B,X);
+ BODY_40_59(47,B,C,D,E,T,A,X);
+ BODY_40_59(48,A,B,C,D,E,T,X);
+ BODY_40_59(49,T,A,B,C,D,E,X);
+ BODY_40_59(50,E,T,A,B,C,D,X);
+ BODY_40_59(51,D,E,T,A,B,C,X);
+ BODY_40_59(52,C,D,E,T,A,B,X);
+ BODY_40_59(53,B,C,D,E,T,A,X);
+ BODY_40_59(54,A,B,C,D,E,T,X);
+ BODY_40_59(55,T,A,B,C,D,E,X);
+ BODY_40_59(56,E,T,A,B,C,D,X);
+ BODY_40_59(57,D,E,T,A,B,C,X);
+ BODY_40_59(58,C,D,E,T,A,B,X);
+ BODY_40_59(59,B,C,D,E,T,A,X);
+
+ BODY_60_79(60,A,B,C,D,E,T,X);
+ BODY_60_79(61,T,A,B,C,D,E,X);
+ BODY_60_79(62,E,T,A,B,C,D,X);
+ BODY_60_79(63,D,E,T,A,B,C,X);
+ BODY_60_79(64,C,D,E,T,A,B,X);
+ BODY_60_79(65,B,C,D,E,T,A,X);
+ BODY_60_79(66,A,B,C,D,E,T,X);
+ BODY_60_79(67,T,A,B,C,D,E,X);
+ BODY_60_79(68,E,T,A,B,C,D,X);
+ BODY_60_79(69,D,E,T,A,B,C,X);
+ BODY_60_79(70,C,D,E,T,A,B,X);
+ BODY_60_79(71,B,C,D,E,T,A,X);
+ BODY_60_79(72,A,B,C,D,E,T,X);
+ BODY_60_79(73,T,A,B,C,D,E,X);
+ BODY_60_79(74,E,T,A,B,C,D,X);
+ BODY_60_79(75,D,E,T,A,B,C,X);
+ BODY_60_79(76,C,D,E,T,A,B,X);
+ BODY_60_79(77,B,C,D,E,T,A,X);
+ BODY_60_79(78,A,B,C,D,E,T,X);
+ BODY_60_79(79,T,A,B,C,D,E,X);
+
+ c->h0=(c->h0+E)&0xffffffffL;
+ c->h1=(c->h1+T)&0xffffffffL;
+ c->h2=(c->h2+A)&0xffffffffL;
+ c->h3=(c->h3+B)&0xffffffffL;
+ c->h4=(c->h4+C)&0xffffffffL;
+
+ num-=64;
+ if (num <= 0) break;
+
+ A=c->h0;
+ B=c->h1;
+ C=c->h2;
+ D=c->h3;
+ E=c->h4;
+
+ W+=16;
+ }
+ }
+#endif
+
+void SHA1_Final(md, c)
+unsigned char *md;
+SHA_CTX *c;
+ {
+ int i,j;
+ u_int32_t l;
+ u_int32_t *p;
+ static unsigned char end[4]={0x80,0x00,0x00,0x00};
+ unsigned char *cp=end;
+
+ /* c->num should definitly have room for at least one more byte. */
+ p=c->data;
+ j=c->num;
+ i=j>>2;
+#ifdef PURIFY
+ if ((j&0x03) == 0) p[i]=0;
+#endif
+ l=p[i];
+ M_p_c2nl(cp,l,j&0x03);
+ p[i]=l;
+ i++;
+ /* i is the next 'undefined word' */
+ if (c->num >= SHA_LAST_BLOCK)
+ {
+ for (; i<SHA_LBLOCK; i++)
+ p[i]=0;
+ sha1_block(c,p,64);
+ i=0;
+ }
+ for (; i<(SHA_LBLOCK-2); i++)
+ p[i]=0;
+ p[SHA_LBLOCK-2]=c->Nh;
+ p[SHA_LBLOCK-1]=c->Nl;
+#if BYTE_ORDER == LITTLE_ENDIAN && defined(SHA1_ASM)
+ Endian_Reverse32(p[SHA_LBLOCK-2]);
+ Endian_Reverse32(p[SHA_LBLOCK-1]);
+#endif
+ sha1_block(c,p,64);
+ cp=md;
+ l=c->h0; nl2c(l,cp);
+ l=c->h1; nl2c(l,cp);
+ l=c->h2; nl2c(l,cp);
+ l=c->h3; nl2c(l,cp);
+ l=c->h4; nl2c(l,cp);
+
+ /* clear stuff, sha1_block may be leaving some stuff on the stack
+ * but I'm not worried :-) */
+ c->num=0;
+/* memset((char *)&c,0,sizeof(c));*/
+ }
+
diff --git a/lib/libmd/sha256.3 b/lib/libmd/sha256.3
new file mode 100644
index 0000000..fb96100
--- /dev/null
+++ b/lib/libmd/sha256.3
@@ -0,0 +1,139 @@
+.\"
+.\" ----------------------------------------------------------------------------
+.\" "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
+.\" ----------------------------------------------------------------------------
+.\"
+.\" From: Id: mdX.3,v 1.14 1999/02/11 20:31:49 wollman Exp
+.\" $FreeBSD$
+.\"
+.Dd September 14, 2005
+.Dt SHA256 3
+.Os
+.Sh NAME
+.Nm SHA256_Init ,
+.Nm SHA256_Update ,
+.Nm SHA256_Final ,
+.Nm SHA256_End ,
+.Nm SHA256_File ,
+.Nm SHA256_FileChunk ,
+.Nm SHA256_Data
+.Nd calculate the FIPS 180-2 ``SHA-256'' message digest
+.Sh LIBRARY
+.Lb libmd
+.Sh SYNOPSIS
+.In sys/types.h
+.In sha256.h
+.Ft void
+.Fn SHA256_Init "SHA256_CTX *context"
+.Ft void
+.Fn SHA256_Update "SHA256_CTX *context" "const unsigned char *data" "size_t len"
+.Ft void
+.Fn SHA256_Final "unsigned char digest[32]" "SHA256_CTX *context"
+.Ft "char *"
+.Fn SHA256_End "SHA256_CTX *context" "char *buf"
+.Ft "char *"
+.Fn SHA256_File "const char *filename" "char *buf"
+.Ft "char *"
+.Fn SHA256_FileChunk "const char *filename" "char *buf" "off_t offset" "off_t length"
+.Ft "char *"
+.Fn SHA256_Data "const unsigned char *data" "unsigned int len" "char *buf"
+.Sh DESCRIPTION
+The
+.Li SHA256_
+functions calculate a 256-bit cryptographic checksum (digest)
+for any number of input bytes.
+A cryptographic checksum is a one-way
+hash function; that is, it is computationally impractical to find
+the input corresponding to a particular output.
+This net result is
+a
+.Dq fingerprint
+of the input-data, which does not disclose the actual input.
+.Pp
+The
+.Fn SHA256_Init ,
+.Fn SHA256_Update ,
+and
+.Fn SHA256_Final
+functions are the core functions.
+Allocate an
+.Vt SHA256_CTX ,
+initialize it with
+.Fn SHA256_Init ,
+run over the data with
+.Fn SHA256_Update ,
+and finally extract the result using
+.Fn SHA256_Final .
+.Pp
+.Fn SHA256_End
+is a wrapper for
+.Fn SHA256_Final
+which converts the return value to a 65-character
+(including the terminating '\e0')
+.Tn ASCII
+string which represents the 256 bits in hexadecimal.
+.Pp
+.Fn SHA256_File
+calculates the digest of a file, and uses
+.Fn SHA256_End
+to return the result.
+If the file cannot be opened, a null pointer is returned.
+.Fn SHA256_FileChunk
+is similar to
+.Fn SHA256_File ,
+but it only calculates the digest over a byte-range of the file specified,
+starting at
+.Fa offset
+and spanning
+.Fa length
+bytes.
+If the
+.Fa length
+parameter is specified as 0, or more than the length of the remaining part
+of the file,
+.Fn SHA256_FileChunk
+calculates the digest from
+.Fa offset
+to the end of file.
+.Fn SHA256_Data
+calculates the digest of a chunk of data in memory, and uses
+.Fn SHA256_End
+to return the result.
+.Pp
+When using
+.Fn SHA256_End ,
+.Fn SHA256_File ,
+or
+.Fn SHA256_Data ,
+the
+.Fa buf
+argument can be a null pointer, in which case the returned string
+is allocated with
+.Xr malloc 3
+and subsequently must be explicitly deallocated using
+.Xr free 3
+after use.
+If the
+.Fa buf
+argument is non-null it must point to at least 65 characters of buffer space.
+.Sh SEE ALSO
+.Xr md2 3 ,
+.Xr md4 3 ,
+.Xr md5 3 ,
+.Xr ripemd 3 ,
+.Xr sha 3
+.Sh HISTORY
+These functions appeared in
+.Fx 4.0 .
+.Sh AUTHORS
+The core hash routines were implemented by Colin Percival based on
+the published
+.Tn FIPS 180-2
+standard.
+.Sh BUGS
+No method is known to exist which finds two files having the same hash value,
+nor to find a file with a specific hash value.
+There is on the other hand no guarantee that such a method does not exist.
diff --git a/lib/libmd/sha256.h b/lib/libmd/sha256.h
new file mode 100644
index 0000000..ce51787
--- /dev/null
+++ b/lib/libmd/sha256.h
@@ -0,0 +1,50 @@
+/*-
+ * Copyright 2005 Colin Percival
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 _SHA256_H_
+#define _SHA256_H_
+
+#include <sys/types.h>
+
+typedef struct SHA256Context {
+ uint32_t state[8];
+ uint32_t count[2];
+ unsigned char buf[64];
+} SHA256_CTX;
+
+__BEGIN_DECLS
+void SHA256_Init(SHA256_CTX *);
+void SHA256_Update(SHA256_CTX *, const void *, size_t);
+void SHA256_Final(unsigned char [32], SHA256_CTX *);
+char *SHA256_End(SHA256_CTX *, char *);
+char *SHA256_File(const char *, char *);
+char *SHA256_FileChunk(const char *, char *, off_t, off_t);
+char *SHA256_Data(const void *, unsigned int, char *);
+__END_DECLS
+
+#endif /* !_SHA256_H_ */
diff --git a/lib/libmd/sha256c.c b/lib/libmd/sha256c.c
new file mode 100644
index 0000000..c95fd31
--- /dev/null
+++ b/lib/libmd/sha256c.c
@@ -0,0 +1,300 @@
+/*-
+ * Copyright 2005 Colin Percival
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 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 <sys/types.h>
+
+#include <string.h>
+
+#include "sha256.h"
+
+#if BYTE_ORDER == BIG_ENDIAN
+
+/* Copy a vector of big-endian uint32_t into a vector of bytes */
+#define be32enc_vect(dst, src, len) \
+ memcpy((void *)dst, (const void *)src, (size_t)len)
+
+/* Copy a vector of bytes into a vector of big-endian uint32_t */
+#define be32dec_vect(dst, src, len) \
+ memcpy((void *)dst, (const void *)src, (size_t)len)
+
+#else /* BYTE_ORDER != BIG_ENDIAN */
+
+/*
+ * Encode a length len/4 vector of (uint32_t) into a length len vector of
+ * (unsigned char) in big-endian form. Assumes len is a multiple of 4.
+ */
+static void
+be32enc_vect(unsigned char *dst, const uint32_t *src, size_t len)
+{
+ size_t i;
+
+ for (i = 0; i < len / 4; i++)
+ be32enc(dst + i * 4, src[i]);
+}
+
+/*
+ * Decode a big-endian length len vector of (unsigned char) into a length
+ * len/4 vector of (uint32_t). Assumes len is a multiple of 4.
+ */
+static void
+be32dec_vect(uint32_t *dst, const unsigned char *src, size_t len)
+{
+ size_t i;
+
+ for (i = 0; i < len / 4; i++)
+ dst[i] = be32dec(src + i * 4);
+}
+
+#endif /* BYTE_ORDER != BIG_ENDIAN */
+
+/* Elementary functions used by SHA256 */
+#define Ch(x, y, z) ((x & (y ^ z)) ^ z)
+#define Maj(x, y, z) ((x & (y | z)) | (y & z))
+#define SHR(x, n) (x >> n)
+#define ROTR(x, n) ((x >> n) | (x << (32 - n)))
+#define S0(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22))
+#define S1(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25))
+#define s0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3))
+#define s1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10))
+
+/* SHA256 round function */
+#define RND(a, b, c, d, e, f, g, h, k) \
+ t0 = h + S1(e) + Ch(e, f, g) + k; \
+ t1 = S0(a) + Maj(a, b, c); \
+ d += t0; \
+ h = t0 + t1;
+
+/* Adjusted round function for rotating state */
+#define RNDr(S, W, i, k) \
+ RND(S[(64 - i) % 8], S[(65 - i) % 8], \
+ S[(66 - i) % 8], S[(67 - i) % 8], \
+ S[(68 - i) % 8], S[(69 - i) % 8], \
+ S[(70 - i) % 8], S[(71 - i) % 8], \
+ W[i] + k)
+
+/*
+ * SHA256 block compression function. The 256-bit state is transformed via
+ * the 512-bit input block to produce a new state.
+ */
+static void
+SHA256_Transform(uint32_t * state, const unsigned char block[64])
+{
+ uint32_t W[64];
+ uint32_t S[8];
+ uint32_t t0, t1;
+ int i;
+
+ /* 1. Prepare message schedule W. */
+ be32dec_vect(W, block, 64);
+ for (i = 16; i < 64; i++)
+ W[i] = s1(W[i - 2]) + W[i - 7] + s0(W[i - 15]) + W[i - 16];
+
+ /* 2. Initialize working variables. */
+ memcpy(S, state, 32);
+
+ /* 3. Mix. */
+ RNDr(S, W, 0, 0x428a2f98);
+ RNDr(S, W, 1, 0x71374491);
+ RNDr(S, W, 2, 0xb5c0fbcf);
+ RNDr(S, W, 3, 0xe9b5dba5);
+ RNDr(S, W, 4, 0x3956c25b);
+ RNDr(S, W, 5, 0x59f111f1);
+ RNDr(S, W, 6, 0x923f82a4);
+ RNDr(S, W, 7, 0xab1c5ed5);
+ RNDr(S, W, 8, 0xd807aa98);
+ RNDr(S, W, 9, 0x12835b01);
+ RNDr(S, W, 10, 0x243185be);
+ RNDr(S, W, 11, 0x550c7dc3);
+ RNDr(S, W, 12, 0x72be5d74);
+ RNDr(S, W, 13, 0x80deb1fe);
+ RNDr(S, W, 14, 0x9bdc06a7);
+ RNDr(S, W, 15, 0xc19bf174);
+ RNDr(S, W, 16, 0xe49b69c1);
+ RNDr(S, W, 17, 0xefbe4786);
+ RNDr(S, W, 18, 0x0fc19dc6);
+ RNDr(S, W, 19, 0x240ca1cc);
+ RNDr(S, W, 20, 0x2de92c6f);
+ RNDr(S, W, 21, 0x4a7484aa);
+ RNDr(S, W, 22, 0x5cb0a9dc);
+ RNDr(S, W, 23, 0x76f988da);
+ RNDr(S, W, 24, 0x983e5152);
+ RNDr(S, W, 25, 0xa831c66d);
+ RNDr(S, W, 26, 0xb00327c8);
+ RNDr(S, W, 27, 0xbf597fc7);
+ RNDr(S, W, 28, 0xc6e00bf3);
+ RNDr(S, W, 29, 0xd5a79147);
+ RNDr(S, W, 30, 0x06ca6351);
+ RNDr(S, W, 31, 0x14292967);
+ RNDr(S, W, 32, 0x27b70a85);
+ RNDr(S, W, 33, 0x2e1b2138);
+ RNDr(S, W, 34, 0x4d2c6dfc);
+ RNDr(S, W, 35, 0x53380d13);
+ RNDr(S, W, 36, 0x650a7354);
+ RNDr(S, W, 37, 0x766a0abb);
+ RNDr(S, W, 38, 0x81c2c92e);
+ RNDr(S, W, 39, 0x92722c85);
+ RNDr(S, W, 40, 0xa2bfe8a1);
+ RNDr(S, W, 41, 0xa81a664b);
+ RNDr(S, W, 42, 0xc24b8b70);
+ RNDr(S, W, 43, 0xc76c51a3);
+ RNDr(S, W, 44, 0xd192e819);
+ RNDr(S, W, 45, 0xd6990624);
+ RNDr(S, W, 46, 0xf40e3585);
+ RNDr(S, W, 47, 0x106aa070);
+ RNDr(S, W, 48, 0x19a4c116);
+ RNDr(S, W, 49, 0x1e376c08);
+ RNDr(S, W, 50, 0x2748774c);
+ RNDr(S, W, 51, 0x34b0bcb5);
+ RNDr(S, W, 52, 0x391c0cb3);
+ RNDr(S, W, 53, 0x4ed8aa4a);
+ RNDr(S, W, 54, 0x5b9cca4f);
+ RNDr(S, W, 55, 0x682e6ff3);
+ RNDr(S, W, 56, 0x748f82ee);
+ RNDr(S, W, 57, 0x78a5636f);
+ RNDr(S, W, 58, 0x84c87814);
+ RNDr(S, W, 59, 0x8cc70208);
+ RNDr(S, W, 60, 0x90befffa);
+ RNDr(S, W, 61, 0xa4506ceb);
+ RNDr(S, W, 62, 0xbef9a3f7);
+ RNDr(S, W, 63, 0xc67178f2);
+
+ /* 4. Mix local working variables into global state */
+ for (i = 0; i < 8; i++)
+ state[i] += S[i];
+}
+
+static unsigned char PAD[64] = {
+ 0x80, 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
+};
+
+/* Add padding and terminating bit-count. */
+static void
+SHA256_Pad(SHA256_CTX * ctx)
+{
+ unsigned char len[8];
+ uint32_t r, plen;
+
+ /*
+ * Convert length to a vector of bytes -- we do this now rather
+ * than later because the length will change after we pad.
+ */
+ be32enc_vect(len, ctx->count, 8);
+
+ /* Add 1--64 bytes so that the resulting length is 56 mod 64 */
+ r = (ctx->count[1] >> 3) & 0x3f;
+ plen = (r < 56) ? (56 - r) : (120 - r);
+ SHA256_Update(ctx, PAD, (size_t)plen);
+
+ /* Add the terminating bit-count */
+ SHA256_Update(ctx, len, 8);
+}
+
+/* SHA-256 initialization. Begins a SHA-256 operation. */
+void
+SHA256_Init(SHA256_CTX * ctx)
+{
+
+ /* Zero bits processed so far */
+ ctx->count[0] = ctx->count[1] = 0;
+
+ /* Magic initialization constants */
+ ctx->state[0] = 0x6A09E667;
+ ctx->state[1] = 0xBB67AE85;
+ ctx->state[2] = 0x3C6EF372;
+ ctx->state[3] = 0xA54FF53A;
+ ctx->state[4] = 0x510E527F;
+ ctx->state[5] = 0x9B05688C;
+ ctx->state[6] = 0x1F83D9AB;
+ ctx->state[7] = 0x5BE0CD19;
+}
+
+/* Add bytes into the hash */
+void
+SHA256_Update(SHA256_CTX * ctx, const void *in, size_t len)
+{
+ uint32_t bitlen[2];
+ uint32_t r;
+ const unsigned char *src = in;
+
+ /* Number of bytes left in the buffer from previous updates */
+ r = (ctx->count[1] >> 3) & 0x3f;
+
+ /* Convert the length into a number of bits */
+ bitlen[1] = ((uint32_t)len) << 3;
+ bitlen[0] = (uint32_t)(len >> 29);
+
+ /* Update number of bits */
+ if ((ctx->count[1] += bitlen[1]) < bitlen[1])
+ ctx->count[0]++;
+ ctx->count[0] += bitlen[0];
+
+ /* Handle the case where we don't need to perform any transforms */
+ if (len < 64 - r) {
+ memcpy(&ctx->buf[r], src, len);
+ return;
+ }
+
+ /* Finish the current block */
+ memcpy(&ctx->buf[r], src, 64 - r);
+ SHA256_Transform(ctx->state, ctx->buf);
+ src += 64 - r;
+ len -= 64 - r;
+
+ /* Perform complete blocks */
+ while (len >= 64) {
+ SHA256_Transform(ctx->state, src);
+ src += 64;
+ len -= 64;
+ }
+
+ /* Copy left over data into buffer */
+ memcpy(ctx->buf, src, len);
+}
+
+/*
+ * SHA-256 finalization. Pads the input data, exports the hash value,
+ * and clears the context state.
+ */
+void
+SHA256_Final(unsigned char digest[32], SHA256_CTX * ctx)
+{
+
+ /* Add padding */
+ SHA256_Pad(ctx);
+
+ /* Write the hash */
+ be32enc_vect(digest, ctx->state, 32);
+
+ /* Clear the context state */
+ memset((void *)ctx, 0, sizeof(*ctx));
+}
diff --git a/lib/libmd/sha_locl.h b/lib/libmd/sha_locl.h
new file mode 100644
index 0000000..461c9ea
--- /dev/null
+++ b/lib/libmd/sha_locl.h
@@ -0,0 +1,243 @@
+/* crypto/sha/sha_locl.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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 cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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 licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifdef undef
+/* one or the other needs to be defined */
+#ifndef SHA_1 /* FIPE 180-1 */
+#define SHA_0 /* FIPS 180 */
+#endif
+#endif
+
+#define ULONG unsigned long
+#define UCHAR unsigned char
+#define UINT unsigned int
+
+#ifdef NOCONST
+#define const
+#endif
+
+#undef c2nl
+#define c2nl(c,l) (l =(((unsigned long)(*((c)++)))<<24), \
+ l|=(((unsigned long)(*((c)++)))<<16), \
+ l|=(((unsigned long)(*((c)++)))<< 8), \
+ l|=(((unsigned long)(*((c)++))) ))
+
+#undef p_c2nl
+#define p_c2nl(c,l,n) { \
+ switch (n) { \
+ case 0: l =((unsigned long)(*((c)++)))<<24; \
+ case 1: l|=((unsigned long)(*((c)++)))<<16; \
+ case 2: l|=((unsigned long)(*((c)++)))<< 8; \
+ case 3: l|=((unsigned long)(*((c)++))); \
+ } \
+ }
+
+#undef c2nl_p
+/* NOTE the pointer is not incremented at the end of this */
+#define c2nl_p(c,l,n) { \
+ l=0; \
+ (c)+=n; \
+ switch (n) { \
+ case 3: l =((unsigned long)(*(--(c))))<< 8; \
+ case 2: l|=((unsigned long)(*(--(c))))<<16; \
+ case 1: l|=((unsigned long)(*(--(c))))<<24; \
+ } \
+ }
+
+#undef p_c2nl_p
+#define p_c2nl_p(c,l,sc,len) { \
+ switch (sc) \
+ { \
+ case 0: l =((unsigned long)(*((c)++)))<<24; \
+ if (--len == 0) break; \
+ case 1: l|=((unsigned long)(*((c)++)))<<16; \
+ if (--len == 0) break; \
+ case 2: l|=((unsigned long)(*((c)++)))<< 8; \
+ } \
+ }
+
+#undef nl2c
+#define nl2c(l,c) (*((c)++)=(unsigned char)(((l)>>24)&0xff), \
+ *((c)++)=(unsigned char)(((l)>>16)&0xff), \
+ *((c)++)=(unsigned char)(((l)>> 8)&0xff), \
+ *((c)++)=(unsigned char)(((l) )&0xff))
+
+#undef c2l
+#define c2l(c,l) (l =(((unsigned long)(*((c)++))) ), \
+ l|=(((unsigned long)(*((c)++)))<< 8), \
+ l|=(((unsigned long)(*((c)++)))<<16), \
+ l|=(((unsigned long)(*((c)++)))<<24))
+
+#undef p_c2l
+#define p_c2l(c,l,n) { \
+ switch (n) { \
+ case 0: l =((unsigned long)(*((c)++))); \
+ case 1: l|=((unsigned long)(*((c)++)))<< 8; \
+ case 2: l|=((unsigned long)(*((c)++)))<<16; \
+ case 3: l|=((unsigned long)(*((c)++)))<<24; \
+ } \
+ }
+
+#undef c2l_p
+/* NOTE the pointer is not incremented at the end of this */
+#define c2l_p(c,l,n) { \
+ l=0; \
+ (c)+=n; \
+ switch (n) { \
+ case 3: l =((unsigned long)(*(--(c))))<<16; \
+ case 2: l|=((unsigned long)(*(--(c))))<< 8; \
+ case 1: l|=((unsigned long)(*(--(c)))); \
+ } \
+ }
+
+#undef p_c2l_p
+#define p_c2l_p(c,l,sc,len) { \
+ switch (sc) \
+ { \
+ case 0: l =((unsigned long)(*((c)++))); \
+ if (--len == 0) break; \
+ case 1: l|=((unsigned long)(*((c)++)))<< 8; \
+ if (--len == 0) break; \
+ case 2: l|=((unsigned long)(*((c)++)))<<16; \
+ } \
+ }
+
+#undef l2c
+#define l2c(l,c) (*((c)++)=(unsigned char)(((l) )&0xff), \
+ *((c)++)=(unsigned char)(((l)>> 8)&0xff), \
+ *((c)++)=(unsigned char)(((l)>>16)&0xff), \
+ *((c)++)=(unsigned char)(((l)>>24)&0xff))
+
+#undef ROTATE
+#if defined(WIN32)
+#define ROTATE(a,n) _lrotl(a,n)
+#else
+#define ROTATE(a,n) (((a)<<(n))|(((a)&0xffffffff)>>(32-(n))))
+#endif
+
+/* A nice byte order reversal from Wei Dai <weidai@eskimo.com> */
+#if defined(WIN32)
+/* 5 instructions with rotate instruction, else 9 */
+#define Endian_Reverse32(a) \
+ { \
+ unsigned long l=(a); \
+ (a)=((ROTATE(l,8)&0x00FF00FF)|(ROTATE(l,24)&0xFF00FF00)); \
+ }
+#else
+/* 6 instructions with rotate instruction, else 8 */
+#define Endian_Reverse32(a) \
+ { \
+ unsigned long l=(a); \
+ l=(((l&0xFF00FF00)>>8L)|((l&0x00FF00FF)<<8L)); \
+ (a)=ROTATE(l,16L); \
+ }
+#endif
+
+/* As pointed out by Wei Dai <weidai@eskimo.com>, F() below can be
+ * simplified to the code in F_00_19. Wei attributes these optimisations
+ * to Peter Gutmann's SHS code, and he attributes it to Rich Schroeppel.
+ * #define F(x,y,z) (((x) & (y)) | ((~(x)) & (z)))
+ * I've just become aware of another tweak to be made, again from Wei Dai,
+ * in F_40_59, (x&a)|(y&a) -> (x|y)&a
+ */
+#define F_00_19(b,c,d) ((((c) ^ (d)) & (b)) ^ (d))
+#define F_20_39(b,c,d) ((b) ^ (c) ^ (d))
+#define F_40_59(b,c,d) (((b) & (c)) | (((b)|(c)) & (d)))
+#define F_60_79(b,c,d) F_20_39(b,c,d)
+
+#ifdef SHA_0
+#undef Xupdate
+#define Xupdate(a,i,ia,ib,ic,id) X[(i)&0x0f]=(a)=\
+ (ia[(i)&0x0f]^ib[((i)+2)&0x0f]^ic[((i)+8)&0x0f]^id[((i)+13)&0x0f]);
+#endif
+#ifdef SHA_1
+#undef Xupdate
+#define Xupdate(a,i,ia,ib,ic,id) (a)=\
+ (ia[(i)&0x0f]^ib[((i)+2)&0x0f]^ic[((i)+8)&0x0f]^id[((i)+13)&0x0f]);\
+ X[(i)&0x0f]=(a)=ROTATE((a),1);
+#endif
+
+#define BODY_00_15(i,a,b,c,d,e,f,xa) \
+ (f)=xa[i]+(e)+K_00_19+ROTATE((a),5)+F_00_19((b),(c),(d)); \
+ (b)=ROTATE((b),30);
+
+#define BODY_16_19(i,a,b,c,d,e,f,xa,xb,xc,xd) \
+ Xupdate(f,i,xa,xb,xc,xd); \
+ (f)+=(e)+K_00_19+ROTATE((a),5)+F_00_19((b),(c),(d)); \
+ (b)=ROTATE((b),30);
+
+#define BODY_20_31(i,a,b,c,d,e,f,xa,xb,xc,xd) \
+ Xupdate(f,i,xa,xb,xc,xd); \
+ (f)+=(e)+K_20_39+ROTATE((a),5)+F_20_39((b),(c),(d)); \
+ (b)=ROTATE((b),30);
+
+#define BODY_32_39(i,a,b,c,d,e,f,xa) \
+ Xupdate(f,i,xa,xa,xa,xa); \
+ (f)+=(e)+K_20_39+ROTATE((a),5)+F_20_39((b),(c),(d)); \
+ (b)=ROTATE((b),30);
+
+#define BODY_40_59(i,a,b,c,d,e,f,xa) \
+ Xupdate(f,i,xa,xa,xa,xa); \
+ (f)+=(e)+K_40_59+ROTATE((a),5)+F_40_59((b),(c),(d)); \
+ (b)=ROTATE((b),30);
+
+#define BODY_60_79(i,a,b,c,d,e,f,xa) \
+ Xupdate(f,i,xa,xa,xa,xa); \
+ (f)=X[(i)&0x0f]+(e)+K_60_79+ROTATE((a),5)+F_60_79((b),(c),(d)); \
+ (b)=ROTATE((b),30);
+
diff --git a/lib/libmd/shadriver.c b/lib/libmd/shadriver.c
new file mode 100644
index 0000000..7f799fb
--- /dev/null
+++ b/lib/libmd/shadriver.c
@@ -0,0 +1,66 @@
+/* SHADRIVER.C - test driver for SHA-1 (and SHA-0)
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/* Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All
+ rights reserved.
+
+ RSA Data Security, Inc. makes no representations concerning either
+ the merchantability of this software or the suitability of this
+ software for any particular purpose. It is provided "as is"
+ without express or implied warranty of any kind.
+
+ These notices must be retained in any copies of any part of this
+ documentation and/or software.
+ */
+
+/* The following makes SHA default to SHA-1 if it has not already been
+ defined with C compiler flags.
+ */
+#ifndef SHA
+#define SHA 1
+#endif
+
+#include <sys/types.h>
+
+#include <stdio.h>
+#include <time.h>
+#include <string.h>
+#include "sha.h"
+#include "sha256.h"
+#if SHA == 1
+#define SHA_Data SHA1_Data
+#elif SHA == 256
+#define SHA_Data SHA256_Data
+#endif
+
+/* Digests a string and prints the result.
+ */
+static void SHAString (string)
+char *string;
+{
+ char buf[2*32+1];
+
+ printf ("SHA-%d (\"%s\") = %s\n",
+ SHA, string, SHA_Data(string,strlen(string),buf));
+}
+
+/* Digests a reference suite of strings and prints the results.
+ */
+main()
+{
+ printf ("SHA-%d test suite:\n", SHA);
+
+ SHAString ("");
+ SHAString ("abc");
+ SHAString ("message digest");
+ SHAString ("abcdefghijklmnopqrstuvwxyz");
+ SHAString
+ ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
+ SHAString
+ ("1234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890");
+ return 0;
+}
diff --git a/lib/libmemstat/Makefile b/lib/libmemstat/Makefile
new file mode 100644
index 0000000..dd63b88
--- /dev/null
+++ b/lib/libmemstat/Makefile
@@ -0,0 +1,30 @@
+# $FreeBSD$
+
+WARNS?= 3
+LIB= memstat
+SHLIB_MAJOR= 1
+DPADD= ${LIBKVM}
+LDADD= -lkvm
+SRCS+= memstat.c
+SRCS+= memstat_all.c
+SRCS+= memstat_malloc.c
+SRCS+= memstat_uma.c
+INCS= memstat.h
+
+MAN= libmemstat.3
+
+MLINKS+= libmemstat.3 memstat_mtl_alloc.3
+MLINKS+= libmemstat.3 memstat_mtl_first.3
+MLINKS+= libmemstat.3 memstat_mtl_next.3
+MLINKS+= libmemstat.3 memstat_mtl_find.3
+MLINKS+= libmemstat.3 memstat_mtl_free.3
+MLINKS+= libmemstat.3 memstat_mtl_geterror.3
+MLINKS+= libmemstat.3 memstat_strerror.3
+MLINKS+= libmemstat.3 memstat_sysctl_all.3
+MLINKS+= libmemstat.3 memstat_sysctl_malloc.3
+MLINKS+= libmemstat.3 memstat_sysctl_uma.3
+MLINKS+= libmemstat.3 memstat_kvm_all.3
+MLINKS+= libmemstat.3 memstat_kvm_malloc.3
+MLINKS+= libmemstat.3 memstat_kvm_uma.3
+
+.include <bsd.lib.mk>
diff --git a/lib/libmemstat/libmemstat.3 b/lib/libmemstat/libmemstat.3
new file mode 100644
index 0000000..82ec53a
--- /dev/null
+++ b/lib/libmemstat/libmemstat.3
@@ -0,0 +1,496 @@
+.\" Copyright (c) 2005 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 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 27, 2005
+.Os
+.Dt LIBMEMSTAT 3
+.Sh NAME
+.Nm libmemstat
+.Nd "library interface to retrieve kernel memory allocator statistics"
+.Sh LIBRARY
+.Lb libmemstat
+.Sh SYNOPSIS
+.In sys/types.h
+.In memstat.h
+.Ss General Functions
+.Ft "const char *"
+.Fn memstat_strerror "int error"
+.Ss Memory Type List Management Functions
+.Ft "struct memory_type_list *"
+.Fn memstat_mtl_alloc "void"
+.Ft "struct memory_type *"
+.Fn memstat_mtl_first "struct memory_type_list *list"
+.Ft "struct memory_type *"
+.Fn memstat_mtl_next "struct memory_type *mtp"
+.Ft "struct memory_type *"
+.Fo memstat_mtl_find
+.Fa "struct memory_type_list *list" "int allocator" "const char *name"
+.Fc
+.Ft void
+.Fn memstat_mtl_free "struct memory_type_list *list"
+.Ft int
+.Fn memstat_mtl_geterror "struct memory_type_list *list"
+.Ss Allocator Query Functions
+.Ft int
+.Fn memstat_kvm_all "struct memory_type_list *list" "void *kvm_handle"
+.Ft int
+.Fn memstat_kvm_malloc "struct memory_type_list *list" "void *kvm_handle"
+.Ft int
+.Fn memstat_kvm_uma "struct memory_type_list *list" "void *kvm_handle"
+.Ft int
+.Fn memstat_sysctl_all "struct memory_type_list *list" "int flags"
+.Ft int
+.Fn memstat_sysctl_malloc "struct memory_type_list *list" "int flags"
+.Ft int
+.Fn memstat_sysctl_uma "struct memory_type_list *list" "int flags"
+.Ss Memory Type Accessor Methods
+.Ft "const char *"
+.Fn memstat_get_name "const struct memory_type *mtp"
+.Ft int
+.Fn memstat_get_allocator "const struct memory_type *mtp"
+.Ft uint64_t
+.Fn memstat_get_countlimit "const struct memory_type *mtp"
+.Ft uint64_t
+.Fn memstat_get_byteslimit "const struct memory_type *mtp"
+.Ft uint64_t
+.Fn memstat_get_sizemask "const struct memory_type *mtp"
+.Ft uint64_t
+.Fn memstat_get_size "const struct memory_type *mtp"
+.Ft uint64_t
+.Fn memstat_get_memalloced "const struct memory_type *mtp"
+.Ft uint64_t
+.Fn memstat_get_memfreed "const struct memory_type *mtp"
+.Ft uint64_t
+.Fn memstat_get_numallocs "const struct memory_type *mtp"
+.Ft uint64_t
+.Fn memstat_get_numfrees "const struct memory_type *mtp"
+.Ft uint64_t
+.Fn memstat_get_bytes "const struct memory_type *mtp"
+.Ft uint64_t
+.Fn memstat_get_count "const struct memory_type *mtp"
+.Ft uint64_t
+.Fn memstat_get_free "const struct memory_type *mtp"
+.Ft uint64_t
+.Fn memstat_get_failures "const struct memory_type *mtp"
+.Ft "void *"
+.Fn memstat_get_caller_pointer "const struct memory_type *mtp" "int index"
+.Ft void
+.Fo memstat_set_caller_pointer
+.Fa "struct memory_type *mtp" "int index" "void *value"
+.Fc
+.Ft uint64_t
+.Fn memstat_get_caller_uint64 "const struct memory_type *mtp" "int index"
+.Ft void
+.Fo memstat_set_caller_uint64
+.Fa "struct memory_type *mtp" "int index" "uint64_t value"
+.Fc
+.Ft uint64_t
+.Fn memstat_get_zonefree "const struct memory_type *mtp"
+.Ft uint64_t
+.Fn memstat_get_kegfree "const struct memory_type *mtp"
+.Ft uint64_t
+.Fn memstat_get_percpu_memalloced "const struct memory_type *mtp" "int cpu"
+.Ft uint64_t
+.Fn memstat_get_percpu_memfreed "const struct memory_type *mtp" "int cpu"
+.Ft uint64_t
+.Fn memstat_get_percpu_numallocs "const struct memory_type *mtp" "int cpu"
+.Ft uint64_t
+.Fn memstat_get_percpu_numfrees "const struct memory_type *mtp" "int cpu"
+.Ft uint64_t
+.Fn memstat_get_percpu_sizemask "const struct memory_type *mtp" "int cpu"
+.Ft "void *"
+.Fo memstat_get_percpu_caller_pointer
+.Fa "const struct memory_type *mtp" "int cpu" "int index"
+.Fc
+.Ft void
+.Fo memstat_set_percpu_caller_pointer
+.Fa "struct memory_type *mtp" "int cpu" "int index" "void *value"
+.Fc
+.Ft uint64_t
+.Fo memstat_get_percpu_caller_uint64
+.Fa "const struct memory_type *mtp" "int cpu" "int index"
+.Fc
+.Ft void
+.Fo memstat_set_percpu_caller_uint64
+.Fa "struct memory_type *mtp" "int cpu" "int index" "uint64_t value"
+.Fc
+.Ft uint64_t
+.Fn memstat_get_percpu_free "const struct memory_type *mtp" "int cpu"
+.Sh DESCRIPTION
+.Nm
+provides an interface to retrieve kernel memory allocator statistics, for
+the purposes of debugging and system monitoring, insulating applications
+from implementation details of the allocators, and allowing a tool to
+transparently support multiple allocators.
+.Nm
+supports both retrieving a single statistics snapshot, as well as
+incrementally updating statistics for long-term monitoring.
+.Pp
+.Nm
+describes each memory type using a
+.Vt "struct memory_type" ,
+an opaque memory type accessed by the application using accessor functions
+in the library.
+.Nm
+returns and updates chains of
+.Vt "struct memory_type"
+via a
+.Vt "struct memory_type_list" ,
+which will be allocated by calling
+.Fn memstat_mtl_alloc ,
+and freed on completion using
+.Fn memstat_mtl_free .
+Lists of memory types are populated via calls that query the kernel for
+statistics information; currently:
+.Fn memstat_kvm_all ,
+.Fn memstat_kvm_malloc ,
+.Fn memstat_kvm_uma ,
+.Fn memstat_sysctl_all ,
+.Fn memstat_sysctl_uma ,
+and
+.Fn memstat_sysctl_malloc .
+Repeated calls will incrementally update the list of memory types, permitting
+tracking over time without recreating all list state.
+If an error is detected during a query call, error condition information may
+be retrieved using
+.Fn memstat_mtl_geterror ,
+and converted to a user-readable string using
+.Fn memstat_strerror .
+.Pp
+Freeing the list will free all memory type data in the list, and so
+invalidates any outstanding pointers to entries in the list.
+.Vt "struct memory_type"
+entries in the list may be iterated over using
+.Fn memstat_mtl_first
+and
+.Fn memstat_mtl_next ,
+which respectively return the first entry in a list, and the next entry in a
+list.
+.Fn memstat_mtl_find ,
+which will return a pointer to the first entry matching the passed
+parameters.
+.Pp
+A series of accessor methods is provided to access fields of the structure,
+including retrieving statistics and properties, as well as setting of caller
+owned fields.
+Direct application access to the data structure fields is not supported.
+.Ss Library Vt memory_type Ss Fields
+Each
+.Vt "struct memory_type"
+holds a description of the memory type, including its name and the allocator
+it is managed by, as well as current statistics on use.
+Some statistics are directly measured, others are derived from directly
+measured statistics.
+Certain high level statistics are present across all available allocators,
+such as the number of allocation and free operations; other measurements,
+such as the quantity of free items in per-CPU caches, or administrative
+limit on the number of allocations, is available only for specific
+allocators.
+.Ss Caller Vt memory_type Ss Fields
+.Vt "struct memory_type"
+includes fields to allow the application to store data, in the form of
+pointers and 64-bit integers, with memory types.
+For example, the application author might make use of one of the caller
+pointers to reference a more complex data structure tracking long-term
+behavior of the memory type, or a window system object that is used to
+render the state of the memory type.
+General and per-CPU storage is provided with each
+.Vt "struct memory_type"
+in the form of an array of pointers and integers.
+The array entries are accessed via the
+.Fa index
+argument to the get and set accessor methods.
+Possible values of
+.Fa index
+range between
+0
+and
+.Dv MEMSTAT_MAXCALLER .
+.Pp
+Caller-owned fields are initialized to
+0
+or
+.Dv NULL
+when a new
+.Vt "struct memory_type"
+is allocated and attached to a memory type list; these fields retain their
+values across queries that update library-owned fields.
+.Ss Allocator Types
+Currently,
+.Nm
+supports two kernel allocators:
+.Dv ALLOCATOR_UMA
+for
+.Xr uma 9 ,
+and
+.Dv ALLOCATOR_MALLOC
+for
+.Xr malloc 9 .
+These values may be passed to
+.Fn memstat_mtl_find ,
+and will be returned by
+.Fn memstat_get_allocator .
+Two additional constants in the allocator name space are defined:
+.Dv ALLOCATOR_UNKNOWN ,
+which will only be returned as a result of a library error, and
+.Dv ALLOCATOR_ANY ,
+which can be used to specify that returning types matching any allocator is
+permittible from
+.Fn memstat_mtl_find .
+.Ss Access Method List
+The following accessor methods are defined, of which some will be valid for
+a given memory type:
+.Bl -tag -width indent
+.It Fn memstat_get_name
+Return a pointer to the name of the memory type.
+Memory for the name is owned by
+.Nm
+and will be valid through a call to
+.Fn memstat_mtl_free .
+Note that names will be unique with respect to a single allocator, but that
+the same name might be used by different memory types owned by different
+memory allocators.
+.It Fn memstat_get_allocator
+Return an integer identifier for the memory allocator that owns the memory
+type.
+.It Fn memstat_get_countlimit
+If the memory type has an administrative limit on the number of simultaneous
+allocations, return it.
+.It Fn memstat_get_byteslimit
+If the memory type has an administrative limit on the number of bytes of
+memory that may be simultaenously allocated for the memory type, return it.
+.It Fn memstat_get_sizemask
+If the memory type supports variable allocation sizes, return a bitmask of
+sizes allocated for the memory type.
+.It Fn memstat_get_size
+If the memory type supports a fixed allocation size, return that size.
+.It Fn memstat_get_memalloced
+Return the total number of bytes allocated for the memory type over its
+lifetime.
+.It Fn memstat_get_memfreed
+Return the total number of bytes freed for the memory type over its lifetime.
+.It Fn memstat_get_numallocs
+Return the total number of allocations for the memory type over its lifetime.
+.It Fn memstat_get_numfrees
+Return the total number of frees for the memory type over its lifetime.
+.It Fn memstat_get_bytes
+Return the current number of bytes allocated to the memory type.
+.It Fn memstat_get_count
+Return the current number of allocations for the memory type.
+.It Fn memstat_get_free
+If the memory allocator supports a cache, return the number of items in the
+cache.
+.It Fn memstat_get_failures
+If the memory allocator and type permit allocation failures, return the
+number of allocation failures measured.
+.It Fn memstat_get_caller_pointer
+Return a caller-owned pointer for the memory type.
+.It Fn memstat_set_caller_pointer
+Set a caller-owned pointer for the memory type.
+.It Fn memstat_get_caller_uint64
+Return a caller-owned integer for the memory type.
+.It Fn memstat_set_caller_uint64
+Set a caller-owned integer for the memory type.
+.It Fn memstat_get_zonefree
+If the memory allocator supports a multi-level allocation structure, return
+the number of cached items in the zone.
+These items will be in a fully constructed state available for immediate
+use.
+.It Fn memstat_get_kegfree
+If the memory allocator supports a multi-level allocation structure, return
+the number of cached items in the keg.
+These items may be in a partially constructed state, and may require further
+processing before they can be made available for use.
+.It Fn memstat_get_percpu_memalloced
+If the memory allocator supports per-CPU statistics, return the number of
+bytes of memory allocated for the memory type on the CPU over its lifetime.
+.It Fn memstat_get_percpu_memfreed
+If the memory allocator supports per-CPU statistics, return the number of
+bytes of memory freed from the memory type on the CPU over its lifetime.
+.It Fn memstat_get_percpu_numallocs
+If the memory allocator supports per-CPU statistics, return the number of
+allocations for the memory type on the CPU over its lifetime.
+.It Fn memstat_get_percpu_numfrees
+If the memory allocator supports per-CPU statistics, return the number of
+frees for the memory type on the CPU over its lifetime.
+.It Fn memstat_get_percpu_sizemask
+If the memory allocator supports variable size memory allocation and per-CPU
+statistics, return the size bitmask for the memory type on the CPU.
+.It Fn memstat_get_percpu_caller_pointer
+Return a caller-owned per-CPU pointer for the memory type.
+.It Fn memstat_set_percpu_caller_pointer
+Set a caller-owned per-CPU pointer for the memory type.
+.It Fn memstat_get_percpu_caller_uint64
+Return a caller-owned per-CPU integer for the memory type.
+.It Fn memsttat_set_percpu_caller_uint64
+Set a caller-owned per-CPU integer for the memory type.
+.It Fn memstat_get_percpu_free
+If the memory allocator supports a per-CPU cache, return the number of free
+items in the per-CPU cache of the designated CPU.
+.El
+.Sh RETURN VALUES
+.Nm
+functions fall into three categories: functions returning a pointer to an
+object, functions returning an integer return value, and functions
+implementing accessor methods returning data from a
+.Vt "struct memory_type" .
+.Pp
+Functions returning a pointer to an object will generally return
+.Dv NULL
+on failure.
+.Fn memstat_mtl_alloc
+will return an error value via
+.Va errno ,
+which will consist of the value
+.Er ENOMEM .
+Functions
+.Fn memstat_mtl_first ,
+.Fn memstat_mtl_next ,
+and
+.Fn memstat_mtl_find
+will return
+.Dv NULL
+when there is no entry or match in the list; however, this is not considered
+a failure mode and no error value is available.
+.Pp
+Functions returning an integer success value will return
+0
+on success, or
+\-1
+on failure.
+If a failure is returned, the list error access method,
+.Fn memstat_mtl_geterror ,
+may be used to retrieve the error state.
+The string representation of the error may be retrieved using
+.Fn memstat_strerror .
+Possible error values are:
+.Bl -tag -width ".Dv MEMSTAT_ERROR_KVM_SHORTREAD"
+.It Dv MEMSTAT_ERROR_UNDEFINED
+Undefined error.
+Occurs if
+.Fn memstat_mtl_geterror
+is called on a list before an error associated with the list has occurred.
+.It Dv MEMSTAT_ERROR_NOMEMORY
+Insufficient memory.
+Occurs if library calls to
+.Xr malloc 3
+fail, or if a system call to retrieve kernel statistics fails with
+.Er ENOMEM .
+.It Dv MEMSTAT_ERROR_VERSION
+Returned if the current version of
+.Nm
+is unable to interpret the statistics data returned by the kernel due to an
+explicit version mismatch, or to differences in data structures that cannot
+be reconciled.
+.It Dv MEMSTAT_ERROR_PERMISSION
+Returned if a statistics source returns
+.Va errno
+values of
+.Er EACCES
+or
+.Er EPERM .
+.It Dv MEMSTAT_ERROR_TOOMANYCPUS
+Returned if the compile-time limit on the number of CPUs in
+.Nm
+is lower than the number of CPUs returned by a statistics data source.
+.It Dv MEMSTAT_ERROR_DATAERROR
+Returned if
+.Nm
+is unable to interpret statistics data returned by the data source, even
+though there does not appear to be a version problem.
+.It Dv MEMSTAT_ERROR_KVM
+Returned if
+.Nm
+experiences an error while using
+.Xr kvm 3
+interfaces to query statistics data.
+Use
+.Xr kvm_geterr 3
+to retrieve the error.
+.It Dv MEMSTAT_ERROR_KVM_NOSYMBOL
+Returned if
+.Nm
+is unable to read a required symbol from the kernel being operated on.
+.It Dv MEMSTAT_ERROR_KVM_SHORTREAD
+Returned if
+.Nm
+attempts to read data from a live memory image or kernel core dump and
+insufficient data is returned.
+.El
+.Pp
+Finally, functions returning data from a
+.Vt "struct memory_type"
+pointer are not permitted to fail, and directly return either a statistic
+or pointer to a string.
+.Sh EXAMPLES
+Create a memory type list, query the
+.Xr uma 9
+memory allocator for available statistics, and print out the number of
+allocations performed by the
+.Dv mbuf
+zone.
+.Bd -literal -offset indent
+struct memory_type_list *mtlp;
+struct memory_type *mtp;
+uint64_t mbuf_count;
+
+mtlp = memstat_mtl_alloc();
+if (mtlp == NULL)
+ err(-1, "memstat_mtl_alloc");
+if (memstat_sysctl_uma(mtlp, 0) < 0)
+ err(-1, "memstat_sysctl_uma");
+mtp = memstat_mtl_find(mtlp, ALLOCATOR_UMA, "mbuf");
+if (mtp == NULL)
+ errx(-1, "memstat_mtl_find: mbuf not found");
+mbuf_count = memstat_get_count(mtp);
+memstat_mtl_free(mtlp);
+
+printf("mbufs: %llu\en", (unsigned long long)mbuf_count);
+.Ed
+.Sh SEE ALSO
+.Xr malloc 9 ,
+.Xr uma 9
+.Sh HISTORY
+The
+.Nm
+library appeared in
+.Fx 6.0 .
+.Sh AUTHORS
+The kernel memory allocator changes necessary to support a general purpose
+monitoring library, along with the library, were written by
+.An Robert Watson Aq rwatson@FreeBSD.org .
+.Sh BUGS
+There are memory allocators in the kernel, such as the VM page allocator
+and
+.Nm sf_buf
+allocator, which are not currently supported by
+.Nm .
+.Pp
+Once a memory type is present on a memory type list, it will not be removed
+even if the kernel no longer presents information on the type via its
+monitoring interfaces.
+In order to flush removed memory types, it is necessary to free the entire
+list and allocate a new one.
diff --git a/lib/libmemstat/memstat.c b/lib/libmemstat/memstat.c
new file mode 100644
index 0000000..28e4813
--- /dev/null
+++ b/lib/libmemstat/memstat.c
@@ -0,0 +1,421 @@
+/*-
+ * Copyright (c) 2005 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/param.h>
+#include <sys/sysctl.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "memstat.h"
+#include "memstat_internal.h"
+
+const char *
+memstat_strerror(int error)
+{
+
+ switch (error) {
+ case MEMSTAT_ERROR_NOMEMORY:
+ return ("Cannot allocate memory");
+ case MEMSTAT_ERROR_VERSION:
+ return ("Version mismatch");
+ case MEMSTAT_ERROR_PERMISSION:
+ return ("Permission denied");
+ case MEMSTAT_ERROR_TOOMANYCPUS:
+ return ("Too many CPUs");
+ case MEMSTAT_ERROR_DATAERROR:
+ return ("Data format error");
+ case MEMSTAT_ERROR_KVM:
+ return ("KVM error");
+ case MEMSTAT_ERROR_KVM_NOSYMBOL:
+ return ("KVM unable to find symbol");
+ case MEMSTAT_ERROR_KVM_SHORTREAD:
+ return ("KVM short read");
+ case MEMSTAT_ERROR_UNDEFINED:
+ default:
+ return ("Unknown error");
+ }
+}
+
+struct memory_type_list *
+memstat_mtl_alloc(void)
+{
+ struct memory_type_list *mtlp;
+
+ mtlp = malloc(sizeof(*mtlp));
+ if (mtlp == NULL)
+ return (NULL);
+
+ LIST_INIT(&mtlp->mtl_list);
+ mtlp->mtl_error = MEMSTAT_ERROR_UNDEFINED;
+ return (mtlp);
+}
+
+struct memory_type *
+memstat_mtl_first(struct memory_type_list *list)
+{
+
+ return (LIST_FIRST(&list->mtl_list));
+}
+
+struct memory_type *
+memstat_mtl_next(struct memory_type *mtp)
+{
+
+ return (LIST_NEXT(mtp, mt_list));
+}
+
+void
+_memstat_mtl_empty(struct memory_type_list *list)
+{
+ struct memory_type *mtp;
+
+ while ((mtp = LIST_FIRST(&list->mtl_list))) {
+ LIST_REMOVE(mtp, mt_list);
+ free(mtp);
+ }
+}
+
+void
+memstat_mtl_free(struct memory_type_list *list)
+{
+
+ _memstat_mtl_empty(list);
+ free(list);
+}
+
+int
+memstat_mtl_geterror(struct memory_type_list *list)
+{
+
+ return (list->mtl_error);
+}
+
+/*
+ * Look for an existing memory_type entry in a memory_type list, based on the
+ * allocator and name of the type. If not found, return NULL. No errno or
+ * memstat error.
+ */
+struct memory_type *
+memstat_mtl_find(struct memory_type_list *list, int allocator,
+ const char *name)
+{
+ struct memory_type *mtp;
+
+ LIST_FOREACH(mtp, &list->mtl_list, mt_list) {
+ if ((mtp->mt_allocator == allocator ||
+ allocator == ALLOCATOR_ANY) &&
+ strcmp(mtp->mt_name, name) == 0)
+ return (mtp);
+ }
+ return (NULL);
+}
+
+/*
+ * Allocate a new memory_type with the specificed allocator type and name,
+ * then insert into the list. The structure will be zero'd.
+ *
+ * libmemstat(3) internal function.
+ */
+struct memory_type *
+_memstat_mt_allocate(struct memory_type_list *list, int allocator,
+ const char *name)
+{
+ struct memory_type *mtp;
+
+ mtp = malloc(sizeof(*mtp));
+ if (mtp == NULL)
+ return (NULL);
+
+ bzero(mtp, sizeof(*mtp));
+
+ mtp->mt_allocator = allocator;
+ strlcpy(mtp->mt_name, name, MEMTYPE_MAXNAME);
+ LIST_INSERT_HEAD(&list->mtl_list, mtp, mt_list);
+ return (mtp);
+}
+
+/*
+ * Reset any libmemstat(3)-owned statistics in a memory_type record so that
+ * it can be reused without incremental addition problems. Caller-owned
+ * memory is left "as-is", and must be updated by the caller if desired.
+ *
+ * libmemstat(3) internal function.
+ */
+void
+_memstat_mt_reset_stats(struct memory_type *mtp)
+{
+ int i;
+
+ mtp->mt_countlimit = 0;
+ mtp->mt_byteslimit = 0;
+ mtp->mt_sizemask = 0;
+ mtp->mt_size = 0;
+
+ mtp->mt_memalloced = 0;
+ mtp->mt_memfreed = 0;
+ mtp->mt_numallocs = 0;
+ mtp->mt_numfrees = 0;
+ mtp->mt_bytes = 0;
+ mtp->mt_count = 0;
+ mtp->mt_free = 0;
+ mtp->mt_failures = 0;
+
+ mtp->mt_zonefree = 0;
+ mtp->mt_kegfree = 0;
+
+ for (i = 0; i < MEMSTAT_MAXCPU; i++) {
+ mtp->mt_percpu_alloc[i].mtp_memalloced = 0;
+ mtp->mt_percpu_alloc[i].mtp_memfreed = 0;
+ mtp->mt_percpu_alloc[i].mtp_numallocs = 0;
+ mtp->mt_percpu_alloc[i].mtp_numfrees = 0;
+ mtp->mt_percpu_alloc[i].mtp_sizemask = 0;
+ mtp->mt_percpu_cache[i].mtp_free = 0;
+ }
+}
+
+/*
+ * Accessor methods for struct memory_type. Avoids encoding the structure
+ * ABI into the application.
+ */
+const char *
+memstat_get_name(const struct memory_type *mtp)
+{
+
+ return (mtp->mt_name);
+}
+
+int
+memstat_get_allocator(const struct memory_type *mtp)
+{
+
+ return (mtp->mt_allocator);
+}
+
+uint64_t
+memstat_get_countlimit(const struct memory_type *mtp)
+{
+
+ return (mtp->mt_countlimit);
+}
+
+uint64_t
+memstat_get_byteslimit(const struct memory_type *mtp)
+{
+
+ return (mtp->mt_byteslimit);
+}
+
+uint64_t
+memstat_get_sizemask(const struct memory_type *mtp)
+{
+
+ return (mtp->mt_sizemask);
+}
+
+uint64_t
+memstat_get_size(const struct memory_type *mtp)
+{
+
+ return (mtp->mt_size);
+}
+
+uint64_t
+memstat_get_memalloced(const struct memory_type *mtp)
+{
+
+ return (mtp->mt_memalloced);
+}
+
+uint64_t
+memstat_get_memfreed(const struct memory_type *mtp)
+{
+
+ return (mtp->mt_memfreed);
+}
+
+uint64_t
+memstat_get_numallocs(const struct memory_type *mtp)
+{
+
+ return (mtp->mt_numallocs);
+}
+
+uint64_t
+memstat_get_numfrees(const struct memory_type *mtp)
+{
+
+ return (mtp->mt_numfrees);
+}
+
+uint64_t
+memstat_get_bytes(const struct memory_type *mtp)
+{
+
+ return (mtp->mt_bytes);
+}
+
+uint64_t
+memstat_get_count(const struct memory_type *mtp)
+{
+
+ return (mtp->mt_count);
+}
+
+uint64_t
+memstat_get_free(const struct memory_type *mtp)
+{
+
+ return (mtp->mt_free);
+}
+
+uint64_t
+memstat_get_failures(const struct memory_type *mtp)
+{
+
+ return (mtp->mt_failures);
+}
+
+void *
+memstat_get_caller_pointer(const struct memory_type *mtp, int index)
+{
+
+ return (mtp->mt_caller_pointer[index]);
+}
+
+void
+memstat_set_caller_pointer(struct memory_type *mtp, int index, void *value)
+{
+
+ mtp->mt_caller_pointer[index] = value;
+}
+
+uint64_t
+memstat_get_caller_uint64(const struct memory_type *mtp, int index)
+{
+
+ return (mtp->mt_caller_uint64[index]);
+}
+
+void
+memstat_set_caller_uint64(struct memory_type *mtp, int index, uint64_t value)
+{
+
+ mtp->mt_caller_uint64[index] = value;
+}
+
+uint64_t
+memstat_get_zonefree(const struct memory_type *mtp)
+{
+
+ return (mtp->mt_zonefree);
+}
+
+uint64_t
+memstat_get_kegfree(const struct memory_type *mtp)
+{
+
+ return (mtp->mt_kegfree);
+}
+
+uint64_t
+memstat_get_percpu_memalloced(const struct memory_type *mtp, int cpu)
+{
+
+ return (mtp->mt_percpu_alloc[cpu].mtp_memalloced);
+}
+
+uint64_t
+memstat_get_percpu_memfreed(const struct memory_type *mtp, int cpu)
+{
+
+ return (mtp->mt_percpu_alloc[cpu].mtp_memfreed);
+}
+
+uint64_t
+memstat_get_percpu_numallocs(const struct memory_type *mtp, int cpu)
+{
+
+ return (mtp->mt_percpu_alloc[cpu].mtp_numallocs);
+}
+
+uint64_t
+memstat_get_percpu_numfrees(const struct memory_type *mtp, int cpu)
+{
+
+ return (mtp->mt_percpu_alloc[cpu].mtp_numfrees);
+}
+
+uint64_t
+memstat_get_percpu_sizemask(const struct memory_type *mtp, int cpu)
+{
+
+ return (mtp->mt_percpu_alloc[cpu].mtp_sizemask);
+}
+
+void *
+memstat_get_percpu_caller_pointer(const struct memory_type *mtp, int cpu,
+ int index)
+{
+
+ return (mtp->mt_percpu_alloc[cpu].mtp_caller_pointer[index]);
+}
+
+void
+memstat_set_percpu_caller_pointer(struct memory_type *mtp, int cpu,
+ int index, void *value)
+{
+
+ mtp->mt_percpu_alloc[cpu].mtp_caller_pointer[index] = value;
+}
+
+uint64_t
+memstat_get_percpu_caller_uint64(const struct memory_type *mtp, int cpu,
+ int index)
+{
+
+ return (mtp->mt_percpu_alloc[cpu].mtp_caller_uint64[index]);
+}
+
+void
+memstat_set_percpu_caller_uint64(struct memory_type *mtp, int cpu, int index,
+ uint64_t value)
+{
+
+ mtp->mt_percpu_alloc[cpu].mtp_caller_uint64[index] = value;
+}
+
+uint64_t
+memstat_get_percpu_free(const struct memory_type *mtp, int cpu)
+{
+
+ return (mtp->mt_percpu_cache[cpu].mtp_free);
+}
diff --git a/lib/libmemstat/memstat.h b/lib/libmemstat/memstat.h
new file mode 100644
index 0000000..904e77e
--- /dev/null
+++ b/lib/libmemstat/memstat.h
@@ -0,0 +1,174 @@
+/*-
+ * Copyright (c) 2005 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$
+ */
+
+#ifndef _MEMSTAT_H_
+#define _MEMSTAT_H_
+
+/*
+ * Number of CPU slots in library-internal data structures. This should be
+ * at least the value of MAXCPU from param.h.
+ */
+#define MEMSTAT_MAXCPU 16
+
+/*
+ * Amount of caller data to maintain for each caller data slot. Applications
+ * must not request more than this number of caller save data, or risk
+ * corrupting internal libmemstat(3) data structures. A compile time check
+ * in the application is probably appropriate.
+ */
+#define MEMSTAT_MAXCALLER 16
+
+/*
+ * libmemstat(3) is able to extract memory data from different allocators;
+ * when it does so, it tags which allocator it got the data from so that
+ * consumers can determine which fields are usable, as data returned varies
+ * some.
+ */
+#define ALLOCATOR_UNKNOWN 0
+#define ALLOCATOR_MALLOC 1
+#define ALLOCATOR_UMA 2
+#define ALLOCATOR_ANY 255
+
+/*
+ * Library maximum type name. Should be max(set of name maximums over
+ * various allocators).
+ */
+#define MEMTYPE_MAXNAME 32
+
+/*
+ * Library error conditions, mostly from the underlying data sources. On
+ * failure, functions typically return (-1) or (NULL); on success, (0) or a
+ * valid data pointer. The error from the last operation is stored in
+ * struct memory_type, and accessed via memstat_get_error(mtp).
+ */
+#define MEMSTAT_ERROR_UNDEFINED 0 /* Initialization value. */
+#define MEMSTAT_ERROR_NOMEMORY 1 /* Out of memory. */
+#define MEMSTAT_ERROR_VERSION 2 /* Unsupported version. */
+#define MEMSTAT_ERROR_PERMISSION 3 /* Permission denied. */
+#define MEMSTAT_ERROR_TOOMANYCPUS 4 /* Too many CPUs. */
+#define MEMSTAT_ERROR_DATAERROR 5 /* Error in stat data. */
+#define MEMSTAT_ERROR_KVM 6 /* See kvm_geterr() for err. */
+#define MEMSTAT_ERROR_KVM_NOSYMBOL 7 /* Symbol not available. */
+#define MEMSTAT_ERROR_KVM_SHORTREAD 8 /* Short kvm_read return. */
+
+/*
+ * Forward declare struct memory_type, which holds per-type properties and
+ * statistics. This is an opaque type, to be frobbed only from within the
+ * library, in order to avoid building ABI assumptions into the application.
+ * Accessor methods should be used to get and sometimes set the fields from
+ * consumers of the library.
+ */
+struct memory_type;
+
+/*
+ * struct memory_type_list is the head of a list of memory types and
+ * statistics.
+ */
+struct memory_type_list;
+
+__BEGIN_DECLS
+/*
+ * Functions that operate without memory type or memory type list context.
+ */
+const char *memstat_strerror(int error);
+
+/*
+ * Functions for managing memory type and statistics data.
+ */
+struct memory_type_list *memstat_mtl_alloc(void);
+struct memory_type *memstat_mtl_first(struct memory_type_list *list);
+struct memory_type *memstat_mtl_next(struct memory_type *mtp);
+struct memory_type *memstat_mtl_find(struct memory_type_list *list,
+ int allocator, const char *name);
+void memstat_mtl_free(struct memory_type_list *list);
+int memstat_mtl_geterror(struct memory_type_list *list);
+
+/*
+ * Functions to retrieve data from a live kernel using sysctl.
+ */
+int memstat_sysctl_all(struct memory_type_list *list, int flags);
+int memstat_sysctl_malloc(struct memory_type_list *list, int flags);
+int memstat_sysctl_uma(struct memory_type_list *list, int flags);
+
+/*
+ * Functions to retrieve data from a kernel core (or /dev/kmem).
+ */
+int memstat_kvm_all(struct memory_type_list *list, void *kvm_handle);
+int memstat_kvm_malloc(struct memory_type_list *list, void *kvm_handle);
+int memstat_kvm_uma(struct memory_type_list *list, void *kvm_handle);
+
+/*
+ * Accessor methods for struct memory_type.
+ */
+const char *memstat_get_name(const struct memory_type *mtp);
+int memstat_get_allocator(const struct memory_type *mtp);
+uint64_t memstat_get_countlimit(const struct memory_type *mtp);
+uint64_t memstat_get_byteslimit(const struct memory_type *mtp);
+uint64_t memstat_get_sizemask(const struct memory_type *mtp);
+uint64_t memstat_get_size(const struct memory_type *mtp);
+uint64_t memstat_get_memalloced(const struct memory_type *mtp);
+uint64_t memstat_get_memfreed(const struct memory_type *mtp);
+uint64_t memstat_get_numallocs(const struct memory_type *mtp);
+uint64_t memstat_get_numfrees(const struct memory_type *mtp);
+uint64_t memstat_get_bytes(const struct memory_type *mtp);
+uint64_t memstat_get_count(const struct memory_type *mtp);
+uint64_t memstat_get_free(const struct memory_type *mtp);
+uint64_t memstat_get_failures(const struct memory_type *mtp);
+void *memstat_get_caller_pointer(const struct memory_type *mtp,
+ int index);
+void memstat_set_caller_pointer(struct memory_type *mtp,
+ int index, void *value);
+uint64_t memstat_get_caller_uint64(const struct memory_type *mtp,
+ int index);
+void memstat_set_caller_uint64(struct memory_type *mtp, int index,
+ uint64_t value);
+uint64_t memstat_get_zonefree(const struct memory_type *mtp);
+uint64_t memstat_get_kegfree(const struct memory_type *mtp);
+uint64_t memstat_get_percpu_memalloced(const struct memory_type *mtp,
+ int cpu);
+uint64_t memstat_get_percpu_memfreed(const struct memory_type *mtp,
+ int cpu);
+uint64_t memstat_get_percpu_numallocs(const struct memory_type *mtp,
+ int cpu);
+uint64_t memstat_get_percpu_numfrees(const struct memory_type *mtp,
+ int cpu);
+uint64_t memstat_get_percpu_sizemask(const struct memory_type *mtp,
+ int cpu);
+void *memstat_get_percpu_caller_pointer(
+ const struct memory_type *mtp, int cpu, int index);
+void memstat_set_percpu_caller_pointer(struct memory_type *mtp,
+ int cpu, int index, void *value);
+uint64_t memstat_get_percpu_caller_uint64(
+ const struct memory_type *mtp, int cpu, int index);
+void memstat_set_percpu_caller_uint64(struct memory_type *mtp,
+ int cpu, int index, uint64_t value);
+uint64_t memstat_get_percpu_free(const struct memory_type *mtp,
+ int cpu);
+__END_DECLS
+
+#endif /* !_MEMSTAT_H_ */
diff --git a/lib/libmemstat/memstat_all.c b/lib/libmemstat/memstat_all.c
new file mode 100644
index 0000000..bd74b8a
--- /dev/null
+++ b/lib/libmemstat/memstat_all.c
@@ -0,0 +1,58 @@
+/*-
+ * Copyright (c) 2005 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 <sys/queue.h>
+
+#include "memstat.h"
+
+/*
+ * Query all available memory allocator sources. Currently this consists of
+ * malloc(9) and UMA(9).
+ */
+int
+memstat_sysctl_all(struct memory_type_list *mtlp, int flags)
+{
+
+ if (memstat_sysctl_malloc(mtlp, flags) < 0)
+ return (-1);
+ if (memstat_sysctl_uma(mtlp, flags) < 0)
+ return (-1);
+ return (0);
+}
+
+int
+memstat_kvm_all(struct memory_type_list *mtlp, void *kvm_handle)
+{
+
+ if (memstat_kvm_malloc(mtlp, kvm_handle) < 0)
+ return (-1);
+ if (memstat_kvm_uma(mtlp, kvm_handle) < 0)
+ return (-1);
+ return (0);
+}
diff --git a/lib/libmemstat/memstat_internal.h b/lib/libmemstat/memstat_internal.h
new file mode 100644
index 0000000..7123518
--- /dev/null
+++ b/lib/libmemstat/memstat_internal.h
@@ -0,0 +1,124 @@
+/*-
+ * Copyright (c) 2005 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$
+ */
+
+#ifndef _MEMSTAT_INTERNAL_H_
+#define _MEMSTAT_INTERNAL_H_
+
+/*
+ * memstat maintains its own internal notion of statistics on each memory
+ * type, common across UMA and kernel malloc. Some fields are straight from
+ * the allocator statistics, others are derived when extracted from the
+ * kernel. A struct memory_type will describe each type supported by an
+ * allocator. memory_type structures can be chained into lists.
+ */
+struct memory_type {
+ /*
+ * Static properties of type.
+ */
+ int mt_allocator; /* malloc(9), uma(9), etc. */
+ char mt_name[MEMTYPE_MAXNAME]; /* name of memory type. */
+
+ /*
+ * (Relatively) static zone settings, that don't uniquely identify
+ * the zone, but also don't change much.
+ */
+ uint64_t mt_countlimit; /* 0, or maximum allocations. */
+ uint64_t mt_byteslimit; /* 0, or maximum bytes. */
+ uint64_t mt_sizemask; /* malloc: allocated size bitmask. */
+ uint64_t mt_size; /* uma: size of objects. */
+
+ /*
+ * Zone or type information that includes all caches and any central
+ * zone state. Depending on the allocator, this may be synthesized
+ * from several sources, or directly measured.
+ */
+ uint64_t mt_memalloced; /* Bytes allocated over life time. */
+ uint64_t mt_memfreed; /* Bytes freed over life time. */
+ uint64_t mt_numallocs; /* Allocations over life time. */
+ uint64_t mt_numfrees; /* Frees over life time. */
+ uint64_t mt_bytes; /* Bytes currently allocated. */
+ uint64_t mt_count; /* Number of current allocations. */
+ uint64_t mt_free; /* Number of cached free items. */
+ uint64_t mt_failures; /* Number of allocation failures. */
+
+ /*
+ * Caller-owned memory.
+ */
+ void *mt_caller_pointer[MEMSTAT_MAXCALLER]; /* Pointers. */
+ uint64_t mt_caller_uint64[MEMSTAT_MAXCALLER]; /* Integers. */
+
+ /*
+ * For allocators making use of per-CPU caches, we also provide raw
+ * statistics from the central allocator and each per-CPU cache,
+ * which (combined) sometimes make up the above general statistics.
+ *
+ * First, central zone/type state, all numbers excluding any items
+ * cached in per-CPU caches.
+ *
+ * XXXRW: Might be desirable to separately expose allocation stats
+ * from zone, which should (combined with per-cpu) add up to the
+ * global stats above.
+ */
+ uint64_t mt_zonefree; /* Free items in zone. */
+ uint64_t mt_kegfree; /* Free items in keg. */
+
+ /*
+ * Per-CPU measurements fall into two categories: per-CPU allocation,
+ * and per-CPU cache state.
+ */
+ struct {
+ uint64_t mtp_memalloced;/* Per-CPU mt_memalloced. */
+ uint64_t mtp_memfreed; /* Per-CPU mt_memfreed. */
+ uint64_t mtp_numallocs; /* Per-CPU mt_numallocs. */
+ uint64_t mtp_numfrees; /* Per-CPU mt_numfrees. */
+ uint64_t mtp_sizemask; /* Per-CPU mt_sizemask. */
+ void *mtp_caller_pointer[MEMSTAT_MAXCALLER];
+ uint64_t mtp_caller_uint64[MEMSTAT_MAXCALLER];
+ } mt_percpu_alloc[MEMSTAT_MAXCPU];
+
+ struct {
+ uint64_t mtp_free; /* Per-CPU cache free items. */
+ } mt_percpu_cache[MEMSTAT_MAXCPU];
+
+ LIST_ENTRY(memory_type) mt_list; /* List of types. */
+};
+
+/*
+ * Description of struct memory_type_list is in memstat.h.
+ */
+struct memory_type_list {
+ LIST_HEAD(, memory_type) mtl_list;
+ int mtl_error;
+};
+
+void _memstat_mtl_empty(struct memory_type_list *list);
+struct memory_type *_memstat_mt_allocate(struct memory_type_list *list,
+ int allocator, const char *name);
+void _memstat_mt_reset_stats(struct memory_type *mtp);
+
+#endif /* !_MEMSTAT_INTERNAL_H_ */
diff --git a/lib/libmemstat/memstat_malloc.c b/lib/libmemstat/memstat_malloc.c
new file mode 100644
index 0000000..b9b686f
--- /dev/null
+++ b/lib/libmemstat/memstat_malloc.c
@@ -0,0 +1,408 @@
+/*-
+ * Copyright (c) 2005 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/param.h>
+#include <sys/malloc.h>
+#include <sys/sysctl.h>
+
+#include <err.h>
+#include <errno.h>
+#include <kvm.h>
+#include <nlist.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "memstat.h"
+#include "memstat_internal.h"
+
+static struct nlist namelist[] = {
+#define X_KMEMSTATISTICS 0
+ { .n_name = "_kmemstatistics" },
+#define X_MP_MAXCPUS 1
+ { .n_name = "_mp_maxcpus" },
+ { .n_name = "" },
+};
+
+/*
+ * Extract malloc(9) statistics from the running kernel, and store all memory
+ * type information in the passed list. For each type, check the list for an
+ * existing entry with the right name/allocator -- if present, update that
+ * entry. Otherwise, add a new entry. On error, the entire list will be
+ * cleared, as entries will be in an inconsistent state.
+ *
+ * To reduce the level of work for a list that starts empty, we keep around a
+ * hint as to whether it was empty when we began, so we can avoid searching
+ * the list for entries to update. Updates are O(n^2) due to searching for
+ * each entry before adding it.
+ */
+int
+memstat_sysctl_malloc(struct memory_type_list *list, int flags)
+{
+ struct malloc_type_stream_header *mtshp;
+ struct malloc_type_header *mthp;
+ struct malloc_type_stats *mtsp;
+ struct memory_type *mtp;
+ int count, hint_dontsearch, i, j, maxcpus;
+ char *buffer, *p;
+ size_t size;
+
+ hint_dontsearch = LIST_EMPTY(&list->mtl_list);
+
+ /*
+ * Query the number of CPUs, number of malloc types so that we can
+ * guess an initial buffer size. We loop until we succeed or really
+ * fail. Note that the value of maxcpus we query using sysctl is not
+ * the version we use when processing the real data -- that is read
+ * from the header.
+ */
+retry:
+ size = sizeof(maxcpus);
+ if (sysctlbyname("kern.smp.maxcpus", &maxcpus, &size, NULL, 0) < 0) {
+ if (errno == EACCES || errno == EPERM)
+ list->mtl_error = MEMSTAT_ERROR_PERMISSION;
+ else
+ list->mtl_error = MEMSTAT_ERROR_DATAERROR;
+ return (-1);
+ }
+ if (size != sizeof(maxcpus)) {
+ list->mtl_error = MEMSTAT_ERROR_DATAERROR;
+ return (-1);
+ }
+
+ if (maxcpus > MEMSTAT_MAXCPU) {
+ list->mtl_error = MEMSTAT_ERROR_TOOMANYCPUS;
+ return (-1);
+ }
+
+ size = sizeof(count);
+ if (sysctlbyname("kern.malloc_count", &count, &size, NULL, 0) < 0) {
+ if (errno == EACCES || errno == EPERM)
+ list->mtl_error = MEMSTAT_ERROR_PERMISSION;
+ else
+ list->mtl_error = MEMSTAT_ERROR_VERSION;
+ return (-1);
+ }
+ if (size != sizeof(count)) {
+ list->mtl_error = MEMSTAT_ERROR_DATAERROR;
+ return (-1);
+ }
+
+ size = sizeof(*mthp) + count * (sizeof(*mthp) + sizeof(*mtsp) *
+ maxcpus);
+
+ buffer = malloc(size);
+ if (buffer == NULL) {
+ list->mtl_error = MEMSTAT_ERROR_NOMEMORY;
+ return (-1);
+ }
+
+ if (sysctlbyname("kern.malloc_stats", buffer, &size, NULL, 0) < 0) {
+ /*
+ * XXXRW: ENOMEM is an ambiguous return, we should bound the
+ * number of loops, perhaps.
+ */
+ if (errno == ENOMEM) {
+ free(buffer);
+ goto retry;
+ }
+ if (errno == EACCES || errno == EPERM)
+ list->mtl_error = MEMSTAT_ERROR_PERMISSION;
+ else
+ list->mtl_error = MEMSTAT_ERROR_VERSION;
+ free(buffer);
+ return (-1);
+ }
+
+ if (size == 0) {
+ free(buffer);
+ return (0);
+ }
+
+ if (size < sizeof(*mtshp)) {
+ list->mtl_error = MEMSTAT_ERROR_VERSION;
+ free(buffer);
+ return (-1);
+ }
+ p = buffer;
+ mtshp = (struct malloc_type_stream_header *)p;
+ p += sizeof(*mtshp);
+
+ if (mtshp->mtsh_version != MALLOC_TYPE_STREAM_VERSION) {
+ list->mtl_error = MEMSTAT_ERROR_VERSION;
+ free(buffer);
+ return (-1);
+ }
+
+ if (mtshp->mtsh_maxcpus > MEMSTAT_MAXCPU) {
+ list->mtl_error = MEMSTAT_ERROR_TOOMANYCPUS;
+ free(buffer);
+ return (-1);
+ }
+
+ /*
+ * For the remainder of this function, we are quite trusting about
+ * the layout of structures and sizes, since we've determined we have
+ * a matching version and acceptable CPU count.
+ */
+ maxcpus = mtshp->mtsh_maxcpus;
+ count = mtshp->mtsh_count;
+ for (i = 0; i < count; i++) {
+ mthp = (struct malloc_type_header *)p;
+ p += sizeof(*mthp);
+
+ if (hint_dontsearch == 0) {
+ mtp = memstat_mtl_find(list, ALLOCATOR_MALLOC,
+ mthp->mth_name);
+ } else
+ mtp = NULL;
+ if (mtp == NULL)
+ mtp = _memstat_mt_allocate(list, ALLOCATOR_MALLOC,
+ mthp->mth_name);
+ if (mtp == NULL) {
+ _memstat_mtl_empty(list);
+ free(buffer);
+ list->mtl_error = MEMSTAT_ERROR_NOMEMORY;
+ return (-1);
+ }
+
+ /*
+ * Reset the statistics on a current node.
+ */
+ _memstat_mt_reset_stats(mtp);
+
+ for (j = 0; j < maxcpus; j++) {
+ mtsp = (struct malloc_type_stats *)p;
+ p += sizeof(*mtsp);
+
+ /*
+ * Sumarize raw statistics across CPUs into coalesced
+ * statistics.
+ */
+ mtp->mt_memalloced += mtsp->mts_memalloced;
+ mtp->mt_memfreed += mtsp->mts_memfreed;
+ mtp->mt_numallocs += mtsp->mts_numallocs;
+ mtp->mt_numfrees += mtsp->mts_numfrees;
+ mtp->mt_sizemask |= mtsp->mts_size;
+
+ /*
+ * Copies of per-CPU statistics.
+ */
+ mtp->mt_percpu_alloc[j].mtp_memalloced =
+ mtsp->mts_memalloced;
+ mtp->mt_percpu_alloc[j].mtp_memfreed =
+ mtsp->mts_memfreed;
+ mtp->mt_percpu_alloc[j].mtp_numallocs =
+ mtsp->mts_numallocs;
+ mtp->mt_percpu_alloc[j].mtp_numfrees =
+ mtsp->mts_numfrees;
+ mtp->mt_percpu_alloc[j].mtp_sizemask =
+ mtsp->mts_size;
+ }
+
+ /*
+ * Derived cross-CPU statistics.
+ */
+ mtp->mt_bytes = mtp->mt_memalloced - mtp->mt_memfreed;
+ mtp->mt_count = mtp->mt_numallocs - mtp->mt_numfrees;
+ }
+
+ free(buffer);
+
+ return (0);
+}
+
+static int
+kread(kvm_t *kvm, void *kvm_pointer, void *address, size_t size,
+ size_t offset)
+{
+ ssize_t ret;
+
+ ret = kvm_read(kvm, (unsigned long)kvm_pointer + offset, address,
+ size);
+ if (ret < 0)
+ return (MEMSTAT_ERROR_KVM);
+ if ((size_t)ret != size)
+ return (MEMSTAT_ERROR_KVM_SHORTREAD);
+ return (0);
+}
+
+static int
+kread_string(kvm_t *kvm, void *kvm_pointer, char *buffer, int buflen)
+{
+ ssize_t ret;
+ int i;
+
+ for (i = 0; i < buflen; i++) {
+ ret = kvm_read(kvm, (unsigned long)kvm_pointer + i,
+ &(buffer[i]), sizeof(char));
+ if (ret < 0)
+ return (MEMSTAT_ERROR_KVM);
+ if ((size_t)ret != sizeof(char))
+ return (MEMSTAT_ERROR_KVM_SHORTREAD);
+ if (buffer[i] == '\0')
+ return (0);
+ }
+ /* Truncate. */
+ buffer[i-1] = '\0';
+ return (0);
+}
+
+static int
+kread_symbol(kvm_t *kvm, int index, void *address, size_t size,
+ size_t offset)
+{
+ ssize_t ret;
+
+ ret = kvm_read(kvm, namelist[index].n_value + offset, address, size);
+ if (ret < 0)
+ return (MEMSTAT_ERROR_KVM);
+ if ((size_t)ret != size)
+ return (MEMSTAT_ERROR_KVM_SHORTREAD);
+ return (0);
+}
+
+int
+memstat_kvm_malloc(struct memory_type_list *list, void *kvm_handle)
+{
+ struct memory_type *mtp;
+ void *kmemstatistics;
+ int hint_dontsearch, j, mp_maxcpus, ret;
+ char name[MEMTYPE_MAXNAME];
+ struct malloc_type_stats mts[MEMSTAT_MAXCPU], *mtsp;
+ struct malloc_type type, *typep;
+ kvm_t *kvm;
+
+ kvm = (kvm_t *)kvm_handle;
+
+ hint_dontsearch = LIST_EMPTY(&list->mtl_list);
+
+ if (kvm_nlist(kvm, namelist) != 0) {
+ list->mtl_error = MEMSTAT_ERROR_KVM;
+ return (-1);
+ }
+
+ if (namelist[X_KMEMSTATISTICS].n_type == 0 ||
+ namelist[X_KMEMSTATISTICS].n_value == 0) {
+ list->mtl_error = MEMSTAT_ERROR_KVM_NOSYMBOL;
+ return (-1);
+ }
+
+ ret = kread_symbol(kvm, X_MP_MAXCPUS, &mp_maxcpus,
+ sizeof(mp_maxcpus), 0);
+ if (ret != 0) {
+ list->mtl_error = ret;
+ return (-1);
+ }
+
+ if (mp_maxcpus > MEMSTAT_MAXCPU) {
+ list->mtl_error = MEMSTAT_ERROR_TOOMANYCPUS;
+ return (-1);
+ }
+
+ ret = kread_symbol(kvm, X_KMEMSTATISTICS, &kmemstatistics,
+ sizeof(kmemstatistics), 0);
+ if (ret != 0) {
+ list->mtl_error = ret;
+ return (-1);
+ }
+
+ for (typep = kmemstatistics; typep != NULL; typep = type.ks_next) {
+ ret = kread(kvm, typep, &type, sizeof(type), 0);
+ if (ret != 0) {
+ _memstat_mtl_empty(list);
+ list->mtl_error = ret;
+ return (-1);
+ }
+ ret = kread_string(kvm, (void *)type.ks_shortdesc, name,
+ MEMTYPE_MAXNAME);
+ if (ret != 0) {
+ _memstat_mtl_empty(list);
+ list->mtl_error = ret;
+ return (-1);
+ }
+
+ /*
+ * Take advantage of explicit knowledge that
+ * malloc_type_internal is simply an array of statistics
+ * structures of number MAXCPU. Since our compile-time
+ * value for MAXCPU may differ from the kernel's, we
+ * populate our own array.
+ */
+ ret = kread(kvm, type.ks_handle, mts, mp_maxcpus *
+ sizeof(struct malloc_type_stats), 0);
+ if (ret != 0) {
+ _memstat_mtl_empty(list);
+ list->mtl_error = ret;
+ return (-1);
+ }
+
+ if (hint_dontsearch == 0) {
+ mtp = memstat_mtl_find(list, ALLOCATOR_MALLOC, name);
+ } else
+ mtp = NULL;
+ if (mtp == NULL)
+ mtp = _memstat_mt_allocate(list, ALLOCATOR_MALLOC,
+ name);
+ if (mtp == NULL) {
+ _memstat_mtl_empty(list);
+ list->mtl_error = MEMSTAT_ERROR_NOMEMORY;
+ return (-1);
+ }
+
+ /*
+ * This logic is replicated from kern_malloc.c, and should
+ * be kept in sync.
+ */
+ _memstat_mt_reset_stats(mtp);
+ for (j = 0; j < mp_maxcpus; j++) {
+ mtsp = &mts[j];
+ mtp->mt_memalloced += mtsp->mts_memalloced;
+ mtp->mt_memfreed += mtsp->mts_memfreed;
+ mtp->mt_numallocs += mtsp->mts_numallocs;
+ mtp->mt_numfrees += mtsp->mts_numfrees;
+ mtp->mt_sizemask |= mtsp->mts_size;
+
+ mtp->mt_percpu_alloc[j].mtp_memalloced =
+ mtsp->mts_memalloced;
+ mtp->mt_percpu_alloc[j].mtp_memfreed =
+ mtsp->mts_memfreed;
+ mtp->mt_percpu_alloc[j].mtp_numallocs =
+ mtsp->mts_numallocs;
+ mtp->mt_percpu_alloc[j].mtp_numfrees =
+ mtsp->mts_numfrees;
+ mtp->mt_percpu_alloc[j].mtp_sizemask =
+ mtsp->mts_size;
+ }
+
+ mtp->mt_bytes = mtp->mt_memalloced - mtp->mt_memfreed;
+ mtp->mt_count = mtp->mt_numallocs - mtp->mt_numfrees;
+ }
+
+ return (0);
+}
diff --git a/lib/libmemstat/memstat_uma.c b/lib/libmemstat/memstat_uma.c
new file mode 100644
index 0000000..b24721f
--- /dev/null
+++ b/lib/libmemstat/memstat_uma.c
@@ -0,0 +1,465 @@
+/*-
+ * Copyright (c) 2005-2006 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/param.h>
+#include <sys/sysctl.h>
+
+#define LIBMEMSTAT /* Cause vm_page.h not to include opt_vmpage.h */
+#include <vm/vm.h>
+#include <vm/vm_page.h>
+
+#include <vm/uma.h>
+#include <vm/uma_int.h>
+
+#include <err.h>
+#include <errno.h>
+#include <kvm.h>
+#include <nlist.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "memstat.h"
+#include "memstat_internal.h"
+
+static struct nlist namelist[] = {
+#define X_UMA_KEGS 0
+ { .n_name = "_uma_kegs" },
+#define X_MP_MAXID 1
+ { .n_name = "_mp_maxid" },
+#define X_ALL_CPUS 2
+ { .n_name = "_all_cpus" },
+ { .n_name = "" },
+};
+
+/*
+ * Extract uma(9) statistics from the running kernel, and store all memory
+ * type information in the passed list. For each type, check the list for an
+ * existing entry with the right name/allocator -- if present, update that
+ * entry. Otherwise, add a new entry. On error, the entire list will be
+ * cleared, as entries will be in an inconsistent state.
+ *
+ * To reduce the level of work for a list that starts empty, we keep around a
+ * hint as to whether it was empty when we began, so we can avoid searching
+ * the list for entries to update. Updates are O(n^2) due to searching for
+ * each entry before adding it.
+ */
+int
+memstat_sysctl_uma(struct memory_type_list *list, int flags)
+{
+ struct uma_stream_header *ushp;
+ struct uma_type_header *uthp;
+ struct uma_percpu_stat *upsp;
+ struct memory_type *mtp;
+ int count, hint_dontsearch, i, j, maxcpus;
+ char *buffer, *p;
+ size_t size;
+
+ hint_dontsearch = LIST_EMPTY(&list->mtl_list);
+
+ /*
+ * Query the number of CPUs, number of malloc types so that we can
+ * guess an initial buffer size. We loop until we succeed or really
+ * fail. Note that the value of maxcpus we query using sysctl is not
+ * the version we use when processing the real data -- that is read
+ * from the header.
+ */
+retry:
+ size = sizeof(maxcpus);
+ if (sysctlbyname("kern.smp.maxcpus", &maxcpus, &size, NULL, 0) < 0) {
+ if (errno == EACCES || errno == EPERM)
+ list->mtl_error = MEMSTAT_ERROR_PERMISSION;
+ else
+ list->mtl_error = MEMSTAT_ERROR_DATAERROR;
+ return (-1);
+ }
+ if (size != sizeof(maxcpus)) {
+ list->mtl_error = MEMSTAT_ERROR_DATAERROR;
+ return (-1);
+ }
+
+ if (maxcpus > MEMSTAT_MAXCPU) {
+ list->mtl_error = MEMSTAT_ERROR_TOOMANYCPUS;
+ return (-1);
+ }
+
+ size = sizeof(count);
+ if (sysctlbyname("vm.zone_count", &count, &size, NULL, 0) < 0) {
+ if (errno == EACCES || errno == EPERM)
+ list->mtl_error = MEMSTAT_ERROR_PERMISSION;
+ else
+ list->mtl_error = MEMSTAT_ERROR_VERSION;
+ return (-1);
+ }
+ if (size != sizeof(count)) {
+ list->mtl_error = MEMSTAT_ERROR_DATAERROR;
+ return (-1);
+ }
+
+ size = sizeof(*uthp) + count * (sizeof(*uthp) + sizeof(*upsp) *
+ maxcpus);
+
+ buffer = malloc(size);
+ if (buffer == NULL) {
+ list->mtl_error = MEMSTAT_ERROR_NOMEMORY;
+ return (-1);
+ }
+
+ if (sysctlbyname("vm.zone_stats", buffer, &size, NULL, 0) < 0) {
+ /*
+ * XXXRW: ENOMEM is an ambiguous return, we should bound the
+ * number of loops, perhaps.
+ */
+ if (errno == ENOMEM) {
+ free(buffer);
+ goto retry;
+ }
+ if (errno == EACCES || errno == EPERM)
+ list->mtl_error = MEMSTAT_ERROR_PERMISSION;
+ else
+ list->mtl_error = MEMSTAT_ERROR_VERSION;
+ free(buffer);
+ return (-1);
+ }
+
+ if (size == 0) {
+ free(buffer);
+ return (0);
+ }
+
+ if (size < sizeof(*ushp)) {
+ list->mtl_error = MEMSTAT_ERROR_VERSION;
+ free(buffer);
+ return (-1);
+ }
+ p = buffer;
+ ushp = (struct uma_stream_header *)p;
+ p += sizeof(*ushp);
+
+ if (ushp->ush_version != UMA_STREAM_VERSION) {
+ list->mtl_error = MEMSTAT_ERROR_VERSION;
+ free(buffer);
+ return (-1);
+ }
+
+ if (ushp->ush_maxcpus > MEMSTAT_MAXCPU) {
+ list->mtl_error = MEMSTAT_ERROR_TOOMANYCPUS;
+ free(buffer);
+ return (-1);
+ }
+
+ /*
+ * For the remainder of this function, we are quite trusting about
+ * the layout of structures and sizes, since we've determined we have
+ * a matching version and acceptable CPU count.
+ */
+ maxcpus = ushp->ush_maxcpus;
+ count = ushp->ush_count;
+ for (i = 0; i < count; i++) {
+ uthp = (struct uma_type_header *)p;
+ p += sizeof(*uthp);
+
+ if (hint_dontsearch == 0) {
+ mtp = memstat_mtl_find(list, ALLOCATOR_UMA,
+ uthp->uth_name);
+ } else
+ mtp = NULL;
+ if (mtp == NULL)
+ mtp = _memstat_mt_allocate(list, ALLOCATOR_UMA,
+ uthp->uth_name);
+ if (mtp == NULL) {
+ _memstat_mtl_empty(list);
+ free(buffer);
+ list->mtl_error = MEMSTAT_ERROR_NOMEMORY;
+ return (-1);
+ }
+
+ /*
+ * Reset the statistics on a current node.
+ */
+ _memstat_mt_reset_stats(mtp);
+
+ mtp->mt_numallocs = uthp->uth_allocs;
+ mtp->mt_numfrees = uthp->uth_frees;
+ mtp->mt_failures = uthp->uth_fails;
+
+ for (j = 0; j < maxcpus; j++) {
+ upsp = (struct uma_percpu_stat *)p;
+ p += sizeof(*upsp);
+
+ mtp->mt_percpu_cache[j].mtp_free =
+ upsp->ups_cache_free;
+ mtp->mt_free += upsp->ups_cache_free;
+ mtp->mt_numallocs += upsp->ups_allocs;
+ mtp->mt_numfrees += upsp->ups_frees;
+ }
+
+ mtp->mt_size = uthp->uth_size;
+ mtp->mt_memalloced = mtp->mt_numallocs * uthp->uth_size;
+ mtp->mt_memfreed = mtp->mt_numfrees * uthp->uth_size;
+ mtp->mt_bytes = mtp->mt_memalloced - mtp->mt_memfreed;
+ mtp->mt_countlimit = uthp->uth_limit;
+ mtp->mt_byteslimit = uthp->uth_limit * uthp->uth_size;
+
+ mtp->mt_count = mtp->mt_numallocs - mtp->mt_numfrees;
+ mtp->mt_zonefree = uthp->uth_zone_free;
+
+ /*
+ * UMA secondary zones share a keg with the primary zone. To
+ * avoid double-reporting of free items, report keg free
+ * items only in the primary zone.
+ */
+ if (!(uthp->uth_zone_flags & UTH_ZONE_SECONDARY)) {
+ mtp->mt_kegfree = uthp->uth_keg_free;
+ mtp->mt_free += mtp->mt_kegfree;
+ }
+ mtp->mt_free += mtp->mt_zonefree;
+ }
+
+ free(buffer);
+
+ return (0);
+}
+
+static int
+kread(kvm_t *kvm, void *kvm_pointer, void *address, size_t size,
+ size_t offset)
+{
+ ssize_t ret;
+
+ ret = kvm_read(kvm, (unsigned long)kvm_pointer + offset, address,
+ size);
+ if (ret < 0)
+ return (MEMSTAT_ERROR_KVM);
+ if ((size_t)ret != size)
+ return (MEMSTAT_ERROR_KVM_SHORTREAD);
+ return (0);
+}
+
+static int
+kread_string(kvm_t *kvm, void *kvm_pointer, char *buffer, int buflen)
+{
+ ssize_t ret;
+ int i;
+
+ for (i = 0; i < buflen; i++) {
+ ret = kvm_read(kvm, (unsigned long)kvm_pointer + i,
+ &(buffer[i]), sizeof(char));
+ if (ret < 0)
+ return (MEMSTAT_ERROR_KVM);
+ if ((size_t)ret != sizeof(char))
+ return (MEMSTAT_ERROR_KVM_SHORTREAD);
+ if (buffer[i] == '\0')
+ return (0);
+ }
+ /* Truncate. */
+ buffer[i-1] = '\0';
+ return (0);
+}
+
+static int
+kread_symbol(kvm_t *kvm, int index, void *address, size_t size,
+ size_t offset)
+{
+ ssize_t ret;
+
+ ret = kvm_read(kvm, namelist[index].n_value + offset, address, size);
+ if (ret < 0)
+ return (MEMSTAT_ERROR_KVM);
+ if ((size_t)ret != size)
+ return (MEMSTAT_ERROR_KVM_SHORTREAD);
+ return (0);
+}
+
+/*
+ * memstat_kvm_uma() is similar to memstat_sysctl_uma(), only it extracts
+ * UMA(9) statistics from a kernel core/memory file.
+ */
+int
+memstat_kvm_uma(struct memory_type_list *list, void *kvm_handle)
+{
+ LIST_HEAD(, uma_keg) uma_kegs;
+ struct memory_type *mtp;
+ struct uma_bucket *ubp, ub;
+ struct uma_cache *ucp, *ucp_array;
+ struct uma_zone *uzp, uz;
+ struct uma_keg *kzp, kz;
+ int hint_dontsearch, i, mp_maxid, ret;
+ char name[MEMTYPE_MAXNAME];
+ __cpumask_t all_cpus;
+ kvm_t *kvm;
+
+ kvm = (kvm_t *)kvm_handle;
+ hint_dontsearch = LIST_EMPTY(&list->mtl_list);
+ if (kvm_nlist(kvm, namelist) != 0) {
+ list->mtl_error = MEMSTAT_ERROR_KVM;
+ return (-1);
+ }
+ if (namelist[X_UMA_KEGS].n_type == 0 ||
+ namelist[X_UMA_KEGS].n_value == 0) {
+ list->mtl_error = MEMSTAT_ERROR_KVM_NOSYMBOL;
+ return (-1);
+ }
+ ret = kread_symbol(kvm, X_MP_MAXID, &mp_maxid, sizeof(mp_maxid), 0);
+ if (ret != 0) {
+ list->mtl_error = ret;
+ return (-1);
+ }
+ ret = kread_symbol(kvm, X_UMA_KEGS, &uma_kegs, sizeof(uma_kegs), 0);
+ if (ret != 0) {
+ list->mtl_error = ret;
+ return (-1);
+ }
+ ret = kread_symbol(kvm, X_ALL_CPUS, &all_cpus, sizeof(all_cpus), 0);
+ if (ret != 0) {
+ list->mtl_error = ret;
+ return (-1);
+ }
+ ucp_array = malloc(sizeof(struct uma_cache) * (mp_maxid + 1));
+ if (ucp_array == NULL) {
+ list->mtl_error = MEMSTAT_ERROR_NOMEMORY;
+ return (-1);
+ }
+ for (kzp = LIST_FIRST(&uma_kegs); kzp != NULL; kzp =
+ LIST_NEXT(&kz, uk_link)) {
+ ret = kread(kvm, kzp, &kz, sizeof(kz), 0);
+ if (ret != 0) {
+ free(ucp_array);
+ _memstat_mtl_empty(list);
+ list->mtl_error = ret;
+ return (-1);
+ }
+ for (uzp = LIST_FIRST(&kz.uk_zones); uzp != NULL; uzp =
+ LIST_NEXT(&uz, uz_link)) {
+ ret = kread(kvm, uzp, &uz, sizeof(uz), 0);
+ if (ret != 0) {
+ free(ucp_array);
+ _memstat_mtl_empty(list);
+ list->mtl_error = ret;
+ return (-1);
+ }
+ ret = kread(kvm, uzp, ucp_array,
+ sizeof(struct uma_cache) * (mp_maxid + 1),
+ offsetof(struct uma_zone, uz_cpu[0]));
+ if (ret != 0) {
+ free(ucp_array);
+ _memstat_mtl_empty(list);
+ list->mtl_error = ret;
+ return (-1);
+ }
+ ret = kread_string(kvm, uz.uz_name, name,
+ MEMTYPE_MAXNAME);
+ if (ret != 0) {
+ free(ucp_array);
+ _memstat_mtl_empty(list);
+ list->mtl_error = ret;
+ return (-1);
+ }
+ if (hint_dontsearch == 0) {
+ mtp = memstat_mtl_find(list, ALLOCATOR_UMA,
+ name);
+ } else
+ mtp = NULL;
+ if (mtp == NULL)
+ mtp = _memstat_mt_allocate(list, ALLOCATOR_UMA,
+ name);
+ if (mtp == NULL) {
+ free(ucp_array);
+ _memstat_mtl_empty(list);
+ list->mtl_error = MEMSTAT_ERROR_NOMEMORY;
+ return (-1);
+ }
+ /*
+ * Reset the statistics on a current node.
+ */
+ _memstat_mt_reset_stats(mtp);
+ mtp->mt_numallocs = uz.uz_allocs;
+ mtp->mt_numfrees = uz.uz_frees;
+ mtp->mt_failures = uz.uz_fails;
+ if (kz.uk_flags & UMA_ZFLAG_INTERNAL)
+ goto skip_percpu;
+ for (i = 0; i < mp_maxid + 1; i++) {
+ if ((all_cpus & (1 << i)) == 0)
+ continue;
+ ucp = &ucp_array[i];
+ mtp->mt_numallocs += ucp->uc_allocs;
+ mtp->mt_numfrees += ucp->uc_frees;
+
+ if (ucp->uc_allocbucket != NULL) {
+ ret = kread(kvm, ucp->uc_allocbucket,
+ &ub, sizeof(ub), 0);
+ if (ret != 0) {
+ free(ucp_array);
+ _memstat_mtl_empty(list);
+ list->mtl_error = ret;
+ return (-1);
+ }
+ mtp->mt_free += ub.ub_cnt;
+ }
+ if (ucp->uc_freebucket != NULL) {
+ ret = kread(kvm, ucp->uc_freebucket,
+ &ub, sizeof(ub), 0);
+ if (ret != 0) {
+ free(ucp_array);
+ _memstat_mtl_empty(list);
+ list->mtl_error = ret;
+ return (-1);
+ }
+ mtp->mt_free += ub.ub_cnt;
+ }
+ }
+skip_percpu:
+ mtp->mt_size = kz.uk_size;
+ mtp->mt_memalloced = mtp->mt_numallocs * mtp->mt_size;
+ mtp->mt_memfreed = mtp->mt_numfrees * mtp->mt_size;
+ mtp->mt_bytes = mtp->mt_memalloced - mtp->mt_memfreed;
+ if (kz.uk_ppera > 1)
+ mtp->mt_countlimit = kz.uk_maxpages /
+ kz.uk_ipers;
+ else
+ mtp->mt_countlimit = kz.uk_maxpages *
+ kz.uk_ipers;
+ mtp->mt_byteslimit = mtp->mt_countlimit * mtp->mt_size;
+ mtp->mt_count = mtp->mt_numallocs - mtp->mt_numfrees;
+ for (ubp = LIST_FIRST(&uz.uz_full_bucket); ubp !=
+ NULL; ubp = LIST_NEXT(&ub, ub_link)) {
+ ret = kread(kvm, ubp, &ub, sizeof(ub), 0);
+ mtp->mt_zonefree += ub.ub_cnt;
+ }
+ if (!((kz.uk_flags & UMA_ZONE_SECONDARY) &&
+ LIST_FIRST(&kz.uk_zones) != uzp)) {
+ mtp->mt_kegfree = kz.uk_free;
+ mtp->mt_free += mtp->mt_kegfree;
+ }
+ mtp->mt_free += mtp->mt_zonefree;
+ }
+ }
+ free(ucp_array);
+ return (0);
+}
diff --git a/lib/libmenu/Makefile b/lib/libmenu/Makefile
new file mode 100644
index 0000000..6e05739
--- /dev/null
+++ b/lib/libmenu/Makefile
@@ -0,0 +1,84 @@
+# Makefile for libmenu
+# $FreeBSD$
+
+NCURSES=${.CURDIR}/../../contrib/ncurses
+
+.PATH: ${NCURSES}/menu ${NCURSES}/include
+.PATH: ${NCURSES}/man
+
+LIB= menu
+DPADD= ${LIBNCURSES}
+LDADD= -lncurses
+AWK?= awk
+
+SRCS= ncurses_def.h \
+ m_attribs.c m_cursor.c m_driver.c m_format.c m_global.c m_hook.c \
+ m_item_cur.c m_item_nam.c m_item_new.c m_item_opt.c m_item_top.c \
+ m_item_use.c m_item_val.c m_item_vis.c m_items.c m_new.c m_opts.c \
+ m_pad.c m_pattern.c m_post.c m_req_name.c m_scale.c m_spacing.c \
+ m_sub.c m_userptr.c m_win.c
+INCS= ${NCURSES}/menu/menu.h ${NCURSES}/menu/eti.h
+
+CLEANFILES+= ncurses_def.h
+CFLAGS+= -I.
+.if exists(${.OBJDIR}/../libncurses)
+CFLAGS+= -I${.OBJDIR}/../libncurses
+.endif
+CFLAGS+=-I${.CURDIR}/../libncurses -I${NCURSES}/menu -I${NCURSES}/include \
+ -Wall -DNDEBUG -DHAVE_CONFIG_H
+
+ncurses_def.h: MKncurses_def.sh ncurses_defs
+ AWK=${AWK} sh ${NCURSES}/include/MKncurses_def.sh \
+ ${NCURSES}/include/ncurses_defs > ncurses_def.h
+
+MANx= menu.3x menu_attributes.3x menu_cursor.3x \
+ menu_driver.3x menu_format.3x menu_hook.3x menu_items.3x \
+ menu_mark.3x menu_new.3x menu_opts.3x menu_pattern.3x \
+ menu_post.3x menu_requestname.3x menu_spacing.3x \
+ menu_userptr.3x menu_win.3x mitem_current.3x mitem_name.3x \
+ mitem_new.3x mitem_opts.3x mitem_userptr.3x mitem_value.3x \
+ mitem_visible.3x
+
+# Generate the MAN list from MANx
+.for page in ${MANx}
+CLEANFILES+=${page:T:S/x$//g}
+MAN+=${page:T:S/x$//g}
+${page:T:S/x$//g}: ${page}
+ cat ${.ALLSRC} > ${.TARGET}
+.endfor
+
+MLINKS+=menu_attributes.3 menu_back.3 menu_attributes.3 menu_fore.3 \
+ menu_attributes.3 menu_grey.3 menu_attributes.3 menu_pad.3 \
+ menu_attributes.3 set_menu_back.3 menu_attributes.3 set_menu_fore.3 \
+ menu_attributes.3 set_menu_grey.3 menu_attributes.3 set_menu_pad.3
+MLINKS+=menu_cursor.3 pos_menu_cursor.3
+MLINKS+=menu_format.3 set_menu_format.3
+MLINKS+=menu_hook.3 item_init.3 menu_hook.3 item_term.3 \
+ menu_hook.3 menu_init.3 menu_hook.3 menu_term.3 \
+ menu_hook.3 set_item_init.3 menu_hook.3 set_item_term.3 \
+ menu_hook.3 set_menu_init.3 menu_hook.3 set_menu_term.3
+MLINKS+=menu_items.3 item_count.3 menu_items.3 set_menu_items.3
+MLINKS+=menu_mark.3 set_menu_mark.3
+MLINKS+=menu_new.3 free_menu.3 menu_new.3 new_menu.3
+MLINKS+=menu_opts.3 menu_opts_off.3 menu_opts.3 menu_opts_on.3
+MLINKS+=menu_pattern.3 set_menu_pattern.3
+MLINKS+=menu_post.3 post_menu.3 menu_post.3 unpost_menu.3
+MLINKS+=menu_requestname.3 menu_request_by_name.3 \
+ menu_requestname.3 menu_request_name.3
+MLINKS+=menu_spacing.3 set_menu_spacing.3
+MLINKS+=menu_userptr.3 set_menu_userptr.3
+MLINKS+=menu_win.3 menu_sub.3 menu_win.3 scale_menu.3 \
+ menu_win.3 set_menu_sub.3 menu_win.3 set_menu_win.3
+MLINKS+=mitem_current.3 current_item.3 mitem_current.3 item_index.3 \
+ mitem_current.3 set_top_row.3 mitem_current.3 top_row.3 \
+ mitem_current.3 set_current_item.3
+MLINKS+=mitem_name.3 item_description.3 mitem_name.3 item_name.3
+MLINKS+=mitem_new.3 free_item.3 mitem_new.3 new_item.3
+MLINKS+=mitem_opts.3 item_opts.3 mitem_opts.3 item_opts_off.3 \
+ mitem_opts.3 item_opts_on.3 mitem_opts.3 set_item_opts.3 \
+ mitem_opts.3 set_menu_opts.3
+MLINKS+=mitem_userptr.3 item_userptr.3 mitem_userptr.3 set_item_userptr.3
+MLINKS+=mitem_value.3 item_value.3 mitem_value.3 set_item_value.3
+MLINKS+=mitem_visible.3 item_visible.3
+
+.include <bsd.lib.mk>
diff --git a/lib/libmilter/Makefile b/lib/libmilter/Makefile
new file mode 100644
index 0000000..9ce6bcf
--- /dev/null
+++ b/lib/libmilter/Makefile
@@ -0,0 +1,32 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+SENDMAIL_DIR=${.CURDIR}/../../contrib/sendmail
+.PATH: ${SENDMAIL_DIR}/libmilter ${SENDMAIL_DIR}/libsm
+
+CFLAGS+=-I${SENDMAIL_DIR}/src -I${SENDMAIL_DIR}/include -I.
+CFLAGS+=-DNOT_SENDMAIL -Dsm_snprintf=snprintf
+CFLAGS+=-D_THREAD_SAFE
+
+.if ${MK_INET6_SUPPORT} != "no"
+CFLAGS+=-DNETINET6
+.endif
+
+# User customizations to the sendmail build environment
+CFLAGS+=${SENDMAIL_CFLAGS}
+
+INCSDIR=${INCLUDEDIR}/libmilter
+INCS= ${SENDMAIL_DIR}/include/libmilter/mfapi.h \
+ ${SENDMAIL_DIR}/include/libmilter/mfdef.h
+LIB= milter
+
+SRCS+= sm_os.h
+SRCS+= main.c engine.c listener.c handler.c comm.c smfi.c \
+ signal.c sm_gethost.c errstring.c strl.c
+CLEANFILES+=sm_os.h
+
+sm_os.h:
+ ln -sf ${SENDMAIL_DIR}/include/sm/os/sm_os_freebsd.h sm_os.h
+
+.include <bsd.lib.mk>
diff --git a/lib/libmp/Makefile b/lib/libmp/Makefile
new file mode 100644
index 0000000..e4454cf
--- /dev/null
+++ b/lib/libmp/Makefile
@@ -0,0 +1,14 @@
+# $FreeBSD$
+
+LIB= mp
+SHLIB_MAJOR= 5
+DPADD= ${LIBCRYPTO}
+LDADD= -lcrypto
+MAN= libmp.3
+INCS= mp.h
+SRCS= mpasbn.c
+
+WARNS?= 0
+CFLAGS+= -I${.CURDIR}/../../crypto
+
+.include <bsd.lib.mk>
diff --git a/lib/libmp/libmp.3 b/lib/libmp/libmp.3
new file mode 100644
index 0000000..9be21d7
--- /dev/null
+++ b/lib/libmp/libmp.3
@@ -0,0 +1,322 @@
+.\"
+.\" 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.
+.\"
+.\" This manual page is based on the mp(3X) manual page from Sun Release
+.\" 4.1, dated 7 September 1989. It's an old, crufty, and relatively ugly
+.\" manual page, but it does document what appears to be the "traditional"
+.\" libmp interface.
+.\"
+.\" $FreeBSD$
+.\"
+.\" See above for rationale for this date.
+.Dd September 7, 1989
+.Dt LIBMP 3
+.Os
+.Sh NAME
+.Nm libmp
+.Nd traditional BSD multiple precision integer arithmetic library
+.Sh SYNOPSIS
+.In mp.h
+.Pp
+Function prototypes are given in the main body of the text.
+.Pp
+Applications using this interface must be linked with
+.Fl l Ns Ar mp
+(this library)
+and
+.Fl l Ns Ar crypto
+.Pq Xr crypto 3 .
+.Sh DESCRIPTION
+.Bf -symbolic
+This interface is obsolete in favor of the
+.Xr crypto 3
+.Vt BIGNUM
+library.
+.Ef
+.Pp
+.Nm
+is the traditional
+.Bx
+multiple precision integer arithmetic library.
+It has a number of problems,
+and is unsuitable for use in any programs where reliability is a concern.
+It is provided here for compatibility only.
+.Pp
+These routines perform arithmetic on integers of arbitrary precision
+stored using the defined type
+.Vt MINT .
+Pointers to
+.Vt MINT
+are initialized using
+.Fn itom
+or
+.Fn xtom ,
+and must be recycled with
+.Fn mfree
+when they are no longer needed.
+Routines which store a result in one of their arguments expect that
+the latter has also been initialized prior to being passed to it.
+The following routines are defined and implemented:
+.Pp
+.Ft "MINT *" Ns
+.Fn itom "short n" ;
+.Pp
+.Ft "MINT *" Ns
+.Fn xtom "const char *s" ;
+.Pp
+.Ft "char *" Ns
+.Fn mtox "const MINT *mp" ;
+.Pp
+.Ft void
+.Fn mfree "MINT *mp" ;
+.Bd -ragged -offset indent
+.Fn itom
+returns an
+.Vt MINT
+with the value of
+.Fa n .
+.Fn xtom
+returns an
+.Vt MINT
+with the value of
+.Fa s ,
+which is treated to be in hexadecimal.
+The return values from
+.Fn itom
+and
+.Fn xtom
+must be released with
+.Fn mfree
+when they are no longer needed.
+.Fn mtox
+returns a null-terminated hexadecimal string having the value of
+.Fa mp ;
+its return value must be released with
+.Fn free
+.Pq Xr free 3
+when it is no longer needed.
+.Ed
+.Pp
+.Ft void
+.Fn madd "const MINT *mp1" "const MINT *mp2" "MINT *rmp" ;
+.Pp
+.Ft void
+.Fn msub "const MINT *mp1" "const MINT *mp2" "MINT *rmp" ;
+.Pp
+.Ft void
+.Fn mult "const MINT *mp1" "const MINT *mp2" "MINT *rmp" ;
+.Bd -ragged -offset indent
+.Fn madd ,
+.Fn msub ,
+and
+.Fn mult
+store the sum, difference, or product, respectively, of
+.Fa mp1
+and
+.Fa mp2
+in
+.Fa rmp .
+.Ed
+.Pp
+.Ft void
+.Fn mdiv "const MINT *nmp" "const MINT *dmp" "MINT *qmp" "MINT *rmp" ;
+.Pp
+.Ft void
+.Fn sdiv "const MINT *nmp" "short d" "MINT *qmp" "short *ro" ;
+.Bd -ragged -offset indent
+.Fn mdiv
+computes the quotient and remainder of
+.Fa nmp
+and
+.Fa dmp
+and stores the result in
+.Fa qmp
+and
+.Fa rmp ,
+respectively.
+.Fn sdiv
+is similar to
+.Fn mdiv
+except the divisor
+.Fa ( dmp
+or
+.Fa d )
+and remainder
+.Fa ( rmp
+or
+.Fa ro )
+are ordinary integers.
+.Ed
+.Pp
+.Ft void
+.Fn pow "const MINT *bmp" "const MINT *emp" "const MINT *mmp" "MINT *rmp" ;
+.Pp
+.Ft void
+.Fn rpow "const MINT *bmp" "short e" "MINT *rmp" ;
+.Bd -ragged -offset indent
+.Fn rpow
+computes the result of
+.Fa bmp
+raised to the
+.Fa emp Ns th
+power and reduced modulo
+.Fa mmp ;
+the result is stored in
+.Fa rmp .
+.Fn pow
+computes the result of
+.Fa bmp
+raised to the
+.Fa e Ns th
+power and stores the result in
+.Fa rmp .
+.Ed
+.Pp
+.Ft void
+.Fn min "MINT *mp" ;
+.Pp
+.Ft void
+.Fn mout "const MINT *mp" ;
+.Bd -ragged -offset indent
+.Fn min
+reads a line from standard input, tries to interpret it as a decimal
+number, and if successful, stores the result in
+.Fa mp .
+.Fn mout
+prints the value, in decimal, of
+.Fa mp
+to standard output (without a trailing newline).
+.Ed
+.Pp
+.Ft void
+.Fn gcd "const MINT *mp1" "const MINT *mp2" "MINT *rmp" ;
+.Bd -ragged -offset indent
+.Fn gcd
+computes the greatest common divisor of
+.Fa mp1
+and
+.Fa mp2
+and stores the result in
+.Fa rmp .
+.Ed
+.Pp
+.Ft int
+.Fn mcmp "const MINT *mp1" "const MINT *mp2" ;
+.Bd -ragged -offset indent
+.Fa mcmp
+compares the values of
+.Fa mp1
+and
+.Fa mp2
+and returns
+0 if the two values are equal,
+a value greater than 0 if
+.Fa mp1
+is greater than
+.Fa mp2 ,
+and a value less than 0 if
+.Fa mp2
+is greater than
+.Fa mp1 .
+.Ed
+.Pp
+.Ft void
+.Fn move "const MINT *smp" "MINT *tmp" ;
+.Bd -ragged -offset indent
+.Fn move
+copies the value of
+.Fa smp
+to
+.Fa tmp
+(both values must be initialized).
+.Ed
+.Pp
+.Ft void
+.Fn msqrt "const MINT *nmp" "MINT *xmp" "MINT *rmp" ;
+.Bd -ragged -offset indent
+.Fn msqrt
+computes the square root and remainder of
+.Fa nmp
+and stores them in
+.Fa xmp
+and
+.Fa rmp ,
+respectively.
+.Ed
+.Sh IMPLEMENTATION NOTES
+This version of
+.Nm
+is implemented in terms of the
+.Xr crypto 3
+.Vt BIGNUM
+library.
+.Sh DIAGNOSTICS
+Running out of memory or illegal operations result in error messages
+on standard error and a call to
+.Xr abort 3 .
+.Sh SEE ALSO
+.Xr abort 3 ,
+.Xr bn 3 ,
+.Xr crypto 3 ,
+.Xr free 3 ,
+.Xr malloc 3 ,
+.Xr math 3
+.Sh HISTORY
+A
+.Nm
+library appeared in
+.Bx 4.3 .
+.Fx 2.2
+shipped with a
+.Nm
+implemented in terms of
+.Nm libgmp .
+This implementation appeared in
+.Fx 5.0 .
+.Sh BUGS
+The
+.Fn pow
+routine exists in both
+.Nm libmp
+and
+.Nm libm
+with incompatible semantics.
+.Pp
+Errors are reported via output to standard error and abnormal
+program termination instead of via return values.
+The application cannot control this behavior.
+.Pp
+It is not clear whether the string returned by
+.Fn mtox
+may be written to by the caller.
+This implementation allows it, but others may not.
+Ideally,
+.Fn mtox
+would take a pointer to a buffer to fill in.
+.Pp
+It is not clear whether using the same variable as both source and
+destination in a single invocation is permitted.
+Some of the calls in this implementation allow this, while others
+do not.
diff --git a/lib/libmp/mp.h b/lib/libmp/mp.h
new file mode 100644
index 0000000..4c2c94d
--- /dev/null
+++ b/lib/libmp/mp.h
@@ -0,0 +1,32 @@
+/* $FreeBSD$ */
+
+#ifndef _MP_H_
+#define _MP_H_
+
+#ifndef HEADER_BN_H_
+#include <openssl/bn.h>
+#endif
+
+typedef struct _mint {
+ BIGNUM *bn;
+} MINT;
+
+void gcd(const MINT *, const MINT *, MINT *);
+MINT *itom(short);
+void madd(const MINT *, const MINT *, MINT *);
+int mcmp(const MINT *, const MINT *);
+void mdiv(const MINT *, const MINT *, MINT *, MINT *);
+void mfree(MINT *);
+void min(MINT *);
+void mout(const MINT *);
+void move(const MINT *, MINT *);
+void msqrt(const MINT *, MINT *, MINT *);
+void msub(const MINT *, const MINT *, MINT *);
+char *mtox(const MINT *);
+void mult(const MINT *, const MINT *, MINT *);
+void pow(const MINT *, const MINT *, const MINT *, MINT *);
+void rpow(const MINT *, short, MINT *);
+void sdiv(const MINT *, short, MINT *, short *);
+MINT *xtom(const char *);
+
+#endif /* !_MP_H_ */
diff --git a/lib/libmp/mpasbn.c b/lib/libmp/mpasbn.c
new file mode 100644
index 0000000..726e2f1
--- /dev/null
+++ b/lib/libmp/mpasbn.c
@@ -0,0 +1,590 @@
+/*
+ * 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.
+ */
+
+/*
+ * This is the traditional Berkeley MP library implemented in terms of
+ * the OpenSSL BIGNUM library. It was written to replace libgmp, and
+ * is meant to be as compatible with the latter as feasible.
+ *
+ * There seems to be a lack of documentation for the Berkeley MP
+ * interface. All I could find was libgmp documentation (which didn't
+ * talk about the semantics of the functions) and an old SunOS 4.1
+ * manual page from 1989. The latter wasn't very detailed, either,
+ * but at least described what the function's arguments were. In
+ * general the interface seems to be archaic, somewhat poorly
+ * designed, and poorly, if at all, documented. It is considered
+ * harmful.
+ *
+ * Miscellaneous notes on this implementation:
+ *
+ * - The SunOS manual page mentioned above indicates that if an error
+ * occurs, the library should "produce messages and core images."
+ * Given that most of the functions don't have return values (and
+ * thus no sane way of alerting the caller to an error), this seems
+ * reasonable. The MPERR and MPERRX macros call warn and warnx,
+ * respectively, then abort().
+ *
+ * - All the functions which take an argument to be "filled in"
+ * assume that the argument has been initialized by one of the *tom()
+ * routines before being passed to it. I never saw this documented
+ * anywhere, but this seems to be consistent with the way this
+ * library is used.
+ *
+ * - msqrt() is the only routine which had to be implemented which
+ * doesn't have a close counterpart in the OpenSSL BIGNUM library.
+ * It was implemented by hand using Newton's recursive formula.
+ * Doing it this way, although more error-prone, has the positive
+ * sideaffect of testing a lot of other functions; if msqrt()
+ * produces the correct results, most of the other routines will as
+ * well.
+ *
+ * - Internal-use-only routines (i.e., those defined here statically
+ * and not in mp.h) have an underscore prepended to their name (this
+ * is more for aesthetical reasons than technical). All such
+ * routines take an extra argument, 'msg', that denotes what they
+ * should call themselves in an error message. This is so a user
+ * doesn't get an error message from a function they didn't call.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <openssl/crypto.h>
+#include <openssl/err.h>
+
+#include "openssl/crypto/bn/bn_lcl.h"
+#include "mp.h"
+
+#define MPERR(s) do { warn s; abort(); } while (0)
+#define MPERRX(s) do { warnx s; abort(); } while (0)
+#define BN_ERRCHECK(msg, expr) do { \
+ if (!(expr)) _bnerr(msg); \
+} while (0)
+
+static void _bnerr(const char *);
+static MINT *_dtom(const char *, const char *);
+static MINT *_itom(const char *, short);
+static void _madd(const char *, const MINT *, const MINT *, MINT *);
+static int _mcmpa(const char *, const MINT *, const MINT *);
+static void _mdiv(const char *, const MINT *, const MINT *, MINT *, MINT *);
+static void _mfree(const char *, MINT *);
+static void _moveb(const char *, const BIGNUM *, MINT *);
+static void _movem(const char *, const MINT *, MINT *);
+static void _msub(const char *, const MINT *, const MINT *, MINT *);
+static char *_mtod(const char *, const MINT *);
+static char *_mtox(const char *, const MINT *);
+static void _mult(const char *, const MINT *, const MINT *, MINT *);
+static void _sdiv(const char *, const MINT *, short, MINT *, short *);
+static MINT *_xtom(const char *, const char *);
+
+/*
+ * Report an error from one of the BN_* functions using MPERRX.
+ */
+static void
+_bnerr(const char *msg)
+{
+
+ ERR_load_crypto_strings();
+ MPERRX(("%s: %s", msg, ERR_reason_error_string(ERR_get_error())));
+}
+
+/*
+ * Convert a decimal string to an MINT.
+ */
+static MINT *
+_dtom(const char *msg, const char *s)
+{
+ MINT *mp;
+
+ mp = malloc(sizeof(*mp));
+ if (mp == NULL)
+ MPERR(("%s", msg));
+ mp->bn = BN_new();
+ if (mp->bn == NULL)
+ _bnerr(msg);
+ BN_ERRCHECK(msg, BN_dec2bn(&mp->bn, s));
+ return (mp);
+}
+
+/*
+ * Compute the greatest common divisor of mp1 and mp2; result goes in rmp.
+ */
+void
+gcd(const MINT *mp1, const MINT *mp2, MINT *rmp)
+{
+ BIGNUM b;
+ BN_CTX c;
+
+ BN_CTX_init(&c);
+ BN_init(&b);
+ BN_ERRCHECK("gcd", BN_gcd(&b, mp1->bn, mp2->bn, &c));
+ _moveb("gcd", &b, rmp);
+ BN_free(&b);
+ BN_CTX_free(&c);
+}
+
+/*
+ * Make an MINT out of a short integer. Return value must be mfree()'d.
+ */
+static MINT *
+_itom(const char *msg, short n)
+{
+ MINT *mp;
+ char *s;
+
+ asprintf(&s, "%x", n);
+ if (s == NULL)
+ MPERR(("%s", msg));
+ mp = _xtom(msg, s);
+ free(s);
+ return (mp);
+}
+
+MINT *
+itom(short n)
+{
+
+ return (_itom("itom", n));
+}
+
+/*
+ * Compute rmp=mp1+mp2.
+ */
+static void
+_madd(const char *msg, const MINT *mp1, const MINT *mp2, MINT *rmp)
+{
+ BIGNUM b;
+
+ BN_init(&b);
+ BN_ERRCHECK(msg, BN_add(&b, mp1->bn, mp2->bn));
+ _moveb(msg, &b, rmp);
+ BN_free(&b);
+}
+
+void
+madd(const MINT *mp1, const MINT *mp2, MINT *rmp)
+{
+
+ _madd("madd", mp1, mp2, rmp);
+}
+
+/*
+ * Return -1, 0, or 1 if mp1<mp2, mp1==mp2, or mp1>mp2, respectivley.
+ */
+int
+mcmp(const MINT *mp1, const MINT *mp2)
+{
+
+ return (BN_cmp(mp1->bn, mp2->bn));
+}
+
+/*
+ * Same as mcmp but compares absolute values.
+ */
+static int
+_mcmpa(const char *msg __unused, const MINT *mp1, const MINT *mp2)
+{
+
+ return (BN_ucmp(mp1->bn, mp2->bn));
+}
+
+/*
+ * Compute qmp=nmp/dmp and rmp=nmp%dmp.
+ */
+static void
+_mdiv(const char *msg, const MINT *nmp, const MINT *dmp, MINT *qmp, MINT *rmp)
+{
+ BIGNUM q, r;
+ BN_CTX c;
+
+ BN_CTX_init(&c);
+ BN_init(&r);
+ BN_init(&q);
+ BN_ERRCHECK(msg, BN_div(&q, &r, nmp->bn, dmp->bn, &c));
+ _moveb(msg, &q, qmp);
+ _moveb(msg, &r, rmp);
+ BN_free(&q);
+ BN_free(&r);
+ BN_CTX_free(&c);
+}
+
+void
+mdiv(const MINT *nmp, const MINT *dmp, MINT *qmp, MINT *rmp)
+{
+
+ _mdiv("mdiv", nmp, dmp, qmp, rmp);
+}
+
+/*
+ * Free memory associated with an MINT.
+ */
+static void
+_mfree(const char *msg __unused, MINT *mp)
+{
+
+ BN_clear(mp->bn);
+ BN_free(mp->bn);
+ free(mp);
+}
+
+void
+mfree(MINT *mp)
+{
+
+ _mfree("mfree", mp);
+}
+
+/*
+ * Read an integer from standard input and stick the result in mp.
+ * The input is treated to be in base 10. This must be the silliest
+ * API in existence; why can't the program read in a string and call
+ * xtom()? (Or if base 10 is desires, perhaps dtom() could be
+ * exported.)
+ */
+void
+min(MINT *mp)
+{
+ MINT *rmp;
+ char *line, *nline;
+ size_t linelen;
+
+ line = fgetln(stdin, &linelen);
+ if (line == NULL)
+ MPERR(("min"));
+ nline = malloc(linelen);
+ if (nline == NULL)
+ MPERR(("min"));
+ strncpy(nline, line, linelen);
+ nline[linelen] = '\0';
+ rmp = _dtom("min", nline);
+ _movem("min", rmp, mp);
+ _mfree("min", rmp);
+ free(nline);
+}
+
+/*
+ * Print the value of mp to standard output in base 10. See blurb
+ * above min() for why this is so useless.
+ */
+void
+mout(const MINT *mp)
+{
+ char *s;
+
+ s = _mtod("mout", mp);
+ printf("%s", s);
+ free(s);
+}
+
+/*
+ * Set the value of tmp to the value of smp (i.e., tmp=smp).
+ */
+void
+move(const MINT *smp, MINT *tmp)
+{
+
+ _movem("move", smp, tmp);
+}
+
+
+/*
+ * Internal routine to set the value of tmp to that of sbp.
+ */
+static void
+_moveb(const char *msg, const BIGNUM *sbp, MINT *tmp)
+{
+
+ BN_ERRCHECK(msg, BN_copy(tmp->bn, sbp));
+}
+
+/*
+ * Internal routine to set the value of tmp to that of smp.
+ */
+static void
+_movem(const char *msg, const MINT *smp, MINT *tmp)
+{
+
+ BN_ERRCHECK(msg, BN_copy(tmp->bn, smp->bn));
+}
+
+/*
+ * Compute the square root of nmp and put the result in xmp. The
+ * remainder goes in rmp. Should satisfy: rmp=nmp-(xmp*xmp).
+ *
+ * Note that the OpenSSL BIGNUM library does not have a square root
+ * function, so this had to be implemented by hand using Newton's
+ * recursive formula:
+ *
+ * x = (x + (n / x)) / 2
+ *
+ * where x is the square root of the positive number n. In the
+ * beginning, x should be a reasonable guess, but the value 1,
+ * although suboptimal, works, too; this is that is used below.
+ */
+void
+msqrt(const MINT *nmp, MINT *xmp, MINT *rmp)
+{
+ MINT *tolerance;
+ MINT *ox, *x;
+ MINT *z1, *z2, *z3;
+ short i;
+
+ tolerance = _itom("msqrt", 1);
+ x = _itom("msqrt", 1);
+ ox = _itom("msqrt", 0);
+ z1 = _itom("msqrt", 0);
+ z2 = _itom("msqrt", 0);
+ z3 = _itom("msqrt", 0);
+ do {
+ _movem("msqrt", x, ox);
+ _mdiv("msqrt", nmp, x, z1, z2);
+ _madd("msqrt", x, z1, z2);
+ _sdiv("msqrt", z2, 2, x, &i);
+ _msub("msqrt", ox, x, z3);
+ } while (_mcmpa("msqrt", z3, tolerance) == 1);
+ _movem("msqrt", x, xmp);
+ _mult("msqrt", x, x, z1);
+ _msub("msqrt", nmp, z1, z2);
+ _movem("msqrt", z2, rmp);
+ _mfree("msqrt", tolerance);
+ _mfree("msqrt", ox);
+ _mfree("msqrt", x);
+ _mfree("msqrt", z1);
+ _mfree("msqrt", z2);
+ _mfree("msqrt", z3);
+}
+
+/*
+ * Compute rmp=mp1-mp2.
+ */
+static void
+_msub(const char *msg, const MINT *mp1, const MINT *mp2, MINT *rmp)
+{
+ BIGNUM b;
+
+ BN_init(&b);
+ BN_ERRCHECK(msg, BN_sub(&b, mp1->bn, mp2->bn));
+ _moveb(msg, &b, rmp);
+ BN_free(&b);
+}
+
+void
+msub(const MINT *mp1, const MINT *mp2, MINT *rmp)
+{
+
+ _msub("msub", mp1, mp2, rmp);
+}
+
+/*
+ * Return a decimal representation of mp. Return value must be
+ * free()'d.
+ */
+static char *
+_mtod(const char *msg, const MINT *mp)
+{
+ char *s, *s2;
+
+ s = BN_bn2dec(mp->bn);
+ if (s == NULL)
+ _bnerr(msg);
+ asprintf(&s2, "%s", s);
+ if (s2 == NULL)
+ MPERR(("%s", msg));
+ OPENSSL_free(s);
+ return (s2);
+}
+
+/*
+ * Return a hexadecimal representation of mp. Return value must be
+ * free()'d.
+ */
+static char *
+_mtox(const char *msg, const MINT *mp)
+{
+ char *p, *s, *s2;
+ int len;
+
+ s = BN_bn2hex(mp->bn);
+ if (s == NULL)
+ _bnerr(msg);
+ asprintf(&s2, "%s", s);
+ if (s2 == NULL)
+ MPERR(("%s", msg));
+ OPENSSL_free(s);
+
+ /*
+ * This is a kludge for libgmp compatibility. The latter's
+ * implementation of this function returns lower-case letters,
+ * but BN_bn2hex returns upper-case. Some programs (e.g.,
+ * newkey(1)) are sensitive to this. Although it's probably
+ * their fault, it's nice to be compatible.
+ */
+ len = strlen(s2);
+ for (p = s2; p < s2 + len; p++)
+ *p = tolower(*p);
+
+ return (s2);
+}
+
+char *
+mtox(const MINT *mp)
+{
+
+ return (_mtox("mtox", mp));
+}
+
+/*
+ * Compute rmp=mp1*mp2.
+ */
+static void
+_mult(const char *msg, const MINT *mp1, const MINT *mp2, MINT *rmp)
+{
+ BIGNUM b;
+ BN_CTX c;
+
+ BN_CTX_init(&c);
+ BN_init(&b);
+ BN_ERRCHECK(msg, BN_mul(&b, mp1->bn, mp2->bn, &c));
+ _moveb(msg, &b, rmp);
+ BN_free(&b);
+ BN_CTX_free(&c);
+}
+
+void
+mult(const MINT *mp1, const MINT *mp2, MINT *rmp)
+{
+
+ _mult("mult", mp1, mp2, rmp);
+}
+
+/*
+ * Compute rmp=(bmp^emp)mod mmp. (Note that here and above rpow() '^'
+ * means 'raise to power', not 'bitwise XOR'.)
+ */
+void
+pow(const MINT *bmp, const MINT *emp, const MINT *mmp, MINT *rmp)
+{
+ BIGNUM b;
+ BN_CTX c;
+
+ BN_CTX_init(&c);
+ BN_init(&b);
+ BN_ERRCHECK("pow", BN_mod_exp(&b, bmp->bn, emp->bn, mmp->bn, &c));
+ _moveb("pow", &b, rmp);
+ BN_free(&b);
+ BN_CTX_free(&c);
+}
+
+/*
+ * Compute rmp=bmp^e. (See note above pow().)
+ */
+void
+rpow(const MINT *bmp, short e, MINT *rmp)
+{
+ MINT *emp;
+ BIGNUM b;
+ BN_CTX c;
+
+ BN_CTX_init(&c);
+ BN_init(&b);
+ emp = _itom("rpow", e);
+ BN_ERRCHECK("rpow", BN_exp(&b, bmp->bn, emp->bn, &c));
+ _moveb("rpow", &b, rmp);
+ _mfree("rpow", emp);
+ BN_free(&b);
+ BN_CTX_free(&c);
+}
+
+/*
+ * Compute qmp=nmp/d and ro=nmp%d.
+ */
+static void
+_sdiv(const char *msg, const MINT *nmp, short d, MINT *qmp, short *ro)
+{
+ MINT *dmp, *rmp;
+ BIGNUM q, r;
+ BN_CTX c;
+ char *s;
+
+ BN_CTX_init(&c);
+ BN_init(&q);
+ BN_init(&r);
+ dmp = _itom(msg, d);
+ rmp = _itom(msg, 0);
+ BN_ERRCHECK(msg, BN_div(&q, &r, nmp->bn, dmp->bn, &c));
+ _moveb(msg, &q, qmp);
+ _moveb(msg, &r, rmp);
+ s = _mtox(msg, rmp);
+ errno = 0;
+ *ro = strtol(s, NULL, 16);
+ if (errno != 0)
+ MPERR(("%s underflow or overflow", msg));
+ free(s);
+ _mfree(msg, dmp);
+ _mfree(msg, rmp);
+ BN_free(&r);
+ BN_free(&q);
+ BN_CTX_free(&c);
+}
+
+void
+sdiv(const MINT *nmp, short d, MINT *qmp, short *ro)
+{
+
+ _sdiv("sdiv", nmp, d, qmp, ro);
+}
+
+/*
+ * Convert a hexadecimal string to an MINT.
+ */
+static MINT *
+_xtom(const char *msg, const char *s)
+{
+ MINT *mp;
+
+ mp = malloc(sizeof(*mp));
+ if (mp == NULL)
+ MPERR(("%s", msg));
+ mp->bn = BN_new();
+ if (mp->bn == NULL)
+ _bnerr(msg);
+ BN_ERRCHECK(msg, BN_hex2bn(&mp->bn, s));
+ return (mp);
+}
+
+MINT *
+xtom(const char *s)
+{
+
+ return (_xtom("xtom", s));
+}
diff --git a/lib/libncp/CREDITS b/lib/libncp/CREDITS
new file mode 100644
index 0000000..4338055
--- /dev/null
+++ b/lib/libncp/CREDITS
@@ -0,0 +1,27 @@
+# $FreeBSD$
+
+In the development of NetWare client for FreeBSD next sources was used:
+
+ncpfs for Linux - written by Volker Lendecke (lendecke@math.uni-goettingen.de),
+ thanks to him for giving a permission to publish his code under BSD-style
+ license.
+
+"Interrupt List" from Ralf Brown,
+
+Many files from the /sys directory.
+
+NDK documentation from Novell Inc.
+
+
+Also thanks to thouse who gets time to testing, reporting problems and give
+a good suggestions (in alphabet order):
+
+Anatoly A. Orehovsky
+Andrew Petrenko
+Jesus Rodriguez
+Matthew N. Dodd
+Mike Pitt
+Vadim Mikhailov
+
+
+Author - Boris Popov <bp@butya.kz>, <bp@freebsd.org>
diff --git a/lib/libncp/Makefile b/lib/libncp/Makefile
new file mode 100644
index 0000000..b62fecc
--- /dev/null
+++ b/lib/libncp/Makefile
@@ -0,0 +1,14 @@
+# $FreeBSD$
+
+LIB= ncp
+
+SHLIB_MAJOR= 2
+
+DPADD= ${LIBIPX}
+LDADD= -lipx
+
+SRCS= ncpl_subr.c ncpl_bind.c ncpl_queue.c ncpl_file.c ncpl_misc.c \
+ ncpl_net.c ncpl_rcfile.c ncpl_conn.c ncpl_nls.c ncpl_msg.c \
+ ncpl_rpc.c ncpl_crypt.c ipx.c sap.c
+
+.include <bsd.lib.mk>
diff --git a/lib/libncp/ipx.c b/lib/libncp/ipx.c
new file mode 100644
index 0000000..9371fdd
--- /dev/null
+++ b/lib/libncp/ipx.c
@@ -0,0 +1,355 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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 Boris Popov.
+ * 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 THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 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/ioctl.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/route.h>
+
+/* IPX */
+#include <netipx/ipx.h>
+#include <netipx/ipx_if.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <netncp/ncp_lib.h>
+
+#define IPX_NODE_LEN 6
+
+typedef u_long IPXNet;
+typedef u_short IPXPort;
+typedef union ipx_host IPXNode;
+
+
+void
+ipx_fprint_node(FILE * file, IPXNode node){
+ fprintf(file, "%02X%02X%02X%02X%02X%02X",
+ (unsigned char) node.c_host[0],
+ (unsigned char) node.c_host[1],
+ (unsigned char) node.c_host[2],
+ (unsigned char) node.c_host[3],
+ (unsigned char) node.c_host[4],
+ (unsigned char) node.c_host[5]
+ );
+}
+
+void
+ipx_fprint_network(FILE * file, const IPXNet net){
+ fprintf(file, "%08X", (u_int32_t)ntohl(net));
+}
+
+void
+ipx_fprint_port(FILE * file, IPXPort port)
+{
+ fprintf(file, "%04X", ntohs(port));
+}
+
+void
+ipx_fprint_addr(FILE * file, struct ipx_addr *ipx)
+{
+ ipx_fprint_network(file, ipx_netlong(*ipx));
+ fprintf(file, ":");
+ ipx_fprint_node(file, ipx->x_host);
+ fprintf(file, ":");
+ ipx_fprint_port(file, ipx->x_port);
+}
+
+void
+ipx_print_node(IPXNode node)
+{
+ ipx_fprint_node(stdout, node);
+}
+
+void
+ipx_print_network(IPXNet net)
+{
+ ipx_fprint_network(stdout, net);
+}
+
+void
+ipx_print_port(IPXPort port)
+{
+ ipx_fprint_port(stdout, port);
+}
+
+void
+ipx_print_addr(struct ipx_addr *ipx)
+{
+ ipx_fprint_addr(stdout, ipx);
+}
+
+int
+ipx_sscanf_node(char *buf, unsigned char node[6])
+{
+ int i;
+ int n[6];
+
+ if ((i = sscanf(buf, "%2x%2x%2x%2x%2x%2x",
+ &(n[0]), &(n[1]), &(n[2]),
+ &(n[3]), &(n[4]), &(n[5]))) != 6)
+ {
+ return i;
+ }
+ for (i = 0; i < 6; i++)
+ {
+ node[i] = n[i];
+ }
+ return 6;
+}
+
+int
+ipx_sscanf_saddr(char *buf, struct sockaddr_ipx *target)
+{
+ char *p;
+ struct sockaddr_ipx addr;
+ unsigned long sipx_net;
+
+ addr.sipx_family = AF_IPX;
+/*!! addr.sipx_type = NCP_PTYPE;*/
+
+ if (sscanf(buf, "%lx", &sipx_net) != 1)
+ {
+ return 1;
+ }
+ ((union ipx_net_u*)(&addr.sipx_addr.x_net))->long_e = htonl(sipx_net);
+ if ((p = strchr(buf, ':')) == NULL){
+ return 1;
+ }
+ p += 1;
+ if (ipx_sscanf_node(p, addr.sipx_node) != 6)
+ {
+ return 1;
+ }
+ if ((p = strchr(p, ':')) == NULL)
+ {
+ return 1;
+ }
+ p += 1;
+ if (sscanf(p, "%hx", &addr.sipx_port) != 1)
+ {
+ return 1;
+ }
+ addr.sipx_port = htons(addr.sipx_port);
+ *target = addr;
+ return 0;
+}
+
+
+void ipx_assign_node(IPXNode *dest, IPXNode *src) {
+ memcpy(dest, src, IPX_NODE_LEN);
+}
+
+
+static void rt_xaddrs(caddr_t, caddr_t, struct rt_addrinfo *);
+static int if_ipxscan(int addrcount, struct sockaddr_dl *sdl,
+ struct if_msghdr *ifm, struct ifa_msghdr *ifam,
+ struct ipx_addr *addr);
+
+/*
+ * Find an IPX interface.
+ * ifname specifies interface name, if NULL search for all interfaces
+ * if ifname[0]='0', also all interfaces, but return its name
+ * addr on input preferred net address can be specified or 0 for any,
+ * on return contains full address (except port)
+ * returns 0 if interface was found
+ */
+int
+ipx_iffind(char *ifname,struct ipx_addr *addr){
+ char name[32];
+ int all=0, flags, foundit = 0, addrcount;
+ struct if_msghdr *ifm, *nextifm;
+ struct ifa_msghdr *ifam;
+ struct sockaddr_dl *sdl;
+ char *buf, *lim, *next;
+ size_t needed;
+ int mib[6];
+
+ if( ifname!=NULL ) {
+ strncpy(name,ifname,sizeof(name)-1);
+ if( name[0]==0 )
+ all=1;
+ } else
+ all = 1;
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0;
+ mib[3] = AF_IPX;
+ mib[4] = NET_RT_IFLIST;
+ mib[5] = 0;
+
+ 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) {
+ free(buf);
+ return(1);
+ }
+ lim = buf + needed;
+
+ next = buf;
+ while (next < lim) {
+ ifm = (struct if_msghdr *)next;
+ if (ifm->ifm_type == RTM_IFINFO) {
+ sdl = (struct sockaddr_dl *)(ifm + 1);
+ flags = ifm->ifm_flags;
+ } else {
+ fprintf(stderr, "if_ipxfind: out of sync parsing NET_RT_IFLIST\n");
+ fprintf(stderr, "expected %d, got %d\n", RTM_IFINFO, ifm->ifm_type);
+ fprintf(stderr, "msglen = %d\n", ifm->ifm_msglen);
+ fprintf(stderr, "buf:%p, next:%p, lim:%p\n", buf, next, lim);
+ free(buf);
+ return(1);
+ }
+
+ next += ifm->ifm_msglen;
+ ifam = NULL;
+ addrcount = 0;
+ while (next < lim) {
+ nextifm = (struct if_msghdr *)next;
+ if (nextifm->ifm_type != RTM_NEWADDR)
+ break;
+ if (ifam == NULL)
+ ifam = (struct ifa_msghdr *)nextifm;
+ addrcount++;
+ next += nextifm->ifm_msglen;
+ }
+
+ if (all) {
+ if ((flags & IFF_UP) == 0)
+ continue; /* not up */
+ strncpy(name, sdl->sdl_data, sdl->sdl_nlen);
+ name[sdl->sdl_nlen] = '\0';
+ } else {
+ if (strlen(name) != sdl->sdl_nlen)
+ continue; /* not same len */
+ if (strncmp(name, sdl->sdl_data, sdl->sdl_nlen) != 0)
+ continue; /* not same name */
+ }
+
+ foundit=if_ipxscan(addrcount, sdl, ifm, ifam, addr);
+ if( foundit ) {
+ if( ifname!=NULL && ifname[0]==0) {
+ strncpy(ifname,sdl->sdl_data, sdl->sdl_nlen);
+ ifname[sdl->sdl_nlen]=0;
+ }
+ break;
+ }
+ }
+ free(buf);
+
+ return foundit ? 0:1;
+}
+
+
+int
+if_ipxscan(addrcount, sdl, ifm, ifam, addr)
+ int addrcount;
+ struct sockaddr_dl *sdl;
+ struct if_msghdr *ifm;
+ struct ifa_msghdr *ifam;
+ struct ipx_addr *addr;
+{
+ struct rt_addrinfo info;
+ struct sockaddr_ipx *sipx;
+ int s;
+
+ if ((s = socket(AF_IPX, SOCK_DGRAM, 0)) < 0) {
+ perror("ifconfig: socket");
+ return 0;
+ }
+
+ while (addrcount > 0) {
+ info.rti_addrs = ifam->ifam_addrs;
+ /* Expand the compacted addresses */
+ rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam, &info);
+ addrcount--;
+ ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen);
+ if (info.rti_info[RTAX_IFA]->sa_family == AF_IPX) {
+ sipx = (struct sockaddr_ipx *)info.rti_info[RTAX_IFA];
+ if( ipx_nullnet(sipx->sipx_addr) ) continue;
+ if( ipx_nullnet(*addr) ||
+ ipx_neteq(sipx->sipx_addr,*addr) ) {
+ *addr=sipx->sipx_addr;
+ close(s);
+ return(1);
+ }
+ }
+ }
+ close(s);
+ return(0);
+}
+/*
+ * Expand the compacted form of addresses as returned via the
+ * configuration read via sysctl().
+ */
+
+#define ROUNDUP(a) \
+ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
+#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
+
+static void
+rt_xaddrs(cp, cplim, rtinfo)
+ caddr_t cp, cplim;
+ struct rt_addrinfo *rtinfo;
+{
+ struct sockaddr *sa;
+ int i;
+
+ memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info));
+ for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
+ if ((rtinfo->rti_addrs & (1 << i)) == 0)
+ continue;
+ rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
+ ADVANCE(cp, sa);
+ }
+}
+
diff --git a/lib/libncp/ipxsap.h b/lib/libncp/ipxsap.h
new file mode 100644
index 0000000..2d8d7f0
--- /dev/null
+++ b/lib/libncp/ipxsap.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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 Boris Popov.
+ * 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 THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 _IPXSAP_H_
+#define _IPXSAP_H_
+
+#define IPX_SAP_GENERAL_QUERY 1
+#define IPX_SAP_GENERAL_RESPONSE 2
+#define IPX_SAP_NEAREST_QUERY 3
+#define IPX_SAP_NEAREST_RESPONSE 4
+
+
+#define IPX_SAP_MAX_ENTRIES 7
+#define IPX_SAP_SERVER_DOWN 16
+#define IPX_SAP_SERVER_NAME_LEN 48
+#define IPX_SAP_REQUEST_LEN 4
+
+/* Values for server_type */
+#define IPX_SAP_FILE_SERVER 4
+
+struct sap_query {
+ u_short query_type; /* net order */
+ u_short server_type; /* net order */
+};
+
+struct sap_entry {
+ u_short server_type;
+ u_char server_name[IPX_SAP_SERVER_NAME_LEN];
+ struct ipx_addr ipx;
+ u_short hops;
+};
+
+struct sap_packet {
+ u_short operation;
+ struct sap_entry sap_entries[1];
+};
+
+struct sap_rq {
+ struct sockaddr_ipx dest_addr;
+ int sock;
+ int entries;
+ struct sap_packet* buffer;
+};
+/*
+#define sap_name_equal(n1,n2) (strncmp(n1,n2,IPX_SAP_SERVER_NAME_LEN) == 0);
+#define sap_type_equal(t1,t2) (t1==IPX_SAP_GENERAL_RQ || t2==IPX_SAP_GENERAL_RQ || t1==t2);
+*/
+void sap_copy_name(char *dest,char *src);
+int sap_getsock(int *rsock);
+
+
+int sap_rq_init(struct sap_rq* out,int sock);
+int sap_rq_flush(struct sap_rq* out);
+void sap_rq_general(struct sap_rq* out,u_short ser_type);
+void sap_rq_gns_request(struct sap_rq* out,u_short ser_type);
+void sap_rq_response(struct sap_rq* out,u_short type,char *name,struct sockaddr_ipx* addr,u_short hops,int down_allow);
+void sap_rq_gns_response(struct sap_rq* out,u_short type,char * name,struct sockaddr_ipx* addr,u_short hops);
+void sap_rq_set_destination(struct sap_rq* out,struct ipx_addr *dest);
+
+int sap_find_nearest(int server_type, struct sockaddr_ipx *result,char *server_name);
+
+extern int (*sap_sendto_func)(void* buffer,int size,struct sockaddr_ipx* daddr,int sock);
+int ipx_iffind(char *ifname, struct ipx_addr *addr);
+
+#endif /* !_IPXSAP_H_ */
diff --git a/lib/libncp/ncpl_bind.c b/lib/libncp/ncpl_bind.c
new file mode 100644
index 0000000..ab591eb
--- /dev/null
+++ b/lib/libncp/ncpl_bind.c
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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 Boris Popov.
+ * 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 THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 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 <arpa/inet.h>
+#include <errno.h>
+#include <string.h>
+#include <netncp/ncp_lib.h>
+
+static void nw_passencrypt(char *old, char *new, char *out);
+
+int
+ncp_get_bindery_object_id(NWCONN_HANDLE connid, u_int16_t object_type,
+ const char *object_name, struct ncp_bindery_object *target)
+{
+ int error;
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 53);
+ ncp_add_word_hl(conn, object_type);
+ ncp_add_pstring(conn, object_name);
+
+ if ((error = ncp_request(connid, 23, conn)) != 0) {
+ return error;
+ }
+ if (conn->rpsize < 54) {
+ return EACCES;
+ }
+ target->object_id = ncp_reply_dword_hl(conn, 0);
+ target->object_type = ncp_reply_word_hl(conn, 4);
+ memcpy(target->object_name, ncp_reply_data(conn, 6), 48);
+ return 0;
+}
+
+int
+ncp_read_property_value(NWCONN_HANDLE connid, int object_type,
+ const char *object_name, int segment, const char *prop_name,
+ struct nw_property *target)
+{
+ int error;
+ struct ncp_buf conn;
+ ncp_init_request_s(&conn, 61);
+ ncp_add_word_hl(&conn, object_type);
+ ncp_add_pstring(&conn, object_name);
+ ncp_add_byte(&conn, segment);
+ ncp_add_pstring(&conn, prop_name);
+
+ if ((error = ncp_request(connid,23,&conn)) != 0) {
+ return error;
+ }
+ memcpy(&(target->value), ncp_reply_data(&conn, 0), 128);
+ target->more_flag = ncp_reply_byte(&conn, 128);
+ target->property_flag = ncp_reply_byte(&conn, 129);
+ return 0;
+}
+
+int
+ncp_scan_bindery_object(NWCONN_HANDLE connid, u_int32_t last_id,
+ u_int16_t object_type, char *search_string,
+ struct ncp_bindery_object *target)
+{
+ int error;
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 55);
+ ncp_add_dword_hl(conn, last_id);
+ ncp_add_word_hl(conn, object_type);
+ ncp_add_pstring(conn, search_string);
+ error = ncp_request(connid, 23, conn);
+ if (error) return error;
+ target->object_id = ncp_reply_dword_hl(conn, 0);
+ target->object_type = ncp_reply_word_hl(conn, 4);
+ memcpy(target->object_name, ncp_reply_data(conn, 6),NCP_BINDERY_NAME_LEN);
+ target->object_flags = ncp_reply_byte(conn, 54);
+ target->object_security = ncp_reply_byte(conn, 55);
+ target->object_has_prop = ncp_reply_byte(conn, 56);
+ return 0;
+}
+
+int
+ncp_get_bindery_object_name(NWCONN_HANDLE connid, u_int32_t object_id,
+ struct ncp_bindery_object *target)
+{
+ int error;
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 54);
+ ncp_add_dword_hl(conn, object_id);
+ if ((error = ncp_request(connid, 23, conn)) != 0)
+ return error;
+ target->object_id = ncp_reply_dword_hl(conn, 0);
+ target->object_type = ncp_reply_word_hl(conn, 4);
+ memcpy(target->object_name, ncp_reply_data(conn, 6), 48);
+ return 0;
+}
+
+int
+ncp_change_obj_passwd(NWCONN_HANDLE connid,
+ const struct ncp_bindery_object *object,
+ const u_char *key,
+ const u_char *oldpasswd,
+ const u_char *newpasswd)
+{
+ long id = htonl(object->object_id);
+ u_char cryptkey[8];
+ u_char newpwd[16]; /* new passwd as stored by server */
+ u_char oldpwd[16]; /* old passwd as stored by server */
+ u_char len;
+ DECLARE_RQ;
+
+ memcpy(cryptkey, key, 8);
+ nw_keyhash((u_char *)&id, oldpasswd, strlen(oldpasswd), oldpwd);
+ nw_keyhash((u_char *)&id, newpasswd, strlen(newpasswd), newpwd);
+ nw_encrypt(cryptkey, oldpwd, cryptkey);
+ nw_passencrypt(oldpwd, newpwd, newpwd);
+ nw_passencrypt(oldpwd + 8, newpwd + 8, newpwd + 8);
+ if ((len = strlen(newpasswd)) > 63) {
+ len = 63;
+ }
+ len = ((len ^ oldpwd[0] ^ oldpwd[1]) & 0x7f) | 0x40;
+
+ ncp_init_request_s(conn, 75);
+ ncp_add_mem(conn, cryptkey, 8);
+ ncp_add_word_hl(conn, object->object_type);
+ ncp_add_pstring(conn, object->object_name);
+ ncp_add_byte(conn, len);
+ ncp_add_mem(conn, newpwd, 16);
+ return ncp_request(connid, 23, conn);
+}
+
+/*
+ * target is a 8-byte buffer
+ */
+int
+ncp_get_encryption_key(NWCONN_HANDLE cH, char *target) {
+ int error;
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 23);
+
+ error = ncp_request(cH, 23, conn);
+ if (error)
+ return error;
+ if (conn->rpsize < 8)
+ return EACCES;
+ memcpy(target, ncp_reply_data(conn, 0), 8);
+ return 0;
+}
+
+int
+ncp_keyed_verify_password(NWCONN_HANDLE cH, char *key, char *passwd,
+ struct ncp_bindery_object *objinfo)
+{
+ u_long id = htonl(objinfo->object_id);
+ u_char cryptkey[8];
+ u_char buf[128];
+ DECLARE_RQ;
+
+ nw_keyhash((u_char *)&id, passwd, strlen(passwd), buf);
+ nw_encrypt(key, buf, cryptkey);
+
+ ncp_init_request_s(conn, 74);
+ ncp_add_mem(conn, cryptkey, sizeof(cryptkey));
+ ncp_add_word_hl(conn, objinfo->object_type);
+ ncp_add_pstring(conn, objinfo->object_name);
+
+ return ncp_request(cH, 23, conn);
+}
+
+static char passkeys[256 + 16] = {
+ 0x0f, 0x08, 0x05, 0x07, 0x0c, 0x02, 0x0e, 0x09,
+ 0x00, 0x01, 0x06, 0x0d, 0x03, 0x04, 0x0b, 0x0a,
+ 0x02, 0x0c, 0x0e, 0x06, 0x0f, 0x00, 0x01, 0x08,
+ 0x0d, 0x03, 0x0a, 0x04, 0x09, 0x0b, 0x05, 0x07,
+ 0x05, 0x02, 0x09, 0x0f, 0x0c, 0x04, 0x0d, 0x00,
+ 0x0e, 0x0a, 0x06, 0x08, 0x0b, 0x01, 0x03, 0x07,
+ 0x0f, 0x0d, 0x02, 0x06, 0x07, 0x08, 0x05, 0x09,
+ 0x00, 0x04, 0x0c, 0x03, 0x01, 0x0a, 0x0b, 0x0e,
+ 0x05, 0x0e, 0x02, 0x0b, 0x0d, 0x0a, 0x07, 0x00,
+ 0x08, 0x06, 0x04, 0x01, 0x0f, 0x0c, 0x03, 0x09,
+ 0x08, 0x02, 0x0f, 0x0a, 0x05, 0x09, 0x06, 0x0c,
+ 0x00, 0x0b, 0x01, 0x0d, 0x07, 0x03, 0x04, 0x0e,
+ 0x0e, 0x08, 0x00, 0x09, 0x04, 0x0b, 0x02, 0x07,
+ 0x0c, 0x03, 0x0a, 0x05, 0x0d, 0x01, 0x06, 0x0f,
+ 0x01, 0x04, 0x08, 0x0a, 0x0d, 0x0b, 0x07, 0x0e,
+ 0x05, 0x0f, 0x03, 0x09, 0x00, 0x02, 0x06, 0x0c,
+ 0x05, 0x03, 0x0c, 0x08, 0x0b, 0x02, 0x0e, 0x0a,
+ 0x04, 0x01, 0x0d, 0x00, 0x06, 0x07, 0x0f, 0x09,
+ 0x06, 0x00, 0x0b, 0x0e, 0x0d, 0x04, 0x0c, 0x0f,
+ 0x07, 0x02, 0x08, 0x0a, 0x01, 0x05, 0x03, 0x09,
+ 0x0b, 0x05, 0x0a, 0x0e, 0x0f, 0x01, 0x0c, 0x00,
+ 0x06, 0x04, 0x02, 0x09, 0x03, 0x0d, 0x07, 0x08,
+ 0x07, 0x02, 0x0a, 0x00, 0x0e, 0x08, 0x0f, 0x04,
+ 0x0c, 0x0b, 0x09, 0x01, 0x05, 0x0d, 0x03, 0x06,
+ 0x07, 0x04, 0x0f, 0x09, 0x05, 0x01, 0x0c, 0x0b,
+ 0x00, 0x03, 0x08, 0x0e, 0x02, 0x0a, 0x06, 0x0d,
+ 0x09, 0x04, 0x08, 0x00, 0x0a, 0x03, 0x01, 0x0c,
+ 0x05, 0x0f, 0x07, 0x02, 0x0b, 0x0e, 0x06, 0x0d,
+ 0x09, 0x05, 0x04, 0x07, 0x0e, 0x08, 0x03, 0x01,
+ 0x0d, 0x0b, 0x0c, 0x02, 0x00, 0x0f, 0x06, 0x0a,
+ 0x09, 0x0a, 0x0b, 0x0d, 0x05, 0x03, 0x0f, 0x00,
+ 0x01, 0x0c, 0x08, 0x07, 0x06, 0x04, 0x0e, 0x02,
+ 0x03, 0x0e, 0x0f, 0x02, 0x0d, 0x0c, 0x04, 0x05,
+ 0x09, 0x06, 0x00, 0x01, 0x0b, 0x07, 0x0a, 0x08
+};
+
+static void
+nw_passencrypt(char *old, char *new, char *out)
+{
+ char *p, v;
+ char copy[8];
+ int i, di, ax;
+
+#define HIGH(x) (((x) >> 4) & 0xf)
+#define LOW(x) ((x) & 0xf)
+ memcpy(copy, new, 8);
+
+ for (i = 0; i < 16; i++) {
+ for (di = 0, ax = 0, p = old; di < 8; di++, ax += 0x20, p++) {
+ v = copy[di] ^ *p;
+ copy[di] = (passkeys[HIGH(v) + ax + 0x10] << 4) |
+ passkeys[LOW(v) + ax];
+ }
+ v = old[7];
+ for (p = old + 7; p > old; p--) {
+ *p = HIGH(p[-1]) | ((*p) << 4);
+ }
+ *old = HIGH(v) | (*old) << 4;
+ bzero(out, 8);
+
+ for (di = 0; di < 16; di++) {
+ v = passkeys[di + 0x100];
+ v = (v & 1) ? HIGH(copy[v / 2]) : LOW(copy[v / 2]);
+ out[di / 2] |= ((di & 1) ? v << 4 : v);
+ }
+ memcpy(copy, out, 8);
+ }
+}
diff --git a/lib/libncp/ncpl_conn.c b/lib/libncp/ncpl_conn.c
new file mode 100644
index 0000000..977752c
--- /dev/null
+++ b/lib/libncp/ncpl_conn.c
@@ -0,0 +1,514 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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 Boris Popov.
+ * 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 THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ *
+ * Current scheme to create/open connection:
+ * 1. ncp_li_init() - lookup -S [-U] options in command line
+ * 2. ncp_li_init() - try to find existing connection
+ * 3. ncp_li_init() - if no server name and no accessible connections - bail out
+ * 4. This is connection candidate, read .rc file, override with command line
+ * and go ahead
+ * Note: connection referenced only via ncp_login() call. Although it is
+ * possible to get connection handle in other way, it will be unwise to use
+ * it, since conn can be destroyed at any time.
+ *
+ */
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/mount.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <pwd.h>
+#include <grp.h>
+#include <unistd.h>
+
+#include <netncp/ncp_lib.h>
+#include <netncp/ncp_rcfile.h>
+#include <fs/nwfs/nwfs.h>
+
+static char *server_name; /* need a better way ! */
+
+
+
+int
+ncp_li_setserver(struct ncp_conn_loginfo *li, const char *arg) {
+ if (strlen(arg) >= NCP_BINDERY_NAME_LEN) {
+ ncp_error("server name '%s' too long", 0, arg);
+ return ENAMETOOLONG;
+ }
+ ncp_str_upper(strcpy(li->server, arg));
+ return 0;
+}
+
+int
+ncp_li_setuser(struct ncp_conn_loginfo *li, char *arg) {
+ if (arg && strlen(arg) >= NCP_BINDERY_NAME_LEN) {
+ ncp_error("user name '%s' too long", 0, arg);
+ return ENAMETOOLONG;
+ }
+ if (li->user)
+ free(li->user);
+ if (arg) {
+ li->user = strdup(arg);
+ if (li->user == NULL)
+ return ENOMEM;
+ ncp_str_upper(li->user);
+ } else
+ li->user = NULL;
+ return 0;
+}
+
+int
+ncp_li_setpassword(struct ncp_conn_loginfo *li, const char *passwd) {
+ if (passwd && strlen(passwd) >= 127) {
+ ncp_error("password too long", 0);
+ return ENAMETOOLONG;
+ }
+ if (li->password) {
+ bzero(li->password, strlen(li->password));
+ free(li->password);
+ }
+ if (passwd) {
+ li->password = strdup(passwd);
+ if (li->password == NULL)
+ return ENOMEM;
+ } else
+ li->password = NULL;
+ return 0;
+}
+/*
+ * Prescan command line for [-S server] [-U user] arguments
+ * and fill li structure with defaults
+ */
+int
+ncp_li_init(struct ncp_conn_loginfo *li, int argc, char *argv[]) {
+ int opt, error = 0;
+ char *arg;
+
+ bzero(li,sizeof(*li));
+ li->timeout = 15; /* these values should be large enough to handle */
+ li->retry_count = 4; /* slow servers, even on ethernet */
+ li->access_mode = 0;
+ li->password = NULL;
+ li->sig_level = 1;
+ li->objtype = NCP_BINDERY_USER;
+ li->owner = NCP_DEFAULT_OWNER;
+ li->group = NCP_DEFAULT_GROUP;
+ server_name = NULL;
+ if (argv == NULL) return 0;
+ while (error == 0 && (opt = ncp_getopt(argc, argv, ":S:U:")) != -1) {
+ arg = ncp_optarg;
+ switch (opt) {
+ case 'S':
+ error = ncp_li_setserver(li, arg);
+ break;
+ case 'U':
+ error = ncp_li_setuser(li, arg);
+ break;
+ }
+ }
+ ncp_optind = ncp_optreset = 1;
+ return error;
+}
+
+void
+ncp_li_done(struct ncp_conn_loginfo *li) {
+ if (li->user)
+ free(li->user);
+ if (li->password)
+ free(li->password);
+}
+
+/*
+ * Lookup existing connection based on li structure, if connection
+ * found, it will be referenced. Otherwise full login sequence performed.
+ */
+int
+ncp_li_login(struct ncp_conn_loginfo *li, int *aconnid) {
+ int connHandle, error;
+
+ if ((error = ncp_conn_scan(li, &connHandle)) == 0) {
+ *aconnid = connHandle;
+ return 0;
+ }
+ error = ncp_connect(li, &connHandle);
+ if (error) return errno;
+ error = ncp_login(connHandle, li->user, li->objtype, li->password);
+ if (error) {
+ ncp_disconnect(connHandle);
+ } else
+ *aconnid = connHandle;
+ return error;
+}
+
+/*
+ * read rc file as follows:
+ * 1. read [server] section
+ * 2. override with [server:user] section
+ * Since abcence of rcfile is not a bug, silently ignore that fact.
+ * rcfile never closed to reduce number of open/close operations.
+ */
+int
+ncp_li_readrc(struct ncp_conn_loginfo *li) {
+ int i, val, error;
+ char uname[NCP_BINDERY_NAME_LEN*2+1];
+ char *sect = NULL, *p;
+
+ /*
+ * if info from cmd line incomplete, try to find existing
+ * connection and fill server/user from it.
+ */
+ if (li->server[0] == 0 || li->user == NULL) {
+ int connHandle;
+ struct ncp_conn_stat cs;
+
+ if ((error = ncp_conn_scan(li, &connHandle)) != 0) {
+ ncp_error("no default connection found", errno);
+ return error;
+ }
+ ncp_conn_getinfo(connHandle, &cs);
+ ncp_li_setserver(li, cs.li.server);
+ ncp_li_setuser(li, cs.user);
+ ncp_li_setpassword(li, "");
+ ncp_disconnect(connHandle);
+ }
+ if (ncp_open_rcfile()) return 0;
+
+ for (i = 0; i < 2; i++) {
+ switch (i) {
+ case 0:
+ sect = li->server;
+ break;
+ case 1:
+ strcat(strcat(strcpy(uname,li->server),":"),li->user ? li->user : "default");
+ sect = uname;
+ break;
+ }
+ rc_getstringptr(ncp_rc, sect, "password", &p);
+ if (p)
+ ncp_li_setpassword(li, p);
+ rc_getint(ncp_rc,sect, "timeout", &li->timeout);
+ rc_getint(ncp_rc,sect, "retry_count", &li->retry_count);
+ rc_getint(ncp_rc,sect, "sig_level", &li->sig_level);
+ if (rc_getint(ncp_rc,sect,"access_mode",&val) == 0)
+ li->access_mode = val;
+ if(rc_getbool(ncp_rc,sect,"bindery",&val) == 0 && val) {
+ li->opt |= NCP_OPT_BIND;
+ }
+ }
+ return 0;
+}
+
+/*
+ * check for all uncompleted fields
+ */
+int
+ncp_li_check(struct ncp_conn_loginfo *li) {
+ int error = 0;
+ char *p;
+
+ do {
+ if (li->server[0] == 0) {
+ ncp_error("no server name specified", 0);
+ error = 1;
+ break;
+ }
+ error = ncp_find_fileserver(li,
+ (server_name==NULL) ? AF_IPX : AF_INET, server_name);
+ if (error) {
+ ncp_error("can't find server %s", error, li->server);
+ break;
+ }
+ if (li->user == NULL || li->user[0] == 0) {
+ ncp_error("no user name specified for server %s",
+ 0, li->server);
+ error = 1;
+ break;
+ }
+ if (li->password == NULL) {
+ p = getpass("Netware password:");
+ error = ncp_li_setpassword(li, p) ? 1 : 0;
+ }
+ } while (0);
+ return error;
+}
+
+int
+ncp_conn_cnt(void) {
+ int error, cnt = 0;
+ size_t len = sizeof(cnt);
+
+ error = sysctlbyname("net.ncp.conn_cnt", &cnt, &len, NULL, 0);
+ if (error) cnt = 0;
+ return cnt;
+}
+
+/*
+ * Find an existing connection and reference it
+ */
+int
+ncp_conn_find(char *server,char *user) {
+ struct ncp_conn_args ca;
+ int connid, error;
+
+ if (server == NULL && user == NULL) {
+ error = ncp_conn_scan(NULL,&connid);
+ if (error) return -2;
+ return connid;
+ }
+ if (server == NULL)
+ return -2;
+ ncp_str_upper(server);
+ if (user) ncp_str_upper(user);
+ bzero(&ca, sizeof(ca));
+ ncp_li_setserver(&ca, server);
+ ncp_li_setuser(&ca, user);
+ error = ncp_conn_scan(&ca,&connid);
+ if (error)
+ connid = -1;
+ return connid;
+}
+
+int
+ncp_li_arg(struct ncp_conn_loginfo *li, int opt, char *arg) {
+ int error = 0, sig_level;
+ char *p, *cp;
+ struct group *gr;
+ struct passwd *pw;
+
+ switch(opt) {
+ case 'S': /* we already fill server/[user] pair */
+ case 'U':
+ break;
+ case 'A':
+ server_name = arg;
+ break;
+ case 'B':
+ li->opt |= NCP_OPT_BIND;
+ break;
+ case 'C':
+ li->opt |= NCP_OPT_NOUPCASEPASS;
+ break;
+ case 'I':
+ sig_level = atoi(arg);
+ if (sig_level < 0 || sig_level > 3) {
+ ncp_error("invalid NCP signature level option `%s'\
+ (must be a number between 0 and 3)", 0, arg);
+ error = 1;
+ }
+ li->sig_level = sig_level;
+ if (sig_level > 1) li->opt |= NCP_OPT_SIGN;
+ break;
+ case 'M':
+ li->access_mode = strtol(arg, NULL, 8);
+ break;
+ case 'N':
+ ncp_li_setpassword(li, "");
+ break;
+ case 'O':
+ p = strdup(arg);
+ cp = strchr(p, ':');
+ if (cp) {
+ *cp++ = '\0';
+ if (*cp) {
+ gr = getgrnam(cp);
+ if (gr) {
+ li->group = gr->gr_gid;
+ } else
+ ncp_error("invalid group name %s, ignored",
+ 0, cp);
+ }
+ }
+ if (*p) {
+ pw = getpwnam(p);
+ if (pw) {
+ li->owner = pw->pw_uid;
+ } else
+ ncp_error("invalid user name %s, ignored", 0, p);
+ }
+ endpwent();
+ free(p);
+ break;
+ case 'P':
+ li->opt |= NCP_OPT_PERMANENT;
+ break;
+ case 'R':
+ li->retry_count = atoi(arg);
+ break;
+ case 'W':
+ li->timeout = atoi(arg);
+ break;
+ }
+ return error;
+}
+
+void *
+ncp_conn_list(void) {
+ int error, cnt = 0;
+ size_t len;
+ void *p;
+
+ cnt = ncp_conn_cnt();
+ if (cnt == 0) return NULL;
+ len = cnt*(sizeof(struct ncp_conn_stat))+sizeof(int);
+ p = malloc(len);
+ if (p == NULL) return NULL;
+ error = sysctlbyname("net.ncp.conn_stat", p, &len, NULL, 0);
+ if (error) {
+ free(p);
+ p = NULL;
+ }
+ return p;
+}
+
+
+int
+ncp_conn_setflags(int connid, u_int16_t mask, u_int16_t flags) {
+ int error;
+ DECLARE_RQ;
+
+ ncp_init_request(conn);
+ ncp_add_byte(conn, NCP_CONN_SETFLAGS);
+ ncp_add_word_lh(conn, mask);
+ ncp_add_word_lh(conn, flags);
+ if ((error = ncp_conn_request(connid, conn)) < 0)
+ return -1;
+ return error;
+}
+
+int
+ncp_login(int connHandle, const char *user, int objtype, const char *password) {
+ int error;
+ struct ncp_conn_login *p;
+ DECLARE_RQ;
+
+ ncp_init_request(conn);
+ ncp_add_byte(conn, NCP_CONN_LOGIN);
+ p = (struct ncp_conn_login *)&conn->packet[conn->rqsize];
+ p->username = (char *)user;
+ p->objtype = objtype;
+ p->password = (char *)password;
+ conn->rqsize += sizeof(*p);
+ if ((error = ncp_conn_request(connHandle, conn)) < 0)
+ return -1;
+ return error;
+}
+
+int
+ncp_connect_addr(struct sockaddr *sa, NWCONN_HANDLE *chp) {
+ int error;
+ struct ncp_conn_args li;
+
+ bzero(&li, sizeof(li));
+ bcopy(sa, &li.addr, sa->sa_len);
+ /*
+ * XXX Temporary !!!. server will be filled in kernel !!!
+ */
+ strcpy(li.server,ipx_ntoa(li.ipxaddr.sipx_addr));
+ error = ncp_connect(&li, chp);
+ return error;
+}
+
+int
+ncp_conn_getinfo(int connHandle, struct ncp_conn_stat *ps) {
+ int error;
+ DECLARE_RQ;
+
+ ncp_init_request(conn);
+ ncp_add_byte(conn, NCP_CONN_GETINFO);
+ if ((error = ncp_conn_request(connHandle, conn)) < 0)
+ return -1;
+ memcpy(ps, ncp_reply_data(conn,0), sizeof(*ps));
+ return error;
+}
+
+int
+ncp_conn_getuser(int connHandle, char **user) {
+ int error;
+ DECLARE_RQ;
+
+ ncp_init_request(conn);
+ ncp_add_byte(conn, NCP_CONN_GETUSER);
+ if ((error = ncp_conn_request(connHandle, conn)) < 0)
+ return -1;
+ *user = strdup(ncp_reply_data(conn,0));
+ return error;
+}
+
+int
+ncp_conn2ref(int connHandle, int *connRef) {
+ int error;
+ DECLARE_RQ;
+
+ ncp_init_request(conn);
+ ncp_add_byte(conn, NCP_CONN_CONN2REF);
+ if ((error = ncp_conn_request(connHandle, conn)) < 0)
+ return -1;
+ *connRef = *((int*)ncp_reply_data(conn,0));
+ return error;
+}
+
+int
+ncp_path2conn(char *path, int *connHandle) {
+ struct statfs st;
+ int d, error;
+
+ if ((error = statfs(path, &st)) != 0) return errno;
+ if (strcmp(st.f_fstypename,"nwfs") != 0) return EINVAL;
+ if ((d = open(path, O_RDONLY)) < 0) return errno;
+ if ((error = ioctl(d,NWFSIOC_GETCONN, connHandle)) != 0) return errno;
+ close(d);
+ return 0;
+}
+
+int
+ncp_conn_dup(NWCONN_HANDLE org, NWCONN_HANDLE *res) {
+ int error;
+ DECLARE_RQ;
+
+ ncp_init_request(conn);
+ ncp_add_byte(conn, NCP_CONN_DUP);
+ if ((error = ncp_conn_request(org, conn)) < 0)
+ return errno;
+ *res = *((int*)ncp_reply_data(conn, 0));
+ return 0;
+}
diff --git a/lib/libncp/ncpl_crypt.c b/lib/libncp/ncpl_crypt.c
new file mode 100644
index 0000000..bc304c0
--- /dev/null
+++ b/lib/libncp/ncpl_crypt.c
@@ -0,0 +1,139 @@
+/*
+ * Routines in this file based on the work of Volker Lendecke,
+ * Adapted for ncplib by Boris Popov
+ * Please note that ncpl_crypt.c file should be indentical to this one
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/malloc.h>
+#include <string.h>
+
+/*$*********************************************************
+ $*
+ $* This code has been taken from DDJ 11/93, from an
+ $* article by Pawel Szczerbina.
+ $*
+ $* Password encryption routines follow.
+ $* Converted to C from Barry Nance's Pascal
+ $* prog published in the March -93 issue of Byte.
+ $*
+ $* Adapted to be useable for ncpfs by
+ $* Volker Lendecke <lendecke@namu01.gwdg.de> in
+ $* October 1995.
+ $*
+ $********************************************************* */
+
+
+
+typedef unsigned char buf32[32];
+
+static unsigned char encrypttable[256] = {
+0x7, 0x8, 0x0, 0x8, 0x6, 0x4, 0xE, 0x4, 0x5, 0xC, 0x1, 0x7, 0xB, 0xF, 0xA, 0x8,
+0xF, 0x8, 0xC, 0xC, 0x9, 0x4, 0x1, 0xE, 0x4, 0x6, 0x2, 0x4, 0x0, 0xA, 0xB, 0x9,
+0x2, 0xF, 0xB, 0x1, 0xD, 0x2, 0x1, 0x9, 0x5, 0xE, 0x7, 0x0, 0x0, 0x2, 0x6, 0x6,
+0x0, 0x7, 0x3, 0x8, 0x2, 0x9, 0x3, 0xF, 0x7, 0xF, 0xC, 0xF, 0x6, 0x4, 0xA, 0x0,
+0x2, 0x3, 0xA, 0xB, 0xD, 0x8, 0x3, 0xA, 0x1, 0x7, 0xC, 0xF, 0x1, 0x8, 0x9, 0xD,
+0x9, 0x1, 0x9, 0x4, 0xE, 0x4, 0xC, 0x5, 0x5, 0xC, 0x8, 0xB, 0x2, 0x3, 0x9, 0xE,
+0x7, 0x7, 0x6, 0x9, 0xE, 0xF, 0xC, 0x8, 0xD, 0x1, 0xA, 0x6, 0xE, 0xD, 0x0, 0x7,
+0x7, 0xA, 0x0, 0x1, 0xF, 0x5, 0x4, 0xB, 0x7, 0xB, 0xE, 0xC, 0x9, 0x5, 0xD, 0x1,
+0xB, 0xD, 0x1, 0x3, 0x5, 0xD, 0xE, 0x6, 0x3, 0x0, 0xB, 0xB, 0xF, 0x3, 0x6, 0x4,
+0x9, 0xD, 0xA, 0x3, 0x1, 0x4, 0x9, 0x4, 0x8, 0x3, 0xB, 0xE, 0x5, 0x0, 0x5, 0x2,
+0xC, 0xB, 0xD, 0x5, 0xD, 0x5, 0xD, 0x2, 0xD, 0x9, 0xA, 0xC, 0xA, 0x0, 0xB, 0x3,
+0x5, 0x3, 0x6, 0x9, 0x5, 0x1, 0xE, 0xE, 0x0, 0xE, 0x8, 0x2, 0xD, 0x2, 0x2, 0x0,
+0x4, 0xF, 0x8, 0x5, 0x9, 0x6, 0x8, 0x6, 0xB, 0xA, 0xB, 0xF, 0x0, 0x7, 0x2, 0x8,
+0xC, 0x7, 0x3, 0xA, 0x1, 0x4, 0x2, 0x5, 0xF, 0x7, 0xA, 0xC, 0xE, 0x5, 0x9, 0x3,
+0xE, 0x7, 0x1, 0x2, 0xE, 0x1, 0xF, 0x4, 0xA, 0x6, 0xC, 0x6, 0xF, 0x4, 0x3, 0x0,
+0xC, 0x0, 0x3, 0x6, 0xF, 0x8, 0x7, 0xB, 0x2, 0xD, 0xC, 0x6, 0xA, 0xA, 0x8, 0xD
+};
+
+static buf32 encryptkeys = {
+ 0x48, 0x93, 0x46, 0x67, 0x98, 0x3D, 0xE6, 0x8D,
+ 0xB7, 0x10, 0x7A, 0x26, 0x5A, 0xB9, 0xB1, 0x35,
+ 0x6B, 0x0F, 0xD5, 0x70, 0xAE, 0xFB, 0xAD, 0x11,
+ 0xF4, 0x47, 0xDC, 0xA7, 0xEC, 0xCF, 0x50, 0xC0
+};
+
+/*
+ * Create table-based 16-bytes hash from a 32-bytes array
+ */
+static void
+nw_hash(buf32 temp, unsigned char *target) {
+ short sum;
+ unsigned char b3;
+ int s, b2, i;
+
+ sum = 0;
+
+ for (b2 = 0; b2 <= 1; ++b2) {
+ for (s = 0; s <= 31; ++s) {
+ b3 = (temp[s] + sum) ^ (temp[(s + sum) & 31] - encryptkeys[s]);
+ sum += b3;
+ temp[s] = b3;
+ }
+ }
+
+ for (i = 0; i <= 15; ++i) {
+ target[i] = encrypttable[temp[2 * i]]
+ | (encrypttable[temp[2 * i + 1]] << 4);
+ }
+}
+
+
+/*
+ * Create a 16-bytes pattern from given buffer based on a four bytes key
+ */
+void
+nw_keyhash(const u_char *key, const u_char *buf, int buflen, u_char *target) {
+ int b2, d, s;
+ buf32 temp;
+
+ while (buflen > 0 && buf[buflen - 1] == 0)
+ buflen--;
+
+ bzero(temp, sizeof(temp));
+
+ d = 0;
+ while (buflen >= 32) {
+ for (s = 0; s <= 31; ++s)
+ temp[s] ^= buf[d++];
+ buflen -= 32;
+ }
+ b2 = d;
+ if (buflen > 0) {
+ for (s = 0; s <= 31; ++s) {
+ if (d + buflen == b2) {
+ temp[s] ^= encryptkeys[s];
+ b2 = d;
+ } else
+ temp[s] ^= buf[b2++];
+ }
+ }
+ for (s = 0; s <= 31; ++s)
+ temp[s] ^= key[s & 3];
+
+ nw_hash(temp, target);
+}
+
+/*
+ * Create an 8-bytes pattern from an 8-bytes key and 16-bytes of data
+ */
+void
+nw_encrypt(const u_char *fra, const u_char *buf, u_char *target) {
+ buf32 k;
+ int s;
+
+ nw_keyhash(fra, buf, 16, k);
+ nw_keyhash(fra + 4, buf, 16, k + 16);
+
+ for (s = 0; s < 16; s++)
+ k[s] ^= k[31 - s];
+
+ for (s = 0; s < 8; s++)
+ *target++ = k[s] ^ k[15 - s];
+}
+
+
diff --git a/lib/libncp/ncpl_file.c b/lib/libncp/ncpl_file.c
new file mode 100644
index 0000000..2ffcc46
--- /dev/null
+++ b/lib/libncp/ncpl_file.c
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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 Boris Popov.
+ * 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 THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 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/ioctl.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <strings.h>
+
+#include <netncp/ncp_lib.h>
+#include <netncp/ncp_file.h>
+#include <fs/nwfs/nwfs.h>
+
+int
+ncp_read(NWCONN_HANDLE connid, ncp_fh *fh, off_t offset, size_t count, char *target) {
+ int result;
+ struct ncp_rw rwrq;
+ DECLARE_RQ;
+
+ ncp_init_request(conn);
+ ncp_add_byte(conn, NCP_CONN_READ);
+ rwrq.nrw_fh = *fh;
+ rwrq.nrw_base = target;
+ rwrq.nrw_cnt = count;
+ rwrq.nrw_offset = offset;
+ ncp_add_mem(conn, &rwrq, sizeof(rwrq));
+ if ((result = ncp_conn_request(connid, conn)) < 0)
+ return -1;
+ return result;
+}
+
+int
+ncp_write(NWCONN_HANDLE connid, ncp_fh *fh, off_t offset, size_t count, char *source)
+{
+ int result;
+ struct ncp_rw rwrq;
+ DECLARE_RQ;
+
+ ncp_init_request(conn);
+ ncp_add_byte(conn, NCP_CONN_WRITE);
+ rwrq.nrw_fh = *fh;
+ rwrq.nrw_base = source;
+ rwrq.nrw_cnt = count;
+ rwrq.nrw_offset = offset;
+ ncp_add_mem(conn, &rwrq, sizeof(rwrq));
+
+ if ((result = ncp_conn_request(connid, conn)) < 0)
+ return -1;
+ return result;
+}
+
+int
+ncp_geteinfo(char *path, struct nw_entry_info *fi) {
+ int d, error;
+
+ if ((d = open(path, O_RDONLY)) < 0) return errno;
+ if ((error = ioctl(d, NWFSIOC_GETEINFO, fi)) != 0) return errno;
+ close(d);
+ return 0;
+}
+
+
+int
+ncp_AllocTempDirHandle(char *path, NWDIR_HANDLE *pdh) {
+ int d;
+
+ if ((d = open(path, O_RDONLY)) < 0) return errno;
+ *pdh = d;
+ return 0;
+}
+
+int
+ncp_DeallocateDirHandle(NWDIR_HANDLE dh) {
+ close(dh);
+ return 0;
+}
+
+int
+ncp_GetNSEntryInfo(NWDIR_HANDLE dh, struct nw_entry_info *fi, int *ns) {
+ int error;
+
+ if ((error = ioctl(dh, NWFSIOC_GETEINFO, fi)) != 0) return errno;
+ if ((error = ioctl(dh, NWFSIOC_GETNS, ns)) != 0) return errno;
+ return 0;
+}
+
+NWCCODE
+ncp_ScanForDeletedFiles(NWCONN_HANDLE cH, pnuint32 iterHandle,
+ pnuint32 volNum, pnuint32 dirBase, nuint8 ns,
+ NWDELETED_INFO *entryInfo)
+{
+ int error;
+ struct nw_entry_info *pfi;
+ DECLARE_RQ;
+#define UNITEDT(d,t) (((d) << 16) | (t))
+
+ bzero(entryInfo, sizeof(NWDELETED_INFO));
+ ncp_init_request(conn);
+ ncp_add_byte(conn, 16);
+ ncp_add_byte(conn, ns);
+ ncp_add_byte(conn, 0); /* data stream */
+ ncp_add_dword_lh(conn, IM_ALL & ~(IM_SPACE_ALLOCATED | IM_TOTAL_SIZE | IM_EA | IM_DIRECTORY));
+ ncp_add_dword_lh(conn, *iterHandle);
+
+ ncp_add_byte(conn, *volNum);
+ ncp_add_dword_lh(conn, *dirBase);
+ ncp_add_byte(conn, NCP_HF_DIRBASE); /* dirBase */
+ ncp_add_byte(conn, 0); /* no component */
+ if ((error = ncp_request(cH, 87, conn)) != 0) {
+ return error;
+ }
+ if (conn->rpsize < 0x61) {
+ return EBADRPC; /* EACCES ? */
+ }
+ *iterHandle = entryInfo->sequence = ncp_reply_dword_lh(conn, 0x00);
+ entryInfo->deletedTime = ncp_reply_word_lh(conn, 0x04);
+ entryInfo->deletedDateAndTime = UNITEDT(ncp_reply_word_lh(conn, 0x06), entryInfo->deletedTime);
+ entryInfo->deletorID = ncp_reply_dword_hl(conn, 0x08);
+ *volNum = ncp_reply_dword_lh(conn, 0x0C);
+ *dirBase = ncp_reply_dword_lh(conn, 0x10);
+ entryInfo->parent = ncp_reply_dword_lh(conn, 0x10);
+ pfi = (struct nw_entry_info*) ncp_reply_data(conn, 0x14);
+ entryInfo->nameLength = pfi->nameLen;
+ memcpy(entryInfo->name, pfi->entryName, pfi->nameLen);
+ return error;
+}
+
+NWCCODE
+ncp_PurgeDeletedFile(NWCONN_HANDLE cH, nuint32 iterHandle,
+ nuint32 volNum, nuint32 dirBase, nuint8 ns)
+{
+ DECLARE_RQ;
+
+ ncp_init_request(conn);
+ ncp_add_byte(conn, 18);
+ ncp_add_byte(conn, ns);
+ ncp_add_byte(conn, 0); /* reserved */
+ ncp_add_dword_lh(conn, iterHandle);
+ ncp_add_dword_lh(conn, volNum);
+ ncp_add_dword_lh(conn, dirBase);
+ return ncp_request(cH, 87, conn);
+}
+
+
+static void
+ncp_extract_entryInfo(char *data, NW_ENTRY_INFO *entry) {
+ u_char l;
+ const int info_struct_size = sizeof(NW_ENTRY_INFO) - 257;
+
+ memcpy(entry, data, info_struct_size);
+ data += info_struct_size;
+ l = *data++;
+ entry->nameLen = l;
+ memcpy(entry->entryName, data, l);
+ entry->entryName[l] = '\0';
+ return;
+}
+
+NWCCODE
+ncp_ScanNSEntryInfo(NWCONN_HANDLE cH,
+ nuint8 namSpc, nuint16 attrs, SEARCH_SEQUENCE *seq,
+ pnstr8 searchPattern, nuint32 retInfoMask, NW_ENTRY_INFO *entryInfo)
+{
+ int error, l;
+ DECLARE_RQ;
+
+ if (seq->searchDirNumber == -1) {
+ seq->searchDirNumber = 0;
+ ncp_init_request(conn);
+ ncp_add_byte(conn, 2);
+ ncp_add_byte(conn, namSpc);
+ ncp_add_byte(conn, 0);
+ ncp_add_handle_path(conn, seq->volNumber, seq->dirNumber,
+ NCP_HF_DIRBASE, NULL);
+ error = ncp_request(cH, 87, conn);
+ if (error) return error;
+ memcpy(seq, ncp_reply_data(conn, 0), 9);
+ }
+ ncp_init_request(conn);
+ ncp_add_byte(conn, 3);
+ ncp_add_byte(conn, namSpc);
+ ncp_add_byte(conn, 0); /* dataStream */
+ ncp_add_word_lh(conn, attrs); /* SearchAttributes */
+ ncp_add_dword_lh(conn, retInfoMask);
+ ncp_add_mem(conn, seq, sizeof(*seq));
+ l = strlen(searchPattern);
+ ncp_add_byte(conn, l);
+ ncp_add_mem(conn, searchPattern, l);
+ error = ncp_request(cH, 87, conn);
+ if (error) return error;
+ memcpy(seq, ncp_reply_data(conn, 0), sizeof(*seq));
+ ncp_extract_entryInfo(ncp_reply_data(conn, 10), entryInfo);
+ return 0;
+}
+
+int
+ncp_NSEntryInfo(NWCONN_HANDLE cH, nuint8 ns, nuint8 vol, nuint32 dirent,
+ NW_ENTRY_INFO *entryInfo)
+{
+ DECLARE_RQ;
+ int error;
+
+ ncp_init_request(conn);
+ ncp_add_byte(conn, 6);
+ ncp_add_byte(conn, ns);
+ ncp_add_byte(conn, ns); /* DestNameSpace */
+ ncp_add_word_lh(conn, htons(0xff00)); /* get all */
+ ncp_add_dword_lh(conn, IM_ALL);
+ ncp_add_handle_path(conn, vol, dirent, NCP_HF_DIRBASE, NULL);
+ error = ncp_request(cH, 87, conn);
+ if (error) return error;
+ ncp_extract_entryInfo(ncp_reply_data(conn, 0), entryInfo);
+ return 0;
+}
+
+NWCCODE
+NWGetVolumeName(NWCONN_HANDLE cH, u_char volume, char *name) {
+ int error, len;
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 44);
+ ncp_add_byte(conn, volume);
+ error = ncp_request(cH, 22, conn);
+ if (error) return error;
+ len = ncp_reply_byte(conn, 29);
+ if (len == 0)
+ return ENOENT;
+ bcopy(ncp_reply_data(conn, 30), name, len);
+ name[len] = 0;
+ return 0;
+}
diff --git a/lib/libncp/ncpl_misc.c b/lib/libncp/ncpl_misc.c
new file mode 100644
index 0000000..16a54c5
--- /dev/null
+++ b/lib/libncp/ncpl_misc.c
@@ -0,0 +1,296 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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 Boris Popov.
+ * 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 THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * calls that don't fit to any other category
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <stdio.h>
+#include <strings.h>
+
+#include <netncp/ncp_lib.h>
+
+static time_t
+ncp_nw_to_ctime(struct nw_time_buffer *source) {
+ struct tm u_time;
+
+ bzero(&u_time,sizeof(struct tm));
+ /*
+ * XXX: NW 4.x tracks daylight automatically
+ */
+ u_time.tm_isdst = -1;
+ u_time.tm_sec = source->second;
+ u_time.tm_min = source->minute;
+ u_time.tm_hour = source->hour;
+ u_time.tm_mday = source->day;
+ u_time.tm_mon = source->month - 1;
+ u_time.tm_year = source->year;
+
+ if (u_time.tm_year < 80) {
+ u_time.tm_year += 100;
+ }
+ return mktime(&u_time);
+}
+
+int
+ncp_get_file_server_information(NWCONN_HANDLE connid,
+ struct ncp_file_server_info *target)
+{
+ int error;
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 17);
+ if ((error = ncp_request(connid, 23, conn)) != 0)
+ return error;
+ memcpy(target, ncp_reply_data(conn, 0), sizeof(*target));
+ target->MaximumServiceConnections
+ = htons(target->MaximumServiceConnections);
+ target->ConnectionsInUse
+ = htons(target->ConnectionsInUse);
+ target->MaxConnectionsEverUsed
+ = htons(target->MaxConnectionsEverUsed);
+ target->NumberMountedVolumes
+ = htons(target->NumberMountedVolumes);
+ return 0;
+}
+
+int
+ncp_get_stations_logged_info(NWCONN_HANDLE connid, u_int32_t connection,
+ struct ncp_bindery_object *target, time_t *login_time)
+{
+ int error;
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 28);
+ ncp_add_dword_lh(conn, connection);
+
+ if ((error = ncp_request(connid, 23, conn)) != 0)
+ return error;
+ bzero(target, sizeof(*target));
+ target->object_id = ncp_reply_dword_hl(conn, 0);
+ target->object_type = ncp_reply_word_hl(conn, 4);
+ memcpy(target->object_name, ncp_reply_data(conn, 6),
+ sizeof(target->object_name));
+ *login_time = ncp_nw_to_ctime((struct nw_time_buffer *)ncp_reply_data(conn, 54));
+ return 0;
+}
+
+int
+ncp_get_internet_address(NWCONN_HANDLE connid, u_int32_t connection,
+ struct ipx_addr *target, u_int8_t * conn_type)
+{
+ int error;
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 26);
+ ncp_add_dword_lh(conn, connection);
+ error = ncp_request(connid, 23, conn);
+ if (error) return error;
+ bzero(target, sizeof(*target));
+ ipx_netlong(*target) = ncp_reply_dword_lh(conn, 0);
+ memcpy(&(target->x_host), ncp_reply_data(conn, 4), 6);
+ target->x_port = ncp_reply_word_lh(conn, 10);
+ *conn_type = ncp_reply_byte(conn, 12);
+ return 0;
+}
+
+NWCCODE
+NWGetObjectConnectionNumbers(NWCONN_HANDLE connHandle,
+ pnstr8 pObjName, nuint16 objType,
+ pnuint16 pNumConns, pnuint16 pConnHandleList,
+ nuint16 maxConns)
+{
+ int error, i, n;
+ nuint32 lastconn;
+ DECLARE_RQ;
+
+ lastconn = 0;
+ ncp_init_request_s(conn, 27);
+ ncp_add_dword_lh(conn, lastconn);
+ ncp_add_word_hl(conn, objType);
+ ncp_add_pstring(conn, pObjName);
+ if ((error = ncp_request(connHandle, 23, conn)) != 0) return error;
+ n = min(ncp_reply_byte(conn, 0), maxConns);
+ *pNumConns = n;
+ for (i = 0; i < n ; i++) {
+ *pConnHandleList++ = ncp_reply_dword_lh(conn, i * 4 + 1);
+ }
+ return 0;
+}
+
+void
+NWUnpackDateTime(nuint32 dateTime, NW_DATE *sDate, NW_TIME *sTime) {
+ NWUnpackDate(dateTime >> 16, sDate);
+ NWUnpackTime(dateTime & 0xffff, sTime);
+}
+
+void
+NWUnpackDate(nuint16 date, NW_DATE *sDate) {
+ sDate->day = date & 0x1f;
+ sDate->month = (date >> 5) & 0xf;
+ sDate->year = ((date >> 9) & 0x7f) + 1980;
+}
+
+void
+NWUnpackTime(nuint16 time, NW_TIME *sTime) {
+ sTime->seconds = time & 0x1f;
+ sTime->minutes = (time >> 5) & 0x3f;
+ sTime->hours = (time >> 11) & 0x1f;
+}
+
+nuint32
+NWPackDateTime(NW_DATE *sDate, NW_TIME *sTime) {
+ return 0;
+}
+
+nuint16
+NWPackDate(NW_DATE *sDate) {
+ return 0;
+}
+
+nuint16
+NWPackTime(NW_TIME *sTime) {
+ return 0;
+}
+
+time_t
+ncp_UnpackDateTime(nuint32 dateTime) {
+ struct tm u_time;
+ NW_DATE d;
+ NW_TIME t;
+
+ NWUnpackDateTime(dateTime, &d, &t);
+ bzero(&u_time,sizeof(struct tm));
+ u_time.tm_isdst = -1;
+ u_time.tm_sec = t.seconds;
+ u_time.tm_min = t.minutes;
+ u_time.tm_hour = t.hours;
+ u_time.tm_mday = d.day;
+ u_time.tm_mon = d.month - 1;
+ u_time.tm_year = d.year - 1900;
+
+ return mktime(&u_time);
+}
+
+int
+ncp_GetFileServerDateAndTime(NWCONN_HANDLE cH, time_t *target) {
+ int error;
+ DECLARE_RQ;
+
+ ncp_init_request(conn);
+ if ((error = ncp_request(cH, 20, conn)) != 0)
+ return error;
+ *target = ncp_nw_to_ctime((struct nw_time_buffer *) ncp_reply_data(conn, 0));
+ return 0;
+}
+
+int
+ncp_SetFileServerDateAndTime(NWCONN_HANDLE cH, time_t * source) {
+ int year;
+ struct tm *utime = localtime(source);
+ DECLARE_RQ;
+
+ year = utime->tm_year;
+ if (year > 99) {
+ year -= 100;
+ }
+ ncp_init_request_s(conn, 202);
+ ncp_add_byte(conn, year);
+ ncp_add_byte(conn, utime->tm_mon + 1);
+ ncp_add_byte(conn, utime->tm_mday);
+ ncp_add_byte(conn, utime->tm_hour);
+ ncp_add_byte(conn, utime->tm_min);
+ ncp_add_byte(conn, utime->tm_sec);
+ return ncp_request(cH, 23, conn);
+}
+
+NWCCODE
+NWDownFileServer(NWCONN_HANDLE cH, int force) {
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 211);
+ ncp_add_byte(conn, force ? 0 : 0xff);
+ return ncp_request(cH, 23, conn);
+}
+
+NWCCODE
+NWCloseBindery(NWCONN_HANDLE cH) {
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 68);
+ return ncp_request(cH, 23, conn);
+}
+
+NWCCODE
+NWOpenBindery(NWCONN_HANDLE cH) {
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 69);
+ return ncp_request(cH, 23, conn);
+}
+
+NWCCODE
+NWDisableTTS(NWCONN_HANDLE cH) {
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 207);
+ return ncp_request(cH, 23, conn);
+}
+
+NWCCODE
+NWEnableTTS(NWCONN_HANDLE cH) {
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 208);
+ return ncp_request(cH, 23, conn);
+}
+
+NWCCODE
+NWDisableFileServerLogin(NWCONN_HANDLE cH) {
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 203);
+ return ncp_request(cH, 23, conn);
+}
+
+NWCCODE
+NWEnableFileServerLogin(NWCONN_HANDLE cH) {
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 204);
+ return ncp_request(cH, 23, conn);
+}
diff --git a/lib/libncp/ncpl_msg.c b/lib/libncp/ncpl_msg.c
new file mode 100644
index 0000000..5af2d72
--- /dev/null
+++ b/lib/libncp/ncpl_msg.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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 Boris Popov.
+ * 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 THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 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 <stdio.h>
+#include <strings.h>
+
+#include <netncp/ncp_lib.h>
+#include <netncp/ncp_nls.h>
+
+NWCCODE
+NWDisableBroadcasts(NWCONN_HANDLE connHandle) {
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 2);
+ return ncp_request(connHandle, 21, conn);
+}
+
+NWCCODE
+NWEnableBroadcasts(NWCONN_HANDLE connHandle) {
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 3);
+ return ncp_request(connHandle, 21, conn);
+}
+
+NWCCODE
+NWBroadcastToConsole(NWCONN_HANDLE connHandle, pnstr8 message) {
+ int l, error;
+ DECLARE_RQ;
+
+ l = strlen(message);
+ if (l > 60) return EMSGSIZE;
+ ncp_init_request_s(conn, 9);
+ ncp_add_byte(conn, l);
+ ncp_add_mem_nls(conn, message, l);
+ error = ncp_request(connHandle, 21, conn);
+ return error;
+}
+
+NWCCODE
+NWSendBroadcastMessage(NWCONN_HANDLE connHandle, pnstr8 message,
+ nuint16 connCount, pnuint16 connList, pnuint8 resultList)
+{
+ int l, i, error;
+ DECLARE_RQ;
+
+ l = strlen(message);
+ if (l > 255) return EMSGSIZE;
+ if (connCount > 350) return EINVAL;
+
+ ncp_init_request_s(conn, 0x0A);
+ ncp_add_word_lh(conn, connCount);
+ for (i = 0; i < connCount; i++)
+ ncp_add_dword_lh(conn, connList[i]);
+ ncp_add_byte(conn, l);
+ ncp_add_mem_nls(conn, message, l);
+ error = ncp_request(connHandle, 0x15, conn);
+ if (!error) {
+ l = ncp_reply_word_lh(conn, 0);
+ for (i = 0; i < l; i++)
+ resultList[i] = ncp_reply_dword_lh(conn, (i)*4 + 2);
+ return 0;
+ }
+ if (error != 0xfb) return error;
+ if (l > 58) return EMSGSIZE;
+ ncp_init_request_s(conn, 0);
+ ncp_add_byte(conn, connCount);
+ for (i = 0; i < connCount; i++)
+ ncp_add_byte(conn, connList[i]);
+ ncp_add_byte(conn, l);
+ ncp_add_mem_nls(conn, message, l);
+ error = ncp_request(connHandle, 0x15, conn);
+ if (error) return error;
+ i = ncp_reply_byte(conn, 0);
+ memcpy(resultList, ncp_reply_data(conn, 1), i);
+ return 0;
+}
+
+
+NWCCODE
+NWGetBroadcastMessage(NWCONN_HANDLE connHandle, pnstr8 message) {
+ int i, error;
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 0x0B);
+ error = ncp_request(connHandle, 0x15, conn);
+ if (error) {
+ if (error != 0x89fb) return error;
+ ncp_init_request_s(conn, 0x01);
+ if ((error = ncp_request(connHandle, 0x15, conn)) != 0)
+ return error;
+ }
+ i = ncp_reply_byte(conn, 0);
+ if (i == 0) return ENOENT;
+ memcpy(message, ncp_reply_data(conn, 1), i);
+ message[i] = 0;
+ ncp_nls_str_n2u(message, message);
+ return 0;
+}
diff --git a/lib/libncp/ncpl_net.c b/lib/libncp/ncpl_net.c
new file mode 100644
index 0000000..c161ce1
--- /dev/null
+++ b/lib/libncp/ncpl_net.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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 Boris Popov.
+ * 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 THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 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/types.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/syscall.h>
+#include <ctype.h>
+#include <netinet/in.h>
+#include <netipx/ipx.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include "ipxsap.h"
+#include <netncp/ncp_lib.h>
+
+static int ncp_find_server_in(struct ncp_conn_loginfo *li, int type, char *server_name);
+
+static int
+ncp_find_server_ipx(struct ncp_conn_loginfo *li, int type) {
+ char server[NCP_BINDERY_NAME_LEN + 1];
+ int error;
+ char nearest[NCP_BINDERY_NAME_LEN + 1];
+ struct nw_property prop;
+ struct ipx_addr *n_addr = (struct ipx_addr *) &prop;
+/* struct ncp_conn_loginfo ltmp;*/
+ int connid;
+
+ bzero(server, sizeof(server));
+ bzero(nearest, sizeof(nearest));
+
+ strcpy(server, li->server);
+ ncp_str_upper(server);
+
+ if ((error = sap_find_nearest(type, &li->ipxaddr, nearest)) != 0) {
+ return error;
+ }
+ /* if no server specified return info about nearest */
+ if (!li->server[0]) {
+ strcpy(li->server, nearest);
+ return 0;
+ }
+/* printf("%s\n",ipx_ntoa(li->ipxaddr.sipx_addr));*/
+ if (strcmp(server, nearest) == 0) {
+ return 0;
+ }
+ /* We have to ask the nearest server for our wanted server */
+ li->opt=0;
+ if ((error = ncp_connect(li, &connid)) != 0) {
+ return error;
+ }
+ if (ncp_read_property_value(connid, type, server, 1, "NET_ADDRESS", &prop) != 0) {
+ ncp_disconnect(connid);
+ return EHOSTUNREACH;
+ }
+ if ((error = ncp_disconnect(connid)) != 0) {
+ return error;
+ }
+ li->ipxaddr.sipx_family = AF_IPX;
+ li->ipxaddr.sipx_addr.x_net = n_addr->x_net;
+ li->ipxaddr.sipx_port = n_addr->x_port;
+ li->ipxaddr.sipx_addr.x_host = n_addr->x_host;
+ return 0;
+}
+
+static int
+ncp_find_server_in(struct ncp_conn_loginfo *li, int type, char *server_name) {
+ struct hostent* h;
+ int l;
+
+ h = gethostbyname(server_name);
+ if (!h) {
+ fprintf(stderr, "Get host address `%s': ", server_name);
+ herror(NULL);
+ return 1;
+ }
+ if (h->h_addrtype != AF_INET) {
+ fprintf(stderr, "Get host address `%s': Not AF_INET\n", server_name);
+ return 1;
+ }
+ if (h->h_length != 4) {
+ fprintf(stderr, "Get host address `%s': Bad address length\n", server_name);
+ return 1;
+ }
+ l = sizeof(struct sockaddr_in);
+ bzero(&li->inaddr, l);
+ li->inaddr.sin_len = l;
+ li->inaddr.sin_family = h->h_addrtype;
+ memcpy(&li->inaddr.sin_addr.s_addr, h->h_addr, 4);
+ li->inaddr.sin_port = htons(524); /* ncp */
+ return 0;
+}
+
+int
+ncp_find_server(struct ncp_conn_loginfo *li, int type, int af, char *name) {
+ int error = EHOSTUNREACH;
+
+ switch(af) {
+ case AF_IPX:
+ error = ncp_find_server_ipx(li, type);
+ break;
+ case AF_INET:
+ if (name)
+ error = ncp_find_server_in(li, type, name);
+ break;
+ default:
+ error = EPROTONOSUPPORT;
+ }
+ return error;
+}
+
+int
+ncp_find_fileserver(struct ncp_conn_loginfo *li, int af, char *name) {
+ return ncp_find_server(li, NCP_BINDERY_FSERVER, af, name);
+}
diff --git a/lib/libncp/ncpl_nls.c b/lib/libncp/ncpl_nls.c
new file mode 100644
index 0000000..68fae01
--- /dev/null
+++ b/lib/libncp/ncpl_nls.c
@@ -0,0 +1,350 @@
+/*
+ * Copyright (c) 1999-2002, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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 Boris Popov.
+ * 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 THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Languages support. Currently is very primitive.
+ */
+#include <sys/types.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <strings.h>
+#include <locale.h>
+
+#include <netncp/ncp_lib.h>
+#include <netncp/ncp_cfg.h>
+#include <netncp/ncp_nls.h>
+
+#ifndef NCP_NLS_DEFAULT
+#define NCP_NLS_DEFAULT NCP_NLS_AS_IS
+#endif
+
+/*
+ * TODO: Make all tables dynamically loadable.
+ */
+#ifdef NCP_NLS_KOI2CP866
+/* Russian tables from easy-cyrillic:
+ * Copyright (C) 1993-1994 by Andrey A. Chernov, Moscow, Russia
+ */
+static u_int8_t alt2koi8[] = {
+ 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, /* 0x00 */
+ 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f,
+ 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, /* 0x10 */
+ 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x5f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60 */
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70 */
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0xe1, 0xe2, 0xf7, 0xe7, 0xe4, 0xe5, 0xf6, 0xfa,
+ 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0,
+ 0xf2, 0xf3, 0xf4, 0xf5, 0xe6, 0xe8, 0xe3, 0xfe,
+ 0xfb, 0xfd, 0xff, 0xf9, 0xf8, 0xfc, 0xe0, 0xf1,
+ 0xc1, 0xc2, 0xd7, 0xc7, 0xc4, 0xc5, 0xd6, 0xda,
+ 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0,
+ 0x90, 0x91, 0x92, 0x81, 0x87, 0xb2, 0xb4, 0xa7,
+ 0xa6, 0xb5, 0xa1, 0xa8, 0xae, 0xad, 0xac, 0x83,
+ 0x84, 0x89, 0x88, 0x86, 0x80, 0x8a, 0xaf, 0xb0,
+ 0xab, 0xa5, 0xbb, 0xb8, 0xb1, 0xa0, 0xbe, 0xb9,
+ 0xba, 0xb6, 0xb7, 0xaa, 0xa9, 0xa2, 0xa4, 0xbd,
+ 0xbc, 0x85, 0x82, 0x8d, 0x8c, 0x8e, 0x8f, 0x8b,
+ 0xd2, 0xd3, 0xd4, 0xd5, 0xc6, 0xc8, 0xc3, 0xde,
+ 0xdb, 0xdd, 0xdf, 0xd9, 0xd8, 0xdc, 0xc0, 0xd1,
+ 0xb3, 0xa3, 0x99, 0x98, 0x93, 0x9b, 0x9f, 0x97,
+ 0x9c, 0x95, 0x9e, 0x96, 0xbf, 0x9d, 0x94, 0x9a
+};
+
+static u_int8_t koi82alt[] = {
+ 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, /* 0x00 */
+ 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f,
+ 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, /* 0x10 */
+ 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x5f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60 */
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70 */
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0xc4, 0xb3, 0xda, 0xbf, 0xc0, 0xd9, 0xc3, 0xb4, /* 0x80 */
+ 0xc2, 0xc1, 0xc5, 0xdf, 0xdc, 0xdb, 0xdd, 0xde,
+ 0xb0, 0xb1, 0xb2, 0xf4, 0xfe, 0xf9, 0xfb, 0xf7,
+ 0xf3, 0xf2, 0xff, 0xf5, 0xf8, 0xfd, 0xfa, 0xf6,
+ 0xcd, 0xba, 0xd5, 0xf1, 0xd6, 0xc9, 0xb8, 0xb7,
+ 0xbb, 0xd4, 0xd3, 0xc8, 0xbe, 0xbd, 0xbc, 0xc6,
+ 0xc7, 0xcc, 0xb5, 0xf0, 0xb6, 0xb9, 0xd1, 0xd2,
+ 0xcb, 0xcf, 0xd0, 0xca, 0xd8, 0xd7, 0xce, 0xfc,
+ 0xee, 0xa0, 0xa1, 0xe6, 0xa4, 0xa5, 0xe4, 0xa3,
+ 0xe5, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae,
+ 0xaf, 0xef, 0xe0, 0xe1, 0xe2, 0xe3, 0xa6, 0xa2,
+ 0xec, 0xeb, 0xa7, 0xe8, 0xed, 0xe9, 0xe7, 0xea,
+ 0x9e, 0x80, 0x81, 0x96, 0x84, 0x85, 0x94, 0x83,
+ 0x95, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
+ 0x8f, 0x9f, 0x90, 0x91, 0x92, 0x93, 0x86, 0x82, /* 0xf0 */
+ 0x9c, 0x9b, 0x87, 0x98, 0x9d, 0x99, 0x97, 0x9a
+};
+
+#endif
+
+/*
+ * Characters mapping for codepages used in Sweden.
+ */
+static u_int8_t se_nw2unix[] = {
+ 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, /* 0x00 */
+ 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f,
+ 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, /* 0x10 */
+ 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x5f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60 */
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70 */
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0xe1, 0xe2, 0xf7, 0xe7, 0xE4, 0xc4, 0xE5, 0xfa, /* 0x80 */
+ 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xC4, 0xC5,
+ 0xf2, 0xf3, 0xf4, 0xf5, 0xF6, 0xe8, 0xe3, 0xfe, /* 0x90 */
+ 0xfb, 0xD6, 0xff, 0xf9, 0xf8, 0xfc, 0xe0, 0xf1,
+ 0xc1, 0xc2, 0xd7, 0xc7, 0xc4, 0xc5, 0xd6, 0xda, /* 0xA0 */
+ 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0,
+ 0x90, 0x91, 0x92, 0x81, 0x87, 0xb2, 0xb4, 0xa7, /* 0xB0 */
+ 0xa6, 0xb5, 0xa1, 0xa8, 0xae, 0xad, 0xac, 0x83,
+ 0x84, 0x89, 0x88, 0x86, 0x80, 0x8a, 0xaf, 0xb0, /* 0xC0 */
+ 0xab, 0xa5, 0xbb, 0xb8, 0xb1, 0xa0, 0xbe, 0xb9,
+ 0xba, 0xb6, 0xb7, 0xaa, 0xa9, 0xa2, 0xa4, 0xbd, /* 0xD0 */
+ 0xbc, 0x85, 0x82, 0x8d, 0x8c, 0x8e, 0x8f, 0x8b,
+ 0xd2, 0xd3, 0xd4, 0xd5, 0xc6, 0xc8, 0xc3, 0xde, /* 0xE0 */
+ 0xdb, 0xdd, 0xdf, 0xd9, 0xd8, 0xdc, 0xc0, 0xd1,
+ 0xb3, 0xa3, 0x99, 0x98, 0x93, 0x9b, 0x9f, 0x97, /* 0xF0 */
+ 0x9c, 0x95, 0x9e, 0x96, 0xbf, 0x9d, 0x94, 0x9a
+};
+
+static u_int8_t se_unix2nw[] = {
+ 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, /* 0x00 */
+ 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f,
+ 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, /* 0x10 */
+ 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x5f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60 */
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70 */
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0xc4, 0xb3, 0xda, 0xbf, 0xc0, 0xd9, 0xc3, 0xb4, /* 0x80 */
+ 0xc2, 0xc1, 0xc5, 0xdf, 0xdc, 0xdb, 0xdd, 0xde,
+ 0xb0, 0xb1, 0xb2, 0xf4, 0xfe, 0xf9, 0xfb, 0xf7, /* 0x90 */
+ 0xf3, 0xf2, 0xff, 0xf5, 0xf8, 0xfd, 0xfa, 0xf6,
+ 0xcd, 0xba, 0xd5, 0xf1, 0xd6, 0xc9, 0xb8, 0xb7, /* 0xA0 */
+ 0xbb, 0xd4, 0xd3, 0xc8, 0xbe, 0xbd, 0xbc, 0xc6,
+ 0xc7, 0xcc, 0xb5, 0xf0, 0xb6, 0xb9, 0xd1, 0xd2, /* 0xB0 */
+ 0xcb, 0xcf, 0xd0, 0xca, 0xd8, 0xd7, 0xce, 0xfc,
+ 0xee, 0xa0, 0xa1, 0xe6, 0x8E, 0x8F, 0xe4, 0xa3, /* 0xC0 */
+ 0xe5, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae,
+ 0xaf, 0xef, 0xe0, 0xe1, 0xe2, 0xe3, 0x99, 0xa2, /* 0xD0 */
+ 0xec, 0xeb, 0xa7, 0xe8, 0xed, 0xe9, 0xe7, 0xea,
+ 0x9e, 0x80, 0x81, 0x96, 0x84, 0x86, 0x94, 0x83, /* 0xE0 */
+ 0x95, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
+ 0x8f, 0x9f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x82, /* 0xf0 */
+ 0x9c, 0x9b, 0x87, 0x98, 0x9d, 0x99, 0x97, 0x9a
+};
+
+
+static u_int8_t def2lower[256];
+static u_int8_t def2upper[256];
+
+/*
+ * List of available charsets
+ */
+struct ncp_nlsdesc {
+ int scheme;
+ char *name;
+ struct ncp_nlstables nls;
+};
+
+static struct ncp_nlsdesc ncp_nlslist[] = {
+ {NCP_NLS_AS_IS, NCP_NLS_AS_IS_NAME,
+ {def2lower, def2upper, NULL, NULL, 0}
+ },
+#ifdef NCP_NLS_KOI2CP866
+ {NCP_NLS_KOI_866, NCP_NLS_KOI_866_NAME,
+ {def2lower, def2upper, alt2koi8, koi82alt, 0}
+ },
+#endif
+ {NCP_NLS_SE, NCP_NLS_SE_NAME,
+ {def2lower, def2upper, se_nw2unix, se_unix2nw, 0}
+ },
+ {0}
+};
+
+struct ncp_nlstables ncp_nls;
+
+int
+ncp_nls_setlocale(char *name) {
+ int i;
+
+ ncp_nls.to_lower = def2lower;
+ ncp_nls.to_upper = def2upper;
+ if (setlocale(LC_CTYPE, name) == NULL) {
+ fprintf(stderr, "Can't set locale '%s'\n", name);
+ return EINVAL;
+ }
+ for (i = 0; i < 256; i++) {
+ ncp_nls.to_lower[i] = tolower(i);
+ ncp_nls.to_upper[i] = toupper(i);
+ }
+ return 0;
+}
+
+int
+ncp_nls_setrecode(int scheme) {
+ struct ncp_nlsdesc *nd;
+
+ if (scheme == 0) {
+#if NCP_NLS_DEFAULT
+ scheme = NCP_NLS_DEFAULT;
+#else
+ scheme = NCP_NLS_AS_IS;
+#endif
+ }
+ for (nd = ncp_nlslist; nd->name; nd++) {
+ if (nd->scheme != scheme) continue;
+ ncp_nls.u2n = nd->nls.u2n;
+ ncp_nls.n2u = nd->nls.n2u;
+ return ncp_nls_setlocale("");
+ }
+ fprintf(stderr, "Character conversion scheme %d was not compiled in\n", scheme);
+ return EINVAL;
+}
+
+int
+ncp_nls_setrecodebyname(char *name) {
+ struct ncp_nlsdesc *nd;
+
+ for (nd = ncp_nlslist; nd->name; nd++) {
+ if (strcmp(nd->name, name) != 0) continue;
+ ncp_nls.u2n = nd->nls.u2n;
+ ncp_nls.n2u = nd->nls.n2u;
+ return 0;
+ }
+ fprintf(stderr, "Character conversion scheme %s was not compiled in\n", name);
+ return EINVAL;
+}
+
+char *
+ncp_nls_str_n2u(char *dst, const char *src) {
+ char *p;
+
+ if (ncp_nls.n2u == NULL) {
+ return strcpy(dst, src);
+ }
+ p = dst;
+ while (*src)
+ *p++ = ncp_nls.n2u[(u_char)*(src++)];
+ *p = 0;
+ return dst;
+}
+
+char *
+ncp_nls_str_u2n(char *dst, const char *src) {
+ char *p;
+
+ if (ncp_nls.u2n == NULL) {
+ return strcpy(dst, src);
+ }
+ p = dst;
+ while (*src)
+ *p++ = ncp_nls.u2n[(u_char)*(src++)];
+ *p = 0;
+ return dst;
+}
+
+char *
+ncp_nls_mem_n2u(char *dst, const char *src, int size) {
+ char *p;
+
+ if (size == 0) return NULL;
+ if (ncp_nls.n2u == NULL) {
+ return memcpy(dst, src, size);
+ }
+ for(p = dst; size; size--, p++)
+ *p = ncp_nls.n2u[(u_char)*(src++)];
+ return dst;
+}
+
+char *
+ncp_nls_mem_u2n(char *dst, const char *src, int size) {
+ char *p;
+
+ if (size == 0) return NULL;
+ if (ncp_nls.u2n == NULL) {
+ return strcpy(dst, src);
+ }
+ for(p = dst; size; size--, p++)
+ *p = ncp_nls.u2n[(u_char)*(src++)];
+ return dst;
+}
+
+char *
+ncp_str_upper(char *s) {
+ char *p = s;
+ while (*s) {
+ *s = toupper(*s);
+ s++;
+ }
+ return p;
+}
diff --git a/lib/libncp/ncpl_queue.c b/lib/libncp/ncpl_queue.c
new file mode 100644
index 0000000..1f003a1
--- /dev/null
+++ b/lib/libncp/ncpl_queue.c
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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 Boris Popov.
+ * 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 THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * NetWare queue interface
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <errno.h>
+#include <stdio.h>
+#include <netncp/ncp_lib.h>
+
+int
+ncp_create_queue_job_and_file(NWCONN_HANDLE connid, u_int32_t queue_id,
+ struct queue_job *job)
+{
+ int error;
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 121);
+ ncp_add_dword_hl(conn, queue_id);
+ ncp_add_mem(conn, &(job->j), sizeof(job->j));
+
+ if ((error = ncp_request(connid, 23, conn)) != 0)
+ return error;
+ memcpy(&(job->j), ncp_reply_data(conn, 0), 78);
+ ConvertToNWfromDWORD(job->j.JobFileHandle, &job->file_handle);
+ return 0;
+}
+
+int
+ncp_close_file_and_start_job(NWCONN_HANDLE connid, u_int32_t queue_id,
+ struct queue_job *job)
+{
+ int error;
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 127);
+ ncp_add_dword_hl(conn, queue_id);
+ ncp_add_dword_lh(conn, job->j.JobNumber);
+ error = ncp_request(connid, 23, conn);
+ return error;
+}
+
+int
+ncp_attach_to_queue(NWCONN_HANDLE connid, u_int32_t queue_id) {
+ int error;
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 111);
+ ncp_add_dword_hl(conn, queue_id);
+ error = ncp_request(connid, 23, conn);
+ return error;
+}
+
+int
+ncp_detach_from_queue(NWCONN_HANDLE connid, u_int32_t queue_id) {
+ int error;
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 112);
+ ncp_add_dword_hl(conn, queue_id);
+ error= ncp_request(connid, 23, conn);
+ return error;
+}
+
+int
+ncp_service_queue_job(NWCONN_HANDLE connid, u_int32_t queue_id,
+ u_int16_t job_type, struct queue_job *job)
+{
+ int error;
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 124);
+ ncp_add_dword_hl(conn, queue_id);
+ ncp_add_word_hl(conn, job_type);
+ if ((error = ncp_request(connid, 23, conn)) != 0) {
+ return error;
+ }
+ memcpy(&(job->j), ncp_reply_data(conn, 0), 78);
+ ConvertToNWfromDWORD(job->j.JobFileHandle, &job->file_handle);
+ return error;
+}
+
+int
+ncp_finish_servicing_job(NWCONN_HANDLE connid, u_int32_t queue_id,
+ u_int32_t job_number, u_int32_t charge_info)
+{
+ int error;
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 131);
+ ncp_add_dword_hl(conn, queue_id);
+ ncp_add_dword_lh(conn, job_number);
+ ncp_add_dword_hl(conn, charge_info);
+
+ error = ncp_request(connid, 23, conn);
+ return error;
+}
+
+int
+ncp_abort_servicing_job(NWCONN_HANDLE connid, u_int32_t queue_id,
+ u_int32_t job_number)
+{
+ int error;
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 132);
+ ncp_add_dword_hl(conn, queue_id);
+ ncp_add_dword_lh(conn, job_number);
+ error = ncp_request(connid, 23, conn);
+ return error;
+}
+
+int
+ncp_get_queue_length(NWCONN_HANDLE connid, u_int32_t queue_id,
+ u_int32_t *queue_length)
+{
+ int error;
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 125);
+ ncp_add_dword_hl(conn, queue_id);
+
+ if ((error = ncp_request(connid, 23, conn)) != 0)
+ return error;
+ if (conn->rpsize < 12) {
+ ncp_printf("ncp_reply_size %d < 12\n", conn->rpsize);
+ return EINVAL;
+ }
+ if (ncp_reply_dword_hl(conn,0) != queue_id) {
+ printf("Ouch! Server didn't reply with same queue id in ncp_get_queue_length!\n");
+ return EINVAL;
+ }
+ *queue_length = ncp_reply_dword_lh(conn,8);
+ return error;
+}
+
+int
+ncp_get_queue_job_ids(NWCONN_HANDLE connid, u_int32_t queue_id,
+ u_int32_t queue_section, u_int32_t *length1, u_int32_t *length2,
+ u_int32_t ids[])
+{
+ int error;
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn,129);
+ ncp_add_dword_hl(conn, queue_id);
+ ncp_add_dword_lh(conn, queue_section);
+
+ if ((error = ncp_request(connid, 23, conn)) != 0)
+ return error;
+ if (conn->rpsize < 8) {
+ ncp_printf("ncp_reply_size %d < 8\n", conn->rpsize);
+ return EINVAL;
+ }
+ *length2 = ncp_reply_dword_lh(conn,4);
+ if (conn->rpsize < 8 + 4*(*length2)) {
+ ncp_printf("ncp_reply_size %d < %d\n", conn->rpsize, 8+4*(*length2));
+ return EINVAL;
+ }
+ if (ids) {
+ int count = min(*length1, *length2)*sizeof(u_int32_t);
+ int pos;
+
+ for (pos=0; pos<count; pos+=sizeof(u_int32_t)) {
+ *ids++ = ncp_reply_dword_lh(conn, 8+pos);
+ }
+ }
+ *length1 = ncp_reply_dword_lh(conn,0);
+ return error;
+}
+
+int
+ncp_get_queue_job_info(NWCONN_HANDLE connid, u_int32_t queue_id,
+ u_int32_t job_id, struct nw_queue_job_entry *jobdata)
+{
+ int error;
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn,122);
+ ncp_add_dword_hl(conn, queue_id);
+ ncp_add_dword_lh(conn, job_id);
+
+ if ((error = ncp_request(connid, 23, conn)) != 0)
+ return error;
+
+ if (conn->rpsize < sizeof(struct nw_queue_job_entry)) {
+ ncp_printf("ncp_reply_size %d < %d\n", conn->rpsize,sizeof(struct nw_queue_job_entry));
+ return EINVAL;
+ }
+ memcpy(jobdata,ncp_reply_data(conn,0), sizeof(struct nw_queue_job_entry));
+ return error;
+}
diff --git a/lib/libncp/ncpl_rcfile.c b/lib/libncp/ncpl_rcfile.c
new file mode 100644
index 0000000..72395f3
--- /dev/null
+++ b/lib/libncp/ncpl_rcfile.c
@@ -0,0 +1,409 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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 Boris Popov.
+ * 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 THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 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 <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <pwd.h>
+#include <unistd.h>
+
+#include <netncp/ncp_lib.h>
+#include <netncp/ncp_rcfile.h>
+#include <netncp/ncp_cfg.h>
+
+#define NWFS_CFG_FILE NCP_PREFIX"/etc/nwfs.conf"
+
+struct rcfile *ncp_rc = NULL;
+
+SLIST_HEAD(rcfile_head, rcfile);
+static struct rcfile_head pf_head = {NULL};
+
+int rc_merge(char *filename,struct rcfile **rcfile);
+static struct rcfile* rc_find(char *filename);
+static struct rcsection *rc_findsect(struct rcfile *rcp, char *sectname);
+static struct rcsection *rc_addsect(struct rcfile *rcp, char *sectname);
+static int rc_sect_free(struct rcsection *rsp);
+static struct rckey *rc_sect_findkey(struct rcsection *rsp, char *keyname);
+static struct rckey *rc_sect_addkey(struct rcsection *rsp, char *name, char *value);
+static void rc_key_free(struct rckey *p);
+static void rc_parse(struct rcfile *rcp);
+
+
+/*
+ * open rcfile and load its content, if already open - return previous handle
+ */
+int
+rc_open(char *filename,char *mode,struct rcfile **rcfile) {
+ struct rcfile *rcp;
+ FILE *f;
+
+ rcp = rc_find(filename);
+ if( rcp ) {
+ *rcfile = rcp;
+ return 0;
+ }
+ f = fopen (filename, mode);
+ if (f==NULL)
+ return errno;
+ rcp = malloc(sizeof(struct rcfile));
+ if (rcp==NULL) {
+ fclose(f);
+ return ENOMEM;
+ }
+ bzero(rcp, sizeof(struct rcfile));
+ rcp->rf_name = strdup (filename);
+ rcp->rf_f = f;
+ SLIST_INSERT_HEAD(&pf_head, rcp, rf_next);
+ rc_parse(rcp);
+ *rcfile = rcp;
+ return 0;
+}
+
+int
+rc_merge(char *filename,struct rcfile **rcfile) {
+ struct rcfile *rcp = *rcfile;
+ FILE *f, *t;
+
+ if (rcp == NULL) {
+ return rc_open(filename,"r",rcfile);
+ }
+ f = fopen (filename, "r");
+ if (f==NULL)
+ return errno;
+ t = rcp->rf_f;
+ rcp->rf_f = f;
+ rc_parse(rcp);
+ rcp->rf_f = t;
+ fclose(f);
+ return 0;
+}
+
+int
+rc_close(struct rcfile *rcp) {
+ struct rcsection *p,*n;
+
+ fclose(rcp->rf_f);
+ for(p = SLIST_FIRST(&rcp->rf_sect);p;) {
+ n = p;
+ p = SLIST_NEXT(p,rs_next);
+ rc_sect_free(n);
+ }
+ free(rcp->rf_name);
+ SLIST_REMOVE(&pf_head, rcp, rcfile, rf_next);
+ free(rcp);
+ return 0;
+}
+
+static struct rcfile*
+rc_find(char *filename) {
+ struct rcfile *p;
+
+ SLIST_FOREACH(p, &pf_head, rf_next)
+ if (strcmp (filename, p->rf_name)==0)
+ return p;
+ return 0;
+}
+
+static struct rcsection *
+rc_findsect(struct rcfile *rcp, char *sectname) {
+ struct rcsection *p;
+
+ SLIST_FOREACH(p, &rcp->rf_sect, rs_next)
+ if (strcmp(p->rs_name, sectname)==0)
+ return p;
+ return NULL;
+}
+
+static struct rcsection *
+rc_addsect(struct rcfile *rcp, char *sectname) {
+ struct rcsection *p;
+
+ p = rc_findsect(rcp, sectname);
+ if (p) return p;
+ p = malloc(sizeof(*p));
+ if (!p) return NULL;
+ p->rs_name = strdup(sectname);
+ SLIST_INIT(&p->rs_keys);
+ SLIST_INSERT_HEAD(&rcp->rf_sect, p, rs_next);
+ return p;
+}
+
+static int
+rc_sect_free(struct rcsection *rsp) {
+ struct rckey *p,*n;
+
+ for(p = SLIST_FIRST(&rsp->rs_keys);p;) {
+ n = p;
+ p = SLIST_NEXT(p,rk_next);
+ rc_key_free(n);
+ }
+ free(rsp->rs_name);
+ free(rsp);
+ return 0;
+}
+
+static struct rckey *
+rc_sect_findkey(struct rcsection *rsp, char *keyname) {
+ struct rckey *p;
+
+ SLIST_FOREACH(p, &rsp->rs_keys, rk_next)
+ if (strcmp(p->rk_name, keyname)==0)
+ return p;
+ return NULL;
+}
+
+static struct rckey *
+rc_sect_addkey(struct rcsection *rsp, char *name, char *value) {
+ struct rckey *p;
+
+ p = rc_sect_findkey(rsp, name);
+ if (p) {
+ free(p->rk_value);
+ } else {
+ p = malloc(sizeof(*p));
+ if (!p) return NULL;
+ SLIST_INSERT_HEAD(&rsp->rs_keys, p, rk_next);
+ p->rk_name = strdup(name);
+ }
+ p->rk_value = value ? strdup(value) : strdup("");
+ return p;
+}
+
+void
+rc_sect_delkey(struct rcsection *rsp, struct rckey *p) {
+
+ SLIST_REMOVE(&rsp->rs_keys,p,rckey,rk_next);
+ rc_key_free(p);
+ return;
+}
+
+static void
+rc_key_free(struct rckey *p){
+ free(p->rk_value);
+ free(p->rk_name);
+ free(p);
+}
+
+enum { stNewLine, stHeader, stSkipToEOL, stGetKey, stGetValue};
+
+static void
+rc_parse(struct rcfile *rcp) {
+ FILE *f = rcp->rf_f;
+ int state = stNewLine, c;
+ struct rcsection *rsp = NULL;
+ struct rckey *rkp = NULL;
+ char buf[2048];
+ char *next = buf, *last = &buf[sizeof(buf)-1];
+
+ while ((c = getc (f)) != EOF) {
+ if (c == '\r')
+ continue;
+ if (state == stNewLine) {
+ next = buf;
+ if (isspace(c))
+ continue; /* skip leading junk */
+ if (c == '[') {
+ state = stHeader;
+ rsp = NULL;
+ continue;
+ }
+ if (c == '#' || c == ';') {
+ state = stSkipToEOL;
+ } else { /* something meaningfull */
+ state = stGetKey;
+ }
+ }
+ if (state == stSkipToEOL || next == last) {/* ignore long lines */
+ if (c == '\n'){
+ state = stNewLine;
+ next = buf;
+ }
+ continue;
+ }
+ if (state == stHeader) {
+ if (c == ']') {
+ *next = 0;
+ next = buf;
+ rsp = rc_addsect(rcp, buf);
+ state = stSkipToEOL;
+ } else
+ *next++ = c;
+ continue;
+ }
+ if (state == stGetKey) {
+ if (c == ' ' || c == '\t')/* side effect: 'key name='*/
+ continue; /* become 'keyname=' */
+ if (c == '\n') { /* silently ignore ... */
+ state = stNewLine;
+ continue;
+ }
+ if (c != '=') {
+ *next++ = c;
+ continue;
+ }
+ *next = 0;
+ if (rsp == NULL) {
+ fprintf(stderr, "Key '%s' defined before section\n", buf);
+ state = stSkipToEOL;
+ continue;
+ }
+ rkp = rc_sect_addkey(rsp, buf, NULL);
+ next = buf;
+ state = stGetValue;
+ continue;
+ }
+ /* only stGetValue left */
+ if (state != stGetValue) {
+ fprintf(stderr, "Well, I can't parse file '%s'\n",rcp->rf_name);
+ state = stSkipToEOL;
+ }
+ if (c != '\n') {
+ *next++ = c;
+ continue;
+ }
+ *next = 0;
+ rkp->rk_value = strdup(buf);
+ state = stNewLine;
+ rkp = NULL;
+ } /* while */
+ if (c == EOF && state == stGetValue) {
+ *next = 0;
+ rkp->rk_value = strdup(buf);
+ }
+ return;
+}
+
+int
+rc_getstringptr(struct rcfile *rcp,char *section, char *key,char **dest) {
+ struct rcsection *rsp;
+ struct rckey *rkp;
+
+ *dest = NULL;
+ rsp = rc_findsect(rcp, section);
+ if (!rsp) return ENOENT;
+ rkp = rc_sect_findkey(rsp,key);
+ if (!rkp) return ENOENT;
+ *dest = rkp->rk_value;
+ return 0;
+}
+
+int
+rc_getstring(struct rcfile *rcp,char *section, char *key,int maxlen,char *dest) {
+ char *value;
+ int error;
+
+ error = rc_getstringptr(rcp, section, key, &value);
+ if (error) return error;
+ if (strlen(value) >= maxlen) {
+ fprintf(stderr, "line too long for key '%s' in section '%s', max = %d\n",key, section, maxlen);
+ return EINVAL;
+ }
+ strcpy(dest,value);
+ return 0;
+}
+
+int
+rc_getint(struct rcfile *rcp,char *section, char *key,int *value) {
+ struct rcsection *rsp;
+ struct rckey *rkp;
+
+ rsp = rc_findsect(rcp, section);
+ if (!rsp) return ENOENT;
+ rkp = rc_sect_findkey(rsp,key);
+ if (!rkp) return ENOENT;
+ errno = 0;
+ *value = strtol(rkp->rk_value,NULL,0);
+ if (errno) {
+ fprintf(stderr, "invalid int value '%s' for key '%s' in section '%s'\n",rkp->rk_value,key,section);
+ return errno;
+ }
+ return 0;
+}
+
+/*
+ * 1,yes,true
+ * 0,no,false
+ */
+int
+rc_getbool(struct rcfile *rcp,char *section, char *key,int *value) {
+ struct rcsection *rsp;
+ struct rckey *rkp;
+ char *p;
+
+ rsp = rc_findsect(rcp, section);
+ if (!rsp) return ENOENT;
+ rkp = rc_sect_findkey(rsp,key);
+ if (!rkp) return ENOENT;
+ p = rkp->rk_value;
+ while (*p && isspace(*p)) p++;
+ if (*p == '0' || strcasecmp(p,"no") == 0 || strcasecmp(p,"false") == 0) {
+ *value = 0;
+ return 0;
+ }
+ if (*p == '1' || strcasecmp(p,"yes") == 0 || strcasecmp(p,"true") == 0) {
+ *value = 1;
+ return 0;
+ }
+ fprintf(stderr, "invalid boolean value '%s' for key '%s' in section '%s' \n",p, key, section);
+ return EINVAL;
+}
+
+/*
+ * first read ~/.nwfsrc, next try to merge NWFS_CFG_FILE
+ */
+int
+ncp_open_rcfile(void) {
+ char *home, *fn;
+ int error;
+
+ home = getenv("HOME");
+ if (home) {
+ fn = malloc(strlen(home) + 20);
+ sprintf(fn, "%s/.nwfsrc", home);
+ error = rc_open(fn,"r",&ncp_rc);
+ free (fn);
+ }
+ error = rc_merge(NWFS_CFG_FILE, &ncp_rc);
+ if( ncp_rc == NULL ) {
+ printf("Warning: no cfg files found.\n");
+ return 1;
+ }
+ return 0;
+}
+
diff --git a/lib/libncp/ncpl_rpc.c b/lib/libncp/ncpl_rpc.c
new file mode 100644
index 0000000..f2240e3
--- /dev/null
+++ b/lib/libncp/ncpl_rpc.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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 Boris Popov.
+ * 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 THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * NetWare RPCs
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <stdio.h>
+#include <strings.h>
+#include <netncp/ncp_lib.h>
+
+struct ncp_rpc_rq {
+ nuint16 len; /* HL */
+ nuint8 subfn;
+ nuint32 reserved[4];
+ nuint8 flags[4];
+} __attribute__ ((packed));
+
+struct ncp_rpc_rp {
+ nuint32 rpccode;
+ nuint32 reserved[4];
+ nuint32 rpcval;
+} __attribute__ ((packed));
+
+static NWCCODE
+ncp_rpc(NWCONN_HANDLE cH, int rpcfn,
+ const nuint8* rpcarg, char* arg1, char *arg2,
+ nuint32* rpcval) {
+ NWCCODE error;
+ NW_FRAGMENT rq[4], rp;
+ struct ncp_rpc_rq rqh;
+ struct ncp_rpc_rp rph;
+
+ rqh.subfn = rpcfn;
+ if (rpcarg)
+ bcopy(rpcarg, rqh.reserved, 4 * 4 + 4);
+ else
+ bzero(rqh.reserved, 4 * 4 + 4);
+ rq[0].fragAddress = (char*)&rqh;
+ rq[0].fragSize = sizeof(rqh);
+ rq[1].fragAddress = arg1;
+ rq[1].fragSize = strlen(arg1) + 1;
+ rq[2].fragAddress = arg2;
+ rq[2].fragSize = arg2 ? (strlen(arg2) + 1) : 0;
+ rqh.len = htons(rq[2].fragSize + rq[1].fragSize + sizeof(rqh) - 2);
+ rp.fragAddress = (char*)&rph;
+ rp.fragSize = sizeof(rph);
+ error = NWRequest(cH, 131, 3, rq, 1, &rp);
+ if (error) return error;
+ if (rp.fragSize < 4) return EBADRPC;
+ error = rph.rpccode;
+ if (error) return error;
+ if (rpcval) {
+ if (rp.fragSize < 24)
+ return EBADRPC;
+ *rpcval = rph.rpcval;
+ }
+ return 0;
+}
+
+NWCCODE
+NWSMLoadNLM(NWCONN_HANDLE cH, pnstr8 cmd) {
+ return ncp_rpc(cH, 1, NULL, cmd, NULL, NULL);
+}
+
+NWCCODE
+NWSMUnloadNLM(NWCONN_HANDLE cH, pnstr8 cmd) {
+ return ncp_rpc(cH, 2, NULL, cmd, NULL, NULL);
+}
+
+NWCCODE
+NWSMMountVolume(NWCONN_HANDLE cH, pnstr8 volName, nuint32* volnum) {
+ return ncp_rpc(cH, 3, NULL, volName, NULL, volnum);
+}
+
+NWCCODE
+NWSMDismountVolumeByName(NWCONN_HANDLE cH, pnstr8 vol) {
+ return ncp_rpc(cH, 4, NULL, vol, NULL, NULL);
+}
+
+struct ncp_set_hdr {
+ nuint32 typeFlag; /* 0 - str, 1 - value */
+ nuint32 value;
+ nuint32 pad[20 - 4 - 4];
+} __attribute__ ((packed));
+
+NWCCODE
+NWSMSetDynamicCmdIntValue(NWCONN_HANDLE cH, pnstr8 setCommandName, nuint32 cmdValue) {
+ struct ncp_set_hdr rq;
+
+ memset(&rq, 0, sizeof(rq));
+ rq.typeFlag = 1;
+ rq.value = cmdValue;
+ return ncp_rpc(cH, 6, (char*)&rq, setCommandName, NULL, NULL);
+}
+
+NWCCODE
+NWSMSetDynamicCmdStrValue(NWCONN_HANDLE cH, pnstr8 setCommandName,
+ pnstr8 cmdValue) {
+ return ncp_rpc(cH, 6, NULL, setCommandName, cmdValue, NULL);
+}
+
+NWCCODE
+NWSMExecuteNCFFile(NWCONN_HANDLE cH, pnstr8 NCFFileName) {
+ return ncp_rpc(cH, 7, NULL, NCFFileName, NULL, NULL);
+}
diff --git a/lib/libncp/ncpl_subr.c b/lib/libncp/ncpl_subr.c
new file mode 100644
index 0000000..1863143
--- /dev/null
+++ b/lib/libncp/ncpl_subr.c
@@ -0,0 +1,493 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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 Boris Popov.
+ * 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 THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 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/types.h>
+#include <sys/errno.h>
+#include <sys/sysctl.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include <netncp/ncp_lib.h>
+#include <netncp/ncp_rcfile.h>
+#include <netncp/ncp_nls.h>
+/*#include <netncp/ncp_cfg.h>*/
+#include <netncp/ncpio.h>
+
+#define _PATH_NCP _PATH_DEV NCP_NAME
+
+void
+ncp_add_word_lh(struct ncp_buf *conn, u_int16_t x) {
+ setwle(conn->packet, conn->rqsize, x);
+ conn->rqsize += 2;
+ return;
+}
+
+void
+ncp_add_dword_lh(struct ncp_buf *conn, u_int32_t x) {
+ setdle(conn->packet, conn->rqsize, x);
+ conn->rqsize += 4;
+ return;
+}
+
+void
+ncp_add_word_hl(struct ncp_buf *conn, u_int16_t x){
+ setwbe(conn->packet, conn->rqsize, x);
+ conn->rqsize += 2;
+ return;
+}
+
+void
+ncp_add_dword_hl(struct ncp_buf *conn, u_int32_t x) {
+ setdbe(conn->packet, conn->rqsize, x);
+ conn->rqsize += 4;
+ return;
+}
+
+void
+ncp_add_mem(struct ncp_buf *conn, const void *source, int size) {
+ memcpy(conn->packet+conn->rqsize, source, size);
+ conn->rqsize += size;
+ return;
+}
+
+void
+ncp_add_mem_nls(struct ncp_buf *conn, const void *source, int size) {
+ ncp_nls_mem_u2n(conn->packet+conn->rqsize, source, size);
+ conn->rqsize += size;
+ return;
+}
+
+void
+ncp_add_pstring(struct ncp_buf *conn, const char *s) {
+ int len = strlen(s);
+ if (len > 255) {
+ ncp_printf("ncp_add_pstring: string too long: %s\n", s);
+ len = 255;
+ }
+ ncp_add_byte(conn, len);
+ ncp_add_mem(conn, s, len);
+ return;
+}
+
+void
+ncp_add_handle_path(struct ncp_buf *conn, nuint32 volNumber, nuint32 dirNumber,
+ int handleFlag, const char *path)
+{
+ ncp_add_byte(conn, volNumber);
+ ncp_add_dword_lh(conn, dirNumber);
+ ncp_add_byte(conn, handleFlag);
+ if (path) {
+ ncp_add_byte(conn, 1); /* 1 component */
+ ncp_add_pstring(conn, path);
+ } else {
+ ncp_add_byte(conn, 0);
+ }
+}
+
+void
+ncp_init_request(struct ncp_buf *conn) {
+ conn->rqsize = 0;
+ conn->rpsize = 0;
+}
+
+void
+ncp_init_request_s(struct ncp_buf *conn, int subfn) {
+ ncp_init_request(conn);
+ ncp_add_word_lh(conn, 0);
+ ncp_add_byte(conn, subfn);
+}
+
+u_int16_t
+ncp_reply_word_hl(struct ncp_buf *conn, int offset) {
+ return getwbe(ncp_reply_data(conn, offset), 0);
+}
+
+u_int16_t
+ncp_reply_word_lh(struct ncp_buf *conn, int offset) {
+ return getwle(ncp_reply_data(conn, offset), 0);
+}
+
+u_int32_t
+ncp_reply_dword_hl(struct ncp_buf *conn, int offset) {
+ return getdbe(ncp_reply_data(conn, offset), 0);
+}
+
+u_int32_t
+ncp_reply_dword_lh(struct ncp_buf *conn, int offset) {
+ return getdle(ncp_reply_data(conn, offset), 0);
+}
+
+
+int
+ncp_connect(struct ncp_conn_args *li, int *connHandle) {
+ struct ncpioc_connect args;
+ int fd, r;
+ if ((fd = open(_PATH_NCP, O_RDWR)) < 0)
+ return (errno);
+ args.ioc_li = li;
+ args.ioc_connhandle = connHandle;
+ errno = 0;
+ (void)ioctl(fd, NCPIOC_CONNECT, &args);
+ r = errno;
+ close(fd);
+ return (r);
+}
+
+int
+ncp_disconnect(int cH) {
+ DECLARE_RQ;
+
+ ncp_init_request(conn);
+ ncp_add_byte(conn, NCP_CONN_CONNCLOSE);
+ return ncp_conn_request(cH, conn);
+}
+
+int
+ncp_request(int connHandle,int function, struct ncp_buf *ncpbuf){
+ struct ncpioc_request args;
+ int fd, r;
+ if ((fd = open(_PATH_NCP, O_RDWR)) < 0)
+ return (errno);
+ args.ioc_connhandle = connHandle;
+ args.ioc_fn = function;
+ args.ioc_ncpbuf = ncpbuf;
+ errno = 0;
+ (void)ioctl(fd, NCPIOC_REQUEST, &args);
+ r = errno;
+ close(fd);
+ return (r);
+}
+
+int
+ncp_conn_request(int connHandle, struct ncp_buf *ncpbuf){
+ return (ncp_request(connHandle, NCP_CONN, ncpbuf));
+}
+
+int
+ncp_conn_scan(struct ncp_conn_loginfo *li, int *connid) {
+ struct ncpioc_connscan args;
+ int fd, r;
+ if ((fd = open(_PATH_NCP, O_RDWR)) < 0)
+ return (errno);
+ args.ioc_li = li;
+ args.ioc_connhandle = connid;
+ errno = 0;
+ (void)ioctl(fd, NCPIOC_CONNSCAN, &args);
+ r = errno;
+ close(fd);
+ return (r);
+}
+
+NWCCODE
+NWRequest(NWCONN_HANDLE cH, nuint16 fn,
+ nuint16 nrq, NW_FRAGMENT* rq,
+ nuint16 nrp, NW_FRAGMENT* rp)
+{
+ int error;
+ struct ncp_conn_frag nf;
+ DECLARE_RQ;
+
+ ncp_init_request(conn);
+ ncp_add_byte(conn, NCP_CONN_FRAG);
+ nf.fn = fn;
+ nf.rqfcnt = nrq;
+ nf.rqf = rq;
+ nf.rpf = rp;
+ nf.rpfcnt = nrp;
+ ncp_add_mem(conn, &nf, sizeof(nf));
+ error = ncp_conn_request(cH, conn);
+ return error;
+}
+
+
+int
+ncp_initlib(void){
+ int error;
+ int kv;
+ size_t kvlen = sizeof(kv);
+ static int ncp_initialized;
+
+ if (ncp_initialized)
+ return 0;
+ error = sysctlbyname("net.ncp.version", &kv, &kvlen, NULL, 0);
+ if (error) {
+ if (errno == ENOENT)
+ fprintf(stderr, "Kernel module ncp is not loaded.\n");
+ else
+ fprintf(stderr, "%s: kernel module is old, please recompile it.\n", __func__);
+ return error;
+ }
+ if (NCP_VERSION != kv) {
+ fprintf(stderr, "%s: kernel module version(%d) don't match library(%d).\n", __func__, kv, NCP_VERSION);
+ return EINVAL;
+ }
+ if ((error = ncp_nls_setrecode(0)) != 0) {
+ fprintf(stderr, "%s: can't initialise recode\n", __func__);
+ return error;
+ }
+ if ((error = ncp_nls_setlocale("")) != 0) {
+ fprintf(stderr, "%s: can't initialise locale\n", __func__);
+ return error;
+ }
+ ncp_initialized++;
+ return 0;
+}
+
+
+/*
+ */
+int ncp_opterr = 1, /* if error message should be printed */
+ ncp_optind = 1, /* index into parent argv vector */
+ ncp_optopt, /* character checked for validity */
+ ncp_optreset; /* reset getopt */
+char *ncp_optarg; /* argument associated with option */
+
+#define BADCH (int)'?'
+#define BADARG (int)':'
+#define EMSG ""
+
+int
+ncp_getopt(nargc, nargv, ostr)
+ int nargc;
+ char * const *nargv;
+ const char *ostr;
+{
+ static char *place = EMSG; /* option letter processing */
+ char *oli; /* option letter list index */
+ int tmpind;
+
+ if (ncp_optreset || !*place) { /* update scanning pointer */
+ ncp_optreset = 0;
+ tmpind = ncp_optind;
+ while (1) {
+ if (tmpind >= nargc) {
+ place = EMSG;
+ return (-1);
+ }
+ if (*(place = nargv[tmpind]) != '-') {
+ tmpind++;
+ continue; /* lookup next option */
+ }
+ if (place[1] && *++place == '-') { /* found "--" */
+ ncp_optind = ++tmpind;
+ place = EMSG;
+ return (-1);
+ }
+ ncp_optind = tmpind;
+ break;
+ }
+ } /* option letter okay? */
+ if ((ncp_optopt = (int)*place++) == (int)':' ||
+ !(oli = strchr(ostr, ncp_optopt))) {
+ /*
+ * if the user didn't specify '-' as an option,
+ * assume it means -1.
+ */
+ if (ncp_optopt == (int)'-')
+ return (-1);
+ if (!*place)
+ ++ncp_optind;
+ if (ncp_opterr && *ostr != ':')
+ (void)fprintf(stderr,
+ "%s: illegal option -- %c\n", _getprogname(), ncp_optopt);
+ return (BADCH);
+ }
+ if (*++oli != ':') { /* don't need argument */
+ ncp_optarg = NULL;
+ if (!*place)
+ ++ncp_optind;
+ }
+ else { /* need an argument */
+ if (*place) /* no white space */
+ ncp_optarg = place;
+ else if (nargc <= ++ncp_optind) { /* no arg */
+ place = EMSG;
+ if (*ostr == ':')
+ return (BADARG);
+ if (ncp_opterr)
+ (void)fprintf(stderr,
+ "%s: option requires an argument -- %c\n",
+ _getprogname(), ncp_optopt);
+ return (BADCH);
+ }
+ else /* white space */
+ ncp_optarg = nargv[ncp_optind];
+ place = EMSG;
+ ++ncp_optind;
+ }
+ return (ncp_optopt); /* dump back option letter */
+}
+/*
+ * misc options parsing routines
+ */
+int
+ncp_args_parserc(struct ncp_args *na, char *sect, ncp_setopt_t *set_callback) {
+ int len, error;
+
+ for (; na->opt; na++) {
+ switch (na->at) {
+ case NCA_STR:
+ if (rc_getstringptr(ncp_rc,sect,na->name,&na->str) == 0) {
+ len = strlen(na->str);
+ if (len > na->ival) {
+ fprintf(stderr,"rc: Argument for option '%c' (%s) too long\n",na->opt,na->name);
+ return EINVAL;
+ }
+ set_callback(na);
+ }
+ break;
+ case NCA_BOOL:
+ error = rc_getbool(ncp_rc,sect,na->name,&na->ival);
+ if (error == ENOENT) break;
+ if (error) return EINVAL;
+ set_callback(na);
+ break;
+ case NCA_INT:
+ if (rc_getint(ncp_rc,sect,na->name,&na->ival) == 0) {
+ if (((na->flag & NAFL_HAVEMIN) &&
+ (na->ival < na->min)) ||
+ ((na->flag & NAFL_HAVEMAX) &&
+ (na->ival > na->max))) {
+ fprintf(stderr,"rc: Argument for option '%c' (%s) should be in [%d-%d] range\n",na->opt,na->name,na->min,na->max);
+ return EINVAL;
+ }
+ set_callback(na);
+ };
+ break;
+ default:
+ break;
+ }
+ }
+ return 0;
+}
+
+int
+ncp_args_parseopt(struct ncp_args *na, int opt, char *optarg, ncp_setopt_t *set_callback) {
+ int len;
+
+ for (; na->opt; na++) {
+ if (na->opt != opt) continue;
+ switch (na->at) {
+ case NCA_STR:
+ na->str = optarg;
+ if (optarg) {
+ len = strlen(na->str);
+ if (len > na->ival) {
+ fprintf(stderr,"opt: Argument for option '%c' (%s) too long\n",na->opt,na->name);
+ return EINVAL;
+ }
+ set_callback(na);
+ }
+ break;
+ case NCA_BOOL:
+ na->ival = 0;
+ set_callback(na);
+ break;
+ case NCA_INT:
+ errno = 0;
+ na->ival = strtol(optarg, NULL, 0);
+ if (errno) {
+ fprintf(stderr,"opt: Invalid integer value for option '%c' (%s).\n",na->opt,na->name);
+ return EINVAL;
+ }
+ if (((na->flag & NAFL_HAVEMIN) &&
+ (na->ival < na->min)) ||
+ ((na->flag & NAFL_HAVEMAX) &&
+ (na->ival > na->max))) {
+ fprintf(stderr,"opt: Argument for option '%c' (%s) should be in [%d-%d] range\n",na->opt,na->name,na->min,na->max);
+ return EINVAL;
+ }
+ set_callback(na);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ return 0;
+}
+
+/*
+ * Print a (descriptive) error message
+ * error values:
+ * 0 - no specific error code available;
+ * -999..-1 - NDS error
+ * 1..32767 - system error
+ * the rest - requester error;
+ */
+void
+ncp_error(const char *fmt, int error, ...) {
+ va_list ap;
+
+ fprintf(stderr, "%s: ", _getprogname());
+ va_start(ap, error);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ if (error == -1)
+ error = errno;
+ if (error > -1000 && error < 0) {
+ fprintf(stderr, ": dserr = %d\n", error);
+ } else if (error & 0x8000) {
+ fprintf(stderr, ": nwerr = %04x\n", error);
+ } else if (error) {
+ fprintf(stderr, ": syserr = %s\n", strerror(error));
+ } else
+ fprintf(stderr, "\n");
+}
+
+char *
+ncp_printb(char *dest, int flags, const struct ncp_bitname *bnp) {
+ int first = 1;
+
+ strcpy(dest, "<");
+ for(; bnp->bn_bit; bnp++) {
+ if (flags & bnp->bn_bit) {
+ strcat(dest, bnp->bn_name);
+ first = 0;
+ }
+ if (!first && (flags & bnp[1].bn_bit))
+ strcat(dest, "|");
+ }
+ strcat(dest, ">");
+ return dest;
+}
diff --git a/lib/libncp/sap.c b/lib/libncp/sap.c
new file mode 100644
index 0000000..a0c7d0c
--- /dev/null
+++ b/lib/libncp/sap.c
@@ -0,0 +1,304 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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 Boris Popov.
+ * 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 THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 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 <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <arpa/inet.h>
+#include <netipx/ipx.h>
+#include <errno.h>
+#include <unistd.h>
+#include "ipxsap.h"
+
+/*
+ * TODO: These should go to ipx headers
+ */
+#define ipx_set_net(x,y) ((x).x_net.s_net[0] = (y).x_net.s_net[0]); \
+ ((x).x_net.s_net[1]=(y).x_net.s_net[1])
+#define ipx_set_nullnet(x) ((x).x_net.s_net[0]=0); ((x).x_net.s_net[1]=0)
+#define ipx_set_nullhost(x) ((x).x_host.s_host[0] = 0); \
+ ((x).x_host.s_host[1] = 0); ((x).x_host.s_host[2] = 0)
+#define ipx_set_wildnet(x) ((x).x_net.s_net[0] = 0xFFFF); \
+ ((x).x_net.s_net[1]=0xFFFF)
+#define ipx_set_wildhost(x) ((x).x_host.s_host[0] = 0xFFFF); \
+ ((x).x_host.s_host[1] = 0xFFFF); ((x).x_host.s_host[2] = 0xFFFF);
+
+
+static struct sap_packet* sap_packet_alloc(int entries);
+static int sap_size(int entries, u_short operation);
+int (*sap_sendto_func)(void*,int,struct sockaddr_ipx*,int sock)=NULL;
+
+static int
+sap_sendto(void* buffer, int size, struct sockaddr_ipx* daddr, int sock)
+{
+ if (sap_sendto_func)
+ return sap_sendto_func(buffer,size,daddr,sock);
+ return sendto(sock, (char*)buffer, size, 0,
+ (struct sockaddr*)daddr, sizeof(*daddr));
+}
+
+static struct sap_packet*
+sap_packet_alloc(int entries)
+{
+ if (entries > IPX_SAP_MAX_ENTRIES)
+ return NULL;
+ return
+ (struct sap_packet*)malloc(sap_size(entries, IPX_SAP_GENERAL_RESPONSE));
+}
+
+static int
+sap_size(int entries, u_short operation)
+{
+ if (entries <= 0)
+ return 0;
+ switch (operation) {
+ case IPX_SAP_GENERAL_QUERY:
+ return entries == 1 ? IPX_SAP_REQUEST_LEN : 0;
+ case IPX_SAP_GENERAL_RESPONSE:
+ if (entries > IPX_SAP_MAX_ENTRIES)
+ return 0;
+ return sizeof(struct sap_packet) + (entries - 1) * sizeof(struct sap_entry);
+ case IPX_SAP_NEAREST_QUERY:
+ return entries == 1 ? IPX_SAP_REQUEST_LEN : 0;
+ case IPX_SAP_NEAREST_RESPONSE:
+ return entries == 1 ? sizeof(struct sap_packet) : 0;
+ default:
+ return 0;
+ }
+}
+
+void
+sap_copyname(char *dest, const char *src)
+{
+ bzero(dest, IPX_SAP_SERVER_NAME_LEN);
+ strncpy(dest, src, IPX_SAP_SERVER_NAME_LEN - 1);
+}
+
+int
+sap_rq_init(struct sap_rq* rq, int sock)
+{
+ rq->buffer = sap_packet_alloc(IPX_SAP_MAX_ENTRIES);
+ if (rq->buffer == NULL)
+ return 0;
+ rq->entries = 0;
+ rq->buffer->operation = htons(IPX_SAP_GENERAL_QUERY);
+ rq->dest_addr.sipx_family = AF_IPX;
+ rq->dest_addr.sipx_len = sizeof(struct sockaddr_ipx);
+ rq->sock = sock;
+ return 1;
+}
+
+int
+sap_rq_flush(struct sap_rq* rq)
+{
+ int result;
+
+ if (rq->entries == 0)
+ return 0;
+ result = sap_sendto(rq->buffer,
+ sap_size(rq->entries, ntohs(rq->buffer->operation)),
+ &rq->dest_addr, rq->sock);
+ rq->entries = 0;
+ return result;
+}
+
+void
+sap_rq_general_query(struct sap_rq* rq, u_short ser_type)
+{
+ struct sap_entry* sep;
+
+ sap_rq_flush(rq);
+ rq->buffer->operation = htons(IPX_SAP_GENERAL_QUERY);
+ sep = rq->buffer->sap_entries + rq->entries++;
+ sep->server_type = htons(ser_type);
+}
+
+void
+sap_rq_gns_request(struct sap_rq* rq, u_short ser_type)
+{
+ struct sap_entry* sep;
+
+ sap_rq_flush(rq);
+ rq->buffer->operation = htons(IPX_SAP_NEAREST_QUERY);
+ sep = rq->buffer->sap_entries + rq->entries++;
+ sep->server_type = htons(ser_type);
+}
+
+void
+sap_rq_general_response(struct sap_rq* rq,u_short type,char *name,struct sockaddr_ipx* addr, u_short hops,int down_allow)
+{
+ struct sap_entry* sep;
+
+ if (hops >= IPX_SAP_SERVER_DOWN && !down_allow) return;
+ if (rq->entries >= IPX_SAP_MAX_ENTRIES)
+ sap_rq_flush(rq);
+ if (rq->buffer->operation != htons(IPX_SAP_GENERAL_RESPONSE)){
+ sap_rq_flush(rq);
+ rq->buffer->operation = htons(IPX_SAP_GENERAL_RESPONSE);
+ }
+ sep = rq->buffer->sap_entries + rq->entries;
+ sep->server_type = htons(type);
+ sap_copyname(sep->server_name, name);
+ memcpy(&sep->ipx, &addr->sipx_addr, sizeof(struct ipx_addr));
+ sep->hops = htons(hops);
+ rq->entries++;
+}
+
+void
+sap_rq_gns_response(struct sap_rq* rq,u_short type,char *name,struct sockaddr_ipx* addr,u_short hops)
+{
+ struct sap_entry* sep;
+
+ if (hops >= IPX_SAP_SERVER_DOWN) return;
+ sap_rq_flush(rq);
+ rq->buffer->operation = htons(IPX_SAP_NEAREST_RESPONSE);
+ sep = rq->buffer->sap_entries + rq->entries;
+ sep->server_type = htons(type);
+ sap_copyname(sep->server_name, name);
+ memcpy(&sep->ipx, &addr->sipx_addr, sizeof(struct ipx_addr));
+ sep->hops = htons(hops);
+ rq->entries++;
+}
+
+void
+sap_rq_set_destination(struct sap_rq* rq,struct ipx_addr *dest)
+{
+ sap_rq_flush(rq);
+ memcpy(&rq->dest_addr.sipx_addr,dest,sizeof(struct ipx_addr));
+}
+
+int
+sap_getsock(int *rsock) {
+ struct sockaddr_ipx sap_addr;
+ int opt, sock, slen;
+
+ sock = socket(AF_IPX, SOCK_DGRAM, 0);
+ if (sock < 0)
+ return (errno);
+ slen = sizeof(sap_addr);
+ bzero(&sap_addr, slen);
+ sap_addr.sipx_family = AF_IPX;
+ sap_addr.sipx_len = slen;
+ if (bind(sock, (struct sockaddr*)&sap_addr, slen) == -1) {
+ close(sock);
+ return(errno);
+ }
+ opt = 1;
+ if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt)) != 0){
+ close(sock);
+ return(errno);
+ }
+ *rsock = sock;
+ return(0);
+}
+
+static int
+sap_recv(int sock,void *buf,int len,int flags, int timeout){
+ fd_set rd, wr, ex;
+ struct timeval tv;
+ int result;
+
+ FD_ZERO(&rd);
+ FD_ZERO(&wr);
+ FD_ZERO(&ex);
+ FD_SET(sock, &rd);
+
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+
+ if ((result = select(sock + 1, &rd, &wr, &ex, &tv)) == -1) {
+ return result;
+ }
+ if (FD_ISSET(sock, &rd)) {
+ result = recv(sock, buf, len, flags);
+ } else {
+ errno = ETIMEDOUT;
+ result = -1;
+ }
+ return result;
+}
+
+int
+sap_find_nearest(int server_type, struct sockaddr_ipx *daddr, char *server_name)
+{
+ struct ipx_addr addr;
+ char data[1024];
+ int sock, error, packets, len;
+ struct sap_packet *reply = (struct sap_packet*)&data;
+ struct sap_rq sap_rq;
+
+ error = sap_getsock(&sock);
+ if (error)
+ return error;
+ bzero(&addr, sizeof(addr));
+ /* BAD: we should enum all ifs (and nets ?) */
+ if (ipx_iffind(NULL, &addr) != 0) {
+ return (EPROTONOSUPPORT);
+ }
+ ipx_set_wildhost(addr);
+ addr.x_port = htons(IPXPORT_SAP);
+
+ if (!sap_rq_init(&sap_rq, sock)) {
+ close(sock);
+ return(ENOMEM);
+ }
+ sap_rq_set_destination(&sap_rq, &addr);
+ sap_rq_gns_request(&sap_rq, server_type);
+ sap_rq_flush(&sap_rq);
+ packets = 5;
+ do {
+ len = sap_recv(sock, data, sizeof(data), 0, 1);
+ if (len >= 66 &&
+ ntohs(reply->operation) == IPX_SAP_NEAREST_RESPONSE)
+ break;
+ if (len < 0)
+ packets--;
+ } while (packets > 0);
+
+ if (packets == 0) {
+ close(sock);
+ return ENETDOWN;
+ }
+
+ daddr->sipx_addr = reply->sap_entries[0].ipx;
+ daddr->sipx_family = AF_IPX;
+ daddr->sipx_len = sizeof(struct sockaddr_ipx);
+ sap_copyname(server_name, reply->sap_entries[0].server_name);
+ errno = 0;
+ close(sock);
+ return 0;
+}
diff --git a/lib/libncurses/Makefile b/lib/libncurses/Makefile
new file mode 100644
index 0000000..4fddbdc
--- /dev/null
+++ b/lib/libncurses/Makefile
@@ -0,0 +1,564 @@
+# $FreeBSD$
+
+SHLIBDIR?= /lib
+
+.include <bsd.own.mk>
+
+NCURSES=${.CURDIR}/../../contrib/ncurses
+
+LIB= ncurses
+SHLIB_MAJOR=6
+
+# Should be elsewhere
+AWK?= awk
+TERMINFODIR?= ${SHAREDIR}/misc
+
+NCURSES_MAJOR!=egrep 'NCURSES_MAJOR[ ]*=' ${NCURSES}/dist.mk | sed -e 's%^[^0-9]*%%'
+NCURSES_MINOR!=egrep 'NCURSES_MINOR[ ]*=' ${NCURSES}/dist.mk | sed -e 's%^[^0-9]*%%'
+NCURSES_PATCH!=egrep 'NCURSES_PATCH[ ]*=' ${NCURSES}/dist.mk | sed -e 's%^[^0-9]*%%'
+
+# From autoconf (!)
+NCURSES_CONST= const
+NCURSES_XNAMES= 1
+NCURSES_OSPEED= short
+NCURSES_CH_T= chtype
+NCURSES_EXT_FUNCS= 1
+NCURSES_LIBUTF8= 0
+NCURSES_MBSTATE_T= 0
+BROKEN_LINKER= 0
+BUILTIN_BOOL= 1
+BOOL_TYPE= 0
+HAVE_VSSCANF= 1
+HEADER_STDBOOL= 1
+TYPE_OF_BOOL= unsigned char
+TYPEOF_CHTYPE= long
+WIDEC_SHIFT= 8
+SHIFT_LIMIT= 32
+ONEUL= 1UL
+
+.PATH: ${NCURSES}/ncurses
+.PATH: ${NCURSES}/ncurses/base
+.PATH: ${NCURSES}/ncurses/tinfo
+.PATH: ${NCURSES}/ncurses/tty
+.PATH: ${NCURSES}/ncurses/trace
+.PATH: ${NCURSES}/include
+.PATH: ${NCURSES}/man
+
+CFLAGS+=-I. -I${.CURDIR} -I${NCURSES}/ncurses -I${NCURSES}/include
+CFLAGS+=-Wall -DFREEBSD_NATIVE -DNDEBUG -DHAVE_CONFIG_H -DTERMIOS
+
+GENSRC= \
+ codes.c \
+ expanded.c \
+ fallback.c \
+ lib_gen.c \
+ lib_keyname.c \
+ names.c \
+ unctrl.c
+
+GENHDR= \
+ curses.h \
+ hashsize.h \
+ init_keytry.h \
+ ncurses_def.h \
+ nomacros.h \
+ parametrized.h \
+ term.h \
+ termcap.h \
+ unctrl.h
+
+# Installed
+HEADERS=curses.h term.h termcap.h unctrl.h
+SRCHDRS=ncurses_dll.h
+INCS= ${HEADERS} ${SRCHDRS}
+INCSLINKS= curses.h ${INCLUDEDIR}/ncurses.h
+
+# Components of names.c and codes.c
+NAMESRC=boolnames boolfnames numnames numfnames strnames strfnames
+CODESRC=boolcodes numcodes strcodes
+
+SRCS= ${GENHDR} ${GENSRC} \
+ access.c \
+ add_tries.c \
+ alloc_entry.c \
+ alloc_ttype.c \
+ captoinfo.c \
+ comp_captab.c \
+ comp_error.c \
+ comp_expand.c \
+ comp_hash.c \
+ comp_parse.c \
+ comp_scan.c \
+ define_key.c \
+ doalloc.c \
+ free_ttype.c \
+ getenv_num.c \
+ hardscroll.c \
+ hashmap.c \
+ home_terminfo.c \
+ init_keytry.c \
+ keybound.c \
+ keyok.c \
+ lib_acs.c \
+ lib_addch.c \
+ lib_addstr.c \
+ lib_baudrate.c \
+ lib_beep.c \
+ lib_bkgd.c \
+ lib_box.c \
+ lib_chgat.c \
+ lib_clear.c \
+ lib_clearok.c \
+ lib_clrbot.c \
+ lib_clreol.c \
+ lib_color.c \
+ lib_colorset.c \
+ lib_cur_term.c \
+ lib_data.c \
+ lib_delch.c \
+ lib_delwin.c \
+ lib_dft_fgbg.c \
+ lib_echo.c \
+ lib_endwin.c \
+ lib_erase.c \
+ lib_flash.c \
+ lib_freeall.c \
+ lib_getch.c \
+ lib_getstr.c \
+ lib_has_cap.c \
+ lib_hline.c \
+ lib_immedok.c \
+ lib_inchstr.c \
+ lib_initscr.c \
+ lib_insch.c \
+ lib_insdel.c \
+ lib_insstr.c \
+ lib_instr.c \
+ lib_isendwin.c \
+ lib_kernel.c \
+ lib_leaveok.c \
+ lib_longname.c \
+ lib_mouse.c \
+ lib_move.c \
+ lib_mvcur.c \
+ lib_mvwin.c \
+ lib_napms.c \
+ lib_newterm.c \
+ lib_newwin.c \
+ lib_nl.c \
+ lib_options.c \
+ lib_overlay.c \
+ lib_pad.c \
+ lib_print.c \
+ lib_printw.c \
+ lib_raw.c \
+ lib_redrawln.c \
+ lib_refresh.c \
+ lib_restart.c \
+ lib_scanw.c \
+ lib_screen.c \
+ lib_scroll.c \
+ lib_scrollok.c \
+ lib_scrreg.c \
+ lib_set_term.c \
+ lib_setup.c \
+ lib_slk.c \
+ lib_slkatr_set.c \
+ lib_slkatrof.c \
+ lib_slkatron.c \
+ lib_slkatrset.c \
+ lib_slkattr.c \
+ lib_slkclear.c \
+ lib_slkcolor.c \
+ lib_slkinit.c \
+ lib_slklab.c \
+ lib_slkrefr.c \
+ lib_slkset.c \
+ lib_slktouch.c \
+ lib_termcap.c \
+ lib_termname.c \
+ lib_tgoto.c \
+ lib_ti.c \
+ lib_touch.c \
+ lib_tparm.c \
+ lib_tputs.c \
+ lib_trace.c \
+ lib_tstp.c \
+ lib_ttyflags.c \
+ lib_twait.c \
+ lib_ungetch.c \
+ lib_vidattr.c \
+ lib_vline.c \
+ lib_wattroff.c \
+ lib_wattron.c \
+ lib_winch.c \
+ lib_window.c \
+ memmove.c \
+ name_match.c \
+ nc_panel.c \
+ parse_entry.c \
+ read_entry.c \
+ resizeterm.c \
+ safe_sprintf.c \
+ setbuf.c \
+ sigaction.c \
+ strings.c \
+ tries.c \
+ tty_update.c \
+ varargs.c \
+ version.c \
+ visbuf.c \
+ vsscanf.c \
+ wresize.c \
+ write_entry.c
+
+# Currently unused, for debugging libncurses itself.
+DBGSRCS=lib_traceatr.c \
+ lib_tracebits.c \
+ lib_tracechr.c \
+ lib_tracedmp.c \
+ lib_tracemse.c \
+ trace_buf.c \
+ trace_tries.c \
+ trace_xnames.c
+
+# From our old libtermcap.
+# Used instead of the hideous read_termcap.c abomination.
+SRCS+= termcap.c
+
+CLEANFILES+= ${GENSRC} ${GENHDR} keys.list make_hash term.h.new \
+ make_keys MKterm.h.awk comp_captab.c curses.head \
+ namehdr nameftr codeftr ${NAMESRC} ${CODESRC}
+
+.if !defined(NO_INSTALLLIB)
+SYMLINKS+=libncurses.a ${LIBDIR}/libcurses.a
+SYMLINKS+=libncurses.a ${LIBDIR}/libtermcap.a
+SYMLINKS+=libncurses.a ${LIBDIR}/libtermlib.a
+SYMLINKS+=libncurses.a ${LIBDIR}/libmytinfo.a
+SYMLINKS+=libncurses.a ${LIBDIR}/libtinfo.a
+.endif
+.if !defined(NO_PIC)
+# no need for major at all, it's an ld-time redirection only
+SYMLINKS+=libncurses.so ${LIBDIR}/libcurses.so
+SYMLINKS+=libncurses.so ${LIBDIR}/libtermcap.so
+SYMLINKS+=libncurses.so ${LIBDIR}/libtermlib.so
+SYMLINKS+=libncurses.so ${LIBDIR}/libmytinfo.so
+SYMLINKS+=libncurses.so ${LIBDIR}/libtinfo.so
+.endif
+.if ${MK_PROFILE} != "no"
+SYMLINKS+=libncurses_p.a ${LIBDIR}/libcurses_p.a
+SYMLINKS+=libncurses_p.a ${LIBDIR}/libtermcap_p.a
+SYMLINKS+=libncurses_p.a ${LIBDIR}/libtermlib_p.a
+SYMLINKS+=libncurses_p.a ${LIBDIR}/libmytinfo_p.a
+SYMLINKS+=libncurses_p.a ${LIBDIR}/libtinfo_p.a
+.endif
+
+DOCSDIR= /usr/share/doc/ncurses
+DOCS= ncurses-intro.html hackguide.html
+
+.if ${MK_HTML} != "no"
+.PATH: ${NCURSES}/doc/html
+FILESGROUPS= DOCS
+.endif
+
+# Generated source
+namehdr nameftr codeftr ${NAMESRC} ${CODESRC}: MKnames.awk Caps
+ ${AWK} -f ${NCURSES}/ncurses/tinfo/MKnames.awk ${NCURSES}/include/Caps
+
+.ORDER: namehdr ${NAMESRC} ${CODESRC} nameftr codeftr names.c codes.c
+
+names.c: namehdr ${NAMESRC} nameftr
+ cat namehdr ${NAMESRC} nameftr > $@
+
+codes.c: namehdr ${CODESRC} codeftr
+ cat namehdr ${CODESRC} codeftr > $@
+
+lib_gen.c: MKlib_gen.sh curses.h
+ LC_ALL=C sh ${NCURSES}/ncurses/base/MKlib_gen.sh "${CC} -E ${CFLAGS}" \
+ "${AWK}" generated < curses.h >$@
+
+lib_keyname.c: keys.list MKkeyname.awk
+ ${AWK} -f ${NCURSES}/ncurses/base/MKkeyname.awk keys.list > lib_keyname.c
+
+unctrl.c: MKunctrl.awk
+ echo | ${AWK} -f ${NCURSES}/ncurses/base/MKunctrl.awk > unctrl.c
+
+comp_captab.c: MKcaptab.awk Caps make_hash
+ sh ${NCURSES}/ncurses/tinfo/MKcaptab.awk "${AWK}" \
+ ${NCURSES}/include/Caps > comp_captab.c
+
+expanded.c: MKexpanded.sh
+ sh ${NCURSES}/ncurses/tty/MKexpanded.sh "${CC} -E" ${CFLAGS} >expanded.c
+
+fallback.c: MKfallback.sh
+ sh ${NCURSES}/ncurses/tinfo/MKfallback.sh > fallback.c
+
+# Generated headers
+ncurses_def.h: MKncurses_def.sh ncurses_defs
+ AWK=${AWK} sh ${NCURSES}/include/MKncurses_def.sh \
+ ${NCURSES}/include/ncurses_defs > ncurses_def.h
+
+nomacros.h: MKlib_gen.sh curses.h
+ LC_ALL=C sh ${NCURSES}/ncurses/base/MKlib_gen.sh "${CC} -E ${CFLAGS}" \
+ "${AWK}" generated < curses.h | fgrep undef > $@
+
+init_keytry.h: keys.list make_keys
+ ./make_keys keys.list > init_keytry.h
+
+hashsize.h: MKhashsize.sh Caps
+ sh ${NCURSES}/include/MKhashsize.sh ${NCURSES}/include/Caps > $@
+
+parametrized.h: MKparametrized.sh Caps
+ AWK=${AWK} sh ${NCURSES}/include/MKparametrized.sh \
+ ${NCURSES}/include/Caps > $@
+
+term.h: MKterm.h.awk edit_cfg.sh Caps
+ ${AWK} -f MKterm.h.awk ${NCURSES}/include/Caps > $@.new
+ sh ${NCURSES}/include/edit_cfg.sh ${.CURDIR}/ncurses_cfg.h $@.new
+ mv -f $@.new $@
+
+curses.h: curses.head MKkey_defs.sh Caps
+ cat curses.head > $@.new
+ AWK=${AWK} _POSIX2_VERSION=199209 sh ${NCURSES}/include/MKkey_defs.sh \
+ ${NCURSES}/include/Caps >> $@.new
+ cat ${NCURSES}/include/curses.tail >> $@.new
+ mv -f $@.new $@
+
+# Generated intermediate files
+keys.list: MKkeys_list.sh Caps
+ AWK=${AWK} sh ${NCURSES}/ncurses/tinfo/MKkeys_list.sh \
+ ${NCURSES}/include/Caps | LC_ALL=C sort > keys.list
+
+# Build tools
+build-tools: make_hash make_keys
+
+make_keys: make_keys.c names.c ncurses_def.h ${HEADERS}
+ ${CC} -o $@ ${CFLAGS} ${NCURSES}/ncurses/tinfo/make_keys.c
+
+make_hash: comp_hash.c hashsize.h ncurses_def.h ${HEADERS}
+ ${CC} -o $@ ${CFLAGS} -DMAIN_PROGRAM \
+ ${NCURSES}/ncurses/tinfo/comp_hash.c
+
+# ./configure generated
+MKterm.h.awk: MKterm.h.awk.in
+ sed <${NCURSES}/include/MKterm.h.awk.in >$@ \
+ -e "/@NCURSES_MAJOR@/s%%${NCURSES_MAJOR}%" \
+ -e "/@NCURSES_MINOR@/s%%${NCURSES_MINOR}%" \
+ -e "/@NCURSES_CONST@/s%%${NCURSES_CONST}%" \
+ -e "/@NCURSES_XNAMES@/s%%${NCURSES_XNAMES}%"
+
+termcap.h: termcap.h.in
+ sed <${NCURSES}/include/termcap.h.in >$@ \
+ -e "/@NCURSES_MAJOR@/s%%${NCURSES_MAJOR}%" \
+ -e "/@NCURSES_MINOR@/s%%${NCURSES_MINOR}%" \
+ -e "/@NCURSES_CONST@/s%%${NCURSES_CONST}%" \
+ -e "/@NCURSES_OSPEED@/s%%${NCURSES_OSPEED}%"
+
+curses.head: curses.h.in
+ sed <${NCURSES}/include/curses.h.in >$@ \
+ -e "/@BROKEN_LINKER@/s%%${BROKEN_LINKER}%" \
+ -e "/@HAVE_VSSCANF@/s%%${HAVE_VSSCANF}%" \
+ -e "/@NCURSES_CONST@/s%%${NCURSES_CONST}%" \
+ -e "/@NCURSES_MAJOR@/s%%${NCURSES_MAJOR}%" \
+ -e "/@NCURSES_MINOR@/s%%${NCURSES_MINOR}%" \
+ -e "/@NCURSES_PATCH@/s%%${NCURSES_PATCH}%" \
+ -e "/@NCURSES_CH_T@/s%%${NCURSES_CH_T}%" \
+ -e "/@NCURSES_EXT_FUNCS@/s%%${NCURSES_EXT_FUNCS}%" \
+ -e "/@NCURSES_LIBUTF8@/s%%${NCURSES_LIBUTF8}%" \
+ -e "/@NCURSES_MBSTATE_T@/s%%${NCURSES_MBSTATE_T}%" \
+ -e "s%@cf_cv_1UL@%${ONEUL}%g" \
+ -e "s%@cf_cv_builtin_bool@%${BUILTIN_BOOL}%g" \
+ -e "s%@cf_cv_cc_bool_type@%${BOOL_TYPE}%g" \
+ -e "s%@cf_cv_shift_limit@%${SHIFT_LIMIT}%g" \
+ -e "s%@cf_cv_header_stdbool_h@%${HEADER_STDBOOL}%g" \
+ -e "s%@cf_cv_type_of_bool@%${TYPE_OF_BOOL}%g" \
+ -e "s%@cf_cv_typeof_chtype@%${TYPEOF_CHTYPE}%g" \
+ -e "s%@cf_cv_widec_shift@%${WIDEC_SHIFT}%g" \
+ -e "s/ _WCHAR_T/ __wchar_t/g" \
+ -e "s/ _WINT_T/ __wint_t/g" \
+
+unctrl.h: unctrl.h.in
+ sed <${NCURSES}/include/$@.in >$@ \
+ -e "/@NCURSES_MAJOR@/s%%${NCURSES_MAJOR}%" \
+ -e "/@NCURSES_MINOR@/s%%${NCURSES_MINOR}%"
+
+# MAN page gunk
+terminfo.5: MKterminfo.sh terminfo.head Caps
+ sh ${NCURSES}/man/MKterminfo.sh ${NCURSES}/man/terminfo.head \
+ ${NCURSES}/include/Caps ${NCURSES}/man/terminfo.tail >$@
+
+CLEANFILES+= terminfo.5
+MANFILTER= sed -e 's%@TERMINFO@%${TERMINFODIR}/terminfo%g' \
+ -e 's%@NCURSES_OSPEED@%${NCURSES_OSPEED}%g'
+
+MANx= curs_addch.3x curs_addchstr.3x curs_addstr.3x curs_attr.3x \
+ curs_beep.3x curs_bkgd.3x curs_border.3x curs_clear.3x curs_color.3x \
+ curs_delch.3x curs_deleteln.3x curs_extend.3x curs_getch.3x \
+ curs_getstr.3x \
+ curs_getyx.3x curs_inch.3x curs_inchstr.3x curs_initscr.3x \
+ curs_inopts.3x curs_insch.3x curs_insstr.3x curs_instr.3x \
+ curs_kernel.3x curs_mouse.3x curs_move.3x curs_outopts.3x \
+ curs_overlay.3x curs_pad.3x curs_print.3x curs_printw.3x \
+ curs_refresh.3x curs_scanw.3x curs_scr_dump.3x curs_scroll.3x \
+ curs_slk.3x curs_termattrs.3x curs_termcap.3x curs_terminfo.3x \
+ curs_touch.3x curs_trace.3x curs_util.3x curs_window.3x \
+ default_colors.3x define_key.3x \
+ keybound.3x keyok.3x ncurses.3x resizeterm.3x wresize.3x
+MAN= term.5 terminfo.5
+MAN+= term.7
+
+# Generate the MAN list from MANx
+.for page in ${MANx}
+CLEANFILES+=${page:T:S/x$//g}
+MAN+=${page:T:S/x$//g}
+${page:T:S/x$//g}: ${page}
+ cat ${.ALLSRC} > ${.TARGET}
+.endfor
+
+MLINKS+=ncurses.3 curses.3
+MLINKS+=curs_addch.3 addch.3 curs_addch.3 echochar.3 curs_addch.3 mvaddch.3 \
+ curs_addch.3 mvwaddch.3 curs_addch.3 waddch.3 curs_addch.3 wechochar.3
+MLINKS+=curs_addchstr.3 addchnstr.3 curs_addchstr.3 addchstr.3 \
+ curs_addchstr.3 mvaddchnstr.3 curs_addchstr.3 mvaddchstr.3 \
+ curs_addchstr.3 mvwaddchnstr.3 curs_addchstr.3 mvwaddchstr.3 \
+ curs_addchstr.3 waddchnstr.3 curs_addchstr.3 waddchstr.3
+MLINKS+=curs_addstr.3 addnstr.3 curs_addstr.3 addstr.3 \
+ curs_addstr.3 mvaddnstr.3 curs_addstr.3 mvaddstr.3 \
+ curs_addstr.3 mvwaddnstr.3 curs_addstr.3 mvwaddstr.3 \
+ curs_addstr.3 waddnstr.3 curs_addstr.3 waddstr.3
+MLINKS+=curs_attr.3 PAIR_NUMBER.3 \
+ curs_attr.3 attr_get.3 curs_attr.3 attr_off.3 curs_attr.3 attr_on.3 \
+ curs_attr.3 attr_set.3 curs_attr.3 attroff.3 curs_attr.3 attron.3 \
+ curs_attr.3 attrset.3 curs_attr.3 chgat.3 curs_attr.3 color_set.3 \
+ curs_attr.3 mvchgat.3 curs_attr.3 mvwchgat.3 curs_attr.3 standend.3 \
+ curs_attr.3 standout.3 curs_attr.3 wattr_get.3 curs_attr.3 wattr_off.3 \
+ curs_attr.3 wattr_on.3 curs_attr.3 wattr_set.3 curs_attr.3 wattroff.3 \
+ curs_attr.3 wattron.3 curs_attr.3 wattrset.3 curs_attr.3 wchgat.3 \
+ curs_attr.3 wcolor_set.3 curs_attr.3 wstandend.3 \
+ curs_attr.3 wstandout.3
+MLINKS+=curs_beep.3 beep.3 curs_beep.3 flash.3
+MLINKS+=curs_bkgd.3 bkgd.3 curs_bkgd.3 bkgdset.3 curs_bkgd.3 getbkgd.3 \
+ curs_bkgd.3 wbkgd.3 curs_bkgd.3 wbkgdset.3
+MLINKS+=curs_border.3 border.3 curs_border.3 box.3 curs_border.3 hline.3 \
+ curs_border.3 mvhline.3 curs_border.3 mvvline.3 \
+ curs_border.3 mvwhline.3 \
+ curs_border.3 mvwvline.3 curs_border.3 vline.3 curs_border.3 wborder.3 \
+ curs_border.3 whline.3 curs_border.3 wvline.3
+MLINKS+=curs_clear.3 clear.3 curs_clear.3 clrtobot.3 curs_clear.3 clrtoeol.3 \
+ curs_clear.3 erase.3 curs_clear.3 wclear.3 curs_clear.3 wclrtobot.3 \
+ curs_clear.3 wclrtoeol.3 curs_clear.3 werase.3
+MLINKS+=curs_color.3 COLOR_PAIR.3 \
+ curs_color.3 can_change_color.3 curs_color.3 color_content.3 \
+ curs_color.3 has_colors.3 curs_color.3 init_color.3 \
+ curs_color.3 init_pair.3 curs_color.3 pair_content.3 \
+ curs_color.3 start_color.3
+MLINKS+=curs_delch.3 delch.3 curs_delch.3 mvdelch.3 curs_delch.3 mvwdelch.3 \
+ curs_delch.3 wdelch.3
+MLINKS+=curs_deleteln.3 deleteln.3 curs_deleteln.3 insdelln.3 \
+ curs_deleteln.3 insertln.3 curs_deleteln.3 wdeleteln.3 \
+ curs_deleteln.3 winsdelln.3 curs_deleteln.3 winsertln.3
+MLINKS+=curs_extend.3 curses_version.3 curs_extend.3 use_extended_names.3
+MLINKS+=curs_getch.3 getch.3 curs_getch.3 has_key.3 curs_getch.3 mvgetch.3 \
+ curs_getch.3 mvwgetch.3 curs_getch.3 ungetch.3 curs_getch.3 wgetch.3
+MLINKS+=curs_getstr.3 getnstr.3 curs_getstr.3 getstr.3 \
+ curs_getstr.3 mvgetnstr.3 curs_getstr.3 mvgetstr.3 \
+ curs_getstr.3 mvwgetnstr.3 curs_getstr.3 mvwgetstr.3 \
+ curs_getstr.3 wgetnstr.3 curs_getstr.3 wgetstr.3
+MLINKS+=curs_getyx.3 getbegyx.3 curs_getyx.3 getmaxyx.3 \
+ curs_getyx.3 getparyx.3 curs_getyx.3 getyx.3
+MLINKS+=curs_inch.3 inch.3 curs_inch.3 mvinch.3 curs_inch.3 mvwinch.3 \
+ curs_inch.3 winch.3
+MLINKS+=curs_inchstr.3 inchnstr.3 curs_inchstr.3 inchstr.3 \
+ curs_inchstr.3 mvinchnstr.3 curs_inchstr.3 mvinchstr.3 \
+ curs_inchstr.3 mvwinchnstr.3 curs_inchstr.3 mvwinchstr.3 \
+ curs_inchstr.3 winchnstr.3 curs_inchstr.3 winchstr.3
+MLINKS+=curs_initscr.3 delscreen.3 curs_initscr.3 endwin.3 \
+ curs_initscr.3 initscr.3 curs_initscr.3 isendwin.3 \
+ curs_initscr.3 newterm.3 curs_initscr.3 set_term.3
+MLINKS+=curs_inopts.3 cbreak.3 curs_inopts.3 echo.3 curs_inopts.3 halfdelay.3 \
+ curs_inopts.3 intrflush.3 curs_inopts.3 keypad.3 curs_inopts.3 meta.3 \
+ curs_inopts.3 nocbreak.3 curs_inopts.3 nodelay.3 \
+ curs_inopts.3 noecho.3 curs_inopts.3 noqiflush.3 curs_inopts.3 noraw.3 \
+ curs_inopts.3 notimeout.3 curs_inopts.3 qiflush.3 curs_inopts.3 raw.3 \
+ curs_inopts.3 timeout.3 curs_inopts.3 typeahead.3 \
+ curs_inopts.3 wtimeout.3
+MLINKS+=curs_insch.3 insch.3 curs_insch.3 mvinsch.3 curs_insch.3 mvwinsch.3 \
+ curs_insch.3 winsch.3
+MLINKS+=curs_insstr.3 insnstr.3 curs_insstr.3 insstr.3 \
+ curs_insstr.3 mvinsnstr.3 curs_insstr.3 mvinsstr.3 \
+ curs_insstr.3 mvwinsnstr.3 curs_insstr.3 mvwinsstr.3 \
+ curs_insstr.3 winsnstr.3 curs_insstr.3 winsstr.3
+MLINKS+=curs_instr.3 innstr.3 curs_instr.3 instr.3 curs_instr.3 mvinnstr.3 \
+ curs_instr.3 mvinstr.3 curs_instr.3 mvwinnstr.3 \
+ curs_instr.3 mvwinstr.3 curs_instr.3 winnstr.3 curs_instr.3 winstr.3
+MLINKS+=curs_kernel.3 curs_set.3 curs_kernel.3 def_prog_mode.3 \
+ curs_kernel.3 def_shell_mode.3 curs_kernel.3 getsyx.3 \
+ curs_kernel.3 napms.3 curs_kernel.3 reset_prog_mode.3 \
+ curs_kernel.3 reset_shell_mode.3 curs_kernel.3 resetty.3 \
+ curs_kernel.3 ripoffline.3 curs_kernel.3 savetty.3 \
+ curs_kernel.3 setsyx.3
+MLINKS+=curs_mouse.3 getmouse.3 curs_mouse.3 mouse_trafo.3 \
+ curs_mouse.3 mouseinterval.3 \
+ curs_mouse.3 mousemask.3 curs_mouse.3 ungetmouse.3 \
+ curs_mouse.3 wenclose.3 curs_mouse.3 wmouse_trafo.3
+MLINKS+=curs_move.3 move.3 curs_move.3 wmove.3
+MLINKS+=curs_outopts.3 clearok.3 curs_outopts.3 idcok.3 curs_outopts.3 idlok.3 \
+ curs_outopts.3 immedok.3 curs_outopts.3 leaveok.3 curs_outopts.3 nl.3 \
+ curs_outopts.3 nonl.3 curs_outopts.3 scrollok.3 \
+ curs_outopts.3 setscrreg.3 curs_outopts.3 wsetscrreg.3
+MLINKS+=curs_overlay.3 copywin.3 curs_overlay.3 overlay.3 \
+ curs_overlay.3 overwrite.3
+MLINKS+=curs_pad.3 newpad.3 curs_pad.3 pechochar.3 curs_pad.3 pnoutrefresh.3 \
+ curs_pad.3 prefresh.3 curs_pad.3 subpad.3
+MLINKS+=curs_print.3 mcprint.3
+MLINKS+=curs_printw.3 mvprintw.3 curs_printw.3 mvwprintw.3 \
+ curs_printw.3 printw.3 curs_printw.3 vw_printw.3 \
+ curs_printw.3 vwprintw.3 curs_printw.3 wprintw.3
+MLINKS+=curs_refresh.3 doupdate.3 curs_refresh.3 redrawwin.3 \
+ curs_refresh.3 refresh.3 curs_refresh.3 wnoutrefresh.3 \
+ curs_refresh.3 wredrawln.3 curs_refresh.3 wrefresh.3
+MLINKS+=curs_scanw.3 mvscanw.3 curs_scanw.3 mvwscanw.3 curs_scanw.3 scanw.3 \
+ curs_scanw.3 vw_scanw.3 curs_scanw.3 vwscanw.3 curs_scanw.3 wscanw.3
+MLINKS+=curs_scr_dump.3 scr_dump.3 curs_scr_dump.3 scr_init.3 \
+ curs_scr_dump.3 scr_restore.3 curs_scr_dump.3 scr_set.3
+MLINKS+=curs_scroll.3 scrl.3 curs_scroll.3 scroll.3 curs_scroll.3 wscrl.3
+MLINKS+=curs_slk.3 slk_attr.3 curs_slk.3 slk_attr_off.3 \
+ curs_slk.3 slk_attr_on.3 curs_slk.3 slk_attr_set.3 \
+ curs_slk.3 slk_attroff.3 curs_slk.3 slk_attron.3 \
+ curs_slk.3 slk_attrset.3 curs_slk.3 slk_clear.3 \
+ curs_slk.3 slk_color.3 curs_slk.3 slk_init.3 curs_slk.3 slk_label.3 \
+ curs_slk.3 slk_noutrefresh.3 curs_slk.3 slk_refresh.3 \
+ curs_slk.3 slk_restore.3 curs_slk.3 slk_set.3 curs_slk.3 slk_touch.3
+MLINKS+=curs_termattrs.3 baudrate.3 curs_termattrs.3 erasechar.3 \
+ curs_termattrs.3 has_ic.3 curs_termattrs.3 has_il.3 \
+ curs_termattrs.3 killchar.3 curs_termattrs.3 longname.3 \
+ curs_termattrs.3 termattrs.3 curs_termattrs.3 termname.3
+MLINKS+=curs_termcap.3 termcap.3 curs_termcap.3 tgetent.3 \
+ curs_termcap.3 tgetflag.3 curs_termcap.3 tgetnum.3 \
+ curs_termcap.3 tgetstr.3 curs_termcap.3 tgoto.3 \
+ curs_termcap.3 tputs.3
+MLINKS+=curs_terminfo.3 del_curterm.3 curs_terminfo.3 mvcur.3 \
+ curs_terminfo.3 putp.3 curs_terminfo.3 restartterm.3 \
+ curs_terminfo.3 set_curterm.3 curs_terminfo.3 setterm.3 \
+ curs_terminfo.3 setupterm.3 curs_terminfo.3 tigetflag.3 \
+ curs_terminfo.3 tigetnum.3 curs_terminfo.3 tigetstr.3 \
+ curs_terminfo.3 tparm.3 curs_terminfo.3 tputs.3 \
+ curs_terminfo.3 vidattr.3 curs_terminfo.3 vidputs.3
+MLINKS+=curs_touch.3 is_linetouched.3 curs_touch.3 is_wintouched.3 \
+ curs_touch.3 touchline.3 curs_touch.3 touchwin.3 \
+ curs_touch.3 untouchwin.3 curs_touch.3 wtouchln.3
+MLINKS+=curs_util.3 delay_output.3 curs_util.3 filter.3 \
+ curs_util.3 flushinp.3 curs_util.3 getwin.3 \
+ curs_util.3 keyname.3 curs_util.3 putwin.3 \
+ curs_util.3 unctrl.3 curs_util.3 use_env.3
+MLINKS+=curs_window.3 delwin.3 curs_window.3 derwin.3 curs_window.3 dupwin.3 \
+ curs_window.3 mvderwin.3 curs_window.3 mvwin.3 curs_window.3 newwin.3 \
+ curs_window.3 subwin.3 curs_window.3 syncok.3 \
+ curs_window.3 wcursyncup.3 curs_window.3 wsyncdown.3 \
+ curs_window.3 wsyncup.3
+MLINKS+=default_colors.3 assume_default_colors.3 \
+ default_colors.3 use_default_colors.3
+
+NO_LINT=
+
+.include <bsd.lib.mk>
diff --git a/lib/libncurses/ncurses_cfg.h b/lib/libncurses/ncurses_cfg.h
new file mode 100644
index 0000000..3fc4c2b
--- /dev/null
+++ b/lib/libncurses/ncurses_cfg.h
@@ -0,0 +1,155 @@
+/* include/ncurses_cfg.h. Generated automatically by configure. */
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Thomas E. Dickey <dickey@clark.net> 1997 *
+ ****************************************************************************/
+/*
+ * $Id: ncurses_cfg.hin,v 1.3 2000/09/02 17:13:32 tom Exp $
+ *
+ * This is a template-file used to generate the "ncurses_cfg.h" file.
+ *
+ * Rather than list every definition, the configuration script substitutes the
+ * definitions that it finds using 'sed'. You need a patch (original date
+ * 971222) to autoconf 2.12 or 2.13 to do this.
+ *
+ * See:
+ * http://dickey.his.com/autoconf/
+ * ftp://dickey.his.com/autoconf/
+ */
+
+/* $FreeBSD$ */
+
+#ifndef NC_CONFIG_H
+#define NC_CONFIG_H
+
+#define BSD_TPUTS 1
+#define CC_HAS_INLINE_FUNCS 1
+#define CC_HAS_PROTOS 1
+#define GCC_NORETURN __dead2
+#define GCC_PRINTF 1
+#define GCC_SCANF 1
+#define GCC_UNUSED __unused
+#define HAVE_BIG_CORE 1
+#define HAVE_BSD_CGETENT 1
+#define HAVE_CURSES_VERSION 1
+#define HAVE_DIRENT_H 1
+#define HAVE_ERRNO 1
+#define HAVE_FCNTL_H 1
+#define HAVE_FORM_H 1
+#define HAVE_GETCWD 1
+#define HAVE_GETEGID 1
+#define HAVE_GETEUID 1
+#define HAVE_GETTIMEOFDAY 1
+#define HAVE_GETTTYNAM 1
+#define HAVE_HAS_KEY 1
+#define HAVE_ISASCII 1
+#define HAVE_ISSETUGID 1
+#define HAVE_LIBFORM 1
+#define HAVE_LIBMENU 1
+#define HAVE_LIBPANEL 1
+#define HAVE_LIMITS_H 1
+#define HAVE_LINK 1
+#define HAVE_LOCALE_H 1
+#define HAVE_LONG_FILE_NAMES 1
+#define HAVE_MEMCCPY 1
+#define HAVE_MENU_H 1
+#define HAVE_MKSTEMP 1
+#define HAVE_NANOSLEEP 1
+#define HAVE_NC_ALLOC_H 1
+#define HAVE_PANEL_H 1
+#define HAVE_POLL 1
+#define HAVE_POLL_H 1
+#define HAVE_REGEX_H_FUNCS 1
+#define HAVE_REMOVE 1
+#define HAVE_REMOVE 1
+#define HAVE_RESIZETERM 1
+#define HAVE_SELECT 1
+#define HAVE_SETBUF 1
+#define HAVE_SETBUFFER 1
+#define HAVE_SETVBUF 1
+#define HAVE_SIGACTION 1
+#define HAVE_SIGVEC 1
+#define HAVE_SIZECHANGE 1
+#define HAVE_STRDUP 1
+#define HAVE_STRSTR 1
+#define HAVE_SYMLINK 1
+#define HAVE_SYS_IOCTL_H 1
+#define HAVE_SYS_PARAM_H 1
+#define HAVE_SYS_POLL_H 1
+#define HAVE_SYS_SELECT_H 1
+#define HAVE_SYS_TIMES_H 1
+#define HAVE_SYS_TIME_H 1
+#define HAVE_SYS_TIME_SELECT 1
+#define HAVE_TCGETATTR 1
+#define HAVE_TCGETPGRP 1
+#define HAVE_TERMIOS_H 1
+#define HAVE_TIMES 1
+#define HAVE_TTYENT_H 1
+#define HAVE_UNISTD_H 1
+#define HAVE_UNISTD_H 1
+#define HAVE_UNLINK 1
+#define HAVE_USE_DEFAULT_COLORS 1
+#define HAVE_VSNPRINTF 1
+#define HAVE_VSSCANF 1
+#define HAVE_WORKING_POLL 1
+#define HAVE_WRESIZE 1
+#define MIXEDCASE_FILENAMES 1
+#define NCURSES_EXT_FUNCS 1
+#define NCURSES_NO_PADDING 1
+#define NCURSES_PATHSEP ':'
+#define NDEBUG 1
+#define RETSIGTYPE void
+#define STDC_HEADERS 1
+#define SYSTEM_NAME "FreeBSD"
+#define TERMINFO "/usr/share/misc/terminfo"
+#define TERMINFO_DIRS "/usr/share/misc/terminfo"
+#define TIME_WITH_SYS_TIME 1
+#define TYPEOF_CHTYPE long
+#define USE_ASSUMED_COLOR 1
+#define USE_COLORFGBG 1
+#define USE_DATABASE 1
+#define USE_GETCAP 1
+#define USE_HASHMAP 1
+#define USE_SIGWINCH 1
+
+#include <ncurses_def.h>
+
+ /* The C compiler may not treat these properly but C++ has to */
+#ifdef __cplusplus
+#undef const
+#undef inline
+#else
+#if defined(lint) || defined(TRACE)
+#undef inline
+#define inline /* nothing */
+#endif
+#endif
+
+#endif /* NC_CONFIG_H */
diff --git a/lib/libncurses/pathnames.h b/lib/libncurses/pathnames.h
new file mode 100644
index 0000000..5cac36f
--- /dev/null
+++ b/lib/libncurses/pathnames.h
@@ -0,0 +1,38 @@
+/*
+ * 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. 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.
+ *
+ * @(#)pathnames.h 8.1 (Berkeley) 6/4/93
+ * $FreeBSD$
+ */
+
+#define _PATH_DEF ".termcap /usr/share/misc/termcap"
+#define _PATH_DEF_SEC "/usr/share/misc/termcap"
diff --git a/lib/libncurses/termcap.c b/lib/libncurses/termcap.c
new file mode 100644
index 0000000..24e71d3
--- /dev/null
+++ b/lib/libncurses/termcap.c
@@ -0,0 +1,267 @@
+/* A portion of this file is from ncurses: */
+/***************************************************************************
+* COPYRIGHT NOTICE *
+****************************************************************************
+* ncurses is copyright (C) 1992-1995 *
+* Zeyd M. Ben-Halim *
+* zmbenhal@netcom.com *
+* Eric S. Raymond *
+* esr@snark.thyrsus.com *
+* *
+* Permission is hereby granted to reproduce and distribute ncurses *
+* by any means and for any fee, whether alone or as part of a *
+* larger distribution, in source or in binary form, PROVIDED *
+* this notice is included with any such distribution, and is not *
+* removed from any of its header files. Mention of ncurses in any *
+* applications linked with it is highly appreciated. *
+* *
+* ncurses comes AS IS with no warranty, implied or expressed. *
+* *
+***************************************************************************/
+
+#include <curses.priv.h>
+
+#include <string.h>
+#include <term.h>
+#include <tic.h>
+#include <term_entry.h>
+
+/* The rest is from BSD */
+/*
+ * 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.
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifndef lint
+static const char sccsid[] = "@(#)termcap.c 8.1 (Berkeley) 6/4/93";
+#endif /* not lint */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include "pathnames.h"
+
+#define PBUFSIZ MAXPATHLEN /* max length of filename path */
+#define PVECSIZ 32 /* max number of names in path */
+#define TBUFSIZ 1024 /* max length of _nc_tgetent buffer */
+
+char _nc_termcap[TBUFSIZ + 1]; /* Last getcap, provided to tgetent() emul */
+
+/*
+ * termcap - routines for dealing with the terminal capability data base
+ *
+ * BUG: Should use a "last" pointer in tbuf, so that searching
+ * for capabilities alphabetically would not be a n**2/2
+ * process when large numbers of capabilities are given.
+ * Note: If we add a last pointer now we will screw up the
+ * tc capability. We really should compile termcap.
+ *
+ * Essentially all the work here is scanning and decoding escapes
+ * in string capabilities. We don't use stdio because the editor
+ * doesn't, and because living w/o it is not hard.
+ */
+
+/*
+ * Get an entry for terminal name in buffer _nc_termcap from the termcap
+ * file.
+ */
+int
+_nc_read_termcap_entry(const char *const name, TERMTYPE *const tp)
+{
+ ENTRY *ep;
+ char *p;
+ char *cp;
+ char *dummy;
+ char **fname;
+ char *home;
+ int i;
+ char pathbuf[PBUFSIZ]; /* holds raw path of filenames */
+ char *pathvec[PVECSIZ]; /* to point to names in pathbuf */
+ char **pvec; /* holds usable tail of path vector */
+ char *termpath;
+
+ _nc_termcap[0] = '\0'; /* in case */
+ dummy = NULL;
+ fname = pathvec;
+ pvec = pathvec;
+ p = pathbuf;
+ cp = getenv("TERMCAP");
+ /*
+ * TERMCAP can have one of two things in it. It can be the
+ * name of a file to use instead of /etc/termcap. In this
+ * case it better start with a "/". Or it can be an entry to
+ * use so we don't have to read the file. In this case it
+ * has to already have the newlines crunched out. If TERMCAP
+ * does not hold a file name then a path of names is searched
+ * instead. The path is found in the TERMPATH variable, or
+ * becomes "$HOME/.termcap /etc/termcap" if no TERMPATH exists.
+ */
+ if (!cp || *cp != '/') { /* no TERMCAP or it holds an entry */
+ if ( (termpath = getenv("TERMPATH")) )
+ strncpy(pathbuf, termpath, PBUFSIZ);
+ else {
+ if ( (home = getenv("HOME")) ) {/* set up default */
+ strncpy(pathbuf, home, PBUFSIZ - 1); /* $HOME first */
+ pathbuf[PBUFSIZ - 2] = '\0'; /* -2 because we add a slash */
+ p += strlen(pathbuf); /* path, looking in */
+ *p++ = '/';
+ } /* if no $HOME look in current directory */
+ strncpy(p, _PATH_DEF, PBUFSIZ - (p - pathbuf));
+ }
+ }
+ else /* user-defined name in TERMCAP */
+ strncpy(pathbuf, cp, PBUFSIZ); /* still can be tokenized */
+
+ /* For safety */
+ if (issetugid())
+ strcpy(pathbuf, _PATH_DEF_SEC);
+
+ pathbuf[PBUFSIZ - 1] = '\0';
+
+ *fname++ = pathbuf; /* tokenize path into vector of names */
+ while (*++p)
+ if (*p == ' ' || *p == ':') {
+ *p = '\0';
+ while (*++p)
+ if (*p != ' ' && *p != ':')
+ break;
+ if (*p == '\0')
+ break;
+ *fname++ = p;
+ if (fname >= pathvec + PVECSIZ) {
+ fname--;
+ break;
+ }
+ }
+ *fname = (char *) 0; /* mark end of vector */
+ if (cp && *cp && *cp != '/')
+ if (cgetset(cp) < 0)
+ return(-2);
+
+ i = cgetent(&dummy, pathvec, (char *)name);
+
+ if (i == 0) {
+ char *pd, *ps, *tok, *s, *tcs;
+ size_t len;
+
+ pd = _nc_termcap;
+ ps = dummy;
+ if ((tok = strchr(ps, ':')) == NULL) {
+ len = strlen(ps);
+ if (len >= TBUFSIZ)
+ i = -1;
+ else
+ strcpy(pd, ps);
+ goto done;
+ }
+ len = tok - ps + 1;
+ if (pd + len + 1 - _nc_termcap >= TBUFSIZ) {
+ i = -1;
+ goto done;
+ }
+ memcpy(pd, ps, len);
+ ps += len;
+ pd += len;
+ *pd = '\0';
+ tcs = pd - 1;
+ for (;;) {
+ while ((tok = strsep(&ps, ":")) != NULL &&
+ *(tok - 2) != '\\' &&
+ (*tok == '\0' || *tok == '\\' || !isgraph(*tok)))
+ ;
+ if (tok == NULL)
+ break;
+ for (s = tcs; s != NULL && s[1] != '\0';
+ s = strchr(s, ':')) {
+ s++;
+ if (s[0] == tok[0] && s[1] == tok[1])
+ goto skip_it;
+ }
+ len = strlen(tok);
+ if (pd + len + 1 - _nc_termcap >= TBUFSIZ) {
+ i = -1;
+ break;
+ }
+ memcpy(pd, tok, len);
+ pd += len;
+ *pd++ = ':';
+ *pd = '\0';
+ skip_it: ;
+ }
+ }
+done:
+ if (dummy)
+ free(dummy);
+
+
+/*
+ * From here on is ncurses-specific glue code
+ */
+
+ if (i < 0)
+ return(ERR);
+
+ _nc_set_source("TERMCAP");
+ _nc_read_entry_source((FILE *)NULL, _nc_termcap, FALSE, TRUE, NULLHOOK);
+
+ if (_nc_head == (ENTRY *)NULL)
+ return(ERR);
+
+ /* resolve all use references */
+ _nc_resolve_uses(TRUE);
+
+ for_entry_list(ep)
+ if (_nc_name_match(ep->tterm.term_names, name, "|:"))
+ {
+ /*
+ * Make a local copy of the terminal capabilities. free
+ * all entry storage except the string table for the
+ * loaded type (which we disconnected from the list by
+ * NULLing out ep->tterm.str_table above).
+ */
+ memcpy(tp, &ep->tterm, sizeof(TERMTYPE));
+ ep->tterm.str_table = (char *)NULL;
+ _nc_free_entries(_nc_head);
+ _nc_head = _nc_tail = NULL; /* do not reuse! */
+
+ return 1; /* OK */
+ }
+
+ _nc_free_entries(_nc_head);
+ _nc_head = _nc_tail = NULL; /* do not reuse! */
+ return(0); /* not found */
+}
diff --git a/lib/libnetgraph/Makefile b/lib/libnetgraph/Makefile
new file mode 100644
index 0000000..42596e2
--- /dev/null
+++ b/lib/libnetgraph/Makefile
@@ -0,0 +1,28 @@
+# $FreeBSD$
+# $Whistle: Makefile,v 1.4 1999/01/17 03:41:02 julian Exp $
+
+LIB= netgraph
+WARNS?= 3
+MAN= netgraph.3
+
+SHLIB_MAJOR= 2
+
+SRCS= sock.c msg.c debug.c
+INCS= netgraph.h
+
+MLINKS+= netgraph.3 NgMkSockNode.3
+MLINKS+= netgraph.3 NgNameNode.3
+MLINKS+= netgraph.3 NgSendMsg.3
+MLINKS+= netgraph.3 NgSendAsciiMsg.3
+MLINKS+= netgraph.3 NgSendMsgReply.3
+MLINKS+= netgraph.3 NgRecvMsg.3
+MLINKS+= netgraph.3 NgAllocRecvMsg.3
+MLINKS+= netgraph.3 NgRecvAsciiMsg.3
+MLINKS+= netgraph.3 NgAllocRecvAsciiMsg.3
+MLINKS+= netgraph.3 NgSendData.3
+MLINKS+= netgraph.3 NgRecvData.3
+MLINKS+= netgraph.3 NgAllocRecvData.3
+MLINKS+= netgraph.3 NgSetDebug.3
+MLINKS+= netgraph.3 NgSetErrLog.3
+
+.include <bsd.lib.mk>
diff --git a/lib/libnetgraph/debug.c b/lib/libnetgraph/debug.c
new file mode 100644
index 0000000..dfc75f5
--- /dev/null
+++ b/lib/libnetgraph/debug.c
@@ -0,0 +1,346 @@
+/*
+ * debug.c
+ *
+ * Copyright (c) 1996-1999 Whistle Communications, Inc.
+ * 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 Whistle Communications;
+ * provided, however, that:
+ * 1. Any and all reproductions of the source or object code must include the
+ * copyright notice above and the following disclaimer of warranties; and
+ * 2. No rights are granted, in any manner or form, to use Whistle
+ * Communications, Inc. trademarks, including the mark "WHISTLE
+ * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+ * such appears in the above copyright notice or in the software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS 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.
+ * WHISTLE COMMUNICATIONS 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 WHISTLE COMMUNICATIONS 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 WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Archie Cobbs <archie@whistle.com>
+ *
+ * $Whistle: debug.c,v 1.24 1999/01/24 01:15:33 archie Exp $
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+
+#include <stdarg.h>
+
+#include <netinet/in.h>
+#include <net/ethernet.h>
+#include <net/bpf.h>
+
+#include <netgraph/ng_message.h>
+#include <netgraph/ng_socket.h>
+
+#include "netgraph.h"
+#include "internal.h"
+
+#include <netgraph/ng_UI.h>
+#include <netgraph/ng_async.h>
+#include <netgraph/ng_atmllc.h>
+#include <netgraph/ng_bpf.h>
+#include <netgraph/ng_bridge.h>
+#include <netgraph/ng_cisco.h>
+#include <netgraph/ng_device.h>
+#include <netgraph/ng_echo.h>
+#include <netgraph/ng_eiface.h>
+#include <netgraph/ng_etf.h>
+#include <netgraph/ng_ether.h>
+#include <netgraph/ng_fec.h>
+#include <netgraph/ng_frame_relay.h>
+#include <netgraph/ng_gif.h>
+#include <netgraph/ng_gif_demux.h>
+#include <netgraph/ng_hole.h>
+#include <netgraph/ng_hub.h>
+#include <netgraph/ng_iface.h>
+#include <netgraph/ng_ip_input.h>
+#include <netgraph/ng_ipfw.h>
+#include <netgraph/ng_ksocket.h>
+#include <netgraph/ng_l2tp.h>
+#include <netgraph/ng_lmi.h>
+#include <netgraph/ng_mppc.h>
+#include <netgraph/ng_nat.h>
+#include <netgraph/ng_one2many.h>
+#include <netgraph/ng_ppp.h>
+#include <netgraph/ng_pppoe.h>
+#include <netgraph/ng_pptpgre.h>
+#include <netgraph/ng_rfc1490.h>
+#include <netgraph/ng_socket.h>
+#include <netgraph/ng_source.h>
+#include <netgraph/ng_split.h>
+#include <netgraph/ng_sppp.h>
+#include <netgraph/ng_tcpmss.h>
+#include <netgraph/ng_tee.h>
+#include <netgraph/ng_tty.h>
+#include <netgraph/ng_vjc.h>
+#include <netgraph/ng_vlan.h>
+#ifdef WHISTLE
+#include <machine/../isa/df_def.h>
+#include <machine/../isa/if_wfra.h>
+#include <machine/../isa/ipac.h>
+#include <netgraph/ng_df.h>
+#include <netgraph/ng_ipac.h>
+#include <netgraph/ng_tn.h>
+#endif
+
+/* Global debug level */
+int _gNgDebugLevel = 0;
+
+/* Debug printing functions */
+void (*_NgLog) (const char *fmt,...) = warn;
+void (*_NgLogx) (const char *fmt,...) = warnx;
+
+/* Internal functions */
+static const char *NgCookie(int cookie);
+
+/* Known typecookie list */
+struct ng_cookie {
+ int cookie;
+ const char *type;
+};
+
+#define COOKIE(c) { NGM_ ## c ## _COOKIE, #c }
+
+/* List of known cookies */
+static const struct ng_cookie cookies[] = {
+ COOKIE(UI),
+ COOKIE(ASYNC),
+ COOKIE(ATMLLC),
+ COOKIE(BPF),
+ COOKIE(BRIDGE),
+ COOKIE(CISCO),
+ COOKIE(DEVICE),
+ COOKIE(ECHO),
+ COOKIE(EIFACE),
+ COOKIE(ETF),
+ COOKIE(ETHER),
+ COOKIE(FEC),
+ COOKIE(FRAMERELAY),
+ COOKIE(GIF),
+ COOKIE(GIF_DEMUX),
+ COOKIE(GENERIC),
+ COOKIE(HOLE),
+ COOKIE(HUB),
+ COOKIE(IFACE),
+ COOKIE(IP_INPUT),
+ COOKIE(IPFW),
+ COOKIE(KSOCKET),
+ COOKIE(L2TP),
+ COOKIE(LMI),
+ COOKIE(MPPC),
+ COOKIE(NAT),
+ COOKIE(ONE2MANY),
+ COOKIE(PPP),
+ COOKIE(PPPOE),
+ COOKIE(PPTPGRE),
+ COOKIE(RFC1490),
+ COOKIE(SOCKET),
+ COOKIE(SOURCE),
+ COOKIE(SPLIT),
+ COOKIE(SPPP),
+ COOKIE(TCPMSS),
+ COOKIE(TEE),
+ COOKIE(TTY),
+ COOKIE(VJC),
+ COOKIE(VLAN),
+#ifdef WHISTLE
+ COOKIE(DF),
+ COOKIE(IPAC),
+ COOKIE(TN),
+ COOKIE(WFRA),
+#endif
+ { 0, NULL }
+};
+
+/*
+ * Set debug level, ie, verbosity, if "level" is non-negative.
+ * Returns old debug level.
+ */
+int
+NgSetDebug(int level)
+{
+ int old = _gNgDebugLevel;
+
+ if (level < 0)
+ level = old;
+ _gNgDebugLevel = level;
+ return (old);
+}
+
+/*
+ * Set debug logging functions.
+ */
+void
+NgSetErrLog(void (*log) (const char *fmt,...),
+ void (*logx) (const char *fmt,...))
+{
+ _NgLog = log;
+ _NgLogx = logx;
+}
+
+/*
+ * Display a netgraph sockaddr
+ */
+void
+_NgDebugSockaddr(const struct sockaddr_ng *sg)
+{
+ NGLOGX("SOCKADDR: { fam=%d len=%d addr=\"%s\" }",
+ sg->sg_family, sg->sg_len, sg->sg_data);
+}
+
+#define ARGS_BUFSIZE 2048
+#define RECURSIVE_DEBUG_ADJUST 4
+
+/*
+ * Display a negraph message
+ */
+void
+_NgDebugMsg(const struct ng_mesg *msg, const char *path)
+{
+ u_char buf[2 * sizeof(struct ng_mesg) + ARGS_BUFSIZE];
+ struct ng_mesg *const req = (struct ng_mesg *)buf;
+ struct ng_mesg *const bin = (struct ng_mesg *)req->data;
+ int arglen, csock = -1;
+
+ /* Display header stuff */
+ NGLOGX("NG_MESG :");
+ NGLOGX(" vers %d", msg->header.version);
+ NGLOGX(" arglen %d", msg->header.arglen);
+ NGLOGX(" flags %ld", msg->header.flags);
+ NGLOGX(" token %lu", (u_long)msg->header.token);
+ NGLOGX(" cookie %s (%d)",
+ NgCookie(msg->header.typecookie), msg->header.typecookie);
+
+ /* At lower debugging levels, skip ASCII translation */
+ if (_gNgDebugLevel <= 2)
+ goto fail2;
+
+ /* If path is not absolute, don't bother trying to use relative
+ address on a different socket for the ASCII translation */
+ if (strchr(path, ':') == NULL)
+ goto fail2;
+
+ /* Get a temporary socket */
+ if (NgMkSockNode(NULL, &csock, NULL) < 0)
+ goto fail;
+
+ /* Copy binary message into request message payload */
+ arglen = msg->header.arglen;
+ if (arglen > ARGS_BUFSIZE)
+ arglen = ARGS_BUFSIZE;
+ memcpy(bin, msg, sizeof(*msg) + arglen);
+ bin->header.arglen = arglen;
+
+ /* Lower debugging to avoid infinite recursion */
+ _gNgDebugLevel -= RECURSIVE_DEBUG_ADJUST;
+
+ /* Ask the node to translate the binary message to ASCII for us */
+ if (NgSendMsg(csock, path, NGM_GENERIC_COOKIE,
+ NGM_BINARY2ASCII, bin, sizeof(*bin) + bin->header.arglen) < 0) {
+ _gNgDebugLevel += RECURSIVE_DEBUG_ADJUST;
+ goto fail;
+ }
+ if (NgRecvMsg(csock, req, sizeof(buf), NULL) < 0) {
+ _gNgDebugLevel += RECURSIVE_DEBUG_ADJUST;
+ goto fail;
+ }
+
+ /* Restore debugging level */
+ _gNgDebugLevel += RECURSIVE_DEBUG_ADJUST;
+
+ /* Display command string and arguments */
+ NGLOGX(" cmd %s (%d)", bin->header.cmdstr, bin->header.cmd);
+ NGLOGX(" args %s", bin->data);
+ goto done;
+
+fail:
+ /* Just display binary version */
+ NGLOGX(" [error decoding message: %s]", strerror(errno));
+fail2:
+ NGLOGX(" cmd %d", msg->header.cmd);
+ NGLOGX(" args (%d bytes)", msg->header.arglen);
+ _NgDebugBytes((u_char *)msg->data, msg->header.arglen);
+
+done:
+ if (csock != -1)
+ (void)close(csock);
+}
+
+/*
+ * Return the name of the node type corresponding to the cookie
+ */
+static const char *
+NgCookie(int cookie)
+{
+ int k;
+
+ for (k = 0; cookies[k].cookie != 0; k++) {
+ if (cookies[k].cookie == cookie)
+ return cookies[k].type;
+ }
+ return "??";
+}
+
+/*
+ * Dump bytes in hex
+ */
+void
+_NgDebugBytes(const u_char *ptr, int len)
+{
+ char buf[100];
+ int k, count;
+
+#define BYPERLINE 16
+
+ for (count = 0; count < len; ptr += BYPERLINE, count += BYPERLINE) {
+
+ /* Do hex */
+ snprintf(buf, sizeof(buf), "%04x: ", count);
+ for (k = 0; k < BYPERLINE; k++, count++)
+ if (count < len)
+ snprintf(buf + strlen(buf),
+ sizeof(buf) - strlen(buf), "%02x ", ptr[k]);
+ else
+ snprintf(buf + strlen(buf),
+ sizeof(buf) - strlen(buf), " ");
+ snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " ");
+ count -= BYPERLINE;
+
+ /* Do ASCII */
+ for (k = 0; k < BYPERLINE; k++, count++)
+ if (count < len)
+ snprintf(buf + strlen(buf),
+ sizeof(buf) - strlen(buf),
+ "%c", isprint(ptr[k]) ? ptr[k] : '.');
+ else
+ snprintf(buf + strlen(buf),
+ sizeof(buf) - strlen(buf), " ");
+ count -= BYPERLINE;
+
+ /* Print it */
+ NGLOGX("%s", buf);
+ }
+}
+
diff --git a/lib/libnetgraph/internal.h b/lib/libnetgraph/internal.h
new file mode 100644
index 0000000..0c947e5
--- /dev/null
+++ b/lib/libnetgraph/internal.h
@@ -0,0 +1,74 @@
+
+/*
+ * internal.h
+ *
+ * Copyright (c) 1996-1999 Whistle Communications, Inc.
+ * 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 Whistle Communications;
+ * provided, however, that:
+ * 1. Any and all reproductions of the source or object code must include the
+ * copyright notice above and the following disclaimer of warranties; and
+ * 2. No rights are granted, in any manner or form, to use Whistle
+ * Communications, Inc. trademarks, including the mark "WHISTLE
+ * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+ * such appears in the above copyright notice or in the software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS 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.
+ * WHISTLE COMMUNICATIONS 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 WHISTLE COMMUNICATIONS 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 WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Archie Cobbs <archie@whistle.com>
+ *
+ * $FreeBSD$
+ * $Whistle: internal.h,v 1.5 1999/01/20 00:57:22 archie Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/linker.h>
+#include <stddef.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <ctype.h>
+#include <err.h>
+
+/* the 'sockaddr overhead' for a netgraph address. This is everything before
+ * the string that constitutes the address. */
+#define NGSA_OVERHEAD (offsetof(struct sockaddr_ng, sg_data))
+
+extern int _gNgDebugLevel;
+
+extern void (*_NgLog)(const char *fmt, ...);
+extern void (*_NgLogx)(const char *fmt, ...);
+
+#define NGLOG (*_NgLog)
+#define NGLOGX (*_NgLogx)
+
+extern void _NgDebugSockaddr(const struct sockaddr_ng *sg);
+extern void _NgDebugMsg(const struct ng_mesg *msg, const char *path);
+extern void _NgDebugBytes(const u_char *ptr, int size);
+
diff --git a/lib/libnetgraph/msg.c b/lib/libnetgraph/msg.c
new file mode 100644
index 0000000..8b4ca06
--- /dev/null
+++ b/lib/libnetgraph/msg.c
@@ -0,0 +1,378 @@
+/*
+ * msg.c
+ *
+ * Copyright (c) 1996-1999 Whistle Communications, Inc.
+ * 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 Whistle Communications;
+ * provided, however, that:
+ * 1. Any and all reproductions of the source or object code must include the
+ * copyright notice above and the following disclaimer of warranties; and
+ * 2. No rights are granted, in any manner or form, to use Whistle
+ * Communications, Inc. trademarks, including the mark "WHISTLE
+ * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+ * such appears in the above copyright notice or in the software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS 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.
+ * WHISTLE COMMUNICATIONS 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 WHISTLE COMMUNICATIONS 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 WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Archie Cobbs <archie@whistle.com>
+ *
+ * $Whistle: msg.c,v 1.9 1999/01/20 00:57:23 archie Exp $
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <stdarg.h>
+#include <netgraph/ng_message.h>
+#include <netgraph/ng_socket.h>
+
+#include "netgraph.h"
+#include "internal.h"
+
+/* Next message token value */
+static int gMsgId;
+
+/* For delivering both messages and replies */
+static int NgDeliverMsg(int cs, const char *path,
+ const struct ng_mesg *hdr, const void *args, size_t arglen);
+
+/*
+ * Send a message to a node using control socket node "cs".
+ * Returns -1 if error and sets errno appropriately.
+ * If successful, returns the message ID (token) used.
+ */
+int
+NgSendMsg(int cs, const char *path,
+ int cookie, int cmd, const void *args, size_t arglen)
+{
+ struct ng_mesg msg;
+
+ /* Prepare message header */
+ memset(&msg, 0, sizeof(msg));
+ msg.header.version = NG_VERSION;
+ msg.header.typecookie = cookie;
+ if (++gMsgId < 0)
+ gMsgId = 1;
+ msg.header.token = gMsgId;
+ msg.header.flags = NGF_ORIG;
+ msg.header.cmd = cmd;
+ snprintf((char *)msg.header.cmdstr, NG_CMDSTRSIZ, "cmd%d", cmd);
+
+ /* Deliver message */
+ if (NgDeliverMsg(cs, path, &msg, args, arglen) < 0)
+ return (-1);
+ return (msg.header.token);
+}
+
+/*
+ * Send a message given in ASCII format. We first ask the node to translate
+ * the command into binary, and then we send the binary.
+ */
+int
+NgSendAsciiMsg(int cs, const char *path, const char *fmt, ...)
+{
+ struct ng_mesg *reply, *binary, *ascii;
+ char *buf, *cmd, *args;
+ va_list fmtargs;
+ int token;
+
+ /* Parse out command and arguments */
+ va_start(fmtargs, fmt);
+ vasprintf(&buf, fmt, fmtargs);
+ va_end(fmtargs);
+ if (buf == NULL)
+ return (-1);
+
+ /* Parse out command, arguments */
+ for (cmd = buf; isspace(*cmd); cmd++)
+ ;
+ for (args = cmd; *args != '\0' && !isspace(*args); args++)
+ ;
+ if (*args != '\0') {
+ while (isspace(*args))
+ *args++ = '\0';
+ }
+
+ /* Get a bigger buffer to hold inner message header plus arg string */
+ if ((ascii = malloc(sizeof(struct ng_mesg)
+ + strlen(args) + 1)) == NULL) {
+ free(buf);
+ return (-1);
+ }
+ memset(ascii, 0, sizeof(*ascii));
+
+ /* Build inner header (only need cmdstr, arglen, and data fields) */
+ strncpy((char *)ascii->header.cmdstr, cmd,
+ sizeof(ascii->header.cmdstr) - 1);
+ strcpy(ascii->data, args);
+ ascii->header.arglen = strlen(ascii->data) + 1;
+ free(buf);
+
+ /* Send node a request to convert ASCII to binary */
+ if (NgSendMsg(cs, path, NGM_GENERIC_COOKIE, NGM_ASCII2BINARY,
+ (u_char *)ascii, sizeof(*ascii) + ascii->header.arglen) < 0) {
+ free(ascii);
+ return (-1);
+ }
+ free(ascii);
+
+ /* Get reply */
+ if (NgAllocRecvMsg(cs, &reply, NULL) < 0)
+ return (-1);
+
+ /* Now send binary version */
+ binary = (struct ng_mesg *)reply->data;
+ if (++gMsgId < 0)
+ gMsgId = 1;
+ binary->header.token = gMsgId;
+ binary->header.version = NG_VERSION;
+ if (NgDeliverMsg(cs,
+ path, binary, binary->data, binary->header.arglen) < 0) {
+ free(reply);
+ return (-1);
+ }
+ token = binary->header.token;
+ free(reply);
+ return (token);
+}
+
+/*
+ * Send a message that is a reply to a previously received message.
+ * Returns -1 and sets errno on error, otherwise returns zero.
+ */
+int
+NgSendReplyMsg(int cs, const char *path,
+ const struct ng_mesg *msg, const void *args, size_t arglen)
+{
+ struct ng_mesg rep;
+
+ /* Prepare message header */
+ rep = *msg;
+ rep.header.flags = NGF_RESP;
+
+ /* Deliver message */
+ return (NgDeliverMsg(cs, path, &rep, args, arglen));
+}
+
+/*
+ * Send a message to a node using control socket node "cs".
+ * Returns -1 if error and sets errno appropriately, otherwise zero.
+ */
+static int
+NgDeliverMsg(int cs, const char *path,
+ const struct ng_mesg *hdr, const void *args, size_t arglen)
+{
+ u_char sgbuf[NG_PATHSIZ + NGSA_OVERHEAD];
+ struct sockaddr_ng *const sg = (struct sockaddr_ng *) sgbuf;
+ u_char *buf = NULL;
+ struct ng_mesg *msg;
+ int errnosv = 0;
+ int rtn = 0;
+
+ /* Sanity check */
+ if (args == NULL)
+ arglen = 0;
+
+ /* Get buffer */
+ if ((buf = malloc(sizeof(*msg) + arglen)) == NULL) {
+ errnosv = errno;
+ if (_gNgDebugLevel >= 1)
+ NGLOG("malloc");
+ rtn = -1;
+ goto done;
+ }
+ msg = (struct ng_mesg *) buf;
+
+ /* Finalize message */
+ *msg = *hdr;
+ msg->header.arglen = arglen;
+ memcpy(msg->data, args, arglen);
+
+ /* Prepare socket address */
+ sg->sg_family = AF_NETGRAPH;
+ /* XXX handle overflow */
+ strlcpy(sg->sg_data, path, NG_PATHSIZ);
+ sg->sg_len = strlen(sg->sg_data) + 1 + NGSA_OVERHEAD;
+
+ /* Debugging */
+ if (_gNgDebugLevel >= 2) {
+ NGLOGX("SENDING %s:",
+ (msg->header.flags & NGF_RESP) ? "RESPONSE" : "MESSAGE");
+ _NgDebugSockaddr(sg);
+ _NgDebugMsg(msg, sg->sg_data);
+ }
+
+ /* Send it */
+ if (sendto(cs, msg, sizeof(*msg) + arglen,
+ 0, (struct sockaddr *) sg, sg->sg_len) < 0) {
+ errnosv = errno;
+ if (_gNgDebugLevel >= 1)
+ NGLOG("sendto(%s)", sg->sg_data);
+ rtn = -1;
+ goto done;
+ }
+
+ /* Wait for reply if there should be one. */
+ if (msg->header.cmd & NGM_HASREPLY) {
+ fd_set rfds;
+ int n;
+
+ FD_ZERO(&rfds);
+ FD_SET(cs, &rfds);
+ n = select(cs + 1, &rfds, NULL, NULL, NULL);
+ if (n == -1) {
+ errnosv = errno;
+ if (_gNgDebugLevel >= 1)
+ NGLOG("select");
+ rtn = -1;
+ }
+ }
+
+done:
+ /* Done */
+ free(buf); /* OK if buf is NULL */
+ errno = errnosv;
+ return (rtn);
+}
+
+/*
+ * Receive a control message.
+ *
+ * On error, this returns -1 and sets errno.
+ * Otherwise, it returns the length of the received reply.
+ */
+int
+NgRecvMsg(int cs, struct ng_mesg *rep, size_t replen, char *path)
+{
+ u_char sgbuf[NG_PATHSIZ + NGSA_OVERHEAD];
+ struct sockaddr_ng *const sg = (struct sockaddr_ng *) sgbuf;
+ socklen_t sglen = sizeof(sgbuf);
+ int len, errnosv;
+
+ /* Read reply */
+ len = recvfrom(cs, rep, replen, 0, (struct sockaddr *) sg, &sglen);
+ if (len < 0) {
+ errnosv = errno;
+ if (_gNgDebugLevel >= 1)
+ NGLOG("recvfrom");
+ goto errout;
+ }
+ if (path != NULL)
+ strlcpy(path, sg->sg_data, NG_PATHSIZ);
+
+ /* Debugging */
+ if (_gNgDebugLevel >= 2) {
+ NGLOGX("RECEIVED %s:",
+ (rep->header.flags & NGF_RESP) ? "RESPONSE" : "MESSAGE");
+ _NgDebugSockaddr(sg);
+ _NgDebugMsg(rep, sg->sg_data);
+ }
+
+ /* Done */
+ return (len);
+
+errout:
+ errno = errnosv;
+ return (-1);
+}
+
+/*
+ * Identical to NgRecvMsg() except buffer is dynamically allocated.
+ */
+int
+NgAllocRecvMsg(int cs, struct ng_mesg **rep, char *path)
+{
+ int len;
+ socklen_t optlen;
+
+ optlen = sizeof(len);
+ if (getsockopt(cs, SOL_SOCKET, SO_RCVBUF, &len, &optlen) == -1 ||
+ (*rep = malloc(len)) == NULL)
+ return (-1);
+ if ((len = NgRecvMsg(cs, *rep, len, path)) < 0)
+ free(*rep);
+ return (len);
+}
+
+/*
+ * Receive a control message and convert the arguments to ASCII
+ */
+int
+NgRecvAsciiMsg(int cs, struct ng_mesg *reply, size_t replen, char *path)
+{
+ struct ng_mesg *msg, *ascii;
+ int bufSize, errnosv;
+ u_char *buf;
+
+ /* Allocate buffer */
+ bufSize = 2 * sizeof(*reply) + replen;
+ if ((buf = malloc(bufSize)) == NULL)
+ return (-1);
+ msg = (struct ng_mesg *)buf;
+ ascii = (struct ng_mesg *)msg->data;
+
+ /* Get binary message */
+ if (NgRecvMsg(cs, msg, bufSize, path) < 0)
+ goto fail;
+ memcpy(reply, msg, sizeof(*msg));
+
+ /* Ask originating node to convert the arguments to ASCII */
+ if (NgSendMsg(cs, path, NGM_GENERIC_COOKIE,
+ NGM_BINARY2ASCII, msg, sizeof(*msg) + msg->header.arglen) < 0)
+ goto fail;
+ if (NgRecvMsg(cs, msg, bufSize, NULL) < 0)
+ goto fail;
+
+ /* Copy result to client buffer */
+ if (sizeof(*ascii) + ascii->header.arglen > replen) {
+ errno = ERANGE;
+fail:
+ errnosv = errno;
+ free(buf);
+ errno = errnosv;
+ return (-1);
+ }
+ strncpy(reply->data, ascii->data, ascii->header.arglen);
+
+ /* Done */
+ free(buf);
+ return (0);
+}
+
+/*
+ * Identical to NgRecvAsciiMsg() except buffer is dynamically allocated.
+ */
+int
+NgAllocRecvAsciiMsg(int cs, struct ng_mesg **reply, char *path)
+{
+ int len;
+ socklen_t optlen;
+
+ optlen = sizeof(len);
+ if (getsockopt(cs, SOL_SOCKET, SO_RCVBUF, &len, &optlen) == -1 ||
+ (*reply = malloc(len)) == NULL)
+ return (-1);
+ if ((len = NgRecvAsciiMsg(cs, *reply, len, path)) < 0)
+ free(*reply);
+ return (len);
+}
diff --git a/lib/libnetgraph/netgraph.3 b/lib/libnetgraph/netgraph.3
new file mode 100644
index 0000000..d2ef8bd
--- /dev/null
+++ b/lib/libnetgraph/netgraph.3
@@ -0,0 +1,398 @@
+.\" Copyright (c) 1996-1999 Whistle Communications, Inc.
+.\" 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 Whistle Communications;
+.\" provided, however, that:
+.\" 1. Any and all reproductions of the source or object code must include the
+.\" copyright notice above and the following disclaimer of warranties; and
+.\" 2. No rights are granted, in any manner or form, to use Whistle
+.\" Communications, Inc. trademarks, including the mark "WHISTLE
+.\" COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+.\" such appears in the above copyright notice or in the software.
+.\"
+.\" THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+.\" TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS 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.
+.\" WHISTLE COMMUNICATIONS 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 WHISTLE COMMUNICATIONS 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 WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+.\" OF SUCH DAMAGE.
+.\"
+.\" Author: Archie Cobbs <archie@whistle.com>
+.\"
+.\" $FreeBSD$
+.\" $Whistle: netgraph.3,v 1.7 1999/01/25 07:14:06 archie Exp $
+.\"
+.Dd January 27, 2004
+.Dt NETGRAPH 3
+.Os
+.Sh NAME
+.Nm NgMkSockNode ,
+.Nm NgNameNode ,
+.Nm NgSendMsg ,
+.Nm NgSendAsciiMsg ,
+.Nm NgSendMsgReply ,
+.Nm NgRecvMsg ,
+.Nm NgAllocRecvMsg ,
+.Nm NgRecvAsciiMsg ,
+.Nm NgAllocRecvAsciiMsg ,
+.Nm NgSendData ,
+.Nm NgRecvData ,
+.Nm NgAllocRecvData ,
+.Nm NgSetDebug ,
+.Nm NgSetErrLog
+.Nd netgraph user library
+.Sh LIBRARY
+.Lb libnetgraph
+.Sh SYNOPSIS
+.In netgraph.h
+.Ft int
+.Fn NgMkSockNode "const char *name" "int *csp" "int *dsp"
+.Ft int
+.Fn NgNameNode "int cs" "const char *path" "const char *fmt" ...
+.Ft int
+.Fo NgSendMsg
+.Fa "int cs" "const char *path" "int cookie" "int cmd" "const void *arg"
+.Fa "size_t arglen"
+.Fc
+.Ft int
+.Fn NgSendAsciiMsg "int cs" "const char *path" "const char *fmt" ...
+.Ft int
+.Fo NgSendMsgReply
+.Fa "int cs" "const char *path" "struct ng_mesg *msg" "const void *arg"
+.Fa "size_t arglen"
+.Fc
+.Ft int
+.Fn NgRecvMsg "int cs" "struct ng_mesg *rep" "size_t replen" "char *path"
+.Ft int
+.Fn NgAllocRecvMsg "int cs" "struct ng_mesg **rep" "char *path"
+.Ft int
+.Fn NgRecvAsciiMsg "int cs" "struct ng_mesg *rep" "size_t replen" "char *path"
+.Ft int
+.Fn NgAllocRecvAsciiMsg "int cs" "struct ng_mesg **rep" "char *path"
+.Ft int
+.Fn NgSendData "int ds" "const char *hook" "const u_char *buf" "size_t len"
+.Ft int
+.Fn NgRecvData "int ds" "u_char *buf" "size_t len" "char *hook"
+.Ft int
+.Fn NgAllocRecvData "int ds" "u_char **buf" "char *hook"
+.Ft int
+.Fn NgSetDebug "int level"
+.Ft void
+.Fo NgSetErrLog
+.Fa "void \*[lp]*log\*[rp]\*[lp]const char *fmt, ...\*[rp]"
+.Fa "void \*[lp]*logx\*[rp]\*[lp]const char *fmt, ...\*[rp]"
+.Fc
+.Sh DESCRIPTION
+These functions facilitate user-mode program participation in the kernel
+.Xr netgraph 4
+graph-based networking system, by utilizing the netgraph
+.Vt socket
+node type (see
+.Xr ng_socket 4 ) .
+.Pp
+The
+.Fn NgMkSockNode
+function should be called first, to create a new
+.Vt socket
+type netgraph node with associated control and data sockets.
+If
+.Fa name
+is
+.No non- Ns Dv NULL ,
+the node will have that global name assigned to it.
+The
+.Fa csp
+and
+.Fa dsp
+arguments will be set to the newly opened control and data sockets
+associated with the node; either
+.Fa csp
+or
+.Fa dsp
+may be
+.Dv NULL
+if only one socket is desired.
+The
+.Fn NgMkSockNode
+function loads the
+.Vt socket
+node type KLD if it is not already loaded.
+.Pp
+The
+.Fn NgNameNode
+function assigns a global name to the node addressed by
+.Fa path .
+.Pp
+The
+.Fn NgSendMsg
+function sends a binary control message from the
+.Vt socket
+node associated with control socket
+.Fa cs
+to the node addressed by
+.Fa path .
+The
+.Fa cookie
+indicates how to interpret
+.Fa cmd ,
+which indicates a specific command.
+Extra argument data (if any) is specified by
+.Fa arg
+and
+.Fa arglen .
+The
+.Fa cookie , cmd ,
+and argument data are defined by the header file corresponding
+to the type of the node being addressed.
+The unique, non-negative token value chosen for use in the message
+header is returned.
+This value is typically used to associate replies.
+.Pp
+Use
+.Fn NgSendMsgReply
+to send reply to a previously received control message.
+The original message header should be pointed to by
+.Fa msg .
+.Pp
+The
+.Fn NgSendAsciiMsg
+function performs the same function as
+.Fn NgSendMsg ,
+but adds support for
+.Tn ASCII
+encoding of control messages.
+The
+.Fn NgSendAsciiMsg
+function formats its input a la
+.Xr printf 3
+and then sends the resulting
+.Tn ASCII
+string to the node in a
+.Dv NGM_ASCII2BINARY
+control message.
+The node returns a binary version of the
+message, which is then sent back to the node just as with
+.Fn NgSendMsg .
+As with
+.Fn NgSendMsg ,
+the message token value is returned.
+Note that
+.Tn ASCII
+conversion may not be supported by all node types.
+.Pp
+The
+.Fn NgRecvMsg
+function reads the next control message received by the node associated with
+control socket
+.Fa cs .
+The message and any extra argument data must fit in
+.Fa replen
+bytes.
+If
+.Fa path
+is
+.No non- Ns Dv NULL ,
+it must point to a buffer of at least
+.Dv NG_PATHSIZ
+bytes, which will be filled in (and
+.Dv NUL
+terminated) with the path to
+the node from which the message was received.
+.Pp
+The length of the control message is returned.
+A return value of zero indicates that the socket was closed.
+.Pp
+The
+.Fn NgAllocRecvMsg
+function works exactly like
+.Fn NgRecvMsg ,
+except that the buffer for a message is dynamically allocated
+to guarantee that a message is not truncated.
+The size of the buffer is equal to the socket's receive buffer size.
+The caller is responsible for freeing the buffer when it is no longer required.
+.Pp
+The
+.Fn NgRecvAsciiMsg
+function works exactly like
+.Fn NgRecvMsg ,
+except that after the message is received, any binary arguments
+are converted to
+.Tn ASCII
+by sending a
+.Dv NGM_BINARY2ASCII
+request back to the originating node.
+The result is the same as
+.Fn NgRecvMsg ,
+with the exception that the reply arguments field will contain a
+.Dv NUL Ns -terminated
+.Tn ASCII
+version of the arguments (and the reply
+header argument length field will be adjusted).
+.Pp
+The
+.Fn NgAllocRecvAsciiMsg
+function works exactly like
+.Fn NgRecvAsciiMsg ,
+except that the buffer for a message is dynamically allocated
+to guarantee that a message is not truncated.
+The size of the buffer is equal to the socket's receive buffer size.
+The caller is responsible for freeing the buffer when it is no longer required.
+.Pp
+The
+.Fn NgSendData
+function writes a data packet out on the specified hook of the node
+corresponding to data socket
+.Fa ds .
+The node must already be connected to some other node via that hook.
+.Pp
+The
+.Fn NgRecvData
+function reads the next data packet (of up to
+.Fa len
+bytes) received by the node corresponding to data socket
+.Fa ds
+and stores it in
+.Fa buf ,
+which must be large enough to hold the entire packet.
+If
+.Fa hook
+is
+.No non- Ns Dv NULL ,
+it must point to a buffer of at least
+.Dv NG_HOOKSIZ
+bytes, which will be filled in (and
+.Dv NUL
+terminated) with the name of
+the hook on which the data was received.
+.Pp
+The length of the packet is returned.
+A return value of zero indicates that the socket was closed.
+.Pp
+The
+.Fn NgAllocRecvData
+function works exactly like
+.Fn NgRecvData ,
+except that the buffer for a data packet is dynamically allocated
+to guarantee that a data packet is not truncated.
+The size of the buffer is equal to the socket's receive buffer size.
+The caller is responsible for freeing the buffer when it is no longer required.
+.Pp
+The
+.Fn NgSetDebug
+and
+.Fn NgSetErrLog
+functions are used for debugging.
+The
+.Fn NgSetDebug
+function sets the debug level (if non-negative), and returns the old setting.
+Higher debug levels result in more verbosity.
+The default is zero.
+All debug and error messages are logged via the functions
+specified in the most recent call to
+.Fn NgSetErrLog .
+The default logging functions are
+.Xr vwarn 3
+and
+.Xr vwarnx 3 .
+.Pp
+At debug level 3, the library attempts to display control message arguments
+in
+.Tn ASCII
+format; however, this results in additional messages being
+sent which may interfere with debugging.
+At even higher levels,
+even these additional messages will be displayed, etc.
+.Pp
+Note that
+.Xr select 2
+can be used on the data and the control sockets to detect the presence of
+incoming data and control messages, respectively.
+Data and control packets are always written and read atomically, i.e.,
+in one whole piece.
+.Pp
+User mode programs must be linked with the
+.Fl l Ns Li netgraph
+flag to link in this library.
+.Sh INITIALIZATION
+To enable netgraph in your kernel, either your kernel must be
+compiled with
+.Cd "options NETGRAPH"
+in the kernel configuration
+file, or else the
+.Xr netgraph 4
+and
+.Xr ng_socket 4
+KLD modules must have been loaded via
+.Xr kldload 8 .
+.Sh RETURN VALUES
+The
+.Fn NgSetDebug
+function returns the previous debug setting.
+.Pp
+The
+.Fn NgSetErrLog
+function has no return value.
+.Pp
+All other functions return \-1 if there was an error and set
+.Va errno
+accordingly.
+.Pp
+A return value of zero from
+.Fn NgRecvMsg
+or
+.Fn NgRecvData
+indicates that the netgraph socket has been closed.
+.Pp
+For
+.Fn NgSendAsciiMsg
+and
+.Fn NgRecvAsciiMsg ,
+the following additional errors are possible:
+.Bl -tag -width Er
+.It Bq Er ENOSYS
+The node type does not know how to encode or decode the control message.
+.It Bq Er ERANGE
+The encoded or decoded arguments were too long for the supplied buffer.
+.It Bq Er ENOENT
+An unknown structure field was seen in an
+.Tn ASCII
+control message.
+.It Bq Er EALREADY
+The same structure field was specified twice in an
+.Tn ASCII
+control message.
+.It Bq Er EINVAL
+.Tn ASCII
+control message parse error or illegal value.
+.It Bq Er E2BIG
+ASCII control message array or fixed width string buffer overflow.
+.El
+.Sh SEE ALSO
+.Xr select 2 ,
+.Xr socket 2 ,
+.Xr warnx 3 ,
+.Xr kld 4 ,
+.Xr netgraph 4 ,
+.Xr ng_socket 4
+.Sh HISTORY
+The
+.Nm netgraph
+system was designed and first implemented at Whistle Communications, Inc.\& in
+a version of
+.Fx 2.2
+customized for the Whistle InterJet.
+.Sh AUTHORS
+.An "Archie Cobbs" Aq archie@FreeBSD.org
diff --git a/lib/libnetgraph/netgraph.h b/lib/libnetgraph/netgraph.h
new file mode 100644
index 0000000..4eb15bd
--- /dev/null
+++ b/lib/libnetgraph/netgraph.h
@@ -0,0 +1,69 @@
+
+/*
+ * netgraph.h
+ *
+ * Copyright (c) 1996-1999 Whistle Communications, Inc.
+ * 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 Whistle Communications;
+ * provided, however, that:
+ * 1. Any and all reproductions of the source or object code must include the
+ * copyright notice above and the following disclaimer of warranties; and
+ * 2. No rights are granted, in any manner or form, to use Whistle
+ * Communications, Inc. trademarks, including the mark "WHISTLE
+ * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+ * such appears in the above copyright notice or in the software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS 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.
+ * WHISTLE COMMUNICATIONS 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 WHISTLE COMMUNICATIONS 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 WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Archie Cobbs <archie@whistle.com>
+ *
+ * $FreeBSD$
+ * $Whistle: netgraph.h,v 1.7 1999/01/20 00:57:23 archie Exp $
+ */
+
+#ifndef _NETGRAPH_H_
+#define _NETGRAPH_H_
+
+#include <sys/types.h>
+#include <netgraph/ng_message.h>
+
+__BEGIN_DECLS
+int NgMkSockNode(const char *, int *, int *);
+int NgNameNode(int, const char *, const char *, ...) __printflike(3, 4);
+int NgSendMsg(int, const char *, int, int, const void *, size_t);
+int NgSendAsciiMsg(int, const char *, const char *, ...) __printflike(3, 4);
+int NgSendReplyMsg(int, const char *,
+ const struct ng_mesg *, const void *, size_t);
+int NgRecvMsg(int, struct ng_mesg *, size_t, char *);
+int NgAllocRecvMsg(int, struct ng_mesg **, char *);
+int NgRecvAsciiMsg(int, struct ng_mesg *, size_t, char *);
+int NgAllocRecvAsciiMsg(int, struct ng_mesg **, char *);
+int NgSendData(int, const char *, const u_char *, size_t);
+int NgRecvData(int, u_char *, size_t, char *);
+int NgAllocRecvData(int, u_char **, char *);
+int NgSetDebug(int);
+void NgSetErrLog(void (*)(const char *fmt, ...),
+ void (*)(const char *fmt, ...));
+__END_DECLS
+
+#endif
+
diff --git a/lib/libnetgraph/sock.c b/lib/libnetgraph/sock.c
new file mode 100644
index 0000000..395f28b
--- /dev/null
+++ b/lib/libnetgraph/sock.c
@@ -0,0 +1,300 @@
+/*
+ * sock.c
+ *
+ * Copyright (c) 1996-1999 Whistle Communications, Inc.
+ * 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 Whistle Communications;
+ * provided, however, that:
+ * 1. Any and all reproductions of the source or object code must include the
+ * copyright notice above and the following disclaimer of warranties; and
+ * 2. No rights are granted, in any manner or form, to use Whistle
+ * Communications, Inc. trademarks, including the mark "WHISTLE
+ * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+ * such appears in the above copyright notice or in the software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS 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.
+ * WHISTLE COMMUNICATIONS 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 WHISTLE COMMUNICATIONS 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 WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Archie Cobbs <archie@whistle.com>
+ *
+ * $Whistle: sock.c,v 1.12 1999/01/20 00:57:23 archie Exp $
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <stdarg.h>
+#include <netgraph/ng_message.h>
+#include <netgraph/ng_socket.h>
+
+#include "netgraph.h"
+#include "internal.h"
+
+/* The socket node type KLD */
+#define NG_SOCKET_KLD "ng_socket.ko"
+
+/*
+ * Create a socket type node and give it the supplied name.
+ * Return data and control sockets corresponding to the node.
+ * Returns -1 if error and sets errno.
+ */
+int
+NgMkSockNode(const char *name, int *csp, int *dsp)
+{
+ char namebuf[NG_NODESIZ];
+ int cs = -1; /* control socket */
+ int ds = -1; /* data socket */
+ int errnosv;
+
+ /* Empty name means no name */
+ if (name && *name == 0)
+ name = NULL;
+
+ /* Create control socket; this also creates the netgraph node.
+ If we get an EPROTONOSUPPORT then the socket node type is
+ not loaded, so load it and try again. */
+ if ((cs = socket(AF_NETGRAPH, SOCK_DGRAM, NG_CONTROL)) < 0) {
+ if (errno == EPROTONOSUPPORT) {
+ if (kldload(NG_SOCKET_KLD) < 0) {
+ errnosv = errno;
+ if (_gNgDebugLevel >= 1)
+ NGLOG("can't load %s", NG_SOCKET_KLD);
+ goto errout;
+ }
+ cs = socket(AF_NETGRAPH, SOCK_DGRAM, NG_CONTROL);
+ if (cs >= 0)
+ goto gotNode;
+ }
+ errnosv = errno;
+ if (_gNgDebugLevel >= 1)
+ NGLOG("socket");
+ goto errout;
+ }
+
+gotNode:
+ /* Assign the node the desired name, if any */
+ if (name != NULL) {
+ u_char sbuf[NG_NODESIZ + NGSA_OVERHEAD];
+ struct sockaddr_ng *const sg = (struct sockaddr_ng *) sbuf;
+
+ /* Assign name */
+ strlcpy(sg->sg_data, name, NG_NODESIZ);
+ sg->sg_family = AF_NETGRAPH;
+ sg->sg_len = strlen(sg->sg_data) + 1 + NGSA_OVERHEAD;
+ if (bind(cs, (struct sockaddr *) sg, sg->sg_len) < 0) {
+ errnosv = errno;
+ if (_gNgDebugLevel >= 1)
+ NGLOG("bind(%s)", sg->sg_data);
+ goto errout;
+ }
+
+ /* Save node name */
+ strlcpy(namebuf, name, sizeof(namebuf));
+ } else if (dsp != NULL) {
+ u_char rbuf[sizeof(struct ng_mesg) + sizeof(struct nodeinfo)];
+ struct ng_mesg *const resp = (struct ng_mesg *) rbuf;
+ struct nodeinfo *const ni = (struct nodeinfo *) resp->data;
+
+ /* Find out the node ID */
+ if (NgSendMsg(cs, ".", NGM_GENERIC_COOKIE,
+ NGM_NODEINFO, NULL, 0) < 0) {
+ errnosv = errno;
+ if (_gNgDebugLevel >= 1)
+ NGLOG("send nodeinfo");
+ goto errout;
+ }
+ if (NgRecvMsg(cs, resp, sizeof(rbuf), NULL) < 0) {
+ errnosv = errno;
+ if (_gNgDebugLevel >= 1)
+ NGLOG("recv nodeinfo");
+ goto errout;
+ }
+
+ /* Save node "name" */
+ snprintf(namebuf, sizeof(namebuf), "[%lx]", (u_long) ni->id);
+ }
+
+ /* Create data socket if desired */
+ if (dsp != NULL) {
+ u_char sbuf[NG_NODESIZ + 1 + NGSA_OVERHEAD];
+ struct sockaddr_ng *const sg = (struct sockaddr_ng *) sbuf;
+
+ /* Create data socket, initially just "floating" */
+ if ((ds = socket(AF_NETGRAPH, SOCK_DGRAM, NG_DATA)) < 0) {
+ errnosv = errno;
+ if (_gNgDebugLevel >= 1)
+ NGLOG("socket");
+ goto errout;
+ }
+
+ /* Associate the data socket with the node */
+ snprintf(sg->sg_data, NG_NODESIZ + 1, "%s:", namebuf);
+ sg->sg_family = AF_NETGRAPH;
+ sg->sg_len = strlen(sg->sg_data) + 1 + NGSA_OVERHEAD;
+ if (connect(ds, (struct sockaddr *) sg, sg->sg_len) < 0) {
+ errnosv = errno;
+ if (_gNgDebugLevel >= 1)
+ NGLOG("connect(%s)", sg->sg_data);
+ goto errout;
+ }
+ }
+
+ /* Return the socket(s) */
+ if (csp)
+ *csp = cs;
+ else
+ close(cs);
+ if (dsp)
+ *dsp = ds;
+ return (0);
+
+errout:
+ /* Failed */
+ if (cs >= 0)
+ close(cs);
+ if (ds >= 0)
+ close(ds);
+ errno = errnosv;
+ return (-1);
+}
+
+/*
+ * Assign a globally unique name to a node
+ * Returns -1 if error and sets errno.
+ */
+int
+NgNameNode(int cs, const char *path, const char *fmt, ...)
+{
+ struct ngm_name ngn;
+ va_list args;
+
+ /* Build message arg */
+ va_start(args, fmt);
+ vsnprintf(ngn.name, sizeof(ngn.name), fmt, args);
+ va_end(args);
+
+ /* Send message */
+ if (NgSendMsg(cs, path,
+ NGM_GENERIC_COOKIE, NGM_NAME, &ngn, sizeof(ngn)) < 0) {
+ if (_gNgDebugLevel >= 1)
+ NGLOGX("%s: failed", __func__);
+ return (-1);
+ }
+
+ /* Done */
+ return (0);
+}
+
+/*
+ * Read a packet from a data socket
+ * Returns -1 if error and sets errno.
+ */
+int
+NgRecvData(int ds, u_char * buf, size_t len, char *hook)
+{
+ u_char frombuf[NG_HOOKSIZ + NGSA_OVERHEAD];
+ struct sockaddr_ng *const from = (struct sockaddr_ng *) frombuf;
+ socklen_t fromlen = sizeof(frombuf);
+ int rtn, errnosv;
+
+ /* Read packet */
+ rtn = recvfrom(ds, buf, len, 0, (struct sockaddr *) from, &fromlen);
+ if (rtn < 0) {
+ errnosv = errno;
+ if (_gNgDebugLevel >= 1)
+ NGLOG("recvfrom");
+ errno = errnosv;
+ return (-1);
+ }
+
+ /* Copy hook name */
+ if (hook != NULL)
+ strlcpy(hook, from->sg_data, NG_HOOKSIZ);
+
+ /* Debugging */
+ if (_gNgDebugLevel >= 2) {
+ NGLOGX("READ %s from hook \"%s\" (%d bytes)",
+ rtn ? "PACKET" : "EOF", from->sg_data, rtn);
+ if (_gNgDebugLevel >= 3)
+ _NgDebugBytes(buf, rtn);
+ }
+
+ /* Done */
+ return (rtn);
+}
+
+/*
+ * Identical to NgRecvData() except buffer is dynamically allocated.
+ */
+int
+NgAllocRecvData(int ds, u_char **buf, char *hook)
+{
+ int len;
+ socklen_t optlen;
+
+ optlen = sizeof(len);
+ if (getsockopt(ds, SOL_SOCKET, SO_RCVBUF, &len, &optlen) == -1 ||
+ (*buf = malloc(len)) == NULL)
+ return (-1);
+ if ((len = NgRecvData(ds, *buf, len, hook)) < 0)
+ free(*buf);
+ return (len);
+}
+
+/*
+ * Write a packet to a data socket. The packet will be sent
+ * out the corresponding node on the specified hook.
+ * Returns -1 if error and sets errno.
+ */
+int
+NgSendData(int ds, const char *hook, const u_char * buf, size_t len)
+{
+ u_char sgbuf[NG_HOOKSIZ + NGSA_OVERHEAD];
+ struct sockaddr_ng *const sg = (struct sockaddr_ng *) sgbuf;
+ int errnosv;
+
+ /* Set up destination hook */
+ sg->sg_family = AF_NETGRAPH;
+ strlcpy(sg->sg_data, hook, NG_HOOKSIZ);
+ sg->sg_len = strlen(sg->sg_data) + 1 + NGSA_OVERHEAD;
+
+ /* Debugging */
+ if (_gNgDebugLevel >= 2) {
+ NGLOGX("WRITE PACKET to hook \"%s\" (%d bytes)", hook, len);
+ _NgDebugSockaddr(sg);
+ if (_gNgDebugLevel >= 3)
+ _NgDebugBytes(buf, len);
+ }
+
+ /* Send packet */
+ if (sendto(ds, buf, len, 0, (struct sockaddr *) sg, sg->sg_len) < 0) {
+ errnosv = errno;
+ if (_gNgDebugLevel >= 1)
+ NGLOG("sendto(%s)", sg->sg_data);
+ errno = errnosv;
+ return (-1);
+ }
+
+ /* Done */
+ return (0);
+}
+
diff --git a/lib/libngatm/Makefile b/lib/libngatm/Makefile
new file mode 100644
index 0000000..d53a612
--- /dev/null
+++ b/lib/libngatm/Makefile
@@ -0,0 +1,54 @@
+# $FreeBSD$
+#
+# Author: Harti Brandt <harti@freebsd.org>
+#
+LIB= ngatm
+SHLIB_MAJOR= 2
+MAN= libngatm.3 uniaddr.3 unifunc.3 unimsg.3 unisap.3 unistruct.3
+WARNS?= 6
+
+# source of the library lives in contrib
+SDIR= ${.CURDIR}/../../sys
+CTRB= ${.CURDIR}/../../contrib/ngatm
+LIBBASE= ${SDIR}/contrib/ngatm
+
+CFLAGS+= -I${LIBBASE} -I${.OBJDIR} -I${CTRB}/libngatm
+# CFLAGS+= -DSSCOP_DEBUG -DSSCFU_DEBUG -DUNI_DEBUG -DCCATM_DEBUG
+
+.PATH: ${LIBBASE}/netnatm ${LIBBASE}/netnatm/saal ${LIBBASE}/netnatm/misc \
+ ${LIBBASE}/netnatm/msg ${LIBBASE}/netnatm/sig ${LIBBASE}/netnatm/api
+.PATH: ${CTRB}/libngatm ${CTRB}/man
+
+SRCS= unimsg.c unimsg_common.c straddr.c \
+ traffic.c uni_ie.c uni_msg.c \
+ saal_sscop.c saal_sscfu.c \
+ sig_call.c sig_coord.c sig_party.c sig_print.c sig_reset.c \
+ sig_uni.c sig_unimsgcpy.c sig_verify.c \
+ cc_conn.c cc_user.c cc_sig.c cc_data.c cc_port.c unisap.c \
+ cc_dump.c
+
+# Includes
+INCSGROUPS= INCSATM INCSSAAL INCSMSG INCSSIG INCSAPI
+
+# common files
+INCSATMDIR= $(INCLUDEDIR)/netnatm
+INCSATM= unimsg.h addr.h
+
+# signaling AAL
+INCSSAALDIR= $(INCLUDEDIR)/netnatm/saal
+INCSSAAL= saal/sscfu.h saal/sscfudef.h saal/sscop.h saal/sscopdef.h
+
+# message parsing
+INCSMSGDIR= $(INCLUDEDIR)/netnatm/msg
+INCSMSG= msg/uni_config.h msg/uni_hdr.h msg/uni_ie.h msg/uni_msg.h \
+ msg/unimsglib.h msg/uniprint.h msg/unistruct.h
+
+# signaling layer
+INCSSIGDIR= $(INCLUDEDIR)/netnatm/sig
+INCSSIG= sig/uni.h sig/unidef.h sig/unisig.h
+
+# call control layer
+INCSAPIDIR= $(INCLUDEDIR)/netnatm/api
+INCSAPI= api/atmapi.h api/ccatm.h api/unisap.h
+
+.include <bsd.lib.mk>
diff --git a/lib/libopie/Makefile b/lib/libopie/Makefile
new file mode 100644
index 0000000..5b6740e
--- /dev/null
+++ b/lib/libopie/Makefile
@@ -0,0 +1,36 @@
+# Makefile for libopie
+#
+# $FreeBSD$
+#
+OPIE_DIST?= ${.CURDIR}/../../contrib/opie
+DIST_DIR= ${OPIE_DIST}/${.CURDIR:T}
+SHLIB_MAJOR= 4
+
+KEYFILE?= \"/etc/opiekeys\"
+
+.PATH: ${DIST_DIR} ${OPIE_DIST}/libmissing
+
+LIB= opie
+SRCS= atob8.c btoa8.c btoh.c challenge.c getsequence.c hash.c hashlen.c \
+ keycrunch.c lock.c lookup.c newseed.c parsechallenge.c passcheck.c \
+ passwd.c randomchallenge.c readpass.c unlock.c verify.c version.c \
+ btoe.c accessfile.c generator.c insecure.c getutmpentry.c \
+ readrec.c writerec.c open.c \
+ getutline.c pututline.c endutent.c setutent.c # from libmissing
+SRCS+= opieextra.c
+INCS= ${OPIE_DIST}/opie.h
+
+CFLAGS+=-I${.CURDIR} -I${OPIE_DIST} -I${DIST_DIR} \
+ -DKEY_FILE=${KEYFILE}
+
+ACCESSFILE?= \"/etc/opieaccess\"
+CFLAGS+= -DINSECURE_OVERRIDE -DPATH_ACCESS_FILE=${ACCESSFILE}
+
+DPADD= ${LIBMD}
+LDADD= -lmd
+
+MAN= ${OPIE_DIST}/opie.4 ${OPIE_DIST}/opiekeys.5 ${OPIE_DIST}/opieaccess.5
+
+MLINKS= opie.4 skey.4
+
+.include <bsd.lib.mk>
diff --git a/lib/libopie/config.h b/lib/libopie/config.h
new file mode 100644
index 0000000..b6ad39b
--- /dev/null
+++ b/lib/libopie/config.h
@@ -0,0 +1,381 @@
+/* $FreeBSD$ */
+/* config.h. Generated automatically by configure. */
+/* config.h.in. Generated automatically from configure.in by autoheader. */
+
+/* Define if on AIX 3.
+ System headers sometimes define this.
+ We just want to avoid a redefinition error message. */
+#ifndef _ALL_SOURCE
+/* #undef _ALL_SOURCE */
+#endif
+
+/* Define if using alloca.c. */
+/* #undef C_ALLOCA */
+
+/* Define to empty if the keyword does not work. */
+/* #undef const */
+
+/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems.
+ This function is required for alloca.c support on those systems. */
+/* #undef CRAY_STACKSEG_END */
+
+/* Define if you have alloca, as a function or macro. */
+#define HAVE_ALLOCA 1
+
+/* Define if you have <alloca.h> and it should be used (not on Ultrix). */
+/* #undef HAVE_ALLOCA_H */
+
+/* Define if you have <sys/wait.h> that is POSIX.1 compatible. */
+#define HAVE_SYS_WAIT_H 1
+
+/* Define if on MINIX. */
+/* #undef _MINIX */
+
+/* Define if the system does not provide POSIX.1 features except
+ with this defined. */
+/* #undef _POSIX_1_SOURCE */
+
+/* Define if you need to in order for stat and other things to work. */
+/* #undef _POSIX_SOURCE */
+
+/* Define as the return type of signal handlers (int or void). */
+#define RETSIGTYPE void
+
+/* If using the C implementation of alloca, define if you know the
+ direction of stack growth for your system; otherwise it will be
+ automatically deduced at run-time.
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown
+ */
+/* #undef STACK_DIRECTION */
+
+/* Define if you want the FTP daemon to support anonymous logins. */
+/* #undef DOANONYMOUS */
+
+/* The default value of the PATH environment variable */
+#define DEFAULT_PATH "/usr/bin:/bin:/usr/sbin:/sbin:/usr/X11R6/bin"
+
+/* Defined if the file /etc/default/login exists
+ (and, presumably, should be looked at by login) */
+/* #undef HAVE_ETC_DEFAULT_LOGIN */
+
+/* Defined to the name of a file that contains a list of files whose
+ permissions and ownerships should be changed on login. */
+/* #undef HAVE_LOGIN_PERMFILE */
+
+/* Defined to the name of a file that contains a list of environment
+ values that should be set on login. */
+/* #undef HAVE_LOGIN_ENVFILE */
+
+/* Defined if the file /etc/securetty exists
+ (and, presumably, should be looked at by login) */
+/* #undef HAVE_SECURETTY */
+
+/* Defined if the file /etc/shadow exists
+ (and, presumably, should be looked at for shadow passwords) */
+/* #undef HAVE_ETC_SHADOW */
+
+/* The path to the access file, if we're going to use it */
+/* #undef PATH_ACCESS_FILE */
+
+/* The path to the mail spool, if we know it */
+#define PATH_MAIL "/var/mail"
+
+/* The path to the utmp file, if we know it */
+#define PATH_UTMP_AC "/var/run/utmp"
+
+/* The path to the wtmp file, if we know it */
+#define PATH_WTMP_AC "/var/log/wtmp"
+
+/* The path to the wtmpx file, if we know it */
+/* #undef PATH_WTMPX_AC */
+
+/* Defined if the system's profile (/etc/profile) displays
+ the motd file */
+/* #undef HAVE_MOTD_IN_PROFILE */
+
+/* Defined if the system's profile (/etc/profile) informs the
+ user of new mail */
+/* #undef HAVE_MAILCHECK_IN_PROFILE */
+
+/* Define if you have a nonstandard gettimeofday() that takes one argument
+ instead of two. */
+/* #undef HAVE_ONE_ARG_GETTIMEOFDAY */
+
+/* Define if the system has the getenv function */
+#define HAVE_GETENV 1
+
+/* Define if the system has the setenv function */
+#define HAVE_SETENV 1
+
+/* Define if the system has the /var/adm/sulog file */
+/* #undef HAVE_SULOG */
+
+/* Define if the system has the unsetenv function */
+#define HAVE_UNSETENV 1
+
+/* Define if the compiler can handle ANSI-style argument lists */
+#define HAVE_ANSIDECL 1
+
+/* Define if the compiler can handle ANSI-style prototypes */
+#define HAVE_ANSIPROTO 1
+
+/* Define if the system has an ANSI-style printf (returns int instead of char *) */
+#define HAVE_ANSISPRINTF 1
+
+/* Define if the compiler can handle ANSI-style variable argument lists */
+#define HAVE_ANSISTDARG 1
+
+/* Define if the compiler can handle void argument lists to functions */
+#define HAVE_VOIDARG 1
+
+/* Define if the compiler can handle void return "values" from functions */
+#define HAVE_VOIDRET 1
+
+/* Define if the compiler can handle void pointers to our liking */
+#define HAVE_VOIDPTR 1
+
+/* Define if the /bin/ls command seems to support the -g flag */
+/* #undef HAVE_LS_G_FLAG */
+
+/* Define if there is a ut_pid field in struct utmp */
+/* #undef HAVE_UT_PID */
+
+/* Define if there is a ut_type field in struct utmp */
+/* #undef HAVE_UT_TYPE */
+
+/* Define if there is a ut_name field in struct utmp */
+#define HAVE_UT_NAME 1
+
+/* Define if there is a ut_host field in struct utmp */
+#define HAVE_UT_HOST 1
+
+/* Define if the system has getutline() */
+/* #undef HAVE_GETUTLINE */
+
+/* Defined if the system has SunOS C2 security shadow passwords */
+/* #undef HAVE_SUNOS_C2_SHADOW */
+
+/* Defined if you want to disable utmp support */
+/* #undef DISABLE_UTMP */
+
+/* Defined if you want to allow users to override the insecure checks */
+/* #undef INSECURE_OVERRIDE */
+
+/* Defined to the default hash value, always defined */
+#define MDX 5
+
+/* Defined if new-style prompts are to be used */
+#define NEW_PROMPTS 1
+
+/* Defined to the path of the OPIE lock directory */
+#define OPIE_LOCK_DIR "/var/spool/opielocks"
+
+/* Defined if users are to be asked to re-type secret pass phrases */
+/* #undef RETYPE */
+
+/* Defined if su should not switch to disabled accounts */
+/* #undef SU_STAR_CHECK */
+
+/* Don't turn it on! It allows intruder easily disable whole OPIE for user */
+/* Defined if user locking is to be used */
+/* #undef USER_LOCKING */
+
+/* Define if you have the bcopy function. */
+/* #undef HAVE_BCOPY */
+
+/* Define if you have the bzero function. */
+/* #undef HAVE_BZERO */
+
+/* Define if you have the endspent function. */
+/* #undef HAVE_ENDSPENT */
+
+/* Define if you have the fpurge function. */
+#define HAVE_FPURGE 1
+
+/* Define if you have the getdtablesize function. */
+/* #undef HAVE_GETDTABLESIZE */
+
+/* Define if you have the getgroups function. */
+#define HAVE_GETGROUPS 1
+
+/* Define if you have the gethostname function. */
+/* #undef HAVE_GETHOSTNAME */
+
+/* Define if you have the getspnam function. */
+/* #undef HAVE_GETSPNAM */
+
+/* Define if you have the gettimeofday function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define if you have the getttynam function. */
+#define HAVE_GETTTYNAM 1
+
+/* Define if you have the getusershell function. */
+#define HAVE_GETUSERSHELL 1
+
+/* Define if you have the getutxline function. */
+/* #undef HAVE_GETUTXLINE */
+
+/* Define if you have the getwd function. */
+/* #undef HAVE_GETWD */
+
+/* Define if you have the index function. */
+/* #undef HAVE_INDEX */
+
+/* Define if you have the lstat function. */
+#define HAVE_LSTAT 1
+
+/* Define if you have the on_exit function. */
+/* #undef HAVE_ON_EXIT */
+
+/* Define if you have the pututxline function. */
+/* #undef HAVE_PUTUTXLINE */
+
+/* Define if you have the rindex function. */
+/* #undef HAVE_RINDEX */
+
+/* Define if you have the setgroups function. */
+#define HAVE_SETGROUPS 1
+
+/* Define if you have the setlogin function. */
+#define HAVE_SETLOGIN 1
+
+/* Define if you have the setpriority function. */
+#define HAVE_SETPRIORITY 1
+
+/* Define if you have the setregid function. */
+/* #undef HAVE_SETREGID */
+
+/* Define if you have the setresgid function. */
+/* #undef HAVE_SETRESGID */
+
+/* Define if you have the setresuid function. */
+/* #undef HAVE_SETRESUID */
+
+/* Define if you have the setreuid function. */
+/* #undef HAVE_SETREUID */
+
+/* Define if you have the setvbuf function. */
+#define HAVE_SETVBUF 1
+
+/* Define if you have the sigaddset function. */
+#define HAVE_SIGADDSET 1
+
+/* Define if you have the sigblock function. */
+/* #undef HAVE_SIGBLOCK */
+
+/* Define if you have the sigemptyset function. */
+#define HAVE_SIGEMPTYSET 1
+
+/* Define if you have the sigsetmask function. */
+/* #undef HAVE_SIGSETMASK */
+
+/* Define if you have the socket function. */
+#define HAVE_SOCKET 1
+
+/* Define if you have the strerror function. */
+#define HAVE_STRERROR 1
+
+/* Define if you have the strftime function. */
+#define HAVE_STRFTIME 1
+
+/* Define if you have the strncasecmp function. */
+#define HAVE_STRNCASECMP 1
+
+/* Define if you have the strstr function. */
+#define HAVE_STRSTR 1
+
+/* Define if you have the ttyslot function. */
+#define HAVE_TTYSLOT 1
+
+/* Define if you have the usleep function. */
+#define HAVE_USLEEP 1
+
+/* Define if you have the <crypt.h> header file. */
+/* #undef HAVE_CRYPT_H */
+
+/* Define if you have the <dirent.h> header file. */
+#define HAVE_DIRENT_H 1
+
+/* Define if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define if you have the <lastlog.h> header file. */
+/* #undef HAVE_LASTLOG_H */
+
+/* Define if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* Define if you have the <ndir.h> header file. */
+/* #undef HAVE_NDIR_H */
+
+/* Define if you have the <paths.h> header file. */
+#define HAVE_PATHS_H 1
+
+/* Define if you have the <pwd.h> header file. */
+#define HAVE_PWD_H 1
+
+/* Define if you have the <shadow.h> header file. */
+/* #undef HAVE_SHADOW_H */
+
+/* Define if you have the <signal.h> header file. */
+#define HAVE_SIGNAL_H 1
+
+/* Define if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define if you have the <sys/dir.h> header file. */
+/* #undef HAVE_SYS_DIR_H */
+
+/* Define if you have the <sys/file.h> header file. */
+#define HAVE_SYS_FILE_H 1
+
+/* Define if you have the <sys/ioctl.h> header file. */
+#define HAVE_SYS_IOCTL_H 1
+
+/* Define if you have the <sys/ndir.h> header file. */
+/* #undef HAVE_SYS_NDIR_H */
+
+/* Define if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define if you have the <sys/select.h> header file. */
+#define HAVE_SYS_SELECT_H 1
+
+/* Define if you have the <sys/signal.h> header file. */
+#define HAVE_SYS_SIGNAL_H 1
+
+/* Define if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define if you have the <sys/utsname.h> header file. */
+#define HAVE_SYS_UTSNAME_H 1
+
+/* Define if you have the <syslog.h> header file. */
+#define HAVE_SYSLOG_H 1
+
+/* Define if you have the <termios.h> header file. */
+#define HAVE_TERMIOS_H 1
+
+/* Define if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define if you have the <utmpx.h> header file. */
+/* #undef HAVE_UTMPX_H */
+
+/* Define if you have the crypt library (-lcrypt). */
+#define HAVE_LIBCRYPT 1
+
+/* Define if you have the nsl library (-lnsl). */
+/* #undef HAVE_LIBNSL */
+
+/* Define if you have the posix library (-lposix). */
+/* #undef HAVE_LIBPOSIX */
+
+/* Define if you have the socket library (-lsocket). */
+/* #undef HAVE_LIBSOCKET */
diff --git a/lib/libopie/opieextra.c b/lib/libopie/opieextra.c
new file mode 100644
index 0000000..6e2b6b8
--- /dev/null
+++ b/lib/libopie/opieextra.c
@@ -0,0 +1,98 @@
+/*
+ * This file contains routines modified from OpenBSD. Parts are contributed
+ * by Todd Miller <millert@openbsd.org>, Theo De Raadt <deraadt@openbsd.org>
+ * and possibly others.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <opie.h>
+
+/*
+ * opie_haopie()
+ *
+ * Returns: 1 user doesnt exist, -1 file error, 0 user exists.
+ *
+ */
+int
+opie_haskey(username)
+char *username;
+{
+ struct opie opie;
+
+ return opielookup(&opie, username);
+}
+
+/*
+ * opie_keyinfo()
+ *
+ * Returns the current sequence number and
+ * seed for the passed user.
+ *
+ */
+char *
+opie_keyinfo(username)
+char *username;
+{
+ int i;
+ static char str[OPIE_CHALLENGE_MAX];
+ struct opie opie;
+
+ i = opiechallenge(&opie, username, str);
+ if (i == -1)
+ return(0);
+
+ return(str);
+}
+
+/*
+ * opie_passverify()
+ *
+ * Check to see if answer is the correct one to the current
+ * challenge.
+ *
+ * Returns: 0 success, -1 failure
+ *
+ */
+int
+opie_passverify(username, passwd)
+char *username;
+char *passwd;
+{
+ int i;
+ struct opie opie;
+
+ i = opielookup(&opie, username);
+ if (i == -1 || i == 1)
+ return(-1);
+
+ if (opieverify(&opie, passwd) == 0)
+ return(opie.opie_n);
+
+ return(-1);
+}
+
+#define OPIE_HASH_DEFAULT 1
+
+/* Current hash type (index into opie_hash_types array) */
+static int opie_hash_type = OPIE_HASH_DEFAULT;
+
+struct opie_algorithm_table {
+ const char *name;
+};
+
+static struct opie_algorithm_table opie_algorithm_table[] = {
+ "md4", "md5"
+};
+
+/* Get current hash type */
+const char *
+opie_get_algorithm()
+{
+ return(opie_algorithm_table[opie_hash_type].name);
+}
+
+
diff --git a/lib/libpam/Makefile b/lib/libpam/Makefile
new file mode 100644
index 0000000..088e8a0
--- /dev/null
+++ b/lib/libpam/Makefile
@@ -0,0 +1,31 @@
+# Copyright 1998 Juniper Networks, Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+
+# The modules must be built first, because they are built into the
+# static version of libpam.
+SUBDIR+= modules libpam
+
+.include <bsd.subdir.mk>
diff --git a/lib/libpam/Makefile.inc b/lib/libpam/Makefile.inc
new file mode 100644
index 0000000..9fefb46
--- /dev/null
+++ b/lib/libpam/Makefile.inc
@@ -0,0 +1,32 @@
+# Copyright 1998 Juniper Networks, Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+
+.ifdef PAM_DEBUG
+DEBUG_FLAGS+= -DDEBUG
+.endif
+
+SHLIB_MAJOR= 3
+PAM_MOD_DIR= ${LIBDIR}
diff --git a/lib/libpam/libpam/Makefile b/lib/libpam/libpam/Makefile
new file mode 100644
index 0000000..6c81940
--- /dev/null
+++ b/lib/libpam/libpam/Makefile
@@ -0,0 +1,168 @@
+#-
+# Copyright (c) 1998 Juniper Networks, Inc.
+# All rights reserved.
+# Copyright (c) 2002 Networks Associates Technology, Inc.
+# All rights reserved.
+#
+# Portions of this software was developed for the FreeBSD Project by
+# ThinkSec AS 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+
+OPENPAM= ${.CURDIR}/../../../contrib/openpam
+.PATH: ${OPENPAM}/include ${OPENPAM}/lib ${OPENPAM}/doc/man
+
+LIB= pam
+NO_PROFILE=
+
+SRCS= openpam_borrow_cred.c \
+ openpam_configure.c \
+ openpam_dispatch.c \
+ openpam_dynamic.c \
+ openpam_findenv.c \
+ openpam_free_data.c \
+ openpam_free_envlist.c \
+ openpam_get_option.c \
+ openpam_load.c \
+ openpam_log.c \
+ openpam_nullconv.c \
+ openpam_readline.c \
+ openpam_restore_cred.c \
+ openpam_set_option.c \
+ openpam_ttyconv.c \
+ pam_acct_mgmt.c \
+ pam_authenticate.c \
+ pam_chauthtok.c \
+ pam_close_session.c \
+ pam_end.c \
+ pam_error.c \
+ pam_get_authtok.c \
+ pam_get_data.c \
+ pam_get_item.c \
+ pam_get_user.c \
+ pam_getenv.c \
+ pam_getenvlist.c \
+ pam_info.c \
+ pam_open_session.c \
+ pam_prompt.c \
+ pam_putenv.c \
+ pam_set_data.c \
+ pam_set_item.c \
+ pam_setcred.c \
+ pam_setenv.c \
+ pam_start.c \
+ pam_strerror.c \
+ pam_verror.c \
+ pam_vinfo.c \
+ pam_vprompt.c
+# Local additions
+SRCS+= pam_debug_log.c
+
+MAN= openpam.3 \
+ openpam_borrow_cred.3 \
+ openpam_free_data.3 \
+ openpam_free_envlist.3 \
+ openpam_get_option.3 \
+ openpam_log.3 \
+ openpam_nullconv.3 \
+ openpam_readline.3 \
+ openpam_restore_cred.3 \
+ openpam_set_option.3 \
+ openpam_ttyconv.3 \
+ pam.3 \
+ pam_acct_mgmt.3 \
+ pam_authenticate.3 \
+ pam_chauthtok.3 \
+ pam_close_session.3 \
+ pam_conv.3 \
+ pam_end.3 \
+ pam_error.3 \
+ pam_get_authtok.3 \
+ pam_get_data.3 \
+ pam_get_item.3 \
+ pam_get_user.3 \
+ pam_getenv.3 \
+ pam_getenvlist.3 \
+ pam_info.3 \
+ pam_open_session.3 \
+ pam_prompt.3 \
+ pam_putenv.3 \
+ pam_set_data.3 \
+ pam_set_item.3 \
+ pam_setcred.3 \
+ pam_setenv.3 \
+ pam_sm_acct_mgmt.3 \
+ pam_sm_authenticate.3 \
+ pam_sm_chauthtok.3 \
+ pam_sm_close_session.3 \
+ pam_sm_open_session.3 \
+ pam_sm_setcred.3 \
+ pam_start.3 \
+ pam_strerror.3 \
+ pam_verror.3 \
+ pam_vinfo.3 \
+ pam_vprompt.3 \
+ pam.conf.5
+
+MLINKS= pam.conf.5 pam.d.5
+
+CSTD?= c99
+WARNS?= 3
+CFLAGS+= -I${.CURDIR} -I${OPENPAM}/include
+CFLAGS+= -DLIB_MAJ=${SHLIB_MAJOR}
+CFLAGS+= -DOPENPAM_MODULES_DIR='"${PAM_MOD_DIR:C/\/*$//}/"'
+
+HEADERS= security/openpam.h \
+ security/openpam_version.h \
+ security/pam_appl.h \
+ security/pam_constants.h \
+ security/pam_modules.h \
+ security/pam_types.h \
+
+ADD_HEADERS= security/pam_mod_misc.h
+
+# Static modules
+MODULE_DIR= ../modules
+.include "${.CURDIR}/${MODULE_DIR}/modules.inc"
+STATIC_MODULES= ${MODULES:C/.*/${MODULE_DIR}\/&\/lib&.a/}
+STATICOBJS+= openpam_static_modules.o
+CLEANFILES+= openpam_static.o \
+ openpam_static_modules.o
+
+openpam_static_modules.o: openpam_static.o ${STATIC_MODULES}
+ ${LD} -o ${.TARGET} -r --whole-archive ${.ALLSRC}
+
+# Can't put openpam_static.c in SRCS but want .o in .depend.
+DPSRCS= openpam_static.c
+
+# Headers
+INCS= ${HEADERS} ${ADD_HEADERS}
+INCSDIR= ${INCLUDEDIR}/security
+
+.include <bsd.lib.mk>
diff --git a/lib/libpam/libpam/pam_debug_log.c b/lib/libpam/libpam/pam_debug_log.c
new file mode 100644
index 0000000..c3fe8e3
--- /dev/null
+++ b/lib/libpam/libpam/pam_debug_log.c
@@ -0,0 +1,62 @@
+/*-
+ * Copyright 2001 Mark R V Murray
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 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 <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <security/pam_appl.h>
+#include <security/openpam.h>
+#include <security/pam_mod_misc.h>
+
+/* Print a verbose error, including the function name and a
+ * cleaned up filename.
+ */
+void
+_pam_verbose_error(pam_handle_t *pamh, int flags,
+ const char *file, const char *function, const char *format, ...)
+{
+ va_list ap;
+ char *fmtbuf, *modname, *period;
+
+ if (!(flags & PAM_SILENT) && !openpam_get_option(pamh, "no_warn")) {
+ modname = basename(file);
+ period = strchr(modname, '.');
+ if (period == NULL)
+ period = strchr(modname, '\0');
+ va_start(ap, format);
+ asprintf(&fmtbuf, "%.*s: %s: %s\n", (int)(period - modname),
+ modname, function, format);
+ pam_verror(pamh, fmtbuf, ap);
+ free(fmtbuf);
+ va_end(ap);
+ }
+}
diff --git a/lib/libpam/libpam/pam_std_option.c b/lib/libpam/libpam/pam_std_option.c
new file mode 100644
index 0000000..a9ddfba
--- /dev/null
+++ b/lib/libpam/libpam/pam_std_option.c
@@ -0,0 +1,178 @@
+/*-
+ * Copyright 1998 Juniper Networks, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+
+#include <security/pam_appl.h>
+#include <security/pam_mod_misc.h>
+
+/* Everyone has to have these options. It is not an error to
+ * specify them and then not use them.
+ */
+struct opttab std_options[PAM_MAX_OPTIONS] = {
+ { "debug", PAM_OPT_DEBUG },
+ { "no_warn", PAM_OPT_NO_WARN },
+ { "echo_pass", PAM_OPT_ECHO_PASS },
+ { "use_first_pass", PAM_OPT_USE_FIRST_PASS },
+ { "try_first_pass", PAM_OPT_TRY_FIRST_PASS },
+ { "use_mapped_pass", PAM_OPT_USE_MAPPED_PASS },
+ { "try_mapped_pass", PAM_OPT_TRY_MAPPED_PASS },
+ { "expose_account", PAM_OPT_EXPOSE_ACCOUNT },
+ { NULL, 0 }
+};
+
+/* Populate the options structure, syslogging all errors */
+void
+pam_std_option(struct options *options, struct opttab other_options[],
+ int argc, const char *argv[])
+{
+ struct opttab *oo;
+ int i, j, std, extra, arglen, found;
+
+ std = 1;
+ extra = 1;
+ oo = other_options;
+ for (i = 0; i < PAM_MAX_OPTIONS; i++) {
+ if (std && std_options[i].name == NULL)
+ std = 0;
+ else if (extra && (oo == NULL || oo->name == NULL))
+ extra = 0;
+
+ if (std)
+ options->opt[i].name = std_options[i].name;
+ else if (extra) {
+ if (oo->value != i)
+ syslog(LOG_DEBUG, "Extra option fault: %d %d",
+ oo->value, i);
+ options->opt[i].name = oo->name;
+ oo++;
+ }
+ else
+ options->opt[i].name = NULL;
+
+ options->opt[i].bool = 0;
+ options->opt[i].arg = NULL;
+ }
+
+ for (j = 0; j < argc; j++) {
+#ifdef DEBUG
+ syslog(LOG_DEBUG, "Doing arg %s", argv[j]);
+#endif
+ found = 0;
+ for (i = 0; i < PAM_MAX_OPTIONS; i++) {
+ if (options->opt[i].name == NULL)
+ break;
+ arglen = strlen(options->opt[i].name);
+ if (strcmp(argv[j], options->opt[i].name) == 0) {
+ options->opt[i].bool = 1;
+ found = 1;
+ break;
+ }
+ else if (strncmp(argv[j], options->opt[i].name, arglen)
+ == 0 && argv[j][arglen] == '=') {
+ options->opt[i].bool = 1;
+ options->opt[i].arg
+ = strdup(&argv[j][arglen + 1]);
+ found = 1;
+ break;
+ }
+ }
+ if (!found)
+ syslog(LOG_WARNING, "PAM option: %s invalid", argv[j]);
+ }
+}
+
+/* Test if option is set in options */
+int
+pam_test_option(struct options *options, enum opt option, char **arg)
+{
+ if (arg != NULL)
+ *arg = options->opt[option].arg;
+ return options->opt[option].bool;
+}
+
+/* Set option in options, errors to syslog */
+void
+pam_set_option(struct options *options, enum opt option)
+{
+ if (option < PAM_OPT_STD_MAX)
+ options->opt[option].bool = 1;
+#ifdef DEBUG
+ else
+ syslog(LOG_DEBUG, "PAM options: attempt to set option %d",
+ option);
+#endif
+}
+
+/* Clear option in options, errors to syslog */
+void
+pam_clear_option(struct options *options, enum opt option)
+{
+ if (option < PAM_OPT_STD_MAX)
+ options->opt[option].bool = 0;
+#ifdef DEBUG
+ else
+ syslog(LOG_DEBUG, "PAM options: attempt to clear option %d",
+ option);
+#endif
+}
+
+#ifdef DEBUG1
+enum { PAM_OPT_FOO=PAM_OPT_STD_MAX, PAM_OPT_BAR, PAM_OPT_BAZ, PAM_OPT_QUX };
+
+struct opttab other_options[] = {
+ { "foo", PAM_OPT_FOO },
+ { "bar", PAM_OPT_BAR },
+ { "baz", PAM_OPT_BAZ },
+ { "qux", PAM_OPT_QUX },
+ { NULL, 0 }
+};
+
+int
+main(int argc, const char *argv[])
+{
+ struct options options;
+ int i, opt;
+ char *arg;
+
+ pam_std_option(&options, other_options, argc, argv);
+ for (i = 0; i < PAM_MAX_OPTIONS; i++) {
+ opt = pam_test_option(&options, i, &arg);
+ if (opt) {
+ if (arg == NULL)
+ printf("%d []\n", i);
+ else
+ printf("%d [%s]\n", i, arg);
+ }
+ }
+ return 0;
+}
+#endif
diff --git a/lib/libpam/libpam/security/pam_mod_misc.h b/lib/libpam/libpam/security/pam_mod_misc.h
new file mode 100644
index 0000000..ffc6f92
--- /dev/null
+++ b/lib/libpam/libpam/security/pam_mod_misc.h
@@ -0,0 +1,56 @@
+/*-
+ * Copyright 1998 Juniper Networks, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef PAM_MOD_MISC_H
+#define PAM_MOD_MISC_H
+
+#include <sys/cdefs.h>
+
+/*
+ * Common option names
+ */
+#define PAM_OPT_NULLOK "nullok"
+#define PAM_OPT_AUTH_AS_SELF "auth_as_self"
+#define PAM_OPT_ECHO_PASS "echo_pass"
+#define PAM_OPT_DEBUG "debug"
+
+__BEGIN_DECLS
+void _pam_verbose_error(pam_handle_t *, int, const char *,
+ const char *, const char *, ...);
+__END_DECLS
+
+#define PAM_LOG(...) \
+ openpam_log(PAM_LOG_DEBUG, __VA_ARGS__)
+
+#define PAM_RETURN(arg) \
+ return (arg)
+
+#define PAM_VERBOSE_ERROR(...) \
+ _pam_verbose_error(pamh, flags, __FILE__, __FUNCTION__, __VA_ARGS__)
+
+#endif
diff --git a/lib/libpam/modules/Makefile b/lib/libpam/modules/Makefile
new file mode 100644
index 0000000..cacf011
--- /dev/null
+++ b/lib/libpam/modules/Makefile
@@ -0,0 +1,31 @@
+# Copyright 1998 Juniper Networks, Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+
+.include "modules.inc"
+
+SUBDIR= ${MODULES}
+
+.include <bsd.subdir.mk>
diff --git a/lib/libpam/modules/Makefile.inc b/lib/libpam/modules/Makefile.inc
new file mode 100644
index 0000000..d4f2bb3
--- /dev/null
+++ b/lib/libpam/modules/Makefile.inc
@@ -0,0 +1,22 @@
+# $FreeBSD$
+
+PAMDIR= ${.CURDIR}/../../../../contrib/openpam
+
+NO_INSTALLLIB=
+NO_PROFILE=
+
+CFLAGS+= -I${PAMDIR}/include -I${.CURDIR}/../../libpam
+WARNS?= 4
+
+# This is nasty.
+# For the static case, libpam.a depends on the modules.
+# For the dynamic case, the modules depend on libpam.so.N
+.if defined(_NO_LIBPAM_SO_YET)
+NO_PIC=
+.else
+SHLIB_NAME?= ${LIB}.so.${SHLIB_MAJOR}
+DPADD+= ${LIBPAM}
+LDADD+= -lpam
+.endif
+
+.include "../Makefile.inc"
diff --git a/lib/libpam/modules/modules.inc b/lib/libpam/modules/modules.inc
new file mode 100644
index 0000000..c570cfd
--- /dev/null
+++ b/lib/libpam/modules/modules.inc
@@ -0,0 +1,33 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+MODULES =
+MODULES += pam_chroot
+MODULES += pam_deny
+MODULES += pam_echo
+MODULES += pam_exec
+MODULES += pam_ftpusers
+MODULES += pam_group
+MODULES += pam_guest
+.if ${MK_KERBEROS} != "no"
+MODULES += pam_krb5
+MODULES += pam_ksu
+.endif
+MODULES += pam_lastlog
+MODULES += pam_login_access
+MODULES += pam_nologin
+MODULES += pam_opie
+MODULES += pam_opieaccess
+MODULES += pam_passwdqc
+MODULES += pam_permit
+MODULES += pam_radius
+MODULES += pam_rhosts
+MODULES += pam_rootok
+MODULES += pam_securetty
+MODULES += pam_self
+.if ${MK_OPENSSH} != "no"
+MODULES += pam_ssh
+.endif
+MODULES += pam_tacplus
+MODULES += pam_unix
diff --git a/lib/libpam/modules/pam_chroot/Makefile b/lib/libpam/modules/pam_chroot/Makefile
new file mode 100644
index 0000000..6d0fc0e
--- /dev/null
+++ b/lib/libpam/modules/pam_chroot/Makefile
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+LIB= pam_chroot
+SRCS= pam_chroot.c
+MAN= pam_chroot.8
+
+.include <bsd.lib.mk>
diff --git a/lib/libpam/modules/pam_chroot/pam_chroot.8 b/lib/libpam/modules/pam_chroot/pam_chroot.8
new file mode 100644
index 0000000..1bb4800
--- /dev/null
+++ b/lib/libpam/modules/pam_chroot/pam_chroot.8
@@ -0,0 +1,94 @@
+.\" Copyright (c) 2003 Networks Associates Technology, Inc.
+.\" All rights reserved.
+.\"
+.\" Portions of this software were developed for the FreeBSD Project by
+.\" ThinkSec AS 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING 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 10, 2003
+.Dt PAM_CHROOT 8
+.Os
+.Sh NAME
+.Nm pam_chroot
+.Nd Chroot PAM module
+.Sh SYNOPSIS
+.Op Ar service-name
+.Ar module-type
+.Ar control-flag
+.Pa pam_chroot
+.Op Ar arguments
+.Sh DESCRIPTION
+The chroot service module for PAM chroots users into either a
+predetermined directory or one derived from their home directory.
+If a user's home directory as specified in the
+.Vt passwd
+structure returned by
+.Xr getpwnam 3
+contains the string
+.Dq Li /./ ,
+the portion of the directory name to the left of that string is used
+as the chroot directory, and the portion to the right will be the
+current working directory inside the chroot tree.
+Otherwise, the directories specified by the
+.Cm dir
+and
+.Cm cwd
+options (see below) are used.
+.Bl -tag -width ".Cm also_root"
+.It Cm also_root
+Do not hold user ID 0 exempt from the chroot requirement.
+.It Cm always
+Report a failure if a chroot directory could not be derived from the
+user's home directory, and the
+.Cm dir
+option was not specified.
+.It Cm cwd Ns = Ns Ar directory
+Specify the directory to
+.Xr chdir 2
+into after a successful
+.Xr chroot 2
+call.
+.It Cm dir Ns = Ns Ar directory
+Specify the chroot directory to use if one could not be derived from
+the user's home directory.
+.El
+.Sh SEE ALSO
+.Xr pam.conf 5 ,
+.Xr pam 8
+.Sh AUTHORS
+The
+.Nm
+module and this manual page were developed for the
+.Fx
+Project by
+ThinkSec AS and NAI Labs, the Security Research Division of Network
+Associates, Inc.\& under DARPA/SPAWAR contract N66001-01-C-8035
+.Pq Dq CBOSS ,
+as part of the DARPA CHATS research program.
diff --git a/lib/libpam/modules/pam_chroot/pam_chroot.c b/lib/libpam/modules/pam_chroot/pam_chroot.c
new file mode 100644
index 0000000..447e5f7
--- /dev/null
+++ b/lib/libpam/modules/pam_chroot/pam_chroot.c
@@ -0,0 +1,109 @@
+/*-
+ * Copyright (c) 2003 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project by ThinkSec AS 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 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 <pwd.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#define PAM_SM_SESSION
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <security/openpam.h>
+
+PAM_EXTERN int
+pam_sm_open_session(pam_handle_t *pamh, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+ const char *dir, *end, *cwd, *user;
+ struct passwd *pwd;
+ char buf[PATH_MAX];
+
+ if (pam_get_user(pamh, &user, NULL) != PAM_SUCCESS ||
+ user == NULL || (pwd = getpwnam(user)) == NULL)
+ return (PAM_SESSION_ERR);
+ if (pwd->pw_uid == 0 && !openpam_get_option(pamh, "also_root"))
+ return (PAM_SUCCESS);
+ if (pwd->pw_dir == NULL)
+ return (PAM_SESSION_ERR);
+ if ((end = strstr(pwd->pw_dir, "/./")) != NULL) {
+ if (snprintf(buf, sizeof(buf), "%.*s",
+ (int)(end - pwd->pw_dir), pwd->pw_dir) > (int)sizeof(buf)) {
+ openpam_log(PAM_LOG_ERROR,
+ "%s's home directory is too long", user);
+ return (PAM_SESSION_ERR);
+ }
+ dir = buf;
+ cwd = end + 2;
+ } else if ((dir = openpam_get_option(pamh, "dir")) != NULL) {
+ if ((cwd = openpam_get_option(pamh, "cwd")) == NULL)
+ cwd = "/";
+ } else {
+ if (openpam_get_option(pamh, "always")) {
+ openpam_log(PAM_LOG_ERROR,
+ "%s has no chroot directory", user);
+ return (PAM_SESSION_ERR);
+ }
+ return (PAM_SUCCESS);
+ }
+
+ openpam_log(PAM_LOG_DEBUG, "chrooting %s to %s", dir, user);
+
+ if (chroot(dir) == -1) {
+ openpam_log(PAM_LOG_ERROR, "chroot(): %m");
+ return (PAM_SESSION_ERR);
+ }
+ if (chdir(cwd) == -1) {
+ openpam_log(PAM_LOG_ERROR, "chdir(): %m");
+ return (PAM_SESSION_ERR);
+ }
+ pam_setenv(pamh, "HOME", cwd, 1);
+ return (PAM_SUCCESS);
+}
+
+PAM_EXTERN int
+pam_sm_close_session(pam_handle_t *pamh __unused, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+
+ return (PAM_SUCCESS);
+}
+
+PAM_MODULE_ENTRY("pam_chroot");
diff --git a/lib/libpam/modules/pam_deny/Makefile b/lib/libpam/modules/pam_deny/Makefile
new file mode 100644
index 0000000..3bf8196
--- /dev/null
+++ b/lib/libpam/modules/pam_deny/Makefile
@@ -0,0 +1,31 @@
+# Copyright 1999 Max Khon.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+
+LIB= pam_deny
+SRCS= pam_deny.c
+MAN= pam_deny.8
+
+.include <bsd.lib.mk>
diff --git a/lib/libpam/modules/pam_deny/pam_deny.8 b/lib/libpam/modules/pam_deny/pam_deny.8
new file mode 100644
index 0000000..d9544be
--- /dev/null
+++ b/lib/libpam/modules/pam_deny/pam_deny.8
@@ -0,0 +1,80 @@
+.\" Copyright (c) 2001 Mark R V Murray
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING 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, 2001
+.Dt PAM_DENY 8
+.Os
+.Sh NAME
+.Nm pam_deny
+.Nd Deny PAM module
+.Sh SYNOPSIS
+.Op Ar service-name
+.Ar module-type
+.Ar control-flag
+.Pa pam_deny
+.Op Ar options
+.Sh DESCRIPTION
+The Deny authentication service module for PAM,
+.Nm
+provides functionality for all the PAM categories:
+authentication,
+account management,
+session management and
+password management.
+In terms of the
+.Ar module-type
+parameter, these are the
+.Dq Li auth ,
+.Dq Li account ,
+.Dq Li session ,
+and
+.Dq Li password
+features.
+.Pp
+The Deny module
+will universally deny all requests.
+It is primarily of use during testing,
+and to
+.Dq null-out
+unwanted functionality.
+.Pp
+The following options may be passed to the module:
+.Bl -tag -width ".Cm no_warn"
+.It Cm debug
+.Xr syslog 3
+debugging information at
+.Dv LOG_DEBUG
+level.
+.It Cm no_warn
+suppress warning messages to the user.
+These messages include
+reasons why the user's
+authentication attempt was declined.
+.El
+.Sh SEE ALSO
+.Xr syslog 3 ,
+.Xr pam.conf 5 ,
+.Xr pam 8
diff --git a/lib/libpam/modules/pam_deny/pam_deny.c b/lib/libpam/modules/pam_deny/pam_deny.c
new file mode 100644
index 0000000..3d491b1
--- /dev/null
+++ b/lib/libpam/modules/pam_deny/pam_deny.c
@@ -0,0 +1,93 @@
+/*-
+ * Copyright 2001 Mark R V Murray
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 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>
+
+#define PAM_SM_AUTH
+#define PAM_SM_ACCOUNT
+#define PAM_SM_SESSION
+#define PAM_SM_PASSWORD
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+
+PAM_EXTERN int
+pam_sm_authenticate(pam_handle_t *pamh, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+ const char *user;
+ int r;
+
+ if ((r = pam_get_user(pamh, &user, NULL)) != PAM_SUCCESS)
+ return (r);
+
+ return (PAM_AUTH_ERR);
+}
+
+PAM_EXTERN int
+pam_sm_setcred(pam_handle_t *pamh __unused, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+
+ return (PAM_CRED_ERR);
+}
+
+PAM_EXTERN int
+pam_sm_acct_mgmt(pam_handle_t *pamh __unused, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+
+ return (PAM_AUTH_ERR);
+}
+
+PAM_EXTERN int
+pam_sm_chauthtok(pam_handle_t *pamh __unused, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+
+ return (PAM_AUTHTOK_ERR);
+}
+
+PAM_EXTERN int
+pam_sm_open_session(pam_handle_t *pamh __unused, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+
+ return (PAM_SESSION_ERR);
+}
+
+PAM_EXTERN int
+pam_sm_close_session(pam_handle_t *pamh __unused, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+
+ return (PAM_SESSION_ERR);
+}
+
+PAM_MODULE_ENTRY("pam_deny");
diff --git a/lib/libpam/modules/pam_echo/Makefile b/lib/libpam/modules/pam_echo/Makefile
new file mode 100644
index 0000000..6f23946
--- /dev/null
+++ b/lib/libpam/modules/pam_echo/Makefile
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+LIB= pam_echo
+SRCS= pam_echo.c
+MAN= pam_echo.8
+
+.include <bsd.lib.mk>
diff --git a/lib/libpam/modules/pam_echo/pam_echo.8 b/lib/libpam/modules/pam_echo/pam_echo.8
new file mode 100644
index 0000000..b162b5b
--- /dev/null
+++ b/lib/libpam/modules/pam_echo/pam_echo.8
@@ -0,0 +1,93 @@
+.\" Copyright (c) 2001,2003 Networks Associates Technology, Inc.
+.\" All rights reserved.
+.\"
+.\" Portions of this software were developed for the FreeBSD Project by
+.\" ThinkSec AS 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING 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, 2003
+.Dt PAM_ECHO 8
+.Os
+.Sh NAME
+.Nm pam_echo
+.Nd Echo PAM module
+.Sh SYNOPSIS
+.Op Ar service-name
+.Ar module-type
+.Ar control-flag
+.Pa pam_echo
+.Op Ar arguments
+.Sh DESCRIPTION
+The echo service module for PAM displays its arguments to the user,
+separated by spaces, using the current conversation function.
+.Pp
+If the
+.Cm %
+character occurs anywhere in the arguments to
+.Nm ,
+it is assumed to introduce one of the following escape sequences:
+.Bl -tag -width 4n
+.It Cm %H
+The name of the host on which the client runs
+.Pq Dv PAM_RHOST .
+.\".It Cm %h
+.\"The name of the host on which the server runs.
+.It Cm %s
+The current service name
+.Pq Dv PAM_SERVICE .
+.It Cm %t
+The name of the controlling tty
+.Pq Dv PAM_TTY .
+.It Cm %U
+The applicant's user name
+.Pq Dv PAM_RUSER .
+.It Cm %u
+The target account's user name
+.Pq Dv PAM_USER .
+.El
+.Pp
+Any other two-character sequence beginning with
+.Cm %
+expands to the character following the
+.Cm %
+character.
+.Sh SEE ALSO
+.Xr pam.conf 5 ,
+.Xr pam 8
+.Sh AUTHORS
+The
+.Nm
+module and this manual page were developed for the
+.Fx
+Project by
+ThinkSec AS and NAI Labs, the Security Research Division of Network
+Associates, Inc.\& under DARPA/SPAWAR contract N66001-01-C-8035
+.Pq Dq CBOSS ,
+as part of the DARPA CHATS research program.
diff --git a/lib/libpam/modules/pam_echo/pam_echo.c b/lib/libpam/modules/pam_echo/pam_echo.c
new file mode 100644
index 0000000..ff00859
--- /dev/null
+++ b/lib/libpam/modules/pam_echo/pam_echo.c
@@ -0,0 +1,156 @@
+/*-
+ * Copyright (c) 2001,2003 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project by ThinkSec AS 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 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 <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <security/openpam.h>
+
+static int
+_pam_echo(pam_handle_t *pamh, int flags,
+ int argc, const char *argv[])
+{
+ char msg[PAM_MAX_MSG_SIZE];
+ const void *str;
+ const char *p, *q;
+ int err, i, item;
+ size_t len;
+
+ if (flags & PAM_SILENT)
+ return (PAM_SUCCESS);
+ for (i = 0, len = 0; i < argc && len < sizeof(msg) - 1; ++i) {
+ if (i > 0)
+ msg[len++] = ' ';
+ for (p = argv[i]; *p != '\0' && len < sizeof(msg) - 1; ++p) {
+ if (*p != '%' || p[1] == '\0') {
+ msg[len++] = *p;
+ continue;
+ }
+ switch (*++p) {
+ case 'H':
+ item = PAM_RHOST;
+ break;
+ case 'h':
+ /* not implemented */
+ item = -1;
+ break;
+ case 's':
+ item = PAM_SERVICE;
+ break;
+ case 't':
+ item = PAM_TTY;
+ break;
+ case 'U':
+ item = PAM_RUSER;
+ break;
+ case 'u':
+ item = PAM_USER;
+ break;
+ default:
+ item = -1;
+ msg[len++] = *p;
+ break;
+ }
+ if (item == -1)
+ continue;
+ err = pam_get_item(pamh, item, &str);
+ if (err != PAM_SUCCESS)
+ return (err);
+ if (str == NULL)
+ str = "(null)";
+ for (q = str; *q != '\0' && len < sizeof(msg) - 1; ++q)
+ msg[len++] = *q;
+ }
+ }
+ msg[len] = '\0';
+ return (pam_info(pamh, "%s", msg));
+}
+
+PAM_EXTERN int
+pam_sm_authenticate(pam_handle_t *pamh, int flags,
+ int argc, const char *argv[])
+{
+
+ return (_pam_echo(pamh, flags, argc, argv));
+}
+
+PAM_EXTERN int
+pam_sm_setcred(pam_handle_t *pamh __unused, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+
+ return (PAM_SUCCESS);
+}
+
+PAM_EXTERN int
+pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
+ int argc, const char *argv[])
+{
+
+ return (_pam_echo(pamh, flags, argc, argv));
+}
+
+PAM_EXTERN int
+pam_sm_open_session(pam_handle_t *pamh, int flags,
+ int argc, const char *argv[])
+{
+
+ return (_pam_echo(pamh, flags, argc, argv));
+}
+
+PAM_EXTERN int
+pam_sm_close_session(pam_handle_t *pamh, int flags,
+ int argc, const char *argv[])
+{
+
+ return (_pam_echo(pamh, flags, argc, argv));
+}
+
+PAM_EXTERN int
+pam_sm_chauthtok(pam_handle_t *pamh, int flags,
+ int argc, const char *argv[])
+{
+
+ if (flags & PAM_PRELIM_CHECK)
+ return (PAM_SUCCESS);
+ return (_pam_echo(pamh, flags, argc, argv));
+}
+
+PAM_MODULE_ENTRY("pam_echo");
diff --git a/lib/libpam/modules/pam_exec/Makefile b/lib/libpam/modules/pam_exec/Makefile
new file mode 100644
index 0000000..0cf4268
--- /dev/null
+++ b/lib/libpam/modules/pam_exec/Makefile
@@ -0,0 +1,9 @@
+# $FreeBSD$
+
+LIB= pam_exec
+SRCS= pam_exec.c
+MAN= pam_exec.8
+
+WARNS?= 0
+
+.include <bsd.lib.mk>
diff --git a/lib/libpam/modules/pam_exec/pam_exec.8 b/lib/libpam/modules/pam_exec/pam_exec.8
new file mode 100644
index 0000000..311d64c
--- /dev/null
+++ b/lib/libpam/modules/pam_exec/pam_exec.8
@@ -0,0 +1,75 @@
+.\" Copyright (c) 2001,2003 Networks Associates Technology, Inc.
+.\" All rights reserved.
+.\"
+.\" Portions of this software were developed for the FreeBSD Project by
+.\" ThinkSec AS 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING 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 1, 2005
+.Dt PAM_EXEC 8
+.Os
+.Sh NAME
+.Nm pam_exec
+.Nd Exec PAM module
+.Sh SYNOPSIS
+.Op Ar service-name
+.Ar module-type
+.Ar control-flag
+.Pa pam_exec
+.Op Ar arguments
+.Sh DESCRIPTION
+The exec service module for PAM executes the program designated by its
+first argument, with its remaining arguments as command-line
+arguments.
+The child's environment is set to the current PAM environment list,
+as returned by
+.Xr pam_getenvlist 3 .
+In addition, the following PAM items are exported as environment
+variables:
+.Ev PAM_RHOST ,
+.Ev PAM_RUSER ,
+.Ev PAM_SERVICE ,
+.Ev PAM_TTY ,
+and
+.Ev PAM_USER .
+.Sh SEE ALSO
+.Xr pam_get_item 3 ,
+.Xr pam.conf 5 ,
+.Xr pam 8
+.Sh AUTHORS
+The
+.Nm
+module and this manual page were developed for the
+.Fx
+Project by
+ThinkSec AS and NAI Labs, the Security Research Division of Network
+Associates, Inc.\& under DARPA/SPAWAR contract N66001-01-C-8035
+.Pq Dq CBOSS ,
+as part of the DARPA CHATS research program.
diff --git a/lib/libpam/modules/pam_exec/pam_exec.c b/lib/libpam/modules/pam_exec/pam_exec.c
new file mode 100644
index 0000000..e4a35ee
--- /dev/null
+++ b/lib/libpam/modules/pam_exec/pam_exec.c
@@ -0,0 +1,198 @@
+/*-
+ * Copyright (c) 2001,2003 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project by ThinkSec AS 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 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 <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <security/openpam.h>
+
+#define ENV_ITEM(n) { (n), #n }
+static struct {
+ int item;
+ const char *name;
+} env_items[] = {
+ ENV_ITEM(PAM_SERVICE),
+ ENV_ITEM(PAM_USER),
+ ENV_ITEM(PAM_TTY),
+ ENV_ITEM(PAM_RHOST),
+ ENV_ITEM(PAM_RUSER),
+};
+
+static int
+_pam_exec(pam_handle_t *pamh __unused, int flags __unused,
+ int argc, const char *argv[])
+{
+ int childerr, envlen, i, nitems, pam_err, status;
+ char *env, **envlist, **tmp;
+ pid_t pid;
+
+ if (argc < 1)
+ return (PAM_SERVICE_ERR);
+
+ /*
+ * XXX For additional credit, divert child's stdin/stdout/stderr
+ * to the conversation function.
+ */
+
+ /*
+ * Set up the child's environment list. It consists of the PAM
+ * environment, plus a few hand-picked PAM items.
+ */
+ envlist = pam_getenvlist(pamh);
+ for (envlen = 0; envlist[envlen] != NULL; ++envlen)
+ /* nothing */ ;
+ nitems = sizeof(env_items) / sizeof(*env_items);
+ tmp = realloc(envlist, (envlen + nitems + 1) * sizeof(*envlist));
+ if (tmp == NULL) {
+ openpam_free_envlist(envlist);
+ return (PAM_BUF_ERR);
+ }
+ envlist = tmp;
+ for (i = 0; i < nitems; ++i) {
+ const void *item;
+ char *envstr;
+
+ pam_err = pam_get_item(pamh, env_items[i].item, &item);
+ if (pam_err != PAM_SUCCESS || item == NULL)
+ continue;
+ asprintf(&envstr, "%s=%s", env_items[i].name, item);
+ if (envstr == NULL) {
+ openpam_free_envlist(envlist);
+ return (PAM_BUF_ERR);
+ }
+ envlist[envlen++] = envstr;
+ envlist[envlen] = NULL;
+ }
+
+ /*
+ * Fork and run the command. By using vfork() instead of fork(),
+ * we can distinguish between an execve() failure and a non-zero
+ * exit code from the command.
+ */
+ childerr = 0;
+ if ((pid = vfork()) == 0) {
+ execve(argv[0], (char * const *)argv, (char * const *)envlist);
+ childerr = errno;
+ _exit(1);
+ }
+ openpam_free_envlist(envlist);
+ if (pid == -1) {
+ openpam_log(PAM_LOG_ERROR, "vfork(): %m");
+ return (PAM_SYSTEM_ERR);
+ }
+ if (waitpid(pid, &status, 0) == -1) {
+ openpam_log(PAM_LOG_ERROR, "waitpid(): %m");
+ return (PAM_SYSTEM_ERR);
+ }
+ if (childerr != 0) {
+ openpam_log(PAM_LOG_ERROR, "execve(): %m");
+ return (PAM_SYSTEM_ERR);
+ }
+ if (WIFSIGNALED(status)) {
+ openpam_log(PAM_LOG_ERROR, "%s caught signal %d%s",
+ argv[0], WTERMSIG(status),
+ WCOREDUMP(status) ? " (core dumped)" : "");
+ return (PAM_SYSTEM_ERR);
+ }
+ if (!WIFEXITED(status)) {
+ openpam_log(PAM_LOG_ERROR, "unknown status 0x%x", status);
+ return (PAM_SYSTEM_ERR);
+ }
+ if (WEXITSTATUS(status) != 0) {
+ openpam_log(PAM_LOG_ERROR, "%s returned code %d",
+ argv[0], WEXITSTATUS(status));
+ return (PAM_SYSTEM_ERR);
+ }
+ return (PAM_SUCCESS);
+}
+
+PAM_EXTERN int
+pam_sm_authenticate(pam_handle_t *pamh, int flags,
+ int argc, const char *argv[])
+{
+
+ return (_pam_exec(pamh, flags, argc, argv));
+}
+
+PAM_EXTERN int
+pam_sm_setcred(pam_handle_t *pamh, int flags,
+ int argc, const char *argv[])
+{
+
+ return (_pam_exec(pamh, flags, argc, argv));
+}
+
+PAM_EXTERN int
+pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
+ int argc, const char *argv[])
+{
+
+ return (_pam_exec(pamh, flags, argc, argv));
+}
+
+PAM_EXTERN int
+pam_sm_open_session(pam_handle_t *pamh, int flags,
+ int argc, const char *argv[])
+{
+
+ return (_pam_exec(pamh, flags, argc, argv));
+}
+
+PAM_EXTERN int
+pam_sm_close_session(pam_handle_t *pamh, int flags,
+ int argc, const char *argv[])
+{
+
+ return (_pam_exec(pamh, flags, argc, argv));
+}
+
+PAM_EXTERN int
+pam_sm_chauthtok(pam_handle_t *pamh, int flags,
+ int argc, const char *argv[])
+{
+
+ return (_pam_exec(pamh, flags, argc, argv));
+}
+
+PAM_MODULE_ENTRY("pam_exec");
diff --git a/lib/libpam/modules/pam_ftpusers/Makefile b/lib/libpam/modules/pam_ftpusers/Makefile
new file mode 100644
index 0000000..8bca1aa
--- /dev/null
+++ b/lib/libpam/modules/pam_ftpusers/Makefile
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+LIB= pam_ftpusers
+SRCS= pam_ftpusers.c
+MAN= pam_ftpusers.8
+
+.include <bsd.lib.mk>
diff --git a/lib/libpam/modules/pam_ftpusers/pam_ftpusers.8 b/lib/libpam/modules/pam_ftpusers/pam_ftpusers.8
new file mode 100644
index 0000000..380e3b0
--- /dev/null
+++ b/lib/libpam/modules/pam_ftpusers/pam_ftpusers.8
@@ -0,0 +1,99 @@
+.\" Copyright (c) 2001 Mark R V Murray
+.\" All rights reserved.
+.\" Copyright (c) 2002 Networks Associates Technology, Inc.
+.\" All rights reserved.
+.\"
+.\" Portions of this software were developed for the FreeBSD Project by
+.\" ThinkSec AS 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING 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 PAM_FTPUSERS 8
+.Os
+.Sh NAME
+.Nm pam_ftpusers
+.Nd ftpusers PAM module
+.Sh SYNOPSIS
+.Op Ar service-name
+.Ar module-type
+.Ar control-flag
+.Pa pam_ftpusers
+.Op Ar options
+.Sh DESCRIPTION
+The
+.Pa ftpusers
+service module for PAM,
+.Nm
+provides functionality for only one PAM category:
+account management.
+In terms of the
+.Ar module-type
+parameter, this is the
+.Dq Li account
+feature.
+.Ss Ftpusers Account Management Module
+The
+.Pa ftpusers
+account management component
+.Pq Fn pam_sm_acct_mgmt ,
+succeeds if and only if the user is listed in
+.Pa /etc/ftpusers .
+.Pp
+The following options may be passed to the authentication module:
+.Bl -tag -width ".Cm disallow"
+.It Cm debug
+.Xr syslog 3
+debugging information at
+.Dv LOG_DEBUG
+level.
+.It Cm no_warn
+suppress warning messages to the user.
+These messages include reasons why the user's authentication attempt
+was declined.
+.It Cm disallow
+reverse the semantics;
+.Nm
+will succeed if and only if the user is not listed in
+.Pa /etc/ftpusers .
+.El
+.Sh SEE ALSO
+.Xr ftpusers 5 ,
+.Xr pam.conf 5 ,
+.Xr pam 8
+.Sh AUTHORS
+The
+.Nm
+module and this manual page were developed for the
+.Fx
+Project by
+ThinkSec AS and NAI Labs, the Security Research Division of Network
+Associates, Inc.\& under DARPA/SPAWAR contract N66001-01-C-8035
+.Pq Dq CBOSS ,
+as part of the DARPA CHATS research program.
diff --git a/lib/libpam/modules/pam_ftpusers/pam_ftpusers.c b/lib/libpam/modules/pam_ftpusers/pam_ftpusers.c
new file mode 100644
index 0000000..421955a
--- /dev/null
+++ b/lib/libpam/modules/pam_ftpusers/pam_ftpusers.c
@@ -0,0 +1,115 @@
+/*-
+ * Copyright (c) 2001 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project by ThinkSec AS 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 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 <grp.h>
+#include <paths.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define PAM_SM_ACCOUNT
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <security/pam_mod_misc.h>
+#include <security/openpam.h>
+
+PAM_EXTERN int
+pam_sm_acct_mgmt(pam_handle_t *pamh, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+ struct passwd *pwd;
+ struct group *grp;
+ const char *user;
+ int pam_err, found, allow;
+ char *line, *name, **mem;
+ size_t len, ulen;
+ FILE *f;
+
+ pam_err = pam_get_user(pamh, &user, NULL);
+ if (pam_err != PAM_SUCCESS)
+ return (pam_err);
+ if (user == NULL || (pwd = getpwnam(user)) == NULL)
+ return (PAM_SERVICE_ERR);
+
+ found = 0;
+ ulen = strlen(user);
+ if ((f = fopen(_PATH_FTPUSERS, "r")) == NULL) {
+ PAM_LOG("%s: %m", _PATH_FTPUSERS);
+ goto done;
+ }
+ while (!found && (line = fgetln(f, &len)) != NULL) {
+ if (*line == '#')
+ continue;
+ while (len > 0 && isspace(line[len - 1]))
+ --len;
+ if (len == 0)
+ continue;
+ /* simple case first */
+ if (*line != '@') {
+ if (len == ulen && strncmp(user, line, len) == 0)
+ found = 1;
+ continue;
+ }
+ /* member of specified group? */
+ asprintf(&name, "%.*s", (int)len - 1, line + 1);
+ if (name == NULL) {
+ fclose(f);
+ return (PAM_BUF_ERR);
+ }
+ grp = getgrnam(name);
+ free(name);
+ if (grp == NULL)
+ continue;
+ for (mem = grp->gr_mem; mem && *mem && !found; ++mem)
+ if (strcmp(user, *mem) == 0)
+ found = 1;
+ }
+ done:
+ allow = (openpam_get_option(pamh, "disallow") == NULL);
+ if (found)
+ pam_err = allow ? PAM_SUCCESS : PAM_AUTH_ERR;
+ else
+ pam_err = allow ? PAM_AUTH_ERR : PAM_SUCCESS;
+ if (f != NULL)
+ fclose(f);
+ return (pam_err);
+}
+
+PAM_MODULE_ENTRY("pam_ftpusers");
diff --git a/lib/libpam/modules/pam_group/Makefile b/lib/libpam/modules/pam_group/Makefile
new file mode 100644
index 0000000..73b072a
--- /dev/null
+++ b/lib/libpam/modules/pam_group/Makefile
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+LIB= pam_group
+SRCS= pam_group.c
+MAN= pam_group.8
+
+.include <bsd.lib.mk>
diff --git a/lib/libpam/modules/pam_group/pam_group.8 b/lib/libpam/modules/pam_group/pam_group.8
new file mode 100644
index 0000000..832841b
--- /dev/null
+++ b/lib/libpam/modules/pam_group/pam_group.8
@@ -0,0 +1,83 @@
+.\" Copyright (c) 2003 Networks Associates Technology, Inc.
+.\" All rights reserved.
+.\"
+.\" Portions of this software were developed for the FreeBSD Project by
+.\" ThinkSec AS 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING 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, 2003
+.Dt PAM_GROUP 8
+.Os
+.Sh NAME
+.Nm pam_group
+.Nd Group PAM module
+.Sh SYNOPSIS
+.Op Ar service-name
+.Ar module-type
+.Ar control-flag
+.Pa pam_group
+.Op Ar arguments
+.Sh DESCRIPTION
+The group service module for PAM accepts or rejects users based on
+their membership in a particular file group.
+.Pp
+The following options may be passed to the
+.Nm
+module:
+.Bl -tag -width ".Cm fail_safe"
+.It Cm deny
+Reverse the meaning of the test, i.e., reject the applicant if and only
+if he or she is a member of the specified group.
+This can be useful to exclude certain groups of users from certain
+services.
+.It Cm fail_safe
+If the specified group does not exist, or has no members, act as if
+it does exist and the applicant is a member.
+.It Cm group Ns = Ns Ar groupname
+Specify the name of the group to check.
+The default is
+.Dq Li wheel .
+.It Cm root_only
+Skip this module entirely if the target account is not the superuser
+account.
+.El
+.Sh SEE ALSO
+.Xr pam.conf 5 ,
+.Xr pam 8
+.Sh AUTHORS
+The
+.Nm
+module and this manual page were developed for the
+.Fx
+Project by
+ThinkSec AS and NAI Labs, the Security Research Division of Network
+Associates, Inc.\& under DARPA/SPAWAR contract N66001-01-C-8035
+.Pq Dq CBOSS ,
+as part of the DARPA CHATS research program.
diff --git a/lib/libpam/modules/pam_group/pam_group.c b/lib/libpam/modules/pam_group/pam_group.c
new file mode 100644
index 0000000..a9d5fc3
--- /dev/null
+++ b/lib/libpam/modules/pam_group/pam_group.c
@@ -0,0 +1,117 @@
+/*-
+ * Copyright (c) 2003 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 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 <grp.h>
+#include <pwd.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#define PAM_SM_AUTH
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <security/openpam.h>
+
+
+PAM_EXTERN int
+pam_sm_authenticate(pam_handle_t *pamh, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+ const char *group, *user;
+ const void *ruser;
+ char *const *list;
+ struct passwd *pwd;
+ struct group *grp;
+
+ /* get target account */
+ if (pam_get_user(pamh, &user, NULL) != PAM_SUCCESS ||
+ user == NULL || (pwd = getpwnam(user)) == NULL)
+ return (PAM_AUTH_ERR);
+ if (pwd->pw_uid != 0 && openpam_get_option(pamh, "root_only"))
+ return (PAM_IGNORE);
+
+ /* get applicant */
+ if (pam_get_item(pamh, PAM_RUSER, &ruser) != PAM_SUCCESS
+ || ruser == NULL || (pwd = getpwnam(ruser)) == NULL)
+ return (PAM_AUTH_ERR);
+
+ /* get regulating group */
+ if ((group = openpam_get_option(pamh, "group")) == NULL)
+ group = "wheel";
+ if ((grp = getgrnam(group)) == NULL || grp->gr_mem == NULL)
+ goto failed;
+
+ /* check if the group is empty */
+ if (*grp->gr_mem == NULL)
+ goto failed;
+
+ /* check membership */
+ if (pwd->pw_gid == grp->gr_gid)
+ goto found;
+ for (list = grp->gr_mem; *list != NULL; ++list)
+ if (strcmp(*list, pwd->pw_name) == 0)
+ goto found;
+
+ not_found:
+ if (openpam_get_option(pamh, "deny"))
+ return (PAM_SUCCESS);
+ return (PAM_AUTH_ERR);
+ found:
+ if (openpam_get_option(pamh, "deny"))
+ return (PAM_AUTH_ERR);
+ return (PAM_SUCCESS);
+ failed:
+ if (openpam_get_option(pamh, "fail_safe"))
+ goto found;
+ else
+ goto not_found;
+}
+
+PAM_EXTERN int
+pam_sm_setcred(pam_handle_t * pamh __unused, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+
+ return (PAM_SUCCESS);
+}
+
+PAM_MODULE_ENTRY("pam_group");
diff --git a/lib/libpam/modules/pam_guest/Makefile b/lib/libpam/modules/pam_guest/Makefile
new file mode 100644
index 0000000..ccc192e
--- /dev/null
+++ b/lib/libpam/modules/pam_guest/Makefile
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+LIB= pam_guest
+SRCS= pam_guest.c
+MAN= pam_guest.8
+
+.include <bsd.lib.mk>
diff --git a/lib/libpam/modules/pam_guest/pam_guest.8 b/lib/libpam/modules/pam_guest/pam_guest.8
new file mode 100644
index 0000000..0bd1755
--- /dev/null
+++ b/lib/libpam/modules/pam_guest/pam_guest.8
@@ -0,0 +1,98 @@
+.\" Copyright (c) 2003 Networks Associates Technology, Inc.
+.\" All rights reserved.
+.\"
+.\" Portions of this software were developed for the FreeBSD Project by
+.\" ThinkSec AS 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING 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, 2003
+.Dt PAM_GUEST 8
+.Os
+.Sh NAME
+.Nm pam_guest
+.Nd Guest PAM module
+.Sh SYNOPSIS
+.Op Ar service-name
+.Ar module-type
+.Ar control-flag
+.Pa pam_guest
+.Op Ar arguments
+.Sh DESCRIPTION
+The guest service module for PAM allows guest logins.
+If successful, the
+.Nm
+module sets the PAM environment variable
+.Ev GUEST
+to the login name.
+The application can check this variable using
+.Xr pam_getenv 3
+to differentiate guest logins from normal logins.
+.Pp
+The following options may be passed to the
+.Nm
+module:
+.Bl -tag -width ".Cm pass_as_ruser"
+.It Cm guests Ns = Ns Ar list
+Comma-separated list of guest account names.
+The default is
+.Dq Li guest .
+A typical value for
+.Xr ftpd 8
+would be
+.Dq Li anonymous,ftp .
+.It Cm nopass
+Omits the password prompt if the target account is on the list of
+guest accounts.
+.It Cm pass_as_ruser
+The password typed in by the user is exported as the
+.Dv PAM_RUSER
+item.
+This is useful for applications like
+.Xr ftpd 8
+where guest users are encouraged to use their email address as
+password.
+.It Cm pass_is_user
+Requires the guest user to type in the guest account name as password.
+.El
+.Sh SEE ALSO
+.Xr pam_getenv 3 ,
+.Xr pam_get_item 3 ,
+.Xr pam.conf 5 ,
+.Xr pam 8
+.Sh AUTHORS
+The
+.Nm
+module and this manual page were developed for the
+.Fx
+Project by
+ThinkSec AS and NAI Labs, the Security Research Division of Network
+Associates, Inc.\& under DARPA/SPAWAR contract N66001-01-C-8035
+.Pq Dq CBOSS ,
+as part of the DARPA CHATS research program.
diff --git a/lib/libpam/modules/pam_guest/pam_guest.c b/lib/libpam/modules/pam_guest/pam_guest.c
new file mode 100644
index 0000000..110edce
--- /dev/null
+++ b/lib/libpam/modules/pam_guest/pam_guest.c
@@ -0,0 +1,114 @@
+/*-
+ * Copyright (c) 2003 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 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>
+
+#define PAM_SM_AUTH
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <security/openpam.h>
+
+#define DEFAULT_GUESTS "guest"
+
+static int
+lookup(const char *str, const char *list)
+{
+ const char *next;
+ size_t len;
+
+ len = strlen(str);
+ while (*list != '\0') {
+ while (*list == ',')
+ ++list;
+ if ((next = strchr(list, ',')) == NULL)
+ next = strchr(list, '\0');
+ if (next - list == (ptrdiff_t)len &&
+ strncmp(list, str, len) == 0)
+ return (1);
+ list = next;
+ }
+ return (0);
+}
+
+PAM_EXTERN int
+pam_sm_authenticate(pam_handle_t *pamh, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+ const char *authtok, *guests, *user;
+ int err, is_guest;
+
+ /* get target account */
+ if (pam_get_user(pamh, &user, NULL) != PAM_SUCCESS || user == NULL)
+ return (PAM_AUTH_ERR);
+
+ /* get list of guest logins */
+ if ((guests = openpam_get_option(pamh, "guests")) == NULL)
+ guests = DEFAULT_GUESTS;
+
+ /* check if the target account is on the list */
+ is_guest = lookup(user, guests);
+
+ /* check password */
+ if (!openpam_get_option(pamh, "nopass")) {
+ err = pam_get_authtok(pamh, PAM_AUTHTOK, &authtok, NULL);
+ if (err != PAM_SUCCESS)
+ return (err);
+ if (openpam_get_option(pamh, "pass_is_user") &&
+ strcmp(user, authtok) != 0)
+ return (PAM_AUTH_ERR);
+ if (openpam_get_option(pamh, "pass_as_ruser"))
+ pam_set_item(pamh, PAM_RUSER, authtok);
+ }
+
+ /* done */
+ if (is_guest) {
+ pam_setenv(pamh, "GUEST", user, 1);
+ return (PAM_SUCCESS);
+ }
+ return (PAM_AUTH_ERR);
+}
+
+PAM_EXTERN int
+pam_sm_setcred(pam_handle_t * pamh __unused, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+
+ return (PAM_SUCCESS);
+}
+
+PAM_MODULE_ENTRY("pam_guest");
diff --git a/lib/libpam/modules/pam_krb5/Makefile b/lib/libpam/modules/pam_krb5/Makefile
new file mode 100644
index 0000000..a90236c
--- /dev/null
+++ b/lib/libpam/modules/pam_krb5/Makefile
@@ -0,0 +1,38 @@
+# Copyright 2001 FreeBSD, 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$
+
+LIB= pam_krb5
+SRCS= pam_krb5.c
+MAN= pam_krb5.8
+.if defined(_FREEFALL_CONFIG)
+CFLAGS+=-D_FREEFALL_CONFIG
+WARNS= 0
+.endif
+
+DPADD= ${LIBKRB5} ${LIBASN1} ${LIBROKEN} ${LIBCOM_ERR} ${LIBCRYPT} ${LIBCRYPTO}
+LDADD= -lkrb5 -lasn1 -lroken -lcom_err -lcrypt -lcrypto
+
+.include <bsd.lib.mk>
diff --git a/lib/libpam/modules/pam_krb5/pam_krb5.8 b/lib/libpam/modules/pam_krb5/pam_krb5.8
new file mode 100644
index 0000000..3e0db91
--- /dev/null
+++ b/lib/libpam/modules/pam_krb5/pam_krb5.8
@@ -0,0 +1,217 @@
+.\"
+.\" $Id: pam_krb5.5,v 1.5 2000/01/05 00:59:56 fcusack Exp $
+.\" $FreeBSD$
+.Dd January 15, 1999
+.Dt PAM_KRB5 8
+.Os
+.Sh NAME
+.Nm pam_krb5
+.Nd Kerberos 5 PAM module
+.Sh SYNOPSIS
+.Pa /usr/lib/pam_krb5.so
+.Sh DESCRIPTION
+The Kerberos 5 service module for PAM, typically
+.Pa /usr/lib/pam_krb5.so ,
+provides functionality for three PAM categories:
+authentication,
+account management,
+and password management.
+It also provides null functions for session management.
+The
+.Pa pam_krb5.so
+module is a shared object
+that can be dynamically loaded to provide
+the necessary functionality upon demand.
+Its path is specified in the
+PAM configuration file.
+.Ss Kerberos 5 Authentication Module
+The Kerberos 5 authentication component
+provides functions to verify the identity of a user
+.Pq Fn pam_sm_authenticate
+and to set user specific credentials
+.Pq Fn pam_sm_setcred .
+.Fn pam_sm_authenticate
+converts the supplied username into a Kerberos principal,
+by appending the default local realm name.
+It also supports usernames with explicit realm names.
+If a realm name is supplied, then upon a successful return, it
+changes the username by mapping the principal name into a local username
+(calling
+.Fn krb5_aname_to_localname ) .
+This typically just means
+the realm name is stripped.
+.Pp
+It prompts the user for a password and obtains a new Kerberos TGT for
+the principal.
+The TGT is verified by obtaining a service
+ticket for the local host.
+.Pp
+When prompting for the current password, the authentication
+module will use the prompt
+.Dq Li "Password for <principal>:" .
+.Pp
+The
+.Fn pam_sm_setcred
+function stores the newly acquired credentials in a credentials cache,
+and sets the environment variable
+.Ev KRB5CCNAME
+appropriately.
+The credentials cache should be destroyed by the user at logout with
+.Xr kdestroy 1 .
+.Pp
+The following options may be passed to the authentication module:
+.Bl -tag -width ".Cm use_first_pass"
+.It Cm debug
+.Xr syslog 3
+debugging information at
+.Dv LOG_DEBUG
+level.
+.It Cm no_warn
+suppress warning messages to the user.
+These messages include
+reasons why the user's
+authentication attempt was declined.
+.It Cm use_first_pass
+If the authentication module is not the first in the stack,
+and a previous module obtained the user's password, that password is
+used to authenticate the user.
+If this fails, the authentication
+module returns failure without prompting the user for a password.
+This option has no effect if the authentication module is
+the first in the stack, or if no previous modules obtained the
+user's password.
+.It Cm try_first_pass
+This option is similar to the
+.Cm use_first_pass
+option, except that if the previously obtained password fails, the
+user is prompted for another password.
+.It Cm forwardable
+Obtain forwardable Kerberos credentials for the user.
+.It Cm no_ccache
+Do not save the obtained credentials in a credentials cache.
+This is a
+useful option if the authentication module is used for services such
+as ftp or pop, where the user would not be able to destroy them.
+[This
+is not a recommendation to use the module for those services.]
+.It Cm ccache Ns = Ns Ar name
+Use
+.Ar name
+as the credentials cache.
+.Ar name
+must be in the form
+.Ar type : Ns Ar residual .
+The special tokens
+.Ql %u ,
+to designate the decimal UID of the user;
+and
+.Ql %p ,
+to designate the current process ID; can be used in
+.Ar name .
+.El
+.Ss Kerberos 5 Account Management Module
+The Kerberos 5 account management component
+provides a function to perform account management,
+.Fn pam_sm_acct_mgmt .
+The function verifies that the authenticated principal is allowed
+to login to the local user account by calling
+.Fn krb5_kuserok
+(which checks the user's
+.Pa .k5login
+file).
+.Ss Kerberos 5 Password Management Module
+The Kerberos 5 password management component
+provides a function to change passwords
+.Pq Fn pam_sm_chauthtok .
+The username supplied (the
+user running the
+.Xr passwd 1
+command, or the username given as an argument) is mapped into
+a Kerberos principal name, using the same technique as in
+the authentication module.
+Note that if a realm name was
+explicitly supplied during authentication, but not during
+a password change, the mapping
+done by the password management module may not result in the
+same principal as was used for authentication.
+.Pp
+Unlike when
+changing a
+.Ux
+password, the password management module will
+allow any user to change any principal's password (if the user knows
+the principal's old password, of course).
+Also unlike
+.Ux ,
+root
+is always prompted for the principal's old password.
+.Pp
+The password management module uses the same heuristics as
+.Xr kpasswd 1
+to determine how to contact the Kerberos password server.
+.Pp
+The following options may be passed to the password management
+module:
+.Bl -tag -width ".Cm use_first_pass"
+.It Cm debug
+.Xr syslog 3
+debugging information at
+.Dv LOG_DEBUG
+level.
+.It Cm use_first_pass
+If the password management module is not the first in the stack,
+and a previous module obtained the user's old password, that password is
+used to authenticate the user.
+If this fails, the password
+management
+module returns failure without prompting the user for the old password.
+If successful, the new password entered to the previous module is also
+used as the new Kerberos password.
+If the new password fails,
+the password management module returns failure without
+prompting the user for a new password.
+.It Cm try_first_pass
+This option is similar to the
+.Cm use_first_pass
+option, except that if the previously obtained old or new passwords fail,
+the user is prompted for them.
+.El
+.Ss Kerberos 5 Session Management Module
+The Kerberos 5 session management component
+provides functions to initiate
+.Pq Fn pam_sm_open_session
+and terminate
+.Pq Fn pam_sm_close_session
+sessions.
+Since session management is not defined under Kerberos 5,
+both of these functions simply return success.
+They are provided
+only because of the naming conventions for PAM modules.
+.Sh ENVIRONMENT
+.Bl -tag -width "KRB5CCNAME"
+.It Ev KRB5CCNAME
+Location of the credentials cache.
+.El
+.Sh FILES
+.Bl -tag -width ".Pa /tmp/krb5cc_ Ns Ar uid" -compact
+.It Pa /tmp/krb5cc_ Ns Ar uid
+default credentials cache
+.Ar ( uid
+is the decimal UID of the user).
+.It Pa $HOME/.k5login
+file containing Kerberos principals that are allowed access.
+.El
+.Sh SEE ALSO
+.Xr kdestroy 1 ,
+.Xr passwd 1 ,
+.Xr syslog 3 ,
+.Xr pam.conf 5 ,
+.Xr pam 8
+.Sh NOTES
+Applications should not call
+.Fn pam_authenticate
+more than once between calls to
+.Fn pam_start
+and
+.Fn pam_end
+when using the Kerberos 5 PAM module.
diff --git a/lib/libpam/modules/pam_krb5/pam_krb5.c b/lib/libpam/modules/pam_krb5/pam_krb5.c
new file mode 100644
index 0000000..0ed57f9
--- /dev/null
+++ b/lib/libpam/modules/pam_krb5/pam_krb5.c
@@ -0,0 +1,971 @@
+/*-
+ * This pam_krb5 module contains code that is:
+ * Copyright (c) Derrick J. Brashear, 1996. All rights reserved.
+ * Copyright (c) Frank Cusack, 1999-2001. All rights reserved.
+ * Copyright (c) Jacques A. Vidrine, 2000-2001. All rights reserved.
+ * Copyright (c) Nicolas Williams, 2001. All rights reserved.
+ * Copyright (c) Perot Systems Corporation, 2001. All rights reserved.
+ * Copyright (c) Mark R V Murray, 2001. All rights reserved.
+ * Copyright (c) Networks Associates Technology, Inc., 2002-2005.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS 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
+ * notices, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce 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.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions. (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * 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 <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <limits.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include <krb5.h>
+#include <com_err.h>
+
+#define PAM_SM_AUTH
+#define PAM_SM_ACCOUNT
+#define PAM_SM_PASSWORD
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <security/pam_mod_misc.h>
+#include <security/openpam.h>
+
+#define COMPAT_HEIMDAL
+/* #define COMPAT_MIT */
+
+static int verify_krb_v5_tgt(krb5_context, krb5_ccache, char *, int);
+static void cleanup_cache(pam_handle_t *, void *, int);
+static const char *compat_princ_component(krb5_context, krb5_principal, int);
+static void compat_free_data_contents(krb5_context, krb5_data *);
+
+#define USER_PROMPT "Username: "
+#define PASSWORD_PROMPT "Password:"
+#define NEW_PASSWORD_PROMPT "New Password:"
+
+#define PAM_OPT_CCACHE "ccache"
+#define PAM_OPT_DEBUG "debug"
+#define PAM_OPT_FORWARDABLE "forwardable"
+#define PAM_OPT_NO_CCACHE "no_ccache"
+#define PAM_OPT_REUSE_CCACHE "reuse_ccache"
+
+/*
+ * authentication management
+ */
+PAM_EXTERN int
+pam_sm_authenticate(pam_handle_t *pamh, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+ krb5_error_code krbret;
+ krb5_context pam_context;
+ krb5_creds creds;
+ krb5_principal princ;
+ krb5_ccache ccache;
+ krb5_get_init_creds_opt opts;
+ struct passwd *pwd;
+ int retval;
+ void *ccache_data;
+ const char *user, *pass;
+ const void *sourceuser, *service;
+ char *principal, *princ_name, *ccache_name, luser[32], *srvdup;
+
+ retval = pam_get_user(pamh, &user, USER_PROMPT);
+ if (retval != PAM_SUCCESS)
+ return (retval);
+
+ PAM_LOG("Got user: %s", user);
+
+ retval = pam_get_item(pamh, PAM_RUSER, &sourceuser);
+ if (retval != PAM_SUCCESS)
+ return (retval);
+
+ PAM_LOG("Got ruser: %s", (const char *)sourceuser);
+
+ service = NULL;
+ pam_get_item(pamh, PAM_SERVICE, &service);
+ if (service == NULL)
+ service = "unknown";
+
+ PAM_LOG("Got service: %s", (const char *)service);
+
+ krbret = krb5_init_context(&pam_context);
+ if (krbret != 0) {
+ PAM_VERBOSE_ERROR("Kerberos 5 error");
+ return (PAM_SERVICE_ERR);
+ }
+
+ PAM_LOG("Context initialised");
+
+ krb5_get_init_creds_opt_init(&opts);
+
+ if (openpam_get_option(pamh, PAM_OPT_FORWARDABLE))
+ krb5_get_init_creds_opt_set_forwardable(&opts, 1);
+
+ PAM_LOG("Credentials initialised");
+
+ krbret = krb5_cc_register(pam_context, &krb5_mcc_ops, FALSE);
+ if (krbret != 0 && krbret != KRB5_CC_TYPE_EXISTS) {
+ PAM_VERBOSE_ERROR("Kerberos 5 error");
+ retval = PAM_SERVICE_ERR;
+ goto cleanup3;
+ }
+
+ PAM_LOG("Done krb5_cc_register()");
+
+ /* Get principal name */
+ if (openpam_get_option(pamh, PAM_OPT_AUTH_AS_SELF))
+ asprintf(&principal, "%s/%s", (const char *)sourceuser, user);
+ else
+ principal = strdup(user);
+
+ PAM_LOG("Created principal: %s", principal);
+
+ krbret = krb5_parse_name(pam_context, principal, &princ);
+ free(principal);
+ if (krbret != 0) {
+ PAM_LOG("Error krb5_parse_name(): %s",
+ krb5_get_err_text(pam_context, krbret));
+ PAM_VERBOSE_ERROR("Kerberos 5 error");
+ retval = PAM_SERVICE_ERR;
+ goto cleanup3;
+ }
+
+ PAM_LOG("Done krb5_parse_name()");
+
+ /* Now convert the principal name into something human readable */
+ princ_name = NULL;
+ krbret = krb5_unparse_name(pam_context, princ, &princ_name);
+ if (krbret != 0) {
+ PAM_LOG("Error krb5_unparse_name(): %s",
+ krb5_get_err_text(pam_context, krbret));
+ PAM_VERBOSE_ERROR("Kerberos 5 error");
+ retval = PAM_SERVICE_ERR;
+ goto cleanup2;
+ }
+
+ PAM_LOG("Got principal: %s", princ_name);
+
+ /* Get password */
+ retval = pam_get_authtok(pamh, PAM_AUTHTOK, &pass, PASSWORD_PROMPT);
+ if (retval != PAM_SUCCESS)
+ goto cleanup2;
+
+ PAM_LOG("Got password");
+
+ /* Verify the local user exists (AFTER getting the password) */
+ if (strchr(user, '@')) {
+ /* get a local account name for this principal */
+ krbret = krb5_aname_to_localname(pam_context, princ,
+ sizeof(luser), luser);
+ if (krbret != 0) {
+ PAM_VERBOSE_ERROR("Kerberos 5 error");
+ PAM_LOG("Error krb5_aname_to_localname(): %s",
+ krb5_get_err_text(pam_context, krbret));
+ retval = PAM_USER_UNKNOWN;
+ goto cleanup2;
+ }
+
+ retval = pam_set_item(pamh, PAM_USER, luser);
+ if (retval != PAM_SUCCESS)
+ goto cleanup2;
+
+ PAM_LOG("PAM_USER Redone");
+ }
+
+ pwd = getpwnam(user);
+ if (pwd == NULL) {
+ retval = PAM_USER_UNKNOWN;
+ goto cleanup2;
+ }
+
+ PAM_LOG("Done getpwnam()");
+
+ /* Get a TGT */
+ memset(&creds, 0, sizeof(krb5_creds));
+ krbret = krb5_get_init_creds_password(pam_context, &creds, princ,
+ pass, NULL, pamh, 0, NULL, &opts);
+ if (krbret != 0) {
+ PAM_VERBOSE_ERROR("Kerberos 5 error");
+ PAM_LOG("Error krb5_get_init_creds_password(): %s",
+ krb5_get_err_text(pam_context, krbret));
+ retval = PAM_AUTH_ERR;
+ goto cleanup2;
+ }
+
+ PAM_LOG("Got TGT");
+
+ /* Generate a temporary cache */
+ krbret = krb5_cc_gen_new(pam_context, &krb5_mcc_ops, &ccache);
+ if (krbret != 0) {
+ PAM_VERBOSE_ERROR("Kerberos 5 error");
+ PAM_LOG("Error krb5_cc_gen_new(): %s",
+ krb5_get_err_text(pam_context, krbret));
+ retval = PAM_SERVICE_ERR;
+ goto cleanup;
+ }
+ krbret = krb5_cc_initialize(pam_context, ccache, princ);
+ if (krbret != 0) {
+ PAM_VERBOSE_ERROR("Kerberos 5 error");
+ PAM_LOG("Error krb5_cc_initialize(): %s",
+ krb5_get_err_text(pam_context, krbret));
+ retval = PAM_SERVICE_ERR;
+ goto cleanup;
+ }
+ krbret = krb5_cc_store_cred(pam_context, ccache, &creds);
+ if (krbret != 0) {
+ PAM_VERBOSE_ERROR("Kerberos 5 error");
+ PAM_LOG("Error krb5_cc_store_cred(): %s",
+ krb5_get_err_text(pam_context, krbret));
+ krb5_cc_destroy(pam_context, ccache);
+ retval = PAM_SERVICE_ERR;
+ goto cleanup;
+ }
+
+ PAM_LOG("Credentials stashed");
+
+ /* Verify them */
+ if ((srvdup = strdup(service)) == NULL) {
+ retval = PAM_BUF_ERR;
+ goto cleanup;
+ }
+ krbret = verify_krb_v5_tgt(pam_context, ccache, srvdup,
+ openpam_get_option(pamh, PAM_OPT_DEBUG) ? 1 : 0);
+ free(srvdup);
+ if (krbret == -1) {
+ PAM_VERBOSE_ERROR("Kerberos 5 error");
+ krb5_cc_destroy(pam_context, ccache);
+ retval = PAM_AUTH_ERR;
+ goto cleanup;
+ }
+
+ PAM_LOG("Credentials stash verified");
+
+ retval = pam_get_data(pamh, "ccache", &ccache_data);
+ if (retval == PAM_SUCCESS) {
+ krb5_cc_destroy(pam_context, ccache);
+ PAM_VERBOSE_ERROR("Kerberos 5 error");
+ retval = PAM_AUTH_ERR;
+ goto cleanup;
+ }
+
+ PAM_LOG("Credentials stash not pre-existing");
+
+ asprintf(&ccache_name, "%s:%s", krb5_cc_get_type(pam_context,
+ ccache), krb5_cc_get_name(pam_context, ccache));
+ if (ccache_name == NULL) {
+ PAM_VERBOSE_ERROR("Kerberos 5 error");
+ retval = PAM_BUF_ERR;
+ goto cleanup;
+ }
+ retval = pam_set_data(pamh, "ccache", ccache_name, cleanup_cache);
+ if (retval != 0) {
+ krb5_cc_destroy(pam_context, ccache);
+ PAM_VERBOSE_ERROR("Kerberos 5 error");
+ retval = PAM_SERVICE_ERR;
+ goto cleanup;
+ }
+
+ PAM_LOG("Credentials stash saved");
+
+cleanup:
+ krb5_free_cred_contents(pam_context, &creds);
+ PAM_LOG("Done cleanup");
+cleanup2:
+ krb5_free_principal(pam_context, princ);
+ PAM_LOG("Done cleanup2");
+cleanup3:
+ if (princ_name)
+ free(princ_name);
+
+ krb5_free_context(pam_context);
+
+ PAM_LOG("Done cleanup3");
+
+ if (retval != PAM_SUCCESS)
+ PAM_VERBOSE_ERROR("Kerberos 5 refuses you");
+
+ return (retval);
+}
+
+PAM_EXTERN int
+pam_sm_setcred(pam_handle_t *pamh, int flags,
+ int argc __unused, const char *argv[] __unused)
+{
+#ifdef _FREEFALL_CONFIG
+ return (PAM_SUCCESS);
+#else
+
+ krb5_error_code krbret;
+ krb5_context pam_context;
+ krb5_principal princ;
+ krb5_creds creds;
+ krb5_ccache ccache_temp, ccache_perm;
+ krb5_cc_cursor cursor;
+ struct passwd *pwd = NULL;
+ int retval;
+ const char *cache_name, *q;
+ const void *user;
+ void *cache_data;
+ char *cache_name_buf = NULL, *p;
+
+ uid_t euid;
+ gid_t egid;
+
+ if (flags & PAM_DELETE_CRED)
+ return (PAM_SUCCESS);
+
+ if (flags & PAM_REFRESH_CRED)
+ return (PAM_SUCCESS);
+
+ if (flags & PAM_REINITIALIZE_CRED)
+ return (PAM_SUCCESS);
+
+ if (!(flags & PAM_ESTABLISH_CRED))
+ return (PAM_SERVICE_ERR);
+
+ /* If a persistent cache isn't desired, stop now. */
+ if (openpam_get_option(pamh, PAM_OPT_NO_CCACHE))
+ return (PAM_SUCCESS);
+
+ PAM_LOG("Establishing credentials");
+
+ /* Get username */
+ retval = pam_get_item(pamh, PAM_USER, &user);
+ if (retval != PAM_SUCCESS)
+ return (retval);
+
+ PAM_LOG("Got user: %s", (const char *)user);
+
+ krbret = krb5_init_context(&pam_context);
+ if (krbret != 0) {
+ PAM_LOG("Error krb5_init_context() failed");
+ return (PAM_SERVICE_ERR);
+ }
+
+ PAM_LOG("Context initialised");
+
+ euid = geteuid(); /* Usually 0 */
+ egid = getegid();
+
+ PAM_LOG("Got euid, egid: %d %d", euid, egid);
+
+ /* Retrieve the temporary cache */
+ retval = pam_get_data(pamh, "ccache", &cache_data);
+ if (retval != PAM_SUCCESS) {
+ retval = PAM_CRED_UNAVAIL;
+ goto cleanup3;
+ }
+ krbret = krb5_cc_resolve(pam_context, cache_data, &ccache_temp);
+ if (krbret != 0) {
+ PAM_LOG("Error krb5_cc_resolve(\"%s\"): %s", (const char *)cache_data,
+ krb5_get_err_text(pam_context, krbret));
+ retval = PAM_SERVICE_ERR;
+ goto cleanup3;
+ }
+
+ /* Get the uid. This should exist. */
+ pwd = getpwnam(user);
+ if (pwd == NULL) {
+ retval = PAM_USER_UNKNOWN;
+ goto cleanup3;
+ }
+
+ PAM_LOG("Done getpwnam()");
+
+ /* Avoid following a symlink as root */
+ if (setegid(pwd->pw_gid)) {
+ retval = PAM_SERVICE_ERR;
+ goto cleanup3;
+ }
+ if (seteuid(pwd->pw_uid)) {
+ retval = PAM_SERVICE_ERR;
+ goto cleanup3;
+ }
+
+ PAM_LOG("Done setegid() & seteuid()");
+
+ /* Get the cache name */
+ cache_name = openpam_get_option(pamh, PAM_OPT_CCACHE);
+ if (cache_name == NULL) {
+ asprintf(&cache_name_buf, "FILE:/tmp/krb5cc_%d", pwd->pw_uid);
+ cache_name = cache_name_buf;
+ }
+
+ p = calloc(PATH_MAX + 16, sizeof(char));
+ q = cache_name;
+
+ if (p == NULL) {
+ PAM_LOG("Error malloc(): failure");
+ retval = PAM_BUF_ERR;
+ goto cleanup3;
+ }
+ cache_name = p;
+
+ /* convert %u and %p */
+ while (*q) {
+ if (*q == '%') {
+ q++;
+ if (*q == 'u') {
+ sprintf(p, "%d", pwd->pw_uid);
+ p += strlen(p);
+ }
+ else if (*q == 'p') {
+ sprintf(p, "%d", getpid());
+ p += strlen(p);
+ }
+ else {
+ /* Not a special token */
+ *p++ = '%';
+ q--;
+ }
+ q++;
+ }
+ else {
+ *p++ = *q++;
+ }
+ }
+
+ PAM_LOG("Got cache_name: %s", cache_name);
+
+ /* Initialize the new ccache */
+ krbret = krb5_cc_get_principal(pam_context, ccache_temp, &princ);
+ if (krbret != 0) {
+ PAM_LOG("Error krb5_cc_get_principal(): %s",
+ krb5_get_err_text(pam_context, krbret));
+ retval = PAM_SERVICE_ERR;
+ goto cleanup3;
+ }
+ krbret = krb5_cc_resolve(pam_context, cache_name, &ccache_perm);
+ if (krbret != 0) {
+ PAM_LOG("Error krb5_cc_resolve(): %s",
+ krb5_get_err_text(pam_context, krbret));
+ retval = PAM_SERVICE_ERR;
+ goto cleanup2;
+ }
+ krbret = krb5_cc_initialize(pam_context, ccache_perm, princ);
+ if (krbret != 0) {
+ PAM_LOG("Error krb5_cc_initialize(): %s",
+ krb5_get_err_text(pam_context, krbret));
+ retval = PAM_SERVICE_ERR;
+ goto cleanup2;
+ }
+
+ PAM_LOG("Cache initialised");
+
+ /* Prepare for iteration over creds */
+ krbret = krb5_cc_start_seq_get(pam_context, ccache_temp, &cursor);
+ if (krbret != 0) {
+ PAM_LOG("Error krb5_cc_start_seq_get(): %s",
+ krb5_get_err_text(pam_context, krbret));
+ krb5_cc_destroy(pam_context, ccache_perm);
+ retval = PAM_SERVICE_ERR;
+ goto cleanup2;
+ }
+
+ PAM_LOG("Prepared for iteration");
+
+ /* Copy the creds (should be two of them) */
+ while ((krbret = krb5_cc_next_cred(pam_context, ccache_temp,
+ &cursor, &creds) == 0)) {
+ krbret = krb5_cc_store_cred(pam_context, ccache_perm, &creds);
+ if (krbret != 0) {
+ PAM_LOG("Error krb5_cc_store_cred(): %s",
+ krb5_get_err_text(pam_context, krbret));
+ krb5_cc_destroy(pam_context, ccache_perm);
+ krb5_free_cred_contents(pam_context, &creds);
+ retval = PAM_SERVICE_ERR;
+ goto cleanup2;
+ }
+ krb5_free_cred_contents(pam_context, &creds);
+ PAM_LOG("Iteration");
+ }
+ krb5_cc_end_seq_get(pam_context, ccache_temp, &cursor);
+
+ PAM_LOG("Done iterating");
+
+ if (strstr(cache_name, "FILE:") == cache_name) {
+ if (chown(&cache_name[5], pwd->pw_uid, pwd->pw_gid) == -1) {
+ PAM_LOG("Error chown(): %s", strerror(errno));
+ krb5_cc_destroy(pam_context, ccache_perm);
+ retval = PAM_SERVICE_ERR;
+ goto cleanup2;
+ }
+ PAM_LOG("Done chown()");
+
+ if (chmod(&cache_name[5], (S_IRUSR | S_IWUSR)) == -1) {
+ PAM_LOG("Error chmod(): %s", strerror(errno));
+ krb5_cc_destroy(pam_context, ccache_perm);
+ retval = PAM_SERVICE_ERR;
+ goto cleanup2;
+ }
+ PAM_LOG("Done chmod()");
+ }
+
+ krb5_cc_close(pam_context, ccache_perm);
+
+ PAM_LOG("Cache closed");
+
+ retval = pam_setenv(pamh, "KRB5CCNAME", cache_name, 1);
+ if (retval != PAM_SUCCESS) {
+ PAM_LOG("Error pam_setenv(): %s", pam_strerror(pamh, retval));
+ krb5_cc_destroy(pam_context, ccache_perm);
+ retval = PAM_SERVICE_ERR;
+ goto cleanup2;
+ }
+
+ PAM_LOG("Environment done: KRB5CCNAME=%s", cache_name);
+
+cleanup2:
+ krb5_free_principal(pam_context, princ);
+ PAM_LOG("Done cleanup2");
+cleanup3:
+ krb5_free_context(pam_context);
+ PAM_LOG("Done cleanup3");
+
+ seteuid(euid);
+ setegid(egid);
+
+ PAM_LOG("Done seteuid() & setegid()");
+
+ if (cache_name_buf != NULL)
+ free(cache_name_buf);
+
+ return (retval);
+#endif
+}
+
+/*
+ * account management
+ */
+PAM_EXTERN int
+pam_sm_acct_mgmt(pam_handle_t *pamh, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+ krb5_error_code krbret;
+ krb5_context pam_context;
+ krb5_ccache ccache;
+ krb5_principal princ;
+ int retval;
+ const void *user;
+ void *ccache_name;
+
+ retval = pam_get_item(pamh, PAM_USER, &user);
+ if (retval != PAM_SUCCESS)
+ return (retval);
+
+ PAM_LOG("Got user: %s", (const char *)user);
+
+ retval = pam_get_data(pamh, "ccache", &ccache_name);
+ if (retval != PAM_SUCCESS)
+ return (PAM_SUCCESS);
+
+ PAM_LOG("Got credentials");
+
+ krbret = krb5_init_context(&pam_context);
+ if (krbret != 0) {
+ PAM_LOG("Error krb5_init_context() failed");
+ return (PAM_PERM_DENIED);
+ }
+
+ PAM_LOG("Context initialised");
+
+ krbret = krb5_cc_resolve(pam_context, (const char *)ccache_name, &ccache);
+ if (krbret != 0) {
+ PAM_LOG("Error krb5_cc_resolve(\"%s\"): %s", (const char *)ccache_name,
+ krb5_get_err_text(pam_context, krbret));
+ krb5_free_context(pam_context);
+ return (PAM_PERM_DENIED);
+ }
+
+ PAM_LOG("Got ccache %s", (const char *)ccache_name);
+
+
+ krbret = krb5_cc_get_principal(pam_context, ccache, &princ);
+ if (krbret != 0) {
+ PAM_LOG("Error krb5_cc_get_principal(): %s",
+ krb5_get_err_text(pam_context, krbret));
+ retval = PAM_PERM_DENIED;;
+ goto cleanup;
+ }
+
+ PAM_LOG("Got principal");
+
+ if (krb5_kuserok(pam_context, princ, (const char *)user))
+ retval = PAM_SUCCESS;
+ else
+ retval = PAM_PERM_DENIED;
+ krb5_free_principal(pam_context, princ);
+
+ PAM_LOG("Done kuserok()");
+
+cleanup:
+ krb5_free_context(pam_context);
+ PAM_LOG("Done cleanup");
+
+ return (retval);
+
+}
+
+/*
+ * password management
+ */
+PAM_EXTERN int
+pam_sm_chauthtok(pam_handle_t *pamh, int flags,
+ int argc __unused, const char *argv[] __unused)
+{
+ krb5_error_code krbret;
+ krb5_context pam_context;
+ krb5_creds creds;
+ krb5_principal princ;
+ krb5_get_init_creds_opt opts;
+ krb5_data result_code_string, result_string;
+ int result_code, retval;
+ const char *pass;
+ const void *user;
+ char *princ_name, *passdup;
+
+ if (!(flags & PAM_UPDATE_AUTHTOK))
+ return (PAM_AUTHTOK_ERR);
+
+ retval = pam_get_item(pamh, PAM_USER, &user);
+ if (retval != PAM_SUCCESS)
+ return (retval);
+
+ PAM_LOG("Got user: %s", (const char *)user);
+
+ krbret = krb5_init_context(&pam_context);
+ if (krbret != 0) {
+ PAM_LOG("Error krb5_init_context() failed");
+ return (PAM_SERVICE_ERR);
+ }
+
+ PAM_LOG("Context initialised");
+
+ krb5_get_init_creds_opt_init(&opts);
+
+ PAM_LOG("Credentials options initialised");
+
+ /* Get principal name */
+ krbret = krb5_parse_name(pam_context, (const char *)user, &princ);
+ if (krbret != 0) {
+ PAM_LOG("Error krb5_parse_name(): %s",
+ krb5_get_err_text(pam_context, krbret));
+ retval = PAM_USER_UNKNOWN;
+ goto cleanup3;
+ }
+
+ /* Now convert the principal name into something human readable */
+ princ_name = NULL;
+ krbret = krb5_unparse_name(pam_context, princ, &princ_name);
+ if (krbret != 0) {
+ PAM_LOG("Error krb5_unparse_name(): %s",
+ krb5_get_err_text(pam_context, krbret));
+ retval = PAM_SERVICE_ERR;
+ goto cleanup2;
+ }
+
+ PAM_LOG("Got principal: %s", princ_name);
+
+ /* Get password */
+ retval = pam_get_authtok(pamh, PAM_OLDAUTHTOK, &pass, PASSWORD_PROMPT);
+ if (retval != PAM_SUCCESS)
+ goto cleanup2;
+
+ PAM_LOG("Got password");
+
+ memset(&creds, 0, sizeof(krb5_creds));
+ krbret = krb5_get_init_creds_password(pam_context, &creds, princ,
+ pass, NULL, pamh, 0, "kadmin/changepw", &opts);
+ if (krbret != 0) {
+ PAM_LOG("Error krb5_get_init_creds_password(): %s",
+ krb5_get_err_text(pam_context, krbret));
+ retval = PAM_AUTH_ERR;
+ goto cleanup2;
+ }
+
+ PAM_LOG("Credentials established");
+
+ /* Now get the new password */
+ for (;;) {
+ retval = pam_get_authtok(pamh,
+ PAM_AUTHTOK, &pass, NEW_PASSWORD_PROMPT);
+ if (retval != PAM_TRY_AGAIN)
+ break;
+ pam_error(pamh, "Mismatch; try again, EOF to quit.");
+ }
+ if (retval != PAM_SUCCESS)
+ goto cleanup;
+
+ PAM_LOG("Got new password");
+
+ /* Change it */
+ if ((passdup = strdup(pass)) == NULL) {
+ retval = PAM_BUF_ERR;
+ goto cleanup;
+ }
+ krbret = krb5_change_password(pam_context, &creds, passdup,
+ &result_code, &result_code_string, &result_string);
+ free(passdup);
+ if (krbret != 0) {
+ PAM_LOG("Error krb5_change_password(): %s",
+ krb5_get_err_text(pam_context, krbret));
+ retval = PAM_AUTHTOK_ERR;
+ goto cleanup;
+ }
+ if (result_code) {
+ PAM_LOG("Error krb5_change_password(): (result_code)");
+ retval = PAM_AUTHTOK_ERR;
+ goto cleanup;
+ }
+
+ PAM_LOG("Password changed");
+
+ if (result_string.data)
+ free(result_string.data);
+ if (result_code_string.data)
+ free(result_code_string.data);
+
+cleanup:
+ krb5_free_cred_contents(pam_context, &creds);
+ PAM_LOG("Done cleanup");
+cleanup2:
+ krb5_free_principal(pam_context, princ);
+ PAM_LOG("Done cleanup2");
+cleanup3:
+ if (princ_name)
+ free(princ_name);
+
+ krb5_free_context(pam_context);
+
+ PAM_LOG("Done cleanup3");
+
+ return (retval);
+}
+
+PAM_MODULE_ENTRY("pam_krb5");
+
+/*
+ * This routine with some modification is from the MIT V5B6 appl/bsd/login.c
+ * Modified by Sam Hartman <hartmans@mit.edu> to support PAM services
+ * for Debian.
+ *
+ * Verify the Kerberos ticket-granting ticket just retrieved for the
+ * user. If the Kerberos server doesn't respond, assume the user is
+ * trying to fake us out (since we DID just get a TGT from what is
+ * supposedly our KDC). If the host/<host> service is unknown (i.e.,
+ * the local keytab doesn't have it), and we cannot find another
+ * service we do have, let her in.
+ *
+ * Returns 1 for confirmation, -1 for failure, 0 for uncertainty.
+ */
+/* ARGSUSED */
+static int
+verify_krb_v5_tgt(krb5_context context, krb5_ccache ccache,
+ char *pam_service, int debug)
+{
+ krb5_error_code retval;
+ krb5_principal princ;
+ krb5_keyblock *keyblock;
+ krb5_data packet;
+ krb5_auth_context auth_context;
+ char phost[BUFSIZ];
+ const char *services[3], **service;
+
+ packet.data = 0;
+
+ /* If possible we want to try and verify the ticket we have
+ * received against a keytab. We will try multiple service
+ * principals, including at least the host principal and the PAM
+ * service principal. The host principal is preferred because access
+ * to that key is generally sufficient to compromise root, while the
+ * service key for this PAM service may be less carefully guarded.
+ * It is important to check the keytab first before the KDC so we do
+ * not get spoofed by a fake KDC.
+ */
+ services[0] = "host";
+ services[1] = pam_service;
+ services[2] = NULL;
+ keyblock = 0;
+ retval = -1;
+ for (service = &services[0]; *service != NULL; service++) {
+ retval = krb5_sname_to_principal(context, NULL, *service,
+ KRB5_NT_SRV_HST, &princ);
+ if (retval != 0) {
+ if (debug)
+ syslog(LOG_DEBUG,
+ "pam_krb5: verify_krb_v5_tgt(): %s: %s",
+ "krb5_sname_to_principal()",
+ krb5_get_err_text(context, retval));
+ return -1;
+ }
+
+ /* Extract the name directly. */
+ strncpy(phost, compat_princ_component(context, princ, 1),
+ BUFSIZ);
+ phost[BUFSIZ - 1] = '\0';
+
+ /*
+ * Do we have service/<host> keys?
+ * (use default/configured keytab, kvno IGNORE_VNO to get the
+ * first match, and ignore enctype.)
+ */
+ retval = krb5_kt_read_service_key(context, NULL, princ, 0, 0,
+ &keyblock);
+ if (retval != 0)
+ continue;
+ break;
+ }
+ if (retval != 0) { /* failed to find key */
+ /* Keytab or service key does not exist */
+ if (debug)
+ syslog(LOG_DEBUG,
+ "pam_krb5: verify_krb_v5_tgt(): %s: %s",
+ "krb5_kt_read_service_key()",
+ krb5_get_err_text(context, retval));
+ retval = 0;
+ goto cleanup;
+ }
+ if (keyblock)
+ krb5_free_keyblock(context, keyblock);
+
+ /* Talk to the kdc and construct the ticket. */
+ auth_context = NULL;
+ retval = krb5_mk_req(context, &auth_context, 0, *service, phost,
+ NULL, ccache, &packet);
+ if (auth_context) {
+ krb5_auth_con_free(context, auth_context);
+ auth_context = NULL; /* setup for rd_req */
+ }
+ if (retval) {
+ if (debug)
+ syslog(LOG_DEBUG,
+ "pam_krb5: verify_krb_v5_tgt(): %s: %s",
+ "krb5_mk_req()",
+ krb5_get_err_text(context, retval));
+ retval = -1;
+ goto cleanup;
+ }
+
+ /* Try to use the ticket. */
+ retval = krb5_rd_req(context, &auth_context, &packet, princ, NULL,
+ NULL, NULL);
+ if (retval) {
+ if (debug)
+ syslog(LOG_DEBUG,
+ "pam_krb5: verify_krb_v5_tgt(): %s: %s",
+ "krb5_rd_req()",
+ krb5_get_err_text(context, retval));
+ retval = -1;
+ }
+ else
+ retval = 1;
+
+cleanup:
+ if (packet.data)
+ compat_free_data_contents(context, &packet);
+ krb5_free_principal(context, princ);
+ return retval;
+}
+
+/* Free the memory for cache_name. Called by pam_end() */
+/* ARGSUSED */
+static void
+cleanup_cache(pam_handle_t *pamh __unused, void *data, int pam_end_status __unused)
+{
+ krb5_context pam_context;
+ krb5_ccache ccache;
+ krb5_error_code krbret;
+
+ if (krb5_init_context(&pam_context))
+ return;
+
+ krbret = krb5_cc_resolve(pam_context, data, &ccache);
+ if (krbret == 0)
+ krb5_cc_destroy(pam_context, ccache);
+ krb5_free_context(pam_context);
+ free(data);
+}
+
+#ifdef COMPAT_HEIMDAL
+#ifdef COMPAT_MIT
+#error This cannot be MIT and Heimdal compatible!
+#endif
+#endif
+
+#ifndef COMPAT_HEIMDAL
+#ifndef COMPAT_MIT
+#error One of COMPAT_MIT and COMPAT_HEIMDAL must be specified!
+#endif
+#endif
+
+#ifdef COMPAT_HEIMDAL
+/* ARGSUSED */
+static const char *
+compat_princ_component(krb5_context context __unused, krb5_principal princ, int n)
+{
+ return princ->name.name_string.val[n];
+}
+
+/* ARGSUSED */
+static void
+compat_free_data_contents(krb5_context context __unused, krb5_data * data)
+{
+ krb5_xfree(data->data);
+}
+#endif
+
+#ifdef COMPAT_MIT
+static const char *
+compat_princ_component(krb5_context context, krb5_principal princ, int n)
+{
+ return krb5_princ_component(context, princ, n)->data;
+}
+
+static void
+compat_free_data_contents(krb5_context context, krb5_data * data)
+{
+ krb5_free_data_contents(context, data);
+}
+#endif
diff --git a/lib/libpam/modules/pam_ksu/Makefile b/lib/libpam/modules/pam_ksu/Makefile
new file mode 100644
index 0000000..1cb1999
--- /dev/null
+++ b/lib/libpam/modules/pam_ksu/Makefile
@@ -0,0 +1,34 @@
+# Copyright 2002 FreeBSD, 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$
+
+LIB= pam_ksu
+SRCS= pam_ksu.c
+MAN= pam_ksu.8
+
+DPADD= ${LIBKRB5} ${LIBASN1} ${LIBROKEN} ${LIBCOM_ERR} ${LIBCRYPT} ${LIBCRYPTO}
+LDADD= -lkrb5 -lasn1 -lroken -lcom_err -lcrypt -lcrypto
+
+.include <bsd.lib.mk>
diff --git a/lib/libpam/modules/pam_ksu/pam_ksu.8 b/lib/libpam/modules/pam_ksu/pam_ksu.8
new file mode 100644
index 0000000..614dc9e
--- /dev/null
+++ b/lib/libpam/modules/pam_ksu/pam_ksu.8
@@ -0,0 +1,122 @@
+.\" Copyright (c) 2001 Mark R V Murray
+.\" All rights reserved.
+.\" Copyright (c) 2001 Networks Associates Technology, Inc.
+.\" All rights reserved.
+.\"
+.\" This software was developed for the FreeBSD Project by ThinkSec AS 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING 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 15, 2002
+.Dt PAM_KSU 8
+.Os
+.Sh NAME
+.Nm pam_ksu
+.Nd Kerberos 5 SU PAM module
+.Sh SYNOPSIS
+.Op Ar service-name
+.Ar module-type
+.Ar control-flag
+.Pa pam_ksu
+.Op Ar options
+.Sh DESCRIPTION
+The Kerberos 5 SU authentication service module for PAM,
+.Nm
+for only one PAM category: authentication.
+In terms of the
+.Ar module-type
+parameter, this is the
+.Dq Li auth
+feature.
+The module is specifically designed to be used with the
+.Xr su 1
+utility.
+.\" It also provides a null function for session management.
+.Ss Kerberos 5 SU Authentication Module
+The Kerberos 5 SU authentication component provides functions to verify
+the identity of a user
+.Pq Fn pam_sm_authenticate ,
+and determine whether or not the user is authorized to obtain the
+privileges of the target account.
+If the target account is
+.Dq root ,
+then the Kerberos 5 principal used
+for authentication and authorization will be the
+.Dq root
+instance of
+the current user, e.g.\&
+.Dq Li user/root@REAL.M .
+Otherwise, the principal will simply be the current user's default
+principal, e.g.\&
+.Dq Li user@REAL.M .
+.Pp
+The user is prompted for a password if necessary.
+Authorization is performed
+by comparing the Kerberos 5 principal with those listed in the
+.Pa .k5login
+file in the target account's home directory
+(e.g.\&
+.Pa /root/.k5login
+for root).
+.Pp
+The following options may be passed to the authentication module:
+.Bl -tag -width ".Cm use_first_pass"
+.It Cm debug
+.Xr syslog 3
+debugging information at
+.Dv LOG_DEBUG
+level.
+.It Cm use_first_pass
+If the authentication module
+is not the first in the stack,
+and a previous module
+obtained the user's password,
+that password is used
+to authenticate the user.
+If this fails,
+the authentication module returns failure
+without prompting the user for a password.
+This option has no effect
+if the authentication module
+is the first in the stack,
+or if no previous modules
+obtained the user's password.
+.It Cm try_first_pass
+This option is similar to the
+.Cm use_first_pass
+option,
+except that if the previously obtained password fails,
+the user is prompted for another password.
+.El
+.Sh SEE ALSO
+.Xr su 1 ,
+.Xr syslog 3 ,
+.Xr pam.conf 5 ,
+.Xr pam 8
diff --git a/lib/libpam/modules/pam_ksu/pam_ksu.c b/lib/libpam/modules/pam_ksu/pam_ksu.c
new file mode 100644
index 0000000..80a395a
--- /dev/null
+++ b/lib/libpam/modules/pam_ksu/pam_ksu.c
@@ -0,0 +1,256 @@
+/*-
+ * Copyright (c) 2002 Jacques A. Vidrine <nectar@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 <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <krb5.h>
+
+#define PAM_SM_AUTH
+#define PAM_SM_CRED
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <security/pam_mod_misc.h>
+
+static const char superuser[] = "root";
+
+static long get_su_principal(krb5_context, const char *, const char *,
+ char **, krb5_principal *);
+static int auth_krb5(pam_handle_t *, krb5_context, const char *,
+ krb5_principal);
+
+PAM_EXTERN int
+pam_sm_authenticate(pam_handle_t *pamh, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+ krb5_context context;
+ krb5_principal su_principal;
+ const char *user;
+ const void *ruser;
+ char *su_principal_name;
+ long rv;
+ int pamret;
+
+ pamret = pam_get_user(pamh, &user, NULL);
+ if (pamret != PAM_SUCCESS)
+ return (pamret);
+ PAM_LOG("Got user: %s", user);
+ pamret = pam_get_item(pamh, PAM_RUSER, &ruser);
+ if (pamret != PAM_SUCCESS)
+ return (pamret);
+ PAM_LOG("Got ruser: %s", (const char *)ruser);
+ rv = krb5_init_context(&context);
+ if (rv != 0) {
+ PAM_LOG("krb5_init_context failed: %s",
+ krb5_get_err_text(context, rv));
+ return (PAM_SERVICE_ERR);
+ }
+ rv = get_su_principal(context, user, ruser, &su_principal_name, &su_principal);
+ if (rv != 0)
+ return (PAM_AUTH_ERR);
+ PAM_LOG("kuserok: %s -> %s", su_principal_name, user);
+ rv = krb5_kuserok(context, su_principal, user);
+ pamret = rv ? auth_krb5(pamh, context, su_principal_name, su_principal) : PAM_AUTH_ERR;
+ free(su_principal_name);
+ krb5_free_principal(context, su_principal);
+ krb5_free_context(context);
+ return (pamret);
+}
+
+PAM_EXTERN int
+pam_sm_setcred(pam_handle_t *pamh __unused, int flags __unused,
+ int ac __unused, const char *av[] __unused)
+{
+
+ return (PAM_SUCCESS);
+}
+
+/* Authenticate using Kerberos 5.
+ * pamh -- The PAM handle.
+ * context -- An initialized krb5_context.
+ * su_principal_name -- The target principal name, used only for password prompts.
+ * If NULL, the password prompts will not include a principal
+ * name.
+ * su_principal -- The target krb5_principal.
+ * Note that a valid keytab in the default location with a host entry
+ * must be available, and that the PAM application must have sufficient
+ * privileges to access it.
+ * Returns PAM_SUCCESS if authentication was successful, or an appropriate
+ * PAM error code if it was not.
+ */
+static int
+auth_krb5(pam_handle_t *pamh, krb5_context context, const char *su_principal_name,
+ krb5_principal su_principal)
+{
+ krb5_creds creds;
+ krb5_get_init_creds_opt gic_opt;
+ krb5_verify_init_creds_opt vic_opt;
+ const char *pass;
+ char *prompt;
+ long rv;
+ int pamret;
+
+ prompt = NULL;
+ krb5_get_init_creds_opt_init(&gic_opt);
+ krb5_verify_init_creds_opt_init(&vic_opt);
+ if (su_principal_name != NULL)
+ (void)asprintf(&prompt, "Password for %s:", su_principal_name);
+ else
+ (void)asprintf(&prompt, "Password:");
+ if (prompt == NULL)
+ return (PAM_BUF_ERR);
+ pass = NULL;
+ pamret = pam_get_authtok(pamh, PAM_AUTHTOK, &pass, prompt);
+ free(prompt);
+ if (pamret != PAM_SUCCESS)
+ return (pamret);
+ rv = krb5_get_init_creds_password(context, &creds, su_principal,
+ pass, NULL, NULL, 0, NULL, &gic_opt);
+ if (rv != 0) {
+ PAM_LOG("krb5_get_init_creds_password: %s",
+ krb5_get_err_text(context, rv));
+ return (PAM_AUTH_ERR);
+ }
+ krb5_verify_init_creds_opt_set_ap_req_nofail(&vic_opt, 1);
+ rv = krb5_verify_init_creds(context, &creds, NULL, NULL, NULL,
+ &vic_opt);
+ krb5_free_cred_contents(context, &creds);
+ if (rv != 0) {
+ PAM_LOG("krb5_verify_init_creds: %s",
+ krb5_get_err_text(context, rv));
+ return (PAM_AUTH_ERR);
+ }
+ return (PAM_SUCCESS);
+}
+
+/* Determine the target principal given the current user and the target user.
+ * context -- An initialized krb5_context.
+ * target_user -- The target username.
+ * current_user -- The current username.
+ * su_principal_name -- (out) The target principal name.
+ * su_principal -- (out) The target krb5_principal.
+ * When the target user is `root', the target principal will be a `root
+ * instance', e.g. `luser/root@REA.LM'. Otherwise, the target principal
+ * will simply be the current user's default principal name. Note that
+ * in any case, if KRB5CCNAME is set and a credentials cache exists, the
+ * principal name found there will be the `starting point', rather than
+ * the ruser parameter.
+ *
+ * Returns 0 for success, or a com_err error code on failure.
+ */
+static long
+get_su_principal(krb5_context context, const char *target_user, const char *current_user,
+ char **su_principal_name, krb5_principal *su_principal)
+{
+ krb5_principal default_principal;
+ krb5_ccache ccache;
+ char *principal_name, *ccname, *p;
+ long rv;
+ uid_t euid, ruid;
+
+ *su_principal = NULL;
+ default_principal = NULL;
+ /* Unless KRB5CCNAME was explicitly set, we won't really be able
+ * to look at the credentials cache since krb5_cc_default will
+ * look at getuid().
+ */
+ ruid = getuid();
+ euid = geteuid();
+ rv = seteuid(ruid);
+ if (rv != 0)
+ return (errno);
+ p = getenv("KRB5CCNAME");
+ if (p != NULL)
+ ccname = strdup(p);
+ else
+ (void)asprintf(&ccname, "%s%lu", KRB5_DEFAULT_CCROOT, (unsigned long)ruid);
+ if (ccname == NULL)
+ return (errno);
+ rv = krb5_cc_resolve(context, ccname, &ccache);
+ free(ccname);
+ if (rv == 0) {
+ rv = krb5_cc_get_principal(context, ccache, &default_principal);
+ krb5_cc_close(context, ccache);
+ if (rv != 0)
+ default_principal = NULL; /* just to be safe */
+ }
+ rv = seteuid(euid);
+ if (rv != 0)
+ return (errno);
+ if (default_principal == NULL) {
+ rv = krb5_make_principal(context, &default_principal, NULL, current_user, NULL);
+ if (rv != 0) {
+ PAM_LOG("Could not determine default principal name.");
+ return (rv);
+ }
+ }
+ /* Now that we have some principal, if the target account is
+ * `root', then transform it into a `root' instance, e.g.
+ * `user@REA.LM' -> `user/root@REA.LM'.
+ */
+ rv = krb5_unparse_name(context, default_principal, &principal_name);
+ krb5_free_principal(context, default_principal);
+ if (rv != 0) {
+ PAM_LOG("krb5_unparse_name: %s",
+ krb5_get_err_text(context, rv));
+ return (rv);
+ }
+ PAM_LOG("Default principal name: %s", principal_name);
+ if (strcmp(target_user, superuser) == 0) {
+ p = strrchr(principal_name, '@');
+ if (p == NULL) {
+ PAM_LOG("malformed principal name `%s'", principal_name);
+ free(principal_name);
+ return (rv);
+ }
+ *p++ = '\0';
+ *su_principal_name = NULL;
+ (void)asprintf(su_principal_name, "%s/%s@%s", principal_name, superuser, p);
+ free(principal_name);
+ } else
+ *su_principal_name = principal_name;
+
+ if (*su_principal_name == NULL)
+ return (errno);
+ rv = krb5_parse_name(context, *su_principal_name, &default_principal);
+ if (rv != 0) {
+ PAM_LOG("krb5_parse_name `%s': %s", *su_principal_name,
+ krb5_get_err_text(context, rv));
+ free(*su_principal_name);
+ return (rv);
+ }
+ PAM_LOG("Target principal name: %s", *su_principal_name);
+ *su_principal = default_principal;
+ return (0);
+}
+
+PAM_MODULE_ENTRY("pam_ksu");
diff --git a/lib/libpam/modules/pam_lastlog/Makefile b/lib/libpam/modules/pam_lastlog/Makefile
new file mode 100644
index 0000000..f0b96c4
--- /dev/null
+++ b/lib/libpam/modules/pam_lastlog/Makefile
@@ -0,0 +1,34 @@
+# Copyright 2001 Mark R V Murray
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+
+LIB= pam_lastlog
+SRCS= pam_lastlog.c
+MAN= pam_lastlog.8
+
+DPADD= ${LIBUTIL}
+LDADD= -lutil
+
+.include <bsd.lib.mk>
diff --git a/lib/libpam/modules/pam_lastlog/pam_lastlog.8 b/lib/libpam/modules/pam_lastlog/pam_lastlog.8
new file mode 100644
index 0000000..9fc7e45
--- /dev/null
+++ b/lib/libpam/modules/pam_lastlog/pam_lastlog.8
@@ -0,0 +1,106 @@
+.\" Copyright (c) 2001 Mark R V Murray
+.\" All rights reserved.
+.\" Copyright (c) 2001 Networks Associates Technology, Inc.
+.\" All rights reserved.
+.\"
+.\" Portions of this software were developed for the FreeBSD Project by
+.\" ThinkSec AS 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING 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, 2002
+.Dt PAM_LASTLOG 8
+.Os
+.Sh NAME
+.Nm pam_lastlog
+.Nd login accounting PAM module
+.Sh SYNOPSIS
+.Op Ar service-name
+.Ar module-type
+.Ar control-flag
+.Pa pam_lastlog
+.Op Ar options
+.Sh DESCRIPTION
+The login accounting service module for PAM,
+.Nm
+provides functionality for only one PAM category:
+session management.
+In terms of the
+.Ar module-type
+parameter, this is the
+.Dq Li session
+feature.
+.Ss Login Accounting Session Management Module
+The login accounting session management component provides functions
+to initiate
+.Pq Fn pam_sm_open_session
+and terminate
+.Pq Fn pam_sm_close_session
+sessions.
+The
+.Fn pam_sm_open_session
+function records the session in the
+.Xr utmp 5 ,
+.Xr wtmp 5
+and
+.Xr lastlog 5
+databases.
+The
+.Fn pam_sm_close_session
+function does nothing.
+.Pp
+The following options may be passed to the authentication module:
+.Bl -tag -width ".Cm no_warn"
+.It Cm debug
+.Xr syslog 3
+debugging information at
+.Dv LOG_DEBUG
+level.
+.It Cm no_warn
+suppress warning messages to the user.
+.It Cm no_fail
+Ignore I/O failures.
+.El
+.Sh SEE ALSO
+.Xr last 1 ,
+.Xr w 1 ,
+.Xr login 3 ,
+.Xr logout 3 ,
+.Xr pam.conf 5 ,
+.Xr utmp 5 ,
+.Xr lastlogin 8 ,
+.Xr pam 8
+.Sh AUTHORS
+The
+.Nm
+module and this manual page were developed for the FreeBSD Project by
+ThinkSec AS and NAI Labs, the Security Research Division of Network
+Associates, Inc.\& under DARPA/SPAWAR contract N66001-01-C-8035
+.Pq Dq CBOSS ,
+as part of the DARPA CHATS research program.
diff --git a/lib/libpam/modules/pam_lastlog/pam_lastlog.c b/lib/libpam/modules/pam_lastlog/pam_lastlog.c
new file mode 100644
index 0000000..519d452
--- /dev/null
+++ b/lib/libpam/modules/pam_lastlog/pam_lastlog.c
@@ -0,0 +1,187 @@
+/*-
+ * Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 2001 Mark R V Murray
+ * All rights reserved.
+ * Copyright (c) 2001 Networks Associates Technology, Inc.
+ * All rights reserved.
+ * Copyright (c) 2004 Joe R. Doupnik
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS 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.
+ * 4. Neither the name of the University nor the names of its 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$");
+
+#define _BSD_SOURCE
+
+#include <sys/param.h>
+
+#include <fcntl.h>
+#include <libutil.h>
+#include <paths.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <time.h>
+#include <unistd.h>
+#include <utmp.h>
+
+#define PAM_SM_SESSION
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <security/pam_mod_misc.h>
+
+PAM_EXTERN int
+pam_sm_open_session(pam_handle_t *pamh, int flags,
+ int argc __unused, const char *argv[] __unused)
+{
+ struct passwd *pwd;
+ struct utmp utmp;
+ struct lastlog ll;
+ time_t t;
+ const char *user;
+ const void *rhost, *tty;
+ off_t llpos;
+ int fd, pam_err;
+
+ pam_err = pam_get_user(pamh, &user, NULL);
+ if (pam_err != PAM_SUCCESS)
+ return (pam_err);
+ if (user == NULL || (pwd = getpwnam(user)) == NULL)
+ return (PAM_SERVICE_ERR);
+ PAM_LOG("Got user: %s", user);
+
+ pam_err = pam_get_item(pamh, PAM_RHOST, &rhost);
+ if (pam_err != PAM_SUCCESS)
+ goto err;
+ pam_err = pam_get_item(pamh, PAM_TTY, &tty);
+ if (pam_err != PAM_SUCCESS)
+ goto err;
+ if (tty == NULL) {
+ pam_err = PAM_SERVICE_ERR;
+ goto err;
+ }
+ if (strncmp(tty, _PATH_DEV, strlen(_PATH_DEV)) == 0)
+ tty = (const char *)tty + strlen(_PATH_DEV);
+ if (*(const char *)tty == '\0')
+ return (PAM_SERVICE_ERR);
+
+ fd = open(_PATH_LASTLOG, O_RDWR|O_CREAT, 0644);
+ if (fd == -1)
+ goto file_err;
+
+ /*
+ * Record session in lastlog(5).
+ */
+ llpos = (off_t)(pwd->pw_uid * sizeof(ll));
+ if (lseek(fd, llpos, L_SET) != llpos)
+ goto file_err;
+ if ((flags & PAM_SILENT) == 0) {
+ if (read(fd, &ll, sizeof ll) == sizeof ll && ll.ll_time != 0) {
+ t = ll.ll_time;
+ if (*ll.ll_host != '\0')
+ pam_info(pamh, "Last login: %.*s from %.*s",
+ 24 - 5, ctime(&t),
+ (int)sizeof(ll.ll_host), ll.ll_host);
+ else
+ pam_info(pamh, "Last login: %.*s on %.*s",
+ 24 - 5, ctime(&t),
+ (int)sizeof(ll.ll_line), ll.ll_line);
+ }
+ if (lseek(fd, llpos, L_SET) != llpos)
+ goto file_err;
+ }
+
+ bzero(&ll, sizeof(ll));
+ ll.ll_time = time(NULL);
+
+ /* note: does not need to be NUL-terminated */
+ strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
+ if (rhost != NULL && *(const char *)rhost != '\0')
+ /* note: does not need to be NUL-terminated */
+ strncpy(ll.ll_host, rhost, sizeof(ll.ll_host));
+
+ if (write(fd, (char *)&ll, sizeof(ll)) != sizeof(ll) || close(fd) != 0)
+ goto file_err;
+
+ PAM_LOG("Login recorded in %s", _PATH_LASTLOG);
+
+ /*
+ * Record session in utmp(5) and wtmp(5).
+ */
+ bzero(&utmp, sizeof(utmp));
+ utmp.ut_time = time(NULL);
+ /* note: does not need to be NUL-terminated */
+ strncpy(utmp.ut_name, user, sizeof(utmp.ut_name));
+ if (rhost != NULL && *(const char *)rhost != '\0')
+ strncpy(utmp.ut_host, rhost, sizeof(utmp.ut_host));
+ (void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line));
+ login(&utmp);
+
+ return (PAM_SUCCESS);
+
+file_err:
+ syslog(LOG_ERR, "%s: %m", _PATH_LASTLOG);
+ if (fd != -1)
+ close(fd);
+ pam_err = PAM_SYSTEM_ERR;
+err:
+ if (openpam_get_option(pamh, "no_fail"))
+ return (PAM_SUCCESS);
+ return (pam_err);
+}
+
+PAM_EXTERN int
+pam_sm_close_session(pam_handle_t *pamh __unused, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+ const void *tty;
+
+ pam_get_item(pamh, PAM_TTY, (const void **)&tty);
+ if (strncmp(tty, _PATH_DEV, strlen(_PATH_DEV)) == 0)
+ tty = (const char *)tty + strlen(_PATH_DEV);
+ if (*(const char *)tty == '\0')
+ return (PAM_SERVICE_ERR);
+ if (logout(tty) != 1)
+ syslog(LOG_ERR, "%s(): no utmp record for %s",
+ __func__, (const char *)tty);
+ logwtmp(tty, "", "");
+ return (PAM_SUCCESS);
+}
+
+PAM_MODULE_ENTRY("pam_lastlog");
diff --git a/lib/libpam/modules/pam_login_access/Makefile b/lib/libpam/modules/pam_login_access/Makefile
new file mode 100644
index 0000000..5679a62
--- /dev/null
+++ b/lib/libpam/modules/pam_login_access/Makefile
@@ -0,0 +1,31 @@
+# Copyright 2001 Mark R V Murray
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+
+LIB= pam_login_access
+SRCS= pam_login_access.c login_access.c
+MAN= login.access.5 pam_login_access.8
+
+.include <bsd.lib.mk>
diff --git a/lib/libpam/modules/pam_login_access/login.access.5 b/lib/libpam/modules/pam_login_access/login.access.5
new file mode 100644
index 0000000..abbd3bc
--- /dev/null
+++ b/lib/libpam/modules/pam_login_access/login.access.5
@@ -0,0 +1,58 @@
+.\"
+.\" $FreeBSD$
+.\"
+.Dd April 30, 1994
+.Dt LOGIN.ACCESS 5
+.Os
+.Sh NAME
+.Nm login.access
+.Nd login access control table
+.Sh DESCRIPTION
+The
+.Nm
+file specifies (user, host) combinations and/or (user, tty)
+combinations for which a login will be either accepted or refused.
+.Pp
+When someone logs in, the
+.Nm
+is scanned for the first entry that
+matches the (user, host) combination, or, in case of non-networked
+logins, the first entry that matches the (user, tty) combination.
+The
+permissions field of that table entry determines whether the login will
+be accepted or refused.
+.Pp
+Each line of the login access control table has three fields separated by a
+.Ql \&:
+character:
+.Ar permission : Ns Ar users : Ns Ar origins
+.Pp
+The first field should be a "+" (access granted) or "-" (access denied)
+character.
+The second field should be a list of one or more login names,
+group names, or ALL (always matches).
+The third field should be a list
+of one or more tty names (for non-networked logins), host names, domain
+names (begin with "."), host addresses, internet network numbers (end
+with "."), ALL (always matches) or LOCAL (matches any string that does
+not contain a "." character).
+If you run NIS you can use @netgroupname
+in host or user patterns.
+.Pp
+The EXCEPT operator makes it possible to write very compact rules.
+.Pp
+The group file is searched only when a name does not match that of the
+logged-in user.
+Only groups are matched in which users are explicitly
+listed: the program does not look at a user's primary group id value.
+.Sh FILES
+.Bl -tag -width /etc/login.access -compact
+.It Pa /etc/login.access
+login access control table
+.El
+.Sh SEE ALSO
+.Xr login 1 ,
+.Xr pam 8 ,
+.Xr pam_login_access 8
+.Sh AUTHORS
+.An Guido van Rooij
diff --git a/lib/libpam/modules/pam_login_access/login_access.c b/lib/libpam/modules/pam_login_access/login_access.c
new file mode 100644
index 0000000..dbc1397
--- /dev/null
+++ b/lib/libpam/modules/pam_login_access/login_access.c
@@ -0,0 +1,231 @@
+ /*
+ * This module implements a simple but effective form of login access
+ * control based on login names and on host (or domain) names, internet
+ * addresses (or network numbers), or on terminal line names in case of
+ * non-networked logins. Diagnostics are reported through syslog(3).
+ *
+ * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "%Z% %M% %I% %E% %U%";
+#endif
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <ctype.h>
+#include <errno.h>
+#include <grp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "pam_login_access.h"
+
+#define _PATH_LOGACCESS "/etc/login.access"
+
+ /* Delimiters for fields and for lists of users, ttys or hosts. */
+
+static char fs[] = ":"; /* field separator */
+static char sep[] = ", \t"; /* list-element separator */
+
+ /* Constants to be used in assignments only, not in comparisons... */
+
+#define YES 1
+#define NO 0
+
+static int from_match(const char *, const char *);
+static int list_match(char *, const char *,
+ int (*)(const char *, const char *));
+static int netgroup_match(const char *, const char *, const char *);
+static int string_match(const char *, const char *);
+static int user_match(const char *, const char *);
+
+/* login_access - match username/group and host/tty with access control file */
+
+int
+login_access(const char *user, const char *from)
+{
+ FILE *fp;
+ char line[BUFSIZ];
+ char *perm; /* becomes permission field */
+ char *users; /* becomes list of login names */
+ char *froms; /* becomes list of terminals or hosts */
+ int match = NO;
+ int end;
+ int lineno = 0; /* for diagnostics */
+
+ /*
+ * Process the table one line at a time and stop at the first match.
+ * Blank lines and lines that begin with a '#' character are ignored.
+ * Non-comment lines are broken at the ':' character. All fields are
+ * mandatory. The first field should be a "+" or "-" character. A
+ * non-existing table means no access control.
+ */
+
+ if ((fp = fopen(_PATH_LOGACCESS, "r")) != NULL) {
+ while (!match && fgets(line, sizeof(line), fp)) {
+ lineno++;
+ if (line[end = strlen(line) - 1] != '\n') {
+ syslog(LOG_ERR, "%s: line %d: missing newline or line too long",
+ _PATH_LOGACCESS, lineno);
+ continue;
+ }
+ if (line[0] == '#')
+ continue; /* comment line */
+ while (end > 0 && isspace(line[end - 1]))
+ end--;
+ line[end] = 0; /* strip trailing whitespace */
+ if (line[0] == 0) /* skip blank lines */
+ continue;
+ if (!(perm = strtok(line, fs))
+ || !(users = strtok((char *) 0, fs))
+ || !(froms = strtok((char *) 0, fs))
+ || strtok((char *) 0, fs)) {
+ syslog(LOG_ERR, "%s: line %d: bad field count", _PATH_LOGACCESS,
+ lineno);
+ continue;
+ }
+ if (perm[0] != '+' && perm[0] != '-') {
+ syslog(LOG_ERR, "%s: line %d: bad first field", _PATH_LOGACCESS,
+ lineno);
+ continue;
+ }
+ match = (list_match(froms, from, from_match)
+ && list_match(users, user, user_match));
+ }
+ (void) fclose(fp);
+ } else if (errno != ENOENT) {
+ syslog(LOG_ERR, "cannot open %s: %m", _PATH_LOGACCESS);
+ }
+ return (match == 0 || (line[0] == '+'));
+}
+
+/* list_match - match an item against a list of tokens with exceptions */
+
+static int
+list_match(char *list, const char *item,
+ int (*match_fn)(const char *, const char *))
+{
+ char *tok;
+ int match = NO;
+
+ /*
+ * Process tokens one at a time. We have exhausted all possible matches
+ * when we reach an "EXCEPT" token or the end of the list. If we do find
+ * a match, look for an "EXCEPT" list and recurse to determine whether
+ * the match is affected by any exceptions.
+ */
+
+ for (tok = strtok(list, sep); tok != 0; tok = strtok((char *) 0, sep)) {
+ if (strcasecmp(tok, "EXCEPT") == 0) /* EXCEPT: give up */
+ break;
+ if ((match = (*match_fn)(tok, item)) != 0) /* YES */
+ break;
+ }
+ /* Process exceptions to matches. */
+
+ if (match != NO) {
+ while ((tok = strtok((char *) 0, sep)) && strcasecmp(tok, "EXCEPT"))
+ /* VOID */ ;
+ if (tok == 0 || list_match((char *) 0, item, match_fn) == NO)
+ return (match);
+ }
+ return (NO);
+}
+
+/* netgroup_match - match group against machine or user */
+
+static int
+netgroup_match(const char *group __unused,
+ const char *machine __unused, const char *user __unused)
+{
+ syslog(LOG_ERR, "NIS netgroup support not configured");
+ return 0;
+}
+
+/* user_match - match a username against one token */
+
+static int
+user_match(const char *tok, const char *string)
+{
+ struct group *group;
+ int i;
+
+ /*
+ * If a token has the magic value "ALL" the match always succeeds.
+ * Otherwise, return YES if the token fully matches the username, or if
+ * the token is a group that contains the username.
+ */
+
+ if (tok[0] == '@') { /* netgroup */
+ return (netgroup_match(tok + 1, (char *) 0, string));
+ } else if (string_match(tok, string)) { /* ALL or exact match */
+ return (YES);
+ } else if ((group = getgrnam(tok)) != NULL) {/* try group membership */
+ for (i = 0; group->gr_mem[i]; i++)
+ if (strcasecmp(string, group->gr_mem[i]) == 0)
+ return (YES);
+ }
+ return (NO);
+}
+
+/* from_match - match a host or tty against a list of tokens */
+
+static int
+from_match(const char *tok, const char *string)
+{
+ int tok_len;
+ int str_len;
+
+ /*
+ * If a token has the magic value "ALL" the match always succeeds. Return
+ * YES if the token fully matches the string. If the token is a domain
+ * name, return YES if it matches the last fields of the string. If the
+ * token has the magic value "LOCAL", return YES if the string does not
+ * contain a "." character. If the token is a network number, return YES
+ * if it matches the head of the string.
+ */
+
+ if (tok[0] == '@') { /* netgroup */
+ return (netgroup_match(tok + 1, string, (char *) 0));
+ } else if (string_match(tok, string)) { /* ALL or exact match */
+ return (YES);
+ } else if (tok[0] == '.') { /* domain: match last fields */
+ if ((str_len = strlen(string)) > (tok_len = strlen(tok))
+ && strcasecmp(tok, string + str_len - tok_len) == 0)
+ return (YES);
+ } else if (strcasecmp(tok, "LOCAL") == 0) { /* local: no dots */
+ if (strchr(string, '.') == 0)
+ return (YES);
+ } else if (tok[(tok_len = strlen(tok)) - 1] == '.' /* network */
+ && strncmp(tok, string, tok_len) == 0) {
+ return (YES);
+ }
+ return (NO);
+}
+
+/* string_match - match a string against one token */
+
+static int
+string_match(const char *tok, const char *string)
+{
+
+ /*
+ * If the token has the magic value "ALL" the match always succeeds.
+ * Otherwise, return YES if the token fully matches the string.
+ */
+
+ if (strcasecmp(tok, "ALL") == 0) { /* all: always matches */
+ return (YES);
+ } else if (strcasecmp(tok, string) == 0) { /* try exact match */
+ return (YES);
+ }
+ return (NO);
+}
diff --git a/lib/libpam/modules/pam_login_access/pam_login_access.8 b/lib/libpam/modules/pam_login_access/pam_login_access.8
new file mode 100644
index 0000000..02f0d2d
--- /dev/null
+++ b/lib/libpam/modules/pam_login_access/pam_login_access.8
@@ -0,0 +1,89 @@
+.\" Copyright (c) 2001 Mark R V Murray
+.\" All rights reserved.
+.\" Copyright (c) 2001 Networks Associates Technology, Inc.
+.\" All rights reserved.
+.\"
+.\" Portions of this software were developed for the FreeBSD Project by
+.\" ThinkSec AS 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING 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, 2002
+.Dt PAM_LOGIN_ACCESS 8
+.Os
+.Sh NAME
+.Nm pam_login_access
+.Nd login.access PAM module
+.Sh SYNOPSIS
+.Op Ar service-name
+.Ar module-type
+.Ar control-flag
+.Pa pam_login_access
+.Op Ar options
+.Sh DESCRIPTION
+The
+.Pa login.access
+service module for PAM,
+.Nm
+provides functionality for only one PAM category:
+account management.
+In terms of the
+.Ar module-type
+parameter, this is the
+.Dq Li account
+feature.
+.Ss Login.access Account Management Module
+The
+.Pa login.access
+account management component
+.Pq Fn pam_sm_acct_mgmt ,
+returns success if and only the user is allowed to log in on the
+specified tty (in the case of a local login) or from the specified
+remote host (in the case of a remote login), according to the
+restrictions listed in
+.Xr login.access 5 .
+.Sh SEE ALSO
+.Xr login.access 5 ,
+.Xr pam.conf 5 ,
+.Xr pam 8
+.Sh AUTHORS
+The
+.Xr login.access 5
+access control scheme was designed and implemented by
+.An Wietse Venema .
+.Pp
+The
+.Nm
+module and this manual page were developed for the
+.Fx
+Project by
+ThinkSec AS and NAI Labs, the Security Research Division of Network
+Associates, Inc.\& under DARPA/SPAWAR contract N66001-01-C-8035
+.Pq Dq CBOSS ,
+as part of the DARPA CHATS research program.
diff --git a/lib/libpam/modules/pam_login_access/pam_login_access.c b/lib/libpam/modules/pam_login_access/pam_login_access.c
new file mode 100644
index 0000000..945d5eb
--- /dev/null
+++ b/lib/libpam/modules/pam_login_access/pam_login_access.c
@@ -0,0 +1,101 @@
+/*-
+ * Copyright (c) 2001 Mark R V Murray
+ * All rights reserved.
+ * Copyright (c) 2001 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 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 _BSD_SOURCE
+
+#include <sys/param.h>
+
+#include <syslog.h>
+#include <unistd.h>
+
+#define PAM_SM_ACCOUNT
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <security/pam_mod_misc.h>
+
+#include "pam_login_access.h"
+
+PAM_EXTERN int
+pam_sm_acct_mgmt(pam_handle_t *pamh, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+ const void *rhost, *tty, *user;
+ char hostname[MAXHOSTNAMELEN];
+ int pam_err;
+
+ pam_err = pam_get_item(pamh, PAM_USER, &user);
+ if (pam_err != PAM_SUCCESS)
+ return (pam_err);
+
+ if (user == NULL)
+ return (PAM_SERVICE_ERR);
+
+ PAM_LOG("Got user: %s", (const char *)user);
+
+ pam_err = pam_get_item(pamh, PAM_RHOST, &rhost);
+ if (pam_err != PAM_SUCCESS)
+ return (pam_err);
+
+ pam_err = pam_get_item(pamh, PAM_TTY, &tty);
+ if (pam_err != PAM_SUCCESS)
+ return (pam_err);
+
+ gethostname(hostname, sizeof hostname);
+
+ if (rhost == NULL || *(const char *)rhost == '\0') {
+ PAM_LOG("Checking login.access for user %s on tty %s",
+ (const char *)user, (const char *)tty);
+ if (login_access(user, tty) != 0)
+ return (PAM_SUCCESS);
+ PAM_VERBOSE_ERROR("%s is not allowed to log in on %s",
+ user, tty);
+ } else {
+ PAM_LOG("Checking login.access for user %s from host %s",
+ (const char *)user, (const char *)rhost);
+ if (login_access(user, rhost) != 0)
+ return (PAM_SUCCESS);
+ PAM_VERBOSE_ERROR("%s is not allowed to log in from %s",
+ user, rhost);
+ }
+
+ return (PAM_AUTH_ERR);
+}
+
+PAM_MODULE_ENTRY("pam_login_access");
diff --git a/lib/libpam/modules/pam_login_access/pam_login_access.h b/lib/libpam/modules/pam_login_access/pam_login_access.h
new file mode 100644
index 0000000..38c3049
--- /dev/null
+++ b/lib/libpam/modules/pam_login_access/pam_login_access.h
@@ -0,0 +1,39 @@
+/*-
+ * Copyright (c) 2001 Mark R V Murray
+ * All rights reserved.
+ * Copyright (c) 2001 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+extern int login_access(const char *, const char *);
diff --git a/lib/libpam/modules/pam_nologin/Makefile b/lib/libpam/modules/pam_nologin/Makefile
new file mode 100644
index 0000000..ba5a7d4
--- /dev/null
+++ b/lib/libpam/modules/pam_nologin/Makefile
@@ -0,0 +1,34 @@
+# Copyright 2001 Mark R V Murray
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+
+LIB= pam_nologin
+SRCS= pam_nologin.c
+MAN= pam_nologin.8
+
+DPADD= ${LIBUTIL}
+LDADD= -lutil
+
+.include <bsd.lib.mk>
diff --git a/lib/libpam/modules/pam_nologin/pam_nologin.8 b/lib/libpam/modules/pam_nologin/pam_nologin.8
new file mode 100644
index 0000000..a2c5990
--- /dev/null
+++ b/lib/libpam/modules/pam_nologin/pam_nologin.8
@@ -0,0 +1,90 @@
+.\" Copyright (c) 2001 Mark R V Murray
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING 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 8, 2001
+.Dt PAM_NOLOGIN 8
+.Os
+.Sh NAME
+.Nm pam_nologin
+.Nd NoLogin PAM module
+.Sh SYNOPSIS
+.Op Ar service-name
+.Ar module-type
+.Ar control-flag
+.Pa pam_nologin
+.Op Ar options
+.Sh DESCRIPTION
+The NoLogin authentication service module for PAM,
+.Nm
+provides functionality for only one PAM category:
+authentication.
+In terms of the
+.Ar module-type
+parameter, this is the
+.Dq Li auth
+feature.
+It also provides a null function for session management.
+.Ss NoLogin Authentication Module
+The NoLogin authentication component
+.Pq Fn pam_sm_authenticate ,
+always returns success for the superuser,
+and returns success for all other users
+if the file
+.Pa /var/run/nologin
+does not exist.
+If
+.Pa /var/run/nologin
+does exist,
+then its contents are echoed
+to non-superusers
+before failure is returned.
+If a "nologin" capability
+is specified in
+.Xr login.conf 5 ,
+then the file thus specified
+is used instead.
+This usually defaults to
+.Pa /var/run/nologin .
+.Pp
+The following options may be passed to the authentication module:
+.Bl -tag -width ".Cm no_warn"
+.It Cm debug
+.Xr syslog 3
+debugging information at
+.Dv LOG_DEBUG
+level.
+.It Cm no_warn
+suppress warning messages to the user.
+These messages include
+reasons why the user's
+authentication attempt was declined.
+.El
+.Sh SEE ALSO
+.Xr syslog 3 ,
+.Xr login.conf 5 ,
+.Xr nologin 5 ,
+.Xr pam.conf 5 ,
+.Xr pam 8
diff --git a/lib/libpam/modules/pam_nologin/pam_nologin.c b/lib/libpam/modules/pam_nologin/pam_nologin.c
new file mode 100644
index 0000000..2145688
--- /dev/null
+++ b/lib/libpam/modules/pam_nologin/pam_nologin.c
@@ -0,0 +1,122 @@
+/*-
+ * Copyright 2001 Mark R V Murray
+ * All rights reserved.
+ * Copyright (c) 2001 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 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 <fcntl.h>
+#include <login_cap.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define PAM_SM_AUTH
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <security/pam_mod_misc.h>
+
+#define NOLOGIN "/var/run/nologin"
+
+static char nologin_def[] = NOLOGIN;
+
+PAM_EXTERN int
+pam_sm_authenticate(pam_handle_t *pamh, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+ login_cap_t *lc;
+ struct passwd *pwd;
+ struct stat st;
+ int retval, fd;
+ const char *user, *nologin;
+ char *mtmp;
+
+ retval = pam_get_user(pamh, &user, NULL);
+ if (retval != PAM_SUCCESS)
+ return (retval);
+
+ PAM_LOG("Got user: %s", user);
+
+ lc = login_getclass(NULL);
+ nologin = login_getcapstr(lc, "nologin", nologin_def, nologin_def);
+ login_close(lc);
+ lc = NULL;
+
+ fd = open(nologin, O_RDONLY, 0);
+ if (fd < 0)
+ return (PAM_SUCCESS);
+
+ PAM_LOG("Opened %s file", NOLOGIN);
+
+ pwd = getpwnam(user);
+ if (pwd && pwd->pw_uid == 0)
+ retval = PAM_SUCCESS;
+ else {
+ if (!pwd)
+ retval = PAM_USER_UNKNOWN;
+ else
+ retval = PAM_AUTH_ERR;
+ }
+
+ if (fstat(fd, &st) < 0)
+ return (retval);
+
+ mtmp = malloc(st.st_size + 1);
+ if (mtmp != NULL) {
+ read(fd, mtmp, st.st_size);
+ mtmp[st.st_size] = '\0';
+ pam_error(pamh, "%s", mtmp);
+ free(mtmp);
+ }
+
+ if (retval != PAM_SUCCESS)
+ PAM_VERBOSE_ERROR("Administrator refusing you: %s", NOLOGIN);
+
+ return (retval);
+}
+
+PAM_EXTERN int
+pam_sm_setcred(pam_handle_t *pamh __unused, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+
+ return (PAM_SUCCESS);
+}
+
+PAM_MODULE_ENTRY("pam_nologin");
diff --git a/lib/libpam/modules/pam_opie/Makefile b/lib/libpam/modules/pam_opie/Makefile
new file mode 100644
index 0000000..fbc1278
--- /dev/null
+++ b/lib/libpam/modules/pam_opie/Makefile
@@ -0,0 +1,35 @@
+# Copyright 2000 James Bloom
+# All rights reserved.
+# Based upon code Copyright 1998 Juniper Networks, 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$
+
+LIB= pam_opie
+SRCS= pam_opie.c
+MAN= pam_opie.8
+
+DPADD= ${LIBOPIE}
+LDADD= -lopie
+
+.include <bsd.lib.mk>
diff --git a/lib/libpam/modules/pam_opie/pam_opie.8 b/lib/libpam/modules/pam_opie/pam_opie.8
new file mode 100644
index 0000000..968985a
--- /dev/null
+++ b/lib/libpam/modules/pam_opie/pam_opie.8
@@ -0,0 +1,123 @@
+.\" Copyright (c) 2001 Mark R V Murray
+.\" All rights reserved.
+.\" Copyright (c) 2002 Networks Associates Technology, Inc.
+.\" All rights reserved.
+.\"
+.\" Portions of this software were developed for the FreeBSD Project by
+.\" ThinkSec AS 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING 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, 2001
+.Dt PAM_OPIE 8
+.Os
+.Sh NAME
+.Nm pam_opie
+.Nd OPIE PAM module
+.Sh SYNOPSIS
+.Op Ar service-name
+.Ar module-type
+.Ar control-flag
+.Pa pam_opie
+.Op Ar options
+.Sh DESCRIPTION
+The OPIE authentication service module for PAM,
+.Nm
+provides functionality for only one PAM category:
+that of authentication.
+In terms of the
+.Ar module-type
+parameter, this is the
+.Dq Li auth
+feature.
+It also provides a null function for session management.
+.Pp
+Note that this module does not enforce
+.Xr opieaccess 5
+checks.
+There is a separate module,
+.Xr pam_opieaccess 8 ,
+for this purpose.
+.Ss OPIE Authentication Module
+The OPIE authentication component
+provides functions to verify the identity of a user
+.Pq Fn pam_sm_authenticate ,
+which obtains the relevant
+.Xr opie 4
+credentials.
+It provides the user with an OPIE challenge,
+and verifies that this is correct with
+.Xr opiechallenge 3 .
+.Pp
+The following options may be passed to the authentication module:
+.Bl -tag -width ".Cm auth_as_self"
+.It Cm debug
+.Xr syslog 3
+debugging information at
+.Dv LOG_DEBUG
+level.
+.It Cm auth_as_self
+This option will require the user
+to authenticate himself as the user
+given by
+.Xr getlogin 2 ,
+not as the account they are attempting to access.
+This is primarily for services like
+.Xr su 1 ,
+where the user's ability to retype
+their own password
+might be deemed sufficient.
+.It Cm no_fake_prompts
+Do not generate fake challenges for users who do not have an OPIE key.
+Note that this can leak information to a hypothetical attacker about
+who uses OPIE and who does not, but it can be useful on systems where
+some users want to use OPIE but most do not.
+.El
+.Pp
+Note that
+.Nm
+ignores the standard options
+.Cm try_first_pass
+and
+.Cm use_first_pass ,
+since a challenge must be generated before the user can submit a valid
+response.
+.Sh FILES
+.Bl -tag -width ".Pa /etc/opiekeys" -compact
+.It Pa /etc/opiekeys
+default OPIE password database.
+.El
+.Sh SEE ALSO
+.Xr passwd 1 ,
+.Xr getlogin 2 ,
+.Xr opiechallenge 3 ,
+.Xr syslog 3 ,
+.Xr opie 4 ,
+.Xr pam.conf 5 ,
+.Xr pam 8
diff --git a/lib/libpam/modules/pam_opie/pam_opie.c b/lib/libpam/modules/pam_opie/pam_opie.c
new file mode 100644
index 0000000..737b044
--- /dev/null
+++ b/lib/libpam/modules/pam_opie/pam_opie.c
@@ -0,0 +1,146 @@
+/*-
+ * Copyright 2000 James Bloom
+ * All rights reserved.
+ * Based upon code Copyright 1998 Juniper Networks, Inc.
+ * Copyright (c) 2001-2003 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 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 <opie.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define PAM_SM_AUTH
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <security/pam_mod_misc.h>
+
+#define PAM_OPT_NO_FAKE_PROMPTS "no_fake_prompts"
+
+PAM_EXTERN int
+pam_sm_authenticate(pam_handle_t *pamh, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+ struct opie opie;
+ struct passwd *pwd;
+ int retval, i;
+ const char *(promptstr[]) = { "%s\nPassword: ", "%s\nPassword [echo on]: "};
+ char challenge[OPIE_CHALLENGE_MAX];
+ char *user;
+ char *response;
+ int style;
+
+ user = NULL;
+ if (openpam_get_option(pamh, PAM_OPT_AUTH_AS_SELF)) {
+ if ((pwd = getpwnam(getlogin())) == NULL)
+ return (PAM_AUTH_ERR);
+ user = pwd->pw_name;
+ }
+ else {
+ retval = pam_get_user(pamh, (const char **)&user, NULL);
+ if (retval != PAM_SUCCESS)
+ return (retval);
+ }
+
+ PAM_LOG("Got user: %s", user);
+
+ /*
+ * Don't call the OPIE atexit() handler when our program exits,
+ * since the module has been unloaded and we will SEGV.
+ */
+ opiedisableaeh();
+
+ /*
+ * If the no_fake_prompts option was given, and the user
+ * doesn't have an OPIE key, just fail rather than present the
+ * user with a bogus OPIE challenge.
+ */
+ /* XXX generates a const warning because of incorrect prototype */
+ if (opiechallenge(&opie, (char *)user, challenge) != 0 &&
+ openpam_get_option(pamh, PAM_OPT_NO_FAKE_PROMPTS))
+ return (PAM_AUTH_ERR);
+
+ /*
+ * It doesn't make sense to use a password that has already been
+ * typed in, since we haven't presented the challenge to the user
+ * yet, so clear the stored password.
+ */
+ pam_set_item(pamh, PAM_AUTHTOK, NULL);
+
+ style = PAM_PROMPT_ECHO_OFF;
+ for (i = 0; i < 2; i++) {
+ retval = pam_prompt(pamh, style, &response,
+ promptstr[i], challenge);
+ if (retval != PAM_SUCCESS) {
+ opieunlock();
+ return (retval);
+ }
+
+ PAM_LOG("Completed challenge %d: %s", i, response);
+
+ if (response[0] != '\0')
+ break;
+
+ /* Second time round, echo the password */
+ style = PAM_PROMPT_ECHO_ON;
+ }
+
+ pam_set_item(pamh, PAM_AUTHTOK, response);
+
+ /*
+ * Opieverify is supposed to return -1 only if an error occurs.
+ * But it returns -1 even if the response string isn't in the form
+ * it expects. Thus we can't log an error and can only check for
+ * success or lack thereof.
+ */
+ retval = opieverify(&opie, response);
+ free(response);
+ return (retval == 0 ? PAM_SUCCESS : PAM_AUTH_ERR);
+}
+
+PAM_EXTERN int
+pam_sm_setcred(pam_handle_t *pamh __unused, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+
+ return (PAM_SUCCESS);
+}
+
+PAM_MODULE_ENTRY("pam_opie");
diff --git a/lib/libpam/modules/pam_opieaccess/Makefile b/lib/libpam/modules/pam_opieaccess/Makefile
new file mode 100644
index 0000000..1554a88
--- /dev/null
+++ b/lib/libpam/modules/pam_opieaccess/Makefile
@@ -0,0 +1,10 @@
+# $FreeBSD$
+
+LIB= pam_opieaccess
+SRCS= ${LIB}.c
+MAN= pam_opieaccess.8
+
+DPADD= ${LIBOPIE}
+LDADD= -lopie
+
+.include <bsd.lib.mk>
diff --git a/lib/libpam/modules/pam_opieaccess/pam_opieaccess.8 b/lib/libpam/modules/pam_opieaccess/pam_opieaccess.8
new file mode 100644
index 0000000..07a66a4
--- /dev/null
+++ b/lib/libpam/modules/pam_opieaccess/pam_opieaccess.8
@@ -0,0 +1,140 @@
+.\" Copyright (c) 2001 Mark R V Murray
+.\" All rights reserved.
+.\" Copyright (c) 2002 Networks Associates Technology, Inc.
+.\" All rights reserved.
+.\"
+.\" Portions of this software were developed for the FreeBSD Project by
+.\" ThinkSec AS 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING 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 21, 2002
+.Dt PAM_OPIEACCESS 8
+.Os
+.Sh NAME
+.Nm pam_opieaccess
+.Nd OPIEAccess PAM module
+.Sh SYNOPSIS
+.Op Ar service-name
+.Ar module-type
+.Ar control-flag
+.Pa pam_opieaccess
+.Op Ar options
+.Sh DESCRIPTION
+The
+.Nm
+module is used in conjunction with the
+.Xr pam_opie 8
+PAM module to ascertain that authentication can proceed by other means
+(such as the
+.Xr pam_unix 8
+module) even if OPIE authentication failed.
+To properly use this module,
+.Xr pam_opie 8
+should be marked
+.Dq Li sufficient ,
+and
+.Nm
+should be listed right below it and marked
+.Dq Li requisite .
+.Pp
+The
+.Nm
+module provides functionality for only one PAM category:
+authentication.
+In terms of the
+.Ar module-type
+parameter, this is the
+.Dq Li auth
+feature.
+It also provides null functions for the remaining module types.
+.Ss OPIEAccess Authentication Module
+The authentication component
+.Pq Fn pam_sm_authenticate ,
+returns
+.Dv PAM_SUCCESS
+in two cases:
+.Bl -enum
+.It
+The user does not have OPIE enabled.
+.It
+The user has OPIE enabled, and the remote host is listed as a trusted
+host in
+.Pa /etc/opieaccess ,
+and the user does not have a file named
+.Pa opiealways
+in his home directory.
+.El
+.Pp
+Otherwise, it returns
+.Dv PAM_AUTH_ERR .
+.Pp
+The following options may be passed to the authentication module:
+.Bl -tag -width ".Cm allow_local"
+.It Cm allow_local
+Normally, local logins are subjected to the same restrictions as
+remote logins from
+.Dq localhost .
+This option causes
+.Nm
+to always allow local logins.
+.It Cm debug
+.Xr syslog 3
+debugging information at
+.Dv LOG_DEBUG
+level.
+.It Cm no_warn
+suppress warning messages to the user.
+These messages include reasons why the user's authentication attempt
+was declined.
+.El
+.Sh FILES
+.Bl -tag -width ".Pa /etc/opieaccess"
+.It Pa /etc/opieaccess
+List of trusted hosts or networks.
+See
+.Xr opieaccess 5
+for a description of its syntax.
+.El
+.Sh SEE ALSO
+.Xr opie 4 ,
+.Xr opieaccess 5 ,
+.Xr pam.conf 5 ,
+.Xr pam 8 ,
+.Xr pam_opie 8
+.Sh AUTHORS
+The
+.Nm
+module and this manual page were developed for the
+.Fx
+Project by
+ThinkSec AS and NAI Labs, the Security Research Division of Network
+Associates, Inc.\& under DARPA/SPAWAR contract N66001-01-C-8035
+.Pq Dq CBOSS ,
+as part of the DARPA CHATS research program.
diff --git a/lib/libpam/modules/pam_opieaccess/pam_opieaccess.c b/lib/libpam/modules/pam_opieaccess/pam_opieaccess.c
new file mode 100644
index 0000000..0351115
--- /dev/null
+++ b/lib/libpam/modules/pam_opieaccess/pam_opieaccess.c
@@ -0,0 +1,95 @@
+/*-
+ * Copyright (c) 2002 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project by ThinkSec AS 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 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 _BSD_SOURCE
+
+#include <sys/types.h>
+#include <opie.h>
+#include <pwd.h>
+#include <unistd.h>
+#include <syslog.h>
+
+#define PAM_SM_AUTH
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <security/pam_mod_misc.h>
+
+PAM_EXTERN int
+pam_sm_authenticate(pam_handle_t *pamh, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+ struct opie opie;
+ struct passwd *pwent;
+ const void *luser, *rhost;
+ int r;
+
+ r = pam_get_item(pamh, PAM_USER, &luser);
+ if (r != PAM_SUCCESS)
+ return (r);
+ if (luser == NULL)
+ return (PAM_SERVICE_ERR);
+
+ pwent = getpwnam(luser);
+ if (pwent == NULL || opielookup(&opie, __DECONST(char *, luser)) != 0)
+ return (PAM_SUCCESS);
+
+ r = pam_get_item(pamh, PAM_RHOST, &rhost);
+ if (r != PAM_SUCCESS)
+ return (r);
+ if (rhost == NULL || *(const char *)rhost == '\0')
+ rhost = openpam_get_option(pamh, "allow_local") ?
+ "" : "localhost";
+
+ if (opieaccessfile(__DECONST(char *, rhost)) != 0 &&
+ opiealways(pwent->pw_dir) != 0)
+ return (PAM_SUCCESS);
+
+ PAM_VERBOSE_ERROR("Refused; remote host is not in opieaccess");
+
+ return (PAM_AUTH_ERR);
+}
+
+PAM_EXTERN int
+pam_sm_setcred(pam_handle_t *pamh __unused, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+
+ return (PAM_SUCCESS);
+}
+
+PAM_MODULE_ENTRY("pam_opieaccess");
diff --git a/lib/libpam/modules/pam_passwdqc/Makefile b/lib/libpam/modules/pam_passwdqc/Makefile
new file mode 100644
index 0000000..905afe1
--- /dev/null
+++ b/lib/libpam/modules/pam_passwdqc/Makefile
@@ -0,0 +1,17 @@
+# $FreeBSD$
+
+SRCDIR= ${.CURDIR}/../../../../contrib/pam_modules/pam_passwdqc
+.PATH: ${SRCDIR}
+
+LIB= pam_passwdqc
+SRCS= pam_passwdqc.c passwdqc_check.c passwdqc_random.c wordset_4k.c
+MAN= pam_passwdqc.8
+
+WARNS?= 0
+CFLAGS+= -I${SRCDIR}
+
+DPADD= ${LIBCRYPT}
+LDADD= -lcrypt
+
+.include <bsd.lib.mk>
+
diff --git a/lib/libpam/modules/pam_passwdqc/pam_passwdqc.8 b/lib/libpam/modules/pam_passwdqc/pam_passwdqc.8
new file mode 100644
index 0000000..408f77d
--- /dev/null
+++ b/lib/libpam/modules/pam_passwdqc/pam_passwdqc.8
@@ -0,0 +1,268 @@
+.\" Copyright (c) 2000-2002 Solar Designer.
+.\" All rights reserved.
+.\" Copyright (c) 2001 Networks Associates Technology, Inc.
+.\" All rights reserved.
+.\"
+.\" Portions of this software were developed for the FreeBSD Project by
+.\" ThinkSec AS 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING 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, 2002
+.Dt PAM_PASSWDQC 8
+.Os
+.Sh NAME
+.Nm pam_passwdqc
+.Nd Password quality-control PAM module
+.Sh SYNOPSIS
+.Op Ar service-name
+.Ar module-type
+.Ar control-flag
+.Pa pam_passwdqc
+.Op Ar options
+.Sh DESCRIPTION
+The
+.Nm
+module is a simple password strength checking module for
+PAM.
+In addition to checking regular passwords, it offers support for
+passphrases and can provide randomly generated passwords.
+.Pp
+The
+.Nm
+module provides functionality for only one PAM category:
+password changing.
+In terms of the
+.Ar module-type
+parameter, this is the
+.Dq Li password
+feature.
+.Pp
+The
+.Fn pam_chauthtok
+service function will ask the user for a new password, and verify that
+it meets certain minimum standards.
+If the chosen password is unsatisfactory, the service function returns
+.Dv PAM_AUTHTOK_ERR .
+.Pp
+The following options may be passed to the authentication module:
+.Bl -tag -width indent
+.It Xo
+.Sm off
+.Cm min No = Ar N0 , N1 , N2 , N3 , N4
+.Sm on
+.Xc
+.Sm off
+.Pq Cm min No = Cm disabled , No 24 , 12 , 8 , 7
+.Sm on
+The minimum allowed password lengths for different kinds of
+passwords/passphrases.
+The keyword
+.Cm disabled
+can be used to
+disallow passwords of a given kind regardless of their length.
+Each subsequent number is required to be no larger than the preceding
+one.
+.Pp
+.Ar N0
+is used for passwords consisting of characters from one character
+class only.
+The character classes are: digits, lower-case letters, upper-case
+letters, and other characters.
+There is also a special class for
+.No non- Ns Tn ASCII
+characters which could not
+be classified, but are assumed to be non-digits.
+.Pp
+.Ar N1
+is used for passwords consisting of characters from two character
+classes, which do not meet the requirements for a passphrase.
+.Pp
+.Ar N2
+is used for passphrases.
+A passphrase must consist of sufficient words (see the
+.Cm passphrase
+option below).
+.Pp
+.Ar N3
+and
+.Ar N4
+are used for passwords consisting of characters from three
+and four character classes, respectively.
+.Pp
+When calculating the number of character classes, upper-case letters
+used as the first character and digits used as the last character of a
+password are not counted.
+.Pp
+In addition to being sufficiently long, passwords are required to
+contain enough different characters for the character classes and
+the minimum length they have been checked against.
+.Pp
+.It Cm max Ns = Ns Ar N
+.Pq Cm max Ns = Ns 40
+The maximum allowed password length.
+This can be used to prevent users from setting passwords which may be
+too long for some system services.
+The value 8 is treated specially: if
+.Cm max
+is set to 8, passwords longer than 8 characters will not be rejected,
+but will be truncated to 8 characters for the strength checks and the
+user will be warned.
+This is for compatibility with the traditional DES password hashes,
+which truncate the password at 8 characters.
+.Pp
+It is important that you do set
+.Cm max Ns = Ns 8
+if you are using the traditional
+hashes, or some weak passwords will pass the checks.
+.It Cm passphrase Ns = Ns Ar N
+.Pq Cm passphrase Ns = Ns 3
+The number of words required for a passphrase, or 0 to disable
+passphrase support.
+.It Cm match Ns = Ns Ar N
+.Pq Cm match Ns = Ns 4
+The length of common substring required to conclude that a password is
+at least partially based on information found in a character string,
+or 0 to disable the substring search.
+Note that the password will not be rejected once a weak substring is
+found; it will instead be subjected to the usual strength requirements
+with the weak substring removed.
+.Pp
+The substring search is case-insensitive and is able to detect and
+remove a common substring spelled backwards.
+.It Xo
+.Sm off
+.Cm similar No = Cm permit | deny
+.Sm on
+.Xc
+.Pq Cm similar Ns = Ns Cm deny
+Whether a new password is allowed to be similar to the old one.
+The passwords are considered to be similar when there is a sufficiently
+long common substring and the new password with the substring removed
+would be weak.
+.It Xo
+.Sm off
+.Cm random No = Ar N Op , Cm only
+.Sm on
+.Xc
+.Pq Cm random Ns = Ns 42
+The size of randomly-generated passwords in bits, or 0 to disable this
+feature.
+Passwords that contain the offered randomly-generated string will be
+allowed regardless of other possible restrictions.
+.Pp
+The
+.Cm only
+modifier can be used to disallow user-chosen passwords.
+.It Xo
+.Sm off
+.Cm enforce No = Cm none | users | everyone
+.Sm on
+.Xc
+.Pq Cm enforce Ns = Ns Cm everyone
+The module can be configured to warn of weak passwords only, but not
+actually enforce strong passwords.
+The
+.Cm users
+setting will enforce strong passwords for non-root users only.
+.It Cm non-unix
+Normally,
+.Nm
+uses
+.Xr getpwnam 3
+to obtain the user's personal login information and use that during
+the password strength checks.
+This behavior can be disabled with the
+.Cm non-unix
+option.
+.It Cm retry Ns = Ns Ar N
+.Pq Cm retry Ns = Ns 3
+The number of times the module will ask for a new password if the user
+fails to provide a sufficiently strong password and enter it twice the
+first time.
+.It Cm ask_oldauthtok Ns Op = Ns Cm update
+Ask for the old password as well.
+Normally,
+.Nm
+leaves this task for subsequent modules.
+With no argument, the
+.Cm ask_oldauthtok
+option will cause
+.Nm
+to ask for the old password during the preliminary check phase.
+If the
+.Cm ask_oldauthtok
+option is specified with the
+.Cm update
+argument,
+.Nm
+will do that during the update phase.
+.It Cm check_oldauthtok
+This tells
+.Nm
+to validate the old password before giving a
+new password prompt.
+Normally, this task is left for subsequent modules.
+.Pp
+The primary use for this option is when
+.Cm ask_oldauthtok Ns = Ns Cm update
+is also specified, in which case no other modules gets a chance to ask
+for and validate the password.
+Of course, this will only work with
+.Ux
+passwords.
+.It Cm use_first_pass , use_authtok
+Use the new password obtained by modules stacked before
+.Nm .
+This disables user interaction within
+.Nm .
+The only difference between
+.Cm use_first_pass
+and
+.Cm use_authtok
+is that the former is incompatible with
+.Cm ask_oldauthtok .
+.El
+.Sh SEE ALSO
+.Xr getpwnam 3 ,
+.Xr pam.conf 5 ,
+.Xr pam 8
+.Sh AUTHORS
+The
+.Nm
+module was written by
+.An Solar Designer Aq solar@openwall.com .
+This manual page, derived from the author's documentation, was written
+for the
+.Fx
+Project by
+ThinkSec AS and NAI Labs, the Security Research Division of Network
+Associates, Inc.\& under DARPA/SPAWAR contract N66001-01-C-8035
+.Pq Dq CBOSS ,
+as part of the DARPA CHATS research program.
diff --git a/lib/libpam/modules/pam_permit/Makefile b/lib/libpam/modules/pam_permit/Makefile
new file mode 100644
index 0000000..dbbd5b5
--- /dev/null
+++ b/lib/libpam/modules/pam_permit/Makefile
@@ -0,0 +1,31 @@
+# Copyright 1999 Max Khon.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+
+LIB= pam_permit
+SRCS= pam_permit.c
+MAN= pam_permit.8
+
+.include <bsd.lib.mk>
diff --git a/lib/libpam/modules/pam_permit/pam_permit.8 b/lib/libpam/modules/pam_permit/pam_permit.8
new file mode 100644
index 0000000..c7d98ab
--- /dev/null
+++ b/lib/libpam/modules/pam_permit/pam_permit.8
@@ -0,0 +1,75 @@
+.\" Copyright (c) 2001 Mark R V Murray
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING 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, 2001
+.Dt PAM_PERMIT 8
+.Os
+.Sh NAME
+.Nm pam_permit
+.Nd Promiscuous PAM module
+.Sh SYNOPSIS
+.Op Ar service-name
+.Ar module-type
+.Ar control-flag
+.Pa pam_permit
+.Op Ar options
+.Sh DESCRIPTION
+The Promiscuous authentication service module for PAM,
+.Nm
+provides functionality for all the PAM categories:
+authentication,
+account management,
+session management and
+password management.
+In terms of the
+.Ar module-type
+parameter, these are the
+.Dq Li auth ,
+.Dq Li account ,
+.Dq Li session ,
+and
+.Dq Li password
+features.
+.Pp
+The Promiscuous module
+will universally allow all requests.
+It is primarily of use during testing,
+and to silence
+.Dq noisy
+PAM-enabled applications.
+.Pp
+The following options may be passed to the module:
+.Bl -tag -width ".Cm debug"
+.It Cm debug
+.Xr syslog 3
+debugging information at
+.Dv LOG_DEBUG
+level.
+.El
+.Sh SEE ALSO
+.Xr syslog 3 ,
+.Xr pam.conf 5 ,
+.Xr pam 8
diff --git a/lib/libpam/modules/pam_permit/pam_permit.c b/lib/libpam/modules/pam_permit/pam_permit.c
new file mode 100644
index 0000000..fe0a4ed
--- /dev/null
+++ b/lib/libpam/modules/pam_permit/pam_permit.c
@@ -0,0 +1,93 @@
+/*-
+ * Copyright 2001 Mark R V Murray
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 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>
+
+#define PAM_SM_AUTH
+#define PAM_SM_ACCOUNT
+#define PAM_SM_SESSION
+#define PAM_SM_PASSWORD
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+
+PAM_EXTERN int
+pam_sm_authenticate(pam_handle_t *pamh, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+ const char *user;
+ int r;
+
+ if ((r = pam_get_user(pamh, &user, NULL)) != PAM_SUCCESS)
+ return (r);
+
+ return (PAM_SUCCESS);
+}
+
+PAM_EXTERN int
+pam_sm_setcred(pam_handle_t *pamh __unused, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+
+ return (PAM_SUCCESS);
+}
+
+PAM_EXTERN int
+pam_sm_acct_mgmt(pam_handle_t *pamh __unused, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+
+ return (PAM_SUCCESS);
+}
+
+PAM_EXTERN int
+pam_sm_chauthtok(pam_handle_t *pamh __unused, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+
+ return (PAM_SUCCESS);
+}
+
+PAM_EXTERN int
+pam_sm_open_session(pam_handle_t *pamh __unused, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+
+ return (PAM_SUCCESS);
+}
+
+PAM_EXTERN int
+pam_sm_close_session(pam_handle_t *pamh __unused, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+
+ return (PAM_SUCCESS);
+}
+
+PAM_MODULE_ENTRY("pam_permit");
diff --git a/lib/libpam/modules/pam_radius/Makefile b/lib/libpam/modules/pam_radius/Makefile
new file mode 100644
index 0000000..88e4357
--- /dev/null
+++ b/lib/libpam/modules/pam_radius/Makefile
@@ -0,0 +1,35 @@
+# Copyright 1998 Juniper Networks, Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+
+LIB= pam_radius
+SRCS= pam_radius.c
+MAN= pam_radius.8
+WARNS= 0
+
+DPADD= ${LIBRADIUS}
+LDADD= -lradius
+
+.include <bsd.lib.mk>
diff --git a/lib/libpam/modules/pam_radius/pam_radius.8 b/lib/libpam/modules/pam_radius/pam_radius.8
new file mode 100644
index 0000000..25e7312
--- /dev/null
+++ b/lib/libpam/modules/pam_radius/pam_radius.8
@@ -0,0 +1,138 @@
+.\" Copyright (c) 1999
+.\" Andrzej Bialecki <abial@FreeBSD.org>. All rights reserved.
+.\"
+.\" Copyright (c) 1992, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software donated 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. 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd October 28, 2002
+.Dt PAM_RADIUS 8
+.Os
+.Sh NAME
+.Nm pam_radius
+.Nd RADIUS authentication PAM module
+.Sh SYNOPSIS
+.Op Ar service-name
+.Ar module-type
+.Ar control-flag
+.Pa pam_radius
+.Op Ar options
+.Sh DESCRIPTION
+The
+.Nm
+module provides authentication services based
+upon the RADIUS (Remote Authentication Dial In User Service) protocol
+for the PAM (Pluggable Authentication Module) framework.
+.Pp
+The
+.Nm
+module accepts these optional parameters:
+.Bl -tag -width Fl
+.It Cm use_first_pass
+causes
+.Nm
+to use a previously entered password instead of prompting for a new one.
+If no password has been entered then authentication fails.
+.It Cm try_first_pass
+causes
+.Nm
+to use a previously entered password, if one is available.
+If no
+password has been entered,
+.Nm
+prompts for one as usual.
+.It Cm echo_pass
+causes echoing to be left on if
+.Nm
+prompts for a password.
+.It Cm conf Ns = Ns Ar pathname
+specifies a non-standard location for the RADIUS client configuration file
+(normally located in
+.Pa /etc/radius.conf ) .
+.It Cm nas_id Ns = Ns Ar identifier
+specifies a NAS identifier to send instead of the hostname.
+.It Cm template_user Ns = Ns Ar username
+specifies a user whose
+.Xr passwd 5
+entry will be used as a template to create the session environment
+if the supplied username does not exist in local password database.
+The user
+will be authenticated with the supplied username and password, but his
+credentials to the system will be presented as the ones for
+.Ar username ,
+i.e., his login class, home directory, resource limits, etc.\& will be set to ones
+defined for
+.Ar username .
+.Pp
+If this option is omitted, and there is no username
+in the system databases equal to the supplied one (as determined by call to
+.Xr getpwnam 3 ) ,
+the authentication will fail.
+.It Cm nas_ipaddr Ns Op No = Ns Ar address
+specifies a NAS IP address to be sent.
+If option is present, but there is no value provided then IP address
+corresponding to the current hostname will be used.
+.El
+.Sh FILES
+.Bl -tag -width /etc/radius.conf -compact
+.It Pa /etc/radius.conf
+The standard RADIUS client configuration file for
+.Nm
+.El
+.Sh SEE ALSO
+.Xr passwd 5 ,
+.Xr radius.conf 5 ,
+.Xr pam 8
+.Sh HISTORY
+The
+.Nm
+module first appeared in
+.Fx 3.1 .
+The
+.Nm
+manual page first appeared in
+.Fx 3.3 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+manual page was written by
+.An Andrzej Bialecki Aq abial@FreeBSD.org .
+.Pp
+The
+.Nm
+module was written by
+.An John D. Polstra Aq jdp@FreeBSD.org .
diff --git a/lib/libpam/modules/pam_radius/pam_radius.c b/lib/libpam/modules/pam_radius/pam_radius.c
new file mode 100644
index 0000000..511baf3
--- /dev/null
+++ b/lib/libpam/modules/pam_radius/pam_radius.c
@@ -0,0 +1,364 @@
+/*-
+ * Copyright 1998 Juniper Networks, Inc.
+ * All rights reserved.
+ * Copyright (c) 2001-2003 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 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/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <radlib.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#define PAM_SM_AUTH
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <security/pam_mod_misc.h>
+
+#define PAM_OPT_CONF "conf"
+#define PAM_OPT_TEMPLATE_USER "template_user"
+#define PAM_OPT_NAS_ID "nas_id"
+#define PAM_OPT_NAS_IPADDR "nas_ipaddr"
+
+#define MAX_CHALLENGE_MSGS 10
+#define PASSWORD_PROMPT "RADIUS Password:"
+
+static int build_access_request(struct rad_handle *, const char *,
+ const char *, const char *, const char *, const void *,
+ size_t);
+static int do_accept(pam_handle_t *, struct rad_handle *);
+static int do_challenge(pam_handle_t *, struct rad_handle *,
+ const char *);
+
+/*
+ * Construct an access request, but don't send it. Returns 0 on success,
+ * -1 on failure.
+ */
+static int
+build_access_request(struct rad_handle *radh, const char *user,
+ const char *pass, const char *nas_id, const char *nas_ipaddr,
+ const void *state, size_t state_len)
+{
+ int error;
+ char host[MAXHOSTNAMELEN];
+ struct sockaddr_in *haddr;
+ struct addrinfo hints;
+ struct addrinfo *res;
+
+ if (rad_create_request(radh, RAD_ACCESS_REQUEST) == -1) {
+ syslog(LOG_CRIT, "rad_create_request: %s", rad_strerror(radh));
+ return (-1);
+ }
+ if (nas_id == NULL ||
+ (nas_ipaddr != NULL && strlen(nas_ipaddr) == 0)) {
+ if (gethostname(host, sizeof host) != -1) {
+ if (nas_id == NULL)
+ nas_id = host;
+ if (nas_ipaddr != NULL && strlen(nas_ipaddr) == 0)
+ nas_ipaddr = host;
+ }
+ }
+ if ((user != NULL &&
+ rad_put_string(radh, RAD_USER_NAME, user) == -1) ||
+ (pass != NULL &&
+ rad_put_string(radh, RAD_USER_PASSWORD, pass) == -1) ||
+ (nas_id != NULL &&
+ rad_put_string(radh, RAD_NAS_IDENTIFIER, nas_id) == -1)) {
+ syslog(LOG_CRIT, "rad_put_string: %s", rad_strerror(radh));
+ return (-1);
+ }
+ if (nas_ipaddr != NULL) {
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET;
+ if (getaddrinfo(nas_ipaddr, NULL, &hints, &res) == 0 &&
+ res != NULL && res->ai_family == AF_INET) {
+ haddr = (struct sockaddr_in *)res->ai_addr;
+ error = rad_put_addr(radh, RAD_NAS_IP_ADDRESS,
+ haddr->sin_addr);
+ freeaddrinfo(res);
+ if (error == -1) {
+ syslog(LOG_CRIT, "rad_put_addr: %s",
+ rad_strerror(radh));
+ return (-1);
+ }
+ }
+ }
+ if (state != NULL && rad_put_attr(radh, RAD_STATE, state,
+ state_len) == -1) {
+ syslog(LOG_CRIT, "rad_put_attr: %s", rad_strerror(radh));
+ return (-1);
+ }
+ if (rad_put_int(radh, RAD_SERVICE_TYPE, RAD_AUTHENTICATE_ONLY) == -1) {
+ syslog(LOG_CRIT, "rad_put_int: %s", rad_strerror(radh));
+ return (-1);
+ }
+ return (0);
+}
+
+static int
+do_accept(pam_handle_t *pamh, struct rad_handle *radh)
+{
+ int attrtype;
+ const void *attrval;
+ size_t attrlen;
+ char *s;
+
+ while ((attrtype = rad_get_attr(radh, &attrval, &attrlen)) > 0) {
+ if (attrtype == RAD_USER_NAME) {
+ s = rad_cvt_string(attrval, attrlen);
+ if (s == NULL) {
+ syslog(LOG_CRIT,
+ "rad_cvt_string: out of memory");
+ return (-1);
+ }
+ pam_set_item(pamh, PAM_USER, s);
+ free(s);
+ }
+ }
+ if (attrtype == -1) {
+ syslog(LOG_CRIT, "rad_get_attr: %s", rad_strerror(radh));
+ return (-1);
+ }
+ return (0);
+}
+
+static int
+do_challenge(pam_handle_t *pamh, struct rad_handle *radh, const char *user)
+{
+ int retval;
+ int attrtype;
+ const void *attrval;
+ size_t attrlen;
+ const void *state;
+ size_t statelen;
+ struct pam_message msgs[MAX_CHALLENGE_MSGS];
+ const struct pam_message *msg_ptrs[MAX_CHALLENGE_MSGS];
+ struct pam_response *resp;
+ int num_msgs;
+ const void *item;
+ const struct pam_conv *conv;
+
+ state = NULL;
+ statelen = 0;
+ num_msgs = 0;
+ while ((attrtype = rad_get_attr(radh, &attrval, &attrlen)) > 0) {
+ switch (attrtype) {
+
+ case RAD_STATE:
+ state = attrval;
+ statelen = attrlen;
+ break;
+
+ case RAD_REPLY_MESSAGE:
+ if (num_msgs >= MAX_CHALLENGE_MSGS) {
+ syslog(LOG_CRIT,
+ "Too many RADIUS challenge messages");
+ return (PAM_SERVICE_ERR);
+ }
+ msgs[num_msgs].msg = rad_cvt_string(attrval, attrlen);
+ if (msgs[num_msgs].msg == NULL) {
+ syslog(LOG_CRIT,
+ "rad_cvt_string: out of memory");
+ return (PAM_SERVICE_ERR);
+ }
+ msgs[num_msgs].msg_style = PAM_TEXT_INFO;
+ msg_ptrs[num_msgs] = &msgs[num_msgs];
+ num_msgs++;
+ break;
+ }
+ }
+ if (attrtype == -1) {
+ syslog(LOG_CRIT, "rad_get_attr: %s", rad_strerror(radh));
+ return (PAM_SERVICE_ERR);
+ }
+ if (num_msgs == 0) {
+ msgs[num_msgs].msg = strdup("(null RADIUS challenge): ");
+ if (msgs[num_msgs].msg == NULL) {
+ syslog(LOG_CRIT, "Out of memory");
+ return (PAM_SERVICE_ERR);
+ }
+ msgs[num_msgs].msg_style = PAM_TEXT_INFO;
+ msg_ptrs[num_msgs] = &msgs[num_msgs];
+ num_msgs++;
+ }
+ msgs[num_msgs-1].msg_style = PAM_PROMPT_ECHO_ON;
+ if ((retval = pam_get_item(pamh, PAM_CONV, &item)) != PAM_SUCCESS) {
+ syslog(LOG_CRIT, "do_challenge: cannot get PAM_CONV");
+ return (retval);
+ }
+ conv = (const struct pam_conv *)item;
+ if ((retval = conv->conv(num_msgs, msg_ptrs, &resp,
+ conv->appdata_ptr)) != PAM_SUCCESS)
+ return (retval);
+ if (build_access_request(radh, user, resp[num_msgs-1].resp, NULL,
+ NULL, state, statelen) == -1)
+ return (PAM_SERVICE_ERR);
+ memset(resp[num_msgs-1].resp, 0, strlen(resp[num_msgs-1].resp));
+ free(resp[num_msgs-1].resp);
+ free(resp);
+ while (num_msgs > 0)
+ free(msgs[--num_msgs].msg);
+ return (PAM_SUCCESS);
+}
+
+PAM_EXTERN int
+pam_sm_authenticate(pam_handle_t *pamh, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+ struct rad_handle *radh;
+ const char *user, *pass;
+ const void *tmpuser;
+ const char *conf_file, *template_user, *nas_id, *nas_ipaddr;
+ int retval;
+ int e;
+
+ conf_file = openpam_get_option(pamh, PAM_OPT_CONF);
+ template_user = openpam_get_option(pamh, PAM_OPT_TEMPLATE_USER);
+ nas_id = openpam_get_option(pamh, PAM_OPT_NAS_ID);
+ nas_ipaddr = openpam_get_option(pamh, PAM_OPT_NAS_IPADDR);
+
+ retval = pam_get_user(pamh, &user, NULL);
+ if (retval != PAM_SUCCESS)
+ return (retval);
+
+ PAM_LOG("Got user: %s", user);
+
+ retval = pam_get_authtok(pamh, PAM_AUTHTOK, &pass, PASSWORD_PROMPT);
+ if (retval != PAM_SUCCESS)
+ return (retval);
+
+ PAM_LOG("Got password");
+
+ radh = rad_open();
+ if (radh == NULL) {
+ syslog(LOG_CRIT, "rad_open failed");
+ return (PAM_SERVICE_ERR);
+ }
+
+ PAM_LOG("Radius opened");
+
+ if (rad_config(radh, conf_file) == -1) {
+ syslog(LOG_ALERT, "rad_config: %s", rad_strerror(radh));
+ rad_close(radh);
+ return (PAM_SERVICE_ERR);
+ }
+
+ PAM_LOG("Radius config file read");
+
+ if (build_access_request(radh, user, pass, nas_id, nas_ipaddr, NULL,
+ 0) == -1) {
+ rad_close(radh);
+ return (PAM_SERVICE_ERR);
+ }
+
+ PAM_LOG("Radius build access done");
+
+ for (;;) {
+ switch (rad_send_request(radh)) {
+
+ case RAD_ACCESS_ACCEPT:
+ e = do_accept(pamh, radh);
+ rad_close(radh);
+ if (e == -1)
+ return (PAM_SERVICE_ERR);
+ if (template_user != NULL) {
+
+ PAM_LOG("Trying template user: %s",
+ template_user);
+
+ /*
+ * If the given user name doesn't exist in
+ * the local password database, change it
+ * to the value given in the "template_user"
+ * option.
+ */
+ retval = pam_get_item(pamh, PAM_USER, &tmpuser);
+ if (retval != PAM_SUCCESS)
+ return (retval);
+ if (getpwnam(tmpuser) == NULL) {
+ pam_set_item(pamh, PAM_USER,
+ template_user);
+ PAM_LOG("Using template user");
+ }
+
+ }
+ return (PAM_SUCCESS);
+
+ case RAD_ACCESS_REJECT:
+ rad_close(radh);
+ PAM_VERBOSE_ERROR("Radius rejection");
+ return (PAM_AUTH_ERR);
+
+ case RAD_ACCESS_CHALLENGE:
+ retval = do_challenge(pamh, radh, user);
+ if (retval != PAM_SUCCESS) {
+ rad_close(radh);
+ return (retval);
+ }
+ break;
+
+ case -1:
+ syslog(LOG_CRIT, "rad_send_request: %s",
+ rad_strerror(radh));
+ rad_close(radh);
+ PAM_VERBOSE_ERROR("Radius failure");
+ return (PAM_AUTHINFO_UNAVAIL);
+
+ default:
+ syslog(LOG_CRIT,
+ "rad_send_request: unexpected return value");
+ rad_close(radh);
+ PAM_VERBOSE_ERROR("Radius error");
+ return (PAM_SERVICE_ERR);
+ }
+ }
+}
+
+PAM_EXTERN int
+pam_sm_setcred(pam_handle_t *pamh __unused, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+
+ return (PAM_SUCCESS);
+}
+
+PAM_MODULE_ENTRY("pam_radius");
diff --git a/lib/libpam/modules/pam_rhosts/Makefile b/lib/libpam/modules/pam_rhosts/Makefile
new file mode 100644
index 0000000..866267e
--- /dev/null
+++ b/lib/libpam/modules/pam_rhosts/Makefile
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+LIB= pam_rhosts
+SRCS= pam_rhosts.c
+MAN= pam_rhosts.8
+
+.include <bsd.lib.mk>
diff --git a/lib/libpam/modules/pam_rhosts/pam_rhosts.8 b/lib/libpam/modules/pam_rhosts/pam_rhosts.8
new file mode 100644
index 0000000..8adfcc6
--- /dev/null
+++ b/lib/libpam/modules/pam_rhosts/pam_rhosts.8
@@ -0,0 +1,95 @@
+.\" Copyright (c) 2001 Mark R V Murray
+.\" All rights reserved.
+.\" Copyright (c) 2001 Networks Associates Technology, Inc.
+.\" All rights reserved.
+.\"
+.\" Portions of this software were developed for the FreeBSD Project by
+.\" ThinkSec AS 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING 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 5, 2001
+.Dt PAM_RHOSTS 8
+.Os
+.Sh NAME
+.Nm pam_rhosts
+.Nd Rhosts PAM module
+.Sh SYNOPSIS
+.Op Ar service-name
+.Ar module-type
+.Ar control-flag
+.Pa pam_rhosts
+.Op Ar options
+.Sh DESCRIPTION
+The rhosts authentication service module for PAM,
+.Nm
+provides functionality for only one PAM category:
+authentication.
+In terms of the
+.Ar module-type
+parameter, this is the
+.Dq Li auth
+feature.
+.Ss Rhosts Authentication Module
+The Rhosts authentication component
+.Pq Fn pam_sm_authenticate ,
+returns success if and only if the target user's UID is not 0 and the
+remote host and user are listed in
+.Pa /etc/hosts.equiv
+or in the target user's
+.Pa ~/.rhosts .
+.Pp
+The following options may be passed to the authentication module:
+.Bl -tag -width ".Cm allow_root"
+.It Cm debug
+.Xr syslog 3
+debugging information at
+.Dv LOG_DEBUG
+level.
+.It Cm no_warn
+suppress warning messages to the user.
+These messages include reasons why the user's authentication attempt
+was declined.
+.It Cm allow_root
+do not automatically fail if the target user's UID is 0.
+.El
+.Sh SEE ALSO
+.Xr hosts.equiv 5 ,
+.Xr pam.conf 5 ,
+.Xr pam 8
+.Sh AUTHORS
+The
+.Nm
+module and this manual page were developed for the
+.Fx
+Project by
+ThinkSec AS and NAI Labs, the Security Research Division of Network
+Associates, Inc.\& under DARPA/SPAWAR contract N66001-01-C-8035
+.Pq Dq CBOSS ,
+as part of the DARPA CHATS research program.
diff --git a/lib/libpam/modules/pam_rhosts/pam_rhosts.c b/lib/libpam/modules/pam_rhosts/pam_rhosts.c
new file mode 100644
index 0000000..4ba6ade
--- /dev/null
+++ b/lib/libpam/modules/pam_rhosts/pam_rhosts.c
@@ -0,0 +1,95 @@
+/*-
+ * Copyright (c) 2002 Danny Braniss
+ * All rights reserved.
+ * Copyright (c) 2001,2002 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <pwd.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
+
+#define PAM_SM_AUTH
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <security/pam_mod_misc.h>
+
+#define OPT_ALLOW_ROOT "allow_root"
+
+PAM_EXTERN int
+pam_sm_authenticate(pam_handle_t *pamh, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+ struct passwd *pw;
+ const char *user;
+ const void *ruser, *rhost;
+ int err, superuser;
+
+ err = pam_get_user(pamh, &user, NULL);
+ if (err != PAM_SUCCESS)
+ return (err);
+
+ if ((pw = getpwnam(user)) == NULL)
+ return (PAM_USER_UNKNOWN);
+ if (pw->pw_uid == 0 &&
+ openpam_get_option(pamh, OPT_ALLOW_ROOT) == NULL)
+ return (PAM_AUTH_ERR);
+
+ err = pam_get_item(pamh, PAM_RUSER, &ruser);
+ if (err != PAM_SUCCESS)
+ return (PAM_AUTH_ERR);
+
+ err = pam_get_item(pamh, PAM_RHOST, &rhost);
+ if (err != PAM_SUCCESS)
+ return (PAM_AUTH_ERR);
+
+ superuser = (strcmp(user, "root") == 0);
+ err = ruserok(rhost, superuser, ruser, user);
+ if (err != 0)
+ return (PAM_AUTH_ERR);
+
+ return (PAM_SUCCESS);
+}
+
+PAM_EXTERN int
+pam_sm_setcred(pam_handle_t *pamh __unused, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+
+ return (PAM_SUCCESS);
+}
+
+PAM_MODULE_ENTRY("pam_rhosts");
diff --git a/lib/libpam/modules/pam_rootok/Makefile b/lib/libpam/modules/pam_rootok/Makefile
new file mode 100644
index 0000000..8582daa
--- /dev/null
+++ b/lib/libpam/modules/pam_rootok/Makefile
@@ -0,0 +1,31 @@
+# Copyright 2001 Mark R V Murray
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+
+LIB= pam_rootok
+SRCS= pam_rootok.c
+MAN= pam_rootok.8
+
+.include <bsd.lib.mk>
diff --git a/lib/libpam/modules/pam_rootok/pam_rootok.8 b/lib/libpam/modules/pam_rootok/pam_rootok.8
new file mode 100644
index 0000000..4203fbd
--- /dev/null
+++ b/lib/libpam/modules/pam_rootok/pam_rootok.8
@@ -0,0 +1,75 @@
+.\" Copyright (c) 2001 Mark R V Murray
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING 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 8, 2001
+.Dt PAM_ROOTOK 8
+.Os
+.Sh NAME
+.Nm pam_rootok
+.Nd RootOK PAM module
+.Sh SYNOPSIS
+.Op Ar service-name
+.Ar module-type
+.Ar control-flag
+.Pa pam_rootok
+.Op Ar options
+.Sh DESCRIPTION
+The RootOK authentication service module for PAM,
+.Nm
+provides functionality for only one PAM category:
+authentication.
+In terms of the
+.Ar module-type
+parameter, this is the
+.Dq Li auth
+feature.
+It also provides a null function for session management.
+.Ss RootOK Authentication Module
+The RootOK authentication component
+.Pq Fn pam_sm_authenticate ,
+always returns success for the superuser;
+i.e.,
+if
+.Xr getuid 2
+returns 0.
+.Pp
+The following options may be passed to the authentication module:
+.Bl -tag -width ".Cm no_warn"
+.It Cm debug
+.Xr syslog 3
+debugging information at
+.Dv LOG_DEBUG
+level.
+.It Cm no_warn
+suppress warning messages to the user.
+These messages include
+reasons why the user's
+authentication attempt was declined.
+.El
+.Sh SEE ALSO
+.Xr getuid 2 ,
+.Xr pam.conf 5 ,
+.Xr pam 8
diff --git a/lib/libpam/modules/pam_rootok/pam_rootok.c b/lib/libpam/modules/pam_rootok/pam_rootok.c
new file mode 100644
index 0000000..16fab1f
--- /dev/null
+++ b/lib/libpam/modules/pam_rootok/pam_rootok.c
@@ -0,0 +1,73 @@
+/*-
+ * Copyright (c) 2001 Mark R V Murray
+ * All rights reserved.
+ * Copyright (c) 2001 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 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 _BSD_SOURCE
+
+#include <unistd.h>
+#include <syslog.h>
+
+#define PAM_SM_AUTH
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <security/pam_mod_misc.h>
+
+PAM_EXTERN int
+pam_sm_authenticate(pam_handle_t *pamh, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+
+ if (getuid() == 0)
+ return (PAM_SUCCESS);
+
+ PAM_VERBOSE_ERROR("Refused; not superuser");
+ PAM_LOG("User is not superuser");
+
+ return (PAM_AUTH_ERR);
+}
+
+PAM_EXTERN int
+pam_sm_setcred(pam_handle_t *pamh __unused, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+
+ return (PAM_SUCCESS);
+}
+
+PAM_MODULE_ENTRY("pam_rootok");
diff --git a/lib/libpam/modules/pam_securetty/Makefile b/lib/libpam/modules/pam_securetty/Makefile
new file mode 100644
index 0000000..8eb3e6e
--- /dev/null
+++ b/lib/libpam/modules/pam_securetty/Makefile
@@ -0,0 +1,31 @@
+# Copyright 2001 Mark R V Murray
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+
+LIB= pam_securetty
+SRCS= pam_securetty.c
+MAN= pam_securetty.8
+
+.include <bsd.lib.mk>
diff --git a/lib/libpam/modules/pam_securetty/pam_securetty.8 b/lib/libpam/modules/pam_securetty/pam_securetty.8
new file mode 100644
index 0000000..5825fb4
--- /dev/null
+++ b/lib/libpam/modules/pam_securetty/pam_securetty.8
@@ -0,0 +1,92 @@
+.\" Copyright (c) 2001 Mark R V Murray
+.\" All rights reserved.
+.\" Copyright (c) 2002 Networks Associates Technology, Inc.
+.\" All rights reserved.
+.\"
+.\" Portions of this software were developed for the FreeBSD Project by
+.\" ThinkSec AS 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING 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 8, 2001
+.Dt PAM_SECURETTY 8
+.Os
+.Sh NAME
+.Nm pam_securetty
+.Nd SecureTTY PAM module
+.Sh SYNOPSIS
+.Op Ar service-name
+.Ar module-type
+.Ar control-flag
+.Pa pam_securetty
+.Op Ar options
+.Sh DESCRIPTION
+The SecureTTY service module for PAM,
+.Nm
+provides functionality for only one PAM category:
+account management.
+In terms of the
+.Ar module-type
+parameter, this is the
+.Dq Li account
+feature.
+It also provides null functions for authentication and session
+management.
+.Ss SecureTTY Account Management Module
+The SecureTTY account management component
+.Pq Fn pam_sm_acct_mgmt ,
+returns failure if the user is attempting to authenticate as superuser,
+and the process is attached to an insecure TTY.
+In all other cases, the module returns success.
+.Pp
+A TTY is considered secure if it is listed in
+.Pa /etc/ttys
+and has the
+.Dv TTY_SECURE
+flag set.
+.Pp
+The following options may be passed to the authentication module:
+.Bl -tag -width ".Cm no_warn"
+.It Cm debug
+.Xr syslog 3
+debugging information at
+.Dv LOG_DEBUG
+level.
+.It Cm no_warn
+suppress warning messages to the user.
+These messages include
+reasons why the user's
+authentication attempt was declined.
+.El
+.Sh SEE ALSO
+.Xr getttynam 3 ,
+.Xr syslog 3 ,
+.Xr pam.conf 5 ,
+.Xr ttys 5 ,
+.Xr pam 8
diff --git a/lib/libpam/modules/pam_securetty/pam_securetty.c b/lib/libpam/modules/pam_securetty/pam_securetty.c
new file mode 100644
index 0000000..f58274a
--- /dev/null
+++ b/lib/libpam/modules/pam_securetty/pam_securetty.c
@@ -0,0 +1,96 @@
+/*-
+ * Copyright (c) 2001 Mark R V Murray
+ * All rights reserved.
+ * Copyright (c) 2001 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 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 <pwd.h>
+#include <ttyent.h>
+#include <string.h>
+
+#define PAM_SM_ACCOUNT
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <security/pam_mod_misc.h>
+
+#define TTY_PREFIX "/dev/"
+
+PAM_EXTERN int
+pam_sm_acct_mgmt(pam_handle_t *pamh __unused, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+ struct passwd *pwd;
+ struct ttyent *ty;
+ const char *user;
+ const void *tty;
+ int pam_err;
+
+ pam_err = pam_get_user(pamh, &user, NULL);
+ if (pam_err != PAM_SUCCESS)
+ return (pam_err);
+ if (user == NULL || (pwd = getpwnam(user)) == NULL)
+ return (PAM_SERVICE_ERR);
+
+ PAM_LOG("Got user: %s", user);
+
+ /* If the user is not root, secure ttys do not apply */
+ if (pwd->pw_uid != 0)
+ return (PAM_SUCCESS);
+
+ pam_err = pam_get_item(pamh, PAM_TTY, &tty);
+ if (pam_err != PAM_SUCCESS)
+ return (pam_err);
+
+ PAM_LOG("Got TTY: %s", (const char *)tty);
+
+ /* Ignore any "/dev/" on the PAM_TTY item */
+ if (tty != NULL && strncmp(TTY_PREFIX, tty, sizeof(TTY_PREFIX)) == 0) {
+ PAM_LOG("WARNING: PAM_TTY starts with " TTY_PREFIX);
+ tty = (const char *)tty + sizeof(TTY_PREFIX) - 1;
+ }
+
+ if (tty != NULL && (ty = getttynam(tty)) != NULL &&
+ (ty->ty_status & TTY_SECURE) != 0)
+ return (PAM_SUCCESS);
+
+ PAM_VERBOSE_ERROR("Not on secure TTY");
+ return (PAM_AUTH_ERR);
+}
+
+PAM_MODULE_ENTRY("pam_securetty");
diff --git a/lib/libpam/modules/pam_self/Makefile b/lib/libpam/modules/pam_self/Makefile
new file mode 100644
index 0000000..50718e1
--- /dev/null
+++ b/lib/libpam/modules/pam_self/Makefile
@@ -0,0 +1,31 @@
+# Copyright 2001 Mark R V Murray
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+
+LIB= pam_self
+SRCS= pam_self.c
+MAN= pam_self.8
+
+.include <bsd.lib.mk>
diff --git a/lib/libpam/modules/pam_self/pam_self.8 b/lib/libpam/modules/pam_self/pam_self.8
new file mode 100644
index 0000000..d021434
--- /dev/null
+++ b/lib/libpam/modules/pam_self/pam_self.8
@@ -0,0 +1,96 @@
+.\" Copyright (c) 2001 Mark R V Murray
+.\" All rights reserved.
+.\" Copyright (c) 2001 Networks Associates Technology, Inc.
+.\" All rights reserved.
+.\"
+.\" Portions of this software were developed for the FreeBSD Project by
+.\" ThinkSec AS 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING 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 5, 2001
+.Dt PAM_SELF 8
+.Os
+.Sh NAME
+.Nm pam_self
+.Nd Self PAM module
+.Sh SYNOPSIS
+.Op Ar service-name
+.Ar module-type
+.Ar control-flag
+.Pa pam_self
+.Op Ar options
+.Sh DESCRIPTION
+The Self authentication service module for PAM,
+.Nm
+provides functionality for only one PAM category:
+authentication.
+In terms of the
+.Ar module-type
+parameter, this is the
+.Dq Li auth
+feature.
+.Ss Self Authentication Module
+The Self authentication component
+.Pq Fn pam_sm_authenticate ,
+returns success if and only if the target user's user ID is identical
+with the current real user ID.
+If the current real user ID is zero, authentication will fail,
+unless the
+.Cm allow_root
+option was specified.
+.Pp
+The following options may be passed to the authentication module:
+.Bl -tag -width ".Cm allow_root"
+.It Cm debug
+.Xr syslog 3
+debugging information at
+.Dv LOG_DEBUG
+level.
+.It Cm no_warn
+suppress warning messages to the user.
+These messages include reasons why the user's authentication attempt
+was declined.
+.It Cm allow_root
+do not automatically fail if the current real user ID is 0.
+.El
+.Sh SEE ALSO
+.Xr getuid 2 ,
+.Xr pam.conf 5 ,
+.Xr pam 8
+.Sh AUTHORS
+The
+.Nm
+module and this manual page were developed for the
+.Fx
+Project by
+ThinkSec AS and NAI Labs, the Security Research Division of Network
+Associates, Inc.\& under DARPA/SPAWAR contract N66001-01-C-8035
+.Pq Dq CBOSS ,
+as part of the DARPA CHATS research program.
diff --git a/lib/libpam/modules/pam_self/pam_self.c b/lib/libpam/modules/pam_self/pam_self.c
new file mode 100644
index 0000000..63df46c
--- /dev/null
+++ b/lib/libpam/modules/pam_self/pam_self.c
@@ -0,0 +1,89 @@
+/*-
+ * Copyright (c) 2001 Mark R V Murray
+ * All rights reserved.
+ * Copyright (c) 2001,2002 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 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 _BSD_SOURCE
+
+#include <pwd.h>
+#include <unistd.h>
+#include <syslog.h>
+
+#define PAM_SM_AUTH
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <security/pam_mod_misc.h>
+
+#define OPT_ALLOW_ROOT "allow_root"
+
+PAM_EXTERN int
+pam_sm_authenticate(pam_handle_t *pamh, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+ struct passwd *pwd;
+ const char *luser;
+ int pam_err;
+ uid_t uid;
+
+ pam_err = pam_get_user(pamh, &luser, NULL);
+ if (pam_err != PAM_SUCCESS)
+ return (pam_err);
+ if (luser == NULL || (pwd = getpwnam(luser)) == NULL)
+ return (PAM_AUTH_ERR);
+
+ uid = getuid();
+ if (uid == 0 && !openpam_get_option(pamh, OPT_ALLOW_ROOT))
+ return (PAM_AUTH_ERR);
+
+ if (uid == (uid_t)pwd->pw_uid)
+ return (PAM_SUCCESS);
+
+ PAM_VERBOSE_ERROR("Refused; source and target users differ");
+
+ return (PAM_AUTH_ERR);
+}
+
+PAM_EXTERN int
+pam_sm_setcred(pam_handle_t *pamh __unused, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+
+ return (PAM_SUCCESS);
+}
+
+PAM_MODULE_ENTRY("pam_self");
diff --git a/lib/libpam/modules/pam_ssh/Makefile b/lib/libpam/modules/pam_ssh/Makefile
new file mode 100644
index 0000000..f7dcd0c
--- /dev/null
+++ b/lib/libpam/modules/pam_ssh/Makefile
@@ -0,0 +1,20 @@
+# PAM module for SSH
+# $FreeBSD$
+
+SSHDIR= ${.CURDIR}/../../../../crypto/openssh
+
+LIB= pam_ssh
+MAN= pam_ssh.8
+SRCS= pam_ssh.c
+
+WARNS?= 0
+CFLAGS+= -I${SSHDIR} -include ssh_namespace.h
+
+DPADD= ${LIBSSH} ${LIBCRYPTO} ${LIBCRYPT}
+LDADD= -lssh -lcrypto -lcrypt
+
+.include <bsd.lib.mk>
+
+.PATH: ${SSHDIR}
+
+${OBJS} ${POBJS} ${SOBJS}: ssh_namespace.h
diff --git a/lib/libpam/modules/pam_ssh/pam_ssh.8 b/lib/libpam/modules/pam_ssh/pam_ssh.8
new file mode 100644
index 0000000..07e3176
--- /dev/null
+++ b/lib/libpam/modules/pam_ssh/pam_ssh.8
@@ -0,0 +1,157 @@
+.\" Copyright (c) 2001 Mark R V Murray
+.\" All rights reserved.
+.\" Copyright (c) 2001-2003 Networks Associates Technology, Inc.
+.\" All rights reserved.
+.\"
+.\" This software was developed for the FreeBSD Project by ThinkSec AS 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING 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 26, 2001
+.Dt PAM_SSH 8
+.Os
+.Sh NAME
+.Nm pam_ssh
+.Nd authentication and session management with SSH private keys
+.Sh SYNOPSIS
+.Op Ar service-name
+.Ar module-type
+.Ar control-flag
+.Pa pam_ssh
+.Op Ar options
+.Sh DESCRIPTION
+The
+SSH
+authentication service module for PAM,
+.Nm
+provides functionality for two PAM categories:
+authentication
+and session management.
+In terms of the
+.Ar module-type
+parameter, they are the
+.Dq Li auth
+and
+.Dq Li session
+features.
+.Ss SSH Authentication Module
+The
+SSH
+authentication component
+provides a function to verify the identity of a user
+.Pq Fn pam_sm_authenticate ,
+by prompting the user for a passphrase and verifying that it can
+decrypt the target user's SSH key using that passphrase.
+.Pp
+The following options may be passed to the authentication module:
+.Bl -tag -width ".Cm use_first_pass"
+.It Cm use_first_pass
+If the authentication module
+is not the first in the stack,
+and a previous module
+obtained the user's password,
+that password is used
+to authenticate the user.
+If this fails,
+the authentication module returns failure
+without prompting the user for a password.
+This option has no effect
+if the authentication module
+is the first in the stack,
+or if no previous modules
+obtained the user's password.
+.It Cm try_first_pass
+This option is similar to the
+.Cm use_first_pass
+option,
+except that if the previously obtained password fails,
+the user is prompted for another password.
+.It Cm nullok
+Normally, keys with no passphrase are ignored for authentication
+purposes.
+If this option is set, keys with no passphrase will be taken into
+consideration, allowing the user to log in with a blank password.
+.El
+.Ss SSH Session Management Module
+The
+SSH
+session management component
+provides functions to initiate
+.Pq Fn pam_sm_open_session
+and terminate
+.Pq Fn pam_sm_close_session
+sessions.
+The
+.Fn pam_sm_open_session
+function starts an SSH agent,
+passing it any private keys it decrypted
+during the authentication phase,
+and sets the environment variables
+the agent specifies.
+The
+.Fn pam_sm_close_session
+function kills the previously started SSH agent
+by sending it a
+.Dv SIGTERM .
+.Pp
+The following options may be passed to the session management module:
+.Bl -tag -width ".Cm want_agent"
+.It Cm want_agent
+Start an agent even if no keys were decrypted during the
+authentication phase.
+.El
+.Sh FILES
+.Bl -tag -width ".Pa $HOME/.ssh/identity" -compact
+.It Pa $HOME/.ssh/identity
+SSH1 RSA key
+.It Pa $HOME/.ssh/id_rsa
+SSH2 RSA key
+.It Pa $HOME/.ssh/id_dsa
+SSH2 DSA key
+.El
+.Sh SEE ALSO
+.Xr ssh-agent 1 ,
+.Xr pam.conf 5 ,
+.Xr pam 8
+.Sh AUTHORS
+The
+.Nm
+module was originally written by
+.An -nosplit
+.An "Andrew J. Korty" Aq ajk@iu.edu .
+The current implementation was developed for the
+.Fx
+Project by
+ThinkSec AS and NAI Labs, the Security Research Division of Network
+Associates, Inc.\& under DARPA/SPAWAR contract N66001-01-C-8035
+.Pq Dq CBOSS ,
+as part of the DARPA CHATS research program.
+This manual page was written by
+.An "Mark R V Murray" Aq markm@FreeBSD.org .
diff --git a/lib/libpam/modules/pam_ssh/pam_ssh.c b/lib/libpam/modules/pam_ssh/pam_ssh.c
new file mode 100644
index 0000000..11ebfe8
--- /dev/null
+++ b/lib/libpam/modules/pam_ssh/pam_ssh.c
@@ -0,0 +1,424 @@
+/*-
+ * Copyright (c) 2003 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project by ThinkSec AS 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 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 <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#define PAM_SM_AUTH
+#define PAM_SM_SESSION
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <security/openpam.h>
+
+#include <openssl/evp.h>
+
+#include "key.h"
+#include "authfd.h"
+#include "authfile.h"
+
+extern char **environ;
+
+struct pam_ssh_key {
+ Key *key;
+ char *comment;
+};
+
+static const char *pam_ssh_prompt = "SSH passphrase: ";
+static const char *pam_ssh_have_keys = "pam_ssh_have_keys";
+
+static const char *pam_ssh_keyfiles[] = {
+ ".ssh/identity", /* SSH1 RSA key */
+ ".ssh/id_rsa", /* SSH2 RSA key */
+ ".ssh/id_dsa", /* SSH2 DSA key */
+ NULL
+};
+
+static const char *pam_ssh_agent = "/usr/bin/ssh-agent";
+static char *const pam_ssh_agent_argv[] = { "ssh_agent", "-s", NULL };
+static char *const pam_ssh_agent_envp[] = { NULL };
+
+/*
+ * Attempts to load a private key from the specified file in the specified
+ * directory, using the specified passphrase. If successful, returns a
+ * struct pam_ssh_key containing the key and its comment.
+ */
+static struct pam_ssh_key *
+pam_ssh_load_key(const char *dir, const char *kfn, const char *passphrase)
+{
+ struct pam_ssh_key *psk;
+ char fn[PATH_MAX];
+ char *comment;
+ Key *key;
+
+ if (snprintf(fn, sizeof(fn), "%s/%s", dir, kfn) > (int)sizeof(fn))
+ return (NULL);
+ comment = NULL;
+ key = key_load_private(fn, passphrase, &comment);
+ if (key == NULL) {
+ openpam_log(PAM_LOG_DEBUG, "failed to load key from %s\n", fn);
+ return (NULL);
+ }
+
+ openpam_log(PAM_LOG_DEBUG, "loaded '%s' from %s\n", comment, fn);
+ if ((psk = malloc(sizeof(*psk))) == NULL) {
+ key_free(key);
+ free(comment);
+ return (NULL);
+ }
+ psk->key = key;
+ psk->comment = comment;
+ return (psk);
+}
+
+/*
+ * Wipes a private key and frees the associated resources.
+ */
+static void
+pam_ssh_free_key(pam_handle_t *pamh __unused,
+ void *data, int pam_err __unused)
+{
+ struct pam_ssh_key *psk;
+
+ psk = data;
+ key_free(psk->key);
+ free(psk->comment);
+ free(psk);
+}
+
+PAM_EXTERN int
+pam_sm_authenticate(pam_handle_t *pamh, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+ const char **kfn, *passphrase, *user;
+ const void *item;
+ struct passwd *pwd;
+ struct pam_ssh_key *psk;
+ int nkeys, nullok, pam_err, pass;
+
+ nullok = (openpam_get_option(pamh, "nullok") != NULL);
+
+ /* PEM is not loaded by default */
+ OpenSSL_add_all_algorithms();
+
+ /* get user name and home directory */
+ pam_err = pam_get_user(pamh, &user, NULL);
+ if (pam_err != PAM_SUCCESS)
+ return (pam_err);
+ pwd = getpwnam(user);
+ if (pwd == NULL)
+ return (PAM_USER_UNKNOWN);
+ if (pwd->pw_dir == NULL)
+ return (PAM_AUTH_ERR);
+
+ nkeys = 0;
+ pass = (pam_get_item(pamh, PAM_AUTHTOK, &item) == PAM_SUCCESS &&
+ item != NULL);
+ load_keys:
+ /* get passphrase */
+ pam_err = pam_get_authtok(pamh, PAM_AUTHTOK,
+ &passphrase, pam_ssh_prompt);
+ if (pam_err != PAM_SUCCESS)
+ return (pam_err);
+
+ if (*passphrase == '\0' && !nullok)
+ goto skip_keys;
+
+ /* switch to user credentials */
+ pam_err = openpam_borrow_cred(pamh, pwd);
+ if (pam_err != PAM_SUCCESS)
+ return (pam_err);
+
+ /* try to load keys from all keyfiles we know of */
+ for (kfn = pam_ssh_keyfiles; *kfn != NULL; ++kfn) {
+ psk = pam_ssh_load_key(pwd->pw_dir, *kfn, passphrase);
+ if (psk != NULL) {
+ pam_set_data(pamh, *kfn, psk, pam_ssh_free_key);
+ ++nkeys;
+ }
+ }
+
+ /* switch back to arbitrator credentials */
+ openpam_restore_cred(pamh);
+
+ skip_keys:
+ /*
+ * If we tried an old token and didn't get anything, and
+ * try_first_pass was specified, try again after prompting the
+ * user for a new passphrase.
+ */
+ if (nkeys == 0 && pass == 1 &&
+ openpam_get_option(pamh, "try_first_pass") != NULL) {
+ pam_set_item(pamh, PAM_AUTHTOK, NULL);
+ pass = 0;
+ goto load_keys;
+ }
+
+ /* no keys? */
+ if (nkeys == 0)
+ return (PAM_AUTH_ERR);
+
+ pam_set_data(pamh, pam_ssh_have_keys, NULL, NULL);
+ return (PAM_SUCCESS);
+}
+
+PAM_EXTERN int
+pam_sm_setcred(pam_handle_t *pamh __unused, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+
+ return (PAM_SUCCESS);
+}
+
+/*
+ * Parses a line from ssh-agent's output.
+ */
+static void
+pam_ssh_process_agent_output(pam_handle_t *pamh, FILE *f)
+{
+ char *line, *p, *key, *val;
+ size_t len;
+
+ while ((line = fgetln(f, &len)) != NULL) {
+ if (len < 4 || strncmp(line, "SSH_", 4) != 0)
+ continue;
+
+ /* find equal sign at end of key */
+ for (p = key = line; p < line + len; ++p)
+ if (*p == '=')
+ break;
+ if (p == line + len || *p != '=')
+ continue;
+ *p = '\0';
+
+ /* find semicolon at end of value */
+ for (val = ++p; p < line + len; ++p)
+ if (*p == ';')
+ break;
+ if (p == line + len || *p != ';')
+ continue;
+ *p = '\0';
+
+ /* store key-value pair in environment */
+ openpam_log(PAM_LOG_DEBUG, "got %s: %s", key, val);
+ pam_setenv(pamh, key, val, 1);
+ }
+}
+
+/*
+ * Starts an ssh agent and stores the environment variables derived from
+ * its output.
+ */
+static int
+pam_ssh_start_agent(pam_handle_t *pamh)
+{
+ int agent_pipe[2];
+ pid_t pid;
+ FILE *f;
+
+ /* get a pipe which we will use to read the agent's output */
+ if (pipe(agent_pipe) == -1)
+ return (PAM_SYSTEM_ERR);
+
+ /* start the agent */
+ openpam_log(PAM_LOG_DEBUG, "starting an ssh agent");
+ pid = fork();
+ if (pid == (pid_t)-1) {
+ /* failed */
+ close(agent_pipe[0]);
+ close(agent_pipe[1]);
+ return (PAM_SYSTEM_ERR);
+ }
+ if (pid == 0) {
+ int fd;
+
+ /* child: drop privs, close fds and start agent */
+ setgid(getegid());
+ setuid(geteuid());
+ close(STDIN_FILENO);
+ open(_PATH_DEVNULL, O_RDONLY);
+ dup2(agent_pipe[1], STDOUT_FILENO);
+ dup2(agent_pipe[1], STDERR_FILENO);
+ for (fd = 3; fd < getdtablesize(); ++fd)
+ close(fd);
+ execve(pam_ssh_agent, pam_ssh_agent_argv, pam_ssh_agent_envp);
+ _exit(127);
+ }
+
+ /* parent */
+ close(agent_pipe[1]);
+ if ((f = fdopen(agent_pipe[0], "r")) == NULL)
+ return (PAM_SYSTEM_ERR);
+ pam_ssh_process_agent_output(pamh, f);
+ fclose(f);
+
+ return (PAM_SUCCESS);
+}
+
+/*
+ * Adds previously stored keys to a running agent.
+ */
+static int
+pam_ssh_add_keys_to_agent(pam_handle_t *pamh)
+{
+ AuthenticationConnection *ac;
+ struct pam_ssh_key *psk;
+ const char **kfn;
+ void *item;
+ char **envlist, **env;
+ int pam_err;
+
+ /* switch to PAM environment */
+ envlist = environ;
+ if ((environ = pam_getenvlist(pamh)) == NULL) {
+ environ = envlist;
+ return (PAM_SYSTEM_ERR);
+ }
+
+ /* get a connection to the agent */
+ if ((ac = ssh_get_authentication_connection()) == NULL) {
+ pam_err = PAM_SYSTEM_ERR;
+ goto end;
+ }
+
+ /* look for keys to add to it */
+ for (kfn = pam_ssh_keyfiles; *kfn != NULL; ++kfn) {
+ pam_err = pam_get_data(pamh, *kfn, &item);
+ if (pam_err == PAM_SUCCESS && item != NULL) {
+ psk = item;
+ if (ssh_add_identity(ac, psk->key, psk->comment))
+ openpam_log(PAM_LOG_DEBUG,
+ "added %s to ssh agent", psk->comment);
+ else
+ openpam_log(PAM_LOG_DEBUG, "failed "
+ "to add %s to ssh agent", psk->comment);
+ /* we won't need the key again, so wipe it */
+ pam_set_data(pamh, *kfn, NULL, NULL);
+ }
+ }
+ pam_err = PAM_SUCCESS;
+ end:
+ /* disconnect from agent */
+ if (ac != NULL)
+ ssh_close_authentication_connection(ac);
+
+ /* switch back to original environment */
+ for (env = environ; *env != NULL; ++env)
+ free(*env);
+ free(environ);
+ environ = envlist;
+
+ return (pam_err);
+}
+
+PAM_EXTERN int
+pam_sm_open_session(pam_handle_t *pamh, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+ struct passwd *pwd;
+ const char *user;
+ void *data;
+ int pam_err;
+
+ /* no keys, no work */
+ if (pam_get_data(pamh, pam_ssh_have_keys, &data) != PAM_SUCCESS &&
+ openpam_get_option(pamh, "want_agent") == NULL)
+ return (PAM_SUCCESS);
+
+ /* switch to user credentials */
+ pam_err = pam_get_user(pamh, &user, NULL);
+ if (pam_err != PAM_SUCCESS)
+ return (pam_err);
+ pwd = getpwnam(user);
+ if (pwd == NULL)
+ return (PAM_USER_UNKNOWN);
+ pam_err = openpam_borrow_cred(pamh, pwd);
+ if (pam_err != PAM_SUCCESS)
+ return (pam_err);
+
+ /* start the agent */
+ pam_err = pam_ssh_start_agent(pamh);
+ if (pam_err != PAM_SUCCESS) {
+ openpam_restore_cred(pamh);
+ return (pam_err);
+ }
+
+ /* we have an agent, see if we can add any keys to it */
+ pam_err = pam_ssh_add_keys_to_agent(pamh);
+ if (pam_err != PAM_SUCCESS) {
+ /* XXX ignore failures */
+ }
+
+ openpam_restore_cred(pamh);
+ return (PAM_SUCCESS);
+}
+
+PAM_EXTERN int
+pam_sm_close_session(pam_handle_t *pamh, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+ const char *ssh_agent_pid;
+ char *end;
+ int status;
+ pid_t pid;
+
+ if ((ssh_agent_pid = pam_getenv(pamh, "SSH_AGENT_PID")) == NULL) {
+ openpam_log(PAM_LOG_DEBUG, "no ssh agent");
+ return (PAM_SUCCESS);
+ }
+ pid = (pid_t)strtol(ssh_agent_pid, &end, 10);
+ if (*ssh_agent_pid == '\0' || *end != '\0') {
+ openpam_log(PAM_LOG_DEBUG, "invalid ssh agent pid");
+ return (PAM_SESSION_ERR);
+ }
+ openpam_log(PAM_LOG_DEBUG, "killing ssh agent %d", (int)pid);
+ if (kill(pid, SIGTERM) == -1 ||
+ (waitpid(pid, &status, 0) == -1 && errno != ECHILD))
+ return (PAM_SYSTEM_ERR);
+ return (PAM_SUCCESS);
+}
+
+PAM_MODULE_ENTRY("pam_ssh");
diff --git a/lib/libpam/modules/pam_tacplus/Makefile b/lib/libpam/modules/pam_tacplus/Makefile
new file mode 100644
index 0000000..053812a
--- /dev/null
+++ b/lib/libpam/modules/pam_tacplus/Makefile
@@ -0,0 +1,34 @@
+# Copyright 1998 Juniper Networks, Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+
+LIB= pam_tacplus
+SRCS= pam_tacplus.c
+MAN= pam_tacplus.8
+
+DPADD= ${LIBTACPLUS}
+LDADD= -ltacplus
+
+.include <bsd.lib.mk>
diff --git a/lib/libpam/modules/pam_tacplus/pam_tacplus.8 b/lib/libpam/modules/pam_tacplus/pam_tacplus.8
new file mode 100644
index 0000000..03faf0c
--- /dev/null
+++ b/lib/libpam/modules/pam_tacplus/pam_tacplus.8
@@ -0,0 +1,130 @@
+.\" Copyright (c) 1999
+.\" Andrzej Bialecki <abial@FreeBSD.org>. All rights reserved.
+.\"
+.\" Copyright (c) 1992, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software donated 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. 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd August 2, 1999
+.Dt PAM_TACPLUS 8
+.Os
+.Sh NAME
+.Nm pam_tacplus
+.Nd TACACS+ authentication PAM module
+.Sh SYNOPSIS
+.Op Ar service-name
+.Ar module-type
+.Ar control-flag
+.Pa pam_tacplus
+.Op Ar options
+.Sh DESCRIPTION
+The
+.Nm
+module provides authentication services based
+upon the TACACS+ protocol
+for the PAM (Pluggable Authentication Module) framework.
+.Pp
+The
+.Nm
+module accepts these optional parameters:
+.Bl -tag -width ".Cm use_first_pass"
+.It Cm use_first_pass
+causes
+.Nm
+to use a previously entered password instead of prompting for a new one.
+If no password has been entered then authentication fails.
+.It Cm try_first_pass
+causes
+.Nm
+to use a previously entered password, if one is available.
+If no
+password has been entered,
+.Nm
+prompts for one as usual.
+.It Cm echo_pass
+causes echoing to be left on if
+.Nm
+prompts for a password.
+.It Cm conf Ns = Ns Ar pathname
+specifies a non-standard location for the TACACS+ client configuration file
+(normally located in
+.Pa /etc/tacplus.conf ) .
+.It Cm template_user Ns = Ns Ar username
+specifies a user whose
+.Xr passwd 5
+entry will be used as a template to create the session environment
+if the supplied username does not exist in local password database.
+The user
+will be authenticated with the supplied username and password, but his
+credentials to the system will be presented as the ones for
+.Ar username ,
+i.e., his login class, home directory, resource limits, etc.\& will be set to ones
+defined for
+.Ar username .
+.Pp
+If this option is omitted, and there is no username
+in the system databases equal to the supplied one (as determined by call to
+.Xr getpwnam 3 ) ,
+the authentication will fail.
+.El
+.Sh FILES
+.Bl -tag -width /etc/tacplus.conf -compact
+.It Pa /etc/tacplus.conf
+The standard TACACS+ client configuration file for
+.Nm
+.El
+.Sh SEE ALSO
+.Xr passwd 5 ,
+.Xr tacplus.conf 5 ,
+.Xr pam 8
+.Sh HISTORY
+The
+.Nm
+module first appeared in
+.Fx 3.1 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+manual page was written by
+.An Andrzej Bialecki Aq abial@FreeBSD.org
+and adapted to TACACS+ from RADIUS by
+.An Mark R V Murray Aq markm@FreeBSD.org .
+.Pp
+The
+.Nm
+module was written by
+.An John D. Polstra Aq jdp@FreeBSD.org .
diff --git a/lib/libpam/modules/pam_tacplus/pam_tacplus.c b/lib/libpam/modules/pam_tacplus/pam_tacplus.c
new file mode 100644
index 0000000..7f860c3
--- /dev/null
+++ b/lib/libpam/modules/pam_tacplus/pam_tacplus.c
@@ -0,0 +1,281 @@
+/*-
+ * Copyright 1998 Juniper Networks, Inc.
+ * All rights reserved.
+ * Copyright (c) 2001-2003 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 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 <pwd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <taclib.h>
+#include <unistd.h>
+
+#define PAM_SM_AUTH
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <security/pam_mod_misc.h>
+
+#define PAM_OPT_CONF "conf"
+#define PAM_OPT_TEMPLATE_USER "template_user"
+
+typedef int (*set_func)(struct tac_handle *, const char *);
+
+static int do_item(pam_handle_t *, struct tac_handle *, int,
+ set_func, const char *);
+static char *get_msg(struct tac_handle *);
+static int set_msg(struct tac_handle *, const char *);
+
+static int
+do_item(pam_handle_t *pamh, struct tac_handle *tach, int item,
+ set_func func, const char *funcname)
+{
+ int retval;
+ const void *value;
+
+ retval = pam_get_item(pamh, item, &value);
+ if (retval != PAM_SUCCESS)
+ return retval;
+ if (value != NULL && (*func)(tach, (const char *)value) == -1) {
+ syslog(LOG_CRIT, "%s: %s", funcname, tac_strerror(tach));
+ tac_close(tach);
+ return PAM_SERVICE_ERR;
+ }
+ return PAM_SUCCESS;
+}
+
+static char *
+get_msg(struct tac_handle *tach)
+{
+ char *msg;
+
+ msg = tac_get_msg(tach);
+ if (msg == NULL) {
+ syslog(LOG_CRIT, "tac_get_msg: %s", tac_strerror(tach));
+ tac_close(tach);
+ return NULL;
+ }
+ return msg;
+}
+
+static int
+set_msg(struct tac_handle *tach, const char *msg)
+{
+ if (tac_set_msg(tach, msg) == -1) {
+ syslog(LOG_CRIT, "tac_set_msg: %s", tac_strerror(tach));
+ tac_close(tach);
+ return -1;
+ }
+ return 0;
+}
+
+PAM_EXTERN int
+pam_sm_authenticate(pam_handle_t *pamh, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+ int retval;
+ struct tac_handle *tach;
+ const char *conf_file, *template_user;
+
+ conf_file = openpam_get_option(pamh, PAM_OPT_CONF);
+ template_user = openpam_get_option(pamh, PAM_OPT_TEMPLATE_USER);
+
+ tach = tac_open();
+ if (tach == NULL) {
+ syslog(LOG_CRIT, "tac_open failed");
+ return (PAM_SERVICE_ERR);
+ }
+ if (tac_config(tach, conf_file) == -1) {
+ syslog(LOG_ALERT, "tac_config: %s", tac_strerror(tach));
+ tac_close(tach);
+ return (PAM_SERVICE_ERR);
+ }
+ if (tac_create_authen(tach, TAC_AUTHEN_LOGIN, TAC_AUTHEN_TYPE_ASCII,
+ TAC_AUTHEN_SVC_LOGIN) == -1) {
+ syslog(LOG_CRIT, "tac_create_authen: %s", tac_strerror(tach));
+ tac_close(tach);
+ return (PAM_SERVICE_ERR);
+ }
+
+ PAM_LOG("Done tac_open() ... tac_close()");
+
+ retval = do_item(pamh, tach, PAM_USER, tac_set_user, "tac_set_user");
+ if (retval != PAM_SUCCESS)
+ return (retval);
+
+ PAM_LOG("Done user");
+
+ retval = do_item(pamh, tach, PAM_TTY, tac_set_port, "tac_set_port");
+ if (retval != PAM_SUCCESS)
+ return (retval);
+
+ PAM_LOG("Done tty");
+
+ retval = do_item(pamh, tach, PAM_RHOST, tac_set_rem_addr,
+ "tac_set_rem_addr");
+ if (retval != PAM_SUCCESS)
+ return (retval);
+
+ for (;;) {
+ char *srvr_msg;
+ size_t msg_len;
+ const char *user_msg;
+ char *data_msg;
+ int sflags;
+ int status;
+
+ sflags = tac_send_authen(tach);
+ if (sflags == -1) {
+ syslog(LOG_CRIT, "tac_send_authen: %s",
+ tac_strerror(tach));
+ tac_close(tach);
+ return (PAM_AUTHINFO_UNAVAIL);
+ }
+ status = TAC_AUTHEN_STATUS(sflags);
+ openpam_set_option(pamh, PAM_OPT_ECHO_PASS,
+ TAC_AUTHEN_NOECHO(sflags) ? NULL : "");
+ switch (status) {
+
+ case TAC_AUTHEN_STATUS_PASS:
+ tac_close(tach);
+ if (template_user != NULL) {
+ const void *item;
+ const char *user;
+
+ PAM_LOG("Trying template user: %s",
+ template_user);
+
+ /*
+ * If the given user name doesn't exist in
+ * the local password database, change it
+ * to the value given in the "template_user"
+ * option.
+ */
+ retval = pam_get_item(pamh, PAM_USER, &item);
+ if (retval != PAM_SUCCESS)
+ return (retval);
+ user = (const char *)item;
+ if (getpwnam(user) == NULL) {
+ pam_set_item(pamh, PAM_USER,
+ template_user);
+ PAM_LOG("Using template user");
+ }
+ }
+ return (PAM_SUCCESS);
+
+ case TAC_AUTHEN_STATUS_FAIL:
+ tac_close(tach);
+ PAM_VERBOSE_ERROR("TACACS+ authentication failed");
+ return (PAM_AUTH_ERR);
+
+ case TAC_AUTHEN_STATUS_GETUSER:
+ case TAC_AUTHEN_STATUS_GETPASS:
+ if ((srvr_msg = get_msg(tach)) == NULL)
+ return (PAM_SERVICE_ERR);
+ if (status == TAC_AUTHEN_STATUS_GETUSER)
+ retval = pam_get_user(pamh, &user_msg,
+ *srvr_msg ? srvr_msg : NULL);
+ else if (status == TAC_AUTHEN_STATUS_GETPASS)
+ retval = pam_get_authtok(pamh,
+ PAM_AUTHTOK, &user_msg,
+ *srvr_msg ? srvr_msg : "Password:");
+ free(srvr_msg);
+ if (retval != PAM_SUCCESS) {
+ /* XXX - send a TACACS+ abort packet */
+ tac_close(tach);
+ return (retval);
+ }
+ if (set_msg(tach, user_msg) == -1)
+ return (PAM_SERVICE_ERR);
+ break;
+
+ case TAC_AUTHEN_STATUS_GETDATA:
+ if ((srvr_msg = get_msg(tach)) == NULL)
+ return (PAM_SERVICE_ERR);
+ retval = pam_prompt(pamh,
+ openpam_get_option(pamh, PAM_OPT_ECHO_PASS) ?
+ PAM_PROMPT_ECHO_ON : PAM_PROMPT_ECHO_OFF,
+ &data_msg, "%s", *srvr_msg ? srvr_msg : "Data:");
+ free(srvr_msg);
+ if (retval != PAM_SUCCESS) {
+ /* XXX - send a TACACS+ abort packet */
+ tac_close(tach);
+ return (retval);
+ }
+ retval = set_msg(tach, data_msg);
+ memset(data_msg, 0, strlen(data_msg));
+ free(data_msg);
+ if (retval == -1)
+ return (PAM_SERVICE_ERR);
+ break;
+
+ case TAC_AUTHEN_STATUS_ERROR:
+ srvr_msg = (char *)tac_get_data(tach, &msg_len);
+ if (srvr_msg != NULL && msg_len != 0) {
+ syslog(LOG_CRIT, "tac_send_authen:"
+ " server detected error: %s", srvr_msg);
+ free(srvr_msg);
+ }
+ else
+ syslog(LOG_CRIT,
+ "tac_send_authen: server detected error");
+ tac_close(tach);
+ return (PAM_AUTHINFO_UNAVAIL);
+ break;
+
+ case TAC_AUTHEN_STATUS_RESTART:
+ case TAC_AUTHEN_STATUS_FOLLOW:
+ default:
+ syslog(LOG_CRIT,
+ "tac_send_authen: unexpected status %#x", status);
+ tac_close(tach);
+ return (PAM_AUTHINFO_UNAVAIL);
+ }
+ }
+}
+
+PAM_EXTERN int
+pam_sm_setcred(pam_handle_t *pamh __unused, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+
+ return (PAM_IGNORE);
+}
+
+PAM_MODULE_ENTRY("pam_tacplus");
diff --git a/lib/libpam/modules/pam_unix/Makefile b/lib/libpam/modules/pam_unix/Makefile
new file mode 100644
index 0000000..fd48360
--- /dev/null
+++ b/lib/libpam/modules/pam_unix/Makefile
@@ -0,0 +1,53 @@
+# Copyright 1998 Juniper Networks, Inc.
+# All rights reserved.
+# Copyright (c) 2002 Networks Associates Technology, Inc.
+# All rights reserved.
+#
+# Portions of this software was developed for the FreeBSD Project by
+# ThinkSec AS 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+
+NO_PROFILE=
+.include <bsd.own.mk>
+
+LIB= pam_unix
+SRCS= pam_unix.c
+MAN= pam_unix.8
+
+DPADD= ${LIBUTIL} ${LIBCRYPT}
+LDADD= -lutil -lcrypt
+
+.if ${MK_NIS} != "no"
+CFLAGS+= -DYP
+DPADD+= ${LIBYPCLNT}
+LDADD+= -lypclnt
+.endif
+
+.include <bsd.lib.mk>
diff --git a/lib/libpam/modules/pam_unix/pam_unix.8 b/lib/libpam/modules/pam_unix/pam_unix.8
new file mode 100644
index 0000000..e1ccab6
--- /dev/null
+++ b/lib/libpam/modules/pam_unix/pam_unix.8
@@ -0,0 +1,201 @@
+.\" Copyright (c) 2001 Mark R V Murray
+.\" All rights reserved.
+.\" Copyright (c) 2001 Networks Associates Technology, Inc.
+.\" All rights reserved.
+.\"
+.\" This software was developed for the FreeBSD Project by ThinkSec AS 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING 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 26, 2001
+.Dt PAM_UNIX 8
+.Os
+.Sh NAME
+.Nm pam_unix
+.Nd UNIX PAM module
+.Sh SYNOPSIS
+.Op Ar service-name
+.Ar module-type
+.Ar control-flag
+.Pa pam_unix
+.Op Ar options
+.Sh DESCRIPTION
+The
+.Ux
+authentication service module for PAM,
+.Nm
+provides functionality for two PAM categories:
+authentication
+and account management.
+In terms of the
+.Ar module-type
+parameter, they are the
+.Dq Li auth
+and
+.Dq Li account
+features.
+It also provides a null function for session management.
+.Ss Ux Ss Authentication Module
+The
+.Ux
+authentication component
+provides functions to verify the identity of a user
+.Pq Fn pam_sm_authenticate ,
+which obtains the relevant
+.Xr passwd 5
+entry.
+It prompts the user for a password
+and verifies that this is correct with
+.Xr crypt 3 .
+.Pp
+The following options may be passed to the authentication module:
+.Bl -tag -width ".Cm use_first_pass"
+.It Cm debug
+.Xr syslog 3
+debugging information at
+.Dv LOG_DEBUG
+level.
+.It Cm use_first_pass
+If the authentication module
+is not the first in the stack,
+and a previous module
+obtained the user's password,
+that password is used
+to authenticate the user.
+If this fails,
+the authentication module returns failure
+without prompting the user for a password.
+This option has no effect
+if the authentication module
+is the first in the stack,
+or if no previous modules
+obtained the user's password.
+.It Cm try_first_pass
+This option is similar to the
+.Cm use_first_pass
+option,
+except that if the previously obtained password fails,
+the user is prompted for another password.
+.It Cm auth_as_self
+This option will require the user
+to authenticate himself as the user
+given by
+.Xr getlogin 2 ,
+not as the account they are attempting to access.
+This is primarily for services like
+.Xr su 1 ,
+where the user's ability to retype
+their own password
+might be deemed sufficient.
+.It Cm nullok
+If the password database
+has no password
+for the entity being authenticated,
+then this option
+will forgo password prompting,
+and silently allow authentication to succeed.
+.It Cm local_pass
+Use only the local password database,
+even if NIS is in use.
+This will cause an authentication failure
+if the system is configured
+to only use NIS.
+.It Cm nis_pass
+Use only the NIS password database.
+This will cause an authentication failure
+if the system is not configured
+to use NIS.
+.El
+.Ss Ux Ss Account Management Module
+The
+.Ux
+account management component
+provides a function to perform account management,
+.Fn pam_sm_acct_mgmt .
+The function verifies
+that the authenticated user
+is allowed to login to the local user account
+by checking the password expiry date.
+.Pp
+The following options may be passed to the management module:
+.Bl -tag -width ".Cm use_first_pass"
+.It Cm debug
+.Xr syslog 3
+debugging information at
+.Dv LOG_DEBUG
+level.
+.El
+.Ss Ux Ss Password Management Module
+The
+.Ux
+password management component
+provides a function to perform account management,
+.Fn pam_sm_chauthtok .
+The function changes
+the user's password.
+.Pp
+The following options may be passed to the password module:
+.Bl -tag -width ".Cm use_first_pass"
+.It Cm debug
+.Xr syslog 3
+debugging information at
+.Dv LOG_DEBUG
+level.
+.It Cm no_warn
+suppress warning messages to the user.
+These messages include
+reasons why the user's
+authentication attempt was declined.
+.It Cm local_pass
+forces the password module
+to change a local password
+in favour of a NIS one.
+.It Cm nis_pass
+forces the password module
+to change a NIS password
+in favour of a local one.
+.El
+.Sh FILES
+.Bl -tag -width ".Pa /etc/master.passwd" -compact
+.It Pa /etc/master.passwd
+default
+.Ux
+password database.
+.El
+.Sh SEE ALSO
+.Xr passwd 1 ,
+.Xr getlogin 2 ,
+.Xr crypt 3 ,
+.Xr getpwent 3 ,
+.Xr syslog 3 ,
+.Xr nsswitch.conf 5 ,
+.Xr passwd 5 ,
+.Xr pam 8 ,
+.Xr yp 8
diff --git a/lib/libpam/modules/pam_unix/pam_unix.c b/lib/libpam/modules/pam_unix/pam_unix.c
new file mode 100644
index 0000000..26084ec
--- /dev/null
+++ b/lib/libpam/modules/pam_unix/pam_unix.c
@@ -0,0 +1,465 @@
+/*-
+ * Copyright 1998 Juniper Networks, Inc.
+ * All rights reserved.
+ * Copyright (c) 2002-2003 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software was developed for the FreeBSD Project by
+ * ThinkSec AS 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 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 <sys/time.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <login_cap.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include <libutil.h>
+
+#ifdef YP
+#include <ypclnt.h>
+#endif
+
+#define PAM_SM_AUTH
+#define PAM_SM_ACCOUNT
+#define PAM_SM_PASSWORD
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <security/pam_mod_misc.h>
+
+#define PASSWORD_HASH "md5"
+#define DEFAULT_WARN (2L * 7L * 86400L) /* Two weeks */
+#define SALTSIZE 32
+
+static void makesalt(char []);
+
+static char password_hash[] = PASSWORD_HASH;
+
+#define PAM_OPT_LOCAL_PASS "local_pass"
+#define PAM_OPT_NIS_PASS "nis_pass"
+
+char *tempname = NULL;
+
+/*
+ * authentication management
+ */
+PAM_EXTERN int
+pam_sm_authenticate(pam_handle_t *pamh, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+ login_cap_t *lc;
+ struct passwd *pwd;
+ int retval;
+ const char *pass, *user, *realpw, *prompt;
+
+ if (openpam_get_option(pamh, PAM_OPT_AUTH_AS_SELF)) {
+ pwd = getpwnam(getlogin());
+ } else {
+ retval = pam_get_user(pamh, &user, NULL);
+ if (retval != PAM_SUCCESS)
+ return (retval);
+ pwd = getpwnam(user);
+ }
+
+ PAM_LOG("Got user: %s", user);
+
+ if (pwd != NULL) {
+ PAM_LOG("Doing real authentication");
+ realpw = pwd->pw_passwd;
+ if (realpw[0] == '\0') {
+ if (!(flags & PAM_DISALLOW_NULL_AUTHTOK) &&
+ openpam_get_option(pamh, PAM_OPT_NULLOK))
+ return (PAM_SUCCESS);
+ realpw = "*";
+ }
+ lc = login_getpwclass(pwd);
+ } else {
+ PAM_LOG("Doing dummy authentication");
+ realpw = "*";
+ lc = login_getclass(NULL);
+ }
+ prompt = login_getcapstr(lc, "passwd_prompt", NULL, NULL);
+ retval = pam_get_authtok(pamh, PAM_AUTHTOK, &pass, prompt);
+ login_close(lc);
+ if (retval != PAM_SUCCESS)
+ return (retval);
+ PAM_LOG("Got password");
+ if (strcmp(crypt(pass, realpw), realpw) == 0)
+ return (PAM_SUCCESS);
+
+ PAM_VERBOSE_ERROR("UNIX authentication refused");
+ return (PAM_AUTH_ERR);
+}
+
+PAM_EXTERN int
+pam_sm_setcred(pam_handle_t *pamh __unused, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+
+ return (PAM_SUCCESS);
+}
+
+/*
+ * account management
+ */
+PAM_EXTERN int
+pam_sm_acct_mgmt(pam_handle_t *pamh, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+ struct addrinfo hints, *res;
+ struct passwd *pwd;
+ struct timeval tp;
+ login_cap_t *lc;
+ time_t warntime;
+ int retval;
+ const char *user;
+ const void *rhost, *tty;
+ char rhostip[MAXHOSTNAMELEN] = "";
+
+ retval = pam_get_user(pamh, &user, NULL);
+ if (retval != PAM_SUCCESS)
+ return (retval);
+
+ if (user == NULL || (pwd = getpwnam(user)) == NULL)
+ return (PAM_SERVICE_ERR);
+
+ PAM_LOG("Got user: %s", user);
+
+ retval = pam_get_item(pamh, PAM_RHOST, &rhost);
+ if (retval != PAM_SUCCESS)
+ return (retval);
+
+ retval = pam_get_item(pamh, PAM_TTY, &tty);
+ if (retval != PAM_SUCCESS)
+ return (retval);
+
+ if (*pwd->pw_passwd == '\0' &&
+ (flags & PAM_DISALLOW_NULL_AUTHTOK) != 0)
+ return (PAM_NEW_AUTHTOK_REQD);
+
+ lc = login_getpwclass(pwd);
+ if (lc == NULL) {
+ PAM_LOG("Unable to get login class for user %s", user);
+ return (PAM_SERVICE_ERR);
+ }
+
+ PAM_LOG("Got login_cap");
+
+ if (pwd->pw_change || pwd->pw_expire)
+ gettimeofday(&tp, NULL);
+
+ /*
+ * Check pw_expire before pw_change - no point in letting the
+ * user change the password on an expired account.
+ */
+
+ if (pwd->pw_expire) {
+ warntime = login_getcaptime(lc, "warnexpire",
+ DEFAULT_WARN, DEFAULT_WARN);
+ if (tp.tv_sec >= pwd->pw_expire) {
+ login_close(lc);
+ return (PAM_ACCT_EXPIRED);
+ } else if (pwd->pw_expire - tp.tv_sec < warntime &&
+ (flags & PAM_SILENT) == 0) {
+ pam_error(pamh, "Warning: your account expires on %s",
+ ctime(&pwd->pw_expire));
+ }
+ }
+
+ retval = PAM_SUCCESS;
+ if (pwd->pw_change) {
+ warntime = login_getcaptime(lc, "warnpassword",
+ DEFAULT_WARN, DEFAULT_WARN);
+ if (tp.tv_sec >= pwd->pw_change) {
+ retval = PAM_NEW_AUTHTOK_REQD;
+ } else if (pwd->pw_change - tp.tv_sec < warntime &&
+ (flags & PAM_SILENT) == 0) {
+ pam_error(pamh, "Warning: your password expires on %s",
+ ctime(&pwd->pw_change));
+ }
+ }
+
+ /*
+ * From here on, we must leave retval untouched (unless we
+ * know we're going to fail), because we need to remember
+ * whether we're supposed to return PAM_SUCCESS or
+ * PAM_NEW_AUTHTOK_REQD.
+ */
+
+ if (rhost && *(const char *)rhost != '\0') {
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+ if (getaddrinfo(rhost, NULL, &hints, &res) == 0) {
+ getnameinfo(res->ai_addr, res->ai_addrlen,
+ rhostip, sizeof(rhostip), NULL, 0,
+ NI_NUMERICHOST);
+ }
+ if (res != NULL)
+ freeaddrinfo(res);
+ }
+
+ /*
+ * Check host / tty / time-of-day restrictions
+ */
+
+ if (!auth_hostok(lc, rhost, rhostip) ||
+ !auth_ttyok(lc, tty) ||
+ !auth_timeok(lc, time(NULL)))
+ retval = PAM_AUTH_ERR;
+
+ login_close(lc);
+
+ return (retval);
+}
+
+/*
+ * password management
+ *
+ * standard Unix and NIS password changing
+ */
+PAM_EXTERN int
+pam_sm_chauthtok(pam_handle_t *pamh, int flags,
+ int argc __unused, const char *argv[] __unused)
+{
+#ifdef YP
+ struct ypclnt *ypclnt;
+ void *yp_domain, *yp_server;
+#endif
+ char salt[SALTSIZE + 1];
+ login_cap_t * lc;
+ struct passwd *pwd, *old_pwd;
+ const char *user, *old_pass, *new_pass;
+ char *encrypted;
+ int pfd, tfd, retval;
+
+ if (openpam_get_option(pamh, PAM_OPT_AUTH_AS_SELF))
+ pwd = getpwnam(getlogin());
+ else {
+ retval = pam_get_user(pamh, &user, NULL);
+ if (retval != PAM_SUCCESS)
+ return (retval);
+ pwd = getpwnam(user);
+ }
+
+ if (pwd == NULL)
+ return (PAM_AUTHTOK_RECOVERY_ERR);
+
+ PAM_LOG("Got user: %s", user);
+
+ if (flags & PAM_PRELIM_CHECK) {
+
+ PAM_LOG("PRELIM round");
+
+ if (getuid() == 0 &&
+ (pwd->pw_fields & _PWF_SOURCE) == _PWF_FILES)
+ /* root doesn't need the old password */
+ return (pam_set_item(pamh, PAM_OLDAUTHTOK, ""));
+#ifdef YP
+ if (getuid() == 0 &&
+ (pwd->pw_fields & _PWF_SOURCE) == _PWF_NIS) {
+
+ yp_domain = yp_server = NULL;
+ (void)pam_get_data(pamh, "yp_domain", &yp_domain);
+ (void)pam_get_data(pamh, "yp_server", &yp_server);
+
+ ypclnt = ypclnt_new(yp_domain, "passwd.byname", yp_server);
+ if (ypclnt == NULL)
+ return (PAM_BUF_ERR);
+
+ if (ypclnt_connect(ypclnt) == -1) {
+ ypclnt_free(ypclnt);
+ return (PAM_SERVICE_ERR);
+ }
+
+ retval = ypclnt_havepasswdd(ypclnt);
+ ypclnt_free(ypclnt);
+ if (retval == 1)
+ return (pam_set_item(pamh, PAM_OLDAUTHTOK, ""));
+ else if (retval == -1)
+ return (PAM_SERVICE_ERR);
+ }
+#endif
+ if (pwd->pw_passwd[0] == '\0'
+ && openpam_get_option(pamh, PAM_OPT_NULLOK)) {
+ /*
+ * No password case. XXX Are we giving too much away
+ * by not prompting for a password?
+ * XXX check PAM_DISALLOW_NULL_AUTHTOK
+ */
+ old_pass = "";
+ } else {
+ retval = pam_get_authtok(pamh,
+ PAM_OLDAUTHTOK, &old_pass, NULL);
+ if (retval != PAM_SUCCESS)
+ return (retval);
+ }
+ PAM_LOG("Got old password");
+ /* always encrypt first */
+ encrypted = crypt(old_pass, pwd->pw_passwd);
+ if (old_pass[0] == '\0' &&
+ !openpam_get_option(pamh, PAM_OPT_NULLOK))
+ return (PAM_PERM_DENIED);
+ if (strcmp(encrypted, pwd->pw_passwd) != 0)
+ return (PAM_PERM_DENIED);
+ }
+ else if (flags & PAM_UPDATE_AUTHTOK) {
+ PAM_LOG("UPDATE round");
+
+ retval = pam_get_authtok(pamh,
+ PAM_OLDAUTHTOK, &old_pass, NULL);
+ if (retval != PAM_SUCCESS)
+ return (retval);
+ PAM_LOG("Got old password");
+
+ /* get new password */
+ for (;;) {
+ retval = pam_get_authtok(pamh,
+ PAM_AUTHTOK, &new_pass, NULL);
+ if (retval != PAM_TRY_AGAIN)
+ break;
+ pam_error(pamh, "Mismatch; try again, EOF to quit.");
+ }
+ PAM_LOG("Got new password");
+ if (retval != PAM_SUCCESS) {
+ PAM_VERBOSE_ERROR("Unable to get new password");
+ return (retval);
+ }
+
+ if (getuid() != 0 && new_pass[0] == '\0' &&
+ !openpam_get_option(pamh, PAM_OPT_NULLOK))
+ return (PAM_PERM_DENIED);
+
+ if ((old_pwd = pw_dup(pwd)) == NULL)
+ return (PAM_BUF_ERR);
+
+ pwd->pw_change = 0;
+ lc = login_getclass(pwd->pw_class);
+ if (login_setcryptfmt(lc, password_hash, NULL) == NULL)
+ openpam_log(PAM_LOG_ERROR,
+ "can't set password cipher, relying on default");
+ login_close(lc);
+ makesalt(salt);
+ pwd->pw_passwd = crypt(new_pass, salt);
+#ifdef YP
+ switch (old_pwd->pw_fields & _PWF_SOURCE) {
+ case _PWF_FILES:
+#endif
+ retval = PAM_SERVICE_ERR;
+ if (pw_init(NULL, NULL))
+ openpam_log(PAM_LOG_ERROR, "pw_init() failed");
+ else if ((pfd = pw_lock()) == -1)
+ openpam_log(PAM_LOG_ERROR, "pw_lock() failed");
+ else if ((tfd = pw_tmp(-1)) == -1)
+ openpam_log(PAM_LOG_ERROR, "pw_tmp() failed");
+ else if (pw_copy(pfd, tfd, pwd, old_pwd) == -1)
+ openpam_log(PAM_LOG_ERROR, "pw_copy() failed");
+ else if (pw_mkdb(pwd->pw_name) == -1)
+ openpam_log(PAM_LOG_ERROR, "pw_mkdb() failed");
+ else
+ retval = PAM_SUCCESS;
+ pw_fini();
+#ifdef YP
+ break;
+ case _PWF_NIS:
+ yp_domain = yp_server = NULL;
+ (void)pam_get_data(pamh, "yp_domain", &yp_domain);
+ (void)pam_get_data(pamh, "yp_server", &yp_server);
+ ypclnt = ypclnt_new(yp_domain,
+ "passwd.byname", yp_server);
+ if (ypclnt == NULL) {
+ retval = PAM_BUF_ERR;
+ } else if (ypclnt_connect(ypclnt) == -1 ||
+ ypclnt_passwd(ypclnt, pwd, old_pass) == -1) {
+ openpam_log(PAM_LOG_ERROR, "%s", ypclnt->error);
+ retval = PAM_SERVICE_ERR;
+ } else {
+ retval = PAM_SUCCESS;
+ }
+ ypclnt_free(ypclnt);
+ break;
+ default:
+ openpam_log(PAM_LOG_ERROR, "unsupported source 0x%x",
+ pwd->pw_fields & _PWF_SOURCE);
+ retval = PAM_SERVICE_ERR;
+ }
+#endif
+ free(old_pwd);
+ }
+ else {
+ /* Very bad juju */
+ retval = PAM_ABORT;
+ PAM_LOG("Illegal 'flags'");
+ }
+
+ return (retval);
+}
+
+/* Mostly stolen from passwd(1)'s local_passwd.c - markm */
+
+static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */
+ "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+static void
+to64(char *s, long v, int n)
+{
+ while (--n >= 0) {
+ *s++ = itoa64[v&0x3f];
+ v >>= 6;
+ }
+}
+
+/* Salt suitable for traditional DES and MD5 */
+void
+makesalt(char salt[SALTSIZE])
+{
+ int i;
+
+ /* These are not really random numbers, they are just
+ * numbers that change to thwart construction of a
+ * dictionary. This is exposed to the public.
+ */
+ for (i = 0; i < SALTSIZE; i += 4)
+ to64(&salt[i], arc4random(), 4);
+ salt[SALTSIZE] = '\0';
+}
+
+PAM_MODULE_ENTRY("pam_unix");
diff --git a/lib/libpanel/Makefile b/lib/libpanel/Makefile
new file mode 100644
index 0000000..6d828b2
--- /dev/null
+++ b/lib/libpanel/Makefile
@@ -0,0 +1,48 @@
+# Makefile for libpanel
+# $FreeBSD$
+
+NCURSES=${.CURDIR}/../../contrib/ncurses
+
+.PATH: ${NCURSES}/panel ${NCURSES}/include
+.PATH: ${NCURSES}/man
+
+LIB= panel
+DPADD= ${LIBNCURSES}
+LDADD= -lncurses
+AWK?= awk
+
+SRCS= ncurses_def.h \
+ p_above.c p_below.c p_bottom.c p_delete.c p_hidden.c \
+ p_hide.c p_move.c p_new.c p_replace.c p_show.c p_top.c \
+ p_update.c p_user.c p_win.c panel.c
+INCS= ${NCURSES}/panel/panel.h
+
+CLEANFILES+= ncurses_def.h
+CFLAGS+= -I.
+.if exists(${.OBJDIR}/../libncurses)
+CFLAGS+= -I${.OBJDIR}/../libncurses
+.endif
+CFLAGS+= -I${.CURDIR}/../libncurses
+CFLAGS+= -I${NCURSES}/panel -I${NCURSES}/include -I${NCURSES}/ncurses \
+ -Wall -DNDEBUG -DHAVE_CONFIG_H
+
+ncurses_def.h: MKncurses_def.sh ncurses_defs
+ AWK=${AWK} sh ${NCURSES}/include/MKncurses_def.sh \
+ ${NCURSES}/include/ncurses_defs > ncurses_def.h
+
+# generate MAN
+CLEANFILES+= panel.3
+MAN= panel.3
+panel.3: panel.3x
+ cat ${.ALLSRC} > ${.TARGET}
+
+MLINKS+=panel.3 bottom_panel.3 panel.3 del_panel.3 panel.3 hide_panel.3 \
+ panel.3 move_panel.3 panel.3 new_panel.3 panel.3 panel_above.3 \
+ panel.3 panel_below.3 panel.3 panel_hidden.3 \
+ panel.3 panel_userptr.3 panel.3 panel_window.3 \
+ panel.3 replace_panel.3 panel.3 set_panel_userptr.3 \
+ panel.3 show_panel.3 panel.3 top_panel.3 panel.3 update_panels.3
+
+.include <bsd.lib.mk>
+
+.SUFFIXES: .3x .3
diff --git a/lib/libpcap/Makefile b/lib/libpcap/Makefile
new file mode 100644
index 0000000..a1d5fc3
--- /dev/null
+++ b/lib/libpcap/Makefile
@@ -0,0 +1,47 @@
+# Makefile for libpcap
+# $FreeBSD$
+
+SHLIBDIR?= /lib
+
+.include <bsd.own.mk>
+
+LIB= pcap
+SRCS= grammar.y tokdefs.h version.h pcap-bpf.c \
+ pcap.c inet.c fad-getad.c gencode.c optimize.c nametoaddr.c \
+ etherent.c savefile.c bpf_filter.c bpf_image.c bpf_dump.c \
+ scanner.l version.c
+INCS= pcap.h pcap-int.h pcap-namedb.h
+MAN= pcap.3
+CLEANFILES=tokdefs.h version.h version.c
+
+YFLAGS+=-p pcapyy
+LFLAGS+=-Ppcapyy
+CFLAGS+=-DHAVE_CONFIG_H -Dyylval=pcapyylval -I${.CURDIR} -I.
+CFLAGS+=-D_U_="__attribute__((unused))"
+CFLAGS+=-DHAVE_SNPRINTF -DHAVE_VSNPRINTF
+.if ${MK_INET6_SUPPORT} != "no"
+CFLAGS+=-DINET6
+.endif
+
+SHLIB_MAJOR=4
+
+#
+# Magic to grab sources out of src/contrib
+#
+PCAP_DISTDIR?=${.CURDIR}/../../contrib/libpcap
+CFLAGS+=-I${PCAP_DISTDIR}
+.PATH: ${PCAP_DISTDIR}
+.PATH: ${PCAP_DISTDIR}/bpf/net
+
+version.c: ${PCAP_DISTDIR}/VERSION
+ @rm -f $@
+ sed 's/.*/char pcap_version[] = "&";/' ${PCAP_DISTDIR}/VERSION > $@
+
+version.h: ${PCAP_DISTDIR}/VERSION
+ @rm -f $@
+ sed 's/.*/char pcap_version_string[] = "libpcap version &";/' ${PCAP_DISTDIR}/VERSION > $@
+
+tokdefs.h: grammar.h
+ ln -sf grammar.h tokdefs.h
+
+.include <bsd.lib.mk>
diff --git a/lib/libpcap/config.h b/lib/libpcap/config.h
new file mode 100644
index 0000000..c88624b
--- /dev/null
+++ b/lib/libpcap/config.h
@@ -0,0 +1,181 @@
+/* $FreeBSD$ */
+/* This is an edited copy of the config.h generated by configure. */
+
+/* config.h. Generated by configure. */
+/* config.h.in. Generated from configure.in by autoheader. */
+/* Long story short: aclocal.m4 depends on autoconf 2.13
+ * implementation details wrt "const"; newer versions
+ * have different implementation details so for now we
+ * put "const" here. This may cause duplicate definitions
+ * in config.h but that should be OK since they're the same.
+ */
+/* #undef const */
+
+/* Enable optimizer debugging */
+/* #undef BDEBUG */
+
+/* define if you have the DAG API */
+/* #undef HAVE_DAG_API */
+
+/* Define to 1 if you have the declaration of `ether_hostton', and to 0 if you
+ don't. */
+#define HAVE_DECL_ETHER_HOSTTON 1
+
+/* define if you have a /dev/dlpi */
+/* #undef HAVE_DEV_DLPI */
+
+/* Define to 1 if you have the `ether_hostton' function. */
+#define HAVE_ETHER_HOSTTON 1
+
+/* on HP-UX 10.20 */
+/* #undef HAVE_HPUX10_20 */
+
+/* on HP-UX 9.x */
+/* #undef HAVE_HPUX9 */
+
+/* if ppa_info_t_dl_module_id exists */
+/* #undef HAVE_HP_PPA_INFO_T_DL_MODULE_ID_1 */
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <netinet/ether.h> header file. */
+/* #undef HAVE_NETINET_ETHER_H */
+
+/* Define to 1 if you have the <netinet/if_ether.h> header file. */
+#define HAVE_NETINET_IF_ETHER_H 1
+
+/* if there's an os_proto.h */
+/* #undef HAVE_OS_PROTO_H */
+
+/* define if you have a /proc/net/dev */
+/* #undef HAVE_PROC_NET_DEV */
+
+/* Define to 1 if you have the `snprintf' function. */
+#define HAVE_SNPRINTF 1
+
+/* if struct sockaddr has sa_len */
+#define HAVE_SOCKADDR_SA_LEN 1
+
+/* if struct sockaddr_storage exists */
+#define HAVE_SOCKADDR_STORAGE 1
+
+/* On solaris */
+/* #undef HAVE_SOLARIS */
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the `strerror' function. */
+#define HAVE_STRERROR 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+#define HAVE_STRLCPY 1
+
+/* Define to 1 if you have the <sys/bufmod.h> header file. */
+/* #undef HAVE_SYS_BUFMOD_H */
+
+/* Define to 1 if you have the <sys/dlpi_ext.h> header file. */
+/* #undef HAVE_SYS_DLPI_EXT_H */
+
+/* Define to 1 if you have the <sys/ioccom.h> header file. */
+#define HAVE_SYS_IOCCOM_H 1
+
+/* Define to 1 if you have the <sys/sockio.h> header file. */
+#define HAVE_SYS_SOCKIO_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* if if_packet.h has tpacket_stats defined */
+/* #undef HAVE_TPACKET_STATS */
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* define if version.h is generated in the build procedure */
+#define HAVE_VERSION_H 1
+
+/* Define to 1 if you have the `vsnprintf' function. */
+#define HAVE_VSNPRINTF 1
+
+/* define if your compiler has __attribute__ */
+#define HAVE___ATTRIBUTE__ 1
+
+/* IPv6 */
+/* #undef INET6 */
+
+/* if unaligned access fails */
+/* #undef LBL_ALIGN */
+
+/* Define to 1 if netinet/ether.h declares `ether_hostton' */
+/* #undef NETINET_ETHER_H_DECLARES_ETHER_HOSTTON */
+
+/* Define to 1 if netinet/if_ether.h declares `ether_hostton' */
+#define NETINET_IF_ETHER_H_DECLARES_ETHER_HOSTTON
+
+/* do not use protochain */
+/* #undef NO_PROTOCHAIN */
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME ""
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING ""
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION ""
+
+/* /dev/dlpi directory */
+/* #undef PCAP_DEV_PREFIX */
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Enable parser debugging */
+/* #undef YYDEBUG */
+
+/* needed on HP-UX */
+/* #undef _HPUX_SOURCE */
+
+/* define on AIX to get certain functions */
+/* #undef _SUN */
+
+/* Define as token for inline if inlining supported */
+#define inline inline
+
+/* on sinix */
+/* #undef sinix */
+
+/* if we have u_int16_t */
+/* #undef u_int16_t */
+
+/* if we have u_int32_t */
+/* #undef u_int32_t */
+
+/* if we have u_int8_t */
+/* #undef u_int8_t */
diff --git a/lib/libpmc/Makefile b/lib/libpmc/Makefile
new file mode 100644
index 0000000..c2560bd
--- /dev/null
+++ b/lib/libpmc/Makefile
@@ -0,0 +1,51 @@
+# $FreeBSD$
+
+LIB= pmc
+
+SRCS= libpmc.c pmclog.c
+INCS= pmc.h pmclog.h
+
+WARNS?= 6
+
+MAN= pmc.3 pmclog.3
+
+MLINKS+= \
+ pmc.3 pmc_allocate.3 \
+ pmc.3 pmc_attach.3 \
+ pmc.3 pmc_capabilities.3 \
+ pmc.3 pmc_configure_logfile.3 \
+ pmc.3 pmc_cpuinfo.3 \
+ pmc.3 pmc_detach.3 \
+ pmc.3 pmc_disable.3 \
+ pmc.3 pmc_enable.3 \
+ pmc.3 pmc_event_names_of_class.3 \
+ pmc.3 pmc_flush_logfile.3 \
+ pmc.3 pmc_get_driver_stats.3 \
+ pmc.3 pmc_init.3 \
+ pmc.3 pmc_name_of_capability.3 \
+ pmc.3 pmc_name_of_class.3 \
+ pmc.3 pmc_name_of_cputype.3 \
+ pmc.3 pmc_name_of_event.3 \
+ pmc.3 pmc_name_of_mode.3 \
+ pmc.3 pmc_name_of_state.3 \
+ pmc.3 pmc_ncpu.3 \
+ pmc.3 pmc_npmc.3 \
+ pmc.3 pmc_pmcinfo.3 \
+ pmc.3 pmc_read.3 \
+ pmc.3 pmc_release.3 \
+ pmc.3 pmc_rw.3 \
+ pmc.3 pmc_set.3 \
+ pmc.3 pmc_start.3 \
+ pmc.3 pmc_stop.3 \
+ pmc.3 pmc_width.3 \
+ pmc.3 pmc_write.3 \
+ pmc.3 pmc_writelog.3 \
+ pmc.3 pmc_x86_get_msr.3
+
+MLINKS+= \
+ pmclog.3 pmclog_open.3 \
+ pmclog.3 pmclog_close.3 \
+ pmclog.3 pmclog_feed.3 \
+ pmclog.3 pmclog_read.3
+
+.include <bsd.lib.mk>
diff --git a/lib/libpmc/libpmc.c b/lib/libpmc/libpmc.c
new file mode 100644
index 0000000..658e6b7
--- /dev/null
+++ b/lib/libpmc/libpmc.c
@@ -0,0 +1,2237 @@
+/*-
+ * Copyright (c) 2003-2006 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 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/module.h>
+#include <sys/pmc.h>
+#include <sys/syscall.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pmc.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+
+/* Function prototypes */
+#if defined(__i386__)
+static int k7_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
+ struct pmc_op_pmcallocate *_pmc_config);
+#endif
+#if defined(__amd64__) || defined(__i386__)
+static int k8_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
+ struct pmc_op_pmcallocate *_pmc_config);
+static int p4_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
+ struct pmc_op_pmcallocate *_pmc_config);
+#endif
+#if defined(__i386__)
+static int p5_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
+ struct pmc_op_pmcallocate *_pmc_config);
+static int p6_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
+ struct pmc_op_pmcallocate *_pmc_config);
+#endif
+
+#define PMC_CALL(cmd, params) \
+ syscall(pmc_syscall, PMC_OP_##cmd, (params))
+
+/*
+ * Event aliases provide a way for the user to ask for generic events
+ * like "cache-misses", or "instructions-retired". These aliases are
+ * mapped to the appropriate canonical event descriptions using a
+ * lookup table.
+ */
+
+struct pmc_event_alias {
+ const char *pm_alias;
+ const char *pm_spec;
+};
+
+static const struct pmc_event_alias *pmc_mdep_event_aliases;
+
+/*
+ * The pmc_event_descr table maps symbolic names known to the user
+ * to integer codes used by the PMC KLD.
+ */
+
+struct pmc_event_descr {
+ const char *pm_ev_name;
+ enum pmc_event pm_ev_code;
+ enum pmc_class pm_ev_class;
+};
+
+static const struct pmc_event_descr
+pmc_event_table[] =
+{
+#undef __PMC_EV
+#define __PMC_EV(C,N,EV) { #EV, PMC_EV_ ## C ## _ ## N, PMC_CLASS_ ## C },
+ __PMC_EVENTS()
+};
+
+/*
+ * Mapping tables, mapping enumeration values to human readable
+ * strings.
+ */
+
+static const char * pmc_capability_names[] = {
+#undef __PMC_CAP
+#define __PMC_CAP(N,V,D) #N ,
+ __PMC_CAPS()
+};
+
+static const char * pmc_class_names[] = {
+#undef __PMC_CLASS
+#define __PMC_CLASS(C) #C ,
+ __PMC_CLASSES()
+};
+
+static const char * pmc_cputype_names[] = {
+#undef __PMC_CPU
+#define __PMC_CPU(S, D) #S ,
+ __PMC_CPUS()
+};
+
+static const char * pmc_disposition_names[] = {
+#undef __PMC_DISP
+#define __PMC_DISP(D) #D ,
+ __PMC_DISPOSITIONS()
+};
+
+static const char * pmc_mode_names[] = {
+#undef __PMC_MODE
+#define __PMC_MODE(M,N) #M ,
+ __PMC_MODES()
+};
+
+static const char * pmc_state_names[] = {
+#undef __PMC_STATE
+#define __PMC_STATE(S) #S ,
+ __PMC_STATES()
+};
+
+static int pmc_syscall = -1; /* filled in by pmc_init() */
+
+static struct pmc_cpuinfo cpu_info; /* filled in by pmc_init() */
+
+
+/* Architecture dependent event parsing */
+static int (*pmc_mdep_allocate_pmc)(enum pmc_event _pe, char *_ctrspec,
+ struct pmc_op_pmcallocate *_pmc_config);
+
+/* Event masks for events */
+struct pmc_masks {
+ const char *pm_name;
+ const uint32_t pm_value;
+};
+#define PMCMASK(N,V) { .pm_name = #N, .pm_value = (V) }
+#define NULLMASK PMCMASK(NULL,0)
+
+#if defined(__amd64__) || defined(__i386__)
+static int
+pmc_parse_mask(const struct pmc_masks *pmask, char *p, uint32_t *evmask)
+{
+ const struct pmc_masks *pm;
+ char *q, *r;
+ int c;
+
+ if (pmask == NULL) /* no mask keywords */
+ return -1;
+ q = strchr(p, '='); /* skip '=' */
+ if (*++q == '\0') /* no more data */
+ return -1;
+ c = 0; /* count of mask keywords seen */
+ while ((r = strsep(&q, "+")) != NULL) {
+ for (pm = pmask; pm->pm_name && strcmp(r, pm->pm_name); pm++)
+ ;
+ if (pm->pm_name == NULL) /* not found */
+ return -1;
+ *evmask |= pm->pm_value;
+ c++;
+ }
+ return c;
+}
+#endif
+
+#define KWMATCH(p,kw) (strcasecmp((p), (kw)) == 0)
+#define KWPREFIXMATCH(p,kw) (strncasecmp((p), (kw), sizeof((kw)) - 1) == 0)
+#define EV_ALIAS(N,S) { .pm_alias = N, .pm_spec = S }
+
+#if defined(__i386__)
+
+/*
+ * AMD K7 (Athlon) CPUs.
+ */
+
+static struct pmc_event_alias k7_aliases[] = {
+ EV_ALIAS("branches", "k7-retired-branches"),
+ EV_ALIAS("branch-mispredicts", "k7-retired-branches-mispredicted"),
+ EV_ALIAS("cycles", "tsc"),
+ EV_ALIAS("dc-misses", "k7-dc-misses,mask=moesi"),
+ EV_ALIAS("ic-misses", "k7-ic-misses"),
+ EV_ALIAS("instructions", "k7-retired-instructions"),
+ EV_ALIAS("interrupts", "k7-hardware-interrupts"),
+ EV_ALIAS(NULL, NULL)
+};
+
+#define K7_KW_COUNT "count"
+#define K7_KW_EDGE "edge"
+#define K7_KW_INV "inv"
+#define K7_KW_OS "os"
+#define K7_KW_UNITMASK "unitmask"
+#define K7_KW_USR "usr"
+
+static int
+k7_allocate_pmc(enum pmc_event pe, char *ctrspec,
+ struct pmc_op_pmcallocate *pmc_config)
+{
+ char *e, *p, *q;
+ int c, has_unitmask;
+ uint32_t count, unitmask;
+
+ pmc_config->pm_md.pm_amd.pm_amd_config = 0;
+ pmc_config->pm_caps |= PMC_CAP_READ;
+
+ if (pe == PMC_EV_TSC_TSC) {
+ /* TSC events must be unqualified. */
+ if (ctrspec && *ctrspec != '\0')
+ return -1;
+ return 0;
+ }
+
+ if (pe == PMC_EV_K7_DC_REFILLS_FROM_L2 ||
+ pe == PMC_EV_K7_DC_REFILLS_FROM_SYSTEM ||
+ pe == PMC_EV_K7_DC_WRITEBACKS) {
+ has_unitmask = 1;
+ unitmask = AMD_PMC_UNITMASK_MOESI;
+ } else
+ unitmask = has_unitmask = 0;
+
+ pmc_config->pm_caps |= PMC_CAP_WRITE;
+
+ while ((p = strsep(&ctrspec, ",")) != NULL) {
+ if (KWPREFIXMATCH(p, K7_KW_COUNT "=")) {
+ q = strchr(p, '=');
+ if (*++q == '\0') /* skip '=' */
+ return -1;
+
+ count = strtol(q, &e, 0);
+ if (e == q || *e != '\0')
+ return -1;
+
+ pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
+ pmc_config->pm_md.pm_amd.pm_amd_config |=
+ AMD_PMC_TO_COUNTER(count);
+
+ } else if (KWMATCH(p, K7_KW_EDGE)) {
+ pmc_config->pm_caps |= PMC_CAP_EDGE;
+ } else if (KWMATCH(p, K7_KW_INV)) {
+ pmc_config->pm_caps |= PMC_CAP_INVERT;
+ } else if (KWMATCH(p, K7_KW_OS)) {
+ pmc_config->pm_caps |= PMC_CAP_SYSTEM;
+ } else if (KWPREFIXMATCH(p, K7_KW_UNITMASK "=")) {
+ if (has_unitmask == 0)
+ return -1;
+ unitmask = 0;
+ q = strchr(p, '=');
+ if (*++q == '\0') /* skip '=' */
+ return -1;
+
+ while ((c = tolower(*q++)) != 0)
+ if (c == 'm')
+ unitmask |= AMD_PMC_UNITMASK_M;
+ else if (c == 'o')
+ unitmask |= AMD_PMC_UNITMASK_O;
+ else if (c == 'e')
+ unitmask |= AMD_PMC_UNITMASK_E;
+ else if (c == 's')
+ unitmask |= AMD_PMC_UNITMASK_S;
+ else if (c == 'i')
+ unitmask |= AMD_PMC_UNITMASK_I;
+ else if (c == '+')
+ continue;
+ else
+ return -1;
+
+ if (unitmask == 0)
+ return -1;
+
+ } else if (KWMATCH(p, K7_KW_USR)) {
+ pmc_config->pm_caps |= PMC_CAP_USER;
+ } else
+ return -1;
+ }
+
+ if (has_unitmask) {
+ pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
+ pmc_config->pm_md.pm_amd.pm_amd_config |=
+ AMD_PMC_TO_UNITMASK(unitmask);
+ }
+
+ return 0;
+
+}
+
+#endif
+
+#if defined(__amd64__) || defined(__i386__)
+
+/*
+ * AMD K8 PMCs.
+ *
+ * These are very similar to AMD K7 PMCs, but support more kinds of
+ * events.
+ */
+
+static struct pmc_event_alias k8_aliases[] = {
+ EV_ALIAS("branches", "k8-fr-retired-taken-branches"),
+ EV_ALIAS("branch-mispredicts",
+ "k8-fr-retired-taken-branches-mispredicted"),
+ EV_ALIAS("cycles", "tsc"),
+ EV_ALIAS("dc-misses", "k8-dc-miss"),
+ EV_ALIAS("ic-misses", "k8-ic-miss"),
+ EV_ALIAS("instructions", "k8-fr-retired-x86-instructions"),
+ EV_ALIAS("interrupts", "k8-fr-taken-hardware-interrupts"),
+ EV_ALIAS("unhalted-cycles", "k8-bu-cpu-clk-unhalted"),
+ EV_ALIAS(NULL, NULL)
+};
+
+#define __K8MASK(N,V) PMCMASK(N,(1 << (V)))
+
+/*
+ * Parsing tables
+ */
+
+/* fp dispatched fpu ops */
+static const struct pmc_masks k8_mask_fdfo[] = {
+ __K8MASK(add-pipe-excluding-junk-ops, 0),
+ __K8MASK(multiply-pipe-excluding-junk-ops, 1),
+ __K8MASK(store-pipe-excluding-junk-ops, 2),
+ __K8MASK(add-pipe-junk-ops, 3),
+ __K8MASK(multiply-pipe-junk-ops, 4),
+ __K8MASK(store-pipe-junk-ops, 5),
+ NULLMASK
+};
+
+/* ls segment register loads */
+static const struct pmc_masks k8_mask_lsrl[] = {
+ __K8MASK(es, 0),
+ __K8MASK(cs, 1),
+ __K8MASK(ss, 2),
+ __K8MASK(ds, 3),
+ __K8MASK(fs, 4),
+ __K8MASK(gs, 5),
+ __K8MASK(hs, 6),
+ NULLMASK
+};
+
+/* ls locked operation */
+static const struct pmc_masks k8_mask_llo[] = {
+ __K8MASK(locked-instructions, 0),
+ __K8MASK(cycles-in-request, 1),
+ __K8MASK(cycles-to-complete, 2),
+ NULLMASK
+};
+
+/* dc refill from {l2,system} and dc copyback */
+static const struct pmc_masks k8_mask_dc[] = {
+ __K8MASK(invalid, 0),
+ __K8MASK(shared, 1),
+ __K8MASK(exclusive, 2),
+ __K8MASK(owner, 3),
+ __K8MASK(modified, 4),
+ NULLMASK
+};
+
+/* dc one bit ecc error */
+static const struct pmc_masks k8_mask_dobee[] = {
+ __K8MASK(scrubber, 0),
+ __K8MASK(piggyback, 1),
+ NULLMASK
+};
+
+/* dc dispatched prefetch instructions */
+static const struct pmc_masks k8_mask_ddpi[] = {
+ __K8MASK(load, 0),
+ __K8MASK(store, 1),
+ __K8MASK(nta, 2),
+ NULLMASK
+};
+
+/* dc dcache accesses by locks */
+static const struct pmc_masks k8_mask_dabl[] = {
+ __K8MASK(accesses, 0),
+ __K8MASK(misses, 1),
+ NULLMASK
+};
+
+/* bu internal l2 request */
+static const struct pmc_masks k8_mask_bilr[] = {
+ __K8MASK(ic-fill, 0),
+ __K8MASK(dc-fill, 1),
+ __K8MASK(tlb-reload, 2),
+ __K8MASK(tag-snoop, 3),
+ __K8MASK(cancelled, 4),
+ NULLMASK
+};
+
+/* bu fill request l2 miss */
+static const struct pmc_masks k8_mask_bfrlm[] = {
+ __K8MASK(ic-fill, 0),
+ __K8MASK(dc-fill, 1),
+ __K8MASK(tlb-reload, 2),
+ NULLMASK
+};
+
+/* bu fill into l2 */
+static const struct pmc_masks k8_mask_bfil[] = {
+ __K8MASK(dirty-l2-victim, 0),
+ __K8MASK(victim-from-l2, 1),
+ NULLMASK
+};
+
+/* fr retired fpu instructions */
+static const struct pmc_masks k8_mask_frfi[] = {
+ __K8MASK(x87, 0),
+ __K8MASK(mmx-3dnow, 1),
+ __K8MASK(packed-sse-sse2, 2),
+ __K8MASK(scalar-sse-sse2, 3),
+ NULLMASK
+};
+
+/* fr retired fastpath double op instructions */
+static const struct pmc_masks k8_mask_frfdoi[] = {
+ __K8MASK(low-op-pos-0, 0),
+ __K8MASK(low-op-pos-1, 1),
+ __K8MASK(low-op-pos-2, 2),
+ NULLMASK
+};
+
+/* fr fpu exceptions */
+static const struct pmc_masks k8_mask_ffe[] = {
+ __K8MASK(x87-reclass-microfaults, 0),
+ __K8MASK(sse-retype-microfaults, 1),
+ __K8MASK(sse-reclass-microfaults, 2),
+ __K8MASK(sse-and-x87-microtraps, 3),
+ NULLMASK
+};
+
+/* nb memory controller page access event */
+static const struct pmc_masks k8_mask_nmcpae[] = {
+ __K8MASK(page-hit, 0),
+ __K8MASK(page-miss, 1),
+ __K8MASK(page-conflict, 2),
+ NULLMASK
+};
+
+/* nb memory controller turnaround */
+static const struct pmc_masks k8_mask_nmct[] = {
+ __K8MASK(dimm-turnaround, 0),
+ __K8MASK(read-to-write-turnaround, 1),
+ __K8MASK(write-to-read-turnaround, 2),
+ NULLMASK
+};
+
+/* nb memory controller bypass saturation */
+static const struct pmc_masks k8_mask_nmcbs[] = {
+ __K8MASK(memory-controller-hi-pri-bypass, 0),
+ __K8MASK(memory-controller-lo-pri-bypass, 1),
+ __K8MASK(dram-controller-interface-bypass, 2),
+ __K8MASK(dram-controller-queue-bypass, 3),
+ NULLMASK
+};
+
+/* nb sized commands */
+static const struct pmc_masks k8_mask_nsc[] = {
+ __K8MASK(nonpostwrszbyte, 0),
+ __K8MASK(nonpostwrszdword, 1),
+ __K8MASK(postwrszbyte, 2),
+ __K8MASK(postwrszdword, 3),
+ __K8MASK(rdszbyte, 4),
+ __K8MASK(rdszdword, 5),
+ __K8MASK(rdmodwr, 6),
+ NULLMASK
+};
+
+/* nb probe result */
+static const struct pmc_masks k8_mask_npr[] = {
+ __K8MASK(probe-miss, 0),
+ __K8MASK(probe-hit, 1),
+ __K8MASK(probe-hit-dirty-no-memory-cancel, 2),
+ __K8MASK(probe-hit-dirty-with-memory-cancel, 3),
+ NULLMASK
+};
+
+/* nb hypertransport bus bandwidth */
+static const struct pmc_masks k8_mask_nhbb[] = { /* HT bus bandwidth */
+ __K8MASK(command, 0),
+ __K8MASK(data, 1),
+ __K8MASK(buffer-release, 2),
+ __K8MASK(nop, 3),
+ NULLMASK
+};
+
+#undef __K8MASK
+
+#define K8_KW_COUNT "count"
+#define K8_KW_EDGE "edge"
+#define K8_KW_INV "inv"
+#define K8_KW_MASK "mask"
+#define K8_KW_OS "os"
+#define K8_KW_USR "usr"
+
+static int
+k8_allocate_pmc(enum pmc_event pe, char *ctrspec,
+ struct pmc_op_pmcallocate *pmc_config)
+{
+ char *e, *p, *q;
+ int n;
+ uint32_t count, evmask;
+ const struct pmc_masks *pm, *pmask;
+
+ pmc_config->pm_caps |= PMC_CAP_READ;
+ pmc_config->pm_md.pm_amd.pm_amd_config = 0;
+
+ if (pe == PMC_EV_TSC_TSC) {
+ /* TSC events must be unqualified. */
+ if (ctrspec && *ctrspec != '\0')
+ return -1;
+ return 0;
+ }
+
+ pmask = NULL;
+ evmask = 0;
+
+#define __K8SETMASK(M) pmask = k8_mask_##M
+
+ /* setup parsing tables */
+ switch (pe) {
+ case PMC_EV_K8_FP_DISPATCHED_FPU_OPS:
+ __K8SETMASK(fdfo);
+ break;
+ case PMC_EV_K8_LS_SEGMENT_REGISTER_LOAD:
+ __K8SETMASK(lsrl);
+ break;
+ case PMC_EV_K8_LS_LOCKED_OPERATION:
+ __K8SETMASK(llo);
+ break;
+ case PMC_EV_K8_DC_REFILL_FROM_L2:
+ case PMC_EV_K8_DC_REFILL_FROM_SYSTEM:
+ case PMC_EV_K8_DC_COPYBACK:
+ __K8SETMASK(dc);
+ break;
+ case PMC_EV_K8_DC_ONE_BIT_ECC_ERROR:
+ __K8SETMASK(dobee);
+ break;
+ case PMC_EV_K8_DC_DISPATCHED_PREFETCH_INSTRUCTIONS:
+ __K8SETMASK(ddpi);
+ break;
+ case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS:
+ __K8SETMASK(dabl);
+ break;
+ case PMC_EV_K8_BU_INTERNAL_L2_REQUEST:
+ __K8SETMASK(bilr);
+ break;
+ case PMC_EV_K8_BU_FILL_REQUEST_L2_MISS:
+ __K8SETMASK(bfrlm);
+ break;
+ case PMC_EV_K8_BU_FILL_INTO_L2:
+ __K8SETMASK(bfil);
+ break;
+ case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS:
+ __K8SETMASK(frfi);
+ break;
+ case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS:
+ __K8SETMASK(frfdoi);
+ break;
+ case PMC_EV_K8_FR_FPU_EXCEPTIONS:
+ __K8SETMASK(ffe);
+ break;
+ case PMC_EV_K8_NB_MEMORY_CONTROLLER_PAGE_ACCESS_EVENT:
+ __K8SETMASK(nmcpae);
+ break;
+ case PMC_EV_K8_NB_MEMORY_CONTROLLER_TURNAROUND:
+ __K8SETMASK(nmct);
+ break;
+ case PMC_EV_K8_NB_MEMORY_CONTROLLER_BYPASS_SATURATION:
+ __K8SETMASK(nmcbs);
+ break;
+ case PMC_EV_K8_NB_SIZED_COMMANDS:
+ __K8SETMASK(nsc);
+ break;
+ case PMC_EV_K8_NB_PROBE_RESULT:
+ __K8SETMASK(npr);
+ break;
+ case PMC_EV_K8_NB_HT_BUS0_BANDWIDTH:
+ case PMC_EV_K8_NB_HT_BUS1_BANDWIDTH:
+ case PMC_EV_K8_NB_HT_BUS2_BANDWIDTH:
+ __K8SETMASK(nhbb);
+ break;
+
+ default:
+ break; /* no options defined */
+ }
+
+ pmc_config->pm_caps |= PMC_CAP_WRITE;
+
+ while ((p = strsep(&ctrspec, ",")) != NULL) {
+ if (KWPREFIXMATCH(p, K8_KW_COUNT "=")) {
+ q = strchr(p, '=');
+ if (*++q == '\0') /* skip '=' */
+ return -1;
+
+ count = strtol(q, &e, 0);
+ if (e == q || *e != '\0')
+ return -1;
+
+ pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
+ pmc_config->pm_md.pm_amd.pm_amd_config |=
+ AMD_PMC_TO_COUNTER(count);
+
+ } else if (KWMATCH(p, K8_KW_EDGE)) {
+ pmc_config->pm_caps |= PMC_CAP_EDGE;
+ } else if (KWMATCH(p, K8_KW_INV)) {
+ pmc_config->pm_caps |= PMC_CAP_INVERT;
+ } else if (KWPREFIXMATCH(p, K8_KW_MASK "=")) {
+ if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0)
+ return -1;
+ pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
+ } else if (KWMATCH(p, K8_KW_OS)) {
+ pmc_config->pm_caps |= PMC_CAP_SYSTEM;
+ } else if (KWMATCH(p, K8_KW_USR)) {
+ pmc_config->pm_caps |= PMC_CAP_USER;
+ } else
+ return -1;
+ }
+
+ /* other post processing */
+
+ switch (pe) {
+ case PMC_EV_K8_FP_DISPATCHED_FPU_OPS:
+ case PMC_EV_K8_FP_CYCLES_WITH_NO_FPU_OPS_RETIRED:
+ case PMC_EV_K8_FP_DISPATCHED_FPU_FAST_FLAG_OPS:
+ case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS:
+ case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS:
+ case PMC_EV_K8_FR_FPU_EXCEPTIONS:
+ /* XXX only available in rev B and later */
+ break;
+ case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS:
+ /* XXX only available in rev C and later */
+ break;
+ case PMC_EV_K8_LS_LOCKED_OPERATION:
+ /* XXX CPU Rev A,B evmask is to be zero */
+ if (evmask & (evmask - 1)) /* > 1 bit set */
+ return -1;
+ if (evmask == 0) {
+ evmask = 0x01; /* Rev C and later: #instrs */
+ pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
+ }
+ break;
+ default:
+ if (evmask == 0 && pmask != NULL) {
+ for (pm = pmask; pm->pm_name; pm++)
+ evmask |= pm->pm_value;
+ pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
+ }
+ }
+
+ if (pmc_config->pm_caps & PMC_CAP_QUALIFIER)
+ pmc_config->pm_md.pm_amd.pm_amd_config =
+ AMD_PMC_TO_UNITMASK(evmask);
+
+ return 0;
+}
+
+#endif
+
+#if defined(__amd64__) || defined(__i386__)
+
+/*
+ * Intel P4 PMCs
+ */
+
+static struct pmc_event_alias p4_aliases[] = {
+ EV_ALIAS("branches", "p4-branch-retired,mask=mmtp+mmtm"),
+ EV_ALIAS("branch-mispredicts", "p4-mispred-branch-retired"),
+ EV_ALIAS("cycles", "tsc"),
+ EV_ALIAS("instructions",
+ "p4-instr-retired,mask=nbogusntag+nbogustag"),
+ EV_ALIAS("unhalted-cycles", "p4-global-power-events"),
+ EV_ALIAS(NULL, NULL)
+};
+
+#define P4_KW_ACTIVE "active"
+#define P4_KW_ACTIVE_ANY "any"
+#define P4_KW_ACTIVE_BOTH "both"
+#define P4_KW_ACTIVE_NONE "none"
+#define P4_KW_ACTIVE_SINGLE "single"
+#define P4_KW_BUSREQTYPE "busreqtype"
+#define P4_KW_CASCADE "cascade"
+#define P4_KW_EDGE "edge"
+#define P4_KW_INV "complement"
+#define P4_KW_OS "os"
+#define P4_KW_MASK "mask"
+#define P4_KW_PRECISE "precise"
+#define P4_KW_TAG "tag"
+#define P4_KW_THRESHOLD "threshold"
+#define P4_KW_USR "usr"
+
+#define __P4MASK(N,V) PMCMASK(N, (1 << (V)))
+
+static const struct pmc_masks p4_mask_tcdm[] = { /* tc deliver mode */
+ __P4MASK(dd, 0),
+ __P4MASK(db, 1),
+ __P4MASK(di, 2),
+ __P4MASK(bd, 3),
+ __P4MASK(bb, 4),
+ __P4MASK(bi, 5),
+ __P4MASK(id, 6),
+ __P4MASK(ib, 7),
+ NULLMASK
+};
+
+static const struct pmc_masks p4_mask_bfr[] = { /* bpu fetch request */
+ __P4MASK(tcmiss, 0),
+ NULLMASK,
+};
+
+static const struct pmc_masks p4_mask_ir[] = { /* itlb reference */
+ __P4MASK(hit, 0),
+ __P4MASK(miss, 1),
+ __P4MASK(hit-uc, 2),
+ NULLMASK
+};
+
+static const struct pmc_masks p4_mask_memcan[] = { /* memory cancel */
+ __P4MASK(st-rb-full, 2),
+ __P4MASK(64k-conf, 3),
+ NULLMASK
+};
+
+static const struct pmc_masks p4_mask_memcomp[] = { /* memory complete */
+ __P4MASK(lsc, 0),
+ __P4MASK(ssc, 1),
+ NULLMASK
+};
+
+static const struct pmc_masks p4_mask_lpr[] = { /* load port replay */
+ __P4MASK(split-ld, 1),
+ NULLMASK
+};
+
+static const struct pmc_masks p4_mask_spr[] = { /* store port replay */
+ __P4MASK(split-st, 1),
+ NULLMASK
+};
+
+static const struct pmc_masks p4_mask_mlr[] = { /* mob load replay */
+ __P4MASK(no-sta, 1),
+ __P4MASK(no-std, 3),
+ __P4MASK(partial-data, 4),
+ __P4MASK(unalgn-addr, 5),
+ NULLMASK
+};
+
+static const struct pmc_masks p4_mask_pwt[] = { /* page walk type */
+ __P4MASK(dtmiss, 0),
+ __P4MASK(itmiss, 1),
+ NULLMASK
+};
+
+static const struct pmc_masks p4_mask_bcr[] = { /* bsq cache reference */
+ __P4MASK(rd-2ndl-hits, 0),
+ __P4MASK(rd-2ndl-hite, 1),
+ __P4MASK(rd-2ndl-hitm, 2),
+ __P4MASK(rd-3rdl-hits, 3),
+ __P4MASK(rd-3rdl-hite, 4),
+ __P4MASK(rd-3rdl-hitm, 5),
+ __P4MASK(rd-2ndl-miss, 8),
+ __P4MASK(rd-3rdl-miss, 9),
+ __P4MASK(wr-2ndl-miss, 10),
+ NULLMASK
+};
+
+static const struct pmc_masks p4_mask_ia[] = { /* ioq allocation */
+ __P4MASK(all-read, 5),
+ __P4MASK(all-write, 6),
+ __P4MASK(mem-uc, 7),
+ __P4MASK(mem-wc, 8),
+ __P4MASK(mem-wt, 9),
+ __P4MASK(mem-wp, 10),
+ __P4MASK(mem-wb, 11),
+ __P4MASK(own, 13),
+ __P4MASK(other, 14),
+ __P4MASK(prefetch, 15),
+ NULLMASK
+};
+
+static const struct pmc_masks p4_mask_iae[] = { /* ioq active entries */
+ __P4MASK(all-read, 5),
+ __P4MASK(all-write, 6),
+ __P4MASK(mem-uc, 7),
+ __P4MASK(mem-wc, 8),
+ __P4MASK(mem-wt, 9),
+ __P4MASK(mem-wp, 10),
+ __P4MASK(mem-wb, 11),
+ __P4MASK(own, 13),
+ __P4MASK(other, 14),
+ __P4MASK(prefetch, 15),
+ NULLMASK
+};
+
+static const struct pmc_masks p4_mask_fda[] = { /* fsb data activity */
+ __P4MASK(drdy-drv, 0),
+ __P4MASK(drdy-own, 1),
+ __P4MASK(drdy-other, 2),
+ __P4MASK(dbsy-drv, 3),
+ __P4MASK(dbsy-own, 4),
+ __P4MASK(dbsy-other, 5),
+ NULLMASK
+};
+
+static const struct pmc_masks p4_mask_ba[] = { /* bsq allocation */
+ __P4MASK(req-type0, 0),
+ __P4MASK(req-type1, 1),
+ __P4MASK(req-len0, 2),
+ __P4MASK(req-len1, 3),
+ __P4MASK(req-io-type, 5),
+ __P4MASK(req-lock-type, 6),
+ __P4MASK(req-cache-type, 7),
+ __P4MASK(req-split-type, 8),
+ __P4MASK(req-dem-type, 9),
+ __P4MASK(req-ord-type, 10),
+ __P4MASK(mem-type0, 11),
+ __P4MASK(mem-type1, 12),
+ __P4MASK(mem-type2, 13),
+ NULLMASK
+};
+
+static const struct pmc_masks p4_mask_sia[] = { /* sse input assist */
+ __P4MASK(all, 15),
+ NULLMASK
+};
+
+static const struct pmc_masks p4_mask_psu[] = { /* packed sp uop */
+ __P4MASK(all, 15),
+ NULLMASK
+};
+
+static const struct pmc_masks p4_mask_pdu[] = { /* packed dp uop */
+ __P4MASK(all, 15),
+ NULLMASK
+};
+
+static const struct pmc_masks p4_mask_ssu[] = { /* scalar sp uop */
+ __P4MASK(all, 15),
+ NULLMASK
+};
+
+static const struct pmc_masks p4_mask_sdu[] = { /* scalar dp uop */
+ __P4MASK(all, 15),
+ NULLMASK
+};
+
+static const struct pmc_masks p4_mask_64bmu[] = { /* 64 bit mmx uop */
+ __P4MASK(all, 15),
+ NULLMASK
+};
+
+static const struct pmc_masks p4_mask_128bmu[] = { /* 128 bit mmx uop */
+ __P4MASK(all, 15),
+ NULLMASK
+};
+
+static const struct pmc_masks p4_mask_xfu[] = { /* X87 fp uop */
+ __P4MASK(all, 15),
+ NULLMASK
+};
+
+static const struct pmc_masks p4_mask_xsmu[] = { /* x87 simd moves uop */
+ __P4MASK(allp0, 3),
+ __P4MASK(allp2, 4),
+ NULLMASK
+};
+
+static const struct pmc_masks p4_mask_gpe[] = { /* global power events */
+ __P4MASK(running, 0),
+ NULLMASK
+};
+
+static const struct pmc_masks p4_mask_tmx[] = { /* TC ms xfer */
+ __P4MASK(cisc, 0),
+ NULLMASK
+};
+
+static const struct pmc_masks p4_mask_uqw[] = { /* uop queue writes */
+ __P4MASK(from-tc-build, 0),
+ __P4MASK(from-tc-deliver, 1),
+ __P4MASK(from-rom, 2),
+ NULLMASK
+};
+
+static const struct pmc_masks p4_mask_rmbt[] = {
+ /* retired mispred branch type */
+ __P4MASK(conditional, 1),
+ __P4MASK(call, 2),
+ __P4MASK(return, 3),
+ __P4MASK(indirect, 4),
+ NULLMASK
+};
+
+static const struct pmc_masks p4_mask_rbt[] = { /* retired branch type */
+ __P4MASK(conditional, 1),
+ __P4MASK(call, 2),
+ __P4MASK(retired, 3),
+ __P4MASK(indirect, 4),
+ NULLMASK
+};
+
+static const struct pmc_masks p4_mask_rs[] = { /* resource stall */
+ __P4MASK(sbfull, 5),
+ NULLMASK
+};
+
+static const struct pmc_masks p4_mask_wb[] = { /* WC buffer */
+ __P4MASK(wcb-evicts, 0),
+ __P4MASK(wcb-full-evict, 1),
+ NULLMASK
+};
+
+static const struct pmc_masks p4_mask_fee[] = { /* front end event */
+ __P4MASK(nbogus, 0),
+ __P4MASK(bogus, 1),
+ NULLMASK
+};
+
+static const struct pmc_masks p4_mask_ee[] = { /* execution event */
+ __P4MASK(nbogus0, 0),
+ __P4MASK(nbogus1, 1),
+ __P4MASK(nbogus2, 2),
+ __P4MASK(nbogus3, 3),
+ __P4MASK(bogus0, 4),
+ __P4MASK(bogus1, 5),
+ __P4MASK(bogus2, 6),
+ __P4MASK(bogus3, 7),
+ NULLMASK
+};
+
+static const struct pmc_masks p4_mask_re[] = { /* replay event */
+ __P4MASK(nbogus, 0),
+ __P4MASK(bogus, 1),
+ NULLMASK
+};
+
+static const struct pmc_masks p4_mask_insret[] = { /* instr retired */
+ __P4MASK(nbogusntag, 0),
+ __P4MASK(nbogustag, 1),
+ __P4MASK(bogusntag, 2),
+ __P4MASK(bogustag, 3),
+ NULLMASK
+};
+
+static const struct pmc_masks p4_mask_ur[] = { /* uops retired */
+ __P4MASK(nbogus, 0),
+ __P4MASK(bogus, 1),
+ NULLMASK
+};
+
+static const struct pmc_masks p4_mask_ut[] = { /* uop type */
+ __P4MASK(tagloads, 1),
+ __P4MASK(tagstores, 2),
+ NULLMASK
+};
+
+static const struct pmc_masks p4_mask_br[] = { /* branch retired */
+ __P4MASK(mmnp, 0),
+ __P4MASK(mmnm, 1),
+ __P4MASK(mmtp, 2),
+ __P4MASK(mmtm, 3),
+ NULLMASK
+};
+
+static const struct pmc_masks p4_mask_mbr[] = { /* mispred branch retired */
+ __P4MASK(nbogus, 0),
+ NULLMASK
+};
+
+static const struct pmc_masks p4_mask_xa[] = { /* x87 assist */
+ __P4MASK(fpsu, 0),
+ __P4MASK(fpso, 1),
+ __P4MASK(poao, 2),
+ __P4MASK(poau, 3),
+ __P4MASK(prea, 4),
+ NULLMASK
+};
+
+static const struct pmc_masks p4_mask_machclr[] = { /* machine clear */
+ __P4MASK(clear, 0),
+ __P4MASK(moclear, 2),
+ __P4MASK(smclear, 3),
+ NULLMASK
+};
+
+/* P4 event parser */
+static int
+p4_allocate_pmc(enum pmc_event pe, char *ctrspec,
+ struct pmc_op_pmcallocate *pmc_config)
+{
+
+ char *e, *p, *q;
+ int count, has_tag, has_busreqtype, n;
+ uint32_t evmask, cccractivemask;
+ const struct pmc_masks *pm, *pmask;
+
+ pmc_config->pm_caps |= PMC_CAP_READ;
+ pmc_config->pm_md.pm_p4.pm_p4_cccrconfig =
+ pmc_config->pm_md.pm_p4.pm_p4_escrconfig = 0;
+
+ if (pe == PMC_EV_TSC_TSC) {
+ /* TSC must not be further qualified */
+ if (ctrspec && *ctrspec != '\0')
+ return -1;
+ return 0;
+ }
+
+ pmask = NULL;
+ evmask = 0;
+ cccractivemask = 0x3;
+ has_tag = has_busreqtype = 0;
+ pmc_config->pm_caps |= PMC_CAP_WRITE;
+
+#define __P4SETMASK(M) do { \
+ pmask = p4_mask_##M; \
+} while (0)
+
+ switch (pe) {
+ case PMC_EV_P4_TC_DELIVER_MODE:
+ __P4SETMASK(tcdm);
+ break;
+ case PMC_EV_P4_BPU_FETCH_REQUEST:
+ __P4SETMASK(bfr);
+ break;
+ case PMC_EV_P4_ITLB_REFERENCE:
+ __P4SETMASK(ir);
+ break;
+ case PMC_EV_P4_MEMORY_CANCEL:
+ __P4SETMASK(memcan);
+ break;
+ case PMC_EV_P4_MEMORY_COMPLETE:
+ __P4SETMASK(memcomp);
+ break;
+ case PMC_EV_P4_LOAD_PORT_REPLAY:
+ __P4SETMASK(lpr);
+ break;
+ case PMC_EV_P4_STORE_PORT_REPLAY:
+ __P4SETMASK(spr);
+ break;
+ case PMC_EV_P4_MOB_LOAD_REPLAY:
+ __P4SETMASK(mlr);
+ break;
+ case PMC_EV_P4_PAGE_WALK_TYPE:
+ __P4SETMASK(pwt);
+ break;
+ case PMC_EV_P4_BSQ_CACHE_REFERENCE:
+ __P4SETMASK(bcr);
+ break;
+ case PMC_EV_P4_IOQ_ALLOCATION:
+ __P4SETMASK(ia);
+ has_busreqtype = 1;
+ break;
+ case PMC_EV_P4_IOQ_ACTIVE_ENTRIES:
+ __P4SETMASK(iae);
+ has_busreqtype = 1;
+ break;
+ case PMC_EV_P4_FSB_DATA_ACTIVITY:
+ __P4SETMASK(fda);
+ break;
+ case PMC_EV_P4_BSQ_ALLOCATION:
+ __P4SETMASK(ba);
+ break;
+ case PMC_EV_P4_SSE_INPUT_ASSIST:
+ __P4SETMASK(sia);
+ break;
+ case PMC_EV_P4_PACKED_SP_UOP:
+ __P4SETMASK(psu);
+ break;
+ case PMC_EV_P4_PACKED_DP_UOP:
+ __P4SETMASK(pdu);
+ break;
+ case PMC_EV_P4_SCALAR_SP_UOP:
+ __P4SETMASK(ssu);
+ break;
+ case PMC_EV_P4_SCALAR_DP_UOP:
+ __P4SETMASK(sdu);
+ break;
+ case PMC_EV_P4_64BIT_MMX_UOP:
+ __P4SETMASK(64bmu);
+ break;
+ case PMC_EV_P4_128BIT_MMX_UOP:
+ __P4SETMASK(128bmu);
+ break;
+ case PMC_EV_P4_X87_FP_UOP:
+ __P4SETMASK(xfu);
+ break;
+ case PMC_EV_P4_X87_SIMD_MOVES_UOP:
+ __P4SETMASK(xsmu);
+ break;
+ case PMC_EV_P4_GLOBAL_POWER_EVENTS:
+ __P4SETMASK(gpe);
+ break;
+ case PMC_EV_P4_TC_MS_XFER:
+ __P4SETMASK(tmx);
+ break;
+ case PMC_EV_P4_UOP_QUEUE_WRITES:
+ __P4SETMASK(uqw);
+ break;
+ case PMC_EV_P4_RETIRED_MISPRED_BRANCH_TYPE:
+ __P4SETMASK(rmbt);
+ break;
+ case PMC_EV_P4_RETIRED_BRANCH_TYPE:
+ __P4SETMASK(rbt);
+ break;
+ case PMC_EV_P4_RESOURCE_STALL:
+ __P4SETMASK(rs);
+ break;
+ case PMC_EV_P4_WC_BUFFER:
+ __P4SETMASK(wb);
+ break;
+ case PMC_EV_P4_BSQ_ACTIVE_ENTRIES:
+ case PMC_EV_P4_B2B_CYCLES:
+ case PMC_EV_P4_BNR:
+ case PMC_EV_P4_SNOOP:
+ case PMC_EV_P4_RESPONSE:
+ break;
+ case PMC_EV_P4_FRONT_END_EVENT:
+ __P4SETMASK(fee);
+ break;
+ case PMC_EV_P4_EXECUTION_EVENT:
+ __P4SETMASK(ee);
+ break;
+ case PMC_EV_P4_REPLAY_EVENT:
+ __P4SETMASK(re);
+ break;
+ case PMC_EV_P4_INSTR_RETIRED:
+ __P4SETMASK(insret);
+ break;
+ case PMC_EV_P4_UOPS_RETIRED:
+ __P4SETMASK(ur);
+ break;
+ case PMC_EV_P4_UOP_TYPE:
+ __P4SETMASK(ut);
+ break;
+ case PMC_EV_P4_BRANCH_RETIRED:
+ __P4SETMASK(br);
+ break;
+ case PMC_EV_P4_MISPRED_BRANCH_RETIRED:
+ __P4SETMASK(mbr);
+ break;
+ case PMC_EV_P4_X87_ASSIST:
+ __P4SETMASK(xa);
+ break;
+ case PMC_EV_P4_MACHINE_CLEAR:
+ __P4SETMASK(machclr);
+ break;
+ default:
+ return -1;
+ }
+
+ /* process additional flags */
+ while ((p = strsep(&ctrspec, ",")) != NULL) {
+ if (KWPREFIXMATCH(p, P4_KW_ACTIVE)) {
+ q = strchr(p, '=');
+ if (*++q == '\0') /* skip '=' */
+ return -1;
+
+ if (strcmp(q, P4_KW_ACTIVE_NONE) == 0)
+ cccractivemask = 0x0;
+ else if (strcmp(q, P4_KW_ACTIVE_SINGLE) == 0)
+ cccractivemask = 0x1;
+ else if (strcmp(q, P4_KW_ACTIVE_BOTH) == 0)
+ cccractivemask = 0x2;
+ else if (strcmp(q, P4_KW_ACTIVE_ANY) == 0)
+ cccractivemask = 0x3;
+ else
+ return -1;
+
+ } else if (KWPREFIXMATCH(p, P4_KW_BUSREQTYPE)) {
+ if (has_busreqtype == 0)
+ return -1;
+
+ q = strchr(p, '=');
+ if (*++q == '\0') /* skip '=' */
+ return -1;
+
+ count = strtol(q, &e, 0);
+ if (e == q || *e != '\0')
+ return -1;
+ evmask = (evmask & ~0x1F) | (count & 0x1F);
+ } else if (KWMATCH(p, P4_KW_CASCADE))
+ pmc_config->pm_caps |= PMC_CAP_CASCADE;
+ else if (KWMATCH(p, P4_KW_EDGE))
+ pmc_config->pm_caps |= PMC_CAP_EDGE;
+ else if (KWMATCH(p, P4_KW_INV))
+ pmc_config->pm_caps |= PMC_CAP_INVERT;
+ else if (KWPREFIXMATCH(p, P4_KW_MASK "=")) {
+ if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0)
+ return -1;
+ pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
+ } else if (KWMATCH(p, P4_KW_OS))
+ pmc_config->pm_caps |= PMC_CAP_SYSTEM;
+ else if (KWMATCH(p, P4_KW_PRECISE))
+ pmc_config->pm_caps |= PMC_CAP_PRECISE;
+ else if (KWPREFIXMATCH(p, P4_KW_TAG "=")) {
+ if (has_tag == 0)
+ return -1;
+
+ q = strchr(p, '=');
+ if (*++q == '\0') /* skip '=' */
+ return -1;
+
+ count = strtol(q, &e, 0);
+ if (e == q || *e != '\0')
+ return -1;
+
+ pmc_config->pm_caps |= PMC_CAP_TAGGING;
+ pmc_config->pm_md.pm_p4.pm_p4_escrconfig |=
+ P4_ESCR_TO_TAG_VALUE(count);
+ } else if (KWPREFIXMATCH(p, P4_KW_THRESHOLD "=")) {
+ q = strchr(p, '=');
+ if (*++q == '\0') /* skip '=' */
+ return -1;
+
+ count = strtol(q, &e, 0);
+ if (e == q || *e != '\0')
+ return -1;
+
+ pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
+ pmc_config->pm_md.pm_p4.pm_p4_cccrconfig &=
+ ~P4_CCCR_THRESHOLD_MASK;
+ pmc_config->pm_md.pm_p4.pm_p4_cccrconfig |=
+ P4_CCCR_TO_THRESHOLD(count);
+ } else if (KWMATCH(p, P4_KW_USR))
+ pmc_config->pm_caps |= PMC_CAP_USER;
+ else
+ return -1;
+ }
+
+ /* other post processing */
+ if (pe == PMC_EV_P4_IOQ_ALLOCATION ||
+ pe == PMC_EV_P4_FSB_DATA_ACTIVITY ||
+ pe == PMC_EV_P4_BSQ_ALLOCATION)
+ pmc_config->pm_caps |= PMC_CAP_EDGE;
+
+ /* fill in thread activity mask */
+ pmc_config->pm_md.pm_p4.pm_p4_cccrconfig |=
+ P4_CCCR_TO_ACTIVE_THREAD(cccractivemask);
+
+ if (evmask)
+ pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
+
+ switch (pe) {
+ case PMC_EV_P4_FSB_DATA_ACTIVITY:
+ if ((evmask & 0x06) == 0x06 ||
+ (evmask & 0x18) == 0x18)
+ return -1; /* can't have own+other bits together */
+ if (evmask == 0) /* default:drdy-{drv,own}+dbsy{drv,own} */
+ evmask = 0x1D;
+ break;
+ case PMC_EV_P4_MACHINE_CLEAR:
+ /* only one bit is allowed to be set */
+ if ((evmask & (evmask - 1)) != 0)
+ return -1;
+ if (evmask == 0) {
+ evmask = 0x1; /* 'CLEAR' */
+ pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
+ }
+ break;
+ default:
+ if (evmask == 0 && pmask) {
+ for (pm = pmask; pm->pm_name; pm++)
+ evmask |= pm->pm_value;
+ pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
+ }
+ }
+
+ pmc_config->pm_md.pm_p4.pm_p4_escrconfig =
+ P4_ESCR_TO_EVENT_MASK(evmask);
+
+ return 0;
+}
+
+#endif
+
+#if defined(__i386__)
+
+/*
+ * Pentium style PMCs
+ */
+
+static struct pmc_event_alias p5_aliases[] = {
+ EV_ALIAS("cycles", "tsc"),
+ EV_ALIAS(NULL, NULL)
+};
+
+static int
+p5_allocate_pmc(enum pmc_event pe, char *ctrspec,
+ struct pmc_op_pmcallocate *pmc_config)
+{
+ return -1 || pe || ctrspec || pmc_config; /* shut up gcc */
+}
+
+/*
+ * Pentium Pro style PMCs. These PMCs are found in Pentium II, Pentium III,
+ * and Pentium M CPUs.
+ */
+
+static struct pmc_event_alias p6_aliases[] = {
+ EV_ALIAS("branches", "p6-br-inst-retired"),
+ EV_ALIAS("branch-mispredicts", "p6-br-miss-pred-retired"),
+ EV_ALIAS("cycles", "tsc"),
+ EV_ALIAS("dc-misses", "p6-dcu-lines-in"),
+ EV_ALIAS("ic-misses", "p6-ifu-ifetch-miss"),
+ EV_ALIAS("instructions", "p6-inst-retired"),
+ EV_ALIAS("interrupts", "p6-hw-int-rx"),
+ EV_ALIAS("unhalted-cycles", "p6-cpu-clk-unhalted"),
+ EV_ALIAS(NULL, NULL)
+};
+
+#define P6_KW_CMASK "cmask"
+#define P6_KW_EDGE "edge"
+#define P6_KW_INV "inv"
+#define P6_KW_OS "os"
+#define P6_KW_UMASK "umask"
+#define P6_KW_USR "usr"
+
+static struct pmc_masks p6_mask_mesi[] = {
+ PMCMASK(m, 0x01),
+ PMCMASK(e, 0x02),
+ PMCMASK(s, 0x04),
+ PMCMASK(i, 0x08),
+ NULLMASK
+};
+
+static struct pmc_masks p6_mask_mesihw[] = {
+ PMCMASK(m, 0x01),
+ PMCMASK(e, 0x02),
+ PMCMASK(s, 0x04),
+ PMCMASK(i, 0x08),
+ PMCMASK(nonhw, 0x00),
+ PMCMASK(hw, 0x10),
+ PMCMASK(both, 0x30),
+ NULLMASK
+};
+
+static struct pmc_masks p6_mask_hw[] = {
+ PMCMASK(nonhw, 0x00),
+ PMCMASK(hw, 0x10),
+ PMCMASK(both, 0x30),
+ NULLMASK
+};
+
+static struct pmc_masks p6_mask_any[] = {
+ PMCMASK(self, 0x00),
+ PMCMASK(any, 0x20),
+ NULLMASK
+};
+
+static struct pmc_masks p6_mask_ekp[] = {
+ PMCMASK(nta, 0x00),
+ PMCMASK(t1, 0x01),
+ PMCMASK(t2, 0x02),
+ PMCMASK(wos, 0x03),
+ NULLMASK
+};
+
+static struct pmc_masks p6_mask_pps[] = {
+ PMCMASK(packed-and-scalar, 0x00),
+ PMCMASK(scalar, 0x01),
+ NULLMASK
+};
+
+static struct pmc_masks p6_mask_mite[] = {
+ PMCMASK(packed-multiply, 0x01),
+ PMCMASK(packed-shift, 0x02),
+ PMCMASK(pack, 0x04),
+ PMCMASK(unpack, 0x08),
+ PMCMASK(packed-logical, 0x10),
+ PMCMASK(packed-arithmetic, 0x20),
+ NULLMASK
+};
+
+static struct pmc_masks p6_mask_fmt[] = {
+ PMCMASK(mmxtofp, 0x00),
+ PMCMASK(fptommx, 0x01),
+ NULLMASK
+};
+
+static struct pmc_masks p6_mask_sr[] = {
+ PMCMASK(es, 0x01),
+ PMCMASK(ds, 0x02),
+ PMCMASK(fs, 0x04),
+ PMCMASK(gs, 0x08),
+ NULLMASK
+};
+
+static struct pmc_masks p6_mask_eet[] = {
+ PMCMASK(all, 0x00),
+ PMCMASK(freq, 0x02),
+ NULLMASK
+};
+
+static struct pmc_masks p6_mask_efur[] = {
+ PMCMASK(all, 0x00),
+ PMCMASK(loadop, 0x01),
+ PMCMASK(stdsta, 0x02),
+ NULLMASK
+};
+
+static struct pmc_masks p6_mask_essir[] = {
+ PMCMASK(sse-packed-single, 0x00),
+ PMCMASK(sse-packed-single-scalar-single, 0x01),
+ PMCMASK(sse2-packed-double, 0x02),
+ PMCMASK(sse2-scalar-double, 0x03),
+ NULLMASK
+};
+
+static struct pmc_masks p6_mask_esscir[] = {
+ PMCMASK(sse-packed-single, 0x00),
+ PMCMASK(sse-scalar-single, 0x01),
+ PMCMASK(sse2-packed-double, 0x02),
+ PMCMASK(sse2-scalar-double, 0x03),
+ NULLMASK
+};
+
+/* P6 event parser */
+static int
+p6_allocate_pmc(enum pmc_event pe, char *ctrspec,
+ struct pmc_op_pmcallocate *pmc_config)
+{
+ char *e, *p, *q;
+ uint32_t evmask;
+ int count, n;
+ const struct pmc_masks *pm, *pmask;
+
+ pmc_config->pm_caps |= PMC_CAP_READ;
+ pmc_config->pm_md.pm_ppro.pm_ppro_config = 0;
+
+ if (pe == PMC_EV_TSC_TSC) {
+ if (ctrspec && *ctrspec != '\0')
+ return -1;
+ return 0;
+ }
+
+ pmc_config->pm_caps |= PMC_CAP_WRITE;
+ evmask = 0;
+
+#define P6MASKSET(M) pmask = p6_mask_ ## M
+
+ switch(pe) {
+ case PMC_EV_P6_L2_IFETCH: P6MASKSET(mesi); break;
+ case PMC_EV_P6_L2_LD: P6MASKSET(mesi); break;
+ case PMC_EV_P6_L2_ST: P6MASKSET(mesi); break;
+ case PMC_EV_P6_L2_RQSTS: P6MASKSET(mesi); break;
+ case PMC_EV_P6_BUS_DRDY_CLOCKS:
+ case PMC_EV_P6_BUS_LOCK_CLOCKS:
+ case PMC_EV_P6_BUS_TRAN_BRD:
+ case PMC_EV_P6_BUS_TRAN_RFO:
+ case PMC_EV_P6_BUS_TRANS_WB:
+ case PMC_EV_P6_BUS_TRAN_IFETCH:
+ case PMC_EV_P6_BUS_TRAN_INVAL:
+ case PMC_EV_P6_BUS_TRAN_PWR:
+ case PMC_EV_P6_BUS_TRANS_P:
+ case PMC_EV_P6_BUS_TRANS_IO:
+ case PMC_EV_P6_BUS_TRAN_DEF:
+ case PMC_EV_P6_BUS_TRAN_BURST:
+ case PMC_EV_P6_BUS_TRAN_ANY:
+ case PMC_EV_P6_BUS_TRAN_MEM:
+ P6MASKSET(any); break;
+ case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED:
+ case PMC_EV_P6_EMON_KNI_PREF_MISS:
+ P6MASKSET(ekp); break;
+ case PMC_EV_P6_EMON_KNI_INST_RETIRED:
+ case PMC_EV_P6_EMON_KNI_COMP_INST_RET:
+ P6MASKSET(pps); break;
+ case PMC_EV_P6_MMX_INSTR_TYPE_EXEC:
+ P6MASKSET(mite); break;
+ case PMC_EV_P6_FP_MMX_TRANS:
+ P6MASKSET(fmt); break;
+ case PMC_EV_P6_SEG_RENAME_STALLS:
+ case PMC_EV_P6_SEG_REG_RENAMES:
+ P6MASKSET(sr); break;
+ case PMC_EV_P6_EMON_EST_TRANS:
+ P6MASKSET(eet); break;
+ case PMC_EV_P6_EMON_FUSED_UOPS_RET:
+ P6MASKSET(efur); break;
+ case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED:
+ P6MASKSET(essir); break;
+ case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED:
+ P6MASKSET(esscir); break;
+ default:
+ pmask = NULL;
+ break;
+ }
+
+ /* Pentium M PMCs have a few events with different semantics */
+ if (cpu_info.pm_cputype == PMC_CPU_INTEL_PM) {
+ if (pe == PMC_EV_P6_L2_LD ||
+ pe == PMC_EV_P6_L2_LINES_IN ||
+ pe == PMC_EV_P6_L2_LINES_OUT)
+ P6MASKSET(mesihw);
+ else if (pe == PMC_EV_P6_L2_M_LINES_OUTM)
+ P6MASKSET(hw);
+ }
+
+ /* Parse additional modifiers if present */
+ while ((p = strsep(&ctrspec, ",")) != NULL) {
+ if (KWPREFIXMATCH(p, P6_KW_CMASK "=")) {
+ q = strchr(p, '=');
+ if (*++q == '\0') /* skip '=' */
+ return -1;
+ count = strtol(q, &e, 0);
+ if (e == q || *e != '\0')
+ return -1;
+ pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
+ pmc_config->pm_md.pm_ppro.pm_ppro_config |=
+ P6_EVSEL_TO_CMASK(count);
+ } else if (KWMATCH(p, P6_KW_EDGE)) {
+ pmc_config->pm_caps |= PMC_CAP_EDGE;
+ } else if (KWMATCH(p, P6_KW_INV)) {
+ pmc_config->pm_caps |= PMC_CAP_INVERT;
+ } else if (KWMATCH(p, P6_KW_OS)) {
+ pmc_config->pm_caps |= PMC_CAP_SYSTEM;
+ } else if (KWPREFIXMATCH(p, P6_KW_UMASK "=")) {
+ evmask = 0;
+ if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0)
+ return -1;
+ if ((pe == PMC_EV_P6_BUS_DRDY_CLOCKS ||
+ pe == PMC_EV_P6_BUS_LOCK_CLOCKS ||
+ pe == PMC_EV_P6_BUS_TRAN_BRD ||
+ pe == PMC_EV_P6_BUS_TRAN_RFO ||
+ pe == PMC_EV_P6_BUS_TRAN_IFETCH ||
+ pe == PMC_EV_P6_BUS_TRAN_INVAL ||
+ pe == PMC_EV_P6_BUS_TRAN_PWR ||
+ pe == PMC_EV_P6_BUS_TRAN_DEF ||
+ pe == PMC_EV_P6_BUS_TRAN_BURST ||
+ pe == PMC_EV_P6_BUS_TRAN_ANY ||
+ pe == PMC_EV_P6_BUS_TRAN_MEM ||
+ pe == PMC_EV_P6_BUS_TRANS_IO ||
+ pe == PMC_EV_P6_BUS_TRANS_P ||
+ pe == PMC_EV_P6_BUS_TRANS_WB ||
+ pe == PMC_EV_P6_EMON_EST_TRANS ||
+ pe == PMC_EV_P6_EMON_FUSED_UOPS_RET ||
+ pe == PMC_EV_P6_EMON_KNI_COMP_INST_RET ||
+ pe == PMC_EV_P6_EMON_KNI_INST_RETIRED ||
+ pe == PMC_EV_P6_EMON_KNI_PREF_DISPATCHED ||
+ pe == PMC_EV_P6_EMON_KNI_PREF_MISS ||
+ pe == PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED ||
+ pe == PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED ||
+ pe == PMC_EV_P6_FP_MMX_TRANS)
+ && (n > 1))
+ return -1; /* only one mask keyword allowed */
+ pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
+ } else if (KWMATCH(p, P6_KW_USR)) {
+ pmc_config->pm_caps |= PMC_CAP_USER;
+ } else
+ return -1;
+ }
+
+ /* post processing */
+ switch (pe) {
+
+ /*
+ * The following events default to an evmask of 0
+ */
+
+ /* default => 'self' */
+ case PMC_EV_P6_BUS_DRDY_CLOCKS:
+ case PMC_EV_P6_BUS_LOCK_CLOCKS:
+ case PMC_EV_P6_BUS_TRAN_BRD:
+ case PMC_EV_P6_BUS_TRAN_RFO:
+ case PMC_EV_P6_BUS_TRANS_WB:
+ case PMC_EV_P6_BUS_TRAN_IFETCH:
+ case PMC_EV_P6_BUS_TRAN_INVAL:
+ case PMC_EV_P6_BUS_TRAN_PWR:
+ case PMC_EV_P6_BUS_TRANS_P:
+ case PMC_EV_P6_BUS_TRANS_IO:
+ case PMC_EV_P6_BUS_TRAN_DEF:
+ case PMC_EV_P6_BUS_TRAN_BURST:
+ case PMC_EV_P6_BUS_TRAN_ANY:
+ case PMC_EV_P6_BUS_TRAN_MEM:
+
+ /* default => 'nta' */
+ case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED:
+ case PMC_EV_P6_EMON_KNI_PREF_MISS:
+
+ /* default => 'packed and scalar' */
+ case PMC_EV_P6_EMON_KNI_INST_RETIRED:
+ case PMC_EV_P6_EMON_KNI_COMP_INST_RET:
+
+ /* default => 'mmx to fp transitions' */
+ case PMC_EV_P6_FP_MMX_TRANS:
+
+ /* default => 'SSE Packed Single' */
+ case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED:
+ case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED:
+
+ /* default => 'all fused micro-ops' */
+ case PMC_EV_P6_EMON_FUSED_UOPS_RET:
+
+ /* default => 'all transitions' */
+ case PMC_EV_P6_EMON_EST_TRANS:
+ break;
+
+ case PMC_EV_P6_MMX_UOPS_EXEC:
+ evmask = 0x0F; /* only value allowed */
+ break;
+
+ default:
+
+ /*
+ * For all other events, set the default event mask
+ * to a logical OR of all the allowed event mask bits.
+ */
+
+ if (evmask == 0 && pmask) {
+ for (pm = pmask; pm->pm_name; pm++)
+ evmask |= pm->pm_value;
+ pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
+ }
+
+ break;
+ }
+
+ if (pmc_config->pm_caps & PMC_CAP_QUALIFIER)
+ pmc_config->pm_md.pm_ppro.pm_ppro_config |=
+ P6_EVSEL_TO_UMASK(evmask);
+
+ return 0;
+}
+
+#endif
+
+/*
+ * API entry points
+ */
+
+
+int
+pmc_allocate(const char *ctrspec, enum pmc_mode mode,
+ uint32_t flags, int cpu, pmc_id_t *pmcid)
+{
+ int retval;
+ enum pmc_event pe;
+ char *r, *spec_copy;
+ const char *ctrname;
+ const struct pmc_event_alias *p;
+ struct pmc_op_pmcallocate pmc_config;
+
+ spec_copy = NULL;
+ retval = -1;
+
+ if (mode != PMC_MODE_SS && mode != PMC_MODE_TS &&
+ mode != PMC_MODE_SC && mode != PMC_MODE_TC) {
+ errno = EINVAL;
+ goto out;
+ }
+
+ /* replace an event alias with the canonical event specifier */
+ if (pmc_mdep_event_aliases)
+ for (p = pmc_mdep_event_aliases; p->pm_alias; p++)
+ if (!strcmp(ctrspec, p->pm_alias)) {
+ spec_copy = strdup(p->pm_spec);
+ break;
+ }
+
+ if (spec_copy == NULL)
+ spec_copy = strdup(ctrspec);
+
+ r = spec_copy;
+ ctrname = strsep(&r, ",");
+
+ /* look for the given counter name */
+
+ for (pe = PMC_EVENT_FIRST; pe < (PMC_EVENT_LAST+1); pe++)
+ if (!strcmp(ctrname, pmc_event_table[pe].pm_ev_name))
+ break;
+
+ if (pe > PMC_EVENT_LAST) {
+ errno = EINVAL;
+ goto out;
+ }
+
+ bzero(&pmc_config, sizeof(pmc_config));
+ pmc_config.pm_ev = pmc_event_table[pe].pm_ev_code;
+ pmc_config.pm_class = pmc_event_table[pe].pm_ev_class;
+ pmc_config.pm_cpu = cpu;
+ pmc_config.pm_mode = mode;
+ pmc_config.pm_flags = flags;
+
+ if (PMC_IS_SAMPLING_MODE(mode))
+ pmc_config.pm_caps |= PMC_CAP_INTERRUPT;
+
+ if (pmc_mdep_allocate_pmc(pe, r, &pmc_config) < 0) {
+ errno = EINVAL;
+ goto out;
+ }
+
+ if (PMC_CALL(PMCALLOCATE, &pmc_config) < 0)
+ goto out;
+
+ *pmcid = pmc_config.pm_pmcid;
+
+ retval = 0;
+
+ out:
+ if (spec_copy)
+ free(spec_copy);
+
+ return retval;
+}
+
+int
+pmc_attach(pmc_id_t pmc, pid_t pid)
+{
+ struct pmc_op_pmcattach pmc_attach_args;
+
+ pmc_attach_args.pm_pmc = pmc;
+ pmc_attach_args.pm_pid = pid;
+
+ return PMC_CALL(PMCATTACH, &pmc_attach_args);
+}
+
+int
+pmc_capabilities(pmc_id_t pmcid, uint32_t *caps)
+{
+ unsigned int i;
+ enum pmc_class cl;
+
+ cl = PMC_ID_TO_CLASS(pmcid);
+ for (i = 0; i < cpu_info.pm_nclass; i++)
+ if (cpu_info.pm_classes[i].pm_class == cl) {
+ *caps = cpu_info.pm_classes[i].pm_caps;
+ return 0;
+ }
+ return EINVAL;
+}
+
+int
+pmc_configure_logfile(int fd)
+{
+ struct pmc_op_configurelog cla;
+
+ cla.pm_logfd = fd;
+ if (PMC_CALL(CONFIGURELOG, &cla) < 0)
+ return -1;
+ return 0;
+}
+
+int
+pmc_cpuinfo(const struct pmc_cpuinfo **pci)
+{
+ if (pmc_syscall == -1) {
+ errno = ENXIO;
+ return -1;
+ }
+
+ *pci = &cpu_info;
+ return 0;
+}
+
+int
+pmc_detach(pmc_id_t pmc, pid_t pid)
+{
+ struct pmc_op_pmcattach pmc_detach_args;
+
+ pmc_detach_args.pm_pmc = pmc;
+ pmc_detach_args.pm_pid = pid;
+
+ return PMC_CALL(PMCDETACH, &pmc_detach_args);
+}
+
+int
+pmc_disable(int cpu, int pmc)
+{
+ struct pmc_op_pmcadmin ssa;
+
+ ssa.pm_cpu = cpu;
+ ssa.pm_pmc = pmc;
+ ssa.pm_state = PMC_STATE_DISABLED;
+ return PMC_CALL(PMCADMIN, &ssa);
+}
+
+int
+pmc_enable(int cpu, int pmc)
+{
+ struct pmc_op_pmcadmin ssa;
+
+ ssa.pm_cpu = cpu;
+ ssa.pm_pmc = pmc;
+ ssa.pm_state = PMC_STATE_FREE;
+ return PMC_CALL(PMCADMIN, &ssa);
+}
+
+/*
+ * Return a list of events known to a given PMC class. 'cl' is the
+ * PMC class identifier, 'eventnames' is the returned list of 'const
+ * char *' pointers pointing to the names of the events. 'nevents' is
+ * the number of event name pointers returned.
+ *
+ * The space for 'eventnames' is allocated using malloc(3). The caller
+ * is responsible for freeing this space when done.
+ */
+
+int
+pmc_event_names_of_class(enum pmc_class cl, const char ***eventnames,
+ int *nevents)
+{
+ int count;
+ const char **names;
+ const struct pmc_event_descr *ev;
+
+ switch (cl)
+ {
+ case PMC_CLASS_TSC:
+ ev = &pmc_event_table[PMC_EV_TSC_TSC];
+ count = 1;
+ break;
+ case PMC_CLASS_K7:
+ ev = &pmc_event_table[PMC_EV_K7_FIRST];
+ count = PMC_EV_K7_LAST - PMC_EV_K7_FIRST + 1;
+ break;
+ case PMC_CLASS_K8:
+ ev = &pmc_event_table[PMC_EV_K8_FIRST];
+ count = PMC_EV_K8_LAST - PMC_EV_K8_FIRST + 1;
+ break;
+ case PMC_CLASS_P5:
+ ev = &pmc_event_table[PMC_EV_P5_FIRST];
+ count = PMC_EV_P5_LAST - PMC_EV_P5_FIRST + 1;
+ break;
+ case PMC_CLASS_P6:
+ ev = &pmc_event_table[PMC_EV_P6_FIRST];
+ count = PMC_EV_P6_LAST - PMC_EV_P6_FIRST + 1;
+ break;
+ case PMC_CLASS_P4:
+ ev = &pmc_event_table[PMC_EV_P4_FIRST];
+ count = PMC_EV_P4_LAST - PMC_EV_P4_FIRST + 1;
+ break;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ if ((names = malloc(count * sizeof(const char *))) == NULL)
+ return -1;
+
+ *eventnames = names;
+ *nevents = count;
+
+ for (;count--; ev++, names++)
+ *names = ev->pm_ev_name;
+ return 0;
+}
+
+int
+pmc_flush_logfile(void)
+{
+ return PMC_CALL(FLUSHLOG,0);
+}
+
+int
+pmc_get_driver_stats(struct pmc_driverstats *ds)
+{
+ struct pmc_op_getdriverstats gms;
+
+ if (PMC_CALL(GETDRIVERSTATS, &gms) < 0)
+ return -1;
+
+ /* copy out fields in the current userland<->library interface */
+ ds->pm_intr_ignored = gms.pm_intr_ignored;
+ ds->pm_intr_processed = gms.pm_intr_processed;
+ ds->pm_intr_bufferfull = gms.pm_intr_bufferfull;
+ ds->pm_syscalls = gms.pm_syscalls;
+ ds->pm_syscall_errors = gms.pm_syscall_errors;
+ ds->pm_buffer_requests = gms.pm_buffer_requests;
+ ds->pm_buffer_requests_failed = gms.pm_buffer_requests_failed;
+ ds->pm_log_sweeps = gms.pm_log_sweeps;
+
+ return 0;
+}
+
+int
+pmc_get_msr(pmc_id_t pmc, uint32_t *msr)
+{
+ struct pmc_op_getmsr gm;
+
+ gm.pm_pmcid = pmc;
+ if (PMC_CALL(PMCGETMSR, &gm) < 0)
+ return -1;
+ *msr = gm.pm_msr;
+ return 0;
+}
+
+int
+pmc_init(void)
+{
+ int error, pmc_mod_id;
+ unsigned int n;
+ uint32_t abi_version;
+ struct module_stat pmc_modstat;
+ struct pmc_op_getcpuinfo op_cpu_info;
+
+ if (pmc_syscall != -1) /* already inited */
+ return 0;
+
+ /* retrieve the system call number from the KLD */
+ if ((pmc_mod_id = modfind(PMC_MODULE_NAME)) < 0)
+ return -1;
+
+ pmc_modstat.version = sizeof(struct module_stat);
+ if ((error = modstat(pmc_mod_id, &pmc_modstat)) < 0)
+ return -1;
+
+ pmc_syscall = pmc_modstat.data.intval;
+
+ /* check the kernel module's ABI against our compiled-in version */
+ abi_version = PMC_VERSION;
+ if (PMC_CALL(GETMODULEVERSION, &abi_version) < 0)
+ return (pmc_syscall = -1);
+
+ /* ignore patch & minor numbers for the comparision */
+ if ((abi_version & 0xFF000000) != (PMC_VERSION & 0xFF000000)) {
+ errno = EPROGMISMATCH;
+ return (pmc_syscall = -1);
+ }
+
+ if (PMC_CALL(GETCPUINFO, &op_cpu_info) < 0)
+ return (pmc_syscall = -1);
+
+ cpu_info.pm_cputype = op_cpu_info.pm_cputype;
+ cpu_info.pm_ncpu = op_cpu_info.pm_ncpu;
+ cpu_info.pm_npmc = op_cpu_info.pm_npmc;
+ cpu_info.pm_nclass = op_cpu_info.pm_nclass;
+ for (n = 0; n < cpu_info.pm_nclass; n++)
+ cpu_info.pm_classes[n] = op_cpu_info.pm_classes[n];
+
+ /* set parser pointer */
+ switch (cpu_info.pm_cputype) {
+#if defined(__i386__)
+ case PMC_CPU_AMD_K7:
+ pmc_mdep_event_aliases = k7_aliases;
+ pmc_mdep_allocate_pmc = k7_allocate_pmc;
+ break;
+ case PMC_CPU_INTEL_P5:
+ pmc_mdep_event_aliases = p5_aliases;
+ pmc_mdep_allocate_pmc = p5_allocate_pmc;
+ break;
+ case PMC_CPU_INTEL_P6: /* P6 ... Pentium M CPUs have */
+ case PMC_CPU_INTEL_PII: /* similar PMCs. */
+ case PMC_CPU_INTEL_PIII:
+ case PMC_CPU_INTEL_PM:
+ pmc_mdep_event_aliases = p6_aliases;
+ pmc_mdep_allocate_pmc = p6_allocate_pmc;
+ break;
+#endif
+#if defined(__amd64__) || defined(__i386__)
+ case PMC_CPU_INTEL_PIV:
+ pmc_mdep_event_aliases = p4_aliases;
+ pmc_mdep_allocate_pmc = p4_allocate_pmc;
+ break;
+ case PMC_CPU_AMD_K8:
+ pmc_mdep_event_aliases = k8_aliases;
+ pmc_mdep_allocate_pmc = k8_allocate_pmc;
+ break;
+#endif
+
+ default:
+ /*
+ * Some kind of CPU this version of the library knows nothing
+ * about. This shouldn't happen since the abi version check
+ * should have caught this.
+ */
+ errno = ENXIO;
+ return (pmc_syscall = -1);
+ }
+
+ return 0;
+}
+
+const char *
+pmc_name_of_capability(enum pmc_caps cap)
+{
+ int i;
+
+ /*
+ * 'cap' should have a single bit set and should be in
+ * range.
+ */
+
+ if ((cap & (cap - 1)) || cap < PMC_CAP_FIRST ||
+ cap > PMC_CAP_LAST) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ i = ffs(cap);
+
+ return pmc_capability_names[i - 1];
+}
+
+const char *
+pmc_name_of_class(enum pmc_class pc)
+{
+ if ((int) pc >= PMC_CLASS_FIRST &&
+ pc <= PMC_CLASS_LAST)
+ return pmc_class_names[pc];
+
+ errno = EINVAL;
+ return NULL;
+}
+
+const char *
+pmc_name_of_cputype(enum pmc_cputype cp)
+{
+ if ((int) cp >= PMC_CPU_FIRST &&
+ cp <= PMC_CPU_LAST)
+ return pmc_cputype_names[cp];
+ errno = EINVAL;
+ return NULL;
+}
+
+const char *
+pmc_name_of_disposition(enum pmc_disp pd)
+{
+ if ((int) pd >= PMC_DISP_FIRST &&
+ pd <= PMC_DISP_LAST)
+ return pmc_disposition_names[pd];
+
+ errno = EINVAL;
+ return NULL;
+}
+
+const char *
+pmc_name_of_event(enum pmc_event pe)
+{
+ if ((int) pe >= PMC_EVENT_FIRST &&
+ pe <= PMC_EVENT_LAST)
+ return pmc_event_table[pe].pm_ev_name;
+
+ errno = EINVAL;
+ return NULL;
+}
+
+const char *
+pmc_name_of_mode(enum pmc_mode pm)
+{
+ if ((int) pm >= PMC_MODE_FIRST &&
+ pm <= PMC_MODE_LAST)
+ return pmc_mode_names[pm];
+
+ errno = EINVAL;
+ return NULL;
+}
+
+const char *
+pmc_name_of_state(enum pmc_state ps)
+{
+ if ((int) ps >= PMC_STATE_FIRST &&
+ ps <= PMC_STATE_LAST)
+ return pmc_state_names[ps];
+
+ errno = EINVAL;
+ return NULL;
+}
+
+int
+pmc_ncpu(void)
+{
+ if (pmc_syscall == -1) {
+ errno = ENXIO;
+ return -1;
+ }
+
+ return cpu_info.pm_ncpu;
+}
+
+int
+pmc_npmc(int cpu)
+{
+ if (pmc_syscall == -1) {
+ errno = ENXIO;
+ return -1;
+ }
+
+ if (cpu < 0 || cpu >= (int) cpu_info.pm_ncpu) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ return cpu_info.pm_npmc;
+}
+
+int
+pmc_pmcinfo(int cpu, struct pmc_pmcinfo **ppmci)
+{
+ int nbytes, npmc;
+ struct pmc_op_getpmcinfo *pmci;
+
+ if ((npmc = pmc_npmc(cpu)) < 0)
+ return -1;
+
+ nbytes = sizeof(struct pmc_op_getpmcinfo) +
+ npmc * sizeof(struct pmc_info);
+
+ if ((pmci = calloc(1, nbytes)) == NULL)
+ return -1;
+
+ pmci->pm_cpu = cpu;
+
+ if (PMC_CALL(GETPMCINFO, pmci) < 0) {
+ free(pmci);
+ return -1;
+ }
+
+ /* kernel<->library, library<->userland interfaces are identical */
+ *ppmci = (struct pmc_pmcinfo *) pmci;
+
+ return 0;
+}
+
+int
+pmc_read(pmc_id_t pmc, pmc_value_t *value)
+{
+ struct pmc_op_pmcrw pmc_read_op;
+
+ pmc_read_op.pm_pmcid = pmc;
+ pmc_read_op.pm_flags = PMC_F_OLDVALUE;
+ pmc_read_op.pm_value = -1;
+
+ if (PMC_CALL(PMCRW, &pmc_read_op) < 0)
+ return -1;
+
+ *value = pmc_read_op.pm_value;
+
+ return 0;
+}
+
+int
+pmc_release(pmc_id_t pmc)
+{
+ struct pmc_op_simple pmc_release_args;
+
+ pmc_release_args.pm_pmcid = pmc;
+
+ return PMC_CALL(PMCRELEASE, &pmc_release_args);
+}
+
+int
+pmc_rw(pmc_id_t pmc, pmc_value_t newvalue, pmc_value_t *oldvaluep)
+{
+ struct pmc_op_pmcrw pmc_rw_op;
+
+ pmc_rw_op.pm_pmcid = pmc;
+ pmc_rw_op.pm_flags = PMC_F_NEWVALUE | PMC_F_OLDVALUE;
+ pmc_rw_op.pm_value = newvalue;
+
+ if (PMC_CALL(PMCRW, &pmc_rw_op) < 0)
+ return -1;
+
+ *oldvaluep = pmc_rw_op.pm_value;
+
+ return 0;
+}
+
+int
+pmc_set(pmc_id_t pmc, pmc_value_t value)
+{
+ struct pmc_op_pmcsetcount sc;
+
+ sc.pm_pmcid = pmc;
+ sc.pm_count = value;
+
+ if (PMC_CALL(PMCSETCOUNT, &sc) < 0)
+ return -1;
+
+ return 0;
+
+}
+
+int
+pmc_start(pmc_id_t pmc)
+{
+ struct pmc_op_simple pmc_start_args;
+
+ pmc_start_args.pm_pmcid = pmc;
+ return PMC_CALL(PMCSTART, &pmc_start_args);
+}
+
+int
+pmc_stop(pmc_id_t pmc)
+{
+ struct pmc_op_simple pmc_stop_args;
+
+ pmc_stop_args.pm_pmcid = pmc;
+ return PMC_CALL(PMCSTOP, &pmc_stop_args);
+}
+
+int
+pmc_width(pmc_id_t pmcid, uint32_t *width)
+{
+ unsigned int i;
+ enum pmc_class cl;
+
+ cl = PMC_ID_TO_CLASS(pmcid);
+ for (i = 0; i < cpu_info.pm_nclass; i++)
+ if (cpu_info.pm_classes[i].pm_class == cl) {
+ *width = cpu_info.pm_classes[i].pm_width;
+ return 0;
+ }
+ return EINVAL;
+}
+
+int
+pmc_write(pmc_id_t pmc, pmc_value_t value)
+{
+ struct pmc_op_pmcrw pmc_write_op;
+
+ pmc_write_op.pm_pmcid = pmc;
+ pmc_write_op.pm_flags = PMC_F_NEWVALUE;
+ pmc_write_op.pm_value = value;
+
+ return PMC_CALL(PMCRW, &pmc_write_op);
+}
+
+int
+pmc_writelog(uint32_t userdata)
+{
+ struct pmc_op_writelog wl;
+
+ wl.pm_userdata = userdata;
+ return PMC_CALL(WRITELOG, &wl);
+}
diff --git a/lib/libpmc/pmc.3 b/lib/libpmc/pmc.3
new file mode 100644
index 0000000..4c11b1a
--- /dev/null
+++ b/lib/libpmc/pmc.3
@@ -0,0 +1,3421 @@
+.\" Copyright (c) 2003-2006 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" This software is provided by Joseph Koshy ``as is'' and
+.\" any express or implied warranties, including, but not limited to, the
+.\" implied warranties of merchantability and fitness for a particular purpose
+.\" are disclaimed. in no event shall Joseph Koshy be liable
+.\" for any direct, indirect, incidental, special, exemplary, or consequential
+.\" damages (including, but not limited to, procurement of substitute goods
+.\" or services; loss of use, data, or profits; or business interruption)
+.\" however caused and on any theory of liability, whether in contract, strict
+.\" liability, or tort (including 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, 2006
+.Os
+.Dt PMC 3
+.Sh NAME
+.Nm pmc_allocate ,
+.Nm pmc_attach ,
+.Nm pmc_capabilities ,
+.Nm pmc_configure_logfile ,
+.Nm pmc_cpuinfo ,
+.Nm pmc_detach ,
+.Nm pmc_disable ,
+.Nm pmc_enable ,
+.Nm pmc_event_names_of_class ,
+.Nm pmc_flush_logfile ,
+.Nm pmc_get_driver_stats ,
+.Nm pmc_get_msr ,
+.Nm pmc_init ,
+.Nm pmc_name_of_capability ,
+.Nm pmc_name_of_class ,
+.Nm pmc_name_of_cputype ,
+.Nm pmc_name_of_event ,
+.Nm pmc_name_of_mode ,
+.Nm pmc_name_of_state ,
+.Nm pmc_ncpu ,
+.Nm pmc_npmc ,
+.Nm pmc_pmcinfo ,
+.Nm pmc_read ,
+.Nm pmc_release ,
+.Nm pmc_rw ,
+.Nm pmc_set ,
+.Nm pmc_start ,
+.Nm pmc_stop ,
+.Nm pmc_width ,
+.Nm pmc_write ,
+.Nm pmc_writelog
+.Nd programming API for using hardware performance monitoring counters
+.Sh LIBRARY
+.Lb libpmc
+.Sh SYNOPSIS
+.In pmc.h
+.Ft int
+.Fo pmc_allocate
+.Fa "const char *eventspecifier"
+.Fa "enum pmc_mode mode"
+.Fa "uint32_t flags"
+.Fa "int cpu"
+.Fa "pmc_id_t *pmcid"
+.Fc
+.Ft int
+.Fn pmc_attach "pmc_id_t pmcid" "pid_t pid"
+.Ft int
+.Fn pmc_capabilities "pmc_id_t pmc" "uint32_t *caps"
+.Ft int
+.Fn pmc_configure_logfile "int fd"
+.Ft int
+.Fn pmc_cpuinfo "const struct pmc_cpuinfo **cpu_info"
+.Ft int
+.Fn pmc_detach "pmc_id_t pmcid" "pid_t pid"
+.Ft int
+.Fn pmc_disable "int cpu" "int pmc"
+.Ft int
+.Fn pmc_enable "int cpu" "int pmc"
+.Ft int
+.Fo pmc_event_names_of_class
+.Fa "enum pmc_class cl"
+.Fa "const char ***eventnames"
+.Fa "int *nevents"
+.Fc
+.Ft int
+.Fn pmc_flush_logfile void
+.Ft int
+.Fn pmc_get_driver_stats "struct pmc_driverstats *gms"
+.Ft int
+.Fn pmc_get_msr "pmc_id_t pmc" "uint32_t *msr"
+.Ft int
+.Fn pmc_init void
+.Ft "const char *"
+.Fn pmc_name_of_capability "enum pmc_caps pc"
+.Ft "const char *"
+.Fn pmc_name_of_class "enum pmc_class pc"
+.Ft "const char *"
+.Fn pmc_name_of_cputype "enum pmc_cputype ct"
+.Ft "const char *"
+.Fn pmc_name_of_disposition "enum pmc_disp pd"
+.Ft "const char *"
+.Fn pmc_name_of_event "enum pmc_event pe"
+.Ft "const char *"
+.Fn pmc_name_of_mode "enum pmc_mode pm"
+.Ft "const char *"
+.Fn pmc_name_of_state "enum pmc_state ps"
+.Ft int
+.Fn pmc_ncpu void
+.Ft int
+.Fn pmc_npmc "int cpu"
+.Ft int
+.Fn pmc_pmcinfo "int cpu" "struct pmc_pmcinfo **pmc_info"
+.Ft int
+.Fn pmc_read "pmc_id_t pmc" "pmc_value_t *value"
+.Ft int
+.Fn pmc_release "pmc_id_t pmc"
+.Ft int
+.Fn pmc_rw "pmc_id_t pmc" "pmc_value_t newvalue" "pmc_value_t *oldvaluep"
+.Ft int
+.Fn pmc_set "pmc_id_t pmc" "pmc_value_t value"
+.Ft int
+.Fn pmc_start "pmc_id_t pmc"
+.Ft int
+.Fn pmc_stop "pmc_id_t pmc"
+.Ft int
+.Fn pmc_write "pmc_id_t pmc" "pmc_value_t value"
+.Ft int
+.Fn pmc_writelog "uint32_t userdata"
+.Ft int
+.Fn pmc_width "pmc_id_t pmc" "uint32_t *width"
+.Sh DESCRIPTION
+These functions implement a high-level library for using the
+system's hardware performance counters.
+.Pp
+PMCs are allocated using
+.Fn pmc_allocate ,
+released using
+.Fn pmc_release
+and read using
+.Fn pmc_read .
+Allocated PMCs may be started or stopped at any time using
+.Fn pmc_start
+and
+.Fn pmc_stop
+respectively.
+An allocated PMC may be of
+.Dq global
+scope, meaning that the PMC measures system-wide events, or
+.Dq process-private
+scope, meaning that the PMC only counts hardware events when
+the allocating process (or, optionally, its children)
+are active.
+.Pp
+PMCs may further be in
+.Dq "counting mode" ,
+or in
+.Dq "sampling mode" .
+Sampling mode PMCs deliver an interrupt to the CPU after
+a configured number of hardware events have been seen.
+A process-private sampling mode PMC will cause its owner
+process to get periodic
+.Dv SIGPROF
+interrupts, while a global sampling mode PMC is used to
+do system-wide statistical sampling (see
+.Xr hwpmc 4 ) .
+The sampling rate desired of a sampling-mode PMC is set using
+.Fn pmc_set .
+Counting mode PMCs do not interrupt the CPU; their values
+can be read using
+.Fn pmc_read .
+.Pp
+System-wide statistical sampling is configured by allocating
+at least one sampling mode PMC with
+global scope, and when a log file is configured using
+.Fn pmc_configure_logfile .
+The
+.Xr hwpmc 4
+driver manages system-wide statistical sampling; for more
+information please see
+.Xr hwpmc 4 .
+.Ss Application Programming Interface
+The function
+.Fn pmc_init
+initializes the
+.Nm pmc
+library.
+This function must be called first, before any of the other
+functions in the library.
+.Pp
+The function
+.Fn pmc_allocate
+allocates a counter that counts the events named by
+.Fa eventspecifier ,
+and writes the allocated counter ID to
+.Fa *pmcid .
+Argument
+.Fa eventspecifier
+comprises an PMC event name followed by an optional comma separated
+list of keywords and qualifiers.
+The allowed syntax for
+.Fa eventspecifier
+is processor architecture specific and is listed in section
+.Sx "EVENT SPECIFIERS"
+below.
+The desired PMC mode is specified by
+.Fa mode ,
+and any mode specific modifiers are specified using
+.Fa flags .
+The
+.Fa cpu
+argument is the value
+.Dv PMC_CPU_ANY ,
+or names the CPU the allocation is to be on.
+Requesting a specific CPU only makes sense for global PMCs;
+process-private PMC allocations should always specify
+.Dv PMC_CPU_ANY .
+.Pp
+By default, a PMC configured in process-virtual counting mode is set up
+to profile its owner process.
+The function
+.Fn pmc_attach
+may be used to attach the PMC to a different process.
+It
+needs to be called before the counter is first started
+with
+.Fn pmc_start .
+The function
+.Fn pmc_detach
+may be used to detach a PMC from a process it was attached to
+using a prior call to
+.Fn pmc_attach .
+.Pp
+The function
+.Fn pmc_release
+releases a PMC previously allocated with
+.Fn pmc_allocate .
+This function call implicitly detaches the PMC from all its target
+processes.
+.Pp
+An allocated PMC may be started and stopped using
+.Fn pmc_start
+and
+.Fn pmc_stop
+respectively.
+.Pp
+The current value of a PMC may be read with
+.Fn pmc_read
+and written using
+.Fn pmc_write ,
+provided the underlying hardware supports these operations on
+the allocated PMC.
+The read and write operation may be combined using
+.Fn pmc_rw .
+.Pp
+The function
+.Fn pmc_capabilities
+sets argument
+.Fa caps
+to a bitmask of capabilities supported by the PMC denoted by
+argument
+.Fa pmc .
+The function
+.Fn pmc_width
+sets argument
+.Fa width
+to the width of the PMC denoted by argument
+.Fa pmc .
+.Pp
+The
+.Fn pmc_configure_logfile
+function causes the
+.Xr hwpmc 4
+driver to log performance data to file corresponding
+to the process' file handle
+.Fa fd .
+If argument
+.Fa fd
+is \-1, then any previously configured logging is reset
+and all data queued to be written are discarded.
+.Pp
+The
+.Fn pmc_flush_logfile
+function will send all data queued inside the
+.Xr hwpmc 4
+driver to the configured log file before returning.
+The
+.Fn pmc_writelog
+function will append a log entry containing the argument
+.Fa userdata
+to the log file.
+.Pp
+The function
+.Fn pmc_set
+configures a sampling PMC
+.Fa pmc
+to interrupt every
+.Fa value
+events.
+For counting PMCs,
+.Fn pmc_set
+sets the initial value of the PMC to
+.Fa value .
+.Pp
+The function
+.Fn pmc_get_driver_statistics
+copies a snapshot of the usage statistics maintained by
+.Xr hwpmc 4
+into the memory area pointed to by argument
+.Fa gms .
+.Ss Signal Handling Requirements
+Applications using PMCs are required to handle the following signals:
+.Bl -tag -width indent
+.It Dv SIGBUS
+When the
+.Xr hwpmc 4
+module is unloaded using
+.Xr kldunload 8 ,
+processes that have PMCs allocated to them will be sent a
+.Dv SIGBUS
+signal.
+.It Dv SIGIO
+The
+.Xr hwpmc 4
+driver will send a PMC owning process a
+.Dv SIGIO
+signal if:
+.Bl -bullet
+.It
+If any process-mode PMC allocated by it loses all its
+target processes.
+.It
+If the driver encounters an error when writing log data to a
+configured log file.
+This error may be retrieved by a subsequent call to
+.Fn pmc_flush_logfile .
+.El
+.El
+.Ss Convenience Functions
+The function
+.Fn pmc_ncpu
+returns the number of CPUs present in the system.
+.Pp
+The function
+.Fn pmc_npmc
+returns the number of PMCs supported on CPU
+.Fa cpu .
+The function
+.Fn pmc_cpuinfo
+sets argument
+.Fa cpu_info
+to point to a structure with information about the system's CPUs.
+Function
+.Fn pmc_pmcinfo
+returns information about the current state of CPU
+.Fa cpu Ns 's
+PMCs.
+This function sets argument
+.Fa *pmc_info
+to point to a memory area allocated with
+.Xr calloc 3 .
+The caller is expected to
+.Fn free
+the area when done.
+.Pp
+The functions
+.Fn pmc_name_of_capability ,
+.Fn pmc_name_of_class ,
+.Fn pmc_name_of_cputype ,
+.Fn pmc_name_of_disposition ,
+.Fn pmc_name_of_event ,
+.Fn pmc_name_of_mode
+and
+.Fn pmc_name_of_state
+are useful for code wanting to print error messages.
+They return
+.Vt "const char *"
+pointers to human-readable representations of their arguments.
+These return values should not be freed using
+.Xr free 3 .
+.Pp
+The function
+.Fn pmc_event_names_of_class
+returns a list of event names supported by a given PMC class
+.Fa cl .
+On successful return, an array of
+.Vt "const char *"
+pointers to the names of valid events supported by class
+.Fa cl
+is allocated by the library using
+.Xr malloc 3 ,
+and a pointer to this array is returned in the location pointed to by
+.Fa eventnames .
+The number of pointers allocated is returned in the location pointed
+to by
+.Fa nevents .
+.Ss Administration
+Individual PMCs may be enabled or disabled on a given CPU using
+.Fn pmc_enable
+and
+.Fn pmc_disable
+respectively.
+For these functions,
+.Fa cpu
+is the CPU number, and
+.Fa pmc
+is the index of the PMC to be operated on.
+Only the super-user is allowed to enable and disable PMCs.
+.Ss x86 Architecture Specific API
+The
+.Fn pmc_get_msr
+function returns the processor model specific register number
+associated with
+.Fa pmc .
+Applications may use the x86
+.Ic RDPMC
+instruction to directly read the contents of the PMC.
+.Sh EVENT SPECIFIERS
+Event specifiers are strings comprising of an event name, followed by
+optional parameters modifying the semantics of the hardware event
+being probed.
+Event names are PMC architecture dependent, but the
+.Xr hwpmc 4
+library defines machine independent aliases for commonly used
+events.
+.Ss Event Name Aliases
+Event name aliases are CPU architecture independent names for commonly
+used events.
+The following aliases are known to this version of the
+.Nm pmc
+library:
+.Bl -tag -width indent
+.It Li branches
+Measure the number of branches retired.
+.It Li branch-mispredicts
+Measure the number of retired branches that were mispredicted.
+.It Li cycles
+Measure processor cycles.
+This event is implemented using the processor's Time Stamp Counter
+register.
+.It Li dc-misses
+Measure the number of data cache misses.
+.It Li ic-misses
+Measure the number of instruction cache misses.
+.It Li instructions
+Measure the number of instructions retired.
+.It Li interrupts
+Measure the number of interrupts seen.
+.It Li unhalted-cycles
+Measure the number of cycles the processor is not in a halted
+or sleep state.
+.El
+.Ss Time Stamp Counter (TSC)
+The timestamp counter is a monotonically non-decreasing counter that
+counts processor cycles.
+.Pp
+In the i386 architecture, this counter may
+be selected by requesting an event with event specifier
+.Dq Li tsc .
+The
+.Dq Li tsc
+event does not support any further qualifiers.
+It can only be allocated in system-wide counting mode,
+and is a read-only counter.
+Multiple processes are allowed to allocate the TSC.
+Once allocated, it may be read using the
+.Fn pmc_read
+function, or by using the RDTSC instruction.
+.Ss AMD (K7) PMCs
+These PMCs are present in the
+.Tn "AMD Athlon"
+series of CPUs and are documented in:
+.Rs
+.%B "AMD Athlon Processor x86 Code Optimization Guide"
+.%N "Publication No. 22007"
+.%D "February 2002"
+.%Q "Advanced Micro Devices, Inc."
+.Re
+.Pp
+Event specifiers for AMD K7 PMCs can have the following optional
+qualifiers:
+.Bl -tag -width indent
+.It Li count= Ns Ar value
+Configure the counter to increment only if the number of configured
+events measured in a cycle is greater than or equal to
+.Ar value .
+.It Li edge
+Configure the counter to only count negated-to-asserted transitions
+of the conditions expressed by the other qualifiers.
+In other words, the counter will increment only once whenever a given
+condition becomes true, irrespective of the number of clocks during
+which the condition remains true.
+.It Li inv
+Invert the sense of comparision when the
+.Dq Li count
+qualifier is present, making the counter to increment when the
+number of events per cycle is less than the value specified by
+the
+.Dq Li count
+qualifier.
+.It Li os
+Configure the PMC to count events happening at privilege level 0.
+.It Li unitmask= Ns Ar mask
+This qualifier is used to further qualify a select few events,
+.Dq Li k7-dc-refills-from-l2 ,
+.Dq Li k7-dc-refills-from-system
+and
+.Dq Li k7-dc-writebacks .
+Here
+.Ar mask
+is a string of the following characters optionally separated by
+.Ql +
+characters:
+.Pp
+.Bl -tag -width indent -compact
+.It Li m
+Count operations for lines in the
+.Dq Modified
+state.
+.It Li o
+Count operations for lines in the
+.Dq Owner
+state.
+.It Li e
+Count operations for lines in the
+.Dq Exclusive
+state.
+.It Li s
+Count operations for lines in the
+.Dq Shared
+state.
+.It Li i
+Count operations for lines in the
+.Dq Invalid
+state.
+.El
+.Pp
+If no
+.Dq Li unitmask
+qualifier is specified, the default is to count events for caches
+lines in any of the above states.
+.It Li usr
+Configure the PMC to count events occurring at privilege levels 1, 2
+or 3.
+.El
+.Pp
+If neither of the
+.Dq Li os
+or
+.Dq Li usr
+qualifiers were specified, the default is to enable both.
+.Pp
+The event specifiers supported on AMD K7 PMCs are:
+.Bl -tag -width indent
+.It Li k7-dc-accesses
+Count data cache accesses.
+.It Li k7-dc-misses
+Count data cache misses.
+.It Li k7-dc-refills-from-l2 Op Li ,unitmask= Ns Ar mask
+Count data cache refills from L2 cache.
+This event may be further qualified using the
+.Dq Li unitmask
+qualifier.
+.It Li k7-dc-refills-from-system Op Li ,unitmask= Ns Ar mask
+Count data cache refills from system memory.
+This event may be further qualified using the
+.Dq Li unitmask
+qualifier.
+.It Li k7-dc-writebacks Op Li ,unitmask= Ns Ar mask
+Count data cache writebacks.
+This event may be further qualified using the
+.Dq Li unitmask
+qualifier.
+.It Li k7-l1-dtlb-miss-and-l2-dtlb-hits
+Count L1 DTLB misses and L2 DTLB hits.
+.It Li k7-l1-and-l2-dtlb-misses
+Count L1 and L2 DTLB misses.
+.It Li k7-misaligned-references
+Count misaligned data references.
+.It Li k7-ic-fetches
+Count instruction cache fetches.
+.It Li k7-ic-misses
+Count instruction cache misses.
+.It Li k7-l1-itlb-misses
+Count L1 ITLB misses that are L2 ITLB hits.
+.It Li k7-l1-l2-itlb-misses
+Count L1 (and L2) ITLB misses.
+.It Li k7-retired-instructions
+Count all retired instructions.
+.It Li k7-retired-ops
+Count retired ops.
+.It Li k7-retired-branches
+Count all retired branches (conditional, unconditional, exceptions
+and interrupts).
+.It Li k7-retired-branches-mispredicted
+Count all misprediced retired branches.
+.It Li k7-retired-taken-branches
+Count retired taken branches.
+.It Li k7-retired-taken-branches-mispredicted
+Count mispredicted taken branches that were retired.
+.It Li k7-retired-far-control-transfers
+Count retired far control transfers.
+.It Li k7-retired-resync-branches
+Count retired resync branches (non control transfer branches).
+.It Li k7-interrupts-masked-cycles
+Count the number of cycles when the processor's
+.Va IF
+flag was zero.
+.It Li k7-interrupts-masked-while-pending-cycles
+Count the number of cycles interrupts were masked while pending due
+to the processor's
+.Va IF
+flag being zero.
+.It Li k7-hardware-interrupts
+Count the number of taken hardware interrupts.
+.El
+.Ss AMD (K8) PMCs
+These PMCs are present in the
+.Tn "AMD Athlon64"
+and
+.Tn "AMD Opteron"
+series of CPUs.
+They are documented in:
+.Rs
+.%B "BIOS and Kernel Developer's Guide for the AMD Athlon(tm) 64 and AMD Opteron Processors"
+.%N "Publication No. 26094"
+.%D "April 2004"
+.%Q "Advanced Micro Devices, Inc."
+.Re
+.Pp
+Event specifiers for AMD K8 PMCs can have the following optional
+qualifiers:
+.Bl -tag -width indent
+.It Li count= Ns Ar value
+Configure the counter to increment only if the number of configured
+events measured in a cycle is greater than or equal to
+.Ar value .
+.It Li edge
+Configure the counter to only count negated-to-asserted transitions
+of the conditions expressed by the other fields.
+In other words, the counter will increment only once whenever a given
+condition becomes true, irrespective of the number of clocks during
+which the condition remains true.
+.It Li inv
+Invert the sense of comparision when the
+.Dq Li count
+qualifier is present, making the counter to increment when the
+number of events per cycle is less than the value specified by
+the
+.Dq Li count
+qualifier.
+.It Li mask= Ns Ar qualifier
+Many event specifiers for AMD K8 PMCs need to be additionally
+qualified using a mask qualifier.
+These additional qualifiers are event-specific and are documented
+along with their associated event specifiers below.
+.It Li os
+Configure the PMC to count events happening at privilege level 0.
+.It Li usr
+Configure the PMC to count events occurring at privilege levels 1, 2
+or 3.
+.El
+.Pp
+If neither of the
+.Dq Li os
+or
+.Dq Li usr
+qualifiers were specified, the default is to enable both.
+.Pp
+The event specifiers supported on AMD K8 PMCs are:
+.Bl -tag -width indent
+.It Li k8-bu-cpu-clk-unhalted
+Count the number of clock cycles when the CPU is not in the HLT or
+STPCLK states.
+.It Li k8-bu-fill-request-l2-miss Op Li ,mask= Ns Ar qualifier
+Count fill requests that missed in the L2 cache.
+This event may be further qualified using
+.Ar qualifier ,
+which is a
+.Ql +
+separated set of the following keywords:
+.Pp
+.Bl -tag -width indent -compact
+.It Li dc-fill
+Count data cache fill requests.
+.It Li ic-fill
+Count instruction cache fill requests.
+.It Li tlb-reload
+Count TLB reloads.
+.El
+.Pp
+The default is to count all types of requests.
+.It Li k8-bu-internal-l2-request Op Li ,mask= Ns Ar qualifier
+Count internally generated requests to the L2 cache.
+This event may be further qualified using
+.Ar qualifier ,
+which is a
+.Ql +
+separated set of the following keywords:
+.Pp
+.Bl -tag -width indent -compact
+.It Li cancelled
+Count cancelled requests.
+.It Li dc-fill
+Count data cache fill requests.
+.It Li ic-fill
+Count instruction cache fill requests.
+.It Li tag-snoop
+Count tag snoop requests.
+.It Li tlb-reload
+Count TLB reloads.
+.El
+.Pp
+The default is to count all types of requests.
+.It Li k8-dc-access
+Count data cache accesses including microcode scratchpad accesses.
+.It Li k8-dc-copyback Op Li ,mask= Ns Ar qualifier
+Count data cache copyback operations.
+This event may be further qualified using
+.Ar qualifier ,
+which is a
+.Ql +
+separated set of the following keywords:
+.Pp
+.Bl -tag -width indent -compact
+.It Li exclusive
+Count operations for lines in the
+.Dq exclusive
+state.
+.It Li invalid
+Count operations for lines in the
+.Dq invalid
+state.
+.It Li modified
+Count operations for lines in the
+.Dq modified
+state.
+.It Li owner
+Count operations for lines in the
+.Dq owner
+state.
+.It Li shared
+Count operations for lines in the
+.Dq shared
+state.
+.El
+.Pp
+The default is to count operations for lines in all the
+above states.
+.It Li k8-dc-dcache-accesses-by-locks Op Li ,mask= Ns Ar qualifier
+Count data cache accesses by lock instructions.
+This event is only available on processors of revision C or later
+vintage.
+This event may be further qualified using
+.Ar qualifier ,
+which is a
+.Ql +
+separated set of the following keywords:
+.Pp
+.Bl -tag -width indent -compact
+.It Li accesses
+Count data cache accesses by lock instructions.
+.It Li misses
+Count data cache misses by lock instructions.
+.El
+.Pp
+The default is to count all accesses.
+.It Li k8-dc-dispatched-prefetch-instructions Op Li ,mask= Ns Ar qualifier
+Count the number of dispatched prefetch instructions.
+This event may be further qualified using
+.Ar qualifier ,
+which is a
+.Ql +
+separated set of the following keywords:
+.Pp
+.Bl -tag -width indent -compact
+.It Li load
+Count load operations.
+.It Li nta
+Count non-temporal operations.
+.It Li store
+Count store operations.
+.El
+.Pp
+The default is to count all operations.
+.It Li k8-dc-l1-dtlb-miss-and-l2-dtlb-hit
+Count L1 DTLB misses that are L2 DTLB hits.
+.It Li k8-dc-l1-dtlb-miss-and-l2-dtlb-miss
+Count L1 DTLB misses that are also misses in the L2 DTLB.
+.It Li k8-dc-microarchitectural-early-cancel-of-an-access
+Count microarchitectural early cancels of data cache accesses.
+.It Li k8-dc-microarchitectural-late-cancel-of-an-access
+Count microarchitectural late cancels of data cache accesses.
+.It Li k8-dc-misaligned-data-reference
+Count misaligned data references.
+.It Li k8-dc-miss
+Count data cache misses.
+.It Li k8-dc-one-bit-ecc-error Op Li ,mask= Ns Ar qualifier
+Count one bit ECC errors found by the scrubber.
+This event may be further qualified using
+.Ar qualifier ,
+which is a
+.Ql +
+separated set of the following keywords:
+.Pp
+.Bl -tag -width indent -compact
+.It Li scrubber
+Count scrubber detected errors.
+.It Li piggyback
+Count piggyback scrubber errors.
+.El
+.Pp
+The default is to count both kinds of errors.
+.It Li k8-dc-refill-from-l2 Op Li ,mask= Ns Ar qualifier
+Count data cache refills from L2 cache.
+This event may be further qualified using
+.Ar qualifier ,
+which is a
+.Ql +
+separated set of the following keywords:
+.Pp
+.Bl -tag -width indent -compact
+.It Li exclusive
+Count operations for lines in the
+.Dq exclusive
+state.
+.It Li invalid
+Count operations for lines in the
+.Dq invalid
+state.
+.It Li modified
+Count operations for lines in the
+.Dq modified
+state.
+.It Li owner
+Count operations for lines in the
+.Dq owner
+state.
+.It Li shared
+Count operations for lines in the
+.Dq shared
+state.
+.El
+.Pp
+The default is to count operations for lines in all the
+above states.
+.It Li k8-dc-refill-from-system Op Li ,mask= Ns Ar qualifier
+Count data cache refills from system memory.
+This event may be further qualified using
+.Ar qualifier ,
+which is a
+.Ql +
+separated set of the following keywords:
+.Pp
+.Bl -tag -width indent -compact
+.It Li exclusive
+Count operations for lines in the
+.Dq exclusive
+state.
+.It Li invalid
+Count operations for lines in the
+.Dq invalid
+state.
+.It Li modified
+Count operations for lines in the
+.Dq modified
+state.
+.It Li owner
+Count operations for lines in the
+.Dq owner
+state.
+.It Li shared
+Count operations for lines in the
+.Dq shared
+state.
+.El
+.Pp
+The default is to count operations for lines in all the
+above states.
+.It Li k8-fp-dispatched-fpu-ops Op Li ,mask= Ns Ar qualifier
+Count the number of dispatched FPU ops.
+This event is supported in revision B and later CPUs.
+This event may be further qualified using
+.Ar qualifier ,
+which is a
+.Ql +
+separated set of the following keywords:
+.Pp
+.Bl -tag -width indent -compact
+.It Li add-pipe-excluding-junk-ops
+Count add pipe ops excluding junk ops.
+.It Li add-pipe-junk-ops
+Count junk ops in the add pipe.
+.It Li multiply-pipe-excluding-junk-ops
+Count multiply pipe ops excluding junk ops.
+.It Li multiply-pipe-junk-ops
+Count junk ops in the multiply pipe.
+.It Li store-pipe-excluding-junk-ops
+Count store pipe ops excluding junk ops
+.It Li store-pipe-junk-ops
+Count junk ops in the store pipe.
+.El
+.Pp
+The default is to count all types of ops.
+.It Li k8-fp-cycles-with-no-fpu-ops-retired
+Count cycles when no FPU ops were retired.
+This event is supported in revision B and later CPUs.
+.It Li k8-fp-dispatched-fpu-fast-flag-ops
+Count dispatched FPU ops that use the fast flag interface.
+This event is supported in revision B and later CPUs.
+.It Li k8-fr-decoder-empty
+Count cycles when there was nothing to dispatch (i.e., the decoder
+was empty).
+.It Li k8-fr-dispatch-stalls
+Count all dispatch stalls.
+.It Li k8-fr-dispatch-stall-for-segment-load
+Count dispatch stalls for segment loads.
+.It Li k8-fr-dispatch-stall-for-serialization
+Count dispatch stalls for serialization.
+.It Li k8-fr-dispatch-stall-from-branch-abort-to-retire
+Count dispatch stalls from branch abort to retiral.
+.It Li k8-fr-dispatch-stall-when-fpu-is-full
+Count dispatch stalls when the FPU is full.
+.It Li k8-fr-dispatch-stall-when-ls-is-full
+Count dispatch stalls when the load/store unit is full.
+.It Li k8-fr-dispatch-stall-when-reorder-buffer-is-full
+Count dispatch stalls when the reorder buffer is full.
+.It Li k8-fr-dispatch-stall-when-reservation-stations-are-full
+Count dispatch stalls when reservation stations are full.
+.It Li k8-fr-dispatch-stall-when-waiting-for-all-to-be-quiet
+Count dispatch stalls when waiting for all to be quiet.
+.\" XXX What does "waiting for all to be quiet" mean?
+.It Li k8-fr-dispatch-stall-when-waiting-far-xfer-or-resync-branch-pending
+Count dispatch stalls when a far control transfer or a resync branch
+is pending.
+.It Li k8-fr-fpu-exceptions Op Li ,mask= Ns Ar qualifier
+Count FPU exceptions.
+This event is supported in revision B and later CPUs.
+This event may be further qualified using
+.Ar qualifier ,
+which is a
+.Ql +
+separated set of the following keywords:
+.Pp
+.Bl -tag -width indent -compact
+.It Li sse-and-x87-microtraps
+Count SSE and x87 microtraps.
+.It Li sse-reclass-microfaults
+Count SSE reclass microfaults
+.It Li sse-retype-microfaults
+Count SSE retype microfaults
+.It Li x87-reclass-microfaults
+Count x87 reclass microfaults.
+.El
+.Pp
+The default is to count all types of exceptions.
+.It Li k8-fr-interrupts-masked-cycles
+Count cycles when interrupts were masked (by CPU RFLAGS field IF was zero).
+.It Li k8-fr-interrupts-masked-while-pending-cycles
+Count cycles while interrupts were masked while pending (i.e., cycles
+when INTR was asserted while CPU RFLAGS field IF was zero).
+.It Li k8-fr-number-of-breakpoints-for-dr0
+Count the number of breakpoints for DR0.
+.It Li k8-fr-number-of-breakpoints-for-dr1
+Count the number of breakpoints for DR1.
+.It Li k8-fr-number-of-breakpoints-for-dr2
+Count the number of breakpoints for DR2.
+.It Li k8-fr-number-of-breakpoints-for-dr3
+Count the number of breakpoints for DR3.
+.It Li k8-fr-retired-branches
+Count retired branches including exceptions and interrupts.
+.It Li k8-fr-retired-branches-mispredicted
+Count mispredicted retired branches.
+.It Li k8-fr-retired-far-control-transfers
+Count retired far control transfers (which are always mispredicted).
+.It Li k8-fr-retired-fastpath-double-op-instructions Op Li ,mask= Ns Ar qualifier
+Count retired fastpath double op instructions.
+This event is supported in revision B and later CPUs.
+This event may be further qualified using
+.Ar qualifier ,
+which is a
+.Ql +
+separated set of the following keywords:
+.Pp
+.Bl -tag -width indent -compact
+.It Li low-op-pos-0
+Count instructions with the low op in position 0.
+.It Li low-op-pos-1
+Count instructions with the low op in position 1.
+.It Li low-op-pos-2
+Count instructions with the low op in position 2.
+.El
+.Pp
+The default is to count all types of instructions.
+.It Li k8-fr-retired-fpu-instructions Op Li ,mask= Ns Ar qualifier
+Count retired FPU instructions.
+This event is supported in revision B and later CPUs.
+This event may be further qualified using
+.Ar qualifier ,
+which is a
+.Ql +
+separated set of the following keywords:
+.Pp
+.Bl -tag -width indent -compact
+.It Li mmx-3dnow
+Count MMX and 3DNow!\& instructions.
+.It Li packed-sse-sse2
+Count packed SSE and SSE2 instructions.
+.It Li scalar-sse-sse2
+Count scalar SSE and SSE2 instructions
+.It Li x87
+Count x87 instructions.
+.El
+.Pp
+The default is to count all types of instructions.
+.It Li k8-fr-retired-near-returns
+Count retired near returns.
+.It Li k8-fr-retired-near-returns-mispredicted
+Count mispredicted near returns.
+.It Li k8-fr-retired-resyncs
+Count retired resyncs (non-control transfer branches).
+.It Li k8-fr-retired-taken-hardware-interrupts
+Count retired taken hardware interrupts.
+.It Li k8-fr-retired-taken-branches
+Count retired taken branches.
+.It Li k8-fr-retired-taken-branches-mispredicted
+Count retired taken branches that were mispredicted.
+.It Li k8-fr-retired-taken-branches-mispredicted-by-addr-miscompare
+Count retired taken branches that were mispredicted only due to an
+address miscompare.
+.It Li k8-fr-retired-uops
+Count retired uops.
+.It Li k8-fr-retired-x86-instructions
+Count retired x86 instructions including exceptions and interrupts.
+.It Li k8-ic-fetch
+Count instruction cache fetches.
+.It Li k8-ic-instruction-fetch-stall
+Count cycles in stalls due to instruction fetch.
+.It Li k8-ic-l1-itlb-miss-and-l2-itlb-hit
+Count L1 ITLB misses that are L2 ITLB hits.
+.It Li k8-ic-l1-itlb-miss-and-l2-itlb-miss
+Count ITLB misses that miss in both L1 and L2 ITLBs.
+.It Li k8-ic-microarchitectural-resync-by-snoop
+Count microarchitectural resyncs caused by snoops.
+.It Li k8-ic-miss
+Count instruction cache misses.
+.It Li k8-ic-refill-from-l2
+Count instruction cache refills from L2 cache.
+.It Li k8-ic-refill-from-system
+Count instruction cache refills from system memory.
+.It Li k8-ic-return-stack-hits
+Count hits to the return stack.
+.It Li k8-ic-return-stack-overflow
+Count overflows of the return stack.
+.It Li k8-ls-buffer2-full
+Count load/store buffer2 full events.
+.It Li k8-ls-locked-operation Op Li ,mask= Ns Ar qualifier
+Count locked operations.
+For revision C and later CPUs, the following qualifiers are supported:
+.Pp
+.Bl -tag -width indent -compact
+.It Li cycles-in-request
+Count the number of cycles in the lock request/grant stage.
+.It Li cycles-to-complete
+Count the number of cycles a lock takes to complete once it is
+non-speculative and is the older load/store operation.
+.It Li locked-instructions
+Count the number of lock instructions executed.
+.El
+.Pp
+The default is to count the number of lock instructions executed.
+.It Li k8-ls-microarchitectural-late-cancel
+Count microarchitectural late cancels of operations in the load/store
+unit.
+.It Li k8-ls-microarchitectural-resync-by-self-modifying-code
+Count microarchitectural resyncs caused by self-modifying code.
+.It Li k8-ls-microarchitectural-resync-by-snoop
+Count microarchitectural resyncs caused by snoops.
+.It Li k8-ls-retired-cflush-instructions
+Count retired CFLUSH instructions.
+.It Li k8-ls-retired-cpuid-instructions
+Count retired CPUID instructions.
+.It Li k8-ls-segment-register-load Op Li ,mask= Ns Ar qualifier
+Count segment register loads.
+This event may be further qualified using
+.Ar qualifier ,
+which is a
+.Ql +
+separated set of the following keywords:
+.Bl -tag -width indent -compact
+.It Li cs
+Count CS register loads.
+.It Li ds
+Count DS register loads.
+.It Li es
+Count ES register loads.
+.It Li fs
+Count FS register loads.
+.It Li gs
+Count GS register loads.
+.\" .It Li hs
+.\" Count HS register loads.
+.\" XXX "HS" register?
+.It Li ss
+Count SS register loads.
+.El
+.Pp
+The default is to count all types of loads.
+.It Li k8-nb-memory-controller-bypass-saturation Op Li ,mask= Ns Ar qualifier
+Count memory controller bypass counter saturation events.
+This event may be further qualified using
+.Ar qualifier ,
+which is a
+.Ql +
+separated set of the following keywords:
+.Pp
+.Bl -tag -width indent -compact
+.It Li dram-controller-interface-bypass
+Count DRAM controller interface bypass.
+.It Li dram-controller-queue-bypass
+Count DRAM controller queue bypass.
+.It Li memory-controller-hi-pri-bypass
+Count memory controller high priority bypasses.
+.It Li memory-controller-lo-pri-bypass
+Count memory controller low priority bypasses.
+.El
+.Pp
+.It Li k8-nb-memory-controller-dram-slots-missed
+Count memory controller DRAM command slots missed (in MemClks).
+.It Li k8-nb-memory-controller-page-access-event Op Li ,mask= Ns Ar qualifier
+Count memory controller page access events.
+This event may be further qualified using
+.Ar qualifier ,
+which is a
+.Ql +
+separated set of the following keywords:
+.Pp
+.Bl -tag -width indent -compact
+.It Li page-conflict
+Count page conflicts.
+.It Li page-hit
+Count page hits.
+.It Li page-miss
+Count page misses.
+.El
+.Pp
+The default is to count all types of events.
+.It Li k8-nb-memory-controller-page-table-overflow
+Count memory control page table overflow events.
+.It Li k8-nb-probe-result Op Li ,mask= Ns Ar qualifier
+Count probe events.
+This event may be further qualified using
+.Ar qualifier ,
+which is a
+.Ql +
+separated set of the following keywords:
+.Pp
+.Bl -tag -width indent -compact
+.It Li probe-hit
+Count all probe hits.
+.It Li probe-hit-dirty-no-memory-cancel
+Count probe hits without memory cancels.
+.It Li probe-hit-dirty-with-memory-cancel
+Count probe hits with memory cancels.
+.It Li probe-miss
+Count probe misses.
+.El
+.It Li k8-nb-sized-commands Op Li ,mask= Ns Ar qualifier
+Count sized commands issued.
+This event may be further qualified using
+.Ar qualifier ,
+which is a
+.Ql +
+separated set of the following keywords:
+.Pp
+.Bl -tag -width indent -compact
+.It Li nonpostwrszbyte
+.It Li nonpostwrszdword
+.It Li postwrszbyte
+.It Li postwrszdword
+.It Li rdszbyte
+.It Li rdszdword
+.It Li rdmodwr
+.El
+.Pp
+The default is to count all types of commands.
+.It Li k8-nb-memory-controller-turnaround Op Li ,mask= Ns Ar qualifier
+Count memory control turnaround events.
+This event may be further qualified using
+.Ar qualifier ,
+which is a
+.Ql +
+separated set of the following keywords:
+.Pp
+.Bl -tag -width indent -compact
+.\" XXX doc is unclear whether these are cycle counts or event counts
+.It Li dimm-turnaround
+Count DIMM turnarounds.
+.It Li read-to-write-turnaround
+Count read to write turnarounds.
+.It Li write-to-read-turnaround
+Count write to read turnarounds.
+.El
+.Pp
+The default is to count all types of events.
+.It Li k8-nb-ht-bus0-bandwidth Op Li ,mask= Ns Ar qualifier
+.It Li k8-nb-ht-bus1-bandwidth Op Li ,mask= Ns Ar qualifier
+.It Li k8-nb-ht-bus2-bandwidth Op Li ,mask= Ns Ar qualifier
+Count events on the HyperTransport(tm) buses.
+These events may be further qualified using
+.Ar qualifier ,
+which is a
+.Ql +
+separated set of the following keywords:
+.Pp
+.Bl -tag -width indent -compact
+.It Li buffer-release
+Count buffer release messages sent.
+.It Li command
+Count command messages sent.
+.It Li data
+Count data messages sent.
+.It Li nop
+Count nop messages sent.
+.El
+.Pp
+The default is to count all types of messages.
+.El
+.Ss Intel P6 PMCS
+Intel P6 PMCs are present in Intel
+.Tn "Pentium Pro" ,
+.Tn "Pentium II" ,
+.Tn Celeron ,
+.Tn "Pentium III"
+and
+.Tn "Pentium M"
+processors.
+.Pp
+These CPUs have two counters.
+Some events may only be used on specific counters and some events are
+defined only on specific processor models.
+.Pp
+These PMCs are documented in
+.Rs
+.%B "IA-32 Intel(R) Architecture Software Developer's Manual"
+.%T "Volume 3: System Programming Guide"
+.%N "Order Number 245472-012"
+.%D 2003
+.%Q "Intel Corporation"
+.Re
+.Pp
+Some of these events are affected by processor errata described in
+.Rs
+.%B "Intel(R) Pentium(R) III Processor Specification Update"
+.%N "Document Number: 244453-054"
+.%D "April 2005"
+.%Q "Intel Corporation"
+.Re
+.Pp
+Event specifiers for Intel P6 PMCs can have the following common
+qualifiers:
+.Bl -tag -width indent
+.It Li cmask= Ns Ar value
+Configure the PMC to increment only if the number of configured
+events measured in a cycle is greater than or equal to
+.Ar value .
+.It Li edge
+Configure the PMC to count the number of deasserted to asserted
+transitions of the conditions expressed by the other qualifiers.
+If specified, the counter will increment only once whenever a
+condition becomes true, irrespective of the number of clocks during
+which the condition remains true.
+.It Li inv
+Invert the sense of comparision when the
+.Dq Li cmask
+qualifier is present, making the counter increment when the number of
+events per cycle is less than the value specified by the
+.Dq Li cmask
+qualifier.
+.It Li os
+Configure the PMC to count events happening at processor privilege
+level 0.
+.It Li umask= Ns Ar value
+This qualifier is used to further qualify the event selected (see
+below).
+.It Li usr
+Configure the PMC to count events occurring at privilege levels 1, 2
+or 3.
+.El
+.Pp
+If neither of the
+.Dq Li os
+or
+.Dq Li usr
+qualifiers are specified, the default is to enable both.
+.Pp
+The event specifiers supported by Intel P6 PMCs are:
+.Bl -tag -width indent
+.It Li p6-baclears
+Count the number of times a static branch prediction was made by the
+branch decoder because the BTB did not have a prediction.
+.It Li p6-br-bac-missp-exec
+.Pq Tn "Pentium M"
+Count the number of branch instructions executed that where
+mispredicted at the Front End (BAC).
+.It Li p6-br-bogus
+Count the number of bogus branches.
+.It Li p6-br-call-exec
+.Pq Tn "Pentium M"
+Count the number of call instructions executed.
+.It Li p6-br-call-missp-exec
+.Pq Tn "Pentium M"
+Count the number of call instructions executed that were mispredicted.
+.It Li p6-br-cnd-exec
+.Pq Tn "Pentium M"
+Count the number of conditional branch instructions executed.
+.It Li p6-br-cnd-missp-exec
+.Pq Tn "Pentium M"
+Count the number of conditional branch instructions executed that were
+mispredicted.
+.It Li p6-br-ind-call-exec
+.Pq Tn "Pentium M"
+Count the number of indirect call instructions executed.
+.It Li p6-br-ind-exec
+.Pq Tn "Pentium M"
+Count the number of indirect branch instructions executed.
+.It Li p6-br-ind-missp-exec
+.Pq Tn "Pentium M"
+Count the number of indirect branch instructions executed that were
+mispredicted.
+.It Li p6-br-inst-decoded
+Count the number of branch instructions decoded.
+.It Li p6-br-inst-exec
+.Pq Tn "Pentium M"
+Count the number of branch instructions executed but necessarily retired.
+.It Li p6-br-inst-retired
+Count the number of branch instructions retired.
+.It Li p6-br-miss-pred-retired
+Count the number of mispredicted branch instructions retired.
+.It Li p6-br-miss-pred-taken-ret
+Count the number of taken mispredicted branches retired.
+.It Li p6-br-missp-exec
+.Pq Tn "Pentium M"
+Count the number of branch instructions executed that were
+mispredicted at execution.
+.It Li p6-br-ret-bac-missp-exec
+.Pq Tn "Pentium M"
+Count the number of return instructions executed that were
+mispredicted at the Front End (BAC).
+.It Li p6-br-ret-exec
+.Pq Tn "Pentium M"
+Count the number of return instructions executed.
+.It Li p6-br-ret-missp-exec
+.Pq Tn "Pentium M"
+Count the number of return instructions executed that were
+mispredicted at execution.
+.It Li p6-br-taken-retired
+Count the number of taken branches retired.
+.It Li p6-btb-misses
+Count the number of branches for which the BTB did not produce a
+prediction.
+.It Li p6-bus-bnr-drv
+Count the number of bus clock cycles during which this processor is
+driving the BNR# pin.
+.It Li p6-bus-data-rcv
+Count the number of bus clock cycles during which this processor is
+receiving data.
+.It Li p6-bus-drdy-clocks Op Li ,umask= Ns Ar qualifier
+Count the number of clocks during which DRDY# is asserted.
+An additional qualifier may be specified, and comprises one of the
+following keywords:
+.Pp
+.Bl -tag -width indent -compact
+.It Li any
+Count transactions generated by any agent on the bus.
+.It Li self
+Count transactions generated by this processor.
+.El
+.Pp
+The default is to count operations generated by this processor.
+.It Li p6-bus-hit-drv
+Count the number of bus clock cycles during which this processor is
+driving the HIT# pin.
+.It Li p6-bus-hitm-drv
+Count the number of bus clock cycles during which this processor is
+driving the HITM# pin.
+.It Li p6-bus-lock-clocks Op Li ,umask= Ns Ar qualifier
+Count the number of clocks during with LOCK# is asserted on the
+external system bus.
+An additional qualifier may be specified and comprises one of the following
+keywords:
+.Pp
+.Bl -tag -width indent -compact
+.It Li any
+Count transactions generated by any agent on the bus.
+.It Li self
+Count transactions generated by this processor.
+.El
+.Pp
+The default is to count operations generated by this processor.
+.It Li p6-bus-req-outstanding
+Count the number of bus requests outstanding in any given cycle.
+.It Li p6-bus-snoop-stall
+Count the number of clock cycles during which the bus is snoop stalled.
+.It Li p6-bus-tran-any Op Li ,umask= Ns Ar qualifier
+Count the number of completed bus transactions of any kind.
+An additional qualifier may be specified and comprises one of the following
+keywords:
+.Pp
+.Bl -tag -width indent -compact
+.It Li any
+Count transactions generated by any agent on the bus.
+.It Li self
+Count transactions generated by this processor.
+.El
+.Pp
+The default is to count operations generated by this processor.
+.It Li p6-bus-tran-brd Op Li ,umask= Ns Ar qualifier
+Count the number of burst read transactions.
+An additional qualifier may be specified and comprises one of the following
+keywords:
+.Pp
+.Bl -tag -width indent -compact
+.It Li any
+Count transactions generated by any agent on the bus.
+.It Li self
+Count transactions generated by this processor.
+.El
+.Pp
+The default is to count operations generated by this processor.
+.It Li p6-bus-tran-burst Op Li ,umask= Ns Ar qualifier
+Count the number of completed burst transactions.
+An additional qualifier may be specified and comprises one of the following
+keywords:
+.Pp
+.Bl -tag -width indent -compact
+.It Li any
+Count transactions generated by any agent on the bus.
+.It Li self
+Count transactions generated by this processor.
+.El
+.Pp
+The default is to count operations generated by this processor.
+.It Li p6-bus-tran-def Op Li ,umask= Ns Ar qualifier
+Count the number of completed deferred transactions.
+An additional qualifier may be specified and comprises one of the following
+keywords:
+.Pp
+.Bl -tag -width indent -compact
+.It Li any
+Count transactions generated by any agent on the bus.
+.It Li self
+Count transactions generated by this processor.
+.El
+.Pp
+The default is to count operations generated by this processor.
+.It Li p6-bus-tran-ifetch Op Li ,umask= Ns Ar qualifier
+Count the number of completed instruction fetch transactions.
+An additional qualifier may be specified and comprises one of the following
+keywords:
+.Pp
+.Bl -tag -width indent -compact
+.It Li any
+Count transactions generated by any agent on the bus.
+.It Li self
+Count transactions generated by this processor.
+.El
+.Pp
+The default is to count operations generated by this processor.
+.It Li p6-bus-tran-inval Op Li ,umask= Ns Ar qualifier
+Count the number of completed invalidate transactions.
+An additional qualifier may be specified and comprises one of the following
+keywords:
+.Pp
+.Bl -tag -width indent -compact
+.It Li any
+Count transactions generated by any agent on the bus.
+.It Li self
+Count transactions generated by this processor.
+.El
+.Pp
+The default is to count operations generated by this processor.
+.It Li p6-bus-tran-mem Op Li ,umask= Ns Ar qualifier
+Count the number of completed memory transactions.
+An additional qualifier may be specified and comprises one of the following
+keywords:
+.Pp
+.Bl -tag -width indent -compact
+.It Li any
+Count transactions generated by any agent on the bus.
+.It Li self
+Count transactions generated by this processor.
+.El
+.Pp
+The default is to count operations generated by this processor.
+.It Li p6-bus-tran-pwr Op Li ,umask= Ns Ar qualifier
+Count the number of completed partial write transactions.
+An additional qualifier may be specified and comprises one of the following
+keywords:
+.Pp
+.Bl -tag -width indent -compact
+.It Li any
+Count transactions generated by any agent on the bus.
+.It Li self
+Count transactions generated by this processor.
+.El
+.Pp
+The default is to count operations generated by this processor.
+.It Li p6-bus-tran-rfo Op Li ,umask= Ns Ar qualifier
+Count the number of completed read-for-ownership transactions.
+An additional qualifier may be specified and comprises one of the following
+keywords:
+.Pp
+.Bl -tag -width indent -compact
+.It Li any
+Count transactions generated by any agent on the bus.
+.It Li self
+Count transactions generated by this processor.
+.El
+.Pp
+The default is to count operations generated by this processor.
+.It Li p6-bus-trans-io Op Li ,umask= Ns Ar qualifier
+Count the number of completed I/O transactions.
+An additional qualifier may be specified and comprises one of the following
+keywords:
+.Pp
+.Bl -tag -width indent -compact
+.It Li any
+Count transactions generated by any agent on the bus.
+.It Li self
+Count transactions generated by this processor.
+.El
+.Pp
+The default is to count operations generated by this processor.
+.It Li p6-bus-trans-p Op Li ,umask= Ns Ar qualifier
+Count the number of completed partial transactions.
+An additional qualifier may be specified and comprises one of the following
+keywords:
+.Pp
+.Bl -tag -width indent -compact
+.It Li any
+Count transactions generated by any agent on the bus.
+.It Li self
+Count transactions generated by this processor.
+.El
+.Pp
+The default is to count operations generated by this processor.
+.It Li p6-bus-trans-wb Op Li ,umask= Ns Ar qualifier
+Count the number of completed write-back transactions.
+An additional qualifier may be specified and comprises one of the following
+keywords:
+.Pp
+.Bl -tag -width indent -compact
+.It Li any
+Count transactions generated by any agent on the bus.
+.It Li self
+Count transactions generated by this processor.
+.El
+.Pp
+The default is to count operations generated by this processor.
+.It Li p6-cpu-clk-unhalted
+Count the number of cycles during with the processor was not halted.
+.Pp
+.Pq Tn "Pentium M"
+Count the number of cycles during with the processor was not halted
+and not in a thermal trip.
+.It Li p6-cycles-div-busy
+Count the number of cycles during which the divider is busy and cannot
+accept new divides.
+This event is only allocated on counter 0.
+.It Li p6-cycles-in-pending-and-masked
+Count the number of processor cycles for which interrupts were
+disabled and interrupts were pending.
+.It Li p6-cycles-int-masked
+Count the number of processor cycles for which interrupts were
+disabled.
+.It Li p6-data-mem-refs
+Count all loads and all stores using any memory type, including
+internal retries.
+Each part of a split store is counted separately.
+.It Li p6-dcu-lines-in
+Count the total lines allocated in the data cache unit.
+.It Li p6-dcu-m-lines-in
+Count the number of M state lines allocated in the data cache unit.
+.It Li p6-dcu-m-lines-out
+Count the number of M state lines evicted from the data cache unit.
+.It Li p6-dcu-miss-outstanding
+Count the weighted number of cycles while a data cache unit miss is
+outstanding, incremented by the number of outstanding cache misses at
+any time.
+.It Li p6-div
+Count the number of floating point multiplies.
+This event is only allocated on counter 1.
+.It Li p6-emon-esp-uops
+.Pq Tn "Pentium M"
+Count the total number of micro-ops.
+.It Li p6-emon-est-trans Op Li ,umask= Ns Ar qualifier
+.Pq Tn "Pentium M"
+Count the number of
+.Tn "Enhanced Intel SpeedStep"
+transitions.
+An additional qualifier may be specified, and can be one of the
+following keywords:
+.Pp
+.Bl -tag -width indent -compact
+.It Li all
+Count all transitions.
+.It Li freq
+Count only frequency transitions.
+.El
+.Pp
+The default is to count all transitions.
+.It Li p6-emon-fused-uops-ret Op Li ,umask= Ns Ar qualifier
+.Pq Tn "Pentium M"
+Count the number of retired fused micro-ops.
+An additional qualifier may be specified, and may be one of the
+following keywords:
+.Pp
+.Bl -tag -width indent -compact
+.It Li all
+Count all fused micro-ops.
+.It Li loadop
+Count only load and op micro-ops.
+.It Li stdsta
+Count only STD/STA micro-ops.
+.El
+.Pp
+The default is to count all fused micro-ops.
+.It Li p6-emon-kni-comp-inst-ret
+.Pq Tn "Pentium III"
+Count the number of SSE computational instructions retired.
+An additional qualifier may be specified, and comprises one of the
+following keywords:
+.Pp
+.Bl -tag -width indent -compact
+.It Li packed-and-scalar
+Count packed and scalar operations.
+.It Li scalar
+Count scalar operations only.
+.El
+.Pp
+The default is to count packed and scalar operations.
+.It Li p6-emon-kni-inst-retired Op Li ,umask= Ns Ar qualifier
+.Pq Tn "Pentium III"
+Count the number of SSE instructions retired.
+An additional qualifier may be specified, and comprises one of the
+following keywords:
+.Pp
+.Bl -tag -width indent -compact
+.It Li packed-and-scalar
+Count packed and scalar operations.
+.It Li scalar
+Count scalar operations only.
+.El
+.Pp
+The default is to count packed and scalar operations.
+.It Li p6-emon-kni-pref-dispatched Op Li ,umask= Ns Ar qualifier
+.Pq Tn "Pentium III"
+Count the number of SSE prefetch or weakly ordered instructions
+dispatched (including speculative prefetches).
+An additional qualifier may be specified, and comprises one of the
+following keywords:
+.Pp
+.Bl -tag -width indent -compact
+.It Li nta
+Count non-temporal prefetches.
+.It Li t1
+Count prefetches to L1.
+.It Li t2
+Count prefetches to L2.
+.It Li wos
+Count weakly ordered stores.
+.El
+.Pp
+The default is to count non-temporal prefetches.
+.It Li p6-emon-kni-pref-miss Op Li ,umask= Ns Ar qualifier
+.Pq Tn "Pentium III"
+Count the number of prefetch or weakly ordered instructions that miss
+all caches.
+An additional qualifier may be specified, and comprises one of the
+following keywords:
+.Pp
+.Bl -tag -width indent -compact
+.It Li nta
+Count non-temporal prefetches.
+.It Li t1
+Count prefetches to L1.
+.It Li t2
+Count prefetches to L2.
+.It Li wos
+Count weakly ordered stores.
+.El
+.Pp
+The default is to count non-temporal prefetches.
+.It Li p6-emon-pref-rqsts-dn
+.Pq Tn "Pentium M"
+Count the number of downward prefetches issued.
+.It Li p6-emon-pref-rqsts-up
+.Pq Tn "Pentium M"
+Count the number of upward prefetches issued.
+.It Li p6-emon-simd-instr-retired
+.Pq Tn "Pentium M"
+Count the number of retired
+.Tn MMX
+instructions.
+.It Li p6-emon-sse-sse2-comp-inst-retired Op Li ,umask= Ns Ar qualifier
+.Pq Tn "Pentium M"
+Count the number of computational SSE instructions retired.
+An additional qualifier may be specified and can be one of the
+following keywords:
+.Pp
+.Bl -tag -width indent -compact
+.It Li sse-packed-single
+Count SSE packed-single instructions.
+.It Li sse-scalar-single
+Count SSE scalar-single instructions.
+.It Li sse2-packed-double
+Count SSE2 packed-double instructions.
+.It Li sse2-scalar-double
+Count SSE2 scalar-double instructions.
+.El
+.Pp
+The default is to count SSE packed-single instructions.
+.It Li p6-emon-sse-sse2-inst-retired Op Li ,umask= Ns Ar qualifer
+.Pp
+.Pq Tn "Pentium M"
+Count the number of SSE instructions retired.
+An additional qualifier can be specified, and can be one of the
+following keywords:
+.Pp
+.Bl -tag -width indent -compact
+.It Li sse-packed-single
+Count SSE packed-single instructions.
+.It Li sse-packed-single-scalar-single
+Count SSE packed-single and scalar-single instructions.
+.It Li sse2-packed-double
+Count SSE2 packed-double instructions.
+.It Li sse2-scalar-double
+Count SSE2 scalar-double instructions.
+.El
+.Pp
+The default is to count SSE packed-single instructions.
+.It Li p6-emon-synch-uops
+.Pq Tn "Pentium M"
+Count the number of sync micro-ops.
+.It Li p6-emon-thermal-trip
+.Pq Tn "Pentium M"
+Count the duration or occurrences of thermal trips.
+Use the
+.Dq Li edge
+qualifier to count occurrences of thermal trips.
+.It Li p6-emon-unfusion
+.Pq Tn "Pentium M"
+Count the number of unfusion events in the reorder buffer.
+.It Li p6-flops
+Count the number of computational floating point operations retired.
+This event is only allocated on counter 0.
+.It Li p6-fp-assist
+Count the number of floating point exceptions handled by microcode.
+This event is only allocated on counter 1.
+.It Li p6-fp-comps-ops-exe
+Count the number of computation floating point operations executed.
+This event is only allocated on counter 0.
+.It Li p6-fp-mmx-trans Op Li ,umask= Ns Ar qualifier
+.Pq Tn "Pentium II" , Tn "Pentium III"
+Count the number of transitions between MMX and floating-point
+instructions.
+An additional qualifier may be specified, and comprises one of the
+following keywords:
+.Pp
+.Bl -tag -width indent -compact
+.It Li mmxtofp
+Count transitions from MMX instructions to floating-point instructions.
+.It Li fptommx
+Count transitions from floating-point instructions to MMX instructions.
+.El
+.Pp
+The default is to count MMX to floating-point transitions.
+.It Li p6-hw-int-rx
+Count the number of hardware interrupts received.
+.It Li p6-ifu-fetch
+Count the number of instruction fetches, both cacheable and non-cacheable.
+.It Li p6-ifu-fetch-miss
+Count the number of instruction fetch misses (i.e., those that produce
+memory accesses).
+.It Li p6-ifu-mem-stall
+Count the number of cycles instruction fetch is stalled for any reason.
+.It Li p6-ild-stall
+Count the number of cycles the instruction length decoder is stalled.
+.It Li p6-inst-decoded
+Count the number of instructions decoded.
+.It Li p6-inst-retired
+Count the number of instructions retired.
+.It Li p6-itlb-miss
+Count the number of instruction TLB misses.
+.It Li p6-l2-ads
+Count the number of L2 address strobes.
+.It Li p6-l2-dbus-busy
+Count the number of cycles during which the L2 cache data bus was busy.
+.It Li p6-l2-dbus-busy-rd
+Count the number of cycles during which the L2 cache data bus was busy
+transferring read data from L2 to the processor.
+.It Li p6-l2-ifetch Op Li ,umask= Ns Ar qualifier
+Count the number of L2 instruction fetches.
+An additional qualifier may be specified and comprises a list of the following
+keywords separated by
+.Ql +
+characters:
+.Pp
+.Bl -tag -width indent -compact
+.It Li e
+Count operations affecting E (exclusive) state lines.
+.It Li i
+Count operations affecting I (invalid) state lines.
+.It Li m
+Count operations affecting M (modified) state lines.
+.It Li s
+Count operations affecting S (shared) state lines.
+.El
+.Pp
+The default is to count operations affecting all (MESI) state lines.
+.It Li p6-l2-ld Op Li ,umask= Ns Ar qualifier
+Count the number of L2 data loads.
+An additional qualifier may be specified and comprises a list of the following
+keywords separated by
+.Ql +
+characters:
+.Pp
+.Bl -tag -width indent -compact
+.It Li both
+.Pq Tn "Pentium M"
+Count both hardware-prefetched lines and non-hardware-prefetched lines.
+.It Li e
+Count operations affecting E (exclusive) state lines.
+.It Li hw
+.Pq Tn "Pentium M"
+Count hardware-prefetched lines only.
+.It Li i
+Count operations affecting I (invalid) state lines.
+.It Li m
+Count operations affecting M (modified) state lines.
+.It Li nonhw
+.Pq Tn "Pentium M"
+Exclude hardware-prefetched lines.
+.It Li s
+Count operations affecting S (shared) state lines.
+.El
+.Pp
+The default on processors other than
+.Tn "Pentium M"
+processors is to count operations affecting all (MESI) state lines.
+The default on
+.Tn "Pentium M"
+processors is to count both hardware-prefetched and
+non-hardware-prefetch operations on all (MESI) state lines.
+.Pq Errata
+This event is affected by processor errata E53.
+.It Li p6-l2-lines-in Op Li ,umask= Ns Ar qualifier
+Count the number of L2 lines allocated.
+An additional qualifier may be specified and comprises a list of the following
+keywords separated by
+.Ql +
+characters:
+.Pp
+.Bl -tag -width indent -compact
+.It Li both
+.Pq Tn "Pentium M"
+Count both hardware-prefetched lines and non-hardware-prefetched lines.
+.It Li e
+Count operations affecting E (exclusive) state lines.
+.It Li hw
+.Pq Tn "Pentium M"
+Count hardware-prefetched lines only.
+.It Li i
+Count operations affecting I (invalid) state lines.
+.It Li m
+Count operations affecting M (modified) state lines.
+.It Li nonhw
+.Pq Tn "Pentium M"
+Exclude hardware-prefetched lines.
+.It Li s
+Count operations affecting S (shared) state lines.
+.El
+.Pp
+The default on processors other than
+.Tn "Pentium M"
+processors is to count operations affecting all (MESI) state lines.
+The default on
+.Tn "Pentium M"
+processors is to count both hardware-prefetched and
+non-hardware-prefetch operations on all (MESI) state lines.
+.Pq Errata
+This event is affected by processor errata E45.
+.It Li p6-l2-lines-out Op Li ,umask= Ns Ar qualifier
+Count the number of L2 lines evicted.
+An additional qualifier may be specified and comprises a list of the following
+keywords separated by
+.Ql +
+characters:
+.Pp
+.Bl -tag -width indent -compact
+.It Li both
+.Pq Tn "Pentium M"
+Count both hardware-prefetched lines and non-hardware-prefetched lines.
+.It Li e
+Count operations affecting E (exclusive) state lines.
+.It Li hw
+.Pq Tn "Pentium M"
+Count hardware-prefetched lines only.
+.It Li i
+Count operations affecting I (invalid) state lines.
+.It Li m
+Count operations affecting M (modified) state lines.
+.It Li nonhw
+.Pq Tn "Pentium M" only
+Exclude hardware-prefetched lines.
+.It Li s
+Count operations affecting S (shared) state lines.
+.El
+.Pp
+The default on processors other than
+.Tn "Pentium M"
+processors is to count operations affecting all (MESI) state lines.
+The default on
+.Tn "Pentium M"
+processors is to count both hardware-prefetched and
+non-hardware-prefetch operations on all (MESI) state lines.
+.Pq Errata
+This event is affected by processor errata E45.
+.It Li p6-l2-m-lines-inm
+Count the number of modified lines allocated in L2 cache.
+.It Li p6-l2-m-lines-outm Op Li ,umask= Ns Ar qualifier
+Count the number of L2 M-state lines evicted.
+.Pp
+.Pq Tn "Pentium M"
+On these processors an additional qualifier may be specified and
+comprises a list of the following keywords separated by
+.Ql +
+characters:
+.Pp
+.Bl -tag -width indent -compact
+.It Li both
+Count both hardware-prefetched lines and non-hardware-prefetched lines.
+.It Li hw
+Count hardware-prefetched lines only.
+.It Li nonhw
+Exclude hardware-prefetched lines.
+.El
+.Pp
+The default is to count both hardware-prefetched and
+non-hardware-prefetch operations.
+.Pq Errata
+This event is affected by processor errata E53.
+.It Li p6-l2-rqsts Op Li ,umask= Ns Ar qualifier
+Count the total number of L2 requests.
+An additional qualifier may be specified and comprises a list of the following
+keywords separated by
+.Ql +
+characters:
+.Pp
+.Bl -tag -width indent -compact
+.It Li e
+Count operations affecting E (exclusive) state lines.
+.It Li i
+Count operations affecting I (invalid) state lines.
+.It Li m
+Count operations affecting M (modified) state lines.
+.It Li s
+Count operations affecting S (shared) state lines.
+.El
+.Pp
+The default is to count operations affecting all (MESI) state lines.
+.It Li p6-l2-st
+Count the number of L2 data stores.
+An additional qualifier may be specified and comprises a list of the following
+keywords separated by
+.Ql +
+characters:
+.Pp
+.Bl -tag -width indent -compact
+.It Li e
+Count operations affecting E (exclusive) state lines.
+.It Li i
+Count operations affecting I (invalid) state lines.
+.It Li m
+Count operations affecting M (modified) state lines.
+.It Li s
+Count operations affecting S (shared) state lines.
+.El
+.Pp
+The default is to count operations affecting all (MESI) state lines.
+.It Li p6-ld-blocks
+Count the number of load operations delayed due to store buffer blocks.
+.It Li p6-misalign-mem-ref
+Count the number of misaligned data memory references (crossing a 64
+bit boundary).
+.It Li p6-mmx-assist
+.Pq Tn "Pentium II" , Tn "Pentium III"
+Count the number of MMX assists executed.
+.It Li p6-mmx-instr-exec
+.Pq Tn Celeron , Tn "Pentium II"
+Count the number of MMX instructions executed, except MOVQ and MOVD
+stores from register to memory.
+.It Li p6-mmx-instr-ret
+.Pq Tn "Pentium II"
+Count the number of MMX instructions retired.
+.It Li p6-mmx-instr-type-exec Op Li ,umask= Ns Ar qualifier
+.Pq Tn "Pentium II" , Tn "Pentium III"
+Count the number of MMX instructions executed.
+An additional qualifier may be specified and comprises a list of
+the following keywords separated by
+.Ql +
+characters:
+.Pp
+.Bl -tag -width indent -compact
+.It Li pack
+Count MMX pack operation instructions.
+.It Li packed-arithmetic
+Count MMX packed arithmetic instructions.
+.It Li packed-logical
+Count MMX packed logical instructions.
+.It Li packed-multiply
+Count MMX packed multiply instructions.
+.It Li packed-shift
+Count MMX packed shift instructions.
+.It Li unpack
+Count MMX unpack operation instructions.
+.El
+.Pp
+The default is to count all operations.
+.It Li p6-mmx-sat-instr-exec
+.Pq Tn "Pentium II" , Tn "Pentium III"
+Count the number of MMX saturating instructions executed.
+.It Li p6-mmx-uops-exec
+.Pq Tn "Pentium II" , Tn "Pentium III"
+Count the number of MMX micro-ops executed.
+.It Li p6-mul
+Count the number of floating point multiplies.
+This event is only allocated on counter 1.
+.It Li p6-partial-rat-stalls
+Count the number of cycles or events for partial stalls.
+.It Li p6-resource-stalls
+Count the number of cycles there was a resource related stall of any kind.
+.It Li p6-ret-seg-renames
+.Pq Tn "Pentium II" , Tn "Pentium III"
+Count the number of segment register rename events retired.
+.It Li p6-sb-drains
+Count the number of cycles the store buffer is draining.
+.It Li p6-seg-reg-renames Op Li ,umask= Ns Ar qualifier
+.Pq Tn "Pentium II" , Tn "Pentium III"
+Count the number of segment register renames.
+An additional qualifier may be specified, and comprises a list of the
+following keywords separated by
+.Ql +
+characters:
+.Pp
+.Bl -tag -width indent -compact
+.It Li ds
+Count renames for segment register DS.
+.It Li es
+Count renames for segment register ES.
+.It Li fs
+Count renames for segment register FS.
+.It Li gs
+Count renames for segment register GS.
+.El
+.Pp
+The default is to count operations affecting all segment registers.
+.It Li p6-seg-rename-stalls
+.Pq Tn "Pentium II" , Tn "Pentium III"
+Count the number of segment register renaming stalls.
+An additional qualifier may be specified, and comprises a list of the
+following keywords separated by
+.Ql +
+characters:
+.Pp
+.Bl -tag -width indent -compact
+.It Li ds
+Count stalls for segment register DS.
+.It Li es
+Count stalls for segment register ES.
+.It Li fs
+Count stalls for segment register FS.
+.It Li gs
+Count stalls for segment register GS.
+.El
+.Pp
+The default is to count operations affecting all the segment registers.
+.It Li p6-segment-reg-loads
+Count the number of segment register loads.
+.It Li p6-uops-retired
+Count the number of micro-ops retired.
+.El
+.Ss Intel P4 PMCS
+Intel P4 PMCs are present in Intel
+.Tn "Pentium 4"
+and
+.Tn Xeon
+processors.
+These PMCs are documented in
+.Rs
+.%B "IA-32 Intel(R) Architecture Software Developer's Manual"
+.%T "Volume 3: System Programming Guide"
+.%N "Order Number 245472-012"
+.%D 2003
+.%Q "Intel Corporation"
+.Re
+Further information about using these PMCs may be found in
+.Rs
+.%B "IA-32 Intel(R) Architecture Optimization Guide"
+.%D 2003
+.%N "Order Number 248966-009"
+.%Q "Intel Corporation"
+.Re
+Some of these events are affected by processor errata described in
+.Rs
+.%B "Intel(R) Pentium(R) 4 Processor Specification Update"
+.%N "Document Number: 249199-059"
+.%D "April 2005"
+.%Q "Intel Corporation"
+.Re
+.Pp
+Event specifiers for Intel P4 PMCs can have the following common
+qualifiers:
+.Bl -tag -width indent
+.It Li active= Ns Ar choice
+(On P4 HTT CPUs) Filter event counting based on which logical
+processors are active.
+The allowed values of
+.Ar choice
+are:
+.Pp
+.Bl -tag -width indent -compact
+.It Li any
+Count when either logical processor is active.
+.It Li both
+Count when both logical processors are active.
+.It Li none
+Count only when neither logical processor is active.
+.It Li single
+Count only when one logical processor is active.
+.El
+.Pp
+The default is
+.Dq Li both .
+.It Li cascade
+Configure the PMC to cascade onto its partner.
+See
+.Sx "Cascading P4 PMCs"
+below for more information.
+.It Li edge
+Configure the counter to count false to true transitions of the threshold
+comparision output.
+This qualifier only takes effect if a threshold qualifier has also been
+specified.
+.It Li complement
+Configure the counter to increment only when the event count seen is
+less than the threshold qualifier value specified.
+.It Li mask= Ns Ar qualifier
+Many event specifiers for Intel P4 PMCs need to be additionally
+qualified using a mask qualifier.
+The allowed syntax for these qualifiers is event specific and is
+described along with the events.
+.It Li os
+Configure the PMC to count when the CPL of the processor is 0.
+.It Li precise
+Select precise event based sampling.
+Precise sampling is supported by the hardware for a limited set of
+events.
+.It Li tag= Ns Ar value
+Configure the PMC to tag the internal uop selected by the other
+fields in this event specifier with value
+.Ar value .
+This feature is used when cascading PMCs.
+.It Li threshold= Ns Ar value
+Configure the PMC to increment only when the event counts seen are
+greater than the specified threshold value
+.Ar value .
+.It Li usr
+Configure the PMC to count when the CPL of the processor is 1, 2 or 3.
+.El
+.Pp
+If neither of the
+.Dq Li os
+or
+.Dq Li usr
+qualifiers are specified, the default is to enable both.
+.Pp
+On Intel Pentium 4 processors with HTT, events are
+divided into two classes:
+.Pp
+.Bl -tag -width indent -compact
+.It "TS Events"
+are those where hardware can differentiate between events
+generated on one logical processor from those generated on the
+other.
+.It "TI Events"
+are those where hardware cannot differentiate between events
+generated by multiple logical processors in a package.
+.El
+.Pp
+Only TS events are allowed for use with process-mode PMCs on
+Pentium-4/HTT CPUs.
+.Pp
+The event specifiers supported by Intel P4 PMCs are:
+.Pp
+.Bl -tag -width indent
+.It Li p4-128bit-mmx-uop Op Li ,mask= Ns Ar flags
+.Pq "TI event"
+Count integer SIMD SSE2 instructions that operate on 128 bit SIMD
+operands.
+Qualifier
+.Ar flags
+can take the following value (which is also the default):
+.Pp
+.Bl -tag -width indent -compact
+.It Li all
+Count all uops operating on 128 bit SIMD integer operands in memory or
+XMM register.
+.El
+.Pp
+If an instruction contains more than one 128 bit MMX uop, then each
+uop will be counted.
+.It Li p4-64bit-mmx-uop Op Li ,mask= Ns Ar flags
+.Pq "TI event"
+Count MMX instructions that operate on 64 bit SIMD operands.
+Qualifier
+.Ar flags
+can take the following value (which is also the default):
+.Pp
+.Bl -tag -width indent -compact
+.It Li all
+Count all uops operating on 64 bit SIMD integer operands in memory or
+in MMX registers.
+.El
+.Pp
+If an instruction contains more than one 64 bit MMX uop, then each
+uop will be counted.
+.It Li p4-b2b-cycles
+.Pq "TI event"
+Count back-to-back bys cycles.
+Further documentation for this event is unavailable.
+.It Li p4-bnr
+.Pq "TI event"
+Count bus-not-ready conditions.
+Further documentation for this event is unavailable.
+.It Li p4-bpu-fetch-request Op Li ,mask= Ns Ar qualifier
+.Pq "TS event"
+Count instruction fetch requests qualified by additional
+flags specified in
+.Ar qualifier .
+At this point only one flag is supported:
+.Pp
+.Bl -tag -width indent -compact
+.It Li tcmiss
+Count trace cache lookup misses.
+.El
+.Pp
+The default qualifier is also
+.Dq Li mask=tcmiss .
+.It Li p4-branch-retired Op Li ,mask= Ns Ar flags
+.Pq "TS event"
+Counts retired branches.
+Qualifier
+.Ar flags
+is a list of the following
+.Ql +
+separated strings:
+.Pp
+.Bl -tag -width indent -compact
+.It Li mmnp
+Count branches not-taken and predicted.
+.It Li mmnm
+Count branches not-taken and mis-predicted.
+.It Li mmtp
+Count branches taken and predicted.
+.It Li mmtm
+Count branches taken and mis-predicted.
+.El
+.Pp
+The default qualifier counts all four kinds of branches.
+.It Li p4-bsq-active-entries Op Li ,mask= Ns Ar qualifier
+.Pq "TS event"
+Count the number of entries (clipped at 15) currently active in the
+BSQ.
+Qualifier
+.Ar qualifier
+is a
+.Ql +
+separated set of the following flags:
+.Pp
+.Bl -tag -width indent -compact
+.It Li req-type0 , Li req-type1
+Forms a 2-bit number used to select the request type encoding:
+.Pp
+.Bl -tag -width indent -compact
+.It Li 0
+reads excluding read invalidate
+.It Li 1
+read invalidates
+.It Li 2
+writes other than writebacks
+.It Li 3
+writebacks
+.El
+.Pp
+Bit
+.Dq Li req-type1
+is the MSB for this two bit number.
+.It Li req-len0 , Li req-len1
+Forms a two-bit number that specifies the request length encoding:
+.Pp
+.Bl -tag -width indent -compact
+.It Li 0
+0 chunks
+.It Li 1
+1 chunk
+.It Li 3
+8 chunks
+.El
+.Pp
+Bit
+.Dq Li req-len1
+is the MSB for this two bit number.
+.It Li req-io-type
+Count requests that are input or output requests.
+.It Li req-lock-type
+Count requests that lock the bus.
+.It Li req-lock-cache
+Count requests that lock the cache.
+.It Li req-split-type
+Count requests that is a bus 8-byte chunk that is split across an
+8-byte boundary.
+.It Li req-dem-type
+Count requests that are demand (not prefetches) if set.
+Count requests that are prefetches if not set.
+.It Li req-ord-type
+Count requests that are ordered.
+.It Li mem-type0 , Li mem-type1 , Li mem-type2
+Forms a 3-bit number that specifies a memory type encoding:
+.Pp
+.Bl -tag -width indent -compact
+.It Li 0
+UC
+.It Li 1
+USWC
+.It Li 4
+WT
+.It Li 5
+WP
+.It Li 6
+WB
+.El
+.Pp
+Bit
+.Dq Li mem-type2
+is the MSB of this 3-bit number.
+.El
+.Pp
+The default qualifier has all the above bits set.
+.Pp
+Edge triggering using the
+.Dq Li edge
+qualifier should not be used with this event when counting cycles.
+.It Li p4-bsq-allocation Op Li ,mask= Ns Ar qualifier
+.Pq "TS event"
+Count allocations in the bus sequence unit according to the flags
+specified in
+.Ar qualifier ,
+which is a
+.Ql +
+separated set of the following flags:
+.Pp
+.Bl -tag -width indent -compact
+.It Li req-type0 , Li req-type1
+Forms a 2-bit number used to select the request type encoding:
+.Pp
+.Bl -tag -width indent -compact
+.It Li 0
+reads excluding read invalidate
+.It Li 1
+read invalidates
+.It Li 2
+writes other than writebacks
+.It Li 3
+writebacks
+.El
+.Pp
+Bit
+.Dq Li req-type1
+is the MSB for this two bit number.
+.It Li req-len0 , Li req-len1
+Forms a two-bit number that specifies the request length encoding:
+.Pp
+.Bl -tag -width indent -compact
+.It Li 0
+0 chunks
+.It Li 1
+1 chunk
+.It Li 3
+8 chunks
+.El
+.Pp
+Bit
+.Dq Li req-len1
+is the MSB for this two bit number.
+.It Li req-io-type
+Count requests that are input or output requests.
+.It Li req-lock-type
+Count requests that lock the bus.
+.It Li req-lock-cache
+Count requests that lock the cache.
+.It Li req-split-type
+Count requests that is a bus 8-byte chunk that is split across an
+8-byte boundary.
+.It Li req-dem-type
+Count requests that are demand (not prefetches) if set.
+Count requests that are prefetches if not set.
+.It Li req-ord-type
+Count requests that are ordered.
+.It Li mem-type0 , Li mem-type1 , Li mem-type2
+Forms a 3-bit number that specifies a memory type encoding:
+.Pp
+.Bl -tag -width indent -compact
+.It Li 0
+UC
+.It Li 1
+USWC
+.It Li 4
+WT
+.It Li 5
+WP
+.It Li 6
+WB
+.El
+.Pp
+Bit
+.Dq Li mem-type2
+is the MSB of this 3-bit number.
+.El
+.Pp
+The default qualifier has all the above bits set.
+.Pp
+This event is usually used along with the
+.Dq Li edge
+qualifier to avoid multiple counting.
+.It Li p4-bsq-cache-reference Op Li ,mask= Ns Ar qualifier
+.Pq "TS event"
+Count cache references as seen by the bus unit (2nd or 3rd level
+cache references).
+Qualifier
+.Ar qualifier
+is a
+.Ql +
+separated list of the following keywords:
+.Pp
+.Bl -tag -width indent -compact
+.It Li rd-2ndl-hits
+Count 2nd level cache hits in the shared state.
+.It Li rd-2ndl-hite
+Count 2nd level cache hits in the exclusive state.
+.It Li rd-2ndl-hitm
+Count 2nd level cache hits in the modified state.
+.It Li rd-3rdl-hits
+Count 3rd level cache hits in the shared state.
+.It Li rd-3rdl-hite
+Count 3rd level cache hits in the exclusive state.
+.It Li rd-3rdl-hitm
+Count 3rd level cache hits in the modified state.
+.It Li rd-2ndl-miss
+Count 2nd level cache misses.
+.It Li rd-3rdl-miss
+Count 3rd level cache misses.
+.It Li wr-2ndl-miss
+Count write-back lookups from the data access cache that miss the 2nd
+level cache.
+.El
+.Pp
+The default is to count all the above events.
+.It Li p4-execution-event Op Li ,mask= Ns Ar flags
+.Pq "TS event"
+Count the retirement of tagged uops selected through the execution
+tagging mechanism.
+Qualifier
+.Ar flags
+can contain the following strings separated by
+.Ql +
+characters:
+.Pp
+.Bl -tag -width indent -compact
+.It Li nbogus0 , Li nbogus1 , Li nbogus2 , Li nbogus3
+The marked uops are not bogus.
+.It Li bogus0 , Li bogus1 , Li bogus2 , Li bogus3
+The marked uops are bogus.
+.El
+.Pp
+This event requires additional (upstream) events to be allocated to
+perform the desired uop tagging.
+The default is to set all the above flags.
+This event can be used for precise event based sampling.
+.It Li p4-front-end-event Op Li ,mask= Ns Ar flags
+.Pq "TS event"
+Count the retirement of tagged uops selected through the front-end
+tagging mechanism.
+Qualifier
+.Ar flags
+can contain the following strings separated by
+.Ql +
+characters:
+.Pp
+.Bl -tag -width indent -compact
+.It Li nbogus
+The marked uops are not bogus.
+.It Li bogus
+The marked uops are bogus.
+.El
+.Pp
+This event requires additional (upstream) events to be allocated to
+perform the desired uop tagging.
+The default is to select both kinds of events.
+This event can be used for precise event based sampling.
+.It Li p4-fsb-data-activity Op Li ,mask= Ns Ar flags
+.Pq "TI event"
+Count each DBSY or DRDY event selected by qualifier
+.Ar flags .
+Qualifier
+.Ar flags
+is a
+.Ql +
+separated set of the following flags:
+.Pp
+.Bl -tag -width indent -compact
+.It Li drdy-drv
+Count when this processor is driving data onto the bus.
+.It Li drdy-own
+Count when this processor is reading data from the bus.
+.It Li drdy-other
+Count when data is on the bus but not being sampled by this processor.
+.It Li dbsy-drv
+Count when this processor reserves the bus for use in the next cycle
+in order to drive data.
+.It Li dbsy-own
+Count when some agent reserves the bus for use in the next bus cycle
+to drive data that this processor will sample.
+.It Li dbsy-other
+Count when some agent reserves the bus for use in the next bus cycle
+to drive data that this processor will not sample.
+.El
+.Pp
+Flags
+.Dq Li drdy-own
+and
+.Dq Li drdy-other
+are mutually exclusive.
+Flags
+.Dq Li dbsy-own
+and
+.Dq Li dbsy-other
+are mutually exclusive.
+The default value for
+.Ar qualifier
+is
+.Dq Li drdy-drv+drdy-own+dbsy-drv+dbsy-own .
+.It Li p4-global-power-events Op Li ,mask= Ns Ar flags
+.Pq "TS event"
+Count cycles during which the processor is not stopped.
+Qualifier
+.Ar flags
+can take the following value (which is also the default):
+.Pp
+.Bl -tag -width indent -compact
+.It Li running
+Count cycles when the processor is active.
+.El
+.Pp
+.It Li p4-instr-retired Op Li ,mask= Ns Ar flags
+.Pq "TS event"
+Count instructions retired during a clock cycle.
+Qualifer
+.Ar flags
+comprises of the following strings separated by
+.Ql +
+characters:
+.Pp
+.Bl -tag -width indent -compact
+.It Li nbogusntag
+Count non-bogus instructions that are not tagged.
+.It Li nbogustag
+Count non-bogus instructions that are tagged.
+.It Li bogusntag
+Count bogus instructions that are not tagged.
+.It Li bogustag
+Count bogus instructions that are tagged.
+.El
+.Pp
+The default qualifier counts all the above kinds of instructions.
+.It Li p4-ioq-active-entries Xo
+.Op Li ,mask= Ns Ar qualifier
+.Op Li ,busreqtype= Ns Ar req-type
+.Xc
+.Pq "TS event"
+Count the number of entries (clipped at 15) in the IOQ that are
+active.
+The event masks are specified by qualifier
+.Ar qualifier
+and
+.Ar req-type .
+.Pp
+Qualifier
+.Ar qualifier
+is a
+.Ql +
+separated set of the following flags:
+.Pp
+.Bl -tag -width indent -compact
+.It Li all-read
+Count read entries.
+.It Li all-write
+Count write entries.
+.It Li mem-uc
+Count entries accessing uncacheable memory.
+.It Li mem-wc
+Count entries accessing write-combining memory.
+.It Li mem-wt
+Count entries accessing write-through memory.
+.It Li mem-wp
+Count entries accessing write-protected memory
+.It Li mem-wb
+Count entries accessing write-back memory.
+.It Li own
+Count store requests driven by the processor (i.e., not by other
+processors or by DMA).
+.It Li other
+Count store requests driven by other processors or by DMA.
+.It Li prefetch
+Include hardware and software prefetch requests in the count.
+.El
+.Pp
+The default value for
+.Ar qualifier
+is to enable all the above flags.
+.Pp
+The
+.Ar req-type
+qualifier is a 5-bit number can be additionally used to select a
+specific bus request type.
+The default is 0.
+.Pp
+The
+.Dq Li edge
+qualifier should not be used when counting cycles with this event.
+The exact behaviour of this event depends on the processor revision.
+.It Li p4-ioq-allocation Xo
+.Op Li ,mask= Ns Ar qualifier
+.Op Li ,busreqtype= Ns Ar req-type
+.Xc
+.Pq "TS event"
+Count various types of transactions on the bus matching the flags set
+in
+.Ar qualifier
+and
+.Ar req-type .
+.Pp
+Qualifier
+.Ar qualifier
+is a
+.Ql +
+separated set of the following flags:
+.Pp
+.Bl -tag -width indent -compact
+.It Li all-read
+Count read entries.
+.It Li all-write
+Count write entries.
+.It Li mem-uc
+Count entries accessing uncacheable memory.
+.It Li mem-wc
+Count entries accessing write-combining memory.
+.It Li mem-wt
+Count entries accessing write-through memory.
+.It Li mem-wp
+Count entries accessing write-protected memory
+.It Li mem-wb
+Count entries accessing write-back memory.
+.It Li own
+Count store requests driven by the processor (i.e., not by other
+processors or by DMA).
+.It Li other
+Count store requests driven by other processors or by DMA.
+.It Li prefetch
+Include hardware and software prefetch requests in the count.
+.El
+.Pp
+The default value for
+.Ar qualifier
+is to enable all the above flags.
+.Pp
+The
+.Ar req-type
+qualifier is a 5-bit number can be additionally used to select a
+specific bus request type.
+The default is 0.
+.Pp
+The
+.Dq Li edge
+qualifier is normally used with this event to prevent multiple
+counting.
+The exact behaviour of this event depends on the processor revision.
+.It Li p4-itlb-reference Op mask= Ns Ar qualifier
+.Pq "TS event"
+Count translations using the intruction translation look-aside
+buffer.
+The
+.Ar qualifier
+argument is a list of the following strings separated by
+.Ql +
+characters.
+.Pp
+.Bl -tag -width indent -compact
+.It Li hit
+Count ITLB hits.
+.It Li miss
+Count ITLB misses.
+.It Li hit-uc
+Count uncacheable ITLB hits.
+.El
+.Pp
+If no
+.Ar qualifier
+is specified the default is to count all the three kinds of ITLB
+translations.
+.It Li p4-load-port-replay Op Li ,mask= Ns Ar qualifier
+.Pq "TS event"
+Count replayed events at the load port.
+Qualifier
+.Ar qualifier
+can take on one value:
+.Pp
+.Bl -tag -width indent -compact
+.It Li split-ld
+Count split loads.
+.El
+.Pp
+The default value for
+.Ar qualifier
+is
+.Dq Li split-ld .
+.It Li p4-mispred-branch-retired Op Li ,mask= Ns Ar flags
+.Pq "TS event"
+Count mispredicted IA-32 branch instructions.
+Qualifier
+.Ar flags
+can take the following value (which is also the default):
+.Pp
+.Bl -tag -width indent -compact
+.It Li nbogus
+Count non-bogus retired branch instructions.
+.El
+.It Li p4-machine-clear Op Li ,mask= Ns Ar flags
+.Pq "TS event"
+Count the number of pipeline clears seen by the processor.
+Qualifer
+.Ar flags
+is a list of the following strings separated by
+.Ql +
+characters:
+.Pp
+.Bl -tag -width indent -compact
+.It Li clear
+Count for a portion of the many cycles when the machine is being
+cleared for any reason.
+.It Li moclear
+Count machine clears due to memory ordering issues.
+.It Li smclear
+Count machine clears due to self-modifying code.
+.El
+.Pp
+Use qualifier
+.Dq Li edge
+to get a count of occurrences of machine clears.
+The default qualifier is
+.Dq Li clear .
+.It Li p4-memory-cancel Op Li ,mask= Ns Ar event-list
+.Pq "TS event"
+Count the cancelling of various kinds of requests in the data cache
+address control unit of the CPU.
+The qualifier
+.Ar event-list
+is a list of the following strings separated by
+.Ql +
+characters:
+.Pp
+.Bl -tag -width indent -compact
+.It Li st-rb-full
+Requests cancelled because no store request buffer was available.
+.It Li 64k-conf
+Requests that conflict due to 64K aliasing.
+.El
+.Pp
+If
+.Ar event-list
+is not specified, then the default is to count both kinds of events.
+.It Li p4-memory-complete Op Li ,mask= Ns Ar event-list
+.Pq "TS event"
+Count the completion of load split, store split, uncacheable split and
+uncacheable load operations selected by qualifier
+.Ar event-list .
+The qualifier
+.Ar event-list
+is a
+.Ql +
+separated list of the following flags:
+.Pp
+.Bl -tag -width indent -compact
+.It Li lsc
+Count load splits completed, excluding loads from uncacheable or
+write-combining areas.
+.It Li ssc
+Count any split stores completed.
+.El
+.Pp
+The default is to count both kinds of operations.
+.It Li p4-mob-load-replay Op Li ,mask= Ns Ar qualifier
+.Pq "TS event"
+Count load replays triggered by the memory order buffer.
+Qualifier
+.Ar qualifier
+can be a
+.Ql +
+separated list of the following flags:
+.Pp
+.Bl -tag -width indent -compact
+.It Li no-sta
+Count replays because of unknown store addresses.
+.It Li no-std
+Count replays because of unknown store data.
+.It Li partial-data
+Count replays because of partially overlapped data accesses between
+load and store operations.
+.It Li unalgn-addr
+Count replays because of mismatches in the lower 4 bits of load and
+store operations.
+.El
+.Pp
+The default qualifier is
+.Ar no-sta+no-std+partial-data+unalgn-addr .
+.It Li p4-packed-dp-uop Op Li ,mask= Ns Ar flags
+.Pq "TI event"
+Count packed double-precision uops.
+Qualifier
+.Ar flags
+can take the following value (which is also the default):
+.Pp
+.Bl -tag -width indent -compact
+.It Li all
+Count all uops operating on packed double-precision operands.
+.El
+.It Li p4-packed-sp-uop Op Li ,mask= Ns Ar flags
+.Pq "TI event"
+Count packed single-precision uops.
+Qualifier
+.Ar flags
+can take the following value (which is also the default):
+.Pp
+.Bl -tag -width indent -compact
+.It Li all
+Count all uops operating on packed single-precision operands.
+.El
+.It Li p4-page-walk-type Op Li ,mask= Ns Ar qualifier
+.Pq "TI event"
+Count page walks performed by the page miss handler.
+Qualifier
+.Ar qualifier
+can be a
+.Ql +
+separated list of the following keywords:
+.Pp
+.Bl -tag -width indent -compact
+.It Li dtmiss
+Count page walks for data TLB misses.
+.It Li itmiss
+Count page walks for instruction TLB misses.
+.El
+.Pp
+The default value for
+.Ar qualifier
+is
+.Dq Li dtmiss+itmiss .
+.It Li p4-replay-event Op Li ,mask= Ns Ar flags
+.Pq "TS event"
+Count the retirement of tagged uops selected through the replay
+tagging mechanism.
+Qualifier
+.Ar flags
+contains a
+.Ql +
+separated set of the following strings:
+.Pp
+.Bl -tag -width indent -compact
+.It Li nbogus
+The marked uops are not bogus.
+.It Li bogus
+The marked uops are bogus.
+.El
+.Pp
+This event requires additional (upstream) events to be allocated to
+perform the desired uop tagging.
+The default qualifier counts both kinds of uops.
+This event can be used for precise event based sampling.
+.It Li p4-resource-stall Op Li ,mask= Ns Ar flags
+.Pq "TS event"
+Count the occurrence or latency of stalls in the allocator.
+Qualifier
+.Ar flags
+can take the following value (which is also the default):
+.Pp
+.Bl -tag -width indent -compact
+.It Li sbfull
+A stall due to the lack of store buffers.
+.El
+.It Li p4-response
+.Pq "TI event"
+Count different types of responses.
+Further documentation on this event is not available.
+.It Li p4-retired-branch-type Op Li ,mask= Ns Ar flags
+.Pq "TS event"
+Count branches retired.
+Qualifier
+.Ar flags
+contains a
+.Ql +
+separated list of strings:
+.Pp
+.Bl -tag -width indent -compact
+.It Li conditional
+Count conditional jumps.
+.It Li call
+Count direct and indirect call branches.
+.It Li return
+Count return branches.
+.It Li indirect
+Count returns, indirect calls or indirect jumps.
+.El
+.Pp
+The default qualifier counts all the above branch types.
+.It Li p4-retired-mispred-branch-type Op Li ,mask= Ns Ar flags
+.Pq "TS event"
+Count mispredicted branches retired.
+Qualifier
+.Ar flags
+contains a
+.Ql +
+separated list of strings:
+.Pp
+.Bl -tag -width indent -compact
+.It Li conditional
+Count conditional jumps.
+.It Li call
+Count indirect call branches.
+.It Li return
+Count return branches.
+.It Li indirect
+Count returns, indirect calls or indirect jumps.
+.El
+.Pp
+The default qualifier counts all the above branch types.
+.It Li p4-scalar-dp-uop Op Li ,mask= Ns Ar flags
+.Pq "TI event"
+Count the number of scalar double-precision uops.
+Qualifier
+.Ar flags
+can take the following value (which is also the default):
+.Pp
+.Bl -tag -width indent -compact
+.It Li all
+Count the number of scalar double-precision uops.
+.El
+.It Li p4-scalar-sp-uop Op Li ,mask= Ns Ar flags
+.Pq "TI event"
+Count the number of scalar single-precision uops.
+Qualifier
+.Ar flags
+can take the following value (which is also the default):
+.Pp
+.Bl -tag -width indent -compact
+.It Li all
+Count all uops operating on scalar single-precision operands.
+.El
+.It Li p4-snoop
+.Pq "TI event"
+Count snoop traffic.
+Further documentation on this event is not available.
+.It Li p4-sse-input-assist Op Li ,mask= Ns Ar flags
+.Pq "TI event"
+Count the number of times an assist is required to handle problems
+with the operands for SSE and SSE2 operations.
+Qualifier
+.Ar flags
+can take the following value (which is also the default):
+.Pp
+.Bl -tag -width indent -compact
+.It Li all
+Count assists for all SSE and SSE2 uops.
+.El
+.It Li p4-store-port-replay Op Li ,mask= Ns Ar qualifier
+.Pq "TS event"
+Count events replayed at the store port.
+Qualifier
+.Ar qualifier
+can take on one value:
+.Pp
+.Bl -tag -width indent -compact
+.It Li split-st
+Count split stores.
+.El
+.Pp
+The default value for
+.Ar qualifier
+is
+.Dq Li split-st .
+.It Li p4-tc-deliver-mode Op Li ,mask= Ns Ar qualifier
+.Pq "TI event"
+Count the duration in cycles of operating modes of the trace cache and
+decode engine.
+The desired operating mode is selected by
+.Ar qualifier ,
+which is a list of the following strings separated by
+.Ql +
+characters:
+.Pp
+.Bl -tag -width indent -compact
+.It Li DD
+Both logical processors are in deliver mode.
+.It Li DB
+Logical processor 0 is in deliver mode while logical processor 1 is in
+build mode.
+.It Li DI
+Logical processor 0 is in deliver mode while logical processor 1 is
+halted, or in machine clear, or transitioning to a long microcode
+flow.
+.It Li BD
+Logical processor 0 is in build mode while logical processor 1 is in
+deliver mode.
+.It Li BB
+Both logical processors are in build mode.
+.It Li BI
+Logical processor 0 is in build mode while logical processor 1 is
+halted, or in machine clear or transitioning to a long microcode
+flow.
+.It Li ID
+Logical processor 0 is halted, or in machine clear or transitioning to
+a long microcode flow while logical processor 1 is in deliver mode.
+.It Li IB
+Logical processor 0 is halted, or in machine clear or transitioning to
+a long microcode flow while logical processor 1 is in build mode.
+.El
+.Pp
+If there is only one logical processor in the processor package then
+the qualifier for logical processor 1 is ignored.
+If no qualifier is specified, the default qualifier is
+.Dq Li DD+DB+DI+BD+BB+BI+ID+IB .
+.It Li p4-tc-ms-xfer Op Li ,mask= Ns Ar flags
+.Pq "TI event"
+Count the number of times uop delivery changed from the trace cache to
+MS ROM.
+Qualifier
+.Ar flags
+can take the following value (which is also the default):
+.Pp
+.Bl -tag -width indent -compact
+.It Li cisc
+Count TC to MS transfers.
+.El
+.It Li p4-uop-queue-writes Op Li ,mask= Ns Ar flags
+.Pq "TS event"
+Count the number of valid uops written to the uop queue.
+Qualifier
+.Ar flags
+is a list of the following strings, separated by
+.Ql +
+characters:
+.Pp
+.Bl -tag -width indent -compact
+.It Li from-tc-build
+Count uops being written from the trace cache in build mode.
+.It Li from-tc-deliver
+Count uops being written from the trace cache in deliver mode.
+.It Li from-rom
+Count uops being written from microcode ROM.
+.El
+.Pp
+The default qualifier counts all the above kinds of uops.
+.It Li p4-uop-type Op Li ,mask= Ns Ar flags
+.Pq "TS event"
+This event is used in conjunction with the front-end at-retirement
+mechanism to tag load and store uops.
+Qualifer
+.Ar flags
+comprises the following strings separated by
+.Ql +
+characters:
+.Pp
+.Bl -tag -width indent -compact
+.It Li tagloads
+Mark uops that are load operations.
+.It Li tagstores
+Mark uops that are store operations.
+.El
+.Pp
+The default qualifier counts both kinds of uops.
+.It Li p4-uops-retired Op Li ,mask= Ns Ar flags
+.Pq "TS event"
+Count uops retired during a clock cycle.
+Qualifier
+.Ar flags
+comprises the following strings separated by
+.Ql +
+characters:
+.Pp
+.Bl -tag -width indent -compact
+.It Li nbogus
+Count marked uops that are not bogus.
+.It Li bogus
+Count marked uops that are bogus.
+.El
+.Pp
+The default qualifier counts both kinds of uops.
+.It Li p4-wc-buffer Op Li ,mask= Ns Ar flags
+.Pq "TI event"
+Count write-combining buffer operations.
+Qualifier
+.Ar flags
+contains the following strings separated by
+.Ql +
+characters:
+.Pp
+.Bl -tag -width indent -compact
+.It Li wcb-evicts
+WC buffer evictions due to any cause.
+.It Li wcb-full-evict
+WC buffer evictions due to no WC buffer being available.
+.El
+.Pp
+The default qualifer counts both kinds of evictions.
+.It Li p4-x87-assist Op Li ,mask= Ns Ar flags
+.Pq "TS event"
+Count the retirement of x87 instructions that required special
+handling.
+Qualifier
+.Ar flags
+contains the following strings separated by
+.Ql +
+characters:
+.Pp
+.Bl -tag -width indent -compact
+.It Li fpsu
+Count instructions that saw an FP stack underflow.
+.It Li fpso
+Count instructions that saw an FP stack overflow.
+.It Li poao
+Count instructions that saw an x87 output overflow.
+.It Li poau
+Count instructions that saw an x87 output underflow.
+.It Li prea
+Count instructions that needed an x87 input assist.
+.El
+.Pp
+The default qualifier counts all the above types of instruction
+retirements.
+.It Li p4-x87-fp-uop Op Li ,mask= Ns Ar flags
+.Pq "TI event"
+Count x87 floating-point uops.
+Qualifier
+.Ar flags
+can take the following value (which is also the default):
+.Pp
+.Bl -tag -width indent -compact
+.It Li all
+Count all x87 floating-point uops.
+.El
+.Pp
+If an instruction contains more than one x87 floating-point uops, then
+all x87 floating-point uops will be counted.
+This event does not count x87 floating-point data movement operations.
+.It Li p4-x87-simd-moves-uop Op Li ,mask= Ns Ar flags
+.Pq "TI event"
+Count each x87 FPU, MMX, SSE, or SSE2 uops that load data or store
+data or perform register-to-register moves.
+This event does not count integer move uops.
+Qualifier
+.Ar flags
+may contain the following keywords separated by
+.Ql +
+characters:
+.Pp
+.Bl -tag -width indent -compact
+.It Li allp0
+Count all x87 and SIMD store and move uops.
+.It Li allp2
+Count all x87 and SIMD load uops.
+.El
+.Pp
+The default is to count all uops.
+.Pq Errata
+This event may be affected by processor errata N43.
+.El
+.Ss "Cascading P4 PMCs"
+PMC cascading support is currently poorly implemented.
+While individual event counters may be allocated with a
+.Dq Li cascade
+qualifier, the current API does not offer the ability
+to name and allocate all the resources needed for a
+cascaded event counter pair in a single operation.
+.Ss "Precise Event Based Sampling"
+Support for precise event based sampling is currently
+unimplemented in
+.Xr hwpmc 4 .
+.Sh IMPLEMENTATION NOTES
+On the i386 architecture,
+.Fx
+has historically allowed the use of the RDTSC instruction from
+user-mode (i.e., at a processor CPL of 3) by any process.
+This behaviour is preserved by
+.Xr hwpmc 4 .
+.Sh RETURN VALUES
+The
+.Fn pmc_name_of_capability ,
+.Fn pmc_name_of_class ,
+.Fn pmc_name_of_cputype ,
+.Fn pmc_name_of_disposition ,
+.Fn pmc_name_of_event ,
+.Fn pmc_name_of_mode ,
+and
+.Fn pmc_name_of_state
+functions return a pointer to the human readable form of their argument.
+These pointers may point to statically allocated storage and must
+not be passed to
+.Fn free .
+In case of an error, these functions return
+.Dv NULL
+and set the global variable
+.Va errno .
+.Pp
+The functions
+.Fn pmc_ncpu
+and
+.Fn pmc_npmc
+return the number of CPUs and number of PMCs configured respectively;
+in case of an error they return the value
+\-1
+and set the global variable
+.Va errno .
+.Pp
+All other functions return the value
+0
+if successful; otherwise the value
+\-1
+is returned and the global variable
+.Va errno
+is set to indicate the error.
+.Sh COMPATIBILITY
+The interface between the
+.Nm pmc
+library and the
+.Xr hwpmc 4
+driver is intended to be private to the implementation and may
+change.
+In order to ease forward compatibility with future versions of the
+.Xr hwpmc 4
+driver, applications are urged to dynamically link with the
+.Nm pmc
+library.
+.Pp
+The
+.Nm pmc
+API is
+.Ud
+.Sh ERRORS
+A call to
+.Fn pmc_init
+may fail with the following errors in addition to those returned by
+.Xr modfind 2 ,
+.Xr modstat 2
+and
+.Xr hwpmc 4 :
+.Bl -tag -width Er
+.It Bq Er ENXIO
+An unknown CPU type was encountered during initialization.
+.It Bq Er EPROGMISMATCH
+The version number of the
+.Xr hwpmc 4
+kernel module did not match that compiled into the
+.Nm pmc
+library.
+.El
+.Pp
+A call to
+.Fn pmc_capabilities ,
+.Fn pmc_name_of_capability ,
+.Fn pmc_name_of_disposition ,
+.Fn pmc_name_of_state ,
+.Fn pmc_name_of_event ,
+.Fn pmc_name_of_mode
+.Fn pmc_name_of_class
+and
+.Fn pmc_width
+may fail with the following error:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+An invalid argument was passed to the function.
+.El
+.Pp
+A call to
+.Fn pmc_cpuinfo
+or
+.Fn pmc_ncpu
+may fail with the following error:
+.Bl -tag -width Er
+.It Bq Er ENXIO
+The
+.Nm pmc
+has not been initialized.
+.El
+.Pp
+A call to
+.Fn pmc_npmc
+may fail with the following errors:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The argument passed in was out of range.
+.It Bq Er ENXIO
+The
+.Nm pmc
+library has not been initialized.
+.El
+.Pp
+A call to
+.Fn pmc_pmcinfo
+may fail with the following errors, in addition to those returned by
+.Xr hwpmc 4 :
+.Bl -tag -width Er
+.It Bq Er ENXIO
+The
+.Nm pmc
+library is not yet initialized.
+.El
+.Pp
+A call to
+.Fn pmc_allocate
+may fail with the following errors, in addition to those returned by
+.Xr hwpmc 4 :
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa mode
+argument passed in had an illegal value, or the event specification
+.Fa ctrspec
+was unrecognized for this CPU type.
+.El
+.Pp
+Calls to
+.Fn pmc_attach ,
+.Fn pmc_configure_logfile ,
+.Fn pmc_detach ,
+.Fn pmc_disable ,
+.Fn pmc_enable ,
+.Fn pmc_get_driver_stats ,
+.Fn pmc_get_msr ,
+.Fn pmc_read ,
+.Fn pmc_release ,
+.Fn pmc_rw ,
+.Fn pmc_set ,
+.Fn pmc_start ,
+.Fn pmc_stop ,
+.Fn pmc_write ,
+and
+.Fn pmc_writelog
+may fail with the errors described in
+.Xr hwpmc 4 .
+.Pp
+If a log file was configured using
+.Fn pmc_configure_logfile
+and the
+.Xr hwpmc 4
+driver encountered an error while logging data to it, then
+logging will be stopped and a subsequent call to
+.Fn pmc_flush_logfile
+will fail with the error code seen by the
+.Xr hwpmc 4
+driver.
+.Sh SEE ALSO
+.Xr modfind 2 ,
+.Xr modstat 2 ,
+.Xr calloc 3 ,
+.Xr pmclog 3 ,
+.Xr hwpmc 4 ,
+.Xr pmccontrol 8 ,
+.Xr pmcstat 8
+.Sh HISTORY
+The
+.Nm pmc
+library first appeared in
+.Fx 6.0 .
+.Sh BUGS
+The information returned by
+.Fn pmc_cpuinfo ,
+.Fn pmc_ncpu
+and possibly
+.Fn pmc_npmc
+should really be available all the time, through a better designed
+interface and not just when
+.Xr hwpmc 4
+is present in the kernel.
diff --git a/lib/libpmc/pmc.h b/lib/libpmc/pmc.h
new file mode 100644
index 0000000..ee3f772
--- /dev/null
+++ b/lib/libpmc/pmc.h
@@ -0,0 +1,109 @@
+/*-
+ * Copyright (c) 2003,2004 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 _PMC_H_
+#define _PMC_H_
+
+#include <sys/pmc.h>
+
+/*
+ * Driver statistics.
+ */
+struct pmc_driverstats {
+ int pm_intr_ignored; /* #interrupts ignored */
+ int pm_intr_processed; /* #interrupts processed */
+ int pm_intr_bufferfull; /* #interrupts with ENOSPC */
+ int pm_syscalls; /* #syscalls */
+ int pm_syscall_errors; /* #syscalls with errors */
+ int pm_buffer_requests; /* #buffer requests */
+ int pm_buffer_requests_failed; /* #failed buffer requests */
+ int pm_log_sweeps; /* #sample buffer processing passes */
+};
+
+/*
+ * CPU information.
+ */
+struct pmc_cpuinfo {
+ enum pmc_cputype pm_cputype; /* the kind of CPU */
+ uint32_t pm_ncpu; /* number of CPUs */
+ uint32_t pm_npmc; /* #PMCs per CPU */
+ uint32_t pm_nclass; /* #classes of PMCs */
+ struct pmc_classinfo pm_classes[PMC_CLASS_MAX];
+};
+
+/*
+ * Current PMC state.
+ */
+struct pmc_pmcinfo {
+ int32_t pm_cpu; /* CPU number */
+ struct pmc_info pm_pmcs[]; /* NPMC structs */
+};
+
+/*
+ * Prototypes
+ */
+
+int pmc_allocate(const char *_ctrspec, enum pmc_mode _mode, uint32_t _flags,
+ int _cpu, pmc_id_t *_pmcid);
+int pmc_attach(pmc_id_t _pmcid, pid_t _pid);
+int pmc_capabilities(pmc_id_t _pmc, uint32_t *_caps);
+int pmc_configure_logfile(int _fd);
+int pmc_flush_logfile(void);
+int pmc_detach(pmc_id_t _pmcid, pid_t _pid);
+int pmc_disable(int _cpu, int _pmc);
+int pmc_enable(int _cpu, int _pmc);
+int pmc_get_driver_stats(struct pmc_driverstats *_gms);
+int pmc_get_msr(pmc_id_t _pmc, uint32_t *_msr);
+int pmc_init(void);
+int pmc_read(pmc_id_t _pmc, pmc_value_t *_value);
+int pmc_release(pmc_id_t _pmc);
+int pmc_rw(pmc_id_t _pmc, pmc_value_t _newvalue, pmc_value_t *_oldvalue);
+int pmc_set(pmc_id_t _pmc, pmc_value_t _value);
+int pmc_start(pmc_id_t _pmc);
+int pmc_stop(pmc_id_t _pmc);
+int pmc_width(pmc_id_t _pmc, uint32_t *_width);
+int pmc_write(pmc_id_t _pmc, pmc_value_t _value);
+int pmc_writelog(uint32_t _udata);
+
+int pmc_ncpu(void);
+int pmc_npmc(int _cpu);
+int pmc_cpuinfo(const struct pmc_cpuinfo **_cpu_info);
+int pmc_pmcinfo(int _cpu, struct pmc_pmcinfo **_pmc_info);
+
+const char *pmc_name_of_capability(uint32_t _c);
+const char *pmc_name_of_class(enum pmc_class _pc);
+const char *pmc_name_of_cputype(enum pmc_cputype _cp);
+const char *pmc_name_of_disposition(enum pmc_disp _pd);
+const char *pmc_name_of_event(enum pmc_event _pe);
+const char *pmc_name_of_mode(enum pmc_mode _pm);
+const char *pmc_name_of_state(enum pmc_state _ps);
+
+int pmc_event_names_of_class(enum pmc_class _cl, const char ***_eventnames,
+ int *_nevents);
+
+#endif
diff --git a/lib/libpmc/pmclog.3 b/lib/libpmc/pmclog.3
new file mode 100644
index 0000000..82674a9
--- /dev/null
+++ b/lib/libpmc/pmclog.3
@@ -0,0 +1,320 @@
+.\" Copyright (c) 2005-2006 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" This software is provided by Joseph Koshy ``as is'' and
+.\" any express or implied warranties, including, but not limited to, the
+.\" implied warranties of merchantability and fitness for a particular purpose
+.\" are disclaimed. in no event shall Joseph Koshy be liable
+.\" for any direct, indirect, incidental, special, exemplary, or consequential
+.\" damages (including, but not limited to, procurement of substitute goods
+.\" or services; loss of use, data, or profits; or business interruption)
+.\" however caused and on any theory of liability, whether in contract, strict
+.\" liability, or tort (including 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 26, 2006
+.Os
+.Dt PMCLOG 3
+.Sh NAME
+.Nm pmclog_open ,
+.Nm pmclog_close ,
+.Nm pmclog_read ,
+.Nm pmclog_feed
+.Nd parse event log data generated by
+.Xr hwpmc 4
+.Sh LIBRARY
+.Lb libpmc
+.Sh SYNOPSIS
+.In pmclog.h
+.Ft "void *"
+.Fn pmclog_open "int fd"
+.Ft void
+.Fn pmclog_close "void *cookie"
+.Ft int
+.Fn pmclog_read "void *cookie" "struct pmclog_ev *ev"
+.Ft int
+.Fn pmclog_feed "void *cookie" "char *data" "int len"
+.Sh DESCRIPTION
+These functions provide a way for application programs to extract
+events from an event stream generated by
+.Xr hwpmc 4 .
+.Pp
+A new event log parser is allocated using
+.Fn pmclog_open .
+Argument
+.Fa fd
+may be a file descriptor opened for reading if the event stream is
+present in a file, or the constant
+.Dv PMCLOG_FD_NONE
+for an event stream present in memory.
+This function returns a cookie that is passed into the other functions
+in this API set.
+.Pp
+Function
+.Fn pmclog_read
+returns the next available event in the event stream associated with
+argument
+.Fa cookie .
+Argument
+.Fa ev
+points to an event descriptor that which will contain the result of a
+successfully parsed event.
+.Pp
+An event descriptor returned by
+.Fn pmclog_read
+has the following structure:
+.Bd -literal
+struct pmclog_ev {
+ enum pmclog_state pl_state; /* parser state after 'get_event()' */
+ off_t pl_offset; /* byte offset in stream */
+ size_t pl_count; /* count of records so far */
+ struct timespec pl_ts; /* log entry timestamp */
+ enum pmclog_type pl_type; /* log entry kind */
+ union { /* log entry data */
+ struct pmclog_ev_closelog pl_cl;
+ struct pmclog_ev_dropnotify pl_d;
+ struct pmclog_ev_initialize pl_i;
+ struct pmclog_ev_map_in pl_mi;
+ struct pmclog_ev_map_out pl_mo;
+ struct pmclog_ev_pcsample pl_s;
+ struct pmclog_ev_pmcallocate pl_a;
+ struct pmclog_ev_pmcattach pl_t;
+ struct pmclog_ev_pmcdetach pl_d;
+ struct pmclog_ev_proccsw pl_c;
+ struct pmclog_ev_procexec pl_x;
+ struct pmclog_ev_procexit pl_e;
+ struct pmclog_ev_procfork pl_f;
+ struct pmclog_ev_sysexit pl_e;
+ struct pmclog_ev_userdata pl_u;
+ } pl_u;
+};
+.Ed
+.Pp
+The current state of the parser is recorded in
+.Va pl_state .
+This field can take on the following values:
+.Bl -tag -width ".Dv PMCLOG_REQUIRE_DATA"
+.It Dv PMCLOG_EOF
+(For file based parsers only)
+An end-of-file condition was encountered on the configured file
+descriptor.
+.It Dv PMCLOG_ERROR
+An error occurred during parsing.
+.It Dv PMCLOG_OK
+A complete event record was read into
+.Fa *ev .
+.It Dv PMCLOG_REQUIRE_DATA
+There was insufficient data in the event stream to assemble a complete
+event record.
+For memory based parsers, more data can be fed to the
+parser using function
+.Fn pmclog_feed .
+For file based parsers, function
+.Fn pmclog_read
+may be retried when data is available on the configured file
+descriptor.
+.El
+.Pp
+The rest of the event structure is valid only if field
+.Va pl_state
+contains
+.Dv PMCLOG_OK .
+Field
+.Va pl_offset
+contains the offset of the current record in the byte stream.
+Field
+.Va pl_count
+contains the serial number of this event.
+Field
+.Va pl_ts
+contains a timestamp with the system time when the event occurred.
+Field
+.Va pl_type
+denotes the kind of the event returned in argument
+.Fa *ev
+and is one of the following:
+.Bl -tag -width ".Dv PMCLOG_TYPE_PMCALLOCATE"
+.It Dv PMCLOG_TYPE_CLOSELOG
+A marker indicating a successful close of a log file.
+This record will be the last record of a log file.
+.It Dv PMCLOG_TYPE_DROPNOTIFY
+A marker indicating that
+.Xr hwpmc 4
+had to drop data due to a resource constraint.
+.It Dv PMCLOG_TYPE_INITIALIZE
+An initialization record.
+This is the first record in a log file.
+.It Dv PMCLOG_TYPE_MAP_IN
+A record describing the introduction of a mapping to an executable
+object by a
+.Xr kldload 2
+or
+.Xr mmap 2
+system call.
+.It Dv PMCLOG_TYPE_MAP_OUT
+A record describing the removal of a mapping to an executable
+object by a
+.Xr kldunload 2
+or
+.Xr munmap 2
+system call.
+.It Dv PMCLOG_TYPE_PCSAMPLE
+A record containing an instruction pointer sample.
+.It Dv PMCLOG_TYPE_PMCALLOCATE
+A record describing a PMC allocation operation.
+.It Dv PMCLOG_TYPE_PMCATTACH
+A record describing a PMC attach operation.
+.It Dv PMCLOG_TYPE_PMCDETACH
+A record describing a PMC detach operation.
+.It Dv PMCLOG_TYPE_PROCCSW
+A record describing a PMC reading at the time of a process context switch.
+.It Dv PMCLOG_TYPE_PROCEXEC
+A record describing an
+.Xr execve 2
+by a target process.
+.It Dv PMCLOG_TYPE_PROCEXIT
+A record describing the accumulated PMC reading for a process at the
+time of
+.Xr _exit 2 .
+.It Dv PMCLOG_TYPE_PROCFORK
+A record describing a
+.Xr fork 2
+by a target process.
+.It Dv PMCLOG_TYPE_SYSEXIT
+A record describing a process exit, sent to processes
+owning system-wide sampling PMCs.
+.It Dv PMCLOG_TYPE_USERDATA
+A record containing user data.
+.El
+.Pp
+Function
+.Fn pmclog_feed
+is used with parsers configured to parse memory based event streams.
+It is intended to be called when function
+.Fn pmclog_read
+indicates the need for more data by a returning
+.Dv PMCLOG_REQUIRE_DATA
+in field
+.Va pl_state
+of its event structure argument.
+Argument
+.Fa data
+points to the start of a memory buffer containing fresh event data.
+Argument
+.Fa len
+indicates the number of data bytes available.
+The memory range
+.Bq Fa data , Fa data No + Fa len
+must remain valid till the next time
+.Fn pmclog_read
+returns an error.
+It is an error to use
+.Fn pmclog_feed
+on a parser configured to parse file data.
+.Pp
+Function
+.Fn pmclog_close
+releases the internal state allocated by a prior call
+to
+.Fn pmclog_open .
+.Sh RETURN VALUES
+Function
+.Fn pmclog_open
+will return a
+.No non- Ns Dv NULL
+value if successful or
+.Dv NULL
+otherwise.
+.Pp
+Function
+.Fn pmclog_read
+will return 0 in case a complete event record was successfully read,
+or will return \-1 and will set the
+.Va pl_state
+field of the event record to the appropriate code in case of an error.
+.Pp
+Function
+.Fn pmclog_feed
+will return 0 on success or \-1 in case of failure.
+.Sh EXAMPLES
+A template for using the log file parsing API is shown below in pseudocode:
+.Bd -literal
+void *parser; /* cookie */
+struct pmclog_ev ev; /* parsed event */
+int fd; /* file descriptor */
+
+fd = open(filename, O_RDONLY); /* open log file */
+parser = pmclog_open(fd); /* initialize parser */
+if (parser == NULL)
+ --handle an out of memory error--;
+
+/* read and parse data */
+while (pmclog_read(parser, &ev) == 0) {
+ assert(ev.pl_state == PMCLOG_OK);
+ /* process the event */
+ switch (ev.pl_type) {
+ case PMCLOG_TYPE_ALLOCATE:
+ --process a pmc allocation record--
+ break;
+ case PMCLOG_TYPE_PROCCSW:
+ --process a thread context switch record--
+ break;
+ case PMCLOG_TYPE_PCSAMPLE:
+ --process a PC sample--
+ break;
+ --and so on--
+ }
+}
+
+/* examine parser state */
+switch (ev.pl_state) {
+case PMCLOG_EOF:
+ --normal termination--
+ break;
+case PMCLOG_ERROR:
+ --look at errno here--
+ break;
+case PMCLOG_REQUIRE_DATA:
+ --arrange for more data to be available for parsing--
+ break;
+default:
+ assert(0);
+ /*NOTREACHED*/
+}
+
+pmclog_close(parser); /* cleanup */
+.Ed
+.Sh ERRORS
+A call to
+.Fn pmclog_init_parser
+may fail with any of the errors returned by
+.Xr malloc 3 .
+.Pp
+A call to
+.Fn pmclog_read
+for a file based parser may fail with any of the errors returned by
+.Xr read 2 .
+.Sh SEE ALSO
+.Xr read 2 ,
+.Xr malloc 3 ,
+.Xr pmc 3 ,
+.Xr hwpmc 4 ,
+.Xr pmcstat 8
+.Sh HISTORY
+The
+.Nm pmclog
+API
+.Ud
+It first appeared in
+.Fx 6.0 .
diff --git a/lib/libpmc/pmclog.c b/lib/libpmc/pmclog.c
new file mode 100644
index 0000000..fcd4a4f
--- /dev/null
+++ b/lib/libpmc/pmclog.c
@@ -0,0 +1,553 @@
+/*-
+ * Copyright (c) 2005-2006 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 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/pmc.h>
+#include <sys/pmclog.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <pmc.h>
+#include <pmclog.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+
+#include <machine/pmc_mdep.h>
+
+#define PMCLOG_BUFFER_SIZE 4096
+
+/*
+ * API NOTES
+ *
+ * The pmclog(3) API is oriented towards parsing an event stream in
+ * "realtime", i.e., from an data source that may or may not preserve
+ * record boundaries -- for example when the data source is elsewhere
+ * on a network. The API allows data to be fed into the parser zero
+ * or more bytes at a time.
+ *
+ * The state for a log file parser is maintained in a 'struct
+ * pmclog_parse_state'. Parser invocations are done by calling
+ * 'pmclog_read()'; this function will inform the caller when a
+ * complete event is parsed.
+ *
+ * The parser first assembles a complete log file event in an internal
+ * work area (see "ps_saved" below). Once a complete log file event
+ * is read, the parser then parses it and converts it to an event
+ * descriptor usable by the client. We could possibly avoid this two
+ * step process by directly parsing the input log to set fields in the
+ * event record. However the parser's state machine would get
+ * insanely complicated, and this code is unlikely to be used in
+ * performance critical paths.
+ */
+
+enum pmclog_parser_state {
+ PL_STATE_NEW_RECORD, /* in-between records */
+ PL_STATE_EXPECTING_HEADER, /* header being read */
+ PL_STATE_PARTIAL_RECORD, /* header present but not the record */
+ PL_STATE_ERROR /* parsing error encountered */
+};
+
+struct pmclog_parse_state {
+ enum pmclog_parser_state ps_state;
+ enum pmc_cputype ps_arch; /* log file architecture */
+ uint32_t ps_version; /* hwpmc version */
+ int ps_initialized; /* whether initialized */
+ int ps_count; /* count of records processed */
+ off_t ps_offset; /* stream byte offset */
+ union pmclog_entry ps_saved; /* saved partial log entry */
+ int ps_svcount; /* #bytes saved */
+ int ps_fd; /* active fd or -1 */
+ char *ps_buffer; /* scratch buffer if fd != -1 */
+ char *ps_data; /* current parse pointer */
+ size_t ps_len; /* length of buffered data */
+};
+
+#define PMCLOG_HEADER_FROM_SAVED_STATE(PS) \
+ (* ((uint32_t *) &(PS)->ps_saved))
+
+#define PMCLOG_INITIALIZE_READER(LE,A) LE = (uint32_t *) &(A)
+#define PMCLOG_READ32(LE,V) do { \
+ (V) = *(LE)++; \
+ } while (0)
+#define PMCLOG_READ64(LE,V) do { \
+ uint64_t _v; \
+ _v = (uint64_t) *(LE)++; \
+ _v |= ((uint64_t) *(LE)++) << 32; \
+ (V) = _v; \
+ } while (0)
+
+#define PMCLOG_READSTRING(LE,DST,LEN) strlcpy((DST), (char *) (LE), (LEN))
+
+/*
+ * Assemble a log record from '*len' octets starting from address '*data'.
+ * Update 'data' and 'len' to reflect the number of bytes consumed.
+ *
+ * '*data' is potentially an unaligned address and '*len' octets may
+ * not be enough to complete a event record.
+ */
+
+static enum pmclog_parser_state
+pmclog_get_record(struct pmclog_parse_state *ps, char **data, ssize_t *len)
+{
+ int avail, copylen, recordsize, used;
+ uint32_t h;
+ const int HEADERSIZE = sizeof(uint32_t);
+ char *src, *dst;
+
+ if ((avail = *len) <= 0)
+ return (ps->ps_state = PL_STATE_ERROR);
+
+ src = *data;
+ h = used = 0;
+
+ if (ps->ps_state == PL_STATE_NEW_RECORD)
+ ps->ps_svcount = 0;
+
+ dst = (char *) &ps->ps_saved + ps->ps_svcount;
+
+ switch (ps->ps_state) {
+ case PL_STATE_NEW_RECORD:
+
+ /*
+ * Transitions:
+ *
+ * Case A: avail < headersize
+ * -> 'expecting header'
+ *
+ * Case B: avail >= headersize
+ * B.1: avail < recordsize
+ * -> 'partial record'
+ * B.2: avail >= recordsize
+ * -> 'new record'
+ */
+
+ copylen = avail < HEADERSIZE ? avail : HEADERSIZE;
+ bcopy(src, dst, copylen);
+ ps->ps_svcount = used = copylen;
+
+ if (copylen < HEADERSIZE) {
+ ps->ps_state = PL_STATE_EXPECTING_HEADER;
+ goto done;
+ }
+
+ src += copylen;
+ dst += copylen;
+
+ h = PMCLOG_HEADER_FROM_SAVED_STATE(ps);
+ recordsize = PMCLOG_HEADER_TO_LENGTH(h);
+
+ if (recordsize <= 0)
+ goto error;
+
+ if (recordsize <= avail) { /* full record available */
+ bcopy(src, dst, recordsize - copylen);
+ ps->ps_svcount = used = recordsize;
+ goto done;
+ }
+
+ /* header + a partial record is available */
+ bcopy(src, dst, avail - copylen);
+ ps->ps_svcount = used = avail;
+ ps->ps_state = PL_STATE_PARTIAL_RECORD;
+
+ break;
+
+ case PL_STATE_EXPECTING_HEADER:
+
+ /*
+ * Transitions:
+ *
+ * Case C: avail+saved < headersize
+ * -> 'expecting header'
+ *
+ * Case D: avail+saved >= headersize
+ * D.1: avail+saved < recordsize
+ * -> 'partial record'
+ * D.2: avail+saved >= recordsize
+ * -> 'new record'
+ * (see PARTIAL_RECORD handling below)
+ */
+
+ if (avail + ps->ps_svcount < HEADERSIZE) {
+ bcopy(src, dst, avail);
+ ps->ps_svcount += avail;
+ used = avail;
+ break;
+ }
+
+ used = copylen = HEADERSIZE - ps->ps_svcount;
+ bcopy(src, dst, copylen);
+ src += copylen;
+ dst += copylen;
+ avail -= copylen;
+ ps->ps_svcount += copylen;
+
+ /*FALLTHROUGH*/
+
+ case PL_STATE_PARTIAL_RECORD:
+
+ /*
+ * Transitions:
+ *
+ * Case E: avail+saved < recordsize
+ * -> 'partial record'
+ *
+ * Case F: avail+saved >= recordsize
+ * -> 'new record'
+ */
+
+ h = PMCLOG_HEADER_FROM_SAVED_STATE(ps);
+ recordsize = PMCLOG_HEADER_TO_LENGTH(h);
+
+ if (recordsize <= 0)
+ goto error;
+
+ if (avail + ps->ps_svcount < recordsize) {
+ copylen = avail;
+ ps->ps_state = PL_STATE_PARTIAL_RECORD;
+ } else {
+ copylen = recordsize - ps->ps_svcount;
+ ps->ps_state = PL_STATE_NEW_RECORD;
+ }
+
+ bcopy(src, dst, copylen);
+ ps->ps_svcount += copylen;
+ used += copylen;
+ break;
+
+ default:
+ goto error;
+ }
+
+ done:
+ *data += used;
+ *len -= used;
+ return ps->ps_state;
+
+ error:
+ ps->ps_state = PL_STATE_ERROR;
+ return ps->ps_state;
+}
+
+/*
+ * Get an event from the stream pointed to by '*data'. '*len'
+ * indicates the number of bytes available to parse. Arguments
+ * '*data' and '*len' are updated to indicate the number of bytes
+ * consumed.
+ */
+
+static int
+pmclog_get_event(void *cookie, char **data, ssize_t *len,
+ struct pmclog_ev *ev)
+{
+ int evlen, pathlen;
+ uint32_t h, *le;
+ enum pmclog_parser_state e;
+ struct pmclog_parse_state *ps;
+
+ ps = (struct pmclog_parse_state *) cookie;
+
+ assert(ps->ps_state != PL_STATE_ERROR);
+
+ if ((e = pmclog_get_record(ps,data,len)) == PL_STATE_ERROR) {
+ ev->pl_state = PMCLOG_ERROR;
+ return -1;
+ }
+
+ if (e != PL_STATE_NEW_RECORD) {
+ ev->pl_state = PMCLOG_REQUIRE_DATA;
+ return -1;
+ }
+
+ PMCLOG_INITIALIZE_READER(le, ps->ps_saved);
+
+ PMCLOG_READ32(le,h);
+
+ if (!PMCLOG_HEADER_CHECK_MAGIC(h)) {
+ ps->ps_state = PL_STATE_ERROR;
+ ev->pl_state = PMCLOG_ERROR;
+ return -1;
+ }
+
+ /* copy out the time stamp */
+ PMCLOG_READ32(le,ev->pl_ts.tv_sec);
+ PMCLOG_READ32(le,ev->pl_ts.tv_nsec);
+
+ evlen = PMCLOG_HEADER_TO_LENGTH(h);
+
+#define PMCLOG_GET_PATHLEN(P,E,TYPE) do { \
+ (P) = (E) - offsetof(struct TYPE, pl_pathname); \
+ if ((P) > PATH_MAX || (P) < 0) \
+ goto error; \
+ } while (0)
+
+ switch (ev->pl_type = PMCLOG_HEADER_TO_TYPE(h)) {
+ case PMCLOG_TYPE_CLOSELOG:
+ case PMCLOG_TYPE_DROPNOTIFY:
+ /* nothing to do */
+ break;
+ case PMCLOG_TYPE_INITIALIZE:
+ PMCLOG_READ32(le,ev->pl_u.pl_i.pl_version);
+ PMCLOG_READ32(le,ev->pl_u.pl_i.pl_arch);
+ ps->ps_version = ev->pl_u.pl_i.pl_version;
+ ps->ps_arch = ev->pl_u.pl_i.pl_arch;
+ ps->ps_initialized = 1;
+ break;
+ case PMCLOG_TYPE_MAP_IN:
+ PMCLOG_GET_PATHLEN(pathlen,evlen,pmclog_map_in);
+ PMCLOG_READ32(le,ev->pl_u.pl_mi.pl_pid);
+ PMCLOG_READADDR(le,ev->pl_u.pl_mi.pl_start);
+ PMCLOG_READSTRING(le, ev->pl_u.pl_mi.pl_pathname, pathlen);
+ break;
+ case PMCLOG_TYPE_MAP_OUT:
+ PMCLOG_READ32(le,ev->pl_u.pl_mo.pl_pid);
+ PMCLOG_READADDR(le,ev->pl_u.pl_mo.pl_start);
+ PMCLOG_READADDR(le,ev->pl_u.pl_mo.pl_end);
+ break;
+ case PMCLOG_TYPE_PCSAMPLE:
+ PMCLOG_READ32(le,ev->pl_u.pl_s.pl_pid);
+ PMCLOG_READADDR(le,ev->pl_u.pl_s.pl_pc);
+ PMCLOG_READ32(le,ev->pl_u.pl_s.pl_pmcid);
+ PMCLOG_READ32(le,ev->pl_u.pl_s.pl_usermode);
+ break;
+ case PMCLOG_TYPE_PMCALLOCATE:
+ PMCLOG_READ32(le,ev->pl_u.pl_a.pl_pmcid);
+ PMCLOG_READ32(le,ev->pl_u.pl_a.pl_event);
+ PMCLOG_READ32(le,ev->pl_u.pl_a.pl_flags);
+ if ((ev->pl_u.pl_a.pl_evname =
+ pmc_name_of_event(ev->pl_u.pl_a.pl_event)) == NULL)
+ goto error;
+ break;
+ case PMCLOG_TYPE_PMCATTACH:
+ PMCLOG_GET_PATHLEN(pathlen,evlen,pmclog_pmcattach);
+ PMCLOG_READ32(le,ev->pl_u.pl_t.pl_pmcid);
+ PMCLOG_READ32(le,ev->pl_u.pl_t.pl_pid);
+ PMCLOG_READSTRING(le,ev->pl_u.pl_t.pl_pathname,pathlen);
+ break;
+ case PMCLOG_TYPE_PMCDETACH:
+ PMCLOG_READ32(le,ev->pl_u.pl_d.pl_pmcid);
+ PMCLOG_READ32(le,ev->pl_u.pl_d.pl_pid);
+ break;
+ case PMCLOG_TYPE_PROCCSW:
+ PMCLOG_READ32(le,ev->pl_u.pl_c.pl_pmcid);
+ PMCLOG_READ64(le,ev->pl_u.pl_c.pl_value);
+ PMCLOG_READ32(le,ev->pl_u.pl_c.pl_pid);
+ break;
+ case PMCLOG_TYPE_PROCEXEC:
+ PMCLOG_GET_PATHLEN(pathlen,evlen,pmclog_procexec);
+ PMCLOG_READ32(le,ev->pl_u.pl_x.pl_pid);
+ PMCLOG_READADDR(le,ev->pl_u.pl_x.pl_entryaddr);
+ PMCLOG_READ32(le,ev->pl_u.pl_x.pl_pmcid);
+ PMCLOG_READSTRING(le,ev->pl_u.pl_x.pl_pathname,pathlen);
+ break;
+ case PMCLOG_TYPE_PROCEXIT:
+ PMCLOG_READ32(le,ev->pl_u.pl_e.pl_pmcid);
+ PMCLOG_READ64(le,ev->pl_u.pl_e.pl_value);
+ PMCLOG_READ32(le,ev->pl_u.pl_e.pl_pid);
+ break;
+ case PMCLOG_TYPE_PROCFORK:
+ PMCLOG_READ32(le,ev->pl_u.pl_f.pl_oldpid);
+ PMCLOG_READ32(le,ev->pl_u.pl_f.pl_newpid);
+ break;
+ case PMCLOG_TYPE_SYSEXIT:
+ PMCLOG_READ32(le,ev->pl_u.pl_se.pl_pid);
+ break;
+ case PMCLOG_TYPE_USERDATA:
+ PMCLOG_READ32(le,ev->pl_u.pl_u.pl_userdata);
+ break;
+ default: /* unknown record type */
+ ps->ps_state = PL_STATE_ERROR;
+ ev->pl_state = PMCLOG_ERROR;
+ return -1;
+ }
+
+ ev->pl_offset = (ps->ps_offset += evlen);
+ ev->pl_count = (ps->ps_count += 1);
+ ev->pl_state = PMCLOG_OK;
+ return 0;
+
+ error:
+ ev->pl_state = PMCLOG_ERROR;
+ ps->ps_state = PL_STATE_ERROR;
+ return -1;
+}
+
+/*
+ * Extract and return the next event from the byte stream.
+ *
+ * Returns 0 and sets the event's state to PMCLOG_OK in case an event
+ * was successfully parsed. Otherwise this function returns -1 and
+ * sets the event's state to one of PMCLOG_REQUIRE_DATA (if more data
+ * is needed) or PMCLOG_EOF (if an EOF was seen) or PMCLOG_ERROR if
+ * a parse error was encountered.
+ */
+
+int
+pmclog_read(void *cookie, struct pmclog_ev *ev)
+{
+ int retval;
+ ssize_t nread;
+ struct pmclog_parse_state *ps;
+
+ ps = (struct pmclog_parse_state *) cookie;
+
+ if (ps->ps_state == PL_STATE_ERROR) {
+ ev->pl_state = PMCLOG_ERROR;
+ return -1;
+ }
+
+ /*
+ * If there isn't enough data left for a new event try and get
+ * more data.
+ */
+ if (ps->ps_len == 0) {
+ ev->pl_state = PMCLOG_REQUIRE_DATA;
+
+ /*
+ * If we have a valid file descriptor to read from, attempt
+ * to read from that. This read may return with an error,
+ * (which may be EAGAIN or other recoverable error), or
+ * can return EOF.
+ */
+ if (ps->ps_fd != PMCLOG_FD_NONE) {
+ refill:
+ nread = read(ps->ps_fd, ps->ps_buffer,
+ PMCLOG_BUFFER_SIZE);
+
+ if (nread <= 0) {
+ if (nread == 0)
+ ev->pl_state = PMCLOG_EOF;
+ else if (errno != EAGAIN) /* not restartable */
+ ev->pl_state = PMCLOG_ERROR;
+ return -1;
+ }
+
+ ps->ps_len = nread;
+ ps->ps_data = ps->ps_buffer;
+ } else
+ return -1;
+ }
+
+ assert(ps->ps_len > 0);
+
+
+ /* Retrieve one event from the byte stream. */
+ retval = pmclog_get_event(ps, &ps->ps_data, &ps->ps_len, ev);
+
+ /*
+ * If we need more data and we have a configured fd, try read
+ * from it.
+ */
+ if (retval < 0 && ev->pl_state == PMCLOG_REQUIRE_DATA &&
+ ps->ps_fd != -1) {
+ assert(ps->ps_len == 0);
+ goto refill;
+ }
+
+ return retval;
+}
+
+/*
+ * Feed data to a memory based parser.
+ *
+ * The memory area pointed to by 'data' needs to be valid till the
+ * next error return from pmclog_next_event().
+ */
+
+int
+pmclog_feed(void *cookie, char *data, int len)
+{
+ struct pmclog_parse_state *ps;
+
+ ps = (struct pmclog_parse_state *) cookie;
+
+ if (len < 0 || /* invalid length */
+ ps->ps_buffer || /* called for a file parser */
+ ps->ps_len != 0) /* unnecessary call */
+ return -1;
+
+ ps->ps_data = data;
+ ps->ps_len = len;
+
+ return 0;
+}
+
+/*
+ * Allocate and initialize parser state.
+ */
+
+void *
+pmclog_open(int fd)
+{
+ struct pmclog_parse_state *ps;
+
+ if ((ps = (struct pmclog_parse_state *) malloc(sizeof(*ps))) == NULL)
+ return NULL;
+
+ ps->ps_state = PL_STATE_NEW_RECORD;
+ ps->ps_arch = -1;
+ ps->ps_initialized = 0;
+ ps->ps_count = 0;
+ ps->ps_offset = (off_t) 0;
+ bzero(&ps->ps_saved, sizeof(ps->ps_saved));
+ ps->ps_svcount = 0;
+ ps->ps_fd = fd;
+ ps->ps_data = NULL;
+ ps->ps_buffer = NULL;
+ ps->ps_len = 0;
+
+ /* allocate space for a work area */
+ if (ps->ps_fd != PMCLOG_FD_NONE) {
+ if ((ps->ps_buffer = malloc(PMCLOG_BUFFER_SIZE)) == NULL)
+ return NULL;
+ }
+
+ return ps;
+}
+
+
+/*
+ * Free up parser state.
+ */
+
+void
+pmclog_close(void *cookie)
+{
+ struct pmclog_parse_state *ps;
+
+ ps = (struct pmclog_parse_state *) cookie;
+
+ if (ps->ps_buffer)
+ free(ps->ps_buffer);
+
+ free(ps);
+}
diff --git a/lib/libpmc/pmclog.h b/lib/libpmc/pmclog.h
new file mode 100644
index 0000000..90fb193
--- /dev/null
+++ b/lib/libpmc/pmclog.h
@@ -0,0 +1,154 @@
+/*-
+ * Copyright (c) 2005-2006 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 _PMCLOG_H_
+#define _PMCLOG_H_
+
+#include <sys/pmclog.h>
+
+enum pmclog_state {
+ PMCLOG_OK,
+ PMCLOG_EOF,
+ PMCLOG_REQUIRE_DATA,
+ PMCLOG_ERROR
+};
+
+struct pmclog_ev_dropnotify {
+};
+
+struct pmclog_ev_closelog {
+};
+
+struct pmclog_ev_initialize {
+ uint32_t pl_version;
+ uint32_t pl_arch;
+};
+
+struct pmclog_ev_map_in {
+ pid_t pl_pid;
+ uintfptr_t pl_start;
+ char pl_pathname[PATH_MAX];
+};
+
+struct pmclog_ev_map_out {
+ pid_t pl_pid;
+ uintfptr_t pl_start;
+ uintfptr_t pl_end;
+};
+
+struct pmclog_ev_pcsample {
+ uintfptr_t pl_pc;
+ pid_t pl_pid;
+ pmc_id_t pl_pmcid;
+ uint32_t pl_usermode;
+};
+
+struct pmclog_ev_pmcallocate {
+ uint32_t pl_event;
+ const char * pl_evname;
+ uint32_t pl_flags;
+ pmc_id_t pl_pmcid;
+};
+
+struct pmclog_ev_pmcattach {
+ pmc_id_t pl_pmcid;
+ pid_t pl_pid;
+ char pl_pathname[PATH_MAX];
+};
+
+struct pmclog_ev_pmcdetach {
+ pmc_id_t pl_pmcid;
+ pid_t pl_pid;
+};
+
+struct pmclog_ev_proccsw {
+ pid_t pl_pid;
+ pmc_id_t pl_pmcid;
+ pmc_value_t pl_value;
+};
+
+struct pmclog_ev_procexec {
+ pid_t pl_pid;
+ pmc_id_t pl_pmcid;
+ uintfptr_t pl_entryaddr;
+ char pl_pathname[PATH_MAX];
+};
+
+struct pmclog_ev_procexit {
+ uint32_t pl_pid;
+ pmc_id_t pl_pmcid;
+ pmc_value_t pl_value;
+};
+
+struct pmclog_ev_procfork {
+ pid_t pl_oldpid;
+ pid_t pl_newpid;
+};
+
+struct pmclog_ev_sysexit {
+ pid_t pl_pid;
+};
+
+struct pmclog_ev_userdata {
+ uint32_t pl_userdata;
+};
+
+struct pmclog_ev {
+ enum pmclog_state pl_state; /* state after 'get_event()' */
+ off_t pl_offset; /* byte offset in stream */
+ size_t pl_count; /* count of records so far */
+ struct timespec pl_ts; /* log entry timestamp */
+ enum pmclog_type pl_type; /* type of log entry */
+ union { /* log entry data */
+ struct pmclog_ev_closelog pl_cl;
+ struct pmclog_ev_dropnotify pl_dn;
+ struct pmclog_ev_initialize pl_i;
+ struct pmclog_ev_map_in pl_mi;
+ struct pmclog_ev_map_out pl_mo;
+ struct pmclog_ev_pcsample pl_s;
+ struct pmclog_ev_pmcallocate pl_a;
+ struct pmclog_ev_pmcattach pl_t;
+ struct pmclog_ev_pmcdetach pl_d;
+ struct pmclog_ev_proccsw pl_c;
+ struct pmclog_ev_procexec pl_x;
+ struct pmclog_ev_procexit pl_e;
+ struct pmclog_ev_procfork pl_f;
+ struct pmclog_ev_sysexit pl_se;
+ struct pmclog_ev_userdata pl_u;
+ } pl_u;
+};
+
+#define PMCLOG_FD_NONE (-1)
+
+void *pmclog_open(int _fd);
+int pmclog_feed(void *_cookie, char *_data, int _len);
+int pmclog_read(void *_cookie, struct pmclog_ev *_ev);
+void pmclog_close(void *_cookie);
+
+#endif
+
diff --git a/lib/libpthread/Makefile b/lib/libpthread/Makefile
new file mode 100644
index 0000000..17b46b9
--- /dev/null
+++ b/lib/libpthread/Makefile
@@ -0,0 +1,54 @@
+# $FreeBSD$
+#
+# 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 included legacy CSRG sccsid strings, add -DLIBC_SCCS and -DSYSLIBC_SCCS
+# (for system call stubs) to CFLAGS below. -DSYSLIBC_SCCS affects just the
+# system call stubs.
+.if ${MACHINE_ARCH} == "alpha" || ${MACHINE_ARCH} == "sparc64"
+LIB=kse
+.else
+LIB=pthread
+SHLIBDIR?= /lib
+.endif
+SHLIB_MAJOR= 2
+CFLAGS+=-DPTHREAD_KERNEL
+CFLAGS+=-I${.CURDIR}/../libc/include -I${.CURDIR}/thread \
+ -I${.CURDIR}/../../include
+CFLAGS+=-I${.CURDIR}/arch/${MACHINE_ARCH}/include
+CFLAGS+=-I${.CURDIR}/sys
+CFLAGS+=-I${.CURDIR}/../../libexec/rtld-elf
+CFLAGS+=-I${.CURDIR}/../../libexec/rtld-elf/${MACHINE_ARCH}
+CFLAGS+=-fno-builtin
+
+# Uncomment this if you want libpthread to contain debug information for
+# thread locking.
+CFLAGS+=-D_LOCK_DEBUG
+WARNS?=2
+
+# Uncomment this if you want to build a 1:1 threading mode library
+# however it is no longer strictly conformed to POSIX
+# CFLAGS+=-DSYSTEM_SCOPE_ONLY
+
+# Enable extra internal consistancy checks.
+CFLAGS+=-D_PTHREADS_INVARIANTS -Wall
+
+VERSION_MAP=${.CURDIR}/pthread.map
+
+.if defined(SYMVER_ENABLED)
+# Remove this if library version is bumped and LIBPTHREAD_1_0
+# compatability hacks are removed (see thread/thr_private.h).
+LDFLAGS+=-Wl,-zmuldefs
+CFLAGS+=-DSYMBOL_VERSIONING
+.endif
+
+PRECIOUSLIB=
+
+.include "${.CURDIR}/arch/${MACHINE_ARCH}/Makefile.inc"
+.include "${.CURDIR}/support/Makefile.inc"
+.include "${.CURDIR}/sys/Makefile.inc"
+.include "${.CURDIR}/thread/Makefile.inc"
+
+.include <bsd.lib.mk>
diff --git a/lib/libpthread/arch/alpha/Makefile.inc b/lib/libpthread/arch/alpha/Makefile.inc
new file mode 100644
index 0000000..7bb3ad9
--- /dev/null
+++ b/lib/libpthread/arch/alpha/Makefile.inc
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}/${MACHINE_ARCH}
+
+SRCS+= enter_uts.S context.S pthread_md.c
diff --git a/lib/libpthread/arch/alpha/alpha/context.S b/lib/libpthread/arch/alpha/alpha/context.S
new file mode 100644
index 0000000..6ef42b6
--- /dev/null
+++ b/lib/libpthread/arch/alpha/alpha/context.S
@@ -0,0 +1,353 @@
+/*
+ * Copyright (c) 2001,3 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.
+ */
+/*
+ * Copyright (c) 1994, 1995 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ *
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/* #include <machine/frame.h> */
+#define FRAME_V0 0
+#define FRAME_T0 1
+#define FRAME_T1 2
+#define FRAME_T2 3
+#define FRAME_T3 4
+#define FRAME_T4 5
+#define FRAME_T5 6
+#define FRAME_T6 7
+#define FRAME_T7 8
+#define FRAME_S0 9
+#define FRAME_S1 10
+#define FRAME_S2 11
+#define FRAME_S3 12
+#define FRAME_S4 13
+#define FRAME_S5 14
+#define FRAME_S6 15
+#define FRAME_A3 16
+#define FRAME_A4 17
+#define FRAME_A5 18
+#define FRAME_RA 23
+#define FRAME_T12 24
+#define FRAME_AT 25
+#define FRAME_SP 26
+#define FRAME_TRAPARG_A0 28
+#define FRAME_TRAPARG_A1 29
+#define FRAME_TRAPARG_A2 30
+#define FRAME_PC (FRAME_TRAPARG_A2 + 1 + 1)
+
+/* #include <machine/reg.h> */
+#define R_V0 0
+#define R_T0 1
+#define R_T1 2
+#define R_T2 3
+#define R_T3 4
+#define R_T4 5
+#define R_T5 6
+#define R_T6 7
+#define R_T7 8
+#define R_S0 9
+#define R_S1 10
+#define R_S2 11
+#define R_S3 12
+#define R_S4 13
+#define R_S5 14
+#define R_S6 15
+#define R_A0 16
+#define R_A1 17
+#define R_A2 18
+#define R_A3 19
+#define R_A4 20
+#define R_A5 21
+#define R_T8 22
+#define R_T9 23
+#define R_T10 24
+#define R_T11 25
+#define R_RA 26
+#define R_T12 27
+#define R_SP 30
+#define R_ZERO 31
+
+/*
+ * XXX - The rev id's are defined in <machine/ucontext.h>
+ */
+#define MC_FMT_OFFSET 73*8 /* offset to format from mcontext */
+#define REV0_SIGFRAME 0x0001 /* rev R0 sigcontext format */
+#define REV0_TRAPFRAME 0x0002 /* rev R0 trapframe format */
+
+/*
+ * int _alpha_restore_context(const mcontext_t *mcp,
+ * intptr_t val, intptr_t *loc);
+ *
+ * The format of the context is verified at the beginning.
+ * Returns -1 if invalid format.
+ */
+ .set noreorder
+LEAF(_alpha_restore_context, 3)
+ LDGP(pv)
+ bne a0, Lsc1 /* argument null? */
+Lscbad: ldiq v0, -1 /* return -1 */
+ br Lscend
+Lsc1: ldq t1, MC_FMT_OFFSET(a0) /* is mcontext valid format? */
+ ldiq t0, REV0_TRAPFRAME
+ cmpeq t0, t1, t0 /* is it trapframe format? */
+ bne t0, Lsc_fp /* if so, check fp state */
+ ldiq t0, REV0_SIGFRAME
+ cmpeq t0, t1, t0 /* is it sigcontext format? */
+ beq t0, Lscbad
+ /* supposedly sigcontext format, check magic number */
+ ldiq t0, 0xACEDBADE /* check magic number */
+ ldq t1, ((R_ZERO + 1) * 8)(a0) /* magic in mc_regs[R_ZERO] */
+ cmpeq t0, t1, t0
+ beq t0, Lscbad
+ /* restore floating point regs first */
+Lsc_fp: ldq t0, ((71 + 1) * 8)(a0) /* if FP regs not saved, */
+ beq t0, Lsc2 /* skip setting FP regs */
+ ldt $f0, ((37 + 1) * 8)(a0) /* restore FP regs using */
+ ldt $f1, ((38 + 1) * 8)(a0) /* hw name */
+ ldt $f2, ((39 + 1) * 8)(a0)
+ ldt $f3, ((40 + 1) * 8)(a0)
+ ldt $f4, ((41 + 1) * 8)(a0)
+ ldt $f5, ((42 + 1) * 8)(a0)
+ ldt $f6, ((43 + 1) * 8)(a0)
+ ldt $f7, ((44 + 1) * 8)(a0)
+ ldt $f8, ((45 + 1) * 8)(a0)
+ ldt $f9, ((46 + 1) * 8)(a0)
+ ldt $f10, ((47 + 1) * 8)(a0)
+ ldt $f11, ((48 + 1) * 8)(a0)
+ ldt $f12, ((49 + 1) * 8)(a0)
+ ldt $f13, ((50 + 1) * 8)(a0)
+ ldt $f14, ((51 + 1) * 8)(a0)
+ ldt $f15, ((52 + 1) * 8)(a0)
+ ldt $f16, ((53 + 1) * 8)(a0)
+ ldt $f17, ((54 + 1) * 8)(a0)
+ ldt $f18, ((55 + 1) * 8)(a0)
+ ldt $f19, ((56 + 1) * 8)(a0)
+ ldt $f20, ((57 + 1) * 8)(a0)
+ ldt $f21, ((58 + 1) * 8)(a0)
+ ldt $f22, ((59 + 1) * 8)(a0)
+ ldt $f23, ((60 + 1) * 8)(a0)
+ ldt $f24, ((61 + 1) * 8)(a0)
+ ldt $f25, ((62 + 1) * 8)(a0)
+ ldt $f26, ((63 + 1) * 8)(a0)
+ ldt $f27, ((64 + 1) * 8)(a0)
+ .set noat
+ ldt $f28, ((65 + 1) * 8)(a0)
+ .set at
+ ldt $f29, ((66 + 1) * 8)(a0)
+ ldt $f30, ((67 + 1) * 8)(a0)
+ /* $f31 is hardwired zero */
+ ldt ft0, ((69 + 1) * 8)(a0) /* restore FP control reg */
+ mt_fpcr ft0
+Lsc2: ldiq t0, REV0_SIGFRAME /* check the context format */
+ ldq t1, MC_FMT_OFFSET(a0) /* again. */
+ cmpeq t0, t1, t0 /* is it sigcontext format? */
+ bne t0, Lsc_sc
+ /* trapframe format */
+ ldq v0, ((FRAME_V0 + 1) * 8)(a0) /* restore v0 */
+ ldq t0, ((FRAME_T0 + 1) * 8)(a0) /* restore t0-t7 */
+ ldq t1, ((FRAME_T1 + 1) * 8)(a0)
+ ldq t2, ((FRAME_T2 + 1) * 8)(a0)
+ ldq t3, ((FRAME_T3 + 1) * 8)(a0)
+ ldq t4, ((FRAME_T4 + 1) * 8)(a0)
+ ldq t5, ((FRAME_T5 + 1) * 8)(a0)
+ ldq t6, ((FRAME_T6 + 1) * 8)(a0)
+ ldq t7, ((FRAME_T7 + 1) * 8)(a0)
+ ldq s0, ((FRAME_S0 + 1) * 8)(a0) /* restore s0-s6 */
+ ldq s1, ((FRAME_S1 + 1) * 8)(a0)
+ ldq s2, ((FRAME_S2 + 1) * 8)(a0)
+ ldq s3, ((FRAME_S3 + 1) * 8)(a0)
+ ldq s4, ((FRAME_S4 + 1) * 8)(a0)
+ ldq s5, ((FRAME_S5 + 1) * 8)(a0)
+ ldq s6, ((FRAME_S6 + 1) * 8)(a0)
+ ldq a4, ((FRAME_A4 + 1) * 8)(a0) /* restore a4, a5 */
+ ldq a5, ((FRAME_A5 + 1) * 8)(a0)
+ ldq ra, ((FRAME_RA + 1) * 8)(a0)
+ ldq sp, ((FRAME_SP + 1) * 8)(a0)
+ subq sp, 16, sp /* save room on stack */
+ ldq a3, ((FRAME_TRAPARG_A1 + 1) * 8)(a0)
+ stq a3, 0(a0) /* save a1 on stack */
+ ldq a3, ((FRAME_TRAPARG_A2 + 1) * 8)(a0)
+ stq a3, 8(a0) /* save a2 on stack */
+ .set noat
+ ldq at_reg, ((FRAME_PC + 1) * 8)(a0) /* PC at time of trap? */
+ .set at
+ ldq a3, ((FRAME_A3 + 1) * 8)(a0) /* restore a3 */
+ ldq a0, ((FRAME_TRAPARG_A0 + 1) * 8)(a0) /* restore a0 */
+ br Lsc3
+Lsc_sc: /* sigcontext format */
+ ldq v0, ((R_V0 + 1) * 8)(a0) /* restore v0 */
+ ldq t0, ((R_T0 + 1) * 8)(a0) /* restore t0-t7 */
+ ldq t1, ((R_T1 + 1) * 8)(a0)
+ ldq t2, ((R_T2 + 1) * 8)(a0)
+ ldq t3, ((R_T3 + 1) * 8)(a0)
+ ldq t4, ((R_T4 + 1) * 8)(a0)
+ ldq t5, ((R_T5 + 1) * 8)(a0)
+ ldq t6, ((R_T6 + 1) * 8)(a0)
+ ldq t7, ((R_T7 + 1) * 8)(a0)
+ ldq s0, ((R_S0 + 1) * 8)(a0) /* restore s0-s6 */
+ ldq s1, ((R_S1 + 1) * 8)(a0)
+ ldq s2, ((R_S2 + 1) * 8)(a0)
+ ldq s3, ((R_S3 + 1) * 8)(a0)
+ ldq s4, ((R_S4 + 1) * 8)(a0)
+ ldq s5, ((R_S5 + 1) * 8)(a0)
+ ldq s6, ((R_S6 + 1) * 8)(a0)
+ ldq a4, ((R_A4 + 1) * 8)(a0) /* restore a4, a5 */
+ ldq a5, ((R_A5 + 1) * 8)(a0)
+ ldq ra, ((R_RA + 1) * 8)(a0)
+ ldq sp, ((R_SP + 1) * 8)(a0)
+ subq sp, 16, sp /* save room on stack */
+ ldq a3, ((R_A1 + 1) * 8)(a0) /* get a1 */
+ stq a3, 0(a0) /* save a1 on stack */
+ ldq a3, ((R_A2 + 1) * 8)(a0) /* get a2 */
+ stq a3, 8(a0) /* save a2 on stack */
+ ldq a3, ((R_A3 + 1) * 8)(a0) /* restore a3 */
+ ldq a0, ((R_A0 + 1) * 8)(a0) /* restore a0 */
+Lsc3: beq a2, Lsc4
+ stq a1, 0(a2)
+Lsc4: ldq a1, 0(sp) /* restore a1, a2 */
+ ldq a2, 8(sp)
+ addq sp, 16, sp /* restore stack */
+Lscend: RET
+END(_alpha_restore_context)
+
+
+/*
+ * int _alpha_save_context(mcontext_t *);
+ *
+ * Always save in trapframe format. Floating point registers are
+ * saved but may be optimized away later (see comments below).
+ */
+LEAF(_alpha_save_context, 1)
+ LDGP(pv)
+ bne a0, Lgc1 /* argument null? */
+ ldiq v0, -1 /* return -1 */
+ br Lgcend
+Lgc1: ldiq v0, 1 /* save_context returns 1, */
+ stq v0, ((FRAME_V0 + 1) * 8)(a0) /* so save 1 in v0 */
+ stq t0, ((FRAME_T0 + 1) * 8)(a0) /* save t0-t7 */
+ stq t1, ((FRAME_T1 + 1) * 8)(a0)
+ stq t2, ((FRAME_T2 + 1) * 8)(a0)
+ stq t3, ((FRAME_T3 + 1) * 8)(a0)
+ stq t4, ((FRAME_T4 + 1) * 8)(a0)
+ stq t5, ((FRAME_T5 + 1) * 8)(a0)
+ stq t6, ((FRAME_T6 + 1) * 8)(a0)
+ stq t7, ((FRAME_T7 + 1) * 8)(a0)
+ stq s0, ((FRAME_S0 + 1) * 8)(a0) /* save s0-s6 */
+ stq s1, ((FRAME_S1 + 1) * 8)(a0)
+ stq s2, ((FRAME_S2 + 1) * 8)(a0)
+ stq s3, ((FRAME_S3 + 1) * 8)(a0)
+ stq s4, ((FRAME_S4 + 1) * 8)(a0)
+ stq s5, ((FRAME_S5 + 1) * 8)(a0)
+ stq s6, ((FRAME_S6 + 1) * 8)(a0)
+ stq a0, ((FRAME_TRAPARG_A0 + 1) * 8)(a0) /* save a0-a5 */
+ stq a1, ((FRAME_TRAPARG_A1 + 1) * 8)(a0)
+ stq a2, ((FRAME_TRAPARG_A2 + 1) * 8)(a0)
+ stq a3, ((FRAME_A3 + 1) * 8)(a0)
+ stq a4, ((FRAME_A4 + 1) * 8)(a0)
+ stq a5, ((FRAME_A5 + 1) * 8)(a0)
+ stq ra, ((FRAME_RA + 1) * 8)(a0)
+ stq sp, ((FRAME_SP + 1) * 8)(a0)
+ ldiq t0, REV0_TRAPFRAME /* store trapframe format in */
+ stq t0, MC_FMT_OFFSET(a0) /* ucp->uc-rev */
+ /*
+ * XXX - Do we really need to save floating point registers?
+ *
+ * This is an explicit call to get the current context, so
+ * shouldn't the caller be done with the floating point registers?
+ * Contexts formed by involuntary switches, such as signal delivery,
+ * should have floating point registers saved by the kernel.
+ */
+#if 1
+ stq zero, ((71 + 1) * 8)(a0) /* FP regs are not saved */
+#else
+ ldiq t0, 1 /* say we've used FP, */
+ stq t0, ((71 + 1) * 8)(a0) /* mc_ownedfp = 1 */
+ stt $f0, ((37 + 1) * 8)(a0) /* save first register, using */
+ stt $f1, ((38 + 1) * 8)(a0) /* hw name etc. */
+ stt $f2, ((39 + 1) * 8)(a0)
+ stt $f3, ((40 + 1) * 8)(a0)
+ stt $f4, ((41 + 1) * 8)(a0)
+ stt $f5, ((42 + 1) * 8)(a0)
+ stt $f6, ((43 + 1) * 8)(a0)
+ stt $f7, ((44 + 1) * 8)(a0)
+ stt $f8, ((45 + 1) * 8)(a0)
+ stt $f9, ((46 + 1) * 8)(a0)
+ stt $f10, ((47 + 1) * 8)(a0)
+ stt $f11, ((48 + 1) * 8)(a0)
+ stt $f12, ((49 + 1) * 8)(a0)
+ stt $f13, ((50 + 1) * 8)(a0)
+ stt $f14, ((51 + 1) * 8)(a0)
+ stt $f15, ((52 + 1) * 8)(a0)
+ stt $f16, ((53 + 1) * 8)(a0)
+ stt $f17, ((54 + 1) * 8)(a0)
+ stt $f18, ((55 + 1) * 8)(a0)
+ stt $f19, ((56 + 1) * 8)(a0)
+ stt $f20, ((57 + 1) * 8)(a0)
+ stt $f21, ((58 + 1) * 8)(a0)
+ stt $f22, ((59 + 1) * 8)(a0)
+ stt $f23, ((60 + 1) * 8)(a0)
+ stt $f24, ((61 + 1) * 8)(a0)
+ stt $f25, ((62 + 1) * 8)(a0)
+ stt $f26, ((63 + 1) * 8)(a0)
+ stt $f27, ((64 + 1) * 8)(a0)
+ .set noat
+ stt $f28, ((65 + 1) * 8)(a0)
+ .set at
+ stt $f29, ((66 + 1) * 8)(a0)
+ stt $f30, ((67 + 1) * 8)(a0)
+ /* $f31 is hardwired zero */
+#endif
+ mf_fpcr ft0 /* get FP control reg */
+ stt ft0, ((69 + 1) * 8)(a0) /* and store it in mc_fpcr */
+ stq zero, ((70 + 1) * 8)(a0) /* FP software control XXX */
+ mov zero, v0 /* return zero */
+Lgcend: RET
+END(_alpha_save_context)
diff --git a/lib/libpthread/arch/alpha/alpha/enter_uts.S b/lib/libpthread/arch/alpha/alpha/enter_uts.S
new file mode 100644
index 0000000..6de3bd7
--- /dev/null
+++ b/lib/libpthread/arch/alpha/alpha/enter_uts.S
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2003 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$");
+
+/*
+ * _alpha_enter_uts(struct kse_mailbox *km, kse_func_t uts, void *stack,
+ * long stacksz);
+ */
+LEAF(_alpha_enter_uts, 4)
+ addq a2, a3, a2
+ ldiq a3, ~0xf
+ and a2, a3, a2
+ mov a2, sp
+ mov a1, ra
+ mov a1, t12
+ RET
+ END(_alpha_enter_uts)
diff --git a/lib/libpthread/arch/alpha/alpha/pthread_md.c b/lib/libpthread/arch/alpha/alpha/pthread_md.c
new file mode 100644
index 0000000..c8445b1
--- /dev/null
+++ b/lib/libpthread/arch/alpha/alpha/pthread_md.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2003 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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, 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 <strings.h>
+#include "pthread_md.h"
+
+/*
+ * The constructors.
+ */
+struct tcb *
+_tcb_ctor(struct pthread *thread, int initial)
+{
+ struct tcb *tcb;
+
+ if ((tcb = malloc(sizeof(struct tcb))) != NULL) {
+ bzero(tcb, sizeof(struct tcb));
+ tcb->tcb_thread = thread;
+ /* Allocate TDV */
+ }
+ return (tcb);
+}
+
+void
+_tcb_dtor(struct tcb *tcb)
+{
+ /* Free TDV */
+ free(tcb);
+}
+
+struct kcb *
+_kcb_ctor(struct kse *kse)
+{
+ struct kcb *kcb;
+
+ if ((kcb = malloc(sizeof(struct kcb))) != NULL) {
+ bzero(kcb, sizeof(struct kcb));
+ kcb->kcb_faketcb.tcb_isfake = 1;
+ kcb->kcb_faketcb.tcb_tmbx.tm_flags = TMF_NOUPCALL;
+ kcb->kcb_curtcb = &kcb->kcb_faketcb;
+ kcb->kcb_kse = kse;
+ }
+ return (kcb);
+}
+
+void
+_kcb_dtor(struct kcb *kcb)
+{
+ free(kcb);
+}
diff --git a/lib/libpthread/arch/alpha/include/atomic_ops.h b/lib/libpthread/arch/alpha/include/atomic_ops.h
new file mode 100644
index 0000000..7c3e62b
--- /dev/null
+++ b/lib/libpthread/arch/alpha/include/atomic_ops.h
@@ -0,0 +1,75 @@
+/*-
+ * Copyright (c) 2003 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _ATOMIC_OPS_H_
+#define _ATOMIC_OPS_H_
+
+/*
+ * Atomic swap:
+ * Atomic (tmp = *dst, *dst = val), then *res = tmp
+ *
+ * void atomic_swap_long(long *dst, long val, long *res);
+ */
+static inline void
+atomic_swap_long(long *dst, long val, long *res)
+{
+ /* $1 and $2 are t0 and t1 respectively. */
+ __asm __volatile (
+ " ldq $1, %1\n" /* get cache line before lock */
+ "1: ldq_l $1, %1\n" /* load *dst asserting lock */
+ " mov %2, $2\n" /* save value to be swapped */
+ " stq_c $2, %1\n" /* attempt the store; $2 clobbered */
+ " beq $2, 1b\n" /* it didn't work, loop */
+ " stq $1, %0\n" /* save value of *dst in *res */
+ " mb \n"
+ : "+m"(*res)
+ : "m"(*dst), "r"(val)
+ : "memory", "$1", "$2"); /* clobber t0 and t1 */
+}
+
+static inline void
+atomic_swap_int(int *dst, int val, int *res)
+{
+ /* $1 and $2 are t0 and t1 respectively. */
+ __asm __volatile (
+ " ldl $1, %1\n" /* get cache line before lock */
+ "1: ldl_l $1, %1\n" /* load *dst asserting lock */
+ " mov %2, $2\n" /* save value to be swapped */
+ " stl_c $2, %1\n" /* attempt the store; $2 clobbered */
+ " beq $2, 1b\n" /* it didn't work, loop */
+ " stl $1, %0\n" /* save value of *dst in *res */
+ " mb \n"
+ : "+m"(*res)
+ : "m"(*dst), "r"(val)
+ : "memory", "$1", "$2"); /* clobber t0 and t1 */
+}
+
+#define atomic_swap_ptr(d, v, r) \
+ atomic_swap_long((long *)(d), (long)(v), (long *)(r))
+
+#endif
diff --git a/lib/libpthread/arch/alpha/include/pthread_md.h b/lib/libpthread/arch/alpha/include/pthread_md.h
new file mode 100644
index 0000000..c7a85f1
--- /dev/null
+++ b/lib/libpthread/arch/alpha/include/pthread_md.h
@@ -0,0 +1,247 @@
+/*
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _PTHREAD_MD_H_
+#define _PTHREAD_MD_H_
+
+#include <sys/kse.h>
+#include <stddef.h>
+#include <ucontext.h>
+
+#define KSE_STACKSIZE 16384
+#define DTV_OFFSET offsetof(struct tcb, tcb_tp.tp_tdv)
+
+#define THR_GETCONTEXT(ucp) _alpha_save_context(&(ucp)->uc_mcontext)
+#define THR_SETCONTEXT(ucp) PANIC("THR_SETCONTEXT() now in use!\n")
+
+#define PER_THREAD
+
+struct kcb;
+struct kse;
+struct pthread;
+struct tcb;
+struct tdv; /* We don't know what this is yet? */
+
+/*
+ * tp points to one of these. We define the static TLS as an array
+ * of long double to enforce 16-byte alignment of the TLS memory,
+ * struct alpha_tp, struct tcb and also struct kcb. Both static and
+ * dynamic allocation of any of these structures will result in a
+ * valid, well-aligned thread pointer.
+ */
+struct alpha_tp {
+ struct tdv *tp_tdv; /* dynamic TLS */
+ uint64_t _reserved_;
+ long double tp_tls[0]; /* static TLS */
+};
+
+struct tcb {
+ struct kse_thr_mailbox tcb_tmbx;
+ struct pthread *tcb_thread;
+ struct kcb *tcb_curkcb;
+ long tcb_isfake;
+ struct alpha_tp tcb_tp;
+};
+
+struct kcb {
+ struct kse_mailbox kcb_kmbx;
+ struct tcb kcb_faketcb;
+ struct tcb *kcb_curtcb;
+ struct kse *kcb_kse;
+};
+
+#define _tp __builtin_thread_pointer()
+#define _tcb ((struct tcb*)((char*)(_tp) - offsetof(struct tcb, tcb_tp)))
+
+/*
+ * The kcb and tcb constructors.
+ */
+struct tcb *_tcb_ctor(struct pthread *, int);
+void _tcb_dtor(struct tcb *);
+struct kcb *_kcb_ctor(struct kse *kse);
+void _kcb_dtor(struct kcb *);
+
+/* Called from the KSE to set its private data. */
+static __inline void
+_kcb_set(struct kcb *kcb)
+{
+ /* There is no thread yet; use the fake tcb. */
+ __builtin_set_thread_pointer(&kcb->kcb_faketcb.tcb_tp);
+}
+
+/*
+ * Get the current kcb.
+ *
+ * This can only be called while in a critical region; don't
+ * worry about having the kcb changed out from under us.
+ */
+static __inline struct kcb *
+_kcb_get(void)
+{
+ return (_tcb->tcb_curkcb);
+}
+
+/*
+ * Enter a critical region.
+ *
+ * Read and clear km_curthread in the kse mailbox.
+ */
+static __inline struct kse_thr_mailbox *
+_kcb_critical_enter(void)
+{
+ struct kse_thr_mailbox *crit;
+ uint32_t flags;
+
+ if (_tcb->tcb_isfake != 0) {
+ /*
+ * We already are in a critical region since
+ * there is no current thread.
+ */
+ crit = NULL;
+ } else {
+ flags = _tcb->tcb_tmbx.tm_flags;
+ _tcb->tcb_tmbx.tm_flags |= TMF_NOUPCALL;
+ crit = _tcb->tcb_curkcb->kcb_kmbx.km_curthread;
+ _tcb->tcb_curkcb->kcb_kmbx.km_curthread = NULL;
+ _tcb->tcb_tmbx.tm_flags = flags;
+ }
+ return (crit);
+}
+
+static __inline void
+_kcb_critical_leave(struct kse_thr_mailbox *crit)
+{
+ /* No need to do anything if this is a fake tcb. */
+ if (_tcb->tcb_isfake == 0)
+ _tcb->tcb_curkcb->kcb_kmbx.km_curthread = crit;
+}
+
+static __inline int
+_kcb_in_critical(void)
+{
+ uint32_t flags;
+ int ret;
+
+ if (_tcb->tcb_isfake != 0) {
+ /*
+ * We are in a critical region since there is no
+ * current thread.
+ */
+ ret = 1;
+ } else {
+ flags = _tcb->tcb_tmbx.tm_flags;
+ _tcb->tcb_tmbx.tm_flags |= TMF_NOUPCALL;
+ ret = (_tcb->tcb_curkcb->kcb_kmbx.km_curthread == NULL);
+ _tcb->tcb_tmbx.tm_flags = flags;
+ }
+ return (ret);
+}
+
+static __inline void
+_tcb_set(struct kcb *kcb, struct tcb *tcb)
+{
+ if (tcb == NULL)
+ tcb = &kcb->kcb_faketcb;
+ kcb->kcb_curtcb = tcb;
+ tcb->tcb_curkcb = kcb;
+ __builtin_set_thread_pointer(&tcb->tcb_tp);
+}
+
+static __inline struct tcb *
+_tcb_get(void)
+{
+ return (_tcb);
+}
+
+static __inline struct pthread *
+_get_curthread(void)
+{
+ return (_tcb->tcb_thread);
+}
+
+/*
+ * Get the current kse.
+ *
+ * Like _kcb_get(), this can only be called while in a critical region.
+ */
+static __inline struct kse *
+_get_curkse(void)
+{
+ return (_tcb->tcb_curkcb->kcb_kse);
+}
+
+void _alpha_enter_uts(struct kse_mailbox *km, kse_func_t uts, void *stack,
+ size_t stacksz);
+int _alpha_restore_context(mcontext_t *mc, intptr_t val, intptr_t *loc);
+int _alpha_save_context(mcontext_t *mc);
+
+static __inline int
+_thread_enter_uts(struct tcb *tcb, struct kcb *kcb)
+{
+ if (_alpha_save_context(&tcb->tcb_tmbx.tm_context.uc_mcontext) == 0) {
+ /* Make the fake tcb the current thread. */
+ kcb->kcb_curtcb = &kcb->kcb_faketcb;
+ __builtin_set_thread_pointer(&kcb->kcb_faketcb.tcb_tp);
+ _alpha_enter_uts(&kcb->kcb_kmbx, kcb->kcb_kmbx.km_func,
+ kcb->kcb_kmbx.km_stack.ss_sp,
+ kcb->kcb_kmbx.km_stack.ss_size);
+ /* We should not reach here. */
+ return (-1);
+ }
+ return (0);
+}
+
+static __inline int
+_thread_switch(struct kcb *kcb, struct tcb *tcb, int setmbox)
+{
+ extern int _libkse_debug;
+
+ _tcb_set(kcb, tcb);
+ if (_libkse_debug == 0) {
+ tcb->tcb_tmbx.tm_lwp = kcb->kcb_kmbx.km_lwp;
+ if (setmbox != 0)
+ _alpha_restore_context(
+ &tcb->tcb_tmbx.tm_context.uc_mcontext,
+ (intptr_t)&tcb->tcb_tmbx,
+ (intptr_t *)&kcb->kcb_kmbx.km_curthread);
+ else
+ _alpha_restore_context(
+ &tcb->tcb_tmbx.tm_context.uc_mcontext,
+ 0, NULL);
+ } else {
+ if (setmbox)
+ kse_switchin(&tcb->tcb_tmbx, KSE_SWITCHIN_SETTMBX);
+ else
+ kse_switchin(&tcb->tcb_tmbx, 0);
+ }
+
+ /* We should not reach here. */
+ return (-1);
+}
+
+#endif /* _PTHREAD_MD_H_ */
diff --git a/lib/libpthread/arch/amd64/Makefile.inc b/lib/libpthread/arch/amd64/Makefile.inc
new file mode 100644
index 0000000..c8b0362
--- /dev/null
+++ b/lib/libpthread/arch/amd64/Makefile.inc
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}/${MACHINE_ARCH}
+
+SRCS+= context.S enter_uts.S pthread_md.c
diff --git a/lib/libpthread/arch/amd64/amd64/context.S b/lib/libpthread/arch/amd64/amd64/context.S
new file mode 100644
index 0000000..6a6b558
--- /dev/null
+++ b/lib/libpthread/arch/amd64/amd64/context.S
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2003 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 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 <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * The following notes ("cheat sheet") was provided by Peter Wemm.
+ *
+ * scratch:
+ * rax (1st return)
+ * rcx (4th arg)
+ * rdx (3rd arg, 2nd return)
+ * rsi (2nd arg)
+ * rdi (1st arg)
+ * r8 (5th arg)
+ * r9 (6th arg)
+ * r10 (temp, static chain?)
+ * r11 (temp)
+ *
+ * preserved:
+ * rbx (base pointer)
+ * rsp (stack)
+ * rbp (frame)
+ * r12-r15 (general)
+ *
+ * calls:
+ * rdi 1
+ * rsi 2
+ * rdx 3
+ * rcx 4
+ * r8 5
+ * r9 6
+ *
+ * return:
+ * rax 1
+ * rdx 2
+ *
+ * This means:
+ * arg1 goes in %rdi, arg2 in %rsi, etc. return value is %rax (and
+ * secondary return, eg: pipe(2), in %rdx) %rcx,%rsi,%rdi etc are
+ * trashed by making a call to something. %rbx,%rbp,%r12-15 are the
+ * only registers preserved across a call. Note that unlike i386,
+ * %rsi and %rdi are scratch rather than preserved. FPU is
+ * different, args are in SSE registers rather than the x87 stack.
+ *
+ * Aside from the register calling conventions, amd64 can be treated
+ * very much like i386. Things like setjmp/longjmp etc were literal
+ * translations from i386 but with the register names updated, etc.
+ * The main gotcha is that FPU save/restore is in SSE format, which
+ * means a sparse 512 byte FPU context.
+ */
+
+
+/*
+ * Where do we define these?
+ */
+#define MC_SIZE 800 /* sizeof mcontext_t */
+#define MC_LEN_OFFSET (25*8) /* offset to mc_len from mcontext */
+#define MC_FPFMT_OFFSET (26*8) /* offset to mc_fpformat from mcontext */
+#define MC_FPFMT_NODEV 0x10000
+#define MC_OWNEDFP_OFFSET (27*8) /* offset to mc_ownedfp from mcontext */
+#define MC_OWNEDFP_NONE 0x20000
+#define MC_OWNEDFP_FPU 0x20001
+#define MC_OWNEDFP_PCB 0x20002
+#define MC_FPREGS_OFFSET (28*8) /* offset to FP registers */
+#define MC_FP_CW_OFFSET (28*8) /* offset to FP control word */
+
+#define MC_RDI (1 * 8)
+#define MC_RSI (2 * 8)
+#define MC_RDX (3 * 8)
+#define MC_RCX (4 * 8)
+#define MC_R8 (5 * 8)
+#define MC_R9 (6 * 8)
+#define MC_RAX (7 * 8)
+#define MC_RBX (8 * 8)
+#define MC_RBP (9 * 8)
+#define MC_R10 (10 * 8)
+#define MC_R11 (11 * 8)
+#define MC_R12 (12 * 8)
+#define MC_R13 (13 * 8)
+#define MC_R14 (14 * 8)
+#define MC_R15 (15 * 8)
+#define MC_FLAGS (18 * 8)
+#define MC_RIP (20 * 8)
+#define MC_CS (21 * 8)
+#define MC_RFLAGS (22 * 8)
+#define MC_RSP (23 * 8)
+#define MC_SS (24 * 8)
+
+#define REDZONE 128 /* size of the red zone */
+
+/*
+ * _amd64_ctx_save(mcontext_t *mcp)
+ *
+ * No values are saved to mc_trapno, mc_addr, mc_err and mc_cs.
+ * For the FPU state, only the floating point control word is stored.
+ */
+ENTRY(_amd64_save_context)
+ cmpq $0, %rdi /* check for null pointer */
+ jne 1f
+ movq $-1, %rax
+ jmp 2f
+1: movq %rdi, MC_RDI(%rdi)
+ movq %rsi, MC_RSI(%rdi)
+ movq %rdx, MC_RDX(%rdi)
+ movq %rcx, MC_RCX(%rdi)
+ movq %r8, MC_R8(%rdi)
+ movq %r9, MC_R9(%rdi)
+ movq $1, MC_RAX(%rdi) /* return 1 when restored */
+ movq %rbx, MC_RBX(%rdi)
+ movq %rbp, MC_RBP(%rdi)
+ movq %r10, MC_R10(%rdi)
+ movq %r11, MC_R11(%rdi)
+ movq %r12, MC_R12(%rdi)
+ movq %r13, MC_R13(%rdi)
+ movq %r14, MC_R14(%rdi)
+ movq %r15, MC_R15(%rdi)
+ movq (%rsp), %rax /* get return address */
+ movq %rax, MC_RIP(%rdi) /* save return address (%rip) */
+ pushfq /* get flags */
+ popq %rax
+ movq %rax, MC_RFLAGS(%rdi) /* save flags */
+ movq %rsp, %rax /* setcontext pushes the return */
+ addq $8, %rax /* address onto the stack; */
+ movq %rax, MC_RSP(%rdi) /* account for this -- ???. */
+ movw %ss, MC_SS(%rdi)
+ fnstcw MC_FP_CW_OFFSET(%rdi) /* save FPU control word */
+ movq $MC_OWNEDFP_NONE, MC_OWNEDFP_OFFSET(%rdi) /* no FP */
+ movq $MC_FPFMT_NODEV, MC_FPFMT_OFFSET(%rdi)
+ movq $MC_SIZE, MC_LEN_OFFSET(%rdi)
+ xorq %rax, %rax /* return 0 */
+2: ret
+
+/*
+ * _amd64_ctx_restore(mcontext_t *mcp, intptr_t val, intptr_t *loc);
+ */
+ENTRY(_amd64_restore_context)
+ cmpq $0, %rdi /* check for null pointer */
+ jne 1f
+ movq $-1, %rax
+ jmp 2f
+1: cmpq $MC_SIZE, MC_LEN_OFFSET(%rdi) /* is context valid? */
+ je 2f
+ movq $-1, %rax /* bzzzt, invalid context */
+ ret
+2: movq MC_RCX(%rdi), %rcx
+ movq MC_R8(%rdi), %r8
+ movq MC_R9(%rdi), %r9
+ movq MC_RBX(%rdi), %rbx
+ movq MC_RBP(%rdi), %rbp
+ movq MC_R10(%rdi), %r10
+ movq MC_R11(%rdi), %r11
+ movq MC_R12(%rdi), %r12
+ movq MC_R13(%rdi), %r13
+ movq MC_R14(%rdi), %r14
+ movq MC_R15(%rdi), %r15
+ /*
+ * if (mc_fpowned == MC_OWNEDFP_FPU || mc_fpowned == MC_OWNEDFP_PCB)
+ * restore XMM/SSE FP register format
+ */
+ cmpq $MC_OWNEDFP_NONE, MC_OWNEDFP_OFFSET(%rdi)
+ je 4f
+ cmpq $MC_OWNEDFP_PCB, MC_OWNEDFP_OFFSET(%rdi)
+ je 3f
+ cmpq $MC_OWNEDFP_FPU, MC_OWNEDFP_OFFSET(%rdi)
+ jne 4f
+3: fxrstor MC_FPREGS_OFFSET(%rdi) /* restore XMM FP regs */
+ jmp 5f
+4: fninit
+ fldcw MC_FP_CW_OFFSET(%rdi)
+5: movq MC_RSP(%rdi), %rsp /* switch to context stack */
+ subq $REDZONE, %rsp
+ movq MC_RIP(%rdi), %rax /* return address on stack */
+ pushq %rax
+ movq MC_RDI(%rdi), %rax /* rdi on stack */
+ pushq %rax
+ movq MC_RDX(%rdi), %rax /* rdx on stack */
+ pushq %rax
+ movq MC_RSI(%rdi), %rax /* rsi on stack */
+ pushq %rax
+ movq MC_RFLAGS(%rdi), %rax /* flags on stack*/
+ pushq %rax
+ movq MC_RAX(%rdi), %rax /* restore rax */
+ /* At this point we're done with the context. */
+ cmpq $0, %rdx /* set *loc to val */
+ je 6f
+ movq %rsi, (%rdx)
+6: popfq /* restore flags */
+ popq %rsi /* restore rsi, rdx, and rdi */
+ popq %rdx
+ popq %rdi
+ ret $REDZONE
+
diff --git a/lib/libpthread/arch/amd64/amd64/enter_uts.S b/lib/libpthread/arch/amd64/amd64/enter_uts.S
new file mode 100644
index 0000000..fb0df87
--- /dev/null
+++ b/lib/libpthread/arch/amd64/amd64/enter_uts.S
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2003 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 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 <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+
+/*
+ * _amd64_enter_uts(struct kse_mailbox *km, kse_func_t uts, void *stack,
+ * size_t stacksz);
+ */
+ENTRY(_amd64_enter_uts)
+ addq %rcx, %rdx /* get stack base */
+ andq $~0xf, %rdx /* align to 16 bytes */
+ movq %rdx, %rsp /* switch to UTS stack */
+ movq %rdx, %rbp /* set frame */
+ callq *%rsi
+ ret
diff --git a/lib/libpthread/arch/amd64/amd64/pthread_md.c b/lib/libpthread/arch/amd64/amd64/pthread_md.c
new file mode 100644
index 0000000..3aceec7
--- /dev/null
+++ b/lib/libpthread/arch/amd64/amd64/pthread_md.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2003 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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, 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$
+ */
+
+#include <stdlib.h>
+#include <strings.h>
+#include "rtld_tls.h"
+#include "pthread_md.h"
+
+/*
+ * The constructors.
+ */
+struct tcb *
+_tcb_ctor(struct pthread *thread, int initial)
+{
+ struct tcb *tcb;
+ void *oldtls;
+
+ if (initial) {
+ __asm __volatile("movq %%fs:0, %0" : "=r" (oldtls));
+ } else {
+ oldtls = NULL;
+ }
+
+ tcb = _rtld_allocate_tls(oldtls, sizeof(struct tcb), 16);
+ if (tcb) {
+ tcb->tcb_thread = thread;
+ bzero(&tcb->tcb_tmbx, sizeof(tcb->tcb_tmbx));
+ }
+
+ return (tcb);
+}
+
+void
+_tcb_dtor(struct tcb *tcb)
+{
+ _rtld_free_tls(tcb, sizeof(struct tcb), 16);
+}
+
+struct kcb *
+_kcb_ctor(struct kse *kse)
+{
+ struct kcb *kcb;
+
+ kcb = malloc(sizeof(struct kcb));
+ if (kcb != NULL) {
+ bzero(kcb, sizeof(struct kcb));
+ kcb->kcb_self = kcb;
+ kcb->kcb_kse = kse;
+ }
+ return (kcb);
+}
+
+void
+_kcb_dtor(struct kcb *kcb)
+{
+ free(kcb);
+}
diff --git a/lib/libpthread/arch/amd64/include/atomic_ops.h b/lib/libpthread/arch/amd64/include/atomic_ops.h
new file mode 100644
index 0000000..980eb8e
--- /dev/null
+++ b/lib/libpthread/arch/amd64/include/atomic_ops.h
@@ -0,0 +1,57 @@
+/*-
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _ATOMIC_OPS_H_
+#define _ATOMIC_OPS_H_
+
+/*
+ * Atomic swap:
+ * Atomic (tmp = *dst, *dst = val), then *res = tmp
+ *
+ * void atomic_swap64(intptr_t *dst, intptr_t val, intptr_t *res);
+ */
+static inline void
+atomic_swap64(intptr_t *dst, intptr_t val, intptr_t *res)
+{
+ __asm __volatile(
+ "xchgq %2, %1; movq %2, %0"
+ : "=m" (*res) : "m" (*dst), "r" (val) : "memory");
+}
+
+static inline void
+atomic_swap_int(int *dst, int val, int *res)
+{
+ __asm __volatile(
+ "xchgl %2, %1; movl %2, %0"
+ : "=m" (*res) : "m" (*dst), "r" (val) : "memory");
+}
+
+#define atomic_swap_ptr(d, v, r) \
+ atomic_swap64((intptr_t *)(d), (intptr_t)(v), (intptr_t *)(r))
+
+#endif
diff --git a/lib/libpthread/arch/amd64/include/pthread_md.h b/lib/libpthread/arch/amd64/include/pthread_md.h
new file mode 100644
index 0000000..a7da5df
--- /dev/null
+++ b/lib/libpthread/arch/amd64/include/pthread_md.h
@@ -0,0 +1,268 @@
+/*-
+ * Copyright (C) 2003 David Xu <davidxu@freebsd.org>
+ * 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.
+ *
+ * $FreeBSD$
+ */
+/*
+ * Machine-dependent thread prototypes/definitions for the thread kernel.
+ */
+#ifndef _PTHREAD_MD_H_
+#define _PTHREAD_MD_H_
+
+#include <stddef.h>
+#include <sys/types.h>
+#include <sys/kse.h>
+#include <machine/sysarch.h>
+#include <ucontext.h>
+
+#define KSE_STACKSIZE 16384
+#define DTV_OFFSET offsetof(struct tcb, tcb_dtv)
+
+#define THR_GETCONTEXT(ucp) \
+ (void)_amd64_save_context(&(ucp)->uc_mcontext)
+#define THR_SETCONTEXT(ucp) \
+ (void)_amd64_restore_context(&(ucp)->uc_mcontext, 0, NULL)
+
+#define PER_KSE
+#undef PER_THREAD
+
+struct kse;
+struct pthread;
+struct tdv;
+
+/*
+ * %fs points to a struct kcb.
+ */
+struct kcb {
+ struct tcb *kcb_curtcb;
+ struct kcb *kcb_self; /* self reference */
+ struct kse *kcb_kse;
+ struct kse_mailbox kcb_kmbx;
+};
+
+struct tcb {
+ struct tcb *tcb_self; /* required by rtld */
+ void *tcb_dtv; /* required by rtld */
+ struct pthread *tcb_thread;
+ void *tcb_spare[1]; /* align tcb_tmbx to 16 bytes */
+ struct kse_thr_mailbox tcb_tmbx;
+};
+
+/*
+ * Evaluates to the byte offset of the per-kse variable name.
+ */
+#define __kcb_offset(name) __offsetof(struct kcb, name)
+
+/*
+ * Evaluates to the type of the per-kse variable name.
+ */
+#define __kcb_type(name) __typeof(((struct kcb *)0)->name)
+
+/*
+ * Evaluates to the value of the per-kse variable name.
+ */
+#define KCB_GET64(name) ({ \
+ __kcb_type(name) __result; \
+ \
+ u_long __i; \
+ __asm __volatile("movq %%fs:%1, %0" \
+ : "=r" (__i) \
+ : "m" (*(u_long *)(__kcb_offset(name)))); \
+ __result = (__kcb_type(name))__i; \
+ \
+ __result; \
+})
+
+/*
+ * Sets the value of the per-kse variable name to value val.
+ */
+#define KCB_SET64(name, val) ({ \
+ __kcb_type(name) __val = (val); \
+ \
+ u_long __i; \
+ __i = (u_long)__val; \
+ __asm __volatile("movq %1,%%fs:%0" \
+ : "=m" (*(u_long *)(__kcb_offset(name))) \
+ : "r" (__i)); \
+})
+
+static __inline u_long
+__kcb_readandclear64(volatile u_long *addr)
+{
+ u_long result;
+
+ __asm __volatile (
+ " xorq %0, %0;"
+ " xchgq %%fs:%1, %0;"
+ "# __kcb_readandclear64"
+ : "=&r" (result)
+ : "m" (*addr));
+ return (result);
+}
+
+#define KCB_READANDCLEAR64(name) ({ \
+ __kcb_type(name) __result; \
+ \
+ __result = (__kcb_type(name)) \
+ __kcb_readandclear64((u_long *)__kcb_offset(name)); \
+ __result; \
+})
+
+
+#define _kcb_curkcb() KCB_GET64(kcb_self)
+#define _kcb_curtcb() KCB_GET64(kcb_curtcb)
+#define _kcb_curkse() ((struct kse *)KCB_GET64(kcb_kmbx.km_udata))
+#define _kcb_get_tmbx() KCB_GET64(kcb_kmbx.km_curthread)
+#define _kcb_set_tmbx(value) KCB_SET64(kcb_kmbx.km_curthread, (void *)value)
+#define _kcb_readandclear_tmbx() KCB_READANDCLEAR64(kcb_kmbx.km_curthread)
+
+/*
+ * The constructors.
+ */
+struct tcb *_tcb_ctor(struct pthread *, int);
+void _tcb_dtor(struct tcb *tcb);
+struct kcb *_kcb_ctor(struct kse *);
+void _kcb_dtor(struct kcb *);
+
+/* Called from the KSE to set its private data. */
+static __inline void
+_kcb_set(struct kcb *kcb)
+{
+ amd64_set_fsbase(kcb);
+}
+
+/* Get the current kcb. */
+static __inline struct kcb *
+_kcb_get(void)
+{
+ return (_kcb_curkcb());
+}
+
+static __inline struct kse_thr_mailbox *
+_kcb_critical_enter(void)
+{
+ struct kse_thr_mailbox *crit;
+
+ crit = _kcb_readandclear_tmbx();
+ return (crit);
+}
+
+static __inline void
+_kcb_critical_leave(struct kse_thr_mailbox *crit)
+{
+ _kcb_set_tmbx(crit);
+}
+
+static __inline int
+_kcb_in_critical(void)
+{
+ return (_kcb_get_tmbx() == NULL);
+}
+
+static __inline void
+_tcb_set(struct kcb *kcb, struct tcb *tcb)
+{
+ kcb->kcb_curtcb = tcb;
+}
+
+static __inline struct tcb *
+_tcb_get(void)
+{
+ return (_kcb_curtcb());
+}
+
+static __inline struct pthread *
+_get_curthread(void)
+{
+ struct tcb *tcb;
+
+ tcb = _kcb_curtcb();
+ if (tcb != NULL)
+ return (tcb->tcb_thread);
+ else
+ return (NULL);
+}
+
+static __inline struct kse *
+_get_curkse(void)
+{
+ return ((struct kse *)_kcb_curkse());
+}
+
+void _amd64_enter_uts(struct kse_mailbox *km, kse_func_t uts, void *stack,
+ size_t stacksz);
+int _amd64_restore_context(mcontext_t *mc, intptr_t val, intptr_t *loc);
+int _amd64_save_context(mcontext_t *mc);
+
+static __inline int
+_thread_enter_uts(struct tcb *tcb, struct kcb *kcb)
+{
+ int ret;
+
+ ret = _amd64_save_context(&tcb->tcb_tmbx.tm_context.uc_mcontext);
+ if (ret == 0) {
+ _amd64_enter_uts(&kcb->kcb_kmbx, kcb->kcb_kmbx.km_func,
+ kcb->kcb_kmbx.km_stack.ss_sp,
+ kcb->kcb_kmbx.km_stack.ss_size);
+ /* We should not reach here. */
+ return (-1);
+ }
+ else if (ret < 0)
+ return (-1);
+ return (0);
+}
+
+static __inline int
+_thread_switch(struct kcb *kcb, struct tcb *tcb, int setmbox)
+{
+ extern int _libkse_debug;
+
+ if ((kcb == NULL) || (tcb == NULL))
+ return (-1);
+ kcb->kcb_curtcb = tcb;
+
+ if (_libkse_debug == 0) {
+ tcb->tcb_tmbx.tm_lwp = kcb->kcb_kmbx.km_lwp;
+ if (setmbox != 0)
+ _amd64_restore_context(
+ &tcb->tcb_tmbx.tm_context.uc_mcontext,
+ (intptr_t)&tcb->tcb_tmbx,
+ (intptr_t *)&kcb->kcb_kmbx.km_curthread);
+ else
+ _amd64_restore_context(
+ &tcb->tcb_tmbx.tm_context.uc_mcontext,
+ 0, NULL);
+ /* We should not reach here. */
+ } else {
+ if (setmbox)
+ kse_switchin(&tcb->tcb_tmbx, KSE_SWITCHIN_SETTMBX);
+ else
+ kse_switchin(&tcb->tcb_tmbx, 0);
+ }
+
+ return (-1);
+}
+#endif
diff --git a/lib/libpthread/arch/arm/Makefile.inc b/lib/libpthread/arch/arm/Makefile.inc
new file mode 100644
index 0000000..ced7063
--- /dev/null
+++ b/lib/libpthread/arch/arm/Makefile.inc
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}/${MACHINE_ARCH}
+
+CFLAGS+=-DSYSTEM_SCOPE_ONLY
+
+SRCS+= pthread_md.c context.S
diff --git a/lib/libpthread/arch/arm/arm/context.S b/lib/libpthread/arch/arm/arm/context.S
new file mode 100644
index 0000000..c638804
--- /dev/null
+++ b/lib/libpthread/arch/arm/arm/context.S
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 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. 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$");
+
+/*
+ * int thr_setcontext(mcontext_t *mcp, intptr_t val, intptr_t *loc)
+ *
+ * Restores the context in mcp.
+ *
+ * Returns 0 if there are no errors; -1 otherwise
+ */
+
+.weak _C_LABEL(_thr_setcontext)
+.set _C_LABEL(_thr_setcontext), _C_LABEL(__thr_setcontext)
+
+ENTRY(__thr_setcontext)
+/* Check for NULL pointer. */
+ cmp r0, #0
+ moveq r0, #-1
+ moveq pc, lr
+ cmp r2, #0
+ strne r1, [r2]
+ ldr r1, [r0, #(16 * 4)] /* CPSR */
+ msr cpsr, r1
+ ldmia r0, {r0-r15}
+ mov pc, lr
+ /* XXX: FP bits ? */
+
+/*
+ * int thr_getcontext(mcontext_t *mcp);
+ *
+ * Returns -1 if there is an error, 0 no errors; 1 upon return
+ * from a setcontext().
+ */
+.weak _C_LABEL(_thr_getcontext)
+.set _C_LABEL(_thr_getcontext), _C_LABEL(__thr_getcontext)
+
+ENTRY(__thr_getcontext)
+/* Check for NULL pointer. */
+ cmp r0, #0
+ moveq r0, #-1
+ moveq pc, lr
+ stmia r0, {r1-r14}
+ mov r1, #1
+ str r1, [r0] /* Return 1 from setcontext */
+ str lr, [r0, #(15 * 4)] /* PC */
+ mrs r1, cpsr
+ str r1, [r0, #(16 * 4)] /* CPSR */
+ mov r0, #0 /* Return 0. */
+ mov pc, lr
+
+ENTRY(_arm_enter_uts)
+ add sp, r2, r3 /* Stack addr + size. */
+ mov pc, r1
diff --git a/lib/libpthread/arch/arm/arm/pthread_md.c b/lib/libpthread/arch/arm/arm/pthread_md.c
new file mode 100644
index 0000000..72426d4
--- /dev/null
+++ b/lib/libpthread/arch/arm/arm/pthread_md.c
@@ -0,0 +1,86 @@
+/*-
+ * Copyright (C) 2003 Jake Burkholder <jake@freebsd.org>
+ * Copyright (C) 2003 David Xu <davidxu@freebsd.org>
+ * Copyright (c) 2001,2003 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include <unistd.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ucontext.h>
+
+#include <machine/sysarch.h>
+
+#include "pthread_md.h"
+
+struct arm_tp **arm_tp = (struct arm_tp **)ARM_TP_ADDRESS;
+
+struct tcb *
+_tcb_ctor(struct pthread *thread, int initial)
+{
+ struct tcb *tcb;
+
+ if ((tcb = malloc(sizeof(struct tcb)))) {
+ bzero(tcb, sizeof(struct tcb));
+ tcb->tcb_thread = thread;
+ /* XXX - Allocate tdv/tls */
+ }
+ return (tcb);
+}
+
+void
+_tcb_dtor(struct tcb *tcb)
+{
+
+ free(tcb);
+}
+
+struct kcb *
+_kcb_ctor(struct kse *kse)
+{
+ struct kcb *kcb;
+
+ kcb = malloc(sizeof(struct kcb));
+ if (kcb != NULL) {
+ bzero(kcb, sizeof(struct kcb));
+ kcb->kcb_faketcb.tcb_isfake = 1;
+ kcb->kcb_faketcb.tcb_tmbx.tm_flags = TMF_NOUPCALL;
+ kcb->kcb_curtcb = &kcb->kcb_faketcb;
+ kcb->kcb_kse = kse;
+ }
+ return (kcb);
+}
+
+void
+_kcb_dtor(struct kcb *kcb)
+{
+ free(kcb);
+}
diff --git a/lib/libpthread/arch/arm/include/atomic_ops.h b/lib/libpthread/arch/arm/include/atomic_ops.h
new file mode 100644
index 0000000..3a209b3
--- /dev/null
+++ b/lib/libpthread/arch/arm/include/atomic_ops.h
@@ -0,0 +1,53 @@
+/*-
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _ATOMIC_OPS_H_
+#define _ATOMIC_OPS_H_
+
+#include <machine/atomic.h>
+#include "thr_private.h"
+
+/*
+ * Atomic swap:
+ * Atomic (tmp = *dst, *dst = val), then *res = tmp
+ *
+ * void atomic_swap32(intptr_t *dst, intptr_t val, intptr_t *res);
+ */
+static inline void
+atomic_swap32(intptr_t *dst, intptr_t val, intptr_t *res)
+{
+ *res = __swp(val, dst);
+}
+
+#define atomic_swap_ptr(d, v, r) \
+ atomic_swap32((intptr_t *)d, (intptr_t)v, (intptr_t *)r)
+
+#define atomic_swap_int(d, v, r) \
+ atomic_swap32((intptr_t *)d, (intptr_t)v, (intptr_t *)r)
+#endif
+
diff --git a/lib/libpthread/arch/arm/include/pthread_md.h b/lib/libpthread/arch/arm/include/pthread_md.h
new file mode 100644
index 0000000..857fa1b
--- /dev/null
+++ b/lib/libpthread/arch/arm/include/pthread_md.h
@@ -0,0 +1,257 @@
+/*-
+ * Copyright (c) 2003 Jake Burkholder <jake@freebsd.org>.
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Machine-dependent thread prototypes/definitions for the thread kernel.
+ */
+#ifndef _PTHREAD_MD_H_
+#define _PTHREAD_MD_H_
+
+#include <sys/kse.h>
+#include <stddef.h>
+#include <ucontext.h>
+
+#define KSE_STACKSIZE 16384
+#define DTV_OFFSET offsetof(struct tcb, tcb_tp.tp_tdv)
+
+int _thr_setcontext(mcontext_t *, intptr_t, intptr_t *);
+int _thr_getcontext(mcontext_t *);
+
+#define THR_GETCONTEXT(ucp) _thr_getcontext(&(ucp)->uc_mcontext)
+#define THR_SETCONTEXT(ucp) _thr_setcontext(&(ucp)->uc_mcontext, 0, NULL)
+
+#define PER_THREAD
+
+struct kcb;
+struct kse;
+struct pthread;
+struct tcb;
+struct tdv; /* We don't know what this is yet? */
+
+
+/*
+ * %r6 points to one of these. We define the static TLS as an array
+ * of long double to enforce 16-byte alignment of the TLS memory.
+ *
+ * XXX - Both static and dynamic allocation of any of these structures
+ * will result in a valid, well-aligned thread pointer???
+ */
+struct arm_tp {
+ struct tdv *tp_tdv; /* dynamic TLS */
+};
+
+struct tcb {
+ struct pthread *tcb_thread;
+ struct kcb *tcb_curkcb;
+ uint32_t tcb_isfake;
+ struct kse_thr_mailbox tcb_tmbx; /* needs 32-byte alignment */
+ struct arm_tp tcb_tp;
+};
+
+struct kcb {
+ struct kse_mailbox kcb_kmbx;
+ struct tcb kcb_faketcb;
+ struct tcb *kcb_curtcb;
+ struct kse *kcb_kse;
+};
+
+extern struct arm_tp **arm_tp;
+#define _tp (*arm_tp)
+
+#define _tcb ((struct tcb*)((char*)(_tp) - offsetof(struct tcb, tcb_tp)))
+
+/*
+ * The kcb and tcb constructors.
+ */
+struct tcb *_tcb_ctor(struct pthread *, int);
+void _tcb_dtor(struct tcb *);
+struct kcb *_kcb_ctor(struct kse *kse);
+void _kcb_dtor(struct kcb *);
+
+static __inline uint32_t
+__kcb_swp(uint32_t val, void *ptr)
+{
+
+ __asm __volatile("swp %0, %1, [%2]"
+ : "=r" (val) : "r" (val) , "r" (ptr) : "memory");
+ return (val);
+}
+
+/* Called from the KSE to set its private data. */
+static __inline void
+_kcb_set(struct kcb *kcb)
+{
+ /* There is no thread yet; use the fake tcb. */
+ __kcb_swp((uint32_t)&kcb->kcb_faketcb.tcb_tp, &_tp);
+}
+
+/*
+ * Get the current kcb.
+ *
+ * This can only be called while in a critical region; don't
+ * worry about having the kcb changed out from under us.
+ */
+static __inline struct kcb *
+_kcb_get(void)
+{
+ return (_tcb->tcb_curkcb);
+}
+
+/*
+ * Enter a critical region.
+ *
+ * Read and clear km_curthread in the kse mailbox.
+ */
+static __inline struct kse_thr_mailbox *
+_kcb_critical_enter(void)
+{
+ struct kse_thr_mailbox *crit;
+
+ if (_tcb->tcb_isfake)
+ return (NULL);
+ crit = (struct kse_thr_mailbox *)__kcb_swp((uint32_t)NULL,
+ &_tcb->tcb_curkcb->kcb_kmbx.km_curthread);
+ return (crit);
+}
+
+static __inline void
+_kcb_critical_leave(struct kse_thr_mailbox *crit)
+{
+
+ if (_tcb->tcb_isfake == 0)
+ __kcb_swp((uint32_t)crit,
+ &_tcb->tcb_curkcb->kcb_kmbx.km_curthread);
+}
+
+static __inline int
+_kcb_in_critical(void)
+{
+ uint32_t flags;
+ int ret;
+
+ return (_tcb->tcb_curkcb->kcb_kmbx.km_curthread == NULL);
+ if (_tcb->tcb_isfake != 0) {
+ /*
+ * We are in a critical region since there is no
+ * current thread.
+ */
+ ret = 1;
+ } else {
+ flags = _tcb->tcb_tmbx.tm_flags;
+ _tcb->tcb_tmbx.tm_flags |= TMF_NOUPCALL;
+ ret = (_tcb->tcb_curkcb->kcb_kmbx.km_curthread == NULL);
+ _tcb->tcb_tmbx.tm_flags = flags;
+ }
+ return (ret);
+}
+
+static __inline void
+_tcb_set(struct kcb *kcb, struct tcb *tcb)
+{
+ if (tcb == NULL)
+ tcb = &kcb->kcb_faketcb;
+ __kcb_swp((uint32_t)&tcb->tcb_tp, &_tp);
+ kcb->kcb_curtcb = tcb;
+ tcb->tcb_curkcb = kcb;
+}
+
+static __inline struct tcb *
+_tcb_get(void)
+{
+ return (_tcb);
+}
+
+static __inline struct pthread *
+_get_curthread(void)
+{
+ return (_tcb->tcb_thread);
+}
+
+/*
+ * Get the current kse.
+ *
+ * Like _kcb_get(), this can only be called while in a critical region.
+ */
+static __inline struct kse *
+_get_curkse(void)
+{
+ return (_tcb->tcb_curkcb->kcb_kse);
+}
+
+void _arm_enter_uts(struct kse_mailbox *km, kse_func_t uts, void *stack,
+ size_t stacksz);
+
+static __inline int
+_thread_enter_uts(struct tcb *tcb, struct kcb *kcb)
+{
+ int ret;
+
+ if ((ret = _thr_getcontext(&tcb->tcb_tmbx.tm_context.uc_mcontext))
+ == 0) {
+ kcb->kcb_curtcb = &kcb->kcb_faketcb;
+ __kcb_swp((int)&kcb->kcb_faketcb.tcb_tp, &_tp);
+ _arm_enter_uts(&kcb->kcb_kmbx, kcb->kcb_kmbx.km_func,
+ kcb->kcb_kmbx.km_stack.ss_sp,
+ kcb->kcb_kmbx.km_stack.ss_size);
+ /* We should not reach here. */
+ return (-1);
+ } else if (ret < 0)
+ return (-1);
+ return (0);
+}
+
+static __inline int
+_thread_switch(struct kcb *kcb, struct tcb *tcb, int setmbox)
+{
+ extern int _libkse_debug;
+ mcontext_t *mc;
+
+ if (!tcb || !kcb)
+ return (-1);
+ _tcb_set(kcb, tcb);
+ mc = &tcb->tcb_tmbx.tm_context.uc_mcontext;
+ if (_libkse_debug == 0) {
+ tcb->tcb_tmbx.tm_lwp = kcb->kcb_kmbx.km_lwp;
+ if (setmbox)
+ _thr_setcontext(mc, (intptr_t)&tcb->tcb_tmbx,
+ (intptr_t *)&kcb->kcb_kmbx.km_curthread);
+ else
+ _thr_setcontext(mc, 0, NULL);
+ } else {
+ if (setmbox)
+ kse_switchin(&tcb->tcb_tmbx, KSE_SWITCHIN_SETTMBX);
+ else
+ kse_switchin(&tcb->tcb_tmbx, 0);
+ }
+
+ /* We should not reach here. */
+ return (-1);
+}
+
+#endif /* _PTHREAD_MD_H_ */
diff --git a/lib/libpthread/arch/i386/Makefile.inc b/lib/libpthread/arch/i386/Makefile.inc
new file mode 100644
index 0000000..73a9a8a
--- /dev/null
+++ b/lib/libpthread/arch/i386/Makefile.inc
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}/${MACHINE_ARCH}
+
+SRCS+= thr_enter_uts.S thr_getcontext.S pthread_md.c
diff --git a/lib/libpthread/arch/i386/i386/pthread_md.c b/lib/libpthread/arch/i386/i386/pthread_md.c
new file mode 100644
index 0000000..cbea6d4
--- /dev/null
+++ b/lib/libpthread/arch/i386/i386/pthread_md.c
@@ -0,0 +1,100 @@
+/*-
+ * Copyright (C) 2003 David Xu <davidxu@freebsd.org>
+ * Copyright (c) 2001,2003 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <machine/cpufunc.h>
+#include <machine/sysarch.h>
+
+#include <unistd.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ucontext.h>
+
+#include "rtld_tls.h"
+#include "pthread_md.h"
+
+struct tcb *
+_tcb_ctor(struct pthread *thread, int initial)
+{
+ struct tcb *tcb;
+ void *oldtls;
+
+ if (initial) {
+ __asm __volatile("movl %%gs:0, %0" : "=r" (oldtls));
+ } else {
+ oldtls = NULL;
+ }
+
+ tcb = _rtld_allocate_tls(oldtls, sizeof(struct tcb), 16);
+ if (tcb) {
+ tcb->tcb_thread = thread;
+ tcb->tcb_spare = 0;
+ bzero(&tcb->tcb_tmbx, sizeof(tcb->tcb_tmbx));
+ }
+
+ return (tcb);
+}
+
+void
+_tcb_dtor(struct tcb *tcb)
+{
+ _rtld_free_tls(tcb, sizeof(struct tcb), 16);
+}
+
+/*
+ * Initialize KSD. This also includes setting up the LDT.
+ */
+struct kcb *
+_kcb_ctor(struct kse *kse)
+{
+ struct kcb *kcb;
+
+ kcb = malloc(sizeof(struct kcb));
+ if (kcb != NULL) {
+ bzero(kcb, sizeof(struct kcb));
+ kcb->kcb_self = kcb;
+ kcb->kcb_kse = kse;
+ }
+ return (kcb);
+}
+
+void
+_kcb_dtor(struct kcb *kcb)
+{
+ free(kcb);
+}
+
+int
+i386_set_gsbase(void *addr)
+{
+
+ return (sysarch(I386_SET_GSBASE, &addr));
+}
diff --git a/lib/libpthread/arch/i386/i386/thr_enter_uts.S b/lib/libpthread/arch/i386/i386/thr_enter_uts.S
new file mode 100644
index 0000000..bf6df8f
--- /dev/null
+++ b/lib/libpthread/arch/i386/i386/thr_enter_uts.S
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2002 Jonathan Mini <mini@freebsd.org>.
+ * 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 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 <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+
+/*
+ * _i386_enter_uts(struct kse_mailbox *km, kse_func_t uts, void *stack,
+ * long stacksz);
+ * +4 = km, +8 = uts, +12 = stack, +16 = size
+ */
+ENTRY(_i386_enter_uts)
+ movl %esp, %edx /* save stack */
+ movl 12(%edx), %eax /* get bottom of stack */
+ addl 16(%edx), %eax /* add length */
+ movl %eax, %esp /* switch to uts stack */
+ pushl 4(%edx) /* push the address of the mailbox */
+ call *8(%edx)
+ ret
diff --git a/lib/libpthread/arch/i386/i386/thr_getcontext.S b/lib/libpthread/arch/i386/i386/thr_getcontext.S
new file mode 100644
index 0000000..d9d300f
--- /dev/null
+++ b/lib/libpthread/arch/i386/i386/thr_getcontext.S
@@ -0,0 +1,156 @@
+/*-
+ * 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 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 <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Where do we define these?
+ */
+#define MC_LEN_OFFSET 80 /* offset to mc_len from mcontext */
+#define MC_LEN 640 /* mc_len <machine/ucontext.h> */
+#define MC_FPFMT_OFFSET 84
+#define MC_FPFMT_NODEV 0x10000
+#define MC_FPFMT_387 0x10001
+#define MC_FPFMT_XMM 0x10002
+#define MC_OWNEDFP_OFFSET 88
+#define MC_OWNEDFP_NONE 0x20000
+#define MC_OWNEDFP_FPU 0x20001
+#define MC_OWNEDFP_PCB 0x20002
+#define MC_FPREGS_OFFSET 96 /* offset to FP regs from mcontext */
+#define MC_FP_CW_OFFSET 96 /* offset to FP control word */
+
+/*
+ * int thr_setcontext(mcontext_t *mcp, intptr_t val, intptr_t *loc)
+ *
+ * Restores the context in mcp.
+ *
+ * Returns 0 if there are no errors; -1 otherwise
+ */
+ .weak CNAME(_thr_setcontext)
+ .set CNAME(_thr_setcontext),CNAME(__thr_setcontext)
+ENTRY(__thr_setcontext)
+ movl 4(%esp), %edx /* get address of mcontext */
+ cmpl $0, %edx /* check for null pointer */
+ jne 1f
+ movl $-1, %eax
+ jmp 8f
+1: cmpl $MC_LEN, MC_LEN_OFFSET(%edx) /* is context valid? */
+ je 2f
+ movl $-1, %eax /* bzzzt, invalid context */
+ jmp 8f
+2: /*movl 4(%edx), %gs*/ /* we don't touch %gs */
+ movw 8(%edx), %fs
+ movw 12(%edx), %es
+ movw 16(%edx), %ds
+ movw 76(%edx), %ss
+ movl 20(%edx), %edi
+ movl 24(%edx), %esi
+ movl 28(%edx), %ebp
+ movl %esp, %ecx /* save current stack in ecx */
+ movl 72(%edx), %esp /* switch to context defined stack */
+ pushl 60(%edx) /* push return address on stack */
+ pushl 44(%edx) /* push ecx on stack */
+ pushl 48(%edx) /* push eax on stack */
+ /*
+ * if (mc_fpowned == MC_OWNEDFP_FPU || mc_fpowned == MC_OWNEDFP_PCB) {
+ * if (mc_fpformat == MC_FPFMT_387)
+ * restore 387 FP register format
+ * else if (mc_fpformat == MC_FPFMT_XMM)
+ * restore XMM/SSE FP register format
+ * }
+ */
+ cmpl $MC_OWNEDFP_FPU, MC_OWNEDFP_OFFSET(%edx)
+ je 3f
+ cmpl $MC_OWNEDFP_PCB, MC_OWNEDFP_OFFSET(%edx)
+ jne 5f
+3: cmpl $MC_FPFMT_387, MC_FPFMT_OFFSET(%edx)
+ jne 4f
+ frstor MC_FPREGS_OFFSET(%edx) /* restore 387 FP regs */
+ jmp 6f
+4: cmpl $MC_FPFMT_XMM, MC_FPFMT_OFFSET(%edx)
+ jne 5f
+ fxrstor MC_FPREGS_OFFSET(%edx) /* restore XMM FP regs */
+ jmp 6f
+5: fninit
+ fldcw MC_FP_CW_OFFSET(%edx)
+6: pushl 68(%edx) /* push flags register on stack*/
+ movl 36(%edx), %ebx /* restore ebx and edx */
+ movl 40(%edx), %edx
+ movl 12(%ecx), %eax /* get 3rd arg (loc) */
+ cmpl $0, %eax /* do nothing if loc == null */
+ je 7f
+ movl 8(%ecx), %ecx /* get 2nd arg (val) */
+ movl %ecx, (%eax) /* set loc = val */
+7: popfl /* restore flags after test */
+ popl %eax /* restore eax and ecx last */
+ popl %ecx
+8: ret
+
+/*
+ * int thr_getcontext(mcontext_t *mcp);
+ *
+ * Returns -1 if there is an error, 0 no errors; 1 upon return
+ * from a setcontext().
+ */
+ .weak CNAME(_thr_getcontext)
+ .set CNAME(_thr_getcontext),CNAME(__thr_getcontext)
+ENTRY(__thr_getcontext)
+ pushl %edx /* save edx */
+ movl 8(%esp), %edx /* get address of mcontext */
+ cmpl $0, %edx /* check for null pointer */
+ jne 1f
+ popl %edx /* restore edx and stack */
+ movl $-1, %eax
+ jmp 2f
+1: /*movw %gs, 4(%edx)*/ /* we don't touch %gs */
+ movw %fs, 8(%edx)
+ movw %es, 12(%edx)
+ movw %ds, 16(%edx)
+ movw %ss, 76(%edx)
+ movl %edi, 20(%edx)
+ movl %esi, 24(%edx)
+ movl %ebp, 28(%edx)
+ movl %ebx, 36(%edx)
+ movl $1, 48(%edx) /* store successful return in eax */
+ popl %eax /* get saved value of edx */
+ movl %eax, 40(%edx) /* save edx */
+ movl %ecx, 44(%edx)
+ movl (%esp), %eax /* get return address */
+ movl %eax, 60(%edx) /* save return address */
+ fnstcw MC_FP_CW_OFFSET(%edx)
+ movl $MC_LEN, MC_LEN_OFFSET(%edx)
+ movl $MC_FPFMT_NODEV, MC_FPFMT_OFFSET(%edx) /* no FP */
+ movl $MC_OWNEDFP_NONE, MC_OWNEDFP_OFFSET(%edx) /* no FP */
+ pushfl
+ popl %eax /* get eflags */
+ movl %eax, 68(%edx) /* store eflags */
+ movl %esp, %eax /* setcontext pushes the return */
+ addl $4, %eax /* address onto the top of the */
+ movl %eax, 72(%edx) /* stack; account for this */
+ movl 40(%edx), %edx /* restore edx -- is this needed? */
+ xorl %eax, %eax /* return 0 */
+2: ret
diff --git a/lib/libpthread/arch/i386/include/atomic_ops.h b/lib/libpthread/arch/i386/include/atomic_ops.h
new file mode 100644
index 0000000..7bc3d1b
--- /dev/null
+++ b/lib/libpthread/arch/i386/include/atomic_ops.h
@@ -0,0 +1,51 @@
+/*-
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _ATOMIC_OPS_H_
+#define _ATOMIC_OPS_H_
+
+/*
+ * Atomic swap:
+ * Atomic (tmp = *dst, *dst = val), then *res = tmp
+ *
+ * void atomic_swap32(intptr_t *dst, intptr_t val, intptr_t *res);
+ */
+static inline void
+atomic_swap32(intptr_t *dst, intptr_t val, intptr_t *res)
+{
+ __asm __volatile(
+ "xchgl %2, %1; movl %2, %0"
+ : "=m" (*res) : "m" (*dst), "r" (val) : "memory");
+}
+
+#define atomic_swap_ptr(d, v, r) \
+ atomic_swap32((intptr_t *)d, (intptr_t)v, (intptr_t *)r)
+
+#define atomic_swap_int(d, v, r) \
+ atomic_swap32((intptr_t *)d, (intptr_t)v, (intptr_t *)r)
+#endif
diff --git a/lib/libpthread/arch/i386/include/pthread_md.h b/lib/libpthread/arch/i386/include/pthread_md.h
new file mode 100644
index 0000000..52afd6a
--- /dev/null
+++ b/lib/libpthread/arch/i386/include/pthread_md.h
@@ -0,0 +1,264 @@
+/*-
+ * Copyright (c) 2002 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+/*
+ * Machine-dependent thread prototypes/definitions for the thread kernel.
+ */
+#ifndef _PTHREAD_MD_H_
+#define _PTHREAD_MD_H_
+
+#include <stddef.h>
+#include <sys/types.h>
+#include <sys/kse.h>
+#include <machine/sysarch.h>
+#include <ucontext.h>
+
+extern int _thr_setcontext(mcontext_t *, intptr_t, intptr_t *);
+extern int _thr_getcontext(mcontext_t *);
+
+#define KSE_STACKSIZE 16384
+#define DTV_OFFSET offsetof(struct tcb, tcb_dtv)
+
+#define THR_GETCONTEXT(ucp) _thr_getcontext(&(ucp)->uc_mcontext)
+#define THR_SETCONTEXT(ucp) _thr_setcontext(&(ucp)->uc_mcontext, 0, NULL)
+
+#define PER_KSE
+#undef PER_THREAD
+
+struct kse;
+struct pthread;
+
+/*
+ * %gs points to a struct kcb.
+ */
+struct kcb {
+ struct tcb *kcb_curtcb;
+ struct kcb *kcb_self; /* self reference */
+ struct kse *kcb_kse;
+ struct kse_mailbox kcb_kmbx;
+};
+
+struct tcb {
+ struct tcb *tcb_self; /* required by rtld */
+ void *tcb_dtv; /* required by rtld */
+ struct pthread *tcb_thread;
+ void *tcb_spare; /* align tcb_tmbx to 16 bytes */
+ struct kse_thr_mailbox tcb_tmbx;
+};
+
+/*
+ * Evaluates to the byte offset of the per-kse variable name.
+ */
+#define __kcb_offset(name) __offsetof(struct kcb, name)
+
+/*
+ * Evaluates to the type of the per-kse variable name.
+ */
+#define __kcb_type(name) __typeof(((struct kcb *)0)->name)
+
+/*
+ * Evaluates to the value of the per-kse variable name.
+ */
+#define KCB_GET32(name) ({ \
+ __kcb_type(name) __result; \
+ \
+ u_int __i; \
+ __asm __volatile("movl %%gs:%1, %0" \
+ : "=r" (__i) \
+ : "m" (*(u_int *)(__kcb_offset(name)))); \
+ __result = (__kcb_type(name))__i; \
+ \
+ __result; \
+})
+
+/*
+ * Sets the value of the per-kse variable name to value val.
+ */
+#define KCB_SET32(name, val) ({ \
+ __kcb_type(name) __val = (val); \
+ \
+ u_int __i; \
+ __i = (u_int)__val; \
+ __asm __volatile("movl %1,%%gs:%0" \
+ : "=m" (*(u_int *)(__kcb_offset(name))) \
+ : "r" (__i)); \
+})
+
+static __inline u_long
+__kcb_readandclear32(volatile u_long *addr)
+{
+ u_long result;
+
+ __asm __volatile (
+ " xorl %0, %0;"
+ " xchgl %%gs:%1, %0;"
+ "# __kcb_readandclear32"
+ : "=&r" (result)
+ : "m" (*addr));
+ return (result);
+}
+
+#define KCB_READANDCLEAR32(name) ({ \
+ __kcb_type(name) __result; \
+ \
+ __result = (__kcb_type(name)) \
+ __kcb_readandclear32((u_long *)__kcb_offset(name)); \
+ __result; \
+})
+
+
+#define _kcb_curkcb() KCB_GET32(kcb_self)
+#define _kcb_curtcb() KCB_GET32(kcb_curtcb)
+#define _kcb_curkse() ((struct kse *)KCB_GET32(kcb_kmbx.km_udata))
+#define _kcb_get_tmbx() KCB_GET32(kcb_kmbx.km_curthread)
+#define _kcb_set_tmbx(value) KCB_SET32(kcb_kmbx.km_curthread, (void *)value)
+#define _kcb_readandclear_tmbx() KCB_READANDCLEAR32(kcb_kmbx.km_curthread)
+
+
+/*
+ * The constructors.
+ */
+struct tcb *_tcb_ctor(struct pthread *, int);
+void _tcb_dtor(struct tcb *tcb);
+struct kcb *_kcb_ctor(struct kse *);
+void _kcb_dtor(struct kcb *);
+
+/* Called from the KSE to set its private data. */
+static __inline void
+_kcb_set(struct kcb *kcb)
+{
+ i386_set_gsbase(kcb);
+}
+
+/* Get the current kcb. */
+static __inline struct kcb *
+_kcb_get(void)
+{
+ return (_kcb_curkcb());
+}
+
+static __inline struct kse_thr_mailbox *
+_kcb_critical_enter(void)
+{
+ struct kse_thr_mailbox *crit;
+
+ crit = _kcb_readandclear_tmbx();
+ return (crit);
+}
+
+static __inline void
+_kcb_critical_leave(struct kse_thr_mailbox *crit)
+{
+ _kcb_set_tmbx(crit);
+}
+
+static __inline int
+_kcb_in_critical(void)
+{
+ return (_kcb_get_tmbx() == NULL);
+}
+
+static __inline void
+_tcb_set(struct kcb *kcb, struct tcb *tcb)
+{
+ kcb->kcb_curtcb = tcb;
+}
+
+static __inline struct tcb *
+_tcb_get(void)
+{
+ return (_kcb_curtcb());
+}
+
+static __inline struct pthread *
+_get_curthread(void)
+{
+ struct tcb *tcb;
+
+ tcb = _kcb_curtcb();
+ if (tcb != NULL)
+ return (tcb->tcb_thread);
+ else
+ return (NULL);
+}
+
+static __inline struct kse *
+_get_curkse(void)
+{
+ return ((struct kse *)_kcb_curkse());
+}
+
+void _i386_enter_uts(struct kse_mailbox *km, kse_func_t uts, void *stack,
+ size_t stacksz);
+
+static __inline int
+_thread_enter_uts(struct tcb *tcb, struct kcb *kcb)
+{
+ int ret;
+
+ ret = _thr_getcontext(&tcb->tcb_tmbx.tm_context.uc_mcontext);
+ if (ret == 0) {
+ _i386_enter_uts(&kcb->kcb_kmbx, kcb->kcb_kmbx.km_func,
+ kcb->kcb_kmbx.km_stack.ss_sp,
+ kcb->kcb_kmbx.km_stack.ss_size);
+ /* We should not reach here. */
+ return (-1);
+ }
+ else if (ret < 0)
+ return (-1);
+ return (0);
+}
+
+static __inline int
+_thread_switch(struct kcb *kcb, struct tcb *tcb, int setmbox)
+{
+ extern int _libkse_debug;
+
+ if ((kcb == NULL) || (tcb == NULL))
+ return (-1);
+ kcb->kcb_curtcb = tcb;
+ if (_libkse_debug == 0) {
+ tcb->tcb_tmbx.tm_lwp = kcb->kcb_kmbx.km_lwp;
+ if (setmbox != 0)
+ _thr_setcontext(&tcb->tcb_tmbx.tm_context.uc_mcontext,
+ (intptr_t)&tcb->tcb_tmbx,
+ (intptr_t *)&kcb->kcb_kmbx.km_curthread);
+ else
+ _thr_setcontext(&tcb->tcb_tmbx.tm_context.uc_mcontext,
+ 0, NULL);
+ } else {
+ if (setmbox)
+ kse_switchin(&tcb->tcb_tmbx, KSE_SWITCHIN_SETTMBX);
+ else
+ kse_switchin(&tcb->tcb_tmbx, 0);
+ }
+
+ /* We should not reach here. */
+ return (-1);
+}
+
+#endif
diff --git a/lib/libpthread/arch/ia64/Makefile.inc b/lib/libpthread/arch/ia64/Makefile.inc
new file mode 100644
index 0000000..c8b0362
--- /dev/null
+++ b/lib/libpthread/arch/ia64/Makefile.inc
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}/${MACHINE_ARCH}
+
+SRCS+= context.S enter_uts.S pthread_md.c
diff --git a/lib/libpthread/arch/ia64/ia64/context.S b/lib/libpthread/arch/ia64/ia64/context.S
new file mode 100644
index 0000000..9411293
--- /dev/null
+++ b/lib/libpthread/arch/ia64/ia64/context.S
@@ -0,0 +1,351 @@
+/*
+ * 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 <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/syscall.h>
+
+#define SIZEOF_SPECIAL (18*8)
+
+/*
+ * int _ia64_restore_context(mcontext_t *mc, intptr_t val, intptr_t *loc);
+ */
+ENTRY(_ia64_restore_context, 3)
+{ .mmi
+ invala
+ mov ar.rsc=0xc
+ add r32=16,r32
+ ;;
+}
+{ .mmi
+ loadrs
+ ld8 r12=[r32] // sp
+ add r31=8,r32
+ ;;
+}
+{ .mii
+ ld8 r16=[r31],16 // unat (before)
+ add r30=16,r32
+ add r14=SIZEOF_SPECIAL,r32
+ ;;
+}
+{ .mmi
+ ld8 r17=[r30],16 // rp
+ ld8 r18=[r31],16 // pr
+ mov r2=r33
+ ;;
+}
+{ .mmi
+ ld8 r19=[r30],16 // pfs
+ ld8 r20=[r31],32 // bspstore
+ mov rp=r17
+ ;;
+}
+{ .mmi
+ ld8 r21=[r30],32 // rnat
+ ld8 r22=[r31],16 // rsc
+ mov pr=r18,0x1fffe
+ ;;
+}
+{ .mmi
+ ld8 r23=[r30] // fpsr
+ ld8 r24=[r31] // psr -- not used
+ mov r3=r34
+ ;;
+}
+{ .mmi
+ ld8 r17=[r14],8 // unat (after)
+ mov ar.bspstore=r20
+ cmp.ne p15,p0=r0,r3
+ ;;
+}
+{ .mmi
+ mov ar.rnat=r21
+ mov ar.unat=r17
+ add r15=8,r14
+ ;;
+}
+{ .mmi
+ ld8.fill r4=[r14],16 // r4
+ ld8.fill r5=[r15],16 // r5
+ mov ar.pfs=r19
+ ;;
+}
+{ .mmi
+ ld8.fill r6=[r14],16 // r6
+ ld8.fill r7=[r15],16 // r7
+ nop 0
+ ;;
+}
+{ .mmi
+ mov ar.unat=r16
+ mov ar.rsc=r22
+ nop 0
+}
+{ .mmi
+ ld8 r17=[r14],16 // b1
+ ld8 r18=[r15],16 // b2
+ nop 0
+ ;;
+}
+{ .mmi
+ ld8 r19=[r14],16 // b3
+ ld8 r20=[r15],16 // b4
+ mov b1=r17
+ ;;
+}
+{ .mmi
+ ld8 r16=[r14],24 // b5
+ ld8 r17=[r15],32 // lc
+ mov b2=r18
+ ;;
+}
+{ .mmi
+ ldf.fill f2=[r14],32
+ ldf.fill f3=[r15],32
+ mov b3=r19
+ ;;
+}
+{ .mmi
+ ldf.fill f4=[r14],32
+ ldf.fill f5=[r15],32
+ mov b4=r20
+ ;;
+}
+{ .mmi
+ ldf.fill f16=[r14],32
+ ldf.fill f17=[r15],32
+ mov b5=r16
+ ;;
+}
+{ .mmi
+ ldf.fill f18=[r14],32
+ ldf.fill f19=[r15],32
+ mov ar.lc=r17
+ ;;
+}
+ ldf.fill f20=[r14],32
+ ldf.fill f21=[r15],32
+ ;;
+ ldf.fill f22=[r14],32
+ ldf.fill f23=[r15],32
+ ;;
+ ldf.fill f24=[r14],32
+ ldf.fill f25=[r15],32
+ ;;
+ ldf.fill f26=[r14],32
+ ldf.fill f27=[r15],32
+ ;;
+ ldf.fill f28=[r14],32
+ ldf.fill f29=[r15],32
+ ;;
+ ldf.fill f30=[r14],32+24
+ ldf.fill f31=[r15],24+24
+ ;;
+ ld8 r8=[r14],16
+ ld8 r9=[r15],16
+ ;;
+ ld8 r10=[r14]
+ ld8 r11=[r15]
+ ;;
+{ .mmb
+(p15) st8 [r3]=r2
+ mov ar.fpsr=r23
+ br.ret.sptk rp
+ ;;
+}
+END(_ia64_restore_context)
+
+/*
+ * int _ia64_save_context(mcontext_t *mc);
+ */
+ENTRY(_ia64_save_context, 1)
+{ .mmi
+ mov r14=ar.rsc
+ mov r15=ar.fpsr
+ add r31=8,r32
+ ;;
+}
+{ .mmi
+ st8 [r32]=r0,16
+ st8 [r31]=r0,16
+ nop 0
+ ;;
+}
+{ .mmi
+ mov ar.rsc=0xc
+ mov r16=ar.unat
+ nop 0
+ ;;
+}
+{ .mmi
+ flushrs
+ st8 [r32]=sp,16 // sp
+ mov r17=rp
+ ;;
+}
+{ .mmi
+ st8 [r31]=r16,16 // unat (before)
+ st8 [r32]=r17,16 // rp
+ mov r16=pr
+ ;;
+}
+{ .mmi
+ st8 [r31]=r16,16 // pr
+ mov r17=ar.bsp
+ mov r16=ar.pfs
+ ;;
+}
+{ .mmi
+ st8 [r32]=r16,16 // pfs
+ st8 [r31]=r17,16 // bspstore
+ nop 0
+ ;;
+}
+{ .mmi
+ mov r16=ar.rnat
+ mov ar.rsc=r14
+ add r30=SIZEOF_SPECIAL-(6*8),r32
+ ;;
+}
+{ .mmi
+ st8 [r32]=r16,16 // rnat
+ st8 [r31]=r0,16 // __spare
+ nop 0
+ ;;
+}
+{ .mmi
+ st8 [r32]=r13,16 // tp -- not used
+ st8 [r31]=r14,16 // rsc
+ mov r16=b1
+ ;;
+}
+{ .mmi
+ st8 [r32]=r15,10*8 // fpr
+ st8 [r31]=r0,8*8 // psr
+ nop 0
+ ;;
+}
+ /* callee_saved */
+{ .mmi
+ .mem.offset 8,0
+ st8.spill [r31]=r4,16 // r4
+ .mem.offset 16,0
+ st8.spill [r32]=r5,16 // r5
+ mov r17=b2
+ ;;
+}
+{ .mmi
+ .mem.offset 24,0
+ st8.spill [r31]=r6,16 // r6
+ .mem.offset 32,0
+ st8.spill [r32]=r7,16 // r7
+ mov r18=b3
+ ;;
+}
+{ .mmi
+ st8 [r31]=r16,16 // b1
+ mov r16=ar.unat
+ mov r19=b4
+ ;;
+}
+{ .mmi
+ st8 [r30]=r16 // unat (after)
+ st8 [r32]=r17,16 // b2
+ mov r16=b5
+ ;;
+}
+{ .mmi
+ st8 [r31]=r18,16 // b3
+ st8 [r32]=r19,16 // b4
+ mov r17=ar.lc
+ ;;
+}
+ st8 [r31]=r16,16 // b5
+ st8 [r32]=r17,16 // lc
+ ;;
+ st8 [r31]=r0,24 // __spare
+ stf.spill [r32]=f2,32
+ ;;
+ stf.spill [r31]=f3,32
+ stf.spill [r32]=f4,32
+ ;;
+ stf.spill [r31]=f5,32
+ stf.spill [r32]=f16,32
+ ;;
+ stf.spill [r31]=f17,32
+ stf.spill [r32]=f18,32
+ ;;
+ stf.spill [r31]=f19,32
+ stf.spill [r32]=f20,32
+ ;;
+ stf.spill [r31]=f21,32
+ stf.spill [r32]=f22,32
+ ;;
+ stf.spill [r31]=f23,32
+ stf.spill [r32]=f24,32
+ ;;
+ stf.spill [r31]=f25,32
+ stf.spill [r32]=f26,32
+ ;;
+ stf.spill [r31]=f27,32
+ stf.spill [r32]=f28,32
+ ;;
+{ .mmi
+ stf.spill [r31]=f29,32
+ stf.spill [r32]=f30,32+24
+ add r14=1,r0
+ ;;
+}
+{ .mmi
+ stf.spill [r31]=f31,24+24
+ st8 [r32]=r14,16 // r8
+ add r8=0,r0
+ ;;
+}
+ st8 [r31]=r0,16 // r9
+ st8 [r32]=r0 // r10
+ ;;
+{ .mmb
+ st8 [r31]=r0 // r11
+ mf
+ br.ret.sptk rp
+ ;;
+}
+END(_ia64_save_context)
+
+/*
+ * void _ia64_break_setcontext(mcontext_t *mc);
+ */
+ENTRY(_ia64_break_setcontext, 1)
+{ .mmi
+ mov r8=r32
+ break 0x180000
+ nop 0
+ ;;
+}
+END(_ia64_break_setcontext)
diff --git a/lib/libpthread/arch/ia64/ia64/enter_uts.S b/lib/libpthread/arch/ia64/ia64/enter_uts.S
new file mode 100644
index 0000000..5df4d93
--- /dev/null
+++ b/lib/libpthread/arch/ia64/ia64/enter_uts.S
@@ -0,0 +1,60 @@
+/*
+ * 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 <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * void _ia64_enter_uts(kse_func_t uts, struct kse_mailbox *km, void *stack,
+ * size_t stacksz);
+ */
+ENTRY(_ia64_enter_uts, 4)
+{ .mmi
+ ld8 r14=[in0],8
+ mov ar.rsc=0xc
+ add r15=in2,in3
+ ;;
+}
+{ .mmi
+ flushrs
+ ld8 r1=[in0]
+ mov b7=r14
+ ;;
+}
+{ .mii
+ mov ar.bspstore=in2
+ add sp=-16,r15
+ mov rp=r14
+ ;;
+}
+{ .mib
+ mov ar.rsc=0xf
+ mov in0=in1
+ br.cond.sptk b7
+ ;;
+}
+1: br.cond.sptk 1b
+END(_ia64_enter_uts)
diff --git a/lib/libpthread/arch/ia64/ia64/pthread_md.c b/lib/libpthread/arch/ia64/ia64/pthread_md.c
new file mode 100644
index 0000000..00e9a40
--- /dev/null
+++ b/lib/libpthread/arch/ia64/ia64/pthread_md.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2003 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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, 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$
+ */
+
+#include <stdlib.h>
+#include <strings.h>
+#include "pthread_md.h"
+
+/*
+ * The constructors.
+ */
+struct tcb *
+_tcb_ctor(struct pthread *thread, int initial)
+{
+ struct tcb *tcb;
+
+ if ((tcb = malloc(sizeof(struct tcb))) != NULL) {
+ bzero(tcb, sizeof(struct tcb));
+ tcb->tcb_thread = thread;
+ /* Allocate TDV */
+ }
+ return (tcb);
+}
+
+void
+_tcb_dtor(struct tcb *tcb)
+{
+ /* Free TDV */
+ free(tcb);
+}
+
+struct kcb *
+_kcb_ctor(struct kse *kse)
+{
+ struct kcb *kcb;
+
+ if ((kcb = malloc(sizeof(struct kcb))) != NULL) {
+ bzero(kcb, sizeof(struct kcb));
+ kcb->kcb_faketcb.tcb_isfake = 1;
+ kcb->kcb_faketcb.tcb_tmbx.tm_flags = TMF_NOUPCALL;
+ kcb->kcb_curtcb = &kcb->kcb_faketcb;
+ kcb->kcb_kse = kse;
+ }
+ return (kcb);
+}
+
+void
+_kcb_dtor(struct kcb *kcb)
+{
+ free(kcb);
+}
diff --git a/lib/libpthread/arch/ia64/include/atomic_ops.h b/lib/libpthread/arch/ia64/include/atomic_ops.h
new file mode 100644
index 0000000..483c905
--- /dev/null
+++ b/lib/libpthread/arch/ia64/include/atomic_ops.h
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _ATOMIC_OPS_H_
+#define _ATOMIC_OPS_H_
+
+static inline void
+atomic_swap_int(int *dst, int val, int *res)
+{
+ __asm("xchg4 %0=[%2],%1" : "=r"(*res) : "r"(val), "r"(dst));
+}
+
+static inline void
+atomic_swap_long(long *dst, long val, long *res)
+{
+ __asm("xchg8 %0=[%2],%1" : "=r"(*res) : "r"(val), "r"(dst));
+}
+
+#define atomic_swap_ptr(d,v,r) \
+ atomic_swap_long((long*)d, (long)v, (long*)r)
+
+#endif /* _ATOMIC_OPS_H_ */
diff --git a/lib/libpthread/arch/ia64/include/pthread_md.h b/lib/libpthread/arch/ia64/include/pthread_md.h
new file mode 100644
index 0000000..1df5046
--- /dev/null
+++ b/lib/libpthread/arch/ia64/include/pthread_md.h
@@ -0,0 +1,252 @@
+/*
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _PTHREAD_MD_H_
+#define _PTHREAD_MD_H_
+
+#include <sys/kse.h>
+#include <stddef.h>
+#include <ucontext.h>
+
+#define KSE_STACKSIZE 16384
+#define DTV_OFFSET offsetof(struct tcb, tcb_tp.tp_tdv)
+
+#define THR_GETCONTEXT(ucp) _ia64_save_context(&(ucp)->uc_mcontext)
+#define THR_SETCONTEXT(ucp) PANIC("THR_SETCONTEXT() now in use!\n")
+
+#define PER_THREAD
+
+struct kcb;
+struct kse;
+struct pthread;
+struct tcb;
+struct tdv; /* We don't know what this is yet? */
+
+/*
+ * tp points to one of these. We define the static TLS as an array
+ * of long double to enforce 16-byte alignment of the TLS memory,
+ * struct ia64_tp, struct tcb and also struct kcb. Both static and
+ * dynamic allocation of any of these structures will result in a
+ * valid, well-aligned thread pointer.
+ */
+struct ia64_tp {
+ struct tdv *tp_tdv; /* dynamic TLS */
+ uint64_t _reserved_;
+ long double tp_tls[0]; /* static TLS */
+};
+
+struct tcb {
+ struct kse_thr_mailbox tcb_tmbx;
+ struct pthread *tcb_thread;
+ struct kcb *tcb_curkcb;
+ long tcb_isfake;
+ struct ia64_tp tcb_tp;
+};
+
+struct kcb {
+ struct kse_mailbox kcb_kmbx;
+ struct tcb kcb_faketcb;
+ struct tcb *kcb_curtcb;
+ struct kse *kcb_kse;
+};
+
+register struct ia64_tp *_tp __asm("%r13");
+
+#define _tcb ((struct tcb*)((char*)(_tp) - offsetof(struct tcb, tcb_tp)))
+
+/*
+ * The kcb and tcb constructors.
+ */
+struct tcb *_tcb_ctor(struct pthread *, int);
+void _tcb_dtor(struct tcb *);
+struct kcb *_kcb_ctor(struct kse *kse);
+void _kcb_dtor(struct kcb *);
+
+/* Called from the KSE to set its private data. */
+static __inline void
+_kcb_set(struct kcb *kcb)
+{
+ /* There is no thread yet; use the fake tcb. */
+ _tp = &kcb->kcb_faketcb.tcb_tp;
+}
+
+/*
+ * Get the current kcb.
+ *
+ * This can only be called while in a critical region; don't
+ * worry about having the kcb changed out from under us.
+ */
+static __inline struct kcb *
+_kcb_get(void)
+{
+ return (_tcb->tcb_curkcb);
+}
+
+/*
+ * Enter a critical region.
+ *
+ * Read and clear km_curthread in the kse mailbox.
+ */
+static __inline struct kse_thr_mailbox *
+_kcb_critical_enter(void)
+{
+ struct kse_thr_mailbox *crit;
+ uint32_t flags;
+
+ if (_tcb->tcb_isfake != 0) {
+ /*
+ * We already are in a critical region since
+ * there is no current thread.
+ */
+ crit = NULL;
+ } else {
+ flags = _tcb->tcb_tmbx.tm_flags;
+ _tcb->tcb_tmbx.tm_flags |= TMF_NOUPCALL;
+ crit = _tcb->tcb_curkcb->kcb_kmbx.km_curthread;
+ _tcb->tcb_curkcb->kcb_kmbx.km_curthread = NULL;
+ _tcb->tcb_tmbx.tm_flags = flags;
+ }
+ return (crit);
+}
+
+static __inline void
+_kcb_critical_leave(struct kse_thr_mailbox *crit)
+{
+ /* No need to do anything if this is a fake tcb. */
+ if (_tcb->tcb_isfake == 0)
+ _tcb->tcb_curkcb->kcb_kmbx.km_curthread = crit;
+}
+
+static __inline int
+_kcb_in_critical(void)
+{
+ uint32_t flags;
+ int ret;
+
+ if (_tcb->tcb_isfake != 0) {
+ /*
+ * We are in a critical region since there is no
+ * current thread.
+ */
+ ret = 1;
+ } else {
+ flags = _tcb->tcb_tmbx.tm_flags;
+ _tcb->tcb_tmbx.tm_flags |= TMF_NOUPCALL;
+ ret = (_tcb->tcb_curkcb->kcb_kmbx.km_curthread == NULL);
+ _tcb->tcb_tmbx.tm_flags = flags;
+ }
+ return (ret);
+}
+
+static __inline void
+_tcb_set(struct kcb *kcb, struct tcb *tcb)
+{
+ if (tcb == NULL)
+ tcb = &kcb->kcb_faketcb;
+ kcb->kcb_curtcb = tcb;
+ tcb->tcb_curkcb = kcb;
+ _tp = &tcb->tcb_tp;
+}
+
+static __inline struct tcb *
+_tcb_get(void)
+{
+ return (_tcb);
+}
+
+static __inline struct pthread *
+_get_curthread(void)
+{
+ return (_tcb->tcb_thread);
+}
+
+/*
+ * Get the current kse.
+ *
+ * Like _kcb_get(), this can only be called while in a critical region.
+ */
+static __inline struct kse *
+_get_curkse(void)
+{
+ return (_tcb->tcb_curkcb->kcb_kse);
+}
+
+void _ia64_break_setcontext(mcontext_t *mc);
+void _ia64_enter_uts(kse_func_t uts, struct kse_mailbox *km, void *stack,
+ size_t stacksz);
+int _ia64_restore_context(mcontext_t *mc, intptr_t val, intptr_t *loc);
+int _ia64_save_context(mcontext_t *mc);
+
+static __inline int
+_thread_enter_uts(struct tcb *tcb, struct kcb *kcb)
+{
+ if (_ia64_save_context(&tcb->tcb_tmbx.tm_context.uc_mcontext) == 0) {
+ /* Make the fake tcb the current thread. */
+ kcb->kcb_curtcb = &kcb->kcb_faketcb;
+ _tp = &kcb->kcb_faketcb.tcb_tp;
+ _ia64_enter_uts(kcb->kcb_kmbx.km_func, &kcb->kcb_kmbx,
+ kcb->kcb_kmbx.km_stack.ss_sp,
+ kcb->kcb_kmbx.km_stack.ss_size);
+ /* We should not reach here. */
+ return (-1);
+ }
+ return (0);
+}
+
+static __inline int
+_thread_switch(struct kcb *kcb, struct tcb *tcb, int setmbox)
+{
+ mcontext_t *mc;
+
+ _tcb_set(kcb, tcb);
+ mc = &tcb->tcb_tmbx.tm_context.uc_mcontext;
+ if (mc->mc_flags & _MC_FLAGS_ASYNC_CONTEXT) {
+ if (setmbox) {
+ mc->mc_flags |= _MC_FLAGS_KSE_SET_MBOX;
+ mc->mc_special.ifa =
+ (intptr_t)&kcb->kcb_kmbx.km_curthread;
+ mc->mc_special.isr = (intptr_t)&tcb->tcb_tmbx;
+ }
+ _ia64_break_setcontext(mc);
+ } else if (mc->mc_flags & _MC_FLAGS_SYSCALL_CONTEXT) {
+ if (setmbox)
+ kse_switchin(&tcb->tcb_tmbx, KSE_SWITCHIN_SETTMBX);
+ else
+ kse_switchin(&tcb->tcb_tmbx, 0);
+ } else {
+ if (setmbox)
+ _ia64_restore_context(mc, (intptr_t)&tcb->tcb_tmbx,
+ (intptr_t *)&kcb->kcb_kmbx.km_curthread);
+ else
+ _ia64_restore_context(mc, 0, NULL);
+ }
+ /* We should not reach here. */
+ return (-1);
+}
+
+#endif /* _PTHREAD_MD_H_ */
diff --git a/lib/libpthread/arch/powerpc/Makefile.inc b/lib/libpthread/arch/powerpc/Makefile.inc
new file mode 100644
index 0000000..f4417a6
--- /dev/null
+++ b/lib/libpthread/arch/powerpc/Makefile.inc
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+# XXX temporary
+CFLAGS+=-DSYSTEM_SCOPE_ONLY
+
+.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}/${MACHINE_ARCH}
+
+SRCS+= enter_uts.S context.S pthread_md.c
diff --git a/lib/libpthread/arch/powerpc/include/atomic_ops.h b/lib/libpthread/arch/powerpc/include/atomic_ops.h
new file mode 100644
index 0000000..8068e6f
--- /dev/null
+++ b/lib/libpthread/arch/powerpc/include/atomic_ops.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2004 by 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.
+ * 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$
+ */
+
+#ifndef _ATOMIC_OPS_H_
+#define _ATOMIC_OPS_H_
+
+/*
+ * Atomic swap:
+ * Atomic (tmp = *dst, *dst = val), then *res = tmp
+ *
+ * void atomic_swap32(intptr_t *dst, intptr_t val, intptr_t *res);
+ */
+static inline void
+atomic_swap32(intptr_t *dst, intptr_t val, intptr_t *res)
+{
+ int tmp;
+
+ tmp = 0; /* should be a better way to quieten cc1... */
+#ifdef __GNUC__
+ __asm __volatile(
+ "1: lwarx %0, 0, %4\n" /* load with reservation */
+ " stwcx. %3, 0, %4\n" /* attempt to store val */
+ " bne- 1b\n" /* interrupted? retry */
+ " stw %0, %1\n" /* else, *dst -> *res */
+ : "=&r" (tmp), "=m" (*res), "+m" (*dst)
+ : "r" (val), "r" (dst)
+ : "cc", "memory");
+#endif
+}
+
+#define atomic_swap_ptr(d, v, r) \
+ atomic_swap32((intptr_t *)d, (intptr_t)v, (intptr_t *)r)
+
+#define atomic_swap_int(d, v, r) \
+ atomic_swap32((intptr_t *)d, (intptr_t)v, (intptr_t *)r)
+#endif
diff --git a/lib/libpthread/arch/powerpc/include/pthread_md.h b/lib/libpthread/arch/powerpc/include/pthread_md.h
new file mode 100644
index 0000000..33a58b5
--- /dev/null
+++ b/lib/libpthread/arch/powerpc/include/pthread_md.h
@@ -0,0 +1,258 @@
+/*
+ * Copyright 2004 by 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.
+ * 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$
+ */
+
+/*
+ * Machine-dependent thread prototypes/definitions for the thread kernel.
+ */
+#ifndef _PTHREAD_MD_H_
+#define _PTHREAD_MD_H_
+
+#include <sys/kse.h>
+#include <stddef.h>
+#include <ucontext.h>
+
+extern void _ppc32_enter_uts(struct kse_mailbox *, kse_func_t, void *, size_t);
+extern int _ppc32_setcontext(mcontext_t *, intptr_t, intptr_t *);
+extern int _ppc32_getcontext(mcontext_t *);
+
+#define KSE_STACKSIZE 16384
+#define DTV_OFFSET offsetof(struct tcb, tcb_tp.tp_tdv)
+
+#define THR_GETCONTEXT(ucp) _ppc32_getcontext(&(ucp)->uc_mcontext)
+#define THR_SETCONTEXT(ucp) _ppc32_setcontext(&(ucp)->uc_mcontext, 0, NULL)
+
+#define PER_THREAD
+
+struct kcb;
+struct kse;
+struct pthread;
+struct tcb;
+struct tdv;
+
+/*
+ * %r2 points to a struct kcb.
+ */
+struct ppc32_tp {
+ struct tdv *tp_tdv; /* dynamic TLS */
+ uint32_t _reserved_;
+ long double tp_tls[0]; /* static TLS */
+};
+
+struct tcb {
+ struct kse_thr_mailbox tcb_tmbx;
+ struct pthread *tcb_thread;
+ struct kcb *tcb_curkcb;
+ long tcb_isfake;
+ struct ppc32_tp tcb_tp;
+};
+
+struct kcb {
+ struct kse_mailbox kcb_kmbx;
+ struct tcb kcb_faketcb;
+ struct tcb *kcb_curtcb;
+ struct kse *kcb_kse;
+};
+
+/*
+ * From the PowerPC32 TLS spec:
+ *
+ * "r2 is the thread pointer, and points 0x7000 past the end of the
+ * thread control block." Or, 0x7008 past the start of the 8-byte tcb
+ */
+#define TP_OFFSET 0x7008
+register uint8_t *_tpr __asm("%r2");
+
+#define _tcb ((struct tcb *)(_tpr - TP_OFFSET - offsetof(struct tcb, tcb_tp)))
+
+/*
+ * The kcb and tcb constructors.
+ */
+struct tcb *_tcb_ctor(struct pthread *, int);
+void _tcb_dtor(struct tcb *);
+struct kcb *_kcb_ctor(struct kse *kse);
+void _kcb_dtor(struct kcb *);
+
+/* Called from the KSE to set its private data. */
+static __inline void
+_kcb_set(struct kcb *kcb)
+{
+ /* There is no thread yet; use the fake tcb. */
+ _tpr = (uint8_t *)&kcb->kcb_faketcb.tcb_tp + TP_OFFSET;
+}
+
+/*
+ * Get the current kcb.
+ *
+ * This can only be called while in a critical region; don't
+ * worry about having the kcb changed out from under us.
+ */
+static __inline struct kcb *
+_kcb_get(void)
+{
+ return (_tcb->tcb_curkcb);
+}
+
+/*
+ * Enter a critical region.
+ *
+ * Read and clear km_curthread in the kse mailbox.
+ */
+static __inline struct kse_thr_mailbox *
+_kcb_critical_enter(void)
+{
+ struct kse_thr_mailbox *crit;
+ uint32_t flags;
+
+ if (_tcb->tcb_isfake != 0) {
+ /*
+ * We already are in a critical region since
+ * there is no current thread.
+ */
+ crit = NULL;
+ } else {
+ flags = _tcb->tcb_tmbx.tm_flags;
+ _tcb->tcb_tmbx.tm_flags |= TMF_NOUPCALL;
+ crit = _tcb->tcb_curkcb->kcb_kmbx.km_curthread;
+ _tcb->tcb_curkcb->kcb_kmbx.km_curthread = NULL;
+ _tcb->tcb_tmbx.tm_flags = flags;
+ }
+ return (crit);
+}
+
+static __inline void
+_kcb_critical_leave(struct kse_thr_mailbox *crit)
+{
+ /* No need to do anything if this is a fake tcb. */
+ if (_tcb->tcb_isfake == 0)
+ _tcb->tcb_curkcb->kcb_kmbx.km_curthread = crit;
+}
+
+static __inline int
+_kcb_in_critical(void)
+{
+ uint32_t flags;
+ int ret;
+
+ if (_tcb->tcb_isfake != 0) {
+ /*
+ * We are in a critical region since there is no
+ * current thread.
+ */
+ ret = 1;
+ } else {
+ flags = _tcb->tcb_tmbx.tm_flags;
+ _tcb->tcb_tmbx.tm_flags |= TMF_NOUPCALL;
+ ret = (_tcb->tcb_curkcb->kcb_kmbx.km_curthread == NULL);
+ _tcb->tcb_tmbx.tm_flags = flags;
+ }
+ return (ret);
+}
+
+static __inline void
+_tcb_set(struct kcb *kcb, struct tcb *tcb)
+{
+ if (tcb == NULL)
+ tcb = &kcb->kcb_faketcb;
+ kcb->kcb_curtcb = tcb;
+ tcb->tcb_curkcb = kcb;
+ _tpr = (uint8_t *)&tcb->tcb_tp + TP_OFFSET;
+}
+
+static __inline struct tcb *
+_tcb_get(void)
+{
+ return (_tcb);
+}
+
+static __inline struct pthread *
+_get_curthread(void)
+{
+ return (_tcb->tcb_thread);
+}
+
+/*
+ * Get the current kse.
+ *
+ * Like _kcb_get(), this can only be called while in a critical region.
+ */
+static __inline struct kse *
+_get_curkse(void)
+{
+ return (_tcb->tcb_curkcb->kcb_kse);
+}
+
+static __inline int
+_thread_enter_uts(struct tcb *tcb, struct kcb *kcb)
+{
+ if (_ppc32_getcontext(&tcb->tcb_tmbx.tm_context.uc_mcontext) == 0) {
+ /* Make the fake tcb the current thread. */
+ kcb->kcb_curtcb = &kcb->kcb_faketcb;
+ _tpr = (uint8_t *)&kcb->kcb_faketcb.tcb_tp + TP_OFFSET;
+ _ppc32_enter_uts(&kcb->kcb_kmbx, kcb->kcb_kmbx.km_func,
+ kcb->kcb_kmbx.km_stack.ss_sp,
+ kcb->kcb_kmbx.km_stack.ss_size - 32);
+ /* We should not reach here. */
+ return (-1);
+ }
+ return (0);
+}
+
+static __inline int
+_thread_switch(struct kcb *kcb, struct tcb *tcb, int setmbox)
+{
+ mcontext_t *mc;
+ extern int _libkse_debug;
+
+ _tcb_set(kcb, tcb);
+ mc = &tcb->tcb_tmbx.tm_context.uc_mcontext;
+
+ /*
+ * A full context needs a system call to restore, so use
+ * kse_switchin. Otherwise, the partial context can be
+ * restored with _ppc32_setcontext
+ */
+ if (mc->mc_vers != _MC_VERSION_KSE && _libkse_debug != 0) {
+ if (setmbox)
+ kse_switchin(&tcb->tcb_tmbx, KSE_SWITCHIN_SETTMBX);
+ else
+ kse_switchin(&tcb->tcb_tmbx, 0);
+ } else {
+ tcb->tcb_tmbx.tm_lwp = kcb->kcb_kmbx.km_lwp;
+ if (setmbox)
+ _ppc32_setcontext(mc, (intptr_t)&tcb->tcb_tmbx,
+ (intptr_t *)&kcb->kcb_kmbx.km_curthread);
+ else
+ _ppc32_setcontext(mc, 0, NULL);
+ }
+
+ /* We should not reach here. */
+ return (-1);
+}
+
+#endif /* _PTHREAD_MD_H_ */
diff --git a/lib/libpthread/arch/powerpc/powerpc/assym.c b/lib/libpthread/arch/powerpc/powerpc/assym.c
new file mode 100644
index 0000000..a8479e7
--- /dev/null
+++ b/lib/libpthread/arch/powerpc/powerpc/assym.c
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+/* Used to generate mcontext_t offsets */
+
+#include <sys/types.h>
+#include <sys/assym.h>
+#include <sys/ucontext.h>
+
+#include <stddef.h>
+
+ASSYM(_MC_VERSION, _MC_VERSION);
+ASSYM(_MC_VERSION_KSE, _MC_VERSION_KSE);
+ASSYM(_MC_FP_VALID, _MC_FP_VALID);
+
+ASSYM(_MC_VERS, offsetof(mcontext_t, mc_vers));
+ASSYM(_MC_FLAGS, offsetof(mcontext_t, mc_flags));
+
+ASSYM(_MC_R0, offsetof(mcontext_t, mc_frame[0]));
+ASSYM(_MC_R1, offsetof(mcontext_t, mc_frame[1]));
+ASSYM(_MC_R2, offsetof(mcontext_t, mc_frame[2]));
+ASSYM(_MC_R3, offsetof(mcontext_t, mc_frame[3]));
+ASSYM(_MC_R4, offsetof(mcontext_t, mc_frame[4]));
+ASSYM(_MC_R5, offsetof(mcontext_t, mc_frame[5]));
+ASSYM(_MC_R6, offsetof(mcontext_t, mc_frame[6]));
+ASSYM(_MC_R7, offsetof(mcontext_t, mc_frame[7]));
+ASSYM(_MC_R8, offsetof(mcontext_t, mc_frame[8]));
+ASSYM(_MC_R9, offsetof(mcontext_t, mc_frame[9]));
+ASSYM(_MC_R10, offsetof(mcontext_t, mc_frame[10]));
+ASSYM(_MC_R11, offsetof(mcontext_t, mc_frame[11]));
+ASSYM(_MC_R12, offsetof(mcontext_t, mc_frame[12]));
+ASSYM(_MC_R13, offsetof(mcontext_t, mc_frame[13]));
+ASSYM(_MC_R14, offsetof(mcontext_t, mc_frame[14]));
+ASSYM(_MC_R15, offsetof(mcontext_t, mc_frame[15]));
+ASSYM(_MC_R16, offsetof(mcontext_t, mc_frame[16]));
+ASSYM(_MC_R17, offsetof(mcontext_t, mc_frame[17]));
+ASSYM(_MC_R18, offsetof(mcontext_t, mc_frame[18]));
+ASSYM(_MC_R19, offsetof(mcontext_t, mc_frame[19]));
+ASSYM(_MC_R20, offsetof(mcontext_t, mc_frame[20]));
+ASSYM(_MC_R21, offsetof(mcontext_t, mc_frame[21]));
+ASSYM(_MC_R22, offsetof(mcontext_t, mc_frame[22]));
+ASSYM(_MC_R23, offsetof(mcontext_t, mc_frame[23]));
+ASSYM(_MC_R24, offsetof(mcontext_t, mc_frame[24]));
+ASSYM(_MC_R25, offsetof(mcontext_t, mc_frame[25]));
+ASSYM(_MC_R26, offsetof(mcontext_t, mc_frame[26]));
+ASSYM(_MC_R27, offsetof(mcontext_t, mc_frame[27]));
+ASSYM(_MC_R28, offsetof(mcontext_t, mc_frame[28]));
+ASSYM(_MC_R29, offsetof(mcontext_t, mc_frame[29]));
+ASSYM(_MC_R30, offsetof(mcontext_t, mc_frame[30]));
+ASSYM(_MC_R31, offsetof(mcontext_t, mc_frame[31]));
+ASSYM(_MC_LR, offsetof(mcontext_t, mc_frame[32]));
+ASSYM(_MC_CR, offsetof(mcontext_t, mc_frame[33]));
+ASSYM(_MC_XER, offsetof(mcontext_t, mc_frame[34]));
+ASSYM(_MC_CTR, offsetof(mcontext_t, mc_frame[35]));
+
+ASSYM(_MC_FPSCR, offsetof(mcontext_t, mc_fpreg[32]));
+ASSYM(_MC_F0, offsetof(mcontext_t, mc_fpreg[0]));
+ASSYM(_MC_F1, offsetof(mcontext_t, mc_fpreg[1]));
+ASSYM(_MC_F2, offsetof(mcontext_t, mc_fpreg[2]));
+ASSYM(_MC_F3, offsetof(mcontext_t, mc_fpreg[3]));
+ASSYM(_MC_F4, offsetof(mcontext_t, mc_fpreg[4]));
+ASSYM(_MC_F5, offsetof(mcontext_t, mc_fpreg[5]));
+ASSYM(_MC_F6, offsetof(mcontext_t, mc_fpreg[6]));
+ASSYM(_MC_F7, offsetof(mcontext_t, mc_fpreg[7]));
+ASSYM(_MC_F8, offsetof(mcontext_t, mc_fpreg[8]));
+ASSYM(_MC_F9, offsetof(mcontext_t, mc_fpreg[9]));
+ASSYM(_MC_F10, offsetof(mcontext_t, mc_fpreg[10]));
+ASSYM(_MC_F11, offsetof(mcontext_t, mc_fpreg[11]));
+ASSYM(_MC_F12, offsetof(mcontext_t, mc_fpreg[12]));
+ASSYM(_MC_F13, offsetof(mcontext_t, mc_fpreg[13]));
+ASSYM(_MC_F14, offsetof(mcontext_t, mc_fpreg[14]));
+ASSYM(_MC_F15, offsetof(mcontext_t, mc_fpreg[15]));
+ASSYM(_MC_F16, offsetof(mcontext_t, mc_fpreg[16]));
+ASSYM(_MC_F17, offsetof(mcontext_t, mc_fpreg[17]));
+ASSYM(_MC_F18, offsetof(mcontext_t, mc_fpreg[18]));
+ASSYM(_MC_F19, offsetof(mcontext_t, mc_fpreg[19]));
+ASSYM(_MC_F20, offsetof(mcontext_t, mc_fpreg[20]));
+ASSYM(_MC_F21, offsetof(mcontext_t, mc_fpreg[21]));
+ASSYM(_MC_F22, offsetof(mcontext_t, mc_fpreg[22]));
+ASSYM(_MC_F23, offsetof(mcontext_t, mc_fpreg[23]));
+ASSYM(_MC_F24, offsetof(mcontext_t, mc_fpreg[24]));
+ASSYM(_MC_F25, offsetof(mcontext_t, mc_fpreg[25]));
+ASSYM(_MC_F26, offsetof(mcontext_t, mc_fpreg[26]));
+ASSYM(_MC_F27, offsetof(mcontext_t, mc_fpreg[27]));
+ASSYM(_MC_F28, offsetof(mcontext_t, mc_fpreg[28]));
+ASSYM(_MC_F29, offsetof(mcontext_t, mc_fpreg[29]));
+ASSYM(_MC_F30, offsetof(mcontext_t, mc_fpreg[30]));
+ASSYM(_MC_F31, offsetof(mcontext_t, mc_fpreg[31]));
diff --git a/lib/libpthread/arch/powerpc/powerpc/assym.s b/lib/libpthread/arch/powerpc/powerpc/assym.s
new file mode 100644
index 0000000..7017c15
--- /dev/null
+++ b/lib/libpthread/arch/powerpc/powerpc/assym.s
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Struct offsets for version 0x1 of the mcontext struct.
+ * Generated with
+ * cc -c assym.c
+ * ${SYSSRC}/kern/genassym.sh assym.o > assym_syms.s
+ * hand-edit output
+ */
+#define _MC_VERSION 0x1
+#define _MC_VERSION_KSE 0xee
+#define _MC_FP_VALID 0x1
+
+#define _MC_VERS 0x0
+#define _MC_FLAGS 0x4
+
+#define _MC_R0 0x298
+#define _MC_R1 0x21c
+#define _MC_R2 0x220
+#define _MC_R3 0x224
+#define _MC_R4 0x228
+#define _MC_R5 0x22c
+#define _MC_R6 0x230
+#define _MC_R7 0x234
+#define _MC_R8 0x238
+#define _MC_R9 0x23c
+#define _MC_R10 0x240
+#define _MC_R11 0x244
+#define _MC_R12 0x248
+#define _MC_R13 0x24c
+#define _MC_R14 0x250
+#define _MC_R15 0x254
+#define _MC_R16 0x258
+#define _MC_R17 0x25c
+#define _MC_R18 0x260
+#define _MC_R19 0x264
+#define _MC_R20 0x268
+#define _MC_R21 0x26c
+#define _MC_R22 0x270
+#define _MC_R23 0x274
+#define _MC_R24 0x278
+#define _MC_R25 0x27c
+#define _MC_R26 0x280
+#define _MC_R27 0x284
+#define _MC_R28 0x288
+#define _MC_R29 0x28c
+#define _MC_R30 0x290
+#define _MC_R31 0x294
+#define _MC_LR 0x298
+#define _MC_CR 0x29c
+#define _MC_XER 0x2a0
+#define _MC_CTR 0x2a4
+
+#define _MC_FPSCR 0x3c0
+#define _MC_F0 0x2c0
+#define _MC_F1 0x2c8
+#define _MC_F2 0x2d0
+#define _MC_F3 0x2d8
+#define _MC_F4 0x2e0
+#define _MC_F5 0x2e8
+#define _MC_F6 0x2f0
+#define _MC_F7 0x2f8
+#define _MC_F8 0x300
+#define _MC_F9 0x308
+#define _MC_F10 0x310
+#define _MC_F11 0x318
+#define _MC_F12 0x320
+#define _MC_F13 0x328
+#define _MC_F14 0x330
+#define _MC_F15 0x338
+#define _MC_F16 0x340
+#define _MC_F17 0x348
+#define _MC_F18 0x350
+#define _MC_F19 0x358
+#define _MC_F20 0x360
+#define _MC_F21 0x368
+#define _MC_F22 0x370
+#define _MC_F23 0x378
+#define _MC_F24 0x380
+#define _MC_F25 0x388
+#define _MC_F26 0x390
+#define _MC_F27 0x398
+#define _MC_F28 0x3a0
+#define _MC_F29 0x3a8
+#define _MC_F30 0x3b0
+#define _MC_F31 0x3b8
+
diff --git a/lib/libpthread/arch/powerpc/powerpc/context.S b/lib/libpthread/arch/powerpc/powerpc/context.S
new file mode 100644
index 0000000..34d175a
--- /dev/null
+++ b/lib/libpthread/arch/powerpc/powerpc/context.S
@@ -0,0 +1,151 @@
+/*
+ * 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$");
+
+#include "assym.s"
+
+/*
+ * int _ppc32_getcontext(mcontext_t *mcp)
+ *
+ * Save register state from a voluntary context switch.
+ * Only volatile registers, and those needed to complete
+ * a setcontext call, need to be saved.
+ *
+ * r1
+ * r14-31
+ * f14-31 XXX
+ * lr
+ *
+ * Return 0 for this call, and set up the context so it will return
+ * 1 when restored with _ppc32_setcontext().
+ *
+ * XXX XXX
+ * Floating-point is a big issue. Since there's no way to determine
+ * if the caller has used FP, all volatile register need to be saved.
+ * If FP hasn't been used, this results in a lazy FP exception in
+ * the kernel and from that point on FP is always switched in/out
+ * for the thread, which may be a big performance drag for the system.
+ * An alternative is to use a system call to get the context, which
+ * will do the right thing for floating point, but will save all
+ * registers rather than the caller-saved subset, and has the overhead
+ * of a syscall.
+ * Maybe another option would be to give a light-weight way for a
+ * thread to determine if FP is in used: perhaps a syscall that
+ * returns in the asm traphandler, or an OSX-style read-only page
+ * with a flag to indicate FP state.
+ *
+ * For now, punt the issue ala Alpha 1:1 model and fix in the future.
+ */
+ENTRY(_ppc32_getcontext)
+ stw %r1, _MC_R1(%r3)
+ stw %r13, _MC_R13(%r3)
+ stw %r14, _MC_R14(%r3)
+ stw %r15, _MC_R15(%r3)
+ stw %r16, _MC_R16(%r3)
+ stw %r17, _MC_R17(%r3)
+ stw %r18, _MC_R18(%r3)
+ stw %r19, _MC_R19(%r3)
+ stw %r20, _MC_R20(%r3)
+ stw %r21, _MC_R21(%r3)
+ stw %r22, _MC_R22(%r3)
+ stw %r23, _MC_R23(%r3)
+ stw %r24, _MC_R24(%r3)
+ stw %r25, _MC_R25(%r3)
+ stw %r26, _MC_R26(%r3)
+ stw %r27, _MC_R27(%r3)
+ stw %r28, _MC_R28(%r3)
+ stw %r29, _MC_R28(%r3)
+ stw %r30, _MC_R30(%r3)
+ stw %r31, _MC_R31(%r3)
+ mflr %r4
+ stw %r4, _MC_LR(%r3)
+ mfcr %r4
+ stw %r4, _MC_CR(%r3)
+
+ /* XXX f14-31 ? */
+
+ li %r4, _MC_VERSION_KSE /* partial ucontext version */
+ stw %r4, _MC_VERS(%r3)
+
+ /* Return 0 */
+ li %r3, 0
+ blr
+
+/*
+ * int _ppc32_setcontext(const mcontext_t *mcp, intptr_t val,
+ * intptr_t *loc);
+ *
+ * Should only be called for partial KSE contexts. The full context
+ * case is handled by kse_switchin() in _thread_switch()
+ *
+ * Returns -1 on error and 1 for return from a saved context
+ */
+
+ENTRY(_ppc32_setcontext)
+ lwz %r6, _MC_VERS(%r3)
+ cmpwi %r6, _MC_VERSION_KSE /* KSE partial context ? */
+ beq 1f
+ li %r3, -1 /* invalid context type, return -1 */
+ blr
+
+1: /* partial format, callee-saved regs assumed */
+ lwz %r1, _MC_R1(%r3)
+ lwz %r13, _MC_R13(%r3)
+ lwz %r14, _MC_R14(%r3)
+ lwz %r15, _MC_R15(%r3)
+ lwz %r16, _MC_R16(%r3)
+ lwz %r17, _MC_R17(%r3)
+ lwz %r18, _MC_R18(%r3)
+ lwz %r19, _MC_R19(%r3)
+ lwz %r20, _MC_R20(%r3)
+ lwz %r21, _MC_R21(%r3)
+ lwz %r22, _MC_R22(%r3)
+ lwz %r23, _MC_R23(%r3)
+ lwz %r24, _MC_R24(%r3)
+ lwz %r25, _MC_R25(%r3)
+ lwz %r26, _MC_R26(%r3)
+ lwz %r27, _MC_R27(%r3)
+ lwz %r28, _MC_R28(%r3)
+ lwz %r29, _MC_R28(%r3)
+ lwz %r30, _MC_R30(%r3)
+ lwz %r31, _MC_R31(%r3)
+ lwz %r6, _MC_LR(%r3)
+ mtlr %r6
+ lwz %r6, _MC_CR(%r3)
+ mtcr %r6
+
+ /* XXX f14-31 ? */
+
+ /* if (loc != NULL) *loc = val */
+ cmpwi %r5, 0
+ beq 2f
+ stw %r4, 0(%r5)
+
+ /* Return 1 */
+2: li %r3, 1
+ blr
diff --git a/lib/libpthread/arch/powerpc/powerpc/enter_uts.S b/lib/libpthread/arch/powerpc/powerpc/enter_uts.S
new file mode 100644
index 0000000..7cc4d7f
--- /dev/null
+++ b/lib/libpthread/arch/powerpc/powerpc/enter_uts.S
@@ -0,0 +1,40 @@
+/*
+ * 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$");
+
+/*
+ * _ppc32_enter_uts(struct kse_mailbox *km, kse_func_t uts, void *stack,
+ * long stacksz);
+ *
+ * Call (*uts)(km) on the requested stack. This function doesn't
+ * return. The km parameter stays in %r3.
+ */
+ENTRY(_ppc32_enter_uts)
+ add %r1,%r5,%r6 /* new stack = stack + stacksz */
+ mtlr %r4 /* link register = uts */
+ blrl /* (*uts)(km) */
diff --git a/lib/libpthread/arch/powerpc/powerpc/pthread_md.c b/lib/libpthread/arch/powerpc/powerpc/pthread_md.c
new file mode 100644
index 0000000..c8445b1
--- /dev/null
+++ b/lib/libpthread/arch/powerpc/powerpc/pthread_md.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2003 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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, 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 <strings.h>
+#include "pthread_md.h"
+
+/*
+ * The constructors.
+ */
+struct tcb *
+_tcb_ctor(struct pthread *thread, int initial)
+{
+ struct tcb *tcb;
+
+ if ((tcb = malloc(sizeof(struct tcb))) != NULL) {
+ bzero(tcb, sizeof(struct tcb));
+ tcb->tcb_thread = thread;
+ /* Allocate TDV */
+ }
+ return (tcb);
+}
+
+void
+_tcb_dtor(struct tcb *tcb)
+{
+ /* Free TDV */
+ free(tcb);
+}
+
+struct kcb *
+_kcb_ctor(struct kse *kse)
+{
+ struct kcb *kcb;
+
+ if ((kcb = malloc(sizeof(struct kcb))) != NULL) {
+ bzero(kcb, sizeof(struct kcb));
+ kcb->kcb_faketcb.tcb_isfake = 1;
+ kcb->kcb_faketcb.tcb_tmbx.tm_flags = TMF_NOUPCALL;
+ kcb->kcb_curtcb = &kcb->kcb_faketcb;
+ kcb->kcb_kse = kse;
+ }
+ return (kcb);
+}
+
+void
+_kcb_dtor(struct kcb *kcb)
+{
+ free(kcb);
+}
diff --git a/lib/libpthread/arch/sparc64/Makefile.inc b/lib/libpthread/arch/sparc64/Makefile.inc
new file mode 100644
index 0000000..07107b4
--- /dev/null
+++ b/lib/libpthread/arch/sparc64/Makefile.inc
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}/${MACHINE_ARCH}
+
+SRCS+= pthread_md.c thr_getcontext.S
diff --git a/lib/libpthread/arch/sparc64/include/atomic_ops.h b/lib/libpthread/arch/sparc64/include/atomic_ops.h
new file mode 100644
index 0000000..4f4d8af
--- /dev/null
+++ b/lib/libpthread/arch/sparc64/include/atomic_ops.h
@@ -0,0 +1,75 @@
+/*-
+ * Copyright (c) 2003 Jake Burkholder <jake@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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _ATOMIC_OPS_H_
+#define _ATOMIC_OPS_H_
+
+#include <machine/atomic.h>
+
+/*
+ * Atomic swap:
+ * Atomic (tmp = *dst, *dst = val), then *res = tmp
+ *
+ * void atomic_swap_long(long *dst, long val, long *res);
+ */
+static __inline void
+atomic_swap_long(long *dst, long val, long *res)
+{
+ long tmp;
+ long r;
+
+ tmp = *dst;
+ for (;;) {
+ r = atomic_cas_64(dst, tmp, val);
+ if (r == tmp)
+ break;
+ tmp = r;
+ }
+ *res = tmp;
+}
+
+static __inline void
+atomic_swap_int(int *dst, int val, int *res)
+{
+ int tmp;
+ int r;
+
+ tmp = *dst;
+ for (;;) {
+ r = atomic_cas_32(dst, tmp, val);
+ if (r == tmp)
+ break;
+ tmp = r;
+ }
+ *res = tmp;
+}
+
+#define atomic_swap_ptr(dst, val, res) \
+ atomic_swap_long((long *)dst, (long)val, (long *)res)
+
+#endif
diff --git a/lib/libpthread/arch/sparc64/include/pthread_md.h b/lib/libpthread/arch/sparc64/include/pthread_md.h
new file mode 100644
index 0000000..fac62c2
--- /dev/null
+++ b/lib/libpthread/arch/sparc64/include/pthread_md.h
@@ -0,0 +1,254 @@
+/*-
+ * Copyright (c) 2003 Jake Burkholder <jake@freebsd.org>.
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Machine-dependent thread prototypes/definitions for the thread kernel.
+ */
+#ifndef _PTHREAD_MD_H_
+#define _PTHREAD_MD_H_
+
+#include <sys/kse.h>
+#include <stddef.h>
+#include <ucontext.h>
+
+#define KSE_STACKSIZE 16384
+#define DTV_OFFSET offsetof(struct tcb, tcb_tp.tp_tdv)
+
+int _thr_setcontext(mcontext_t *, intptr_t, intptr_t *);
+int _thr_getcontext(mcontext_t *);
+
+#define THR_GETCONTEXT(ucp) _thr_getcontext(&(ucp)->uc_mcontext)
+#define THR_SETCONTEXT(ucp) _thr_setcontext(&(ucp)->uc_mcontext, 0, NULL)
+
+#define PER_THREAD
+
+struct kcb;
+struct kse;
+struct pthread;
+struct tcb;
+struct tdv; /* We don't know what this is yet? */
+
+
+/*
+ * %g6 points to one of these. We define the static TLS as an array
+ * of long double to enforce 16-byte alignment of the TLS memory.
+ *
+ * XXX - Both static and dynamic allocation of any of these structures
+ * will result in a valid, well-aligned thread pointer???
+ */
+struct sparc64_tp {
+ struct tdv *tp_tdv; /* dynamic TLS */
+ uint64_t _reserved_;
+ long double tp_tls[0]; /* static TLS */
+};
+
+struct tcb {
+ struct pthread *tcb_thread;
+ void *tcb_addr; /* allocated tcb address */
+ struct kcb *tcb_curkcb;
+ uint64_t tcb_isfake;
+ uint64_t tcb_spare[4];
+ struct kse_thr_mailbox tcb_tmbx; /* needs 64-byte alignment */
+ struct sparc64_tp tcb_tp;
+} __aligned(64);
+
+struct kcb {
+ struct kse_mailbox kcb_kmbx;
+ struct tcb kcb_faketcb;
+ struct tcb *kcb_curtcb;
+ struct kse *kcb_kse;
+};
+
+register struct sparc64_tp *_tp __asm("%g6");
+
+#define _tcb ((struct tcb*)((char*)(_tp) - offsetof(struct tcb, tcb_tp)))
+
+/*
+ * The kcb and tcb constructors.
+ */
+struct tcb *_tcb_ctor(struct pthread *, int);
+void _tcb_dtor(struct tcb *);
+struct kcb *_kcb_ctor(struct kse *kse);
+void _kcb_dtor(struct kcb *);
+
+/* Called from the KSE to set its private data. */
+static __inline void
+_kcb_set(struct kcb *kcb)
+{
+ /* There is no thread yet; use the fake tcb. */
+ _tp = &kcb->kcb_faketcb.tcb_tp;
+}
+
+/*
+ * Get the current kcb.
+ *
+ * This can only be called while in a critical region; don't
+ * worry about having the kcb changed out from under us.
+ */
+static __inline struct kcb *
+_kcb_get(void)
+{
+ return (_tcb->tcb_curkcb);
+}
+
+/*
+ * Enter a critical region.
+ *
+ * Read and clear km_curthread in the kse mailbox.
+ */
+static __inline struct kse_thr_mailbox *
+_kcb_critical_enter(void)
+{
+ struct kse_thr_mailbox *crit;
+ uint32_t flags;
+
+ if (_tcb->tcb_isfake != 0) {
+ /*
+ * We already are in a critical region since
+ * there is no current thread.
+ */
+ crit = NULL;
+ } else {
+ flags = _tcb->tcb_tmbx.tm_flags;
+ _tcb->tcb_tmbx.tm_flags |= TMF_NOUPCALL;
+ crit = _tcb->tcb_curkcb->kcb_kmbx.km_curthread;
+ _tcb->tcb_curkcb->kcb_kmbx.km_curthread = NULL;
+ _tcb->tcb_tmbx.tm_flags = flags;
+ }
+ return (crit);
+}
+
+static __inline void
+_kcb_critical_leave(struct kse_thr_mailbox *crit)
+{
+ /* No need to do anything if this is a fake tcb. */
+ if (_tcb->tcb_isfake == 0)
+ _tcb->tcb_curkcb->kcb_kmbx.km_curthread = crit;
+}
+
+static __inline int
+_kcb_in_critical(void)
+{
+ uint32_t flags;
+ int ret;
+
+ if (_tcb->tcb_isfake != 0) {
+ /*
+ * We are in a critical region since there is no
+ * current thread.
+ */
+ ret = 1;
+ } else {
+ flags = _tcb->tcb_tmbx.tm_flags;
+ _tcb->tcb_tmbx.tm_flags |= TMF_NOUPCALL;
+ ret = (_tcb->tcb_curkcb->kcb_kmbx.km_curthread == NULL);
+ _tcb->tcb_tmbx.tm_flags = flags;
+ }
+ return (ret);
+}
+
+static __inline void
+_tcb_set(struct kcb *kcb, struct tcb *tcb)
+{
+ if (tcb == NULL)
+ tcb = &kcb->kcb_faketcb;
+ kcb->kcb_curtcb = tcb;
+ tcb->tcb_curkcb = kcb;
+ _tp = &tcb->tcb_tp;
+}
+
+static __inline struct tcb *
+_tcb_get(void)
+{
+ return (_tcb);
+}
+
+static __inline struct pthread *
+_get_curthread(void)
+{
+ return (_tcb->tcb_thread);
+}
+
+/*
+ * Get the current kse.
+ *
+ * Like _kcb_get(), this can only be called while in a critical region.
+ */
+static __inline struct kse *
+_get_curkse(void)
+{
+ return (_tcb->tcb_curkcb->kcb_kse);
+}
+
+void _sparc64_enter_uts(kse_func_t uts, struct kse_mailbox *km, void *stack,
+ size_t stacksz);
+
+static __inline int
+_thread_enter_uts(struct tcb *tcb, struct kcb *kcb)
+{
+ if (_thr_getcontext(&tcb->tcb_tmbx.tm_context.uc_mcontext) == 0) {
+ /* Make the fake tcb the current thread. */
+ kcb->kcb_curtcb = &kcb->kcb_faketcb;
+ _tp = &kcb->kcb_faketcb.tcb_tp;
+ _sparc64_enter_uts(kcb->kcb_kmbx.km_func, &kcb->kcb_kmbx,
+ kcb->kcb_kmbx.km_stack.ss_sp,
+ kcb->kcb_kmbx.km_stack.ss_size);
+ /* We should not reach here. */
+ return (-1);
+ }
+ return (0);
+}
+
+static __inline int
+_thread_switch(struct kcb *kcb, struct tcb *tcb, int setmbox)
+{
+ extern int _libkse_debug;
+ mcontext_t *mc;
+
+ _tcb_set(kcb, tcb);
+ mc = &tcb->tcb_tmbx.tm_context.uc_mcontext;
+ if (_libkse_debug == 0) {
+ tcb->tcb_tmbx.tm_lwp = kcb->kcb_kmbx.km_lwp;
+ if (setmbox)
+ _thr_setcontext(mc, (intptr_t)&tcb->tcb_tmbx,
+ (intptr_t *)&kcb->kcb_kmbx.km_curthread);
+ else
+ _thr_setcontext(mc, 0, NULL);
+ } else {
+ if (setmbox)
+ kse_switchin(&tcb->tcb_tmbx, KSE_SWITCHIN_SETTMBX);
+ else
+ kse_switchin(&tcb->tcb_tmbx, 0);
+ }
+
+ /* We should not reach here. */
+ return (-1);
+}
+
+#endif /* _PTHREAD_MD_H_ */
diff --git a/lib/libpthread/arch/sparc64/sparc64/assym.s b/lib/libpthread/arch/sparc64/sparc64/assym.s
new file mode 100644
index 0000000..3e22c9f
--- /dev/null
+++ b/lib/libpthread/arch/sparc64/sparc64/assym.s
@@ -0,0 +1,15 @@
+/*
+ * Offsets into structures used from asm. Must be kept in sync with
+ * appropriate headers.
+ *
+ * $FreeBSD$
+ */
+
+#define UC_MCONTEXT 0x40
+
+#define MC_FLAGS 0x0
+#define MC_VALID_FLAGS 0x1
+#define MC_GLOBAL 0x0
+#define MC_OUT 0x40
+#define MC_TPC 0xc8
+#define MC_TNPC 0xc0
diff --git a/lib/libpthread/arch/sparc64/sparc64/pthread_md.c b/lib/libpthread/arch/sparc64/sparc64/pthread_md.c
new file mode 100644
index 0000000..d6bf95d
--- /dev/null
+++ b/lib/libpthread/arch/sparc64/sparc64/pthread_md.c
@@ -0,0 +1,91 @@
+/*-
+ * Copyright (C) 2003 Jake Burkholder <jake@freebsd.org>
+ * Copyright (C) 2003 David Xu <davidxu@freebsd.org>
+ * Copyright (c) 2001,2003 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include <unistd.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ucontext.h>
+
+#include "pthread_md.h"
+
+struct tcb *
+_tcb_ctor(struct pthread *thread, int initial)
+{
+ struct tcb *tcb;
+ void *addr;
+
+ addr = malloc(sizeof(struct tcb) + 63);
+ if (addr == NULL)
+ tcb = NULL;
+ else {
+ tcb = (struct tcb *)(((uintptr_t)(addr) + 63) & ~63);
+ bzero(tcb, sizeof(struct tcb));
+ tcb->tcb_addr = addr;
+ tcb->tcb_thread = thread;
+ /* XXX - Allocate tdv/tls */
+ }
+ return (tcb);
+}
+
+void
+_tcb_dtor(struct tcb *tcb)
+{
+ void *addr;
+
+ addr = tcb->tcb_addr;
+ tcb->tcb_addr = NULL;
+ free(addr);
+}
+
+struct kcb *
+_kcb_ctor(struct kse *kse)
+{
+ struct kcb *kcb;
+
+ kcb = malloc(sizeof(struct kcb));
+ if (kcb != NULL) {
+ bzero(kcb, sizeof(struct kcb));
+ kcb->kcb_faketcb.tcb_isfake = 1;
+ kcb->kcb_faketcb.tcb_tmbx.tm_flags = TMF_NOUPCALL;
+ kcb->kcb_curtcb = &kcb->kcb_faketcb;
+ kcb->kcb_kse = kse;
+ }
+ return (kcb);
+}
+
+void
+_kcb_dtor(struct kcb *kcb)
+{
+ free(kcb);
+}
diff --git a/lib/libpthread/arch/sparc64/sparc64/thr_getcontext.S b/lib/libpthread/arch/sparc64/sparc64/thr_getcontext.S
new file mode 100644
index 0000000..ca6473a
--- /dev/null
+++ b/lib/libpthread/arch/sparc64/sparc64/thr_getcontext.S
@@ -0,0 +1,87 @@
+/*-
+ * Copyright (C) 2003 Jake Burkholder <jake@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$");
+
+#include "assym.s"
+
+ .weak CNAME(_thr_getcontext)
+ .set CNAME(_thr_getcontext),CNAME(__thr_getcontext)
+ENTRY(__thr_getcontext)
+ add %o7, 8, %o1
+ add %o1, 4, %o2
+ stx %sp, [%o0 + MC_OUT + (6 * 8)]
+ stx %o1, [%o0 + MC_TPC]
+ stx %o2, [%o0 + MC_TNPC]
+ mov MC_VALID_FLAGS, %l0 /* Validate the context. */
+ stx %l0, [%o0 + MC_FLAGS]
+ mov 1, %l0
+ stx %l0, [%o0 + MC_OUT + (0 * 8)] /* return 1 when resumed */
+ retl
+ mov 0, %o0 /* return 0 */
+END(__thr_getcontext)
+
+ .weak CNAME(_thr_setcontext)
+ .set CNAME(_thr_setcontext),CNAME(__thr_setcontext)
+ENTRY(__thr_setcontext)
+ save %sp, -CCFSZ, %sp
+ flushw
+ mov %i0, %l0
+ mov %i1, %l1
+ mov %i2, %l2
+ ldx [%l0 + MC_GLOBAL + (1 * 8)], %g1
+ ldx [%l0 + MC_GLOBAL + (2 * 8)], %g2
+ ldx [%l0 + MC_GLOBAL + (3 * 8)], %g3
+ ldx [%l0 + MC_GLOBAL + (4 * 8)], %g4
+ ldx [%l0 + MC_GLOBAL + (5 * 8)], %g5
+ ldx [%l0 + MC_GLOBAL + (6 * 8)], %g6
+ ldx [%l0 + MC_GLOBAL + (7 * 8)], %g7
+ ldx [%l0 + MC_OUT + (0 * 8)], %i0
+ ldx [%l0 + MC_OUT + (1 * 8)], %i1
+ ldx [%l0 + MC_OUT + (2 * 8)], %i2
+ ldx [%l0 + MC_OUT + (3 * 8)], %i3
+ ldx [%l0 + MC_OUT + (4 * 8)], %i4
+ ldx [%l0 + MC_OUT + (5 * 8)], %i5
+ ldx [%l0 + MC_OUT + (6 * 8)], %i6
+ ldx [%l0 + MC_OUT + (7 * 8)], %i7
+ ldx [%l0 + MC_TPC], %l4
+ ldx [%l0 + MC_TNPC], %l3
+ brz %l2, 1f
+ nop
+ stx %l1, [%l2]
+1: jmpl %l3, %g0
+ return %l4
+END(__thr_setcontext)
+
+ENTRY(_sparc64_enter_uts)
+ save %sp, -CCFSZ, %sp
+ flushw
+ add %i2, %i3, %i2
+ sub %i2, SPOFF + CCFSZ, %sp
+ jmpl %i0, %g0
+ mov %i1, %o0
+END(_sparc64_enter_uts)
diff --git a/lib/libpthread/pthread.map b/lib/libpthread/pthread.map
new file mode 100644
index 0000000..31ee580
--- /dev/null
+++ b/lib/libpthread/pthread.map
@@ -0,0 +1,737 @@
+# $FreeBSD$
+
+#
+# Hack. libpthread had versioning before libc, but we need to
+# reside in the same namespace as libc if we want to override
+# libc functions. Use this so we don't break older applications
+# that require symbols from "LIBTHREAD_1_0".
+#
+# From now on, use the same naming scheme as libc.
+#
+#
+LIBTHREAD_1_0 {
+global:
+ ___creat;
+ __accept;
+ __close;
+ __connect;
+ __error;
+ __fcntl;
+ __fsync;
+ __msync;
+ __nanosleep;
+ __open;
+ __poll;
+ __pthread_cond_timedwait;
+ __pthread_cond_wait;
+ __pthread_mutex_init;
+ __pthread_mutex_lock;
+ __pthread_mutex_trylock;
+ __pthread_mutex_timedlock;
+ __read;
+ __readv;
+ __select;
+ __sigsuspend;
+ __sigtimedwait;
+ __sigwait;
+ __sigwaitinfo;
+ __wait4;
+ __write;
+ __writev;
+ _aio_suspend;
+ _execve;
+ _fork;
+ _nanosleep;
+ _pause;
+ _pselect;
+ _pthread_atfork;
+ _pthread_barrier_destroy;
+ _pthread_barrier_init;
+ _pthread_barrier_wait;
+ _pthread_barrierattr_destroy;
+ _pthread_barrierattr_getpshared;
+ _pthread_barrierattr_init;
+ _pthread_barrierattr_setpshared;
+ _pthread_attr_destroy;
+ _pthread_attr_get_np;
+ _pthread_attr_getdetachstate;
+ _pthread_attr_getguardsize;
+ _pthread_attr_getinheritsched;
+ _pthread_attr_getschedparam;
+ _pthread_attr_getschedpolicy;
+ _pthread_attr_getscope;
+ _pthread_attr_getstack;
+ _pthread_attr_getstackaddr;
+ _pthread_attr_getstacksize;
+ _pthread_attr_init;
+ _pthread_attr_setcreatesuspend_np;
+ _pthread_attr_setdetachstate;
+ _pthread_attr_setguardsize;
+ _pthread_attr_setinheritsched;
+ _pthread_attr_setschedparam;
+ _pthread_attr_setschedpolicy;
+ _pthread_attr_setscope;
+ _pthread_attr_setstack;
+ _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_condattr_default;
+ _pthread_condattr_destroy;
+ _pthread_condattr_getpshared;
+ _pthread_condattr_init;
+ _pthread_condattr_setpshared;
+ _pthread_create;
+ _pthread_detach;
+ _pthread_equal;
+ _pthread_exit;
+ _pthread_getconcurrency;
+ _pthread_getprio;
+ _pthread_getschedparam;
+ _pthread_getspecific;
+ _pthread_join;
+ _pthread_key_create;
+ _pthread_key_delete;
+ _pthread_kill;
+ _pthread_main_np;
+ _pthread_multi_np;
+ _pthread_mutex_destroy;
+ _pthread_mutex_getprioceiling;
+ _pthread_mutex_init;
+ _pthread_mutex_lock;
+ _pthread_mutex_setprioceiling;
+ _pthread_mutex_timedlock;
+ _pthread_mutex_trylock;
+ _pthread_mutex_unlock;
+ _pthread_mutexattr_default;
+ _pthread_mutexattr_destroy;
+ _pthread_mutexattr_getkind_np;
+ _pthread_mutexattr_getprioceiling;
+ _pthread_mutexattr_getprotocol;
+ _pthread_mutexattr_getpshared;
+ _pthread_mutexattr_gettype;
+ _pthread_mutexattr_init;
+ _pthread_mutexattr_setkind_np;
+ _pthread_mutexattr_setprioceiling;
+ _pthread_mutexattr_setprotocol;
+ _pthread_mutexattr_setpshared;
+ _pthread_mutexattr_settype;
+ _pthread_once;
+ _pthread_resume_all_np;
+ _pthread_resume_np;
+ _pthread_rwlock_destroy;
+ _pthread_rwlock_init;
+ _pthread_rwlock_rdlock;
+ _pthread_rwlock_timedrdlock;
+ _pthread_rwlock_timedwrlock;
+ _pthread_rwlock_tryrdlock;
+ _pthread_rwlock_trywrlock;
+ _pthread_rwlock_unlock;
+ _pthread_rwlock_wrlock;
+ _pthread_rwlockattr_destroy;
+ _pthread_rwlockattr_getpshared;
+ _pthread_rwlockattr_init;
+ _pthread_rwlockattr_setpshared;
+ _pthread_self;
+ _pthread_set_name_np;
+ _pthread_setcancelstate;
+ _pthread_setcanceltype;
+ _pthread_setconcurrency;
+ _pthread_setprio;
+ _pthread_setschedparam;
+ _pthread_setspecific;
+ _pthread_sigmask;
+ _pthread_single_np;
+ _pthread_spin_destroy;
+ _pthread_spin_init;
+ _pthread_spin_lock;
+ _pthread_spin_trylock;
+ _pthread_spin_unlock;
+ _pthread_suspend_all_np;
+ _pthread_suspend_np;
+ _pthread_switch_add_np;
+ _pthread_switch_delete_np;
+ _pthread_testcancel;
+ _pthread_yield;
+ _raise;
+ _sched_yield;
+ _sem_init;
+ _sem_post;
+ _sem_timedwait;
+ _sem_wait;
+ _sigaction;
+ _sigaltstack;
+ _sigpending;
+ _sigprocmask;
+ _sigsuspend;
+ _sigtimedwait;
+ _sigwait;
+ _sigwaitinfo;
+ _sleep;
+ _spinlock;
+ _spinlock_debug;
+ _spinunlock;
+ _system;
+ _tcdrain;
+ _usleep;
+ _vfork;
+ _wait;
+ _waitpid;
+ accept;
+ aio_suspend;
+ close;
+ connect;
+ creat;
+ execve;
+ fcntl;
+ fork;
+ fsync;
+ msync;
+ nanosleep;
+ open;
+ pause;
+ poll;
+ pselect;
+ pthread_atfork;
+ pthread_barrier_destroy;
+ pthread_barrier_init;
+ pthread_barrier_wait;
+ pthread_barrierattr_destroy;
+ pthread_barrierattr_getpshared;
+ pthread_barrierattr_init;
+ pthread_barrierattr_setpshared;
+ pthread_attr_destroy;
+ pthread_attr_get_np;
+ pthread_attr_getdetachstate;
+ pthread_attr_getguardsize;
+ pthread_attr_getinheritsched;
+ pthread_attr_getschedparam;
+ pthread_attr_getschedpolicy;
+ pthread_attr_getscope;
+ pthread_attr_getstack;
+ pthread_attr_getstackaddr;
+ pthread_attr_getstacksize;
+ pthread_attr_init;
+ pthread_attr_setcreatesuspend_np;
+ pthread_attr_setdetachstate;
+ pthread_attr_setguardsize;
+ pthread_attr_setinheritsched;
+ pthread_attr_setschedparam;
+ pthread_attr_setschedpolicy;
+ pthread_attr_setscope;
+ pthread_attr_setstack;
+ 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_condattr_destroy;
+ pthread_condattr_getpshared;
+ pthread_condattr_init;
+ pthread_condattr_setpshared;
+ pthread_create;
+ pthread_detach;
+ pthread_equal;
+ pthread_exit;
+ pthread_getconcurrency;
+ pthread_getprio;
+ pthread_getschedparam;
+ pthread_getspecific;
+ pthread_join;
+ pthread_key_create;
+ pthread_key_delete;
+ pthread_kill;
+ pthread_main_np;
+ pthread_multi_np;
+ pthread_mutex_destroy;
+ pthread_mutex_getprioceiling;
+ pthread_mutex_init;
+ pthread_mutex_lock;
+ pthread_mutex_setprioceiling;
+ pthread_mutex_timedlock;
+ pthread_mutex_trylock;
+ pthread_mutex_unlock;
+ pthread_mutexattr_destroy;
+ pthread_mutexattr_getkind_np;
+ pthread_mutexattr_getprioceiling;
+ pthread_mutexattr_getprotocol;
+ pthread_mutexattr_getpshared;
+ pthread_mutexattr_gettype;
+ pthread_mutexattr_init;
+ pthread_mutexattr_setkind_np;
+ pthread_mutexattr_setprioceiling;
+ pthread_mutexattr_setprotocol;
+ pthread_mutexattr_setpshared;
+ pthread_mutexattr_settype;
+ pthread_once;
+ pthread_resume_all_np;
+ pthread_resume_np;
+ pthread_rwlock_destroy;
+ pthread_rwlock_init;
+ pthread_rwlock_rdlock;
+ pthread_rwlock_timedrdlock;
+ pthread_rwlock_timedwrlock;
+ pthread_rwlock_tryrdlock;
+ pthread_rwlock_trywrlock;
+ pthread_rwlock_unlock;
+ pthread_rwlock_wrlock;
+ pthread_rwlockattr_destroy;
+ pthread_rwlockattr_getpshared;
+ pthread_rwlockattr_init;
+ pthread_rwlockattr_setpshared;
+ pthread_self;
+ pthread_set_name_np;
+ pthread_setcancelstate;
+ pthread_setcanceltype;
+ pthread_setconcurrency;
+ pthread_setprio;
+ pthread_setschedparam;
+ pthread_setspecific;
+ pthread_sigmask;
+ pthread_single_np;
+ pthread_spin_destroy;
+ pthread_spin_init;
+ pthread_spin_lock;
+ pthread_spin_trylock;
+ pthread_spin_unlock;
+ pthread_suspend_all_np;
+ pthread_suspend_np;
+ pthread_switch_add_np;
+ pthread_switch_delete_np;
+ pthread_testcancel;
+ pthread_yield;
+ raise;
+ read;
+ readv;
+ sched_yield;
+ select;
+ sem_init;
+ sem_post;
+ sem_timedwait;
+ sem_wait;
+ sigaction;
+ sigaltstack;
+ sigpending;
+ sigprocmask;
+ sigsuspend;
+ sigwait;
+ sigwaitinfo;
+ sigtimedwait;
+ sleep;
+ system;
+ tcdrain;
+ usleep;
+ vfork;
+ wait4;
+ wait;
+ waitpid;
+ write;
+ writev;
+
+ # Debugger needs these.
+ _libkse_debug;
+ _thread_activated;
+ _thread_active_threads;
+ _thread_keytable;
+ _thread_list;
+ _thread_max_keys;
+ _thread_off_attr_flags;
+ _thread_off_dtv;
+ _thread_off_linkmap;
+ _thread_off_next;
+ _thread_off_tcb;
+ _thread_off_tmbx;
+ _thread_off_key_allocated;
+ _thread_off_key_destructor;
+ _thread_off_kse;
+ _thread_off_kse_locklevel;
+ _thread_off_state;
+ _thread_off_thr_locklevel;
+ _thread_off_tlsindex;
+ _thread_size_key;
+ _thread_state_running;
+ _thread_state_zoombie;
+
+local:
+ *;
+};
+
+#
+# Use the same naming scheme as libc.
+#
+FBSD_1.0 {
+global:
+ __error;
+ accept;
+ aio_suspend;
+ close;
+ connect;
+ creat;
+ execve;
+ fcntl;
+ fork;
+ fsync;
+ msync;
+ nanosleep;
+ open;
+ pause;
+ poll;
+ pselect;
+ pthread_atfork;
+ pthread_barrier_destroy;
+ pthread_barrier_init;
+ pthread_barrier_wait;
+ pthread_barrierattr_destroy;
+ pthread_barrierattr_getpshared;
+ pthread_barrierattr_init;
+ pthread_barrierattr_setpshared;
+ pthread_attr_destroy;
+ pthread_attr_get_np;
+ pthread_attr_getdetachstate;
+ pthread_attr_getguardsize;
+ pthread_attr_getinheritsched;
+ pthread_attr_getschedparam;
+ pthread_attr_getschedpolicy;
+ pthread_attr_getscope;
+ pthread_attr_getstack;
+ pthread_attr_getstackaddr;
+ pthread_attr_getstacksize;
+ pthread_attr_init;
+ pthread_attr_setcreatesuspend_np;
+ pthread_attr_setdetachstate;
+ pthread_attr_setguardsize;
+ pthread_attr_setinheritsched;
+ pthread_attr_setschedparam;
+ pthread_attr_setschedpolicy;
+ pthread_attr_setscope;
+ pthread_attr_setstack;
+ 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_condattr_destroy;
+ pthread_condattr_init;
+ pthread_create;
+ pthread_detach;
+ pthread_equal;
+ pthread_exit;
+ pthread_getconcurrency;
+ pthread_getprio;
+ pthread_getschedparam;
+ pthread_getspecific;
+ pthread_join;
+ pthread_key_create;
+ pthread_key_delete;
+ pthread_kill;
+ pthread_main_np;
+ pthread_multi_np;
+ pthread_mutex_destroy;
+ pthread_mutex_getprioceiling;
+ pthread_mutex_init;
+ pthread_mutex_lock;
+ pthread_mutex_setprioceiling;
+ pthread_mutex_timedlock;
+ pthread_mutex_trylock;
+ pthread_mutex_unlock;
+ pthread_mutexattr_destroy;
+ pthread_mutexattr_getkind_np;
+ pthread_mutexattr_getprioceiling;
+ pthread_mutexattr_getprotocol;
+ pthread_mutexattr_gettype;
+ pthread_mutexattr_init;
+ pthread_mutexattr_setkind_np;
+ pthread_mutexattr_setprioceiling;
+ pthread_mutexattr_setprotocol;
+ pthread_mutexattr_settype;
+ pthread_once;
+ pthread_resume_all_np;
+ pthread_resume_np;
+ pthread_rwlock_destroy;
+ pthread_rwlock_init;
+ pthread_rwlock_rdlock;
+ pthread_rwlock_timedrdlock;
+ pthread_rwlock_timedwrlock;
+ pthread_rwlock_tryrdlock;
+ pthread_rwlock_trywrlock;
+ pthread_rwlock_unlock;
+ pthread_rwlock_wrlock;
+ pthread_rwlockattr_destroy;
+ pthread_rwlockattr_getpshared;
+ pthread_rwlockattr_init;
+ pthread_rwlockattr_setpshared;
+ pthread_self;
+ pthread_set_name_np;
+ pthread_setcancelstate;
+ pthread_setcanceltype;
+ pthread_setconcurrency;
+ pthread_setprio;
+ pthread_setschedparam;
+ pthread_setspecific;
+ pthread_sigmask;
+ pthread_single_np;
+ pthread_spin_destroy;
+ pthread_spin_init;
+ pthread_spin_lock;
+ pthread_spin_trylock;
+ pthread_spin_unlock;
+ pthread_suspend_all_np;
+ pthread_suspend_np;
+ pthread_switch_add_np;
+ pthread_switch_delete_np;
+ pthread_testcancel;
+ pthread_yield;
+ raise;
+ read;
+ readv;
+ sched_yield;
+ select;
+ sem_init;
+ sem_post;
+ sem_timedwait;
+ sem_wait;
+ sigaction;
+ sigaltstack;
+ sigpending;
+ sigprocmask;
+ sigsuspend;
+ sigwait;
+ sigwaitinfo;
+ sigtimedwait;
+ sleep;
+ system;
+ tcdrain;
+ usleep;
+ vfork;
+ wait4;
+ wait;
+ waitpid;
+ write;
+ writev;
+local:
+ *;
+};
+
+#
+# List the private interfaces reserved for use in FreeBSD libraries.
+# These are not part of our application ABI.
+#
+FBSDprivate {
+global:
+ ___creat;
+ __accept;
+ __close;
+ __connect;
+ __fcntl;
+ __fsync;
+ __msync;
+ __nanosleep;
+ __open;
+ __poll;
+ __pthread_cond_timedwait;
+ __pthread_cond_wait;
+ __pthread_mutex_init;
+ __pthread_mutex_lock;
+ __pthread_mutex_trylock;
+ __pthread_mutex_timedlock;
+ __read;
+ __readv;
+ __select;
+ __sigsuspend;
+ __sigtimedwait;
+ __sigwait;
+ __sigwaitinfo;
+ __wait4;
+ __write;
+ __writev;
+ _aio_suspend;
+ _execve;
+ _fork;
+ _nanosleep;
+ _pause;
+ _pselect;
+ _pthread_atfork;
+ _pthread_barrier_destroy;
+ _pthread_barrier_init;
+ _pthread_barrier_wait;
+ _pthread_barrierattr_destroy;
+ _pthread_barrierattr_getpshared;
+ _pthread_barrierattr_init;
+ _pthread_barrierattr_setpshared;
+ _pthread_attr_destroy;
+ _pthread_attr_get_np;
+ _pthread_attr_getdetachstate;
+ _pthread_attr_getguardsize;
+ _pthread_attr_getinheritsched;
+ _pthread_attr_getschedparam;
+ _pthread_attr_getschedpolicy;
+ _pthread_attr_getscope;
+ _pthread_attr_getstack;
+ _pthread_attr_getstackaddr;
+ _pthread_attr_getstacksize;
+ _pthread_attr_init;
+ _pthread_attr_setcreatesuspend_np;
+ _pthread_attr_setdetachstate;
+ _pthread_attr_setguardsize;
+ _pthread_attr_setinheritsched;
+ _pthread_attr_setschedparam;
+ _pthread_attr_setschedpolicy;
+ _pthread_attr_setscope;
+ _pthread_attr_setstack;
+ _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_condattr_default;
+ _pthread_condattr_destroy;
+ _pthread_condattr_init;
+ _pthread_create;
+ _pthread_detach;
+ _pthread_equal;
+ _pthread_exit;
+ _pthread_getconcurrency;
+ _pthread_getprio;
+ _pthread_getschedparam;
+ _pthread_getspecific;
+ _pthread_join;
+ _pthread_key_create;
+ _pthread_key_delete;
+ _pthread_kill;
+ _pthread_main_np;
+ _pthread_multi_np;
+ _pthread_mutex_destroy;
+ _pthread_mutex_getprioceiling;
+ _pthread_mutex_init;
+ _pthread_mutex_lock;
+ _pthread_mutex_setprioceiling;
+ _pthread_mutex_timedlock;
+ _pthread_mutex_trylock;
+ _pthread_mutex_unlock;
+ _pthread_mutexattr_default;
+ _pthread_mutexattr_destroy;
+ _pthread_mutexattr_getkind_np;
+ _pthread_mutexattr_getprioceiling;
+ _pthread_mutexattr_getprotocol;
+ _pthread_mutexattr_gettype;
+ _pthread_mutexattr_init;
+ _pthread_mutexattr_setkind_np;
+ _pthread_mutexattr_setprioceiling;
+ _pthread_mutexattr_setprotocol;
+ _pthread_mutexattr_settype;
+ _pthread_once;
+ _pthread_resume_all_np;
+ _pthread_resume_np;
+ _pthread_rwlock_destroy;
+ _pthread_rwlock_init;
+ _pthread_rwlock_rdlock;
+ _pthread_rwlock_timedrdlock;
+ _pthread_rwlock_timedwrlock;
+ _pthread_rwlock_tryrdlock;
+ _pthread_rwlock_trywrlock;
+ _pthread_rwlock_unlock;
+ _pthread_rwlock_wrlock;
+ _pthread_rwlockattr_destroy;
+ _pthread_rwlockattr_getpshared;
+ _pthread_rwlockattr_init;
+ _pthread_rwlockattr_setpshared;
+ _pthread_self;
+ _pthread_set_name_np;
+ _pthread_setcancelstate;
+ _pthread_setcanceltype;
+ _pthread_setconcurrency;
+ _pthread_setprio;
+ _pthread_setschedparam;
+ _pthread_setspecific;
+ _pthread_sigmask;
+ _pthread_single_np;
+ _pthread_spin_destroy;
+ _pthread_spin_init;
+ _pthread_spin_lock;
+ _pthread_spin_trylock;
+ _pthread_spin_unlock;
+ _pthread_suspend_all_np;
+ _pthread_suspend_np;
+ _pthread_switch_add_np;
+ _pthread_switch_delete_np;
+ _pthread_testcancel;
+ _pthread_yield;
+ _raise;
+ _sched_yield;
+ _sem_init;
+ _sem_post;
+ _sem_timedwait;
+ _sem_wait;
+ _sigaction;
+ _sigaltstack;
+ _sigpending;
+ _sigprocmask;
+ _sigsuspend;
+ _sigtimedwait;
+ _sigwait;
+ _sigwaitinfo;
+ _sleep;
+ _spinlock;
+ _spinlock_debug;
+ _spinunlock;
+ _system;
+ _tcdrain;
+ _usleep;
+ _vfork;
+ _wait;
+ _waitpid;
+
+ # Debugger needs these.
+ _libkse_debug;
+ _thread_activated;
+ _thread_active_threads;
+ _thread_keytable;
+ _thread_list;
+ _thread_max_keys;
+ _thread_off_attr_flags;
+ _thread_off_dtv;
+ _thread_off_linkmap;
+ _thread_off_next;
+ _thread_off_tcb;
+ _thread_off_tmbx;
+ _thread_off_key_allocated;
+ _thread_off_key_destructor;
+ _thread_off_kse;
+ _thread_off_kse_locklevel;
+ _thread_off_sigmask;
+ _thread_off_sigpend;
+ _thread_off_state;
+ _thread_off_thr_locklevel;
+ _thread_off_tlsindex;
+ _thread_size_key;
+ _thread_state_running;
+ _thread_state_zoombie;
+
+local:
+ *;
+};
diff --git a/lib/libpthread/support/Makefile.inc b/lib/libpthread/support/Makefile.inc
new file mode 100644
index 0000000..956667f
--- /dev/null
+++ b/lib/libpthread/support/Makefile.inc
@@ -0,0 +1,40 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/support ${.CURDIR}/../libc/gen ${.CURDIR}/../libc/string
+.PATH: ${.CURDIR}/../libc/${MACHINE_ARCH}/sys
+
+CFLAGS+= -I${.CURDIR}/../libc/${MACHINE_ARCH}
+
+SYSCALLS= clock_gettime \
+ kse_create \
+ kse_exit \
+ kse_release \
+ kse_switchin \
+ kse_thr_interrupt \
+ kse_wakeup \
+ sigaction \
+ sigprocmask \
+ sigtimedwait \
+ write
+
+SYSCALL_SRC= ${SYSCALLS:S/$/.S/}
+SYSCALL_OBJ= ${SYSCALLS:S/$/.So/}
+
+${SYSCALL_SRC}:
+ printf '#include "SYS.h"\nRSYSCALL(${.PREFIX})\n' > ${.TARGET}
+
+LIBC_OBJS= sigsetops.So \
+ bcopy.So \
+ bzero.So \
+ cerror.So \
+ memcpy.So \
+ memset.So \
+ strcpy.So \
+ strlen.So
+
+SOBJS+= thr_libc.So
+CLEANFILES+= ${SYSCALL_SRC} ${SYSCALL_OBJ} ${LIBC_OBJS}
+
+thr_libc.So: ${SYSCALL_OBJ} ${LIBC_OBJS}
+ ${CC} -fPIC -nostdlib -o ${.TARGET} -r ${.ALLSRC}
+
diff --git a/lib/libpthread/support/thr_support.c b/lib/libpthread/support/thr_support.c
new file mode 100644
index 0000000..2956e07
--- /dev/null
+++ b/lib/libpthread/support/thr_support.c
@@ -0,0 +1,62 @@
+/*-
+ * Copyright 2003 Alexander Kabaev.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list 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$
+ */
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/kse.h>
+#include <signal.h>
+#include <string.h>
+
+#include "thr_private.h"
+
+__strong_reference(clock_gettime, _thr_clock_gettime);
+__strong_reference(kse_exit, _thr_kse_exit);
+__strong_reference(kse_wakeup, _thr_kse_wakeup);
+__strong_reference(kse_create, _thr_kse_create);
+__strong_reference(kse_thr_interrupt, _thr_kse_thr_interrupt);
+__strong_reference(kse_release, _thr_kse_release);
+__strong_reference(kse_switchin, _thr_kse_switchin);
+
+__strong_reference(sigaction, _thr_sigaction);
+__strong_reference(sigprocmask, _thr_sigprocmask);
+__strong_reference(sigemptyset, _thr_sigemptyset);
+__strong_reference(sigaddset, _thr_sigaddset);
+__strong_reference(sigfillset, _thr_sigfillset);
+__strong_reference(sigismember, _thr_sigismember);
+__strong_reference(sigdelset, _thr_sigdelset);
+
+__strong_reference(memset, _thr_memset);
+__strong_reference(memcpy, _thr_memcpy);
+__strong_reference(strcpy, _thr_strcpy);
+__strong_reference(strlen, _thr_strlen);
+__strong_reference(bzero, _thr_bzero);
+__strong_reference(bcopy, _thr_bcopy);
+
+__strong_reference(__sys_write, _thr__sys_write);
+__strong_reference(__sys_sigtimedwait, _thr__sys_sigtimedwait);
+
diff --git a/lib/libpthread/sys/Makefile.inc b/lib/libpthread/sys/Makefile.inc
new file mode 100644
index 0000000..fb4a108
--- /dev/null
+++ b/lib/libpthread/sys/Makefile.inc
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/sys
+
+SRCS+= lock.c thr_error.c
diff --git a/lib/libpthread/sys/lock.c b/lib/libpthread/sys/lock.c
new file mode 100644
index 0000000..2ac8c0c
--- /dev/null
+++ b/lib/libpthread/sys/lock.c
@@ -0,0 +1,351 @@
+/*-
+ * Copyright (c) 2001, 2003 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <machine/atomic.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#include "atomic_ops.h"
+#include "lock.h"
+
+#ifdef _LOCK_DEBUG
+#define LCK_ASSERT(e) assert(e)
+#else
+#define LCK_ASSERT(e)
+#endif
+
+#define MAX_SPINS 500
+
+void
+_lock_destroy(struct lock *lck)
+{
+ if ((lck != NULL) && (lck->l_head != NULL)) {
+ free(lck->l_head);
+ lck->l_head = NULL;
+ lck->l_tail = NULL;
+ }
+}
+
+int
+_lock_init(struct lock *lck, enum lock_type ltype,
+ lock_handler_t *waitfunc, lock_handler_t *wakeupfunc)
+{
+ if (lck == NULL)
+ return (-1);
+ else if ((lck->l_head = malloc(sizeof(struct lockreq))) == NULL)
+ return (-1);
+ else {
+ lck->l_type = ltype;
+ lck->l_wait = waitfunc;
+ lck->l_wakeup = wakeupfunc;
+ lck->l_head->lr_locked = 0;
+ lck->l_head->lr_watcher = NULL;
+ lck->l_head->lr_owner = NULL;
+ lck->l_head->lr_active = 1;
+ lck->l_tail = lck->l_head;
+ }
+ return (0);
+}
+
+int
+_lock_reinit(struct lock *lck, enum lock_type ltype,
+ lock_handler_t *waitfunc, lock_handler_t *wakeupfunc)
+{
+ if (lck == NULL)
+ return (-1);
+ else if (lck->l_head == NULL)
+ return (_lock_init(lck, ltype, waitfunc, wakeupfunc));
+ else {
+ lck->l_head->lr_locked = 0;
+ lck->l_head->lr_watcher = NULL;
+ lck->l_head->lr_owner = NULL;
+ lck->l_head->lr_active = 1;
+ lck->l_tail = lck->l_head;
+ }
+ return (0);
+}
+
+int
+_lockuser_init(struct lockuser *lu, void *priv)
+{
+ if (lu == NULL)
+ return (-1);
+ else if ((lu->lu_myreq == NULL) &&
+ ((lu->lu_myreq = malloc(sizeof(struct lockreq))) == NULL))
+ return (-1);
+ else {
+ lu->lu_myreq->lr_locked = 1;
+ lu->lu_myreq->lr_watcher = NULL;
+ lu->lu_myreq->lr_owner = lu;
+ lu->lu_myreq->lr_active = 0;
+ lu->lu_watchreq = NULL;
+ lu->lu_priority = 0;
+ lu->lu_private = priv;
+ lu->lu_private2 = NULL;
+ }
+ return (0);
+}
+
+int
+_lockuser_reinit(struct lockuser *lu, void *priv)
+{
+ if (lu == NULL)
+ return (-1);
+ /*
+ * All lockusers keep their watch request and drop their
+ * own (lu_myreq) request. Their own request is either
+ * some other lockuser's watch request or is the head of
+ * the lock.
+ */
+ lu->lu_myreq = lu->lu_watchreq;
+ if (lu->lu_myreq == NULL)
+ return (_lockuser_init(lu, priv));
+ else {
+ lu->lu_myreq->lr_locked = 1;
+ lu->lu_myreq->lr_watcher = NULL;
+ lu->lu_myreq->lr_owner = lu;
+ lu->lu_myreq->lr_active = 0;
+ lu->lu_watchreq = NULL;
+ lu->lu_priority = 0;
+ lu->lu_private = priv;
+ lu->lu_private2 = NULL;
+ }
+ return (0);
+}
+
+void
+_lockuser_destroy(struct lockuser *lu)
+{
+ if ((lu != NULL) && (lu->lu_myreq != NULL))
+ free(lu->lu_myreq);
+}
+
+/*
+ * Acquire a lock waiting (spin or sleep) for it to become available.
+ */
+void
+_lock_acquire(struct lock *lck, struct lockuser *lu, int prio)
+{
+ int i;
+ int lval;
+
+ /**
+ * XXX - We probably want to remove these checks to optimize
+ * performance. It is also a bug if any one of the
+ * checks fail, so it's probably better to just let it
+ * SEGV and fix it.
+ */
+#if 0
+ if (lck == NULL || lu == NULL || lck->l_head == NULL)
+ return;
+#endif
+ if ((lck->l_type & LCK_PRIORITY) != 0) {
+ LCK_ASSERT(lu->lu_myreq->lr_locked == 1);
+ LCK_ASSERT(lu->lu_myreq->lr_watcher == NULL);
+ LCK_ASSERT(lu->lu_myreq->lr_owner == lu);
+ LCK_ASSERT(lu->lu_watchreq == NULL);
+
+ lu->lu_priority = prio;
+ }
+ /*
+ * Atomically swap the head of the lock request with
+ * this request.
+ */
+ atomic_swap_ptr(&lck->l_head, lu->lu_myreq, &lu->lu_watchreq);
+
+ if (lu->lu_watchreq->lr_locked != 0) {
+ atomic_store_rel_ptr
+ ((volatile uintptr_t *)&lu->lu_watchreq->lr_watcher,
+ (uintptr_t)lu);
+ if ((lck->l_wait == NULL) ||
+ ((lck->l_type & LCK_ADAPTIVE) == 0)) {
+ while (lu->lu_watchreq->lr_locked != 0)
+ ; /* spin, then yield? */
+ } else {
+ /*
+ * Spin for a bit before invoking the wait function.
+ *
+ * We should be a little smarter here. If we're
+ * running on a single processor, then the lock
+ * owner got preempted and spinning will accomplish
+ * nothing but waste time. If we're running on
+ * multiple processors, the owner could be running
+ * on another CPU and we might acquire the lock if
+ * we spin for a bit.
+ *
+ * The other thing to keep in mind is that threads
+ * acquiring these locks are considered to be in
+ * critical regions; they will not be preempted by
+ * the _UTS_ until they release the lock. It is
+ * therefore safe to assume that if a lock can't
+ * be acquired, it is currently held by a thread
+ * running in another KSE.
+ */
+ for (i = 0; i < MAX_SPINS; i++) {
+ if (lu->lu_watchreq->lr_locked == 0)
+ return;
+ if (lu->lu_watchreq->lr_active == 0)
+ break;
+ }
+ atomic_swap_int((int *)&lu->lu_watchreq->lr_locked,
+ 2, &lval);
+ if (lval == 0)
+ lu->lu_watchreq->lr_locked = 0;
+ else
+ lck->l_wait(lck, lu);
+
+ }
+ }
+ lu->lu_myreq->lr_active = 1;
+}
+
+/*
+ * Release a lock.
+ */
+void
+_lock_release(struct lock *lck, struct lockuser *lu)
+{
+ struct lockuser *lu_tmp, *lu_h;
+ struct lockreq *myreq;
+ int prio_h;
+ int lval;
+
+ /**
+ * XXX - We probably want to remove these checks to optimize
+ * performance. It is also a bug if any one of the
+ * checks fail, so it's probably better to just let it
+ * SEGV and fix it.
+ */
+#if 0
+ if ((lck == NULL) || (lu == NULL))
+ return;
+#endif
+ if ((lck->l_type & LCK_PRIORITY) != 0) {
+ prio_h = 0;
+ lu_h = NULL;
+
+ /* Update tail if our request is last. */
+ if (lu->lu_watchreq->lr_owner == NULL) {
+ atomic_store_rel_ptr((volatile uintptr_t *)&lck->l_tail,
+ (uintptr_t)lu->lu_myreq);
+ atomic_store_rel_ptr
+ ((volatile uintptr_t *)&lu->lu_myreq->lr_owner,
+ (uintptr_t)NULL);
+ } else {
+ /* Remove ourselves from the list. */
+ atomic_store_rel_ptr((volatile uintptr_t *)
+ &lu->lu_myreq->lr_owner,
+ (uintptr_t)lu->lu_watchreq->lr_owner);
+ atomic_store_rel_ptr((volatile uintptr_t *)
+ &lu->lu_watchreq->lr_owner->lu_myreq,
+ (uintptr_t)lu->lu_myreq);
+ }
+ /*
+ * The watch request now becomes our own because we've
+ * traded away our previous request. Save our previous
+ * request so that we can grant the lock.
+ */
+ myreq = lu->lu_myreq;
+ lu->lu_myreq = lu->lu_watchreq;
+ lu->lu_watchreq = NULL;
+ lu->lu_myreq->lr_locked = 1;
+ lu->lu_myreq->lr_owner = lu;
+ lu->lu_myreq->lr_watcher = NULL;
+ /*
+ * Traverse the list of lock requests in reverse order
+ * looking for the user with the highest priority.
+ */
+ for (lu_tmp = lck->l_tail->lr_watcher; lu_tmp != NULL;
+ lu_tmp = lu_tmp->lu_myreq->lr_watcher) {
+ if (lu_tmp->lu_priority > prio_h) {
+ lu_h = lu_tmp;
+ prio_h = lu_tmp->lu_priority;
+ }
+ }
+ if (lu_h != NULL) {
+ /* Give the lock to the highest priority user. */
+ if (lck->l_wakeup != NULL) {
+ atomic_swap_int(
+ (int *)&lu_h->lu_watchreq->lr_locked,
+ 0, &lval);
+ if (lval == 2)
+ /* Notify the sleeper */
+ lck->l_wakeup(lck,
+ lu_h->lu_myreq->lr_watcher);
+ }
+ else
+ atomic_store_rel_int(
+ &lu_h->lu_watchreq->lr_locked, 0);
+ } else {
+ if (lck->l_wakeup != NULL) {
+ atomic_swap_int((int *)&myreq->lr_locked,
+ 0, &lval);
+ if (lval == 2)
+ /* Notify the sleeper */
+ lck->l_wakeup(lck, myreq->lr_watcher);
+ }
+ else
+ /* Give the lock to the previous request. */
+ atomic_store_rel_int(&myreq->lr_locked, 0);
+ }
+ } else {
+ /*
+ * The watch request now becomes our own because we've
+ * traded away our previous request. Save our previous
+ * request so that we can grant the lock.
+ */
+ myreq = lu->lu_myreq;
+ lu->lu_myreq = lu->lu_watchreq;
+ lu->lu_watchreq = NULL;
+ lu->lu_myreq->lr_locked = 1;
+ if (lck->l_wakeup) {
+ atomic_swap_int((int *)&myreq->lr_locked, 0, &lval);
+ if (lval == 2)
+ /* Notify the sleeper */
+ lck->l_wakeup(lck, myreq->lr_watcher);
+ }
+ else
+ /* Give the lock to the previous request. */
+ atomic_store_rel_int(&myreq->lr_locked, 0);
+ }
+ lu->lu_myreq->lr_active = 0;
+}
+
+void
+_lock_grant(struct lock *lck /* unused */, struct lockuser *lu)
+{
+ atomic_store_rel_int(&lu->lu_watchreq->lr_locked, 3);
+}
+
+void
+_lockuser_setactive(struct lockuser *lu, int active)
+{
+ lu->lu_myreq->lr_active = active;
+}
+
diff --git a/lib/libpthread/sys/lock.h b/lib/libpthread/sys/lock.h
new file mode 100644
index 0000000..6102a0b
--- /dev/null
+++ b/lib/libpthread/sys/lock.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2001, 2003 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 _LOCK_H_
+#define _LOCK_H_
+
+struct lockreq;
+struct lockuser;
+struct lock;
+
+enum lock_type {
+ LCK_DEFAULT = 0x0000, /* default is FIFO spin locks */
+ LCK_PRIORITY = 0x0001,
+ LCK_ADAPTIVE = 0x0002 /* call user-supplied handlers */
+};
+
+typedef void lock_handler_t(struct lock *, struct lockuser *);
+
+struct lock {
+ struct lockreq *l_head;
+ struct lockreq *l_tail; /* only used for priority locks */
+ enum lock_type l_type;
+ lock_handler_t *l_wait; /* only used for adaptive locks */
+ lock_handler_t *l_wakeup; /* only used for adaptive locks */
+};
+
+/* Try to make this >= CACHELINESIZE */
+struct lockreq {
+ struct lockuser *lr_watcher; /* only used for priority locks */
+ struct lockuser *lr_owner; /* only used for priority locks */
+ volatile int lr_locked; /* lock granted = 0, busy otherwise */
+ volatile int lr_active; /* non-zero if the lock is last lock for thread */
+};
+
+struct lockuser {
+ struct lockreq *lu_myreq; /* request to give up/trade */
+ struct lockreq *lu_watchreq; /* watch this request */
+ int lu_priority; /* only used for priority locks */
+ void *lu_private1; /* private{1,2} are initialized to */
+ void *lu_private2; /* NULL and can be used by caller */
+#define lu_private lu_private1
+};
+
+#define _LCK_INITIALIZER(lck_req) { &lck_req, NULL, LCK_DEFAULT, \
+ NULL, NULL }
+#define _LCK_REQUEST_INITIALIZER { 0, NULL, NULL, 0 }
+
+#define _LCK_BUSY(lu) ((lu)->lu_watchreq->lr_locked != 0)
+#define _LCK_ACTIVE(lu) ((lu)->lu_watchreq->lr_active != 0)
+#define _LCK_GRANTED(lu) ((lu)->lu_watchreq->lr_locked == 3)
+
+#define _LCK_SET_PRIVATE(lu, p) (lu)->lu_private = (void *)(p)
+#define _LCK_GET_PRIVATE(lu) (lu)->lu_private
+#define _LCK_SET_PRIVATE2(lu, p) (lu)->lu_private2 = (void *)(p)
+#define _LCK_GET_PRIVATE2(lu) (lu)->lu_private2
+
+void _lock_acquire(struct lock *, struct lockuser *, int);
+void _lock_destroy(struct lock *);
+void _lock_grant(struct lock *, struct lockuser *);
+int _lock_init(struct lock *, enum lock_type,
+ lock_handler_t *, lock_handler_t *);
+int _lock_reinit(struct lock *, enum lock_type,
+ lock_handler_t *, lock_handler_t *);
+void _lock_release(struct lock *, struct lockuser *);
+int _lockuser_init(struct lockuser *lu, void *priv);
+void _lockuser_destroy(struct lockuser *lu);
+int _lockuser_reinit(struct lockuser *lu, void *priv);
+void _lockuser_setactive(struct lockuser *lu, int active);
+
+#endif
diff --git a/lib/libpthread/sys/thr_error.c b/lib/libpthread/sys/thr_error.c
new file mode 100644
index 0000000..0ba34e0
--- /dev/null
+++ b/lib/libpthread/sys/thr_error.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.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 John Birrell
+ * and Chris Provenzano.
+ * 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 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$
+ */
+#include <pthread.h>
+#include "libc_private.h"
+#include "thr_private.h"
+
+#undef errno
+extern int errno;
+
+LT10_COMPAT_DEFAULT(__error);
+
+int *
+__error(void)
+{
+ struct pthread *curthread;
+
+ if (__isthreaded == 0)
+ return (&errno);
+ else if (_kse_in_critical())
+ return &(_get_curkse()->k_error);
+ else {
+ curthread = _get_curthread();
+ if ((curthread == NULL) || (curthread == _thr_initial))
+ return (&errno);
+ else
+ return (&curthread->error);
+ }
+}
diff --git a/lib/libpthread/test/Makefile b/lib/libpthread/test/Makefile
new file mode 100644
index 0000000..5b5eb3c
--- /dev/null
+++ b/lib/libpthread/test/Makefile
@@ -0,0 +1,116 @@
+#
+# $FreeBSD$
+#
+# Automated test suite for libpthread (pthreads).
+#
+
+# File lists.
+
+# Tests written in C.
+CTESTS := hello_d.c hello_s.c join_leak_d.c mutex_d.c sem_d.c sigsuspend_d.c \
+ sigwait_d.c
+
+# C programs that are used internally by the tests. The build system merely
+# compiles these.
+BTESTS := guard_b.c hello_b.c
+
+# Tests written in perl.
+PTESTS := guard_s.pl propagate_s.pl
+
+# Munge the file lists to their final executable names (strip the .c).
+CTESTS := $(CTESTS:R)
+BTESTS := $(BTESTS:R)
+
+CPPFLAGS := -D_LIBC_R_ -D_REENTRANT
+CFLAGS := -Wall -pipe -g3
+LDFLAGS_A := -static
+LDFLAGS_P := -pg
+LDFLAGS_S :=
+LIBS := -lpthread
+
+# Flags passed to verify. "-v" or "-u" may be useful.
+VERIFY = perl verify
+VFLAGS :=
+
+all : default
+
+# Only use the following suffixes, in order to avoid any strange built-in rules.
+.SUFFIXES :
+.SUFFIXES : .c .o .d .pl
+
+# Clear out all paths, then set just one (default path) for the main build
+# directory.
+.PATH :
+.PATH : .
+
+# Build the C programs.
+.for bin in $(CTESTS) $(BTESTS)
+$(bin)_a : $(bin:S/$/&.c/)
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c $(bin:S/$/&.c/) -o $(@:S/$/&.o/)
+ $(CC) -o $@ $(@:S/$/&.o/) $(LDFLAGS_A) $(LIBS)
+ @$(SHELL) -ec "$(CC) -M $(CPPFLAGS) $(bin:S/$/&.c/) | sed \"s/\($(bin:T)\)\.o\([ :]*\)/$(bin:H:S!/!\\/!g)\/\1_a.o \2/g\" > $(@:R:S/$/&.d/)"
+
+$(bin)_p : $(bin:S/$/&.c/)
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c $(bin:S/$/&.c/) -o $(@:S/$/&.o/)
+ $(CC) -o $@ $(@:S/$/&.o/) $(LDFLAGS_P) $(LIBS)
+ @$(SHELL) -ec "$(CC) -M $(CPPFLAGS) $(bin:S/$/&.c/) | sed \"s/\($(bin:T)\)\.o\([ :]*\)/$(bin:H:S!/!\\/!g)\/\1_p.o \2/g\" > $(@:R:S/$/&.d/)"
+
+$(bin)_s : $(bin:S/$/&.c/)
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c $(bin:S/$/&.c/) -o $(@:S/$/&.o/)
+ $(CC) -o $@ $(@:S/$/&.o/) $(LDFLAGS_S) $(LIBS)
+ @$(SHELL) -ec "$(CC) -M $(CPPFLAGS) $(bin:S/$/&.c/) | sed \"s/\($(bin:T)\)\.o\([ :]*\)/$(bin:H:S!/!\\/!g)\/\1_s.o \2/g\" > $(@:R:S/$/&.d/)"
+.endfor
+
+# Dependency file inclusion.
+.for depfile in $(CTESTS:R:S/$/&_a.d/) $(BTESTS:R:S/$/&_a.d/) \
+ $(CTESTS:R:S/$/&_p.d/) $(BTESTS:R:S/$/&_p.d/) \
+ $(CTESTS:R:S/$/&_s.d/) $(BTESTS:R:S/$/&_s.d/)
+.if exists($(depfile))
+.include "$(depfile)"
+.endif
+.endfor
+
+default : check
+
+tests_a : $(CTESTS:S/$/&_a/) $(BTESTS:S/$/&_a/)
+tests_p : $(CTESTS:S/$/&_p/) $(BTESTS:S/$/&_p/)
+tests_s : $(CTESTS:S/$/&_s/) $(BTESTS:S/$/&_s/)
+
+tests : tests_a tests_p tests_s
+
+check_a : tests_a
+.for bin in $(CTESTS) $(BTESTS)
+ @cp $(bin)_a $(bin)
+.endfor
+ @echo "Test static library:"
+ @$(VERIFY) $(VFLAGS) $(CTESTS) $(PTESTS)
+
+check_p : tests_p
+.for bin in $(CTESTS) $(BTESTS)
+ @cp $(bin)_p $(bin)
+.endfor
+ @echo "Test profile library:"
+ @$(VERIFY) $(VFLAGS) $(CTESTS) $(PTESTS)
+
+check_s : tests_s
+.for bin in $(CTESTS) $(BTESTS)
+ @cp $(bin)_s $(bin)
+.endfor
+ @echo "Test shared library:"
+ @$(VERIFY) $(VFLAGS) $(CTESTS) $(PTESTS)
+
+check : check_a check_p check_s
+
+clean :
+ rm -f *~
+ rm -f *.core
+ rm -f *.out
+ rm -f *.perf
+ rm -f *.diff
+ rm -f *.gmon
+ rm -f $(CTESTS) $(BTESTS)
+ rm -f $(CTESTS:S/$/&_a/) $(BTESTS:S/$/&_a/)
+ rm -f $(CTESTS:S/$/&_p/) $(BTESTS:S/$/&_p/)
+ rm -f $(CTESTS:S/$/&_s/) $(BTESTS:S/$/&_s/)
+ rm -f *.d
+ rm -f *.o
diff --git a/lib/libpthread/test/README b/lib/libpthread/test/README
new file mode 100644
index 0000000..8f625a1
--- /dev/null
+++ b/lib/libpthread/test/README
@@ -0,0 +1,28 @@
+$FreeBSD$
+
+This test suite is meant to test general functionality of pthreads, as well as
+provide a simple framework for regression tests. In general, this test suite
+can be used with any pthreads library, but in reality there are a number of
+libpthread-specific aspects to this test suite which would require some
+effort to get around if testing another pthreads library.
+
+This test suite assumes that libpthread is installed.
+
+There are two forms of test that the 'verify' script understands. The simpler
+form is the diff format, where the output of the test program is diff'ed with
+the correspondingly named .exp file. If there is diff output, the test fails.
+The sequence test format is somewhat more complex, and is documented in the
+command line usage output for verify. The advantage of this format is that it
+allows multiple tests to pass/fail within one program.
+
+There is no driving need for test naming consistency, but the existing tests
+generally follow these conventions:
+
+<name>_d.c <name>_d.exp : Diff mode C test and expected output file.
+<name>_s.c : Sequence mode C test.
+<name>_b*.c : Back end C program used by perl tests.
+<name>_d.pl <name>_d.pl.exp : Diff mode perl test and expected output file.
+<name>_s.pl : Sequence mode perl test.
+
+<name> is something descriptive, such as "pr14685" in the case of a PR-related
+regression test, or "mutex" in the case of a test of mutexes.
diff --git a/lib/libpthread/test/guard_b.c b/lib/libpthread/test/guard_b.c
new file mode 100644
index 0000000..2e27031
--- /dev/null
+++ b/lib/libpthread/test/guard_b.c
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2001 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
+ * unmodified other than the allowable 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$
+ *
+ * Test thread stack guard functionality.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <pthread.h>
+
+#define FRAME_SIZE 1024
+#define FRAME_OVERHEAD 40
+
+struct args
+{
+ void *top; /* Top of thread's initial stack frame. */
+ int cur; /* Recursion depth. */
+ int max; /* Maximum recursion depth. */
+};
+
+void *
+recurse(void *args)
+{
+ int top;
+ struct args *parms = (struct args *)args;
+ char filler[FRAME_SIZE - FRAME_OVERHEAD];
+
+ /* Touch the memory in this stack frame. */
+ top = 0xa5;
+ memset(filler, 0xa5, sizeof(filler));
+
+ if (parms->top == NULL) {
+ /* Initial stack frame. */
+ parms->top = (void*)&top;
+ }
+
+ /*
+ * Make sure frame size is what we expect. Getting this right involves
+ * hand tweaking, so just print a warning rather than aborting.
+ */
+ if (parms->top - (void *)&top != FRAME_SIZE * parms->cur) {
+ fprintf(stderr,
+ "Stack size (%ld) != expected (%ld), frame %ld\n",
+ (long)parms->top - (long)&top,
+ (long)(FRAME_SIZE * parms->cur), (long)parms->cur);
+ }
+
+ parms->cur++;
+ if (parms->cur < parms->max)
+ recurse(args);
+
+ return NULL;
+}
+
+
+int
+main(int argc, char **argv)
+{
+ size_t def_stacksize, def_guardsize;
+ size_t stacksize, guardsize;
+ pthread_t thread;
+ pthread_attr_t attr;
+ struct args args;
+
+ if (argc != 3) {
+ fprintf(stderr, "usage: guard_b <stacksize> <guardsize>\n");
+ exit(1);
+ }
+ fprintf(stderr, "Test begin\n");
+
+ stacksize = strtoul(argv[1], NULL, 10);
+ guardsize = strtoul(argv[2], NULL, 10);
+
+ assert(pthread_attr_init(&attr) == 0);
+ /*
+ * Exercise the attribute APIs more thoroughly than is strictly
+ * necessary for the meat of this test program.
+ */
+ assert(pthread_attr_getstacksize(&attr, &def_stacksize) == 0);
+ assert(pthread_attr_getguardsize(&attr, &def_guardsize) == 0);
+ if (def_stacksize != stacksize) {
+ assert(pthread_attr_setstacksize(&attr, stacksize) == 0);
+ assert(pthread_attr_getstacksize(&attr, &def_stacksize) == 0);
+ assert(def_stacksize == stacksize);
+ }
+ if (def_guardsize != guardsize) {
+ assert(pthread_attr_setguardsize(&attr, guardsize) == 0);
+ assert(pthread_attr_getguardsize(&attr, &def_guardsize) == 0);
+ assert(def_guardsize >= guardsize);
+ }
+
+ /*
+ * Create a thread that will come just short of overflowing the thread
+ * stack. We need to leave a bit of breathing room in case the thread
+ * is context switched, and we also have to take care not to call any
+ * functions in the deepest stack frame.
+ */
+ args.top = NULL;
+ args.cur = 0;
+ args.max = (stacksize / FRAME_SIZE) - 1;
+ fprintf(stderr, "No overflow:\n");
+ assert(pthread_create(&thread, &attr, recurse, &args) == 0);
+ assert(pthread_join(thread, NULL) == 0);
+
+ /*
+ * Create a thread that will barely of overflow the thread stack. This
+ * should cause a segfault.
+ */
+ args.top = NULL;
+ args.cur = 0;
+ args.max = (stacksize / FRAME_SIZE) + 1;
+ fprintf(stderr, "Overflow:\n");
+ assert(pthread_create(&thread, &attr, recurse, &args) == 0);
+ assert(pthread_join(thread, NULL) == 0);
+
+ /* Not reached. */
+ fprintf(stderr, "Unexpected success\n");
+ abort();
+
+ return 0;
+}
diff --git a/lib/libpthread/test/guard_b.exp b/lib/libpthread/test/guard_b.exp
new file mode 100644
index 0000000..8e5b9e4
--- /dev/null
+++ b/lib/libpthread/test/guard_b.exp
@@ -0,0 +1,3 @@
+Test begin
+No overflow:
+Overflow:
diff --git a/lib/libpthread/test/guard_s.pl b/lib/libpthread/test/guard_s.pl
new file mode 100755
index 0000000..7802ff3
--- /dev/null
+++ b/lib/libpthread/test/guard_s.pl
@@ -0,0 +1,69 @@
+#!/usr/bin/perl -w
+#
+# Copyright (C) 2001 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
+# unmodified other than the allowable 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$
+#
+# Test thread stack guard functionality. The C test program needs to be driven
+# by this script because it segfaults when the stack guard is hit.
+#
+
+print "1..30\n";
+
+$i = 0;
+# Iterates 10 times.
+for ($stacksize = 65536; $stacksize < 131072; $stacksize += 7168)
+{
+ # Iterates 3 times (1024, 4096, 7168).
+ for ($guardsize = 1024; $guardsize < 8192; $guardsize += 3072)
+ {
+ $i++;
+
+ print "stacksize: $stacksize, guardsize: $guardsize\n";
+
+ `./guard_b $stacksize $guardsize >guard_b.out 2>&1`;
+
+ if (! -f "./guard_b.out")
+ {
+ print "not ok $i\n";
+ }
+ else
+ {
+ `diff guard_b.exp guard_b.out >guard_b.diff 2>&1`;
+ if ($?)
+ {
+ # diff returns non-zero if there is a difference.
+ print "not ok $i\n";
+ }
+ else
+ {
+ print "ok $i\n";
+ }
+ }
+ }
+}
diff --git a/lib/libpthread/test/hello_b.c b/lib/libpthread/test/hello_b.c
new file mode 100644
index 0000000..2eefa7f
--- /dev/null
+++ b/lib/libpthread/test/hello_b.c
@@ -0,0 +1,13 @@
+/****************************************************************************
+ *
+ * Back end C programs can be anything compilable.
+ *
+ * $FreeBSD$
+ *
+ ****************************************************************************/
+
+int
+main()
+{
+ return 0;
+}
diff --git a/lib/libpthread/test/hello_d.c b/lib/libpthread/test/hello_d.c
new file mode 100644
index 0000000..6d77526
--- /dev/null
+++ b/lib/libpthread/test/hello_d.c
@@ -0,0 +1,38 @@
+/****************************************************************************
+ *
+ * Simple diff mode test.
+ *
+ * $FreeBSD$
+ *
+ ****************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <pthread.h>
+
+void *
+entry(void * a_arg)
+{
+ fprintf(stderr, "Hello world\n");
+
+ return NULL;
+}
+
+int
+main()
+{
+ pthread_t thread;
+ int error;
+
+ error = pthread_create(&thread, NULL, entry, NULL);
+ if (error)
+ fprintf(stderr, "Error in pthread_create(): %s\n",
+ strerror(error));
+
+ error = pthread_join(thread, NULL);
+ if (error)
+ fprintf(stderr, "Error in pthread_join(): %s\n",
+ strerror(error));
+
+ return 0;
+}
diff --git a/lib/libpthread/test/hello_d.exp b/lib/libpthread/test/hello_d.exp
new file mode 100644
index 0000000..802992c
--- /dev/null
+++ b/lib/libpthread/test/hello_d.exp
@@ -0,0 +1 @@
+Hello world
diff --git a/lib/libpthread/test/hello_s.c b/lib/libpthread/test/hello_s.c
new file mode 100644
index 0000000..942bf2d
--- /dev/null
+++ b/lib/libpthread/test/hello_s.c
@@ -0,0 +1,47 @@
+/****************************************************************************
+ *
+ * Simple sequence mode test.
+ *
+ * $FreeBSD$
+ *
+ ****************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <pthread.h>
+
+void *
+entry(void * a_arg)
+{
+ fprintf(stderr, "ok 1\n");
+ fprintf(stderr, "ok \n");
+ fprintf(stderr, "ok 3\n");
+
+ return NULL;
+}
+
+int
+main()
+{
+ pthread_t thread;
+ int error;
+
+ fprintf(stderr, "1..3\n");
+
+ fprintf(stderr, "Some random text\n");
+
+ error = pthread_create(&thread, NULL, entry, NULL);
+ fprintf(stderr, "More unimportant text\n");
+ if (error)
+ fprintf(stderr,"Error in pthread_create(): %s\n",
+ strerror(error));
+
+ error = pthread_join(thread, NULL);
+ if (error)
+ fprintf(stderr, "Error in pthread_join(): %s\n",
+ strerror(error));
+
+ fprintf(stderr, "Hello world\n");
+
+ return 0;
+}
diff --git a/lib/libpthread/test/join_leak_d.c b/lib/libpthread/test/join_leak_d.c
new file mode 100644
index 0000000..6532ca5
--- /dev/null
+++ b/lib/libpthread/test/join_leak_d.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2001 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$
+ *
+ * Test for leaked joined threads.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <errno.h>
+#include <string.h>
+#include <pthread.h>
+
+#define NITERATIONS 16384
+#define MAXGROWTH 16384
+
+void *
+thread_entry(void *a_arg)
+{
+ return NULL;
+}
+
+int
+main(void)
+{
+ pthread_t thread;
+ int i, error;
+ char *brk, *nbrk;
+ unsigned growth;
+
+ fprintf(stderr, "Test begin\n");
+
+ /* Get an initial brk value. */
+ brk = sbrk(0);
+
+ /* Create threads and join them, one at a time. */
+ for (i = 0; i < NITERATIONS; i++) {
+ if ((error = pthread_create(&thread, NULL, thread_entry, NULL))
+ != 0) {
+ fprintf(stderr, "Error in pthread_create(): %s\n",
+ strerror(error));
+ exit(1);
+ }
+ if ((error = pthread_join(thread, NULL)) != 0) {
+ fprintf(stderr, "Error in pthread_join(): %s\n",
+ strerror(error));
+ exit(1);
+ }
+ }
+
+ /* Get a final brk value. */
+ nbrk = sbrk(0);
+
+ /*
+ * Check that the amount of heap space allocated is below an acceptable
+ * threshold. We could just compare brk and nbrk, but the test could
+ * conceivably break if the internals of the threads library changes.
+ */
+ if (nbrk > brk) {
+ /* Heap grows up. */
+ growth = nbrk - brk;
+ } else if (nbrk <= brk) {
+ /* Heap grows down, or no growth. */
+ growth = brk - nbrk;
+ }
+
+ if (growth > MAXGROWTH) {
+ fprintf(stderr, "Heap growth exceeded maximum (%u > %u)\n",
+ growth, MAXGROWTH);
+ }
+#if (0)
+ else {
+ fprintf(stderr, "Heap growth acceptable (%u <= %u)\n",
+ growth, MAXGROWTH);
+ }
+#endif
+
+ fprintf(stderr, "Test end\n");
+ return 0;
+}
diff --git a/lib/libpthread/test/join_leak_d.exp b/lib/libpthread/test/join_leak_d.exp
new file mode 100644
index 0000000..369a88d
--- /dev/null
+++ b/lib/libpthread/test/join_leak_d.exp
@@ -0,0 +1,2 @@
+Test begin
+Test end
diff --git a/lib/libpthread/test/mutex_d.c b/lib/libpthread/test/mutex_d.c
new file mode 100644
index 0000000..2aa3b1d
--- /dev/null
+++ b/lib/libpthread/test/mutex_d.c
@@ -0,0 +1,1558 @@
+/*
+ * Copyright (c) 1998 Daniel M. Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel M. Eischen.
+ * 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 DANIEL M. 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <assert.h>
+#include <errno.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <sysexits.h>
+#include "pthread.h"
+
+#if defined(_LIBC_R_)
+#include <pthread_np.h>
+#endif
+
+#ifndef NELEMENTS
+#define NELEMENTS(arr) (sizeof (arr) / sizeof (arr[0]))
+#endif
+
+#ifndef NUM_THREADS
+#define NUM_THREADS 10
+#endif
+
+#define MAX_THREAD_CMDS 10
+
+static void log_error(const char *, ...) __printflike(1, 2);
+static void log_trace (const char *, ...) __printflike(1, 2);
+static void log (const char *, ...) __printflike(1, 2);
+
+/*------------------------------------------------------------
+ * Types
+ *----------------------------------------------------------*/
+
+typedef enum {
+ STAT_INITIAL, /* initial state */
+ STAT_WAITCONDVAR, /* waiting for condition variable signal */
+ STAT_WAITMUTEX /* waiting for mutex lock */
+} thread_status_t;
+
+typedef enum {
+ FLAGS_REPORT_WAITCONDMUTEX = 0x01,
+ FLAGS_REPORT_WAITCONDVAR = 0x02,
+ FLAGS_REPORT_WAITMUTEX = 0x04,
+ FLAGS_REPORT_BUSY_LOOP = 0x08,
+ FLAGS_IS_BUSY = 0x10,
+ FLAGS_WAS_BUSY = 0x20
+} thread_flags_t;
+
+typedef enum {
+ CMD_NONE,
+ CMD_TAKE_MUTEX,
+ CMD_RELEASE_MUTEX,
+ CMD_WAIT_FOR_SIGNAL,
+ CMD_BUSY_LOOP,
+ CMD_PROTECTED_OP,
+ CMD_RELEASE_ALL
+} thread_cmd_id_t;
+
+typedef struct {
+ thread_cmd_id_t cmd_id;
+ pthread_mutex_t *mutex;
+ pthread_cond_t *cond;
+} thread_cmd_t;
+
+typedef struct {
+ pthread_cond_t cond_var;
+ thread_status_t status;
+ thread_cmd_t cmd;
+ int flags;
+ int priority;
+ int ret;
+ pthread_t tid;
+ u_int8_t id;
+} thread_state_t;
+
+typedef enum {
+ M_POSIX,
+ M_SS2_DEFAULT,
+ M_SS2_ERRORCHECK,
+ M_SS2_NORMAL,
+ M_SS2_RECURSIVE
+} mutex_kind_t;
+
+
+/*------------------------------------------------------------
+ * Constants
+ *----------------------------------------------------------*/
+
+const char *protocol_strs[] = {
+ "PTHREAD_PRIO_NONE",
+ "PTHREAD_PRIO_INHERIT",
+ "PTHREAD_PRIO_PROTECT"
+};
+
+const int protocols[] = {
+ PTHREAD_PRIO_NONE,
+ PTHREAD_PRIO_INHERIT,
+ PTHREAD_PRIO_PROTECT
+};
+
+const char *mutextype_strs[] = {
+ "POSIX (type not specified)",
+ "SS2 PTHREAD_MUTEX_DEFAULT",
+ "SS2 PTHREAD_MUTEX_ERRORCHECK",
+ "SS2 PTHREAD_MUTEX_NORMAL",
+ "SS2 PTHREAD_MUTEX_RECURSIVE"
+};
+
+const int mutex_types[] = {
+ 0, /* M_POSIX */
+ PTHREAD_MUTEX_DEFAULT, /* M_SS2_DEFAULT */
+ PTHREAD_MUTEX_ERRORCHECK, /* M_SS2_ERRORCHECK */
+ PTHREAD_MUTEX_NORMAL, /* M_SS2_NORMAL */
+ PTHREAD_MUTEX_RECURSIVE /* M_SS2_RECURSIVE */
+};
+
+
+/*------------------------------------------------------------
+ * Objects
+ *----------------------------------------------------------*/
+
+static int done = 0;
+static int trace_enabled = 0;
+static int use_global_condvar = 0;
+static thread_state_t states[NUM_THREADS];
+static int pipefd[2];
+
+static pthread_mutex_t waiter_mutex;
+static pthread_mutex_t cond_mutex;
+static pthread_cond_t cond_var;
+
+static FILE *logfile;
+static int error_count = 0, pass_count = 0, total = 0;
+
+
+/*------------------------------------------------------------
+ * Prototypes
+ *----------------------------------------------------------*/
+extern char *strtok_r(char *str, const char *sep, char **last);
+
+
+/*------------------------------------------------------------
+ * Functions
+ *----------------------------------------------------------*/
+
+#if defined(_LIBC_R_) && defined(DEBUG)
+static void
+kern_switch (pthread_t pthread_out, pthread_t pthread_in)
+{
+ if (pthread_out != NULL)
+ printf ("Swapping out thread 0x%lx, ", (long) pthread_out);
+ else
+ printf ("Swapping out kernel thread, ");
+
+ if (pthread_in != NULL)
+ printf ("swapping in thread 0x%lx\n", (long) pthread_in);
+ else
+ printf ("swapping in kernel thread.\n");
+}
+#endif
+
+
+static void
+log_error (const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start (ap, fmt);
+ fprintf (logfile, "FAIL: ");
+ vfprintf (logfile, fmt, ap);
+ error_count = error_count + 1;
+ total = total + 1;
+}
+
+
+static void
+log_pass (void)
+{
+ fprintf (logfile, "PASS\n");
+ pass_count = pass_count + 1;
+ total = total + 1;
+}
+
+
+static void
+log_trace (const char *fmt, ...)
+{
+ va_list ap;
+
+ if (trace_enabled) {
+ va_start (ap, fmt);
+ vfprintf (logfile, fmt, ap);
+ }
+}
+
+
+static void
+log (const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start (ap, fmt);
+ vfprintf (logfile, fmt, ap);
+}
+
+
+static void
+check_result (int expected, int actual)
+{
+ if (expected != actual)
+ log_error ("expected %d, returned %d\n", expected, actual);
+ else
+ log_pass ();
+}
+
+
+/*
+ * Check to see that the threads ran in the specified order.
+ */
+static void
+check_run_order (char *order)
+{
+ const char *sep = ":,";
+ char *tok, *last, *idstr, *endptr;
+ int expected_id, bytes, count = 0, errors = 0;
+ u_int8_t id;
+
+ assert ((tok = (char *) malloc (strlen(order) + 1)) != NULL);
+ strcpy (tok, order); /* tok has to be larger than order */
+ assert (ioctl (pipefd[0], FIONREAD, &bytes) == 0);
+ log_trace ("%d bytes read from FIFO.\n", bytes);
+
+ for (idstr = strtok_r (tok, sep, &last);
+ (idstr != NULL) && (count < bytes);
+ idstr = strtok_r (NULL, sep, &last)) {
+
+ /* Get the expected id: */
+ expected_id = (int) strtol (idstr, &endptr, 10);
+ assert ((endptr != NULL) && (*endptr == '\0'));
+
+ /* Read the actual id from the pipe: */
+ assert (read (pipefd[0], &id, sizeof (id)) == sizeof (id));
+ count = count + sizeof (id);
+
+ if (id != expected_id) {
+ log_trace ("Thread %d ran out of order.\n", id);
+ errors = errors + 1;
+ }
+ else {
+ log_trace ("Thread %d at priority %d reporting.\n",
+ (int) id, states[id].priority);
+ }
+ }
+
+ if (count < bytes) {
+ /* Clear the pipe: */
+ while (count < bytes) {
+ read (pipefd[0], &id, sizeof (id));
+ count = count + 1;
+ errors = errors + 1;
+ }
+ }
+ else if (bytes < count)
+ errors = errors + count - bytes;
+
+ if (errors == 0)
+ log_pass ();
+ else
+ log_error ("%d threads ran out of order", errors);
+}
+
+
+static void *
+waiter (void *arg)
+{
+ thread_state_t *statep = (thread_state_t *) arg;
+ pthread_mutex_t *held_mutex[MAX_THREAD_CMDS];
+ int held_mutex_owned[MAX_THREAD_CMDS];
+ sigset_t mask;
+ struct timeval tv1, tv2;
+ thread_cmd_t cmd;
+ int i, mutex_count = 0;
+
+ statep->status = STAT_INITIAL;
+
+ /* Block all signals except for interrupt.*/
+ sigfillset (&mask);
+ sigdelset (&mask, SIGINT);
+ sigprocmask (SIG_BLOCK, &mask, NULL);
+
+ while (done == 0) {
+ /* Wait for signal from the main thread to continue. */
+ statep->status = STAT_WAITMUTEX;
+ log_trace ("Thread %d: locking cond_mutex.\n",
+ (int) statep->id);
+ pthread_mutex_lock (&cond_mutex);
+
+ /* Do we report our status. */
+ if (statep->flags & FLAGS_REPORT_WAITCONDMUTEX)
+ write (pipefd[1], &statep->id, sizeof (statep->id));
+ log_trace ("Thread %d: waiting for cond_var.\n",
+ (int) statep->id);
+
+ /* Wait for a command. */
+ statep->status = STAT_WAITCONDVAR;
+
+ /*
+ * The threads are allowed commanded to wait either on
+ * their own unique condition variable (so they may be
+ * separately signaled) or on one global condition variable
+ * (so they may be signaled together).
+ */
+ if (use_global_condvar != 0)
+ pthread_cond_wait (&cond_var, &cond_mutex);
+ else
+ pthread_cond_wait (&statep->cond_var, &cond_mutex);
+
+ /* Do we report our status? */
+ if (statep->flags & FLAGS_REPORT_WAITCONDVAR) {
+ write (pipefd[1], &statep->id, sizeof (statep->id));
+ log_trace ("Thread %d: wrote to pipe.\n",
+ (int) statep->id);
+ }
+ log_trace ("Thread %d: received cond_var signal.\n",
+ (int) statep->id);
+
+ /* Get a copy of the command before releasing the mutex. */
+ cmd = statep->cmd;
+
+ /* Clear the command after copying it. */
+ statep->cmd.cmd_id = CMD_NONE;
+
+ /* Unlock the condition variable mutex. */
+ assert (pthread_mutex_unlock (&cond_mutex) == 0);
+
+ /* Peform the command.*/
+ switch (cmd.cmd_id) {
+ case CMD_TAKE_MUTEX:
+ statep->ret = pthread_mutex_lock (cmd.mutex);
+ if (statep->ret == 0) {
+ assert (mutex_count < sizeof (held_mutex));
+ held_mutex[mutex_count] = cmd.mutex;
+ held_mutex_owned[mutex_count] = 1;
+ mutex_count++;
+ }
+ else {
+ held_mutex_owned[mutex_count] = 0;
+ log_trace ("Thread id %d unable to lock mutex, "
+ "error = %d\n", (int) statep->id,
+ statep->ret);
+ }
+ break;
+
+ case CMD_RELEASE_MUTEX:
+ assert ((mutex_count <= sizeof (held_mutex)) &&
+ (mutex_count > 0));
+ mutex_count--;
+ if (held_mutex_owned[mutex_count] != 0)
+ assert (pthread_mutex_unlock
+ (held_mutex[mutex_count]) == 0);
+ break;
+
+ case CMD_WAIT_FOR_SIGNAL:
+ assert (pthread_mutex_lock (cmd.mutex) == 0);
+ assert (pthread_cond_wait (cmd.cond, cmd.mutex) == 0);
+ assert (pthread_mutex_unlock (cmd.mutex) == 0);
+ break;
+
+ case CMD_BUSY_LOOP:
+ log_trace ("Thread %d: Entering busy loop.\n",
+ (int) statep->id);
+ /* Spin for 15 seconds. */
+ assert (gettimeofday (&tv2, NULL) == 0);
+ tv1.tv_sec = tv2.tv_sec + 5;
+ tv1.tv_usec = tv2.tv_usec;
+ statep->flags |= FLAGS_IS_BUSY;
+ while (timercmp (&tv2, &tv1,<)) {
+ assert (gettimeofday (&tv2, NULL) == 0);
+ }
+ statep->flags &= ~FLAGS_IS_BUSY;
+ statep->flags |= FLAGS_WAS_BUSY;
+
+ /* Do we report our status? */
+ if (statep->flags & FLAGS_REPORT_BUSY_LOOP)
+ write (pipefd[1], &statep->id,
+ sizeof (statep->id));
+
+ log_trace ("Thread %d: Leaving busy loop.\n",
+ (int) statep->id);
+ break;
+
+ case CMD_PROTECTED_OP:
+ assert (pthread_mutex_lock (cmd.mutex) == 0);
+ statep->flags |= FLAGS_WAS_BUSY;
+ /* Do we report our status? */
+ if (statep->flags & FLAGS_REPORT_BUSY_LOOP)
+ write (pipefd[1], &statep->id,
+ sizeof (statep->id));
+
+ assert (pthread_mutex_unlock (cmd.mutex) == 0);
+ break;
+
+ case CMD_RELEASE_ALL:
+ assert ((mutex_count <= sizeof (held_mutex)) &&
+ (mutex_count > 0));
+ for (i = mutex_count - 1; i >= 0; i--) {
+ if (held_mutex_owned[i] != 0)
+ assert (pthread_mutex_unlock
+ (held_mutex[i]) == 0);
+ }
+ mutex_count = 0;
+ break;
+
+ case CMD_NONE:
+ default:
+ break;
+ }
+
+ /* Wait for the big giant waiter lock. */
+ statep->status = STAT_WAITMUTEX;
+ log_trace ("Thread %d: waiting for big giant lock.\n",
+ (int) statep->id);
+ pthread_mutex_lock (&waiter_mutex);
+ if (statep->flags & FLAGS_REPORT_WAITMUTEX)
+ write (pipefd[1], &statep->id, sizeof (statep->id));
+ log_trace ("Thread %d: got big giant lock.\n",
+ (int) statep->id);
+ statep->status = STAT_INITIAL;
+ pthread_mutex_unlock (&waiter_mutex);
+ }
+
+ log_trace ("Thread %ld: Exiting thread 0x%lx\n", (long) statep->id,
+ (long) pthread_self());
+ pthread_exit (arg);
+ return (NULL);
+}
+
+
+static void *
+lock_twice (void *arg)
+{
+ thread_state_t *statep = (thread_state_t *) arg;
+ sigset_t mask;
+
+ statep->status = STAT_INITIAL;
+
+ /* Block all signals except for interrupt.*/
+ sigfillset (&mask);
+ sigdelset (&mask, SIGINT);
+ sigprocmask (SIG_BLOCK, &mask, NULL);
+
+ /* Wait for a signal to continue. */
+ log_trace ("Thread %d: locking cond_mutex.\n", (int) statep->id);
+ pthread_mutex_lock (&cond_mutex);
+
+ log_trace ("Thread %d: waiting for cond_var.\n", (int) statep->id);
+ statep->status = STAT_WAITCONDVAR;
+ pthread_cond_wait (&cond_var, &cond_mutex);
+
+ log_trace ("Thread %d: received cond_var signal.\n", (int) statep->id);
+
+ /* Unlock the condition variable mutex. */
+ assert (pthread_mutex_unlock (&cond_mutex) == 0);
+
+ statep->status = STAT_WAITMUTEX;
+ /* Lock the mutex once. */
+ assert (pthread_mutex_lock (statep->cmd.mutex) == 0);
+
+ /* Lock it again and capture the error. */
+ statep->ret = pthread_mutex_lock (statep->cmd.mutex);
+ statep->status = 0;
+
+ assert (pthread_mutex_unlock (statep->cmd.mutex) == 0);
+
+ /* Unlock it again if it is locked recursively. */
+ if (statep->ret == 0)
+ pthread_mutex_unlock (statep->cmd.mutex);
+
+ log_trace ("Thread %ld: Exiting thread 0x%lx\n", (long) statep->id,
+ (long) pthread_self());
+ pthread_exit (arg);
+ return (NULL);
+}
+
+
+static void
+sighandler (int signo)
+{
+ log ("Signal handler caught signal %d, thread id 0x%lx\n",
+ signo, (long) pthread_self());
+
+ if (signo == SIGINT)
+ done = 1;
+}
+
+
+static void
+send_cmd (int id, thread_cmd_id_t cmd)
+{
+ assert (pthread_mutex_lock (&cond_mutex) == 0);
+ assert (states[id].status == STAT_WAITCONDVAR);
+ states[id].cmd.cmd_id = cmd;
+ states[id].cmd.mutex = NULL;
+ states[id].cmd.cond = NULL;
+ /* Clear the busy flags. */
+ states[id].flags &= ~(FLAGS_WAS_BUSY | FLAGS_IS_BUSY);
+ assert (pthread_cond_signal (&states[id].cond_var) == 0);
+ assert (pthread_mutex_unlock (&cond_mutex) == 0);
+}
+
+
+static void
+send_mutex_cmd (int id, thread_cmd_id_t cmd, pthread_mutex_t *m)
+{
+ assert (pthread_mutex_lock (&cond_mutex) == 0);
+ assert (states[id].status == STAT_WAITCONDVAR);
+ states[id].cmd.cmd_id = cmd;
+ states[id].cmd.mutex = m;
+ states[id].cmd.cond = NULL;
+ /* Clear the busy flags. */
+ states[id].flags &= ~(FLAGS_WAS_BUSY | FLAGS_IS_BUSY);
+ assert (pthread_cond_signal (&states[id].cond_var) == 0);
+ assert (pthread_mutex_unlock (&cond_mutex) == 0);
+}
+
+
+static void
+send_mutex_cv_cmd (int id, thread_cmd_id_t cmd, pthread_mutex_t *m,
+ pthread_cond_t *cv)
+{
+ assert (pthread_mutex_lock (&cond_mutex) == 0);
+ assert (states[id].status == STAT_WAITCONDVAR);
+ states[id].cmd.cmd_id = cmd;
+ states[id].cmd.mutex = m;
+ states[id].cmd.cond = cv;
+ /* Clear the busy flags. */
+ states[id].flags &= ~(FLAGS_WAS_BUSY | FLAGS_IS_BUSY);
+ assert (pthread_cond_signal (&states[id].cond_var) == 0);
+ assert (pthread_mutex_unlock (&cond_mutex) == 0);
+}
+
+
+static void
+mutex_init_test (void)
+{
+ pthread_mutexattr_t mattr;
+ pthread_mutex_t mutex;
+ mutex_kind_t mkind;
+ int mproto, ret;
+
+ /*
+ * Initialize a mutex attribute.
+ *
+ * pthread_mutexattr_init not tested for: ENOMEM
+ */
+ assert (pthread_mutexattr_init (&mattr) == 0);
+
+ /*
+ * Initialize a mutex.
+ *
+ * pthread_mutex_init not tested for: EAGAIN ENOMEM EPERM EBUSY
+ */
+ log ("Testing pthread_mutex_init\n");
+ log ("--------------------------\n");
+
+ for (mproto = 0; mproto < NELEMENTS(protocols); mproto++) {
+ for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) {
+ /* Initialize the mutex attribute. */
+ assert (pthread_mutexattr_init (&mattr) == 0);
+ assert (pthread_mutexattr_setprotocol (&mattr,
+ protocols[mproto]) == 0);
+
+ /*
+ * Ensure that the first mutex type is a POSIX
+ * compliant mutex.
+ */
+ if (mkind != M_POSIX) {
+ assert (pthread_mutexattr_settype (&mattr,
+ mutex_types[mkind]) == 0);
+ }
+
+ log (" Protocol %s, Type %s - ",
+ protocol_strs[mproto], mutextype_strs[mkind]);
+ ret = pthread_mutex_init (&mutex, &mattr);
+ check_result (/* expected */ 0, ret);
+ assert (pthread_mutex_destroy (&mutex) == 0);
+
+ /*
+ * Destroy a mutex attribute.
+ *
+ * XXX - There should probably be a magic number
+ * associated with a mutex attribute so that
+ * destroy can be reasonably sure the attribute
+ * is valid.
+ *
+ * pthread_mutexattr_destroy not tested for: EINVAL
+ */
+ assert (pthread_mutexattr_destroy (&mattr) == 0);
+ }
+ }
+}
+
+
+static void
+mutex_destroy_test (void)
+{
+ pthread_mutexattr_t mattr;
+ pthread_mutex_t mutex;
+ pthread_condattr_t cattr;
+ pthread_cond_t cv;
+ pthread_attr_t pattr;
+ int mproto, ret;
+ mutex_kind_t mkind;
+ thread_state_t state;
+
+ /*
+ * Destroy a mutex.
+ *
+ * XXX - There should probably be a magic number associated
+ * with a mutex so that destroy can be reasonably sure
+ * the mutex is valid.
+ *
+ * pthread_mutex_destroy not tested for:
+ */
+ log ("Testing pthread_mutex_destroy\n");
+ log ("-----------------------------\n");
+
+ assert (pthread_attr_init (&pattr) == 0);
+ assert (pthread_attr_setdetachstate (&pattr,
+ PTHREAD_CREATE_DETACHED) == 0);
+ state.flags = 0; /* No flags yet. */
+
+ for (mproto = 0; mproto < NELEMENTS(protocols); mproto++) {
+ for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) {
+ /* Initialize the mutex attribute. */
+ assert (pthread_mutexattr_init (&mattr) == 0);
+ assert (pthread_mutexattr_setprotocol (&mattr,
+ protocols[mproto]) == 0);
+
+ /*
+ * Ensure that the first mutex type is a POSIX
+ * compliant mutex.
+ */
+ if (mkind != M_POSIX) {
+ assert (pthread_mutexattr_settype (&mattr,
+ mutex_types[mkind]) == 0);
+ }
+
+ /* Create the mutex. */
+ assert (pthread_mutex_init (&mutex, &mattr) == 0);
+
+ log (" Protocol %s, Type %s\n",
+ protocol_strs[mproto], mutextype_strs[mkind]);
+
+ log (" Destruction of unused mutex - ");
+ assert (pthread_mutex_init (&mutex, &mattr) == 0);
+ ret = pthread_mutex_destroy (&mutex);
+ check_result (/* expected */ 0, ret);
+
+ log (" Destruction of mutex locked by self - ");
+ assert (pthread_mutex_init (&mutex, &mattr) == 0);
+ assert (pthread_mutex_lock (&mutex) == 0);
+ ret = pthread_mutex_destroy (&mutex);
+ check_result (/* expected */ EBUSY, ret);
+ assert (pthread_mutex_unlock (&mutex) == 0);
+ assert (pthread_mutex_destroy (&mutex) == 0);
+
+ log (" Destruction of mutex locked by another "
+ "thread - ");
+ assert (pthread_mutex_init (&mutex, &mattr) == 0);
+ send_mutex_cmd (0, CMD_TAKE_MUTEX, &mutex);
+ sleep (1);
+ ret = pthread_mutex_destroy (&mutex);
+ check_result (/* expected */ EBUSY, ret);
+ send_cmd (0, CMD_RELEASE_ALL);
+ sleep (1);
+ assert (pthread_mutex_destroy (&mutex) == 0);
+
+ log (" Destruction of mutex while being used in "
+ "cond_wait - ");
+ assert (pthread_mutex_init (&mutex, &mattr) == 0);
+ assert (pthread_condattr_init (&cattr) == 0);
+ assert (pthread_cond_init (&cv, &cattr) == 0);
+ send_mutex_cv_cmd (0, CMD_WAIT_FOR_SIGNAL, &mutex, &cv);
+ sleep (1);
+ ret = pthread_mutex_destroy (&mutex);
+ check_result (/* expected */ EBUSY, ret);
+ pthread_cond_signal (&cv);
+ sleep (1);
+ assert (pthread_mutex_destroy (&mutex) == 0);
+ }
+ }
+}
+
+
+static void
+mutex_lock_test (void)
+{
+ pthread_mutexattr_t mattr;
+ pthread_mutex_t mutex;
+ pthread_attr_t pattr;
+ int mproto, ret;
+ mutex_kind_t mkind;
+ thread_state_t state;
+
+ /*
+ * Lock a mutex.
+ *
+ * pthread_lock not tested for:
+ */
+ log ("Testing pthread_mutex_lock\n");
+ log ("--------------------------\n");
+
+ assert (pthread_attr_init (&pattr) == 0);
+ assert (pthread_attr_setdetachstate (&pattr,
+ PTHREAD_CREATE_DETACHED) == 0);
+ state.flags = 0; /* No flags yet. */
+
+ for (mproto = 0; mproto < NELEMENTS(protocols); mproto++) {
+ for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) {
+ /* Initialize the mutex attribute. */
+ assert (pthread_mutexattr_init (&mattr) == 0);
+ assert (pthread_mutexattr_setprotocol (&mattr,
+ protocols[mproto]) == 0);
+
+ /*
+ * Ensure that the first mutex type is a POSIX
+ * compliant mutex.
+ */
+ if (mkind != M_POSIX) {
+ assert (pthread_mutexattr_settype (&mattr,
+ mutex_types[mkind]) == 0);
+ }
+
+ /* Create the mutex. */
+ assert (pthread_mutex_init (&mutex, &mattr) == 0);
+
+ log (" Protocol %s, Type %s\n",
+ protocol_strs[mproto], mutextype_strs[mkind]);
+
+ log (" Lock on unlocked mutex - ");
+ ret = pthread_mutex_lock (&mutex);
+ check_result (/* expected */ 0, ret);
+ pthread_mutex_unlock (&mutex);
+
+ log (" Lock on invalid mutex - ");
+ ret = pthread_mutex_lock (NULL);
+ check_result (/* expected */ EINVAL, ret);
+
+ log (" Lock on mutex held by self - ");
+ assert (pthread_create (&state.tid, &pattr, lock_twice,
+ (void *) &state) == 0);
+ /* Let the thread start. */
+ sleep (1);
+ state.cmd.mutex = &mutex;
+ state.ret = 0xdeadbeef;
+ assert (pthread_mutex_lock (&cond_mutex) == 0);
+ assert (pthread_cond_signal (&cond_var) == 0);
+ assert (pthread_mutex_unlock (&cond_mutex) == 0);
+ /* Let the thread receive and process the command. */
+ sleep (1);
+
+ switch (mkind) {
+ case M_POSIX:
+ check_result (/* expected */ EDEADLK,
+ state.ret);
+ break;
+ case M_SS2_DEFAULT:
+ check_result (/* expected */ EDEADLK,
+ state.ret);
+ break;
+ case M_SS2_ERRORCHECK:
+ check_result (/* expected */ EDEADLK,
+ state.ret);
+ break;
+ case M_SS2_NORMAL:
+ check_result (/* expected */ 0xdeadbeef,
+ state.ret);
+ break;
+ case M_SS2_RECURSIVE:
+ check_result (/* expected */ 0, state.ret);
+ break;
+ }
+ pthread_mutex_destroy (&mutex);
+ pthread_mutexattr_destroy (&mattr);
+ }
+ }
+}
+
+
+static void
+mutex_unlock_test (void)
+{
+ const int test_thread_id = 0; /* ID of test thread */
+ pthread_mutexattr_t mattr;
+ pthread_mutex_t mutex;
+ int mproto, ret;
+ mutex_kind_t mkind;
+
+ /*
+ * Unlock a mutex.
+ *
+ * pthread_unlock not tested for:
+ */
+ log ("Testing pthread_mutex_unlock\n");
+ log ("----------------------------\n");
+
+ for (mproto = 0; mproto < NELEMENTS(protocols); mproto++) {
+ for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) {
+ /* Initialize the mutex attribute. */
+ assert (pthread_mutexattr_init (&mattr) == 0);
+ assert (pthread_mutexattr_setprotocol (&mattr,
+ protocols[mproto]) == 0);
+
+ /*
+ * Ensure that the first mutex type is a POSIX
+ * compliant mutex.
+ */
+ if (mkind != M_POSIX) {
+ assert (pthread_mutexattr_settype (&mattr,
+ mutex_types[mkind]) == 0);
+ }
+
+ /* Create the mutex. */
+ assert (pthread_mutex_init (&mutex, &mattr) == 0);
+
+ log (" Protocol %s, Type %s\n",
+ protocol_strs[mproto], mutextype_strs[mkind]);
+
+ log (" Unlock on mutex held by self - ");
+ assert (pthread_mutex_lock (&mutex) == 0);
+ ret = pthread_mutex_unlock (&mutex);
+ check_result (/* expected */ 0, ret);
+
+ log (" Unlock on invalid mutex - ");
+ ret = pthread_mutex_unlock (NULL);
+ check_result (/* expected */ EINVAL, ret);
+
+ log (" Unlock on mutex locked by another thread - ");
+ send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &mutex);
+ sleep (1);
+ ret = pthread_mutex_unlock (&mutex);
+ switch (mkind) {
+ case M_POSIX:
+ check_result (/* expected */ EPERM, ret);
+ break;
+ case M_SS2_DEFAULT:
+ check_result (/* expected */ EPERM, ret);
+ break;
+ case M_SS2_ERRORCHECK:
+ check_result (/* expected */ EPERM, ret);
+ break;
+ case M_SS2_NORMAL:
+ check_result (/* expected */ EPERM, ret);
+ break;
+ case M_SS2_RECURSIVE:
+ check_result (/* expected */ EPERM, ret);
+ break;
+ }
+ if (ret == 0) {
+ /*
+ * If for some reason we were able to unlock
+ * the mutex, relock it so that the test
+ * thread has no problems releasing the mutex.
+ */
+ pthread_mutex_lock (&mutex);
+ }
+ send_cmd (test_thread_id, CMD_RELEASE_ALL);
+ sleep (1);
+
+ pthread_mutex_destroy (&mutex);
+ pthread_mutexattr_destroy (&mattr);
+ }
+ }
+}
+
+
+static void
+queueing_order_test (void)
+{
+ int i;
+
+ log ("Testing queueing order\n");
+ log ("----------------------\n");
+ assert (pthread_mutex_lock (&waiter_mutex) == 0);
+ /*
+ * Tell the threads to report when they take the waiters mutex.
+ */
+ assert (pthread_mutex_lock (&cond_mutex) == 0);
+ for (i = 0; i < NUM_THREADS; i++) {
+ states[i].flags = FLAGS_REPORT_WAITMUTEX;
+ assert (pthread_cond_signal (&states[i].cond_var) == 0);
+ }
+ assert (pthread_mutex_unlock (&cond_mutex) == 0);
+
+ /* Signal the threads to continue. */
+ sleep (1);
+
+ /* Use the global condition variable next time. */
+ use_global_condvar = 1;
+
+ /* Release the waiting threads and allow them to run again. */
+ assert (pthread_mutex_unlock (&waiter_mutex) == 0);
+ sleep (1);
+
+ log (" Queueing order on a mutex - ");
+ check_run_order ("9,8,7,6,5,4,3,2,1,0");
+ for (i = 0; i < NUM_THREADS; i = i + 1) {
+ /* Tell the threads to report when they've been signaled. */
+ states[i].flags = FLAGS_REPORT_WAITCONDVAR;
+ }
+
+ /*
+ * Prevent the threads from continuing their loop after we
+ * signal them.
+ */
+ assert (pthread_mutex_lock (&waiter_mutex) == 0);
+
+
+ log (" Queueing order on a condition variable - ");
+ /*
+ * Signal one thread to run and see that the highest priority
+ * thread executes.
+ */
+ assert (pthread_mutex_lock (&cond_mutex) == 0);
+ assert (pthread_cond_signal (&cond_var) == 0);
+ assert (pthread_mutex_unlock (&cond_mutex) == 0);
+ sleep (1);
+ if (states[NUM_THREADS - 1].status != STAT_WAITMUTEX)
+ log_error ("highest priority thread does not run.\n");
+
+ /* Signal the remaining threads. */
+ assert (pthread_mutex_lock (&cond_mutex) == 0);
+ assert (pthread_cond_broadcast (&cond_var) == 0);
+ assert (pthread_mutex_unlock (&cond_mutex) == 0);
+ sleep (1);
+
+ check_run_order ("9,8,7,6,5,4,3,2,1,0");
+ for (i = 0; i < NUM_THREADS; i = i + 1) {
+ /* Tell the threads not to report anything. */
+ states[i].flags = 0;
+ }
+
+ /* Use the thread unique condition variable next time. */
+ use_global_condvar = 0;
+
+ /* Allow the threads to continue their loop. */
+ assert (pthread_mutex_unlock (&waiter_mutex) == 0);
+ sleep (1);
+}
+
+
+static void
+mutex_prioceiling_test (void)
+{
+ const int test_thread_id = 0; /* ID of test thread */
+ pthread_mutexattr_t mattr;
+ struct sched_param param;
+ pthread_mutex_t m[3];
+ mutex_kind_t mkind;
+ int i, ret, policy, my_prio, old_ceiling;
+
+ log ("Testing priority ceilings\n");
+ log ("-------------------------\n");
+ for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) {
+
+ log (" Protype PTHREAD_PRIO_PROTECT, Type %s\n",
+ mutextype_strs[mkind]);
+
+ /*
+ * Initialize and create a mutex.
+ */
+ assert (pthread_mutexattr_init (&mattr) == 0);
+
+ /* Get this threads current priority. */
+ assert (pthread_getschedparam (pthread_self(), &policy,
+ &param) == 0);
+ my_prio = param.sched_priority; /* save for later use */
+ log_trace ("Current scheduling policy %d, priority %d\n",
+ policy, my_prio);
+
+ /*
+ * Initialize and create 3 priority protection mutexes with
+ * default (max priority) ceilings.
+ */
+ assert (pthread_mutexattr_setprotocol(&mattr,
+ PTHREAD_PRIO_PROTECT) == 0);
+
+ /*
+ * Ensure that the first mutex type is a POSIX
+ * compliant mutex.
+ */
+ if (mkind != M_POSIX) {
+ assert (pthread_mutexattr_settype (&mattr,
+ mutex_types[mkind]) == 0);
+ }
+
+ for (i = 0; i < 3; i++)
+ assert (pthread_mutex_init (&m[i], &mattr) == 0);
+
+ /*
+ * Set the ceiling priorities for the 3 priority protection
+ * mutexes to, 5 less than, equal to, and 5 greater than,
+ * this threads current priority.
+ */
+ for (i = 0; i < 3; i++)
+ assert (pthread_mutex_setprioceiling (&m[i],
+ my_prio - 5 + 5*i, &old_ceiling) == 0);
+
+ /*
+ * Check that if we attempt to take a mutex whose priority
+ * ceiling is lower than our priority, we get an error.
+ */
+ log (" Lock with ceiling priority < thread priority - ");
+ ret = pthread_mutex_lock (&m[0]);
+ check_result (/* expected */ EINVAL, ret);
+ if (ret == 0)
+ pthread_mutex_unlock (&m[0]);
+
+ /*
+ * Check that we can take a mutex whose priority ceiling
+ * is equal to our priority.
+ */
+ log (" Lock with ceiling priority = thread priority - ");
+ ret = pthread_mutex_lock (&m[1]);
+ check_result (/* expected */ 0, ret);
+ if (ret == 0)
+ pthread_mutex_unlock (&m[1]);
+
+ /*
+ * Check that we can take a mutex whose priority ceiling
+ * is higher than our priority.
+ */
+ log (" Lock with ceiling priority > thread priority - ");
+ ret = pthread_mutex_lock (&m[2]);
+ check_result (/* expected */ 0, ret);
+ if (ret == 0)
+ pthread_mutex_unlock (&m[2]);
+
+ /*
+ * Have the test thread go into a busy loop for 5 seconds
+ * and see that it doesn't block this thread (since the
+ * priority ceiling of mutex 0 and the priority of the test
+ * thread are both less than the priority of this thread).
+ */
+ log (" Preemption with ceiling priority < thread "
+ "priority - ");
+ /* Have the test thread take mutex 0. */
+ send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &m[0]);
+ sleep (1);
+
+ log_trace ("Sending busy command.\n");
+ send_cmd (test_thread_id, CMD_BUSY_LOOP);
+ log_trace ("Busy sent, yielding\n");
+ pthread_yield ();
+ log_trace ("Returned from yield.\n");
+ if (states[test_thread_id].flags &
+ (FLAGS_IS_BUSY | FLAGS_WAS_BUSY))
+ log_error ("test thread inproperly preempted us.\n");
+ else {
+ /* Let the thread finish its busy loop. */
+ sleep (6);
+ if ((states[test_thread_id].flags & FLAGS_WAS_BUSY) == 0)
+ log_error ("test thread never finished.\n");
+ else
+ log_pass ();
+ }
+ states[test_thread_id].flags &= ~FLAGS_WAS_BUSY;
+
+ /* Have the test thread release mutex 0. */
+ send_cmd (test_thread_id, CMD_RELEASE_ALL);
+ sleep (1);
+
+ /*
+ * Have the test thread go into a busy loop for 5 seconds
+ * and see that it preempts this thread (since the priority
+ * ceiling of mutex 1 is the same as the priority of this
+ * thread). The test thread should not run to completion
+ * as its time quantum should expire before the 5 seconds
+ * are up.
+ */
+ log (" Preemption with ceiling priority = thread "
+ "priority - ");
+
+ /* Have the test thread take mutex 1. */
+ send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &m[1]);
+ sleep (1);
+
+ log_trace ("Sending busy\n");
+ send_cmd (test_thread_id, CMD_BUSY_LOOP);
+ log_trace ("Busy sent, yielding\n");
+ pthread_yield ();
+ log_trace ("Returned from yield.\n");
+ if ((states[test_thread_id].flags & FLAGS_IS_BUSY) == 0)
+ log_error ("test thread did not switch in on yield.\n");
+ else if (states[test_thread_id].flags & FLAGS_WAS_BUSY)
+ log_error ("test thread ran to completion.\n");
+ else {
+ /* Let the thread finish its busy loop. */
+ sleep (6);
+ if ((states[test_thread_id].flags & FLAGS_WAS_BUSY) == 0)
+ log_error ("test thread never finished.\n");
+ else
+ log_pass ();
+ }
+ states[test_thread_id].flags &= ~FLAGS_WAS_BUSY;
+
+ /* Have the test thread release mutex 1. */
+ send_cmd (test_thread_id, CMD_RELEASE_ALL);
+ sleep (1);
+
+ /*
+ * Set the scheduling policy of the test thread to SCHED_FIFO
+ * and have it go into a busy loop for 5 seconds. This
+ * thread is SCHED_RR, and since the priority ceiling of
+ * mutex 1 is the same as the priority of this thread, the
+ * test thread should run to completion once it is switched
+ * in.
+ */
+ log (" SCHED_FIFO scheduling and ceiling priority = "
+ "thread priority - ");
+ param.sched_priority = states[test_thread_id].priority;
+ assert (pthread_setschedparam (states[test_thread_id].tid,
+ SCHED_FIFO, &param) == 0);
+
+ /* Have the test thread take mutex 1. */
+ send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &m[1]);
+ sleep (1);
+
+ log_trace ("Sending busy\n");
+ send_cmd (test_thread_id, CMD_BUSY_LOOP);
+ log_trace ("Busy sent, yielding\n");
+ pthread_yield ();
+ log_trace ("Returned from yield.\n");
+ if ((states[test_thread_id].flags & FLAGS_WAS_BUSY) == 0) {
+ log_error ("test thread did not run to completion.\n");
+ /* Let the thread finish it's busy loop. */
+ sleep (6);
+ }
+ else
+ log_pass ();
+ states[test_thread_id].flags &= ~FLAGS_WAS_BUSY;
+
+ /* Restore the test thread scheduling parameters. */
+ param.sched_priority = states[test_thread_id].priority;
+ assert (pthread_setschedparam (states[test_thread_id].tid,
+ SCHED_RR, &param) == 0);
+
+ /* Have the test thread release mutex 1. */
+ send_cmd (test_thread_id, CMD_RELEASE_ALL);
+ sleep (1);
+
+ /*
+ * Have the test thread go into a busy loop for 5 seconds
+ * and see that it preempts this thread (since the priority
+ * ceiling of mutex 2 is the greater than the priority of
+ * this thread). The test thread should run to completion
+ * and block this thread because its active priority is
+ * higher.
+ */
+ log (" SCHED_FIFO scheduling and ceiling priority > "
+ "thread priority - ");
+ /* Have the test thread take mutex 2. */
+ send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &m[2]);
+ sleep (1);
+
+ log_trace ("Sending busy\n");
+ send_cmd (test_thread_id, CMD_BUSY_LOOP);
+ log_trace ("Busy sent, yielding\n");
+ pthread_yield ();
+ log_trace ("Returned from yield.\n");
+ if ((states[test_thread_id].flags & FLAGS_IS_BUSY) != 0) {
+ log_error ("test thread did not run to completion.\n");
+ /* Let the thread finish it's busy loop. */
+ sleep (6);
+ }
+ else if ((states[test_thread_id].flags & FLAGS_WAS_BUSY) == 0)
+ log_error ("test thread never finished.\n");
+ else
+ log_pass ();
+ states[test_thread_id].flags &= ~FLAGS_WAS_BUSY;
+
+ /* Have the test thread release mutex 2. */
+ send_cmd (test_thread_id, CMD_RELEASE_ALL);
+ sleep (1);
+
+ /* Destroy the mutexes. */
+ for (i = 0; i < 3; i++)
+ assert (pthread_mutex_destroy (&m[i]) == 0);
+ }
+}
+
+
+static void
+mutex_prioinherit_test (void)
+{
+ pthread_mutexattr_t mattr;
+ struct sched_param param;
+ pthread_mutex_t m[3];
+ mutex_kind_t mkind;
+ int i, policy, my_prio;
+
+ /* Get this threads current priority. */
+ assert (pthread_getschedparam (pthread_self(), &policy,
+ &param) == 0);
+ my_prio = param.sched_priority; /* save for later use */
+ log_trace ("Current scheduling policy %d, priority %d\n",
+ policy, my_prio);
+
+ log ("Testing priority inheritence\n");
+ log ("----------------------------\n");
+ for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) {
+
+ log (" Protype PTHREAD_PRIO_INHERIT, Type %s\n",
+ mutextype_strs[mkind]);
+
+ /*
+ * Initialize and create a mutex.
+ */
+ assert (pthread_mutexattr_init (&mattr) == 0);
+
+ /*
+ * Initialize and create 3 priority inheritence mutexes with
+ * default (max priority) ceilings.
+ */
+ assert (pthread_mutexattr_setprotocol(&mattr,
+ PTHREAD_PRIO_INHERIT) == 0);
+
+ /*
+ * Ensure that the first mutex type is a POSIX
+ * compliant mutex.
+ */
+ if (mkind != M_POSIX) {
+ assert (pthread_mutexattr_settype (&mattr,
+ mutex_types[mkind]) == 0);
+ }
+
+ for (i = 0; i < 3; i++)
+ assert (pthread_mutex_init (&m[i], &mattr) == 0);
+
+ /*
+ * Test setup:
+ * Thread 4 - take mutex 0, 1
+ * Thread 2 - enter protected busy loop with mutex 0
+ * Thread 3 - enter protected busy loop with mutex 1
+ * Thread 4 - enter protected busy loop with mutex 2
+ * Thread 5 - enter busy loop
+ * Thread 6 - enter protected busy loop with mutex 0
+ * Thread 4 - releases mutexes 1 and 0.
+ *
+ * Expected results:
+ * Threads complete in order 4, 6, 5, 3, 2
+ */
+ log (" Simple inheritence test - ");
+
+ /*
+ * Command thread 4 to take mutexes 0 and 1.
+ */
+ send_mutex_cmd (4, CMD_TAKE_MUTEX, &m[0]);
+ sleep (1); /* Allow command to be received. */
+ send_mutex_cmd (4, CMD_TAKE_MUTEX, &m[1]);
+ sleep (1);
+
+ /*
+ * Tell the threads to report themselves when they are
+ * at the bottom of their loop (waiting on wait_mutex).
+ */
+ for (i = 0; i < NUM_THREADS; i++)
+ states[i].flags |= FLAGS_REPORT_WAITMUTEX;
+
+ /*
+ * Command thread 2 to take mutex 0 and thread 3 to take
+ * mutex 1, both via a protected operation command. Since
+ * thread 4 owns mutexes 0 and 1, both threads 2 and 3
+ * will block until the mutexes are released by thread 4.
+ */
+ log_trace ("Commanding protected operation to thread 2.\n");
+ send_mutex_cmd (2, CMD_PROTECTED_OP, &m[0]);
+ log_trace ("Commanding protected operation to thread 3.\n");
+ send_mutex_cmd (3, CMD_PROTECTED_OP, &m[1]);
+ sleep (1);
+
+ /*
+ * Command thread 4 to take mutex 2 via a protected operation
+ * and thread 5 to enter a busy loop for 5 seconds. Since
+ * thread 5 has higher priority than thread 4, thread 5 will
+ * enter the busy loop before thread 4 is activated.
+ */
+ log_trace ("Commanding protected operation to thread 4.\n");
+ send_mutex_cmd (4, CMD_PROTECTED_OP, &m[2]);
+ log_trace ("Commanding busy loop to thread 5.\n");
+ send_cmd (5, CMD_BUSY_LOOP);
+ sleep (1);
+ if ((states[5].flags & FLAGS_IS_BUSY) == 0)
+ log_error ("thread 5 is not running.\n");
+ log_trace ("Commanding protected operation thread 6.\n");
+ send_mutex_cmd (6, CMD_PROTECTED_OP, &m[0]);
+ sleep (1);
+ if ((states[4].flags & FLAGS_WAS_BUSY) == 0)
+ log_error ("thread 4 failed to inherit priority.\n");
+ states[4].flags = 0;
+ send_cmd (4, CMD_RELEASE_ALL);
+ sleep (5);
+ check_run_order ("4,6,5,3,2");
+
+ /*
+ * Clear the flags.
+ */
+ for (i = 0; i < NUM_THREADS; i++)
+ states[i].flags = 0;
+
+ /*
+ * Test setup:
+ * Thread 2 - enter busy loop (SCHED_FIFO)
+ * Thread 4 - take mutex 0
+ * Thread 4 - priority change to same priority as thread 2
+ * Thread 4 - release mutex 0
+ *
+ * Expected results:
+ * Since thread 4 owns a priority mutex, it should be
+ * placed at the front of the run queue (for its new
+ * priority slot) when its priority is lowered to the
+ * same priority as thread 2. If thread 4 did not own
+ * a priority mutex, then it would have been added to
+ * the end of the run queue and thread 2 would have
+ * executed until it blocked (because it's scheduling
+ * policy is SCHED_FIFO).
+ *
+ */
+ log (" Inheritence test with change of priority - ");
+
+ /*
+ * Change threads 2 and 4 scheduling policies to be
+ * SCHED_FIFO.
+ */
+ param.sched_priority = states[2].priority;
+ assert (pthread_setschedparam (states[2].tid, SCHED_FIFO,
+ &param) == 0);
+ param.sched_priority = states[4].priority;
+ assert (pthread_setschedparam (states[4].tid, SCHED_FIFO,
+ &param) == 0);
+
+ /*
+ * Command thread 4 to take mutex 0.
+ */
+ send_mutex_cmd (4, CMD_TAKE_MUTEX, &m[0]);
+ sleep (1);
+
+ /*
+ * Command thread 2 to enter busy loop.
+ */
+ send_cmd (2, CMD_BUSY_LOOP);
+ sleep (1); /* Allow command to be received. */
+
+ /*
+ * Command thread 4 to enter busy loop.
+ */
+ send_cmd (4, CMD_BUSY_LOOP);
+ sleep (1); /* Allow command to be received. */
+
+ /* Have threads 2 and 4 report themselves. */
+ states[2].flags = FLAGS_REPORT_WAITMUTEX;
+ states[4].flags = FLAGS_REPORT_WAITMUTEX;
+
+ /* Change the priority of thread 4. */
+ param.sched_priority = states[2].priority;
+ assert (pthread_setschedparam (states[4].tid, SCHED_FIFO,
+ &param) == 0);
+ sleep (5);
+ check_run_order ("4,2");
+
+ /* Clear the flags */
+ states[2].flags = 0;
+ states[4].flags = 0;
+
+ /* Reset the policies. */
+ param.sched_priority = states[2].priority;
+ assert (pthread_setschedparam (states[2].tid, SCHED_RR,
+ &param) == 0);
+ param.sched_priority = states[4].priority;
+ assert (pthread_setschedparam (states[4].tid, SCHED_RR,
+ &param) == 0);
+
+ send_cmd (4, CMD_RELEASE_MUTEX);
+ sleep (1);
+
+ /* Destroy the mutexes. */
+ for (i = 0; i < 3; i++)
+ assert (pthread_mutex_destroy (&m[i]) == 0);
+ }
+}
+
+
+int main (int argc, char *argv[])
+{
+ pthread_mutexattr_t mattr;
+ pthread_condattr_t cattr;
+ pthread_attr_t pattr;
+ int i, policy, main_prio;
+ void * exit_status;
+ sigset_t mask;
+ struct sigaction act;
+ struct sched_param param;
+
+ logfile = stdout;
+
+ assert (pthread_getschedparam (pthread_self (), &policy, &param) == 0);
+ main_prio = param.sched_priority;
+
+ /* Setupt our signal mask. */
+ sigfillset (&mask);
+ sigdelset (&mask, SIGINT);
+ sigprocmask (SIG_SETMASK, &mask, NULL);
+
+ /* Install a signal handler for SIGINT */
+ sigemptyset (&act.sa_mask);
+ sigaddset (&act.sa_mask, SIGINT);
+ act.sa_handler = sighandler;
+ act.sa_flags = SA_RESTART;
+ sigaction (SIGINT, &act, NULL);
+
+ /* This test relies on the concurrency level being 1. */
+ pthread_setconcurrency(1);
+
+ /*
+ * Initialize the thread attribute.
+ */
+ assert (pthread_attr_init (&pattr) == 0);
+ assert (pthread_attr_setdetachstate (&pattr,
+ PTHREAD_CREATE_JOINABLE) == 0);
+
+ /*
+ * Initialize and create the waiter and condvar mutexes.
+ */
+ assert (pthread_mutexattr_init (&mattr) == 0);
+ assert (pthread_mutex_init (&waiter_mutex, &mattr) == 0);
+ assert (pthread_mutex_init (&cond_mutex, &mattr) == 0);
+
+ /*
+ * Initialize and create a condition variable.
+ */
+ assert (pthread_condattr_init (&cattr) == 0);
+ assert (pthread_cond_init (&cond_var, &cattr) == 0);
+
+ /* Create a pipe to catch the results of thread wakeups. */
+ assert (pipe (pipefd) == 0);
+
+#if defined(_LIBC_R_) && defined(DEBUG)
+ assert (pthread_switch_add_np (kern_switch) == 0);
+#endif
+
+ /*
+ * Create the waiting threads.
+ */
+ for (i = 0; i < NUM_THREADS; i++) {
+ assert (pthread_cond_init (&states[i].cond_var, &cattr) == 0);
+ states[i].id = (u_int8_t) i; /* NUM_THREADS must be <= 256 */
+ states[i].status = 0;
+ states[i].cmd.cmd_id = CMD_NONE;
+ states[i].flags = 0; /* No flags yet. */
+ assert (pthread_create (&states[i].tid, &pattr, waiter,
+ (void *) &states[i]) == 0);
+ param.sched_priority = main_prio - 10 + i;
+ states[i].priority = param.sched_priority;
+ assert (pthread_setschedparam (states[i].tid, SCHED_OTHER,
+ &param) == 0);
+#if defined(_LIBC_R_)
+ {
+ char buf[30];
+
+ snprintf (buf, sizeof(buf), "waiter_%d", i);
+ pthread_set_name_np (states[i].tid, buf);
+ }
+#endif
+ }
+
+ /* Allow the threads to start. */
+ sleep (1);
+ log_trace ("Done creating threads.\n");
+
+ log ("\n");
+ mutex_init_test ();
+ log ("\n");
+ mutex_destroy_test ();
+ log ("\n");
+ mutex_lock_test ();
+ log ("\n");
+ mutex_unlock_test ();
+ log ("\n");
+ queueing_order_test ();
+ log ("\n");
+ mutex_prioinherit_test ();
+ log ("\n");
+ mutex_prioceiling_test ();
+ log ("\n");
+
+ log ("Total tests %d, passed %d, failed %d\n",
+ total, pass_count, error_count);
+
+ /* Set the done flag and signal the threads to exit. */
+ log_trace ("Setting done flag.\n");
+ done = 1;
+
+ /*
+ * Wait for the threads to finish.
+ */
+ log_trace ("Trying to join threads.\n");
+ for (i = 0; i < NUM_THREADS; i++) {
+ send_cmd (i, CMD_NONE);
+ assert (pthread_join (states[i].tid, &exit_status) == 0);
+ }
+
+ /* Clean up after ourselves. */
+ close (pipefd[0]);
+ close (pipefd[1]);
+
+ if (error_count != 0)
+ exit (EX_OSERR); /* any better ideas??? */
+ else
+ exit (EX_OK);
+}
diff --git a/lib/libpthread/test/mutex_d.exp b/lib/libpthread/test/mutex_d.exp
new file mode 100644
index 0000000..de8a4e4
--- /dev/null
+++ b/lib/libpthread/test/mutex_d.exp
@@ -0,0 +1,290 @@
+
+Testing pthread_mutex_init
+--------------------------
+ Protocol PTHREAD_PRIO_NONE, Type POSIX (type not specified) - PASS
+ Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_DEFAULT - PASS
+ Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_ERRORCHECK - PASS
+ Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_NORMAL - PASS
+ Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_RECURSIVE - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type POSIX (type not specified) - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_DEFAULT - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_ERRORCHECK - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_NORMAL - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_RECURSIVE - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type POSIX (type not specified) - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_DEFAULT - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_ERRORCHECK - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_NORMAL - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_RECURSIVE - PASS
+
+Testing pthread_mutex_destroy
+-----------------------------
+ Protocol PTHREAD_PRIO_NONE, Type POSIX (type not specified)
+ Destruction of unused mutex - PASS
+ Destruction of mutex locked by self - PASS
+ Destruction of mutex locked by another thread - PASS
+ Destruction of mutex while being used in cond_wait - PASS
+ Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_DEFAULT
+ Destruction of unused mutex - PASS
+ Destruction of mutex locked by self - PASS
+ Destruction of mutex locked by another thread - PASS
+ Destruction of mutex while being used in cond_wait - PASS
+ Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_ERRORCHECK
+ Destruction of unused mutex - PASS
+ Destruction of mutex locked by self - PASS
+ Destruction of mutex locked by another thread - PASS
+ Destruction of mutex while being used in cond_wait - PASS
+ Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_NORMAL
+ Destruction of unused mutex - PASS
+ Destruction of mutex locked by self - PASS
+ Destruction of mutex locked by another thread - PASS
+ Destruction of mutex while being used in cond_wait - PASS
+ Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_RECURSIVE
+ Destruction of unused mutex - PASS
+ Destruction of mutex locked by self - PASS
+ Destruction of mutex locked by another thread - PASS
+ Destruction of mutex while being used in cond_wait - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type POSIX (type not specified)
+ Destruction of unused mutex - PASS
+ Destruction of mutex locked by self - PASS
+ Destruction of mutex locked by another thread - PASS
+ Destruction of mutex while being used in cond_wait - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_DEFAULT
+ Destruction of unused mutex - PASS
+ Destruction of mutex locked by self - PASS
+ Destruction of mutex locked by another thread - PASS
+ Destruction of mutex while being used in cond_wait - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_ERRORCHECK
+ Destruction of unused mutex - PASS
+ Destruction of mutex locked by self - PASS
+ Destruction of mutex locked by another thread - PASS
+ Destruction of mutex while being used in cond_wait - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_NORMAL
+ Destruction of unused mutex - PASS
+ Destruction of mutex locked by self - PASS
+ Destruction of mutex locked by another thread - PASS
+ Destruction of mutex while being used in cond_wait - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_RECURSIVE
+ Destruction of unused mutex - PASS
+ Destruction of mutex locked by self - PASS
+ Destruction of mutex locked by another thread - PASS
+ Destruction of mutex while being used in cond_wait - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type POSIX (type not specified)
+ Destruction of unused mutex - PASS
+ Destruction of mutex locked by self - PASS
+ Destruction of mutex locked by another thread - PASS
+ Destruction of mutex while being used in cond_wait - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_DEFAULT
+ Destruction of unused mutex - PASS
+ Destruction of mutex locked by self - PASS
+ Destruction of mutex locked by another thread - PASS
+ Destruction of mutex while being used in cond_wait - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_ERRORCHECK
+ Destruction of unused mutex - PASS
+ Destruction of mutex locked by self - PASS
+ Destruction of mutex locked by another thread - PASS
+ Destruction of mutex while being used in cond_wait - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_NORMAL
+ Destruction of unused mutex - PASS
+ Destruction of mutex locked by self - PASS
+ Destruction of mutex locked by another thread - PASS
+ Destruction of mutex while being used in cond_wait - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_RECURSIVE
+ Destruction of unused mutex - PASS
+ Destruction of mutex locked by self - PASS
+ Destruction of mutex locked by another thread - PASS
+ Destruction of mutex while being used in cond_wait - PASS
+
+Testing pthread_mutex_lock
+--------------------------
+ Protocol PTHREAD_PRIO_NONE, Type POSIX (type not specified)
+ Lock on unlocked mutex - PASS
+ Lock on invalid mutex - PASS
+ Lock on mutex held by self - PASS
+ Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_DEFAULT
+ Lock on unlocked mutex - PASS
+ Lock on invalid mutex - PASS
+ Lock on mutex held by self - PASS
+ Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_ERRORCHECK
+ Lock on unlocked mutex - PASS
+ Lock on invalid mutex - PASS
+ Lock on mutex held by self - PASS
+ Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_NORMAL
+ Lock on unlocked mutex - PASS
+ Lock on invalid mutex - PASS
+ Lock on mutex held by self - PASS
+ Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_RECURSIVE
+ Lock on unlocked mutex - PASS
+ Lock on invalid mutex - PASS
+ Lock on mutex held by self - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type POSIX (type not specified)
+ Lock on unlocked mutex - PASS
+ Lock on invalid mutex - PASS
+ Lock on mutex held by self - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_DEFAULT
+ Lock on unlocked mutex - PASS
+ Lock on invalid mutex - PASS
+ Lock on mutex held by self - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_ERRORCHECK
+ Lock on unlocked mutex - PASS
+ Lock on invalid mutex - PASS
+ Lock on mutex held by self - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_NORMAL
+ Lock on unlocked mutex - PASS
+ Lock on invalid mutex - PASS
+ Lock on mutex held by self - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_RECURSIVE
+ Lock on unlocked mutex - PASS
+ Lock on invalid mutex - PASS
+ Lock on mutex held by self - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type POSIX (type not specified)
+ Lock on unlocked mutex - PASS
+ Lock on invalid mutex - PASS
+ Lock on mutex held by self - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_DEFAULT
+ Lock on unlocked mutex - PASS
+ Lock on invalid mutex - PASS
+ Lock on mutex held by self - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_ERRORCHECK
+ Lock on unlocked mutex - PASS
+ Lock on invalid mutex - PASS
+ Lock on mutex held by self - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_NORMAL
+ Lock on unlocked mutex - PASS
+ Lock on invalid mutex - PASS
+ Lock on mutex held by self - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_RECURSIVE
+ Lock on unlocked mutex - PASS
+ Lock on invalid mutex - PASS
+ Lock on mutex held by self - PASS
+
+Testing pthread_mutex_unlock
+----------------------------
+ Protocol PTHREAD_PRIO_NONE, Type POSIX (type not specified)
+ Unlock on mutex held by self - PASS
+ Unlock on invalid mutex - PASS
+ Unlock on mutex locked by another thread - PASS
+ Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_DEFAULT
+ Unlock on mutex held by self - PASS
+ Unlock on invalid mutex - PASS
+ Unlock on mutex locked by another thread - PASS
+ Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_ERRORCHECK
+ Unlock on mutex held by self - PASS
+ Unlock on invalid mutex - PASS
+ Unlock on mutex locked by another thread - PASS
+ Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_NORMAL
+ Unlock on mutex held by self - PASS
+ Unlock on invalid mutex - PASS
+ Unlock on mutex locked by another thread - PASS
+ Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_RECURSIVE
+ Unlock on mutex held by self - PASS
+ Unlock on invalid mutex - PASS
+ Unlock on mutex locked by another thread - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type POSIX (type not specified)
+ Unlock on mutex held by self - PASS
+ Unlock on invalid mutex - PASS
+ Unlock on mutex locked by another thread - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_DEFAULT
+ Unlock on mutex held by self - PASS
+ Unlock on invalid mutex - PASS
+ Unlock on mutex locked by another thread - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_ERRORCHECK
+ Unlock on mutex held by self - PASS
+ Unlock on invalid mutex - PASS
+ Unlock on mutex locked by another thread - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_NORMAL
+ Unlock on mutex held by self - PASS
+ Unlock on invalid mutex - PASS
+ Unlock on mutex locked by another thread - PASS
+ Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_RECURSIVE
+ Unlock on mutex held by self - PASS
+ Unlock on invalid mutex - PASS
+ Unlock on mutex locked by another thread - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type POSIX (type not specified)
+ Unlock on mutex held by self - PASS
+ Unlock on invalid mutex - PASS
+ Unlock on mutex locked by another thread - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_DEFAULT
+ Unlock on mutex held by self - PASS
+ Unlock on invalid mutex - PASS
+ Unlock on mutex locked by another thread - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_ERRORCHECK
+ Unlock on mutex held by self - PASS
+ Unlock on invalid mutex - PASS
+ Unlock on mutex locked by another thread - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_NORMAL
+ Unlock on mutex held by self - PASS
+ Unlock on invalid mutex - PASS
+ Unlock on mutex locked by another thread - PASS
+ Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_RECURSIVE
+ Unlock on mutex held by self - PASS
+ Unlock on invalid mutex - PASS
+ Unlock on mutex locked by another thread - PASS
+
+Testing queueing order
+----------------------
+ Queueing order on a mutex - PASS
+ Queueing order on a condition variable - PASS
+
+Testing priority inheritence
+----------------------------
+ Protype PTHREAD_PRIO_INHERIT, Type POSIX (type not specified)
+ Simple inheritence test - PASS
+ Inheritence test with change of priority - PASS
+ Protype PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_DEFAULT
+ Simple inheritence test - PASS
+ Inheritence test with change of priority - PASS
+ Protype PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_ERRORCHECK
+ Simple inheritence test - PASS
+ Inheritence test with change of priority - PASS
+ Protype PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_NORMAL
+ Simple inheritence test - PASS
+ Inheritence test with change of priority - PASS
+ Protype PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_RECURSIVE
+ Simple inheritence test - PASS
+ Inheritence test with change of priority - PASS
+
+Testing priority ceilings
+-------------------------
+ Protype PTHREAD_PRIO_PROTECT, Type POSIX (type not specified)
+ Lock with ceiling priority < thread priority - PASS
+ Lock with ceiling priority = thread priority - PASS
+ Lock with ceiling priority > thread priority - PASS
+ Preemption with ceiling priority < thread priority - PASS
+ Preemption with ceiling priority = thread priority - PASS
+ SCHED_FIFO scheduling and ceiling priority = thread priority - PASS
+ SCHED_FIFO scheduling and ceiling priority > thread priority - PASS
+ Protype PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_DEFAULT
+ Lock with ceiling priority < thread priority - PASS
+ Lock with ceiling priority = thread priority - PASS
+ Lock with ceiling priority > thread priority - PASS
+ Preemption with ceiling priority < thread priority - PASS
+ Preemption with ceiling priority = thread priority - PASS
+ SCHED_FIFO scheduling and ceiling priority = thread priority - PASS
+ SCHED_FIFO scheduling and ceiling priority > thread priority - PASS
+ Protype PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_ERRORCHECK
+ Lock with ceiling priority < thread priority - PASS
+ Lock with ceiling priority = thread priority - PASS
+ Lock with ceiling priority > thread priority - PASS
+ Preemption with ceiling priority < thread priority - PASS
+ Preemption with ceiling priority = thread priority - PASS
+ SCHED_FIFO scheduling and ceiling priority = thread priority - PASS
+ SCHED_FIFO scheduling and ceiling priority > thread priority - PASS
+ Protype PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_NORMAL
+ Lock with ceiling priority < thread priority - PASS
+ Lock with ceiling priority = thread priority - PASS
+ Lock with ceiling priority > thread priority - PASS
+ Preemption with ceiling priority < thread priority - PASS
+ Preemption with ceiling priority = thread priority - PASS
+ SCHED_FIFO scheduling and ceiling priority = thread priority - PASS
+ SCHED_FIFO scheduling and ceiling priority > thread priority - PASS
+ Protype PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_RECURSIVE
+ Lock with ceiling priority < thread priority - PASS
+ Lock with ceiling priority = thread priority - PASS
+ Lock with ceiling priority > thread priority - PASS
+ Preemption with ceiling priority < thread priority - PASS
+ Preemption with ceiling priority = thread priority - PASS
+ SCHED_FIFO scheduling and ceiling priority = thread priority - PASS
+ SCHED_FIFO scheduling and ceiling priority > thread priority - PASS
+
+Total tests 212, passed 212, failed 0
diff --git a/lib/libpthread/test/propagate_s.pl b/lib/libpthread/test/propagate_s.pl
new file mode 100755
index 0000000..6b85090
--- /dev/null
+++ b/lib/libpthread/test/propagate_s.pl
@@ -0,0 +1,74 @@
+#!/usr/bin/perl -w
+#
+# 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.
+#
+###########################################################################
+#
+# Verify that no cancellation points are propagated inside of libpthread.
+#
+# $FreeBSD$
+#
+
+@CPOINTS = ("aio_suspend", "close", "creat", "fcntl", "fsync", "mq_receive",
+ "mq_send", "msync", "nanosleep", "open", "pause",
+ "pthread_cond_timedwait", "pthread_cond_wait", "pthread_join",
+ "pthread_testcancel", "read", "sem_wait", "sigsuspend",
+ "sigtimedwait", "sigwait", "sigwaitinfo", "sleep", "system",
+ "tcdrain", "wait", "waitpid", "write");
+
+print "1..1\n";
+
+$cpoints = join '\|', @CPOINTS;
+$regexp = "\" U \\(" . $cpoints . "\\\)\$\"";
+
+`nm -a /usr/lib/libc.a |grep $regexp >propagate_s.out`;
+if (!open (NMOUT, "<./propagate_s.out"))
+{
+ print "not ok 1\n";
+}
+else
+{
+ $propagations = 0;
+
+ while (<NMOUT>)
+ {
+ $propagations++;
+ print "$_\n";
+ }
+ if ($propagations != 0)
+ {
+ print "$propagations propagation(s)\n";
+ print "not ok 1\n";
+ }
+ else
+ {
+ print "ok 1\n";
+ }
+ close NMOUT;
+ unlink "propagate_s.out";
+}
diff --git a/lib/libpthread/test/sem_d.c b/lib/libpthread/test/sem_d.c
new file mode 100644
index 0000000..b834591
--- /dev/null
+++ b/lib/libpthread/test/sem_d.c
@@ -0,0 +1,133 @@
+/****************************************************************************
+ *
+ * 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.
+ *
+ ****************************************************************************
+ *
+ * sem test.
+ *
+ * $FreeBSD$
+ *
+ ****************************************************************************/
+
+#include <assert.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <semaphore.h>
+#include <pthread.h>
+
+#define NTHREADS 10
+
+void *
+entry(void * a_arg)
+{
+ sem_t * sem = (sem_t *) a_arg;
+
+ sem_wait(sem);
+ fprintf(stderr, "Got semaphore\n");
+
+ return NULL;
+}
+
+int
+main()
+{
+ sem_t sem_a, sem_b;
+ pthread_t threads[NTHREADS];
+ unsigned i;
+ int val;
+
+ fprintf(stderr, "Test begin\n");
+
+#ifdef _LIBC_R_
+ assert(-1 == sem_init(&sem_b, 1, 0));
+ assert(EPERM == errno);
+#endif
+
+ assert(0 == sem_init(&sem_b, 0, 0));
+ assert(0 == sem_getvalue(&sem_b, &val));
+ assert(0 == val);
+
+ assert(0 == sem_post(&sem_b));
+ assert(0 == sem_getvalue(&sem_b, &val));
+ assert(1 == val);
+
+ assert(0 == sem_wait(&sem_b));
+ assert(-1 == sem_trywait(&sem_b));
+ assert(EAGAIN == errno);
+ assert(0 == sem_post(&sem_b));
+ assert(0 == sem_trywait(&sem_b));
+ assert(0 == sem_post(&sem_b));
+ assert(0 == sem_wait(&sem_b));
+ assert(0 == sem_post(&sem_b));
+
+#ifdef _LIBC_R_
+ assert(SEM_FAILED == sem_open("/foo", O_CREAT | O_EXCL, 0644, 0));
+ assert(ENOSYS == errno);
+
+ assert(-1 == sem_close(&sem_b));
+ assert(ENOSYS == errno);
+
+ assert(-1 == sem_unlink("/foo"));
+ assert(ENOSYS == errno);
+#endif
+
+ assert(0 == sem_destroy(&sem_b));
+
+ assert(0 == sem_init(&sem_a, 0, 0));
+
+ for (i = 0; i < NTHREADS; i++) {
+ pthread_create(&threads[i], NULL, entry, (void *) &sem_a);
+ }
+
+ for (i = 0; i < NTHREADS; i++) {
+ assert(0 == sem_post(&sem_a));
+ }
+
+ for (i = 0; i < NTHREADS; i++) {
+ pthread_join(threads[i], NULL);
+ }
+
+ for (i = 0; i < NTHREADS; i++) {
+ pthread_create(&threads[i], NULL, entry, (void *) &sem_a);
+ }
+
+ for (i = 0; i < NTHREADS; i++) {
+ assert(0 == sem_post(&sem_a));
+ }
+
+ for (i = 0; i < NTHREADS; i++) {
+ pthread_join(threads[i], NULL);
+ }
+
+ assert(0 == sem_destroy(&sem_a));
+
+ fprintf(stderr, "Test end\n");
+ return 0;
+}
diff --git a/lib/libpthread/test/sem_d.exp b/lib/libpthread/test/sem_d.exp
new file mode 100644
index 0000000..b0de3da
--- /dev/null
+++ b/lib/libpthread/test/sem_d.exp
@@ -0,0 +1,22 @@
+Test begin
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Test end
diff --git a/lib/libpthread/test/sigsuspend_d.c b/lib/libpthread/test/sigsuspend_d.c
new file mode 100644
index 0000000..d405e3d
--- /dev/null
+++ b/lib/libpthread/test/sigsuspend_d.c
@@ -0,0 +1,290 @@
+/*
+ * Copyright (c) 1998 Daniel M. Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel M. Eischen.
+ * 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 DANIEL M. 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 REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <unistd.h>
+
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+
+#if defined(_LIBC_R_)
+#include <pthread_np.h>
+#endif
+
+static int sigcounts[NSIG + 1];
+static int sigfifo[NSIG + 1];
+static int fifo_depth = 0;
+static sigset_t suspender_mask;
+static pthread_t suspender_tid;
+
+
+static void *
+sigsuspender (void *arg)
+{
+ int save_count, status, i;
+ sigset_t run_mask;
+
+ /* Run with all signals blocked. */
+ sigfillset (&run_mask);
+ sigprocmask (SIG_SETMASK, &run_mask, NULL);
+
+ /* Allow these signals to wake us up during a sigsuspend. */
+ sigfillset (&suspender_mask); /* Default action */
+ sigdelset (&suspender_mask, SIGKILL); /* Cannot catch */
+ sigdelset (&suspender_mask, SIGSTOP); /* Cannot catch */
+ sigdelset (&suspender_mask, SIGINT); /* terminate */
+ sigdelset (&suspender_mask, SIGHUP); /* terminate */
+ sigdelset (&suspender_mask, SIGQUIT); /* create core image */
+ sigdelset (&suspender_mask, SIGURG); /* ignore */
+ sigdelset (&suspender_mask, SIGIO); /* ignore */
+ sigdelset (&suspender_mask, SIGUSR2); /* terminate */
+
+ while (sigcounts[SIGINT] == 0) {
+ save_count = sigcounts[SIGUSR2];
+
+ status = sigsuspend (&suspender_mask);
+ if ((status == 0) || (errno != EINTR)) {
+ fprintf (stderr, "Unable to suspend for signals, "
+ "errno %d, return value %d\n",
+ errno, status);
+ exit (1);
+ }
+ for (i = 0; i < fifo_depth; i++)
+ fprintf (stderr, "Sigsuspend woke up by signal %d\n",
+ sigfifo[i]);
+ fifo_depth = 0;
+ }
+
+ pthread_exit (arg);
+ return (NULL);
+}
+
+
+static void
+sighandler (int signo)
+{
+ sigset_t set, suspend_set;
+ pthread_t self;
+
+ if ((signo >= 0) && (signo <= NSIG))
+ sigcounts[signo]++;
+
+ /*
+ * If we are running on behalf of the suspender thread,
+ * ensure that we have the correct mask set.
+ */
+ self = pthread_self ();
+ if (self == suspender_tid) {
+ sigfifo[fifo_depth] = signo;
+ fifo_depth++;
+ fprintf (stderr,
+ " -> Suspender thread signal handler caught signal %d\n",
+ signo);
+
+ /* Get the current signal mask. */
+ sigprocmask (SIG_SETMASK, NULL, &set);
+
+ /* The handler should run with the current signal masked. */
+ suspend_set = suspender_mask;
+ sigaddset(&suspend_set, signo);
+
+ if (memcmp(&set, &suspend_set, sizeof(set)))
+ fprintf (stderr,
+ " >>> FAIL: sigsuspender signal handler running "
+ "with incorrect mask.\n");
+ }
+ else
+ fprintf (stderr,
+ " -> Main thread signal handler caught signal %d\n",
+ signo);
+}
+
+
+static void
+send_thread_signal (pthread_t tid, int signo)
+{
+ if (pthread_kill (tid, signo) != 0) {
+ fprintf (stderr, "Unable to send thread signal, errno %d.\n",
+ errno);
+ exit (1);
+ }
+}
+
+
+static void
+send_process_signal (int signo)
+{
+ if (kill (getpid (), signo) != 0) {
+ fprintf (stderr, "Unable to send process signal, errno %d.\n",
+ errno);
+ exit (1);
+ }
+}
+
+
+int main (int argc, char *argv[])
+{
+ pthread_attr_t pattr;
+ void * exit_status;
+ struct sigaction act;
+ sigset_t oldset;
+ sigset_t newset;
+
+ /* Initialize our signal counts. */
+ memset ((void *) sigcounts, 0, NSIG * sizeof (int));
+
+ /* Ignore signal SIGIO. */
+ sigemptyset (&act.sa_mask);
+ sigaddset (&act.sa_mask, SIGIO);
+ act.sa_handler = SIG_IGN;
+ act.sa_flags = 0;
+ sigaction (SIGIO, &act, NULL);
+
+ /* Install a signal handler for SIGURG. */
+ sigemptyset (&act.sa_mask);
+ sigaddset (&act.sa_mask, SIGURG);
+ act.sa_handler = sighandler;
+ act.sa_flags = SA_RESTART;
+ sigaction (SIGURG, &act, NULL);
+
+ /* Install a signal handler for SIGXCPU */
+ sigemptyset (&act.sa_mask);
+ sigaddset (&act.sa_mask, SIGXCPU);
+ sigaction (SIGXCPU, &act, NULL);
+
+ /* Get our current signal mask. */
+ sigprocmask (SIG_SETMASK, NULL, &oldset);
+
+ /* Mask out SIGUSR1 and SIGUSR2. */
+ newset = oldset;
+ sigaddset (&newset, SIGUSR1);
+ sigaddset (&newset, SIGUSR2);
+ sigprocmask (SIG_SETMASK, &newset, NULL);
+
+ /* Install a signal handler for SIGUSR1 */
+ sigemptyset (&act.sa_mask);
+ sigaddset (&act.sa_mask, SIGUSR1);
+ sigaction (SIGUSR1, &act, NULL);
+
+ /* Install a signal handler for SIGUSR2 */
+ sigemptyset (&act.sa_mask);
+ sigaddset (&act.sa_mask, SIGUSR2);
+ sigaction (SIGUSR2, &act, NULL);
+
+ /*
+ * Initialize the thread attribute.
+ */
+ if ((pthread_attr_init (&pattr) != 0) ||
+ (pthread_attr_setdetachstate (&pattr,
+ PTHREAD_CREATE_JOINABLE) != 0)) {
+ fprintf (stderr, "Unable to initialize thread attributes.\n");
+ exit (1);
+ }
+
+ /*
+ * Create the sigsuspender thread.
+ */
+ if (pthread_create (&suspender_tid, &pattr, sigsuspender, NULL) != 0) {
+ fprintf (stderr, "Unable to create thread, errno %d.\n", errno);
+ exit (1);
+ }
+#if defined(_LIBC_R_)
+ pthread_set_name_np (suspender_tid, "sigsuspender");
+#endif
+
+ /*
+ * Verify that an ignored signal doesn't cause a wakeup.
+ * We don't have a handler installed for SIGIO.
+ */
+ send_thread_signal (suspender_tid, SIGIO);
+ sleep (1);
+ send_process_signal (SIGIO);
+ sleep (1);
+ if (sigcounts[SIGIO] != 0)
+ fprintf (stderr, "FAIL: sigsuspend wakes up for ignored signal "
+ "SIGIO.\n");
+
+ /*
+ * Verify that a signal with a default action of ignore, for
+ * which we have a signal handler installed, will release a
+ * sigsuspend.
+ */
+ send_thread_signal (suspender_tid, SIGURG);
+ sleep (1);
+ send_process_signal (SIGURG);
+ sleep (1);
+ if (sigcounts[SIGURG] != 2)
+ fprintf (stderr,
+ "FAIL: sigsuspend doesn't wake up for SIGURG.\n");
+
+ /*
+ * Verify that a SIGUSR2 signal will release a sigsuspended
+ * thread.
+ */
+ send_thread_signal (suspender_tid, SIGUSR2);
+ sleep (1);
+ send_process_signal (SIGUSR2);
+ sleep (1);
+ if (sigcounts[SIGUSR2] != 2)
+ fprintf (stderr,
+ "FAIL: sigsuspend doesn't wake up for SIGUSR2.\n");
+
+ /*
+ * Verify that a signal, blocked in both the main and
+ * sigsuspender threads, does not cause the signal handler
+ * to be called.
+ */
+ send_thread_signal (suspender_tid, SIGUSR1);
+ sleep (1);
+ send_process_signal (SIGUSR1);
+ sleep (1);
+ if (sigcounts[SIGUSR1] != 0)
+ fprintf (stderr, "FAIL: signal hander called for SIGUSR1.\n");
+
+ /*
+ * Verify that we can still kill the process for a signal
+ * not being waited on by sigwait.
+ */
+ send_process_signal (SIGPIPE);
+ fprintf (stderr, "FAIL: SIGPIPE did not terminate process.\n");
+
+ /*
+ * Wait for the thread to finish.
+ */
+ pthread_join (suspender_tid, &exit_status);
+
+ return (0);
+}
diff --git a/lib/libpthread/test/sigsuspend_d.exp b/lib/libpthread/test/sigsuspend_d.exp
new file mode 100644
index 0000000..901fa50
--- /dev/null
+++ b/lib/libpthread/test/sigsuspend_d.exp
@@ -0,0 +1,8 @@
+ -> Suspender thread signal handler caught signal 16
+Sigsuspend woke up by signal 16
+ -> Suspender thread signal handler caught signal 16
+Sigsuspend woke up by signal 16
+ -> Suspender thread signal handler caught signal 31
+Sigsuspend woke up by signal 31
+ -> Suspender thread signal handler caught signal 31
+Sigsuspend woke up by signal 31
diff --git a/lib/libpthread/test/sigwait_d.c b/lib/libpthread/test/sigwait_d.c
new file mode 100644
index 0000000..f3ccd6b
--- /dev/null
+++ b/lib/libpthread/test/sigwait_d.c
@@ -0,0 +1,304 @@
+/*
+ * Copyright (c) 1998 Daniel M. Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel M. Eischen.
+ * 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 DANIEL M. 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 REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <unistd.h>
+
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+
+#if defined(_LIBC_R_)
+#include <pthread_np.h>
+#endif
+
+static int sigcounts[NSIG + 1];
+static sigset_t wait_mask;
+static pthread_mutex_t waiter_mutex;
+
+
+static void *
+sigwaiter (void *arg)
+{
+ int signo;
+ sigset_t mask;
+
+ /* Block SIGHUP */
+ sigemptyset (&mask);
+ sigaddset (&mask, SIGHUP);
+ sigprocmask (SIG_BLOCK, &mask, NULL);
+
+ while (sigcounts[SIGINT] == 0) {
+ if (sigwait (&wait_mask, &signo) != 0) {
+ fprintf (stderr,
+ "Unable to wait for signal, errno %d\n",
+ errno);
+ exit (1);
+ }
+ sigcounts[signo]++;
+ fprintf (stderr, "Sigwait caught signal %d\n", signo);
+
+ /* Allow the main thread to prevent the sigwait. */
+ pthread_mutex_lock (&waiter_mutex);
+ pthread_mutex_unlock (&waiter_mutex);
+ }
+
+ pthread_exit (arg);
+ return (NULL);
+}
+
+
+static void
+sighandler (int signo)
+{
+ fprintf (stderr, " -> Signal handler caught signal %d\n", signo);
+
+ if ((signo >= 0) && (signo <= NSIG))
+ sigcounts[signo]++;
+}
+
+static void
+send_thread_signal (pthread_t tid, int signo)
+{
+ if (pthread_kill (tid, signo) != 0) {
+ fprintf (stderr, "Unable to send thread signal, errno %d.\n",
+ errno);
+ exit (1);
+ }
+}
+
+static void
+send_process_signal (int signo)
+{
+ if (kill (getpid (), signo) != 0) {
+ fprintf (stderr, "Unable to send process signal, errno %d.\n",
+ errno);
+ exit (1);
+ }
+}
+
+
+int main (int argc, char *argv[])
+{
+ pthread_mutexattr_t mattr;
+ pthread_attr_t pattr;
+ pthread_t tid;
+ void * exit_status;
+ struct sigaction act;
+
+ /* Initialize our signal counts. */
+ memset ((void *) sigcounts, 0, NSIG * sizeof (int));
+
+ /* Setup our wait mask. */
+ sigemptyset (&wait_mask); /* Default action */
+ sigaddset (&wait_mask, SIGHUP); /* terminate */
+ sigaddset (&wait_mask, SIGINT); /* terminate */
+ sigaddset (&wait_mask, SIGQUIT); /* create core image */
+ sigaddset (&wait_mask, SIGURG); /* ignore */
+ sigaddset (&wait_mask, SIGIO); /* ignore */
+ sigaddset (&wait_mask, SIGUSR1); /* terminate */
+
+ /* Ignore signals SIGHUP and SIGIO. */
+ sigemptyset (&act.sa_mask);
+ sigaddset (&act.sa_mask, SIGHUP);
+ sigaddset (&act.sa_mask, SIGIO);
+ act.sa_handler = SIG_IGN;
+ act.sa_flags = 0;
+ sigaction (SIGHUP, &act, NULL);
+ sigaction (SIGIO, &act, NULL);
+
+ /* Install a signal handler for SIGURG */
+ sigemptyset (&act.sa_mask);
+ sigaddset (&act.sa_mask, SIGURG);
+ act.sa_handler = sighandler;
+ act.sa_flags = SA_RESTART;
+ sigaction (SIGURG, &act, NULL);
+
+ /* Install a signal handler for SIGXCPU */
+ sigemptyset (&act.sa_mask);
+ sigaddset (&act.sa_mask, SIGXCPU);
+ sigaction (SIGXCPU, &act, NULL);
+
+ /*
+ * Initialize the thread attribute.
+ */
+ if ((pthread_attr_init (&pattr) != 0) ||
+ (pthread_attr_setdetachstate (&pattr,
+ PTHREAD_CREATE_JOINABLE) != 0)) {
+ fprintf (stderr, "Unable to initialize thread attributes.\n");
+ exit (1);
+ }
+
+ /*
+ * Initialize and create a mutex.
+ */
+ if ((pthread_mutexattr_init (&mattr) != 0) ||
+ (pthread_mutex_init (&waiter_mutex, &mattr) != 0)) {
+ fprintf (stderr, "Unable to create waiter mutex.\n");
+ exit (1);
+ }
+
+ /*
+ * Create the sigwaiter thread.
+ */
+ if (pthread_create (&tid, &pattr, sigwaiter, NULL) != 0) {
+ fprintf (stderr, "Unable to create thread.\n");
+ exit (1);
+ }
+#if defined(_LIBC_R_)
+ pthread_set_name_np (tid, "sigwaiter");
+#endif
+
+ /*
+ * Verify that an ignored signal doesn't cause a wakeup.
+ * We don't have a handler installed for SIGIO.
+ */
+ send_thread_signal (tid, SIGIO);
+ sleep (1);
+ send_process_signal (SIGIO);
+ sleep (1);
+ if (sigcounts[SIGIO] != 0)
+ fprintf (stderr,
+ "FAIL: sigwait wakes up for ignored signal SIGIO.\n");
+
+ /*
+ * Verify that a signal with a default action of ignore, for
+ * which we have a signal handler installed, will release a sigwait.
+ */
+ send_thread_signal (tid, SIGURG);
+ sleep (1);
+ send_process_signal (SIGURG);
+ sleep (1);
+ if (sigcounts[SIGURG] != 2)
+ fprintf (stderr, "FAIL: sigwait doesn't wake up for SIGURG.\n");
+
+ /*
+ * Verify that a signal with a default action that terminates
+ * the process will release a sigwait.
+ */
+ send_thread_signal (tid, SIGUSR1);
+ sleep (1);
+ send_process_signal (SIGUSR1);
+ sleep (1);
+ if (sigcounts[SIGUSR1] != 2)
+ fprintf (stderr,
+ "FAIL: sigwait doesn't wake up for SIGUSR1.\n");
+
+ /*
+ * Verify that if we install a signal handler for a previously
+ * ignored signal, an occurrence of this signal will release
+ * the (already waiting) sigwait.
+ */
+
+ /* Install a signal handler for SIGHUP. */
+ sigemptyset (&act.sa_mask);
+ sigaddset (&act.sa_mask, SIGHUP);
+ act.sa_handler = sighandler;
+ act.sa_flags = SA_RESTART;
+ sigaction (SIGHUP, &act, NULL);
+
+ /* Sending SIGHUP should release the sigwait. */
+ send_process_signal (SIGHUP);
+ sleep (1);
+ send_thread_signal (tid, SIGHUP);
+ sleep (1);
+ if (sigcounts[SIGHUP] != 2)
+ fprintf (stderr, "FAIL: sigwait doesn't wake up for SIGHUP.\n");
+
+ /*
+ * Verify that a pending signal in the waiters mask will
+ * cause sigwait to return the pending signal. We do this
+ * by taking the waiters mutex and signaling the waiter to
+ * release him from the sigwait. The waiter will block
+ * on taking the mutex, and we can then send the waiter a
+ * signal which should be added to his pending signals.
+ * The next time the waiter does a sigwait, he should
+ * return with the pending signal.
+ */
+ sigcounts[SIGHUP] = 0;
+ pthread_mutex_lock (&waiter_mutex);
+ /* Release the waiter from sigwait. */
+ send_process_signal (SIGHUP);
+ sleep (1);
+ if (sigcounts[SIGHUP] != 1)
+ fprintf (stderr, "FAIL: sigwait doesn't wake up for SIGHUP.\n");
+ /*
+ * Add SIGHUP to the process pending signals. Since there is
+ * a signal handler installed for SIGHUP and this signal is
+ * blocked from the waiter thread and unblocked in the main
+ * thread, the signal handler should be called once for SIGHUP.
+ */
+ send_process_signal (SIGHUP);
+ /* Release the waiter thread and allow him to run. */
+ pthread_mutex_unlock (&waiter_mutex);
+ sleep (1);
+ if (sigcounts[SIGHUP] != 2)
+ fprintf (stderr,
+ "FAIL: sigwait doesn't return for pending SIGHUP.\n");
+
+ /*
+ * Repeat the above test using pthread_kill and SIGUSR1.
+ */
+ sigcounts[SIGUSR1] = 0;
+ pthread_mutex_lock (&waiter_mutex);
+ /* Release the waiter from sigwait. */
+ send_thread_signal (tid, SIGUSR1);
+ sleep (1);
+ if (sigcounts[SIGUSR1] != 1)
+ fprintf (stderr,
+ "FAIL: sigwait doesn't wake up for SIGUSR1.\n");
+ /* Add SIGUSR1 to the waiters pending signals. */
+ send_thread_signal (tid, SIGUSR1);
+ /* Release the waiter thread and allow him to run. */
+ pthread_mutex_unlock (&waiter_mutex);
+ sleep (1);
+ if (sigcounts[SIGUSR1] != 2)
+ fprintf (stderr,
+ "FAIL: sigwait doesn't return for pending SIGUSR1.\n");
+
+ /*
+ * Verify that we can still kill the process for a signal
+ * not being waited on by sigwait.
+ */
+ send_process_signal (SIGPIPE);
+ fprintf (stderr, "FAIL: SIGPIPE did not terminate process.\n");
+
+ /*
+ * Wait for the thread to finish.
+ */
+ pthread_join (tid, &exit_status);
+
+ return (0);
+}
diff --git a/lib/libpthread/test/sigwait_d.exp b/lib/libpthread/test/sigwait_d.exp
new file mode 100644
index 0000000..2e9b2c4
--- /dev/null
+++ b/lib/libpthread/test/sigwait_d.exp
@@ -0,0 +1,10 @@
+Sigwait caught signal 16
+Sigwait caught signal 16
+Sigwait caught signal 30
+Sigwait caught signal 30
+Sigwait caught signal 1
+Sigwait caught signal 1
+Sigwait caught signal 1
+ -> Signal handler caught signal 1
+Sigwait caught signal 30
+Sigwait caught signal 30
diff --git a/lib/libpthread/test/verify b/lib/libpthread/test/verify
new file mode 100755
index 0000000..2863e5c
--- /dev/null
+++ b/lib/libpthread/test/verify
@@ -0,0 +1,474 @@
+#!/usr/bin/perl -w
+#-*-mode:perl-*-
+#############################################################################
+#
+# Copyright (C) 1999-2001 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.
+#
+#############################################################################
+#
+# Test harness.
+#
+# $FreeBSD$
+#
+#############################################################################
+
+# Shut off buffering.
+select(STDOUT);
+$| = 1;
+
+#
+# Parse command-line arguments.
+#
+use Getopt::Long;
+Getopt::Long::config("bundling"); # Allow -hv rather than forcing -h -v.
+
+# Set option defaults for optional arguments.
+$opt_help = 0;
+$opt_verbose = 0;
+$opt_quiet = 0;
+$opt_srcdir = ".";
+$opt_objdir = ".";
+$opt_ustats = 0;
+$opt_zero = 0;
+
+$opt_retval =
+&GetOptions("h|help" => \$opt_help,
+ "v|verbose" => \$opt_verbose,
+ "q|quiet" => \$opt_quiet,
+ "s|srcdir=s" => \$opt_srcdir,
+ "o|objdir=s" => \$opt_objdir,
+ "u|ustats" => \$opt_ustats,
+ "z|zero" => \$opt_zero
+ );
+
+if ($opt_help)
+{
+ &usage();
+ exit(0);
+}
+
+if ($opt_retval == 0)
+{
+ &usage();
+ exit 1;
+}
+
+if ($opt_verbose && $opt_quiet)
+{
+ print STDERR "-v and -q are incompatible\n";
+ &usage();
+ exit 1;
+}
+
+if ($#ARGV + 1 == 0)
+{
+ print STDERR "No tests specified\n";
+ &usage();
+ exit 1;
+}
+
+if ($opt_verbose)
+{
+ print STDERR "Option values: h:$opt_help, v:$opt_verbose, "
+ . "s:\"$opt_srcdir\", o:\"$opt_objdir\" "
+ . "q:$opt_quiet, u:$opt_ustats, z:$opt_zero\n";
+ printf STDERR "Tests (%d total): @ARGV\n", $#ARGV + 1;
+}
+
+#
+# Create and print header.
+#
+@TSTATS =
+(
+ "--------------------------------------------------------------------------\n",
+ "Test c_user c_system c_total chng\n",
+ " passed/FAILED h_user h_system h_total %% chng\n"
+ );
+
+if (!$opt_quiet)
+{
+ foreach $line (@TSTATS)
+ {
+ printf STDOUT "$line";
+ }
+}
+
+#
+# Run sequence test(s).
+#
+$total_utime = 0.0; # Total user time.
+$total_stime = 0.0; # Total system time.
+$total_hutime = 0.0; # Total historical user time.
+$total_hstime = 0.0; # Total historical system time.
+$total_ntime = 0.0; # Total time for tests that have historical data.
+
+foreach $test (@ARGV)
+{
+ # Strip out any whitespace in $test.
+ $test =~ s/^\s*(.*)\s*$/$1/;
+
+ $okay = 1;
+
+ if (-e "$opt_srcdir/$test.exp")
+ {
+ # Diff mode.
+
+ ($okay, $utime, $stime) = &run_test($test);
+
+ if (-e "$opt_objdir/$test.out")
+ {
+ `diff $opt_srcdir/$test.exp $opt_objdir/$test.out > $opt_objdir/$test.diff 2>&1`;
+ if ($?)
+ {
+ # diff returns non-zero if there is a difference.
+ $okay = 0;
+ }
+ }
+ else
+ {
+ $okay = 0;
+ if ($opt_verbose)
+ {
+ print STDERR
+ "Nonexistent output file \"$opt_objdir/$test.out\"\n";
+ }
+ }
+
+ ($hutime, $hstime) = &print_stats($test, $okay, 0, 0, $utime, $stime);
+ }
+ else
+ {
+ # Sequence mode.
+
+ ($okay, $utime, $stime) = &run_test($test);
+
+ if (open (STEST_OUT, "<$opt_objdir/$test.out"))
+ {
+ $num_subtests = 0;
+ $num_failed_subtests = 0;
+
+ while (defined($line = <STEST_OUT>))
+ {
+ if ($line =~ /1\.\.(\d+)/)
+ {
+ $num_subtests = $1;
+ last;
+ }
+ }
+ if ($num_subtests == 0)
+ {
+ $okay = 0;
+ if ($opt_verbose)
+ {
+ print STDERR "Malformed or missing 1..n line\n";
+ }
+ }
+ else
+ {
+ for ($subtest = 1; $subtest <= $num_subtests; $subtest++)
+ {
+ while (defined($line = <STEST_OUT>))
+ {
+ if ($line =~ /^not\s+ok\s+(\d+)?/)
+ {
+ $not = 1;
+ $test_num = $1;
+ last;
+ }
+ elsif ($line =~ /^ok\s+(\d+)?/)
+ {
+ $not = 0;
+ $test_num = $1;
+ last;
+ }
+ }
+ if (defined($line))
+ {
+ if (defined($test_num) && ($test_num != $subtest))
+ {
+ # There was no output printed for one or more tests.
+ for (; $subtest < $test_num; $subtest++)
+ {
+ $num_failed_subtests++;
+ }
+ }
+ if ($not)
+ {
+ $num_failed_subtests++;
+ }
+ }
+ else
+ {
+ for (; $subtest <= $num_subtests; $subtest++)
+ {
+ $num_failed_subtests++;
+ }
+ }
+ }
+
+ if (0 < $num_failed_subtests)
+ {
+ $okay = 0;
+ }
+ }
+ }
+ else
+ {
+ if (!$opt_quiet)
+ {
+ print STDERR "Cannot open output file \"$opt_objdir/$test.out\"\n";
+ }
+ exit 1;
+ }
+
+ ($hutime, $hstime) = &print_stats($test, $okay,
+ $num_failed_subtests, $num_subtests,
+ $utime, $stime);
+ }
+
+ $total_hutime += $hutime;
+ $total_hstime += $hstime;
+
+ if ($okay)
+ {
+ $total_utime += $utime;
+ $total_stime += $stime;
+ }
+ else
+ {
+ @FAILED_TESTS = (@FAILED_TESTS, $test);
+ }
+
+ # If there were historical data, add the run time to the total time to
+ # compare against the historical run time.
+ if (0 < ($hutime + $hstime))
+ {
+ $total_ntime += $utime + $stime;
+ }
+}
+
+# Print summary stats.
+$tt_str = sprintf ("%d / %d passed (%5.2f%%%%)",
+ ($#ARGV + 1) - ($#FAILED_TESTS + 1),
+ $#ARGV + 1,
+ (($#ARGV + 1) - ($#FAILED_TESTS + 1))
+ / ($#ARGV + 1) * 100);
+
+$t_str = sprintf ("Totals %7.2f %7.2f %7.2f"
+ . " %7.2f\n"
+ . " %s %7.2f %7.2f %7.2f %7.2f%%%%\n",
+ $total_utime, $total_stime, $total_utime + $total_stime,
+ ($total_ntime - ($total_hutime + $total_hstime)),
+ $tt_str . ' ' x (40 - length($tt_str)),
+ $total_hutime, $total_hstime, $total_hutime + $total_hstime,
+ ($total_hutime + $total_hstime == 0.0) ? 0.0 :
+ (($total_ntime
+ - ($total_hutime + $total_hstime))
+ / ($total_hutime + $total_hstime) * 100));
+
+@TSTATS = ("--------------------------------------------------------------------------\n",
+ $t_str,
+ "--------------------------------------------------------------------------\n"
+ );
+if (!$opt_quiet)
+{
+ foreach $line (@TSTATS)
+ {
+ printf STDOUT "$line";
+ }
+}
+
+if ($#FAILED_TESTS >= 0)
+{
+ # One or more tests failed, so return an error.
+ exit 1;
+}
+# End of main execution.
+
+sub run_test
+{
+ my ($test) = @_;
+ my ($okay) = 1;
+ my ($tutime, $tstime);
+ my ($utime, $stime, $cutime, $cstime);
+ my (@TSTATS, @TPATH);
+ my ($t_str);
+ my ($srcdir, $objdir);
+
+ # Get the path component of $test, if any.
+ @TPATH = split(/\//, $test);
+ pop(@TPATH);
+ $srcdir = join('/', ($opt_srcdir, @TPATH));
+ $objdir = join('/', ($opt_objdir, @TPATH));
+
+ @TSTATS = ("--------------------------------------------------------------------------\n");
+
+ $t_str = sprintf ("%s%s", $test, ' ' x (40 - length($test)));
+ @TSTATS = (@TSTATS, $t_str);
+ @STATS = (@STATS, @TSTATS);
+ if (!$opt_quiet)
+ {
+ foreach $line (@TSTATS)
+ {
+ printf STDOUT "$line";
+ }
+ }
+
+ ($utime, $stime, $cutime, $cstime) = times;
+ `$opt_objdir/$test $srcdir $objdir > $opt_objdir/$test.out 2>&1`;
+ ($utime, $stime, $tutime, $tstime) = times;
+
+ # Subtract the before time from the after time.
+ $tutime -= $cutime;
+ $tstime -= $cstime;
+
+ if ($opt_zero)
+ {
+ if ($?)
+ {
+ $okay = 0;
+ if ($opt_verbose)
+ {
+ print STDERR
+ "\"$opt_objdir/$test > $opt_objdir/$test.out 2>&1\" returned $?\n";
+ }
+ }
+ }
+
+ return ($okay, $tutime, $tstime);
+}
+
+sub print_stats
+{
+ my ($test, $okay, $failed_subtests, $subtests, $utime, $stime) = @_;
+ my ($hutime, $hstime);
+# my (TEST_PERF);
+ my (@TSTATS);
+ my ($t_str, $pass_str);
+
+ $pass_str = $okay ? "passed" : "*** FAILED ***";
+ if ((0 != $subtests) && (!$okay))
+ {
+ $pass_str = $pass_str . " ($failed_subtests/$subtests failed)";
+ }
+ $pass_str = $pass_str . ' ' x (39 - length($pass_str));
+
+ if (-r "$test.perf")
+ {
+ if (!open (TEST_PERF, "<$opt_objdir/$test.perf"))
+ {
+ print STDERR "Unable to open \"$opt_objdir/$test.perf\"\n";
+ exit 1;
+ }
+ $_ = <TEST_PERF>;
+
+ ($hutime, $hstime) = split;
+ close TEST_PERF;
+
+ $t_str = sprintf (" %7.2f %7.2f %7.2f %7.2f\n"
+ . " %s %7.2f %7.2f %7.2f %7.2f%%%%\n",
+ $utime, $stime, $utime + $stime,
+ ($utime + $stime) - ($hutime + $hstime),
+ $pass_str,
+ $hutime, $hstime, $hutime + $hstime,
+ (($hutime + $hstime) == 0.0) ? 0.0 :
+ ((($utime + $stime) - ($hutime + $hstime))
+ / ($hutime + $hstime) * 100));
+ }
+ else
+ {
+ $hutime = 0.0;
+ $hstime = 0.0;
+
+ $t_str = sprintf (" %7.2f %7.2f %7.2f \n"
+ . " %s\n",
+ $utime, $stime, $utime + $stime,
+ $pass_str);
+ }
+ @TSTATS = ($t_str);
+ if (!$opt_quiet)
+ {
+ foreach $line (@TSTATS)
+ {
+ printf STDOUT "$line";
+ }
+ }
+
+ if ($okay && $opt_ustats)
+ {
+ if (!open (TEST_PERF, ">$opt_objdir/$test.perf"))
+ {
+ if (!$opt_quiet)
+ {
+ print STDERR "Unable to update \"$opt_objdir/$test.perf\"\n";
+ }
+ }
+ else
+ {
+ print TEST_PERF "$utime $stime\n";
+ close TEST_PERF;
+ }
+ }
+
+ return ($hutime, $hstime);
+}
+
+sub usage
+{
+ print <<EOF;
+$0 usage:
+ $0 [<options>] <test>+
+
+ Option | Description
+ --------------+-------------------------------------------------------------
+ -h --help | Print usage and exit.
+ -v --verbose | Verbose (incompatible with quiet).
+ -q --quiet | Quiet (incompatible with verbose).
+ -s --srcdir | Path to source tree (default is ".").
+ -o --objdir | Path to object tree (default is ".").
+ -u --ustats | Update historical statistics (stored in "<test>.perf".
+ -z --zero | Consider non-zero exit code to be an error.
+ --------------+-------------------------------------------------------------
+
+ If <test>.exp exists, <test>'s output is diff'ed with <test>.exp. Any
+ difference is considered failure.
+
+ If <test>.exp does not exist, output to stdout of the following form is
+ expected:
+
+ 1..<n>
+ {not }ok[ 1]
+ {not }ok[ 2]
+ ...
+ {not }ok[ n]
+
+ 1 <= <n> < 2^31
+
+ Lines which do not match the patterns shown above are ignored.
+EOF
+}
diff --git a/lib/libpthread/thread/Makefile.inc b/lib/libpthread/thread/Makefile.inc
new file mode 100644
index 0000000..561be93
--- /dev/null
+++ b/lib/libpthread/thread/Makefile.inc
@@ -0,0 +1,117 @@
+# $FreeBSD$
+
+# thr sources
+.PATH: ${.CURDIR}/thread
+
+SRCS+= \
+ thr_accept.c \
+ thr_aio_suspend.c \
+ thr_atfork.c \
+ thr_attr_destroy.c \
+ thr_attr_init.c \
+ thr_attr_get_np.c \
+ thr_attr_getdetachstate.c \
+ thr_attr_getguardsize.c \
+ thr_attr_getinheritsched.c \
+ thr_attr_getschedparam.c \
+ thr_attr_getschedpolicy.c \
+ thr_attr_getscope.c \
+ thr_attr_getstack.c \
+ thr_attr_getstackaddr.c \
+ thr_attr_getstacksize.c \
+ thr_attr_setcreatesuspend_np.c \
+ thr_attr_setdetachstate.c \
+ thr_attr_setguardsize.c \
+ thr_attr_setinheritsched.c \
+ thr_attr_setschedparam.c \
+ thr_attr_setschedpolicy.c \
+ thr_attr_setscope.c \
+ thr_attr_setstack.c \
+ thr_attr_setstackaddr.c \
+ thr_attr_setstacksize.c \
+ thr_autoinit.c \
+ thr_barrier.c \
+ thr_barrierattr.c \
+ thr_cancel.c \
+ thr_clean.c \
+ thr_close.c \
+ thr_concurrency.c \
+ thr_cond.c \
+ thr_condattr_destroy.c \
+ thr_condattr_init.c \
+ thr_condattr_pshared.c \
+ thr_connect.c \
+ thr_creat.c \
+ thr_create.c \
+ thr_detach.c \
+ thr_equal.c \
+ thr_execve.c \
+ thr_exit.c \
+ thr_fcntl.c \
+ thr_find_thread.c \
+ thr_fork.c \
+ thr_fsync.c \
+ thr_getprio.c \
+ thr_getschedparam.c \
+ thr_info.c \
+ thr_init.c \
+ thr_join.c \
+ thr_kern.c \
+ thr_kill.c \
+ thr_main_np.c \
+ thr_mattr_init.c \
+ thr_mattr_kind_np.c \
+ thr_mattr_pshared.c \
+ thr_msync.c \
+ thr_multi_np.c \
+ thr_mutex.c \
+ thr_mutex_prioceiling.c \
+ thr_mutex_protocol.c \
+ thr_mutexattr_destroy.c \
+ thr_nanosleep.c \
+ thr_once.c \
+ thr_open.c \
+ thr_pause.c \
+ thr_poll.c \
+ thr_printf.c \
+ thr_priority_queue.c \
+ thr_pselect.c \
+ thr_pspinlock.c \
+ thr_raise.c \
+ thr_read.c \
+ thr_readv.c \
+ thr_resume_np.c \
+ thr_rtld.c \
+ thr_rwlock.c \
+ thr_rwlockattr.c \
+ thr_select.c \
+ thr_self.c \
+ thr_sem.c \
+ thr_seterrno.c \
+ thr_setprio.c \
+ thr_setschedparam.c \
+ thr_sig.c \
+ thr_sigaction.c \
+ thr_sigaltstack.c \
+ thr_sigmask.c \
+ thr_sigpending.c \
+ thr_sigprocmask.c \
+ thr_sigsuspend.c \
+ thr_sigwait.c \
+ thr_single_np.c \
+ thr_sleep.c \
+ thr_spec.c \
+ thr_spinlock.c \
+ thr_stack.c \
+ thr_suspend_np.c \
+ thr_switch_np.c \
+ thr_system.c \
+ thr_symbols.c \
+ thr_tcdrain.c \
+ thr_vfork.c \
+ thr_wait.c \
+ thr_wait4.c \
+ thr_waitpid.c \
+ thr_write.c \
+ thr_writev.c \
+ thr_yield.c
diff --git a/lib/libpthread/thread/thr_accept.c b/lib/libpthread/thread/thr_accept.c
new file mode 100644
index 0000000..fc60fb4
--- /dev/null
+++ b/lib/libpthread/thread/thr_accept.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2003 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 THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 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 <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__accept);
+LT10_COMPAT_DEFAULT(accept);
+
+__weak_reference(__accept, accept);
+
+int
+__accept(int s, struct sockaddr *addr, socklen_t *addrlen)
+{
+ struct pthread *curthread;
+ int ret;
+
+ curthread = _get_curthread();
+ _thr_cancel_enter(curthread);
+ ret = __sys_accept(s, addr, addrlen);
+ _thr_cancel_leave(curthread, ret == -1);
+
+ return (ret);
+}
diff --git a/lib/libpthread/thread/thr_aio_suspend.c b/lib/libpthread/thread/thr_aio_suspend.c
new file mode 100644
index 0000000..43a2414
--- /dev/null
+++ b/lib/libpthread/thread/thr_aio_suspend.c
@@ -0,0 +1,54 @@
+/*
+ * 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$
+ */
+
+#include <aio.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_aio_suspend);
+LT10_COMPAT_DEFAULT(aio_suspend);
+
+__weak_reference(_aio_suspend, aio_suspend);
+
+int
+_aio_suspend(const struct aiocb * const iocbs[], int niocb, const struct
+ timespec *timeout)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ _thr_cancel_enter(curthread);
+ ret = __sys_aio_suspend(iocbs, niocb, timeout);
+ _thr_cancel_leave(curthread, 1);
+
+ return (ret);
+}
+
diff --git a/lib/libpthread/thread/thr_atfork.c b/lib/libpthread/thread/thr_atfork.c
new file mode 100644
index 0000000..a741329
--- /dev/null
+++ b/lib/libpthread/thread/thr_atfork.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2003 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 THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <sys/queue.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_atfork);
+LT10_COMPAT_DEFAULT(pthread_atfork);
+
+__weak_reference(_pthread_atfork, pthread_atfork);
+
+int
+_pthread_atfork(void (*prepare)(void), void (*parent)(void),
+ void (*child)(void))
+{
+ struct pthread_atfork *af;
+
+ if (_thr_initial == NULL)
+ _libpthread_init(NULL);
+
+ if ((af = malloc(sizeof(struct pthread_atfork))) == NULL)
+ return (ENOMEM);
+
+ af->prepare = prepare;
+ af->parent = parent;
+ af->child = child;
+ _pthread_mutex_lock(&_thr_atfork_mutex);
+ TAILQ_INSERT_TAIL(&_thr_atfork_list, af, qe);
+ _pthread_mutex_unlock(&_thr_atfork_mutex);
+ return (0);
+}
+
diff --git a/lib/libpthread/thread/thr_attr_destroy.c b/lib/libpthread/thread/thr_attr_destroy.c
new file mode 100644
index 0000000..4442584
--- /dev/null
+++ b/lib/libpthread/thread/thr_attr_destroy.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 1996 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_destroy);
+LT10_COMPAT_DEFAULT(pthread_attr_destroy);
+
+__weak_reference(_pthread_attr_destroy, pthread_attr_destroy);
+
+int
+_pthread_attr_destroy(pthread_attr_t *attr)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL)
+ /* Invalid argument: */
+ ret = EINVAL;
+ else {
+ /* Free the memory allocated to the attribute object: */
+ free(*attr);
+
+ /*
+ * Leave the attribute pointer NULL now that the memory
+ * has been freed:
+ */
+ *attr = NULL;
+ ret = 0;
+ }
+ return(ret);
+}
diff --git a/lib/libpthread/thread/thr_attr_get_np.c b/lib/libpthread/thread/thr_attr_get_np.c
new file mode 100644
index 0000000..a63088f
--- /dev/null
+++ b/lib/libpthread/thread/thr_attr_get_np.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2002,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$
+ */
+#include <errno.h>
+#include <string.h>
+#include <pthread.h>
+#include <pthread_np.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_get_np);
+LT10_COMPAT_DEFAULT(pthread_attr_get_np);
+
+__weak_reference(_pthread_attr_get_np, pthread_attr_get_np);
+
+int
+_pthread_attr_get_np(pthread_t pid, pthread_attr_t *dst)
+{
+ struct pthread *curthread;
+ struct pthread_attr attr;
+ int ret;
+
+ if (pid == NULL || dst == NULL || *dst == NULL)
+ return (EINVAL);
+
+ curthread = _get_curthread();
+ if ((ret = _thr_ref_add(curthread, pid, /*include dead*/0)) != 0)
+ return (ret);
+ attr = pid->attr;
+ _thr_ref_delete(curthread, pid);
+ memcpy(*dst, &attr, sizeof(struct pthread_attr));
+
+ return (0);
+}
diff --git a/lib/libpthread/thread/thr_attr_getdetachstate.c b/lib/libpthread/thread/thr_attr_getdetachstate.c
new file mode 100644
index 0000000..e2ff6bd
--- /dev/null
+++ b/lib/libpthread/thread/thr_attr_getdetachstate.c
@@ -0,0 +1,62 @@
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_getdetachstate);
+LT10_COMPAT_DEFAULT(pthread_attr_getdetachstate);
+
+__weak_reference(_pthread_attr_getdetachstate, pthread_attr_getdetachstate);
+
+int
+_pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL || detachstate == NULL)
+ ret = EINVAL;
+ else {
+ /* Check if the detached flag is set: */
+ if ((*attr)->flags & PTHREAD_DETACHED)
+ /* Return detached: */
+ *detachstate = PTHREAD_CREATE_DETACHED;
+ else
+ /* Return joinable: */
+ *detachstate = PTHREAD_CREATE_JOINABLE;
+ ret = 0;
+ }
+ return(ret);
+}
diff --git a/lib/libpthread/thread/thr_attr_getguardsize.c b/lib/libpthread/thread/thr_attr_getguardsize.c
new file mode 100644
index 0000000..351015c
--- /dev/null
+++ b/lib/libpthread/thread/thr_attr_getguardsize.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2001 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
+ * unmodified other than the allowable 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 <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_getguardsize);
+LT10_COMPAT_DEFAULT(pthread_attr_getguardsize);
+
+__weak_reference(_pthread_attr_getguardsize, pthread_attr_getguardsize);
+
+int
+_pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL || guardsize == NULL)
+ ret = EINVAL;
+ else {
+ /* Return the guard size: */
+ *guardsize = (*attr)->guardsize_attr;
+ ret = 0;
+ }
+ return(ret);
+}
diff --git a/lib/libpthread/thread/thr_attr_getinheritsched.c b/lib/libpthread/thread/thr_attr_getinheritsched.c
new file mode 100644
index 0000000..eab19e3
--- /dev/null
+++ b/lib/libpthread/thread/thr_attr_getinheritsched.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_getinheritsched);
+LT10_COMPAT_DEFAULT(pthread_attr_getinheritsched);
+
+__weak_reference(_pthread_attr_getinheritsched, pthread_attr_getinheritsched);
+
+int
+_pthread_attr_getinheritsched(const pthread_attr_t *attr, int *sched_inherit)
+{
+ int ret = 0;
+
+ if ((attr == NULL) || (*attr == NULL))
+ ret = EINVAL;
+ else
+ *sched_inherit = (*attr)->sched_inherit;
+
+ return(ret);
+}
diff --git a/lib/libpthread/thread/thr_attr_getschedparam.c b/lib/libpthread/thread/thr_attr_getschedparam.c
new file mode 100644
index 0000000..ca2eed3
--- /dev/null
+++ b/lib/libpthread/thread/thr_attr_getschedparam.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_getschedparam);
+LT10_COMPAT_DEFAULT(pthread_attr_getschedparam);
+
+__weak_reference(_pthread_attr_getschedparam, pthread_attr_getschedparam);
+
+int
+_pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param)
+{
+ int ret = 0;
+
+ if ((attr == NULL) || (*attr == NULL) || (param == NULL))
+ ret = EINVAL;
+ else
+ param->sched_priority = (*attr)->prio;
+
+ return(ret);
+}
diff --git a/lib/libpthread/thread/thr_attr_getschedpolicy.c b/lib/libpthread/thread/thr_attr_getschedpolicy.c
new file mode 100644
index 0000000..dc952bd
--- /dev/null
+++ b/lib/libpthread/thread/thr_attr_getschedpolicy.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_getschedpolicy);
+LT10_COMPAT_DEFAULT(pthread_attr_getschedpolicy);
+
+__weak_reference(_pthread_attr_getschedpolicy, pthread_attr_getschedpolicy);
+
+int
+_pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy)
+{
+ int ret = 0;
+
+ if ((attr == NULL) || (*attr == NULL) || (policy == NULL))
+ ret = EINVAL;
+ else
+ *policy = (*attr)->sched_policy;
+
+ return(ret);
+}
diff --git a/lib/libpthread/thread/thr_attr_getscope.c b/lib/libpthread/thread/thr_attr_getscope.c
new file mode 100644
index 0000000..ceb198f
--- /dev/null
+++ b/lib/libpthread/thread/thr_attr_getscope.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_getscope);
+LT10_COMPAT_DEFAULT(pthread_attr_getscope);
+
+__weak_reference(_pthread_attr_getscope, pthread_attr_getscope);
+
+int
+_pthread_attr_getscope(const pthread_attr_t *attr, int *contentionscope)
+{
+ int ret = 0;
+
+ if ((attr == NULL) || (*attr == NULL) || (contentionscope == NULL))
+ /* Return an invalid argument: */
+ ret = EINVAL;
+
+ else
+ *contentionscope = (*attr)->flags & PTHREAD_SCOPE_SYSTEM ?
+ PTHREAD_SCOPE_SYSTEM : PTHREAD_SCOPE_PROCESS;
+
+ return(ret);
+}
diff --git a/lib/libpthread/thread/thr_attr_getstack.c b/lib/libpthread/thread/thr_attr_getstack.c
new file mode 100644
index 0000000..79a92cb
--- /dev/null
+++ b/lib/libpthread/thread/thr_attr_getstack.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2003 Craig Rodrigues <rodrigc@attbi.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Craig Rodrigues.
+ * 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 CRAIG RODRIGUES AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_getstack);
+LT10_COMPAT_DEFAULT(pthread_attr_getstack);
+
+__weak_reference(_pthread_attr_getstack, pthread_attr_getstack);
+
+int
+_pthread_attr_getstack(const pthread_attr_t * __restrict attr,
+ void ** __restrict stackaddr,
+ size_t * __restrict stacksize)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL || stackaddr == NULL
+ || stacksize == NULL )
+ ret = EINVAL;
+ else {
+ /* Return the stack address and size */
+ *stackaddr = (*attr)->stackaddr_attr;
+ *stacksize = (*attr)->stacksize_attr;
+ ret = 0;
+ }
+ return(ret);
+}
+
diff --git a/lib/libpthread/thread/thr_attr_getstackaddr.c b/lib/libpthread/thread/thr_attr_getstackaddr.c
new file mode 100644
index 0000000..0d5c87c
--- /dev/null
+++ b/lib/libpthread/thread/thr_attr_getstackaddr.c
@@ -0,0 +1,57 @@
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_getstackaddr);
+LT10_COMPAT_DEFAULT(pthread_attr_getstackaddr);
+
+__weak_reference(_pthread_attr_getstackaddr, pthread_attr_getstackaddr);
+
+int
+_pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL || stackaddr == NULL)
+ ret = EINVAL;
+ else {
+ /* Return the stack address: */
+ *stackaddr = (*attr)->stackaddr_attr;
+ ret = 0;
+ }
+ return(ret);
+}
diff --git a/lib/libpthread/thread/thr_attr_getstacksize.c b/lib/libpthread/thread/thr_attr_getstacksize.c
new file mode 100644
index 0000000..2636e97
--- /dev/null
+++ b/lib/libpthread/thread/thr_attr_getstacksize.c
@@ -0,0 +1,57 @@
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_getstacksize);
+LT10_COMPAT_DEFAULT(pthread_attr_getstacksize);
+
+__weak_reference(_pthread_attr_getstacksize, pthread_attr_getstacksize);
+
+int
+_pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL || stacksize == NULL)
+ ret = EINVAL;
+ else {
+ /* Return the stack size: */
+ *stacksize = (*attr)->stacksize_attr;
+ ret = 0;
+ }
+ return(ret);
+}
diff --git a/lib/libpthread/thread/thr_attr_init.c b/lib/libpthread/thread/thr_attr_init.c
new file mode 100644
index 0000000..77f3f24
--- /dev/null
+++ b/lib/libpthread/thread/thr_attr_init.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 1996 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_init);
+LT10_COMPAT_DEFAULT(pthread_attr_init);
+
+__weak_reference(_pthread_attr_init, pthread_attr_init);
+
+int
+_pthread_attr_init(pthread_attr_t *attr)
+{
+ int ret;
+ pthread_attr_t pattr;
+
+ /* Allocate memory for the attribute object: */
+ if ((pattr = (pthread_attr_t) malloc(sizeof(struct pthread_attr))) == NULL)
+ /* Insufficient memory: */
+ ret = ENOMEM;
+ else {
+ /* Initialise the attribute object with the defaults: */
+ memcpy(pattr, &_pthread_attr_default,
+ sizeof(struct pthread_attr));
+ pattr->guardsize_attr = _thr_guard_default;
+ pattr->stacksize_attr = _thr_stack_default;
+
+ /* Return a pointer to the attribute object: */
+ *attr = pattr;
+ ret = 0;
+ }
+ return(ret);
+}
diff --git a/lib/libpthread/thread/thr_attr_setcreatesuspend_np.c b/lib/libpthread/thread/thr_attr_setcreatesuspend_np.c
new file mode 100644
index 0000000..aa5f878
--- /dev/null
+++ b/lib/libpthread/thread/thr_attr_setcreatesuspend_np.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_setcreatesuspend_np);
+LT10_COMPAT_DEFAULT(pthread_attr_setcreatesuspend_np);
+
+__weak_reference(_pthread_attr_setcreatesuspend_np, pthread_attr_setcreatesuspend_np);
+
+int
+_pthread_attr_setcreatesuspend_np(pthread_attr_t *attr)
+{
+ int ret;
+
+ if (attr == NULL || *attr == NULL) {
+ ret = EINVAL;
+ } else {
+ (*attr)->suspend = THR_CREATE_SUSPENDED;
+ ret = 0;
+ }
+ return(ret);
+}
diff --git a/lib/libpthread/thread/thr_attr_setdetachstate.c b/lib/libpthread/thread/thr_attr_setdetachstate.c
new file mode 100644
index 0000000..b17680b
--- /dev/null
+++ b/lib/libpthread/thread/thr_attr_setdetachstate.c
@@ -0,0 +1,64 @@
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_setdetachstate);
+LT10_COMPAT_DEFAULT(pthread_attr_setdetachstate);
+
+__weak_reference(_pthread_attr_setdetachstate, pthread_attr_setdetachstate);
+
+int
+_pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL ||
+ (detachstate != PTHREAD_CREATE_DETACHED &&
+ detachstate != PTHREAD_CREATE_JOINABLE))
+ ret = EINVAL;
+ else {
+ /* Check if detached state: */
+ if (detachstate == PTHREAD_CREATE_DETACHED)
+ /* Set the detached flag: */
+ (*attr)->flags |= PTHREAD_DETACHED;
+ else
+ /* Reset the detached flag: */
+ (*attr)->flags &= ~PTHREAD_DETACHED;
+ ret = 0;
+ }
+ return(ret);
+}
diff --git a/lib/libpthread/thread/thr_attr_setguardsize.c b/lib/libpthread/thread/thr_attr_setguardsize.c
new file mode 100644
index 0000000..dedee8b
--- /dev/null
+++ b/lib/libpthread/thread/thr_attr_setguardsize.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2001 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
+ * unmodified other than the allowable 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 <sys/param.h>
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_setguardsize);
+LT10_COMPAT_DEFAULT(pthread_attr_setguardsize);
+
+__weak_reference(_pthread_attr_setguardsize, pthread_attr_setguardsize);
+
+int
+_pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize)
+{
+ int ret;
+
+ /* Check for invalid arguments. */
+ if (attr == NULL || *attr == NULL)
+ ret = EINVAL;
+ else {
+ /* Save the stack size. */
+ (*attr)->guardsize_attr = guardsize;
+ ret = 0;
+ }
+ return(ret);
+}
diff --git a/lib/libpthread/thread/thr_attr_setinheritsched.c b/lib/libpthread/thread/thr_attr_setinheritsched.c
new file mode 100644
index 0000000..5182b7d
--- /dev/null
+++ b/lib/libpthread/thread/thr_attr_setinheritsched.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_setinheritsched);
+LT10_COMPAT_DEFAULT(pthread_attr_setinheritsched);
+
+__weak_reference(_pthread_attr_setinheritsched, pthread_attr_setinheritsched);
+
+int
+_pthread_attr_setinheritsched(pthread_attr_t *attr, int sched_inherit)
+{
+ int ret = 0;
+
+ if ((attr == NULL) || (*attr == NULL))
+ ret = EINVAL;
+ else if (sched_inherit != PTHREAD_INHERIT_SCHED &&
+ sched_inherit != PTHREAD_EXPLICIT_SCHED)
+ ret = ENOTSUP;
+ else
+ (*attr)->sched_inherit = sched_inherit;
+
+ return(ret);
+}
diff --git a/lib/libpthread/thread/thr_attr_setschedparam.c b/lib/libpthread/thread/thr_attr_setschedparam.c
new file mode 100644
index 0000000..61d741d
--- /dev/null
+++ b/lib/libpthread/thread/thr_attr_setschedparam.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_setschedparam);
+LT10_COMPAT_DEFAULT(pthread_attr_setschedparam);
+
+__weak_reference(_pthread_attr_setschedparam, pthread_attr_setschedparam);
+
+int
+_pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param)
+{
+ int ret = 0;
+
+ if ((attr == NULL) || (*attr == NULL))
+ ret = EINVAL;
+ else if (param == NULL) {
+ ret = ENOTSUP;
+ } else if ((param->sched_priority < THR_MIN_PRIORITY) ||
+ (param->sched_priority > THR_MAX_PRIORITY)) {
+ /* Return an unsupported value error. */
+ ret = ENOTSUP;
+ } else
+ (*attr)->prio = param->sched_priority;
+
+ return(ret);
+}
diff --git a/lib/libpthread/thread/thr_attr_setschedpolicy.c b/lib/libpthread/thread/thr_attr_setschedpolicy.c
new file mode 100644
index 0000000..fb24cb1
--- /dev/null
+++ b/lib/libpthread/thread/thr_attr_setschedpolicy.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_setschedpolicy);
+LT10_COMPAT_DEFAULT(pthread_attr_setschedpolicy);
+
+__weak_reference(_pthread_attr_setschedpolicy, pthread_attr_setschedpolicy);
+
+int
+_pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
+{
+ int ret = 0;
+
+ if ((attr == NULL) || (*attr == NULL))
+ ret = EINVAL;
+ else if ((policy < SCHED_FIFO) || (policy > SCHED_RR)) {
+ ret = ENOTSUP;
+ } else
+ (*attr)->sched_policy = policy;
+
+ return(ret);
+}
diff --git a/lib/libpthread/thread/thr_attr_setscope.c b/lib/libpthread/thread/thr_attr_setscope.c
new file mode 100644
index 0000000..3cc7f16
--- /dev/null
+++ b/lib/libpthread/thread/thr_attr_setscope.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_setscope);
+LT10_COMPAT_DEFAULT(pthread_attr_setscope);
+
+__weak_reference(_pthread_attr_setscope, pthread_attr_setscope);
+
+int
+_pthread_attr_setscope(pthread_attr_t *attr, int contentionscope)
+{
+ int ret = 0;
+
+ if ((attr == NULL) || (*attr == NULL)) {
+ /* Return an invalid argument: */
+ ret = EINVAL;
+ } else if ((contentionscope != PTHREAD_SCOPE_PROCESS) &&
+ (contentionscope != PTHREAD_SCOPE_SYSTEM)) {
+ ret = EINVAL;
+ } else if (contentionscope == PTHREAD_SCOPE_SYSTEM) {
+ (*attr)->flags |= contentionscope;
+ } else {
+ (*attr)->flags &= ~PTHREAD_SCOPE_SYSTEM;
+ }
+ return (ret);
+}
diff --git a/lib/libpthread/thread/thr_attr_setstack.c b/lib/libpthread/thread/thr_attr_setstack.c
new file mode 100644
index 0000000..bdccfd8
--- /dev/null
+++ b/lib/libpthread/thread/thr_attr_setstack.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2003 Craig Rodrigues <rodrigc@attbi.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Craig Rodrigues.
+ * 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 CRAIG RODRIGUES AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_setstack);
+LT10_COMPAT_DEFAULT(pthread_attr_setstack);
+
+__weak_reference(_pthread_attr_setstack, pthread_attr_setstack);
+
+int
+_pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr,
+ size_t stacksize)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL || stackaddr == NULL
+ || stacksize < PTHREAD_STACK_MIN )
+ ret = EINVAL;
+ else {
+ /* Save the stack address and stack size */
+ (*attr)->stackaddr_attr = stackaddr;
+ (*attr)->stacksize_attr = stacksize;
+ ret = 0;
+ }
+ return(ret);
+}
+
diff --git a/lib/libpthread/thread/thr_attr_setstackaddr.c b/lib/libpthread/thread/thr_attr_setstackaddr.c
new file mode 100644
index 0000000..5f0a903
--- /dev/null
+++ b/lib/libpthread/thread/thr_attr_setstackaddr.c
@@ -0,0 +1,57 @@
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_setstackaddr);
+LT10_COMPAT_DEFAULT(pthread_attr_setstackaddr);
+
+__weak_reference(_pthread_attr_setstackaddr, pthread_attr_setstackaddr);
+
+int
+_pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL || stackaddr == NULL)
+ ret = EINVAL;
+ else {
+ /* Save the stack address: */
+ (*attr)->stackaddr_attr = stackaddr;
+ ret = 0;
+ }
+ return(ret);
+}
diff --git a/lib/libpthread/thread/thr_attr_setstacksize.c b/lib/libpthread/thread/thr_attr_setstacksize.c
new file mode 100644
index 0000000..6fa9760
--- /dev/null
+++ b/lib/libpthread/thread/thr_attr_setstacksize.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 1996 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_setstacksize);
+LT10_COMPAT_DEFAULT(pthread_attr_setstacksize);
+
+__weak_reference(_pthread_attr_setstacksize, pthread_attr_setstacksize);
+
+int
+_pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL || stacksize < PTHREAD_STACK_MIN)
+ ret = EINVAL;
+ else {
+ /* Save the stack size: */
+ (*attr)->stacksize_attr = stacksize;
+ ret = 0;
+ }
+ return(ret);
+}
diff --git a/lib/libpthread/thread/thr_autoinit.c b/lib/libpthread/thread/thr_autoinit.c
new file mode 100644
index 0000000..95b2a85
--- /dev/null
+++ b/lib/libpthread/thread/thr_autoinit.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2002 Alfred Perlstein <alfred@freebsd.org>.
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 module uses GCC extentions to initialize the
+ * threads package at program start-up time.
+ */
+
+#include <pthread.h>
+#include "thr_private.h"
+
+void _thread_init_hack(void) __attribute__ ((constructor));
+
+void
+_thread_init_hack(void)
+{
+
+ _libpthread_init(NULL);
+}
+
+/*
+ * For the shared version of the threads library, the above is sufficient.
+ * But for the archive version of the library, we need a little bit more.
+ * Namely, we must arrange for this particular module to be pulled in from
+ * the archive library at link time. To accomplish that, we define and
+ * initialize a variable, "_thread_autoinit_dummy_decl". This variable is
+ * referenced (as an extern) from libc/stdlib/exit.c. This will always
+ * create a need for this module, ensuring that it is present in the
+ * executable.
+ */
+extern int _thread_autoinit_dummy_decl;
+int _thread_autoinit_dummy_decl = 0;
diff --git a/lib/libpthread/thread/thr_barrier.c b/lib/libpthread/thread/thr_barrier.c
new file mode 100644
index 0000000..c8be343
--- /dev/null
+++ b/lib/libpthread/thread/thr_barrier.c
@@ -0,0 +1,129 @@
+/*-
+ * Copyright (c) 2003 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include "namespace.h"
+#include <pthread.h>
+#include "un-namespace.h"
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_barrier_init);
+LT10_COMPAT_DEFAULT(pthread_barrier_init);
+LT10_COMPAT_PRIVATE(_pthread_barrier_wait);
+LT10_COMPAT_DEFAULT(pthread_barrier_wait);
+LT10_COMPAT_PRIVATE(_pthread_barrier_destroy);
+LT10_COMPAT_DEFAULT(pthread_barrier_destroy);
+
+__weak_reference(_pthread_barrier_init, pthread_barrier_init);
+__weak_reference(_pthread_barrier_wait, pthread_barrier_wait);
+__weak_reference(_pthread_barrier_destroy, pthread_barrier_destroy);
+
+int
+_pthread_barrier_destroy(pthread_barrier_t *barrier)
+{
+ pthread_barrier_t bar;
+ int ret, ret2;
+
+ if (barrier == NULL || *barrier == NULL)
+ return (EINVAL);
+
+ bar = *barrier;
+ if (bar->b_waiters > 0)
+ return (EBUSY);
+ *barrier = NULL;
+ ret = _pthread_mutex_destroy(&bar->b_lock);
+ ret2 = _pthread_cond_destroy(&bar->b_cond);
+ free(bar);
+ return (ret ? ret : ret2);
+}
+
+int
+_pthread_barrier_init(pthread_barrier_t *barrier,
+ const pthread_barrierattr_t *attr, unsigned count)
+{
+ pthread_barrier_t bar;
+ int ret;
+
+ if (barrier == NULL || count <= 0)
+ return (EINVAL);
+
+ bar = malloc(sizeof(struct pthread_barrier));
+ if (bar == NULL)
+ return (ENOMEM);
+
+ if ((ret = _pthread_mutex_init(&bar->b_lock, NULL)) != 0) {
+ free(bar);
+ return (ret);
+ }
+
+ if ((ret = _pthread_cond_init(&bar->b_cond, NULL)) != 0) {
+ _pthread_mutex_destroy(&bar->b_lock);
+ free(bar);
+ return (ret);
+ }
+
+ bar->b_waiters = 0;
+ bar->b_count = count;
+ bar->b_generation = 0;
+ *barrier = bar;
+
+ return (0);
+}
+
+int
+_pthread_barrier_wait(pthread_barrier_t *barrier)
+{
+ int ret, gen;
+ pthread_barrier_t bar;
+
+ if (barrier == NULL || *barrier == NULL)
+ return (EINVAL);
+
+ bar = *barrier;
+ if ((ret = _pthread_mutex_lock(&bar->b_lock)) != 0)
+ return (ret);
+
+ if (++bar->b_waiters == bar->b_count) {
+ /* Current thread is lastest thread */
+ bar->b_generation++;
+ bar->b_waiters = 0;
+ ret = _pthread_cond_broadcast(&bar->b_cond);
+ if (ret == 0)
+ ret = PTHREAD_BARRIER_SERIAL_THREAD;
+ } else {
+ gen = bar->b_generation;
+ do {
+ ret = _pthread_cond_wait(
+ &bar->b_cond, &bar->b_lock);
+ /* test generation to avoid bogus wakeup */
+ } while (ret == 0 && gen == bar->b_generation);
+ }
+ _pthread_mutex_unlock(&bar->b_lock);
+ return (ret);
+}
diff --git a/lib/libpthread/thread/thr_barrierattr.c b/lib/libpthread/thread/thr_barrierattr.c
new file mode 100644
index 0000000..3384aee
--- /dev/null
+++ b/lib/libpthread/thread/thr_barrierattr.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2003 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 <errno.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_barrierattr_destroy);
+LT10_COMPAT_DEFAULT(pthread_barrierattr_destroy);
+LT10_COMPAT_PRIVATE(_pthread_barrierattr_init);
+LT10_COMPAT_DEFAULT(pthread_barrierattr_init);
+LT10_COMPAT_PRIVATE(_pthread_barrierattr_setpshared);
+LT10_COMPAT_DEFAULT(pthread_barrierattr_setpshared);
+LT10_COMPAT_PRIVATE(_pthread_barrierattr_getpshared);
+LT10_COMPAT_DEFAULT(pthread_barrierattr_getpshared);
+
+__weak_reference(_pthread_barrierattr_destroy, pthread_barrierattr_destroy);
+__weak_reference(_pthread_barrierattr_init, pthread_barrierattr_init);
+__weak_reference(_pthread_barrierattr_setpshared,
+ pthread_barrierattr_setpshared);
+__weak_reference(_pthread_barrierattr_getpshared,
+ pthread_barrierattr_getpshared);
+
+int
+_pthread_barrierattr_destroy(pthread_barrierattr_t *attr)
+{
+
+ if (attr == NULL || *attr == NULL)
+ return (EINVAL);
+
+ free(*attr);
+ return (0);
+}
+
+int
+_pthread_barrierattr_getpshared(const pthread_barrierattr_t *attr,
+ int *pshared)
+{
+
+ if (attr == NULL || *attr == NULL)
+ return (EINVAL);
+
+ *pshared = (*attr)->pshared;
+ return (0);
+}
+
+int
+_pthread_barrierattr_init(pthread_barrierattr_t *attr)
+{
+
+ if (attr == NULL)
+ return (EINVAL);
+
+ if ((*attr = malloc(sizeof(struct pthread_barrierattr))) == NULL)
+ return (ENOMEM);
+
+ (*attr)->pshared = PTHREAD_PROCESS_PRIVATE;
+ return (0);
+}
+
+int
+_pthread_barrierattr_setpshared(pthread_barrierattr_t *attr, int pshared)
+{
+
+ if (attr == NULL || *attr == NULL)
+ return (EINVAL);
+
+ /* Only PTHREAD_PROCESS_PRIVATE is supported. */
+ if (pshared != PTHREAD_PROCESS_PRIVATE)
+ return (EINVAL);
+
+ (*attr)->pshared = pshared;
+ return (0);
+}
diff --git a/lib/libpthread/thread/thr_cancel.c b/lib/libpthread/thread/thr_cancel.c
new file mode 100644
index 0000000..bbf6fdf
--- /dev/null
+++ b/lib/libpthread/thread/thr_cancel.c
@@ -0,0 +1,311 @@
+/*
+ * David Leonard <d@openbsd.org>, 1999. Public domain.
+ * $FreeBSD$
+ */
+#include <sys/errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_cancel);
+LT10_COMPAT_DEFAULT(pthread_cancel);
+LT10_COMPAT_PRIVATE(_pthread_setcancelstate);
+LT10_COMPAT_DEFAULT(pthread_setcancelstate);
+LT10_COMPAT_PRIVATE(_pthread_setcanceltype);
+LT10_COMPAT_DEFAULT(pthread_setcanceltype);
+LT10_COMPAT_PRIVATE(_pthread_testcancel);
+LT10_COMPAT_DEFAULT(pthread_testcancel);
+
+__weak_reference(_pthread_cancel, pthread_cancel);
+__weak_reference(_pthread_setcancelstate, pthread_setcancelstate);
+__weak_reference(_pthread_setcanceltype, pthread_setcanceltype);
+__weak_reference(_pthread_testcancel, pthread_testcancel);
+
+static inline int
+checkcancel(struct pthread *curthread)
+{
+ if ((curthread->cancelflags & THR_CANCELLING) != 0) {
+ /*
+ * It is possible for this thread to be swapped out
+ * while performing cancellation; do not allow it
+ * to be cancelled again.
+ */
+ if ((curthread->flags & THR_FLAGS_EXITING) != 0) {
+ /*
+ * This may happen once, but after this, it
+ * shouldn't happen again.
+ */
+ curthread->cancelflags &= ~THR_CANCELLING;
+ return (0);
+ }
+ if ((curthread->cancelflags & PTHREAD_CANCEL_DISABLE) == 0) {
+ curthread->cancelflags &= ~THR_CANCELLING;
+ return (1);
+ }
+ }
+ return (0);
+}
+
+static inline void
+testcancel(struct pthread *curthread)
+{
+ if (checkcancel(curthread) != 0) {
+ /* Unlock before exiting: */
+ THR_THREAD_UNLOCK(curthread, curthread);
+
+ _thr_exit_cleanup();
+ pthread_exit(PTHREAD_CANCELED);
+ PANIC("cancel");
+ }
+}
+
+int
+_pthread_cancel(pthread_t pthread)
+{
+ struct pthread *curthread = _get_curthread();
+ struct pthread *joinee = NULL;
+ struct kse_mailbox *kmbx = NULL;
+ int ret;
+
+ if ((ret = _thr_ref_add(curthread, pthread, /*include dead*/0)) == 0) {
+ /*
+ * Take the thread's lock while we change the cancel flags.
+ */
+ THR_THREAD_LOCK(curthread, pthread);
+ THR_SCHED_LOCK(curthread, pthread);
+ if (pthread->flags & THR_FLAGS_EXITING) {
+ THR_SCHED_UNLOCK(curthread, pthread);
+ THR_THREAD_UNLOCK(curthread, pthread);
+ _thr_ref_delete(curthread, pthread);
+ return (ESRCH);
+ }
+ if (((pthread->cancelflags & PTHREAD_CANCEL_DISABLE) != 0) ||
+ (((pthread->cancelflags & THR_AT_CANCEL_POINT) == 0) &&
+ ((pthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) == 0)))
+ /* Just mark it for cancellation: */
+ pthread->cancelflags |= THR_CANCELLING;
+ else {
+ /*
+ * Check if we need to kick it back into the
+ * run queue:
+ */
+ switch (pthread->state) {
+ case PS_RUNNING:
+ /* No need to resume: */
+ pthread->cancelflags |= THR_CANCELLING;
+ break;
+
+ case PS_LOCKWAIT:
+ /*
+ * These can't be removed from the queue.
+ * Just mark it as cancelling and tell it
+ * to yield once it leaves the critical
+ * region.
+ */
+ pthread->cancelflags |= THR_CANCELLING;
+ pthread->critical_yield = 1;
+ break;
+
+ case PS_SLEEP_WAIT:
+ case PS_SIGSUSPEND:
+ case PS_SIGWAIT:
+ /* Interrupt and resume: */
+ pthread->interrupted = 1;
+ pthread->cancelflags |= THR_CANCELLING;
+ kmbx = _thr_setrunnable_unlocked(pthread);
+ break;
+
+ case PS_JOIN:
+ /* Disconnect the thread from the joinee: */
+ joinee = pthread->join_status.thread;
+ pthread->join_status.thread = NULL;
+ pthread->cancelflags |= THR_CANCELLING;
+ kmbx = _thr_setrunnable_unlocked(pthread);
+ if ((joinee != NULL) &&
+ (pthread->kseg == joinee->kseg)) {
+ /* Remove the joiner from the joinee. */
+ joinee->joiner = NULL;
+ joinee = NULL;
+ }
+ break;
+
+ case PS_SUSPENDED:
+ case PS_MUTEX_WAIT:
+ case PS_COND_WAIT:
+ /*
+ * Threads in these states may be in queues.
+ * In order to preserve queue integrity, the
+ * cancelled thread must remove itself from the
+ * queue. Mark the thread as interrupted and
+ * needing cancellation, and set the state to
+ * running. When the thread resumes, it will
+ * remove itself from the queue and call the
+ * cancellation completion routine.
+ */
+ pthread->interrupted = 1;
+ pthread->cancelflags |= THR_CANCEL_NEEDED;
+ kmbx = _thr_setrunnable_unlocked(pthread);
+ pthread->continuation =
+ _thr_finish_cancellation;
+ break;
+
+ case PS_DEAD:
+ case PS_DEADLOCK:
+ case PS_STATE_MAX:
+ /* Ignore - only here to silence -Wall: */
+ break;
+ }
+ if ((pthread->cancelflags & THR_AT_CANCEL_POINT) &&
+ (pthread->blocked != 0 ||
+ pthread->attr.flags & PTHREAD_SCOPE_SYSTEM))
+ kse_thr_interrupt(&pthread->tcb->tcb_tmbx,
+ KSE_INTR_INTERRUPT, 0);
+ }
+
+ /*
+ * Release the thread's lock and remove the
+ * reference:
+ */
+ THR_SCHED_UNLOCK(curthread, pthread);
+ THR_THREAD_UNLOCK(curthread, pthread);
+ _thr_ref_delete(curthread, pthread);
+ if (kmbx != NULL)
+ kse_wakeup(kmbx);
+
+ if ((joinee != NULL) &&
+ (_thr_ref_add(curthread, joinee, /* include dead */1) == 0)) {
+ /* Remove the joiner from the joinee. */
+ THR_SCHED_LOCK(curthread, joinee);
+ joinee->joiner = NULL;
+ THR_SCHED_UNLOCK(curthread, joinee);
+ _thr_ref_delete(curthread, joinee);
+ }
+ }
+ return (ret);
+}
+
+int
+_pthread_setcancelstate(int state, int *oldstate)
+{
+ struct pthread *curthread = _get_curthread();
+ int ostate;
+ int ret;
+ int need_exit = 0;
+
+ /* Take the thread's lock while fiddling with the state: */
+ THR_THREAD_LOCK(curthread, curthread);
+
+ ostate = curthread->cancelflags & PTHREAD_CANCEL_DISABLE;
+
+ switch (state) {
+ case PTHREAD_CANCEL_ENABLE:
+ curthread->cancelflags &= ~PTHREAD_CANCEL_DISABLE;
+ if ((curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0)
+ need_exit = checkcancel(curthread);
+ ret = 0;
+ break;
+ case PTHREAD_CANCEL_DISABLE:
+ curthread->cancelflags |= PTHREAD_CANCEL_DISABLE;
+ ret = 0;
+ break;
+ default:
+ ret = EINVAL;
+ }
+
+ THR_THREAD_UNLOCK(curthread, curthread);
+ if (need_exit != 0) {
+ _thr_exit_cleanup();
+ pthread_exit(PTHREAD_CANCELED);
+ PANIC("cancel");
+ }
+ if (ret == 0 && oldstate != NULL)
+ *oldstate = ostate;
+
+ return (ret);
+}
+
+int
+_pthread_setcanceltype(int type, int *oldtype)
+{
+ struct pthread *curthread = _get_curthread();
+ int otype;
+ int ret;
+ int need_exit = 0;
+
+ /* Take the thread's lock while fiddling with the state: */
+ THR_THREAD_LOCK(curthread, curthread);
+
+ otype = curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS;
+ switch (type) {
+ case PTHREAD_CANCEL_ASYNCHRONOUS:
+ curthread->cancelflags |= PTHREAD_CANCEL_ASYNCHRONOUS;
+ need_exit = checkcancel(curthread);
+ ret = 0;
+ break;
+ case PTHREAD_CANCEL_DEFERRED:
+ curthread->cancelflags &= ~PTHREAD_CANCEL_ASYNCHRONOUS;
+ ret = 0;
+ break;
+ default:
+ ret = EINVAL;
+ }
+
+ THR_THREAD_UNLOCK(curthread, curthread);
+ if (need_exit != 0) {
+ _thr_exit_cleanup();
+ pthread_exit(PTHREAD_CANCELED);
+ PANIC("cancel");
+ }
+ if (ret == 0 && oldtype != NULL)
+ *oldtype = otype;
+
+ return (ret);
+}
+
+void
+_pthread_testcancel(void)
+{
+ struct pthread *curthread = _get_curthread();
+
+ THR_THREAD_LOCK(curthread, curthread);
+ testcancel(curthread);
+ THR_THREAD_UNLOCK(curthread, curthread);
+}
+
+void
+_thr_cancel_enter(struct pthread *thread)
+{
+ /* Look for a cancellation before we block: */
+ THR_THREAD_LOCK(thread, thread);
+ testcancel(thread);
+ thread->cancelflags |= THR_AT_CANCEL_POINT;
+ THR_THREAD_UNLOCK(thread, thread);
+}
+
+void
+_thr_cancel_leave(struct pthread *thread, int check)
+{
+ THR_THREAD_LOCK(thread, thread);
+ thread->cancelflags &= ~THR_AT_CANCEL_POINT;
+ /* Look for a cancellation after we unblock: */
+ if (check)
+ testcancel(thread);
+ THR_THREAD_UNLOCK(thread, thread);
+}
+
+void
+_thr_finish_cancellation(void *arg)
+{
+ struct pthread *curthread = _get_curthread();
+
+ curthread->continuation = NULL;
+ curthread->interrupted = 0;
+
+ THR_THREAD_LOCK(curthread, curthread);
+ if ((curthread->cancelflags & THR_CANCEL_NEEDED) != 0) {
+ curthread->cancelflags &= ~THR_CANCEL_NEEDED;
+ THR_THREAD_UNLOCK(curthread, curthread);
+ _thr_exit_cleanup();
+ pthread_exit(PTHREAD_CANCELED);
+ }
+ THR_THREAD_UNLOCK(curthread, curthread);
+}
diff --git a/lib/libpthread/thread/thr_clean.c b/lib/libpthread/thread/thr_clean.c
new file mode 100644
index 0000000..4db5c93
--- /dev/null
+++ b/lib/libpthread/thread/thr_clean.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <signal.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_cleanup_push);
+LT10_COMPAT_DEFAULT(pthread_cleanup_push);
+LT10_COMPAT_PRIVATE(_pthread_cleanup_pop);
+LT10_COMPAT_DEFAULT(pthread_cleanup_pop);
+
+__weak_reference(_pthread_cleanup_push, pthread_cleanup_push);
+__weak_reference(_pthread_cleanup_pop, pthread_cleanup_pop);
+
+void
+_pthread_cleanup_push(void (*routine) (void *), void *routine_arg)
+{
+ struct pthread *curthread = _get_curthread();
+ struct pthread_cleanup *new;
+
+ if ((new = (struct pthread_cleanup *)
+ malloc(sizeof(struct pthread_cleanup))) != NULL) {
+ new->routine = routine;
+ new->routine_arg = routine_arg;
+ new->onstack = 0;
+ new->next = curthread->cleanup;
+
+ curthread->cleanup = new;
+ }
+}
+
+void
+_pthread_cleanup_pop(int execute)
+{
+ struct pthread *curthread = _get_curthread();
+ struct pthread_cleanup *old;
+
+ if ((old = curthread->cleanup) != NULL) {
+ curthread->cleanup = old->next;
+ if (execute) {
+ old->routine(old->routine_arg);
+ }
+ if (old->onstack == 0)
+ free(old);
+ }
+}
diff --git a/lib/libpthread/thread/thr_close.c b/lib/libpthread/thread/thr_close.c
new file mode 100644
index 0000000..7b4fe72
--- /dev/null
+++ b/lib/libpthread/thread/thr_close.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__close);
+LT10_COMPAT_DEFAULT(close);
+
+__weak_reference(__close, close);
+
+int
+__close(int fd)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ _thr_cancel_enter(curthread);
+ ret = __sys_close(fd);
+ _thr_cancel_leave(curthread, 1);
+
+ return (ret);
+}
diff --git a/lib/libpthread/thread/thr_concurrency.c b/lib/libpthread/thread/thr_concurrency.c
new file mode 100644
index 0000000..74e0e11
--- /dev/null
+++ b/lib/libpthread/thread/thr_concurrency.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2003 Daniel M. Eischen <deischen@freebsd.org>
+ * Copyright (c) 2003 Sergey Osokin <osa@freebsd.org.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. 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_getconcurrency);
+LT10_COMPAT_DEFAULT(pthread_getconcurrency);
+LT10_COMPAT_PRIVATE(_pthread_setconcurrency);
+LT10_COMPAT_DEFAULT(pthread_setconcurrency);
+
+/*#define DEBUG_CONCURRENCY */
+#ifdef DEBUG_CONCURRENCY
+#define DBG_MSG stdout_debug
+#else
+#define DBG_MSG(x...)
+#endif
+
+static int level = 0;
+
+__weak_reference(_pthread_getconcurrency, pthread_getconcurrency);
+__weak_reference(_pthread_setconcurrency, pthread_setconcurrency);
+
+int
+_pthread_getconcurrency(void)
+{
+ return (level);
+}
+
+int
+_pthread_setconcurrency(int new_level)
+{
+ int ret;
+
+ if (new_level < 0)
+ ret = EINVAL;
+ else if (new_level == level)
+ ret = 0;
+ else if (new_level == 0) {
+ level = 0;
+ ret = 0;
+ } else if ((_kse_isthreaded() == 0) && (_kse_setthreaded(1) != 0)) {
+ DBG_MSG("Can't enable threading.\n");
+ ret = EAGAIN;
+ } else {
+ ret = _thr_setconcurrency(new_level);
+ if (ret == 0)
+ level = new_level;
+ }
+ return (ret);
+}
+
+int
+_thr_setconcurrency(int new_level)
+{
+ struct pthread *curthread;
+ struct kse *newkse, *kse;
+ kse_critical_t crit;
+ int kse_count;
+ int i;
+ int ret;
+
+ /*
+ * Turn on threaded mode, if failed, it is unnecessary to
+ * do further work.
+ */
+ if (_kse_isthreaded() == 0 && _kse_setthreaded(1))
+ return (EAGAIN);
+
+ ret = 0;
+ curthread = _get_curthread();
+ /* Race condition, but so what. */
+ kse_count = _kse_initial->k_kseg->kg_ksecount;
+ if (new_level > kse_count) {
+ for (i = kse_count; i < new_level; i++) {
+ newkse = _kse_alloc(curthread, 0);
+ if (newkse == NULL) {
+ DBG_MSG("Can't alloc new KSE.\n");
+ ret = EAGAIN;
+ break;
+ }
+ newkse->k_kseg = _kse_initial->k_kseg;
+ newkse->k_schedq = _kse_initial->k_schedq;
+ newkse->k_curthread = NULL;
+ crit = _kse_critical_enter();
+ KSE_SCHED_LOCK(curthread->kse, newkse->k_kseg);
+ TAILQ_INSERT_TAIL(&newkse->k_kseg->kg_kseq,
+ newkse, k_kgqe);
+ newkse->k_kseg->kg_ksecount++;
+ newkse->k_flags |= KF_STARTED;
+ KSE_SCHED_UNLOCK(curthread->kse, newkse->k_kseg);
+ if (kse_create(&newkse->k_kcb->kcb_kmbx, 0) != 0) {
+ KSE_SCHED_LOCK(curthread->kse, newkse->k_kseg);
+ TAILQ_REMOVE(&newkse->k_kseg->kg_kseq,
+ newkse, k_kgqe);
+ newkse->k_kseg->kg_ksecount--;
+ KSE_SCHED_UNLOCK(curthread->kse,
+ newkse->k_kseg);
+ _kse_critical_leave(crit);
+ _kse_free(curthread, newkse);
+ DBG_MSG("kse_create syscall failed.\n");
+ ret = EAGAIN;
+ break;
+ } else {
+ _kse_critical_leave(crit);
+ }
+ }
+ } else if (new_level < kse_count) {
+ kse_count = 0;
+ crit = _kse_critical_enter();
+ KSE_SCHED_LOCK(curthread->kse, _kse_initial->k_kseg);
+ /* Count the number of active KSEs */
+ TAILQ_FOREACH(kse, &_kse_initial->k_kseg->kg_kseq, k_kgqe) {
+ if ((kse->k_flags & KF_TERMINATED) == 0)
+ kse_count++;
+ }
+ /* Reduce the number of active KSEs appropriately. */
+ kse = TAILQ_FIRST(&_kse_initial->k_kseg->kg_kseq);
+ while ((kse != NULL) && (kse_count > new_level)) {
+ if ((kse != _kse_initial) &&
+ ((kse->k_flags & KF_TERMINATED) == 0)) {
+ kse->k_flags |= KF_TERMINATED;
+ kse_count--;
+ /* Wakup the KSE in case it is idle. */
+ kse_wakeup(&kse->k_kcb->kcb_kmbx);
+ }
+ kse = TAILQ_NEXT(kse, k_kgqe);
+ }
+ KSE_SCHED_UNLOCK(curthread->kse, _kse_initial->k_kseg);
+ _kse_critical_leave(crit);
+ }
+ return (ret);
+}
+
+int
+_thr_setmaxconcurrency(void)
+{
+ int vcpu;
+ size_t len;
+ int ret;
+
+ len = sizeof(vcpu);
+ ret = sysctlbyname("kern.threads.virtual_cpu", &vcpu, &len, NULL, 0);
+ if (ret == 0 && vcpu > 0)
+ ret = _thr_setconcurrency(vcpu);
+ return (ret);
+}
+
diff --git a/lib/libpthread/thread/thr_cond.c b/lib/libpthread/thread/thr_cond.c
new file mode 100644
index 0000000..e39ae63
--- /dev/null
+++ b/lib/libpthread/thread/thr_cond.c
@@ -0,0 +1,847 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <errno.h>
+#include <string.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__pthread_cond_wait);
+LT10_COMPAT_PRIVATE(_pthread_cond_wait);
+LT10_COMPAT_DEFAULT(pthread_cond_wait);
+LT10_COMPAT_PRIVATE(__pthread_cond_timedwait);
+LT10_COMPAT_PRIVATE(_pthread_cond_timedwait);
+LT10_COMPAT_DEFAULT(pthread_cond_timedwait);
+LT10_COMPAT_PRIVATE(_pthread_cond_init);
+LT10_COMPAT_DEFAULT(pthread_cond_init);
+LT10_COMPAT_PRIVATE(_pthread_cond_destroy);
+LT10_COMPAT_DEFAULT(pthread_cond_destroy);
+LT10_COMPAT_PRIVATE(_pthread_cond_signal);
+LT10_COMPAT_DEFAULT(pthread_cond_signal);
+LT10_COMPAT_PRIVATE(_pthread_cond_broadcast);
+LT10_COMPAT_DEFAULT(pthread_cond_broadcast);
+
+#define THR_IN_CONDQ(thr) (((thr)->sflags & THR_FLAGS_IN_SYNCQ) != 0)
+#define THR_CONDQ_SET(thr) (thr)->sflags |= THR_FLAGS_IN_SYNCQ
+#define THR_CONDQ_CLEAR(thr) (thr)->sflags &= ~THR_FLAGS_IN_SYNCQ
+
+/*
+ * Prototypes
+ */
+static inline struct pthread *cond_queue_deq(pthread_cond_t);
+static inline void cond_queue_remove(pthread_cond_t, pthread_t);
+static inline void cond_queue_enq(pthread_cond_t, pthread_t);
+static void cond_wait_backout(void *);
+static inline void check_continuation(struct pthread *,
+ struct pthread_cond *, pthread_mutex_t *);
+
+/*
+ * Double underscore versions are cancellation points. Single underscore
+ * versions are not and are provided for libc internal usage (which
+ * shouldn't introduce cancellation points).
+ */
+__weak_reference(__pthread_cond_wait, pthread_cond_wait);
+__weak_reference(__pthread_cond_timedwait, pthread_cond_timedwait);
+
+__weak_reference(_pthread_cond_init, pthread_cond_init);
+__weak_reference(_pthread_cond_destroy, pthread_cond_destroy);
+__weak_reference(_pthread_cond_signal, pthread_cond_signal);
+__weak_reference(_pthread_cond_broadcast, pthread_cond_broadcast);
+
+
+int
+_pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr)
+{
+ enum pthread_cond_type type;
+ pthread_cond_t pcond;
+ int flags;
+ int rval = 0;
+
+ if (cond == NULL)
+ rval = EINVAL;
+ else {
+ /*
+ * Check if a pointer to a condition variable attribute
+ * structure was passed by the caller:
+ */
+ if (cond_attr != NULL && *cond_attr != NULL) {
+ /* Default to a fast condition variable: */
+ type = (*cond_attr)->c_type;
+ flags = (*cond_attr)->c_flags;
+ } else {
+ /* Default to a fast condition variable: */
+ type = COND_TYPE_FAST;
+ flags = 0;
+ }
+
+ /* Process according to condition variable type: */
+ switch (type) {
+ /* Fast condition variable: */
+ case COND_TYPE_FAST:
+ /* Nothing to do here. */
+ break;
+
+ /* Trap invalid condition variable types: */
+ default:
+ /* Return an invalid argument error: */
+ rval = EINVAL;
+ break;
+ }
+
+ /* Check for no errors: */
+ if (rval == 0) {
+ if ((pcond = (pthread_cond_t)
+ malloc(sizeof(struct pthread_cond))) == NULL) {
+ rval = ENOMEM;
+ } else if (_lock_init(&pcond->c_lock, LCK_ADAPTIVE,
+ _thr_lock_wait, _thr_lock_wakeup) != 0) {
+ free(pcond);
+ rval = ENOMEM;
+ } else {
+ /*
+ * Initialise the condition variable
+ * structure:
+ */
+ TAILQ_INIT(&pcond->c_queue);
+ pcond->c_flags = COND_FLAGS_INITED;
+ pcond->c_type = type;
+ pcond->c_mutex = NULL;
+ pcond->c_seqno = 0;
+ *cond = pcond;
+ }
+ }
+ }
+ /* Return the completion status: */
+ return (rval);
+}
+
+int
+_pthread_cond_destroy(pthread_cond_t *cond)
+{
+ struct pthread_cond *cv;
+ struct pthread *curthread = _get_curthread();
+ int rval = 0;
+
+ if (cond == NULL || *cond == NULL)
+ rval = EINVAL;
+ else {
+ /* Lock the condition variable structure: */
+ THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
+
+ /*
+ * NULL the caller's pointer now that the condition
+ * variable has been destroyed:
+ */
+ cv = *cond;
+ *cond = NULL;
+
+ /* Unlock the condition variable structure: */
+ THR_LOCK_RELEASE(curthread, &cv->c_lock);
+
+ /* Free the cond lock structure: */
+ _lock_destroy(&cv->c_lock);
+
+ /*
+ * Free the memory allocated for the condition
+ * variable structure:
+ */
+ free(cv);
+
+ }
+ /* Return the completion status: */
+ return (rval);
+}
+
+int
+_pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
+{
+ struct pthread *curthread = _get_curthread();
+ int rval = 0;
+ int done = 0;
+ int mutex_locked = 1;
+ int seqno;
+
+ if (cond == NULL)
+ return (EINVAL);
+
+ /*
+ * If the condition variable is statically initialized,
+ * perform the dynamic initialization:
+ */
+ if (*cond == NULL &&
+ (rval = pthread_cond_init(cond, NULL)) != 0)
+ return (rval);
+
+ if (!_kse_isthreaded())
+ _kse_setthreaded(1);
+
+ /*
+ * Enter a loop waiting for a condition signal or broadcast
+ * to wake up this thread. A loop is needed in case the waiting
+ * thread is interrupted by a signal to execute a signal handler.
+ * It is not (currently) possible to remain in the waiting queue
+ * while running a handler. Instead, the thread is interrupted
+ * and backed out of the waiting queue prior to executing the
+ * signal handler.
+ */
+
+ /* Lock the condition variable structure: */
+ THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
+ seqno = (*cond)->c_seqno;
+ do {
+ /*
+ * If the condvar was statically allocated, properly
+ * initialize the tail queue.
+ */
+ if (((*cond)->c_flags & COND_FLAGS_INITED) == 0) {
+ TAILQ_INIT(&(*cond)->c_queue);
+ (*cond)->c_flags |= COND_FLAGS_INITED;
+ }
+
+ /* Process according to condition variable type: */
+ switch ((*cond)->c_type) {
+ /* Fast condition variable: */
+ case COND_TYPE_FAST:
+ if ((mutex == NULL) || (((*cond)->c_mutex != NULL) &&
+ ((*cond)->c_mutex != *mutex))) {
+ /* Return invalid argument error: */
+ rval = EINVAL;
+ } else {
+ /* Reset the timeout and interrupted flags: */
+ curthread->timeout = 0;
+ curthread->interrupted = 0;
+
+ /*
+ * Queue the running thread for the condition
+ * variable:
+ */
+ cond_queue_enq(*cond, curthread);
+
+ /* Wait forever: */
+ curthread->wakeup_time.tv_sec = -1;
+
+ /* Unlock the mutex: */
+ if (mutex_locked &&
+ ((rval = _mutex_cv_unlock(mutex)) != 0)) {
+ /*
+ * Cannot unlock the mutex, so remove
+ * the running thread from the condition
+ * variable queue:
+ */
+ cond_queue_remove(*cond, curthread);
+ }
+ else {
+ /* Remember the mutex: */
+ (*cond)->c_mutex = *mutex;
+
+ /*
+ * Don't unlock the mutex the next
+ * time through the loop (if the
+ * thread has to be requeued after
+ * handling a signal).
+ */
+ mutex_locked = 0;
+
+ /*
+ * This thread is active and is in a
+ * critical region (holding the cv
+ * lock); we should be able to safely
+ * set the state.
+ */
+ THR_SCHED_LOCK(curthread, curthread);
+ THR_SET_STATE(curthread, PS_COND_WAIT);
+
+ /* Remember the CV: */
+ curthread->data.cond = *cond;
+ curthread->sigbackout = cond_wait_backout;
+ THR_SCHED_UNLOCK(curthread, curthread);
+
+ /* Unlock the CV structure: */
+ THR_LOCK_RELEASE(curthread,
+ &(*cond)->c_lock);
+
+ /* Schedule the next thread: */
+ _thr_sched_switch(curthread);
+
+ /*
+ * XXX - This really isn't a good check
+ * since there can be more than one
+ * thread waiting on the CV. Signals
+ * sent to threads waiting on mutexes
+ * or CVs should really be deferred
+ * until the threads are no longer
+ * waiting, but POSIX says that signals
+ * should be sent "as soon as possible".
+ */
+ done = (seqno != (*cond)->c_seqno);
+ if (done && !THR_IN_CONDQ(curthread)) {
+ /*
+ * The thread is dequeued, so
+ * it is safe to clear these.
+ */
+ curthread->data.cond = NULL;
+ curthread->sigbackout = NULL;
+ check_continuation(curthread,
+ NULL, mutex);
+ return (_mutex_cv_lock(mutex));
+ }
+
+ /* Relock the CV structure: */
+ THR_LOCK_ACQUIRE(curthread,
+ &(*cond)->c_lock);
+
+ /*
+ * Clear these after taking the lock to
+ * prevent a race condition where a
+ * signal can arrive before dequeueing
+ * the thread.
+ */
+ curthread->data.cond = NULL;
+ curthread->sigbackout = NULL;
+ done = (seqno != (*cond)->c_seqno);
+
+ if (THR_IN_CONDQ(curthread)) {
+ cond_queue_remove(*cond,
+ curthread);
+
+ /* Check for no more waiters: */
+ if (TAILQ_EMPTY(&(*cond)->c_queue))
+ (*cond)->c_mutex = NULL;
+ }
+ }
+ }
+ break;
+
+ /* Trap invalid condition variable types: */
+ default:
+ /* Return an invalid argument error: */
+ rval = EINVAL;
+ break;
+ }
+
+ check_continuation(curthread, *cond,
+ mutex_locked ? NULL : mutex);
+ } while ((done == 0) && (rval == 0));
+
+ /* Unlock the condition variable structure: */
+ THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
+
+ if (mutex_locked == 0)
+ _mutex_cv_lock(mutex);
+
+ /* Return the completion status: */
+ return (rval);
+}
+
+__strong_reference(_pthread_cond_wait, _thr_cond_wait);
+
+int
+__pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ _thr_cancel_enter(curthread);
+ ret = _pthread_cond_wait(cond, mutex);
+ _thr_cancel_leave(curthread, 1);
+ return (ret);
+}
+
+int
+_pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
+ const struct timespec * abstime)
+{
+ struct pthread *curthread = _get_curthread();
+ int rval = 0;
+ int done = 0;
+ int mutex_locked = 1;
+ int seqno;
+
+ THR_ASSERT(curthread->locklevel == 0,
+ "cv_timedwait: locklevel is not zero!");
+
+ if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 ||
+ abstime->tv_nsec >= 1000000000)
+ return (EINVAL);
+ /*
+ * If the condition variable is statically initialized, perform dynamic
+ * initialization.
+ */
+ if (*cond == NULL && (rval = pthread_cond_init(cond, NULL)) != 0)
+ return (rval);
+
+ if (!_kse_isthreaded())
+ _kse_setthreaded(1);
+
+ /*
+ * Enter a loop waiting for a condition signal or broadcast
+ * to wake up this thread. A loop is needed in case the waiting
+ * thread is interrupted by a signal to execute a signal handler.
+ * It is not (currently) possible to remain in the waiting queue
+ * while running a handler. Instead, the thread is interrupted
+ * and backed out of the waiting queue prior to executing the
+ * signal handler.
+ */
+
+ /* Lock the condition variable structure: */
+ THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
+ seqno = (*cond)->c_seqno;
+ do {
+ /*
+ * If the condvar was statically allocated, properly
+ * initialize the tail queue.
+ */
+ if (((*cond)->c_flags & COND_FLAGS_INITED) == 0) {
+ TAILQ_INIT(&(*cond)->c_queue);
+ (*cond)->c_flags |= COND_FLAGS_INITED;
+ }
+
+ /* Process according to condition variable type: */
+ switch ((*cond)->c_type) {
+ /* Fast condition variable: */
+ case COND_TYPE_FAST:
+ if ((mutex == NULL) || (((*cond)->c_mutex != NULL) &&
+ ((*cond)->c_mutex != *mutex))) {
+ /* Return invalid argument error: */
+ rval = EINVAL;
+ } else {
+ /* Reset the timeout and interrupted flags: */
+ curthread->timeout = 0;
+ curthread->interrupted = 0;
+
+ /*
+ * Queue the running thread for the condition
+ * variable:
+ */
+ cond_queue_enq(*cond, curthread);
+
+ /* Unlock the mutex: */
+ if (mutex_locked &&
+ ((rval = _mutex_cv_unlock(mutex)) != 0)) {
+ /*
+ * Cannot unlock the mutex; remove the
+ * running thread from the condition
+ * variable queue:
+ */
+ cond_queue_remove(*cond, curthread);
+ } else {
+ /* Remember the mutex: */
+ (*cond)->c_mutex = *mutex;
+
+ /*
+ * Don't unlock the mutex the next
+ * time through the loop (if the
+ * thread has to be requeued after
+ * handling a signal).
+ */
+ mutex_locked = 0;
+
+ /*
+ * This thread is active and is in a
+ * critical region (holding the cv
+ * lock); we should be able to safely
+ * set the state.
+ */
+ THR_SCHED_LOCK(curthread, curthread);
+ /* Set the wakeup time: */
+ curthread->wakeup_time.tv_sec =
+ abstime->tv_sec;
+ curthread->wakeup_time.tv_nsec =
+ abstime->tv_nsec;
+ THR_SET_STATE(curthread, PS_COND_WAIT);
+
+ /* Remember the CV: */
+ curthread->data.cond = *cond;
+ curthread->sigbackout = cond_wait_backout;
+ THR_SCHED_UNLOCK(curthread, curthread);
+
+ /* Unlock the CV structure: */
+ THR_LOCK_RELEASE(curthread,
+ &(*cond)->c_lock);
+
+ /* Schedule the next thread: */
+ _thr_sched_switch(curthread);
+
+ /*
+ * XXX - This really isn't a good check
+ * since there can be more than one
+ * thread waiting on the CV. Signals
+ * sent to threads waiting on mutexes
+ * or CVs should really be deferred
+ * until the threads are no longer
+ * waiting, but POSIX says that signals
+ * should be sent "as soon as possible".
+ */
+ done = (seqno != (*cond)->c_seqno);
+ if (done && !THR_IN_CONDQ(curthread)) {
+ /*
+ * The thread is dequeued, so
+ * it is safe to clear these.
+ */
+ curthread->data.cond = NULL;
+ curthread->sigbackout = NULL;
+ check_continuation(curthread,
+ NULL, mutex);
+ return (_mutex_cv_lock(mutex));
+ }
+
+ /* Relock the CV structure: */
+ THR_LOCK_ACQUIRE(curthread,
+ &(*cond)->c_lock);
+
+ /*
+ * Clear these after taking the lock to
+ * prevent a race condition where a
+ * signal can arrive before dequeueing
+ * the thread.
+ */
+ curthread->data.cond = NULL;
+ curthread->sigbackout = NULL;
+
+ done = (seqno != (*cond)->c_seqno);
+
+ if (THR_IN_CONDQ(curthread)) {
+ cond_queue_remove(*cond,
+ curthread);
+
+ /* Check for no more waiters: */
+ if (TAILQ_EMPTY(&(*cond)->c_queue))
+ (*cond)->c_mutex = NULL;
+ }
+
+ if (curthread->timeout != 0) {
+ /* The wait timedout. */
+ rval = ETIMEDOUT;
+ }
+ }
+ }
+ break;
+
+ /* Trap invalid condition variable types: */
+ default:
+ /* Return an invalid argument error: */
+ rval = EINVAL;
+ break;
+ }
+
+ check_continuation(curthread, *cond,
+ mutex_locked ? NULL : mutex);
+ } while ((done == 0) && (rval == 0));
+
+ /* Unlock the condition variable structure: */
+ THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
+
+ if (mutex_locked == 0)
+ _mutex_cv_lock(mutex);
+
+ /* Return the completion status: */
+ return (rval);
+}
+
+int
+__pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
+ const struct timespec *abstime)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ _thr_cancel_enter(curthread);
+ ret = _pthread_cond_timedwait(cond, mutex, abstime);
+ _thr_cancel_leave(curthread, 1);
+ return (ret);
+}
+
+
+int
+_pthread_cond_signal(pthread_cond_t * cond)
+{
+ struct pthread *curthread = _get_curthread();
+ struct pthread *pthread;
+ struct kse_mailbox *kmbx;
+ int rval = 0;
+
+ THR_ASSERT(curthread->locklevel == 0,
+ "cv_timedwait: locklevel is not zero!");
+ if (cond == NULL)
+ rval = EINVAL;
+ /*
+ * If the condition variable is statically initialized, perform dynamic
+ * initialization.
+ */
+ else if (*cond != NULL || (rval = pthread_cond_init(cond, NULL)) == 0) {
+ /* Lock the condition variable structure: */
+ THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
+
+ /* Process according to condition variable type: */
+ switch ((*cond)->c_type) {
+ /* Fast condition variable: */
+ case COND_TYPE_FAST:
+ /* Increment the sequence number: */
+ (*cond)->c_seqno++;
+
+ /*
+ * Wakeups have to be done with the CV lock held;
+ * otherwise there is a race condition where the
+ * thread can timeout, run on another KSE, and enter
+ * another blocking state (including blocking on a CV).
+ */
+ if ((pthread = TAILQ_FIRST(&(*cond)->c_queue))
+ != NULL) {
+ THR_SCHED_LOCK(curthread, pthread);
+ cond_queue_remove(*cond, pthread);
+ pthread->sigbackout = NULL;
+ if ((pthread->kseg == curthread->kseg) &&
+ (pthread->active_priority >
+ curthread->active_priority))
+ curthread->critical_yield = 1;
+ kmbx = _thr_setrunnable_unlocked(pthread);
+ THR_SCHED_UNLOCK(curthread, pthread);
+ if (kmbx != NULL)
+ kse_wakeup(kmbx);
+ }
+ /* Check for no more waiters: */
+ if (TAILQ_EMPTY(&(*cond)->c_queue))
+ (*cond)->c_mutex = NULL;
+ break;
+
+ /* Trap invalid condition variable types: */
+ default:
+ /* Return an invalid argument error: */
+ rval = EINVAL;
+ break;
+ }
+
+ /* Unlock the condition variable structure: */
+ THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
+ }
+
+ /* Return the completion status: */
+ return (rval);
+}
+
+__strong_reference(_pthread_cond_signal, _thr_cond_signal);
+
+int
+_pthread_cond_broadcast(pthread_cond_t * cond)
+{
+ struct pthread *curthread = _get_curthread();
+ struct pthread *pthread;
+ struct kse_mailbox *kmbx;
+ int rval = 0;
+
+ THR_ASSERT(curthread->locklevel == 0,
+ "cv_timedwait: locklevel is not zero!");
+ if (cond == NULL)
+ rval = EINVAL;
+ /*
+ * If the condition variable is statically initialized, perform dynamic
+ * initialization.
+ */
+ else if (*cond != NULL || (rval = pthread_cond_init(cond, NULL)) == 0) {
+ /* Lock the condition variable structure: */
+ THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
+
+ /* Process according to condition variable type: */
+ switch ((*cond)->c_type) {
+ /* Fast condition variable: */
+ case COND_TYPE_FAST:
+ /* Increment the sequence number: */
+ (*cond)->c_seqno++;
+
+ /*
+ * Enter a loop to bring all threads off the
+ * condition queue:
+ */
+ while ((pthread = TAILQ_FIRST(&(*cond)->c_queue))
+ != NULL) {
+ THR_SCHED_LOCK(curthread, pthread);
+ cond_queue_remove(*cond, pthread);
+ pthread->sigbackout = NULL;
+ if ((pthread->kseg == curthread->kseg) &&
+ (pthread->active_priority >
+ curthread->active_priority))
+ curthread->critical_yield = 1;
+ kmbx = _thr_setrunnable_unlocked(pthread);
+ THR_SCHED_UNLOCK(curthread, pthread);
+ if (kmbx != NULL)
+ kse_wakeup(kmbx);
+ }
+
+ /* There are no more waiting threads: */
+ (*cond)->c_mutex = NULL;
+ break;
+
+ /* Trap invalid condition variable types: */
+ default:
+ /* Return an invalid argument error: */
+ rval = EINVAL;
+ break;
+ }
+
+ /* Unlock the condition variable structure: */
+ THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
+ }
+
+ /* Return the completion status: */
+ return (rval);
+}
+
+__strong_reference(_pthread_cond_broadcast, _thr_cond_broadcast);
+
+static inline void
+check_continuation(struct pthread *curthread, struct pthread_cond *cond,
+ pthread_mutex_t *mutex)
+{
+ if ((curthread->interrupted != 0) &&
+ (curthread->continuation != NULL)) {
+ if (cond != NULL)
+ /* Unlock the condition variable structure: */
+ THR_LOCK_RELEASE(curthread, &cond->c_lock);
+ /*
+ * Note that even though this thread may have been
+ * canceled, POSIX requires that the mutex be
+ * reaquired prior to cancellation.
+ */
+ if (mutex != NULL)
+ _mutex_cv_lock(mutex);
+ curthread->continuation((void *) curthread);
+ PANIC("continuation returned in pthread_cond_wait.\n");
+ }
+}
+
+static void
+cond_wait_backout(void *arg)
+{
+ struct pthread *curthread = (struct pthread *)arg;
+ pthread_cond_t cond;
+
+ cond = curthread->data.cond;
+ if (cond != NULL) {
+ /* Lock the condition variable structure: */
+ THR_LOCK_ACQUIRE(curthread, &cond->c_lock);
+
+ /* Process according to condition variable type: */
+ switch (cond->c_type) {
+ /* Fast condition variable: */
+ case COND_TYPE_FAST:
+ cond_queue_remove(cond, curthread);
+
+ /* Check for no more waiters: */
+ if (TAILQ_EMPTY(&cond->c_queue))
+ cond->c_mutex = NULL;
+ break;
+
+ default:
+ break;
+ }
+
+ /* Unlock the condition variable structure: */
+ THR_LOCK_RELEASE(curthread, &cond->c_lock);
+ }
+ /* No need to call this again. */
+ curthread->sigbackout = NULL;
+}
+
+/*
+ * Dequeue a waiting thread from the head of a condition queue in
+ * descending priority order.
+ */
+static inline struct pthread *
+cond_queue_deq(pthread_cond_t cond)
+{
+ struct pthread *pthread;
+
+ while ((pthread = TAILQ_FIRST(&cond->c_queue)) != NULL) {
+ TAILQ_REMOVE(&cond->c_queue, pthread, sqe);
+ THR_CONDQ_CLEAR(pthread);
+ if ((pthread->timeout == 0) && (pthread->interrupted == 0))
+ /*
+ * Only exit the loop when we find a thread
+ * that hasn't timed out or been canceled;
+ * those threads are already running and don't
+ * need their run state changed.
+ */
+ break;
+ }
+
+ return (pthread);
+}
+
+/*
+ * Remove a waiting thread from a condition queue in descending priority
+ * order.
+ */
+static inline void
+cond_queue_remove(pthread_cond_t cond, struct pthread *pthread)
+{
+ /*
+ * Because pthread_cond_timedwait() can timeout as well
+ * as be signaled by another thread, it is necessary to
+ * guard against removing the thread from the queue if
+ * it isn't in the queue.
+ */
+ if (THR_IN_CONDQ(pthread)) {
+ TAILQ_REMOVE(&cond->c_queue, pthread, sqe);
+ THR_CONDQ_CLEAR(pthread);
+ }
+}
+
+/*
+ * Enqueue a waiting thread to a condition queue in descending priority
+ * order.
+ */
+static inline void
+cond_queue_enq(pthread_cond_t cond, struct pthread *pthread)
+{
+ struct pthread *tid = TAILQ_LAST(&cond->c_queue, cond_head);
+
+ THR_ASSERT(!THR_IN_SYNCQ(pthread),
+ "cond_queue_enq: thread already queued!");
+
+ /*
+ * For the common case of all threads having equal priority,
+ * we perform a quick check against the priority of the thread
+ * at the tail of the queue.
+ */
+ if ((tid == NULL) || (pthread->active_priority <= tid->active_priority))
+ TAILQ_INSERT_TAIL(&cond->c_queue, pthread, sqe);
+ else {
+ tid = TAILQ_FIRST(&cond->c_queue);
+ while (pthread->active_priority <= tid->active_priority)
+ tid = TAILQ_NEXT(tid, sqe);
+ TAILQ_INSERT_BEFORE(tid, pthread, sqe);
+ }
+ THR_CONDQ_SET(pthread);
+ pthread->data.cond = cond;
+}
diff --git a/lib/libpthread/thread/thr_condattr_destroy.c b/lib/libpthread/thread/thr_condattr_destroy.c
new file mode 100644
index 0000000..4e2c337
--- /dev/null
+++ b/lib/libpthread/thread/thr_condattr_destroy.c
@@ -0,0 +1,56 @@
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_condattr_destroy);
+LT10_COMPAT_DEFAULT(pthread_condattr_destroy);
+
+__weak_reference(_pthread_condattr_destroy, pthread_condattr_destroy);
+
+int
+_pthread_condattr_destroy(pthread_condattr_t *attr)
+{
+ int ret;
+ if (attr == NULL || *attr == NULL) {
+ ret = EINVAL;
+ } else {
+ free(*attr);
+ *attr = NULL;
+ ret = 0;
+ }
+ return(ret);
+}
diff --git a/lib/libpthread/thread/thr_condattr_init.c b/lib/libpthread/thread/thr_condattr_init.c
new file mode 100644
index 0000000..e553839
--- /dev/null
+++ b/lib/libpthread/thread/thr_condattr_init.c
@@ -0,0 +1,61 @@
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_condattr_init);
+LT10_COMPAT_DEFAULT(pthread_condattr_init);
+
+__weak_reference(_pthread_condattr_init, pthread_condattr_init);
+
+int
+_pthread_condattr_init(pthread_condattr_t *attr)
+{
+ int ret;
+ pthread_condattr_t pattr;
+
+ if ((pattr = (pthread_condattr_t)
+ malloc(sizeof(struct pthread_cond_attr))) == NULL) {
+ ret = ENOMEM;
+ } else {
+ memcpy(pattr, &_pthread_condattr_default,
+ sizeof(struct pthread_cond_attr));
+ *attr = pattr;
+ ret = 0;
+ }
+ return (ret);
+}
diff --git a/lib/libpthread/thread/thr_condattr_pshared.c b/lib/libpthread/thread/thr_condattr_pshared.c
new file mode 100644
index 0000000..7cef4d9
--- /dev/null
+++ b/lib/libpthread/thread/thr_condattr_pshared.c
@@ -0,0 +1,56 @@
+/*
+ * 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 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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, 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$
+ *
+ */
+
+#include <errno.h>
+#include "thr_private.h"
+
+__weak_reference(_pthread_condattr_getpshared, pthread_condattr_getpshared);
+__weak_reference(_pthread_condattr_setpshared, pthread_condattr_setpshared);
+
+int
+_pthread_condattr_getpshared(const pthread_condattr_t *attr,
+ int *pshared)
+{
+ if (attr == NULL || *attr == NULL)
+ return (EINVAL);
+
+ pshared = PTHREAD_PROCESS_PRIVATE;
+ return (0);
+}
+
+int
+_pthread_condattr_setpshared(pthread_condattr_t *attr, int pshared)
+{
+ if (attr == NULL || *attr == NULL)
+ return (EINVAL);
+
+ if (pshared != PTHREAD_PROCESS_PRIVATE)
+ return (EINVAL);
+ return (0);
+}
diff --git a/lib/libpthread/thread/thr_connect.c b/lib/libpthread/thread/thr_connect.c
new file mode 100644
index 0000000..225d8b9
--- /dev/null
+++ b/lib/libpthread/thread/thr_connect.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2003 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 THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 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 <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__connect);
+LT10_COMPAT_DEFAULT(connect);
+
+__weak_reference(__connect, connect);
+
+int
+__connect(int fd, const struct sockaddr *name, socklen_t namelen)
+{
+ struct pthread *curthread;
+ int ret;
+
+ curthread = _get_curthread();
+ _thr_cancel_enter(curthread);
+ ret = __sys_connect(fd, name, namelen);
+ _thr_cancel_leave(curthread, ret == -1);
+
+ return (ret);
+}
diff --git a/lib/libpthread/thread/thr_creat.c b/lib/libpthread/thread/thr_creat.c
new file mode 100644
index 0000000..7528f0b
--- /dev/null
+++ b/lib/libpthread/thread/thr_creat.c
@@ -0,0 +1,58 @@
+/*
+ * 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$
+ */
+
+#include <fcntl.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(___creat);
+LT10_COMPAT_DEFAULT(creat);
+
+extern int __creat(const char *, mode_t);
+
+__weak_reference(___creat, creat);
+
+int
+___creat(const char *path, mode_t mode)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ _thr_cancel_enter(curthread);
+ ret = __creat(path, mode);
+ /*
+ * To avoid possible file handle leak,
+ * only check cancellation point if it is failure
+ */
+ _thr_cancel_leave(curthread, (ret == -1));
+
+ return ret;
+}
diff --git a/lib/libpthread/thread/thr_create.c b/lib/libpthread/thread/thr_create.c
new file mode 100644
index 0000000..98edb71
--- /dev/null
+++ b/lib/libpthread/thread/thr_create.c
@@ -0,0 +1,348 @@
+/*
+ * Copyright (c) 2003 Daniel M. Eischen <deischen@gdeb.com>
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <sys/time.h>
+#include <machine/reg.h>
+#include <pthread.h>
+#include "thr_private.h"
+#include "libc_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_create);
+LT10_COMPAT_DEFAULT(pthread_create);
+
+static void free_thread(struct pthread *curthread, struct pthread *thread);
+static int create_stack(struct pthread_attr *pattr);
+static void free_stack(struct pthread_attr *pattr);
+static void thread_start(struct pthread *curthread,
+ void *(*start_routine) (void *), void *arg);
+
+__weak_reference(_pthread_create, pthread_create);
+
+/*
+ * Some notes on new thread creation and first time initializion
+ * to enable multi-threading.
+ *
+ * There are basically two things that need to be done.
+ *
+ * 1) The internal library variables must be initialized.
+ * 2) Upcalls need to be enabled to allow multiple threads
+ * to be run.
+ *
+ * The first may be done as a result of other pthread functions
+ * being called. When _thr_initial is null, _libpthread_init is
+ * called to initialize the internal variables; this also creates
+ * or sets the initial thread. It'd be nice to automatically
+ * have _libpthread_init called on program execution so we don't
+ * have to have checks throughout the library.
+ *
+ * The second part is only triggered by the creation of the first
+ * thread (other than the initial/main thread). If the thread
+ * being created is a scope system thread, then a new KSE/KSEG
+ * pair needs to be allocated. Also, if upcalls haven't been
+ * enabled on the initial thread's KSE, they must be now that
+ * there is more than one thread; this could be delayed until
+ * the initial KSEG has more than one thread.
+ */
+int
+_pthread_create(pthread_t * thread, const pthread_attr_t * attr,
+ void *(*start_routine) (void *), void *arg)
+{
+ struct pthread *curthread, *new_thread;
+ struct kse *kse = NULL;
+ struct kse_group *kseg = NULL;
+ kse_critical_t crit;
+ int ret = 0;
+
+ if (_thr_initial == NULL)
+ _libpthread_init(NULL);
+
+ /*
+ * Turn on threaded mode, if failed, it is unnecessary to
+ * do further work.
+ */
+ if (_kse_isthreaded() == 0 && _kse_setthreaded(1)) {
+ return (EAGAIN);
+ }
+ curthread = _get_curthread();
+
+ /*
+ * Allocate memory for the thread structure.
+ * Some functions use malloc, so don't put it
+ * in a critical region.
+ */
+ if ((new_thread = _thr_alloc(curthread)) == NULL) {
+ /* Insufficient memory to create a thread: */
+ ret = EAGAIN;
+ } else {
+ /* Check if default thread attributes are required: */
+ if (attr == NULL || *attr == NULL)
+ /* Use the default thread attributes: */
+ new_thread->attr = _pthread_attr_default;
+ else {
+ new_thread->attr = *(*attr);
+ if ((*attr)->sched_inherit == PTHREAD_INHERIT_SCHED) {
+ /* inherit scheduling contention scop */
+ if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
+ new_thread->attr.flags |= PTHREAD_SCOPE_SYSTEM;
+ else
+ new_thread->attr.flags &= ~PTHREAD_SCOPE_SYSTEM;
+ /*
+ * scheduling policy and scheduling parameters will be
+ * inherited in following code.
+ */
+ }
+ }
+ if (_thread_scope_system > 0)
+ new_thread->attr.flags |= PTHREAD_SCOPE_SYSTEM;
+ else if ((_thread_scope_system < 0)
+ && (thread != &_thr_sig_daemon))
+ new_thread->attr.flags &= ~PTHREAD_SCOPE_SYSTEM;
+ if (create_stack(&new_thread->attr) != 0) {
+ /* Insufficient memory to create a stack: */
+ ret = EAGAIN;
+ _thr_free(curthread, new_thread);
+ }
+ else if (((new_thread->attr.flags & PTHREAD_SCOPE_SYSTEM) != 0) &&
+ (((kse = _kse_alloc(curthread, 1)) == NULL)
+ || ((kseg = _kseg_alloc(curthread)) == NULL))) {
+ /* Insufficient memory to create a new KSE/KSEG: */
+ ret = EAGAIN;
+ if (kse != NULL) {
+ kse->k_kcb->kcb_kmbx.km_flags |= KMF_DONE;
+ _kse_free(curthread, kse);
+ }
+ free_stack(&new_thread->attr);
+ _thr_free(curthread, new_thread);
+ }
+ else {
+ if (kseg != NULL) {
+ /* Add the KSE to the KSEG's list of KSEs. */
+ TAILQ_INSERT_HEAD(&kseg->kg_kseq, kse, k_kgqe);
+ kseg->kg_ksecount = 1;
+ kse->k_kseg = kseg;
+ kse->k_schedq = &kseg->kg_schedq;
+ }
+ /*
+ * Write a magic value to the thread structure
+ * to help identify valid ones:
+ */
+ new_thread->magic = THR_MAGIC;
+
+ new_thread->slice_usec = -1;
+ new_thread->start_routine = start_routine;
+ new_thread->arg = arg;
+ new_thread->cancelflags = PTHREAD_CANCEL_ENABLE |
+ PTHREAD_CANCEL_DEFERRED;
+
+ /* No thread is wanting to join to this one: */
+ new_thread->joiner = NULL;
+
+ /*
+ * Initialize the machine context.
+ * Enter a critical region to get consistent context.
+ */
+ crit = _kse_critical_enter();
+ THR_GETCONTEXT(&new_thread->tcb->tcb_tmbx.tm_context);
+ /* Initialize the thread for signals: */
+ new_thread->sigmask = curthread->sigmask;
+ _kse_critical_leave(crit);
+
+ new_thread->tcb->tcb_tmbx.tm_udata = new_thread;
+ new_thread->tcb->tcb_tmbx.tm_context.uc_sigmask =
+ new_thread->sigmask;
+ new_thread->tcb->tcb_tmbx.tm_context.uc_stack.ss_size =
+ new_thread->attr.stacksize_attr;
+ new_thread->tcb->tcb_tmbx.tm_context.uc_stack.ss_sp =
+ new_thread->attr.stackaddr_attr;
+ makecontext(&new_thread->tcb->tcb_tmbx.tm_context,
+ (void (*)(void))thread_start, 3, new_thread,
+ start_routine, arg);
+ /*
+ * Check if this thread is to inherit the scheduling
+ * attributes from its parent:
+ */
+ if (new_thread->attr.sched_inherit == PTHREAD_INHERIT_SCHED) {
+ /*
+ * Copy the scheduling attributes.
+ * Lock the scheduling lock to get consistent
+ * scheduling parameters.
+ */
+ THR_SCHED_LOCK(curthread, curthread);
+ new_thread->base_priority =
+ curthread->base_priority &
+ ~THR_SIGNAL_PRIORITY;
+ new_thread->attr.prio =
+ curthread->base_priority &
+ ~THR_SIGNAL_PRIORITY;
+ new_thread->attr.sched_policy =
+ curthread->attr.sched_policy;
+ THR_SCHED_UNLOCK(curthread, curthread);
+ } else {
+ /*
+ * Use just the thread priority, leaving the
+ * other scheduling attributes as their
+ * default values:
+ */
+ new_thread->base_priority =
+ new_thread->attr.prio;
+ }
+ new_thread->active_priority = new_thread->base_priority;
+ new_thread->inherited_priority = 0;
+
+ /* Initialize the mutex queue: */
+ TAILQ_INIT(&new_thread->mutexq);
+
+ /* Initialise hooks in the thread structure: */
+ new_thread->specific = NULL;
+ new_thread->specific_data_count = 0;
+ new_thread->cleanup = NULL;
+ new_thread->flags = 0;
+ new_thread->tlflags = 0;
+ new_thread->sigbackout = NULL;
+ new_thread->continuation = NULL;
+ new_thread->wakeup_time.tv_sec = -1;
+ new_thread->lock_switch = 0;
+ sigemptyset(&new_thread->sigpend);
+ new_thread->check_pending = 0;
+ new_thread->locklevel = 0;
+ new_thread->rdlock_count = 0;
+ new_thread->sigstk.ss_sp = 0;
+ new_thread->sigstk.ss_size = 0;
+ new_thread->sigstk.ss_flags = SS_DISABLE;
+ new_thread->oldsigmask = NULL;
+
+ if (new_thread->attr.suspend == THR_CREATE_SUSPENDED) {
+ new_thread->state = PS_SUSPENDED;
+ new_thread->flags = THR_FLAGS_SUSPENDED;
+ }
+ else
+ new_thread->state = PS_RUNNING;
+
+ /*
+ * System scope threads have their own kse and
+ * kseg. Process scope threads are all hung
+ * off the main process kseg.
+ */
+ if ((new_thread->attr.flags & PTHREAD_SCOPE_SYSTEM) == 0) {
+ new_thread->kseg = _kse_initial->k_kseg;
+ new_thread->kse = _kse_initial;
+ }
+ else {
+ kse->k_curthread = NULL;
+ kse->k_kseg->kg_flags |= KGF_SINGLE_THREAD;
+ new_thread->kse = kse;
+ new_thread->kseg = kse->k_kseg;
+ kse->k_kcb->kcb_kmbx.km_udata = kse;
+ kse->k_kcb->kcb_kmbx.km_curthread = NULL;
+ }
+
+ /*
+ * Schedule the new thread starting a new KSEG/KSE
+ * pair if necessary.
+ */
+ ret = _thr_schedule_add(curthread, new_thread);
+ if (ret != 0)
+ free_thread(curthread, new_thread);
+ else {
+ /* Return a pointer to the thread structure: */
+ (*thread) = new_thread;
+ }
+ }
+ }
+
+ /* Return the status: */
+ return (ret);
+}
+
+static void
+free_thread(struct pthread *curthread, struct pthread *thread)
+{
+ free_stack(&thread->attr);
+ if ((thread->attr.flags & PTHREAD_SCOPE_SYSTEM) != 0) {
+ /* Free the KSE and KSEG. */
+ _kseg_free(thread->kseg);
+ _kse_free(curthread, thread->kse);
+ }
+ _thr_free(curthread, thread);
+}
+
+static int
+create_stack(struct pthread_attr *pattr)
+{
+ int ret;
+
+ /* Check if a stack was specified in the thread attributes: */
+ if ((pattr->stackaddr_attr) != NULL) {
+ pattr->guardsize_attr = 0;
+ pattr->flags |= THR_STACK_USER;
+ ret = 0;
+ }
+ else
+ ret = _thr_stack_alloc(pattr);
+ return (ret);
+}
+
+static void
+free_stack(struct pthread_attr *pattr)
+{
+ struct kse *curkse;
+ kse_critical_t crit;
+
+ if ((pattr->flags & THR_STACK_USER) == 0) {
+ crit = _kse_critical_enter();
+ curkse = _get_curkse();
+ KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock);
+ /* Stack routines don't use malloc/free. */
+ _thr_stack_free(pattr);
+ KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
+ _kse_critical_leave(crit);
+ }
+}
+
+static void
+thread_start(struct pthread *curthread, void *(*start_routine) (void *),
+ void *arg)
+{
+ /* Run the current thread's start routine with argument: */
+ pthread_exit(start_routine(arg));
+
+ /* This point should never be reached. */
+ PANIC("Thread has resumed after exit");
+}
diff --git a/lib/libpthread/thread/thr_detach.c b/lib/libpthread/thread/thr_detach.c
new file mode 100644
index 0000000..2ae95df
--- /dev/null
+++ b/lib/libpthread/thread/thr_detach.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <machine/atomic.h>
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_detach);
+LT10_COMPAT_DEFAULT(pthread_detach);
+
+__weak_reference(_pthread_detach, pthread_detach);
+
+int
+_pthread_detach(pthread_t pthread)
+{
+ struct pthread *curthread = _get_curthread();
+ struct kse_mailbox *kmbx = NULL;
+ struct pthread *joiner;
+ int rval = 0;
+
+ /* Check for invalid calling parameters: */
+ if (pthread == NULL || pthread->magic != THR_MAGIC)
+ /* Return an invalid argument error: */
+ rval = EINVAL;
+
+ else if ((rval = _thr_ref_add(curthread, pthread,
+ /*include dead*/1)) != 0) {
+ /* Return an error: */
+ }
+
+ /* Check if the thread is already detached: */
+ else if ((pthread->attr.flags & PTHREAD_DETACHED) != 0) {
+ /* Return an error: */
+ _thr_ref_delete(curthread, pthread);
+ rval = EINVAL;
+ } else {
+ /* Lock the detached thread: */
+ THR_SCHED_LOCK(curthread, pthread);
+
+ /* Flag the thread as detached: */
+ pthread->attr.flags |= PTHREAD_DETACHED;
+
+ /* Retrieve any joining thread and remove it: */
+ joiner = pthread->joiner;
+ if ((joiner != NULL) && (joiner->kseg == pthread->kseg)) {
+ /*
+ * We already own the scheduler lock for the joiner.
+ * Take advantage of that and make the joiner runnable.
+ */
+ if (joiner->join_status.thread == pthread) {
+ /*
+ * Set the return value for the woken thread:
+ */
+ joiner->join_status.error = ESRCH;
+ joiner->join_status.ret = NULL;
+ joiner->join_status.thread = NULL;
+
+ kmbx = _thr_setrunnable_unlocked(joiner);
+ }
+ joiner = NULL;
+ }
+ THR_SCHED_UNLOCK(curthread, pthread);
+ /* See if there is a thread waiting in pthread_join(): */
+ if ((joiner != NULL) &&
+ (_thr_ref_add(curthread, joiner, 0) == 0)) {
+ /* Lock the joiner before fiddling with it. */
+ THR_SCHED_LOCK(curthread, joiner);
+ if (joiner->join_status.thread == pthread) {
+ /*
+ * Set the return value for the woken thread:
+ */
+ joiner->join_status.error = ESRCH;
+ joiner->join_status.ret = NULL;
+ joiner->join_status.thread = NULL;
+
+ kmbx = _thr_setrunnable_unlocked(joiner);
+ }
+ THR_SCHED_UNLOCK(curthread, joiner);
+ _thr_ref_delete(curthread, joiner);
+ }
+ _thr_ref_delete(curthread, pthread);
+ if (kmbx != NULL)
+ kse_wakeup(kmbx);
+ }
+
+ /* Return the completion status: */
+ return (rval);
+}
diff --git a/lib/libpthread/thread/thr_equal.c b/lib/libpthread/thread/thr_equal.c
new file mode 100644
index 0000000..95a3b65
--- /dev/null
+++ b/lib/libpthread/thread/thr_equal.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_equal);
+LT10_COMPAT_DEFAULT(pthread_equal);
+
+__weak_reference(_pthread_equal, pthread_equal);
+
+int
+_pthread_equal(pthread_t t1, pthread_t t2)
+{
+ /* Compare the two thread pointers: */
+ return (t1 == t2);
+}
diff --git a/lib/libpthread/thread/thr_execve.c b/lib/libpthread/thread/thr_execve.c
new file mode 100644
index 0000000..b902981
--- /dev/null
+++ b/lib/libpthread/thread/thr_execve.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2004 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(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 <errno.h>
+#include <pthread.h>
+#include <unistd.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_execve);
+LT10_COMPAT_DEFAULT(execve);
+
+__weak_reference(_execve, execve);
+
+int
+_execve(const char *name, char *const *argv, char *const *envp)
+{
+ struct kse_execve_args args;
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
+ ret = __sys_execve(name, argv, envp);
+ else {
+ /*
+ * When exec'ing, set the kernel signal mask to the thread's
+ * signal mask to satisfy POSIX requirements.
+ */
+ args.sigmask = curthread->sigmask;
+ args.sigpend = curthread->sigpend;
+ args.path = (char *)name;
+ args.argv = (char **)argv;
+ args.envp = (char **)envp;
+ args.reserved = NULL;
+ ret = kse_thr_interrupt(NULL, KSE_INTR_EXECVE, (long)&args);
+ }
+
+ return (ret);
+}
diff --git a/lib/libpthread/thread/thr_exit.c b/lib/libpthread/thread/thr_exit.c
new file mode 100644
index 0000000..1b2f84e
--- /dev/null
+++ b/lib/libpthread/thread/thr_exit.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_exit);
+LT10_COMPAT_DEFAULT(pthread_exit);
+
+void _pthread_exit(void *status);
+
+__weak_reference(_pthread_exit, pthread_exit);
+
+void
+_thr_exit(char *fname, int lineno, char *msg)
+{
+
+ /* Write an error message to the standard error file descriptor: */
+ _thread_printf(2,
+ "Fatal error '%s' at line %d in file %s (errno = %d)\n",
+ msg, lineno, fname, errno);
+
+ abort();
+}
+
+/*
+ * Only called when a thread is cancelled. It may be more useful
+ * to call it from pthread_exit() if other ways of asynchronous or
+ * abnormal thread termination can be found.
+ */
+void
+_thr_exit_cleanup(void)
+{
+ struct pthread *curthread = _get_curthread();
+
+ /*
+ * POSIX states that cancellation/termination of a thread should
+ * not release any visible resources (such as mutexes) and that
+ * it is the applications responsibility. Resources that are
+ * internal to the threads library, including file and fd locks,
+ * are not visible to the application and need to be released.
+ */
+ /* Unlock all private mutexes: */
+ _mutex_unlock_private(curthread);
+
+ /*
+ * This still isn't quite correct because we don't account
+ * for held spinlocks (see libc/stdlib/malloc.c).
+ */
+}
+
+void
+_pthread_exit(void *status)
+{
+ struct pthread *curthread = _get_curthread();
+ kse_critical_t crit;
+ struct kse *curkse;
+
+ /* Check if this thread is already in the process of exiting: */
+ if ((curthread->flags & THR_FLAGS_EXITING) != 0) {
+ char msg[128];
+ snprintf(msg, sizeof(msg), "Thread %p has called "
+ "pthread_exit() from a destructor. POSIX 1003.1 "
+ "1996 s16.2.5.2 does not allow this!", curthread);
+ PANIC(msg);
+ }
+
+ /*
+ * Flag this thread as exiting. Threads should now be prevented
+ * from joining to this thread.
+ */
+ THR_SCHED_LOCK(curthread, curthread);
+ curthread->flags |= THR_FLAGS_EXITING;
+ THR_SCHED_UNLOCK(curthread, curthread);
+
+ /*
+ * To avoid signal-lost problem, if signals had already been
+ * delivered to us, handle it. we have already set EXITING flag
+ * so no new signals should be delivered to us.
+ * XXX this is not enough if signal was delivered just before
+ * thread called sigprocmask and masked it! in this case, we
+ * might have to re-post the signal by kill() if the signal
+ * is targeting process (not for a specified thread).
+ * Kernel has same signal-lost problem, a signal may be delivered
+ * to a thread which is on the way to call sigprocmask or thr_exit()!
+ */
+ if (curthread->check_pending)
+ _thr_sig_check_pending(curthread);
+ /* Save the return value: */
+ curthread->ret = status;
+ while (curthread->cleanup != NULL) {
+ pthread_cleanup_pop(1);
+ }
+ if (curthread->attr.cleanup_attr != NULL) {
+ curthread->attr.cleanup_attr(curthread->attr.arg_attr);
+ }
+ /* Check if there is thread specific data: */
+ if (curthread->specific != NULL) {
+ /* Run the thread-specific data destructors: */
+ _thread_cleanupspecific();
+ }
+ if (!_kse_isthreaded())
+ exit(0);
+ crit = _kse_critical_enter();
+ curkse = _get_curkse();
+ KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock);
+ /* Use thread_list_lock */
+ _thread_active_threads--;
+ if ((_thread_scope_system <= 0 && _thread_active_threads == 1) ||
+ (_thread_scope_system > 0 && _thread_active_threads == 0)) {
+ KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
+ _kse_critical_leave(crit);
+ exit(0);
+ /* Never reach! */
+ }
+ KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
+
+ /* This thread will never be re-scheduled. */
+ KSE_LOCK(curkse);
+ THR_SET_STATE(curthread, PS_DEAD);
+ _thr_sched_switch_unlocked(curthread);
+ /* Never reach! */
+
+ /* This point should not be reached. */
+ PANIC("Dead thread has resumed");
+}
diff --git a/lib/libpthread/thread/thr_fcntl.c b/lib/libpthread/thread/thr_fcntl.c
new file mode 100644
index 0000000..d59dfd7
--- /dev/null
+++ b/lib/libpthread/thread/thr_fcntl.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <stdarg.h>
+#include "namespace.h"
+#include <fcntl.h>
+#include "un-namespace.h"
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__fcntl);
+LT10_COMPAT_DEFAULT(fcntl);
+
+__weak_reference(__fcntl, fcntl);
+
+int
+__fcntl(int fd, int cmd,...)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret, check = 1;
+ va_list ap;
+
+ _thr_cancel_enter(curthread);
+
+ va_start(ap, cmd);
+ switch (cmd) {
+ case F_DUPFD:
+ ret = __sys_fcntl(fd, cmd, va_arg(ap, int));
+ /*
+ * To avoid possible file handle leak,
+ * only check cancellation point if it is failure
+ */
+ check = (ret == -1);
+ break;
+ case F_SETFD:
+ case F_SETFL:
+ ret = __sys_fcntl(fd, cmd, va_arg(ap, int));
+ break;
+ case F_GETFD:
+ case F_GETFL:
+ ret = __sys_fcntl(fd, cmd);
+ break;
+ default:
+ ret = __sys_fcntl(fd, cmd, va_arg(ap, void *));
+ }
+ va_end(ap);
+
+ _thr_cancel_leave(curthread, check);
+
+ return (ret);
+}
diff --git a/lib/libpthread/thread/thr_find_thread.c b/lib/libpthread/thread/thr_find_thread.c
new file mode 100644
index 0000000..5a64640
--- /dev/null
+++ b/lib/libpthread/thread/thr_find_thread.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2003 Daniel Eischen <deischen@freebsd.org>
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+/*
+ * Find a thread in the linked list of active threads and add a reference
+ * to it. Threads with positive reference counts will not be deallocated
+ * until all references are released.
+ */
+int
+_thr_ref_add(struct pthread *curthread, struct pthread *thread,
+ int include_dead)
+{
+ kse_critical_t crit;
+ struct pthread *pthread;
+ struct kse *curkse;
+
+ if (thread == NULL)
+ /* Invalid thread: */
+ return (EINVAL);
+
+ crit = _kse_critical_enter();
+ curkse = _get_curkse();
+ KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock);
+ pthread = _thr_hash_find(thread);
+ if (pthread) {
+ if ((include_dead == 0) &&
+ ((pthread->state == PS_DEAD) ||
+ ((pthread->state == PS_DEADLOCK) ||
+ ((pthread->flags & THR_FLAGS_EXITING) != 0))))
+ pthread = NULL;
+ else {
+ pthread->refcount++;
+ if (curthread != NULL)
+ curthread->critical_count++;
+ }
+ }
+ KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
+ _kse_critical_leave(crit);
+
+ /* Return zero if the thread exists: */
+ return ((pthread != NULL) ? 0 : ESRCH);
+}
+
+void
+_thr_ref_delete(struct pthread *curthread, struct pthread *thread)
+{
+ kse_critical_t crit;
+ struct kse *curkse;
+
+ if (thread != NULL) {
+ crit = _kse_critical_enter();
+ curkse = _get_curkse();
+ KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock);
+ thread->refcount--;
+ if (curthread != NULL)
+ curthread->critical_count--;
+ if ((thread->refcount == 0) &&
+ (thread->tlflags & TLFLAGS_GC_SAFE) != 0)
+ THR_GCLIST_ADD(thread);
+ KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
+ _kse_critical_leave(crit);
+ }
+}
diff --git a/lib/libpthread/thread/thr_fork.c b/lib/libpthread/thread/thr_fork.c
new file mode 100644
index 0000000..4dfa487
--- /dev/null
+++ b/lib/libpthread/thread/thr_fork.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <spinlock.h>
+#include <sys/signalvar.h>
+
+#include "libc_private.h"
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_fork);
+LT10_COMPAT_DEFAULT(fork);
+
+__weak_reference(_fork, fork);
+
+pid_t
+_fork(void)
+{
+ sigset_t sigset, oldset;
+ struct pthread *curthread;
+ struct pthread_atfork *af;
+ pid_t ret;
+ int errsave;
+
+ curthread = _get_curthread();
+
+ if (!_kse_isthreaded()) {
+ SIGFILLSET(sigset);
+ __sys_sigprocmask(SIG_SETMASK, &sigset, &oldset);
+ ret = __sys_fork();
+ if (ret == 0)
+ /* Child */
+ __sys_sigprocmask(SIG_SETMASK, &curthread->sigmask,
+ NULL);
+ else
+ __sys_sigprocmask(SIG_SETMASK, &oldset, NULL);
+ return (ret);
+ }
+
+ /*
+ * Masks all signals until we reach a safe point in
+ * _kse_single_thread, and the signal masks will be
+ * restored in that function, for M:N thread, all
+ * signals were already masked in kernel atomically,
+ * we only need to do this for bound thread.
+ */
+ if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) {
+ SIGFILLSET(sigset);
+ __sys_sigprocmask(SIG_SETMASK, &sigset, &oldset);
+ }
+
+ _pthread_mutex_lock(&_thr_atfork_mutex);
+
+ /* Run down atfork prepare handlers. */
+ TAILQ_FOREACH_REVERSE(af, &_thr_atfork_list, atfork_head, qe) {
+ if (af->prepare != NULL)
+ af->prepare();
+ }
+
+ /* Fork a new process: */
+ if (_kse_isthreaded() != 0) {
+ _malloc_prefork();
+ }
+ if ((ret = __sys_fork()) == 0) {
+ /* Child process */
+ errsave = errno;
+
+ /* Kernel signal mask is restored in _kse_single_thread */
+ _kse_single_thread(curthread);
+
+ /* Run down atfork child handlers. */
+ TAILQ_FOREACH(af, &_thr_atfork_list, qe) {
+ if (af->child != NULL)
+ af->child();
+ }
+ _thr_mutex_reinit(&_thr_atfork_mutex);
+ } else {
+ if (_kse_isthreaded() != 0) {
+ _malloc_postfork();
+ }
+ errsave = errno;
+ if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) {
+ __sys_sigprocmask(SIG_SETMASK, &oldset, NULL);
+ }
+ /* Run down atfork parent handlers. */
+ TAILQ_FOREACH(af, &_thr_atfork_list, qe) {
+ if (af->parent != NULL)
+ af->parent();
+ }
+ _pthread_mutex_unlock(&_thr_atfork_mutex);
+ }
+ errno = errsave;
+
+ /* Return the process ID: */
+ return (ret);
+}
diff --git a/lib/libpthread/thread/thr_fsync.c b/lib/libpthread/thread/thr_fsync.c
new file mode 100644
index 0000000..fc6360a
--- /dev/null
+++ b/lib/libpthread/thread/thr_fsync.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <unistd.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__fsync);
+LT10_COMPAT_DEFAULT(fsync);
+
+__weak_reference(__fsync, fsync);
+
+int
+__fsync(int fd)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ _thr_cancel_enter(curthread);
+ ret = __sys_fsync(fd);
+ _thr_cancel_leave(curthread, 1);
+
+ return (ret);
+}
diff --git a/lib/libpthread/thread/thr_getprio.c b/lib/libpthread/thread/thr_getprio.c
new file mode 100644
index 0000000..875c1b3
--- /dev/null
+++ b/lib/libpthread/thread/thr_getprio.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <errno.h>
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_getprio);
+LT10_COMPAT_DEFAULT(pthread_getprio);
+
+__weak_reference(_pthread_getprio, pthread_getprio);
+
+int
+_pthread_getprio(pthread_t pthread)
+{
+ int policy, ret;
+ struct sched_param param;
+
+ if ((ret = _pthread_getschedparam(pthread, &policy, &param)) == 0)
+ ret = param.sched_priority;
+ else {
+ /* Invalid thread: */
+ errno = ret;
+ ret = -1;
+ }
+
+ /* Return the thread priority or an error status: */
+ return (ret);
+}
diff --git a/lib/libpthread/thread/thr_getschedparam.c b/lib/libpthread/thread/thr_getschedparam.c
new file mode 100644
index 0000000..dca342f
--- /dev/null
+++ b/lib/libpthread/thread/thr_getschedparam.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_getschedparam);
+LT10_COMPAT_DEFAULT(pthread_getschedparam);
+
+__weak_reference(_pthread_getschedparam, pthread_getschedparam);
+
+int
+_pthread_getschedparam(pthread_t pthread, int *policy,
+ struct sched_param *param)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret, tmp;
+
+ if ((param == NULL) || (policy == NULL))
+ /* Return an invalid argument error: */
+ ret = EINVAL;
+ else if (pthread == curthread) {
+ /*
+ * Avoid searching the thread list when it is the current
+ * thread.
+ */
+ THR_SCHED_LOCK(curthread, curthread);
+ param->sched_priority =
+ THR_BASE_PRIORITY(pthread->base_priority);
+ tmp = pthread->attr.sched_policy;
+ THR_SCHED_UNLOCK(curthread, curthread);
+ *policy = tmp;
+ ret = 0;
+ }
+ /* Find the thread in the list of active threads. */
+ else if ((ret = _thr_ref_add(curthread, pthread, /*include dead*/0))
+ == 0) {
+ THR_SCHED_LOCK(curthread, pthread);
+ param->sched_priority =
+ THR_BASE_PRIORITY(pthread->base_priority);
+ tmp = pthread->attr.sched_policy;
+ THR_SCHED_UNLOCK(curthread, pthread);
+ _thr_ref_delete(curthread, pthread);
+ *policy = tmp;
+ }
+ return (ret);
+}
diff --git a/lib/libpthread/thread/thr_info.c b/lib/libpthread/thread/thr_info.c
new file mode 100644
index 0000000..ab5320f
--- /dev/null
+++ b/lib/libpthread/thread/thr_info.c
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <errno.h>
+#include "thr_private.h"
+
+#ifndef NELEMENTS
+#define NELEMENTS(arr) (sizeof(arr) / sizeof(arr[0]))
+#endif
+
+LT10_COMPAT_PRIVATE(_pthread_set_name_np);
+LT10_COMPAT_DEFAULT(pthread_set_name_np);
+
+static void dump_thread(int fd, pthread_t pthread, int long_version);
+
+__weak_reference(_pthread_set_name_np, pthread_set_name_np);
+
+struct s_thread_info {
+ enum pthread_state state;
+ char *name;
+};
+
+/* Static variables: */
+static const struct s_thread_info thread_info[] = {
+ {PS_RUNNING , "Running"},
+ {PS_LOCKWAIT , "Waiting on an internal lock"},
+ {PS_MUTEX_WAIT , "Waiting on a mutex"},
+ {PS_COND_WAIT , "Waiting on a condition variable"},
+ {PS_SLEEP_WAIT , "Sleeping"},
+ {PS_SIGSUSPEND , "Suspended, waiting for a signal"},
+ {PS_SIGWAIT , "Waiting for a signal"},
+ {PS_JOIN , "Waiting to join"},
+ {PS_SUSPENDED , "Suspended"},
+ {PS_DEAD , "Dead"},
+ {PS_DEADLOCK , "Deadlocked"},
+ {PS_STATE_MAX , "Not a real state!"}
+};
+
+void
+_thread_dump_info(void)
+{
+ char s[512], tmpfile[128];
+ pthread_t pthread;
+ int fd, i;
+
+ for (i = 0; i < 100000; i++) {
+ snprintf(tmpfile, sizeof(tmpfile), "/tmp/pthread.dump.%u.%i",
+ getpid(), i);
+ /* Open the dump file for append and create it if necessary: */
+ if ((fd = __sys_open(tmpfile, O_RDWR | O_CREAT | O_EXCL,
+ 0666)) < 0) {
+ /* Can't open the dump file. */
+ if (errno == EEXIST)
+ continue;
+ /*
+ * We only need to continue in case of
+ * EEXIT error. Most other error
+ * codes means that we will fail all
+ * the times.
+ */
+ return;
+ } else {
+ break;
+ }
+ }
+ if (i==100000) {
+ /* all 100000 possibilities are in use :( */
+ return;
+ } else {
+ /* Dump the active threads. */
+ strcpy(s, "\n\n========\nACTIVE THREADS\n\n");
+ __sys_write(fd, s, strlen(s));
+
+ /* Enter a loop to report each thread in the global list: */
+ TAILQ_FOREACH(pthread, &_thread_list, tle) {
+ if (pthread->state != PS_DEAD)
+ dump_thread(fd, pthread, /*long_verson*/ 1);
+ }
+
+ /*
+ * Dump the ready threads.
+ * XXX - We can't easily do this because the run queues
+ * are per-KSEG.
+ */
+ strcpy(s, "\n\n========\nREADY THREADS - unimplemented\n\n");
+ __sys_write(fd, s, strlen(s));
+
+
+ /*
+ * Dump the waiting threads.
+ * XXX - We can't easily do this because the wait queues
+ * are per-KSEG.
+ */
+ strcpy(s, "\n\n========\nWAITING THREADS - unimplemented\n\n");
+ __sys_write(fd, s, strlen(s));
+
+ /* Close the dump file. */
+ __sys_close(fd);
+ }
+}
+
+static void
+dump_thread(int fd, pthread_t pthread, int long_version)
+{
+ struct pthread *curthread = _get_curthread();
+ char s[512];
+ int i;
+
+ /* Find the state: */
+ for (i = 0; i < NELEMENTS(thread_info) - 1; i++)
+ if (thread_info[i].state == pthread->state)
+ break;
+
+ /* Output a record for the thread: */
+ snprintf(s, sizeof(s),
+ "--------------------\n"
+ "Thread %p (%s), scope %s, prio %3d, blocked %s, state %s [%s:%d]\n",
+ pthread, (pthread->name == NULL) ? "" : pthread->name,
+ pthread->attr.flags & PTHREAD_SCOPE_SYSTEM ? "system" : "process",
+ pthread->active_priority, (pthread->blocked != 0) ? "yes" : "no",
+ thread_info[i].name, pthread->fname, pthread->lineno);
+ __sys_write(fd, s, strlen(s));
+
+ if (long_version != 0) {
+ /* Check if this is the running thread: */
+ if (pthread == curthread) {
+ /* Output a record for the running thread: */
+ strcpy(s, "This is the running thread\n");
+ __sys_write(fd, s, strlen(s));
+ }
+ /* Check if this is the initial thread: */
+ if (pthread == _thr_initial) {
+ /* Output a record for the initial thread: */
+ strcpy(s, "This is the initial thread\n");
+ __sys_write(fd, s, strlen(s));
+ }
+
+ /* Process according to thread state: */
+ switch (pthread->state) {
+ case PS_SIGWAIT:
+ snprintf(s, sizeof(s), "sigmask (hi) ");
+ __sys_write(fd, s, strlen(s));
+ for (i = _SIG_WORDS - 1; i >= 0; i--) {
+ snprintf(s, sizeof(s), "%08x ",
+ pthread->sigmask.__bits[i]);
+ __sys_write(fd, s, strlen(s));
+ }
+ snprintf(s, sizeof(s), "(lo)\n");
+ __sys_write(fd, s, strlen(s));
+
+ snprintf(s, sizeof(s), "waitset (hi) ");
+ __sys_write(fd, s, strlen(s));
+ for (i = _SIG_WORDS - 1; i >= 0; i--) {
+ snprintf(s, sizeof(s), "%08x ",
+ pthread->data.sigwait->waitset->__bits[i]);
+ __sys_write(fd, s, strlen(s));
+ }
+ snprintf(s, sizeof(s), "(lo)\n");
+ __sys_write(fd, s, strlen(s));
+ break;
+ /*
+ * Trap other states that are not explicitly
+ * coded to dump information:
+ */
+ default:
+ snprintf(s, sizeof(s), "sigmask (hi) ");
+ __sys_write(fd, s, strlen(s));
+ for (i = _SIG_WORDS - 1; i >= 0; i--) {
+ snprintf(s, sizeof(s), "%08x ",
+ pthread->sigmask.__bits[i]);
+ __sys_write(fd, s, strlen(s));
+ }
+ snprintf(s, sizeof(s), "(lo)\n");
+ __sys_write(fd, s, strlen(s));
+ break;
+ }
+ }
+}
+
+/* Set the thread name for debug: */
+void
+_pthread_set_name_np(pthread_t thread, char *name)
+{
+ /* Check if the caller has specified a valid thread: */
+ if (thread != NULL && thread->magic == THR_MAGIC) {
+ if (thread->name != NULL) {
+ /* Free space for previous name. */
+ free(thread->name);
+ }
+ thread->name = strdup(name);
+ }
+}
diff --git a/lib/libpthread/thread/thr_init.c b/lib/libpthread/thread/thr_init.c
new file mode 100644
index 0000000..35c4ee3
--- /dev/null
+++ b/lib/libpthread/thread/thr_init.c
@@ -0,0 +1,533 @@
+/*
+ * Copyright (c) 2003 Daniel M. Eischen <deischen@freebsd.org>
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/* Allocate space for global thread variables here: */
+#define GLOBAL_PTHREAD_PRIVATE
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/signalvar.h>
+#include <machine/reg.h>
+
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <sys/event.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+#include <sys/ttycom.h>
+#include <sys/wait.h>
+#include <sys/mman.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <pthread.h>
+#include <pthread_np.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 "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_libkse_debug);
+LT10_COMPAT_PRIVATE(_thread_activated);
+LT10_COMPAT_PRIVATE(_thread_active_threads);
+LT10_COMPAT_PRIVATE(_thread_list);
+
+int __pthread_cond_wait(pthread_cond_t *, pthread_mutex_t *);
+int __pthread_mutex_lock(pthread_mutex_t *);
+int __pthread_mutex_trylock(pthread_mutex_t *);
+void _thread_init_hack(void);
+extern int _thread_state_running;
+
+static void init_private(void);
+static void init_main_thread(struct pthread *thread);
+
+/*
+ * All weak references used within libc should be in this table.
+ * This is so that static libraries will work.
+ */
+static void *references[] = {
+ &_accept,
+ &_bind,
+ &_close,
+ &_connect,
+ &_dup,
+ &_dup2,
+ &_execve,
+ &_fcntl,
+ &_flock,
+ &_flockfile,
+ &_fstat,
+ &_fstatfs,
+ &_fsync,
+ &_funlockfile,
+ &_getdirentries,
+ &_getlogin,
+ &_getpeername,
+ &_getsockname,
+ &_getsockopt,
+ &_ioctl,
+ &_kevent,
+ &_listen,
+ &_nanosleep,
+ &_open,
+ &_pthread_getspecific,
+ &_pthread_key_create,
+ &_pthread_key_delete,
+ &_pthread_mutex_destroy,
+ &_pthread_mutex_init,
+ &_pthread_mutex_lock,
+ &_pthread_mutex_trylock,
+ &_pthread_mutex_unlock,
+ &_pthread_mutexattr_init,
+ &_pthread_mutexattr_destroy,
+ &_pthread_mutexattr_settype,
+ &_pthread_once,
+ &_pthread_setspecific,
+ &_read,
+ &_readv,
+ &_recvfrom,
+ &_recvmsg,
+ &_select,
+ &_sendmsg,
+ &_sendto,
+ &_setsockopt,
+ &_sigaction,
+ &_sigprocmask,
+ &_sigsuspend,
+ &_socket,
+ &_socketpair,
+ &_thread_init_hack,
+ &_wait4,
+ &_write,
+ &_writev
+};
+
+/*
+ * These are needed when linking statically. All references within
+ * libgcc (and in the future libc) to these routines are weak, but
+ * if they are not (strongly) referenced by the application or other
+ * libraries, then the actual functions will not be loaded.
+ */
+static void *libgcc_references[] = {
+ &_pthread_once,
+ &_pthread_key_create,
+ &_pthread_key_delete,
+ &_pthread_getspecific,
+ &_pthread_setspecific,
+ &_pthread_mutex_init,
+ &_pthread_mutex_destroy,
+ &_pthread_mutex_lock,
+ &_pthread_mutex_trylock,
+ &_pthread_mutex_unlock
+};
+
+#define DUAL_ENTRY(entry) \
+ (pthread_func_t)entry, (pthread_func_t)entry
+
+static pthread_func_t jmp_table[][2] = {
+ {DUAL_ENTRY(_pthread_atfork)}, /* PJT_ATFORK */
+ {DUAL_ENTRY(_pthread_attr_destroy)}, /* PJT_ATTR_DESTROY */
+ {DUAL_ENTRY(_pthread_attr_getdetachstate)}, /* PJT_ATTR_GETDETACHSTATE */
+ {DUAL_ENTRY(_pthread_attr_getguardsize)}, /* PJT_ATTR_GETGUARDSIZE */
+ {DUAL_ENTRY(_pthread_attr_getinheritsched)}, /* PJT_ATTR_GETINHERITSCHED */
+ {DUAL_ENTRY(_pthread_attr_getschedparam)}, /* PJT_ATTR_GETSCHEDPARAM */
+ {DUAL_ENTRY(_pthread_attr_getschedpolicy)}, /* PJT_ATTR_GETSCHEDPOLICY */
+ {DUAL_ENTRY(_pthread_attr_getscope)}, /* PJT_ATTR_GETSCOPE */
+ {DUAL_ENTRY(_pthread_attr_getstackaddr)}, /* PJT_ATTR_GETSTACKADDR */
+ {DUAL_ENTRY(_pthread_attr_getstacksize)}, /* PJT_ATTR_GETSTACKSIZE */
+ {DUAL_ENTRY(_pthread_attr_init)}, /* PJT_ATTR_INIT */
+ {DUAL_ENTRY(_pthread_attr_setdetachstate)}, /* PJT_ATTR_SETDETACHSTATE */
+ {DUAL_ENTRY(_pthread_attr_setguardsize)}, /* PJT_ATTR_SETGUARDSIZE */
+ {DUAL_ENTRY(_pthread_attr_setinheritsched)}, /* PJT_ATTR_SETINHERITSCHED */
+ {DUAL_ENTRY(_pthread_attr_setschedparam)}, /* PJT_ATTR_SETSCHEDPARAM */
+ {DUAL_ENTRY(_pthread_attr_setschedpolicy)}, /* PJT_ATTR_SETSCHEDPOLICY */
+ {DUAL_ENTRY(_pthread_attr_setscope)}, /* PJT_ATTR_SETSCOPE */
+ {DUAL_ENTRY(_pthread_attr_setstackaddr)}, /* PJT_ATTR_SETSTACKADDR */
+ {DUAL_ENTRY(_pthread_attr_setstacksize)}, /* PJT_ATTR_SETSTACKSIZE */
+ {DUAL_ENTRY(_pthread_cancel)}, /* PJT_CANCEL */
+ {DUAL_ENTRY(_pthread_cleanup_pop)}, /* PJT_CLEANUP_POP */
+ {DUAL_ENTRY(_pthread_cleanup_push)}, /* PJT_CLEANUP_PUSH */
+ {DUAL_ENTRY(_pthread_cond_broadcast)}, /* PJT_COND_BROADCAST */
+ {DUAL_ENTRY(_pthread_cond_destroy)}, /* PJT_COND_DESTROY */
+ {DUAL_ENTRY(_pthread_cond_init)}, /* PJT_COND_INIT */
+ {DUAL_ENTRY(_pthread_cond_signal)}, /* PJT_COND_SIGNAL */
+ {DUAL_ENTRY(_pthread_cond_timedwait)}, /* PJT_COND_TIMEDWAIT */
+ {(pthread_func_t)__pthread_cond_wait,
+ (pthread_func_t)_pthread_cond_wait}, /* PJT_COND_WAIT */
+ {DUAL_ENTRY(_pthread_detach)}, /* PJT_DETACH */
+ {DUAL_ENTRY(_pthread_equal)}, /* PJT_EQUAL */
+ {DUAL_ENTRY(_pthread_exit)}, /* PJT_EXIT */
+ {DUAL_ENTRY(_pthread_getspecific)}, /* PJT_GETSPECIFIC */
+ {DUAL_ENTRY(_pthread_join)}, /* PJT_JOIN */
+ {DUAL_ENTRY(_pthread_key_create)}, /* PJT_KEY_CREATE */
+ {DUAL_ENTRY(_pthread_key_delete)}, /* PJT_KEY_DELETE*/
+ {DUAL_ENTRY(_pthread_kill)}, /* PJT_KILL */
+ {DUAL_ENTRY(_pthread_main_np)}, /* PJT_MAIN_NP */
+ {DUAL_ENTRY(_pthread_mutexattr_destroy)}, /* PJT_MUTEXATTR_DESTROY */
+ {DUAL_ENTRY(_pthread_mutexattr_init)}, /* PJT_MUTEXATTR_INIT */
+ {DUAL_ENTRY(_pthread_mutexattr_settype)}, /* PJT_MUTEXATTR_SETTYPE */
+ {DUAL_ENTRY(_pthread_mutex_destroy)}, /* PJT_MUTEX_DESTROY */
+ {DUAL_ENTRY(_pthread_mutex_init)}, /* PJT_MUTEX_INIT */
+ {(pthread_func_t)__pthread_mutex_lock,
+ (pthread_func_t)_pthread_mutex_lock}, /* PJT_MUTEX_LOCK */
+ {(pthread_func_t)__pthread_mutex_trylock,
+ (pthread_func_t)_pthread_mutex_trylock},/* PJT_MUTEX_TRYLOCK */
+ {DUAL_ENTRY(_pthread_mutex_unlock)}, /* PJT_MUTEX_UNLOCK */
+ {DUAL_ENTRY(_pthread_once)}, /* PJT_ONCE */
+ {DUAL_ENTRY(_pthread_rwlock_destroy)}, /* PJT_RWLOCK_DESTROY */
+ {DUAL_ENTRY(_pthread_rwlock_init)}, /* PJT_RWLOCK_INIT */
+ {DUAL_ENTRY(_pthread_rwlock_rdlock)}, /* PJT_RWLOCK_RDLOCK */
+ {DUAL_ENTRY(_pthread_rwlock_tryrdlock)},/* PJT_RWLOCK_TRYRDLOCK */
+ {DUAL_ENTRY(_pthread_rwlock_trywrlock)},/* PJT_RWLOCK_TRYWRLOCK */
+ {DUAL_ENTRY(_pthread_rwlock_unlock)}, /* PJT_RWLOCK_UNLOCK */
+ {DUAL_ENTRY(_pthread_rwlock_wrlock)}, /* PJT_RWLOCK_WRLOCK */
+ {DUAL_ENTRY(_pthread_self)}, /* PJT_SELF */
+ {DUAL_ENTRY(_pthread_setcancelstate)}, /* PJT_SETCANCELSTATE */
+ {DUAL_ENTRY(_pthread_setcanceltype)}, /* PJT_SETCANCELTYPE */
+ {DUAL_ENTRY(_pthread_setspecific)}, /* PJT_SETSPECIFIC */
+ {DUAL_ENTRY(_pthread_sigmask)}, /* PJT_SIGMASK */
+ {DUAL_ENTRY(_pthread_testcancel)} /* PJT_TESTCANCEL */
+};
+
+static int init_once = 0;
+
+/*
+ * Threaded process initialization.
+ *
+ * This is only called under two conditions:
+ *
+ * 1) Some thread routines have detected that the library hasn't yet
+ * been initialized (_thr_initial == NULL && curthread == NULL), or
+ *
+ * 2) An explicit call to reinitialize after a fork (indicated
+ * by curthread != NULL)
+ */
+void
+_libpthread_init(struct pthread *curthread)
+{
+ int fd;
+
+ /* Check if this function has already been called: */
+ if ((_thr_initial != NULL) && (curthread == NULL))
+ /* Only initialize the threaded application once. */
+ return;
+
+ /*
+ * Make gcc quiescent about {,libgcc_}references not being
+ * referenced:
+ */
+ if ((references[0] == NULL) || (libgcc_references[0] == NULL))
+ PANIC("Failed loading mandatory references in _thread_init");
+
+ /* Pull debug symbols in for static binary */
+ _thread_state_running = PS_RUNNING;
+
+ /*
+ * Check the size of the jump table to make sure it is preset
+ * with the correct number of entries.
+ */
+ if (sizeof(jmp_table) != (sizeof(pthread_func_t) * PJT_MAX * 2))
+ PANIC("Thread jump table not properly initialized");
+ memcpy(__thr_jtable, jmp_table, sizeof(jmp_table));
+
+ /*
+ * Check for the special case of this process running as
+ * or in place of init as pid = 1:
+ */
+ if ((_thr_pid = getpid()) == 1) {
+ /*
+ * Setup a new session for this process which is
+ * assumed to be running as root.
+ */
+ if (setsid() == -1)
+ PANIC("Can't set session ID");
+ if (revoke(_PATH_CONSOLE) != 0)
+ PANIC("Can't revoke console");
+ if ((fd = __sys_open(_PATH_CONSOLE, O_RDWR)) < 0)
+ PANIC("Can't open console");
+ if (setlogin("root") == -1)
+ PANIC("Can't set login to root");
+ if (__sys_ioctl(fd, TIOCSCTTY, (char *) NULL) == -1)
+ PANIC("Can't set controlling terminal");
+ }
+
+ /* Initialize pthread private data. */
+ init_private();
+ _kse_init();
+
+ /* Initialize the initial kse and kseg. */
+ _kse_initial = _kse_alloc(NULL, _thread_scope_system > 0);
+ if (_kse_initial == NULL)
+ PANIC("Can't allocate initial kse.");
+ _kse_initial->k_kseg = _kseg_alloc(NULL);
+ if (_kse_initial->k_kseg == NULL)
+ PANIC("Can't allocate initial kseg.");
+ _kse_initial->k_kseg->kg_flags |= KGF_SINGLE_THREAD;
+ _kse_initial->k_schedq = &_kse_initial->k_kseg->kg_schedq;
+
+ TAILQ_INSERT_TAIL(&_kse_initial->k_kseg->kg_kseq, _kse_initial, k_kgqe);
+ _kse_initial->k_kseg->kg_ksecount = 1;
+
+ /* Set the initial thread. */
+ if (curthread == NULL) {
+ /* Create and initialize the initial thread. */
+ curthread = _thr_alloc(NULL);
+ if (curthread == NULL)
+ PANIC("Can't allocate initial thread");
+ _thr_initial = curthread;
+ init_main_thread(curthread);
+ } else {
+ /*
+ * The initial thread is the current thread. It is
+ * assumed that the current thread is already initialized
+ * because it is left over from a fork().
+ */
+ _thr_initial = curthread;
+ }
+ _kse_initial->k_kseg->kg_threadcount = 0;
+ _thr_initial->kse = _kse_initial;
+ _thr_initial->kseg = _kse_initial->k_kseg;
+ _thr_initial->active = 1;
+
+ /*
+ * Add the thread to the thread list and to the KSEG's thread
+ * queue.
+ */
+ THR_LIST_ADD(_thr_initial);
+ KSEG_THRQ_ADD(_kse_initial->k_kseg, _thr_initial);
+
+ /* Setup the KSE/thread specific data for the current KSE/thread. */
+ _thr_initial->kse->k_curthread = _thr_initial;
+ _kcb_set(_thr_initial->kse->k_kcb);
+ _tcb_set(_thr_initial->kse->k_kcb, _thr_initial->tcb);
+ _thr_initial->kse->k_flags |= KF_INITIALIZED;
+
+ _thr_signal_init();
+ _kse_critical_leave(&_thr_initial->tcb->tcb_tmbx);
+ /*
+ * activate threaded mode as soon as possible if we are
+ * being debugged
+ */
+ if (_libkse_debug)
+ _kse_setthreaded(1);
+}
+
+/*
+ * This function and pthread_create() do a lot of the same things.
+ * It'd be nice to consolidate the common stuff in one place.
+ */
+static void
+init_main_thread(struct pthread *thread)
+{
+ /* Setup the thread attributes. */
+ thread->attr = _pthread_attr_default;
+ thread->attr.flags |= PTHREAD_SCOPE_SYSTEM;
+ /*
+ * Set up the thread stack.
+ *
+ * Create a red zone below the main stack. All other stacks
+ * are constrained to a maximum size by the parameters
+ * passed to mmap(), but this stack is only limited by
+ * resource limits, so this stack needs an explicitly mapped
+ * red zone to protect the thread stack that is just beyond.
+ */
+ if (mmap((void *)_usrstack - _thr_stack_initial -
+ _thr_guard_default, _thr_guard_default, 0, MAP_ANON,
+ -1, 0) == MAP_FAILED)
+ PANIC("Cannot allocate red zone for initial thread");
+
+ /*
+ * Mark the stack as an application supplied stack so that it
+ * isn't deallocated.
+ *
+ * XXX - I'm not sure it would hurt anything to deallocate
+ * the main thread stack because deallocation doesn't
+ * actually free() it; it just puts it in the free
+ * stack queue for later reuse.
+ */
+ thread->attr.stackaddr_attr = (void *)_usrstack - _thr_stack_initial;
+ thread->attr.stacksize_attr = _thr_stack_initial;
+ thread->attr.guardsize_attr = _thr_guard_default;
+ thread->attr.flags |= THR_STACK_USER;
+
+ /*
+ * Write a magic value to the thread structure
+ * to help identify valid ones:
+ */
+ thread->magic = THR_MAGIC;
+
+ thread->slice_usec = -1;
+ thread->cancelflags = PTHREAD_CANCEL_ENABLE | PTHREAD_CANCEL_DEFERRED;
+ thread->name = strdup("initial thread");
+
+ /* Initialize the thread for signals: */
+ SIGEMPTYSET(thread->sigmask);
+
+ /*
+ * Set up the thread mailbox. The threads saved context
+ * is also in the mailbox.
+ */
+ thread->tcb->tcb_tmbx.tm_udata = thread;
+ thread->tcb->tcb_tmbx.tm_context.uc_stack.ss_size =
+ thread->attr.stacksize_attr;
+ thread->tcb->tcb_tmbx.tm_context.uc_stack.ss_sp =
+ thread->attr.stackaddr_attr;
+
+ /* Default the priority of the initial thread: */
+ thread->base_priority = THR_DEFAULT_PRIORITY;
+ thread->active_priority = THR_DEFAULT_PRIORITY;
+ thread->inherited_priority = 0;
+
+ /* Initialize the mutex queue: */
+ TAILQ_INIT(&thread->mutexq);
+
+ /* Initialize hooks in the thread structure: */
+ thread->specific = NULL;
+ thread->cleanup = NULL;
+ thread->flags = 0;
+ thread->sigbackout = NULL;
+ thread->continuation = NULL;
+
+ thread->state = PS_RUNNING;
+ thread->uniqueid = 0;
+}
+
+static void
+init_private(void)
+{
+ struct clockinfo clockinfo;
+ size_t len;
+ int mib[2];
+
+ /*
+ * Avoid reinitializing some things if they don't need to be,
+ * e.g. after a fork().
+ */
+ if (init_once == 0) {
+ /* Find the stack top */
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_USRSTACK;
+ len = sizeof (_usrstack);
+ if (sysctl(mib, 2, &_usrstack, &len, NULL, 0) == -1)
+ PANIC("Cannot get kern.usrstack from sysctl");
+ /* Get the kernel clockrate: */
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_CLOCKRATE;
+ len = sizeof (struct clockinfo);
+ if (sysctl(mib, 2, &clockinfo, &len, NULL, 0) == 0)
+ _clock_res_usec = 1000000 / clockinfo.stathz;
+ else
+ _clock_res_usec = CLOCK_RES_USEC;
+
+ _thr_page_size = getpagesize();
+ _thr_guard_default = _thr_page_size;
+ if (sizeof(void *) == 8) {
+ _thr_stack_default = THR_STACK64_DEFAULT;
+ _thr_stack_initial = THR_STACK64_INITIAL;
+ }
+ else {
+ _thr_stack_default = THR_STACK32_DEFAULT;
+ _thr_stack_initial = THR_STACK32_INITIAL;
+ }
+ _pthread_attr_default.guardsize_attr = _thr_guard_default;
+ _pthread_attr_default.stacksize_attr = _thr_stack_default;
+ TAILQ_INIT(&_thr_atfork_list);
+ init_once = 1; /* Don't do this again. */
+ } else {
+ /*
+ * Destroy the locks before creating them. We don't
+ * know what state they are in so it is better to just
+ * recreate them.
+ */
+ _lock_destroy(&_thread_signal_lock);
+ _lock_destroy(&_mutex_static_lock);
+ _lock_destroy(&_rwlock_static_lock);
+ _lock_destroy(&_keytable_lock);
+ }
+
+ /* Initialize everything else. */
+ TAILQ_INIT(&_thread_list);
+ TAILQ_INIT(&_thread_gc_list);
+ _pthread_mutex_init(&_thr_atfork_mutex, NULL);
+
+ /*
+ * Initialize the lock for temporary installation of signal
+ * handlers (to support sigwait() semantics) and for the
+ * process signal mask and pending signal sets.
+ */
+ if (_lock_init(&_thread_signal_lock, LCK_ADAPTIVE,
+ _kse_lock_wait, _kse_lock_wakeup) != 0)
+ PANIC("Cannot initialize _thread_signal_lock");
+ if (_lock_init(&_mutex_static_lock, LCK_ADAPTIVE,
+ _thr_lock_wait, _thr_lock_wakeup) != 0)
+ PANIC("Cannot initialize mutex static init lock");
+ if (_lock_init(&_rwlock_static_lock, LCK_ADAPTIVE,
+ _thr_lock_wait, _thr_lock_wakeup) != 0)
+ PANIC("Cannot initialize rwlock static init lock");
+ if (_lock_init(&_keytable_lock, LCK_ADAPTIVE,
+ _thr_lock_wait, _thr_lock_wakeup) != 0)
+ PANIC("Cannot initialize thread specific keytable lock");
+ _thr_spinlock_init();
+
+ /* Clear pending signals and get the process signal mask. */
+ SIGEMPTYSET(_thr_proc_sigpending);
+
+ /* Are we in M:N mode (default) or 1:1 mode? */
+#ifdef SYSTEM_SCOPE_ONLY
+ _thread_scope_system = 1;
+#else
+ if (getenv("LIBPTHREAD_SYSTEM_SCOPE") != NULL)
+ _thread_scope_system = 1;
+ else if (getenv("LIBPTHREAD_PROCESS_SCOPE") != NULL)
+ _thread_scope_system = -1;
+#endif
+ if (getenv("LIBPTHREAD_DEBUG") != NULL)
+ _thr_debug_flags |= DBG_INFO_DUMP;
+
+ /*
+ * _thread_list_lock and _kse_count are initialized
+ * by _kse_init()
+ */
+}
diff --git a/lib/libpthread/thread/thr_join.c b/lib/libpthread/thread/thr_join.c
new file mode 100644
index 0000000..1a3452e
--- /dev/null
+++ b/lib/libpthread/thread/thr_join.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_join);
+LT10_COMPAT_DEFAULT(pthread_join);
+
+__weak_reference(_pthread_join, pthread_join);
+
+int
+_pthread_join(pthread_t pthread, void **thread_return)
+{
+ struct pthread *curthread = _get_curthread();
+ void *tmp;
+ kse_critical_t crit;
+ int ret = 0;
+
+ _thr_cancel_enter(curthread);
+
+ /* Check if the caller has specified an invalid thread: */
+ if (pthread == NULL || pthread->magic != THR_MAGIC) {
+ /* Invalid thread: */
+ _thr_cancel_leave(curthread, 1);
+ return (EINVAL);
+ }
+
+ /* Check if the caller has specified itself: */
+ if (pthread == curthread) {
+ /* Avoid a deadlock condition: */
+ _thr_cancel_leave(curthread, 1);
+ return (EDEADLK);
+ }
+
+ /*
+ * Find the thread in the list of active threads or in the
+ * list of dead threads:
+ */
+ if ((ret = _thr_ref_add(curthread, pthread, /*include dead*/1)) != 0) {
+ /* Return an error: */
+ _thr_cancel_leave(curthread, 1);
+ return (ESRCH);
+ }
+
+ THR_SCHED_LOCK(curthread, pthread);
+ /* Check if this thread has been detached: */
+ if ((pthread->attr.flags & PTHREAD_DETACHED) != 0) {
+ THR_SCHED_UNLOCK(curthread, pthread);
+ /* Remove the reference and return an error: */
+ _thr_ref_delete(curthread, pthread);
+ ret = ESRCH;
+ } else {
+ /* Lock the target thread while checking its state. */
+ if (pthread->state == PS_DEAD) {
+ /* Return the thread's return value: */
+ tmp = pthread->ret;
+
+ /* Detach the thread. */
+ pthread->attr.flags |= PTHREAD_DETACHED;
+
+ /* Unlock the thread. */
+ THR_SCHED_UNLOCK(curthread, pthread);
+
+ /*
+ * Remove the thread from the list of active
+ * threads and add it to the GC list.
+ */
+ crit = _kse_critical_enter();
+ KSE_LOCK_ACQUIRE(curthread->kse, &_thread_list_lock);
+ THR_LIST_REMOVE(pthread);
+ THR_GCLIST_ADD(pthread);
+ KSE_LOCK_RELEASE(curthread->kse, &_thread_list_lock);
+ _kse_critical_leave(crit);
+
+ /* Remove the reference. */
+ _thr_ref_delete(curthread, pthread);
+ if (thread_return != NULL)
+ *thread_return = tmp;
+ }
+ else if (pthread->joiner != NULL) {
+ /* Unlock the thread and remove the reference. */
+ THR_SCHED_UNLOCK(curthread, pthread);
+ _thr_ref_delete(curthread, pthread);
+
+ /* Multiple joiners are not supported. */
+ ret = ENOTSUP;
+ }
+ else {
+ /* Set the running thread to be the joiner: */
+ pthread->joiner = curthread;
+
+ /* Keep track of which thread we're joining to: */
+ curthread->join_status.thread = pthread;
+
+ /* Unlock the thread and remove the reference. */
+ THR_SCHED_UNLOCK(curthread, pthread);
+ _thr_ref_delete(curthread, pthread);
+
+ THR_SCHED_LOCK(curthread, curthread);
+ while (curthread->join_status.thread == pthread) {
+ THR_SET_STATE(curthread, PS_JOIN);
+ THR_SCHED_UNLOCK(curthread, curthread);
+ /* Schedule the next thread: */
+ _thr_sched_switch(curthread);
+ THR_SCHED_LOCK(curthread, curthread);
+ }
+ THR_SCHED_UNLOCK(curthread, curthread);
+
+ if ((curthread->cancelflags & THR_CANCELLING) &&
+ !(curthread->cancelflags & PTHREAD_CANCEL_DISABLE)) {
+ if (_thr_ref_add(curthread, pthread, 1) == 0) {
+ THR_SCHED_LOCK(curthread, pthread);
+ pthread->joiner = NULL;
+ THR_SCHED_UNLOCK(curthread, pthread);
+ _thr_ref_delete(curthread, pthread);
+ }
+ pthread_exit(PTHREAD_CANCELED);
+ }
+
+ /*
+ * The thread return value and error are set by the
+ * thread we're joining to when it exits or detaches:
+ */
+ ret = curthread->join_status.error;
+ if ((ret == 0) && (thread_return != NULL))
+ *thread_return = curthread->join_status.ret;
+ }
+ }
+ _thr_cancel_leave(curthread, 1);
+
+ /* Return the completion status: */
+ return (ret);
+}
diff --git a/lib/libpthread/thread/thr_kern.c b/lib/libpthread/thread/thr_kern.c
new file mode 100644
index 0000000..f1b28c0
--- /dev/null
+++ b/lib/libpthread/thread/thr_kern.c
@@ -0,0 +1,2551 @@
+/*
+ * Copyright (C) 2003 Daniel M. Eischen <deischen@freebsd.org>
+ * Copyright (C) 2002 Jonathon Mini <mini@freebsd.org>
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 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/kse.h>
+#include <sys/ptrace.h>
+#include <sys/signalvar.h>
+#include <sys/queue.h>
+#include <machine/atomic.h>
+#include <machine/sigframe.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <ucontext.h>
+#include <unistd.h>
+
+#include "atomic_ops.h"
+#include "thr_private.h"
+#include "libc_private.h"
+#ifdef NOTYET
+#include "spinlock.h"
+#endif
+
+/* #define DEBUG_THREAD_KERN */
+#ifdef DEBUG_THREAD_KERN
+#define DBG_MSG stdout_debug
+#else
+#define DBG_MSG(x...)
+#endif
+
+/*
+ * Define a high water mark for the maximum number of threads that
+ * will be cached. Once this level is reached, any extra threads
+ * will be free()'d.
+ */
+#define MAX_CACHED_THREADS 100
+/*
+ * Define high water marks for the maximum number of KSEs and KSE groups
+ * that will be cached. Because we support 1:1 threading, there could have
+ * same number of KSEs and KSE groups as threads. Once these levels are
+ * reached, any extra KSE and KSE groups will be free()'d.
+ */
+#define MAX_CACHED_KSES ((_thread_scope_system <= 0) ? 50 : 100)
+#define MAX_CACHED_KSEGS ((_thread_scope_system <= 0) ? 50 : 100)
+
+#define KSE_SET_MBOX(kse, thrd) \
+ (kse)->k_kcb->kcb_kmbx.km_curthread = &(thrd)->tcb->tcb_tmbx
+
+#define KSE_SET_EXITED(kse) (kse)->k_flags |= KF_EXITED
+
+/*
+ * Macros for manipulating the run queues. The priority queue
+ * routines use the thread's pqe link and also handle the setting
+ * and clearing of the thread's THR_FLAGS_IN_RUNQ flag.
+ */
+#define KSE_RUNQ_INSERT_HEAD(kse, thrd) \
+ _pq_insert_head(&(kse)->k_schedq->sq_runq, thrd)
+#define KSE_RUNQ_INSERT_TAIL(kse, thrd) \
+ _pq_insert_tail(&(kse)->k_schedq->sq_runq, thrd)
+#define KSE_RUNQ_REMOVE(kse, thrd) \
+ _pq_remove(&(kse)->k_schedq->sq_runq, thrd)
+#define KSE_RUNQ_FIRST(kse) \
+ ((_libkse_debug == 0) ? \
+ _pq_first(&(kse)->k_schedq->sq_runq) : \
+ _pq_first_debug(&(kse)->k_schedq->sq_runq))
+
+#define KSE_RUNQ_THREADS(kse) ((kse)->k_schedq->sq_runq.pq_threads)
+
+#define THR_NEED_CANCEL(thrd) \
+ (((thrd)->cancelflags & THR_CANCELLING) != 0 && \
+ ((thrd)->cancelflags & PTHREAD_CANCEL_DISABLE) == 0 && \
+ (((thrd)->cancelflags & THR_AT_CANCEL_POINT) != 0 || \
+ ((thrd)->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0))
+
+#define THR_NEED_ASYNC_CANCEL(thrd) \
+ (((thrd)->cancelflags & THR_CANCELLING) != 0 && \
+ ((thrd)->cancelflags & PTHREAD_CANCEL_DISABLE) == 0 && \
+ (((thrd)->cancelflags & THR_AT_CANCEL_POINT) == 0 && \
+ ((thrd)->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0))
+
+/*
+ * We've got to keep track of everything that is allocated, not only
+ * to have a speedy free list, but also so they can be deallocated
+ * after a fork().
+ */
+static TAILQ_HEAD(, kse) active_kseq;
+static TAILQ_HEAD(, kse) free_kseq;
+static TAILQ_HEAD(, kse_group) free_kse_groupq;
+static TAILQ_HEAD(, kse_group) active_kse_groupq;
+static TAILQ_HEAD(, kse_group) gc_ksegq;
+static struct lock kse_lock; /* also used for kseg queue */
+static int free_kse_count = 0;
+static int free_kseg_count = 0;
+static TAILQ_HEAD(, pthread) free_threadq;
+static struct lock thread_lock;
+static int free_thread_count = 0;
+static int inited = 0;
+static int active_kse_count = 0;
+static int active_kseg_count = 0;
+static u_int64_t next_uniqueid = 1;
+
+LIST_HEAD(thread_hash_head, pthread);
+#define THREAD_HASH_QUEUES 127
+static struct thread_hash_head thr_hashtable[THREAD_HASH_QUEUES];
+#define THREAD_HASH(thrd) ((unsigned long)thrd % THREAD_HASH_QUEUES)
+
+/* Lock for thread tcb constructor/destructor */
+static pthread_mutex_t _tcb_mutex;
+
+#ifdef DEBUG_THREAD_KERN
+static void dump_queues(struct kse *curkse);
+#endif
+static void kse_check_completed(struct kse *kse);
+static void kse_check_waitq(struct kse *kse);
+static void kse_fini(struct kse *curkse);
+static void kse_reinit(struct kse *kse, int sys_scope);
+static void kse_sched_multi(struct kse_mailbox *kmbx);
+static void kse_sched_single(struct kse_mailbox *kmbx);
+static void kse_switchout_thread(struct kse *kse, struct pthread *thread);
+static void kse_wait(struct kse *kse, struct pthread *td_wait, int sigseq);
+static void kse_free_unlocked(struct kse *kse);
+static void kse_destroy(struct kse *kse);
+static void kseg_free_unlocked(struct kse_group *kseg);
+static void kseg_init(struct kse_group *kseg);
+static void kseg_reinit(struct kse_group *kseg);
+static void kseg_destroy(struct kse_group *kseg);
+static void kse_waitq_insert(struct pthread *thread);
+static void kse_wakeup_multi(struct kse *curkse);
+static struct kse_mailbox *kse_wakeup_one(struct pthread *thread);
+static void thr_cleanup(struct kse *kse, struct pthread *curthread);
+static void thr_link(struct pthread *thread);
+static void thr_resume_wrapper(int sig, siginfo_t *, ucontext_t *);
+static void thr_resume_check(struct pthread *curthread, ucontext_t *ucp);
+static int thr_timedout(struct pthread *thread, struct timespec *curtime);
+static void thr_unlink(struct pthread *thread);
+static void thr_destroy(struct pthread *curthread, struct pthread *thread);
+static void thread_gc(struct pthread *thread);
+static void kse_gc(struct pthread *thread);
+static void kseg_gc(struct pthread *thread);
+
+static void __inline
+thr_accounting(struct pthread *thread)
+{
+ if ((thread->slice_usec != -1) &&
+ (thread->slice_usec <= TIMESLICE_USEC) &&
+ (thread->attr.sched_policy != SCHED_FIFO)) {
+ thread->slice_usec += (thread->tcb->tcb_tmbx.tm_uticks
+ + thread->tcb->tcb_tmbx.tm_sticks) * _clock_res_usec;
+ /* Check for time quantum exceeded: */
+ if (thread->slice_usec > TIMESLICE_USEC)
+ thread->slice_usec = -1;
+ }
+ thread->tcb->tcb_tmbx.tm_uticks = 0;
+ thread->tcb->tcb_tmbx.tm_sticks = 0;
+}
+
+/*
+ * This is called after a fork().
+ * No locks need to be taken here since we are guaranteed to be
+ * single threaded.
+ *
+ * XXX
+ * POSIX says for threaded process, fork() function is used
+ * only to run new programs, and the effects of calling functions
+ * that require certain resources between the call to fork() and
+ * the call to an exec function are undefined.
+ *
+ * It is not safe to free memory after fork(), because these data
+ * structures may be in inconsistent state.
+ */
+void
+_kse_single_thread(struct pthread *curthread)
+{
+#ifdef NOTYET
+ struct kse *kse;
+ struct kse_group *kseg;
+ struct pthread *thread;
+
+ _thr_spinlock_init();
+ *__malloc_lock = (spinlock_t)_SPINLOCK_INITIALIZER;
+ if (__isthreaded) {
+ _thr_rtld_fini();
+ _thr_signal_deinit();
+ }
+ __isthreaded = 0;
+ /*
+ * Restore signal mask early, so any memory problems could
+ * dump core.
+ */
+ __sys_sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL);
+ _thread_active_threads = 1;
+
+ /*
+ * Enter a loop to remove and free all threads other than
+ * the running thread from the active thread list:
+ */
+ while ((thread = TAILQ_FIRST(&_thread_list)) != NULL) {
+ THR_GCLIST_REMOVE(thread);
+ /*
+ * Remove this thread from the list (the current
+ * thread will be removed but re-added by libpthread
+ * initialization.
+ */
+ TAILQ_REMOVE(&_thread_list, thread, tle);
+ /* Make sure this isn't the running thread: */
+ if (thread != curthread) {
+ _thr_stack_free(&thread->attr);
+ if (thread->specific != NULL)
+ free(thread->specific);
+ thr_destroy(curthread, thread);
+ }
+ }
+
+ TAILQ_INIT(&curthread->mutexq); /* initialize mutex queue */
+ curthread->joiner = NULL; /* no joining threads yet */
+ curthread->refcount = 0;
+ SIGEMPTYSET(curthread->sigpend); /* clear pending signals */
+
+ /* Don't free thread-specific data as the caller may require it */
+
+ /* Free the free KSEs: */
+ while ((kse = TAILQ_FIRST(&free_kseq)) != NULL) {
+ TAILQ_REMOVE(&free_kseq, kse, k_qe);
+ kse_destroy(kse);
+ }
+ free_kse_count = 0;
+
+ /* Free the active KSEs: */
+ while ((kse = TAILQ_FIRST(&active_kseq)) != NULL) {
+ TAILQ_REMOVE(&active_kseq, kse, k_qe);
+ kse_destroy(kse);
+ }
+ active_kse_count = 0;
+
+ /* Free the free KSEGs: */
+ while ((kseg = TAILQ_FIRST(&free_kse_groupq)) != NULL) {
+ TAILQ_REMOVE(&free_kse_groupq, kseg, kg_qe);
+ kseg_destroy(kseg);
+ }
+ free_kseg_count = 0;
+
+ /* Free the active KSEGs: */
+ while ((kseg = TAILQ_FIRST(&active_kse_groupq)) != NULL) {
+ TAILQ_REMOVE(&active_kse_groupq, kseg, kg_qe);
+ kseg_destroy(kseg);
+ }
+ active_kseg_count = 0;
+
+ /* Free the free threads. */
+ while ((thread = TAILQ_FIRST(&free_threadq)) != NULL) {
+ TAILQ_REMOVE(&free_threadq, thread, tle);
+ thr_destroy(curthread, thread);
+ }
+ free_thread_count = 0;
+
+ /* Free the to-be-gc'd threads. */
+ while ((thread = TAILQ_FIRST(&_thread_gc_list)) != NULL) {
+ TAILQ_REMOVE(&_thread_gc_list, thread, gcle);
+ thr_destroy(curthread, thread);
+ }
+ TAILQ_INIT(&gc_ksegq);
+ _gc_count = 0;
+
+ if (inited != 0) {
+ /*
+ * Destroy these locks; they'll be recreated to assure they
+ * are in the unlocked state.
+ */
+ _lock_destroy(&kse_lock);
+ _lock_destroy(&thread_lock);
+ _lock_destroy(&_thread_list_lock);
+ inited = 0;
+ }
+
+ /*
+ * After a fork(), the leftover thread goes back to being
+ * scope process.
+ */
+ curthread->attr.flags &= ~PTHREAD_SCOPE_SYSTEM;
+ curthread->attr.flags |= PTHREAD_SCOPE_PROCESS;
+
+ /* We're no longer part of any lists */
+ curthread->tlflags = 0;
+
+ /*
+ * After a fork, we are still operating on the thread's original
+ * stack. Don't clear the THR_FLAGS_USER from the thread's
+ * attribute flags.
+ */
+
+ /* Initialize the threads library. */
+ curthread->kse = NULL;
+ curthread->kseg = NULL;
+ _kse_initial = NULL;
+ _libpthread_init(curthread);
+#else
+ int i;
+
+ /* Reset the current thread and KSE lock data. */
+ for (i = 0; i < curthread->locklevel; i++) {
+ _lockuser_reinit(&curthread->lockusers[i], (void *)curthread);
+ }
+ curthread->locklevel = 0;
+ for (i = 0; i < curthread->kse->k_locklevel; i++) {
+ _lockuser_reinit(&curthread->kse->k_lockusers[i],
+ (void *)curthread->kse);
+ _LCK_SET_PRIVATE2(&curthread->kse->k_lockusers[i], NULL);
+ }
+ curthread->kse->k_locklevel = 0;
+ _thr_spinlock_init();
+ if (__isthreaded) {
+ _thr_rtld_fini();
+ _thr_signal_deinit();
+ }
+ __isthreaded = 0;
+ curthread->kse->k_kcb->kcb_kmbx.km_curthread = NULL;
+ curthread->attr.flags |= PTHREAD_SCOPE_SYSTEM;
+
+ /* After a fork(), there child should have no pending signals. */
+ sigemptyset(&curthread->sigpend);
+
+ /*
+ * Restore signal mask early, so any memory problems could
+ * dump core.
+ */
+ sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL);
+ _thread_active_threads = 1;
+#endif
+}
+
+/*
+ * This is used to initialize housekeeping and to initialize the
+ * KSD for the KSE.
+ */
+void
+_kse_init(void)
+{
+ if (inited == 0) {
+ TAILQ_INIT(&active_kseq);
+ TAILQ_INIT(&active_kse_groupq);
+ TAILQ_INIT(&free_kseq);
+ TAILQ_INIT(&free_kse_groupq);
+ TAILQ_INIT(&free_threadq);
+ TAILQ_INIT(&gc_ksegq);
+ if (_lock_init(&kse_lock, LCK_ADAPTIVE,
+ _kse_lock_wait, _kse_lock_wakeup) != 0)
+ PANIC("Unable to initialize free KSE queue lock");
+ if (_lock_init(&thread_lock, LCK_ADAPTIVE,
+ _kse_lock_wait, _kse_lock_wakeup) != 0)
+ PANIC("Unable to initialize free thread queue lock");
+ if (_lock_init(&_thread_list_lock, LCK_ADAPTIVE,
+ _kse_lock_wait, _kse_lock_wakeup) != 0)
+ PANIC("Unable to initialize thread list lock");
+ _pthread_mutex_init(&_tcb_mutex, NULL);
+ active_kse_count = 0;
+ active_kseg_count = 0;
+ _gc_count = 0;
+ inited = 1;
+ }
+}
+
+/*
+ * This is called when the first thread (other than the initial
+ * thread) is created.
+ */
+int
+_kse_setthreaded(int threaded)
+{
+ sigset_t sigset;
+
+ if ((threaded != 0) && (__isthreaded == 0)) {
+ SIGFILLSET(sigset);
+ __sys_sigprocmask(SIG_SETMASK, &sigset, &_thr_initial->sigmask);
+
+ /*
+ * Tell the kernel to create a KSE for the initial thread
+ * and enable upcalls in it.
+ */
+ _kse_initial->k_flags |= KF_STARTED;
+
+ if (_thread_scope_system <= 0) {
+ _thr_initial->attr.flags &= ~PTHREAD_SCOPE_SYSTEM;
+ _kse_initial->k_kseg->kg_flags &= ~KGF_SINGLE_THREAD;
+ _kse_initial->k_kcb->kcb_kmbx.km_curthread = NULL;
+ }
+ else {
+ /*
+ * For bound thread, kernel reads mailbox pointer
+ * once, we'd set it here before calling kse_create.
+ */
+ _tcb_set(_kse_initial->k_kcb, _thr_initial->tcb);
+ KSE_SET_MBOX(_kse_initial, _thr_initial);
+ _kse_initial->k_kcb->kcb_kmbx.km_flags |= KMF_BOUND;
+ }
+
+ /*
+ * Locking functions in libc are required when there are
+ * threads other than the initial thread.
+ */
+ _thr_rtld_init();
+
+ __isthreaded = 1;
+ if (kse_create(&_kse_initial->k_kcb->kcb_kmbx, 0) != 0) {
+ _kse_initial->k_flags &= ~KF_STARTED;
+ __isthreaded = 0;
+ PANIC("kse_create() failed\n");
+ return (-1);
+ }
+ _thr_initial->tcb->tcb_tmbx.tm_lwp =
+ _kse_initial->k_kcb->kcb_kmbx.km_lwp;
+ _thread_activated = 1;
+
+#ifndef SYSTEM_SCOPE_ONLY
+ if (_thread_scope_system <= 0) {
+ /* Set current thread to initial thread */
+ _tcb_set(_kse_initial->k_kcb, _thr_initial->tcb);
+ KSE_SET_MBOX(_kse_initial, _thr_initial);
+ _thr_start_sig_daemon();
+ _thr_setmaxconcurrency();
+ }
+ else
+#endif
+ __sys_sigprocmask(SIG_SETMASK, &_thr_initial->sigmask,
+ NULL);
+ }
+ return (0);
+}
+
+/*
+ * Lock wait and wakeup handlers for KSE locks. These are only used by
+ * KSEs, and should never be used by threads. KSE locks include the
+ * KSE group lock (used for locking the scheduling queue) and the
+ * kse_lock defined above.
+ *
+ * When a KSE lock attempt blocks, the entire KSE blocks allowing another
+ * KSE to run. For the most part, it doesn't make much sense to try and
+ * schedule another thread because you need to lock the scheduling queue
+ * in order to do that. And since the KSE lock is used to lock the scheduling
+ * queue, you would just end up blocking again.
+ */
+void
+_kse_lock_wait(struct lock *lock, struct lockuser *lu)
+{
+ struct kse *curkse = (struct kse *)_LCK_GET_PRIVATE(lu);
+ struct timespec ts;
+ int saved_flags;
+
+ if (curkse->k_kcb->kcb_kmbx.km_curthread != NULL)
+ PANIC("kse_lock_wait does not disable upcall.\n");
+ /*
+ * Enter a loop to wait until we get the lock.
+ */
+ ts.tv_sec = 0;
+ ts.tv_nsec = 1000000; /* 1 sec */
+ while (!_LCK_GRANTED(lu)) {
+ /*
+ * Yield the kse and wait to be notified when the lock
+ * is granted.
+ */
+ saved_flags = curkse->k_kcb->kcb_kmbx.km_flags;
+ curkse->k_kcb->kcb_kmbx.km_flags |= KMF_NOUPCALL |
+ KMF_NOCOMPLETED;
+ kse_release(&ts);
+ curkse->k_kcb->kcb_kmbx.km_flags = saved_flags;
+ }
+}
+
+void
+_kse_lock_wakeup(struct lock *lock, struct lockuser *lu)
+{
+ struct kse *curkse;
+ struct kse *kse;
+ struct kse_mailbox *mbx;
+
+ curkse = _get_curkse();
+ kse = (struct kse *)_LCK_GET_PRIVATE(lu);
+
+ if (kse == curkse)
+ PANIC("KSE trying to wake itself up in lock");
+ else {
+ mbx = &kse->k_kcb->kcb_kmbx;
+ _lock_grant(lock, lu);
+ /*
+ * Notify the owning kse that it has the lock.
+ * It is safe to pass invalid address to kse_wakeup
+ * even if the mailbox is not in kernel at all,
+ * and waking up a wrong kse is also harmless.
+ */
+ kse_wakeup(mbx);
+ }
+}
+
+/*
+ * Thread wait and wakeup handlers for thread locks. These are only used
+ * by threads, never by KSEs. Thread locks include the per-thread lock
+ * (defined in its structure), and condition variable and mutex locks.
+ */
+void
+_thr_lock_wait(struct lock *lock, struct lockuser *lu)
+{
+ struct pthread *curthread = (struct pthread *)lu->lu_private;
+
+ do {
+ THR_LOCK_SWITCH(curthread);
+ THR_SET_STATE(curthread, PS_LOCKWAIT);
+ _thr_sched_switch_unlocked(curthread);
+ } while (!_LCK_GRANTED(lu));
+}
+
+void
+_thr_lock_wakeup(struct lock *lock, struct lockuser *lu)
+{
+ struct pthread *thread;
+ struct pthread *curthread;
+ struct kse_mailbox *kmbx;
+
+ curthread = _get_curthread();
+ thread = (struct pthread *)_LCK_GET_PRIVATE(lu);
+
+ THR_SCHED_LOCK(curthread, thread);
+ _lock_grant(lock, lu);
+ kmbx = _thr_setrunnable_unlocked(thread);
+ THR_SCHED_UNLOCK(curthread, thread);
+ if (kmbx != NULL)
+ kse_wakeup(kmbx);
+}
+
+kse_critical_t
+_kse_critical_enter(void)
+{
+ kse_critical_t crit;
+
+ crit = (kse_critical_t)_kcb_critical_enter();
+ return (crit);
+}
+
+void
+_kse_critical_leave(kse_critical_t crit)
+{
+ struct pthread *curthread;
+
+ _kcb_critical_leave((struct kse_thr_mailbox *)crit);
+ if ((crit != NULL) && ((curthread = _get_curthread()) != NULL))
+ THR_YIELD_CHECK(curthread);
+}
+
+int
+_kse_in_critical(void)
+{
+ return (_kcb_in_critical());
+}
+
+void
+_thr_critical_enter(struct pthread *thread)
+{
+ thread->critical_count++;
+}
+
+void
+_thr_critical_leave(struct pthread *thread)
+{
+ thread->critical_count--;
+ THR_YIELD_CHECK(thread);
+}
+
+void
+_thr_sched_switch(struct pthread *curthread)
+{
+ struct kse *curkse;
+
+ (void)_kse_critical_enter();
+ curkse = _get_curkse();
+ KSE_SCHED_LOCK(curkse, curkse->k_kseg);
+ _thr_sched_switch_unlocked(curthread);
+}
+
+/*
+ * XXX - We may need to take the scheduling lock before calling
+ * this, or perhaps take the lock within here before
+ * doing anything else.
+ */
+void
+_thr_sched_switch_unlocked(struct pthread *curthread)
+{
+ struct kse *curkse;
+ volatile int resume_once = 0;
+ ucontext_t *uc;
+
+ /* We're in the scheduler, 5 by 5: */
+ curkse = curthread->kse;
+
+ curthread->need_switchout = 1; /* The thread yielded on its own. */
+ curthread->critical_yield = 0; /* No need to yield anymore. */
+
+ /* Thread can unlock the scheduler lock. */
+ curthread->lock_switch = 1;
+
+ if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
+ kse_sched_single(&curkse->k_kcb->kcb_kmbx);
+ else {
+ if (__predict_false(_libkse_debug != 0)) {
+ /*
+ * Because debugger saves single step status in thread
+ * mailbox's tm_dflags, we can safely clear single
+ * step status here. the single step status will be
+ * restored by kse_switchin when the thread is
+ * switched in again. This also lets uts run in full
+ * speed.
+ */
+ ptrace(PT_CLEARSTEP, curkse->k_kcb->kcb_kmbx.km_lwp,
+ (caddr_t) 1, 0);
+ }
+
+ KSE_SET_SWITCH(curkse);
+ _thread_enter_uts(curthread->tcb, curkse->k_kcb);
+ }
+
+ /*
+ * Unlock the scheduling queue and leave the
+ * critical region.
+ */
+ /* Don't trust this after a switch! */
+ curkse = curthread->kse;
+
+ curthread->lock_switch = 0;
+ KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
+ _kse_critical_leave(&curthread->tcb->tcb_tmbx);
+
+ /*
+ * This thread is being resumed; check for cancellations.
+ */
+ if (THR_NEED_ASYNC_CANCEL(curthread) && !THR_IN_CRITICAL(curthread)) {
+ uc = alloca(sizeof(ucontext_t));
+ resume_once = 0;
+ THR_GETCONTEXT(uc);
+ if (resume_once == 0) {
+ resume_once = 1;
+ curthread->check_pending = 0;
+ thr_resume_check(curthread, uc);
+ }
+ }
+ THR_ACTIVATE_LAST_LOCK(curthread);
+}
+
+/*
+ * This is the scheduler for a KSE which runs a scope system thread.
+ * The multi-thread KSE scheduler should also work for a single threaded
+ * KSE, but we use a separate scheduler so that it can be fine-tuned
+ * to be more efficient (and perhaps not need a separate stack for
+ * the KSE, allowing it to use the thread's stack).
+ */
+
+static void
+kse_sched_single(struct kse_mailbox *kmbx)
+{
+ struct kse *curkse;
+ struct pthread *curthread;
+ struct timespec ts;
+ sigset_t sigmask;
+ int i, sigseqno, level, first = 0;
+
+ curkse = (struct kse *)kmbx->km_udata;
+ curthread = curkse->k_curthread;
+
+ if (__predict_false((curkse->k_flags & KF_INITIALIZED) == 0)) {
+ /* Setup this KSEs specific data. */
+ _kcb_set(curkse->k_kcb);
+ _tcb_set(curkse->k_kcb, curthread->tcb);
+ curkse->k_flags |= KF_INITIALIZED;
+ first = 1;
+ curthread->active = 1;
+
+ /* Setup kernel signal masks for new thread. */
+ __sys_sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL);
+ /*
+ * Enter critical region, this is meanless for bound thread,
+ * It is used to let other code work, those code want mailbox
+ * to be cleared.
+ */
+ (void)_kse_critical_enter();
+ } else {
+ /*
+ * Bound thread always has tcb set, this prevent some
+ * code from blindly setting bound thread tcb to NULL,
+ * buggy code ?
+ */
+ _tcb_set(curkse->k_kcb, curthread->tcb);
+ }
+
+ curthread->critical_yield = 0;
+ curthread->need_switchout = 0;
+
+ /*
+ * Lock the scheduling queue.
+ *
+ * There is no scheduling queue for single threaded KSEs,
+ * but we need a lock for protection regardless.
+ */
+ if (curthread->lock_switch == 0)
+ KSE_SCHED_LOCK(curkse, curkse->k_kseg);
+
+ /*
+ * This has to do the job of kse_switchout_thread(), only
+ * for a single threaded KSE/KSEG.
+ */
+
+ switch (curthread->state) {
+ case PS_MUTEX_WAIT:
+ case PS_COND_WAIT:
+ if (THR_NEED_CANCEL(curthread)) {
+ curthread->interrupted = 1;
+ curthread->continuation = _thr_finish_cancellation;
+ THR_SET_STATE(curthread, PS_RUNNING);
+ }
+ break;
+
+ case PS_LOCKWAIT:
+ /*
+ * This state doesn't timeout.
+ */
+ curthread->wakeup_time.tv_sec = -1;
+ curthread->wakeup_time.tv_nsec = -1;
+ level = curthread->locklevel - 1;
+ if (_LCK_GRANTED(&curthread->lockusers[level]))
+ THR_SET_STATE(curthread, PS_RUNNING);
+ break;
+
+ case PS_DEAD:
+ curthread->check_pending = 0;
+ /* Unlock the scheduling queue and exit the KSE and thread. */
+ thr_cleanup(curkse, curthread);
+ KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
+ PANIC("bound thread shouldn't get here\n");
+ break;
+
+ case PS_JOIN:
+ if (THR_NEED_CANCEL(curthread)) {
+ curthread->join_status.thread = NULL;
+ THR_SET_STATE(curthread, PS_RUNNING);
+ } else {
+ /*
+ * This state doesn't timeout.
+ */
+ curthread->wakeup_time.tv_sec = -1;
+ curthread->wakeup_time.tv_nsec = -1;
+ }
+ break;
+
+ case PS_SUSPENDED:
+ if (THR_NEED_CANCEL(curthread)) {
+ curthread->interrupted = 1;
+ THR_SET_STATE(curthread, PS_RUNNING);
+ } else {
+ /*
+ * These states don't timeout.
+ */
+ curthread->wakeup_time.tv_sec = -1;
+ curthread->wakeup_time.tv_nsec = -1;
+ }
+ break;
+
+ case PS_RUNNING:
+ if ((curthread->flags & THR_FLAGS_SUSPENDED) != 0 &&
+ !THR_NEED_CANCEL(curthread)) {
+ THR_SET_STATE(curthread, PS_SUSPENDED);
+ /*
+ * These states don't timeout.
+ */
+ curthread->wakeup_time.tv_sec = -1;
+ curthread->wakeup_time.tv_nsec = -1;
+ }
+ break;
+
+ case PS_SIGWAIT:
+ PANIC("bound thread does not have SIGWAIT state\n");
+
+ case PS_SLEEP_WAIT:
+ PANIC("bound thread does not have SLEEP_WAIT state\n");
+
+ case PS_SIGSUSPEND:
+ PANIC("bound thread does not have SIGSUSPEND state\n");
+
+ case PS_DEADLOCK:
+ /*
+ * These states don't timeout and don't need
+ * to be in the waiting queue.
+ */
+ curthread->wakeup_time.tv_sec = -1;
+ curthread->wakeup_time.tv_nsec = -1;
+ break;
+
+ default:
+ PANIC("Unknown state\n");
+ break;
+ }
+
+ while (curthread->state != PS_RUNNING) {
+ sigseqno = curkse->k_sigseqno;
+ if (curthread->check_pending != 0) {
+ /*
+ * Install pending signals into the frame, possible
+ * cause mutex or condvar backout.
+ */
+ curthread->check_pending = 0;
+ SIGFILLSET(sigmask);
+
+ /*
+ * Lock out kernel signal code when we are processing
+ * signals, and get a fresh copy of signal mask.
+ */
+ __sys_sigprocmask(SIG_SETMASK, &sigmask,
+ &curthread->sigmask);
+ for (i = 1; i <= _SIG_MAXSIG; i++) {
+ if (SIGISMEMBER(curthread->sigmask, i))
+ continue;
+ if (SIGISMEMBER(curthread->sigpend, i))
+ (void)_thr_sig_add(curthread, i,
+ &curthread->siginfo[i-1]);
+ }
+ __sys_sigprocmask(SIG_SETMASK, &curthread->sigmask,
+ NULL);
+ /* The above code might make thread runnable */
+ if (curthread->state == PS_RUNNING)
+ break;
+ }
+ THR_DEACTIVATE_LAST_LOCK(curthread);
+ kse_wait(curkse, curthread, sigseqno);
+ THR_ACTIVATE_LAST_LOCK(curthread);
+ if (curthread->wakeup_time.tv_sec >= 0) {
+ KSE_GET_TOD(curkse, &ts);
+ if (thr_timedout(curthread, &ts)) {
+ /* Indicate the thread timedout: */
+ curthread->timeout = 1;
+ /* Make the thread runnable. */
+ THR_SET_STATE(curthread, PS_RUNNING);
+ }
+ }
+ }
+
+ if (curthread->lock_switch == 0) {
+ /* Unlock the scheduling queue. */
+ KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
+ }
+
+ DBG_MSG("Continuing bound thread %p\n", curthread);
+ if (first) {
+ _kse_critical_leave(&curthread->tcb->tcb_tmbx);
+ pthread_exit(curthread->start_routine(curthread->arg));
+ }
+}
+
+#ifdef DEBUG_THREAD_KERN
+static void
+dump_queues(struct kse *curkse)
+{
+ struct pthread *thread;
+
+ DBG_MSG("Threads in waiting queue:\n");
+ TAILQ_FOREACH(thread, &curkse->k_kseg->kg_schedq.sq_waitq, pqe) {
+ DBG_MSG(" thread %p, state %d, blocked %d\n",
+ thread, thread->state, thread->blocked);
+ }
+}
+#endif
+
+/*
+ * This is the scheduler for a KSE which runs multiple threads.
+ */
+static void
+kse_sched_multi(struct kse_mailbox *kmbx)
+{
+ struct kse *curkse;
+ struct pthread *curthread, *td_wait;
+ int ret;
+
+ curkse = (struct kse *)kmbx->km_udata;
+ THR_ASSERT(curkse->k_kcb->kcb_kmbx.km_curthread == NULL,
+ "Mailbox not null in kse_sched_multi");
+
+ /* Check for first time initialization: */
+ if (__predict_false((curkse->k_flags & KF_INITIALIZED) == 0)) {
+ /* Setup this KSEs specific data. */
+ _kcb_set(curkse->k_kcb);
+
+ /* Set this before grabbing the context. */
+ curkse->k_flags |= KF_INITIALIZED;
+ }
+
+ /*
+ * No current thread anymore, calling _get_curthread in UTS
+ * should dump core
+ */
+ _tcb_set(curkse->k_kcb, NULL);
+
+ /* If this is an upcall; take the scheduler lock. */
+ if (!KSE_IS_SWITCH(curkse))
+ KSE_SCHED_LOCK(curkse, curkse->k_kseg);
+ else
+ KSE_CLEAR_SWITCH(curkse);
+
+ if (KSE_IS_IDLE(curkse)) {
+ KSE_CLEAR_IDLE(curkse);
+ curkse->k_kseg->kg_idle_kses--;
+ }
+
+ /*
+ * Now that the scheduler lock is held, get the current
+ * thread. The KSE's current thread cannot be safely
+ * examined without the lock because it could have returned
+ * as completed on another KSE. See kse_check_completed().
+ */
+ curthread = curkse->k_curthread;
+
+ /*
+ * If the current thread was completed in another KSE, then
+ * it will be in the run queue. Don't mark it as being blocked.
+ */
+ if ((curthread != NULL) &&
+ ((curthread->flags & THR_FLAGS_IN_RUNQ) == 0) &&
+ (curthread->need_switchout == 0)) {
+ /*
+ * Assume the current thread is blocked; when the
+ * completed threads are checked and if the current
+ * thread is among the completed, the blocked flag
+ * will be cleared.
+ */
+ curthread->blocked = 1;
+ DBG_MSG("Running thread %p is now blocked in kernel.\n",
+ curthread);
+ }
+
+ /* Check for any unblocked threads in the kernel. */
+ kse_check_completed(curkse);
+
+ /*
+ * Check for threads that have timed-out.
+ */
+ kse_check_waitq(curkse);
+
+ /*
+ * Switchout the current thread, if necessary, as the last step
+ * so that it is inserted into the run queue (if it's runnable)
+ * _after_ any other threads that were added to it above.
+ */
+ if (curthread == NULL)
+ ; /* Nothing to do here. */
+ else if ((curthread->need_switchout == 0) && DBG_CAN_RUN(curthread) &&
+ (curthread->blocked == 0) && (THR_IN_CRITICAL(curthread))) {
+ /*
+ * Resume the thread and tell it to yield when
+ * it leaves the critical region.
+ */
+ curthread->critical_yield = 1;
+ curthread->active = 1;
+ if ((curthread->flags & THR_FLAGS_IN_RUNQ) != 0)
+ KSE_RUNQ_REMOVE(curkse, curthread);
+ curkse->k_curthread = curthread;
+ curthread->kse = curkse;
+ DBG_MSG("Continuing thread %p in critical region\n",
+ curthread);
+ kse_wakeup_multi(curkse);
+ KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
+ ret = _thread_switch(curkse->k_kcb, curthread->tcb, 1);
+ if (ret != 0)
+ PANIC("Can't resume thread in critical region\n");
+ }
+ else if ((curthread->flags & THR_FLAGS_IN_RUNQ) == 0) {
+ curthread->tcb->tcb_tmbx.tm_lwp = 0;
+ kse_switchout_thread(curkse, curthread);
+ }
+ curkse->k_curthread = NULL;
+
+#ifdef DEBUG_THREAD_KERN
+ dump_queues(curkse);
+#endif
+
+ /* Check if there are no threads ready to run: */
+ while (((curthread = KSE_RUNQ_FIRST(curkse)) == NULL) &&
+ (curkse->k_kseg->kg_threadcount != 0) &&
+ ((curkse->k_flags & KF_TERMINATED) == 0)) {
+ /*
+ * Wait for a thread to become active or until there are
+ * no more threads.
+ */
+ td_wait = KSE_WAITQ_FIRST(curkse);
+ kse_wait(curkse, td_wait, 0);
+ kse_check_completed(curkse);
+ kse_check_waitq(curkse);
+ }
+
+ /* Check for no more threads: */
+ if ((curkse->k_kseg->kg_threadcount == 0) ||
+ ((curkse->k_flags & KF_TERMINATED) != 0)) {
+ /*
+ * Normally this shouldn't return, but it will if there
+ * are other KSEs running that create new threads that
+ * are assigned to this KSE[G]. For instance, if a scope
+ * system thread were to create a scope process thread
+ * and this kse[g] is the initial kse[g], then that newly
+ * created thread would be assigned to us (the initial
+ * kse[g]).
+ */
+ kse_wakeup_multi(curkse);
+ KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
+ kse_fini(curkse);
+ /* never returns */
+ }
+
+ THR_ASSERT(curthread != NULL,
+ "Return from kse_wait/fini without thread.");
+ THR_ASSERT(curthread->state != PS_DEAD,
+ "Trying to resume dead thread!");
+ KSE_RUNQ_REMOVE(curkse, curthread);
+
+ /*
+ * Make the selected thread the current thread.
+ */
+ curkse->k_curthread = curthread;
+
+ /*
+ * Make sure the current thread's kse points to this kse.
+ */
+ curthread->kse = curkse;
+
+ /*
+ * Reset the time slice if this thread is running for the first
+ * time or running again after using its full time slice allocation.
+ */
+ if (curthread->slice_usec == -1)
+ curthread->slice_usec = 0;
+
+ /* Mark the thread active. */
+ curthread->active = 1;
+
+ /*
+ * The thread's current signal frame will only be NULL if it
+ * is being resumed after being blocked in the kernel. In
+ * this case, and if the thread needs to run down pending
+ * signals or needs a cancellation check, we need to add a
+ * signal frame to the thread's context.
+ */
+ if (curthread->lock_switch == 0 && curthread->state == PS_RUNNING &&
+ (curthread->check_pending != 0 ||
+ THR_NEED_ASYNC_CANCEL(curthread)) &&
+ !THR_IN_CRITICAL(curthread)) {
+ curthread->check_pending = 0;
+ signalcontext(&curthread->tcb->tcb_tmbx.tm_context, 0,
+ (__sighandler_t *)thr_resume_wrapper);
+ }
+ kse_wakeup_multi(curkse);
+ /*
+ * Continue the thread at its current frame:
+ */
+ if (curthread->lock_switch != 0) {
+ /*
+ * This thread came from a scheduler switch; it will
+ * unlock the scheduler lock and set the mailbox.
+ */
+ ret = _thread_switch(curkse->k_kcb, curthread->tcb, 0);
+ } else {
+ /* This thread won't unlock the scheduler lock. */
+ KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
+ ret = _thread_switch(curkse->k_kcb, curthread->tcb, 1);
+ }
+ if (ret != 0)
+ PANIC("Thread has returned from _thread_switch");
+
+ /* This point should not be reached. */
+ PANIC("Thread has returned from _thread_switch");
+}
+
+static void
+thr_resume_wrapper(int sig, siginfo_t *siginfo, ucontext_t *ucp)
+{
+ struct pthread *curthread = _get_curthread();
+ struct kse *curkse;
+ int ret, err_save = errno;
+
+ DBG_MSG(">>> sig wrapper\n");
+ if (curthread->lock_switch)
+ PANIC("thr_resume_wrapper, lock_switch != 0\n");
+ thr_resume_check(curthread, ucp);
+ errno = err_save;
+ _kse_critical_enter();
+ curkse = curthread->kse;
+ curthread->tcb->tcb_tmbx.tm_context = *ucp;
+ ret = _thread_switch(curkse->k_kcb, curthread->tcb, 1);
+ if (ret != 0)
+ PANIC("thr_resume_wrapper: thread has returned "
+ "from _thread_switch");
+ /* THR_SETCONTEXT(ucp); */ /* not work, why ? */
+}
+
+static void
+thr_resume_check(struct pthread *curthread, ucontext_t *ucp)
+{
+ _thr_sig_rundown(curthread, ucp);
+
+ if (THR_NEED_ASYNC_CANCEL(curthread))
+ pthread_testcancel();
+}
+
+/*
+ * Clean up a thread. This must be called with the thread's KSE
+ * scheduling lock held. The thread must be a thread from the
+ * KSE's group.
+ */
+static void
+thr_cleanup(struct kse *curkse, struct pthread *thread)
+{
+ struct pthread *joiner;
+ struct kse_mailbox *kmbx = NULL;
+ int sys_scope;
+
+ if ((joiner = thread->joiner) != NULL) {
+ /* Joinee scheduler lock held; joiner won't leave. */
+ if (joiner->kseg == curkse->k_kseg) {
+ if (joiner->join_status.thread == thread) {
+ joiner->join_status.thread = NULL;
+ joiner->join_status.ret = thread->ret;
+ (void)_thr_setrunnable_unlocked(joiner);
+ }
+ } else {
+ KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
+ /* The joiner may have removed itself and exited. */
+ if (_thr_ref_add(thread, joiner, 0) == 0) {
+ KSE_SCHED_LOCK(curkse, joiner->kseg);
+ if (joiner->join_status.thread == thread) {
+ joiner->join_status.thread = NULL;
+ joiner->join_status.ret = thread->ret;
+ kmbx = _thr_setrunnable_unlocked(joiner);
+ }
+ KSE_SCHED_UNLOCK(curkse, joiner->kseg);
+ _thr_ref_delete(thread, joiner);
+ if (kmbx != NULL)
+ kse_wakeup(kmbx);
+ }
+ KSE_SCHED_LOCK(curkse, curkse->k_kseg);
+ }
+ thread->attr.flags |= PTHREAD_DETACHED;
+ }
+
+ if (!(sys_scope = (thread->attr.flags & PTHREAD_SCOPE_SYSTEM))) {
+ /*
+ * Remove the thread from the KSEG's list of threads.
+ */
+ KSEG_THRQ_REMOVE(thread->kseg, thread);
+ /*
+ * Migrate the thread to the main KSE so that this
+ * KSE and KSEG can be cleaned when their last thread
+ * exits.
+ */
+ thread->kseg = _kse_initial->k_kseg;
+ thread->kse = _kse_initial;
+ }
+
+ /*
+ * We can't hold the thread list lock while holding the
+ * scheduler lock.
+ */
+ KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
+ DBG_MSG("Adding thread %p to GC list\n", thread);
+ KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock);
+ thread->tlflags |= TLFLAGS_GC_SAFE;
+ THR_GCLIST_ADD(thread);
+ KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
+ if (sys_scope) {
+ /*
+ * System scope thread is single thread group,
+ * when thread is exited, its kse and ksegrp should
+ * be recycled as well.
+ * kse upcall stack belongs to thread, clear it here.
+ */
+ curkse->k_stack.ss_sp = 0;
+ curkse->k_stack.ss_size = 0;
+ kse_exit();
+ PANIC("kse_exit() failed for system scope thread");
+ }
+ KSE_SCHED_LOCK(curkse, curkse->k_kseg);
+}
+
+void
+_thr_gc(struct pthread *curthread)
+{
+ thread_gc(curthread);
+ kse_gc(curthread);
+ kseg_gc(curthread);
+}
+
+static void
+thread_gc(struct pthread *curthread)
+{
+ struct pthread *td, *td_next;
+ kse_critical_t crit;
+ TAILQ_HEAD(, pthread) worklist;
+
+ TAILQ_INIT(&worklist);
+ crit = _kse_critical_enter();
+ KSE_LOCK_ACQUIRE(curthread->kse, &_thread_list_lock);
+
+ /* Check the threads waiting for GC. */
+ for (td = TAILQ_FIRST(&_thread_gc_list); td != NULL; td = td_next) {
+ td_next = TAILQ_NEXT(td, gcle);
+ if ((td->tlflags & TLFLAGS_GC_SAFE) == 0)
+ continue;
+ else if (((td->attr.flags & PTHREAD_SCOPE_SYSTEM) != 0) &&
+ ((td->kse->k_kcb->kcb_kmbx.km_flags & KMF_DONE) == 0)) {
+ /*
+ * The thread and KSE are operating on the same
+ * stack. Wait for the KSE to exit before freeing
+ * the thread's stack as well as everything else.
+ */
+ continue;
+ }
+ /*
+ * Remove the thread from the GC list. If the thread
+ * isn't yet detached, it will get added back to the
+ * GC list at a later time.
+ */
+ THR_GCLIST_REMOVE(td);
+ DBG_MSG("Freeing thread %p stack\n", td);
+ /*
+ * We can free the thread stack since it's no longer
+ * in use.
+ */
+ _thr_stack_free(&td->attr);
+ if (((td->attr.flags & PTHREAD_DETACHED) != 0) &&
+ (td->refcount == 0)) {
+ /*
+ * The thread has detached and is no longer
+ * referenced. It is safe to remove all
+ * remnants of the thread.
+ */
+ THR_LIST_REMOVE(td);
+ TAILQ_INSERT_HEAD(&worklist, td, gcle);
+ }
+ }
+ KSE_LOCK_RELEASE(curthread->kse, &_thread_list_lock);
+ _kse_critical_leave(crit);
+
+ while ((td = TAILQ_FIRST(&worklist)) != NULL) {
+ TAILQ_REMOVE(&worklist, td, gcle);
+ /*
+ * XXX we don't free initial thread and its kse
+ * (if thread is a bound thread), because there might
+ * have some code referencing initial thread and kse.
+ */
+ if (td == _thr_initial) {
+ DBG_MSG("Initial thread won't be freed\n");
+ continue;
+ }
+
+ if ((td->attr.flags & PTHREAD_SCOPE_SYSTEM) != 0) {
+ crit = _kse_critical_enter();
+ KSE_LOCK_ACQUIRE(curthread->kse, &kse_lock);
+ kse_free_unlocked(td->kse);
+ kseg_free_unlocked(td->kseg);
+ KSE_LOCK_RELEASE(curthread->kse, &kse_lock);
+ _kse_critical_leave(crit);
+ }
+ DBG_MSG("Freeing thread %p\n", td);
+ _thr_free(curthread, td);
+ }
+}
+
+static void
+kse_gc(struct pthread *curthread)
+{
+ kse_critical_t crit;
+ TAILQ_HEAD(, kse) worklist;
+ struct kse *kse;
+
+ if (free_kse_count <= MAX_CACHED_KSES)
+ return;
+ TAILQ_INIT(&worklist);
+ crit = _kse_critical_enter();
+ KSE_LOCK_ACQUIRE(curthread->kse, &kse_lock);
+ while (free_kse_count > MAX_CACHED_KSES) {
+ kse = TAILQ_FIRST(&free_kseq);
+ TAILQ_REMOVE(&free_kseq, kse, k_qe);
+ TAILQ_INSERT_HEAD(&worklist, kse, k_qe);
+ free_kse_count--;
+ }
+ KSE_LOCK_RELEASE(curthread->kse, &kse_lock);
+ _kse_critical_leave(crit);
+
+ while ((kse = TAILQ_FIRST(&worklist))) {
+ TAILQ_REMOVE(&worklist, kse, k_qe);
+ kse_destroy(kse);
+ }
+}
+
+static void
+kseg_gc(struct pthread *curthread)
+{
+ kse_critical_t crit;
+ TAILQ_HEAD(, kse_group) worklist;
+ struct kse_group *kseg;
+
+ if (free_kseg_count <= MAX_CACHED_KSEGS)
+ return;
+ TAILQ_INIT(&worklist);
+ crit = _kse_critical_enter();
+ KSE_LOCK_ACQUIRE(curthread->kse, &kse_lock);
+ while (free_kseg_count > MAX_CACHED_KSEGS) {
+ kseg = TAILQ_FIRST(&free_kse_groupq);
+ TAILQ_REMOVE(&free_kse_groupq, kseg, kg_qe);
+ free_kseg_count--;
+ TAILQ_INSERT_HEAD(&worklist, kseg, kg_qe);
+ }
+ KSE_LOCK_RELEASE(curthread->kse, &kse_lock);
+ _kse_critical_leave(crit);
+
+ while ((kseg = TAILQ_FIRST(&worklist))) {
+ TAILQ_REMOVE(&worklist, kseg, kg_qe);
+ kseg_destroy(kseg);
+ }
+}
+
+/*
+ * Only new threads that are running or suspended may be scheduled.
+ */
+int
+_thr_schedule_add(struct pthread *curthread, struct pthread *newthread)
+{
+ kse_critical_t crit;
+ int ret;
+
+ /* Add the new thread. */
+ thr_link(newthread);
+
+ /*
+ * If this is the first time creating a thread, make sure
+ * the mailbox is set for the current thread.
+ */
+ if ((newthread->attr.flags & PTHREAD_SCOPE_SYSTEM) != 0) {
+ /* We use the thread's stack as the KSE's stack. */
+ newthread->kse->k_kcb->kcb_kmbx.km_stack.ss_sp =
+ newthread->attr.stackaddr_attr;
+ newthread->kse->k_kcb->kcb_kmbx.km_stack.ss_size =
+ newthread->attr.stacksize_attr;
+
+ /*
+ * No need to lock the scheduling queue since the
+ * KSE/KSEG pair have not yet been started.
+ */
+ KSEG_THRQ_ADD(newthread->kseg, newthread);
+ /* this thread never gives up kse */
+ newthread->active = 1;
+ newthread->kse->k_curthread = newthread;
+ newthread->kse->k_kcb->kcb_kmbx.km_flags = KMF_BOUND;
+ newthread->kse->k_kcb->kcb_kmbx.km_func =
+ (kse_func_t *)kse_sched_single;
+ newthread->kse->k_kcb->kcb_kmbx.km_quantum = 0;
+ KSE_SET_MBOX(newthread->kse, newthread);
+ /*
+ * This thread needs a new KSE and KSEG.
+ */
+ newthread->kse->k_flags &= ~KF_INITIALIZED;
+ newthread->kse->k_flags |= KF_STARTED;
+ /* Fire up! */
+ ret = kse_create(&newthread->kse->k_kcb->kcb_kmbx, 1);
+ if (ret != 0)
+ ret = errno;
+ }
+ else {
+ /*
+ * Lock the KSE and add the new thread to its list of
+ * assigned threads. If the new thread is runnable, also
+ * add it to the KSE's run queue.
+ */
+ crit = _kse_critical_enter();
+ KSE_SCHED_LOCK(curthread->kse, newthread->kseg);
+ KSEG_THRQ_ADD(newthread->kseg, newthread);
+ if (newthread->state == PS_RUNNING)
+ THR_RUNQ_INSERT_TAIL(newthread);
+ if ((newthread->kse->k_flags & KF_STARTED) == 0) {
+ /*
+ * This KSE hasn't been started yet. Start it
+ * outside of holding the lock.
+ */
+ newthread->kse->k_flags |= KF_STARTED;
+ newthread->kse->k_kcb->kcb_kmbx.km_func =
+ (kse_func_t *)kse_sched_multi;
+ newthread->kse->k_kcb->kcb_kmbx.km_flags = 0;
+ kse_create(&newthread->kse->k_kcb->kcb_kmbx, 0);
+ } else if ((newthread->state == PS_RUNNING) &&
+ KSE_IS_IDLE(newthread->kse)) {
+ /*
+ * The thread is being scheduled on another KSEG.
+ */
+ kse_wakeup_one(newthread);
+ }
+ KSE_SCHED_UNLOCK(curthread->kse, newthread->kseg);
+ _kse_critical_leave(crit);
+ ret = 0;
+ }
+ if (ret != 0)
+ thr_unlink(newthread);
+
+ return (ret);
+}
+
+void
+kse_waitq_insert(struct pthread *thread)
+{
+ struct pthread *td;
+
+ if (thread->wakeup_time.tv_sec == -1)
+ TAILQ_INSERT_TAIL(&thread->kse->k_schedq->sq_waitq, thread,
+ pqe);
+ else {
+ td = TAILQ_FIRST(&thread->kse->k_schedq->sq_waitq);
+ while ((td != NULL) && (td->wakeup_time.tv_sec != -1) &&
+ ((td->wakeup_time.tv_sec < thread->wakeup_time.tv_sec) ||
+ ((td->wakeup_time.tv_sec == thread->wakeup_time.tv_sec) &&
+ (td->wakeup_time.tv_nsec <= thread->wakeup_time.tv_nsec))))
+ td = TAILQ_NEXT(td, pqe);
+ if (td == NULL)
+ TAILQ_INSERT_TAIL(&thread->kse->k_schedq->sq_waitq,
+ thread, pqe);
+ else
+ TAILQ_INSERT_BEFORE(td, thread, pqe);
+ }
+ thread->flags |= THR_FLAGS_IN_WAITQ;
+}
+
+/*
+ * This must be called with the scheduling lock held.
+ */
+static void
+kse_check_completed(struct kse *kse)
+{
+ struct pthread *thread;
+ struct kse_thr_mailbox *completed;
+ int sig;
+
+ if ((completed = kse->k_kcb->kcb_kmbx.km_completed) != NULL) {
+ kse->k_kcb->kcb_kmbx.km_completed = NULL;
+ while (completed != NULL) {
+ thread = completed->tm_udata;
+ DBG_MSG("Found completed thread %p, name %s\n",
+ thread,
+ (thread->name == NULL) ? "none" : thread->name);
+ thread->blocked = 0;
+ if (thread != kse->k_curthread) {
+ thr_accounting(thread);
+ if ((thread->flags & THR_FLAGS_SUSPENDED) != 0)
+ THR_SET_STATE(thread, PS_SUSPENDED);
+ else
+ KSE_RUNQ_INSERT_TAIL(kse, thread);
+ if ((thread->kse != kse) &&
+ (thread->kse->k_curthread == thread)) {
+ /*
+ * Remove this thread from its
+ * previous KSE so that it (the KSE)
+ * doesn't think it is still active.
+ */
+ thread->kse->k_curthread = NULL;
+ thread->active = 0;
+ }
+ }
+ if ((sig = thread->tcb->tcb_tmbx.tm_syncsig.si_signo)
+ != 0) {
+ if (SIGISMEMBER(thread->sigmask, sig))
+ SIGADDSET(thread->sigpend, sig);
+ else if (THR_IN_CRITICAL(thread))
+ kse_thr_interrupt(NULL, KSE_INTR_SIGEXIT, sig);
+ else
+ (void)_thr_sig_add(thread, sig,
+ &thread->tcb->tcb_tmbx.tm_syncsig);
+ thread->tcb->tcb_tmbx.tm_syncsig.si_signo = 0;
+ }
+ completed = completed->tm_next;
+ }
+ }
+}
+
+/*
+ * This must be called with the scheduling lock held.
+ */
+static void
+kse_check_waitq(struct kse *kse)
+{
+ struct pthread *pthread;
+ struct timespec ts;
+
+ KSE_GET_TOD(kse, &ts);
+
+ /*
+ * Wake up threads that have timedout. This has to be
+ * done before adding the current thread to the run queue
+ * so that a CPU intensive thread doesn't get preference
+ * over waiting threads.
+ */
+ while (((pthread = KSE_WAITQ_FIRST(kse)) != NULL) &&
+ thr_timedout(pthread, &ts)) {
+ /* Remove the thread from the wait queue: */
+ KSE_WAITQ_REMOVE(kse, pthread);
+ DBG_MSG("Found timedout thread %p in waitq\n", pthread);
+
+ /* Indicate the thread timedout: */
+ pthread->timeout = 1;
+
+ /* Add the thread to the priority queue: */
+ if ((pthread->flags & THR_FLAGS_SUSPENDED) != 0)
+ THR_SET_STATE(pthread, PS_SUSPENDED);
+ else {
+ THR_SET_STATE(pthread, PS_RUNNING);
+ KSE_RUNQ_INSERT_TAIL(kse, pthread);
+ }
+ }
+}
+
+static int
+thr_timedout(struct pthread *thread, struct timespec *curtime)
+{
+ if (thread->wakeup_time.tv_sec < 0)
+ return (0);
+ else if (thread->wakeup_time.tv_sec > curtime->tv_sec)
+ return (0);
+ else if ((thread->wakeup_time.tv_sec == curtime->tv_sec) &&
+ (thread->wakeup_time.tv_nsec > curtime->tv_nsec))
+ return (0);
+ else
+ return (1);
+}
+
+/*
+ * This must be called with the scheduling lock held.
+ *
+ * Each thread has a time slice, a wakeup time (used when it wants
+ * to wait for a specified amount of time), a run state, and an
+ * active flag.
+ *
+ * When a thread gets run by the scheduler, the active flag is
+ * set to non-zero (1). When a thread performs an explicit yield
+ * or schedules a state change, it enters the scheduler and the
+ * active flag is cleared. When the active flag is still seen
+ * set in the scheduler, that means that the thread is blocked in
+ * the kernel (because it is cleared before entering the scheduler
+ * in all other instances).
+ *
+ * The wakeup time is only set for those states that can timeout.
+ * It is set to (-1, -1) for all other instances.
+ *
+ * The thread's run state, aside from being useful when debugging,
+ * is used to place the thread in an appropriate queue. There
+ * are 2 basic queues:
+ *
+ * o run queue - queue ordered by priority for all threads
+ * that are runnable
+ * o waiting queue - queue sorted by wakeup time for all threads
+ * that are not otherwise runnable (not blocked
+ * in kernel, not waiting for locks)
+ *
+ * The thread's time slice is used for round-robin scheduling
+ * (the default scheduling policy). While a SCHED_RR thread
+ * is runnable it's time slice accumulates. When it reaches
+ * the time slice interval, it gets reset and added to the end
+ * of the queue of threads at its priority. When a thread no
+ * longer becomes runnable (blocks in kernel, waits, etc), its
+ * time slice is reset.
+ *
+ * The job of kse_switchout_thread() is to handle all of the above.
+ */
+static void
+kse_switchout_thread(struct kse *kse, struct pthread *thread)
+{
+ int level;
+ int i;
+ int restart;
+ siginfo_t siginfo;
+
+ /*
+ * Place the currently running thread into the
+ * appropriate queue(s).
+ */
+ DBG_MSG("Switching out thread %p, state %d\n", thread, thread->state);
+
+ THR_DEACTIVATE_LAST_LOCK(thread);
+ if (thread->blocked != 0) {
+ thread->active = 0;
+ thread->need_switchout = 0;
+ /* This thread must have blocked in the kernel. */
+ /*
+ * Check for pending signals and cancellation for
+ * this thread to see if we need to interrupt it
+ * in the kernel.
+ */
+ if (THR_NEED_CANCEL(thread)) {
+ kse_thr_interrupt(&thread->tcb->tcb_tmbx,
+ KSE_INTR_INTERRUPT, 0);
+ } else if (thread->check_pending != 0) {
+ for (i = 1; i <= _SIG_MAXSIG; ++i) {
+ if (SIGISMEMBER(thread->sigpend, i) &&
+ !SIGISMEMBER(thread->sigmask, i)) {
+ restart = _thread_sigact[i - 1].sa_flags & SA_RESTART;
+ kse_thr_interrupt(&thread->tcb->tcb_tmbx,
+ restart ? KSE_INTR_RESTART : KSE_INTR_INTERRUPT, 0);
+ break;
+ }
+ }
+ }
+ }
+ else {
+ switch (thread->state) {
+ case PS_MUTEX_WAIT:
+ case PS_COND_WAIT:
+ if (THR_NEED_CANCEL(thread)) {
+ thread->interrupted = 1;
+ thread->continuation = _thr_finish_cancellation;
+ THR_SET_STATE(thread, PS_RUNNING);
+ } else {
+ /* Insert into the waiting queue: */
+ KSE_WAITQ_INSERT(kse, thread);
+ }
+ break;
+
+ case PS_LOCKWAIT:
+ /*
+ * This state doesn't timeout.
+ */
+ thread->wakeup_time.tv_sec = -1;
+ thread->wakeup_time.tv_nsec = -1;
+ level = thread->locklevel - 1;
+ if (!_LCK_GRANTED(&thread->lockusers[level]))
+ KSE_WAITQ_INSERT(kse, thread);
+ else
+ THR_SET_STATE(thread, PS_RUNNING);
+ break;
+
+ case PS_SLEEP_WAIT:
+ case PS_SIGWAIT:
+ if (THR_NEED_CANCEL(thread)) {
+ thread->interrupted = 1;
+ THR_SET_STATE(thread, PS_RUNNING);
+ } else {
+ KSE_WAITQ_INSERT(kse, thread);
+ }
+ break;
+
+ case PS_JOIN:
+ if (THR_NEED_CANCEL(thread)) {
+ thread->join_status.thread = NULL;
+ THR_SET_STATE(thread, PS_RUNNING);
+ } else {
+ /*
+ * This state doesn't timeout.
+ */
+ thread->wakeup_time.tv_sec = -1;
+ thread->wakeup_time.tv_nsec = -1;
+
+ /* Insert into the waiting queue: */
+ KSE_WAITQ_INSERT(kse, thread);
+ }
+ break;
+
+ case PS_SIGSUSPEND:
+ case PS_SUSPENDED:
+ if (THR_NEED_CANCEL(thread)) {
+ thread->interrupted = 1;
+ THR_SET_STATE(thread, PS_RUNNING);
+ } else {
+ /*
+ * These states don't timeout.
+ */
+ thread->wakeup_time.tv_sec = -1;
+ thread->wakeup_time.tv_nsec = -1;
+
+ /* Insert into the waiting queue: */
+ KSE_WAITQ_INSERT(kse, thread);
+ }
+ break;
+
+ case PS_DEAD:
+ /*
+ * The scheduler is operating on a different
+ * stack. It is safe to do garbage collecting
+ * here.
+ */
+ thread->active = 0;
+ thread->need_switchout = 0;
+ thread->lock_switch = 0;
+ thr_cleanup(kse, thread);
+ return;
+ break;
+
+ case PS_RUNNING:
+ if ((thread->flags & THR_FLAGS_SUSPENDED) != 0 &&
+ !THR_NEED_CANCEL(thread))
+ THR_SET_STATE(thread, PS_SUSPENDED);
+ break;
+
+ case PS_DEADLOCK:
+ /*
+ * These states don't timeout.
+ */
+ thread->wakeup_time.tv_sec = -1;
+ thread->wakeup_time.tv_nsec = -1;
+
+ /* Insert into the waiting queue: */
+ KSE_WAITQ_INSERT(kse, thread);
+ break;
+
+ default:
+ PANIC("Unknown state\n");
+ break;
+ }
+
+ thr_accounting(thread);
+ if (thread->state == PS_RUNNING) {
+ if (thread->slice_usec == -1) {
+ /*
+ * The thread exceeded its time quantum or
+ * it yielded the CPU; place it at the tail
+ * of the queue for its priority.
+ */
+ KSE_RUNQ_INSERT_TAIL(kse, thread);
+ } else {
+ /*
+ * The thread hasn't exceeded its interval
+ * Place it at the head of the queue for its
+ * priority.
+ */
+ KSE_RUNQ_INSERT_HEAD(kse, thread);
+ }
+ }
+ }
+ thread->active = 0;
+ thread->need_switchout = 0;
+ if (thread->check_pending != 0) {
+ /* Install pending signals into the frame. */
+ thread->check_pending = 0;
+ KSE_LOCK_ACQUIRE(kse, &_thread_signal_lock);
+ for (i = 1; i <= _SIG_MAXSIG; i++) {
+ if (SIGISMEMBER(thread->sigmask, i))
+ continue;
+ if (SIGISMEMBER(thread->sigpend, i))
+ (void)_thr_sig_add(thread, i,
+ &thread->siginfo[i-1]);
+ else if (SIGISMEMBER(_thr_proc_sigpending, i) &&
+ _thr_getprocsig_unlocked(i, &siginfo)) {
+ (void)_thr_sig_add(thread, i, &siginfo);
+ }
+ }
+ KSE_LOCK_RELEASE(kse, &_thread_signal_lock);
+ }
+}
+
+/*
+ * This function waits for the smallest timeout value of any waiting
+ * thread, or until it receives a message from another KSE.
+ *
+ * This must be called with the scheduling lock held.
+ */
+static void
+kse_wait(struct kse *kse, struct pthread *td_wait, int sigseqno)
+{
+ struct timespec ts, ts_sleep;
+ int saved_flags;
+
+ if ((td_wait == NULL) || (td_wait->wakeup_time.tv_sec < 0)) {
+ /* Limit sleep to no more than 1 minute. */
+ ts_sleep.tv_sec = 60;
+ ts_sleep.tv_nsec = 0;
+ } else {
+ KSE_GET_TOD(kse, &ts);
+ TIMESPEC_SUB(&ts_sleep, &td_wait->wakeup_time, &ts);
+ if (ts_sleep.tv_sec > 60) {
+ ts_sleep.tv_sec = 60;
+ ts_sleep.tv_nsec = 0;
+ }
+ }
+ /* Don't sleep for negative times. */
+ if ((ts_sleep.tv_sec >= 0) && (ts_sleep.tv_nsec >= 0)) {
+ KSE_SET_IDLE(kse);
+ kse->k_kseg->kg_idle_kses++;
+ KSE_SCHED_UNLOCK(kse, kse->k_kseg);
+ if ((kse->k_kseg->kg_flags & KGF_SINGLE_THREAD) &&
+ (kse->k_sigseqno != sigseqno))
+ ; /* don't sleep */
+ else {
+ saved_flags = kse->k_kcb->kcb_kmbx.km_flags;
+ kse->k_kcb->kcb_kmbx.km_flags |= KMF_NOUPCALL;
+ kse_release(&ts_sleep);
+ kse->k_kcb->kcb_kmbx.km_flags = saved_flags;
+ }
+ KSE_SCHED_LOCK(kse, kse->k_kseg);
+ if (KSE_IS_IDLE(kse)) {
+ KSE_CLEAR_IDLE(kse);
+ kse->k_kseg->kg_idle_kses--;
+ }
+ }
+}
+
+/*
+ * Avoid calling this kse_exit() so as not to confuse it with the
+ * system call of the same name.
+ */
+static void
+kse_fini(struct kse *kse)
+{
+ /* struct kse_group *free_kseg = NULL; */
+ struct timespec ts;
+ struct pthread *td;
+
+ /*
+ * Check to see if this is one of the main kses.
+ */
+ if (kse->k_kseg != _kse_initial->k_kseg) {
+ PANIC("shouldn't get here");
+ /* This is for supporting thread groups. */
+#ifdef NOT_YET
+ /* Remove this KSE from the KSEG's list of KSEs. */
+ KSE_SCHED_LOCK(kse, kse->k_kseg);
+ TAILQ_REMOVE(&kse->k_kseg->kg_kseq, kse, k_kgqe);
+ kse->k_kseg->kg_ksecount--;
+ if (TAILQ_EMPTY(&kse->k_kseg->kg_kseq))
+ free_kseg = kse->k_kseg;
+ KSE_SCHED_UNLOCK(kse, kse->k_kseg);
+
+ /*
+ * Add this KSE to the list of free KSEs along with
+ * the KSEG if is now orphaned.
+ */
+ KSE_LOCK_ACQUIRE(kse, &kse_lock);
+ if (free_kseg != NULL)
+ kseg_free_unlocked(free_kseg);
+ kse_free_unlocked(kse);
+ KSE_LOCK_RELEASE(kse, &kse_lock);
+ kse_exit();
+ /* Never returns. */
+ PANIC("kse_exit()");
+#endif
+ } else {
+ /*
+ * We allow program to kill kse in initial group (by
+ * lowering the concurrency).
+ */
+ if ((kse != _kse_initial) &&
+ ((kse->k_flags & KF_TERMINATED) != 0)) {
+ KSE_SCHED_LOCK(kse, kse->k_kseg);
+ TAILQ_REMOVE(&kse->k_kseg->kg_kseq, kse, k_kgqe);
+ kse->k_kseg->kg_ksecount--;
+ /*
+ * Migrate thread to _kse_initial if its lastest
+ * kse it ran on is the kse.
+ */
+ td = TAILQ_FIRST(&kse->k_kseg->kg_threadq);
+ while (td != NULL) {
+ if (td->kse == kse)
+ td->kse = _kse_initial;
+ td = TAILQ_NEXT(td, kle);
+ }
+ KSE_SCHED_UNLOCK(kse, kse->k_kseg);
+ KSE_LOCK_ACQUIRE(kse, &kse_lock);
+ kse_free_unlocked(kse);
+ KSE_LOCK_RELEASE(kse, &kse_lock);
+ /* Make sure there is always at least one is awake */
+ KSE_WAKEUP(_kse_initial);
+ kse_exit();
+ /* Never returns. */
+ PANIC("kse_exit() failed for initial kseg");
+ }
+ KSE_SCHED_LOCK(kse, kse->k_kseg);
+ KSE_SET_IDLE(kse);
+ kse->k_kseg->kg_idle_kses++;
+ KSE_SCHED_UNLOCK(kse, kse->k_kseg);
+ ts.tv_sec = 120;
+ ts.tv_nsec = 0;
+ kse->k_kcb->kcb_kmbx.km_flags = 0;
+ kse_release(&ts);
+ /* Never reach */
+ }
+}
+
+void
+_thr_set_timeout(const struct timespec *timeout)
+{
+ struct pthread *curthread = _get_curthread();
+ struct timespec ts;
+
+ /* Reset the timeout flag for the running thread: */
+ curthread->timeout = 0;
+
+ /* Check if the thread is to wait forever: */
+ if (timeout == NULL) {
+ /*
+ * Set the wakeup time to something that can be recognised as
+ * different to an actual time of day:
+ */
+ curthread->wakeup_time.tv_sec = -1;
+ curthread->wakeup_time.tv_nsec = -1;
+ }
+ /* Check if no waiting is required: */
+ else if ((timeout->tv_sec == 0) && (timeout->tv_nsec == 0)) {
+ /* Set the wake up time to 'immediately': */
+ curthread->wakeup_time.tv_sec = 0;
+ curthread->wakeup_time.tv_nsec = 0;
+ } else {
+ /* Calculate the time for the current thread to wakeup: */
+ KSE_GET_TOD(curthread->kse, &ts);
+ TIMESPEC_ADD(&curthread->wakeup_time, &ts, timeout);
+ }
+}
+
+void
+_thr_panic_exit(char *file, int line, char *msg)
+{
+ char buf[256];
+
+ snprintf(buf, sizeof(buf), "(%s:%d) %s\n", file, line, msg);
+ __sys_write(2, buf, strlen(buf));
+ abort();
+}
+
+void
+_thr_setrunnable(struct pthread *curthread, struct pthread *thread)
+{
+ kse_critical_t crit;
+ struct kse_mailbox *kmbx;
+
+ crit = _kse_critical_enter();
+ KSE_SCHED_LOCK(curthread->kse, thread->kseg);
+ kmbx = _thr_setrunnable_unlocked(thread);
+ KSE_SCHED_UNLOCK(curthread->kse, thread->kseg);
+ _kse_critical_leave(crit);
+ if ((kmbx != NULL) && (__isthreaded != 0))
+ kse_wakeup(kmbx);
+}
+
+struct kse_mailbox *
+_thr_setrunnable_unlocked(struct pthread *thread)
+{
+ struct kse_mailbox *kmbx = NULL;
+
+ if ((thread->kseg->kg_flags & KGF_SINGLE_THREAD) != 0) {
+ /* No silly queues for these threads. */
+ if ((thread->flags & THR_FLAGS_SUSPENDED) != 0)
+ THR_SET_STATE(thread, PS_SUSPENDED);
+ else {
+ THR_SET_STATE(thread, PS_RUNNING);
+ kmbx = kse_wakeup_one(thread);
+ }
+
+ } else if (thread->state != PS_RUNNING) {
+ if ((thread->flags & THR_FLAGS_IN_WAITQ) != 0)
+ KSE_WAITQ_REMOVE(thread->kse, thread);
+ if ((thread->flags & THR_FLAGS_SUSPENDED) != 0)
+ THR_SET_STATE(thread, PS_SUSPENDED);
+ else {
+ THR_SET_STATE(thread, PS_RUNNING);
+ if ((thread->blocked == 0) && (thread->active == 0) &&
+ (thread->flags & THR_FLAGS_IN_RUNQ) == 0)
+ THR_RUNQ_INSERT_TAIL(thread);
+ /*
+ * XXX - Threads are not yet assigned to specific
+ * KSEs; they are assigned to the KSEG. So
+ * the fact that a thread's KSE is waiting
+ * doesn't necessarily mean that it will be
+ * the KSE that runs the thread after the
+ * lock is granted. But we don't know if the
+ * other KSEs within the same KSEG are also
+ * in a waiting state or not so we err on the
+ * side of caution and wakeup the thread's
+ * last known KSE. We ensure that the
+ * threads KSE doesn't change while it's
+ * scheduling lock is held so it is safe to
+ * reference it (the KSE). If the KSE wakes
+ * up and doesn't find any more work it will
+ * again go back to waiting so no harm is
+ * done.
+ */
+ kmbx = kse_wakeup_one(thread);
+ }
+ }
+ return (kmbx);
+}
+
+static struct kse_mailbox *
+kse_wakeup_one(struct pthread *thread)
+{
+ struct kse *ke;
+
+ if (KSE_IS_IDLE(thread->kse)) {
+ KSE_CLEAR_IDLE(thread->kse);
+ thread->kseg->kg_idle_kses--;
+ return (&thread->kse->k_kcb->kcb_kmbx);
+ } else {
+ TAILQ_FOREACH(ke, &thread->kseg->kg_kseq, k_kgqe) {
+ if (KSE_IS_IDLE(ke)) {
+ KSE_CLEAR_IDLE(ke);
+ ke->k_kseg->kg_idle_kses--;
+ return (&ke->k_kcb->kcb_kmbx);
+ }
+ }
+ }
+ return (NULL);
+}
+
+static void
+kse_wakeup_multi(struct kse *curkse)
+{
+ struct kse *ke;
+ int tmp;
+
+ if ((tmp = KSE_RUNQ_THREADS(curkse)) && curkse->k_kseg->kg_idle_kses) {
+ TAILQ_FOREACH(ke, &curkse->k_kseg->kg_kseq, k_kgqe) {
+ if (KSE_IS_IDLE(ke)) {
+ KSE_CLEAR_IDLE(ke);
+ ke->k_kseg->kg_idle_kses--;
+ KSE_WAKEUP(ke);
+ if (--tmp == 0)
+ break;
+ }
+ }
+ }
+}
+
+/*
+ * Allocate a new KSEG.
+ *
+ * We allow the current thread to be NULL in the case that this
+ * is the first time a KSEG is being created (library initialization).
+ * In this case, we don't need to (and can't) take any locks.
+ */
+struct kse_group *
+_kseg_alloc(struct pthread *curthread)
+{
+ struct kse_group *kseg = NULL;
+ kse_critical_t crit;
+
+ if ((curthread != NULL) && (free_kseg_count > 0)) {
+ /* Use the kse lock for the kseg queue. */
+ crit = _kse_critical_enter();
+ KSE_LOCK_ACQUIRE(curthread->kse, &kse_lock);
+ if ((kseg = TAILQ_FIRST(&free_kse_groupq)) != NULL) {
+ TAILQ_REMOVE(&free_kse_groupq, kseg, kg_qe);
+ free_kseg_count--;
+ active_kseg_count++;
+ TAILQ_INSERT_TAIL(&active_kse_groupq, kseg, kg_qe);
+ }
+ KSE_LOCK_RELEASE(curthread->kse, &kse_lock);
+ _kse_critical_leave(crit);
+ if (kseg)
+ kseg_reinit(kseg);
+ }
+
+ /*
+ * If requested, attempt to allocate a new KSE group only if the
+ * KSE allocation was successful and a KSE group wasn't found in
+ * the free list.
+ */
+ if ((kseg == NULL) &&
+ ((kseg = (struct kse_group *)malloc(sizeof(*kseg))) != NULL)) {
+ if (_pq_alloc(&kseg->kg_schedq.sq_runq,
+ THR_MIN_PRIORITY, THR_LAST_PRIORITY) != 0) {
+ free(kseg);
+ kseg = NULL;
+ } else {
+ kseg_init(kseg);
+ /* Add the KSEG to the list of active KSEGs. */
+ if (curthread != NULL) {
+ crit = _kse_critical_enter();
+ KSE_LOCK_ACQUIRE(curthread->kse, &kse_lock);
+ active_kseg_count++;
+ TAILQ_INSERT_TAIL(&active_kse_groupq,
+ kseg, kg_qe);
+ KSE_LOCK_RELEASE(curthread->kse, &kse_lock);
+ _kse_critical_leave(crit);
+ } else {
+ active_kseg_count++;
+ TAILQ_INSERT_TAIL(&active_kse_groupq,
+ kseg, kg_qe);
+ }
+ }
+ }
+ return (kseg);
+}
+
+static void
+kseg_init(struct kse_group *kseg)
+{
+ kseg_reinit(kseg);
+ _lock_init(&kseg->kg_lock, LCK_ADAPTIVE, _kse_lock_wait,
+ _kse_lock_wakeup);
+}
+
+static void
+kseg_reinit(struct kse_group *kseg)
+{
+ TAILQ_INIT(&kseg->kg_kseq);
+ TAILQ_INIT(&kseg->kg_threadq);
+ TAILQ_INIT(&kseg->kg_schedq.sq_waitq);
+ kseg->kg_threadcount = 0;
+ kseg->kg_ksecount = 0;
+ kseg->kg_idle_kses = 0;
+ kseg->kg_flags = 0;
+}
+
+/*
+ * This must be called with the kse lock held and when there are
+ * no more threads that reference it.
+ */
+static void
+kseg_free_unlocked(struct kse_group *kseg)
+{
+ TAILQ_REMOVE(&active_kse_groupq, kseg, kg_qe);
+ TAILQ_INSERT_HEAD(&free_kse_groupq, kseg, kg_qe);
+ free_kseg_count++;
+ active_kseg_count--;
+}
+
+void
+_kseg_free(struct kse_group *kseg)
+{
+ struct kse *curkse;
+ kse_critical_t crit;
+
+ crit = _kse_critical_enter();
+ curkse = _get_curkse();
+ KSE_LOCK_ACQUIRE(curkse, &kse_lock);
+ kseg_free_unlocked(kseg);
+ KSE_LOCK_RELEASE(curkse, &kse_lock);
+ _kse_critical_leave(crit);
+}
+
+static void
+kseg_destroy(struct kse_group *kseg)
+{
+ _lock_destroy(&kseg->kg_lock);
+ _pq_free(&kseg->kg_schedq.sq_runq);
+ free(kseg);
+}
+
+/*
+ * Allocate a new KSE.
+ *
+ * We allow the current thread to be NULL in the case that this
+ * is the first time a KSE is being created (library initialization).
+ * In this case, we don't need to (and can't) take any locks.
+ */
+struct kse *
+_kse_alloc(struct pthread *curthread, int sys_scope)
+{
+ struct kse *kse = NULL;
+ char *stack;
+ kse_critical_t crit;
+ int i;
+
+ if ((curthread != NULL) && (free_kse_count > 0)) {
+ crit = _kse_critical_enter();
+ KSE_LOCK_ACQUIRE(curthread->kse, &kse_lock);
+ /* Search for a finished KSE. */
+ kse = TAILQ_FIRST(&free_kseq);
+ while ((kse != NULL) &&
+ ((kse->k_kcb->kcb_kmbx.km_flags & KMF_DONE) == 0)) {
+ kse = TAILQ_NEXT(kse, k_qe);
+ }
+ if (kse != NULL) {
+ DBG_MSG("found an unused kse.\n");
+ TAILQ_REMOVE(&free_kseq, kse, k_qe);
+ free_kse_count--;
+ TAILQ_INSERT_TAIL(&active_kseq, kse, k_qe);
+ active_kse_count++;
+ }
+ KSE_LOCK_RELEASE(curthread->kse, &kse_lock);
+ _kse_critical_leave(crit);
+ if (kse != NULL)
+ kse_reinit(kse, sys_scope);
+ }
+ if ((kse == NULL) &&
+ ((kse = (struct kse *)malloc(sizeof(*kse))) != NULL)) {
+ if (sys_scope != 0)
+ stack = NULL;
+ else if ((stack = malloc(KSE_STACKSIZE)) == NULL) {
+ free(kse);
+ return (NULL);
+ }
+ bzero(kse, sizeof(*kse));
+
+ /* Initialize KCB without the lock. */
+ if ((kse->k_kcb = _kcb_ctor(kse)) == NULL) {
+ if (stack != NULL)
+ free(stack);
+ free(kse);
+ return (NULL);
+ }
+
+ /* Initialize the lockusers. */
+ for (i = 0; i < MAX_KSE_LOCKLEVEL; i++) {
+ _lockuser_init(&kse->k_lockusers[i], (void *)kse);
+ _LCK_SET_PRIVATE2(&kse->k_lockusers[i], NULL);
+ }
+ /* _lock_init(kse->k_lock, ...) */
+
+ if (curthread != NULL) {
+ crit = _kse_critical_enter();
+ KSE_LOCK_ACQUIRE(curthread->kse, &kse_lock);
+ }
+ kse->k_flags = 0;
+ TAILQ_INSERT_TAIL(&active_kseq, kse, k_qe);
+ active_kse_count++;
+ if (curthread != NULL) {
+ KSE_LOCK_RELEASE(curthread->kse, &kse_lock);
+ _kse_critical_leave(crit);
+ }
+ /*
+ * Create the KSE context.
+ * Scope system threads (one thread per KSE) are not required
+ * to have a stack for an unneeded kse upcall.
+ */
+ if (!sys_scope) {
+ kse->k_kcb->kcb_kmbx.km_func = (kse_func_t *)kse_sched_multi;
+ kse->k_stack.ss_sp = stack;
+ kse->k_stack.ss_size = KSE_STACKSIZE;
+ } else {
+ kse->k_kcb->kcb_kmbx.km_func = (kse_func_t *)kse_sched_single;
+ kse->k_stack.ss_sp = NULL;
+ kse->k_stack.ss_size = 0;
+ }
+ kse->k_kcb->kcb_kmbx.km_udata = (void *)kse;
+ kse->k_kcb->kcb_kmbx.km_quantum = 20000;
+ /*
+ * We need to keep a copy of the stack in case it
+ * doesn't get used; a KSE running a scope system
+ * thread will use that thread's stack.
+ */
+ kse->k_kcb->kcb_kmbx.km_stack = kse->k_stack;
+ }
+ return (kse);
+}
+
+static void
+kse_reinit(struct kse *kse, int sys_scope)
+{
+ if (!sys_scope) {
+ kse->k_kcb->kcb_kmbx.km_func = (kse_func_t *)kse_sched_multi;
+ if (kse->k_stack.ss_sp == NULL) {
+ /* XXX check allocation failure */
+ kse->k_stack.ss_sp = (char *) malloc(KSE_STACKSIZE);
+ kse->k_stack.ss_size = KSE_STACKSIZE;
+ }
+ kse->k_kcb->kcb_kmbx.km_quantum = 20000;
+ } else {
+ kse->k_kcb->kcb_kmbx.km_func = (kse_func_t *)kse_sched_single;
+ if (kse->k_stack.ss_sp)
+ free(kse->k_stack.ss_sp);
+ kse->k_stack.ss_sp = NULL;
+ kse->k_stack.ss_size = 0;
+ kse->k_kcb->kcb_kmbx.km_quantum = 0;
+ }
+ kse->k_kcb->kcb_kmbx.km_stack = kse->k_stack;
+ kse->k_kcb->kcb_kmbx.km_udata = (void *)kse;
+ kse->k_kcb->kcb_kmbx.km_curthread = NULL;
+ kse->k_kcb->kcb_kmbx.km_flags = 0;
+ kse->k_curthread = NULL;
+ kse->k_kseg = 0;
+ kse->k_schedq = 0;
+ kse->k_locklevel = 0;
+ kse->k_flags = 0;
+ kse->k_error = 0;
+ kse->k_cpu = 0;
+ kse->k_sigseqno = 0;
+}
+
+void
+kse_free_unlocked(struct kse *kse)
+{
+ TAILQ_REMOVE(&active_kseq, kse, k_qe);
+ active_kse_count--;
+ kse->k_kseg = NULL;
+ kse->k_kcb->kcb_kmbx.km_quantum = 20000;
+ kse->k_flags = 0;
+ TAILQ_INSERT_HEAD(&free_kseq, kse, k_qe);
+ free_kse_count++;
+}
+
+void
+_kse_free(struct pthread *curthread, struct kse *kse)
+{
+ kse_critical_t crit;
+
+ if (curthread == NULL)
+ kse_free_unlocked(kse);
+ else {
+ crit = _kse_critical_enter();
+ KSE_LOCK_ACQUIRE(curthread->kse, &kse_lock);
+ kse_free_unlocked(kse);
+ KSE_LOCK_RELEASE(curthread->kse, &kse_lock);
+ _kse_critical_leave(crit);
+ }
+}
+
+static void
+kse_destroy(struct kse *kse)
+{
+ int i;
+
+ if (kse->k_stack.ss_sp != NULL)
+ free(kse->k_stack.ss_sp);
+ _kcb_dtor(kse->k_kcb);
+ for (i = 0; i < MAX_KSE_LOCKLEVEL; ++i)
+ _lockuser_destroy(&kse->k_lockusers[i]);
+ _lock_destroy(&kse->k_lock);
+ free(kse);
+}
+
+struct pthread *
+_thr_alloc(struct pthread *curthread)
+{
+ kse_critical_t crit;
+ struct pthread *thread = NULL;
+ int i;
+
+ if (curthread != NULL) {
+ if (GC_NEEDED())
+ _thr_gc(curthread);
+ if (free_thread_count > 0) {
+ crit = _kse_critical_enter();
+ KSE_LOCK_ACQUIRE(curthread->kse, &thread_lock);
+ if ((thread = TAILQ_FIRST(&free_threadq)) != NULL) {
+ TAILQ_REMOVE(&free_threadq, thread, tle);
+ free_thread_count--;
+ }
+ KSE_LOCK_RELEASE(curthread->kse, &thread_lock);
+ _kse_critical_leave(crit);
+ }
+ }
+ if ((thread == NULL) &&
+ ((thread = malloc(sizeof(struct pthread))) != NULL)) {
+ bzero(thread, sizeof(struct pthread));
+ thread->siginfo = calloc(_SIG_MAXSIG, sizeof(siginfo_t));
+ if (thread->siginfo == NULL) {
+ free(thread);
+ return (NULL);
+ }
+ if (curthread) {
+ _pthread_mutex_lock(&_tcb_mutex);
+ thread->tcb = _tcb_ctor(thread, 0 /* not initial tls */);
+ _pthread_mutex_unlock(&_tcb_mutex);
+ } else {
+ thread->tcb = _tcb_ctor(thread, 1 /* initial tls */);
+ }
+ if (thread->tcb == NULL) {
+ free(thread->siginfo);
+ free(thread);
+ return (NULL);
+ }
+ /*
+ * Initialize thread locking.
+ * Lock initializing needs malloc, so don't
+ * enter critical region before doing this!
+ */
+ if (_lock_init(&thread->lock, LCK_ADAPTIVE,
+ _thr_lock_wait, _thr_lock_wakeup) != 0)
+ PANIC("Cannot initialize thread lock");
+ for (i = 0; i < MAX_THR_LOCKLEVEL; i++) {
+ _lockuser_init(&thread->lockusers[i], (void *)thread);
+ _LCK_SET_PRIVATE2(&thread->lockusers[i],
+ (void *)thread);
+ }
+ }
+ return (thread);
+}
+
+void
+_thr_free(struct pthread *curthread, struct pthread *thread)
+{
+ kse_critical_t crit;
+
+ DBG_MSG("Freeing thread %p\n", thread);
+ if (thread->name) {
+ free(thread->name);
+ thread->name = NULL;
+ }
+ if ((curthread == NULL) || (free_thread_count >= MAX_CACHED_THREADS)) {
+ thr_destroy(curthread, thread);
+ } else {
+ /* Add the thread to the free thread list. */
+ crit = _kse_critical_enter();
+ KSE_LOCK_ACQUIRE(curthread->kse, &thread_lock);
+ TAILQ_INSERT_TAIL(&free_threadq, thread, tle);
+ free_thread_count++;
+ KSE_LOCK_RELEASE(curthread->kse, &thread_lock);
+ _kse_critical_leave(crit);
+ }
+}
+
+static void
+thr_destroy(struct pthread *curthread, struct pthread *thread)
+{
+ int i;
+
+ for (i = 0; i < MAX_THR_LOCKLEVEL; i++)
+ _lockuser_destroy(&thread->lockusers[i]);
+ _lock_destroy(&thread->lock);
+ if (curthread) {
+ _pthread_mutex_lock(&_tcb_mutex);
+ _tcb_dtor(thread->tcb);
+ _pthread_mutex_unlock(&_tcb_mutex);
+ } else {
+ _tcb_dtor(thread->tcb);
+ }
+ free(thread->siginfo);
+ free(thread);
+}
+
+/*
+ * Add an active thread:
+ *
+ * o Assign the thread a unique id (which GDB uses to track
+ * threads.
+ * o Add the thread to the list of all threads and increment
+ * number of active threads.
+ */
+static void
+thr_link(struct pthread *thread)
+{
+ kse_critical_t crit;
+ struct kse *curkse;
+
+ crit = _kse_critical_enter();
+ curkse = _get_curkse();
+ KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock);
+ /*
+ * Initialize the unique id (which GDB uses to track
+ * threads), add the thread to the list of all threads,
+ * and
+ */
+ thread->uniqueid = next_uniqueid++;
+ THR_LIST_ADD(thread);
+ _thread_active_threads++;
+ KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
+ _kse_critical_leave(crit);
+}
+
+/*
+ * Remove an active thread.
+ */
+static void
+thr_unlink(struct pthread *thread)
+{
+ kse_critical_t crit;
+ struct kse *curkse;
+
+ crit = _kse_critical_enter();
+ curkse = _get_curkse();
+ KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock);
+ THR_LIST_REMOVE(thread);
+ _thread_active_threads--;
+ KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
+ _kse_critical_leave(crit);
+}
+
+void
+_thr_hash_add(struct pthread *thread)
+{
+ struct thread_hash_head *head;
+
+ head = &thr_hashtable[THREAD_HASH(thread)];
+ LIST_INSERT_HEAD(head, thread, hle);
+}
+
+void
+_thr_hash_remove(struct pthread *thread)
+{
+ LIST_REMOVE(thread, hle);
+}
+
+struct pthread *
+_thr_hash_find(struct pthread *thread)
+{
+ struct pthread *td;
+ struct thread_hash_head *head;
+
+ head = &thr_hashtable[THREAD_HASH(thread)];
+ LIST_FOREACH(td, head, hle) {
+ if (td == thread)
+ return (thread);
+ }
+ return (NULL);
+}
+
+void
+_thr_debug_check_yield(struct pthread *curthread)
+{
+ /*
+ * Note that TMDF_SUSPEND is set after process is suspended.
+ * When we are being debugged, every suspension in process
+ * will cause all KSEs to schedule an upcall in kernel, unless the
+ * KSE is in critical region.
+ * If the function is being called, it means the KSE is no longer
+ * in critical region, if the TMDF_SUSPEND is set by debugger
+ * before KSE leaves critical region, we will catch it here, else
+ * if the flag is changed during testing, it also not a problem,
+ * because the change only occurs after a process suspension event
+ * occurs. A suspension event will always cause KSE to schedule an
+ * upcall, in the case, because we are not in critical region,
+ * upcall will be scheduled sucessfully, the flag will be checked
+ * again in kse_sched_multi, we won't back until the flag
+ * is cleared by debugger, the flag will be cleared in next
+ * suspension event.
+ */
+ if (!DBG_CAN_RUN(curthread)) {
+ if ((curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) == 0)
+ _thr_sched_switch(curthread);
+ else
+ kse_thr_interrupt(&curthread->tcb->tcb_tmbx,
+ KSE_INTR_DBSUSPEND, 0);
+ }
+}
diff --git a/lib/libpthread/thread/thr_kill.c b/lib/libpthread/thread/thr_kill.c
new file mode 100644
index 0000000..a03ec38
--- /dev/null
+++ b/lib/libpthread/thread/thr_kill.c
@@ -0,0 +1,69 @@
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <signal.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_kill);
+LT10_COMPAT_DEFAULT(pthread_kill);
+
+__weak_reference(_pthread_kill, pthread_kill);
+
+int
+_pthread_kill(pthread_t pthread, int sig)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ /* Check for invalid signal numbers: */
+ if (sig < 0 || sig > _SIG_MAXSIG)
+ /* Invalid signal: */
+ ret = EINVAL;
+ /*
+ * Ensure the thread is in the list of active threads, and the
+ * signal is valid (signal 0 specifies error checking only) and
+ * not being ignored:
+ */
+ else if ((ret = _thr_ref_add(curthread, pthread, /*include dead*/0))
+ == 0) {
+ if ((sig > 0) &&
+ (_thread_sigact[sig - 1].sa_handler != SIG_IGN))
+ _thr_sig_send(pthread, sig);
+ _thr_ref_delete(curthread, pthread);
+ }
+
+ /* Return the completion status: */
+ return (ret);
+}
diff --git a/lib/libpthread/thread/thr_main_np.c b/lib/libpthread/thread/thr_main_np.c
new file mode 100644
index 0000000..50fb9c8
--- /dev/null
+++ b/lib/libpthread/thread/thr_main_np.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2001 Alfred Perlstein
+ * Author: Alfred Perlstein <alfred@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 <pthread.h>
+#include <pthread_np.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_main_np);
+LT10_COMPAT_DEFAULT(pthread_main_np);
+
+__weak_reference(_pthread_main_np, pthread_main_np);
+
+/*
+ * Provide the equivelant to Solaris thr_main() function
+ */
+int
+_pthread_main_np()
+{
+
+ if (!_thr_initial)
+ return (-1);
+ else
+ return (pthread_equal(pthread_self(), _thr_initial) ? 1 : 0);
+}
diff --git a/lib/libpthread/thread/thr_mattr_init.c b/lib/libpthread/thread/thr_mattr_init.c
new file mode 100644
index 0000000..b273bab
--- /dev/null
+++ b/lib/libpthread/thread/thr_mattr_init.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1996 Jeffrey Hsu <hsu@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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_mutexattr_init);
+LT10_COMPAT_DEFAULT(pthread_mutexattr_init);
+
+__weak_reference(_pthread_mutexattr_init, pthread_mutexattr_init);
+
+int
+_pthread_mutexattr_init(pthread_mutexattr_t *attr)
+{
+ int ret;
+ pthread_mutexattr_t pattr;
+
+ if ((pattr = (pthread_mutexattr_t)
+ malloc(sizeof(struct pthread_mutex_attr))) == NULL) {
+ ret = ENOMEM;
+ } else {
+ memcpy(pattr, &_pthread_mutexattr_default,
+ sizeof(struct pthread_mutex_attr));
+ *attr = pattr;
+ ret = 0;
+ }
+ return (ret);
+}
diff --git a/lib/libpthread/thread/thr_mattr_kind_np.c b/lib/libpthread/thread/thr_mattr_kind_np.c
new file mode 100644
index 0000000..12cd775
--- /dev/null
+++ b/lib/libpthread/thread/thr_mattr_kind_np.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 1996 Jeffrey Hsu <hsu@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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_mutexattr_setkind_np);
+LT10_COMPAT_DEFAULT(pthread_mutexattr_setkind_np);
+LT10_COMPAT_PRIVATE(_pthread_mutexattr_getkind_np);
+LT10_COMPAT_DEFAULT(pthread_mutexattr_getkind_np);
+LT10_COMPAT_PRIVATE(_pthread_mutexattr_gettype);
+LT10_COMPAT_DEFAULT(pthread_mutexattr_gettype);
+LT10_COMPAT_PRIVATE(_pthread_mutexattr_settype);
+LT10_COMPAT_DEFAULT(pthread_mutexattr_settype);
+
+__weak_reference(_pthread_mutexattr_setkind_np, pthread_mutexattr_setkind_np);
+__weak_reference(_pthread_mutexattr_getkind_np, pthread_mutexattr_getkind_np);
+__weak_reference(_pthread_mutexattr_gettype, pthread_mutexattr_gettype);
+__weak_reference(_pthread_mutexattr_settype, pthread_mutexattr_settype);
+
+int
+_pthread_mutexattr_setkind_np(pthread_mutexattr_t *attr, int kind)
+{
+ int ret;
+ if (attr == NULL || *attr == NULL) {
+ errno = EINVAL;
+ ret = -1;
+ } else {
+ (*attr)->m_type = kind;
+ ret = 0;
+ }
+ return(ret);
+}
+
+int
+_pthread_mutexattr_getkind_np(pthread_mutexattr_t attr)
+{
+ int ret;
+ if (attr == NULL) {
+ errno = EINVAL;
+ ret = -1;
+ } else {
+ ret = attr->m_type;
+ }
+ return(ret);
+}
+
+int
+_pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
+{
+ int ret;
+ if (attr == NULL || *attr == NULL || type >= PTHREAD_MUTEX_TYPE_MAX) {
+ errno = EINVAL;
+ ret = -1;
+ } else {
+ (*attr)->m_type = type;
+ ret = 0;
+ }
+ return(ret);
+}
+
+int
+_pthread_mutexattr_gettype(pthread_mutexattr_t *attr, int *type)
+{
+ int ret;
+
+ if (attr == NULL || *attr == NULL || (*attr)->m_type >=
+ PTHREAD_MUTEX_TYPE_MAX) {
+ ret = EINVAL;
+ } else {
+ *type = (*attr)->m_type;
+ ret = 0;
+ }
+ return ret;
+}
diff --git a/lib/libpthread/thread/thr_mattr_pshared.c b/lib/libpthread/thread/thr_mattr_pshared.c
new file mode 100644
index 0000000..03aff41
--- /dev/null
+++ b/lib/libpthread/thread/thr_mattr_pshared.c
@@ -0,0 +1,56 @@
+/*
+ * 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 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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, 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$
+ *
+ */
+
+#include <errno.h>
+#include "thr_private.h"
+
+__weak_reference(_pthread_mutexattr_getpshared, pthread_mutexattr_getpshared);
+__weak_reference(_pthread_mutexattr_setpshared, pthread_mutexattr_setpshared);
+
+int
+_pthread_mutexattr_getpshared(const pthread_mutexattr_t *attr,
+ int *pshared)
+{
+ if (attr == NULL || *attr == NULL)
+ return (EINVAL);
+
+ pshared = PTHREAD_PROCESS_PRIVATE;
+ return (0);
+}
+
+int
+_pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared)
+{
+ if (attr == NULL || *attr == NULL)
+ return (EINVAL);
+
+ if (pshared != PTHREAD_PROCESS_PRIVATE)
+ return (EINVAL);
+ return (0);
+}
diff --git a/lib/libpthread/thread/thr_msync.c b/lib/libpthread/thread/thr_msync.c
new file mode 100644
index 0000000..66e88c5
--- /dev/null
+++ b/lib/libpthread/thread/thr_msync.c
@@ -0,0 +1,36 @@
+/*
+ * David Leonard <d@openbsd.org>, 1999. Public Domain.
+ *
+ * $OpenBSD: uthread_msync.c,v 1.2 1999/06/09 07:16:17 d Exp $
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__msync);
+LT10_COMPAT_DEFAULT(msync);
+
+__weak_reference(__msync, msync);
+
+int
+__msync(void *addr, size_t len, int flags)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ /*
+ * XXX This is quite pointless unless we know how to get the
+ * file descriptor associated with the memory, and lock it for
+ * write. The only real use of this wrapper is to guarantee
+ * a cancellation point, as per the standard. sigh.
+ */
+ _thr_cancel_enter(curthread);
+ ret = __sys_msync(addr, len, flags);
+ _thr_cancel_leave(curthread, 1);
+
+ return ret;
+}
diff --git a/lib/libpthread/thread/thr_multi_np.c b/lib/libpthread/thread/thr_multi_np.c
new file mode 100644
index 0000000..54ce22c
--- /dev/null
+++ b/lib/libpthread/thread/thr_multi_np.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 1996 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <pthread_np.h>
+
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_multi_np);
+LT10_COMPAT_DEFAULT(pthread_multi_np);
+
+__weak_reference(_pthread_multi_np, pthread_multi_np);
+
+int
+_pthread_multi_np()
+{
+
+ /* Return to multi-threaded scheduling mode: */
+ /*
+ * XXX - Do we want to do this?
+ * __is_threaded = 1;
+ */
+ pthread_resume_all_np();
+ return (0);
+}
diff --git a/lib/libpthread/thread/thr_mutex.c b/lib/libpthread/thread/thr_mutex.c
new file mode 100644
index 0000000..6383cd8
--- /dev/null
+++ b/lib/libpthread/thread/thr_mutex.c
@@ -0,0 +1,1832 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <errno.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+#if defined(_PTHREADS_INVARIANTS)
+#define MUTEX_INIT_LINK(m) do { \
+ (m)->m_qe.tqe_prev = NULL; \
+ (m)->m_qe.tqe_next = NULL; \
+} while (0)
+#define MUTEX_ASSERT_IS_OWNED(m) do { \
+ if ((m)->m_qe.tqe_prev == NULL) \
+ PANIC("mutex is not on list"); \
+} while (0)
+#define MUTEX_ASSERT_NOT_OWNED(m) do { \
+ if (((m)->m_qe.tqe_prev != NULL) || \
+ ((m)->m_qe.tqe_next != NULL)) \
+ PANIC("mutex is on list"); \
+} while (0)
+#define THR_ASSERT_NOT_IN_SYNCQ(thr) do { \
+ THR_ASSERT(((thr)->sflags & THR_FLAGS_IN_SYNCQ) == 0, \
+ "thread in syncq when it shouldn't be."); \
+} while (0);
+#else
+#define MUTEX_INIT_LINK(m)
+#define MUTEX_ASSERT_IS_OWNED(m)
+#define MUTEX_ASSERT_NOT_OWNED(m)
+#define THR_ASSERT_NOT_IN_SYNCQ(thr)
+#endif
+
+#define THR_IN_MUTEXQ(thr) (((thr)->sflags & THR_FLAGS_IN_SYNCQ) != 0)
+#define MUTEX_DESTROY(m) do { \
+ _lock_destroy(&(m)->m_lock); \
+ free(m); \
+} while (0)
+
+
+/*
+ * Prototypes
+ */
+static struct kse_mailbox *mutex_handoff(struct pthread *,
+ struct pthread_mutex *);
+static inline int mutex_self_trylock(struct pthread *, pthread_mutex_t);
+static inline int mutex_self_lock(struct pthread *, pthread_mutex_t);
+static int mutex_unlock_common(pthread_mutex_t *, int);
+static void mutex_priority_adjust(struct pthread *, pthread_mutex_t);
+static void mutex_rescan_owned (struct pthread *, struct pthread *,
+ struct pthread_mutex *);
+static inline pthread_t mutex_queue_deq(pthread_mutex_t);
+static inline void mutex_queue_remove(pthread_mutex_t, pthread_t);
+static inline void mutex_queue_enq(pthread_mutex_t, pthread_t);
+static void mutex_lock_backout(void *arg);
+
+static struct pthread_mutex_attr static_mutex_attr =
+ PTHREAD_MUTEXATTR_STATIC_INITIALIZER;
+static pthread_mutexattr_t static_mattr = &static_mutex_attr;
+
+LT10_COMPAT_PRIVATE(__pthread_mutex_init);
+LT10_COMPAT_PRIVATE(_pthread_mutex_init);
+LT10_COMPAT_DEFAULT(pthread_mutex_init);
+LT10_COMPAT_PRIVATE(__pthread_mutex_lock);
+LT10_COMPAT_PRIVATE(_pthread_mutex_lock);
+LT10_COMPAT_DEFAULT(pthread_mutex_lock);
+LT10_COMPAT_PRIVATE(__pthread_mutex_timedlock);
+LT10_COMPAT_PRIVATE(_pthread_mutex_timedlock);
+LT10_COMPAT_DEFAULT(pthread_mutex_timedlock);
+LT10_COMPAT_PRIVATE(__pthread_mutex_trylock);
+LT10_COMPAT_PRIVATE(_pthread_mutex_trylock);
+LT10_COMPAT_DEFAULT(pthread_mutex_trylock);
+LT10_COMPAT_PRIVATE(_pthread_mutex_destroy);
+LT10_COMPAT_DEFAULT(pthread_mutex_destroy);
+LT10_COMPAT_PRIVATE(_pthread_mutex_unlock);
+LT10_COMPAT_DEFAULT(pthread_mutex_unlock);
+
+/* Single underscore versions provided for libc internal usage: */
+__weak_reference(__pthread_mutex_init, pthread_mutex_init);
+__weak_reference(__pthread_mutex_lock, pthread_mutex_lock);
+__weak_reference(__pthread_mutex_timedlock, pthread_mutex_timedlock);
+__weak_reference(__pthread_mutex_trylock, pthread_mutex_trylock);
+
+/* No difference between libc and application usage of these: */
+__weak_reference(_pthread_mutex_destroy, pthread_mutex_destroy);
+__weak_reference(_pthread_mutex_unlock, pthread_mutex_unlock);
+
+
+
+int
+__pthread_mutex_init(pthread_mutex_t *mutex,
+ const pthread_mutexattr_t *mutex_attr)
+{
+ struct pthread_mutex *pmutex;
+ enum pthread_mutextype type;
+ int protocol;
+ int ceiling;
+ int flags;
+ int ret = 0;
+
+ if (mutex == NULL)
+ ret = EINVAL;
+
+ /* Check if default mutex attributes: */
+ else if (mutex_attr == NULL || *mutex_attr == NULL) {
+ /* Default to a (error checking) POSIX mutex: */
+ type = PTHREAD_MUTEX_ERRORCHECK;
+ protocol = PTHREAD_PRIO_NONE;
+ ceiling = THR_MAX_PRIORITY;
+ flags = 0;
+ }
+
+ /* Check mutex type: */
+ else if (((*mutex_attr)->m_type < PTHREAD_MUTEX_ERRORCHECK) ||
+ ((*mutex_attr)->m_type >= PTHREAD_MUTEX_TYPE_MAX))
+ /* Return an invalid argument error: */
+ ret = EINVAL;
+
+ /* Check mutex protocol: */
+ else if (((*mutex_attr)->m_protocol < PTHREAD_PRIO_NONE) ||
+ ((*mutex_attr)->m_protocol > PTHREAD_MUTEX_RECURSIVE))
+ /* Return an invalid argument error: */
+ ret = EINVAL;
+
+ else {
+ /* Use the requested mutex type and protocol: */
+ type = (*mutex_attr)->m_type;
+ protocol = (*mutex_attr)->m_protocol;
+ ceiling = (*mutex_attr)->m_ceiling;
+ flags = (*mutex_attr)->m_flags;
+ }
+
+ /* Check no errors so far: */
+ if (ret == 0) {
+ if ((pmutex = (pthread_mutex_t)
+ malloc(sizeof(struct pthread_mutex))) == NULL)
+ ret = ENOMEM;
+ else if (_lock_init(&pmutex->m_lock, LCK_ADAPTIVE,
+ _thr_lock_wait, _thr_lock_wakeup) != 0) {
+ free(pmutex);
+ *mutex = NULL;
+ ret = ENOMEM;
+ } else {
+ /* Set the mutex flags: */
+ pmutex->m_flags = flags;
+
+ /* Process according to mutex type: */
+ switch (type) {
+ /* case PTHREAD_MUTEX_DEFAULT: */
+ case PTHREAD_MUTEX_ERRORCHECK:
+ case PTHREAD_MUTEX_NORMAL:
+ /* Nothing to do here. */
+ break;
+
+ /* Single UNIX Spec 2 recursive mutex: */
+ case PTHREAD_MUTEX_RECURSIVE:
+ /* Reset the mutex count: */
+ pmutex->m_count = 0;
+ break;
+
+ /* Trap invalid mutex types: */
+ default:
+ /* Return an invalid argument error: */
+ ret = EINVAL;
+ break;
+ }
+ if (ret == 0) {
+ /* Initialise the rest of the mutex: */
+ TAILQ_INIT(&pmutex->m_queue);
+ pmutex->m_flags |= MUTEX_FLAGS_INITED;
+ pmutex->m_owner = NULL;
+ pmutex->m_type = type;
+ pmutex->m_protocol = protocol;
+ pmutex->m_refcount = 0;
+ if (protocol == PTHREAD_PRIO_PROTECT)
+ pmutex->m_prio = ceiling;
+ else
+ pmutex->m_prio = -1;
+ pmutex->m_saved_prio = 0;
+ MUTEX_INIT_LINK(pmutex);
+ *mutex = pmutex;
+ } else {
+ /* Free the mutex lock structure: */
+ MUTEX_DESTROY(pmutex);
+ *mutex = NULL;
+ }
+ }
+ }
+ /* Return the completion status: */
+ return (ret);
+}
+
+int
+_pthread_mutex_init(pthread_mutex_t *mutex,
+ const pthread_mutexattr_t *mutex_attr)
+{
+ struct pthread_mutex_attr mattr, *mattrp;
+
+ if ((mutex_attr == NULL) || (*mutex_attr == NULL))
+ return (__pthread_mutex_init(mutex, &static_mattr));
+ else {
+ mattr = **mutex_attr;
+ mattr.m_flags |= MUTEX_FLAGS_PRIVATE;
+ mattrp = &mattr;
+ return (__pthread_mutex_init(mutex, &mattrp));
+ }
+}
+
+void
+_thr_mutex_reinit(pthread_mutex_t *mutex)
+{
+ _lock_reinit(&(*mutex)->m_lock, LCK_ADAPTIVE,
+ _thr_lock_wait, _thr_lock_wakeup);
+ TAILQ_INIT(&(*mutex)->m_queue);
+ (*mutex)->m_owner = NULL;
+ (*mutex)->m_count = 0;
+ (*mutex)->m_refcount = 0;
+ (*mutex)->m_prio = 0;
+ (*mutex)->m_saved_prio = 0;
+}
+
+int
+_pthread_mutex_destroy(pthread_mutex_t *mutex)
+{
+ struct pthread *curthread = _get_curthread();
+ pthread_mutex_t m;
+ int ret = 0;
+
+ if (mutex == NULL || *mutex == NULL)
+ ret = EINVAL;
+ else {
+ /* Lock the mutex structure: */
+ THR_LOCK_ACQUIRE(curthread, &(*mutex)->m_lock);
+
+ /*
+ * Check to see if this mutex is in use:
+ */
+ if (((*mutex)->m_owner != NULL) ||
+ (!TAILQ_EMPTY(&(*mutex)->m_queue)) ||
+ ((*mutex)->m_refcount != 0)) {
+ ret = EBUSY;
+
+ /* Unlock the mutex structure: */
+ THR_LOCK_RELEASE(curthread, &(*mutex)->m_lock);
+ } else {
+ /*
+ * Save a pointer to the mutex so it can be free'd
+ * and set the caller's pointer to NULL:
+ */
+ m = *mutex;
+ *mutex = NULL;
+
+ /* Unlock the mutex structure: */
+ THR_LOCK_RELEASE(curthread, &m->m_lock);
+
+ /*
+ * Free the memory allocated for the mutex
+ * structure:
+ */
+ MUTEX_ASSERT_NOT_OWNED(m);
+ MUTEX_DESTROY(m);
+ }
+ }
+
+ /* Return the completion status: */
+ return (ret);
+}
+
+static int
+init_static(struct pthread *thread, pthread_mutex_t *mutex)
+{
+ int ret;
+
+ THR_LOCK_ACQUIRE(thread, &_mutex_static_lock);
+
+ if (*mutex == NULL)
+ ret = pthread_mutex_init(mutex, NULL);
+ else
+ ret = 0;
+
+ THR_LOCK_RELEASE(thread, &_mutex_static_lock);
+
+ return (ret);
+}
+
+static int
+init_static_private(struct pthread *thread, pthread_mutex_t *mutex)
+{
+ int ret;
+
+ THR_LOCK_ACQUIRE(thread, &_mutex_static_lock);
+
+ if (*mutex == NULL)
+ ret = pthread_mutex_init(mutex, &static_mattr);
+ else
+ ret = 0;
+
+ THR_LOCK_RELEASE(thread, &_mutex_static_lock);
+
+ return (ret);
+}
+
+static int
+mutex_trylock_common(struct pthread *curthread, pthread_mutex_t *mutex)
+{
+ int private;
+ int ret = 0;
+
+ THR_ASSERT((mutex != NULL) && (*mutex != NULL),
+ "Uninitialized mutex in pthread_mutex_trylock_basic");
+
+ /* Lock the mutex structure: */
+ THR_LOCK_ACQUIRE(curthread, &(*mutex)->m_lock);
+ private = (*mutex)->m_flags & MUTEX_FLAGS_PRIVATE;
+
+ /*
+ * If the mutex was statically allocated, properly
+ * initialize the tail queue.
+ */
+ if (((*mutex)->m_flags & MUTEX_FLAGS_INITED) == 0) {
+ TAILQ_INIT(&(*mutex)->m_queue);
+ MUTEX_INIT_LINK(*mutex);
+ (*mutex)->m_flags |= MUTEX_FLAGS_INITED;
+ }
+
+ /* Process according to mutex type: */
+ switch ((*mutex)->m_protocol) {
+ /* Default POSIX mutex: */
+ case PTHREAD_PRIO_NONE:
+ /* Check if this mutex is not locked: */
+ if ((*mutex)->m_owner == NULL) {
+ /* Lock the mutex for the running thread: */
+ (*mutex)->m_owner = curthread;
+
+ /* Add to the list of owned mutexes: */
+ MUTEX_ASSERT_NOT_OWNED(*mutex);
+ TAILQ_INSERT_TAIL(&curthread->mutexq,
+ (*mutex), m_qe);
+ } else if ((*mutex)->m_owner == curthread)
+ ret = mutex_self_trylock(curthread, *mutex);
+ else
+ /* Return a busy error: */
+ ret = EBUSY;
+ break;
+
+ /* POSIX priority inheritence mutex: */
+ case PTHREAD_PRIO_INHERIT:
+ /* Check if this mutex is not locked: */
+ if ((*mutex)->m_owner == NULL) {
+ /* Lock the mutex for the running thread: */
+ (*mutex)->m_owner = curthread;
+
+ THR_SCHED_LOCK(curthread, curthread);
+ /* Track number of priority mutexes owned: */
+ curthread->priority_mutex_count++;
+
+ /*
+ * The mutex takes on the attributes of the
+ * running thread when there are no waiters.
+ */
+ (*mutex)->m_prio = curthread->active_priority;
+ (*mutex)->m_saved_prio =
+ curthread->inherited_priority;
+ curthread->inherited_priority = (*mutex)->m_prio;
+ THR_SCHED_UNLOCK(curthread, curthread);
+
+ /* Add to the list of owned mutexes: */
+ MUTEX_ASSERT_NOT_OWNED(*mutex);
+ TAILQ_INSERT_TAIL(&curthread->mutexq,
+ (*mutex), m_qe);
+ } else if ((*mutex)->m_owner == curthread)
+ ret = mutex_self_trylock(curthread, *mutex);
+ else
+ /* Return a busy error: */
+ ret = EBUSY;
+ break;
+
+ /* POSIX priority protection mutex: */
+ case PTHREAD_PRIO_PROTECT:
+ /* Check for a priority ceiling violation: */
+ if (curthread->active_priority > (*mutex)->m_prio)
+ ret = EINVAL;
+
+ /* Check if this mutex is not locked: */
+ else if ((*mutex)->m_owner == NULL) {
+ /* Lock the mutex for the running thread: */
+ (*mutex)->m_owner = curthread;
+
+ THR_SCHED_LOCK(curthread, curthread);
+ /* Track number of priority mutexes owned: */
+ curthread->priority_mutex_count++;
+
+ /*
+ * The running thread inherits the ceiling
+ * priority of the mutex and executes at that
+ * priority.
+ */
+ curthread->active_priority = (*mutex)->m_prio;
+ (*mutex)->m_saved_prio =
+ curthread->inherited_priority;
+ curthread->inherited_priority =
+ (*mutex)->m_prio;
+ THR_SCHED_UNLOCK(curthread, curthread);
+ /* Add to the list of owned mutexes: */
+ MUTEX_ASSERT_NOT_OWNED(*mutex);
+ TAILQ_INSERT_TAIL(&curthread->mutexq,
+ (*mutex), m_qe);
+ } else if ((*mutex)->m_owner == curthread)
+ ret = mutex_self_trylock(curthread, *mutex);
+ else
+ /* Return a busy error: */
+ ret = EBUSY;
+ break;
+
+ /* Trap invalid mutex types: */
+ default:
+ /* Return an invalid argument error: */
+ ret = EINVAL;
+ break;
+ }
+
+ if (ret == 0 && private)
+ THR_CRITICAL_ENTER(curthread);
+
+ /* Unlock the mutex structure: */
+ THR_LOCK_RELEASE(curthread, &(*mutex)->m_lock);
+
+ /* Return the completion status: */
+ return (ret);
+}
+
+int
+__pthread_mutex_trylock(pthread_mutex_t *mutex)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret = 0;
+
+ if (mutex == NULL)
+ ret = EINVAL;
+
+ /*
+ * If the mutex is statically initialized, perform the dynamic
+ * initialization:
+ */
+ else if ((*mutex != NULL) ||
+ ((ret = init_static(curthread, mutex)) == 0))
+ ret = mutex_trylock_common(curthread, mutex);
+
+ return (ret);
+}
+
+int
+_pthread_mutex_trylock(pthread_mutex_t *mutex)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret = 0;
+
+ if (mutex == NULL)
+ ret = EINVAL;
+
+ /*
+ * If the mutex is statically initialized, perform the dynamic
+ * initialization marking the mutex private (delete safe):
+ */
+ else if ((*mutex != NULL) ||
+ ((ret = init_static_private(curthread, mutex)) == 0))
+ ret = mutex_trylock_common(curthread, mutex);
+
+ return (ret);
+}
+
+static int
+mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m,
+ const struct timespec * abstime)
+{
+ int private;
+ int ret = 0;
+
+ THR_ASSERT((m != NULL) && (*m != NULL),
+ "Uninitialized mutex in pthread_mutex_trylock_basic");
+
+ if (abstime != NULL && (abstime->tv_sec < 0 || abstime->tv_nsec < 0 ||
+ abstime->tv_nsec >= 1000000000))
+ return (EINVAL);
+
+ /* Reset the interrupted flag: */
+ curthread->interrupted = 0;
+ curthread->timeout = 0;
+ curthread->wakeup_time.tv_sec = -1;
+
+ private = (*m)->m_flags & MUTEX_FLAGS_PRIVATE;
+
+ /*
+ * Enter a loop waiting to become the mutex owner. We need a
+ * loop in case the waiting thread is interrupted by a signal
+ * to execute a signal handler. It is not (currently) possible
+ * to remain in the waiting queue while running a handler.
+ * Instead, the thread is interrupted and backed out of the
+ * waiting queue prior to executing the signal handler.
+ */
+ do {
+ /* Lock the mutex structure: */
+ THR_LOCK_ACQUIRE(curthread, &(*m)->m_lock);
+
+ /*
+ * If the mutex was statically allocated, properly
+ * initialize the tail queue.
+ */
+ if (((*m)->m_flags & MUTEX_FLAGS_INITED) == 0) {
+ TAILQ_INIT(&(*m)->m_queue);
+ (*m)->m_flags |= MUTEX_FLAGS_INITED;
+ MUTEX_INIT_LINK(*m);
+ }
+
+ /* Process according to mutex type: */
+ switch ((*m)->m_protocol) {
+ /* Default POSIX mutex: */
+ case PTHREAD_PRIO_NONE:
+ if ((*m)->m_owner == NULL) {
+ /* Lock the mutex for this thread: */
+ (*m)->m_owner = curthread;
+
+ /* Add to the list of owned mutexes: */
+ MUTEX_ASSERT_NOT_OWNED(*m);
+ TAILQ_INSERT_TAIL(&curthread->mutexq,
+ (*m), m_qe);
+ if (private)
+ THR_CRITICAL_ENTER(curthread);
+
+ /* Unlock the mutex structure: */
+ THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+ } else if ((*m)->m_owner == curthread) {
+ ret = mutex_self_lock(curthread, *m);
+
+ /* Unlock the mutex structure: */
+ THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+ } else {
+ /*
+ * Join the queue of threads waiting to lock
+ * the mutex and save a pointer to the mutex.
+ */
+ mutex_queue_enq(*m, curthread);
+ curthread->data.mutex = *m;
+ curthread->sigbackout = mutex_lock_backout;
+ /*
+ * This thread is active and is in a critical
+ * region (holding the mutex lock); we should
+ * be able to safely set the state.
+ */
+ THR_SCHED_LOCK(curthread, curthread);
+ /* Set the wakeup time: */
+ if (abstime) {
+ curthread->wakeup_time.tv_sec =
+ abstime->tv_sec;
+ curthread->wakeup_time.tv_nsec =
+ abstime->tv_nsec;
+ }
+
+ THR_SET_STATE(curthread, PS_MUTEX_WAIT);
+ THR_SCHED_UNLOCK(curthread, curthread);
+
+ /* Unlock the mutex structure: */
+ THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+
+ /* Schedule the next thread: */
+ _thr_sched_switch(curthread);
+
+ if (THR_IN_MUTEXQ(curthread)) {
+ THR_LOCK_ACQUIRE(curthread, &(*m)->m_lock);
+ mutex_queue_remove(*m, curthread);
+ THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+ }
+ /*
+ * Only clear these after assuring the
+ * thread is dequeued.
+ */
+ curthread->data.mutex = NULL;
+ curthread->sigbackout = NULL;
+ }
+ break;
+
+ /* POSIX priority inheritence mutex: */
+ case PTHREAD_PRIO_INHERIT:
+ /* Check if this mutex is not locked: */
+ if ((*m)->m_owner == NULL) {
+ /* Lock the mutex for this thread: */
+ (*m)->m_owner = curthread;
+
+ THR_SCHED_LOCK(curthread, curthread);
+ /* Track number of priority mutexes owned: */
+ curthread->priority_mutex_count++;
+
+ /*
+ * The mutex takes on attributes of the
+ * running thread when there are no waiters.
+ * Make sure the thread's scheduling lock is
+ * held while priorities are adjusted.
+ */
+ (*m)->m_prio = curthread->active_priority;
+ (*m)->m_saved_prio =
+ curthread->inherited_priority;
+ curthread->inherited_priority = (*m)->m_prio;
+ THR_SCHED_UNLOCK(curthread, curthread);
+
+ /* Add to the list of owned mutexes: */
+ MUTEX_ASSERT_NOT_OWNED(*m);
+ TAILQ_INSERT_TAIL(&curthread->mutexq,
+ (*m), m_qe);
+ if (private)
+ THR_CRITICAL_ENTER(curthread);
+
+ /* Unlock the mutex structure: */
+ THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+ } else if ((*m)->m_owner == curthread) {
+ ret = mutex_self_lock(curthread, *m);
+
+ /* Unlock the mutex structure: */
+ THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+ } else {
+ /*
+ * Join the queue of threads waiting to lock
+ * the mutex and save a pointer to the mutex.
+ */
+ mutex_queue_enq(*m, curthread);
+ curthread->data.mutex = *m;
+ curthread->sigbackout = mutex_lock_backout;
+
+ /*
+ * This thread is active and is in a critical
+ * region (holding the mutex lock); we should
+ * be able to safely set the state.
+ */
+ if (curthread->active_priority > (*m)->m_prio)
+ /* Adjust priorities: */
+ mutex_priority_adjust(curthread, *m);
+
+ THR_SCHED_LOCK(curthread, curthread);
+ /* Set the wakeup time: */
+ if (abstime) {
+ curthread->wakeup_time.tv_sec =
+ abstime->tv_sec;
+ curthread->wakeup_time.tv_nsec =
+ abstime->tv_nsec;
+ }
+ THR_SET_STATE(curthread, PS_MUTEX_WAIT);
+ THR_SCHED_UNLOCK(curthread, curthread);
+
+ /* Unlock the mutex structure: */
+ THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+
+ /* Schedule the next thread: */
+ _thr_sched_switch(curthread);
+
+ if (THR_IN_MUTEXQ(curthread)) {
+ THR_LOCK_ACQUIRE(curthread, &(*m)->m_lock);
+ mutex_queue_remove(*m, curthread);
+ THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+ }
+ /*
+ * Only clear these after assuring the
+ * thread is dequeued.
+ */
+ curthread->data.mutex = NULL;
+ curthread->sigbackout = NULL;
+ }
+ break;
+
+ /* POSIX priority protection mutex: */
+ case PTHREAD_PRIO_PROTECT:
+ /* Check for a priority ceiling violation: */
+ if (curthread->active_priority > (*m)->m_prio) {
+ /* Unlock the mutex structure: */
+ THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+ ret = EINVAL;
+ }
+ /* Check if this mutex is not locked: */
+ else if ((*m)->m_owner == NULL) {
+ /*
+ * Lock the mutex for the running
+ * thread:
+ */
+ (*m)->m_owner = curthread;
+
+ THR_SCHED_LOCK(curthread, curthread);
+ /* Track number of priority mutexes owned: */
+ curthread->priority_mutex_count++;
+
+ /*
+ * The running thread inherits the ceiling
+ * priority of the mutex and executes at that
+ * priority. Make sure the thread's
+ * scheduling lock is held while priorities
+ * are adjusted.
+ */
+ curthread->active_priority = (*m)->m_prio;
+ (*m)->m_saved_prio =
+ curthread->inherited_priority;
+ curthread->inherited_priority = (*m)->m_prio;
+ THR_SCHED_UNLOCK(curthread, curthread);
+
+ /* Add to the list of owned mutexes: */
+ MUTEX_ASSERT_NOT_OWNED(*m);
+ TAILQ_INSERT_TAIL(&curthread->mutexq,
+ (*m), m_qe);
+ if (private)
+ THR_CRITICAL_ENTER(curthread);
+
+ /* Unlock the mutex structure: */
+ THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+ } else if ((*m)->m_owner == curthread) {
+ ret = mutex_self_lock(curthread, *m);
+
+ /* Unlock the mutex structure: */
+ THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+ } else {
+ /*
+ * Join the queue of threads waiting to lock
+ * the mutex and save a pointer to the mutex.
+ */
+ mutex_queue_enq(*m, curthread);
+ curthread->data.mutex = *m;
+ curthread->sigbackout = mutex_lock_backout;
+
+ /* Clear any previous error: */
+ curthread->error = 0;
+
+ /*
+ * This thread is active and is in a critical
+ * region (holding the mutex lock); we should
+ * be able to safely set the state.
+ */
+
+ THR_SCHED_LOCK(curthread, curthread);
+ /* Set the wakeup time: */
+ if (abstime) {
+ curthread->wakeup_time.tv_sec =
+ abstime->tv_sec;
+ curthread->wakeup_time.tv_nsec =
+ abstime->tv_nsec;
+ }
+ THR_SET_STATE(curthread, PS_MUTEX_WAIT);
+ THR_SCHED_UNLOCK(curthread, curthread);
+
+ /* Unlock the mutex structure: */
+ THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+
+ /* Schedule the next thread: */
+ _thr_sched_switch(curthread);
+
+ if (THR_IN_MUTEXQ(curthread)) {
+ THR_LOCK_ACQUIRE(curthread, &(*m)->m_lock);
+ mutex_queue_remove(*m, curthread);
+ THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+ }
+ /*
+ * Only clear these after assuring the
+ * thread is dequeued.
+ */
+ curthread->data.mutex = NULL;
+ curthread->sigbackout = NULL;
+
+ /*
+ * The threads priority may have changed while
+ * waiting for the mutex causing a ceiling
+ * violation.
+ */
+ ret = curthread->error;
+ curthread->error = 0;
+ }
+ break;
+
+ /* Trap invalid mutex types: */
+ default:
+ /* Unlock the mutex structure: */
+ THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+
+ /* Return an invalid argument error: */
+ ret = EINVAL;
+ break;
+ }
+
+ } while (((*m)->m_owner != curthread) && (ret == 0) &&
+ (curthread->interrupted == 0) && (curthread->timeout == 0));
+
+ if (ret == 0 && (*m)->m_owner != curthread && curthread->timeout)
+ ret = ETIMEDOUT;
+
+ /*
+ * Check to see if this thread was interrupted and
+ * is still in the mutex queue of waiting threads:
+ */
+ if (curthread->interrupted != 0) {
+ /* Remove this thread from the mutex queue. */
+ THR_LOCK_ACQUIRE(curthread, &(*m)->m_lock);
+ if (THR_IN_SYNCQ(curthread))
+ mutex_queue_remove(*m, curthread);
+ THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+
+ /* Check for asynchronous cancellation. */
+ if (curthread->continuation != NULL)
+ curthread->continuation((void *) curthread);
+ }
+
+ /* Return the completion status: */
+ return (ret);
+}
+
+int
+__pthread_mutex_lock(pthread_mutex_t *m)
+{
+ struct pthread *curthread;
+ int ret = 0;
+
+ if (_thr_initial == NULL)
+ _libpthread_init(NULL);
+
+ curthread = _get_curthread();
+ if (m == NULL)
+ ret = EINVAL;
+
+ /*
+ * If the mutex is statically initialized, perform the dynamic
+ * initialization:
+ */
+ else if ((*m != NULL) || ((ret = init_static(curthread, m)) == 0))
+ ret = mutex_lock_common(curthread, m, NULL);
+
+ return (ret);
+}
+
+__strong_reference(__pthread_mutex_lock, _thr_mutex_lock);
+
+int
+_pthread_mutex_lock(pthread_mutex_t *m)
+{
+ struct pthread *curthread;
+ int ret = 0;
+
+ if (_thr_initial == NULL)
+ _libpthread_init(NULL);
+ curthread = _get_curthread();
+
+ if (m == NULL)
+ ret = EINVAL;
+
+ /*
+ * If the mutex is statically initialized, perform the dynamic
+ * initialization marking it private (delete safe):
+ */
+ else if ((*m != NULL) ||
+ ((ret = init_static_private(curthread, m)) == 0))
+ ret = mutex_lock_common(curthread, m, NULL);
+
+ return (ret);
+}
+
+int
+__pthread_mutex_timedlock(pthread_mutex_t *m,
+ const struct timespec *abs_timeout)
+{
+ struct pthread *curthread;
+ int ret = 0;
+
+ if (_thr_initial == NULL)
+ _libpthread_init(NULL);
+
+ curthread = _get_curthread();
+ if (m == NULL)
+ ret = EINVAL;
+
+ /*
+ * If the mutex is statically initialized, perform the dynamic
+ * initialization:
+ */
+ else if ((*m != NULL) || ((ret = init_static(curthread, m)) == 0))
+ ret = mutex_lock_common(curthread, m, abs_timeout);
+
+ return (ret);
+}
+
+int
+_pthread_mutex_timedlock(pthread_mutex_t *m,
+ const struct timespec *abs_timeout)
+{
+ struct pthread *curthread;
+ int ret = 0;
+
+ if (_thr_initial == NULL)
+ _libpthread_init(NULL);
+ curthread = _get_curthread();
+
+ if (m == NULL)
+ ret = EINVAL;
+
+ /*
+ * If the mutex is statically initialized, perform the dynamic
+ * initialization marking it private (delete safe):
+ */
+ else if ((*m != NULL) ||
+ ((ret = init_static_private(curthread, m)) == 0))
+ ret = mutex_lock_common(curthread, m, abs_timeout);
+
+ return (ret);
+}
+
+int
+_pthread_mutex_unlock(pthread_mutex_t *m)
+{
+ return (mutex_unlock_common(m, /* add reference */ 0));
+}
+
+__strong_reference(_pthread_mutex_unlock, _thr_mutex_unlock);
+
+int
+_mutex_cv_unlock(pthread_mutex_t *m)
+{
+ return (mutex_unlock_common(m, /* add reference */ 1));
+}
+
+int
+_mutex_cv_lock(pthread_mutex_t *m)
+{
+ struct pthread *curthread;
+ int ret;
+
+ curthread = _get_curthread();
+ if ((ret = _pthread_mutex_lock(m)) == 0) {
+ THR_LOCK_ACQUIRE(curthread, &(*m)->m_lock);
+ (*m)->m_refcount--;
+ THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+ }
+ return (ret);
+}
+
+static inline int
+mutex_self_trylock(struct pthread *curthread, pthread_mutex_t m)
+{
+ int ret = 0;
+
+ switch (m->m_type) {
+ /* case PTHREAD_MUTEX_DEFAULT: */
+ case PTHREAD_MUTEX_ERRORCHECK:
+ case PTHREAD_MUTEX_NORMAL:
+ ret = EBUSY;
+ break;
+
+ case PTHREAD_MUTEX_RECURSIVE:
+ /* Increment the lock count: */
+ m->m_count++;
+ break;
+
+ default:
+ /* Trap invalid mutex types; */
+ ret = EINVAL;
+ }
+
+ return (ret);
+}
+
+static inline int
+mutex_self_lock(struct pthread *curthread, pthread_mutex_t m)
+{
+ int ret = 0;
+
+ /*
+ * Don't allow evil recursive mutexes for private use
+ * in libc and libpthread.
+ */
+ if (m->m_flags & MUTEX_FLAGS_PRIVATE)
+ PANIC("Recurse on a private mutex.");
+
+ switch (m->m_type) {
+ /* case PTHREAD_MUTEX_DEFAULT: */
+ case PTHREAD_MUTEX_ERRORCHECK:
+ /*
+ * POSIX specifies that mutexes should return EDEADLK if a
+ * recursive lock is detected.
+ */
+ ret = EDEADLK;
+ break;
+
+ case PTHREAD_MUTEX_NORMAL:
+ /*
+ * What SS2 define as a 'normal' mutex. Intentionally
+ * deadlock on attempts to get a lock you already own.
+ */
+
+ THR_SCHED_LOCK(curthread, curthread);
+ THR_SET_STATE(curthread, PS_DEADLOCK);
+ THR_SCHED_UNLOCK(curthread, curthread);
+
+ /* Unlock the mutex structure: */
+ THR_LOCK_RELEASE(curthread, &m->m_lock);
+
+ /* Schedule the next thread: */
+ _thr_sched_switch(curthread);
+ break;
+
+ case PTHREAD_MUTEX_RECURSIVE:
+ /* Increment the lock count: */
+ m->m_count++;
+ break;
+
+ default:
+ /* Trap invalid mutex types; */
+ ret = EINVAL;
+ }
+
+ return (ret);
+}
+
+static int
+mutex_unlock_common(pthread_mutex_t *m, int add_reference)
+{
+ struct pthread *curthread = _get_curthread();
+ struct kse_mailbox *kmbx = NULL;
+ int ret = 0;
+
+ if (m == NULL || *m == NULL)
+ ret = EINVAL;
+ else {
+ /* Lock the mutex structure: */
+ THR_LOCK_ACQUIRE(curthread, &(*m)->m_lock);
+
+ /* Process according to mutex type: */
+ switch ((*m)->m_protocol) {
+ /* Default POSIX mutex: */
+ case PTHREAD_PRIO_NONE:
+ /*
+ * Check if the running thread is not the owner of the
+ * mutex:
+ */
+ if ((*m)->m_owner != curthread)
+ ret = EPERM;
+ else if (((*m)->m_type == PTHREAD_MUTEX_RECURSIVE) &&
+ ((*m)->m_count > 0))
+ /* Decrement the count: */
+ (*m)->m_count--;
+ else {
+ /*
+ * Clear the count in case this is a recursive
+ * mutex.
+ */
+ (*m)->m_count = 0;
+
+ /* Remove the mutex from the threads queue. */
+ MUTEX_ASSERT_IS_OWNED(*m);
+ TAILQ_REMOVE(&(*m)->m_owner->mutexq,
+ (*m), m_qe);
+ MUTEX_INIT_LINK(*m);
+
+ /*
+ * Hand off the mutex to the next waiting
+ * thread:
+ */
+ kmbx = mutex_handoff(curthread, *m);
+ }
+ break;
+
+ /* POSIX priority inheritence mutex: */
+ case PTHREAD_PRIO_INHERIT:
+ /*
+ * Check if the running thread is not the owner of the
+ * mutex:
+ */
+ if ((*m)->m_owner != curthread)
+ ret = EPERM;
+ else if (((*m)->m_type == PTHREAD_MUTEX_RECURSIVE) &&
+ ((*m)->m_count > 0))
+ /* Decrement the count: */
+ (*m)->m_count--;
+ else {
+ /*
+ * Clear the count in case this is recursive
+ * mutex.
+ */
+ (*m)->m_count = 0;
+
+ /*
+ * Restore the threads inherited priority and
+ * recompute the active priority (being careful
+ * not to override changes in the threads base
+ * priority subsequent to locking the mutex).
+ */
+ THR_SCHED_LOCK(curthread, curthread);
+ curthread->inherited_priority =
+ (*m)->m_saved_prio;
+ curthread->active_priority =
+ MAX(curthread->inherited_priority,
+ curthread->base_priority);
+
+ /*
+ * This thread now owns one less priority mutex.
+ */
+ curthread->priority_mutex_count--;
+ THR_SCHED_UNLOCK(curthread, curthread);
+
+ /* Remove the mutex from the threads queue. */
+ MUTEX_ASSERT_IS_OWNED(*m);
+ TAILQ_REMOVE(&(*m)->m_owner->mutexq,
+ (*m), m_qe);
+ MUTEX_INIT_LINK(*m);
+
+ /*
+ * Hand off the mutex to the next waiting
+ * thread:
+ */
+ kmbx = mutex_handoff(curthread, *m);
+ }
+ break;
+
+ /* POSIX priority ceiling mutex: */
+ case PTHREAD_PRIO_PROTECT:
+ /*
+ * Check if the running thread is not the owner of the
+ * mutex:
+ */
+ if ((*m)->m_owner != curthread)
+ ret = EPERM;
+ else if (((*m)->m_type == PTHREAD_MUTEX_RECURSIVE) &&
+ ((*m)->m_count > 0))
+ /* Decrement the count: */
+ (*m)->m_count--;
+ else {
+ /*
+ * Clear the count in case this is a recursive
+ * mutex.
+ */
+ (*m)->m_count = 0;
+
+ /*
+ * Restore the threads inherited priority and
+ * recompute the active priority (being careful
+ * not to override changes in the threads base
+ * priority subsequent to locking the mutex).
+ */
+ THR_SCHED_LOCK(curthread, curthread);
+ curthread->inherited_priority =
+ (*m)->m_saved_prio;
+ curthread->active_priority =
+ MAX(curthread->inherited_priority,
+ curthread->base_priority);
+
+ /*
+ * This thread now owns one less priority mutex.
+ */
+ curthread->priority_mutex_count--;
+ THR_SCHED_UNLOCK(curthread, curthread);
+
+ /* Remove the mutex from the threads queue. */
+ MUTEX_ASSERT_IS_OWNED(*m);
+ TAILQ_REMOVE(&(*m)->m_owner->mutexq,
+ (*m), m_qe);
+ MUTEX_INIT_LINK(*m);
+
+ /*
+ * Hand off the mutex to the next waiting
+ * thread:
+ */
+ kmbx = mutex_handoff(curthread, *m);
+ }
+ break;
+
+ /* Trap invalid mutex types: */
+ default:
+ /* Return an invalid argument error: */
+ ret = EINVAL;
+ break;
+ }
+
+ if ((ret == 0) && (add_reference != 0))
+ /* Increment the reference count: */
+ (*m)->m_refcount++;
+
+ /* Leave the critical region if this is a private mutex. */
+ if ((ret == 0) && ((*m)->m_flags & MUTEX_FLAGS_PRIVATE))
+ THR_CRITICAL_LEAVE(curthread);
+
+ /* Unlock the mutex structure: */
+ THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+
+ if (kmbx != NULL)
+ kse_wakeup(kmbx);
+ }
+
+ /* Return the completion status: */
+ return (ret);
+}
+
+
+/*
+ * This function is called when a change in base priority occurs for
+ * a thread that is holding or waiting for a priority protection or
+ * inheritence mutex. A change in a threads base priority can effect
+ * changes to active priorities of other threads and to the ordering
+ * of mutex locking by waiting threads.
+ *
+ * This must be called without the target thread's scheduling lock held.
+ */
+void
+_mutex_notify_priochange(struct pthread *curthread, struct pthread *pthread,
+ int propagate_prio)
+{
+ struct pthread_mutex *m;
+
+ /* Adjust the priorites of any owned priority mutexes: */
+ if (pthread->priority_mutex_count > 0) {
+ /*
+ * Rescan the mutexes owned by this thread and correct
+ * their priorities to account for this threads change
+ * in priority. This has the side effect of changing
+ * the threads active priority.
+ *
+ * Be sure to lock the first mutex in the list of owned
+ * mutexes. This acts as a barrier against another
+ * simultaneous call to change the threads priority
+ * and from the owning thread releasing the mutex.
+ */
+ m = TAILQ_FIRST(&pthread->mutexq);
+ if (m != NULL) {
+ THR_LOCK_ACQUIRE(curthread, &m->m_lock);
+ /*
+ * Make sure the thread still owns the lock.
+ */
+ if (m == TAILQ_FIRST(&pthread->mutexq))
+ mutex_rescan_owned(curthread, pthread,
+ /* rescan all owned */ NULL);
+ THR_LOCK_RELEASE(curthread, &m->m_lock);
+ }
+ }
+
+ /*
+ * If this thread is waiting on a priority inheritence mutex,
+ * check for priority adjustments. A change in priority can
+ * also cause a ceiling violation(*) for a thread waiting on
+ * a priority protection mutex; we don't perform the check here
+ * as it is done in pthread_mutex_unlock.
+ *
+ * (*) It should be noted that a priority change to a thread
+ * _after_ taking and owning a priority ceiling mutex
+ * does not affect ownership of that mutex; the ceiling
+ * priority is only checked before mutex ownership occurs.
+ */
+ if (propagate_prio != 0) {
+ /*
+ * Lock the thread's scheduling queue. This is a bit
+ * convoluted; the "in synchronization queue flag" can
+ * only be cleared with both the thread's scheduling and
+ * mutex locks held. The thread's pointer to the wanted
+ * mutex is guaranteed to be valid during this time.
+ */
+ THR_SCHED_LOCK(curthread, pthread);
+
+ if (((pthread->sflags & THR_FLAGS_IN_SYNCQ) == 0) ||
+ ((m = pthread->data.mutex) == NULL))
+ THR_SCHED_UNLOCK(curthread, pthread);
+ else {
+ /*
+ * This thread is currently waiting on a mutex; unlock
+ * the scheduling queue lock and lock the mutex. We
+ * can't hold both at the same time because the locking
+ * order could cause a deadlock.
+ */
+ THR_SCHED_UNLOCK(curthread, pthread);
+ THR_LOCK_ACQUIRE(curthread, &m->m_lock);
+
+ /*
+ * Check to make sure this thread is still in the
+ * same state (the lock above can yield the CPU to
+ * another thread or the thread may be running on
+ * another CPU).
+ */
+ if (((pthread->sflags & THR_FLAGS_IN_SYNCQ) != 0) &&
+ (pthread->data.mutex == m)) {
+ /*
+ * Remove and reinsert this thread into
+ * the list of waiting threads to preserve
+ * decreasing priority order.
+ */
+ mutex_queue_remove(m, pthread);
+ mutex_queue_enq(m, pthread);
+
+ if (m->m_protocol == PTHREAD_PRIO_INHERIT)
+ /* Adjust priorities: */
+ mutex_priority_adjust(curthread, m);
+ }
+
+ /* Unlock the mutex structure: */
+ THR_LOCK_RELEASE(curthread, &m->m_lock);
+ }
+ }
+}
+
+/*
+ * Called when a new thread is added to the mutex waiting queue or
+ * when a threads priority changes that is already in the mutex
+ * waiting queue.
+ *
+ * This must be called with the mutex locked by the current thread.
+ */
+static void
+mutex_priority_adjust(struct pthread *curthread, pthread_mutex_t mutex)
+{
+ pthread_mutex_t m = mutex;
+ struct pthread *pthread_next, *pthread = mutex->m_owner;
+ int done, temp_prio;
+
+ /*
+ * Calculate the mutex priority as the maximum of the highest
+ * active priority of any waiting threads and the owning threads
+ * active priority(*).
+ *
+ * (*) Because the owning threads current active priority may
+ * reflect priority inherited from this mutex (and the mutex
+ * priority may have changed) we must recalculate the active
+ * priority based on the threads saved inherited priority
+ * and its base priority.
+ */
+ pthread_next = TAILQ_FIRST(&m->m_queue); /* should never be NULL */
+ temp_prio = MAX(pthread_next->active_priority,
+ MAX(m->m_saved_prio, pthread->base_priority));
+
+ /* See if this mutex really needs adjusting: */
+ if (temp_prio == m->m_prio)
+ /* No need to propagate the priority: */
+ return;
+
+ /* Set new priority of the mutex: */
+ m->m_prio = temp_prio;
+
+ /*
+ * Don't unlock the mutex passed in as an argument. It is
+ * expected to be locked and unlocked by the caller.
+ */
+ done = 1;
+ do {
+ /*
+ * Save the threads priority before rescanning the
+ * owned mutexes:
+ */
+ temp_prio = pthread->active_priority;
+
+ /*
+ * Fix the priorities for all mutexes held by the owning
+ * thread since taking this mutex. This also has a
+ * potential side-effect of changing the threads priority.
+ *
+ * At this point the mutex is locked by the current thread.
+ * The owning thread can't release the mutex until it is
+ * unlocked, so we should be able to safely walk its list
+ * of owned mutexes.
+ */
+ mutex_rescan_owned(curthread, pthread, m);
+
+ /*
+ * If this isn't the first time through the loop,
+ * the current mutex needs to be unlocked.
+ */
+ if (done == 0)
+ THR_LOCK_RELEASE(curthread, &m->m_lock);
+
+ /* Assume we're done unless told otherwise: */
+ done = 1;
+
+ /*
+ * If the thread is currently waiting on a mutex, check
+ * to see if the threads new priority has affected the
+ * priority of the mutex.
+ */
+ if ((temp_prio != pthread->active_priority) &&
+ ((pthread->sflags & THR_FLAGS_IN_SYNCQ) != 0) &&
+ ((m = pthread->data.mutex) != NULL) &&
+ (m->m_protocol == PTHREAD_PRIO_INHERIT)) {
+ /* Lock the mutex structure: */
+ THR_LOCK_ACQUIRE(curthread, &m->m_lock);
+
+ /*
+ * Make sure the thread is still waiting on the
+ * mutex:
+ */
+ if (((pthread->sflags & THR_FLAGS_IN_SYNCQ) != 0) &&
+ (m == pthread->data.mutex)) {
+ /*
+ * The priority for this thread has changed.
+ * Remove and reinsert this thread into the
+ * list of waiting threads to preserve
+ * decreasing priority order.
+ */
+ mutex_queue_remove(m, pthread);
+ mutex_queue_enq(m, pthread);
+
+ /*
+ * Grab the waiting thread with highest
+ * priority:
+ */
+ pthread_next = TAILQ_FIRST(&m->m_queue);
+
+ /*
+ * Calculate the mutex priority as the maximum
+ * of the highest active priority of any
+ * waiting threads and the owning threads
+ * active priority.
+ */
+ temp_prio = MAX(pthread_next->active_priority,
+ MAX(m->m_saved_prio,
+ m->m_owner->base_priority));
+
+ if (temp_prio != m->m_prio) {
+ /*
+ * The priority needs to be propagated
+ * to the mutex this thread is waiting
+ * on and up to the owner of that mutex.
+ */
+ m->m_prio = temp_prio;
+ pthread = m->m_owner;
+
+ /* We're not done yet: */
+ done = 0;
+ }
+ }
+ /* Only release the mutex if we're done: */
+ if (done != 0)
+ THR_LOCK_RELEASE(curthread, &m->m_lock);
+ }
+ } while (done == 0);
+}
+
+static void
+mutex_rescan_owned(struct pthread *curthread, struct pthread *pthread,
+ struct pthread_mutex *mutex)
+{
+ struct pthread_mutex *m;
+ struct pthread *pthread_next;
+ int active_prio, inherited_prio;
+
+ /*
+ * Start walking the mutexes the thread has taken since
+ * taking this mutex.
+ */
+ if (mutex == NULL) {
+ /*
+ * A null mutex means start at the beginning of the owned
+ * mutex list.
+ */
+ m = TAILQ_FIRST(&pthread->mutexq);
+
+ /* There is no inherited priority yet. */
+ inherited_prio = 0;
+ } else {
+ /*
+ * The caller wants to start after a specific mutex. It
+ * is assumed that this mutex is a priority inheritence
+ * mutex and that its priority has been correctly
+ * calculated.
+ */
+ m = TAILQ_NEXT(mutex, m_qe);
+
+ /* Start inheriting priority from the specified mutex. */
+ inherited_prio = mutex->m_prio;
+ }
+ active_prio = MAX(inherited_prio, pthread->base_priority);
+
+ for (; m != NULL; m = TAILQ_NEXT(m, m_qe)) {
+ /*
+ * We only want to deal with priority inheritence
+ * mutexes. This might be optimized by only placing
+ * priority inheritence mutexes into the owned mutex
+ * list, but it may prove to be useful having all
+ * owned mutexes in this list. Consider a thread
+ * exiting while holding mutexes...
+ */
+ if (m->m_protocol == PTHREAD_PRIO_INHERIT) {
+ /*
+ * Fix the owners saved (inherited) priority to
+ * reflect the priority of the previous mutex.
+ */
+ m->m_saved_prio = inherited_prio;
+
+ if ((pthread_next = TAILQ_FIRST(&m->m_queue)) != NULL)
+ /* Recalculate the priority of the mutex: */
+ m->m_prio = MAX(active_prio,
+ pthread_next->active_priority);
+ else
+ m->m_prio = active_prio;
+
+ /* Recalculate new inherited and active priorities: */
+ inherited_prio = m->m_prio;
+ active_prio = MAX(m->m_prio, pthread->base_priority);
+ }
+ }
+
+ /*
+ * Fix the threads inherited priority and recalculate its
+ * active priority.
+ */
+ pthread->inherited_priority = inherited_prio;
+ active_prio = MAX(inherited_prio, pthread->base_priority);
+
+ if (active_prio != pthread->active_priority) {
+ /* Lock the thread's scheduling queue: */
+ THR_SCHED_LOCK(curthread, pthread);
+
+ if ((pthread->flags & THR_FLAGS_IN_RUNQ) == 0) {
+ /*
+ * This thread is not in a run queue. Just set
+ * its active priority.
+ */
+ pthread->active_priority = active_prio;
+ }
+ else {
+ /*
+ * This thread is in a run queue. Remove it from
+ * the queue before changing its priority:
+ */
+ THR_RUNQ_REMOVE(pthread);
+
+ /*
+ * POSIX states that if the priority is being
+ * lowered, the thread must be inserted at the
+ * head of the queue for its priority if it owns
+ * any priority protection or inheritence mutexes.
+ */
+ if ((active_prio < pthread->active_priority) &&
+ (pthread->priority_mutex_count > 0)) {
+ /* Set the new active priority. */
+ pthread->active_priority = active_prio;
+
+ THR_RUNQ_INSERT_HEAD(pthread);
+ } else {
+ /* Set the new active priority. */
+ pthread->active_priority = active_prio;
+
+ THR_RUNQ_INSERT_TAIL(pthread);
+ }
+ }
+ THR_SCHED_UNLOCK(curthread, pthread);
+ }
+}
+
+void
+_mutex_unlock_private(pthread_t pthread)
+{
+ struct pthread_mutex *m, *m_next;
+
+ for (m = TAILQ_FIRST(&pthread->mutexq); m != NULL; m = m_next) {
+ m_next = TAILQ_NEXT(m, m_qe);
+ if ((m->m_flags & MUTEX_FLAGS_PRIVATE) != 0)
+ pthread_mutex_unlock(&m);
+ }
+}
+
+/*
+ * This is called by the current thread when it wants to back out of a
+ * mutex_lock in order to run a signal handler.
+ */
+static void
+mutex_lock_backout(void *arg)
+{
+ struct pthread *curthread = (struct pthread *)arg;
+ struct pthread_mutex *m;
+
+ if ((curthread->sflags & THR_FLAGS_IN_SYNCQ) != 0) {
+ /*
+ * Any other thread may clear the "in sync queue flag",
+ * but only the current thread can clear the pointer
+ * to the mutex. So if the flag is set, we can
+ * guarantee that the pointer to the mutex is valid.
+ * The only problem may be if the mutex is destroyed
+ * out from under us, but that should be considered
+ * an application bug.
+ */
+ m = curthread->data.mutex;
+
+ /* Lock the mutex structure: */
+ THR_LOCK_ACQUIRE(curthread, &m->m_lock);
+
+
+ /*
+ * Check to make sure this thread doesn't already own
+ * the mutex. Since mutexes are unlocked with direct
+ * handoffs, it is possible the previous owner gave it
+ * to us after we checked the sync queue flag and before
+ * we locked the mutex structure.
+ */
+ if (m->m_owner == curthread) {
+ THR_LOCK_RELEASE(curthread, &m->m_lock);
+ mutex_unlock_common(&m, /* add_reference */ 0);
+ } else {
+ /*
+ * Remove ourselves from the mutex queue and
+ * clear the pointer to the mutex. We may no
+ * longer be in the mutex queue, but the removal
+ * function will DTRT.
+ */
+ mutex_queue_remove(m, curthread);
+ curthread->data.mutex = NULL;
+ THR_LOCK_RELEASE(curthread, &m->m_lock);
+ }
+ }
+ /* No need to call this again. */
+ curthread->sigbackout = NULL;
+}
+
+/*
+ * Dequeue a waiting thread from the head of a mutex queue in descending
+ * priority order.
+ *
+ * In order to properly dequeue a thread from the mutex queue and
+ * make it runnable without the possibility of errant wakeups, it
+ * is necessary to lock the thread's scheduling queue while also
+ * holding the mutex lock.
+ */
+static struct kse_mailbox *
+mutex_handoff(struct pthread *curthread, struct pthread_mutex *mutex)
+{
+ struct kse_mailbox *kmbx = NULL;
+ struct pthread *pthread;
+
+ /* Keep dequeueing until we find a valid thread: */
+ mutex->m_owner = NULL;
+ pthread = TAILQ_FIRST(&mutex->m_queue);
+ while (pthread != NULL) {
+ /* Take the thread's scheduling lock: */
+ THR_SCHED_LOCK(curthread, pthread);
+
+ /* Remove the thread from the mutex queue: */
+ TAILQ_REMOVE(&mutex->m_queue, pthread, sqe);
+ pthread->sflags &= ~THR_FLAGS_IN_SYNCQ;
+
+ /*
+ * Only exit the loop if the thread hasn't been
+ * cancelled.
+ */
+ switch (mutex->m_protocol) {
+ case PTHREAD_PRIO_NONE:
+ /*
+ * Assign the new owner and add the mutex to the
+ * thread's list of owned mutexes.
+ */
+ mutex->m_owner = pthread;
+ TAILQ_INSERT_TAIL(&pthread->mutexq, mutex, m_qe);
+ break;
+
+ case PTHREAD_PRIO_INHERIT:
+ /*
+ * Assign the new owner and add the mutex to the
+ * thread's list of owned mutexes.
+ */
+ mutex->m_owner = pthread;
+ TAILQ_INSERT_TAIL(&pthread->mutexq, mutex, m_qe);
+
+ /* Track number of priority mutexes owned: */
+ pthread->priority_mutex_count++;
+
+ /*
+ * Set the priority of the mutex. Since our waiting
+ * threads are in descending priority order, the
+ * priority of the mutex becomes the active priority
+ * of the thread we just dequeued.
+ */
+ mutex->m_prio = pthread->active_priority;
+
+ /* Save the owning threads inherited priority: */
+ mutex->m_saved_prio = pthread->inherited_priority;
+
+ /*
+ * The owning threads inherited priority now becomes
+ * his active priority (the priority of the mutex).
+ */
+ pthread->inherited_priority = mutex->m_prio;
+ break;
+
+ case PTHREAD_PRIO_PROTECT:
+ if (pthread->active_priority > mutex->m_prio) {
+ /*
+ * Either the mutex ceiling priority has
+ * been lowered and/or this threads priority
+ * has been raised subsequent to the thread
+ * being queued on the waiting list.
+ */
+ pthread->error = EINVAL;
+ }
+ else {
+ /*
+ * Assign the new owner and add the mutex
+ * to the thread's list of owned mutexes.
+ */
+ mutex->m_owner = pthread;
+ TAILQ_INSERT_TAIL(&pthread->mutexq,
+ mutex, m_qe);
+
+ /* Track number of priority mutexes owned: */
+ pthread->priority_mutex_count++;
+
+ /*
+ * Save the owning threads inherited
+ * priority:
+ */
+ mutex->m_saved_prio =
+ pthread->inherited_priority;
+
+ /*
+ * The owning thread inherits the ceiling
+ * priority of the mutex and executes at
+ * that priority:
+ */
+ pthread->inherited_priority = mutex->m_prio;
+ pthread->active_priority = mutex->m_prio;
+
+ }
+ break;
+ }
+
+ /* Make the thread runnable and unlock the scheduling queue: */
+ kmbx = _thr_setrunnable_unlocked(pthread);
+
+ /* Add a preemption point. */
+ if ((curthread->kseg == pthread->kseg) &&
+ (pthread->active_priority > curthread->active_priority))
+ curthread->critical_yield = 1;
+
+ if (mutex->m_owner == pthread) {
+ /* We're done; a valid owner was found. */
+ if (mutex->m_flags & MUTEX_FLAGS_PRIVATE)
+ THR_CRITICAL_ENTER(pthread);
+ THR_SCHED_UNLOCK(curthread, pthread);
+ break;
+ }
+ THR_SCHED_UNLOCK(curthread, pthread);
+ /* Get the next thread from the waiting queue: */
+ pthread = TAILQ_NEXT(pthread, sqe);
+ }
+
+ if ((pthread == NULL) && (mutex->m_protocol == PTHREAD_PRIO_INHERIT))
+ /* This mutex has no priority: */
+ mutex->m_prio = 0;
+ return (kmbx);
+}
+
+/*
+ * Dequeue a waiting thread from the head of a mutex queue in descending
+ * priority order.
+ */
+static inline pthread_t
+mutex_queue_deq(struct pthread_mutex *mutex)
+{
+ pthread_t pthread;
+
+ while ((pthread = TAILQ_FIRST(&mutex->m_queue)) != NULL) {
+ TAILQ_REMOVE(&mutex->m_queue, pthread, sqe);
+ pthread->sflags &= ~THR_FLAGS_IN_SYNCQ;
+
+ /*
+ * Only exit the loop if the thread hasn't been
+ * cancelled.
+ */
+ if (pthread->interrupted == 0)
+ break;
+ }
+
+ return (pthread);
+}
+
+/*
+ * Remove a waiting thread from a mutex queue in descending priority order.
+ */
+static inline void
+mutex_queue_remove(pthread_mutex_t mutex, pthread_t pthread)
+{
+ if ((pthread->sflags & THR_FLAGS_IN_SYNCQ) != 0) {
+ TAILQ_REMOVE(&mutex->m_queue, pthread, sqe);
+ pthread->sflags &= ~THR_FLAGS_IN_SYNCQ;
+ }
+}
+
+/*
+ * Enqueue a waiting thread to a queue in descending priority order.
+ */
+static inline void
+mutex_queue_enq(pthread_mutex_t mutex, pthread_t pthread)
+{
+ pthread_t tid = TAILQ_LAST(&mutex->m_queue, mutex_head);
+
+ THR_ASSERT_NOT_IN_SYNCQ(pthread);
+ /*
+ * For the common case of all threads having equal priority,
+ * we perform a quick check against the priority of the thread
+ * at the tail of the queue.
+ */
+ if ((tid == NULL) || (pthread->active_priority <= tid->active_priority))
+ TAILQ_INSERT_TAIL(&mutex->m_queue, pthread, sqe);
+ else {
+ tid = TAILQ_FIRST(&mutex->m_queue);
+ while (pthread->active_priority <= tid->active_priority)
+ tid = TAILQ_NEXT(tid, sqe);
+ TAILQ_INSERT_BEFORE(tid, pthread, sqe);
+ }
+ pthread->sflags |= THR_FLAGS_IN_SYNCQ;
+}
diff --git a/lib/libpthread/thread/thr_mutex_prioceiling.c b/lib/libpthread/thread/thr_mutex_prioceiling.c
new file mode 100644
index 0000000..f254346
--- /dev/null
+++ b/lib/libpthread/thread/thr_mutex_prioceiling.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_mutexattr_getprioceiling);
+LT10_COMPAT_DEFAULT(pthread_mutexattr_getprioceiling);
+LT10_COMPAT_PRIVATE(_pthread_mutexattr_setprioceiling);
+LT10_COMPAT_DEFAULT(pthread_mutexattr_setprioceiling);
+LT10_COMPAT_PRIVATE(_pthread_mutex_getprioceiling);
+LT10_COMPAT_DEFAULT(pthread_mutex_getprioceiling);
+LT10_COMPAT_PRIVATE(_pthread_mutex_setprioceiling);
+LT10_COMPAT_DEFAULT(pthread_mutex_setprioceiling);
+
+__weak_reference(_pthread_mutexattr_getprioceiling, pthread_mutexattr_getprioceiling);
+__weak_reference(_pthread_mutexattr_setprioceiling, pthread_mutexattr_setprioceiling);
+__weak_reference(_pthread_mutex_getprioceiling, pthread_mutex_getprioceiling);
+__weak_reference(_pthread_mutex_setprioceiling, pthread_mutex_setprioceiling);
+
+int
+_pthread_mutexattr_getprioceiling(pthread_mutexattr_t *mattr, int *prioceiling)
+{
+ int ret = 0;
+
+ if ((mattr == NULL) || (*mattr == NULL))
+ ret = EINVAL;
+ else if ((*mattr)->m_protocol != PTHREAD_PRIO_PROTECT)
+ ret = EINVAL;
+ else
+ *prioceiling = (*mattr)->m_ceiling;
+
+ return(ret);
+}
+
+int
+_pthread_mutexattr_setprioceiling(pthread_mutexattr_t *mattr, int prioceiling)
+{
+ int ret = 0;
+
+ if ((mattr == NULL) || (*mattr == NULL))
+ ret = EINVAL;
+ else if ((*mattr)->m_protocol != PTHREAD_PRIO_PROTECT)
+ ret = EINVAL;
+ else
+ (*mattr)->m_ceiling = prioceiling;
+
+ return(ret);
+}
+
+int
+_pthread_mutex_getprioceiling(pthread_mutex_t *mutex,
+ int *prioceiling)
+{
+ int ret;
+
+ if ((mutex == NULL) || (*mutex == NULL))
+ ret = EINVAL;
+ else if ((*mutex)->m_protocol != PTHREAD_PRIO_PROTECT)
+ ret = EINVAL;
+ else
+ ret = (*mutex)->m_prio;
+
+ return(ret);
+}
+
+int
+_pthread_mutex_setprioceiling(pthread_mutex_t *mutex,
+ int prioceiling, int *old_ceiling)
+{
+ int ret = 0;
+ int tmp;
+
+ if ((mutex == NULL) || (*mutex == NULL))
+ ret = EINVAL;
+ else if ((*mutex)->m_protocol != PTHREAD_PRIO_PROTECT)
+ ret = EINVAL;
+ /* Lock the mutex: */
+ else if ((ret = pthread_mutex_lock(mutex)) == 0) {
+ tmp = (*mutex)->m_prio;
+ /* Set the new ceiling: */
+ (*mutex)->m_prio = prioceiling;
+
+ /* Unlock the mutex: */
+ ret = pthread_mutex_unlock(mutex);
+
+ /* Return the old ceiling: */
+ *old_ceiling = tmp;
+ }
+ return(ret);
+}
diff --git a/lib/libpthread/thread/thr_mutex_protocol.c b/lib/libpthread/thread/thr_mutex_protocol.c
new file mode 100644
index 0000000..9e3e46b
--- /dev/null
+++ b/lib/libpthread/thread/thr_mutex_protocol.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_mutexattr_getprotocol);
+LT10_COMPAT_DEFAULT(pthread_mutexattr_getprotocol);
+LT10_COMPAT_PRIVATE(_pthread_mutexattr_setprotocol);
+LT10_COMPAT_DEFAULT(pthread_mutexattr_setprotocol);
+
+__weak_reference(_pthread_mutexattr_getprotocol, pthread_mutexattr_getprotocol);
+__weak_reference(_pthread_mutexattr_setprotocol, pthread_mutexattr_setprotocol);
+
+int
+_pthread_mutexattr_getprotocol(pthread_mutexattr_t *mattr, int *protocol)
+{
+ int ret = 0;
+
+ if ((mattr == NULL) || (*mattr == NULL))
+ ret = EINVAL;
+ else
+ *protocol = (*mattr)->m_protocol;
+
+ return(ret);
+}
+
+int
+_pthread_mutexattr_setprotocol(pthread_mutexattr_t *mattr, int protocol)
+{
+ int ret = 0;
+
+ if ((mattr == NULL) || (*mattr == NULL) ||
+ (protocol < PTHREAD_PRIO_NONE) || (protocol > PTHREAD_PRIO_PROTECT))
+ ret = EINVAL;
+ else {
+ (*mattr)->m_protocol = protocol;
+ (*mattr)->m_ceiling = THR_MAX_PRIORITY;
+ }
+ return(ret);
+}
+
diff --git a/lib/libpthread/thread/thr_mutexattr_destroy.c b/lib/libpthread/thread/thr_mutexattr_destroy.c
new file mode 100644
index 0000000..2ae34a8
--- /dev/null
+++ b/lib/libpthread/thread/thr_mutexattr_destroy.c
@@ -0,0 +1,56 @@
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_mutexattr_destroy);
+LT10_COMPAT_DEFAULT(pthread_mutexattr_destroy);
+
+__weak_reference(_pthread_mutexattr_destroy, pthread_mutexattr_destroy);
+
+int
+_pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
+{
+ int ret;
+ if (attr == NULL || *attr == NULL) {
+ ret = EINVAL;
+ } else {
+ free(*attr);
+ *attr = NULL;
+ ret = 0;
+ }
+ return(ret);
+}
diff --git a/lib/libpthread/thread/thr_nanosleep.c b/lib/libpthread/thread/thr_nanosleep.c
new file mode 100644
index 0000000..72f85b2
--- /dev/null
+++ b/lib/libpthread/thread/thr_nanosleep.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__nanosleep);
+LT10_COMPAT_PRIVATE(_nanosleep);
+LT10_COMPAT_DEFAULT(nanosleep);
+
+__weak_reference(__nanosleep, nanosleep);
+
+int
+_nanosleep(const struct timespec *time_to_sleep,
+ struct timespec *time_remaining)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret = 0;
+ struct timespec ts, ts1;
+ struct timespec remaining_time;
+ struct timespec wakeup_time;
+
+ /* Check if the time to sleep is legal: */
+ if ((time_to_sleep == NULL) || (time_to_sleep->tv_sec < 0) ||
+ (time_to_sleep->tv_nsec < 0) ||
+ (time_to_sleep->tv_nsec >= 1000000000)) {
+ /* Return an EINVAL error : */
+ errno = EINVAL;
+ ret = -1;
+ } else {
+ if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
+ return (__sys_nanosleep(time_to_sleep, time_remaining));
+
+ KSE_GET_TOD(curthread->kse, &ts);
+
+ /* Calculate the time for the current thread to wake up: */
+ TIMESPEC_ADD(&wakeup_time, &ts, time_to_sleep);
+
+ THR_LOCK_SWITCH(curthread);
+ curthread->interrupted = 0;
+ curthread->wakeup_time = wakeup_time;
+ THR_SET_STATE(curthread, PS_SLEEP_WAIT);
+
+ /* Reschedule the current thread to sleep: */
+ _thr_sched_switch_unlocked(curthread);
+
+ /* Calculate the remaining time to sleep: */
+ KSE_GET_TOD(curthread->kse, &ts1);
+ remaining_time.tv_sec = time_to_sleep->tv_sec
+ + ts.tv_sec - ts1.tv_sec;
+ remaining_time.tv_nsec = time_to_sleep->tv_nsec
+ + ts.tv_nsec - ts1.tv_nsec;
+
+ /* Check if the nanosecond field has underflowed: */
+ if (remaining_time.tv_nsec < 0) {
+ /* Handle the underflow: */
+ remaining_time.tv_sec -= 1;
+ remaining_time.tv_nsec += 1000000000;
+ }
+ /* Check if the nanosecond field has overflowed: */
+ else if (remaining_time.tv_nsec >= 1000000000) {
+ /* Handle the overflow: */
+ remaining_time.tv_sec += 1;
+ remaining_time.tv_nsec -= 1000000000;
+ }
+
+ /* Check if the sleep was longer than the required time: */
+ if (remaining_time.tv_sec < 0) {
+ /* Reset the time left: */
+ remaining_time.tv_sec = 0;
+ remaining_time.tv_nsec = 0;
+ }
+
+ /* Check if the time remaining is to be returned: */
+ if (time_remaining != NULL) {
+ /* Return the actual time slept: */
+ time_remaining->tv_sec = remaining_time.tv_sec;
+ time_remaining->tv_nsec = remaining_time.tv_nsec;
+ }
+
+ /* Check if the sleep was interrupted: */
+ if (curthread->interrupted) {
+ /* Return an EINTR error : */
+ errno = EINTR;
+ ret = -1;
+ }
+ }
+ return (ret);
+}
+
+int
+__nanosleep(const struct timespec *time_to_sleep,
+ struct timespec *time_remaining)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ _thr_cancel_enter(curthread);
+ ret = _nanosleep(time_to_sleep, time_remaining);
+ _thr_cancel_leave(curthread, 1);
+
+ return (ret);
+}
diff --git a/lib/libpthread/thread/thr_once.c b/lib/libpthread/thread/thr_once.c
new file mode 100644
index 0000000..f93800f
--- /dev/null
+++ b/lib/libpthread/thread/thr_once.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <pthread.h>
+#include "un-namespace.h"
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_once);
+LT10_COMPAT_DEFAULT(pthread_once);
+
+__weak_reference(_pthread_once, pthread_once);
+
+#define ONCE_NEVER_DONE PTHREAD_NEEDS_INIT
+#define ONCE_DONE PTHREAD_DONE_INIT
+#define ONCE_IN_PROGRESS 0x02
+#define ONCE_MASK 0x03
+
+static pthread_mutex_t once_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t once_cv = PTHREAD_COND_INITIALIZER;
+
+/*
+ * POSIX:
+ * The pthread_once() function is not a cancellation point. However,
+ * if init_routine is a cancellation point and is canceled, the effect
+ * on once_control shall be as if pthread_once() was never called.
+ */
+
+static void
+once_cancel_handler(void *arg)
+{
+ pthread_once_t *once_control = arg;
+
+ _pthread_mutex_lock(&once_lock);
+ once_control->state = ONCE_NEVER_DONE;
+ _pthread_mutex_unlock(&once_lock);
+ _pthread_cond_broadcast(&once_cv);
+}
+
+int
+_pthread_once(pthread_once_t *once_control, void (*init_routine) (void))
+{
+ struct pthread *curthread;
+ int wakeup = 0;
+
+ if (once_control->state == ONCE_DONE)
+ return (0);
+ _pthread_mutex_lock(&once_lock);
+ while (*(volatile int *)&(once_control->state) == ONCE_IN_PROGRESS)
+ _pthread_cond_wait(&once_cv, &once_lock);
+ /*
+ * If previous thread was canceled, then the state still
+ * could be ONCE_NEVER_DONE, we need to check it again.
+ */
+ if (*(volatile int *)&(once_control->state) == ONCE_NEVER_DONE) {
+ once_control->state = ONCE_IN_PROGRESS;
+ _pthread_mutex_unlock(&once_lock);
+ curthread = _get_curthread();
+ THR_CLEANUP_PUSH(curthread, once_cancel_handler, once_control);
+ init_routine();
+ THR_CLEANUP_POP(curthread, 0);
+ _pthread_mutex_lock(&once_lock);
+ once_control->state = ONCE_DONE;
+ wakeup = 1;
+ }
+ _pthread_mutex_unlock(&once_lock);
+ if (wakeup)
+ _pthread_cond_broadcast(&once_cv);
+ return (0);
+}
+
diff --git a/lib/libpthread/thread/thr_open.c b/lib/libpthread/thread/thr_open.c
new file mode 100644
index 0000000..63b5f4a
--- /dev/null
+++ b/lib/libpthread/thread/thr_open.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <stdarg.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__open);
+LT10_COMPAT_DEFAULT(open);
+
+__weak_reference(__open, open);
+
+int
+__open(const char *path, int flags,...)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+ int mode = 0;
+ va_list ap;
+
+ _thr_cancel_enter(curthread);
+
+ /* Check if the file is being created: */
+ if (flags & O_CREAT) {
+ /* Get the creation mode: */
+ va_start(ap, flags);
+ mode = va_arg(ap, int);
+ va_end(ap);
+ }
+
+ ret = __sys_open(path, flags, mode);
+ /*
+ * To avoid possible file handle leak,
+ * only check cancellation point if it is failure
+ */
+ _thr_cancel_leave(curthread, (ret == -1));
+
+ return ret;
+}
diff --git a/lib/libpthread/thread/thr_pause.c b/lib/libpthread/thread/thr_pause.c
new file mode 100644
index 0000000..b3f0fe5
--- /dev/null
+++ b/lib/libpthread/thread/thr_pause.c
@@ -0,0 +1,54 @@
+/*
+ * 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$
+ */
+
+#include <unistd.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+extern int __pause(void);
+
+LT10_COMPAT_PRIVATE(_pause);
+LT10_COMPAT_DEFAULT(pause);
+
+__weak_reference(_pause, pause);
+
+int
+_pause(void)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ _thr_cancel_enter(curthread);
+ ret = __pause();
+ _thr_cancel_leave(curthread, 1);
+
+ return ret;
+}
diff --git a/lib/libpthread/thread/thr_poll.c b/lib/libpthread/thread/thr_poll.c
new file mode 100644
index 0000000..5e3890b
--- /dev/null
+++ b/lib/libpthread/thread/thr_poll.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 1999 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <poll.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/fcntl.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__poll);
+LT10_COMPAT_DEFAULT(poll);
+
+__weak_reference(__poll, poll);
+
+int
+__poll(struct pollfd *fds, unsigned int nfds, int timeout)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ _thr_cancel_enter(curthread);
+ ret = __sys_poll(fds, nfds, timeout);
+ _thr_cancel_leave(curthread, 1);
+
+ return ret;
+}
diff --git a/lib/libpthread/thread/thr_printf.c b/lib/libpthread/thread/thr_printf.c
new file mode 100644
index 0000000..2a4b12b
--- /dev/null
+++ b/lib/libpthread/thread/thr_printf.c
@@ -0,0 +1,135 @@
+/*-
+ * 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 <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "thr_private.h"
+
+static void pchar(int fd, char c);
+static void pstr(int fd, const char *s);
+
+/*
+ * Write formatted output to stdout, in a thread-safe manner.
+ *
+ * Recognises the following conversions:
+ * %c -> char
+ * %d -> signed int (base 10)
+ * %s -> string
+ * %u -> unsigned int (base 10)
+ * %x -> unsigned int (base 16)
+ * %p -> unsigned int (base 16)
+ */
+void
+_thread_printf(int fd, const char *fmt, ...)
+{
+ static const char digits[16] = "0123456789abcdef";
+ va_list ap;
+ char buf[20];
+ char *s;
+ unsigned long r, u;
+ int c;
+ long d;
+ int islong;
+
+ va_start(ap, fmt);
+ while ((c = *fmt++)) {
+ islong = 0;
+ if (c == '%') {
+next: c = *fmt++;
+ if (c == '\0')
+ goto out;
+ switch (c) {
+ case 'c':
+ pchar(fd, va_arg(ap, int));
+ continue;
+ case 's':
+ pstr(fd, va_arg(ap, char *));
+ continue;
+ case 'l':
+ islong = 1;
+ goto next;
+ case 'p':
+ islong = 1;
+ case 'd':
+ case 'u':
+ case 'x':
+ r = ((c == 'u') || (c == 'd')) ? 10 : 16;
+ if (c == 'd') {
+ if (islong)
+ d = va_arg(ap, unsigned long);
+ else
+ d = va_arg(ap, unsigned);
+ if (d < 0) {
+ pchar(fd, '-');
+ u = (unsigned long)(d * -1);
+ } else
+ u = (unsigned long)d;
+ } else {
+ if (islong)
+ u = va_arg(ap, unsigned long);
+ else
+ u = va_arg(ap, unsigned);
+ }
+ s = buf;
+ do {
+ *s++ = digits[u % r];
+ } while (u /= r);
+ while (--s >= buf)
+ pchar(fd, *s);
+ continue;
+ }
+ }
+ pchar(fd, c);
+ }
+out:
+ va_end(ap);
+}
+
+/*
+ * Write a single character to stdout, in a thread-safe manner.
+ */
+static void
+pchar(int fd, char c)
+{
+
+ __sys_write(fd, &c, 1);
+}
+
+/*
+ * Write a string to stdout, in a thread-safe manner.
+ */
+static void
+pstr(int fd, const char *s)
+{
+
+ __sys_write(fd, s, strlen(s));
+}
+
diff --git a/lib/libpthread/thread/thr_priority_queue.c b/lib/libpthread/thread/thr_priority_queue.c
new file mode 100644
index 0000000..f750a01
--- /dev/null
+++ b/lib/libpthread/thread/thr_priority_queue.c
@@ -0,0 +1,324 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+#include <stdlib.h>
+#include <sys/queue.h>
+#include <string.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+/* Prototypes: */
+static void pq_insert_prio_list(pq_queue_t *pq, int prio);
+
+#if defined(_PTHREADS_INVARIANTS)
+
+#define PQ_IN_SCHEDQ (THR_FLAGS_IN_RUNQ | THR_FLAGS_IN_WAITQ)
+
+#define PQ_SET_ACTIVE(pq) (pq)->pq_flags |= PQF_ACTIVE
+#define PQ_CLEAR_ACTIVE(pq) (pq)->pq_flags &= ~PQF_ACTIVE
+#define PQ_ASSERT_ACTIVE(pq, msg) do { \
+ if (((pq)->pq_flags & PQF_ACTIVE) == 0) \
+ PANIC(msg); \
+} while (0)
+#define PQ_ASSERT_INACTIVE(pq, msg) do { \
+ if (((pq)->pq_flags & PQF_ACTIVE) != 0) \
+ PANIC(msg); \
+} while (0)
+#define PQ_ASSERT_IN_WAITQ(thrd, msg) do { \
+ if (((thrd)->flags & THR_FLAGS_IN_WAITQ) == 0) \
+ PANIC(msg); \
+} while (0)
+#define PQ_ASSERT_IN_RUNQ(thrd, msg) do { \
+ if (((thrd)->flags & THR_FLAGS_IN_RUNQ) == 0) \
+ PANIC(msg); \
+} while (0)
+#define PQ_ASSERT_NOT_QUEUED(thrd, msg) do { \
+ if (((thrd)->flags & PQ_IN_SCHEDQ) != 0) \
+ PANIC(msg); \
+} while (0)
+
+#else
+
+#define PQ_SET_ACTIVE(pq)
+#define PQ_CLEAR_ACTIVE(pq)
+#define PQ_ASSERT_ACTIVE(pq, msg)
+#define PQ_ASSERT_INACTIVE(pq, msg)
+#define PQ_ASSERT_IN_WAITQ(thrd, msg)
+#define PQ_ASSERT_IN_RUNQ(thrd, msg)
+#define PQ_ASSERT_NOT_QUEUED(thrd, msg)
+
+#endif
+
+int
+_pq_alloc(pq_queue_t *pq, int minprio, int maxprio)
+{
+ int ret = 0;
+ int prioslots = maxprio - minprio + 1;
+
+ if (pq == NULL)
+ ret = -1;
+
+ /* Create the priority queue with (maxprio - minprio + 1) slots: */
+ else if ((pq->pq_lists =
+ (pq_list_t *) malloc(sizeof(pq_list_t) * prioslots)) == NULL)
+ ret = -1;
+
+ else {
+ /* Remember the queue size: */
+ pq->pq_size = prioslots;
+ ret = _pq_init(pq);
+ }
+ return (ret);
+}
+
+void
+_pq_free(pq_queue_t *pq)
+{
+ if ((pq != NULL) && (pq->pq_lists != NULL))
+ free(pq->pq_lists);
+}
+
+int
+_pq_init(pq_queue_t *pq)
+{
+ int i, ret = 0;
+
+ if ((pq == NULL) || (pq->pq_lists == NULL))
+ ret = -1;
+
+ else {
+ /* Initialize the queue for each priority slot: */
+ for (i = 0; i < pq->pq_size; i++) {
+ TAILQ_INIT(&pq->pq_lists[i].pl_head);
+ pq->pq_lists[i].pl_prio = i;
+ pq->pq_lists[i].pl_queued = 0;
+ }
+ /* Initialize the priority queue: */
+ TAILQ_INIT(&pq->pq_queue);
+ pq->pq_flags = 0;
+ pq->pq_threads = 0;
+ }
+ return (ret);
+}
+
+void
+_pq_remove(pq_queue_t *pq, pthread_t pthread)
+{
+ int prio = pthread->active_priority;
+
+ /*
+ * Make some assertions when debugging is enabled:
+ */
+ PQ_ASSERT_INACTIVE(pq, "_pq_remove: pq_active");
+ PQ_SET_ACTIVE(pq);
+ PQ_ASSERT_IN_RUNQ(pthread, "_pq_remove: Not in priority queue");
+
+ /*
+ * Remove this thread from priority list. Note that if
+ * the priority list becomes empty, it is not removed
+ * from the priority queue because another thread may be
+ * added to the priority list (resulting in a needless
+ * removal/insertion). Priority lists are only removed
+ * from the priority queue when _pq_first is called.
+ */
+ TAILQ_REMOVE(&pq->pq_lists[prio].pl_head, pthread, pqe);
+ pq->pq_threads--;
+ /* This thread is now longer in the priority queue. */
+ pthread->flags &= ~THR_FLAGS_IN_RUNQ;
+
+ PQ_CLEAR_ACTIVE(pq);
+}
+
+
+void
+_pq_insert_head(pq_queue_t *pq, pthread_t pthread)
+{
+ int prio;
+
+ /*
+ * Make some assertions when debugging is enabled:
+ */
+ PQ_ASSERT_INACTIVE(pq, "_pq_insert_head: pq_active");
+ PQ_SET_ACTIVE(pq);
+ PQ_ASSERT_NOT_QUEUED(pthread,
+ "_pq_insert_head: Already in priority queue");
+
+ prio = pthread->active_priority;
+ TAILQ_INSERT_HEAD(&pq->pq_lists[prio].pl_head, pthread, pqe);
+ if (pq->pq_lists[prio].pl_queued == 0)
+ /* Insert the list into the priority queue: */
+ pq_insert_prio_list(pq, prio);
+ pq->pq_threads++;
+ /* Mark this thread as being in the priority queue. */
+ pthread->flags |= THR_FLAGS_IN_RUNQ;
+
+ PQ_CLEAR_ACTIVE(pq);
+}
+
+
+void
+_pq_insert_tail(pq_queue_t *pq, pthread_t pthread)
+{
+ int prio;
+
+ /*
+ * Make some assertions when debugging is enabled:
+ */
+ PQ_ASSERT_INACTIVE(pq, "_pq_insert_tail: pq_active");
+ PQ_SET_ACTIVE(pq);
+ PQ_ASSERT_NOT_QUEUED(pthread,
+ "_pq_insert_tail: Already in priority queue");
+
+ prio = pthread->active_priority;
+ TAILQ_INSERT_TAIL(&pq->pq_lists[prio].pl_head, pthread, pqe);
+ if (pq->pq_lists[prio].pl_queued == 0)
+ /* Insert the list into the priority queue: */
+ pq_insert_prio_list(pq, prio);
+ pq->pq_threads++;
+ /* Mark this thread as being in the priority queue. */
+ pthread->flags |= THR_FLAGS_IN_RUNQ;
+
+ PQ_CLEAR_ACTIVE(pq);
+}
+
+
+pthread_t
+_pq_first(pq_queue_t *pq)
+{
+ pq_list_t *pql;
+ pthread_t pthread = NULL;
+
+ /*
+ * Make some assertions when debugging is enabled:
+ */
+ PQ_ASSERT_INACTIVE(pq, "_pq_first: pq_active");
+ PQ_SET_ACTIVE(pq);
+
+ while (((pql = TAILQ_FIRST(&pq->pq_queue)) != NULL) &&
+ (pthread == NULL)) {
+ if ((pthread = TAILQ_FIRST(&pql->pl_head)) == NULL) {
+ /*
+ * The priority list is empty; remove the list
+ * from the queue.
+ */
+ TAILQ_REMOVE(&pq->pq_queue, pql, pl_link);
+
+ /* Mark the list as not being in the queue: */
+ pql->pl_queued = 0;
+ }
+ }
+
+ PQ_CLEAR_ACTIVE(pq);
+ return (pthread);
+}
+
+/*
+ * Select a thread which is allowed to run by debugger, we probably
+ * should merge the function into _pq_first if that function is only
+ * used by scheduler to select a thread.
+ */
+pthread_t
+_pq_first_debug(pq_queue_t *pq)
+{
+ pq_list_t *pql, *pqlnext = NULL;
+ pthread_t pthread = NULL;
+
+ /*
+ * Make some assertions when debugging is enabled:
+ */
+ PQ_ASSERT_INACTIVE(pq, "_pq_first: pq_active");
+ PQ_SET_ACTIVE(pq);
+
+ for (pql = TAILQ_FIRST(&pq->pq_queue);
+ pql != NULL && pthread == NULL; pql = pqlnext) {
+ if ((pthread = TAILQ_FIRST(&pql->pl_head)) == NULL) {
+ /*
+ * The priority list is empty; remove the list
+ * from the queue.
+ */
+ pqlnext = TAILQ_NEXT(pql, pl_link);
+ TAILQ_REMOVE(&pq->pq_queue, pql, pl_link);
+
+ /* Mark the list as not being in the queue: */
+ pql->pl_queued = 0;
+ } else {
+ /*
+ * note there may be a suspension event during this
+ * test, If TMDF_SUSPEND is set after we tested it,
+ * we will run the thread, this seems be a problem,
+ * fortunatly, when we are being debugged, all context
+ * switch will be done by kse_switchin, that is a
+ * syscall, kse_switchin will check the flag again,
+ * the thread will be returned via upcall, so next
+ * time, UTS won't run the thread.
+ */
+ while (pthread != NULL && !DBG_CAN_RUN(pthread)) {
+ pthread = TAILQ_NEXT(pthread, pqe);
+ }
+ if (pthread == NULL)
+ pqlnext = TAILQ_NEXT(pql, pl_link);
+ }
+ }
+
+ PQ_CLEAR_ACTIVE(pq);
+ return (pthread);
+}
+
+static void
+pq_insert_prio_list(pq_queue_t *pq, int prio)
+{
+ pq_list_t *pql;
+
+ /*
+ * Make some assertions when debugging is enabled:
+ */
+ PQ_ASSERT_ACTIVE(pq, "pq_insert_prio_list: pq_active");
+
+ /*
+ * The priority queue is in descending priority order. Start at
+ * the beginning of the queue and find the list before which the
+ * new list should be inserted.
+ */
+ pql = TAILQ_FIRST(&pq->pq_queue);
+ while ((pql != NULL) && (pql->pl_prio > prio))
+ pql = TAILQ_NEXT(pql, pl_link);
+
+ /* Insert the list: */
+ if (pql == NULL)
+ TAILQ_INSERT_TAIL(&pq->pq_queue, &pq->pq_lists[prio], pl_link);
+ else
+ TAILQ_INSERT_BEFORE(pql, &pq->pq_lists[prio], pl_link);
+
+ /* Mark this list as being in the queue: */
+ pq->pq_lists[prio].pl_queued = 1;
+}
diff --git a/lib/libpthread/thread/thr_private.h b/lib/libpthread/thread/thr_private.h
new file mode 100644
index 0000000..f839960
--- /dev/null
+++ b/lib/libpthread/thread/thr_private.h
@@ -0,0 +1,1320 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Private thread definitions for the uthread kernel.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _THR_PRIVATE_H
+#define _THR_PRIVATE_H
+
+/*
+ * Include files.
+ */
+#include <setjmp.h>
+#include <signal.h>
+#include <stdio.h>
+#include <sys/queue.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/cdefs.h>
+#include <sys/kse.h>
+#include <sched.h>
+#include <ucontext.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <pthread_np.h>
+
+#ifndef LIBTHREAD_DB
+#include "lock.h"
+#include "pthread_md.h"
+#endif
+
+/*
+ * Unfortunately, libpthread had symbol versioning before libc.
+ * But now libc has symbol versioning, we need to occupy the
+ * same version namespace in order to override some libc functions.
+ * So in order to avoid breaking binaries requiring symbols from
+ * LIBTHREAD_1_0, we need to provide a compatible interface for
+ * those symbols.
+ */
+#if defined(SYMBOL_VERSIONING) && defined(PIC)
+#define SYM_LT10(sym) __CONCAT(sym, _lt10)
+#define SYM_FB10(sym) __CONCAT(sym, _fb10)
+#define SYM_FBP10(sym) __CONCAT(sym, _fbp10)
+#define WEAK_REF(sym, alias) __weak_reference(sym, alias)
+#define SYM_COMPAT(sym, impl, ver) __sym_compat(sym, impl, ver)
+#define SYM_DEFAULT(sym, impl, ver) __sym_default(sym, impl, ver)
+
+#define LT10_COMPAT(sym) \
+ WEAK_REF(sym, SYM_LT10(sym)); \
+ SYM_COMPAT(sym, SYM_LT10(sym), LIBTHREAD_1_0)
+
+#define LT10_COMPAT_DEFAULT(sym) \
+ LT10_COMPAT(sym); \
+ WEAK_REF(sym, SYM_FB10(sym)); \
+ SYM_DEFAULT(sym, SYM_FB10(sym), FBSD_1.0)
+
+#define LT10_COMPAT_PRIVATE(sym) \
+ LT10_COMPAT(sym); \
+ WEAK_REF(sym, SYM_FBP10(sym)); \
+ SYM_DEFAULT(sym, SYM_FBP10(sym), FBSDprivate)
+#else
+#define LT10_COMPAT_DEFAULT(sym)
+#define LT10_COMPAT_PRIVATE(sym)
+#endif
+
+/*
+ * Evaluate the storage class specifier.
+ */
+#ifdef GLOBAL_PTHREAD_PRIVATE
+#define SCLASS
+#define SCLASS_PRESET(x...) = x
+#else
+#define SCLASS extern
+#define SCLASS_PRESET(x...)
+#endif
+
+/*
+ * Kernel fatal error handler macro.
+ */
+#define PANIC(string) _thr_exit(__FILE__, __LINE__, string)
+
+
+/* Output debug messages like this: */
+#ifdef STDOUT_FILENO
+#define stdout_debug(...) _thread_printf(STDOUT_FILENO, __VA_ARGS__)
+#endif
+#ifdef STDERR_FILENO
+#define stderr_debug(...) _thread_printf(STDERR_FILENO, __VA_ARGS__)
+#endif
+
+#define DBG_MUTEX 0x0001
+#define DBG_SIG 0x0002
+#define DBG_INFO_DUMP 0x0004
+
+#ifdef _PTHREADS_INVARIANTS
+#define THR_ASSERT(cond, msg) do { \
+ if (!(cond)) \
+ PANIC(msg); \
+} while (0)
+#else
+#define THR_ASSERT(cond, msg)
+#endif
+
+/*
+ * State change macro without scheduling queue change:
+ */
+#define THR_SET_STATE(thrd, newstate) do { \
+ (thrd)->state = newstate; \
+ (thrd)->fname = __FILE__; \
+ (thrd)->lineno = __LINE__; \
+} while (0)
+
+
+#define TIMESPEC_ADD(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 >= 1000000000) { \
+ (dst)->tv_sec++; \
+ (dst)->tv_nsec -= 1000000000; \
+ } \
+ } while (0)
+
+#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)
+
+/*
+ * Priority queues.
+ *
+ * XXX It'd be nice if these were contained in uthread_priority_queue.[ch].
+ */
+typedef struct pq_list {
+ TAILQ_HEAD(, pthread) pl_head; /* list of threads at this priority */
+ TAILQ_ENTRY(pq_list) pl_link; /* link for queue of priority lists */
+ int pl_prio; /* the priority of this list */
+ int pl_queued; /* is this in the priority queue */
+} pq_list_t;
+
+typedef struct pq_queue {
+ TAILQ_HEAD(, pq_list) pq_queue; /* queue of priority lists */
+ pq_list_t *pq_lists; /* array of all priority lists */
+ int pq_size; /* number of priority lists */
+#define PQF_ACTIVE 0x0001
+ int pq_flags;
+ int pq_threads;
+} pq_queue_t;
+
+/*
+ * Each KSEG has a scheduling queue. For now, threads that exist in their
+ * own KSEG (system scope) will get a full priority queue. In the future
+ * this can be optimized for the single thread per KSEG case.
+ */
+struct sched_queue {
+ pq_queue_t sq_runq;
+ TAILQ_HEAD(, pthread) sq_waitq; /* waiting in userland */
+};
+
+typedef struct kse_thr_mailbox *kse_critical_t;
+
+struct kse_group;
+
+#define MAX_KSE_LOCKLEVEL 5
+struct kse {
+ /* -- location and order specific items for gdb -- */
+ struct kcb *k_kcb;
+ struct pthread *k_curthread; /* current thread */
+ struct kse_group *k_kseg; /* parent KSEG */
+ struct sched_queue *k_schedq; /* scheduling queue */
+ /* -- end of location and order specific items -- */
+ TAILQ_ENTRY(kse) k_qe; /* KSE list link entry */
+ TAILQ_ENTRY(kse) k_kgqe; /* KSEG's KSE list entry */
+ /*
+ * Items that are only modified by the kse, or that otherwise
+ * don't need to be locked when accessed
+ */
+ struct lock k_lock;
+ struct lockuser k_lockusers[MAX_KSE_LOCKLEVEL];
+ int k_locklevel;
+ stack_t k_stack;
+ int k_flags;
+#define KF_STARTED 0x0001 /* kernel kse created */
+#define KF_INITIALIZED 0x0002 /* initialized on 1st upcall */
+#define KF_TERMINATED 0x0004 /* kse is terminated */
+#define KF_IDLE 0x0008 /* kse is idle */
+#define KF_SWITCH 0x0010 /* thread switch in UTS */
+ int k_error; /* syscall errno in critical */
+ int k_cpu; /* CPU ID when bound */
+ int k_sigseqno; /* signal buffered count */
+};
+
+#define KSE_SET_IDLE(kse) ((kse)->k_flags |= KF_IDLE)
+#define KSE_CLEAR_IDLE(kse) ((kse)->k_flags &= ~KF_IDLE)
+#define KSE_IS_IDLE(kse) (((kse)->k_flags & KF_IDLE) != 0)
+#define KSE_SET_SWITCH(kse) ((kse)->k_flags |= KF_SWITCH)
+#define KSE_CLEAR_SWITCH(kse) ((kse)->k_flags &= ~KF_SWITCH)
+#define KSE_IS_SWITCH(kse) (((kse)->k_flags & KF_SWITCH) != 0)
+
+/*
+ * Each KSE group contains one or more KSEs in which threads can run.
+ * At least for now, there is one scheduling queue per KSE group; KSEs
+ * within the same KSE group compete for threads from the same scheduling
+ * queue. A scope system thread has one KSE in one KSE group; the group
+ * does not use its scheduling queue.
+ */
+struct kse_group {
+ TAILQ_HEAD(, kse) kg_kseq; /* list of KSEs in group */
+ TAILQ_HEAD(, pthread) kg_threadq; /* list of threads in group */
+ TAILQ_ENTRY(kse_group) kg_qe; /* link entry */
+ struct sched_queue kg_schedq; /* scheduling queue */
+ struct lock kg_lock;
+ int kg_threadcount; /* # of assigned threads */
+ int kg_ksecount; /* # of assigned KSEs */
+ int kg_idle_kses;
+ int kg_flags;
+#define KGF_SINGLE_THREAD 0x0001 /* scope system kse group */
+#define KGF_SCHEDQ_INITED 0x0002 /* has an initialized schedq */
+};
+
+/*
+ * Add/remove threads from a KSE's scheduling queue.
+ * For now the scheduling queue is hung off the KSEG.
+ */
+#define KSEG_THRQ_ADD(kseg, thr) \
+do { \
+ TAILQ_INSERT_TAIL(&(kseg)->kg_threadq, thr, kle);\
+ (kseg)->kg_threadcount++; \
+} while (0)
+
+#define KSEG_THRQ_REMOVE(kseg, thr) \
+do { \
+ TAILQ_REMOVE(&(kseg)->kg_threadq, thr, kle); \
+ (kseg)->kg_threadcount--; \
+} while (0)
+
+
+/*
+ * Lock acquire and release for KSEs.
+ */
+#define KSE_LOCK_ACQUIRE(kse, lck) \
+do { \
+ if ((kse)->k_locklevel < MAX_KSE_LOCKLEVEL) { \
+ (kse)->k_locklevel++; \
+ _lock_acquire((lck), \
+ &(kse)->k_lockusers[(kse)->k_locklevel - 1], 0); \
+ } \
+ else \
+ PANIC("Exceeded maximum lock level"); \
+} while (0)
+
+#define KSE_LOCK_RELEASE(kse, lck) \
+do { \
+ if ((kse)->k_locklevel > 0) { \
+ _lock_release((lck), \
+ &(kse)->k_lockusers[(kse)->k_locklevel - 1]); \
+ (kse)->k_locklevel--; \
+ } \
+} while (0)
+
+/*
+ * Lock our own KSEG.
+ */
+#define KSE_LOCK(curkse) \
+ KSE_LOCK_ACQUIRE(curkse, &(curkse)->k_kseg->kg_lock)
+#define KSE_UNLOCK(curkse) \
+ KSE_LOCK_RELEASE(curkse, &(curkse)->k_kseg->kg_lock)
+
+/*
+ * Lock a potentially different KSEG.
+ */
+#define KSE_SCHED_LOCK(curkse, kseg) \
+ KSE_LOCK_ACQUIRE(curkse, &(kseg)->kg_lock)
+#define KSE_SCHED_UNLOCK(curkse, kseg) \
+ KSE_LOCK_RELEASE(curkse, &(kseg)->kg_lock)
+
+/*
+ * Waiting queue manipulation macros (using pqe link):
+ */
+#define KSE_WAITQ_REMOVE(kse, thrd) \
+do { \
+ if (((thrd)->flags & THR_FLAGS_IN_WAITQ) != 0) { \
+ TAILQ_REMOVE(&(kse)->k_schedq->sq_waitq, thrd, pqe); \
+ (thrd)->flags &= ~THR_FLAGS_IN_WAITQ; \
+ } \
+} while (0)
+#define KSE_WAITQ_INSERT(kse, thrd) kse_waitq_insert(thrd)
+#define KSE_WAITQ_FIRST(kse) TAILQ_FIRST(&(kse)->k_schedq->sq_waitq)
+
+#define KSE_WAKEUP(kse) kse_wakeup(&(kse)->k_kcb->kcb_kmbx)
+
+/*
+ * TailQ initialization values.
+ */
+#define TAILQ_INITIALIZER { NULL, NULL }
+
+/*
+ * lock initialization values.
+ */
+#define LCK_INITIALIZER { NULL, NULL, LCK_DEFAULT }
+
+struct pthread_mutex {
+ /*
+ * Lock for accesses to this structure.
+ */
+ struct lock m_lock;
+ enum pthread_mutextype m_type;
+ int m_protocol;
+ TAILQ_HEAD(mutex_head, pthread) m_queue;
+ struct pthread *m_owner;
+ long m_flags;
+ int m_count;
+ int m_refcount;
+
+ /*
+ * Used for priority inheritence and protection.
+ *
+ * m_prio - For priority inheritence, the highest active
+ * priority (threads locking the mutex inherit
+ * this priority). For priority protection, the
+ * ceiling priority of this mutex.
+ * m_saved_prio - mutex owners inherited priority before
+ * taking the mutex, restored when the owner
+ * unlocks the mutex.
+ */
+ int m_prio;
+ int m_saved_prio;
+
+ /*
+ * Link for list of all mutexes a thread currently owns.
+ */
+ TAILQ_ENTRY(pthread_mutex) m_qe;
+};
+
+/*
+ * Flags for mutexes.
+ */
+#define MUTEX_FLAGS_PRIVATE 0x01
+#define MUTEX_FLAGS_INITED 0x02
+#define MUTEX_FLAGS_BUSY 0x04
+
+/*
+ * Static mutex initialization values.
+ */
+#define PTHREAD_MUTEX_STATIC_INITIALIZER \
+ { LCK_INITIALIZER, PTHREAD_MUTEX_DEFAULT, PTHREAD_PRIO_NONE, \
+ TAILQ_INITIALIZER, NULL, MUTEX_FLAGS_PRIVATE, 0, 0, 0, 0, \
+ TAILQ_INITIALIZER }
+
+struct pthread_mutex_attr {
+ enum pthread_mutextype m_type;
+ int m_protocol;
+ int m_ceiling;
+ long m_flags;
+};
+
+#define PTHREAD_MUTEXATTR_STATIC_INITIALIZER \
+ { PTHREAD_MUTEX_DEFAULT, PTHREAD_PRIO_NONE, 0, MUTEX_FLAGS_PRIVATE }
+
+/*
+ * Condition variable definitions.
+ */
+enum pthread_cond_type {
+ COND_TYPE_FAST,
+ COND_TYPE_MAX
+};
+
+struct pthread_cond {
+ /*
+ * Lock for accesses to this structure.
+ */
+ struct lock c_lock;
+ enum pthread_cond_type c_type;
+ TAILQ_HEAD(cond_head, pthread) c_queue;
+ struct pthread_mutex *c_mutex;
+ long c_flags;
+ long c_seqno;
+};
+
+struct pthread_cond_attr {
+ enum pthread_cond_type c_type;
+ long c_flags;
+};
+
+struct pthread_barrier {
+ pthread_mutex_t b_lock;
+ pthread_cond_t b_cond;
+ int b_count;
+ int b_waiters;
+ int b_generation;
+};
+
+struct pthread_barrierattr {
+ int pshared;
+};
+
+struct pthread_spinlock {
+ volatile int s_lock;
+ pthread_t s_owner;
+};
+
+/*
+ * Flags for condition variables.
+ */
+#define COND_FLAGS_PRIVATE 0x01
+#define COND_FLAGS_INITED 0x02
+#define COND_FLAGS_BUSY 0x04
+
+/*
+ * Static cond initialization values.
+ */
+#define PTHREAD_COND_STATIC_INITIALIZER \
+ { LCK_INITIALIZER, COND_TYPE_FAST, TAILQ_INITIALIZER, \
+ NULL, NULL, 0, 0 }
+
+/*
+ * Cleanup definitions.
+ */
+struct pthread_cleanup {
+ struct pthread_cleanup *next;
+ void (*routine) (void *);
+ void *routine_arg;
+ int onstack;
+};
+
+#define THR_CLEANUP_PUSH(td, func, arg) { \
+ struct pthread_cleanup __cup; \
+ \
+ __cup.routine = func; \
+ __cup.routine_arg = arg; \
+ __cup.onstack = 1; \
+ __cup.next = (td)->cleanup; \
+ (td)->cleanup = &__cup;
+
+#define THR_CLEANUP_POP(td, exec) \
+ (td)->cleanup = __cup.next; \
+ if ((exec) != 0) \
+ __cup.routine(__cup.routine_arg); \
+}
+
+struct pthread_atfork {
+ TAILQ_ENTRY(pthread_atfork) qe;
+ void (*prepare)(void);
+ void (*parent)(void);
+ void (*child)(void);
+};
+
+struct pthread_attr {
+ int sched_policy;
+ int sched_inherit;
+ int sched_interval;
+ int prio;
+ int suspend;
+#define THR_STACK_USER 0x100 /* 0xFF reserved for <pthread.h> */
+#define THR_SIGNAL_THREAD 0x200 /* This is a signal thread */
+ int flags;
+ void *arg_attr;
+ void (*cleanup_attr) (void *);
+ void *stackaddr_attr;
+ size_t stacksize_attr;
+ size_t guardsize_attr;
+};
+
+/*
+ * Thread creation state attributes.
+ */
+#define THR_CREATE_RUNNING 0
+#define THR_CREATE_SUSPENDED 1
+
+/*
+ * Miscellaneous definitions.
+ */
+#define THR_STACK32_DEFAULT (1 * 1024 * 1024)
+#define THR_STACK64_DEFAULT (2 * 1024 * 1024)
+
+/*
+ * Maximum size of initial thread's stack. This perhaps deserves to be larger
+ * than the stacks of other threads, since many applications are likely to run
+ * almost entirely on this stack.
+ */
+#define THR_STACK32_INITIAL (2 * 1024 * 1024)
+#define THR_STACK64_INITIAL (4 * 1024 * 1024)
+
+/*
+ * Define the different priority ranges. All applications have thread
+ * priorities constrained within 0-31. The threads library raises the
+ * priority when delivering signals in order to ensure that signal
+ * delivery happens (from the POSIX spec) "as soon as possible".
+ * In the future, the threads library will also be able to map specific
+ * threads into real-time (cooperating) processes or kernel threads.
+ * The RT and SIGNAL priorities will be used internally and added to
+ * thread base priorities so that the scheduling queue can handle both
+ * normal and RT priority threads with and without signal handling.
+ *
+ * The approach taken is that, within each class, signal delivery
+ * always has priority over thread execution.
+ */
+#define THR_DEFAULT_PRIORITY 15
+#define THR_MIN_PRIORITY 0
+#define THR_MAX_PRIORITY 31 /* 0x1F */
+#define THR_SIGNAL_PRIORITY 32 /* 0x20 */
+#define THR_RT_PRIORITY 64 /* 0x40 */
+#define THR_FIRST_PRIORITY THR_MIN_PRIORITY
+#define THR_LAST_PRIORITY \
+ (THR_MAX_PRIORITY + THR_SIGNAL_PRIORITY + THR_RT_PRIORITY)
+#define THR_BASE_PRIORITY(prio) ((prio) & THR_MAX_PRIORITY)
+
+/*
+ * Clock resolution in microseconds.
+ */
+#define CLOCK_RES_USEC 10000
+
+/*
+ * Time slice period in microseconds.
+ */
+#define TIMESLICE_USEC 20000
+
+/*
+ * XXX - Define a thread-safe macro to get the current time of day
+ * which is updated at regular intervals by something.
+ *
+ * For now, we just make the system call to get the time.
+ */
+#define KSE_GET_TOD(curkse, tsp) \
+do { \
+ *tsp = (curkse)->k_kcb->kcb_kmbx.km_timeofday; \
+ if ((tsp)->tv_sec == 0) \
+ clock_gettime(CLOCK_REALTIME, tsp); \
+} while (0)
+
+struct pthread_rwlockattr {
+ int pshared;
+};
+
+struct pthread_rwlock {
+ pthread_mutex_t lock; /* monitor lock */
+ pthread_cond_t read_signal;
+ pthread_cond_t write_signal;
+ int state; /* 0 = idle >0 = # of readers -1 = writer */
+ int blocked_writers;
+};
+
+/*
+ * Thread states.
+ */
+enum pthread_state {
+ PS_RUNNING,
+ PS_LOCKWAIT,
+ PS_MUTEX_WAIT,
+ PS_COND_WAIT,
+ PS_SLEEP_WAIT,
+ PS_SIGSUSPEND,
+ PS_SIGWAIT,
+ PS_JOIN,
+ PS_SUSPENDED,
+ PS_DEAD,
+ PS_DEADLOCK,
+ PS_STATE_MAX
+};
+
+struct sigwait_data {
+ sigset_t *waitset;
+ siginfo_t *siginfo; /* used to save siginfo for sigwaitinfo() */
+};
+
+union pthread_wait_data {
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+ struct lock *lock;
+ struct sigwait_data *sigwait;
+};
+
+/*
+ * Define a continuation routine that can be used to perform a
+ * transfer of control:
+ */
+typedef void (*thread_continuation_t) (void *);
+
+/*
+ * This stores a thread's state prior to running a signal handler.
+ * It is used when a signal is delivered to a thread blocked in
+ * userland. If the signal handler returns normally, the thread's
+ * state is restored from here.
+ */
+struct pthread_sigframe {
+ int psf_valid;
+ int psf_flags;
+ int psf_cancelflags;
+ int psf_interrupted;
+ int psf_timeout;
+ int psf_signo;
+ enum pthread_state psf_state;
+ union pthread_wait_data psf_wait_data;
+ struct timespec psf_wakeup_time;
+ sigset_t psf_sigset;
+ sigset_t psf_sigmask;
+ int psf_seqno;
+ thread_continuation_t psf_continuation;
+};
+
+struct join_status {
+ struct pthread *thread;
+ void *ret;
+ int error;
+};
+
+struct pthread_specific_elem {
+ const void *data;
+ int seqno;
+};
+
+struct pthread_key {
+ volatile int allocated;
+ volatile int count;
+ int seqno;
+ void (*destructor) (void *);
+};
+
+#define MAX_THR_LOCKLEVEL 5
+/*
+ * Thread structure.
+ */
+struct pthread {
+ /* Thread control block */
+ struct tcb *tcb;
+
+ /*
+ * Magic value to help recognize a valid thread structure
+ * from an invalid one:
+ */
+#define THR_MAGIC ((u_int32_t) 0xd09ba115)
+ u_int32_t magic;
+ char *name;
+ u_int64_t uniqueid; /* for gdb */
+
+ /* Queue entry for list of all threads: */
+ TAILQ_ENTRY(pthread) tle; /* link for all threads in process */
+ TAILQ_ENTRY(pthread) kle; /* link for all threads in KSE/KSEG */
+
+ /* Queue entry for GC lists: */
+ TAILQ_ENTRY(pthread) gcle;
+
+ /* Hash queue entry */
+ LIST_ENTRY(pthread) hle;
+
+ /*
+ * Lock for accesses to this thread structure.
+ */
+ struct lock lock;
+ struct lockuser lockusers[MAX_THR_LOCKLEVEL];
+ int locklevel;
+ kse_critical_t critical[MAX_KSE_LOCKLEVEL];
+ struct kse *kse;
+ struct kse_group *kseg;
+
+ /*
+ * Thread start routine, argument, stack pointer and thread
+ * attributes.
+ */
+ void *(*start_routine)(void *);
+ void *arg;
+ struct pthread_attr attr;
+
+ int active; /* thread running */
+ int blocked; /* thread blocked in kernel */
+ int need_switchout;
+
+ /*
+ * Used for tracking delivery of signal handlers.
+ */
+ siginfo_t *siginfo;
+ thread_continuation_t sigbackout;
+
+ /*
+ * Cancelability flags - the lower 2 bits are used by cancel
+ * definitions in pthread.h
+ */
+#define THR_AT_CANCEL_POINT 0x0004
+#define THR_CANCELLING 0x0008
+#define THR_CANCEL_NEEDED 0x0010
+ int cancelflags;
+
+ thread_continuation_t continuation;
+
+ /*
+ * The thread's base and pending signal masks. The active
+ * signal mask is stored in the thread's context (in mailbox).
+ */
+ sigset_t sigmask;
+ sigset_t sigpend;
+ sigset_t *oldsigmask;
+ volatile int check_pending;
+ int refcount;
+
+ /* Thread state: */
+ enum pthread_state state;
+ volatile int lock_switch;
+
+ /*
+ * Number of microseconds accumulated by this thread when
+ * time slicing is active.
+ */
+ long slice_usec;
+
+ /*
+ * Time to wake up thread. This is used for sleeping threads and
+ * for any operation which may time out (such as select).
+ */
+ struct timespec wakeup_time;
+
+ /* TRUE if operation has timed out. */
+ int timeout;
+
+ /*
+ * Error variable used instead of errno. The function __error()
+ * returns a pointer to this.
+ */
+ int error;
+
+ /*
+ * The joiner is the thread that is joining to this thread. The
+ * join status keeps track of a join operation to another thread.
+ */
+ struct pthread *joiner;
+ struct join_status join_status;
+
+ /*
+ * The current thread can belong to only one scheduling queue at
+ * a time (ready or waiting queue). It can also belong to:
+ *
+ * o A queue of threads waiting for a mutex
+ * o A queue of threads waiting for a condition variable
+ *
+ * It is possible for a thread to belong to more than one of the
+ * above queues if it is handling a signal. A thread may only
+ * enter a mutex or condition variable queue when it is not
+ * being called from a signal handler. If a thread is a member
+ * of one of these queues when a signal handler is invoked, it
+ * must be removed from the queue before invoking the handler
+ * and then added back to the queue after return from the handler.
+ *
+ * Use pqe for the scheduling queue link (both ready and waiting),
+ * sqe for synchronization (mutex, condition variable, and join)
+ * queue links, and qe for all other links.
+ */
+ TAILQ_ENTRY(pthread) pqe; /* priority, wait queues link */
+ TAILQ_ENTRY(pthread) sqe; /* synchronization queue link */
+
+ /* Wait data. */
+ union pthread_wait_data data;
+
+ /*
+ * Set to TRUE if a blocking operation was
+ * interrupted by a signal:
+ */
+ int interrupted;
+
+ /*
+ * Set to non-zero when this thread has entered a critical
+ * region. We allow for recursive entries into critical regions.
+ */
+ int critical_count;
+
+ /*
+ * Set to TRUE if this thread should yield after leaving a
+ * critical region to check for signals, messages, etc.
+ */
+ int critical_yield;
+
+ int sflags;
+#define THR_FLAGS_IN_SYNCQ 0x0001
+
+ /* Miscellaneous flags; only set with scheduling lock held. */
+ int flags;
+#define THR_FLAGS_PRIVATE 0x0001
+#define THR_FLAGS_IN_WAITQ 0x0002 /* in waiting queue using pqe link */
+#define THR_FLAGS_IN_RUNQ 0x0004 /* in run queue using pqe link */
+#define THR_FLAGS_EXITING 0x0008 /* thread is exiting */
+#define THR_FLAGS_SUSPENDED 0x0010 /* thread is suspended */
+
+ /* Thread list flags; only set with thread list lock held. */
+#define TLFLAGS_GC_SAFE 0x0001 /* thread safe for cleaning */
+#define TLFLAGS_IN_TDLIST 0x0002 /* thread in all thread list */
+#define TLFLAGS_IN_GCLIST 0x0004 /* thread in gc list */
+ int tlflags;
+
+ /*
+ * Base priority is the user setable and retrievable priority
+ * of the thread. It is only affected by explicit calls to
+ * set thread priority and upon thread creation via a thread
+ * attribute or default priority.
+ */
+ char base_priority;
+
+ /*
+ * Inherited priority is the priority a thread inherits by
+ * taking a priority inheritence or protection mutex. It
+ * is not affected by base priority changes. Inherited
+ * priority defaults to and remains 0 until a mutex is taken
+ * that is being waited on by any other thread whose priority
+ * is non-zero.
+ */
+ char inherited_priority;
+
+ /*
+ * Active priority is always the maximum of the threads base
+ * priority and inherited priority. When there is a change
+ * in either the base or inherited priority, the active
+ * priority must be recalculated.
+ */
+ char active_priority;
+
+ /* Number of priority ceiling or protection mutexes owned. */
+ int priority_mutex_count;
+
+ /* Number rwlocks rdlocks held. */
+ int rdlock_count;
+
+ /*
+ * Queue of currently owned mutexes.
+ */
+ TAILQ_HEAD(, pthread_mutex) mutexq;
+
+ void *ret;
+ struct pthread_specific_elem *specific;
+ int specific_data_count;
+
+ /* Alternative stack for sigaltstack() */
+ stack_t sigstk;
+
+ /*
+ * Current locks bitmap for rtld.
+ */
+ int rtld_bits;
+
+ /* Cleanup handlers Link List */
+ struct pthread_cleanup *cleanup;
+ char *fname; /* Ptr to source file name */
+ int lineno; /* Source line number. */
+};
+
+/*
+ * Critical regions can also be detected by looking at the threads
+ * current lock level. Ensure these macros increment and decrement
+ * the lock levels such that locks can not be held with a lock level
+ * of 0.
+ */
+#define THR_IN_CRITICAL(thrd) \
+ (((thrd)->locklevel > 0) || \
+ ((thrd)->critical_count > 0))
+
+#define THR_YIELD_CHECK(thrd) \
+do { \
+ if (!THR_IN_CRITICAL(thrd)) { \
+ if (__predict_false(_libkse_debug)) \
+ _thr_debug_check_yield(thrd); \
+ if ((thrd)->critical_yield != 0) \
+ _thr_sched_switch(thrd); \
+ if ((thrd)->check_pending != 0) \
+ _thr_sig_check_pending(thrd); \
+ } \
+} while (0)
+
+#define THR_LOCK_ACQUIRE(thrd, lck) \
+do { \
+ if ((thrd)->locklevel < MAX_THR_LOCKLEVEL) { \
+ THR_DEACTIVATE_LAST_LOCK(thrd); \
+ (thrd)->locklevel++; \
+ _lock_acquire((lck), \
+ &(thrd)->lockusers[(thrd)->locklevel - 1], \
+ (thrd)->active_priority); \
+ } else \
+ PANIC("Exceeded maximum lock level"); \
+} while (0)
+
+#define THR_LOCK_RELEASE(thrd, lck) \
+do { \
+ if ((thrd)->locklevel > 0) { \
+ _lock_release((lck), \
+ &(thrd)->lockusers[(thrd)->locklevel - 1]); \
+ (thrd)->locklevel--; \
+ THR_ACTIVATE_LAST_LOCK(thrd); \
+ if ((thrd)->locklevel == 0) \
+ THR_YIELD_CHECK(thrd); \
+ } \
+} while (0)
+
+#define THR_ACTIVATE_LAST_LOCK(thrd) \
+do { \
+ if ((thrd)->locklevel > 0) \
+ _lockuser_setactive( \
+ &(thrd)->lockusers[(thrd)->locklevel - 1], 1); \
+} while (0)
+
+#define THR_DEACTIVATE_LAST_LOCK(thrd) \
+do { \
+ if ((thrd)->locklevel > 0) \
+ _lockuser_setactive( \
+ &(thrd)->lockusers[(thrd)->locklevel - 1], 0); \
+} while (0)
+
+/*
+ * For now, threads will have their own lock separate from their
+ * KSE scheduling lock.
+ */
+#define THR_LOCK(thr) THR_LOCK_ACQUIRE(thr, &(thr)->lock)
+#define THR_UNLOCK(thr) THR_LOCK_RELEASE(thr, &(thr)->lock)
+#define THR_THREAD_LOCK(curthrd, thr) THR_LOCK_ACQUIRE(curthrd, &(thr)->lock)
+#define THR_THREAD_UNLOCK(curthrd, thr) THR_LOCK_RELEASE(curthrd, &(thr)->lock)
+
+/*
+ * Priority queue manipulation macros (using pqe link). We use
+ * the thread's kseg link instead of the kse link because a thread
+ * does not (currently) have a statically assigned kse.
+ */
+#define THR_RUNQ_INSERT_HEAD(thrd) \
+ _pq_insert_head(&(thrd)->kseg->kg_schedq.sq_runq, thrd)
+#define THR_RUNQ_INSERT_TAIL(thrd) \
+ _pq_insert_tail(&(thrd)->kseg->kg_schedq.sq_runq, thrd)
+#define THR_RUNQ_REMOVE(thrd) \
+ _pq_remove(&(thrd)->kseg->kg_schedq.sq_runq, thrd)
+
+/*
+ * Macros to insert/remove threads to the all thread list and
+ * the gc list.
+ */
+#define THR_LIST_ADD(thrd) do { \
+ if (((thrd)->tlflags & TLFLAGS_IN_TDLIST) == 0) { \
+ TAILQ_INSERT_HEAD(&_thread_list, thrd, tle); \
+ _thr_hash_add(thrd); \
+ (thrd)->tlflags |= TLFLAGS_IN_TDLIST; \
+ } \
+} while (0)
+#define THR_LIST_REMOVE(thrd) do { \
+ if (((thrd)->tlflags & TLFLAGS_IN_TDLIST) != 0) { \
+ TAILQ_REMOVE(&_thread_list, thrd, tle); \
+ _thr_hash_remove(thrd); \
+ (thrd)->tlflags &= ~TLFLAGS_IN_TDLIST; \
+ } \
+} while (0)
+#define THR_GCLIST_ADD(thrd) do { \
+ if (((thrd)->tlflags & TLFLAGS_IN_GCLIST) == 0) { \
+ TAILQ_INSERT_HEAD(&_thread_gc_list, thrd, gcle);\
+ (thrd)->tlflags |= TLFLAGS_IN_GCLIST; \
+ _gc_count++; \
+ } \
+} while (0)
+#define THR_GCLIST_REMOVE(thrd) do { \
+ if (((thrd)->tlflags & TLFLAGS_IN_GCLIST) != 0) { \
+ TAILQ_REMOVE(&_thread_gc_list, thrd, gcle); \
+ (thrd)->tlflags &= ~TLFLAGS_IN_GCLIST; \
+ _gc_count--; \
+ } \
+} while (0)
+
+#define GC_NEEDED() (atomic_load_acq_int(&_gc_count) >= 5)
+
+/*
+ * Locking the scheduling queue for another thread uses that thread's
+ * KSEG lock.
+ */
+#define THR_SCHED_LOCK(curthr, thr) do { \
+ (curthr)->critical[(curthr)->locklevel] = _kse_critical_enter(); \
+ (curthr)->locklevel++; \
+ KSE_SCHED_LOCK((curthr)->kse, (thr)->kseg); \
+} while (0)
+
+#define THR_SCHED_UNLOCK(curthr, thr) do { \
+ KSE_SCHED_UNLOCK((curthr)->kse, (thr)->kseg); \
+ (curthr)->locklevel--; \
+ _kse_critical_leave((curthr)->critical[(curthr)->locklevel]); \
+} while (0)
+
+/* Take the scheduling lock with the intent to call the scheduler. */
+#define THR_LOCK_SWITCH(curthr) do { \
+ (void)_kse_critical_enter(); \
+ KSE_SCHED_LOCK((curthr)->kse, (curthr)->kseg); \
+} while (0)
+#define THR_UNLOCK_SWITCH(curthr) do { \
+ KSE_SCHED_UNLOCK((curthr)->kse, (curthr)->kseg);\
+} while (0)
+
+#define THR_CRITICAL_ENTER(thr) (thr)->critical_count++
+#define THR_CRITICAL_LEAVE(thr) do { \
+ (thr)->critical_count--; \
+ if (((thr)->critical_yield != 0) && \
+ ((thr)->critical_count == 0)) { \
+ (thr)->critical_yield = 0; \
+ _thr_sched_switch(thr); \
+ } \
+} while (0)
+
+#define THR_IS_ACTIVE(thrd) \
+ ((thrd)->kse != NULL) && ((thrd)->kse->k_curthread == (thrd))
+
+#define THR_IN_SYNCQ(thrd) (((thrd)->sflags & THR_FLAGS_IN_SYNCQ) != 0)
+
+#define THR_IS_SUSPENDED(thrd) \
+ (((thrd)->state == PS_SUSPENDED) || \
+ (((thrd)->flags & THR_FLAGS_SUSPENDED) != 0))
+#define THR_IS_EXITING(thrd) (((thrd)->flags & THR_FLAGS_EXITING) != 0)
+#define DBG_CAN_RUN(thrd) (((thrd)->tcb->tcb_tmbx.tm_dflags & \
+ TMDF_SUSPEND) == 0)
+
+extern int __isthreaded;
+
+static inline int
+_kse_isthreaded(void)
+{
+ return (__isthreaded != 0);
+}
+
+/*
+ * Global variables for the pthread kernel.
+ */
+
+SCLASS void *_usrstack SCLASS_PRESET(NULL);
+SCLASS struct kse *_kse_initial SCLASS_PRESET(NULL);
+SCLASS struct pthread *_thr_initial SCLASS_PRESET(NULL);
+/* For debugger */
+SCLASS int _libkse_debug SCLASS_PRESET(0);
+SCLASS int _thread_activated SCLASS_PRESET(0);
+SCLASS int _thread_scope_system SCLASS_PRESET(0);
+
+/* List of all threads: */
+SCLASS TAILQ_HEAD(, pthread) _thread_list
+ SCLASS_PRESET(TAILQ_HEAD_INITIALIZER(_thread_list));
+
+/* List of threads needing GC: */
+SCLASS TAILQ_HEAD(, pthread) _thread_gc_list
+ SCLASS_PRESET(TAILQ_HEAD_INITIALIZER(_thread_gc_list));
+
+SCLASS int _thread_active_threads SCLASS_PRESET(1);
+
+SCLASS TAILQ_HEAD(atfork_head, pthread_atfork) _thr_atfork_list;
+SCLASS pthread_mutex_t _thr_atfork_mutex;
+
+/* Default thread attributes: */
+SCLASS struct pthread_attr _pthread_attr_default
+ SCLASS_PRESET({
+ SCHED_RR, 0, TIMESLICE_USEC, THR_DEFAULT_PRIORITY,
+ THR_CREATE_RUNNING, PTHREAD_CREATE_JOINABLE, NULL,
+ NULL, NULL, /* stacksize */0, /* guardsize */0
+ });
+
+/* Default mutex attributes: */
+SCLASS struct pthread_mutex_attr _pthread_mutexattr_default
+ SCLASS_PRESET({PTHREAD_MUTEX_DEFAULT, PTHREAD_PRIO_NONE, 0, 0 });
+
+/* Default condition variable attributes: */
+SCLASS struct pthread_cond_attr _pthread_condattr_default
+ SCLASS_PRESET({COND_TYPE_FAST, 0});
+
+/* Clock resolution in usec. */
+SCLASS int _clock_res_usec SCLASS_PRESET(CLOCK_RES_USEC);
+
+/* Array of signal actions for this process: */
+SCLASS struct sigaction _thread_sigact[_SIG_MAXSIG];
+
+/*
+ * Lock for above count of dummy handlers and for the process signal
+ * mask and pending signal sets.
+ */
+SCLASS struct lock _thread_signal_lock;
+
+/* Pending signals and mask for this process: */
+SCLASS sigset_t _thr_proc_sigpending;
+SCLASS siginfo_t _thr_proc_siginfo[_SIG_MAXSIG];
+
+SCLASS pid_t _thr_pid SCLASS_PRESET(0);
+
+/* Garbage collector lock. */
+SCLASS struct lock _gc_lock;
+SCLASS int _gc_check SCLASS_PRESET(0);
+SCLASS int _gc_count SCLASS_PRESET(0);
+
+SCLASS struct lock _mutex_static_lock;
+SCLASS struct lock _rwlock_static_lock;
+SCLASS struct lock _keytable_lock;
+SCLASS struct lock _thread_list_lock;
+SCLASS int _thr_guard_default;
+SCLASS int _thr_stack_default;
+SCLASS int _thr_stack_initial;
+SCLASS int _thr_page_size;
+SCLASS pthread_t _thr_sig_daemon;
+SCLASS int _thr_debug_flags SCLASS_PRESET(0);
+
+/* Undefine the storage class and preset specifiers: */
+#undef SCLASS
+#undef SCLASS_PRESET
+
+
+/*
+ * Function prototype definitions.
+ */
+__BEGIN_DECLS
+int _cond_reinit(pthread_cond_t *);
+struct kse *_kse_alloc(struct pthread *, int sys_scope);
+kse_critical_t _kse_critical_enter(void);
+void _kse_critical_leave(kse_critical_t);
+int _kse_in_critical(void);
+void _kse_free(struct pthread *, struct kse *);
+void _kse_init(void);
+struct kse_group *_kseg_alloc(struct pthread *);
+void _kse_lock_wait(struct lock *, struct lockuser *lu);
+void _kse_lock_wakeup(struct lock *, struct lockuser *lu);
+void _kse_single_thread(struct pthread *);
+int _kse_setthreaded(int);
+void _kseg_free(struct kse_group *);
+int _mutex_cv_lock(pthread_mutex_t *);
+int _mutex_cv_unlock(pthread_mutex_t *);
+void _mutex_notify_priochange(struct pthread *, struct pthread *, int);
+int _mutex_reinit(struct pthread_mutex *);
+void _mutex_unlock_private(struct pthread *);
+void _libpthread_init(struct pthread *);
+int _pq_alloc(struct pq_queue *, int, int);
+void _pq_free(struct pq_queue *);
+int _pq_init(struct pq_queue *);
+void _pq_remove(struct pq_queue *pq, struct pthread *);
+void _pq_insert_head(struct pq_queue *pq, struct pthread *);
+void _pq_insert_tail(struct pq_queue *pq, struct pthread *);
+struct pthread *_pq_first(struct pq_queue *pq);
+struct pthread *_pq_first_debug(struct pq_queue *pq);
+void *_pthread_getspecific(pthread_key_t);
+int _pthread_key_create(pthread_key_t *, void (*) (void *));
+int _pthread_key_delete(pthread_key_t);
+int _pthread_mutex_destroy(pthread_mutex_t *);
+int _pthread_mutex_init(pthread_mutex_t *, const pthread_mutexattr_t *);
+int _pthread_mutex_lock(pthread_mutex_t *);
+int _pthread_mutex_trylock(pthread_mutex_t *);
+int _pthread_mutex_unlock(pthread_mutex_t *);
+int _pthread_mutexattr_init(pthread_mutexattr_t *);
+int _pthread_mutexattr_destroy(pthread_mutexattr_t *);
+int _pthread_mutexattr_settype(pthread_mutexattr_t *, int);
+int _pthread_once(pthread_once_t *, void (*) (void));
+int _pthread_rwlock_init(pthread_rwlock_t *, const pthread_rwlockattr_t *);
+int _pthread_rwlock_destroy (pthread_rwlock_t *);
+struct pthread *_pthread_self(void);
+int _pthread_setspecific(pthread_key_t, const void *);
+void _pthread_yield(void);
+void _pthread_cleanup_push(void (*routine) (void *), void *routine_arg);
+void _pthread_cleanup_pop(int execute);
+struct pthread *_thr_alloc(struct pthread *);
+void _thr_exit(char *, int, char *);
+void _thr_exit_cleanup(void);
+void _thr_lock_wait(struct lock *lock, struct lockuser *lu);
+void _thr_lock_wakeup(struct lock *lock, struct lockuser *lu);
+void _thr_mutex_reinit(pthread_mutex_t *);
+int _thr_ref_add(struct pthread *, struct pthread *, int);
+void _thr_ref_delete(struct pthread *, struct pthread *);
+void _thr_rtld_init(void);
+void _thr_rtld_fini(void);
+int _thr_schedule_add(struct pthread *, struct pthread *);
+void _thr_schedule_remove(struct pthread *, struct pthread *);
+void _thr_setrunnable(struct pthread *curthread, struct pthread *thread);
+struct kse_mailbox *_thr_setrunnable_unlocked(struct pthread *thread);
+struct kse_mailbox *_thr_sig_add(struct pthread *, int, siginfo_t *);
+void _thr_sig_dispatch(struct kse *, int, siginfo_t *);
+int _thr_stack_alloc(struct pthread_attr *);
+void _thr_stack_free(struct pthread_attr *);
+void _thr_exit_cleanup(void);
+void _thr_free(struct pthread *, struct pthread *);
+void _thr_gc(struct pthread *);
+void _thr_panic_exit(char *, int, char *);
+void _thread_cleanupspecific(void);
+void _thread_dump_info(void);
+void _thread_printf(int, const char *, ...);
+void _thr_sched_switch(struct pthread *);
+void _thr_sched_switch_unlocked(struct pthread *);
+void _thr_set_timeout(const struct timespec *);
+void _thr_seterrno(struct pthread *, int);
+void _thr_sig_handler(int, siginfo_t *, ucontext_t *);
+void _thr_sig_check_pending(struct pthread *);
+void _thr_sig_rundown(struct pthread *, ucontext_t *);
+void _thr_sig_send(struct pthread *pthread, int sig);
+void _thr_sigframe_restore(struct pthread *thread, struct pthread_sigframe *psf);
+void _thr_spinlock_init(void);
+void _thr_cancel_enter(struct pthread *);
+void _thr_cancel_leave(struct pthread *, int);
+int _thr_setconcurrency(int new_level);
+int _thr_setmaxconcurrency(void);
+void _thr_critical_enter(struct pthread *);
+void _thr_critical_leave(struct pthread *);
+int _thr_start_sig_daemon(void);
+int _thr_getprocsig(int sig, siginfo_t *siginfo);
+int _thr_getprocsig_unlocked(int sig, siginfo_t *siginfo);
+void _thr_signal_init(void);
+void _thr_signal_deinit(void);
+void _thr_hash_add(struct pthread *);
+void _thr_hash_remove(struct pthread *);
+struct pthread *_thr_hash_find(struct pthread *);
+void _thr_finish_cancellation(void *arg);
+int _thr_sigonstack(void *sp);
+void _thr_debug_check_yield(struct pthread *);
+
+/*
+ * Aliases for _pthread functions. Should be called instead of
+ * originals if PLT replocation is unwanted at runtme.
+ */
+int _thr_cond_broadcast(pthread_cond_t *);
+int _thr_cond_signal(pthread_cond_t *);
+int _thr_cond_wait(pthread_cond_t *, pthread_mutex_t *);
+int _thr_mutex_lock(pthread_mutex_t *);
+int _thr_mutex_unlock(pthread_mutex_t *);
+int _thr_rwlock_rdlock (pthread_rwlock_t *);
+int _thr_rwlock_wrlock (pthread_rwlock_t *);
+int _thr_rwlock_unlock (pthread_rwlock_t *);
+
+/* #include <sys/aio.h> */
+#ifdef _SYS_AIO_H_
+int __sys_aio_suspend(const struct aiocb * const[], int, const struct timespec *);
+#endif
+
+/* #include <fcntl.h> */
+#ifdef _SYS_FCNTL_H_
+int __sys_fcntl(int, int, ...);
+int __sys_open(const char *, int, ...);
+#endif
+
+/* #include <sys/ioctl.h> */
+#ifdef _SYS_IOCTL_H_
+int __sys_ioctl(int, unsigned long, ...);
+#endif
+
+/* #inclde <sched.h> */
+#ifdef _SCHED_H_
+int __sys_sched_yield(void);
+#endif
+
+/* #include <signal.h> */
+#ifdef _SIGNAL_H_
+int __sys_kill(pid_t, int);
+int __sys_sigaction(int, const struct sigaction *, struct sigaction *);
+int __sys_sigpending(sigset_t *);
+int __sys_sigprocmask(int, const sigset_t *, sigset_t *);
+int __sys_sigsuspend(const sigset_t *);
+int __sys_sigreturn(ucontext_t *);
+int __sys_sigaltstack(const struct sigaltstack *, struct sigaltstack *);
+#endif
+
+/* #include <sys/socket.h> */
+#ifdef _SYS_SOCKET_H_
+int __sys_accept(int, struct sockaddr *, socklen_t *);
+int __sys_connect(int, const struct sockaddr *, socklen_t);
+int __sys_sendfile(int, int, off_t, size_t, struct sf_hdtr *,
+ off_t *, int);
+#endif
+
+/* #include <sys/uio.h> */
+#ifdef _SYS_UIO_H_
+ssize_t __sys_readv(int, const struct iovec *, int);
+ssize_t __sys_writev(int, const struct iovec *, int);
+#endif
+
+/* #include <time.h> */
+#ifdef _TIME_H_
+int __sys_nanosleep(const struct timespec *, struct timespec *);
+#endif
+
+/* #include <unistd.h> */
+#ifdef _UNISTD_H_
+int __sys_close(int);
+int __sys_execve(const char *, char * const *, char * const *);
+int __sys_fork(void);
+int __sys_fsync(int);
+pid_t __sys_getpid(void);
+int __sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
+ssize_t __sys_read(int, void *, size_t);
+ssize_t __sys_write(int, const void *, size_t);
+void __sys_exit(int);
+int __sys_sigwait(const sigset_t *, int *);
+int __sys_sigtimedwait(sigset_t *, siginfo_t *, struct timespec *);
+#endif
+
+/* #include <poll.h> */
+#ifdef _SYS_POLL_H_
+int __sys_poll(struct pollfd *, unsigned, int);
+#endif
+
+/* #include <sys/mman.h> */
+#ifdef _SYS_MMAN_H_
+int __sys_msync(void *, size_t, int);
+#endif
+
+#endif /* !_THR_PRIVATE_H */
diff --git a/lib/libpthread/thread/thr_pselect.c b/lib/libpthread/thread/thr_pselect.c
new file mode 100644
index 0000000..a0e9410
--- /dev/null
+++ b/lib/libpthread/thread/thr_pselect.c
@@ -0,0 +1,60 @@
+/*-
+ * Copyright (c) 2002 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. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 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/select.h>
+#include <sys/time.h>
+
+#include <errno.h>
+#include <signal.h>
+#include <pthread.h>
+
+#include "thr_private.h"
+
+extern int __pselect(int count, fd_set *rfds, fd_set *wfds, fd_set *efds,
+ const struct timespec *timo, const sigset_t *mask);
+
+LT10_COMPAT_PRIVATE(_pselect);
+LT10_COMPAT_DEFAULT(pselect);
+
+__weak_reference(_pselect, pselect);
+
+int
+_pselect(int count, fd_set *rfds, fd_set *wfds, fd_set *efds,
+ const struct timespec *timo, const sigset_t *mask)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ _thr_cancel_enter(curthread);
+ ret = __pselect(count, rfds, wfds, efds, timo, mask);
+ _thr_cancel_leave(curthread, 1);
+
+ return (ret);
+}
diff --git a/lib/libpthread/thread/thr_pspinlock.c b/lib/libpthread/thread/thr_pspinlock.c
new file mode 100644
index 0000000..5836fde
--- /dev/null
+++ b/lib/libpthread/thread/thr_pspinlock.c
@@ -0,0 +1,174 @@
+/*-
+ * Copyright (c) 2003 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <errno.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "atomic_ops.h"
+#include "thr_private.h"
+
+#define SPIN_COUNT 10000
+
+LT10_COMPAT_PRIVATE(_pthread_spin_init);
+LT10_COMPAT_DEFAULT(pthread_spin_init);
+LT10_COMPAT_PRIVATE(_pthread_spin_destroy);
+LT10_COMPAT_DEFAULT(pthread_spin_destroy);
+LT10_COMPAT_PRIVATE(_pthread_spin_trylock);
+LT10_COMPAT_DEFAULT(pthread_spin_trylock);
+LT10_COMPAT_PRIVATE(_pthread_spin_lock);
+LT10_COMPAT_DEFAULT(pthread_spin_lock);
+LT10_COMPAT_PRIVATE(_pthread_spin_unlock);
+LT10_COMPAT_DEFAULT(pthread_spin_unlock);
+
+__weak_reference(_pthread_spin_init, pthread_spin_init);
+__weak_reference(_pthread_spin_destroy, pthread_spin_destroy);
+__weak_reference(_pthread_spin_trylock, pthread_spin_trylock);
+__weak_reference(_pthread_spin_lock, pthread_spin_lock);
+__weak_reference(_pthread_spin_unlock, pthread_spin_unlock);
+
+int
+_pthread_spin_init(pthread_spinlock_t *lock, int pshared)
+{
+ struct pthread_spinlock *lck;
+ int ret;
+
+ if (lock == NULL || pshared != PTHREAD_PROCESS_PRIVATE)
+ ret = EINVAL;
+ else if ((lck = malloc(sizeof(struct pthread_spinlock))) == NULL)
+ ret = ENOMEM;
+ else {
+ lck->s_lock = 0;
+ lck->s_owner= NULL;
+ *lock = lck;
+ ret = 0;
+ }
+
+ return (ret);
+}
+
+int
+_pthread_spin_destroy(pthread_spinlock_t *lock)
+{
+ int ret;
+
+ if (lock == NULL || *lock == NULL)
+ ret = EINVAL;
+ else if ((*lock)->s_owner != NULL)
+ ret = EBUSY;
+ else {
+ free(*lock);
+ *lock = NULL;
+ ret = 0;
+ }
+
+ return (ret);
+}
+
+int
+_pthread_spin_trylock(pthread_spinlock_t *lock)
+{
+ struct pthread_spinlock *lck;
+ struct pthread *self = _pthread_self();
+ int oldval, ret;
+
+ if (lock == NULL || (lck = *lock) == NULL)
+ ret = EINVAL;
+ else if (lck->s_owner == self)
+ ret = EDEADLK;
+ else if (lck->s_lock != 0)
+ ret = EBUSY;
+ else {
+ atomic_swap_int((int *)&(lck)->s_lock, 1, &oldval);
+ if (oldval)
+ ret = EBUSY;
+ else {
+ lck->s_owner = _pthread_self();
+ ret = 0;
+ }
+ }
+ return (ret);
+}
+
+int
+_pthread_spin_lock(pthread_spinlock_t *lock)
+{
+ struct pthread_spinlock *lck;
+ struct pthread *self = _pthread_self();
+ int count, oldval, ret;
+
+ if (lock == NULL || (lck = *lock) == NULL)
+ ret = EINVAL;
+ else if (lck->s_owner == self)
+ ret = EDEADLK;
+ else {
+ do {
+ count = SPIN_COUNT;
+ while (lck->s_lock) {
+#ifdef __i386__
+ /* tell cpu we are spinning */
+ __asm __volatile("pause");
+#endif
+ if (--count <= 0) {
+ count = SPIN_COUNT;
+ _pthread_yield();
+ }
+ }
+ atomic_swap_int((int *)&(lck)->s_lock, 1, &oldval);
+ } while (oldval);
+
+ lck->s_owner = self;
+ ret = 0;
+ }
+
+ return (ret);
+}
+
+int
+_pthread_spin_unlock(pthread_spinlock_t *lock)
+{
+ struct pthread_spinlock *lck;
+ int ret;
+
+ if (lock == NULL || (lck = *lock) == NULL)
+ ret = EINVAL;
+ else {
+ if (lck->s_owner != _pthread_self())
+ ret = EPERM;
+ else {
+ lck->s_owner = NULL;
+ atomic_swap_int((int *)&lck->s_lock, 0, &ret);
+ ret = 0;
+ }
+ }
+
+ return (ret);
+}
+
diff --git a/lib/libpthread/thread/thr_raise.c b/lib/libpthread/thread/thr_raise.c
new file mode 100644
index 0000000..ad4aa39
--- /dev/null
+++ b/lib/libpthread/thread/thr_raise.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2003 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 <pthread.h>
+#include <errno.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_raise);
+LT10_COMPAT_DEFAULT(raise);
+
+__weak_reference(_raise, raise);
+
+int
+_raise(int sig)
+{
+ int ret;
+
+ if (!_kse_isthreaded())
+ ret = kill(getpid(), sig);
+ else {
+ ret = pthread_kill(pthread_self(), sig);
+ if (ret != 0) {
+ errno = ret;
+ ret = -1;
+ }
+ }
+ return (ret);
+}
diff --git a/lib/libpthread/thread/thr_read.c b/lib/libpthread/thread/thr_read.c
new file mode 100644
index 0000000..dc29d1b
--- /dev/null
+++ b/lib/libpthread/thread/thr_read.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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/fcntl.h>
+#include <sys/uio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__read);
+LT10_COMPAT_DEFAULT(read);
+
+__weak_reference(__read, read);
+
+ssize_t
+__read(int fd, void *buf, size_t nbytes)
+{
+ struct pthread *curthread = _get_curthread();
+ ssize_t ret;
+
+ _thr_cancel_enter(curthread);
+ ret = __sys_read(fd, buf, nbytes);
+ _thr_cancel_leave(curthread, 1);
+
+ return ret;
+}
diff --git a/lib/libpthread/thread/thr_readv.c b/lib/libpthread/thread/thr_readv.c
new file mode 100644
index 0000000..c2d9360
--- /dev/null
+++ b/lib/libpthread/thread/thr_readv.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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/fcntl.h>
+#include <sys/uio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__readv);
+LT10_COMPAT_DEFAULT(readv);
+
+__weak_reference(__readv, readv);
+
+ssize_t
+__readv(int fd, const struct iovec *iov, int iovcnt)
+{
+ struct pthread *curthread = _get_curthread();
+ ssize_t ret;
+
+ _thr_cancel_enter(curthread);
+ ret = __sys_readv(fd, iov, iovcnt);
+ _thr_cancel_leave(curthread, 1);
+
+ return ret;
+}
diff --git a/lib/libpthread/thread/thr_resume_np.c b/lib/libpthread/thread/thr_resume_np.c
new file mode 100644
index 0000000..70c5f17
--- /dev/null
+++ b/lib/libpthread/thread/thr_resume_np.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+static struct kse_mailbox *resume_common(struct pthread *);
+
+LT10_COMPAT_PRIVATE(_pthread_resume_np);
+LT10_COMPAT_DEFAULT(pthread_resume_np);
+LT10_COMPAT_PRIVATE(_pthread_resume_all_np);
+LT10_COMPAT_DEFAULT(pthread_resume_all_np);
+
+__weak_reference(_pthread_resume_np, pthread_resume_np);
+__weak_reference(_pthread_resume_all_np, pthread_resume_all_np);
+
+
+/* Resume a thread: */
+int
+_pthread_resume_np(pthread_t thread)
+{
+ struct pthread *curthread = _get_curthread();
+ struct kse_mailbox *kmbx;
+ int ret;
+
+ /* Add a reference to the thread: */
+ if ((ret = _thr_ref_add(curthread, thread, /*include dead*/0)) == 0) {
+ /* Lock the threads scheduling queue: */
+ THR_SCHED_LOCK(curthread, thread);
+ kmbx = resume_common(thread);
+ THR_SCHED_UNLOCK(curthread, thread);
+ _thr_ref_delete(curthread, thread);
+ if (kmbx != NULL)
+ kse_wakeup(kmbx);
+ }
+ return (ret);
+}
+
+void
+_pthread_resume_all_np(void)
+{
+ struct pthread *curthread = _get_curthread();
+ struct pthread *thread;
+ struct kse_mailbox *kmbx;
+ kse_critical_t crit;
+
+ /* Take the thread list lock: */
+ crit = _kse_critical_enter();
+ KSE_LOCK_ACQUIRE(curthread->kse, &_thread_list_lock);
+
+ TAILQ_FOREACH(thread, &_thread_list, tle) {
+ if (thread != curthread) {
+ THR_SCHED_LOCK(curthread, thread);
+ kmbx = resume_common(thread);
+ THR_SCHED_UNLOCK(curthread, thread);
+ if (kmbx != NULL)
+ kse_wakeup(kmbx);
+ }
+ }
+
+ /* Release the thread list lock: */
+ KSE_LOCK_RELEASE(curthread->kse, &_thread_list_lock);
+ _kse_critical_leave(crit);
+}
+
+static struct kse_mailbox *
+resume_common(struct pthread *thread)
+{
+ /* Clear the suspend flag: */
+ thread->flags &= ~THR_FLAGS_SUSPENDED;
+
+ /*
+ * If the thread's state is suspended, that means it is
+ * now runnable but not in any scheduling queue. Set the
+ * state to running and insert it into the run queue.
+ */
+ if (thread->state == PS_SUSPENDED)
+ return (_thr_setrunnable_unlocked(thread));
+ else
+ return (NULL);
+}
diff --git a/lib/libpthread/thread/thr_rtld.c b/lib/libpthread/thread/thr_rtld.c
new file mode 100644
index 0000000..e813073
--- /dev/null
+++ b/lib/libpthread/thread/thr_rtld.c
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 2001 Alexander Kabaev
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 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$
+ */
+#include <sys/cdefs.h>
+#include <stdlib.h>
+
+#include "rtld_lock.h"
+#include "thr_private.h"
+
+static int _thr_rtld_clr_flag(int);
+static void *_thr_rtld_lock_create(void);
+static void _thr_rtld_lock_destroy(void *);
+static void _thr_rtld_lock_release(void *);
+static void _thr_rtld_rlock_acquire(void *);
+static int _thr_rtld_set_flag(int);
+static void _thr_rtld_wlock_acquire(void *);
+
+#ifdef NOTYET
+static void *
+_thr_rtld_lock_create(void)
+{
+ pthread_rwlock_t prwlock;
+ if (_pthread_rwlock_init(&prwlock, NULL))
+ return (NULL);
+ return (prwlock);
+}
+
+static void
+_thr_rtld_lock_destroy(void *lock)
+{
+ pthread_rwlock_t prwlock;
+
+ prwlock = (pthread_rwlock_t)lock;
+ if (prwlock != NULL)
+ _pthread_rwlock_destroy(&prwlock);
+}
+
+static void
+_thr_rtld_rlock_acquire(void *lock)
+{
+ pthread_rwlock_t prwlock;
+
+ prwlock = (pthread_rwlock_t)lock;
+ _thr_rwlock_rdlock(&prwlock);
+}
+
+static void
+_thr_rtld_wlock_acquire(void *lock)
+{
+ pthread_rwlock_t prwlock;
+
+ prwlock = (pthread_rwlock_t)lock;
+ _thr_rwlock_wrlock(&prwlock);
+}
+
+static void
+_thr_rtld_lock_release(void *lock)
+{
+ pthread_rwlock_t prwlock;
+
+ prwlock = (pthread_rwlock_t)lock;
+ _thr_rwlock_unlock(&prwlock);
+}
+
+
+static int
+_thr_rtld_set_flag(int mask)
+{
+ struct pthread *curthread;
+ int bits;
+
+ curthread = _get_curthread();
+ if (curthread != NULL) {
+ bits = curthread->rtld_bits;
+ curthread->rtld_bits |= mask;
+ } else {
+ bits = 0;
+ PANIC("No current thread in rtld call");
+ }
+
+ return (bits);
+}
+
+static int
+_thr_rtld_clr_flag(int mask)
+{
+ struct pthread *curthread;
+ int bits;
+
+ curthread = _get_curthread();
+ if (curthread != NULL) {
+ bits = curthread->rtld_bits;
+ curthread->rtld_bits &= ~mask;
+ } else {
+ bits = 0;
+ PANIC("No current thread in rtld call");
+ }
+ return (bits);
+}
+
+void
+_thr_rtld_init(void)
+{
+ struct RtldLockInfo li;
+
+ li.lock_create = _thr_rtld_lock_create;
+ li.lock_destroy = _thr_rtld_lock_destroy;
+ li.rlock_acquire = _thr_rtld_rlock_acquire;
+ li.wlock_acquire = _thr_rtld_wlock_acquire;
+ li.lock_release = _thr_rtld_lock_release;
+ li.thread_set_flag = _thr_rtld_set_flag;
+ li.thread_clr_flag = _thr_rtld_clr_flag;
+ li.at_fork = NULL;
+ _rtld_thread_init(&li);
+}
+
+void
+_thr_rtld_fini(void)
+{
+ _rtld_thread_init(NULL);
+}
+#endif
+
+struct rtld_kse_lock {
+ struct lock lck;
+ struct kse *owner;
+ kse_critical_t crit;
+ int count;
+ int write;
+};
+
+static void *
+_thr_rtld_lock_create(void)
+{
+ struct rtld_kse_lock *l;
+
+ if ((l = malloc(sizeof(struct rtld_kse_lock))) != NULL) {
+ _lock_init(&l->lck, LCK_ADAPTIVE, _kse_lock_wait,
+ _kse_lock_wakeup);
+ l->owner = NULL;
+ l->count = 0;
+ l->write = 0;
+ }
+ return (l);
+}
+
+static void
+_thr_rtld_lock_destroy(void *lock)
+{
+ /* XXX We really can not free memory after a fork() */
+#if 0
+ struct rtld_kse_lock *l;
+
+ l = (struct rtld_kse_lock *)lock;
+ _lock_destroy(&l->lck);
+ free(l);
+#endif
+ return;
+}
+
+static void
+_thr_rtld_rlock_acquire(void *lock)
+{
+ struct rtld_kse_lock *l;
+ kse_critical_t crit;
+ struct kse *curkse;
+
+ l = (struct rtld_kse_lock *)lock;
+ crit = _kse_critical_enter();
+ curkse = _get_curkse();
+ if (l->owner == curkse) {
+ l->count++;
+ _kse_critical_leave(crit); /* probably not necessary */
+ } else {
+ KSE_LOCK_ACQUIRE(curkse, &l->lck);
+ l->crit = crit;
+ l->owner = curkse;
+ l->count = 1;
+ l->write = 0;
+ }
+}
+
+static void
+_thr_rtld_wlock_acquire(void *lock)
+{
+ struct rtld_kse_lock *l;
+ kse_critical_t crit;
+ struct kse *curkse;
+
+ l = (struct rtld_kse_lock *)lock;
+ crit = _kse_critical_enter();
+ curkse = _get_curkse();
+ if (l->owner == curkse) {
+ _kse_critical_leave(crit);
+ PANIC("Recursive write lock attempt on rtld lock");
+ } else {
+ KSE_LOCK_ACQUIRE(curkse, &l->lck);
+ l->crit = crit;
+ l->owner = curkse;
+ l->count = 1;
+ l->write = 1;
+ }
+}
+
+static void
+_thr_rtld_lock_release(void *lock)
+{
+ struct rtld_kse_lock *l;
+ kse_critical_t crit;
+ struct kse *curkse;
+
+ l = (struct rtld_kse_lock *)lock;
+ crit = _kse_critical_enter();
+ curkse = _get_curkse();
+ if (l->owner != curkse) {
+ /*
+ * We might want to forcibly unlock the rtld lock
+ * and/or disable threaded mode so there is better
+ * chance that the panic will work. Otherwise,
+ * we could end up trying to take the rtld lock
+ * again.
+ */
+ _kse_critical_leave(crit);
+ PANIC("Attempt to unlock rtld lock when not owner.");
+ } else {
+ l->count--;
+ if (l->count == 0) {
+ /*
+ * If there ever is a count associated with
+ * _kse_critical_leave(), we'll need to add
+ * another call to it here with the crit
+ * value from above.
+ */
+ crit = l->crit;
+ l->owner = NULL;
+ l->write = 0;
+ KSE_LOCK_RELEASE(curkse, &l->lck);
+ }
+ _kse_critical_leave(crit);
+ }
+}
+
+
+static int
+_thr_rtld_set_flag(int mask)
+{
+ return (0);
+}
+
+static int
+_thr_rtld_clr_flag(int mask)
+{
+ return (0);
+}
+
+void
+_thr_rtld_init(void)
+{
+ struct RtldLockInfo li;
+
+ li.lock_create = _thr_rtld_lock_create;
+ li.lock_destroy = _thr_rtld_lock_destroy;
+ li.rlock_acquire = _thr_rtld_rlock_acquire;
+ li.wlock_acquire = _thr_rtld_wlock_acquire;
+ li.lock_release = _thr_rtld_lock_release;
+ li.thread_set_flag = _thr_rtld_set_flag;
+ li.thread_clr_flag = _thr_rtld_clr_flag;
+ li.at_fork = NULL;
+ _rtld_thread_init(&li);
+}
+
+void
+_thr_rtld_fini(void)
+{
+ _rtld_thread_init(NULL);
+}
diff --git a/lib/libpthread/thread/thr_rwlock.c b/lib/libpthread/thread/thr_rwlock.c
new file mode 100644
index 0000000..a0b36de
--- /dev/null
+++ b/lib/libpthread/thread/thr_rwlock.c
@@ -0,0 +1,438 @@
+/*-
+ * Copyright (c) 1998 Alex Nash
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#include "namespace.h"
+#include <pthread.h>
+#include "un-namespace.h"
+#include "thr_private.h"
+
+/* maximum number of times a read lock may be obtained */
+#define MAX_READ_LOCKS (INT_MAX - 1)
+
+LT10_COMPAT_PRIVATE(_pthread_rwlock_destroy);
+LT10_COMPAT_DEFAULT(pthread_rwlock_destroy);
+LT10_COMPAT_PRIVATE(_pthread_rwlock_init);
+LT10_COMPAT_DEFAULT(pthread_rwlock_init);
+LT10_COMPAT_PRIVATE(_pthread_rwlock_rdlock);
+LT10_COMPAT_DEFAULT(pthread_rwlock_rdlock);
+LT10_COMPAT_PRIVATE(_pthread_rwlock_timedrdlock);
+LT10_COMPAT_DEFAULT(pthread_rwlock_timedrdlock);
+LT10_COMPAT_PRIVATE(_pthread_rwlock_tryrdlock);
+LT10_COMPAT_DEFAULT(pthread_rwlock_tryrdlock);
+LT10_COMPAT_PRIVATE(_pthread_rwlock_trywrlock);
+LT10_COMPAT_DEFAULT(pthread_rwlock_trywrlock);
+LT10_COMPAT_PRIVATE(_pthread_rwlock_unlock);
+LT10_COMPAT_DEFAULT(pthread_rwlock_unlock);
+LT10_COMPAT_PRIVATE(_pthread_rwlock_wrlock);
+LT10_COMPAT_DEFAULT(pthread_rwlock_wrlock);
+LT10_COMPAT_PRIVATE(_pthread_rwlock_timedwrlock);
+LT10_COMPAT_DEFAULT(pthread_rwlock_timedwrlock);
+
+__weak_reference(_pthread_rwlock_destroy, pthread_rwlock_destroy);
+__weak_reference(_pthread_rwlock_init, pthread_rwlock_init);
+__weak_reference(_pthread_rwlock_rdlock, pthread_rwlock_rdlock);
+__weak_reference(_pthread_rwlock_timedrdlock, pthread_rwlock_timedrdlock);
+__weak_reference(_pthread_rwlock_tryrdlock, pthread_rwlock_tryrdlock);
+__weak_reference(_pthread_rwlock_trywrlock, pthread_rwlock_trywrlock);
+__weak_reference(_pthread_rwlock_unlock, pthread_rwlock_unlock);
+__weak_reference(_pthread_rwlock_wrlock, pthread_rwlock_wrlock);
+__weak_reference(_pthread_rwlock_timedwrlock, pthread_rwlock_timedwrlock);
+
+/*
+ * Prototypes
+ */
+static int init_static(pthread_rwlock_t *rwlock);
+
+
+static int
+init_static(pthread_rwlock_t *rwlock)
+{
+ struct pthread *thread = _get_curthread();
+ int ret;
+
+ THR_LOCK_ACQUIRE(thread, &_rwlock_static_lock);
+
+ if (*rwlock == NULL)
+ ret = _pthread_rwlock_init(rwlock, NULL);
+ else
+ ret = 0;
+
+ THR_LOCK_RELEASE(thread, &_rwlock_static_lock);
+ return (ret);
+}
+
+int
+_pthread_rwlock_destroy (pthread_rwlock_t *rwlock)
+{
+ int ret;
+
+ if (rwlock == NULL)
+ ret = EINVAL;
+ else {
+ pthread_rwlock_t prwlock;
+
+ prwlock = *rwlock;
+
+ _pthread_mutex_destroy(&prwlock->lock);
+ _pthread_cond_destroy(&prwlock->read_signal);
+ _pthread_cond_destroy(&prwlock->write_signal);
+ free(prwlock);
+
+ *rwlock = NULL;
+
+ ret = 0;
+ }
+ return (ret);
+}
+
+int
+_pthread_rwlock_init (pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr)
+{
+ pthread_rwlock_t prwlock;
+ int ret;
+
+ /* allocate rwlock object */
+ prwlock = (pthread_rwlock_t)malloc(sizeof(struct pthread_rwlock));
+
+ if (prwlock == NULL)
+ return (ENOMEM);
+
+ /* initialize the lock */
+ if ((ret = _pthread_mutex_init(&prwlock->lock, NULL)) != 0)
+ free(prwlock);
+ else {
+ /* initialize the read condition signal */
+ ret = _pthread_cond_init(&prwlock->read_signal, NULL);
+
+ if (ret != 0) {
+ _pthread_mutex_destroy(&prwlock->lock);
+ free(prwlock);
+ } else {
+ /* initialize the write condition signal */
+ ret = _pthread_cond_init(&prwlock->write_signal, NULL);
+
+ if (ret != 0) {
+ _pthread_cond_destroy(&prwlock->read_signal);
+ _pthread_mutex_destroy(&prwlock->lock);
+ free(prwlock);
+ } else {
+ /* success */
+ prwlock->state = 0;
+ prwlock->blocked_writers = 0;
+
+ *rwlock = prwlock;
+ }
+ }
+ }
+
+ return (ret);
+}
+
+static int
+rwlock_rdlock_common (pthread_rwlock_t *rwlock, const struct timespec *abstime)
+{
+ pthread_rwlock_t prwlock;
+ struct pthread *curthread;
+ int ret;
+
+ if (rwlock == NULL)
+ return (EINVAL);
+
+ prwlock = *rwlock;
+
+ /* check for static initialization */
+ if (prwlock == NULL) {
+ if ((ret = init_static(rwlock)) != 0)
+ return (ret);
+
+ prwlock = *rwlock;
+ }
+
+ /* grab the monitor lock */
+ if ((ret = _thr_mutex_lock(&prwlock->lock)) != 0)
+ return (ret);
+
+ /* check lock count */
+ if (prwlock->state == MAX_READ_LOCKS) {
+ _thr_mutex_unlock(&prwlock->lock);
+ return (EAGAIN);
+ }
+
+ curthread = _get_curthread();
+ if ((curthread->rdlock_count > 0) && (prwlock->state > 0)) {
+ /*
+ * To avoid having to track all the rdlocks held by
+ * a thread or all of the threads that hold a rdlock,
+ * we keep a simple count of all the rdlocks held by
+ * a thread. If a thread holds any rdlocks it is
+ * possible that it is attempting to take a recursive
+ * rdlock. If there are blocked writers and precedence
+ * is given to them, then that would result in the thread
+ * deadlocking. So allowing a thread to take the rdlock
+ * when it already has one or more rdlocks avoids the
+ * deadlock. I hope the reader can follow that logic ;-)
+ */
+ ; /* nothing needed */
+ } else {
+ /* give writers priority over readers */
+ while (prwlock->blocked_writers || prwlock->state < 0) {
+ if (abstime)
+ ret = _pthread_cond_timedwait
+ (&prwlock->read_signal,
+ &prwlock->lock, abstime);
+ else
+ ret = _thr_cond_wait(&prwlock->read_signal,
+ &prwlock->lock);
+ if (ret != 0) {
+ /* can't do a whole lot if this fails */
+ _thr_mutex_unlock(&prwlock->lock);
+ return (ret);
+ }
+ }
+ }
+
+ curthread->rdlock_count++;
+ prwlock->state++; /* indicate we are locked for reading */
+
+ /*
+ * Something is really wrong if this call fails. Returning
+ * error won't do because we've already obtained the read
+ * lock. Decrementing 'state' is no good because we probably
+ * don't have the monitor lock.
+ */
+ _thr_mutex_unlock(&prwlock->lock);
+
+ return (ret);
+}
+
+int
+_pthread_rwlock_rdlock (pthread_rwlock_t *rwlock)
+{
+ return (rwlock_rdlock_common(rwlock, NULL));
+}
+
+__strong_reference(_pthread_rwlock_rdlock, _thr_rwlock_rdlock);
+
+int
+_pthread_rwlock_timedrdlock (pthread_rwlock_t *rwlock,
+ const struct timespec *abstime)
+{
+ return (rwlock_rdlock_common(rwlock, abstime));
+}
+
+int
+_pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock)
+{
+ struct pthread *curthread;
+ pthread_rwlock_t prwlock;
+ int ret;
+
+ if (rwlock == NULL)
+ return (EINVAL);
+
+ prwlock = *rwlock;
+
+ /* check for static initialization */
+ if (prwlock == NULL) {
+ if ((ret = init_static(rwlock)) != 0)
+ return (ret);
+
+ prwlock = *rwlock;
+ }
+
+ /* grab the monitor lock */
+ if ((ret = _pthread_mutex_lock(&prwlock->lock)) != 0)
+ return (ret);
+
+ curthread = _get_curthread();
+ if (prwlock->state == MAX_READ_LOCKS)
+ ret = EAGAIN;
+ else if ((curthread->rdlock_count > 0) && (prwlock->state > 0)) {
+ /* see comment for pthread_rwlock_rdlock() */
+ curthread->rdlock_count++;
+ prwlock->state++;
+ }
+ /* give writers priority over readers */
+ else if (prwlock->blocked_writers || prwlock->state < 0)
+ ret = EBUSY;
+ else {
+ curthread->rdlock_count++;
+ prwlock->state++; /* indicate we are locked for reading */
+ }
+
+ /* see the comment on this in pthread_rwlock_rdlock */
+ _pthread_mutex_unlock(&prwlock->lock);
+
+ return (ret);
+}
+
+int
+_pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock)
+{
+ pthread_rwlock_t prwlock;
+ int ret;
+
+ if (rwlock == NULL)
+ return (EINVAL);
+
+ prwlock = *rwlock;
+
+ /* check for static initialization */
+ if (prwlock == NULL) {
+ if ((ret = init_static(rwlock)) != 0)
+ return (ret);
+
+ prwlock = *rwlock;
+ }
+
+ /* grab the monitor lock */
+ if ((ret = _pthread_mutex_lock(&prwlock->lock)) != 0)
+ return (ret);
+
+ if (prwlock->state != 0)
+ ret = EBUSY;
+ else
+ /* indicate we are locked for writing */
+ prwlock->state = -1;
+
+ /* see the comment on this in pthread_rwlock_rdlock */
+ _pthread_mutex_unlock(&prwlock->lock);
+
+ return (ret);
+}
+
+int
+_pthread_rwlock_unlock (pthread_rwlock_t *rwlock)
+{
+ struct pthread *curthread;
+ pthread_rwlock_t prwlock;
+ int ret;
+
+ if (rwlock == NULL)
+ return (EINVAL);
+
+ prwlock = *rwlock;
+
+ if (prwlock == NULL)
+ return (EINVAL);
+
+ /* grab the monitor lock */
+ if ((ret = _thr_mutex_lock(&prwlock->lock)) != 0)
+ return (ret);
+
+ curthread = _get_curthread();
+ if (prwlock->state > 0) {
+ curthread->rdlock_count--;
+ prwlock->state--;
+ if (prwlock->state == 0 && prwlock->blocked_writers)
+ ret = _thr_cond_signal(&prwlock->write_signal);
+ } else if (prwlock->state < 0) {
+ prwlock->state = 0;
+
+ if (prwlock->blocked_writers)
+ ret = _thr_cond_signal(&prwlock->write_signal);
+ else
+ ret = _thr_cond_broadcast(&prwlock->read_signal);
+ } else
+ ret = EINVAL;
+
+ /* see the comment on this in pthread_rwlock_rdlock */
+ _thr_mutex_unlock(&prwlock->lock);
+
+ return (ret);
+}
+
+__strong_reference(_pthread_rwlock_unlock, _thr_rwlock_unlock);
+
+static int
+rwlock_wrlock_common (pthread_rwlock_t *rwlock, const struct timespec *abstime)
+{
+ pthread_rwlock_t prwlock;
+ int ret;
+
+ if (rwlock == NULL)
+ return (EINVAL);
+
+ prwlock = *rwlock;
+
+ /* check for static initialization */
+ if (prwlock == NULL) {
+ if ((ret = init_static(rwlock)) != 0)
+ return (ret);
+
+ prwlock = *rwlock;
+ }
+
+ /* grab the monitor lock */
+ if ((ret = _thr_mutex_lock(&prwlock->lock)) != 0)
+ return (ret);
+
+ while (prwlock->state != 0) {
+ prwlock->blocked_writers++;
+
+ if (abstime != NULL)
+ ret = _pthread_cond_timedwait(&prwlock->write_signal,
+ &prwlock->lock, abstime);
+ else
+ ret = _thr_cond_wait(&prwlock->write_signal,
+ &prwlock->lock);
+ if (ret != 0) {
+ prwlock->blocked_writers--;
+ _thr_mutex_unlock(&prwlock->lock);
+ return (ret);
+ }
+
+ prwlock->blocked_writers--;
+ }
+
+ /* indicate we are locked for writing */
+ prwlock->state = -1;
+
+ /* see the comment on this in pthread_rwlock_rdlock */
+ _thr_mutex_unlock(&prwlock->lock);
+
+ return (ret);
+}
+
+int
+_pthread_rwlock_wrlock (pthread_rwlock_t *rwlock)
+{
+ return (rwlock_wrlock_common (rwlock, NULL));
+}
+__strong_reference(_pthread_rwlock_wrlock, _thr_rwlock_wrlock);
+
+int
+_pthread_rwlock_timedwrlock (pthread_rwlock_t *rwlock,
+ const struct timespec *abstime)
+{
+ return (rwlock_wrlock_common (rwlock, abstime));
+}
diff --git a/lib/libpthread/thread/thr_rwlockattr.c b/lib/libpthread/thread/thr_rwlockattr.c
new file mode 100644
index 0000000..174b28f
--- /dev/null
+++ b/lib/libpthread/thread/thr_rwlockattr.c
@@ -0,0 +1,107 @@
+/*-
+ * Copyright (c) 1998 Alex Nash
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_rwlockattr_destroy);
+LT10_COMPAT_DEFAULT(pthread_rwlockattr_destroy);
+LT10_COMPAT_PRIVATE(_pthread_rwlockattr_getpshared);
+LT10_COMPAT_DEFAULT(pthread_rwlockattr_getpshared);
+LT10_COMPAT_PRIVATE(_pthread_rwlockattr_init);
+LT10_COMPAT_DEFAULT(pthread_rwlockattr_init);
+LT10_COMPAT_PRIVATE(_pthread_rwlockattr_setpshared);
+LT10_COMPAT_DEFAULT(pthread_rwlockattr_setpshared);
+
+__weak_reference(_pthread_rwlockattr_destroy, pthread_rwlockattr_destroy);
+__weak_reference(_pthread_rwlockattr_getpshared, pthread_rwlockattr_getpshared);
+__weak_reference(_pthread_rwlockattr_init, pthread_rwlockattr_init);
+__weak_reference(_pthread_rwlockattr_setpshared, pthread_rwlockattr_setpshared);
+
+int
+_pthread_rwlockattr_destroy(pthread_rwlockattr_t *rwlockattr)
+{
+ pthread_rwlockattr_t prwlockattr;
+
+ if (rwlockattr == NULL)
+ return(EINVAL);
+
+ prwlockattr = *rwlockattr;
+
+ if (prwlockattr == NULL)
+ return(EINVAL);
+
+ free(prwlockattr);
+
+ return(0);
+}
+
+int
+_pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *rwlockattr,
+ int *pshared)
+{
+ *pshared = (*rwlockattr)->pshared;
+
+ return(0);
+}
+
+int
+_pthread_rwlockattr_init(pthread_rwlockattr_t *rwlockattr)
+{
+ pthread_rwlockattr_t prwlockattr;
+
+ if (rwlockattr == NULL)
+ return(EINVAL);
+
+ prwlockattr = (pthread_rwlockattr_t)
+ malloc(sizeof(struct pthread_rwlockattr));
+
+ if (prwlockattr == NULL)
+ return(ENOMEM);
+
+ prwlockattr->pshared = PTHREAD_PROCESS_PRIVATE;
+ *rwlockattr = prwlockattr;
+
+ return(0);
+}
+
+int
+_pthread_rwlockattr_setpshared(pthread_rwlockattr_t *rwlockattr, int pshared)
+{
+ /* Only PTHREAD_PROCESS_PRIVATE is supported. */
+ if (pshared != PTHREAD_PROCESS_PRIVATE)
+ return(EINVAL);
+
+ (*rwlockattr)->pshared = pshared;
+
+ return(0);
+}
+
diff --git a/lib/libpthread/thread/thr_select.c b/lib/libpthread/thread/thr_select.c
new file mode 100644
index 0000000..97bcc37
--- /dev/null
+++ b/lib/libpthread/thread/thr_select.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <unistd.h>
+#include <errno.h>
+#include <poll.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/fcntl.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__select);
+LT10_COMPAT_DEFAULT(select);
+
+__weak_reference(__select, select);
+
+int
+__select(int numfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+ struct timeval *timeout)
+{
+ struct pthread *curthread = _get_curthread();
+ struct timespec ts;
+ int ret;
+
+ if (numfds == 0 && timeout != NULL) {
+ TIMEVAL_TO_TIMESPEC(timeout, &ts);
+ return nanosleep(&ts, NULL);
+ } else {
+ _thr_cancel_enter(curthread);
+ ret = __sys_select(numfds, readfds, writefds, exceptfds, timeout);
+ _thr_cancel_leave(curthread, 1);
+ }
+ return ret;
+}
diff --git a/lib/libpthread/thread/thr_self.c b/lib/libpthread/thread/thr_self.c
new file mode 100644
index 0000000..28ac613
--- /dev/null
+++ b/lib/libpthread/thread/thr_self.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_self);
+LT10_COMPAT_DEFAULT(pthread_self);
+
+__weak_reference(_pthread_self, pthread_self);
+
+pthread_t
+_pthread_self(void)
+{
+ if (_thr_initial == NULL)
+ _libpthread_init(NULL);
+
+ /* Return the running thread pointer: */
+ return (_get_curthread());
+}
diff --git a/lib/libpthread/thread/thr_sem.c b/lib/libpthread/thread/thr_sem.c
new file mode 100644
index 0000000..21746bbe
--- /dev/null
+++ b/lib/libpthread/thread/thr_sem.c
@@ -0,0 +1,267 @@
+/*
+ * 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$
+ */
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <stdlib.h>
+#include <time.h>
+#include <_semaphore.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_sem_init);
+LT10_COMPAT_DEFAULT(sem_init);
+LT10_COMPAT_PRIVATE(_sem_wait);
+LT10_COMPAT_DEFAULT(sem_wait);
+LT10_COMPAT_PRIVATE(_sem_timedwait);
+LT10_COMPAT_DEFAULT(sem_timedwait);
+LT10_COMPAT_PRIVATE(_sem_post);
+LT10_COMPAT_DEFAULT(sem_post);
+
+__weak_reference(_sem_init, sem_init);
+__weak_reference(_sem_wait, sem_wait);
+__weak_reference(_sem_timedwait, sem_timedwait);
+__weak_reference(_sem_post, sem_post);
+
+
+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
+decrease_nwaiters(void *arg)
+{
+ sem_t *sem = (sem_t *)arg;
+
+ (*sem)->nwaiters--;
+ /*
+ * this function is called from cancellation point,
+ * the mutex should already be hold.
+ */
+ _pthread_mutex_unlock(&(*sem)->lock);
+}
+
+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);
+ }
+
+ /*
+ * Initialize the semaphore.
+ */
+ if (_pthread_mutex_init(&sem->lock, NULL) != 0) {
+ free(sem);
+ errno = ENOSPC;
+ return (NULL);
+ }
+
+ if (_pthread_cond_init(&sem->gtzero, NULL) != 0) {
+ _pthread_mutex_destroy(&sem->lock);
+ free(sem);
+ 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
+_sem_init(sem_t *sem, int pshared, unsigned int value)
+{
+ semid_t semid;
+
+ 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
+_sem_wait(sem_t *sem)
+{
+ struct pthread *curthread;
+ int retval;
+
+ if (sem_check_validity(sem) != 0)
+ return (-1);
+
+ curthread = _get_curthread();
+ if ((*sem)->syssem != 0) {
+ _thr_cancel_enter(curthread);
+ retval = ksem_wait((*sem)->semid);
+ _thr_cancel_leave(curthread, retval != 0);
+ }
+ else {
+ _pthread_testcancel();
+ _pthread_mutex_lock(&(*sem)->lock);
+
+ while ((*sem)->count <= 0) {
+ (*sem)->nwaiters++;
+ THR_CLEANUP_PUSH(curthread, decrease_nwaiters, sem);
+ _pthread_cond_wait(&(*sem)->gtzero, &(*sem)->lock);
+ THR_CLEANUP_POP(curthread, 0);
+ (*sem)->nwaiters--;
+ }
+ (*sem)->count--;
+
+ _pthread_mutex_unlock(&(*sem)->lock);
+
+ retval = 0;
+ }
+ return (retval);
+}
+
+int
+_sem_timedwait(sem_t * __restrict sem,
+ const struct timespec * __restrict abs_timeout)
+{
+ struct pthread *curthread;
+ int retval;
+ int timeout_invalid;
+
+ if (sem_check_validity(sem) != 0)
+ return (-1);
+
+ if ((*sem)->syssem != 0) {
+ curthread = _get_curthread();
+ _thr_cancel_enter(curthread);
+ retval = ksem_timedwait((*sem)->semid, abs_timeout);
+ _thr_cancel_leave(curthread, retval != 0);
+ }
+ else {
+ /*
+ * The timeout argument is only supposed to
+ * be checked if the thread would have blocked.
+ * This is checked outside of the lock so a
+ * segfault on an invalid address doesn't end
+ * up leaving the mutex locked.
+ */
+ _pthread_testcancel();
+ timeout_invalid = (abs_timeout->tv_nsec >= 1000000000) ||
+ (abs_timeout->tv_nsec < 0);
+ _pthread_mutex_lock(&(*sem)->lock);
+
+ if ((*sem)->count <= 0) {
+ if (timeout_invalid) {
+ _pthread_mutex_unlock(&(*sem)->lock);
+ errno = EINVAL;
+ return (-1);
+ }
+ (*sem)->nwaiters++;
+ _pthread_cleanup_push(decrease_nwaiters, sem);
+ _pthread_cond_timedwait(&(*sem)->gtzero,
+ &(*sem)->lock, abs_timeout);
+ _pthread_cleanup_pop(0);
+ (*sem)->nwaiters--;
+ }
+ if ((*sem)->count == 0) {
+ errno = ETIMEDOUT;
+ retval = -1;
+ }
+ else {
+ (*sem)->count--;
+ retval = 0;
+ }
+
+ _pthread_mutex_unlock(&(*sem)->lock);
+ }
+
+ return (retval);
+}
+
+int
+_sem_post(sem_t *sem)
+{
+ struct pthread *curthread;
+ int retval;
+
+ if (sem_check_validity(sem) != 0)
+ return (-1);
+
+ if ((*sem)->syssem != 0)
+ retval = ksem_post((*sem)->semid);
+ else {
+ /*
+ * sem_post() is required to be safe to call from within
+ * signal handlers. Thus, we must enter a critical region.
+ */
+ curthread = _get_curthread();
+ _thr_critical_enter(curthread);
+ _pthread_mutex_lock(&(*sem)->lock);
+
+ (*sem)->count++;
+ if ((*sem)->nwaiters > 0)
+ _pthread_cond_signal(&(*sem)->gtzero);
+
+ _pthread_mutex_unlock(&(*sem)->lock);
+ _thr_critical_leave(curthread);
+ retval = 0;
+ }
+
+ return (retval);
+}
diff --git a/lib/libpthread/thread/thr_seterrno.c b/lib/libpthread/thread/thr_seterrno.c
new file mode 100644
index 0000000..245d43f
--- /dev/null
+++ b/lib/libpthread/thread/thr_seterrno.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 "thr_private.h"
+
+/*
+ * This function needs to reference the global error variable which is
+ * normally hidden from the user.
+ */
+#ifdef errno
+#undef errno;
+#endif
+extern int errno;
+
+void
+_thread_seterrno(pthread_t thread, int error)
+{
+ /* Check for the initial thread: */
+ if (thread == _thr_initial)
+ /* The initial thread always uses the global error variable: */
+ errno = error;
+ else
+ /*
+ * Threads other than the initial thread always use the error
+ * field in the thread structureL
+ */
+ thread->error = error;
+}
diff --git a/lib/libpthread/thread/thr_setprio.c b/lib/libpthread/thread/thr_setprio.c
new file mode 100644
index 0000000..3b7796a
--- /dev/null
+++ b/lib/libpthread/thread/thr_setprio.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_setprio);
+LT10_COMPAT_DEFAULT(pthread_setprio);
+
+__weak_reference(_pthread_setprio, pthread_setprio);
+
+int
+_pthread_setprio(pthread_t pthread, int prio)
+{
+ int ret, policy;
+ struct sched_param param;
+
+ if ((ret = pthread_getschedparam(pthread, &policy, &param)) == 0) {
+ param.sched_priority = prio;
+ ret = pthread_setschedparam(pthread, policy, &param);
+ }
+
+ /* Return the error status: */
+ return (ret);
+}
diff --git a/lib/libpthread/thread/thr_setschedparam.c b/lib/libpthread/thread/thr_setschedparam.c
new file mode 100644
index 0000000..8f5154c
--- /dev/null
+++ b/lib/libpthread/thread/thr_setschedparam.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <sys/param.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_setschedparam);
+LT10_COMPAT_DEFAULT(pthread_setschedparam);
+
+__weak_reference(_pthread_setschedparam, pthread_setschedparam);
+
+int
+_pthread_setschedparam(pthread_t pthread, int policy,
+ const struct sched_param *param)
+{
+ struct pthread *curthread = _get_curthread();
+ int in_syncq;
+ int in_readyq = 0;
+ int old_prio;
+ int ret = 0;
+
+ if ((param == NULL) || (policy < SCHED_FIFO) || (policy > SCHED_RR)) {
+ /* Return an invalid argument error: */
+ ret = EINVAL;
+ } else if ((param->sched_priority < THR_MIN_PRIORITY) ||
+ (param->sched_priority > THR_MAX_PRIORITY)) {
+ /* Return an unsupported value error. */
+ ret = ENOTSUP;
+
+ /* Find the thread in the list of active threads: */
+ } else if ((ret = _thr_ref_add(curthread, pthread, /*include dead*/0))
+ == 0) {
+ /*
+ * Lock the threads scheduling queue while we change
+ * its priority:
+ */
+ THR_SCHED_LOCK(curthread, pthread);
+ if ((pthread->state == PS_DEAD) ||
+ (pthread->state == PS_DEADLOCK) ||
+ ((pthread->flags & THR_FLAGS_EXITING) != 0)) {
+ THR_SCHED_UNLOCK(curthread, pthread);
+ _thr_ref_delete(curthread, pthread);
+ return (ESRCH);
+ }
+ in_syncq = pthread->sflags & THR_FLAGS_IN_SYNCQ;
+
+ /* Set the scheduling policy: */
+ pthread->attr.sched_policy = policy;
+
+ if (param->sched_priority ==
+ THR_BASE_PRIORITY(pthread->base_priority))
+ /*
+ * There is nothing to do; unlock the threads
+ * scheduling queue.
+ */
+ THR_SCHED_UNLOCK(curthread, pthread);
+ else {
+ /*
+ * Remove the thread from its current priority
+ * queue before any adjustments are made to its
+ * active priority:
+ */
+ old_prio = pthread->active_priority;
+ if ((pthread->flags & THR_FLAGS_IN_RUNQ) != 0) {
+ in_readyq = 1;
+ THR_RUNQ_REMOVE(pthread);
+ }
+
+ /* Set the thread base priority: */
+ pthread->base_priority &=
+ (THR_SIGNAL_PRIORITY | THR_RT_PRIORITY);
+ pthread->base_priority = param->sched_priority;
+
+ /* Recalculate the active priority: */
+ pthread->active_priority = MAX(pthread->base_priority,
+ pthread->inherited_priority);
+
+ if (in_readyq) {
+ if ((pthread->priority_mutex_count > 0) &&
+ (old_prio > pthread->active_priority)) {
+ /*
+ * POSIX states that if the priority is
+ * being lowered, the thread must be
+ * inserted at the head of the queue for
+ * its priority if it owns any priority
+ * protection or inheritence mutexes.
+ */
+ THR_RUNQ_INSERT_HEAD(pthread);
+ }
+ else
+ THR_RUNQ_INSERT_TAIL(pthread);
+ }
+
+ /* Unlock the threads scheduling queue: */
+ THR_SCHED_UNLOCK(curthread, pthread);
+
+ /*
+ * Check for any mutex priority adjustments. This
+ * includes checking for a priority mutex on which
+ * this thread is waiting.
+ */
+ _mutex_notify_priochange(curthread, pthread, in_syncq);
+ }
+ _thr_ref_delete(curthread, pthread);
+ }
+ return (ret);
+}
diff --git a/lib/libpthread/thread/thr_sig.c b/lib/libpthread/thread/thr_sig.c
new file mode 100644
index 0000000..f53b87f
--- /dev/null
+++ b/lib/libpthread/thread/thr_sig.c
@@ -0,0 +1,1259 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/signalvar.h>
+#include <signal.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+/* Prototypes: */
+static inline void build_siginfo(siginfo_t *info, int signo);
+#ifndef SYSTEM_SCOPE_ONLY
+static struct pthread *thr_sig_find(struct kse *curkse, int sig,
+ siginfo_t *info);
+#endif
+static inline void thr_sigframe_restore(struct pthread *thread,
+ struct pthread_sigframe *psf);
+static inline void thr_sigframe_save(struct pthread *thread,
+ struct pthread_sigframe *psf);
+
+#define SA_KILL 0x01 /* terminates process by default */
+#define SA_STOP 0x02
+#define SA_CONT 0x04
+
+static int sigproptbl[NSIG] = {
+ SA_KILL, /* SIGHUP */
+ SA_KILL, /* SIGINT */
+ SA_KILL, /* SIGQUIT */
+ SA_KILL, /* SIGILL */
+ SA_KILL, /* SIGTRAP */
+ SA_KILL, /* SIGABRT */
+ SA_KILL, /* SIGEMT */
+ SA_KILL, /* SIGFPE */
+ SA_KILL, /* SIGKILL */
+ SA_KILL, /* SIGBUS */
+ SA_KILL, /* SIGSEGV */
+ SA_KILL, /* SIGSYS */
+ SA_KILL, /* SIGPIPE */
+ SA_KILL, /* SIGALRM */
+ SA_KILL, /* SIGTERM */
+ 0, /* SIGURG */
+ SA_STOP, /* SIGSTOP */
+ SA_STOP, /* SIGTSTP */
+ SA_CONT, /* SIGCONT */
+ 0, /* SIGCHLD */
+ SA_STOP, /* SIGTTIN */
+ SA_STOP, /* SIGTTOU */
+ 0, /* SIGIO */
+ SA_KILL, /* SIGXCPU */
+ SA_KILL, /* SIGXFSZ */
+ SA_KILL, /* SIGVTALRM */
+ SA_KILL, /* SIGPROF */
+ 0, /* SIGWINCH */
+ 0, /* SIGINFO */
+ SA_KILL, /* SIGUSR1 */
+ SA_KILL /* SIGUSR2 */
+};
+
+/* #define DEBUG_SIGNAL */
+#ifdef DEBUG_SIGNAL
+#define DBG_MSG stdout_debug
+#else
+#define DBG_MSG(x...)
+#endif
+
+static __inline int
+_thr_dump_enabled(void)
+{
+ return ((_thr_debug_flags & DBG_INFO_DUMP) != 0);
+}
+
+/*
+ * Signal setup and delivery.
+ *
+ * 1) Delivering signals to threads in the same KSE.
+ * These signals are sent by upcall events and are set in the
+ * km_sigscaught field of the KSE mailbox. Since these signals
+ * are received while operating on the KSE stack, they can be
+ * delivered either by using signalcontext() to add a stack frame
+ * to the target thread's stack, or by adding them in the thread's
+ * pending set and having the thread run them down after it
+ * 2) Delivering signals to threads in other KSEs/KSEGs.
+ * 3) Delivering signals to threads in critical regions.
+ * 4) Delivering signals to threads after they change their signal masks.
+ *
+ * Methods of delivering signals.
+ *
+ * 1) Add a signal frame to the thread's saved context.
+ * 2) Add the signal to the thread structure, mark the thread as
+ * having signals to handle, and let the thread run them down
+ * after it resumes from the KSE scheduler.
+ *
+ * Problem with 1). You can't do this to a running thread or a
+ * thread in a critical region.
+ *
+ * Problem with 2). You can't do this to a thread that doesn't
+ * yield in some way (explicitly enters the scheduler). A thread
+ * blocked in the kernel or a CPU hungry thread will not see the
+ * signal without entering the scheduler.
+ *
+ * The solution is to use both 1) and 2) to deliver signals:
+ *
+ * o Thread in critical region - use 2). When the thread
+ * leaves the critical region it will check to see if it
+ * has pending signals and run them down.
+ *
+ * o Thread enters scheduler explicitly - use 2). The thread
+ * can check for pending signals after it returns from the
+ * the scheduler.
+ *
+ * o Thread is running and not current thread - use 2). When the
+ * thread hits a condition specified by one of the other bullets,
+ * the signal will be delivered.
+ *
+ * o Thread is running and is current thread (e.g., the thread
+ * has just changed its signal mask and now sees that it has
+ * pending signals) - just run down the pending signals.
+ *
+ * o Thread is swapped out due to quantum expiration - use 1)
+ *
+ * o Thread is blocked in kernel - kse_thr_wakeup() and then
+ * use 1)
+ */
+
+/*
+ * Rules for selecting threads for signals received:
+ *
+ * 1) If the signal is a sychronous signal, it is delivered to
+ * the generating (current thread). If the thread has the
+ * signal masked, it is added to the threads pending signal
+ * set until the thread unmasks it.
+ *
+ * 2) A thread in sigwait() where the signal is in the thread's
+ * waitset.
+ *
+ * 3) A thread in sigsuspend() where the signal is not in the
+ * thread's suspended signal mask.
+ *
+ * 4) Any thread (first found/easiest to deliver) that has the
+ * signal unmasked.
+ */
+
+#ifndef SYSTEM_SCOPE_ONLY
+
+static void *
+sig_daemon(void *arg /* Unused */)
+{
+ int i;
+ kse_critical_t crit;
+ struct timespec ts;
+ sigset_t set;
+ struct kse *curkse;
+ struct pthread *curthread = _get_curthread();
+
+ DBG_MSG("signal daemon started(%p)\n", curthread);
+
+ curthread->name = strdup("signal thread");
+ crit = _kse_critical_enter();
+ curkse = _get_curkse();
+
+ /*
+ * Daemon thread is a bound thread and we must be created with
+ * all signals masked
+ */
+#if 0
+ SIGFILLSET(set);
+ __sys_sigprocmask(SIG_SETMASK, &set, NULL);
+#endif
+ __sys_sigpending(&set);
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+ while (1) {
+ KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock);
+ _thr_proc_sigpending = set;
+ KSE_LOCK_RELEASE(curkse, &_thread_signal_lock);
+ for (i = 1; i <= _SIG_MAXSIG; i++) {
+ if (SIGISMEMBER(set, i) != 0)
+ _thr_sig_dispatch(curkse, i,
+ NULL /* no siginfo */);
+ }
+ ts.tv_sec = 30;
+ ts.tv_nsec = 0;
+ curkse->k_kcb->kcb_kmbx.km_flags =
+ KMF_NOUPCALL | KMF_NOCOMPLETED | KMF_WAITSIGEVENT;
+ kse_release(&ts);
+ curkse->k_kcb->kcb_kmbx.km_flags = 0;
+ set = curkse->k_kcb->kcb_kmbx.km_sigscaught;
+ }
+ return (0);
+}
+
+
+/* Utility function to create signal daemon thread */
+int
+_thr_start_sig_daemon(void)
+{
+ pthread_attr_t attr;
+ sigset_t sigset, oldset;
+
+ SIGFILLSET(sigset);
+ pthread_sigmask(SIG_SETMASK, &sigset, &oldset);
+ pthread_attr_init(&attr);
+ pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
+ attr->flags |= THR_SIGNAL_THREAD;
+ /* sigmask will be inherited */
+ if (pthread_create(&_thr_sig_daemon, &attr, sig_daemon, NULL))
+ PANIC("can not create signal daemon thread!\n");
+ pthread_attr_destroy(&attr);
+ pthread_sigmask(SIG_SETMASK, &oldset, NULL);
+ return (0);
+}
+
+/*
+ * This signal handler only delivers asynchronous signals.
+ * This must be called with upcalls disabled and without
+ * holding any locks.
+ */
+void
+_thr_sig_dispatch(struct kse *curkse, int sig, siginfo_t *info)
+{
+ struct kse_mailbox *kmbx;
+ struct pthread *thread;
+
+ DBG_MSG(">>> _thr_sig_dispatch(%d)\n", sig);
+
+ /* Check if the signal requires a dump of thread information: */
+ if (_thr_dump_enabled() && (sig == SIGINFO)) {
+ /* Dump thread information to file: */
+ _thread_dump_info();
+ }
+
+ while ((thread = thr_sig_find(curkse, sig, info)) != NULL) {
+ /*
+ * Setup the target thread to receive the signal:
+ */
+ DBG_MSG("Got signal %d, selecting thread %p\n", sig, thread);
+ KSE_SCHED_LOCK(curkse, thread->kseg);
+ if ((thread->state == PS_DEAD) ||
+ (thread->state == PS_DEADLOCK) ||
+ THR_IS_EXITING(thread) || THR_IS_SUSPENDED(thread)) {
+ KSE_SCHED_UNLOCK(curkse, thread->kseg);
+ _thr_ref_delete(NULL, thread);
+ } else if (SIGISMEMBER(thread->sigmask, sig)) {
+ KSE_SCHED_UNLOCK(curkse, thread->kseg);
+ _thr_ref_delete(NULL, thread);
+ } else {
+ kmbx = _thr_sig_add(thread, sig, info);
+ KSE_SCHED_UNLOCK(curkse, thread->kseg);
+ _thr_ref_delete(NULL, thread);
+ if (kmbx != NULL)
+ kse_wakeup(kmbx);
+ break;
+ }
+ }
+ DBG_MSG("<<< _thr_sig_dispatch\n");
+}
+
+#endif /* ! SYSTEM_SCOPE_ONLY */
+
+static __inline int
+sigprop(int sig)
+{
+
+ if (sig > 0 && sig < NSIG)
+ return (sigproptbl[_SIG_IDX(sig)]);
+ return (0);
+}
+
+typedef void (*ohandler)(int sig, int code,
+ struct sigcontext *scp, char *addr, __sighandler_t *catcher);
+
+void
+_thr_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
+{
+ struct pthread_sigframe psf;
+ __siginfohandler_t *sigfunc;
+ struct pthread *curthread;
+ struct kse *curkse;
+ struct sigaction act;
+ int sa_flags, err_save;
+
+ err_save = errno;
+
+ DBG_MSG(">>> _thr_sig_handler(%d)\n", sig);
+
+ curthread = _get_curthread();
+ if (curthread == NULL)
+ PANIC("No current thread.\n");
+ if (!(curthread->attr.flags & PTHREAD_SCOPE_SYSTEM))
+ PANIC("Thread is not system scope.\n");
+ if (curthread->flags & THR_FLAGS_EXITING) {
+ errno = err_save;
+ return;
+ }
+
+ curkse = _get_curkse();
+ /*
+ * If thread is in critical region or if thread is on
+ * the way of state transition, then latch signal into buffer.
+ */
+ if (_kse_in_critical() || THR_IN_CRITICAL(curthread) ||
+ curthread->state != PS_RUNNING) {
+ DBG_MSG(">>> _thr_sig_handler(%d) in critical\n", sig);
+ curthread->siginfo[sig-1] = *info;
+ curthread->check_pending = 1;
+ curkse->k_sigseqno++;
+ SIGADDSET(curthread->sigpend, sig);
+ /*
+ * If the kse is on the way to idle itself, but
+ * we have signal ready, we should prevent it
+ * to sleep, kernel will latch the wakeup request,
+ * so kse_release will return from kernel immediately.
+ */
+ if (KSE_IS_IDLE(curkse))
+ kse_wakeup(&curkse->k_kcb->kcb_kmbx);
+ errno = err_save;
+ return;
+ }
+
+ /* Check if the signal requires a dump of thread information: */
+ if (_thr_dump_enabled() && (sig == SIGINFO)) {
+ /* Dump thread information to file: */
+ _thread_dump_info();
+ }
+
+ /* Check the threads previous state: */
+ curthread->critical_count++;
+ if (curthread->sigbackout != NULL)
+ curthread->sigbackout((void *)curthread);
+ curthread->critical_count--;
+ thr_sigframe_save(curthread, &psf);
+ THR_ASSERT(!(curthread->sigbackout), "sigbackout was not cleared.");
+
+ _kse_critical_enter();
+ /* Get a fresh copy of signal mask */
+ __sys_sigprocmask(SIG_BLOCK, NULL, &curthread->sigmask);
+ KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock);
+ sigfunc = _thread_sigact[sig - 1].sa_sigaction;
+ sa_flags = _thread_sigact[sig - 1].sa_flags;
+ if (sa_flags & SA_RESETHAND) {
+ act.sa_handler = SIG_DFL;
+ act.sa_flags = SA_RESTART;
+ SIGEMPTYSET(act.sa_mask);
+ __sys_sigaction(sig, &act, NULL);
+ __sys_sigaction(sig, NULL, &_thread_sigact[sig - 1]);
+ }
+ KSE_LOCK_RELEASE(curkse, &_thread_signal_lock);
+ _kse_critical_leave(&curthread->tcb->tcb_tmbx);
+
+ /* Now invoke real handler */
+ if (((__sighandler_t *)sigfunc != SIG_DFL) &&
+ ((__sighandler_t *)sigfunc != SIG_IGN) &&
+ (sigfunc != (__siginfohandler_t *)_thr_sig_handler)) {
+ if ((sa_flags & SA_SIGINFO) != 0 || info == NULL)
+ (*(sigfunc))(sig, info, ucp);
+ else {
+ ((ohandler)(*sigfunc))(
+ sig, info->si_code, (struct sigcontext *)ucp,
+ info->si_addr, (__sighandler_t *)sigfunc);
+ }
+ } else {
+ if ((__sighandler_t *)sigfunc == SIG_DFL) {
+ if (sigprop(sig) & SA_KILL) {
+ if (_kse_isthreaded())
+ kse_thr_interrupt(NULL,
+ KSE_INTR_SIGEXIT, sig);
+ else
+ kill(getpid(), sig);
+ }
+#ifdef NOTYET
+ else if (sigprop(sig) & SA_STOP)
+ kse_thr_interrupt(NULL, KSE_INTR_JOBSTOP, sig);
+#endif
+ }
+ }
+ _kse_critical_enter();
+ curthread->sigmask = ucp->uc_sigmask;
+ SIG_CANTMASK(curthread->sigmask);
+ _kse_critical_leave(&curthread->tcb->tcb_tmbx);
+
+ thr_sigframe_restore(curthread, &psf);
+
+ DBG_MSG("<<< _thr_sig_handler(%d)\n", sig);
+
+ errno = err_save;
+}
+
+struct sighandle_info {
+ __siginfohandler_t *sigfunc;
+ int sa_flags;
+ int sig;
+ siginfo_t *info;
+ ucontext_t *ucp;
+};
+
+static void handle_signal(struct pthread *curthread,
+ struct sighandle_info *shi);
+static void handle_signal_altstack(struct pthread *curthread,
+ struct sighandle_info *shi);
+
+/* Must be called with signal lock and schedule lock held in order */
+static void
+thr_sig_invoke_handler(struct pthread *curthread, int sig, siginfo_t *info,
+ ucontext_t *ucp)
+{
+ __siginfohandler_t *sigfunc;
+ sigset_t sigmask;
+ int sa_flags;
+ int onstack;
+ struct sigaction act;
+ struct kse *curkse;
+ struct sighandle_info shi;
+
+ /*
+ * Invoke the signal handler without going through the scheduler:
+ */
+ DBG_MSG("Got signal %d, calling handler for current thread %p\n",
+ sig, curthread);
+
+ if (!_kse_in_critical())
+ PANIC("thr_sig_invoke_handler without in critical\n");
+ curkse = curthread->kse;
+ /*
+ * Check that a custom handler is installed and if
+ * the signal is not blocked:
+ */
+ sigfunc = _thread_sigact[sig - 1].sa_sigaction;
+ sa_flags = _thread_sigact[sig - 1].sa_flags;
+ sigmask = curthread->sigmask;
+ SIGSETOR(curthread->sigmask, _thread_sigact[sig - 1].sa_mask);
+ if (!(sa_flags & (SA_NODEFER | SA_RESETHAND)))
+ SIGADDSET(curthread->sigmask, sig);
+ if ((sig != SIGILL) && (sa_flags & SA_RESETHAND)) {
+ act.sa_handler = SIG_DFL;
+ act.sa_flags = SA_RESTART;
+ SIGEMPTYSET(act.sa_mask);
+ __sys_sigaction(sig, &act, NULL);
+ __sys_sigaction(sig, NULL, &_thread_sigact[sig - 1]);
+ }
+ KSE_LOCK_RELEASE(curkse, &_thread_signal_lock);
+ KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
+ /*
+ * We are processing buffered signals, synchronize working
+ * signal mask into kernel.
+ */
+ if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
+ __sys_sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL);
+ onstack = _thr_sigonstack(&sigfunc);
+ ucp->uc_stack = curthread->sigstk;
+ ucp->uc_stack.ss_flags = (curthread->sigstk.ss_flags & SS_DISABLE)
+ ? SS_DISABLE : ((onstack) ? SS_ONSTACK : 0);
+ if (curthread->oldsigmask) {
+ ucp->uc_sigmask = *(curthread->oldsigmask);
+ curthread->oldsigmask = NULL;
+ } else
+ ucp->uc_sigmask = sigmask;
+ shi.sigfunc = sigfunc;
+ shi.sig = sig;
+ shi.sa_flags = sa_flags;
+ shi.info = info;
+ shi.ucp = ucp;
+ if ((curthread->sigstk.ss_flags & SS_DISABLE) == 0) {
+ /* Deliver signal on alternative stack */
+ if (sa_flags & SA_ONSTACK && !onstack)
+ handle_signal_altstack(curthread, &shi);
+ else
+ handle_signal(curthread, &shi);
+ } else {
+ handle_signal(curthread, &shi);
+ }
+
+ _kse_critical_enter();
+ /* Don't trust after critical leave/enter */
+ curkse = curthread->kse;
+
+ /*
+ * Restore the thread's signal mask.
+ */
+ curthread->sigmask = ucp->uc_sigmask;
+ SIG_CANTMASK(curthread->sigmask);
+ if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
+ __sys_sigprocmask(SIG_SETMASK, &ucp->uc_sigmask, NULL);
+ KSE_SCHED_LOCK(curkse, curkse->k_kseg);
+ KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock);
+
+ DBG_MSG("Got signal %d, handler returned %p\n", sig, curthread);
+}
+
+static void
+handle_signal(struct pthread *curthread, struct sighandle_info *shi)
+{
+ _kse_critical_leave(&curthread->tcb->tcb_tmbx);
+
+ /* Check if the signal requires a dump of thread information: */
+ if (_thr_dump_enabled() && (shi->sig == SIGINFO)) {
+ /* Dump thread information to file: */
+ _thread_dump_info();
+ }
+
+ if (((__sighandler_t *)shi->sigfunc != SIG_DFL) &&
+ ((__sighandler_t *)shi->sigfunc != SIG_IGN)) {
+ if ((shi->sa_flags & SA_SIGINFO) != 0 || shi->info == NULL)
+ (*(shi->sigfunc))(shi->sig, shi->info, shi->ucp);
+ else {
+ ((ohandler)(*shi->sigfunc))(
+ shi->sig, shi->info->si_code,
+ (struct sigcontext *)shi->ucp,
+ shi->info->si_addr,
+ (__sighandler_t *)shi->sigfunc);
+ }
+ } else {
+ if ((__sighandler_t *)shi->sigfunc == SIG_DFL) {
+ if (sigprop(shi->sig) & SA_KILL) {
+ if (_kse_isthreaded())
+ kse_thr_interrupt(NULL,
+ KSE_INTR_SIGEXIT, shi->sig);
+ else
+ kill(getpid(), shi->sig);
+ }
+#ifdef NOTYET
+ else if (sigprop(shi->sig) & SA_STOP)
+ kse_thr_interrupt(NULL, KSE_INTR_JOBSTOP,
+ shi->sig);
+#endif
+ }
+ }
+}
+
+static void
+handle_signal_wrapper(struct pthread *curthread, ucontext_t *ret_uc,
+ struct sighandle_info *shi)
+{
+ shi->ucp->uc_stack.ss_flags = SS_ONSTACK;
+ handle_signal(curthread, shi);
+ if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
+ setcontext(ret_uc);
+ else {
+ /* Work around for ia64, THR_SETCONTEXT does not work */
+ _kse_critical_enter();
+ curthread->tcb->tcb_tmbx.tm_context = *ret_uc;
+ _thread_switch(curthread->kse->k_kcb, curthread->tcb, 1);
+ /* THR_SETCONTEXT */
+ }
+}
+
+/*
+ * Jump to stack set by sigaltstack before invoking signal handler
+ */
+static void
+handle_signal_altstack(struct pthread *curthread, struct sighandle_info *shi)
+{
+ volatile int once;
+ ucontext_t uc1, *uc2;
+
+ THR_ASSERT(_kse_in_critical(), "Not in critical");
+
+ once = 0;
+ THR_GETCONTEXT(&uc1);
+ if (once == 0) {
+ once = 1;
+ /* XXX
+ * We are still in critical region, it is safe to operate thread
+ * context
+ */
+ uc2 = &curthread->tcb->tcb_tmbx.tm_context;
+ uc2->uc_stack = curthread->sigstk;
+ makecontext(uc2, (void (*)(void))handle_signal_wrapper,
+ 3, curthread, &uc1, shi);
+ if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
+ setcontext(uc2);
+ else {
+ _thread_switch(curthread->kse->k_kcb, curthread->tcb, 1);
+ /* THR_SETCONTEXT(uc2); */
+ }
+ }
+}
+
+int
+_thr_getprocsig(int sig, siginfo_t *siginfo)
+{
+ kse_critical_t crit;
+ struct kse *curkse;
+ int ret;
+
+ DBG_MSG(">>> _thr_getprocsig\n");
+
+ crit = _kse_critical_enter();
+ curkse = _get_curkse();
+ KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock);
+ ret = _thr_getprocsig_unlocked(sig, siginfo);
+ KSE_LOCK_RELEASE(curkse, &_thread_signal_lock);
+ _kse_critical_leave(crit);
+
+ DBG_MSG("<<< _thr_getprocsig\n");
+ return (ret);
+}
+
+int
+_thr_getprocsig_unlocked(int sig, siginfo_t *siginfo)
+{
+ sigset_t sigset;
+ struct timespec ts;
+
+ /* try to retrieve signal from kernel */
+ SIGEMPTYSET(sigset);
+ SIGADDSET(sigset, sig);
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+ SIGDELSET(_thr_proc_sigpending, sig);
+ if (__sys_sigtimedwait(&sigset, siginfo, &ts) > 0)
+ return (sig);
+ return (0);
+}
+
+#ifndef SYSTEM_SCOPE_ONLY
+/*
+ * Find a thread that can handle the signal. This must be called
+ * with upcalls disabled.
+ */
+struct pthread *
+thr_sig_find(struct kse *curkse, int sig, siginfo_t *info)
+{
+ struct kse_mailbox *kmbx = NULL;
+ struct pthread *pthread;
+ struct pthread *suspended_thread, *signaled_thread;
+ __siginfohandler_t *sigfunc;
+ siginfo_t si;
+
+ DBG_MSG("Looking for thread to handle signal %d\n", sig);
+
+ /*
+ * Enter a loop to look for threads that have the signal
+ * unmasked. POSIX specifies that a thread in a sigwait
+ * will get the signal over any other threads. Second
+ * preference will be threads in in a sigsuspend. Third
+ * preference will be the current thread. If none of the
+ * above, then the signal is delivered to the first thread
+ * that is found. Note that if a custom handler is not
+ * installed, the signal only affects threads in sigwait.
+ */
+ suspended_thread = NULL;
+ signaled_thread = NULL;
+
+ KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock);
+ TAILQ_FOREACH(pthread, &_thread_list, tle) {
+ if (pthread == _thr_sig_daemon)
+ continue;
+ /* Signal delivering to bound thread is done by kernel */
+ if (pthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
+ continue;
+ /* Take the scheduling lock. */
+ KSE_SCHED_LOCK(curkse, pthread->kseg);
+ if ((pthread->state == PS_DEAD) ||
+ (pthread->state == PS_DEADLOCK) ||
+ THR_IS_EXITING(pthread) ||
+ THR_IS_SUSPENDED(pthread)) {
+ ; /* Skip this thread. */
+ } else if (pthread->state == PS_SIGWAIT &&
+ SIGISMEMBER(*(pthread->data.sigwait->waitset), sig)) {
+ /*
+ * retrieve signal from kernel, if it is job control
+ * signal, and sigaction is SIG_DFL, then we will
+ * be stopped in kernel, we hold lock here, but that
+ * does not matter, because that's job control, and
+ * whole process should be stopped.
+ */
+ if (_thr_getprocsig(sig, &si)) {
+ DBG_MSG("Waking thread %p in sigwait"
+ " with signal %d\n", pthread, sig);
+ /* where to put siginfo ? */
+ *(pthread->data.sigwait->siginfo) = si;
+ kmbx = _thr_setrunnable_unlocked(pthread);
+ }
+ KSE_SCHED_UNLOCK(curkse, pthread->kseg);
+ /*
+ * POSIX doesn't doesn't specify which thread
+ * will get the signal if there are multiple
+ * waiters, so we give it to the first thread
+ * we find.
+ *
+ * Do not attempt to deliver this signal
+ * to other threads and do not add the signal
+ * to the process pending set.
+ */
+ KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
+ if (kmbx != NULL)
+ kse_wakeup(kmbx);
+ if (suspended_thread != NULL)
+ _thr_ref_delete(NULL, suspended_thread);
+ if (signaled_thread != NULL)
+ _thr_ref_delete(NULL, signaled_thread);
+ return (NULL);
+ } else if (!SIGISMEMBER(pthread->sigmask, sig)) {
+ /*
+ * If debugger is running, we don't quick exit,
+ * and give it a chance to check the signal.
+ */
+ if (_libkse_debug == 0) {
+ sigfunc = _thread_sigact[sig - 1].sa_sigaction;
+ if ((__sighandler_t *)sigfunc == SIG_DFL) {
+ if (sigprop(sig) & SA_KILL) {
+ kse_thr_interrupt(NULL,
+ KSE_INTR_SIGEXIT, sig);
+ /* Never reach */
+ }
+ }
+ }
+ if (pthread->state == PS_SIGSUSPEND) {
+ if (suspended_thread == NULL) {
+ suspended_thread = pthread;
+ suspended_thread->refcount++;
+ }
+ } else if (signaled_thread == NULL) {
+ signaled_thread = pthread;
+ signaled_thread->refcount++;
+ }
+ }
+ KSE_SCHED_UNLOCK(curkse, pthread->kseg);
+ }
+ KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
+
+ if (suspended_thread != NULL) {
+ pthread = suspended_thread;
+ if (signaled_thread)
+ _thr_ref_delete(NULL, signaled_thread);
+ } else if (signaled_thread) {
+ pthread = signaled_thread;
+ } else {
+ pthread = NULL;
+ }
+ return (pthread);
+}
+#endif /* ! SYSTEM_SCOPE_ONLY */
+
+static inline void
+build_siginfo(siginfo_t *info, int signo)
+{
+ bzero(info, sizeof(*info));
+ info->si_signo = signo;
+ info->si_pid = _thr_pid;
+}
+
+/*
+ * This is called by a thread when it has pending signals to deliver.
+ * It should only be called from the context of the thread.
+ */
+void
+_thr_sig_rundown(struct pthread *curthread, ucontext_t *ucp)
+{
+ struct pthread_sigframe psf;
+ siginfo_t siginfo;
+ int i, err_save;
+ kse_critical_t crit;
+ struct kse *curkse;
+ sigset_t sigmask;
+
+ err_save = errno;
+
+ DBG_MSG(">>> thr_sig_rundown (%p)\n", curthread);
+
+ /* Check the threads previous state: */
+ curthread->critical_count++;
+ if (curthread->sigbackout != NULL)
+ curthread->sigbackout((void *)curthread);
+ curthread->critical_count--;
+
+ THR_ASSERT(!(curthread->sigbackout), "sigbackout was not cleared.");
+ THR_ASSERT((curthread->state == PS_RUNNING), "state is not PS_RUNNING");
+
+ thr_sigframe_save(curthread, &psf);
+ /*
+ * Lower the priority before calling the handler in case
+ * it never returns (longjmps back):
+ */
+ crit = _kse_critical_enter();
+ curkse = curthread->kse;
+ KSE_SCHED_LOCK(curkse, curkse->k_kseg);
+ KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock);
+ curthread->active_priority &= ~THR_SIGNAL_PRIORITY;
+ SIGFILLSET(sigmask);
+ while (1) {
+ /*
+ * For bound thread, we mask all signals and get a fresh
+ * copy of signal mask from kernel
+ */
+ if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) {
+ __sys_sigprocmask(SIG_SETMASK, &sigmask,
+ &curthread->sigmask);
+ }
+ for (i = 1; i <= _SIG_MAXSIG; i++) {
+ if (SIGISMEMBER(curthread->sigmask, i))
+ continue;
+ if (SIGISMEMBER(curthread->sigpend, i)) {
+ SIGDELSET(curthread->sigpend, i);
+ siginfo = curthread->siginfo[i-1];
+ break;
+ }
+ if (!(curthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
+ && SIGISMEMBER(_thr_proc_sigpending, i)) {
+ if (_thr_getprocsig_unlocked(i, &siginfo))
+ break;
+ }
+ }
+ if (i <= _SIG_MAXSIG)
+ thr_sig_invoke_handler(curthread, i, &siginfo, ucp);
+ else {
+ if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) {
+ __sys_sigprocmask(SIG_SETMASK,
+ &curthread->sigmask, NULL);
+ }
+ break;
+ }
+ }
+
+ /* Don't trust after signal handling */
+ curkse = curthread->kse;
+ KSE_LOCK_RELEASE(curkse, &_thread_signal_lock);
+ KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
+ _kse_critical_leave(&curthread->tcb->tcb_tmbx);
+ /* repost masked signal to kernel, it hardly happens in real world */
+ if ((curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) &&
+ !SIGISEMPTY(curthread->sigpend)) { /* dirty read */
+ __sys_sigprocmask(SIG_SETMASK, &sigmask, &curthread->sigmask);
+ for (i = 1; i <= _SIG_MAXSIG; ++i) {
+ if (SIGISMEMBER(curthread->sigpend, i)) {
+ SIGDELSET(curthread->sigpend, i);
+ if (!_kse_isthreaded())
+ kill(getpid(), i);
+ else
+ kse_thr_interrupt(
+ &curthread->tcb->tcb_tmbx,
+ KSE_INTR_SENDSIG,
+ i);
+ }
+ }
+ __sys_sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL);
+ }
+ DBG_MSG("<<< thr_sig_rundown (%p)\n", curthread);
+
+ thr_sigframe_restore(curthread, &psf);
+ errno = err_save;
+}
+
+/*
+ * This checks pending signals for the current thread. It should be
+ * called whenever a thread changes its signal mask. Note that this
+ * is called from a thread (using its stack).
+ *
+ * XXX - We might want to just check to see if there are pending
+ * signals for the thread here, but enter the UTS scheduler
+ * to actually install the signal handler(s).
+ */
+void
+_thr_sig_check_pending(struct pthread *curthread)
+{
+ ucontext_t uc;
+ volatile int once;
+ int errsave;
+
+ /*
+ * If the thread is in critical region, delay processing signals.
+ * If the thread state is not PS_RUNNING, it might be switching
+ * into UTS and but a THR_LOCK_RELEASE saw check_pending, and it
+ * goes here, in the case we delay processing signals, lets UTS
+ * process complicated things, normally UTS will call _thr_sig_add
+ * to resume the thread, so we needn't repeat doing it here.
+ */
+ if (THR_IN_CRITICAL(curthread) || curthread->state != PS_RUNNING)
+ return;
+
+ errsave = errno;
+ once = 0;
+ THR_GETCONTEXT(&uc);
+ if (once == 0) {
+ once = 1;
+ curthread->check_pending = 0;
+ _thr_sig_rundown(curthread, &uc);
+ }
+ errno = errsave;
+}
+
+/*
+ * Perform thread specific actions in response to a signal.
+ * This function is only called if there is a handler installed
+ * for the signal, and if the target thread has the signal
+ * unmasked.
+ *
+ * This must be called with the thread's scheduling lock held.
+ */
+struct kse_mailbox *
+_thr_sig_add(struct pthread *pthread, int sig, siginfo_t *info)
+{
+ siginfo_t siginfo;
+ struct kse *curkse;
+ struct kse_mailbox *kmbx = NULL;
+ struct pthread *curthread = _get_curthread();
+ int restart;
+ int suppress_handler = 0;
+ int fromproc = 0;
+ __sighandler_t *sigfunc;
+
+ DBG_MSG(">>> _thr_sig_add %p (%d)\n", pthread, sig);
+
+ curkse = _get_curkse();
+ restart = _thread_sigact[sig - 1].sa_flags & SA_RESTART;
+ sigfunc = _thread_sigact[sig - 1].sa_handler;
+ fromproc = (curthread == _thr_sig_daemon);
+
+ if (pthread->state == PS_DEAD || pthread->state == PS_DEADLOCK ||
+ pthread->state == PS_STATE_MAX)
+ return (NULL); /* return false */
+
+ if ((pthread->attr.flags & PTHREAD_SCOPE_SYSTEM) &&
+ (curthread != pthread)) {
+ PANIC("Please use _thr_send_sig for bound thread");
+ return (NULL);
+ }
+
+ if (pthread->state != PS_SIGWAIT &&
+ SIGISMEMBER(pthread->sigmask, sig)) {
+ /* signal is masked, just add signal to thread. */
+ if (!fromproc) {
+ SIGADDSET(pthread->sigpend, sig);
+ if (info == NULL)
+ build_siginfo(&pthread->siginfo[sig-1], sig);
+ else if (info != &pthread->siginfo[sig-1])
+ memcpy(&pthread->siginfo[sig-1], info,
+ sizeof(*info));
+ } else {
+ if (!_thr_getprocsig(sig, &pthread->siginfo[sig-1]))
+ return (NULL);
+ SIGADDSET(pthread->sigpend, sig);
+ }
+ }
+ else {
+ /* if process signal not exists, just return */
+ if (fromproc) {
+ if (!_thr_getprocsig(sig, &siginfo))
+ return (NULL);
+ info = &siginfo;
+ }
+
+ if (pthread->state != PS_SIGWAIT && sigfunc == SIG_DFL &&
+ (sigprop(sig) & SA_KILL)) {
+ kse_thr_interrupt(NULL, KSE_INTR_SIGEXIT, sig);
+ /* Never reach */
+ }
+
+ /*
+ * Process according to thread state:
+ */
+ switch (pthread->state) {
+ case PS_DEAD:
+ case PS_DEADLOCK:
+ case PS_STATE_MAX:
+ return (NULL); /* XXX return false */
+ case PS_LOCKWAIT:
+ case PS_SUSPENDED:
+ /*
+ * You can't call a signal handler for threads in these
+ * states.
+ */
+ suppress_handler = 1;
+ break;
+ case PS_RUNNING:
+ if ((pthread->flags & THR_FLAGS_IN_RUNQ)) {
+ THR_RUNQ_REMOVE(pthread);
+ pthread->active_priority |= THR_SIGNAL_PRIORITY;
+ THR_RUNQ_INSERT_TAIL(pthread);
+ } else {
+ /* Possible not in RUNQ and has curframe ? */
+ pthread->active_priority |= THR_SIGNAL_PRIORITY;
+ }
+ break;
+ /*
+ * States which cannot be interrupted but still require the
+ * signal handler to run:
+ */
+ case PS_COND_WAIT:
+ case PS_MUTEX_WAIT:
+ break;
+
+ case PS_SLEEP_WAIT:
+ /*
+ * Unmasked signals always cause sleep to terminate
+ * early regardless of SA_RESTART:
+ */
+ pthread->interrupted = 1;
+ break;
+
+ case PS_JOIN:
+ break;
+
+ case PS_SIGSUSPEND:
+ pthread->interrupted = 1;
+ break;
+
+ case PS_SIGWAIT:
+ if (info == NULL)
+ build_siginfo(&pthread->siginfo[sig-1], sig);
+ else if (info != &pthread->siginfo[sig-1])
+ memcpy(&pthread->siginfo[sig-1], info,
+ sizeof(*info));
+ /*
+ * The signal handler is not called for threads in
+ * SIGWAIT.
+ */
+ suppress_handler = 1;
+ /* Wake up the thread if the signal is not blocked. */
+ if (SIGISMEMBER(*(pthread->data.sigwait->waitset), sig)) {
+ /* Return the signal number: */
+ *(pthread->data.sigwait->siginfo) = pthread->siginfo[sig-1];
+ /* Make the thread runnable: */
+ kmbx = _thr_setrunnable_unlocked(pthread);
+ } else {
+ /* Increment the pending signal count. */
+ SIGADDSET(pthread->sigpend, sig);
+ if (!SIGISMEMBER(pthread->sigmask, sig)) {
+ if (sigfunc == SIG_DFL &&
+ sigprop(sig) & SA_KILL) {
+ kse_thr_interrupt(NULL,
+ KSE_INTR_SIGEXIT,
+ sig);
+ /* Never reach */
+ }
+ pthread->check_pending = 1;
+ pthread->interrupted = 1;
+ kmbx = _thr_setrunnable_unlocked(pthread);
+ }
+ }
+ return (kmbx);
+ }
+
+ SIGADDSET(pthread->sigpend, sig);
+ if (info == NULL)
+ build_siginfo(&pthread->siginfo[sig-1], sig);
+ else if (info != &pthread->siginfo[sig-1])
+ memcpy(&pthread->siginfo[sig-1], info, sizeof(*info));
+ pthread->check_pending = 1;
+ if (!(pthread->attr.flags & PTHREAD_SCOPE_SYSTEM) &&
+ (pthread->blocked != 0) && !THR_IN_CRITICAL(pthread))
+ kse_thr_interrupt(&pthread->tcb->tcb_tmbx,
+ restart ? KSE_INTR_RESTART : KSE_INTR_INTERRUPT, 0);
+ if (suppress_handler == 0) {
+ /*
+ * Setup a signal frame and save the current threads
+ * state:
+ */
+ if (pthread->state != PS_RUNNING) {
+ if (pthread->flags & THR_FLAGS_IN_RUNQ)
+ THR_RUNQ_REMOVE(pthread);
+ pthread->active_priority |= THR_SIGNAL_PRIORITY;
+ kmbx = _thr_setrunnable_unlocked(pthread);
+ }
+ }
+ }
+ return (kmbx);
+}
+
+/*
+ * Send a signal to a specific thread (ala pthread_kill):
+ */
+void
+_thr_sig_send(struct pthread *pthread, int sig)
+{
+ struct pthread *curthread = _get_curthread();
+ struct kse_mailbox *kmbx;
+
+ if (pthread->attr.flags & PTHREAD_SCOPE_SYSTEM) {
+ kse_thr_interrupt(&pthread->tcb->tcb_tmbx, KSE_INTR_SENDSIG, sig);
+ return;
+ }
+
+ /* Lock the scheduling queue of the target thread. */
+ THR_SCHED_LOCK(curthread, pthread);
+ if (_thread_sigact[sig - 1].sa_handler != SIG_IGN) {
+ kmbx = _thr_sig_add(pthread, sig, NULL);
+ /* Add a preemption point. */
+ if (kmbx == NULL && (curthread->kseg == pthread->kseg) &&
+ (pthread->active_priority > curthread->active_priority))
+ curthread->critical_yield = 1;
+ THR_SCHED_UNLOCK(curthread, pthread);
+ if (kmbx != NULL)
+ kse_wakeup(kmbx);
+ /* XXX
+ * If thread sent signal to itself, check signals now.
+ * It is not really needed, _kse_critical_leave should
+ * have already checked signals.
+ */
+ if (pthread == curthread && curthread->check_pending)
+ _thr_sig_check_pending(curthread);
+
+ } else {
+ THR_SCHED_UNLOCK(curthread, pthread);
+ }
+}
+
+static inline void
+thr_sigframe_restore(struct pthread *curthread, struct pthread_sigframe *psf)
+{
+ kse_critical_t crit;
+ struct kse *curkse;
+
+ THR_THREAD_LOCK(curthread, curthread);
+ curthread->cancelflags = psf->psf_cancelflags;
+ crit = _kse_critical_enter();
+ curkse = curthread->kse;
+ KSE_SCHED_LOCK(curkse, curthread->kseg);
+ curthread->flags = psf->psf_flags;
+ curthread->interrupted = psf->psf_interrupted;
+ curthread->timeout = psf->psf_timeout;
+ curthread->data = psf->psf_wait_data;
+ curthread->wakeup_time = psf->psf_wakeup_time;
+ curthread->continuation = psf->psf_continuation;
+ KSE_SCHED_UNLOCK(curkse, curthread->kseg);
+ _kse_critical_leave(crit);
+ THR_THREAD_UNLOCK(curthread, curthread);
+}
+
+static inline void
+thr_sigframe_save(struct pthread *curthread, struct pthread_sigframe *psf)
+{
+ kse_critical_t crit;
+ struct kse *curkse;
+
+ THR_THREAD_LOCK(curthread, curthread);
+ psf->psf_cancelflags = curthread->cancelflags;
+ crit = _kse_critical_enter();
+ curkse = curthread->kse;
+ KSE_SCHED_LOCK(curkse, curthread->kseg);
+ /* This has to initialize all members of the sigframe. */
+ psf->psf_flags = (curthread->flags & (THR_FLAGS_PRIVATE | THR_FLAGS_EXITING));
+ psf->psf_interrupted = curthread->interrupted;
+ psf->psf_timeout = curthread->timeout;
+ psf->psf_wait_data = curthread->data;
+ psf->psf_wakeup_time = curthread->wakeup_time;
+ psf->psf_continuation = curthread->continuation;
+ KSE_SCHED_UNLOCK(curkse, curthread->kseg);
+ _kse_critical_leave(crit);
+ THR_THREAD_UNLOCK(curthread, curthread);
+}
+
+void
+_thr_signal_init(void)
+{
+ struct sigaction act;
+ __siginfohandler_t *sigfunc;
+ int i;
+ sigset_t sigset;
+
+ SIGFILLSET(sigset);
+ __sys_sigprocmask(SIG_SETMASK, &sigset, &_thr_initial->sigmask);
+ /* Enter a loop to get the existing signal status: */
+ for (i = 1; i <= _SIG_MAXSIG; i++) {
+ /* Get the signal handler details: */
+ if (__sys_sigaction(i, NULL, &_thread_sigact[i - 1]) != 0) {
+ /*
+ * Abort this process if signal
+ * initialisation fails:
+ */
+ PANIC("Cannot read signal handler info");
+ }
+ /* Intall wrapper if handler was set */
+ sigfunc = _thread_sigact[i - 1].sa_sigaction;
+ if (((__sighandler_t *)sigfunc) != SIG_DFL &&
+ ((__sighandler_t *)sigfunc) != SIG_IGN) {
+ act = _thread_sigact[i - 1];
+ act.sa_flags |= SA_SIGINFO;
+ act.sa_sigaction =
+ (__siginfohandler_t *)_thr_sig_handler;
+ __sys_sigaction(i, &act, NULL);
+ }
+ }
+ if (_thr_dump_enabled()) {
+ /*
+ * Install the signal handler for SIGINFO. It isn't
+ * really needed, but it is nice to have for debugging
+ * purposes.
+ */
+ _thread_sigact[SIGINFO - 1].sa_flags = SA_SIGINFO | SA_RESTART;
+ SIGEMPTYSET(act.sa_mask);
+ act.sa_flags = SA_SIGINFO | SA_RESTART;
+ act.sa_sigaction = (__siginfohandler_t *)&_thr_sig_handler;
+ if (__sys_sigaction(SIGINFO, &act, NULL) != 0) {
+ __sys_sigprocmask(SIG_SETMASK, &_thr_initial->sigmask,
+ NULL);
+ /*
+ * Abort this process if signal initialisation fails:
+ */
+ PANIC("Cannot initialize signal handler");
+ }
+ }
+ __sys_sigprocmask(SIG_SETMASK, &_thr_initial->sigmask, NULL);
+ __sys_sigaltstack(NULL, &_thr_initial->sigstk);
+}
+
+void
+_thr_signal_deinit(void)
+{
+ int i;
+ struct pthread *curthread = _get_curthread();
+
+ /* Clear process pending signals. */
+ sigemptyset(&_thr_proc_sigpending);
+
+ /* Enter a loop to get the existing signal status: */
+ for (i = 1; i <= _SIG_MAXSIG; i++) {
+ /* Check for signals which cannot be trapped: */
+ if (i == SIGKILL || i == SIGSTOP) {
+ }
+
+ /* Set the signal handler details: */
+ else if (__sys_sigaction(i, &_thread_sigact[i - 1],
+ NULL) != 0) {
+ /*
+ * Abort this process if signal
+ * initialisation fails:
+ */
+ PANIC("Cannot set signal handler info");
+ }
+ }
+ __sys_sigaltstack(&curthread->sigstk, NULL);
+}
+
diff --git a/lib/libpthread/thread/thr_sigaction.c b/lib/libpthread/thread/thr_sigaction.c
new file mode 100644
index 0000000..7ee0ce6
--- /dev/null
+++ b/lib/libpthread/thread/thr_sigaction.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <signal.h>
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_sigaction);
+LT10_COMPAT_DEFAULT(sigaction);
+
+__weak_reference(_sigaction, sigaction);
+
+int
+_sigaction(int sig, const struct sigaction * act, struct sigaction * oact)
+{
+ int ret = 0;
+ int err = 0;
+ struct sigaction newact, oldact;
+ struct pthread *curthread;
+ kse_critical_t crit;
+
+ /* Check if the signal number is out of range: */
+ if (sig < 1 || sig > _SIG_MAXSIG) {
+ /* Return an invalid argument: */
+ errno = EINVAL;
+ ret = -1;
+ } else {
+ if (act)
+ newact = *act;
+
+ crit = _kse_critical_enter();
+ curthread = _get_curthread();
+ KSE_LOCK_ACQUIRE(curthread->kse, &_thread_signal_lock);
+
+ oldact = _thread_sigact[sig - 1];
+
+ /* Check if a signal action was supplied: */
+ if (act != NULL) {
+ /* Set the new signal handler: */
+ _thread_sigact[sig - 1] = newact;
+ }
+
+ /*
+ * Check if the kernel needs to be advised of a change
+ * in signal action:
+ */
+ if (act != NULL && sig != SIGINFO) {
+
+ newact.sa_flags |= SA_SIGINFO;
+
+ /*
+ * Check if the signal handler is being set to
+ * the default or ignore handlers:
+ */
+ if (newact.sa_handler != SIG_DFL &&
+ newact.sa_handler != SIG_IGN) {
+ /*
+ * Specify the thread kernel signal
+ * handler:
+ */
+ newact.sa_handler = (void (*) ())_thr_sig_handler;
+ }
+ /* Change the signal action in the kernel: */
+ if (__sys_sigaction(sig, &newact, NULL) != 0) {
+ _thread_sigact[sig - 1] = oldact;
+ /* errno is in kse, will copy it to thread */
+ err = errno;
+ ret = -1;
+ }
+ }
+ KSE_LOCK_RELEASE(curthread->kse, &_thread_signal_lock);
+ _kse_critical_leave(crit);
+ /*
+ * Check if the existing signal action structure contents are
+ * to be returned:
+ */
+ if (oact != NULL) {
+ /* Return the existing signal action contents: */
+ *oact = oldact;
+ }
+ if (ret != 0) {
+ /* Return errno to thread */
+ errno = err;
+ }
+ }
+
+ /* Return the completion status: */
+ return (ret);
+}
diff --git a/lib/libpthread/thread/thr_sigaltstack.c b/lib/libpthread/thread/thr_sigaltstack.c
new file mode 100644
index 0000000..8ebbdee
--- /dev/null
+++ b/lib/libpthread/thread/thr_sigaltstack.c
@@ -0,0 +1,110 @@
+/*-
+ * Copyright (c) 2003 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <signal.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_sigaltstack);
+LT10_COMPAT_DEFAULT(sigaltstack);
+
+__weak_reference(_sigaltstack, sigaltstack);
+
+int
+_sigaltstack(stack_t *_ss, stack_t *_oss)
+{
+ struct pthread *curthread = _get_curthread();
+ stack_t ss, oss;
+ int oonstack, errsave, ret;
+ kse_critical_t crit;
+
+ if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) {
+ crit = _kse_critical_enter();
+ ret = __sys_sigaltstack(_ss, _oss);
+ errsave = errno;
+ /* Get a copy */
+ if (ret == 0 && _ss != NULL)
+ curthread->sigstk = *_ss;
+ _kse_critical_leave(crit);
+ errno = errsave;
+ return (ret);
+ }
+
+ if (_ss)
+ ss = *_ss;
+ if (_oss)
+ oss = *_oss;
+
+ /* Should get and set stack in atomic way */
+ crit = _kse_critical_enter();
+ oonstack = _thr_sigonstack(&ss);
+ if (_oss != NULL) {
+ oss = curthread->sigstk;
+ oss.ss_flags = (curthread->sigstk.ss_flags & SS_DISABLE)
+ ? SS_DISABLE : ((oonstack) ? SS_ONSTACK : 0);
+ }
+
+ if (_ss != NULL) {
+ if (oonstack) {
+ _kse_critical_leave(crit);
+ errno = EPERM;
+ return (-1);
+ }
+ if ((ss.ss_flags & ~SS_DISABLE) != 0) {
+ _kse_critical_leave(crit);
+ errno = EINVAL;
+ return (-1);
+ }
+ if (!(ss.ss_flags & SS_DISABLE)) {
+ if (ss.ss_size < MINSIGSTKSZ) {
+ _kse_critical_leave(crit);
+ errno = ENOMEM;
+ return (-1);
+ }
+ curthread->sigstk = ss;
+ } else {
+ curthread->sigstk.ss_flags |= SS_DISABLE;
+ }
+ }
+ _kse_critical_leave(crit);
+ if (_oss != NULL)
+ *_oss = oss;
+ return (0);
+}
+
+int
+_thr_sigonstack(void *sp)
+{
+ struct pthread *curthread = _get_curthread();
+
+ return ((curthread->sigstk.ss_flags & SS_DISABLE) == 0 ?
+ (((size_t)sp - (size_t)curthread->sigstk.ss_sp) < curthread->sigstk.ss_size)
+ : 0);
+}
+
diff --git a/lib/libpthread/thread/thr_sigmask.c b/lib/libpthread/thread/thr_sigmask.c
new file mode 100644
index 0000000..05f5ae1
--- /dev/null
+++ b/lib/libpthread/thread/thr_sigmask.c
@@ -0,0 +1,116 @@
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/signalvar.h>
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_sigmask);
+LT10_COMPAT_DEFAULT(pthread_sigmask);
+
+__weak_reference(_pthread_sigmask, pthread_sigmask);
+
+int
+_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
+{
+ struct pthread *curthread = _get_curthread();
+ sigset_t oldset, newset;
+ int ret;
+
+ if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) {
+ ret = __sys_sigprocmask(how, set, oset);
+ if (ret != 0)
+ ret = errno;
+ /* Get a fresh copy */
+ __sys_sigprocmask(SIG_SETMASK, NULL, &curthread->sigmask);
+ return (ret);
+ }
+
+ if (set)
+ newset = *set;
+
+ THR_SCHED_LOCK(curthread, curthread);
+
+ ret = 0;
+ if (oset != NULL)
+ /* Return the current mask: */
+ oldset = curthread->sigmask;
+
+ /* Check if a new signal set was provided by the caller: */
+ if (set != NULL) {
+ /* Process according to what to do: */
+ switch (how) {
+ /* Block signals: */
+ case SIG_BLOCK:
+ /* Add signals to the existing mask: */
+ SIGSETOR(curthread->sigmask, newset);
+ break;
+
+ /* Unblock signals: */
+ case SIG_UNBLOCK:
+ /* Clear signals from the existing mask: */
+ SIGSETNAND(curthread->sigmask, newset);
+ break;
+
+ /* Set the signal process mask: */
+ case SIG_SETMASK:
+ /* Set the new mask: */
+ curthread->sigmask = newset;
+ break;
+
+ /* Trap invalid actions: */
+ default:
+ /* Return an invalid argument: */
+ ret = EINVAL;
+ break;
+ }
+ SIG_CANTMASK(curthread->sigmask);
+ THR_SCHED_UNLOCK(curthread, curthread);
+
+ /*
+ * Run down any pending signals:
+ */
+ if (ret == 0)
+ _thr_sig_check_pending(curthread);
+ } else
+ THR_SCHED_UNLOCK(curthread, curthread);
+
+ if (ret == 0 && oset != NULL)
+ *oset = oldset;
+ return (ret);
+}
diff --git a/lib/libpthread/thread/thr_sigpending.c b/lib/libpthread/thread/thr_sigpending.c
new file mode 100644
index 0000000..5c666bf
--- /dev/null
+++ b/lib/libpthread/thread/thr_sigpending.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 1999 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/signalvar.h>
+#include <signal.h>
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_sigpending);
+LT10_COMPAT_DEFAULT(sigpending);
+
+__weak_reference(_sigpending, sigpending);
+
+int
+_sigpending(sigset_t *set)
+{
+ struct pthread *curthread = _get_curthread();
+ kse_critical_t crit;
+ sigset_t sigset;
+ int ret = 0;
+
+ /* Check for a null signal set pointer: */
+ if (set == NULL) {
+ /* Return an invalid argument: */
+ ret = EINVAL;
+ }
+ else {
+ if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
+ return (__sys_sigpending(set));
+
+ crit = _kse_critical_enter();
+ KSE_SCHED_LOCK(curthread->kse, curthread->kseg);
+ sigset = curthread->sigpend;
+ KSE_SCHED_UNLOCK(curthread->kse, curthread->kseg);
+ KSE_LOCK_ACQUIRE(curthread->kse, &_thread_signal_lock);
+ SIGSETOR(sigset, _thr_proc_sigpending);
+ KSE_LOCK_RELEASE(curthread->kse, &_thread_signal_lock);
+ _kse_critical_leave(crit);
+ *set = sigset;
+ }
+ /* Return the completion status: */
+ return (ret);
+}
diff --git a/lib/libpthread/thread/thr_sigprocmask.c b/lib/libpthread/thread/thr_sigprocmask.c
new file mode 100644
index 0000000..d2a20dd
--- /dev/null
+++ b/lib/libpthread/thread/thr_sigprocmask.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/signalvar.h>
+#include <signal.h>
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_sigprocmask);
+LT10_COMPAT_DEFAULT(sigprocmask);
+
+__weak_reference(_sigprocmask, sigprocmask);
+
+int
+_sigprocmask(int how, const sigset_t *set, sigset_t *oset)
+{
+ int ret;
+
+ ret = pthread_sigmask(how, set, oset);
+ if (ret) {
+ errno = ret;
+ ret = -1;
+ }
+ return (ret);
+}
diff --git a/lib/libpthread/thread/thr_sigsuspend.c b/lib/libpthread/thread/thr_sigsuspend.c
new file mode 100644
index 0000000..2f3ed5d
--- /dev/null
+++ b/lib/libpthread/thread/thr_sigsuspend.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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/signalvar.h>
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <string.h>
+
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__sigsuspend);
+LT10_COMPAT_PRIVATE(_sigsuspend);
+LT10_COMPAT_DEFAULT(sigsuspend);
+
+__weak_reference(__sigsuspend, sigsuspend);
+
+int
+_sigsuspend(const sigset_t *set)
+{
+ struct pthread *curthread = _get_curthread();
+ sigset_t oldmask, newmask, tempset;
+ int ret = -1;
+
+ if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
+ return (__sys_sigsuspend(set));
+
+ /* Check if a new signal set was provided by the caller: */
+ if (set != NULL) {
+ newmask = *set;
+ SIG_CANTMASK(newmask);
+ THR_LOCK_SWITCH(curthread);
+
+ /* Save current sigmask: */
+ oldmask = curthread->sigmask;
+ curthread->oldsigmask = &oldmask;
+
+ /* Change the caller's mask: */
+ curthread->sigmask = newmask;
+ tempset = curthread->sigpend;
+ SIGSETNAND(tempset, newmask);
+ if (SIGISEMPTY(tempset)) {
+ THR_SET_STATE(curthread, PS_SIGSUSPEND);
+ /* Wait for a signal: */
+ _thr_sched_switch_unlocked(curthread);
+ } else {
+ curthread->check_pending = 1;
+ THR_UNLOCK_SWITCH(curthread);
+ /* check pending signal I can handle: */
+ _thr_sig_check_pending(curthread);
+ }
+ if ((curthread->cancelflags & THR_CANCELLING) != 0)
+ curthread->oldsigmask = NULL;
+ else {
+ THR_ASSERT(curthread->oldsigmask == NULL,
+ "oldsigmask is not cleared");
+ }
+
+ /* Always return an interrupted error: */
+ errno = EINTR;
+ } else {
+ /* Return an invalid argument error: */
+ errno = EINVAL;
+ }
+
+ /* Return the completion status: */
+ return (ret);
+}
+
+int
+__sigsuspend(const sigset_t * set)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ _thr_cancel_enter(curthread);
+ ret = _sigsuspend(set);
+ _thr_cancel_leave(curthread, 1);
+
+ return (ret);
+}
diff --git a/lib/libpthread/thread/thr_sigwait.c b/lib/libpthread/thread/thr_sigwait.c
new file mode 100644
index 0000000..cd7ac22
--- /dev/null
+++ b/lib/libpthread/thread/thr_sigwait.c
@@ -0,0 +1,212 @@
+//depot/projects/kse/lib/libpthread/thread/thr_sigwait.c#1 - branch change 15154 (text+ko)
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <signal.h>
+#include <sys/param.h>
+#include <sys/signalvar.h>
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__sigwait);
+LT10_COMPAT_PRIVATE(_sigwait);
+LT10_COMPAT_DEFAULT(sigwait);
+LT10_COMPAT_PRIVATE(__sigtimedwait);
+LT10_COMPAT_PRIVATE(_sigtimedwait);
+LT10_COMPAT_DEFAULT(sigtimedwait);
+LT10_COMPAT_PRIVATE(__sigwaitinfo);
+LT10_COMPAT_PRIVATE(_sigwaitinfo);
+LT10_COMPAT_DEFAULT(sigwaitinfo);
+
+__weak_reference(__sigwait, sigwait);
+__weak_reference(__sigtimedwait, sigtimedwait);
+__weak_reference(__sigwaitinfo, sigwaitinfo);
+
+static int
+lib_sigtimedwait(const sigset_t *set, siginfo_t *info,
+ const struct timespec * timeout)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret = 0;
+ int i;
+ struct sigwait_data waitdata;
+ sigset_t waitset;
+ kse_critical_t crit;
+ siginfo_t siginfo;
+
+ if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) {
+ if (info == NULL)
+ info = &siginfo;
+ return (__sys_sigtimedwait((sigset_t *)set, info,
+ (struct timespec *)timeout));
+ }
+
+ /*
+ * Initialize the set of signals that will be waited on:
+ */
+ waitset = *set;
+
+ /* These signals can't be waited on. */
+ SIGDELSET(waitset, SIGKILL);
+ SIGDELSET(waitset, SIGSTOP);
+
+ /*
+ * POSIX says that the _application_ must explicitly install
+ * a dummy handler for signals that are SIG_IGN in order
+ * to sigwait on them. Note that SIG_IGN signals are left in
+ * the mask because a subsequent sigaction could enable an
+ * ignored signal.
+ */
+
+ crit = _kse_critical_enter();
+ KSE_SCHED_LOCK(curthread->kse, curthread->kseg);
+ for (i = 1; i <= _SIG_MAXSIG; ++i) {
+ if (SIGISMEMBER(waitset, i) &&
+ SIGISMEMBER(curthread->sigpend, i)) {
+ SIGDELSET(curthread->sigpend, i);
+ siginfo = curthread->siginfo[i - 1];
+ KSE_SCHED_UNLOCK(curthread->kse,
+ curthread->kseg);
+ _kse_critical_leave(crit);
+ ret = i;
+ goto OUT;
+ }
+ }
+ curthread->timeout = 0;
+ curthread->interrupted = 0;
+ _thr_set_timeout(timeout);
+ /* Wait for a signal: */
+ siginfo.si_signo = 0;
+ waitdata.waitset = &waitset;
+ waitdata.siginfo = &siginfo;
+ curthread->data.sigwait = &waitdata;
+ THR_SET_STATE(curthread, PS_SIGWAIT);
+ _thr_sched_switch_unlocked(curthread);
+ /*
+ * Return the signal number to the caller:
+ */
+ if (siginfo.si_signo > 0) {
+ ret = siginfo.si_signo;
+ } else {
+ if (curthread->interrupted)
+ errno = EINTR;
+ else if (curthread->timeout)
+ errno = EAGAIN;
+ ret = -1;
+ }
+ curthread->timeout = 0;
+ curthread->interrupted = 0;
+ /*
+ * Probably unnecessary, but since it's in a union struct
+ * we don't know how it could be used in the future.
+ */
+ curthread->data.sigwait = NULL;
+
+OUT:
+ if (ret > 0 && info != NULL)
+ *info = siginfo;
+
+ return (ret);
+}
+
+int
+__sigtimedwait(const sigset_t *set, siginfo_t *info,
+ const struct timespec * timeout)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ _thr_cancel_enter(curthread);
+ ret = lib_sigtimedwait(set, info, timeout);
+ _thr_cancel_leave(curthread, 1);
+ return (ret);
+}
+
+int _sigtimedwait(const sigset_t *set, siginfo_t *info,
+ const struct timespec * timeout)
+{
+ return lib_sigtimedwait(set, info, timeout);
+}
+
+int
+__sigwaitinfo(const sigset_t *set, siginfo_t *info)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ _thr_cancel_enter(curthread);
+ ret = lib_sigtimedwait(set, info, NULL);
+ _thr_cancel_leave(curthread, 1);
+ return (ret);
+}
+
+int
+_sigwaitinfo(const sigset_t *set, siginfo_t *info)
+{
+ return lib_sigtimedwait(set, info, NULL);
+}
+
+int
+__sigwait(const sigset_t *set, int *sig)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ _thr_cancel_enter(curthread);
+ ret = lib_sigtimedwait(set, NULL, NULL);
+ if (ret > 0) {
+ *sig = ret;
+ ret = 0;
+ } else {
+ ret = errno;
+ }
+ _thr_cancel_leave(curthread, 1);
+ return (ret);
+}
+
+int
+_sigwait(const sigset_t *set, int *sig)
+{
+ int ret;
+
+ ret = lib_sigtimedwait(set, NULL, NULL);
+ if (ret > 0) {
+ *sig = ret;
+ ret = 0;
+ } else {
+ ret = errno;
+ }
+ return (ret);
+}
+
diff --git a/lib/libpthread/thread/thr_single_np.c b/lib/libpthread/thread/thr_single_np.c
new file mode 100644
index 0000000..882f6aa
--- /dev/null
+++ b/lib/libpthread/thread/thr_single_np.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1996 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <pthread_np.h>
+
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_single_np);
+LT10_COMPAT_DEFAULT(pthread_single_np);
+
+__weak_reference(_pthread_single_np, pthread_single_np);
+
+int _pthread_single_np()
+{
+
+ /* Enter single-threaded (non-POSIX) scheduling mode: */
+ pthread_suspend_all_np();
+ /*
+ * XXX - Do we want to do this?
+ * __is_threaded = 0;
+ */
+ return (0);
+}
diff --git a/lib/libpthread/thread/thr_sleep.c b/lib/libpthread/thread/thr_sleep.c
new file mode 100644
index 0000000..0a11876
--- /dev/null
+++ b/lib/libpthread/thread/thr_sleep.c
@@ -0,0 +1,71 @@
+/*
+ * 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$
+ */
+
+#include <unistd.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+extern unsigned int __sleep(unsigned int);
+extern int __usleep(useconds_t);
+
+LT10_COMPAT_PRIVATE(_sleep);
+LT10_COMPAT_DEFAULT(sleep);
+LT10_COMPAT_PRIVATE(_usleep);
+LT10_COMPAT_DEFAULT(usleep);
+
+__weak_reference(_sleep, sleep);
+__weak_reference(_usleep, usleep);
+
+unsigned int
+_sleep(unsigned int seconds)
+{
+ struct pthread *curthread = _get_curthread();
+ unsigned int ret;
+
+ _thr_cancel_enter(curthread);
+ ret = __sleep(seconds);
+ _thr_cancel_leave(curthread, 1);
+
+ return (ret);
+}
+
+int
+_usleep(useconds_t useconds)
+{
+ struct pthread *curthread = _get_curthread();
+ unsigned int ret;
+
+ _thr_cancel_enter(curthread);
+ ret = __usleep(useconds);
+ _thr_cancel_leave(curthread, 1);
+
+ return (ret);
+}
diff --git a/lib/libpthread/thread/thr_spec.c b/lib/libpthread/thread/thr_spec.c
new file mode 100644
index 0000000..f6e8861
--- /dev/null
+++ b/lib/libpthread/thread/thr_spec.c
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <pthread.h>
+
+#include "thr_private.h"
+
+
+struct pthread_key _thread_keytable[PTHREAD_KEYS_MAX];
+
+/*
+ * XXX - This breaks the linker if LT10_COMPAT_DEFAULT doesn't
+ * also include a weak reference to the default symbol.
+ */
+LT10_COMPAT_PRIVATE(_thread_keytable);
+
+LT10_COMPAT_PRIVATE(_pthread_key_create);
+LT10_COMPAT_DEFAULT(pthread_key_create);
+LT10_COMPAT_PRIVATE(_pthread_key_delete);
+LT10_COMPAT_DEFAULT(pthread_key_delete);
+LT10_COMPAT_PRIVATE(_pthread_getspecific);
+LT10_COMPAT_DEFAULT(pthread_getspecific);
+LT10_COMPAT_PRIVATE(_pthread_setspecific);
+LT10_COMPAT_DEFAULT(pthread_setspecific);
+
+__weak_reference(_pthread_key_create, pthread_key_create);
+__weak_reference(_pthread_key_delete, pthread_key_delete);
+__weak_reference(_pthread_getspecific, pthread_getspecific);
+__weak_reference(_pthread_setspecific, pthread_setspecific);
+
+
+int
+_pthread_key_create(pthread_key_t *key, void (*destructor) (void *))
+{
+ struct pthread *curthread = _get_curthread();
+ int i;
+
+ /* Lock the key table: */
+ THR_LOCK_ACQUIRE(curthread, &_keytable_lock);
+ for (i = 0; i < PTHREAD_KEYS_MAX; i++) {
+
+ if (_thread_keytable[i].allocated == 0) {
+ _thread_keytable[i].allocated = 1;
+ _thread_keytable[i].destructor = destructor;
+ _thread_keytable[i].seqno++;
+
+ /* Unlock the key table: */
+ THR_LOCK_RELEASE(curthread, &_keytable_lock);
+ *key = i;
+ return (0);
+ }
+
+ }
+ /* Unlock the key table: */
+ THR_LOCK_RELEASE(curthread, &_keytable_lock);
+ return (EAGAIN);
+}
+
+int
+_pthread_key_delete(pthread_key_t key)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret = 0;
+
+ if ((unsigned int)key < PTHREAD_KEYS_MAX) {
+ /* Lock the key table: */
+ THR_LOCK_ACQUIRE(curthread, &_keytable_lock);
+
+ if (_thread_keytable[key].allocated)
+ _thread_keytable[key].allocated = 0;
+ else
+ ret = EINVAL;
+
+ /* Unlock the key table: */
+ THR_LOCK_RELEASE(curthread, &_keytable_lock);
+ } else
+ ret = EINVAL;
+ return (ret);
+}
+
+void
+_thread_cleanupspecific(void)
+{
+ struct pthread *curthread = _get_curthread();
+ void (*destructor)( void *);
+ void *data = NULL;
+ int key;
+ int i;
+
+ if (curthread->specific == NULL)
+ return;
+
+ /* Lock the key table: */
+ THR_LOCK_ACQUIRE(curthread, &_keytable_lock);
+ for (i = 0; (i < PTHREAD_DESTRUCTOR_ITERATIONS) &&
+ (curthread->specific_data_count > 0); i++) {
+ for (key = 0; (key < PTHREAD_KEYS_MAX) &&
+ (curthread->specific_data_count > 0); key++) {
+ destructor = NULL;
+
+ if (_thread_keytable[key].allocated &&
+ (curthread->specific[key].data != NULL)) {
+ if (curthread->specific[key].seqno ==
+ _thread_keytable[key].seqno) {
+ data = (void *)
+ curthread->specific[key].data;
+ destructor = _thread_keytable[key].destructor;
+ }
+ curthread->specific[key].data = NULL;
+ curthread->specific_data_count--;
+ }
+
+ /*
+ * If there is a destructore, call it
+ * with the key table entry unlocked:
+ */
+ if (destructor != NULL) {
+ /*
+ * Don't hold the lock while calling the
+ * destructor:
+ */
+ THR_LOCK_RELEASE(curthread, &_keytable_lock);
+ destructor(data);
+ THR_LOCK_ACQUIRE(curthread, &_keytable_lock);
+ }
+ }
+ }
+ THR_LOCK_RELEASE(curthread, &_keytable_lock);
+ free(curthread->specific);
+ curthread->specific = NULL;
+ if (curthread->specific_data_count > 0)
+ stderr_debug("Thread %p has exited with leftover "
+ "thread-specific data after %d destructor iterations\n",
+ curthread, PTHREAD_DESTRUCTOR_ITERATIONS);
+}
+
+static inline struct pthread_specific_elem *
+pthread_key_allocate_data(void)
+{
+ struct pthread_specific_elem *new_data;
+
+ new_data = (struct pthread_specific_elem *)
+ malloc(sizeof(struct pthread_specific_elem) * PTHREAD_KEYS_MAX);
+ if (new_data != NULL) {
+ memset((void *) new_data, 0,
+ sizeof(struct pthread_specific_elem) * PTHREAD_KEYS_MAX);
+ }
+ return (new_data);
+}
+
+int
+_pthread_setspecific(pthread_key_t key, const void *value)
+{
+ struct pthread *pthread;
+ int ret = 0;
+
+ /* Point to the running thread: */
+ pthread = _get_curthread();
+
+ if ((pthread->specific) ||
+ (pthread->specific = pthread_key_allocate_data())) {
+ if ((unsigned int)key < PTHREAD_KEYS_MAX) {
+ if (_thread_keytable[key].allocated) {
+ if (pthread->specific[key].data == NULL) {
+ if (value != NULL)
+ pthread->specific_data_count++;
+ } else if (value == NULL)
+ pthread->specific_data_count--;
+ pthread->specific[key].data = value;
+ pthread->specific[key].seqno =
+ _thread_keytable[key].seqno;
+ ret = 0;
+ } else
+ ret = EINVAL;
+ } else
+ ret = EINVAL;
+ } else
+ ret = ENOMEM;
+ return (ret);
+}
+
+void *
+_pthread_getspecific(pthread_key_t key)
+{
+ struct pthread *pthread;
+ void *data;
+
+ /* Point to the running thread: */
+ pthread = _get_curthread();
+
+ /* Check if there is specific data: */
+ if (pthread->specific != NULL && (unsigned int)key < PTHREAD_KEYS_MAX) {
+ /* Check if this key has been used before: */
+ if (_thread_keytable[key].allocated &&
+ (pthread->specific[key].seqno == _thread_keytable[key].seqno)) {
+ /* Return the value: */
+ data = (void *) pthread->specific[key].data;
+ } else {
+ /*
+ * This key has not been used before, so return NULL
+ * instead:
+ */
+ data = NULL;
+ }
+ } else
+ /* No specific data has been created, so just return NULL: */
+ data = NULL;
+ return (data);
+}
diff --git a/lib/libpthread/thread/thr_spinlock.c b/lib/libpthread/thread/thr_spinlock.c
new file mode 100644
index 0000000..d187439
--- /dev/null
+++ b/lib/libpthread/thread/thr_spinlock.c
@@ -0,0 +1,152 @@
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <machine/atomic.h>
+
+#include <libc_private.h>
+#include "spinlock.h"
+#include "thr_private.h"
+
+#define MAX_SPINLOCKS 72
+
+struct spinlock_extra {
+ spinlock_t *owner;
+ pthread_mutex_t lock;
+};
+
+static void init_spinlock(spinlock_t *lck);
+
+static struct pthread_mutex_attr static_mutex_attr =
+ PTHREAD_MUTEXATTR_STATIC_INITIALIZER;
+static pthread_mutexattr_t static_mattr = &static_mutex_attr;
+
+static pthread_mutex_t spinlock_static_lock;
+static struct spinlock_extra extra[MAX_SPINLOCKS];
+static int spinlock_count = 0;
+static int initialized = 0;
+
+LT10_COMPAT_PRIVATE(_spinlock);
+LT10_COMPAT_PRIVATE(_spinlock_debug);
+LT10_COMPAT_PRIVATE(_spinunlock);
+
+/*
+ * These are for compatability only. Spinlocks of this type
+ * are deprecated.
+ */
+
+void
+_spinunlock(spinlock_t *lck)
+{
+ struct spinlock_extra *extra;
+
+ extra = (struct spinlock_extra *)lck->fname;
+ _pthread_mutex_unlock(&extra->lock);
+}
+
+/*
+ * Lock a location for the running thread. Yield to allow other
+ * threads to run if this thread is blocked because the lock is
+ * not available. Note that this function does not sleep. It
+ * assumes that the lock will be available very soon.
+ */
+void
+_spinlock(spinlock_t *lck)
+{
+ struct spinlock_extra *extra;
+
+ if (!__isthreaded)
+ PANIC("Spinlock called when not threaded.");
+ if (!initialized)
+ PANIC("Spinlocks not initialized.");
+ /*
+ * Try to grab the lock and loop if another thread grabs
+ * it before we do.
+ */
+ if (lck->fname == NULL)
+ init_spinlock(lck);
+ extra = (struct spinlock_extra *)lck->fname;
+ _pthread_mutex_lock(&extra->lock);
+}
+
+/*
+ * Lock a location for the running thread. Yield to allow other
+ * threads to run if this thread is blocked because the lock is
+ * not available. Note that this function does not sleep. It
+ * assumes that the lock will be available very soon.
+ *
+ * This function checks if the running thread has already locked the
+ * location, warns if this occurs and creates a thread dump before
+ * returning.
+ */
+void
+_spinlock_debug(spinlock_t *lck, char *fname, int lineno)
+{
+ _spinlock(lck);
+}
+
+static void
+init_spinlock(spinlock_t *lck)
+{
+ _pthread_mutex_lock(&spinlock_static_lock);
+ if ((lck->fname == NULL) && (spinlock_count < MAX_SPINLOCKS)) {
+ lck->fname = (char *)&extra[spinlock_count];
+ extra[spinlock_count].owner = lck;
+ spinlock_count++;
+ }
+ _pthread_mutex_unlock(&spinlock_static_lock);
+ if (lck->fname == NULL)
+ PANIC("Exceeded max spinlocks");
+}
+
+void
+_thr_spinlock_init(void)
+{
+ int i;
+
+ if (initialized != 0) {
+ _thr_mutex_reinit(&spinlock_static_lock);
+ for (i = 0; i < spinlock_count; i++)
+ _thr_mutex_reinit(&extra[i].lock);
+ } else {
+ if (_pthread_mutex_init(&spinlock_static_lock, &static_mattr))
+ PANIC("Cannot initialize spinlock_static_lock");
+ for (i = 0; i < MAX_SPINLOCKS; i++) {
+ if (_pthread_mutex_init(&extra[i].lock, &static_mattr))
+ PANIC("Cannot initialize spinlock extra");
+ }
+ initialized = 1;
+ }
+}
diff --git a/lib/libpthread/thread/thr_stack.c b/lib/libpthread/thread/thr_stack.c
new file mode 100644
index 0000000..f634055
--- /dev/null
+++ b/lib/libpthread/thread/thr_stack.c
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2001 Daniel Eischen <deischen@freebsd.org>
+ * Copyright (c) 2000-2001 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, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/queue.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+/* Spare thread stack. */
+struct stack {
+ LIST_ENTRY(stack) qe; /* Stack queue linkage. */
+ size_t stacksize; /* Stack size (rounded up). */
+ size_t guardsize; /* Guard size. */
+ void *stackaddr; /* Stack address. */
+};
+
+/*
+ * Default sized (stack and guard) spare stack queue. Stacks are cached
+ * to avoid additional complexity managing mmap()ed stack regions. Spare
+ * stacks are used in LIFO order to increase cache locality.
+ */
+static LIST_HEAD(, stack) dstackq = LIST_HEAD_INITIALIZER(dstackq);
+
+/*
+ * Miscellaneous sized (non-default stack and/or guard) spare stack queue.
+ * Stacks are cached to avoid additional complexity managing mmap()ed
+ * stack regions. This list is unordered, since ordering on both stack
+ * size and guard size would be more trouble than it's worth. Stacks are
+ * allocated from this cache on a first size match basis.
+ */
+static LIST_HEAD(, stack) mstackq = LIST_HEAD_INITIALIZER(mstackq);
+
+/**
+ * Base address of the last stack allocated (including its red zone, if
+ * there is one). Stacks are allocated contiguously, starting beyond the
+ * top of the main stack. When a new stack is created, a red zone is
+ * typically created (actually, the red zone is mapped with PROT_NONE) above
+ * the top of the stack, such that the stack will not be able to grow all
+ * the way to the bottom of the next stack. This isn't fool-proof. It is
+ * possible for a stack to grow by a large amount, such that it grows into
+ * the next stack, and as long as the memory within the red zone is never
+ * accessed, nothing will prevent one thread stack from trouncing all over
+ * the next.
+ *
+ * low memory
+ * . . . . . . . . . . . . . . . . . .
+ * | |
+ * | stack 3 | start of 3rd thread stack
+ * +-----------------------------------+
+ * | |
+ * | Red Zone (guard page) | red zone for 2nd thread
+ * | |
+ * +-----------------------------------+
+ * | stack 2 - PTHREAD_STACK_DEFAULT | top of 2nd thread stack
+ * | |
+ * | |
+ * | |
+ * | |
+ * | stack 2 |
+ * +-----------------------------------+ <-- start of 2nd thread stack
+ * | |
+ * | Red Zone | red zone for 1st thread
+ * | |
+ * +-----------------------------------+
+ * | stack 1 - PTHREAD_STACK_DEFAULT | top of 1st thread stack
+ * | |
+ * | |
+ * | |
+ * | |
+ * | stack 1 |
+ * +-----------------------------------+ <-- start of 1st thread stack
+ * | | (initial value of last_stack)
+ * | Red Zone |
+ * | | red zone for main thread
+ * +-----------------------------------+
+ * | USRSTACK - PTHREAD_STACK_INITIAL | top of main thread stack
+ * | | ^
+ * | | |
+ * | | |
+ * | | | stack growth
+ * | |
+ * +-----------------------------------+ <-- start of main thread stack
+ * (USRSTACK)
+ * high memory
+ *
+ */
+static void *last_stack = NULL;
+
+/*
+ * Round size up to the nearest multiple of
+ * _thr_page_size.
+ */
+static inline size_t
+round_up(size_t size)
+{
+ if (size % _thr_page_size != 0)
+ size = ((size / _thr_page_size) + 1) *
+ _thr_page_size;
+ return size;
+}
+
+int
+_thr_stack_alloc(struct pthread_attr *attr)
+{
+ struct stack *spare_stack;
+ struct kse *curkse;
+ kse_critical_t crit;
+ size_t stacksize;
+ size_t guardsize;
+ char *stackaddr;
+
+ /*
+ * Round up stack size to nearest multiple of _thr_page_size so
+ * that mmap() * will work. If the stack size is not an even
+ * multiple, we end up initializing things such that there is
+ * unused space above the beginning of the stack, so the stack
+ * sits snugly against its guard.
+ */
+ stacksize = round_up(attr->stacksize_attr);
+ guardsize = round_up(attr->guardsize_attr);
+
+ attr->stackaddr_attr = NULL;
+ attr->flags &= ~THR_STACK_USER;
+
+ /*
+ * Use the garbage collector lock for synchronization of the
+ * spare stack lists and allocations from usrstack.
+ */
+ crit = _kse_critical_enter();
+ curkse = _get_curkse();
+ KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock);
+ /*
+ * If the stack and guard sizes are default, try to allocate a stack
+ * from the default-size stack cache:
+ */
+ if ((stacksize == _thr_stack_default) &&
+ (guardsize == _thr_guard_default)) {
+ if ((spare_stack = LIST_FIRST(&dstackq)) != NULL) {
+ /* Use the spare stack. */
+ LIST_REMOVE(spare_stack, qe);
+ attr->stackaddr_attr = spare_stack->stackaddr;
+ }
+ }
+ /*
+ * The user specified a non-default stack and/or guard size, so try to
+ * allocate a stack from the non-default size stack cache, using the
+ * rounded up stack size (stack_size) in the search:
+ */
+ else {
+ LIST_FOREACH(spare_stack, &mstackq, qe) {
+ if (spare_stack->stacksize == stacksize &&
+ spare_stack->guardsize == guardsize) {
+ LIST_REMOVE(spare_stack, qe);
+ attr->stackaddr_attr = spare_stack->stackaddr;
+ break;
+ }
+ }
+ }
+ if (attr->stackaddr_attr != NULL) {
+ /* A cached stack was found. Release the lock. */
+ KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
+ _kse_critical_leave(crit);
+ }
+ else {
+ /* Allocate a stack from usrstack. */
+ if (last_stack == NULL)
+ last_stack = _usrstack - _thr_stack_initial -
+ _thr_guard_default;
+
+ /* Allocate a new stack. */
+ stackaddr = last_stack - stacksize - guardsize;
+
+ /*
+ * Even if stack allocation fails, we don't want to try to
+ * use this location again, so unconditionally decrement
+ * last_stack. Under normal operating conditions, the most
+ * likely reason for an mmap() error is a stack overflow of
+ * the adjacent thread stack.
+ */
+ last_stack -= (stacksize + guardsize);
+
+ /* Release the lock before mmap'ing it. */
+ KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
+ _kse_critical_leave(crit);
+
+ /* Map the stack and guard page together, and split guard
+ page from allocated space: */
+ if ((stackaddr = mmap(stackaddr, stacksize+guardsize,
+ PROT_READ | PROT_WRITE, MAP_STACK,
+ -1, 0)) != MAP_FAILED &&
+ (guardsize == 0 ||
+ mprotect(stackaddr, guardsize, PROT_NONE) == 0)) {
+ stackaddr += guardsize;
+ } else {
+ if (stackaddr != MAP_FAILED)
+ munmap(stackaddr, stacksize + guardsize);
+ stackaddr = NULL;
+ }
+ attr->stackaddr_attr = stackaddr;
+ }
+ if (attr->stackaddr_attr != NULL)
+ return (0);
+ else
+ return (-1);
+}
+
+/* This function must be called with _thread_list_lock held. */
+void
+_thr_stack_free(struct pthread_attr *attr)
+{
+ struct stack *spare_stack;
+
+ if ((attr != NULL) && ((attr->flags & THR_STACK_USER) == 0)
+ && (attr->stackaddr_attr != NULL)) {
+ spare_stack = (attr->stackaddr_attr + attr->stacksize_attr
+ - sizeof(struct stack));
+ spare_stack->stacksize = round_up(attr->stacksize_attr);
+ spare_stack->guardsize = round_up(attr->guardsize_attr);
+ spare_stack->stackaddr = attr->stackaddr_attr;
+
+ if (spare_stack->stacksize == _thr_stack_default &&
+ spare_stack->guardsize == _thr_guard_default) {
+ /* Default stack/guard size. */
+ LIST_INSERT_HEAD(&dstackq, spare_stack, qe);
+ } else {
+ /* Non-default stack/guard size. */
+ LIST_INSERT_HEAD(&mstackq, spare_stack, qe);
+ }
+ attr->stackaddr_attr = NULL;
+ }
+}
diff --git a/lib/libpthread/thread/thr_suspend_np.c b/lib/libpthread/thread/thr_suspend_np.c
new file mode 100644
index 0000000..16c129c
--- /dev/null
+++ b/lib/libpthread/thread/thr_suspend_np.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+static void suspend_common(struct pthread *thread);
+
+LT10_COMPAT_PRIVATE(_pthread_suspend_np);
+LT10_COMPAT_DEFAULT(pthread_suspend_np);
+LT10_COMPAT_PRIVATE(_pthread_suspend_all_np);
+LT10_COMPAT_DEFAULT(pthread_suspend_all_np);
+
+__weak_reference(_pthread_suspend_np, pthread_suspend_np);
+__weak_reference(_pthread_suspend_all_np, pthread_suspend_all_np);
+
+/* Suspend a thread: */
+int
+_pthread_suspend_np(pthread_t thread)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ /* Suspending the current thread doesn't make sense. */
+ if (thread == _get_curthread())
+ ret = EDEADLK;
+
+ /* Add a reference to the thread: */
+ else if ((ret = _thr_ref_add(curthread, thread, /*include dead*/0))
+ == 0) {
+ /* Lock the threads scheduling queue: */
+ THR_SCHED_LOCK(curthread, thread);
+ suspend_common(thread);
+ /* Unlock the threads scheduling queue: */
+ THR_SCHED_UNLOCK(curthread, thread);
+
+ /* Don't forget to remove the reference: */
+ _thr_ref_delete(curthread, thread);
+ }
+ return (ret);
+}
+
+void
+_pthread_suspend_all_np(void)
+{
+ struct pthread *curthread = _get_curthread();
+ struct pthread *thread;
+ kse_critical_t crit;
+
+ /* Take the thread list lock: */
+ crit = _kse_critical_enter();
+ KSE_LOCK_ACQUIRE(curthread->kse, &_thread_list_lock);
+
+ TAILQ_FOREACH(thread, &_thread_list, tle) {
+ if (thread != curthread) {
+ THR_SCHED_LOCK(curthread, thread);
+ suspend_common(thread);
+ THR_SCHED_UNLOCK(curthread, thread);
+ }
+ }
+
+ /* Release the thread list lock: */
+ KSE_LOCK_RELEASE(curthread->kse, &_thread_list_lock);
+ _kse_critical_leave(crit);
+}
+
+void
+suspend_common(struct pthread *thread)
+{
+ if ((thread->state != PS_DEAD) &&
+ (thread->state != PS_DEADLOCK) &&
+ ((thread->flags & THR_FLAGS_EXITING) == 0)) {
+ thread->flags |= THR_FLAGS_SUSPENDED;
+ if ((thread->flags & THR_FLAGS_IN_RUNQ) != 0) {
+ THR_RUNQ_REMOVE(thread);
+ THR_SET_STATE(thread, PS_SUSPENDED);
+ }
+#ifdef NOT_YET
+ if ((thread->attr.flags & PTHREAD_SCOPE_SYSTEM) != 0)
+ /* ??? */
+#endif
+ }
+}
diff --git a/lib/libpthread/thread/thr_switch_np.c b/lib/libpthread/thread/thr_switch_np.c
new file mode 100644
index 0000000..247b879
--- /dev/null
+++ b/lib/libpthread/thread/thr_switch_np.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include <pthread_np.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_switch_add_np);
+LT10_COMPAT_DEFAULT(pthread_switch_add_np);
+LT10_COMPAT_PRIVATE(_pthread_switch_delete_np);
+LT10_COMPAT_DEFAULT(pthread_switch_delete_np);
+
+__weak_reference(_pthread_switch_add_np, pthread_switch_add_np);
+__weak_reference(_pthread_switch_delete_np, pthread_switch_delete_np);
+
+int
+_pthread_switch_add_np(pthread_switch_routine_t routine)
+{
+ return (ENOTSUP);
+}
+
+int
+_pthread_switch_delete_np(pthread_switch_routine_t routine)
+{
+ return (ENOTSUP);
+}
diff --git a/lib/libpthread/thread/thr_symbols.c b/lib/libpthread/thread/thr_symbols.c
new file mode 100644
index 0000000..2b9639b
--- /dev/null
+++ b/lib/libpthread/thread/thr_symbols.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2004 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <stddef.h>
+#include <pthread.h>
+#include <rtld.h>
+
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_thread_off_tcb);
+LT10_COMPAT_PRIVATE(_thread_off_tmbx);
+LT10_COMPAT_PRIVATE(_thread_off_next);
+LT10_COMPAT_PRIVATE(_thread_off_attr_flags);
+LT10_COMPAT_PRIVATE(_thread_off_kse);
+LT10_COMPAT_PRIVATE(_thread_off_kse_locklevel);
+LT10_COMPAT_PRIVATE(_thread_off_thr_locklevel);
+LT10_COMPAT_PRIVATE(_thread_off_linkmap);
+LT10_COMPAT_PRIVATE(_thread_off_tlsindex);
+LT10_COMPAT_PRIVATE(_thread_size_key);
+LT10_COMPAT_PRIVATE(_thread_off_key_allocated);
+LT10_COMPAT_PRIVATE(_thread_off_key_destructor);
+LT10_COMPAT_PRIVATE(_thread_max_keys);
+LT10_COMPAT_PRIVATE(_thread_off_dtv);
+LT10_COMPAT_PRIVATE(_thread_off_state);
+LT10_COMPAT_PRIVATE(_thread_state_running);
+LT10_COMPAT_PRIVATE(_thread_state_zoombie);
+
+/* A collection of symbols needed by debugger */
+
+/* int _libkse_debug */
+int _thread_off_tcb = offsetof(struct pthread, tcb);
+int _thread_off_tmbx = offsetof(struct tcb, tcb_tmbx);
+int _thread_off_next = offsetof(struct pthread, tle.tqe_next);
+int _thread_off_attr_flags = offsetof(struct pthread, attr.flags);
+int _thread_off_kse = offsetof(struct pthread, kse);
+int _thread_off_kse_locklevel = offsetof(struct kse, k_locklevel);
+int _thread_off_thr_locklevel = offsetof(struct pthread, locklevel);
+int _thread_off_linkmap = offsetof(Obj_Entry, linkmap);
+int _thread_off_tlsindex = offsetof(Obj_Entry, tlsindex);
+int _thread_size_key = sizeof(struct pthread_key);
+int _thread_off_key_allocated = offsetof(struct pthread_key, allocated);
+int _thread_off_key_destructor = offsetof(struct pthread_key, destructor);
+int _thread_max_keys = PTHREAD_KEYS_MAX;
+int _thread_off_dtv = DTV_OFFSET;
+int _thread_off_state = offsetof(struct pthread, state);
+int _thread_state_running = PS_RUNNING;
+int _thread_state_zoombie = PS_DEAD;
+int _thread_off_sigmask = offsetof(struct pthread, sigmask);
+int _thread_off_sigpend = offsetof(struct pthread, sigpend);
diff --git a/lib/libpthread/thread/thr_system.c b/lib/libpthread/thread/thr_system.c
new file mode 100644
index 0000000..5e4fe1c
--- /dev/null
+++ b/lib/libpthread/thread/thr_system.c
@@ -0,0 +1,54 @@
+/*
+ * 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$
+ */
+
+#include <stdlib.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+extern int __system(const char *);
+
+LT10_COMPAT_PRIVATE(_system);
+LT10_COMPAT_DEFAULT(system);
+
+__weak_reference(_system, system);
+
+int
+_system(const char *string)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ _thr_cancel_enter(curthread);
+ ret = __system(string);
+ _thr_cancel_leave(curthread, 1);
+
+ return ret;
+}
diff --git a/lib/libpthread/thread/thr_tcdrain.c b/lib/libpthread/thread/thr_tcdrain.c
new file mode 100644
index 0000000..e231d52
--- /dev/null
+++ b/lib/libpthread/thread/thr_tcdrain.c
@@ -0,0 +1,54 @@
+/*
+ * 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$
+ */
+
+#include <termios.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+extern int __tcdrain(int);
+
+LT10_COMPAT_PRIVATE(_tcdrain);
+LT10_COMPAT_DEFAULT(tcdrain);
+
+__weak_reference(_tcdrain, tcdrain);
+
+int
+_tcdrain(int fd)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ _thr_cancel_enter(curthread);
+ ret = __tcdrain(fd);
+ _thr_cancel_leave(curthread, 1);
+
+ return (ret);
+}
diff --git a/lib/libpthread/thread/thr_vfork.c b/lib/libpthread/thread/thr_vfork.c
new file mode 100644
index 0000000..428c129
--- /dev/null
+++ b/lib/libpthread/thread/thr_vfork.c
@@ -0,0 +1,17 @@
+/*
+ * $FreeBSD$
+ */
+#include <unistd.h>
+
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_vfork);
+LT10_COMPAT_DEFAULT(vfork);
+
+__weak_reference(_vfork, vfork);
+
+int
+_vfork(void)
+{
+ return (fork());
+}
diff --git a/lib/libpthread/thread/thr_wait.c b/lib/libpthread/thread/thr_wait.c
new file mode 100644
index 0000000..8f61a0c
--- /dev/null
+++ b/lib/libpthread/thread/thr_wait.c
@@ -0,0 +1,53 @@
+/*
+ * 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$
+ */
+
+#include <pthread.h>
+#include "thr_private.h"
+
+extern int __wait(int *);
+
+LT10_COMPAT_PRIVATE(_wait);
+LT10_COMPAT_DEFAULT(wait);
+
+__weak_reference(_wait, wait);
+
+pid_t
+_wait(int *istat)
+{
+ struct pthread *curthread = _get_curthread();
+ pid_t ret;
+
+ _thr_cancel_enter(curthread);
+ ret = __wait(istat);
+ _thr_cancel_leave(curthread, 1);
+
+ return ret;
+}
diff --git a/lib/libpthread/thread/thr_wait4.c b/lib/libpthread/thread/thr_wait4.c
new file mode 100644
index 0000000..fae0fed
--- /dev/null
+++ b/lib/libpthread/thread/thr_wait4.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 "namespace.h"
+#include <errno.h>
+#include <sys/wait.h>
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__wait4);
+LT10_COMPAT_DEFAULT(wait4);
+
+__weak_reference(__wait4, wait4);
+
+pid_t
+__wait4(pid_t pid, int *istat, int options, struct rusage *rusage)
+{
+ struct pthread *curthread = _get_curthread();
+ pid_t ret;
+
+ _thr_cancel_enter(curthread);
+ ret = _wait4(pid, istat, options, rusage);
+ _thr_cancel_leave(curthread, 1);
+
+ return ret;
+}
diff --git a/lib/libpthread/thread/thr_waitpid.c b/lib/libpthread/thread/thr_waitpid.c
new file mode 100644
index 0000000..1244c12
--- /dev/null
+++ b/lib/libpthread/thread/thr_waitpid.c
@@ -0,0 +1,55 @@
+/*
+ * 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$
+ */
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_waitpid);
+LT10_COMPAT_DEFAULT(waitpid);
+
+extern int __waitpid(pid_t, int *, int);
+
+__weak_reference(_waitpid, waitpid);
+
+pid_t
+_waitpid(pid_t wpid, int *status, int options)
+{
+ struct pthread *curthread = _get_curthread();
+ pid_t ret;
+
+ _thr_cancel_enter(curthread);
+ ret = __waitpid(wpid, status, options);
+ _thr_cancel_leave(curthread, 1);
+
+ return ret;
+}
diff --git a/lib/libpthread/thread/thr_write.c b/lib/libpthread/thread/thr_write.c
new file mode 100644
index 0000000..00ad990
--- /dev/null
+++ b/lib/libpthread/thread/thr_write.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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/fcntl.h>
+#include <sys/uio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__write);
+LT10_COMPAT_DEFAULT(write);
+
+__weak_reference(__write, write);
+
+ssize_t
+__write(int fd, const void *buf, size_t nbytes)
+{
+ struct pthread *curthread = _get_curthread();
+ ssize_t ret;
+
+ _thr_cancel_enter(curthread);
+ ret = __sys_write(fd, buf, nbytes);
+ _thr_cancel_leave(curthread, 1);
+
+ return ret;
+}
diff --git a/lib/libpthread/thread/thr_writev.c b/lib/libpthread/thread/thr_writev.c
new file mode 100644
index 0000000..a05159f
--- /dev/null
+++ b/lib/libpthread/thread/thr_writev.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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/fcntl.h>
+#include <sys/uio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__writev);
+LT10_COMPAT_DEFAULT(writev);
+
+__weak_reference(__writev, writev);
+
+ssize_t
+__writev(int fd, const struct iovec *iov, int iovcnt)
+{
+ struct pthread *curthread = _get_curthread();
+ ssize_t ret;
+
+ _thr_cancel_enter(curthread);
+ ret = __sys_writev(fd, iov, iovcnt);
+ _thr_cancel_leave(curthread, 1);
+
+ return ret;
+}
diff --git a/lib/libpthread/thread/thr_yield.c b/lib/libpthread/thread/thr_yield.c
new file mode 100644
index 0000000..6ba77f8
--- /dev/null
+++ b/lib/libpthread/thread/thr_yield.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_sched_yield);
+LT10_COMPAT_DEFAULT(sched_yield);
+LT10_COMPAT_PRIVATE(_pthread_yield);
+LT10_COMPAT_DEFAULT(pthread_yield);
+
+__weak_reference(_sched_yield, sched_yield);
+__weak_reference(_pthread_yield, pthread_yield);
+
+int
+_sched_yield(void)
+{
+ struct pthread *curthread = _get_curthread();
+
+ if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
+ return (__sys_sched_yield());
+
+ /* Reset the accumulated time slice value for the current thread: */
+ curthread->slice_usec = -1;
+
+ /* Schedule the next thread: */
+ _thr_sched_switch(curthread);
+ /* Always return no error. */
+ return(0);
+}
+
+/* Draft 4 yield */
+void
+_pthread_yield(void)
+{
+ struct pthread *curthread = _get_curthread();
+
+ if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) {
+ __sys_sched_yield();
+ return;
+ }
+
+ /* Reset the accumulated time slice value for the current thread: */
+ curthread->slice_usec = -1;
+
+ /* Schedule the next thread: */
+ _thr_sched_switch(curthread);
+}
diff --git a/lib/libradius/Makefile b/lib/libradius/Makefile
new file mode 100644
index 0000000..4102e1b
--- /dev/null
+++ b/lib/libradius/Makefile
@@ -0,0 +1,45 @@
+# Copyright 1998 Juniper Networks, Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+LIB= radius
+SRCS= radlib.c
+INCS= radlib.h radlib_vs.h
+CFLAGS+= -Wall
+SHLIB_MAJOR= 2
+MAN= libradius.3 radius.conf.5
+
+.if ${MK_OPENSSL} == "no"
+DPADD= ${LIBMD}
+LDADD= -lmd
+.else
+DPADD= ${LIBCRYPTO}
+LDADD= -lcrypto
+CFLAGS+= -DWITH_SSL
+.endif
+
+.include <bsd.lib.mk>
diff --git a/lib/libradius/libradius.3 b/lib/libradius/libradius.3
new file mode 100644
index 0000000..095d6e9
--- /dev/null
+++ b/lib/libradius/libradius.3
@@ -0,0 +1,555 @@
+.\" Copyright 1998 Juniper Networks, Inc.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd April 27, 2004
+.Dt LIBRADIUS 3
+.Os
+.Sh NAME
+.Nm libradius
+.Nd RADIUS client library
+.Sh SYNOPSIS
+.In radlib.h
+.Ft "struct rad_handle *"
+.Fn rad_acct_open "void"
+.Ft int
+.Fn rad_add_server "struct rad_handle *h" "const char *host" "int port" "const char *secret" "int timeout" "int max_tries"
+.Ft "struct rad_handle *"
+.Fn rad_auth_open "void"
+.Ft void
+.Fn rad_close "struct rad_handle *h"
+.Ft int
+.Fn rad_config "struct rad_handle *h" "const char *file"
+.Ft int
+.Fn rad_continue_send_request "struct rad_handle *h" "int selected" "int *fd" "struct timeval *tv"
+.Ft int
+.Fn rad_create_request "struct rad_handle *h" "int code"
+.Ft "struct in_addr"
+.Fn rad_cvt_addr "const void *data"
+.Ft u_int32_t
+.Fn rad_cvt_int "const void *data"
+.Ft char *
+.Fn rad_cvt_string "const void *data" "size_t len"
+.Ft int
+.Fn rad_get_attr "struct rad_handle *h" "const void **data" "size_t *len"
+.Ft int
+.Fn rad_get_vendor_attr "u_int32_t *vendor" "const void **data" "size_t *len"
+.Ft int
+.Fn rad_init_send_request "struct rad_handle *h" "int *fd" "struct timeval *tv"
+.Ft int
+.Fn rad_put_addr "struct rad_handle *h" "int type" "struct in_addr addr"
+.Ft int
+.Fn rad_put_attr "struct rad_handle *h" "int type" "const void *data" "size_t len"
+.Ft int
+.Fn rad_put_int "struct rad_handle *h" "int type" "u_int32_t value"
+.Ft int
+.Fn rad_put_string "struct rad_handle *h" "int type" "const char *str"
+.Ft int
+.Fn rad_put_message_authentic "struct rad_handle *h"
+.Ft int
+.Fn rad_put_vendor_addr "struct rad_handle *h" "int vendor" "int type" "struct in_addr addr"
+.Ft int
+.Fn rad_put_vendor_attr "struct rad_handle *h" "int vendor" "int type" "const void *data" "size_t len"
+.Ft int
+.Fn rad_put_vendor_int "struct rad_handle *h" "int vendor" "int type" "u_int32_t value"
+.Ft int
+.Fn rad_put_vendor_string "struct rad_handle *h" "int vendor" "int type" "const char *str"
+.Ft ssize_t
+.Fn rad_request_authenticator "struct rad_handle *h" "char *buf" "size_t len"
+.Ft int
+.Fn rad_send_request "struct rad_handle *h"
+.Ft "const char *"
+.Fn rad_server_secret "struct rad_handle *h"
+.Ft u_char *
+.Fn rad_demangle "struct rad_handle *h" "const void *mangled" "size_t mlen"
+.Ft u_char *
+.Fn rad_demangle_mppe_key "struct rad_handle *h" "const void *mangled" "size_t mlen" "size_t *len"
+.Ft "const char *"
+.Fn rad_strerror "struct rad_handle *h"
+.Sh DESCRIPTION
+The
+.Nm
+library implements the client side of the Remote Authentication Dial
+In User Service (RADIUS).
+RADIUS, defined in RFCs 2865 and 2866,
+allows clients to perform authentication and accounting by means of
+network requests to remote servers.
+.Ss Initialization
+To use the library, an application must first call
+.Fn rad_auth_open
+or
+.Fn rad_acct_open
+to obtain a
+.Vt "struct rad_handle *" ,
+which provides the context for subsequent operations.
+The former function is used for RADIUS authentication and the
+latter is used for RADIUS accounting.
+Calls to
+.Fn rad_auth_open
+and
+.Fn rad_acct_open
+always succeed unless insufficient virtual memory is available.
+If
+the necessary memory cannot be allocated, the functions return
+.Dv NULL .
+For compatibility with earlier versions of this library,
+.Fn rad_open
+is provided as a synonym for
+.Fn rad_auth_open .
+.Pp
+Before issuing any RADIUS requests, the library must be made aware
+of the servers it can contact.
+The easiest way to configure the
+library is to call
+.Fn rad_config .
+.Fn rad_config
+causes the library to read a configuration file whose format is
+described in
+.Xr radius.conf 5 .
+The pathname of the configuration file is passed as the
+.Fa file
+argument to
+.Fn rad_config .
+This argument may also be given as
+.Dv NULL ,
+in which case the standard configuration file
+.Pa /etc/radius.conf
+is used.
+.Fn rad_config
+returns 0 on success, or \-1 if an error occurs.
+.Pp
+The library can also be configured programmatically by calls to
+.Fn rad_add_server .
+The
+.Fa host
+parameter specifies the server host, either as a fully qualified
+domain name or as a dotted-quad IP address in text form.
+The
+.Fa port
+parameter specifies the UDP port to contact on the server.
+If
+.Fa port
+is given as 0, the library looks up the
+.Ql radius/udp
+or
+.Ql radacct/udp
+service in the network
+.Xr services 5
+database, and uses the port found
+there.
+If no entry is found, the library uses the standard RADIUS
+ports, 1812 for authentication and 1813 for accounting.
+The shared secret for the server host is passed to the
+.Fa secret
+parameter.
+It may be any
+.Dv NUL Ns -terminated
+string of bytes.
+The RADIUS protocol
+ignores all but the leading 128 bytes of the shared secret.
+The timeout for receiving replies from the server is passed to the
+.Fa timeout
+parameter, in units of seconds.
+The maximum number of repeated
+requests to make before giving up is passed into the
+.Fa max_tries
+parameter.
+.Fn rad_add_server
+returns 0 on success, or \-1 if an error occurs.
+.Pp
+.Fn rad_add_server
+may be called multiple times, and it may be used together with
+.Fn rad_config .
+At most 10 servers may be specified.
+When multiple servers are given, they are tried in round-robin
+fashion until a valid response is received, or until each server's
+.Fa max_tries
+limit has been reached.
+.Ss Creating a RADIUS Request
+A RADIUS request consists of a code specifying the kind of request,
+and zero or more attributes which provide additional information.
+To
+begin constructing a new request, call
+.Fn rad_create_request .
+In addition to the usual
+.Vt "struct rad_handle *" ,
+this function takes a
+.Fa code
+parameter which specifies the type of the request.
+Most often this
+will be
+.Dv RAD_ACCESS_REQUEST .
+.Fn rad_create_request
+returns 0 on success, or \-1 on if an error occurs.
+.Pp
+After the request has been created with
+.Fn rad_create_request ,
+attributes can be attached to it.
+This is done through calls to
+.Fn rad_put_addr ,
+.Fn rad_put_int ,
+and
+.Fn rad_put_string .
+Each accepts a
+.Fa type
+parameter identifying the attribute, and a value which may be
+an Internet address, an integer, or a
+.Dv NUL Ns -terminated
+string,
+respectively.
+Alternatively,
+.Fn rad_put_vendor_addr ,
+.Fn rad_put_vendor_int
+or
+.Fn rad_put_vendor_string
+may be used to specify vendor specific attributes.
+Vendor specific
+definitions may be found in
+.In radlib_vs.h
+.Pp
+The library also provides a function
+.Fn rad_put_attr
+which can be used to supply a raw, uninterpreted attribute.
+The
+.Fa data
+argument points to an array of bytes, and the
+.Fa len
+argument specifies its length.
+.Pp
+It is possible adding the Message-Authenticator to the request.
+This is an HMAC-MD5 hash of the entire Access-Request packet (see RFC 3579).
+This attribute must be present in any packet that includes an EAP-Message
+attribute.
+It can be added by using the
+.Fn rad_put_message_authentic
+function.
+The
+.Nm
+library
+calculates the HMAC-MD5 hash implicitly before sending the request.
+If the Message-Authenticator was found inside the response packet,
+then the packet is silently dropped, if the validation failed.
+In order to get this feature, the library should be compiled with
+OpenSSL support.
+.Pp
+The
+.Fn rad_put_X
+functions return 0 on success, or \-1 if an error occurs.
+.Ss Sending the Request and Receiving the Response
+After the RADIUS request has been constructed, it is sent either by means of
+.Fn rad_send_request
+or by a combination of calls to
+.Fn rad_init_send_request
+and
+.Fn rad_continue_send_request .
+.Pp
+The
+.Fn rad_send_request
+function sends the request and waits for a valid reply,
+retrying the defined servers in round-robin fashion as necessary.
+If a valid response is received,
+.Fn rad_send_request
+returns the RADIUS code which specifies the type of the response.
+This will typically be
+.Dv RAD_ACCESS_ACCEPT ,
+.Dv RAD_ACCESS_REJECT ,
+or
+.Dv RAD_ACCESS_CHALLENGE .
+If no valid response is received,
+.Fn rad_send_request
+returns \-1.
+.Pp
+As an alternative, if you do not wish to block waiting for a response,
+.Fn rad_init_send_request
+and
+.Fn rad_continue_send_request
+may be used instead.
+If a reply is received from the RADIUS server or a
+timeout occurs, these functions return a value as described for
+.Fn rad_send_request .
+Otherwise, a value of zero is returned and the values pointed to by
+.Fa fd
+and
+.Fa tv
+are set to the descriptor and timeout that should be passed to
+.Xr select 2 .
+.Pp
+.Fn rad_init_send_request
+must be called first, followed by repeated calls to
+.Fn rad_continue_send_request
+as long as a return value of zero is given.
+Between each call, the application should call
+.Xr select 2 ,
+passing
+.Fa *fd
+as a read descriptor and timing out after the interval specified by
+.Fa tv .
+When
+.Xr select 2
+returns,
+.Fn rad_continue_send_request
+should be called with
+.Fa selected
+set to a non-zero value if
+.Xr select 2
+indicated that the descriptor is readable.
+.Pp
+Like RADIUS requests, each response may contain zero or more
+attributes.
+After a response has been received successfully by
+.Fn rad_send_request
+or
+.Fn rad_continue_send_request ,
+its attributes can be extracted one by one using
+.Fn rad_get_attr .
+Each time
+.Fn rad_get_attr
+is called, it gets the next attribute from the current response, and
+stores a pointer to the data and the length of the data via the
+reference parameters
+.Fa data
+and
+.Fa len ,
+respectively.
+Note that the data resides in the response itself,
+and must not be modified.
+A successful call to
+.Fn rad_get_attr
+returns the RADIUS attribute type.
+If no more attributes remain in the current response,
+.Fn rad_get_attr
+returns 0.
+If an error such as a malformed attribute is detected, \-1 is
+returned.
+.Pp
+If
+.Fn rad_get_attr
+returns
+.Dv RAD_VENDOR_SPECIFIC ,
+.Fn rad_get_vendor_attr
+may be called to determine the vendor.
+The vendor specific RADIUS attribute type is returned.
+The reference parameters
+.Fa data
+and
+.Fa len
+(as returned from
+.Fn rad_get_attr )
+are passed to
+.Fn rad_get_vendor_attr ,
+and are adjusted to point to the vendor specific attribute data.
+.Pp
+The common types of attributes can be decoded using
+.Fn rad_cvt_addr ,
+.Fn rad_cvt_int ,
+and
+.Fn rad_cvt_string .
+These functions accept a pointer to the attribute data, which should
+have been obtained using
+.Fn rad_get_attr
+and optionally
+.Fn rad_get_vendor_attr .
+In the case of
+.Fn rad_cvt_string ,
+the length
+.Fa len
+must also be given.
+These functions interpret the attribute as an
+Internet address, an integer, or a string, respectively, and return
+its value.
+.Fn rad_cvt_string
+returns its value as a
+.Dv NUL Ns -terminated
+string in dynamically
+allocated memory.
+The application should free the string using
+.Xr free 3
+when it is no longer needed.
+.Pp
+If insufficient virtual memory is available,
+.Fn rad_cvt_string
+returns
+.Dv NULL .
+.Fn rad_cvt_addr
+and
+.Fn rad_cvt_int
+cannot fail.
+.Pp
+The
+.Fn rad_request_authenticator
+function may be used to obtain the Request-Authenticator attribute value
+associated with the current RADIUS server according to the supplied
+rad_handle.
+The target buffer
+.Fa buf
+of length
+.Fa len
+must be supplied and should be at least 16 bytes.
+The return value is the number of bytes written to
+.Fa buf
+or \-1 to indicate that
+.Fa len
+was not large enough.
+.Pp
+The
+.Fn rad_server_secret
+returns the secret shared with the current RADIUS server according to the
+supplied rad_handle.
+.Pp
+The
+.Fn rad_demangle
+function demangles attributes containing passwords and MS-CHAPv1 MPPE-Keys.
+The return value is
+.Dv NULL
+on failure, or the plaintext attribute.
+This value should be freed using
+.Xr free 3
+when it is no longer needed.
+.Pp
+The
+.Fn rad_demangle_mppe_key
+function demangles the send- and recv-keys when using MPPE (see RFC 2548).
+The return value is
+.Dv NULL
+on failure, or the plaintext attribute.
+This value should be freed using
+.Xr free 3
+when it is no longer needed.
+.Ss Obtaining Error Messages
+Those functions which accept a
+.Vt "struct rad_handle *"
+argument record an error message if they fail.
+The error message
+can be retrieved by calling
+.Fn rad_strerror .
+The message text is overwritten on each new error for the given
+.Vt "struct rad_handle *" .
+Thus the message must be copied if it is to be preserved through
+subsequent library calls using the same handle.
+.Ss Cleanup
+To free the resources used by the RADIUS library, call
+.Fn rad_close .
+.Sh RETURN VALUES
+The following functions return a non-negative value on success.
+If
+they detect an error, they return \-1 and record an error message
+which can be retrieved using
+.Fn rad_strerror .
+.Pp
+.Bl -item -offset indent -compact
+.It
+.Fn rad_add_server
+.It
+.Fn rad_config
+.It
+.Fn rad_create_request
+.It
+.Fn rad_get_attr
+.It
+.Fn rad_put_addr
+.It
+.Fn rad_put_attr
+.It
+.Fn rad_put_int
+.It
+.Fn rad_put_string
+.It
+.Fn rad_put_message_authentic
+.It
+.Fn rad_init_send_request
+.It
+.Fn rad_continue_send_request
+.It
+.Fn rad_send_request
+.El
+.Pp
+The following functions return a
+.No non- Ns Dv NULL
+pointer on success.
+If they are unable to allocate sufficient
+virtual memory, they return
+.Dv NULL ,
+without recording an error message.
+.Pp
+.Bl -item -offset indent -compact
+.It
+.Fn rad_acct_open
+.It
+.Fn rad_auth_open
+.It
+.Fn rad_cvt_string
+.El
+.Pp
+The following functions return a
+.No non- Ns Dv NULL
+pointer on success.
+If they fail, they return
+.Dv NULL ,
+with recording an error message.
+.Pp
+.Bl -item -offset indent -compact
+.It
+.Fn rad_demangle
+.It
+.Fn rad_demangle_mppe_key
+.El
+.Sh FILES
+.Bl -tag -width indent
+.It Pa /etc/radius.conf
+.El
+.Sh SEE ALSO
+.Xr radius.conf 5
+.Rs
+.%A "C. Rigney, et al"
+.%T "Remote Authentication Dial In User Service (RADIUS)"
+.%O "RFC 2865"
+.Re
+.Rs
+.%A "C. Rigney"
+.%T "RADIUS Accounting"
+.%O "RFC 2866"
+.Re
+.Rs
+.%A G. Zorn
+.%T "Microsoft Vendor-specific RADIUS attributes"
+.%O RFC 2548
+.Re
+.Rs
+.%A C. Rigney, et al
+.%T "RADIUS extensions"
+.%O RFC 2869
+.Re
+.Sh AUTHORS
+.An -nosplit
+This software was originally written by
+.An John Polstra ,
+and donated to the
+.Fx
+project by Juniper Networks, Inc.
+.An Oleg Semyonov
+subsequently added the ability to perform RADIUS
+accounting.
+Later additions and changes by
+.An Michael Bretterklieber .
diff --git a/lib/libradius/radius.conf.5 b/lib/libradius/radius.conf.5
new file mode 100644
index 0000000..6fa5cd7
--- /dev/null
+++ b/lib/libradius/radius.conf.5
@@ -0,0 +1,185 @@
+.\" Copyright 1998 Juniper Networks, Inc.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd October 30, 1999
+.Dt RADIUS.CONF 5
+.Os
+.Sh NAME
+.Nm radius.conf
+.Nd RADIUS client configuration file
+.Sh SYNOPSIS
+.Pa /etc/radius.conf
+.Sh DESCRIPTION
+.Nm
+contains the information necessary to configure the RADIUS client
+library.
+It is parsed by
+.Xr rad_config 3 .
+The file contains one or more lines of text, each describing a
+single RADIUS server which will be used by the library.
+Leading
+white space is ignored, as are empty lines and lines containing
+only comments.
+.Pp
+A RADIUS server is described by three to five fields on a line:
+.Pp
+.Bl -item -offset indent -compact
+.It
+Service type
+.It
+Server host
+.It
+Shared secret
+.It
+Timeout
+.It
+Retries
+.El
+.Pp
+The fields are separated by white space.
+The
+.Ql #
+character at the beginning of a field begins a comment, which extends
+to the end of the line.
+A field may be enclosed in double quotes,
+in which case it may contain white space and/or begin with the
+.Ql #
+character.
+Within a quoted string, the double quote character can
+be represented by
+.Ql \e\&" ,
+and the backslash can be represented by
+.Ql \e\e .
+No other escape sequences are supported.
+.Pp
+.Pp
+The first field gives the service type, either
+.Ql auth
+for RADIUS authentication or
+.Ql acct
+for RADIUS accounting.
+If a single server provides both services, two
+lines are required in the file.
+Earlier versions of this file did
+not include a service type.
+For backward compatibility, if the first
+field is not
+.Ql auth
+or
+.Ql acct
+the library behaves as if
+.Ql auth
+were specified, and interprets the fields in the line as if they
+were fields two through five.
+.Pp
+The second field specifies
+the server host, either as a fully qualified domain name or as a
+dotted-quad IP address.
+The host may optionally be followed by a
+.Ql \&:
+and a numeric port number, without intervening white space.
+If the
+port specification is omitted, it defaults to the
+.Ql radius
+or
+.Ql radacct
+service in the
+.Pa /etc/services
+file for service types
+.Ql auth
+and
+.Ql acct ,
+respectively.
+If no such entry is present, the standard ports 1812 and 1813 are
+used.
+.Pp
+The third field contains the shared secret, which should be known
+only to the client and server hosts.
+It is an arbitrary string of
+characters, though it must be enclosed in double quotes if it
+contains white space.
+The shared secret may be
+any length, but the RADIUS protocol uses only the first 128
+characters.
+N.B., some popular RADIUS servers have bugs which
+prevent them from working properly with secrets longer than 16
+characters.
+.Pp
+The fourth field contains a decimal integer specifying the timeout in
+seconds for receiving a valid reply from the server.
+If this field
+is omitted, it defaults to 3 seconds.
+.Pp
+The fifth field contains a decimal integer specifying the maximum
+number of attempts that will be made to authenticate with the server
+before giving up.
+If omitted, it defaults to 3 attempts.
+Note,
+this is the total number of attempts and not the number of retries.
+.Pp
+Up to 10 RADIUS servers may be specified for each service type.
+The servers are tried in
+round-robin fashion, until a valid response is received or the
+maximum number of tries has been reached for all servers.
+.Pp
+The standard location for this file is
+.Pa /etc/radius.conf .
+But an alternate pathname may be specified in the call to
+.Xr rad_config 3 .
+Since the file contains sensitive information in the form of the
+shared secrets, it should not be readable except by root.
+.Sh FILES
+.Pa /etc/radius.conf
+.Sh EXAMPLES
+.Bd -literal
+# A simple entry using all the defaults:
+acct radius1.domain.com OurLittleSecret
+
+# A server still using the obsolete RADIUS port, with increased
+# timeout and maximum tries:
+auth auth.domain.com:1645 "I can't see you" 5 4
+
+# A server specified by its IP address:
+auth 192.168.27.81 $X*#..38947ax-+=
+.Ed
+.Sh SEE ALSO
+.Xr libradius 3
+.Rs
+.%A C. Rigney, et al
+.%T "Remote Authentication Dial In User Service (RADIUS)"
+.%O RFC 2138
+.Re
+.Rs
+.%A C. Rigney
+.%T RADIUS Accounting
+.%O RFC 2139
+.Re
+.Sh AUTHORS
+This documentation was written by
+.An John Polstra ,
+and donated to the
+.Fx
+project by Juniper Networks, Inc.
diff --git a/lib/libradius/radlib.c b/lib/libradius/radlib.c
new file mode 100644
index 0000000..6060885
--- /dev/null
+++ b/lib/libradius/radlib.c
@@ -0,0 +1,1232 @@
+/*-
+ * Copyright 1998 Juniper Networks, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#ifdef WITH_SSL
+#include <openssl/hmac.h>
+#include <openssl/md5.h>
+#define MD5Init MD5_Init
+#define MD5Update MD5_Update
+#define MD5Final MD5_Final
+#else
+#define MD5_DIGEST_LENGTH 16
+#include <md5.h>
+#endif
+
+/* We need the MPPE_KEY_LEN define */
+#include <netgraph/ng_mppc.h>
+
+#include <errno.h>
+#include <netdb.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "radlib_private.h"
+
+static void clear_password(struct rad_handle *);
+static void generr(struct rad_handle *, const char *, ...)
+ __printflike(2, 3);
+static void insert_scrambled_password(struct rad_handle *, int);
+static void insert_request_authenticator(struct rad_handle *, int);
+static void insert_message_authenticator(struct rad_handle *, int);
+static int is_valid_response(struct rad_handle *, int,
+ const struct sockaddr_in *);
+static int put_password_attr(struct rad_handle *, int,
+ const void *, size_t);
+static int put_raw_attr(struct rad_handle *, int,
+ const void *, size_t);
+static int split(char *, char *[], int, char *, size_t);
+
+static void
+clear_password(struct rad_handle *h)
+{
+ if (h->pass_len != 0) {
+ memset(h->pass, 0, h->pass_len);
+ h->pass_len = 0;
+ }
+ h->pass_pos = 0;
+}
+
+static void
+generr(struct rad_handle *h, const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ vsnprintf(h->errmsg, ERRSIZE, format, ap);
+ va_end(ap);
+}
+
+static void
+insert_scrambled_password(struct rad_handle *h, int srv)
+{
+ MD5_CTX ctx;
+ unsigned char md5[MD5_DIGEST_LENGTH];
+ const struct rad_server *srvp;
+ int padded_len;
+ int pos;
+
+ srvp = &h->servers[srv];
+ padded_len = h->pass_len == 0 ? 16 : (h->pass_len+15) & ~0xf;
+
+ memcpy(md5, &h->request[POS_AUTH], LEN_AUTH);
+ for (pos = 0; pos < padded_len; pos += 16) {
+ int i;
+
+ /* Calculate the new scrambler */
+ MD5Init(&ctx);
+ MD5Update(&ctx, srvp->secret, strlen(srvp->secret));
+ MD5Update(&ctx, md5, 16);
+ MD5Final(md5, &ctx);
+
+ /*
+ * Mix in the current chunk of the password, and copy
+ * the result into the right place in the request. Also
+ * modify the scrambler in place, since we will use this
+ * in calculating the scrambler for next time.
+ */
+ for (i = 0; i < 16; i++)
+ h->request[h->pass_pos + pos + i] =
+ md5[i] ^= h->pass[pos + i];
+ }
+}
+
+static void
+insert_request_authenticator(struct rad_handle *h, int srv)
+{
+ MD5_CTX ctx;
+ const struct rad_server *srvp;
+
+ srvp = &h->servers[srv];
+
+ /* Create the request authenticator */
+ MD5Init(&ctx);
+ MD5Update(&ctx, &h->request[POS_CODE], POS_AUTH - POS_CODE);
+ MD5Update(&ctx, memset(&h->request[POS_AUTH], 0, LEN_AUTH), LEN_AUTH);
+ MD5Update(&ctx, &h->request[POS_ATTRS], h->req_len - POS_ATTRS);
+ MD5Update(&ctx, srvp->secret, strlen(srvp->secret));
+ MD5Final(&h->request[POS_AUTH], &ctx);
+}
+
+static void
+insert_message_authenticator(struct rad_handle *h, int srv)
+{
+#ifdef WITH_SSL
+ u_char md[EVP_MAX_MD_SIZE];
+ u_int md_len;
+ const struct rad_server *srvp;
+ HMAC_CTX ctx;
+ srvp = &h->servers[srv];
+
+ if (h->authentic_pos != 0) {
+ HMAC_CTX_init(&ctx);
+ HMAC_Init(&ctx, srvp->secret, strlen(srvp->secret), EVP_md5());
+ HMAC_Update(&ctx, &h->request[POS_CODE], POS_AUTH - POS_CODE);
+ HMAC_Update(&ctx, &h->request[POS_AUTH], LEN_AUTH);
+ HMAC_Update(&ctx, &h->request[POS_ATTRS],
+ h->req_len - POS_ATTRS);
+ HMAC_Final(&ctx, md, &md_len);
+ HMAC_CTX_cleanup(&ctx);
+ HMAC_cleanup(&ctx);
+ memcpy(&h->request[h->authentic_pos + 2], md, md_len);
+ }
+#endif
+}
+
+/*
+ * Return true if the current response is valid for a request to the
+ * specified server.
+ */
+static int
+is_valid_response(struct rad_handle *h, int srv,
+ const struct sockaddr_in *from)
+{
+ MD5_CTX ctx;
+ unsigned char md5[MD5_DIGEST_LENGTH];
+ const struct rad_server *srvp;
+ int len;
+#ifdef WITH_SSL
+ HMAC_CTX hctx;
+ u_char resp[MSGSIZE], md[EVP_MAX_MD_SIZE];
+ int pos, md_len;
+#endif
+
+ srvp = &h->servers[srv];
+
+ /* Check the source address */
+ if (from->sin_family != srvp->addr.sin_family ||
+ from->sin_addr.s_addr != srvp->addr.sin_addr.s_addr ||
+ from->sin_port != srvp->addr.sin_port)
+ return 0;
+
+ /* Check the message length */
+ if (h->resp_len < POS_ATTRS)
+ return 0;
+ len = h->response[POS_LENGTH] << 8 | h->response[POS_LENGTH+1];
+ if (len > h->resp_len)
+ return 0;
+
+ /* Check the response authenticator */
+ MD5Init(&ctx);
+ MD5Update(&ctx, &h->response[POS_CODE], POS_AUTH - POS_CODE);
+ MD5Update(&ctx, &h->request[POS_AUTH], LEN_AUTH);
+ MD5Update(&ctx, &h->response[POS_ATTRS], len - POS_ATTRS);
+ MD5Update(&ctx, srvp->secret, strlen(srvp->secret));
+ MD5Final(md5, &ctx);
+ if (memcmp(&h->response[POS_AUTH], md5, sizeof md5) != 0)
+ return 0;
+
+#ifdef WITH_SSL
+ /*
+ * For non accounting responses check the message authenticator,
+ * if any.
+ */
+ if (h->response[POS_CODE] != RAD_ACCOUNTING_RESPONSE) {
+
+ memcpy(resp, h->response, MSGSIZE);
+ pos = POS_ATTRS;
+
+ /* Search and verify the Message-Authenticator */
+ while (pos < len - 2) {
+
+ if (h->response[pos] == RAD_MESSAGE_AUTHENTIC) {
+ /* zero fill the Message-Authenticator */
+ memset(&resp[pos + 2], 0, MD5_DIGEST_LENGTH);
+
+ HMAC_CTX_init(&hctx);
+ HMAC_Init(&hctx, srvp->secret,
+ strlen(srvp->secret), EVP_md5());
+ HMAC_Update(&hctx, &h->response[POS_CODE],
+ POS_AUTH - POS_CODE);
+ HMAC_Update(&hctx, &h->request[POS_AUTH],
+ LEN_AUTH);
+ HMAC_Update(&hctx, &resp[POS_ATTRS],
+ h->resp_len - POS_ATTRS);
+ HMAC_Final(&hctx, md, &md_len);
+ HMAC_CTX_cleanup(&hctx);
+ HMAC_cleanup(&hctx);
+ if (memcmp(md, &h->response[pos + 2],
+ MD5_DIGEST_LENGTH) != 0)
+ return 0;
+ break;
+ }
+ pos += h->response[pos + 1];
+ }
+ }
+#endif
+ return 1;
+}
+
+static int
+put_password_attr(struct rad_handle *h, int type, const void *value, size_t len)
+{
+ int padded_len;
+ int pad_len;
+
+ if (h->pass_pos != 0) {
+ generr(h, "Multiple User-Password attributes specified");
+ return -1;
+ }
+ if (len > PASSSIZE)
+ len = PASSSIZE;
+ padded_len = len == 0 ? 16 : (len+15) & ~0xf;
+ pad_len = padded_len - len;
+
+ /*
+ * Put in a place-holder attribute containing all zeros, and
+ * remember where it is so we can fill it in later.
+ */
+ clear_password(h);
+ put_raw_attr(h, type, h->pass, padded_len);
+ h->pass_pos = h->req_len - padded_len;
+
+ /* Save the cleartext password, padded as necessary */
+ memcpy(h->pass, value, len);
+ h->pass_len = len;
+ memset(h->pass + len, 0, pad_len);
+ return 0;
+}
+
+static int
+put_raw_attr(struct rad_handle *h, int type, const void *value, size_t len)
+{
+ if (len > 253) {
+ generr(h, "Attribute too long");
+ return -1;
+ }
+ if (h->req_len + 2 + len > MSGSIZE) {
+ generr(h, "Maximum message length exceeded");
+ return -1;
+ }
+ h->request[h->req_len++] = type;
+ h->request[h->req_len++] = len + 2;
+ memcpy(&h->request[h->req_len], value, len);
+ h->req_len += len;
+ return 0;
+}
+
+int
+rad_add_server(struct rad_handle *h, const char *host, int port,
+ const char *secret, int timeout, int tries)
+{
+ struct rad_server *srvp;
+
+ if (h->num_servers >= MAXSERVERS) {
+ generr(h, "Too many RADIUS servers specified");
+ return -1;
+ }
+ srvp = &h->servers[h->num_servers];
+
+ memset(&srvp->addr, 0, sizeof srvp->addr);
+ srvp->addr.sin_len = sizeof srvp->addr;
+ srvp->addr.sin_family = AF_INET;
+ if (!inet_aton(host, &srvp->addr.sin_addr)) {
+ struct hostent *hent;
+
+ if ((hent = gethostbyname(host)) == NULL) {
+ generr(h, "%s: host not found", host);
+ return -1;
+ }
+ memcpy(&srvp->addr.sin_addr, hent->h_addr,
+ sizeof srvp->addr.sin_addr);
+ }
+ if (port != 0)
+ srvp->addr.sin_port = htons((u_short)port);
+ else {
+ struct servent *sent;
+
+ if (h->type == RADIUS_AUTH)
+ srvp->addr.sin_port =
+ (sent = getservbyname("radius", "udp")) != NULL ?
+ sent->s_port : htons(RADIUS_PORT);
+ else
+ srvp->addr.sin_port =
+ (sent = getservbyname("radacct", "udp")) != NULL ?
+ sent->s_port : htons(RADACCT_PORT);
+ }
+ if ((srvp->secret = strdup(secret)) == NULL) {
+ generr(h, "Out of memory");
+ return -1;
+ }
+ srvp->timeout = timeout;
+ srvp->max_tries = tries;
+ srvp->num_tries = 0;
+ h->num_servers++;
+ return 0;
+}
+
+void
+rad_close(struct rad_handle *h)
+{
+ int srv;
+
+ if (h->fd != -1)
+ close(h->fd);
+ for (srv = 0; srv < h->num_servers; srv++) {
+ memset(h->servers[srv].secret, 0,
+ strlen(h->servers[srv].secret));
+ free(h->servers[srv].secret);
+ }
+ clear_password(h);
+ free(h);
+}
+
+int
+rad_config(struct rad_handle *h, const char *path)
+{
+ FILE *fp;
+ char buf[MAXCONFLINE];
+ int linenum;
+ int retval;
+
+ if (path == NULL)
+ path = PATH_RADIUS_CONF;
+ if ((fp = fopen(path, "r")) == NULL) {
+ generr(h, "Cannot open \"%s\": %s", path, strerror(errno));
+ return -1;
+ }
+ retval = 0;
+ linenum = 0;
+ while (fgets(buf, sizeof buf, fp) != NULL) {
+ int len;
+ char *fields[5];
+ int nfields;
+ char msg[ERRSIZE];
+ char *type;
+ char *host, *res;
+ char *port_str;
+ char *secret;
+ char *timeout_str;
+ char *maxtries_str;
+ char *end;
+ char *wanttype;
+ unsigned long timeout;
+ unsigned long maxtries;
+ int port;
+ int i;
+
+ linenum++;
+ len = strlen(buf);
+ /* We know len > 0, else fgets would have returned NULL. */
+ if (buf[len - 1] != '\n') {
+ if (len == sizeof buf - 1)
+ generr(h, "%s:%d: line too long", path,
+ linenum);
+ else
+ generr(h, "%s:%d: missing newline", path,
+ linenum);
+ retval = -1;
+ break;
+ }
+ buf[len - 1] = '\0';
+
+ /* Extract the fields from the line. */
+ nfields = split(buf, fields, 5, msg, sizeof msg);
+ if (nfields == -1) {
+ generr(h, "%s:%d: %s", path, linenum, msg);
+ retval = -1;
+ break;
+ }
+ if (nfields == 0)
+ continue;
+ /*
+ * The first field should contain "auth" or "acct" for
+ * authentication or accounting, respectively. But older
+ * versions of the file didn't have that field. Default
+ * it to "auth" for backward compatibility.
+ */
+ if (strcmp(fields[0], "auth") != 0 &&
+ strcmp(fields[0], "acct") != 0) {
+ if (nfields >= 5) {
+ generr(h, "%s:%d: invalid service type", path,
+ linenum);
+ retval = -1;
+ break;
+ }
+ nfields++;
+ for (i = nfields; --i > 0; )
+ fields[i] = fields[i - 1];
+ fields[0] = "auth";
+ }
+ if (nfields < 3) {
+ generr(h, "%s:%d: missing shared secret", path,
+ linenum);
+ retval = -1;
+ break;
+ }
+ type = fields[0];
+ host = fields[1];
+ secret = fields[2];
+ timeout_str = fields[3];
+ maxtries_str = fields[4];
+
+ /* Ignore the line if it is for the wrong service type. */
+ wanttype = h->type == RADIUS_AUTH ? "auth" : "acct";
+ if (strcmp(type, wanttype) != 0)
+ continue;
+
+ /* Parse and validate the fields. */
+ res = host;
+ host = strsep(&res, ":");
+ port_str = strsep(&res, ":");
+ if (port_str != NULL) {
+ port = strtoul(port_str, &end, 10);
+ if (*end != '\0') {
+ generr(h, "%s:%d: invalid port", path,
+ linenum);
+ retval = -1;
+ break;
+ }
+ } else
+ port = 0;
+ if (timeout_str != NULL) {
+ timeout = strtoul(timeout_str, &end, 10);
+ if (*end != '\0') {
+ generr(h, "%s:%d: invalid timeout", path,
+ linenum);
+ retval = -1;
+ break;
+ }
+ } else
+ timeout = TIMEOUT;
+ if (maxtries_str != NULL) {
+ maxtries = strtoul(maxtries_str, &end, 10);
+ if (*end != '\0') {
+ generr(h, "%s:%d: invalid maxtries", path,
+ linenum);
+ retval = -1;
+ break;
+ }
+ } else
+ maxtries = MAXTRIES;
+
+ if (rad_add_server(h, host, port, secret, timeout, maxtries) ==
+ -1) {
+ strcpy(msg, h->errmsg);
+ generr(h, "%s:%d: %s", path, linenum, msg);
+ retval = -1;
+ break;
+ }
+ }
+ /* Clear out the buffer to wipe a possible copy of a shared secret */
+ memset(buf, 0, sizeof buf);
+ fclose(fp);
+ return retval;
+}
+
+/*
+ * rad_init_send_request() must have previously been called.
+ * Returns:
+ * 0 The application should select on *fd with a timeout of tv before
+ * calling rad_continue_send_request again.
+ * < 0 Failure
+ * > 0 Success
+ */
+int
+rad_continue_send_request(struct rad_handle *h, int selected, int *fd,
+ struct timeval *tv)
+{
+ int n;
+
+ if (selected) {
+ struct sockaddr_in from;
+ int fromlen;
+
+ fromlen = sizeof from;
+ h->resp_len = recvfrom(h->fd, h->response,
+ MSGSIZE, MSG_WAITALL, (struct sockaddr *)&from, &fromlen);
+ if (h->resp_len == -1) {
+ generr(h, "recvfrom: %s", strerror(errno));
+ return -1;
+ }
+ if (is_valid_response(h, h->srv, &from)) {
+ h->resp_len = h->response[POS_LENGTH] << 8 |
+ h->response[POS_LENGTH+1];
+ h->resp_pos = POS_ATTRS;
+ return h->response[POS_CODE];
+ }
+ }
+
+ if (h->try == h->total_tries) {
+ generr(h, "No valid RADIUS responses received");
+ return -1;
+ }
+
+ /*
+ * Scan round-robin to the next server that has some
+ * tries left. There is guaranteed to be one, or we
+ * would have exited this loop by now.
+ */
+ while (h->servers[h->srv].num_tries >= h->servers[h->srv].max_tries)
+ if (++h->srv >= h->num_servers)
+ h->srv = 0;
+
+ if (h->request[POS_CODE] == RAD_ACCOUNTING_REQUEST)
+ /* Insert the request authenticator into the request */
+ insert_request_authenticator(h, h->srv);
+ else
+ /* Insert the scrambled password into the request */
+ if (h->pass_pos != 0)
+ insert_scrambled_password(h, h->srv);
+
+ insert_message_authenticator(h, h->srv);
+
+ /* Send the request */
+ n = sendto(h->fd, h->request, h->req_len, 0,
+ (const struct sockaddr *)&h->servers[h->srv].addr,
+ sizeof h->servers[h->srv].addr);
+ if (n != h->req_len) {
+ if (n == -1)
+ generr(h, "sendto: %s", strerror(errno));
+ else
+ generr(h, "sendto: short write");
+ return -1;
+ }
+
+ h->try++;
+ h->servers[h->srv].num_tries++;
+ tv->tv_sec = h->servers[h->srv].timeout;
+ tv->tv_usec = 0;
+ *fd = h->fd;
+
+ return 0;
+}
+
+int
+rad_create_request(struct rad_handle *h, int code)
+{
+ int i;
+
+ h->request[POS_CODE] = code;
+ h->request[POS_IDENT] = ++h->ident;
+ /* Create a random authenticator */
+ for (i = 0; i < LEN_AUTH; i += 2) {
+ long r;
+ r = random();
+ h->request[POS_AUTH+i] = (u_char)r;
+ h->request[POS_AUTH+i+1] = (u_char)(r >> 8);
+ }
+ h->req_len = POS_ATTRS;
+ clear_password(h);
+ h->request_created = 1;
+ return 0;
+}
+
+struct in_addr
+rad_cvt_addr(const void *data)
+{
+ struct in_addr value;
+
+ memcpy(&value.s_addr, data, sizeof value.s_addr);
+ return value;
+}
+
+u_int32_t
+rad_cvt_int(const void *data)
+{
+ u_int32_t value;
+
+ memcpy(&value, data, sizeof value);
+ return ntohl(value);
+}
+
+char *
+rad_cvt_string(const void *data, size_t len)
+{
+ char *s;
+
+ s = malloc(len + 1);
+ if (s != NULL) {
+ memcpy(s, data, len);
+ s[len] = '\0';
+ }
+ return s;
+}
+
+/*
+ * Returns the attribute type. If none are left, returns 0. On failure,
+ * returns -1.
+ */
+int
+rad_get_attr(struct rad_handle *h, const void **value, size_t *len)
+{
+ int type;
+
+ if (h->resp_pos >= h->resp_len)
+ return 0;
+ if (h->resp_pos + 2 > h->resp_len) {
+ generr(h, "Malformed attribute in response");
+ return -1;
+ }
+ type = h->response[h->resp_pos++];
+ *len = h->response[h->resp_pos++] - 2;
+ if (h->resp_pos + (int)*len > h->resp_len) {
+ generr(h, "Malformed attribute in response");
+ return -1;
+ }
+ *value = &h->response[h->resp_pos];
+ h->resp_pos += *len;
+ return type;
+}
+
+/*
+ * Returns -1 on error, 0 to indicate no event and >0 for success
+ */
+int
+rad_init_send_request(struct rad_handle *h, int *fd, struct timeval *tv)
+{
+ int srv;
+
+ /* Make sure we have a socket to use */
+ if (h->fd == -1) {
+ struct sockaddr_in sin;
+
+ if ((h->fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
+ generr(h, "Cannot create socket: %s", strerror(errno));
+ return -1;
+ }
+ memset(&sin, 0, sizeof sin);
+ sin.sin_len = sizeof sin;
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = INADDR_ANY;
+ sin.sin_port = htons(0);
+ if (bind(h->fd, (const struct sockaddr *)&sin,
+ sizeof sin) == -1) {
+ generr(h, "bind: %s", strerror(errno));
+ close(h->fd);
+ h->fd = -1;
+ return -1;
+ }
+ }
+
+ if (h->request[POS_CODE] == RAD_ACCOUNTING_REQUEST) {
+ /* Make sure no password given */
+ if (h->pass_pos || h->chap_pass) {
+ generr(h, "User or Chap Password"
+ " in accounting request");
+ return -1;
+ }
+ } else {
+ if (h->eap_msg == 0) {
+ /* Make sure the user gave us a password */
+ if (h->pass_pos == 0 && !h->chap_pass) {
+ generr(h, "No User or Chap Password"
+ " attributes given");
+ return -1;
+ }
+ if (h->pass_pos != 0 && h->chap_pass) {
+ generr(h, "Both User and Chap Password"
+ " attributes given");
+ return -1;
+ }
+ }
+ }
+
+ /* Fill in the length field in the message */
+ h->request[POS_LENGTH] = h->req_len >> 8;
+ h->request[POS_LENGTH+1] = h->req_len;
+
+ /*
+ * Count the total number of tries we will make, and zero the
+ * counter for each server.
+ */
+ h->total_tries = 0;
+ for (srv = 0; srv < h->num_servers; srv++) {
+ h->total_tries += h->servers[srv].max_tries;
+ h->servers[srv].num_tries = 0;
+ }
+ if (h->total_tries == 0) {
+ generr(h, "No RADIUS servers specified");
+ return -1;
+ }
+
+ h->try = h->srv = 0;
+
+ return rad_continue_send_request(h, 0, fd, tv);
+}
+
+/*
+ * Create and initialize a rad_handle structure, and return it to the
+ * caller. Can fail only if the necessary memory cannot be allocated.
+ * In that case, it returns NULL.
+ */
+struct rad_handle *
+rad_auth_open(void)
+{
+ struct rad_handle *h;
+
+ h = (struct rad_handle *)malloc(sizeof(struct rad_handle));
+ if (h != NULL) {
+ srandomdev();
+ h->fd = -1;
+ h->num_servers = 0;
+ h->ident = random();
+ h->errmsg[0] = '\0';
+ memset(h->pass, 0, sizeof h->pass);
+ h->pass_len = 0;
+ h->pass_pos = 0;
+ h->chap_pass = 0;
+ h->authentic_pos = 0;
+ h->type = RADIUS_AUTH;
+ h->request_created = 0;
+ h->eap_msg = 0;
+ }
+ return h;
+}
+
+struct rad_handle *
+rad_acct_open(void)
+{
+ struct rad_handle *h;
+
+ h = rad_open();
+ if (h != NULL)
+ h->type = RADIUS_ACCT;
+ return h;
+}
+
+struct rad_handle *
+rad_open(void)
+{
+ return rad_auth_open();
+}
+
+int
+rad_put_addr(struct rad_handle *h, int type, struct in_addr addr)
+{
+ return rad_put_attr(h, type, &addr.s_addr, sizeof addr.s_addr);
+}
+
+int
+rad_put_attr(struct rad_handle *h, int type, const void *value, size_t len)
+{
+ int result;
+
+ if (!h->request_created) {
+ generr(h, "Please call rad_create_request()"
+ " before putting attributes");
+ return -1;
+ }
+
+ if (h->request[POS_CODE] == RAD_ACCOUNTING_REQUEST) {
+ if (type == RAD_EAP_MESSAGE) {
+ generr(h, "EAP-Message attribute is not valid"
+ " in accounting requests");
+ return -1;
+ }
+ }
+
+ /*
+ * When proxying EAP Messages, the Message Authenticator
+ * MUST be present; see RFC 3579.
+ */
+ if (type == RAD_EAP_MESSAGE) {
+ if (rad_put_message_authentic(h) == -1)
+ return -1;
+ }
+
+ if (type == RAD_USER_PASSWORD) {
+ result = put_password_attr(h, type, value, len);
+ } else if (type == RAD_MESSAGE_AUTHENTIC) {
+ result = rad_put_message_authentic(h);
+ } else {
+ result = put_raw_attr(h, type, value, len);
+ if (result == 0) {
+ if (type == RAD_CHAP_PASSWORD)
+ h->chap_pass = 1;
+ else if (type == RAD_EAP_MESSAGE)
+ h->eap_msg = 1;
+ }
+ }
+
+ return result;
+}
+
+int
+rad_put_int(struct rad_handle *h, int type, u_int32_t value)
+{
+ u_int32_t nvalue;
+
+ nvalue = htonl(value);
+ return rad_put_attr(h, type, &nvalue, sizeof nvalue);
+}
+
+int
+rad_put_string(struct rad_handle *h, int type, const char *str)
+{
+ return rad_put_attr(h, type, str, strlen(str));
+}
+
+int
+rad_put_message_authentic(struct rad_handle *h)
+{
+#ifdef WITH_SSL
+ u_char md_zero[MD5_DIGEST_LENGTH];
+
+ if (h->request[POS_CODE] == RAD_ACCOUNTING_REQUEST) {
+ generr(h, "Message-Authenticator is not valid"
+ " in accounting requests");
+ return -1;
+ }
+
+ if (h->authentic_pos == 0) {
+ h->authentic_pos = h->req_len;
+ memset(md_zero, 0, sizeof(md_zero));
+ return (put_raw_attr(h, RAD_MESSAGE_AUTHENTIC, md_zero,
+ sizeof(md_zero)));
+ }
+ return 0;
+#else
+ generr(h, "Message Authenticator not supported,"
+ " please recompile libradius with SSL support");
+ return -1;
+#endif
+}
+
+/*
+ * Returns the response type code on success, or -1 on failure.
+ */
+int
+rad_send_request(struct rad_handle *h)
+{
+ struct timeval timelimit;
+ struct timeval tv;
+ int fd;
+ int n;
+
+ n = rad_init_send_request(h, &fd, &tv);
+
+ if (n != 0)
+ return n;
+
+ gettimeofday(&timelimit, NULL);
+ timeradd(&tv, &timelimit, &timelimit);
+
+ for ( ; ; ) {
+ fd_set readfds;
+
+ FD_ZERO(&readfds);
+ FD_SET(fd, &readfds);
+
+ n = select(fd + 1, &readfds, NULL, NULL, &tv);
+
+ if (n == -1) {
+ generr(h, "select: %s", strerror(errno));
+ return -1;
+ }
+
+ if (!FD_ISSET(fd, &readfds)) {
+ /* Compute a new timeout */
+ gettimeofday(&tv, NULL);
+ timersub(&timelimit, &tv, &tv);
+ if (tv.tv_sec > 0 || (tv.tv_sec == 0 && tv.tv_usec > 0))
+ /* Continue the select */
+ continue;
+ }
+
+ n = rad_continue_send_request(h, n, &fd, &tv);
+
+ if (n != 0)
+ return n;
+
+ gettimeofday(&timelimit, NULL);
+ timeradd(&tv, &timelimit, &timelimit);
+ }
+}
+
+const char *
+rad_strerror(struct rad_handle *h)
+{
+ return h->errmsg;
+}
+
+/*
+ * Destructively split a string into fields separated by white space.
+ * `#' at the beginning of a field begins a comment that extends to the
+ * end of the string. Fields may be quoted with `"'. Inside quoted
+ * strings, the backslash escapes `\"' and `\\' are honored.
+ *
+ * Pointers to up to the first maxfields fields are stored in the fields
+ * array. Missing fields get NULL pointers.
+ *
+ * The return value is the actual number of fields parsed, and is always
+ * <= maxfields.
+ *
+ * On a syntax error, places a message in the msg string, and returns -1.
+ */
+static int
+split(char *str, char *fields[], int maxfields, char *msg, size_t msglen)
+{
+ char *p;
+ int i;
+ static const char ws[] = " \t";
+
+ for (i = 0; i < maxfields; i++)
+ fields[i] = NULL;
+ p = str;
+ i = 0;
+ while (*p != '\0') {
+ p += strspn(p, ws);
+ if (*p == '#' || *p == '\0')
+ break;
+ if (i >= maxfields) {
+ snprintf(msg, msglen, "line has too many fields");
+ return -1;
+ }
+ if (*p == '"') {
+ char *dst;
+
+ dst = ++p;
+ fields[i] = dst;
+ while (*p != '"') {
+ if (*p == '\\') {
+ p++;
+ if (*p != '"' && *p != '\\' &&
+ *p != '\0') {
+ snprintf(msg, msglen,
+ "invalid `\\' escape");
+ return -1;
+ }
+ }
+ if (*p == '\0') {
+ snprintf(msg, msglen,
+ "unterminated quoted string");
+ return -1;
+ }
+ *dst++ = *p++;
+ }
+ *dst = '\0';
+ p++;
+ if (*fields[i] == '\0') {
+ snprintf(msg, msglen,
+ "empty quoted string not permitted");
+ return -1;
+ }
+ if (*p != '\0' && strspn(p, ws) == 0) {
+ snprintf(msg, msglen, "quoted string not"
+ " followed by white space");
+ return -1;
+ }
+ } else {
+ fields[i] = p;
+ p += strcspn(p, ws);
+ if (*p != '\0')
+ *p++ = '\0';
+ }
+ i++;
+ }
+ return i;
+}
+
+int
+rad_get_vendor_attr(u_int32_t *vendor, const void **data, size_t *len)
+{
+ struct vendor_attribute *attr;
+
+ attr = (struct vendor_attribute *)*data;
+ *vendor = ntohl(attr->vendor_value);
+ *data = attr->attrib_data;
+ *len = attr->attrib_len - 2;
+
+ return (attr->attrib_type);
+}
+
+int
+rad_put_vendor_addr(struct rad_handle *h, int vendor, int type,
+ struct in_addr addr)
+{
+ return (rad_put_vendor_attr(h, vendor, type, &addr.s_addr,
+ sizeof addr.s_addr));
+}
+
+int
+rad_put_vendor_attr(struct rad_handle *h, int vendor, int type,
+ const void *value, size_t len)
+{
+ struct vendor_attribute *attr;
+ int res;
+
+ if (!h->request_created) {
+ generr(h, "Please call rad_create_request()"
+ " before putting attributes");
+ return -1;
+ }
+
+ if ((attr = malloc(len + 6)) == NULL) {
+ generr(h, "malloc failure (%zu bytes)", len + 6);
+ return -1;
+ }
+
+ attr->vendor_value = htonl(vendor);
+ attr->attrib_type = type;
+ attr->attrib_len = len + 2;
+ memcpy(attr->attrib_data, value, len);
+
+ res = put_raw_attr(h, RAD_VENDOR_SPECIFIC, attr, len + 6);
+ free(attr);
+ if (res == 0 && vendor == RAD_VENDOR_MICROSOFT
+ && (type == RAD_MICROSOFT_MS_CHAP_RESPONSE
+ || type == RAD_MICROSOFT_MS_CHAP2_RESPONSE)) {
+ h->chap_pass = 1;
+ }
+ return (res);
+}
+
+int
+rad_put_vendor_int(struct rad_handle *h, int vendor, int type, u_int32_t i)
+{
+ u_int32_t value;
+
+ value = htonl(i);
+ return (rad_put_vendor_attr(h, vendor, type, &value, sizeof value));
+}
+
+int
+rad_put_vendor_string(struct rad_handle *h, int vendor, int type,
+ const char *str)
+{
+ return (rad_put_vendor_attr(h, vendor, type, str, strlen(str)));
+}
+
+ssize_t
+rad_request_authenticator(struct rad_handle *h, char *buf, size_t len)
+{
+ if (len < LEN_AUTH)
+ return (-1);
+ memcpy(buf, h->request + POS_AUTH, LEN_AUTH);
+ if (len > LEN_AUTH)
+ buf[LEN_AUTH] = '\0';
+ return (LEN_AUTH);
+}
+
+u_char *
+rad_demangle(struct rad_handle *h, const void *mangled, size_t mlen)
+{
+ char R[LEN_AUTH];
+ const char *S;
+ int i, Ppos;
+ MD5_CTX Context;
+ u_char b[MD5_DIGEST_LENGTH], *C, *demangled;
+
+ if ((mlen % 16 != 0) || mlen > 128) {
+ generr(h, "Cannot interpret mangled data of length %lu",
+ (u_long)mlen);
+ return NULL;
+ }
+
+ C = (u_char *)mangled;
+
+ /* We need the shared secret as Salt */
+ S = rad_server_secret(h);
+
+ /* We need the request authenticator */
+ if (rad_request_authenticator(h, R, sizeof R) != LEN_AUTH) {
+ generr(h, "Cannot obtain the RADIUS request authenticator");
+ return NULL;
+ }
+
+ demangled = malloc(mlen);
+ if (!demangled)
+ return NULL;
+
+ MD5Init(&Context);
+ MD5Update(&Context, S, strlen(S));
+ MD5Update(&Context, R, LEN_AUTH);
+ MD5Final(b, &Context);
+ Ppos = 0;
+ while (mlen) {
+
+ mlen -= 16;
+ for (i = 0; i < 16; i++)
+ demangled[Ppos++] = C[i] ^ b[i];
+
+ if (mlen) {
+ MD5Init(&Context);
+ MD5Update(&Context, S, strlen(S));
+ MD5Update(&Context, C, 16);
+ MD5Final(b, &Context);
+ }
+
+ C += 16;
+ }
+
+ return demangled;
+}
+
+u_char *
+rad_demangle_mppe_key(struct rad_handle *h, const void *mangled,
+ size_t mlen, size_t *len)
+{
+ char R[LEN_AUTH]; /* variable names as per rfc2548 */
+ const char *S;
+ u_char b[MD5_DIGEST_LENGTH], *demangled;
+ const u_char *A, *C;
+ MD5_CTX Context;
+ int Slen, i, Clen, Ppos;
+ u_char *P;
+
+ if (mlen % 16 != SALT_LEN) {
+ generr(h, "Cannot interpret mangled data of length %lu",
+ (u_long)mlen);
+ return NULL;
+ }
+
+ /* We need the RADIUS Request-Authenticator */
+ if (rad_request_authenticator(h, R, sizeof R) != LEN_AUTH) {
+ generr(h, "Cannot obtain the RADIUS request authenticator");
+ return NULL;
+ }
+
+ A = (const u_char *)mangled; /* Salt comes first */
+ C = (const u_char *)mangled + SALT_LEN; /* Then the ciphertext */
+ Clen = mlen - SALT_LEN;
+ S = rad_server_secret(h); /* We need the RADIUS secret */
+ Slen = strlen(S);
+ P = alloca(Clen); /* We derive our plaintext */
+
+ MD5Init(&Context);
+ MD5Update(&Context, S, Slen);
+ MD5Update(&Context, R, LEN_AUTH);
+ MD5Update(&Context, A, SALT_LEN);
+ MD5Final(b, &Context);
+ Ppos = 0;
+
+ while (Clen) {
+ Clen -= 16;
+
+ for (i = 0; i < 16; i++)
+ P[Ppos++] = C[i] ^ b[i];
+
+ if (Clen) {
+ MD5Init(&Context);
+ MD5Update(&Context, S, Slen);
+ MD5Update(&Context, C, 16);
+ MD5Final(b, &Context);
+ }
+
+ C += 16;
+ }
+
+ /*
+ * The resulting plain text consists of a one-byte length, the text and
+ * maybe some padding.
+ */
+ *len = *P;
+ if (*len > mlen - 1) {
+ generr(h, "Mangled data seems to be garbage %zu %zu",
+ *len, mlen-1);
+ return NULL;
+ }
+
+ if (*len > MPPE_KEY_LEN * 2) {
+ generr(h, "Key to long (%zu) for me max. %d",
+ *len, MPPE_KEY_LEN * 2);
+ return NULL;
+ }
+ demangled = malloc(*len);
+ if (!demangled)
+ return NULL;
+
+ memcpy(demangled, P + 1, *len);
+ return demangled;
+}
+
+const char *
+rad_server_secret(struct rad_handle *h)
+{
+ return (h->servers[h->srv].secret);
+}
diff --git a/lib/libradius/radlib.h b/lib/libradius/radlib.h
new file mode 100644
index 0000000..2c42c3a
--- /dev/null
+++ b/lib/libradius/radlib.h
@@ -0,0 +1,220 @@
+/*-
+ * Copyright 1998 Juniper Networks, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _RADLIB_H_
+#define _RADLIB_H_
+
+#include <sys/types.h>
+#include <netinet/in.h>
+
+/* Limits */
+#define RAD_MAX_ATTR_LEN 253
+
+/* Message types */
+#define RAD_ACCESS_REQUEST 1
+#define RAD_ACCESS_ACCEPT 2
+#define RAD_ACCESS_REJECT 3
+#define RAD_ACCOUNTING_REQUEST 4
+#define RAD_ACCOUNTING_RESPONSE 5
+#define RAD_ACCESS_CHALLENGE 11
+
+/* Attribute types and values */
+#define RAD_USER_NAME 1 /* String */
+#define RAD_USER_PASSWORD 2 /* String */
+#define RAD_CHAP_PASSWORD 3 /* String */
+#define RAD_NAS_IP_ADDRESS 4 /* IP address */
+#define RAD_NAS_PORT 5 /* Integer */
+#define RAD_SERVICE_TYPE 6 /* Integer */
+ #define RAD_LOGIN 1
+ #define RAD_FRAMED 2
+ #define RAD_CALLBACK_LOGIN 3
+ #define RAD_CALLBACK_FRAMED 4
+ #define RAD_OUTBOUND 5
+ #define RAD_ADMINISTRATIVE 6
+ #define RAD_NAS_PROMPT 7
+ #define RAD_AUTHENTICATE_ONLY 8
+ #define RAD_CALLBACK_NAS_PROMPT 9
+#define RAD_FRAMED_PROTOCOL 7 /* Integer */
+ #define RAD_PPP 1
+ #define RAD_SLIP 2
+ #define RAD_ARAP 3 /* Appletalk */
+ #define RAD_GANDALF 4
+ #define RAD_XYLOGICS 5
+#define RAD_FRAMED_IP_ADDRESS 8 /* IP address */
+#define RAD_FRAMED_IP_NETMASK 9 /* IP address */
+#define RAD_FRAMED_ROUTING 10 /* Integer */
+#define RAD_FILTER_ID 11 /* String */
+#define RAD_FRAMED_MTU 12 /* Integer */
+#define RAD_FRAMED_COMPRESSION 13 /* Integer */
+ #define RAD_COMP_NONE 0
+ #define RAD_COMP_VJ 1
+ #define RAD_COMP_IPXHDR 2
+#define RAD_LOGIN_IP_HOST 14 /* IP address */
+#define RAD_LOGIN_SERVICE 15 /* Integer */
+#define RAD_LOGIN_TCP_PORT 16 /* Integer */
+ /* unassiged 17 */
+#define RAD_REPLY_MESSAGE 18 /* String */
+#define RAD_CALLBACK_NUMBER 19 /* String */
+#define RAD_CALLBACK_ID 20 /* String */
+ /* unassiged 21 */
+#define RAD_FRAMED_ROUTE 22 /* String */
+#define RAD_FRAMED_IPX_NETWORK 23 /* IP address */
+#define RAD_STATE 24 /* String */
+#define RAD_CLASS 25 /* Integer */
+#define RAD_VENDOR_SPECIFIC 26 /* Integer */
+#define RAD_SESSION_TIMEOUT 27 /* Integer */
+#define RAD_IDLE_TIMEOUT 28 /* Integer */
+#define RAD_TERMINATION_ACTION 29 /* Integer */
+#define RAD_CALLED_STATION_ID 30 /* String */
+#define RAD_CALLING_STATION_ID 31 /* String */
+#define RAD_NAS_IDENTIFIER 32 /* Integer */
+#define RAD_PROXY_STATE 33 /* Integer */
+#define RAD_LOGIN_LAT_SERVICE 34 /* Integer */
+#define RAD_LOGIN_LAT_NODE 35 /* Integer */
+#define RAD_LOGIN_LAT_GROUP 36 /* Integer */
+#define RAD_FRAMED_APPLETALK_LINK 37 /* Integer */
+#define RAD_FRAMED_APPLETALK_NETWORK 38 /* Integer */
+#define RAD_FRAMED_APPLETALK_ZONE 39 /* Integer */
+ /* reserved for accounting 40-59 */
+#define RAD_ACCT_INPUT_GIGAWORDS 52
+#define RAD_ACCT_OUTPUT_GIGAWORDS 53
+
+#define RAD_CHAP_CHALLENGE 60 /* String */
+#define RAD_NAS_PORT_TYPE 61 /* Integer */
+ #define RAD_ASYNC 0
+ #define RAD_SYNC 1
+ #define RAD_ISDN_SYNC 2
+ #define RAD_ISDN_ASYNC_V120 3
+ #define RAD_ISDN_ASYNC_V110 4
+ #define RAD_VIRTUAL 5
+ #define RAD_PIAFS 6
+ #define RAD_HDLC_CLEAR_CHANNEL 7
+ #define RAD_X_25 8
+ #define RAD_X_75 9
+ #define RAD_G_3_FAX 10
+ #define RAD_SDSL 11
+ #define RAD_ADSL_CAP 12
+ #define RAD_ADSL_DMT 13
+ #define RAD_IDSL 14
+ #define RAD_ETHERNET 15
+ #define RAD_XDSL 16
+ #define RAD_CABLE 17
+ #define RAD_WIRELESS_OTHER 18
+ #define RAD_WIRELESS_IEEE_802_11 19
+#define RAD_PORT_LIMIT 62 /* Integer */
+#define RAD_LOGIN_LAT_PORT 63 /* Integer */
+#define RAD_CONNECT_INFO 77 /* String */
+#define RAD_EAP_MESSAGE 79 /* Octets */
+#define RAD_MESSAGE_AUTHENTIC 80 /* Octets */
+#define RAD_ACCT_INTERIM_INTERVAL 85 /* Integer */
+#define RAD_NAS_IPV6_ADDRESS 95 /* IPv6 address */
+#define RAD_FRAMED_INTERFACE_ID 96 /* 8 octets */
+#define RAD_FRAMED_IPV6_PREFIX 97 /* Octets */
+#define RAD_LOGIN_IPV6_HOST 98 /* IPv6 address */
+#define RAD_FRAMED_IPV6_ROUTE 99 /* String */
+#define RAD_FRAMED_IPV6_POOL 100 /* String */
+
+/* Accounting attribute types and values */
+#define RAD_ACCT_STATUS_TYPE 40 /* Integer */
+ #define RAD_START 1
+ #define RAD_STOP 2
+ #define RAD_UPDATE 3
+ #define RAD_ACCOUNTING_ON 7
+ #define RAD_ACCOUNTING_OFF 8
+#define RAD_ACCT_DELAY_TIME 41 /* Integer */
+#define RAD_ACCT_INPUT_OCTETS 42 /* Integer */
+#define RAD_ACCT_OUTPUT_OCTETS 43 /* Integer */
+#define RAD_ACCT_SESSION_ID 44 /* String */
+#define RAD_ACCT_AUTHENTIC 45 /* Integer */
+ #define RAD_AUTH_RADIUS 1
+ #define RAD_AUTH_LOCAL 2
+ #define RAD_AUTH_REMOTE 3
+#define RAD_ACCT_SESSION_TIME 46 /* Integer */
+#define RAD_ACCT_INPUT_PACKETS 47 /* Integer */
+#define RAD_ACCT_OUTPUT_PACKETS 48 /* Integer */
+#define RAD_ACCT_TERMINATE_CAUSE 49 /* Integer */
+ #define RAD_TERM_USER_REQUEST 1
+ #define RAD_TERM_LOST_CARRIER 2
+ #define RAD_TERM_LOST_SERVICE 3
+ #define RAD_TERM_IDLE_TIMEOUT 4
+ #define RAD_TERM_SESSION_TIMEOUT 5
+ #define RAD_TERM_ADMIN_RESET 6
+ #define RAD_TERM_ADMIN_REBOOT 7
+ #define RAD_TERM_PORT_ERROR 8
+ #define RAD_TERM_NAS_ERROR 9
+ #define RAD_TERM_NAS_REQUEST 10
+ #define RAD_TERM_NAS_REBOOT 11
+ #define RAD_TERM_PORT_UNNEEDED 12
+ #define RAD_TERM_PORT_PREEMPTED 13
+ #define RAD_TERM_PORT_SUSPENDED 14
+ #define RAD_TERM_SERVICE_UNAVAILABLE 15
+ #define RAD_TERM_CALLBACK 16
+ #define RAD_TERM_USER_ERROR 17
+ #define RAD_TERM_HOST_REQUEST 18
+#define RAD_ACCT_MULTI_SESSION_ID 50 /* String */
+#define RAD_ACCT_LINK_COUNT 51 /* Integer */
+
+struct rad_handle;
+struct timeval;
+
+__BEGIN_DECLS
+struct rad_handle *rad_acct_open(void);
+int rad_add_server(struct rad_handle *,
+ const char *, int, const char *, int, int);
+struct rad_handle *rad_auth_open(void);
+void rad_close(struct rad_handle *);
+int rad_config(struct rad_handle *, const char *);
+int rad_continue_send_request(struct rad_handle *, int,
+ int *, struct timeval *);
+int rad_create_request(struct rad_handle *, int);
+struct in_addr rad_cvt_addr(const void *);
+u_int32_t rad_cvt_int(const void *);
+char *rad_cvt_string(const void *, size_t);
+int rad_get_attr(struct rad_handle *, const void **,
+ size_t *);
+int rad_init_send_request(struct rad_handle *, int *,
+ struct timeval *);
+struct rad_handle *rad_open(void); /* Deprecated, == rad_auth_open */
+int rad_put_addr(struct rad_handle *, int, struct in_addr);
+int rad_put_attr(struct rad_handle *, int,
+ const void *, size_t);
+int rad_put_int(struct rad_handle *, int, u_int32_t);
+int rad_put_string(struct rad_handle *, int,
+ const char *);
+int rad_put_message_authentic(struct rad_handle *);
+ssize_t rad_request_authenticator(struct rad_handle *, char *,
+ size_t);
+int rad_send_request(struct rad_handle *);
+const char *rad_server_secret(struct rad_handle *);
+const char *rad_strerror(struct rad_handle *);
+u_char *rad_demangle(struct rad_handle *, const void *,
+ size_t);
+
+__END_DECLS
+
+#endif /* _RADLIB_H_ */
diff --git a/lib/libradius/radlib_private.h b/lib/libradius/radlib_private.h
new file mode 100644
index 0000000..d323cbd
--- /dev/null
+++ b/lib/libradius/radlib_private.h
@@ -0,0 +1,103 @@
+/*-
+ * Copyright 1998 Juniper Networks, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef RADLIB_PRIVATE_H
+#define RADLIB_PRIVATE_H
+
+#include <sys/types.h>
+#include <netinet/in.h>
+
+#include "radlib.h"
+#include "radlib_vs.h"
+
+/* Handle types */
+#define RADIUS_AUTH 0 /* RADIUS authentication, default */
+#define RADIUS_ACCT 1 /* RADIUS accounting */
+
+/* Defaults */
+#define MAXTRIES 3
+#define PATH_RADIUS_CONF "/etc/radius.conf"
+#define RADIUS_PORT 1812
+#define RADACCT_PORT 1813
+#define TIMEOUT 3 /* In seconds */
+
+/* Limits */
+#define ERRSIZE 128 /* Maximum error message length */
+#define MAXCONFLINE 1024 /* Maximum config file line length */
+#define MAXSERVERS 10 /* Maximum number of servers to try */
+#define MSGSIZE 4096 /* Maximum RADIUS message */
+#define PASSSIZE 128 /* Maximum significant password chars */
+
+/* Positions of fields in RADIUS messages */
+#define POS_CODE 0 /* Message code */
+#define POS_IDENT 1 /* Identifier */
+#define POS_LENGTH 2 /* Message length */
+#define POS_AUTH 4 /* Authenticator */
+#define LEN_AUTH 16 /* Length of authenticator */
+#define POS_ATTRS 20 /* Start of attributes */
+
+struct rad_server {
+ struct sockaddr_in addr; /* Address of server */
+ char *secret; /* Shared secret */
+ int timeout; /* Timeout in seconds */
+ int max_tries; /* Number of tries before giving up */
+ int num_tries; /* Number of tries so far */
+};
+
+struct rad_handle {
+ int fd; /* Socket file descriptor */
+ struct rad_server servers[MAXSERVERS]; /* Servers to contact */
+ int num_servers; /* Number of valid server entries */
+ int ident; /* Current identifier value */
+ char errmsg[ERRSIZE]; /* Most recent error message */
+ unsigned char request[MSGSIZE]; /* Request to send */
+ char request_created; /* rad_create_request() called? */
+ int req_len; /* Length of request */
+ char pass[PASSSIZE]; /* Cleartext password */
+ int pass_len; /* Length of cleartext password */
+ int pass_pos; /* Position of scrambled password */
+ char chap_pass; /* Have we got a CHAP_PASSWORD ? */
+ int authentic_pos; /* Position of message authenticator */
+ char eap_msg; /* Are we an EAP Proxy? */
+ unsigned char response[MSGSIZE]; /* Response received */
+ int resp_len; /* Length of response */
+ int resp_pos; /* Current position scanning attrs */
+ int total_tries; /* How many requests we'll send */
+ int try; /* How many requests we've sent */
+ int srv; /* Server number we did last */
+ int type; /* Handle type */
+};
+
+struct vendor_attribute {
+ u_int32_t vendor_value;
+ u_char attrib_type;
+ u_char attrib_len;
+ u_char attrib_data[1];
+};
+
+#endif
diff --git a/lib/libradius/radlib_vs.h b/lib/libradius/radlib_vs.h
new file mode 100644
index 0000000..8b3a75e
--- /dev/null
+++ b/lib/libradius/radlib_vs.h
@@ -0,0 +1,84 @@
+/*-
+ * Copyright (c) 2002 Brian Somers <brian@Awfulhak.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 _RADLIB_VS_H_
+#define _RADLIB_VS_H_
+
+#include <sys/types.h>
+#include <netinet/in.h>
+
+#define RAD_VENDOR_MICROSOFT 311 /* rfc2548 */
+ #define RAD_MICROSOFT_MS_CHAP_RESPONSE 1
+ #define RAD_MICROSOFT_MS_CHAP_ERROR 2
+ #define RAD_MICROSOFT_MS_CHAP_PW_1 3
+ #define RAD_MICROSOFT_MS_CHAP_PW_2 4
+ #define RAD_MICROSOFT_MS_CHAP_LM_ENC_PW 5
+ #define RAD_MICROSOFT_MS_CHAP_NT_ENC_PW 6
+ #define RAD_MICROSOFT_MS_MPPE_ENCRYPTION_POLICY 7
+ #define RAD_MICROSOFT_MS_MPPE_ENCRYPTION_TYPES 8
+ #define RAD_MICROSOFT_MS_RAS_VENDOR 9
+ #define RAD_MICROSOFT_MS_CHAP_DOMAIN 10
+ #define RAD_MICROSOFT_MS_CHAP_CHALLENGE 11
+ #define RAD_MICROSOFT_MS_CHAP_MPPE_KEYS 12
+ #define RAD_MICROSOFT_MS_BAP_USAGE 13
+ #define RAD_MICROSOFT_MS_LINK_UTILIZATION_THRESHOLD 14
+ #define RAD_MICROSOFT_MS_LINK_DROP_TIME_LIMIT 15
+ #define RAD_MICROSOFT_MS_MPPE_SEND_KEY 16
+ #define RAD_MICROSOFT_MS_MPPE_RECV_KEY 17
+ #define RAD_MICROSOFT_MS_RAS_VERSION 18
+ #define RAD_MICROSOFT_MS_OLD_ARAP_PASSWORD 19
+ #define RAD_MICROSOFT_MS_NEW_ARAP_PASSWORD 20
+ #define RAD_MICROSOFT_MS_ARAP_PASSWORD_CHANGE_REASON 21
+ #define RAD_MICROSOFT_MS_FILTER 22
+ #define RAD_MICROSOFT_MS_ACCT_AUTH_TYPE 23
+ #define RAD_MICROSOFT_MS_ACCT_EAP_TYPE 24
+ #define RAD_MICROSOFT_MS_CHAP2_RESPONSE 25
+ #define RAD_MICROSOFT_MS_CHAP2_SUCCESS 26
+ #define RAD_MICROSOFT_MS_CHAP2_PW 27
+ #define RAD_MICROSOFT_MS_PRIMARY_DNS_SERVER 28
+ #define RAD_MICROSOFT_MS_SECONDARY_DNS_SERVER 29
+ #define RAD_MICROSOFT_MS_PRIMARY_NBNS_SERVER 30
+ #define RAD_MICROSOFT_MS_SECONDARY_NBNS_SERVER 31
+ #define RAD_MICROSOFT_MS_ARAP_CHALLENGE 33
+
+#define SALT_LEN 2
+
+struct rad_handle;
+
+__BEGIN_DECLS
+int rad_get_vendor_attr(u_int32_t *, const void **, size_t *);
+int rad_put_vendor_addr(struct rad_handle *, int, int, struct in_addr);
+int rad_put_vendor_attr(struct rad_handle *, int, int, const void *,
+ size_t);
+int rad_put_vendor_int(struct rad_handle *, int, int, u_int32_t);
+int rad_put_vendor_string(struct rad_handle *, int, int, const char *);
+u_char *rad_demangle_mppe_key(struct rad_handle *, const void *, size_t,
+ size_t *);
+__END_DECLS
+
+#endif /* _RADLIB_VS_H_ */
diff --git a/lib/librpcsvc/Makefile b/lib/librpcsvc/Makefile
new file mode 100644
index 0000000..3939a6a
--- /dev/null
+++ b/lib/librpcsvc/Makefile
@@ -0,0 +1,40 @@
+# from: @(#)Makefile 5.10 (Berkeley) 6/24/90
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+.PATH: ${.CURDIR}/../../include/rpcsvc
+
+LIB= rpcsvc
+
+RPCSRCS= klm_prot.x mount.x nfs_prot.x nlm_prot.x rex.x rnusers.x \
+ rquota.x rstat.x rwall.x sm_inter.x spray.x yppasswd.x ypxfrd.x \
+ ypupdate_prot.x
+
+OTHERSRCS= rnusers.c rstat.c rwall.c
+SECRPCSRCS= secretkey.c xcrypt.c
+
+.if ${MK_NIS} != "no"
+OTHERSRCS+= yp_passwd.c yp_update.c
+.endif
+
+RPCCOM = rpcgen -C
+
+INCDIRS= -I${DESTDIR}/usr/include/rpcsvc
+
+CFLAGS+= -DYP ${INCDIRS}
+
+GENSRCS= ${RPCSRCS:R:S/$/_xdr.c/g}
+SRCS+= ${GENSRCS} ${OTHERSRCS} ${SECRPCSRCS}
+
+CLEANFILES+= ${GENSRCS}
+
+.include <bsd.lib.mk>
+
+.SUFFIXES: .x _xdr.c
+
+.x_xdr.c:
+ ${RPCCOM} -c ${.IMPSRC} -o ${.TARGET}
+
+OBJS= ${RPCSRCS:R:S/$/_xdr.o/g} ${SECRPCSRCS:R:S/$/.o/g} \
+ ${OTHERSRCS:R:S/$/.o/g}
diff --git a/lib/librpcsvc/rnusers.c b/lib/librpcsvc/rnusers.c
new file mode 100644
index 0000000..49cab07
--- /dev/null
+++ b/lib/librpcsvc/rnusers.c
@@ -0,0 +1,72 @@
+/*
+ * Sun RPC 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 Sun RPC 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 or with the express written consent of
+ * Sun Microsystems, Inc.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)rnusers.c 1.2 91/03/11 TIRPC 1.0; from 1.7 89/03/24 SMI";
+#endif
+
+/*
+ * rnusers.c
+ *
+ * "High" level programmatic interface to rnusers RPC service.
+ *
+ * Copyright (c) 1985 by Sun Microsystems, Inc.
+ */
+
+#include <rpc/rpc.h>
+#include <rpcsvc/rnusers.h>
+
+int
+rusers(host, up)
+ char *host;
+ struct utmpidlearr *up;
+{
+ return (callrpc(host, RUSERSPROG, RUSERSVERS_IDLE, RUSERSPROC_NAMES,
+ (xdrproc_t)xdr_void, (char *) NULL,
+ (xdrproc_t)xdr_utmpidlearr, (char *) up));
+}
+
+int
+rnusers(host)
+ char *host;
+{
+ int nusers;
+
+ if (callrpc(host, RUSERSPROG, RUSERSVERS_ORIG, RUSERSPROC_NUM,
+ (xdrproc_t)xdr_void, (char *) NULL,
+ (xdrproc_t)xdr_u_long, (char *) &nusers) != 0)
+ return (-1);
+ else
+ return (nusers);
+}
+
diff --git a/lib/librpcsvc/rstat.c b/lib/librpcsvc/rstat.c
new file mode 100644
index 0000000..1c19c4e
--- /dev/null
+++ b/lib/librpcsvc/rstat.c
@@ -0,0 +1,71 @@
+/*
+ * Sun RPC 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 Sun RPC 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 or with the express written consent of
+ * Sun Microsystems, Inc.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)rstat.c 1.2 91/03/11 TIRPC 1.0; from 1.6 89/03/24 SMI";
+#endif
+
+/*
+ * Copyright (c) 1985 by Sun Microsystems, Inc.
+ */
+
+/*
+ * "High" level programmatic interface to rstat RPC service.
+ */
+#include <rpc/rpc.h>
+#include <rpcsvc/rstat.h>
+
+enum clnt_stat
+rstat(host, statp)
+ char *host;
+ struct statstime *statp;
+{
+ return (callrpc(host, RSTATPROG, RSTATVERS_TIME, RSTATPROC_STATS,
+ (xdrproc_t)xdr_void, (char *) NULL,
+ (xdrproc_t)xdr_statstime, (char *) statp));
+}
+
+int
+havedisk(host)
+ char *host;
+{
+ long have;
+
+ if (callrpc(host, RSTATPROG, RSTATVERS_SWTCH, RSTATPROC_HAVEDISK,
+ (xdrproc_t)xdr_void, (char *) NULL,
+ (xdrproc_t)xdr_long, (char *) &have) != 0)
+ return (-1);
+ else
+ return (have);
+}
+
diff --git a/lib/librpcsvc/rwall.c b/lib/librpcsvc/rwall.c
new file mode 100644
index 0000000..dd7b590
--- /dev/null
+++ b/lib/librpcsvc/rwall.c
@@ -0,0 +1,56 @@
+/*
+ * Sun RPC 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 Sun RPC 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 or with the express written consent of
+ * Sun Microsystems, Inc.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)rwall.c 1.2 91/03/11 TIRPC 1.0; from 1.3 89/03/24 SMI";
+#endif
+
+/*
+ * Copyright (c) 1985 by Sun Microsystems, Inc.
+ */
+
+/*
+ * "High" level programmatic interface to rwall RPC service.
+ */
+#include <rpc/rpc.h>
+#include <rpcsvc/rwall.h>
+
+int
+rwall(host, msg)
+ char *host;
+ char *msg;
+{
+ return (callrpc(host, WALLPROG, WALLVERS, WALLPROC_WALL,
+ (xdrproc_t)xdr_wrapstring, (char *) &msg,
+ (xdrproc_t)xdr_void, (char *) NULL));
+}
diff --git a/lib/librpcsvc/secretkey.c b/lib/librpcsvc/secretkey.c
new file mode 100644
index 0000000..f455445
--- /dev/null
+++ b/lib/librpcsvc/secretkey.c
@@ -0,0 +1,89 @@
+/*
+ * Sun RPC 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 Sun RPC 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 or with the express written consent of
+ * Sun Microsystems, Inc.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)secretkey.c 1.8 91/03/11 Copyr 1986 Sun Micro";
+#endif
+
+/*
+ * secretkey.c
+ * Copyright (C) 1986, Sun Microsystems, Inc.
+ */
+
+/*
+ * Secret key lookup routines
+ */
+#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>
+
+extern int xdecrypt( char *, char * );
+
+/*
+ * Get somebody's encrypted secret key from the database, using the given
+ * passwd to decrypt it.
+ */
+int
+getsecretkey(netname, secretkey, passwd)
+ char *netname;
+ char *secretkey;
+ char *passwd;
+{
+ char lookup[3 * HEXKEYBYTES];
+ char *p;
+
+ if (secretkey == NULL)
+ return (0);
+ if (!getpublicandprivatekey(netname, lookup))
+ return (0);
+ p = strchr(lookup, ':');
+ if (p == NULL) {
+ return (0);
+ }
+ p++;
+ if (!xdecrypt(p, passwd)) {
+ return (0);
+ }
+ if (memcmp(p, p + HEXKEYBYTES, KEYCHECKSUMSIZE) != 0) {
+ secretkey[0] = '\0';
+ return (1);
+ }
+ p[HEXKEYBYTES] = '\0';
+ (void) strncpy(secretkey, p, HEXKEYBYTES);
+ secretkey[HEXKEYBYTES] = '\0';
+ return (1);
+}
diff --git a/lib/librpcsvc/xcrypt.c b/lib/librpcsvc/xcrypt.c
new file mode 100644
index 0000000..ed6cbef
--- /dev/null
+++ b/lib/librpcsvc/xcrypt.c
@@ -0,0 +1,188 @@
+/*
+ * Sun RPC 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 Sun RPC 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.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC 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 SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+/*
+ * Hex encryption/decryption and utility routines
+ *
+ * Copyright (C) 1986, Sun Microsystems, Inc.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <rpc/des_crypt.h>
+
+static char hex[16] = {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f',
+};
+
+static char hexval( char );
+static void bin2hex( int, unsigned char *, char * );
+static void hex2bin( int, char *, char * );
+void passwd2des( char *, char * );
+
+/*
+ * Encrypt a secret key given passwd
+ * The secret key is passed and returned in hex notation.
+ * Its length must be a multiple of 16 hex digits (64 bits).
+ */
+int
+xencrypt(secret, passwd)
+ char *secret;
+ char *passwd;
+{
+ char key[8];
+ char ivec[8];
+ char *buf;
+ int err;
+ int len;
+
+ len = strlen(secret) / 2;
+ buf = malloc((unsigned)len);
+
+ hex2bin(len, secret, buf);
+ passwd2des(passwd, key);
+ bzero(ivec, 8);
+
+ err = cbc_crypt(key, buf, len, DES_ENCRYPT | DES_HW, ivec);
+ if (DES_FAILED(err)) {
+ free(buf);
+ return (0);
+ }
+ bin2hex(len, (unsigned char *) buf, secret);
+ free(buf);
+ return (1);
+}
+
+/*
+ * Decrypt secret key using passwd
+ * The secret key is passed and returned in hex notation.
+ * Once again, the length is a multiple of 16 hex digits
+ */
+int
+xdecrypt(secret, passwd)
+ char *secret;
+ char *passwd;
+{
+ char key[8];
+ char ivec[8];
+ char *buf;
+ int err;
+ int len;
+
+ len = strlen(secret) / 2;
+ buf = malloc((unsigned)len);
+
+ hex2bin(len, secret, buf);
+ passwd2des(passwd, key);
+ bzero(ivec, 8);
+
+ err = cbc_crypt(key, buf, len, DES_DECRYPT | DES_HW, ivec);
+ if (DES_FAILED(err)) {
+ free(buf);
+ return (0);
+ }
+ bin2hex(len, (unsigned char *) buf, secret);
+ free(buf);
+ return (1);
+}
+
+
+/*
+ * Turn password into DES key
+ */
+void
+passwd2des(pw, key)
+ char *pw;
+ char *key;
+{
+ int i;
+
+ bzero(key, 8);
+ for (i = 0; *pw; i = (i+1)%8) {
+ key[i] ^= *pw++ << 1;
+ }
+ des_setparity(key);
+}
+
+
+
+/*
+ * Hex to binary conversion
+ */
+static void
+hex2bin(len, hexnum, binnum)
+ int len;
+ char *hexnum;
+ char *binnum;
+{
+ int i;
+
+ for (i = 0; i < len; i++) {
+ *binnum++ = 16 * hexval(hexnum[2*i]) + hexval(hexnum[2*i+1]);
+ }
+}
+
+/*
+ * Binary to hex conversion
+ */
+static void
+bin2hex(len, binnum, hexnum)
+ int len;
+ unsigned char *binnum;
+ char *hexnum;
+{
+ int i;
+ unsigned val;
+
+ for (i = 0; i < len; i++) {
+ val = binnum[i];
+ hexnum[i*2] = hex[val >> 4];
+ hexnum[i*2+1] = hex[val & 0xf];
+ }
+ hexnum[len*2] = 0;
+}
+
+static char
+hexval(c)
+ char c;
+{
+ if (c >= '0' && c <= '9') {
+ return (c - '0');
+ } else if (c >= 'a' && c <= 'z') {
+ return (c - 'a' + 10);
+ } else if (c >= 'A' && c <= 'Z') {
+ return (c - 'A' + 10);
+ } else {
+ return (-1);
+ }
+}
diff --git a/lib/librpcsvc/yp_passwd.c b/lib/librpcsvc/yp_passwd.c
new file mode 100644
index 0000000..e7c5914
--- /dev/null
+++ b/lib/librpcsvc/yp_passwd.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 1995, 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 <stdlib.h>
+#include <rpc/rpc.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+#include <rpcsvc/yppasswd.h>
+#include <netinet/in.h>
+
+/*
+ * XXX <rpcsvc/yppasswd.h> does a typedef that makes 'yppasswd'
+ * a type of struct yppasswd. This leads to a namespace collision:
+ * gcc will not let you have a type called yppasswd and a function
+ * called yppasswd(). In order to get around this, we call the
+ * actual function _yppasswd() and put a macro called yppasswd()
+ * in yppasswd.h which calls the underlying function, thereby
+ * fooling gcc.
+ */
+
+int
+_yppasswd(char *oldpass, struct x_passwd *newpw)
+{
+ char *server;
+ char *domain;
+ int rval, result;
+ struct yppasswd yppasswd;
+
+ yppasswd.newpw = *newpw;
+ yppasswd.oldpass = oldpass;
+
+ if (yp_get_default_domain(&domain))
+ return (-1);
+
+ if (yp_master(domain, "passwd.byname", &server))
+ return(-1);
+
+ rval = getrpcport(server, YPPASSWDPROG,
+ YPPASSWDPROC_UPDATE, IPPROTO_UDP);
+
+ if (rval == 0 || rval >= IPPORT_RESERVED) {
+ free(server);
+ return(-1);
+ }
+
+ rval = callrpc(server, YPPASSWDPROG, YPPASSWDVERS, YPPASSWDPROC_UPDATE,
+ (xdrproc_t)xdr_yppasswd, (char *)&yppasswd,
+ (xdrproc_t)xdr_int, (char *)&result);
+
+ free(server);
+ if (rval || result)
+ return(-1);
+ else
+ return(0);
+}
diff --git a/lib/librpcsvc/yp_update.c b/lib/librpcsvc/yp_update.c
new file mode 100644
index 0000000..1d2848d
--- /dev/null
+++ b/lib/librpcsvc/yp_update.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 1995, 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.
+ *
+ * ypupdate client-side library function.
+ *
+ * Written by Bill Paul <wpaul@ctr.columbia.edu>
+ * Center for Telecommunications Research
+ * Columbia University, New York City
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h>
+#include <rpc/rpc.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+#include <rpcsvc/ypupdate_prot.h>
+#include <rpc/key_prot.h>
+
+#ifndef WINDOW
+#define WINDOW (60*60)
+#endif
+
+#ifndef TIMEOUT
+#define TIMEOUT 300
+#endif
+
+int
+yp_update(char *domain, char *map, unsigned int ypop, char *key, int keylen,
+ char *data, int datalen)
+{
+ char *master;
+ int rval;
+ unsigned int res;
+ struct ypupdate_args upargs;
+ struct ypdelete_args delargs;
+ CLIENT *clnt;
+ char netname[MAXNETNAMELEN+1];
+ des_block des_key;
+ struct timeval timeout;
+
+ /* Get the master server name for 'domain.' */
+ if ((rval = yp_master(domain, map, &master)))
+ return(rval);
+
+ /* Check that ypupdated is running there. */
+ if (getrpcport(master, YPU_PROG, YPU_VERS, ypop))
+ return(YPERR_DOMAIN);
+
+ /* Get a handle. */
+ if ((clnt = clnt_create(master, YPU_PROG, YPU_VERS, "tcp")) == NULL)
+ return(YPERR_RPC);
+
+ /*
+ * Assemble netname of server.
+ * NOTE: It's difficult to discern from the documentation, but
+ * when you make a Secure RPC call, the netname you pass should
+ * be the netname of the guy on the other side, not your own
+ * netname. This is how the client side knows what public key
+ * to use for the initial exchange. Passing your own netname
+ * only works if the server on the other side is running under
+ * your UID.
+ */
+ if (!host2netname(netname, master, domain)) {
+ clnt_destroy(clnt);
+ return(YPERR_BADARGS);
+ }
+
+ /* Make up a DES session key. */
+ key_gendes(&des_key);
+
+ /* Set up DES authentication. */
+ if ((clnt->cl_auth = (AUTH *)authdes_create(netname, WINDOW, NULL,
+ &des_key)) == NULL) {
+ clnt_destroy(clnt);
+ return(YPERR_RESRC);
+ }
+
+ /* Set a timeout for clnt_call(). */
+ timeout.tv_usec = 0;
+ timeout.tv_sec = TIMEOUT;
+
+ /*
+ * Make the call. Note that we use clnt_call() here rather than
+ * the rpcgen-erated client stubs. We could use those stubs, but
+ * then we'd have to do some gymnastics to get at the error
+ * information to figure out what error code to send back to the
+ * caller. With clnt_call(), we get the error status returned to
+ * us right away, and we only have to exert a small amount of
+ * extra effort.
+ */
+ switch (ypop) {
+ case YPOP_CHANGE:
+ upargs.mapname = map;
+ upargs.key.yp_buf_len = keylen;
+ upargs.key.yp_buf_val = key;
+ upargs.datum.yp_buf_len = datalen;
+ upargs.datum.yp_buf_val = data;
+
+ if ((rval = clnt_call(clnt, YPU_CHANGE,
+ (xdrproc_t)xdr_ypupdate_args, &upargs,
+ (xdrproc_t)xdr_u_int, &res, timeout)) != RPC_SUCCESS) {
+ if (rval == RPC_AUTHERROR)
+ res = YPERR_ACCESS;
+ else
+ res = YPERR_RPC;
+ }
+
+ break;
+ case YPOP_INSERT:
+ upargs.mapname = map;
+ upargs.key.yp_buf_len = keylen;
+ upargs.key.yp_buf_val = key;
+ upargs.datum.yp_buf_len = datalen;
+ upargs.datum.yp_buf_val = data;
+
+ if ((rval = clnt_call(clnt, YPU_INSERT,
+ (xdrproc_t)xdr_ypupdate_args, &upargs,
+ (xdrproc_t)xdr_u_int, &res, timeout)) != RPC_SUCCESS) {
+ if (rval == RPC_AUTHERROR)
+ res = YPERR_ACCESS;
+ else
+ res = YPERR_RPC;
+ }
+
+ break;
+ case YPOP_DELETE:
+ delargs.mapname = map;
+ delargs.key.yp_buf_len = keylen;
+ delargs.key.yp_buf_val = key;
+
+ if ((rval = clnt_call(clnt, YPU_DELETE,
+ (xdrproc_t)xdr_ypdelete_args, &delargs,
+ (xdrproc_t)xdr_u_int, &res, timeout)) != RPC_SUCCESS) {
+ if (rval == RPC_AUTHERROR)
+ res = YPERR_ACCESS;
+ else
+ res = YPERR_RPC;
+ }
+
+ break;
+ case YPOP_STORE:
+ upargs.mapname = map;
+ upargs.key.yp_buf_len = keylen;
+ upargs.key.yp_buf_val = key;
+ upargs.datum.yp_buf_len = datalen;
+ upargs.datum.yp_buf_val = data;
+
+ if ((rval = clnt_call(clnt, YPU_STORE,
+ (xdrproc_t)xdr_ypupdate_args, &upargs,
+ (xdrproc_t)xdr_u_int, &res, timeout)) != RPC_SUCCESS) {
+ if (rval == RPC_AUTHERROR)
+ res = YPERR_ACCESS;
+ else
+ res = YPERR_RPC;
+ }
+
+ break;
+ default:
+ res = YPERR_BADARGS;
+ break;
+ }
+
+ /* All done: tear down the connection. */
+ auth_destroy(clnt->cl_auth);
+ clnt_destroy(clnt);
+ free(master);
+
+ return(res);
+}
diff --git a/lib/librt/Makefile b/lib/librt/Makefile
new file mode 100644
index 0000000..ea42355
--- /dev/null
+++ b/lib/librt/Makefile
@@ -0,0 +1,14 @@
+# $FreeBSD$
+
+LIB=rt
+SHLIB_MAJOR= 1
+CFLAGS+=-I${.CURDIR}/../libc/include -I${.CURDIR}
+CFLAGS+=-Winline -Wall -g
+
+#MAN= libthr.3
+
+SRCS+= aio.c mq.c sigev_thread.c timer.c
+
+PRECIOUSLIB=
+
+.include <bsd.lib.mk>
diff --git a/lib/librt/aio.c b/lib/librt/aio.c
new file mode 100644
index 0000000..25d7662
--- /dev/null
+++ b/lib/librt/aio.c
@@ -0,0 +1,196 @@
+/*
+ * 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 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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, 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$
+ *
+ */
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <sys/aio.h>
+
+#include "namespace.h"
+#include <errno.h>
+#include <stddef.h>
+#include <signal.h>
+#include "sigev_thread.h"
+#include "un-namespace.h"
+
+__weak_reference(__aio_read, _aio_read);
+__weak_reference(__aio_read, aio_read);
+__weak_reference(__aio_write, _aio_write);
+__weak_reference(__aio_write, aio_write);
+__weak_reference(__aio_return, _aio_return);
+__weak_reference(__aio_return, aio_return);
+__weak_reference(__aio_waitcomplete, _aio_waitcomplete);
+__weak_reference(__aio_waitcomplete, aio_waitcomplete);
+__weak_reference(__aio_fsync, _aio_fsync);
+__weak_reference(__aio_fsync, aio_fsync);
+
+typedef void (*aio_func)(union sigval val, struct aiocb *iocb);
+
+extern int __sys_aio_read(struct aiocb *iocb);
+extern int __sys_aio_write(struct aiocb *iocb);
+extern int __sys_aio_waitcomplete(struct aiocb **iocbp, struct timespec *timeout);
+extern int __sys_aio_return(struct aiocb *iocb);
+extern int __sys_aio_error(struct aiocb *iocb);
+extern int __sys_aio_fsync(int op, struct aiocb *iocb);
+
+static void
+aio_dispatch(struct sigev_node *sn)
+{
+ aio_func f = sn->sn_func;
+
+ f(sn->sn_value, (struct aiocb *)sn->sn_id);
+}
+
+static int
+aio_sigev_alloc(struct aiocb *iocb, struct sigev_node **sn,
+ struct sigevent *saved_ev)
+{
+ if (__sigev_check_init()) {
+ /* This might be that thread library is not enabled. */
+ errno = EINVAL;
+ return (-1);
+ }
+
+ *sn = __sigev_alloc(SI_ASYNCIO, &iocb->aio_sigevent, NULL, 1);
+ if (*sn == NULL) {
+ errno = EAGAIN;
+ return (-1);
+ }
+
+ *saved_ev = iocb->aio_sigevent;
+ (*sn)->sn_id = (sigev_id_t)iocb;
+ __sigev_get_sigevent(*sn, &iocb->aio_sigevent, (*sn)->sn_id);
+ (*sn)->sn_dispatch = aio_dispatch;
+
+ __sigev_list_lock();
+ __sigev_register(*sn);
+ __sigev_list_unlock();
+
+ return (0);
+}
+
+static int
+aio_io(struct aiocb *iocb, int (*sysfunc)(struct aiocb *iocb))
+{
+ struct sigev_node *sn;
+ struct sigevent saved_ev;
+ int ret, err;
+
+ if (iocb->aio_sigevent.sigev_notify != SIGEV_THREAD) {
+ ret = sysfunc(iocb);
+ return (ret);
+ }
+
+ ret = aio_sigev_alloc(iocb, &sn, &saved_ev);
+ if (ret)
+ return (ret);
+ ret = sysfunc(iocb);
+ iocb->aio_sigevent = saved_ev;
+ if (ret != 0) {
+ err = errno;
+ __sigev_list_lock();
+ __sigev_delete_node(sn);
+ __sigev_list_unlock();
+ errno = err;
+ }
+ return (ret);
+}
+
+int
+__aio_read(struct aiocb *iocb)
+{
+
+ return aio_io(iocb, &__sys_aio_read);
+}
+
+int
+__aio_write(struct aiocb *iocb)
+{
+
+ return aio_io(iocb, &__sys_aio_write);
+}
+
+int
+__aio_waitcomplete(struct aiocb **iocbp, struct timespec *timeout)
+{
+ int err;
+ int ret = __sys_aio_waitcomplete(iocbp, timeout);
+
+ if (*iocbp) {
+ if ((*iocbp)->aio_sigevent.sigev_notify == SIGEV_THREAD) {
+ err = errno;
+ __sigev_list_lock();
+ __sigev_delete(SI_ASYNCIO, (sigev_id_t)(*iocbp));
+ __sigev_list_unlock();
+ errno = err;
+ }
+ }
+
+ return (ret);
+}
+
+int
+__aio_return(struct aiocb *iocb)
+{
+
+ if (iocb->aio_sigevent.sigev_notify == SIGEV_THREAD) {
+ if (__sys_aio_error(iocb) == EINPROGRESS)
+ return (EINPROGRESS);
+ __sigev_list_lock();
+ __sigev_delete(SI_ASYNCIO, (sigev_id_t)iocb);
+ __sigev_list_unlock();
+ }
+
+ return __sys_aio_return(iocb);
+}
+
+int
+__aio_fsync(int op, struct aiocb *iocb)
+{
+ struct sigev_node *sn;
+ struct sigevent saved_ev;
+ int ret, err;
+
+ if (iocb->aio_sigevent.sigev_notify != SIGEV_THREAD)
+ return __sys_aio_fsync(op, iocb);
+
+ ret = aio_sigev_alloc(iocb, &sn, &saved_ev);
+ if (ret)
+ return (ret);
+ ret = __sys_aio_fsync(op, iocb);
+ iocb->aio_sigevent = saved_ev;
+ if (ret != 0) {
+ err = errno;
+ __sigev_list_lock();
+ __sigev_delete_node(sn);
+ __sigev_list_unlock();
+ errno = err;
+ }
+ return (ret);
+}
diff --git a/lib/librt/mq.c b/lib/librt/mq.c
new file mode 100644
index 0000000..9bdb503
--- /dev/null
+++ b/lib/librt/mq.c
@@ -0,0 +1,232 @@
+/*-
+ * Copyright (c) 2006 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <sys/mqueue.h>
+
+#include "namespace.h"
+#include <errno.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <signal.h>
+#include "sigev_thread.h"
+#include "un-namespace.h"
+
+extern int __sys_kmq_notify(int, const struct sigevent *);
+extern int __sys_kmq_open(const char *, int, mode_t,
+ const struct mq_attr *);
+extern int __sys_kmq_setattr(int, const struct mq_attr *__restrict,
+ struct mq_attr *__restrict);
+extern ssize_t __sys_kmq_timedreceive(int, char *__restrict, size_t,
+ unsigned *__restrict, const struct timespec *__restrict);
+extern int __sys_kmq_timedsend(int, const char *, size_t, unsigned,
+ const struct timespec *);
+extern int __sys_kmq_unlink(const char *);
+extern int __sys_close(int fd);
+
+struct __mq {
+ int oshandle;
+ struct sigev_node *node;
+};
+
+__weak_reference(__mq_open, mq_open);
+__weak_reference(__mq_open, _mq_open);
+__weak_reference(__mq_close, mq_close);
+__weak_reference(__mq_close, _mq_close);
+__weak_reference(__mq_notify, mq_notify);
+__weak_reference(__mq_notify, _mq_notify);
+__weak_reference(__mq_getattr, mq_getattr);
+__weak_reference(__mq_getattr, _mq_getattr);
+__weak_reference(__mq_setattr, mq_setattr);
+__weak_reference(__mq_setattr, _mq_setattr);
+__weak_reference(__mq_timedreceive, mq_timedreceive);
+__weak_reference(__mq_timedreceive, _mq_timedreceive);
+__weak_reference(__mq_timedsend, mq_timedsend);
+__weak_reference(__mq_timedsend, _mq_timedsend);
+__weak_reference(__mq_unlink, mq_unlink);
+__weak_reference(__mq_unlink, _mq_unlink);
+__weak_reference(__mq_send, mq_send);
+__weak_reference(__mq_send, _mq_send);
+__weak_reference(__mq_receive, mq_receive);
+__weak_reference(__mq_receive, _mq_receive);
+
+mqd_t
+__mq_open(const char *name, int oflag, mode_t mode,
+ const struct mq_attr *attr)
+{
+ struct __mq *mq;
+ int err;
+
+ mq = malloc(sizeof(struct __mq));
+ if (mq == NULL)
+ return (NULL);
+
+ mq->oshandle = __sys_kmq_open(name, oflag, mode, attr);
+ if (mq->oshandle != -1) {
+ mq->node = NULL;
+ return (mq);
+ }
+ err = errno;
+ free(mq);
+ errno = err;
+ return ((mqd_t)-1L);
+}
+
+int
+__mq_close(mqd_t mqd)
+{
+ int h;
+
+ if (mqd->node != NULL) {
+ __sigev_list_lock();
+ __sigev_delete_node(mqd->node);
+ __sigev_list_unlock();
+ }
+ h = mqd->oshandle;
+ free(mqd);
+ return (__sys_close(h));
+}
+
+typedef void (*mq_func)(union sigval val);
+
+static void
+mq_dispatch(struct sigev_node *sn)
+{
+ mq_func f = sn->sn_func;
+
+ /*
+ * Check generation before calling user function,
+ * this should avoid expired notification.
+ */
+ if (sn->sn_gen == sn->sn_info.si_value.sival_int)
+ f(sn->sn_value);
+}
+
+int
+__mq_notify(mqd_t mqd, const struct sigevent *evp)
+{
+ struct sigevent ev;
+ struct sigev_node *sn;
+ int ret;
+
+ if (evp == NULL || evp->sigev_notify != SIGEV_THREAD) {
+ if (mqd->node != NULL) {
+ __sigev_list_lock();
+ __sigev_delete_node(mqd->node);
+ mqd->node = NULL;
+ __sigev_list_unlock();
+ }
+ return __sys_kmq_notify(mqd->oshandle, evp);
+ }
+
+ if (__sigev_check_init()) {
+ /*
+ * Thread library is not enabled.
+ */
+ errno = EINVAL;
+ return (-1);
+ }
+
+ sn = __sigev_alloc(SI_MESGQ, evp, mqd->node, 1);
+ if (sn == NULL) {
+ errno = EAGAIN;
+ return (-1);
+ }
+
+ sn->sn_id = mqd->oshandle;
+ sn->sn_dispatch = mq_dispatch;
+ __sigev_get_sigevent(sn, &ev, sn->sn_gen);
+ __sigev_list_lock();
+ if (mqd->node != NULL)
+ __sigev_delete_node(mqd->node);
+ mqd->node = sn;
+ __sigev_register(sn);
+ ret = __sys_kmq_notify(mqd->oshandle, &ev);
+ __sigev_list_unlock();
+ return (ret);
+}
+
+int
+__mq_getattr(mqd_t mqd, struct mq_attr *attr)
+{
+
+ return __sys_kmq_setattr(mqd->oshandle, NULL, attr);
+}
+
+int
+__mq_setattr(mqd_t mqd, const struct mq_attr *newattr, struct mq_attr *oldattr)
+{
+
+ return __sys_kmq_setattr(mqd->oshandle, newattr, oldattr);
+}
+
+ssize_t
+__mq_timedreceive(mqd_t mqd, char *buf, size_t len,
+ unsigned *prio, const struct timespec *timeout)
+{
+
+ return __sys_kmq_timedreceive(mqd->oshandle, buf, len, prio, timeout);
+}
+
+ssize_t
+__mq_receive(mqd_t mqd, char *buf, size_t len, unsigned *prio)
+{
+
+ return __sys_kmq_timedreceive(mqd->oshandle, buf, len, prio, NULL);
+}
+
+ssize_t
+__mq_timedsend(mqd_t mqd, char *buf, size_t len,
+ unsigned prio, const struct timespec *timeout)
+{
+
+ return __sys_kmq_timedsend(mqd->oshandle, buf, len, prio, timeout);
+}
+
+ssize_t
+__mq_send(mqd_t mqd, char *buf, size_t len, unsigned prio)
+{
+
+ return __sys_kmq_timedsend(mqd->oshandle, buf, len, prio, NULL);
+}
+
+int
+__mq_unlink(const char *path)
+{
+
+ return __sys_kmq_unlink(path);
+}
+
+int
+__mq_oshandle(mqd_t mqd)
+{
+
+ return (mqd->oshandle);
+}
diff --git a/lib/librt/sigev_thread.c b/lib/librt/sigev_thread.c
new file mode 100644
index 0000000..928ba1e
--- /dev/null
+++ b/lib/librt/sigev_thread.c
@@ -0,0 +1,465 @@
+/*
+ * 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 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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, 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$
+ *
+ */
+
+#include <sys/types.h>
+#include <machine/atomic.h>
+
+#include "namespace.h"
+#include <err.h>
+#include <errno.h>
+#include <ucontext.h>
+#include <sys/thr.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "sigev_thread.h"
+
+LIST_HEAD(sigev_list_head, sigev_node);
+#define HASH_QUEUES 17
+#define HASH(t, id) ((((id) << 3) + (t)) % HASH_QUEUES)
+
+static struct sigev_list_head sigev_hash[HASH_QUEUES];
+static struct sigev_list_head sigev_all;
+static LIST_HEAD(,sigev_thread) sigev_threads;
+static int sigev_generation;
+static pthread_mutex_t *sigev_list_mtx;
+static pthread_once_t sigev_once = PTHREAD_ONCE_INIT;
+static pthread_once_t sigev_once_default = PTHREAD_ONCE_INIT;
+static struct sigev_thread *sigev_default_thread;
+static pthread_attr_t sigev_default_attr;
+static int atfork_registered;
+
+static void __sigev_fork_prepare(void);
+static void __sigev_fork_parent(void);
+static void __sigev_fork_child(void);
+static struct sigev_thread *sigev_thread_create(int);
+static void *sigev_service_loop(void *);
+static void *worker_routine(void *);
+static void worker_cleanup(void *);
+
+#pragma weak _pthread_create
+
+static void
+attrcopy(pthread_attr_t *src, pthread_attr_t *dst)
+{
+ struct sched_param sched;
+ void *a;
+ size_t u;
+ int v;
+
+ _pthread_attr_getschedpolicy(src, &v);
+ _pthread_attr_setschedpolicy(dst, v);
+
+ _pthread_attr_getinheritsched(src, &v);
+ _pthread_attr_setinheritsched(dst, v);
+
+ _pthread_attr_getschedparam(src, &sched);
+ _pthread_attr_setschedparam(dst, &sched);
+
+ _pthread_attr_getscope(src, &v);
+ _pthread_attr_setscope(dst, v);
+
+ _pthread_attr_getstacksize(src, &u);
+ _pthread_attr_setstacksize(dst, u);
+
+ _pthread_attr_getstackaddr(src, &a);
+ _pthread_attr_setstackaddr(src, a);
+
+ _pthread_attr_getguardsize(src, &u);
+ _pthread_attr_setguardsize(dst, u);
+}
+
+static __inline int
+have_threads(void)
+{
+ return (&_pthread_create != NULL);
+}
+
+void
+__sigev_thread_init(void)
+{
+ static int inited = 0;
+ pthread_mutexattr_t mattr;
+ int i;
+
+ _pthread_mutexattr_init(&mattr);
+ _pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_NORMAL);
+ sigev_list_mtx = malloc(sizeof(pthread_mutex_t));
+ _pthread_mutex_init(sigev_list_mtx, &mattr);
+ _pthread_mutexattr_destroy(&mattr);
+
+ for (i = 0; i < HASH_QUEUES; ++i)
+ LIST_INIT(&sigev_hash[i]);
+ LIST_INIT(&sigev_all);
+ LIST_INIT(&sigev_threads);
+ sigev_default_thread = NULL;
+ if (atfork_registered == 0) {
+ _pthread_atfork(
+ __sigev_fork_prepare,
+ __sigev_fork_parent,
+ __sigev_fork_child);
+ atfork_registered = 1;
+ }
+ if (!inited) {
+ _pthread_attr_init(&sigev_default_attr);
+ _pthread_attr_setscope(&sigev_default_attr,
+ PTHREAD_SCOPE_SYSTEM);
+ _pthread_attr_setdetachstate(&sigev_default_attr,
+ PTHREAD_CREATE_DETACHED);
+ inited = 1;
+ }
+ sigev_default_thread = sigev_thread_create(0);
+}
+
+int
+__sigev_check_init(void)
+{
+ if (!have_threads())
+ return (-1);
+
+ _pthread_once(&sigev_once, __sigev_thread_init);
+ return (sigev_default_thread != NULL) ? 0 : -1;
+}
+
+static void
+__sigev_fork_prepare(void)
+{
+}
+
+static void
+__sigev_fork_parent(void)
+{
+}
+
+static void
+__sigev_fork_child(void)
+{
+ /*
+ * This is a hack, the thread libraries really should
+ * check if the handlers were already registered in
+ * pthread_atfork().
+ */
+ atfork_registered = 1;
+ memcpy(&sigev_once, &sigev_once_default, sizeof(sigev_once));
+ __sigev_thread_init();
+}
+
+void
+__sigev_list_lock(void)
+{
+ _pthread_mutex_lock(sigev_list_mtx);
+}
+
+void
+__sigev_list_unlock(void)
+{
+ _pthread_mutex_unlock(sigev_list_mtx);
+}
+
+struct sigev_node *
+__sigev_alloc(int type, const struct sigevent *evp, struct sigev_node *prev,
+ int usedefault)
+{
+ struct sigev_node *sn;
+
+ sn = calloc(1, sizeof(*sn));
+ if (sn != NULL) {
+ sn->sn_value = evp->sigev_value;
+ sn->sn_func = evp->sigev_notify_function;
+ sn->sn_gen = atomic_fetchadd_int(&sigev_generation, 1);
+ sn->sn_type = type;
+ _pthread_attr_init(&sn->sn_attr);
+ _pthread_attr_setdetachstate(&sn->sn_attr, PTHREAD_CREATE_DETACHED);
+ if (evp->sigev_notify_attributes)
+ attrcopy(evp->sigev_notify_attributes, &sn->sn_attr);
+ if (prev) {
+ __sigev_list_lock();
+ prev->sn_tn->tn_refcount++;
+ __sigev_list_unlock();
+ sn->sn_tn = prev->sn_tn;
+ } else {
+ sn->sn_tn = sigev_thread_create(usedefault);
+ if (sn->sn_tn == NULL) {
+ _pthread_attr_destroy(&sn->sn_attr);
+ free(sn);
+ sn = NULL;
+ }
+ }
+ }
+ return (sn);
+}
+
+void
+__sigev_get_sigevent(struct sigev_node *sn, struct sigevent *newevp,
+ sigev_id_t id)
+{
+ /*
+ * Build a new sigevent, and tell kernel to deliver SIGSERVICE
+ * signal to the new thread.
+ */
+ newevp->sigev_notify = SIGEV_THREAD_ID;
+ newevp->sigev_signo = SIGSERVICE;
+ newevp->sigev_notify_thread_id = (lwpid_t)sn->sn_tn->tn_lwpid;
+ newevp->sigev_value.sival_ptr = (void *)id;
+}
+
+void
+__sigev_free(struct sigev_node *sn)
+{
+ _pthread_attr_destroy(&sn->sn_attr);
+ free(sn);
+}
+
+struct sigev_node *
+__sigev_find(int type, sigev_id_t id)
+{
+ struct sigev_node *sn;
+ int chain = HASH(type, id);
+
+ LIST_FOREACH(sn, &sigev_hash[chain], sn_link) {
+ if (sn->sn_type == type && sn->sn_id == id)
+ break;
+ }
+ return (sn);
+}
+
+int
+__sigev_register(struct sigev_node *sn)
+{
+ int chain = HASH(sn->sn_type, sn->sn_id);
+
+ LIST_INSERT_HEAD(&sigev_hash[chain], sn, sn_link);
+ return (0);
+}
+
+int
+__sigev_delete(int type, sigev_id_t id)
+{
+ struct sigev_node *sn;
+
+ sn = __sigev_find(type, id);
+ if (sn != NULL)
+ return (__sigev_delete_node(sn));
+ return (0);
+}
+
+int
+__sigev_delete_node(struct sigev_node *sn)
+{
+ LIST_REMOVE(sn, sn_link);
+
+ if (--sn->sn_tn->tn_refcount == 0)
+ _pthread_kill(sn->sn_tn->tn_thread, SIGSERVICE);
+ if (sn->sn_flags & SNF_WORKING)
+ sn->sn_flags |= SNF_REMOVED;
+ else
+ __sigev_free(sn);
+ return (0);
+}
+
+static sigev_id_t
+sigev_get_id(siginfo_t *si)
+{
+ switch(si->si_code) {
+ case SI_TIMER:
+ return (si->si_timerid);
+ case SI_MESGQ:
+ return (si->si_mqd);
+ case SI_ASYNCIO:
+ return (sigev_id_t)si->si_value.sival_ptr;
+ }
+ return (-1);
+}
+
+static struct sigev_thread *
+sigev_thread_create(int usedefault)
+{
+ struct sigev_thread *tn;
+ sigset_t set, oset;
+ int ret;
+
+ if (usedefault && sigev_default_thread) {
+ __sigev_list_lock();
+ sigev_default_thread->tn_refcount++;
+ __sigev_list_unlock();
+ return (sigev_default_thread);
+ }
+
+ tn = malloc(sizeof(*tn));
+ tn->tn_cur = NULL;
+ tn->tn_lwpid = -1;
+ tn->tn_refcount = 1;
+ _pthread_cond_init(&tn->tn_cv, NULL);
+
+ /* for debug */
+ __sigev_list_lock();
+ LIST_INSERT_HEAD(&sigev_threads, tn, tn_link);
+ __sigev_list_unlock();
+
+ sigfillset(&set); /* SIGSERVICE is masked. */
+ sigdelset(&set, SIGBUS);
+ sigdelset(&set, SIGILL);
+ sigdelset(&set, SIGFPE);
+ sigdelset(&set, SIGSEGV);
+ sigdelset(&set, SIGTRAP);
+ _sigprocmask(SIG_SETMASK, &set, &oset);
+ ret = _pthread_create(&tn->tn_thread, &sigev_default_attr,
+ sigev_service_loop, tn);
+ _sigprocmask(SIG_SETMASK, &oset, NULL);
+
+ if (ret != 0) {
+ __sigev_list_lock();
+ LIST_REMOVE(tn, tn_link);
+ __sigev_list_unlock();
+ free(tn);
+ tn = NULL;
+ } else {
+ /* wait the thread to get its lwpid */
+
+ __sigev_list_lock();
+ while (tn->tn_lwpid == -1)
+ _pthread_cond_wait(&tn->tn_cv, sigev_list_mtx);
+ __sigev_list_unlock();
+ }
+ return (tn);
+}
+
+/*
+ * The thread receives notification from kernel and creates
+ * a thread to call user callback function.
+ */
+static void *
+sigev_service_loop(void *arg)
+{
+ static int failure;
+
+ siginfo_t si;
+ sigset_t set;
+ struct sigev_thread *tn;
+ struct sigev_node *sn;
+ sigev_id_t id;
+ pthread_t td;
+ int ret;
+
+ tn = arg;
+ thr_self(&tn->tn_lwpid);
+ __sigev_list_lock();
+ _pthread_cond_broadcast(&tn->tn_cv);
+ __sigev_list_unlock();
+
+ sigemptyset(&set);
+ sigaddset(&set, SIGSERVICE);
+ for (;;) {
+ ret = sigwaitinfo(&set, &si);
+
+ __sigev_list_lock();
+ if (tn->tn_refcount == 0) {
+ LIST_REMOVE(tn, tn_link);
+ __sigev_list_unlock();
+ free(tn);
+ break;
+ }
+
+ if (ret == -1) {
+ __sigev_list_unlock();
+ continue;
+ }
+
+ id = sigev_get_id(&si);
+ sn = __sigev_find(si.si_code, id);
+ if (sn == NULL) {
+ __sigev_list_unlock();
+ continue;
+ }
+
+ sn->sn_info = si;
+ if (sn->sn_flags & SNF_SYNC)
+ tn->tn_cur = sn;
+ else
+ tn->tn_cur = NULL;
+ sn->sn_flags |= SNF_WORKING;
+ __sigev_list_unlock();
+
+ ret = _pthread_create(&td, &sn->sn_attr, worker_routine, sn);
+ if (ret != 0) {
+ if (failure++ < 5)
+ warnc(ret, "%s:%s failed to create thread.\n",
+ __FILE__, __func__);
+
+ __sigev_list_lock();
+ sn->sn_flags &= ~SNF_WORKING;
+ if (sn->sn_flags & SNF_REMOVED)
+ __sigev_free(sn);
+ __sigev_list_unlock();
+ } else if (tn->tn_cur) {
+ __sigev_list_lock();
+ while (tn->tn_cur)
+ _pthread_cond_wait(&tn->tn_cv, sigev_list_mtx);
+ __sigev_list_unlock();
+ }
+ }
+ return (0);
+}
+
+/*
+ * newly created worker thread to call user callback function.
+ */
+static void *
+worker_routine(void *arg)
+{
+ struct sigev_node *sn = arg;
+
+ _pthread_cleanup_push(worker_cleanup, sn);
+ sn->sn_dispatch(sn);
+ _pthread_cleanup_pop(1);
+
+ return (0);
+}
+
+/* clean up a notification after dispatch. */
+static void
+worker_cleanup(void *arg)
+{
+ struct sigev_node *sn = arg;
+
+ __sigev_list_lock();
+ if (sn->sn_flags & SNF_SYNC) {
+ sn->sn_tn->tn_cur = NULL;
+ _pthread_cond_broadcast(&sn->sn_tn->tn_cv);
+ }
+ if (sn->sn_flags & SNF_REMOVED)
+ __sigev_free(sn);
+ else
+ sn->sn_flags &= ~SNF_WORKING;
+ __sigev_list_unlock();
+}
diff --git a/lib/librt/sigev_thread.h b/lib/librt/sigev_thread.h
new file mode 100644
index 0000000..7e30c2a
--- /dev/null
+++ b/lib/librt/sigev_thread.h
@@ -0,0 +1,85 @@
+/*
+ * 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 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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, 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 _SIGEV_THREAD_H_
+#define _SIGEV_THREAD_H_
+
+#include <sys/types.h>
+#include <sys/queue.h>
+
+struct sigev_thread;
+struct sigev_node;
+
+typedef uintptr_t sigev_id_t;
+typedef void (*sigev_dispatch_t)(struct sigev_node *);
+
+struct sigev_node {
+ LIST_ENTRY(sigev_node) sn_link;
+ int sn_type;
+ sigev_id_t sn_id;
+ sigev_dispatch_t sn_dispatch;
+ union sigval sn_value;
+ void *sn_func;
+ int sn_flags;
+ int sn_gen;
+ siginfo_t sn_info;
+ pthread_attr_t sn_attr;
+ struct sigev_thread *sn_tn;
+};
+
+
+struct sigev_thread {
+ LIST_ENTRY(sigev_thread) tn_link;
+ pthread_t tn_thread;
+ struct sigev_node *tn_cur;
+ int tn_refcount;
+ long tn_lwpid;
+ pthread_cond_t tn_cv;
+};
+
+#define SNF_WORKING 0x01
+#define SNF_REMOVED 0x02
+#define SNF_SYNC 0x04
+
+#define SIGSERVICE (SIGTHR+1)
+
+int __sigev_check_init();
+struct sigev_node *__sigev_alloc(int, const struct sigevent *,
+ struct sigev_node *, int);
+struct sigev_node *__sigev_find(int, sigev_id_t);
+void __sigev_get_sigevent(struct sigev_node *, struct sigevent *,
+ sigev_id_t);
+int __sigev_register(struct sigev_node *);
+int __sigev_delete(int, sigev_id_t);
+int __sigev_delete_node(struct sigev_node *);
+void __sigev_list_lock(void);
+void __sigev_list_unlock(void);
+void __sigev_free(struct sigev_node *);
+
+#endif
diff --git a/lib/librt/timer.c b/lib/librt/timer.c
new file mode 100644
index 0000000..f02e761
--- /dev/null
+++ b/lib/librt/timer.c
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2006 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 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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, 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$
+ *
+ */
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <sys/syscall.h>
+
+#include "namespace.h"
+#include <errno.h>
+#include <stddef.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <time.h>
+#include "sigev_thread.h"
+#include "un-namespace.h"
+
+extern int __sys_ktimer_create(clockid_t, struct sigevent *__restrict,
+ int *__restrict);
+extern int __sys_ktimer_delete(int);
+extern int __sys_ktimer_gettime(int, struct itimerspec *);
+extern int __sys_ktimer_getoverrun(int);
+extern int __sys_ktimer_settime(int, int,
+ const struct itimerspec *__restrict, struct itimerspec *__restrict);
+
+struct __timer {
+ int oshandle;
+ struct sigev_node *node;
+};
+
+__weak_reference(__timer_create, timer_create);
+__weak_reference(__timer_create, _timer_create);
+__weak_reference(__timer_delete, timer_delete);
+__weak_reference(__timer_delete, _timer_delete);
+__weak_reference(__timer_gettime, timer_gettime);
+__weak_reference(__timer_gettime, _timer_gettime);
+__weak_reference(__timer_settime, timer_settime);
+__weak_reference(__timer_settime, _timer_settime);
+__weak_reference(__timer_getoverrun, timer_getoverrun);
+__weak_reference(__timer_getoverrun, _timer_getoverrun);
+
+typedef void (*timer_func)(union sigval val, int overrun);
+
+static void
+timer_dispatch(struct sigev_node *sn)
+{
+ timer_func f = sn->sn_func;
+
+ /* I want to avoid expired notification. */
+ if (sn->sn_info.si_value.sival_int == sn->sn_gen)
+ f(sn->sn_value, sn->sn_info.si_overrun);
+}
+
+int
+__timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid)
+{
+ struct __timer *timer;
+ struct sigevent ev;
+ struct sigev_node *sn;
+ int ret, err;
+
+ timer = malloc(sizeof(struct __timer));
+ if (timer == NULL)
+ return (-1);
+
+ if (evp == NULL || evp->sigev_notify != SIGEV_THREAD) {
+ ret = __sys_ktimer_create(clockid, evp, &timer->oshandle);
+ if (ret == -1) {
+ err = errno;
+ free(timer);
+ errno = err;
+ return (ret);
+ }
+ timer->node = NULL;
+ *timerid = timer;
+ return (0);
+ }
+
+ if (__sigev_check_init()) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ sn = __sigev_alloc(SI_TIMER, evp, NULL, 0);
+ if (sn == NULL) {
+ errno = EAGAIN;
+ return (-1);
+ }
+
+ __sigev_get_sigevent(sn, &ev, sn->sn_gen);
+ ret = __sys_ktimer_create(clockid, &ev, &timer->oshandle);
+ if (ret != 0) {
+ err = errno;
+ __sigev_free(sn);
+ free(timer);
+ errno = err;
+ return (-1);
+ }
+ sn->sn_flags |= SNF_SYNC;
+ sn->sn_dispatch = timer_dispatch;
+ sn->sn_id = timer->oshandle;
+ timer->node = sn;
+ __sigev_list_lock();
+ __sigev_register(sn);
+ __sigev_list_unlock();
+ *timerid = timer;
+ return (0);
+}
+
+int
+__timer_delete(timer_t timerid)
+{
+ int ret, err;
+
+ if (timerid->node != NULL) {
+ __sigev_list_lock();
+ __sigev_delete_node(timerid->node);
+ __sigev_list_unlock();
+ }
+ ret = __sys_ktimer_delete(timerid->oshandle);
+ err = errno;
+ free(timerid);
+ errno = err;
+ return (ret);
+}
+
+int
+__timer_gettime(timer_t timerid, struct itimerspec *value)
+{
+
+ return __sys_ktimer_gettime(timerid->oshandle, value);
+}
+
+int
+__timer_getoverrun(timer_t timerid)
+{
+
+ return __sys_ktimer_getoverrun(timerid->oshandle);
+}
+
+int
+__timer_settime(timer_t timerid, int flags,
+ const struct itimerspec *__restrict value,
+ struct itimerspec *__restrict ovalue)
+{
+
+ return __sys_ktimer_settime(timerid->oshandle,
+ flags, value, ovalue);
+}
+
+int
+__timer_oshandle(timer_t timerid)
+{
+
+ return (timerid->oshandle);
+}
diff --git a/lib/libsbuf/Makefile b/lib/libsbuf/Makefile
new file mode 100644
index 0000000..b166bef
--- /dev/null
+++ b/lib/libsbuf/Makefile
@@ -0,0 +1,10 @@
+# $FreeBSD$
+
+LIB= sbuf
+SHLIBDIR?= /lib
+SRCS= subr_sbuf.c
+WARNS?= 2
+
+.PATH: ${.CURDIR}/../../sys/kern
+
+.include <bsd.lib.mk>
diff --git a/lib/libsdp/Makefile b/lib/libsdp/Makefile
new file mode 100644
index 0000000..bf71fe3
--- /dev/null
+++ b/lib/libsdp/Makefile
@@ -0,0 +1,36 @@
+# $Id: Makefile,v 1.2 2003/09/07 20:34:19 max Exp $
+# $FreeBSD$
+
+LIB= sdp
+MAN= sdp.3
+
+WARNS?= 2
+CFLAGS+= -I${.CURDIR}
+
+SHLIB_MAJOR= 2
+
+SRCS= search.c service.c session.c util.c
+INCS= sdp.h
+
+MLINKS+= sdp.3 SDP_GET8.3
+MLINKS+= sdp.3 SDP_GET16.3
+MLINKS+= sdp.3 SDP_GET32.3
+MLINKS+= sdp.3 SDP_GET64.3
+MLINKS+= sdp.3 SDP_GET128.3
+MLINKS+= sdp.3 SDP_PUT8.3
+MLINKS+= sdp.3 SDP_PUT16.3
+MLINKS+= sdp.3 SDP_PUT32.3
+MLINKS+= sdp.3 SDP_PUT64.3
+MLINKS+= sdp.3 SDP_PUT128.3
+MLINKS+= sdp.3 sdp_open.3
+MLINKS+= sdp.3 sdp_open_local.3
+MLINKS+= sdp.3 sdp_close.3
+MLINKS+= sdp.3 sdp_error.3
+MLINKS+= sdp.3 sdp_search.3
+MLINKS+= sdp.3 sdp_attr2desc.3
+MLINKS+= sdp.3 sdp_uuid2desc.3
+MLINKS+= sdp.3 sdp_register_service.3
+MLINKS+= sdp.3 sdp_unregister_service.3
+MLINKS+= sdp.3 sdp_change_service.3
+
+.include <bsd.lib.mk>
diff --git a/lib/libsdp/sdp-int.h b/lib/libsdp/sdp-int.h
new file mode 100644
index 0000000..d8a064d
--- /dev/null
+++ b/lib/libsdp/sdp-int.h
@@ -0,0 +1,62 @@
+/*
+ * sdp-int.h
+ *
+ * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.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.
+ *
+ * $Id: sdp-int.h,v 1.1 2003/09/01 23:01:07 max Exp $
+ * $FreeBSD$
+ */
+
+#ifndef _SDP_INT_H_
+#define _SDP_INT_H_
+
+__BEGIN_DECLS
+
+/*
+ * SDP session
+ */
+
+struct sdp_session {
+ uint16_t flags;
+#define SDP_SESSION_LOCAL (1 << 0)
+ uint16_t tid; /* current session transaction ID (tid) */
+ uint16_t omtu; /* outgoing MTU (req buffer size) */
+ uint16_t imtu; /* incoming MTU (rsp buffer size) */
+ uint8_t *req; /* request buffer (start) */
+ uint8_t *req_e; /* request buffer (end) */
+ uint8_t *rsp; /* response buffer (start) */
+ uint8_t *rsp_e; /* response buffer (end) */
+ uint32_t cslen; /* continuation state length */
+ uint8_t cs[16];/* continuation state */
+ int32_t s; /* L2CAP socket */
+ int32_t error; /* last error code */
+};
+typedef struct sdp_session sdp_session_t;
+typedef struct sdp_session * sdp_session_p;
+
+__END_DECLS
+
+#endif /* ndef _SDP_INT_H_ */
+
diff --git a/lib/libsdp/sdp.3 b/lib/libsdp/sdp.3
new file mode 100644
index 0000000..c51b6f9
--- /dev/null
+++ b/lib/libsdp/sdp.3
@@ -0,0 +1,415 @@
+.\" Copyright (c) 2003 Maksim Yevmenkin <m_evmenkin@yahoo.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.
+.\"
+.\" $Id: sdp.3,v 1.1 2003/09/07 20:34:19 max Exp $
+.\" $FreeBSD$
+.\"
+.Dd May 27, 2005
+.Dt SDP 3
+.Os
+.Sh NAME
+.Nm SDP_GET8 ,
+.Nm SDP_GET16 ,
+.Nm SDP_GET32 ,
+.Nm SDP_GET64 ,
+.Nm SDP_GET128 ,
+.Nm SDP_GET_UUID128 ,
+.Nm SDP_PUT8 ,
+.Nm SDP_PUT16 ,
+.Nm SDP_PUT32 ,
+.Nm SDP_PUT64 ,
+.Nm SDP_PUT128 ,
+.Nm SDP_PUT_UUID128 ,
+.Nm sdp_open ,
+.Nm sdp_open_local ,
+.Nm sdp_close ,
+.Nm sdp_error ,
+.Nm sdp_search ,
+.Nm sdp_attr2desc ,
+.Nm sdp_uuid2desc
+.Nd Bluetooth SDP routines
+.Sh LIBRARY
+.Lb libsdp
+.Sh SYNOPSIS
+.In bluetooth.h
+.In sdp.h
+.Fn SDP_GET8 "b" "cp"
+.Fn SDP_GET16 "s" "cp"
+.Fn SDP_GET32 "l" "cp"
+.Fn SDP_GET64 "l" "cp"
+.Fn SDP_GET128 "l" "cp"
+.Fn SDP_GET_UUID128 "l" "cp"
+.Fn SDP_PUT8 "b" "cp"
+.Fn SDP_PUT16 "s" "cp"
+.Fn SDP_PUT32 "l" "cp"
+.Fn SDP_PUT64 "l" "cp"
+.Fn SDP_PUT128 "l" "cp"
+.Fn SDP_PUT_UUID128 "l" "cp"
+.Ft "void *"
+.Fn sdp_open "bdaddr_t const *l" "bdaddr_t const *r"
+.Ft "void *"
+.Fn sdp_open_local "char const *control"
+.Ft int32_t
+.Fn sdp_close "void *xs"
+.Ft int32_t
+.Fn sdp_error "void *xs"
+.Ft int32_t
+.Fo sdp_search
+.Fa "void *xs" "uint32_t plen" "uint16_t const *pp" "uint32_t alen"
+.Fa "uint32_t const *ap" "uint32_t vlen" "sdp_attr_t *vp"
+.Fc
+.Ft "char const * const"
+.Fn sdp_attr2desc "uint16_t attr"
+.Ft "char const * const"
+.Fn sdp_uuid2desc "uint16_t uuid"
+.Ft int32_t
+.Fo sdp_register_service
+.Fa "void *xss" "uint16_t uuid" "bdaddr_p const bdaddr" "uint8_t const *data"
+.Fa "uint32_t datalen" "uint32_t *handle"
+.Fc
+.Ft int32_t
+.Fn sdp_unregister_service "void *xss" "uint32_t handle"
+.Ft int32_t
+.Fo sdp_change_service
+.Fa "void *xss" "uint32_t handle" "uint8_t const *data" "uint32_t datalen"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn SDP_GET8 ,
+.Fn SDP_GET16 ,
+.Fn SDP_GET32 ,
+.Fn SDP_GET64
+and
+.Fn SDP_GET128
+macros are used to get byte, short, long, long long and 128-bit integer
+from the buffer pointed by
+.Fa cp
+pointer.
+The pointer is automatically advanced.
+.Pp
+The
+.Fn SDP_PUT8 ,
+.Fn SDP_PUT16 ,
+.Fn SDP_PUT32 ,
+.Fn SDP_PUT64
+and
+.Fn SDP_PUT128
+macros are used to put byte, short, long, long long and 128-bit integer
+into the buffer pointed by
+.Fa cp
+pointer.
+The pointer is automatically advanced.
+.Pp
+.Fn SDP_GET_UUID128
+and
+.Fn SDP_PUT_UUID128
+macros are used to get and put 128-bit UUID into the buffer pointed by
+.Fa cp
+pointer.
+The pointer is automatically advanced.
+.Pp
+The
+.Fn sdp_open
+and
+.Fn sdp_open_local
+functions each return a pointer to an opaque object describing SDP session.
+The
+.Fa l
+argument passed to
+.Fn sdp_open
+function should point to a source BD_ADDR.
+If source BD_ADDR is
+.Dv NULL
+then source address
+.Dv NG_HCI_BDADDR_ANY
+is used.
+The
+.Fa r
+argument passed to
+.Fn sdp_open
+function should point to a
+.Pf non- Dv NULL
+remote BD_ADDR.
+Remote BD_ADDR cannot be
+.Dv NG_HCI_BDADDR_ANY .
+The
+.Fn sdp_open_local
+function takes path to the control socket and opens a connection to a local
+SDP server.
+If path to the control socket is
+.Dv NULL
+then default
+.Pa /var/run/sdp
+path will be used.
+.Pp
+The
+.Fn sdp_close
+function terminates active SDP session and deletes SDP session object.
+The
+.Fa xs
+parameter should point to a valid SDP session object created with
+.Fn sdp_open
+or
+.Fn sdp_open_local .
+.Pp
+The
+.Fn sdp_error
+function returns last error that is stored inside SDP session object.
+The
+.Fa xs
+parameter should point to a valid SDP session object created with
+.Fn sdp_open
+or
+.Fn sdp_open_local .
+The error value returned can be converted to a human readable message by
+calling
+.Xr strerror 3
+function.
+.Pp
+The
+.Fn sdp_search
+function is used to perform SDP Service Search Attribute Request.
+The
+.Fa xs
+parameter should point to a valid SDP session object created with
+.Fn sdp_open
+or
+.Fn sdp_open_local .
+The
+.Fa pp
+parameter is a Service Search Pattern - an array of one or more Service
+Class IDs.
+The maximum number of Service Class IDs in the array is 12.
+The
+.Fa plen
+parameter is the length of the Service Search pattern.
+The
+.Fa ap
+parameter is an Attribute ID Range List - an array of one or more SDP Attribute
+ID Range.
+Each attribute ID Range is encoded as a 32-bit unsigned integer data
+element, where the high order 16 bits are interpreted as the beginning
+attribute ID of the range and the low order 16 bits are interpreted as the
+ending attribute ID of the range.
+The attribute IDs contained in the Attribute ID Ranges List must be listed in
+ascending order without duplication of any attribute ID values.
+Note that all attributes may be requested by specifying a range of
+0x0000-0xFFFF.
+The
+.Fa alen
+parameter is the length of the Attribute ID Ranges List.
+The
+.Fn SDP_ATTR_RANGE "lo" "hi"
+macro can be used to prepare Attribute ID Range.
+The
+.Fa vp
+parameter should be an array of
+.Vt sdp_attr_t
+structures.
+Each
+.Vt sdp_attr_t
+structure describes single SDP attribute and defined as follows:
+.Bd -literal -offset indent
+struct sdp_attr {
+ uint16_t flags;
+#define SDP_ATTR_OK (0 << 0)
+#define SDP_ATTR_INVALID (1 << 0)
+#define SDP_ATTR_TRUNCATED (1 << 1)
+ uint16_t attr; /* SDP_ATTR_xxx */
+ uint32_t vlen; /* length of the value[] in bytes */
+ uint8_t *value; /* base pointer */
+};
+typedef struct sdp_attr sdp_attr_t;
+typedef struct sdp_attr * sdp_attr_p;
+.Ed
+.Pp
+The caller of the
+.Fn sdp_search
+function is expected to prepare the array of
+.Vt sdp_attr
+structures and for each element of the array both
+.Va vlen
+and
+.Va value
+must be set.
+The
+.Fn sdp_search
+function will fill each
+.Vt sdp_attr_t
+structure with attribute and value, i.e., it will set
+.Va flags ,
+.Va attr
+and
+.Va vlen
+fields.
+The actual value of the attribute will be copied into
+.Va value
+buffer.
+Note: attributes are returned in the order they appear in the Service Search
+Attribute Response.
+SDP server could return several attributes for the same record.
+In this case the order of the attributes will be: all attributes for the first
+records, then all attributes for the secord record etc.
+.Pp
+The
+.Fn sdp_attr2desc
+and
+.Fn sdp_uuid2desc
+functions each take a numeric attribute ID/UUID value and convert it to a
+human readable description.
+.Pp
+The
+.Fn sdp_register_service
+function
+is used to register service with the local SDP server.
+The
+.Fa xss
+parameter should point to a valid SDP session object obtained from
+.Fn sdp_open_local .
+The
+.Fa uuid
+parameter is a SDP Service Class ID for the service to be registered.
+The
+.Fa bdaddr
+parameter should point to a valid BD_ADDR.
+The service will be only advertised if request was received by the local device
+with
+.Fa bdaddr .
+If
+.Fa bdaddr
+is set to
+.Dv NG_HCI_BDADDR_ANY
+then the service will be advertised to any remote devices that queries for it.
+The
+.Fa data
+and
+.Fa datalen
+parameters specify data and size of the data for the service.
+Upon successful return
+.Fn sdp_register_service
+will populate
+.Fa handle
+with the SDP record handle.
+This parameter is optional and can be set to
+.Dv NULL .
+.Pp
+The
+.Fn sdp_unregister_service
+function
+is used to unregister service with the local SDP server.
+The
+.Fa xss
+parameter should point to a valid SDP session object obtained from
+.Fn sdp_open_local .
+The
+.Fa handle
+parameter should contain a valid SDP record handle of the service to be
+unregistered.
+.Pp
+The
+.Fn sdp_change_service
+function is used to change data associated with the existing service on
+the local SDP server.
+The
+.Fa xss
+parameter should point to a valid SDP session object obtained from
+.Fn sdp_open_local .
+The
+.Fa handle
+parameter should contain a valid SDP record handle of the service to be changed.
+The
+.Fa data
+and
+.Fa datalen
+parameters specify data and size of the data for the service.
+.Sh CAVEAT
+When registering services with the local SDP server the application must
+keep the SDP session open.
+If SDP session is closed then the local SDP server will remove all services
+that were registered over the session.
+The application is allowed to change or unregister service if it was registered
+over the same session.
+.Sh EXAMPLES
+The following example shows how to get
+.Dv SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST
+attribute for the
+.Dv SDP_SERVICE_CLASS_SERIAL_PORT
+service from the remote device.
+.Bd -literal -offset indent
+bdaddr_t remote;
+uint8_t buffer[1024];
+void *ss = NULL;
+uint16_t serv = SDP_SERVICE_CLASS_SERIAL_PORT;
+uint32_t attr = SDP_ATTR_RANGE(
+ SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
+ SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST);
+sdp_attr_t proto = { SDP_ATTR_INVALID,0,sizeof(buffer),buffer };
+
+/* Obtain/set remote BDADDR here */
+
+if ((ss = sdp_open(NG_HCI_BDADDR_ANY, remote)) == NULL)
+ /* exit ENOMEM */
+if (sdp_error(ss) != 0)
+ /* exit sdp_error(ss) */
+
+if (sdp_search(ss, 1, &serv, 1, &attr, 1, &proto) != 0)
+ /* exit sdp_error(ss) */
+
+if (proto.flags != SDP_ATTR_OK)
+ /* exit see proto.flags for details */
+
+/* If we got here then we have attribute value in proto.value */
+.Ed
+.Sh DIAGNOSTICS
+Both
+.Fn sdp_open
+and
+.Fn sdp_open_local
+will return
+.Dv NULL
+if memory allocation for the new SDP session object fails.
+If the new SDP object was created then caller is still expected to call
+.Fn sdp_error
+to check if there was connection error.
+.Pp
+The
+.Fn sdp_search ,
+.Fn sdp_register_service ,
+.Fn sdp_unregister_service
+and
+.Fn sdp_change_service
+functions return non-zero value on error.
+The caller is expected to call
+.Fn sdp_error
+to find out more about error.
+.Sh SEE ALSO
+.Xr bluetooth 3 ,
+.Xr strerror 3 ,
+.Xr sdpcontrol 8 ,
+.Xr sdpd 8
+.Sh AUTHORS
+.An Maksim Yevmenkin Aq m_evmenkin@yahoo.com
+.Sh BUGS
+Most likely.
+Please report bugs if found.
diff --git a/lib/libsdp/sdp.h b/lib/libsdp/sdp.h
new file mode 100644
index 0000000..2b06b2c
--- /dev/null
+++ b/lib/libsdp/sdp.h
@@ -0,0 +1,653 @@
+/*
+ * sdp.h
+ *
+ * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.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.
+ *
+ * $Id: sdp.h,v 1.3 2003/09/05 00:33:59 max Exp $
+ * $FreeBSD$
+ */
+
+#ifndef _SDP_H_
+#define _SDP_H_
+
+__BEGIN_DECLS
+
+/*
+ * Data representation (page 349)
+ */
+
+/* Nil, the null type */
+#define SDP_DATA_NIL 0x00
+
+/* Unsigned integer */
+#define SDP_DATA_UINT8 0x08
+#define SDP_DATA_UINT16 0x09
+#define SDP_DATA_UINT32 0x0A
+#define SDP_DATA_UINT64 0x0B
+#define SDP_DATA_UINT128 0x0C
+
+/* Signed two's-complement integer */
+#define SDP_DATA_INT8 0x10
+#define SDP_DATA_INT16 0x11
+#define SDP_DATA_INT32 0x12
+#define SDP_DATA_INT64 0x13
+#define SDP_DATA_INT128 0x14
+
+/* UUID, a universally unique identifier */
+#define SDP_DATA_UUID16 0x19
+#define SDP_DATA_UUID32 0x1A
+#define SDP_DATA_UUID128 0x1C
+
+/* Text string */
+#define SDP_DATA_STR8 0x25
+#define SDP_DATA_STR16 0x26
+#define SDP_DATA_STR32 0x27
+
+/* Boolean */
+#define SDP_DATA_BOOL 0x28
+
+/*
+ * Data element sequence.
+ * A data element whose data field is a sequence of data elements
+ */
+#define SDP_DATA_SEQ8 0x35
+#define SDP_DATA_SEQ16 0x36
+#define SDP_DATA_SEQ32 0x37
+
+/*
+ * Data element alternative.
+ * A data element whose data field is a sequence of data elements from
+ * which one data element is to be selected.
+ */
+#define SDP_DATA_ALT8 0x3D
+#define SDP_DATA_ALT16 0x3E
+#define SDP_DATA_ALT32 0x3F
+
+/* URL, a uniform resource locator */
+#define SDP_DATA_URL8 0x45
+#define SDP_DATA_URL16 0x46
+#define SDP_DATA_URL32 0x47
+
+/*
+ * Protocols UUID (short) http://www.bluetoothsig.org/assigned-numbers/sdp.htm
+ * BASE UUID 00000000-0000-1000-8000-00805F9B34FB
+ */
+
+#define SDP_UUID_PROTOCOL_SDP 0x0001
+#define SDP_UUID_PROTOCOL_UDP 0x0002
+#define SDP_UUID_PROTOCOL_RFCOMM 0x0003
+#define SDP_UUID_PROTOCOL_TCP 0x0004
+#define SDP_UUID_PROTOCOL_TCS_BIN 0x0005
+#define SDP_UUID_PROTOCOL_TCS_AT 0x0006
+#define SDP_UUID_PROTOCOL_OBEX 0x0008
+#define SDP_UUID_PROTOCOL_IP 0x0009
+#define SDP_UUID_PROTOCOL_FTP 0x000A
+#define SDP_UUID_PROTOCOL_HTTP 0x000C
+#define SDP_UUID_PROTOCOL_WSP 0x000E
+#define SDP_UUID_PROTOCOL_BNEP 0x000F
+#define SDP_UUID_PROTOCOL_UPNP 0x0010
+#define SDP_UUID_PROTOCOL_HIDP 0x0011
+#define SDP_UUID_PROTOCOL_HARDCOPY_CONTROL_CHANNEL 0x0012
+#define SDP_UUID_PROTOCOL_HARDCOPY_DATA_CHANNEL 0x0014
+#define SDP_UUID_PROTOCOL_HARDCOPY_NOTIFICATION 0x0016
+#define SDP_UUID_PROTOCOL_AVCTP 0x0017
+#define SDP_UUID_PROTOCOL_AVDTP 0x0019
+#define SDP_UUID_PROTOCOL_CMPT 0x001B
+#define SDP_UUID_PROTOCOL_UDI_C_PLANE 0x001D
+#define SDP_UUID_PROTOCOL_L2CAP 0x0100
+
+/*
+ * Service class IDs http://www.bluetoothsig.org/assigned-numbers/sdp.htm
+ */
+
+#define SDP_SERVICE_CLASS_SERVICE_DISCOVERY_SERVER 0x1000
+#define SDP_SERVICE_CLASS_BROWSE_GROUP_DESCRIPTOR 0x1001
+#define SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP 0x1002
+#define SDP_SERVICE_CLASS_SERIAL_PORT 0x1101
+#define SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP 0x1102
+#define SDP_SERVICE_CLASS_DIALUP_NETWORKING 0x1103
+#define SDP_SERVICE_CLASS_IR_MC_SYNC 0x1104
+#define SDP_SERVICE_CLASS_OBEX_OBJECT_PUSH 0x1105
+#define SDP_SERVICE_CLASS_OBEX_FILE_TRANSFER 0x1106
+#define SDP_SERVICE_CLASS_IR_MC_SYNC_COMMAND 0x1107
+#define SDP_SERVICE_CLASS_HEADSET 0x1108
+#define SDP_SERVICE_CLASS_CORDLESS_TELEPHONY 0x1109
+#define SDP_SERVICE_CLASS_AUDIO_SOURCE 0x110A
+#define SDP_SERVICE_CLASS_AUDIO_SINK 0x110B
+#define SDP_SERVICE_CLASS_AV_REMOTE_CONTROL_TARGET 0x110C
+#define SDP_SERVICE_CLASS_ADVANCED_AUDIO_DISTRIBUTION 0x110D
+#define SDP_SERVICE_CLASS_AV_REMOTE_CONTROL 0x110E
+#define SDP_SERVICE_CLASS_VIDEO_CONFERENCING 0x110F
+#define SDP_SERVICE_CLASS_INTERCOM 0x1110
+#define SDP_SERVICE_CLASS_FAX 0x1111
+#define SDP_SERVICE_CLASS_HEADSET_AUDIO_GATEWAY 0x1112
+#define SDP_SERVICE_CLASS_WAP 0x1113
+#define SDP_SERVICE_CLASS_WAP_CLIENT 0x1114
+#define SDP_SERVICE_CLASS_PANU 0x1115
+#define SDP_SERVICE_CLASS_NAP 0x1116
+#define SDP_SERVICE_CLASS_GN 0x1117
+#define SDP_SERVICE_CLASS_DIRECT_PRINTING 0x1118
+#define SDP_SERVICE_CLASS_REFERENCE_PRINTING 0x1119
+#define SDP_SERVICE_CLASS_IMAGING 0x111A
+#define SDP_SERVICE_CLASS_IMAGING_RESPONDER 0x111B
+#define SDP_SERVICE_CLASS_IMAGING_AUTOMATIC_ARCHIVE 0x111C
+#define SDP_SERVICE_CLASS_IMAGING_REFERENCED_OBJECTS 0x111D
+#define SDP_SERVICE_CLASS_HANDSFREE 0x111E
+#define SDP_SERVICE_CLASS_HANDSFREE_AUDIO_GATEWAY 0x111F
+#define SDP_SERVICE_CLASS_DIRECT_PRINTING_REFERENCE_OBJECTS 0x1120
+#define SDP_SERVICE_CLASS_REFLECTED_UI 0x1121
+#define SDP_SERVICE_CLASS_BASIC_PRINTING 0x1122
+#define SDP_SERVICE_CLASS_PRINTING_STATUS 0x1123
+#define SDP_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE 0x1124
+#define SDP_SERVICE_CLASS_HARDCOPY_CABLE_REPLACEMENT 0x1125
+#define SDP_SERVICE_CLASS_HCR_PRINT 0x1126
+#define SDP_SERVICE_CLASS_HCR_SCAN 0x1127
+#define SDP_SERVICE_CLASS_COMMON_ISDN_ACCESS 0x1128
+#define SDP_SERVICE_CLASS_VIDEO_CONFERENCING_GW 0x1129
+#define SDP_SERVICE_CLASS_UDI_MT 0x112A
+#define SDP_SERVICE_CLASS_UDI_TA 0x112B
+#define SDP_SERVICE_CLASS_AUDIO_VIDEO 0x112C
+#define SDP_SERVICE_CLASS_SIM_ACCESS 0x112D
+#define SDP_SERVICE_CLASS_PNP_INFORMATION 0x1200
+#define SDP_SERVICE_CLASS_GENERIC_NETWORKING 0x1201
+#define SDP_SERVICE_CLASS_GENERIC_FILE_TRANSFER 0x1202
+#define SDP_SERVICE_CLASS_GENERIC_AUDIO 0x1203
+#define SDP_SERVICE_CLASS_GENERIC_TELEPHONY 0x1204
+#define SDP_SERVICE_CLASS_UPNP 0x1205
+#define SDP_SERVICE_CLASS_UPNP_IP 0x1206
+#define SDP_SERVICE_CLASS_ESDP_UPNP_IP_PAN 0x1300
+#define SDP_SERVICE_CLASS_ESDP_UPNP_IP_LAP 0x1301
+#define SDP_SERVICE_CLASS_ESDP_UPNP_L2CAP 0x1302
+
+/*
+ * Universal attribute definitions (page 366) and
+ * http://www.bluetoothsig.org/assigned-numbers/sdp.htm
+ */
+
+#define SDP_ATTR_RANGE(lo, hi) \
+ (uint32_t)(((uint16_t)(lo) << 16) | ((uint16_t)(hi)))
+
+#define SDP_ATTR_SERVICE_RECORD_HANDLE 0x0000
+#define SDP_ATTR_SERVICE_CLASS_ID_LIST 0x0001
+#define SDP_ATTR_SERVICE_RECORD_STATE 0x0002
+#define SDP_ATTR_SERVICE_ID 0x0003
+#define SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST 0x0004
+#define SDP_ATTR_BROWSE_GROUP_LIST 0x0005
+#define SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST 0x0006
+#define SDP_ATTR_SERVICE_INFO_TIME_TO_LIVE 0x0007
+#define SDP_ATTR_SERVICE_AVAILABILITY 0x0008
+#define SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST 0x0009
+#define SDP_ATTR_DOCUMENTATION_URL 0x000A
+#define SDP_ATTR_CLIENT_EXECUTABLE_URL 0x000B
+#define SDP_ATTR_ICON_URL 0x000C
+#define SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS 0x000D
+#define SDP_ATTR_GROUP_ID 0x0200
+#define SDP_ATTR_IP_SUBNET 0x0200
+#define SDP_ATTR_VERSION_NUMBER_LIST 0x0200
+#define SDP_ATTR_SERVICE_DATABASE_STATE 0x0201
+#define SDP_ATTR_SERVICE_VERSION 0x0300
+#define SDP_ATTR_EXTERNAL_NETWORK 0x0301
+#define SDP_ATTR_NETWORK 0x0301
+#define SDP_ATTR_SUPPORTED_DATA_STORES_LIST 0x0301
+#define SDP_ATTR_FAX_CLASS1_SUPPORT 0x0302
+#define SDP_ATTR_REMOTE_AUDIO_VOLUME_CONTROL 0x0302
+#define SDP_ATTR_FAX_CLASS20_SUPPORT 0x0303
+#define SDP_ATTR_SUPPORTED_FORMATS_LIST 0x0303
+#define SDP_ATTR_FAX_CLASS2_SUPPORT 0x0304
+#define SDP_ATTR_AUDIO_FEEDBACK_SUPPORT 0x0305
+#define SDP_ATTR_NETWORK_ADDRESS 0x0306
+#define SDP_ATTR_WAP_GATEWAY 0x0307
+#define SDP_ATTR_HOME_PAGE_URL 0x0308
+#define SDP_ATTR_WAP_STACK_TYPE 0x0309
+#define SDP_ATTR_SECURITY_DESCRIPTION 0x030A
+#define SDP_ATTR_NET_ACCESS_TYPE 0x030B
+#define SDP_ATTR_MAX_NET_ACCESS_RATE 0x030C
+#define SDP_ATTR_IPV4_SUBNET 0x030D
+#define SDP_ATTR_IPV6_SUBNET 0x030E
+#define SDP_ATTR_SUPPORTED_CAPABALITIES 0x0310
+#define SDP_ATTR_SUPPORTED_FEATURES 0x0311
+#define SDP_ATTR_SUPPORTED_FUNCTIONS 0x0312
+#define SDP_ATTR_TOTAL_IMAGING_DATA_CAPACITY 0x0313
+
+/*
+ * The offset must be added to the attribute ID base (contained in the
+ * LANGUAGE_BASE_ATTRIBUTE_ID_LIST attribute) in order to compute the
+ * attribute ID for these attributes.
+ */
+
+#define SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID 0x0100
+#define SDP_ATTR_SERVICE_NAME_OFFSET 0x0000
+#define SDP_ATTR_SERVICE_DESCRIPTION_OFFSET 0x0001
+#define SDP_ATTR_PROVIDER_NAME_OFFSET 0x0002
+
+/*
+ * Protocol data unit (PDU) format (page 352)
+ */
+
+#define SDP_PDU_ERROR_RESPONSE 0x01
+#define SDP_PDU_SERVICE_SEARCH_REQUEST 0x02
+#define SDP_PDU_SERVICE_SEARCH_RESPONSE 0x03
+#define SDP_PDU_SERVICE_ATTRIBUTE_REQUEST 0x04
+#define SDP_PDU_SERVICE_ATTRIBUTE_RESPONSE 0x05
+#define SDP_PDU_SERVICE_SEARCH_ATTRIBUTE_REQUEST 0x06
+#define SDP_PDU_SERVICE_SEARCH_ATTRIBUTE_RESPONSE 0x07
+
+struct sdp_pdu {
+ uint8_t pid; /* PDU ID - SDP_PDU_xxx */
+ uint16_t tid; /* transaction ID */
+ uint16_t len; /* parameters length (in bytes) */
+} __attribute__ ((packed));
+typedef struct sdp_pdu sdp_pdu_t;
+typedef struct sdp_pdu * sdp_pdu_p;
+
+/*
+ * Error codes for SDP_PDU_ERROR_RESPONSE
+ */
+
+#define SDP_ERROR_CODE_INVALID_SDP_VERSION 0x0001
+#define SDP_ERROR_CODE_INVALID_SERVICE_RECORD_HANDLE 0x0002
+#define SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX 0x0003
+#define SDP_ERROR_CODE_INVALID_PDU_SIZE 0x0004
+#define SDP_ERROR_CODE_INVALID_CONTINUATION_STATE 0x0005
+#define SDP_ERROR_CODE_INSUFFICIENT_RESOURCES 0x0006
+
+/*
+ * SDP int128/uint128 parameter
+ */
+
+struct int128 {
+ int8_t b[16];
+};
+typedef struct int128 int128_t;
+typedef struct int128 uint128_t;
+
+/*
+ * SDP attribute
+ */
+
+struct sdp_attr {
+ uint16_t flags;
+#define SDP_ATTR_OK (0 << 0)
+#define SDP_ATTR_INVALID (1 << 0)
+#define SDP_ATTR_TRUNCATED (1 << 1)
+ uint16_t attr; /* SDP_ATTR_xxx */
+ uint32_t vlen; /* length of the value[] in bytes */
+ uint8_t *value; /* base pointer */
+};
+typedef struct sdp_attr sdp_attr_t;
+typedef struct sdp_attr * sdp_attr_p;
+
+/******************************************************************************
+ * User interface
+ *****************************************************************************/
+
+/* Inline versions of get/put byte/short/long. Pointer is advanced */
+#define SDP_GET8(b, cp) { \
+ register uint8_t *t_cp = (uint8_t *)(cp); \
+ (b) = *t_cp; \
+ (cp) ++; \
+}
+
+#define SDP_GET16(s, cp) { \
+ register uint8_t *t_cp = (uint8_t *)(cp); \
+ (s) = ((uint16_t)t_cp[0] << 8) \
+ | ((uint16_t)t_cp[1]) \
+ ; \
+ (cp) += 2; \
+}
+
+#define SDP_GET32(l, cp) { \
+ register uint8_t *t_cp = (uint8_t *)(cp); \
+ (l) = ((uint32_t)t_cp[0] << 24) \
+ | ((uint32_t)t_cp[1] << 16) \
+ | ((uint32_t)t_cp[2] << 8) \
+ | ((uint32_t)t_cp[3]) \
+ ; \
+ (cp) += 4; \
+}
+
+#define SDP_GET64(l, cp) { \
+ register uint8_t *t_cp = (uint8_t *)(cp); \
+ (l) = ((uint64_t)t_cp[0] << 56) \
+ | ((uint64_t)t_cp[1] << 48) \
+ | ((uint64_t)t_cp[2] << 40) \
+ | ((uint64_t)t_cp[3] << 32) \
+ | ((uint64_t)t_cp[4] << 24) \
+ | ((uint64_t)t_cp[5] << 16) \
+ | ((uint64_t)t_cp[6] << 8) \
+ | ((uint64_t)t_cp[7]) \
+ ; \
+ (cp) += 8; \
+}
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define SDP_GET128(l, cp) { \
+ register uint8_t *t_cp = (uint8_t *)(cp); \
+ (l)->b[15] = *t_cp++; \
+ (l)->b[14] = *t_cp++; \
+ (l)->b[13] = *t_cp++; \
+ (l)->b[12] = *t_cp++; \
+ (l)->b[11] = *t_cp++; \
+ (l)->b[10] = *t_cp++; \
+ (l)->b[9] = *t_cp++; \
+ (l)->b[8] = *t_cp++; \
+ (l)->b[7] = *t_cp++; \
+ (l)->b[6] = *t_cp++; \
+ (l)->b[5] = *t_cp++; \
+ (l)->b[4] = *t_cp++; \
+ (l)->b[3] = *t_cp++; \
+ (l)->b[2] = *t_cp++; \
+ (l)->b[1] = *t_cp++; \
+ (l)->b[0] = *t_cp++; \
+ (cp) += 16; \
+}
+
+#define SDP_GET_UUID128(l, cp) { \
+ register uint8_t *t_cp = (uint8_t *)(cp); \
+ (l)->b[0] = *t_cp++; \
+ (l)->b[1] = *t_cp++; \
+ (l)->b[2] = *t_cp++; \
+ (l)->b[3] = *t_cp++; \
+ (l)->b[4] = *t_cp++; \
+ (l)->b[5] = *t_cp++; \
+ (l)->b[6] = *t_cp++; \
+ (l)->b[7] = *t_cp++; \
+ (l)->b[8] = *t_cp++; \
+ (l)->b[9] = *t_cp++; \
+ (l)->b[10] = *t_cp++; \
+ (l)->b[11] = *t_cp++; \
+ (l)->b[12] = *t_cp++; \
+ (l)->b[13] = *t_cp++; \
+ (l)->b[14] = *t_cp++; \
+ (l)->b[15] = *t_cp++; \
+ (cp) += 16; \
+}
+#elif BYTE_ORDER == BIG_ENDIAN
+#define SDP_GET128(l, cp) { \
+ register uint8_t *t_cp = (uint8_t *)(cp); \
+ (l)->b[0] = *t_cp++; \
+ (l)->b[1] = *t_cp++; \
+ (l)->b[2] = *t_cp++; \
+ (l)->b[3] = *t_cp++; \
+ (l)->b[4] = *t_cp++; \
+ (l)->b[5] = *t_cp++; \
+ (l)->b[6] = *t_cp++; \
+ (l)->b[7] = *t_cp++; \
+ (l)->b[8] = *t_cp++; \
+ (l)->b[9] = *t_cp++; \
+ (l)->b[10] = *t_cp++; \
+ (l)->b[11] = *t_cp++; \
+ (l)->b[12] = *t_cp++; \
+ (l)->b[13] = *t_cp++; \
+ (l)->b[14] = *t_cp++; \
+ (l)->b[15] = *t_cp++; \
+ (cp) += 16; \
+}
+
+#define SDP_GET_UUID128(l, cp) SDP_GET128(l, cp)
+#else
+#error "Unsupported BYTE_ORDER"
+#endif /* BYTE_ORDER */
+
+#define SDP_PUT8(b, cp) { \
+ register uint8_t t_b = (uint8_t)(b); \
+ register uint8_t *t_cp = (uint8_t *)(cp); \
+ *t_cp = t_b; \
+ (cp) ++; \
+}
+
+#define SDP_PUT16(s, cp) { \
+ register uint16_t t_s = (uint16_t)(s); \
+ register uint8_t *t_cp = (uint8_t *)(cp); \
+ *t_cp++ = t_s >> 8; \
+ *t_cp = t_s; \
+ (cp) += 2; \
+}
+
+#define SDP_PUT32(l, cp) { \
+ register uint32_t t_l = (uint32_t)(l); \
+ register uint8_t *t_cp = (uint8_t *)(cp); \
+ *t_cp++ = t_l >> 24; \
+ *t_cp++ = t_l >> 16; \
+ *t_cp++ = t_l >> 8; \
+ *t_cp = t_l; \
+ (cp) += 4; \
+}
+
+#define SDP_PUT64(l, cp) { \
+ register uint64_t t_l = (uint64_t)(l); \
+ register uint8_t *t_cp = (uint8_t *)(cp); \
+ *t_cp++ = t_l >> 56; \
+ *t_cp++ = t_l >> 48; \
+ *t_cp++ = t_l >> 40; \
+ *t_cp++ = t_l >> 32; \
+ *t_cp++ = t_l >> 24; \
+ *t_cp++ = t_l >> 16; \
+ *t_cp++ = t_l >> 8; \
+ *t_cp = t_l; \
+ (cp) += 8; \
+}
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define SDP_PUT128(l, cp) { \
+ register uint8_t *t_cp = (uint8_t *)(cp); \
+ *t_cp++ = (l)->b[15]; \
+ *t_cp++ = (l)->b[14]; \
+ *t_cp++ = (l)->b[13]; \
+ *t_cp++ = (l)->b[12]; \
+ *t_cp++ = (l)->b[11]; \
+ *t_cp++ = (l)->b[10]; \
+ *t_cp++ = (l)->b[9]; \
+ *t_cp++ = (l)->b[8]; \
+ *t_cp++ = (l)->b[7]; \
+ *t_cp++ = (l)->b[6]; \
+ *t_cp++ = (l)->b[5]; \
+ *t_cp++ = (l)->b[4]; \
+ *t_cp++ = (l)->b[3]; \
+ *t_cp++ = (l)->b[2]; \
+ *t_cp++ = (l)->b[1]; \
+ *t_cp = (l)->b[0]; \
+ (cp) += 16; \
+}
+
+#define SDP_PUT_UUID128(l, cp) { \
+ register uint8_t *t_cp = (uint8_t *)(cp); \
+ *t_cp++ = (l)->b[0]; \
+ *t_cp++ = (l)->b[1]; \
+ *t_cp++ = (l)->b[2]; \
+ *t_cp++ = (l)->b[3]; \
+ *t_cp++ = (l)->b[4]; \
+ *t_cp++ = (l)->b[5]; \
+ *t_cp++ = (l)->b[6]; \
+ *t_cp++ = (l)->b[7]; \
+ *t_cp++ = (l)->b[8]; \
+ *t_cp++ = (l)->b[9]; \
+ *t_cp++ = (l)->b[10]; \
+ *t_cp++ = (l)->b[11]; \
+ *t_cp++ = (l)->b[12]; \
+ *t_cp++ = (l)->b[13]; \
+ *t_cp++ = (l)->b[14]; \
+ *t_cp = (l)->b[15]; \
+ (cp) += 16; \
+}
+#elif BYTE_ORDER == BIG_ENDIAN
+#define SDP_PUT128(l, cp) { \
+ register uint8_t *t_cp = (uint8_t *)(cp); \
+ *t_cp++ = (l)->b[0]; \
+ *t_cp++ = (l)->b[1]; \
+ *t_cp++ = (l)->b[2]; \
+ *t_cp++ = (l)->b[3]; \
+ *t_cp++ = (l)->b[4]; \
+ *t_cp++ = (l)->b[5]; \
+ *t_cp++ = (l)->b[6]; \
+ *t_cp++ = (l)->b[7]; \
+ *t_cp++ = (l)->b[8]; \
+ *t_cp++ = (l)->b[9]; \
+ *t_cp++ = (l)->b[10]; \
+ *t_cp++ = (l)->b[11]; \
+ *t_cp++ = (l)->b[12]; \
+ *t_cp++ = (l)->b[13]; \
+ *t_cp++ = (l)->b[14]; \
+ *t_cp = (l)->b[15]; \
+ (cp) += 16; \
+}
+
+#define SDP_PUT_UUID128(l, cp) SDP_PUT128(l, cp)
+#else
+#error "Unsupported BYTE_ORDER"
+#endif /* BYTE_ORDER */
+
+void * sdp_open (bdaddr_t const *l, bdaddr_t const *r);
+void * sdp_open_local (char const *control);
+int32_t sdp_close (void *xs);
+int32_t sdp_error (void *xs);
+
+int32_t sdp_search (void *xs,
+ uint32_t plen, uint16_t const *pp,
+ uint32_t alen, uint32_t const *ap,
+ uint32_t vlen, sdp_attr_t *vp);
+
+char const * const sdp_attr2desc (uint16_t attr);
+char const * const sdp_uuid2desc (uint16_t uuid);
+void sdp_print (uint32_t level, uint8_t const *start,
+ uint8_t const *end);
+
+/******************************************************************************
+ * sdpd interface and Bluetooth profiles data
+ *****************************************************************************/
+
+#define SDP_LOCAL_PATH "/var/run/sdp"
+#define SDP_LOCAL_MTU 4096
+
+/*
+ * These are NOT defined in spec and only accepted on control sockets.
+ * The response to these request always will be SDP_PDU_ERROR_RESPONSE.
+ * The first 2 bytes (after PDU header) is an error code (in network
+ * byte order). The rest of the data (pdu->len - 2) is a response data
+ * and depend on the request.
+ *
+ * SDP_PDU_SERVICE_REGISTER_REQUEST
+ * pdu_header_t hdr;
+ * u_int16_t uuid; service class UUID (network byte order)
+ * bdaddr_t bdaddr; local BD_ADDR (or ANY)
+ * profile data[pdu->len - sizeof(uuid) - sizeof(bdaddr)]
+ *
+ * in successful reponse additional data will contain 4 bytes record handle
+ *
+ *
+ * SDP_PDU_SERVICE_UNREGISTER_REQUEST
+ * pdu_header_t hdr;
+ * u_int32_t record_handle; (network byte order)
+ *
+ * no additional data in response.
+ *
+ *
+ * SDP_PDU_SERVICE_CHANGE_REQUEST
+ * pdu_header_t hdr;
+ * u_int32_t record_handle; (network byte order)
+ * profile data[pdu->len - sizeof(record_handle)]
+ *
+ * no additional data in response.
+ */
+
+#define SDP_PDU_SERVICE_REGISTER_REQUEST 0x81
+#define SDP_PDU_SERVICE_UNREGISTER_REQUEST 0x82
+#define SDP_PDU_SERVICE_CHANGE_REQUEST 0x83
+
+struct sdp_dun_profile
+{
+ uint8_t server_channel;
+ uint8_t audio_feedback_support;
+ uint8_t reserved[2];
+};
+typedef struct sdp_dun_profile sdp_dun_profile_t;
+typedef struct sdp_dun_profile * sdp_dun_profile_p;
+
+struct sdp_ftrn_profile
+{
+ uint8_t server_channel;
+ uint8_t reserved[3];
+};
+typedef struct sdp_ftrn_profile sdp_ftrn_profile_t;
+typedef struct sdp_ftrn_profile * sdp_ftrn_profile_p;
+
+/* Keep this in sync with sdp_opush_profile */
+struct sdp_irmc_profile
+{
+ uint8_t server_channel;
+ uint8_t supported_formats_size;
+ uint8_t supported_formats[30];
+};
+typedef struct sdp_irmc_profile sdp_irmc_profile_t;
+typedef struct sdp_irmc_profile * sdp_irmc_profile_p;
+
+struct sdp_irmc_command_profile
+{
+ uint8_t server_channel;
+ uint8_t reserved[3];
+};
+typedef struct sdp_irmc_command_profile sdp_irmc_command_profile_t;
+typedef struct sdp_irmc_command_profile * sdp_irmc_command_profile_p;
+
+struct sdp_lan_profile
+{
+ uint8_t server_channel;
+ uint8_t load_factor;
+ uint8_t reserved;
+ uint8_t ip_subnet_radius;
+ uint32_t ip_subnet;
+};
+typedef struct sdp_lan_profile sdp_lan_profile_t;
+typedef struct sdp_lan_profile * sdp_lan_profile_p;
+
+/* Keep this in sync with sdp_irmc_profile */
+struct sdp_opush_profile
+{
+ uint8_t server_channel;
+ uint8_t supported_formats_size;
+ uint8_t supported_formats[30];
+};
+typedef struct sdp_opush_profile sdp_opush_profile_t;
+typedef struct sdp_opush_profile * sdp_opush_profile_p;
+
+struct sdp_sp_profile
+{
+ uint8_t server_channel;
+ uint8_t reserved[3];
+};
+typedef struct sdp_sp_profile sdp_sp_profile_t;
+typedef struct sdp_sp_profile * sdp_sp_profile_p;
+
+int32_t sdp_register_service (void *xss, uint16_t uuid,
+ bdaddr_p const bdaddr, uint8_t const *data,
+ uint32_t datalen, uint32_t *handle);
+int32_t sdp_unregister_service (void *xss, uint32_t handle);
+int32_t sdp_change_service (void *xss, uint32_t handle,
+ uint8_t const *data, uint32_t datalen);
+
+__END_DECLS
+
+#endif /* ndef _SDP_H_ */
+
diff --git a/lib/libsdp/search.c b/lib/libsdp/search.c
new file mode 100644
index 0000000..54ac3a4
--- /dev/null
+++ b/lib/libsdp/search.c
@@ -0,0 +1,421 @@
+/*
+ * search.c
+ *
+ * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.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.
+ *
+ * $Id: search.c,v 1.2 2003/09/04 22:12:13 max Exp $
+ * $FreeBSD$
+ */
+
+#include <sys/uio.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <bluetooth.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sdp-int.h>
+#include <sdp.h>
+
+int32_t
+sdp_search(void *xss,
+ uint32_t plen, uint16_t const *pp,
+ uint32_t alen, uint32_t const *ap,
+ uint32_t vlen, sdp_attr_t *vp)
+{
+ struct sdp_xpdu {
+ sdp_pdu_t pdu;
+ uint16_t len;
+ } __attribute__ ((packed)) xpdu;
+
+ sdp_session_p ss = (sdp_session_p) xss;
+ uint8_t *req = NULL, *rsp = NULL, *rsp_tmp = NULL;
+ int32_t t, len;
+ uint16_t lo, hi;
+
+ if (ss == NULL)
+ return (-1);
+
+ if (ss->req == NULL || ss->rsp == NULL ||
+ plen == 0 || pp == NULL || alen == 0 || ap == NULL) {
+ ss->error = EINVAL;
+ return (-1);
+ }
+
+ req = ss->req;
+
+ /* Calculate ServiceSearchPattern length */
+ plen = plen * (sizeof(pp[0]) + 1);
+
+ /* Calculate AttributeIDList length */
+ for (len = 0, t = 0; t < alen; t ++) {
+ lo = (uint16_t) (ap[t] >> 16);
+ hi = (uint16_t) (ap[t]);
+
+ if (lo > hi) {
+ ss->error = EINVAL;
+ return (-1);
+ }
+
+ if (lo != hi)
+ len += (sizeof(ap[t]) + 1);
+ else
+ len += (sizeof(lo) + 1);
+ }
+ alen = len;
+
+ /* Calculate length of the request */
+ len = plen + sizeof(uint8_t) + sizeof(uint16_t) +
+ /* ServiceSearchPattern */
+ sizeof(uint16_t) +
+ /* MaximumAttributeByteCount */
+ alen + sizeof(uint8_t) + sizeof(uint16_t);
+ /* AttributeIDList */
+
+ if (ss->req_e - req < len) {
+ ss->error = ENOBUFS;
+ return (-1);
+ }
+
+ /* Put ServiceSearchPattern */
+ SDP_PUT8(SDP_DATA_SEQ16, req);
+ SDP_PUT16(plen, req);
+ for (; plen > 0; pp ++, plen -= (sizeof(pp[0]) + 1)) {
+ SDP_PUT8(SDP_DATA_UUID16, req);
+ SDP_PUT16(*pp, req);
+ }
+
+ /* Put MaximumAttributeByteCount */
+ SDP_PUT16(0xffff, req);
+
+ /* Put AttributeIDList */
+ SDP_PUT8(SDP_DATA_SEQ16, req);
+ SDP_PUT16(alen, req);
+ for (; alen > 0; ap ++) {
+ lo = (uint16_t) (*ap >> 16);
+ hi = (uint16_t) (*ap);
+
+ if (lo != hi) {
+ /* Put attribute range */
+ SDP_PUT8(SDP_DATA_UINT32, req);
+ SDP_PUT32(*ap, req);
+ alen -= (sizeof(ap[0]) + 1);
+ } else {
+ /* Put attribute */
+ SDP_PUT8(SDP_DATA_UINT16, req);
+ SDP_PUT16(lo, req);
+ alen -= (sizeof(lo) + 1);
+ }
+ }
+
+ /* Submit ServiceSearchAttributeRequest and wait for response */
+ ss->cslen = 0;
+ rsp = ss->rsp;
+
+ do {
+ struct iovec iov[2];
+ uint8_t *req_cs = req;
+
+ /* Add continuation state (if any) */
+ if (ss->req_e - req_cs < ss->cslen + 1) {
+ ss->error = ENOBUFS;
+ return (-1);
+ }
+
+ SDP_PUT8(ss->cslen, req_cs);
+ if (ss->cslen > 0) {
+ memcpy(req_cs, ss->cs, ss->cslen);
+ req_cs += ss->cslen;
+ }
+
+ /* Prepare SDP PDU header */
+ xpdu.pdu.pid = SDP_PDU_SERVICE_SEARCH_ATTRIBUTE_REQUEST;
+ xpdu.pdu.tid = htons(ss->tid);
+ xpdu.pdu.len = htons(req_cs - ss->req);
+
+ /* Submit request */
+ iov[0].iov_base = (void *) &xpdu;
+ iov[0].iov_len = sizeof(xpdu.pdu);
+ iov[1].iov_base = (void *) ss->req;
+ iov[1].iov_len = req_cs - ss->req;
+
+ do {
+ len = writev(ss->s, iov, sizeof(iov)/sizeof(iov[0]));
+ } while (len < 0 && errno == EINTR);
+
+ if (len < 0) {
+ ss->error = errno;
+ return (-1);
+ }
+
+ /* Read response */
+ iov[0].iov_base = (void *) &xpdu;
+ iov[0].iov_len = sizeof(xpdu);
+ iov[1].iov_base = (void *) rsp;
+ iov[1].iov_len = ss->imtu;
+
+ do {
+ len = readv(ss->s, iov, sizeof(iov)/sizeof(iov[0]));
+ } while (len < 0 && errno == EINTR);
+
+ if (len < 0) {
+ ss->error = errno;
+ return (-1);
+ }
+ if (len < sizeof(xpdu)) {
+ ss->error = ENOMSG;
+ return (-1);
+ }
+
+ xpdu.pdu.tid = ntohs(xpdu.pdu.tid);
+ xpdu.pdu.len = ntohs(xpdu.pdu.len);
+ xpdu.len = ntohs(xpdu.len);
+
+ if (xpdu.pdu.pid == SDP_PDU_ERROR_RESPONSE ||
+ xpdu.pdu.tid != ss->tid ||
+ xpdu.pdu.len > len ||
+ xpdu.len > xpdu.pdu.len) {
+ ss->error = EIO;
+ return (-1);
+ }
+
+ /* Save continuation state (if any) */
+ ss->cslen = rsp[xpdu.len];
+ if (ss->cslen > 0) {
+ if (ss->cslen > sizeof(ss->cs)) {
+ ss->error = ENOBUFS;
+ return (-1);
+ }
+
+ memcpy(ss->cs, rsp + xpdu.len + 1, ss->cslen);
+
+ /*
+ * Ensure that we always have ss->imtu bytes
+ * available in the ss->rsp buffer
+ */
+
+ if (ss->rsp_e - rsp <= ss->imtu) {
+ uint32_t size, offset;
+
+ size = ss->rsp_e - ss->rsp + ss->imtu;
+ offset = rsp - ss->rsp;
+
+ rsp_tmp = realloc(ss->rsp, size);
+ if (rsp_tmp == NULL) {
+ ss->error = ENOMEM;
+ return (-1);
+ }
+
+ ss->rsp = rsp_tmp;
+ ss->rsp_e = ss->rsp + size;
+ rsp = ss->rsp + offset;
+ }
+ }
+
+ rsp += xpdu.len;
+ ss->tid ++;
+ } while (ss->cslen > 0);
+
+ /*
+ * If we got here then we have completed SDP transaction and now
+ * we must populate attribute values into vp array. At this point
+ * ss->rsp points to the beginning of the response and rsp points
+ * to the end of the response.
+ *
+ * From Bluetooth v1.1 spec page 364
+ *
+ * The AttributeLists is a data element sequence where each element
+ * in turn is a data element sequence representing an attribute list.
+ * Each attribute list contains attribute IDs and attribute values
+ * from one service record. The first element in each attribute list
+ * contains the attribute ID of the first attribute to be returned for
+ * that service record. The second element in each attribute list
+ * contains the corresponding attribute value. Successive pairs of
+ * elements in each attribute list contain additional attribute ID
+ * and value pairs. Only attributes that have non-null values within
+ * the service record and whose attribute IDs were specified in the
+ * SDP_ServiceSearchAttributeRequest are contained in the AttributeLists
+ * Neither an attribute ID nor attribute value is placed in
+ * AttributeLists for attributes in the service record that have no
+ * value. Within each attribute list, the attributes are listed in
+ * ascending order of attribute ID value.
+ */
+
+ if (vp == NULL)
+ goto done;
+
+ rsp_tmp = ss->rsp;
+
+ /* Skip the first SEQ */
+ SDP_GET8(t, rsp_tmp);
+ switch (t) {
+ case SDP_DATA_SEQ8:
+ SDP_GET8(len, rsp_tmp);
+ break;
+
+ case SDP_DATA_SEQ16:
+ SDP_GET16(len, rsp_tmp);
+ break;
+
+ case SDP_DATA_SEQ32:
+ SDP_GET32(len, rsp_tmp);
+ break;
+
+ default:
+ ss->error = ENOATTR;
+ return (-1);
+ /* NOT REACHED */
+ }
+
+ for (; rsp_tmp < rsp && vlen > 0; ) {
+ /* Get set of attributes for the next record */
+ SDP_GET8(t, rsp_tmp);
+ switch (t) {
+ case SDP_DATA_SEQ8:
+ SDP_GET8(len, rsp_tmp);
+ break;
+
+ case SDP_DATA_SEQ16:
+ SDP_GET16(len, rsp_tmp);
+ break;
+
+ case SDP_DATA_SEQ32:
+ SDP_GET32(len, rsp_tmp);
+ break;
+
+ default:
+ ss->error = ENOATTR;
+ return (-1);
+ /* NOT REACHED */
+ }
+
+ /* Now rsp_tmp points to list of (attr,value) pairs */
+ for (; len > 0 && vlen > 0; vp ++, vlen --) {
+ /* Attribute */
+ SDP_GET8(t, rsp_tmp);
+ if (t != SDP_DATA_UINT16) {
+ ss->error = ENOATTR;
+ return (-1);
+ }
+ SDP_GET16(vp->attr, rsp_tmp);
+
+ /* Attribute value */
+ switch (rsp_tmp[0]) {
+ case SDP_DATA_NIL:
+ alen = 0;
+ break;
+
+ case SDP_DATA_UINT8:
+ case SDP_DATA_INT8:
+ case SDP_DATA_BOOL:
+ alen = sizeof(uint8_t);
+ break;
+
+ case SDP_DATA_UINT16:
+ case SDP_DATA_INT16:
+ case SDP_DATA_UUID16:
+ alen = sizeof(uint16_t);
+ break;
+
+ case SDP_DATA_UINT32:
+ case SDP_DATA_INT32:
+ case SDP_DATA_UUID32:
+ alen = sizeof(uint32_t);
+ break;
+
+ case SDP_DATA_UINT64:
+ case SDP_DATA_INT64:
+ alen = sizeof(uint64_t);
+ break;
+
+ case SDP_DATA_UINT128:
+ case SDP_DATA_INT128:
+ case SDP_DATA_UUID128:
+ alen = sizeof(uint128_t);
+ break;
+
+ case SDP_DATA_STR8:
+ case SDP_DATA_URL8:
+ case SDP_DATA_SEQ8:
+ case SDP_DATA_ALT8:
+ alen = rsp_tmp[1] + sizeof(uint8_t);
+ break;
+
+ case SDP_DATA_STR16:
+ case SDP_DATA_URL16:
+ case SDP_DATA_SEQ16:
+ case SDP_DATA_ALT16:
+ alen = ((uint16_t)rsp_tmp[1] << 8)
+ | ((uint16_t)rsp_tmp[2]);
+ alen += sizeof(uint16_t);
+ break;
+
+ case SDP_DATA_STR32:
+ case SDP_DATA_URL32:
+ case SDP_DATA_SEQ32:
+ case SDP_DATA_ALT32:
+ alen = ((uint32_t)rsp_tmp[1] << 24)
+ | ((uint32_t)rsp_tmp[2] << 16)
+ | ((uint32_t)rsp_tmp[3] << 8)
+ | ((uint32_t)rsp_tmp[4]);
+ alen += sizeof(uint32_t);
+ break;
+
+ default:
+ ss->error = ENOATTR;
+ return (-1);
+ /* NOT REACHED */
+ }
+
+ alen += sizeof(uint8_t);
+
+ if (vp->value != NULL) {
+ if (alen <= vp->vlen) {
+ vp->flags = SDP_ATTR_OK;
+ vp->vlen = alen;
+ } else
+ vp->flags = SDP_ATTR_TRUNCATED;
+
+ memcpy(vp->value, rsp_tmp, vp->vlen);
+ } else
+ vp->flags = SDP_ATTR_INVALID;
+
+ len -= (
+ sizeof(uint8_t) + sizeof(uint16_t) +
+ alen
+ );
+
+ rsp_tmp += alen;
+ }
+ }
+done:
+ ss->error = 0;
+
+ return (0);
+}
+
diff --git a/lib/libsdp/service.c b/lib/libsdp/service.c
new file mode 100644
index 0000000..2667966
--- /dev/null
+++ b/lib/libsdp/service.c
@@ -0,0 +1,237 @@
+/*
+ * service.c
+ *
+ * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.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.
+ *
+ * $Id: service.c,v 1.1 2004/01/13 19:32:36 max Exp $
+ * $FreeBSD$
+ */
+
+#include <sys/uio.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <bluetooth.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sdp-int.h>
+#include <sdp.h>
+
+static int32_t sdp_receive_error_pdu(sdp_session_p ss);
+
+int32_t
+sdp_register_service(void *xss, uint16_t uuid, bdaddr_p const bdaddr,
+ uint8_t const *data, uint32_t datalen, uint32_t *handle)
+{
+ sdp_session_p ss = (sdp_session_p) xss;
+ struct iovec iov[4];
+ sdp_pdu_t pdu;
+ int32_t len;
+
+ if (ss == NULL)
+ return (-1);
+ if (bdaddr == NULL || data == NULL ||
+ datalen == 0 || !(ss->flags & SDP_SESSION_LOCAL)) {
+ ss->error = EINVAL;
+ return (-1);
+ }
+ if (sizeof(pdu)+sizeof(uuid)+sizeof(*bdaddr)+datalen > SDP_LOCAL_MTU) {
+ ss->error = EMSGSIZE;
+ return (-1);
+ }
+
+ pdu.pid = SDP_PDU_SERVICE_REGISTER_REQUEST;
+ pdu.tid = htons(++ss->tid);
+ pdu.len = htons(sizeof(uuid) + sizeof(*bdaddr) + datalen);
+
+ uuid = htons(uuid);
+
+ iov[0].iov_base = (void *) &pdu;
+ iov[0].iov_len = sizeof(pdu);
+
+ iov[1].iov_base = (void *) &uuid;
+ iov[1].iov_len = sizeof(uuid);
+
+ iov[2].iov_base = (void *) bdaddr;
+ iov[2].iov_len = sizeof(*bdaddr);
+
+ iov[3].iov_base = (void *) data;
+ iov[3].iov_len = datalen;
+
+ do {
+ len = writev(ss->s, iov, sizeof(iov)/sizeof(iov[0]));
+ } while (len < 0 && errno == EINTR);
+
+ if (len < 0) {
+ ss->error = errno;
+ return (-1);
+ }
+
+ len = sdp_receive_error_pdu(ss);
+ if (len < 0)
+ return (-1);
+ if (len != sizeof(pdu) + sizeof(uint16_t) + sizeof(uint32_t)) {
+ ss->error = EIO;
+ return (-1);
+ }
+
+ if (handle != NULL) {
+ *handle = (uint32_t) ss->rsp[--len];
+ *handle |= (uint32_t) ss->rsp[--len] << 8;
+ *handle |= (uint32_t) ss->rsp[--len] << 16;
+ *handle |= (uint32_t) ss->rsp[--len] << 24;
+ }
+
+ return (0);
+}
+
+int32_t
+sdp_unregister_service(void *xss, uint32_t handle)
+{
+ sdp_session_p ss = (sdp_session_p) xss;
+ struct iovec iov[2];
+ sdp_pdu_t pdu;
+ int32_t len;
+
+ if (ss == NULL)
+ return (-1);
+ if (!(ss->flags & SDP_SESSION_LOCAL)) {
+ ss->error = EINVAL;
+ return (-1);
+ }
+ if (sizeof(pdu) + sizeof(handle) > SDP_LOCAL_MTU) {
+ ss->error = EMSGSIZE;
+ return (-1);
+ }
+
+ pdu.pid = SDP_PDU_SERVICE_UNREGISTER_REQUEST;
+ pdu.tid = htons(++ss->tid);
+ pdu.len = htons(sizeof(handle));
+
+ handle = htonl(handle);
+
+ iov[0].iov_base = (void *) &pdu;
+ iov[0].iov_len = sizeof(pdu);
+
+ iov[1].iov_base = (void *) &handle;
+ iov[1].iov_len = sizeof(handle);
+
+ do {
+ len = writev(ss->s, iov, sizeof(iov)/sizeof(iov[0]));
+ } while (len < 0 && errno == EINTR);
+
+ if (len < 0) {
+ ss->error = errno;
+ return (-1);
+ }
+
+ return ((sdp_receive_error_pdu(ss) < 0)? -1 : 0);
+}
+
+int32_t
+sdp_change_service(void *xss, uint32_t handle,
+ uint8_t const *data, uint32_t datalen)
+{
+ sdp_session_p ss = (sdp_session_p) xss;
+ struct iovec iov[3];
+ sdp_pdu_t pdu;
+ int32_t len;
+
+ if (ss == NULL)
+ return (-1);
+ if (data == NULL || datalen == 0 || !(ss->flags & SDP_SESSION_LOCAL)) {
+ ss->error = EINVAL;
+ return (-1);
+ }
+ if (sizeof(pdu) + sizeof(handle) + datalen > SDP_LOCAL_MTU) {
+ ss->error = EMSGSIZE;
+ return (-1);
+ }
+
+ pdu.pid = SDP_PDU_SERVICE_CHANGE_REQUEST;
+ pdu.tid = htons(++ss->tid);
+ pdu.len = htons(sizeof(handle) + datalen);
+
+ handle = htons(handle);
+
+ iov[0].iov_base = (void *) &pdu;
+ iov[0].iov_len = sizeof(pdu);
+
+ iov[1].iov_base = (void *) &handle;
+ iov[1].iov_len = sizeof(handle);
+
+ iov[2].iov_base = (void *) data;
+ iov[2].iov_len = datalen;
+
+ do {
+ len = writev(ss->s, iov, sizeof(iov)/sizeof(iov[0]));
+ } while (len < 0 && errno == EINTR);
+
+ if (len < 0) {
+ ss->error = errno;
+ return (-1);
+ }
+
+ return ((sdp_receive_error_pdu(ss) < 0)? -1 : 0);
+}
+
+static int32_t
+sdp_receive_error_pdu(sdp_session_p ss)
+{
+ sdp_pdu_p pdu;
+ int32_t len;
+ uint16_t error;
+
+ do {
+ len = read(ss->s, ss->rsp, ss->rsp_e - ss->rsp);
+ } while (len < 0 && errno == EINTR);
+
+ if (len < 0) {
+ ss->error = errno;
+ return (-1);
+ }
+
+ pdu = (sdp_pdu_p) ss->rsp;
+ pdu->tid = ntohs(pdu->tid);
+ pdu->len = ntohs(pdu->len);
+
+ if (pdu->pid != SDP_PDU_ERROR_RESPONSE || pdu->tid != ss->tid ||
+ pdu->len < 2 || pdu->len != len - sizeof(*pdu)) {
+ ss->error = EIO;
+ return (-1);
+ }
+
+ error = (uint16_t) ss->rsp[sizeof(pdu)] << 8;
+ error |= (uint16_t) ss->rsp[sizeof(pdu) + 1];
+
+ if (error != 0) {
+ ss->error = EIO;
+ return (-1);
+ }
+
+ return (len);
+}
+
diff --git a/lib/libsdp/session.c b/lib/libsdp/session.c
new file mode 100644
index 0000000..a31f327
--- /dev/null
+++ b/lib/libsdp/session.c
@@ -0,0 +1,177 @@
+/*
+ * session.c
+ *
+ * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.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.
+ *
+ * $Id: session.c,v 1.2 2003/09/04 22:12:13 max Exp $
+ * $FreeBSD$
+ */
+
+#include <bluetooth.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sdp-int.h>
+#include <sdp.h>
+
+void *
+sdp_open(bdaddr_t const *l, bdaddr_t const *r)
+{
+ sdp_session_p ss = NULL;
+ struct sockaddr_l2cap sa;
+ socklen_t size;
+
+ if ((ss = calloc(1, sizeof(*ss))) == NULL)
+ goto fail;
+
+ if (l == NULL || r == NULL) {
+ ss->error = EINVAL;
+ goto fail;
+ }
+
+ ss->s = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BLUETOOTH_PROTO_L2CAP);
+ if (ss->s < 0) {
+ ss->error = errno;
+ goto fail;
+ }
+
+ sa.l2cap_len = sizeof(sa);
+ sa.l2cap_family = AF_BLUETOOTH;
+ sa.l2cap_psm = 0;
+ memcpy(&sa.l2cap_bdaddr, l, sizeof(sa.l2cap_bdaddr));
+ if (bind(ss->s, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
+ ss->error = errno;
+ goto fail;
+ }
+
+ sa.l2cap_psm = htole16(NG_L2CAP_PSM_SDP);
+ memcpy(&sa.l2cap_bdaddr, r, sizeof(sa.l2cap_bdaddr));
+ if (connect(ss->s, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
+ ss->error = errno;
+ goto fail;
+ }
+
+ size = sizeof(ss->omtu);
+ if (getsockopt(ss->s, SOL_L2CAP, SO_L2CAP_OMTU, &ss->omtu, &size) < 0) {
+ ss->error = errno;
+ goto fail;
+ }
+ if ((ss->req = malloc(ss->omtu)) == NULL) {
+ ss->error = ENOMEM;
+ goto fail;
+ }
+ ss->req_e = ss->req + ss->omtu;
+
+ size = sizeof(ss->imtu);
+ if (getsockopt(ss->s, SOL_L2CAP, SO_L2CAP_IMTU, &ss->imtu, &size) < 0) {
+ ss->error = errno;
+ goto fail;
+ }
+ if ((ss->rsp = malloc(ss->imtu)) == NULL) {
+ ss->error = ENOMEM;
+ goto fail;
+ }
+ ss->rsp_e = ss->rsp + ss->imtu;
+ ss->error = 0;
+fail:
+ return ((void *) ss);
+}
+
+void *
+sdp_open_local(char const *control)
+{
+ sdp_session_p ss = NULL;
+ struct sockaddr_un sa;
+
+ if ((ss = calloc(1, sizeof(*ss))) == NULL)
+ goto fail;
+
+ ss->s = socket(PF_UNIX, SOCK_STREAM, 0);
+ if (ss->s < 0) {
+ ss->error = errno;
+ goto fail;
+ }
+
+ if (control == NULL)
+ control = SDP_LOCAL_PATH;
+
+ sa.sun_len = sizeof(sa);
+ sa.sun_family = AF_UNIX;
+ strlcpy(sa.sun_path, control, sizeof(sa.sun_path));
+
+ if (connect(ss->s, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
+ ss->error = errno;
+ goto fail;
+ }
+
+ ss->flags |= SDP_SESSION_LOCAL;
+ ss->imtu = ss->omtu = SDP_LOCAL_MTU;
+
+ if ((ss->req = malloc(ss->omtu)) == NULL) {
+ ss->error = ENOMEM;
+ goto fail;
+ }
+ ss->req_e = ss->req + ss->omtu;
+
+ if ((ss->rsp = malloc(ss->imtu)) == NULL) {
+ ss->error = ENOMEM;
+ goto fail;
+ }
+ ss->rsp_e = ss->rsp + ss->imtu;
+ ss->error = 0;
+fail:
+ return ((void *) ss);
+}
+
+int32_t
+sdp_close(void *xss)
+{
+ sdp_session_p ss = (sdp_session_p) xss;
+
+ if (ss != NULL) {
+ if (ss->s >= 0)
+ close(ss->s);
+
+ if (ss->req != NULL)
+ free(ss->req);
+ if (ss->rsp != NULL)
+ free(ss->rsp);
+
+ memset(ss, 0, sizeof(*ss));
+ free(ss);
+ }
+
+ return (0);
+}
+
+int32_t
+sdp_error(void *xss)
+{
+ sdp_session_p ss = (sdp_session_p) xss;
+
+ return ((ss != NULL)? ss->error : EINVAL);
+}
diff --git a/lib/libsdp/util.c b/lib/libsdp/util.c
new file mode 100644
index 0000000..7c7330d
--- /dev/null
+++ b/lib/libsdp/util.c
@@ -0,0 +1,448 @@
+/*
+ * util.c
+ *
+ * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.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.
+ *
+ * $Id: util.c,v 1.5 2003/09/08 02:29:35 max Exp $
+ * $FreeBSD$
+ */
+
+#include <netinet/in.h>
+#include <bluetooth.h>
+#include <stdio.h>
+#include <sdp.h>
+
+/*
+ * SDP attribute description
+ */
+
+struct sdp_attr_desc {
+ uint32_t attr;
+ char const *desc;
+};
+typedef struct sdp_attr_desc sdp_attr_desc_t;
+typedef struct sdp_attr_desc * sdp_attr_desc_p;
+
+static sdp_attr_desc_t sdp_uuids_desc[] = {
+{ SDP_UUID_PROTOCOL_SDP, "SDP", },
+{ SDP_UUID_PROTOCOL_UDP, "UDP", },
+{ SDP_UUID_PROTOCOL_RFCOMM, "RFCOMM", },
+{ SDP_UUID_PROTOCOL_TCP, "TCP", },
+{ SDP_UUID_PROTOCOL_TCS_BIN, "TCS BIN", },
+{ SDP_UUID_PROTOCOL_TCS_AT, "TCS AT", },
+{ SDP_UUID_PROTOCOL_OBEX, "OBEX", },
+{ SDP_UUID_PROTOCOL_IP, "IP", },
+{ SDP_UUID_PROTOCOL_FTP, "FTP", },
+{ SDP_UUID_PROTOCOL_HTTP, "HTTP", },
+{ SDP_UUID_PROTOCOL_WSP, "WSP", },
+{ SDP_UUID_PROTOCOL_BNEP, "BNEP", },
+{ SDP_UUID_PROTOCOL_UPNP, "UPNP", },
+{ SDP_UUID_PROTOCOL_HIDP, "HIDP", },
+{ SDP_UUID_PROTOCOL_HARDCOPY_CONTROL_CHANNEL, "Hardcopy Control Channel", },
+{ SDP_UUID_PROTOCOL_HARDCOPY_DATA_CHANNEL, "Hardcopy Data Channel", },
+{ SDP_UUID_PROTOCOL_HARDCOPY_NOTIFICATION, "Hardcopy Notification", },
+{ SDP_UUID_PROTOCOL_AVCTP, "AVCTP", },
+{ SDP_UUID_PROTOCOL_AVDTP, "AVDTP", },
+{ SDP_UUID_PROTOCOL_CMPT, "CMPT", },
+{ SDP_UUID_PROTOCOL_UDI_C_PLANE, "UDI C-Plane", },
+{ SDP_UUID_PROTOCOL_L2CAP, "L2CAP", },
+/* Service Class IDs/Bluetooth Profile IDs */
+{ SDP_SERVICE_CLASS_SERVICE_DISCOVERY_SERVER, "Service Discovery Server", },
+{ SDP_SERVICE_CLASS_BROWSE_GROUP_DESCRIPTOR, "Browse Group Descriptor", },
+{ SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP, "Public Browse Group", },
+{ SDP_SERVICE_CLASS_SERIAL_PORT, "Serial Port", },
+{ SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP, "LAN Access Using PPP", },
+{ SDP_SERVICE_CLASS_DIALUP_NETWORKING, "Dial-Up Networking", },
+{ SDP_SERVICE_CLASS_IR_MC_SYNC, "IrMC Sync", },
+{ SDP_SERVICE_CLASS_OBEX_OBJECT_PUSH, "OBEX Object Push", },
+{ SDP_SERVICE_CLASS_OBEX_FILE_TRANSFER, "OBEX File Transfer", },
+{ SDP_SERVICE_CLASS_IR_MC_SYNC_COMMAND, "IrMC Sync Command", },
+{ SDP_SERVICE_CLASS_HEADSET, "Headset", },
+{ SDP_SERVICE_CLASS_CORDLESS_TELEPHONY, "Cordless Telephony", },
+{ SDP_SERVICE_CLASS_AUDIO_SOURCE, "Audio Source", },
+{ SDP_SERVICE_CLASS_AUDIO_SINK, "Audio Sink", },
+{ SDP_SERVICE_CLASS_AV_REMOTE_CONTROL_TARGET, "A/V Remote Control Target", },
+{ SDP_SERVICE_CLASS_ADVANCED_AUDIO_DISTRIBUTION, "Advanced Audio Distribution", },
+{ SDP_SERVICE_CLASS_AV_REMOTE_CONTROL, "A/V Remote Control", },
+{ SDP_SERVICE_CLASS_VIDEO_CONFERENCING, "Video Conferencing", },
+{ SDP_SERVICE_CLASS_INTERCOM, "Intercom", },
+{ SDP_SERVICE_CLASS_FAX, "Fax", },
+{ SDP_SERVICE_CLASS_HEADSET_AUDIO_GATEWAY, "Headset Audio Gateway", },
+{ SDP_SERVICE_CLASS_WAP, "WAP", },
+{ SDP_SERVICE_CLASS_WAP_CLIENT, "WAP Client", },
+{ SDP_SERVICE_CLASS_PANU, "PANU", },
+{ SDP_SERVICE_CLASS_NAP, "Network Access Point", },
+{ SDP_SERVICE_CLASS_GN, "GN", },
+{ SDP_SERVICE_CLASS_DIRECT_PRINTING, "Direct Printing", },
+{ SDP_SERVICE_CLASS_REFERENCE_PRINTING, "Reference Printing", },
+{ SDP_SERVICE_CLASS_IMAGING, "Imaging", },
+{ SDP_SERVICE_CLASS_IMAGING_RESPONDER, "Imaging Responder", },
+{ SDP_SERVICE_CLASS_IMAGING_AUTOMATIC_ARCHIVE, "Imaging Automatic Archive", },
+{ SDP_SERVICE_CLASS_IMAGING_REFERENCED_OBJECTS, "Imaging Referenced Objects", },
+{ SDP_SERVICE_CLASS_HANDSFREE, "Handsfree", },
+{ SDP_SERVICE_CLASS_HANDSFREE_AUDIO_GATEWAY, "Handsfree Audio Gateway", },
+{ SDP_SERVICE_CLASS_DIRECT_PRINTING_REFERENCE_OBJECTS, "Direct Printing Reference Objects", },
+{ SDP_SERVICE_CLASS_REFLECTED_UI, "Reflected UI", },
+{ SDP_SERVICE_CLASS_BASIC_PRINTING, "Basic Printing", },
+{ SDP_SERVICE_CLASS_PRINTING_STATUS, "Printing Status", },
+{ SDP_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE, "Human Interface Device", },
+{ SDP_SERVICE_CLASS_HARDCOPY_CABLE_REPLACEMENT, "Hardcopy Cable Replacement", },
+{ SDP_SERVICE_CLASS_HCR_PRINT, "HCR Print", },
+{ SDP_SERVICE_CLASS_HCR_SCAN, "HCR Scan", },
+{ SDP_SERVICE_CLASS_COMMON_ISDN_ACCESS, "Common ISDN Access", },
+{ SDP_SERVICE_CLASS_VIDEO_CONFERENCING_GW, "Video Conferencing Gateway", },
+{ SDP_SERVICE_CLASS_UDI_MT, "UDI MT", },
+{ SDP_SERVICE_CLASS_UDI_TA, "UDI TA", },
+{ SDP_SERVICE_CLASS_AUDIO_VIDEO, "Audio/Video", },
+{ SDP_SERVICE_CLASS_SIM_ACCESS, "SIM Access", },
+{ SDP_SERVICE_CLASS_PNP_INFORMATION, "PNP Information", },
+{ SDP_SERVICE_CLASS_GENERIC_NETWORKING, "Generic Networking", },
+{ SDP_SERVICE_CLASS_GENERIC_FILE_TRANSFER, "Generic File Transfer", },
+{ SDP_SERVICE_CLASS_GENERIC_AUDIO, "Generic Audio", },
+{ SDP_SERVICE_CLASS_GENERIC_TELEPHONY, "Generic Telephony", },
+{ SDP_SERVICE_CLASS_UPNP, "UPNP", },
+{ SDP_SERVICE_CLASS_UPNP_IP, "UPNP IP", },
+{ SDP_SERVICE_CLASS_ESDP_UPNP_IP_PAN, "ESDP UPNP IP PAN", },
+{ SDP_SERVICE_CLASS_ESDP_UPNP_IP_LAP, "ESDP UPNP IP LAP", },
+{ SDP_SERVICE_CLASS_ESDP_UPNP_L2CAP, "ESDP UPNP L2CAP", },
+{ 0xffff, NULL, }
+};
+
+static sdp_attr_desc_t sdp_attrs_desc[] = {
+{ SDP_ATTR_SERVICE_RECORD_HANDLE,
+ "Record handle",
+ },
+{ SDP_ATTR_SERVICE_CLASS_ID_LIST,
+ "Service Class ID list",
+ },
+{ SDP_ATTR_SERVICE_RECORD_STATE,
+ "Service Record State",
+ },
+{ SDP_ATTR_SERVICE_ID,
+ "Service ID",
+ },
+{ SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
+ "Protocol Descriptor List",
+ },
+{ SDP_ATTR_BROWSE_GROUP_LIST,
+ "Browse Group List",
+ },
+{ SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST,
+ "Language Base Attribute ID List",
+ },
+{ SDP_ATTR_SERVICE_INFO_TIME_TO_LIVE,
+ "Service Info Time-To-Live",
+ },
+{ SDP_ATTR_SERVICE_AVAILABILITY,
+ "Service Availability",
+ },
+{ SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST,
+ "Bluetooh Profile Descriptor List",
+ },
+{ SDP_ATTR_DOCUMENTATION_URL,
+ "Documentation URL",
+ },
+{ SDP_ATTR_CLIENT_EXECUTABLE_URL,
+ "Client Executable URL",
+ },
+{ SDP_ATTR_ICON_URL,
+ "Icon URL",
+ },
+{ SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS,
+ "Additional Protocol Descriptor Lists" },
+{ SDP_ATTR_GROUP_ID,
+/*SDP_ATTR_IP_SUBNET,
+ SDP_ATTR_VERSION_NUMBER_LIST*/
+ "Group ID/IP Subnet/Version Number List",
+ },
+{ SDP_ATTR_SERVICE_DATABASE_STATE,
+ "Service Database State",
+ },
+{ SDP_ATTR_SERVICE_VERSION,
+ "Service Version",
+ },
+{ SDP_ATTR_EXTERNAL_NETWORK,
+/*SDP_ATTR_NETWORK,
+ SDP_ATTR_SUPPORTED_DATA_STORES_LIST*/
+ "External Network/Network/Supported Data Stores List",
+ },
+{ SDP_ATTR_FAX_CLASS1_SUPPORT,
+/*SDP_ATTR_REMOTE_AUDIO_VOLUME_CONTROL*/
+ "Fax Class1 Support/Remote Audio Volume Control",
+ },
+{ SDP_ATTR_FAX_CLASS20_SUPPORT,
+/*SDP_ATTR_SUPPORTED_FORMATS_LIST*/
+ "Fax Class20 Support/Supported Formats List",
+ },
+{ SDP_ATTR_FAX_CLASS2_SUPPORT,
+ "Fax Class2 Support",
+ },
+{ SDP_ATTR_AUDIO_FEEDBACK_SUPPORT,
+ "Audio Feedback Support",
+ },
+{ SDP_ATTR_NETWORK_ADDRESS,
+ "Network Address",
+ },
+{ SDP_ATTR_WAP_GATEWAY,
+ "WAP Gateway",
+ },
+{ SDP_ATTR_HOME_PAGE_URL,
+ "Home Page URL",
+ },
+{ SDP_ATTR_WAP_STACK_TYPE,
+ "WAP Stack Type",
+ },
+{ SDP_ATTR_SECURITY_DESCRIPTION,
+ "Security Description",
+ },
+{ SDP_ATTR_NET_ACCESS_TYPE,
+ "Net Access Type",
+ },
+{ SDP_ATTR_MAX_NET_ACCESS_RATE,
+ "Max Net Access Rate",
+ },
+{ SDP_ATTR_IPV4_SUBNET,
+ "IPv4 Subnet",
+ },
+{ SDP_ATTR_IPV6_SUBNET,
+ "IPv6 Subnet",
+ },
+{ SDP_ATTR_SUPPORTED_CAPABALITIES,
+ "Supported Capabalities",
+ },
+{ SDP_ATTR_SUPPORTED_FEATURES,
+ "Supported Features",
+ },
+{ SDP_ATTR_SUPPORTED_FUNCTIONS,
+ "Supported Functions",
+ },
+{ SDP_ATTR_TOTAL_IMAGING_DATA_CAPACITY,
+ "Total Imaging Data Capacity",
+ },
+{ 0xffff, NULL, }
+};
+
+char const * const
+sdp_attr2desc(uint16_t attr)
+{
+ register sdp_attr_desc_p a = sdp_attrs_desc;
+
+ for (; a->desc != NULL; a++)
+ if (attr == a->attr)
+ break;
+
+ return ((a->desc != NULL)? a->desc : "Unknown");
+}
+
+char const * const
+sdp_uuid2desc(uint16_t uuid)
+{
+ register sdp_attr_desc_p a = sdp_uuids_desc;
+
+ for (; a->desc != NULL; a++)
+ if (uuid == a->attr)
+ break;
+
+ return ((a->desc != NULL)? a->desc : "Unknown");
+}
+
+void
+sdp_print(uint32_t level, uint8_t const *start, uint8_t const *end)
+{
+ union {
+ int8_t int8;
+ int16_t int16;
+ int32_t int32;
+ int64_t int64;
+ int128_t int128;
+ uint8_t uint8;
+ uint16_t uint16;
+ uint32_t uint32;
+ uint64_t uint64;
+ } value;
+ uint8_t type;
+ uint32_t i;
+
+ if (start == NULL || end == NULL)
+ return;
+
+ while (start < end) {
+ for (i = 0; i < level; i++)
+ printf("\t");
+
+ SDP_GET8(type, start);
+
+ switch (type) {
+ case SDP_DATA_NIL:
+ printf("nil\n");
+ break;
+
+ case SDP_DATA_UINT8:
+ SDP_GET8(value.uint8, start);
+ printf("uint8 %u\n", value.uint8);
+ break;
+ case SDP_DATA_UINT16:
+ SDP_GET16(value.uint16, start);
+ printf("uint16 %u\n", value.uint16);
+ break;
+ case SDP_DATA_UINT32:
+ SDP_GET32(value.uint32, start);
+ printf("uint32 %u\n", value.uint32);
+ break;
+ case SDP_DATA_UINT64:
+ SDP_GET64(value.uint64, start);
+ printf("uint64 %ju\n", value.uint64);
+ break;
+
+ case SDP_DATA_UINT128:
+ case SDP_DATA_INT128:
+ SDP_GET128(&value.int128, start);
+ printf("u/int128 %#8.8x%8.8x%8.8x%8.8x\n",
+ *(uint32_t *)&value.int128.b[0],
+ *(uint32_t *)&value.int128.b[4],
+ *(uint32_t *)&value.int128.b[8],
+ *(uint32_t *)&value.int128.b[12]);
+ break;
+
+ case SDP_DATA_UUID128:
+ SDP_GET_UUID128(&value.int128, start);
+ printf("uuid128 %#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x\n",
+ ntohl(*(uint32_t *)&value.int128.b[0]),
+ ntohs(*(uint16_t *)&value.int128.b[4]),
+ ntohs(*(uint16_t *)&value.int128.b[6]),
+ ntohs(*(uint16_t *)&value.int128.b[8]),
+ ntohs(*(uint16_t *)&value.int128.b[10]),
+ ntohl(*(uint32_t *)&value.int128.b[12]));
+ break;
+
+ case SDP_DATA_INT8:
+ SDP_GET8(value.int8, start);
+ printf("int8 %d\n", value.int8);
+ break;
+ case SDP_DATA_INT16:
+ SDP_GET16(value.int16, start);
+ printf("int16 %d\n", value.int16);
+ break;
+ case SDP_DATA_INT32:
+ SDP_GET32(value.int32, start);
+ printf("int32 %d\n", value.int32);
+ break;
+ case SDP_DATA_INT64:
+ SDP_GET64(value.int64, start);
+ printf("int64 %ju\n", value.int64);
+ break;
+
+ case SDP_DATA_UUID16:
+ SDP_GET16(value.uint16, start);
+ printf("uuid16 %#4.4x - %s\n", value.uint16,
+ sdp_uuid2desc(value.uint16));
+ break;
+ case SDP_DATA_UUID32:
+ SDP_GET32(value.uint32, start);
+ printf("uuid32 %#8.8x\n", value.uint32);
+ break;
+
+ case SDP_DATA_STR8:
+ SDP_GET8(value.uint8, start);
+ printf("str8 %*.*s\n", value.uint8, value.uint8, start);
+ start += value.uint8;
+ break;
+ case SDP_DATA_STR16:
+ SDP_GET16(value.uint16, start);
+ printf("str16 %*.*s\n", value.uint16, value.uint16, start);
+ start += value.uint16;
+ break;
+ case SDP_DATA_STR32:
+ SDP_GET32(value.uint32, start);
+ printf("str32 %*.*s\n", value.uint32, value.uint32, start);
+ start += value.uint32;
+ break;
+
+ case SDP_DATA_BOOL:
+ SDP_GET8(value.uint8, start);
+ printf("bool %d\n", value.uint8);
+ break;
+
+ case SDP_DATA_SEQ8:
+ SDP_GET8(value.uint8, start);
+ printf("seq8 %d\n", value.uint8);
+ sdp_print(level + 1, start, start + value.uint8);
+ start += value.uint8;
+ break;
+ case SDP_DATA_SEQ16:
+ SDP_GET16(value.uint16, start);
+ printf("seq16 %d\n", value.uint16);
+ sdp_print(level + 1, start, start + value.uint16);
+ start += value.uint16;
+ break;
+ case SDP_DATA_SEQ32:
+ SDP_GET32(value.uint32, start);
+ printf("seq32 %d\n", value.uint32);
+ sdp_print(level + 1, start, start + value.uint32);
+ start += value.uint32;
+ break;
+
+ case SDP_DATA_ALT8:
+ SDP_GET8(value.uint8, start);
+ printf("alt8 %d\n", value.uint8);
+ sdp_print(level + 1, start, start + value.uint8);
+ start += value.uint8;
+ break;
+ case SDP_DATA_ALT16:
+ SDP_GET16(value.uint16, start);
+ printf("alt16 %d\n", value.uint16);
+ sdp_print(level + 1, start, start + value.uint16);
+ start += value.uint16;
+ break;
+ case SDP_DATA_ALT32:
+ SDP_GET32(value.uint32, start);
+ printf("alt32 %d\n", value.uint32);
+ sdp_print(level + 1, start, start + value.uint32);
+ start += value.uint32;
+ break;
+
+ case SDP_DATA_URL8:
+ SDP_GET8(value.uint8, start);
+ printf("url8 %*.*s\n", value.uint8, value.uint8, start);
+ start += value.uint8;
+ break;
+ case SDP_DATA_URL16:
+ SDP_GET16(value.uint16, start);
+ printf("url16 %*.*s\n", value.uint16, value.uint16, start);
+ start += value.uint16;
+ break;
+ case SDP_DATA_URL32:
+ SDP_GET32(value.uint32, start);
+ printf("url32 %*.*s\n", value.uint32, value.uint32, start);
+ start += value.uint32;
+ break;
+
+ default:
+ printf("unknown data type: %#02x\n", *start ++);
+ break;
+ }
+ }
+}
+
diff --git a/lib/libsm/Makefile b/lib/libsm/Makefile
new file mode 100644
index 0000000..9d767e9
--- /dev/null
+++ b/lib/libsm/Makefile
@@ -0,0 +1,39 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+SENDMAIL_DIR=${.CURDIR}/../../contrib/sendmail
+.PATH: ${SENDMAIL_DIR}/libsm
+
+CFLAGS+=-I${SENDMAIL_DIR}/src -I${SENDMAIL_DIR}/include -I.
+CFLAGS+=-DNEWDB -DNIS -DMAP_REGEX -DNOT_SENDMAIL
+
+.if ${MK_INET6_SUPPORT} != "no"
+CFLAGS+=-DNETINET6
+.endif
+
+# User customizations to the sendmail build environment
+CFLAGS+=${SENDMAIL_CFLAGS}
+
+LIB= sm
+
+SRCS+= sm_os.h
+SRCS+= assert.c debug.c errstring.c exc.c heap.c match.c rpool.c \
+ strdup.c strerror.c strl.c clrerr.c fclose.c feof.c ferror.c \
+ fflush.c fget.c fpos.c findfp.c flags.c fopen.c fprintf.c \
+ fpurge.c fput.c fread.c fscanf.c fseek.c fvwrite.c fwalk.c \
+ fwrite.c get.c makebuf.c put.c refill.c rewind.c setvbuf.c \
+ smstdio.c snprintf.c sscanf.c stdio.c strio.c ungetc.c \
+ vasprintf.c vfprintf.c vfscanf.c vprintf.c vsnprintf.c \
+ wbuf.c wsetup.c string.c stringf.c \
+ xtrap.c strto.c test.c path.c strcasecmp.c strrevcmp.c \
+ signal.c clock.c config.c sem.c shm.c mbdb.c strexit.c cf.c ldap.c \
+ niprop.c mpeix.c memstat.c
+CLEANFILES+=sm_os.h
+
+INTERNALLIB=
+
+sm_os.h:
+ ln -sf ${SENDMAIL_DIR}/include/sm/os/sm_os_freebsd.h sm_os.h
+
+.include <bsd.lib.mk>
diff --git a/lib/libsmb/Makefile b/lib/libsmb/Makefile
new file mode 100644
index 0000000..1ba02d6
--- /dev/null
+++ b/lib/libsmb/Makefile
@@ -0,0 +1,19 @@
+# $FreeBSD$
+
+CONTRIBDIR= ${.CURDIR}/../../contrib/smbfs
+.PATH: ${CONTRIBDIR}/lib/smb
+
+LIB= smb
+SHLIB_MAJOR= 2
+DPADD= ${LIBKICONV}
+LDADD= -lkiconv
+
+SRCS= rcfile.c ctx.c cfopt.c subr.c nls.c rap.c mbuf.c rq.c file.c \
+ print.c \
+ kiconv.c \
+ nb.c nb_name.c nb_net.c nbns_rq.c
+
+WARNS?= 1
+CFLAGS+= -DSMB_CFG_FILE=\"/etc/nsmb.conf\" -I${CONTRIBDIR}/include
+
+.include <bsd.lib.mk>
diff --git a/lib/libsmdb/Makefile b/lib/libsmdb/Makefile
new file mode 100644
index 0000000..b796deb
--- /dev/null
+++ b/lib/libsmdb/Makefile
@@ -0,0 +1,23 @@
+# $FreeBSD$
+
+SENDMAIL_DIR=${.CURDIR}/../../contrib/sendmail
+.PATH: ${SENDMAIL_DIR}/libsmdb
+
+CFLAGS+=-I${SENDMAIL_DIR}/src -I${SENDMAIL_DIR}/include -I.
+CFLAGS+=-DNEWDB -DNOT_SENDMAIL
+
+# User customizations to the sendmail build environment
+CFLAGS+=${SENDMAIL_CFLAGS}
+
+LIB= smdb
+
+SRCS+= sm_os.h
+SRCS+= smdb.c smdb1.c smdb2.c smndbm.c
+CLEANFILES+=sm_os.h
+
+INTERNALLIB=
+
+sm_os.h:
+ ln -sf ${SENDMAIL_DIR}/include/sm/os/sm_os_freebsd.h sm_os.h
+
+.include <bsd.lib.mk>
diff --git a/lib/libsmutil/Makefile b/lib/libsmutil/Makefile
new file mode 100644
index 0000000..2e835fd
--- /dev/null
+++ b/lib/libsmutil/Makefile
@@ -0,0 +1,23 @@
+# $FreeBSD$
+
+SENDMAIL_DIR=${.CURDIR}/../../contrib/sendmail
+.PATH: ${SENDMAIL_DIR}/libsmutil
+
+CFLAGS+=-I${SENDMAIL_DIR}/src -I${SENDMAIL_DIR}/include -I.
+CFLAGS+=-DNEWDB -DNIS -DMAP_REGEX -DNOT_SENDMAIL
+
+# User customizations to the sendmail build environment
+CFLAGS+=${SENDMAIL_CFLAGS}
+
+LIB= smutil
+
+SRCS+= sm_os.h
+SRCS+= debug.c err.c lockfile.c safefile.c snprintf.c cf.c
+CLEANFILES+=sm_os.h
+
+INTERNALLIB=
+
+sm_os.h:
+ ln -sf ${SENDMAIL_DIR}/include/sm/os/sm_os_freebsd.h sm_os.h
+
+.include <bsd.lib.mk>
diff --git a/lib/libstand/Makefile b/lib/libstand/Makefile
new file mode 100644
index 0000000..56a1923
--- /dev/null
+++ b/lib/libstand/Makefile
@@ -0,0 +1,199 @@
+# $FreeBSD$
+# Originally from $NetBSD: Makefile,v 1.21 1997/10/26 22:08:38 lukem Exp $
+#
+# Notes:
+# - We don't use the libc strerror/sys_errlist because the string table is
+# quite large.
+#
+
+LIB= stand
+NO_PROFILE=
+NO_PIC=
+INCS= stand.h
+MAN= libstand.3
+
+CFLAGS+= -ffreestanding -Wformat
+CFLAGS+= -I${.CURDIR}
+
+.if ${MACHINE_ARCH} == "alpha"
+CFLAGS+= -mno-fp-regs
+.endif
+.if ${MACHINE_ARCH} == "i386" || ${MACHINE_ARCH} == "amd64"
+CFLAGS+= -mpreferred-stack-boundary=2
+CFLAGS+= -mno-mmx -mno-3dnow -mno-sse -mno-sse2
+.endif
+.if ${MACHINE_ARCH} == "i386"
+CFLAGS+= -mno-sse3
+.endif
+.if ${MACHINE_ARCH} == "powerpc"
+CFLAGS+= -msoft-float -D_STANDALONE
+.endif
+.if ${MACHINE_ARCH} == "amd64"
+CFLAGS+= -m32 -I.
+.endif
+
+# standalone components and stuff we have modified locally
+SRCS+= zutil.h __main.c assert.c bcd.c bswap.c environment.c getopt.c gets.c \
+ globals.c pager.c printf.c strdup.c strerror.c strtol.c random.c \
+ sbrk.c twiddle.c zalloc.c zalloc_malloc.c
+
+# private (pruned) versions of libc string functions
+SRCS+= strcasecmp.c
+
+# byte order functions from libc
+.if ${MACHINE_ARCH} != "amd64"
+.PATH: ${.CURDIR}/../libc/${MACHINE_ARCH}/net
+.else
+.PATH: ${.CURDIR}/../libc/i386/net
+.endif
+SRCS+= htons.S ntohs.S htonl.S ntohl.S
+
+# string functions from libc
+.PATH: ${.CURDIR}/../libc/string
+.if ${MACHINE_ARCH} == "i386" || ${MACHINE_ARCH} == "powerpc" || \
+ ${MACHINE_ARCH} == "sparc64" || ${MACHINE_ARCH} == "amd64"
+SRCS+= bcmp.c bcopy.c bzero.c ffs.c index.c memccpy.c memchr.c memcmp.c \
+ memcpy.c memmove.c memset.c qdivrem.c rindex.c strcat.c strchr.c \
+ strcmp.c strcpy.c strcspn.c strlen.c strncat.c strncmp.c strncpy.c \
+ strpbrk.c strrchr.c strsep.c strspn.c strstr.c strtok.c swab.c
+.endif
+.if ${MACHINE_ARCH} == "alpha"
+.PATH: ${.CURDIR}/../libc/alpha/string
+SRCS+= bcmp.c bcopy.S bzero.S ffs.S index.c memccpy.c memchr.c memcmp.c \
+ memcpy.S memmove.S memset.c rindex.c strcat.c strchr.c \
+ strcmp.c strcpy.c strcspn.c strlen.c \
+ strncat.c strncmp.c strncpy.c strpbrk.c strrchr.c strsep.c \
+ strspn.c strstr.c strtok.c swab.c
+
+SRCS+= __divqu.S __divq.S __divlu.S __divl.S
+SRCS+= __remqu.S __remq.S __remlu.S __reml.S
+
+CLEANFILES+= __divqu.S __divq.S __divlu.S __divl.S
+CLEANFILES+= __remqu.S __remq.S __remlu.S __reml.S
+
+
+__divqu.S: ${.CURDIR}/../libc/alpha/gen/divrem.m4
+ m4 -DNAME=__divqu -DOP=div -DS=false -DWORDSIZE=64 \
+ ${.ALLSRC} > ${.TARGET}
+
+__divq.S: ${.CURDIR}/../libc/alpha/gen/divrem.m4
+ m4 -DNAME=__divq -DOP=div -DS=true -DWORDSIZE=64 \
+ ${.ALLSRC} > ${.TARGET}
+
+__divlu.S: ${.CURDIR}/../libc/alpha/gen/divrem.m4
+ m4 -DNAME=__divlu -DOP=div -DS=false -DWORDSIZE=32 \
+ ${.ALLSRC} > ${.TARGET}
+
+__divl.S: ${.CURDIR}/../libc/alpha/gen/divrem.m4
+ m4 -DNAME=__divl -DOP=div -DS=true -DWORDSIZE=32 \
+ ${.ALLSRC} > ${.TARGET}
+
+__remqu.S: ${.CURDIR}/../libc/alpha/gen/divrem.m4
+ m4 -DNAME=__remqu -DOP=rem -DS=false -DWORDSIZE=64 \
+ ${.ALLSRC} > ${.TARGET}
+
+__remq.S: ${.CURDIR}/../libc/alpha/gen/divrem.m4
+ m4 -DNAME=__remq -DOP=rem -DS=true -DWORDSIZE=64 \
+ ${.ALLSRC} > ${.TARGET}
+
+__remlu.S: ${.CURDIR}/../libc/alpha/gen/divrem.m4
+ m4 -DNAME=__remlu -DOP=rem -DS=false -DWORDSIZE=32 \
+ ${.ALLSRC} > ${.TARGET}
+
+__reml.S: ${.CURDIR}/../libc/alpha/gen/divrem.m4
+ m4 -DNAME=__reml -DOP=rem -DS=true -DWORDSIZE=32 \
+ ${.ALLSRC} > ${.TARGET}
+.endif
+.if ${MACHINE_ARCH} == "ia64"
+.PATH: ${.CURDIR}/../libc/ia64/string
+SRCS+= bcmp.c bcopy.S bzero.S ffs.S index.c memccpy.c memchr.c memcmp.c \
+ memcpy.S memmove.S memset.c rindex.c strcat.c strchr.c \
+ strcmp.c strcpy.c strcspn.c strlen.c \
+ strncat.c strncmp.c strncpy.c strpbrk.c strrchr.c strsep.c \
+ strspn.c strstr.c strtok.c swab.c
+
+.PATH: ${.CURDIR}/../libc/ia64/gen
+SRCS+= __divdi3.S __divsi3.S __moddi3.S __modsi3.S
+SRCS+= __udivdi3.S __udivsi3.S __umoddi3.S __umodsi3.S
+.endif
+.if ${MACHINE_ARCH} == "powerpc"
+.PATH: ${.CURDIR}/../libc/quad
+SRCS+= ashldi3.c ashrdi3.c
+.PATH: ${.CURDIR}/../libc/powerpc/gen
+SRCS+= syncicache.c
+.endif
+
+# _setjmp/_longjmp
+.if ${MACHINE_ARCH} == "amd64"
+.PATH: ${.CURDIR}/i386
+.else
+.PATH: ${.CURDIR}/${MACHINE_ARCH}
+.endif
+SRCS+= _setjmp.S
+
+# decompression functionality from libbz2
+# NOTE: to actually test this functionality after libbz2 upgrade compile
+# loader(8) with LOADER_BZIP2_SUPPORT defined
+.PATH: ${.CURDIR}/../../contrib/bzip2
+CFLAGS+= -DBZ_NO_STDIO -DBZ_NO_COMPRESS
+SRCS+= libstand_bzlib_private.h
+
+.for file in bzlib.c crctable.c decompress.c huffman.c randtable.c
+SRCS+= _${file}
+CLEANFILES+= _${file}
+
+_${file}: ${file}
+ sed "s|bzlib_private\.h|libstand_bzlib_private.h|" ${.ALLSRC} > ${.TARGET}
+.endfor
+
+CLEANFILES+= libstand_bzlib_private.h
+libstand_bzlib_private.h: bzlib_private.h
+ sed -e 's|<stdlib.h>|"stand.h"|' \
+ ${.ALLSRC} > ${.TARGET}
+
+# decompression functionality from libz
+.PATH: ${.CURDIR}/../libz
+CFLAGS+=-DHAVE_MEMCPY -I${.CURDIR}/../libz
+SRCS+= adler32.c crc32.c libstand_zutil.h
+
+.for file in infback.c inffast.c inflate.c inftrees.c zutil.c
+SRCS+= _${file}
+CLEANFILES+= _${file}
+
+_${file}: ${file}
+ sed "s|zutil\.h|libstand_zutil.h|" ${.ALLSRC} > ${.TARGET}
+.endfor
+
+# depend on stand.h being able to be included multiple times
+CLEANFILES+= libstand_zutil.h
+libstand_zutil.h: zutil.h
+ sed -e 's|<stddef.h>|"stand.h"|' \
+ -e 's|<string.h>|"stand.h"|' \
+ -e 's|<stdlib.h>|"stand.h"|' \
+ ${.ALLSRC} > ${.TARGET}
+
+# io routines
+SRCS+= closeall.c dev.c ioctl.c nullfs.c stat.c \
+ fstat.c close.c lseek.c open.c read.c write.c readdir.c
+
+# network routines
+SRCS+= arp.c ether.c inet_ntoa.c in_cksum.c net.c udp.c netif.c rpc.c
+
+# network info services:
+SRCS+= bootp.c rarp.c bootparam.c
+
+# boot filesystems
+SRCS+= ufs.c nfs.c cd9660.c tftp.c gzipfs.c bzipfs.c
+SRCS+= dosfs.c ext2fs.c
+SRCS+= splitfs.c
+
+.include <bsd.lib.mk>
+
+.if ${MACHINE_ARCH} == "amd64"
+${SRCS:M*.c:R:S/$/.o/g}: machine
+
+beforedepend: machine
+
+machine:
+ ln -s ${.CURDIR}/../../sys/i386/include machine
+.endif
diff --git a/lib/libstand/__main.c b/lib/libstand/__main.c
new file mode 100644
index 0000000..1c7e677
--- /dev/null
+++ b/lib/libstand/__main.c
@@ -0,0 +1,43 @@
+/* $NetBSD: __main.c,v 1.4 1996/03/14 18:52:03 christos Exp $ */
+
+/*
+ * Copyright (c) 1993 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 by Christopher G. Demetriou.
+ * 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>
+
+void __main(void);
+
+void
+__main()
+{
+}
diff --git a/lib/libstand/alpha/_setjmp.S b/lib/libstand/alpha/_setjmp.S
new file mode 100644
index 0000000..1587978
--- /dev/null
+++ b/lib/libstand/alpha/_setjmp.S
@@ -0,0 +1,120 @@
+/* $NetBSD: _setjmp.S,v 1.2 1996/10/17 03:08:03 cgd Exp $ */
+/* $FreeBSD$ */
+
+/*
+ * Copyright (c) 1994, 1995 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <machine/asm.h>
+
+/*
+ * 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, 1)
+ LDGP(pv)
+ stq ra, (2 * 8)(a0) /* sc_pc = return address */
+ stq s0, (( 9 + 4) * 8)(a0) /* saved bits of sc_regs */
+ stq s1, ((10 + 4) * 8)(a0)
+ stq s2, ((11 + 4) * 8)(a0)
+ stq s3, ((12 + 4) * 8)(a0)
+ stq s4, ((13 + 4) * 8)(a0)
+ stq s5, ((14 + 4) * 8)(a0)
+ stq s6, ((15 + 4) * 8)(a0)
+ stq ra, ((26 + 4) * 8)(a0)
+ stq sp, ((30 + 4) * 8)(a0)
+ ldiq t0, 0xacedbadd /* sigcontext magic number */
+ stq t0, ((31 + 4) * 8)(a0) /* magic in sc_regs[31] */
+ /* Too bad we can't check if we actually used FP */
+ ldiq t0, 1
+ stq t0, (36 * 8)(a0) /* say we've used FP. */
+#if 0
+ stt fs0, ((2 + 37) * 8)(a0) /* saved bits of sc_fpregs */
+ stt fs1, ((3 + 37) * 8)(a0)
+ stt fs2, ((4 + 37) * 8)(a0)
+ stt fs3, ((5 + 37) * 8)(a0)
+ stt fs4, ((6 + 37) * 8)(a0)
+ stt fs5, ((7 + 37) * 8)(a0)
+ stt fs6, ((8 + 37) * 8)(a0)
+ stt fs7, ((9 + 37) * 8)(a0)
+ mf_fpcr ft0 /* get FP control reg */
+ stt ft0, (69 * 8)(a0) /* and store it in sc_fpcr */
+ stq zero, (70 * 8)(a0) /* FP software control XXX */
+#endif
+ stq zero, (71 * 8)(a0) /* sc_reserved[0] */
+ stq zero, (72 * 8)(a0) /* sc_reserved[1] */
+ stq zero, (73 * 8)(a0) /* sc_xxx[0] */
+ stq zero, (74 * 8)(a0) /* sc_xxx[1] */
+ stq zero, (75 * 8)(a0) /* sc_xxx[2] */
+ stq zero, (76 * 8)(a0) /* sc_xxx[3] */
+ stq zero, (77 * 8)(a0) /* sc_xxx[4] */
+ stq zero, (78 * 8)(a0) /* sc_xxx[5] */
+ stq zero, (79 * 8)(a0) /* sc_xxx[6] */
+ stq zero, (80 * 8)(a0) /* sc_xxx[7] */
+
+ mov zero, v0 /* return zero */
+ RET
+END(_setjmp)
+
+LEAF(_longjmp, 2)
+ LDGP(pv)
+
+ ldq ra, (2 * 8)(a0) /* sc_pc = return address */
+ ldq s0, (( 9 + 4) * 8)(a0) /* saved bits of sc_regs */
+ ldq s1, ((10 + 4) * 8)(a0)
+ ldq s2, ((11 + 4) * 8)(a0)
+ ldq s3, ((12 + 4) * 8)(a0)
+ ldq s4, ((13 + 4) * 8)(a0)
+ ldq s5, ((14 + 4) * 8)(a0)
+ ldq s6, ((15 + 4) * 8)(a0)
+ /* ldq ra, ((26 + 4) * 8)(a0) set above */
+ ldq sp, ((30 + 4) * 8)(a0)
+#if 0
+ ldt fs0, ((2 + 37) * 8)(a0) /* saved bits of sc_fpregs */
+ ldt fs1, ((3 + 37) * 8)(a0)
+ ldt fs2, ((4 + 37) * 8)(a0)
+ ldt fs3, ((5 + 37) * 8)(a0)
+ ldt fs4, ((6 + 37) * 8)(a0)
+ ldt fs5, ((7 + 37) * 8)(a0)
+ ldt fs6, ((8 + 37) * 8)(a0)
+ ldt fs7, ((9 + 37) * 8)(a0)
+ ldt ft0, (69 * 8)(a0) /* get sc_fpcr */
+ mt_fpcr ft0 /* and restore it. */
+#endif
+
+ mov a1, v0 /* return second arg */
+ RET
+
+END(_longjmp)
diff --git a/lib/libstand/arm/_setjmp.S b/lib/libstand/arm/_setjmp.S
new file mode 100644
index 0000000..631213f
--- /dev/null
+++ b/lib/libstand/arm/_setjmp.S
@@ -0,0 +1,106 @@
+/* $NetBSD: _setjmp.S,v 1.5 2003/04/05 23:08:51 bjh21 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$");
+
+#define SOFTFLOAT /* XXX */
+/*
+ * 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 are scratch registers in functions
+ */
+
+ENTRY(_setjmp)
+ ldr r1, .L_setjmp_magic
+ str r1, [r0], #4
+#ifdef SOFTFLOAT
+ add r0, r0, #52
+#else
+ /* Store fp registers */
+ sfm f4, 4, [r0], #48
+ /* Store fpsr */
+ rfs r1
+ str r1, [r0], #0x0004
+#endif /* SOFTFLOAT */
+ /* Store integer registers */
+ stmia r0, {r4-r14}
+
+ mov r0, #0x00000000
+ mov r15, r14
+
+.L_setjmp_magic:
+ .word _JB_MAGIC__SETJMP
+
+ENTRY(_longjmp)
+ ldr r2, .L_setjmp_magic
+ ldr r3, [r0], #4
+ teq r2, r3
+ bne botch
+
+#ifdef SOFTFLOAT
+ add r0, r0, #52
+#else
+ /* Restore fp registers */
+ lfm f4, 4, [r0], #48
+ /* Restore fpsr */
+ ldr r4, [r0], #0x0004
+ wfs r4
+#endif /* SOFTFLOAT */
+ /* Restore integer registers */
+ ldmia r0, {r4-r14}
+
+ /* Validate sp and r14 */
+ teq sp, #0
+ teqne r14, #0
+ beq botch
+
+ /* Set return value */
+ mov r0, r1
+ teq r0, #0x00000000
+ moveq r0, #0x00000001
+ mov r15, r14
+
+ /* validation failed, die die die. */
+botch:
+ bl PIC_SYM(_C_LABEL(longjmperror), PLT)
+ bl PIC_SYM(_C_LABEL(abort), PLT)
+ b . - 8 /* Cannot get here */
diff --git a/lib/libstand/arp.c b/lib/libstand/arp.c
new file mode 100644
index 0000000..59f0ce5
--- /dev/null
+++ b/lib/libstand/arp.c
@@ -0,0 +1,313 @@
+/* $NetBSD: arp.c,v 1.18 1997/07/07 15:52:49 drochner Exp $ */
+
+/*
+ * Copyright (c) 1992 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.
+ * 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, Lawrence Berkeley Laboratory 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.
+ *
+ * @(#) Header: arp.c,v 1.5 93/07/15 05:52:26 leres Exp (LBL)
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#include <netinet/in_systm.h>
+
+#include <string.h>
+
+#include "stand.h"
+#include "net.h"
+
+/* Cache stuff */
+#define ARP_NUM 8 /* need at most 3 arp entries */
+
+struct arp_list {
+ struct in_addr addr;
+ u_char ea[6];
+} arp_list[ARP_NUM] = {
+ /* XXX - net order `INADDR_BROADCAST' must be a constant */
+ { {0xffffffff}, BA }
+};
+int arp_num = 1;
+
+/* Local forwards */
+static ssize_t arpsend(struct iodesc *, void *, size_t);
+static ssize_t arprecv(struct iodesc *, void *, size_t, time_t);
+
+/* Broadcast an ARP packet, asking who has addr on interface d */
+u_char *
+arpwhohas(d, addr)
+ struct iodesc *d;
+ struct in_addr addr;
+{
+ int i;
+ struct ether_arp *ah;
+ struct arp_list *al;
+ struct {
+ struct ether_header eh;
+ struct {
+ struct ether_arp arp;
+ u_char pad[18]; /* 60 - sizeof(...) */
+ } data;
+ } wbuf;
+ struct {
+ struct ether_header eh;
+ struct {
+ struct ether_arp arp;
+ u_char pad[24]; /* extra space */
+ } data;
+ } rbuf;
+
+ /* Try for cached answer first */
+ for (i = 0, al = arp_list; i < arp_num; ++i, ++al)
+ if (addr.s_addr == al->addr.s_addr)
+ return (al->ea);
+
+ /* Don't overflow cache */
+ if (arp_num > ARP_NUM - 1) {
+ arp_num = 1; /* recycle */
+ printf("arpwhohas: overflowed arp_list!\n");
+ }
+
+#ifdef ARP_DEBUG
+ if (debug)
+ printf("arpwhohas: send request for %s\n", inet_ntoa(addr));
+#endif
+
+ bzero((char*)&wbuf.data, sizeof(wbuf.data));
+ ah = &wbuf.data.arp;
+ ah->arp_hrd = htons(ARPHRD_ETHER);
+ ah->arp_pro = htons(ETHERTYPE_IP);
+ ah->arp_hln = sizeof(ah->arp_sha); /* hardware address length */
+ ah->arp_pln = sizeof(ah->arp_spa); /* protocol address length */
+ ah->arp_op = htons(ARPOP_REQUEST);
+ MACPY(d->myea, ah->arp_sha);
+ bcopy(&d->myip, ah->arp_spa, sizeof(ah->arp_spa));
+ /* Leave zeros in arp_tha */
+ bcopy(&addr, ah->arp_tpa, sizeof(ah->arp_tpa));
+
+ /* Store ip address in cache (incomplete entry). */
+ al->addr = addr;
+
+ i = sendrecv(d,
+ arpsend, &wbuf.data, sizeof(wbuf.data),
+ arprecv, &rbuf.data, sizeof(rbuf.data));
+ if (i == -1) {
+ panic("arp: no response for %s\n",
+ inet_ntoa(addr));
+ }
+
+ /* Store ethernet address in cache */
+ ah = &rbuf.data.arp;
+#ifdef ARP_DEBUG
+ if (debug) {
+ printf("arp: response from %s\n",
+ ether_sprintf(rbuf.eh.ether_shost));
+ printf("arp: cacheing %s --> %s\n",
+ inet_ntoa(addr), ether_sprintf(ah->arp_sha));
+ }
+#endif
+ MACPY(ah->arp_sha, al->ea);
+ ++arp_num;
+
+ return (al->ea);
+}
+
+static ssize_t
+arpsend(d, pkt, len)
+ struct iodesc *d;
+ void *pkt;
+ size_t len;
+{
+
+#ifdef ARP_DEBUG
+ if (debug)
+ printf("arpsend: called\n");
+#endif
+
+ return (sendether(d, pkt, len, bcea, ETHERTYPE_ARP));
+}
+
+/*
+ * Returns 0 if this is the packet we're waiting for
+ * else -1 (and errno == 0)
+ */
+static ssize_t
+arprecv(d, pkt, len, tleft)
+ struct iodesc *d;
+ void *pkt;
+ size_t len;
+ time_t tleft;
+{
+ ssize_t n;
+ struct ether_arp *ah;
+ u_int16_t etype; /* host order */
+
+#ifdef ARP_DEBUG
+ if (debug)
+ printf("arprecv: ");
+#endif
+
+ n = readether(d, pkt, len, tleft, &etype);
+ errno = 0; /* XXX */
+ if (n == -1 || n < sizeof(struct ether_arp)) {
+#ifdef ARP_DEBUG
+ if (debug)
+ printf("bad len=%d\n", n);
+#endif
+ return (-1);
+ }
+
+ if (etype != ETHERTYPE_ARP) {
+#ifdef ARP_DEBUG
+ if (debug)
+ printf("not arp type=%d\n", etype);
+#endif
+ return (-1);
+ }
+
+ /* Ethernet address now checked in readether() */
+
+ ah = (struct ether_arp *)pkt;
+ if (ah->arp_hrd != htons(ARPHRD_ETHER) ||
+ ah->arp_pro != htons(ETHERTYPE_IP) ||
+ ah->arp_hln != sizeof(ah->arp_sha) ||
+ ah->arp_pln != sizeof(ah->arp_spa) )
+ {
+#ifdef ARP_DEBUG
+ if (debug)
+ printf("bad hrd/pro/hln/pln\n");
+#endif
+ return (-1);
+ }
+
+ if (ah->arp_op == htons(ARPOP_REQUEST)) {
+#ifdef ARP_DEBUG
+ if (debug)
+ printf("is request\n");
+#endif
+ arp_reply(d, ah);
+ return (-1);
+ }
+
+ if (ah->arp_op != htons(ARPOP_REPLY)) {
+#ifdef ARP_DEBUG
+ if (debug)
+ printf("not ARP reply\n");
+#endif
+ return (-1);
+ }
+
+ /* Is the reply from the source we want? */
+ if (bcmp(&arp_list[arp_num].addr,
+ ah->arp_spa, sizeof(ah->arp_spa)))
+ {
+#ifdef ARP_DEBUG
+ if (debug)
+ printf("unwanted address\n");
+#endif
+ return (-1);
+ }
+ /* We don't care who the reply was sent to. */
+
+ /* We have our answer. */
+#ifdef ARP_DEBUG
+ if (debug)
+ printf("got it\n");
+#endif
+ return (n);
+}
+
+/*
+ * Convert an ARP request into a reply and send it.
+ * Notes: Re-uses buffer. Pad to length = 46.
+ */
+void
+arp_reply(d, pkt)
+ struct iodesc *d;
+ void *pkt; /* the request */
+{
+ struct ether_arp *arp = pkt;
+
+ if (arp->arp_hrd != htons(ARPHRD_ETHER) ||
+ arp->arp_pro != htons(ETHERTYPE_IP) ||
+ arp->arp_hln != sizeof(arp->arp_sha) ||
+ arp->arp_pln != sizeof(arp->arp_spa) )
+ {
+#ifdef ARP_DEBUG
+ if (debug)
+ printf("arp_reply: bad hrd/pro/hln/pln\n");
+#endif
+ return;
+ }
+
+ if (arp->arp_op != htons(ARPOP_REQUEST)) {
+#ifdef ARP_DEBUG
+ if (debug)
+ printf("arp_reply: not request!\n");
+#endif
+ return;
+ }
+
+ /* If we are not the target, ignore the request. */
+ if (bcmp(arp->arp_tpa, &d->myip, sizeof(arp->arp_tpa)))
+ return;
+
+#ifdef ARP_DEBUG
+ if (debug) {
+ printf("arp_reply: to %s\n", ether_sprintf(arp->arp_sha));
+ }
+#endif
+
+ arp->arp_op = htons(ARPOP_REPLY);
+ /* source becomes target */
+ bcopy(arp->arp_sha, arp->arp_tha, sizeof(arp->arp_tha));
+ bcopy(arp->arp_spa, arp->arp_tpa, sizeof(arp->arp_tpa));
+ /* here becomes source */
+ bcopy(d->myea, arp->arp_sha, sizeof(arp->arp_sha));
+ bcopy(&d->myip, arp->arp_spa, sizeof(arp->arp_spa));
+
+ /*
+ * No need to get fancy here. If the send fails, the
+ * requestor will just ask again.
+ */
+ (void) sendether(d, pkt, sizeof(*arp) + 18,
+ arp->arp_tha, ETHERTYPE_ARP);
+}
diff --git a/lib/libstand/assert.c b/lib/libstand/assert.c
new file mode 100644
index 0000000..b424358
--- /dev/null
+++ b/lib/libstand/assert.c
@@ -0,0 +1,44 @@
+/*-
+ * Copyright (c) 1998 Michael Smith.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 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 "stand.h"
+
+void
+__assert(const char *func, const char *file, int line, const char *expression)
+{
+ if (func == NULL)
+ printf("Assertion failed: (%s), file %s, line %d.\n",
+ expression, file, line);
+ else
+ printf("Assertion failed: (%s), function %s, file %s, line "
+ "%d.\n", expression, func, file, line);
+ exit();
+}
diff --git a/lib/libstand/bcd.c b/lib/libstand/bcd.c
new file mode 100644
index 0000000..7bd67c9
--- /dev/null
+++ b/lib/libstand/bcd.c
@@ -0,0 +1,38 @@
+/*
+ * Some data-tables that are often used.
+ * Cannot be copyrighted.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+u_char const bcd2bin_data[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0, 0, 0, 0, 0, 0,
+ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 0, 0, 0, 0, 0, 0,
+ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 0, 0, 0, 0, 0, 0,
+ 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 0, 0, 0, 0, 0, 0,
+ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 0, 0, 0, 0, 0, 0,
+ 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 0, 0, 0, 0, 0, 0,
+ 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 0, 0, 0, 0, 0, 0,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 0, 0, 0, 0, 0, 0,
+ 90, 91, 92, 93, 94, 95, 96, 97, 98, 99
+};
+
+u_char const bin2bcd_data[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99
+};
+
+/* This is actually used with radix [2..36] */
+char const hex2ascii_data[] = "0123456789abcdefghijklmnopqrstuvwxyz";
diff --git a/lib/libstand/bootp.c b/lib/libstand/bootp.c
new file mode 100644
index 0000000..0a6d310
--- /dev/null
+++ b/lib/libstand/bootp.c
@@ -0,0 +1,418 @@
+/* $NetBSD: bootp.c,v 1.14 1998/02/16 11:10:54 drochner Exp $ */
+
+/*
+ * Copyright (c) 1992 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.
+ * 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, Lawrence Berkeley Laboratory 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.
+ *
+ * @(#) Header: bootp.c,v 1.4 93/09/11 03:13:51 leres Exp (LBL)
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+
+#include <string.h>
+
+#define BOOTP_DEBUGxx
+#define SUPPORT_DHCP
+
+#include "stand.h"
+#include "net.h"
+#include "netif.h"
+#include "bootp.h"
+
+
+struct in_addr servip;
+
+static n_long nmask, smask;
+
+static time_t bot;
+
+static char vm_rfc1048[4] = VM_RFC1048;
+#ifdef BOOTP_VEND_CMU
+static char vm_cmu[4] = VM_CMU;
+#endif
+
+/* Local forwards */
+static ssize_t bootpsend(struct iodesc *, void *, size_t);
+static ssize_t bootprecv(struct iodesc *, void *, size_t, time_t);
+static int vend_rfc1048(u_char *, u_int);
+#ifdef BOOTP_VEND_CMU
+static void vend_cmu(u_char *);
+#endif
+
+#ifdef SUPPORT_DHCP
+static char expected_dhcpmsgtype = -1, dhcp_ok;
+struct in_addr dhcp_serverip;
+#endif
+
+/* Fetch required bootp infomation */
+void
+bootp(sock, flag)
+ int sock;
+ int flag;
+{
+ struct iodesc *d;
+ struct bootp *bp;
+ struct {
+ u_char header[HEADER_SIZE];
+ struct bootp wbootp;
+ } wbuf;
+ struct {
+ u_char header[HEADER_SIZE];
+ struct bootp rbootp;
+ } rbuf;
+
+#ifdef BOOTP_DEBUG
+ if (debug)
+ printf("bootp: socket=%d\n", sock);
+#endif
+ if (!bot)
+ bot = getsecs();
+
+ if (!(d = socktodesc(sock))) {
+ printf("bootp: bad socket. %d\n", sock);
+ return;
+ }
+#ifdef BOOTP_DEBUG
+ if (debug)
+ printf("bootp: d=%lx\n", (long)d);
+#endif
+
+ bp = &wbuf.wbootp;
+ bzero(bp, sizeof(*bp));
+
+ bp->bp_op = BOOTREQUEST;
+ bp->bp_htype = 1; /* 10Mb Ethernet (48 bits) */
+ bp->bp_hlen = 6;
+ bp->bp_xid = htonl(d->xid);
+ MACPY(d->myea, bp->bp_chaddr);
+ strncpy(bp->bp_file, bootfile, sizeof(bp->bp_file));
+ bcopy(vm_rfc1048, bp->bp_vend, sizeof(vm_rfc1048));
+#ifdef SUPPORT_DHCP
+ bp->bp_vend[4] = TAG_DHCP_MSGTYPE;
+ bp->bp_vend[5] = 1;
+ bp->bp_vend[6] = DHCPDISCOVER;
+
+ /*
+ * If we are booting from PXE, we want to send the string
+ * 'PXEClient' to the DHCP server so you have the option of
+ * only responding to PXE aware dhcp requests.
+ */
+ if (flag & BOOTP_PXE) {
+ bp->bp_vend[7] = TAG_CLASSID;
+ bp->bp_vend[8] = 9;
+ bcopy("PXEClient", &bp->bp_vend[9], 9);
+ bp->bp_vend[18] = TAG_END;
+ } else
+ bp->bp_vend[7] = TAG_END;
+#else
+ bp->bp_vend[4] = TAG_END;
+#endif
+
+ d->myip.s_addr = INADDR_ANY;
+ d->myport = htons(IPPORT_BOOTPC);
+ d->destip.s_addr = INADDR_BROADCAST;
+ d->destport = htons(IPPORT_BOOTPS);
+
+#ifdef SUPPORT_DHCP
+ expected_dhcpmsgtype = DHCPOFFER;
+ dhcp_ok = 0;
+#endif
+
+ if(sendrecv(d,
+ bootpsend, bp, sizeof(*bp),
+ bootprecv, &rbuf.rbootp, sizeof(rbuf.rbootp))
+ == -1) {
+ printf("bootp: no reply\n");
+ return;
+ }
+
+#ifdef SUPPORT_DHCP
+ if(dhcp_ok) {
+ u_int32_t leasetime;
+ bp->bp_vend[6] = DHCPREQUEST;
+ bp->bp_vend[7] = TAG_REQ_ADDR;
+ bp->bp_vend[8] = 4;
+ bcopy(&rbuf.rbootp.bp_yiaddr, &bp->bp_vend[9], 4);
+ bp->bp_vend[13] = TAG_SERVERID;
+ bp->bp_vend[14] = 4;
+ bcopy(&dhcp_serverip.s_addr, &bp->bp_vend[15], 4);
+ bp->bp_vend[19] = TAG_LEASETIME;
+ bp->bp_vend[20] = 4;
+ leasetime = htonl(300);
+ bcopy(&leasetime, &bp->bp_vend[21], 4);
+ if (flag & BOOTP_PXE) {
+ bp->bp_vend[25] = TAG_CLASSID;
+ bp->bp_vend[26] = 9;
+ bcopy("PXEClient", &bp->bp_vend[27], 9);
+ bp->bp_vend[36] = TAG_END;
+ } else
+ bp->bp_vend[25] = TAG_END;
+
+ expected_dhcpmsgtype = DHCPACK;
+
+ if(sendrecv(d,
+ bootpsend, bp, sizeof(*bp),
+ bootprecv, &rbuf.rbootp, sizeof(rbuf.rbootp))
+ == -1) {
+ printf("DHCPREQUEST failed\n");
+ return;
+ }
+ }
+#endif
+
+ myip = d->myip = rbuf.rbootp.bp_yiaddr;
+ servip = rbuf.rbootp.bp_siaddr;
+ if(rootip.s_addr == INADDR_ANY) rootip = servip;
+ bcopy(rbuf.rbootp.bp_file, bootfile, sizeof(bootfile));
+ bootfile[sizeof(bootfile) - 1] = '\0';
+
+ if (IN_CLASSA(ntohl(myip.s_addr)))
+ nmask = htonl(IN_CLASSA_NET);
+ else if (IN_CLASSB(ntohl(myip.s_addr)))
+ nmask = htonl(IN_CLASSB_NET);
+ else
+ nmask = htonl(IN_CLASSC_NET);
+#ifdef BOOTP_DEBUG
+ if (debug)
+ printf("'native netmask' is %s\n", intoa(nmask));
+#endif
+
+ /* Check subnet mask against net mask; toss if bogus */
+ if ((nmask & smask) != nmask) {
+#ifdef BOOTP_DEBUG
+ if (debug)
+ printf("subnet mask (%s) bad\n", intoa(smask));
+#endif
+ smask = 0;
+ }
+
+ /* Get subnet (or natural net) mask */
+ netmask = nmask;
+ if (smask)
+ netmask = smask;
+#ifdef BOOTP_DEBUG
+ if (debug)
+ printf("mask: %s\n", intoa(netmask));
+#endif
+
+ /* We need a gateway if root is on a different net */
+ if (!SAMENET(myip, rootip, netmask)) {
+#ifdef BOOTP_DEBUG
+ if (debug)
+ printf("need gateway for root ip\n");
+#endif
+ }
+
+ /* Toss gateway if on a different net */
+ if (!SAMENET(myip, gateip, netmask)) {
+#ifdef BOOTP_DEBUG
+ if (debug)
+ printf("gateway ip (%s) bad\n", inet_ntoa(gateip));
+#endif
+ gateip.s_addr = 0;
+ }
+
+ /* Bump xid so next request will be unique. */
+ ++d->xid;
+}
+
+/* Transmit a bootp request */
+static ssize_t
+bootpsend(d, pkt, len)
+ struct iodesc *d;
+ void *pkt;
+ size_t len;
+{
+ struct bootp *bp;
+
+#ifdef BOOTP_DEBUG
+ if (debug)
+ printf("bootpsend: d=%lx called.\n", (long)d);
+#endif
+
+ bp = pkt;
+ bp->bp_secs = htons((u_short)(getsecs() - bot));
+
+#ifdef BOOTP_DEBUG
+ if (debug)
+ printf("bootpsend: calling sendudp\n");
+#endif
+
+ return (sendudp(d, pkt, len));
+}
+
+static ssize_t
+bootprecv(d, pkt, len, tleft)
+struct iodesc *d;
+void *pkt;
+size_t len;
+time_t tleft;
+{
+ ssize_t n;
+ struct bootp *bp;
+
+#ifdef BOOTP_DEBUGx
+ if (debug)
+ printf("bootp_recvoffer: called\n");
+#endif
+
+ n = readudp(d, pkt, len, tleft);
+ if (n == -1 || n < sizeof(struct bootp) - BOOTP_VENDSIZE)
+ goto bad;
+
+ bp = (struct bootp *)pkt;
+
+#ifdef BOOTP_DEBUG
+ if (debug)
+ printf("bootprecv: checked. bp = 0x%lx, n = %d\n",
+ (long)bp, (int)n);
+#endif
+ if (bp->bp_xid != htonl(d->xid)) {
+#ifdef BOOTP_DEBUG
+ if (debug) {
+ printf("bootprecv: expected xid 0x%lx, got 0x%x\n",
+ d->xid, ntohl(bp->bp_xid));
+ }
+#endif
+ goto bad;
+ }
+
+#ifdef BOOTP_DEBUG
+ if (debug)
+ printf("bootprecv: got one!\n");
+#endif
+
+ /* Suck out vendor info */
+ if (bcmp(vm_rfc1048, bp->bp_vend, sizeof(vm_rfc1048)) == 0) {
+ if(vend_rfc1048(bp->bp_vend, sizeof(bp->bp_vend)) != 0)
+ goto bad;
+ }
+#ifdef BOOTP_VEND_CMU
+ else if (bcmp(vm_cmu, bp->bp_vend, sizeof(vm_cmu)) == 0)
+ vend_cmu(bp->bp_vend);
+#endif
+ else
+ printf("bootprecv: unknown vendor 0x%lx\n", (long)bp->bp_vend);
+
+ return(n);
+bad:
+ errno = 0;
+ return (-1);
+}
+
+static int
+vend_rfc1048(cp, len)
+ u_char *cp;
+ u_int len;
+{
+ u_char *ep;
+ int size;
+ u_char tag;
+
+#ifdef BOOTP_DEBUG
+ if (debug)
+ printf("vend_rfc1048 bootp info. len=%d\n", len);
+#endif
+ ep = cp + len;
+
+ /* Step over magic cookie */
+ cp += sizeof(int);
+
+ while (cp < ep) {
+ tag = *cp++;
+ size = *cp++;
+ if (tag == TAG_END)
+ break;
+
+ if (tag == TAG_SUBNET_MASK) {
+ bcopy(cp, &smask, sizeof(smask));
+ }
+ if (tag == TAG_GATEWAY) {
+ bcopy(cp, &gateip.s_addr, sizeof(gateip.s_addr));
+ }
+ if (tag == TAG_SWAPSERVER) {
+ /* let it override bp_siaddr */
+ bcopy(cp, &rootip.s_addr, sizeof(swapip.s_addr));
+ }
+ if (tag == TAG_ROOTPATH) {
+ strncpy(rootpath, (char *)cp, sizeof(rootpath));
+ rootpath[size] = '\0';
+ }
+ if (tag == TAG_HOSTNAME) {
+ strncpy(hostname, (char *)cp, sizeof(hostname));
+ hostname[size] = '\0';
+ }
+#ifdef SUPPORT_DHCP
+ if (tag == TAG_DHCP_MSGTYPE) {
+ if(*cp != expected_dhcpmsgtype)
+ return(-1);
+ dhcp_ok = 1;
+ }
+ if (tag == TAG_SERVERID) {
+ bcopy(cp, &dhcp_serverip.s_addr,
+ sizeof(dhcp_serverip.s_addr));
+ }
+#endif
+ cp += size;
+ }
+ return(0);
+}
+
+#ifdef BOOTP_VEND_CMU
+static void
+vend_cmu(cp)
+ u_char *cp;
+{
+ struct cmu_vend *vp;
+
+#ifdef BOOTP_DEBUG
+ if (debug)
+ printf("vend_cmu bootp info.\n");
+#endif
+ vp = (struct cmu_vend *)cp;
+
+ if (vp->v_smask.s_addr != 0) {
+ smask = vp->v_smask.s_addr;
+ }
+ if (vp->v_dgate.s_addr != 0) {
+ gateip = vp->v_dgate;
+ }
+}
+#endif
diff --git a/lib/libstand/bootp.h b/lib/libstand/bootp.h
new file mode 100644
index 0000000..ed9101f
--- /dev/null
+++ b/lib/libstand/bootp.h
@@ -0,0 +1,145 @@
+/* $NetBSD: bootp.h,v 1.4 1997/09/06 13:55:57 drochner Exp $ */
+
+/*
+ * Bootstrap Protocol (BOOTP). RFC951 and RFC1048.
+ *
+ * This file specifies the "implementation-independent" BOOTP protocol
+ * information which is common to both client and server.
+ *
+ * Copyright 1988 by Carnegie Mellon.
+ *
+ * Permission to use, copy, modify, and distribute this program for any
+ * purpose and without fee is hereby granted, provided that this copyright
+ * and permission notice appear on all copies and supporting documentation,
+ * the name of Carnegie Mellon not be used in advertising or publicity
+ * pertaining to distribution of the program without specific prior
+ * permission, and notice be given in supporting documentation that copying
+ * and distribution is by permission of Carnegie Mellon and Stanford
+ * University. Carnegie Mellon makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * $FreeBSD$
+ */
+
+
+struct bootp {
+ unsigned char bp_op; /* packet opcode type */
+ unsigned char bp_htype; /* hardware addr type */
+ unsigned char bp_hlen; /* hardware addr length */
+ unsigned char bp_hops; /* gateway hops */
+ unsigned int bp_xid; /* transaction ID */
+ unsigned short bp_secs; /* seconds since boot began */
+ unsigned short bp_flags;
+ struct in_addr bp_ciaddr; /* client IP address */
+ struct in_addr bp_yiaddr; /* 'your' IP address */
+ struct in_addr bp_siaddr; /* server IP address */
+ struct in_addr bp_giaddr; /* gateway IP address */
+ unsigned char bp_chaddr[16]; /* client hardware address */
+ unsigned char bp_sname[64]; /* server host name */
+ unsigned char bp_file[128]; /* boot file name */
+#ifdef SUPPORT_DHCP
+#define BOOTP_VENDSIZE 312
+#else
+#define BOOTP_VENDSIZE 64
+#endif
+ unsigned char bp_vend[BOOTP_VENDSIZE]; /* vendor-specific area */
+};
+
+/*
+ * UDP port numbers, server and client.
+ */
+#define IPPORT_BOOTPS 67
+#define IPPORT_BOOTPC 68
+
+#define BOOTREPLY 2
+#define BOOTREQUEST 1
+
+
+/*
+ * Vendor magic cookie (v_magic) for CMU
+ */
+#define VM_CMU "CMU"
+
+/*
+ * Vendor magic cookie (v_magic) for RFC1048
+ */
+#define VM_RFC1048 { 99, 130, 83, 99 }
+
+
+
+/*
+ * RFC1048 tag values used to specify what information is being supplied in
+ * the vendor field of the packet.
+ */
+
+#define TAG_PAD ((unsigned char) 0)
+#define TAG_SUBNET_MASK ((unsigned char) 1)
+#define TAG_TIME_OFFSET ((unsigned char) 2)
+#define TAG_GATEWAY ((unsigned char) 3)
+#define TAG_TIME_SERVER ((unsigned char) 4)
+#define TAG_NAME_SERVER ((unsigned char) 5)
+#define TAG_DOMAIN_SERVER ((unsigned char) 6)
+#define TAG_LOG_SERVER ((unsigned char) 7)
+#define TAG_COOKIE_SERVER ((unsigned char) 8)
+#define TAG_LPR_SERVER ((unsigned char) 9)
+#define TAG_IMPRESS_SERVER ((unsigned char) 10)
+#define TAG_RLP_SERVER ((unsigned char) 11)
+#define TAG_HOSTNAME ((unsigned char) 12)
+#define TAG_BOOTSIZE ((unsigned char) 13)
+#define TAG_DUMPFILE ((unsigned char) 14)
+#define TAG_DOMAINNAME ((unsigned char) 15)
+#define TAG_SWAPSERVER ((unsigned char) 16)
+#define TAG_ROOTPATH ((unsigned char) 17)
+
+#ifdef SUPPORT_DHCP
+#define TAG_REQ_ADDR ((unsigned char) 50)
+#define TAG_LEASETIME ((unsigned char) 51)
+#define TAG_OVERLOAD ((unsigned char) 52)
+#define TAG_DHCP_MSGTYPE ((unsigned char) 53)
+#define TAG_SERVERID ((unsigned char) 54)
+#define TAG_PARAM_REQ ((unsigned char) 55)
+#define TAG_MSG ((unsigned char) 56)
+#define TAG_MAXSIZE ((unsigned char) 57)
+#define TAG_T1 ((unsigned char) 58)
+#define TAG_T2 ((unsigned char) 59)
+#define TAG_CLASSID ((unsigned char) 60)
+#define TAG_CLIENTID ((unsigned char) 61)
+#endif
+
+#define TAG_END ((unsigned char) 255)
+
+#ifdef SUPPORT_DHCP
+#define DHCPDISCOVER 1
+#define DHCPOFFER 2
+#define DHCPREQUEST 3
+#define DHCPDECLINE 4
+#define DHCPACK 5
+#define DHCPNAK 6
+#define DHCPRELEASE 7
+#endif
+
+/*
+ * bootp flags
+ */
+#define BOOTP_NONE 0x0000 /* No flags */
+#define BOOTP_PXE 0x0001 /* Booting from PXE. */
+
+/*
+ * "vendor" data permitted for CMU bootp clients.
+ */
+
+struct cmu_vend {
+ unsigned char v_magic[4]; /* magic number */
+ unsigned int v_flags; /* flags/opcodes, etc. */
+ struct in_addr v_smask; /* Subnet mask */
+ struct in_addr v_dgate; /* Default gateway */
+ struct in_addr v_dns1, v_dns2; /* Domain name servers */
+ struct in_addr v_ins1, v_ins2; /* IEN-116 name servers */
+ struct in_addr v_ts1, v_ts2; /* Time servers */
+ unsigned char v_unused[25]; /* currently unused */
+};
+
+
+/* v_flags values */
+#define VF_SMASK 1 /* Subnet mask field contains valid data */
diff --git a/lib/libstand/bootparam.c b/lib/libstand/bootparam.c
new file mode 100644
index 0000000..e4d2f10
--- /dev/null
+++ b/lib/libstand/bootparam.c
@@ -0,0 +1,452 @@
+/* $NetBSD: bootparam.c,v 1.11 1997/06/26 19:11:32 drochner Exp $ */
+
+/*
+ * Copyright (c) 1995 Gordon W. Ross
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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.
+ * 4. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Gordon W. Ross
+ *
+ * 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$");
+
+/*
+ * RPC/bootparams
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+
+#include <string.h>
+
+#include "rpcv2.h"
+
+#include "stand.h"
+#include "net.h"
+#include "netif.h"
+#include "rpc.h"
+#include "bootparam.h"
+
+#ifdef DEBUG_RPC
+#define RPC_PRINTF(a) printf a
+#else
+#define RPC_PRINTF(a)
+#endif
+
+struct in_addr bp_server_addr; /* net order */
+n_short bp_server_port; /* net order */
+
+/*
+ * RPC definitions for bootparamd
+ */
+#define BOOTPARAM_PROG 100026
+#define BOOTPARAM_VERS 1
+#define BOOTPARAM_WHOAMI 1
+#define BOOTPARAM_GETFILE 2
+
+/*
+ * Inet address in RPC messages
+ * (Note, really four ints, NOT chars. Blech.)
+ */
+struct xdr_inaddr {
+ u_int32_t atype;
+ int32_t addr[4];
+};
+
+int xdr_inaddr_encode(char **p, struct in_addr ia);
+int xdr_inaddr_decode(char **p, struct in_addr *ia);
+
+int xdr_string_encode(char **p, char *str, int len);
+int xdr_string_decode(char **p, char *str, int *len_p);
+
+
+/*
+ * RPC: bootparam/whoami
+ * Given client IP address, get:
+ * client name (hostname)
+ * domain name (domainname)
+ * gateway address
+ *
+ * The hostname and domainname are set here for convenience.
+ *
+ * Note - bpsin is initialized to the broadcast address,
+ * and will be replaced with the bootparam server address
+ * after this call is complete. Have to use PMAP_PROC_CALL
+ * to make sure we get responses only from a servers that
+ * know about us (don't want to broadcast a getport call).
+ */
+int
+bp_whoami(sockfd)
+ int sockfd;
+{
+ /* RPC structures for PMAPPROC_CALLIT */
+ struct args {
+ u_int32_t prog;
+ u_int32_t vers;
+ u_int32_t proc;
+ u_int32_t arglen;
+ struct xdr_inaddr xina;
+ } *args;
+ struct repl {
+ u_int16_t _pad;
+ u_int16_t port;
+ u_int32_t encap_len;
+ /* encapsulated data here */
+ n_long capsule[64];
+ } *repl;
+ struct {
+ n_long h[RPC_HEADER_WORDS];
+ struct args d;
+ } sdata;
+ struct {
+ n_long h[RPC_HEADER_WORDS];
+ struct repl d;
+ } rdata;
+ char *send_tail, *recv_head;
+ struct iodesc *d;
+ int len, x;
+
+ RPC_PRINTF(("bp_whoami: myip=%s\n", inet_ntoa(myip)));
+
+ if (!(d = socktodesc(sockfd))) {
+ RPC_PRINTF(("bp_whoami: bad socket. %d\n", sockfd));
+ return (-1);
+ }
+ args = &sdata.d;
+ repl = &rdata.d;
+
+ /*
+ * Build request args for PMAPPROC_CALLIT.
+ */
+ args->prog = htonl(BOOTPARAM_PROG);
+ args->vers = htonl(BOOTPARAM_VERS);
+ args->proc = htonl(BOOTPARAM_WHOAMI);
+ args->arglen = htonl(sizeof(struct xdr_inaddr));
+ send_tail = (char*) &args->xina;
+
+ /*
+ * append encapsulated data (client IP address)
+ */
+ if (xdr_inaddr_encode(&send_tail, myip))
+ return (-1);
+
+ /* RPC: portmap/callit */
+ d->myport = htons(--rpc_port);
+ d->destip.s_addr = INADDR_BROADCAST; /* XXX: subnet bcast? */
+ /* rpc_call will set d->destport */
+
+ len = rpc_call(d, PMAPPROG, PMAPVERS, PMAPPROC_CALLIT,
+ args, send_tail - (char*)args,
+ repl, sizeof(*repl));
+ if (len < 8) {
+ printf("bootparamd: 'whoami' call failed\n");
+ return (-1);
+ }
+
+ /* Save bootparam server address (from IP header). */
+ rpc_fromaddr(repl, &bp_server_addr, &bp_server_port);
+
+ /*
+ * Note that bp_server_port is now 111 due to the
+ * indirect call (using PMAPPROC_CALLIT), so get the
+ * actual port number from the reply data.
+ */
+ bp_server_port = repl->port;
+
+ RPC_PRINTF(("bp_whoami: server at %s:%d\n",
+ inet_ntoa(bp_server_addr), ntohs(bp_server_port)));
+
+ /* We have just done a portmap call, so cache the portnum. */
+ rpc_pmap_putcache(bp_server_addr,
+ BOOTPARAM_PROG,
+ BOOTPARAM_VERS,
+ (int)ntohs(bp_server_port));
+
+ /*
+ * Parse the encapsulated results from bootparam/whoami
+ */
+ x = ntohl(repl->encap_len);
+ if (len < x) {
+ printf("bp_whoami: short reply, %d < %d\n", len, x);
+ return (-1);
+ }
+ recv_head = (char*) repl->capsule;
+
+ /* client name */
+ hostnamelen = MAXHOSTNAMELEN-1;
+ if (xdr_string_decode(&recv_head, hostname, &hostnamelen)) {
+ RPC_PRINTF(("bp_whoami: bad hostname\n"));
+ return (-1);
+ }
+
+ /* domain name */
+ domainnamelen = MAXHOSTNAMELEN-1;
+ if (xdr_string_decode(&recv_head, domainname, &domainnamelen)) {
+ RPC_PRINTF(("bp_whoami: bad domainname\n"));
+ return (-1);
+ }
+
+ /* gateway address */
+ if (xdr_inaddr_decode(&recv_head, &gateip)) {
+ RPC_PRINTF(("bp_whoami: bad gateway\n"));
+ return (-1);
+ }
+
+ /* success */
+ return(0);
+}
+
+
+/*
+ * RPC: bootparam/getfile
+ * Given client name and file "key", get:
+ * server name
+ * server IP address
+ * server pathname
+ */
+int
+bp_getfile(sockfd, key, serv_addr, pathname)
+ int sockfd;
+ char *key;
+ char *pathname;
+ struct in_addr *serv_addr;
+{
+ struct {
+ n_long h[RPC_HEADER_WORDS];
+ n_long d[64];
+ } sdata;
+ struct {
+ n_long h[RPC_HEADER_WORDS];
+ n_long d[128];
+ } rdata;
+ char serv_name[FNAME_SIZE];
+ char *send_tail, *recv_head;
+ /* misc... */
+ struct iodesc *d;
+ int sn_len, path_len, rlen;
+
+ if (!(d = socktodesc(sockfd))) {
+ RPC_PRINTF(("bp_getfile: bad socket. %d\n", sockfd));
+ return (-1);
+ }
+
+ send_tail = (char*) sdata.d;
+ recv_head = (char*) rdata.d;
+
+ /*
+ * Build request message.
+ */
+
+ /* client name (hostname) */
+ if (xdr_string_encode(&send_tail, hostname, hostnamelen)) {
+ RPC_PRINTF(("bp_getfile: bad client\n"));
+ return (-1);
+ }
+
+ /* key name (root or swap) */
+ if (xdr_string_encode(&send_tail, key, strlen(key))) {
+ RPC_PRINTF(("bp_getfile: bad key\n"));
+ return (-1);
+ }
+
+ /* RPC: bootparam/getfile */
+ d->myport = htons(--rpc_port);
+ d->destip = bp_server_addr;
+ /* rpc_call will set d->destport */
+
+ rlen = rpc_call(d,
+ BOOTPARAM_PROG, BOOTPARAM_VERS, BOOTPARAM_GETFILE,
+ sdata.d, send_tail - (char*)sdata.d,
+ rdata.d, sizeof(rdata.d));
+ if (rlen < 4) {
+ RPC_PRINTF(("bp_getfile: short reply\n"));
+ errno = EBADRPC;
+ return (-1);
+ }
+ recv_head = (char*) rdata.d;
+
+ /*
+ * Parse result message.
+ */
+
+ /* server name */
+ sn_len = FNAME_SIZE-1;
+ if (xdr_string_decode(&recv_head, serv_name, &sn_len)) {
+ RPC_PRINTF(("bp_getfile: bad server name\n"));
+ return (-1);
+ }
+
+ /* server IP address (mountd/NFS) */
+ if (xdr_inaddr_decode(&recv_head, serv_addr)) {
+ RPC_PRINTF(("bp_getfile: bad server addr\n"));
+ return (-1);
+ }
+
+ /* server pathname */
+ path_len = MAXPATHLEN-1;
+ if (xdr_string_decode(&recv_head, pathname, &path_len)) {
+ RPC_PRINTF(("bp_getfile: bad server path\n"));
+ return (-1);
+ }
+
+ /* success */
+ return(0);
+}
+
+
+/*
+ * eXternal Data Representation routines.
+ * (but with non-standard args...)
+ */
+
+
+int
+xdr_string_encode(pkt, str, len)
+ char **pkt;
+ char *str;
+ int len;
+{
+ u_int32_t *lenp;
+ char *datap;
+ int padlen = (len + 3) & ~3; /* padded length */
+
+ /* The data will be int aligned. */
+ lenp = (u_int32_t*) *pkt;
+ *pkt += sizeof(*lenp);
+ *lenp = htonl(len);
+
+ datap = *pkt;
+ *pkt += padlen;
+ bcopy(str, datap, len);
+
+ return (0);
+}
+
+int
+xdr_string_decode(pkt, str, len_p)
+ char **pkt;
+ char *str;
+ int *len_p; /* bufsize - 1 */
+{
+ u_int32_t *lenp;
+ char *datap;
+ int slen; /* string length */
+ int plen; /* padded length */
+
+ /* The data will be int aligned. */
+ lenp = (u_int32_t*) *pkt;
+ *pkt += sizeof(*lenp);
+ slen = ntohl(*lenp);
+ plen = (slen + 3) & ~3;
+
+ if (slen > *len_p)
+ slen = *len_p;
+ datap = *pkt;
+ *pkt += plen;
+ bcopy(datap, str, slen);
+
+ str[slen] = '\0';
+ *len_p = slen;
+
+ return (0);
+}
+
+
+int
+xdr_inaddr_encode(pkt, ia)
+ char **pkt;
+ struct in_addr ia; /* network order */
+{
+ struct xdr_inaddr *xi;
+ u_char *cp;
+ int32_t *ip;
+ union {
+ n_long l; /* network order */
+ u_char c[4];
+ } uia;
+
+ /* The data will be int aligned. */
+ xi = (struct xdr_inaddr *) *pkt;
+ *pkt += sizeof(*xi);
+ xi->atype = htonl(1);
+ uia.l = ia.s_addr;
+ cp = uia.c;
+ ip = xi->addr;
+ /*
+ * Note: the htonl() calls below DO NOT
+ * imply that uia.l is in host order.
+ * In fact this needs it in net order.
+ */
+ *ip++ = htonl((unsigned int)*cp++);
+ *ip++ = htonl((unsigned int)*cp++);
+ *ip++ = htonl((unsigned int)*cp++);
+ *ip++ = htonl((unsigned int)*cp++);
+
+ return (0);
+}
+
+int
+xdr_inaddr_decode(pkt, ia)
+ char **pkt;
+ struct in_addr *ia; /* network order */
+{
+ struct xdr_inaddr *xi;
+ u_char *cp;
+ int32_t *ip;
+ union {
+ n_long l; /* network order */
+ u_char c[4];
+ } uia;
+
+ /* The data will be int aligned. */
+ xi = (struct xdr_inaddr *) *pkt;
+ *pkt += sizeof(*xi);
+ if (xi->atype != htonl(1)) {
+ RPC_PRINTF(("xdr_inaddr_decode: bad addrtype=%d\n",
+ ntohl(xi->atype)));
+ return(-1);
+ }
+
+ cp = uia.c;
+ ip = xi->addr;
+ /*
+ * Note: the ntohl() calls below DO NOT
+ * imply that uia.l is in host order.
+ * In fact this needs it in net order.
+ */
+ *cp++ = ntohl(*ip++);
+ *cp++ = ntohl(*ip++);
+ *cp++ = ntohl(*ip++);
+ *cp++ = ntohl(*ip++);
+ ia->s_addr = uia.l;
+
+ return (0);
+}
diff --git a/lib/libstand/bootparam.h b/lib/libstand/bootparam.h
new file mode 100644
index 0000000..6f0c773
--- /dev/null
+++ b/lib/libstand/bootparam.h
@@ -0,0 +1,5 @@
+/* $NetBSD: bootparam.h,v 1.3 1998/01/05 19:19:41 perry Exp $ */
+
+int bp_whoami(int sock);
+int bp_getfile(int sock, char *key, struct in_addr *addrp, char *path);
+
diff --git a/lib/libstand/bswap.c b/lib/libstand/bswap.c
new file mode 100644
index 0000000..a9bd323
--- /dev/null
+++ b/lib/libstand/bswap.c
@@ -0,0 +1,40 @@
+/*
+ * Written by Manuel Bouyer <bouyer@netbsd.org>.
+ * Public domain.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *rcsid = "$NetBSD: bswap32.c,v 1.1 1997/10/09 15:42:33 bouyer Exp $";
+static char *rcsid = "$NetBSD: bswap64.c,v 1.1 1997/10/09 15:42:33 bouyer Exp $";
+#endif
+
+#include <sys/types.h>
+
+#undef bswap32
+#undef bswap64
+
+u_int32_t
+bswap32(x)
+ u_int32_t x;
+{
+ return ((x << 24) & 0xff000000 ) |
+ ((x << 8) & 0x00ff0000 ) |
+ ((x >> 8) & 0x0000ff00 ) |
+ ((x >> 24) & 0x000000ff );
+}
+
+u_int64_t
+bswap64(x)
+ u_int64_t x;
+{
+ u_int32_t *p = (u_int32_t*)&x;
+ u_int32_t t;
+ t = bswap32(p[0]);
+ p[0] = bswap32(p[1]);
+ p[1] = t;
+ return x;
+}
+
diff --git a/lib/libstand/bzipfs.c b/lib/libstand/bzipfs.c
new file mode 100644
index 0000000..d4d3adf
--- /dev/null
+++ b/lib/libstand/bzipfs.c
@@ -0,0 +1,303 @@
+/*
+ * Copyright (c) 1998 Michael Smith.
+ * Copyright (c) 2000 Maxim Sobolev
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "stand.h"
+
+#include <sys/stat.h>
+#include <string.h>
+#include <bzlib.h>
+
+#define BZ_BUFSIZE 2048 /* XXX larger? */
+
+struct bz_file
+{
+ int bzf_rawfd;
+ bz_stream bzf_bzstream;
+ char bzf_buf[BZ_BUFSIZE];
+};
+
+static int bzf_fill(struct bz_file *z);
+static int bzf_open(const char *path, struct open_file *f);
+static int bzf_close(struct open_file *f);
+static int bzf_read(struct open_file *f, void *buf, size_t size, size_t *resid);
+static off_t bzf_seek(struct open_file *f, off_t offset, int where);
+static int bzf_stat(struct open_file *f, struct stat *sb);
+
+struct fs_ops bzipfs_fsops = {
+ "bzip",
+ bzf_open,
+ bzf_close,
+ bzf_read,
+ null_write,
+ bzf_seek,
+ bzf_stat,
+ null_readdir
+};
+
+#if 0
+void *
+calloc(int items, size_t size)
+{
+ return(malloc(items * size));
+}
+#endif
+
+static int
+bzf_fill(struct bz_file *bzf)
+{
+ int result;
+ int req;
+
+ req = BZ_BUFSIZE - bzf->bzf_bzstream.avail_in;
+ result = 0;
+
+ /* If we need more */
+ if (req > 0) {
+ /* move old data to bottom of buffer */
+ if (req < BZ_BUFSIZE)
+ bcopy(bzf->bzf_buf + req, bzf->bzf_buf, BZ_BUFSIZE - req);
+
+ /* read to fill buffer and update availibility data */
+ result = read(bzf->bzf_rawfd, bzf->bzf_buf + bzf->bzf_bzstream.avail_in, req);
+ bzf->bzf_bzstream.next_in = bzf->bzf_buf;
+ if (result >= 0)
+ bzf->bzf_bzstream.avail_in += result;
+ }
+ return(result);
+}
+
+/*
+ * Adapted from get_byte/check_header in libz
+ *
+ * Returns 0 if the header is OK, nonzero if not.
+ */
+static int
+get_byte(struct bz_file *bzf)
+{
+ if ((bzf->bzf_bzstream.avail_in == 0) && (bzf_fill(bzf) == -1))
+ return(-1);
+ bzf->bzf_bzstream.avail_in--;
+ return(*(bzf->bzf_bzstream.next_in)++);
+}
+
+static int bz_magic[3] = {'B', 'Z', 'h'}; /* bzip2 magic header */
+
+static int
+check_header(struct bz_file *bzf)
+{
+ unsigned int len;
+ int c;
+
+ /* Check the bzip2 magic header */
+ for (len = 0; len < 3; len++) {
+ c = get_byte(bzf);
+ if (c != bz_magic[len]) {
+ return(1);
+ }
+ }
+ /* Check that the block size is valid */
+ c = get_byte(bzf);
+ if (c < '1' || c > '9')
+ return(1);
+
+ /* Put back bytes that we've took from the input stream */
+ bzf->bzf_bzstream.next_in -= 4;
+ bzf->bzf_bzstream.avail_in += 4;
+
+ return(0);
+}
+
+static int
+bzf_open(const char *fname, struct open_file *f)
+{
+ static char *bzfname;
+ int rawfd;
+ struct bz_file *bzf;
+ char *cp;
+ int error;
+ struct stat sb;
+
+ /* Have to be in "just read it" mode */
+ if (f->f_flags != F_READ)
+ return(EPERM);
+
+ /* If the name already ends in .gz or .bz2, ignore it */
+ if ((cp = strrchr(fname, '.')) && (!strcmp(cp, ".gz")
+ || !strcmp(cp, ".bz2") || !strcmp(cp, ".split")))
+ return(ENOENT);
+
+ /* Construct new name */
+ bzfname = malloc(strlen(fname) + 5);
+ sprintf(bzfname, "%s.bz2", fname);
+
+ /* Try to open the compressed datafile */
+ rawfd = open(bzfname, O_RDONLY);
+ free(bzfname);
+ if (rawfd == -1)
+ return(ENOENT);
+
+ if (fstat(rawfd, &sb) < 0) {
+ printf("bzf_open: stat failed\n");
+ close(rawfd);
+ return(ENOENT);
+ }
+ if (!S_ISREG(sb.st_mode)) {
+ printf("bzf_open: not a file\n");
+ close(rawfd);
+ return(EISDIR); /* best guess */
+ }
+
+ /* Allocate a bz_file structure, populate it */
+ bzf = malloc(sizeof(struct bz_file));
+ bzero(bzf, sizeof(struct bz_file));
+ bzf->bzf_rawfd = rawfd;
+
+ /* Verify that the file is bzipped (XXX why do this afterwards?) */
+ if (check_header(bzf)) {
+ close(bzf->bzf_rawfd);
+ BZ2_bzDecompressEnd(&(bzf->bzf_bzstream));
+ free(bzf);
+ return(EFTYPE);
+ }
+
+ /* Initialise the inflation engine */
+ if ((error = BZ2_bzDecompressInit(&(bzf->bzf_bzstream), 0, 1)) != BZ_OK) {
+ printf("bzf_open: BZ2_bzDecompressInit returned %d\n", error);
+ close(bzf->bzf_rawfd);
+ free(bzf);
+ return(EIO);
+ }
+
+ /* Looks OK, we'll take it */
+ f->f_fsdata = bzf;
+ return(0);
+}
+
+static int
+bzf_close(struct open_file *f)
+{
+ struct bz_file *bzf = (struct bz_file *)f->f_fsdata;
+
+ BZ2_bzDecompressEnd(&(bzf->bzf_bzstream));
+ close(bzf->bzf_rawfd);
+ free(bzf);
+ return(0);
+}
+
+static int
+bzf_read(struct open_file *f, void *buf, size_t size, size_t *resid)
+{
+ struct bz_file *bzf = (struct bz_file *)f->f_fsdata;
+ int error;
+
+ bzf->bzf_bzstream.next_out = buf; /* where and how much */
+ bzf->bzf_bzstream.avail_out = size;
+
+ while (bzf->bzf_bzstream.avail_out) {
+ if ((bzf->bzf_bzstream.avail_in == 0) && (bzf_fill(bzf) == -1)) {
+ printf("bzf_read: fill error\n");
+ return(EIO);
+ }
+ if (bzf->bzf_bzstream.avail_in == 0) { /* oops, unexpected EOF */
+ printf("bzf_read: unexpected EOF\n");
+ if (bzf->bzf_bzstream.avail_out == size)
+ return (EIO);
+ break;
+ }
+
+ error = BZ2_bzDecompress(&bzf->bzf_bzstream); /* decompression pass */
+ if (error == BZ_STREAM_END) { /* EOF, all done */
+ break;
+ }
+ if (error != BZ_OK) { /* argh, decompression error */
+ printf("bzf_read: BZ2_bzDecompress returned %d\n", error);
+ return(EIO);
+ }
+ }
+ if (resid != NULL)
+ *resid = bzf->bzf_bzstream.avail_out;
+ return(0);
+}
+
+static off_t
+bzf_seek(struct open_file *f, off_t offset, int where)
+{
+ struct bz_file *bzf = (struct bz_file *)f->f_fsdata;
+ off_t target;
+ char discard[16];
+
+ switch (where) {
+ case SEEK_SET:
+ target = offset;
+ break;
+ case SEEK_CUR:
+ target = offset + bzf->bzf_bzstream.total_out_lo32;
+ break;
+ case SEEK_END:
+ target = -1;
+ default:
+ errno = EINVAL;
+ return (-1);
+ }
+
+ /* Can we get there from here? */
+ if (target < bzf->bzf_bzstream.total_out_lo32) {
+ errno = EOFFSET;
+ return -1;
+ }
+
+ /* skip forwards if required */
+ while (target > bzf->bzf_bzstream.total_out_lo32) {
+ errno = bzf_read(f, discard, min(sizeof(discard),
+ target - bzf->bzf_bzstream.total_out_lo32), NULL);
+ if (errno)
+ return(-1);
+ }
+ /* This is where we are (be honest if we overshot) */
+ return (bzf->bzf_bzstream.total_out_lo32);
+}
+
+static int
+bzf_stat(struct open_file *f, struct stat *sb)
+{
+ struct bz_file *bzf = (struct bz_file *)f->f_fsdata;
+ int result;
+
+ /* stat as normal, but indicate that size is unknown */
+ if ((result = fstat(bzf->bzf_rawfd, sb)) == 0)
+ sb->st_size = -1;
+ return(result);
+}
+
+void
+bz_internal_error(int errorcode)
+{
+ panic("bzipfs: critical error %d in bzip2 library occured\n", errorcode);
+}
diff --git a/lib/libstand/cd9660.c b/lib/libstand/cd9660.c
new file mode 100644
index 0000000..449480b
--- /dev/null
+++ b/lib/libstand/cd9660.c
@@ -0,0 +1,588 @@
+/* $NetBSD: cd9660.c,v 1.5 1997/06/26 19:11:33 drochner Exp $ */
+
+/*
+ * Copyright (C) 1996 Wolfgang Solfrank.
+ * Copyright (C) 1996 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Stand-alone ISO9660 file reading package.
+ *
+ * Note: This doesn't support Rock Ridge extensions, extended attributes,
+ * blocksizes other than 2048 bytes, multi-extent files, etc.
+ */
+#include <sys/param.h>
+#include <string.h>
+#include <sys/dirent.h>
+#include <isofs/cd9660/iso.h>
+#include <isofs/cd9660/cd9660_rrip.h>
+
+#include "stand.h"
+
+#define SUSP_CONTINUATION "CE"
+#define SUSP_PRESENT "SP"
+#define SUSP_STOP "ST"
+#define SUSP_EXTREF "ER"
+#define RRIP_NAME "NM"
+
+typedef struct {
+ ISO_SUSP_HEADER h;
+ u_char signature [ISODCL ( 5, 6)];
+ u_char len_skp [ISODCL ( 7, 7)]; /* 711 */
+} ISO_SUSP_PRESENT;
+
+static int buf_read_file(struct open_file *f, char **buf_p,
+ size_t *size_p);
+static int cd9660_open(const char *path, struct open_file *f);
+static int cd9660_close(struct open_file *f);
+static int cd9660_read(struct open_file *f, void *buf, size_t size,
+ size_t *resid);
+static int cd9660_write(struct open_file *f, void *buf, size_t size,
+ size_t *resid);
+static off_t cd9660_seek(struct open_file *f, off_t offset, int where);
+static int cd9660_stat(struct open_file *f, struct stat *sb);
+static int cd9660_readdir(struct open_file *f, struct dirent *d);
+static int dirmatch(struct open_file *f, const char *path,
+ struct iso_directory_record *dp, int use_rrip, int lenskip);
+static int rrip_check(struct open_file *f, struct iso_directory_record *dp,
+ int *lenskip);
+static char *rrip_lookup_name(struct open_file *f,
+ struct iso_directory_record *dp, int lenskip, size_t *len);
+static ISO_SUSP_HEADER *susp_lookup_record(struct open_file *f,
+ const char *identifier, struct iso_directory_record *dp,
+ int lenskip);
+
+struct fs_ops cd9660_fsops = {
+ "cd9660",
+ cd9660_open,
+ cd9660_close,
+ cd9660_read,
+ cd9660_write,
+ cd9660_seek,
+ cd9660_stat,
+ cd9660_readdir
+};
+
+#define F_ISDIR 0x0001 /* Directory */
+#define F_ROOTDIR 0x0002 /* Root directory */
+#define F_RR 0x0004 /* Rock Ridge on this volume */
+
+struct file {
+ int f_flags; /* file flags */
+ off_t f_off; /* Current offset within file */
+ daddr_t f_bno; /* Starting block number */
+ off_t f_size; /* Size of file */
+ daddr_t f_buf_blkno; /* block number of data block */
+ char *f_buf; /* buffer for data block */
+ int f_susp_skip; /* len_skip for SUSP records */
+};
+
+struct ptable_ent {
+ char namlen [ISODCL( 1, 1)]; /* 711 */
+ char extlen [ISODCL( 2, 2)]; /* 711 */
+ char block [ISODCL( 3, 6)]; /* 732 */
+ char parent [ISODCL( 7, 8)]; /* 722 */
+ char name [1];
+};
+#define PTFIXSZ 8
+#define PTSIZE(pp) roundup(PTFIXSZ + isonum_711((pp)->namlen), 2)
+
+#define cdb2devb(bno) ((bno) * ISO_DEFAULT_BLOCK_SIZE / DEV_BSIZE)
+
+static ISO_SUSP_HEADER *
+susp_lookup_record(struct open_file *f, const char *identifier,
+ struct iso_directory_record *dp, int lenskip)
+{
+ static char susp_buffer[ISO_DEFAULT_BLOCK_SIZE];
+ ISO_SUSP_HEADER *sh;
+ ISO_RRIP_CONT *shc;
+ char *p, *end;
+ int error;
+ size_t read;
+
+ p = dp->name + isonum_711(dp->name_len) + lenskip;
+ /* Names of even length have a padding byte after the name. */
+ if ((isonum_711(dp->name_len) & 1) == 0)
+ p++;
+ end = (char *)dp + isonum_711(dp->length);
+ while (p + 3 < end) {
+ sh = (ISO_SUSP_HEADER *)p;
+ if (bcmp(sh->type, identifier, 2) == 0)
+ return (sh);
+ if (bcmp(sh->type, SUSP_STOP, 2) == 0)
+ return (NULL);
+ if (bcmp(sh->type, SUSP_CONTINUATION, 2) == 0) {
+ shc = (ISO_RRIP_CONT *)sh;
+ error = f->f_dev->dv_strategy(f->f_devdata, F_READ,
+ cdb2devb(isonum_733(shc->location)),
+ ISO_DEFAULT_BLOCK_SIZE, susp_buffer, &read);
+
+ /* Bail if it fails. */
+ if (error != 0 || read != ISO_DEFAULT_BLOCK_SIZE)
+ return (NULL);
+ p = susp_buffer + isonum_733(shc->offset);
+ end = p + isonum_733(shc->length);
+ } else
+ /* Ignore this record and skip to the next. */
+ p += isonum_711(sh->length);
+ }
+ return (NULL);
+}
+
+static char *
+rrip_lookup_name(struct open_file *f, struct iso_directory_record *dp,
+ int lenskip, size_t *len)
+{
+ ISO_RRIP_ALTNAME *p;
+
+ if (len == NULL)
+ return (NULL);
+
+ p = (ISO_RRIP_ALTNAME *)susp_lookup_record(f, RRIP_NAME, dp, lenskip);
+ if (p == NULL)
+ return (NULL);
+ switch (*p->flags) {
+ case ISO_SUSP_CFLAG_CURRENT:
+ *len = 1;
+ return (".");
+ case ISO_SUSP_CFLAG_PARENT:
+ *len = 2;
+ return ("..");
+ case 0:
+ *len = isonum_711(p->h.length) - 5;
+ return ((char *)p + 5);
+ default:
+ /*
+ * We don't handle hostnames or continued names as they are
+ * too hard, so just bail and use the default name.
+ */
+ return (NULL);
+ }
+}
+
+static int
+rrip_check(struct open_file *f, struct iso_directory_record *dp, int *lenskip)
+{
+ ISO_SUSP_PRESENT *sp;
+ ISO_RRIP_EXTREF *er;
+ char *p;
+
+ /* First, see if we can find a SP field. */
+ p = dp->name + isonum_711(dp->name_len);
+ if (p > (char *)dp + isonum_711(dp->length))
+ return (0);
+ sp = (ISO_SUSP_PRESENT *)p;
+ if (bcmp(sp->h.type, SUSP_PRESENT, 2) != 0)
+ return (0);
+ if (isonum_711(sp->h.length) != sizeof(ISO_SUSP_PRESENT))
+ return (0);
+ if (sp->signature[0] != 0xbe || sp->signature[1] != 0xef)
+ return (0);
+ *lenskip = isonum_711(sp->len_skp);
+
+ /*
+ * Now look for an ER field. If RRIP is present, then there must
+ * be at least one of these. It would be more pedantic to walk
+ * through the list of fields looking for a Rock Ridge ER field.
+ */
+ er = (ISO_RRIP_EXTREF *)susp_lookup_record(f, SUSP_EXTREF, dp, 0);
+ if (er == NULL)
+ return (0);
+ return (1);
+}
+
+static int
+dirmatch(struct open_file *f, const char *path, struct iso_directory_record *dp,
+ int use_rrip, int lenskip)
+{
+ size_t len;
+ char *cp;
+ int i, icase;
+
+ if (use_rrip)
+ cp = rrip_lookup_name(f, dp, lenskip, &len);
+ else
+ cp = NULL;
+ if (cp == NULL) {
+ len = isonum_711(dp->name_len);
+ cp = dp->name;
+ icase = 1;
+ } else
+ icase = 0;
+ for (i = len; --i >= 0; path++, cp++) {
+ if (!*path || *path == '/')
+ break;
+ if (*path == *cp)
+ continue;
+ if (!icase && toupper(*path) == *cp)
+ continue;
+ return 0;
+ }
+ if (*path && *path != '/')
+ return 0;
+ /*
+ * Allow stripping of trailing dots and the version number.
+ * Note that this will find the first instead of the last version
+ * of a file.
+ */
+ if (i >= 0 && (*cp == ';' || *cp == '.')) {
+ /* This is to prevent matching of numeric extensions */
+ if (*cp == '.' && cp[1] != ';')
+ return 0;
+ while (--i >= 0)
+ if (*++cp != ';' && (*cp < '0' || *cp > '9'))
+ return 0;
+ }
+ return 1;
+}
+
+static int
+cd9660_open(const char *path, struct open_file *f)
+{
+ struct file *fp = 0;
+ void *buf;
+ struct iso_primary_descriptor *vd;
+ size_t buf_size, read, dsize, off;
+ daddr_t bno, boff;
+ struct iso_directory_record rec;
+ struct iso_directory_record *dp = 0;
+ int rc, first, use_rrip, lenskip;
+
+ /* First find the volume descriptor */
+ buf = malloc(buf_size = ISO_DEFAULT_BLOCK_SIZE);
+ vd = buf;
+ for (bno = 16;; bno++) {
+ twiddle();
+ rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, cdb2devb(bno),
+ ISO_DEFAULT_BLOCK_SIZE, buf, &read);
+ if (rc)
+ goto out;
+ if (read != ISO_DEFAULT_BLOCK_SIZE) {
+ rc = EIO;
+ goto out;
+ }
+ rc = EINVAL;
+ if (bcmp(vd->id, ISO_STANDARD_ID, sizeof vd->id) != 0)
+ goto out;
+ if (isonum_711(vd->type) == ISO_VD_END)
+ goto out;
+ if (isonum_711(vd->type) == ISO_VD_PRIMARY)
+ break;
+ }
+ if (isonum_723(vd->logical_block_size) != ISO_DEFAULT_BLOCK_SIZE)
+ goto out;
+
+ rec = *(struct iso_directory_record *) vd->root_directory_record;
+ if (*path == '/') path++; /* eat leading '/' */
+
+ first = 1;
+ use_rrip = 0;
+ while (*path) {
+ bno = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length);
+ dsize = isonum_733(rec.size);
+ off = 0;
+ boff = 0;
+
+ while (off < dsize) {
+ if ((off % ISO_DEFAULT_BLOCK_SIZE) == 0) {
+ twiddle();
+ rc = f->f_dev->dv_strategy
+ (f->f_devdata, F_READ,
+ cdb2devb(bno + boff),
+ ISO_DEFAULT_BLOCK_SIZE,
+ buf, &read);
+ if (rc)
+ goto out;
+ if (read != ISO_DEFAULT_BLOCK_SIZE) {
+ rc = EIO;
+ goto out;
+ }
+ boff++;
+ dp = (struct iso_directory_record *) buf;
+ }
+ if (isonum_711(dp->length) == 0) {
+ /* skip to next block, if any */
+ off = boff * ISO_DEFAULT_BLOCK_SIZE;
+ continue;
+ }
+
+ /* See if RRIP is in use. */
+ if (first)
+ use_rrip = rrip_check(f, dp, &lenskip);
+
+ if (dirmatch(f, path, dp, use_rrip,
+ first ? 0 : lenskip)) {
+ first = 0;
+ break;
+ } else
+ first = 0;
+
+ dp = (struct iso_directory_record *)
+ ((char *) dp + isonum_711(dp->length));
+ off += isonum_711(dp->length);
+ }
+ if (off >= dsize) {
+ rc = ENOENT;
+ goto out;
+ }
+
+ rec = *dp;
+ while (*path && *path != '/') /* look for next component */
+ path++;
+ if (*path) path++; /* skip '/' */
+ }
+
+ /* allocate file system specific data structure */
+ fp = malloc(sizeof(struct file));
+ bzero(fp, sizeof(struct file));
+ f->f_fsdata = (void *)fp;
+
+ if ((isonum_711(rec.flags) & 2) != 0) {
+ fp->f_flags = F_ISDIR;
+ }
+ if (first) {
+ fp->f_flags |= F_ROOTDIR;
+
+ /* Check for Rock Ridge since we didn't in the loop above. */
+ bno = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length);
+ twiddle();
+ rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, cdb2devb(bno),
+ ISO_DEFAULT_BLOCK_SIZE, buf, &read);
+ if (rc)
+ goto out;
+ if (read != ISO_DEFAULT_BLOCK_SIZE) {
+ rc = EIO;
+ goto out;
+ }
+ dp = (struct iso_directory_record *)buf;
+ use_rrip = rrip_check(f, dp, &lenskip);
+ }
+ if (use_rrip) {
+ fp->f_flags |= F_RR;
+ fp->f_susp_skip = lenskip;
+ }
+ fp->f_off = 0;
+ fp->f_bno = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length);
+ fp->f_size = isonum_733(rec.size);
+ free(buf);
+
+ return 0;
+
+out:
+ if (fp)
+ free(fp);
+ free(buf);
+
+ return rc;
+}
+
+static int
+cd9660_close(struct open_file *f)
+{
+ struct file *fp = (struct file *)f->f_fsdata;
+
+ f->f_fsdata = 0;
+ free(fp);
+
+ return 0;
+}
+
+static int
+buf_read_file(struct open_file *f, char **buf_p, size_t *size_p)
+{
+ struct file *fp = (struct file *)f->f_fsdata;
+ daddr_t blkno, blkoff;
+ int rc = 0;
+ size_t read;
+
+ blkno = fp->f_off / ISO_DEFAULT_BLOCK_SIZE + fp->f_bno;
+ blkoff = fp->f_off % ISO_DEFAULT_BLOCK_SIZE;
+
+ if (blkno != fp->f_buf_blkno) {
+ if (fp->f_buf == (char *)0)
+ fp->f_buf = malloc(ISO_DEFAULT_BLOCK_SIZE);
+
+ twiddle();
+ rc = f->f_dev->dv_strategy(f->f_devdata, F_READ,
+ cdb2devb(blkno), ISO_DEFAULT_BLOCK_SIZE, fp->f_buf, &read);
+ if (rc)
+ return (rc);
+ if (read != ISO_DEFAULT_BLOCK_SIZE)
+ return (EIO);
+
+ fp->f_buf_blkno = blkno;
+ }
+
+ *buf_p = fp->f_buf + blkoff;
+ *size_p = ISO_DEFAULT_BLOCK_SIZE - blkoff;
+
+ if (*size_p > fp->f_size - fp->f_off)
+ *size_p = fp->f_size - fp->f_off;
+ return (rc);
+}
+
+static int
+cd9660_read(struct open_file *f, void *start, size_t size, size_t *resid)
+{
+ struct file *fp = (struct file *)f->f_fsdata;
+ char *buf, *addr;
+ size_t buf_size, csize;
+ int rc = 0;
+
+ addr = start;
+ while (size) {
+ if (fp->f_off < 0 || fp->f_off >= fp->f_size)
+ break;
+
+ rc = buf_read_file(f, &buf, &buf_size);
+ if (rc)
+ break;
+
+ csize = size > buf_size ? buf_size : size;
+ bcopy(buf, addr, csize);
+
+ fp->f_off += csize;
+ addr += csize;
+ size -= csize;
+ }
+ if (resid)
+ *resid = size;
+ return (rc);
+}
+
+static int
+cd9660_readdir(struct open_file *f, struct dirent *d)
+{
+ struct file *fp = (struct file *)f->f_fsdata;
+ struct iso_directory_record *ep;
+ size_t buf_size, reclen, namelen;
+ int error = 0;
+ int lenskip;
+ char *buf, *name;
+
+again:
+ if (fp->f_off >= fp->f_size)
+ return (ENOENT);
+ error = buf_read_file(f, &buf, &buf_size);
+ if (error)
+ return (error);
+ ep = (struct iso_directory_record *)buf;
+
+ if (isonum_711(ep->length) == 0) {
+ daddr_t blkno;
+
+ /* skip to next block, if any */
+ blkno = fp->f_off / ISO_DEFAULT_BLOCK_SIZE;
+ fp->f_off = (blkno + 1) * ISO_DEFAULT_BLOCK_SIZE;
+ goto again;
+ }
+
+ if (fp->f_flags & F_RR) {
+ if (fp->f_flags & F_ROOTDIR && fp->f_off == 0)
+ lenskip = 0;
+ else
+ lenskip = fp->f_susp_skip;
+ name = rrip_lookup_name(f, ep, lenskip, &namelen);
+ } else
+ name = NULL;
+ if (name == NULL) {
+ namelen = isonum_711(ep->name_len);
+ name = ep->name;
+ if (namelen == 1) {
+ if (ep->name[0] == 0)
+ name = ".";
+ else if (ep->name[0] == 1) {
+ namelen = 2;
+ name = "..";
+ }
+ }
+ }
+ reclen = sizeof(struct dirent) - (MAXNAMLEN+1) + namelen + 1;
+ reclen = (reclen + 3) & ~3;
+
+ d->d_fileno = isonum_733(ep->extent);
+ d->d_reclen = reclen;
+ if (isonum_711(ep->flags) & 2)
+ d->d_type = DT_DIR;
+ else
+ d->d_type = DT_REG;
+ d->d_namlen = namelen;
+
+ bcopy(name, d->d_name, d->d_namlen);
+ d->d_name[d->d_namlen] = 0;
+
+ fp->f_off += isonum_711(ep->length);
+ return (0);
+}
+
+static int
+cd9660_write(struct open_file *f, void *start, size_t size, size_t *resid)
+{
+ return EROFS;
+}
+
+static off_t
+cd9660_seek(struct open_file *f, off_t offset, int where)
+{
+ struct file *fp = (struct file *)f->f_fsdata;
+
+ switch (where) {
+ case SEEK_SET:
+ fp->f_off = offset;
+ break;
+ case SEEK_CUR:
+ fp->f_off += offset;
+ break;
+ case SEEK_END:
+ fp->f_off = fp->f_size - offset;
+ break;
+ default:
+ return -1;
+ }
+ return fp->f_off;
+}
+
+static int
+cd9660_stat(struct open_file *f, struct stat *sb)
+{
+ struct file *fp = (struct file *)f->f_fsdata;
+
+ /* only important stuff */
+ sb->st_mode = S_IRUSR | S_IRGRP | S_IROTH;
+ if (fp->f_flags & F_ISDIR)
+ sb->st_mode |= S_IFDIR;
+ else
+ sb->st_mode |= S_IFREG;
+ sb->st_uid = sb->st_gid = 0;
+ sb->st_size = fp->f_size;
+ return 0;
+}
diff --git a/lib/libstand/close.c b/lib/libstand/close.c
new file mode 100644
index 0000000..8ad628b
--- /dev/null
+++ b/lib/libstand/close.c
@@ -0,0 +1,100 @@
+/* $NetBSD: close.c,v 1.7 1997/01/22 00:38:09 cgd Exp $ */
+
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * The Mach Operating System project at Carnegie-Mellon 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. 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.
+ *
+ * @(#)close.c 8.1 (Berkeley) 6/11/93
+ *
+ *
+ * Copyright (c) 1989, 1990, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Author: Alessandro Forin
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "stand.h"
+
+int
+close(int fd)
+{
+ struct open_file *f = &files[fd];
+ int err1 = 0, err2 = 0;
+
+ if ((unsigned)fd >= SOPEN_MAX || f->f_flags == 0) {
+ errno = EBADF;
+ return (-1);
+ }
+ if (f->f_rabuf != NULL)
+ free(f->f_rabuf);
+ if (!(f->f_flags & F_RAW) && f->f_ops)
+ err1 = (f->f_ops->fo_close)(f);
+ if (!(f->f_flags & F_NODEV) && f->f_dev)
+ err2 = (f->f_dev->dv_close)(f);
+ if (f->f_devdata != NULL)
+ devclose(f);
+ f->f_flags = 0;
+ if (err1) {
+ errno = err1;
+ return (-1);
+ }
+ if (err2) {
+ errno = err2;
+ return (-1);
+ }
+ return (0);
+}
diff --git a/lib/libstand/closeall.c b/lib/libstand/closeall.c
new file mode 100644
index 0000000..2f7be72
--- /dev/null
+++ b/lib/libstand/closeall.c
@@ -0,0 +1,80 @@
+/* $NetBSD: closeall.c,v 1.1 1996/01/13 22:25:36 leo Exp $ */
+
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * The Mach Operating System project at Carnegie-Mellon 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. 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.
+ *
+ * @(#)close.c 8.1 (Berkeley) 6/11/93
+ *
+ *
+ * Copyright (c) 1989, 1990, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Author: Alessandro Forin
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "stand.h"
+
+void
+closeall()
+{
+ int i;
+
+ for (i = 0; i < SOPEN_MAX; i++)
+ if (files[i].f_flags != 0)
+ (void)close(i);
+}
diff --git a/lib/libstand/dev.c b/lib/libstand/dev.c
new file mode 100644
index 0000000..12d7130
--- /dev/null
+++ b/lib/libstand/dev.c
@@ -0,0 +1,65 @@
+/* $NetBSD: dev.c,v 1.4 1994/10/30 21:48:23 cgd Exp $ */
+
+/*-
+ * 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.
+ * 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.
+ *
+ * @(#)dev.c 8.1 (Berkeley) 6/11/93
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/reboot.h>
+
+#include "stand.h"
+
+int
+nodev()
+{
+ return (ENXIO);
+}
+
+void
+nullsys()
+{
+}
+
+/* ARGSUSED */
+int
+noioctl(f, cmd, data)
+ struct open_file *f;
+ u_long cmd;
+ void *data;
+{
+ return (EINVAL);
+}
diff --git a/lib/libstand/dosfs.c b/lib/libstand/dosfs.c
new file mode 100644
index 0000000..161d330
--- /dev/null
+++ b/lib/libstand/dosfs.c
@@ -0,0 +1,708 @@
+/*
+ * Copyright (c) 1996, 1998 Robert Nordier
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(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 AUTHOR(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$");
+
+/*
+ * Readonly filesystem for Microsoft FAT12/FAT16/FAT32 filesystems,
+ * also supports VFAT.
+ */
+
+#include <sys/types.h>
+#include <string.h>
+#include <stddef.h>
+
+#include "stand.h"
+
+#include "dosfs.h"
+
+
+static int dos_open(const char *path, struct open_file *fd);
+static int dos_close(struct open_file *fd);
+static int dos_read(struct open_file *fd, void *buf, size_t size, size_t *resid);
+static off_t dos_seek(struct open_file *fd, off_t offset, int whence);
+static int dos_stat(struct open_file *fd, struct stat *sb);
+
+struct fs_ops dosfs_fsops = {
+ "dosfs",
+ dos_open,
+ dos_close,
+ dos_read,
+ null_write,
+ dos_seek,
+ dos_stat,
+ null_readdir
+};
+
+#define SECSIZ 512 /* sector size */
+#define SSHIFT 9 /* SECSIZ shift */
+#define DEPSEC 16 /* directory entries per sector */
+#define DSHIFT 4 /* DEPSEC shift */
+#define LOCLUS 2 /* lowest cluster number */
+
+/* DOS "BIOS Parameter Block" */
+typedef struct {
+ u_char secsiz[2]; /* sector size */
+ u_char spc; /* sectors per cluster */
+ u_char ressec[2]; /* reserved sectors */
+ u_char fats; /* FATs */
+ u_char dirents[2]; /* root directory entries */
+ u_char secs[2]; /* total sectors */
+ u_char media; /* media descriptor */
+ u_char spf[2]; /* sectors per FAT */
+ u_char spt[2]; /* sectors per track */
+ u_char heads[2]; /* drive heads */
+ u_char hidsec[4]; /* hidden sectors */
+ u_char lsecs[4]; /* huge sectors */
+ u_char lspf[4]; /* huge sectors per FAT */
+ u_char xflg[2]; /* flags */
+ u_char vers[2]; /* filesystem version */
+ u_char rdcl[4]; /* root directory start cluster */
+ u_char infs[2]; /* filesystem info sector */
+ u_char bkbs[2]; /* backup boot sector */
+} DOS_BPB;
+
+/* Initial portion of DOS boot sector */
+typedef struct {
+ u_char jmp[3]; /* usually 80x86 'jmp' opcode */
+ u_char oem[8]; /* OEM name and version */
+ DOS_BPB bpb; /* BPB */
+} DOS_BS;
+
+/* Supply missing "." and ".." root directory entries */
+static const char *const dotstr[2] = {".", ".."};
+static DOS_DE dot[2] = {
+ {". ", " ", FA_DIR, {0, 0, {0, 0}, {0, 0}, {0, 0}, {0, 0}},
+ {0, 0}, {0x21, 0}, {0, 0}, {0, 0, 0, 0}},
+ {".. ", " ", FA_DIR, {0, 0, {0, 0}, {0, 0}, {0, 0}, {0, 0}},
+ {0, 0}, {0x21, 0}, {0, 0}, {0, 0, 0, 0}}
+};
+
+/* The usual conversion macros to avoid multiplication and division */
+#define bytsec(n) ((n) >> SSHIFT)
+#define secbyt(s) ((s) << SSHIFT)
+#define entsec(e) ((e) >> DSHIFT)
+#define bytblk(fs, n) ((n) >> (fs)->bshift)
+#define blkbyt(fs, b) ((b) << (fs)->bshift)
+#define secblk(fs, s) ((s) >> ((fs)->bshift - SSHIFT))
+#define blksec(fs, b) ((b) << ((fs)->bshift - SSHIFT))
+
+/* Convert cluster number to offset within filesystem */
+#define blkoff(fs, b) (secbyt((fs)->lsndta) + blkbyt(fs, (b) - LOCLUS))
+
+/* Convert cluster number to logical sector number */
+#define blklsn(fs, b) ((fs)->lsndta + blksec(fs, (b) - LOCLUS))
+
+/* Convert cluster number to offset within FAT */
+#define fatoff(sz, c) ((sz) == 12 ? (c) + ((c) >> 1) : \
+ (sz) == 16 ? (c) << 1 : \
+ (c) << 2)
+
+/* Does cluster number reference a valid data cluster? */
+#define okclus(fs, c) ((c) >= LOCLUS && (c) <= (fs)->xclus)
+
+/* Get start cluster from directory entry */
+#define stclus(sz, de) ((sz) != 32 ? cv2((de)->clus) : \
+ ((u_int)cv2((de)->dex.h_clus) << 16) | \
+ cv2((de)->clus))
+
+static int dosunmount(DOS_FS *);
+static int parsebs(DOS_FS *, DOS_BS *);
+static int namede(DOS_FS *, const char *, DOS_DE **);
+static int lookup(DOS_FS *, u_int, const char *, DOS_DE **);
+static void cp_xdnm(u_char *, DOS_XDE *);
+static void cp_sfn(u_char *, DOS_DE *);
+static off_t fsize(DOS_FS *, DOS_DE *);
+static int fatcnt(DOS_FS *, u_int);
+static int fatget(DOS_FS *, u_int *);
+static int fatend(u_int, u_int);
+static int ioread(DOS_FS *, u_int, void *, u_int);
+static int iobuf(DOS_FS *, u_int);
+static int ioget(struct open_file *, u_int, void *, u_int);
+
+/*
+ * Mount DOS filesystem
+ */
+static int
+dos_mount(DOS_FS *fs, struct open_file *fd)
+{
+ int err;
+
+ bzero(fs, sizeof(DOS_FS));
+ fs->fd = fd;
+ if ((err = !(fs->buf = malloc(SECSIZ)) ? errno : 0) ||
+ (err = ioget(fs->fd, 0, fs->buf, 1)) ||
+ (err = parsebs(fs, (DOS_BS *)fs->buf))) {
+ (void)dosunmount(fs);
+ return(err);
+ }
+ return 0;
+}
+
+/*
+ * Unmount mounted filesystem
+ */
+static int
+dos_unmount(DOS_FS *fs)
+{
+ int err;
+
+ if (fs->links)
+ return(EBUSY);
+ if ((err = dosunmount(fs)))
+ return(err);
+ return 0;
+}
+
+/*
+ * Common code shared by dos_mount() and dos_unmount()
+ */
+static int
+dosunmount(DOS_FS *fs)
+{
+ if (fs->buf)
+ free(fs->buf);
+ free(fs);
+ return(0);
+}
+
+/*
+ * Open DOS file
+ */
+static int
+dos_open(const char *path, struct open_file *fd)
+{
+ DOS_DE *de;
+ DOS_FILE *f;
+ DOS_FS *fs;
+ u_int size, clus;
+ int err = 0;
+
+ /* Allocate mount structure, associate with open */
+ fs = malloc(sizeof(DOS_FS));
+
+ if ((err = dos_mount(fs, fd)))
+ goto out;
+
+ if ((err = namede(fs, path, &de)))
+ goto out;
+
+ clus = stclus(fs->fatsz, de);
+ size = cv4(de->size);
+
+ if ((!(de->attr & FA_DIR) && (!clus != !size)) ||
+ ((de->attr & FA_DIR) && size) ||
+ (clus && !okclus(fs, clus))) {
+ err = EINVAL;
+ goto out;
+ }
+ f = malloc(sizeof(DOS_FILE));
+ bzero(f, sizeof(DOS_FILE));
+ f->fs = fs;
+ fs->links++;
+ f->de = *de;
+ fd->f_fsdata = (void *)f;
+
+ out:
+ return(err);
+}
+
+/*
+ * Read from file
+ */
+static int
+dos_read(struct open_file *fd, void *buf, size_t nbyte, size_t *resid)
+{
+ off_t size;
+ u_int nb, off, clus, c, cnt, n;
+ DOS_FILE *f = (DOS_FILE *)fd->f_fsdata;
+ int err = 0;
+
+ nb = (u_int)nbyte;
+ if ((size = fsize(f->fs, &f->de)) == -1)
+ return EINVAL;
+ if (nb > (n = size - f->offset))
+ nb = n;
+ off = f->offset;
+ if ((clus = stclus(f->fs->fatsz, &f->de)))
+ off &= f->fs->bsize - 1;
+ c = f->c;
+ cnt = nb;
+ while (cnt) {
+ n = 0;
+ if (!c) {
+ if ((c = clus))
+ n = bytblk(f->fs, f->offset);
+ } else if (!off)
+ n++;
+ while (n--) {
+ if ((err = fatget(f->fs, &c)))
+ goto out;
+ if (!okclus(f->fs, c)) {
+ err = EINVAL;
+ goto out;
+ }
+ }
+ if (!clus || (n = f->fs->bsize - off) > cnt)
+ n = cnt;
+ if ((err = ioread(f->fs, (c ? blkoff(f->fs, c) :
+ secbyt(f->fs->lsndir)) + off,
+ buf, n)))
+ goto out;
+ f->offset += n;
+ f->c = c;
+ off = 0;
+ buf = (char *)buf + n;
+ cnt -= n;
+ }
+ out:
+ if (resid)
+ *resid = nbyte - nb + cnt;
+ return(err);
+}
+
+/*
+ * Reposition within file
+ */
+static off_t
+dos_seek(struct open_file *fd, off_t offset, int whence)
+{
+ off_t off;
+ u_int size;
+ DOS_FILE *f = (DOS_FILE *)fd->f_fsdata;
+
+ size = cv4(f->de.size);
+ switch (whence) {
+ case SEEK_SET:
+ off = 0;
+ break;
+ case SEEK_CUR:
+ off = f->offset;
+ break;
+ case SEEK_END:
+ off = size;
+ break;
+ default:
+ errno = EINVAL;
+ return(-1);
+ }
+ off += offset;
+ if (off < 0 || off > size) {
+ errno = EINVAL;
+ return(-1);
+ }
+ f->offset = (u_int)off;
+ f->c = 0;
+ return(off);
+}
+
+/*
+ * Close open file
+ */
+static int
+dos_close(struct open_file *fd)
+{
+ DOS_FILE *f = (DOS_FILE *)fd->f_fsdata;
+ DOS_FS *fs = f->fs;
+
+ f->fs->links--;
+ free(f);
+ dos_unmount(fs);
+ return 0;
+}
+
+/*
+ * Return some stat information on a file.
+ */
+static int
+dos_stat(struct open_file *fd, struct stat *sb)
+{
+ DOS_FILE *f = (DOS_FILE *)fd->f_fsdata;
+
+ /* only important stuff */
+ sb->st_mode = f->de.attr & FA_DIR ? S_IFDIR | 0555 : S_IFREG | 0444;
+ sb->st_nlink = 1;
+ sb->st_uid = 0;
+ sb->st_gid = 0;
+ if ((sb->st_size = fsize(f->fs, &f->de)) == -1)
+ return EINVAL;
+ return (0);
+}
+
+/*
+ * Parse DOS boot sector
+ */
+static int
+parsebs(DOS_FS *fs, DOS_BS *bs)
+{
+ u_int sc;
+
+ if ((bs->jmp[0] != 0x69 &&
+ bs->jmp[0] != 0xe9 &&
+ (bs->jmp[0] != 0xeb || bs->jmp[2] != 0x90)) ||
+ bs->bpb.media < 0xf0)
+ return EINVAL;
+ if (cv2(bs->bpb.secsiz) != SECSIZ)
+ return EINVAL;
+ if (!(fs->spc = bs->bpb.spc) || fs->spc & (fs->spc - 1))
+ return EINVAL;
+ fs->bsize = secbyt(fs->spc);
+ fs->bshift = ffs(fs->bsize) - 1;
+ if ((fs->spf = cv2(bs->bpb.spf))) {
+ if (bs->bpb.fats != 2)
+ return EINVAL;
+ if (!(fs->dirents = cv2(bs->bpb.dirents)))
+ return EINVAL;
+ } else {
+ if (!(fs->spf = cv4(bs->bpb.lspf)))
+ return EINVAL;
+ if (!bs->bpb.fats || bs->bpb.fats > 16)
+ return EINVAL;
+ if ((fs->rdcl = cv4(bs->bpb.rdcl)) < LOCLUS)
+ return EINVAL;
+ }
+ if (!(fs->lsnfat = cv2(bs->bpb.ressec)))
+ return EINVAL;
+ fs->lsndir = fs->lsnfat + fs->spf * bs->bpb.fats;
+ fs->lsndta = fs->lsndir + entsec(fs->dirents);
+ if (!(sc = cv2(bs->bpb.secs)) && !(sc = cv4(bs->bpb.lsecs)))
+ return EINVAL;
+ if (fs->lsndta > sc)
+ return EINVAL;
+ if ((fs->xclus = secblk(fs, sc - fs->lsndta) + 1) < LOCLUS)
+ return EINVAL;
+ fs->fatsz = fs->dirents ? fs->xclus < 0xff6 ? 12 : 16 : 32;
+ sc = (secbyt(fs->spf) << 1) / (fs->fatsz >> 2) - 1;
+ if (fs->xclus > sc)
+ fs->xclus = sc;
+ return 0;
+}
+
+/*
+ * Return directory entry from path
+ */
+static int
+namede(DOS_FS *fs, const char *path, DOS_DE **dep)
+{
+ char name[256];
+ DOS_DE *de;
+ char *s;
+ size_t n;
+ int err;
+
+ err = 0;
+ de = dot;
+ if (*path == '/')
+ path++;
+ while (*path) {
+ if (!(s = strchr(path, '/')))
+ s = strchr(path, 0);
+ if ((n = s - path) > 255)
+ return ENAMETOOLONG;
+ memcpy(name, path, n);
+ name[n] = 0;
+ path = s;
+ if (!(de->attr & FA_DIR))
+ return ENOTDIR;
+ if ((err = lookup(fs, stclus(fs->fatsz, de), name, &de)))
+ return err;
+ if (*path == '/')
+ path++;
+ }
+ *dep = de;
+ return 0;
+}
+
+/*
+ * Lookup path segment
+ */
+static int
+lookup(DOS_FS *fs, u_int clus, const char *name, DOS_DE **dep)
+{
+ static DOS_DIR dir[DEPSEC];
+ u_char lfn[261];
+ u_char sfn[13];
+ u_int nsec, lsec, xdn, chk, sec, ent, x;
+ int err, ok, i;
+
+ if (!clus)
+ for (ent = 0; ent < 2; ent++)
+ if (!strcasecmp(name, dotstr[ent])) {
+ *dep = dot + ent;
+ return 0;
+ }
+ if (!clus && fs->fatsz == 32)
+ clus = fs->rdcl;
+ nsec = !clus ? entsec(fs->dirents) : fs->spc;
+ lsec = 0;
+ xdn = chk = 0;
+ for (;;) {
+ if (!clus && !lsec)
+ lsec = fs->lsndir;
+ else if (okclus(fs, clus))
+ lsec = blklsn(fs, clus);
+ else
+ return EINVAL;
+ for (sec = 0; sec < nsec; sec++) {
+ if ((err = ioget(fs->fd, lsec + sec, dir, 1)))
+ return err;
+ for (ent = 0; ent < DEPSEC; ent++) {
+ if (!*dir[ent].de.name)
+ return ENOENT;
+ if (*dir[ent].de.name != 0xe5) {
+ if ((dir[ent].de.attr & FA_MASK) == FA_XDE) {
+ x = dir[ent].xde.seq;
+ if (x & 0x40 || (x + 1 == xdn &&
+ dir[ent].xde.chk == chk)) {
+ if (x & 0x40) {
+ chk = dir[ent].xde.chk;
+ x &= ~0x40;
+ }
+ if (x >= 1 && x <= 20) {
+ cp_xdnm(lfn, &dir[ent].xde);
+ xdn = x;
+ continue;
+ }
+ }
+ } else if (!(dir[ent].de.attr & FA_LABEL)) {
+ if ((ok = xdn == 1)) {
+ for (x = 0, i = 0; i < 11; i++)
+ x = ((((x & 1) << 7) | (x >> 1)) +
+ dir[ent].de.name[i]) & 0xff;
+ ok = chk == x &&
+ !strcasecmp(name, (const char *)lfn);
+ }
+ if (!ok) {
+ cp_sfn(sfn, &dir[ent].de);
+ ok = !strcasecmp(name, (const char *)sfn);
+ }
+ if (ok) {
+ *dep = &dir[ent].de;
+ return 0;
+ }
+ }
+ }
+ xdn = 0;
+ }
+ }
+ if (!clus)
+ break;
+ if ((err = fatget(fs, &clus)))
+ return err;
+ if (fatend(fs->fatsz, clus))
+ break;
+ }
+ return ENOENT;
+}
+
+/*
+ * Copy name from extended directory entry
+ */
+static void
+cp_xdnm(u_char *lfn, DOS_XDE *xde)
+{
+ static struct {
+ u_int off;
+ u_int dim;
+ } ix[3] = {
+ {offsetof(DOS_XDE, name1), sizeof(xde->name1) / 2},
+ {offsetof(DOS_XDE, name2), sizeof(xde->name2) / 2},
+ {offsetof(DOS_XDE, name3), sizeof(xde->name3) / 2}
+ };
+ u_char *p;
+ u_int n, x, c;
+
+ lfn += 13 * ((xde->seq & ~0x40) - 1);
+ for (n = 0; n < 3; n++)
+ for (p = (u_char *)xde + ix[n].off, x = ix[n].dim; x;
+ p += 2, x--) {
+ if ((c = cv2(p)) && (c < 32 || c > 127))
+ c = '?';
+ if (!(*lfn++ = c))
+ return;
+ }
+ if (xde->seq & 0x40)
+ *lfn = 0;
+}
+
+/*
+ * Copy short filename
+ */
+static void
+cp_sfn(u_char *sfn, DOS_DE *de)
+{
+ u_char *p;
+ int j, i;
+
+ p = sfn;
+ if (*de->name != ' ') {
+ for (j = 7; de->name[j] == ' '; j--);
+ for (i = 0; i <= j; i++)
+ *p++ = de->name[i];
+ if (*de->ext != ' ') {
+ *p++ = '.';
+ for (j = 2; de->ext[j] == ' '; j--);
+ for (i = 0; i <= j; i++)
+ *p++ = de->ext[i];
+ }
+ }
+ *p = 0;
+ if (*sfn == 5)
+ *sfn = 0xe5;
+}
+
+/*
+ * Return size of file in bytes
+ */
+static off_t
+fsize(DOS_FS *fs, DOS_DE *de)
+{
+ u_long size;
+ u_int c;
+ int n;
+
+ if (!(size = cv4(de->size)) && de->attr & FA_DIR) {
+ if (!(c = cv2(de->clus)))
+ size = fs->dirents * sizeof(DOS_DE);
+ else {
+ if ((n = fatcnt(fs, c)) == -1)
+ return n;
+ size = blkbyt(fs, n);
+ }
+ }
+ return size;
+}
+
+/*
+ * Count number of clusters in chain
+ */
+static int
+fatcnt(DOS_FS *fs, u_int c)
+{
+ int n;
+
+ for (n = 0; okclus(fs, c); n++)
+ if (fatget(fs, &c))
+ return -1;
+ return fatend(fs->fatsz, c) ? n : -1;
+}
+
+/*
+ * Get next cluster in cluster chain
+ */
+static int
+fatget(DOS_FS *fs, u_int *c)
+{
+ u_char buf[4];
+ u_int x;
+ int err;
+
+ err = ioread(fs, secbyt(fs->lsnfat) + fatoff(fs->fatsz, *c), buf,
+ fs->fatsz != 32 ? 2 : 4);
+ if (err)
+ return err;
+ x = fs->fatsz != 32 ? cv2(buf) : cv4(buf);
+ *c = fs->fatsz == 12 ? *c & 1 ? x >> 4 : x & 0xfff : x;
+ return 0;
+}
+
+/*
+ * Is cluster an end-of-chain marker?
+ */
+static int
+fatend(u_int sz, u_int c)
+{
+ return c > (sz == 12 ? 0xff7U : sz == 16 ? 0xfff7U : 0xffffff7);
+}
+
+/*
+ * Offset-based I/O primitive
+ */
+static int
+ioread(DOS_FS *fs, u_int offset, void *buf, u_int nbyte)
+{
+ char *s;
+ u_int off, n;
+ int err;
+
+ s = buf;
+ if ((off = offset & (SECSIZ - 1))) {
+ offset -= off;
+ if ((err = iobuf(fs, bytsec(offset))))
+ return err;
+ offset += SECSIZ;
+ if ((n = SECSIZ - off) > nbyte)
+ n = nbyte;
+ memcpy(s, fs->buf + off, n);
+ s += n;
+ nbyte -= n;
+ }
+ n = nbyte & (SECSIZ - 1);
+ if (nbyte -= n) {
+ if ((err = ioget(fs->fd, bytsec(offset), s, bytsec(nbyte))))
+ return err;
+ offset += nbyte;
+ s += nbyte;
+ }
+ if (n) {
+ if ((err = iobuf(fs, bytsec(offset))))
+ return err;
+ memcpy(s, fs->buf, n);
+ }
+ return 0;
+}
+
+/*
+ * Buffered sector-based I/O primitive
+ */
+static int
+iobuf(DOS_FS *fs, u_int lsec)
+{
+ int err;
+
+ if (fs->bufsec != lsec) {
+ if ((err = ioget(fs->fd, lsec, fs->buf, 1)))
+ return err;
+ fs->bufsec = lsec;
+ }
+ return 0;
+}
+
+/*
+ * Sector-based I/O primitive
+ */
+static int
+ioget(struct open_file *fd, u_int lsec, void *buf, u_int nsec)
+{
+ int err;
+
+ if ((err = (fd->f_dev->dv_strategy)(fd->f_devdata, F_READ, lsec,
+ secbyt(nsec), buf, NULL)))
+ return(err);
+ return(0);
+}
diff --git a/lib/libstand/dosfs.h b/lib/libstand/dosfs.h
new file mode 100644
index 0000000..e44b6b5
--- /dev/null
+++ b/lib/libstand/dosfs.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 1996, 1998 Robert Nordier
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(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 AUTHOR(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.
+ */
+
+#ifndef DOSIO_H
+#define DOSIO_H
+
+/*
+ * DOS file attributes
+ */
+
+#define FA_RDONLY 001 /* read-only */
+#define FA_HIDDEN 002 /* hidden file */
+#define FA_SYSTEM 004 /* system file */
+#define FA_LABEL 010 /* volume label */
+#define FA_DIR 020 /* directory */
+#define FA_ARCH 040 /* archive (file modified) */
+#define FA_XDE 017 /* extended directory entry */
+#define FA_MASK 077 /* all attributes */
+
+/*
+ * Macros to convert DOS-format 16-bit and 32-bit quantities
+ */
+
+#define cv2(p) ((u_int16_t)(p)[0] | \
+ ((u_int16_t)(p)[1] << 010))
+#define cv4(p) ((u_int32_t)(p)[0] | \
+ ((u_int32_t)(p)[1] << 010) | \
+ ((u_int32_t)(p)[2] << 020) | \
+ ((u_int32_t)(p)[3] << 030))
+
+/*
+ * Directory, filesystem, and file structures.
+ */
+
+typedef struct {
+ u_char x_case; /* case */
+ u_char c_hsec; /* created: secs/100 */
+ u_char c_time[2]; /* created: time */
+ u_char c_date[2]; /* created: date */
+ u_char a_date[2]; /* accessed: date */
+ u_char h_clus[2]; /* clus[hi] */
+} DOS_DEX;
+
+typedef struct {
+ u_char name[8]; /* name */
+ u_char ext[3]; /* extension */
+ u_char attr; /* attributes */
+ DOS_DEX dex; /* VFAT/FAT32 only */
+ u_char time[2]; /* modified: time */
+ u_char date[2]; /* modified: date */
+ u_char clus[2]; /* starting cluster */
+ u_char size[4]; /* size */
+} DOS_DE;
+
+typedef struct {
+ u_char seq; /* flags */
+ u_char name1[5][2]; /* 1st name area */
+ u_char attr; /* (see fat_de) */
+ u_char res; /* reserved */
+ u_char chk; /* checksum */
+ u_char name2[6][2]; /* 2nd name area */
+ u_char clus[2]; /* (see fat_de) */
+ u_char name3[2][2]; /* 3rd name area */
+} DOS_XDE;
+
+typedef union {
+ DOS_DE de; /* standard directory entry */
+ DOS_XDE xde; /* extended directory entry */
+} DOS_DIR;
+
+typedef struct {
+ struct open_file *fd; /* file descriptor */
+ u_char *buf; /* buffer */
+ u_int bufsec; /* buffered sector */
+ u_int links; /* active links to structure */
+ u_int spc; /* sectors per cluster */
+ u_int bsize; /* cluster size in bytes */
+ u_int bshift; /* cluster conversion shift */
+ u_int dirents; /* root directory entries */
+ u_int spf; /* sectors per fat */
+ u_int rdcl; /* root directory start cluster */
+ u_int lsnfat; /* start of fat */
+ u_int lsndir; /* start of root dir */
+ u_int lsndta; /* start of data area */
+ u_int fatsz; /* FAT entry size */
+ u_int xclus; /* maximum cluster number */
+} DOS_FS;
+
+typedef struct {
+ DOS_FS *fs; /* associated filesystem */
+ DOS_DE de; /* directory entry */
+ u_int offset; /* current offset */
+ u_int c; /* last cluster read */
+} DOS_FILE;
+
+#endif /* !DOSIO_H */
diff --git a/lib/libstand/environment.c b/lib/libstand/environment.c
new file mode 100644
index 0000000..1a3cfc7
--- /dev/null
+++ b/lib/libstand/environment.c
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 1998 Michael Smith.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Manage an environment-like space in which string variables may be stored.
+ * Provide support for some method-like operations for setting/retrieving
+ * variables in order to allow some type strength.
+ */
+
+#include "stand.h"
+
+#include <string.h>
+
+static void env_discard(struct env_var *ev);
+
+struct env_var *environ = NULL;
+
+/*
+ * Look up (name) and return it's env_var structure.
+ */
+struct env_var *
+env_getenv(const char *name)
+{
+ struct env_var *ev;
+
+ for (ev = environ; ev != NULL; ev = ev->ev_next)
+ if (!strcmp(ev->ev_name, name))
+ break;
+ return(ev);
+}
+
+/*
+ * Some notes:
+ *
+ * If the EV_VOLATILE flag is set, a copy of the variable is made.
+ * If EV_DYNAMIC is set, the the variable has been allocated with
+ * malloc and ownership transferred to the environment.
+ * If (value) is NULL, the variable is set but has no value.
+ */
+int
+env_setenv(const char *name, int flags, const void *value,
+ ev_sethook_t sethook, ev_unsethook_t unsethook)
+{
+ struct env_var *ev, *curr, *last;
+
+ if ((ev = env_getenv(name)) != NULL) {
+ /*
+ * If there's a set hook, let it do the work (unless we are working
+ * for one already.
+ */
+ if ((ev->ev_sethook != NULL) && !(flags & EV_NOHOOK))
+ return(ev->ev_sethook(ev, flags, value));
+ } else {
+
+ /*
+ * New variable; create and sort into list
+ */
+ ev = malloc(sizeof(struct env_var));
+ ev->ev_name = strdup(name);
+ ev->ev_value = NULL;
+ /* hooks can only be set when the variable is instantiated */
+ ev->ev_sethook = sethook;
+ ev->ev_unsethook = unsethook;
+
+ /* Sort into list */
+ ev->ev_prev = NULL;
+ ev->ev_next = NULL;
+ /* Search for the record to insert before */
+ for (last = NULL, curr = environ;
+ curr != NULL;
+ last = curr, curr = curr->ev_next) {
+
+ if (strcmp(ev->ev_name, curr->ev_name) < 0) {
+ if (curr->ev_prev) {
+ curr->ev_prev->ev_next = ev;
+ } else {
+ environ = ev;
+ }
+ ev->ev_next = curr;
+ ev->ev_prev = curr->ev_prev;
+ curr->ev_prev = ev;
+ break;
+ }
+ }
+ if (curr == NULL) {
+ if (last == NULL) {
+ environ = ev;
+ } else {
+ last->ev_next = ev;
+ ev->ev_prev = last;
+ }
+ }
+ }
+
+ /* If there is data in the variable, discard it */
+ if (ev->ev_value != NULL)
+ free(ev->ev_value);
+
+ /* If we have a new value, use it */
+ if (flags & EV_VOLATILE) {
+ ev->ev_value = strdup(value);
+ } else {
+ ev->ev_value = value;
+ }
+
+ /* Keep the flag components that are relevant */
+ ev->ev_flags = flags & (EV_DYNAMIC);
+
+ return(0);
+}
+
+char *
+getenv(const char *name)
+{
+ struct env_var *ev;
+
+ /* Set but no value gives empty string */
+ if ((ev = env_getenv(name)) != NULL) {
+ if (ev->ev_value != NULL)
+ return(ev->ev_value);
+ return("");
+ }
+ return(NULL);
+}
+
+int
+setenv(const char *name, const char *value, int overwrite)
+{
+ /* No guarantees about state, always assume volatile */
+ if (overwrite || (env_getenv(name) == NULL))
+ return(env_setenv(name, EV_VOLATILE, value, NULL, NULL));
+ return(0);
+}
+
+int
+putenv(const char *string)
+{
+ char *value, *copy;
+ int result;
+
+ copy = strdup(string);
+ if ((value = strchr(copy, '=')) != NULL)
+ *(value++) = 0;
+ result = setenv(copy, value, 1);
+ free(copy);
+ return(result);
+}
+
+int
+unsetenv(const char *name)
+{
+ struct env_var *ev;
+ int err;
+
+ err = 0;
+ if ((ev = env_getenv(name)) == NULL) {
+ err = ENOENT;
+ } else {
+ if (ev->ev_unsethook != NULL)
+ err = ev->ev_unsethook(ev);
+ if (err == 0) {
+ env_discard(ev);
+ }
+ }
+ return(err);
+}
+
+static void
+env_discard(struct env_var *ev)
+{
+ if (ev->ev_prev)
+ ev->ev_prev->ev_next = ev->ev_next;
+ if (ev->ev_next)
+ ev->ev_next->ev_prev = ev->ev_prev;
+ if (environ == ev)
+ environ = ev->ev_next;
+ free(ev->ev_name);
+ if (ev->ev_flags & EV_DYNAMIC)
+ free(ev->ev_value);
+ free(ev);
+}
+
+int
+env_noset(struct env_var *ev, int flags, const void *value)
+{
+ return(EPERM);
+}
+
+int
+env_nounset(struct env_var *ev)
+{
+ return(EPERM);
+}
diff --git a/lib/libstand/ether.c b/lib/libstand/ether.c
new file mode 100644
index 0000000..1fc5ff2
--- /dev/null
+++ b/lib/libstand/ether.c
@@ -0,0 +1,154 @@
+/* $NetBSD: ether.c,v 1.11 1997/07/07 15:52:50 drochner Exp $ */
+
+/*
+ * Copyright (c) 1992 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.
+ * 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, Lawrence Berkeley Laboratory 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.
+ *
+ * @(#) Header: net.c,v 1.9 93/08/06 19:32:15 leres Exp (LBL)
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <string.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+
+#include "stand.h"
+#include "net.h"
+#include "netif.h"
+
+/* Caller must leave room for ethernet header in front!! */
+ssize_t
+sendether(d, pkt, len, dea, etype)
+ struct iodesc *d;
+ void *pkt;
+ size_t len;
+ u_char *dea;
+ int etype;
+{
+ ssize_t n;
+ struct ether_header *eh;
+
+#ifdef ETHER_DEBUG
+ if (debug)
+ printf("sendether: called\n");
+#endif
+
+ eh = (struct ether_header *)pkt - 1;
+ len += sizeof(*eh);
+
+ MACPY(d->myea, eh->ether_shost); /* by byte */
+ MACPY(dea, eh->ether_dhost); /* by byte */
+ eh->ether_type = htons(etype);
+
+ n = netif_put(d, eh, len);
+ if (n == -1 || n < sizeof(*eh))
+ return (-1);
+
+ n -= sizeof(*eh);
+ return (n);
+}
+
+/*
+ * Get a packet of any Ethernet type, with our address or
+ * the broadcast address. Save the Ether type in arg 5.
+ * NOTE: Caller must leave room for the Ether header.
+ */
+ssize_t
+readether(d, pkt, len, tleft, etype)
+ struct iodesc *d;
+ void *pkt;
+ size_t len;
+ time_t tleft;
+ u_int16_t *etype;
+{
+ ssize_t n;
+ struct ether_header *eh;
+
+#ifdef ETHER_DEBUG
+ if (debug)
+ printf("readether: called\n");
+#endif
+
+ eh = (struct ether_header *)pkt - 1;
+ len += sizeof(*eh);
+
+ n = netif_get(d, eh, len, tleft);
+ if (n == -1 || n < sizeof(*eh))
+ return (-1);
+
+ /* Validate Ethernet address. */
+ if (bcmp(d->myea, eh->ether_dhost, 6) != 0 &&
+ bcmp(bcea, eh->ether_dhost, 6) != 0) {
+#ifdef ETHER_DEBUG
+ if (debug)
+ printf("readether: not ours (ea=%s)\n",
+ ether_sprintf(eh->ether_dhost));
+#endif
+ return (-1);
+ }
+ *etype = ntohs(eh->ether_type);
+
+ n -= sizeof(*eh);
+ return (n);
+}
+
+/*
+ * Convert Ethernet address to printable (loggable) representation.
+ */
+static char digits[] = "0123456789abcdef";
+char *
+ether_sprintf(ap)
+ u_char *ap;
+{
+ int i;
+ static char etherbuf[18];
+ char *cp = etherbuf;
+
+ for (i = 0; i < 6; i++) {
+ *cp++ = digits[*ap >> 4];
+ *cp++ = digits[*ap++ & 0xf];
+ *cp++ = ':';
+ }
+ *--cp = 0;
+ return (etherbuf);
+}
diff --git a/lib/libstand/ext2fs.c b/lib/libstand/ext2fs.c
new file mode 100644
index 0000000..1bd78e2
--- /dev/null
+++ b/lib/libstand/ext2fs.c
@@ -0,0 +1,906 @@
+/*-
+ * Copyright (c) 1999,2000 Jonathan Lemon <jlemon@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$");
+
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * The Mach Operating System project at Carnegie-Mellon 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. 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 (c) 1990, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Author: David Golub
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include "stand.h"
+#include "string.h"
+
+static int ext2fs_open(const char *path, struct open_file *f);
+static int ext2fs_close(struct open_file *f);
+static int ext2fs_read(struct open_file *f, void *buf,
+ size_t size, size_t *resid);
+static off_t ext2fs_seek(struct open_file *f, off_t offset, int where);
+static int ext2fs_stat(struct open_file *f, struct stat *sb);
+static int ext2fs_readdir(struct open_file *f, struct dirent *d);
+
+static int dtmap[] = { DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR,
+ DT_BLK, DT_FIFO, DT_SOCK, DT_LNK };
+#define EXTFTODT(x) (x) > sizeof(dtmap) / sizeof(dtmap[0]) ? \
+ DT_UNKNOWN : dtmap[x]
+
+struct fs_ops ext2fs_fsops = {
+ "ext2fs",
+ ext2fs_open,
+ ext2fs_close,
+ ext2fs_read,
+ null_write,
+ ext2fs_seek,
+ ext2fs_stat,
+ ext2fs_readdir
+};
+
+#define EXT2_SBSIZE 1024
+#define EXT2_SBLOCK (1024 / DEV_BSIZE) /* block offset of superblock */
+#define EXT2_MAGIC 0xef53
+#define EXT2_ROOTINO 2
+
+#define EXT2_REV0 0 /* original revision of ext2 */
+#define EXT2_R0_ISIZE 128 /* inode size */
+#define EXT2_R0_FIRSTINO 11 /* first inode */
+
+#define EXT2_MINBSHIFT 10 /* mininum block shift */
+#define EXT2_MINFSHIFT 10 /* mininum frag shift */
+
+#define NDADDR 12 /* # of direct blocks */
+#define NIADDR 3 /* # of indirect blocks */
+
+/*
+ * file system block to disk address
+ */
+#define fsb_to_db(fs, blk) ((blk) << (fs)->fs_fsbtodb)
+
+/*
+ * inode to block group offset
+ * inode to block group
+ * inode to disk address
+ * inode to block offset
+ */
+#define ino_to_bgo(fs, ino) (((ino) - 1) % (fs)->fs_ipg)
+#define ino_to_bg(fs, ino) (((ino) - 1) / (fs)->fs_ipg)
+#define ino_to_db(fs, bg, ino) \
+ fsb_to_db(fs, ((bg)[ino_to_bg(fs, ino)].bg_inotbl + \
+ ino_to_bgo(fs, ino) / (fs)->fs_ipb))
+#define ino_to_bo(fs, ino) (ino_to_bgo(fs, ino) % (fs)->fs_ipb)
+
+#define nindir(fs) \
+ ((fs)->fs_bsize / sizeof(u_int32_t))
+#define lblkno(fs, loc) /* loc / bsize */ \
+ ((loc) >> (fs)->fs_bshift)
+#define smalllblktosize(fs, blk) /* blk * bsize */ \
+ ((blk) << (fs)->fs_bshift)
+#define blkoff(fs, loc) /* loc % bsize */ \
+ ((loc) & (fs)->fs_bmask)
+#define fragroundup(fs, size) /* roundup(size, fsize) */ \
+ (((size) + (fs)->fs_fmask) & ~(fs)->fs_fmask)
+#define dblksize(fs, dip, lbn) \
+ (((lbn) >= NDADDR || (dip)->di_size >= smalllblktosize(fs, (lbn) + 1)) \
+ ? (fs)->fs_bsize \
+ : (fragroundup(fs, blkoff(fs, (dip)->di_size))))
+
+/*
+ * superblock describing ext2fs
+ */
+struct ext2fs_disk {
+ u_int32_t fd_inodes; /* # of inodes */
+ u_int32_t fd_blocks; /* # of blocks */
+ u_int32_t fd_resblk; /* # of reserved blocks */
+ u_int32_t fd_freeblk; /* # of free blocks */
+ u_int32_t fd_freeino; /* # of free inodes */
+ u_int32_t fd_firstblk; /* first data block */
+ u_int32_t fd_bsize; /* block size */
+ u_int32_t fd_fsize; /* frag size */
+ u_int32_t fd_bpg; /* blocks per group */
+ u_int32_t fd_fpg; /* frags per group */
+ u_int32_t fd_ipg; /* inodes per group */
+ u_int32_t fd_mtime; /* mount time */
+ u_int32_t fd_wtime; /* write time */
+ u_int16_t fd_mount; /* # of mounts */
+ int16_t fd_maxmount; /* max # of mounts */
+ u_int16_t fd_magic; /* magic number */
+ u_int16_t fd_state; /* state */
+ u_int16_t fd_eflag; /* error flags */
+ u_int16_t fd_mnrrev; /* minor revision */
+ u_int32_t fd_lastchk; /* last check */
+ u_int32_t fd_chkintvl; /* maximum check interval */
+ u_int32_t fd_os; /* os */
+ u_int32_t fd_revision; /* revision */
+ u_int16_t fd_uid; /* uid for reserved blocks */
+ u_int16_t fd_gid; /* gid for reserved blocks */
+
+ u_int32_t fd_firstino; /* first non-reserved inode */
+ u_int16_t fd_isize; /* inode size */
+ u_int16_t fd_nblkgrp; /* block group # of superblock */
+ u_int32_t fd_fcompat; /* compatible features */
+ u_int32_t fd_fincompat; /* incompatible features */
+ u_int32_t fd_frocompat; /* read-only compatibilties */
+ u_int8_t fd_uuid[16]; /* volume uuid */
+ char fd_volname[16]; /* volume name */
+ char fd_fsmnt[64]; /* name last mounted on */
+ u_int32_t fd_bitmap; /* compression bitmap */
+
+ u_int8_t fd_nblkpa; /* # of blocks to preallocate */
+ u_int8_t fd_ndblkpa; /* # of dir blocks to preallocate */
+};
+
+struct ext2fs_core {
+ int fc_bsize; /* block size */
+ int fc_bshift; /* block shift amount */
+ int fc_bmask; /* block mask */
+ int fc_fsize; /* frag size */
+ int fc_fshift; /* frag shift amount */
+ int fc_fmask; /* frag mask */
+ int fc_isize; /* inode size */
+ int fc_imask; /* inode mask */
+ int fc_firstino; /* first non-reserved inode */
+ int fc_ipb; /* inodes per block */
+ int fc_fsbtodb; /* fsb to ds shift */
+};
+
+struct ext2fs {
+ struct ext2fs_disk fs_fd;
+ char fs_pad[EXT2_SBSIZE - sizeof(struct ext2fs_disk)];
+ struct ext2fs_core fs_fc;
+
+#define fs_magic fs_fd.fd_magic
+#define fs_revision fs_fd.fd_revision
+#define fs_blocks fs_fd.fd_blocks
+#define fs_firstblk fs_fd.fd_firstblk
+#define fs_bpg fs_fd.fd_bpg
+#define fs_ipg fs_fd.fd_ipg
+
+#define fs_bsize fs_fc.fc_bsize
+#define fs_bshift fs_fc.fc_bshift
+#define fs_bmask fs_fc.fc_bmask
+#define fs_fsize fs_fc.fc_fsize
+#define fs_fshift fs_fc.fc_fshift
+#define fs_fmask fs_fc.fc_fmask
+#define fs_isize fs_fc.fc_isize
+#define fs_imask fs_fc.fc_imask
+#define fs_firstino fs_fc.fc_firstino
+#define fs_ipb fs_fc.fc_ipb
+#define fs_fsbtodb fs_fc.fc_fsbtodb
+};
+
+struct ext2blkgrp {
+ u_int32_t bg_blkmap; /* block bitmap */
+ u_int32_t bg_inomap; /* inode bitmap */
+ u_int32_t bg_inotbl; /* inode table */
+ u_int16_t bg_nfblk; /* # of free blocks */
+ u_int16_t bg_nfino; /* # of free inodes */
+ u_int16_t bg_ndirs; /* # of dirs */
+ char bg_pad[14];
+};
+
+struct ext2dinode {
+ u_int16_t di_mode; /* mode */
+ u_int16_t di_uid; /* uid */
+ u_int32_t di_size; /* byte size */
+ u_int32_t di_atime; /* access time */
+ u_int32_t di_ctime; /* creation time */
+ u_int32_t di_mtime; /* modification time */
+ u_int32_t di_dtime; /* deletion time */
+ u_int16_t di_gid; /* gid */
+ u_int16_t di_nlink; /* link count */
+ u_int32_t di_nblk; /* block count */
+ u_int32_t di_flags; /* file flags */
+
+ u_int32_t di_osdep1; /* os dependent stuff */
+
+ u_int32_t di_db[NDADDR]; /* direct blocks */
+ u_int32_t di_ib[NIADDR]; /* indirect blocks */
+ u_int32_t di_version; /* version */
+ u_int32_t di_facl; /* file acl */
+ u_int32_t di_dacl; /* dir acl */
+ u_int32_t di_faddr; /* fragment addr */
+
+ u_int8_t di_frag; /* fragment number */
+ u_int8_t di_fsize; /* fragment size */
+
+ char di_pad[10];
+
+#define di_shortlink di_db
+};
+
+#define EXT2_MAXNAMLEN 255
+
+struct ext2dirent {
+ u_int32_t d_ino; /* inode */
+ u_int16_t d_reclen; /* directory entry length */
+ u_int8_t d_namlen; /* name length */
+ u_int8_t d_type; /* file type */
+ char d_name[EXT2_MAXNAMLEN];
+};
+
+struct file {
+ off_t f_seekp; /* seek pointer */
+ struct ext2fs *f_fs; /* pointer to super-block */
+ struct ext2blkgrp *f_bg; /* pointer to blkgrp map */
+ struct ext2dinode f_di; /* copy of on-disk inode */
+ int f_nindir[NIADDR]; /* number of blocks mapped by
+ indirect block at level i */
+ char *f_blk[NIADDR]; /* buffer for indirect block
+ at level i */
+ size_t f_blksize[NIADDR]; /* size of buffer */
+ daddr_t f_blkno[NIADDR]; /* disk address of block in
+ buffer */
+ char *f_buf; /* buffer for data block */
+ size_t f_buf_size; /* size of data block */
+ daddr_t f_buf_blkno; /* block number of data block */
+};
+
+/* forward decls */
+static int read_inode(ino_t inumber, struct open_file *f);
+static int block_map(struct open_file *f, daddr_t file_block,
+ daddr_t *disk_block_p);
+static int buf_read_file(struct open_file *f, char **buf_p,
+ size_t *size_p);
+static int search_directory(char *name, struct open_file *f,
+ ino_t *inumber_p);
+
+/*
+ * Open a file.
+ */
+static int
+ext2fs_open(const char *upath, struct open_file *f)
+{
+ struct file *fp;
+ struct ext2fs *fs;
+ size_t buf_size;
+ ino_t inumber, parent_inumber;
+ int i, len, groups, bg_per_blk, blkgrps, mult;
+ int nlinks = 0;
+ int error = 0;
+ char *cp, *ncp, *path = NULL, *buf = NULL;
+ char namebuf[MAXPATHLEN+1];
+ char c;
+
+ /* allocate file system specific data structure */
+ fp = malloc(sizeof(struct file));
+ if (fp == NULL)
+ return (ENOMEM);
+ bzero(fp, sizeof(struct file));
+ f->f_fsdata = (void *)fp;
+
+ /* allocate space and read super block */
+ fs = (struct ext2fs *)malloc(sizeof(*fs));
+ fp->f_fs = fs;
+ twiddle();
+ error = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
+ EXT2_SBLOCK, EXT2_SBSIZE, (char *)fs, &buf_size);
+ if (error)
+ goto out;
+
+ if (buf_size != EXT2_SBSIZE || fs->fs_magic != EXT2_MAGIC) {
+ error = EINVAL;
+ goto out;
+ }
+
+ /*
+ * compute in-core values for the superblock
+ */
+ fs->fs_bshift = EXT2_MINBSHIFT + fs->fs_fd.fd_bsize;
+ fs->fs_bsize = 1 << fs->fs_bshift;
+ fs->fs_bmask = fs->fs_bsize - 1;
+
+ fs->fs_fshift = EXT2_MINFSHIFT + fs->fs_fd.fd_fsize;
+ fs->fs_fsize = 1 << fs->fs_fshift;
+ fs->fs_fmask = fs->fs_fsize - 1;
+
+ if (fs->fs_revision == EXT2_REV0) {
+ fs->fs_isize = EXT2_R0_ISIZE;
+ fs->fs_firstino = EXT2_R0_FIRSTINO;
+ } else {
+ fs->fs_isize = fs->fs_fd.fd_isize;
+ fs->fs_firstino = fs->fs_fd.fd_firstino;
+ }
+ fs->fs_imask = fs->fs_isize - 1;
+ fs->fs_ipb = fs->fs_bsize / fs->fs_isize;
+ fs->fs_fsbtodb = (fs->fs_bsize / DEV_BSIZE) - 1;
+
+ /*
+ * we have to load in the "group descriptors" here
+ */
+ groups = howmany(fs->fs_blocks - fs->fs_firstblk, fs->fs_bpg);
+ bg_per_blk = fs->fs_bsize / sizeof(struct ext2blkgrp);
+ blkgrps = howmany(groups, bg_per_blk);
+ len = blkgrps * fs->fs_bsize;
+
+ fp->f_bg = malloc(len);
+ twiddle();
+ error = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
+ EXT2_SBLOCK + EXT2_SBSIZE / DEV_BSIZE, len,
+ (char *)fp->f_bg, &buf_size);
+ if (error)
+ goto out;
+
+ /*
+ * XXX
+ * validation of values? (blocksize, descriptors, etc?)
+ */
+
+ /*
+ * Calculate indirect block levels.
+ */
+ mult = 1;
+ for (i = 0; i < NIADDR; i++) {
+ mult *= nindir(fs);
+ fp->f_nindir[i] = mult;
+ }
+
+ inumber = EXT2_ROOTINO;
+ if ((error = read_inode(inumber, f)) != 0)
+ goto out;
+
+ path = strdup(upath);
+ if (path == NULL) {
+ error = ENOMEM;
+ goto out;
+ }
+ cp = path;
+ while (*cp) {
+ /*
+ * Remove extra separators
+ */
+ while (*cp == '/')
+ cp++;
+ if (*cp == '\0')
+ break;
+
+ /*
+ * Check that current node is a directory.
+ */
+ if (! S_ISDIR(fp->f_di.di_mode)) {
+ error = ENOTDIR;
+ goto out;
+ }
+
+ /*
+ * Get next component of path name.
+ */
+ len = 0;
+
+ ncp = cp;
+ while ((c = *cp) != '\0' && c != '/') {
+ if (++len > EXT2_MAXNAMLEN) {
+ error = ENOENT;
+ goto out;
+ }
+ cp++;
+ }
+ *cp = '\0';
+
+ /*
+ * Look up component in current directory.
+ * Save directory inumber in case we find a
+ * symbolic link.
+ */
+ parent_inumber = inumber;
+ error = search_directory(ncp, f, &inumber);
+ *cp = c;
+ if (error)
+ goto out;
+
+ /*
+ * Open next component.
+ */
+ if ((error = read_inode(inumber, f)) != 0)
+ goto out;
+
+ /*
+ * Check for symbolic link.
+ */
+ if (S_ISLNK(fp->f_di.di_mode)) {
+ int link_len = fp->f_di.di_size;
+ int len;
+
+ len = strlen(cp);
+ if (link_len + len > MAXPATHLEN ||
+ ++nlinks > MAXSYMLINKS) {
+ error = ENOENT;
+ goto out;
+ }
+
+ bcopy(cp, &namebuf[link_len], len + 1);
+ if (fp->f_di.di_nblk == 0) {
+ bcopy(fp->f_di.di_shortlink,
+ namebuf, link_len);
+ } else {
+ /*
+ * Read file for symbolic link
+ */
+ struct ext2fs *fs = fp->f_fs;
+ daddr_t disk_block;
+ size_t buf_size;
+
+ if (! buf)
+ buf = malloc(fs->fs_bsize);
+ error = block_map(f, (daddr_t)0, &disk_block);
+ if (error)
+ goto out;
+
+ twiddle();
+ error = (f->f_dev->dv_strategy)(f->f_devdata,
+ F_READ, fsb_to_db(fs, disk_block),
+ fs->fs_bsize, buf, &buf_size);
+ if (error)
+ goto out;
+
+ bcopy((char *)buf, namebuf, link_len);
+ }
+
+ /*
+ * If relative pathname, restart at parent directory.
+ * If absolute pathname, restart at root.
+ */
+ cp = namebuf;
+ if (*cp != '/')
+ inumber = parent_inumber;
+ else
+ inumber = (ino_t)EXT2_ROOTINO;
+
+ if ((error = read_inode(inumber, f)) != 0)
+ goto out;
+ }
+ }
+
+ /*
+ * Found terminal component.
+ */
+ error = 0;
+out:
+ if (buf)
+ free(buf);
+ if (path)
+ free(path);
+ if (error) {
+ if (fp->f_buf)
+ free(fp->f_buf);
+ free(fp->f_fs);
+ free(fp);
+ }
+ return (error);
+}
+
+/*
+ * Read a new inode into a file structure.
+ */
+static int
+read_inode(ino_t inumber, struct open_file *f)
+{
+ struct file *fp = (struct file *)f->f_fsdata;
+ struct ext2fs *fs = fp->f_fs;
+ struct ext2dinode *dp;
+ char *buf;
+ size_t rsize;
+ int level, error = 0;
+
+ /*
+ * Read inode and save it.
+ */
+ buf = malloc(fs->fs_bsize);
+ twiddle();
+ error = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
+ ino_to_db(fs, fp->f_bg, inumber), fs->fs_bsize, buf, &rsize);
+ if (error)
+ goto out;
+ if (rsize != fs->fs_bsize) {
+ error = EIO;
+ goto out;
+ }
+
+ dp = (struct ext2dinode *)buf;
+ fp->f_di = dp[ino_to_bo(fs, inumber)];
+
+ /* clear out old buffers */
+ for (level = 0; level < NIADDR; level++)
+ fp->f_blkno[level] = -1;
+ fp->f_buf_blkno = -1;
+
+out:
+ free(buf);
+ return (error);
+}
+
+/*
+ * Given an offset in a file, find the disk block number that
+ * contains that block.
+ */
+static int
+block_map(struct open_file *f, daddr_t file_block, daddr_t *disk_block_p)
+{
+ struct file *fp = (struct file *)f->f_fsdata;
+ struct ext2fs *fs = fp->f_fs;
+ daddr_t ind_block_num;
+ int32_t *ind_p;
+ int idx, level;
+ int error;
+
+ /*
+ * Index structure of an inode:
+ *
+ * di_db[0..NDADDR-1] hold block numbers for blocks
+ * 0..NDADDR-1
+ *
+ * di_ib[0] index block 0 is the single indirect block
+ * holds block numbers for blocks
+ * NDADDR .. NDADDR + NINDIR(fs)-1
+ *
+ * di_ib[1] index block 1 is the double indirect block
+ * holds block numbers for INDEX blocks for blocks
+ * NDADDR + NINDIR(fs) ..
+ * NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1
+ *
+ * di_ib[2] index block 2 is the triple indirect block
+ * holds block numbers for double-indirect
+ * blocks for blocks
+ * NDADDR + NINDIR(fs) + NINDIR(fs)**2 ..
+ * NDADDR + NINDIR(fs) + NINDIR(fs)**2
+ * + NINDIR(fs)**3 - 1
+ */
+
+ if (file_block < NDADDR) {
+ /* Direct block. */
+ *disk_block_p = fp->f_di.di_db[file_block];
+ return (0);
+ }
+
+ file_block -= NDADDR;
+
+ /*
+ * nindir[0] = NINDIR
+ * nindir[1] = NINDIR**2
+ * nindir[2] = NINDIR**3
+ * etc
+ */
+ for (level = 0; level < NIADDR; level++) {
+ if (file_block < fp->f_nindir[level])
+ break;
+ file_block -= fp->f_nindir[level];
+ }
+ if (level == NIADDR) {
+ /* Block number too high */
+ return (EFBIG);
+ }
+
+ ind_block_num = fp->f_di.di_ib[level];
+
+ for (; level >= 0; level--) {
+ if (ind_block_num == 0) {
+ *disk_block_p = 0; /* missing */
+ return (0);
+ }
+
+ if (fp->f_blkno[level] != ind_block_num) {
+ if (fp->f_blk[level] == (char *)0)
+ fp->f_blk[level] =
+ malloc(fs->fs_bsize);
+ twiddle();
+ error = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
+ fsb_to_db(fp->f_fs, ind_block_num), fs->fs_bsize,
+ fp->f_blk[level], &fp->f_blksize[level]);
+ if (error)
+ return (error);
+ if (fp->f_blksize[level] != fs->fs_bsize)
+ return (EIO);
+ fp->f_blkno[level] = ind_block_num;
+ }
+
+ ind_p = (int32_t *)fp->f_blk[level];
+
+ if (level > 0) {
+ idx = file_block / fp->f_nindir[level - 1];
+ file_block %= fp->f_nindir[level - 1];
+ } else {
+ idx = file_block;
+ }
+ ind_block_num = ind_p[idx];
+ }
+
+ *disk_block_p = ind_block_num;
+
+ return (0);
+}
+
+/*
+ * Read a portion of a file into an internal buffer. Return
+ * the location in the buffer and the amount in the buffer.
+ */
+static int
+buf_read_file(struct open_file *f, char **buf_p, size_t *size_p)
+{
+ struct file *fp = (struct file *)f->f_fsdata;
+ struct ext2fs *fs = fp->f_fs;
+ long off;
+ daddr_t file_block;
+ daddr_t disk_block;
+ size_t block_size;
+ int error = 0;
+
+ off = blkoff(fs, fp->f_seekp);
+ file_block = lblkno(fs, fp->f_seekp);
+ block_size = dblksize(fs, &fp->f_di, file_block);
+
+ if (file_block != fp->f_buf_blkno) {
+ error = block_map(f, file_block, &disk_block);
+ if (error)
+ goto done;
+
+ if (fp->f_buf == (char *)0)
+ fp->f_buf = malloc(fs->fs_bsize);
+
+ if (disk_block == 0) {
+ bzero(fp->f_buf, block_size);
+ fp->f_buf_size = block_size;
+ } else {
+ twiddle();
+ error = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
+ fsb_to_db(fs, disk_block), block_size,
+ fp->f_buf, &fp->f_buf_size);
+ if (error)
+ goto done;
+ }
+ fp->f_buf_blkno = file_block;
+ }
+
+ /*
+ * Return address of byte in buffer corresponding to
+ * offset, and size of remainder of buffer after that
+ * byte.
+ */
+ *buf_p = fp->f_buf + off;
+ *size_p = block_size - off;
+
+ /*
+ * But truncate buffer at end of file.
+ */
+ if (*size_p > fp->f_di.di_size - fp->f_seekp)
+ *size_p = fp->f_di.di_size - fp->f_seekp;
+done:
+ return (error);
+}
+
+/*
+ * Search a directory for a name and return its
+ * i_number.
+ */
+static int
+search_directory(char *name, struct open_file *f, ino_t *inumber_p)
+{
+ struct file *fp = (struct file *)f->f_fsdata;
+ struct ext2dirent *dp, *edp;
+ char *buf;
+ size_t buf_size;
+ int namlen, length;
+ int error;
+
+ length = strlen(name);
+ fp->f_seekp = 0;
+ while (fp->f_seekp < fp->f_di.di_size) {
+ error = buf_read_file(f, &buf, &buf_size);
+ if (error)
+ return (error);
+ dp = (struct ext2dirent *)buf;
+ edp = (struct ext2dirent *)(buf + buf_size);
+ while (dp < edp) {
+ if (dp->d_ino == (ino_t)0)
+ goto next;
+ namlen = dp->d_namlen;
+ if (namlen == length &&
+ strncmp(name, dp->d_name, length) == 0) {
+ /* found entry */
+ *inumber_p = dp->d_ino;
+ return (0);
+ }
+ next:
+ dp = (struct ext2dirent *)((char *)dp + dp->d_reclen);
+ }
+ fp->f_seekp += buf_size;
+ }
+ return (ENOENT);
+}
+
+static int
+ext2fs_close(struct open_file *f)
+{
+ struct file *fp = (struct file *)f->f_fsdata;
+ int level;
+
+ f->f_fsdata = (void *)0;
+ if (fp == (struct file *)0)
+ return (0);
+
+ for (level = 0; level < NIADDR; level++) {
+ if (fp->f_blk[level])
+ free(fp->f_blk[level]);
+ }
+ if (fp->f_buf)
+ free(fp->f_buf);
+ if (fp->f_bg)
+ free(fp->f_bg);
+ free(fp->f_fs);
+ free(fp);
+ return (0);
+}
+
+static int
+ext2fs_read(struct open_file *f, void *addr, size_t size, size_t *resid)
+{
+ struct file *fp = (struct file *)f->f_fsdata;
+ size_t csize, buf_size;
+ char *buf;
+ int error = 0;
+
+ while (size != 0) {
+ if (fp->f_seekp >= fp->f_di.di_size)
+ break;
+
+ error = buf_read_file(f, &buf, &buf_size);
+ if (error)
+ break;
+
+ csize = size;
+ if (csize > buf_size)
+ csize = buf_size;
+
+ bcopy(buf, addr, csize);
+
+ fp->f_seekp += csize;
+ addr = (char *)addr + csize;
+ size -= csize;
+ }
+ if (resid)
+ *resid = size;
+ return (error);
+}
+
+static off_t
+ext2fs_seek(struct open_file *f, off_t offset, int where)
+{
+ struct file *fp = (struct file *)f->f_fsdata;
+
+ switch (where) {
+ case SEEK_SET:
+ fp->f_seekp = offset;
+ break;
+ case SEEK_CUR:
+ fp->f_seekp += offset;
+ break;
+ case SEEK_END:
+ fp->f_seekp = fp->f_di.di_size - offset;
+ break;
+ default:
+ errno = EINVAL;
+ return (-1);
+ }
+ return (fp->f_seekp);
+}
+
+static int
+ext2fs_stat(struct open_file *f, struct stat *sb)
+{
+ struct file *fp = (struct file *)f->f_fsdata;
+
+ /* only important stuff */
+ sb->st_mode = fp->f_di.di_mode;
+ sb->st_uid = fp->f_di.di_uid;
+ sb->st_gid = fp->f_di.di_gid;
+ sb->st_size = fp->f_di.di_size;
+ return (0);
+}
+
+static int
+ext2fs_readdir(struct open_file *f, struct dirent *d)
+{
+ struct file *fp = (struct file *)f->f_fsdata;
+ struct ext2dirent *ed;
+ char *buf;
+ size_t buf_size;
+ int error;
+
+ /*
+ * assume that a directory entry will not be split across blocks
+ */
+again:
+ if (fp->f_seekp >= fp->f_di.di_size)
+ return (ENOENT);
+ error = buf_read_file(f, &buf, &buf_size);
+ if (error)
+ return (error);
+ ed = (struct ext2dirent *)buf;
+ fp->f_seekp += ed->d_reclen;
+ if (ed->d_ino == (ino_t)0)
+ goto again;
+ d->d_type = EXTFTODT(ed->d_type);
+ strncpy(d->d_name, ed->d_name, ed->d_namlen);
+ d->d_name[ed->d_namlen] = '\0';
+ return (0);
+}
diff --git a/lib/libstand/fstat.c b/lib/libstand/fstat.c
new file mode 100644
index 0000000..7d95360
--- /dev/null
+++ b/lib/libstand/fstat.c
@@ -0,0 +1,65 @@
+/* $NetBSD: fstat.c,v 1.1 1996/01/13 22:25:38 leo Exp $ */
+
+/*-
+ * 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.
+ * 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.
+ *
+ * @(#)stat.c 8.1 (Berkeley) 6/11/93
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "stand.h"
+
+int
+fstat(fd, sb)
+ int fd;
+ struct stat *sb;
+{
+ struct open_file *f = &files[fd];
+
+ if ((unsigned)fd >= SOPEN_MAX || f->f_flags == 0) {
+ errno = EBADF;
+ return (-1);
+ }
+
+ /* operation not defined on raw devices */
+ if (f->f_flags & F_RAW) {
+ errno = EOPNOTSUPP;
+ return (-1);
+ }
+
+ errno = (f->f_ops->fo_stat)(f, sb);
+ if (errno)
+ return (-1);
+ return (0);
+}
diff --git a/lib/libstand/getopt.c b/lib/libstand/getopt.c
new file mode 100644
index 0000000..9af05e0
--- /dev/null
+++ b/lib/libstand/getopt.c
@@ -0,0 +1,115 @@
+/*
+ * 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. 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)getopt.c 8.3 (Berkeley) 4/27/95";
+#endif /* LIBC_SCCS and not lint */
+
+#include "stand.h"
+#include <string.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(nargc, nargv, ostr)
+ int nargc;
+ char * const *nargv;
+ const char *ostr;
+{
+ static char *place = EMSG; /* option letter processing */
+ char *oli; /* option letter list index */
+
+ if (optreset || !*place) { /* update scanning pointer */
+ optreset = 0;
+ if (optind >= nargc || *(place = nargv[optind]) != '-') {
+ place = EMSG;
+ return (-1);
+ }
+ if (place[1] && *++place == '-') { /* found "--" */
+ ++optind;
+ place = EMSG;
+ return (-1);
+ }
+ } /* option letter okay? */
+ if ((optopt = (int)*place++) == (int)':' ||
+ !(oli = strchr(ostr, optopt))) {
+ /*
+ * if the user didn't specify '-' as an option,
+ * assume it means -1.
+ */
+ if (optopt == (int)'-')
+ return (-1);
+ if (!*place)
+ ++optind;
+ if (opterr && *ostr != ':')
+ (void)printf("illegal option -- %c\n", optopt);
+ return (BADCH);
+ }
+ if (*++oli != ':') { /* don't need argument */
+ optarg = NULL;
+ if (!*place)
+ ++optind;
+ }
+ else { /* need an argument */
+ if (*place) /* no white space */
+ optarg = place;
+ else if (nargc <= ++optind) { /* no arg */
+ place = EMSG;
+ if (*ostr == ':')
+ return (BADARG);
+ if (opterr)
+ (void)printf("option requires an argument -- %c\n", optopt);
+ return (BADCH);
+ }
+ else /* white space */
+ optarg = nargv[optind];
+ place = EMSG;
+ ++optind;
+ }
+ return (optopt); /* dump back option letter */
+}
diff --git a/lib/libstand/gets.c b/lib/libstand/gets.c
new file mode 100644
index 0000000..cb0e755
--- /dev/null
+++ b/lib/libstand/gets.c
@@ -0,0 +1,116 @@
+/* $NetBSD: gets.c,v 1.6 1995/10/11 21:16:57 pk Exp $ */
+
+/*-
+ * 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.
+ * 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.
+ *
+ * @(#)gets.c 8.1 (Berkeley) 6/11/93
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "stand.h"
+
+/* gets() with constrained input length */
+
+void
+ngets(char *buf, int n)
+{
+ int c;
+ char *lp;
+
+ for (lp = buf;;)
+ switch (c = getchar() & 0177) {
+ case '\n':
+ case '\r':
+ *lp = '\0';
+ putchar('\n');
+ return;
+ case '\b':
+ case '\177':
+ if (lp > buf) {
+ lp--;
+ putchar('\b');
+ putchar(' ');
+ putchar('\b');
+ }
+ break;
+ case 'r'&037: {
+ char *p;
+
+ putchar('\n');
+ for (p = buf; p < lp; ++p)
+ putchar(*p);
+ break;
+ }
+ case 'u'&037:
+ case 'w'&037:
+ lp = buf;
+ putchar('\n');
+ break;
+ default:
+ if ((n < 1) || ((lp - buf) < n)) {
+ *lp++ = c;
+ putchar(c);
+ }
+ }
+ /*NOTREACHED*/
+}
+
+int
+fgetstr(char *buf, int size, int fd)
+{
+ char c;
+ int err, len;
+
+ size--; /* leave space for terminator */
+ len = 0;
+ while (size != 0) {
+ err = read(fd, &c, sizeof(c));
+ if (err < 0) /* read error */
+ return(-1);
+ if (err == 0) { /* EOF */
+ if (len == 0)
+ return(-1); /* nothing to read */
+ break;
+ }
+ if ((c == '\r') || /* line terminators */
+ (c == '\n'))
+ break;
+ *buf++ = c; /* keep char */
+ size--;
+ len++;
+ }
+ *buf = 0;
+ return(len);
+}
+
diff --git a/lib/libstand/globals.c b/lib/libstand/globals.c
new file mode 100644
index 0000000..0310823
--- /dev/null
+++ b/lib/libstand/globals.c
@@ -0,0 +1,36 @@
+/* $NetBSD: globals.c,v 1.3 1995/09/18 21:19:27 pk Exp $ */
+
+/*
+ * globals.c:
+ *
+ * global variables should be separate, so nothing else
+ * must be included extraneously.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+
+#include "stand.h"
+#include "net.h"
+
+u_char bcea[6] = BA; /* broadcast ethernet address */
+
+char rootpath[FNAME_SIZE] = "/"; /* root mount path */
+char bootfile[FNAME_SIZE]; /* bootp says to boot this */
+char hostname[FNAME_SIZE]; /* our hostname */
+int hostnamelen;
+char domainname[FNAME_SIZE]; /* our DNS domain */
+int domainnamelen;
+char ifname[IFNAME_SIZE]; /* name of interface (e.g. "le0") */
+struct in_addr myip; /* my ip address */
+struct in_addr nameip; /* DNS server ip address */
+struct in_addr rootip; /* root ip address */
+struct in_addr swapip; /* swap ip address */
+struct in_addr gateip; /* swap ip address */
+n_long netmask = 0xffffff00; /* subnet or net mask */
+int errno; /* our old friend */
+
diff --git a/lib/libstand/gzipfs.c b/lib/libstand/gzipfs.c
new file mode 100644
index 0000000..0d7c59b
--- /dev/null
+++ b/lib/libstand/gzipfs.c
@@ -0,0 +1,345 @@
+/*
+ * Copyright (c) 1998 Michael Smith.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "stand.h"
+
+#include <sys/stat.h>
+#include <string.h>
+#include <zlib.h>
+
+#define Z_BUFSIZE 2048 /* XXX larger? */
+
+struct z_file
+{
+ int zf_rawfd;
+ off_t zf_dataoffset;
+ z_stream zf_zstream;
+ char zf_buf[Z_BUFSIZE];
+};
+
+static int zf_fill(struct z_file *z);
+static int zf_open(const char *path, struct open_file *f);
+static int zf_close(struct open_file *f);
+static int zf_read(struct open_file *f, void *buf, size_t size, size_t *resid);
+static off_t zf_seek(struct open_file *f, off_t offset, int where);
+static int zf_stat(struct open_file *f, struct stat *sb);
+
+struct fs_ops gzipfs_fsops = {
+ "zip",
+ zf_open,
+ zf_close,
+ zf_read,
+ null_write,
+ zf_seek,
+ zf_stat,
+ null_readdir
+};
+
+#if 0
+void *
+calloc(int items, size_t size)
+{
+ return(malloc(items * size));
+}
+#endif
+
+static int
+zf_fill(struct z_file *zf)
+{
+ int result;
+ int req;
+
+ req = Z_BUFSIZE - zf->zf_zstream.avail_in;
+ result = 0;
+
+ /* If we need more */
+ if (req > 0) {
+ /* move old data to bottom of buffer */
+ if (req < Z_BUFSIZE)
+ bcopy(zf->zf_buf + req, zf->zf_buf, Z_BUFSIZE - req);
+
+ /* read to fill buffer and update availibility data */
+ result = read(zf->zf_rawfd, zf->zf_buf + zf->zf_zstream.avail_in, req);
+ zf->zf_zstream.next_in = zf->zf_buf;
+ if (result >= 0)
+ zf->zf_zstream.avail_in += result;
+ }
+ return(result);
+}
+
+/*
+ * Adapted from get_byte/check_header in libz
+ *
+ * Returns 0 if the header is OK, nonzero if not.
+ */
+static int
+get_byte(struct z_file *zf, off_t *curoffp)
+{
+ if ((zf->zf_zstream.avail_in == 0) && (zf_fill(zf) == -1))
+ return(-1);
+ zf->zf_zstream.avail_in--;
+ ++*curoffp;
+ return(*(zf->zf_zstream.next_in)++);
+}
+
+static int gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
+
+/* gzip flag byte */
+#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
+#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
+#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
+#define COMMENT 0x10 /* bit 4 set: file comment present */
+#define RESERVED 0xE0 /* bits 5..7: reserved */
+
+static int
+check_header(struct z_file *zf)
+{
+ int method; /* method byte */
+ int flags; /* flags byte */
+ uInt len;
+ int c;
+
+ zf->zf_dataoffset = 0;
+ /* Check the gzip magic header */
+ for (len = 0; len < 2; len++) {
+ c = get_byte(zf, &zf->zf_dataoffset);
+ if (c != gz_magic[len]) {
+ return(1);
+ }
+ }
+ method = get_byte(zf, &zf->zf_dataoffset);
+ flags = get_byte(zf, &zf->zf_dataoffset);
+ if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
+ return(1);
+ }
+
+ /* Discard time, xflags and OS code: */
+ for (len = 0; len < 6; len++) (void)get_byte(zf, &zf->zf_dataoffset);
+
+ if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
+ len = (uInt)get_byte(zf, &zf->zf_dataoffset);
+ len += ((uInt)get_byte(zf, &zf->zf_dataoffset))<<8;
+ /* len is garbage if EOF but the loop below will quit anyway */
+ while (len-- != 0 && get_byte(zf, &zf->zf_dataoffset) != -1) ;
+ }
+ if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
+ while ((c = get_byte(zf, &zf->zf_dataoffset)) != 0 && c != -1) ;
+ }
+ if ((flags & COMMENT) != 0) { /* skip the .gz file comment */
+ while ((c = get_byte(zf, &zf->zf_dataoffset)) != 0 && c != -1) ;
+ }
+ if ((flags & HEAD_CRC) != 0) { /* skip the header crc */
+ for (len = 0; len < 2; len++) c = get_byte(zf, &zf->zf_dataoffset);
+ }
+ /* if there's data left, we're in business */
+ return((c == -1) ? 1 : 0);
+}
+
+static int
+zf_open(const char *fname, struct open_file *f)
+{
+ static char *zfname;
+ int rawfd;
+ struct z_file *zf;
+ char *cp;
+ int error;
+ struct stat sb;
+
+ /* Have to be in "just read it" mode */
+ if (f->f_flags != F_READ)
+ return(EPERM);
+
+ /* If the name already ends in .gz or .bz2, ignore it */
+ if ((cp = strrchr(fname, '.')) && (!strcmp(cp, ".gz")
+ || !strcmp(cp, ".bz2") || !strcmp(cp, ".split")))
+ return(ENOENT);
+
+ /* Construct new name */
+ zfname = malloc(strlen(fname) + 4);
+ if (zfname == NULL)
+ return(ENOMEM);
+ sprintf(zfname, "%s.gz", fname);
+
+ /* Try to open the compressed datafile */
+ rawfd = open(zfname, O_RDONLY);
+ free(zfname);
+ if (rawfd == -1)
+ return(ENOENT);
+
+ if (fstat(rawfd, &sb) < 0) {
+ printf("zf_open: stat failed\n");
+ close(rawfd);
+ return(ENOENT);
+ }
+ if (!S_ISREG(sb.st_mode)) {
+ printf("zf_open: not a file\n");
+ close(rawfd);
+ return(EISDIR); /* best guess */
+ }
+
+ /* Allocate a z_file structure, populate it */
+ zf = malloc(sizeof(struct z_file));
+ if (zf == NULL)
+ return(ENOMEM);
+ bzero(zf, sizeof(struct z_file));
+ zf->zf_rawfd = rawfd;
+
+ /* Verify that the file is gzipped (XXX why do this afterwards?) */
+ if (check_header(zf)) {
+ close(zf->zf_rawfd);
+ inflateEnd(&(zf->zf_zstream));
+ free(zf);
+ return(EFTYPE);
+ }
+
+ /* Initialise the inflation engine */
+ if ((error = inflateInit2(&(zf->zf_zstream), -15)) != Z_OK) {
+ printf("zf_open: inflateInit returned %d : %s\n", error, zf->zf_zstream.msg);
+ close(zf->zf_rawfd);
+ free(zf);
+ return(EIO);
+ }
+
+ /* Looks OK, we'll take it */
+ f->f_fsdata = zf;
+ return(0);
+}
+
+static int
+zf_close(struct open_file *f)
+{
+ struct z_file *zf = (struct z_file *)f->f_fsdata;
+
+ inflateEnd(&(zf->zf_zstream));
+ close(zf->zf_rawfd);
+ free(zf);
+ return(0);
+}
+
+static int
+zf_read(struct open_file *f, void *buf, size_t size, size_t *resid)
+{
+ struct z_file *zf = (struct z_file *)f->f_fsdata;
+ int error;
+
+ zf->zf_zstream.next_out = buf; /* where and how much */
+ zf->zf_zstream.avail_out = size;
+
+ while (zf->zf_zstream.avail_out) {
+ if ((zf->zf_zstream.avail_in == 0) && (zf_fill(zf) == -1)) {
+ printf("zf_read: fill error\n");
+ return(EIO);
+ }
+ if (zf->zf_zstream.avail_in == 0) { /* oops, unexpected EOF */
+ printf("zf_read: unexpected EOF\n");
+ if (zf->zf_zstream.avail_out == size)
+ return (EIO);
+ break;
+ }
+
+ error = inflate(&zf->zf_zstream, Z_SYNC_FLUSH); /* decompression pass */
+ if (error == Z_STREAM_END) { /* EOF, all done */
+ break;
+ }
+ if (error != Z_OK) { /* argh, decompression error */
+ printf("inflate: %s\n", zf->zf_zstream.msg);
+ return(EIO);
+ }
+ }
+ if (resid != NULL)
+ *resid = zf->zf_zstream.avail_out;
+ return(0);
+}
+
+static int
+zf_rewind(struct open_file *f)
+{
+ struct z_file *zf = (struct z_file *)f->f_fsdata;
+
+ if (lseek(zf->zf_rawfd, zf->zf_dataoffset, SEEK_SET) == -1)
+ return -1;
+ zf->zf_zstream.avail_in = 0;
+ zf->zf_zstream.next_in = NULL;
+ (void)inflateReset(&zf->zf_zstream);
+
+ return 0;
+}
+
+static off_t
+zf_seek(struct open_file *f, off_t offset, int where)
+{
+ struct z_file *zf = (struct z_file *)f->f_fsdata;
+ off_t target;
+ char discard[16];
+
+ switch (where) {
+ case SEEK_SET:
+ target = offset;
+ break;
+ case SEEK_CUR:
+ target = offset + zf->zf_zstream.total_out;
+ break;
+ case SEEK_END:
+ target = -1;
+ default:
+ errno = EINVAL;
+ return (-1);
+ }
+
+ /* rewind if required */
+ if (target < zf->zf_zstream.total_out && zf_rewind(f) != 0)
+ return -1;
+
+ /* skip forwards if required */
+ while (target > zf->zf_zstream.total_out) {
+ errno = zf_read(f, discard, min(sizeof(discard),
+ target - zf->zf_zstream.total_out), NULL);
+ if (errno)
+ return(-1);
+ }
+ /* This is where we are (be honest if we overshot) */
+ return (zf->zf_zstream.total_out);
+}
+
+
+static int
+zf_stat(struct open_file *f, struct stat *sb)
+{
+ struct z_file *zf = (struct z_file *)f->f_fsdata;
+ int result;
+
+ /* stat as normal, but indicate that size is unknown */
+ if ((result = fstat(zf->zf_rawfd, sb)) == 0)
+ sb->st_size = -1;
+ return(result);
+}
+
+
+
diff --git a/lib/libstand/i386/_setjmp.S b/lib/libstand/i386/_setjmp.S
new file mode 100644
index 0000000..6fc8ac1
--- /dev/null
+++ b/lib/libstand/i386/_setjmp.S
@@ -0,0 +1,79 @@
+/*-
+ * 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. 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.
+ */
+
+#if defined(LIBC_RCS) && !defined(lint)
+ .text
+ .asciz "$FreeBSD$"
+#endif /* LIBC_RCS 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 environment 'a'.
+ * The previous signal state is NOT restored.
+ */
+
+#include <machine/asm.h>
+
+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)
+ xorl %eax,%eax
+ ret
+
+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
+ testl %eax,%eax
+ jnz 1f
+ incl %eax
+1: movl %ecx,0(%esp)
+ ret
diff --git a/lib/libstand/if_ether.h b/lib/libstand/if_ether.h
new file mode 100644
index 0000000..392ef7a
--- /dev/null
+++ b/lib/libstand/if_ether.h
@@ -0,0 +1,265 @@
+/* $NetBSD: if_ether.h,v 1.25 1997/01/17 17:06:06 mikel Exp $ */
+
+/*
+ * Copyright (c) 1982, 1986, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. 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.
+ *
+ * @(#)if_ether.h 8.1 (Berkeley) 6/10/93
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Ethernet address - 6 octets
+ * this is only used by the ethers(3) functions.
+ */
+struct ether_addr {
+ u_int8_t ether_addr_octet[6];
+};
+
+/*
+ * Structure of a 10Mb/s Ethernet header.
+ */
+#define ETHER_ADDR_LEN 6
+
+struct ether_header {
+ u_int8_t ether_dhost[ETHER_ADDR_LEN];
+ u_int8_t ether_shost[ETHER_ADDR_LEN];
+ u_int16_t ether_type;
+};
+
+#define ETHERTYPE_PUP 0x0200 /* PUP protocol */
+#define ETHERTYPE_IP 0x0800 /* IP protocol */
+#define ETHERTYPE_ARP 0x0806 /* address resolution protocol */
+#define ETHERTYPE_REVARP 0x8035 /* reverse addr resolution protocol */
+
+/*
+ * The ETHERTYPE_NTRAILER packet types starting at ETHERTYPE_TRAIL have
+ * (type-ETHERTYPE_TRAIL)*512 bytes of data followed
+ * by an ETHER type (as given above) and then the (variable-length) header.
+ */
+#define ETHERTYPE_TRAIL 0x1000 /* Trailer packet */
+#define ETHERTYPE_NTRAILER 16
+
+#define ETHER_IS_MULTICAST(addr) (*(addr) & 0x01) /* is address mcast/bcast? */
+
+#define ETHERMTU 1500
+#define ETHERMIN (60-14)
+
+#ifdef _KERNEL
+/*
+ * Macro to map an IP multicast address to an Ethernet multicast address.
+ * The high-order 25 bits of the Ethernet address are statically assigned,
+ * and the low-order 23 bits are taken from the low end of the IP address.
+ */
+#define ETHER_MAP_IP_MULTICAST(ipaddr, enaddr) \
+ /* struct in_addr *ipaddr; */ \
+ /* u_int8_t enaddr[ETHER_ADDR_LEN]; */ \
+{ \
+ (enaddr)[0] = 0x01; \
+ (enaddr)[1] = 0x00; \
+ (enaddr)[2] = 0x5e; \
+ (enaddr)[3] = ((u_int8_t *)ipaddr)[1] & 0x7f; \
+ (enaddr)[4] = ((u_int8_t *)ipaddr)[2]; \
+ (enaddr)[5] = ((u_int8_t *)ipaddr)[3]; \
+}
+#endif
+
+/*
+ * Ethernet Address Resolution Protocol.
+ *
+ * See RFC 826 for protocol description. Structure below is adapted
+ * to resolving internet addresses. Field names used correspond to
+ * RFC 826.
+ */
+struct ether_arp {
+ struct arphdr ea_hdr; /* fixed-size header */
+ u_int8_t arp_sha[ETHER_ADDR_LEN]; /* sender hardware address */
+ u_int8_t arp_spa[4]; /* sender protocol address */
+ u_int8_t arp_tha[ETHER_ADDR_LEN]; /* target hardware address */
+ u_int8_t arp_tpa[4]; /* target protocol address */
+};
+#define arp_hrd ea_hdr.ar_hrd
+#define arp_pro ea_hdr.ar_pro
+#define arp_hln ea_hdr.ar_hln
+#define arp_pln ea_hdr.ar_pln
+#define arp_op ea_hdr.ar_op
+
+/*
+ * Structure shared between the ethernet driver modules and
+ * the address resolution code. For example, each ec_softc or il_softc
+ * begins with this structure.
+ */
+struct arpcom {
+ struct ifnet ac_if; /* network-visible interface */
+ u_int8_t ac_enaddr[ETHER_ADDR_LEN]; /* ethernet hardware address */
+ char ac__pad[2]; /* be nice to m68k ports */
+ LIST_HEAD(, ether_multi) ac_multiaddrs; /* list of ether multicast addrs */
+ int ac_multicnt; /* length of ac_multiaddrs list */
+};
+
+struct llinfo_arp {
+ LIST_ENTRY(llinfo_arp) la_list;
+ struct rtentry *la_rt;
+ struct mbuf *la_hold; /* last packet until resolved/timeout */
+ long la_asked; /* last time we QUERIED for this addr */
+#define la_timer la_rt->rt_rmx.rmx_expire /* deletion time in seconds */
+};
+
+struct sockaddr_inarp {
+ u_int8_t sin_len;
+ u_int8_t sin_family;
+ u_int16_t sin_port;
+ struct in_addr sin_addr;
+ struct in_addr sin_srcaddr;
+ u_int16_t sin_tos;
+ u_int16_t sin_other;
+#define SIN_PROXY 1
+};
+
+/*
+ * IP and ethernet specific routing flags
+ */
+#define RTF_USETRAILERS RTF_PROTO1 /* use trailers */
+#define RTF_ANNOUNCE RTF_PROTO2 /* announce new arp entry */
+
+#ifdef _KERNEL
+u_int8_t etherbroadcastaddr[ETHER_ADDR_LEN];
+u_int8_t ether_ipmulticast_min[ETHER_ADDR_LEN];
+u_int8_t ether_ipmulticast_max[ETHER_ADDR_LEN];
+struct ifqueue arpintrq;
+
+void arpwhohas(struct arpcom *, struct in_addr *);
+void arpintr(void);
+int arpresolve(struct arpcom *,
+ struct rtentry *, struct mbuf *, struct sockaddr *, u_char *);
+void arp_ifinit(struct arpcom *, struct ifaddr *);
+void arp_rtrequest(int, struct rtentry *, struct sockaddr *);
+
+int ether_addmulti(struct ifreq *, struct arpcom *);
+int ether_delmulti(struct ifreq *, struct arpcom *);
+#endif /* _KERNEL */
+
+/*
+ * Ethernet multicast address structure. There is one of these for each
+ * multicast address or range of multicast addresses that we are supposed
+ * to listen to on a particular interface. They are kept in a linked list,
+ * rooted in the interface's arpcom structure. (This really has nothing to
+ * do with ARP, or with the Internet address family, but this appears to be
+ * the minimally-disrupting place to put it.)
+ */
+struct ether_multi {
+ u_int8_t enm_addrlo[ETHER_ADDR_LEN]; /* low or only address of range */
+ u_int8_t enm_addrhi[ETHER_ADDR_LEN]; /* high or only address of range */
+ struct arpcom *enm_ac; /* back pointer to arpcom */
+ u_int enm_refcount; /* no. claims to this addr/range */
+ LIST_ENTRY(ether_multi) enm_list;
+};
+
+/*
+ * Structure used by macros below to remember position when stepping through
+ * all of the ether_multi records.
+ */
+struct ether_multistep {
+ struct ether_multi *e_enm;
+};
+
+/*
+ * Macro for looking up the ether_multi record for a given range of Ethernet
+ * multicast addresses connected to a given arpcom structure. If no matching
+ * record is found, "enm" returns NULL.
+ */
+#define ETHER_LOOKUP_MULTI(addrlo, addrhi, ac, enm) \
+ /* u_int8_t addrlo[ETHER_ADDR_LEN]; */ \
+ /* u_int8_t addrhi[ETHER_ADDR_LEN]; */ \
+ /* struct arpcom *ac; */ \
+ /* struct ether_multi *enm; */ \
+{ \
+ for ((enm) = (ac)->ac_multiaddrs.lh_first; \
+ (enm) != NULL && \
+ (bcmp((enm)->enm_addrlo, (addrlo), ETHER_ADDR_LEN) != 0 || \
+ bcmp((enm)->enm_addrhi, (addrhi), ETHER_ADDR_LEN) != 0); \
+ (enm) = (enm)->enm_list.le_next); \
+}
+
+/*
+ * Macro to step through all of the ether_multi records, one at a time.
+ * The current position is remembered in "step", which the caller must
+ * provide. ETHER_FIRST_MULTI(), below, must be called to initialize "step"
+ * and get the first record. Both macros return a NULL "enm" when there
+ * are no remaining records.
+ */
+#define ETHER_NEXT_MULTI(step, enm) \
+ /* struct ether_multistep step; */ \
+ /* struct ether_multi *enm; */ \
+{ \
+ if (((enm) = (step).e_enm) != NULL) \
+ (step).e_enm = (enm)->enm_list.le_next; \
+}
+
+#define ETHER_FIRST_MULTI(step, ac, enm) \
+ /* struct ether_multistep step; */ \
+ /* struct arpcom *ac; */ \
+ /* struct ether_multi *enm; */ \
+{ \
+ (step).e_enm = (ac)->ac_multiaddrs.lh_first; \
+ ETHER_NEXT_MULTI((step), (enm)); \
+}
+
+#ifdef _KERNEL
+void arp_rtrequest(int, struct rtentry *, struct sockaddr *);
+int arpresolve(struct arpcom *, struct rtentry *, struct mbuf *,
+ struct sockaddr *, u_char *);
+void arpintr(void);
+int arpioctl(u_long, caddr_t);
+void arp_ifinit(struct arpcom *, struct ifaddr *);
+void revarpinput(struct mbuf *);
+void in_revarpinput(struct mbuf *);
+void revarprequest(struct ifnet *);
+int revarpwhoarewe(struct ifnet *, struct in_addr *, struct in_addr *);
+int revarpwhoami(struct in_addr *, struct ifnet *);
+int db_show_arptab(void);
+#endif
+
+/*
+ * Prototype ethers(3) functions.
+ */
+#ifndef _KERNEL
+#include <sys/cdefs.h>
+__BEGIN_DECLS
+char * ether_ntoa(struct ether_addr *);
+struct ether_addr *
+ ether_aton(char *);
+int ether_ntohost(char *, struct ether_addr *);
+int ether_hostton(char *, struct ether_addr *);
+int ether_line(char *, struct ether_addr *, char *);
+__END_DECLS
+#endif
diff --git a/lib/libstand/in_cksum.c b/lib/libstand/in_cksum.c
new file mode 100644
index 0000000..e253fad
--- /dev/null
+++ b/lib/libstand/in_cksum.c
@@ -0,0 +1,98 @@
+/* $NetBSD: in_cksum.c,v 1.6 2000/03/31 19:55:09 castor Exp $ */
+
+/*
+ * Copyright (c) 1992 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.
+ * 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, Lawrence Berkeley Laboratory 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.
+ *
+ * @(#) Header: in_cksum.c,v 1.1 92/09/11 01:15:55 leres Exp (LBL)
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <machine/endian.h>
+
+#include "stand.h"
+
+/*
+ * Checksum routine for Internet Protocol family headers.
+ * This routine is very heavily used in the network
+ * code and should be modified for each CPU to be as fast as possible.
+ * In particular, it should not be this one.
+ */
+int
+in_cksum(p, len)
+ void *p;
+ int len;
+{
+ int sum = 0, oddbyte = 0, v = 0;
+ u_char *cp = p;
+
+ /* we assume < 2^16 bytes being summed */
+ while (len > 0) {
+ if (oddbyte) {
+ sum += v + *cp++;
+ len--;
+ }
+ if (((long)cp & 1) == 0) {
+ while ((len -= 2) >= 0) {
+ sum += *(u_short *)cp;
+ cp += 2;
+ }
+ } else {
+ while ((len -= 2) >= 0) {
+#if BYTE_ORDER == BIG_ENDIAN
+ sum += *cp++ << 8;
+ sum += *cp++;
+#else
+ sum += *cp++;
+ sum += *cp++ << 8;
+#endif
+ }
+ }
+ if ((oddbyte = len & 1) != 0)
+#if BYTE_ORDER == BIG_ENDIAN
+ v = *cp << 8;
+#else
+ v = *cp;
+#endif
+ }
+ if (oddbyte)
+ sum += v;
+ sum = (sum >> 16) + (sum & 0xffff); /* add in accumulated carries */
+ sum += sum >> 16; /* add potential last carry */
+ return (0xffff & ~sum);
+}
diff --git a/lib/libstand/inet_ntoa.c b/lib/libstand/inet_ntoa.c
new file mode 100644
index 0000000..3bfe09e
--- /dev/null
+++ b/lib/libstand/inet_ntoa.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.
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)inet_ntoa.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include "stand.h"
+
+/*
+ * Convert network-format internet address
+ * to base 256 d.d.d.d representation.
+ */
+char *
+inet_ntoa(in)
+ struct in_addr in;
+{
+ static const char fmt[] = "%u.%u.%u.%u";
+ static char ret[sizeof "255.255.255.255"];
+ unsigned char *src = (unsigned char *) &in;
+
+ sprintf(ret, fmt, src[0], src[1], src[2], src[3]);
+ return (ret);
+}
+
+/*
+ * 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);
diff --git a/lib/libstand/ioctl.c b/lib/libstand/ioctl.c
new file mode 100644
index 0000000..debd9e4
--- /dev/null
+++ b/lib/libstand/ioctl.c
@@ -0,0 +1,92 @@
+/* $NetBSD: ioctl.c,v 1.4 1994/10/30 21:48:24 cgd Exp $ */
+
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * The Mach Operating System project at Carnegie-Mellon 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. 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.
+ *
+ * @(#)ioctl.c 8.1 (Berkeley) 6/11/93
+ *
+ *
+ * Copyright (c) 1989, 1990, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Author: Alessandro Forin
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "stand.h"
+
+int
+ioctl(fd, cmd, arg)
+ int fd;
+ u_long cmd;
+ char *arg;
+{
+ struct open_file *f = &files[fd];
+
+ if ((unsigned)fd >= SOPEN_MAX || f->f_flags == 0) {
+ errno = EBADF;
+ return (-1);
+ }
+ if (f->f_flags & F_RAW) {
+ errno = (f->f_dev->dv_ioctl)(f, cmd, arg);
+ if (errno)
+ return (-1);
+ return (0);
+ }
+ errno = EIO;
+ return (-1);
+}
diff --git a/lib/libstand/iodesc.h b/lib/libstand/iodesc.h
new file mode 100644
index 0000000..690c65b
--- /dev/null
+++ b/lib/libstand/iodesc.h
@@ -0,0 +1,54 @@
+/* $NetBSD: iodesc.h,v 1.4 1995/09/23 03:31:50 gwr Exp $ */
+
+/*
+ * Copyright (c) 1993 Adam Glass
+ * Copyright (c) 1992 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.
+ * 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, Lawrence Berkeley Laboratory 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.
+ */
+
+#ifndef __SYS_LIBNETBOOT_IODESC_H
+#define __SYS_LIBNETBOOT_IODESC_H
+
+struct iodesc {
+ struct in_addr destip; /* dest. ip addr, net order */
+ struct in_addr myip; /* local ip addr, net order */
+ u_short destport; /* dest. port, net order */
+ u_short myport; /* local port, net order */
+ u_long xid; /* transaction identification */
+ u_char myea[6]; /* my ethernet address */
+ struct netif *io_netif;
+};
+
+#endif /* __SYS_LIBNETBOOT_IODESC_H */
diff --git a/lib/libstand/libstand.3 b/lib/libstand/libstand.3
new file mode 100644
index 0000000..d1c544c
--- /dev/null
+++ b/lib/libstand/libstand.3
@@ -0,0 +1,680 @@
+.\" Copyright (c) Michael Smith
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING 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 6, 2004
+.Dt LIBSTAND 3
+.Os
+.Sh NAME
+.Nm libstand
+.Nd support library for standalone executables
+.Sh SYNOPSIS
+.In stand.h
+.Sh DESCRIPTION
+The
+.Nm
+library provides a set of supporting functions for standalone
+applications, mimicking where possible the standard
+.Bx
+programming
+environment.
+The following sections group these functions by kind.
+Unless specifically described here, see the corresponding section 3
+manpages for the given functions.
+.Sh STRING FUNCTIONS
+String functions are available as documented in
+.Xr string 3
+and
+.Xr bstring 3 .
+.Sh MEMORY ALLOCATION
+.Bl -hang -width 10n
+.It Xo
+.Ft "void *"
+.Fn malloc "size_t size"
+.Xc
+.Pp
+Allocate
+.Fa size
+bytes of memory from the heap using a best-fit algorithm.
+.It Xo
+.Ft void
+.Fn free "void *ptr"
+.Xc
+.Pp
+Free the allocated object at
+.Fa ptr .
+.It Xo
+.Ft void
+.Fn setheap "void *start" "void *limit"
+.Xc
+.Pp
+Initialise the heap.
+This function must be called before calling
+.Fn alloc
+for the first time.
+The region between
+.Fa start
+and
+.Fa limit
+will be used for the heap; attempting to allocate beyond this will result
+in a panic.
+.It Xo
+.Ft "char *"
+.Fn sbrk "int junk"
+.Xc
+.Pp
+Provides the behaviour of
+.Fn sbrk 0 ,
+i.e., returns the highest point that the heap has reached.
+This value can
+be used during testing to determine the actual heap usage.
+The
+.Fa junk
+argument is ignored.
+.El
+.Sh ENVIRONMENT
+A set of functions are provided for manipulating a flat variable space similar
+to the traditional shell-supported environment.
+Major enhancements are support
+for set/unset hook functions.
+.Bl -hang -width 10n
+.It Xo
+.Ft "char *"
+.Fn getenv "const char *name"
+.Xc
+.It Xo
+.Ft int
+.Fn setenv "const char *name" "const char *value" "int overwrite"
+.Xc
+.It Xo
+.Ft int
+.Fn putenv "const char *string"
+.Xc
+.It Xo
+.Ft int
+.Fn unsetenv "const char *name"
+.Xc
+.Pp
+These functions behave similarly to their standard library counterparts.
+.It Xo
+.Ft "struct env_var *"
+.Fn env_getenv "const char *name"
+.Xc
+.Pp
+Looks up a variable in the environment and returns its entire
+data structure.
+.It Xo
+.Ft int
+.Fn env_setenv "const char *name" "int flags" "const void *value" "ev_sethook_t sethook" "ev_unsethook_t unsethook"
+.Xc
+.Pp
+Creates a new or sets an existing environment variable called
+.Fa name .
+If creating a new variable, the
+.Fa sethook
+and
+.Fa unsethook
+arguments may be specified.
+.Pp
+The set hook is invoked whenever an attempt
+is made to set the variable, unless the EV_NOHOOK flag is set.
+Typically
+a set hook will validate the
+.Fa value
+argument, and then call
+.Fn env_setenv
+again with EV_NOHOOK set to actually save the value.
+The predefined function
+.Fn env_noset
+may be specified to refuse all attempts to set a variable.
+.Pp
+The unset hook is invoked when an attempt is made to unset a variable.
+If it
+returns zero, the variable will be unset.
+The predefined function
+.Fa env_nounset
+may be used to prevent a variable being unset.
+.El
+.Sh STANDARD LIBRARY SUPPORT
+.Bl -hang -width 10n
+.It Xo
+.Ft int
+.Fn getopt "int argc" "char * const *argv" "const char *optstring"
+.Xc
+.It Xo
+.Ft long
+.Fn strtol "const char *nptr" "char **endptr" "int base"
+.Xc
+.It Xo
+.Ft void
+.Fn srandom "unsigned long seed"
+.Xc
+.It Xo
+.Ft "unsigned long"
+.Fn random void
+.Xc
+.It Xo
+.Ft "char *"
+.Fn strerror "int error"
+.Xc
+.Pp
+Returns error messages for the subset of errno values supported by
+.Nm .
+.It Fn assert expression
+.Pp
+Requires
+.In assert.h .
+.It Xo
+.Ft int
+.Fn setjmp "jmp_buf env"
+.Xc
+.It Xo
+.Ft void
+.Fn longjmp "jmp_buf env" "int val"
+.Xc
+.Pp
+Defined as
+.Fn _setjmp
+and
+.Fn _longjmp
+respectively as there is no signal state to manipulate.
+Requires
+.In setjmp.h .
+.El
+.Sh CHARACTER I/O
+.Bl -hang -width 10n
+.It Xo
+.Ft void
+.Fn gets "char *buf"
+.Xc
+.Pp
+Read characters from the console into
+.Fa buf .
+All of the standard cautions apply to this function.
+.It Xo
+.Ft void
+.Fn ngets "char *buf" "int size"
+.Xc
+.Pp
+Read at most
+.Fa size
+- 1 characters from the console into
+.Fa buf .
+If
+.Fa size
+is less than 1, the function's behaviour is as for
+.Fn gets .
+.It Xo
+.Ft int
+.Fn fgetstr "char *buf" "int size" "int fd"
+.Xc
+.Pp
+Read a line of at most
+.Fa size
+characters into
+.Fa buf .
+Line terminating characters are stripped, and the buffer is always
+.Dv NUL
+terminated.
+Returns the number of characters in
+.Fa buf
+if successful, or -1 if a read error occurs.
+.It Xo
+.Ft int
+.Fn printf "const char *fmt" "..."
+.Xc
+.It Xo
+.Ft void
+.Fn vprintf "const char *fmt" "va_list ap"
+.Xc
+.It Xo
+.Ft int
+.Fn sprintf "char *buf" "const char *fmt" "..."
+.Xc
+.It Xo
+.Ft void
+.Fn vsprintf "char *buf" "const char *fmt" "va_list ap"
+.Xc
+.Pp
+The *printf functions implement a subset of the standard
+.Fn printf
+family functionality and some extensions.
+The following standard conversions
+are supported: c,d,n,o,p,s,u,x.
+The following modifiers are supported:
++,-,#,*,0,field width,precision,l.
+.Pp
+The
+.Li b
+conversion is provided to decode error registers.
+Its usage is:
+.Pp
+.Bd -ragged -offset indent
+printf(
+.Qq reg=%b\en ,
+regval,
+.Qq <base><arg>*
+);
+.Ed
+.Pp
+where <base> is the output expressed as a control character, e.g.\& \e10 gives
+octal, \e20 gives hex.
+Each <arg> is a sequence of characters, the first of
+which gives the bit number to be inspected (origin 1) and the next characters
+(up to a character less than 32) give the text to be displayed if the bit is set.
+Thus
+.Pp
+.Bd -ragged -offset indent
+printf(
+.Qq reg=%b\en ,
+3,
+.Qq \e10\e2BITTWO\e1BITONE\en
+);
+.Ed
+.Pp
+would give the output
+.Pp
+.Bd -ragged -offset indent
+reg=3<BITTWO,BITONE>
+.Ed
+.Pp
+The
+.Li D
+conversion provides a hexdump facility, e.g.
+.Pp
+.Bd -ragged -offset indent
+printf(
+.Qq %6D ,
+ptr,
+.Qq \&:
+); gives
+.Qq XX:XX:XX:XX:XX:XX
+.Ed
+.Bd -ragged -offset indent
+printf(
+.Qq %*D ,
+len,
+ptr,
+.Qq "\ "
+); gives
+.Qq XX XX XX ...
+.Ed
+.El
+.Sh CHARACTER TESTS AND CONVERSIONS
+.Bl -hang -width 10n
+.It Xo
+.Ft int
+.Fn isupper "int c"
+.Xc
+.It Xo
+.Ft int
+.Fn islower "int c"
+.Xc
+.It Xo
+.Ft int
+.Fn isspace "int c"
+.Xc
+.It Xo
+.Ft int
+.Fn isdigit "int c"
+.Xc
+.It Xo
+.Ft int
+.Fn isxdigit "int c"
+.Xc
+.It Xo
+.Ft int
+.Fn isascii "int c"
+.Xc
+.It Xo
+.Ft int
+.Fn isalpha "int c"
+.Xc
+.It Xo
+.Ft int
+.Fn toupper "int c"
+.Xc
+.It Xo
+.Ft int
+.Fn tolower "int c"
+.Xc
+.El
+.Sh FILE I/O
+.Bl -hang -width 10n
+.It Xo
+.Ft int
+.Fn open "const char *path" "int flags"
+.Xc
+.Pp
+Similar to the behaviour as specified in
+.Xr open 2 ,
+except that file creation is not supported, so the mode parameter is not
+required.
+The
+.Fa flags
+argument may be one of O_RDONLY, O_WRONLY and O_RDWR (although no file systems
+currently support writing).
+.It Xo
+.Ft int
+.Fn close "int fd"
+.Xc
+.It Xo
+.Ft void
+.Fn closeall void
+.Xc
+.Pp
+Close all open files.
+.It Xo
+.Ft ssize_t
+.Fn read "int fd" "void *buf" "size_t len"
+.Xc
+.It Xo
+.Ft ssize_t
+.Fn write "int fd" "void *buf" "size_t len"
+.Xc
+.Pp
+(No file systems currently support writing.)
+.It Xo
+.Ft off_t
+.Fn lseek "int fd" "off_t offset" "int whence"
+.Xc
+.Pp
+Files being automatically uncompressed during reading cannot seek backwards
+from the current point.
+.It Xo
+.Ft int
+.Fn stat "const char *path" "struct stat *sb"
+.Xc
+.It Xo
+.Ft int
+.Fn fstat "int fd" "struct stat *sb"
+.Xc
+.Pp
+The
+.Fn stat
+and
+.Fn fstat
+functions only fill out the following fields in the
+.Fa sb
+structure: st_mode,st_nlink,st_uid,st_gid,st_size.
+The
+.Nm tftp
+file system cannot provide meaningful values for this call, and the
+.Nm cd9660
+file system always reports files having uid/gid of zero.
+.El
+.Sh PAGER
+The
+.Nm
+library supplies a simple internal pager to ease reading the output of large
+commands.
+.Bl -hang -width 10n
+.It Xo
+.Ft void
+.Fn pager_open
+.Xc
+.Pp
+Initialises the pager and tells it that the next line output will be the top of the
+display.
+The environment variable LINES is consulted to determine the number of
+lines to be displayed before pausing.
+.It Xo
+.Ft void
+.Fn pager_close void
+.Xc
+.Pp
+Closes the pager.
+.It Xo
+.Ft int
+.Fn pager_output "const char *lines"
+.Xc
+.Pp
+Sends the lines in the
+.Dv NUL Ns
+-terminated buffer at
+.Fa lines
+to the pager.
+Newline characters are counted in order to determine the number
+of lines being output (wrapped lines are not accounted for).
+The
+.Fn pager_output
+function will return zero when all of the lines have been output, or nonzero
+if the display was paused and the user elected to quit.
+.It Xo
+.Ft int
+.Fn pager_file "const char *fname"
+.Xc
+.Pp
+Attempts to open and display the file
+.Fa fname .
+Returns -1 on error, 0 at EOF, or 1 if the user elects to quit while reading.
+.El
+.Sh MISC
+.Bl -hang -width 10n
+.It Xo
+.Ft void
+.Fn twiddle void
+.Xc
+.Pp
+Successive calls emit the characters in the sequence |,/,-,\\ followed by a
+backspace in order to provide reassurance to the user.
+.El
+.Sh REQUIRED LOW-LEVEL SUPPORT
+The following resources are consumed by
+.Nm
+- stack, heap, console and devices.
+.Pp
+The stack must be established before
+.Nm
+functions can be invoked.
+Stack requirements vary depending on the functions
+and file systems used by the consumer and the support layer functions detailed
+below.
+.Pp
+The heap must be established before calling
+.Fn alloc
+or
+.Fn open
+by calling
+.Fn setheap .
+Heap usage will vary depending on the number of simultaneously open files,
+as well as client behaviour.
+Automatic decompression will allocate more
+than 64K of data per open file.
+.Pp
+Console access is performed via the
+.Fn getchar ,
+.Fn putchar
+and
+.Fn ischar
+functions detailed below.
+.Pp
+Device access is initiated via
+.Fn devopen
+and is performed through the
+.Fn dv_strategy ,
+.Fn dv_ioctl
+and
+.Fn dv_close
+functions in the device switch structure that
+.Fn devopen
+returns.
+.Pp
+The consumer must provide the following support functions:
+.Bl -hang -width 10n
+.It Xo
+.Ft int
+.Fn getchar void
+.Xc
+.Pp
+Return a character from the console, used by
+.Fn gets ,
+.Fn ngets
+and pager functions.
+.It Xo
+.Ft int
+.Fn ischar void
+.Xc
+.Pp
+Returns nonzero if a character is waiting from the console.
+.It Xo
+.Ft void
+.Fn putchar int
+.Xc
+.Pp
+Write a character to the console, used by
+.Fn gets ,
+.Fn ngets ,
+.Fn *printf ,
+.Fn panic
+and
+.Fn twiddle
+and thus by many other functions for debugging and informational output.
+.It Xo
+.Ft int
+.Fn devopen "struct open_file *of" "const char *name" "const char **file"
+.Xc
+.Pp
+Open the appropriate device for the file named in
+.Fa name ,
+returning in
+.Fa file
+a pointer to the remaining body of
+.Fa name
+which does not refer to the device.
+The
+.Va f_dev
+field in
+.Fa of
+will be set to point to the
+.Vt devsw
+structure for the opened device if successful.
+Device identifiers must
+always precede the path component, but may otherwise be arbitrarily formatted.
+Used by
+.Fn open
+and thus for all device-related I/O.
+.It Xo
+.Ft int
+.Fn devclose "struct open_file *of"
+.Xc
+.Pp
+Close the device allocated for
+.Fa of .
+The device driver itself will already have been called for the close; this call
+should clean up any allocation made by devopen only.
+.It Xo
+.Ft void
+.Fn panic "const char *msg" "..."
+.Xc
+.Pp
+Signal a fatal and unrecoverable error condition.
+The
+.Fa msg ...
+arguments are as for
+.Fn printf .
+.El
+.Sh INTERNAL FILE SYSTEMS
+Internal file systems are enabled by the consumer exporting the array
+.Vt struct fs_ops *file_system[] ,
+which should be initialised with pointers
+to
+.Vt struct fs_ops
+structures.
+The following file system handlers are supplied by
+.Nm ,
+the consumer may supply other file systems of their own:
+.Bl -hang -width ".Va cd9660_fsops"
+.It Va ufs_fsops
+The
+.Bx
+UFS.
+.It Va ext2fs_fsops
+Linux ext2fs file system.
+.It Va tftp_fsops
+File access via TFTP.
+.It Va nfs_fsops
+File access via NFS.
+.It Va cd9660_fsops
+ISO 9660 (CD-ROM) file system.
+.It Va gzipfs_fsops
+Stacked file system supporting gzipped files.
+When trying the gzipfs file system,
+.Nm
+appends
+.Li .gz
+to the end of the filename, and then tries to locate the file using the other
+file systems.
+Placement of this file system in the
+.Va file_system[]
+array determines whether gzipped files will be opened in preference to non-gzipped
+files.
+It is only possible to seek a gzipped file forwards, and
+.Fn stat
+and
+.Fn fstat
+on gzipped files will report an invalid length.
+.It Va bzipfs_fsops
+The same as
+.Va gzipfs_fsops ,
+but for
+.Xr bzip2 1 Ns -compressed
+files.
+.El
+.Pp
+The array of
+.Vt struct fs_ops
+pointers should be terminated with a NULL.
+.Sh DEVICES
+Devices are exported by the supporting code via the array
+.Vt struct devsw *devsw[]
+which is a NULL terminated array of pointers to device switch structures.
+.Sh HISTORY
+The
+.Nm
+library contains contributions from many sources, including:
+.Bl -bullet -compact
+.It
+.Nm libsa
+from
+.Nx
+.It
+.Nm libc
+and
+.Nm libkern
+from
+.Fx 3.0 .
+.It
+.Nm zalloc
+from
+.An Matthew Dillon Aq dillon@backplane.com
+.El
+.Pp
+The reorganisation and port to
+.Fx 3.0 ,
+the environment functions and this manpage were written by
+.An Mike Smith Aq msmith@FreeBSD.org .
+.Sh BUGS
+The lack of detailed memory usage data is unhelpful.
diff --git a/lib/libstand/lseek.c b/lib/libstand/lseek.c
new file mode 100644
index 0000000..6880ef9
--- /dev/null
+++ b/lib/libstand/lseek.c
@@ -0,0 +1,146 @@
+/* $NetBSD: lseek.c,v 1.4 1997/01/22 00:38:10 cgd Exp $ */
+
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * The Mach Operating System project at Carnegie-Mellon 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. 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.
+ *
+ * @(#)lseek.c 8.1 (Berkeley) 6/11/93
+ *
+ *
+ * Copyright (c) 1989, 1990, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Author: Alessandro Forin
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "stand.h"
+
+off_t
+lseek(int fd, off_t offset, int where)
+{
+ off_t bufpos, filepos, target;
+ struct open_file *f = &files[fd];
+
+ if ((unsigned)fd >= SOPEN_MAX || f->f_flags == 0) {
+ errno = EBADF;
+ return (-1);
+ }
+
+ if (f->f_flags & F_RAW) {
+ /*
+ * On RAW devices, update internal offset.
+ */
+ switch (where) {
+ case SEEK_SET:
+ f->f_offset = offset;
+ break;
+ case SEEK_CUR:
+ f->f_offset += offset;
+ break;
+ case SEEK_END:
+ default:
+ errno = EOFFSET;
+ return (-1);
+ }
+ return (f->f_offset);
+ }
+
+ /*
+ * If there is some unconsumed data in the readahead buffer and it
+ * contains the desired offset, simply adjust the buffer offset and
+ * length. We don't bother with SEEK_END here, since the code to
+ * handle it would fail in the same cases where the non-readahead
+ * code fails (namely, for streams which cannot seek backward and whose
+ * size isn't known in advance).
+ */
+ if (f->f_ralen != 0 && where != SEEK_END) {
+ if ((filepos = (f->f_ops->fo_seek)(f, (off_t)0, SEEK_CUR)) == -1)
+ return (-1);
+ bufpos = filepos - f->f_ralen;
+ switch (where) {
+ case SEEK_SET:
+ target = offset;
+ break;
+ case SEEK_CUR:
+ target = bufpos + offset;
+ break;
+ default:
+ errno = EINVAL;
+ return (-1);
+ }
+ if (bufpos <= target && target < filepos) {
+ f->f_raoffset += target - bufpos;
+ f->f_ralen -= target - bufpos;
+ return (target);
+ }
+ }
+
+ /*
+ * If this is a relative seek, we need to correct the offset for
+ * bytes that we have already read but the caller doesn't know
+ * about.
+ */
+ if (where == SEEK_CUR)
+ offset -= f->f_ralen;
+
+ /*
+ * Invalidate the readahead buffer.
+ */
+ f->f_ralen = 0;
+
+ return (f->f_ops->fo_seek)(f, offset, where);
+}
diff --git a/lib/libstand/net.c b/lib/libstand/net.c
new file mode 100644
index 0000000..77cf891
--- /dev/null
+++ b/lib/libstand/net.c
@@ -0,0 +1,293 @@
+/* $NetBSD: net.c,v 1.20 1997/12/26 22:41:30 scottr Exp $ */
+
+/*
+ * Copyright (c) 1992 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.
+ * 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, Lawrence Berkeley Laboratory 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.
+ *
+ * @(#) Header: net.c,v 1.9 93/08/06 19:32:15 leres Exp (LBL)
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <string.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <netinet/in_systm.h>
+
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+
+#include "stand.h"
+#include "net.h"
+
+/*
+ * Send a packet and wait for a reply, with exponential backoff.
+ *
+ * The send routine must return the actual number of bytes written,
+ * or -1 on error.
+ *
+ * The receive routine can indicate success by returning the number of
+ * bytes read; it can return 0 to indicate EOF; it can return -1 with a
+ * non-zero errno to indicate failure; finally, it can return -1 with a
+ * zero errno to indicate it isn't done yet.
+ */
+ssize_t
+sendrecv(d, sproc, sbuf, ssize, rproc, rbuf, rsize)
+ struct iodesc *d;
+ ssize_t (*sproc)(struct iodesc *, void *, size_t);
+ void *sbuf;
+ size_t ssize;
+ ssize_t (*rproc)(struct iodesc *, void *, size_t, time_t);
+ void *rbuf;
+ size_t rsize;
+{
+ ssize_t cc;
+ time_t t, tmo, tlast;
+ long tleft;
+
+#ifdef NET_DEBUG
+ if (debug)
+ printf("sendrecv: called\n");
+#endif
+
+ tmo = MINTMO;
+ tlast = tleft = 0;
+ t = getsecs();
+ for (;;) {
+ if (tleft <= 0) {
+ if (tmo >= MAXTMO) {
+ errno = ETIMEDOUT;
+ return -1;
+ }
+ cc = (*sproc)(d, sbuf, ssize);
+ if (cc != -1 && cc < ssize)
+ panic("sendrecv: short write! (%zd < %zd)",
+ cc, ssize);
+
+ tleft = tmo;
+ tmo <<= 1;
+ if (tmo > MAXTMO)
+ tmo = MAXTMO;
+
+ if (cc == -1) {
+ /* Error on transmit; wait before retrying */
+ while ((getsecs() - t) < tmo);
+ tleft = 0;
+ continue;
+ }
+
+ tlast = t;
+ }
+
+ /* Try to get a packet and process it. */
+ cc = (*rproc)(d, rbuf, rsize, tleft);
+ /* Return on data, EOF or real error. */
+ if (cc != -1 || errno != 0)
+ return (cc);
+
+ /* Timed out or didn't get the packet we're waiting for */
+ t = getsecs();
+ tleft -= t - tlast;
+ tlast = t;
+ }
+}
+
+/*
+ * Like inet_addr() in the C library, but we only accept base-10.
+ * Return values are in network order.
+ */
+n_long
+inet_addr(cp)
+ char *cp;
+{
+ u_long val;
+ int n;
+ char c;
+ u_int parts[4];
+ u_int *pp = parts;
+
+ for (;;) {
+ /*
+ * Collect number up to ``.''.
+ * Values are specified as for C:
+ * 0x=hex, 0=octal, other=decimal.
+ */
+ val = 0;
+ while ((c = *cp) != '\0') {
+ if (c >= '0' && c <= '9') {
+ val = (val * 10) + (c - '0');
+ cp++;
+ continue;
+ }
+ break;
+ }
+ if (*cp == '.') {
+ /*
+ * 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 > 0xff)
+ goto bad;
+ *pp++ = val, cp++;
+ } else
+ break;
+ }
+ /*
+ * Check for trailing characters.
+ */
+ if (*cp != '\0')
+ goto bad;
+
+ /*
+ * 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 > 0xffffff)
+ goto bad;
+ val |= parts[0] << 24;
+ break;
+
+ case 3: /* a.b.c -- 8.8.16 bits */
+ if (val > 0xffff)
+ goto bad;
+ val |= (parts[0] << 24) | (parts[1] << 16);
+ break;
+
+ case 4: /* a.b.c.d -- 8.8.8.8 bits */
+ if (val > 0xff)
+ goto bad;
+ val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
+ break;
+ }
+
+ return (htonl(val));
+ bad:
+ return (htonl(INADDR_NONE));
+}
+
+char *
+inet_ntoa(ia)
+ struct in_addr ia;
+{
+ return (intoa(ia.s_addr));
+}
+
+/* Similar to inet_ntoa() */
+char *
+intoa(addr)
+ n_long addr;
+{
+ char *cp;
+ u_int byte;
+ int n;
+ static char buf[17]; /* strlen(".255.255.255.255") + 1 */
+
+ addr = ntohl(addr);
+ cp = &buf[sizeof buf];
+ *--cp = '\0';
+
+ n = 4;
+ do {
+ byte = addr & 0xff;
+ *--cp = byte % 10 + '0';
+ byte /= 10;
+ if (byte > 0) {
+ *--cp = byte % 10 + '0';
+ byte /= 10;
+ if (byte > 0)
+ *--cp = byte + '0';
+ }
+ *--cp = '.';
+ addr >>= 8;
+ } while (--n > 0);
+
+ return (cp+1);
+}
+
+static char *
+number(s, n)
+ char *s;
+ int *n;
+{
+ for (*n = 0; isdigit(*s); s++)
+ *n = (*n * 10) + *s - '0';
+ return s;
+}
+
+n_long
+ip_convertaddr(p)
+ char *p;
+{
+#define IP_ANYADDR 0
+ n_long addr = 0, n;
+
+ if (p == (char *)0 || *p == '\0')
+ return IP_ANYADDR;
+ p = number(p, &n);
+ addr |= (n << 24) & 0xff000000;
+ if (*p == '\0' || *p++ != '.')
+ return IP_ANYADDR;
+ p = number(p, &n);
+ addr |= (n << 16) & 0xff0000;
+ if (*p == '\0' || *p++ != '.')
+ return IP_ANYADDR;
+ p = number(p, &n);
+ addr |= (n << 8) & 0xff00;
+ if (*p == '\0' || *p++ != '.')
+ return IP_ANYADDR;
+ p = number(p, &n);
+ addr |= n & 0xff;
+ if (*p != '\0')
+ return IP_ANYADDR;
+
+ return htonl(addr);
+}
diff --git a/lib/libstand/net.h b/lib/libstand/net.h
new file mode 100644
index 0000000..dcd574f
--- /dev/null
+++ b/lib/libstand/net.h
@@ -0,0 +1,125 @@
+/* $NetBSD: net.h,v 1.10 1995/10/20 00:46:30 cgd Exp $ */
+
+/*
+ * Copyright (c) 1993 Adam Glass
+ * Copyright (c) 1992 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.
+ * 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, Lawrence Berkeley Laboratory 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _KERNEL /* XXX - see <netinet/in.h> */
+#undef __IPADDR
+#define __IPADDR(x) htonl((u_int32_t)(x))
+#endif
+
+#include "iodesc.h"
+
+#define BA { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }
+
+/* Returns true if n_long's on the same net */
+#define SAMENET(a1, a2, m) ((a1.s_addr & m) == (a2.s_addr & m))
+
+#define MACPY(s, d) bcopy((char *)s, (char *)d, 6)
+
+#define MAXTMO 20 /* seconds */
+#define MINTMO 2 /* seconds */
+
+#define FNAME_SIZE 128
+#define IFNAME_SIZE 16
+#define RECV_SIZE 1536 /* XXX delete this */
+
+/*
+ * How much room to leave for headers:
+ * 14: struct ether_header
+ * 20: struct ip
+ * 8: struct udphdr
+ * That's 42 but let's pad it out to 48 bytes.
+ */
+#define ETHER_SIZE 14
+#define HEADER_SIZE 48
+
+extern u_char bcea[6];
+extern char rootpath[FNAME_SIZE];
+extern char bootfile[FNAME_SIZE];
+extern char hostname[FNAME_SIZE];
+extern int hostnamelen;
+extern char domainname[FNAME_SIZE];
+extern int domainnamelen;
+extern char ifname[IFNAME_SIZE];
+
+/* All of these are in network order. */
+extern struct in_addr myip;
+extern struct in_addr rootip;
+extern struct in_addr swapip;
+extern struct in_addr gateip;
+extern struct in_addr nameip;
+extern n_long netmask;
+
+extern int debug; /* defined in the machdep sources */
+
+extern struct iodesc sockets[SOPEN_MAX];
+
+/* ARP/RevARP functions: */
+u_char *arpwhohas(struct iodesc *, struct in_addr);
+void arp_reply(struct iodesc *, void *);
+int rarp_getipaddress(int);
+
+/* Link functions: */
+ssize_t sendether(struct iodesc *d, void *pkt, size_t len,
+ u_char *dea, int etype);
+ssize_t readether(struct iodesc *d, void *pkt, size_t len,
+ time_t tleft, u_int16_t *etype);
+
+ssize_t sendudp(struct iodesc *, void *, size_t);
+ssize_t readudp(struct iodesc *, void *, size_t, time_t);
+ssize_t sendrecv(struct iodesc *,
+ ssize_t (*)(struct iodesc *, void *, size_t),
+ void *, size_t,
+ ssize_t (*)(struct iodesc *, void *, size_t, time_t),
+ void *, size_t);
+
+/* bootp/DHCP */
+void bootp(int, int);
+
+/* Utilities: */
+char *ether_sprintf(u_char *);
+int in_cksum(void *, int);
+char *inet_ntoa(struct in_addr);
+char *intoa(n_long); /* similar to inet_ntoa */
+n_long inet_addr(char *);
+
+/* Machine-dependent functions: */
+time_t getsecs(void);
diff --git a/lib/libstand/netif.c b/lib/libstand/netif.c
new file mode 100644
index 0000000..c260690
--- /dev/null
+++ b/lib/libstand/netif.c
@@ -0,0 +1,335 @@
+/* $NetBSD: netif.c,v 1.10 1997/09/06 13:57:14 drochner Exp $ */
+
+/*
+ * Copyright (c) 1993 Adam Glass
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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 Adam Glass.
+ * 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 Adam Glass ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 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/types.h>
+#include <sys/cdefs.h>
+#include <sys/mount.h>
+#include <string.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+
+#include "stand.h"
+#include "net.h"
+#include "netif.h"
+
+struct iodesc sockets[SOPEN_MAX];
+#ifdef NETIF_DEBUG
+int netif_debug = 0;
+#endif
+
+/*
+ * netif_init:
+ *
+ * initialize the generic network interface layer
+ */
+
+void
+netif_init()
+{
+ struct netif_driver *drv;
+ int d, i;
+
+#ifdef NETIF_DEBUG
+ if (netif_debug)
+ printf("netif_init: called\n");
+#endif
+ for (d = 0; netif_drivers[d]; d++) {
+ drv = netif_drivers[d];
+ for (i = 0; i < drv->netif_nifs; i++)
+ drv->netif_ifs[i].dif_used = 0;
+ }
+}
+
+int
+netif_match(nif, machdep_hint)
+ struct netif *nif;
+ void *machdep_hint;
+{
+ struct netif_driver *drv = nif->nif_driver;
+
+#if 0
+ if (netif_debug)
+ printf("%s%d: netif_match (%d)\n", drv->netif_bname,
+ nif->nif_unit, nif->nif_sel);
+#endif
+ return drv->netif_match(nif, machdep_hint);
+}
+
+struct netif *
+netif_select(machdep_hint)
+ void *machdep_hint;
+{
+ int d, u, unit_done, s;
+ struct netif_driver *drv;
+ struct netif cur_if;
+ static struct netif best_if;
+ int best_val;
+ int val;
+
+ best_val = 0;
+ best_if.nif_driver = NULL;
+
+ for (d = 0; netif_drivers[d] != NULL; d++) {
+ cur_if.nif_driver = netif_drivers[d];
+ drv = cur_if.nif_driver;
+
+ for (u = 0; u < drv->netif_nifs; u++) {
+ cur_if.nif_unit = u;
+ unit_done = 0;
+
+#ifdef NETIF_DEBUG
+ if (netif_debug)
+ printf("\t%s%d:", drv->netif_bname,
+ cur_if.nif_unit);
+#endif
+
+ for (s = 0; s < drv->netif_ifs[u].dif_nsel; s++) {
+ cur_if.nif_sel = s;
+
+ if (drv->netif_ifs[u].dif_used & (1 << s)) {
+#ifdef NETIF_DEBUG
+ if (netif_debug)
+ printf(" [%d used]", s);
+#endif
+ continue;
+ }
+
+ val = netif_match(&cur_if, machdep_hint);
+#ifdef NETIF_DEBUG
+ if (netif_debug)
+ printf(" [%d -> %d]", s, val);
+#endif
+ if (val > best_val) {
+ best_val = val;
+ best_if = cur_if;
+ }
+ }
+#ifdef NETIF_DEBUG
+ if (netif_debug)
+ printf("\n");
+#endif
+ }
+ }
+
+ if (best_if.nif_driver == NULL)
+ return NULL;
+
+ best_if.nif_driver->
+ netif_ifs[best_if.nif_unit].dif_used |= (1 << best_if.nif_sel);
+
+#ifdef NETIF_DEBUG
+ if (netif_debug)
+ printf("netif_select: %s%d(%d) wins\n",
+ best_if.nif_driver->netif_bname,
+ best_if.nif_unit, best_if.nif_sel);
+#endif
+ return &best_if;
+}
+
+int
+netif_probe(nif, machdep_hint)
+ struct netif *nif;
+ void *machdep_hint;
+{
+ struct netif_driver *drv = nif->nif_driver;
+
+#ifdef NETIF_DEBUG
+ if (netif_debug)
+ printf("%s%d: netif_probe\n", drv->netif_bname, nif->nif_unit);
+#endif
+ return drv->netif_probe(nif, machdep_hint);
+}
+
+void
+netif_attach(nif, desc, machdep_hint)
+ struct netif *nif;
+ struct iodesc *desc;
+ void *machdep_hint;
+{
+ struct netif_driver *drv = nif->nif_driver;
+
+#ifdef NETIF_DEBUG
+ if (netif_debug)
+ printf("%s%d: netif_attach\n", drv->netif_bname, nif->nif_unit);
+#endif
+ desc->io_netif = nif;
+#ifdef PARANOID
+ if (drv->netif_init == NULL)
+ panic("%s%d: no netif_init support\n", drv->netif_bname,
+ nif->nif_unit);
+#endif
+ drv->netif_init(desc, machdep_hint);
+ bzero(drv->netif_ifs[nif->nif_unit].dif_stats,
+ sizeof(struct netif_stats));
+}
+
+void
+netif_detach(nif)
+ struct netif *nif;
+{
+ struct netif_driver *drv = nif->nif_driver;
+
+#ifdef NETIF_DEBUG
+ if (netif_debug)
+ printf("%s%d: netif_detach\n", drv->netif_bname, nif->nif_unit);
+#endif
+#ifdef PARANOID
+ if (drv->netif_end == NULL)
+ panic("%s%d: no netif_end support\n", drv->netif_bname,
+ nif->nif_unit);
+#endif
+ drv->netif_end(nif);
+}
+
+ssize_t
+netif_get(desc, pkt, len, timo)
+ struct iodesc *desc;
+ void *pkt;
+ size_t len;
+ time_t timo;
+{
+#ifdef NETIF_DEBUG
+ struct netif *nif = desc->io_netif;
+#endif
+ struct netif_driver *drv = desc->io_netif->nif_driver;
+ ssize_t rv;
+
+#ifdef NETIF_DEBUG
+ if (netif_debug)
+ printf("%s%d: netif_get\n", drv->netif_bname, nif->nif_unit);
+#endif
+#ifdef PARANOID
+ if (drv->netif_get == NULL)
+ panic("%s%d: no netif_get support\n", drv->netif_bname,
+ nif->nif_unit);
+#endif
+ rv = drv->netif_get(desc, pkt, len, timo);
+#ifdef NETIF_DEBUG
+ if (netif_debug)
+ printf("%s%d: netif_get returning %d\n", drv->netif_bname,
+ nif->nif_unit, (int)rv);
+#endif
+ return rv;
+}
+
+ssize_t
+netif_put(desc, pkt, len)
+ struct iodesc *desc;
+ void *pkt;
+ size_t len;
+{
+#ifdef NETIF_DEBUG
+ struct netif *nif = desc->io_netif;
+#endif
+ struct netif_driver *drv = desc->io_netif->nif_driver;
+ ssize_t rv;
+
+#ifdef NETIF_DEBUG
+ if (netif_debug)
+ printf("%s%d: netif_put\n", drv->netif_bname, nif->nif_unit);
+#endif
+#ifdef PARANOID
+ if (drv->netif_put == NULL)
+ panic("%s%d: no netif_put support\n", drv->netif_bname,
+ nif->nif_unit);
+#endif
+ rv = drv->netif_put(desc, pkt, len);
+#ifdef NETIF_DEBUG
+ if (netif_debug)
+ printf("%s%d: netif_put returning %d\n", drv->netif_bname,
+ nif->nif_unit, (int)rv);
+#endif
+ return rv;
+}
+
+struct iodesc *
+socktodesc(sock)
+ int sock;
+{
+ if (sock >= SOPEN_MAX) {
+ errno = EBADF;
+ return (NULL);
+ }
+ return (&sockets[sock]);
+}
+
+int
+netif_open(machdep_hint)
+ void *machdep_hint;
+{
+ int fd;
+ struct iodesc *s;
+ struct netif *nif;
+
+ /* find a free socket */
+ for (fd = 0, s = sockets; fd < SOPEN_MAX; fd++, s++)
+ if (s->io_netif == (struct netif *)0)
+ goto fnd;
+ errno = EMFILE;
+ return (-1);
+
+fnd:
+ bzero(s, sizeof(*s));
+ netif_init();
+ nif = netif_select(machdep_hint);
+ if (!nif)
+ panic("netboot: no interfaces left untried");
+ if (netif_probe(nif, machdep_hint)) {
+ printf("netboot: couldn't probe %s%d\n",
+ nif->nif_driver->netif_bname, nif->nif_unit);
+ errno = EINVAL;
+ return(-1);
+ }
+ netif_attach(nif, s, machdep_hint);
+
+ return(fd);
+}
+
+int
+netif_close(sock)
+ int sock;
+{
+ if (sock >= SOPEN_MAX) {
+ errno = EBADF;
+ return(-1);
+ }
+ netif_detach(sockets[sock].io_netif);
+ sockets[sock].io_netif = (struct netif *)0;
+
+ return(0);
+}
diff --git a/lib/libstand/netif.h b/lib/libstand/netif.h
new file mode 100644
index 0000000..dac2851
--- /dev/null
+++ b/lib/libstand/netif.h
@@ -0,0 +1,67 @@
+/* $NetBSD: netif.h,v 1.4 1995/09/14 23:45:30 pk Exp $ */
+
+/* $FreeBSD$ */
+
+#ifndef __SYS_LIBNETBOOT_NETIF_H
+#define __SYS_LIBNETBOOT_NETIF_H
+#include "iodesc.h"
+
+#define NENTS(x) sizeof(x)/sizeof(x[0])
+
+struct netif_driver {
+ const char *netif_bname;
+ int (*netif_match)(struct netif *, void *);
+ int (*netif_probe)(struct netif *, void *);
+ void (*netif_init)(struct iodesc *, void *);
+ int (*netif_get)(struct iodesc *, void *, size_t, time_t);
+ int (*netif_put)(struct iodesc *, void *, size_t);
+ void (*netif_end)(struct netif *);
+ struct netif_dif *netif_ifs;
+ int netif_nifs;
+};
+
+struct netif_dif {
+ int dif_unit;
+ int dif_nsel;
+ struct netif_stats *dif_stats;
+ void *dif_private;
+ /* the following fields are used internally by the netif layer */
+ u_long dif_used;
+};
+
+struct netif_stats {
+ int collisions;
+ int collision_error;
+ int missed;
+ int sent;
+ int received;
+ int deferred;
+ int overflow;
+};
+
+struct netif {
+ struct netif_driver *nif_driver;
+ int nif_unit;
+ int nif_sel;
+ void *nif_devdata;
+};
+
+extern struct netif_driver *netif_drivers[]; /* machdep */
+extern int n_netif_drivers;
+
+extern int netif_debug;
+
+void netif_init(void);
+struct netif *netif_select(void *);
+int netif_probe(struct netif *, void *);
+void netif_attach(struct netif *, struct iodesc *, void *);
+void netif_detach(struct netif *);
+ssize_t netif_get(struct iodesc *, void *, size_t, time_t);
+ssize_t netif_put(struct iodesc *, void *, size_t);
+
+int netif_open(void *);
+int netif_close(int);
+
+struct iodesc *socktodesc(int);
+
+#endif /* __SYS_LIBNETBOOT_NETIF_H */
diff --git a/lib/libstand/nfs.c b/lib/libstand/nfs.c
new file mode 100644
index 0000000..1c439a8
--- /dev/null
+++ b/lib/libstand/nfs.c
@@ -0,0 +1,768 @@
+/* $NetBSD: nfs.c,v 1.2 1998/01/24 12:43:09 drochner Exp $ */
+
+/*-
+ * 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/param.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <string.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+
+#include "rpcv2.h"
+#include "nfsv2.h"
+
+#include "stand.h"
+#include "net.h"
+#include "netif.h"
+#include "rpc.h"
+
+#define NFS_DEBUGxx
+
+/* Define our own NFS attributes without NQNFS stuff. */
+struct nfsv2_fattrs {
+ n_long fa_type;
+ n_long fa_mode;
+ n_long fa_nlink;
+ n_long fa_uid;
+ n_long fa_gid;
+ n_long fa_size;
+ n_long fa_blocksize;
+ n_long fa_rdev;
+ n_long fa_blocks;
+ n_long fa_fsid;
+ n_long fa_fileid;
+ struct nfsv2_time fa_atime;
+ struct nfsv2_time fa_mtime;
+ struct nfsv2_time fa_ctime;
+};
+
+
+struct nfs_read_args {
+ u_char fh[NFS_FHSIZE];
+ n_long off;
+ n_long len;
+ n_long xxx; /* XXX what's this for? */
+};
+
+/* Data part of nfs rpc reply (also the largest thing we receive) */
+#define NFSREAD_SIZE 1024
+struct nfs_read_repl {
+ n_long errno;
+ struct nfsv2_fattrs fa;
+ n_long count;
+ u_char data[NFSREAD_SIZE];
+};
+
+#ifndef NFS_NOSYMLINK
+struct nfs_readlnk_repl {
+ n_long errno;
+ n_long len;
+ char path[NFS_MAXPATHLEN];
+};
+#endif
+
+struct nfs_readdir_args {
+ u_char fh[NFS_FHSIZE];
+ n_long cookie;
+ n_long count;
+};
+
+struct nfs_readdir_data {
+ n_long fileid;
+ n_long len;
+ char name[0];
+};
+
+struct nfs_readdir_off {
+ n_long cookie;
+ n_long follows;
+};
+
+struct nfs_iodesc {
+ struct iodesc *iodesc;
+ off_t off;
+ u_char fh[NFS_FHSIZE];
+ struct nfsv2_fattrs fa; /* all in network order */
+};
+
+/*
+ * XXX interactions with tftp? See nfswrapper.c for a confusing
+ * issue.
+ */
+int nfs_open(const char *path, struct open_file *f);
+static int nfs_close(struct open_file *f);
+static int nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid);
+static int nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid);
+static off_t nfs_seek(struct open_file *f, off_t offset, int where);
+static int nfs_stat(struct open_file *f, struct stat *sb);
+static int nfs_readdir(struct open_file *f, struct dirent *d);
+
+struct nfs_iodesc nfs_root_node;
+
+struct fs_ops nfs_fsops = {
+ "nfs",
+ nfs_open,
+ nfs_close,
+ nfs_read,
+ nfs_write,
+ nfs_seek,
+ nfs_stat,
+ nfs_readdir
+};
+
+/*
+ * Fetch the root file handle (call mount daemon)
+ * Return zero or error number.
+ */
+int
+nfs_getrootfh(d, path, fhp)
+ struct iodesc *d;
+ char *path;
+ u_char *fhp;
+{
+ int len;
+ struct args {
+ n_long len;
+ char path[FNAME_SIZE];
+ } *args;
+ struct repl {
+ n_long errno;
+ u_char fh[NFS_FHSIZE];
+ } *repl;
+ struct {
+ n_long h[RPC_HEADER_WORDS];
+ struct args d;
+ } sdata;
+ struct {
+ n_long h[RPC_HEADER_WORDS];
+ struct repl d;
+ } rdata;
+ size_t cc;
+
+#ifdef NFS_DEBUG
+ if (debug)
+ printf("nfs_getrootfh: %s\n", path);
+#endif
+
+ args = &sdata.d;
+ repl = &rdata.d;
+
+ bzero(args, sizeof(*args));
+ len = strlen(path);
+ if (len > sizeof(args->path))
+ len = sizeof(args->path);
+ args->len = htonl(len);
+ bcopy(path, args->path, len);
+ len = 4 + roundup(len, 4);
+
+ cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT,
+ args, len, repl, sizeof(*repl));
+ if (cc == -1) {
+ /* errno was set by rpc_call */
+ return (errno);
+ }
+ if (cc < 4)
+ return (EBADRPC);
+ if (repl->errno)
+ return (ntohl(repl->errno));
+ bcopy(repl->fh, fhp, sizeof(repl->fh));
+ return (0);
+}
+
+/*
+ * Lookup a file. Store handle and attributes.
+ * Return zero or error number.
+ */
+int
+nfs_lookupfh(d, name, newfd)
+ struct nfs_iodesc *d;
+ const char *name;
+ struct nfs_iodesc *newfd;
+{
+ int len, rlen;
+ struct args {
+ u_char fh[NFS_FHSIZE];
+ n_long len;
+ char name[FNAME_SIZE];
+ } *args;
+ struct repl {
+ n_long errno;
+ u_char fh[NFS_FHSIZE];
+ struct nfsv2_fattrs fa;
+ } *repl;
+ struct {
+ n_long h[RPC_HEADER_WORDS];
+ struct args d;
+ } sdata;
+ struct {
+ n_long h[RPC_HEADER_WORDS];
+ struct repl d;
+ } rdata;
+ ssize_t cc;
+
+#ifdef NFS_DEBUG
+ if (debug)
+ printf("lookupfh: called\n");
+#endif
+
+ args = &sdata.d;
+ repl = &rdata.d;
+
+ bzero(args, sizeof(*args));
+ bcopy(d->fh, args->fh, sizeof(args->fh));
+ len = strlen(name);
+ if (len > sizeof(args->name))
+ len = sizeof(args->name);
+ bcopy(name, args->name, len);
+ args->len = htonl(len);
+ len = 4 + roundup(len, 4);
+ len += NFS_FHSIZE;
+
+ rlen = sizeof(*repl);
+
+ cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP,
+ args, len, repl, rlen);
+ if (cc == -1)
+ return (errno); /* XXX - from rpc_call */
+ if (cc < 4)
+ return (EIO);
+ if (repl->errno) {
+ /* saerrno.h now matches NFS error numbers. */
+ return (ntohl(repl->errno));
+ }
+ bcopy( repl->fh, &newfd->fh, sizeof(newfd->fh));
+ bcopy(&repl->fa, &newfd->fa, sizeof(newfd->fa));
+ return (0);
+}
+
+#ifndef NFS_NOSYMLINK
+/*
+ * Get the destination of a symbolic link.
+ */
+int
+nfs_readlink(d, buf)
+ struct nfs_iodesc *d;
+ char *buf;
+{
+ struct {
+ n_long h[RPC_HEADER_WORDS];
+ u_char fh[NFS_FHSIZE];
+ } sdata;
+ struct {
+ n_long h[RPC_HEADER_WORDS];
+ struct nfs_readlnk_repl d;
+ } rdata;
+ ssize_t cc;
+
+#ifdef NFS_DEBUG
+ if (debug)
+ printf("readlink: called\n");
+#endif
+
+ bcopy(d->fh, sdata.fh, NFS_FHSIZE);
+ cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READLINK,
+ sdata.fh, NFS_FHSIZE,
+ &rdata.d, sizeof(rdata.d));
+ if (cc == -1)
+ return (errno);
+
+ if (cc < 4)
+ return (EIO);
+
+ if (rdata.d.errno)
+ return (ntohl(rdata.d.errno));
+
+ rdata.d.len = ntohl(rdata.d.len);
+ if (rdata.d.len > NFS_MAXPATHLEN)
+ return (ENAMETOOLONG);
+
+ bcopy(rdata.d.path, buf, rdata.d.len);
+ buf[rdata.d.len] = 0;
+ return (0);
+}
+#endif
+
+/*
+ * Read data from a file.
+ * Return transfer count or -1 (and set errno)
+ */
+ssize_t
+nfs_readdata(d, off, addr, len)
+ struct nfs_iodesc *d;
+ off_t off;
+ void *addr;
+ size_t len;
+{
+ struct nfs_read_args *args;
+ struct nfs_read_repl *repl;
+ struct {
+ n_long h[RPC_HEADER_WORDS];
+ struct nfs_read_args d;
+ } sdata;
+ struct {
+ n_long h[RPC_HEADER_WORDS];
+ struct nfs_read_repl d;
+ } rdata;
+ size_t cc;
+ long x;
+ int hlen, rlen;
+
+ args = &sdata.d;
+ repl = &rdata.d;
+
+ bcopy(d->fh, args->fh, NFS_FHSIZE);
+ args->off = htonl((n_long)off);
+ if (len > NFSREAD_SIZE)
+ len = NFSREAD_SIZE;
+ args->len = htonl((n_long)len);
+ args->xxx = htonl((n_long)0);
+ hlen = sizeof(*repl) - NFSREAD_SIZE;
+
+ cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READ,
+ args, sizeof(*args),
+ repl, sizeof(*repl));
+ if (cc == -1) {
+ /* errno was already set by rpc_call */
+ return (-1);
+ }
+ if (cc < hlen) {
+ errno = EBADRPC;
+ return (-1);
+ }
+ if (repl->errno) {
+ errno = ntohl(repl->errno);
+ return (-1);
+ }
+ rlen = cc - hlen;
+ x = ntohl(repl->count);
+ if (rlen < x) {
+ printf("nfsread: short packet, %d < %ld\n", rlen, x);
+ errno = EBADRPC;
+ return(-1);
+ }
+ bcopy(repl->data, addr, x);
+ return (x);
+}
+
+/*
+ * Open a file.
+ * return zero or error number
+ */
+int
+nfs_open(upath, f)
+ const char *upath;
+ struct open_file *f;
+{
+ struct iodesc *desc;
+ struct nfs_iodesc *currfd;
+ char buf[2 * NFS_FHSIZE + 3];
+ u_char *fh;
+ char *cp;
+ int i;
+#ifndef NFS_NOSYMLINK
+ struct nfs_iodesc *newfd;
+ struct nfsv2_fattrs *fa;
+ char *ncp;
+ int c;
+ char namebuf[NFS_MAXPATHLEN + 1];
+ char linkbuf[NFS_MAXPATHLEN + 1];
+ int nlinks = 0;
+#endif
+ int error;
+ char *path;
+
+#ifdef NFS_DEBUG
+ if (debug)
+ printf("nfs_open: %s (rootpath=%s)\n", path, rootpath);
+#endif
+ if (!rootpath[0]) {
+ printf("no rootpath, no nfs\n");
+ return (ENXIO);
+ }
+
+#ifndef __i386__
+ if (strcmp(f->f_dev->dv_name, "net") != 0)
+ return(EINVAL);
+#endif
+
+ if (!(desc = socktodesc(*(int *)(f->f_devdata))))
+ return(EINVAL);
+
+ /* Bind to a reserved port. */
+ desc->myport = htons(--rpc_port);
+ desc->destip = rootip;
+ if ((error = nfs_getrootfh(desc, rootpath, nfs_root_node.fh)))
+ return (error);
+ nfs_root_node.iodesc = desc;
+
+ fh = &nfs_root_node.fh[0];
+ buf[0] = 'X';
+ cp = &buf[1];
+ for (i = 0; i < NFS_FHSIZE; i++, cp += 2)
+ sprintf(cp, "%02x", fh[i]);
+ sprintf(cp, "X");
+ setenv("boot.nfsroot.server", inet_ntoa(rootip), 1);
+ setenv("boot.nfsroot.path", rootpath, 1);
+ setenv("boot.nfsroot.nfshandle", buf, 1);
+
+#ifndef NFS_NOSYMLINK
+ /* Fake up attributes for the root dir. */
+ fa = &nfs_root_node.fa;
+ fa->fa_type = htonl(NFDIR);
+ fa->fa_mode = htonl(0755);
+ fa->fa_nlink = htonl(2);
+
+ currfd = &nfs_root_node;
+ newfd = 0;
+
+ cp = path = strdup(upath);
+ if (path == NULL) {
+ error = ENOMEM;
+ goto out;
+ }
+ while (*cp) {
+ /*
+ * Remove extra separators
+ */
+ while (*cp == '/')
+ cp++;
+
+ if (*cp == '\0')
+ break;
+ /*
+ * Check that current node is a directory.
+ */
+ if (currfd->fa.fa_type != htonl(NFDIR)) {
+ error = ENOTDIR;
+ goto out;
+ }
+
+ /* allocate file system specific data structure */
+ newfd = malloc(sizeof(*newfd));
+ newfd->iodesc = currfd->iodesc;
+ newfd->off = 0;
+
+ /*
+ * Get next component of path name.
+ */
+ {
+ int len = 0;
+
+ ncp = cp;
+ while ((c = *cp) != '\0' && c != '/') {
+ if (++len > NFS_MAXNAMLEN) {
+ error = ENOENT;
+ goto out;
+ }
+ cp++;
+ }
+ *cp = '\0';
+ }
+
+ /* lookup a file handle */
+ error = nfs_lookupfh(currfd, ncp, newfd);
+ *cp = c;
+ if (error)
+ goto out;
+
+ /*
+ * Check for symbolic link
+ */
+ if (newfd->fa.fa_type == htonl(NFLNK)) {
+ int link_len, len;
+
+ error = nfs_readlink(newfd, linkbuf);
+ if (error)
+ goto out;
+
+ link_len = strlen(linkbuf);
+ len = strlen(cp);
+
+ if (link_len + len > MAXPATHLEN
+ || ++nlinks > MAXSYMLINKS) {
+ error = ENOENT;
+ goto out;
+ }
+
+ bcopy(cp, &namebuf[link_len], len + 1);
+ bcopy(linkbuf, namebuf, link_len);
+
+ /*
+ * If absolute pathname, restart at root.
+ * If relative pathname, restart at parent directory.
+ */
+ cp = namebuf;
+ if (*cp == '/') {
+ if (currfd != &nfs_root_node)
+ free(currfd);
+ currfd = &nfs_root_node;
+ }
+
+ free(newfd);
+ newfd = 0;
+
+ continue;
+ }
+
+ if (currfd != &nfs_root_node)
+ free(currfd);
+ currfd = newfd;
+ newfd = 0;
+ }
+
+ error = 0;
+
+out:
+ if (newfd)
+ free(newfd);
+ if (path)
+ free(path);
+#else
+ /* allocate file system specific data structure */
+ currfd = malloc(sizeof(*currfd));
+ currfd->iodesc = desc;
+ currfd->off = 0;
+
+ error = nfs_lookupfh(&nfs_root_node, upath, currfd);
+#endif
+ if (!error) {
+ f->f_fsdata = (void *)currfd;
+ return (0);
+ }
+
+#ifdef NFS_DEBUG
+ if (debug)
+ printf("nfs_open: %s lookupfh failed: %s\n",
+ path, strerror(error));
+#endif
+#ifndef NFS_NOSYMLINK
+ if (currfd != &nfs_root_node)
+#endif
+ free(currfd);
+
+ return (error);
+}
+
+int
+nfs_close(f)
+ struct open_file *f;
+{
+ struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
+
+#ifdef NFS_DEBUG
+ if (debug)
+ printf("nfs_close: fp=0x%lx\n", (u_long)fp);
+#endif
+
+ if (fp != &nfs_root_node && fp)
+ free(fp);
+ f->f_fsdata = (void *)0;
+
+ return (0);
+}
+
+/*
+ * read a portion of a file
+ */
+int
+nfs_read(f, buf, size, resid)
+ struct open_file *f;
+ void *buf;
+ size_t size;
+ size_t *resid; /* out */
+{
+ struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
+ ssize_t cc;
+ char *addr = buf;
+
+#ifdef NFS_DEBUG
+ if (debug)
+ printf("nfs_read: size=%lu off=%d\n", (u_long)size,
+ (int)fp->off);
+#endif
+ while ((int)size > 0) {
+ twiddle();
+ cc = nfs_readdata(fp, fp->off, (void *)addr, size);
+ /* XXX maybe should retry on certain errors */
+ if (cc == -1) {
+#ifdef NFS_DEBUG
+ if (debug)
+ printf("nfs_read: read: %s", strerror(errno));
+#endif
+ return (errno); /* XXX - from nfs_readdata */
+ }
+ if (cc == 0) {
+#ifdef NFS_DEBUG
+ if (debug)
+ printf("nfs_read: hit EOF unexpectantly");
+#endif
+ goto ret;
+ }
+ fp->off += cc;
+ addr += cc;
+ size -= cc;
+ }
+ret:
+ if (resid)
+ *resid = size;
+
+ return (0);
+}
+
+/*
+ * Not implemented.
+ */
+int
+nfs_write(f, buf, size, resid)
+ struct open_file *f;
+ void *buf;
+ size_t size;
+ size_t *resid; /* out */
+{
+ return (EROFS);
+}
+
+off_t
+nfs_seek(f, offset, where)
+ struct open_file *f;
+ off_t offset;
+ int where;
+{
+ struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata;
+ n_long size = ntohl(d->fa.fa_size);
+
+ switch (where) {
+ case SEEK_SET:
+ d->off = offset;
+ break;
+ case SEEK_CUR:
+ d->off += offset;
+ break;
+ case SEEK_END:
+ d->off = size - offset;
+ break;
+ default:
+ errno = EINVAL;
+ return (-1);
+ }
+
+ return (d->off);
+}
+
+/* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */
+int nfs_stat_types[8] = {
+ 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 };
+
+int
+nfs_stat(f, sb)
+ struct open_file *f;
+ struct stat *sb;
+{
+ struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
+ n_long ftype, mode;
+
+ ftype = ntohl(fp->fa.fa_type);
+ mode = ntohl(fp->fa.fa_mode);
+ mode |= nfs_stat_types[ftype & 7];
+
+ sb->st_mode = mode;
+ sb->st_nlink = ntohl(fp->fa.fa_nlink);
+ sb->st_uid = ntohl(fp->fa.fa_uid);
+ sb->st_gid = ntohl(fp->fa.fa_gid);
+ sb->st_size = ntohl(fp->fa.fa_size);
+
+ return (0);
+}
+
+static int
+nfs_readdir(struct open_file *f, struct dirent *d)
+{
+ struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
+ struct nfs_readdir_args *args;
+ struct nfs_readdir_data *rd;
+ struct nfs_readdir_off *roff = NULL;
+ static char *buf;
+ static n_long cookie = 0;
+ size_t cc;
+ n_long eof;
+
+ struct {
+ n_long h[RPC_HEADER_WORDS];
+ struct nfs_readdir_args d;
+ } sdata;
+ static struct {
+ n_long h[RPC_HEADER_WORDS];
+ u_char d[NFS_READDIRSIZE];
+ } rdata;
+
+ if (cookie == 0) {
+ refill:
+ args = &sdata.d;
+ bzero(args, sizeof(*args));
+
+ bcopy(fp->fh, args->fh, NFS_FHSIZE);
+ args->cookie = htonl(cookie);
+ args->count = htonl(NFS_READDIRSIZE);
+
+ cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READDIR,
+ args, sizeof(*args),
+ rdata.d, sizeof(rdata.d));
+ buf = rdata.d;
+ roff = (struct nfs_readdir_off *)buf;
+ if (ntohl(roff->cookie) != 0)
+ return EIO;
+ }
+ roff = (struct nfs_readdir_off *)buf;
+
+ if (ntohl(roff->follows) == 0) {
+ eof = ntohl((roff+1)->cookie);
+ if (eof) {
+ cookie = 0;
+ return ENOENT;
+ }
+ goto refill;
+ }
+
+ buf += sizeof(struct nfs_readdir_off);
+ rd = (struct nfs_readdir_data *)buf;
+ d->d_namlen = ntohl(rd->len);
+ bcopy(rd->name, d->d_name, d->d_namlen);
+ d->d_name[d->d_namlen] = '\0';
+
+ buf += (sizeof(struct nfs_readdir_data) + roundup(htonl(rd->len),4));
+ roff = (struct nfs_readdir_off *)buf;
+ cookie = ntohl(roff->cookie);
+ return 0;
+}
diff --git a/lib/libstand/nfsv2.h b/lib/libstand/nfsv2.h
new file mode 100644
index 0000000..02c3070
--- /dev/null
+++ b/lib/libstand/nfsv2.h
@@ -0,0 +1,168 @@
+/* $FreeBSD$ */
+/* $NetBSD: nfsv2.h,v 1.2 1996/02/26 23:05:23 gwr Exp $ */
+
+/*
+ * Copyright (c) 1989, 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.
+ * 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.
+ *
+ * @(#)nfsv2.h 8.1 (Berkeley) 6/10/93
+ */
+
+/*
+ * nfs definitions as per the version 2 specs
+ */
+
+/*
+ * Constants as defined in the Sun NFS Version 2 spec.
+ * "NFS: Network File System Protocol Specification" RFC1094
+ */
+
+#define NFS_PORT 2049
+#define NFS_PROG 100003
+#define NFS_VER2 2
+#define NFS_MAXDGRAMDATA 8192
+#define NFS_MAXDATA 32768
+#define NFS_MAXPATHLEN 1024
+#define NFS_MAXNAMLEN 255
+#define NFS_FHSIZE 32
+#define NFS_MAXPKTHDR 404
+#define NFS_MAXPACKET (NFS_MAXPKTHDR+NFS_MAXDATA)
+#define NFS_MINPACKET 20
+#define NFS_FABLKSIZE 512 /* Size in bytes of a block wrt fa_blocks */
+#define NFS_READDIRSIZE 1024
+
+/* Stat numbers for rpc returns */
+#define NFS_OK 0
+#define NFSERR_PERM 1
+#define NFSERR_NOENT 2
+#define NFSERR_IO 5
+#define NFSERR_NXIO 6
+#define NFSERR_ACCES 13
+#define NFSERR_EXIST 17
+#define NFSERR_NODEV 19
+#define NFSERR_NOTDIR 20
+#define NFSERR_ISDIR 21
+#define NFSERR_FBIG 27
+#define NFSERR_NOSPC 28
+#define NFSERR_ROFS 30
+#define NFSERR_NAMETOL 63
+#define NFSERR_NOTEMPTY 66
+#define NFSERR_DQUOT 69
+#define NFSERR_STALE 70
+#define NFSERR_WFLUSH 99
+
+/* Sizes in bytes of various nfs rpc components */
+#define NFSX_FH 32
+#define NFSX_UNSIGNED 4
+#define NFSX_FATTR 68
+#define NFSX_SATTR 32
+#define NFSX_STATFS 20
+#define NFSX_COOKIE 4
+
+/* nfs rpc procedure numbers */
+#define NFSPROC_NULL 0
+#define NFSPROC_GETATTR 1
+#define NFSPROC_SETATTR 2
+#define NFSPROC_NOOP 3
+#define NFSPROC_ROOT NFSPROC_NOOP /* Obsolete */
+#define NFSPROC_LOOKUP 4
+#define NFSPROC_READLINK 5
+#define NFSPROC_READ 6
+#define NFSPROC_WRITECACHE NFSPROC_NOOP /* Obsolete */
+#define NFSPROC_WRITE 8
+#define NFSPROC_CREATE 9
+#define NFSPROC_REMOVE 10
+#define NFSPROC_RENAME 11
+#define NFSPROC_LINK 12
+#define NFSPROC_SYMLINK 13
+#define NFSPROC_MKDIR 14
+#define NFSPROC_RMDIR 15
+#define NFSPROC_READDIR 16
+#define NFSPROC_STATFS 17
+
+#define NFS_NPROCS 18
+
+
+/* File types */
+typedef enum {
+ NFNON=0,
+ NFREG=1,
+ NFDIR=2,
+ NFBLK=3,
+ NFCHR=4,
+ NFLNK=5
+} nfstype;
+
+/* Structs for common parts of the rpc's */
+struct nfsv2_time {
+ n_long nfs_sec;
+ n_long nfs_usec;
+};
+
+/*
+ * File attributes and setable attributes.
+ */
+struct nfsv2_fattr {
+ n_long fa_type;
+ n_long fa_mode;
+ n_long fa_nlink;
+ n_long fa_uid;
+ n_long fa_gid;
+ n_long fa_size;
+ n_long fa_blocksize;
+ n_long fa_rdev;
+ n_long fa_blocks;
+ n_long fa_fsid;
+ n_long fa_fileid;
+ struct nfsv2_time fa_atime;
+ struct nfsv2_time fa_mtime;
+ struct nfsv2_time fa_ctime;
+};
+
+struct nfsv2_sattr {
+ n_long sa_mode;
+ n_long sa_uid;
+ n_long sa_gid;
+ n_long sa_size;
+ struct nfsv2_time sa_atime;
+ struct nfsv2_time sa_mtime;
+};
+
+struct nfsv2_statfs {
+ n_long sf_tsize;
+ n_long sf_bsize;
+ n_long sf_blocks;
+ n_long sf_bfree;
+ n_long sf_bavail;
+};
diff --git a/lib/libstand/nullfs.c b/lib/libstand/nullfs.c
new file mode 100644
index 0000000..fea4c7a
--- /dev/null
+++ b/lib/libstand/nullfs.c
@@ -0,0 +1,109 @@
+/* $NetBSD: nullfs.c,v 1.1 1996/01/13 22:25:39 leo Exp $ */
+
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * The Mach Operating System project at Carnegie-Mellon 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. 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.
+ *
+ * @(#)open.c 8.1 (Berkeley) 6/11/93
+ *
+ *
+ * Copyright (c) 1989, 1990, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Author: Alessandro Forin
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "stand.h"
+
+/*
+ * Null filesystem
+ */
+int null_open (const char *path, struct open_file *f)
+{
+ return EINVAL;
+}
+
+int null_close(struct open_file *f)
+{
+ return 0;
+}
+
+int null_read (struct open_file *f, void *buf, size_t size, size_t *resid)
+{
+ return EIO;
+}
+
+int null_write (struct open_file *f, void *buf, size_t size, size_t *resid)
+{
+ return EIO;
+}
+
+off_t null_seek (struct open_file *f, off_t offset, int where)
+{
+ errno = EIO;
+ return -1;
+}
+
+int null_stat (struct open_file *f, struct stat *sb)
+{
+ return EIO;
+}
+
+int null_readdir(struct open_file *f, struct dirent *d)
+{
+ return EIO;
+}
diff --git a/lib/libstand/open.c b/lib/libstand/open.c
new file mode 100644
index 0000000..64721e5
--- /dev/null
+++ b/lib/libstand/open.c
@@ -0,0 +1,148 @@
+/* $NetBSD: open.c,v 1.16 1997/01/28 09:41:03 pk Exp $ */
+
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * The Mach Operating System project at Carnegie-Mellon 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. 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.
+ *
+ * @(#)open.c 8.1 (Berkeley) 6/11/93
+ *
+ *
+ * Copyright (c) 1989, 1990, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Author: Alessandro Forin
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "stand.h"
+
+struct open_file files[SOPEN_MAX];
+
+static int
+o_gethandle(void)
+{
+ int fd;
+
+ for (fd = 0; fd < SOPEN_MAX; fd++)
+ if (files[fd].f_flags == 0)
+ return(fd);
+ return(-1);
+}
+
+static void
+o_rainit(struct open_file *f)
+{
+ f->f_rabuf = malloc(SOPEN_RASIZE);
+ f->f_ralen = 0;
+ f->f_raoffset = 0;
+}
+
+int
+open(const char *fname, int mode)
+{
+ struct open_file *f;
+ int fd, i, error, besterror;
+ const char *file;
+
+ if ((fd = o_gethandle()) == -1) {
+ errno = EMFILE;
+ return(-1);
+ }
+
+ f = &files[fd];
+ f->f_flags = mode + 1;
+ f->f_dev = (struct devsw *)0;
+ f->f_ops = (struct fs_ops *)0;
+ f->f_offset = 0;
+ f->f_devdata = NULL;
+ file = (char *)0;
+ error = devopen(f, fname, &file);
+ if (error ||
+ (((f->f_flags & F_NODEV) == 0) && f->f_dev == (struct devsw *)0))
+ goto err;
+
+ /* see if we opened a raw device; otherwise, 'file' is the file name. */
+ if (file == (char *)0 || *file == '\0') {
+ f->f_flags |= F_RAW;
+ return (fd);
+ }
+
+ /* pass file name to the different filesystem open routines */
+ besterror = ENOENT;
+ for (i = 0; file_system[i] != NULL; i++) {
+
+ error = ((*file_system[i]).fo_open)(file, f);
+ if (error == 0) {
+
+ f->f_ops = file_system[i];
+ o_rainit(f);
+ return (fd);
+ }
+ if (error != EINVAL)
+ besterror = error;
+ }
+ error = besterror;
+
+ if ((f->f_flags & F_NODEV) == 0)
+ f->f_dev->dv_close(f);
+ if (error)
+ devclose(f);
+
+ err:
+ f->f_flags = 0;
+ errno = error;
+ return (-1);
+}
diff --git a/lib/libstand/pager.c b/lib/libstand/pager.c
new file mode 100644
index 0000000..a966b0b
--- /dev/null
+++ b/lib/libstand/pager.c
@@ -0,0 +1,161 @@
+/*-
+ * Copyright (c) 1998 Michael Smith <msmith@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.
+ */
+/*
+ * Simple paged-output and paged-viewing functions
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "stand.h"
+#include <string.h>
+
+static int p_maxlines = -1;
+static int p_freelines;
+
+static char *pager_prompt1 = " --more-- <space> page down <enter> line down <q> quit ";
+static char *pager_blank = " ";
+
+/*
+ * 'open' the pager
+ */
+void
+pager_open(void)
+{
+ int nlines;
+ char *cp, *lp;
+
+ nlines = 24; /* sensible default */
+ if ((cp = getenv("LINES")) != NULL) {
+ nlines = strtol(cp, &lp, 0);
+ }
+
+ p_maxlines = nlines - 1;
+ if (p_maxlines < 1)
+ p_maxlines = 1;
+ p_freelines = p_maxlines;
+}
+
+/*
+ * 'close' the pager
+ */
+void
+pager_close(void)
+{
+ p_maxlines = -1;
+}
+
+/*
+ * Emit lines to the pager; may not return until the user
+ * has responded to the prompt.
+ *
+ * Will return nonzero if the user enters 'q' or 'Q' at the prompt.
+ *
+ * XXX note that this watches outgoing newlines (and eats them), but
+ * does not handle wrap detection (req. count of columns).
+ */
+
+int
+pager_output(const char *cp)
+{
+ int action;
+
+ if (cp == NULL)
+ return(0);
+
+ for (;;) {
+ if (*cp == 0)
+ return(0);
+
+ putchar(*cp); /* always emit character */
+
+ if (*(cp++) == '\n') { /* got a newline? */
+ p_freelines--;
+ if (p_freelines <= 0) {
+ printf("%s", pager_prompt1);
+ action = 0;
+ while (action == 0) {
+ switch(getchar()) {
+ case '\r':
+ case '\n':
+ p_freelines = 1;
+ action = 1;
+ break;
+ case ' ':
+ p_freelines = p_maxlines;
+ action = 1;
+ break;
+ case 'q':
+ case 'Q':
+ action = 2;
+ break;
+ default:
+ break;
+ }
+ }
+ printf("\r%s\r", pager_blank);
+ if (action == 2)
+ return(1);
+ }
+ }
+ }
+}
+
+/*
+ * Display from (fd).
+ */
+int
+pager_file(const char *fname)
+{
+ char buf[80];
+ size_t hmuch;
+ int fd;
+ int result;
+
+ if ((fd = open(fname, O_RDONLY)) == -1) {
+ printf("can't open '%s': %s\n", fname, strerror(errno));
+ return(-1);
+ }
+
+ for (;;) {
+ hmuch = read(fd, buf, sizeof(buf) - 1);
+ if (hmuch == -1) {
+ result = -1;
+ break;
+ }
+ if (hmuch == 0) {
+ result = 0;
+ break;
+ }
+ buf[hmuch] = 0;
+ if (pager_output(buf)) {
+ result = 1;
+ break;
+ }
+ }
+ close(fd);
+ return(result);
+}
diff --git a/lib/libstand/powerpc/_setjmp.S b/lib/libstand/powerpc/_setjmp.S
new file mode 100644
index 0000000..5a30810
--- /dev/null
+++ b/lib/libstand/powerpc/_setjmp.S
@@ -0,0 +1,36 @@
+/* $NetBSD: _setjmp.S,v 1.1 1997/03/29 20:55:53 thorpej Exp $ */
+
+#include <machine/asm.h>
+
+#if (defined(LIBC_SCCS) || defined(LIBC_RCS)) && !defined(lint)
+ .text
+ .asciz "$FreeBSD$"
+#endif
+
+/*
+ * 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.
+ */
+
+ENTRY(_setjmp)
+ mflr 11
+ mfcr 12
+ mr 10,1
+ mr 9,2
+ stmw 9,8(3)
+ li 3,0
+ blr
+
+ENTRY(_longjmp)
+ lmw 9,8(3)
+ mtlr 11
+ mtcr 12
+ mr 2,9
+ mr 1,10
+ mr 3,4
+ blr
diff --git a/lib/libstand/printf.c b/lib/libstand/printf.c
new file mode 100644
index 0000000..ebc2c0f
--- /dev/null
+++ b/lib/libstand/printf.c
@@ -0,0 +1,435 @@
+/*-
+ * Copyright (c) 1986, 1988, 1991, 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.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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.
+ *
+ * @(#)subr_prf.c 8.3 (Berkeley) 1/21/94
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Standaloneified version of the FreeBSD kernel printf family.
+ */
+
+#include <sys/types.h>
+#include <sys/stddef.h>
+#include <sys/stdint.h>
+#include <limits.h>
+#include <string.h>
+#include "stand.h"
+
+/*
+ * Note that stdarg.h and the ANSI style va_start macro is used for both
+ * ANSI and traditional C compilers.
+ */
+#include <machine/stdarg.h>
+
+#define MAXNBUF (sizeof(intmax_t) * CHAR_BIT + 1)
+
+static char *ksprintn (char *buf, uintmax_t num, int base, int *len, int upper);
+static int kvprintf(char const *fmt, void (*func)(int), void *arg, int radix, va_list ap);
+
+int
+printf(const char *fmt, ...)
+{
+ va_list ap;
+ int retval;
+
+ va_start(ap, fmt);
+ retval = kvprintf(fmt, putchar, NULL, 10, ap);
+ va_end(ap);
+ return retval;
+}
+
+void
+vprintf(const char *fmt, va_list ap)
+{
+
+ kvprintf(fmt, putchar, NULL, 10, ap);
+}
+
+int
+sprintf(char *buf, const char *cfmt, ...)
+{
+ int retval;
+ va_list ap;
+
+ va_start(ap, cfmt);
+ retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
+ buf[retval] = '\0';
+ va_end(ap);
+ return retval;
+}
+
+void
+vsprintf(char *buf, const char *cfmt, va_list ap)
+{
+ int retval;
+
+ retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
+ buf[retval] = '\0';
+}
+
+/*
+ * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse
+ * order; return an optional length and a pointer to the last character
+ * written in the buffer (i.e., the first character of the string).
+ * The buffer pointed to by `nbuf' must have length >= MAXNBUF.
+ */
+static char *
+ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper)
+{
+ char *p, c;
+
+ p = nbuf;
+ *p = '\0';
+ do {
+ c = hex2ascii(num % base);
+ *++p = upper ? toupper(c) : c;
+ } while (num /= base);
+ if (lenp)
+ *lenp = p - nbuf;
+ return (p);
+}
+
+/*
+ * Scaled down version of printf(3).
+ *
+ * Two additional formats:
+ *
+ * The format %b is supported to decode error registers.
+ * Its usage is:
+ *
+ * printf("reg=%b\n", regval, "<base><arg>*");
+ *
+ * where <base> is the output base expressed as a control character, e.g.
+ * \10 gives octal; \20 gives hex. Each arg is a sequence of characters,
+ * the first of which gives the bit number to be inspected (origin 1), and
+ * the next characters (up to a control character, i.e. a character <= 32),
+ * give the name of the register. Thus:
+ *
+ * kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
+ *
+ * would produce output:
+ *
+ * reg=3<BITTWO,BITONE>
+ *
+ * XXX: %D -- Hexdump, takes pointer and separator string:
+ * ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX
+ * ("%*D", len, ptr, " " -> XX XX XX XX ...
+ */
+static int
+kvprintf(char const *fmt, void (*func)(int), void *arg, int radix, va_list ap)
+{
+#define PCHAR(c) {int cc=(c); if (func) (*func)(cc); else *d++ = cc; retval++; }
+ char nbuf[MAXNBUF];
+ char *d;
+ const char *p, *percent, *q;
+ u_char *up;
+ int ch, n;
+ uintmax_t num;
+ int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
+ int jflag, tflag, zflag;
+ int dwidth, upper;
+ char padc;
+ int retval = 0;
+
+ num = 0;
+ if (!func)
+ d = (char *) arg;
+ else
+ d = NULL;
+
+ if (fmt == NULL)
+ fmt = "(fmt null)\n";
+
+ if (radix < 2 || radix > 36)
+ radix = 10;
+
+ for (;;) {
+ padc = ' ';
+ width = 0;
+ while ((ch = (u_char)*fmt++) != '%') {
+ if (ch == '\0')
+ return (retval);
+ PCHAR(ch);
+ }
+ percent = fmt - 1;
+ qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
+ sign = 0; dot = 0; dwidth = 0; upper = 0;
+ jflag = 0; tflag = 0; zflag = 0;
+reswitch: switch (ch = (u_char)*fmt++) {
+ case '.':
+ dot = 1;
+ goto reswitch;
+ case '#':
+ sharpflag = 1;
+ goto reswitch;
+ case '+':
+ sign = 1;
+ goto reswitch;
+ case '-':
+ ladjust = 1;
+ goto reswitch;
+ case '%':
+ PCHAR(ch);
+ break;
+ case '*':
+ if (!dot) {
+ width = va_arg(ap, int);
+ if (width < 0) {
+ ladjust = !ladjust;
+ width = -width;
+ }
+ } else {
+ dwidth = va_arg(ap, int);
+ }
+ goto reswitch;
+ case '0':
+ if (!dot) {
+ padc = '0';
+ goto reswitch;
+ }
+ case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ for (n = 0;; ++fmt) {
+ n = n * 10 + ch - '0';
+ ch = *fmt;
+ if (ch < '0' || ch > '9')
+ break;
+ }
+ if (dot)
+ dwidth = n;
+ else
+ width = n;
+ goto reswitch;
+ case 'b':
+ num = va_arg(ap, int);
+ p = va_arg(ap, char *);
+ for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;)
+ PCHAR(*q--);
+
+ if (num == 0)
+ break;
+
+ for (tmp = 0; *p;) {
+ n = *p++;
+ if (num & (1 << (n - 1))) {
+ PCHAR(tmp ? ',' : '<');
+ for (; (n = *p) > ' '; ++p)
+ PCHAR(n);
+ tmp = 1;
+ } else
+ for (; *p > ' '; ++p)
+ continue;
+ }
+ if (tmp)
+ PCHAR('>');
+ break;
+ case 'c':
+ PCHAR(va_arg(ap, int));
+ break;
+ case 'D':
+ up = va_arg(ap, u_char *);
+ p = va_arg(ap, char *);
+ if (!width)
+ width = 16;
+ while(width--) {
+ PCHAR(hex2ascii(*up >> 4));
+ PCHAR(hex2ascii(*up & 0x0f));
+ up++;
+ if (width)
+ for (q=p;*q;q++)
+ PCHAR(*q);
+ }
+ break;
+ case 'd':
+ case 'i':
+ base = 10;
+ sign = 1;
+ goto handle_sign;
+ case 'j':
+ jflag = 1;
+ goto reswitch;
+ case 'l':
+ if (lflag) {
+ lflag = 0;
+ qflag = 1;
+ } else
+ lflag = 1;
+ goto reswitch;
+ case 'n':
+ if (jflag)
+ *(va_arg(ap, intmax_t *)) = retval;
+ else if (qflag)
+ *(va_arg(ap, quad_t *)) = retval;
+ else if (lflag)
+ *(va_arg(ap, long *)) = retval;
+ else if (zflag)
+ *(va_arg(ap, size_t *)) = retval;
+ else
+ *(va_arg(ap, int *)) = retval;
+ break;
+ case 'o':
+ base = 8;
+ goto handle_nosign;
+ case 'p':
+ base = 16;
+ sharpflag = (width == 0);
+ sign = 0;
+ num = (uintptr_t)va_arg(ap, void *);
+ goto number;
+ case 'q':
+ qflag = 1;
+ goto reswitch;
+ case 'r':
+ base = radix;
+ if (sign)
+ goto handle_sign;
+ goto handle_nosign;
+ case 's':
+ p = va_arg(ap, char *);
+ if (p == NULL)
+ p = "(null)";
+ if (!dot)
+ n = strlen (p);
+ else
+ for (n = 0; n < dwidth && p[n]; n++)
+ continue;
+
+ width -= n;
+
+ if (!ladjust && width > 0)
+ while (width--)
+ PCHAR(padc);
+ while (n--)
+ PCHAR(*p++);
+ if (ladjust && width > 0)
+ while (width--)
+ PCHAR(padc);
+ break;
+ case 't':
+ tflag = 1;
+ goto reswitch;
+ case 'u':
+ base = 10;
+ goto handle_nosign;
+ case 'X':
+ upper = 1;
+ case 'x':
+ base = 16;
+ goto handle_nosign;
+ case 'y':
+ base = 16;
+ sign = 1;
+ goto handle_sign;
+ case 'z':
+ zflag = 1;
+ goto reswitch;
+handle_nosign:
+ sign = 0;
+ if (jflag)
+ num = va_arg(ap, uintmax_t);
+ else if (qflag)
+ num = va_arg(ap, u_quad_t);
+ else if (tflag)
+ num = va_arg(ap, ptrdiff_t);
+ else if (lflag)
+ num = va_arg(ap, u_long);
+ else if (zflag)
+ num = va_arg(ap, size_t);
+ else
+ num = va_arg(ap, u_int);
+ goto number;
+handle_sign:
+ if (jflag)
+ num = va_arg(ap, intmax_t);
+ else if (qflag)
+ num = va_arg(ap, quad_t);
+ else if (tflag)
+ num = va_arg(ap, ptrdiff_t);
+ else if (lflag)
+ num = va_arg(ap, long);
+ else if (zflag)
+ num = va_arg(ap, size_t);
+ else
+ num = va_arg(ap, int);
+number:
+ if (sign && (intmax_t)num < 0) {
+ neg = 1;
+ num = -(intmax_t)num;
+ }
+ p = ksprintn(nbuf, num, base, &tmp, upper);
+ if (sharpflag && num != 0) {
+ if (base == 8)
+ tmp++;
+ else if (base == 16)
+ tmp += 2;
+ }
+ if (neg)
+ tmp++;
+
+ if (!ladjust && width && (width -= tmp) > 0)
+ while (width--)
+ PCHAR(padc);
+ if (neg)
+ PCHAR('-');
+ if (sharpflag && num != 0) {
+ if (base == 8) {
+ PCHAR('0');
+ } else if (base == 16) {
+ PCHAR('0');
+ PCHAR('x');
+ }
+ }
+
+ while (*p)
+ PCHAR(*p--);
+
+ if (ladjust && width && (width -= tmp) > 0)
+ while (width--)
+ PCHAR(padc);
+
+ break;
+ default:
+ while (percent < fmt)
+ PCHAR(*percent++);
+ break;
+ }
+ }
+#undef PCHAR
+}
diff --git a/lib/libstand/qdivrem.c b/lib/libstand/qdivrem.c
new file mode 100644
index 0000000..584a0b1
--- /dev/null
+++ b/lib/libstand/qdivrem.c
@@ -0,0 +1,353 @@
+/*-
+ * 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.
+ * 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.
+ *
+ * From: Id: qdivrem.c,v 1.7 1997/11/07 09:20:40 phk Exp
+ */
+
+#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 nn = COMBINE(uj0, uj1);
+ qhat = nn / v1;
+ rhat = nn % 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);
+}
+
+/*
+ * Divide two unsigned quads.
+ */
+
+u_quad_t
+__udivdi3(a, b)
+ u_quad_t a, b;
+{
+
+ return (__qdivrem(a, b, (u_quad_t *)0));
+}
+
+/*
+ * 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);
+}
+
+/*
+ * 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);
+}
+
+/*
+ * 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/libstand/quad.h b/lib/libstand/quad.h
new file mode 100644
index 0000000..86c3772
--- /dev/null
+++ b/lib/libstand/quad.h
@@ -0,0 +1,116 @@
+/*-
+ * 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.
+ * 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.
+ *
+ * @(#)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/cdefs.h>
+#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)
+
+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);
+u_quad_t __udivdi3(u_quad_t a, u_quad_t b);
+u_quad_t __umoddi3(u_quad_t a, u_quad_t b);
+
+/*
+ * XXX
+ * Compensate for gcc 1 vs gcc 2. Gcc 1 defines ?sh?di3's second argument
+ * as u_quad_t, while gcc 2 correctly uses int. Unfortunately, we still use
+ * both compilers.
+ */
+#if __GNUC__ >= 2
+typedef unsigned int qshift_t;
+#else
+typedef u_quad_t qshift_t;
+#endif
diff --git a/lib/libstand/random.c b/lib/libstand/random.c
new file mode 100644
index 0000000..441c4ae
--- /dev/null
+++ b/lib/libstand/random.c
@@ -0,0 +1,74 @@
+/*-
+ * 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. 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.
+ *
+ * @(#)random.c 8.1 (Berkeley) 6/10/93
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+static u_long randseed = 1;
+
+void
+srandom(seed)
+ u_long seed;
+{
+ randseed = seed;
+}
+
+/*
+ * Pseudo-random number generator for randomizing the profiling clock,
+ * and whatever else we might use it for. The result is uniform on
+ * [0, 2^31 - 1].
+ */
+u_long
+random()
+{
+ long x, hi, lo, t;
+
+ /*
+ * Compute x[n + 1] = (7^5 * x[n]) mod (2^31 - 1).
+ * 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.
+ */
+ x = randseed;
+ hi = x / 127773;
+ lo = x % 127773;
+ t = 16807 * lo - 2836 * hi;
+ if (t <= 0)
+ t += 0x7fffffff;
+ randseed = t;
+ return (t);
+}
diff --git a/lib/libstand/rarp.c b/lib/libstand/rarp.c
new file mode 100644
index 0000000..eed1ed0
--- /dev/null
+++ b/lib/libstand/rarp.c
@@ -0,0 +1,229 @@
+/* $NetBSD: rarp.c,v 1.16 1997/07/07 15:52:52 drochner Exp $ */
+
+/*
+ * Copyright (c) 1992 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.
+ * 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, Lawrence Berkeley Laboratory 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.
+ *
+ * @(#) Header: arp.c,v 1.5 93/07/15 05:52:26 leres Exp (LBL)
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#include <netinet/in_systm.h>
+
+#include <string.h>
+
+#include "stand.h"
+#include "net.h"
+#include "netif.h"
+
+
+static ssize_t rarpsend(struct iodesc *, void *, size_t);
+static ssize_t rarprecv(struct iodesc *, void *, size_t, time_t);
+
+/*
+ * Ethernet (Reverse) Address Resolution Protocol (see RFC 903, and 826).
+ */
+int
+rarp_getipaddress(sock)
+ int sock;
+{
+ struct iodesc *d;
+ struct ether_arp *ap;
+ struct {
+ u_char header[ETHER_SIZE];
+ struct {
+ struct ether_arp arp;
+ u_char pad[18]; /* 60 - sizeof(arp) */
+ } data;
+ } wbuf;
+ struct {
+ u_char header[ETHER_SIZE];
+ struct {
+ struct ether_arp arp;
+ u_char pad[24]; /* extra space */
+ } data;
+ } rbuf;
+
+#ifdef RARP_DEBUG
+ if (debug)
+ printf("rarp: socket=%d\n", sock);
+#endif
+ if (!(d = socktodesc(sock))) {
+ printf("rarp: bad socket. %d\n", sock);
+ return (-1);
+ }
+#ifdef RARP_DEBUG
+ if (debug)
+ printf("rarp: d=%x\n", (u_int)d);
+#endif
+
+ bzero((char*)&wbuf.data, sizeof(wbuf.data));
+ ap = &wbuf.data.arp;
+ ap->arp_hrd = htons(ARPHRD_ETHER);
+ ap->arp_pro = htons(ETHERTYPE_IP);
+ ap->arp_hln = sizeof(ap->arp_sha); /* hardware address length */
+ ap->arp_pln = sizeof(ap->arp_spa); /* protocol address length */
+ ap->arp_op = htons(ARPOP_REVREQUEST);
+ bcopy(d->myea, ap->arp_sha, 6);
+ bcopy(d->myea, ap->arp_tha, 6);
+
+ if (sendrecv(d,
+ rarpsend, &wbuf.data, sizeof(wbuf.data),
+ rarprecv, &rbuf.data, sizeof(rbuf.data)) < 0)
+ {
+ printf("No response for RARP request\n");
+ return (-1);
+ }
+
+ ap = &rbuf.data.arp;
+ bcopy(ap->arp_tpa, (char *)&myip, sizeof(myip));
+#if 0
+ /* XXX - Can NOT assume this is our root server! */
+ bcopy(ap->arp_spa, (char *)&rootip, sizeof(rootip));
+#endif
+
+ /* Compute our "natural" netmask. */
+ if (IN_CLASSA(myip.s_addr))
+ netmask = IN_CLASSA_NET;
+ else if (IN_CLASSB(myip.s_addr))
+ netmask = IN_CLASSB_NET;
+ else
+ netmask = IN_CLASSC_NET;
+
+ d->myip = myip;
+ return (0);
+}
+
+/*
+ * Broadcast a RARP request (i.e. who knows who I am)
+ */
+static ssize_t
+rarpsend(d, pkt, len)
+ struct iodesc *d;
+ void *pkt;
+ size_t len;
+{
+
+#ifdef RARP_DEBUG
+ if (debug)
+ printf("rarpsend: called\n");
+#endif
+
+ return (sendether(d, pkt, len, bcea, ETHERTYPE_REVARP));
+}
+
+/*
+ * Returns 0 if this is the packet we're waiting for
+ * else -1 (and errno == 0)
+ */
+static ssize_t
+rarprecv(d, pkt, len, tleft)
+ struct iodesc *d;
+ void *pkt;
+ size_t len;
+ time_t tleft;
+{
+ ssize_t n;
+ struct ether_arp *ap;
+ u_int16_t etype; /* host order */
+
+#ifdef RARP_DEBUG
+ if (debug)
+ printf("rarprecv: ");
+#endif
+
+ n = readether(d, pkt, len, tleft, &etype);
+ errno = 0; /* XXX */
+ if (n == -1 || n < sizeof(struct ether_arp)) {
+#ifdef RARP_DEBUG
+ if (debug)
+ printf("bad len=%d\n", n);
+#endif
+ return (-1);
+ }
+
+ if (etype != ETHERTYPE_REVARP) {
+#ifdef RARP_DEBUG
+ if (debug)
+ printf("bad type=0x%x\n", etype);
+#endif
+ return (-1);
+ }
+
+ ap = (struct ether_arp *)pkt;
+ if (ap->arp_hrd != htons(ARPHRD_ETHER) ||
+ ap->arp_pro != htons(ETHERTYPE_IP) ||
+ ap->arp_hln != sizeof(ap->arp_sha) ||
+ ap->arp_pln != sizeof(ap->arp_spa) )
+ {
+#ifdef RARP_DEBUG
+ if (debug)
+ printf("bad hrd/pro/hln/pln\n");
+#endif
+ return (-1);
+ }
+
+ if (ap->arp_op != htons(ARPOP_REVREPLY)) {
+#ifdef RARP_DEBUG
+ if (debug)
+ printf("bad op=0x%x\n", ntohs(ap->arp_op));
+#endif
+ return (-1);
+ }
+
+ /* Is the reply for our Ethernet address? */
+ if (bcmp(ap->arp_tha, d->myea, 6)) {
+#ifdef RARP_DEBUG
+ if (debug)
+ printf("unwanted address\n");
+#endif
+ return (-1);
+ }
+
+ /* We have our answer. */
+#ifdef RARP_DEBUG
+ if (debug)
+ printf("got it\n");
+#endif
+ return (n);
+}
diff --git a/lib/libstand/read.c b/lib/libstand/read.c
new file mode 100644
index 0000000..09e24e1
--- /dev/null
+++ b/lib/libstand/read.c
@@ -0,0 +1,131 @@
+/* $NetBSD: read.c,v 1.8 1997/01/22 00:38:12 cgd Exp $ */
+
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * The Mach Operating System project at Carnegie-Mellon 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. 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.
+ *
+ * @(#)read.c 8.1 (Berkeley) 6/11/93
+ *
+ *
+ * Copyright (c) 1989, 1990, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Author: Alessandro Forin
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include "stand.h"
+
+ssize_t
+read(int fd, void *dest, size_t bcount)
+{
+ struct open_file *f = &files[fd];
+ size_t resid;
+
+ if ((unsigned)fd >= SOPEN_MAX || !(f->f_flags & F_READ)) {
+ errno = EBADF;
+ return (-1);
+ }
+ if (f->f_flags & F_RAW) {
+ twiddle();
+ errno = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
+ btodb(f->f_offset), bcount, dest, &resid);
+ if (errno)
+ return (-1);
+ f->f_offset += resid;
+ return (resid);
+ }
+
+ /*
+ * Optimise reads from regular files using a readahead buffer.
+ * If the request can't be satisfied from the current buffer contents,
+ * check to see if it should be bypassed, or refill the buffer and complete
+ * the request.
+ */
+ resid = bcount;
+ for (;;) {
+ size_t ccount, cresid;
+ /* how much can we supply? */
+ ccount = imin(f->f_ralen, resid);
+ if (ccount > 0) {
+ bcopy(f->f_rabuf + f->f_raoffset, dest, ccount);
+ f->f_raoffset += ccount;
+ f->f_ralen -= ccount;
+ resid -= ccount;
+ if (resid == 0)
+ return(bcount);
+ dest = (char *)dest + ccount;
+ }
+
+ /* will filling the readahead buffer again not help? */
+ if (resid >= SOPEN_RASIZE) {
+ /* bypass the rest of the request and leave the buffer empty */
+ if ((errno = (f->f_ops->fo_read)(f, dest, resid, &cresid)))
+ return (-1);
+ return(bcount - cresid);
+ }
+
+ /* fetch more data */
+ if ((errno = (f->f_ops->fo_read)(f, f->f_rabuf, SOPEN_RASIZE, &cresid)))
+ return (-1);
+ f->f_raoffset = 0;
+ f->f_ralen = SOPEN_RASIZE - cresid;
+ /* no more data, return what we had */
+ if (f->f_ralen == 0)
+ return(bcount - resid);
+ }
+}
diff --git a/lib/libstand/readdir.c b/lib/libstand/readdir.c
new file mode 100644
index 0000000..e49d93d
--- /dev/null
+++ b/lib/libstand/readdir.c
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 1999,2000 Jonathan Lemon <jlemon@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 "stand.h"
+
+struct dirent *
+readdirfd(int fd)
+{
+ static struct dirent dir; /* XXX not thread safe */
+ struct open_file *f = &files[fd];
+
+ if ((unsigned)fd >= SOPEN_MAX || !(f->f_flags & F_READ)) {
+ errno = EBADF;
+ return (NULL);
+ }
+ if (f->f_flags & F_RAW) {
+ errno = EIO;
+ return (NULL);
+ }
+ errno = (f->f_ops->fo_readdir)(f, &dir);
+ if (errno)
+ return (NULL);
+ return (&dir);
+}
diff --git a/lib/libstand/rpc.c b/lib/libstand/rpc.c
new file mode 100644
index 0000000..bddb49d
--- /dev/null
+++ b/lib/libstand/rpc.c
@@ -0,0 +1,443 @@
+/* $NetBSD: rpc.c,v 1.18 1998/01/23 19:27:45 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1992 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.
+ * 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, Lawrence Berkeley Laboratory 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.
+ *
+ * @(#) Header: rpc.c,v 1.12 93/09/28 08:31:56 leres Exp (LBL)
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * RPC functions used by NFS and bootparams.
+ * Note that bootparams requires the ability to find out the
+ * address of the server from which its response has come.
+ * This is supported by keeping the IP/UDP headers in the
+ * buffer space provided by the caller. (See rpc_fromaddr)
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+
+#include <string.h>
+
+#include "rpcv2.h"
+
+#include "stand.h"
+#include "net.h"
+#include "netif.h"
+#include "rpc.h"
+
+struct auth_info {
+ int32_t authtype; /* auth type */
+ u_int32_t authlen; /* auth length */
+};
+
+struct auth_unix {
+ int32_t ua_time;
+ int32_t ua_hostname; /* null */
+ int32_t ua_uid;
+ int32_t ua_gid;
+ int32_t ua_gidlist; /* null */
+};
+
+struct rpc_call {
+ u_int32_t rp_xid; /* request transaction id */
+ int32_t rp_direction; /* call direction (0) */
+ u_int32_t rp_rpcvers; /* rpc version (2) */
+ u_int32_t rp_prog; /* program */
+ u_int32_t rp_vers; /* version */
+ u_int32_t rp_proc; /* procedure */
+};
+
+struct rpc_reply {
+ u_int32_t rp_xid; /* request transaction id */
+ int32_t rp_direction; /* call direction (1) */
+ int32_t rp_astatus; /* accept status (0: accepted) */
+ union {
+ u_int32_t rpu_errno;
+ struct {
+ struct auth_info rok_auth;
+ u_int32_t rok_status;
+ } rpu_rok;
+ } rp_u;
+};
+
+/* Local forwards */
+static ssize_t recvrpc(struct iodesc *, void *, size_t, time_t);
+static int rpc_getport(struct iodesc *, n_long, n_long);
+
+int rpc_xid;
+int rpc_port = 0x400; /* predecrement */
+
+/*
+ * Make a rpc call; return length of answer
+ * Note: Caller must leave room for headers.
+ */
+ssize_t
+rpc_call(d, prog, vers, proc, sdata, slen, rdata, rlen)
+ struct iodesc *d;
+ n_long prog, vers, proc;
+ void *sdata;
+ size_t slen;
+ void *rdata;
+ size_t rlen;
+{
+ ssize_t cc;
+ struct auth_info *auth;
+ struct rpc_call *call;
+ struct rpc_reply *reply;
+ char *send_head, *send_tail;
+ char *recv_head, *recv_tail;
+ n_long x;
+ int port; /* host order */
+
+#ifdef RPC_DEBUG
+ if (debug)
+ printf("rpc_call: prog=0x%x vers=%d proc=%d\n",
+ prog, vers, proc);
+#endif
+
+ port = rpc_getport(d, prog, vers);
+ if (port == -1)
+ return (-1);
+
+ d->destport = htons(port);
+
+ /*
+ * Prepend authorization stuff and headers.
+ * Note, must prepend things in reverse order.
+ */
+ send_head = sdata;
+ send_tail = (char *)sdata + slen;
+
+ /* Auth verifier is always auth_null */
+ send_head -= sizeof(*auth);
+ auth = (struct auth_info *)send_head;
+ auth->authtype = htonl(RPCAUTH_NULL);
+ auth->authlen = 0;
+
+#if 1
+ /* Auth credentials: always auth unix (as root) */
+ send_head -= sizeof(struct auth_unix);
+ bzero(send_head, sizeof(struct auth_unix));
+ send_head -= sizeof(*auth);
+ auth = (struct auth_info *)send_head;
+ auth->authtype = htonl(RPCAUTH_UNIX);
+ auth->authlen = htonl(sizeof(struct auth_unix));
+#else
+ /* Auth credentials: always auth_null (XXX OK?) */
+ send_head -= sizeof(*auth);
+ auth = send_head;
+ auth->authtype = htonl(RPCAUTH_NULL);
+ auth->authlen = 0;
+#endif
+
+ /* RPC call structure. */
+ send_head -= sizeof(*call);
+ call = (struct rpc_call *)send_head;
+ rpc_xid++;
+ call->rp_xid = htonl(rpc_xid);
+ call->rp_direction = htonl(RPC_CALL);
+ call->rp_rpcvers = htonl(RPC_VER2);
+ call->rp_prog = htonl(prog);
+ call->rp_vers = htonl(vers);
+ call->rp_proc = htonl(proc);
+
+ /* Make room for the rpc_reply header. */
+ recv_head = rdata;
+ recv_tail = (char *)rdata + rlen;
+ recv_head -= sizeof(*reply);
+
+ cc = sendrecv(d,
+ sendudp, send_head, send_tail - send_head,
+ recvrpc, recv_head, recv_tail - recv_head);
+
+#ifdef RPC_DEBUG
+ if (debug)
+ printf("callrpc: cc=%ld rlen=%lu\n", (long)cc, (u_long)rlen);
+#endif
+ if (cc == -1)
+ return (-1);
+
+ if (cc <= sizeof(*reply)) {
+ errno = EBADRPC;
+ return (-1);
+ }
+
+ recv_tail = recv_head + cc;
+
+ /*
+ * Check the RPC reply status.
+ * The xid, dir, astatus were already checked.
+ */
+ reply = (struct rpc_reply *)recv_head;
+ auth = &reply->rp_u.rpu_rok.rok_auth;
+ x = ntohl(auth->authlen);
+ if (x != 0) {
+#ifdef RPC_DEBUG
+ if (debug)
+ printf("callrpc: reply auth != NULL\n");
+#endif
+ errno = EBADRPC;
+ return(-1);
+ }
+ x = ntohl(reply->rp_u.rpu_rok.rok_status);
+ if (x != 0) {
+ printf("callrpc: error = %ld\n", (long)x);
+ errno = EBADRPC;
+ return(-1);
+ }
+ recv_head += sizeof(*reply);
+
+ return (ssize_t)(recv_tail - recv_head);
+}
+
+/*
+ * Returns true if packet is the one we're waiting for.
+ * This just checks the XID, direction, acceptance.
+ * Remaining checks are done by callrpc
+ */
+static ssize_t
+recvrpc(d, pkt, len, tleft)
+ struct iodesc *d;
+ void *pkt;
+ size_t len;
+ time_t tleft;
+{
+ struct rpc_reply *reply;
+ ssize_t n;
+ int x;
+
+ errno = 0;
+#ifdef RPC_DEBUG
+ if (debug)
+ printf("recvrpc: called len=%lu\n", (u_long)len);
+#endif
+
+ n = readudp(d, pkt, len, tleft);
+ if (n <= (4 * 4))
+ return -1;
+
+ reply = (struct rpc_reply *)pkt;
+
+ x = ntohl(reply->rp_xid);
+ if (x != rpc_xid) {
+#ifdef RPC_DEBUG
+ if (debug)
+ printf("recvrpc: rp_xid %d != xid %d\n", x, rpc_xid);
+#endif
+ return -1;
+ }
+
+ x = ntohl(reply->rp_direction);
+ if (x != RPC_REPLY) {
+#ifdef RPC_DEBUG
+ if (debug)
+ printf("recvrpc: rp_direction %d != REPLY\n", x);
+#endif
+ return -1;
+ }
+
+ x = ntohl(reply->rp_astatus);
+ if (x != RPC_MSGACCEPTED) {
+ errno = ntohl(reply->rp_u.rpu_errno);
+ printf("recvrpc: reject, astat=%d, errno=%d\n", x, errno);
+ return -1;
+ }
+
+ /* Return data count (thus indicating success) */
+ return (n);
+}
+
+/*
+ * Given a pointer to a reply just received,
+ * dig out the IP address/port from the headers.
+ */
+void
+rpc_fromaddr(pkt, addr, port)
+ void *pkt;
+ struct in_addr *addr;
+ u_short *port;
+{
+ struct hackhdr {
+ /* Tail of IP header: just IP addresses */
+ n_long ip_src;
+ n_long ip_dst;
+ /* UDP header: */
+ u_int16_t uh_sport; /* source port */
+ u_int16_t uh_dport; /* destination port */
+ int16_t uh_ulen; /* udp length */
+ u_int16_t uh_sum; /* udp checksum */
+ /* RPC reply header: */
+ struct rpc_reply rpc;
+ } *hhdr;
+
+ hhdr = ((struct hackhdr *)pkt) - 1;
+ addr->s_addr = hhdr->ip_src;
+ *port = hhdr->uh_sport;
+}
+
+/*
+ * RPC Portmapper cache
+ */
+#define PMAP_NUM 8 /* need at most 5 pmap entries */
+
+int rpc_pmap_num;
+struct pmap_list {
+ struct in_addr addr; /* server, net order */
+ u_int prog; /* host order */
+ u_int vers; /* host order */
+ int port; /* host order */
+} rpc_pmap_list[PMAP_NUM];
+
+/* return port number in host order, or -1 */
+int
+rpc_pmap_getcache(addr, prog, vers)
+ struct in_addr addr; /* server, net order */
+ u_int prog; /* host order */
+ u_int vers; /* host order */
+{
+ struct pmap_list *pl;
+
+ for (pl = rpc_pmap_list; pl < &rpc_pmap_list[rpc_pmap_num]; pl++) {
+ if (pl->addr.s_addr == addr.s_addr &&
+ pl->prog == prog && pl->vers == vers )
+ {
+ return (pl->port);
+ }
+ }
+ return (-1);
+}
+
+void
+rpc_pmap_putcache(addr, prog, vers, port)
+ struct in_addr addr; /* server, net order */
+ u_int prog; /* host order */
+ u_int vers; /* host order */
+ int port; /* host order */
+{
+ struct pmap_list *pl;
+
+ /* Don't overflow cache... */
+ if (rpc_pmap_num >= PMAP_NUM) {
+ /* ... just re-use the last entry. */
+ rpc_pmap_num = PMAP_NUM - 1;
+#ifdef RPC_DEBUG
+ printf("rpc_pmap_putcache: cache overflow\n");
+#endif
+ }
+
+ pl = &rpc_pmap_list[rpc_pmap_num];
+ rpc_pmap_num++;
+
+ /* Cache answer */
+ pl->addr = addr;
+ pl->prog = prog;
+ pl->vers = vers;
+ pl->port = port;
+}
+
+
+/*
+ * Request a port number from the port mapper.
+ * Returns the port in host order.
+ */
+int
+rpc_getport(d, prog, vers)
+ struct iodesc *d;
+ n_long prog; /* host order */
+ n_long vers; /* host order */
+{
+ struct args {
+ n_long prog; /* call program */
+ n_long vers; /* call version */
+ n_long proto; /* call protocol */
+ n_long port; /* call port (unused) */
+ } *args;
+ struct res {
+ n_long port;
+ } *res;
+ struct {
+ n_long h[RPC_HEADER_WORDS];
+ struct args d;
+ } sdata;
+ struct {
+ n_long h[RPC_HEADER_WORDS];
+ struct res d;
+ n_long pad;
+ } rdata;
+ ssize_t cc;
+ int port;
+
+#ifdef RPC_DEBUG
+ if (debug)
+ printf("getport: prog=0x%x vers=%d\n", prog, vers);
+#endif
+
+ /* This one is fixed forever. */
+ if (prog == PMAPPROG)
+ return (PMAPPORT);
+
+ /* Try for cached answer first */
+ port = rpc_pmap_getcache(d->destip, prog, vers);
+ if (port != -1)
+ return (port);
+
+ args = &sdata.d;
+ args->prog = htonl(prog);
+ args->vers = htonl(vers);
+ args->proto = htonl(IPPROTO_UDP);
+ args->port = 0;
+ res = &rdata.d;
+
+ cc = rpc_call(d, PMAPPROG, PMAPVERS, PMAPPROC_GETPORT,
+ args, sizeof(*args), res, sizeof(*res));
+ if (cc < sizeof(*res)) {
+ printf("getport: %s", strerror(errno));
+ errno = EBADRPC;
+ return (-1);
+ }
+ port = (int)ntohl(res->port);
+
+ rpc_pmap_putcache(d->destip, prog, vers, port);
+
+ return (port);
+}
diff --git a/lib/libstand/rpc.h b/lib/libstand/rpc.h
new file mode 100644
index 0000000..1b6c60d
--- /dev/null
+++ b/lib/libstand/rpc.h
@@ -0,0 +1,68 @@
+/* $NetBSD: rpc.h,v 1.8 1996/09/26 23:22:03 cgd Exp $ */
+
+/*
+ * Copyright (c) 1992 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.
+ * 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, Lawrence Berkeley Laboratory 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.
+ */
+
+/* XXX defines we can't easily get from system includes */
+#define PMAPPORT 111
+#define PMAPPROG 100000
+#define PMAPVERS 2
+#define PMAPPROC_NULL 0
+#define PMAPPROC_SET 1
+#define PMAPPROC_UNSET 2
+#define PMAPPROC_GETPORT 3
+#define PMAPPROC_DUMP 4
+#define PMAPPROC_CALLIT 5
+
+/* RPC functions: */
+ssize_t rpc_call(struct iodesc *, n_long, n_long, n_long,
+ void *, size_t, void *, size_t);
+void rpc_fromaddr(void *, struct in_addr *, u_short *);
+int rpc_pmap_getcache(struct in_addr, u_int, u_int);
+void rpc_pmap_putcache(struct in_addr, u_int, u_int, int);
+
+extern int rpc_port; /* decrement before bind */
+
+/*
+ * How much space to leave in front of RPC requests.
+ * In 32-bit words (alignment) we have:
+ * 12: Ether + IP + UDP + padding
+ * 6: RPC call header
+ * 7: Auth UNIX
+ * 2: Auth NULL
+ */
+#define RPC_HEADER_WORDS 28
diff --git a/lib/libstand/rpcv2.h b/lib/libstand/rpcv2.h
new file mode 100644
index 0000000..e4d2dbe
--- /dev/null
+++ b/lib/libstand/rpcv2.h
@@ -0,0 +1,89 @@
+/* $NetBSD: rpcv2.h,v 1.1 1996/02/26 23:05:32 gwr Exp $ */
+
+/*
+ * Copyright (c) 1989, 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.
+ * 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.
+ *
+ * @(#)rpcv2.h 8.1 (Berkeley) 6/10/93
+ */
+
+/*
+ * Definitions for Sun RPC Version 2, from
+ * "RPC: Remote Procedure Call Protocol Specification" RFC1057
+ */
+
+/* Version # */
+#define RPC_VER2 2
+
+/* Authentication */
+#define RPCAUTH_NULL 0
+#define RPCAUTH_UNIX 1
+#define RPCAUTH_SHORT 2
+#define RPCAUTH_MAXSIZ 400
+#define RPCAUTH_UNIXGIDS 16
+
+/* Rpc Constants */
+#define RPC_CALL 0
+#define RPC_REPLY 1
+#define RPC_MSGACCEPTED 0
+#define RPC_MSGDENIED 1
+#define RPC_PROGUNAVAIL 1
+#define RPC_PROGMISMATCH 2
+#define RPC_PROCUNAVAIL 3
+#define RPC_GARBAGE 4 /* I like this one */
+#define RPC_MISMATCH 0
+#define RPC_AUTHERR 1
+
+/* Authentication failures */
+#define AUTH_BADCRED 1
+#define AUTH_REJECTCRED 2
+#define AUTH_BADVERF 3
+#define AUTH_REJECTVERF 4
+#define AUTH_TOOWEAK 5 /* Give em wheaties */
+
+/* Sizes of rpc header parts */
+#define RPC_SIZ 24
+#define RPC_REPLYSIZ 28
+
+/* RPC Prog definitions */
+#define RPCPROG_MNT 100005
+#define RPCMNT_VER1 1
+#define RPCMNT_MOUNT 1
+#define RPCMNT_DUMP 2
+#define RPCMNT_UMOUNT 3
+#define RPCMNT_UMNTALL 4
+#define RPCMNT_EXPORT 5
+#define RPCMNT_NAMELEN 255
+#define RPCMNT_PATHLEN 1024
+#define RPCPROG_NFS 100003
diff --git a/lib/libstand/saioctl.h b/lib/libstand/saioctl.h
new file mode 100644
index 0000000..bf7df4c
--- /dev/null
+++ b/lib/libstand/saioctl.h
@@ -0,0 +1,52 @@
+/* $NetBSD: saioctl.h,v 1.2 1994/10/26 05:45:04 cgd Exp $ */
+
+/*-
+ * 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.
+ * 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.
+ *
+ * @(#)saioctl.h 8.1 (Berkeley) 6/11/93
+ */
+
+/* ioctl's -- for disks just now */
+#define SAIOHDR (('d'<<8)|1) /* next i/o includes header */
+#define SAIOCHECK (('d'<<8)|2) /* next i/o checks data */
+#define SAIOHCHECK (('d'<<8)|3) /* next i/o checks header & data */
+#define SAIONOBAD (('d'<<8)|4) /* inhibit bad sector forwarding */
+#define SAIODOBAD (('d'<<8)|5) /* enable bad sector forwarding */
+#define SAIOECCLIM (('d'<<8)|6) /* set limit to ecc correction, bits */
+#define SAIOECCUNL (('d'<<8)|7) /* use standard ecc procedures */
+#define SAIORETRIES (('d'<<8)|8) /* set retry count for unit */
+#define SAIODEVDATA (('d'<<8)|9) /* get pointer to pack label */
+#define SAIOSSI (('d'<<8)|10) /* set skip sector inhibit */
+#define SAIONOSSI (('d'<<8)|11) /* inhibit skip sector handling */
+#define SAIOSSDEV (('d'<<8)|12) /* is device skip sector type? */
+#define SAIODEBUG (('d'<<8)|13) /* enable/disable debugging */
+#define SAIOGBADINFO (('d'<<8)|14) /* get bad-sector table */
diff --git a/lib/libstand/sbrk.c b/lib/libstand/sbrk.c
new file mode 100644
index 0000000..93d94e4
--- /dev/null
+++ b/lib/libstand/sbrk.c
@@ -0,0 +1,62 @@
+/*-
+ * Copyright (c) 1998 Michael Smith
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Minimal sbrk() emulation required for malloc support.
+ */
+
+#include <string.h>
+#include "stand.h"
+
+static size_t maxheap, heapsize = 0;
+static void *heapbase;
+
+void
+setheap(void *base, void *top)
+{
+ /* Align start address to 16 bytes for the malloc code. Sigh. */
+ heapbase = (void *)(((uintptr_t)base + 15) & ~15);
+ maxheap = (char *)top - (char *)heapbase;
+}
+
+char *
+sbrk(int incr)
+{
+ char *ret;
+
+ if ((heapsize + incr) <= maxheap) {
+ ret = (char *)heapbase + heapsize;
+ bzero(ret, incr);
+ heapsize += incr;
+ return(ret);
+ }
+ errno = ENOMEM;
+ return((char *)-1);
+}
+
diff --git a/lib/libstand/sparc64/_setjmp.S b/lib/libstand/sparc64/_setjmp.S
new file mode 100644
index 0000000..a661881
--- /dev/null
+++ b/lib/libstand/sparc64/_setjmp.S
@@ -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.
+ * 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.
+ *
+ * $Header: _setjmp.s,v 1.1 91/07/06 16:45:53 torek Exp
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+ .asciz "@(#)_setjmp.s 8.1 (Berkeley) 6/4/93"
+#else
+ 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$");
+
+#define _JB_FP 0x0
+#define _JB_PC 0x8
+#define _JB_SP 0x10
+
+ .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)
+ stx %sp, [%o0 + _JB_SP]
+ stx %o7, [%o0 + _JB_PC]
+ stx %fp, [%o0 + _JB_FP]
+ retl
+ clr %o0
+END(_setjmp)
+
+ENTRY(_longjmp)
+ mov 1, %g1
+ movrnz %o1, %o1, %g1
+ mov %o0, %g2
+ ldx [%g2 + _JB_FP], %g3
+1: cmp %fp, %g3
+ bl,a 1b
+ restore
+ be,a 2f
+ ldx [%g2 + _JB_SP], %o0
+
+.Lbotch:
+ illtrap
+
+2: cmp %o0, %sp
+ bge,a 3f
+ mov %o0, %sp
+ b,a .Lbotch
+ nop
+3: ldx [%g2 + _JB_PC], %o7
+ retl
+ mov %g1, %o0
+END(_longjmp)
diff --git a/lib/libstand/splitfs.c b/lib/libstand/splitfs.c
new file mode 100644
index 0000000..af28704
--- /dev/null
+++ b/lib/libstand/splitfs.c
@@ -0,0 +1,313 @@
+/*
+ * Copyright (c) 2002 Maxim Sobolev
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "stand.h"
+
+#define NTRIES (3)
+#define CONF_BUF (512)
+#define SEEK_BUF (512)
+
+struct split_file
+{
+ char **filesv; /* Filenames */
+ char **descsv; /* Descriptions */
+ int filesc; /* Number of parts */
+ int curfile; /* Current file number */
+ int curfd; /* Current file descriptor */
+ off_t tot_pos; /* Offset from the beginning of the sequence */
+ off_t file_pos; /* Offset from the beginning of the slice */
+};
+
+static int split_openfile(struct split_file *sf);
+static int splitfs_open(const char *path, struct open_file *f);
+static int splitfs_close(struct open_file *f);
+static int splitfs_read(struct open_file *f, void *buf, size_t size, size_t *resid);
+static off_t splitfs_seek(struct open_file *f, off_t offset, int where);
+static int splitfs_stat(struct open_file *f, struct stat *sb);
+
+struct fs_ops splitfs_fsops = {
+ "split",
+ splitfs_open,
+ splitfs_close,
+ splitfs_read,
+ null_write,
+ splitfs_seek,
+ splitfs_stat,
+ null_readdir
+};
+
+static void
+split_file_destroy(struct split_file *sf)
+{
+ int i;
+
+ if (sf->filesc > 0) {
+ for (i = 0; i < sf->filesc; i++) {
+ free(sf->filesv[i]);
+ free(sf->descsv[i]);
+ }
+ free(sf->filesv);
+ free(sf->descsv);
+ }
+ free(sf);
+}
+
+static int
+split_openfile(struct split_file *sf)
+{
+ int i;
+
+ for (i = 0;; i++) {
+ sf->curfd = open(sf->filesv[sf->curfile], O_RDONLY);
+ if (sf->curfd >= 0)
+ break;
+ if ((sf->curfd == -1) && (errno != ENOENT))
+ return (errno);
+ if (i == NTRIES)
+ return (EIO);
+ printf("\nInsert disk labelled %s and press any key...",
+ sf->descsv[sf->curfile]);
+ getchar();
+ putchar('\n');
+ }
+ sf->file_pos = 0;
+ return (0);
+}
+
+static int
+splitfs_open(const char *fname, struct open_file *f)
+{
+ char *buf, *confname, *cp;
+ int conffd;
+ struct split_file *sf;
+ struct stat sb;
+
+ /* Have to be in "just read it" mode */
+ if (f->f_flags != F_READ)
+ return(EPERM);
+
+ /* If the name already ends in `.split', ignore it */
+ if ((cp = strrchr(fname, '.')) && (!strcmp(cp, ".split")))
+ return(ENOENT);
+
+ /* Construct new name */
+ confname = malloc(strlen(fname) + 7);
+ sprintf(confname, "%s.split", fname);
+
+ /* Try to open the configuration file */
+ conffd = open(confname, O_RDONLY);
+ free(confname);
+ if (conffd == -1)
+ return(ENOENT);
+
+ if (fstat(conffd, &sb) < 0) {
+ printf("splitfs_open: stat failed\n");
+ close(conffd);
+ return(ENOENT);
+ }
+ if (!S_ISREG(sb.st_mode)) {
+ printf("splitfs_open: not a file\n");
+ close(conffd);
+ return(EISDIR); /* best guess */
+ }
+
+ /* Allocate a split_file structure, populate it from the config file */
+ sf = malloc(sizeof(struct split_file));
+ bzero(sf, sizeof(struct split_file));
+ buf = malloc(CONF_BUF);
+ while (fgetstr(buf, CONF_BUF, conffd) > 0) {
+ cp = buf;
+ while ((*cp != '\0') && (isspace(*cp) == 0))
+ cp++;
+ if (*cp != '\0') {
+ *cp = '\0';
+ cp++;
+ }
+ while ((*cp != '\0') && (isspace(*cp) != 0))
+ cp++;
+ if (*cp == '\0')
+ cp = buf;
+ sf->filesc++;
+ sf->filesv = realloc(sf->filesv, sizeof(*(sf->filesv)) * sf->filesc);
+ sf->descsv = realloc(sf->descsv, sizeof(*(sf->descsv)) * sf->filesc);
+ sf->filesv[sf->filesc - 1] = strdup(buf);
+ sf->descsv[sf->filesc - 1] = strdup(cp);
+ }
+ free(buf);
+ close(conffd);
+
+ if (sf->filesc == 0) {
+ split_file_destroy(sf);
+ return(ENOENT);
+ }
+ errno = split_openfile(sf);
+ if (errno != 0) {
+ split_file_destroy(sf);
+ return(ENOENT);
+ }
+
+ /* Looks OK, we'll take it */
+ f->f_fsdata = sf;
+ return (0);
+}
+
+static int
+splitfs_close(struct open_file *f)
+{
+ int fd;
+ struct split_file *sf;
+
+ sf = (struct split_file *)f->f_fsdata;
+ fd = sf->curfd;
+ split_file_destroy(sf);
+ return(close(fd));
+}
+
+static int
+splitfs_read(struct open_file *f, void *buf, size_t size, size_t *resid)
+{
+ ssize_t nread;
+ size_t totread;
+ struct split_file *sf;
+
+ sf = (struct split_file *)f->f_fsdata;
+ totread = 0;
+ do {
+ nread = read(sf->curfd, buf, size - totread);
+
+ /* Error? */
+ if (nread == -1)
+ return (errno);
+
+ sf->tot_pos += nread;
+ sf->file_pos += nread;
+ totread += nread;
+ buf = (char *)buf + nread;
+
+ if (totread < size) { /* EOF */
+ if (sf->curfile == (sf->filesc - 1)) /* Last slice */
+ break;
+
+ /* Close previous slice */
+ if (close(sf->curfd) != 0)
+ return (errno);
+
+ sf->curfile++;
+ errno = split_openfile(sf);
+ if (errno)
+ return (errno);
+ }
+ } while (totread < size);
+
+ if (resid != NULL)
+ *resid = size - totread;
+
+ return (0);
+}
+
+static off_t
+splitfs_seek(struct open_file *f, off_t offset, int where)
+{
+ int nread;
+ size_t resid;
+ off_t new_pos, seek_by;
+ struct split_file *sf;
+
+ sf = (struct split_file *)f->f_fsdata;
+
+ seek_by = offset;
+ switch (where) {
+ case SEEK_SET:
+ seek_by -= sf->tot_pos;
+ break;
+ case SEEK_CUR:
+ break;
+ case SEEK_END:
+ panic("splitfs_seek: SEEK_END not supported");
+ break;
+ default:
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (seek_by > 0) {
+ /*
+ * Seek forward - implemented using splitfs_read(), because otherwise we'll be
+ * unable to detect that we have crossed slice boundary and hence
+ * unable to do a long seek crossing that boundary.
+ */
+ void *tmp;
+
+ tmp = malloc(SEEK_BUF);
+ if (tmp == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+
+ nread = 0;
+ for (; seek_by > 0; seek_by -= nread) {
+ resid = 0;
+ errno = splitfs_read(f, tmp, min(seek_by, SEEK_BUF), &resid);
+ nread = min(seek_by, SEEK_BUF) - resid;
+ if ((errno != 0) || (nread == 0))
+ /* Error or EOF */
+ break;
+ }
+ free(tmp);
+ if (errno != 0)
+ return (-1);
+ }
+
+ if (seek_by != 0) {
+ /* Seek backward or seek past the boundary of the last slice */
+ if (sf->file_pos + seek_by < 0)
+ panic("splitfs_seek: can't seek past the beginning of the slice");
+ new_pos = lseek(sf->curfd, seek_by, SEEK_CUR);
+ if (new_pos < 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+ sf->tot_pos += new_pos - sf->file_pos;
+ sf->file_pos = new_pos;
+ }
+
+ return (sf->tot_pos);
+}
+
+static int
+splitfs_stat(struct open_file *f, struct stat *sb)
+{
+ int result;
+ struct split_file *sf = (struct split_file *)f->f_fsdata;
+
+ /* stat as normal, but indicate that size is unknown */
+ if ((result = fstat(sf->curfd, sb)) == 0)
+ sb->st_size = -1;
+ return (result);
+}
diff --git a/lib/libstand/stand.h b/lib/libstand/stand.h
new file mode 100644
index 0000000..2279bc7
--- /dev/null
+++ b/lib/libstand/stand.h
@@ -0,0 +1,415 @@
+/*
+ * Copyright (c) 1998 Michael Smith.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ * From $NetBSD: stand.h,v 1.22 1997/06/26 19:17:40 drochner Exp $
+ */
+
+/*-
+ * 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.
+ * 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.
+ *
+ * @(#)stand.h 8.1 (Berkeley) 6/11/93
+ */
+
+#ifndef STAND_H
+#define STAND_H
+
+#include <sys/types.h>
+#include <sys/cdefs.h>
+#include <sys/stat.h>
+#include <sys/dirent.h>
+#include <string.h>
+
+#define CHK(fmt, args...) printf("%s(%d): " fmt "\n", __func__, __LINE__ , ##args)
+#define PCHK(fmt, args...) {printf("%s(%d): " fmt "\n", __func__, __LINE__ , ##args); getchar();}
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+/* Avoid unwanted userlandish components */
+#define _KERNEL
+#include <sys/errno.h>
+#undef _KERNEL
+
+/* special stand error codes */
+#define EADAPT (ELAST+1) /* bad adaptor */
+#define ECTLR (ELAST+2) /* bad controller */
+#define EUNIT (ELAST+3) /* bad unit */
+#define ESLICE (ELAST+4) /* bad slice */
+#define EPART (ELAST+5) /* bad partition */
+#define ERDLAB (ELAST+6) /* can't read disk label */
+#define EUNLAB (ELAST+7) /* unlabeled disk */
+#define EOFFSET (ELAST+8) /* relative seek not supported */
+#define ESALAST (ELAST+8) /* */
+
+struct open_file;
+
+/*
+ * This structure is used to define file system operations in a file system
+ * independent way.
+ *
+ * XXX note that filesystem providers should export a pointer to their fs_ops
+ * struct, so that consumers can reference this and thus include the
+ * filesystems that they require.
+ */
+struct fs_ops {
+ const char *fs_name;
+ int (*fo_open)(const char *path, struct open_file *f);
+ int (*fo_close)(struct open_file *f);
+ int (*fo_read)(struct open_file *f, void *buf,
+ size_t size, size_t *resid);
+ int (*fo_write)(struct open_file *f, void *buf,
+ size_t size, size_t *resid);
+ off_t (*fo_seek)(struct open_file *f, off_t offset, int where);
+ int (*fo_stat)(struct open_file *f, struct stat *sb);
+ int (*fo_readdir)(struct open_file *f, struct dirent *d);
+};
+
+/*
+ * libstand-supplied filesystems
+ */
+extern struct fs_ops ufs_fsops;
+extern struct fs_ops tftp_fsops;
+extern struct fs_ops nfs_fsops;
+extern struct fs_ops cd9660_fsops;
+extern struct fs_ops gzipfs_fsops;
+extern struct fs_ops bzipfs_fsops;
+extern struct fs_ops dosfs_fsops;
+extern struct fs_ops ext2fs_fsops;
+extern struct fs_ops splitfs_fsops;
+
+/* where values for lseek(2) */
+#define SEEK_SET 0 /* set file offset to offset */
+#define SEEK_CUR 1 /* set file offset to current plus offset */
+#define SEEK_END 2 /* set file offset to EOF plus offset */
+
+/*
+ * Device switch
+ */
+struct devsw {
+ const char dv_name[8];
+ int dv_type; /* opaque type constant, arch-dependant */
+ int (*dv_init)(void); /* early probe call */
+ int (*dv_strategy)(void *devdata, int rw, daddr_t blk, size_t size,
+ char *buf, size_t *rsize);
+ int (*dv_open)(struct open_file *f, ...);
+ int (*dv_close)(struct open_file *f);
+ int (*dv_ioctl)(struct open_file *f, u_long cmd, void *data);
+ void (*dv_print)(int verbose); /* print device information */
+ void (*dv_cleanup)(void);
+};
+
+/*
+ * libstand-supplied device switch
+ */
+extern struct devsw netdev;
+
+extern int errno;
+
+struct open_file {
+ int f_flags; /* see F_* below */
+ struct devsw *f_dev; /* pointer to device operations */
+ void *f_devdata; /* device specific data */
+ struct fs_ops *f_ops; /* pointer to file system operations */
+ void *f_fsdata; /* file system specific data */
+ off_t f_offset; /* current file offset */
+ char *f_rabuf; /* readahead buffer pointer */
+ size_t f_ralen; /* valid data in readahead buffer */
+ off_t f_raoffset; /* consumer offset in readahead buffer */
+#define SOPEN_RASIZE 512
+};
+
+#define SOPEN_MAX 8
+extern struct open_file files[];
+
+/* f_flags values */
+#define F_READ 0x0001 /* file opened for reading */
+#define F_WRITE 0x0002 /* file opened for writing */
+#define F_RAW 0x0004 /* raw device open - no file system */
+#define F_NODEV 0x0008 /* network open - no device */
+
+#define isascii(c) (((c) & ~0x7F) == 0)
+
+static __inline int isupper(int c)
+{
+ return c >= 'A' && c <= 'Z';
+}
+
+static __inline int islower(int c)
+{
+ return c >= 'a' && c <= 'z';
+}
+
+static __inline int isspace(int c)
+{
+ return c == ' ' || (c >= 0x9 && c <= 0xd);
+}
+
+static __inline int isdigit(int c)
+{
+ return c >= '0' && c <= '9';
+}
+
+static __inline int isxdigit(int c)
+{
+ return isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
+}
+
+static __inline int isalpha(int c)
+{
+ return isupper(c) || islower(c);
+}
+
+static __inline int isalnum(int c)
+{
+ return isalpha(c) || isdigit(c);
+}
+
+static __inline int toupper(int c)
+{
+ return islower(c) ? c - 'a' + 'A' : c;
+}
+
+static __inline int tolower(int c)
+{
+ return isupper(c) ? c - 'A' + 'a' : c;
+}
+
+/* sbrk emulation */
+extern void setheap(void *base, void *top);
+extern char *sbrk(int incr);
+
+/* Matt Dillon's zalloc/zmalloc */
+extern void *malloc(size_t bytes);
+extern void free(void *ptr);
+/*#define free(p) {CHK("free %p", p); free(p);} */ /* use for catching guard violations */
+extern void *calloc(size_t n1, size_t n2);
+extern void *realloc(void *ptr, size_t size);
+extern void *reallocf(void *ptr, size_t size);
+extern void mallocstats(void);
+#ifdef __alpha__
+extern void free_region(void *start, void *end);
+#endif
+
+/* disklabel support (undocumented, may be junk) */
+struct disklabel;
+extern char *getdisklabel(const char *, struct disklabel *);
+
+extern int printf(const char *fmt, ...) __printflike(1, 2);
+extern void vprintf(const char *fmt, __va_list);
+extern int sprintf(char *buf, const char *cfmt, ...) __printflike(2, 3);
+extern void vsprintf(char *buf, const char *cfmt, __va_list);
+
+extern void twiddle(void);
+
+extern void ngets(char *, int);
+#define gets(x) ngets((x), 0)
+extern int fgetstr(char *buf, int size, int fd);
+
+extern int open(const char *, int);
+#define O_RDONLY 0x0
+#define O_WRONLY 0x1
+#define O_RDWR 0x2
+extern int close(int);
+extern void closeall(void);
+extern ssize_t read(int, void *, size_t);
+extern ssize_t write(int, void *, size_t);
+extern struct dirent *readdirfd(int);
+
+extern void srandom(u_long seed);
+extern u_long random(void);
+
+/* imports from stdlib, locally modified */
+extern long strtol(const char *, char **, int);
+extern char *optarg; /* getopt(3) external variables */
+extern int optind, opterr, optopt, optreset;
+extern int getopt(int, char * const [], const char *);
+
+/* pager.c */
+extern void pager_open(void);
+extern void pager_close(void);
+extern int pager_output(const char *lines);
+extern int pager_file(const char *fname);
+
+/* No signal state to preserve */
+#define setjmp _setjmp
+#define longjmp _longjmp
+
+/* environment.c */
+#define EV_DYNAMIC (1<<0) /* value was dynamically allocated, free if changed/unset */
+#define EV_VOLATILE (1<<1) /* value is volatile, make a copy of it */
+#define EV_NOHOOK (1<<2) /* don't call hook when setting */
+
+struct env_var;
+typedef char *(ev_format_t)(struct env_var *ev);
+typedef int (ev_sethook_t)(struct env_var *ev, int flags,
+ const void *value);
+typedef int (ev_unsethook_t)(struct env_var *ev);
+
+struct env_var
+{
+ char *ev_name;
+ int ev_flags;
+ void *ev_value;
+ ev_sethook_t *ev_sethook;
+ ev_unsethook_t *ev_unsethook;
+ struct env_var *ev_next, *ev_prev;
+};
+extern struct env_var *environ;
+
+extern struct env_var *env_getenv(const char *name);
+extern int env_setenv(const char *name, int flags,
+ const void *value, ev_sethook_t sethook,
+ ev_unsethook_t unsethook);
+extern char *getenv(const char *name);
+extern int setenv(const char *name, const char *value,
+ int overwrite);
+extern int putenv(const char *string);
+extern int unsetenv(const char *name);
+
+extern ev_sethook_t env_noset; /* refuse set operation */
+extern ev_unsethook_t env_nounset; /* refuse unset operation */
+
+/* BCD conversions (undocumented) */
+extern u_char const bcd2bin_data[];
+extern u_char const bin2bcd_data[];
+extern char const hex2ascii_data[];
+
+#define bcd2bin(bcd) (bcd2bin_data[bcd])
+#define bin2bcd(bin) (bin2bcd_data[bin])
+#define hex2ascii(hex) (hex2ascii_data[hex])
+
+/* min/max (undocumented) */
+static __inline int imax(int a, int b) { return (a > b ? a : b); }
+static __inline int imin(int a, int b) { return (a < b ? a : b); }
+static __inline long lmax(long a, long b) { return (a > b ? a : b); }
+static __inline long lmin(long a, long b) { return (a < b ? a : b); }
+static __inline u_int max(u_int a, u_int b) { return (a > b ? a : b); }
+static __inline u_int min(u_int a, u_int b) { return (a < b ? a : b); }
+static __inline quad_t qmax(quad_t a, quad_t b) { return (a > b ? a : b); }
+static __inline quad_t qmin(quad_t a, quad_t b) { return (a < b ? a : b); }
+static __inline u_long ulmax(u_long a, u_long b) { return (a > b ? a : b); }
+static __inline u_long ulmin(u_long a, u_long b) { return (a < b ? a : b); }
+
+/* swaps (undocumented, useful?) */
+#ifdef __i386__
+extern u_int32_t bswap32(u_int32_t x);
+extern u_int64_t bswap64(u_int64_t x);
+#endif
+
+/* null functions for device/filesystem switches (undocumented) */
+extern int nodev(void);
+extern int noioctl(struct open_file *, u_long, void *);
+extern void nullsys(void);
+
+extern int null_open(const char *path, struct open_file *f);
+extern int null_close(struct open_file *f);
+extern int null_read(struct open_file *f, void *buf, size_t size, size_t *resid);
+extern int null_write(struct open_file *f, void *buf, size_t size, size_t *resid);
+extern off_t null_seek(struct open_file *f, off_t offset, int where);
+extern int null_stat(struct open_file *f, struct stat *sb);
+extern int null_readdir(struct open_file *f, struct dirent *d);
+
+
+/*
+ * Machine dependent functions and data, must be provided or stubbed by
+ * the consumer
+ */
+extern int getchar(void);
+extern int ischar(void);
+extern void putchar(int);
+extern int devopen(struct open_file *, const char *, const char **);
+extern int devclose(struct open_file *f);
+extern void panic(const char *, ...) __dead2 __printflike(1, 2);
+extern struct fs_ops *file_system[];
+extern struct devsw *devsw[];
+
+/*
+ * Expose byteorder(3) functions.
+ */
+#ifndef _BYTEORDER_PROTOTYPED
+#define _BYTEORDER_PROTOTYPED
+extern uint32_t htonl(uint32_t);
+extern uint16_t htons(uint16_t);
+extern uint32_t ntohl(uint32_t);
+extern uint16_t ntohs(uint16_t);
+#endif
+
+#ifndef _BYTEORDER_FUNC_DEFINED
+#define _BYTEORDER_FUNC_DEFINED
+#define htonl(x) __htonl(x)
+#define htons(x) __htons(x)
+#define ntohl(x) __ntohl(x)
+#define ntohs(x) __ntohs(x)
+#endif
+
+void *Malloc(size_t, const char *, int);
+void *Calloc(size_t, size_t, const char *, int);
+void *Realloc(void *, size_t, const char *, int);
+void Free(void *, const char *, int);
+
+#if 1
+#define malloc(x) Malloc(x, __FILE__, __LINE__)
+#define calloc(x, y) Calloc(x, y, __FILE__, __LINE__)
+#define free(x) Free(x, __FILE__, __LINE__)
+#define realloc(x, y) Realloc(x, y, __FILE__, __LINE__)
+#else
+#define malloc(x) Malloc(x, NULL, 0)
+#define calloc(x, y) Calloc(x, y, NULL, 0)
+#define free(x) Free(x, NULL, 0)
+#define realloc(x, y) Realloc(x, y, NULL, 0)
+#endif
+
+#endif /* STAND_H */
diff --git a/lib/libstand/stat.c b/lib/libstand/stat.c
new file mode 100644
index 0000000..8593281
--- /dev/null
+++ b/lib/libstand/stat.c
@@ -0,0 +1,56 @@
+/* $NetBSD: stat.c,v 1.4 1996/01/13 22:25:43 leo Exp $ */
+
+/*-
+ * 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.
+ * 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.
+ *
+ * @(#)stat.c 8.1 (Berkeley) 6/11/93
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "stand.h"
+
+int
+stat(str, sb)
+ const char *str;
+ struct stat *sb;
+{
+ int fd, rv;
+
+ fd = open(str, O_RDONLY);
+ if (fd < 0)
+ return (-1);
+ rv = fstat(fd, sb);
+ (void)close(fd);
+ return (rv);
+}
diff --git a/lib/libstand/strcasecmp.c b/lib/libstand/strcasecmp.c
new file mode 100644
index 0000000..9eb8350
--- /dev/null
+++ b/lib/libstand/strcasecmp.c
@@ -0,0 +1,77 @@
+/*
+ * 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. 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/cdefs.h>
+#include <string.h>
+#include "stand.h"
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strcasecmp.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+int
+strcasecmp(s1, s2)
+ const char *s1, *s2;
+{
+ const u_char
+ *us1 = (const u_char *)s1,
+ *us2 = (const u_char *)s2;
+
+ while (tolower(*us1) == tolower(*us2++))
+ if (*us1++ == '\0')
+ return (0);
+ return (tolower(*us1) - tolower(*--us2));
+}
+
+int
+strncasecmp(s1, s2, n)
+ const char *s1, *s2;
+ size_t n;
+{
+ if (n != 0) {
+ const u_char
+ *us1 = (const u_char *)s1,
+ *us2 = (const u_char *)s2;
+
+ do {
+ if (tolower(*us1) != tolower(*us2++))
+ return (tolower(*us1) - tolower(*--us2));
+ if (*us1++ == '\0')
+ break;
+ } while (--n != 0);
+ }
+ return (0);
+}
diff --git a/lib/libstand/strdup.c b/lib/libstand/strdup.c
new file mode 100644
index 0000000..2204d33
--- /dev/null
+++ b/lib/libstand/strdup.c
@@ -0,0 +1,59 @@
+/*
+ * 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. 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strdup.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+#include "stand.h"
+#include <stddef.h>
+#include <string.h>
+
+char *
+strdup(str)
+ const char *str;
+{
+ size_t len;
+ char *copy = NULL;
+
+ if (str != NULL) {
+ len = strlen(str) + 1;
+ if ((copy = malloc(len)) == NULL)
+ return (NULL);
+ memcpy(copy, str, len);
+ }
+ return (copy);
+}
diff --git a/lib/libstand/strerror.c b/lib/libstand/strerror.c
new file mode 100644
index 0000000..7c7f579
--- /dev/null
+++ b/lib/libstand/strerror.c
@@ -0,0 +1,91 @@
+/* $NetBSD: strerror.c,v 1.12 1997/01/25 00:37:50 cgd Exp $ */
+
+/*-
+ * 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.
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "stand.h"
+
+static struct
+{
+ int err;
+ char *msg;
+} errtab[] = {
+ {0, "no error"},
+ /* standard errors */
+ {EPERM, "operation not permitted"},
+ {ENOENT, "no such file or directory"},
+ {EIO, "input/output error"},
+ {ENXIO, "device not configured"},
+ {ENOEXEC, "exec format error"},
+ {EBADF, "bad file descriptor"},
+ {ENOMEM, "cannot allocate memory"},
+ {ENODEV, "operation not supported by device"},
+ {ENOTDIR, "not a directory"},
+ {EISDIR, "is a directory"},
+ {EINVAL, "invalid argument"},
+ {EMFILE, "too many open files"},
+ {EFBIG, "file too large"},
+ {EROFS, "read-only filesystem"},
+ {EOPNOTSUPP, "operation not supported"},
+ {ETIMEDOUT, "operation timed out"},
+ {ESTALE, "stale NFS file handle"},
+ {EBADRPC, "RPC struct is bad"},
+ {EFTYPE, "inappropriate file type or format"},
+
+ {EADAPT, "bad adaptor number"},
+ {ECTLR, "bad controller number"},
+ {EUNIT, "bad unit number"},
+ {ESLICE, "bad slice number"},
+ {EPART, "bad partition"},
+ {ERDLAB, "can't read disk label"},
+ {EUNLAB, "disk unlabelled"},
+ {EOFFSET, "illegal seek"},
+ {0, NULL}
+};
+
+
+char *
+strerror(int err)
+{
+ static char msg[32];
+ int i;
+
+ for (i = 0; errtab[i].msg != NULL; i++)
+ if (errtab[i].err == err)
+ return(errtab[i].msg);
+ sprintf(msg, "unknown error (%d)", err);
+ return(msg);
+}
diff --git a/lib/libstand/strtol.c b/lib/libstand/strtol.c
new file mode 100644
index 0000000..4844a1a
--- /dev/null
+++ b/lib/libstand/strtol.c
@@ -0,0 +1,136 @@
+/*-
+ * 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. 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strtol.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+#include "stand.h"
+#include <limits.h>
+
+/*
+ * Convert a string to a long integer.
+ *
+ * Ignores `locale' stuff. Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+long
+strtol(nptr, endptr, base)
+ const char *nptr;
+ char **endptr;
+ int base;
+{
+ const char *s;
+ unsigned long acc;
+ unsigned char c;
+ unsigned long cutoff;
+ int neg = 0, any, cutlim;
+
+ /* Be sensible about NULL strings */
+ if (nptr == NULL)
+ nptr = "";
+ s = nptr;
+
+ /*
+ * 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.
+ */
+ do {
+ c = *s++;
+ } while (isspace(c));
+ if (c == '-') {
+ neg = 1;
+ c = *s++;
+ } else 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 ? -(unsigned long)LONG_MIN : LONG_MAX;
+ cutlim = cutoff % (unsigned long)base;
+ cutoff /= (unsigned long)base;
+ for (acc = 0, any = 0;; c = *s++) {
+ if (!isascii(c))
+ break;
+ if (isdigit(c))
+ c -= '0';
+ else if (isalpha(c))
+ c -= isupper(c) ? 'A' - 10 : '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 (neg)
+ acc = -acc;
+ if (endptr != 0)
+ *endptr = (char *)(any ? s - 1 : nptr);
+ return (acc);
+}
diff --git a/lib/libstand/tftp.c b/lib/libstand/tftp.c
new file mode 100644
index 0000000..0cbfa52
--- /dev/null
+++ b/lib/libstand/tftp.c
@@ -0,0 +1,426 @@
+/* $NetBSD: tftp.c,v 1.4 1997/09/17 16:57:07 drochner Exp $ */
+
+/*
+ * Copyright (c) 1996
+ * Matthias Drochner. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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 Matthias Drochner.
+ * 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$");
+
+/*
+ * Simple TFTP implementation for libsa.
+ * Assumes:
+ * - socket descriptor (int) at open_file->f_devdata
+ * - server host IP in global servip
+ * Restrictions:
+ * - read only
+ * - lseek only with SEEK_SET or SEEK_CUR
+ * - no big time differences between transfers (<tftp timeout)
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <netinet/udp.h>
+#include <netinet/in_systm.h>
+#include <arpa/tftp.h>
+
+#include <string.h>
+
+#include "stand.h"
+#include "net.h"
+#include "netif.h"
+
+#include "tftp.h"
+
+static int tftp_open(const char *path, struct open_file *f);
+static int tftp_close(struct open_file *f);
+static int tftp_read(struct open_file *f, void *buf, size_t size, size_t *resid);
+static int tftp_write(struct open_file *f, void *buf, size_t size, size_t *resid);
+static off_t tftp_seek(struct open_file *f, off_t offset, int where);
+static int tftp_stat(struct open_file *f, struct stat *sb);
+
+struct fs_ops tftp_fsops = {
+ "tftp",
+ tftp_open,
+ tftp_close,
+ tftp_read,
+ tftp_write,
+ tftp_seek,
+ tftp_stat,
+ null_readdir
+};
+
+extern struct in_addr servip;
+
+static int tftpport = 2000;
+
+#define RSPACE 520 /* max data packet, rounded up */
+
+struct tftp_handle {
+ struct iodesc *iodesc;
+ int currblock; /* contents of lastdata */
+ int islastblock; /* flag */
+ int validsize;
+ int off;
+ char *path; /* saved for re-requests */
+ struct {
+ u_char header[HEADER_SIZE];
+ struct tftphdr t;
+ u_char space[RSPACE];
+ } lastdata;
+};
+
+static int tftperrors[8] = {
+ 0, /* ??? */
+ ENOENT,
+ EPERM,
+ ENOSPC,
+ EINVAL, /* ??? */
+ EINVAL, /* ??? */
+ EEXIST,
+ EINVAL /* ??? */
+};
+
+static ssize_t
+recvtftp(d, pkt, len, tleft)
+ struct iodesc *d;
+ void *pkt;
+ ssize_t len;
+ time_t tleft;
+{
+ struct tftphdr *t;
+
+ errno = 0;
+
+ len = readudp(d, pkt, len, tleft);
+
+ if (len < 4)
+ return (-1);
+
+ t = (struct tftphdr *) pkt;
+ switch (ntohs(t->th_opcode)) {
+ case DATA: {
+ int got;
+
+ if (htons(t->th_block) != d->xid) {
+ /*
+ * Expected block?
+ */
+ return (-1);
+ }
+ if (d->xid == 1) {
+ /*
+ * First data packet from new port.
+ */
+ struct udphdr *uh;
+ uh = (struct udphdr *) pkt - 1;
+ d->destport = uh->uh_sport;
+ } /* else check uh_sport has not changed??? */
+ got = len - (t->th_data - (char *) t);
+ return got;
+ }
+ case ERROR:
+ if ((unsigned) ntohs(t->th_code) >= 8) {
+ printf("illegal tftp error %d\n", ntohs(t->th_code));
+ errno = EIO;
+ } else {
+#ifdef DEBUG
+ printf("tftp-error %d\n", ntohs(t->th_code));
+#endif
+ errno = tftperrors[ntohs(t->th_code)];
+ }
+ return (-1);
+ default:
+#ifdef DEBUG
+ printf("tftp type %d not handled\n", ntohs(t->th_opcode));
+#endif
+ return (-1);
+ }
+}
+
+/* send request, expect first block (or error) */
+static int
+tftp_makereq(h)
+ struct tftp_handle *h;
+{
+ struct {
+ u_char header[HEADER_SIZE];
+ struct tftphdr t;
+ u_char space[FNAME_SIZE + 6];
+ } wbuf;
+ char *wtail;
+ int l;
+ ssize_t res;
+ struct tftphdr *t;
+
+ wbuf.t.th_opcode = htons((u_short) RRQ);
+ wtail = wbuf.t.th_stuff;
+ l = strlen(h->path);
+ bcopy(h->path, wtail, l + 1);
+ wtail += l + 1;
+ bcopy("octet", wtail, 6);
+ wtail += 6;
+
+ t = &h->lastdata.t;
+
+ /* h->iodesc->myport = htons(--tftpport); */
+ h->iodesc->myport = htons(tftpport + (getsecs() & 0x3ff));
+ h->iodesc->destport = htons(IPPORT_TFTP);
+ h->iodesc->xid = 1; /* expected block */
+
+ res = sendrecv(h->iodesc, sendudp, &wbuf.t, wtail - (char *) &wbuf.t,
+ recvtftp, t, sizeof(*t) + RSPACE);
+
+ if (res == -1)
+ return (errno);
+
+ h->currblock = 1;
+ h->validsize = res;
+ h->islastblock = 0;
+ if (res < SEGSIZE)
+ h->islastblock = 1; /* very short file */
+ return (0);
+}
+
+/* ack block, expect next */
+static int
+tftp_getnextblock(h)
+ struct tftp_handle *h;
+{
+ struct {
+ u_char header[HEADER_SIZE];
+ struct tftphdr t;
+ } wbuf;
+ char *wtail;
+ int res;
+ struct tftphdr *t;
+
+ wbuf.t.th_opcode = htons((u_short) ACK);
+ wtail = (char *) &wbuf.t.th_block;
+ wbuf.t.th_block = htons((u_short) h->currblock);
+ wtail += 2;
+
+ t = &h->lastdata.t;
+
+ h->iodesc->xid = h->currblock + 1; /* expected block */
+
+ res = sendrecv(h->iodesc, sendudp, &wbuf.t, wtail - (char *) &wbuf.t,
+ recvtftp, t, sizeof(*t) + RSPACE);
+
+ if (res == -1) /* 0 is OK! */
+ return (errno);
+
+ h->currblock++;
+ h->validsize = res;
+ if (res < SEGSIZE)
+ h->islastblock = 1; /* EOF */
+ return (0);
+}
+
+static int
+tftp_open(path, f)
+ const char *path;
+ struct open_file *f;
+{
+ struct tftp_handle *tftpfile;
+ struct iodesc *io;
+ int res;
+
+#ifndef __i386__
+ if (strcmp(f->f_dev->dv_name, "net") != 0)
+ return (EINVAL);
+#endif
+
+ tftpfile = (struct tftp_handle *) malloc(sizeof(*tftpfile));
+ if (!tftpfile)
+ return (ENOMEM);
+
+ tftpfile->iodesc = io = socktodesc(*(int *) (f->f_devdata));
+ if (io == NULL)
+ return (EINVAL);
+
+ io->destip = servip;
+ tftpfile->off = 0;
+ tftpfile->path = strdup(path);
+ if (tftpfile->path == NULL) {
+ free(tftpfile);
+ return(ENOMEM);
+ }
+
+ res = tftp_makereq(tftpfile, path);
+
+ if (res) {
+ free(tftpfile->path);
+ free(tftpfile);
+ return (res);
+ }
+ f->f_fsdata = (void *) tftpfile;
+ return (0);
+}
+
+static int
+tftp_read(f, addr, size, resid)
+ struct open_file *f;
+ void *addr;
+ size_t size;
+ size_t *resid; /* out */
+{
+ struct tftp_handle *tftpfile;
+ static int tc = 0;
+ tftpfile = (struct tftp_handle *) f->f_fsdata;
+
+ while (size > 0) {
+ int needblock, count;
+
+ if (!(tc++ % 16))
+ twiddle();
+
+ needblock = tftpfile->off / SEGSIZE + 1;
+
+ if (tftpfile->currblock > needblock) /* seek backwards */
+ tftp_makereq(tftpfile); /* no error check, it worked
+ * for open */
+
+ while (tftpfile->currblock < needblock) {
+ int res;
+
+ res = tftp_getnextblock(tftpfile);
+ if (res) { /* no answer */
+#ifdef DEBUG
+ printf("tftp: read error\n");
+#endif
+ return (res);
+ }
+ if (tftpfile->islastblock)
+ break;
+ }
+
+ if (tftpfile->currblock == needblock) {
+ int offinblock, inbuffer;
+
+ offinblock = tftpfile->off % SEGSIZE;
+
+ inbuffer = tftpfile->validsize - offinblock;
+ if (inbuffer < 0) {
+#ifdef DEBUG
+ printf("tftp: invalid offset %d\n",
+ tftpfile->off);
+#endif
+ return (EINVAL);
+ }
+ count = (size < inbuffer ? size : inbuffer);
+ bcopy(tftpfile->lastdata.t.th_data + offinblock,
+ addr, count);
+
+ addr = (char *)addr + count;
+ tftpfile->off += count;
+ size -= count;
+
+ if ((tftpfile->islastblock) && (count == inbuffer))
+ break; /* EOF */
+ } else {
+#ifdef DEBUG
+ printf("tftp: block %d not found\n", needblock);
+#endif
+ return (EINVAL);
+ }
+
+ }
+
+ if (resid)
+ *resid = size;
+ return (0);
+}
+
+static int
+tftp_close(f)
+ struct open_file *f;
+{
+ struct tftp_handle *tftpfile;
+ tftpfile = (struct tftp_handle *) f->f_fsdata;
+
+ /* let it time out ... */
+
+ if (tftpfile) {
+ free(tftpfile->path);
+ free(tftpfile);
+ }
+ return (0);
+}
+
+static int
+tftp_write(f, start, size, resid)
+ struct open_file *f;
+ void *start;
+ size_t size;
+ size_t *resid; /* out */
+{
+ return (EROFS);
+}
+
+static int
+tftp_stat(f, sb)
+ struct open_file *f;
+ struct stat *sb;
+{
+ struct tftp_handle *tftpfile;
+ tftpfile = (struct tftp_handle *) f->f_fsdata;
+
+ sb->st_mode = 0444 | S_IFREG;
+ sb->st_nlink = 1;
+ sb->st_uid = 0;
+ sb->st_gid = 0;
+ sb->st_size = -1;
+ return (0);
+}
+
+static off_t
+tftp_seek(f, offset, where)
+ struct open_file *f;
+ off_t offset;
+ int where;
+{
+ struct tftp_handle *tftpfile;
+ tftpfile = (struct tftp_handle *) f->f_fsdata;
+
+ switch (where) {
+ case SEEK_SET:
+ tftpfile->off = offset;
+ break;
+ case SEEK_CUR:
+ tftpfile->off += offset;
+ break;
+ default:
+ errno = EOFFSET;
+ return (-1);
+ }
+ return (tftpfile->off);
+}
diff --git a/lib/libstand/tftp.h b/lib/libstand/tftp.h
new file mode 100644
index 0000000..cbbbbd7
--- /dev/null
+++ b/lib/libstand/tftp.h
@@ -0,0 +1,36 @@
+/* $NetBSD: tftp.h,v 1.1.1.1 1997/03/14 02:40:31 perry Exp $ */
+
+/*
+ * Copyright (c) 1996
+ * Matthias Drochner. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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 Matthias Drochner.
+ * 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.
+ *
+ */
+
+
+#define IPPORT_TFTP 69
diff --git a/lib/libstand/twiddle.c b/lib/libstand/twiddle.c
new file mode 100644
index 0000000..46bd895
--- /dev/null
+++ b/lib/libstand/twiddle.c
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 1986, 1988, 1991, 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.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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.
+ *
+ * @(#)subr_prf.c 8.3 (Berkeley) 1/21/94
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include "stand.h"
+
+/* Extra functions from NetBSD standalone printf.c */
+
+void
+twiddle()
+{
+ static int pos;
+
+ putchar("|/-\\"[pos++ & 3]);
+ putchar('\b');
+}
diff --git a/lib/libstand/udp.c b/lib/libstand/udp.c
new file mode 100644
index 0000000..5f4a5df
--- /dev/null
+++ b/lib/libstand/udp.c
@@ -0,0 +1,275 @@
+/* Taken from $NetBSD: net.c,v 1.20 1997/12/26 22:41:30 scottr Exp $ */
+
+/*
+ * Copyright (c) 1992 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.
+ * 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, Lawrence Berkeley Laboratory 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.
+ *
+ * @(#) Header: net.c,v 1.9 93/08/06 19:32:15 leres Exp (LBL)
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <string.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <netinet/in_systm.h>
+
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+
+#include "stand.h"
+#include "net.h"
+
+/* Caller must leave room for ethernet, ip and udp headers in front!! */
+ssize_t
+sendudp(d, pkt, len)
+ struct iodesc *d;
+ void *pkt;
+ size_t len;
+{
+ ssize_t cc;
+ struct ip *ip;
+ struct udphdr *uh;
+ u_char *ea;
+
+#ifdef NET_DEBUG
+ if (debug) {
+ printf("sendudp: d=%lx called.\n", (long)d);
+ if (d) {
+ printf("saddr: %s:%d",
+ inet_ntoa(d->myip), ntohs(d->myport));
+ printf(" daddr: %s:%d\n",
+ inet_ntoa(d->destip), ntohs(d->destport));
+ }
+ }
+#endif
+
+ uh = (struct udphdr *)pkt - 1;
+ ip = (struct ip *)uh - 1;
+ len += sizeof(*ip) + sizeof(*uh);
+
+ bzero(ip, sizeof(*ip) + sizeof(*uh));
+
+ ip->ip_v = IPVERSION; /* half-char */
+ ip->ip_hl = sizeof(*ip) >> 2; /* half-char */
+ ip->ip_len = htons(len);
+ ip->ip_p = IPPROTO_UDP; /* char */
+ ip->ip_ttl = IP_TTL; /* char */
+ ip->ip_src = d->myip;
+ ip->ip_dst = d->destip;
+ ip->ip_sum = in_cksum(ip, sizeof(*ip)); /* short, but special */
+
+ uh->uh_sport = d->myport;
+ uh->uh_dport = d->destport;
+ uh->uh_ulen = htons(len - sizeof(*ip));
+
+#ifndef UDP_NO_CKSUM
+ {
+ struct udpiphdr *ui;
+ struct ip tip;
+
+ /* Calculate checksum (must save and restore ip header) */
+ tip = *ip;
+ ui = (struct udpiphdr *)ip;
+ bzero(&ui->ui_x1, sizeof(ui->ui_x1));
+ ui->ui_len = uh->uh_ulen;
+ uh->uh_sum = in_cksum(ui, len);
+ *ip = tip;
+ }
+#endif
+
+ if (ip->ip_dst.s_addr == INADDR_BROADCAST || ip->ip_src.s_addr == 0 ||
+ netmask == 0 || SAMENET(ip->ip_src, ip->ip_dst, netmask))
+ ea = arpwhohas(d, ip->ip_dst);
+ else
+ ea = arpwhohas(d, gateip);
+
+ cc = sendether(d, ip, len, ea, ETHERTYPE_IP);
+ if (cc == -1)
+ return (-1);
+ if (cc != len)
+ panic("sendudp: bad write (%zd != %zd)", cc, len);
+ return (cc - (sizeof(*ip) + sizeof(*uh)));
+}
+
+/*
+ * Receive a UDP packet and validate it is for us.
+ * Caller leaves room for the headers (Ether, IP, UDP)
+ */
+ssize_t
+readudp(d, pkt, len, tleft)
+ struct iodesc *d;
+ void *pkt;
+ size_t len;
+ time_t tleft;
+{
+ ssize_t n;
+ size_t hlen;
+ struct ip *ip;
+ struct udphdr *uh;
+ u_int16_t etype; /* host order */
+
+#ifdef NET_DEBUG
+ if (debug)
+ printf("readudp: called\n");
+#endif
+
+ uh = (struct udphdr *)pkt - 1;
+ ip = (struct ip *)uh - 1;
+
+ n = readether(d, ip, len + sizeof(*ip) + sizeof(*uh), tleft, &etype);
+ if (n == -1 || n < sizeof(*ip) + sizeof(*uh))
+ return -1;
+
+ /* Ethernet address checks now in readether() */
+
+ /* Need to respond to ARP requests. */
+ if (etype == ETHERTYPE_ARP) {
+ struct arphdr *ah = (void *)ip;
+ if (ah->ar_op == htons(ARPOP_REQUEST)) {
+ /* Send ARP reply */
+ arp_reply(d, ah);
+ }
+ return -1;
+ }
+
+ if (etype != ETHERTYPE_IP) {
+#ifdef NET_DEBUG
+ if (debug)
+ printf("readudp: not IP. ether_type=%x\n", etype);
+#endif
+ return -1;
+ }
+
+ /* Check ip header */
+ if (ip->ip_v != IPVERSION ||
+ ip->ip_p != IPPROTO_UDP) { /* half char */
+#ifdef NET_DEBUG
+ if (debug)
+ printf("readudp: IP version or not UDP. ip_v=%d ip_p=%d\n", ip->ip_v, ip->ip_p);
+#endif
+ return -1;
+ }
+
+ hlen = ip->ip_hl << 2;
+ if (hlen < sizeof(*ip) ||
+ in_cksum(ip, hlen) != 0) {
+#ifdef NET_DEBUG
+ if (debug)
+ printf("readudp: short hdr or bad cksum.\n");
+#endif
+ return -1;
+ }
+ if (n < ntohs(ip->ip_len)) {
+#ifdef NET_DEBUG
+ if (debug)
+ printf("readudp: bad length %d < %d.\n",
+ (int)n, ntohs(ip->ip_len));
+#endif
+ return -1;
+ }
+ if (d->myip.s_addr && ip->ip_dst.s_addr != d->myip.s_addr) {
+#ifdef NET_DEBUG
+ if (debug) {
+ printf("readudp: bad saddr %s != ", inet_ntoa(d->myip));
+ printf("%s\n", inet_ntoa(ip->ip_dst));
+ }
+#endif
+ return -1;
+ }
+
+ /* If there were ip options, make them go away */
+ if (hlen != sizeof(*ip)) {
+ bcopy(((u_char *)ip) + hlen, uh, len - hlen);
+ ip->ip_len = htons(sizeof(*ip));
+ n -= hlen - sizeof(*ip);
+ }
+ if (uh->uh_dport != d->myport) {
+#ifdef NET_DEBUG
+ if (debug)
+ printf("readudp: bad dport %d != %d\n",
+ d->myport, ntohs(uh->uh_dport));
+#endif
+ return -1;
+ }
+
+#ifndef UDP_NO_CKSUM
+ if (uh->uh_sum) {
+ struct udpiphdr *ui;
+ struct ip tip;
+
+ n = ntohs(uh->uh_ulen) + sizeof(*ip);
+ if (n > RECV_SIZE - ETHER_SIZE) {
+ printf("readudp: huge packet, udp len %d\n", (int)n);
+ return -1;
+ }
+
+ /* Check checksum (must save and restore ip header) */
+ tip = *ip;
+ ui = (struct udpiphdr *)ip;
+ bzero(&ui->ui_x1, sizeof(ui->ui_x1));
+ ui->ui_len = uh->uh_ulen;
+ if (in_cksum(ui, n) != 0) {
+#ifdef NET_DEBUG
+ if (debug)
+ printf("readudp: bad cksum\n");
+#endif
+ *ip = tip;
+ return -1;
+ }
+ *ip = tip;
+ }
+#endif
+ if (ntohs(uh->uh_ulen) < sizeof(*uh)) {
+#ifdef NET_DEBUG
+ if (debug)
+ printf("readudp: bad udp len %d < %d\n",
+ ntohs(uh->uh_ulen), (int)sizeof(*uh));
+#endif
+ return -1;
+ }
+
+ n = (n > (ntohs(uh->uh_ulen) - sizeof(*uh))) ?
+ ntohs(uh->uh_ulen) - sizeof(*uh) : n;
+ return (n);
+}
diff --git a/lib/libstand/ufs.c b/lib/libstand/ufs.c
new file mode 100644
index 0000000..169991f
--- /dev/null
+++ b/lib/libstand/ufs.c
@@ -0,0 +1,869 @@
+/* $NetBSD: ufs.c,v 1.20 1998/03/01 07:15:39 ross Exp $ */
+
+/*-
+ * Copyright (c) 2002 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project by Marshall
+ * Kirk McKusick 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
+ *
+ * Copyright (c) 1982, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * The Mach Operating System project at Carnegie-Mellon 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. 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 (c) 1990, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Author: David Golub
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Stand-alone file reading package.
+ */
+
+#include <sys/param.h>
+#include <sys/disklabel.h>
+#include <sys/time.h>
+#include <ufs/ufs/dinode.h>
+#include <ufs/ufs/dir.h>
+#include <ufs/ffs/fs.h>
+#include "stand.h"
+#include "string.h"
+
+#ifdef __alpha__
+#define COMPAT_UFS /* DUX has old format file systems */
+#endif
+
+static int ufs_open(const char *path, struct open_file *f);
+static int ufs_write(struct open_file *f, void *buf, size_t size, size_t *resid);
+static int ufs_close(struct open_file *f);
+static int ufs_read(struct open_file *f, void *buf, size_t size, size_t *resid);
+static off_t ufs_seek(struct open_file *f, off_t offset, int where);
+static int ufs_stat(struct open_file *f, struct stat *sb);
+static int ufs_readdir(struct open_file *f, struct dirent *d);
+
+struct fs_ops ufs_fsops = {
+ "ufs",
+ ufs_open,
+ ufs_close,
+ ufs_read,
+ ufs_write,
+ ufs_seek,
+ ufs_stat,
+ ufs_readdir
+};
+
+/*
+ * In-core open file.
+ */
+struct file {
+ off_t f_seekp; /* seek pointer */
+ struct fs *f_fs; /* pointer to super-block */
+ union dinode {
+ struct ufs1_dinode di1;
+ struct ufs2_dinode di2;
+ } f_di; /* copy of on-disk inode */
+ int f_nindir[NIADDR];
+ /* number of blocks mapped by
+ indirect block at level i */
+ char *f_blk[NIADDR]; /* buffer for indirect block at
+ level i */
+ size_t f_blksize[NIADDR];
+ /* size of buffer */
+ ufs2_daddr_t f_blkno[NIADDR];/* disk address of block in buffer */
+ ufs2_daddr_t f_buf_blkno; /* block number of data block */
+ char *f_buf; /* buffer for data block */
+ size_t f_buf_size; /* size of data block */
+};
+#define DIP(fp, field) \
+ ((fp)->f_fs->fs_magic == FS_UFS1_MAGIC ? \
+ (fp)->f_di.di1.field : (fp)->f_di.di2.field)
+
+static int read_inode(ino_t, struct open_file *);
+static int block_map(struct open_file *, ufs2_daddr_t, ufs2_daddr_t *);
+static int buf_read_file(struct open_file *, char **, size_t *);
+static int buf_write_file(struct open_file *, char *, size_t *);
+static int search_directory(char *, struct open_file *, ino_t *);
+
+/*
+ * Read a new inode into a file structure.
+ */
+static int
+read_inode(inumber, f)
+ ino_t inumber;
+ struct open_file *f;
+{
+ struct file *fp = (struct file *)f->f_fsdata;
+ struct fs *fs = fp->f_fs;
+ char *buf;
+ size_t rsize;
+ int rc;
+
+ if (fs == NULL)
+ panic("fs == NULL");
+
+ /*
+ * Read inode and save it.
+ */
+ buf = malloc(fs->fs_bsize);
+ twiddle();
+ rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
+ fsbtodb(fs, ino_to_fsba(fs, inumber)), fs->fs_bsize,
+ buf, &rsize);
+ if (rc)
+ goto out;
+ if (rsize != fs->fs_bsize) {
+ rc = EIO;
+ goto out;
+ }
+
+ if (fp->f_fs->fs_magic == FS_UFS1_MAGIC)
+ fp->f_di.di1 = ((struct ufs1_dinode *)buf)
+ [ino_to_fsbo(fs, inumber)];
+ else
+ fp->f_di.di2 = ((struct ufs2_dinode *)buf)
+ [ino_to_fsbo(fs, inumber)];
+
+ /*
+ * Clear out the old buffers
+ */
+ {
+ int level;
+
+ for (level = 0; level < NIADDR; level++)
+ fp->f_blkno[level] = -1;
+ fp->f_buf_blkno = -1;
+ }
+ fp->f_seekp = 0;
+out:
+ free(buf);
+ return (rc);
+}
+
+/*
+ * Given an offset in a file, find the disk block number that
+ * contains that block.
+ */
+static int
+block_map(f, file_block, disk_block_p)
+ struct open_file *f;
+ ufs2_daddr_t file_block;
+ ufs2_daddr_t *disk_block_p; /* out */
+{
+ struct file *fp = (struct file *)f->f_fsdata;
+ struct fs *fs = fp->f_fs;
+ int level;
+ int idx;
+ ufs2_daddr_t ind_block_num;
+ int rc;
+
+ /*
+ * Index structure of an inode:
+ *
+ * di_db[0..NDADDR-1] hold block numbers for blocks
+ * 0..NDADDR-1
+ *
+ * di_ib[0] index block 0 is the single indirect block
+ * holds block numbers for blocks
+ * NDADDR .. NDADDR + NINDIR(fs)-1
+ *
+ * di_ib[1] index block 1 is the double indirect block
+ * holds block numbers for INDEX blocks for blocks
+ * NDADDR + NINDIR(fs) ..
+ * NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1
+ *
+ * di_ib[2] index block 2 is the triple indirect block
+ * holds block numbers for double-indirect
+ * blocks for blocks
+ * NDADDR + NINDIR(fs) + NINDIR(fs)**2 ..
+ * NDADDR + NINDIR(fs) + NINDIR(fs)**2
+ * + NINDIR(fs)**3 - 1
+ */
+
+ if (file_block < NDADDR) {
+ /* Direct block. */
+ *disk_block_p = DIP(fp, di_db[file_block]);
+ return (0);
+ }
+
+ file_block -= NDADDR;
+
+ /*
+ * nindir[0] = NINDIR
+ * nindir[1] = NINDIR**2
+ * nindir[2] = NINDIR**3
+ * etc
+ */
+ for (level = 0; level < NIADDR; level++) {
+ if (file_block < fp->f_nindir[level])
+ break;
+ file_block -= fp->f_nindir[level];
+ }
+ if (level == NIADDR) {
+ /* Block number too high */
+ return (EFBIG);
+ }
+
+ ind_block_num = DIP(fp, di_ib[level]);
+
+ for (; level >= 0; level--) {
+ if (ind_block_num == 0) {
+ *disk_block_p = 0; /* missing */
+ return (0);
+ }
+
+ if (fp->f_blkno[level] != ind_block_num) {
+ if (fp->f_blk[level] == (char *)0)
+ fp->f_blk[level] =
+ malloc(fs->fs_bsize);
+ twiddle();
+ rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
+ fsbtodb(fp->f_fs, ind_block_num),
+ fs->fs_bsize,
+ fp->f_blk[level],
+ &fp->f_blksize[level]);
+ if (rc)
+ return (rc);
+ if (fp->f_blksize[level] != fs->fs_bsize)
+ return (EIO);
+ fp->f_blkno[level] = ind_block_num;
+ }
+
+ if (level > 0) {
+ idx = file_block / fp->f_nindir[level - 1];
+ file_block %= fp->f_nindir[level - 1];
+ } else
+ idx = file_block;
+
+ if (fp->f_fs->fs_magic == FS_UFS1_MAGIC)
+ ind_block_num = ((ufs1_daddr_t *)fp->f_blk[level])[idx];
+ else
+ ind_block_num = ((ufs2_daddr_t *)fp->f_blk[level])[idx];
+ }
+
+ *disk_block_p = ind_block_num;
+
+ return (0);
+}
+
+/*
+ * Write a portion of a file from an internal buffer.
+ */
+static int
+buf_write_file(f, buf_p, size_p)
+ struct open_file *f;
+ char *buf_p;
+ size_t *size_p; /* out */
+{
+ struct file *fp = (struct file *)f->f_fsdata;
+ struct fs *fs = fp->f_fs;
+ long off;
+ ufs_lbn_t file_block;
+ ufs2_daddr_t disk_block;
+ size_t block_size;
+ int rc;
+
+ /*
+ * Calculate the starting block address and offset.
+ */
+ off = blkoff(fs, fp->f_seekp);
+ file_block = lblkno(fs, fp->f_seekp);
+ block_size = sblksize(fs, DIP(fp, di_size), file_block);
+
+ rc = block_map(f, file_block, &disk_block);
+ if (rc)
+ return (rc);
+
+ if (disk_block == 0)
+ /* Because we can't allocate space on the drive */
+ return (EFBIG);
+
+ /*
+ * Truncate buffer at end of file, and at the end of
+ * this block.
+ */
+ if (*size_p > DIP(fp, di_size) - fp->f_seekp)
+ *size_p = DIP(fp, di_size) - fp->f_seekp;
+ if (*size_p > block_size - off)
+ *size_p = block_size - off;
+
+ /*
+ * If we don't entirely occlude the block and it's not
+ * in memory already, read it in first.
+ */
+ if (((off > 0) || (*size_p + off < block_size)) &&
+ (file_block != fp->f_buf_blkno)) {
+
+ if (fp->f_buf == (char *)0)
+ fp->f_buf = malloc(fs->fs_bsize);
+
+ twiddle();
+ rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
+ fsbtodb(fs, disk_block),
+ block_size, fp->f_buf, &fp->f_buf_size);
+ if (rc)
+ return (rc);
+
+ fp->f_buf_blkno = file_block;
+ }
+
+ /*
+ * Copy the user data into the cached block.
+ */
+ bcopy(buf_p, fp->f_buf + off, *size_p);
+
+ /*
+ * Write the block out to storage.
+ */
+
+ twiddle();
+ rc = (f->f_dev->dv_strategy)(f->f_devdata, F_WRITE,
+ fsbtodb(fs, disk_block),
+ block_size, fp->f_buf, &fp->f_buf_size);
+ return (rc);
+}
+
+/*
+ * Read a portion of a file into an internal buffer. Return
+ * the location in the buffer and the amount in the buffer.
+ */
+static int
+buf_read_file(f, buf_p, size_p)
+ struct open_file *f;
+ char **buf_p; /* out */
+ size_t *size_p; /* out */
+{
+ struct file *fp = (struct file *)f->f_fsdata;
+ struct fs *fs = fp->f_fs;
+ long off;
+ ufs_lbn_t file_block;
+ ufs2_daddr_t disk_block;
+ size_t block_size;
+ int rc;
+
+ off = blkoff(fs, fp->f_seekp);
+ file_block = lblkno(fs, fp->f_seekp);
+ block_size = sblksize(fs, DIP(fp, di_size), file_block);
+
+ if (file_block != fp->f_buf_blkno) {
+ if (fp->f_buf == (char *)0)
+ fp->f_buf = malloc(fs->fs_bsize);
+
+ rc = block_map(f, file_block, &disk_block);
+ if (rc)
+ return (rc);
+
+ if (disk_block == 0) {
+ bzero(fp->f_buf, block_size);
+ fp->f_buf_size = block_size;
+ } else {
+ twiddle();
+ rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
+ fsbtodb(fs, disk_block),
+ block_size, fp->f_buf, &fp->f_buf_size);
+ if (rc)
+ return (rc);
+ }
+
+ fp->f_buf_blkno = file_block;
+ }
+
+ /*
+ * Return address of byte in buffer corresponding to
+ * offset, and size of remainder of buffer after that
+ * byte.
+ */
+ *buf_p = fp->f_buf + off;
+ *size_p = block_size - off;
+
+ /*
+ * But truncate buffer at end of file.
+ */
+ if (*size_p > DIP(fp, di_size) - fp->f_seekp)
+ *size_p = DIP(fp, di_size) - fp->f_seekp;
+
+ return (0);
+}
+
+/*
+ * Search a directory for a name and return its
+ * i_number.
+ */
+static int
+search_directory(name, f, inumber_p)
+ char *name;
+ struct open_file *f;
+ ino_t *inumber_p; /* out */
+{
+ struct file *fp = (struct file *)f->f_fsdata;
+ struct direct *dp;
+ struct direct *edp;
+ char *buf;
+ size_t buf_size;
+ int namlen, length;
+ int rc;
+
+ length = strlen(name);
+
+ fp->f_seekp = 0;
+ while (fp->f_seekp < DIP(fp, di_size)) {
+ rc = buf_read_file(f, &buf, &buf_size);
+ if (rc)
+ return (rc);
+
+ dp = (struct direct *)buf;
+ edp = (struct direct *)(buf + buf_size);
+ while (dp < edp) {
+ if (dp->d_ino == (ino_t)0)
+ goto next;
+#if BYTE_ORDER == LITTLE_ENDIAN
+ if (fp->f_fs->fs_maxsymlinklen <= 0)
+ namlen = dp->d_type;
+ else
+#endif
+ namlen = dp->d_namlen;
+ if (namlen == length &&
+ !strcmp(name, dp->d_name)) {
+ /* found entry */
+ *inumber_p = dp->d_ino;
+ return (0);
+ }
+ next:
+ dp = (struct direct *)((char *)dp + dp->d_reclen);
+ }
+ fp->f_seekp += buf_size;
+ }
+ return (ENOENT);
+}
+
+static int sblock_try[] = SBLOCKSEARCH;
+
+/*
+ * Open a file.
+ */
+static int
+ufs_open(upath, f)
+ const char *upath;
+ struct open_file *f;
+{
+ char *cp, *ncp;
+ int c;
+ ino_t inumber, parent_inumber;
+ struct file *fp;
+ struct fs *fs;
+ int i, rc;
+ size_t buf_size;
+ int nlinks = 0;
+ char namebuf[MAXPATHLEN+1];
+ char *buf = NULL;
+ char *path = NULL;
+
+ /* allocate file system specific data structure */
+ fp = malloc(sizeof(struct file));
+ bzero(fp, sizeof(struct file));
+ f->f_fsdata = (void *)fp;
+
+ /* allocate space and read super block */
+ fs = malloc(SBLOCKSIZE);
+ fp->f_fs = fs;
+ twiddle();
+ /*
+ * Try reading the superblock in each of its possible locations.
+ */
+ for (i = 0; sblock_try[i] != -1; i++) {
+ rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
+ sblock_try[i] / DEV_BSIZE, SBLOCKSIZE,
+ (char *)fs, &buf_size);
+ if (rc)
+ goto out;
+ if ((fs->fs_magic == FS_UFS1_MAGIC ||
+ (fs->fs_magic == FS_UFS2_MAGIC &&
+ fs->fs_sblockloc == sblock_try[i])) &&
+ buf_size == SBLOCKSIZE &&
+ fs->fs_bsize <= MAXBSIZE &&
+ fs->fs_bsize >= sizeof(struct fs))
+ break;
+ }
+ if (sblock_try[i] == -1) {
+ rc = EINVAL;
+ goto out;
+ }
+ /*
+ * Calculate indirect block levels.
+ */
+ {
+ ufs2_daddr_t mult;
+ int level;
+
+ mult = 1;
+ for (level = 0; level < NIADDR; level++) {
+ mult *= NINDIR(fs);
+ fp->f_nindir[level] = mult;
+ }
+ }
+
+ inumber = ROOTINO;
+ if ((rc = read_inode(inumber, f)) != 0)
+ goto out;
+
+ cp = path = strdup(upath);
+ if (path == NULL) {
+ rc = ENOMEM;
+ goto out;
+ }
+ while (*cp) {
+
+ /*
+ * Remove extra separators
+ */
+ while (*cp == '/')
+ cp++;
+ if (*cp == '\0')
+ break;
+
+ /*
+ * Check that current node is a directory.
+ */
+ if ((DIP(fp, di_mode) & IFMT) != IFDIR) {
+ rc = ENOTDIR;
+ goto out;
+ }
+
+ /*
+ * Get next component of path name.
+ */
+ {
+ int len = 0;
+
+ ncp = cp;
+ while ((c = *cp) != '\0' && c != '/') {
+ if (++len > MAXNAMLEN) {
+ rc = ENOENT;
+ goto out;
+ }
+ cp++;
+ }
+ *cp = '\0';
+ }
+
+ /*
+ * Look up component in current directory.
+ * Save directory inumber in case we find a
+ * symbolic link.
+ */
+ parent_inumber = inumber;
+ rc = search_directory(ncp, f, &inumber);
+ *cp = c;
+ if (rc)
+ goto out;
+
+ /*
+ * Open next component.
+ */
+ if ((rc = read_inode(inumber, f)) != 0)
+ goto out;
+
+ /*
+ * Check for symbolic link.
+ */
+ if ((DIP(fp, di_mode) & IFMT) == IFLNK) {
+ int link_len = DIP(fp, di_size);
+ int len;
+
+ len = strlen(cp);
+
+ if (link_len + len > MAXPATHLEN ||
+ ++nlinks > MAXSYMLINKS) {
+ rc = ENOENT;
+ goto out;
+ }
+
+ bcopy(cp, &namebuf[link_len], len + 1);
+
+ if (link_len < fs->fs_maxsymlinklen) {
+ if (fp->f_fs->fs_magic == FS_UFS1_MAGIC)
+ cp = (caddr_t)(fp->f_di.di1.di_db);
+ else
+ cp = (caddr_t)(fp->f_di.di2.di_db);
+ bcopy(cp, namebuf, (unsigned) link_len);
+ } else {
+ /*
+ * Read file for symbolic link
+ */
+ size_t buf_size;
+ ufs2_daddr_t disk_block;
+ struct fs *fs = fp->f_fs;
+
+ if (!buf)
+ buf = malloc(fs->fs_bsize);
+ rc = block_map(f, (ufs2_daddr_t)0, &disk_block);
+ if (rc)
+ goto out;
+
+ twiddle();
+ rc = (f->f_dev->dv_strategy)(f->f_devdata,
+ F_READ, fsbtodb(fs, disk_block),
+ fs->fs_bsize, buf, &buf_size);
+ if (rc)
+ goto out;
+
+ bcopy((char *)buf, namebuf, (unsigned)link_len);
+ }
+
+ /*
+ * If relative pathname, restart at parent directory.
+ * If absolute pathname, restart at root.
+ */
+ cp = namebuf;
+ if (*cp != '/')
+ inumber = parent_inumber;
+ else
+ inumber = (ino_t)ROOTINO;
+
+ if ((rc = read_inode(inumber, f)) != 0)
+ goto out;
+ }
+ }
+
+ /*
+ * Found terminal component.
+ */
+ rc = 0;
+ fp->f_seekp = 0;
+out:
+ if (buf)
+ free(buf);
+ if (path)
+ free(path);
+ if (rc) {
+ if (fp->f_buf)
+ free(fp->f_buf);
+ free(fp->f_fs);
+ free(fp);
+ }
+ return (rc);
+}
+
+static int
+ufs_close(f)
+ struct open_file *f;
+{
+ struct file *fp = (struct file *)f->f_fsdata;
+ int level;
+
+ f->f_fsdata = (void *)0;
+ if (fp == (struct file *)0)
+ return (0);
+
+ for (level = 0; level < NIADDR; level++) {
+ if (fp->f_blk[level])
+ free(fp->f_blk[level]);
+ }
+ if (fp->f_buf)
+ free(fp->f_buf);
+ free(fp->f_fs);
+ free(fp);
+ return (0);
+}
+
+/*
+ * Copy a portion of a file into kernel memory.
+ * Cross block boundaries when necessary.
+ */
+static int
+ufs_read(f, start, size, resid)
+ struct open_file *f;
+ void *start;
+ size_t size;
+ size_t *resid; /* out */
+{
+ struct file *fp = (struct file *)f->f_fsdata;
+ size_t csize;
+ char *buf;
+ size_t buf_size;
+ int rc = 0;
+ char *addr = start;
+
+ while (size != 0) {
+ if (fp->f_seekp >= DIP(fp, di_size))
+ break;
+
+ rc = buf_read_file(f, &buf, &buf_size);
+ if (rc)
+ break;
+
+ csize = size;
+ if (csize > buf_size)
+ csize = buf_size;
+
+ bcopy(buf, addr, csize);
+
+ fp->f_seekp += csize;
+ addr += csize;
+ size -= csize;
+ }
+ if (resid)
+ *resid = size;
+ return (rc);
+}
+
+/*
+ * Write to a portion of an already allocated file.
+ * Cross block boundaries when necessary. Can not
+ * extend the file.
+ */
+static int
+ufs_write(f, start, size, resid)
+ struct open_file *f;
+ void *start;
+ size_t size;
+ size_t *resid; /* out */
+{
+ struct file *fp = (struct file *)f->f_fsdata;
+ size_t csize;
+ int rc = 0;
+ char *addr = start;
+
+ csize = size;
+ while ((size != 0) && (csize != 0)) {
+ if (fp->f_seekp >= DIP(fp, di_size))
+ break;
+
+ if (csize >= 512) csize = 512; /* XXX */
+
+ rc = buf_write_file(f, addr, &csize);
+ if (rc)
+ break;
+
+ fp->f_seekp += csize;
+ addr += csize;
+ size -= csize;
+ }
+ if (resid)
+ *resid = size;
+ return (rc);
+}
+
+static off_t
+ufs_seek(f, offset, where)
+ struct open_file *f;
+ off_t offset;
+ int where;
+{
+ struct file *fp = (struct file *)f->f_fsdata;
+
+ switch (where) {
+ case SEEK_SET:
+ fp->f_seekp = offset;
+ break;
+ case SEEK_CUR:
+ fp->f_seekp += offset;
+ break;
+ case SEEK_END:
+ fp->f_seekp = DIP(fp, di_size) - offset;
+ break;
+ default:
+ errno = EINVAL;
+ return (-1);
+ }
+ return (fp->f_seekp);
+}
+
+static int
+ufs_stat(f, sb)
+ struct open_file *f;
+ struct stat *sb;
+{
+ struct file *fp = (struct file *)f->f_fsdata;
+
+ /* only important stuff */
+ sb->st_mode = DIP(fp, di_mode);
+ sb->st_uid = DIP(fp, di_uid);
+ sb->st_gid = DIP(fp, di_gid);
+ sb->st_size = DIP(fp, di_size);
+ return (0);
+}
+
+static int
+ufs_readdir(struct open_file *f, struct dirent *d)
+{
+ struct file *fp = (struct file *)f->f_fsdata;
+ struct direct *dp;
+ char *buf;
+ size_t buf_size;
+ int error;
+
+ /*
+ * assume that a directory entry will not be split across blocks
+ */
+again:
+ if (fp->f_seekp >= DIP(fp, di_size))
+ return (ENOENT);
+ error = buf_read_file(f, &buf, &buf_size);
+ if (error)
+ return (error);
+ dp = (struct direct *)buf;
+ fp->f_seekp += dp->d_reclen;
+ if (dp->d_ino == (ino_t)0)
+ goto again;
+ d->d_type = dp->d_type;
+ strcpy(d->d_name, dp->d_name);
+ return (0);
+}
diff --git a/lib/libstand/write.c b/lib/libstand/write.c
new file mode 100644
index 0000000..8f0fa97
--- /dev/null
+++ b/lib/libstand/write.c
@@ -0,0 +1,99 @@
+/* $NetBSD: write.c,v 1.7 1996/06/21 20:29:30 pk Exp $ */
+
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * The Mach Operating System project at Carnegie-Mellon 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. 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.
+ *
+ * @(#)write.c 8.1 (Berkeley) 6/11/93
+ *
+ *
+ * Copyright (c) 1989, 1990, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Author: Alessandro Forin
+ *
+ * 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 the
+ * rights to redistribute these changes.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include "stand.h"
+
+ssize_t
+write(fd, dest, bcount)
+ int fd;
+ void *dest;
+ size_t bcount;
+{
+ struct open_file *f = &files[fd];
+ size_t resid;
+
+ if ((unsigned)fd >= SOPEN_MAX || !(f->f_flags & F_WRITE)) {
+ errno = EBADF;
+ return (-1);
+ }
+ if (f->f_flags & F_RAW) {
+ twiddle();
+ errno = (f->f_dev->dv_strategy)(f->f_devdata, F_WRITE,
+ btodb(f->f_offset), bcount, dest, &resid);
+ if (errno)
+ return (-1);
+ f->f_offset += resid;
+ return (resid);
+ }
+ resid = bcount;
+ if ((errno = (f->f_ops->fo_write)(f, dest, bcount, &resid)))
+ return (-1);
+ return (bcount - resid);
+}
diff --git a/lib/libstand/zalloc.c b/lib/libstand/zalloc.c
new file mode 100644
index 0000000..aa8ccd0
--- /dev/null
+++ b/lib/libstand/zalloc.c
@@ -0,0 +1,303 @@
+/*
+ * This module derived from code donated to the FreeBSD Project by
+ * Matthew Dillon <dillon@backplane.com>
+ *
+ * Copyright (c) 1998 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * LIB/MEMORY/ZALLOC.C - self contained low-overhead memory pool/allocation
+ * subsystem
+ *
+ * This subsystem implements memory pools and memory allocation
+ * routines.
+ *
+ * Pools are managed via a linked list of 'free' areas. Allocating
+ * memory creates holes in the freelist, freeing memory fills them.
+ * Since the freelist consists only of free memory areas, it is possible
+ * to allocate the entire pool without incuring any structural overhead.
+ *
+ * The system works best when allocating similarly-sized chunks of
+ * memory. Care must be taken to avoid fragmentation when
+ * allocating/deallocating dissimilar chunks.
+ *
+ * When a memory pool is first allocated, the entire pool is marked as
+ * allocated. This is done mainly because we do not want to modify any
+ * portion of a pool's data area until we are given permission. The
+ * caller must explicitly deallocate portions of the pool to make them
+ * available.
+ *
+ * z[n]xalloc() works like z[n]alloc() but the allocation is made from
+ * within the specified address range. If the segment could not be
+ * allocated, NULL is returned. WARNING! The address range will be
+ * aligned to an 8 or 16 byte boundry depending on the cpu so if you
+ * give an unaligned address range, unexpected results may occur.
+ *
+ * If a standard allocation fails, the reclaim function will be called
+ * to recover some space. This usually causes other portions of the
+ * same pool to be released. Memory allocations at this low level
+ * should not block but you can do that too in your reclaim function
+ * if you want. Reclaim does not function when z[n]xalloc() is used,
+ * only for z[n]alloc().
+ *
+ * Allocation and frees of 0 bytes are valid operations.
+ */
+
+#include "zalloc_defs.h"
+
+/*
+ * znalloc() - allocate memory (without zeroing) from pool. Call reclaim
+ * and retry if appropriate, return NULL if unable to allocate
+ * memory.
+ */
+
+void *
+znalloc(MemPool *mp, iaddr_t bytes)
+{
+ /*
+ * align according to pool object size (can be 0). This is
+ * inclusive of the MEMNODE_SIZE_MASK minimum alignment.
+ *
+ */
+ bytes = (bytes + MEMNODE_SIZE_MASK) & ~MEMNODE_SIZE_MASK;
+
+ if (bytes == 0)
+ return((void *)-1);
+
+ /*
+ * locate freelist entry big enough to hold the object. If all objects
+ * are the same size, this is a constant-time function.
+ */
+
+ if (bytes <= mp->mp_Size - mp->mp_Used) {
+ MemNode **pmn;
+ MemNode *mn;
+
+ for (pmn = &mp->mp_First; (mn=*pmn) != NULL; pmn = &mn->mr_Next) {
+ if (bytes > mn->mr_Bytes)
+ continue;
+
+ /*
+ * Cut a chunk of memory out of the beginning of this
+ * block and fixup the link appropriately.
+ */
+
+ {
+ char *ptr = (char *)mn;
+
+ if (mn->mr_Bytes == bytes) {
+ *pmn = mn->mr_Next;
+ } else {
+ mn = (MemNode *)((char *)mn + bytes);
+ mn->mr_Next = ((MemNode *)ptr)->mr_Next;
+ mn->mr_Bytes = ((MemNode *)ptr)->mr_Bytes - bytes;
+ *pmn = mn;
+ }
+ mp->mp_Used += bytes;
+ return(ptr);
+ }
+ }
+ }
+
+ /*
+ * Memory pool is full, return NULL.
+ */
+
+ return(NULL);
+}
+
+/*
+ * zfree() - free previously allocated memory
+ */
+
+void
+zfree(MemPool *mp, void *ptr, iaddr_t bytes)
+{
+ /*
+ * align according to pool object size (can be 0). This is
+ * inclusive of the MEMNODE_SIZE_MASK minimum alignment.
+ */
+ bytes = (bytes + MEMNODE_SIZE_MASK) & ~MEMNODE_SIZE_MASK;
+
+ if (bytes == 0)
+ return;
+
+ /*
+ * panic if illegal pointer
+ */
+
+ if ((char *)ptr < (char *)mp->mp_Base ||
+ (char *)ptr + bytes > (char *)mp->mp_End ||
+ ((iaddr_t)ptr & MEMNODE_SIZE_MASK) != 0)
+ panic("zfree(%p,%d): wild pointer", ptr, bytes);
+
+ /*
+ * free the segment
+ */
+
+ {
+ MemNode **pmn;
+ MemNode *mn;
+
+ mp->mp_Used -= bytes;
+
+ for (pmn = &mp->mp_First; (mn = *pmn) != NULL; pmn = &mn->mr_Next) {
+ /*
+ * If area between last node and current node
+ * - check range
+ * - check merge with next area
+ * - check merge with previous area
+ */
+ if ((char *)ptr <= (char *)mn) {
+ /*
+ * range check
+ */
+ if ((char *)ptr + bytes > (char *)mn)
+ panic("zfree(%p,%d): corrupt memlist1",ptr, bytes);
+
+ /*
+ * merge against next area or create independant area
+ */
+
+ if ((char *)ptr + bytes == (char *)mn) {
+ ((MemNode *)ptr)->mr_Next = mn->mr_Next;
+ ((MemNode *)ptr)->mr_Bytes= bytes + mn->mr_Bytes;
+ } else {
+ ((MemNode *)ptr)->mr_Next = mn;
+ ((MemNode *)ptr)->mr_Bytes= bytes;
+ }
+ *pmn = mn = (MemNode *)ptr;
+
+ /*
+ * merge against previous area (if there is a previous
+ * area).
+ */
+
+ if (pmn != &mp->mp_First) {
+ if ((char*)pmn + ((MemNode*)pmn)->mr_Bytes == (char*)ptr) {
+ ((MemNode *)pmn)->mr_Next = mn->mr_Next;
+ ((MemNode *)pmn)->mr_Bytes += mn->mr_Bytes;
+ mn = (MemNode *)pmn;
+ }
+ }
+ return;
+ /* NOT REACHED */
+ }
+ if ((char *)ptr < (char *)mn + mn->mr_Bytes)
+ panic("zfree(%p,%d): corrupt memlist2", ptr, bytes);
+ }
+ /*
+ * We are beyond the last MemNode, append new MemNode. Merge against
+ * previous area if possible.
+ */
+ if (pmn == &mp->mp_First ||
+ (char *)pmn + ((MemNode *)pmn)->mr_Bytes != (char *)ptr
+ ) {
+ ((MemNode *)ptr)->mr_Next = NULL;
+ ((MemNode *)ptr)->mr_Bytes = bytes;
+ *pmn = (MemNode *)ptr;
+ mn = (MemNode *)ptr;
+ } else {
+ ((MemNode *)pmn)->mr_Bytes += bytes;
+ mn = (MemNode *)pmn;
+ }
+ }
+}
+
+/*
+ * zextendPool() - extend memory pool to cover additional space.
+ *
+ * Note: the added memory starts out as allocated, you
+ * must free it to make it available to the memory subsystem.
+ *
+ * Note: mp_Size may not reflect (mp_End - mp_Base) range
+ * due to other parts of the system doing their own sbrk()
+ * calls.
+ */
+
+void
+zextendPool(MemPool *mp, void *base, iaddr_t bytes)
+{
+ if (mp->mp_Size == 0) {
+ mp->mp_Base = base;
+ mp->mp_Used = bytes;
+ mp->mp_End = (char *)base + bytes;
+ mp->mp_Size = bytes;
+ } else {
+ void *pend = (char *)mp->mp_Base + mp->mp_Size;
+
+ if (base < mp->mp_Base) {
+ mp->mp_Size += (char *)mp->mp_Base - (char *)base;
+ mp->mp_Used += (char *)mp->mp_Base - (char *)base;
+ mp->mp_Base = base;
+ }
+ base = (char *)base + bytes;
+ if (base > pend) {
+ mp->mp_Size += (char *)base - (char *)pend;
+ mp->mp_Used += (char *)base - (char *)pend;
+ mp->mp_End = (char *)base;
+ }
+ }
+}
+
+#ifdef ZALLOCDEBUG
+
+void
+zallocstats(MemPool *mp)
+{
+ int abytes = 0;
+ int hbytes = 0;
+ int fcount = 0;
+ MemNode *mn;
+
+ printf("%d bytes reserved", (int) mp->mp_Size);
+
+ mn = mp->mp_First;
+
+ if ((void *)mn != (void *)mp->mp_Base) {
+ abytes += (char *)mn - (char *)mp->mp_Base;
+ }
+
+ while (mn) {
+ if ((char *)mn + mn->mr_Bytes != mp->mp_End) {
+ hbytes += mn->mr_Bytes;
+ ++fcount;
+ }
+ if (mn->mr_Next)
+ abytes += (char *)mn->mr_Next - ((char *)mn + mn->mr_Bytes);
+ mn = mn->mr_Next;
+ }
+ printf(" %d bytes allocated\n%d fragments (%d bytes fragmented)\n",
+ abytes,
+ fcount,
+ hbytes
+ );
+}
+
+#endif
+
diff --git a/lib/libstand/zalloc_defs.h b/lib/libstand/zalloc_defs.h
new file mode 100644
index 0000000..2544f59
--- /dev/null
+++ b/lib/libstand/zalloc_defs.h
@@ -0,0 +1,81 @@
+/*
+ * This module derived from code donated to the FreeBSD Project by
+ * Matthew Dillon <dillon@backplane.com>
+ *
+ * Copyright (c) 1998 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$
+ */
+
+/*
+ * DEFS.H
+ */
+
+#define USEGUARD /* use stard/end guard bytes */
+#define USEENDGUARD
+#define DMALLOCDEBUG /* add debugging code to gather stats */
+#define ZALLOCDEBUG
+
+#include <string.h>
+#include "stand.h"
+
+typedef uintptr_t iaddr_t; /* unsigned int same size as pointer */
+typedef intptr_t saddr_t; /* signed int same size as pointer */
+#include "zalloc_mem.h"
+
+#define Prototype extern
+#define Library extern
+
+#ifndef NULL
+#define NULL ((void *)0)
+#endif
+
+/*
+ * block extension for sbrk()
+ */
+
+#define BLKEXTEND (4 * 1024)
+#define BLKEXTENDMASK (BLKEXTEND - 1)
+
+/*
+ * required malloc alignment. Use sizeof(long double) for architecture
+ * independance.
+ *
+ * Note: if we implement a more sophisticated realloc, we should ensure that
+ * MALLOCALIGN is at least as large as MemNode.
+ */
+
+typedef struct Guard {
+ size_t ga_Bytes;
+ size_t ga_Magic; /* must be at least 32 bits */
+} Guard;
+
+#define MATYPE long double
+#define MALLOCALIGN ((sizeof(MATYPE) > sizeof(Guard)) ? sizeof(MATYPE) : sizeof(Guard))
+#define GAMAGIC 0x55FF44FD
+#define GAFREE 0x5F54F4DF
+
+#include "zalloc_protos.h"
+
diff --git a/lib/libstand/zalloc_malloc.c b/lib/libstand/zalloc_malloc.c
new file mode 100644
index 0000000..3161fc3
--- /dev/null
+++ b/lib/libstand/zalloc_malloc.c
@@ -0,0 +1,209 @@
+/*
+ * This module derived from code donated to the FreeBSD Project by
+ * Matthew Dillon <dillon@backplane.com>
+ *
+ * Copyright (c) 1998 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * MALLOC.C - malloc equivalent, runs on top of zalloc and uses sbrk
+ */
+
+#include "zalloc_defs.h"
+
+static MemPool MallocPool;
+
+#ifdef DMALLOCDEBUG
+static int MallocMax;
+static int MallocCount;
+
+void mallocstats(void);
+#endif
+
+#ifdef malloc
+#undef malloc
+#undef free
+#endif
+
+#ifdef __alpha__
+void
+free_region(void *start, void *end)
+{
+ zextendPool(&MallocPool, start, (caddr_t)end - (caddr_t)start);
+ zfree(&MallocPool, start, (caddr_t)end - (caddr_t)start);
+}
+#endif
+
+void *
+Malloc(size_t bytes, const char *file, int line)
+{
+ Guard *res;
+
+#ifdef USEENDGUARD
+ bytes += MALLOCALIGN + 1;
+#else
+ bytes += MALLOCALIGN;
+#endif
+
+ while ((res = znalloc(&MallocPool, bytes)) == NULL) {
+ int incr = (bytes + BLKEXTENDMASK) & ~BLKEXTENDMASK;
+ char *base;
+
+ if ((base = sbrk(incr)) == (char *)-1)
+ return(NULL);
+ zextendPool(&MallocPool, base, incr);
+ zfree(&MallocPool, base, incr);
+ }
+#ifdef DMALLOCDEBUG
+ if (++MallocCount > MallocMax)
+ MallocMax = MallocCount;
+#endif
+#ifdef USEGUARD
+ res->ga_Magic = GAMAGIC;
+#endif
+ res->ga_Bytes = bytes;
+#ifdef USEENDGUARD
+ *((signed char *)res + bytes - 1) = -2;
+#endif
+
+ return((char *)res + MALLOCALIGN);
+}
+
+void
+Free(void *ptr, const char *file, int line)
+{
+ size_t bytes;
+
+ if (ptr != NULL) {
+ Guard *res = (void *)((char *)ptr - MALLOCALIGN);
+
+ if (file == NULL)
+ file = "unknown";
+#ifdef USEGUARD
+ if (res->ga_Magic == GAFREE) {
+ printf("free: duplicate free @ %p from %s:%d\n", ptr, file, line);
+ return;
+ }
+ if (res->ga_Magic != GAMAGIC)
+ panic("free: guard1 fail @ %p from %s:%d", ptr, file, line);
+ res->ga_Magic = GAFREE;
+#endif
+#ifdef USEENDGUARD
+ if (*((signed char *)res + res->ga_Bytes - 1) == -1) {
+ printf("free: duplicate2 free @ %p from %s:%d\n", ptr, file, line);
+ return;
+ }
+ if (*((signed char *)res + res->ga_Bytes - 1) != -2)
+ panic("free: guard2 fail @ %p + %d from %s:%d", ptr, res->ga_Bytes - MALLOCALIGN, file, line);
+ *((signed char *)res + res->ga_Bytes - 1) = -1;
+#endif
+
+ bytes = res->ga_Bytes;
+ zfree(&MallocPool, res, bytes);
+#ifdef DMALLOCDEBUG
+ --MallocCount;
+#endif
+ }
+}
+
+
+void *
+Calloc(size_t n1, size_t n2, const char *file, int line)
+{
+ iaddr_t bytes = (iaddr_t)n1 * (iaddr_t)n2;
+ void *res;
+
+ if ((res = Malloc(bytes, file, line)) != NULL) {
+ bzero(res, bytes);
+#ifdef DMALLOCDEBUG
+ if (++MallocCount > MallocMax)
+ MallocMax = MallocCount;
+#endif
+ }
+ return(res);
+}
+
+/*
+ * realloc() - I could be fancier here and free the old buffer before
+ * allocating the new one (saving potential fragmentation
+ * and potential buffer copies). But I don't bother.
+ */
+
+void *
+Realloc(void *ptr, size_t size, const char *file, int line)
+{
+ void *res;
+ size_t old;
+
+ if ((res = Malloc(size, file, line)) != NULL) {
+ if (ptr) {
+ old = *(size_t *)((char *)ptr - MALLOCALIGN) - MALLOCALIGN;
+ if (old < size)
+ bcopy(ptr, res, old);
+ else
+ bcopy(ptr, res, size);
+ Free(ptr, file, line);
+ } else {
+#ifdef DMALLOCDEBUG
+ if (++MallocCount > MallocMax)
+ MallocMax = MallocCount;
+#ifdef EXITSTATS
+ if (DidAtExit == 0) {
+ DidAtExit = 1;
+ atexit(mallocstats);
+ }
+#endif
+#endif
+ }
+ }
+ return(res);
+}
+
+void *
+Reallocf(void *ptr, size_t size, const char *file, int line)
+{
+ void *res;
+
+ if ((res = Realloc(ptr, size, file, line)) == NULL)
+ Free(ptr, file, line);
+ return(res);
+}
+
+#ifdef DMALLOCDEBUG
+
+void
+mallocstats(void)
+{
+ printf("Active Allocations: %d/%d\n", MallocCount, MallocMax);
+#ifdef ZALLOCDEBUG
+ zallocstats(&MallocPool);
+#endif
+}
+
+#endif
+
diff --git a/lib/libstand/zalloc_mem.h b/lib/libstand/zalloc_mem.h
new file mode 100644
index 0000000..c872da1
--- /dev/null
+++ b/lib/libstand/zalloc_mem.h
@@ -0,0 +1,55 @@
+/*
+ * This module derived from code donated to the FreeBSD Project by
+ * Matthew Dillon <dillon@backplane.com>
+ *
+ * Copyright (c) 1998 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$
+ */
+
+/*
+ * H/MEM.H
+ *
+ * Basic memory pool / memory node structures.
+ */
+
+typedef struct MemNode {
+ struct MemNode *mr_Next;
+ iaddr_t mr_Bytes;
+} MemNode;
+
+typedef struct MemPool {
+ void *mp_Base;
+ void *mp_End;
+ MemNode *mp_First;
+ iaddr_t mp_Size;
+ iaddr_t mp_Used;
+} MemPool;
+
+#define MEMNODE_SIZE_MASK ((sizeof(MemNode) <= 8) ? 7 : 15)
+
+#define ZNOTE_FREE 0
+#define ZNOTE_REUSE 1
+
diff --git a/lib/libstand/zalloc_protos.h b/lib/libstand/zalloc_protos.h
new file mode 100644
index 0000000..c90bd5a
--- /dev/null
+++ b/lib/libstand/zalloc_protos.h
@@ -0,0 +1,35 @@
+/*
+ * This module derived from code donated to the FreeBSD Project by
+ * Matthew Dillon <dillon@backplane.com>
+ *
+ * Copyright (c) 1998 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$
+ */
+
+Library void *znalloc(struct MemPool *mpool, iaddr_t bytes);
+Library void zfree(struct MemPool *mpool, void *ptr, iaddr_t bytes);
+Library void zextendPool(MemPool *mp, void *base, iaddr_t bytes);
+Library void zallocstats(struct MemPool *mp);
diff --git a/lib/libtacplus/Makefile b/lib/libtacplus/Makefile
new file mode 100644
index 0000000..f39f271
--- /dev/null
+++ b/lib/libtacplus/Makefile
@@ -0,0 +1,36 @@
+# Copyright (c) 1998, 2001, Juniper Networks, Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+
+LIB= tacplus
+SRCS= taclib.c
+INCS= taclib.h
+CFLAGS+= -Wall
+DPADD= ${LIBMD}
+LDADD= -lmd
+SHLIB_MAJOR= 2
+MAN= libtacplus.3 tacplus.conf.5
+
+.include <bsd.lib.mk>
diff --git a/lib/libtacplus/libtacplus.3 b/lib/libtacplus/libtacplus.3
new file mode 100644
index 0000000..94c9694
--- /dev/null
+++ b/lib/libtacplus/libtacplus.3
@@ -0,0 +1,490 @@
+.\" Copyright (c) 1998, 2001, 2002, Juniper Networks, Inc.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd September 2, 1998
+.Dt LIBTACPLUS 3
+.Os
+.Sh NAME
+.Nm libtacplus
+.Nd TACACS+ client library
+.Sh SYNOPSIS
+.In taclib.h
+.Ft int
+.Fn tac_add_server "struct tac_handle *h" "const char *host" "int port" "const char *secret" "int timeout" "int flags"
+.Ft void
+.Fn tac_clear_avs "struct tac_handle *h"
+.Ft void
+.Fn tac_close "struct tac_handle *h"
+.Ft int
+.Fn tac_config "struct tac_handle *h" "const char *path"
+.Ft int
+.Fn tac_create_authen "struct tac_handle *h" "int action" "int type" "int service"
+.Ft int
+.Fn tac_create_author "struct tac_handle *h" "int method" "int type" "int service"
+.Ft char *
+.Fn tac_get_av "struct tac_handle *h" "u_int index"
+.Ft char *
+.Fn tac_get_av_value "struct tac_handle *h" "const char *attribute"
+.Ft void *
+.Fn tac_get_data "struct tac_handle *h" "size_t *len"
+.Ft char *
+.Fn tac_get_msg "struct tac_handle *h"
+.Ft struct tac_handle *
+.Fn tac_open "void"
+.Ft int
+.Fn tac_send_authen "struct tac_handle *h"
+.Ft int
+.Fn tac_send_author "struct tac_handle *h"
+.Ft int
+.Fn tac_set_av "struct tac_handle *h" "u_int index" "const char *av_pair"
+.Ft int
+.Fn tac_set_data "struct tac_handle *h" "const void *data" "size_t data_len"
+.Ft int
+.Fn tac_set_msg "struct tac_handle *h" "const char *msg"
+.Ft int
+.Fn tac_set_port "struct tac_handle *h" "const char *port"
+.Ft int
+.Fn tac_set_priv "struct tac_handle *h" "int priv"
+.Ft int
+.Fn tac_set_rem_addr "struct tac_handle *h" "const char *addr"
+.Ft int
+.Fn tac_set_user "struct tac_handle *h" "const char *user"
+.Ft const char *
+.Fn tac_strerror "struct tac_handle *h"
+.Sh DESCRIPTION
+The
+.Nm
+library implements the client side of the TACACS+ network access
+control protocol.
+TACACS+ allows clients to perform authentication,
+authorization, and accounting by means of network requests to remote
+servers.
+This library currently supports only the authentication
+and authorization portion of the protocol.
+.Sh INITIALIZATION
+To use the library, an application must first call
+.Fn tac_open
+to obtain a
+.Va struct tac_handle * ,
+which provides context for subsequent operations.
+Calls to
+.Fn tac_open
+always succeed unless insufficient virtual memory is available.
+If
+the necessary memory cannot be allocated,
+.Fn tac_open
+returns
+.Dv NULL .
+.Pp
+Before issuing any TACACS+ requests, the library must be made aware
+of the servers it can contact.
+The easiest way to configure the
+library is to call
+.Fn tac_config .
+.Fn tac_config
+causes the library to read a configuration file whose format is
+described in
+.Xr tacplus.conf 5 .
+The pathname of the configuration file is passed as the
+.Va file
+argument to
+.Fn tac_config .
+This argument may also be given as
+.Dv NULL ,
+in which case the standard configuration file
+.Pa /etc/tacplus.conf
+is used.
+.Fn tac_config
+returns 0 on success, or \-1 if an error occurs.
+.Pp
+The library can also be configured programmatically by calls to
+.Fn tac_add_server .
+The
+.Va host
+parameter specifies the server host, either as a fully qualified
+domain name or as a dotted-quad IP address in text form.
+The
+.Va port
+parameter specifies the TCP port to contact on the server.
+If
+.Va port
+is given as 0, the library uses port 49, the standard TACACS+ port.
+The shared secret for the server host is passed to the
+.Va secret
+parameter.
+It may be any null-terminated string of bytes.
+The timeout for receiving replies from the server is passed to the
+.Va timeout
+parameter, in units of seconds.
+The
+.Va flags
+parameter is a bit mask of flags to specify various characteristics of
+the server.
+It may contain:
+.Pp
+.Bl -tag -width Fl
+.It Dv TAC_SRVR_SINGLE_CONNECT
+Causes the library to attempt to negotiate single connection mode
+when communicating with the server.
+In single connection mode, the
+original TCP connection is held open for multiple TACACS+ sessions.
+Older servers do not support this mode, and some of them become
+confused if the client attempts to negotiate it.
+.El
+.Pp
+.Fn tac_add_server
+returns 0 on success, or \-1 if an error occurs.
+.Pp
+.Fn tac_add_server
+may be called multiple times, and it may be used together with
+.Fn tac_config .
+At most 10 servers may be specified.
+When multiple servers are given, they are tried in round-robin
+fashion until a working, accessible server is found.
+Once the
+library finds such a server, it continues to use it as long as it
+works.
+.Sh CREATING A TACACS+ AUTHENTICATION REQUEST
+To begin constructing a new authentication request, call
+.Fn tac_create_authen .
+The
+.Va action ,
+.Va type ,
+and
+.Va service
+arguments must be set to appropriate values as defined in the
+TACACS+ protocol specification.
+The
+.In taclib.h
+header file contains symbolic constants for these values.
+.Sh CREATING A TACACS+ AUTHORIZATION REQUEST
+To begin constructing a new authorization request, call
+.Fn tac_create_author .
+The
+.Va method ,
+.Va type ,
+and
+.Va service
+arguments must be set to appropriate values as defined in the
+TACACS+ protocol specification.
+The
+.In taclib.h
+header file contains symbolic constants for these values.
+.Sh SETTING OPTIONAL PARAMETERS ON A REQUEST
+After creating a request,
+various optional parameters may be attached to it through calls to
+.Fn tac_set_av ,
+.Fn tac_set_data ,
+.Fn tac_set_port ,
+.Fn tac_set_priv ,
+.Fn tac_set_rem_addr ,
+and
+.Fn tac_set_user .
+The library creates its own copies of any strings provided to these
+functions, so that it is not necessary for the caller to preserve
+them.
+By default, each of these parameters is empty except for the
+privilege level, which defaults to
+.Ql USER
+privilege.
+.Pp
+.Fn tac_set_av
+only applies to the context of an authorization request.
+The format
+for an attribute value pair is defined in the TACACS+ protocol
+specification.
+The index specified can be any value between 0 and
+255 inclusive and indicates the position in the list to place the
+attribute value pair.
+Calling
+.Fn tac_set_av
+with same index twice effectively replaces the value at that position.
+Use
+.Fn tac_clear_avs
+to clear all attribute value pairs that may have been set.
+.Sh SENDING THE AUTHENTICATION REQUEST AND RECEIVING THE RESPONSE
+After the TACACS+ authentication request has been constructed, it is
+sent by means of
+.Fn tac_send_authen .
+This function connects to a server if not already connected, sends
+the request, and waits for a reply.
+On failure,
+.Fn tac_send_authen
+returns \-1.
+Otherwise, it returns the TACACS+ status code and flags,
+packed into an integer value.
+The status can be extracted using the
+macro
+.Fn TAC_AUTHEN_STATUS .
+Possible status codes, defined in
+.In taclib.h ,
+include:
+.Pp
+.Bl -item -compact -offset indent
+.It
+.Dv TAC_AUTHEN_STATUS_PASS
+.It
+.Dv TAC_AUTHEN_STATUS_FAIL
+.It
+.Dv TAC_AUTHEN_STATUS_GETDATA
+.It
+.Dv TAC_AUTHEN_STATUS_GETUSER
+.It
+.Dv TAC_AUTHEN_STATUS_GETPASS
+.It
+.Dv TAC_AUTHEN_STATUS_RESTART
+.It
+.Dv TAC_AUTHEN_STATUS_ERROR
+.It
+.Dv TAC_AUTHEN_STATUS_FOLLOW
+.El
+.Pp
+The only flag is the no-echo flag, which can be tested using the
+macro
+.Fn TAC_AUTHEN_NOECHO .
+.Sh EXTRACTING INFORMATION FROM THE SERVER'S AUTHENTICATION RESPONSE
+An authentication response packet from the server may contain a
+server message, a data string, or both.
+After a successful call to
+.Fn tac_send_authen ,
+this information may be retrieved from the response by calling
+.Fn tac_get_msg
+and
+.Fn tac_get_data .
+These functions return dynamically-allocated copies of the
+information from the packet.
+The caller is responsible for freeing
+the copies when it no longer needs them.
+The data returned from
+these functions is guaranteed to be terminated by a null byte.
+.Pp
+In the case of
+.Fn tac_get_data ,
+the
+.Va len
+argument points to a location into which the library will store the
+actual length of the received data, not including the null
+terminator.
+This argument may be given as
+.Dv NULL
+if the caller is not interested in the length.
+.Sh SENDING AUTHENTICATION CONTINUE PACKETS
+If
+.Fn tac_send_authen
+returns a value containing one of the status codes
+.Dv TAC_AUTHEN_STATUS_GETDATA ,
+.Dv TAC_AUTHEN_STATUS_GETUSER ,
+or
+.Dv TAC_AUTHEN_STATUS_GETPASS ,
+then the client must provide additional information to the server by
+means of a TACACS+ CONTINUE packet.
+To do so, the application must
+first set the packet's user message and/or data fields using
+.Fn tac_set_msg
+and
+.Fn tac_set_data .
+The client then sends the CONTINUE packet with
+.Fn tac_send_authen .
+N.B.,
+.Fn tac_create_authen
+should
+.Em not
+be called to construct a CONTINUE packet; it is used only for the
+initial authentication request.
+.Pp
+When it receives the CONTINUE packet, the server may again request
+more information by returning
+.Dv TAC_AUTHEN_STATUS_GETDATA ,
+.Dv TAC_AUTHEN_STATUS_GETUSER ,
+or
+.Dv TAC_AUTHEN_STATUS_GETPASS .
+The application should send further CONTINUEs until some other
+status is received from the server.
+.Sh SENDING THE AUTHORIZATION REQUEST AND RECEIVING THE RESPONSE
+After the TACACS+ authorization request has been constructed, it
+is sent by means of
+.Fn tac_send_author .
+This function connects to a server if not already connected, sends
+the request, and waits for a reply.
+On failure,
+.Fn tac_send_author
+returns \-1.
+Otherwise, it returns the TACACS+ status code and
+number of attribute value (AV) pairs received packed into an
+integer value.
+The status can be extracted using the macro
+.Fn TAC_AUTHOR_STATUS .
+Possible status codes, defined in
+.In taclib.h ,
+include:
+.Pp
+.Bl -item -compact -offset indent
+.It
+.Dv TAC_AUTHOR_STATUS_PASS_ADD
+.It
+.Dv TAC_AUTHOR_STATUS_PASS_REPL
+.It
+.Dv TAC_AUTHOR_STATUS_FAIL
+.It
+.Dv TAC_AUTHOR_STATUS_ERROR
+.El
+.Pp
+The number of AV pairs received is obtained using
+.Fn TAC_AUTHEN_AV_COUNT .
+.Sh EXTRACTING INFORMATION FROM THE SERVER'S AUTHORIZATION RESPONSE
+Like an authentication response packet, an authorization
+response packet from the
+server may contain a server message, a data string, or both.
+Refer
+to EXTRACTING INFORMATION FROM THE SERVER'S AUTHENTICATION RESPONSE
+for instruction on extraction of those values.
+.Pp
+An authorization response packet from the server may also contain
+attribute value (AV) pairs.
+To extract these, use
+.Fn tac_get_av
+or
+.Fn tac_get_av_value .
+.Fn tac_get_av
+takes the index of the AV pair as it is positioned in the list.
+The indexes start at 0 (use
+.Fn TAC_AUTHEN_AV_COUNT
+on the return value of
+.Fn tac_send_author
+to get the total number of items in this list).
+Alternatively,
+.Fn tac_get_av_value
+can be used.
+.Fn tac_get_av_value
+takes the attribute name and returns the
+corresponding value only, not the AV pair.
+These functions return
+dynamically-allocated copies of the information from the packet.
+The caller is responsible for freeing the copies when it no longer
+needs them.
+The data returned from these functions is guaranteed
+to be terminated by a null byte.
+.Sh OBTAINING ERROR MESSAGES
+Those functions which accept a
+.Va struct tac_handle *
+argument record an error message if they fail.
+The error message
+can be retrieved by calling
+.Fn tac_strerror .
+The message text is overwritten on each new error for the given
+.Va struct tac_handle * .
+Thus the message must be copied if it is to be preserved through
+subsequent library calls using the same handle.
+.Sh CLEANUP
+To free the resources used by the TACACS+ library, call
+.Fn tac_close .
+.Sh RETURN VALUES
+The following functions return a non-negative value on success.
+If
+they detect an error, they return \-1 and record an error message
+which can be retrieved using
+.Fn tac_strerror .
+.Pp
+.Bl -item -offset indent -compact
+.It
+.Fn tac_add_server
+.It
+.Fn tac_config
+.It
+.Fn tac_create_authen
+.It
+.Fn tac_create_author
+.It
+.Fn tac_send_authen
+.It
+.Fn tac_send_author
+.It
+.Fn tac_set_av
+.It
+.Fn tac_set_data
+.It
+.Fn tac_set_msg
+.It
+.Fn tac_set_port
+.It
+.Fn tac_set_priv
+.It
+.Fn tac_set_rem_addr
+.It
+.Fn tac_set_user
+.El
+.Pp
+The following functions return a
+.No non- Ns Dv NULL
+pointer on success.
+If they are unable to allocate sufficient
+virtual memory, they return
+.Dv NULL
+and record an error message which can be retrieved using
+.Fn tac_strerror .
+.Pp
+.Bl -item -offset indent -compact
+.It
+.Fn tac_get_av
+.It
+.Fn tac_get_av_pair
+.It
+.Fn tac_get_data
+.It
+.Fn tac_get_msg
+.El
+.Pp
+The following functions return a
+.No non- Ns Dv NULL
+pointer on success.
+If they are unable to allocate sufficient
+virtual memory, they return
+.Dv NULL ,
+without recording an error message.
+.Pp
+.Bl -item -offset indent -compact
+.It
+.Fn tac_open
+.El
+.Sh FILES
+.Pa /etc/tacplus.conf
+.Sh SEE ALSO
+.Xr tacplus.conf 5
+.Rs
+.%A D. Carrel
+.%A Lol Grant
+.%T The TACACS+ Protocol, Version 1.78
+.%O draft-grant-tacacs-02.txt (Internet Draft)
+.Re
+.Sh AUTHORS
+.An -nosplit
+This software was written by
+.An John Polstra
+and
+.An Paul Fraley ,
+and donated to the
+.Fx
+project by Juniper Networks, Inc.
diff --git a/lib/libtacplus/taclib.c b/lib/libtacplus/taclib.c
new file mode 100644
index 0000000..6ac3c72
--- /dev/null
+++ b/lib/libtacplus/taclib.c
@@ -0,0 +1,1318 @@
+/*-
+ * Copyright (c) 1998, 2001, 2002, Juniper Networks, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <md5.h>
+#include <netdb.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "taclib_private.h"
+
+static int add_str_8(struct tac_handle *, u_int8_t *,
+ struct clnt_str *);
+static int add_str_16(struct tac_handle *, u_int16_t *,
+ struct clnt_str *);
+static int protocol_version(int, int, int);
+static void close_connection(struct tac_handle *);
+static int conn_server(struct tac_handle *);
+static void crypt_msg(struct tac_handle *, struct tac_msg *);
+static void *dup_str(struct tac_handle *, const struct srvr_str *,
+ size_t *);
+static int establish_connection(struct tac_handle *);
+static void free_str(struct clnt_str *);
+static void generr(struct tac_handle *, const char *, ...)
+ __printflike(2, 3);
+static void gen_session_id(struct tac_msg *);
+static int get_srvr_end(struct tac_handle *);
+static int get_srvr_str(struct tac_handle *, const char *,
+ struct srvr_str *, size_t);
+static void init_clnt_str(struct clnt_str *);
+static void init_srvr_str(struct srvr_str *);
+static int read_timed(struct tac_handle *, void *, size_t,
+ const struct timeval *);
+static int recv_msg(struct tac_handle *);
+static int save_str(struct tac_handle *, struct clnt_str *,
+ const void *, size_t);
+static int send_msg(struct tac_handle *);
+static int split(char *, char *[], int, char *, size_t);
+static void *xmalloc(struct tac_handle *, size_t);
+static char *xstrdup(struct tac_handle *, const char *);
+static void clear_srvr_avs(struct tac_handle *);
+static void create_msg(struct tac_handle *, int, int, int);
+
+/*
+ * Append some optional data to the current request, and store its
+ * length into the 8-bit field referenced by "fld". Returns 0 on
+ * success, or -1 on failure.
+ *
+ * This function also frees the "cs" string data and initializes it
+ * for the next time.
+ */
+static int
+add_str_8(struct tac_handle *h, u_int8_t *fld, struct clnt_str *cs)
+{
+ u_int16_t len;
+
+ if (add_str_16(h, &len, cs) == -1)
+ return -1;
+ len = ntohs(len);
+ if (len > 0xff) {
+ generr(h, "Field too long");
+ return -1;
+ }
+ *fld = len;
+ return 0;
+}
+
+/*
+ * Append some optional data to the current request, and store its
+ * length into the 16-bit field (network byte order) referenced by
+ * "fld". Returns 0 on success, or -1 on failure.
+ *
+ * This function also frees the "cs" string data and initializes it
+ * for the next time.
+ */
+static int
+add_str_16(struct tac_handle *h, u_int16_t *fld, struct clnt_str *cs)
+{
+ size_t len;
+
+ len = cs->len;
+ if (cs->data == NULL)
+ len = 0;
+ if (len != 0) {
+ int offset;
+
+ if (len > 0xffff) {
+ generr(h, "Field too long");
+ return -1;
+ }
+ offset = ntohl(h->request.length);
+ if (offset + len > BODYSIZE) {
+ generr(h, "Message too long");
+ return -1;
+ }
+ memcpy(h->request.u.body + offset, cs->data, len);
+ h->request.length = htonl(offset + len);
+ }
+ *fld = htons(len);
+ free_str(cs);
+ return 0;
+}
+
+static int
+protocol_version(int msg_type, int var, int type)
+{
+ int minor;
+
+ switch (msg_type) {
+ case TAC_AUTHEN:
+ /* 'var' represents the 'action' */
+ switch (var) {
+ case TAC_AUTHEN_LOGIN:
+ switch (type) {
+
+ case TAC_AUTHEN_TYPE_PAP:
+ case TAC_AUTHEN_TYPE_CHAP:
+ case TAC_AUTHEN_TYPE_MSCHAP:
+ case TAC_AUTHEN_TYPE_ARAP:
+ minor = 1;
+ break;
+
+ default:
+ minor = 0;
+ break;
+ }
+ break;
+
+ case TAC_AUTHEN_SENDAUTH:
+ minor = 1;
+ break;
+
+ default:
+ minor = 0;
+ break;
+ };
+ break;
+
+ case TAC_AUTHOR:
+ /* 'var' represents the 'method' */
+ switch (var) {
+ /*
+ * When new authentication methods are added, include 'method'
+ * in determining the value of 'minor'. At this point, all
+ * methods defined in this implementation (see "Authorization
+ * authentication methods" in taclib.h) are minor version 0
+ * Not all types, however, indicate minor version 0.
+ */
+ case TAC_AUTHEN_METH_NOT_SET:
+ case TAC_AUTHEN_METH_NONE:
+ case TAC_AUTHEN_METH_KRB5:
+ case TAC_AUTHEN_METH_LINE:
+ case TAC_AUTHEN_METH_ENABLE:
+ case TAC_AUTHEN_METH_LOCAL:
+ case TAC_AUTHEN_METH_TACACSPLUS:
+ case TAC_AUTHEN_METH_RCMD:
+ switch (type) {
+ case TAC_AUTHEN_TYPE_PAP:
+ case TAC_AUTHEN_TYPE_CHAP:
+ case TAC_AUTHEN_TYPE_MSCHAP:
+ case TAC_AUTHEN_TYPE_ARAP:
+ minor = 1;
+ break;
+
+ default:
+ minor = 0;
+ break;
+ }
+ break;
+ default:
+ minor = 0;
+ break;
+ }
+ break;
+
+ default:
+ minor = 0;
+ break;
+ }
+
+ return TAC_VER_MAJOR << 4 | minor;
+}
+
+
+static void
+close_connection(struct tac_handle *h)
+{
+ if (h->fd != -1) {
+ close(h->fd);
+ h->fd = -1;
+ }
+}
+
+static int
+conn_server(struct tac_handle *h)
+{
+ const struct tac_server *srvp = &h->servers[h->cur_server];
+ int flags;
+
+ if ((h->fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
+ generr(h, "Cannot create socket: %s", strerror(errno));
+ return -1;
+ }
+ if ((flags = fcntl(h->fd, F_GETFL, 0)) == -1 ||
+ fcntl(h->fd, F_SETFL, flags | O_NONBLOCK) == -1) {
+ generr(h, "Cannot set non-blocking mode on socket: %s",
+ strerror(errno));
+ close(h->fd);
+ h->fd = -1;
+ return -1;
+ }
+ if (connect(h->fd, (struct sockaddr *)&srvp->addr,
+ sizeof srvp->addr) == 0)
+ return 0;
+
+ if (errno == EINPROGRESS) {
+ fd_set wfds;
+ struct timeval tv;
+ int nfds;
+ struct sockaddr peer;
+ socklen_t errlen, peerlen;
+ int err;
+
+ /* Wait for the connection to complete. */
+ FD_ZERO(&wfds);
+ FD_SET(h->fd, &wfds);
+ tv.tv_sec = srvp->timeout;
+ tv.tv_usec = 0;
+ nfds = select(h->fd + 1, NULL, &wfds, NULL, &tv);
+ if (nfds == -1) {
+ generr(h, "select: %s", strerror(errno));
+ close(h->fd);
+ h->fd = -1;
+ return -1;
+ }
+ if (nfds == 0) {
+ generr(h, "connect: timed out");
+ close(h->fd);
+ h->fd = -1;
+ return -1;
+ }
+
+ /* See whether we are connected now. */
+ peerlen = sizeof peer;
+ if (getpeername(h->fd, &peer, &peerlen) == 0)
+ return 0;
+
+ if (errno != ENOTCONN) {
+ generr(h, "getpeername: %s", strerror(errno));
+ close(h->fd);
+ h->fd = -1;
+ return -1;
+ }
+
+ /* Find out why the connect failed. */
+ errlen = sizeof err;
+ getsockopt(h->fd, SOL_SOCKET, SO_ERROR, &err, &errlen);
+ errno = err;
+ }
+ generr(h, "connect: %s", strerror(errno));
+ close(h->fd);
+ h->fd = -1;
+ return -1;
+}
+
+/*
+ * Encrypt or decrypt a message. The operations are symmetrical.
+ */
+static void
+crypt_msg(struct tac_handle *h, struct tac_msg *msg)
+{
+ const char *secret;
+ MD5_CTX base_ctx;
+ MD5_CTX ctx;
+ unsigned char md5[16];
+ int chunk;
+ int msg_len;
+
+ secret = h->servers[h->cur_server].secret;
+ if (secret[0] == '\0')
+ msg->flags |= TAC_UNENCRYPTED;
+ if (msg->flags & TAC_UNENCRYPTED)
+ return;
+
+ msg_len = ntohl(msg->length);
+
+ MD5Init(&base_ctx);
+ MD5Update(&base_ctx, msg->session_id, sizeof msg->session_id);
+ MD5Update(&base_ctx, secret, strlen(secret));
+ MD5Update(&base_ctx, &msg->version, sizeof msg->version);
+ MD5Update(&base_ctx, &msg->seq_no, sizeof msg->seq_no);
+
+ ctx = base_ctx;
+ for (chunk = 0; chunk < msg_len; chunk += sizeof md5) {
+ int chunk_len;
+ int i;
+
+ MD5Final(md5, &ctx);
+
+ if ((chunk_len = msg_len - chunk) > sizeof md5)
+ chunk_len = sizeof md5;
+ for (i = 0; i < chunk_len; i++)
+ msg->u.body[chunk + i] ^= md5[i];
+
+ ctx = base_ctx;
+ MD5Update(&ctx, md5, sizeof md5);
+ }
+}
+
+/*
+ * Return a dynamically allocated copy of the given server string.
+ * The copy is null-terminated. If "len" is non-NULL, the length of
+ * the string (excluding the terminating null byte) is stored via it.
+ * Returns NULL on failure. Empty strings are still allocated even
+ * though they have no content.
+ */
+static void *
+dup_str(struct tac_handle *h, const struct srvr_str *ss, size_t *len)
+{
+ unsigned char *p;
+
+ if ((p = (unsigned char *)xmalloc(h, ss->len + 1)) == NULL)
+ return NULL;
+ if (ss->data != NULL && ss->len != 0)
+ memcpy(p, ss->data, ss->len);
+ p[ss->len] = '\0';
+ if (len != NULL)
+ *len = ss->len;
+ return p;
+}
+
+static int
+establish_connection(struct tac_handle *h)
+{
+ int i;
+
+ if (h->fd >= 0) /* Already connected. */
+ return 0;
+ if (h->num_servers == 0) {
+ generr(h, "No TACACS+ servers specified");
+ return -1;
+ }
+ /*
+ * Try the servers round-robin. We begin with the one that
+ * worked for us the last time. That way, once we find a good
+ * server, we won't waste any more time trying the bad ones.
+ */
+ for (i = 0; i < h->num_servers; i++) {
+ if (conn_server(h) == 0) {
+ h->single_connect = (h->servers[h->cur_server].flags &
+ TAC_SRVR_SINGLE_CONNECT) != 0;
+ return 0;
+ }
+ if (++h->cur_server >= h->num_servers) /* Wrap around */
+ h->cur_server = 0;
+ }
+ /* Just return whatever error was last reported by conn_server(). */
+ return -1;
+}
+
+/*
+ * Free a client string, obliterating its contents first for security.
+ */
+static void
+free_str(struct clnt_str *cs)
+{
+ if (cs->data != NULL) {
+ memset(cs->data, 0, cs->len);
+ free(cs->data);
+ cs->data = NULL;
+ cs->len = 0;
+ }
+}
+
+static void
+generr(struct tac_handle *h, const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ vsnprintf(h->errmsg, ERRSIZE, format, ap);
+ va_end(ap);
+}
+
+static void
+gen_session_id(struct tac_msg *msg)
+{
+ int r;
+
+ r = random();
+ msg->session_id[0] = r >> 8;
+ msg->session_id[1] = r;
+ r = random();
+ msg->session_id[2] = r >> 8;
+ msg->session_id[3] = r;
+}
+
+/*
+ * Verify that we are exactly at the end of the response message.
+ * Returns 0 on success, -1 on failure.
+ */
+static int
+get_srvr_end(struct tac_handle *h)
+{
+ int len;
+
+ len = ntohl(h->response.length);
+
+ if (h->srvr_pos != len) {
+ generr(h, "Invalid length field in response "
+ "from server: end expected at %u, response length %u",
+ h->srvr_pos, len);
+ return -1;
+ }
+ return 0;
+}
+
+static int
+get_srvr_str(struct tac_handle *h, const char *field,
+ struct srvr_str *ss, size_t len)
+{
+ if (h->srvr_pos + len > ntohl(h->response.length)) {
+ generr(h, "Invalid length field in %s response from server "
+ "(%lu > %lu)", field, (u_long)(h->srvr_pos + len),
+ (u_long)ntohl(h->response.length));
+ return -1;
+ }
+ ss->data = len != 0 ? h->response.u.body + h->srvr_pos : NULL;
+ ss->len = len;
+ h->srvr_pos += len;
+ return 0;
+}
+
+static void
+init_clnt_str(struct clnt_str *cs)
+{
+ cs->data = NULL;
+ cs->len = 0;
+}
+
+static void
+init_srvr_str(struct srvr_str *ss)
+{
+ ss->data = NULL;
+ ss->len = 0;
+}
+
+static int
+read_timed(struct tac_handle *h, void *buf, size_t len,
+ const struct timeval *deadline)
+{
+ char *ptr;
+
+ ptr = (char *)buf;
+ while (len > 0) {
+ int n;
+
+ n = read(h->fd, ptr, len);
+ if (n == -1) {
+ struct timeval tv;
+ int nfds;
+
+ if (errno != EAGAIN) {
+ generr(h, "Network read error: %s",
+ strerror(errno));
+ return -1;
+ }
+
+ /* Wait until we can read more data. */
+ gettimeofday(&tv, NULL);
+ timersub(deadline, &tv, &tv);
+ if (tv.tv_sec >= 0) {
+ fd_set rfds;
+
+ FD_ZERO(&rfds);
+ FD_SET(h->fd, &rfds);
+ nfds =
+ select(h->fd + 1, &rfds, NULL, NULL, &tv);
+ if (nfds == -1) {
+ generr(h, "select: %s",
+ strerror(errno));
+ return -1;
+ }
+ } else
+ nfds = 0;
+ if (nfds == 0) {
+ generr(h, "Network read timed out");
+ return -1;
+ }
+ } else if (n == 0) {
+ generr(h, "unexpected EOF from server");
+ return -1;
+ } else {
+ ptr += n;
+ len -= n;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Receive a response from the server and decrypt it. Returns 0 on
+ * success, or -1 on failure.
+ */
+static int
+recv_msg(struct tac_handle *h)
+{
+ struct timeval deadline;
+ struct tac_msg *msg;
+ u_int32_t len;
+
+ msg = &h->response;
+ gettimeofday(&deadline, NULL);
+ deadline.tv_sec += h->servers[h->cur_server].timeout;
+
+ /* Read the message header and make sure it is reasonable. */
+ if (read_timed(h, msg, HDRSIZE, &deadline) == -1)
+ return -1;
+ if (memcmp(msg->session_id, h->request.session_id,
+ sizeof msg->session_id) != 0) {
+ generr(h, "Invalid session ID in received message");
+ return -1;
+ }
+ if (msg->type != h->request.type) {
+ generr(h, "Invalid type in received message"
+ " (got %u, expected %u)",
+ msg->type, h->request.type);
+ return -1;
+ }
+ len = ntohl(msg->length);
+ if (len > BODYSIZE) {
+ generr(h, "Received message too large (%u > %u)",
+ len, BODYSIZE);
+ return -1;
+ }
+ if (msg->seq_no != ++h->last_seq_no) {
+ generr(h, "Invalid sequence number in received message"
+ " (got %u, expected %u)",
+ msg->seq_no, h->last_seq_no);
+ return -1;
+ }
+
+ /* Read the message body. */
+ if (read_timed(h, msg->u.body, len, &deadline) == -1)
+ return -1;
+
+ /* Decrypt it. */
+ crypt_msg(h, msg);
+
+ /*
+ * Turn off single-connection mode if the server isn't amenable
+ * to it.
+ */
+ if (!(msg->flags & TAC_SINGLE_CONNECT))
+ h->single_connect = 0;
+ return 0;
+}
+
+static int
+save_str(struct tac_handle *h, struct clnt_str *cs, const void *data,
+ size_t len)
+{
+ free_str(cs);
+ if (data != NULL && len != 0) {
+ if ((cs->data = xmalloc(h, len)) == NULL)
+ return -1;
+ cs->len = len;
+ memcpy(cs->data, data, len);
+ }
+ return 0;
+}
+
+/*
+ * Send the current request, after encrypting it. Returns 0 on success,
+ * or -1 on failure.
+ */
+static int
+send_msg(struct tac_handle *h)
+{
+ struct timeval deadline;
+ struct tac_msg *msg;
+ char *ptr;
+ int len;
+
+ if (h->last_seq_no & 1) {
+ generr(h, "Attempt to send message out of sequence");
+ return -1;
+ }
+
+ if (establish_connection(h) == -1)
+ return -1;
+
+ msg = &h->request;
+ msg->seq_no = ++h->last_seq_no;
+ if (msg->seq_no == 1)
+ gen_session_id(msg);
+ crypt_msg(h, msg);
+
+ if (h->single_connect)
+ msg->flags |= TAC_SINGLE_CONNECT;
+ else
+ msg->flags &= ~TAC_SINGLE_CONNECT;
+ gettimeofday(&deadline, NULL);
+ deadline.tv_sec += h->servers[h->cur_server].timeout;
+ len = HDRSIZE + ntohl(msg->length);
+ ptr = (char *)msg;
+ while (len > 0) {
+ int n;
+
+ n = write(h->fd, ptr, len);
+ if (n == -1) {
+ struct timeval tv;
+ int nfds;
+
+ if (errno != EAGAIN) {
+ generr(h, "Network write error: %s",
+ strerror(errno));
+ return -1;
+ }
+
+ /* Wait until we can write more data. */
+ gettimeofday(&tv, NULL);
+ timersub(&deadline, &tv, &tv);
+ if (tv.tv_sec >= 0) {
+ fd_set wfds;
+
+ FD_ZERO(&wfds);
+ FD_SET(h->fd, &wfds);
+ nfds =
+ select(h->fd + 1, NULL, &wfds, NULL, &tv);
+ if (nfds == -1) {
+ generr(h, "select: %s",
+ strerror(errno));
+ return -1;
+ }
+ } else
+ nfds = 0;
+ if (nfds == 0) {
+ generr(h, "Network write timed out");
+ return -1;
+ }
+ } else {
+ ptr += n;
+ len -= n;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Destructively split a string into fields separated by white space.
+ * `#' at the beginning of a field begins a comment that extends to the
+ * end of the string. Fields may be quoted with `"'. Inside quoted
+ * strings, the backslash escapes `\"' and `\\' are honored.
+ *
+ * Pointers to up to the first maxfields fields are stored in the fields
+ * array. Missing fields get NULL pointers.
+ *
+ * The return value is the actual number of fields parsed, and is always
+ * <= maxfields.
+ *
+ * On a syntax error, places a message in the msg string, and returns -1.
+ */
+static int
+split(char *str, char *fields[], int maxfields, char *msg, size_t msglen)
+{
+ char *p;
+ int i;
+ static const char ws[] = " \t";
+
+ for (i = 0; i < maxfields; i++)
+ fields[i] = NULL;
+ p = str;
+ i = 0;
+ while (*p != '\0') {
+ p += strspn(p, ws);
+ if (*p == '#' || *p == '\0')
+ break;
+ if (i >= maxfields) {
+ snprintf(msg, msglen, "line has too many fields");
+ return -1;
+ }
+ if (*p == '"') {
+ char *dst;
+
+ dst = ++p;
+ fields[i] = dst;
+ while (*p != '"') {
+ if (*p == '\\') {
+ p++;
+ if (*p != '"' && *p != '\\' &&
+ *p != '\0') {
+ snprintf(msg, msglen,
+ "invalid `\\' escape");
+ return -1;
+ }
+ }
+ if (*p == '\0') {
+ snprintf(msg, msglen,
+ "unterminated quoted string");
+ return -1;
+ }
+ *dst++ = *p++;
+ }
+ *dst = '\0';
+ p++;
+ if (*p != '\0' && strspn(p, ws) == 0) {
+ snprintf(msg, msglen, "quoted string not"
+ " followed by white space");
+ return -1;
+ }
+ } else {
+ fields[i] = p;
+ p += strcspn(p, ws);
+ if (*p != '\0')
+ *p++ = '\0';
+ }
+ i++;
+ }
+ return i;
+}
+
+int
+tac_add_server(struct tac_handle *h, const char *host, int port,
+ const char *secret, int timeout, int flags)
+{
+ struct tac_server *srvp;
+
+ if (h->num_servers >= MAXSERVERS) {
+ generr(h, "Too many TACACS+ servers specified");
+ return -1;
+ }
+ srvp = &h->servers[h->num_servers];
+
+ memset(&srvp->addr, 0, sizeof srvp->addr);
+ srvp->addr.sin_len = sizeof srvp->addr;
+ srvp->addr.sin_family = AF_INET;
+ if (!inet_aton(host, &srvp->addr.sin_addr)) {
+ struct hostent *hent;
+
+ if ((hent = gethostbyname(host)) == NULL) {
+ generr(h, "%s: host not found", host);
+ return -1;
+ }
+ memcpy(&srvp->addr.sin_addr, hent->h_addr,
+ sizeof srvp->addr.sin_addr);
+ }
+ srvp->addr.sin_port = htons(port != 0 ? port : TACPLUS_PORT);
+ if ((srvp->secret = xstrdup(h, secret)) == NULL)
+ return -1;
+ srvp->timeout = timeout;
+ srvp->flags = flags;
+ h->num_servers++;
+ return 0;
+}
+
+void
+tac_close(struct tac_handle *h)
+{
+ int i, srv;
+
+ if (h->fd != -1)
+ close(h->fd);
+ for (srv = 0; srv < h->num_servers; srv++) {
+ memset(h->servers[srv].secret, 0,
+ strlen(h->servers[srv].secret));
+ free(h->servers[srv].secret);
+ }
+ free_str(&h->user);
+ free_str(&h->port);
+ free_str(&h->rem_addr);
+ free_str(&h->data);
+ free_str(&h->user_msg);
+ for (i=0; i<MAXAVPAIRS; i++)
+ free_str(&(h->avs[i]));
+
+ /* Clear everything else before freeing memory */
+ memset(h, 0, sizeof(struct tac_handle));
+ free(h);
+}
+
+int
+tac_config(struct tac_handle *h, const char *path)
+{
+ FILE *fp;
+ char buf[MAXCONFLINE];
+ int linenum;
+ int retval;
+
+ if (path == NULL)
+ path = PATH_TACPLUS_CONF;
+ if ((fp = fopen(path, "r")) == NULL) {
+ generr(h, "Cannot open \"%s\": %s", path, strerror(errno));
+ return -1;
+ }
+ retval = 0;
+ linenum = 0;
+ while (fgets(buf, sizeof buf, fp) != NULL) {
+ int len;
+ char *fields[4];
+ int nfields;
+ char msg[ERRSIZE];
+ char *host, *res;
+ char *port_str;
+ char *secret;
+ char *timeout_str;
+ char *options_str;
+ char *end;
+ unsigned long timeout;
+ int port;
+ int options;
+
+ linenum++;
+ len = strlen(buf);
+ /* We know len > 0, else fgets would have returned NULL. */
+ if (buf[len - 1] != '\n') {
+ if (len >= sizeof buf - 1)
+ generr(h, "%s:%d: line too long", path,
+ linenum);
+ else
+ generr(h, "%s:%d: missing newline", path,
+ linenum);
+ retval = -1;
+ break;
+ }
+ buf[len - 1] = '\0';
+
+ /* Extract the fields from the line. */
+ nfields = split(buf, fields, 4, msg, sizeof msg);
+ if (nfields == -1) {
+ generr(h, "%s:%d: %s", path, linenum, msg);
+ retval = -1;
+ break;
+ }
+ if (nfields == 0)
+ continue;
+ if (nfields < 2) {
+ generr(h, "%s:%d: missing shared secret", path,
+ linenum);
+ retval = -1;
+ break;
+ }
+ host = fields[0];
+ secret = fields[1];
+ timeout_str = fields[2];
+ options_str = fields[3];
+
+ /* Parse and validate the fields. */
+ res = host;
+ host = strsep(&res, ":");
+ port_str = strsep(&res, ":");
+ if (port_str != NULL) {
+ port = strtoul(port_str, &end, 10);
+ if (port_str[0] == '\0' || *end != '\0') {
+ generr(h, "%s:%d: invalid port", path,
+ linenum);
+ retval = -1;
+ break;
+ }
+ } else
+ port = 0;
+ if (timeout_str != NULL) {
+ timeout = strtoul(timeout_str, &end, 10);
+ if (timeout_str[0] == '\0' || *end != '\0') {
+ generr(h, "%s:%d: invalid timeout", path,
+ linenum);
+ retval = -1;
+ break;
+ }
+ } else
+ timeout = TIMEOUT;
+ options = 0;
+ if (options_str != NULL) {
+ if (strcmp(options_str, "single-connection") == 0)
+ options |= TAC_SRVR_SINGLE_CONNECT;
+ else {
+ generr(h, "%s:%d: invalid option \"%s\"",
+ path, linenum, options_str);
+ retval = -1;
+ break;
+ }
+ };
+
+ if (tac_add_server(h, host, port, secret, timeout,
+ options) == -1) {
+ char msg[ERRSIZE];
+
+ strcpy(msg, h->errmsg);
+ generr(h, "%s:%d: %s", path, linenum, msg);
+ retval = -1;
+ break;
+ }
+ }
+ /* Clear out the buffer to wipe a possible copy of a shared secret */
+ memset(buf, 0, sizeof buf);
+ fclose(fp);
+ return retval;
+}
+
+int
+tac_create_authen(struct tac_handle *h, int action, int type, int service)
+{
+ struct tac_authen_start *as;
+
+ create_msg(h, TAC_AUTHEN, action, type);
+
+ as = &h->request.u.authen_start;
+ as->action = action;
+ as->priv_lvl = TAC_PRIV_LVL_USER;
+ as->authen_type = type;
+ as->service = service;
+
+ return 0;
+}
+
+int
+tac_create_author(struct tac_handle *h, int method, int type, int service)
+{
+ struct tac_author_request *areq;
+
+ create_msg(h, TAC_AUTHOR, method, type);
+
+ areq = &h->request.u.author_request;
+ areq->authen_meth = method;
+ areq->priv_lvl = TAC_PRIV_LVL_USER;
+ areq->authen_type = type;
+ areq->service = service;
+
+ return 0;
+}
+
+static void
+create_msg(struct tac_handle *h, int msg_type, int var, int type)
+{
+ struct tac_msg *msg;
+ int i;
+
+ h->last_seq_no = 0;
+
+ msg = &h->request;
+ msg->type = msg_type;
+ msg->version = protocol_version(msg_type, var, type);
+ msg->flags = 0; /* encrypted packet body */
+
+ free_str(&h->user);
+ free_str(&h->port);
+ free_str(&h->rem_addr);
+ free_str(&h->data);
+ free_str(&h->user_msg);
+
+ for (i=0; i<MAXAVPAIRS; i++)
+ free_str(&(h->avs[i]));
+}
+
+void *
+tac_get_data(struct tac_handle *h, size_t *len)
+{
+ return dup_str(h, &h->srvr_data, len);
+}
+
+char *
+tac_get_msg(struct tac_handle *h)
+{
+ return dup_str(h, &h->srvr_msg, NULL);
+}
+
+/*
+ * Create and initialize a tac_handle structure, and return it to the
+ * caller. Can fail only if the necessary memory cannot be allocated.
+ * In that case, it returns NULL.
+ */
+struct tac_handle *
+tac_open(void)
+{
+ int i;
+ struct tac_handle *h;
+
+ h = (struct tac_handle *)malloc(sizeof(struct tac_handle));
+ if (h != NULL) {
+ h->fd = -1;
+ h->num_servers = 0;
+ h->cur_server = 0;
+ h->errmsg[0] = '\0';
+ init_clnt_str(&h->user);
+ init_clnt_str(&h->port);
+ init_clnt_str(&h->rem_addr);
+ init_clnt_str(&h->data);
+ init_clnt_str(&h->user_msg);
+ for (i=0; i<MAXAVPAIRS; i++) {
+ init_clnt_str(&(h->avs[i]));
+ init_srvr_str(&(h->srvr_avs[i]));
+ }
+ init_srvr_str(&h->srvr_msg);
+ init_srvr_str(&h->srvr_data);
+ srandomdev();
+ }
+ return h;
+}
+
+int
+tac_send_authen(struct tac_handle *h)
+{
+ struct tac_authen_reply *ar;
+
+ if (h->num_servers == 0)
+ return -1;
+
+ if (h->last_seq_no == 0) { /* Authentication START packet */
+ struct tac_authen_start *as;
+
+ as = &h->request.u.authen_start;
+ h->request.length =
+ htonl(offsetof(struct tac_authen_start, rest[0]));
+ if (add_str_8(h, &as->user_len, &h->user) == -1 ||
+ add_str_8(h, &as->port_len, &h->port) == -1 ||
+ add_str_8(h, &as->rem_addr_len, &h->rem_addr) == -1 ||
+ add_str_8(h, &as->data_len, &h->data) == -1)
+ return -1;
+ } else { /* Authentication CONTINUE packet */
+ struct tac_authen_cont *ac;
+
+ ac = &h->request.u.authen_cont;
+ ac->flags = 0;
+ h->request.length =
+ htonl(offsetof(struct tac_authen_cont, rest[0]));
+ if (add_str_16(h, &ac->user_msg_len, &h->user_msg) == -1 ||
+ add_str_16(h, &ac->data_len, &h->data) == -1)
+ return -1;
+ }
+
+ /* Send the message and retrieve the reply. */
+ if (send_msg(h) == -1 || recv_msg(h) == -1)
+ return -1;
+
+ /* Scan the optional fields in the reply. */
+ ar = &h->response.u.authen_reply;
+ h->srvr_pos = offsetof(struct tac_authen_reply, rest[0]);
+ if (get_srvr_str(h, "msg", &h->srvr_msg, ntohs(ar->msg_len)) == -1 ||
+ get_srvr_str(h, "data", &h->srvr_data, ntohs(ar->data_len)) == -1 ||
+ get_srvr_end(h) == -1)
+ return -1;
+
+ if (!h->single_connect &&
+ ar->status != TAC_AUTHEN_STATUS_GETDATA &&
+ ar->status != TAC_AUTHEN_STATUS_GETUSER &&
+ ar->status != TAC_AUTHEN_STATUS_GETPASS)
+ close_connection(h);
+
+ return ar->flags << 8 | ar->status;
+}
+
+int
+tac_send_author(struct tac_handle *h)
+{
+ int i, current;
+ char dbgstr[64];
+ struct tac_author_request *areq = &h->request.u.author_request;
+ struct tac_author_response *ares = &h->response.u.author_response;
+
+ h->request.length =
+ htonl(offsetof(struct tac_author_request, rest[0]));
+
+ /* Count each specified AV pair */
+ for (areq->av_cnt=0, i=0; i<MAXAVPAIRS; i++)
+ if (h->avs[i].len && h->avs[i].data)
+ areq->av_cnt++;
+
+ /*
+ * Each AV size is a byte starting right after 'av_cnt'. Update the
+ * offset to include these AV sizes.
+ */
+ h->request.length = ntohl(htonl(h->request.length) + areq->av_cnt);
+
+ /* Now add the string arguments from 'h' */
+ if (add_str_8(h, &areq->user_len, &h->user) == -1 ||
+ add_str_8(h, &areq->port_len, &h->port) == -1 ||
+ add_str_8(h, &areq->rem_addr_len, &h->rem_addr) == -1)
+ return -1;
+
+ /* Add each AV pair, the size of each placed in areq->rest[current] */
+ for (current=0, i=0; i<MAXAVPAIRS; i++) {
+ if (h->avs[i].len && h->avs[i].data) {
+ if (add_str_8(h, &areq->rest[current++],
+ &(h->avs[i])) == -1)
+ return -1;
+ }
+ }
+
+ /* Send the message and retrieve the reply. */
+ if (send_msg(h) == -1 || recv_msg(h) == -1)
+ return -1;
+
+ /* Update the offset in the response packet based on av pairs count */
+ h->srvr_pos = offsetof(struct tac_author_response, rest[0]) +
+ ares->av_cnt;
+
+ /* Scan the optional fields in the response. */
+ if (get_srvr_str(h, "msg", &h->srvr_msg, ntohs(ares->msg_len)) == -1 ||
+ get_srvr_str(h, "data", &h->srvr_data, ntohs(ares->data_len)) ==-1)
+ return -1;
+
+ /* Get each AV pair (just setting pointers, not malloc'ing) */
+ clear_srvr_avs(h);
+ for (i=0; i<ares->av_cnt; i++) {
+ snprintf(dbgstr, sizeof dbgstr, "av-pair-%d", i);
+ if (get_srvr_str(h, dbgstr, &(h->srvr_avs[i]),
+ ares->rest[i]) == -1)
+ return -1;
+ }
+
+ /* Should have ended up at the end */
+ if (get_srvr_end(h) == -1)
+ return -1;
+
+ /* Sanity checks */
+ if (!h->single_connect)
+ close_connection(h);
+
+ return ares->av_cnt << 8 | ares->status;
+}
+
+int
+tac_set_rem_addr(struct tac_handle *h, const char *addr)
+{
+ return save_str(h, &h->rem_addr, addr, addr != NULL ? strlen(addr) : 0);
+}
+
+int
+tac_set_data(struct tac_handle *h, const void *data, size_t data_len)
+{
+ return save_str(h, &h->data, data, data_len);
+}
+
+int
+tac_set_msg(struct tac_handle *h, const char *msg)
+{
+ return save_str(h, &h->user_msg, msg, msg != NULL ? strlen(msg) : 0);
+}
+
+int
+tac_set_port(struct tac_handle *h, const char *port)
+{
+ return save_str(h, &h->port, port, port != NULL ? strlen(port) : 0);
+}
+
+int
+tac_set_priv(struct tac_handle *h, int priv)
+{
+ if (!(TAC_PRIV_LVL_MIN <= priv && priv <= TAC_PRIV_LVL_MAX)) {
+ generr(h, "Attempt to set invalid privilege level");
+ return -1;
+ }
+ h->request.u.authen_start.priv_lvl = priv;
+ return 0;
+}
+
+int
+tac_set_user(struct tac_handle *h, const char *user)
+{
+ return save_str(h, &h->user, user, user != NULL ? strlen(user) : 0);
+}
+
+int
+tac_set_av(struct tac_handle *h, u_int index, const char *av)
+{
+ if (index >= MAXAVPAIRS)
+ return -1;
+ return save_str(h, &(h->avs[index]), av, av != NULL ? strlen(av) : 0);
+}
+
+char *
+tac_get_av(struct tac_handle *h, u_int index)
+{
+ if (index >= MAXAVPAIRS)
+ return NULL;
+ return dup_str(h, &(h->srvr_avs[index]), NULL);
+}
+
+char *
+tac_get_av_value(struct tac_handle *h, const char *attribute)
+{
+ int i, len;
+ const char *ch, *end;
+ const char *candidate;
+ int candidate_len;
+ int found_seperator;
+ struct srvr_str srvr;
+
+ if (attribute == NULL || ((len = strlen(attribute)) == 0))
+ return NULL;
+
+ for (i=0; i<MAXAVPAIRS; i++) {
+ candidate = h->srvr_avs[i].data;
+ candidate_len = h->srvr_avs[i].len;
+
+ /*
+ * Valid 'srvr_avs' guaranteed to be contiguous starting at
+ * index 0 (not necessarily the case with 'avs'). Break out
+ * when the "end" of the list has been reached.
+ */
+ if (!candidate)
+ break;
+
+ if (len < candidate_len &&
+ !strncmp(candidate, attribute, len)) {
+
+ ch = candidate + len;
+ end = candidate + candidate_len;
+
+ /*
+ * Sift out the white space between A and V (should not
+ * be any, but don't trust implementation of server...)
+ */
+ found_seperator = 0;
+ while ((*ch == '=' || *ch == '*' || *ch == ' ' ||
+ *ch == '\t') && ch != end) {
+ if (*ch == '=' || *ch == '*')
+ found_seperator++;
+ ch++;
+ }
+
+ /*
+ * Note:
+ * The case of 'attribute' == "foo" and
+ * h->srvr_avs[0] = "foobie=var1"
+ * h->srvr_avs[1] = "foo=var2"
+ * is handled.
+ */
+ if (found_seperator == 1 && ch != end) {
+ srvr.len = end - ch;
+ srvr.data = ch;
+ return dup_str(h, &srvr, NULL);
+ }
+ }
+ }
+ return NULL;
+}
+
+void
+tac_clear_avs(struct tac_handle *h)
+{
+ int i;
+ for (i=0; i<MAXAVPAIRS; i++)
+ save_str(h, &(h->avs[i]), NULL, 0);
+}
+
+static void
+clear_srvr_avs(struct tac_handle *h)
+{
+ int i;
+ for (i=0; i<MAXAVPAIRS; i++)
+ init_srvr_str(&(h->srvr_avs[i]));
+}
+
+
+const char *
+tac_strerror(struct tac_handle *h)
+{
+ return h->errmsg;
+}
+
+static void *
+xmalloc(struct tac_handle *h, size_t size)
+{
+ void *r;
+
+ if ((r = malloc(size)) == NULL)
+ generr(h, "Out of memory");
+ return r;
+}
+
+static char *
+xstrdup(struct tac_handle *h, const char *s)
+{
+ char *r;
+
+ if ((r = strdup(s)) == NULL)
+ generr(h, "Out of memory");
+ return r;
+}
diff --git a/lib/libtacplus/taclib.h b/lib/libtacplus/taclib.h
new file mode 100644
index 0000000..2ef36b9
--- /dev/null
+++ b/lib/libtacplus/taclib.h
@@ -0,0 +1,132 @@
+/*-
+ * Copyright (c) 1998, 2001, Juniper Networks, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _TACLIB_H_
+#define _TACLIB_H_
+
+#include <sys/types.h>
+
+struct tac_handle;
+
+/* Flags for tac_add_server(). */
+#define TAC_SRVR_SINGLE_CONNECT 0x04 /* Keep connection open for multiple
+ sessions. */
+
+/* Disassembly of tac_send_authen() return value. */
+#define TAC_AUTHEN_STATUS(s) ((s) & 0xff)
+#define TAC_AUTHEN_NOECHO(s) ((s) & (1<<8))
+
+/* Disassembly of tac_send_author() return value. */
+#define TAC_AUTHOR_STATUS(s) ((s) & 0xff)
+#define TAC_AUTHEN_AV_COUNT(s) (((s)>>8) & 0xff)
+
+/* Privilege levels */
+#define TAC_PRIV_LVL_MIN 0x00
+#define TAC_PRIV_LVL_USER 0x01
+#define TAC_PRIV_LVL_ROOT 0x0f
+#define TAC_PRIV_LVL_MAX 0x0f
+
+/* Authentication actions */
+#define TAC_AUTHEN_LOGIN 0x01
+#define TAC_AUTHEN_CHPASS 0x02
+#define TAC_AUTHEN_SENDPASS 0x03
+#define TAC_AUTHEN_SENDAUTH 0x04
+
+/* Authentication types */
+#define TAC_AUTHEN_TYPE_ASCII 0x01
+#define TAC_AUTHEN_TYPE_PAP 0x02
+#define TAC_AUTHEN_TYPE_CHAP 0x03
+#define TAC_AUTHEN_TYPE_ARAP 0x04
+#define TAC_AUTHEN_TYPE_MSCHAP 0x05
+
+/* Authentication services */
+#define TAC_AUTHEN_SVC_NONE 0x00
+#define TAC_AUTHEN_SVC_LOGIN 0x01
+#define TAC_AUTHEN_SVC_ENABLE 0x02
+#define TAC_AUTHEN_SVC_PPP 0x03
+#define TAC_AUTHEN_SVC_ARAP 0x04
+#define TAC_AUTHEN_SVC_PT 0x05
+#define TAC_AUTHEN_SVC_RCMD 0x06
+#define TAC_AUTHEN_SVC_X25 0x07
+#define TAC_AUTHEN_SVC_NASI 0x08
+#define TAC_AUTHEN_SVC_FWPROXY 0x09
+
+/* Authentication reply status codes */
+#define TAC_AUTHEN_STATUS_PASS 0x01
+#define TAC_AUTHEN_STATUS_FAIL 0x02
+#define TAC_AUTHEN_STATUS_GETDATA 0x03
+#define TAC_AUTHEN_STATUS_GETUSER 0x04
+#define TAC_AUTHEN_STATUS_GETPASS 0x05
+#define TAC_AUTHEN_STATUS_RESTART 0x06
+#define TAC_AUTHEN_STATUS_ERROR 0x07
+#define TAC_AUTHEN_STATUS_FOLLOW 0x21
+
+/* Authorization authenticatication methods */
+#define TAC_AUTHEN_METH_NOT_SET 0x00
+#define TAC_AUTHEN_METH_NONE 0x01
+#define TAC_AUTHEN_METH_KRB5 0x02
+#define TAC_AUTHEN_METH_LINE 0x03
+#define TAC_AUTHEN_METH_ENABLE 0x04
+#define TAC_AUTHEN_METH_LOCAL 0x05
+#define TAC_AUTHEN_METH_TACACSPLUS 0x06
+#define TAC_AUTHEN_METH_RCMD 0x20
+/* If adding more, see comments in protocol_version() in taclib.c */
+
+/* Authorization status */
+#define TAC_AUTHOR_STATUS_PASS_ADD 0x01
+#define TAC_AUTHOR_STATUS_PASS_REPL 0x02
+#define TAC_AUTHOR_STATUS_FAIL 0x10
+#define TAC_AUTHOR_STATUS_ERROR 0x11
+
+__BEGIN_DECLS
+int tac_add_server(struct tac_handle *,
+ const char *, int, const char *, int, int);
+void tac_close(struct tac_handle *);
+int tac_config(struct tac_handle *, const char *);
+int tac_create_authen(struct tac_handle *, int, int, int);
+void *tac_get_data(struct tac_handle *, size_t *);
+char *tac_get_msg(struct tac_handle *);
+struct tac_handle *tac_open(void);
+int tac_send_authen(struct tac_handle *);
+int tac_set_data(struct tac_handle *,
+ const void *, size_t);
+int tac_set_msg(struct tac_handle *, const char *);
+int tac_set_port(struct tac_handle *, const char *);
+int tac_set_priv(struct tac_handle *, int);
+int tac_set_rem_addr(struct tac_handle *, const char *);
+int tac_set_user(struct tac_handle *, const char *);
+const char *tac_strerror(struct tac_handle *);
+int tac_send_author(struct tac_handle *);
+int tac_create_author(struct tac_handle *, int, int, int);
+int tac_set_av(struct tac_handle *, u_int, const char *);
+char *tac_get_av(struct tac_handle *, u_int);
+char *tac_get_av_value(struct tac_handle *, const char *);
+void tac_clear_avs(struct tac_handle *);
+__END_DECLS
+
+#endif /* _TACLIB_H_ */
diff --git a/lib/libtacplus/taclib_private.h b/lib/libtacplus/taclib_private.h
new file mode 100644
index 0000000..bbc1990
--- /dev/null
+++ b/lib/libtacplus/taclib_private.h
@@ -0,0 +1,177 @@
+/*-
+ * Copyright (c) 1998, 2001, Juniper Networks, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef TACLIB_PRIVATE_H
+#define TACLIB_PRIVATE_H
+
+#include "taclib.h"
+
+/* Defaults */
+#define PATH_TACPLUS_CONF "/etc/tacplus.conf"
+#define TACPLUS_PORT 49
+#define TIMEOUT 3 /* In seconds */
+
+/* Limits */
+#define BODYSIZE 8150 /* Maximum message body size */
+#define ERRSIZE 128 /* Maximum error message length */
+#define MAXCONFLINE 1024 /* Maximum config file line length */
+#define MAXSERVERS 10 /* Maximum number of servers to try */
+#define MAXAVPAIRS 255 /* Maximum number of AV pairs */
+
+/* Protocol constants. */
+#define HDRSIZE 12 /* Size of message header */
+
+/* Protocol version number */
+#define TAC_VER_MAJOR 0xc /* Major version number */
+
+/* Protocol packet types */
+#define TAC_AUTHEN 0x01 /* Authentication */
+#define TAC_AUTHOR 0x02 /* Authorization */
+#define TAC_ACCT 0x03 /* Accouting */
+
+/* Protocol header flags */
+#define TAC_UNENCRYPTED 0x01
+#define TAC_SINGLE_CONNECT 0x04
+
+struct tac_server {
+ struct sockaddr_in addr; /* Address of server */
+ char *secret; /* Shared secret */
+ int timeout; /* Timeout in seconds */
+ int flags;
+};
+
+/*
+ * An optional string of bytes specified by the client for inclusion in
+ * a request. The data is always a dynamically allocated copy that
+ * belongs to the library. It is copied into the request packet just
+ * before sending the request.
+ */
+struct clnt_str {
+ void *data;
+ size_t len;
+};
+
+/*
+ * An optional string of bytes from a server response. The data resides
+ * in the response packet itself, and must not be freed.
+ */
+struct srvr_str {
+ const void *data;
+ size_t len;
+};
+
+struct tac_authen_start {
+ u_int8_t action;
+ u_int8_t priv_lvl;
+ u_int8_t authen_type;
+ u_int8_t service;
+ u_int8_t user_len;
+ u_int8_t port_len;
+ u_int8_t rem_addr_len;
+ u_int8_t data_len;
+ unsigned char rest[1];
+};
+
+struct tac_authen_reply {
+ u_int8_t status;
+ u_int8_t flags;
+ u_int16_t msg_len;
+ u_int16_t data_len;
+ unsigned char rest[1];
+};
+
+struct tac_authen_cont {
+ u_int16_t user_msg_len;
+ u_int16_t data_len;
+ u_int8_t flags;
+ unsigned char rest[1];
+};
+
+struct tac_author_request {
+ u_int8_t authen_meth;
+ u_int8_t priv_lvl;
+ u_int8_t authen_type;
+ u_int8_t service;
+ u_int8_t user_len;
+ u_int8_t port_len;
+ u_int8_t rem_addr_len;
+ u_int8_t av_cnt;
+ unsigned char rest[1];
+};
+
+struct tac_author_response {
+ u_int8_t status;
+ u_int8_t av_cnt;
+ u_int16_t msg_len;
+ u_int16_t data_len;
+ unsigned char rest[1];
+};
+
+struct tac_msg {
+ u_int8_t version;
+ u_int8_t type;
+ u_int8_t seq_no;
+ u_int8_t flags;
+ u_int8_t session_id[4];
+ u_int32_t length;
+ union {
+ struct tac_authen_start authen_start;
+ struct tac_authen_reply authen_reply;
+ struct tac_authen_cont authen_cont;
+ struct tac_author_request author_request;
+ struct tac_author_response author_response;
+ unsigned char body[BODYSIZE];
+ } u;
+};
+
+struct tac_handle {
+ int fd; /* Socket file descriptor */
+ struct tac_server servers[MAXSERVERS]; /* Servers to contact */
+ int num_servers; /* Number of valid server entries */
+ int cur_server; /* Server we are currently using */
+ int single_connect; /* Use a single connection */
+ int last_seq_no;
+ char errmsg[ERRSIZE]; /* Most recent error message */
+
+ struct clnt_str user;
+ struct clnt_str port;
+ struct clnt_str rem_addr;
+ struct clnt_str data;
+ struct clnt_str user_msg;
+ struct clnt_str avs[MAXAVPAIRS];
+
+ struct tac_msg request;
+ struct tac_msg response;
+
+ int srvr_pos; /* Scan position in response body */
+ struct srvr_str srvr_msg;
+ struct srvr_str srvr_data;
+ struct srvr_str srvr_avs[MAXAVPAIRS];
+};
+
+#endif
diff --git a/lib/libtacplus/tacplus.conf.5 b/lib/libtacplus/tacplus.conf.5
new file mode 100644
index 0000000..e68982d
--- /dev/null
+++ b/lib/libtacplus/tacplus.conf.5
@@ -0,0 +1,134 @@
+.\" Copyright 1998 Juniper Networks, Inc.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd July 29, 1998
+.Dt TACPLUS.CONF 5
+.Os
+.Sh NAME
+.Nm tacplus.conf
+.Nd TACACS+ client configuration file
+.Sh SYNOPSIS
+.Pa /etc/tacplus.conf
+.Sh DESCRIPTION
+.Nm
+contains the information necessary to configure the TACACS+ client
+library.
+It is parsed by
+.Fn tac_config
+(see
+.Xr libtacplus 3 ) .
+The file contains one or more lines of text, each describing a
+single TACACS+ server which is to be used by the library.
+Leading
+white space is ignored, as are empty lines and lines containing
+only comments.
+.Pp
+A TACACS+ server is described by two to four fields on a line.
+The
+fields are separated by white space.
+The
+.Ql #
+character at the beginning of a field begins a comment, which extends
+to the end of the line.
+A field may be enclosed in double quotes,
+in which case it may contain white space and/or begin with the
+.Ql #
+character.
+Within a quoted string, the double quote character can
+be represented by
+.Ql \e\&" ,
+and the backslash can be represented by
+.Ql \e\e .
+No other escape sequences are supported.
+.Pp
+The first field specifies
+the server host, either as a fully qualified domain name or as a
+dotted-quad IP address.
+The host may optionally be followed by a
+.Ql \&:
+and a numeric port number, without intervening white space.
+If the
+port specification is omitted, it defaults to 49, the standard TACACS+
+port.
+.Pp
+The second field contains the shared secret, which should be known
+only to the client and server hosts.
+It is an arbitrary string
+of characters, though it must be enclosed in double quotes if it
+contains white space or is empty.
+An empty secret disables the
+normal encryption mechanism, causing all data to cross the network in
+cleartext.
+.Pp
+The third field contains a decimal integer specifying the timeout
+in seconds for communicating with the server.
+The timeout applies
+separately to each connect, write, and read operation.
+If this field
+is omitted, it defaults to 3 seconds.
+.Pp
+The optional fourth field may contain the string
+.Ql single-connection .
+If this option is included, the library will attempt to negotiate
+with the server to keep the TCP connection open for multiple
+sessions.
+Some older TACACS+ servers become confused if this option
+is specified.
+.Pp
+Up to 10 TACACS+ servers may be specified.
+The servers are tried in
+order, until a valid response is received or the list is exhausted.
+.Pp
+The standard location for this file is
+.Pa /etc/tacplus.conf .
+An alternate pathname may be specified in the call to
+.Fn tac_config
+(see
+.Xr libtacplus 3 ) .
+Since the file contains sensitive information in the form of the
+shared secrets, it should not be readable except by root.
+.Sh FILES
+.Pa /etc/tacplus.conf
+.Sh EXAMPLES
+.Bd -literal
+# A simple entry using all the defaults:
+tacserver.domain.com OurLittleSecret
+
+# A server using a non-standard port, with an increased timeout and
+# the "single-connection" option.
+auth.domain.com:4333 "Don't tell!!" 15 single-connection
+
+# A server specified by its IP address:
+192.168.27.81 $X*#..38947ax-+=
+.Ed
+.Sh SEE ALSO
+.Xr libtacplus 3
+.Sh AUTHORS
+This documentation was written by
+.An John Polstra ,
+and donated to the
+.Fx
+project by Juniper Networks, Inc.
diff --git a/lib/libtelnet/Makefile b/lib/libtelnet/Makefile
new file mode 100644
index 0000000..eda86aa
--- /dev/null
+++ b/lib/libtelnet/Makefile
@@ -0,0 +1,33 @@
+# From: @(#)Makefile 8.2 (Berkeley) 12/15/93
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+TELNETDIR= ${.CURDIR}/../../contrib/telnet
+.PATH: ${TELNETDIR}/libtelnet
+
+LIB= telnet
+
+INTERNALLIB=
+
+SRCS= genget.c getent.c misc.c
+CFLAGS+= -I${TELNETDIR}
+
+WARNS?= 0
+
+.if !defined(RELEASE_CRUNCH)
+.if ${MK_OPENSSL} != "no"
+SRCS+= encrypt.c auth.c enc_des.c sra.c pk.c
+CFLAGS+= -DENCRYPTION -DAUTHENTICATION -DSRA
+.if ${MK_KERBEROS_SUPPORT} != "no"
+SRCS+= kerberos5.c
+CFLAGS+= -DKRB5 -I${KRB5DIR}/lib/krb5 -I${KRB5OBJDIR} -I${ASN1OBJDIR}
+CFLAGS+= -DFORWARD -Dnet_write=telnet_net_write
+.endif
+.endif
+.endif
+
+INCS= ${TELNETDIR}/arpa/telnet.h
+INCSDIR= ${INCLUDEDIR}/arpa
+
+.include <bsd.lib.mk>
diff --git a/lib/libthr/Makefile b/lib/libthr/Makefile
new file mode 100644
index 0000000..37073ea
--- /dev/null
+++ b/lib/libthr/Makefile
@@ -0,0 +1,55 @@
+# $FreeBSD$
+#
+# 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 included legacy CSRG sccsid strings, add -DLIBC_SCCS and -DSYSLIBC_SCCS
+# (for system call stubs) to CFLAGS below. -DSYSLIBC_SCCS affects just the
+# system call stubs.
+
+.if ${MACHINE_ARCH} == "alpha" || ${MACHINE_ARCH} == "sparc64"
+SHLIBDIR?= /lib
+.endif
+
+.include <bsd.own.mk>
+
+LIB=thr
+SHLIB_MAJOR= 2
+CFLAGS+=-DPTHREAD_KERNEL
+CFLAGS+=-I${.CURDIR}/../libc/include -I${.CURDIR}/thread \
+ -I${.CURDIR}/../../include
+CFLAGS+=-I${.CURDIR}/arch/${MACHINE_ARCH}/include
+CFLAGS+=-I${.CURDIR}/sys
+CFLAGS+=-I${.CURDIR}/../../libexec/rtld-elf
+CFLAGS+=-I${.CURDIR}/../../libexec/rtld-elf/${MACHINE_ARCH}
+CFLAGS+=-I${.CURDIR}/../libthread_db
+CFLAGS+=-Winline
+
+# CFLAGS+=-DSYSTEM_SCOPE_ONLY
+
+LDFLAGS= -Wl,--version-script=${.CURDIR}/pthread.map
+
+MAN= libthr.3
+
+# enable extra internal consistancy checks
+CFLAGS+=-D_PTHREADS_INVARIANTS -Wall
+#CFLAGS+=-g
+
+PRECIOUSLIB=
+
+.include "${.CURDIR}/arch/${MACHINE_ARCH}/Makefile.inc"
+.include "${.CURDIR}/sys/Makefile.inc"
+.include "${.CURDIR}/thread/Makefile.inc"
+
+.if ${MACHINE_ARCH} == "alpha" || ${MACHINE_ARCH} == "sparc64"
+SYMLINKS+=lib${LIB}.a ${LIBDIR}/libpthread.a
+.if !defined(NO_PIC)
+SYMLINKS+=lib${LIB}.so ${LIBDIR}/libpthread.so
+.endif
+.if ${MK_PROFILE} != "no"
+SYMLINKS+=lib${LIB}_p.a ${LIBDIR}/libpthread_p.a
+.endif
+.endif
+
+.include <bsd.lib.mk>
diff --git a/lib/libthr/arch/alpha/Makefile.inc b/lib/libthr/arch/alpha/Makefile.inc
new file mode 100644
index 0000000..508d2b4
--- /dev/null
+++ b/lib/libthr/arch/alpha/Makefile.inc
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}/${MACHINE_ARCH}
+
+SRCS+= pthread_md.c
diff --git a/lib/libthr/arch/alpha/alpha/pthread_md.c b/lib/libthr/arch/alpha/alpha/pthread_md.c
new file mode 100644
index 0000000..1a82341
--- /dev/null
+++ b/lib/libthr/arch/alpha/alpha/pthread_md.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2003 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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, 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$
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "pthread_md.h"
+
+/*
+ * The constructors.
+ */
+struct tcb *
+_tcb_ctor(struct pthread *thread, int initial)
+{
+ struct tcb *tcb;
+
+ if ((tcb = malloc(sizeof(struct tcb))) != NULL) {
+ memset(tcb, 0, sizeof(struct tcb));
+ tcb->tcb_thread = thread;
+ }
+ return (tcb);
+}
+
+void
+_tcb_dtor(struct tcb *tcb)
+{
+ free(tcb);
+}
diff --git a/lib/libthr/arch/alpha/include/pthread_md.h b/lib/libthr/arch/alpha/include/pthread_md.h
new file mode 100644
index 0000000..003cba0
--- /dev/null
+++ b/lib/libthr/arch/alpha/include/pthread_md.h
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _PTHREAD_MD_H_
+#define _PTHREAD_MD_H_
+
+#include <stddef.h>
+#include <sys/types.h>
+
+#define DTV_OFFSET offsetof(struct tcb, tcb_dtv)
+
+/*
+ * Variant I tcb. The structure layout is fixed, don't blindly
+ * change it!
+ */
+struct tcb {
+ void *tcb_dtv;
+ struct pthread *tcb_thread;
+};
+
+#define _tp __builtin_thread_pointer()
+#define _tcb ((struct tcb *)_tp)
+
+struct tcb *_tcb_ctor(struct pthread *, int);
+void _tcb_dtor(struct tcb *);
+
+/* Called from the thread to set its private data. */
+static __inline void
+_tcb_set(struct tcb *tcb)
+{
+ __builtin_set_thread_pointer(tcb);
+}
+
+static __inline struct tcb *
+_tcb_get(void)
+{
+ return (_tcb);
+}
+
+extern struct pthread *_thr_initial;
+
+static __inline struct pthread *
+_get_curthread(void)
+{
+ if (_thr_initial)
+ return (_tcb->tcb_thread);
+ return (NULL);
+}
+
+#endif /* _PTHREAD_MD_H_ */
diff --git a/lib/libthr/arch/amd64/Makefile.inc b/lib/libthr/arch/amd64/Makefile.inc
new file mode 100644
index 0000000..6e6d577
--- /dev/null
+++ b/lib/libthr/arch/amd64/Makefile.inc
@@ -0,0 +1,5 @@
+#$FreeBSD$
+
+.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}/${MACHINE_ARCH}
+
+SRCS+= pthread_md.c
diff --git a/lib/libthr/arch/amd64/amd64/pthread_md.c b/lib/libthr/arch/amd64/amd64/pthread_md.c
new file mode 100644
index 0000000..b661657
--- /dev/null
+++ b/lib/libthr/arch/amd64/amd64/pthread_md.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2003 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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, 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$
+ */
+
+#include <sys/types.h>
+#include <rtld_tls.h>
+
+#include "pthread_md.h"
+
+/*
+ * The constructors.
+ */
+struct tcb *
+_tcb_ctor(struct pthread *thread, int initial)
+{
+ struct tcb *tcb;
+
+ if (initial)
+ __asm __volatile("movq %%fs:0, %0" : "=r" (tcb));
+ else
+ tcb = _rtld_allocate_tls(NULL, sizeof(struct tcb), 16);
+ if (tcb)
+ tcb->tcb_thread = thread;
+ return (tcb);
+}
+
+void
+_tcb_dtor(struct tcb *tcb)
+{
+ _rtld_free_tls(tcb, sizeof(struct tcb), 16);
+}
diff --git a/lib/libthr/arch/amd64/include/pthread_md.h b/lib/libthr/arch/amd64/include/pthread_md.h
new file mode 100644
index 0000000..30f63ca
--- /dev/null
+++ b/lib/libthr/arch/amd64/include/pthread_md.h
@@ -0,0 +1,99 @@
+/*-
+ * Copyright (C) 2003 David Xu <davidxu@freebsd.org>
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Machine-dependent thread prototypes/definitions.
+ */
+#ifndef _PTHREAD_MD_H_
+#define _PTHREAD_MD_H_
+
+#include <stddef.h>
+#include <sys/types.h>
+#include <machine/sysarch.h>
+#include <ucontext.h>
+
+#define DTV_OFFSET offsetof(struct tcb, tcb_dtv)
+
+/*
+ * Variant II tcb, first two members are required by rtld,
+ * %fs points to the structure.
+ */
+struct tcb {
+ struct tcb *tcb_self; /* required by rtld */
+ void *tcb_dtv; /* required by rtld */
+ struct pthread *tcb_thread;
+ void *tcb_spare[1];
+};
+
+/*
+ * Evaluates to the byte offset of the per-tcb variable name.
+ */
+#define __tcb_offset(name) __offsetof(struct tcb, name)
+
+/*
+ * Evaluates to the type of the per-tcb variable name.
+ */
+#define __tcb_type(name) __typeof(((struct tcb *)0)->name)
+
+/*
+ * Evaluates to the value of the per-tcb variable name.
+ */
+#define TCB_GET64(name) ({ \
+ __tcb_type(name) __result; \
+ \
+ u_long __i; \
+ __asm __volatile("movq %%fs:%1, %0" \
+ : "=r" (__i) \
+ : "m" (*(u_long *)(__tcb_offset(name)))); \
+ __result = (__tcb_type(name))__i; \
+ \
+ __result; \
+})
+
+struct tcb *_tcb_ctor(struct pthread *, int);
+void _tcb_dtor(struct tcb *tcb);
+
+static __inline void
+_tcb_set(struct tcb *tcb)
+{
+ amd64_set_fsbase(tcb);
+}
+
+static __inline struct tcb *
+_tcb_get(void)
+{
+ return (TCB_GET64(tcb_self));
+}
+
+static __inline struct pthread *
+_get_curthread(void)
+{
+ return (TCB_GET64(tcb_thread));
+}
+#endif
diff --git a/lib/libthr/arch/arm/Makefile.inc b/lib/libthr/arch/arm/Makefile.inc
new file mode 100644
index 0000000..508d2b4
--- /dev/null
+++ b/lib/libthr/arch/arm/Makefile.inc
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}/${MACHINE_ARCH}
+
+SRCS+= pthread_md.c
diff --git a/lib/libthr/arch/arm/arm/pthread_md.c b/lib/libthr/arch/arm/arm/pthread_md.c
new file mode 100644
index 0000000..7ca2b25
--- /dev/null
+++ b/lib/libthr/arch/arm/arm/pthread_md.c
@@ -0,0 +1,50 @@
+/*-
+ * 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, 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <rtld_tls.h>
+
+#include "pthread_md.h"
+
+struct tcb *
+_tcb_ctor(struct pthread *thread, int initial)
+{
+ struct tcb *tcb;
+
+ tcb = malloc(sizeof(struct tcb));
+ if (tcb)
+ tcb->tcb_thread = thread;
+ return (tcb);
+}
+
+void
+_tcb_dtor(struct tcb *tcb)
+{
+ free(tcb);
+}
diff --git a/lib/libthr/arch/arm/include/pthread_md.h b/lib/libthr/arch/arm/include/pthread_md.h
new file mode 100644
index 0000000..30f9f86
--- /dev/null
+++ b/lib/libthr/arch/arm/include/pthread_md.h
@@ -0,0 +1,83 @@
+/*-
+ * 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, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list 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$
+ */
+
+/*
+ * Machine-dependent thread prototypes/definitions.
+ */
+#ifndef _PTHREAD_MD_H_
+#define _PTHREAD_MD_H_
+
+#include <sys/types.h>
+#include <machine/sysarch.h>
+#include <stddef.h>
+
+#define DTV_OFFSET offsetof(struct tcb, tcb_dtv)
+
+/*
+ * Variant II tcb, first two members are required by rtld.
+ */
+struct tcb {
+ struct tcb *tcb_self; /* required by rtld */
+ void *tcb_dtv; /* required by rtld */
+ struct pthread *tcb_thread; /* our hook */
+ void *tcb_spare[1];
+};
+
+/*
+ * The tcb constructors.
+ */
+struct tcb *_tcb_ctor(struct pthread *, int);
+void _tcb_dtor(struct tcb *);
+
+/* Called from the thread to set its private data. */
+static __inline void
+_tcb_set(struct tcb *tcb)
+{
+ *((struct tcb **)ARM_TP_ADDRESS) = tcb;
+}
+
+/*
+ * Get the current tcb.
+ */
+static __inline struct tcb *
+_tcb_get(void)
+{
+ return (*((struct tcb **)ARM_TP_ADDRESS));
+}
+
+extern struct pthread *_thr_initial;
+
+static __inline struct pthread *
+_get_curthread(void)
+{
+ if (_thr_initial)
+ return (_tcb_get()->tcb_thread);
+ return (NULL);
+}
+
+#endif /* _PTHREAD_MD_H_ */
diff --git a/lib/libthr/arch/i386/Makefile.inc b/lib/libthr/arch/i386/Makefile.inc
new file mode 100644
index 0000000..508d2b4
--- /dev/null
+++ b/lib/libthr/arch/i386/Makefile.inc
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}/${MACHINE_ARCH}
+
+SRCS+= pthread_md.c
diff --git a/lib/libthr/arch/i386/i386/pthread_md.c b/lib/libthr/arch/i386/i386/pthread_md.c
new file mode 100644
index 0000000..a8b31d5
--- /dev/null
+++ b/lib/libthr/arch/i386/i386/pthread_md.c
@@ -0,0 +1,57 @@
+/*-
+ * Copyright (C) 2003 David Xu <davidxu@freebsd.org>
+ * Copyright (c) 2001,2003 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <machine/segments.h>
+#include <machine/sysarch.h>
+#include <string.h>
+#include <rtld_tls.h>
+
+#include "pthread_md.h"
+
+struct tcb *
+_tcb_ctor(struct pthread *thread, int initial)
+{
+ struct tcb *tcb;
+
+ if (initial)
+ __asm __volatile("movl %%gs:0, %0" : "=r" (tcb));
+ else
+ tcb = _rtld_allocate_tls(NULL, sizeof(struct tcb), 16);
+ if (tcb)
+ tcb->tcb_thread = thread;
+ return (tcb);
+}
+
+void
+_tcb_dtor(struct tcb *tcb)
+{
+
+ _rtld_free_tls(tcb, sizeof(struct tcb), 16);
+}
diff --git a/lib/libthr/arch/i386/include/pthread_md.h b/lib/libthr/arch/i386/include/pthread_md.h
new file mode 100644
index 0000000..4140b9c
--- /dev/null
+++ b/lib/libthr/arch/i386/include/pthread_md.h
@@ -0,0 +1,103 @@
+/*-
+ * Copyright (c) 2002 Daniel Eischen <deischen@freebsd.org>.
+ * 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, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Machine-dependent thread prototypes/definitions.
+ */
+#ifndef _PTHREAD_MD_H_
+#define _PTHREAD_MD_H_
+
+#include <stddef.h>
+#include <sys/types.h>
+#include <machine/sysarch.h>
+
+#define DTV_OFFSET offsetof(struct tcb, tcb_dtv)
+
+/*
+ * Variant II tcb, first two members are required by rtld,
+ * %gs points to the structure.
+ */
+struct tcb {
+ struct tcb *tcb_self; /* required by rtld */
+ void *tcb_dtv; /* required by rtld */
+ struct pthread *tcb_thread;
+};
+
+/*
+ * Evaluates to the byte offset of the per-tcb variable name.
+ */
+#define __tcb_offset(name) __offsetof(struct tcb, name)
+
+/*
+ * Evaluates to the type of the per-tcb variable name.
+ */
+#define __tcb_type(name) __typeof(((struct tcb *)0)->name)
+
+/*
+ * Evaluates to the value of the per-tcb variable name.
+ */
+#define TCB_GET32(name) ({ \
+ __tcb_type(name) __result; \
+ \
+ u_int __i; \
+ __asm __volatile("movl %%gs:%1, %0" \
+ : "=r" (__i) \
+ : "m" (*(u_int *)(__tcb_offset(name)))); \
+ __result = (__tcb_type(name))__i; \
+ \
+ __result; \
+})
+
+/*
+ * The constructors.
+ */
+struct tcb *_tcb_ctor(struct pthread *, int);
+void _tcb_dtor(struct tcb *tcb);
+
+/* Called from the thread to set its private data. */
+static __inline void
+_tcb_set(struct tcb *tcb)
+{
+ i386_set_gsbase(tcb);
+}
+
+/* Get the current kcb. */
+static __inline struct tcb *
+_tcb_get(void)
+{
+ return (TCB_GET32(tcb_self));
+}
+
+/* Get the current thread. */
+static __inline struct pthread *
+_get_curthread(void)
+{
+ return (TCB_GET32(tcb_thread));
+}
+#endif
diff --git a/lib/libthr/arch/ia64/Makefile.inc b/lib/libthr/arch/ia64/Makefile.inc
new file mode 100644
index 0000000..c07c097
--- /dev/null
+++ b/lib/libthr/arch/ia64/Makefile.inc
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}/${MACHINE_ARCH}
+
+SRCS+= pthread_md.c
diff --git a/lib/libthr/arch/ia64/ia64/pthread_md.c b/lib/libthr/arch/ia64/ia64/pthread_md.c
new file mode 100644
index 0000000..a6f7def
--- /dev/null
+++ b/lib/libthr/arch/ia64/ia64/pthread_md.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2003 Daniel Eischen <deischen@freebsd.org>
+ * 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, 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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, 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$
+ */
+
+#include <sys/types.h>
+#include <rtld_tls.h>
+
+#include "pthread_md.h"
+
+/*
+ * The constructors.
+ */
+struct tcb *
+_tcb_ctor(struct pthread *thread, int initial)
+{
+ struct tcb *tcb;
+ void *oldtls;
+
+ if (initial)
+ oldtls = _tp;
+ else
+ oldtls = NULL;
+ tcb = _rtld_allocate_tls(oldtls, sizeof(struct tcb), 16);
+ if (tcb)
+ tcb->tcb_thread = thread;
+ return (tcb);
+}
+
+void
+_tcb_dtor(struct tcb *tcb)
+{
+ _rtld_free_tls(tcb, sizeof(tcb), 16);
+}
diff --git a/lib/libthr/arch/ia64/include/pthread_md.h b/lib/libthr/arch/ia64/include/pthread_md.h
new file mode 100644
index 0000000..aee5dd2
--- /dev/null
+++ b/lib/libthr/arch/ia64/include/pthread_md.h
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _PTHREAD_MD_H_
+#define _PTHREAD_MD_H_
+
+#include <stddef.h>
+
+#define DTV_OFFSET offsetof(struct tcb, tcb_dtv)
+
+/*
+ * Variant I tcb. The structure layout is fixed, don't blindly
+ * change it!
+ */
+struct tcb {
+ void *tcb_dtv;
+ struct pthread *tcb_thread;
+};
+
+register struct tcb *_tp __asm("%r13");
+
+#define _tcb _tp
+
+/*
+ * The tcb constructors.
+ */
+struct tcb *_tcb_ctor(struct pthread *, int);
+void _tcb_dtor(struct tcb *);
+
+/* Called from the thread to set its private data. */
+static __inline void
+_tcb_set(struct tcb *tcb)
+{
+ _tp = tcb;
+}
+
+static __inline struct tcb *
+_tcb_get(void)
+{
+ return (_tcb);
+}
+
+extern struct pthread *_thr_initial;
+
+static __inline struct pthread *
+_get_curthread(void)
+{
+ if (_thr_initial)
+ return (_tcb->tcb_thread);
+ return (NULL);
+}
+
+#endif /* _PTHREAD_MD_H_ */
diff --git a/lib/libthr/arch/powerpc/Makefile.inc b/lib/libthr/arch/powerpc/Makefile.inc
new file mode 100644
index 0000000..508d2b4
--- /dev/null
+++ b/lib/libthr/arch/powerpc/Makefile.inc
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}/${MACHINE_ARCH}
+
+SRCS+= pthread_md.c
diff --git a/lib/libthr/arch/powerpc/include/pthread_md.h b/lib/libthr/arch/powerpc/include/pthread_md.h
new file mode 100644
index 0000000..008c4cd
--- /dev/null
+++ b/lib/libthr/arch/powerpc/include/pthread_md.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2004 by 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.
+ * 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$
+ */
+
+/*
+ * Machine-dependent thread prototypes/definitions.
+ */
+#ifndef _PTHREAD_MD_H_
+#define _PTHREAD_MD_H_
+
+#include <stddef.h>
+#include <sys/types.h>
+
+#define DTV_OFFSET offsetof(struct tcb, tcb_dtv)
+
+/*
+ * Variant I tcb. The structure layout is fixed, don't blindly
+ * change it.
+ * %r2 points to end of the structure.
+ */
+struct tcb {
+ void *tcb_dtv;
+ struct pthread *tcb_thread;
+};
+
+register uint8_t *_tp __asm("%r2");
+
+#define _tcb ((struct tcb *)(_tp - sizeof(struct tcb)))
+
+struct tcb *_tcb_ctor(struct pthread *, int);
+void _tcb_dtor(struct tcb *);
+
+static __inline void
+_tcb_set(struct tcb *tcb)
+{
+ _tp = (uint8_t *)tcb + sizeof(struct tcb);
+}
+
+static __inline struct tcb *
+_tcb_get(void)
+{
+ return (_tcb);
+}
+
+extern struct pthread *_thr_initial;
+
+static __inline struct pthread *
+_get_curthread(void)
+{
+ if (_thr_initial)
+ return (_tcb->tcb_thread);
+ return (NULL);
+}
+
+#endif /* _PTHREAD_MD_H_ */
diff --git a/lib/libthr/arch/powerpc/powerpc/pthread_md.c b/lib/libthr/arch/powerpc/powerpc/pthread_md.c
new file mode 100644
index 0000000..aa02a8d
--- /dev/null
+++ b/lib/libthr/arch/powerpc/powerpc/pthread_md.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2003 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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, 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$
+ */
+
+#include <sys/types.h>
+#include <rtld_tls.h>
+
+#include "pthread_md.h"
+
+/*
+ * The constructors.
+ */
+struct tcb *
+_tcb_ctor(struct pthread *thread, int initial)
+{
+ struct tcb *tcb;
+ void *oldtls;
+
+ if (initial)
+ oldtls = _tp;
+ else
+ oldtls = NULL;
+ tcb = _rtld_allocate_tls(oldtls, sizeof(struct tcb), 16);
+ if (tcb)
+ tcb->tcb_thread = thread;
+ return (tcb);
+
+}
+
+void
+_tcb_dtor(struct tcb *tcb)
+{
+ _rtld_free_tls(tcb, sizeof(tcb), 16);
+}
diff --git a/lib/libthr/arch/sparc64/Makefile.inc b/lib/libthr/arch/sparc64/Makefile.inc
new file mode 100644
index 0000000..508d2b4
--- /dev/null
+++ b/lib/libthr/arch/sparc64/Makefile.inc
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}/${MACHINE_ARCH}
+
+SRCS+= pthread_md.c
diff --git a/lib/libthr/arch/sparc64/include/pthread_md.h b/lib/libthr/arch/sparc64/include/pthread_md.h
new file mode 100644
index 0000000..054c2be
--- /dev/null
+++ b/lib/libthr/arch/sparc64/include/pthread_md.h
@@ -0,0 +1,87 @@
+/*-
+ * Copyright (c) 2003 Jake Burkholder <jake@freebsd.org>.
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Machine-dependent thread prototypes/definitions.
+ */
+#ifndef _PTHREAD_MD_H_
+#define _PTHREAD_MD_H_
+
+#include <stddef.h>
+
+#define DTV_OFFSET offsetof(struct tcb, tcb_dtv)
+
+/*
+ * Variant II tcb, first two members are required by rtld.
+ * %g7 points to the structure.
+ */
+struct tcb {
+ struct tcb *tcb_self; /* required by rtld */
+ void *tcb_dtv; /* required by rtld */
+ struct pthread *tcb_thread; /* our hook */
+ void *tcb_spare[1];
+};
+
+register struct tcb *_tp __asm("%g7");
+
+#define _tcb (_tp)
+
+/*
+ * The tcb constructors.
+ */
+struct tcb *_tcb_ctor(struct pthread *, int);
+void _tcb_dtor(struct tcb *);
+
+/* Called from the thread to set its private data. */
+static __inline void
+_tcb_set(struct tcb *tcb)
+{
+ _tp = tcb;
+}
+
+/*
+ * Get the current tcb.
+ */
+static __inline struct tcb *
+_tcb_get(void)
+{
+ return (_tcb);
+}
+
+extern struct pthread *_thr_initial;
+
+static __inline struct pthread *
+_get_curthread(void)
+{
+ if (_thr_initial)
+ return (_tcb->tcb_thread);
+ return (NULL);
+}
+
+#endif /* _PTHREAD_MD_H_ */
diff --git a/lib/libthr/arch/sparc64/sparc64/pthread_md.c b/lib/libthr/arch/sparc64/sparc64/pthread_md.c
new file mode 100644
index 0000000..3f8e105
--- /dev/null
+++ b/lib/libthr/arch/sparc64/sparc64/pthread_md.c
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (C) 2003 Jake Burkholder <jake@freebsd.org>
+ * Copyright (C) 2003 David Xu <davidxu@freebsd.org>
+ * Copyright (c) 2001,2003 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <rtld_tls.h>
+
+#include "pthread_md.h"
+
+struct tcb *
+_tcb_ctor(struct pthread *thread, int initial)
+{
+ struct tcb *tcb;
+ void *oldtls;
+
+ if (initial)
+ oldtls = _tp;
+ else
+ oldtls = NULL;
+ tcb = _rtld_allocate_tls(oldtls, sizeof(struct tcb), 16);
+ if (tcb)
+ tcb->tcb_thread = thread;
+ return (tcb);
+}
+
+void
+_tcb_dtor(struct tcb *tcb)
+{
+ _rtld_free_tls(tcb, sizeof(struct tcb), 16);
+}
diff --git a/lib/libthr/libthr.3 b/lib/libthr/libthr.3
new file mode 100644
index 0000000..356edd9
--- /dev/null
+++ b/lib/libthr/libthr.3
@@ -0,0 +1,70 @@
+.\" Copyright (c) 2005 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 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 11, 2005
+.Os
+.Dt LIBTHR 3
+.Sh NAME
+.Nm libthr
+.Nd "alternative POSIX threads library"
+.Sh LIBRARY
+.Lb libthr
+.Sh SYNOPSIS
+.In pthread.h
+.Sh DESCRIPTION
+The
+.Nm
+library provides an alternative 1:1 implementation of the
+.Xr pthread 3
+library interfaces for application threading.
+While applications may be linked directly against
+.Nm ,
+system administrators are offered maximum flexibility by linking against
+.Xr pthread 3 ,
+as they can then use
+.Xr libmap.conf 5
+to select the threading implementation on a per-application basis.
+.Pp
+The
+.Nm
+library
+has been optimized for use by applications expecting system scope thread
+semantics, and can provide significant performance improvements.
+.Sh SEE ALSO
+.Xr pthread 3
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+library
+was originally created by
+.An "Jeff Roberson" Aq jeff@FreeBSD.org ,
+and enhanced by
+.An "Jonathan Mini" Aq mini@FreeBSD.org
+and
+.An "Mike Makonnen" Aq mtm@FreeBSD.org .
+It has been substantially rewritten and optimized by
+.An "David Xu" Aq davidxu@FreeBSD.org .
diff --git a/lib/libthr/pthread.map b/lib/libthr/pthread.map
new file mode 100644
index 0000000..66ebf44
--- /dev/null
+++ b/lib/libthr/pthread.map
@@ -0,0 +1,761 @@
+# $FreeBSD$
+LIBTHREAD_1_0 {
+global:
+ ___creat;
+ __accept;
+ __close;
+ __connect;
+ __error;
+ __fcntl;
+ __fsync;
+ __msync;
+ __nanosleep;
+ __open;
+ __poll;
+ __pthread_cond_timedwait;
+ __pthread_cond_wait;
+ __pthread_mutex_init;
+ __pthread_mutex_lock;
+ __pthread_mutex_timedlock;
+ __pthread_mutex_trylock;
+ __read;
+ __readv;
+ __recvfrom;
+ __recvmsg;
+ __select;
+ __sendmsg;
+ __sendto;
+ __sigsuspend;
+ __sigtimedwait;
+ __sigwait;
+ __sigwaitinfo;
+ __wait4;
+ __write;
+ __writev;
+ _aio_suspend;
+ _execve;
+ _fork;
+ _nanosleep;
+ _pause;
+ _pselect;
+ _pthread_atfork;
+ _pthread_barrier_destroy;
+ _pthread_barrier_init;
+ _pthread_barrier_wait;
+ _pthread_barrierattr_destroy;
+ _pthread_barrierattr_getpshared;
+ _pthread_barrierattr_init;
+ _pthread_barrierattr_setpshared;
+ _pthread_attr_destroy;
+ _pthread_attr_get_np;
+ _pthread_attr_getdetachstate;
+ _pthread_attr_getguardsize;
+ _pthread_attr_getinheritsched;
+ _pthread_attr_getschedparam;
+ _pthread_attr_getschedpolicy;
+ _pthread_attr_getscope;
+ _pthread_attr_getstack;
+ _pthread_attr_getstackaddr;
+ _pthread_attr_getstacksize;
+ _pthread_attr_init;
+ _pthread_attr_setcreatesuspend_np;
+ _pthread_attr_setdetachstate;
+ _pthread_attr_setguardsize;
+ _pthread_attr_setinheritsched;
+ _pthread_attr_setschedparam;
+ _pthread_attr_setschedpolicy;
+ _pthread_attr_setscope;
+ _pthread_attr_setstack;
+ _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_condattr_destroy;
+ _pthread_condattr_getclock;
+ _pthread_condattr_getpshared;
+ _pthread_condattr_init;
+ _pthread_condattr_setclock;
+ _pthread_condattr_setpshared;
+ _pthread_create;
+ _pthread_detach;
+ _pthread_equal;
+ _pthread_exit;
+ _pthread_getconcurrency;
+ _pthread_getprio;
+ _pthread_getschedparam;
+ _pthread_getspecific;
+ _pthread_join;
+ _pthread_key_create;
+ _pthread_key_delete;
+ _pthread_kill;
+ _pthread_main_np;
+ _pthread_multi_np;
+ _pthread_mutex_destroy;
+ _pthread_mutex_getprioceiling;
+ _pthread_mutex_init;
+ _pthread_mutex_lock;
+ _pthread_mutex_setprioceiling;
+ _pthread_mutex_timedlock;
+ _pthread_mutex_trylock;
+ _pthread_mutex_unlock;
+ _pthread_mutexattr_destroy;
+ _pthread_mutexattr_getkind_np;
+ _pthread_mutexattr_getprioceiling;
+ _pthread_mutexattr_getprotocol;
+ _pthread_mutexattr_getpshared;
+ _pthread_mutexattr_gettype;
+ _pthread_mutexattr_init;
+ _pthread_mutexattr_setkind_np;
+ _pthread_mutexattr_setprioceiling;
+ _pthread_mutexattr_setprotocol;
+ _pthread_mutexattr_setpshared;
+ _pthread_mutexattr_settype;
+ _pthread_once;
+ _pthread_resume_all_np;
+ _pthread_resume_np;
+ _pthread_rwlock_destroy;
+ _pthread_rwlock_init;
+ _pthread_rwlock_rdlock;
+ _pthread_rwlock_timedrdlock;
+ _pthread_rwlock_timedwrlock;
+ _pthread_rwlock_tryrdlock;
+ _pthread_rwlock_trywrlock;
+ _pthread_rwlock_unlock;
+ _pthread_rwlock_wrlock;
+ _pthread_rwlockattr_destroy;
+ _pthread_rwlockattr_getpshared;
+ _pthread_rwlockattr_init;
+ _pthread_rwlockattr_setpshared;
+ _pthread_self;
+ _pthread_set_name_np;
+ _pthread_setcancelstate;
+ _pthread_setcanceltype;
+ _pthread_setconcurrency;
+ _pthread_setprio;
+ _pthread_setschedparam;
+ _pthread_setspecific;
+ _pthread_sigmask;
+ _pthread_single_np;
+ _pthread_spin_destroy;
+ _pthread_spin_init;
+ _pthread_spin_lock;
+ _pthread_spin_trylock;
+ _pthread_spin_unlock;
+ _pthread_suspend_all_np;
+ _pthread_suspend_np;
+ _pthread_switch_add_np;
+ _pthread_switch_delete_np;
+ _pthread_testcancel;
+ _pthread_timedjoin_np;
+ _pthread_yield;
+ _raise;
+ _sem_destroy;
+ _sem_getvalue;
+ _sem_init;
+ _sem_post;
+ _sem_timedwait;
+ _sem_trywait;
+ _sem_wait;
+ _sigaction;
+ _sigprocmask;
+ _sigsuspend;
+ _sigtimedwait;
+ _sigwait;
+ _sigwaitinfo;
+ _sleep;
+ _spinlock;
+ _spinlock_debug;
+ _spinunlock;
+ _system;
+ _tcdrain;
+ _usleep;
+ _vfork;
+ _wait;
+ _waitpid;
+ accept;
+ aio_suspend;
+ close;
+ connect;
+ creat;
+ execve;
+ fcntl;
+ fork;
+ fsync;
+ msync;
+ nanosleep;
+ open;
+ pause;
+ poll;
+ pselect;
+ pthread_atfork;
+ pthread_barrier_destroy;
+ pthread_barrier_init;
+ pthread_barrier_wait;
+ pthread_barrierattr_destroy;
+ pthread_barrierattr_getpshared;
+ pthread_barrierattr_init;
+ pthread_barrierattr_setpshared;
+ pthread_attr_destroy;
+ pthread_attr_get_np;
+ pthread_attr_getdetachstate;
+ pthread_attr_getguardsize;
+ pthread_attr_getinheritsched;
+ pthread_attr_getschedparam;
+ pthread_attr_getschedpolicy;
+ pthread_attr_getscope;
+ pthread_attr_getstack;
+ pthread_attr_getstackaddr;
+ pthread_attr_getstacksize;
+ pthread_attr_init;
+ pthread_attr_setcreatesuspend_np;
+ pthread_attr_setdetachstate;
+ pthread_attr_setguardsize;
+ pthread_attr_setinheritsched;
+ pthread_attr_setschedparam;
+ pthread_attr_setschedpolicy;
+ pthread_attr_setscope;
+ pthread_attr_setstack;
+ 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_condattr_destroy;
+ pthread_condattr_getclock;
+ pthread_condattr_getpshared;
+ pthread_condattr_init;
+ pthread_condattr_setclock;
+ pthread_condattr_setpshared;
+ pthread_create;
+ pthread_detach;
+ pthread_equal;
+ pthread_exit;
+ pthread_getconcurrency;
+ pthread_getprio;
+ pthread_getschedparam;
+ pthread_getspecific;
+ pthread_join;
+ pthread_key_create;
+ pthread_key_delete;
+ pthread_kill;
+ pthread_main_np;
+ pthread_multi_np;
+ pthread_mutex_destroy;
+ pthread_mutex_getprioceiling;
+ pthread_mutex_init;
+ pthread_mutex_lock;
+ pthread_mutex_setprioceiling;
+ pthread_mutex_timedlock;
+ pthread_mutex_trylock;
+ pthread_mutex_unlock;
+ pthread_mutexattr_destroy;
+ pthread_mutexattr_getkind_np;
+ pthread_mutexattr_getprioceiling;
+ pthread_mutexattr_getpshared;
+ pthread_mutexattr_getprotocol;
+ pthread_mutexattr_gettype;
+ pthread_mutexattr_init;
+ pthread_mutexattr_setkind_np;
+ pthread_mutexattr_setprioceiling;
+ pthread_mutexattr_setprotocol;
+ pthread_mutexattr_setpshared;
+ pthread_mutexattr_settype;
+ pthread_once;
+ pthread_resume_all_np;
+ pthread_resume_np;
+ pthread_rwlock_destroy;
+ pthread_rwlock_init;
+ pthread_rwlock_rdlock;
+ pthread_rwlock_timedrdlock;
+ pthread_rwlock_timedwrlock;
+ pthread_rwlock_tryrdlock;
+ pthread_rwlock_trywrlock;
+ pthread_rwlock_unlock;
+ pthread_rwlock_wrlock;
+ pthread_rwlockattr_destroy;
+ pthread_rwlockattr_getpshared;
+ pthread_rwlockattr_init;
+ pthread_rwlockattr_setpshared;
+ pthread_self;
+ pthread_set_name_np;
+ pthread_setcancelstate;
+ pthread_setcanceltype;
+ pthread_setconcurrency;
+ pthread_setprio;
+ pthread_setschedparam;
+ pthread_setspecific;
+ pthread_sigmask;
+ pthread_single_np;
+ pthread_spin_destroy;
+ pthread_spin_init;
+ pthread_spin_lock;
+ pthread_spin_trylock;
+ pthread_spin_unlock;
+ pthread_suspend_all_np;
+ pthread_suspend_np;
+ pthread_switch_add_np;
+ pthread_switch_delete_np;
+ pthread_testcancel;
+ pthread_timedjoin_np;
+ pthread_yield;
+ raise;
+ read;
+ readv;
+ recvfrom;
+ recvmsg;
+ select;
+ sem_destroy;
+ sem_getvalue;
+ sem_init;
+ sem_post;
+ sem_timedwait;
+ sem_trywait;
+ sem_wait;
+ sendmsg;
+ sendto;
+ sigaction;
+ sigprocmask;
+ sigsuspend;
+ sigwait;
+ sigwaitinfo;
+ sigtimedwait;
+ sleep;
+ system;
+ tcdrain;
+ usleep;
+ vfork;
+ wait;
+ wait4;
+ waitpid;
+ write;
+ writev;
+
+ # Debugger needs these.
+ _libthr_debug;
+ _thread_active_threads;
+ _thread_bp_create;
+ _thread_bp_death;
+ _thread_event_mask;
+ _thread_keytable;
+ _thread_last_event;
+ _thread_list;
+ _thread_max_keys;
+ _thread_off_attr_flags;
+ _thread_off_dtv;
+ _thread_off_event_buf;
+ _thread_off_event_mask;
+ _thread_off_key_allocated;
+ _thread_off_key_destructor;
+ _thread_off_linkmap;
+ _thread_off_next;
+ _thread_off_report_events;
+ _thread_off_state;
+ _thread_off_tcb;
+ _thread_off_tid;
+ _thread_off_tlsindex;
+ _thread_size_key;
+ _thread_state_running;
+ _thread_state_zoombie;
+local:
+ *;
+};
+
+#
+# Use the same naming scheme as libc.
+#
+FBSD_1.0 {
+global:
+ __error;
+ accept;
+ aio_suspend;
+ close;
+ connect;
+ creat;
+ execve;
+ fcntl;
+ fork;
+ fsync;
+ msync;
+ nanosleep;
+ open;
+ pause;
+ poll;
+ pselect;
+ pthread_atfork;
+ pthread_barrier_destroy;
+ pthread_barrier_init;
+ pthread_barrier_wait;
+ pthread_barrierattr_destroy;
+ pthread_barrierattr_getpshared;
+ pthread_barrierattr_init;
+ pthread_barrierattr_setpshared;
+ pthread_attr_destroy;
+ pthread_attr_get_np;
+ pthread_attr_getdetachstate;
+ pthread_attr_getguardsize;
+ pthread_attr_getinheritsched;
+ pthread_attr_getschedparam;
+ pthread_attr_getschedpolicy;
+ pthread_attr_getscope;
+ pthread_attr_getstack;
+ pthread_attr_getstackaddr;
+ pthread_attr_getstacksize;
+ pthread_attr_init;
+ pthread_attr_setcreatesuspend_np;
+ pthread_attr_setdetachstate;
+ pthread_attr_setguardsize;
+ pthread_attr_setinheritsched;
+ pthread_attr_setschedparam;
+ pthread_attr_setschedpolicy;
+ pthread_attr_setscope;
+ pthread_attr_setstack;
+ 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_condattr_destroy;
+ pthread_condattr_getclock;
+ pthread_condattr_getpshared;
+ pthread_condattr_init;
+ pthread_condattr_setclock;
+ pthread_condattr_setpshared;
+ pthread_create;
+ pthread_detach;
+ pthread_equal;
+ pthread_exit;
+ pthread_getconcurrency;
+ pthread_getprio;
+ pthread_getschedparam;
+ pthread_getspecific;
+ pthread_join;
+ pthread_key_create;
+ pthread_key_delete;
+ pthread_kill;
+ pthread_main_np;
+ pthread_multi_np;
+ pthread_mutex_destroy;
+ pthread_mutex_getprioceiling;
+ pthread_mutex_init;
+ pthread_mutex_lock;
+ pthread_mutex_setprioceiling;
+ pthread_mutex_timedlock;
+ pthread_mutex_trylock;
+ pthread_mutex_unlock;
+ pthread_mutexattr_destroy;
+ pthread_mutexattr_getkind_np;
+ pthread_mutexattr_getprioceiling;
+ pthread_mutexattr_getpshared;
+ pthread_mutexattr_getprotocol;
+ pthread_mutexattr_gettype;
+ pthread_mutexattr_init;
+ pthread_mutexattr_setkind_np;
+ pthread_mutexattr_setprioceiling;
+ pthread_mutexattr_setprotocol;
+ pthread_mutexattr_setpshared;
+ pthread_mutexattr_settype;
+ pthread_once;
+ pthread_resume_all_np;
+ pthread_resume_np;
+ pthread_rwlock_destroy;
+ pthread_rwlock_init;
+ pthread_rwlock_rdlock;
+ pthread_rwlock_timedrdlock;
+ pthread_rwlock_timedwrlock;
+ pthread_rwlock_tryrdlock;
+ pthread_rwlock_trywrlock;
+ pthread_rwlock_unlock;
+ pthread_rwlock_wrlock;
+ pthread_rwlockattr_destroy;
+ pthread_rwlockattr_getpshared;
+ pthread_rwlockattr_init;
+ pthread_rwlockattr_setpshared;
+ pthread_self;
+ pthread_set_name_np;
+ pthread_setcancelstate;
+ pthread_setcanceltype;
+ pthread_setconcurrency;
+ pthread_setprio;
+ pthread_setschedparam;
+ pthread_setspecific;
+ pthread_sigmask;
+ pthread_single_np;
+ pthread_spin_destroy;
+ pthread_spin_init;
+ pthread_spin_lock;
+ pthread_spin_trylock;
+ pthread_spin_unlock;
+ pthread_suspend_all_np;
+ pthread_suspend_np;
+ pthread_switch_add_np;
+ pthread_switch_delete_np;
+ pthread_testcancel;
+ pthread_timedjoin_np;
+ pthread_yield;
+ raise;
+ read;
+ readv;
+ recvfrom;
+ recvmsg;
+ select;
+ sem_destroy;
+ sem_getvalue;
+ sem_init;
+ sem_post;
+ sem_timedwait;
+ sem_trywait;
+ sem_wait;
+ sendmsg;
+ sendto;
+ sigaction;
+ sigprocmask;
+ sigsuspend;
+ sigwait;
+ sigwaitinfo;
+ sigtimedwait;
+ sleep;
+ system;
+ tcdrain;
+ usleep;
+ vfork;
+ wait;
+ wait4;
+ waitpid;
+ write;
+ writev;
+local:
+ *;
+};
+
+#
+# List the private interfaces reserved for use in FreeBSD libraries.
+# These are not part of our application ABI.
+#
+FBSDprivate {
+global:
+ ___creat;
+ __accept;
+ __close;
+ __connect;
+ __fcntl;
+ __fsync;
+ __msync;
+ __nanosleep;
+ __open;
+ __poll;
+ __pthread_cond_timedwait;
+ __pthread_cond_wait;
+ __pthread_mutex_init;
+ __pthread_mutex_lock;
+ __pthread_mutex_timedlock;
+ __pthread_mutex_trylock;
+ __read;
+ __readv;
+ __recvfrom;
+ __recvmsg;
+ __select;
+ __sendmsg;
+ __sendto;
+ __sigsuspend;
+ __sigtimedwait;
+ __sigwait;
+ __sigwaitinfo;
+ __wait4;
+ __write;
+ __writev;
+ _aio_suspend;
+ _execve;
+ _fork;
+ _nanosleep;
+ _pause;
+ _pselect;
+ _pthread_atfork;
+ _pthread_barrier_destroy;
+ _pthread_barrier_init;
+ _pthread_barrier_wait;
+ _pthread_barrierattr_destroy;
+ _pthread_barrierattr_getpshared;
+ _pthread_barrierattr_init;
+ _pthread_barrierattr_setpshared;
+ _pthread_attr_destroy;
+ _pthread_attr_get_np;
+ _pthread_attr_getdetachstate;
+ _pthread_attr_getguardsize;
+ _pthread_attr_getinheritsched;
+ _pthread_attr_getschedparam;
+ _pthread_attr_getschedpolicy;
+ _pthread_attr_getscope;
+ _pthread_attr_getstack;
+ _pthread_attr_getstackaddr;
+ _pthread_attr_getstacksize;
+ _pthread_attr_init;
+ _pthread_attr_setcreatesuspend_np;
+ _pthread_attr_setdetachstate;
+ _pthread_attr_setguardsize;
+ _pthread_attr_setinheritsched;
+ _pthread_attr_setschedparam;
+ _pthread_attr_setschedpolicy;
+ _pthread_attr_setscope;
+ _pthread_attr_setstack;
+ _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_condattr_destroy;
+ _pthread_condattr_getclock;
+ _pthread_condattr_getpshared;
+ _pthread_condattr_init;
+ _pthread_condattr_setclock;
+ _pthread_condattr_setpshared;
+ _pthread_create;
+ _pthread_detach;
+ _pthread_equal;
+ _pthread_exit;
+ _pthread_getconcurrency;
+ _pthread_getprio;
+ _pthread_getschedparam;
+ _pthread_getspecific;
+ _pthread_join;
+ _pthread_key_create;
+ _pthread_key_delete;
+ _pthread_kill;
+ _pthread_main_np;
+ _pthread_multi_np;
+ _pthread_mutex_destroy;
+ _pthread_mutex_getprioceiling;
+ _pthread_mutex_init;
+ _pthread_mutex_lock;
+ _pthread_mutex_setprioceiling;
+ _pthread_mutex_timedlock;
+ _pthread_mutex_trylock;
+ _pthread_mutex_unlock;
+ _pthread_mutexattr_destroy;
+ _pthread_mutexattr_getkind_np;
+ _pthread_mutexattr_getprioceiling;
+ _pthread_mutexattr_getprotocol;
+ _pthread_mutexattr_getpshared;
+ _pthread_mutexattr_gettype;
+ _pthread_mutexattr_init;
+ _pthread_mutexattr_setkind_np;
+ _pthread_mutexattr_setprioceiling;
+ _pthread_mutexattr_setprotocol;
+ _pthread_mutexattr_setpshared;
+ _pthread_mutexattr_settype;
+ _pthread_once;
+ _pthread_resume_all_np;
+ _pthread_resume_np;
+ _pthread_rwlock_destroy;
+ _pthread_rwlock_init;
+ _pthread_rwlock_rdlock;
+ _pthread_rwlock_timedrdlock;
+ _pthread_rwlock_timedwrlock;
+ _pthread_rwlock_tryrdlock;
+ _pthread_rwlock_trywrlock;
+ _pthread_rwlock_unlock;
+ _pthread_rwlock_wrlock;
+ _pthread_rwlockattr_destroy;
+ _pthread_rwlockattr_getpshared;
+ _pthread_rwlockattr_init;
+ _pthread_rwlockattr_setpshared;
+ _pthread_self;
+ _pthread_set_name_np;
+ _pthread_setcancelstate;
+ _pthread_setcanceltype;
+ _pthread_setconcurrency;
+ _pthread_setprio;
+ _pthread_setschedparam;
+ _pthread_setspecific;
+ _pthread_sigmask;
+ _pthread_single_np;
+ _pthread_spin_destroy;
+ _pthread_spin_init;
+ _pthread_spin_lock;
+ _pthread_spin_trylock;
+ _pthread_spin_unlock;
+ _pthread_suspend_all_np;
+ _pthread_suspend_np;
+ _pthread_switch_add_np;
+ _pthread_switch_delete_np;
+ _pthread_testcancel;
+ _pthread_timedjoin_np;
+ _pthread_yield;
+ _raise;
+ _sem_destroy;
+ _sem_getvalue;
+ _sem_init;
+ _sem_post;
+ _sem_timedwait;
+ _sem_trywait;
+ _sem_wait;
+ _sigaction;
+ _sigprocmask;
+ _sigsuspend;
+ _sigtimedwait;
+ _sigwait;
+ _sigwaitinfo;
+ _sleep;
+ _spinlock;
+ _spinlock_debug;
+ _spinunlock;
+ _system;
+ _tcdrain;
+ _usleep;
+ _vfork;
+ _wait;
+ _waitpid;
+
+ # Debugger needs these.
+ _libthr_debug;
+ _thread_active_threads;
+ _thread_bp_create;
+ _thread_bp_death;
+ _thread_event_mask;
+ _thread_keytable;
+ _thread_last_event;
+ _thread_list;
+ _thread_max_keys;
+ _thread_off_attr_flags;
+ _thread_off_dtv;
+ _thread_off_event_buf;
+ _thread_off_event_mask;
+ _thread_off_key_allocated;
+ _thread_off_key_destructor;
+ _thread_off_linkmap;
+ _thread_off_next;
+ _thread_off_report_events;
+ _thread_off_state;
+ _thread_off_tcb;
+ _thread_off_tid;
+ _thread_off_tlsindex;
+ _thread_size_key;
+ _thread_state_running;
+ _thread_state_zoombie;
+local:
+ *;
+};
diff --git a/lib/libthr/support/Makefile.inc b/lib/libthr/support/Makefile.inc
new file mode 100644
index 0000000..bcf4393
--- /dev/null
+++ b/lib/libthr/support/Makefile.inc
@@ -0,0 +1,22 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/support ${.CURDIR}/../libc/gen ${.CURDIR}/../libc/string
+.PATH: ${.CURDIR}/../libc/${MACHINE_ARCH}/sys
+
+CFLAGS+= -I${.CURDIR}/../libc/${MACHINE_ARCH}
+
+SYSCALLS= thr_new
+
+SYSCALL_SRC= ${SYSCALLS:S/$/.S/}
+SYSCALL_OBJ= ${SYSCALLS:S/$/.So/}
+
+${SYSCALL_SRC}:
+ printf '#include "SYS.h"\nRSYSCALL(${.PREFIX})\n' > ${.TARGET}
+
+LIBC_OBJS=
+
+SOBJS+= thr_libc.So
+CLEANFILES+= ${SYSCALL_SRC} ${SYSCALL_OBJ} ${LIBC_OBJS}
+
+thr_libc.So: ${SYSCALL_OBJ} ${LIBC_OBJS}
+ ${CC} -fPIC -nostdlib -o ${.TARGET} -r ${.ALLSRC}
diff --git a/lib/libthr/sys/Makefile.inc b/lib/libthr/sys/Makefile.inc
new file mode 100644
index 0000000..70c6dda
--- /dev/null
+++ b/lib/libthr/sys/Makefile.inc
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/sys
+
+SRCS+= thr_error.c
diff --git a/lib/libthr/sys/thr_error.c b/lib/libthr/sys/thr_error.c
new file mode 100644
index 0000000..902c054
--- /dev/null
+++ b/lib/libthr/sys/thr_error.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.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 John Birrell
+ * and Chris Provenzano.
+ * 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 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$
+ */
+
+#include <pthread.h>
+
+#include "libc_private.h"
+#include "thr_private.h"
+
+#undef errno
+extern int errno;
+
+int *
+__error(void)
+{
+ struct pthread *curthread = _get_curthread();
+
+ if (curthread != NULL && curthread != _thr_initial)
+ return (&curthread->error);
+ else
+ return (&errno);
+}
diff --git a/lib/libthr/thread/Makefile.inc b/lib/libthr/thread/Makefile.inc
new file mode 100644
index 0000000..bdae92e
--- /dev/null
+++ b/lib/libthr/thread/Makefile.inc
@@ -0,0 +1,54 @@
+# $FreeBSD$
+
+# thr sources
+.PATH: ${.CURDIR}/thread
+
+SRCS+= \
+ thr_attr.c \
+ thr_barrier.c \
+ thr_barrierattr.c \
+ thr_cancel.c \
+ thr_clean.c \
+ thr_concurrency.c \
+ thr_cond.c \
+ thr_condattr.c \
+ thr_create.c \
+ thr_detach.c \
+ thr_equal.c \
+ thr_event.c \
+ thr_exit.c \
+ thr_fork.c \
+ thr_getprio.c \
+ thr_getschedparam.c \
+ thr_info.c \
+ thr_init.c \
+ thr_join.c \
+ thr_list.c \
+ thr_kern.c \
+ thr_kill.c \
+ thr_main_np.c \
+ thr_multi_np.c \
+ thr_mutex.c \
+ thr_mutexattr.c \
+ thr_once.c \
+ thr_printf.c \
+ thr_pspinlock.c \
+ thr_resume_np.c \
+ thr_rtld.c \
+ thr_rwlock.c \
+ thr_rwlockattr.c \
+ thr_self.c \
+ thr_sem.c \
+ thr_setprio.c \
+ thr_setschedparam.c \
+ thr_sig.c \
+ thr_single_np.c \
+ thr_spec.c \
+ thr_spinlock.c \
+ thr_stack.c \
+ thr_syscalls.c \
+ thr_suspend_np.c \
+ thr_switch_np.c \
+ thr_symbols.c \
+ thr_umtx.c \
+ thr_yield.c
diff --git a/lib/libthr/thread/thr_atfork.c b/lib/libthr/thread/thr_atfork.c
new file mode 100644
index 0000000..370623a
--- /dev/null
+++ b/lib/libthr/thread/thr_atfork.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2003 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 THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <sys/queue.h>
+#include "thr_private.h"
+
+__weak_reference(_pthread_atfork, pthread_atfork);
+
+int
+_pthread_atfork(void (*prepare)(void), void (*parent)(void),
+ void (*child)(void))
+{
+ struct pthread *curthread;
+ struct pthread_atfork *af;
+
+ _thr_check_init();
+
+ if ((af = malloc(sizeof(struct pthread_atfork))) == NULL)
+ return (ENOMEM);
+
+ curthread = _get_curthread();
+ af->prepare = prepare;
+ af->parent = parent;
+ af->child = child;
+ THR_UMTX_LOCK(curthread, &_thr_atfork_lock);
+ TAILQ_INSERT_TAIL(&_thr_atfork_list, af, qe);
+ THR_UMTX_UNLOCK(curthread, &_thr_atfork_lock);
+ return (0);
+}
diff --git a/lib/libthr/thread/thr_attr.c b/lib/libthr/thread/thr_attr.c
new file mode 100644
index 0000000..24dd064
--- /dev/null
+++ b/lib/libthr/thread/thr_attr.c
@@ -0,0 +1,540 @@
+/*
+ * Copyright (c) 2003 Craig Rodrigues <rodrigc@attbi.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Craig Rodrigues.
+ * 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 CRAIG RODRIGUES AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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 Daniel Eischen <eischen@vigrid.com>.
+ * Copyright (C) 2001 Jason Evans <jasone@freebsd.org>.
+ * Copyright (c) 2002,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(s), this list of conditions and the following disclaimer
+ * unmodified other than the allowable 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.
+ */
+
+/*
+ * Copyright (c) 1996 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <errno.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread_np.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+__weak_reference(_pthread_attr_destroy, pthread_attr_destroy);
+
+int
+_pthread_attr_destroy(pthread_attr_t *attr)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL)
+ /* Invalid argument: */
+ ret = EINVAL;
+ else {
+ /* Free the memory allocated to the attribute object: */
+ free(*attr);
+
+ /*
+ * Leave the attribute pointer NULL now that the memory
+ * has been freed:
+ */
+ *attr = NULL;
+ ret = 0;
+ }
+ return(ret);
+}
+
+__weak_reference(_pthread_attr_get_np, pthread_attr_get_np);
+
+int
+_pthread_attr_get_np(pthread_t pid, pthread_attr_t *dst)
+{
+ struct pthread *curthread;
+ struct pthread_attr attr;
+ int ret;
+
+ if (pid == NULL || dst == NULL || *dst == NULL)
+ return (EINVAL);
+
+ curthread = _get_curthread();
+ if ((ret = _thr_ref_add(curthread, pid, /*include dead*/0)) != 0)
+ return (ret);
+ attr = pid->attr;
+ if (pid->tlflags & TLFLAGS_DETACHED)
+ attr.flags |= PTHREAD_DETACHED;
+ _thr_ref_delete(curthread, pid);
+ memcpy(*dst, &attr, sizeof(struct pthread_attr));
+
+ return (0);
+}
+
+__weak_reference(_pthread_attr_getdetachstate, pthread_attr_getdetachstate);
+
+int
+_pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL || detachstate == NULL)
+ ret = EINVAL;
+ else {
+ /* Check if the detached flag is set: */
+ if ((*attr)->flags & PTHREAD_DETACHED)
+ /* Return detached: */
+ *detachstate = PTHREAD_CREATE_DETACHED;
+ else
+ /* Return joinable: */
+ *detachstate = PTHREAD_CREATE_JOINABLE;
+ ret = 0;
+ }
+ return(ret);
+}
+
+__weak_reference(_pthread_attr_getguardsize, pthread_attr_getguardsize);
+
+int
+_pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL || guardsize == NULL)
+ ret = EINVAL;
+ else {
+ /* Return the guard size: */
+ *guardsize = (*attr)->guardsize_attr;
+ ret = 0;
+ }
+ return(ret);
+}
+
+__weak_reference(_pthread_attr_getinheritsched, pthread_attr_getinheritsched);
+
+int
+_pthread_attr_getinheritsched(const pthread_attr_t *attr, int *sched_inherit)
+{
+ int ret = 0;
+
+ if ((attr == NULL) || (*attr == NULL))
+ ret = EINVAL;
+ else
+ *sched_inherit = (*attr)->sched_inherit;
+
+ return(ret);
+}
+
+__weak_reference(_pthread_attr_getschedparam, pthread_attr_getschedparam);
+
+int
+_pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param)
+{
+ int ret = 0;
+
+ if ((attr == NULL) || (*attr == NULL) || (param == NULL))
+ ret = EINVAL;
+ else
+ param->sched_priority = (*attr)->prio;
+
+ return(ret);
+}
+
+__weak_reference(_pthread_attr_getschedpolicy, pthread_attr_getschedpolicy);
+
+int
+_pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy)
+{
+ int ret = 0;
+
+ if ((attr == NULL) || (*attr == NULL) || (policy == NULL))
+ ret = EINVAL;
+ else
+ *policy = (*attr)->sched_policy;
+
+ return(ret);
+}
+
+__weak_reference(_pthread_attr_getscope, pthread_attr_getscope);
+
+int
+_pthread_attr_getscope(const pthread_attr_t *attr, int *contentionscope)
+{
+ int ret = 0;
+
+ if ((attr == NULL) || (*attr == NULL) || (contentionscope == NULL))
+ /* Return an invalid argument: */
+ ret = EINVAL;
+
+ else
+ *contentionscope = (*attr)->flags & PTHREAD_SCOPE_SYSTEM ?
+ PTHREAD_SCOPE_SYSTEM : PTHREAD_SCOPE_PROCESS;
+
+ return(ret);
+}
+
+__weak_reference(_pthread_attr_getstack, pthread_attr_getstack);
+
+int
+_pthread_attr_getstack(const pthread_attr_t * __restrict attr,
+ void ** __restrict stackaddr,
+ size_t * __restrict stacksize)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL || stackaddr == NULL
+ || stacksize == NULL )
+ ret = EINVAL;
+ else {
+ /* Return the stack address and size */
+ *stackaddr = (*attr)->stackaddr_attr;
+ *stacksize = (*attr)->stacksize_attr;
+ ret = 0;
+ }
+ return(ret);
+}
+
+__weak_reference(_pthread_attr_getstackaddr, pthread_attr_getstackaddr);
+
+int
+_pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL || stackaddr == NULL)
+ ret = EINVAL;
+ else {
+ /* Return the stack address: */
+ *stackaddr = (*attr)->stackaddr_attr;
+ ret = 0;
+ }
+ return(ret);
+}
+
+__weak_reference(_pthread_attr_getstacksize, pthread_attr_getstacksize);
+
+int
+_pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL || stacksize == NULL)
+ ret = EINVAL;
+ else {
+ /* Return the stack size: */
+ *stacksize = (*attr)->stacksize_attr;
+ ret = 0;
+ }
+ return(ret);
+}
+
+__weak_reference(_pthread_attr_init, pthread_attr_init);
+
+int
+_pthread_attr_init(pthread_attr_t *attr)
+{
+ int ret;
+ pthread_attr_t pattr;
+
+ _thr_check_init();
+
+ /* Allocate memory for the attribute object: */
+ if ((pattr = (pthread_attr_t) malloc(sizeof(struct pthread_attr))) == NULL)
+ /* Insufficient memory: */
+ ret = ENOMEM;
+ else {
+ /* Initialise the attribute object with the defaults: */
+ memcpy(pattr, &_pthread_attr_default, sizeof(struct pthread_attr));
+
+ /* Return a pointer to the attribute object: */
+ *attr = pattr;
+ ret = 0;
+ }
+ return(ret);
+}
+
+__weak_reference(_pthread_attr_setcreatesuspend_np, pthread_attr_setcreatesuspend_np);
+
+int
+_pthread_attr_setcreatesuspend_np(pthread_attr_t *attr)
+{
+ int ret;
+
+ if (attr == NULL || *attr == NULL) {
+ ret = EINVAL;
+ } else {
+ (*attr)->suspend = THR_CREATE_SUSPENDED;
+ ret = 0;
+ }
+ return(ret);
+}
+
+__weak_reference(_pthread_attr_setdetachstate, pthread_attr_setdetachstate);
+
+int
+_pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL ||
+ (detachstate != PTHREAD_CREATE_DETACHED &&
+ detachstate != PTHREAD_CREATE_JOINABLE))
+ ret = EINVAL;
+ else {
+ /* Check if detached state: */
+ if (detachstate == PTHREAD_CREATE_DETACHED)
+ /* Set the detached flag: */
+ (*attr)->flags |= PTHREAD_DETACHED;
+ else
+ /* Reset the detached flag: */
+ (*attr)->flags &= ~PTHREAD_DETACHED;
+ ret = 0;
+ }
+ return(ret);
+}
+
+__weak_reference(_pthread_attr_setguardsize, pthread_attr_setguardsize);
+
+int
+_pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize)
+{
+ int ret;
+
+ /* Check for invalid arguments. */
+ if (attr == NULL || *attr == NULL)
+ ret = EINVAL;
+ else {
+ /* Save the stack size. */
+ (*attr)->guardsize_attr = guardsize;
+ ret = 0;
+ }
+ return(ret);
+}
+
+__weak_reference(_pthread_attr_setinheritsched, pthread_attr_setinheritsched);
+
+int
+_pthread_attr_setinheritsched(pthread_attr_t *attr, int sched_inherit)
+{
+ int ret = 0;
+
+ if ((attr == NULL) || (*attr == NULL))
+ ret = EINVAL;
+ else if (sched_inherit != PTHREAD_INHERIT_SCHED &&
+ sched_inherit != PTHREAD_EXPLICIT_SCHED)
+ ret = ENOTSUP;
+ else
+ (*attr)->sched_inherit = sched_inherit;
+
+ return(ret);
+}
+
+__weak_reference(_pthread_attr_setschedparam, pthread_attr_setschedparam);
+
+int
+_pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param)
+{
+ int policy;
+
+ if ((attr == NULL) || (*attr == NULL))
+ return (EINVAL);
+
+ if (param == NULL)
+ return (ENOTSUP);
+
+ policy = (*attr)->sched_policy;
+
+ if (param->sched_priority < _thr_priorities[policy-1].pri_min ||
+ param->sched_priority > _thr_priorities[policy-1].pri_max)
+ return (ENOTSUP);
+
+ (*attr)->prio = param->sched_priority;
+
+ return (0);
+}
+
+__weak_reference(_pthread_attr_setschedpolicy, pthread_attr_setschedpolicy);
+
+int
+_pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
+{
+ int ret = 0;
+
+ if ((attr == NULL) || (*attr == NULL))
+ ret = EINVAL;
+ else if ((policy < SCHED_FIFO) || (policy > SCHED_RR)) {
+ ret = ENOTSUP;
+ } else {
+ (*attr)->sched_policy = policy;
+ (*attr)->prio = _thr_priorities[policy-1].pri_default;
+ }
+ return(ret);
+}
+
+__weak_reference(_pthread_attr_setscope, pthread_attr_setscope);
+
+int
+_pthread_attr_setscope(pthread_attr_t *attr, int contentionscope)
+{
+ int ret = 0;
+
+ if ((attr == NULL) || (*attr == NULL)) {
+ /* Return an invalid argument: */
+ ret = EINVAL;
+ } else if ((contentionscope != PTHREAD_SCOPE_PROCESS) &&
+ (contentionscope != PTHREAD_SCOPE_SYSTEM)) {
+ ret = EINVAL;
+ } else if (contentionscope == PTHREAD_SCOPE_SYSTEM) {
+ (*attr)->flags |= contentionscope;
+ } else {
+ (*attr)->flags &= ~PTHREAD_SCOPE_SYSTEM;
+ }
+ return (ret);
+}
+
+__weak_reference(_pthread_attr_setstack, pthread_attr_setstack);
+
+int
+_pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr,
+ size_t stacksize)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL || stackaddr == NULL
+ || stacksize < PTHREAD_STACK_MIN)
+ ret = EINVAL;
+ else {
+ /* Save the stack address and stack size */
+ (*attr)->stackaddr_attr = stackaddr;
+ (*attr)->stacksize_attr = stacksize;
+ ret = 0;
+ }
+ return(ret);
+}
+
+__weak_reference(_pthread_attr_setstackaddr, pthread_attr_setstackaddr);
+
+int
+_pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL || stackaddr == NULL)
+ ret = EINVAL;
+ else {
+ /* Save the stack address: */
+ (*attr)->stackaddr_attr = stackaddr;
+ ret = 0;
+ }
+ return(ret);
+}
+
+__weak_reference(_pthread_attr_setstacksize, pthread_attr_setstacksize);
+
+int
+_pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL || stacksize < PTHREAD_STACK_MIN)
+ ret = EINVAL;
+ else {
+ /* Save the stack size: */
+ (*attr)->stacksize_attr = stacksize;
+ ret = 0;
+ }
+ return(ret);
+}
diff --git a/lib/libthr/thread/thr_autoinit.c b/lib/libthr/thread/thr_autoinit.c
new file mode 100644
index 0000000..c425569
--- /dev/null
+++ b/lib/libthr/thread/thr_autoinit.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2002 Alfred Perlstein <alfred@freebsd.org>.
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 "thr_private.h"
+
+/*
+ * This module uses GCC extentions to initialize the
+ * threads package at program start-up time.
+ */
+
+void _thread_init_hack(void) __attribute__ ((constructor));
+
+void
+_thread_init_hack(void)
+{
+
+ _thread_init();
+}
+
+/*
+ * For the shared version of the threads library, the above is sufficient.
+ * But for the archive version of the library, we need a little bit more.
+ * Namely, we must arrange for this particular module to be pulled in from
+ * the archive library at link time. To accomplish that, we define and
+ * initialize a variable, "_thread_autoinit_dummy_decl". This variable is
+ * referenced (as an extern) from libc/stdlib/exit.c. This will always
+ * create a need for this module, ensuring that it is present in the
+ * executable.
+ */
+extern int _thread_autoinit_dummy_decl;
+int _thread_autoinit_dummy_decl = 0;
diff --git a/lib/libthr/thread/thr_barrier.c b/lib/libthr/thread/thr_barrier.c
new file mode 100644
index 0000000..8d65d9f
--- /dev/null
+++ b/lib/libthr/thread/thr_barrier.c
@@ -0,0 +1,111 @@
+/*-
+ * Copyright (c) 2003 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.
+ *
+ * $FreeBSD$
+ */
+
+#include "namespace.h"
+#include <errno.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+__weak_reference(_pthread_barrier_init, pthread_barrier_init);
+__weak_reference(_pthread_barrier_wait, pthread_barrier_wait);
+__weak_reference(_pthread_barrier_destroy, pthread_barrier_destroy);
+
+int
+_pthread_barrier_destroy(pthread_barrier_t *barrier)
+{
+ pthread_barrier_t bar;
+
+ if (barrier == NULL || *barrier == NULL)
+ return (EINVAL);
+
+ bar = *barrier;
+ if (bar->b_waiters > 0)
+ return (EBUSY);
+ *barrier = NULL;
+ free(bar);
+ return (0);
+}
+
+int
+_pthread_barrier_init(pthread_barrier_t *barrier,
+ const pthread_barrierattr_t *attr, unsigned count)
+{
+ pthread_barrier_t bar;
+
+ (void)attr;
+
+ if (barrier == NULL || count <= 0)
+ return (EINVAL);
+
+ bar = malloc(sizeof(struct pthread_barrier));
+ if (bar == NULL)
+ return (ENOMEM);
+
+ _thr_umtx_init(&bar->b_lock);
+ bar->b_cycle = 0;
+ bar->b_waiters = 0;
+ bar->b_count = count;
+ *barrier = bar;
+
+ return (0);
+}
+
+int
+_pthread_barrier_wait(pthread_barrier_t *barrier)
+{
+ struct pthread *curthread = _get_curthread();
+ pthread_barrier_t bar;
+ long cycle;
+ int ret;
+
+ if (barrier == NULL || *barrier == NULL)
+ return (EINVAL);
+
+ bar = *barrier;
+ THR_UMTX_LOCK(curthread, &bar->b_lock);
+ if (++bar->b_waiters == bar->b_count) {
+ /* Current thread is lastest thread */
+ bar->b_waiters = 0;
+ bar->b_cycle++;
+ _thr_umtx_wake(&bar->b_cycle, bar->b_count - 1);
+ THR_UMTX_UNLOCK(curthread, &bar->b_lock);
+ ret = PTHREAD_BARRIER_SERIAL_THREAD;
+ } else {
+ cycle = bar->b_cycle;
+ THR_UMTX_UNLOCK(curthread, &bar->b_lock);
+ do {
+ _thr_umtx_wait(&bar->b_cycle, cycle, NULL);
+ /* test cycle to avoid bogus wakeup */
+ } while (cycle == bar->b_cycle);
+ ret = 0;
+ }
+ return (ret);
+}
diff --git a/lib/libthr/thread/thr_barrierattr.c b/lib/libthr/thread/thr_barrierattr.c
new file mode 100644
index 0000000..32b9723
--- /dev/null
+++ b/lib/libthr/thread/thr_barrierattr.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2003 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 <errno.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+__weak_reference(_pthread_barrierattr_destroy, pthread_barrierattr_destroy);
+__weak_reference(_pthread_barrierattr_init, pthread_barrierattr_init);
+__weak_reference(_pthread_barrierattr_setpshared,
+ pthread_barrierattr_setpshared);
+__weak_reference(_pthread_barrierattr_getpshared,
+ pthread_barrierattr_getpshared);
+
+int
+_pthread_barrierattr_destroy(pthread_barrierattr_t *attr)
+{
+
+ if (attr == NULL || *attr == NULL)
+ return (EINVAL);
+
+ free(*attr);
+ return (0);
+}
+
+int
+_pthread_barrierattr_getpshared(const pthread_barrierattr_t *attr,
+ int *pshared)
+{
+
+ if (attr == NULL || *attr == NULL)
+ return (EINVAL);
+
+ *pshared = (*attr)->pshared;
+ return (0);
+}
+
+int
+_pthread_barrierattr_init(pthread_barrierattr_t *attr)
+{
+
+ if (attr == NULL)
+ return (EINVAL);
+
+ if ((*attr = malloc(sizeof(struct pthread_barrierattr))) == NULL)
+ return (ENOMEM);
+
+ (*attr)->pshared = PTHREAD_PROCESS_PRIVATE;
+ return (0);
+}
+
+int
+_pthread_barrierattr_setpshared(pthread_barrierattr_t *attr, int pshared)
+{
+
+ if (attr == NULL || *attr == NULL)
+ return (EINVAL);
+
+ /* Only PTHREAD_PROCESS_PRIVATE is supported. */
+ if (pshared != PTHREAD_PROCESS_PRIVATE)
+ return (EINVAL);
+
+ (*attr)->pshared = pshared;
+ return (0);
+}
diff --git a/lib/libthr/thread/thr_cancel.c b/lib/libthr/thread/thr_cancel.c
new file mode 100644
index 0000000..1047eb2
--- /dev/null
+++ b/lib/libthr/thread/thr_cancel.c
@@ -0,0 +1,163 @@
+/*
+ * 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 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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, 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$
+ *
+ */
+
+#include "namespace.h"
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+__weak_reference(_pthread_cancel, pthread_cancel);
+__weak_reference(_pthread_setcancelstate, pthread_setcancelstate);
+__weak_reference(_pthread_setcanceltype, pthread_setcanceltype);
+__weak_reference(_pthread_testcancel, pthread_testcancel);
+
+int
+_pthread_cancel(pthread_t pthread)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldval, newval = 0;
+ int oldtype;
+ int ret;
+
+ /*
+ * POSIX says _pthread_cancel should be async cancellation safe,
+ * so we temporarily disable async cancellation.
+ */
+ _pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype);
+ if ((ret = _thr_ref_add(curthread, pthread, 0)) != 0) {
+ _pthread_setcanceltype(oldtype, NULL);
+ return (ret);
+ }
+
+ do {
+ oldval = pthread->cancelflags;
+ if (oldval & THR_CANCEL_NEEDED)
+ break;
+ newval = oldval | THR_CANCEL_NEEDED;
+ } while (!atomic_cmpset_acq_int(&pthread->cancelflags, oldval, newval));
+
+ if (!(oldval & THR_CANCEL_NEEDED) && SHOULD_ASYNC_CANCEL(newval))
+ _thr_send_sig(pthread, SIGCANCEL);
+
+ _thr_ref_delete(curthread, pthread);
+ _pthread_setcanceltype(oldtype, NULL);
+ return (0);
+}
+
+static inline void
+testcancel(struct pthread *curthread)
+{
+ int newval;
+
+ newval = curthread->cancelflags;
+ if (SHOULD_CANCEL(newval) && !THR_IN_CRITICAL(curthread))
+ _pthread_exit(PTHREAD_CANCELED);
+}
+
+int
+_pthread_setcancelstate(int state, int *oldstate)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldval, ret;
+
+ oldval = curthread->cancelflags;
+ if (oldstate != NULL)
+ *oldstate = ((oldval & THR_CANCEL_DISABLE) ?
+ PTHREAD_CANCEL_DISABLE : PTHREAD_CANCEL_ENABLE);
+ switch (state) {
+ case PTHREAD_CANCEL_DISABLE:
+ atomic_set_int(&curthread->cancelflags, THR_CANCEL_DISABLE);
+ ret = 0;
+ break;
+ case PTHREAD_CANCEL_ENABLE:
+ atomic_clear_int(&curthread->cancelflags, THR_CANCEL_DISABLE);
+ testcancel(curthread);
+ ret = 0;
+ break;
+ default:
+ ret = EINVAL;
+ }
+
+ return (ret);
+}
+
+int
+_pthread_setcanceltype(int type, int *oldtype)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldval, ret;
+
+ oldval = curthread->cancelflags;
+ if (oldtype != NULL)
+ *oldtype = ((oldval & THR_CANCEL_AT_POINT) ?
+ PTHREAD_CANCEL_ASYNCHRONOUS :
+ PTHREAD_CANCEL_DEFERRED);
+ switch (type) {
+ case PTHREAD_CANCEL_ASYNCHRONOUS:
+ atomic_set_int(&curthread->cancelflags, THR_CANCEL_AT_POINT);
+ testcancel(curthread);
+ ret = 0;
+ break;
+ case PTHREAD_CANCEL_DEFERRED:
+ atomic_clear_int(&curthread->cancelflags, THR_CANCEL_AT_POINT);
+ ret = 0;
+ break;
+ default:
+ ret = EINVAL;
+ }
+
+ return (ret);
+}
+
+void
+_pthread_testcancel(void)
+{
+ testcancel(_get_curthread());
+}
+
+int
+_thr_cancel_enter(struct pthread *curthread)
+{
+ int oldval;
+
+ oldval = curthread->cancelflags;
+ if (!(oldval & THR_CANCEL_AT_POINT)) {
+ atomic_set_int(&curthread->cancelflags, THR_CANCEL_AT_POINT);
+ testcancel(curthread);
+ }
+ return (oldval);
+}
+
+void
+_thr_cancel_leave(struct pthread *curthread, int previous)
+{
+ if (!(previous & THR_CANCEL_AT_POINT))
+ atomic_clear_int(&curthread->cancelflags, THR_CANCEL_AT_POINT);
+}
diff --git a/lib/libthr/thread/thr_clean.c b/lib/libthr/thread/thr_clean.c
new file mode 100644
index 0000000..a5e9378
--- /dev/null
+++ b/lib/libthr/thread/thr_clean.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <signal.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+__weak_reference(_pthread_cleanup_push, pthread_cleanup_push);
+__weak_reference(_pthread_cleanup_pop, pthread_cleanup_pop);
+
+void
+_pthread_cleanup_push(void (*routine) (void *), void *routine_arg)
+{
+ struct pthread *curthread = _get_curthread();
+ struct pthread_cleanup *new;
+
+ if ((new = (struct pthread_cleanup *)
+ malloc(sizeof(struct pthread_cleanup))) != NULL) {
+ new->routine = routine;
+ new->routine_arg = routine_arg;
+ new->onstack = 0;
+ new->next = curthread->cleanup;
+
+ curthread->cleanup = new;
+ }
+}
+
+void
+_pthread_cleanup_pop(int execute)
+{
+ struct pthread *curthread = _get_curthread();
+ struct pthread_cleanup *old;
+
+ if ((old = curthread->cleanup) != NULL) {
+ curthread->cleanup = old->next;
+ if (execute) {
+ old->routine(old->routine_arg);
+ }
+ if (old->onstack == 0)
+ free(old);
+ }
+}
diff --git a/lib/libthr/thread/thr_concurrency.c b/lib/libthr/thread/thr_concurrency.c
new file mode 100644
index 0000000..61f0c4a
--- /dev/null
+++ b/lib/libthr/thread/thr_concurrency.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2003 Sergey Osokin <osa@FreeBSD.org.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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Sergey Osokin.
+ * 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 SERGEY OSOKIN AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <errno.h>
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+static int current_concurrency = 0;
+
+__weak_reference(_pthread_getconcurrency, pthread_getconcurrency);
+__weak_reference(_pthread_setconcurrency, pthread_setconcurrency);
+
+int
+_pthread_getconcurrency(void)
+{
+ return current_concurrency;
+}
+
+int
+_pthread_setconcurrency(int new_level)
+{
+ int ret;
+
+ if (new_level < 0) {
+ ret = EINVAL;
+ } else {
+ current_concurrency = new_level;
+ ret = 0;
+ }
+ return (ret);
+}
diff --git a/lib/libthr/thread/thr_cond.c b/lib/libthr/thread/thr_cond.c
new file mode 100644
index 0000000..f786062
--- /dev/null
+++ b/lib/libthr/thread/thr_cond.c
@@ -0,0 +1,350 @@
+/*
+ * 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 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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, 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$
+ */
+
+#include "namespace.h"
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <pthread.h>
+#include <limits.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+/*
+ * Prototypes
+ */
+int __pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
+int __pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
+ const struct timespec * abstime);
+static int cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);
+static int cond_wait_common(pthread_cond_t *cond, pthread_mutex_t *mutex,
+ const struct timespec *abstime, int cancel);
+static int cond_signal_common(pthread_cond_t *cond, int broadcast);
+
+/*
+ * Double underscore versions are cancellation points. Single underscore
+ * versions are not and are provided for libc internal usage (which
+ * shouldn't introduce cancellation points).
+ */
+__weak_reference(__pthread_cond_wait, pthread_cond_wait);
+__weak_reference(__pthread_cond_timedwait, pthread_cond_timedwait);
+
+__weak_reference(_pthread_cond_init, pthread_cond_init);
+__weak_reference(_pthread_cond_destroy, pthread_cond_destroy);
+__weak_reference(_pthread_cond_signal, pthread_cond_signal);
+__weak_reference(_pthread_cond_broadcast, pthread_cond_broadcast);
+
+static int
+cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr)
+{
+ pthread_cond_t pcond;
+ int rval = 0;
+
+ if ((pcond = (pthread_cond_t)
+ malloc(sizeof(struct pthread_cond))) == NULL) {
+ rval = ENOMEM;
+ } else {
+ /*
+ * Initialise the condition variable structure:
+ */
+ _thr_umtx_init(&pcond->c_lock);
+ pcond->c_seqno = 0;
+ pcond->c_waiters = 0;
+ pcond->c_wakeups = 0;
+ if (cond_attr == NULL || *cond_attr == NULL) {
+ pcond->c_pshared = 0;
+ pcond->c_clockid = CLOCK_REALTIME;
+ } else {
+ pcond->c_pshared = (*cond_attr)->c_pshared;
+ pcond->c_clockid = (*cond_attr)->c_clockid;
+ }
+ *cond = pcond;
+ }
+ /* Return the completion status: */
+ return (rval);
+}
+
+static int
+init_static(struct pthread *thread, pthread_cond_t *cond)
+{
+ int ret;
+
+ THR_LOCK_ACQUIRE(thread, &_cond_static_lock);
+
+ if (*cond == NULL)
+ ret = cond_init(cond, NULL);
+ else
+ ret = 0;
+
+ THR_LOCK_RELEASE(thread, &_cond_static_lock);
+
+ return (ret);
+}
+
+int
+_pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr)
+{
+
+ *cond = NULL;
+ return (cond_init(cond, cond_attr));
+}
+
+int
+_pthread_cond_destroy(pthread_cond_t *cond)
+{
+ struct pthread_cond *cv;
+ struct pthread *curthread = _get_curthread();
+ int rval = 0;
+
+ if (*cond == NULL)
+ rval = EINVAL;
+ else {
+ /* Lock the condition variable structure: */
+ THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
+ if ((*cond)->c_waiters + (*cond)->c_wakeups != 0) {
+ THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
+ return (EBUSY);
+ }
+
+ /*
+ * NULL the caller's pointer now that the condition
+ * variable has been destroyed:
+ */
+ cv = *cond;
+ *cond = NULL;
+
+ /* Unlock the condition variable structure: */
+ THR_LOCK_RELEASE(curthread, &cv->c_lock);
+
+ /* Free the cond lock structure: */
+
+ /*
+ * Free the memory allocated for the condition
+ * variable structure:
+ */
+ free(cv);
+
+ }
+ /* Return the completion status: */
+ return (rval);
+}
+
+struct cond_cancel_info
+{
+ pthread_mutex_t *mutex;
+ pthread_cond_t *cond;
+ long seqno;
+ int count;
+};
+
+static void
+cond_cancel_handler(void *arg)
+{
+ struct pthread *curthread = _get_curthread();
+ struct cond_cancel_info *info = (struct cond_cancel_info *)arg;
+ pthread_cond_t cv;
+
+ cv = *(info->cond);
+ THR_LOCK_ACQUIRE(curthread, &cv->c_lock);
+ if (cv->c_seqno != info->seqno && cv->c_wakeups != 0) {
+ if (cv->c_waiters > 0) {
+ cv->c_seqno++;
+ _thr_umtx_wake(&cv->c_seqno, 1);
+ } else
+ cv->c_wakeups--;
+ } else {
+ cv->c_waiters--;
+ }
+ THR_LOCK_RELEASE(curthread, &cv->c_lock);
+
+ _mutex_cv_lock(info->mutex, info->count);
+}
+
+static int
+cond_wait_common(pthread_cond_t *cond, pthread_mutex_t *mutex,
+ const struct timespec *abstime, int cancel)
+{
+ struct pthread *curthread = _get_curthread();
+ struct timespec ts, ts2, *tsp;
+ struct cond_cancel_info info;
+ pthread_cond_t cv;
+ long seq, oldseq;
+ int oldcancel;
+ int ret = 0;
+
+ /*
+ * If the condition variable is statically initialized,
+ * perform the dynamic initialization:
+ */
+ if (__predict_false(*cond == NULL &&
+ (ret = init_static(curthread, cond)) != 0))
+ return (ret);
+
+ cv = *cond;
+ THR_LOCK_ACQUIRE(curthread, &cv->c_lock);
+ ret = _mutex_cv_unlock(mutex, &info.count);
+ if (ret) {
+ THR_LOCK_RELEASE(curthread, &cv->c_lock);
+ return (ret);
+ }
+ oldseq = seq = cv->c_seqno;
+ info.mutex = mutex;
+ info.cond = cond;
+ info.seqno = oldseq;
+
+ cv->c_waiters++;
+ do {
+ THR_LOCK_RELEASE(curthread, &cv->c_lock);
+
+ if (abstime != NULL) {
+ clock_gettime(cv->c_clockid, &ts);
+ TIMESPEC_SUB(&ts2, abstime, &ts);
+ tsp = &ts2;
+ } else
+ tsp = NULL;
+
+ if (cancel) {
+ THR_CLEANUP_PUSH(curthread, cond_cancel_handler, &info);
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = _thr_umtx_wait(&cv->c_seqno, seq, tsp);
+ _thr_cancel_leave(curthread, oldcancel);
+ THR_CLEANUP_POP(curthread, 0);
+ } else {
+ ret = _thr_umtx_wait(&cv->c_seqno, seq, tsp);
+ }
+
+ THR_LOCK_ACQUIRE(curthread, &cv->c_lock);
+ seq = cv->c_seqno;
+ if (abstime != NULL && ret == ETIMEDOUT)
+ break;
+
+ /*
+ * loop if we have never been told to wake up
+ * or we lost a race.
+ */
+ } while (seq == oldseq || cv->c_wakeups == 0);
+
+ if (seq != oldseq && cv->c_wakeups != 0) {
+ cv->c_wakeups--;
+ ret = 0;
+ } else {
+ cv->c_waiters--;
+ }
+ THR_LOCK_RELEASE(curthread, &cv->c_lock);
+ _mutex_cv_lock(mutex, info.count);
+ return (ret);
+}
+
+int
+_pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
+{
+
+ return (cond_wait_common(cond, mutex, NULL, 0));
+}
+
+int
+__pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
+{
+
+ return (cond_wait_common(cond, mutex, NULL, 1));
+}
+
+int
+_pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
+ const struct timespec * abstime)
+{
+
+ if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 ||
+ abstime->tv_nsec >= 1000000000)
+ return (EINVAL);
+
+ return (cond_wait_common(cond, mutex, abstime, 0));
+}
+
+int
+__pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
+ const struct timespec *abstime)
+{
+
+ if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 ||
+ abstime->tv_nsec >= 1000000000)
+ return (EINVAL);
+
+ return (cond_wait_common(cond, mutex, abstime, 1));
+}
+
+static int
+cond_signal_common(pthread_cond_t *cond, int broadcast)
+{
+ struct pthread *curthread = _get_curthread();
+ pthread_cond_t cv;
+ int ret = 0, oldwaiters;
+
+ /*
+ * If the condition variable is statically initialized, perform dynamic
+ * initialization.
+ */
+ if (__predict_false(*cond == NULL &&
+ (ret = init_static(curthread, cond)) != 0))
+ return (ret);
+
+ cv = *cond;
+ /* Lock the condition variable structure. */
+ THR_LOCK_ACQUIRE(curthread, &cv->c_lock);
+ if (cv->c_waiters) {
+ if (!broadcast) {
+ cv->c_wakeups++;
+ cv->c_waiters--;
+ cv->c_seqno++;
+ _thr_umtx_wake(&cv->c_seqno, 1);
+ } else {
+ oldwaiters = cv->c_waiters;
+ cv->c_wakeups += cv->c_waiters;
+ cv->c_waiters = 0;
+ cv->c_seqno++;
+ _thr_umtx_wake(&cv->c_seqno, oldwaiters);
+ }
+ }
+ THR_LOCK_RELEASE(curthread, &cv->c_lock);
+ return (ret);
+}
+
+int
+_pthread_cond_signal(pthread_cond_t * cond)
+{
+
+ return (cond_signal_common(cond, 0));
+}
+
+int
+_pthread_cond_broadcast(pthread_cond_t * cond)
+{
+
+ return (cond_signal_common(cond, 1));
+}
diff --git a/lib/libthr/thread/thr_condattr.c b/lib/libthr/thread/thr_condattr.c
new file mode 100644
index 0000000..9e14dc2
--- /dev/null
+++ b/lib/libthr/thread/thr_condattr.c
@@ -0,0 +1,130 @@
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+__weak_reference(_pthread_condattr_init, pthread_condattr_init);
+__weak_reference(_pthread_condattr_destroy, pthread_condattr_destroy);
+__weak_reference(_pthread_condattr_getclock, pthread_condattr_getclock);
+__weak_reference(_pthread_condattr_setclock, pthread_condattr_setclock);
+__weak_reference(_pthread_condattr_getpshared, pthread_condattr_getpshared);
+__weak_reference(_pthread_condattr_setpshared, pthread_condattr_setpshared);
+
+int
+_pthread_condattr_init(pthread_condattr_t *attr)
+{
+ pthread_condattr_t pattr;
+ int ret;
+
+ if ((pattr = (pthread_condattr_t)
+ malloc(sizeof(struct pthread_cond_attr))) == NULL) {
+ ret = ENOMEM;
+ } else {
+ memcpy(pattr, &_pthread_condattr_default,
+ sizeof(struct pthread_cond_attr));
+ *attr = pattr;
+ ret = 0;
+ }
+ return (ret);
+}
+
+int
+_pthread_condattr_destroy(pthread_condattr_t *attr)
+{
+ int ret;
+
+ if (attr == NULL || *attr == NULL) {
+ ret = EINVAL;
+ } else {
+ free(*attr);
+ *attr = NULL;
+ ret = 0;
+ }
+ return(ret);
+}
+
+int
+_pthread_condattr_getclock(const pthread_condattr_t *attr,
+ clockid_t *clock_id)
+{
+ if (attr == NULL || *attr == NULL)
+ return (EINVAL);
+ *clock_id = (*attr)->c_clockid;
+ return (0);
+}
+
+int
+_pthread_condattr_setclock(pthread_condattr_t *attr,
+ clockid_t clock_id)
+{
+ if (attr == NULL || *attr == NULL)
+ return (EINVAL);
+ if (clock_id != CLOCK_REALTIME &&
+ clock_id != CLOCK_VIRTUAL &&
+ clock_id != CLOCK_PROF &&
+ clock_id != CLOCK_MONOTONIC) {
+ return (EINVAL);
+ }
+ (*attr)->c_clockid = clock_id;
+ return (0);
+}
+
+int
+_pthread_condattr_getpshared(const pthread_condattr_t *attr,
+ int *pshared)
+{
+ if (attr == NULL || *attr == NULL)
+ return (EINVAL);
+
+ pshared = PTHREAD_PROCESS_PRIVATE;
+ return (0);
+}
+
+int
+_pthread_condattr_setpshared(pthread_condattr_t *attr, int pshared)
+{
+ if (attr == NULL || *attr == NULL)
+ return (EINVAL);
+
+ if (pshared != PTHREAD_PROCESS_PRIVATE)
+ return (EINVAL);
+ return (0);
+}
diff --git a/lib/libthr/thread/thr_create.c b/lib/libthr/thread/thr_create.c
new file mode 100644
index 0000000..bb5724a
--- /dev/null
+++ b/lib/libthr/thread/thr_create.c
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2003 Daniel M. Eischen <deischen@gdeb.com>
+ * 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 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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, 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$
+ */
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/signalvar.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stddef.h>
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+static int create_stack(struct pthread_attr *pattr);
+static void thread_start(struct pthread *curthread);
+
+__weak_reference(_pthread_create, pthread_create);
+
+int
+_pthread_create(pthread_t * thread, const pthread_attr_t * attr,
+ void *(*start_routine) (void *), void *arg)
+{
+ struct pthread *curthread, *new_thread;
+ struct thr_param param;
+ int ret = 0, locked, create_suspended;
+ sigset_t set, oset;
+
+ _thr_check_init();
+
+ /*
+ * Tell libc and others now they need lock to protect their data.
+ */
+ if (_thr_isthreaded() == 0 && _thr_setthreaded(1))
+ return (EAGAIN);
+
+ curthread = _get_curthread();
+ if ((new_thread = _thr_alloc(curthread)) == NULL)
+ return (EAGAIN);
+
+ memset(&param, 0, sizeof(param));
+
+ if (attr == NULL || *attr == NULL)
+ /* Use the default thread attributes: */
+ new_thread->attr = _pthread_attr_default;
+ else
+ new_thread->attr = *(*attr);
+ if (new_thread->attr.sched_inherit == PTHREAD_INHERIT_SCHED) {
+ /* inherit scheduling contention scope */
+ if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
+ new_thread->attr.flags |= PTHREAD_SCOPE_SYSTEM;
+ else
+ new_thread->attr.flags &= ~PTHREAD_SCOPE_SYSTEM;
+ /*
+ * scheduling policy and scheduling parameters will be
+ * inherited in following code.
+ */
+ }
+
+ if (_thr_scope_system > 0)
+ new_thread->attr.flags |= PTHREAD_SCOPE_SYSTEM;
+ else if (_thr_scope_system < 0)
+ new_thread->attr.flags &= ~PTHREAD_SCOPE_SYSTEM;
+
+ new_thread->tid = TID_TERMINATED;
+
+ if (create_stack(&new_thread->attr) != 0) {
+ /* Insufficient memory to create a stack: */
+ _thr_free(curthread, new_thread);
+ return (EAGAIN);
+ }
+ /*
+ * Write a magic value to the thread structure
+ * to help identify valid ones:
+ */
+ new_thread->magic = THR_MAGIC;
+ new_thread->start_routine = start_routine;
+ new_thread->arg = arg;
+ new_thread->cancelflags = PTHREAD_CANCEL_ENABLE |
+ PTHREAD_CANCEL_DEFERRED;
+ /*
+ * Check if this thread is to inherit the scheduling
+ * attributes from its parent:
+ */
+ if (new_thread->attr.sched_inherit == PTHREAD_INHERIT_SCHED) {
+ /*
+ * Copy the scheduling attributes. Lock the scheduling
+ * lock to get consistent scheduling parameters.
+ */
+ THR_LOCK(curthread);
+ new_thread->base_priority = curthread->base_priority;
+ new_thread->attr.prio = curthread->base_priority;
+ new_thread->attr.sched_policy = curthread->attr.sched_policy;
+ THR_UNLOCK(curthread);
+ } else {
+ /*
+ * Use just the thread priority, leaving the
+ * other scheduling attributes as their
+ * default values:
+ */
+ new_thread->base_priority = new_thread->attr.prio;
+ }
+ new_thread->active_priority = new_thread->base_priority;
+
+ /* Initialize the mutex queue: */
+ TAILQ_INIT(&new_thread->mutexq);
+
+ /* Initialise hooks in the thread structure: */
+ if (new_thread->attr.suspend == THR_CREATE_SUSPENDED) {
+ new_thread->flags = THR_FLAGS_NEED_SUSPEND;
+ create_suspended = 1;
+ } else {
+ create_suspended = 0;
+ }
+
+ new_thread->state = PS_RUNNING;
+
+ if (new_thread->attr.flags & PTHREAD_CREATE_DETACHED)
+ new_thread->tlflags |= TLFLAGS_DETACHED;
+
+ /* Add the new thread. */
+ new_thread->refcount = 1;
+ _thr_link(curthread, new_thread);
+ /* Return thread pointer eariler so that new thread can use it. */
+ (*thread) = new_thread;
+ if (SHOULD_REPORT_EVENT(curthread, TD_CREATE)) {
+ THR_THREAD_LOCK(curthread, new_thread);
+ locked = 1;
+ } else
+ locked = 0;
+ param.start_func = (void (*)(void *)) thread_start;
+ param.arg = new_thread;
+ param.stack_base = new_thread->attr.stackaddr_attr;
+ param.stack_size = new_thread->attr.stacksize_attr;
+ param.tls_base = (char *)new_thread->tcb;
+ param.tls_size = sizeof(struct tcb);
+ param.child_tid = &new_thread->tid;
+ param.parent_tid = &new_thread->tid;
+ param.flags = 0;
+ if (new_thread->attr.flags & PTHREAD_SCOPE_SYSTEM)
+ param.flags |= THR_SYSTEM_SCOPE;
+
+ /* Schedule the new thread. */
+ if (create_suspended) {
+ SIGFILLSET(set);
+ SIGDELSET(set, SIGTRAP);
+ __sys_sigprocmask(SIG_SETMASK, &set, &oset);
+ new_thread->sigmask = oset;
+ }
+
+ ret = thr_new(&param, sizeof(param));
+
+ if (create_suspended)
+ __sys_sigprocmask(SIG_SETMASK, &oset, NULL);
+
+ if (ret != 0) {
+ if (!locked)
+ THR_THREAD_LOCK(curthread, new_thread);
+ new_thread->state = PS_DEAD;
+ new_thread->tid = TID_TERMINATED;
+ if (new_thread->flags & THR_FLAGS_NEED_SUSPEND) {
+ new_thread->cycle++;
+ _thr_umtx_wake(&new_thread->cycle, INT_MAX);
+ }
+ THR_THREAD_UNLOCK(curthread, new_thread);
+ THREAD_LIST_LOCK(curthread);
+ _thread_active_threads--;
+ new_thread->tlflags |= TLFLAGS_DETACHED;
+ _thr_ref_delete_unlocked(curthread, new_thread);
+ THREAD_LIST_UNLOCK(curthread);
+ (*thread) = 0;
+ ret = EAGAIN;
+ } else if (locked) {
+ _thr_report_creation(curthread, new_thread);
+ THR_THREAD_UNLOCK(curthread, new_thread);
+ }
+ return (ret);
+}
+
+static int
+create_stack(struct pthread_attr *pattr)
+{
+ int ret;
+
+ /* Check if a stack was specified in the thread attributes: */
+ if ((pattr->stackaddr_attr) != NULL) {
+ pattr->guardsize_attr = 0;
+ pattr->flags |= THR_STACK_USER;
+ ret = 0;
+ }
+ else
+ ret = _thr_stack_alloc(pattr);
+ return (ret);
+}
+
+static void
+thread_start(struct pthread *curthread)
+{
+ if (curthread->attr.suspend == THR_CREATE_SUSPENDED) {
+ sigset_t set = curthread->sigmask;
+
+ _thr_ast(curthread);
+
+ /*
+ * Parent thread have stored signal mask for us,
+ * we should restore it now.
+ */
+ sigprocmask(SIG_SETMASK, &set, NULL);
+ }
+
+ /*
+ * This is used as a serialization point to allow parent
+ * to report 'new thread' event to debugger before the thread
+ * does real work.
+ */
+ THR_LOCK(curthread);
+ THR_UNLOCK(curthread);
+
+ /* Run the current thread's start routine with argument: */
+ _pthread_exit(curthread->start_routine(curthread->arg));
+
+ /* This point should never be reached. */
+ PANIC("Thread has resumed after exit");
+}
diff --git a/lib/libthr/thread/thr_detach.c b/lib/libthr/thread/thr_detach.c
new file mode 100644
index 0000000..bfcb6e6
--- /dev/null
+++ b/lib/libthr/thread/thr_detach.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2005 David Xu <davidxu@freebsd.org>
+ * Copyright (C) 2003 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 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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, 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$
+ *
+ */
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <errno.h>
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+__weak_reference(_pthread_detach, pthread_detach);
+
+int
+_pthread_detach(pthread_t pthread)
+{
+ struct pthread *curthread = _get_curthread();
+ int rval;
+
+ if (pthread == NULL)
+ return (EINVAL);
+
+ THREAD_LIST_LOCK(curthread);
+ if ((rval = _thr_find_thread(curthread, pthread,
+ /*include dead*/1)) != 0) {
+ THREAD_LIST_UNLOCK(curthread);
+ return (rval);
+ }
+
+ /* Check if the thread is already detached or has a joiner. */
+ if ((pthread->tlflags & TLFLAGS_DETACHED) != 0 ||
+ (pthread->joiner != NULL)) {
+ THREAD_LIST_UNLOCK(curthread);
+ return (EINVAL);
+ }
+
+ /* Flag the thread as detached. */
+ pthread->tlflags |= TLFLAGS_DETACHED;
+ if (pthread->state == PS_DEAD)
+ THR_GCLIST_ADD(pthread);
+ THREAD_LIST_UNLOCK(curthread);
+
+ return (0);
+}
diff --git a/lib/libthr/thread/thr_equal.c b/lib/libthr/thread/thr_equal.c
new file mode 100644
index 0000000..f9f4916
--- /dev/null
+++ b/lib/libthr/thread/thr_equal.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <pthread.h>
+#include "un-namespace.h"
+#include "thr_private.h"
+
+__weak_reference(_pthread_equal, pthread_equal);
+
+int
+_pthread_equal(pthread_t t1, pthread_t t2)
+{
+ /* Compare the two thread pointers: */
+ return (t1 == t2);
+}
diff --git a/lib/libthr/thread/thr_event.c b/lib/libthr/thread/thr_event.c
new file mode 100644
index 0000000..6a64cf9
--- /dev/null
+++ b/lib/libthr/thread/thr_event.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2005 David Xu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the 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 "thr_private.h"
+
+void
+_thread_bp_create(void)
+{
+}
+
+void
+_thread_bp_death(void)
+{
+}
+
+void
+_thr_report_creation(struct pthread *curthread, struct pthread *newthread)
+{
+ curthread->event_buf.event = TD_CREATE;
+ curthread->event_buf.th_p = (td_thrhandle_t *)newthread;
+ curthread->event_buf.data = 0;
+ THR_UMTX_LOCK(curthread, &_thr_event_lock);
+ _thread_last_event = curthread;
+ _thread_bp_create();
+ _thread_last_event = NULL;
+ THR_UMTX_UNLOCK(curthread, &_thr_event_lock);
+}
+
+void
+_thr_report_death(struct pthread *curthread)
+{
+ curthread->event_buf.event = TD_DEATH;
+ curthread->event_buf.th_p = (td_thrhandle_t *)curthread;
+ curthread->event_buf.data = 0;
+ THR_UMTX_LOCK(curthread, &_thr_event_lock);
+ _thread_last_event = curthread;
+ _thread_bp_death();
+ _thread_last_event = NULL;
+ THR_UMTX_UNLOCK(curthread, &_thr_event_lock);
+}
diff --git a/lib/libthr/thread/thr_exit.c b/lib/libthr/thread/thr_exit.c
new file mode 100644
index 0000000..d438ac5
--- /dev/null
+++ b/lib/libthr/thread/thr_exit.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+
+#include "thr_private.h"
+
+void _pthread_exit(void *status);
+
+__weak_reference(_pthread_exit, pthread_exit);
+
+void
+_thread_exit(const char *fname, int lineno, const char *msg)
+{
+
+ /* Write an error message to the standard error file descriptor: */
+ _thread_printf(2,
+ "Fatal error '%s' at line %d in file %s (errno = %d)\n",
+ msg, lineno, fname, errno);
+
+ abort();
+}
+
+/*
+ * Only called when a thread is cancelled. It may be more useful
+ * to call it from pthread_exit() if other ways of asynchronous or
+ * abnormal thread termination can be found.
+ */
+void
+_thr_exit_cleanup(void)
+{
+ struct pthread *curthread = _get_curthread();
+
+ /*
+ * POSIX states that cancellation/termination of a thread should
+ * not release any visible resources (such as mutexes) and that
+ * it is the applications responsibility. Resources that are
+ * internal to the threads library, including file and fd locks,
+ * are not visible to the application and need to be released.
+ */
+ /* Unlock all private mutexes: */
+ _mutex_unlock_private(curthread);
+
+ /*
+ * This still isn't quite correct because we don't account
+ * for held spinlocks (see libc/stdlib/malloc.c).
+ */
+}
+
+void
+_pthread_exit(void *status)
+{
+ struct pthread *curthread = _get_curthread();
+
+ /* Check if this thread is already in the process of exiting: */
+ if ((curthread->cancelflags & THR_CANCEL_EXITING) != 0) {
+ char msg[128];
+ snprintf(msg, sizeof(msg), "Thread %p has called "
+ "pthread_exit() from a destructor. POSIX 1003.1 "
+ "1996 s16.2.5.2 does not allow this!", curthread);
+ PANIC(msg);
+ }
+
+ /* Flag this thread as exiting. */
+ atomic_set_int(&curthread->cancelflags, THR_CANCEL_EXITING);
+
+ _thr_exit_cleanup();
+
+ /* Save the return value: */
+ curthread->ret = status;
+ while (curthread->cleanup != NULL) {
+ pthread_cleanup_pop(1);
+ }
+
+ /* Check if there is thread specific data: */
+ if (curthread->specific != NULL) {
+ /* Run the thread-specific data destructors: */
+ _thread_cleanupspecific();
+ }
+
+ if (!_thr_isthreaded())
+ exit(0);
+
+ THREAD_LIST_LOCK(curthread);
+ _thread_active_threads--;
+ if (_thread_active_threads == 0) {
+ THREAD_LIST_UNLOCK(curthread);
+ exit(0);
+ /* Never reach! */
+ }
+ THR_LOCK(curthread);
+ curthread->state = PS_DEAD;
+ THR_UNLOCK(curthread);
+ /*
+ * Thread was created with initial refcount 1, we drop the
+ * reference count to allow it to be garbage collected.
+ */
+ curthread->refcount--;
+ if (curthread->tlflags & TLFLAGS_DETACHED)
+ THR_GCLIST_ADD(curthread);
+ THREAD_LIST_UNLOCK(curthread);
+ if (SHOULD_REPORT_EVENT(curthread, TD_DEATH))
+ _thr_report_death(curthread);
+
+ /*
+ * Kernel will do wakeup at the address, so joiner thread
+ * will be resumed if it is sleeping at the address.
+ */
+ thr_exit(&curthread->tid);
+ PANIC("thr_exit() returned");
+ /* Never reach! */
+}
diff --git a/lib/libthr/thread/thr_fork.c b/lib/libthr/thread/thr_fork.c
new file mode 100644
index 0000000..558a036
--- /dev/null
+++ b/lib/libthr/thread/thr_fork.c
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2005 David Xu <davidxu@freebsd.org>
+ * Copyright (c) 2003 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 THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <spinlock.h>
+#include "un-namespace.h"
+
+#include "libc_private.h"
+#include "thr_private.h"
+
+__weak_reference(_pthread_atfork, pthread_atfork);
+
+int
+_pthread_atfork(void (*prepare)(void), void (*parent)(void),
+ void (*child)(void))
+{
+ struct pthread *curthread;
+ struct pthread_atfork *af;
+
+ _thr_check_init();
+
+ if ((af = malloc(sizeof(struct pthread_atfork))) == NULL)
+ return (ENOMEM);
+
+ curthread = _get_curthread();
+ af->prepare = prepare;
+ af->parent = parent;
+ af->child = child;
+ THR_UMTX_LOCK(curthread, &_thr_atfork_lock);
+ TAILQ_INSERT_TAIL(&_thr_atfork_list, af, qe);
+ THR_UMTX_UNLOCK(curthread, &_thr_atfork_lock);
+ return (0);
+}
+
+__weak_reference(_fork, fork);
+
+pid_t _fork(void);
+
+pid_t
+_fork(void)
+{
+ struct pthread *curthread;
+ struct pthread_atfork *af;
+ pid_t ret;
+ int errsave;
+ int unlock_malloc;
+
+ if (!_thr_is_inited())
+ return (__sys_fork());
+
+ curthread = _get_curthread();
+
+ THR_UMTX_LOCK(curthread, &_thr_atfork_lock);
+
+ /* Run down atfork prepare handlers. */
+ TAILQ_FOREACH_REVERSE(af, &_thr_atfork_list, atfork_head, qe) {
+ if (af->prepare != NULL)
+ af->prepare();
+ }
+
+ /*
+ * Try our best to protect memory from being corrupted in
+ * child process because another thread in malloc code will
+ * simply be kill by fork().
+ */
+ if (_thr_isthreaded() != 0) {
+ unlock_malloc = 1;
+ _malloc_prefork();
+ } else {
+ unlock_malloc = 0;
+ }
+
+ /*
+ * Block all signals until we reach a safe point.
+ */
+ _thr_signal_block(curthread);
+
+ /* Fork a new process: */
+ if ((ret = __sys_fork()) == 0) {
+ /* Child process */
+ errsave = errno;
+ curthread->cancelflags &= ~THR_CANCEL_NEEDED;
+ /*
+ * Thread list will be reinitialized, and later we call
+ * _libpthread_init(), it will add us back to list.
+ */
+ curthread->tlflags &= ~(TLFLAGS_IN_TDLIST | TLFLAGS_DETACHED);
+
+ /* child is a new kernel thread. */
+ thr_self(&curthread->tid);
+
+ /* clear other threads locked us. */
+ _thr_umtx_init(&curthread->lock);
+ _thr_umtx_init(&_thr_atfork_lock);
+ _thr_setthreaded(0);
+
+ /* reinitialize libc spinlocks. */
+ _thr_spinlock_init();
+ _mutex_fork(curthread);
+
+ /* reinitalize library. */
+ _libpthread_init(curthread);
+
+ /* Ready to continue, unblock signals. */
+ _thr_signal_unblock(curthread);
+
+ /* Run down atfork child handlers. */
+ TAILQ_FOREACH(af, &_thr_atfork_list, qe) {
+ if (af->child != NULL)
+ af->child();
+ }
+ } else {
+ /* Parent process */
+ errsave = errno;
+
+ /* Ready to continue, unblock signals. */
+ _thr_signal_unblock(curthread);
+
+ if (unlock_malloc)
+ _malloc_postfork();
+
+ /* Run down atfork parent handlers. */
+ TAILQ_FOREACH(af, &_thr_atfork_list, qe) {
+ if (af->parent != NULL)
+ af->parent();
+ }
+
+ THR_UMTX_UNLOCK(curthread, &_thr_atfork_lock);
+ }
+ errno = errsave;
+
+ /* Return the process ID: */
+ return (ret);
+}
diff --git a/lib/libthr/thread/thr_getprio.c b/lib/libthr/thread/thr_getprio.c
new file mode 100644
index 0000000..e2cac2f
--- /dev/null
+++ b/lib/libthr/thread/thr_getprio.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <errno.h>
+#include <pthread.h>
+#include "un-namespace.h"
+#include "thr_private.h"
+
+__weak_reference(_pthread_getprio, pthread_getprio);
+
+int
+_pthread_getprio(pthread_t pthread)
+{
+ int policy, ret;
+ struct sched_param param;
+
+ if ((ret = _pthread_getschedparam(pthread, &policy, &param)) == 0)
+ ret = param.sched_priority;
+ else {
+ /* Invalid thread: */
+ errno = ret;
+ ret = -1;
+ }
+
+ /* Return the thread priority or an error status: */
+ return (ret);
+}
diff --git a/lib/libthr/thread/thr_getschedparam.c b/lib/libthr/thread/thr_getschedparam.c
new file mode 100644
index 0000000..31b3268
--- /dev/null
+++ b/lib/libthr/thread/thr_getschedparam.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+
+#include "namespace.h"
+#include <errno.h>
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+__weak_reference(_pthread_getschedparam, pthread_getschedparam);
+
+int
+_pthread_getschedparam(pthread_t pthread, int *policy,
+ struct sched_param *param)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret, tmp;
+
+ if ((param == NULL) || (policy == NULL))
+ /* Return an invalid argument error: */
+ ret = EINVAL;
+ else if (pthread == curthread) {
+ /*
+ * Avoid searching the thread list when it is the current
+ * thread.
+ */
+ THR_THREAD_LOCK(curthread, curthread);
+ param->sched_priority = pthread->base_priority;
+ tmp = pthread->attr.sched_policy;
+ THR_THREAD_UNLOCK(curthread, curthread);
+ *policy = tmp;
+ ret = 0;
+ }
+ /* Find the thread in the list of active threads. */
+ else if ((ret = _thr_ref_add(curthread, pthread, /*include dead*/0))
+ == 0) {
+ THR_THREAD_LOCK(curthread, pthread);
+ param->sched_priority = pthread->base_priority;
+ tmp = pthread->attr.sched_policy;
+ THR_THREAD_UNLOCK(curthread, pthread);
+ _thr_ref_delete(curthread, pthread);
+ *policy = tmp;
+ }
+ return (ret);
+}
diff --git a/lib/libthr/thread/thr_info.c b/lib/libthr/thread/thr_info.c
new file mode 100644
index 0000000..804ce98
--- /dev/null
+++ b/lib/libthr/thread/thr_info.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <pthread_np.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+__weak_reference(_pthread_set_name_np, pthread_set_name_np);
+
+/* Set the thread name for debug. */
+void
+_pthread_set_name_np(pthread_t thread, const char *name)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret = 0;
+
+ if (curthread == thread) {
+ if (thr_set_name(thread->tid, name))
+ ret = errno;
+ } else {
+ if (_thr_ref_add(curthread, thread, 0) == 0) {
+ THR_LOCK(thread);
+ if (thread->state != PS_DEAD) {
+ if (thr_set_name(thread->tid, name))
+ ret = errno;
+ }
+ THR_UNLOCK(thread);
+ _thr_ref_delete(curthread, thread);
+ } else {
+ ret = ESRCH;
+ }
+ }
+#if 0
+ /* XXX should return error code. */
+ return (ret);
+#endif
+}
diff --git a/lib/libthr/thread/thr_init.c b/lib/libthr/thread/thr_init.c
new file mode 100644
index 0000000..40365a0
--- /dev/null
+++ b/lib/libthr/thread/thr_init.c
@@ -0,0 +1,466 @@
+/*
+ * Copyright (c) 2003 Daniel M. Eischen <deischen@freebsd.org>
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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/signalvar.h>
+#include <sys/ioctl.h>
+#include <sys/sysctl.h>
+#include <sys/ttycom.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <pthread.h>
+#include <pthread_np.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+#include "libc_private.h"
+#include "thr_private.h"
+
+char *_usrstack;
+struct pthread *_thr_initial;
+int _thr_scope_system;
+int _libthr_debug;
+int _thread_event_mask;
+struct pthread *_thread_last_event;
+pthreadlist _thread_list = TAILQ_HEAD_INITIALIZER(_thread_list);
+pthreadlist _thread_gc_list = TAILQ_HEAD_INITIALIZER(_thread_gc_list);
+int _thread_active_threads = 1;
+atfork_head _thr_atfork_list = TAILQ_HEAD_INITIALIZER(_thr_atfork_list);
+umtx_t _thr_atfork_lock;
+
+/*
+ * XXX these values should be updated from kernel at startup,
+ * but current they are same.
+ */
+struct pthread_prio _thr_priorities[3] = {
+ {0, 31, 0}, /* FIF0 */
+ {-20, 20, 0}, /* OTHER */
+ {0, 31, 0} /* RR */
+};
+
+struct pthread_attr _pthread_attr_default = {
+ .sched_policy = SCHED_OTHER,
+ .sched_inherit = 0,
+ .prio = 0,
+ .suspend = THR_CREATE_RUNNING,
+ .flags = PTHREAD_SCOPE_SYSTEM,
+ .stackaddr_attr = NULL,
+ .stacksize_attr = THR_STACK_DEFAULT,
+ .guardsize_attr = 0
+};
+
+struct pthread_mutex_attr _pthread_mutexattr_default = {
+ .m_type = PTHREAD_MUTEX_DEFAULT,
+ .m_protocol = PTHREAD_PRIO_NONE,
+ .m_ceiling = 0,
+ .m_flags = 0
+};
+
+/* Default condition variable attributes: */
+struct pthread_cond_attr _pthread_condattr_default = {
+ .c_pshared = PTHREAD_PROCESS_PRIVATE,
+ .c_clockid = CLOCK_REALTIME
+};
+
+pid_t _thr_pid;
+size_t _thr_guard_default;
+size_t _thr_stack_default = THR_STACK_DEFAULT;
+size_t _thr_stack_initial = THR_STACK_INITIAL;
+int _thr_page_size;
+int _gc_count;
+umtx_t _mutex_static_lock;
+umtx_t _cond_static_lock;
+umtx_t _rwlock_static_lock;
+umtx_t _keytable_lock;
+umtx_t _thr_list_lock;
+umtx_t _thr_event_lock;
+
+int __pthread_cond_wait(pthread_cond_t *, pthread_mutex_t *);
+int __pthread_mutex_lock(pthread_mutex_t *);
+int __pthread_mutex_trylock(pthread_mutex_t *);
+void _thread_init_hack(void) __attribute__ ((constructor));
+
+static void init_private(void);
+static void init_main_thread(struct pthread *thread);
+
+/*
+ * All weak references used within libc should be in this table.
+ * This is so that static libraries will work.
+ */
+STATIC_LIB_REQUIRE(_accept);
+STATIC_LIB_REQUIRE(_close);
+STATIC_LIB_REQUIRE(_connect);
+STATIC_LIB_REQUIRE(_fcntl);
+STATIC_LIB_REQUIRE(_fsync);
+STATIC_LIB_REQUIRE(_nanosleep);
+STATIC_LIB_REQUIRE(_open);
+STATIC_LIB_REQUIRE(_pthread_getspecific);
+STATIC_LIB_REQUIRE(_pthread_key_create);
+STATIC_LIB_REQUIRE(_pthread_key_delete);
+STATIC_LIB_REQUIRE(_pthread_mutex_destroy);
+STATIC_LIB_REQUIRE(_pthread_mutex_init);
+STATIC_LIB_REQUIRE(_pthread_mutex_lock);
+STATIC_LIB_REQUIRE(_pthread_mutex_trylock);
+STATIC_LIB_REQUIRE(_pthread_mutex_unlock);
+STATIC_LIB_REQUIRE(_pthread_mutexattr_init);
+STATIC_LIB_REQUIRE(_pthread_mutexattr_destroy);
+STATIC_LIB_REQUIRE(_pthread_mutexattr_settype);
+STATIC_LIB_REQUIRE(_pthread_once);
+STATIC_LIB_REQUIRE(_pthread_setspecific);
+STATIC_LIB_REQUIRE(_read);
+STATIC_LIB_REQUIRE(_readv);
+STATIC_LIB_REQUIRE(_recvfrom);
+STATIC_LIB_REQUIRE(_recvmsg);
+STATIC_LIB_REQUIRE(_select);
+STATIC_LIB_REQUIRE(_sendmsg);
+STATIC_LIB_REQUIRE(_sendto);
+STATIC_LIB_REQUIRE(_sigaction);
+STATIC_LIB_REQUIRE(_sigprocmask);
+STATIC_LIB_REQUIRE(_sigsuspend);
+STATIC_LIB_REQUIRE(_socket);
+STATIC_LIB_REQUIRE(_socketpair);
+STATIC_LIB_REQUIRE(_thread_init_hack);
+STATIC_LIB_REQUIRE(_wait4);
+STATIC_LIB_REQUIRE(_write);
+STATIC_LIB_REQUIRE(_writev);
+
+/*
+ * These are needed when linking statically. All references within
+ * libgcc (and in the future libc) to these routines are weak, but
+ * if they are not (strongly) referenced by the application or other
+ * libraries, then the actual functions will not be loaded.
+ */
+STATIC_LIB_REQUIRE(_pthread_once);
+STATIC_LIB_REQUIRE(_pthread_key_create);
+STATIC_LIB_REQUIRE(_pthread_key_delete);
+STATIC_LIB_REQUIRE(_pthread_getspecific);
+STATIC_LIB_REQUIRE(_pthread_setspecific);
+STATIC_LIB_REQUIRE(_pthread_mutex_init);
+STATIC_LIB_REQUIRE(_pthread_mutex_destroy);
+STATIC_LIB_REQUIRE(_pthread_mutex_lock);
+STATIC_LIB_REQUIRE(_pthread_mutex_trylock);
+STATIC_LIB_REQUIRE(_pthread_mutex_unlock);
+STATIC_LIB_REQUIRE(_pthread_create);
+
+/* Pull in all symbols required by libthread_db */
+STATIC_LIB_REQUIRE(_thread_state_running);
+
+#define DUAL_ENTRY(entry) \
+ (pthread_func_t)entry, (pthread_func_t)entry
+
+static pthread_func_t jmp_table[][2] = {
+ {DUAL_ENTRY(_pthread_atfork)}, /* PJT_ATFORK */
+ {DUAL_ENTRY(_pthread_attr_destroy)}, /* PJT_ATTR_DESTROY */
+ {DUAL_ENTRY(_pthread_attr_getdetachstate)}, /* PJT_ATTR_GETDETACHSTATE */
+ {DUAL_ENTRY(_pthread_attr_getguardsize)}, /* PJT_ATTR_GETGUARDSIZE */
+ {DUAL_ENTRY(_pthread_attr_getinheritsched)}, /* PJT_ATTR_GETINHERITSCHED */
+ {DUAL_ENTRY(_pthread_attr_getschedparam)}, /* PJT_ATTR_GETSCHEDPARAM */
+ {DUAL_ENTRY(_pthread_attr_getschedpolicy)}, /* PJT_ATTR_GETSCHEDPOLICY */
+ {DUAL_ENTRY(_pthread_attr_getscope)}, /* PJT_ATTR_GETSCOPE */
+ {DUAL_ENTRY(_pthread_attr_getstackaddr)}, /* PJT_ATTR_GETSTACKADDR */
+ {DUAL_ENTRY(_pthread_attr_getstacksize)}, /* PJT_ATTR_GETSTACKSIZE */
+ {DUAL_ENTRY(_pthread_attr_init)}, /* PJT_ATTR_INIT */
+ {DUAL_ENTRY(_pthread_attr_setdetachstate)}, /* PJT_ATTR_SETDETACHSTATE */
+ {DUAL_ENTRY(_pthread_attr_setguardsize)}, /* PJT_ATTR_SETGUARDSIZE */
+ {DUAL_ENTRY(_pthread_attr_setinheritsched)}, /* PJT_ATTR_SETINHERITSCHED */
+ {DUAL_ENTRY(_pthread_attr_setschedparam)}, /* PJT_ATTR_SETSCHEDPARAM */
+ {DUAL_ENTRY(_pthread_attr_setschedpolicy)}, /* PJT_ATTR_SETSCHEDPOLICY */
+ {DUAL_ENTRY(_pthread_attr_setscope)}, /* PJT_ATTR_SETSCOPE */
+ {DUAL_ENTRY(_pthread_attr_setstackaddr)}, /* PJT_ATTR_SETSTACKADDR */
+ {DUAL_ENTRY(_pthread_attr_setstacksize)}, /* PJT_ATTR_SETSTACKSIZE */
+ {DUAL_ENTRY(_pthread_cancel)}, /* PJT_CANCEL */
+ {DUAL_ENTRY(_pthread_cleanup_pop)}, /* PJT_CLEANUP_POP */
+ {DUAL_ENTRY(_pthread_cleanup_push)}, /* PJT_CLEANUP_PUSH */
+ {DUAL_ENTRY(_pthread_cond_broadcast)}, /* PJT_COND_BROADCAST */
+ {DUAL_ENTRY(_pthread_cond_destroy)}, /* PJT_COND_DESTROY */
+ {DUAL_ENTRY(_pthread_cond_init)}, /* PJT_COND_INIT */
+ {DUAL_ENTRY(_pthread_cond_signal)}, /* PJT_COND_SIGNAL */
+ {DUAL_ENTRY(_pthread_cond_timedwait)}, /* PJT_COND_TIMEDWAIT */
+ {(pthread_func_t)__pthread_cond_wait,
+ (pthread_func_t)_pthread_cond_wait}, /* PJT_COND_WAIT */
+ {DUAL_ENTRY(_pthread_detach)}, /* PJT_DETACH */
+ {DUAL_ENTRY(_pthread_equal)}, /* PJT_EQUAL */
+ {DUAL_ENTRY(_pthread_exit)}, /* PJT_EXIT */
+ {DUAL_ENTRY(_pthread_getspecific)}, /* PJT_GETSPECIFIC */
+ {DUAL_ENTRY(_pthread_join)}, /* PJT_JOIN */
+ {DUAL_ENTRY(_pthread_key_create)}, /* PJT_KEY_CREATE */
+ {DUAL_ENTRY(_pthread_key_delete)}, /* PJT_KEY_DELETE*/
+ {DUAL_ENTRY(_pthread_kill)}, /* PJT_KILL */
+ {DUAL_ENTRY(_pthread_main_np)}, /* PJT_MAIN_NP */
+ {DUAL_ENTRY(_pthread_mutexattr_destroy)}, /* PJT_MUTEXATTR_DESTROY */
+ {DUAL_ENTRY(_pthread_mutexattr_init)}, /* PJT_MUTEXATTR_INIT */
+ {DUAL_ENTRY(_pthread_mutexattr_settype)}, /* PJT_MUTEXATTR_SETTYPE */
+ {DUAL_ENTRY(_pthread_mutex_destroy)}, /* PJT_MUTEX_DESTROY */
+ {DUAL_ENTRY(_pthread_mutex_init)}, /* PJT_MUTEX_INIT */
+ {(pthread_func_t)__pthread_mutex_lock,
+ (pthread_func_t)_pthread_mutex_lock}, /* PJT_MUTEX_LOCK */
+ {(pthread_func_t)__pthread_mutex_trylock,
+ (pthread_func_t)_pthread_mutex_trylock},/* PJT_MUTEX_TRYLOCK */
+ {DUAL_ENTRY(_pthread_mutex_unlock)}, /* PJT_MUTEX_UNLOCK */
+ {DUAL_ENTRY(_pthread_once)}, /* PJT_ONCE */
+ {DUAL_ENTRY(_pthread_rwlock_destroy)}, /* PJT_RWLOCK_DESTROY */
+ {DUAL_ENTRY(_pthread_rwlock_init)}, /* PJT_RWLOCK_INIT */
+ {DUAL_ENTRY(_pthread_rwlock_rdlock)}, /* PJT_RWLOCK_RDLOCK */
+ {DUAL_ENTRY(_pthread_rwlock_tryrdlock)},/* PJT_RWLOCK_TRYRDLOCK */
+ {DUAL_ENTRY(_pthread_rwlock_trywrlock)},/* PJT_RWLOCK_TRYWRLOCK */
+ {DUAL_ENTRY(_pthread_rwlock_unlock)}, /* PJT_RWLOCK_UNLOCK */
+ {DUAL_ENTRY(_pthread_rwlock_wrlock)}, /* PJT_RWLOCK_WRLOCK */
+ {DUAL_ENTRY(_pthread_self)}, /* PJT_SELF */
+ {DUAL_ENTRY(_pthread_setcancelstate)}, /* PJT_SETCANCELSTATE */
+ {DUAL_ENTRY(_pthread_setcanceltype)}, /* PJT_SETCANCELTYPE */
+ {DUAL_ENTRY(_pthread_setspecific)}, /* PJT_SETSPECIFIC */
+ {DUAL_ENTRY(_pthread_sigmask)}, /* PJT_SIGMASK */
+ {DUAL_ENTRY(_pthread_testcancel)} /* PJT_TESTCANCEL */
+};
+
+static int init_once = 0;
+
+/*
+ * For the shared version of the threads library, the above is sufficient.
+ * But for the archive version of the library, we need a little bit more.
+ * Namely, we must arrange for this particular module to be pulled in from
+ * the archive library at link time. To accomplish that, we define and
+ * initialize a variable, "_thread_autoinit_dummy_decl". This variable is
+ * referenced (as an extern) from libc/stdlib/exit.c. This will always
+ * create a need for this module, ensuring that it is present in the
+ * executable.
+ */
+extern int _thread_autoinit_dummy_decl;
+int _thread_autoinit_dummy_decl = 0;
+
+void
+_thread_init_hack(void)
+{
+
+ _libpthread_init(NULL);
+}
+
+
+/*
+ * Threaded process initialization.
+ *
+ * This is only called under two conditions:
+ *
+ * 1) Some thread routines have detected that the library hasn't yet
+ * been initialized (_thr_initial == NULL && curthread == NULL), or
+ *
+ * 2) An explicit call to reinitialize after a fork (indicated
+ * by curthread != NULL)
+ */
+void
+_libpthread_init(struct pthread *curthread)
+{
+ int fd, first = 0;
+ sigset_t sigset, oldset;
+
+ /* Check if this function has already been called: */
+ if ((_thr_initial != NULL) && (curthread == NULL))
+ /* Only initialize the threaded application once. */
+ return;
+
+ /*
+ * Check the size of the jump table to make sure it is preset
+ * with the correct number of entries.
+ */
+ if (sizeof(jmp_table) != (sizeof(pthread_func_t) * PJT_MAX * 2))
+ PANIC("Thread jump table not properly initialized");
+ memcpy(__thr_jtable, jmp_table, sizeof(jmp_table));
+
+ /*
+ * Check for the special case of this process running as
+ * or in place of init as pid = 1:
+ */
+ if ((_thr_pid = getpid()) == 1) {
+ /*
+ * Setup a new session for this process which is
+ * assumed to be running as root.
+ */
+ if (setsid() == -1)
+ PANIC("Can't set session ID");
+ if (revoke(_PATH_CONSOLE) != 0)
+ PANIC("Can't revoke console");
+ if ((fd = __sys_open(_PATH_CONSOLE, O_RDWR)) < 0)
+ PANIC("Can't open console");
+ if (setlogin("root") == -1)
+ PANIC("Can't set login to root");
+ if (_ioctl(fd, TIOCSCTTY, (char *) NULL) == -1)
+ PANIC("Can't set controlling terminal");
+ }
+
+ /* Initialize pthread private data. */
+ init_private();
+
+ /* Set the initial thread. */
+ if (curthread == NULL) {
+ first = 1;
+ /* Create and initialize the initial thread. */
+ curthread = _thr_alloc(NULL);
+ if (curthread == NULL)
+ PANIC("Can't allocate initial thread");
+ init_main_thread(curthread);
+ }
+ /*
+ * Add the thread to the thread list queue.
+ */
+ THR_LIST_ADD(curthread);
+ _thread_active_threads = 1;
+
+ /* Setup the thread specific data */
+ _tcb_set(curthread->tcb);
+
+ if (first) {
+ SIGFILLSET(sigset);
+ SIGDELSET(sigset, SIGTRAP);
+ __sys_sigprocmask(SIG_SETMASK, &sigset, &oldset);
+ _thr_signal_init();
+ _thr_initial = curthread;
+ SIGDELSET(oldset, SIGCANCEL);
+ __sys_sigprocmask(SIG_SETMASK, &oldset, NULL);
+ if (_thread_event_mask & TD_CREATE)
+ _thr_report_creation(curthread, curthread);
+ }
+}
+
+/*
+ * This function and pthread_create() do a lot of the same things.
+ * It'd be nice to consolidate the common stuff in one place.
+ */
+static void
+init_main_thread(struct pthread *thread)
+{
+ /* Setup the thread attributes. */
+ thr_self(&thread->tid);
+ thread->attr = _pthread_attr_default;
+ /*
+ * Set up the thread stack.
+ *
+ * Create a red zone below the main stack. All other stacks
+ * are constrained to a maximum size by the parameters
+ * passed to mmap(), but this stack is only limited by
+ * resource limits, so this stack needs an explicitly mapped
+ * red zone to protect the thread stack that is just beyond.
+ */
+ if (mmap(_usrstack - _thr_stack_initial -
+ _thr_guard_default, _thr_guard_default, 0, MAP_ANON,
+ -1, 0) == MAP_FAILED)
+ PANIC("Cannot allocate red zone for initial thread");
+
+ /*
+ * Mark the stack as an application supplied stack so that it
+ * isn't deallocated.
+ *
+ * XXX - I'm not sure it would hurt anything to deallocate
+ * the main thread stack because deallocation doesn't
+ * actually free() it; it just puts it in the free
+ * stack queue for later reuse.
+ */
+ thread->attr.stackaddr_attr = _usrstack - _thr_stack_initial;
+ thread->attr.stacksize_attr = _thr_stack_initial;
+ thread->attr.guardsize_attr = _thr_guard_default;
+ thread->attr.flags |= THR_STACK_USER;
+
+ /*
+ * Write a magic value to the thread structure
+ * to help identify valid ones:
+ */
+ thread->magic = THR_MAGIC;
+
+ thread->cancelflags = PTHREAD_CANCEL_ENABLE | PTHREAD_CANCEL_DEFERRED;
+ thr_set_name(thread->tid, "initial thread");
+
+ /* Default the priority of the initial thread: */
+ thread->base_priority = THR_DEF_PRIORITY;
+ thread->active_priority = THR_DEF_PRIORITY;
+ thread->inherited_priority = 0;
+
+ /* Initialize the mutex queue: */
+ TAILQ_INIT(&thread->mutexq);
+
+ thread->state = PS_RUNNING;
+
+ /* Others cleared to zero by thr_alloc() */
+}
+
+static void
+init_private(void)
+{
+ size_t len;
+ int mib[2];
+
+ _thr_umtx_init(&_mutex_static_lock);
+ _thr_umtx_init(&_cond_static_lock);
+ _thr_umtx_init(&_rwlock_static_lock);
+ _thr_umtx_init(&_keytable_lock);
+ _thr_umtx_init(&_thr_atfork_lock);
+ _thr_umtx_init(&_thr_event_lock);
+ _thr_once_init();
+ _thr_spinlock_init();
+ _thr_list_init();
+
+ /*
+ * Avoid reinitializing some things if they don't need to be,
+ * e.g. after a fork().
+ */
+ if (init_once == 0) {
+ /* Find the stack top */
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_USRSTACK;
+ len = sizeof (_usrstack);
+ if (sysctl(mib, 2, &_usrstack, &len, NULL, 0) == -1)
+ PANIC("Cannot get kern.usrstack from sysctl");
+ _thr_page_size = getpagesize();
+ _thr_guard_default = _thr_page_size;
+ _pthread_attr_default.guardsize_attr = _thr_guard_default;
+ _pthread_attr_default.stacksize_attr = _thr_stack_default;
+
+ TAILQ_INIT(&_thr_atfork_list);
+#ifdef SYSTEM_SCOPE_ONLY
+ _thr_scope_system = 1;
+#else
+ if (getenv("LIBPTHREAD_SYSTEM_SCOPE") != NULL)
+ _thr_scope_system = 1;
+ else if (getenv("LIBPTHREAD_PROCESS_SCOPE") != NULL)
+ _thr_scope_system = -1;
+#endif
+ }
+ init_once = 1;
+}
diff --git a/lib/libthr/thread/thr_join.c b/lib/libthr/thread/thr_join.c
new file mode 100644
index 0000000..de27074
--- /dev/null
+++ b/lib/libthr/thread/thr_join.c
@@ -0,0 +1,146 @@
+/*
+ * 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 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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, 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$
+ *
+ */
+
+#include "namespace.h"
+#include <errno.h>
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+int _pthread_timedjoin_np(pthread_t pthread, void **thread_return,
+ const struct timespec *abstime);
+static int join_common(pthread_t, void **, const struct timespec *);
+
+__weak_reference(_pthread_join, pthread_join);
+__weak_reference(_pthread_timedjoin_np, pthread_timedjoin_np);
+
+static void backout_join(void *arg)
+{
+ struct pthread *curthread = _get_curthread();
+ struct pthread *pthread = (struct pthread *)arg;
+
+ THREAD_LIST_LOCK(curthread);
+ pthread->joiner = NULL;
+ THREAD_LIST_UNLOCK(curthread);
+}
+
+int
+_pthread_join(pthread_t pthread, void **thread_return)
+{
+ return (join_common(pthread, thread_return, NULL));
+}
+
+int
+_pthread_timedjoin_np(pthread_t pthread, void **thread_return,
+ const struct timespec *abstime)
+{
+ if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 ||
+ abstime->tv_nsec >= 1000000000)
+ return (EINVAL);
+
+ return (join_common(pthread, thread_return, abstime));
+}
+
+static int
+join_common(pthread_t pthread, void **thread_return,
+ const struct timespec *abstime)
+{
+ struct pthread *curthread = _get_curthread();
+ struct timespec ts, ts2, *tsp;
+ void *tmp;
+ long tid;
+ int oldcancel;
+ int ret = 0;
+
+ if (pthread == NULL)
+ return (EINVAL);
+
+ if (pthread == curthread)
+ return (EDEADLK);
+
+ THREAD_LIST_LOCK(curthread);
+ if ((ret = _thr_find_thread(curthread, pthread, 1)) != 0) {
+ ret = ESRCH;
+ } else if ((pthread->tlflags & TLFLAGS_DETACHED) != 0) {
+ ret = ESRCH;
+ } else if (pthread->joiner != NULL) {
+ /* Multiple joiners are not supported. */
+ ret = ENOTSUP;
+ }
+ if (ret) {
+ THREAD_LIST_UNLOCK(curthread);
+ return (ret);
+ }
+ /* Set the running thread to be the joiner: */
+ pthread->joiner = curthread;
+
+ THREAD_LIST_UNLOCK(curthread);
+
+ THR_CLEANUP_PUSH(curthread, backout_join, pthread);
+ oldcancel = _thr_cancel_enter(curthread);
+
+ tid = pthread->tid;
+ while (pthread->tid != TID_TERMINATED) {
+ if (abstime != NULL) {
+ clock_gettime(CLOCK_REALTIME, &ts);
+ TIMESPEC_SUB(&ts2, abstime, &ts);
+ if (ts2.tv_sec < 0) {
+ ret = ETIMEDOUT;
+ break;
+ }
+ tsp = &ts2;
+ } else
+ tsp = NULL;
+ ret = _thr_umtx_wait(&pthread->tid, tid, tsp);
+ if (ret == ETIMEDOUT)
+ break;
+ }
+
+ _thr_cancel_leave(curthread, oldcancel);
+ THR_CLEANUP_POP(curthread, 0);
+
+ if (ret == ETIMEDOUT) {
+ THREAD_LIST_LOCK(curthread);
+ pthread->joiner = NULL;
+ THREAD_LIST_UNLOCK(curthread);
+ } else {
+ ret = 0;
+ tmp = pthread->ret;
+ THREAD_LIST_LOCK(curthread);
+ pthread->tlflags |= TLFLAGS_DETACHED;
+ pthread->joiner = NULL;
+ THR_GCLIST_ADD(pthread);
+ THREAD_LIST_UNLOCK(curthread);
+
+ if (thread_return != NULL)
+ *thread_return = tmp;
+ }
+ return (ret);
+}
diff --git a/lib/libthr/thread/thr_kern.c b/lib/libthr/thread/thr_kern.c
new file mode 100644
index 0000000..aa7dce6
--- /dev/null
+++ b/lib/libthr/thread/thr_kern.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2005 David Xu <davidxu@freebsd.org>
+ * Copyright (C) 2003 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 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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, 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$
+ */
+
+#include <sys/types.h>
+#include <sys/signalvar.h>
+#include <pthread.h>
+
+#include "thr_private.h"
+
+/*#define DEBUG_THREAD_KERN */
+#ifdef DEBUG_THREAD_KERN
+#define DBG_MSG stdout_debug
+#else
+#define DBG_MSG(x...)
+#endif
+
+/*
+ * This is called when the first thread (other than the initial
+ * thread) is created.
+ */
+int
+_thr_setthreaded(int threaded)
+{
+ if (((threaded == 0) ^ (__isthreaded == 0)) == 0)
+ return (0);
+
+ __isthreaded = threaded;
+ if (threaded != 0) {
+ _thr_rtld_init();
+ } else {
+ _thr_rtld_fini();
+ }
+ return (0);
+}
+
+void
+_thr_signal_block(struct pthread *curthread)
+{
+ sigset_t set;
+
+ if (curthread->sigblock > 0) {
+ curthread->sigblock++;
+ return;
+ }
+ SIGFILLSET(set);
+ SIGDELSET(set, SIGBUS);
+ SIGDELSET(set, SIGILL);
+ SIGDELSET(set, SIGFPE);
+ SIGDELSET(set, SIGSEGV);
+ SIGDELSET(set, SIGTRAP);
+ __sys_sigprocmask(SIG_BLOCK, &set, &curthread->sigmask);
+ curthread->sigblock++;
+}
+
+void
+_thr_signal_unblock(struct pthread *curthread)
+{
+ if (--curthread->sigblock == 0)
+ __sys_sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL);
+}
+
+int
+_thr_send_sig(struct pthread *thread, int sig)
+{
+ return thr_kill(thread->tid, sig);
+}
+
+void
+_thr_assert_lock_level()
+{
+ PANIC("locklevel <= 0");
+}
diff --git a/lib/libthr/thread/thr_kill.c b/lib/libthr/thread/thr_kill.c
new file mode 100644
index 0000000..e55681a
--- /dev/null
+++ b/lib/libthr/thread/thr_kill.c
@@ -0,0 +1,69 @@
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <errno.h>
+#include <signal.h>
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+__weak_reference(_pthread_kill, pthread_kill);
+
+int
+_pthread_kill(pthread_t pthread, int sig)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ /* Check for invalid signal numbers: */
+ if (sig < 0 || sig > _SIG_MAXSIG)
+ /* Invalid signal: */
+ ret = EINVAL;
+ /*
+ * Ensure the thread is in the list of active threads, and the
+ * signal is valid (signal 0 specifies error checking only) and
+ * not being ignored:
+ */
+ else if ((ret = _thr_ref_add(curthread, pthread, /*include dead*/0))
+ == 0) {
+ if (sig > 0)
+ _thr_send_sig(pthread, sig);
+ _thr_ref_delete(curthread, pthread);
+ }
+
+ /* Return the completion status: */
+ return (ret);
+}
diff --git a/lib/libthr/thread/thr_list.c b/lib/libthr/thread/thr_list.c
new file mode 100644
index 0000000..d46b5ea
--- /dev/null
+++ b/lib/libthr/thread/thr_list.c
@@ -0,0 +1,343 @@
+/*
+ * Copyright (c) 2005 David Xu <davidxu@freebsd.org>
+ * Copyright (C) 2003 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 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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, 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$
+ */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+
+#include "thr_private.h"
+#include "libc_private.h"
+
+/*#define DEBUG_THREAD_LIST */
+#ifdef DEBUG_THREAD_LIST
+#define DBG_MSG stdout_debug
+#else
+#define DBG_MSG(x...)
+#endif
+
+#define MAX_THREADS 100000
+
+/*
+ * Define a high water mark for the maximum number of threads that
+ * will be cached. Once this level is reached, any extra threads
+ * will be free()'d.
+ */
+#define MAX_CACHED_THREADS 100
+
+/*
+ * We've got to keep track of everything that is allocated, not only
+ * to have a speedy free list, but also so they can be deallocated
+ * after a fork().
+ */
+static TAILQ_HEAD(, pthread) free_threadq;
+static umtx_t free_thread_lock;
+static umtx_t tcb_lock;
+static int free_thread_count = 0;
+static int inited = 0;
+static int total_threads;
+
+LIST_HEAD(thread_hash_head, pthread);
+#define HASH_QUEUES 128
+static struct thread_hash_head thr_hashtable[HASH_QUEUES];
+#define THREAD_HASH(thrd) (((unsigned long)thrd >> 8) % HASH_QUEUES)
+
+static void thr_destroy(struct pthread *curthread, struct pthread *thread);
+
+void
+_thr_list_init(void)
+{
+ int i;
+
+ _gc_count = 0;
+ total_threads = 1;
+ _thr_umtx_init(&_thr_list_lock);
+ TAILQ_INIT(&_thread_list);
+ TAILQ_INIT(&free_threadq);
+ _thr_umtx_init(&free_thread_lock);
+ _thr_umtx_init(&tcb_lock);
+ if (inited) {
+ for (i = 0; i < HASH_QUEUES; ++i)
+ LIST_INIT(&thr_hashtable[i]);
+ }
+ inited = 1;
+}
+
+void
+_thr_gc(struct pthread *curthread)
+{
+ struct pthread *td, *td_next;
+ TAILQ_HEAD(, pthread) worklist;
+
+ TAILQ_INIT(&worklist);
+ THREAD_LIST_LOCK(curthread);
+
+ /* Check the threads waiting for GC. */
+ for (td = TAILQ_FIRST(&_thread_gc_list); td != NULL; td = td_next) {
+ td_next = TAILQ_NEXT(td, gcle);
+ if (td->tid != TID_TERMINATED) {
+ /* make sure we are not still in userland */
+ continue;
+ }
+ _thr_stack_free(&td->attr);
+ if (((td->tlflags & TLFLAGS_DETACHED) != 0) &&
+ (td->refcount == 0)) {
+ THR_GCLIST_REMOVE(td);
+ /*
+ * The thread has detached and is no longer
+ * referenced. It is safe to remove all
+ * remnants of the thread.
+ */
+ THR_LIST_REMOVE(td);
+ TAILQ_INSERT_HEAD(&worklist, td, gcle);
+ }
+ }
+ THREAD_LIST_UNLOCK(curthread);
+
+ while ((td = TAILQ_FIRST(&worklist)) != NULL) {
+ TAILQ_REMOVE(&worklist, td, gcle);
+ /*
+ * XXX we don't free initial thread, because there might
+ * have some code referencing initial thread.
+ */
+ if (td == _thr_initial) {
+ DBG_MSG("Initial thread won't be freed\n");
+ continue;
+ }
+
+ _thr_free(curthread, td);
+ }
+}
+
+struct pthread *
+_thr_alloc(struct pthread *curthread)
+{
+ struct pthread *thread = NULL;
+ struct tcb *tcb;
+
+ if (curthread != NULL) {
+ if (GC_NEEDED())
+ _thr_gc(curthread);
+ if (free_thread_count > 0) {
+ THR_LOCK_ACQUIRE(curthread, &free_thread_lock);
+ if ((thread = TAILQ_FIRST(&free_threadq)) != NULL) {
+ TAILQ_REMOVE(&free_threadq, thread, tle);
+ free_thread_count--;
+ }
+ THR_LOCK_RELEASE(curthread, &free_thread_lock);
+ }
+ }
+ if (thread == NULL) {
+ if (total_threads > MAX_THREADS)
+ return (NULL);
+ atomic_fetchadd_int(&total_threads, 1);
+ thread = malloc(sizeof(struct pthread));
+ if (thread == NULL) {
+ atomic_fetchadd_int(&total_threads, -1);
+ return (NULL);
+ }
+ }
+ if (curthread != NULL) {
+ THR_LOCK_ACQUIRE(curthread, &tcb_lock);
+ tcb = _tcb_ctor(thread, 0 /* not initial tls */);
+ THR_LOCK_RELEASE(curthread, &tcb_lock);
+ } else {
+ tcb = _tcb_ctor(thread, 1 /* initial tls */);
+ }
+ if (tcb != NULL) {
+ memset(thread, 0, sizeof(*thread));
+ thread->tcb = tcb;
+ } else {
+ thr_destroy(curthread, thread);
+ atomic_fetchadd_int(&total_threads, -1);
+ thread = NULL;
+ }
+ return (thread);
+}
+
+void
+_thr_free(struct pthread *curthread, struct pthread *thread)
+{
+ DBG_MSG("Freeing thread %p\n", thread);
+
+ /*
+ * Always free tcb, as we only know it is part of RTLD TLS
+ * block, but don't know its detail and can not assume how
+ * it works, so better to avoid caching it here.
+ */
+ if (curthread != NULL) {
+ THR_LOCK_ACQUIRE(curthread, &tcb_lock);
+ _tcb_dtor(thread->tcb);
+ THR_LOCK_RELEASE(curthread, &tcb_lock);
+ } else {
+ _tcb_dtor(thread->tcb);
+ }
+ thread->tcb = NULL;
+ if ((curthread == NULL) || (free_thread_count >= MAX_CACHED_THREADS)) {
+ thr_destroy(curthread, thread);
+ atomic_fetchadd_int(&total_threads, -1);
+ } else {
+ /*
+ * Add the thread to the free thread list, this also avoids
+ * pthread id is reused too quickly, may help some buggy apps.
+ */
+ THR_LOCK_ACQUIRE(curthread, &free_thread_lock);
+ TAILQ_INSERT_TAIL(&free_threadq, thread, tle);
+ free_thread_count++;
+ THR_LOCK_RELEASE(curthread, &free_thread_lock);
+ }
+}
+
+static void
+thr_destroy(struct pthread *curthread __unused, struct pthread *thread)
+{
+ free(thread);
+}
+
+/*
+ * Add the thread to the list of all threads and increment
+ * number of active threads.
+ */
+void
+_thr_link(struct pthread *curthread, struct pthread *thread)
+{
+ THREAD_LIST_LOCK(curthread);
+ THR_LIST_ADD(thread);
+ _thread_active_threads++;
+ THREAD_LIST_UNLOCK(curthread);
+}
+
+/*
+ * Remove an active thread.
+ */
+void
+_thr_unlink(struct pthread *curthread, struct pthread *thread)
+{
+ THREAD_LIST_LOCK(curthread);
+ THR_LIST_REMOVE(thread);
+ _thread_active_threads--;
+ THREAD_LIST_UNLOCK(curthread);
+}
+
+void
+_thr_hash_add(struct pthread *thread)
+{
+ struct thread_hash_head *head;
+
+ head = &thr_hashtable[THREAD_HASH(thread)];
+ LIST_INSERT_HEAD(head, thread, hle);
+}
+
+void
+_thr_hash_remove(struct pthread *thread)
+{
+ LIST_REMOVE(thread, hle);
+}
+
+struct pthread *
+_thr_hash_find(struct pthread *thread)
+{
+ struct pthread *td;
+ struct thread_hash_head *head;
+
+ head = &thr_hashtable[THREAD_HASH(thread)];
+ LIST_FOREACH(td, head, hle) {
+ if (td == thread)
+ return (thread);
+ }
+ return (NULL);
+}
+
+/*
+ * Find a thread in the linked list of active threads and add a reference
+ * to it. Threads with positive reference counts will not be deallocated
+ * until all references are released.
+ */
+int
+_thr_ref_add(struct pthread *curthread, struct pthread *thread,
+ int include_dead)
+{
+ int ret;
+
+ if (thread == NULL)
+ /* Invalid thread: */
+ return (EINVAL);
+
+ THREAD_LIST_LOCK(curthread);
+ if ((ret = _thr_find_thread(curthread, thread, include_dead)) == 0) {
+ thread->refcount++;
+ }
+ THREAD_LIST_UNLOCK(curthread);
+
+ /* Return zero if the thread exists: */
+ return (ret);
+}
+
+void
+_thr_ref_delete(struct pthread *curthread, struct pthread *thread)
+{
+ THREAD_LIST_LOCK(curthread);
+ _thr_ref_delete_unlocked(curthread, thread);
+ THREAD_LIST_UNLOCK(curthread);
+}
+
+void
+_thr_ref_delete_unlocked(struct pthread *curthread __unused,
+ struct pthread *thread)
+{
+ if (thread != NULL) {
+ thread->refcount--;
+ if ((thread->refcount == 0) && thread->state == PS_DEAD &&
+ (thread->tlflags & TLFLAGS_DETACHED) != 0)
+ THR_GCLIST_ADD(thread);
+ }
+}
+
+int
+_thr_find_thread(struct pthread *curthread __unused, struct pthread *thread,
+ int include_dead)
+{
+ struct pthread *pthread;
+
+ if (thread == NULL)
+ /* Invalid thread: */
+ return (EINVAL);
+
+ pthread = _thr_hash_find(thread);
+ if (pthread) {
+ if (include_dead == 0 && pthread->state == PS_DEAD) {
+ pthread = NULL;
+ }
+ }
+
+ /* Return zero if the thread exists: */
+ return ((pthread != NULL) ? 0 : ESRCH);
+}
diff --git a/lib/libthr/thread/thr_main_np.c b/lib/libthr/thread/thr_main_np.c
new file mode 100644
index 0000000..bfa8b87
--- /dev/null
+++ b/lib/libthr/thread/thr_main_np.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2001 Alfred Perlstein
+ * Author: Alfred Perlstein <alfred@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 "namespace.h"
+#include <pthread.h>
+#include <pthread_np.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+__weak_reference(_pthread_main_np, pthread_main_np);
+
+/*
+ * Provide the equivelant to Solaris thr_main() function
+ */
+int
+_pthread_main_np()
+{
+
+ if (!_thr_initial)
+ return (-1);
+ else
+ return (_pthread_equal(_pthread_self(), _thr_initial) ? 1 : 0);
+}
diff --git a/lib/libthr/thread/thr_multi_np.c b/lib/libthr/thread/thr_multi_np.c
new file mode 100644
index 0000000..3ea2cb4
--- /dev/null
+++ b/lib/libthr/thread/thr_multi_np.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1996 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <pthread.h>
+#include <pthread_np.h>
+#include "un-namespace.h"
+
+__weak_reference(_pthread_multi_np, pthread_multi_np);
+
+int
+_pthread_multi_np()
+{
+
+ /* Return to multi-threaded scheduling mode: */
+ /*
+ * XXX - Do we want to do this?
+ * __is_threaded = 1;
+ */
+ _pthread_resume_all_np();
+ return (0);
+}
diff --git a/lib/libthr/thread/thr_mutex.c b/lib/libthr/thread/thr_mutex.c
new file mode 100644
index 0000000..e79e014
--- /dev/null
+++ b/lib/libthr/thread/thr_mutex.c
@@ -0,0 +1,669 @@
+/*
+ * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
+ * Copyright (c) 2006 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+#if defined(_PTHREADS_INVARIANTS)
+#define MUTEX_INIT_LINK(m) do { \
+ (m)->m_qe.tqe_prev = NULL; \
+ (m)->m_qe.tqe_next = NULL; \
+} while (0)
+#define MUTEX_ASSERT_IS_OWNED(m) do { \
+ if ((m)->m_qe.tqe_prev == NULL) \
+ PANIC("mutex is not on list"); \
+} while (0)
+#define MUTEX_ASSERT_NOT_OWNED(m) do { \
+ if (((m)->m_qe.tqe_prev != NULL) || \
+ ((m)->m_qe.tqe_next != NULL)) \
+ PANIC("mutex is on list"); \
+} while (0)
+#else
+#define MUTEX_INIT_LINK(m)
+#define MUTEX_ASSERT_IS_OWNED(m)
+#define MUTEX_ASSERT_NOT_OWNED(m)
+#endif
+
+/*
+ * Prototypes
+ */
+int __pthread_mutex_init(pthread_mutex_t *mutex,
+ const pthread_mutexattr_t *mutex_attr);
+int __pthread_mutex_trylock(pthread_mutex_t *mutex);
+int __pthread_mutex_lock(pthread_mutex_t *mutex);
+int __pthread_mutex_timedlock(pthread_mutex_t *mutex,
+ const struct timespec *abstime);
+
+static int mutex_self_trylock(pthread_mutex_t);
+static int mutex_self_lock(pthread_mutex_t,
+ const struct timespec *abstime);
+static int mutex_unlock_common(pthread_mutex_t *);
+
+__weak_reference(__pthread_mutex_init, pthread_mutex_init);
+__weak_reference(__pthread_mutex_lock, pthread_mutex_lock);
+__weak_reference(__pthread_mutex_timedlock, pthread_mutex_timedlock);
+__weak_reference(__pthread_mutex_trylock, pthread_mutex_trylock);
+
+/* Single underscore versions provided for libc internal usage: */
+/* No difference between libc and application usage of these: */
+__weak_reference(_pthread_mutex_destroy, pthread_mutex_destroy);
+__weak_reference(_pthread_mutex_unlock, pthread_mutex_unlock);
+
+__weak_reference(_pthread_mutex_getprioceiling, pthread_mutex_getprioceiling);
+__weak_reference(_pthread_mutex_setprioceiling, pthread_mutex_setprioceiling);
+
+static int
+mutex_init(pthread_mutex_t *mutex,
+ const pthread_mutexattr_t *mutex_attr, int private)
+{
+ const struct pthread_mutex_attr *attr;
+ struct pthread_mutex *pmutex;
+
+ if (mutex_attr == NULL) {
+ attr = &_pthread_mutexattr_default;
+ } else {
+ attr = *mutex_attr;
+ if (attr->m_type < PTHREAD_MUTEX_ERRORCHECK ||
+ attr->m_type >= PTHREAD_MUTEX_TYPE_MAX)
+ return (EINVAL);
+ if (attr->m_protocol < PTHREAD_PRIO_NONE ||
+ attr->m_protocol > PTHREAD_PRIO_PROTECT)
+ return (EINVAL);
+ }
+
+ if ((pmutex = (pthread_mutex_t)
+ malloc(sizeof(struct pthread_mutex))) == NULL)
+ return (ENOMEM);
+
+ _thr_umtx_init(&pmutex->m_lock);
+ pmutex->m_type = attr->m_type;
+ pmutex->m_protocol = attr->m_protocol;
+ TAILQ_INIT(&pmutex->m_queue);
+ pmutex->m_owner = NULL;
+ pmutex->m_flags = attr->m_flags | MUTEX_FLAGS_INITED;
+ if (private)
+ pmutex->m_flags |= MUTEX_FLAGS_PRIVATE;
+ pmutex->m_count = 0;
+ pmutex->m_refcount = 0;
+ if (attr->m_protocol == PTHREAD_PRIO_PROTECT)
+ pmutex->m_prio = attr->m_ceiling;
+ else
+ pmutex->m_prio = -1;
+ pmutex->m_saved_prio = 0;
+ MUTEX_INIT_LINK(pmutex);
+ *mutex = pmutex;
+ return (0);
+}
+
+static int
+init_static(struct pthread *thread, pthread_mutex_t *mutex)
+{
+ int ret;
+
+ THR_LOCK_ACQUIRE(thread, &_mutex_static_lock);
+
+ if (*mutex == NULL)
+ ret = mutex_init(mutex, NULL, 0);
+ else
+ ret = 0;
+
+ THR_LOCK_RELEASE(thread, &_mutex_static_lock);
+
+ return (ret);
+}
+
+static int
+init_static_private(struct pthread *thread, pthread_mutex_t *mutex)
+{
+ int ret;
+
+ THR_LOCK_ACQUIRE(thread, &_mutex_static_lock);
+
+ if (*mutex == NULL)
+ ret = mutex_init(mutex, NULL, 1);
+ else
+ ret = 0;
+
+ THR_LOCK_RELEASE(thread, &_mutex_static_lock);
+
+ return (ret);
+}
+
+int
+_pthread_mutex_init(pthread_mutex_t *mutex,
+ const pthread_mutexattr_t *mutex_attr)
+{
+ return mutex_init(mutex, mutex_attr, 1);
+}
+
+int
+__pthread_mutex_init(pthread_mutex_t *mutex,
+ const pthread_mutexattr_t *mutex_attr)
+{
+ return mutex_init(mutex, mutex_attr, 0);
+}
+
+int
+_mutex_reinit(pthread_mutex_t *mutex)
+{
+ _thr_umtx_init(&(*mutex)->m_lock);
+ TAILQ_INIT(&(*mutex)->m_queue);
+ MUTEX_INIT_LINK(*mutex);
+ (*mutex)->m_owner = NULL;
+ (*mutex)->m_count = 0;
+ (*mutex)->m_refcount = 0;
+ (*mutex)->m_prio = 0;
+ (*mutex)->m_saved_prio = 0;
+ return (0);
+}
+
+void
+_mutex_fork(struct pthread *curthread)
+{
+ struct pthread_mutex *m;
+
+ /*
+ * Fix mutex ownership for child process.
+ * note that process shared mutex should not
+ * be inherited because owner is forking thread
+ * which is in parent process, they should be
+ * removed from the owned mutex list, current,
+ * process shared mutex is not supported, so I
+ * am not worried.
+ */
+ TAILQ_FOREACH(m, &curthread->mutexq, m_qe)
+ m->m_lock = (umtx_t)curthread->tid;
+}
+
+int
+_pthread_mutex_destroy(pthread_mutex_t *mutex)
+{
+ struct pthread *curthread = _get_curthread();
+ pthread_mutex_t m;
+ int ret = 0;
+
+ if (__predict_false(*mutex == NULL))
+ ret = EINVAL;
+ else {
+ /*
+ * Try to lock the mutex structure, we only need to
+ * try once, if failed, the mutex is in used.
+ */
+ ret = THR_UMTX_TRYLOCK(curthread, &(*mutex)->m_lock);
+ if (ret)
+ return (ret);
+
+ /*
+ * Check mutex other fields to see if this mutex is
+ * in use. Mostly for prority mutex types, or there
+ * are condition variables referencing it.
+ */
+ if (((*mutex)->m_owner != NULL) ||
+ (TAILQ_FIRST(&(*mutex)->m_queue) != NULL) ||
+ ((*mutex)->m_refcount != 0)) {
+ THR_UMTX_UNLOCK(curthread, &(*mutex)->m_lock);
+ ret = EBUSY;
+ } else {
+ /*
+ * Save a pointer to the mutex so it can be free'd
+ * and set the caller's pointer to NULL.
+ */
+ m = *mutex;
+ *mutex = NULL;
+
+ THR_UMTX_UNLOCK(curthread, &m->m_lock);
+
+ MUTEX_ASSERT_NOT_OWNED(m);
+ free(m);
+ }
+ }
+
+ return (ret);
+}
+
+static int
+mutex_trylock_common(struct pthread *curthread, pthread_mutex_t *mutex)
+{
+ struct pthread_mutex *m;
+ int ret;
+
+ m = *mutex;
+ ret = THR_UMTX_TRYLOCK(curthread, &m->m_lock);
+ if (ret == 0) {
+ m->m_owner = curthread;
+ /* Add to the list of owned mutexes. */
+ MUTEX_ASSERT_NOT_OWNED(m);
+ TAILQ_INSERT_TAIL(&curthread->mutexq, m, m_qe);
+ } else if (m->m_owner == curthread) {
+ ret = mutex_self_trylock(m);
+ } /* else {} */
+
+ return (ret);
+}
+
+int
+__pthread_mutex_trylock(pthread_mutex_t *mutex)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ /*
+ * If the mutex is statically initialized, perform the dynamic
+ * initialization:
+ */
+ if (__predict_false(*mutex == NULL)) {
+ ret = init_static(curthread, mutex);
+ if (__predict_false(ret))
+ return (ret);
+ }
+ return (mutex_trylock_common(curthread, mutex));
+}
+
+int
+_pthread_mutex_trylock(pthread_mutex_t *mutex)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ /*
+ * If the mutex is statically initialized, perform the dynamic
+ * initialization marking the mutex private (delete safe):
+ */
+ if (__predict_false(*mutex == NULL)) {
+ ret = init_static_private(curthread, mutex);
+ if (__predict_false(ret))
+ return (ret);
+ }
+ return (mutex_trylock_common(curthread, mutex));
+}
+
+static int
+mutex_lock_common(struct pthread *curthread, pthread_mutex_t *mutex,
+ const struct timespec * abstime)
+{
+ struct timespec ts, ts2;
+ struct pthread_mutex *m;
+ int ret;
+
+ m = *mutex;
+ ret = THR_UMTX_TRYLOCK(curthread, &m->m_lock);
+ if (ret == 0) {
+ m->m_owner = curthread;
+ /* Add to the list of owned mutexes: */
+ MUTEX_ASSERT_NOT_OWNED(m);
+ TAILQ_INSERT_TAIL(&curthread->mutexq, m, m_qe);
+ } else if (m->m_owner == curthread) {
+ ret = mutex_self_lock(m, abstime);
+ } else {
+ if (abstime == NULL) {
+ THR_UMTX_LOCK(curthread, &m->m_lock);
+ ret = 0;
+ } else if (__predict_false(
+ abstime->tv_sec < 0 || abstime->tv_nsec < 0 ||
+ abstime->tv_nsec >= 1000000000)) {
+ ret = EINVAL;
+ } else {
+ clock_gettime(CLOCK_REALTIME, &ts);
+ TIMESPEC_SUB(&ts2, abstime, &ts);
+ ret = THR_UMTX_TIMEDLOCK(curthread, &m->m_lock, &ts2);
+ /*
+ * Timed out wait is not restarted if
+ * it was interrupted, not worth to do it.
+ */
+ if (ret == EINTR)
+ ret = ETIMEDOUT;
+ }
+ if (ret == 0) {
+ m->m_owner = curthread;
+ /* Add to the list of owned mutexes: */
+ MUTEX_ASSERT_NOT_OWNED(m);
+ TAILQ_INSERT_TAIL(&curthread->mutexq, m, m_qe);
+ }
+ }
+ return (ret);
+}
+
+int
+__pthread_mutex_lock(pthread_mutex_t *m)
+{
+ struct pthread *curthread;
+ int ret;
+
+ _thr_check_init();
+
+ curthread = _get_curthread();
+
+ /*
+ * If the mutex is statically initialized, perform the dynamic
+ * initialization:
+ */
+ if (__predict_false(*m == NULL)) {
+ ret = init_static(curthread, m);
+ if (__predict_false(ret))
+ return (ret);
+ }
+ return (mutex_lock_common(curthread, m, NULL));
+}
+
+int
+_pthread_mutex_lock(pthread_mutex_t *m)
+{
+ struct pthread *curthread;
+ int ret;
+
+ _thr_check_init();
+
+ curthread = _get_curthread();
+
+ /*
+ * If the mutex is statically initialized, perform the dynamic
+ * initialization marking it private (delete safe):
+ */
+ if (__predict_false(*m == NULL)) {
+ ret = init_static_private(curthread, m);
+ if (__predict_false(ret))
+ return (ret);
+ }
+ return (mutex_lock_common(curthread, m, NULL));
+}
+
+int
+__pthread_mutex_timedlock(pthread_mutex_t *m, const struct timespec *abstime)
+{
+ struct pthread *curthread;
+ int ret;
+
+ _thr_check_init();
+
+ curthread = _get_curthread();
+
+ /*
+ * If the mutex is statically initialized, perform the dynamic
+ * initialization:
+ */
+ if (__predict_false(*m == NULL)) {
+ ret = init_static(curthread, m);
+ if (__predict_false(ret))
+ return (ret);
+ }
+ return (mutex_lock_common(curthread, m, abstime));
+}
+
+int
+_pthread_mutex_timedlock(pthread_mutex_t *m, const struct timespec *abstime)
+{
+ struct pthread *curthread;
+ int ret;
+
+ _thr_check_init();
+
+ curthread = _get_curthread();
+
+ /*
+ * If the mutex is statically initialized, perform the dynamic
+ * initialization marking it private (delete safe):
+ */
+ if (__predict_false(*m == NULL)) {
+ ret = init_static_private(curthread, m);
+ if (__predict_false(ret))
+ return (ret);
+ }
+ return (mutex_lock_common(curthread, m, abstime));
+}
+
+int
+_pthread_mutex_unlock(pthread_mutex_t *m)
+{
+ return (mutex_unlock_common(m));
+}
+
+int
+_mutex_cv_lock(pthread_mutex_t *m, int count)
+{
+ int ret;
+
+ ret = mutex_lock_common(_get_curthread(), m, NULL);
+ if (ret == 0) {
+ (*m)->m_refcount--;
+ (*m)->m_count += count;
+ }
+ return (ret);
+}
+
+static int
+mutex_self_trylock(pthread_mutex_t m)
+{
+ int ret;
+
+ switch (m->m_type) {
+ case PTHREAD_MUTEX_ERRORCHECK:
+ case PTHREAD_MUTEX_NORMAL:
+ ret = EBUSY;
+ break;
+
+ case PTHREAD_MUTEX_RECURSIVE:
+ /* Increment the lock count: */
+ if (m->m_count + 1 > 0) {
+ m->m_count++;
+ ret = 0;
+ } else
+ ret = EAGAIN;
+ break;
+
+ default:
+ /* Trap invalid mutex types; */
+ ret = EINVAL;
+ }
+
+ return (ret);
+}
+
+static int
+mutex_self_lock(pthread_mutex_t m, const struct timespec *abstime)
+{
+ struct timespec ts1, ts2;
+ int ret;
+
+ switch (m->m_type) {
+ case PTHREAD_MUTEX_ERRORCHECK:
+ if (abstime) {
+ clock_gettime(CLOCK_REALTIME, &ts1);
+ TIMESPEC_SUB(&ts2, abstime, &ts1);
+ __sys_nanosleep(&ts2, NULL);
+ ret = ETIMEDOUT;
+ } else {
+ /*
+ * POSIX specifies that mutexes should return
+ * EDEADLK if a recursive lock is detected.
+ */
+ ret = EDEADLK;
+ }
+ break;
+
+ case PTHREAD_MUTEX_NORMAL:
+ /*
+ * What SS2 define as a 'normal' mutex. Intentionally
+ * deadlock on attempts to get a lock you already own.
+ */
+ ret = 0;
+ if (abstime) {
+ clock_gettime(CLOCK_REALTIME, &ts1);
+ TIMESPEC_SUB(&ts2, abstime, &ts1);
+ __sys_nanosleep(&ts2, NULL);
+ ret = ETIMEDOUT;
+ } else {
+ ts1.tv_sec = 30;
+ ts1.tv_nsec = 0;
+ for (;;)
+ __sys_nanosleep(&ts1, NULL);
+ }
+ break;
+
+ case PTHREAD_MUTEX_RECURSIVE:
+ /* Increment the lock count: */
+ if (m->m_count + 1 > 0) {
+ m->m_count++;
+ ret = 0;
+ } else
+ ret = EAGAIN;
+ break;
+
+ default:
+ /* Trap invalid mutex types; */
+ ret = EINVAL;
+ }
+
+ return (ret);
+}
+
+static int
+mutex_unlock_common(pthread_mutex_t *mutex)
+{
+ struct pthread *curthread = _get_curthread();
+ struct pthread_mutex *m;
+
+ if (__predict_false((m = *mutex) == NULL))
+ return (EINVAL);
+
+ /*
+ * Check if the running thread is not the owner of the mutex.
+ */
+ if (__predict_false(m->m_owner != curthread))
+ return (EPERM);
+
+ if (__predict_false(
+ m->m_type == PTHREAD_MUTEX_RECURSIVE &&
+ m->m_count > 0)) {
+ m->m_count--;
+ } else {
+ m->m_owner = NULL;
+ /* Remove the mutex from the threads queue. */
+ MUTEX_ASSERT_IS_OWNED(m);
+ TAILQ_REMOVE(&curthread->mutexq, m, m_qe);
+ MUTEX_INIT_LINK(m);
+ THR_UMTX_UNLOCK(curthread, &m->m_lock);
+ }
+ return (0);
+}
+
+int
+_mutex_cv_unlock(pthread_mutex_t *mutex, int *count)
+{
+ struct pthread *curthread = _get_curthread();
+ struct pthread_mutex *m;
+
+ if (__predict_false((m = *mutex) == NULL))
+ return (EINVAL);
+
+ /*
+ * Check if the running thread is not the owner of the mutex.
+ */
+ if (__predict_false(m->m_owner != curthread))
+ return (EPERM);
+
+ /*
+ * Clear the count in case this is a recursive mutex.
+ */
+ *count = m->m_count;
+ m->m_refcount++;
+ m->m_count = 0;
+ m->m_owner = NULL;
+ /* Remove the mutex from the threads queue. */
+ MUTEX_ASSERT_IS_OWNED(m);
+ TAILQ_REMOVE(&curthread->mutexq, m, m_qe);
+ MUTEX_INIT_LINK(m);
+ THR_UMTX_UNLOCK(curthread, &m->m_lock);
+ return (0);
+}
+
+void
+_mutex_unlock_private(pthread_t pthread)
+{
+ struct pthread_mutex *m, *m_next;
+
+ for (m = TAILQ_FIRST(&pthread->mutexq); m != NULL; m = m_next) {
+ m_next = TAILQ_NEXT(m, m_qe);
+ if ((m->m_flags & MUTEX_FLAGS_PRIVATE) != 0)
+ _pthread_mutex_unlock(&m);
+ }
+}
+
+int
+_pthread_mutex_getprioceiling(pthread_mutex_t *mutex,
+ int *prioceiling)
+{
+ int ret;
+
+ if (*mutex == NULL)
+ ret = EINVAL;
+ else if ((*mutex)->m_protocol != PTHREAD_PRIO_PROTECT)
+ ret = EINVAL;
+ else {
+ *prioceiling = (*mutex)->m_prio;
+ ret = 0;
+ }
+
+ return(ret);
+}
+
+int
+_pthread_mutex_setprioceiling(pthread_mutex_t *mutex,
+ int prioceiling, int *old_ceiling)
+{
+ int ret = 0;
+ int tmp;
+
+ if (*mutex == NULL)
+ ret = EINVAL;
+ else if ((*mutex)->m_protocol != PTHREAD_PRIO_PROTECT)
+ ret = EINVAL;
+ else if ((ret = _pthread_mutex_lock(mutex)) == 0) {
+ tmp = (*mutex)->m_prio;
+ (*mutex)->m_prio = prioceiling;
+ ret = _pthread_mutex_unlock(mutex);
+
+ /* Return the old ceiling. */
+ *old_ceiling = tmp;
+ }
+ return(ret);
+}
diff --git a/lib/libthr/thread/thr_mutex_prioceiling.c b/lib/libthr/thread/thr_mutex_prioceiling.c
new file mode 100644
index 0000000..edea124
--- /dev/null
+++ b/lib/libthr/thread/thr_mutex_prioceiling.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+__weak_reference(_pthread_mutexattr_getprioceiling, pthread_mutexattr_getprioceiling);
+__weak_reference(_pthread_mutexattr_setprioceiling, pthread_mutexattr_setprioceiling);
+__weak_reference(_pthread_mutex_getprioceiling, pthread_mutex_getprioceiling);
+__weak_reference(_pthread_mutex_setprioceiling, pthread_mutex_setprioceiling);
+
+int
+_pthread_mutexattr_getprioceiling(pthread_mutexattr_t *mattr, int *prioceiling)
+{
+ int ret = 0;
+
+ if ((mattr == NULL) || (*mattr == NULL))
+ ret = EINVAL;
+ else if ((*mattr)->m_protocol != PTHREAD_PRIO_PROTECT)
+ ret = EINVAL;
+ else
+ *prioceiling = (*mattr)->m_ceiling;
+
+ return(ret);
+}
+
+int
+_pthread_mutexattr_setprioceiling(pthread_mutexattr_t *mattr, int prioceiling)
+{
+ int ret = 0;
+
+ if ((mattr == NULL) || (*mattr == NULL))
+ ret = EINVAL;
+ else if ((*mattr)->m_protocol != PTHREAD_PRIO_PROTECT)
+ ret = EINVAL;
+ else
+ (*mattr)->m_ceiling = prioceiling;
+
+ return(ret);
+}
+
+int
+_pthread_mutex_getprioceiling(pthread_mutex_t *mutex,
+ int *prioceiling)
+{
+ int ret;
+
+ if ((mutex == NULL) || (*mutex == NULL))
+ ret = EINVAL;
+ else if ((*mutex)->m_protocol != PTHREAD_PRIO_PROTECT)
+ ret = EINVAL;
+ else
+ ret = (*mutex)->m_prio;
+
+ return(ret);
+}
+
+int
+_pthread_mutex_setprioceiling(pthread_mutex_t *mutex,
+ int prioceiling, int *old_ceiling)
+{
+ int ret = 0;
+ int tmp;
+
+ if ((mutex == NULL) || (*mutex == NULL))
+ ret = EINVAL;
+ else if ((*mutex)->m_protocol != PTHREAD_PRIO_PROTECT)
+ ret = EINVAL;
+ /* Lock the mutex: */
+ else if ((ret = pthread_mutex_lock(mutex)) == 0) {
+ tmp = (*mutex)->m_prio;
+ /* Set the new ceiling: */
+ (*mutex)->m_prio = prioceiling;
+
+ /* Unlock the mutex: */
+ ret = pthread_mutex_unlock(mutex);
+
+ /* Return the old ceiling: */
+ *old_ceiling = tmp;
+ }
+ return(ret);
+}
diff --git a/lib/libthr/thread/thr_mutex_protocol.c b/lib/libthr/thread/thr_mutex_protocol.c
new file mode 100644
index 0000000..526cbe0
--- /dev/null
+++ b/lib/libthr/thread/thr_mutex_protocol.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+__weak_reference(_pthread_mutexattr_getprotocol, pthread_mutexattr_getprotocol);
+__weak_reference(_pthread_mutexattr_setprotocol, pthread_mutexattr_setprotocol);
+
+int
+_pthread_mutexattr_getprotocol(pthread_mutexattr_t *mattr, int *protocol)
+{
+ int ret = 0;
+
+ if ((mattr == NULL) || (*mattr == NULL))
+ ret = EINVAL;
+ else
+ *protocol = (*mattr)->m_protocol;
+
+ return(ret);
+}
+
+int
+_pthread_mutexattr_setprotocol(pthread_mutexattr_t *mattr, int protocol)
+{
+ int ret = 0;
+
+ if ((mattr == NULL) || (*mattr == NULL) ||
+ (protocol < PTHREAD_PRIO_NONE) || (protocol > PTHREAD_PRIO_PROTECT))
+ ret = EINVAL;
+ else {
+ (*mattr)->m_protocol = protocol;
+ (*mattr)->m_ceiling = THR_MAX_PRIORITY;
+ }
+ return(ret);
+}
+
diff --git a/lib/libthr/thread/thr_mutexattr.c b/lib/libthr/thread/thr_mutexattr.c
new file mode 100644
index 0000000..7244c58
--- /dev/null
+++ b/lib/libthr/thread/thr_mutexattr.c
@@ -0,0 +1,262 @@
+/*
+ * Copyright (c) 1996 Jeffrey Hsu <hsu@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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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) 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+#include <pthread_np.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+__weak_reference(_pthread_mutexattr_init, pthread_mutexattr_init);
+__weak_reference(_pthread_mutexattr_setkind_np, pthread_mutexattr_setkind_np);
+__weak_reference(_pthread_mutexattr_getkind_np, pthread_mutexattr_getkind_np);
+__weak_reference(_pthread_mutexattr_gettype, pthread_mutexattr_gettype);
+__weak_reference(_pthread_mutexattr_settype, pthread_mutexattr_settype);
+__weak_reference(_pthread_mutexattr_destroy, pthread_mutexattr_destroy);
+__weak_reference(_pthread_mutexattr_getpshared, pthread_mutexattr_getpshared);
+__weak_reference(_pthread_mutexattr_setpshared, pthread_mutexattr_setpshared);
+__weak_reference(_pthread_mutexattr_getprotocol, pthread_mutexattr_getprotocol);
+__weak_reference(_pthread_mutexattr_setprotocol, pthread_mutexattr_setprotocol);
+__weak_reference(_pthread_mutexattr_getprioceiling, pthread_mutexattr_getprioceiling);
+__weak_reference(_pthread_mutexattr_setprioceiling, pthread_mutexattr_setprioceiling);
+
+int
+_pthread_mutexattr_init(pthread_mutexattr_t *attr)
+{
+ int ret;
+ pthread_mutexattr_t pattr;
+
+ if ((pattr = (pthread_mutexattr_t)
+ malloc(sizeof(struct pthread_mutex_attr))) == NULL) {
+ ret = ENOMEM;
+ } else {
+ memcpy(pattr, &_pthread_mutexattr_default,
+ sizeof(struct pthread_mutex_attr));
+ *attr = pattr;
+ ret = 0;
+ }
+ return (ret);
+}
+
+int
+_pthread_mutexattr_setkind_np(pthread_mutexattr_t *attr, int kind)
+{
+ int ret;
+ if (attr == NULL || *attr == NULL) {
+ errno = EINVAL;
+ ret = -1;
+ } else {
+ (*attr)->m_type = kind;
+ ret = 0;
+ }
+ return(ret);
+}
+
+int
+_pthread_mutexattr_getkind_np(pthread_mutexattr_t attr)
+{
+ int ret;
+ if (attr == NULL) {
+ errno = EINVAL;
+ ret = -1;
+ } else {
+ ret = attr->m_type;
+ }
+ return(ret);
+}
+
+int
+_pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
+{
+ int ret;
+ if (attr == NULL || *attr == NULL || type >= PTHREAD_MUTEX_TYPE_MAX) {
+ errno = EINVAL;
+ ret = -1;
+ } else {
+ (*attr)->m_type = type;
+ ret = 0;
+ }
+ return(ret);
+}
+
+int
+_pthread_mutexattr_gettype(pthread_mutexattr_t *attr, int *type)
+{
+ int ret;
+
+ if (attr == NULL || *attr == NULL || (*attr)->m_type >=
+ PTHREAD_MUTEX_TYPE_MAX) {
+ ret = EINVAL;
+ } else {
+ *type = (*attr)->m_type;
+ ret = 0;
+ }
+ return ret;
+}
+
+int
+_pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
+{
+ int ret;
+ if (attr == NULL || *attr == NULL) {
+ ret = EINVAL;
+ } else {
+ free(*attr);
+ *attr = NULL;
+ ret = 0;
+ }
+ return(ret);
+}
+
+int
+_pthread_mutexattr_getpshared(const pthread_mutexattr_t *attr,
+ int *pshared)
+{
+
+ if (attr == NULL || *attr == NULL)
+ return (EINVAL);
+
+ *pshared = PTHREAD_PROCESS_PRIVATE;
+ return (0);
+}
+
+int
+_pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared)
+{
+
+ if (attr == NULL || *attr == NULL)
+ return (EINVAL);
+
+ /* Only PTHREAD_PROCESS_PRIVATE is supported. */
+ if (pshared != PTHREAD_PROCESS_PRIVATE)
+ return (EINVAL);
+
+ return (0);
+}
+
+int
+_pthread_mutexattr_getprotocol(pthread_mutexattr_t *mattr, int *protocol)
+{
+ int ret = 0;
+
+ if ((mattr == NULL) || (*mattr == NULL))
+ ret = EINVAL;
+ else
+ *protocol = (*mattr)->m_protocol;
+
+ return(ret);
+}
+
+int
+_pthread_mutexattr_setprotocol(pthread_mutexattr_t *mattr, int protocol)
+{
+ int ret = 0;
+
+ if ((mattr == NULL) || (*mattr == NULL) ||
+ (protocol < PTHREAD_PRIO_NONE) || (protocol > PTHREAD_PRIO_PROTECT))
+ ret = EINVAL;
+ else {
+ (*mattr)->m_protocol = protocol;
+ (*mattr)->m_ceiling = THR_MAX_RR_PRIORITY;
+ }
+ return(ret);
+}
+
+int
+_pthread_mutexattr_getprioceiling(pthread_mutexattr_t *mattr, int *prioceiling)
+{
+ int ret = 0;
+
+ if ((mattr == NULL) || (*mattr == NULL))
+ ret = EINVAL;
+ else if ((*mattr)->m_protocol != PTHREAD_PRIO_PROTECT)
+ ret = EINVAL;
+ else
+ *prioceiling = (*mattr)->m_ceiling;
+
+ return(ret);
+}
+
+int
+_pthread_mutexattr_setprioceiling(pthread_mutexattr_t *mattr, int prioceiling)
+{
+ int ret = 0;
+
+ if ((mattr == NULL) || (*mattr == NULL))
+ ret = EINVAL;
+ else if ((*mattr)->m_protocol != PTHREAD_PRIO_PROTECT)
+ ret = EINVAL;
+ else
+ (*mattr)->m_ceiling = prioceiling;
+
+ return(ret);
+}
+
diff --git a/lib/libthr/thread/thr_once.c b/lib/libthr/thread/thr_once.c
new file mode 100644
index 0000000..4fe392c
--- /dev/null
+++ b/lib/libthr/thread/thr_once.c
@@ -0,0 +1,99 @@
+/*
+ * 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 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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, 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$
+ *
+ */
+
+#include "namespace.h"
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+__weak_reference(_pthread_once, pthread_once);
+
+#define ONCE_NEVER_DONE PTHREAD_NEEDS_INIT
+#define ONCE_DONE PTHREAD_DONE_INIT
+#define ONCE_IN_PROGRESS 0x02
+#define ONCE_MASK 0x03
+
+static pthread_mutex_t _thr_once_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t _thr_once_cv = PTHREAD_COND_INITIALIZER;
+
+/*
+ * POSIX:
+ * The pthread_once() function is not a cancellation point. However,
+ * if init_routine is a cancellation point and is canceled, the effect
+ * on once_control shall be as if pthread_once() was never called.
+ */
+
+static void
+once_cancel_handler(void *arg)
+{
+ pthread_once_t *once_control = arg;
+
+ _pthread_mutex_lock(&_thr_once_lock);
+ once_control->state = ONCE_NEVER_DONE;
+ _pthread_mutex_unlock(&_thr_once_lock);
+ _pthread_cond_broadcast(&_thr_once_cv);
+}
+
+int
+_pthread_once(pthread_once_t *once_control, void (*init_routine) (void))
+{
+ int wakeup = 0;
+
+ if (once_control->state == ONCE_DONE)
+ return (0);
+ _pthread_mutex_lock(&_thr_once_lock);
+ while (*(volatile int *)&(once_control->state) == ONCE_IN_PROGRESS)
+ _pthread_cond_wait(&_thr_once_cv, &_thr_once_lock);
+ /*
+ * If previous thread was canceled, then the state still
+ * could be ONCE_NEVER_DONE, we need to check it again.
+ */
+ if (*(volatile int *)&(once_control->state) == ONCE_NEVER_DONE) {
+ once_control->state = ONCE_IN_PROGRESS;
+ _pthread_mutex_unlock(&_thr_once_lock);
+ _pthread_cleanup_push(once_cancel_handler, once_control);
+ init_routine();
+ _pthread_cleanup_pop(0);
+ _pthread_mutex_lock(&_thr_once_lock);
+ once_control->state = ONCE_DONE;
+ wakeup = 1;
+ }
+ _pthread_mutex_unlock(&_thr_once_lock);
+ if (wakeup)
+ _pthread_cond_broadcast(&_thr_once_cv);
+ return (0);
+}
+
+void
+_thr_once_init()
+{
+ _thr_once_lock = PTHREAD_MUTEX_INITIALIZER;
+ _thr_once_cv = PTHREAD_COND_INITIALIZER;
+}
diff --git a/lib/libthr/thread/thr_printf.c b/lib/libthr/thread/thr_printf.c
new file mode 100644
index 0000000..7d32ae7
--- /dev/null
+++ b/lib/libthr/thread/thr_printf.c
@@ -0,0 +1,135 @@
+/*-
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <pthread.h>
+
+#include "thr_private.h"
+
+static void pchar(int fd, char c);
+static void pstr(int fd, const char *s);
+
+/*
+ * Write formatted output to stdout, in a thread-safe manner.
+ *
+ * Recognises the following conversions:
+ * %c -> char
+ * %d -> signed int (base 10)
+ * %s -> string
+ * %u -> unsigned int (base 10)
+ * %x -> unsigned int (base 16)
+ * %p -> unsigned int (base 16)
+ */
+void
+_thread_printf(int fd, const char *fmt, ...)
+{
+ static const char digits[16] = "0123456789abcdef";
+ va_list ap;
+ char buf[20];
+ char *s;
+ unsigned long r, u;
+ int c;
+ long d;
+ int islong;
+
+ va_start(ap, fmt);
+ while ((c = *fmt++)) {
+ islong = 0;
+ if (c == '%') {
+next: c = *fmt++;
+ if (c == '\0')
+ goto out;
+ switch (c) {
+ case 'c':
+ pchar(fd, va_arg(ap, int));
+ continue;
+ case 's':
+ pstr(fd, va_arg(ap, char *));
+ continue;
+ case 'l':
+ islong = 1;
+ goto next;
+ case 'p':
+ islong = 1;
+ case 'd':
+ case 'u':
+ case 'x':
+ r = ((c == 'u') || (c == 'd')) ? 10 : 16;
+ if (c == 'd') {
+ if (islong)
+ d = va_arg(ap, unsigned long);
+ else
+ d = va_arg(ap, unsigned);
+ if (d < 0) {
+ pchar(fd, '-');
+ u = (unsigned long)(d * -1);
+ } else
+ u = (unsigned long)d;
+ } else {
+ if (islong)
+ u = va_arg(ap, unsigned long);
+ else
+ u = va_arg(ap, unsigned);
+ }
+ s = buf;
+ do {
+ *s++ = digits[u % r];
+ } while (u /= r);
+ while (--s >= buf)
+ pchar(fd, *s);
+ continue;
+ }
+ }
+ pchar(fd, c);
+ }
+out:
+ va_end(ap);
+}
+
+/*
+ * Write a single character to stdout, in a thread-safe manner.
+ */
+static void
+pchar(int fd, char c)
+{
+
+ __sys_write(fd, &c, 1);
+}
+
+/*
+ * Write a string to stdout, in a thread-safe manner.
+ */
+static void
+pstr(int fd, const char *s)
+{
+
+ __sys_write(fd, s, strlen(s));
+}
+
diff --git a/lib/libthr/thread/thr_private.h b/lib/libthr/thread/thr_private.h
new file mode 100644
index 0000000..0453864
--- /dev/null
+++ b/lib/libthr/thread/thr_private.h
@@ -0,0 +1,741 @@
+/*
+ * Copyright (C) 2005 Daniel M. Eischen <deischen@freebsd.org>
+ * Copyright (c) 2005 David Xu <davidxu@freebsd.org>
+ * Copyright (c) 1995-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 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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, 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 _THR_PRIVATE_H
+#define _THR_PRIVATE_H
+
+/*
+ * Include files.
+ */
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/cdefs.h>
+#include <sys/queue.h>
+#include <machine/atomic.h>
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <ucontext.h>
+#include <sys/thr.h>
+#include <pthread.h>
+
+#ifndef __hidden
+#define __hidden __attribute__((visibility("hidden")))
+#endif
+
+#include "pthread_md.h"
+#include "thr_umtx.h"
+#include "thread_db.h"
+
+typedef TAILQ_HEAD(pthreadlist, pthread) pthreadlist;
+typedef TAILQ_HEAD(atfork_head, pthread_atfork) atfork_head;
+
+/* Signal to do cancellation */
+#define SIGCANCEL 32
+
+/*
+ * Kernel fatal error handler macro.
+ */
+#define PANIC(string) _thread_exit(__FILE__,__LINE__,string)
+
+/* Output debug messages like this: */
+#define stdout_debug(args...) _thread_printf(STDOUT_FILENO, ##args)
+#define stderr_debug(args...) _thread_printf(STDOUT_FILENO, ##args)
+
+#ifdef _PTHREADS_INVARIANTS
+#define THR_ASSERT(cond, msg) do { \
+ if (__predict_false(!(cond))) \
+ PANIC(msg); \
+} while (0)
+#else
+#define THR_ASSERT(cond, msg)
+#endif
+
+#ifdef PIC
+# define STATIC_LIB_REQUIRE(name)
+#else
+# define STATIC_LIB_REQUIRE(name) __asm (".globl " #name)
+#endif
+
+#define TIMESPEC_ADD(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 >= 1000000000) { \
+ (dst)->tv_sec++; \
+ (dst)->tv_nsec -= 1000000000; \
+ } \
+ } while (0)
+
+#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)
+
+struct pthread_mutex {
+ /*
+ * Lock for accesses to this structure.
+ */
+ volatile umtx_t m_lock;
+ enum pthread_mutextype m_type;
+ int m_protocol;
+ TAILQ_HEAD(mutex_head, pthread) m_queue;
+ struct pthread *m_owner;
+ int m_flags;
+ int m_count;
+ int m_refcount;
+
+ /*
+ * Used for priority inheritence and protection.
+ *
+ * m_prio - For priority inheritence, the highest active
+ * priority (threads locking the mutex inherit
+ * this priority). For priority protection, the
+ * ceiling priority of this mutex.
+ * m_saved_prio - mutex owners inherited priority before
+ * taking the mutex, restored when the owner
+ * unlocks the mutex.
+ */
+ int m_prio;
+ int m_saved_prio;
+
+ /*
+ * Link for list of all mutexes a thread currently owns.
+ */
+ TAILQ_ENTRY(pthread_mutex) m_qe;
+};
+
+/*
+ * Flags for mutexes.
+ */
+#define MUTEX_FLAGS_PRIVATE 0x01
+#define MUTEX_FLAGS_INITED 0x02
+#define MUTEX_FLAGS_BUSY 0x04
+
+struct pthread_mutex_attr {
+ enum pthread_mutextype m_type;
+ int m_protocol;
+ int m_ceiling;
+ int m_flags;
+};
+
+#define PTHREAD_MUTEXATTR_STATIC_INITIALIZER \
+ { PTHREAD_MUTEX_DEFAULT, PTHREAD_PRIO_NONE, 0, MUTEX_FLAGS_PRIVATE }
+
+struct pthread_cond {
+ /*
+ * Lock for accesses to this structure.
+ */
+ volatile umtx_t c_lock;
+ volatile umtx_t c_seqno;
+ volatile int c_waiters;
+ volatile int c_wakeups;
+ int c_pshared;
+ int c_clockid;
+};
+
+struct pthread_cond_attr {
+ int c_pshared;
+ int c_clockid;
+};
+
+struct pthread_barrier {
+ volatile umtx_t b_lock;
+ volatile umtx_t b_cycle;
+ volatile int b_count;
+ volatile int b_waiters;
+};
+
+struct pthread_barrierattr {
+ int pshared;
+};
+
+struct pthread_spinlock {
+ volatile umtx_t s_lock;
+};
+
+/*
+ * Flags for condition variables.
+ */
+#define COND_FLAGS_PRIVATE 0x01
+#define COND_FLAGS_INITED 0x02
+#define COND_FLAGS_BUSY 0x04
+
+/*
+ * Cleanup definitions.
+ */
+struct pthread_cleanup {
+ struct pthread_cleanup *next;
+ void (*routine)(void *args);
+ void *routine_arg;
+ int onstack;
+};
+
+#define THR_CLEANUP_PUSH(td, func, arg) { \
+ struct pthread_cleanup __cup; \
+ \
+ __cup.routine = func; \
+ __cup.routine_arg = arg; \
+ __cup.onstack = 1; \
+ __cup.next = (td)->cleanup; \
+ (td)->cleanup = &__cup;
+
+#define THR_CLEANUP_POP(td, exec) \
+ (td)->cleanup = __cup.next; \
+ if ((exec) != 0) \
+ __cup.routine(__cup.routine_arg); \
+}
+
+struct pthread_atfork {
+ TAILQ_ENTRY(pthread_atfork) qe;
+ void (*prepare)(void);
+ void (*parent)(void);
+ void (*child)(void);
+};
+
+struct pthread_attr {
+ int sched_policy;
+ int sched_inherit;
+ int prio;
+ int suspend;
+#define THR_STACK_USER 0x100 /* 0xFF reserved for <pthread.h> */
+ int flags;
+ void *stackaddr_attr;
+ size_t stacksize_attr;
+ size_t guardsize_attr;
+};
+
+/*
+ * Thread creation state attributes.
+ */
+#define THR_CREATE_RUNNING 0
+#define THR_CREATE_SUSPENDED 1
+
+/*
+ * Miscellaneous definitions.
+ */
+#define THR_STACK_DEFAULT (sizeof(void *) / 4 * 1024 * 1024)
+
+/*
+ * Maximum size of initial thread's stack. This perhaps deserves to be larger
+ * than the stacks of other threads, since many applications are likely to run
+ * almost entirely on this stack.
+ */
+#define THR_STACK_INITIAL (THR_STACK_DEFAULT * 2)
+
+/*
+ * Define priorities returned by kernel.
+ */
+#define THR_MIN_PRIORITY (_thr_priorities[SCHED_OTHER-1].pri_min)
+#define THR_MAX_PRIORITY (_thr_priorities[SCHED_OTHER-1].pri_min)
+#define THR_DEF_PRIORITY (_thr_priorities[SCHED_OTHER-1].pri_default)
+
+#define THR_MIN_RR_PRIORITY (_thr_priorities[SCHED_RR-1].pri_min)
+#define THR_MAX_RR_PRIORITY (_thr_priorities[SCHED_RR-1].pri_max)
+#define THR_DEF_RR_PRIORITY (_thr_priorities[SCHED_RR-1].pri_default)
+
+/* XXX The SCHED_FIFO should have same priority range as SCHED_RR */
+#define THR_MIN_FIFO_PRIORITY (_thr_priorities[SCHED_FIFO_1].pri_min)
+#define THR_MAX_FIFO_PRIORITY (_thr_priorities[SCHED_FIFO-1].pri_min)
+#define THR_DEF_FIFO_PRIORITY (_thr_priorities[SCHED_FIFO-1].pri_default)
+
+struct pthread_prio {
+ int pri_min;
+ int pri_max;
+ int pri_default;
+};
+
+struct pthread_rwlockattr {
+ int pshared;
+};
+
+struct pthread_rwlock {
+ pthread_mutex_t lock; /* monitor lock */
+ pthread_cond_t read_signal;
+ pthread_cond_t write_signal;
+ int state; /* 0 = idle >0 = # of readers -1 = writer */
+ int blocked_writers;
+};
+
+/*
+ * Thread states.
+ */
+enum pthread_state {
+ PS_RUNNING,
+ PS_DEAD
+};
+
+struct pthread_specific_elem {
+ const void *data;
+ int seqno;
+};
+
+struct pthread_key {
+ volatile int allocated;
+ volatile int count;
+ int seqno;
+ void (*destructor)(void *);
+};
+
+/*
+ * Thread structure.
+ */
+struct pthread {
+ /* Kernel thread id. */
+ long tid;
+#define TID_TERMINATED 1
+
+ /*
+ * Lock for accesses to this thread structure.
+ */
+ umtx_t lock;
+
+ /* Internal condition variable cycle number. */
+ umtx_t cycle;
+
+ /* How many low level locks the thread held. */
+ int locklevel;
+
+ /*
+ * Set to non-zero when this thread has entered a critical
+ * region. We allow for recursive entries into critical regions.
+ */
+ int critical_count;
+
+ /* Signal blocked counter. */
+ int sigblock;
+
+ /* Queue entry for list of all threads. */
+ TAILQ_ENTRY(pthread) tle; /* link for all threads in process */
+
+ /* Queue entry for GC lists. */
+ TAILQ_ENTRY(pthread) gcle;
+
+ /* Hash queue entry. */
+ LIST_ENTRY(pthread) hle;
+
+ /* Threads reference count. */
+ int refcount;
+
+ /*
+ * Thread start routine, argument, stack pointer and thread
+ * attributes.
+ */
+ void *(*start_routine)(void *);
+ void *arg;
+ struct pthread_attr attr;
+
+ /*
+ * Cancelability flags
+ */
+#define THR_CANCEL_DISABLE 0x0001
+#define THR_CANCEL_EXITING 0x0002
+#define THR_CANCEL_AT_POINT 0x0004
+#define THR_CANCEL_NEEDED 0x0008
+#define SHOULD_CANCEL(val) \
+ (((val) & (THR_CANCEL_DISABLE | THR_CANCEL_EXITING | \
+ THR_CANCEL_NEEDED)) == THR_CANCEL_NEEDED)
+
+#define SHOULD_ASYNC_CANCEL(val) \
+ (((val) & (THR_CANCEL_DISABLE | THR_CANCEL_EXITING | \
+ THR_CANCEL_NEEDED | THR_CANCEL_AT_POINT)) == \
+ (THR_CANCEL_NEEDED | THR_CANCEL_AT_POINT))
+ int cancelflags;
+
+ /* Thread temporary signal mask. */
+ sigset_t sigmask;
+
+ /* Thread state: */
+ umtx_t state;
+
+ /*
+ * Error variable used instead of errno. The function __error()
+ * returns a pointer to this.
+ */
+ int error;
+
+ /*
+ * The joiner is the thread that is joining to this thread. The
+ * join status keeps track of a join operation to another thread.
+ */
+ struct pthread *joiner;
+
+ /*
+ * The current thread can belong to a priority mutex queue.
+ * This is the synchronization queue link.
+ */
+ TAILQ_ENTRY(pthread) sqe;
+
+ /* Miscellaneous flags; only set with scheduling lock held. */
+ int flags;
+#define THR_FLAGS_PRIVATE 0x0001
+#define THR_FLAGS_NEED_SUSPEND 0x0002 /* thread should be suspended */
+#define THR_FLAGS_SUSPENDED 0x0004 /* thread is suspended */
+
+ /* Thread list flags; only set with thread list lock held. */
+ int tlflags;
+#define TLFLAGS_GC_SAFE 0x0001 /* thread safe for cleaning */
+#define TLFLAGS_IN_TDLIST 0x0002 /* thread in all thread list */
+#define TLFLAGS_IN_GCLIST 0x0004 /* thread in gc list */
+#define TLFLAGS_DETACHED 0x0008 /* thread is detached */
+
+ /*
+ * Base priority is the user setable and retrievable priority
+ * of the thread. It is only affected by explicit calls to
+ * set thread priority and upon thread creation via a thread
+ * attribute or default priority.
+ */
+ char base_priority;
+
+ /*
+ * Inherited priority is the priority a thread inherits by
+ * taking a priority inheritence or protection mutex. It
+ * is not affected by base priority changes. Inherited
+ * priority defaults to and remains 0 until a mutex is taken
+ * that is being waited on by any other thread whose priority
+ * is non-zero.
+ */
+ char inherited_priority;
+
+ /*
+ * Active priority is always the maximum of the threads base
+ * priority and inherited priority. When there is a change
+ * in either the base or inherited priority, the active
+ * priority must be recalculated.
+ */
+ char active_priority;
+
+ /* Queue of currently owned simple type mutexes. */
+ TAILQ_HEAD(, pthread_mutex) mutexq;
+
+ void *ret;
+ struct pthread_specific_elem *specific;
+ int specific_data_count;
+
+ /* Number rwlocks rdlocks held. */
+ int rdlock_count;
+
+ /*
+ * Current locks bitmap for rtld. */
+ int rtld_bits;
+
+ /* Thread control block */
+ struct tcb *tcb;
+
+ /* Cleanup handlers Link List */
+ struct pthread_cleanup *cleanup;
+
+ /*
+ * Magic value to help recognize a valid thread structure
+ * from an invalid one:
+ */
+#define THR_MAGIC ((u_int32_t) 0xd09ba115)
+ u_int32_t magic;
+
+ /* Enable event reporting */
+ int report_events;
+
+ /* Event mask */
+ int event_mask;
+
+ /* Event */
+ td_event_msg_t event_buf;
+};
+
+#define THR_IN_CRITICAL(thrd) \
+ (((thrd)->locklevel > 0) || \
+ ((thrd)->critical_count > 0))
+
+#define THR_CRITICAL_ENTER(thrd) \
+ (thrd)->critical_count++
+
+#define THR_CRITICAL_LEAVE(thrd) \
+ (thrd)->critical_count--; \
+ _thr_ast(thrd);
+
+#define THR_UMTX_TRYLOCK(thrd, lck) \
+ _thr_umtx_trylock((lck), (thrd)->tid)
+
+#define THR_UMTX_LOCK(thrd, lck) \
+ _thr_umtx_lock((lck), (thrd)->tid)
+
+#define THR_UMTX_TIMEDLOCK(thrd, lck, timo) \
+ _thr_umtx_timedlock((lck), (thrd)->tid, (timo))
+
+#define THR_UMTX_UNLOCK(thrd, lck) \
+ _thr_umtx_unlock((lck), (thrd)->tid)
+
+#define THR_LOCK_ACQUIRE(thrd, lck) \
+do { \
+ (thrd)->locklevel++; \
+ _thr_umtx_lock(lck, (thrd)->tid); \
+} while (0)
+
+#ifdef _PTHREADS_INVARIANTS
+#define THR_ASSERT_LOCKLEVEL(thrd) \
+do { \
+ if (__predict_false((thrd)->locklevel <= 0)) \
+ _thr_assert_lock_level(); \
+} while (0)
+#else
+#define THR_ASSERT_LOCKLEVEL(thrd)
+#endif
+
+#define THR_LOCK_RELEASE(thrd, lck) \
+do { \
+ THR_ASSERT_LOCKLEVEL(thrd); \
+ _thr_umtx_unlock((lck), (thrd)->tid); \
+ (thrd)->locklevel--; \
+ _thr_ast(thrd); \
+} while (0)
+
+#define THR_LOCK(curthrd) THR_LOCK_ACQUIRE(curthrd, &(curthrd)->lock)
+#define THR_UNLOCK(curthrd) THR_LOCK_RELEASE(curthrd, &(curthrd)->lock)
+#define THR_THREAD_LOCK(curthrd, thr) THR_LOCK_ACQUIRE(curthrd, &(thr)->lock)
+#define THR_THREAD_UNLOCK(curthrd, thr) THR_LOCK_RELEASE(curthrd, &(thr)->lock)
+
+#define THREAD_LIST_LOCK(curthrd) \
+do { \
+ THR_LOCK_ACQUIRE((curthrd), &_thr_list_lock); \
+} while (0)
+
+#define THREAD_LIST_UNLOCK(curthrd) \
+do { \
+ THR_LOCK_RELEASE((curthrd), &_thr_list_lock); \
+} while (0)
+
+/*
+ * Macros to insert/remove threads to the all thread list and
+ * the gc list.
+ */
+#define THR_LIST_ADD(thrd) do { \
+ if (((thrd)->tlflags & TLFLAGS_IN_TDLIST) == 0) { \
+ TAILQ_INSERT_HEAD(&_thread_list, thrd, tle); \
+ _thr_hash_add(thrd); \
+ (thrd)->tlflags |= TLFLAGS_IN_TDLIST; \
+ } \
+} while (0)
+#define THR_LIST_REMOVE(thrd) do { \
+ if (((thrd)->tlflags & TLFLAGS_IN_TDLIST) != 0) { \
+ TAILQ_REMOVE(&_thread_list, thrd, tle); \
+ _thr_hash_remove(thrd); \
+ (thrd)->tlflags &= ~TLFLAGS_IN_TDLIST; \
+ } \
+} while (0)
+#define THR_GCLIST_ADD(thrd) do { \
+ if (((thrd)->tlflags & TLFLAGS_IN_GCLIST) == 0) { \
+ TAILQ_INSERT_HEAD(&_thread_gc_list, thrd, gcle);\
+ (thrd)->tlflags |= TLFLAGS_IN_GCLIST; \
+ _gc_count++; \
+ } \
+} while (0)
+#define THR_GCLIST_REMOVE(thrd) do { \
+ if (((thrd)->tlflags & TLFLAGS_IN_GCLIST) != 0) { \
+ TAILQ_REMOVE(&_thread_gc_list, thrd, gcle); \
+ (thrd)->tlflags &= ~TLFLAGS_IN_GCLIST; \
+ _gc_count--; \
+ } \
+} while (0)
+
+#define GC_NEEDED() (_gc_count >= 5)
+
+#define SHOULD_REPORT_EVENT(curthr, e) \
+ (curthr->report_events && \
+ (((curthr)->event_mask | _thread_event_mask ) & e) != 0)
+
+extern int __isthreaded;
+
+/*
+ * Global variables for the pthread kernel.
+ */
+
+extern char *_usrstack __hidden;
+extern struct pthread *_thr_initial __hidden;
+extern int _thr_scope_system __hidden;
+
+/* For debugger */
+extern int _libthr_debug;
+extern int _thread_event_mask;
+extern struct pthread *_thread_last_event;
+
+/* List of all threads: */
+extern pthreadlist _thread_list;
+
+/* List of threads needing GC: */
+extern pthreadlist _thread_gc_list __hidden;
+
+extern int _thread_active_threads;
+extern atfork_head _thr_atfork_list __hidden;
+extern umtx_t _thr_atfork_lock __hidden;
+
+/* Default thread attributes: */
+extern struct pthread_attr _pthread_attr_default __hidden;
+
+/* Default mutex attributes: */
+extern struct pthread_mutex_attr _pthread_mutexattr_default __hidden;
+
+/* Default condition variable attributes: */
+extern struct pthread_cond_attr _pthread_condattr_default __hidden;
+
+extern struct pthread_prio _thr_priorities[] __hidden;
+
+extern pid_t _thr_pid __hidden;
+extern size_t _thr_guard_default __hidden;
+extern size_t _thr_stack_default __hidden;
+extern size_t _thr_stack_initial __hidden;
+extern int _thr_page_size __hidden;
+/* Garbage thread count. */
+extern int _gc_count __hidden;
+
+extern umtx_t _mutex_static_lock __hidden;
+extern umtx_t _cond_static_lock __hidden;
+extern umtx_t _rwlock_static_lock __hidden;
+extern umtx_t _keytable_lock __hidden;
+extern umtx_t _thr_list_lock __hidden;
+extern umtx_t _thr_event_lock __hidden;
+
+/*
+ * Function prototype definitions.
+ */
+__BEGIN_DECLS
+int _thr_setthreaded(int) __hidden;
+int _mutex_cv_lock(pthread_mutex_t *, int count) __hidden;
+int _mutex_cv_unlock(pthread_mutex_t *, int *count) __hidden;
+int _mutex_reinit(pthread_mutex_t *) __hidden;
+void _mutex_fork(struct pthread *curthread) __hidden;
+void _mutex_unlock_private(struct pthread *) __hidden;
+void _libpthread_init(struct pthread *) __hidden;
+struct pthread *_thr_alloc(struct pthread *) __hidden;
+void _thread_exit(const char *, int, const char *) __hidden __dead2;
+void _thr_exit_cleanup(void) __hidden;
+int _thr_ref_add(struct pthread *, struct pthread *, int) __hidden;
+void _thr_ref_delete(struct pthread *, struct pthread *) __hidden;
+void _thr_ref_delete_unlocked(struct pthread *, struct pthread *) __hidden;
+int _thr_find_thread(struct pthread *, struct pthread *, int) __hidden;
+void _thr_rtld_init(void) __hidden;
+void _thr_rtld_fini(void) __hidden;
+int _thr_stack_alloc(struct pthread_attr *) __hidden;
+void _thr_stack_free(struct pthread_attr *) __hidden;
+void _thr_free(struct pthread *, struct pthread *) __hidden;
+void _thr_gc(struct pthread *) __hidden;
+void _thread_cleanupspecific(void) __hidden;
+void _thread_dump_info(void) __hidden;
+void _thread_printf(int, const char *, ...) __hidden;
+void _thr_spinlock_init(void) __hidden;
+int _thr_cancel_enter(struct pthread *) __hidden;
+void _thr_cancel_leave(struct pthread *, int) __hidden;
+void _thr_signal_block(struct pthread *) __hidden;
+void _thr_signal_unblock(struct pthread *) __hidden;
+void _thr_signal_init(void) __hidden;
+void _thr_signal_deinit(void) __hidden;
+int _thr_send_sig(struct pthread *, int sig) __hidden;
+void _thr_list_init(void) __hidden;
+void _thr_hash_add(struct pthread *) __hidden;
+void _thr_hash_remove(struct pthread *) __hidden;
+struct pthread *_thr_hash_find(struct pthread *) __hidden;
+void _thr_link(struct pthread *, struct pthread *) __hidden;
+void _thr_unlink(struct pthread *, struct pthread *) __hidden;
+void _thr_suspend_check(struct pthread *) __hidden;
+void _thr_assert_lock_level(void) __hidden __dead2;
+void _thr_ast(struct pthread *) __hidden;
+void _thr_once_init(void) __hidden;
+void _thr_report_creation(struct pthread *curthread,
+ struct pthread *newthread) __hidden;
+void _thr_report_death(struct pthread *curthread) __hidden;
+void _thread_bp_create(void);
+void _thread_bp_death(void);
+
+/* #include <fcntl.h> */
+#ifdef _SYS_FCNTL_H_
+int __sys_fcntl(int, int, ...);
+int __sys_open(const char *, int, ...);
+#endif
+
+/* #include <signal.h> */
+#ifdef _SIGNAL_H_
+int __sys_kill(pid_t, int);
+int __sys_sigaction(int, const struct sigaction *, struct sigaction *);
+int __sys_sigpending(sigset_t *);
+int __sys_sigprocmask(int, const sigset_t *, sigset_t *);
+int __sys_sigsuspend(const sigset_t *);
+int __sys_sigreturn(ucontext_t *);
+int __sys_sigaltstack(const struct sigaltstack *, struct sigaltstack *);
+int __sys_sigwait(const sigset_t *, int *);
+int __sys_sigtimedwait(const sigset_t *, siginfo_t *,
+ const struct timespec *);
+int __sys_sigwaitinfo(const sigset_t *set, siginfo_t *info);
+#endif
+
+/* #include <time.h> */
+#ifdef _TIME_H_
+int __sys_nanosleep(const struct timespec *, struct timespec *);
+#endif
+
+/* #include <unistd.h> */
+#ifdef _UNISTD_H_
+int __sys_close(int);
+int __sys_fork(void);
+pid_t __sys_getpid(void);
+ssize_t __sys_read(int, void *, size_t);
+ssize_t __sys_write(int, const void *, size_t);
+void __sys_exit(int);
+#endif
+
+static inline int
+_thr_isthreaded(void)
+{
+ return (__isthreaded != 0);
+}
+
+static inline int
+_thr_is_inited(void)
+{
+ return (_thr_initial != NULL);
+}
+
+static inline void
+_thr_check_init(void)
+{
+ if (_thr_initial == NULL)
+ _libpthread_init(NULL);
+}
+
+__END_DECLS
+
+#endif /* !_THR_PRIVATE_H */
diff --git a/lib/libthr/thread/thr_pspinlock.c b/lib/libthr/thread/thr_pspinlock.c
new file mode 100644
index 0000000..ec3d68b
--- /dev/null
+++ b/lib/libthr/thread/thr_pspinlock.c
@@ -0,0 +1,136 @@
+/*-
+ * Copyright (c) 2003 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.
+ *
+ * $FreeBSD$
+ */
+
+#include "namespace.h"
+#include <errno.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+#define SPIN_COUNT 100000
+
+__weak_reference(_pthread_spin_init, pthread_spin_init);
+__weak_reference(_pthread_spin_destroy, pthread_spin_destroy);
+__weak_reference(_pthread_spin_trylock, pthread_spin_trylock);
+__weak_reference(_pthread_spin_lock, pthread_spin_lock);
+__weak_reference(_pthread_spin_unlock, pthread_spin_unlock);
+
+int
+_pthread_spin_init(pthread_spinlock_t *lock, int pshared)
+{
+ struct pthread_spinlock *lck;
+ int ret;
+
+ if (lock == NULL || pshared != PTHREAD_PROCESS_PRIVATE)
+ ret = EINVAL;
+ else if ((lck = malloc(sizeof(struct pthread_spinlock))) == NULL)
+ ret = ENOMEM;
+ else {
+ _thr_umtx_init(&lck->s_lock);
+ *lock = lck;
+ ret = 0;
+ }
+
+ return (ret);
+}
+
+int
+_pthread_spin_destroy(pthread_spinlock_t *lock)
+{
+ int ret;
+
+ if (lock == NULL || *lock == NULL)
+ ret = EINVAL;
+ else {
+ free(*lock);
+ *lock = NULL;
+ ret = 0;
+ }
+
+ return (ret);
+}
+
+int
+_pthread_spin_trylock(pthread_spinlock_t *lock)
+{
+ struct pthread *curthread = _get_curthread();
+ struct pthread_spinlock *lck;
+ int ret;
+
+ if (lock == NULL || (lck = *lock) == NULL)
+ ret = EINVAL;
+ else
+ ret = THR_UMTX_TRYLOCK(curthread, &lck->s_lock);
+ return (ret);
+}
+
+int
+_pthread_spin_lock(pthread_spinlock_t *lock)
+{
+ struct pthread *curthread = _get_curthread();
+ struct pthread_spinlock *lck;
+ int ret, count;
+
+ if (lock == NULL || (lck = *lock) == NULL)
+ ret = EINVAL;
+ else {
+ count = SPIN_COUNT;
+ while ((ret = THR_UMTX_TRYLOCK(curthread, &lck->s_lock)) != 0) {
+ while (lck->s_lock) {
+#ifdef __i386__
+ /* tell cpu we are spinning */
+ __asm __volatile("pause");
+#endif
+ if (--count <= 0) {
+ count = SPIN_COUNT;
+ _pthread_yield();
+ }
+ }
+ }
+ ret = 0;
+ }
+
+ return (ret);
+}
+
+int
+_pthread_spin_unlock(pthread_spinlock_t *lock)
+{
+ struct pthread *curthread = _get_curthread();
+ struct pthread_spinlock *lck;
+ int ret;
+
+ if (lock == NULL || (lck = *lock) == NULL)
+ ret = EINVAL;
+ else {
+ ret = THR_UMTX_UNLOCK(curthread, &lck->s_lock);
+ }
+ return (ret);
+}
diff --git a/lib/libthr/thread/thr_resume_np.c b/lib/libthr/thread/thr_resume_np.c
new file mode 100644
index 0000000..7fd3733
--- /dev/null
+++ b/lib/libthr/thread/thr_resume_np.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <errno.h>
+#include <pthread.h>
+#include <pthread_np.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+__weak_reference(_pthread_resume_np, pthread_resume_np);
+__weak_reference(_pthread_resume_all_np, pthread_resume_all_np);
+
+static void resume_common(struct pthread *thread);
+
+/* Resume a thread: */
+int
+_pthread_resume_np(pthread_t thread)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ /* Add a reference to the thread: */
+ if ((ret = _thr_ref_add(curthread, thread, /*include dead*/0)) == 0) {
+ /* Lock the threads scheduling queue: */
+ THR_THREAD_LOCK(curthread, thread);
+ resume_common(thread);
+ THR_THREAD_UNLOCK(curthread, thread);
+ _thr_ref_delete(curthread, thread);
+ }
+ return (ret);
+}
+
+void
+_pthread_resume_all_np(void)
+{
+ struct pthread *curthread = _get_curthread();
+ struct pthread *thread;
+
+ /* Take the thread list lock: */
+ THREAD_LIST_LOCK(curthread);
+
+ TAILQ_FOREACH(thread, &_thread_list, tle) {
+ if (thread != curthread) {
+ THR_THREAD_LOCK(curthread, thread);
+ resume_common(thread);
+ THR_THREAD_UNLOCK(curthread, thread);
+ }
+ }
+
+ /* Release the thread list lock: */
+ THREAD_LIST_UNLOCK(curthread);
+}
+
+static void
+resume_common(struct pthread *thread)
+{
+ /* Clear the suspend flag: */
+ thread->flags &= ~THR_FLAGS_NEED_SUSPEND;
+ thread->cycle++;
+ _thr_umtx_wake(&thread->cycle, 1);
+}
diff --git a/lib/libthr/thread/thr_rtld.c b/lib/libthr/thread/thr_rtld.c
new file mode 100644
index 0000000..827b962
--- /dev/null
+++ b/lib/libthr/thread/thr_rtld.c
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2006, 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 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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, 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$
+ *
+ */
+
+ /*
+ * A lockless rwlock for rtld.
+ */
+#include <sys/cdefs.h>
+#include <stdlib.h>
+
+#include "rtld_lock.h"
+#include "thr_private.h"
+
+#define CACHE_LINE_SIZE 64
+#define WAFLAG 0x1
+#define RC_INCR 0x2
+
+static int _thr_rtld_clr_flag(int);
+static void *_thr_rtld_lock_create(void);
+static void _thr_rtld_lock_destroy(void *);
+static void _thr_rtld_lock_release(void *);
+static void _thr_rtld_rlock_acquire(void *);
+static int _thr_rtld_set_flag(int);
+static void _thr_rtld_wlock_acquire(void *);
+
+struct rtld_lock {
+ volatile int lock;
+ volatile int rd_waiters;
+ volatile int wr_waiters;
+ volatile umtx_t rd_cv;
+ volatile umtx_t wr_cv;
+ void *base;
+};
+
+static void *
+_thr_rtld_lock_create(void)
+{
+ void *base;
+ char *p;
+ uintptr_t r;
+ struct rtld_lock *l;
+
+ THR_ASSERT(sizeof(struct rtld_lock) <= CACHE_LINE_SIZE,
+ "rtld_lock too large");
+ base = calloc(1, CACHE_LINE_SIZE);
+ p = (char *)base;
+ if ((uintptr_t)p % CACHE_LINE_SIZE != 0) {
+ free(base);
+ base = calloc(1, 2 * CACHE_LINE_SIZE);
+ p = (char *)base;
+ if ((r = (uintptr_t)p % CACHE_LINE_SIZE) != 0)
+ p += CACHE_LINE_SIZE - r;
+ }
+ l = (struct rtld_lock *)p;
+ l->base = base;
+ return (l);
+}
+
+static void
+_thr_rtld_lock_destroy(void *lock)
+{
+ struct rtld_lock *l = (struct rtld_lock *)lock;
+ free(l->base);
+}
+
+static void
+_thr_rtld_rlock_acquire(void *lock)
+{
+ struct pthread *curthread;
+ struct rtld_lock *l;
+ umtx_t v;
+
+ curthread = _get_curthread();
+ l = (struct rtld_lock *)lock;
+
+ THR_CRITICAL_ENTER(curthread);
+ atomic_add_acq_int(&l->lock, RC_INCR);
+ if (!(l->lock & WAFLAG))
+ return;
+ v = l->rd_cv;
+ atomic_add_int(&l->rd_waiters, 1);
+ while (l->lock & WAFLAG) {
+ _thr_umtx_wait(&l->rd_cv, v, NULL);
+ v = l->rd_cv;
+ }
+ atomic_add_int(&l->rd_waiters, -1);
+}
+
+static void
+_thr_rtld_wlock_acquire(void *lock)
+{
+ struct pthread *curthread;
+ struct rtld_lock *l;
+ umtx_t v;
+
+ curthread = _get_curthread();
+ l = (struct rtld_lock *)lock;
+
+ _thr_signal_block(curthread);
+ for (;;) {
+ if (atomic_cmpset_acq_int(&l->lock, 0, WAFLAG))
+ return;
+ v = l->wr_cv;
+ atomic_add_int(&l->wr_waiters, 1);
+ while (l->lock != 0) {
+ _thr_umtx_wait(&l->wr_cv, v, NULL);
+ v = l->wr_cv;
+ }
+ atomic_add_int(&l->wr_waiters, -1);
+ }
+}
+
+static void
+_thr_rtld_lock_release(void *lock)
+{
+ struct pthread *curthread;
+ struct rtld_lock *l;
+
+ curthread = _get_curthread();
+ l = (struct rtld_lock *)lock;
+
+ if ((l->lock & WAFLAG) == 0) {
+ atomic_add_rel_int(&l->lock, -RC_INCR);
+ if (l->lock == 0 && l->wr_waiters) {
+ atomic_add_long(&l->wr_cv, 1);
+ _thr_umtx_wake(&l->wr_cv, l->wr_waiters);
+ }
+ THR_CRITICAL_LEAVE(curthread);
+ } else {
+ atomic_add_rel_int(&l->lock, -WAFLAG);
+ if (l->lock == 0 && l->wr_waiters) {
+ atomic_add_long(&l->wr_cv, 1);
+ _thr_umtx_wake(&l->wr_cv, l->wr_waiters);
+ } else if (l->rd_waiters) {
+ atomic_add_long(&l->rd_cv, 1);
+ _thr_umtx_wake(&l->rd_cv, l->rd_waiters);
+ }
+ _thr_signal_unblock(curthread);
+ }
+}
+
+static int
+_thr_rtld_set_flag(int mask __unused)
+{
+ /*
+ * The caller's code in rtld-elf is broken, it is not signal safe,
+ * just return zero to fool it.
+ */
+ return (0);
+}
+
+static int
+_thr_rtld_clr_flag(int mask __unused)
+{
+ return (0);
+}
+
+void
+_thr_rtld_init(void)
+{
+ struct RtldLockInfo li;
+ struct pthread *curthread;
+ umtx_t dummy;
+
+ curthread = _get_curthread();
+
+ /* force to resolve _umtx_op PLT */
+ _umtx_op((struct umtx *)&dummy, UMTX_OP_WAKE, 1, 0, 0);
+
+ li.lock_create = _thr_rtld_lock_create;
+ li.lock_destroy = _thr_rtld_lock_destroy;
+ li.rlock_acquire = _thr_rtld_rlock_acquire;
+ li.wlock_acquire = _thr_rtld_wlock_acquire;
+ li.lock_release = _thr_rtld_lock_release;
+ li.thread_set_flag = _thr_rtld_set_flag;
+ li.thread_clr_flag = _thr_rtld_clr_flag;
+ li.at_fork = NULL;
+
+ /* mask signals, also force to resolve __sys_sigprocmask PLT */
+ _thr_signal_block(curthread);
+ _rtld_thread_init(&li);
+ _thr_signal_unblock(curthread);
+}
+
+void
+_thr_rtld_fini(void)
+{
+ struct pthread *curthread;
+
+ curthread = _get_curthread();
+ _thr_signal_block(curthread);
+ _rtld_thread_init(NULL);
+ _thr_signal_unblock(curthread);
+}
diff --git a/lib/libthr/thread/thr_rwlock.c b/lib/libthr/thread/thr_rwlock.c
new file mode 100644
index 0000000..81d1459
--- /dev/null
+++ b/lib/libthr/thread/thr_rwlock.c
@@ -0,0 +1,417 @@
+/*-
+ * Copyright (c) 1998 Alex Nash
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#include "namespace.h"
+#include <pthread.h>
+#include "un-namespace.h"
+#include "thr_private.h"
+
+/* maximum number of times a read lock may be obtained */
+#define MAX_READ_LOCKS (INT_MAX - 1)
+
+__weak_reference(_pthread_rwlock_destroy, pthread_rwlock_destroy);
+__weak_reference(_pthread_rwlock_init, pthread_rwlock_init);
+__weak_reference(_pthread_rwlock_rdlock, pthread_rwlock_rdlock);
+__weak_reference(_pthread_rwlock_timedrdlock, pthread_rwlock_timedrdlock);
+__weak_reference(_pthread_rwlock_tryrdlock, pthread_rwlock_tryrdlock);
+__weak_reference(_pthread_rwlock_trywrlock, pthread_rwlock_trywrlock);
+__weak_reference(_pthread_rwlock_unlock, pthread_rwlock_unlock);
+__weak_reference(_pthread_rwlock_wrlock, pthread_rwlock_wrlock);
+__weak_reference(_pthread_rwlock_timedwrlock, pthread_rwlock_timedwrlock);
+
+/*
+ * Prototypes
+ */
+
+static int
+rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr __unused)
+{
+ pthread_rwlock_t prwlock;
+ int ret;
+
+ /* allocate rwlock object */
+ prwlock = (pthread_rwlock_t)malloc(sizeof(struct pthread_rwlock));
+
+ if (prwlock == NULL)
+ return (ENOMEM);
+
+ /* initialize the lock */
+ if ((ret = _pthread_mutex_init(&prwlock->lock, NULL)) != 0)
+ free(prwlock);
+ else {
+ /* initialize the read condition signal */
+ ret = _pthread_cond_init(&prwlock->read_signal, NULL);
+
+ if (ret != 0) {
+ _pthread_mutex_destroy(&prwlock->lock);
+ free(prwlock);
+ } else {
+ /* initialize the write condition signal */
+ ret = _pthread_cond_init(&prwlock->write_signal, NULL);
+
+ if (ret != 0) {
+ _pthread_cond_destroy(&prwlock->read_signal);
+ _pthread_mutex_destroy(&prwlock->lock);
+ free(prwlock);
+ } else {
+ /* success */
+ prwlock->state = 0;
+ prwlock->blocked_writers = 0;
+ *rwlock = prwlock;
+ }
+ }
+ }
+
+ return (ret);
+}
+
+int
+_pthread_rwlock_destroy (pthread_rwlock_t *rwlock)
+{
+ int ret;
+
+ if (rwlock == NULL)
+ ret = EINVAL;
+ else {
+ pthread_rwlock_t prwlock;
+
+ prwlock = *rwlock;
+
+ _pthread_mutex_destroy(&prwlock->lock);
+ _pthread_cond_destroy(&prwlock->read_signal);
+ _pthread_cond_destroy(&prwlock->write_signal);
+ free(prwlock);
+
+ *rwlock = NULL;
+
+ ret = 0;
+ }
+ return (ret);
+}
+
+static int
+init_static(struct pthread *thread, pthread_rwlock_t *rwlock)
+{
+ int ret;
+
+ THR_LOCK_ACQUIRE(thread, &_rwlock_static_lock);
+
+ if (*rwlock == NULL)
+ ret = rwlock_init(rwlock, NULL);
+ else
+ ret = 0;
+
+ THR_LOCK_RELEASE(thread, &_rwlock_static_lock);
+
+ return (ret);
+}
+
+int
+_pthread_rwlock_init (pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr)
+{
+ *rwlock = NULL;
+ return (rwlock_init(rwlock, attr));
+}
+
+static int
+rwlock_rdlock_common (pthread_rwlock_t *rwlock, const struct timespec *abstime)
+{
+ struct pthread *curthread = _get_curthread();
+ pthread_rwlock_t prwlock;
+ int ret;
+
+ if (rwlock == NULL)
+ return (EINVAL);
+
+ prwlock = *rwlock;
+
+ /* check for static initialization */
+ if (prwlock == NULL) {
+ if ((ret = init_static(curthread, rwlock)) != 0)
+ return (ret);
+
+ prwlock = *rwlock;
+ }
+
+ /* grab the monitor lock */
+ if ((ret = _pthread_mutex_lock(&prwlock->lock)) != 0)
+ return (ret);
+
+ /* check lock count */
+ if (prwlock->state == MAX_READ_LOCKS) {
+ _pthread_mutex_unlock(&prwlock->lock);
+ return (EAGAIN);
+ }
+
+ if ((curthread->rdlock_count > 0) && (prwlock->state > 0)) {
+ /*
+ * To avoid having to track all the rdlocks held by
+ * a thread or all of the threads that hold a rdlock,
+ * we keep a simple count of all the rdlocks held by
+ * a thread. If a thread holds any rdlocks it is
+ * possible that it is attempting to take a recursive
+ * rdlock. If there are blocked writers and precedence
+ * is given to them, then that would result in the thread
+ * deadlocking. So allowing a thread to take the rdlock
+ * when it already has one or more rdlocks avoids the
+ * deadlock. I hope the reader can follow that logic ;-)
+ */
+ ; /* nothing needed */
+ } else {
+ /* give writers priority over readers */
+ while (prwlock->blocked_writers || prwlock->state < 0) {
+ if (abstime)
+ ret = _pthread_cond_timedwait
+ (&prwlock->read_signal,
+ &prwlock->lock, abstime);
+ else
+ ret = _pthread_cond_wait(&prwlock->read_signal,
+ &prwlock->lock);
+ if (ret != 0) {
+ /* can't do a whole lot if this fails */
+ _pthread_mutex_unlock(&prwlock->lock);
+ return (ret);
+ }
+ }
+ }
+
+ curthread->rdlock_count++;
+ prwlock->state++; /* indicate we are locked for reading */
+
+ /*
+ * Something is really wrong if this call fails. Returning
+ * error won't do because we've already obtained the read
+ * lock. Decrementing 'state' is no good because we probably
+ * don't have the monitor lock.
+ */
+ _pthread_mutex_unlock(&prwlock->lock);
+
+ return (ret);
+}
+
+int
+_pthread_rwlock_rdlock (pthread_rwlock_t *rwlock)
+{
+ return (rwlock_rdlock_common(rwlock, NULL));
+}
+
+int
+_pthread_rwlock_timedrdlock (pthread_rwlock_t *rwlock,
+ const struct timespec *abstime)
+{
+ return (rwlock_rdlock_common(rwlock, abstime));
+}
+
+int
+_pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock)
+{
+ struct pthread *curthread = _get_curthread();
+ pthread_rwlock_t prwlock;
+ int ret;
+
+ if (rwlock == NULL)
+ return (EINVAL);
+
+ prwlock = *rwlock;
+
+ /* check for static initialization */
+ if (prwlock == NULL) {
+ if ((ret = init_static(curthread, rwlock)) != 0)
+ return (ret);
+
+ prwlock = *rwlock;
+ }
+
+ /* grab the monitor lock */
+ if ((ret = _pthread_mutex_lock(&prwlock->lock)) != 0)
+ return (ret);
+
+ if (prwlock->state == MAX_READ_LOCKS)
+ ret = EAGAIN;
+ else if ((curthread->rdlock_count > 0) && (prwlock->state > 0)) {
+ /* see comment for pthread_rwlock_rdlock() */
+ curthread->rdlock_count++;
+ prwlock->state++;
+ }
+ /* give writers priority over readers */
+ else if (prwlock->blocked_writers || prwlock->state < 0)
+ ret = EBUSY;
+ else {
+ curthread->rdlock_count++;
+ prwlock->state++; /* indicate we are locked for reading */
+ }
+
+ /* see the comment on this in pthread_rwlock_rdlock */
+ _pthread_mutex_unlock(&prwlock->lock);
+
+ return (ret);
+}
+
+int
+_pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock)
+{
+ struct pthread *curthread = _get_curthread();
+ pthread_rwlock_t prwlock;
+ int ret;
+
+ if (rwlock == NULL)
+ return (EINVAL);
+
+ prwlock = *rwlock;
+
+ /* check for static initialization */
+ if (prwlock == NULL) {
+ if ((ret = init_static(curthread, rwlock)) != 0)
+ return (ret);
+
+ prwlock = *rwlock;
+ }
+
+ /* grab the monitor lock */
+ if ((ret = _pthread_mutex_lock(&prwlock->lock)) != 0)
+ return (ret);
+
+ if (prwlock->state != 0)
+ ret = EBUSY;
+ else
+ /* indicate we are locked for writing */
+ prwlock->state = -1;
+
+ /* see the comment on this in pthread_rwlock_rdlock */
+ _pthread_mutex_unlock(&prwlock->lock);
+
+ return (ret);
+}
+
+int
+_pthread_rwlock_unlock (pthread_rwlock_t *rwlock)
+{
+ struct pthread *curthread = _get_curthread();
+ pthread_rwlock_t prwlock;
+ int ret;
+
+ if (rwlock == NULL)
+ return (EINVAL);
+
+ prwlock = *rwlock;
+
+ if (prwlock == NULL)
+ return (EINVAL);
+
+ /* grab the monitor lock */
+ if ((ret = _pthread_mutex_lock(&prwlock->lock)) != 0)
+ return (ret);
+
+ if (prwlock->state > 0) {
+ curthread->rdlock_count--;
+ prwlock->state--;
+ if (prwlock->state == 0 && prwlock->blocked_writers)
+ ret = _pthread_cond_signal(&prwlock->write_signal);
+ } else if (prwlock->state < 0) {
+ prwlock->state = 0;
+
+ if (prwlock->blocked_writers)
+ ret = _pthread_cond_signal(&prwlock->write_signal);
+ else
+ ret = _pthread_cond_broadcast(&prwlock->read_signal);
+ } else
+ ret = EINVAL;
+
+ /* see the comment on this in pthread_rwlock_rdlock */
+ _pthread_mutex_unlock(&prwlock->lock);
+
+ return (ret);
+}
+
+static int
+rwlock_wrlock_common (pthread_rwlock_t *rwlock, const struct timespec *abstime)
+{
+ struct pthread *curthread = _get_curthread();
+ pthread_rwlock_t prwlock;
+ int ret;
+
+ if (rwlock == NULL)
+ return (EINVAL);
+
+ prwlock = *rwlock;
+
+ /* check for static initialization */
+ if (prwlock == NULL) {
+ if ((ret = init_static(curthread, rwlock)) != 0)
+ return (ret);
+
+ prwlock = *rwlock;
+ }
+
+ /* grab the monitor lock */
+ if ((ret = _pthread_mutex_lock(&prwlock->lock)) != 0)
+ return (ret);
+
+ while (prwlock->state != 0) {
+ prwlock->blocked_writers++;
+
+ if (abstime != NULL)
+ ret = _pthread_cond_timedwait(&prwlock->write_signal,
+ &prwlock->lock, abstime);
+ else
+ ret = _pthread_cond_wait(&prwlock->write_signal,
+ &prwlock->lock);
+ if (ret != 0) {
+ prwlock->blocked_writers--;
+ _pthread_mutex_unlock(&prwlock->lock);
+ return (ret);
+ }
+
+ prwlock->blocked_writers--;
+ }
+
+ /* indicate we are locked for writing */
+ prwlock->state = -1;
+
+ /* see the comment on this in pthread_rwlock_rdlock */
+ _pthread_mutex_unlock(&prwlock->lock);
+
+ return (ret);
+}
+
+int
+_pthread_rwlock_wrlock (pthread_rwlock_t *rwlock)
+{
+ return (rwlock_wrlock_common (rwlock, NULL));
+}
+
+int
+_pthread_rwlock_timedwrlock (pthread_rwlock_t *rwlock,
+ const struct timespec *abstime)
+{
+ return (rwlock_wrlock_common (rwlock, abstime));
+}
diff --git a/lib/libthr/thread/thr_rwlockattr.c b/lib/libthr/thread/thr_rwlockattr.c
new file mode 100644
index 0000000..b47d167
--- /dev/null
+++ b/lib/libthr/thread/thr_rwlockattr.c
@@ -0,0 +1,100 @@
+/*-
+ * Copyright (c) 1998 Alex Nash
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <errno.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+__weak_reference(_pthread_rwlockattr_destroy, pthread_rwlockattr_destroy);
+__weak_reference(_pthread_rwlockattr_getpshared, pthread_rwlockattr_getpshared);
+__weak_reference(_pthread_rwlockattr_init, pthread_rwlockattr_init);
+__weak_reference(_pthread_rwlockattr_setpshared, pthread_rwlockattr_setpshared);
+
+int
+_pthread_rwlockattr_destroy(pthread_rwlockattr_t *rwlockattr)
+{
+ pthread_rwlockattr_t prwlockattr;
+
+ if (rwlockattr == NULL)
+ return(EINVAL);
+
+ prwlockattr = *rwlockattr;
+
+ if (prwlockattr == NULL)
+ return(EINVAL);
+
+ free(prwlockattr);
+
+ return(0);
+}
+
+int
+_pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *rwlockattr,
+ int *pshared)
+{
+ *pshared = (*rwlockattr)->pshared;
+
+ return(0);
+}
+
+int
+_pthread_rwlockattr_init(pthread_rwlockattr_t *rwlockattr)
+{
+ pthread_rwlockattr_t prwlockattr;
+
+ if (rwlockattr == NULL)
+ return(EINVAL);
+
+ prwlockattr = (pthread_rwlockattr_t)
+ malloc(sizeof(struct pthread_rwlockattr));
+
+ if (prwlockattr == NULL)
+ return(ENOMEM);
+
+ prwlockattr->pshared = PTHREAD_PROCESS_PRIVATE;
+ *rwlockattr = prwlockattr;
+
+ return(0);
+}
+
+int
+_pthread_rwlockattr_setpshared(pthread_rwlockattr_t *rwlockattr, int pshared)
+{
+ /* Only PTHREAD_PROCESS_PRIVATE is supported. */
+ if (pshared != PTHREAD_PROCESS_PRIVATE)
+ return(EINVAL);
+
+ (*rwlockattr)->pshared = pshared;
+
+ return(0);
+}
+
diff --git a/lib/libthr/thread/thr_self.c b/lib/libthr/thread/thr_self.c
new file mode 100644
index 0000000..85fb54e
--- /dev/null
+++ b/lib/libthr/thread/thr_self.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <pthread.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+__weak_reference(_pthread_self, pthread_self);
+
+pthread_t
+_pthread_self(void)
+{
+ _thr_check_init();
+
+ /* Return the running thread pointer: */
+ return (_get_curthread());
+}
diff --git a/lib/libthr/thread/thr_sem.c b/lib/libthr/thread/thr_sem.c
new file mode 100644
index 0000000..88a3cbd
--- /dev/null
+++ b/lib/libthr/thread/thr_sem.c
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2005 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$
+ */
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <stdlib.h>
+#include <time.h>
+#include <_semaphore.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+
+__weak_reference(_sem_init, sem_init);
+__weak_reference(_sem_destroy, sem_destroy);
+__weak_reference(_sem_getvalue, sem_getvalue);
+__weak_reference(_sem_trywait, sem_trywait);
+__weak_reference(_sem_wait, sem_wait);
+__weak_reference(_sem_timedwait, sem_timedwait);
+__weak_reference(_sem_post, sem_post);
+
+
+static inline int
+sem_check_validity(sem_t *sem)
+{
+
+ if ((sem != NULL) && ((*sem)->magic == SEM_MAGIC))
+ return (0);
+ else {
+ errno = EINVAL;
+ return (-1);
+ }
+}
+
+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);
+ }
+ _thr_umtx_init((umtx_t *)&sem->lock);
+ /*
+ * Fortunatly count and nwaiters are adjacency, so we can
+ * use umtx_wait to wait on it, umtx_wait needs an address
+ * can be accessed as a long interger.
+ */
+ sem->count = (u_int32_t)value;
+ sem->nwaiters = 0;
+ sem->magic = SEM_MAGIC;
+ sem->semid = semid;
+ sem->syssem = system_sem;
+ return (sem);
+}
+
+int
+_sem_init(sem_t *sem, int pshared, unsigned int value)
+{
+ semid_t semid;
+
+ 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
+_sem_destroy(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 {
+ retval = 0;
+ (*sem)->magic = 0;
+ }
+ if (retval == 0)
+ free(*sem);
+ return (retval);
+}
+
+int
+_sem_getvalue(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);
+}
+
+int
+_sem_trywait(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
+_sem_wait(sem_t *sem)
+{
+ struct pthread *curthread;
+ int val, oldcancel, retval;
+
+ if (sem_check_validity(sem) != 0)
+ return (-1);
+
+ curthread = _get_curthread();
+ if ((*sem)->syssem != 0) {
+ oldcancel = _thr_cancel_enter(curthread);
+ retval = ksem_wait((*sem)->semid);
+ _thr_cancel_leave(curthread, oldcancel);
+ return (retval);
+ }
+
+ _pthread_testcancel();
+ do {
+ while ((val = (*sem)->count) > 0) {
+ if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1))
+ return (0);
+ }
+ oldcancel = _thr_cancel_enter(curthread);
+ retval = _thr_umtx_wait((umtx_t *)&(*sem)->count, 0, NULL);
+ _thr_cancel_leave(curthread, oldcancel);
+ } while (retval == 0);
+ errno = retval;
+ return (-1);
+}
+
+int
+_sem_timedwait(sem_t * __restrict sem,
+ const struct timespec * __restrict abstime)
+{
+ struct timespec ts, ts2;
+ struct pthread *curthread;
+ int val, oldcancel, retval;
+
+ if (sem_check_validity(sem) != 0)
+ return (-1);
+
+ curthread = _get_curthread();
+ if ((*sem)->syssem != 0) {
+ oldcancel = _thr_cancel_enter(curthread);
+ retval = ksem_timedwait((*sem)->semid, abstime);
+ _thr_cancel_leave(curthread, oldcancel);
+ return (retval);
+ }
+
+ /*
+ * The timeout argument is only supposed to
+ * be checked if the thread would have blocked.
+ */
+ _pthread_testcancel();
+ do {
+ while ((val = (*sem)->count) > 0) {
+ if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1))
+ return (0);
+ }
+ if (abstime == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+ clock_gettime(CLOCK_REALTIME, &ts);
+ TIMESPEC_SUB(&ts2, abstime, &ts);
+ oldcancel = _thr_cancel_enter(curthread);
+ retval = _thr_umtx_wait((umtx_t *)&(*sem)->count, 0, &ts2);
+ _thr_cancel_leave(curthread, oldcancel);
+ } while (retval == 0);
+ errno = retval;
+ return (-1);
+}
+
+int
+_sem_post(sem_t *sem)
+{
+ int val, retval;
+
+ if (sem_check_validity(sem) != 0)
+ return (-1);
+
+ if ((*sem)->syssem != 0)
+ return (ksem_post((*sem)->semid));
+
+ /*
+ * sem_post() is required to be safe to call from within
+ * signal handlers, these code should work as that.
+ */
+ do {
+ val = (*sem)->count;
+ } while (!atomic_cmpset_acq_int(&(*sem)->count, val, val + 1));
+ retval = _thr_umtx_wake((umtx_t *)&(*sem)->count, val + 1);
+ if (retval > 0)
+ retval = 0;
+ return (retval);
+}
diff --git a/lib/libthr/thread/thr_seterrno.c b/lib/libthr/thread/thr_seterrno.c
new file mode 100644
index 0000000..f481799
--- /dev/null
+++ b/lib/libthr/thread/thr_seterrno.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 "thr_private.h"
+
+/*
+ * This function needs to reference the global error variable which is
+ * normally hidden from the user.
+ */
+#undef errno
+extern int errno;
+
+void
+_thread_seterrno(pthread_t thread, int error)
+{
+ /* Check for the initial thread: */
+ if (thread == NULL || thread == _thr_initial)
+ /* The initial thread always uses the global error variable: */
+ errno = error;
+ else
+ /*
+ * Threads other than the initial thread always use the error
+ * field in the thread structureL
+ */
+ thread->error = error;
+}
diff --git a/lib/libthr/thread/thr_setprio.c b/lib/libthr/thread/thr_setprio.c
new file mode 100644
index 0000000..bb9a9bf
--- /dev/null
+++ b/lib/libthr/thread/thr_setprio.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <pthread.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+__weak_reference(_pthread_setprio, pthread_setprio);
+
+int
+_pthread_setprio(pthread_t pthread, int prio)
+{
+ int ret, policy;
+ struct sched_param param;
+
+ if ((ret = _pthread_getschedparam(pthread, &policy, &param)) == 0) {
+ param.sched_priority = prio;
+ ret = _pthread_setschedparam(pthread, policy, &param);
+ }
+
+ /* Return the error status: */
+ return (ret);
+}
diff --git a/lib/libthr/thread/thr_setschedparam.c b/lib/libthr/thread/thr_setschedparam.c
new file mode 100644
index 0000000..eba5017
--- /dev/null
+++ b/lib/libthr/thread/thr_setschedparam.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <errno.h>
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+__weak_reference(_pthread_setschedparam, pthread_setschedparam);
+
+/*
+ * Set a thread's scheduling parameters, this should be done
+ * in kernel, doing it in userland is no-op.
+ */
+int
+_pthread_setschedparam(pthread_t pthread, int policy,
+ const struct sched_param *param)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret = 0;
+
+ if ((param == NULL) || (policy < SCHED_FIFO) || (policy > SCHED_RR)) {
+ ret = EINVAL;
+ } else if (param->sched_priority < _thr_priorities[policy-1].pri_min ||
+ param->sched_priority > _thr_priorities[policy-1].pri_max) {
+ ret = ENOTSUP;
+ } else if ((ret = _thr_ref_add(curthread, pthread, /*include dead*/0))
+ == 0) {
+ /*
+ * Lock the threads scheduling queue while we change
+ * its priority:
+ */
+ THR_THREAD_LOCK(curthread, pthread);
+ if (pthread->state == PS_DEAD) {
+ THR_THREAD_UNLOCK(curthread, pthread);
+ _thr_ref_delete(curthread, pthread);
+ return (ESRCH);
+ }
+
+ /* Set the scheduling policy: */
+ pthread->attr.sched_policy = policy;
+
+ if (param->sched_priority == pthread->base_priority)
+ /*
+ * There is nothing to do; unlock the threads
+ * scheduling queue.
+ */
+ THR_THREAD_UNLOCK(curthread, pthread);
+ else {
+ pthread->base_priority = param->sched_priority;
+
+ /* Recalculate the active priority: */
+ pthread->active_priority = MAX(pthread->base_priority,
+ pthread->inherited_priority);
+
+ THR_THREAD_UNLOCK(curthread, pthread);
+ }
+ _thr_ref_delete(curthread, pthread);
+ }
+ return (ret);
+}
diff --git a/lib/libthr/thread/thr_sig.c b/lib/libthr/thread/thr_sig.c
new file mode 100644
index 0000000..865fb72
--- /dev/null
+++ b/lib/libthr/thread/thr_sig.c
@@ -0,0 +1,284 @@
+/*
+ * 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 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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, 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$
+ */
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/signalvar.h>
+#include <signal.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+/* #define DEBUG_SIGNAL */
+#ifdef DEBUG_SIGNAL
+#define DBG_MSG stdout_debug
+#else
+#define DBG_MSG(x...)
+#endif
+
+int __sigtimedwait(const sigset_t *set, siginfo_t *info,
+ const struct timespec * timeout);
+int __sigwaitinfo(const sigset_t *set, siginfo_t *info);
+int __sigwait(const sigset_t *set, int *sig);
+
+static void
+sigcancel_handler(int sig __unused,
+ siginfo_t *info __unused, ucontext_t *ucp __unused)
+{
+ struct pthread *curthread = _get_curthread();
+
+ _thr_ast(curthread);
+}
+
+void
+_thr_ast(struct pthread *curthread)
+{
+ if (!THR_IN_CRITICAL(curthread)) {
+ if (__predict_false(
+ SHOULD_ASYNC_CANCEL(curthread->cancelflags)))
+ _pthread_testcancel();
+ if (__predict_false((curthread->flags &
+ (THR_FLAGS_NEED_SUSPEND | THR_FLAGS_SUSPENDED))
+ == THR_FLAGS_NEED_SUSPEND))
+ _thr_suspend_check(curthread);
+ }
+}
+
+void
+_thr_suspend_check(struct pthread *curthread)
+{
+ umtx_t cycle;
+ int err;
+
+ err = errno;
+ /*
+ * Blocks SIGCANCEL which other threads must send.
+ */
+ _thr_signal_block(curthread);
+
+ /*
+ * Increase critical_count, here we don't use THR_LOCK/UNLOCK
+ * because we are leaf code, we don't want to recursively call
+ * ourself.
+ */
+ curthread->critical_count++;
+ THR_UMTX_LOCK(curthread, &(curthread)->lock);
+ while ((curthread->flags & (THR_FLAGS_NEED_SUSPEND |
+ THR_FLAGS_SUSPENDED)) == THR_FLAGS_NEED_SUSPEND) {
+ curthread->cycle++;
+ cycle = curthread->cycle;
+
+ /* Wake the thread suspending us. */
+ _thr_umtx_wake(&curthread->cycle, INT_MAX);
+
+ /*
+ * if we are from pthread_exit, we don't want to
+ * suspend, just go and die.
+ */
+ if (curthread->state == PS_DEAD)
+ break;
+ curthread->flags |= THR_FLAGS_SUSPENDED;
+ THR_UMTX_UNLOCK(curthread, &(curthread)->lock);
+ _thr_umtx_wait(&curthread->cycle, cycle, NULL);
+ THR_UMTX_LOCK(curthread, &(curthread)->lock);
+ curthread->flags &= ~THR_FLAGS_SUSPENDED;
+ }
+ THR_UMTX_UNLOCK(curthread, &(curthread)->lock);
+ curthread->critical_count--;
+
+ /*
+ * Unblocks SIGCANCEL, it is possible a new SIGCANCEL is ready and
+ * a new signal frame will nest us, this seems a problem because
+ * stack will grow and overflow, but because kernel will automatically
+ * mask the SIGCANCEL when delivering the signal, so we at most only
+ * have one nesting signal frame, this should be fine.
+ */
+ _thr_signal_unblock(curthread);
+ errno = err;
+}
+
+void
+_thr_signal_init(void)
+{
+ struct sigaction act;
+
+ /* Install cancel handler. */
+ SIGEMPTYSET(act.sa_mask);
+ act.sa_flags = SA_SIGINFO | SA_RESTART;
+ act.sa_sigaction = (__siginfohandler_t *)&sigcancel_handler;
+ __sys_sigaction(SIGCANCEL, &act, NULL);
+}
+
+void
+_thr_signal_deinit(void)
+{
+}
+
+__weak_reference(_sigaction, sigaction);
+
+int
+_sigaction(int sig, const struct sigaction * act, struct sigaction * oact)
+{
+ /* Check if the signal number is out of range: */
+ if (sig < 1 || sig > _SIG_MAXSIG || sig == SIGCANCEL) {
+ /* Return an invalid argument: */
+ errno = EINVAL;
+ return (-1);
+ }
+
+ return __sys_sigaction(sig, act, oact);
+}
+
+__weak_reference(_sigprocmask, sigprocmask);
+
+int
+_sigprocmask(int how, const sigset_t *set, sigset_t *oset)
+{
+ const sigset_t *p = set;
+ sigset_t newset;
+
+ if (how != SIG_UNBLOCK) {
+ if (set != NULL) {
+ newset = *set;
+ SIGDELSET(newset, SIGCANCEL);
+ p = &newset;
+ }
+ }
+ return (__sys_sigprocmask(how, p, oset));
+}
+
+__weak_reference(_pthread_sigmask, pthread_sigmask);
+
+int
+_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
+{
+ if (_sigprocmask(how, set, oset))
+ return (errno);
+ return (0);
+}
+
+__weak_reference(_sigsuspend, sigsuspend);
+
+int
+_sigsuspend(const sigset_t * set)
+{
+ struct pthread *curthread = _get_curthread();
+ sigset_t newset;
+ const sigset_t *pset;
+ int oldcancel;
+ int ret;
+
+ if (SIGISMEMBER(*set, SIGCANCEL)) {
+ newset = *set;
+ SIGDELSET(newset, SIGCANCEL);
+ pset = &newset;
+ } else
+ pset = set;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __sys_sigsuspend(pset);
+ _thr_cancel_leave(curthread, oldcancel);
+
+ return (ret);
+}
+
+__weak_reference(__sigwait, sigwait);
+__weak_reference(__sigtimedwait, sigtimedwait);
+__weak_reference(__sigwaitinfo, sigwaitinfo);
+
+int
+__sigtimedwait(const sigset_t *set, siginfo_t *info,
+ const struct timespec * timeout)
+{
+ struct pthread *curthread = _get_curthread();
+ sigset_t newset;
+ const sigset_t *pset;
+ int oldcancel;
+ int ret;
+
+ if (SIGISMEMBER(*set, SIGCANCEL)) {
+ newset = *set;
+ SIGDELSET(newset, SIGCANCEL);
+ pset = &newset;
+ } else
+ pset = set;
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __sys_sigtimedwait(pset, info, timeout);
+ _thr_cancel_leave(curthread, oldcancel);
+ return (ret);
+}
+
+int
+__sigwaitinfo(const sigset_t *set, siginfo_t *info)
+{
+ struct pthread *curthread = _get_curthread();
+ sigset_t newset;
+ const sigset_t *pset;
+ int oldcancel;
+ int ret;
+
+ if (SIGISMEMBER(*set, SIGCANCEL)) {
+ newset = *set;
+ SIGDELSET(newset, SIGCANCEL);
+ pset = &newset;
+ } else
+ pset = set;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __sys_sigwaitinfo(pset, info);
+ _thr_cancel_leave(curthread, oldcancel);
+ return (ret);
+}
+
+int
+__sigwait(const sigset_t *set, int *sig)
+{
+ struct pthread *curthread = _get_curthread();
+ sigset_t newset;
+ const sigset_t *pset;
+ int oldcancel;
+ int ret;
+
+ if (SIGISMEMBER(*set, SIGCANCEL)) {
+ newset = *set;
+ SIGDELSET(newset, SIGCANCEL);
+ pset = &newset;
+ } else
+ pset = set;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __sys_sigwait(pset, sig);
+ _thr_cancel_leave(curthread, oldcancel);
+ return (ret);
+}
diff --git a/lib/libthr/thread/thr_sigmask.c b/lib/libthr/thread/thr_sigmask.c
new file mode 100644
index 0000000..2024cc0
--- /dev/null
+++ b/lib/libthr/thread/thr_sigmask.c
@@ -0,0 +1,52 @@
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <errno.h>
+#include <signal.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+__weak_reference(_pthread_sigmask, pthread_sigmask);
+
+extern int
+_sigprocmask(int how, const sigset_t *set, sigset_t *oset);
+
+int
+_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
+{
+ /* use our overridden verion of _sigprocmask */
+ if (_sigprocmask(how, set, oset))
+ return (errno);
+ return (0);
+}
diff --git a/lib/libthr/thread/thr_single_np.c b/lib/libthr/thread/thr_single_np.c
new file mode 100644
index 0000000..c74fc55
--- /dev/null
+++ b/lib/libthr/thread/thr_single_np.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1996 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <pthread.h>
+#include <pthread_np.h>
+#include "un-namespace.h"
+
+__weak_reference(_pthread_single_np, pthread_single_np);
+
+int _pthread_single_np()
+{
+
+ /* Enter single-threaded (non-POSIX) scheduling mode: */
+ _pthread_suspend_all_np();
+ /*
+ * XXX - Do we want to do this?
+ * __is_threaded = 0;
+ */
+ return (0);
+}
diff --git a/lib/libthr/thread/thr_spec.c b/lib/libthr/thread/thr_spec.c
new file mode 100644
index 0000000..cd4d49f
--- /dev/null
+++ b/lib/libthr/thread/thr_spec.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+/* Static variables: */
+struct pthread_key _thread_keytable[PTHREAD_KEYS_MAX];
+
+__weak_reference(_pthread_key_create, pthread_key_create);
+__weak_reference(_pthread_key_delete, pthread_key_delete);
+__weak_reference(_pthread_getspecific, pthread_getspecific);
+__weak_reference(_pthread_setspecific, pthread_setspecific);
+
+
+int
+_pthread_key_create(pthread_key_t *key, void (*destructor) (void *))
+{
+ struct pthread *curthread = _get_curthread();
+ int i;
+
+ /* Lock the key table: */
+ THR_LOCK_ACQUIRE(curthread, &_keytable_lock);
+ for (i = 0; i < PTHREAD_KEYS_MAX; i++) {
+
+ if (_thread_keytable[i].allocated == 0) {
+ _thread_keytable[i].allocated = 1;
+ _thread_keytable[i].destructor = destructor;
+ _thread_keytable[i].seqno++;
+
+ /* Unlock the key table: */
+ THR_LOCK_RELEASE(curthread, &_keytable_lock);
+ *key = i;
+ return (0);
+ }
+
+ }
+ /* Unlock the key table: */
+ THR_LOCK_RELEASE(curthread, &_keytable_lock);
+ return (EAGAIN);
+}
+
+int
+_pthread_key_delete(pthread_key_t key)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret = 0;
+
+ if ((unsigned int)key < PTHREAD_KEYS_MAX) {
+ /* Lock the key table: */
+ THR_LOCK_ACQUIRE(curthread, &_keytable_lock);
+
+ if (_thread_keytable[key].allocated)
+ _thread_keytable[key].allocated = 0;
+ else
+ ret = EINVAL;
+
+ /* Unlock the key table: */
+ THR_LOCK_RELEASE(curthread, &_keytable_lock);
+ } else
+ ret = EINVAL;
+ return (ret);
+}
+
+void
+_thread_cleanupspecific(void)
+{
+ struct pthread *curthread = _get_curthread();
+ void (*destructor)( void *);
+ const void *data = NULL;
+ int key;
+ int i;
+
+ if (curthread->specific == NULL)
+ return;
+
+ /* Lock the key table: */
+ THR_LOCK_ACQUIRE(curthread, &_keytable_lock);
+ for (i = 0; (i < PTHREAD_DESTRUCTOR_ITERATIONS) &&
+ (curthread->specific_data_count > 0); i++) {
+ for (key = 0; (key < PTHREAD_KEYS_MAX) &&
+ (curthread->specific_data_count > 0); key++) {
+ destructor = NULL;
+
+ if (_thread_keytable[key].allocated &&
+ (curthread->specific[key].data != NULL)) {
+ if (curthread->specific[key].seqno ==
+ _thread_keytable[key].seqno) {
+ data = curthread->specific[key].data;
+ destructor = _thread_keytable[key].destructor;
+ }
+ curthread->specific[key].data = NULL;
+ curthread->specific_data_count--;
+ }
+
+ /*
+ * If there is a destructore, call it
+ * with the key table entry unlocked:
+ */
+ if (destructor != NULL) {
+ /*
+ * Don't hold the lock while calling the
+ * destructor:
+ */
+ THR_LOCK_RELEASE(curthread, &_keytable_lock);
+ destructor(__DECONST(void *, data));
+ THR_LOCK_ACQUIRE(curthread, &_keytable_lock);
+ }
+ }
+ }
+ THR_LOCK_RELEASE(curthread, &_keytable_lock);
+ free(curthread->specific);
+ curthread->specific = NULL;
+ if (curthread->specific_data_count > 0)
+ stderr_debug("Thread %p has exited with leftover "
+ "thread-specific data after %d destructor iterations\n",
+ curthread, PTHREAD_DESTRUCTOR_ITERATIONS);
+}
+
+static inline struct pthread_specific_elem *
+pthread_key_allocate_data(void)
+{
+ struct pthread_specific_elem *new_data;
+
+ new_data = (struct pthread_specific_elem *)
+ malloc(sizeof(struct pthread_specific_elem) * PTHREAD_KEYS_MAX);
+ if (new_data != NULL) {
+ memset((void *) new_data, 0,
+ sizeof(struct pthread_specific_elem) * PTHREAD_KEYS_MAX);
+ }
+ return (new_data);
+}
+
+int
+_pthread_setspecific(pthread_key_t key, const void *value)
+{
+ struct pthread *pthread;
+ int ret = 0;
+
+ /* Point to the running thread: */
+ pthread = _get_curthread();
+
+ if ((pthread->specific) ||
+ (pthread->specific = pthread_key_allocate_data())) {
+ if ((unsigned int)key < PTHREAD_KEYS_MAX) {
+ if (_thread_keytable[key].allocated) {
+ if (pthread->specific[key].data == NULL) {
+ if (value != NULL)
+ pthread->specific_data_count++;
+ } else if (value == NULL)
+ pthread->specific_data_count--;
+ pthread->specific[key].data = value;
+ pthread->specific[key].seqno =
+ _thread_keytable[key].seqno;
+ ret = 0;
+ } else
+ ret = EINVAL;
+ } else
+ ret = EINVAL;
+ } else
+ ret = ENOMEM;
+ return (ret);
+}
+
+void *
+_pthread_getspecific(pthread_key_t key)
+{
+ struct pthread *pthread;
+ const void *data;
+
+ /* Point to the running thread: */
+ pthread = _get_curthread();
+
+ /* Check if there is specific data: */
+ if (pthread->specific != NULL && (unsigned int)key < PTHREAD_KEYS_MAX) {
+ /* Check if this key has been used before: */
+ if (_thread_keytable[key].allocated &&
+ (pthread->specific[key].seqno == _thread_keytable[key].seqno)) {
+ /* Return the value: */
+ data = pthread->specific[key].data;
+ } else {
+ /*
+ * This key has not been used before, so return NULL
+ * instead:
+ */
+ data = NULL;
+ }
+ } else
+ /* No specific data has been created, so just return NULL: */
+ data = NULL;
+ return (__DECONST(void *, data));
+}
diff --git a/lib/libthr/thread/thr_spinlock.c b/lib/libthr/thread/thr_spinlock.c
new file mode 100644
index 0000000..b9d2279
--- /dev/null
+++ b/lib/libthr/thread/thr_spinlock.c
@@ -0,0 +1,126 @@
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <pthread.h>
+#include <libc_private.h>
+#include <spinlock.h>
+
+#include "thr_private.h"
+
+#define MAX_SPINLOCKS 72
+
+/*
+ * These data structures are used to trace all spinlocks
+ * in libc.
+ */
+struct spinlock_extra {
+ spinlock_t *owner;
+};
+
+static umtx_t spinlock_static_lock;
+static struct spinlock_extra extra[MAX_SPINLOCKS];
+static int spinlock_count;
+static int initialized;
+
+static void init_spinlock(spinlock_t *lck);
+
+/*
+ * These are for compatability only. Spinlocks of this type
+ * are deprecated.
+ */
+
+void
+_spinunlock(spinlock_t *lck)
+{
+ THR_UMTX_UNLOCK(_get_curthread(), (volatile umtx_t *)&lck->access_lock);
+}
+
+void
+_spinlock(spinlock_t *lck)
+{
+ if (!__isthreaded)
+ PANIC("Spinlock called when not threaded.");
+ if (!initialized)
+ PANIC("Spinlocks not initialized.");
+ if (lck->fname == NULL)
+ init_spinlock(lck);
+ THR_UMTX_LOCK(_get_curthread(), (volatile umtx_t *)&lck->access_lock);
+}
+
+void
+_spinlock_debug(spinlock_t *lck, char *fname __unused, int lineno __unused)
+{
+ _spinlock(lck);
+}
+
+static void
+init_spinlock(spinlock_t *lck)
+{
+ static int count = 0;
+
+ THR_UMTX_LOCK(_get_curthread(), &spinlock_static_lock);
+ if ((lck->fname == NULL) && (spinlock_count < MAX_SPINLOCKS)) {
+ lck->fname = (char *)&extra[spinlock_count];
+ extra[spinlock_count].owner = lck;
+ spinlock_count++;
+ }
+ THR_UMTX_UNLOCK(_get_curthread(), &spinlock_static_lock);
+ if (lck->fname == NULL && ++count < 5)
+ stderr_debug("Warning: exceeded max spinlocks");
+}
+
+void
+_thr_spinlock_init(void)
+{
+ int i;
+
+ _thr_umtx_init(&spinlock_static_lock);
+ if (initialized != 0) {
+ /*
+ * called after fork() to reset state of libc spin locks,
+ * it is not quite right since libc may be in inconsistent
+ * state, resetting the locks to allow current thread to be
+ * able to hold them may not help things too much, but
+ * anyway, we do our best.
+ * it is better to do pthread_atfork in libc.
+ */
+ for (i = 0; i < spinlock_count; i++)
+ _thr_umtx_init((volatile umtx_t *)
+ &extra[i].owner->access_lock);
+ } else {
+ initialized = 1;
+ }
+}
diff --git a/lib/libthr/thread/thr_stack.c b/lib/libthr/thread/thr_stack.c
new file mode 100644
index 0000000..9376086
--- /dev/null
+++ b/lib/libthr/thread/thr_stack.c
@@ -0,0 +1,256 @@
+/*
+ * Copyright (c) 2001 Daniel Eischen <deischen@freebsd.org>
+ * Copyright (c) 2000-2001 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, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/queue.h>
+#include <stdlib.h>
+#include <pthread.h>
+
+#include "thr_private.h"
+
+/* Spare thread stack. */
+struct stack {
+ LIST_ENTRY(stack) qe; /* Stack queue linkage. */
+ size_t stacksize; /* Stack size (rounded up). */
+ size_t guardsize; /* Guard size. */
+ void *stackaddr; /* Stack address. */
+};
+
+/*
+ * Default sized (stack and guard) spare stack queue. Stacks are cached
+ * to avoid additional complexity managing mmap()ed stack regions. Spare
+ * stacks are used in LIFO order to increase cache locality.
+ */
+static LIST_HEAD(, stack) dstackq = LIST_HEAD_INITIALIZER(dstackq);
+
+/*
+ * Miscellaneous sized (non-default stack and/or guard) spare stack queue.
+ * Stacks are cached to avoid additional complexity managing mmap()ed
+ * stack regions. This list is unordered, since ordering on both stack
+ * size and guard size would be more trouble than it's worth. Stacks are
+ * allocated from this cache on a first size match basis.
+ */
+static LIST_HEAD(, stack) mstackq = LIST_HEAD_INITIALIZER(mstackq);
+
+/**
+ * Base address of the last stack allocated (including its red zone, if
+ * there is one). Stacks are allocated contiguously, starting beyond the
+ * top of the main stack. When a new stack is created, a red zone is
+ * typically created (actually, the red zone is mapped with PROT_NONE) above
+ * the top of the stack, such that the stack will not be able to grow all
+ * the way to the bottom of the next stack. This isn't fool-proof. It is
+ * possible for a stack to grow by a large amount, such that it grows into
+ * the next stack, and as long as the memory within the red zone is never
+ * accessed, nothing will prevent one thread stack from trouncing all over
+ * the next.
+ *
+ * low memory
+ * . . . . . . . . . . . . . . . . . .
+ * | |
+ * | stack 3 | start of 3rd thread stack
+ * +-----------------------------------+
+ * | |
+ * | Red Zone (guard page) | red zone for 2nd thread
+ * | |
+ * +-----------------------------------+
+ * | stack 2 - _thr_stack_default | top of 2nd thread stack
+ * | |
+ * | |
+ * | |
+ * | |
+ * | stack 2 |
+ * +-----------------------------------+ <-- start of 2nd thread stack
+ * | |
+ * | Red Zone | red zone for 1st thread
+ * | |
+ * +-----------------------------------+
+ * | stack 1 - _thr_stack_default | top of 1st thread stack
+ * | |
+ * | |
+ * | |
+ * | |
+ * | stack 1 |
+ * +-----------------------------------+ <-- start of 1st thread stack
+ * | | (initial value of last_stack)
+ * | Red Zone |
+ * | | red zone for main thread
+ * +-----------------------------------+
+ * | USRSTACK - _thr_stack_initial | top of main thread stack
+ * | | ^
+ * | | |
+ * | | |
+ * | | | stack growth
+ * | |
+ * +-----------------------------------+ <-- start of main thread stack
+ * (USRSTACK)
+ * high memory
+ *
+ */
+static char *last_stack = NULL;
+
+/*
+ * Round size up to the nearest multiple of
+ * _thr_page_size.
+ */
+static inline size_t
+round_up(size_t size)
+{
+ if (size % _thr_page_size != 0)
+ size = ((size / _thr_page_size) + 1) *
+ _thr_page_size;
+ return size;
+}
+
+int
+_thr_stack_alloc(struct pthread_attr *attr)
+{
+ struct pthread *curthread = _get_curthread();
+ struct stack *spare_stack;
+ size_t stacksize;
+ size_t guardsize;
+ char *stackaddr;
+
+ /*
+ * Round up stack size to nearest multiple of _thr_page_size so
+ * that mmap() * will work. If the stack size is not an even
+ * multiple, we end up initializing things such that there is
+ * unused space above the beginning of the stack, so the stack
+ * sits snugly against its guard.
+ */
+ stacksize = round_up(attr->stacksize_attr);
+ guardsize = round_up(attr->guardsize_attr);
+
+ attr->stackaddr_attr = NULL;
+ attr->flags &= ~THR_STACK_USER;
+
+ /*
+ * Use the garbage collector lock for synchronization of the
+ * spare stack lists and allocations from usrstack.
+ */
+ THREAD_LIST_LOCK(curthread);
+ /*
+ * If the stack and guard sizes are default, try to allocate a stack
+ * from the default-size stack cache:
+ */
+ if ((stacksize == THR_STACK_DEFAULT) &&
+ (guardsize == _thr_guard_default)) {
+ if ((spare_stack = LIST_FIRST(&dstackq)) != NULL) {
+ /* Use the spare stack. */
+ LIST_REMOVE(spare_stack, qe);
+ attr->stackaddr_attr = spare_stack->stackaddr;
+ }
+ }
+ /*
+ * The user specified a non-default stack and/or guard size, so try to
+ * allocate a stack from the non-default size stack cache, using the
+ * rounded up stack size (stack_size) in the search:
+ */
+ else {
+ LIST_FOREACH(spare_stack, &mstackq, qe) {
+ if (spare_stack->stacksize == stacksize &&
+ spare_stack->guardsize == guardsize) {
+ LIST_REMOVE(spare_stack, qe);
+ attr->stackaddr_attr = spare_stack->stackaddr;
+ break;
+ }
+ }
+ }
+ if (attr->stackaddr_attr != NULL) {
+ /* A cached stack was found. Release the lock. */
+ THREAD_LIST_UNLOCK(curthread);
+ }
+ else {
+ /* Allocate a stack from usrstack. */
+ if (last_stack == NULL)
+ last_stack = _usrstack - _thr_stack_initial -
+ _thr_guard_default;
+
+ /* Allocate a new stack. */
+ stackaddr = last_stack - stacksize - guardsize;
+
+ /*
+ * Even if stack allocation fails, we don't want to try to
+ * use this location again, so unconditionally decrement
+ * last_stack. Under normal operating conditions, the most
+ * likely reason for an mmap() error is a stack overflow of
+ * the adjacent thread stack.
+ */
+ last_stack -= (stacksize + guardsize);
+
+ /* Release the lock before mmap'ing it. */
+ THREAD_LIST_UNLOCK(curthread);
+
+ /* Map the stack and guard page together, and split guard
+ page from allocated space: */
+ if ((stackaddr = mmap(stackaddr, stacksize+guardsize,
+ PROT_READ | PROT_WRITE, MAP_STACK,
+ -1, 0)) != MAP_FAILED &&
+ (guardsize == 0 ||
+ mprotect(stackaddr, guardsize, PROT_NONE) == 0)) {
+ stackaddr += guardsize;
+ } else {
+ if (stackaddr != MAP_FAILED)
+ munmap(stackaddr, stacksize + guardsize);
+ stackaddr = NULL;
+ }
+ attr->stackaddr_attr = stackaddr;
+ }
+ if (attr->stackaddr_attr != NULL)
+ return (0);
+ else
+ return (-1);
+}
+
+/* This function must be called with _thread_list_lock held. */
+void
+_thr_stack_free(struct pthread_attr *attr)
+{
+ struct stack *spare_stack;
+
+ if ((attr != NULL) && ((attr->flags & THR_STACK_USER) == 0)
+ && (attr->stackaddr_attr != NULL)) {
+ spare_stack = (struct stack *)
+ ((char *)attr->stackaddr_attr +
+ attr->stacksize_attr - sizeof(struct stack));
+ spare_stack->stacksize = round_up(attr->stacksize_attr);
+ spare_stack->guardsize = round_up(attr->guardsize_attr);
+ spare_stack->stackaddr = attr->stackaddr_attr;
+
+ if (spare_stack->stacksize == THR_STACK_DEFAULT &&
+ spare_stack->guardsize == _thr_guard_default) {
+ /* Default stack/guard size. */
+ LIST_INSERT_HEAD(&dstackq, spare_stack, qe);
+ } else {
+ /* Non-default stack/guard size. */
+ LIST_INSERT_HEAD(&mstackq, spare_stack, qe);
+ }
+ attr->stackaddr_attr = NULL;
+ }
+}
diff --git a/lib/libthr/thread/thr_suspend_np.c b/lib/libthr/thread/thr_suspend_np.c
new file mode 100644
index 0000000..ec34029
--- /dev/null
+++ b/lib/libthr/thread/thr_suspend_np.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <errno.h>
+#include <pthread.h>
+#include <pthread_np.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+static int suspend_common(struct pthread *, struct pthread *,
+ int);
+
+__weak_reference(_pthread_suspend_np, pthread_suspend_np);
+__weak_reference(_pthread_suspend_all_np, pthread_suspend_all_np);
+
+/* Suspend a thread: */
+int
+_pthread_suspend_np(pthread_t thread)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ /* Suspending the current thread doesn't make sense. */
+ if (thread == _get_curthread())
+ ret = EDEADLK;
+
+ /* Add a reference to the thread: */
+ else if ((ret = _thr_ref_add(curthread, thread, /*include dead*/0))
+ == 0) {
+ /* Lock the threads scheduling queue: */
+ THR_THREAD_LOCK(curthread, thread);
+ suspend_common(curthread, thread, 1);
+ /* Unlock the threads scheduling queue: */
+ THR_THREAD_UNLOCK(curthread, thread);
+
+ /* Don't forget to remove the reference: */
+ _thr_ref_delete(curthread, thread);
+ }
+ return (ret);
+}
+
+void
+_pthread_suspend_all_np(void)
+{
+ struct pthread *curthread = _get_curthread();
+ struct pthread *thread;
+ int ret;
+
+ THREAD_LIST_LOCK(curthread);
+
+ TAILQ_FOREACH(thread, &_thread_list, tle) {
+ if (thread != curthread) {
+ THR_THREAD_LOCK(curthread, thread);
+ if (thread->state != PS_DEAD &&
+ !(thread->flags & THR_FLAGS_SUSPENDED))
+ thread->flags |= THR_FLAGS_NEED_SUSPEND;
+ THR_THREAD_UNLOCK(curthread, thread);
+ }
+ }
+ thr_kill(-1, SIGCANCEL);
+
+restart:
+ TAILQ_FOREACH(thread, &_thread_list, tle) {
+ if (thread != curthread) {
+ /* First try to suspend the thread without waiting */
+ THR_THREAD_LOCK(curthread, thread);
+ ret = suspend_common(curthread, thread, 0);
+ if (ret == 0) {
+ /* Can not suspend, try to wait */
+ thread->refcount++;
+ THREAD_LIST_UNLOCK(curthread);
+ suspend_common(curthread, thread, 1);
+ THR_THREAD_UNLOCK(curthread, thread);
+ THREAD_LIST_LOCK(curthread);
+ _thr_ref_delete_unlocked(curthread, thread);
+ /*
+ * Because we were blocked, things may have
+ * been changed, we have to restart the
+ * process.
+ */
+ goto restart;
+ }
+ THR_THREAD_UNLOCK(curthread, thread);
+ }
+ }
+
+ THREAD_LIST_UNLOCK(curthread);
+}
+
+static int
+suspend_common(struct pthread *curthread, struct pthread *thread,
+ int waitok)
+{
+ umtx_t tmp;
+
+ while (thread->state != PS_DEAD &&
+ !(thread->flags & THR_FLAGS_SUSPENDED)) {
+ thread->flags |= THR_FLAGS_NEED_SUSPEND;
+ tmp = thread->cycle;
+ THR_THREAD_UNLOCK(curthread, thread);
+ _thr_send_sig(thread, SIGCANCEL);
+ if (waitok) {
+ _thr_umtx_wait(&thread->cycle, tmp, NULL);
+ THR_THREAD_LOCK(curthread, thread);
+ } else {
+ THR_THREAD_LOCK(curthread, thread);
+ return (0);
+ }
+ }
+
+ return (1);
+}
diff --git a/lib/libthr/thread/thr_switch_np.c b/lib/libthr/thread/thr_switch_np.c
new file mode 100644
index 0000000..f6ffb07
--- /dev/null
+++ b/lib/libthr/thread/thr_switch_np.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+
+#include "namespace.h"
+#include <errno.h>
+#include <pthread.h>
+#include <pthread_np.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+
+__weak_reference(_pthread_switch_add_np, pthread_switch_add_np);
+__weak_reference(_pthread_switch_delete_np, pthread_switch_delete_np);
+
+int
+_pthread_switch_add_np(pthread_switch_routine_t routine __unused)
+{
+ return (ENOTSUP);
+}
+
+int
+_pthread_switch_delete_np(pthread_switch_routine_t routine __unused)
+{
+ return (ENOTSUP);
+}
diff --git a/lib/libthr/thread/thr_symbols.c b/lib/libthr/thread/thr_symbols.c
new file mode 100644
index 0000000..ca6606a
--- /dev/null
+++ b/lib/libthr/thread/thr_symbols.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2004 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <stddef.h>
+#include <pthread.h>
+#include <rtld.h>
+
+#include "thr_private.h"
+
+/* A collection of symbols needed by debugger */
+
+/* int _libthr_debug */
+int _thread_off_tcb = offsetof(struct pthread, tcb);
+int _thread_off_tid = offsetof(struct pthread, tid);
+int _thread_off_next = offsetof(struct pthread, tle.tqe_next);
+int _thread_off_attr_flags = offsetof(struct pthread, attr.flags);
+int _thread_off_linkmap = offsetof(Obj_Entry, linkmap);
+int _thread_off_tlsindex = offsetof(Obj_Entry, tlsindex);
+int _thread_off_report_events = offsetof(struct pthread, report_events);
+int _thread_off_event_mask = offsetof(struct pthread, event_mask);
+int _thread_off_event_buf = offsetof(struct pthread, event_buf);
+int _thread_size_key = sizeof(struct pthread_key);
+int _thread_off_key_allocated = offsetof(struct pthread_key, allocated);
+int _thread_off_key_destructor = offsetof(struct pthread_key, destructor);
+int _thread_max_keys = PTHREAD_KEYS_MAX;
+int _thread_off_dtv = DTV_OFFSET;
+int _thread_off_state = offsetof(struct pthread, state);
+int _thread_state_running = PS_RUNNING;
+int _thread_state_zoombie = PS_DEAD;
diff --git a/lib/libthr/thread/thr_syscalls.c b/lib/libthr/thread/thr_syscalls.c
new file mode 100644
index 0000000..a36849a
--- /dev/null
+++ b/lib/libthr/thread/thr_syscalls.c
@@ -0,0 +1,675 @@
+/*
+ * Copyright (C) 2005 David Xu <davidxu@freebsd.org>.
+ * Copyright (c) 2003 Daniel Eischen <deischen@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$
+ */
+
+/*
+ * Copyright (c) 1995-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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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/types.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <sys/select.h>
+#include <sys/signalvar.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <aio.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+extern int __creat(const char *, mode_t);
+extern int __pause(void);
+extern int __pselect(int, fd_set *, fd_set *, fd_set *,
+ const struct timespec *, const sigset_t *);
+extern unsigned __sleep(unsigned int);
+extern int __system(const char *);
+extern int __tcdrain(int);
+extern int __usleep(useconds_t);
+extern pid_t __wait(int *);
+extern pid_t __waitpid(pid_t, int *, int);
+extern int __sys_aio_suspend(const struct aiocb * const[], int,
+ const struct timespec *);
+extern int __sys_accept(int, struct sockaddr *, socklen_t *);
+extern int __sys_connect(int, const struct sockaddr *, socklen_t);
+extern int __sys_fsync(int);
+extern int __sys_msync(void *, size_t, int);
+extern int __sys_poll(struct pollfd *, unsigned, int);
+extern ssize_t __sys_recv(int, void *, size_t, int);
+extern ssize_t __sys_recvfrom(int, void *, size_t, int, struct sockaddr *, socklen_t *);
+extern ssize_t __sys_recvmsg(int, struct msghdr *, int);
+extern int __sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
+extern int __sys_sendfile(int, int, off_t, size_t, struct sf_hdtr *,
+ off_t *, int);
+extern ssize_t __sys_sendmsg(int, const struct msghdr *, int);
+extern ssize_t __sys_sendto(int, const void *,size_t, int, const struct sockaddr *, socklen_t);
+extern ssize_t __sys_readv(int, const struct iovec *, int);
+extern pid_t __sys_wait4(pid_t, int *, int, struct rusage *);
+extern ssize_t __sys_writev(int, const struct iovec *, int);
+
+int ___creat(const char *, mode_t);
+int __accept(int, struct sockaddr *, socklen_t *);
+int __close(int);
+int __connect(int, const struct sockaddr *, socklen_t);
+int __fcntl(int, int,...);
+int __fsync(int);
+int __msync(void *, size_t, int);
+int __nanosleep(const struct timespec *, struct timespec *);
+int __open(const char *, int,...);
+int __poll(struct pollfd *, unsigned int, int);
+ssize_t __read(int, void *buf, size_t);
+ssize_t __readv(int, const struct iovec *, int);
+ssize_t __recvfrom(int, void *, size_t, int f, struct sockaddr *, socklen_t *);
+ssize_t __recvmsg(int, struct msghdr *, int);
+int __select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
+ssize_t __sendmsg(int, const struct msghdr *, int);
+ssize_t __sendto(int, const void *, size_t, int,
+ const struct sockaddr *, socklen_t);
+pid_t __wait4(pid_t, int *, int, struct rusage *);
+ssize_t __write(int, const void *, size_t);
+ssize_t __writev(int, const struct iovec *, int);
+int _aio_suspend(const struct aiocb * const iocbs[], int,
+ const struct timespec *);
+int _pause(void);
+int _pselect(int, fd_set *, fd_set *, fd_set *,
+ const struct timespec *, const sigset_t *);
+int _raise(int);
+unsigned _sleep(unsigned);
+int _system(const char *);
+int _tcdrain(int);
+int _vfork(void);
+pid_t _wait(int *);
+
+
+__weak_reference(__accept, accept);
+
+int
+__accept(int s, struct sockaddr *addr, socklen_t *addrlen)
+{
+ struct pthread *curthread;
+ int oldcancel;
+ int ret;
+
+ curthread = _get_curthread();
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __sys_accept(s, addr, addrlen);
+ _thr_cancel_leave(curthread, oldcancel);
+
+ return (ret);
+}
+
+__weak_reference(_aio_suspend, aio_suspend);
+
+int
+_aio_suspend(const struct aiocb * const iocbs[], int niocb, const struct
+ timespec *timeout)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldcancel;
+ int ret;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __sys_aio_suspend(iocbs, niocb, timeout);
+ _thr_cancel_leave(curthread, oldcancel);
+
+ return (ret);
+}
+
+__weak_reference(__close, close);
+
+int
+__close(int fd)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldcancel;
+ int ret;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __sys_close(fd);
+ _thr_cancel_leave(curthread, oldcancel);
+
+ return (ret);
+}
+
+__weak_reference(__connect, connect);
+
+int
+__connect(int fd, const struct sockaddr *name, socklen_t namelen)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldcancel;
+ int ret;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __sys_connect(fd, name, namelen);
+ _thr_cancel_leave(curthread, oldcancel);
+
+ return (ret);
+}
+
+__weak_reference(___creat, creat);
+
+int
+___creat(const char *path, mode_t mode)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldcancel;
+ int ret;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __creat(path, mode);
+ _thr_cancel_leave(curthread, oldcancel);
+
+ return ret;
+}
+
+__weak_reference(__fcntl, fcntl);
+
+int
+__fcntl(int fd, int cmd,...)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldcancel;
+ int ret;
+ va_list ap;
+
+ oldcancel = _thr_cancel_enter(curthread);
+
+ va_start(ap, cmd);
+ switch (cmd) {
+ case F_DUPFD:
+ ret = __sys_fcntl(fd, cmd, va_arg(ap, int));
+ break;
+ case F_SETFD:
+ case F_SETFL:
+ ret = __sys_fcntl(fd, cmd, va_arg(ap, int));
+ break;
+ case F_GETFD:
+ case F_GETFL:
+ ret = __sys_fcntl(fd, cmd);
+ break;
+ default:
+ ret = __sys_fcntl(fd, cmd, va_arg(ap, void *));
+ }
+ va_end(ap);
+
+ _thr_cancel_leave(curthread, oldcancel);
+
+ return (ret);
+}
+
+__weak_reference(__fsync, fsync);
+
+int
+__fsync(int fd)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldcancel;
+ int ret;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __sys_fsync(fd);
+ _thr_cancel_leave(curthread, oldcancel);
+
+ return (ret);
+}
+
+__weak_reference(__msync, msync);
+
+int
+__msync(void *addr, size_t len, int flags)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldcancel;
+ int ret;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __sys_msync(addr, len, flags);
+ _thr_cancel_leave(curthread, oldcancel);
+
+ return ret;
+}
+
+__weak_reference(__nanosleep, nanosleep);
+
+int
+__nanosleep(const struct timespec *time_to_sleep,
+ struct timespec *time_remaining)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldcancel;
+ int ret;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __sys_nanosleep(time_to_sleep, time_remaining);
+ _thr_cancel_leave(curthread, oldcancel);
+
+ return (ret);
+}
+
+__weak_reference(__open, open);
+
+int
+__open(const char *path, int flags,...)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldcancel;
+ int ret;
+ int mode = 0;
+ va_list ap;
+
+ oldcancel = _thr_cancel_enter(curthread);
+
+ /* Check if the file is being created: */
+ if (flags & O_CREAT) {
+ /* Get the creation mode: */
+ va_start(ap, flags);
+ mode = va_arg(ap, int);
+ va_end(ap);
+ }
+
+ ret = __sys_open(path, flags, mode);
+
+ _thr_cancel_leave(curthread, oldcancel);
+
+ return ret;
+}
+
+__weak_reference(_pause, pause);
+
+int
+_pause(void)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldcancel;
+ int ret;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __pause();
+ _thr_cancel_leave(curthread, oldcancel);
+
+ return ret;
+}
+
+__weak_reference(__poll, poll);
+
+int
+__poll(struct pollfd *fds, unsigned int nfds, int timeout)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldcancel;
+ int ret;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __sys_poll(fds, nfds, timeout);
+ _thr_cancel_leave(curthread, oldcancel);
+
+ return ret;
+}
+
+__weak_reference(_pselect, pselect);
+
+int
+_pselect(int count, fd_set *rfds, fd_set *wfds, fd_set *efds,
+ const struct timespec *timo, const sigset_t *mask)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldcancel;
+ int ret;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __pselect(count, rfds, wfds, efds, timo, mask);
+ _thr_cancel_leave(curthread, oldcancel);
+
+ return (ret);
+}
+
+__weak_reference(_raise, raise);
+
+int
+_raise(int sig)
+{
+ int ret;
+
+ if (!_thr_isthreaded())
+ ret = kill(getpid(), sig);
+ else
+ ret = _thr_send_sig(_get_curthread(), sig);
+ return (ret);
+}
+
+__weak_reference(__read, read);
+
+ssize_t
+__read(int fd, void *buf, size_t nbytes)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldcancel;
+ ssize_t ret;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __sys_read(fd, buf, nbytes);
+ _thr_cancel_leave(curthread, oldcancel);
+
+ return ret;
+}
+
+__weak_reference(__readv, readv);
+
+ssize_t
+__readv(int fd, const struct iovec *iov, int iovcnt)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldcancel;
+ ssize_t ret;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __sys_readv(fd, iov, iovcnt);
+ _thr_cancel_leave(curthread, oldcancel);
+
+ return ret;
+}
+
+__weak_reference(__recvfrom, recvfrom);
+
+ssize_t
+__recvfrom(int s, void *b, size_t l, int f, struct sockaddr *from,
+ socklen_t *fl)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldcancel;
+ ssize_t ret;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __sys_recvfrom(s, b, l, f, from, fl);
+ _thr_cancel_leave(curthread, oldcancel);
+ return (ret);
+}
+
+__weak_reference(__recvmsg, recvmsg);
+
+ssize_t
+__recvmsg(int s, struct msghdr *m, int f)
+{
+ struct pthread *curthread = _get_curthread();
+ ssize_t ret;
+ int oldcancel;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __sys_recvmsg(s, m, f);
+ _thr_cancel_leave(curthread, oldcancel);
+ return (ret);
+}
+
+__weak_reference(__select, select);
+
+int
+__select(int numfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+ struct timeval *timeout)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldcancel;
+ int ret;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __sys_select(numfds, readfds, writefds, exceptfds, timeout);
+ _thr_cancel_leave(curthread, oldcancel);
+ return ret;
+}
+
+__weak_reference(__sendmsg, sendmsg);
+
+ssize_t
+__sendmsg(int s, const struct msghdr *m, int f)
+{
+ struct pthread *curthread = _get_curthread();
+ ssize_t ret;
+ int oldcancel;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __sys_sendmsg(s, m, f);
+ _thr_cancel_leave(curthread, oldcancel);
+ return (ret);
+}
+
+__weak_reference(__sendto, sendto);
+
+ssize_t
+__sendto(int s, const void *m, size_t l, int f, const struct sockaddr *t,
+ socklen_t tl)
+{
+ struct pthread *curthread = _get_curthread();
+ ssize_t ret;
+ int oldcancel;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __sys_sendto(s, m, l, f, t, tl);
+ _thr_cancel_leave(curthread, oldcancel);
+ return (ret);
+}
+
+__weak_reference(_sleep, sleep);
+
+unsigned int
+_sleep(unsigned int seconds)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldcancel;
+ unsigned int ret;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __sleep(seconds);
+ _thr_cancel_leave(curthread, oldcancel);
+
+ return (ret);
+}
+
+__weak_reference(_system, system);
+
+int
+_system(const char *string)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldcancel;
+ int ret;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __system(string);
+ _thr_cancel_leave(curthread, oldcancel);
+
+ return ret;
+}
+
+__weak_reference(_tcdrain, tcdrain);
+
+int
+_tcdrain(int fd)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldcancel;
+ int ret;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __tcdrain(fd);
+ _thr_cancel_leave(curthread, oldcancel);
+
+ return (ret);
+}
+
+__weak_reference(_usleep, usleep);
+
+int
+_usleep(useconds_t useconds)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldcancel;
+ int ret;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __usleep(useconds);
+ _thr_cancel_leave(curthread, oldcancel);
+
+ return (ret);
+}
+
+__weak_reference(_vfork, vfork);
+
+int
+_vfork(void)
+{
+ return (fork());
+}
+
+__weak_reference(_wait, wait);
+
+pid_t
+_wait(int *istat)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldcancel;
+ pid_t ret;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __wait(istat);
+ _thr_cancel_leave(curthread, oldcancel);
+
+ return ret;
+}
+
+__weak_reference(__wait4, wait4);
+
+pid_t
+__wait4(pid_t pid, int *istat, int options, struct rusage *rusage)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldcancel;
+ pid_t ret;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __sys_wait4(pid, istat, options, rusage);
+ _thr_cancel_leave(curthread, oldcancel);
+
+ return ret;
+}
+
+__weak_reference(_waitpid, waitpid);
+
+pid_t
+_waitpid(pid_t wpid, int *status, int options)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldcancel;
+ pid_t ret;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __waitpid(wpid, status, options);
+ _thr_cancel_leave(curthread, oldcancel);
+
+ return ret;
+}
+
+__weak_reference(__write, write);
+
+ssize_t
+__write(int fd, const void *buf, size_t nbytes)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldcancel;
+ ssize_t ret;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __sys_write(fd, buf, nbytes);
+ _thr_cancel_leave(curthread, oldcancel);
+
+ return ret;
+}
+
+__weak_reference(__writev, writev);
+
+ssize_t
+__writev(int fd, const struct iovec *iov, int iovcnt)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldcancel;
+ ssize_t ret;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __sys_writev(fd, iov, iovcnt);
+ _thr_cancel_leave(curthread, oldcancel);
+
+ return ret;
+}
diff --git a/lib/libthr/thread/thr_umtx.c b/lib/libthr/thread/thr_umtx.c
new file mode 100644
index 0000000..cba6942
--- /dev/null
+++ b/lib/libthr/thread/thr_umtx.c
@@ -0,0 +1,83 @@
+/*
+ * 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 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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, 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$
+ *
+ */
+
+#include "thr_private.h"
+#include "thr_umtx.h"
+
+int
+__thr_umtx_lock(volatile umtx_t *mtx, long id)
+{
+ while (_umtx_op(__DEVOLATILE(struct umtx *, mtx),
+ UMTX_OP_LOCK, id, 0, 0))
+ ;
+ return (0);
+}
+
+int
+__thr_umtx_timedlock(volatile umtx_t *mtx, long id,
+ const struct timespec *timeout)
+{
+ if (timeout && (timeout->tv_sec < 0 || (timeout->tv_sec == 0 &&
+ timeout->tv_nsec <= 0)))
+ return (ETIMEDOUT);
+ if (_umtx_op(__DEVOLATILE(struct umtx *, mtx), UMTX_OP_LOCK, id, 0,
+ __DECONST(void *, timeout)) == 0)
+ return (0);
+ return (errno);
+}
+
+int
+__thr_umtx_unlock(volatile umtx_t *mtx, long id)
+{
+ if (_umtx_op(__DEVOLATILE(struct umtx *, mtx), UMTX_OP_UNLOCK,
+ id, 0, 0) == 0)
+ return (0);
+ return (errno);
+}
+
+int
+_thr_umtx_wait(volatile umtx_t *mtx, long id, const struct timespec *timeout)
+{
+ if (timeout && (timeout->tv_sec < 0 || (timeout->tv_sec == 0 &&
+ timeout->tv_nsec <= 0)))
+ return (ETIMEDOUT);
+ if (_umtx_op(__DEVOLATILE(struct umtx *, mtx), UMTX_OP_WAIT, id, 0,
+ __DECONST(void*, timeout)) == 0)
+ return (0);
+ return (errno);
+}
+
+int
+_thr_umtx_wake(volatile umtx_t *mtx, int nr_wakeup)
+{
+ if (_umtx_op(__DEVOLATILE(struct umtx *, mtx), UMTX_OP_WAKE,
+ nr_wakeup, 0, 0) == 0)
+ return (0);
+ return (errno);
+}
diff --git a/lib/libthr/thread/thr_umtx.h b/lib/libthr/thread/thr_umtx.h
new file mode 100644
index 0000000..1fbf534
--- /dev/null
+++ b/lib/libthr/thread/thr_umtx.h
@@ -0,0 +1,87 @@
+/*-
+ * 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, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 _THR_FBSD_UMTX_H_
+#define _THR_FBSD_UMTX_H_
+
+#include <sys/umtx.h>
+
+typedef long umtx_t;
+
+int __thr_umtx_lock(volatile umtx_t *mtx, long id) __hidden;
+int __thr_umtx_timedlock(volatile umtx_t *mtx, long id,
+ const struct timespec *timeout) __hidden;
+int __thr_umtx_unlock(volatile umtx_t *mtx, long id) __hidden;
+
+static inline void
+_thr_umtx_init(volatile umtx_t *mtx)
+{
+ *mtx = 0;
+}
+
+static inline int
+_thr_umtx_trylock(volatile umtx_t *mtx, long id)
+{
+ if (atomic_cmpset_acq_ptr((volatile uintptr_t *)mtx,
+ (uintptr_t)UMTX_UNOWNED, (uintptr_t)id))
+ return (0);
+ return (EBUSY);
+}
+
+static inline int
+_thr_umtx_lock(volatile umtx_t *mtx, long id)
+{
+ if (atomic_cmpset_acq_ptr((volatile uintptr_t *)mtx,
+ (uintptr_t)UMTX_UNOWNED, (uintptr_t)id))
+ return (0);
+ return (__thr_umtx_lock(mtx, id));
+}
+
+static inline int
+_thr_umtx_timedlock(volatile umtx_t *mtx, long id,
+ const struct timespec *timeout)
+{
+ if (atomic_cmpset_acq_ptr((volatile uintptr_t *)mtx,
+ (uintptr_t)UMTX_UNOWNED, (uintptr_t)id))
+ return (0);
+ return (__thr_umtx_timedlock(mtx, id, timeout));
+}
+
+static inline int
+_thr_umtx_unlock(volatile umtx_t *mtx, long id)
+{
+ if (atomic_cmpset_rel_ptr((volatile uintptr_t *)mtx,
+ (uintptr_t)id, (uintptr_t)UMTX_UNOWNED))
+ return (0);
+ return __thr_umtx_unlock(mtx, id);
+}
+
+int _thr_umtx_wait(volatile umtx_t *mtx, umtx_t exp,
+ const struct timespec *timeout) __hidden;
+int _thr_umtx_wake(volatile umtx_t *mtx, int count) __hidden;
+#endif
diff --git a/lib/libthr/thread/thr_yield.c b/lib/libthr/thread/thr_yield.c
new file mode 100644
index 0000000..300504b
--- /dev/null
+++ b/lib/libthr/thread/thr_yield.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <pthread.h>
+#include <sched.h>
+#include "un-namespace.h"
+
+__weak_reference(_pthread_yield, pthread_yield);
+
+/* Draft 4 yield */
+void
+_pthread_yield(void)
+{
+
+ sched_yield();
+}
diff --git a/lib/libthread_db/Makefile b/lib/libthread_db/Makefile
new file mode 100644
index 0000000..f74e49d
--- /dev/null
+++ b/lib/libthread_db/Makefile
@@ -0,0 +1,22 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}
+
+LIB= thread_db
+SHLIB_MAJOR= 2
+SRCS= thread_db.c
+SRCS+= libpthread_db.c libpthread_md.c
+SRCS+= libc_r_db.c libc_r_md.c
+SRCS+= libthr_db.c
+INCS= thread_db.h
+WARNS?= 1
+
+CFLAGS+=-I. -I${.CURDIR}
+SYM_MAPS+=${.CURDIR}/Symbol.map
+
+.if defined(SYMVER_ENABLED)
+SYMBOL_MAPS=${SYM_MAPS}
+VERSION_DEF=${.CURDIR}/../libc/Versions.def
+.endif
+
+.include <bsd.lib.mk>
diff --git a/lib/libthread_db/Symbol.map b/lib/libthread_db/Symbol.map
new file mode 100644
index 0000000..9a3af90
--- /dev/null
+++ b/lib/libthread_db/Symbol.map
@@ -0,0 +1,31 @@
+# $FreeBSD$
+
+FBSD_1.0 {
+ td_init;
+ td_ta_clear_event;
+ td_ta_delete;
+ td_ta_event_addr;
+ td_ta_event_getmsg;
+ td_ta_map_id2thr;
+ td_ta_map_lwp2thr;
+ td_ta_new;
+ td_ta_set_event;
+ td_ta_thr_iter;
+ td_ta_tsd_iter;
+ td_thr_clear_event;
+ td_thr_dbresume;
+ td_thr_dbsuspend;
+ td_thr_event_enable;
+ td_thr_event_getmsg;
+ td_thr_get_info;
+ td_thr_getfpregs;
+ td_thr_getgregs;
+ td_thr_getxmmregs; # x86 only
+ td_thr_set_event;
+ td_thr_setfpregs;
+ td_thr_setgregs;
+ td_thr_setxmmregs; # x86 only
+ td_thr_sstep; # FreeBSD extension to GDB<->thread interface
+ td_thr_tls_get_addr;
+ td_thr_validate;
+};
diff --git a/lib/libthread_db/arch/alpha/libc_r_md.c b/lib/libthread_db/arch/alpha/libc_r_md.c
new file mode 100644
index 0000000..227440c
--- /dev/null
+++ b/lib/libthread_db/arch/alpha/libc_r_md.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2004 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/procfs.h>
+#include <machine/setjmp.h>
+
+void
+libc_r_md_getgregs(jmp_buf jb, prgregset_t r)
+{
+ r->r_regs[R_V0] = jb->_jb[4];
+ r->r_regs[R_T0] = jb->_jb[5];
+ r->r_regs[R_T1] = jb->_jb[6];
+ r->r_regs[R_T2] = jb->_jb[7];
+ r->r_regs[R_T3] = jb->_jb[8];
+ r->r_regs[R_T4] = jb->_jb[9];
+ r->r_regs[R_T5] = jb->_jb[10];
+ r->r_regs[R_T6] = jb->_jb[11];
+ r->r_regs[R_T7] = jb->_jb[12];
+ r->r_regs[R_S0] = jb->_jb[13];
+ r->r_regs[R_S1] = jb->_jb[14];
+ r->r_regs[R_S2] = jb->_jb[15];
+ r->r_regs[R_S3] = jb->_jb[16];
+ r->r_regs[R_S4] = jb->_jb[17];
+ r->r_regs[R_S5] = jb->_jb[18];
+ r->r_regs[R_S6] = jb->_jb[19];
+ r->r_regs[R_A0] = jb->_jb[20];
+ r->r_regs[R_A1] = jb->_jb[21];
+ r->r_regs[R_A2] = jb->_jb[22];
+ r->r_regs[R_A3] = jb->_jb[23];
+ r->r_regs[R_A4] = jb->_jb[24];
+ r->r_regs[R_A5] = jb->_jb[25];
+ r->r_regs[R_T8] = jb->_jb[26];
+ r->r_regs[R_T9] = jb->_jb[27];
+ r->r_regs[R_T10] = jb->_jb[28];
+ r->r_regs[R_T11] = jb->_jb[29];
+ r->r_regs[R_RA] = jb->_jb[30];
+ r->r_regs[R_T12] = jb->_jb[31];
+ r->r_regs[R_AT] = jb->_jb[32];
+ r->r_regs[R_GP] = jb->_jb[33];
+ r->r_regs[R_SP] = jb->_jb[34];
+ r->r_regs[R_ZERO] = jb->_jb[35];
+}
+
+void
+libc_r_md_getfpregs(jmp_buf jb, prfpregset_t *r)
+{
+}
diff --git a/lib/libthread_db/arch/alpha/libpthread_md.c b/lib/libthread_db/arch/alpha/libpthread_md.c
new file mode 100644
index 0000000..7553ed1
--- /dev/null
+++ b/lib/libthread_db/arch/alpha/libpthread_md.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2004 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/procfs.h>
+#include <ucontext.h>
+
+void
+pt_reg_to_ucontext(const struct reg *r, ucontext_t *uc)
+{
+}
+
+void
+pt_ucontext_to_reg(const ucontext_t *uc, struct reg *r)
+{
+}
+
+void
+pt_fpreg_to_ucontext(const struct fpreg* r, ucontext_t *uc)
+{
+}
+
+void
+pt_ucontext_to_fpreg(const ucontext_t *uc, struct fpreg *r)
+{
+}
+
+void
+pt_md_init(void)
+{
+}
+
+int
+pt_reg_sstep(struct reg *reg, int step)
+{
+ return (0);
+}
diff --git a/lib/libthread_db/arch/amd64/libc_r_md.c b/lib/libthread_db/arch/amd64/libc_r_md.c
new file mode 100644
index 0000000..6c53953
--- /dev/null
+++ b/lib/libthread_db/arch/amd64/libc_r_md.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2004 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/procfs.h>
+#include <machine/setjmp.h>
+
+void
+libc_r_md_getgregs(jmp_buf jb, prgregset_t *r)
+{
+}
+
+void
+libc_r_md_getfpregs(jmp_buf jb, prfpregset_t *r)
+{
+}
diff --git a/lib/libthread_db/arch/amd64/libpthread_md.c b/lib/libthread_db/arch/amd64/libpthread_md.c
new file mode 100644
index 0000000..8fca1fd
--- /dev/null
+++ b/lib/libthread_db/arch/amd64/libpthread_md.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2004 David Xu <davidxu@freebsd.org>
+ * Copyright (c) 2004 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/procfs.h>
+#include <ucontext.h>
+
+void
+pt_reg_to_ucontext(const struct reg *r, ucontext_t *uc)
+{
+ mcontext_t *mc = &uc->uc_mcontext;
+
+ mc->mc_rdi = r->r_rdi;
+ mc->mc_rsi = r->r_rsi;
+ mc->mc_rdx = r->r_rdx;
+ mc->mc_rcx = r->r_rcx;
+ mc->mc_r8 = r->r_r8;
+ mc->mc_r9 = r->r_r9;
+ mc->mc_rax = r->r_rax;
+ mc->mc_rbx = r->r_rbx;
+ mc->mc_rbp = r->r_rbp;
+ mc->mc_r10 = r->r_r10;
+ mc->mc_r11 = r->r_r11;
+ mc->mc_r12 = r->r_r12;
+ mc->mc_r13 = r->r_r13;
+ mc->mc_r14 = r->r_r14;
+ mc->mc_r15 = r->r_r15;
+ mc->mc_rip = r->r_rip;
+ mc->mc_cs = r->r_cs;
+ mc->mc_rflags = r->r_rflags;
+ mc->mc_rsp = r->r_rsp;
+ mc->mc_ss = r->r_ss;
+}
+
+void
+pt_ucontext_to_reg(const ucontext_t *uc, struct reg *r)
+{
+ const mcontext_t *mc = &uc->uc_mcontext;
+
+ r->r_rdi = mc->mc_rdi;
+ r->r_rsi = mc->mc_rsi;
+ r->r_rdx = mc->mc_rdx;
+ r->r_rcx = mc->mc_rcx;
+ r->r_r8 = mc->mc_r8;
+ r->r_r9 = mc->mc_r9;
+ r->r_rax = mc->mc_rax;
+ r->r_rbx = mc->mc_rbx;
+ r->r_rbp = mc->mc_rbp;
+ r->r_r10 = mc->mc_r10;
+ r->r_r11 = mc->mc_r11;
+ r->r_r12 = mc->mc_r12;
+ r->r_r13 = mc->mc_r13;
+ r->r_r14 = mc->mc_r14;
+ r->r_r15 = mc->mc_r15;
+ r->r_rip = mc->mc_rip;
+ r->r_cs = mc->mc_cs;
+ r->r_rflags = mc->mc_rflags;
+ r->r_rsp = mc->mc_rsp;
+ r->r_ss = mc->mc_ss;
+}
+
+void
+pt_fpreg_to_ucontext(const struct fpreg* r, ucontext_t *uc)
+{
+ memcpy(&uc->uc_mcontext.mc_fpstate, r, sizeof(r));
+}
+
+void
+pt_ucontext_to_fpreg(const ucontext_t *uc, struct fpreg *r)
+{
+ memcpy(r, &uc->uc_mcontext.mc_fpstate, sizeof(r));
+}
+
+void
+pt_md_init(void)
+{
+ /* Nothing to do */
+}
+
+int
+pt_reg_sstep(struct reg *reg, int step)
+{
+ register_t old;
+
+ old = reg->r_rflags;
+ if (step)
+ reg->r_rflags |= 0x0100;
+ else
+ reg->r_rflags &= ~0x0100;
+ return (old != reg->r_rflags); /* changed ? */
+}
diff --git a/lib/libthread_db/arch/i386/libc_r_md.c b/lib/libthread_db/arch/i386/libc_r_md.c
new file mode 100644
index 0000000..de27b68
--- /dev/null
+++ b/lib/libthread_db/arch/i386/libc_r_md.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2004 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/procfs.h>
+#include <machine/setjmp.h>
+
+void
+libc_r_md_getgregs(jmp_buf jb, prgregset_t r)
+{
+ r->r_eip = jb->_jb[0];
+ r->r_ebx = jb->_jb[1];
+ r->r_esp = jb->_jb[2];
+ r->r_ebp = jb->_jb[3];
+ r->r_esi = jb->_jb[4];
+ r->r_edi = jb->_jb[5];
+ r->r_eax = jb->_jb[6];
+}
+
+void
+libc_r_md_getfpregs(jmp_buf jb, prfpregset_t *r)
+{
+}
diff --git a/lib/libthread_db/arch/i386/libpthread_md.c b/lib/libthread_db/arch/i386/libpthread_md.c
new file mode 100644
index 0000000..dc14e60
--- /dev/null
+++ b/lib/libthread_db/arch/i386/libpthread_md.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2004 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <string.h>
+#include <sys/types.h>
+#include <proc_service.h>
+#include <thread_db.h>
+#include <machine/npx.h>
+
+#include "libpthread_db.h"
+
+static int has_xmm_regs;
+
+void
+pt_reg_to_ucontext(const struct reg *r, ucontext_t *uc)
+{
+ memcpy(&uc->uc_mcontext.mc_fs, &r->r_fs, 18*4);
+ uc->uc_mcontext.mc_gs = r->r_gs;
+}
+
+void
+pt_ucontext_to_reg(const ucontext_t *uc, struct reg *r)
+{
+ memcpy(&r->r_fs, &uc->uc_mcontext.mc_fs, 18*4);
+ r->r_gs = uc->uc_mcontext.mc_gs;
+}
+
+void
+pt_fpreg_to_ucontext(const struct fpreg* r, ucontext_t *uc)
+{
+ if (!has_xmm_regs)
+ memcpy(&uc->uc_mcontext.mc_fpstate, r,
+ sizeof(struct save87));
+ else {
+ int i;
+ struct savexmm *sx = (struct savexmm *)&uc->uc_mcontext.mc_fpstate;
+ memcpy(&sx->sv_env, &r->fpr_env, sizeof(r->fpr_env));
+ for (i = 0; i < 8; ++i)
+ memcpy(&sx->sv_fp[i].fp_acc, &r->fpr_acc[i], 10);
+ }
+}
+
+void
+pt_ucontext_to_fpreg(const ucontext_t *uc, struct fpreg *r)
+{
+ if (!has_xmm_regs)
+ memcpy(r, &uc->uc_mcontext.mc_fpstate, sizeof(struct save87));
+ else {
+ int i;
+ struct savexmm *sx = (struct savexmm *)&uc->uc_mcontext.mc_fpstate;
+ memcpy(&r->fpr_env, &sx->sv_env, sizeof(r->fpr_env));
+ for (i = 0; i < 8; ++i)
+ memcpy(&r->fpr_acc[i], &sx->sv_fp[i].fp_acc, 10);
+ }
+}
+
+void
+pt_fxsave_to_ucontext(const char* r, ucontext_t *uc)
+{
+ if (has_xmm_regs)
+ memcpy(&uc->uc_mcontext.mc_fpstate, r, sizeof(struct savexmm));
+}
+
+void
+pt_ucontext_to_fxsave(const ucontext_t *uc, char *r)
+{
+ if (has_xmm_regs)
+ memcpy(r, &uc->uc_mcontext.mc_fpstate, sizeof(struct savexmm));
+}
+
+void
+pt_md_init(void)
+{
+ ucontext_t uc;
+
+ getcontext(&uc);
+ if (uc.uc_mcontext.mc_fpformat == _MC_FPFMT_XMM)
+ has_xmm_regs = 1;
+}
+
+int
+pt_reg_sstep(struct reg *reg, int step)
+{
+ unsigned int old;
+
+ old = reg->r_eflags;
+ if (step)
+ reg->r_eflags |= 0x0100;
+ else
+ reg->r_eflags &= ~0x0100;
+ return (old != reg->r_eflags); /* changed ? */
+}
+
diff --git a/lib/libthread_db/arch/ia64/libc_r_md.c b/lib/libthread_db/arch/ia64/libc_r_md.c
new file mode 100644
index 0000000..6c53953
--- /dev/null
+++ b/lib/libthread_db/arch/ia64/libc_r_md.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2004 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/procfs.h>
+#include <machine/setjmp.h>
+
+void
+libc_r_md_getgregs(jmp_buf jb, prgregset_t *r)
+{
+}
+
+void
+libc_r_md_getfpregs(jmp_buf jb, prfpregset_t *r)
+{
+}
diff --git a/lib/libthread_db/arch/ia64/libpthread_md.c b/lib/libthread_db/arch/ia64/libpthread_md.c
new file mode 100644
index 0000000..7553ed1
--- /dev/null
+++ b/lib/libthread_db/arch/ia64/libpthread_md.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2004 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/procfs.h>
+#include <ucontext.h>
+
+void
+pt_reg_to_ucontext(const struct reg *r, ucontext_t *uc)
+{
+}
+
+void
+pt_ucontext_to_reg(const ucontext_t *uc, struct reg *r)
+{
+}
+
+void
+pt_fpreg_to_ucontext(const struct fpreg* r, ucontext_t *uc)
+{
+}
+
+void
+pt_ucontext_to_fpreg(const ucontext_t *uc, struct fpreg *r)
+{
+}
+
+void
+pt_md_init(void)
+{
+}
+
+int
+pt_reg_sstep(struct reg *reg, int step)
+{
+ return (0);
+}
diff --git a/lib/libthread_db/arch/sparc64/libc_r_md.c b/lib/libthread_db/arch/sparc64/libc_r_md.c
new file mode 100644
index 0000000..6c53953
--- /dev/null
+++ b/lib/libthread_db/arch/sparc64/libc_r_md.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2004 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/procfs.h>
+#include <machine/setjmp.h>
+
+void
+libc_r_md_getgregs(jmp_buf jb, prgregset_t *r)
+{
+}
+
+void
+libc_r_md_getfpregs(jmp_buf jb, prfpregset_t *r)
+{
+}
diff --git a/lib/libthread_db/arch/sparc64/libpthread_md.c b/lib/libthread_db/arch/sparc64/libpthread_md.c
new file mode 100644
index 0000000..7553ed1
--- /dev/null
+++ b/lib/libthread_db/arch/sparc64/libpthread_md.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2004 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/procfs.h>
+#include <ucontext.h>
+
+void
+pt_reg_to_ucontext(const struct reg *r, ucontext_t *uc)
+{
+}
+
+void
+pt_ucontext_to_reg(const ucontext_t *uc, struct reg *r)
+{
+}
+
+void
+pt_fpreg_to_ucontext(const struct fpreg* r, ucontext_t *uc)
+{
+}
+
+void
+pt_ucontext_to_fpreg(const ucontext_t *uc, struct fpreg *r)
+{
+}
+
+void
+pt_md_init(void)
+{
+}
+
+int
+pt_reg_sstep(struct reg *reg, int step)
+{
+ return (0);
+}
diff --git a/lib/libthread_db/libc_r_db.c b/lib/libthread_db/libc_r_db.c
new file mode 100644
index 0000000..10f7df1
--- /dev/null
+++ b/lib/libthread_db/libc_r_db.c
@@ -0,0 +1,348 @@
+/*
+ * Copyright (c) 2004 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 <machine/setjmp.h>
+#include <proc_service.h>
+#include <stdlib.h>
+#include <string.h>
+#include <thread_db.h>
+
+#include "thread_db_int.h"
+
+void libc_r_md_getfpregs(jmp_buf jb, prfpregset_t *);
+void libc_r_md_getgregs(jmp_buf jb, prgregset_t);
+
+struct td_thragent {
+ TD_THRAGENT_FIELDS;
+ struct ps_prochandle *ta_ph;
+ psaddr_t ta_thread_initial;
+ psaddr_t ta_thread_list;
+ psaddr_t ta_thread_run;
+ int ta_ofs_ctx;
+ int ta_ofs_next;
+ int ta_ofs_uniqueid;
+};
+
+static td_err_e
+libc_r_db_init()
+{
+ return (TD_OK);
+}
+
+static td_err_e
+libc_r_db_ta_clear_event(const td_thragent_t *ta, td_thr_events_t *ev)
+{
+ return (0);
+}
+
+static td_err_e
+libc_r_db_ta_delete(td_thragent_t *ta)
+{
+ free(ta);
+ return (TD_OK);
+}
+
+static td_err_e
+libc_r_db_ta_event_addr(const td_thragent_t *ta, td_thr_events_e ev,
+ td_notify_t *n)
+{
+ return (TD_ERR);
+}
+
+static td_err_e
+libc_r_db_ta_event_getmsg(const td_thragent_t *ta, td_event_msg_t *msg)
+{
+ return (TD_ERR);
+}
+
+static td_err_e
+libc_r_db_ta_map_id2thr(const td_thragent_t *ta, thread_t tid,
+ td_thrhandle_t *th)
+{
+ return (TD_ERR);
+}
+
+static td_err_e
+libc_r_db_ta_map_lwp2thr(const td_thragent_t *ta, lwpid_t lwpid,
+ td_thrhandle_t *th)
+{
+ psaddr_t addr;
+ ps_err_e err;
+
+ th->th_ta = ta;
+ err = ps_pread(ta->ta_ph, ta->ta_thread_initial, &addr, sizeof(addr));
+ if (err != PS_OK)
+ return (TD_ERR);
+ if (addr == NULL)
+ return (TD_NOLWP);
+ err = ps_pread(ta->ta_ph, ta->ta_thread_run, &th->th_thread,
+ sizeof(psaddr_t));
+ return ((err == PS_OK) ? TD_OK : TD_ERR);
+}
+
+static td_err_e
+libc_r_db_ta_new(struct ps_prochandle *ph, td_thragent_t **ta_p)
+{
+ td_thragent_t *ta;
+ psaddr_t addr;
+ ps_err_e err;
+
+ ta = malloc(sizeof(td_thragent_t));
+ if (ta == NULL)
+ return (TD_MALLOC);
+
+ ta->ta_ph = ph;
+
+ err = ps_pglobal_lookup(ph, NULL, "_thread_initial",
+ &ta->ta_thread_initial);
+ if (err != PS_OK)
+ goto fail;
+ err = ps_pglobal_lookup(ph, NULL, "_thread_list", &ta->ta_thread_list);
+ if (err != PS_OK)
+ goto fail;
+ err = ps_pglobal_lookup(ph, NULL, "_thread_run", &ta->ta_thread_run);
+ if (err != PS_OK)
+ goto fail;
+ err = ps_pglobal_lookup(ph, NULL, "_thread_ctx_offset", &addr);
+ if (err != PS_OK)
+ goto fail;
+ err = ps_pread(ph, addr, &ta->ta_ofs_ctx, sizeof(int));
+ if (err != PS_OK)
+ goto fail;
+ err = ps_pglobal_lookup(ph, NULL, "_thread_next_offset", &addr);
+ if (err != PS_OK)
+ goto fail;
+ err = ps_pread(ph, addr, &ta->ta_ofs_next, sizeof(int));
+ if (err != PS_OK)
+ goto fail;
+ err = ps_pglobal_lookup(ph, NULL, "_thread_uniqueid_offset", &addr);
+ if (err != PS_OK)
+ goto fail;
+ err = ps_pread(ph, addr, &ta->ta_ofs_uniqueid, sizeof(int));
+ if (err != PS_OK)
+ goto fail;
+
+ *ta_p = ta;
+ return (TD_OK);
+
+ fail:
+ free(ta);
+ *ta_p = NULL;
+ return (TD_ERR);
+}
+
+static td_err_e
+libc_r_db_ta_set_event(const td_thragent_t *ta, td_thr_events_t *ev)
+{
+ return (0);
+}
+
+static td_err_e
+libc_r_db_ta_thr_iter(const td_thragent_t *ta, td_thr_iter_f *cb, void *data,
+ td_thr_state_e state, int pri, sigset_t *mask, unsigned int flags)
+{
+ td_thrhandle_t th;
+ psaddr_t addr;
+ ps_err_e err;
+
+ th.th_ta = ta;
+
+ err = ps_pread(ta->ta_ph, ta->ta_thread_list, &th.th_thread,
+ sizeof(th.th_thread));
+ if (err != PS_OK)
+ return (TD_ERR);
+ while (th.th_thread != NULL) {
+ if (cb(&th, data) != 0)
+ return (TD_OK);
+ addr = (psaddr_t)((uintptr_t)th.th_thread + ta->ta_ofs_next);
+ err = ps_pread(ta->ta_ph, addr, &th.th_thread,
+ sizeof(th.th_thread));
+ if (err != PS_OK)
+ return (TD_ERR);
+ }
+ return (TD_OK);
+}
+
+static td_err_e
+libc_r_db_thr_clear_event(const td_thrhandle_t *th, td_thr_events_t *ev)
+{
+ return (0);
+}
+
+static td_err_e
+libc_r_db_thr_event_enable(const td_thrhandle_t *th, int oo)
+{
+ return (0);
+}
+
+static td_err_e
+libc_r_db_thr_event_getmsg(const td_thrhandle_t *th, td_event_msg_t *msg)
+{
+ return (TD_ERR);
+}
+
+static td_err_e
+libc_r_db_thr_get_info(const td_thrhandle_t *th, td_thrinfo_t *ti)
+{
+ const td_thragent_t *ta;
+ psaddr_t addr, current;
+ ps_err_e err;
+
+ ta = th->th_ta;
+ ti->ti_ta_p = ta;
+ err = ps_pread(ta->ta_ph, ta->ta_thread_run, &current,
+ sizeof(psaddr_t));
+ if (err != PS_OK)
+ return (TD_ERR);
+ ti->ti_lid = (th->th_thread == current) ? -1 : 0;
+ addr = (psaddr_t)((uintptr_t)th->th_thread + ta->ta_ofs_uniqueid);
+ err = ps_pread(ta->ta_ph, addr, &ti->ti_tid, sizeof(thread_t));
+ /* libc_r numbers its threads starting with 0. Not smart. */
+ ti->ti_tid++;
+ return ((err == PS_OK) ? TD_OK : TD_ERR);
+}
+
+#ifdef __i386__
+static td_err_e
+libc_r_db_thr_getxmmregs(const td_thrhandle_t *th, char *fxsave)
+{
+ return (TD_NOFPREGS);
+}
+#endif
+
+static td_err_e
+libc_r_db_thr_getfpregs(const td_thrhandle_t *th, prfpregset_t *r)
+{
+ jmp_buf jb;
+ const td_thragent_t *ta;
+ psaddr_t addr;
+ ps_err_e err;
+
+ ta = th->th_ta;
+ err = ps_lgetfpregs(ta->ta_ph, -1, r);
+ if (err != PS_OK)
+ return (TD_ERR);
+ err = ps_pread(ta->ta_ph, ta->ta_thread_run, &addr, sizeof(psaddr_t));
+ if (err != PS_OK)
+ return (TD_ERR);
+ if (th->th_thread == addr)
+ return (TD_OK);
+ addr = (psaddr_t)((uintptr_t)th->th_thread + ta->ta_ofs_ctx);
+ err = ps_pread(ta->ta_ph, addr, jb, sizeof(jb));
+ if (err != PS_OK)
+ return (TD_ERR);
+ libc_r_md_getfpregs(jb, r);
+ return (TD_OK);
+}
+
+static td_err_e
+libc_r_db_thr_getgregs(const td_thrhandle_t *th, prgregset_t r)
+{
+ jmp_buf jb;
+ const td_thragent_t *ta;
+ psaddr_t addr;
+ ps_err_e err;
+
+ ta = th->th_ta;
+ err = ps_lgetregs(ta->ta_ph, -1, r);
+ if (err != PS_OK)
+ return (TD_ERR);
+ err = ps_pread(ta->ta_ph, ta->ta_thread_run, &addr, sizeof(psaddr_t));
+ if (err != PS_OK)
+ return (TD_ERR);
+ if (th->th_thread == addr)
+ return (TD_OK);
+ addr = (psaddr_t)((uintptr_t)th->th_thread + ta->ta_ofs_ctx);
+ err = ps_pread(ta->ta_ph, addr, jb, sizeof(jb));
+ if (err != PS_OK)
+ return (TD_ERR);
+ libc_r_md_getgregs(jb, r);
+ return (TD_OK);
+}
+
+static td_err_e
+libc_r_db_thr_set_event(const td_thrhandle_t *th, td_thr_events_t *ev)
+{
+ return (0);
+}
+
+#ifdef __i386__
+static td_err_e
+libc_r_db_thr_setxmmregs(const td_thrhandle_t *th, const char *fxsave)
+{
+ return (TD_NOFPREGS);
+}
+#endif
+
+static td_err_e
+libc_r_db_thr_setfpregs(const td_thrhandle_t *th, const prfpregset_t *r)
+{
+ return (TD_ERR);
+}
+
+static td_err_e
+libc_r_db_thr_setgregs(const td_thrhandle_t *th, const prgregset_t r)
+{
+ return (TD_ERR);
+}
+
+static td_err_e
+libc_r_db_thr_validate(const td_thrhandle_t *th)
+{
+ return (TD_ERR);
+}
+
+struct ta_ops libc_r_db_ops = {
+ .to_init = libc_r_db_init,
+
+ .to_ta_clear_event = libc_r_db_ta_clear_event,
+ .to_ta_delete = libc_r_db_ta_delete,
+ .to_ta_event_addr = libc_r_db_ta_event_addr,
+ .to_ta_event_getmsg = libc_r_db_ta_event_getmsg,
+ .to_ta_map_id2thr = libc_r_db_ta_map_id2thr,
+ .to_ta_map_lwp2thr = libc_r_db_ta_map_lwp2thr,
+ .to_ta_new = libc_r_db_ta_new,
+ .to_ta_set_event = libc_r_db_ta_set_event,
+ .to_ta_thr_iter = libc_r_db_ta_thr_iter,
+
+ .to_thr_clear_event = libc_r_db_thr_clear_event,
+ .to_thr_event_enable = libc_r_db_thr_event_enable,
+ .to_thr_event_getmsg = libc_r_db_thr_event_getmsg,
+ .to_thr_get_info = libc_r_db_thr_get_info,
+ .to_thr_getfpregs = libc_r_db_thr_getfpregs,
+ .to_thr_getgregs = libc_r_db_thr_getgregs,
+ .to_thr_set_event = libc_r_db_thr_set_event,
+ .to_thr_setfpregs = libc_r_db_thr_setfpregs,
+ .to_thr_setgregs = libc_r_db_thr_setgregs,
+ .to_thr_validate = libc_r_db_thr_validate,
+#ifdef __i386__
+ .to_thr_getxmmregs = libc_r_db_thr_getxmmregs,
+ .to_thr_setxmmregs = libc_r_db_thr_setxmmregs,
+#endif
+};
diff --git a/lib/libthread_db/libpthread_db.c b/lib/libthread_db/libpthread_db.c
new file mode 100644
index 0000000..021410c
--- /dev/null
+++ b/lib/libthread_db/libpthread_db.c
@@ -0,0 +1,1149 @@
+/*
+ * Copyright (c) 2004 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/kse.h>
+#include <sys/ptrace.h>
+#include <proc_service.h>
+#include <thread_db.h>
+
+#include "libpthread_db.h"
+
+#define P2T(c) ps2td(c)
+
+static void pt_unmap_lwp(const td_thragent_t *ta, lwpid_t lwp);
+static int pt_validate(const td_thrhandle_t *th);
+
+static int
+ps2td(int c)
+{
+ switch (c) {
+ case PS_OK:
+ return TD_OK;
+ case PS_ERR:
+ return TD_ERR;
+ case PS_BADPID:
+ return TD_BADPH;
+ case PS_BADLID:
+ return TD_NOLWP;
+ case PS_BADADDR:
+ return TD_ERR;
+ case PS_NOSYM:
+ return TD_NOLIBTHREAD;
+ case PS_NOFREGS:
+ return TD_NOFPREGS;
+ default:
+ return TD_ERR;
+ }
+}
+
+static long
+pt_map_thread(const td_thragent_t *const_ta, psaddr_t pt, int type)
+{
+ td_thragent_t *ta = __DECONST(td_thragent_t *, const_ta);
+ struct pt_map *new;
+ int i, first = -1;
+
+ /* leave zero out */
+ for (i = 1; i < ta->map_len; ++i) {
+ if (ta->map[i].type == PT_NONE) {
+ if (first == -1)
+ first = i;
+ } else if (ta->map[i].type == type && ta->map[i].thr == pt) {
+ return (i);
+ }
+ }
+
+ if (first == -1) {
+ if (ta->map_len == 0) {
+ ta->map = calloc(20, sizeof(struct pt_map));
+ if (ta->map == NULL)
+ return (-1);
+ ta->map_len = 20;
+ first = 1;
+ } else {
+ new = realloc(ta->map,
+ sizeof(struct pt_map) * ta->map_len * 2);
+ if (new == NULL)
+ return (-1);
+ memset(new + ta->map_len, '\0', sizeof(struct pt_map) *
+ ta->map_len);
+ first = ta->map_len;
+ ta->map = new;
+ ta->map_len *= 2;
+ }
+ }
+
+ ta->map[first].type = type;
+ ta->map[first].thr = pt;
+ return (first);
+}
+
+static td_err_e
+pt_init(void)
+{
+ pt_md_init();
+ return (0);
+}
+
+static td_err_e
+pt_ta_new(struct ps_prochandle *ph, td_thragent_t **pta)
+{
+#define LOOKUP_SYM(proc, sym, addr) \
+ ret = ps_pglobal_lookup(proc, NULL, sym, addr); \
+ if (ret != 0) { \
+ TDBG("can not find symbol: %s\n", sym); \
+ ret = TD_NOLIBTHREAD; \
+ goto error; \
+ }
+
+#define LOOKUP_VAL(proc, sym, val) \
+ ret = ps_pglobal_lookup(proc, NULL, sym, &vaddr);\
+ if (ret != 0) { \
+ TDBG("can not find symbol: %s\n", sym); \
+ ret = TD_NOLIBTHREAD; \
+ goto error; \
+ } \
+ ret = ps_pread(proc, vaddr, val, sizeof(int)); \
+ if (ret != 0) { \
+ TDBG("can not read value of %s\n", sym);\
+ ret = TD_NOLIBTHREAD; \
+ goto error; \
+ }
+
+ td_thragent_t *ta;
+ psaddr_t vaddr;
+ int dbg;
+ int ret;
+
+ TDBG_FUNC();
+
+ ta = malloc(sizeof(td_thragent_t));
+ if (ta == NULL)
+ return (TD_MALLOC);
+
+ ta->ph = ph;
+ ta->thread_activated = 0;
+ ta->map = NULL;
+ ta->map_len = 0;
+
+ LOOKUP_SYM(ph, "_libkse_debug", &ta->libkse_debug_addr);
+ LOOKUP_SYM(ph, "_thread_list", &ta->thread_list_addr);
+ LOOKUP_SYM(ph, "_thread_activated", &ta->thread_activated_addr);
+ LOOKUP_SYM(ph, "_thread_active_threads",&ta->thread_active_threads_addr);
+ LOOKUP_SYM(ph, "_thread_keytable", &ta->thread_keytable_addr);
+ LOOKUP_VAL(ph, "_thread_off_dtv", &ta->thread_off_dtv);
+ LOOKUP_VAL(ph, "_thread_off_kse_locklevel", &ta->thread_off_kse_locklevel);
+ LOOKUP_VAL(ph, "_thread_off_kse", &ta->thread_off_kse);
+ LOOKUP_VAL(ph, "_thread_off_tlsindex", &ta->thread_off_tlsindex);
+ LOOKUP_VAL(ph, "_thread_off_attr_flags", &ta->thread_off_attr_flags);
+ LOOKUP_VAL(ph, "_thread_size_key", &ta->thread_size_key);
+ LOOKUP_VAL(ph, "_thread_off_tcb", &ta->thread_off_tcb);
+ LOOKUP_VAL(ph, "_thread_off_linkmap", &ta->thread_off_linkmap);
+ LOOKUP_VAL(ph, "_thread_off_tmbx", &ta->thread_off_tmbx);
+ LOOKUP_VAL(ph, "_thread_off_thr_locklevel", &ta->thread_off_thr_locklevel);
+ LOOKUP_VAL(ph, "_thread_off_next", &ta->thread_off_next);
+ LOOKUP_VAL(ph, "_thread_off_state", &ta->thread_off_state);
+ LOOKUP_VAL(ph, "_thread_max_keys", &ta->thread_max_keys);
+ LOOKUP_VAL(ph, "_thread_off_key_allocated", &ta->thread_off_key_allocated);
+ LOOKUP_VAL(ph, "_thread_off_key_destructor", &ta->thread_off_key_destructor);
+ LOOKUP_VAL(ph, "_thread_state_running", &ta->thread_state_running);
+ LOOKUP_VAL(ph, "_thread_state_zoombie", &ta->thread_state_zoombie);
+ LOOKUP_VAL(ph, "_thread_off_sigmask", &ta->thread_off_sigmask);
+ LOOKUP_VAL(ph, "_thread_off_sigpend", &ta->thread_off_sigpend);
+ dbg = getpid();
+ /*
+ * If this fails it probably means we're debugging a core file and
+ * can't write to it.
+ */
+ ps_pwrite(ph, ta->libkse_debug_addr, &dbg, sizeof(int));
+ *pta = ta;
+ return (0);
+
+error:
+ free(ta);
+ return (ret);
+}
+
+static td_err_e
+pt_ta_delete(td_thragent_t *ta)
+{
+ int dbg;
+
+ TDBG_FUNC();
+
+ dbg = 0;
+ /*
+ * Error returns from this write are not really a problem;
+ * the process doesn't exist any more.
+ */
+ ps_pwrite(ta->ph, ta->libkse_debug_addr, &dbg, sizeof(int));
+ if (ta->map)
+ free(ta->map);
+ free(ta);
+ return (TD_OK);
+}
+
+static td_err_e
+pt_ta_map_id2thr(const td_thragent_t *ta, thread_t id, td_thrhandle_t *th)
+{
+ prgregset_t gregs;
+ TAILQ_HEAD(, pthread) thread_list;
+ psaddr_t pt, tcb_addr;
+ lwpid_t lwp;
+ int ret;
+
+ TDBG_FUNC();
+
+ if (id < 0 || id >= ta->map_len || ta->map[id].type == PT_NONE)
+ return (TD_NOTHR);
+ ret = ps_pread(ta->ph, ta->thread_list_addr, &thread_list,
+ sizeof(thread_list));
+ if (ret != 0)
+ return (P2T(ret));
+ pt = (psaddr_t)thread_list.tqh_first;
+ if (ta->map[id].type == PT_LWP) {
+ /*
+ * if we are referencing a lwp, make sure it was not already
+ * mapped to user thread.
+ */
+ while (pt != 0) {
+ ret = ps_pread(ta->ph,
+ pt + ta->thread_off_tcb,
+ &tcb_addr, sizeof(tcb_addr));
+ if (ret != 0)
+ return (P2T(ret));
+ ret = ps_pread(ta->ph,
+ tcb_addr + ta->thread_off_tmbx +
+ offsetof(struct kse_thr_mailbox, tm_lwp),
+ &lwp, sizeof(lwp));
+ if (ret != 0)
+ return (P2T(ret));
+ /*
+ * If the lwp was already mapped to userland thread,
+ * we shouldn't reference it directly in future.
+ */
+ if (lwp == ta->map[id].lwp) {
+ ta->map[id].type = PT_NONE;
+ return (TD_NOTHR);
+ }
+ /* get next thread */
+ ret = ps_pread(ta->ph,
+ pt + ta->thread_off_next,
+ &pt, sizeof(pt));
+ if (ret != 0)
+ return (P2T(ret));
+ }
+ /* check lwp */
+ ret = ps_lgetregs(ta->ph, ta->map[id].lwp, gregs);
+ if (ret != PS_OK) {
+ /* no longer exists */
+ ta->map[id].type = PT_NONE;
+ return (TD_NOTHR);
+ }
+ } else {
+ while (pt != 0 && ta->map[id].thr != pt) {
+ ret = ps_pread(ta->ph,
+ pt + ta->thread_off_tcb,
+ &tcb_addr, sizeof(tcb_addr));
+ if (ret != 0)
+ return (P2T(ret));
+ /* get next thread */
+ ret = ps_pread(ta->ph,
+ pt + ta->thread_off_next,
+ &pt, sizeof(pt));
+ if (ret != 0)
+ return (P2T(ret));
+ }
+
+ if (pt == 0) {
+ /* no longer exists */
+ ta->map[id].type = PT_NONE;
+ return (TD_NOTHR);
+ }
+ }
+ th->th_ta = ta;
+ th->th_tid = id;
+ th->th_thread = pt;
+ return (TD_OK);
+}
+
+static td_err_e
+pt_ta_map_lwp2thr(const td_thragent_t *ta, lwpid_t lwp, td_thrhandle_t *th)
+{
+ TAILQ_HEAD(, pthread) thread_list;
+ psaddr_t pt, ptr;
+ lwpid_t tmp_lwp;
+ int ret;
+
+ TDBG_FUNC();
+
+ ret = ps_pread(ta->ph, ta->thread_list_addr, &thread_list,
+ sizeof(thread_list));
+ if (ret != 0)
+ return (P2T(ret));
+ pt = (psaddr_t)thread_list.tqh_first;
+ while (pt != 0) {
+ ret = ps_pread(ta->ph, pt + ta->thread_off_tcb,
+ &ptr, sizeof(ptr));
+ if (ret != 0)
+ return (P2T(ret));
+ ptr += ta->thread_off_tmbx +
+ offsetof(struct kse_thr_mailbox, tm_lwp);
+ ret = ps_pread(ta->ph, ptr, &tmp_lwp, sizeof(lwpid_t));
+ if (ret != 0)
+ return (P2T(ret));
+ if (tmp_lwp == lwp) {
+ th->th_ta = ta;
+ th->th_tid = pt_map_thread(ta, pt, PT_USER);
+ if (th->th_tid == -1)
+ return (TD_MALLOC);
+ pt_unmap_lwp(ta, lwp);
+ th->th_thread = pt;
+ return (TD_OK);
+ }
+
+ /* get next thread */
+ ret = ps_pread(ta->ph,
+ pt + ta->thread_off_next,
+ &pt, sizeof(pt));
+ if (ret != 0)
+ return (P2T(ret));
+ }
+
+ return (TD_NOTHR);
+}
+
+static td_err_e
+pt_ta_thr_iter(const td_thragent_t *ta,
+ td_thr_iter_f *callback, void *cbdata_p,
+ td_thr_state_e state, int ti_pri,
+ sigset_t *ti_sigmask_p,
+ unsigned int ti_user_flags)
+{
+ TAILQ_HEAD(, pthread) thread_list;
+ td_thrhandle_t th;
+ psaddr_t pt;
+ ps_err_e pserr;
+ int activated;
+
+ TDBG_FUNC();
+
+ pserr = ps_pread(ta->ph, ta->thread_activated_addr, &activated,
+ sizeof(int));
+ if (pserr != PS_OK)
+ return (P2T(pserr));
+ if (!activated)
+ return (TD_OK);
+
+ pserr = ps_pread(ta->ph, ta->thread_list_addr, &thread_list,
+ sizeof(thread_list));
+ if (pserr != 0)
+ return (P2T(pserr));
+ pt = (psaddr_t)thread_list.tqh_first;
+ while (pt != 0) {
+ th.th_ta = ta;
+ th.th_tid = pt_map_thread(ta, pt, PT_USER);
+ th.th_thread = pt;
+ /* should we unmap lwp here ? */
+ if (th.th_tid == -1)
+ return (TD_MALLOC);
+ if ((*callback)(&th, cbdata_p))
+ return (TD_DBERR);
+ /* get next thread */
+ pserr = ps_pread(ta->ph,
+ pt + ta->thread_off_next, &pt,
+ sizeof(pt));
+ if (pserr != PS_OK)
+ return (P2T(pserr));
+ }
+ return (TD_OK);
+}
+
+static td_err_e
+pt_ta_tsd_iter(const td_thragent_t *ta, td_key_iter_f *ki, void *arg)
+{
+ char *keytable;
+ void *destructor;
+ int i, ret, allocated;
+
+ TDBG_FUNC();
+
+ keytable = malloc(ta->thread_max_keys * ta->thread_size_key);
+ if (keytable == NULL)
+ return (TD_MALLOC);
+ ret = ps_pread(ta->ph, (psaddr_t)ta->thread_keytable_addr, keytable,
+ ta->thread_max_keys * ta->thread_size_key);
+ if (ret != 0) {
+ free(keytable);
+ return (P2T(ret));
+ }
+ for (i = 0; i < ta->thread_max_keys; i++) {
+ allocated = *(int *)(keytable + i * ta->thread_size_key +
+ ta->thread_off_key_allocated);
+ destructor = *(void **)(keytable + i * ta->thread_size_key +
+ ta->thread_off_key_destructor);
+ if (allocated) {
+ ret = (ki)(i, destructor, arg);
+ if (ret != 0) {
+ free(keytable);
+ return (TD_DBERR);
+ }
+ }
+ }
+ free(keytable);
+ return (TD_OK);
+}
+
+static td_err_e
+pt_ta_event_addr(const td_thragent_t *ta, td_event_e event, td_notify_t *ptr)
+{
+ TDBG_FUNC();
+ return (TD_ERR);
+}
+
+static td_err_e
+pt_ta_set_event(const td_thragent_t *ta, td_thr_events_t *events)
+{
+ TDBG_FUNC();
+ return (0);
+}
+
+static td_err_e
+pt_ta_clear_event(const td_thragent_t *ta, td_thr_events_t *events)
+{
+ TDBG_FUNC();
+ return (0);
+}
+
+static td_err_e
+pt_ta_event_getmsg(const td_thragent_t *ta, td_event_msg_t *msg)
+{
+ TDBG_FUNC();
+ return (TD_NOMSG);
+}
+
+static td_err_e
+pt_dbsuspend(const td_thrhandle_t *th, int suspend)
+{
+ td_thragent_t *ta = (td_thragent_t *)th->th_ta;
+ psaddr_t tcb_addr, tmbx_addr, ptr;
+ lwpid_t lwp;
+ uint32_t dflags;
+ int attrflags, locklevel, ret;
+
+ TDBG_FUNC();
+
+ ret = pt_validate(th);
+ if (ret)
+ return (ret);
+
+ if (ta->map[th->th_tid].type == PT_LWP) {
+ if (suspend)
+ ret = ps_lstop(ta->ph, ta->map[th->th_tid].lwp);
+ else
+ ret = ps_lcontinue(ta->ph, ta->map[th->th_tid].lwp);
+ return (P2T(ret));
+ }
+
+ ret = ps_pread(ta->ph, ta->map[th->th_tid].thr +
+ ta->thread_off_attr_flags,
+ &attrflags, sizeof(attrflags));
+ if (ret != 0)
+ return (P2T(ret));
+ ret = ps_pread(ta->ph, ta->map[th->th_tid].thr +
+ ta->thread_off_tcb,
+ &tcb_addr, sizeof(tcb_addr));
+ if (ret != 0)
+ return (P2T(ret));
+ tmbx_addr = tcb_addr + ta->thread_off_tmbx;
+ ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp);
+ ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t));
+ if (ret != 0)
+ return (P2T(ret));
+
+ if (lwp != 0) {
+ /* don't suspend signal thread */
+ if (attrflags & 0x200)
+ return (0);
+ if (attrflags & PTHREAD_SCOPE_SYSTEM) {
+ /*
+ * don't suspend system scope thread if it is holding
+ * some low level locks
+ */
+ ptr = ta->map[th->th_tid].thr + ta->thread_off_kse;
+ ret = ps_pread(ta->ph, ptr, &ptr, sizeof(ptr));
+ if (ret != 0)
+ return (P2T(ret));
+ ret = ps_pread(ta->ph, ptr + ta->thread_off_kse_locklevel,
+ &locklevel, sizeof(int));
+ if (ret != 0)
+ return (P2T(ret));
+ if (locklevel <= 0) {
+ ptr = ta->map[th->th_tid].thr +
+ ta->thread_off_thr_locklevel;
+ ret = ps_pread(ta->ph, ptr, &locklevel,
+ sizeof(int));
+ if (ret != 0)
+ return (P2T(ret));
+ }
+ if (suspend) {
+ if (locklevel <= 0)
+ ret = ps_lstop(ta->ph, lwp);
+ } else {
+ ret = ps_lcontinue(ta->ph, lwp);
+ }
+ if (ret != 0)
+ return (P2T(ret));
+ /* FALLTHROUGH */
+ } else {
+ struct ptrace_lwpinfo pl;
+
+ if (ps_linfo(ta->ph, lwp, (caddr_t)&pl))
+ return (TD_ERR);
+ if (suspend) {
+ if (!(pl.pl_flags & PL_FLAG_BOUND))
+ ret = ps_lstop(ta->ph, lwp);
+ } else {
+ ret = ps_lcontinue(ta->ph, lwp);
+ }
+ if (ret != 0)
+ return (P2T(ret));
+ /* FALLTHROUGH */
+ }
+ }
+ /* read tm_dflags */
+ ret = ps_pread(ta->ph,
+ tmbx_addr + offsetof(struct kse_thr_mailbox, tm_dflags),
+ &dflags, sizeof(dflags));
+ if (ret != 0)
+ return (P2T(ret));
+ if (suspend)
+ dflags |= TMDF_SUSPEND;
+ else
+ dflags &= ~TMDF_SUSPEND;
+ ret = ps_pwrite(ta->ph,
+ tmbx_addr + offsetof(struct kse_thr_mailbox, tm_dflags),
+ &dflags, sizeof(dflags));
+ return (P2T(ret));
+}
+
+static td_err_e
+pt_thr_dbresume(const td_thrhandle_t *th)
+{
+ TDBG_FUNC();
+
+ return pt_dbsuspend(th, 0);
+}
+
+static td_err_e
+pt_thr_dbsuspend(const td_thrhandle_t *th)
+{
+ TDBG_FUNC();
+
+ return pt_dbsuspend(th, 1);
+}
+
+static td_err_e
+pt_thr_validate(const td_thrhandle_t *th)
+{
+ td_thrhandle_t temp;
+ int ret;
+
+ TDBG_FUNC();
+
+ ret = pt_ta_map_id2thr(th->th_ta, th->th_tid,
+ &temp);
+ return (ret);
+}
+
+static td_err_e
+pt_thr_get_info(const td_thrhandle_t *th, td_thrinfo_t *info)
+{
+ const td_thragent_t *ta = th->th_ta;
+ struct ptrace_lwpinfo linfo;
+ psaddr_t tcb_addr;
+ uint32_t dflags;
+ lwpid_t lwp;
+ int state;
+ int ret;
+ int attrflags;
+
+ TDBG_FUNC();
+
+ bzero(info, sizeof(*info));
+ ret = pt_validate(th);
+ if (ret)
+ return (ret);
+
+ memset(info, 0, sizeof(*info));
+ if (ta->map[th->th_tid].type == PT_LWP) {
+ info->ti_type = TD_THR_SYSTEM;
+ info->ti_lid = ta->map[th->th_tid].lwp;
+ info->ti_tid = th->th_tid;
+ info->ti_state = TD_THR_RUN;
+ info->ti_type = TD_THR_SYSTEM;
+ return (TD_OK);
+ }
+
+ ret = ps_pread(ta->ph, ta->map[th->th_tid].thr +
+ ta->thread_off_attr_flags,
+ &attrflags, sizeof(attrflags));
+ if (ret != 0)
+ return (P2T(ret));
+ ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + ta->thread_off_tcb,
+ &tcb_addr, sizeof(tcb_addr));
+ if (ret != 0)
+ return (P2T(ret));
+ ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + ta->thread_off_state,
+ &state, sizeof(state));
+ ret = ps_pread(ta->ph,
+ tcb_addr + ta->thread_off_tmbx +
+ offsetof(struct kse_thr_mailbox, tm_lwp),
+ &info->ti_lid, sizeof(lwpid_t));
+ if (ret != 0)
+ return (P2T(ret));
+ ret = ps_pread(ta->ph,
+ tcb_addr + ta->thread_off_tmbx +
+ offsetof(struct kse_thr_mailbox, tm_dflags),
+ &dflags, sizeof(dflags));
+ if (ret != 0)
+ return (P2T(ret));
+ ret = ps_pread(ta->ph, tcb_addr + ta->thread_off_tmbx +
+ offsetof(struct kse_thr_mailbox, tm_lwp), &lwp, sizeof(lwpid_t));
+ if (ret != 0)
+ return (P2T(ret));
+ info->ti_ta_p = th->th_ta;
+ info->ti_tid = th->th_tid;
+
+ if (attrflags & PTHREAD_SCOPE_SYSTEM) {
+ ret = ps_linfo(ta->ph, lwp, &linfo);
+ if (ret == PS_OK) {
+ info->ti_sigmask = linfo.pl_sigmask;
+ info->ti_pending = linfo.pl_siglist;
+ } else
+ return (ret);
+ } else {
+ ret = ps_pread(ta->ph,
+ ta->map[th->th_tid].thr + ta->thread_off_sigmask,
+ &info->ti_sigmask, sizeof(sigset_t));
+ if (ret)
+ return (ret);
+ ret = ps_pread(ta->ph,
+ ta->map[th->th_tid].thr + ta->thread_off_sigpend,
+ &info->ti_pending, sizeof(sigset_t));
+ if (ret)
+ return (ret);
+ }
+
+ if (state == ta->thread_state_running)
+ info->ti_state = TD_THR_RUN;
+ else if (state == ta->thread_state_zoombie)
+ info->ti_state = TD_THR_ZOMBIE;
+ else
+ info->ti_state = TD_THR_SLEEP;
+ info->ti_db_suspended = ((dflags & TMDF_SUSPEND) != 0);
+ info->ti_type = TD_THR_USER;
+ return (0);
+}
+
+#ifdef __i386__
+static td_err_e
+pt_thr_getxmmregs(const td_thrhandle_t *th, char *fxsave)
+{
+ const td_thragent_t *ta = th->th_ta;
+ struct kse_thr_mailbox tmbx;
+ psaddr_t tcb_addr, tmbx_addr, ptr;
+ lwpid_t lwp;
+ int ret;
+
+ return TD_ERR;
+
+ TDBG_FUNC();
+
+ ret = pt_validate(th);
+ if (ret)
+ return (ret);
+
+ if (ta->map[th->th_tid].type == PT_LWP) {
+ ret = ps_lgetxmmregs(ta->ph, ta->map[th->th_tid].lwp, fxsave);
+ return (P2T(ret));
+ }
+
+ ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + ta->thread_off_tcb,
+ &tcb_addr, sizeof(tcb_addr));
+ if (ret != 0)
+ return (P2T(ret));
+ tmbx_addr = tcb_addr + ta->thread_off_tmbx;
+ ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp);
+ ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t));
+ if (ret != 0)
+ return (P2T(ret));
+ if (lwp != 0) {
+ ret = ps_lgetxmmregs(ta->ph, lwp, fxsave);
+ return (P2T(ret));
+ }
+
+ ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx));
+ if (ret != 0)
+ return (P2T(ret));
+ pt_ucontext_to_fxsave(&tmbx.tm_context, fxsave);
+ return (0);
+}
+#endif
+
+static td_err_e
+pt_thr_getfpregs(const td_thrhandle_t *th, prfpregset_t *fpregs)
+{
+ const td_thragent_t *ta = th->th_ta;
+ struct kse_thr_mailbox tmbx;
+ psaddr_t tcb_addr, tmbx_addr, ptr;
+ lwpid_t lwp;
+ int ret;
+
+ TDBG_FUNC();
+
+ ret = pt_validate(th);
+ if (ret)
+ return (ret);
+
+ if (ta->map[th->th_tid].type == PT_LWP) {
+ ret = ps_lgetfpregs(ta->ph, ta->map[th->th_tid].lwp, fpregs);
+ return (P2T(ret));
+ }
+
+ ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + ta->thread_off_tcb,
+ &tcb_addr, sizeof(tcb_addr));
+ if (ret != 0)
+ return (P2T(ret));
+ tmbx_addr = tcb_addr + ta->thread_off_tmbx;
+ ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp);
+ ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t));
+ if (ret != 0)
+ return (P2T(ret));
+ if (lwp != 0) {
+ ret = ps_lgetfpregs(ta->ph, lwp, fpregs);
+ return (P2T(ret));
+ }
+
+ ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx));
+ if (ret != 0)
+ return (P2T(ret));
+ pt_ucontext_to_fpreg(&tmbx.tm_context, fpregs);
+ return (0);
+}
+
+static td_err_e
+pt_thr_getgregs(const td_thrhandle_t *th, prgregset_t gregs)
+{
+ const td_thragent_t *ta = th->th_ta;
+ struct kse_thr_mailbox tmbx;
+ psaddr_t tcb_addr, tmbx_addr, ptr;
+ lwpid_t lwp;
+ int ret;
+
+ TDBG_FUNC();
+
+ ret = pt_validate(th);
+ if (ret)
+ return (ret);
+
+ if (ta->map[th->th_tid].type == PT_LWP) {
+ ret = ps_lgetregs(ta->ph,
+ ta->map[th->th_tid].lwp, gregs);
+ return (P2T(ret));
+ }
+
+ ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + ta->thread_off_tcb,
+ &tcb_addr, sizeof(tcb_addr));
+ if (ret != 0)
+ return (P2T(ret));
+ tmbx_addr = tcb_addr + ta->thread_off_tmbx;
+ ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp);
+ ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t));
+ if (ret != 0)
+ return (P2T(ret));
+ if (lwp != 0) {
+ ret = ps_lgetregs(ta->ph, lwp, gregs);
+ return (P2T(ret));
+ }
+ ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx));
+ if (ret != 0)
+ return (P2T(ret));
+ pt_ucontext_to_reg(&tmbx.tm_context, gregs);
+ return (0);
+}
+
+#ifdef __i386__
+static td_err_e
+pt_thr_setxmmregs(const td_thrhandle_t *th, const char *fxsave)
+{
+ const td_thragent_t *ta = th->th_ta;
+ struct kse_thr_mailbox tmbx;
+ psaddr_t tcb_addr, tmbx_addr, ptr;
+ lwpid_t lwp;
+ int ret;
+
+ return TD_ERR;
+
+ TDBG_FUNC();
+
+ ret = pt_validate(th);
+ if (ret)
+ return (ret);
+
+ if (ta->map[th->th_tid].type == PT_LWP) {
+ ret = ps_lsetxmmregs(ta->ph, ta->map[th->th_tid].lwp, fxsave);
+ return (P2T(ret));
+ }
+
+ ret = ps_pread(ta->ph, ta->map[th->th_tid].thr +
+ ta->thread_off_tcb,
+ &tcb_addr, sizeof(tcb_addr));
+ if (ret != 0)
+ return (P2T(ret));
+ tmbx_addr = tcb_addr + ta->thread_off_tmbx;
+ ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp);
+ ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t));
+ if (ret != 0)
+ return (P2T(ret));
+ if (lwp != 0) {
+ ret = ps_lsetxmmregs(ta->ph, lwp, fxsave);
+ return (P2T(ret));
+ }
+ /*
+ * Read a copy of context, this makes sure that registers
+ * not covered by structure reg won't be clobbered
+ */
+ ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx));
+ if (ret != 0)
+ return (P2T(ret));
+
+ pt_fxsave_to_ucontext(fxsave, &tmbx.tm_context);
+ ret = ps_pwrite(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx));
+ return (P2T(ret));
+}
+#endif
+
+static td_err_e
+pt_thr_setfpregs(const td_thrhandle_t *th, const prfpregset_t *fpregs)
+{
+ const td_thragent_t *ta = th->th_ta;
+ struct kse_thr_mailbox tmbx;
+ psaddr_t tcb_addr, tmbx_addr, ptr;
+ lwpid_t lwp;
+ int ret;
+
+ TDBG_FUNC();
+
+ ret = pt_validate(th);
+ if (ret)
+ return (ret);
+
+ if (ta->map[th->th_tid].type == PT_LWP) {
+ ret = ps_lsetfpregs(ta->ph, ta->map[th->th_tid].lwp, fpregs);
+ return (P2T(ret));
+ }
+
+ ret = ps_pread(ta->ph, ta->map[th->th_tid].thr +
+ ta->thread_off_tcb,
+ &tcb_addr, sizeof(tcb_addr));
+ if (ret != 0)
+ return (P2T(ret));
+ tmbx_addr = tcb_addr + ta->thread_off_tmbx;
+ ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp);
+ ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t));
+ if (ret != 0)
+ return (P2T(ret));
+ if (lwp != 0) {
+ ret = ps_lsetfpregs(ta->ph, lwp, fpregs);
+ return (P2T(ret));
+ }
+ /*
+ * Read a copy of context, this makes sure that registers
+ * not covered by structure reg won't be clobbered
+ */
+ ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx));
+ if (ret != 0)
+ return (P2T(ret));
+
+ pt_fpreg_to_ucontext(fpregs, &tmbx.tm_context);
+ ret = ps_pwrite(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx));
+ return (P2T(ret));
+}
+
+static td_err_e
+pt_thr_setgregs(const td_thrhandle_t *th, const prgregset_t gregs)
+{
+ const td_thragent_t *ta = th->th_ta;
+ struct kse_thr_mailbox tmbx;
+ psaddr_t tcb_addr, tmbx_addr, ptr;
+ lwpid_t lwp;
+ int ret;
+
+ TDBG_FUNC();
+
+ ret = pt_validate(th);
+ if (ret)
+ return (ret);
+
+ if (ta->map[th->th_tid].type == PT_LWP) {
+ ret = ps_lsetregs(ta->ph, ta->map[th->th_tid].lwp, gregs);
+ return (P2T(ret));
+ }
+
+ ret = ps_pread(ta->ph, ta->map[th->th_tid].thr +
+ ta->thread_off_tcb,
+ &tcb_addr, sizeof(tcb_addr));
+ if (ret != 0)
+ return (P2T(ret));
+ tmbx_addr = tcb_addr + ta->thread_off_tmbx;
+ ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp);
+ ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t));
+ if (ret != 0)
+ return (P2T(ret));
+ if (lwp != 0) {
+ ret = ps_lsetregs(ta->ph, lwp, gregs);
+ return (P2T(ret));
+ }
+
+ /*
+ * Read a copy of context, make sure that registers
+ * not covered by structure reg won't be clobbered
+ */
+ ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx));
+ if (ret != 0)
+ return (P2T(ret));
+ pt_reg_to_ucontext(gregs, &tmbx.tm_context);
+ ret = ps_pwrite(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx));
+ return (P2T(ret));
+}
+
+static td_err_e
+pt_thr_event_enable(const td_thrhandle_t *th, int en)
+{
+ TDBG_FUNC();
+ return (0);
+}
+
+static td_err_e
+pt_thr_set_event(const td_thrhandle_t *th, td_thr_events_t *setp)
+{
+ TDBG_FUNC();
+ return (0);
+}
+
+static td_err_e
+pt_thr_clear_event(const td_thrhandle_t *th, td_thr_events_t *setp)
+{
+ TDBG_FUNC();
+ return (0);
+}
+
+static td_err_e
+pt_thr_event_getmsg(const td_thrhandle_t *th, td_event_msg_t *msg)
+{
+ TDBG_FUNC();
+ return (TD_NOMSG);
+}
+
+static td_err_e
+pt_thr_sstep(const td_thrhandle_t *th, int step)
+{
+ const td_thragent_t *ta = th->th_ta;
+ struct kse_thr_mailbox tmbx;
+ struct reg regs;
+ psaddr_t tcb_addr, tmbx_addr;
+ uint32_t dflags;
+ lwpid_t lwp;
+ int ret;
+
+ TDBG_FUNC();
+
+ ret = pt_validate(th);
+ if (ret)
+ return (ret);
+
+ if (ta->map[th->th_tid].type == PT_LWP)
+ return (TD_BADTH);
+
+ ret = ps_pread(ta->ph, ta->map[th->th_tid].thr +
+ ta->thread_off_tcb,
+ &tcb_addr, sizeof(tcb_addr));
+ if (ret != 0)
+ return (P2T(ret));
+
+ /* Clear or set single step flag in thread mailbox */
+ ret = ps_pread(ta->ph,
+ tcb_addr + ta->thread_off_tmbx +
+ offsetof(struct kse_thr_mailbox, tm_dflags),
+ &dflags, sizeof(uint32_t));
+ if (ret != 0)
+ return (P2T(ret));
+ if (step != 0)
+ dflags |= TMDF_SSTEP;
+ else
+ dflags &= ~TMDF_SSTEP;
+ ret = ps_pwrite(ta->ph,
+ tcb_addr + ta->thread_off_tmbx +
+ offsetof(struct kse_thr_mailbox, tm_dflags),
+ &dflags, sizeof(uint32_t));
+ if (ret != 0)
+ return (P2T(ret));
+ /* Get lwp */
+ ret = ps_pread(ta->ph,
+ tcb_addr + ta->thread_off_tmbx +
+ offsetof(struct kse_thr_mailbox, tm_lwp),
+ &lwp, sizeof(lwpid_t));
+ if (ret != 0)
+ return (P2T(ret));
+ if (lwp != 0)
+ return (0);
+
+ tmbx_addr = tcb_addr + ta->thread_off_tmbx;
+ /*
+ * context is in userland, some architectures store
+ * single step status in registers, we should change
+ * these registers.
+ */
+ ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx));
+ if (ret == 0) {
+ pt_ucontext_to_reg(&tmbx.tm_context, &regs);
+ /* only write out if it is really changed. */
+ if (pt_reg_sstep(&regs, step) != 0) {
+ pt_reg_to_ucontext(&regs, &tmbx.tm_context);
+ ret = ps_pwrite(ta->ph, tmbx_addr, &tmbx,
+ sizeof(tmbx));
+ }
+ }
+ return (P2T(ret));
+}
+
+static void
+pt_unmap_lwp(const td_thragent_t *ta, lwpid_t lwp)
+{
+ int i;
+
+ for (i = 0; i < ta->map_len; ++i) {
+ if (ta->map[i].type == PT_LWP && ta->map[i].lwp == lwp) {
+ ta->map[i].type = PT_NONE;
+ return;
+ }
+ }
+}
+
+static int
+pt_validate(const td_thrhandle_t *th)
+{
+
+ if (th->th_tid < 0 || th->th_tid >= th->th_ta->map_len ||
+ th->th_ta->map[th->th_tid].type == PT_NONE)
+ return (TD_NOTHR);
+ return (TD_OK);
+}
+
+td_err_e
+pt_thr_tls_get_addr(const td_thrhandle_t *th, void *_linkmap, size_t offset,
+ void **address)
+{
+ char *obj_entry;
+ const td_thragent_t *ta = th->th_ta;
+ psaddr_t tcb_addr, *dtv_addr;
+ int tls_index, ret;
+
+ /* linkmap is a member of Obj_Entry */
+ obj_entry = (char *)_linkmap - ta->thread_off_linkmap;
+
+ /* get tlsindex of the object file */
+ ret = ps_pread(ta->ph,
+ obj_entry + ta->thread_off_tlsindex,
+ &tls_index, sizeof(tls_index));
+ if (ret != 0)
+ return (P2T(ret));
+
+ /* get thread tcb */
+ ret = ps_pread(ta->ph, ta->map[th->th_tid].thr +
+ ta->thread_off_tcb,
+ &tcb_addr, sizeof(tcb_addr));
+ if (ret != 0)
+ return (P2T(ret));
+
+ /* get dtv array address */
+ ret = ps_pread(ta->ph, tcb_addr + ta->thread_off_dtv,
+ &dtv_addr, sizeof(dtv_addr));
+ if (ret != 0)
+ return (P2T(ret));
+ /* now get the object's tls block base address */
+ ret = ps_pread(ta->ph, &dtv_addr[tls_index+1], address,
+ sizeof(*address));
+ if (ret != 0)
+ return (P2T(ret));
+
+ *address += offset;
+ return (TD_OK);
+}
+
+struct ta_ops libpthread_db_ops = {
+ .to_init = pt_init,
+ .to_ta_clear_event = pt_ta_clear_event,
+ .to_ta_delete = pt_ta_delete,
+ .to_ta_event_addr = pt_ta_event_addr,
+ .to_ta_event_getmsg = pt_ta_event_getmsg,
+ .to_ta_map_id2thr = pt_ta_map_id2thr,
+ .to_ta_map_lwp2thr = pt_ta_map_lwp2thr,
+ .to_ta_new = pt_ta_new,
+ .to_ta_set_event = pt_ta_set_event,
+ .to_ta_thr_iter = pt_ta_thr_iter,
+ .to_ta_tsd_iter = pt_ta_tsd_iter,
+ .to_thr_clear_event = pt_thr_clear_event,
+ .to_thr_dbresume = pt_thr_dbresume,
+ .to_thr_dbsuspend = pt_thr_dbsuspend,
+ .to_thr_event_enable = pt_thr_event_enable,
+ .to_thr_event_getmsg = pt_thr_event_getmsg,
+ .to_thr_get_info = pt_thr_get_info,
+ .to_thr_getfpregs = pt_thr_getfpregs,
+ .to_thr_getgregs = pt_thr_getgregs,
+ .to_thr_set_event = pt_thr_set_event,
+ .to_thr_setfpregs = pt_thr_setfpregs,
+ .to_thr_setgregs = pt_thr_setgregs,
+ .to_thr_validate = pt_thr_validate,
+ .to_thr_tls_get_addr = pt_thr_tls_get_addr,
+
+ /* FreeBSD specific extensions. */
+ .to_thr_sstep = pt_thr_sstep,
+#ifdef __i386__
+ .to_thr_getxmmregs = pt_thr_getxmmregs,
+ .to_thr_setxmmregs = pt_thr_setxmmregs,
+#endif
+};
diff --git a/lib/libthread_db/libpthread_db.h b/lib/libthread_db/libpthread_db.h
new file mode 100644
index 0000000..188da48
--- /dev/null
+++ b/lib/libthread_db/libpthread_db.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2004 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LIBPTHREAD_DB_H_
+#define _LIBPTHREAD_DB_H_
+
+#include <sys/ucontext.h>
+#include <machine/reg.h>
+
+#include "thread_db_int.h"
+
+struct pt_map {
+ enum {
+ PT_NONE,
+ PT_USER,
+ PT_LWP
+ } type;
+
+ union {
+ lwpid_t lwp;
+ psaddr_t thr;
+ };
+};
+
+struct td_thragent {
+ TD_THRAGENT_FIELDS;
+ psaddr_t libkse_debug_addr;
+ psaddr_t thread_list_addr;
+ psaddr_t thread_listgen_addr;
+ psaddr_t thread_activated_addr;
+ psaddr_t thread_active_threads_addr;
+ psaddr_t thread_keytable_addr;
+ int thread_activated;
+ int thread_off_dtv;
+ int thread_off_kse_locklevel;
+ int thread_off_kse;
+ int thread_off_tlsindex;
+ int thread_off_attr_flags;
+ int thread_size_key;
+ int thread_off_tcb;
+ int thread_off_linkmap;
+ int thread_off_tmbx;
+ int thread_off_thr_locklevel;
+ int thread_off_next;
+ int thread_off_state;
+ int thread_max_keys;
+ int thread_off_key_allocated;
+ int thread_off_key_destructor;
+ int thread_state_zoombie;
+ int thread_state_running;
+ int thread_off_sigmask;
+ int thread_off_sigpend;
+ struct pt_map *map;
+ int map_len;
+};
+
+void pt_md_init(void);
+void pt_reg_to_ucontext(const struct reg *, ucontext_t *);
+void pt_ucontext_to_reg(const ucontext_t *, struct reg *);
+void pt_fpreg_to_ucontext(const struct fpreg *, ucontext_t *);
+void pt_ucontext_to_fpreg(const ucontext_t *, struct fpreg *);
+#ifdef __i386__
+void pt_fxsave_to_ucontext(const char *, ucontext_t *);
+void pt_ucontext_to_fxsave(const ucontext_t *, char *);
+#endif
+int pt_reg_sstep(struct reg *reg, int step);
+
+#endif /* _LIBPTHREAD_DB_H_ */
diff --git a/lib/libthread_db/libthr_db.c b/lib/libthread_db/libthr_db.c
new file mode 100644
index 0000000..148da14
--- /dev/null
+++ b/lib/libthread_db/libthr_db.c
@@ -0,0 +1,793 @@
+/*
+ * Copyright (c) 2004 Marcel Moolenaar
+ * Copyright (c) 2005 David Xu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list 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 <proc_service.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <thread_db.h>
+#include <unistd.h>
+
+#include "thread_db_int.h"
+
+#define TERMINATED 1
+
+struct td_thragent {
+ TD_THRAGENT_FIELDS;
+ psaddr_t libthr_debug_addr;
+ psaddr_t thread_list_addr;
+ psaddr_t thread_active_threads_addr;
+ psaddr_t thread_keytable_addr;
+ psaddr_t thread_last_event_addr;
+ psaddr_t thread_event_mask_addr;
+ psaddr_t thread_bp_create_addr;
+ psaddr_t thread_bp_death_addr;
+ int thread_off_dtv;
+ int thread_off_tlsindex;
+ int thread_off_attr_flags;
+ int thread_size_key;
+ int thread_off_tcb;
+ int thread_off_linkmap;
+ int thread_off_next;
+ int thread_off_state;
+ int thread_off_tid;
+ int thread_max_keys;
+ int thread_off_key_allocated;
+ int thread_off_key_destructor;
+ int thread_off_report_events;
+ int thread_off_event_mask;
+ int thread_off_event_buf;
+ int thread_state_zoombie;
+ int thread_state_running;
+};
+
+#define P2T(c) ps2td(c)
+
+static int pt_validate(const td_thrhandle_t *th);
+
+static int
+ps2td(int c)
+{
+ switch (c) {
+ case PS_OK:
+ return TD_OK;
+ case PS_ERR:
+ return TD_ERR;
+ case PS_BADPID:
+ return TD_BADPH;
+ case PS_BADLID:
+ return TD_NOLWP;
+ case PS_BADADDR:
+ return TD_ERR;
+ case PS_NOSYM:
+ return TD_NOLIBTHREAD;
+ case PS_NOFREGS:
+ return TD_NOFPREGS;
+ default:
+ return TD_ERR;
+ }
+}
+
+static td_err_e
+pt_init(void)
+{
+ return (0);
+}
+
+static td_err_e
+pt_ta_new(struct ps_prochandle *ph, td_thragent_t **pta)
+{
+#define LOOKUP_SYM(proc, sym, addr) \
+ ret = ps_pglobal_lookup(proc, NULL, sym, addr); \
+ if (ret != 0) { \
+ TDBG("can not find symbol: %s\n", sym); \
+ ret = TD_NOLIBTHREAD; \
+ goto error; \
+ }
+
+#define LOOKUP_VAL(proc, sym, val) \
+ ret = ps_pglobal_lookup(proc, NULL, sym, &vaddr);\
+ if (ret != 0) { \
+ TDBG("can not find symbol: %s\n", sym); \
+ ret = TD_NOLIBTHREAD; \
+ goto error; \
+ } \
+ ret = ps_pread(proc, vaddr, val, sizeof(int)); \
+ if (ret != 0) { \
+ TDBG("can not read value of %s\n", sym);\
+ ret = TD_NOLIBTHREAD; \
+ goto error; \
+ }
+
+ td_thragent_t *ta;
+ psaddr_t vaddr;
+ int dbg;
+ int ret;
+
+ TDBG_FUNC();
+
+ ta = malloc(sizeof(td_thragent_t));
+ if (ta == NULL)
+ return (TD_MALLOC);
+
+ ta->ph = ph;
+
+ LOOKUP_SYM(ph, "_libthr_debug", &ta->libthr_debug_addr);
+ LOOKUP_SYM(ph, "_thread_list", &ta->thread_list_addr);
+ LOOKUP_SYM(ph, "_thread_active_threads",&ta->thread_active_threads_addr);
+ LOOKUP_SYM(ph, "_thread_keytable", &ta->thread_keytable_addr);
+ LOOKUP_SYM(ph, "_thread_last_event", &ta->thread_last_event_addr);
+ LOOKUP_SYM(ph, "_thread_event_mask", &ta->thread_event_mask_addr);
+ LOOKUP_SYM(ph, "_thread_bp_create", &ta->thread_bp_create_addr);
+ LOOKUP_SYM(ph, "_thread_bp_death", &ta->thread_bp_death_addr);
+ LOOKUP_VAL(ph, "_thread_off_dtv", &ta->thread_off_dtv);
+ LOOKUP_VAL(ph, "_thread_off_tlsindex", &ta->thread_off_tlsindex);
+ LOOKUP_VAL(ph, "_thread_off_attr_flags", &ta->thread_off_attr_flags);
+ LOOKUP_VAL(ph, "_thread_size_key", &ta->thread_size_key);
+ LOOKUP_VAL(ph, "_thread_off_tcb", &ta->thread_off_tcb);
+ LOOKUP_VAL(ph, "_thread_off_tid", &ta->thread_off_tid);
+ LOOKUP_VAL(ph, "_thread_off_linkmap", &ta->thread_off_linkmap);
+ LOOKUP_VAL(ph, "_thread_off_next", &ta->thread_off_next);
+ LOOKUP_VAL(ph, "_thread_off_state", &ta->thread_off_state);
+ LOOKUP_VAL(ph, "_thread_max_keys", &ta->thread_max_keys);
+ LOOKUP_VAL(ph, "_thread_off_key_allocated", &ta->thread_off_key_allocated);
+ LOOKUP_VAL(ph, "_thread_off_key_destructor", &ta->thread_off_key_destructor);
+ LOOKUP_VAL(ph, "_thread_state_running", &ta->thread_state_running);
+ LOOKUP_VAL(ph, "_thread_state_zoombie", &ta->thread_state_zoombie);
+ LOOKUP_VAL(ph, "_thread_off_report_events", &ta->thread_off_report_events);
+ LOOKUP_VAL(ph, "_thread_off_event_mask", &ta->thread_off_event_mask);
+ LOOKUP_VAL(ph, "_thread_off_event_buf", &ta->thread_off_event_buf);
+ dbg = getpid();
+ /*
+ * If this fails it probably means we're debugging a core file and
+ * can't write to it.
+ */
+ ps_pwrite(ph, ta->libthr_debug_addr, &dbg, sizeof(int));
+ *pta = ta;
+ return (0);
+
+error:
+ free(ta);
+ return (ret);
+}
+
+static td_err_e
+pt_ta_delete(td_thragent_t *ta)
+{
+ int dbg;
+
+ TDBG_FUNC();
+
+ dbg = 0;
+ /*
+ * Error returns from this write are not really a problem;
+ * the process doesn't exist any more.
+ */
+ ps_pwrite(ta->ph, ta->libthr_debug_addr, &dbg, sizeof(int));
+ free(ta);
+ return (TD_OK);
+}
+
+static td_err_e
+pt_ta_map_id2thr(const td_thragent_t *ta, thread_t id, td_thrhandle_t *th)
+{
+ TAILQ_HEAD(, pthread) thread_list;
+ psaddr_t pt;
+ long lwp;
+ int ret;
+
+ TDBG_FUNC();
+
+ if (id == 0)
+ return (TD_NOTHR);
+ ret = ps_pread(ta->ph, ta->thread_list_addr, &thread_list,
+ sizeof(thread_list));
+ if (ret != 0)
+ return (P2T(ret));
+ /* Iterate through thread list to find pthread */
+ pt = (psaddr_t)thread_list.tqh_first;
+ while (pt != NULL) {
+ ret = ps_pread(ta->ph, pt + ta->thread_off_tid,
+ &lwp, sizeof(lwp));
+ if (ret != 0)
+ return (P2T(ret));
+ if (lwp == id)
+ break;
+ /* get next thread */
+ ret = ps_pread(ta->ph,
+ pt + ta->thread_off_next,
+ &pt, sizeof(pt));
+ if (ret != 0)
+ return (P2T(ret));
+ }
+ if (pt == NULL)
+ return (TD_NOTHR);
+ th->th_ta = ta;
+ th->th_tid = id;
+ th->th_thread = pt;
+ return (TD_OK);
+}
+
+static td_err_e
+pt_ta_map_lwp2thr(const td_thragent_t *ta, lwpid_t lwp, td_thrhandle_t *th)
+{
+ return (pt_ta_map_id2thr(ta, lwp, th));
+}
+
+static td_err_e
+pt_ta_thr_iter(const td_thragent_t *ta,
+ td_thr_iter_f *callback, void *cbdata_p,
+ td_thr_state_e state, int ti_pri,
+ sigset_t *ti_sigmask_p,
+ unsigned int ti_user_flags)
+{
+ TAILQ_HEAD(, pthread) thread_list;
+ td_thrhandle_t th;
+ psaddr_t pt;
+ long lwp;
+ int ret;
+
+ TDBG_FUNC();
+
+ ret = ps_pread(ta->ph, ta->thread_list_addr, &thread_list,
+ sizeof(thread_list));
+ if (ret != 0)
+ return (P2T(ret));
+ pt = (psaddr_t)thread_list.tqh_first;
+ while (pt != 0) {
+ ret = ps_pread(ta->ph, pt + ta->thread_off_tid, &lwp,
+ sizeof(lwp));
+ if (ret != 0)
+ return (P2T(ret));
+ if (lwp != 0 && lwp != TERMINATED) {
+ th.th_ta = ta;
+ th.th_tid = (thread_t)lwp;
+ th.th_thread = pt;
+ if ((*callback)(&th, cbdata_p))
+ return (TD_DBERR);
+ }
+ /* get next thread */
+ ret = ps_pread(ta->ph, pt + ta->thread_off_next, &pt,
+ sizeof(pt));
+ if (ret != 0)
+ return (P2T(ret));
+ }
+ return (TD_OK);
+}
+
+static td_err_e
+pt_ta_tsd_iter(const td_thragent_t *ta, td_key_iter_f *ki, void *arg)
+{
+ char *keytable;
+ void *destructor;
+ int i, ret, allocated;
+
+ TDBG_FUNC();
+
+ keytable = malloc(ta->thread_max_keys * ta->thread_size_key);
+ if (keytable == NULL)
+ return (TD_MALLOC);
+ ret = ps_pread(ta->ph, (psaddr_t)ta->thread_keytable_addr, keytable,
+ ta->thread_max_keys * ta->thread_size_key);
+ if (ret != 0) {
+ free(keytable);
+ return (P2T(ret));
+ }
+ for (i = 0; i < ta->thread_max_keys; i++) {
+ allocated = *(int *)(keytable + i * ta->thread_size_key +
+ ta->thread_off_key_allocated);
+ destructor = *(void **)(keytable + i * ta->thread_size_key +
+ ta->thread_off_key_destructor);
+ if (allocated) {
+ ret = (ki)(i, destructor, arg);
+ if (ret != 0) {
+ free(keytable);
+ return (TD_DBERR);
+ }
+ }
+ }
+ free(keytable);
+ return (TD_OK);
+}
+
+static td_err_e
+pt_ta_event_addr(const td_thragent_t *ta, td_event_e event, td_notify_t *ptr)
+{
+
+ TDBG_FUNC();
+
+ switch (event) {
+ case TD_CREATE:
+ ptr->type = NOTIFY_BPT;
+ ptr->u.bptaddr = ta->thread_bp_create_addr;
+ return (0);
+ case TD_DEATH:
+ ptr->type = NOTIFY_BPT;
+ ptr->u.bptaddr = ta->thread_bp_death_addr;
+ return (0);
+ default:
+ return (TD_ERR);
+ }
+}
+
+static td_err_e
+pt_ta_set_event(const td_thragent_t *ta, td_thr_events_t *events)
+{
+ td_thr_events_t mask;
+ int ret;
+
+ TDBG_FUNC();
+ ret = ps_pread(ta->ph, ta->thread_event_mask_addr, &mask,
+ sizeof(mask));
+ if (ret != 0)
+ return (P2T(ret));
+ mask |= *events;
+ ret = ps_pwrite(ta->ph, ta->thread_event_mask_addr, &mask,
+ sizeof(mask));
+ return (P2T(ret));
+}
+
+static td_err_e
+pt_ta_clear_event(const td_thragent_t *ta, td_thr_events_t *events)
+{
+ td_thr_events_t mask;
+ int ret;
+
+ TDBG_FUNC();
+ ret = ps_pread(ta->ph, ta->thread_event_mask_addr, &mask,
+ sizeof(mask));
+ if (ret != 0)
+ return (P2T(ret));
+ mask &= ~*events;
+ ret = ps_pwrite(ta->ph, ta->thread_event_mask_addr, &mask,
+ sizeof(mask));
+ return (P2T(ret));
+}
+
+static td_err_e
+pt_ta_event_getmsg(const td_thragent_t *ta, td_event_msg_t *msg)
+{
+ static td_thrhandle_t handle;
+
+ psaddr_t pt, pt_temp;
+ td_thr_events_e tmp;
+ long lwp;
+ int ret;
+
+ TDBG_FUNC();
+
+ ret = ps_pread(ta->ph, ta->thread_last_event_addr, &pt, sizeof(pt));
+ if (ret != 0)
+ return (P2T(ret));
+ if (pt == NULL)
+ return (TD_NOMSG);
+ /*
+ * Take the event pointer, at the time, libthr only reports event
+ * once a time, so it is not a link list.
+ */
+ pt_temp = NULL;
+ ps_pwrite(ta->ph, ta->thread_last_event_addr, &pt_temp, sizeof(pt_temp));
+
+ /* Read event info */
+ ret = ps_pread(ta->ph, pt + ta->thread_off_event_buf, msg, sizeof(*msg));
+ if (ret != 0)
+ return (P2T(ret));
+ if (msg->event == 0)
+ return (TD_NOMSG);
+ /* Clear event */
+ tmp = 0;
+ ps_pwrite(ta->ph, pt + ta->thread_off_event_buf, &tmp, sizeof(tmp));
+ /* Convert event */
+ pt = (psaddr_t)msg->th_p;
+ ret = ps_pread(ta->ph, pt + ta->thread_off_tid, &lwp, sizeof(lwp));
+ if (ret != 0)
+ return (P2T(ret));
+ handle.th_ta = ta;
+ handle.th_tid = lwp;
+ handle.th_thread = pt;
+ msg->th_p = &handle;
+ return (0);
+}
+
+static td_err_e
+pt_dbsuspend(const td_thrhandle_t *th, int suspend)
+{
+ td_thragent_t *ta = (td_thragent_t *)th->th_ta;
+ int ret;
+
+ TDBG_FUNC();
+
+ ret = pt_validate(th);
+ if (ret)
+ return (ret);
+
+ if (suspend)
+ ret = ps_lstop(ta->ph, th->th_tid);
+ else
+ ret = ps_lcontinue(ta->ph, th->th_tid);
+ return (P2T(ret));
+}
+
+static td_err_e
+pt_thr_dbresume(const td_thrhandle_t *th)
+{
+ TDBG_FUNC();
+
+ return pt_dbsuspend(th, 0);
+}
+
+static td_err_e
+pt_thr_dbsuspend(const td_thrhandle_t *th)
+{
+ TDBG_FUNC();
+
+ return pt_dbsuspend(th, 1);
+}
+
+static td_err_e
+pt_thr_validate(const td_thrhandle_t *th)
+{
+ td_thrhandle_t temp;
+ int ret;
+
+ TDBG_FUNC();
+
+ ret = pt_ta_map_id2thr(th->th_ta, th->th_tid, &temp);
+ return (ret);
+}
+
+static td_err_e
+pt_thr_get_info(const td_thrhandle_t *th, td_thrinfo_t *info)
+{
+ const td_thragent_t *ta = th->th_ta;
+ struct ptrace_lwpinfo linfo;
+ int state;
+ int ret;
+
+ TDBG_FUNC();
+
+ bzero(info, sizeof(*info));
+ ret = pt_validate(th);
+ if (ret)
+ return (ret);
+ ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_state,
+ &state, sizeof(state));
+ if (ret != 0)
+ return (P2T(ret));
+ ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_report_events,
+ &info->ti_traceme, sizeof(int));
+ if (ret != 0)
+ return (P2T(ret));
+ ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_event_mask,
+ &info->ti_events, sizeof(td_thr_events_t));
+ if (ret != 0)
+ return (P2T(ret));
+ ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_tcb,
+ &info->ti_tls, sizeof(void *));
+ info->ti_lid = th->th_tid;
+ info->ti_tid = th->th_tid;
+ info->ti_thread = th->th_thread;
+ info->ti_ta_p = th->th_ta;
+ ret = ps_linfo(ta->ph, th->th_tid, &linfo);
+ if (ret == PS_OK) {
+ info->ti_sigmask = linfo.pl_sigmask;
+ info->ti_pending = linfo.pl_siglist;
+ } else
+ return (ret);
+ if (state == ta->thread_state_running)
+ info->ti_state = TD_THR_RUN;
+ else if (state == ta->thread_state_zoombie)
+ info->ti_state = TD_THR_ZOMBIE;
+ else
+ info->ti_state = TD_THR_SLEEP;
+ info->ti_type = TD_THR_USER;
+ return (0);
+}
+
+#ifdef __i386__
+static td_err_e
+pt_thr_getxmmregs(const td_thrhandle_t *th, char *fxsave)
+{
+ const td_thragent_t *ta = th->th_ta;
+ int ret;
+
+ TDBG_FUNC();
+
+ ret = pt_validate(th);
+ if (ret)
+ return (ret);
+
+ ret = ps_lgetxmmregs(ta->ph, th->th_tid, fxsave);
+ return (P2T(ret));
+}
+#endif
+
+static td_err_e
+pt_thr_getfpregs(const td_thrhandle_t *th, prfpregset_t *fpregs)
+{
+ const td_thragent_t *ta = th->th_ta;
+ int ret;
+
+ TDBG_FUNC();
+
+ ret = pt_validate(th);
+ if (ret)
+ return (ret);
+
+ ret = ps_lgetfpregs(ta->ph, th->th_tid, fpregs);
+ return (P2T(ret));
+}
+
+static td_err_e
+pt_thr_getgregs(const td_thrhandle_t *th, prgregset_t gregs)
+{
+ const td_thragent_t *ta = th->th_ta;
+ int ret;
+
+ TDBG_FUNC();
+
+ ret = pt_validate(th);
+ if (ret)
+ return (ret);
+
+ ret = ps_lgetregs(ta->ph, th->th_tid, gregs);
+ return (P2T(ret));
+}
+
+#ifdef __i386__
+static td_err_e
+pt_thr_setxmmregs(const td_thrhandle_t *th, const char *fxsave)
+{
+ const td_thragent_t *ta = th->th_ta;
+ int ret;
+
+ TDBG_FUNC();
+
+ ret = pt_validate(th);
+ if (ret)
+ return (ret);
+
+ ret = ps_lsetxmmregs(ta->ph, th->th_tid, fxsave);
+ return (P2T(ret));
+}
+#endif
+
+static td_err_e
+pt_thr_setfpregs(const td_thrhandle_t *th, const prfpregset_t *fpregs)
+{
+ const td_thragent_t *ta = th->th_ta;
+ int ret;
+
+ TDBG_FUNC();
+
+ ret = pt_validate(th);
+ if (ret)
+ return (ret);
+
+ ret = ps_lsetfpregs(ta->ph, th->th_tid, fpregs);
+ return (P2T(ret));
+}
+
+static td_err_e
+pt_thr_setgregs(const td_thrhandle_t *th, const prgregset_t gregs)
+{
+ const td_thragent_t *ta = th->th_ta;
+ int ret;
+
+ TDBG_FUNC();
+
+ ret = pt_validate(th);
+ if (ret)
+ return (ret);
+
+ ret = ps_lsetregs(ta->ph, th->th_tid, gregs);
+ return (P2T(ret));
+}
+
+static td_err_e
+pt_thr_event_enable(const td_thrhandle_t *th, int en)
+{
+ const td_thragent_t *ta = th->th_ta;
+ int ret;
+
+ TDBG_FUNC();
+ ret = ps_pwrite(ta->ph, th->th_thread + ta->thread_off_report_events,
+ &en, sizeof(int));
+ return (P2T(ret));
+}
+
+static td_err_e
+pt_thr_set_event(const td_thrhandle_t *th, td_thr_events_t *setp)
+{
+ const td_thragent_t *ta = th->th_ta;
+ td_thr_events_t mask;
+ int ret;
+
+ TDBG_FUNC();
+ ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_event_mask,
+ &mask, sizeof(mask));
+ mask |= *setp;
+ ret = ps_pwrite(ta->ph, th->th_thread + ta->thread_off_event_mask,
+ &mask, sizeof(mask));
+ return (P2T(ret));
+}
+
+static td_err_e
+pt_thr_clear_event(const td_thrhandle_t *th, td_thr_events_t *setp)
+{
+ const td_thragent_t *ta = th->th_ta;
+ td_thr_events_t mask;
+ int ret;
+
+ TDBG_FUNC();
+ ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_event_mask,
+ &mask, sizeof(mask));
+ mask &= ~*setp;
+ ret = ps_pwrite(ta->ph, th->th_thread + ta->thread_off_event_mask,
+ &mask, sizeof(mask));
+ return (P2T(ret));
+}
+
+static td_err_e
+pt_thr_event_getmsg(const td_thrhandle_t *th, td_event_msg_t *msg)
+{
+ static td_thrhandle_t handle;
+ td_thragent_t *ta = (td_thragent_t *)th->th_ta;
+ psaddr_t pt, pt_temp;
+ long lwp;
+ int ret;
+ td_thr_events_e tmp;
+
+ TDBG_FUNC();
+ pt = th->th_thread;
+ ret = ps_pread(ta->ph, ta->thread_last_event_addr, &pt_temp, sizeof(pt_temp));
+ if (ret != 0)
+ return (P2T(ret));
+ /* Get event */
+ ret = ps_pread(ta->ph, pt + ta->thread_off_event_buf, msg, sizeof(*msg));
+ if (ret != 0)
+ return (P2T(ret));
+ if (msg->event == 0)
+ return (TD_NOMSG);
+ /*
+ * Take the event pointer, at the time, libthr only reports event
+ * once a time, so it is not a link list.
+ */
+ if (pt == pt_temp) {
+ pt_temp = NULL;
+ ps_pwrite(ta->ph, ta->thread_last_event_addr, &pt_temp, sizeof(pt_temp));
+ }
+ /* Clear event */
+ tmp = 0;
+ ps_pwrite(ta->ph, pt + ta->thread_off_event_buf, &tmp, sizeof(tmp));
+ /* Convert event */
+ pt = (psaddr_t)msg->th_p;
+ ret = ps_pread(ta->ph, pt + ta->thread_off_tid, &lwp, sizeof(lwp));
+ if (ret != 0)
+ return (P2T(ret));
+ handle.th_ta = ta;
+ handle.th_tid = lwp;
+ handle.th_thread = pt;
+ msg->th_p = &handle;
+ return (0);
+}
+
+static td_err_e
+pt_thr_sstep(const td_thrhandle_t *th, int step)
+{
+ TDBG_FUNC();
+
+ return pt_validate(th);
+}
+
+static int
+pt_validate(const td_thrhandle_t *th)
+{
+
+ if (th->th_tid == 0 || th->th_thread == NULL)
+ return (TD_ERR);
+ return (TD_OK);
+}
+
+static td_err_e
+pt_thr_tls_get_addr(const td_thrhandle_t *th, void *_linkmap, size_t offset,
+ void **address)
+{
+ char *obj_entry;
+ const td_thragent_t *ta = th->th_ta;
+ psaddr_t tcb_addr, *dtv_addr;
+ int tls_index, ret;
+
+ /* linkmap is a member of Obj_Entry */
+ obj_entry = (char *)_linkmap - ta->thread_off_linkmap;
+
+ /* get tlsindex of the object file */
+ ret = ps_pread(ta->ph,
+ obj_entry + ta->thread_off_tlsindex,
+ &tls_index, sizeof(tls_index));
+ if (ret != 0)
+ return (P2T(ret));
+
+ /* get thread tcb */
+ ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_tcb,
+ &tcb_addr, sizeof(tcb_addr));
+ if (ret != 0)
+ return (P2T(ret));
+
+ /* get dtv array address */
+ ret = ps_pread(ta->ph, tcb_addr + ta->thread_off_dtv,
+ &dtv_addr, sizeof(dtv_addr));
+ if (ret != 0)
+ return (P2T(ret));
+ /* now get the object's tls block base address */
+ ret = ps_pread(ta->ph, &dtv_addr[tls_index+1], address,
+ sizeof(*address));
+ if (ret != 0)
+ return (P2T(ret));
+
+ *address += offset;
+ return (TD_OK);
+}
+
+struct ta_ops libthr_db_ops = {
+ .to_init = pt_init,
+ .to_ta_clear_event = pt_ta_clear_event,
+ .to_ta_delete = pt_ta_delete,
+ .to_ta_event_addr = pt_ta_event_addr,
+ .to_ta_event_getmsg = pt_ta_event_getmsg,
+ .to_ta_map_id2thr = pt_ta_map_id2thr,
+ .to_ta_map_lwp2thr = pt_ta_map_lwp2thr,
+ .to_ta_new = pt_ta_new,
+ .to_ta_set_event = pt_ta_set_event,
+ .to_ta_thr_iter = pt_ta_thr_iter,
+ .to_ta_tsd_iter = pt_ta_tsd_iter,
+ .to_thr_clear_event = pt_thr_clear_event,
+ .to_thr_dbresume = pt_thr_dbresume,
+ .to_thr_dbsuspend = pt_thr_dbsuspend,
+ .to_thr_event_enable = pt_thr_event_enable,
+ .to_thr_event_getmsg = pt_thr_event_getmsg,
+ .to_thr_get_info = pt_thr_get_info,
+ .to_thr_getfpregs = pt_thr_getfpregs,
+ .to_thr_getgregs = pt_thr_getgregs,
+ .to_thr_set_event = pt_thr_set_event,
+ .to_thr_setfpregs = pt_thr_setfpregs,
+ .to_thr_setgregs = pt_thr_setgregs,
+ .to_thr_validate = pt_thr_validate,
+ .to_thr_tls_get_addr = pt_thr_tls_get_addr,
+
+ /* FreeBSD specific extensions. */
+ .to_thr_sstep = pt_thr_sstep,
+#ifdef __i386__
+ .to_thr_getxmmregs = pt_thr_getxmmregs,
+ .to_thr_setxmmregs = pt_thr_setxmmregs,
+#endif
+};
diff --git a/lib/libthread_db/thread_db.c b/lib/libthread_db/thread_db.c
new file mode 100644
index 0000000..45400bf
--- /dev/null
+++ b/lib/libthread_db/thread_db.c
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2004 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <proc_service.h>
+#include <stddef.h>
+#include <thread_db.h>
+#include <unistd.h>
+
+#include "thread_db_int.h"
+
+struct td_thragent
+{
+ TD_THRAGENT_FIELDS;
+};
+
+static TAILQ_HEAD(, td_thragent) proclist = TAILQ_HEAD_INITIALIZER(proclist);
+
+extern struct ta_ops libc_r_db_ops;
+extern struct ta_ops libpthread_db_ops;
+extern struct ta_ops libthr_db_ops;
+
+static struct ta_ops *ops[] = {
+ &libpthread_db_ops,
+ &libthr_db_ops,
+ &libc_r_db_ops
+};
+
+td_err_e
+td_init(void)
+{
+ td_err_e ret, tmp;
+ size_t i;
+
+ ret = 0;
+ for (i = 0; i < sizeof(ops)/sizeof(ops[0]); i++) {
+ if (ops[i]->to_init != NULL) {
+ tmp = ops[i]->to_init();
+ if (tmp != TD_OK)
+ ret = tmp;
+ }
+ }
+ return (ret);
+}
+
+td_err_e
+td_ta_clear_event(const td_thragent_t *ta, td_thr_events_t *events)
+{
+ return (ta->ta_ops->to_ta_clear_event(ta, events));
+}
+
+td_err_e
+td_ta_delete(td_thragent_t *ta)
+{
+ TAILQ_REMOVE(&proclist, ta, ta_next);
+ return (ta->ta_ops->to_ta_delete(ta));
+}
+
+td_err_e
+td_ta_event_addr(const td_thragent_t *ta, td_event_e event, td_notify_t *ptr)
+{
+ return (ta->ta_ops->to_ta_event_addr(ta, event, ptr));
+}
+
+td_err_e
+td_ta_event_getmsg(const td_thragent_t *ta, td_event_msg_t *msg)
+{
+ return (ta->ta_ops->to_ta_event_getmsg(ta, msg));
+}
+
+td_err_e
+td_ta_map_id2thr(const td_thragent_t *ta, thread_t id, td_thrhandle_t *th)
+{
+ return (ta->ta_ops->to_ta_map_id2thr(ta, id, th));
+}
+
+td_err_e
+td_ta_map_lwp2thr(const td_thragent_t *ta, lwpid_t lwpid, td_thrhandle_t *th)
+{
+ return (ta->ta_ops->to_ta_map_lwp2thr(ta, lwpid, th));
+}
+
+td_err_e
+td_ta_new(struct ps_prochandle *ph, td_thragent_t **pta)
+{
+ size_t i;
+
+ for (i = 0; i < sizeof(ops)/sizeof(ops[0]); ++i) {
+ if (ops[i]->to_ta_new(ph, pta) == TD_OK) {
+ TAILQ_INSERT_HEAD(&proclist, *pta, ta_next);
+ (*pta)->ta_ops = ops[i];
+ return (TD_OK);
+ }
+ }
+ return (TD_NOLIBTHREAD);
+}
+
+td_err_e
+td_ta_set_event(const td_thragent_t *ta, td_thr_events_t *events)
+{
+ return (ta->ta_ops->to_ta_set_event(ta, events));
+}
+
+td_err_e
+td_ta_thr_iter(const td_thragent_t *ta, td_thr_iter_f *callback,
+ void *cbdata_p, td_thr_state_e state, int ti_pri, sigset_t *ti_sigmask_p,
+ unsigned int ti_user_flags)
+{
+ return (ta->ta_ops->to_ta_thr_iter(ta, callback, cbdata_p, state,
+ ti_pri, ti_sigmask_p, ti_user_flags));
+}
+
+td_err_e
+td_ta_tsd_iter(const td_thragent_t *ta, td_key_iter_f *callback,
+ void *cbdata_p)
+{
+ return (ta->ta_ops->to_ta_tsd_iter(ta, callback, cbdata_p));
+}
+
+td_err_e
+td_thr_clear_event(const td_thrhandle_t *th, td_thr_events_t *events)
+{
+ const td_thragent_t *ta = th->th_ta;
+ return (ta->ta_ops->to_thr_clear_event(th, events));
+}
+
+td_err_e
+td_thr_dbresume(const td_thrhandle_t *th)
+{
+ const td_thragent_t *ta = th->th_ta;
+ return (ta->ta_ops->to_thr_dbresume(th));
+}
+
+td_err_e
+td_thr_dbsuspend(const td_thrhandle_t *th)
+{
+ const td_thragent_t *ta = th->th_ta;
+ return (ta->ta_ops->to_thr_dbsuspend(th));
+}
+
+td_err_e
+td_thr_event_enable(const td_thrhandle_t *th, int en)
+{
+ const td_thragent_t *ta = th->th_ta;
+ return (ta->ta_ops->to_thr_event_enable(th, en));
+}
+
+td_err_e
+td_thr_event_getmsg(const td_thrhandle_t *th, td_event_msg_t *msg)
+{
+ const td_thragent_t *ta = th->th_ta;
+ return (ta->ta_ops->to_thr_event_getmsg(th, msg));
+}
+
+td_err_e
+td_thr_get_info(const td_thrhandle_t *th, td_thrinfo_t *info)
+{
+ const td_thragent_t *ta = th->th_ta;
+ return (ta->ta_ops->to_thr_get_info(th, info));
+}
+
+#ifdef __i386__
+td_err_e
+td_thr_getxmmregs(const td_thrhandle_t *th, char *fxsave)
+{
+ const td_thragent_t *ta = th->th_ta;
+ return (ta->ta_ops->to_thr_getxmmregs(th, fxsave));
+}
+#endif
+
+
+td_err_e
+td_thr_getfpregs(const td_thrhandle_t *th, prfpregset_t *fpregset)
+{
+ const td_thragent_t *ta = th->th_ta;
+ return (ta->ta_ops->to_thr_getfpregs(th, fpregset));
+}
+
+td_err_e
+td_thr_getgregs(const td_thrhandle_t *th, prgregset_t gregs)
+{
+ const td_thragent_t *ta = th->th_ta;
+ return (ta->ta_ops->to_thr_getgregs(th, gregs));
+}
+
+td_err_e
+td_thr_set_event(const td_thrhandle_t *th, td_thr_events_t *events)
+{
+ const td_thragent_t *ta = th->th_ta;
+ return (ta->ta_ops->to_thr_set_event(th, events));
+}
+
+#ifdef __i386__
+td_err_e
+td_thr_setxmmregs(const td_thrhandle_t *th, const char *fxsave)
+{
+ const td_thragent_t *ta = th->th_ta;
+ return (ta->ta_ops->to_thr_setxmmregs(th, fxsave));
+}
+#endif
+
+td_err_e
+td_thr_setfpregs(const td_thrhandle_t *th, const prfpregset_t *fpregs)
+{
+ const td_thragent_t *ta = th->th_ta;
+ return (ta->ta_ops->to_thr_setfpregs(th, fpregs));
+}
+
+td_err_e
+td_thr_setgregs(const td_thrhandle_t *th, const prgregset_t gregs)
+{
+ const td_thragent_t *ta = th->th_ta;
+ return (ta->ta_ops->to_thr_setgregs(th, gregs));
+}
+
+td_err_e
+td_thr_validate(const td_thrhandle_t *th)
+{
+ const td_thragent_t *ta = th->th_ta;
+ return (ta->ta_ops->to_thr_validate(th));
+}
+
+td_err_e
+td_thr_tls_get_addr(const td_thrhandle_t *th, void *linkmap, size_t offset,
+ void **address)
+{
+ const td_thragent_t *ta = th->th_ta;
+ return (ta->ta_ops->to_thr_tls_get_addr(th, linkmap, offset, address));
+}
+
+/* FreeBSD specific extensions. */
+
+td_err_e
+td_thr_sstep(const td_thrhandle_t *th, int step)
+{
+ const td_thragent_t *ta = th->th_ta;
+ return (ta->ta_ops->to_thr_sstep(th, step));
+}
diff --git a/lib/libthread_db/thread_db.h b/lib/libthread_db/thread_db.h
new file mode 100644
index 0000000..a05274e
--- /dev/null
+++ b/lib/libthread_db/thread_db.h
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2004 David Xu <davidxu@freebsd.org>
+ * Copyright (c) 2004 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$
+ */
+
+#ifndef _THREAD_DB_H_
+#define _THREAD_DB_H_
+
+#include <sys/procfs.h>
+#include <pthread.h>
+
+typedef enum {
+ TD_ERR = -1, /* Unspecified error. */
+ TD_OK = 0, /* No error. */
+ TD_BADKEY,
+ TD_BADPH,
+ TD_BADSH,
+ TD_BADTA,
+ TD_BADTH,
+ TD_DBERR,
+ TD_MALLOC,
+ TD_NOAPLIC,
+ TD_NOCAPAB,
+ TD_NOEVENT,
+ TD_NOFPREGS,
+ TD_NOLIBTHREAD,
+ TD_NOLWP,
+ TD_NOMSG,
+ TD_NOSV,
+ TD_NOTHR,
+ TD_NOTSD,
+ TD_NOXREGS,
+ TD_PARTIALREG
+} td_err_e;
+
+struct ps_prochandle;
+typedef struct td_thragent td_thragent_t;
+typedef long thread_t; /* Must be an integral type. */
+
+typedef struct {
+ const td_thragent_t *th_ta;
+ psaddr_t th_thread;
+ thread_t th_tid;
+} td_thrhandle_t; /* Used non-opaguely. */
+
+/*
+ * Events.
+ */
+
+typedef enum {
+ TD_EVENT_NONE = 0,
+ TD_CATCHSIG = 0x0001,
+ TD_CONCURRENCY= 0x0002,
+ TD_CREATE = 0x0004,
+ TD_DEATH = 0x0008,
+ TD_IDLE = 0x0010,
+ TD_LOCK_TRY = 0x0020,
+ TD_PREEMPT = 0x0040,
+ TD_PRI_INHERIT= 0x0080,
+ TD_READY = 0x0100,
+ TD_REAP = 0x0200,
+ TD_SLEEP = 0x0400,
+ TD_SWITCHFROM = 0x0800,
+ TD_SWITCHTO = 0x1000,
+ TD_TIMEOUT = 0x2000,
+ TD_ALL_EVENTS = ~0
+} td_thr_events_e;
+
+/* Compatibility with Linux. */
+#define td_event_e td_thr_events_e
+
+typedef struct {
+ td_thr_events_e event;
+ const td_thrhandle_t *th_p;
+ uintptr_t data;
+} td_event_msg_t;
+
+typedef unsigned int td_thr_events_t;
+
+typedef enum {
+ NOTIFY_BPT, /* User inserted breakpoint. */
+ NOTIFY_AUTOBPT, /* Automatic breakpoint. */
+ NOTIFY_SYSCALL /* Invocation of system call. */
+} td_notify_e;
+
+typedef struct {
+ td_notify_e type;
+ union {
+ psaddr_t bptaddr;
+ int syscallno;
+ } u;
+} td_notify_t;
+
+static __inline void
+td_event_addset(td_thr_events_t *es, td_thr_events_e e)
+{
+ *es |= e;
+}
+
+static __inline void
+td_event_delset(td_thr_events_t *es, td_thr_events_e e)
+{
+ *es &= ~e;
+}
+
+static __inline void
+td_event_emptyset(td_thr_events_t *es)
+{
+ *es = TD_EVENT_NONE;
+}
+
+static __inline void
+td_event_fillset(td_thr_events_t *es)
+{
+ *es = TD_ALL_EVENTS;
+}
+
+static __inline int
+td_eventisempty(td_thr_events_t *es)
+{
+ return ((*es == TD_EVENT_NONE) ? 1 : 0);
+}
+
+static __inline int
+td_eventismember(td_thr_events_t *es, td_thr_events_e e)
+{
+ return ((*es & e) ? 1 : 0);
+}
+
+/*
+ * Thread info.
+ */
+
+typedef enum {
+ TD_THR_UNKNOWN = -1,
+ TD_THR_ANY_STATE = 0,
+ TD_THR_ACTIVE,
+ TD_THR_RUN,
+ TD_THR_SLEEP,
+ TD_THR_STOPPED,
+ TD_THR_STOPPED_ASLEEP,
+ TD_THR_ZOMBIE
+} td_thr_state_e;
+
+typedef enum
+{
+ TD_THR_SYSTEM = 1,
+ TD_THR_USER
+} td_thr_type_e;
+
+typedef pthread_key_t thread_key_t;
+
+typedef struct {
+ const td_thragent_t *ti_ta_p;
+ thread_t ti_tid;
+ psaddr_t ti_thread;
+ td_thr_state_e ti_state;
+ td_thr_type_e ti_type;
+ td_thr_events_t ti_events;
+ int ti_pri;
+ lwpid_t ti_lid;
+ char ti_db_suspended;
+ char ti_traceme;
+ sigset_t ti_sigmask;
+ sigset_t ti_pending;
+ psaddr_t ti_tls;
+ psaddr_t ti_startfunc;
+ psaddr_t ti_stkbase;
+ size_t ti_stksize;
+} td_thrinfo_t;
+
+/*
+ * Prototypes.
+ */
+
+typedef int td_key_iter_f(thread_key_t, void (*)(void *), void *);
+typedef int td_thr_iter_f(const td_thrhandle_t *, void *);
+
+/* Flags for `td_ta_thr_iter'. */
+#define TD_THR_ANY_USER_FLAGS 0xffffffff
+#define TD_THR_LOWEST_PRIORITY -20
+#define TD_SIGNO_MASK NULL
+
+__BEGIN_DECLS
+td_err_e td_init(void);
+
+td_err_e td_ta_clear_event(const td_thragent_t *, td_thr_events_t *);
+td_err_e td_ta_delete(td_thragent_t *);
+td_err_e td_ta_event_addr(const td_thragent_t *, td_thr_events_e,
+ td_notify_t *);
+td_err_e td_ta_event_getmsg(const td_thragent_t *, td_event_msg_t *);
+td_err_e td_ta_map_id2thr(const td_thragent_t *, thread_t, td_thrhandle_t *);
+td_err_e td_ta_map_lwp2thr(const td_thragent_t *, lwpid_t, td_thrhandle_t *);
+td_err_e td_ta_new(struct ps_prochandle *, td_thragent_t **);
+td_err_e td_ta_set_event(const td_thragent_t *, td_thr_events_t *);
+td_err_e td_ta_thr_iter(const td_thragent_t *, td_thr_iter_f *, void *,
+ td_thr_state_e, int, sigset_t *, unsigned int);
+td_err_e td_ta_tsd_iter(const td_thragent_t *, td_key_iter_f *, void *);
+
+td_err_e td_thr_clear_event(const td_thrhandle_t *, td_thr_events_t *);
+td_err_e td_thr_dbresume(const td_thrhandle_t *);
+td_err_e td_thr_dbsuspend(const td_thrhandle_t *);
+td_err_e td_thr_event_enable(const td_thrhandle_t *, int);
+td_err_e td_thr_event_getmsg(const td_thrhandle_t *, td_event_msg_t *);
+td_err_e td_thr_get_info(const td_thrhandle_t *, td_thrinfo_t *);
+#ifdef __i386__
+td_err_e td_thr_getxmmregs(const td_thrhandle_t *, char *);
+#endif
+td_err_e td_thr_getfpregs(const td_thrhandle_t *, prfpregset_t *);
+td_err_e td_thr_getgregs(const td_thrhandle_t *, prgregset_t);
+td_err_e td_thr_set_event(const td_thrhandle_t *, td_thr_events_t *);
+#ifdef __i386__
+td_err_e td_thr_setxmmregs(const td_thrhandle_t *, const char *);
+#endif
+td_err_e td_thr_setfpregs(const td_thrhandle_t *, const prfpregset_t *);
+td_err_e td_thr_setgregs(const td_thrhandle_t *, const prgregset_t);
+td_err_e td_thr_validate(const td_thrhandle_t *);
+td_err_e td_thr_tls_get_addr(const td_thrhandle_t *, void *, size_t, void **);
+
+/* FreeBSD specific extensions. */
+td_err_e td_thr_sstep(const td_thrhandle_t *, int);
+__END_DECLS
+
+#endif /* _THREAD_DB_H_ */
diff --git a/lib/libthread_db/thread_db_int.h b/lib/libthread_db/thread_db_int.h
new file mode 100644
index 0000000..2e5ecba
--- /dev/null
+++ b/lib/libthread_db/thread_db_int.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2004 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _THREAD_DB_INT_H_
+#define _THREAD_DB_INT_H_
+
+#include <sys/types.h>
+#include <sys/queue.h>
+
+#define TD_THRAGENT_FIELDS \
+ struct ta_ops *ta_ops; \
+ TAILQ_ENTRY(td_thragent) ta_next; \
+ struct ps_prochandle *ph
+
+struct ta_ops {
+ td_err_e (*to_init)(void);
+
+ td_err_e (*to_ta_clear_event)(const td_thragent_t *,
+ td_thr_events_t *);
+ td_err_e (*to_ta_delete)(td_thragent_t *);
+ td_err_e (*to_ta_event_addr)(const td_thragent_t *, td_thr_events_e,
+ td_notify_t *);
+ td_err_e (*to_ta_event_getmsg)(const td_thragent_t *,
+ td_event_msg_t *);
+ td_err_e (*to_ta_map_id2thr)(const td_thragent_t *, thread_t,
+ td_thrhandle_t *);
+ td_err_e (*to_ta_map_lwp2thr)(const td_thragent_t *, lwpid_t,
+ td_thrhandle_t *);
+ td_err_e (*to_ta_new)(struct ps_prochandle *, td_thragent_t **);
+ td_err_e (*to_ta_set_event)(const td_thragent_t *, td_thr_events_t *);
+ td_err_e (*to_ta_thr_iter)(const td_thragent_t *, td_thr_iter_f *,
+ void *, td_thr_state_e, int, sigset_t *, unsigned int);
+ td_err_e (*to_ta_tsd_iter)(const td_thragent_t *, td_key_iter_f *,
+ void *);
+
+ td_err_e (*to_thr_clear_event)(const td_thrhandle_t *,
+ td_thr_events_t *);
+ td_err_e (*to_thr_dbresume)(const td_thrhandle_t *);
+ td_err_e (*to_thr_dbsuspend)(const td_thrhandle_t *);
+ td_err_e (*to_thr_event_enable)(const td_thrhandle_t *, int);
+ td_err_e (*to_thr_event_getmsg)(const td_thrhandle_t *,
+ td_event_msg_t *);
+ td_err_e (*to_thr_get_info)(const td_thrhandle_t *, td_thrinfo_t *);
+ td_err_e (*to_thr_getfpregs)(const td_thrhandle_t *, prfpregset_t *);
+ td_err_e (*to_thr_getgregs)(const td_thrhandle_t *, prgregset_t);
+ td_err_e (*to_thr_set_event)(const td_thrhandle_t *,
+ td_thr_events_t *);
+ td_err_e (*to_thr_setfpregs)(const td_thrhandle_t *,
+ const prfpregset_t *);
+ td_err_e (*to_thr_setgregs)(const td_thrhandle_t *, const prgregset_t);
+ td_err_e (*to_thr_validate)(const td_thrhandle_t *);
+ td_err_e (*to_thr_tls_get_addr)(const td_thrhandle_t *,
+ void *, size_t, void **);
+
+ /* FreeBSD specific extensions. */
+ td_err_e (*to_thr_sstep)(const td_thrhandle_t *, int);
+#if defined(__i386__)
+ td_err_e (*to_thr_getxmmregs)(const td_thrhandle_t *, char *);
+ td_err_e (*to_thr_setxmmregs)(const td_thrhandle_t *, const char *);
+#endif
+};
+
+#ifdef TD_DEBUG
+#define TDBG(...) ps_plog(__VA_ARGS__)
+#define TDBG_FUNC() ps_plog("%s\n", __func__)
+#else
+#define TDBG(...)
+#define TDBG_FUNC()
+#endif
+
+#endif /* _THREAD_DB_INT_H_ */
diff --git a/lib/libufs/Makefile b/lib/libufs/Makefile
new file mode 100644
index 0000000..855af17
--- /dev/null
+++ b/lib/libufs/Makefile
@@ -0,0 +1,25 @@
+# $FreeBSD$
+
+LIB= ufs
+SHLIBDIR?= /lib
+
+SRCS= block.c cgroup.c inode.c sblock.c type.c
+INCS= libufs.h
+
+MAN= bread.3 cgread.3 libufs.3 sbread.3 ufs_disk_close.3
+MLINKS+= bread.3 bwrite.3
+MLINKS+= cgread.3 cgread1.3
+MLINKS+= sbread.3 sbwrite.3
+MLINKS+= ufs_disk_close.3 ufs_disk_fillout.3
+MLINKS+= ufs_disk_close.3 ufs_disk_fillout_blank.3
+MLINKS+= ufs_disk_close.3 ufs_disk_write.3
+
+WARNS?= 2
+
+CFLAGS+= -D_LIBUFS
+.if defined(LIBUFS_DEBUG)
+CFLAGS+= -D_LIBUFS_DEBUGGING
+.endif
+CFLAGS+= -I${.CURDIR}
+
+.include <bsd.lib.mk>
diff --git a/lib/libufs/block.c b/lib/libufs/block.c
new file mode 100644
index 0000000..c4ff304
--- /dev/null
+++ b/lib/libufs/block.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2002 Juli Mallett. All rights reserved.
+ *
+ * This software was written by Juli Mallett <jmallett@FreeBSD.org> for the
+ * FreeBSD project. Redistribution and use in source and binary forms, with
+ * or without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistribution of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistribution in binary form must reproduce the above copyright
+ * notice, this list 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/mount.h>
+#include <sys/disklabel.h>
+#include <sys/stat.h>
+
+#include <ufs/ufs/ufsmount.h>
+#include <ufs/ufs/dinode.h>
+#include <ufs/ffs/fs.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <libufs.h>
+
+ssize_t
+bread(struct uufsd *disk, ufs2_daddr_t blockno, void *data, size_t size)
+{
+ void *p2;
+ ssize_t cnt;
+
+ ERROR(disk, NULL);
+
+ p2 = data;
+ /*
+ * XXX: various disk controllers require alignment of our buffer
+ * XXX: which is stricter than struct alignment.
+ * XXX: Bounce the buffer if not 64 byte aligned.
+ * XXX: this can be removed if/when the kernel is fixed
+ */
+ if (((intptr_t)data) & 0x3f) {
+ p2 = malloc(size);
+ if (p2 == NULL)
+ ERROR(disk, "allocate bounce buffer");
+ }
+ cnt = pread(disk->d_fd, p2, size, (off_t)(blockno * disk->d_bsize));
+ if (cnt == -1) {
+ ERROR(disk, "read error from block device");
+ goto fail;
+ }
+ if (cnt == 0) {
+ ERROR(disk, "end of file from block device");
+ goto fail;
+ }
+ if ((size_t)cnt != size) {
+ ERROR(disk, "short read or read error from block device");
+ goto fail;
+ }
+ if (p2 != data) {
+ memcpy(data, p2, size);
+ free(p2);
+ }
+ return (cnt);
+fail: memset(data, 0, size);
+ if (p2 != data) {
+ free(p2);
+ }
+ return (-1);
+}
+
+ssize_t
+bwrite(struct uufsd *disk, ufs2_daddr_t blockno, const void *data, size_t size)
+{
+ ssize_t cnt;
+ int rv;
+ void *p2 = NULL;
+
+ ERROR(disk, NULL);
+
+ rv = ufs_disk_write(disk);
+ if (rv == -1) {
+ ERROR(disk, "failed to open disk for writing");
+ return (-1);
+ }
+
+ /*
+ * XXX: various disk controllers require alignment of our buffer
+ * XXX: which is stricter than struct alignment.
+ * XXX: Bounce the buffer if not 64 byte aligned.
+ * XXX: this can be removed if/when the kernel is fixed
+ */
+ if (((intptr_t)data) & 0x3f) {
+ p2 = malloc(size);
+ if (p2 == NULL)
+ ERROR(disk, "allocate bounce buffer");
+ memcpy(p2, data, size);
+ data = p2;
+ }
+ cnt = pwrite(disk->d_fd, data, size, (off_t)(blockno * disk->d_bsize));
+ if (p2 != NULL)
+ free(p2);
+ if (cnt == -1) {
+ ERROR(disk, "write error to block device");
+ return (-1);
+ }
+ if ((size_t)cnt != size) {
+ ERROR(disk, "short write to block device");
+ return (-1);
+ }
+
+ return (cnt);
+}
diff --git a/lib/libufs/bread.3 b/lib/libufs/bread.3
new file mode 100644
index 0000000..80aa921
--- /dev/null
+++ b/lib/libufs/bread.3
@@ -0,0 +1,86 @@
+.\" Author: Juli Mallett <jmallett@FreeBSD.org>
+.\" Date: June 04, 2003
+.\" Description:
+.\" Manual page for libufs functions:
+.\" bread(3)
+.\" bwrite(3)
+.\"
+.\" This file is in the public domain.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd June 4, 2003
+.Dt BREAD 3
+.Os
+.Sh NAME
+.Nm bread , bwrite
+.Nd read and write blocks of a UFS file system
+.Sh LIBRARY
+.Lb libufs
+.Sh SYNOPSIS
+.In sys/param.h
+.In sys/mount.h
+.In ufs/ufs/ufsmount.h
+.In ufs/ufs/dinode.h
+.In ufs/ffs/fs.h
+.In libufs.h
+.Ft ssize_t
+.Fn bread "struct uufsd *disk" "ufs2_daddr_t blockno" "void *data" "size_t size"
+.Ft ssize_t
+.Fo bwrite
+.Fa "struct uufsd *disk" "ufs2_daddr_t blockno"
+.Fa "const void *data" "size_t size"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn bread
+and
+.Fn bwrite
+functions provide a block read and write API for
+.Xr libufs 3
+consumers.
+They operate on a userland UFS disk structure, and perform the read
+and write at a given block address, which uses the current
+.Va d_bsize
+value of the structure.
+.Sh RETURN VALUES
+The
+.Fn bread
+and
+.Fn bwrite
+functions return the amount read or written, or \-1 in case of any error,
+including short read.
+.Sh ERRORS
+The function
+.Fn bread
+may fail and set
+.Va errno
+for any of the errors specified for the library functions
+.Xr ufs_disk_write 3
+or
+.Xr pread 2 .
+Additionally, it may follow the
+.Xr libufs 3
+error methodologies in situations where the amount of data read
+is not equal to the amount requested, or in case of device error.
+.Pp
+The function
+.Fn bwrite
+may fail and set
+.Va errno
+for any of the errors specified for the library function
+.Xr pwrite 2 .
+Additionally, it may follow the
+.Xr libufs 3
+error methodologies in situations where the amount of data written
+is not equal to the amount requested, or in case of a device error.
+.Sh SEE ALSO
+.Xr libufs 3 ,
+.Xr ufs_disk_write 3
+.Sh HISTORY
+These functions first appeared as part of
+.Xr libufs 3
+in
+.Fx 5.0 .
+.Sh AUTHORS
+.An Juli Mallett Aq jmallett@FreeBSD.org
diff --git a/lib/libufs/cgread.3 b/lib/libufs/cgread.3
new file mode 100644
index 0000000..f98da40
--- /dev/null
+++ b/lib/libufs/cgread.3
@@ -0,0 +1,87 @@
+.\" Author: Juli Mallett <jmallett@FreeBSD.org>
+.\" Date: June 04, 2003
+.\" Description:
+.\" Manual page for libufs functions:
+.\" cgread(3)
+.\" cgread1(3)
+.\"
+.\" This file is in the public domain.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd June 4, 2003
+.Dt CGREAD 3
+.Os
+.Sh NAME
+.Nm cgread , cgread1
+.Nd read cylinder groups of UFS disks
+.Sh LIBRARY
+.Lb libufs
+.Sh SYNOPSIS
+.In sys/param.h
+.In sys/mount.h
+.In ufs/ufs/ufsmount.h
+.In ufs/ufs/dinode.h
+.In ufs/ffs/fs.h
+.In libufs.h
+.Ft int
+.Fn cgread "struct uufsd *disk"
+.Ft int
+.Fn cgread1 "struct uufsd *disk" "int c"
+.Sh DESCRIPTION
+The
+.Fn cgread
+and
+.Fn cgread1
+functions provide cylinder group reads for
+.Xr libufs 3
+consumers.
+The
+.Fn cgread1
+function reads from one cylinder group, specified by
+.Fa c
+into the
+.Va d_cg
+field of a userland UFS disk structure.
+It sets the
+.Va d_lcg
+field to the cylinder group number
+.Fa c .
+.Pp
+The
+.Fn cgread
+function operates on sequential cylinder groups.
+Calling the
+.Fn cgread
+function is equivalent to calling
+.Fn cgread1
+with a cylinder group specifier equivalent to the value of the current
+.Va d_ccg
+field, and then incrementing the
+.Va d_ccg
+field.
+.Sh RETURN VALUES
+Both functions return 0 if there are no more cylinder groups to read,
+1 if there are more cylinder groups, and \-1 on error.
+.Sh ERRORS
+The function
+.Fn cgread
+may fail and set
+.Va errno
+for any of the errors specified for the library function
+.Xr bread 3 .
+.Pp
+The function
+.Fn cgread1
+has semantically identical failure conditions to those of
+.Fn cgread .
+.Sh SEE ALSO
+.Xr bread 3 ,
+.Xr libufs 3
+.Sh HISTORY
+These functions first appeared as part of
+.Xr libufs 3
+in
+.Fx 5.1 .
+.Sh AUTHORS
+.An Juli Mallett Aq jmallett@FreeBSD.org
diff --git a/lib/libufs/cgroup.c b/lib/libufs/cgroup.c
new file mode 100644
index 0000000..d615b18
--- /dev/null
+++ b/lib/libufs/cgroup.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2003 Juli Mallett. All rights reserved.
+ *
+ * This software was written by Juli Mallett <jmallett@FreeBSD.org> for the
+ * FreeBSD project. Redistribution and use in source and binary forms, with
+ * or without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistribution of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistribution in binary form must reproduce the above copyright
+ * notice, this list 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/mount.h>
+#include <sys/disklabel.h>
+#include <sys/stat.h>
+
+#include <ufs/ufs/ufsmount.h>
+#include <ufs/ufs/dinode.h>
+#include <ufs/ffs/fs.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <libufs.h>
+
+int
+cgread(struct uufsd *disk)
+{
+ return (cgread1(disk, disk->d_ccg++));
+}
+
+int
+cgread1(struct uufsd *disk, int c)
+{
+ struct fs *fs;
+ off_t ccg;
+
+ fs = &disk->d_fs;
+
+ if (c >= fs->fs_ncg) {
+ return (0);
+ }
+ ccg = fsbtodb(fs, cgtod(fs, c)) * disk->d_bsize;
+ if (bread(disk, fsbtodb(fs, cgtod(fs, c)), disk->d_cgunion.d_buf,
+ fs->fs_bsize) == -1) {
+ ERROR(disk, "unable to read cylinder group");
+ return (-1);
+ }
+ disk->d_lcg = c;
+ return (1);
+}
diff --git a/lib/libufs/inode.c b/lib/libufs/inode.c
new file mode 100644
index 0000000..d8bef61
--- /dev/null
+++ b/lib/libufs/inode.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2002 Juli Mallett. All rights reserved.
+ *
+ * This software was written by Juli Mallett <jmallett@FreeBSD.org> for the
+ * FreeBSD project. Redistribution and use in source and binary forms, with
+ * or without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistribution of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistribution in binary form must reproduce the above copyright
+ * notice, this list 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/mount.h>
+#include <sys/disklabel.h>
+#include <sys/stat.h>
+
+#include <ufs/ufs/ufsmount.h>
+#include <ufs/ufs/dinode.h>
+#include <ufs/ffs/fs.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <libufs.h>
+
+int
+getino(struct uufsd *disk, void **dino, ino_t inode, int *mode)
+{
+ ino_t min, max;
+ caddr_t inoblock;
+ struct ufs1_dinode *dp1;
+ struct ufs2_dinode *dp2;
+ struct fs *fs;
+
+ ERROR(disk, NULL);
+
+ fs = &disk->d_fs;
+ inoblock = disk->d_inoblock;
+ min = disk->d_inomin;
+ max = disk->d_inomax;
+
+ if (inoblock == NULL) {
+ inoblock = malloc(fs->fs_bsize);
+ if (inoblock == NULL) {
+ ERROR(disk, "unable to allocate inode block");
+ return (-1);
+ }
+ disk->d_inoblock = inoblock;
+ }
+ if (inode >= min && inode < max)
+ goto gotit;
+ bread(disk, fsbtodb(fs, ino_to_fsba(fs, inode)), inoblock,
+ fs->fs_bsize);
+ disk->d_inomin = min = inode - (inode % INOPB(fs));
+ disk->d_inomax = max = min + INOPB(fs);
+gotit: switch (disk->d_ufs) {
+ case 1:
+ dp1 = &((struct ufs1_dinode *)inoblock)[inode - min];
+ *mode = dp1->di_mode & IFMT;
+ *dino = dp1;
+ return (0);
+ case 2:
+ dp2 = &((struct ufs2_dinode *)inoblock)[inode - min];
+ *mode = dp2->di_mode & IFMT;
+ *dino = dp2;
+ return (0);
+ default:
+ break;
+ }
+ ERROR(disk, "unknown UFS filesystem type");
+ return (-1);
+}
diff --git a/lib/libufs/libufs.3 b/lib/libufs/libufs.3
new file mode 100644
index 0000000..ecdfb27
--- /dev/null
+++ b/lib/libufs/libufs.3
@@ -0,0 +1,77 @@
+.\" Author: Juli Mallett <jmallett@FreeBSD.org>
+.\" Date: June 04, 2003
+.\" Description:
+.\" Manual page for libufs.
+.\"
+.\" This file is in the public domain.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd June 4, 2003
+.Dt LIBUFS 3
+.Os
+.Sh NAME
+.Nm libufs
+.Nd operate on UFS file systems from userland
+.Sh LIBRARY
+.Lb libufs
+.Sh SYNOPSIS
+.In sys/param.h
+.In sys/mount.h
+.In ufs/ufs/ufsmount.h
+.In ufs/ufs/dinode.h
+.In ufs/ffs/fs.h
+.In libufs.h
+.Sh DESCRIPTION
+The
+.Nm
+library and the functions it provides are used for implementing
+utilities which need to access a UFS file system at a low level from
+userland.
+Facilities provided are used to implement utilities such as
+.Xr newfs 8
+and
+.Xr dumpfs 8 .
+The
+.Nm
+library is designed to be simple, and to provide functions that are
+traditionally useful to have.
+.Pp
+A disk is represented as the type
+.Vt "struct uufsd"
+as defined in
+.In libufs.h .
+The structure is filled out, operations are performed, and the disk
+is closed.
+.Sh ERRORS
+Functions provided by
+.Nm
+return \-1 in every functional error situation.
+They also set the
+.Va d_error
+field of
+.Vt "struct uufsd"
+to a string describing the error.
+.Sh SEE ALSO
+.Xr bread 3 ,
+.Xr bwrite 3 ,
+.Xr cgread 3 ,
+.Xr cgread1 3 ,
+.Xr sbread 3 ,
+.Xr sbwrite 3 ,
+.Xr ufs_disk_close 3 ,
+.Xr ufs_disk_fillout 3 ,
+.Xr ufs_disk_fillout_blank 3 ,
+.Xr ufs_disk_write 3 ,
+.Xr ffs 7
+.Sh HISTORY
+The
+.Xr libufs 3
+library first appeared in
+.Fx 5.0 .
+.Sh AUTHORS
+.An Juli Mallett Aq jmallett@FreeBSD.org
+.Pp
+.An -nosplit
+Additional design, feedback, and ideas were provided by
+.An Poul-Henning Kamp Aq phk@FreeBSD.org .
diff --git a/lib/libufs/libufs.h b/lib/libufs/libufs.h
new file mode 100644
index 0000000..57062f9
--- /dev/null
+++ b/lib/libufs/libufs.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2002 Juli Mallett. All rights reserved.
+ *
+ * This software was written by Juli Mallett <jmallett@FreeBSD.org> for the
+ * FreeBSD project. Redistribution and use in source and binary forms, with
+ * or without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistribution of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistribution in binary form must reproduce the above copyright
+ * notice, this list 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 __LIBUFS_H__
+#define __LIBUFS_H__
+
+/*
+ * libufs macros (internal, non-exported).
+ */
+#ifdef _LIBUFS
+#ifdef _LIBUFS_DEBUGGING
+/*
+ * Trace steps through libufs, to be used at entry and erroneous return.
+ */
+#define ERROR(uufsd, str) \
+do { \
+ fprintf(stderr, "libufs in %s", __func__); \
+ if (str != NULL) \
+ fprintf(stderr, ": %s", str); \
+ if (errno) \
+ fprintf(stderr, ": %s", strerror(errno)); \
+ fprintf(stderr, "\n"); \
+ if ((uufsd) != NULL) \
+ (uufsd)->d_error = str; \
+} while (0)
+#else /* _LIBUFS_DEBUGGING */
+#define ERROR(uufsd, str) \
+do { \
+ if ((uufsd) != NULL) \
+ (uufsd)->d_error = str; \
+} while (0)
+#endif /* _LIBUFS_DEBUGGING */
+#endif /* _LIBUFS */
+
+/*
+ * libufs structures.
+ */
+
+/*
+ * userland ufs disk.
+ */
+struct uufsd {
+ const char *d_name; /* disk name */
+ int d_ufs; /* decimal UFS version */
+ int d_fd; /* raw device file descriptor */
+ long d_bsize; /* device bsize */
+ ufs2_daddr_t d_sblock; /* superblock location */
+ caddr_t d_inoblock; /* inode block */
+ ino_t d_inomin; /* low inode */
+ ino_t d_inomax; /* high inode */
+ union {
+ struct fs d_fs; /* filesystem information */
+ char d_sb[MAXBSIZE];
+ /* superblock as buffer */
+ } d_sbunion;
+ union {
+ struct cg d_cg; /* cylinder group */
+ char d_buf[MAXBSIZE];
+ /* cylinder group storage */
+ } d_cgunion;
+ int d_ccg; /* current cylinder group */
+ int d_lcg; /* last cylinder group (in d_cg) */
+ const char *d_error; /* human readable disk error */
+ int d_mine; /* internal flags */
+#define d_fs d_sbunion.d_fs
+#define d_sb d_sbunion.d_sb
+#define d_cg d_cgunion.d_cg
+};
+
+__BEGIN_DECLS
+
+/*
+ * libufs prototypes.
+ */
+
+/*
+ * block.c
+ */
+ssize_t bread(struct uufsd *, ufs2_daddr_t, void *, size_t);
+ssize_t bwrite(struct uufsd *, ufs2_daddr_t, const void *, size_t);
+
+/*
+ * cgroup.c
+ */
+int cgread(struct uufsd *);
+int cgread1(struct uufsd *, int);
+
+/*
+ * inode.c
+ */
+int getino(struct uufsd *, void **, ino_t, int *);
+
+/*
+ * sblock.c
+ */
+int sbread(struct uufsd *);
+int sbwrite(struct uufsd *, int);
+
+/*
+ * type.c
+ */
+int ufs_disk_close(struct uufsd *);
+int ufs_disk_fillout(struct uufsd *, const char *);
+int ufs_disk_fillout_blank(struct uufsd *, const char *);
+int ufs_disk_write(struct uufsd *);
+
+__END_DECLS
+
+#endif /* __LIBUFS_H__ */
diff --git a/lib/libufs/sblock.c b/lib/libufs/sblock.c
new file mode 100644
index 0000000..c9125f2
--- /dev/null
+++ b/lib/libufs/sblock.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2002 Juli Mallett. All rights reserved.
+ *
+ * This software was written by Juli Mallett <jmallett@FreeBSD.org> for the
+ * FreeBSD project. Redistribution and use in source and binary forms, with
+ * or without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistribution of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistribution in binary form must reproduce the above copyright
+ * notice, this list 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/mount.h>
+#include <sys/disklabel.h>
+#include <sys/stat.h>
+
+#include <ufs/ufs/ufsmount.h>
+#include <ufs/ufs/dinode.h>
+#include <ufs/ffs/fs.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <libufs.h>
+
+static int superblocks[] = SBLOCKSEARCH;
+
+int
+sbread(struct uufsd *disk)
+{
+ struct fs *fs;
+ int sb, superblock;
+
+ ERROR(disk, NULL);
+
+ fs = &disk->d_fs;
+ superblock = superblocks[0];
+
+ for (sb = 0; (superblock = superblocks[sb]) != -1; sb++) {
+ if (bread(disk, superblock, disk->d_sb, SBLOCKSIZE) == -1) {
+ ERROR(disk, "non-existent or truncated superblock");
+ return (-1);
+ }
+ if (fs->fs_magic == FS_UFS1_MAGIC)
+ disk->d_ufs = 1;
+ if (fs->fs_magic == FS_UFS2_MAGIC &&
+ fs->fs_sblockloc == superblock)
+ disk->d_ufs = 2;
+ if (fs->fs_bsize <= MAXBSIZE &&
+ (size_t)fs->fs_bsize >= sizeof(*fs)) {
+ if (disk->d_ufs)
+ break;
+ }
+ disk->d_ufs = 0;
+ }
+ if (superblock == -1 || disk->d_ufs == 0) {
+ /*
+ * Other error cases will result in errno being set, here we
+ * must set it to indicate no superblock could be found with
+ * which to associate this disk/filesystem.
+ */
+ ERROR(disk, "no usable known superblock found");
+ errno = ENOENT;
+ return (-1);
+ }
+ disk->d_bsize = fs->fs_fsize / fsbtodb(fs, 1);
+ disk->d_sblock = superblock / disk->d_bsize;
+ return (0);
+}
+
+int
+sbwrite(struct uufsd *disk, int all)
+{
+ struct fs *fs;
+ int i;
+
+ ERROR(disk, NULL);
+
+ fs = &disk->d_fs;
+
+ if (!disk->d_sblock) {
+ disk->d_sblock = disk->d_fs.fs_sblockloc / disk->d_bsize;
+ }
+
+ if (bwrite(disk, disk->d_sblock, fs, SBLOCKSIZE) == -1) {
+ ERROR(disk, "failed to write superblock");
+ return (-1);
+ }
+ if (all) {
+ for (i = 0; i < fs->fs_ncg; i++)
+ if (bwrite(disk, fsbtodb(fs, cgsblock(fs, i)),
+ fs, SBLOCKSIZE) == -1) {
+ ERROR(disk, "failed to update a superblock");
+ return (-1);
+ }
+ }
+ return (0);
+}
diff --git a/lib/libufs/sbread.3 b/lib/libufs/sbread.3
new file mode 100644
index 0000000..e59365a
--- /dev/null
+++ b/lib/libufs/sbread.3
@@ -0,0 +1,81 @@
+.\" Author: Juli Mallett <jmallett@FreeBSD.org>
+.\" Date: June 04, 2003
+.\" Description:
+.\" Manual page for libufs functions:
+.\" sbread(3)
+.\" sbwrite(3)
+.\"
+.\" This file is in the public domain.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd June 4, 2003
+.Dt SBREAD 3
+.Os
+.Sh NAME
+.Nm sbread , sbwrite
+.Nd read and write superblocks of a UFS file system
+.Sh LIBRARY
+.Lb libufs
+.Sh SYNOPSIS
+.In sys/param.h
+.In sys/mount.h
+.In ufs/ufs/ufsmount.h
+.In ufs/ufs/dinode.h
+.In ufs/ffs/fs.h
+.In libufs.h
+.Ft int
+.Fn sbread "struct uufsd *disk"
+.Ft int
+.Fn sbwrite "struct uufsd *disk" "int all"
+.Sh DESCRIPTION
+The
+.Fn sbread
+and
+.Fn sbwrite
+functions provide superblock reads and writes for
+.Xr libufs 3
+consumers.
+The
+.Fn sbread
+and
+.Fn sbwrite
+functions operate on the superblock field,
+.Va d_sb ,
+associated with a given userland UFS disk structure.
+Additionally, the
+.Fn sbwrite
+function will write to all superblock locations if the
+.Fa all
+value is non-zero.
+.Sh RETURN VALUES
+.Rv -std sbread sbwrite
+.Sh ERRORS
+The function
+.Fn sbread
+may fail and set
+.Va errno
+for any of the errors specified for the library function
+.Xr bread 3 .
+Additionally, it may follow the
+.Xr libufs 3
+error methodologies in situations where no usable superblock could be
+found.
+.Pp
+The function
+.Fn sbwrite
+may fail and set
+.Va errno
+for any of the errors specified for the library function
+.Xr bwrite 3 .
+.Sh SEE ALSO
+.Xr bread 3 ,
+.Xr bwrite 3 ,
+.Xr libufs 3
+.Sh HISTORY
+These functions first appeared as part of
+.Xr libufs 3
+in
+.Fx 5.0 .
+.Sh AUTHORS
+.An Juli Mallett Aq jmallett@FreeBSD.org
diff --git a/lib/libufs/type.c b/lib/libufs/type.c
new file mode 100644
index 0000000..c88da96
--- /dev/null
+++ b/lib/libufs/type.c
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2002 Juli Mallett. All rights reserved.
+ *
+ * This software was written by Juli Mallett <jmallett@FreeBSD.org> for the
+ * FreeBSD project. Redistribution and use in source and binary forms, with
+ * or without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistribution of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistribution in binary form must reproduce the above copyright
+ * notice, this list 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/mount.h>
+#include <sys/disklabel.h>
+#include <sys/stat.h>
+
+#include <ufs/ufs/ufsmount.h>
+#include <ufs/ufs/dinode.h>
+#include <ufs/ffs/fs.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <fstab.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <libufs.h>
+
+/* Internally, track the 'name' value, it's ours. */
+#define MINE_NAME 0x01
+/* Track if its fd points to a writable device. */
+#define MINE_WRITE 0x02
+
+int
+ufs_disk_close(struct uufsd *disk)
+{
+ ERROR(disk, NULL);
+ close(disk->d_fd);
+ if (disk->d_inoblock != NULL) {
+ free(disk->d_inoblock);
+ disk->d_inoblock = NULL;
+ }
+ if (disk->d_mine & MINE_NAME) {
+ free((char *)(uintptr_t)disk->d_name);
+ disk->d_name = NULL;
+ }
+ return (0);
+}
+
+int
+ufs_disk_fillout(struct uufsd *disk, const char *name)
+{
+ if (ufs_disk_fillout_blank(disk, name) == -1) {
+ return (-1);
+ }
+ if (sbread(disk) == -1) {
+ ERROR(disk, "could not read superblock to fill out disk");
+ return (-1);
+ }
+ return (0);
+}
+
+int
+ufs_disk_fillout_blank(struct uufsd *disk, const char *name)
+{
+ struct stat st;
+ struct fstab *fs;
+ const char *oname;
+ char dev[MAXPATHLEN];
+ int fd;
+
+ ERROR(disk, NULL);
+
+ oname = name;
+ fs = getfsfile(name);
+ if (fs != NULL)
+ name = fs->fs_spec;
+again: if (stat(name, &st) < 0) {
+ if (*name != '/') {
+ if (*name == 'r')
+ name++;
+ snprintf(dev, sizeof(dev), "%s%s", _PATH_DEV, name);
+ name = dev;
+ goto again;
+ }
+ ERROR(disk, "could not find special device");
+ return (-1);
+ }
+ fd = open(name, O_RDONLY);
+ if (fd == -1) {
+ ERROR(disk, "could not open special device");
+ return (-1);
+ }
+
+ disk->d_bsize = 1;
+ disk->d_ccg = 0;
+ disk->d_fd = fd;
+ disk->d_inoblock = NULL;
+ disk->d_inomin = 0;
+ disk->d_inomax = 0;
+ disk->d_lcg = 0;
+ disk->d_mine = 0;
+ disk->d_ufs = 0;
+ disk->d_error = NULL;
+
+ if (oname != name) {
+ name = strdup(name);
+ if (name == NULL) {
+ ERROR(disk, "could not allocate memory for disk name");
+ return (-1);
+ }
+ disk->d_mine |= MINE_NAME;
+ }
+ disk->d_name = name;
+
+ return (0);
+}
+
+int
+ufs_disk_write(struct uufsd *disk)
+{
+ ERROR(disk, NULL);
+
+ if (disk->d_mine & MINE_WRITE)
+ return (0);
+
+ close(disk->d_fd);
+
+ disk->d_fd = open(disk->d_name, O_RDWR);
+ if (disk->d_fd < 0) {
+ ERROR(disk, "failed to open disk for writing");
+ return (-1);
+ }
+
+ disk->d_mine |= MINE_WRITE;
+
+ return (0);
+}
diff --git a/lib/libufs/ufs_disk_close.3 b/lib/libufs/ufs_disk_close.3
new file mode 100644
index 0000000..a659116
--- /dev/null
+++ b/lib/libufs/ufs_disk_close.3
@@ -0,0 +1,112 @@
+.\" Author: Juli Mallett <jmallett@FreeBSD.org>
+.\" Date: June 04, 2003
+.\" Description:
+.\" Manual page for libufs functions:
+.\" ufs_disk_close(3)
+.\" ufs_disk_fillout(3)
+.\" ufs_disk_fillout_blank(3)
+.\" ufs_disk_write(3)
+.\"
+.\" This file is in the public domain.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd June 4, 2003
+.Dt UFS_DISK_CLOSE 3
+.Os
+.Sh NAME
+.Nm ufs_disk_close , ufs_disk_fillout , ufs_disk_fillout_blank, ufs_disk_write
+.Nd open and close userland UFS disks
+.Sh LIBRARY
+.Lb libufs
+.Sh SYNOPSIS
+.In sys/param.h
+.In sys/mount.h
+.In ufs/ufs/ufsmount.h
+.In ufs/ufs/dinode.h
+.In ufs/ffs/fs.h
+.In libufs.h
+.Ft int
+.Fn ufs_disk_close "struct uufsd *disk"
+.Ft int
+.Fn ufs_disk_fillout "struct uufsd *disk" "const char *name"
+.Ft int
+.Fn ufs_disk_fillout_blank "struct uufsd *disk" "const char *name"
+.Ft int
+.Fn ufs_disk_write "struct uufsd *disk"
+.Sh DESCRIPTION
+The
+.Fn ufs_disk_close
+function closes a disk and frees internal memory related to it.
+It does not free the
+.Fa disk
+structure.
+.Pp
+The
+.Fn ufs_disk_fillout
+and
+.Fn ufs_disk_fillout_blank
+functions open a disk specified by
+.Fa name
+and populate the structure pointed to by
+.Fa disk .
+The disk is opened read-only.
+The specified
+.Fa name
+may be either a mountpoint, or a device name.
+The
+.Fn ufs_disk_fillout
+function assumes there is a valid superblock and will fail if not,
+whereas the
+.Fn ufs_disk_fillout_blank
+function makes no assumptions of that sort.
+.Pp
+The
+.Fn ufs_disk_write
+function attempts to re-open a disk as writable if it is not currently.
+.Sh ERRORS
+The function
+.Fn ufs_disk_close
+has no failure points.
+.Pp
+The function
+.Fn ufs_disk_fillout
+may fail for any of the reasons
+.Fn ufs_disk_fillout_blank
+might, as well as for any reason
+.Xr sbread 3
+might.
+.Pp
+The
+.Fn ufs_disk_fillout_blank
+may fail and set
+.Va errno
+for any of the errors specified for the library functions
+.Xr open 2 ,
+.Xr strdup 3 .
+Additionally, it may follow the
+.Xr libufs 3
+error methodologies in situations where no device could be found to
+open.
+.Pp
+The function
+.Fn ufs_disk_write
+may fail and set
+.Va errno
+for any of the errors specified for the library functions
+.Xr open 2
+and
+.Xr stat 2 .
+Namely, it will fail if the disk in question may not be written to.
+.Sh SEE ALSO
+.Xr open 2 ,
+.Xr getfsfile 3 ,
+.Xr libufs 3 ,
+.Xr sbread 3
+.Sh HISTORY
+These functions first appeared as part of
+.Xr libufs 3
+in
+.Fx 5.0 .
+.Sh AUTHORS
+.An Juli Mallett Aq jmallett@FreeBSD.org
diff --git a/lib/libugidfw/Makefile b/lib/libugidfw/Makefile
new file mode 100644
index 0000000..bdcb5ca
--- /dev/null
+++ b/lib/libugidfw/Makefile
@@ -0,0 +1,17 @@
+# $FreeBSD$
+
+LIB= ugidfw
+SHLIB_MAJOR= 2
+SRCS= ugidfw.c
+INCS= ugidfw.h
+
+MAN+= bsde_get_rule.3 bsde_get_rule_count.3 bsde_parse_rule.3 \
+ bsde_rule_to_string.3 libugidfw.3
+
+MLINKS= bsde_get_rule.3 bsde_add_rule.3
+MLINKS+= bsde_get_rule.3 bsde_delete_rule.3
+MLINKS+= bsde_get_rule.3 bsde_set_rule.3
+MLINKS+= bsde_get_rule_count.3 bsde_get_rule_slots.3
+MLINKS+= bsde_parse_rule.3 bsde_parse_rule_string.3
+
+.include <bsd.lib.mk>
diff --git a/lib/libugidfw/bsde_get_rule.3 b/lib/libugidfw/bsde_get_rule.3
new file mode 100644
index 0000000..a3b6691
--- /dev/null
+++ b/lib/libugidfw/bsde_get_rule.3
@@ -0,0 +1,159 @@
+.\" Copyright (c) 2003-2004 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
+.\" 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 February 24, 2004
+.Os
+.Dt BSDE_GET_RULE 3
+.Sh NAME
+.Nm bsde_add_rule ,
+.Nm bsde_get_rule ,
+.Nm bsde_set_rule ,
+.Nm bsde_delete_rule
+.Nd "file system firewall rules list management"
+.Sh LIBRARY
+.Lb libugidfw
+.Sh SYNOPSIS
+.In ugidfw.h
+.Ft int
+.Fo bsde_add_rule
+.Fa "int *rulenum" "struct mac_bsdextended_rule *rule"
+.Fa "size_t buflen" "char *errstr"
+.Fc
+.Ft int
+.Fo bsde_get_rule
+.Fa "int rulenum" "struct mac_bsdextended_rule *rule"
+.Fa "size_t errlen" "char *errstr"
+.Fc
+.Ft int
+.Fo bsde_set_rule
+.Fa "int rulenum" "struct mac_bsdextended_rule *rule"
+.Fa "size_t errlen" "char *errstr"
+.Fc
+.Ft int
+.Fn bsde_delete_rule "int rulenum" "size_t errlen" "char *errstr"
+.Sh DESCRIPTION
+The
+.Fn bsde_add_rule
+function fills the next available
+rule (in
+.Vt "struct mac_bsdextended_rule"
+form, either from
+.Fn bsde_get_rule
+or
+.Xr bsde_parse_rule 3 ) .
+If an error occurs,
+.Fa *errstr
+is filled with the error string
+(up to
+.Fa errlen
+characters, including the terminating
+.Dv NUL ) .
+If successful and
+.Fa rulenum
+is
+.No non- Ns Dv NULL ,
+the rule number used will be returned in
+.Fa *rulenum .
+.Pp
+The
+.Fn bsde_get_rule
+function fills in
+.Fa *rule
+with the rule numbered
+.Fa rulenum .
+If an error occurs,
+.Fa *errstr
+is filled in with the error string
+(up to
+.Fa errlen
+characters, including the terminating
+.Dv NUL ) .
+.Pp
+The
+.Fn bsde_set_rule
+function fills the slot numbered
+.Fa rulenum
+with the specified rule
+(in
+.Vt "struct mac_bsdextended_rule"
+form, either from
+.Fn bsde_get_rule
+or
+.Xr bsde_parse_rule 3 ) .
+If an error occurs,
+.Fa *errstr
+is filled with the error string
+(up to
+.Fa errlen
+characters, including the terminating
+.Dv NUL ) .
+.Pp
+The
+.Fn bsde_delete_rule
+function deletes the rule numbered
+.Fa rulenum .
+If an error occurs,
+.Fa *errstr
+is filled with the error string
+(up to
+.Fa errlen
+characters, including the terminating
+.Dv NUL ) .
+.Sh RETURN VALUES
+The
+.Fn bsde_get_rule ,
+.Fn bsde_set_rule ,
+and
+.Fn bsde_delete_rule
+functions return 0 if successful;
+otherwise the value \-1 is returned and the value of
+.Fa *errstr
+is filled in as documented in
+.Sx DESCRIPTION .
+.Sh SEE ALSO
+.Xr bsde_get_rule_count 3 ,
+.Xr bsde_get_rule_slots 3 ,
+.Xr bsde_parse_rule 3 ,
+.Xr bsde_parse_rule_string 3 ,
+.Xr bsde_rule_to_string 3 ,
+.Xr libugidfw 3 ,
+.Xr mac_bsdextended 4 ,
+.Xr ugidfw 8
+.Sh AUTHORS
+This software was contributed to the
+.Fx
+Project by Network Associates Labs,
+the Security Research Division of Network Associates
+Inc.
+under DARPA/SPAWAR contract N66001-01-C-8035
+.Pq Dq CBOSS ,
+as part of the DARPA CHATS research program.
diff --git a/lib/libugidfw/bsde_get_rule_count.3 b/lib/libugidfw/bsde_get_rule_count.3
new file mode 100644
index 0000000..bf441e1
--- /dev/null
+++ b/lib/libugidfw/bsde_get_rule_count.3
@@ -0,0 +1,93 @@
+.\" Copyright (c) 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
+.\" 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 January 7, 2003
+.Os
+.Dt BSDE_GET_RULE_COUNT 3
+.Sh NAME
+.Nm bsde_get_rule_count ,
+.Nm bsde_get_rule_slots
+.Nd "file system firewall statistics"
+.Sh LIBRARY
+.Lb libugidfw
+.Sh SYNOPSIS
+.In ugidfw.h
+.Ft int
+.Fn bsde_get_rule_count "size_t errlen" "char *errstr"
+.Ft int
+.Fn bsde_get_rule_slots "size_t errlen" "char *errstr"
+.Sh DESCRIPTION
+The
+.Fn bsde_get_rule_count
+and
+.Fn bsde_get_rule_slots
+functions
+return the total number of enforced rules
+and the total number of used rule slots, respectively.
+If an error occurs,
+.Fa *errstr
+is filled in with the error string
+(up to
+.Fa errlen
+characters, including the terminating
+.Dv NUL ) .
+.Sh RETURN VALUES
+The
+.Fn bsde_get_rule_count
+and
+.Fn bsde_get_rule_slots
+functions return
+the number of enforced rules and rule slots (respectively)
+if successful;
+otherwise the value \-1 is returned and the value of
+.Fa *errstr
+is filled in as documented in
+.Sx DESCRIPTION .
+.Sh SEE ALSO
+.Xr bsde_delete_rule 3 ,
+.Xr bsde_get_rule 3 ,
+.Xr bsde_parse_rule 3 ,
+.Xr bsde_parse_rule_string 3 ,
+.Xr bsde_rule_to_string 3 ,
+.Xr bsde_set_rule 3 ,
+.Xr libugidfw 3 ,
+.Xr mac_bsdextended 4 ,
+.Xr ugidfw 8
+.Sh AUTHORS
+This software was contributed to the
+.Fx
+Project by Network Associates Labs,
+the Security Research Division of Network Associates
+Inc.
+under DARPA/SPAWAR contract N66001-01-C-8035
+.Pq Dq CBOSS ,
+as part of the DARPA CHATS research program.
diff --git a/lib/libugidfw/bsde_parse_rule.3 b/lib/libugidfw/bsde_parse_rule.3
new file mode 100644
index 0000000..d510cab
--- /dev/null
+++ b/lib/libugidfw/bsde_parse_rule.3
@@ -0,0 +1,105 @@
+.\" Copyright (c) 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
+.\" 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 January 7, 2003
+.Os
+.Dt BSDE_PARSE_RULE 3
+.Sh NAME
+.Nm bsde_parse_rule ,
+.Nm bsde_parse_rule_string
+.Nd "parse file system firewall rules"
+.Sh LIBRARY
+.Lb libugidfw
+.Sh SYNOPSIS
+.In ugidfw.h
+.Ft int
+.Fo bsde_parse_rule
+.Fa "int argc" "char *argv[]" "struct mac_bsdextended_rule *rule"
+.Fa "size_t buflen" "char *errstr"
+.Fc
+.Ft int
+.Fo bsde_parse_rule_string
+.Fa "const char *string" "struct mac_bsdextended_rule *rule"
+.Fa "size_t buflen" "char *errstr"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn bsde_parse_rule
+function parses an argument vector
+(e.g.\&
+.Fa argv
+as passed to
+.Fn main )
+into
+.Fa rule .
+If an error occurs,
+.Fa *errstr
+is filled in with the error string
+(up to
+.Fa errlen
+characters, including the terminating
+.Dv NUL ) .
+.Pp
+The
+.Fn bsde_parse_rule_string
+function is identical to
+.Fn bsde_parse_rule ,
+except that it parses a single string rather than an array of arguments.
+.Sh RETURN VALUES
+The
+.Fn bsde_parse_rule_string
+and
+.Fn bsde_parse_rule
+functions return 0 if successful;
+otherwise the value \-1 is returned and the value of
+.Fa *errstr
+is filled in as documented in
+.Sx DESCRIPTION .
+.Sh SEE ALSO
+.Xr bsde_delete_rule 3 ,
+.Xr bsde_get_rule 3 ,
+.Xr bsde_get_rule_count 3 ,
+.Xr bsde_get_rule_slots 3 ,
+.Xr bsde_rule_to_string 3 ,
+.Xr bsde_set_rule 3 ,
+.Xr libugidfw 3 ,
+.Xr mac_bsdextended 4 ,
+.Xr ugidfw 8
+.Sh AUTHORS
+This software was contributed to the
+.Fx
+Project by Network Associates Labs,
+the Security Research Division of Network Associates
+Inc.
+under DARPA/SPAWAR contract N66001-01-C-8035
+.Pq Dq CBOSS ,
+as part of the DARPA CHATS research program.
diff --git a/lib/libugidfw/bsde_rule_to_string.3 b/lib/libugidfw/bsde_rule_to_string.3
new file mode 100644
index 0000000..4414406
--- /dev/null
+++ b/lib/libugidfw/bsde_rule_to_string.3
@@ -0,0 +1,82 @@
+.\" Copyright (c) 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
+.\" 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 January 7, 2003
+.Os
+.Dt BSDE_RULE_TO_STRING 3
+.Sh NAME
+.Nm bsde_rule_to_string
+.Nd "convert a ugidfw rule into its text representation"
+.Sh LIBRARY
+.Lb libugidfw
+.Sh SYNOPSIS
+.In ugidfw.h
+.Ft int
+.Fo bsde_rule_to_string
+.Fa "struct mac_bsdextended_rule *rule" "char *buf" "size_t buflen"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn bsde_rule_to_string
+function converts a rule in its internal representation
+.Pq Vt "struct mac_bsdextended_rule"
+into its text representation, and writes up to
+.Fa buflen
+bytes of it to
+.Fa buf
+(including the terminating
+.Dv NUL ) .
+.Sh RETURN VALUES
+The
+.Fn bsde_rule_to_string
+function returns \-1 if the conversion was truncated;
+otherwise the value 0 is returned.
+.Sh SEE ALSO
+.Xr bsde_delete_rule 3 ,
+.Xr bsde_get_rule 3 ,
+.Xr bsde_get_rule_count 3 ,
+.Xr bsde_get_rule_slots 3 ,
+.Xr bsde_parse_rule 3 ,
+.Xr bsde_parse_rule_string 3 ,
+.Xr bsde_set_rule 3 ,
+.Xr libugidfw 3 ,
+.Xr mac_bsdextended 4 ,
+.Xr ugidfw 8
+.Sh AUTHORS
+This software was contributed to the
+.Fx
+Project by Network Associates Labs,
+the Security Research Division of Network Associates
+Inc.
+under DARPA/SPAWAR contract N66001-01-C-8035
+.Pq Dq CBOSS ,
+as part of the DARPA CHATS research program.
diff --git a/lib/libugidfw/libugidfw.3 b/lib/libugidfw/libugidfw.3
new file mode 100644
index 0000000..3ff407c
--- /dev/null
+++ b/lib/libugidfw/libugidfw.3
@@ -0,0 +1,115 @@
+.\" Copyright (c) 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
+.\" 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 February 25, 2004
+.Os
+.Dt LIBUGIDFW 3
+.Sh NAME
+.Nm libugidfw
+.Nd "library interface to the file system firewall MAC policy"
+.Sh LIBRARY
+.Lb libugidfw
+.Sh SYNOPSIS
+.In sys/types.h
+.In security/mac_bsdextended/mac_bsdextended.h
+.In ugidfw.h
+.Sh DESCRIPTION
+The
+.Nm
+library routines provide an interface to the
+.Xr mac_bsdextended 4
+file system firewall MAC policy.
+.Pp
+The
+.Nm
+library defines the following functions:
+.Bl -tag -width ".Fn bsde_parse_rule_string"
+.It Fn bsde_rule_to_string
+Converts the internal representation of a rule
+.Pq Vt "struct mac_bsdextended_rule"
+into its text representation;
+see
+.Xr bsde_rule_to_string 3 .
+.It Fn bsde_parse_rule
+Parses an entire rule
+(in argument array form);
+see
+.Xr bsde_parse_rule 3 .
+.It Fn bsde_parse_rule_string
+Parses an entire rule string;
+see
+.Xr bsde_parse_rule_string 3 .
+.It Fn bsde_get_rule_count
+Returns the total number of ugidfw rules being enforced in the system;
+see
+.Xr bsde_get_rule_count 3 .
+.It Fn bsde_get_rule_slots
+Returns the total number of used rule slots;
+see
+.Xr bsde_get_rule_slots 3 .
+.It Fn bsde_get_rule
+Returns a rule by its rule number;
+see
+.Xr bsde_get_rule 3 .
+.It Fn bsde_delete_rule
+Deletes a rule by its rule number;
+see
+.Xr bsde_delete_rule 3 .
+.It Fn bsde_set_rule
+Uploads the rule to the
+.Xr mac_bsdextended 4
+module and applies it;
+see
+.Xr bsde_set_rule 3 .
+.It Fn bsde_add_rule
+Upload the rule to the module, automatically selecting the next available
+rule number; see
+.Xr bsde_add_rule 3 .
+.El
+.Sh SEE ALSO
+.Xr bsde_delete_rule 3 ,
+.Xr bsde_get_rule 3 ,
+.Xr bsde_get_rule_count 3 ,
+.Xr bsde_get_rule_slots 3 ,
+.Xr bsde_parse_rule 3 ,
+.Xr bsde_parse_rule_string 3 ,
+.Xr bsde_rule_to_string 3 ,
+.Xr bsde_set_rule 3
+.Sh AUTHORS
+This software was contributed to the
+.Fx
+Project by Network Associates Labs,
+the Security Research Division of Network Associates
+Inc.
+under DARPA/SPAWAR contract N66001-01-C-8035
+.Pq Dq CBOSS ,
+as part of the DARPA CHATS research program.
diff --git a/lib/libugidfw/ugidfw.c b/lib/libugidfw/ugidfw.c
new file mode 100644
index 0000000..341ac25
--- /dev/null
+++ b/lib/libugidfw/ugidfw.c
@@ -0,0 +1,1323 @@
+/*-
+ * Copyright (c) 2002-2005 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project 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.
+ *
+ * $FreeBSD$
+ */
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/time.h>
+#include <sys/sysctl.h>
+#include <sys/ucred.h>
+#include <sys/mount.h>
+
+#include <security/mac_bsdextended/mac_bsdextended.h>
+
+#include <grp.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ugidfw.h"
+
+/*
+ * Text format for rules: rules contain subject and object elements, mode.
+ * The total form is "subject [s_element] object [o_element] mode [mode]".
+ * At least * one of a uid or gid entry must be present; both may also be
+ * present.
+ */
+
+#define MIB "security.mac.bsdextended"
+
+int
+bsde_rule_to_string(struct mac_bsdextended_rule *rule, char *buf, size_t buflen)
+{
+ struct group *grp;
+ struct passwd *pwd;
+ struct statfs *mntbuf;
+ char *cur, type[sizeof(rule->mbr_object.mbo_type) * CHAR_BIT + 1];
+ size_t left, len;
+ int anymode, unknownmode, truncated, numfs, i, notdone;
+
+ cur = buf;
+ left = buflen;
+ truncated = 0;
+
+ len = snprintf(cur, left, "subject ");
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ if (rule->mbr_subject.mbs_flags) {
+ if (rule->mbr_subject.mbs_neg == MBS_ALL_FLAGS) {
+ len = snprintf(cur, left, "not ");
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ notdone = 1;
+ } else {
+ notdone = 0;
+ }
+
+ if (!notdone && (rule->mbr_subject.mbs_neg & MBO_UID_DEFINED)) {
+ len = snprintf(cur, left, "! ");
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ }
+ if (rule->mbr_subject.mbs_flags & MBO_UID_DEFINED) {
+ pwd = getpwuid(rule->mbr_subject.mbs_uid_min);
+ if (pwd != NULL) {
+ len = snprintf(cur, left, "uid %s",
+ pwd->pw_name);
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ } else {
+ len = snprintf(cur, left, "uid %u",
+ rule->mbr_subject.mbs_uid_min);
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ }
+ if (rule->mbr_subject.mbs_uid_min !=
+ rule->mbr_subject.mbs_uid_max) {
+ pwd = getpwuid(rule->mbr_subject.mbs_uid_max);
+ if (pwd != NULL) {
+ len = snprintf(cur, left, ":%s ",
+ pwd->pw_name);
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ } else {
+ len = snprintf(cur, left, ":%u ",
+ rule->mbr_subject.mbs_uid_max);
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ }
+ } else {
+ len = snprintf(cur, left, " ");
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ }
+ }
+ if (!notdone && (rule->mbr_subject.mbs_neg & MBO_GID_DEFINED)) {
+ len = snprintf(cur, left, "! ");
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ }
+ if (rule->mbr_subject.mbs_flags & MBO_GID_DEFINED) {
+ grp = getgrgid(rule->mbr_subject.mbs_gid_min);
+ if (grp != NULL) {
+ len = snprintf(cur, left, "gid %s",
+ grp->gr_name);
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ } else {
+ len = snprintf(cur, left, "gid %u",
+ rule->mbr_subject.mbs_gid_min);
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ }
+ if (rule->mbr_subject.mbs_gid_min !=
+ rule->mbr_subject.mbs_gid_max) {
+ grp = getgrgid(rule->mbr_subject.mbs_gid_max);
+ if (grp != NULL) {
+ len = snprintf(cur, left, ":%s ",
+ grp->gr_name);
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ } else {
+ len = snprintf(cur, left, ":%u ",
+ rule->mbr_subject.mbs_gid_max);
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ }
+ } else {
+ len = snprintf(cur, left, " ");
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ }
+ }
+ if (!notdone && (rule->mbr_subject.mbs_neg & MBS_PRISON_DEFINED)) {
+ len = snprintf(cur, left, "! ");
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ }
+ if (rule->mbr_subject.mbs_flags & MBS_PRISON_DEFINED) {
+ len = snprintf(cur, left, "jailid %d ",
+ rule->mbr_subject.mbs_prison);
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ }
+ }
+
+ len = snprintf(cur, left, "object ");
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ if (rule->mbr_object.mbo_flags) {
+ if (rule->mbr_object.mbo_neg == MBO_ALL_FLAGS) {
+ len = snprintf(cur, left, "not ");
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ notdone = 1;
+ } else {
+ notdone = 0;
+ }
+
+ if (!notdone && (rule->mbr_object.mbo_neg & MBO_UID_DEFINED)) {
+ len = snprintf(cur, left, "! ");
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ }
+ if (rule->mbr_object.mbo_flags & MBO_UID_DEFINED) {
+ pwd = getpwuid(rule->mbr_object.mbo_uid_min);
+ if (pwd != NULL) {
+ len = snprintf(cur, left, "uid %s",
+ pwd->pw_name);
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ } else {
+ len = snprintf(cur, left, "uid %u",
+ rule->mbr_object.mbo_uid_min);
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ }
+ if (rule->mbr_object.mbo_uid_min !=
+ rule->mbr_object.mbo_uid_max) {
+ pwd = getpwuid(rule->mbr_object.mbo_uid_max);
+ if (pwd != NULL) {
+ len = snprintf(cur, left, ":%s ",
+ pwd->pw_name);
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ } else {
+ len = snprintf(cur, left, ":%u ",
+ rule->mbr_object.mbo_uid_max);
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ }
+ } else {
+ len = snprintf(cur, left, " ");
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ }
+ }
+ if (!notdone && (rule->mbr_object.mbo_neg & MBO_GID_DEFINED)) {
+ len = snprintf(cur, left, "! ");
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ }
+ if (rule->mbr_object.mbo_flags & MBO_GID_DEFINED) {
+ grp = getgrgid(rule->mbr_object.mbo_gid_min);
+ if (grp != NULL) {
+ len = snprintf(cur, left, "gid %s",
+ grp->gr_name);
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ } else {
+ len = snprintf(cur, left, "gid %u",
+ rule->mbr_object.mbo_gid_min);
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ }
+ if (rule->mbr_object.mbo_gid_min !=
+ rule->mbr_object.mbo_gid_max) {
+ grp = getgrgid(rule->mbr_object.mbo_gid_max);
+ if (grp != NULL) {
+ len = snprintf(cur, left, ":%s ",
+ grp->gr_name);
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ } else {
+ len = snprintf(cur, left, ":%u ",
+ rule->mbr_object.mbo_gid_max);
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ }
+ } else {
+ len = snprintf(cur, left, " ");
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ }
+ }
+ if (!notdone && (rule->mbr_object.mbo_neg & MBO_FSID_DEFINED)) {
+ len = snprintf(cur, left, "! ");
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ }
+ if (rule->mbr_object.mbo_flags & MBO_FSID_DEFINED) {
+ numfs = getmntinfo(&mntbuf, MNT_NOWAIT);
+ for (i = 0; i < numfs; i++)
+ if (memcmp(&(rule->mbr_object.mbo_fsid),
+ &(mntbuf[i].f_fsid),
+ sizeof(mntbuf[i].f_fsid)) == 0)
+ break;
+ len = snprintf(cur, left, "filesys %s ",
+ i == numfs ? "???" : mntbuf[i].f_mntonname);
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ }
+ if (!notdone && (rule->mbr_object.mbo_neg & MBO_SUID)) {
+ len = snprintf(cur, left, "! ");
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ }
+ if (rule->mbr_object.mbo_flags & MBO_SUID) {
+ len = snprintf(cur, left, "suid ");
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ }
+ if (!notdone && (rule->mbr_object.mbo_neg & MBO_SGID)) {
+ len = snprintf(cur, left, "! ");
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ }
+ if (rule->mbr_object.mbo_flags & MBO_SGID) {
+ len = snprintf(cur, left, "sgid ");
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ }
+ if (!notdone && (rule->mbr_object.mbo_neg & MBO_UID_SUBJECT)) {
+ len = snprintf(cur, left, "! ");
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ }
+ if (rule->mbr_object.mbo_flags & MBO_UID_SUBJECT) {
+ len = snprintf(cur, left, "uid_of_subject ");
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ }
+ if (!notdone && (rule->mbr_object.mbo_neg & MBO_GID_SUBJECT)) {
+ len = snprintf(cur, left, "! ");
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ }
+ if (rule->mbr_object.mbo_flags & MBO_GID_SUBJECT) {
+ len = snprintf(cur, left, "gid_of_subject ");
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ }
+ if (!notdone && (rule->mbr_object.mbo_neg & MBO_TYPE_DEFINED)) {
+ len = snprintf(cur, left, "! ");
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ }
+ if (rule->mbr_object.mbo_flags & MBO_TYPE_DEFINED) {
+ i = 0;
+ if (rule->mbr_object.mbo_type & MBO_TYPE_REG)
+ type[i++] = 'r';
+ if (rule->mbr_object.mbo_type & MBO_TYPE_DIR)
+ type[i++] = 'd';
+ if (rule->mbr_object.mbo_type & MBO_TYPE_BLK)
+ type[i++] = 'b';
+ if (rule->mbr_object.mbo_type & MBO_TYPE_CHR)
+ type[i++] = 'c';
+ if (rule->mbr_object.mbo_type & MBO_TYPE_LNK)
+ type[i++] = 'l';
+ if (rule->mbr_object.mbo_type & MBO_TYPE_SOCK)
+ type[i++] = 's';
+ if (rule->mbr_object.mbo_type & MBO_TYPE_FIFO)
+ type[i++] = 'p';
+ if (rule->mbr_object.mbo_type == MBO_ALL_TYPE) {
+ i = 0;
+ type[i++] = 'a';
+ }
+ type[i++] = '\0';
+ len = snprintf(cur, left, "type %s ", type);
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+ }
+ }
+
+ len = snprintf(cur, left, "mode ");
+ if (len < 0 || len > left)
+ goto truncated;
+ left -= len;
+ cur += len;
+
+ anymode = (rule->mbr_mode & MBI_ALLPERM);
+ unknownmode = (rule->mbr_mode & ~MBI_ALLPERM);
+
+ if (rule->mbr_mode & MBI_ADMIN) {
+ len = snprintf(cur, left, "a");
+ if (len < 0 || len > left)
+ goto truncated;
+
+ left -= len;
+ cur += len;
+ }
+ if (rule->mbr_mode & MBI_READ) {
+ len = snprintf(cur, left, "r");
+ if (len < 0 || len > left)
+ goto truncated;
+
+ left -= len;
+ cur += len;
+ }
+ if (rule->mbr_mode & MBI_STAT) {
+ len = snprintf(cur, left, "s");
+ if (len < 0 || len > left)
+ goto truncated;
+
+ left -= len;
+ cur += len;
+ }
+ if (rule->mbr_mode & MBI_WRITE) {
+ len = snprintf(cur, left, "w");
+ if (len < 0 || len > left)
+ goto truncated;
+
+ left -= len;
+ cur += len;
+ }
+ if (rule->mbr_mode & MBI_EXEC) {
+ len = snprintf(cur, left, "x");
+ if (len < 0 || len > left)
+ goto truncated;
+
+ left -= len;
+ cur += len;
+ }
+ if (!anymode) {
+ len = snprintf(cur, left, "n");
+ if (len < 0 || len > left)
+ goto truncated;
+
+ left -= len;
+ cur += len;
+ }
+ if (unknownmode) {
+ len = snprintf(cur, left, "?");
+ if (len < 0 || len > left)
+ goto truncated;
+
+ left -= len;
+ cur += len;
+ }
+
+ return (0);
+
+truncated:
+ return (-1);
+}
+
+int
+bsde_parse_uidrange(char *spec, uid_t *min, uid_t *max,
+ size_t buflen, char *errstr){
+ struct passwd *pwd;
+ uid_t uid1, uid2;
+ char *spec1, *spec2, *endp;
+ unsigned long value;
+ size_t len;
+
+ spec2 = spec;
+ spec1 = strsep(&spec2, ":");
+
+ pwd = getpwnam(spec1);
+ if (pwd != NULL)
+ uid1 = pwd->pw_uid;
+ else {
+ value = strtoul(spec1, &endp, 10);
+ if (*endp != '\0') {
+ len = snprintf(errstr, buflen,
+ "invalid uid: '%s'", spec1);
+ return (-1);
+ }
+ uid1 = value;
+ }
+
+ if (spec2 == NULL) {
+ *max = *min = uid1;
+ return (0);
+ }
+
+ pwd = getpwnam(spec2);
+ if (pwd != NULL)
+ uid2 = pwd->pw_uid;
+ else {
+ value = strtoul(spec2, &endp, 10);
+ if (*endp != '\0') {
+ len = snprintf(errstr, buflen,
+ "invalid uid: '%s'", spec2);
+ return (-1);
+ }
+ uid2 = value;
+ }
+
+ *min = uid1;
+ *max = uid2;
+
+ return (0);
+}
+
+int
+bsde_parse_gidrange(char *spec, gid_t *min, gid_t *max,
+ size_t buflen, char *errstr){
+ struct group *grp;
+ gid_t gid1, gid2;
+ char *spec1, *spec2, *endp;
+ unsigned long value;
+ size_t len;
+
+ spec2 = spec;
+ spec1 = strsep(&spec2, ":");
+
+ grp = getgrnam(spec1);
+ if (grp != NULL)
+ gid1 = grp->gr_gid;
+ else {
+ value = strtoul(spec1, &endp, 10);
+ if (*endp != '\0') {
+ len = snprintf(errstr, buflen,
+ "invalid gid: '%s'", spec1);
+ return (-1);
+ }
+ gid1 = value;
+ }
+
+ if (spec2 == NULL) {
+ *max = *min = gid1;
+ return (0);
+ }
+
+ grp = getgrnam(spec2);
+ if (grp != NULL)
+ gid2 = grp->gr_gid;
+ else {
+ value = strtoul(spec2, &endp, 10);
+ if (*endp != '\0') {
+ len = snprintf(errstr, buflen,
+ "invalid gid: '%s'", spec2);
+ return (-1);
+ }
+ gid2 = value;
+ }
+
+ *min = gid1;
+ *max = gid2;
+
+ return (0);
+}
+
+int
+bsde_parse_subject(int argc, char *argv[],
+ struct mac_bsdextended_subject *subject, size_t buflen, char *errstr)
+{
+ int not_seen, flags;
+ int current, neg, nextnot;
+ char *endp;
+ uid_t uid_min, uid_max;
+ gid_t gid_min, gid_max;
+ int jid;
+ size_t len;
+ long value;
+
+ current = 0;
+ flags = 0;
+ neg = 0;
+ nextnot = 0;
+
+ if (strcmp("not", argv[current]) == 0) {
+ not_seen = 1;
+ current++;
+ } else
+ not_seen = 0;
+
+ while (current < argc) {
+ if (strcmp(argv[current], "uid") == 0) {
+ if (current + 2 > argc) {
+ len = snprintf(errstr, buflen, "uid short");
+ return (-1);
+ }
+ if (flags & MBS_UID_DEFINED) {
+ len = snprintf(errstr, buflen, "one uid only");
+ return (-1);
+ }
+ if (bsde_parse_uidrange(argv[current+1],
+ &uid_min, &uid_max, buflen, errstr) < 0)
+ return (-1);
+ flags |= MBS_UID_DEFINED;
+ if (nextnot) {
+ neg ^= MBS_UID_DEFINED;
+ nextnot = 0;
+ }
+ current += 2;
+ } else if (strcmp(argv[current], "gid") == 0) {
+ if (current + 2 > argc) {
+ len = snprintf(errstr, buflen, "gid short");
+ return (-1);
+ }
+ if (flags & MBS_GID_DEFINED) {
+ len = snprintf(errstr, buflen, "one gid only");
+ return (-1);
+ }
+ if (bsde_parse_gidrange(argv[current+1],
+ &gid_min, &gid_max, buflen, errstr) < 0)
+ return (-1);
+ flags |= MBS_GID_DEFINED;
+ if (nextnot) {
+ neg ^= MBS_GID_DEFINED;
+ nextnot = 0;
+ }
+ current += 2;
+ } else if (strcmp(argv[current], "jailid") == 0) {
+ if (current + 2 > argc) {
+ len = snprintf(errstr, buflen, "prison short");
+ return (-1);
+ }
+ if (flags & MBS_PRISON_DEFINED) {
+ len = snprintf(errstr, buflen, "one jail only");
+ return (-1);
+ }
+ value = strtol(argv[current+1], &endp, 10);
+ if (*endp != '\0') {
+ len = snprintf(errstr, buflen,
+ "invalid jid: '%s'", argv[current+1]);
+ return (-1);
+ }
+ jid = value;
+ flags |= MBS_PRISON_DEFINED;
+ if (nextnot) {
+ neg ^= MBS_PRISON_DEFINED;
+ nextnot = 0;
+ }
+ current += 2;
+ } else if (strcmp(argv[current], "!") == 0) {
+ if (nextnot) {
+ len = snprintf(errstr, buflen,
+ "double negative");
+ return (-1);
+ }
+ nextnot = 1;
+ current += 1;
+ } else {
+ len = snprintf(errstr, buflen, "'%s' not expected",
+ argv[current]);
+ return (-1);
+ }
+ }
+
+ subject->mbs_flags = flags;
+ if (not_seen)
+ subject->mbs_neg = MBS_ALL_FLAGS ^ neg;
+ else
+ subject->mbs_neg = neg;
+ if (flags & MBS_UID_DEFINED) {
+ subject->mbs_uid_min = uid_min;
+ subject->mbs_uid_max = uid_max;
+ }
+ if (flags & MBS_GID_DEFINED) {
+ subject->mbs_gid_min = gid_min;
+ subject->mbs_gid_max = gid_max;
+ }
+ if (flags & MBS_PRISON_DEFINED)
+ subject->mbs_prison = jid;
+
+ return (0);
+}
+
+int
+bsde_parse_type(char *spec, int *type, size_t buflen, char *errstr)
+{
+ size_t len;
+ int i;
+
+ *type = 0;
+ for (i = 0; i < strlen(spec); i++) {
+ switch (spec[i]) {
+ case 'r':
+ case '-':
+ *type |= MBO_TYPE_REG;
+ break;
+ case 'd':
+ *type |= MBO_TYPE_DIR;
+ break;
+ case 'b':
+ *type |= MBO_TYPE_BLK;
+ break;
+ case 'c':
+ *type |= MBO_TYPE_CHR;
+ break;
+ case 'l':
+ *type |= MBO_TYPE_LNK;
+ break;
+ case 's':
+ *type |= MBO_TYPE_SOCK;
+ break;
+ case 'p':
+ *type |= MBO_TYPE_FIFO;
+ break;
+ case 'a':
+ *type |= MBO_ALL_TYPE;
+ break;
+ default:
+ len = snprintf(errstr, buflen, "Unknown type code: %c",
+ spec[i]);
+ return (-1);
+ }
+ }
+
+ return (0);
+}
+
+int
+bsde_parse_fsid(char *spec, struct fsid *fsid, size_t buflen, char *errstr)
+{
+ size_t len;
+ struct statfs buf;
+ int i;
+
+ if (statfs(spec, &buf) < 0) {
+ len = snprintf(errstr, buflen, "Unable to get id for %s: %s",
+ spec, strerror(errno));
+ return (-1);
+ }
+
+ *fsid = buf.f_fsid;
+
+ return (0);
+}
+
+int
+bsde_parse_object(int argc, char *argv[],
+ struct mac_bsdextended_object *object, size_t buflen, char *errstr)
+{
+ int not_seen, flags;
+ int current, neg, nextnot;
+ uid_t uid_min, uid_max;
+ gid_t gid_min, gid_max;
+ int type;
+ struct fsid fsid;
+ size_t len;
+
+ current = 0;
+ flags = 0;
+ neg = 0;
+ nextnot = 0;
+
+ if (strcmp("not", argv[current]) == 0) {
+ not_seen = 1;
+ current++;
+ } else
+ not_seen = 0;
+
+ while (current < argc) {
+ if (strcmp(argv[current], "uid") == 0) {
+ if (current + 2 > argc) {
+ len = snprintf(errstr, buflen, "uid short");
+ return (-1);
+ }
+ if (flags & MBO_UID_DEFINED) {
+ len = snprintf(errstr, buflen, "one uid only");
+ return (-1);
+ }
+ if (bsde_parse_uidrange(argv[current+1],
+ &uid_min, &uid_max, buflen, errstr) < 0)
+ return (-1);
+ flags |= MBO_UID_DEFINED;
+ if (nextnot) {
+ neg ^= MBO_UID_DEFINED;
+ nextnot = 0;
+ }
+ current += 2;
+ } else if (strcmp(argv[current], "gid") == 0) {
+ if (current + 2 > argc) {
+ len = snprintf(errstr, buflen, "gid short");
+ return (-1);
+ }
+ if (flags & MBO_GID_DEFINED) {
+ len = snprintf(errstr, buflen, "one gid only");
+ return (-1);
+ }
+ if (bsde_parse_gidrange(argv[current+1],
+ &gid_min, &gid_max, buflen, errstr) < 0)
+ return (-1);
+ flags |= MBO_GID_DEFINED;
+ if (nextnot) {
+ neg ^= MBO_GID_DEFINED;
+ nextnot = 0;
+ }
+ current += 2;
+ } else if (strcmp(argv[current], "filesys") == 0) {
+ if (current + 2 > argc) {
+ len = snprintf(errstr, buflen, "filesys short");
+ return (-1);
+ }
+ if (flags & MBO_FSID_DEFINED) {
+ len = snprintf(errstr, buflen, "one fsid only");
+ return (-1);
+ }
+ if (bsde_parse_fsid(argv[current+1], &fsid,
+ buflen, errstr) < 0)
+ return (-1);
+ flags |= MBO_FSID_DEFINED;
+ if (nextnot) {
+ neg ^= MBO_FSID_DEFINED;
+ nextnot = 0;
+ }
+ current += 2;
+ } else if (strcmp(argv[current], "suid") == 0) {
+ flags |= MBO_SUID;
+ if (nextnot) {
+ neg ^= MBO_SUID;
+ nextnot = 0;
+ }
+ current += 1;
+ } else if (strcmp(argv[current], "sgid") == 0) {
+ flags |= MBO_SGID;
+ if (nextnot) {
+ neg ^= MBO_SGID;
+ nextnot = 0;
+ }
+ current += 1;
+ } else if (strcmp(argv[current], "uid_of_subject") == 0) {
+ flags |= MBO_UID_SUBJECT;
+ if (nextnot) {
+ neg ^= MBO_UID_SUBJECT;
+ nextnot = 0;
+ }
+ current += 1;
+ } else if (strcmp(argv[current], "gid_of_subject") == 0) {
+ flags |= MBO_GID_SUBJECT;
+ if (nextnot) {
+ neg ^= MBO_GID_SUBJECT;
+ nextnot = 0;
+ }
+ current += 1;
+ } else if (strcmp(argv[current], "type") == 0) {
+ if (current + 2 > argc) {
+ len = snprintf(errstr, buflen, "type short");
+ return (-1);
+ }
+ if (flags & MBO_TYPE_DEFINED) {
+ len = snprintf(errstr, buflen, "one type only");
+ return (-1);
+ }
+ if (bsde_parse_type(argv[current+1], &type,
+ buflen, errstr) < 0)
+ return (-1);
+ flags |= MBO_TYPE_DEFINED;
+ if (nextnot) {
+ neg ^= MBO_TYPE_DEFINED;
+ nextnot = 0;
+ }
+ current += 2;
+ } else if (strcmp(argv[current], "!") == 0) {
+ if (nextnot) {
+ len = snprintf(errstr, buflen,
+ "double negative'");
+ return (-1);
+ }
+ nextnot = 1;
+ current += 1;
+ } else {
+ len = snprintf(errstr, buflen, "'%s' not expected",
+ argv[current]);
+ return (-1);
+ }
+ }
+
+ object->mbo_flags = flags;
+ if (not_seen)
+ object->mbo_neg = MBO_ALL_FLAGS ^ neg;
+ else
+ object->mbo_neg = neg;
+ if (flags & MBO_UID_DEFINED) {
+ object->mbo_uid_min = uid_min;
+ object->mbo_uid_max = uid_max;
+ }
+ if (flags & MBO_GID_DEFINED) {
+ object->mbo_gid_min = gid_min;
+ object->mbo_gid_max = gid_max;
+ }
+ if (flags & MBO_FSID_DEFINED)
+ object->mbo_fsid = fsid;
+ if (flags & MBO_TYPE_DEFINED)
+ object->mbo_type = type;
+
+ return (0);
+}
+
+int
+bsde_parse_mode(int argc, char *argv[], mode_t *mode, size_t buflen,
+ char *errstr)
+{
+ size_t len;
+ int i;
+
+ if (argc == 0) {
+ len = snprintf(errstr, buflen, "mode expects mode value");
+ return (-1);
+ }
+
+ if (argc != 1) {
+ len = snprintf(errstr, buflen, "'%s' unexpected", argv[1]);
+ return (-1);
+ }
+
+ *mode = 0;
+ for (i = 0; i < strlen(argv[0]); i++) {
+ switch (argv[0][i]) {
+ case 'a':
+ *mode |= MBI_ADMIN;
+ break;
+ case 'r':
+ *mode |= MBI_READ;
+ break;
+ case 's':
+ *mode |= MBI_STAT;
+ break;
+ case 'w':
+ *mode |= MBI_WRITE;
+ break;
+ case 'x':
+ *mode |= MBI_EXEC;
+ break;
+ case 'n':
+ /* ignore */
+ break;
+ default:
+ len = snprintf(errstr, buflen, "Unknown mode letter: %c",
+ argv[0][i]);
+ return (-1);
+ }
+ }
+
+ return (0);
+}
+
+int
+bsde_parse_rule(int argc, char *argv[], struct mac_bsdextended_rule *rule,
+ size_t buflen, char *errstr)
+{
+ int subject, subject_elements, subject_elements_length;
+ int object, object_elements, object_elements_length;
+ int mode, mode_elements, mode_elements_length;
+ int error, i;
+ size_t len;
+
+ bzero(rule, sizeof(*rule));
+
+ if (argc < 1) {
+ len = snprintf(errstr, buflen, "Rule must begin with subject");
+ return (-1);
+ }
+
+ if (strcmp(argv[0], "subject") != 0) {
+ len = snprintf(errstr, buflen, "Rule must begin with subject");
+ return (-1);
+ }
+ subject = 0;
+ subject_elements = 1;
+
+ /* Search forward for object. */
+
+ object = -1;
+ for (i = 1; i < argc; i++)
+ if (strcmp(argv[i], "object") == 0)
+ object = i;
+
+ if (object == -1) {
+ len = snprintf(errstr, buflen, "Rule must contain an object");
+ return (-1);
+ }
+
+ /* Search forward for mode. */
+ mode = -1;
+ for (i = object; i < argc; i++)
+ if (strcmp(argv[i], "mode") == 0)
+ mode = i;
+
+ if (mode == -1) {
+ len = snprintf(errstr, buflen, "Rule must contain mode");
+ return (-1);
+ }
+
+ subject_elements_length = object - subject - 1;
+ object_elements = object + 1;
+ object_elements_length = mode - object_elements;
+ mode_elements = mode + 1;
+ mode_elements_length = argc - mode_elements;
+
+ error = bsde_parse_subject(subject_elements_length,
+ argv + subject_elements, &rule->mbr_subject, buflen, errstr);
+ if (error)
+ return (-1);
+
+ error = bsde_parse_object(object_elements_length,
+ argv + object_elements, &rule->mbr_object, buflen, errstr);
+ if (error)
+ return (-1);
+
+ error = bsde_parse_mode(mode_elements_length, argv + mode_elements,
+ &rule->mbr_mode, buflen, errstr);
+ if (error)
+ return (-1);
+
+ return (0);
+}
+
+int
+bsde_parse_rule_string(const char *string, struct mac_bsdextended_rule *rule,
+ size_t buflen, char *errstr)
+{
+ char *stringdup, *stringp, *argv[100], **ap;
+ int argc, error;
+
+ stringp = stringdup = strdup(string);
+ while (*stringp == ' ' || *stringp == '\t')
+ stringp++;
+
+ argc = 0;
+ for (ap = argv; (*ap = strsep(&stringp, " \t")) != NULL;) {
+ argc++;
+ if (**ap != '\0')
+ if (++ap >= &argv[100])
+ break;
+ }
+
+ error = bsde_parse_rule(argc, argv, rule, buflen, errstr);
+
+ free(stringdup);
+
+ return (error);
+}
+
+int
+bsde_get_mib(const char *string, int *name, size_t *namelen)
+{
+ size_t len;
+ int error;
+
+ len = *namelen;
+ error = sysctlnametomib(string, name, &len);
+ if (error)
+ return (error);
+
+ *namelen = len;
+ return (0);
+}
+
+int
+bsde_check_version(size_t buflen, char *errstr)
+{
+ size_t len;
+ int error;
+ int version;
+
+ len = sizeof(version);
+ error = sysctlbyname(MIB ".rule_version", &version, &len, NULL, 0);
+ if (error) {
+ len = snprintf(errstr, buflen, "version check failed: %s",
+ strerror(errno));
+ return (-1);
+ }
+ if (version != MB_VERSION) {
+ len = snprintf(errstr, buflen, "module v%d != library v%d",
+ version, MB_VERSION);
+ return (-1);
+ }
+ return (0);
+}
+
+int
+bsde_get_rule_count(size_t buflen, char *errstr)
+{
+ size_t len;
+ int error;
+ int rule_count;
+
+ len = sizeof(rule_count);
+ error = sysctlbyname(MIB ".rule_count", &rule_count, &len, NULL, 0);
+ if (error) {
+ len = snprintf(errstr, buflen, strerror(errno));
+ return (-1);
+ }
+ if (len != sizeof(rule_count)) {
+ len = snprintf(errstr, buflen, "Data error in %s.rule_count",
+ MIB);
+ return (-1);
+ }
+
+ return (rule_count);
+}
+
+int
+bsde_get_rule_slots(size_t buflen, char *errstr)
+{
+ size_t len;
+ int error;
+ int rule_slots;
+
+ len = sizeof(rule_slots);
+ error = sysctlbyname(MIB ".rule_slots", &rule_slots, &len, NULL, 0);
+ if (error) {
+ len = snprintf(errstr, buflen, strerror(errno));
+ return (-1);
+ }
+ if (len != sizeof(rule_slots)) {
+ len = snprintf(errstr, buflen, "Data error in %s.rule_slots",
+ MIB);
+ return (-1);
+ }
+
+ return (rule_slots);
+}
+
+/*
+ * Returns 0 for success;
+ * Returns -1 for failure;
+ * Returns -2 for not present
+ */
+int
+bsde_get_rule(int rulenum, struct mac_bsdextended_rule *rule, size_t errlen,
+ char *errstr)
+{
+ int name[10];
+ size_t len, size;
+ int error;
+
+ if (bsde_check_version(errlen, errstr) != 0)
+ return (-1);
+
+ len = 10;
+ error = bsde_get_mib(MIB ".rules", name, &len);
+ if (error) {
+ len = snprintf(errstr, errlen, "%s: %s", MIB ".rules",
+ strerror(errno));
+ return (-1);
+ }
+
+ size = sizeof(*rule);
+ name[len] = rulenum;
+ len++;
+ error = sysctl(name, len, rule, &size, NULL, 0);
+ if (error == -1 && errno == ENOENT)
+ return (-2);
+ if (error) {
+ len = snprintf(errstr, errlen, "%s.%d: %s", MIB ".rules",
+ rulenum, strerror(errno));
+ return (-1);
+ } else if (size != sizeof(*rule)) {
+ len = snprintf(errstr, errlen, "Data error in %s.%d: %s",
+ MIB ".rules", rulenum, strerror(errno));
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+bsde_delete_rule(int rulenum, size_t buflen, char *errstr)
+{
+ struct mac_bsdextended_rule rule;
+ int name[10];
+ size_t len, size;
+ int error;
+
+ if (bsde_check_version(buflen, errstr) != 0)
+ return (-1);
+
+ len = 10;
+ error = bsde_get_mib(MIB ".rules", name, &len);
+ if (error) {
+ len = snprintf(errstr, buflen, "%s: %s", MIB ".rules",
+ strerror(errno));
+ return (-1);
+ }
+
+ name[len] = rulenum;
+ len++;
+
+ size = sizeof(rule);
+ error = sysctl(name, len, NULL, NULL, &rule, 0);
+ if (error) {
+ len = snprintf(errstr, buflen, "%s.%d: %s", MIB ".rules",
+ rulenum, strerror(errno));
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+bsde_set_rule(int rulenum, struct mac_bsdextended_rule *rule, size_t buflen,
+ char *errstr)
+{
+ int name[10];
+ size_t len, size;
+ int error;
+
+ if (bsde_check_version(buflen, errstr) != 0)
+ return (-1);
+
+ len = 10;
+ error = bsde_get_mib(MIB ".rules", name, &len);
+ if (error) {
+ len = snprintf(errstr, buflen, "%s: %s", MIB ".rules",
+ strerror(errno));
+ return (-1);
+ }
+
+ name[len] = rulenum;
+ len++;
+
+ size = sizeof(*rule);
+ error = sysctl(name, len, NULL, NULL, rule, size);
+ if (error) {
+ len = snprintf(errstr, buflen, "%s.%d: %s", MIB ".rules",
+ rulenum, strerror(errno));
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+bsde_add_rule(int *rulenum, struct mac_bsdextended_rule *rule, size_t buflen,
+ char *errstr)
+{
+ char charstr[BUFSIZ];
+ int name[10];
+ size_t len, size;
+ int error, rule_slots;
+
+ if (bsde_check_version(buflen, errstr) != 0)
+ return (-1);
+
+ len = 10;
+ error = bsde_get_mib(MIB ".rules", name, &len);
+ if (error) {
+ len = snprintf(errstr, buflen, "%s: %s", MIB ".rules",
+ strerror(errno));
+ return (-1);
+ }
+
+ rule_slots = bsde_get_rule_slots(BUFSIZ, charstr);
+ if (rule_slots == -1) {
+ len = snprintf(errstr, buflen, "unable to get rule slots: %s",
+ strerror(errno));
+ return (-1);
+ }
+
+ name[len] = rule_slots;
+ len++;
+
+ size = sizeof(*rule);
+ error = sysctl(name, len, NULL, NULL, rule, size);
+ if (error) {
+ len = snprintf(errstr, buflen, "%s.%d: %s", MIB ".rules",
+ rule_slots, strerror(errno));
+ return (-1);
+ }
+
+ if (rulenum != NULL)
+ *rulenum = rule_slots;
+
+ return (0);
+}
diff --git a/lib/libugidfw/ugidfw.h b/lib/libugidfw/ugidfw.h
new file mode 100644
index 0000000..5b7fcf2
--- /dev/null
+++ b/lib/libugidfw/ugidfw.h
@@ -0,0 +1,58 @@
+/*-
+ * Copyright (c) 2002, 2004 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _UGIDFW_H
+#define _UGIDFW_H
+
+__BEGIN_DECLS
+int bsde_rule_to_string(struct mac_bsdextended_rule *rule, char *buf,
+ size_t buflen);
+int bsde_parse_mode(int argc, char *argv[], mode_t *mode, size_t buflen,
+ char *errstr);
+int bsde_parse_rule(int argc, char *argv[],
+ struct mac_bsdextended_rule *rule, size_t buflen, char *errstr);
+int bsde_parse_rule_string(const char *string,
+ struct mac_bsdextended_rule *rule, size_t buflen, char *errstr);
+int bsde_get_mib(const char *string, int *name, size_t *namelen);
+int bsde_get_rule_count(size_t buflen, char *errstr);
+int bsde_get_rule_slots(size_t buflen, char *errstr);
+int bsde_get_rule(int rulenum, struct mac_bsdextended_rule *rule,
+ size_t errlen, char *errstr);
+int bsde_delete_rule(int rulenum, size_t buflen, char *errstr);
+int bsde_set_rule(int rulenum, struct mac_bsdextended_rule *rule,
+ size_t buflen, char *errstr);
+int bsde_add_rule(int *rulename, struct mac_bsdextended_rule *rule,
+ size_t buflen, char *errstr);
+__END_DECLS
+
+#endif
diff --git a/lib/libusbhid/Makefile b/lib/libusbhid/Makefile
new file mode 100644
index 0000000..4c6ad06
--- /dev/null
+++ b/lib/libusbhid/Makefile
@@ -0,0 +1,22 @@
+# $NetBSD: Makefile,v 1.5 1999/07/23 09:44:38 mrg Exp $
+# $FreeBSD$
+
+LIB= usbhid
+MAN= usbhid.3
+
+SHLIB_MAJOR= 2
+
+MLINKS= usbhid.3 libusbhid.3 usbhid.3 hid_get_report_desc.3 \
+ usbhid.3 hid_dispose_report_desc.3 \
+ usbhid.3 hid_start_parse.3 usbhid.3 hid_end_parse.3 \
+ usbhid.3 hid_get_item.3 usbhid.3 hid_report_size.3 \
+ usbhid.3 hid_locate.3 \
+ usbhid.3 hid_usage_page.3 usbhid.3 hid_usage_in_page.3 \
+ usbhid.3 hid_init.3 \
+ usbhid.3 hid_get_data.3 usbhid.3 hid_set_data.3
+
+SRCS= descr.c parse.c usage.c data.c
+
+INCS= usbhid.h
+
+.include <bsd.lib.mk>
diff --git a/lib/libusbhid/data.c b/lib/libusbhid/data.c
new file mode 100644
index 0000000..d278ddb
--- /dev/null
+++ b/lib/libusbhid/data.c
@@ -0,0 +1,94 @@
+/* $NetBSD: data.c,v 1.8 2000/04/02 11:10:53 augustss Exp $ */
+
+/*
+ * Copyright (c) 1999 Lennart Augustsson <augustss@netbsd.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 <stdlib.h>
+#include "usbhid.h"
+
+int
+hid_get_data(const void *p, const hid_item_t *h)
+{
+ const unsigned char *buf;
+ unsigned int hpos;
+ unsigned int hsize;
+ int data;
+ int i, end, offs;
+
+ buf = p;
+ hpos = h->pos; /* bit position of data */
+ hsize = h->report_size; /* bit length of data */
+
+ if (hsize == 0)
+ return (0);
+ offs = hpos / 8;
+ end = (hpos + hsize) / 8 - offs;
+ data = 0;
+ for (i = 0; i <= end; i++)
+ data |= buf[offs + i] << (i*8);
+ data >>= hpos % 8;
+ data &= (1 << hsize) - 1;
+ if (h->logical_minimum < 0) {
+ /* Need to sign extend */
+ hsize = sizeof data * 8 - hsize;
+ data = (data << hsize) >> hsize;
+ }
+ return (data);
+}
+
+void
+hid_set_data(void *p, const hid_item_t *h, int data)
+{
+ unsigned char *buf;
+ unsigned int hpos;
+ unsigned int hsize;
+ int i, end, offs, mask;
+
+ buf = p;
+ hpos = h->pos; /* bit position of data */
+ hsize = h->report_size; /* bit length of data */
+
+ if (hsize != 32) {
+ mask = (1 << hsize) - 1;
+ data &= mask;
+ } else
+ mask = ~0;
+
+ data <<= (hpos % 8);
+ mask <<= (hpos % 8);
+ mask = ~mask;
+
+ offs = hpos / 8;
+ end = (hpos + hsize) / 8 - offs;
+
+ for (i = 0; i <= end; i++)
+ buf[offs + i] = (buf[offs + i] & (mask >> (i*8))) |
+ ((data >> (i*8)) & 0xff);
+}
diff --git a/lib/libusbhid/descr.c b/lib/libusbhid/descr.c
new file mode 100644
index 0000000..4afdb61
--- /dev/null
+++ b/lib/libusbhid/descr.c
@@ -0,0 +1,79 @@
+/* $NetBSD: descr.c,v 1.9 2000/09/24 02:13:24 augustss Exp $ */
+
+/*
+ * Copyright (c) 1999 Lennart Augustsson <augustss@netbsd.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 <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+
+#include <dev/usb/usb.h>
+
+#include "usbhid.h"
+#include "usbvar.h"
+
+report_desc_t
+hid_get_report_desc(int fd)
+{
+ struct usb_ctl_report_desc rep;
+
+ rep.ucrd_size = 0;
+ if (ioctl(fd, USB_GET_REPORT_DESC, &rep) < 0)
+ return (NULL);
+
+ return hid_use_report_desc(rep.ucrd_data, (unsigned int)rep.ucrd_size);
+}
+
+report_desc_t
+hid_use_report_desc(unsigned char *data, unsigned int size)
+{
+ report_desc_t r;
+
+ r = malloc(sizeof(*r) + size);
+ if (r == 0) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ r->size = size;
+ memcpy(r->data, data, size);
+ return (r);
+}
+
+void
+hid_dispose_report_desc(report_desc_t r)
+{
+
+ free(r);
+}
diff --git a/lib/libusbhid/parse.c b/lib/libusbhid/parse.c
new file mode 100644
index 0000000..3abc036
--- /dev/null
+++ b/lib/libusbhid/parse.c
@@ -0,0 +1,440 @@
+/* $NetBSD: parse.c,v 1.11 2000/09/24 02:19:54 augustss Exp $ */
+
+/*
+ * Copyright (c) 1999, 2001 Lennart Augustsson <augustss@netbsd.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 <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbhid.h>
+
+#include "usbhid.h"
+#include "usbvar.h"
+
+#define MAXUSAGE 100
+struct hid_data {
+ u_char *start;
+ u_char *end;
+ u_char *p;
+ hid_item_t cur;
+ unsigned int usages[MAXUSAGE];
+ int nusage;
+ int minset;
+ int logminsize;
+ int multi;
+ int multimax;
+ int kindset;
+ int reportid;
+
+ /*
+ * The start of collection item has no report ID set, so save
+ * it until we know the ID.
+ */
+ hid_item_t savedcoll;
+ u_char hassavedcoll;
+ /*
+ * Absolute data position (bits) for input/output/feature.
+ * Assumes that hid_input, hid_output and hid_feature have
+ * values 0, 1 and 2.
+ */
+ unsigned int kindpos[3];
+};
+
+static int min(int x, int y) { return x < y ? x : y; }
+
+static int hid_get_item_raw(hid_data_t s, hid_item_t *h);
+
+static void
+hid_clear_local(hid_item_t *c)
+{
+ c->usage = 0;
+ c->usage_minimum = 0;
+ c->usage_maximum = 0;
+ c->designator_index = 0;
+ c->designator_minimum = 0;
+ c->designator_maximum = 0;
+ c->string_index = 0;
+ c->string_minimum = 0;
+ c->string_maximum = 0;
+ c->set_delimiter = 0;
+}
+
+hid_data_t
+hid_start_parse(report_desc_t d, int kindset, int id)
+{
+ struct hid_data *s;
+
+ s = malloc(sizeof *s);
+ memset(s, 0, sizeof *s);
+ s->start = s->p = d->data;
+ s->end = d->data + d->size;
+ s->kindset = kindset;
+ s->reportid = id;
+ s->hassavedcoll = 0;
+ return (s);
+}
+
+void
+hid_end_parse(hid_data_t s)
+{
+ while (s->cur.next) {
+ hid_item_t *hi = s->cur.next->next;
+ free(s->cur.next);
+ s->cur.next = hi;
+ }
+ free(s);
+}
+
+int
+hid_get_item(hid_data_t s, hid_item_t *h)
+{
+ int r;
+
+ for (;;) {
+ r = hid_get_item_raw(s, h);
+ if (r <= 0)
+ break;
+ if (h->report_ID == s->reportid || s->reportid == -1)
+ break;
+ }
+ return (r);
+}
+
+#define REPORT_SAVED_COLL \
+ do { \
+ if (s->hassavedcoll) { \
+ *h = s->savedcoll; \
+ h->report_ID = c->report_ID; \
+ s->hassavedcoll = 0; \
+ return (1); \
+ } \
+ } while(/*LINTED*/ 0)
+
+static int
+hid_get_item_raw(hid_data_t s, hid_item_t *h)
+{
+ hid_item_t *c;
+ unsigned int bTag = 0, bType = 0, bSize;
+ unsigned char *data;
+ int dval;
+ unsigned char *p;
+ hid_item_t *hi;
+ hid_item_t nc;
+ int i;
+ hid_kind_t retkind;
+
+ c = &s->cur;
+
+ top:
+ if (s->multimax) {
+ REPORT_SAVED_COLL;
+ if (c->logical_minimum >= c->logical_maximum) {
+ if (s->logminsize == 1)
+ c->logical_minimum =(int8_t)c->logical_minimum;
+ else if (s->logminsize == 2)
+ c->logical_minimum =(int16_t)c->logical_minimum;
+ }
+ if (s->multi < s->multimax) {
+ c->usage = s->usages[min(s->multi, s->nusage-1)];
+ s->multi++;
+ *h = *c;
+ /*
+ * 'multimax' is only non-zero if the current
+ * item kind is input/output/feature
+ */
+ h->pos = s->kindpos[c->kind];
+ s->kindpos[c->kind] += c->report_size;
+ h->next = 0;
+ return (1);
+ } else {
+ c->report_count = s->multimax;
+ s->multimax = 0;
+ s->nusage = 0;
+ hid_clear_local(c);
+ }
+ }
+ for (;;) {
+ p = s->p;
+ if (p >= s->end)
+ return (0);
+
+ bSize = *p++;
+ if (bSize == 0xfe) {
+ /* long item */
+ bSize = *p++;
+ bSize |= *p++ << 8;
+ bTag = *p++;
+ data = p;
+ p += bSize;
+ } else {
+ /* short item */
+ bTag = bSize >> 4;
+ bType = (bSize >> 2) & 3;
+ bSize &= 3;
+ if (bSize == 3) bSize = 4;
+ data = p;
+ p += bSize;
+ }
+ s->p = p;
+ /*
+ * The spec is unclear if the data is signed or unsigned.
+ */
+ switch(bSize) {
+ case 0:
+ dval = 0;
+ break;
+ case 1:
+ dval = *data++;
+ break;
+ case 2:
+ dval = *data++;
+ dval |= *data++ << 8;
+ break;
+ case 4:
+ dval = *data++;
+ dval |= *data++ << 8;
+ dval |= *data++ << 16;
+ dval |= *data++ << 24;
+ break;
+ default:
+ return (-1);
+ }
+
+ switch (bType) {
+ case 0: /* Main */
+ switch (bTag) {
+ case 8: /* Input */
+ retkind = hid_input;
+ ret:
+ if (!(s->kindset & (1 << retkind))) {
+ /* Drop the items of this kind */
+ s->nusage = 0;
+ continue;
+ }
+ c->kind = retkind;
+ c->flags = dval;
+ if (c->flags & HIO_VARIABLE) {
+ s->multimax = c->report_count;
+ s->multi = 0;
+ c->report_count = 1;
+ if (s->minset) {
+ for (i = c->usage_minimum;
+ i <= c->usage_maximum;
+ i++) {
+ s->usages[s->nusage] = i;
+ if (s->nusage < MAXUSAGE-1)
+ s->nusage++;
+ }
+ c->usage_minimum = 0;
+ c->usage_maximum = 0;
+ s->minset = 0;
+ }
+ goto top;
+ } else {
+ if (s->minset)
+ c->usage = c->usage_minimum;
+ *h = *c;
+ h->next = 0;
+ h->pos = s->kindpos[c->kind];
+ s->kindpos[c->kind] +=
+ c->report_size * c->report_count;
+ hid_clear_local(c);
+ s->minset = 0;
+ return (1);
+ }
+ case 9: /* Output */
+ retkind = hid_output;
+ goto ret;
+ case 10: /* Collection */
+ c->kind = hid_collection;
+ c->collection = dval;
+ c->collevel++;
+ nc = *c;
+ hid_clear_local(c);
+ /*c->report_ID = NO_REPORT_ID;*/
+ s->nusage = 0;
+ if (s->hassavedcoll) {
+ *h = s->savedcoll;
+ h->report_ID = nc.report_ID;
+ s->savedcoll = nc;
+ return (1);
+ } else {
+ s->hassavedcoll = 1;
+ s->savedcoll = nc;
+ }
+ break;
+ case 11: /* Feature */
+ retkind = hid_feature;
+ goto ret;
+ case 12: /* End collection */
+ REPORT_SAVED_COLL;
+ c->kind = hid_endcollection;
+ c->collevel--;
+ *h = *c;
+ /*hid_clear_local(c);*/
+ s->nusage = 0;
+ return (1);
+ default:
+ return (-2);
+ }
+ break;
+
+ case 1: /* Global */
+ switch (bTag) {
+ case 0:
+ c->_usage_page = dval << 16;
+ break;
+ case 1:
+ c->logical_minimum = dval;
+ s->logminsize = bSize;
+ break;
+ case 2:
+ c->logical_maximum = dval;
+ break;
+ case 3:
+ c->physical_maximum = dval;
+ break;
+ case 4:
+ c->physical_maximum = dval;
+ break;
+ case 5:
+ c->unit_exponent = dval;
+ break;
+ case 6:
+ c->unit = dval;
+ break;
+ case 7:
+ c->report_size = dval;
+ break;
+ case 8:
+ c->report_ID = dval;
+ s->kindpos[hid_input] =
+ s->kindpos[hid_output] =
+ s->kindpos[hid_feature] = 0;
+ break;
+ case 9:
+ c->report_count = dval;
+ break;
+ case 10: /* Push */
+ hi = malloc(sizeof *hi);
+ *hi = s->cur;
+ c->next = hi;
+ break;
+ case 11: /* Pop */
+ hi = c->next;
+ s->cur = *hi;
+ free(hi);
+ break;
+ default:
+ return (-3);
+ }
+ break;
+ case 2: /* Local */
+ switch (bTag) {
+ case 0:
+ c->usage = c->_usage_page | dval;
+ if (s->nusage < MAXUSAGE)
+ s->usages[s->nusage++] = c->usage;
+ /* else XXX */
+ break;
+ case 1:
+ s->minset = 1;
+ c->usage_minimum = c->_usage_page | dval;
+ break;
+ case 2:
+ c->usage_maximum = c->_usage_page | dval;
+ break;
+ case 3:
+ c->designator_index = dval;
+ break;
+ case 4:
+ c->designator_minimum = dval;
+ break;
+ case 5:
+ c->designator_maximum = dval;
+ break;
+ case 7:
+ c->string_index = dval;
+ break;
+ case 8:
+ c->string_minimum = dval;
+ break;
+ case 9:
+ c->string_maximum = dval;
+ break;
+ case 10:
+ c->set_delimiter = dval;
+ break;
+ default:
+ return (-4);
+ }
+ break;
+ default:
+ return (-5);
+ }
+ }
+}
+
+int
+hid_report_size(report_desc_t r, enum hid_kind k, int id)
+{
+ struct hid_data *d;
+ hid_item_t h;
+ int size;
+
+ memset(&h, 0, sizeof h);
+ size = 0;
+ for (d = hid_start_parse(r, 1<<k, id); hid_get_item(d, &h); ) {
+ if (h.report_ID == id && h.kind == k) {
+ size = d->kindpos[k];
+ }
+ }
+ hid_end_parse(d);
+ return ((size + 7) / 8);
+}
+
+int
+hid_locate(report_desc_t desc, unsigned int u, enum hid_kind k,
+ hid_item_t *h, int id)
+{
+ hid_data_t d;
+
+ for (d = hid_start_parse(desc, 1<<k, id); hid_get_item(d, h); ) {
+ if (h->kind == k && !(h->flags & HIO_CONST) && h->usage == u) {
+ hid_end_parse(d);
+ return (1);
+ }
+ }
+ hid_end_parse(d);
+ h->report_size = 0;
+ return (0);
+}
diff --git a/lib/libusbhid/usage.c b/lib/libusbhid/usage.c
new file mode 100644
index 0000000..280ef69
--- /dev/null
+++ b/lib/libusbhid/usage.c
@@ -0,0 +1,238 @@
+/* $NetBSD: usage.c,v 1.8 2000/10/10 19:23:58 is Exp $ */
+
+/*
+ * Copyright (c) 1999 Lennart Augustsson <augustss@netbsd.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 <ctype.h>
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "usbhid.h"
+
+#define _PATH_HIDTABLE "/usr/share/misc/usb_hid_usages"
+
+struct usage_in_page {
+ const char *name;
+ int usage;
+};
+
+static struct usage_page {
+ const char *name;
+ int usage;
+ struct usage_in_page *page_contents;
+ int pagesize, pagesizemax;
+} *pages;
+static int npages, npagesmax;
+
+#ifdef DEBUG
+void
+dump_hid_table(void)
+{
+ int i, j;
+
+ for (i = 0; i < npages; i++) {
+ printf("%d\t%s\n", pages[i].usage, pages[i].name);
+ for (j = 0; j < pages[i].pagesize; j++) {
+ printf("\t%d\t%s\n", pages[i].page_contents[j].usage,
+ pages[i].page_contents[j].name);
+ }
+ }
+}
+#endif
+
+void
+hid_init(const char *hidname)
+{
+ FILE *f;
+ char line[100], name[100], *p, *n;
+ int no;
+ int lineno;
+ struct usage_page *curpage = 0;
+
+ if (hidname == 0)
+ hidname = _PATH_HIDTABLE;
+
+ f = fopen(hidname, "r");
+ if (f == NULL)
+ err(1, "%s", hidname);
+ for (lineno = 1; ; lineno++) {
+ if (fgets(line, sizeof line, f) == NULL)
+ break;
+ if (line[0] == '#')
+ continue;
+ for (p = line; *p && isspace(*p); p++)
+ ;
+ if (!*p)
+ continue;
+ if (sscanf(line, " * %[^\n]", name) == 1)
+ no = -1;
+ else if (sscanf(line, " 0x%x %[^\n]", &no, name) != 2 &&
+ sscanf(line, " %d %[^\n]", &no, name) != 2)
+ errx(1, "file %s, line %d, syntax error",
+ hidname, lineno);
+ for (p = name; *p; p++)
+ if (isspace(*p) || *p == '.')
+ *p = '_';
+ n = strdup(name);
+ if (!n)
+ err(1, "strdup");
+ if (isspace(line[0])) {
+ if (!curpage)
+ errx(1, "file %s, line %d, syntax error",
+ hidname, lineno);
+ if (curpage->pagesize >= curpage->pagesizemax) {
+ curpage->pagesizemax += 10;
+ curpage->page_contents =
+ realloc(curpage->page_contents,
+ curpage->pagesizemax *
+ sizeof (struct usage_in_page));
+ if (!curpage->page_contents)
+ err(1, "realloc");
+ }
+ curpage->page_contents[curpage->pagesize].name = n;
+ curpage->page_contents[curpage->pagesize].usage = no;
+ curpage->pagesize++;
+ } else {
+ if (npages >= npagesmax) {
+ if (pages == 0) {
+ npagesmax = 5;
+ pages = malloc(npagesmax *
+ sizeof (struct usage_page));
+ } else {
+ npagesmax += 5;
+ pages = realloc(pages,
+ npagesmax *
+ sizeof (struct usage_page));
+ }
+ if (!pages)
+ err(1, "alloc");
+ }
+ curpage = &pages[npages++];
+ curpage->name = n;
+ curpage->usage = no;
+ curpage->pagesize = 0;
+ curpage->pagesizemax = 10;
+ curpage->page_contents =
+ malloc(curpage->pagesizemax *
+ sizeof (struct usage_in_page));
+ if (!curpage->page_contents)
+ err(1, "malloc");
+ }
+ }
+ fclose(f);
+#ifdef DEBUG
+ dump_hid_table();
+#endif
+}
+
+const char *
+hid_usage_page(int i)
+{
+ static char b[10];
+ int k;
+
+ if (!pages)
+ errx(1, "no hid table");
+
+ for (k = 0; k < npages; k++)
+ if (pages[k].usage == i)
+ return pages[k].name;
+ sprintf(b, "0x%04x", i);
+ return b;
+}
+
+const char *
+hid_usage_in_page(unsigned int u)
+{
+ int page = HID_PAGE(u);
+ int i = HID_USAGE(u);
+ static char b[100];
+ int j, k, us;
+
+ for (k = 0; k < npages; k++)
+ if (pages[k].usage == page)
+ break;
+ if (k >= npages)
+ goto bad;
+ for (j = 0; j < pages[k].pagesize; j++) {
+ us = pages[k].page_contents[j].usage;
+ if (us == -1) {
+ sprintf(b,
+ fmtcheck(pages[k].page_contents[j].name, "%d"),
+ i);
+ return b;
+ }
+ if (us == i)
+ return pages[k].page_contents[j].name;
+ }
+ bad:
+ sprintf(b, "0x%04x", i);
+ return b;
+}
+
+int
+hid_parse_usage_page(const char *name)
+{
+ int k;
+
+ if (!pages)
+ errx(1, "no hid table");
+
+ for (k = 0; k < npages; k++)
+ if (strcmp(pages[k].name, name) == 0)
+ return pages[k].usage;
+ return -1;
+}
+
+/* XXX handle hex */
+int
+hid_parse_usage_in_page(const char *name)
+{
+ const char *sep;
+ int k, j;
+ unsigned int l;
+
+ sep = strchr(name, ':');
+ if (sep == NULL)
+ return -1;
+ l = sep - name;
+ for (k = 0; k < npages; k++)
+ if (strncmp(pages[k].name, name, l) == 0)
+ goto found;
+ return -1;
+ found:
+ sep++;
+ for (j = 0; j < pages[k].pagesize; j++)
+ if (strcmp(pages[k].page_contents[j].name, sep) == 0)
+ return (pages[k].usage << 16) | pages[k].page_contents[j].usage;
+ return (-1);
+}
diff --git a/lib/libusbhid/usbhid.3 b/lib/libusbhid/usbhid.3
new file mode 100644
index 0000000..a11709b
--- /dev/null
+++ b/lib/libusbhid/usbhid.3
@@ -0,0 +1,222 @@
+.\" $NetBSD: usb.3,v 1.13 2000/09/24 02:17:52 augustss Exp $
+.\"
+.\" Copyright (c) 1999, 2001 Lennart Augustsson <augustss@NetBSD.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 29, 2001
+.Dt USBHID 3
+.Os
+.Sh NAME
+.Nm usbhid ,
+.Nm hid_get_report_desc ,
+.Nm hid_use_report_desc ,
+.Nm hid_dispose_report_desc ,
+.Nm hid_start_parse ,
+.Nm hid_end_parse ,
+.Nm hid_get_item ,
+.Nm hid_report_size ,
+.Nm hid_locate ,
+.Nm hid_usage_page ,
+.Nm hid_usage_in_page ,
+.Nm hid_init ,
+.Nm hid_get_data ,
+.Nm hid_set_data
+.Nd USB HID access routines
+.Sh LIBRARY
+.Lb libusbhid
+.Sh SYNOPSIS
+.In usbhid.h
+.Ft report_desc_t
+.Fn hid_get_report_desc "int file"
+.Ft report_desc_t
+.Fn hid_use_report_desc "unsigned char *data" "unsigned int size"
+.Ft void
+.Fn hid_dispose_report_desc "report_desc_t d"
+.Ft hid_data_t
+.Fn hid_start_parse "report_desc_t d" "int kindset" "int id"
+.Ft void
+.Fn hid_end_parse "hid_data_t s"
+.Ft int
+.Fn hid_get_item "hid_data_t s" "hid_item_t *h"
+.Ft int
+.Fn hid_report_size "report_desc_t d" "hid_kind_t k" "int id"
+.Ft int
+.Fn hid_locate "report_desc_t d" "u_int usage" "hid_kind_t k" "hid_item_t *h" "int id"
+.Ft "const char *"
+.Fn hid_usage_page "int i"
+.Ft "const char *"
+.Fn hid_usage_in_page "u_int u"
+.Ft int
+.Fn hid_parse_usage_page "const char *"
+.Ft int
+.Fn hid_parse_usage_in_page "const char *"
+.Ft void
+.Fn hid_init "const char *file"
+.Ft int
+.Fn hid_get_data "const void *data" "const hid_item_t *h"
+.Ft void
+.Fn hid_set_data "void *buf" "const hid_item_t *h" "int data"
+.Sh DESCRIPTION
+The
+.Nm
+library provides routines to extract data from USB Human Interface Devices.
+.Ss Introduction
+USB HID devices send and receive data layed out in a device dependent way.
+The
+.Nm
+library contains routines to extract the
+.Em "report descriptor"
+which contains the data layout information and then use this information.
+.Pp
+The routines can be divided into four parts: extraction of the descriptor,
+parsing of the descriptor, translating to/from symbolic names, and
+data manipulation.
+.Ss Descriptor Functions
+A report descriptor can be obtained by calling
+.Fn hid_get_report_desc
+with a file descriptor obtained by opening a
+.Xr uhid 4
+device.
+Alternatively a data buffer containing the report descriptor can be
+passed into
+.Fn hid_use_report_desc .
+The data is copied into an internal structure.
+When the report descriptor
+is no longer needed it should be freed by calling
+.Fn hid_dispose_report_desc .
+The type
+.Vt report_desc_t
+is opaque and should be used when calling the parsing functions.
+If
+.Fn hid_dispose_report_desc
+fails it will return
+.Dv NULL .
+.Ss Descriptor Parsing Functions
+To parse the report descriptor the
+.Fn hid_start_parse
+function should be called with a report descriptor and a set that
+describes which items that are interesting.
+The set is obtained by OR-ing together values
+.Fa "(1 << k)"
+where
+.Fa k
+is an item of type
+.Vt hid_kind_t .
+The report ID (if present) is given by
+.Fa id .
+The function returns
+.Dv NULL
+if the initialization fails, otherwise an opaque value to be used
+in subsequent calls.
+After parsing the
+.Fn hid_end_parse
+function should be called to free internal data structures.
+.Pp
+To iterate through all the items in the report descriptor
+.Fn hid_get_item
+should be called while it returns a value greater than 0.
+When the report descriptor ends it will returns 0; a syntax
+error within the report descriptor will cause a return value less
+than 0.
+The struct pointed to by
+.Fa h
+will be filled with the relevant data for the item.
+The definition of
+.Vt hid_item_t
+can be found in
+.In usbhid.h
+and the meaning of the components in the USB HID documentation.
+.Pp
+Data should be read/written to the device in the size of
+the report.
+The size of a report (of a certain kind) can be computed by the
+.Fn hid_report_size
+function.
+If the report is prefixed by an ID byte it is given by
+.Fa id .
+.Pp
+To locate a single item the
+.Fn hid_locate
+function can be used.
+It should be given the usage code of
+the item and its kind and it will fill the item and return
+non-zero if the item was found.
+.Ss Name Translation Functions
+The function
+.Fn hid_usage_page
+will return the symbolic name of a usage page, and the function
+.Fn hid_usage_in_page
+will return the symbolic name of the usage within the page.
+Both these functions may return a pointer to static data.
+.Pp
+The functions
+.Fn hid_parse_usage_page
+and
+.Fn hid_parse_usage_in_page
+are the inverses of
+.Fn hid_usage_page
+and
+.Fn hid_usage_in_page .
+They take a usage string and return the number of the usage, or \-1
+if it cannot be found.
+.Pp
+Before any of these functions can be called the usage table
+must be parsed, this is done by calling
+.Fn hid_init
+with the name of the table.
+Passing
+.Dv NULL
+to this function will cause it to use the default table.
+.Ss Data Extraction Functions
+Given the data obtained from a HID device and an item in the
+report descriptor the
+.Fn hid_get_data
+function extracts the value of the item.
+Conversely
+.Fn hid_set_data
+can be used to put data into a report (which must be zeroed first).
+.Sh FILES
+.Bl -tag -width ".Pa /usr/share/misc/usb_hid_usages"
+.It Pa /usr/share/misc/usb_hid_usages
+The default HID usage table.
+.El
+.Sh EXAMPLES
+Not yet.
+.Sh SEE ALSO
+The
+.Tn USB
+specifications can be found at
+.Pa http://www.usb.org/developers/docs/ .
+.Pp
+.Xr uhid 4 ,
+.Xr usb 4
+.Sh HISTORY
+The
+.Nm
+library first appeared in
+.Nx 1.5 .
+.Sh BUGS
+This man page is woefully incomplete.
diff --git a/lib/libusbhid/usbhid.h b/lib/libusbhid/usbhid.h
new file mode 100644
index 0000000..af3228f
--- /dev/null
+++ b/lib/libusbhid/usbhid.h
@@ -0,0 +1,109 @@
+/* $NetBSD: usb.h,v 1.8 2000/08/13 22:22:02 augustss Exp $ */
+
+/*
+ * Copyright (c) 1999 Lennart Augustsson <augustss@netbsd.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>
+
+typedef struct report_desc *report_desc_t;
+
+typedef struct hid_data *hid_data_t;
+
+typedef enum hid_kind {
+ hid_input = 0,
+ hid_output = 1,
+ hid_feature = 2,
+ hid_collection,
+ hid_endcollection
+} hid_kind_t;
+
+typedef struct hid_item {
+ /* Global */
+ unsigned int _usage_page;
+ int logical_minimum;
+ int logical_maximum;
+ int physical_minimum;
+ int physical_maximum;
+ int unit_exponent;
+ int unit;
+ int report_size;
+ int report_ID;
+#define NO_REPORT_ID 0
+ int report_count;
+ /* Local */
+ unsigned int usage;
+ int usage_minimum;
+ int usage_maximum;
+ int designator_index;
+ int designator_minimum;
+ int designator_maximum;
+ int string_index;
+ int string_minimum;
+ int string_maximum;
+ int set_delimiter;
+ /* Misc */
+ int collection;
+ int collevel;
+ enum hid_kind kind;
+ unsigned int flags;
+ /* Absolute data position (bits) */
+ unsigned int pos;
+ /* */
+ struct hid_item *next;
+} hid_item_t;
+
+#define HID_PAGE(u) (((u) >> 16) & 0xffff)
+#define HID_USAGE(u) ((u) & 0xffff)
+
+__BEGIN_DECLS
+
+/* Obtaining a report descriptor, descr.c: */
+report_desc_t hid_get_report_desc(int file);
+report_desc_t hid_use_report_desc(unsigned char *data, unsigned int size);
+void hid_dispose_report_desc(report_desc_t);
+
+/* Parsing of a HID report descriptor, parse.c: */
+hid_data_t hid_start_parse(report_desc_t d, int kindset, int id);
+void hid_end_parse(hid_data_t s);
+int hid_get_item(hid_data_t s, hid_item_t *h);
+int hid_report_size(report_desc_t d, enum hid_kind k, int id);
+int hid_locate(report_desc_t d, unsigned int usage, enum hid_kind k, hid_item_t *h, int id);
+
+/* Conversion to/from usage names, usage.c: */
+const char *hid_usage_page(int i);
+const char *hid_usage_in_page(unsigned int u);
+void hid_init(const char *file);
+int hid_parse_usage_in_page(const char *name);
+int hid_parse_usage_page(const char *name);
+
+/* Extracting/insertion of data, data.c: */
+int hid_get_data(const void *p, const hid_item_t *h);
+void hid_set_data(void *p, const hid_item_t *h, int data);
+
+__END_DECLS
diff --git a/lib/libusbhid/usbvar.h b/lib/libusbhid/usbvar.h
new file mode 100644
index 0000000..7ed04e5
--- /dev/null
+++ b/lib/libusbhid/usbvar.h
@@ -0,0 +1,36 @@
+/* $NetBSD: usbvar.h,v 1.2 1999/05/11 21:15:46 augustss Exp $ */
+
+/*
+ * Copyright (c) 1999 Lennart Augustsson <augustss@netbsd.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$
+ *
+ */
+
+struct report_desc {
+ unsigned int size;
+ unsigned char data[1];
+};
+
diff --git a/lib/libutil/Makefile b/lib/libutil/Makefile
new file mode 100644
index 0000000..8da897e
--- /dev/null
+++ b/lib/libutil/Makefile
@@ -0,0 +1,49 @@
+# @(#)Makefile 8.1 (Berkeley) 6/4/93
+# $FreeBSD$
+
+LIB= util
+SHLIB_MAJOR= 5
+SHLIBDIR?= /lib
+CFLAGS+=-DLIBC_SCCS -I${.CURDIR} -I${.CURDIR}/../libc/gen/
+CFLAGS+=-DINET6
+SRCS= _secure_path.c auth.c fparseln.c humanize_number.c kld.c login.c \
+ login_auth.c login_cap.c login_class.c login_crypt.c login_ok.c \
+ login_times.c login_tty.c logout.c logwtmp.c \
+ pidfile.c property.c pty.c pw_util.c realhostname.c stub.c \
+ trimdomain.c uucplock.c
+INCS= libutil.h login_cap.h
+
+MAN+= kld.3 login.3 login_auth.3 login_tty.3 logout.3 logwtmp.3 pty.3 \
+ login_cap.3 login_class.3 login_times.3 login_ok.3 \
+ _secure_path.3 uucplock.3 property.3 auth.3 realhostname.3 \
+ realhostname_sa.3 trimdomain.3 fparseln.3 humanize_number.3 \
+ pidfile.3
+MAN+= login.conf.5 auth.conf.5
+MLINKS+= kld.3 kld_isloaded.3 kld.3 kld_load.3
+MLINKS+= property.3 properties_read.3 property.3 properties_free.3
+MLINKS+= property.3 property_find.3
+MLINKS+= auth.3 auth_getval.3
+MLINKS+= pty.3 openpty.3 pty.3 forkpty.3
+MLINKS+=login_cap.3 login_getclassbyname.3 login_cap.3 login_close.3 \
+ login_cap.3 login_getclass.3 login_cap.3 login_getuserclass.3 \
+ login_cap.3 login_getcapstr.3 login_cap.3 login_getcaplist.3 \
+ login_cap.3 login_getstyle.3 login_cap.3 login_getcaptime.3 \
+ login_cap.3 login_getcapnum.3 login_cap.3 login_getcapsize.3 \
+ login_cap.3 login_getcapbool.3 login_cap.3 login_getpath.3 \
+ login_cap.3 login_getpwclass.3 login_cap.3 login_setcryptfmt.3
+MLINKS+=login_class.3 setusercontext.3 login_class.3 setclasscontext.3 \
+ login_class.3 setclassenvironment.3 login_class.3 setclassresources.3
+MLINKS+=login_times.3 parse_lt.3 login_times.3 in_ltm.3 \
+ login_times.3 in_lt.3 login_times.3 in_ltms.3 \
+ login_times.3 in_lts.3
+MLINKS+=login_ok.3 auth_ttyok.3 login_ok.3 auth_hostok.3 \
+ login_ok.3 auth_timeok.3
+MLINKS+=login_auth.3 auth_checknologin.3 login_auth.3 auth_cat.3
+MLINKS+=uucplock.3 uu_lock.3 uucplock.3 uu_lock_txfr.3 \
+ uucplock.3 uu_unlock.3 uucplock.3 uu_lockerr.3
+MLINKS+=pidfile.3 pidfile_open.3 \
+ pidfile.3 pidfile_write.3 \
+ pidfile.3 pidfile_close.3 \
+ pidfile.3 pidfile_remove.3
+
+.include <bsd.lib.mk>
diff --git a/lib/libutil/_secure_path.3 b/lib/libutil/_secure_path.3
new file mode 100644
index 0000000..fe23d12
--- /dev/null
+++ b/lib/libutil/_secure_path.3
@@ -0,0 +1,75 @@
+.\" Copyright (c) 1997 David Nugent <davidn@blaze.net.au>
+.\" 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
+.\" David Nugent.
+.\" 5. Modifications may be freely made to this file providing the above
+.\" conditions are met.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd May 2, 1997
+.Os
+.Dt _SECURE_PATH 3
+.Sh NAME
+.Nm _secure_path
+.Nd determine if a file appears to be secure
+.Sh LIBRARY
+.Lb libutil
+.Sh SYNOPSIS
+.In sys/types.h
+.In libutil.h
+.Ft int
+.Fn _secure_path "const char *path" "uid_t uid" "gid_t gid"
+.Sh DESCRIPTION
+This function does some basic security checking on a given path.
+It is intended to be used by processes running with root privileges
+in order to decide whether or not to trust the contents of a given
+file.
+It uses a method often used to detect system compromise.
+.Pp
+A file is considered
+.Sq secure
+if it meets the following conditions:
+.Bl -enum
+.It
+The file exists, and is a regular file (not a symlink, device
+special or named pipe, etc.),
+.It
+Is not world writable.
+.It
+Is owned by the given uid or uid 0, if uid is not -1,
+.It
+Is not group writable or it has group ownership by the given
+gid, if gid is not -1.
+.El
+.Sh RETURN VALUES
+This function returns zero if the file exists and may be
+considered secure, -2 if the file does not exist, and
+-1 otherwise to indicate a security failure.
+The
+.Xr syslog 3
+function is used to log any failure of this function, including the
+reason, at LOG_ERR priority.
+.Sh SEE ALSO
+.Xr lstat 2 ,
+.Xr syslog 3
+.Sh HISTORY
+Code from which this function was derived was contributed to the
+.Fx
+project by Berkeley Software Design, Inc.
+.Sh BUGS
+The checks carried out are rudimentary and no attempt is made
+to eliminate race conditions between use of this function and
+access to the file referenced.
diff --git a/lib/libutil/_secure_path.c b/lib/libutil/_secure_path.c
new file mode 100644
index 0000000..363378b
--- /dev/null
+++ b/lib/libutil/_secure_path.c
@@ -0,0 +1,74 @@
+/*-
+ * Based on code copyright (c) 1995,1997 by
+ * Berkeley Software Design, Inc.
+ * 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 authors.
+ * 5. Modifications may be freely made to this file providing the above
+ * conditions are met.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <libutil.h>
+#include <stddef.h>
+#include <syslog.h>
+
+/*
+ * Check for common security problems on a given path
+ * It must be:
+ * 1. A regular file, and exists
+ * 2. Owned and writable only by root (or given owner)
+ * 3. Group ownership is given group or is non-group writable
+ *
+ * Returns: -2 if file does not exist,
+ * -1 if security test failure
+ * 0 otherwise
+ */
+
+int
+_secure_path(const char *path, uid_t uid, gid_t gid)
+{
+ int r = -1;
+ struct stat sb;
+ const char *msg = NULL;
+
+ if (lstat(path, &sb) < 0) {
+ if (errno == ENOENT) /* special case */
+ r = -2; /* if it is just missing, skip the log entry */
+ else
+ msg = "%s: cannot stat %s: %m";
+ }
+ else if (!S_ISREG(sb.st_mode))
+ msg = "%s: %s is not a regular file";
+ else if (sb.st_mode & S_IWOTH)
+ msg = "%s: %s is world writable";
+ else if ((int)uid != -1 && sb.st_uid != uid && sb.st_uid != 0) {
+ if (uid == 0)
+ msg = "%s: %s is not owned by root";
+ else
+ msg = "%s: %s is not owned by uid %d";
+ } else if ((int)gid != -1 && sb.st_gid != gid && (sb.st_mode & S_IWGRP))
+ msg = "%s: %s is group writeable by non-authorised groups";
+ else
+ r = 0;
+ if (msg != NULL)
+ syslog(LOG_ERR, msg, "_secure_path", path, uid);
+ return r;
+}
diff --git a/lib/libutil/auth.3 b/lib/libutil/auth.3
new file mode 100644
index 0000000..3a1bb4d
--- /dev/null
+++ b/lib/libutil/auth.3
@@ -0,0 +1,56 @@
+.\"
+.\" Copyright (c) 1998 Jordan Hubbard
+.\"
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this 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 7, 1998
+.Os
+.Dt AUTH_GETVAL 3
+.Sh NAME
+.Nm auth_getval
+.Nd functions for reading values from
+.Pa /etc/auth.conf
+.Sh LIBRARY
+.Lb libutil
+.Sh SYNOPSIS
+.In sys/types.h
+.In libutil.h
+.Ft char *
+.Fn auth_getval "const char *name"
+.Sh DESCRIPTION
+The function
+.Fn auth_getval
+returns the value associated with the field called
+.Fa name
+or NULL if no such field is found or the auth file cannot be opened.
+.Sh FILES
+.Pa /etc/auth.conf
+contains the name=value pairs looked up by
+.Fn auth_getval .
+.Sh SEE ALSO
+.Xr properties_free 3 ,
+.Xr properties_read 3 ,
+.Xr property_find 3 ,
+.Xr auth.conf 5
diff --git a/lib/libutil/auth.c b/lib/libutil/auth.c
new file mode 100644
index 0000000..748c3ad
--- /dev/null
+++ b/lib/libutil/auth.c
@@ -0,0 +1,70 @@
+/*
+ * Simple authentication database handling code.
+ *
+ * Copyright (c) 1998
+ * Jordan Hubbard. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * verbatim and that no modifications are made prior to this
+ * point in 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 OR HIS PETS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 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 <fcntl.h>
+#include <libutil.h>
+#include <paths.h>
+#include <syslog.h>
+#include <unistd.h>
+
+static properties P;
+
+static int
+initauthconf(const char *path)
+{
+ int fd;
+
+ if (!P) {
+ if ((fd = open(path, O_RDONLY)) < 0) {
+ syslog(LOG_ERR, "initauthconf: unable to open file: %s", path);
+ return 1;
+ }
+ P = properties_read(fd);
+ close(fd);
+ if (!P) {
+ syslog(LOG_ERR, "initauthconf: unable to parse file: %s", path);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+char *
+auth_getval(const char *name)
+{
+ if (!P && initauthconf(_PATH_AUTHCONF))
+ return NULL;
+ else
+ return property_find(P, name);
+}
diff --git a/lib/libutil/auth.conf.5 b/lib/libutil/auth.conf.5
new file mode 100644
index 0000000..be10eb8
--- /dev/null
+++ b/lib/libutil/auth.conf.5
@@ -0,0 +1,35 @@
+.\" Copyright (c) 1998 Jordan Hubbard
+.\" 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd October 7, 1998
+.Dt AUTH.CONF 5
+.Os
+.Sh NAME
+.Nm auth.conf
+.Nd authentication capability database
+.Sh SYNOPSIS
+.Pa /etc/auth.conf
+.Sh DESCRIPTION
+.Nm
+contains various attributes important to the authentication
+code, most notably
+.Xr crypt 3
+for the time being.
+This documentation will be updated as the
+.Pa /etc/auth.conf
+file, which is very new, evolves.
+.Sh SEE ALSO
+.Xr auth_getval 3 ,
+.Xr crypt 3
diff --git a/lib/libutil/fparseln.3 b/lib/libutil/fparseln.3
new file mode 100644
index 0000000..cd78437
--- /dev/null
+++ b/lib/libutil/fparseln.3
@@ -0,0 +1,158 @@
+.\" $NetBSD: fparseln.3,v 1.7 1999/07/02 15:49:12 simonb Exp $
+.\" $FreeBSD$
+.\"
+.\" Copyright (c) 1997 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.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by Christos Zoulas.
+.\" 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 December 1, 1997
+.Dt FPARSELN 3
+.Os
+.Sh NAME
+.Nm fparseln
+.Nd return the next logical line from a stream
+.Sh LIBRARY
+.Lb libutil
+.Sh SYNOPSIS
+.In stdio.h
+.In libutil.h
+.Ft "char *"
+.Fo fparseln
+.Fa "FILE *stream" "size_t *len" "size_t *lineno"
+.Fa "const char delim[3]" "int flags"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn fparseln
+function
+returns a pointer to the next logical line from the stream referenced by
+.Fa stream .
+This string is
+.Dv NUL
+terminated and it is dynamically allocated on each invocation.
+It is the
+responsibility of the caller to free the pointer.
+.Pp
+By default, if a character is escaped, both it and the preceding escape
+character will be present in the returned string.
+Various
+.Fa flags
+alter this behaviour.
+.Pp
+The meaning of the arguments is as follows:
+.Bl -tag -width "lineno"
+.It Fa stream
+The stream to read from.
+.It Fa len
+If not
+.Dv NULL ,
+the length of the string is stored in the memory location to which it
+points.
+.It Fa lineno
+If not
+.Dv NULL ,
+the value of the memory location to which is pointed to, is incremented
+by the number of lines actually read from the file.
+.It Fa delim
+Contains the escape, continuation, and comment characters.
+If a character is
+.Dv NUL
+then processing for that character is disabled.
+If
+.Dv NULL ,
+all characters default to values specified below.
+The contents of
+.Fa delim
+is as follows:
+.Bl -tag -width "delim[0]"
+.It Fa delim[0]
+The escape character, which defaults to
+.Cm \e ,
+is used to remove any special meaning from the next character.
+.It Fa delim[1]
+The continuation character, which defaults to
+.Cm \e ,
+is used to indicate that the next line should be concatenated with the
+current one if this character is the last character on the current line
+and is not escaped.
+.It Fa delim[2]
+The comment character, which defaults to
+.Cm # ,
+if not escaped indicates the beginning of a comment that extends until the
+end of the current line.
+.El
+.It Fa flags
+If non-zero, alter the operation of
+.Fn fparseln .
+The various flags, which may be
+.Em or Ns -ed
+together, are:
+.Bl -tag -width "FPARSELN_UNESCCOMM"
+.It Dv FPARSELN_UNESCCOMM
+Remove escape preceding an escaped comment.
+.It Dv FPARSELN_UNESCCONT
+Remove escape preceding an escaped continuation.
+.It Dv FPARSELN_UNESCESC
+Remove escape preceding an escaped escape.
+.It Dv FPARSELN_UNESCREST
+Remove escape preceding any other character.
+.It Dv FPARSELN_UNESCALL
+All of the above.
+.El
+.Pp
+.El
+.Sh RETURN VALUES
+Upon successful completion a pointer to the parsed line is returned;
+otherwise,
+.Dv NULL
+is returned.
+.Pp
+The
+.Fn fparseln
+function uses internally
+.Xr fgetln 3 ,
+so all error conditions that apply to
+.Xr fgetln 3 ,
+apply to
+.Fn fparseln .
+In addition
+.Fn fparseln
+may set
+.Va errno
+to
+.Er ENOMEM
+and return
+.Dv NULL
+if it runs out of memory.
+.Sh SEE ALSO
+.Xr fgetln 3
+.Sh HISTORY
+The
+.Fn fparseln
+function first appeared in
+.Nx 1.4
+and
+.Fx 4.0 .
diff --git a/lib/libutil/fparseln.c b/lib/libutil/fparseln.c
new file mode 100644
index 0000000..0624f0e
--- /dev/null
+++ b/lib/libutil/fparseln.c
@@ -0,0 +1,222 @@
+/* $NetBSD: fparseln.c,v 1.9 1999/09/20 04:48:06 lukem Exp $ */
+
+/*
+ * Copyright (c) 1997 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Christos Zoulas.
+ * 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 <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <libutil.h>
+
+static int isescaped(const char *, const char *, int);
+
+/* isescaped():
+ * Return true if the character in *p that belongs to a string
+ * that starts in *sp, is escaped by the escape character esc.
+ */
+static int
+isescaped(const char *sp, const char *p, int esc)
+{
+ const char *cp;
+ size_t ne;
+
+#if 0
+ _DIAGASSERT(sp != NULL);
+ _DIAGASSERT(p != NULL);
+#endif
+
+ /* No escape character */
+ if (esc == '\0')
+ return 1;
+
+ /* Count the number of escape characters that precede ours */
+ for (ne = 0, cp = p; --cp >= sp && *cp == esc; ne++)
+ continue;
+
+ /* Return true if odd number of escape characters */
+ return (ne & 1) != 0;
+}
+
+
+/* fparseln():
+ * Read a line from a file parsing continuations ending in \
+ * and eliminating trailing newlines, or comments starting with
+ * the comment char.
+ */
+char *
+fparseln(FILE *fp, size_t *size, size_t *lineno, const char str[3], int flags)
+{
+ static const char dstr[3] = { '\\', '\\', '#' };
+
+ size_t s, len;
+ char *buf;
+ char *ptr, *cp;
+ int cnt;
+ char esc, con, nl, com;
+
+#if 0
+ _DIAGASSERT(fp != NULL);
+#endif
+
+ len = 0;
+ buf = NULL;
+ cnt = 1;
+
+ if (str == NULL)
+ str = dstr;
+
+ esc = str[0];
+ con = str[1];
+ com = str[2];
+ /*
+ * XXX: it would be cool to be able to specify the newline character,
+ * but unfortunately, fgetln does not let us
+ */
+ nl = '\n';
+
+ while (cnt) {
+ cnt = 0;
+
+ if (lineno)
+ (*lineno)++;
+
+ if ((ptr = fgetln(fp, &s)) == NULL)
+ break;
+
+ if (s && com) { /* Check and eliminate comments */
+ for (cp = ptr; cp < ptr + s; cp++)
+ if (*cp == com && !isescaped(ptr, cp, esc)) {
+ s = cp - ptr;
+ cnt = s == 0 && buf == NULL;
+ break;
+ }
+ }
+
+ if (s && nl) { /* Check and eliminate newlines */
+ cp = &ptr[s - 1];
+
+ if (*cp == nl)
+ s--; /* forget newline */
+ }
+
+ if (s && con) { /* Check and eliminate continuations */
+ cp = &ptr[s - 1];
+
+ if (*cp == con && !isescaped(ptr, cp, esc)) {
+ s--; /* forget escape */
+ cnt = 1;
+ }
+ }
+
+ if (s == 0 && buf != NULL)
+ continue;
+
+ if ((cp = realloc(buf, len + s + 1)) == NULL) {
+ free(buf);
+ return NULL;
+ }
+ buf = cp;
+
+ (void) memcpy(buf + len, ptr, s);
+ len += s;
+ buf[len] = '\0';
+ }
+
+ if ((flags & FPARSELN_UNESCALL) != 0 && esc && buf != NULL &&
+ strchr(buf, esc) != NULL) {
+ ptr = cp = buf;
+ while (cp[0] != '\0') {
+ int skipesc;
+
+ while (cp[0] != '\0' && cp[0] != esc)
+ *ptr++ = *cp++;
+ if (cp[0] == '\0' || cp[1] == '\0')
+ break;
+
+ skipesc = 0;
+ if (cp[1] == com)
+ skipesc += (flags & FPARSELN_UNESCCOMM);
+ if (cp[1] == con)
+ skipesc += (flags & FPARSELN_UNESCCONT);
+ if (cp[1] == esc)
+ skipesc += (flags & FPARSELN_UNESCESC);
+ if (cp[1] != com && cp[1] != con && cp[1] != esc)
+ skipesc = (flags & FPARSELN_UNESCREST);
+
+ if (skipesc)
+ cp++;
+ else
+ *ptr++ = *cp++;
+ *ptr++ = *cp++;
+ }
+ *ptr = '\0';
+ len = strlen(buf);
+ }
+
+ if (size)
+ *size = len;
+ return buf;
+}
+
+#ifdef TEST
+
+int
+main(int argc, char *argv[])
+{
+ char *ptr;
+ size_t size, line;
+
+ line = 0;
+ while ((ptr = fparseln(stdin, &size, &line, NULL,
+ FPARSELN_UNESCALL)) != NULL)
+ printf("line %d (%d) |%s|\n", line, size, ptr);
+ return 0;
+}
+
+/*
+
+# This is a test
+line 1
+line 2 \
+line 3 # Comment
+line 4 \# Not comment \\\\
+
+# And a comment \
+line 5 \\\
+line 6
+
+*/
+
+#endif /* TEST */
diff --git a/lib/libutil/humanize_number.3 b/lib/libutil/humanize_number.3
new file mode 100644
index 0000000..650c936
--- /dev/null
+++ b/lib/libutil/humanize_number.3
@@ -0,0 +1,148 @@
+.\" $NetBSD: humanize_number.3,v 1.4 2003/04/16 13:34:37 wiz Exp $
+.\" $FreeBSD$
+.\"
+.\" Copyright (c) 1999, 2002 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Luke Mewburn and by Tomas Svensson.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce 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 NetBSD
+.\" Foundation, Inc. and its contributors.
+.\" 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.
+.\"
+.Dd May 25, 2004
+.Dt HUMANIZE_NUMBER 3
+.Os
+.Sh NAME
+.Nm humanize_number
+.Nd format a number into a human readable form
+.Sh LIBRARY
+.Lb libutil
+.Sh SYNOPSIS
+.In libutil.h
+.Ft int
+.Fo humanize_number
+.Fa "char *buf" "size_t len" "int64_t number" "const char *suffix"
+.Fa "int scale" "int flags"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn humanize_number
+function formats the signed 64-bit quantity given in
+.Fa number
+into
+.Fa buffer .
+A space and then
+.Fa suffix
+is appended to the end.
+The buffer pointed to by
+.Fa buffer
+must be at least
+.Fa len
+bytes long.
+.Pp
+If the formatted number (including
+.Fa suffix )
+would be too long to fit into
+.Fa buffer ,
+then divide
+.Fa number
+by 1024 until it will.
+In this case, prefix
+.Fa suffix
+with the appropriate SI designator.
+.Pp
+The prefixes are:
+.Bl -column "Prefix" "Description" "Multiplier" -offset indent
+.It Sy "Prefix" Ta Sy "Description" Ta Sy "Multiplier"
+.It Li k Ta No kilo Ta 1024
+.It Li M Ta No mega Ta 1048576
+.It Li G Ta No giga Ta 1073741824
+.It Li T Ta No tera Ta 1099511627776
+.It Li P Ta No peta Ta 1125899906842624
+.It Li E Ta No exa Ta 1152921504606846976
+.El
+.Pp
+The
+.Fa len
+argument must be at least 4 plus the length of
+.Fa suffix ,
+in order to ensure a useful result is generated into
+.Fa buffer .
+To use a specific prefix, specify this as
+.Fa scale
+(multiplier = 1024 ^ scale).
+This cannot be combined with any of the
+.Fa scale
+flags below.
+.Pp
+The following flags may be passed in
+.Fa scale :
+.Bl -tag -width ".Dv HN_DIVISOR_1000" -offset indent
+.It Dv HN_AUTOSCALE
+Format the buffer using the lowest multiplier possible.
+.It Dv HN_GETSCALE
+Return the prefix index number (the number of times
+.Fa number
+must be divided to fit) instead of formatting it to the buffer.
+.El
+.Pp
+The following flags may be passed in
+.Fa flags :
+.Bl -tag -width ".Dv HN_DIVISOR_1000" -offset indent
+.It Dv HN_DECIMAL
+If the final result is less than 10, display it using one digit.
+.It Dv HN_NOSPACE
+Do not put a space between
+.Fa number
+and the prefix.
+.It Dv HN_B
+Use
+.Ql B
+(bytes) as prefix if the original result does not have a prefix.
+.It Dv HN_DIVISOR_1000
+Divide
+.Fa number
+with 1000 instead of 1024.
+.El
+.Sh RETURN VALUES
+The
+.Fn humanize_number
+function returns the number of characters stored in
+.Fa buffer
+(excluding the terminating
+.Dv NUL )
+upon success, or \-1 upon failure.
+If
+.Dv HN_GETSCALE
+is specified, the prefix index number will be returned instead.
+.Sh HISTORY
+The
+.Fn humanize_number
+function first appeared in
+.Nx 2.0 .
diff --git a/lib/libutil/humanize_number.c b/lib/libutil/humanize_number.c
new file mode 100644
index 0000000..21d5e39
--- /dev/null
+++ b/lib/libutil/humanize_number.c
@@ -0,0 +1,148 @@
+/* $NetBSD: humanize_number.c,v 1.8 2004/07/27 01:56:24 enami Exp $ */
+
+/*
+ * Copyright (c) 1997, 1998, 1999, 2002 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, by Luke Mewburn and by Tomas Svensson.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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 NetBSD
+ * Foundation, Inc. and its contributors.
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <locale.h>
+#include <libutil.h>
+
+int
+humanize_number(char *buf, size_t len, int64_t bytes,
+ const char *suffix, int scale, int flags)
+{
+ const char *prefixes, *sep;
+ int b, i, r, maxscale, s1, s2, sign;
+ int64_t divisor, max;
+ size_t baselen;
+
+ assert(buf != NULL);
+ assert(suffix != NULL);
+ assert(scale >= 0);
+
+ if (flags & HN_DIVISOR_1000) {
+ /* SI for decimal multiplies */
+ divisor = 1000;
+ if (flags & HN_B)
+ prefixes = "B\0k\0M\0G\0T\0P\0E";
+ else
+ prefixes = "\0\0k\0M\0G\0T\0P\0E";
+ } else {
+ /*
+ * binary multiplies
+ * XXX IEC 60027-2 recommends Ki, Mi, Gi...
+ */
+ divisor = 1024;
+ if (flags & HN_B)
+ prefixes = "B\0K\0M\0G\0T\0P\0E";
+ else
+ prefixes = "\0\0K\0M\0G\0T\0P\0E";
+ }
+
+#define SCALE2PREFIX(scale) (&prefixes[(scale) << 1])
+ maxscale = 7;
+
+ if (scale >= maxscale &&
+ (scale & (HN_AUTOSCALE | HN_GETSCALE)) == 0)
+ return (-1);
+
+ if (buf == NULL || suffix == NULL)
+ return (-1);
+
+ if (len > 0)
+ buf[0] = '\0';
+ if (bytes < 0) {
+ sign = -1;
+ bytes *= -100;
+ baselen = 3; /* sign, digit, prefix */
+ } else {
+ sign = 1;
+ bytes *= 100;
+ baselen = 2; /* digit, prefix */
+ }
+ if (flags & HN_NOSPACE)
+ sep = "";
+ else {
+ sep = " ";
+ baselen++;
+ }
+ baselen += strlen(suffix);
+
+ /* Check if enough room for `x y' + suffix + `\0' */
+ if (len < baselen + 1)
+ return (-1);
+
+ if (scale & (HN_AUTOSCALE | HN_GETSCALE)) {
+ /* See if there is additional columns can be used. */
+ for (max = 100, i = len - baselen; i-- > 0;)
+ max *= 10;
+
+ for (i = 0; bytes >= max && i < maxscale; i++)
+ bytes /= divisor;
+
+ if (scale & HN_GETSCALE)
+ return (i);
+ } else
+ for (i = 0; i < scale && i < maxscale; i++)
+ bytes /= divisor;
+
+ /* If a value <= 9.9 after rounding and ... */
+ if (bytes < 995 && i > 0 && flags & HN_DECIMAL) {
+ /* baselen + \0 + .N */
+ if (len < baselen + 1 + 2)
+ return (-1);
+ b = ((int)bytes + 5) / 10;
+ s1 = b / 10;
+ s2 = b % 10;
+ r = snprintf(buf, len, "%d%s%d%s%s%s",
+ sign * s1, localeconv()->decimal_point, s2,
+ sep, SCALE2PREFIX(i), suffix);
+ } else
+ r = snprintf(buf, len, "%lld%s%s%s",
+ /* LONGLONG */
+ (long long)(sign * ((bytes + 50) / 100)),
+ sep, SCALE2PREFIX(i), suffix);
+
+ return (r);
+}
diff --git a/lib/libutil/kld.3 b/lib/libutil/kld.3
new file mode 100644
index 0000000..c3cc3a7
--- /dev/null
+++ b/lib/libutil/kld.3
@@ -0,0 +1,98 @@
+.\"-
+.\" Copyright (c) 2006 Dag-Erling Coïdan Smørgrav
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING 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 18, 2006
+.Os
+.Dt KLD 3
+.Sh NAME
+.Nm kld_isloaded ,
+.Nm kld_load
+.Nd kld utility functions
+.Sh LIBRARY
+.Lb libutil
+.Sh SYNOPSIS
+.In libutil.h
+.Ft int
+.Fn kld_isloaded "const char *name"
+.Ft int
+.Fn kld_load "const char *name"
+.Sh DESCRIPTION
+These functions facilitate loading kernel modules from userland
+applications.
+.Pp
+The
+.Fn kld_isloaded
+function takes a name and returns a non-zero value if a module of that
+name is currently loaded.
+The name can be either the name of a module file
+.Po
+.Va cpufreq.ko
+.Pc ,
+the same name without the
+.Pa .ko
+extension
+.Po
+.Va cpufreq
+.Pc ,
+or the name of a module contained within that file
+.Po
+.Va cpu/ichss
+.Pc .
+Only the latter will return correct results if the module is compiled
+into the kernel.
+.Pp
+The
+.Fn kld_load
+function is a simple wrapper around the
+.Fn kldload
+function.
+It returns zero if and only if the corresponding
+.Fn kldload
+call succeeded or returned
+.Er EEXIST
+(signifying that the requested module was already loaded).
+.Sh SEE ALSO
+.Xr kldfirstmod 2
+.Xr kldload 2 ,
+.Xr kldnext 2 ,
+.Xr kldstat 2 ,
+.Xr modfnext 2 ,
+.Xr modstat 2
+.Sh HISTORY
+The
+.Fn kld_isloaded
+and
+.Fn kld_load
+functions first appeared in
+.Fx 7.0 .
+.Sh AUTHORS
+The
+.Fn kld_isloaded
+and
+.Fn kld_load
+functions and this manual page were written by
+.An Dag-Erling Sm\(/orgrav Aq des@FreeBSD.org .
diff --git a/lib/libutil/kld.c b/lib/libutil/kld.c
new file mode 100644
index 0000000..b8aa9ef
--- /dev/null
+++ b/lib/libutil/kld.c
@@ -0,0 +1,74 @@
+/*-
+ * Copyright (c) 2006 Dag-Erling Coïdan Smørgrav
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/linker.h>
+#include <sys/module.h>
+
+#include <errno.h>
+
+int
+kld_isloaded(const char *name)
+{
+ struct kld_file_stat fstat;
+ struct module_stat mstat;
+ const char *ko;
+ int fid, mid;
+
+ for (fid = kldnext(0); fid > 0; fid = kldnext(fid)) {
+ fstat.version = sizeof(fstat);
+ if (kldstat(fid, &fstat) != 0)
+ continue;
+ /* check if the file name matches the supplied name */
+ if (strcmp(fstat.name, name) == 0)
+ return (1);
+ /* strip .ko and try again */
+ if ((ko = strstr(fstat.name, ".ko")) != NULL &&
+ strlen(name) == ko - fstat.name &&
+ strncmp(fstat.name, name, ko - fstat.name) == 0)
+ return (1);
+ /* look for a matching module within the file */
+ for (mid = kldfirstmod(fid); mid > 0; mid = modfnext(mid)) {
+ mstat.version = sizeof(mstat);
+ if (modstat(mid, &mstat) != 0)
+ continue;
+ if (strcmp(mstat.name, name) == 0)
+ return (1);
+ }
+ }
+ return (0);
+}
+
+int
+kld_load(const char *name)
+{
+ if (kldload(name) == -1 && errno != EEXIST)
+ return (-1);
+ return (0);
+}
diff --git a/lib/libutil/libutil.h b/lib/libutil/libutil.h
new file mode 100644
index 0000000..aefff0c
--- /dev/null
+++ b/lib/libutil/libutil.h
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 1996 Peter Wemm <peter@FreeBSD.org>.
+ * All rights reserved.
+ * Copyright (c) 2002 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS 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, is permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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$
+ */
+
+#ifndef _LIBUTIL_H_
+#define _LIBUTIL_H_
+
+#define PROPERTY_MAX_NAME 64
+#define PROPERTY_MAX_VALUE 512
+
+/* for properties.c */
+typedef struct _property {
+ struct _property *next;
+ char *name;
+ char *value;
+} *properties;
+
+#ifdef _SYS_PARAM_H_
+/* for pidfile.c */
+struct pidfh {
+ int pf_fd;
+ char pf_path[MAXPATHLEN + 1];
+ __dev_t pf_dev;
+ ino_t pf_ino;
+};
+#endif
+
+/* Avoid pulling in all the include files for no need */
+struct termios;
+struct winsize;
+struct utmp;
+struct in_addr;
+
+__BEGIN_DECLS
+void clean_environment(const char * const *_white,
+ const char * const *_more_white);
+int extattr_namespace_to_string(int _attrnamespace, char **_string);
+int extattr_string_to_namespace(const char *_string, int *_attrnamespace);
+void login(struct utmp *_ut);
+int login_tty(int _fd);
+int logout(const char *_line);
+void logwtmp(const char *_line, const char *_name, const char *_host);
+void trimdomain(char *_fullhost, int _hostsize);
+int openpty(int *_amaster, int *_aslave, char *_name,
+ struct termios *_termp, struct winsize *_winp);
+int forkpty(int *_amaster, char *_name,
+ struct termios *_termp, struct winsize *_winp);
+int humanize_number(char *_buf, size_t _len, int64_t _number,
+ const char *_suffix, int _scale, int _flags);
+const char *uu_lockerr(int _uu_lockresult);
+int uu_lock(const char *_ttyname);
+int uu_unlock(const char *_ttyname);
+int uu_lock_txfr(const char *_ttyname, pid_t _pid);
+int _secure_path(const char *_path, uid_t _uid, gid_t _gid);
+properties properties_read(int fd);
+void properties_free(properties list);
+char *property_find(properties list, const char *name);
+char *auth_getval(const char *name);
+int realhostname(char *host, size_t hsize, const struct in_addr *ip);
+struct sockaddr;
+int realhostname_sa(char *host, size_t hsize, struct sockaddr *addr,
+ int addrlen);
+
+int kld_isloaded(const char *name);
+int kld_load(const char *name);
+
+#ifdef _STDIO_H_ /* avoid adding new includes */
+char *fparseln(FILE *, size_t *, size_t *, const char[3], int);
+#endif
+
+#ifdef _PWD_H_
+int pw_copy(int _ffd, int _tfd, const struct passwd *_pw, struct passwd *_old_pw);
+struct passwd *pw_dup(const struct passwd *_pw);
+int pw_edit(int _notsetuid);
+int pw_equal(const struct passwd *_pw1, const struct passwd *_pw2);
+void pw_fini(void);
+int pw_init(const char *_dir, const char *_master);
+char *pw_make(const struct passwd *_pw);
+int pw_mkdb(const char *_user);
+int pw_lock(void);
+struct passwd *pw_scan(const char *_line, int _flags);
+const char *pw_tempname(void);
+int pw_tmp(int _mfd);
+#endif
+
+#ifdef _SYS_PARAM_H_
+struct pidfh *pidfile_open(const char *path, mode_t mode, pid_t *pidptr);
+int pidfile_write(struct pidfh *pfh);
+int pidfile_close(struct pidfh *pfh);
+int pidfile_remove(struct pidfh *pfh);
+#endif
+
+__END_DECLS
+
+#define UU_LOCK_INUSE (1)
+#define UU_LOCK_OK (0)
+#define UU_LOCK_OPEN_ERR (-1)
+#define UU_LOCK_READ_ERR (-2)
+#define UU_LOCK_CREAT_ERR (-3)
+#define UU_LOCK_WRITE_ERR (-4)
+#define UU_LOCK_LINK_ERR (-5)
+#define UU_LOCK_TRY_ERR (-6)
+#define UU_LOCK_OWNER_ERR (-7)
+
+/* return values from realhostname() */
+#define HOSTNAME_FOUND (0)
+#define HOSTNAME_INCORRECTNAME (1)
+#define HOSTNAME_INVALIDADDR (2)
+#define HOSTNAME_INVALIDNAME (3)
+
+/* fparseln(3) */
+#define FPARSELN_UNESCESC 0x01
+#define FPARSELN_UNESCCONT 0x02
+#define FPARSELN_UNESCCOMM 0x04
+#define FPARSELN_UNESCREST 0x08
+#define FPARSELN_UNESCALL 0x0f
+
+/* pw_scan() */
+#define PWSCAN_MASTER 0x01
+#define PWSCAN_WARN 0x02
+
+/* humanize_number(3) */
+#define HN_DECIMAL 0x01
+#define HN_NOSPACE 0x02
+#define HN_B 0x04
+#define HN_DIVISOR_1000 0x08
+
+#define HN_GETSCALE 0x10
+#define HN_AUTOSCALE 0x20
+
+#endif /* !_LIBUTIL_H_ */
diff --git a/lib/libutil/login.3 b/lib/libutil/login.3
new file mode 100644
index 0000000..d88f719
--- /dev/null
+++ b/lib/libutil/login.3
@@ -0,0 +1,67 @@
+.\"
+.\" Copyright (c) 1996 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 December 29, 1996
+.Os
+.Dt LOGIN 3
+.Sh NAME
+.Nm login
+.Nd "log a new login record to the utmp and wtmp files"
+.Sh LIBRARY
+.Lb libutil
+.Sh SYNOPSIS
+.In sys/types.h
+.In utmp.h
+.In libutil.h
+.Ft void
+.Fn login "struct utmp *ut"
+.Sh DESCRIPTION
+The function
+.Fn login
+records the
+.Ar ut
+entry being passed into the appropriate slot of the
+.Xr utmp 5
+file,
+and appends it to the
+.Xr wtmp 5
+file.
+The calling process must have permission to write to both files.
+.Sh RETURN VALUES
+None.
+.Sh SEE ALSO
+.Xr logout 3 ,
+.Xr ttyslot 3 ,
+.Xr utmp 5 ,
+.Xr wtmp 5
+.Sh BUGS
+The interface provided by
+.Fn login
+is rather crude.
+The caller must know about the details of a
+.Va struct utmp .
+Some better abstraction needs to be worked out.
diff --git a/lib/libutil/login.c b/lib/libutil/login.c
new file mode 100644
index 0000000..c2a0b16
--- /dev/null
+++ b/lib/libutil/login.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. 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.
+ */
+
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)login.c 8.1 (Berkeley) 6/4/93";
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+
+#include <fcntl.h>
+#include <libutil.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ttyent.h>
+#include <unistd.h>
+#include <utmp.h>
+
+void
+login(struct utmp *ut)
+{
+ struct ttyent *ty;
+ int fd;
+ int tty;
+
+ setttyent();
+ for (tty = 1; (ty = getttyent()) != NULL; ++tty)
+ if (strcmp(ty->ty_name, ut->ut_line) == 0)
+ break;
+ endttyent();
+ if (tty > 0 && (fd = open(_PATH_UTMP, O_WRONLY|O_CREAT, 0644)) >= 0) {
+ (void)lseek(fd, (off_t)(tty * sizeof(struct utmp)), L_SET);
+ (void)write(fd, ut, sizeof(struct utmp));
+ (void)close(fd);
+ }
+ if ((fd = open(_PATH_WTMP, O_WRONLY|O_APPEND, 0)) >= 0) {
+ (void)write(fd, ut, sizeof(struct utmp));
+ (void)close(fd);
+ }
+}
diff --git a/lib/libutil/login.conf.5 b/lib/libutil/login.conf.5
new file mode 100644
index 0000000..01f9a9f
--- /dev/null
+++ b/lib/libutil/login.conf.5
@@ -0,0 +1,437 @@
+.\" Copyright (c) 1996 David Nugent <davidn@blaze.net.au>
+.\" 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
+.\" David Nugent.
+.\" 5. Modifications may be freely made to this file providing the above
+.\" conditions are met.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd April 19, 2006
+.Dt LOGIN.CONF 5
+.Os
+.Sh NAME
+.Nm login.conf
+.Nd login class capability database
+.Sh SYNOPSIS
+.Pa /etc/login.conf ,
+.Pa ~/.login_conf
+.Sh DESCRIPTION
+.Nm
+contains various attributes and capabilities of login classes.
+A login class (an optional annotation against each record in the user
+account database,
+.Pa /etc/master.passwd )
+determines session accounting, resource limits and user environment settings.
+It is used by various programs in the system to set up a user's login
+environment and to enforce policy, accounting and administrative restrictions.
+It also provides the means by which users are able to be
+authenticated to the system and the types of authentication available.
+Attributes in addition to the ones described here are available with
+third-party packages.
+.Pp
+A special record "default" in the system user class capability database
+.Pa /etc/login.conf
+is used automatically for any
+non-root user without a valid login class in
+.Pa /etc/master.passwd .
+A user with a uid of 0 without a valid login class will use the record
+"root" if it exists, or "default" if not.
+.Pp
+In
+.Fx ,
+users may individually create a file called
+.Pa .login_conf
+in their home directory using the same format, consisting of a single
+entry with a record id of "me".
+If present, this file is used by
+.Xr login 1
+to set user-defined environment settings which override those specified
+in the system login capabilities database.
+Only a subset of login capabilities may be overridden, typically those
+which do not involve authentication, resource limits and accounting.
+.Pp
+Records in a class capabilities database consist of a number of
+colon-separated fields.
+The first entry for each record gives one or more names that a record is
+to be known by, each separated by a '|' character.
+The first name is the most common abbreviation.
+The last name given should be a long name that is more descriptive
+of the capability entry, and all others are synonyms.
+All names but the last should be in lower case and contain no blanks;
+the last name may contain upper case characters and blanks for
+readability.
+.Pp
+The default
+.Pa /etc/login.conf
+shipped with
+.Fx
+is an out of the box configuration.
+Whenever changes to this, or
+the user's
+.Pa ~/.login_conf ,
+file are made, the modifications will not be picked up until
+.Xr cap_mkdb 1
+is used to compile the file into a database.
+This database file will have a
+.Pa .db
+extension and is accessed through
+.Xr cgetent 3 .
+See
+.Xr getcap 3
+for a more in-depth description of the format of a capability database.
+.Sh CAPABILITIES
+Fields within each record in the database follow the
+.Xr getcap 3
+conventions for boolean, type string
+.Ql \&=
+and type numeric
+.Ql \&# ,
+although type numeric is deprecated in favour of the string format and
+either form is accepted for a numeric datum.
+Values fall into the following categories:
+.Bl -tag -width "program"
+.It bool
+If the name is present, then the boolean value is true; otherwise, it is
+false
+.It file
+Path name to a data file
+.It program
+Path name to an executable file
+.It list
+A list of values (or pairs of values) separated by commas or spaces
+.It path
+A space or comma separated list of path names, following the usual csh
+conventions (leading tilde with and without username being expanded to
+home directories etc.)
+.It number
+A numeric value, either decimal (default), hexadecimal (with leading 0x),
+or octal (with a leading 0).
+With a numeric type, only one numeric value is allowed.
+Numeric types may also be specified in string format (i.e., the capability
+tag being delimited from the value by '=' instead of '#').
+Whichever method is used, then all records in the database must use the
+same method to allow values to be correctly overridden in interpolated
+records.
+.It size
+A number which expresses a size.
+The default interpretation of a value is the number of bytes, but a
+suffix may specify alternate units:
+.Bl -tag -offset indent -compact -width xxxx
+.It b
+explicitly selects 512-byte blocks
+.It k
+selects kilobytes (1024 bytes)
+.It m
+specifies a multiplier of 1 megabyte (1048576 bytes),
+.It g
+specifies units of gigabytes, and
+.It t
+represents terabytes.
+.El
+A size value is a numeric quantity and case of the suffix is not significant.
+Concatenated values are added together.
+.It time
+A period of time, by default in seconds.
+A prefix may specify a different unit:
+.Bl -tag -offset indent -compact -width xxxx
+.It y
+indicates the number of 365 day years,
+.It w
+indicates the number of weeks,
+.It d
+the number of days,
+.It h
+the number of hours,
+.It m
+the number of minutes, and
+.It s
+the number of seconds.
+.El
+Concatenated values are added together.
+For example, 2 hours and 40 minutes may be written either as
+9600s, 160m or 2h40m.
+.El
+.Pp
+The usual convention to interpolate capability entries using the special
+.Em tc=value
+notation may be used.
+.Sh RESOURCE LIMITS
+.Bl -column coredumpsize indent indent
+.It Sy "Name Type Notes Description
+.It "coredumpsize size Maximum coredump size limit.
+.It "cputime time CPU usage limit.
+.It "datasize size Maximum data size limit.
+.It "filesize size Maximum file size limit.
+.It "maxproc number Maximum number of processes.
+.It "memorylocked size Maximum locked in core memory size limit.
+.It "memoryuse size Maximum of core memory use size limit.
+.It "openfiles number Maximum number of open files per process.
+.It "sbsize size Maximum permitted socketbuffer size.
+.It "vmemoryuse size Maximum permitted total VM usage per process.
+.It "stacksize size Maximum stack size limit.
+.El
+.Pp
+These resource limit entries actually specify both the maximum
+and current limits (see
+.Xr getrlimit 2 ) .
+The current (soft) limit is the one normally used, although the user is
+permitted to increase the current limit to the maximum (hard) limit.
+The maximum and current limits may be specified individually by appending a
+-max or -cur to the capability name.
+.Sh ENVIRONMENT
+.Bl -column ignorenologin indent xbinxxusrxbin
+.It Sy "Name Type Notes Description
+.It "charset string Set $MM_CHARSET environment variable to the specified
+value.
+.It "hushlogin bool false Same as having a ~/.hushlogin file.
+.It "ignorenologin bool false Login not prevented by nologin.
+.It "ftp-chroot bool false Limit FTP access with
+.Xr chroot 2
+to the
+.Ev HOME
+directory of the user.
+See
+.Xr ftpd 8
+for details.
+.It "label string Default MAC policy; see
+.Xr maclabel 7 .
+.It "lang string Set $LANG environment variable to the specified value.
+.It "manpath path Default search path for manpages.
+.It "nocheckmail bool false Display mail status at login.
+.It "nologin file If the file exists it will be displayed and
+the login session will be terminated.
+.It "path path /bin /usr/bin Default search path.
+.It "priority number Initial priority (nice) level.
+.It "requirehome bool false Require a valid home directory to login.
+.It "setenv list A comma-separated list of environment variables and
+values to which they are to be set.
+.It "shell prog Session shell to execute rather than the
+shell specified in the passwd file.
+The SHELL environment variable will
+contain the shell specified in the password file.
+.It "term string Default terminal type if not able to determine
+from other means.
+.It "timezone string Default value of $TZ environment variable.
+.It "umask number 022 Initial umask. Should always have a leading 0 to
+ensure octal interpretation.
+.It "welcome file /etc/motd File containing welcome message.
+.El
+.Sh AUTHENTICATION
+.Bl -column passwd_prompt indent indent
+.It Sy "Name Type Notes Description
+.\" .It "approve program Program to approve login.
+.It "copyright file File containing additional copyright information
+.It "host.allow list List of remote host wildcards from which users in
+the class may access.
+.It "host.deny list List of remote host wildcards from which users
+in the class may not access.
+.It "login_prompt string The login prompt given by
+.Xr login 1
+.It "login-backoff number 3 The number of login attempts
+allowed before the backoff delay is inserted after each subsequent
+attempt.
+The backoff delay is the number of tries above
+.Em login-backoff
+multiplied by 5 seconds.
+.It "login-retries number 10 The number of login attempts
+allowed before the login fails.
+.It "passwd_format string md5 The encryption format that new or
+changed passwords will use.
+Valid values include "des", "md5" and "blf".
+NIS clients using a
+.No non- Ns Fx
+NIS server should probably use "des".
+.It "passwd_prompt string The password prompt presented by
+.Xr login 1
+.It "times.allow list List of time periods during which
+logins are allowed.
+.It "times.deny list List of time periods during which logins are
+disallowed.
+.It "ttys.allow list List of ttys and ttygroups which users
+in the class may use for access.
+.It "ttys.deny list List of ttys and ttygroups which users
+in the class may not use for access.
+.It "warnexpire time Advance notice for pending account expiry.
+.It "warnpassword time Advance notice for pending password expiry.
+.\".It "widepasswords bool false Use the wide password format. The wide password
+.\" format allows up to 128 significant characters in the password.
+.El
+.Pp
+These fields are intended to be used by
+.Xr passwd 1
+and other programs in the login authentication system.
+.Pp
+Capabilities that set environment variables are scanned for both
+.Ql \&~
+and
+.Ql \&$
+characters, which are substituted for a user's home directory and name
+respectively.
+To pass these characters literally into the environment variable, escape
+the character by preceding it with a backslash '\\'.
+.Pp
+The
+.Em host.allow
+and
+.Em host.deny
+entries are comma separated lists used for checking remote access to the system,
+and consist of a list of hostnames and/or IP addresses against which remote
+network logins are checked.
+Items in these lists may contain wildcards in the form used by shell programs
+for wildcard matching (See
+.Xr fnmatch 3
+for details on the implementation).
+The check on hosts is made against both the remote system's Internet address
+and hostname (if available).
+If both lists are empty or not specified, then logins from any remote host
+are allowed.
+If host.allow contains one or more hosts, then only remote systems matching
+any of the items in that list are allowed to log in.
+If host.deny contains one or more hosts, then a login from any matching hosts
+will be disallowed.
+.Pp
+The
+.Em times.allow
+and
+.Em times.deny
+entries consist of a comma-separated list of time periods during which the users
+in a class are allowed to be logged in.
+These are expressed as one or more day codes followed by a start and end times
+expressed in 24 hour format, separated by a hyphen or dash.
+For example, MoThSa0200-1300 translates to Monday, Thursday and Saturday between
+the hours of 2 am and 1 p.m..
+If both of these time lists are empty, users in the class are allowed access at
+any time.
+If
+.Em times.allow
+is specified, then logins are only allowed during the periods given.
+If
+.Em times.deny
+is specified, then logins are denied during the periods given, regardless of whether
+one of the periods specified in
+.Em times.allow
+applies.
+.Pp
+Note that
+.Xr login 1
+enforces only that the actual login falls within periods allowed by these entries.
+Further enforcement over the life of a session requires a separate daemon to
+monitor transitions from an allowed period to a non-allowed one.
+.Pp
+The
+.Em ttys.allow
+and
+.Em ttys.deny
+entries contain a comma-separated list of tty devices (without the /dev/ prefix)
+that a user in a class may use to access the system, and/or a list of ttygroups
+(See
+.Xr getttyent 3
+and
+.Xr ttys 5
+for information on ttygroups).
+If neither entry exists, then the choice of login device used by the user is
+unrestricted.
+If only
+.Em ttys.allow
+is specified, then the user is restricted only to ttys in the given
+group or device list.
+If only
+.Em ttys.deny
+is specified, then the user is prevented from using the specified devices or
+devices in the group.
+If both lists are given and are non-empty, the user is restricted to those
+devices allowed by ttys.allow that are not available by ttys.deny.
+.Pp
+The
+.Em minpasswordlen
+and
+.Em minpasswordcase
+facilities for enforcing restrictions on password quality, which used
+to be supported by
+.Nm ,
+have been superseded by the
+.Xr pam_passwdqc 8
+PAM module.
+.Sh RESERVED CAPABILITIES
+The following capabilities are reserved for the purposes indicated and
+may be supported by third-party software.
+They are not implemented in the base system.
+.Bl -column host.accounted indent indent
+.It Sy "Name Type Notes Description
+.It "accounted bool false Enable session time accounting for all users
+in this class.
+.It "autodelete time Time after expiry when account is auto-deleted.
+.It "bootfull bool false Enable 'boot only if ttygroup is full' strategy
+when terminating sessions.
+.It "daytime time Maximum login time per day.
+.It "expireperiod time Time for expiry allocation.
+.It "graceexpire time Grace days for expired account.
+.It "gracetime time Additional grace login time allowed.
+.It "host.accounted list List of remote host wildcards from which
+login sessions will be accounted.
+.It "host.exempt list List of remote host wildcards from which
+login session accounting is exempted.
+.It "idletime time Maximum idle time before logout.
+.It "minpasswordlen number 6 The minimum length a local
+password may be.
+.It "mixpasswordcase bool true Whether
+.Xr passwd 1
+will warn the user if an all lower case password is entered.
+.It "monthtime time Maximum login time per month.
+.It "passwordtime time Used by
+.Xr passwd 1
+to set next password expiry date.
+.It "refreshtime time New time allowed on account refresh.
+.It "refreshperiod str How often account time is refreshed.
+.It "sessiontime time Maximum login time per session.
+.It "sessionlimit number Maximum number of concurrent
+login sessions on ttys in any group.
+.It "ttys.accounted list List of ttys and ttygroups for which
+login accounting is active.
+.It "ttys.exempt list List of ttys and ttygroups for which login accounting
+is exempt.
+.It "warntime time Advance notice for pending out-of-time.
+.It "weektime time Maximum login time per week.
+.El
+.Pp
+The
+.Em ttys.accounted
+and
+.Em ttys.exempt
+fields operate in a similar manner to
+.Em ttys.allow
+and
+.Em ttys.deny
+as explained
+above.
+Similarly with the
+.Em host.accounted
+and
+.Em host.exempt
+lists.
+.Sh SEE ALSO
+.Xr cap_mkdb 1 ,
+.Xr login 1 ,
+.Xr chroot 2 ,
+.Xr getcap 3 ,
+.Xr getttyent 3 ,
+.Xr login_cap 3 ,
+.Xr login_class 3 ,
+.Xr pam 3 ,
+.Xr passwd 5 ,
+.Xr ttys 5 ,
+.Xr ftpd 8 ,
+.Xr pam_passwdqc 8
diff --git a/lib/libutil/login_auth.3 b/lib/libutil/login_auth.3
new file mode 100644
index 0000000..3750bd6
--- /dev/null
+++ b/lib/libutil/login_auth.3
@@ -0,0 +1,72 @@
+.\" Copyright (c) 1995 David Nugent <davidn@blaze.net.au>
+.\" 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
+.\" David Nugent.
+.\" 5. Modifications may be freely made to this file providing the above
+.\" conditions are met.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd December 29, 1996
+.Os
+.Dt LOGIN_AUTH 3
+.Sh NAME
+.\" .Nm authenticate
+.\" .Nm auth_script
+.\" .Nm auth_env
+.\" .Nm auth_scan
+.\" .Nm auth_rmfiles
+.Nm auth_checknologin ,
+.Nm auth_cat
+.\" .Nm auth_ttyok
+.\" .Nm auth_hostok
+.\" .Nm auth_timesok
+.Nd "authentication style support library for login class capabilities database"
+.Sh LIBRARY
+.Lb libutil
+.Sh SYNOPSIS
+.In sys/types.h
+.In login_cap.h
+.\" .Ft int
+.\". Fn authenticate "const char *name" "const char *classname" "const char *style" "const char *service"
+.\" .Ft int
+.\" .Fn auth_script "const char * path" ...
+.\" .Ft void
+.\" .Fn auth_env "void"
+.\" .Ft int
+.\" .Fn auth_scan "int ok"
+.\" .Ft void
+.\" .Fn auth_rmfiles "void"
+.Ft void
+.Fn auth_checknologin "login_cap_t *lc"
+.Ft int
+.Fn auth_cat "const char *file"
+.\" .Ft int
+.\" .Fn auth_ttyok "login_cap_t *lc" "const char *tty"
+.\" .Ft int
+.\" .Fn auth_hostok "login_cap_t *lc" "const char *hostname" "char const *ip"
+.\" .Ft int
+.\" .Fn auth_timesok "login_cap_t *lc" "time_t now"
+.Sh DESCRIPTION
+This set of functions support the login class authorisation style interface provided
+by
+.Xr login.conf 5 .
+.\" .Sh RETURN VALUES
+.Sh SEE ALSO
+.Xr getcap 3 ,
+.Xr login_cap 3 ,
+.Xr login_class 3 ,
+.Xr login.conf 5 ,
+.Xr termcap 5
diff --git a/lib/libutil/login_auth.c b/lib/libutil/login_auth.c
new file mode 100644
index 0000000..ce9a2e4
--- /dev/null
+++ b/lib/libutil/login_auth.c
@@ -0,0 +1,108 @@
+/*-
+ * Copyright (c) 1996 by
+ * Sean Eric Fagan <sef@kithrup.com>
+ * David Nugent <davidn@blaze.net.au>
+ * All rights reserved.
+ *
+ * Portions copyright (c) 1995,1997 by
+ * Berkeley Software Design, Inc.
+ * 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 authors.
+ * 5. Modifications may be freely made to this file providing the above
+ * conditions are met.
+ *
+ * Low-level routines relating to the user capabilities database
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libutil.h>
+#include <limits.h>
+#include <login_cap.h>
+#include <paths.h>
+#include <pwd.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+
+/*
+ * auth_checknologin()
+ * Checks for the existance of a nologin file in the login_cap
+ * capability <lc>. If there isn't one specified, then it checks
+ * to see if this class should just ignore nologin files. Lastly,
+ * it tries to print out the default nologin file, and, if such
+ * exists, it exits.
+ */
+
+void
+auth_checknologin(login_cap_t *lc)
+{
+ const char *file;
+
+ /* Do we ignore a nologin file? */
+ if (login_getcapbool(lc, "ignorenologin", 0))
+ return;
+
+ /* Note that <file> will be "" if there is no nologin capability */
+ if ((file = login_getcapstr(lc, "nologin", "", NULL)) == NULL)
+ exit(1);
+
+ /*
+ * *file is true IFF there was a "nologin" capability
+ * Note that auth_cat() returns 1 only if the specified
+ * file exists, and is readable. E.g., /.nologin exists.
+ */
+ if ((*file && auth_cat(file)) || auth_cat(_PATH_NOLOGIN))
+ exit(1);
+}
+
+
+/*
+ * auth_cat()
+ * Checks for the readability of <file>; if it can be opened for
+ * reading, it prints it out to stdout, and then exits. Otherwise,
+ * it returns 0 (meaning no nologin file).
+ */
+
+int
+auth_cat(const char *file)
+{
+ int fd, count;
+ char buf[BUFSIZ];
+
+ if ((fd = open(file, O_RDONLY)) < 0)
+ return 0;
+ while ((count = read(fd, buf, sizeof(buf))) > 0)
+ (void)write(fileno(stdout), buf, count);
+ close(fd);
+ sleep(5); /* wait an arbitrary time to drain */
+ return 1;
+}
diff --git a/lib/libutil/login_cap.3 b/lib/libutil/login_cap.3
new file mode 100644
index 0000000..a533421
--- /dev/null
+++ b/lib/libutil/login_cap.3
@@ -0,0 +1,442 @@
+.\" Copyright (c) 1995 David Nugent <davidn@blaze.net.au>
+.\" 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
+.\" David Nugent.
+.\" 5. Modifications may be freely made to this file providing the above
+.\" conditions are met.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd December 27, 1996
+.Os
+.Dt LOGIN_CAP 3
+.Sh NAME
+.Nm login_close ,
+.Nm login_getcapbool ,
+.Nm login_getcaplist ,
+.Nm login_getcapnum ,
+.Nm login_getcapstr ,
+.Nm login_getcapsize ,
+.Nm login_getcaptime ,
+.Nm login_getclass ,
+.Nm login_getclassbyname ,
+.Nm login_getpwclass ,
+.Nm login_getstyle ,
+.Nm login_getuserclass ,
+.Nm login_setcryptfmt
+.Nd "functions for accessing the login class capabilities database"
+.Sh LIBRARY
+.Lb libutil
+.Sh SYNOPSIS
+.In sys/types.h
+.In login_cap.h
+.Ft void
+.Fn login_close "login_cap_t *lc"
+.Ft login_cap_t *
+.Fn login_getclassbyname "const char *nam" "const struct passwd *pwd"
+.Ft login_cap_t *
+.Fn login_getclass "const char *nam"
+.Ft login_cap_t *
+.Fn login_getpwclass "const struct passwd *pwd"
+.Ft login_cap_t *
+.Fn login_getuserclass "const struct passwd *pwd"
+.Ft "const char *"
+.Fn login_getcapstr "login_cap_t *lc" "const char *cap" "const char *def" "const char *error"
+.Ft "const char **"
+.Fn login_getcaplist "login_cap_t *lc" "const char *cap" "const char *chars"
+.Ft "const char *"
+.Fn login_getpath "login_cap_t *lc" "const char *cap" "const char *error"
+.Ft rlim_t
+.Fn login_getcaptime "login_cap_t *lc" "const char *cap" "rlim_t def" "rlim_t error"
+.Ft rlim_t
+.Fn login_getcapnum "login_cap_t *lc" "const char *cap" "rlim_t def" "rlim_t error"
+.Ft rlim_t
+.Fn login_getcapsize "login_cap_t *lc" "const char *cap" "rlim_t def" "rlim_t error"
+.Ft int
+.Fn login_getcapbool "login_cap_t *lc" "const char *cap" "int def"
+.Ft "const char *"
+.Fn login_getstyle "login_cap_t *lc" "const char *style" "const char *auth"
+.Ft const char *
+.Fn login_setcryptfmt "login_cap_t *lc" "const char *def" "const char *error"
+.Sh DESCRIPTION
+These functions represent a programming interface to the login
+classes database provided in
+.Xr login.conf 5 .
+This database contains capabilities, attributes and default environment
+and accounting settings for users and programs running as specific users,
+as determined by the login class field within entries in
+.Pa /etc/master.passwd .
+.Pp
+Entries in
+.Xr login.conf 5
+consist of colon
+.Ql \&:
+separated fields, the first field in each record being one or more
+identifiers for the record (which must be unique for the entire database),
+each separated by a '|', and may optionally include a description as
+the last 'name'.
+Remaining fields in the record consist of keyword/data pairs.
+Long lines may be continued with a backslash within empty entries,
+with the second and subsequent lines optionally indented for readability.
+This is similar to the format used in
+.Xr termcap 5 ,
+except that keywords are not limited to two significant characters,
+and are usually longer for improved readability.
+As with termcap entries, multiple records can be linked together
+(one record including another) using a field containing tc=<recordid>.
+The result is that the entire record referenced by <recordid> replaces
+the tc= field at the point at which it occurs.
+See
+.Xr getcap 3
+for further details on the format and use of a capabilities database.
+.Pp
+The
+.Nm login_cap
+interface provides a convenient means of retrieving login class
+records with all tc= references expanded.
+A program will typically call one of
+.Fn login_getclass ,
+.Fn login_getpwclass ,
+.Fn login_getuserclass
+or
+.Fn login_getclassbyname
+according to its requirements.
+Each of these functions returns a login capabilities structure,
+.Ft login_cap_t ,
+which may subsequently be used to interrogate the database for
+specific values using the rest of the API.
+Once the login_cap_t is of no further use, the
+.Fn login_close
+function should be called to free all resources used.
+.Pp
+The structure of login_cap_t is defined in login_cap.h, as:
+.Bd -literal -offset indent
+typedef struct {
+ char *lc_class;
+ char *lc_cap;
+ char *lc_style;
+} login_cap_t;
+.Ed
+.Pp
+The
+.Ar lc_class
+member contains a pointer to the name of the login class
+retrieved.
+This may not necessarily be the same as the one requested,
+either directly via
+.Fn login_getclassbyname ,
+indirectly via a user's login record using
+.Fn login_getpwclass ,
+by class name using
+.Fn login_getclass ,
+or
+.Fn login_getuserclass .
+If the referenced user has no login class specified in
+.Pa /etc/master.passwd ,
+the class name is NULL or an empty string.
+If the class
+specified does not exist in the database, each of these
+functions will search for a record with an id of "default",
+with that name returned in the
+.Ar lc_class
+field.
+In addition, if the referenced user has a UID of 0 (normally,
+"root", although the user name is not considered) then
+.Fn login_getpwclass
+will search for a record with an id of "root" before it searches
+for the record with the id of "default".
+.Pp
+The
+.Ar lc_cap
+field is used internally by the library to contain the
+expanded login capabilities record.
+Programs with unusual requirements may wish to use this
+with the lower-level
+.Fn getcap
+style functions to access the record directly.
+.Pp
+The
+.Ar lc_style
+field is set by the
+.Fn login_getstyle
+function to the authorisation style, according to the requirements
+of the program handling a login itself.
+.Pp
+As noted above, the
+.Fn login_get*class
+functions return a login_cap_t object which is used to access
+the matching or default record in the capabilities database.
+The
+.Fn login_getclassbyname
+function accepts two arguments: the first one is the record identifier of the
+record to be retrieved, the second is an optional pointer to a
+.Li passwd
+structure.
+If the first
+.Ar name
+argument is NULL, an empty string, or a class that does not exist
+in the supplemental or system login class database, then the system
+.Em default
+record is returned instead.
+If the second
+.Ar pwd
+parameter is NULL, then only the system login class database is
+used.
+However,
+if the
+.Ar pwd
+parameter and the value of
+.Ar pwd->pw_dir
+are both not NULL, then the directory contained in
+.Ar pwd->pw_dir
+is searched for
+a login database file called ".login_conf", and capability records
+contained within it may override the system defaults.
+This scheme allows users to override some login settings from
+those in the system login class database by creating class records
+for their own private class with a record id of `me'.
+In the context of a
+.Em login ,
+it should be noted that some options cannot by overridden by
+users for two reasons; many options, such as resource settings
+and default process priorities, require root privileges
+in order to take effect, and other fields in the user's file are
+not be consulted at all during the early phases of login for
+security or administrative reasons.
+See
+.Xr login.conf 5
+for more information on which settings a user is able to override.
+Typically, these are limited purely to the user's default login
+environment which might otherwise have been overridden in shell
+startup scripts in any case.
+The user's
+.Pa .login_conf
+merely provides a convenient way for a user to set up their preferred
+login environment before the shell is invoked on login.
+Note that access to the
+.Pa /etc/login.conf
+and
+.Pa .login_conf
+files will only be performed subject to the security checks documented in
+.Xr _secure_path 3
+for the uids 0 and
+.Ar pwd->pw_uid
+respectively.
+.Pp
+If the specified record is NULL, empty or does not exist, and the
+system has no "default" record available to fall back to, there is a
+memory allocation error or for some reason
+.Xr cgetent 3
+is unable to access the login capabilities database, this function
+returns NULL.
+.Pp
+The functions
+.Fn login_getpwclass ,
+.Fn login_getclass
+and
+.Fn login_getuserclass
+retrieve the applicable login class record for the user's passwd
+entry or class name by calling
+.Fn login_getclassbyname .
+On failure, NULL is returned.
+The difference between these functions is that
+.Fn login_getuserclass
+includes the user's overriding
+.Pa .login_conf
+that exists in the user's home directory, and
+.Fn login_getpwclass
+and
+.Fn login_getclass
+restrict lookup only to the system login class database in
+.Pa /etc/login.conf .
+As explained earlier,
+.Fn login_getpwclass
+only differs from
+.Fn login_getclass
+in that it allows the default class for user 'root' as "root"
+if none has been specified in the password database.
+Otherwise, if the passwd pointer is NULL, or the user record
+has no login class, then the system "default" entry is retrieved.
+.Pp
+Once a program no longer wishes to use a login_cap_t object,
+.Fn login_close
+may be called to free all resources used by the login class.
+The
+.Fn login_close
+function may be passed a NULL pointer with no harmful side-effects.
+.Pp
+The remaining functions may be used to retrieve individual
+capability records.
+Each function takes a login_cap_t object as its first parameter,
+a capability tag as the second, and remaining parameters being
+default and error values that are returned if the capability is
+not found.
+The type of the additional parameters passed and returned depend
+on the
+.Em type
+of capability each deals with, be it a simple string, a list,
+a time value, a file or memory size value, a path (consisting of
+a colon-separated list of directories) or a boolean flag.
+The manpage for
+.Xr login.conf 5
+deals in specific tags and their type.
+.Pp
+Note that with all functions in this group, you should not call
+.Xr free 3
+on any pointers returned.
+Memory allocated during retrieval or processing of capability
+tags is automatically reused by subsequent calls to functions
+in this group, or deallocated on calling
+.Fn login_close .
+.Bl -tag -width "login_getcaplist()"
+.It Fn login_getcapstr
+This function returns a simple string capability.
+If the string is not found, then the value in
+.Ar def
+is returned as the default value, or if an error
+occurs, the value in the
+.Ar error
+parameter is returned.
+.It Fn login_getcaplist
+This function returns the value corresponding to the named
+capability tag as a list of values in a NULL terminated
+array.
+Within the login class database, some tags are of type
+.Em list ,
+which consist of one or more comma- or space separated
+values.
+Usually, this function is not called directly from an
+application, but is used indirectly via
+.Fn login_getstyle .
+.It Fn login_getpath
+This function returns a list of directories separated by colons
+.Ql \&: .
+Capability tags for which this function is called consist of a list of
+directories separated by spaces.
+.It Fn login_getcaptime
+This function returns a
+.Em time value
+associated with a particular capability tag with the value expressed
+in seconds (the default), minutes, hours, days, weeks or (365 day)
+years or any combination of these.
+A suffix determines the units used: S for seconds, M for minutes,
+H for hours, D for days, W for weeks and Y for 365 day years.
+Case of the units suffix is ignored.
+.Pp
+Time values are normally used for setting resource, accounting and
+session limits.
+If supported by the operating system and compiler (which is true of
+.Fx ) ,
+the value returned is a quad (long long), of type
+.Em rlim_t .
+A value "inf" or "infinity" may be used to express an infinite
+value, in which case RLIM_INFINITY is returned.
+.It Fn login_getcapnum
+This function returns a numeric value for a tag, expressed either as
+tag=<value> or the standard
+.Fn cgetnum
+format tag#<value>.
+The first format should be used in preference to the second, the
+second format is provided for compatibility and consistency with the
+.Xr getcap 3
+database format where numeric types use the
+.Ql \&#
+as the delimiter for numeric values.
+If in the first format, then the value given may be "inf" or
+"infinity" which results in a return value of RLIM_INFINITY.
+If the given capability tag cannot be found, the
+.Ar def
+parameter is returned, and if an error occurs, the
+.Ar error
+parameter is returned.
+.It Fn login_getcapsize
+.Fn login_getcapsize
+returns a value representing a size (typically, file or memory)
+which may be expressed as bytes (the default), 512 byte blocks,
+kilobytes, megabytes, gigabytes, and on systems that support the
+.Ar long long
+type, terabytes.
+The suffix used determines the units, and multiple values and
+units may be used in combination (e.g.\& 1m500k = 1.5 megabytes).
+A value with no suffix is interpreted as bytes, B as 512-byte
+blocks, K as kilobytes, M as megabytes, G as gigabytes and T as
+terabytes.
+Case is ignored.
+The error value is returned if there is a login capabilities database
+error, if an invalid suffix is used, or if a numeric value cannot be
+interpreted.
+.It Fn login_getcapbool
+This function returns a boolean value tied to a particular flag.
+It returns 0 if the given capability tag is not present or is
+negated by the presence of a "tag@" (See
+.Xr getcap 3
+for more information on boolean flags), and returns 1 if the tag
+is found.
+.It Fn login_getstyle
+This function is used by the login authorisation system to determine
+the style of login available in a particular case.
+The function accepts three parameters, the login_cap entry itself and
+two optional parameters, and authorisation type 'auth' and 'style', and
+applies these to determine the authorisation style that best suites
+these rules.
+.Bl -bullet
+.It
+If 'auth' is neither NULL nor an empty string, look for a tag of type
+"auth-<auth>" in the capability record.
+If not present, then look for the default tag "auth=".
+.It
+If no valid authorisation list was found from the previous step, then
+default to "passwd" as the authorisation list.
+.It
+If 'style' is not NULL or empty, look for it in the list of authorisation
+methods found from the previous step.
+If 'style' is NULL or an empty string, then default to "passwd"
+authorisation.
+.It
+If 'style' is found in the chosen list of authorisation methods, then
+return that, otherwise return NULL.
+.El
+.Pp
+This scheme allows the administrator to determine the types of
+authorisation methods accepted by the system, depending on the
+means by which the access occurs.
+For example, the administrator may require skey or kerberos as
+the authentication method used for access to the system via the
+network, and standard methods via direct dialup or console
+logins, significantly reducing the risk of password discovery
+by "snooping" network packets.
+.It Fn login_setcryptfmt
+The
+.Fn login_setcryptfmt
+function is used to set the
+.Xr crypt 3
+format using the
+.Ql passwd_format
+configuration entry.
+If no entry is found,
+.Fa def
+is taken to be used as the fallback.
+If calling
+.Xr crypt_set_format 3
+on the specifier fails,
+.Fa error
+is returned to indicate this.
+.El
+.Sh SEE ALSO
+.Xr crypt 3 ,
+.Xr getcap 3 ,
+.Xr login_class 3 ,
+.Xr login.conf 5 ,
+.Xr termcap 5
diff --git a/lib/libutil/login_cap.c b/lib/libutil/login_cap.c
new file mode 100644
index 0000000..6d965e3
--- /dev/null
+++ b/lib/libutil/login_cap.c
@@ -0,0 +1,808 @@
+/*-
+ * Copyright (c) 1996 by
+ * Sean Eric Fagan <sef@kithrup.com>
+ * David Nugent <davidn@blaze.net.au>
+ * All rights reserved.
+ *
+ * Portions copyright (c) 1995,1997
+ * Berkeley Software Design, Inc.
+ * 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 authors.
+ * 5. Modifications may be freely made to this file providing the above
+ * conditions are met.
+ *
+ * Low-level routines relating to the user capabilities database
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/param.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libutil.h>
+#include <login_cap.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+/*
+ * allocstr()
+ * Manage a single static pointer for handling a local char* buffer,
+ * resizing as necessary to contain the string.
+ *
+ * allocarray()
+ * Manage a static array for handling a group of strings, resizing
+ * when necessary.
+ */
+
+static int lc_object_count = 0;
+
+static size_t internal_stringsz = 0;
+static char * internal_string = NULL;
+static size_t internal_arraysz = 0;
+static const char ** internal_array = NULL;
+
+static char *
+allocstr(const char *str)
+{
+ char *p;
+
+ size_t sz = strlen(str) + 1; /* realloc() only if necessary */
+ if (sz <= internal_stringsz)
+ p = strcpy(internal_string, str);
+ else if ((p = realloc(internal_string, sz)) != NULL) {
+ internal_stringsz = sz;
+ internal_string = strcpy(p, str);
+ }
+ return p;
+}
+
+
+static const char **
+allocarray(size_t sz)
+{
+ static const char **p;
+
+ if (sz <= internal_arraysz)
+ p = internal_array;
+ else if ((p = realloc(internal_array, sz * sizeof(char*))) != NULL) {
+ internal_arraysz = sz;
+ internal_array = p;
+ }
+ return p;
+}
+
+
+/*
+ * arrayize()
+ * Turn a simple string <str> separated by any of
+ * the set of <chars> into an array. The last element
+ * of the array will be NULL, as is proper.
+ * Free using freearraystr()
+ */
+
+static const char **
+arrayize(const char *str, const char *chars, int *size)
+{
+ int i;
+ char *ptr;
+ const char *cptr;
+ const char **res = NULL;
+
+ /* count the sub-strings */
+ for (i = 0, cptr = str; *cptr; i++) {
+ int count = strcspn(cptr, chars);
+ cptr += count;
+ if (*cptr)
+ ++cptr;
+ }
+
+ /* alloc the array */
+ if ((ptr = allocstr(str)) != NULL) {
+ if ((res = allocarray(++i)) == NULL)
+ free((void *)(uintptr_t)(const void *)str);
+ else {
+ /* now split the string */
+ i = 0;
+ while (*ptr) {
+ int count = strcspn(ptr, chars);
+ res[i++] = ptr;
+ ptr += count;
+ if (*ptr)
+ *ptr++ = '\0';
+ }
+ res[i] = NULL;
+ }
+ }
+
+ if (size)
+ *size = i;
+
+ return res;
+}
+
+
+/*
+ * login_close()
+ * Frees up all resources relating to a login class
+ *
+ */
+
+void
+login_close(login_cap_t * lc)
+{
+ if (lc) {
+ free(lc->lc_style);
+ free(lc->lc_class);
+ free(lc->lc_cap);
+ free(lc);
+ if (--lc_object_count == 0) {
+ free(internal_string);
+ free(internal_array);
+ internal_array = NULL;
+ internal_arraysz = 0;
+ internal_string = NULL;
+ internal_stringsz = 0;
+ cgetclose();
+ }
+ }
+}
+
+
+/*
+ * login_getclassbyname() get the login class by its name.
+ * If the name given is NULL or empty, the default class
+ * LOGIN_DEFCLASS (ie. "default") is fetched. If the
+ * 'pwd' argument is non-NULL and contains an non-NULL
+ * dir entry, then the file _FILE_LOGIN_CONF is picked
+ * up from that directory and used before the system
+ * login database.
+ * Return a filled-out login_cap_t structure, including
+ * class name, and the capability record buffer.
+ */
+
+login_cap_t *
+login_getclassbyname(char const *name, const struct passwd *pwd)
+{
+ login_cap_t *lc;
+
+ if ((lc = malloc(sizeof(login_cap_t))) != NULL) {
+ int r, me, i = 0;
+ uid_t euid = 0;
+ gid_t egid = 0;
+ const char *msg = NULL;
+ const char *dir;
+ char userpath[MAXPATHLEN];
+
+ static char *login_dbarray[] = { NULL, NULL, NULL };
+
+ me = (name != NULL && strcmp(name, LOGIN_MECLASS) == 0);
+ dir = (!me || pwd == NULL) ? NULL : pwd->pw_dir;
+ /*
+ * Switch to user mode before checking/reading its ~/.login_conf
+ * - some NFSes have root read access disabled.
+ *
+ * XXX: This fails to configure additional groups.
+ */
+ if (dir) {
+ euid = geteuid();
+ egid = getegid();
+ (void)setegid(pwd->pw_gid);
+ (void)seteuid(pwd->pw_uid);
+ }
+
+ if (dir && snprintf(userpath, MAXPATHLEN, "%s/%s", dir,
+ _FILE_LOGIN_CONF) < MAXPATHLEN) {
+ login_dbarray[i] = userpath;
+ if (_secure_path(userpath, pwd->pw_uid, pwd->pw_gid) != -1)
+ i++; /* only use 'secure' data */
+ }
+ if (_secure_path(_PATH_LOGIN_CONF, 0, 0) != -1)
+ login_dbarray[i++] = _PATH_LOGIN_CONF;
+ login_dbarray[i] = NULL;
+
+ memset(lc, 0, sizeof(login_cap_t));
+ lc->lc_cap = lc->lc_class = lc->lc_style = NULL;
+
+ if (name == NULL || *name == '\0')
+ name = LOGIN_DEFCLASS;
+
+ switch (cgetent(&lc->lc_cap, login_dbarray, name)) {
+ case -1: /* Failed, entry does not exist */
+ if (me)
+ break; /* Don't retry default on 'me' */
+ if (i == 0)
+ r = -1;
+ else if ((r = open(login_dbarray[0], O_RDONLY)) >= 0)
+ close(r);
+ /*
+ * If there's at least one login class database,
+ * and we aren't searching for a default class
+ * then complain about a non-existent class.
+ */
+ if (r >= 0 || strcmp(name, LOGIN_DEFCLASS) != 0)
+ syslog(LOG_ERR, "login_getclass: unknown class '%s'", name);
+ /* fall-back to default class */
+ name = LOGIN_DEFCLASS;
+ msg = "%s: no default/fallback class '%s'";
+ if (cgetent(&lc->lc_cap, login_dbarray, name) != 0 && r >= 0)
+ break;
+ /* FALLTHROUGH - just return system defaults */
+ case 0: /* success! */
+ if ((lc->lc_class = strdup(name)) != NULL) {
+ if (dir) {
+ (void)seteuid(euid);
+ (void)setegid(egid);
+ }
+ ++lc_object_count;
+ return lc;
+ }
+ msg = "%s: strdup: %m";
+ break;
+ case -2:
+ msg = "%s: retrieving class information: %m";
+ break;
+ case -3:
+ msg = "%s: 'tc=' reference loop '%s'";
+ break;
+ case 1:
+ msg = "couldn't resolve 'tc=' reference in '%s'";
+ break;
+ default:
+ msg = "%s: unexpected cgetent() error '%s': %m";
+ break;
+ }
+ if (dir) {
+ (void)seteuid(euid);
+ (void)setegid(egid);
+ }
+ if (msg != NULL)
+ syslog(LOG_ERR, msg, "login_getclass", name);
+ free(lc);
+ }
+
+ return NULL;
+}
+
+
+
+/*
+ * login_getclass()
+ * Get the login class for the system (only) login class database.
+ * Return a filled-out login_cap_t structure, including
+ * class name, and the capability record buffer.
+ */
+
+login_cap_t *
+login_getclass(const char *cls)
+{
+ return login_getclassbyname(cls, NULL);
+}
+
+
+/*
+ * login_getclass()
+ * Get the login class for a given password entry from
+ * the system (only) login class database.
+ * If the password entry's class field is not set, or
+ * the class specified does not exist, then use the
+ * default of LOGIN_DEFCLASS (ie. "default").
+ * Return a filled-out login_cap_t structure, including
+ * class name, and the capability record buffer.
+ */
+
+login_cap_t *
+login_getpwclass(const struct passwd *pwd)
+{
+ const char *cls = NULL;
+
+ if (pwd != NULL) {
+ cls = pwd->pw_class;
+ if (cls == NULL || *cls == '\0')
+ cls = (pwd->pw_uid == 0) ? LOGIN_DEFROOTCLASS : LOGIN_DEFCLASS;
+ }
+ return login_getclassbyname(cls, pwd);
+}
+
+
+/*
+ * login_getuserclass()
+ * Get the login class for a given password entry, allowing user
+ * overrides via ~/.login_conf.
+ */
+
+login_cap_t *
+login_getuserclass(const struct passwd *pwd)
+{
+ return login_getclassbyname(LOGIN_MECLASS, pwd);
+}
+
+
+
+/*
+ * login_getcapstr()
+ * Given a login_cap entry, and a capability name, return the
+ * value defined for that capability, a default if not found, or
+ * an error string on error.
+ */
+
+const char *
+login_getcapstr(login_cap_t *lc, const char *cap, const char *def, const char *error)
+{
+ char *res;
+ int ret;
+
+ if (lc == NULL || cap == NULL || lc->lc_cap == NULL || *cap == '\0')
+ return def;
+
+ if ((ret = cgetstr(lc->lc_cap, cap, &res)) == -1)
+ return def;
+ return (ret >= 0) ? res : error;
+}
+
+
+/*
+ * login_getcaplist()
+ * Given a login_cap entry, and a capability name, return the
+ * value defined for that capability split into an array of
+ * strings.
+ */
+
+const char **
+login_getcaplist(login_cap_t *lc, const char *cap, const char *chars)
+{
+ const char *lstring;
+
+ if (chars == NULL)
+ chars = ", \t";
+ if ((lstring = login_getcapstr(lc, cap, NULL, NULL)) != NULL)
+ return arrayize(lstring, chars, NULL);
+ return NULL;
+}
+
+
+/*
+ * login_getpath()
+ * From the login_cap_t <lc>, get the capability <cap> which is
+ * formatted as either a space or comma delimited list of paths
+ * and append them all into a string and separate by semicolons.
+ * If there is an error of any kind, return <error>.
+ */
+
+const char *
+login_getpath(login_cap_t *lc, const char *cap, const char *error)
+{
+ const char *str;
+ char *ptr;
+ int count;
+
+ str = login_getcapstr(lc, cap, NULL, NULL);
+ if (str == NULL)
+ return error;
+ ptr = __DECONST(char *, str); /* XXXX Yes, very dodgy */
+ while (*ptr) {
+ count = strcspn(ptr, ", \t");
+ ptr += count;
+ if (*ptr)
+ *ptr++ = ':';
+ }
+ return str;
+}
+
+
+static int
+isinfinite(const char *s)
+{
+ static const char *infs[] = {
+ "infinity",
+ "inf",
+ "unlimited",
+ "unlimit",
+ "-1",
+ NULL
+ };
+ const char **i = &infs[0];
+
+ while (*i != NULL) {
+ if (strcasecmp(s, *i) == 0)
+ return 1;
+ ++i;
+ }
+ return 0;
+}
+
+
+static u_quad_t
+rmultiply(u_quad_t n1, u_quad_t n2)
+{
+ u_quad_t m, r;
+ int b1, b2;
+
+ static int bpw = 0;
+
+ /* Handle simple cases */
+ if (n1 == 0 || n2 == 0)
+ return 0;
+ if (n1 == 1)
+ return n2;
+ if (n2 == 1)
+ return n1;
+
+ /*
+ * sizeof() returns number of bytes needed for storage.
+ * This may be different from the actual number of useful bits.
+ */
+ if (!bpw) {
+ bpw = sizeof(u_quad_t) * 8;
+ while (((u_quad_t)1 << (bpw-1)) == 0)
+ --bpw;
+ }
+
+ /*
+ * First check the magnitude of each number. If the sum of the
+ * magnatude is way to high, reject the number. (If this test
+ * is not done then the first multiply below may overflow.)
+ */
+ for (b1 = bpw; (((u_quad_t)1 << (b1-1)) & n1) == 0; --b1)
+ ;
+ for (b2 = bpw; (((u_quad_t)1 << (b2-1)) & n2) == 0; --b2)
+ ;
+ if (b1 + b2 - 2 > bpw) {
+ errno = ERANGE;
+ return (UQUAD_MAX);
+ }
+
+ /*
+ * Decompose the multiplication to be:
+ * h1 = n1 & ~1
+ * h2 = n2 & ~1
+ * l1 = n1 & 1
+ * l2 = n2 & 1
+ * (h1 + l1) * (h2 + l2)
+ * (h1 * h2) + (h1 * l2) + (l1 * h2) + (l1 * l2)
+ *
+ * Since h1 && h2 do not have the low bit set, we can then say:
+ *
+ * (h1>>1 * h2>>1 * 4) + ...
+ *
+ * So if (h1>>1 * h2>>1) > (1<<(bpw - 2)) then the result will
+ * overflow.
+ *
+ * Finally, if MAX - ((h1 * l2) + (l1 * h2) + (l1 * l2)) < (h1*h2)
+ * then adding in residual amout will cause an overflow.
+ */
+
+ m = (n1 >> 1) * (n2 >> 1);
+ if (m >= ((u_quad_t)1 << (bpw-2))) {
+ errno = ERANGE;
+ return (UQUAD_MAX);
+ }
+ m *= 4;
+
+ r = (n1 & n2 & 1)
+ + (n2 & 1) * (n1 & ~(u_quad_t)1)
+ + (n1 & 1) * (n2 & ~(u_quad_t)1);
+
+ if ((u_quad_t)(m + r) < m) {
+ errno = ERANGE;
+ return (UQUAD_MAX);
+ }
+ m += r;
+
+ return (m);
+}
+
+
+/*
+ * login_getcaptime()
+ * From the login_cap_t <lc>, get the capability <cap>, which is
+ * formatted as a time (e.g., "<cap>=10h3m2s"). If <cap> is not
+ * present in <lc>, return <def>; if there is an error of some kind,
+ * return <error>.
+ */
+
+rlim_t
+login_getcaptime(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error)
+{
+ char *res, *ep, *oval;
+ int r;
+ rlim_t tot;
+
+ errno = 0;
+ if (lc == NULL || lc->lc_cap == NULL)
+ return def;
+
+ /*
+ * Look for <cap> in lc_cap.
+ * If it's not there (-1), return <def>.
+ * If there's an error, return <error>.
+ */
+
+ if ((r = cgetstr(lc->lc_cap, cap, &res)) == -1)
+ return def;
+ else if (r < 0) {
+ errno = ERANGE;
+ return error;
+ }
+
+ /* "inf" and "infinity" are special cases */
+ if (isinfinite(res))
+ return RLIM_INFINITY;
+
+ /*
+ * Now go through the string, turning something like 1h2m3s into
+ * an integral value. Whee.
+ */
+
+ errno = 0;
+ tot = 0;
+ oval = res;
+ while (*res) {
+ rlim_t tim = strtoq(res, &ep, 0);
+ rlim_t mult = 1;
+
+ if (ep == NULL || ep == res || errno != 0) {
+ invalid:
+ syslog(LOG_WARNING, "login_getcaptime: class '%s' bad value %s=%s",
+ lc->lc_class, cap, oval);
+ errno = ERANGE;
+ return error;
+ }
+ /* Look for suffixes */
+ switch (*ep++) {
+ case 0:
+ ep--;
+ break; /* end of string */
+ case 's': case 'S': /* seconds */
+ break;
+ case 'm': case 'M': /* minutes */
+ mult = 60;
+ break;
+ case 'h': case 'H': /* hours */
+ mult = 60L * 60L;
+ break;
+ case 'd': case 'D': /* days */
+ mult = 60L * 60L * 24L;
+ break;
+ case 'w': case 'W': /* weeks */
+ mult = 60L * 60L * 24L * 7L;
+ break;
+ case 'y': case 'Y': /* 365-day years */
+ mult = 60L * 60L * 24L * 365L;
+ break;
+ default:
+ goto invalid;
+ }
+ res = ep;
+ tot += rmultiply(tim, mult);
+ if (errno)
+ goto invalid;
+ }
+
+ return tot;
+}
+
+
+/*
+ * login_getcapnum()
+ * From the login_cap_t <lc>, extract the numerical value <cap>.
+ * If it is not present, return <def> for a default, and return
+ * <error> if there is an error.
+ * Like login_getcaptime(), only it only converts to a number, not
+ * to a time; "infinity" and "inf" are 'special.'
+ */
+
+rlim_t
+login_getcapnum(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error)
+{
+ char *ep, *res;
+ int r;
+ rlim_t val;
+
+ if (lc == NULL || lc->lc_cap == NULL)
+ return def;
+
+ /*
+ * For BSDI compatibility, try for the tag=<val> first
+ */
+ if ((r = cgetstr(lc->lc_cap, cap, &res)) == -1) {
+ long lval;
+ /* string capability not present, so try for tag#<val> as numeric */
+ if ((r = cgetnum(lc->lc_cap, cap, &lval)) == -1)
+ return def; /* Not there, so return default */
+ else if (r >= 0)
+ return (rlim_t)lval;
+ }
+
+ if (r < 0) {
+ errno = ERANGE;
+ return error;
+ }
+
+ if (isinfinite(res))
+ return RLIM_INFINITY;
+
+ errno = 0;
+ val = strtoq(res, &ep, 0);
+ if (ep == NULL || ep == res || errno != 0) {
+ syslog(LOG_WARNING, "login_getcapnum: class '%s' bad value %s=%s",
+ lc->lc_class, cap, res);
+ errno = ERANGE;
+ return error;
+ }
+
+ return val;
+}
+
+
+
+/*
+ * login_getcapsize()
+ * From the login_cap_t <lc>, extract the capability <cap>, which is
+ * formatted as a size (e.g., "<cap>=10M"); it can also be "infinity".
+ * If not present, return <def>, or <error> if there is an error of
+ * some sort.
+ */
+
+rlim_t
+login_getcapsize(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error)
+{
+ char *ep, *res, *oval;
+ int r;
+ rlim_t tot;
+
+ if (lc == NULL || lc->lc_cap == NULL)
+ return def;
+
+ if ((r = cgetstr(lc->lc_cap, cap, &res)) == -1)
+ return def;
+ else if (r < 0) {
+ errno = ERANGE;
+ return error;
+ }
+
+ if (isinfinite(res))
+ return RLIM_INFINITY;
+
+ errno = 0;
+ tot = 0;
+ oval = res;
+ while (*res) {
+ rlim_t siz = strtoq(res, &ep, 0);
+ rlim_t mult = 1;
+
+ if (ep == NULL || ep == res || errno != 0) {
+ invalid:
+ syslog(LOG_WARNING, "login_getcapsize: class '%s' bad value %s=%s",
+ lc->lc_class, cap, oval);
+ errno = ERANGE;
+ return error;
+ }
+ switch (*ep++) {
+ case 0: /* end of string */
+ ep--;
+ break;
+ case 'b': case 'B': /* 512-byte blocks */
+ mult = 512;
+ break;
+ case 'k': case 'K': /* 1024-byte Kilobytes */
+ mult = 1024;
+ break;
+ case 'm': case 'M': /* 1024-k kbytes */
+ mult = 1024 * 1024;
+ break;
+ case 'g': case 'G': /* 1Gbyte */
+ mult = 1024 * 1024 * 1024;
+ break;
+ case 't': case 'T': /* 1TBte */
+ mult = 1024LL * 1024LL * 1024LL * 1024LL;
+ break;
+ default:
+ goto invalid;
+ }
+ res = ep;
+ tot += rmultiply(siz, mult);
+ if (errno)
+ goto invalid;
+ }
+
+ return tot;
+}
+
+
+/*
+ * login_getcapbool()
+ * From the login_cap_t <lc>, check for the existance of the capability
+ * of <cap>. Return <def> if <lc>->lc_cap is NULL, otherwise return
+ * the whether or not <cap> exists there.
+ */
+
+int
+login_getcapbool(login_cap_t *lc, const char *cap, int def)
+{
+ if (lc == NULL || lc->lc_cap == NULL)
+ return def;
+ return (cgetcap(lc->lc_cap, cap, ':') != NULL);
+}
+
+
+/*
+ * login_getstyle()
+ * Given a login_cap entry <lc>, and optionally a type of auth <auth>,
+ * and optionally a style <style>, find the style that best suits these
+ * rules:
+ * 1. If <auth> is non-null, look for an "auth-<auth>=" string
+ * in the capability; if not present, default to "auth=".
+ * 2. If there is no auth list found from (1), default to
+ * "passwd" as an authorization list.
+ * 3. If <style> is non-null, look for <style> in the list of
+ * authorization methods found from (2); if <style> is NULL, default
+ * to LOGIN_DEFSTYLE ("passwd").
+ * 4. If the chosen style is found in the chosen list of authorization
+ * methods, return that; otherwise, return NULL.
+ * E.g.:
+ * login_getstyle(lc, NULL, "ftp");
+ * login_getstyle(lc, "login", NULL);
+ * login_getstyle(lc, "skey", "network");
+ */
+
+const char *
+login_getstyle(login_cap_t *lc, const char *style, const char *auth)
+{
+ int i;
+ const char **authtypes = NULL;
+ char *auths= NULL;
+ char realauth[64];
+
+ static const char *defauthtypes[] = { LOGIN_DEFSTYLE, NULL };
+
+ if (auth != NULL && *auth != '\0') {
+ if (snprintf(realauth, sizeof realauth, "auth-%s", auth) < (int)sizeof(realauth))
+ authtypes = login_getcaplist(lc, realauth, NULL);
+ }
+
+ if (authtypes == NULL)
+ authtypes = login_getcaplist(lc, "auth", NULL);
+
+ if (authtypes == NULL)
+ authtypes = defauthtypes;
+
+ /*
+ * We have at least one authtype now; auths is a comma-separated
+ * (or space-separated) list of authentication types. We have to
+ * convert from this to an array of char*'s; authtypes then gets this.
+ */
+ i = 0;
+ if (style != NULL && *style != '\0') {
+ while (authtypes[i] != NULL && strcmp(style, authtypes[i]) != 0)
+ i++;
+ }
+
+ lc->lc_style = NULL;
+ if (authtypes[i] != NULL && (auths = strdup(authtypes[i])) != NULL)
+ lc->lc_style = auths;
+
+ if (lc->lc_style != NULL)
+ lc->lc_style = strdup(lc->lc_style);
+
+ return lc->lc_style;
+}
diff --git a/lib/libutil/login_cap.h b/lib/libutil/login_cap.h
new file mode 100644
index 0000000..a7cb4c6
--- /dev/null
+++ b/lib/libutil/login_cap.h
@@ -0,0 +1,158 @@
+/*-
+ * Copyright (c) 1996 by
+ * Sean Eric Fagan <sef@kithrup.com>
+ * David Nugent <davidn@blaze.net.au>
+ * 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 authors.
+ * 5. Modifications may be freely made to this file providing the above
+ * conditions are met.
+ *
+ * Low-level routines relating to the user capabilities database
+ *
+ * Was login_cap.h,v 1.9 1997/05/07 20:00:01 eivind Exp
+ * $FreeBSD$
+ */
+
+#ifndef _LOGIN_CAP_H_
+#define _LOGIN_CAP_H_
+
+#define LOGIN_DEFCLASS "default"
+#define LOGIN_DEFROOTCLASS "root"
+#define LOGIN_MECLASS "me"
+#define LOGIN_DEFSTYLE "passwd"
+#define LOGIN_DEFSERVICE "login"
+#define LOGIN_DEFUMASK 022
+#define LOGIN_DEFPRI 0
+#define _PATH_LOGIN_CONF "/etc/login.conf"
+#define _FILE_LOGIN_CONF ".login_conf"
+#define _PATH_AUTHPROG "/usr/libexec/login_"
+
+#define LOGIN_SETGROUP 0x0001 /* set group */
+#define LOGIN_SETLOGIN 0x0002 /* set login (via setlogin) */
+#define LOGIN_SETPATH 0x0004 /* set path */
+#define LOGIN_SETPRIORITY 0x0008 /* set priority */
+#define LOGIN_SETRESOURCES 0x0010 /* set resources (cputime, etc.) */
+#define LOGIN_SETUMASK 0x0020 /* set umask, obviously */
+#define LOGIN_SETUSER 0x0040 /* set user (via setuid) */
+#define LOGIN_SETENV 0x0080 /* set user environment */
+#define LOGIN_SETMAC 0x0100 /* set user default MAC label */
+#define LOGIN_SETALL 0x01ff /* set everything */
+
+#define BI_AUTH "authorize" /* accepted authentication */
+#define BI_REJECT "reject" /* rejected authentication */
+#define BI_CHALLENG "reject challenge" /* reject with a challenge */
+#define BI_SILENT "reject silent" /* reject silently */
+#define BI_REMOVE "remove" /* remove file on error */
+#define BI_ROOTOKAY "authorize root" /* root authenticated */
+#define BI_SECURE "authorize secure" /* okay on non-secure line */
+#define BI_SETENV "setenv" /* set environment variable */
+#define BI_VALUE "value" /* set local variable */
+
+#define AUTH_OKAY 0x01 /* user authenticated */
+#define AUTH_ROOTOKAY 0x02 /* root login okay */
+#define AUTH_SECURE 0x04 /* secure login */
+#define AUTH_SILENT 0x08 /* silent rejection */
+#define AUTH_CHALLENGE 0x10 /* a chellenge was given */
+
+#define AUTH_ALLOW (AUTH_OKAY | AUTH_ROOTOKAY | AUTH_SECURE)
+
+typedef struct login_cap {
+ char *lc_class;
+ char *lc_cap;
+ char *lc_style;
+} login_cap_t;
+
+typedef struct login_time {
+ u_short lt_start; /* Start time */
+ u_short lt_end; /* End time */
+#define LTM_NONE 0x00
+#define LTM_SUN 0x01
+#define LTM_MON 0x02
+#define LTM_TUE 0x04
+#define LTM_WED 0x08
+#define LTM_THU 0x10
+#define LTM_FRI 0x20
+#define LTM_SAT 0x40
+#define LTM_ANY 0x7F
+#define LTM_WK 0x3E
+#define LTM_WD 0x41
+ u_char lt_dow; /* Days of week */
+} login_time_t;
+
+#define LC_MAXTIMES 64
+
+#include <sys/cdefs.h>
+__BEGIN_DECLS
+struct passwd;
+
+void login_close(login_cap_t *);
+login_cap_t *login_getclassbyname(const char *, const struct passwd *);
+login_cap_t *login_getclass(const char *);
+login_cap_t *login_getpwclass(const struct passwd *);
+login_cap_t *login_getuserclass(const struct passwd *);
+
+const char *login_getcapstr(login_cap_t*, const char *, const char *, const char *);
+const char **login_getcaplist(login_cap_t *, const char *, const char *);
+const char *login_getstyle(login_cap_t *, const char *, const char *);
+rlim_t login_getcaptime(login_cap_t *, const char *, rlim_t, rlim_t);
+rlim_t login_getcapnum(login_cap_t *, const char *, rlim_t, rlim_t);
+rlim_t login_getcapsize(login_cap_t *, const char *, rlim_t, rlim_t);
+const char *login_getpath(login_cap_t *, const char *, const char *);
+int login_getcapbool(login_cap_t *, const char *, int);
+const char *login_setcryptfmt(login_cap_t *, const char *, const char *);
+
+int setclasscontext(const char*, unsigned int);
+int setusercontext(login_cap_t*, const struct passwd*, uid_t, unsigned int);
+void setclassresources(login_cap_t *);
+void setclassenvironment(login_cap_t *, const struct passwd *, int);
+
+/* Most of these functions are deprecated */
+int auth_approve(login_cap_t*, const char*, const char*);
+int auth_check(const char *, const char *, const char *, const char *, int *);
+void auth_env(void);
+char *auth_mkvalue(const char *n);
+int auth_response(const char *, const char *, const char *, const char *, int *, const char *, const char *);
+void auth_rmfiles(void);
+int auth_scan(int);
+int auth_script(const char*, ...);
+int auth_script_data(const char *, int, const char *, ...);
+char *auth_valud(const char *);
+int auth_setopt(const char *, const char *);
+void auth_clropts(void);
+
+void auth_checknologin(login_cap_t*);
+int auth_cat(const char*);
+
+int auth_ttyok(login_cap_t*, const char *);
+int auth_hostok(login_cap_t*, const char *, char const *);
+int auth_timeok(login_cap_t*, time_t);
+
+struct tm;
+
+login_time_t parse_lt(const char *);
+int in_ltm(const login_time_t *, struct tm *, time_t *);
+int in_ltms(const login_time_t *, struct tm *, time_t *);
+
+/* helper functions */
+
+int login_strinlist(const char **, char const *, int);
+int login_str2inlist(const char **, const char *, const char *, int);
+login_time_t * login_timelist(login_cap_t *, char const *, int *, login_time_t **);
+int login_ttyok(login_cap_t *, const char *, const char *, const char *);
+int login_hostok(login_cap_t *, const char *, const char *, const char *, const char *);
+
+__END_DECLS
+
+#endif /* _LOGIN_CAP_H_ */
diff --git a/lib/libutil/login_class.3 b/lib/libutil/login_class.3
new file mode 100644
index 0000000..8f324dd
--- /dev/null
+++ b/lib/libutil/login_class.3
@@ -0,0 +1,197 @@
+.\" Copyright (c) 1995 David Nugent <davidn@blaze.net.au>
+.\" 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
+.\" David Nugent.
+.\" 5. Modifications may be freely made to this file providing the above
+.\" conditions are met.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd December 28, 1996
+.Os
+.Dt LOGIN_CLASS 3
+.Sh NAME
+.Nm setclasscontext ,
+.Nm setclassenvironment ,
+.Nm setclassresources ,
+.Nm setusercontext
+.Nd "functions for using the login class capabilities database"
+.Sh LIBRARY
+.Lb libutil
+.Sh SYNOPSIS
+.In sys/types.h
+.In login_cap.h
+.Ft int
+.Fn setclasscontext "const char *classname" "unsigned int flags"
+.Ft int
+.Fn setusercontext "login_cap_t *lc" "const struct passwd *pwd" "uid_t uid" "unsigned int flags"
+.Ft void
+.Fn setclassresources "login_cap_t *lc"
+.Ft void
+.Fn setclassenvironment "login_cap_t *lc" "const struct passwd *pwd" "int paths"
+.Sh DESCRIPTION
+These functions provide a higher level interface to the login class
+database than those documented in
+.Xr login_cap 3 .
+These functions are used to set resource limits, environment and
+accounting settings for users on logging into the system and when
+selecting an appropriate set of environment and resource settings
+for system daemons based on login classes.
+These functions may only be called if the current process is
+running with root privileges.
+If the LOGIN_SETLOGIN flag is used this function calls
+.Xr setlogin 2 ,
+and due care must be taken as detailed in the manpage for that
+function and this affects all processes running in the same session
+and not just the current process.
+.Pp
+The
+.Fn setclasscontext
+function sets various class context values (resource limits, umask and
+process priorities) based on values for a specific named class.
+.Pp
+The
+.Fn setusercontext
+function sets class context values based on a given login_cap_t
+object and a specific passwd record (if login_cap_t is NULL),
+the current session's login, and the current process
+user and group ownership.
+Each of these actions is selectable via bit-flags passed
+in the
+.Ar flags
+parameter, which is comprised of one or more of the following:
+.Bl -tag -width LOGIN_SETRESOURCES
+.It LOGIN_SETLOGIN
+Set the login associated with the current session to the user
+specified in the passwd structure using
+.Xr setlogin 2 .
+The
+.Ar pwd
+parameter must not be NULL if this option is used.
+.It LOGIN_SETUSER
+Set ownship of the current process to the uid specified in the
+.Ar uid
+parameter using
+.Xr setuid 2 .
+.It LOGIN_SETGROUP
+Set group ownership of the current process to the group id
+specified in the passwd structure using
+.Xr setgid 2 ,
+and calls
+.Xr initgroups 3
+to set up the group access list for the current process.
+The
+.Ar pwd
+parameter must not be NULL if this option is used.
+.It LOGIN_SETRESOURCES
+Set resource limits for the current process based on values
+specified in the system login class database.
+Class capability tags used, with and without -cur (soft limit)
+or -max (hard limit) suffixes and the corresponding resource
+setting:
+.Bd -literal
+cputime RLIMIT_CPU
+filesize RLIMIT_FSIZE
+datasize RLIMIT_DATA
+stacksize RLIMIT_STACK
+coredumpsize RLIMIT_CORE
+memoryuse RLIMIT_RSS
+memorylocked RLIMIT_MEMLOCK
+maxproc RLIMIT_NPROC
+openfiles RLIMIT_NOFILE
+sbsize RLIMIT_SBSIZE
+vmemoryuse RLIMIT_VMEM
+.Ed
+.It LOGIN_SETPRIORITY
+Set the scheduling priority for the current process based on the
+value specified in the system login class database.
+Class capability tags used:
+.Bd -literal
+priority
+.Ed
+.It LOGIN_SETUMASK
+Set the umask for the current process to a value in the user or
+system login class database.
+Class capability tags used:
+.Bd -literal
+umask
+.Ed
+.It LOGIN_SETPATH
+Set the "path" and "manpath" environment variables based on values
+in the user or system login class database.
+Class capability tags used with the corresponding environment
+variables set:
+.Bd -literal
+path PATH
+manpath MANPATH
+.Ed
+.It LOGIN_SETENV
+Set various environment variables based on values in the user or
+system login class database.
+Class capability tags used with the corresponding environment
+variables set:
+.Bd -literal
+lang LANG
+charset MM_CHARSET
+timezone TZ
+term TERM
+.Ed
+.Pp
+Additional environment variables may be set using the list type
+capability "setenv=var1 val1,var2 val2..,varN valN".
+.It LOGIN_SETMAC
+Set the MAC label for the current process to the label specified
+in system login class database.
+.Pp
+.It LOGIN_SETALL
+Enables all of the above settings.
+.El
+.Pp
+Note that when setting environment variables and a valid passwd
+pointer is provided in the
+.Ar pwd
+parameter, the characters
+.Ql \&~
+and
+.Ql \&$
+are substituted for the user's home directory and login name
+respectively.
+.Pp
+The
+.Fn setclassresources
+and
+.Fn setclassenvironment
+functions are subsets of the setcontext functions above, but may
+be useful in isolation.
+.Sh RETURN VALUES
+The
+.Fn setclasscontext
+and
+.Fn setusercontext
+functions return -1 if an error occurred, or 0 on success.
+If an error occurs when attempting to set the user, login, group
+or resources, a message is reported to
+.Xr syslog 3 ,
+with LOG_ERR priority and directed to the currently active facility.
+.Sh SEE ALSO
+.Xr setgid 2 ,
+.Xr setlogin 2 ,
+.Xr setuid 2 ,
+.Xr getcap 3 ,
+.Xr initgroups 3 ,
+.Xr login_cap 3 ,
+.Xr mac_set_proc 3 ,
+.Xr login.conf 5 ,
+.Xr termcap 5
diff --git a/lib/libutil/login_class.c b/lib/libutil/login_class.c
new file mode 100644
index 0000000..3071605
--- /dev/null
+++ b/lib/libutil/login_class.c
@@ -0,0 +1,429 @@
+/*-
+ * Copyright (c) 1996 by
+ * Sean Eric Fagan <sef@kithrup.com>
+ * David Nugent <davidn@blaze.net.au>
+ * 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 authors.
+ * 5. Modifications may be freely made to this file providing the above
+ * conditions are met.
+ *
+ * High-level routines relating to use of the user capabilities database
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/mac.h>
+#include <sys/rtprio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <login_cap.h>
+#include <paths.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+
+static struct login_res {
+ const char *what;
+ rlim_t (*who)(login_cap_t *, const char *, rlim_t, rlim_t);
+ int why;
+} resources[] = {
+ { "cputime", login_getcaptime, RLIMIT_CPU },
+ { "filesize", login_getcapsize, RLIMIT_FSIZE },
+ { "datasize", login_getcapsize, RLIMIT_DATA },
+ { "stacksize", login_getcapsize, RLIMIT_STACK },
+ { "memoryuse", login_getcapsize, RLIMIT_RSS },
+ { "memorylocked", login_getcapsize, RLIMIT_MEMLOCK },
+ { "maxproc", login_getcapnum, RLIMIT_NPROC },
+ { "openfiles", login_getcapnum, RLIMIT_NOFILE },
+ { "coredumpsize", login_getcapsize, RLIMIT_CORE },
+ { "sbsize", login_getcapsize, RLIMIT_SBSIZE },
+ { "vmemoryuse", login_getcapsize, RLIMIT_VMEM },
+ { NULL, 0, 0 }
+};
+
+
+void
+setclassresources(login_cap_t *lc)
+{
+ struct login_res *lr;
+
+ if (lc == NULL)
+ return;
+
+ for (lr = resources; lr->what != NULL; ++lr) {
+ struct rlimit rlim;
+
+ /*
+ * The login.conf file can have <limit>, <limit>-max, and
+ * <limit>-cur entries.
+ * What we do is get the current current- and maximum- limits.
+ * Then, we try to get an entry for <limit> from the capability,
+ * using the current and max limits we just got as the
+ * default/error values.
+ * *Then*, we try looking for <limit>-cur and <limit>-max,
+ * again using the appropriate values as the default/error
+ * conditions.
+ */
+
+ if (getrlimit(lr->why, &rlim) != 0)
+ syslog(LOG_ERR, "getting %s resource limit: %m", lr->what);
+ else {
+ char name_cur[40];
+ char name_max[40];
+ rlim_t rcur = rlim.rlim_cur;
+ rlim_t rmax = rlim.rlim_max;
+
+ sprintf(name_cur, "%s-cur", lr->what);
+ sprintf(name_max, "%s-max", lr->what);
+
+ rcur = (*lr->who)(lc, lr->what, rcur, rcur);
+ rmax = (*lr->who)(lc, lr->what, rmax, rmax);
+ rlim.rlim_cur = (*lr->who)(lc, name_cur, rcur, rcur);
+ rlim.rlim_max = (*lr->who)(lc, name_max, rmax, rmax);
+
+ if (setrlimit(lr->why, &rlim) == -1)
+ syslog(LOG_WARNING, "set class '%s' resource limit %s: %m", lc->lc_class, lr->what);
+ }
+ }
+}
+
+
+
+static struct login_vars {
+ const char *tag;
+ const char *var;
+ const char *def;
+ int overwrite;
+} pathvars[] = {
+ { "path", "PATH", NULL, 1},
+ { "cdpath", "CDPATH", NULL, 1},
+ { "manpath", "MANPATH", NULL, 1},
+ { NULL, NULL, NULL, 0}
+}, envars[] = {
+ { "lang", "LANG", NULL, 1},
+ { "charset", "MM_CHARSET", NULL, 1},
+ { "timezone", "TZ", NULL, 1},
+ { "term", "TERM", NULL, 0},
+ { NULL, NULL, NULL, 0}
+};
+
+static char *
+substvar(const char * var, const struct passwd * pwd, int hlen, int pch, int nlen)
+{
+ char *np = NULL;
+
+ if (var != NULL) {
+ int tildes = 0;
+ int dollas = 0;
+ char *p;
+
+ if (pwd != NULL) {
+ /* Count the number of ~'s in var to substitute */
+ for (p = (char *)var; (p = strchr(p, '~')) != NULL; p++)
+ ++tildes;
+ /* Count the number of $'s in var to substitute */
+ for (p = (char *)var; (p = strchr(p, '$')) != NULL; p++)
+ ++dollas;
+ }
+
+ np = malloc(strlen(var) + (dollas * nlen)
+ - dollas + (tildes * (pch+hlen))
+ - tildes + 1);
+
+ if (np != NULL) {
+ p = strcpy(np, var);
+
+ if (pwd != NULL) {
+ /*
+ * This loop does user username and homedir substitutions
+ * for unescaped $ (username) and ~ (homedir)
+ */
+ while (*(p += strcspn(p, "~$")) != '\0') {
+ int l = strlen(p);
+
+ if (p > np && *(p-1) == '\\') /* Escaped: */
+ memmove(p - 1, p, l + 1); /* Slide-out the backslash */
+ else if (*p == '~') {
+ int v = pch && *(p+1) != '/'; /* Avoid double // */
+ memmove(p + hlen + v, p + 1, l); /* Subst homedir */
+ memmove(p, pwd->pw_dir, hlen);
+ if (v)
+ p[hlen] = '/';
+ p += hlen + v;
+ }
+ else /* if (*p == '$') */ {
+ memmove(p + nlen, p + 1, l); /* Subst username */
+ memmove(p, pwd->pw_name, nlen);
+ p += nlen;
+ }
+ }
+ }
+ }
+ }
+
+ return np;
+}
+
+
+void
+setclassenvironment(login_cap_t *lc, const struct passwd * pwd, int paths)
+{
+ struct login_vars *vars = paths ? pathvars : envars;
+ int hlen = pwd ? strlen(pwd->pw_dir) : 0;
+ int nlen = pwd ? strlen(pwd->pw_name) : 0;
+ char pch = 0;
+
+ if (hlen && pwd->pw_dir[hlen-1] != '/')
+ ++pch;
+
+ while (vars->tag != NULL) {
+ const char * var = paths ? login_getpath(lc, vars->tag, NULL)
+ : login_getcapstr(lc, vars->tag, NULL, NULL);
+
+ char * np = substvar(var, pwd, hlen, pch, nlen);
+
+ if (np != NULL) {
+ setenv(vars->var, np, vars->overwrite);
+ free(np);
+ } else if (vars->def != NULL) {
+ setenv(vars->var, vars->def, 0);
+ }
+ ++vars;
+ }
+
+ /*
+ * If we're not processing paths, then see if there is a setenv list by
+ * which the admin and/or user may set an arbitrary set of env vars.
+ */
+ if (!paths) {
+ const char **set_env = login_getcaplist(lc, "setenv", ",");
+
+ if (set_env != NULL) {
+ while (*set_env != NULL) {
+ char *p = strchr(*set_env, '=');
+
+ if (p != NULL) { /* Discard invalid entries */
+ char *np;
+
+ *p++ = '\0';
+ if ((np = substvar(p, pwd, hlen, pch, nlen)) != NULL) {
+ setenv(*set_env, np, 1);
+ free(np);
+ }
+ }
+ ++set_env;
+ }
+ }
+ }
+}
+
+
+/*
+ * setclasscontext()
+ *
+ * For the login class <class>, set various class context values
+ * (limits, mainly) to the values for that class. Which values are
+ * set are controlled by <flags> -- see <login_class.h> for the
+ * possible values.
+ *
+ * setclasscontext() can only set resources, priority, and umask.
+ */
+
+int
+setclasscontext(const char *classname, unsigned int flags)
+{
+ int rc;
+ login_cap_t *lc;
+
+ lc = login_getclassbyname(classname, NULL);
+
+ flags &= LOGIN_SETRESOURCES | LOGIN_SETPRIORITY |
+ LOGIN_SETUMASK | LOGIN_SETPATH;
+
+ rc = lc ? setusercontext(lc, NULL, 0, flags) : -1;
+ login_close(lc);
+ return rc;
+}
+
+
+
+/*
+ * Private functionw which takes care of processing
+ */
+
+static mode_t
+setlogincontext(login_cap_t *lc, const struct passwd *pwd,
+ mode_t mymask, unsigned long flags)
+{
+ if (lc) {
+ /* Set resources */
+ if (flags & LOGIN_SETRESOURCES)
+ setclassresources(lc);
+ /* See if there's a umask override */
+ if (flags & LOGIN_SETUMASK)
+ mymask = (mode_t)login_getcapnum(lc, "umask", mymask, mymask);
+ /* Set paths */
+ if (flags & LOGIN_SETPATH)
+ setclassenvironment(lc, pwd, 1);
+ /* Set environment */
+ if (flags & LOGIN_SETENV)
+ setclassenvironment(lc, pwd, 0);
+ }
+ return mymask;
+}
+
+
+
+/*
+ * setusercontext()
+ *
+ * Given a login class <lc> and a user in <pwd>, with a uid <uid>,
+ * set the context as in setclasscontext(). <flags> controls which
+ * values are set.
+ *
+ * The difference between setclasscontext() and setusercontext() is
+ * that the former sets things up for an already-existing process,
+ * while the latter sets things up from a root context. Such as might
+ * be called from login(1).
+ *
+ */
+
+int
+setusercontext(login_cap_t *lc, const struct passwd *pwd, uid_t uid, unsigned int flags)
+{
+ quad_t p;
+ mode_t mymask;
+ login_cap_t *llc = NULL;
+ struct rtprio rtp;
+ int error;
+
+ if (lc == NULL) {
+ if (pwd != NULL && (lc = login_getpwclass(pwd)) != NULL)
+ llc = lc; /* free this when we're done */
+ }
+
+ if (flags & LOGIN_SETPATH)
+ pathvars[0].def = uid ? _PATH_DEFPATH : _PATH_STDPATH;
+
+ /* we need a passwd entry to set these */
+ if (pwd == NULL)
+ flags &= ~(LOGIN_SETGROUP | LOGIN_SETLOGIN | LOGIN_SETMAC);
+
+ /* Set the process priority */
+ if (flags & LOGIN_SETPRIORITY) {
+ p = login_getcapnum(lc, "priority", LOGIN_DEFPRI, LOGIN_DEFPRI);
+
+ if(p > PRIO_MAX) {
+ rtp.type = RTP_PRIO_IDLE;
+ rtp.prio = p - PRIO_MAX - 1;
+ p = (rtp.prio > RTP_PRIO_MAX) ? 31 : p;
+ if(rtprio(RTP_SET, 0, &rtp))
+ syslog(LOG_WARNING, "rtprio '%s' (%s): %m",
+ pwd->pw_name, lc ? lc->lc_class : LOGIN_DEFCLASS);
+ } else if(p < PRIO_MIN) {
+ rtp.type = RTP_PRIO_REALTIME;
+ rtp.prio = abs(p - PRIO_MIN + RTP_PRIO_MAX);
+ p = (rtp.prio > RTP_PRIO_MAX) ? 1 : p;
+ if(rtprio(RTP_SET, 0, &rtp))
+ syslog(LOG_WARNING, "rtprio '%s' (%s): %m",
+ pwd->pw_name, lc ? lc->lc_class : LOGIN_DEFCLASS);
+ } else {
+ if (setpriority(PRIO_PROCESS, 0, (int)p) != 0)
+ syslog(LOG_WARNING, "setpriority '%s' (%s): %m",
+ pwd->pw_name, lc ? lc->lc_class : LOGIN_DEFCLASS);
+ }
+ }
+
+ /* Setup the user's group permissions */
+ if (flags & LOGIN_SETGROUP) {
+ if (setgid(pwd->pw_gid) != 0) {
+ syslog(LOG_ERR, "setgid(%lu): %m", (u_long)pwd->pw_gid);
+ login_close(llc);
+ return -1;
+ }
+ if (initgroups(pwd->pw_name, pwd->pw_gid) == -1) {
+ syslog(LOG_ERR, "initgroups(%s,%lu): %m", pwd->pw_name,
+ (u_long)pwd->pw_gid);
+ login_close(llc);
+ return -1;
+ }
+ }
+
+ /* Set up the user's MAC label. */
+ if ((flags & LOGIN_SETMAC) && mac_is_present(NULL) == 1) {
+ const char *label_string;
+ mac_t label;
+
+ label_string = login_getcapstr(lc, "label", NULL, NULL);
+ if (label_string != NULL) {
+ if (mac_from_text(&label, label_string) == -1) {
+ syslog(LOG_ERR, "mac_from_text('%s') for %s: %m",
+ pwd->pw_name, label_string);
+ return -1;
+ }
+ if (mac_set_proc(label) == -1)
+ error = errno;
+ else
+ error = 0;
+ mac_free(label);
+ if (error != 0) {
+ syslog(LOG_ERR, "mac_set_proc('%s') for %s: %s",
+ label_string, pwd->pw_name, strerror(error));
+ return -1;
+ }
+ }
+ }
+
+ /* Set the sessions login */
+ if ((flags & LOGIN_SETLOGIN) && setlogin(pwd->pw_name) != 0) {
+ syslog(LOG_ERR, "setlogin(%s): %m", pwd->pw_name);
+ login_close(llc);
+ return -1;
+ }
+
+ mymask = (flags & LOGIN_SETUMASK) ? umask(LOGIN_DEFUMASK) : 0;
+ mymask = setlogincontext(lc, pwd, mymask, flags);
+ login_close(llc);
+
+ /* This needs to be done after anything that needs root privs */
+ if ((flags & LOGIN_SETUSER) && setuid(uid) != 0) {
+ syslog(LOG_ERR, "setuid(%lu): %m", (u_long)uid);
+ return -1; /* Paranoia again */
+ }
+
+ /*
+ * Now, we repeat some of the above for the user's private entries
+ */
+ if ((lc = login_getuserclass(pwd)) != NULL) {
+ mymask = setlogincontext(lc, pwd, mymask, flags);
+ login_close(lc);
+ }
+
+ /* Finally, set any umask we've found */
+ if (flags & LOGIN_SETUMASK)
+ umask(mymask);
+
+ return 0;
+}
+
diff --git a/lib/libutil/login_crypt.c b/lib/libutil/login_crypt.c
new file mode 100644
index 0000000..c65fc9b
--- /dev/null
+++ b/lib/libutil/login_crypt.c
@@ -0,0 +1,50 @@
+/*-
+ * Copyright (c) 2000 Brian Fundakowski Feldman
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 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 <login_cap.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+const char *
+login_setcryptfmt(login_cap_t *lc, const char *def, const char *error) {
+ const char *cipher;
+
+ cipher = login_getcapstr(lc, "passwd_format", def, NULL);
+ if (getenv("CRYPT_DEBUG") != NULL)
+ fprintf(stderr, "login_setcryptfmt: "
+ "passwd_format = %s\n", cipher);
+ if (cipher == NULL)
+ return (error);
+ if (!crypt_set_format(cipher))
+ return (error);
+ return (cipher);
+}
diff --git a/lib/libutil/login_ok.3 b/lib/libutil/login_ok.3
new file mode 100644
index 0000000..8a6f291
--- /dev/null
+++ b/lib/libutil/login_ok.3
@@ -0,0 +1,142 @@
+.\" Copyright (c) 1995 David Nugent <davidn@blaze.net.au>
+.\" 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
+.\" David Nugent.
+.\" 5. Modifications may be freely made to this file providing the above
+.\" conditions are met.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd January 2, 1997
+.Os
+.Dt LOGIN_OK 3
+.Sh NAME
+.Nm auth_ttyok ,
+.Nm auth_hostok ,
+.Nm auth_timeok
+.Nd functions for checking login class based login restrictions
+.Sh LIBRARY
+.Lb libutil
+.Sh SYNOPSIS
+.In sys/types.h
+.In time.h
+.In login_cap.h
+.Ft int
+.Fn auth_ttyok "login_cap_t *lc" "const char *tty"
+.Ft int
+.Fn auth_hostok "login_cap_t *lc" "const char *host" "char const *ip"
+.Ft int
+.Fn auth_timeok "login_cap_t *lc" "time_t t"
+.Sh DESCRIPTION
+This set of functions checks to see if login is allowed based on login
+class capability entries in the login database,
+.Xr login.conf 5 .
+.Pp
+The
+.Fn auth_ttyok
+function checks to see if the named tty is available to users of a specific
+class, and is either in the
+.Em ttys.allow
+access list, and not in
+the
+.Em ttys.deny
+access list.
+An empty
+.Em ttys.allow
+list (or if no such capability exists for
+the give login class) logins via any tty device are allowed unless
+the
+.Em ttys.deny
+list exists and is non-empty, and the device or its
+tty group (see
+.Xr ttys 5 )
+is not in the list.
+Access to ttys may be allowed or restricted specifically by tty device
+name, a device name which includes a wildcard (e.g.\& ttyD* or cuaD*),
+or may name a ttygroup, when group=<name> tags have been assigned in
+.Pa /etc/ttys .
+Matching of ttys and ttygroups is case sensitive.
+Passing a
+.Dv NULL
+or empty string as the
+.Ar tty
+parameter causes the function to return a non-zero value.
+.Pp
+The
+.Fn auth_hostok
+function checks for any host restrictions for remote logins.
+The function checks on both a host name and IP address (given in its
+text form, typically n.n.n.n) against the
+.Em host.allow
+and
+.Em host.deny
+login class capabilities.
+As with ttys and their groups, wildcards and character classes may be
+used in the host allow and deny capability records.
+The
+.Xr fnmatch 3
+function is used for matching, and the matching on hostnames is case
+insensitive.
+Note that this function expects that the hostname is fully expanded
+(i.e., the local domain name added if necessary) and the IP address
+is in its canonical form.
+No hostname or address lookups are attempted.
+.Pp
+It is possible to call this function with either the hostname or
+the IP address missing (i.e.\&
+.Dv NULL )
+and matching will be performed
+only on the basis of the parameter given.
+Passing
+.Dv NULL
+or empty strings in both parameters will result in
+a non-zero return value.
+.Pp
+The
+.Fn auth_timeok
+function checks to see that a given time value is within the
+.Em times.allow
+login class capability and not within the
+.Em times.deny
+access lists.
+An empty or non-existent
+.Em times.allow
+list allows access at any
+time, except if a given time is falls within a period in the
+.Em times.deny
+list.
+The format of time period records contained in both
+.Em times.allow
+and
+.Em times.deny
+capability fields is explained in detail in the
+.Xr login_times 3
+manual page.
+.Sh RETURN VALUES
+A non-zero return value from any of these functions indicates that
+login access is granted.
+A zero return value means either that the item being tested is not
+in the
+.Em allow
+access list, or is within the
+.Em deny
+access list.
+.Sh SEE ALSO
+.Xr getcap 3 ,
+.Xr login_cap 3 ,
+.Xr login_class 3 ,
+.Xr login_times 3 ,
+.Xr login.conf 5 ,
+.Xr termcap 5
diff --git a/lib/libutil/login_ok.c b/lib/libutil/login_ok.c
new file mode 100644
index 0000000..26971a9
--- /dev/null
+++ b/lib/libutil/login_ok.c
@@ -0,0 +1,250 @@
+/*-
+ * Copyright (c) 1996 by
+ * David Nugent <davidn@blaze.net.au>
+ * 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 authors.
+ * 5. Modifications may be freely made to this file providing the above
+ * conditions are met.
+ *
+ * Support allow/deny lists in login class capabilities
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/param.h>
+#include <errno.h>
+#include <fnmatch.h>
+#include <login_cap.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ttyent.h>
+#include <unistd.h>
+
+
+/* -- support functions -- */
+
+/*
+ * login_strinlist()
+ * This function is intentionally public - reused by TAS.
+ * Returns TRUE (non-zero) if a string matches a pattern
+ * in a given array of patterns. 'flags' is passed directly
+ * to fnmatch(3).
+ */
+
+int
+login_strinlist(const char **list, char const *str, int flags)
+{
+ int rc = 0;
+
+ if (str != NULL && *str != '\0') {
+ int i = 0;
+
+ while (rc == 0 && list[i] != NULL)
+ rc = fnmatch(list[i++], str, flags) == 0;
+ }
+ return rc;
+}
+
+
+/*
+ * login_str2inlist()
+ * Locate either or two strings in a given list
+ */
+
+int
+login_str2inlist(const char **ttlst, const char *str1, const char *str2, int flags)
+{
+ int rc = 0;
+
+ if (login_strinlist(ttlst, str1, flags))
+ rc = 1;
+ else if (login_strinlist(ttlst, str2, flags))
+ rc = 1;
+ return rc;
+}
+
+
+/*
+ * login_timelist()
+ * This function is intentionally public - reused by TAS.
+ * Returns an allocated list of time periods given an array
+ * of time periods in ascii form.
+ */
+
+login_time_t *
+login_timelist(login_cap_t *lc, char const *cap, int *ltno,
+ login_time_t **ltptr)
+{
+ int j = 0;
+ struct login_time *lt = NULL;
+ const char **tl;
+
+ if ((tl = login_getcaplist(lc, cap, NULL)) != NULL) {
+
+ while (tl[j++] != NULL)
+ ;
+ if (*ltno >= j)
+ lt = *ltptr;
+ else if ((lt = realloc(*ltptr, j * sizeof(struct login_time))) != NULL) {
+ *ltno = j;
+ *ltptr = lt;
+ }
+ if (lt != NULL) {
+ int i = 0;
+
+ for (--j; i < j; i++)
+ lt[i] = parse_lt(tl[i]);
+ lt[i].lt_dow = LTM_NONE;
+ }
+ }
+ return lt;
+}
+
+
+/*
+ * login_ttyok()
+ * This function is a variation of auth_ttyok(), but it checks two
+ * arbitrary capability lists not necessarily related to access.
+ * This hook is provided for the accounted/exclude accounting lists.
+ */
+
+int
+login_ttyok(login_cap_t *lc, const char *tty, const char *allowcap,
+ const char *denycap)
+{
+ int rc = 1;
+
+ if (lc != NULL && tty != NULL && *tty != '\0') {
+ struct ttyent *te;
+ char *grp;
+ const char **ttl;
+
+ te = getttynam(tty); /* Need group name */
+ grp = te ? te->ty_group : NULL;
+ ttl = login_getcaplist(lc, allowcap, NULL);
+
+ if (ttl != NULL && !login_str2inlist(ttl, tty, grp, 0))
+ rc = 0; /* tty or ttygroup not in allow list */
+ else {
+
+ ttl = login_getcaplist(lc, denycap, NULL);
+ if (ttl != NULL && login_str2inlist(ttl, tty, grp, 0))
+ rc = 0; /* tty or ttygroup in deny list */
+ }
+ }
+
+ return rc;
+}
+
+
+/*
+ * auth_ttyok()
+ * Determine whether or not login on a tty is accessible for
+ * a login class
+ */
+
+int
+auth_ttyok(login_cap_t *lc, const char * tty)
+{
+ return login_ttyok(lc, tty, "ttys.allow", "ttys.deny");
+}
+
+
+/*
+ * login_hostok()
+ * This function is a variation of auth_hostok(), but it checks two
+ * arbitrary capability lists not necessarily related to access.
+ * This hook is provided for the accounted/exclude accounting lists.
+ */
+
+int
+login_hostok(login_cap_t *lc, const char *host, const char *ip,
+ const char *allowcap, const char *denycap)
+{
+ int rc = 1; /* Default is ok */
+
+ if (lc != NULL &&
+ ((host != NULL && *host != '\0') || (ip != NULL && *ip != '\0'))) {
+ const char **hl;
+
+ hl = login_getcaplist(lc, allowcap, NULL);
+ if (hl != NULL && !login_str2inlist(hl, host, ip, FNM_CASEFOLD))
+ rc = 0; /* host or IP not in allow list */
+ else {
+
+ hl = login_getcaplist(lc, denycap, NULL);
+ if (hl != NULL && login_str2inlist(hl, host, ip, FNM_CASEFOLD))
+ rc = 0; /* host or IP in deny list */
+ }
+ }
+
+ return rc;
+}
+
+
+/*
+ * auth_hostok()
+ * Determine whether or not login from a host is ok
+ */
+
+int
+auth_hostok(login_cap_t *lc, const char *host, const char *ip)
+{
+ return login_hostok(lc, host, ip, "host.allow", "host.deny");
+}
+
+
+/*
+ * auth_timeok()
+ * Determine whether or not login is ok at a given time
+ */
+
+int
+auth_timeok(login_cap_t *lc, time_t t)
+{
+ int rc = 1; /* Default is ok */
+
+ if (lc != NULL && t != (time_t)0 && t != (time_t)-1) {
+ struct tm *tptr;
+
+ static int ltimesno = 0;
+ static struct login_time *ltimes = NULL;
+
+ if ((tptr = localtime(&t)) != NULL) {
+ struct login_time *lt;
+
+ lt = login_timelist(lc, "times.allow", &ltimesno, &ltimes);
+ if (lt != NULL && in_ltms(lt, tptr, NULL) == -1)
+ rc = 0; /* not in allowed times list */
+ else {
+
+ lt = login_timelist(lc, "times.deny", &ltimesno, &ltimes);
+ if (lt != NULL && in_ltms(lt, tptr, NULL) != -1)
+ rc = 0; /* in deny times list */
+ }
+ if (ltimes) {
+ free(ltimes);
+ ltimes = NULL;
+ ltimesno = 0;
+ }
+ }
+ }
+
+ return rc;
+}
diff --git a/lib/libutil/login_times.3 b/lib/libutil/login_times.3
new file mode 100644
index 0000000..e1f57ce
--- /dev/null
+++ b/lib/libutil/login_times.3
@@ -0,0 +1,161 @@
+.\" Copyright (c) 1995 David Nugent <davidn@blaze.net.au>
+.\" 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
+.\" David Nugent.
+.\" 5. Modifications may be freely made to this file providing the above
+.\" conditions are met.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd January 2, 1997
+.Os
+.Dt LOGIN_TIMES 3
+.Sh NAME
+.Nm parse_lt ,
+.Nm in_ltm ,
+.Nm in_ltms
+.Nd functions for parsing and checking login time periods
+.Sh LIBRARY
+.Lb libutil
+.Sh SYNOPSIS
+.In sys/types.h
+.In time.h
+.In login_cap.h
+.Ft login_time_t
+.Fn parse_lt "const char *str"
+.Ft int
+.Fn in_ltm "const login_time_t *lt" "struct tm *t" "time_t *ends"
+.Ft int
+.Fn in_ltms "const login_time_t *lt" "struct tm *t" "time_t *ends"
+.Sh DESCRIPTION
+This set of functions may be used for parsing and checking login and
+session times against a predefined list of allowed login times as
+used in
+.Xr login.conf 5 .
+.Pp
+The format of allowed and disallowed session times specified in the
+.Ar times.allow
+and
+.Ar times.deny
+capability fields in a login class are comprised of a prefix which
+specifies one or more 2- or 3-character day codes, followed by
+a start and end time in 24 hour format separated by a hyphen.
+Day codes may be concatenated together to select specific days, or
+the special mnemonics "Any" and "All" (for any/all days of the week),
+"Wk" for any day of the week (excluding Saturdays and Sundays) and
+"Wd" for any weekend day may be used.
+.Pp
+For example, the following time period:
+.Dl MoThFrSa1400-2200
+is interpreted as Monday, Thursday through Saturday between the hours
+of 2pm and 10pm.
+.Dl Wd0600-1800
+means Saturday and Sunday, between the hours of 6am through 6pm, and
+.Dl Any0400-1600
+means any day of the week, between 4am and 4pm.
+.Pp
+Note that all time periods reference system local time.
+.Pp
+The
+.Fn parse_lt
+function converts the ASCII representation of a time period into
+a structure of type
+.Ft login_time_t .
+This is defined as:
+.Bd -literal
+typedef struct login_time
+{
+ u_short lt_start; /* Start time */
+ u_short lt_end; /* End time */
+ u_char lt_dow; /* Days of week */
+} login_time_t;
+.Ed
+.Pp
+The
+.Ar lt_start
+and
+.Ar lt_end
+fields contain the number of minutes past midnight at which the
+described period begins and ends.
+The
+.Ar lt_dow
+field is a bit field, containing one bit for each day of the week
+and one bit unused.
+A series
+.Em LTM_*
+macros may be used for testing bits individually and in combination.
+If no bits are set in this field - i.e., it contains the value
+.Em LTM_NONE
+- then the entire period is assumed invalid.
+This is used as a convention to mark the termination of an array
+of login_time_t values.
+If
+.Fn parse_lt
+returns a
+.Ar login_time_t
+with
+.Ar lt_dow
+equal to
+.Em LTM_NONE
+then a parsing error was encountered.
+.Pp
+The remaining functions provide the ability to test a given time_t or
+struct tm value against a specific time period or array of time
+periods.
+The
+.Fn in_ltm
+function determines whether the given time described by the struct tm
+passed as the second parameter falls within the period described
+by the first parameter.
+A boolean value is returned, indicating whether or not the time
+specified falls within the period.
+If the time does fall within the time period, and the third
+parameter to the function is not NULL, the time at which the
+period ends relative to the time passed is returned.
+.Pp
+The
+.Fn in_ltms
+function is similar to
+.Fn in_ltm
+except that the first parameter must be a pointer to an array
+of login_time_t objects, which is up to LC_MAXTIMES (64)
+elements in length, and terminated by an element with its
+.Ar lt_dow
+field set to
+.Em LTM_NONE .
+.Sh RETURN VALUES
+The
+.Fn parse_lt
+function returns a filled in structure of type login_time_t containing the
+parsed time period.
+If a parsing error occurs, the lt_dow field is set to
+.Em LTM_NONE
+(i.e., 0).
+.Pp
+The
+.Fn in_ltm
+function returns non-zero if the given time falls within the period described
+by the login_time_t passed as the first parameter.
+.Pp
+The
+.Fn in_ltms
+function returns the index of the first time period found in which the given
+time falls, or -1 if none of them apply.
+.Sh SEE ALSO
+.Xr getcap 3 ,
+.Xr login_cap 3 ,
+.Xr login_class 3 ,
+.Xr login.conf 5 ,
+.Xr termcap 5
diff --git a/lib/libutil/login_times.c b/lib/libutil/login_times.c
new file mode 100644
index 0000000..10e88dd
--- /dev/null
+++ b/lib/libutil/login_times.c
@@ -0,0 +1,161 @@
+/*-
+ * Copyright (c) 1996 by
+ * David Nugent <davidn@blaze.net.au>
+ * 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 authors.
+ * 5. Modifications may be freely made to this file providing the above
+ * conditions are met.
+ *
+ * Login period parsing and comparison functions.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <ctype.h>
+#include <login_cap.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+static struct
+{
+ const char *dw;
+ u_char cn;
+ u_char fl;
+} dws[] =
+{
+ { "su", 2, LTM_SUN }, { "mo", 2, LTM_MON }, { "tu", 2, LTM_TUE },
+ { "we", 2, LTM_WED }, { "th", 2, LTM_THU }, { "fr", 2, LTM_FRI },
+ { "sa", 2, LTM_SAT }, { "any",3, LTM_ANY }, { "all",3, LTM_ANY },
+ { "wk", 2, LTM_WK }, { "wd", 2, LTM_WD }, { NULL, 0, 0 }
+};
+
+static char *
+parse_time(char * ptr, u_short * t)
+{
+ u_short val;
+
+ for (val = 0; *ptr && isdigit(*ptr); ptr++)
+ val = (u_short)(val * 10 + (*ptr - '0'));
+
+ *t = (u_short)((val / 100) * 60 + (val % 100));
+
+ return ptr;
+}
+
+
+login_time_t
+parse_lt(const char * str)
+{
+ login_time_t t;
+
+ memset(&t, 0, sizeof t);
+ t.lt_dow = LTM_NONE;
+ if (str && *str && strcmp(str, "Never") != 0 && strcmp(str, "None") != 0) {
+ int i;
+ login_time_t m = t;
+ char *p;
+ char buf[64];
+
+ /* Make local copy and force lowercase to simplify parsing */
+ p = strncpy(buf, str, sizeof buf);
+ buf[sizeof buf - 1] = '\0';
+ for (i = 0; buf[i]; i++)
+ buf[i] = (char)tolower(buf[i]);
+
+ while (isalpha(*p)) {
+
+ i = 0;
+ while (dws[i].dw && strncmp(p, dws[i].dw, dws[i].cn) != 0)
+ i++;
+ if (dws[i].dw == NULL)
+ break;
+ m.lt_dow |= dws[i].fl;
+ p += dws[i].cn;
+ }
+
+ if (m.lt_dow == LTM_NONE) /* No (valid) prefix, assume any */
+ m.lt_dow |= LTM_ANY;
+
+ if (isdigit(*p))
+ p = parse_time(p, &m.lt_start);
+ else
+ m.lt_start = 0;
+ if (*p == '-')
+ p = parse_time(++p, &m.lt_end);
+ else
+ m.lt_end = 1440;
+
+ t = m;
+ }
+ return t;
+}
+
+
+int
+in_ltm(const login_time_t * ltm, struct tm * tt, time_t * ends)
+{
+ int rc = 0;
+
+ if (tt != NULL) {
+ /* First, examine the day of the week */
+ if ((u_char)(0x01 << tt->tm_wday) & ltm->lt_dow) {
+ /* Convert `current' time to minute of the day */
+ u_short now = (u_short)((tt->tm_hour * 60) + tt->tm_min);
+
+ if (tt->tm_sec > 30)
+ ++now;
+ if (now >= ltm->lt_start && now < ltm->lt_end) {
+ rc = 2;
+ if (ends != NULL) {
+ /* If requested, return ending time for this period */
+ tt->tm_hour = (int)(ltm->lt_end / 60);
+ tt->tm_min = (int)(ltm->lt_end % 60);
+ *ends = mktime(tt);
+ }
+ }
+ }
+ }
+ return rc;
+}
+
+
+int
+in_lt(const login_time_t * ltm, time_t * t)
+{
+ return in_ltm(ltm, localtime(t), t);
+}
+
+int
+in_ltms(const login_time_t * ltm, struct tm * tm, time_t * t)
+{
+ int i = 0;
+
+ while (i < LC_MAXTIMES && ltm[i].lt_dow != LTM_NONE) {
+ if (in_ltm(ltm + i, tm, t))
+ return i;
+ i++;
+ }
+ return -1;
+}
+
+int
+in_lts(const login_time_t * ltm, time_t * t)
+{
+ return in_ltms(ltm, localtime(t), t);
+}
+
diff --git a/lib/libutil/login_tty.3 b/lib/libutil/login_tty.3
new file mode 100644
index 0000000..6303d68
--- /dev/null
+++ b/lib/libutil/login_tty.3
@@ -0,0 +1,65 @@
+.\"
+.\" Copyright (c) 1996 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 December 29, 1996
+.Os
+.Dt LOGIN_TTY 3
+.Sh NAME
+.Nm login_tty
+.Nd prepare a tty for a new login session
+.Sh LIBRARY
+.Lb libutil
+.Sh SYNOPSIS
+.In libutil.h
+.Ft int
+.Fn login_tty "int fd"
+.Sh DESCRIPTION
+The function
+.Fn login_tty
+prepares a terminal for a new login session.
+The file descriptor
+.Ar fd
+passed to
+.Fn login_tty
+must be opened for reading and writing on a terminal device.
+It will be
+made the controlling terminal for the calling process, after allocating
+a new session with
+.Xr setsid 2 .
+This terminal device will also be made the standard input, standard output,
+and standard error output of the calling process.
+.Sh RETURN VALUES
+The
+.Fn login_tty
+function returns -1 if it could not make the device referenced by
+.Ar fd
+the controlling terminal of the calling process, and 0 otherwise.
+.Sh SEE ALSO
+.Xr dup2 2 ,
+.Xr ioctl 2 ,
+.Xr setsid 2 ,
+.Xr tty 4
diff --git a/lib/libutil/login_tty.c b/lib/libutil/login_tty.c
new file mode 100644
index 0000000..985a6ea
--- /dev/null
+++ b/lib/libutil/login_tty.c
@@ -0,0 +1,62 @@
+/*-
+ * 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. 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)login_tty.c 8.1 (Berkeley) 6/4/93";
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+
+#include <libutil.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int
+login_tty(int fd)
+{
+ (void) setsid();
+ if (ioctl(fd, TIOCSCTTY, (char *)NULL) == -1)
+ return (-1);
+ (void) dup2(fd, 0);
+ (void) dup2(fd, 1);
+ (void) dup2(fd, 2);
+ if (fd > 2)
+ (void) close(fd);
+ return (0);
+}
diff --git a/lib/libutil/logout.3 b/lib/libutil/logout.3
new file mode 100644
index 0000000..426fe08
--- /dev/null
+++ b/lib/libutil/logout.3
@@ -0,0 +1,69 @@
+.\"
+.\" Copyright (c) 1996 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 December 29, 1996
+.Os
+.Dt LOGOUT 3
+.Sh NAME
+.Nm logout
+.Nd remove an entry from the utmp file
+.Sh LIBRARY
+.Lb libutil
+.Sh SYNOPSIS
+.In sys/types.h
+.In libutil.h
+.Ft int
+.Fn logout "const char *line"
+.Sh DESCRIPTION
+The function
+.Fn logout
+searches the
+.Xr utmp 5
+file for the slot described by
+.Ar line
+(usually a tty name).
+If such a slot could be found, it will be updated
+with a record where the
+.Em name
+and
+.Em host
+fields are empty, and the time stamp field is updated to the current time.
+.Sh RETURN VALUES
+The
+.Fn logout
+function returns 1 if the slot described by
+.Ar line
+has been found and updated, 0 otherwise.
+.Sh SEE ALSO
+.Xr login 3 ,
+.Xr utmp 5 ,
+.Xr wtmp 5
+.Sh BUGS
+The calling interface of
+.Fn logout
+is inconsistent with that of
+.Xr login 3 .
diff --git a/lib/libutil/logout.c b/lib/libutil/logout.c
new file mode 100644
index 0000000..292f898
--- /dev/null
+++ b/lib/libutil/logout.c
@@ -0,0 +1,78 @@
+/*-
+ * 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. 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)logout.c 8.1 (Berkeley) 6/4/93";
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include <fcntl.h>
+#include <libutil.h>
+#include <stdlib.h>
+#include <string.h>
+#include <timeconv.h>
+#include <unistd.h>
+#include <utmp.h>
+
+typedef struct utmp UTMP;
+
+int
+logout(const char *line)
+{
+ int fd;
+ UTMP ut;
+ int rval;
+
+ if ((fd = open(_PATH_UTMP, O_RDWR, 0)) < 0)
+ return(0);
+ rval = 0;
+ while (read(fd, &ut, sizeof(UTMP)) == sizeof(UTMP)) {
+ if (!ut.ut_name[0] || strncmp(ut.ut_line, line, UT_LINESIZE))
+ continue;
+ bzero(ut.ut_name, UT_NAMESIZE);
+ bzero(ut.ut_host, UT_HOSTSIZE);
+ ut.ut_time = _time_to_time32(time(NULL));
+ (void)lseek(fd, -(off_t)sizeof(UTMP), L_INCR);
+ (void)write(fd, &ut, sizeof(UTMP));
+ rval = 1;
+ }
+ (void)close(fd);
+ return(rval);
+}
diff --git a/lib/libutil/logwtmp.3 b/lib/libutil/logwtmp.3
new file mode 100644
index 0000000..16903fb
--- /dev/null
+++ b/lib/libutil/logwtmp.3
@@ -0,0 +1,71 @@
+.\"
+.\" Copyright (c) 1996 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 December 29, 1996
+.Os
+.Dt LOGWTMP 3
+.Sh NAME
+.Nm logwtmp
+.Nd append a new record to the wtmp file
+.Sh LIBRARY
+.Lb libutil
+.Sh SYNOPSIS
+.In sys/types.h
+.In libutil.h
+.Ft void
+.Fn logwtmp "const char *line" "const char *name" "const char *host"
+.Sh DESCRIPTION
+The function
+.Fn logwtmp
+tries to append a new record to the
+.Xr wtmp 5
+file, using the provided arguments
+.Ar line ,
+.Ar name ,
+and
+.Ar host ,
+and the current time.
+.Pp
+If the length of the hostname string
+.Ar host
+is longer than what would fit into the hostname field of the
+.Xr wtmp 5
+file, it will first be attempted to convert it into a numerical IP
+address using
+.Xr gethostbyname 3 .
+Failing this, the hostname will be recorded as
+.Qq invalid hostname .
+.Pp
+The calling process must have permission to write to the
+.Xr wtmp 5
+file.
+.Sh RETURN VALUES
+None.
+.Sh SEE ALSO
+.Xr gethostbyname 3 ,
+.Xr login 3 ,
+.Xr wtmp 5
diff --git a/lib/libutil/logwtmp.c b/lib/libutil/logwtmp.c
new file mode 100644
index 0000000..42f3599
--- /dev/null
+++ b/lib/libutil/logwtmp.c
@@ -0,0 +1,104 @@
+/*-
+ * 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. 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)logwtmp.c 8.1 (Berkeley) 6/4/93";
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+
+#include <libutil.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <timeconv.h>
+#include <unistd.h>
+#include <utmp.h>
+
+
+void
+logwtmp(const char *line, const char *name, const char *host)
+{
+ struct utmp ut;
+ struct stat buf;
+ char fullhost[MAXHOSTNAMELEN];
+ int fd;
+
+ strncpy(fullhost, host, sizeof(fullhost) - 1);
+ fullhost[sizeof(fullhost) - 1] = '\0';
+ trimdomain(fullhost, UT_HOSTSIZE);
+ host = fullhost;
+
+ if (strlen(host) > UT_HOSTSIZE) {
+ int error;
+ struct addrinfo hints, *res;
+
+ bzero(&hints, sizeof(struct addrinfo));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_flags = AI_CANONNAME;
+ error = getaddrinfo(host, NULL, &hints, &res);
+ if (error != 0 || res->ai_addr == NULL)
+ host = "invalid hostname";
+ else {
+ error = getnameinfo(res->ai_addr, res->ai_addrlen,
+ fullhost, strlen(fullhost), NULL, 0,
+ NI_NUMERICHOST);
+ if (error != 0) {
+ fprintf(stderr, "%d", error);
+ host = "invalid hostname";
+ }
+ }
+ }
+
+ if ((fd = open(_PATH_WTMP, O_WRONLY|O_APPEND, 0)) < 0)
+ return;
+ if (fstat(fd, &buf) == 0) {
+ (void) strncpy(ut.ut_line, line, sizeof(ut.ut_line));
+ (void) strncpy(ut.ut_name, name, sizeof(ut.ut_name));
+ (void) strncpy(ut.ut_host, host, sizeof(ut.ut_host));
+ ut.ut_time = _time_to_time32(time(NULL));
+ if (write(fd, (char *)&ut, sizeof(struct utmp)) !=
+ sizeof(struct utmp))
+ (void) ftruncate(fd, buf.st_size);
+ }
+ (void) close(fd);
+}
diff --git a/lib/libutil/pidfile.3 b/lib/libutil/pidfile.3
new file mode 100644
index 0000000..64f77b0
--- /dev/null
+++ b/lib/libutil/pidfile.3
@@ -0,0 +1,249 @@
+.\" Copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd August 22, 2005
+.Dt PIDFILE 3
+.Os
+.Sh NAME
+.Nm pidfile_open ,
+.Nm pidfile_write ,
+.Nm pidfile_close ,
+.Nm pidfile_remove
+.Nd "library for PID files handling"
+.Sh LIBRARY
+.Lb libutil
+.Sh SYNOPSIS
+.In sys/param.h
+.In libutil.h
+.Ft "struct pidfh *"
+.Fn pidfile_open "const char *path" "mode_t mode" "pid_t *pidptr"
+.Ft int
+.Fn pidfile_write "struct pidfh *pfh"
+.Ft int
+.Fn pidfile_close "struct pidfh *pfh"
+.Ft int
+.Fn pidfile_remove "struct pidfh *pfh"
+.Sh DESCRIPTION
+The
+.Nm pidfile
+family of functions allows daemons to handle PID files.
+It uses
+.Xr flock 2
+to lock a pidfile and detect already running daemons.
+.Pp
+The
+.Fn pidfile_open
+function opens (or creates) a file specified by the
+.Fa path
+argument and locks it with the
+.Xr flock 2
+system call.
+If a file can not be locked, a PID of an already running daemon is returned in
+the
+.Fa pidptr
+argument (if it is not
+.Dv NULL ) .
+The function does not write process' PID into the file here, so it can be
+used before
+.Fn fork Ns ing
+and exit with a proper error message when needed.
+If the
+.Fa path
+argument is
+.Dv NULL ,
+.Pa /var/run/ Ns Ao Va progname Ac Ns Pa .pid
+file will be used.
+.Pp
+The
+.Fn pidfile_write
+function writes process' PID into a previously opened file.
+.Pp
+The
+.Fn pidfile_close
+function closes a pidfile.
+It should be used after daemon
+.Fn fork Ns s
+to start a child process.
+.Pp
+The
+.Fn pidfile_remove
+function closes and removes a pidfile.
+.Sh RETURN VALUES
+The
+.Fn pidfile_open
+function returns a valid pointer to a
+.Vt pidfh
+structure on success, or
+.Dv NULL
+if an error occurs.
+If an error occurs,
+.Va errno
+will be set.
+.Rv -std pidfile_write pidfile_close pidfile_remove
+.Sh EXAMPLES
+The following example shows in which order these functions should be used.
+Note that it is safe to pass
+.Dv NULL
+to
+.Fn pidfile_write ,
+.Fn pidfile_remove
+and
+.Fn pidfile_close
+functions.
+.Bd -literal
+struct pidfh *pfh;
+pid_t otherpid, childpid;
+
+pfh = pidfile_open("/var/run/daemon.pid", 0600, &otherpid);
+if (pfh == NULL) {
+ if (errno == EEXIST) {
+ errx(EXIT_FAILURE, "Daemon already running, pid: %jd.",
+ (intmax_t)otherpid);
+ }
+ /* If we cannot create pidfile from other reasons, only warn. */
+ warn("Cannot open or create pidfile");
+}
+
+if (daemon(0, 0) == -1) {
+ warn("Cannot daemonize");
+ pidfile_remove(pfh);
+ exit(EXIT_FAILURE);
+}
+
+pidfile_write(pfh);
+
+for (;;) {
+ /* Do work. */
+ childpid = fork();
+ switch (childpid) {
+ case -1:
+ syslog(LOG_ERR, "Cannot fork(): %s.", strerror(errno));
+ break;
+ case 0:
+ pidfile_close(pfh);
+ /* Do child work. */
+ break;
+ default:
+ syslog(LOG_INFO, "Child %jd started.", (intmax_t)childpid);
+ break;
+ }
+}
+
+pidfile_remove(pfh);
+exit(EXIT_SUCCESS);
+.Ed
+.Sh ERRORS
+The
+.Fn pidfile_open
+function will fail if:
+.Bl -tag -width Er
+.It Bq Er EEXIST
+Some process already holds the lock on the given pidfile, meaning that a
+daemon is already running.
+.It Bq Er ENAMETOOLONG
+Specified pidfile's name is too long.
+.It Bq Er EINVAL
+Some process already holds the lock on the given pidfile, but PID read
+from there is invalid.
+.El
+.Pp
+The
+.Fn pidfile_open
+function may also fail and set
+.Va errno
+for any errors specified for the
+.Xr fstat 2 ,
+.Xr open 2 ,
+and
+.Xr read 2
+calls.
+.Pp
+The
+.Fn pidfile_write
+function will fail if:
+.Bl -tag -width Er
+.It Bq Er EDOOFUS
+Improper function use.
+Probably called before
+.Fn pidfile_open .
+.El
+.Pp
+The
+.Fn pidfile_write
+function may also fail and set
+.Va errno
+for any errors specified for the
+.Xr fstat 2 ,
+.Xr ftruncate 2 ,
+and
+.Xr write 2
+calls.
+.Pp
+The
+.Fn pidfile_close
+function may fail and set
+.Va errno
+for any errors specified for the
+.Xr close 2
+and
+.Xr fstat 2
+calls.
+.Pp
+The
+.Fn pidfile_remove
+function will fail if:
+.Bl -tag -width Er
+.It Bq Er EDOOFUS
+Improper function use.
+Probably called not from the process which made
+.Fn pidfile_write .
+.El
+.Pp
+The
+.Fn pidfile_remove
+function may also fail and set
+.Va errno
+for any errors specified for the
+.Xr close 2 ,
+.Xr flock 2 ,
+.Xr fstat 2 ,
+.Xr write 2 ,
+and
+.Xr unlink 2
+calls.
+.Sh SEE ALSO
+.Xr flock 2 ,
+.Xr open 2 ,
+.Xr daemon 3
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm pidfile
+functionality is based on ideas from
+.An John-Mark Gurney Aq jmg@FreeBSD.org .
+.Pp
+The code and manual page was written by
+.An Pawel Jakub Dawidek Aq pjd@FreeBSD.org .
diff --git a/lib/libutil/pidfile.c b/lib/libutil/pidfile.c
new file mode 100644
index 0000000..cf7441e
--- /dev/null
+++ b/lib/libutil/pidfile.c
@@ -0,0 +1,246 @@
+/*-
+ * Copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <err.h>
+#include <errno.h>
+#include <libutil.h>
+
+static int _pidfile_remove(struct pidfh *pfh, int freeit);
+
+static int
+pidfile_verify(struct pidfh *pfh)
+{
+ struct stat sb;
+ int fd;
+
+ if (pfh == NULL || pfh->pf_fd == -1)
+ return (EDOOFUS);
+ /*
+ * Check remembered descriptor.
+ */
+ if (fstat(pfh->pf_fd, &sb) == -1)
+ return (errno);
+ if (sb.st_dev != pfh->pf_dev || sb.st_ino != pfh->pf_ino)
+ return (EDOOFUS);
+ return (0);
+}
+
+static int
+pidfile_read(const char *path, pid_t *pidptr)
+{
+ char buf[16], *endptr;
+ int error, fd, i;
+
+ fd = open(path, O_RDONLY);
+ if (fd == -1)
+ return (errno);
+
+ i = read(fd, buf, sizeof(buf) - 1);
+ error = errno; /* Remember errno in case close() wants to change it. */
+ close(fd);
+ if (i == -1)
+ return (error);
+ buf[i] = '\0';
+
+ *pidptr = strtol(buf, &endptr, 10);
+ if (endptr != &buf[i])
+ return (EINVAL);
+
+ return (0);
+}
+
+struct pidfh *
+pidfile_open(const char *path, mode_t mode, pid_t *pidptr)
+{
+ struct pidfh *pfh;
+ struct stat sb;
+ int error, fd;
+
+ pfh = malloc(sizeof(*pfh));
+ if (pfh == NULL)
+ return (NULL);
+
+ if (path == NULL) {
+ snprintf(pfh->pf_path, sizeof(pfh->pf_path), "/var/run/%s.pid",
+ getprogname());
+ } else {
+ strlcpy(pfh->pf_path, path, sizeof(pfh->pf_path));
+ }
+ if (strlen(pfh->pf_path) == sizeof(pfh->pf_path) - 1) {
+ free(pfh);
+ errno = ENAMETOOLONG;
+ return (NULL);
+ }
+
+ /*
+ * Open the PID file and obtain exclusive lock.
+ * We truncate PID file here only to remove old PID immediatelly,
+ * PID file will be truncated again in pidfile_write(), so
+ * pidfile_write() can be called multiple times.
+ */
+ fd = open(pfh->pf_path,
+ O_WRONLY | O_CREAT | O_EXLOCK | O_TRUNC | O_NONBLOCK, mode);
+ if (fd == -1) {
+ if (errno == EWOULDBLOCK && pidptr != NULL) {
+ errno = pidfile_read(pfh->pf_path, pidptr);
+ if (errno == 0)
+ errno = EEXIST;
+ }
+ free(pfh);
+ return (NULL);
+ }
+ /*
+ * Remember file information, so in pidfile_write() we are sure we write
+ * to the proper descriptor.
+ */
+ if (fstat(fd, &sb) == -1) {
+ error = errno;
+ unlink(pfh->pf_path);
+ close(fd);
+ free(pfh);
+ errno = error;
+ return (NULL);
+ }
+
+ pfh->pf_fd = fd;
+ pfh->pf_dev = sb.st_dev;
+ pfh->pf_ino = sb.st_ino;
+
+ return (pfh);
+}
+
+int
+pidfile_write(struct pidfh *pfh)
+{
+ struct stat sb;
+ char pidstr[16];
+ int error, fd;
+
+ /*
+ * Check remembered descriptor, so we don't overwrite some other
+ * file if pidfile was closed and descriptor reused.
+ */
+ errno = pidfile_verify(pfh);
+ if (errno != 0) {
+ /*
+ * Don't close descriptor, because we are not sure if it's ours.
+ */
+ return (-1);
+ }
+ fd = pfh->pf_fd;
+
+ /*
+ * Truncate PID file, so multiple calls of pidfile_write() are allowed.
+ */
+ if (ftruncate(fd, 0) == -1) {
+ error = errno;
+ _pidfile_remove(pfh, 0);
+ errno = error;
+ return (-1);
+ }
+
+ snprintf(pidstr, sizeof(pidstr), "%u", getpid());
+ if (pwrite(fd, pidstr, strlen(pidstr), 0) != (ssize_t)strlen(pidstr)) {
+ error = errno;
+ _pidfile_remove(pfh, 0);
+ errno = error;
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+pidfile_close(struct pidfh *pfh)
+{
+ int error;
+
+ error = pidfile_verify(pfh);
+ if (error != 0) {
+ errno = error;
+ return (-1);
+ }
+
+ if (close(pfh->pf_fd) == -1)
+ error = errno;
+ free(pfh);
+ if (error != 0) {
+ errno = error;
+ return (-1);
+ }
+ return (0);
+}
+
+static int
+_pidfile_remove(struct pidfh *pfh, int freeit)
+{
+ int error;
+
+ error = pidfile_verify(pfh);
+ if (error != 0) {
+ errno = error;
+ return (-1);
+ }
+
+ if (unlink(pfh->pf_path) == -1)
+ error = errno;
+ if (flock(pfh->pf_fd, LOCK_UN) == -1) {
+ if (error == 0)
+ error = errno;
+ }
+ if (close(pfh->pf_fd) == -1) {
+ if (error == 0)
+ error = errno;
+ }
+ if (freeit)
+ free(pfh);
+ else
+ pfh->pf_fd = -1;
+ if (error != 0) {
+ errno = error;
+ return (-1);
+ }
+ return (0);
+}
+
+int
+pidfile_remove(struct pidfh *pfh)
+{
+
+ return (_pidfile_remove(pfh, 1));
+}
diff --git a/lib/libutil/property.3 b/lib/libutil/property.3
new file mode 100644
index 0000000..61eb153
--- /dev/null
+++ b/lib/libutil/property.3
@@ -0,0 +1,99 @@
+.\"
+.\" Copyright (c) 1998 Jordan Hubbard
+.\"
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this 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 7, 1998
+.Os
+.Dt PROPERTIES 3
+.Sh NAME
+.Nm properties_read ,
+.Nm propery_find ,
+.Nm properties_free
+.Nd "functions to allow creating simple property lists from ASCII file data"
+.Sh LIBRARY
+.Lb libutil
+.Sh SYNOPSIS
+.In sys/types.h
+.In libutil.h
+.Ft properties
+.Fn properties_read "int fd"
+.Ft char *
+.Fn property_find "properties list" "const char *name"
+.Ft void
+.Fn properties_free "properties list"
+.Sh DESCRIPTION
+.Bd -literal
+typedef struct _properties {
+ struct _properties *next;
+ char *name;
+ char *value;
+} *properties;
+.Ed
+.Pp
+The function
+.Fn properties_read
+reads
+.Fa name = value
+pairs from the file descriptor passed in
+.Fa fd
+and returns the head of a new property list, assuming that the
+file's contents have been parsed properly, or NULL in case
+of error.
+.Pp
+The
+.Fn property_find
+function returns the associated value string for the property named
+.Fa name
+if found, otherwise NULL.
+The value returned may be up to
+.Dv PROPERTY_MAX_VALUE
+bytes in length.
+.Pp
+The
+.Fn properties_free
+function is used to free the structure returned by
+.Fn properties_read
+when it is no longer needed.
+.Sh FILE FORMAT
+Each property in the file is assumed to have the format of
+.Fa name = value
+where
+.Fa name
+is an alphanumeric string (and any punctuation not including the `=' character)
+and
+.Fa value
+is an arbitary string of text terminated by a newline character.
+If newlines
+are desired, the entire value should be enclosed in { } (curly-bracket)
+characters.
+Any line beginning with a # or ; character is assumed to
+be a comment and will be ignored.
+.Sh SEE ALSO
+.Xr auth_getval 3
+.Sh AUTHORS
+.An Jordan Hubbard
+.Sh BUGS
+Simplistic.
diff --git a/lib/libutil/property.c b/lib/libutil/property.c
new file mode 100644
index 0000000..a944f9d
--- /dev/null
+++ b/lib/libutil/property.c
@@ -0,0 +1,259 @@
+/*
+ *
+ * Simple property list handling code.
+ *
+ * Copyright (c) 1998
+ * Jordan Hubbard. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * verbatim and that no modifications are made prior to this
+ * point in 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 OR HIS PETS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 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 <err.h>
+#include <libutil.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static properties
+property_alloc(char *name, char *value)
+{
+ properties n;
+
+ if ((n = (properties)malloc(sizeof(struct _property))) == NULL)
+ return (NULL);
+ n->next = NULL;
+ if (name != NULL) {
+ if ((n->name = strdup(name)) == NULL) {
+ free(n);
+ return (NULL);
+ }
+ } else
+ n->name = NULL;
+ if (value != NULL) {
+ if ((n->value = strdup(value)) == NULL) {
+ free(n->name);
+ free(n);
+ return (NULL);
+ }
+ } else
+ n->value = NULL;
+ return (n);
+}
+
+properties
+properties_read(int fd)
+{
+ properties head, ptr;
+ char hold_n[PROPERTY_MAX_NAME + 1];
+ char hold_v[PROPERTY_MAX_VALUE + 1];
+ char buf[BUFSIZ * 4];
+ int bp, n, v, max;
+ enum { LOOK, COMMENT, NAME, VALUE, MVALUE, COMMIT, FILL, STOP } state, last_state;
+ int ch = 0, blevel = 0;
+
+ n = v = bp = max = 0;
+ head = ptr = NULL;
+ state = last_state = LOOK;
+ while (state != STOP) {
+ if (state != COMMIT) {
+ if (bp == max) {
+ last_state = state;
+ state = FILL;
+ } else
+ ch = buf[bp++];
+ }
+ switch(state) {
+ case FILL:
+ if ((max = read(fd, buf, sizeof buf)) < 0) {
+ properties_free(head);
+ return (NULL);
+ }
+ if (max == 0) {
+ state = STOP;
+ } else {
+ /*
+ * Restore the state from before the fill (which will be
+ * initialised to LOOK for the first FILL). This ensures that
+ * if we were part-way through eg., a VALUE state, when the
+ * buffer ran out, that the previous operation will be allowed
+ * to complete.
+ */
+ state = last_state;
+ ch = buf[0];
+ bp = 0;
+ }
+ continue;
+
+ case LOOK:
+ if (isspace((unsigned char)ch))
+ continue;
+ /* Allow shell or lisp style comments */
+ else if (ch == '#' || ch == ';') {
+ state = COMMENT;
+ continue;
+ }
+ else if (isalnum((unsigned char)ch) || ch == '_') {
+ if (n >= PROPERTY_MAX_NAME) {
+ n = 0;
+ state = COMMENT;
+ }
+ else {
+ hold_n[n++] = ch;
+ state = NAME;
+ }
+ }
+ else
+ state = COMMENT; /* Ignore the rest of the line */
+ break;
+
+ case COMMENT:
+ if (ch == '\n')
+ state = LOOK;
+ break;
+
+ case NAME:
+ if (ch == '\n' || !ch) {
+ hold_n[n] = '\0';
+ hold_v[0] = '\0';
+ v = n = 0;
+ state = COMMIT;
+ }
+ else if (isspace((unsigned char)ch))
+ continue;
+ else if (ch == '=') {
+ hold_n[n] = '\0';
+ v = n = 0;
+ state = VALUE;
+ }
+ else
+ hold_n[n++] = ch;
+ break;
+
+ case VALUE:
+ if (v == 0 && ch == '\n') {
+ hold_v[v] = '\0';
+ v = n = 0;
+ state = COMMIT;
+ }
+ else if (v == 0 && isspace((unsigned char)ch))
+ continue;
+ else if (ch == '{') {
+ state = MVALUE;
+ ++blevel;
+ }
+ else if (ch == '\n' || !ch) {
+ hold_v[v] = '\0';
+ v = n = 0;
+ state = COMMIT;
+ }
+ else {
+ if (v >= PROPERTY_MAX_VALUE) {
+ state = COMMENT;
+ v = n = 0;
+ break;
+ }
+ else
+ hold_v[v++] = ch;
+ }
+ break;
+
+ case MVALUE:
+ /* multiline value */
+ if (v >= PROPERTY_MAX_VALUE) {
+ warn("properties_read: value exceeds max length");
+ state = COMMENT;
+ n = v = 0;
+ }
+ else if (ch == '}' && !--blevel) {
+ hold_v[v] = '\0';
+ v = n = 0;
+ state = COMMIT;
+ }
+ else {
+ hold_v[v++] = ch;
+ if (ch == '{')
+ ++blevel;
+ }
+ break;
+
+ case COMMIT:
+ if (head == NULL) {
+ if ((head = ptr = property_alloc(hold_n, hold_v)) == NULL)
+ return (NULL);
+ } else {
+ if ((ptr->next = property_alloc(hold_n, hold_v)) == NULL) {
+ properties_free(head);
+ return (NULL);
+ }
+ ptr = ptr->next;
+ }
+ state = LOOK;
+ v = n = 0;
+ break;
+
+ case STOP:
+ /* we don't handle this here, but this prevents warnings */
+ break;
+ }
+ }
+ if (head == NULL && (head = property_alloc(NULL, NULL)) == NULL)
+ return (NULL);
+
+ return (head);
+}
+
+char *
+property_find(properties list, const char *name)
+{
+ if (list == NULL || name == NULL || !name[0])
+ return (NULL);
+ while (list != NULL) {
+ if (list->name != NULL && strcmp(list->name, name) == 0)
+ return (list->value);
+ list = list->next;
+ }
+ return (NULL);
+}
+
+void
+properties_free(properties list)
+{
+ properties tmp;
+
+ while (list) {
+ tmp = list->next;
+ if (list->name)
+ free(list->name);
+ if (list->value)
+ free(list->value);
+ free(list);
+ list = tmp;
+ }
+}
diff --git a/lib/libutil/pty.3 b/lib/libutil/pty.3
new file mode 100644
index 0000000..35f0b82
--- /dev/null
+++ b/lib/libutil/pty.3
@@ -0,0 +1,149 @@
+.\"
+.\" Copyright (c) 1996 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 December 29, 1996
+.Os
+.Dt PTY 3
+.Sh NAME
+.Nm openpty ,
+.Nm forkpty
+.Nd auxiliary functions to obtain a pseudo-terminal
+.Sh LIBRARY
+.Lb libutil
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/ioctl.h
+.In termios.h
+.In libutil.h
+.Ft int
+.Fn openpty "int *amaster" "int *aslave" "char *name" "struct termios *termp" "struct winsize *winp"
+.Ft int
+.Fn forkpty "int *amaster" "char *name" "struct termios *termp" "struct winsize *winp"
+.Sh DESCRIPTION
+The function
+.Fn openpty
+attempts to obtain the next available pseudo-terminal from the system (see
+.Xr pty 4 ) .
+If it successfully finds one, it subsequently tries to change the
+ownership of the slave device to the real UID of the current process,
+the group membership to the group
+.Dq tty
+(if such a group exists in the system), the access permissions for
+reading and writing by the owner, and for writing by the group, and to
+invalidate any current use of the line by calling
+.Xr revoke 2 .
+.Pp
+If the argument
+.Fa name
+is not
+.Dv NULL ,
+.Fn openpty
+copies the pathname of the slave pty to this area.
+The caller is
+responsible for allocating the required space in this array.
+.Pp
+If the arguments
+.Fa termp
+or
+.Fa winp
+are not
+.Dv NULL ,
+.Fn openpty
+initializes the termios and window size settings from the structures
+these arguments point to, respectively.
+.Pp
+Upon return, the open file descriptors for the master and slave side
+of the pty are returned in the locations pointed to by
+.Fa amaster
+and
+.Fa aslave ,
+respectively.
+.Pp
+The
+.Fn forkpty
+function first calls
+.Fn openpty
+to obtain the next available pseudo-terminal from the system.
+Upon success,
+it forks off a new process.
+In the child process, it closes the descriptor
+for the master side of the pty, and calls
+.Xr login_tty 3
+for the slave pty.
+In the parent process, it closes the descriptor for the
+slave side of the pty.
+The arguments
+.Fa amaster ,
+.Fa name ,
+.Fa termp ,
+and
+.Fa winp
+have the same meaning as described for
+.Fn openpty .
+.Sh RETURN VALUES
+The
+.Fn openpty
+function returns 0 on success, or -1 on failure.
+.Pp
+The
+.Fn forkpty
+function returns -1 on failure, 0 in the slave process, and the process ID of
+the slave process in the parent process.
+.Sh ERRORS
+On failure,
+.Fn openpty
+will set the global variable
+.Dv errno
+to
+.Er ENOENT .
+.Pp
+In addition to this,
+.Fn forkpty
+may set it to any value as described for
+.Xr fork 2 .
+.Sh SEE ALSO
+.Xr chmod 2 ,
+.Xr chown 2 ,
+.Xr fork 2 ,
+.Xr getuid 2 ,
+.Xr open 2 ,
+.Xr revoke 2 ,
+.Xr login_tty 3 ,
+.Xr pty 4 ,
+.Xr termios 4 ,
+.Xr group 5
+.Sh BUGS
+The calling process must have an effective UID of super-user in order
+to perform all the intended actions.
+No notification will occur if
+.Fn openpty
+or
+.Fn forkpty
+failed to proceed with one of the described steps, as long as they could
+at least allocate the pty at all (and create the new process in the case
+of
+.Fn forkpty ) .
diff --git a/lib/libutil/pty.c b/lib/libutil/pty.c
new file mode 100644
index 0000000..553468c
--- /dev/null
+++ b/lib/libutil/pty.c
@@ -0,0 +1,172 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)pty.c 8.3 (Berkeley) 5/16/94";
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <libutil.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+int __use_pts(void);
+
+static int
+new_openpty(int *amaster, int *aslave, char *name, struct termios *termp,
+ struct winsize *winp)
+{
+ int master, slave;
+
+ master = posix_openpt(O_RDWR);
+ if (master == -1)
+ return (-1);
+
+ if (grantpt(master) == -1) {
+ close(master);
+ return (-1);
+ }
+
+ slave = open(ptsname(master), O_RDWR);
+ if (slave == -1) {
+ close(master);
+ return (-1);
+ }
+
+ if (unlockpt(master) == -1) {
+ close(master);
+ close(slave);
+ return (-1);
+ }
+
+ *amaster = master;
+ *aslave = slave;
+
+ if (name)
+ strcpy(name, ptsname(master));
+ if (termp)
+ tcsetattr(slave, TCSAFLUSH, termp);
+ if (winp)
+ ioctl(slave, TIOCSWINSZ, (char *)winp);
+
+ return (0);
+}
+
+int
+openpty(int *amaster, int *aslave, char *name, struct termios *termp, struct winsize *winp)
+{
+ char line[] = "/dev/ptyXX";
+ const char *cp1, *cp2;
+ int master, slave, ttygid;
+ struct group *gr;
+
+ if (__use_pts())
+ return (new_openpty(amaster, aslave, name, termp, winp));
+
+ if ((gr = getgrnam("tty")) != NULL)
+ ttygid = gr->gr_gid;
+ else
+ ttygid = -1;
+
+ for (cp1 = "pqrsPQRS"; *cp1; cp1++) {
+ line[8] = *cp1;
+ for (cp2 = "0123456789abcdefghijklmnopqrstuv"; *cp2; cp2++) {
+ line[5] = 'p';
+ line[9] = *cp2;
+ if ((master = open(line, O_RDWR, 0)) == -1) {
+ if (errno == ENOENT)
+ break; /* try the next pty group */
+ } else {
+ line[5] = 't';
+ (void) chown(line, getuid(), ttygid);
+ (void) chmod(line, S_IRUSR|S_IWUSR|S_IWGRP);
+ (void) revoke(line);
+ if ((slave = open(line, O_RDWR, 0)) != -1) {
+ *amaster = master;
+ *aslave = slave;
+ if (name)
+ strcpy(name, line);
+ if (termp)
+ (void) tcsetattr(slave,
+ TCSAFLUSH, termp);
+ if (winp)
+ (void) ioctl(slave, TIOCSWINSZ,
+ (char *)winp);
+ return (0);
+ }
+ (void) close(master);
+ }
+ }
+ }
+ errno = ENOENT; /* out of ptys */
+ return (-1);
+}
+
+int
+forkpty(int *amaster, char *name, struct termios *termp, struct winsize *winp)
+{
+ int master, slave, pid;
+
+ if (openpty(&master, &slave, name, termp, winp) == -1)
+ return (-1);
+ switch (pid = fork()) {
+ case -1:
+ return (-1);
+ case 0:
+ /*
+ * child
+ */
+ (void) close(master);
+ login_tty(slave);
+ return (0);
+ }
+ /*
+ * parent
+ */
+ *amaster = master;
+ (void) close(slave);
+ return (pid);
+}
diff --git a/lib/libutil/pw_util.c b/lib/libutil/pw_util.c
new file mode 100644
index 0000000..90c9d72
--- /dev/null
+++ b/lib/libutil/pw_util.c
@@ -0,0 +1,616 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 2002 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS 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. 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.
+ */
+
+#ifndef lint
+#if 0
+static const char sccsid[] = "@(#)pw_util.c 8.3 (Berkeley) 4/2/94";
+#endif
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif /* not lint */
+
+/*
+ * This file is used by all the "password" programs; vipw(8), chpass(1),
+ * and passwd(1).
+ */
+
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <libgen.h>
+#include <paths.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <libutil.h>
+
+static pid_t editpid = -1;
+static int lockfd = -1;
+static char masterpasswd[PATH_MAX];
+static char passwd_dir[PATH_MAX];
+static char tempname[PATH_MAX];
+static int initialized;
+
+#if 0
+void
+pw_cont(int sig)
+{
+
+ if (editpid != -1)
+ kill(editpid, sig);
+}
+#endif
+
+/*
+ * Initialize statics and set limits, signals & umask to try to avoid
+ * interruptions, crashes etc. that might expose passord data.
+ */
+int
+pw_init(const char *dir, const char *master)
+{
+#if 0
+ struct rlimit rlim;
+#endif
+
+ if (dir == NULL) {
+ strcpy(passwd_dir, _PATH_ETC);
+ } else {
+ if (strlen(dir) >= sizeof(passwd_dir)) {
+ errno = ENAMETOOLONG;
+ return (-1);
+ }
+ strcpy(passwd_dir, dir);
+ }
+
+ if (master == NULL) {
+ if (dir == NULL) {
+ strcpy(masterpasswd, _PATH_MASTERPASSWD);
+ } else if (snprintf(masterpasswd, sizeof(masterpasswd), "%s/%s",
+ passwd_dir, _MASTERPASSWD) > (int)sizeof(masterpasswd)) {
+ errno = ENAMETOOLONG;
+ return (-1);
+ }
+ } else {
+ if (strlen(master) >= sizeof(masterpasswd)) {
+ errno = ENAMETOOLONG;
+ return (-1);
+ }
+ strcpy(masterpasswd, master);
+ }
+
+ /*
+ * The code that follows is extremely disruptive to the calling
+ * process, and is therefore disabled until someone can conceive
+ * of a realistic scenario where it would fend off a compromise.
+ * Race conditions concerning the temporary files can be guarded
+ * against in other ways than masking signals (by checking stat(2)
+ * results after creation).
+ */
+#if 0
+ /* Unlimited resource limits. */
+ rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
+ (void)setrlimit(RLIMIT_CPU, &rlim);
+ (void)setrlimit(RLIMIT_FSIZE, &rlim);
+ (void)setrlimit(RLIMIT_STACK, &rlim);
+ (void)setrlimit(RLIMIT_DATA, &rlim);
+ (void)setrlimit(RLIMIT_RSS, &rlim);
+
+ /* Don't drop core (not really necessary, but GP's). */
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ (void)setrlimit(RLIMIT_CORE, &rlim);
+
+ /* Turn off signals. */
+ (void)signal(SIGALRM, SIG_IGN);
+ (void)signal(SIGHUP, SIG_IGN);
+ (void)signal(SIGINT, SIG_IGN);
+ (void)signal(SIGPIPE, SIG_IGN);
+ (void)signal(SIGQUIT, SIG_IGN);
+ (void)signal(SIGTERM, SIG_IGN);
+ (void)signal(SIGCONT, pw_cont);
+
+ /* Create with exact permissions. */
+ (void)umask(0);
+#endif
+ initialized = 1;
+ return (0);
+}
+
+/*
+ * Lock the master password file.
+ */
+int
+pw_lock(void)
+{
+
+ if (*masterpasswd == '\0')
+ return (-1);
+
+ /*
+ * If the master password file doesn't exist, the system is hosed.
+ * Might as well try to build one. Set the close-on-exec bit so
+ * that users can't get at the encrypted passwords while editing.
+ * Open should allow flock'ing the file; see 4.4BSD. XXX
+ */
+ for (;;) {
+ struct stat st;
+
+ lockfd = open(masterpasswd, O_RDONLY, 0);
+ if (lockfd < 0 || fcntl(lockfd, F_SETFD, 1) == -1)
+ err(1, "%s", masterpasswd);
+ /* XXX vulnerable to race conditions */
+ if (flock(lockfd, LOCK_EX|LOCK_NB) == -1) {
+ if (errno == EWOULDBLOCK) {
+ errx(1, "the password db file is busy");
+ } else {
+ err(1, "could not lock the passwd file: ");
+ }
+ }
+
+ /*
+ * If the password file was replaced while we were trying to
+ * get the lock, our hardlink count will be 0 and we have to
+ * close and retry.
+ */
+ if (fstat(lockfd, &st) == -1)
+ err(1, "fstat() failed: ");
+ if (st.st_nlink != 0)
+ break;
+ close(lockfd);
+ lockfd = -1;
+ }
+ return (lockfd);
+}
+
+/*
+ * Create and open a presumably safe temp file for editing the password
+ * data, and copy the master password file into it.
+ */
+int
+pw_tmp(int mfd)
+{
+ char buf[8192];
+ ssize_t nr;
+ const char *p;
+ int tfd;
+
+ if (*masterpasswd == '\0')
+ return (-1);
+ if ((p = strrchr(masterpasswd, '/')))
+ ++p;
+ else
+ p = masterpasswd;
+ if (snprintf(tempname, sizeof(tempname), "%.*spw.XXXXXX",
+ (int)(p - masterpasswd), masterpasswd) >= (int)sizeof(tempname)) {
+ errno = ENAMETOOLONG;
+ return (-1);
+ }
+ if ((tfd = mkstemp(tempname)) == -1)
+ return (-1);
+ if (mfd != -1) {
+ while ((nr = read(mfd, buf, sizeof(buf))) > 0)
+ if (write(tfd, buf, (size_t)nr) != nr)
+ break;
+ if (nr != 0) {
+ unlink(tempname);
+ *tempname = '\0';
+ close(tfd);
+ return (-1);
+ }
+ }
+ return (tfd);
+}
+
+/*
+ * Regenerate the password database.
+ */
+int
+pw_mkdb(const char *user)
+{
+ int pstat;
+ pid_t pid;
+
+ (void)fflush(stderr);
+ switch ((pid = fork())) {
+ case -1:
+ return (-1);
+ case 0:
+ /* child */
+ if (user == NULL)
+ execl(_PATH_PWD_MKDB, "pwd_mkdb", "-p",
+ "-d", passwd_dir, tempname, (char *)NULL);
+ else
+ execl(_PATH_PWD_MKDB, "pwd_mkdb", "-p",
+ "-d", passwd_dir, "-u", user, tempname,
+ (char *)NULL);
+ _exit(1);
+ /* NOTREACHED */
+ default:
+ /* parent */
+ break;
+ }
+ if (waitpid(pid, &pstat, 0) == -1)
+ return (-1);
+ if (WIFEXITED(pstat) && WEXITSTATUS(pstat) == 0)
+ return (0);
+ errno = 0;
+ return (-1);
+}
+
+/*
+ * Edit the temp file. Return -1 on error, >0 if the file was modified, 0
+ * if it was not.
+ */
+int
+pw_edit(int notsetuid)
+{
+ struct sigaction sa, sa_int, sa_quit;
+ sigset_t oldsigset, sigset;
+ struct stat st1, st2;
+ const char *editor;
+ int pstat;
+
+ if ((editor = getenv("EDITOR")) == NULL)
+ editor = _PATH_VI;
+ if (stat(tempname, &st1) == -1)
+ return (-1);
+ sa.sa_handler = SIG_IGN;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+ sigaction(SIGINT, &sa, &sa_int);
+ sigaction(SIGQUIT, &sa, &sa_quit);
+ sigemptyset(&sigset);
+ sigaddset(&sigset, SIGCHLD);
+ sigprocmask(SIG_BLOCK, &sigset, &oldsigset);
+ switch ((editpid = fork())) {
+ case -1:
+ return (-1);
+ case 0:
+ sigaction(SIGINT, &sa_int, NULL);
+ sigaction(SIGQUIT, &sa_quit, NULL);
+ sigprocmask(SIG_SETMASK, &oldsigset, NULL);
+ if (notsetuid) {
+ (void)setgid(getgid());
+ (void)setuid(getuid());
+ }
+ errno = 0;
+ execlp(editor, basename(editor), tempname, (char *)NULL);
+ _exit(errno);
+ default:
+ /* parent */
+ break;
+ }
+ for (;;) {
+ if (waitpid(editpid, &pstat, WUNTRACED) == -1) {
+ if (errno == EINTR)
+ continue;
+ unlink(tempname);
+ editpid = -1;
+ break;
+ } else if (WIFSTOPPED(pstat)) {
+ raise(WSTOPSIG(pstat));
+ } else if (WIFEXITED(pstat) && WEXITSTATUS(pstat) == 0) {
+ editpid = -1;
+ break;
+ } else {
+ unlink(tempname);
+ editpid = -1;
+ break;
+ }
+ }
+ sigaction(SIGINT, &sa_int, NULL);
+ sigaction(SIGQUIT, &sa_quit, NULL);
+ sigprocmask(SIG_SETMASK, &oldsigset, NULL);
+ if (stat(tempname, &st2) == -1)
+ return (-1);
+ return (st1.st_mtime != st2.st_mtime);
+}
+
+/*
+ * Clean up. Preserve errno for the caller's convenience.
+ */
+void
+pw_fini(void)
+{
+ int serrno, status;
+
+ if (!initialized)
+ return;
+ initialized = 0;
+ serrno = errno;
+ if (editpid != -1) {
+ kill(editpid, SIGTERM);
+ kill(editpid, SIGCONT);
+ waitpid(editpid, &status, 0);
+ editpid = -1;
+ }
+ if (*tempname != '\0') {
+ unlink(tempname);
+ *tempname = '\0';
+ }
+ if (lockfd != -1)
+ close(lockfd);
+ errno = serrno;
+}
+
+/*
+ * Compares two struct pwds.
+ */
+int
+pw_equal(const struct passwd *pw1, const struct passwd *pw2)
+{
+ return (strcmp(pw1->pw_name, pw2->pw_name) == 0 &&
+ pw1->pw_uid == pw2->pw_uid &&
+ pw1->pw_gid == pw2->pw_gid &&
+ strcmp(pw1->pw_class, pw2->pw_class) == 0 &&
+ pw1->pw_change == pw2->pw_change &&
+ pw1->pw_expire == pw2->pw_expire &&
+ strcmp(pw1->pw_gecos, pw2->pw_gecos) == 0 &&
+ strcmp(pw1->pw_dir, pw2->pw_dir) == 0 &&
+ strcmp(pw1->pw_shell, pw2->pw_shell) == 0);
+}
+
+/*
+ * Make a passwd line out of a struct passwd.
+ */
+char *
+pw_make(const struct passwd *pw)
+{
+ char *line;
+
+ asprintf(&line, "%s:%s:%ju:%ju:%s:%ju:%ju:%s:%s:%s", pw->pw_name,
+ pw->pw_passwd, (uintmax_t)pw->pw_uid, (uintmax_t)pw->pw_gid,
+ pw->pw_class, (uintmax_t)pw->pw_change, (uintmax_t)pw->pw_expire,
+ pw->pw_gecos, pw->pw_dir, pw->pw_shell);
+ return line;
+}
+
+/*
+ * Copy password file from one descriptor to another, replacing or adding
+ * a single record on the way.
+ */
+int
+pw_copy(int ffd, int tfd, const struct passwd *pw, struct passwd *old_pw)
+{
+ char buf[8192], *end, *line, *p, *q, *r, t;
+ struct passwd *fpw;
+ size_t len;
+ int eof, readlen;
+
+ if ((line = pw_make(pw)) == NULL)
+ return (-1);
+
+ eof = 0;
+ len = 0;
+ p = q = end = buf;
+ for (;;) {
+ /* find the end of the current line */
+ for (p = q; q < end && *q != '\0'; ++q)
+ if (*q == '\n')
+ break;
+
+ /* if we don't have a complete line, fill up the buffer */
+ if (q >= end) {
+ if (eof)
+ break;
+ if ((size_t)(q - p) >= sizeof(buf)) {
+ warnx("passwd line too long");
+ errno = EINVAL; /* hack */
+ goto err;
+ }
+ if (p < end) {
+ q = memmove(buf, p, end - p);
+ end -= p - buf;
+ } else {
+ p = q = end = buf;
+ }
+ readlen = read(ffd, end, sizeof(buf) - (end - buf));
+ if (readlen == -1)
+ goto err;
+ else
+ len = (size_t)readlen;
+ if (len == 0 && p == buf)
+ break;
+ end += len;
+ len = end - buf;
+ if (len < (ssize_t)sizeof(buf)) {
+ eof = 1;
+ if (len > 0 && buf[len - 1] != '\n')
+ ++len, *end++ = '\n';
+ }
+ continue;
+ }
+
+ /* is it a blank line or a comment? */
+ for (r = p; r < q && isspace(*r); ++r)
+ /* nothing */ ;
+ if (r == q || *r == '#') {
+ /* yep */
+ if (write(tfd, p, q - p + 1) != q - p + 1)
+ goto err;
+ ++q;
+ continue;
+ }
+
+ /* is it the one we're looking for? */
+ t = *q;
+ *q = '\0';
+ fpw = pw_scan(r, PWSCAN_MASTER);
+ *q = t;
+ if (strcmp(fpw->pw_name, pw->pw_name) != 0) {
+ /* nope */
+ free(fpw);
+ if (write(tfd, p, q - p + 1) != q - p + 1)
+ goto err;
+ ++q;
+ continue;
+ }
+ if (old_pw && !pw_equal(fpw, old_pw)) {
+ warnx("entry inconsistent");
+ free(fpw);
+ errno = EINVAL; /* hack */
+ goto err;
+ }
+ free(fpw);
+
+ /* it is, replace it */
+ len = strlen(line);
+ if (write(tfd, line, len) != (int)len)
+ goto err;
+
+ /* we're done, just copy the rest over */
+ for (;;) {
+ if (write(tfd, q, end - q) != end - q)
+ goto err;
+ q = buf;
+ readlen = read(ffd, buf, sizeof(buf));
+ if (readlen == 0)
+ break;
+ else
+ len = (size_t)readlen;
+ if (readlen == -1)
+ goto err;
+ end = buf + len;
+ }
+ goto done;
+ }
+
+ /* if we got here, we have a new entry */
+ len = strlen(line);
+ if ((size_t)write(tfd, line, len) != len ||
+ write(tfd, "\n", 1) != 1)
+ goto err;
+ done:
+ free(line);
+ return (0);
+ err:
+ free(line);
+ return (-1);
+}
+
+/*
+ * Return the current value of tempname.
+ */
+const char *
+pw_tempname(void)
+{
+
+ return (tempname);
+}
+
+/*
+ * Duplicate a struct passwd.
+ */
+struct passwd *
+pw_dup(const struct passwd *pw)
+{
+ struct passwd *npw;
+ ssize_t len;
+
+ len = sizeof(*npw) +
+ (pw->pw_name ? strlen(pw->pw_name) + 1 : 0) +
+ (pw->pw_passwd ? strlen(pw->pw_passwd) + 1 : 0) +
+ (pw->pw_class ? strlen(pw->pw_class) + 1 : 0) +
+ (pw->pw_gecos ? strlen(pw->pw_gecos) + 1 : 0) +
+ (pw->pw_dir ? strlen(pw->pw_dir) + 1 : 0) +
+ (pw->pw_shell ? strlen(pw->pw_shell) + 1 : 0);
+ if ((npw = malloc((size_t)len)) == NULL)
+ return (NULL);
+ memcpy(npw, pw, sizeof(*npw));
+ len = sizeof(*npw);
+ if (pw->pw_name) {
+ npw->pw_name = ((char *)npw) + len;
+ len += sprintf(npw->pw_name, "%s", pw->pw_name) + 1;
+ }
+ if (pw->pw_passwd) {
+ npw->pw_passwd = ((char *)npw) + len;
+ len += sprintf(npw->pw_passwd, "%s", pw->pw_passwd) + 1;
+ }
+ if (pw->pw_class) {
+ npw->pw_class = ((char *)npw) + len;
+ len += sprintf(npw->pw_class, "%s", pw->pw_class) + 1;
+ }
+ if (pw->pw_gecos) {
+ npw->pw_gecos = ((char *)npw) + len;
+ len += sprintf(npw->pw_gecos, "%s", pw->pw_gecos) + 1;
+ }
+ if (pw->pw_dir) {
+ npw->pw_dir = ((char *)npw) + len;
+ len += sprintf(npw->pw_dir, "%s", pw->pw_dir) + 1;
+ }
+ if (pw->pw_shell) {
+ npw->pw_shell = ((char *)npw) + len;
+ len += sprintf(npw->pw_shell, "%s", pw->pw_shell) + 1;
+ }
+ return (npw);
+}
+
+#include "pw_scan.h"
+
+/*
+ * Wrapper around an internal libc function
+ */
+struct passwd *
+pw_scan(const char *line, int flags)
+{
+ struct passwd pw, *ret;
+ char *bp;
+
+ if ((bp = strdup(line)) == NULL)
+ return (NULL);
+ if (!__pw_scan(bp, &pw, flags)) {
+ free(bp);
+ return (NULL);
+ }
+ ret = pw_dup(&pw);
+ free(bp);
+ return (ret);
+}
diff --git a/lib/libutil/realhostname.3 b/lib/libutil/realhostname.3
new file mode 100644
index 0000000..fd64d4c
--- /dev/null
+++ b/lib/libutil/realhostname.3
@@ -0,0 +1,105 @@
+.\" Copyright (c) 1999 Brian Somers <brian@Awfulhak.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 6, 1999
+.Os
+.Dt REALHOSTNAME 3
+.Sh NAME
+.Nm realhostname
+.Nd "convert an IP number to the real host name"
+.Sh LIBRARY
+.Lb libutil
+.Sh SYNOPSIS
+.In sys/types.h
+.In netinet/in.h
+.In libutil.h
+.Ft int
+.Fn realhostname "char *host" "size_t hsize" "const struct in_addr *ip"
+.Sh DESCRIPTION
+The function
+.Fn realhostname
+converts
+.Ar ip
+to the corresponding host name.
+This is done by resolving
+.Ar ip
+to a host name and then ensuring that the host name resolves
+back to
+.Ar ip .
+.Pp
+.Ar host
+must point to a buffer of at least
+.Ar hsize
+bytes, and will always be written to by this function.
+.Pp
+If the name resolution does not work both ways or if the host name is longer
+than
+.Ar hsize
+bytes,
+.Xr inet_ntoa 3
+is used to convert
+.Ar ip
+to an ASCII form.
+.Pp
+If the string written to
+.Ar host
+is
+.Ar hsize
+bytes long,
+.Ar host
+will not be NUL terminated.
+.Sh RETURN VALUES
+The
+.Fn realhostname
+function will return one of the following constants which are defined in
+.In libutil.h :
+.Pp
+.Bl -tag -width XXX -offset XXX
+.It Li HOSTNAME_FOUND
+A valid host name was found.
+.It Li HOSTNAME_INCORRECTNAME
+A host name was found, but it did not resolve back to the passed
+.Ar ip .
+.Ar host
+now contains the numeric value of
+.Ar ip .
+.It Li HOSTNAME_INVALIDADDR
+.Ar ip
+could not be resolved.
+.Ar host
+now contains the numeric value of
+.Ar ip .
+.It Li HOSTNAME_INVALIDNAME
+A host name was found, but it could not be resolved back to any ip number.
+.Ar host
+now contains the numeric value of
+.Ar ip .
+.El
+.Sh SEE ALSO
+.Xr gethostbyaddr 3 ,
+.Xr gethostbyname 3 ,
+.Xr inet_ntoa 3 ,
+.Xr realhostname_sa 3
diff --git a/lib/libutil/realhostname.c b/lib/libutil/realhostname.c
new file mode 100644
index 0000000..6a1b82f
--- /dev/null
+++ b/lib/libutil/realhostname.c
@@ -0,0 +1,186 @@
+/*-
+ * Copyright (c) 1999 Brian Somers <brian@Awfulhak.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 <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include "libutil.h"
+
+struct sockinet {
+ u_char si_len;
+ u_char si_family;
+ u_short si_port;
+};
+
+int
+realhostname(char *host, size_t hsize, const struct in_addr *ip)
+{
+ char trimmed[MAXHOSTNAMELEN];
+ int result;
+ struct hostent *hp;
+
+ result = HOSTNAME_INVALIDADDR;
+ hp = gethostbyaddr((const char *)ip, sizeof(*ip), AF_INET);
+
+ if (hp != NULL) {
+ strlcpy(trimmed, hp->h_name, sizeof(trimmed));
+ trimdomain(trimmed, strlen(trimmed));
+ if (strlen(trimmed) <= hsize) {
+ char lookup[MAXHOSTNAMELEN];
+
+ strncpy(lookup, hp->h_name, sizeof(lookup) - 1);
+ lookup[sizeof(lookup) - 1] = '\0';
+ hp = gethostbyname(lookup);
+ if (hp == NULL)
+ result = HOSTNAME_INVALIDNAME;
+ else for (; ; hp->h_addr_list++) {
+ if (*hp->h_addr_list == NULL) {
+ result = HOSTNAME_INCORRECTNAME;
+ break;
+ }
+ if (!memcmp(*hp->h_addr_list, ip, sizeof(*ip))) {
+ strncpy(host, trimmed, hsize);
+ return HOSTNAME_FOUND;
+ }
+ }
+ }
+ }
+
+ strncpy(host, inet_ntoa(*ip), hsize);
+
+ return result;
+}
+
+int
+realhostname_sa(char *host, size_t hsize, struct sockaddr *addr, int addrlen)
+{
+ int result, error;
+ char buf[NI_MAXHOST];
+ struct sockaddr_in lsin;
+
+ result = HOSTNAME_INVALIDADDR;
+
+#ifdef INET6
+ /* IPv4 mapped IPv6 addr consideraton, specified in rfc2373. */
+ if (addr->sa_family == AF_INET6 &&
+ addrlen == sizeof(struct sockaddr_in6) &&
+ IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)addr)->sin6_addr)) {
+ struct sockaddr_in6 *sin6;
+
+ sin6 = (struct sockaddr_in6 *)addr;
+
+ memset(&lsin, 0, sizeof(lsin));
+ lsin.sin_len = sizeof(struct sockaddr_in);
+ lsin.sin_family = AF_INET;
+ lsin.sin_port = sin6->sin6_port;
+ memcpy(&lsin.sin_addr, &sin6->sin6_addr.s6_addr[12],
+ sizeof(struct in_addr));
+ addr = (struct sockaddr *)&lsin;
+ addrlen = lsin.sin_len;
+ }
+#endif
+
+ error = getnameinfo(addr, addrlen, buf, sizeof(buf), NULL, 0,
+ NI_NAMEREQD);
+ if (error == 0) {
+ struct addrinfo hints, *res, *ores;
+ struct sockaddr *sa;
+
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = addr->sa_family;
+ hints.ai_flags = AI_CANONNAME | AI_PASSIVE;
+ hints.ai_socktype = SOCK_STREAM;
+
+ error = getaddrinfo(buf, NULL, &hints, &res);
+ if (error) {
+ result = HOSTNAME_INVALIDNAME;
+ goto numeric;
+ }
+ for (ores = res; ; res = res->ai_next) {
+ if (res == NULL) {
+ freeaddrinfo(ores);
+ result = HOSTNAME_INCORRECTNAME;
+ goto numeric;
+ }
+ sa = res->ai_addr;
+ if (sa == NULL) {
+ freeaddrinfo(ores);
+ result = HOSTNAME_INCORRECTNAME;
+ goto numeric;
+ }
+ if (sa->sa_len == addrlen &&
+ sa->sa_family == addr->sa_family) {
+ ((struct sockinet *)sa)->si_port = ((struct sockinet *)addr)->si_port;
+#ifdef INET6
+ /*
+ * XXX: sin6_socpe_id may not been
+ * filled by DNS
+ */
+ if (sa->sa_family == AF_INET6 &&
+ ((struct sockaddr_in6 *)sa)->sin6_scope_id == 0)
+ ((struct sockaddr_in6 *)sa)->sin6_scope_id = ((struct sockaddr_in6 *)addr)->sin6_scope_id;
+#endif
+ if (!memcmp(sa, addr, sa->sa_len)) {
+ result = HOSTNAME_FOUND;
+ if (ores->ai_canonname == NULL) {
+ freeaddrinfo(ores);
+ goto numeric;
+ }
+ strlcpy(buf, ores->ai_canonname,
+ sizeof(buf));
+ trimdomain(buf, hsize);
+ if (strlen(buf) > hsize &&
+ addr->sa_family == AF_INET) {
+ freeaddrinfo(ores);
+ goto numeric;
+ }
+ strncpy(host, buf, hsize);
+ break;
+ }
+ }
+ }
+ freeaddrinfo(ores);
+ } else {
+ numeric:
+ if (getnameinfo(addr, addrlen, buf, sizeof(buf), NULL, 0,
+ NI_NUMERICHOST) == 0)
+ strncpy(host, buf, hsize);
+ }
+
+ return result;
+}
+
+
diff --git a/lib/libutil/realhostname_sa.3 b/lib/libutil/realhostname_sa.3
new file mode 100644
index 0000000..9f7f0df
--- /dev/null
+++ b/lib/libutil/realhostname_sa.3
@@ -0,0 +1,133 @@
+.\" Copyright (C) 1995, 1996, 1997, 1998, 1999, and 2000 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 (c) 1999 Brian Somers <brian@Awfulhak.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 11, 2000
+.Os
+.Dt REALHOSTNAME_SA 3
+.Sh NAME
+.Nm realhostname_sa
+.Nd "convert a"
+.Vt "struct sockaddr"
+to the real host name
+.Sh LIBRARY
+.Lb libutil
+.Sh SYNOPSIS
+.In sys/types.h
+.In netinet/in.h
+.In libutil.h
+.Ft int
+.Fn realhostname_sa "char *host" "size_t hsize" "struct sockaddr *addr" "int addrlen"
+.Sh DESCRIPTION
+The function
+.Fn realhostname_sa
+converts
+.Ar addr
+to the corresponding host name.
+This is done by resolving
+.Ar addr
+to a host name and then ensuring that the host name resolves
+back to
+.Ar addr .
+.Pp
+.Ar host
+must point to a buffer of at least
+.Ar hsize
+bytes, and will always be written to by this function.
+.Pp
+If the name resolution does not work both ways or if the host name is longer
+than
+.Ar hsize
+bytes,
+.Xr getnameinfo 3
+with NI_NUMERICHOST specified, is used to convert
+.Ar addr
+to an ASCII form.
+.Pp
+If the string written to
+.Ar host
+is
+.Ar hsize
+bytes long,
+.Ar host
+will not be NUL terminated.
+.Sh RETURN VALUES
+The
+.Fn realhostname_sa
+function will return one of the following constants which are defined in
+.In libutil.h :
+.Pp
+.Bl -tag -width XXX -offset XXX
+.It Li HOSTNAME_FOUND
+A valid host name was found.
+.It Li HOSTNAME_INCORRECTNAME
+A host name was found, but it did not resolve back to the passed
+.Ar ip .
+.Ar host
+now contains the numeric value of
+.Ar ip .
+.It Li HOSTNAME_INVALIDADDR
+.Ar ip
+could not be resolved.
+.Ar host
+now contains the numeric value of
+.Ar ip .
+.It Li HOSTNAME_INVALIDNAME
+A host name was found, but it could not be resolved back to any ip number.
+.Ar host
+now contains the numeric value of
+.Ar ip .
+.El
+.Sh SEE ALSO
+.Xr getaddrinfo 3 ,
+.Xr getnameinfo 3 ,
+.Xr realhostname 3
diff --git a/lib/libutil/stub.c b/lib/libutil/stub.c
new file mode 100644
index 0000000..ec78a35
--- /dev/null
+++ b/lib/libutil/stub.c
@@ -0,0 +1,46 @@
+/*-
+ * Copyright (c) 2000 Brian Fundakowski Feldman
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 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>
+
+/*
+ * Stub out what's in -lcrypt.
+ */
+
+#pragma weak crypt_set_format
+/* ARGSUSED */
+int
+crypt_set_format(const char *f __unused) {
+
+ if (getenv("CRYPT_DEBUG") != NULL)
+ fprintf(stderr, "crypt_set_format: eek, stub called!\n");
+ return (0);
+}
diff --git a/lib/libutil/trimdomain.3 b/lib/libutil/trimdomain.3
new file mode 100644
index 0000000..f01e884
--- /dev/null
+++ b/lib/libutil/trimdomain.3
@@ -0,0 +1,85 @@
+.\" Copyright (c) 1999 Brian Somers <brian@Awfulhak.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, 1999
+.Os
+.Dt TRIMDOMAIN 3
+.Sh NAME
+.Nm trimdomain
+.Nd "trim the current domain name from a host name"
+.Sh LIBRARY
+.Lb libutil
+.Sh SYNOPSIS
+.In sys/types.h
+.In libutil.h
+.Ft void
+.Fn trimdomain "char *fullhost" "int hostsize"
+.Sh DESCRIPTION
+The function
+.Fn trimdomain
+removes the current domain name from the passed
+.Ar fullhost
+name by writing a
+.Dv NUL
+character over the first period of the passed name.
+The current domain
+name is determined by calling
+.Xr gethostname 3
+and removing everything up to the first period.
+The name is determined
+the first time this function is called and is cached for future use.
+.Pp
+The
+.Fn trimdomain
+function will only trim the domain name if the passed
+.Ar fullname
+ends with the current domain name and if the length of the resulting host
+name does not exceed
+.Ar hostsize .
+.Pp
+If the passed
+.Ar fullname
+is actually a
+.Dv DISPLAY
+specification of the form
+.Sm off
+.Ar host . domain : nn Oo .
+.Ar nn
+.Oc
+.Sm on
+and the domain name is the same as the local domain name,
+.Fn trimdomain
+will remove the embedded domain name, copying the screen and display
+numbers to the end of the base host name and resulting in
+.Sm off
+.Ar host : nn Op . Ar nn .
+.Sm on
+.Sh RETURN VALUES
+The
+.Fn trimdomain
+function does not return a value.
+.Sh SEE ALSO
+.Xr gethostname 3
diff --git a/lib/libutil/trimdomain.c b/lib/libutil/trimdomain.c
new file mode 100644
index 0000000..85c27e0
--- /dev/null
+++ b/lib/libutil/trimdomain.c
@@ -0,0 +1,115 @@
+/*-
+ * Copyright (c) 2001 Brian Somers <brian@Awfulhak.org>
+ * Based on original work by Atsushi Murai <amurai@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 <libutil.h>
+#include <string.h>
+#include <unistd.h>
+
+static int isDISP(const char *);
+
+/*-
+ * Trim the current domain name from fullhost, but only if the result
+ * is less than or equal to hostsize in length.
+ *
+ * This function understands $DISPLAY type fullhosts.
+ *
+ * For example:
+ *
+ * trimdomain("abcde.my.domain", 5) -> "abcde"
+ * trimdomain("abcde.my.domain", 4) -> "abcde.my.domain"
+ * trimdomain("abcde.my.domain:0.0", 9) -> "abcde:0.0"
+ * trimdomain("abcde.my.domain:0.0", 8) -> "abcde.my.domain:0.0"
+ */
+void
+trimdomain(char *fullhost, int hostsize)
+{
+ static size_t dlen;
+ static int first = 1;
+ static char domain[MAXHOSTNAMELEN];
+ char *end, *s;
+ size_t len;
+
+ if (first) {
+ /* XXX: Should we assume that our domain is this persistent ? */
+ first = 0;
+ if (gethostname(domain, sizeof(domain) - 1) == 0 &&
+ (s = strchr(domain, '.')) != NULL)
+ memmove(domain, s + 1, strlen(s + 1) + 1);
+ else
+ domain[0] = '\0';
+ dlen = strlen(domain);
+ }
+
+ if (domain[0] == '\0')
+ return;
+
+ s = fullhost;
+ end = s + hostsize + 1;
+ if ((s = memchr(s, '.', (size_t)(end - s))) != NULL) {
+ if (strncasecmp(s + 1, domain, dlen) == 0) {
+ if (s[dlen + 1] == '\0') {
+ /* Found -- lose the domain. */
+ *s = '\0';
+ } else if (s[dlen + 1] == ':' &&
+ isDISP(s + dlen + 2) &&
+ (len = strlen(s + dlen + 1)) < (size_t)(end - s)) {
+ /* Found -- shuffle the DISPLAY back. */
+ memmove(s, s + dlen + 1, len + 1);
+ }
+ }
+ }
+}
+
+/*
+ * Is the given string NN or NN.NN where ``NN'' is an all-numeric string ?
+ */
+static int
+isDISP(const char *disp)
+{
+ size_t w;
+ int res;
+
+ w = strspn(disp, "0123456789");
+ res = 0;
+ if (w > 0) {
+ if (disp[w] == '\0')
+ res = 1; /* NN */
+ else if (disp[w] == '.') {
+ disp += w + 1;
+ w = strspn(disp, "0123456789");
+ if (w > 0 && disp[w] == '\0')
+ res = 1; /* NN.NN */
+ }
+ }
+ return (res);
+}
diff --git a/lib/libutil/uucplock.3 b/lib/libutil/uucplock.3
new file mode 100644
index 0000000..5f75c7f
--- /dev/null
+++ b/lib/libutil/uucplock.3
@@ -0,0 +1,183 @@
+.\"
+.\" Copyright (c) 1996 Brian Somers <brian@awfulhak.demon.co.uk>
+.\"
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this 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 March 30, 1997
+.Os
+.Dt UUCPLOCK 3
+.Sh NAME
+.Nm uu_lock ,
+.Nm uu_unlock ,
+.Nm uu_lockerr
+.Nd acquire and release control of a serial device
+.Sh LIBRARY
+.Lb libutil
+.Sh SYNOPSIS
+.In sys/types.h
+.In libutil.h
+.Ft int
+.Fn uu_lock "const char *ttyname"
+.Ft int
+.Fn uu_lock_txfr "const char *ttyname" "pid_t pid"
+.Ft int
+.Fn uu_unlock "const char *ttyname"
+.Ft const char *
+.Fn uu_lockerr "int uu_lockresult"
+.Sh DESCRIPTION
+The
+.Fn uu_lock
+function attempts to create a lock file called
+.Pa /var/spool/lock/LCK..
+with a suffix given by the passed
+.Fa ttyname .
+If the file already exists, it is expected to contain the process
+id of the locking program.
+.Pp
+If the file does not already exist, or the owning process given by
+the process id found in the lock file is no longer running,
+.Fn uu_lock
+will write its own process id into the file and return success.
+.Pp
+.Fn uu_lock_txfr
+transfers lock ownership to another process.
+.Fn uu_lock
+must have previously been successful.
+.Pp
+.Fn uu_unlock
+removes the lockfile created by
+.Fn uu_lock
+for the given
+.Fa ttyname .
+Care should be taken that
+.Fn uu_lock
+was successful before calling
+.Fn uu_unlock .
+.Pp
+.Fn uu_lockerr
+returns an error string representing the error
+.Fa uu_lockresult ,
+as returned from
+.Fn uu_lock .
+.Sh RETURN VALUES
+.Fn uu_unlock
+returns 0 on success and -1 on failure.
+.Pp
+.Fn uu_lock
+may return any of the following values:
+.Pp
+.Dv UU_LOCK_INUSE :
+The lock is in use by another process.
+.Pp
+.Dv UU_LOCK_OK :
+The lock was successfully created.
+.Pp
+.Dv UU_LOCK_OPEN_ERR :
+The lock file could not be opened via
+.Xr open 2 .
+.Pp
+.Dv UU_LOCK_READ_ERR :
+The lock file could not be read via
+.Xr read 2 .
+.Pp
+.Dv UU_LOCK_CREAT_ERR :
+Cannot create temporary lock file via
+.Xr creat 2 .
+.Pp
+.Dv UU_LOCK_WRITE_ERR :
+The current process id could not be written to the lock file via a call to
+.Xr write 2 .
+.Pp
+.Dv UU_LOCK_LINK_ERR :
+Cannot link temporary lock file via
+.Xr link 2 .
+.Pp
+.Dv UU_LOCK_TRY_ERR :
+Locking attempts are failed after 5 tries.
+.Pp
+If a value of
+.Dv UU_LOCK_OK
+is passed to
+.Fn uu_lockerr ,
+an empty string is returned.
+Otherwise, a string specifying
+the reason for failure is returned.
+.Fn uu_lockerr
+uses the current value of
+.Va errno
+to determine the exact error.
+Care should be made not to allow
+.Va errno
+to be changed between calls to
+.Fn uu_lock
+and
+.Fn uu_lockerr .
+.Pp
+.Fn uu_lock_txfr
+may return any of the following values:
+.Pp
+.Dv UU_LOCK_OK :
+The transfer was successful.
+The specified process now holds the device
+lock.
+.Pp
+.Dv UU_LOCK_OWNER_ERR :
+The current process does not already own a lock on the specified device.
+.Pp
+.Dv UU_LOCK_WRITE_ERR :
+The new process id could not be written to the lock file via a call to
+.Xr write 2 .
+.Sh ERRORS
+If
+.Fn uu_lock
+returns one of the error values above, the global value
+.Va errno
+can be used to determine the cause.
+Refer to the respective manual pages
+for further details.
+.Pp
+.Fn uu_unlock
+will set the global variable
+.Va errno
+to reflect the reason that the lock file could not be removed.
+Refer to the description of
+.Xr unlink 2
+for further details.
+.Sh SEE ALSO
+.Xr lseek 2 ,
+.Xr open 2 ,
+.Xr read 2 ,
+.Xr write 2
+.Sh BUGS
+It is possible that a stale lock is not recognised as such if a new
+processes is assigned the same processes id as the program that left
+the stale lock.
+.Pp
+The calling process must have write permissions to the
+.Pa /var/spool/lock
+directory.
+There is no mechanism in place to ensure that the
+permissions of this directory are the same as those of the
+serial devices that might be locked.
diff --git a/lib/libutil/uucplock.c b/lib/libutil/uucplock.c
new file mode 100644
index 0000000..71ea25e
--- /dev/null
+++ b/lib/libutil/uucplock.c
@@ -0,0 +1,230 @@
+/*
+ * 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. 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifndef lint
+static const char sccsid[] = "@(#)uucplock.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <dirent.h>
+#include <errno.h>
+#include <paths.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "libutil.h"
+
+#define MAXTRIES 5
+
+#define LOCKTMP "LCKTMP..%d"
+#define LOCKFMT "LCK..%s"
+
+#define GORET(level, val) { err = errno; uuerr = (val); \
+ goto __CONCAT(ret, level); }
+
+/* Forward declarations */
+static int put_pid (int fd, pid_t pid);
+static pid_t get_pid (int fd,int *err);
+
+/*
+ * uucp style locking routines
+ */
+
+int
+uu_lock(const char *tty_name)
+{
+ int fd, tmpfd, i;
+ pid_t pid, pid_old;
+ char lckname[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN],
+ lcktmpname[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN];
+ int err, uuerr;
+
+ pid = getpid();
+ (void)snprintf(lcktmpname, sizeof(lcktmpname), _PATH_UUCPLOCK LOCKTMP,
+ pid);
+ (void)snprintf(lckname, sizeof(lckname), _PATH_UUCPLOCK LOCKFMT,
+ tty_name);
+ if ((tmpfd = creat(lcktmpname, 0664)) < 0)
+ GORET(0, UU_LOCK_CREAT_ERR);
+
+ for (i = 0; i < MAXTRIES; i++) {
+ if (link (lcktmpname, lckname) < 0) {
+ if (errno != EEXIST)
+ GORET(1, UU_LOCK_LINK_ERR);
+ /*
+ * file is already locked
+ * check to see if the process holding the lock
+ * still exists
+ */
+ if ((fd = open(lckname, O_RDONLY)) < 0)
+ GORET(1, UU_LOCK_OPEN_ERR);
+
+ if ((pid_old = get_pid (fd, &err)) == -1)
+ GORET(2, UU_LOCK_READ_ERR);
+
+ close(fd);
+
+ if (kill(pid_old, 0) == 0 || errno != ESRCH)
+ GORET(1, UU_LOCK_INUSE);
+ /*
+ * The process that locked the file isn't running, so
+ * we'll lock it ourselves
+ */
+ (void)unlink(lckname);
+ } else {
+ if (!put_pid (tmpfd, pid))
+ GORET(3, UU_LOCK_WRITE_ERR);
+ break;
+ }
+ }
+ GORET(1, (i >= MAXTRIES) ? UU_LOCK_TRY_ERR : UU_LOCK_OK);
+
+ret3:
+ (void)unlink(lckname);
+ goto ret1;
+ret2:
+ (void)close(fd);
+ret1:
+ (void)close(tmpfd);
+ (void)unlink(lcktmpname);
+ret0:
+ errno = err;
+ return uuerr;
+}
+
+int
+uu_lock_txfr(const char *tty_name, pid_t pid)
+{
+ int fd, err;
+ char lckname[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN];
+
+ snprintf(lckname, sizeof(lckname), _PATH_UUCPLOCK LOCKFMT, tty_name);
+
+ if ((fd = open(lckname, O_RDWR)) < 0)
+ return UU_LOCK_OWNER_ERR;
+ if (get_pid(fd, &err) != getpid())
+ err = UU_LOCK_OWNER_ERR;
+ else {
+ lseek(fd, (off_t)0, SEEK_SET);
+ err = put_pid(fd, pid) ? 0 : UU_LOCK_WRITE_ERR;
+ }
+ close(fd);
+
+ return err;
+}
+
+int
+uu_unlock(const char *tty_name)
+{
+ char tbuf[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN];
+
+ (void)snprintf(tbuf, sizeof(tbuf), _PATH_UUCPLOCK LOCKFMT, tty_name);
+ return unlink(tbuf);
+}
+
+const char *
+uu_lockerr(int uu_lockresult)
+{
+ static char errbuf[128];
+ const char *fmt;
+
+ switch (uu_lockresult) {
+ case UU_LOCK_INUSE:
+ return "device in use";
+ case UU_LOCK_OK:
+ return "";
+ case UU_LOCK_OPEN_ERR:
+ fmt = "open error: %s";
+ break;
+ case UU_LOCK_READ_ERR:
+ fmt = "read error: %s";
+ break;
+ case UU_LOCK_CREAT_ERR:
+ fmt = "creat error: %s";
+ break;
+ case UU_LOCK_WRITE_ERR:
+ fmt = "write error: %s";
+ break;
+ case UU_LOCK_LINK_ERR:
+ fmt = "link error: %s";
+ break;
+ case UU_LOCK_TRY_ERR:
+ fmt = "too many tries: %s";
+ break;
+ case UU_LOCK_OWNER_ERR:
+ fmt = "not locking process: %s";
+ break;
+ default:
+ fmt = "undefined error: %s";
+ break;
+ }
+
+ (void)snprintf(errbuf, sizeof(errbuf), fmt, strerror(errno));
+ return errbuf;
+}
+
+static int
+put_pid(int fd, pid_t pid)
+{
+ char buf[32];
+ int len;
+
+ len = sprintf (buf, "%10d\n", (int)pid);
+ return write (fd, buf, (size_t)len) == len;
+}
+
+static pid_t
+get_pid(int fd, int *err)
+{
+ int bytes_read;
+ char buf[32];
+ pid_t pid;
+
+ bytes_read = read (fd, buf, sizeof (buf) - 1);
+ if (bytes_read > 0) {
+ buf[bytes_read] = '\0';
+ pid = (pid_t)strtol (buf, (char **) NULL, 10);
+ } else {
+ pid = -1;
+ *err = bytes_read ? errno : EINVAL;
+ }
+ return pid;
+}
+
+/* end of uucplock.c */
diff --git a/lib/libvgl/Makefile b/lib/libvgl/Makefile
new file mode 100644
index 0000000..6f88eeb
--- /dev/null
+++ b/lib/libvgl/Makefile
@@ -0,0 +1,41 @@
+# $FreeBSD$
+LIB= vgl
+SHLIB_MAJOR= 4
+CFLAGS+=-Wall -I${.CURDIR}
+SRCS= main.c simple.c bitmap.c text.c mouse.c keyboard.c
+INCS= vgl.h
+MAN= vgl.3
+MLINKS+= vgl.3 VGLBitmapAllocateBits.3 \
+ vgl.3 VGLBitmapCopy.3 \
+ vgl.3 VGLBitmapCreate.3 \
+ vgl.3 VGLBitmapDestroy.3 \
+ vgl.3 VGLBitmapPutChar.3 \
+ vgl.3 VGLBitmapString.3 \
+ vgl.3 VGLBlankDisplay.3 \
+ vgl.3 VGLBox.3 \
+ vgl.3 VGLCheckSwitch.3 \
+ vgl.3 VGLClear.3 \
+ vgl.3 VGLEllipse.3 \
+ vgl.3 VGLEnd.3 \
+ vgl.3 VGLFilledBox.3 \
+ vgl.3 VGLFilledEllipse.3 \
+ vgl.3 VGLGetXY.3 \
+ vgl.3 VGLInit.3 \
+ vgl.3 VGLLine.3 \
+ vgl.3 VGLKeyboardInit.3 \
+ vgl.3 VGLKeyboardEnd.3 \
+ vgl.3 VGLKeyboardGetCh.3 \
+ vgl.3 VGLMouseInit.3 \
+ vgl.3 VGLMouseMode.3 \
+ vgl.3 VGLMouseSetImage.3 \
+ vgl.3 VGLMouseSetStdImage.3 \
+ vgl.3 VGLMouseStatus.3 \
+ vgl.3 VGLPanScreen.3 \
+ vgl.3 VGLSetBorder.3 \
+ vgl.3 VGLSetPalette.3 \
+ vgl.3 VGLSetPaletteIndex.3 \
+ vgl.3 VGLSetVScreenSize.3 \
+ vgl.3 VGLSetXY.3 \
+ vgl.3 VGLTextSetFontFile.3
+
+.include <bsd.lib.mk>
diff --git a/lib/libvgl/bitmap.c b/lib/libvgl/bitmap.c
new file mode 100644
index 0000000..ec99d26
--- /dev/null
+++ b/lib/libvgl/bitmap.c
@@ -0,0 +1,406 @@
+/*-
+ * Copyright (c) 1991-1997 Søren Schmidt
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 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 <signal.h>
+#include <sys/fbio.h>
+#include "vgl.h"
+
+#define min(x, y) (((x) < (y)) ? (x) : (y))
+
+static byte mask[8] = {0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01};
+static int color2bit[16] = {0x00000000, 0x00000001, 0x00000100, 0x00000101,
+ 0x00010000, 0x00010001, 0x00010100, 0x00010101,
+ 0x01000000, 0x01000001, 0x01000100, 0x01000101,
+ 0x01010000, 0x01010001, 0x01010100, 0x01010101};
+
+static void
+WriteVerticalLine(VGLBitmap *dst, int x, int y, int width, byte *line)
+{
+ int i, pos, last, planepos, start_offset, end_offset, offset;
+ int len;
+ unsigned int word = 0;
+ byte *address;
+ byte *VGLPlane[4];
+
+ switch (dst->Type) {
+ case VIDBUF4:
+ case VIDBUF4S:
+ start_offset = (x & 0x07);
+ end_offset = (x + width) & 0x07;
+ i = (width + start_offset) / 8;
+ if (end_offset)
+ i++;
+ VGLPlane[0] = VGLBuf;
+ VGLPlane[1] = VGLPlane[0] + i;
+ VGLPlane[2] = VGLPlane[1] + i;
+ VGLPlane[3] = VGLPlane[2] + i;
+ pos = 0;
+ planepos = 0;
+ last = 8 - start_offset;
+ while (pos < width) {
+ word = 0;
+ while (pos < last && pos < width)
+ word = (word<<1) | color2bit[line[pos++]&0x0f];
+ VGLPlane[0][planepos] = word;
+ VGLPlane[1][planepos] = word>>8;
+ VGLPlane[2][planepos] = word>>16;
+ VGLPlane[3][planepos] = word>>24;
+ planepos++;
+ last += 8;
+ }
+ planepos--;
+ if (end_offset) {
+ word <<= (8 - end_offset);
+ VGLPlane[0][planepos] = word;
+ VGLPlane[1][planepos] = word>>8;
+ VGLPlane[2][planepos] = word>>16;
+ VGLPlane[3][planepos] = word>>24;
+ }
+ if (start_offset || end_offset)
+ width+=8;
+ width /= 8;
+ outb(0x3ce, 0x01); outb(0x3cf, 0x00); /* set/reset enable */
+ outb(0x3ce, 0x08); outb(0x3cf, 0xff); /* bit mask */
+ for (i=0; i<4; i++) {
+ outb(0x3c4, 0x02);
+ outb(0x3c5, 0x01<<i);
+ outb(0x3ce, 0x04);
+ outb(0x3cf, i);
+ pos = VGLAdpInfo.va_line_width*y + x/8;
+ if (dst->Type == VIDBUF4) {
+ if (end_offset)
+ VGLPlane[i][planepos] |= dst->Bitmap[pos+planepos] & mask[end_offset];
+ if (start_offset)
+ VGLPlane[i][0] |= dst->Bitmap[pos] & ~mask[start_offset];
+ bcopy(&VGLPlane[i][0], dst->Bitmap + pos, width);
+ } else { /* VIDBUF4S */
+ if (end_offset) {
+ offset = VGLSetSegment(pos + planepos);
+ VGLPlane[i][planepos] |= dst->Bitmap[offset] & mask[end_offset];
+ }
+ offset = VGLSetSegment(pos);
+ if (start_offset)
+ VGLPlane[i][0] |= dst->Bitmap[offset] & ~mask[start_offset];
+ for (last = width; ; ) {
+ len = min(VGLAdpInfo.va_window_size - offset, last);
+ bcopy(&VGLPlane[i][width - last], dst->Bitmap + offset, len);
+ pos += len;
+ last -= len;
+ if (last <= 0)
+ break;
+ offset = VGLSetSegment(pos);
+ }
+ }
+ }
+ break;
+ case VIDBUF8X:
+ address = dst->Bitmap + VGLAdpInfo.va_line_width * y + x/4;
+ for (i=0; i<4; i++) {
+ outb(0x3c4, 0x02);
+ outb(0x3c5, 0x01 << ((x + i)%4));
+ for (planepos=0, pos=i; pos<width; planepos++, pos+=4)
+ address[planepos] = line[pos];
+ if ((x + i)%4 == 3)
+ ++address;
+ }
+ break;
+ case VIDBUF8S:
+ pos = dst->VXsize * y + x;
+ while (width > 0) {
+ offset = VGLSetSegment(pos);
+ i = min(VGLAdpInfo.va_window_size - offset, width);
+ bcopy(line, dst->Bitmap + offset, i);
+ line += i;
+ pos += i;
+ width -= i;
+ }
+ break;
+ case VIDBUF16S:
+ case VIDBUF24S:
+ case VIDBUF32S:
+ width = width * dst->PixelBytes;
+ pos = (dst->VXsize * y + x) * dst->PixelBytes;
+ while (width > 0) {
+ offset = VGLSetSegment(pos);
+ i = min(VGLAdpInfo.va_window_size - offset, width);
+ bcopy(line, dst->Bitmap + offset, i);
+ line += i;
+ pos += i;
+ width -= i;
+ }
+ break;
+ case VIDBUF8:
+ case MEMBUF:
+ address = dst->Bitmap + dst->VXsize * y + x;
+ bcopy(line, address, width);
+ break;
+ case VIDBUF16:
+ case VIDBUF24:
+ case VIDBUF32:
+ address = dst->Bitmap + (dst->VXsize * y + x) * dst->PixelBytes;
+ bcopy(line, address, width * dst->PixelBytes);
+ break;
+ default:
+ ;
+ }
+}
+
+static void
+ReadVerticalLine(VGLBitmap *src, int x, int y, int width, byte *line)
+{
+ int i, bit, pos, count, planepos, start_offset, end_offset, offset;
+ int width2, len;
+ byte *address;
+ byte *VGLPlane[4];
+
+ switch (src->Type) {
+ case VIDBUF4S:
+ start_offset = (x & 0x07);
+ end_offset = (x + width) & 0x07;
+ count = (width + start_offset) / 8;
+ if (end_offset)
+ count++;
+ VGLPlane[0] = VGLBuf;
+ VGLPlane[1] = VGLPlane[0] + count;
+ VGLPlane[2] = VGLPlane[1] + count;
+ VGLPlane[3] = VGLPlane[2] + count;
+ for (i=0; i<4; i++) {
+ outb(0x3ce, 0x04);
+ outb(0x3cf, i);
+ pos = VGLAdpInfo.va_line_width*y + x/8;
+ for (width2 = count; width2 > 0; ) {
+ offset = VGLSetSegment(pos);
+ len = min(VGLAdpInfo.va_window_size - offset, width2);
+ bcopy(src->Bitmap + offset, &VGLPlane[i][count - width2], len);
+ pos += len;
+ width2 -= len;
+ }
+ }
+ goto read_planar;
+ case VIDBUF4:
+ address = src->Bitmap + VGLAdpInfo.va_line_width * y + x/8;
+ start_offset = (x & 0x07);
+ end_offset = (x + width) & 0x07;
+ count = (width + start_offset) / 8;
+ if (end_offset)
+ count++;
+ VGLPlane[0] = VGLBuf;
+ VGLPlane[1] = VGLPlane[0] + count;
+ VGLPlane[2] = VGLPlane[1] + count;
+ VGLPlane[3] = VGLPlane[2] + count;
+ for (i=0; i<4; i++) {
+ outb(0x3ce, 0x04);
+ outb(0x3cf, i);
+ bcopy(address, &VGLPlane[i][0], count);
+ }
+read_planar:
+ pos = 0;
+ planepos = 0;
+ bit = 7 - start_offset;
+ while (pos < width) {
+ for (; bit >= 0 && pos < width; bit--, pos++) {
+ line[pos] = (VGLPlane[0][planepos] & (1<<bit) ? 1 : 0) |
+ ((VGLPlane[1][planepos] & (1<<bit) ? 1 : 0) << 1) |
+ ((VGLPlane[2][planepos] & (1<<bit) ? 1 : 0) << 2) |
+ ((VGLPlane[3][planepos] & (1<<bit) ? 1 : 0) << 3);
+ }
+ planepos++;
+ bit = 7;
+ }
+ break;
+ case VIDBUF8X:
+ address = src->Bitmap + VGLAdpInfo.va_line_width * y + x/4;
+ for (i=0; i<4; i++) {
+ outb(0x3ce, 0x04);
+ outb(0x3cf, (x + i)%4);
+ for (planepos=0, pos=i; pos<width; planepos++, pos+=4)
+ line[pos] = address[planepos];
+ if ((x + i)%4 == 3)
+ ++address;
+ }
+ break;
+ case VIDBUF8S:
+ pos = src->VXsize * y + x;
+ while (width > 0) {
+ offset = VGLSetSegment(pos);
+ i = min(VGLAdpInfo.va_window_size - offset, width);
+ bcopy(src->Bitmap + offset, line, i);
+ line += i;
+ pos += i;
+ width -= i;
+ }
+ break;
+ case VIDBUF16S:
+ case VIDBUF24S:
+ case VIDBUF32S:
+ width = width * src->PixelBytes;
+ pos = (src->VXsize * y + x) * src->PixelBytes;
+ while (width > 0) {
+ offset = VGLSetSegment(pos);
+ i = min(VGLAdpInfo.va_window_size - offset, width);
+ bcopy(src->Bitmap + offset, line, i);
+ line += i;
+ pos += i;
+ width -= i;
+ }
+ break;
+ case VIDBUF8:
+ case MEMBUF:
+ address = src->Bitmap + src->VXsize * y + x;
+ bcopy(address, line, width);
+ break;
+ case VIDBUF16:
+ case VIDBUF24:
+ case VIDBUF32:
+ address = src->Bitmap + (src->VXsize * y + x) * src->PixelBytes;
+ bcopy(address, line, width * src->PixelBytes);
+ break;
+ default:
+ ;
+ }
+}
+
+int
+__VGLBitmapCopy(VGLBitmap *src, int srcx, int srcy,
+ VGLBitmap *dst, int dstx, int dsty, int width, int hight)
+{
+ int srcline, dstline;
+
+ if (srcx>src->VXsize || srcy>src->VYsize
+ || dstx>dst->VXsize || dsty>dst->VYsize)
+ return -1;
+ if (srcx < 0) {
+ width=width+srcx; dstx-=srcx; srcx=0;
+ }
+ if (srcy < 0) {
+ hight=hight+srcy; dsty-=srcy; srcy=0;
+ }
+ if (dstx < 0) {
+ width=width+dstx; srcx-=dstx; dstx=0;
+ }
+ if (dsty < 0) {
+ hight=hight+dsty; srcy-=dsty; dsty=0;
+ }
+ if (srcx+width > src->VXsize)
+ width=src->VXsize-srcx;
+ if (srcy+hight > src->VYsize)
+ hight=src->VYsize-srcy;
+ if (dstx+width > dst->VXsize)
+ width=dst->VXsize-dstx;
+ if (dsty+hight > dst->VYsize)
+ hight=dst->VYsize-dsty;
+ if (width < 0 || hight < 0)
+ return -1;
+ if (src->Type == MEMBUF) {
+ for (srcline=srcy, dstline=dsty; srcline<srcy+hight; srcline++, dstline++) {
+ WriteVerticalLine(dst, dstx, dstline, width,
+ (src->Bitmap+(srcline*src->VXsize)+srcx));
+ }
+ }
+ else if (dst->Type == MEMBUF) {
+ for (srcline=srcy, dstline=dsty; srcline<srcy+hight; srcline++, dstline++) {
+ ReadVerticalLine(src, srcx, srcline, width,
+ (dst->Bitmap+(dstline*dst->VXsize)+dstx));
+ }
+ }
+ else {
+ byte buffer[2048]; /* XXX */
+ byte *p;
+
+ if (width > sizeof(buffer)) {
+ p = malloc(width);
+ if (p == NULL)
+ return 1;
+ } else {
+ p = buffer;
+ }
+ for (srcline=srcy, dstline=dsty; srcline<srcy+hight; srcline++, dstline++) {
+ ReadVerticalLine(src, srcx, srcline, width, p);
+ WriteVerticalLine(dst, dstx, dstline, width, p);
+ }
+ if (width > sizeof(buffer))
+ free(p);
+ }
+ return 0;
+}
+
+int
+VGLBitmapCopy(VGLBitmap *src, int srcx, int srcy,
+ VGLBitmap *dst, int dstx, int dsty, int width, int hight)
+{
+ int error;
+
+ VGLMouseFreeze(dstx, dsty, width, hight, 0);
+ error = __VGLBitmapCopy(src, srcx, srcy, dst, dstx, dsty, width, hight);
+ VGLMouseUnFreeze();
+ return error;
+}
+
+VGLBitmap
+*VGLBitmapCreate(int type, int xsize, int ysize, byte *bits)
+{
+ VGLBitmap *object;
+
+ if (type != MEMBUF)
+ return NULL;
+ if (xsize < 0 || ysize < 0)
+ return NULL;
+ object = (VGLBitmap *)malloc(sizeof(*object));
+ if (object == NULL)
+ return NULL;
+ object->Type = type;
+ object->Xsize = xsize;
+ object->Ysize = ysize;
+ object->VXsize = xsize;
+ object->VYsize = ysize;
+ object->Xorigin = 0;
+ object->Yorigin = 0;
+ object->Bitmap = bits;
+ return object;
+}
+
+void
+VGLBitmapDestroy(VGLBitmap *object)
+{
+ if (object->Bitmap)
+ free(object->Bitmap);
+ free(object);
+}
+
+int
+VGLBitmapAllocateBits(VGLBitmap *object)
+{
+ object->Bitmap = (byte *)malloc(object->VXsize*object->VYsize);
+ if (object->Bitmap == NULL)
+ return -1;
+ return 0;
+}
diff --git a/lib/libvgl/keyboard.c b/lib/libvgl/keyboard.c
new file mode 100644
index 0000000..5c437ad
--- /dev/null
+++ b/lib/libvgl/keyboard.c
@@ -0,0 +1,94 @@
+/*-
+ * Copyright (c) 1997 Søren Schmidt
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 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 <stdio.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <termios.h>
+#include <sys/time.h>
+#include <sys/fbio.h>
+#include <sys/kbio.h>
+#include "vgl.h"
+
+static struct termios VGLKeyboardTty;
+static int VGLKeyboardMode = -1;
+
+int
+VGLKeyboardInit(int mode)
+{
+ static struct termios term;
+
+ ioctl(0, KDGKBMODE, &VGLKeyboardMode);
+ tcgetattr(0, &VGLKeyboardTty);
+
+ term = VGLKeyboardTty;
+ cfmakeraw(&term);
+ term.c_iflag = IGNPAR | IGNBRK;
+ term.c_oflag = OPOST | ONLCR;
+ term.c_cflag = CREAD | CS8;
+ term.c_lflag &= ~(ICANON | ECHO | ISIG);
+ term.c_cc[VTIME] = 0;
+ term.c_cc[VMIN] = 0;
+ cfsetispeed(&term, 9600);
+ cfsetospeed(&term, 9600);
+ tcsetattr(0, TCSANOW | TCSAFLUSH, &term);
+
+ switch (mode) {
+ case VGL_RAWKEYS:
+ ioctl(0, KDSKBMODE, K_RAW);
+ break;
+ case VGL_CODEKEYS:
+ ioctl(0, KDSKBMODE, K_CODE);
+ break;
+ case VGL_XLATEKEYS:
+ ioctl(0, KDSKBMODE, K_XLATE);
+ break;
+ }
+ return 0;
+}
+
+void
+VGLKeyboardEnd()
+{
+ if (VGLKeyboardMode != -1) {
+ ioctl(0, KDSKBMODE, VGLKeyboardMode);
+ tcsetattr(0, TCSANOW | TCSAFLUSH, &VGLKeyboardTty);
+ }
+}
+
+int
+VGLKeyboardGetCh()
+{
+ unsigned char ch = 0;
+
+ read (0, &ch, 1);
+ return (int)ch;
+}
diff --git a/lib/libvgl/main.c b/lib/libvgl/main.c
new file mode 100644
index 0000000..8506a1b
--- /dev/null
+++ b/lib/libvgl/main.c
@@ -0,0 +1,574 @@
+/*-
+ * Copyright (c) 1991-1997 Søren Schmidt
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 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 <stdio.h>
+#include <sys/types.h>
+#include <sys/signal.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/fbio.h>
+#include <sys/kbio.h>
+#include <sys/consio.h>
+#include "vgl.h"
+
+/* XXX Direct Color 24bits modes unsupported */
+
+#define min(x, y) (((x) < (y)) ? (x) : (y))
+#define max(x, y) (((x) > (y)) ? (x) : (y))
+
+VGLBitmap *VGLDisplay;
+video_info_t VGLModeInfo;
+video_adapter_info_t VGLAdpInfo;
+byte *VGLBuf;
+
+static int VGLMode;
+static int VGLOldMode;
+static size_t VGLBufSize;
+static byte *VGLMem = MAP_FAILED;
+static int VGLSwitchPending;
+static int VGLAbortPending;
+static int VGLOnDisplay;
+static unsigned int VGLCurWindow;
+static int VGLInitDone = 0;
+static vid_info_t VGLOldVInfo;
+
+void
+VGLEnd()
+{
+struct vt_mode smode;
+
+ if (!VGLInitDone)
+ return;
+ VGLInitDone = 0;
+ VGLSwitchPending = 0;
+ VGLAbortPending = 0;
+
+ signal(SIGUSR1, SIG_IGN);
+
+ if (VGLMem != MAP_FAILED) {
+ VGLClear(VGLDisplay, 0);
+ munmap(VGLMem, VGLAdpInfo.va_window_size);
+ }
+
+ if (VGLOldMode >= M_VESA_BASE) {
+ /* ugly, but necessary */
+ ioctl(0, _IO('V', VGLOldMode - M_VESA_BASE), 0);
+ if (VGLOldMode == M_VESA_800x600) {
+ int size[3];
+ size[0] = VGLOldVInfo.mv_csz;
+ size[1] = VGLOldVInfo.mv_rsz;
+ size[2] = 16;
+ ioctl(0, KDRASTER, size);
+ }
+ } else {
+ ioctl(0, _IO('S', VGLOldMode), 0);
+ }
+ ioctl(0, KDDISABIO, 0);
+ ioctl(0, KDSETMODE, KD_TEXT);
+ smode.mode = VT_AUTO;
+ ioctl(0, VT_SETMODE, &smode);
+ if (VGLBuf)
+ free(VGLBuf);
+ VGLBuf = NULL;
+ free(VGLDisplay);
+ VGLDisplay = NULL;
+ VGLKeyboardEnd();
+}
+
+static void
+VGLAbort(int arg __unused)
+{
+ VGLAbortPending = 1;
+ signal(SIGINT, SIG_IGN);
+ signal(SIGTERM, SIG_IGN);
+ signal(SIGSEGV, SIG_IGN);
+ signal(SIGBUS, SIG_IGN);
+ signal(SIGUSR2, SIG_IGN);
+}
+
+static void
+VGLSwitch(int arg __unused)
+{
+ if (!VGLOnDisplay)
+ VGLOnDisplay = 1;
+ else
+ VGLOnDisplay = 0;
+ VGLSwitchPending = 1;
+ signal(SIGUSR1, VGLSwitch);
+}
+
+int
+VGLInit(int mode)
+{
+ struct vt_mode smode;
+ int adptype;
+
+ if (VGLInitDone)
+ return -1;
+
+ signal(SIGUSR1, VGLSwitch);
+ signal(SIGINT, VGLAbort);
+ signal(SIGTERM, VGLAbort);
+ signal(SIGSEGV, VGLAbort);
+ signal(SIGBUS, VGLAbort);
+ signal(SIGUSR2, SIG_IGN);
+
+ VGLOnDisplay = 1;
+ VGLSwitchPending = 0;
+ VGLAbortPending = 0;
+
+ if (ioctl(0, CONS_GET, &VGLOldMode) || ioctl(0, CONS_CURRENT, &adptype))
+ return -1;
+ if (IOCGROUP(mode) == 'V') /* XXX: this is ugly */
+ VGLModeInfo.vi_mode = (mode & 0x0ff) + M_VESA_BASE;
+ else
+ VGLModeInfo.vi_mode = mode & 0x0ff;
+ if (ioctl(0, CONS_MODEINFO, &VGLModeInfo)) /* FBIO_MODEINFO */
+ return -1;
+
+ /* If current mode is VESA_800x600 then save its geometry to restore later */
+ if ((VGLOldMode >= M_VESA_BASE) && (VGLOldMode == M_VESA_800x600)) {
+ VGLOldVInfo.size = sizeof(VGLOldVInfo);
+ if (ioctl(0, CONS_GETINFO, &VGLOldVInfo))
+ return -1;
+ }
+
+ VGLDisplay = (VGLBitmap *)malloc(sizeof(VGLBitmap));
+ if (VGLDisplay == NULL)
+ return -2;
+
+ if (ioctl(0, KDENABIO, 0)) {
+ free(VGLDisplay);
+ return -3;
+ }
+
+ VGLInitDone = 1;
+
+ /*
+ * vi_mem_model specifies the memory model of the current video mode
+ * in -CURRENT.
+ */
+ switch (VGLModeInfo.vi_mem_model) {
+ case V_INFO_MM_PLANAR:
+ /* we can handle EGA/VGA planner modes only */
+ if (VGLModeInfo.vi_depth != 4 || VGLModeInfo.vi_planes != 4
+ || (adptype != KD_EGA && adptype != KD_VGA)) {
+ VGLEnd();
+ return -4;
+ }
+ VGLDisplay->Type = VIDBUF4;
+ break;
+ case V_INFO_MM_PACKED:
+ /* we can do only 256 color packed modes */
+ if (VGLModeInfo.vi_depth != 8) {
+ VGLEnd();
+ return -4;
+ }
+ VGLDisplay->Type = VIDBUF8;
+ VGLDisplay->PixelBytes = 1;
+ break;
+ case V_INFO_MM_VGAX:
+ VGLDisplay->Type = VIDBUF8X;
+ VGLDisplay->PixelBytes = 1;
+ break;
+ case V_INFO_MM_DIRECT:
+ VGLDisplay->PixelBytes = VGLModeInfo.vi_pixel_size;
+ switch (VGLDisplay->PixelBytes) {
+ case 2:
+ VGLDisplay->Type = VIDBUF16;
+ break;
+#if notyet
+ case 3:
+ VGLDisplay->Type = VIDBUF24;
+ break;
+#endif
+ case 4:
+ VGLDisplay->Type = VIDBUF32;
+ break;
+ default:
+ VGLEnd();
+ return -4;
+ }
+ break;
+ default:
+ VGLEnd();
+ return -4;
+ }
+
+ ioctl(0, VT_WAITACTIVE, 0);
+ ioctl(0, KDSETMODE, KD_GRAPHICS);
+ if (ioctl(0, mode, 0)) {
+ VGLEnd();
+ return -5;
+ }
+ if (ioctl(0, CONS_ADPINFO, &VGLAdpInfo)) { /* FBIO_ADPINFO */
+ VGLEnd();
+ return -6;
+ }
+
+ /*
+ * Calculate the shadow screen buffer size. In -CURRENT, va_buffer_size
+ * always holds the entire frame buffer size, wheather it's in the linear
+ * mode or windowed mode.
+ * VGLBufSize = VGLAdpInfo.va_buffer_size;
+ * In -STABLE, va_buffer_size holds the frame buffer size, only if
+ * the linear frame buffer mode is supported. Otherwise the field is zero.
+ * We shall calculate the minimal size in this case:
+ * VGLAdpInfo.va_line_width*VGLModeInfo.vi_height*VGLModeInfo.vi_planes
+ * or
+ * VGLAdpInfo.va_window_size*VGLModeInfo.vi_planes;
+ * Use whichever is larger.
+ */
+ if (VGLAdpInfo.va_buffer_size != 0)
+ VGLBufSize = VGLAdpInfo.va_buffer_size;
+ else
+ VGLBufSize = max(VGLAdpInfo.va_line_width*VGLModeInfo.vi_height,
+ VGLAdpInfo.va_window_size)*VGLModeInfo.vi_planes;
+ VGLBuf = malloc(VGLBufSize);
+ if (VGLBuf == NULL) {
+ VGLEnd();
+ return -7;
+ }
+
+#ifdef LIBVGL_DEBUG
+ fprintf(stderr, "VGLBufSize:0x%x\n", VGLBufSize);
+#endif
+
+ /* see if we are in the windowed buffer mode or in the linear buffer mode */
+ if (VGLBufSize/VGLModeInfo.vi_planes > VGLAdpInfo.va_window_size) {
+ switch (VGLDisplay->Type) {
+ case VIDBUF4:
+ VGLDisplay->Type = VIDBUF4S;
+ break;
+ case VIDBUF8:
+ VGLDisplay->Type = VIDBUF8S;
+ break;
+ case VIDBUF16:
+ VGLDisplay->Type = VIDBUF16S;
+ break;
+ case VIDBUF24:
+ VGLDisplay->Type = VIDBUF24S;
+ break;
+ case VIDBUF32:
+ VGLDisplay->Type = VIDBUF32S;
+ break;
+ default:
+ VGLEnd();
+ return -8;
+ }
+ }
+
+ VGLMode = mode;
+ VGLCurWindow = 0;
+
+ VGLDisplay->Xsize = VGLModeInfo.vi_width;
+ VGLDisplay->Ysize = VGLModeInfo.vi_height;
+ VGLDisplay->VXsize = VGLAdpInfo.va_line_width
+ *8/(VGLModeInfo.vi_depth/VGLModeInfo.vi_planes);
+ VGLDisplay->VYsize = VGLBufSize/VGLModeInfo.vi_planes/VGLAdpInfo.va_line_width;
+ VGLDisplay->Xorigin = 0;
+ VGLDisplay->Yorigin = 0;
+
+ VGLMem = (byte*)mmap(0, VGLAdpInfo.va_window_size, PROT_READ|PROT_WRITE,
+ MAP_FILE, 0, 0);
+ if (VGLMem == MAP_FAILED) {
+ VGLEnd();
+ return -7;
+ }
+ VGLDisplay->Bitmap = VGLMem;
+
+ VGLSavePalette();
+
+#ifdef LIBVGL_DEBUG
+ fprintf(stderr, "va_line_width:%d\n", VGLAdpInfo.va_line_width);
+ fprintf(stderr, "VGLXsize:%d, Ysize:%d, VXsize:%d, VYsize:%d\n",
+ VGLDisplay->Xsize, VGLDisplay->Ysize,
+ VGLDisplay->VXsize, VGLDisplay->VYsize);
+#endif
+
+ smode.mode = VT_PROCESS;
+ smode.waitv = 0;
+ smode.relsig = SIGUSR1;
+ smode.acqsig = SIGUSR1;
+ smode.frsig = SIGINT;
+ if (ioctl(0, VT_SETMODE, &smode)) {
+ VGLEnd();
+ return -9;
+ }
+ VGLTextSetFontFile((byte*)0);
+ VGLClear(VGLDisplay, 0);
+ return 0;
+}
+
+void
+VGLCheckSwitch()
+{
+ if (VGLAbortPending) {
+ VGLEnd();
+ exit(0);
+ }
+ while (VGLSwitchPending) {
+ unsigned int offset;
+ unsigned int len;
+ int i;
+
+ VGLSwitchPending = 0;
+ if (VGLOnDisplay) {
+ ioctl(0, KDENABIO, 0);
+ ioctl(0, KDSETMODE, KD_GRAPHICS);
+ ioctl(0, VGLMode, 0);
+ VGLCurWindow = 0;
+ VGLMem = (byte*)mmap(0, VGLAdpInfo.va_window_size, PROT_READ|PROT_WRITE,
+ MAP_FILE, 0, 0);
+
+ /* XXX: what if mmap() has failed! */
+ VGLDisplay->Type = VIDBUF8; /* XXX */
+ switch (VGLModeInfo.vi_mem_model) {
+ case V_INFO_MM_PLANAR:
+ if (VGLModeInfo.vi_depth == 4 && VGLModeInfo.vi_planes == 4) {
+ if (VGLBufSize/VGLModeInfo.vi_planes > VGLAdpInfo.va_window_size)
+ VGLDisplay->Type = VIDBUF4S;
+ else
+ VGLDisplay->Type = VIDBUF4;
+ } else {
+ /* shouldn't be happening */
+ }
+ break;
+ case V_INFO_MM_PACKED:
+ if (VGLModeInfo.vi_depth == 8) {
+ if (VGLBufSize/VGLModeInfo.vi_planes > VGLAdpInfo.va_window_size)
+ VGLDisplay->Type = VIDBUF8S;
+ else
+ VGLDisplay->Type = VIDBUF8;
+ }
+ break;
+ case V_INFO_MM_VGAX:
+ VGLDisplay->Type = VIDBUF8X;
+ break;
+ case V_INFO_MM_DIRECT:
+ switch (VGLModeInfo.vi_pixel_size) {
+ case 2:
+ if (VGLBufSize/VGLModeInfo.vi_planes > VGLAdpInfo.va_window_size)
+ VGLDisplay->Type = VIDBUF16S;
+ else
+ VGLDisplay->Type = VIDBUF16;
+ break;
+ case 3:
+ if (VGLBufSize/VGLModeInfo.vi_planes > VGLAdpInfo.va_window_size)
+ VGLDisplay->Type = VIDBUF24S;
+ else
+ VGLDisplay->Type = VIDBUF24;
+ break;
+ case 4:
+ if (VGLBufSize/VGLModeInfo.vi_planes > VGLAdpInfo.va_window_size)
+ VGLDisplay->Type = VIDBUF32S;
+ else
+ VGLDisplay->Type = VIDBUF32;
+ break;
+ default:
+ /* shouldn't be happening */
+ break;
+ }
+ default:
+ /* shouldn't be happening */
+ break;
+ }
+
+ VGLDisplay->Bitmap = VGLMem;
+ VGLDisplay->Xsize = VGLModeInfo.vi_width;
+ VGLDisplay->Ysize = VGLModeInfo.vi_height;
+ VGLSetVScreenSize(VGLDisplay, VGLDisplay->VXsize, VGLDisplay->VYsize);
+ VGLPanScreen(VGLDisplay, VGLDisplay->Xorigin, VGLDisplay->Yorigin);
+ switch (VGLDisplay->Type) {
+ case VIDBUF4S:
+ outb(0x3c6, 0xff);
+ outb(0x3ce, 0x01); outb(0x3cf, 0x00); /* set/reset enable */
+ outb(0x3ce, 0x08); outb(0x3cf, 0xff); /* bit mask */
+ for (offset = 0; offset < VGLBufSize/VGLModeInfo.vi_planes;
+ offset += len) {
+ VGLSetSegment(offset);
+ len = min(VGLBufSize/VGLModeInfo.vi_planes - offset,
+ VGLAdpInfo.va_window_size);
+ for (i = 0; i < VGLModeInfo.vi_planes; i++) {
+ outb(0x3c4, 0x02);
+ outb(0x3c5, 0x01<<i);
+ bcopy(&VGLBuf[i*VGLBufSize/VGLModeInfo.vi_planes + offset],
+ VGLMem, len);
+ }
+ }
+ break;
+ case VIDBUF4:
+ case VIDBUF8X:
+ outb(0x3c6, 0xff);
+ outb(0x3ce, 0x01); outb(0x3cf, 0x00); /* set/reset enable */
+ outb(0x3ce, 0x08); outb(0x3cf, 0xff); /* bit mask */
+ for (i = 0; i < VGLModeInfo.vi_planes; i++) {
+ outb(0x3c4, 0x02);
+ outb(0x3c5, 0x01<<i);
+ bcopy(&VGLBuf[i*VGLAdpInfo.va_window_size], VGLMem,
+ VGLAdpInfo.va_window_size);
+ }
+ break;
+ case VIDBUF8:
+ case VIDBUF8S:
+ case VIDBUF16:
+ case VIDBUF16S:
+ case VIDBUF24:
+ case VIDBUF24S:
+ case VIDBUF32:
+ case VIDBUF32S:
+ for (offset = 0; offset < VGLBufSize; offset += len) {
+ VGLSetSegment(offset);
+ len = min(VGLBufSize - offset, VGLAdpInfo.va_window_size);
+ bcopy(&VGLBuf[offset], VGLMem, len);
+ }
+ break;
+ }
+ VGLRestorePalette();
+ ioctl(0, VT_RELDISP, VT_ACKACQ);
+ }
+ else {
+ switch (VGLDisplay->Type) {
+ case VIDBUF4S:
+ for (offset = 0; offset < VGLBufSize/VGLModeInfo.vi_planes;
+ offset += len) {
+ VGLSetSegment(offset);
+ len = min(VGLBufSize/VGLModeInfo.vi_planes - offset,
+ VGLAdpInfo.va_window_size);
+ for (i = 0; i < VGLModeInfo.vi_planes; i++) {
+ outb(0x3ce, 0x04);
+ outb(0x3cf, i);
+ bcopy(VGLMem, &VGLBuf[i*VGLBufSize/VGLModeInfo.vi_planes + offset],
+ len);
+ }
+ }
+ break;
+ case VIDBUF4:
+ case VIDBUF8X:
+ /*
+ * NOTE: the saved buffer is NOT in the MEMBUF format which
+ * the ordinary memory bitmap object is stored in. XXX
+ */
+ for (i = 0; i < VGLModeInfo.vi_planes; i++) {
+ outb(0x3ce, 0x04);
+ outb(0x3cf, i);
+ bcopy(VGLMem, &VGLBuf[i*VGLAdpInfo.va_window_size],
+ VGLAdpInfo.va_window_size);
+ }
+ break;
+ case VIDBUF8:
+ case VIDBUF8S:
+ case VIDBUF16:
+ case VIDBUF16S:
+ case VIDBUF24:
+ case VIDBUF24S:
+ case VIDBUF32:
+ case VIDBUF32S:
+ for (offset = 0; offset < VGLBufSize; offset += len) {
+ VGLSetSegment(offset);
+ len = min(VGLBufSize - offset, VGLAdpInfo.va_window_size);
+ bcopy(VGLMem, &VGLBuf[offset], len);
+ }
+ break;
+ }
+ VGLMem = MAP_FAILED;
+ munmap(VGLDisplay->Bitmap, VGLAdpInfo.va_window_size);
+ ioctl(0, VGLOldMode, 0);
+ ioctl(0, KDSETMODE, KD_TEXT);
+ ioctl(0, KDDISABIO, 0);
+ ioctl(0, VT_RELDISP, VT_TRUE);
+ VGLDisplay->Bitmap = VGLBuf;
+ VGLDisplay->Type = MEMBUF;
+ VGLDisplay->Xsize = VGLDisplay->VXsize;
+ VGLDisplay->Ysize = VGLDisplay->VYsize;
+ while (!VGLOnDisplay) pause();
+ }
+ }
+}
+
+int
+VGLSetSegment(unsigned int offset)
+{
+ if (offset/VGLAdpInfo.va_window_size != VGLCurWindow) {
+ ioctl(0, CONS_SETWINORG, offset); /* FBIO_SETWINORG */
+ VGLCurWindow = offset/VGLAdpInfo.va_window_size;
+ }
+ return (offset%VGLAdpInfo.va_window_size);
+}
+
+int
+VGLSetVScreenSize(VGLBitmap *object, int VXsize, int VYsize)
+{
+ if (VXsize < object->Xsize || VYsize < object->Ysize)
+ return -1;
+ if (object->Type == MEMBUF)
+ return -1;
+ if (ioctl(0, FBIO_SETLINEWIDTH, &VXsize))
+ return -1;
+ ioctl(0, CONS_ADPINFO, &VGLAdpInfo); /* FBIO_ADPINFO */
+ object->VXsize = VGLAdpInfo.va_line_width
+ *8/(VGLModeInfo.vi_depth/VGLModeInfo.vi_planes);
+ object->VYsize = VGLBufSize/VGLModeInfo.vi_planes/VGLAdpInfo.va_line_width;
+ if (VYsize < object->VYsize)
+ object->VYsize = VYsize;
+
+#ifdef LIBVGL_DEBUG
+ fprintf(stderr, "new size: VGLXsize:%d, Ysize:%d, VXsize:%d, VYsize:%d\n",
+ object->Xsize, object->Ysize, object->VXsize, object->VYsize);
+#endif
+
+ return 0;
+}
+
+int
+VGLPanScreen(VGLBitmap *object, int x, int y)
+{
+ video_display_start_t origin;
+
+ if (x < 0 || x + object->Xsize > object->VXsize
+ || y < 0 || y + object->Ysize > object->VYsize)
+ return -1;
+ if (object->Type == MEMBUF)
+ return 0;
+ origin.x = x;
+ origin.y = y;
+ if (ioctl(0, FBIO_SETDISPSTART, &origin))
+ return -1;
+ object->Xorigin = x;
+ object->Yorigin = y;
+
+#ifdef LIBVGL_DEBUG
+ fprintf(stderr, "new origin: (%d, %d)\n", x, y);
+#endif
+
+ return 0;
+}
diff --git a/lib/libvgl/mouse.c b/lib/libvgl/mouse.c
new file mode 100644
index 0000000..4f9dc62
--- /dev/null
+++ b/lib/libvgl/mouse.c
@@ -0,0 +1,285 @@
+/*-
+ * Copyright (c) 1991-1997 Søren Schmidt
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 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 <stdio.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/signal.h>
+#include <sys/consio.h>
+#include <sys/fbio.h>
+#include "vgl.h"
+
+#define X 0xff
+static byte StdAndMask[MOUSE_IMG_SIZE*MOUSE_IMG_SIZE] = {
+ X,X,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ X,X,X,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ X,X,X,X,0,0,0,0,0,0,0,0,0,0,0,0,
+ X,X,X,X,X,0,0,0,0,0,0,0,0,0,0,0,
+ X,X,X,X,X,X,0,0,0,0,0,0,0,0,0,0,
+ X,X,X,X,X,X,X,0,0,0,0,0,0,0,0,0,
+ X,X,X,X,X,X,X,X,0,0,0,0,0,0,0,0,
+ X,X,X,X,X,X,X,X,X,0,0,0,0,0,0,0,
+ X,X,X,X,X,X,X,0,0,0,0,0,0,0,0,0,
+ 0,0,0,X,X,X,X,0,0,0,0,0,0,0,0,0,
+ 0,0,0,X,X,X,X,X,0,0,0,0,0,0,0,0,
+ 0,0,0,0,X,X,X,X,0,0,0,0,0,0,0,0,
+ 0,0,0,0,X,X,X,X,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,
+};
+static byte StdOrMask[MOUSE_IMG_SIZE*MOUSE_IMG_SIZE] = {
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,X,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,X,X,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,X,X,X,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,X,X,X,X,0,0,0,0,0,0,0,0,0,0,0,
+ 0,X,X,X,X,X,0,0,0,0,0,0,0,0,0,0,
+ 0,X,X,X,X,X,X,0,0,0,0,0,0,0,0,0,
+ 0,X,X,0,X,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,X,X,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,X,X,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,X,X,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,X,X,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,
+};
+#undef X
+static VGLBitmap VGLMouseStdAndMask =
+ VGLBITMAP_INITIALIZER(MEMBUF, MOUSE_IMG_SIZE, MOUSE_IMG_SIZE, StdAndMask);
+static VGLBitmap VGLMouseStdOrMask =
+ VGLBITMAP_INITIALIZER(MEMBUF, MOUSE_IMG_SIZE, MOUSE_IMG_SIZE, StdOrMask);
+static VGLBitmap *VGLMouseAndMask, *VGLMouseOrMask;
+static byte map[MOUSE_IMG_SIZE*MOUSE_IMG_SIZE];
+static VGLBitmap VGLMouseSave =
+ VGLBITMAP_INITIALIZER(MEMBUF, MOUSE_IMG_SIZE, MOUSE_IMG_SIZE, map);
+static int VGLMouseVisible = 0;
+static int VGLMouseFrozen = 0;
+static int VGLMouseShown = 0;
+static int VGLMouseXpos = 0;
+static int VGLMouseYpos = 0;
+static int VGLMouseButtons = 0;
+
+void
+VGLMousePointerShow()
+{
+ byte buf[MOUSE_IMG_SIZE*MOUSE_IMG_SIZE];
+ VGLBitmap buffer =
+ VGLBITMAP_INITIALIZER(MEMBUF, MOUSE_IMG_SIZE, MOUSE_IMG_SIZE, buf);
+ byte crtcidx, crtcval, gdcidx, gdcval;
+ int pos;
+
+ if (!VGLMouseVisible) {
+ VGLMouseVisible = 1;
+ crtcidx = inb(0x3c4);
+ crtcval = inb(0x3c5);
+ gdcidx = inb(0x3ce);
+ gdcval = inb(0x3cf);
+ __VGLBitmapCopy(VGLDisplay, VGLMouseXpos, VGLMouseYpos,
+ &VGLMouseSave, 0, 0, MOUSE_IMG_SIZE, MOUSE_IMG_SIZE);
+ bcopy(VGLMouseSave.Bitmap, buffer.Bitmap, MOUSE_IMG_SIZE*MOUSE_IMG_SIZE);
+ for (pos = 0; pos < MOUSE_IMG_SIZE*MOUSE_IMG_SIZE; pos++)
+ buffer.Bitmap[pos]=(buffer.Bitmap[pos]&~(VGLMouseAndMask->Bitmap[pos])) |
+ VGLMouseOrMask->Bitmap[pos];
+ __VGLBitmapCopy(&buffer, 0, 0, VGLDisplay,
+ VGLMouseXpos, VGLMouseYpos, MOUSE_IMG_SIZE, MOUSE_IMG_SIZE);
+ outb(0x3c4, crtcidx);
+ outb(0x3c5, crtcval);
+ outb(0x3ce, gdcidx);
+ outb(0x3cf, gdcval);
+ }
+}
+
+void
+VGLMousePointerHide()
+{
+ byte crtcidx, crtcval, gdcidx, gdcval;
+
+ if (VGLMouseVisible) {
+ VGLMouseVisible = 0;
+ crtcidx = inb(0x3c4);
+ crtcval = inb(0x3c5);
+ gdcidx = inb(0x3ce);
+ gdcval = inb(0x3cf);
+ __VGLBitmapCopy(&VGLMouseSave, 0, 0, VGLDisplay,
+ VGLMouseXpos, VGLMouseYpos, MOUSE_IMG_SIZE, MOUSE_IMG_SIZE);
+ outb(0x3c4, crtcidx);
+ outb(0x3c5, crtcval);
+ outb(0x3ce, gdcidx);
+ outb(0x3cf, gdcval);
+ }
+}
+
+void
+VGLMouseMode(int mode)
+{
+ if (mode == VGL_MOUSESHOW) {
+ if (VGLMouseShown == VGL_MOUSEHIDE) {
+ VGLMousePointerShow();
+ VGLMouseShown = VGL_MOUSESHOW;
+ }
+ }
+ else {
+ if (VGLMouseShown == VGL_MOUSESHOW) {
+ VGLMousePointerHide();
+ VGLMouseShown = VGL_MOUSEHIDE;
+ }
+ }
+}
+
+void
+VGLMouseAction(int dummy)
+{
+ struct mouse_info mouseinfo;
+
+ if (VGLMouseFrozen) {
+ VGLMouseFrozen++;
+ return;
+ }
+ mouseinfo.operation = MOUSE_GETINFO;
+ ioctl(0, CONS_MOUSECTL, &mouseinfo);
+ if (VGLMouseShown == VGL_MOUSESHOW)
+ VGLMousePointerHide();
+ VGLMouseXpos = mouseinfo.u.data.x;
+ VGLMouseYpos = mouseinfo.u.data.y;
+ VGLMouseButtons = mouseinfo.u.data.buttons;
+ if (VGLMouseShown == VGL_MOUSESHOW)
+ VGLMousePointerShow();
+}
+
+void
+VGLMouseSetImage(VGLBitmap *AndMask, VGLBitmap *OrMask)
+{
+ if (VGLMouseShown == VGL_MOUSESHOW)
+ VGLMousePointerHide();
+ VGLMouseAndMask = AndMask;
+ VGLMouseOrMask = OrMask;
+ if (VGLMouseShown == VGL_MOUSESHOW)
+ VGLMousePointerShow();
+}
+
+void
+VGLMouseSetStdImage()
+{
+ if (VGLMouseShown == VGL_MOUSESHOW)
+ VGLMousePointerHide();
+ VGLMouseAndMask = &VGLMouseStdAndMask;
+ VGLMouseOrMask = &VGLMouseStdOrMask;
+ if (VGLMouseShown == VGL_MOUSESHOW)
+ VGLMousePointerShow();
+}
+
+int
+VGLMouseInit(int mode)
+{
+ struct mouse_info mouseinfo;
+ int error;
+
+ VGLMouseSetStdImage();
+ mouseinfo.operation = MOUSE_MODE;
+ mouseinfo.u.mode.signal = SIGUSR2;
+ if ((error = ioctl(0, CONS_MOUSECTL, &mouseinfo)))
+ return error;
+ signal(SIGUSR2, VGLMouseAction);
+ mouseinfo.operation = MOUSE_GETINFO;
+ ioctl(0, CONS_MOUSECTL, &mouseinfo);
+ VGLMouseXpos = mouseinfo.u.data.x;
+ VGLMouseYpos = mouseinfo.u.data.y;
+ VGLMouseButtons = mouseinfo.u.data.buttons;
+ VGLMouseMode(mode);
+ return 0;
+}
+
+int
+VGLMouseStatus(int *x, int *y, char *buttons)
+{
+ signal(SIGUSR2, SIG_IGN);
+ *x = VGLMouseXpos;
+ *y = VGLMouseYpos;
+ *buttons = VGLMouseButtons;
+ signal(SIGUSR2, VGLMouseAction);
+ return VGLMouseShown;
+}
+
+int
+VGLMouseFreeze(int x, int y, int width, int hight, byte color)
+{
+ if (!VGLMouseFrozen) {
+ VGLMouseFrozen = 1;
+ if (width > 1 || hight > 1) { /* bitmap */
+ if (VGLMouseShown == 1) {
+ int overlap;
+
+ if (x > VGLMouseXpos)
+ overlap = (VGLMouseXpos + MOUSE_IMG_SIZE) - x;
+ else
+ overlap = (x + width) - VGLMouseXpos;
+ if (overlap > 0) {
+ if (y > VGLMouseYpos)
+ overlap = (VGLMouseYpos + MOUSE_IMG_SIZE) - y;
+ else
+ overlap = (y + hight) - VGLMouseYpos;
+ if (overlap > 0)
+ VGLMousePointerHide();
+ }
+ }
+ }
+ else { /* bit */
+ if (VGLMouseShown &&
+ x >= VGLMouseXpos && x < VGLMouseXpos + MOUSE_IMG_SIZE &&
+ y >= VGLMouseYpos && y < VGLMouseYpos + MOUSE_IMG_SIZE) {
+ VGLMouseSave.Bitmap[(y-VGLMouseYpos)*MOUSE_IMG_SIZE+(x-VGLMouseXpos)] =
+ (color);
+ if (VGLMouseAndMask->Bitmap
+ [(y-VGLMouseYpos)*MOUSE_IMG_SIZE+(x-VGLMouseXpos)]) {
+ return 1;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+void
+VGLMouseUnFreeze()
+{
+ if (VGLMouseFrozen > 1) {
+ VGLMouseFrozen = 0;
+ VGLMouseAction(0);
+ }
+ else {
+ VGLMouseFrozen = 0;
+ if (VGLMouseShown == VGL_MOUSESHOW && !VGLMouseVisible)
+ VGLMousePointerShow();
+ }
+}
diff --git a/lib/libvgl/simple.c b/lib/libvgl/simple.c
new file mode 100644
index 0000000..b7d789a
--- /dev/null
+++ b/lib/libvgl/simple.c
@@ -0,0 +1,503 @@
+/*-
+ * Copyright (c) 1991-1997 Søren Schmidt
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 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 <signal.h>
+#include <sys/fbio.h>
+#include "vgl.h"
+
+static byte VGLSavePaletteRed[256];
+static byte VGLSavePaletteGreen[256];
+static byte VGLSavePaletteBlue[256];
+
+#define ABS(a) (((a)<0) ? -(a) : (a))
+#define SGN(a) (((a)<0) ? -1 : 1)
+#define min(x, y) (((x) < (y)) ? (x) : (y))
+#define max(x, y) (((x) > (y)) ? (x) : (y))
+
+static void
+color2mem(u_long color, byte *b, int len)
+{
+ switch (len) {
+ case 4:
+ b[3] = (color >> 24) & 0xff;
+ /* fallthrough */
+ case 3:
+ b[2] = (color >> 16) & 0xff;
+ /* fallthrough */
+ case 2:
+ b[1] = (color >> 8) & 0xff;
+ /* fallthrough */
+ case 1:
+ default:
+ b[0] = color & 0xff;
+ break;
+ }
+
+ return;
+}
+
+static u_long
+mem2color(byte *b, int len)
+{
+ u_long color = 0;
+
+ switch (len) {
+ case 4:
+ color |= (b[3] & 0xff) << 24;
+ /* fallthrough */
+ case 3:
+ color |= (b[2] & 0xff) << 16;
+ /* fallthrough */
+ case 2:
+ color |= (b[1] & 0xff) << 8;
+ /* fallthrough */
+ case 1:
+ default:
+ color |= (b[0] & 0xff);
+ break;
+ }
+
+ return color;
+}
+
+void
+VGLSetXY(VGLBitmap *object, int x, int y, u_long color)
+{
+ int offset;
+ byte b[4];
+
+ VGLCheckSwitch();
+ if (x>=0 && x<object->VXsize && y>=0 && y<object->VYsize) {
+ if (!VGLMouseFreeze(x, y, 1, 1, color)) {
+ switch (object->Type) {
+ case MEMBUF:
+ case VIDBUF8:
+ object->Bitmap[y*object->VXsize+x]=((byte)color);
+ break;
+ case VIDBUF8S:
+ object->Bitmap[VGLSetSegment(y*object->VXsize+x)]=((byte)color);
+ break;
+ case VIDBUF16:
+ case VIDBUF24:
+ case VIDBUF32:
+ color2mem(color, b, object->PixelBytes);
+ bcopy(b, &object->Bitmap[(y*object->VXsize+x) * object->PixelBytes],
+ object->PixelBytes);
+ break;
+ case VIDBUF16S:
+ case VIDBUF24S:
+ case VIDBUF32S:
+ color2mem(color, b, object->PixelBytes);
+ offset = VGLSetSegment((y*object->VXsize+x) * object->PixelBytes);
+ bcopy(b, &object->Bitmap[offset], object->PixelBytes);
+ break;
+ case VIDBUF8X:
+ outb(0x3c4, 0x02);
+ outb(0x3c5, 0x01 << (x&0x3));
+ object->Bitmap[(unsigned)(VGLAdpInfo.va_line_width*y)+(x/4)] = ((byte)color);
+ break;
+ case VIDBUF4S:
+ offset = VGLSetSegment(y*VGLAdpInfo.va_line_width + x/8);
+ goto set_planar;
+ case VIDBUF4:
+ offset = y*VGLAdpInfo.va_line_width + x/8;
+set_planar:
+ outb(0x3c4, 0x02); outb(0x3c5, 0x0f);
+ outb(0x3ce, 0x00); outb(0x3cf, (byte)color & 0x0f); /* set/reset */
+ outb(0x3ce, 0x01); outb(0x3cf, 0x0f); /* set/reset enable */
+ outb(0x3ce, 0x08); outb(0x3cf, 0x80 >> (x%8)); /* bit mask */
+ object->Bitmap[offset] |= (byte)color;
+ }
+ }
+ VGLMouseUnFreeze();
+ }
+}
+
+u_long
+VGLGetXY(VGLBitmap *object, int x, int y)
+{
+ int offset;
+ byte b[4];
+#if 0
+ int i;
+ u_long color;
+ byte mask;
+#endif
+
+ VGLCheckSwitch();
+ if (x<0 || x>=object->VXsize || y<0 || y>=object->VYsize)
+ return 0;
+ switch (object->Type) {
+ case MEMBUF:
+ case VIDBUF8:
+ return object->Bitmap[((y*object->VXsize)+x)];
+ case VIDBUF8S:
+ return object->Bitmap[VGLSetSegment(y*object->VXsize+x)];
+ case VIDBUF16:
+ case VIDBUF24:
+ case VIDBUF32:
+ bcopy(&object->Bitmap[(y*object->VXsize+x) * object->PixelBytes],
+ b, object->PixelBytes);
+ return (mem2color(b, object->PixelBytes));
+ case VIDBUF16S:
+ case VIDBUF24S:
+ case VIDBUF32S:
+ offset = VGLSetSegment((y*object->VXsize+x) * object->PixelBytes);
+ bcopy(&object->Bitmap[offset], b, object->PixelBytes);
+
+ return (mem2color(b, object->PixelBytes));
+ case VIDBUF8X:
+ outb(0x3ce, 0x04); outb(0x3cf, x & 0x3);
+ return object->Bitmap[(unsigned)(VGLAdpInfo.va_line_width*y)+(x/4)];
+ case VIDBUF4S:
+ offset = VGLSetSegment(y*VGLAdpInfo.va_line_width + x/8);
+ goto get_planar;
+ case VIDBUF4:
+ offset = y*VGLAdpInfo.va_line_width + x/8;
+get_planar:
+#if 1
+ return (object->Bitmap[offset]&(0x80>>(x%8))) ? 1 : 0; /* XXX */
+#else
+ color = 0;
+ mask = 0x80 >> (x%8);
+ for (i = 0; i < VGLModeInfo.vi_planes; i++) {
+ outb(0x3ce, 0x04); outb(0x3cf, i);
+ color |= (object->Bitmap[offset] & mask) ? (1 << i) : 0;
+ }
+ return color;
+#endif
+ }
+ return 0; /* XXX black? */
+}
+
+void
+VGLLine(VGLBitmap *object, int x1, int y1, int x2, int y2, u_long color)
+{
+ int d, x, y, ax, ay, sx, sy, dx, dy;
+
+ dx = x2-x1; ax = ABS(dx)<<1; sx = SGN(dx); x = x1;
+ dy = y2-y1; ay = ABS(dy)<<1; sy = SGN(dy); y = y1;
+
+ if (ax>ay) { /* x dominant */
+ d = ay-(ax>>1);
+ for (;;) {
+ VGLSetXY(object, x, y, color);
+ if (x==x2)
+ break;
+ if (d>=0) {
+ y += sy; d -= ax;
+ }
+ x += sx; d += ay;
+ }
+ }
+ else { /* y dominant */
+ d = ax-(ay>>1);
+ for (;;) {
+ VGLSetXY(object, x, y, color);
+ if (y==y2)
+ break;
+ if (d>=0) {
+ x += sx; d -= ay;
+ }
+ y += sy; d += ax;
+ }
+ }
+}
+
+void
+VGLBox(VGLBitmap *object, int x1, int y1, int x2, int y2, u_long color)
+{
+ VGLLine(object, x1, y1, x2, y1, color);
+ VGLLine(object, x2, y1, x2, y2, color);
+ VGLLine(object, x2, y2, x1, y2, color);
+ VGLLine(object, x1, y2, x1, y1, color);
+}
+
+void
+VGLFilledBox(VGLBitmap *object, int x1, int y1, int x2, int y2, u_long color)
+{
+ int y;
+
+ for (y=y1; y<=y2; y++) VGLLine(object, x1, y, x2, y, color);
+}
+
+void
+inline set4pixels(VGLBitmap *object, int x, int y, int xc, int yc, u_long color)
+{
+ if (x!=0) {
+ VGLSetXY(object, xc+x, yc+y, color);
+ VGLSetXY(object, xc-x, yc+y, color);
+ if (y!=0) {
+ VGLSetXY(object, xc+x, yc-y, color);
+ VGLSetXY(object, xc-x, yc-y, color);
+ }
+ }
+ else {
+ VGLSetXY(object, xc, yc+y, color);
+ if (y!=0)
+ VGLSetXY(object, xc, yc-y, color);
+ }
+}
+
+void
+VGLEllipse(VGLBitmap *object, int xc, int yc, int a, int b, u_long color)
+{
+ int x = 0, y = b, asq = a*a, asq2 = a*a*2, bsq = b*b;
+ int bsq2 = b*b*2, d = bsq-asq*b+asq/4, dx = 0, dy = asq2*b;
+
+ while (dx<dy) {
+ set4pixels(object, x, y, xc, yc, color);
+ if (d>0) {
+ y--; dy-=asq2; d-=dy;
+ }
+ x++; dx+=bsq2; d+=bsq+dx;
+ }
+ d+=(3*(asq-bsq)/2-(dx+dy))/2;
+ while (y>=0) {
+ set4pixels(object, x, y, xc, yc, color);
+ if (d<0) {
+ x++; dx+=bsq2; d+=dx;
+ }
+ y--; dy-=asq2; d+=asq-dy;
+ }
+}
+
+void
+inline set2lines(VGLBitmap *object, int x, int y, int xc, int yc, u_long color)
+{
+ if (x!=0) {
+ VGLLine(object, xc+x, yc+y, xc-x, yc+y, color);
+ if (y!=0)
+ VGLLine(object, xc+x, yc-y, xc-x, yc-y, color);
+ }
+ else {
+ VGLLine(object, xc, yc+y, xc, yc-y, color);
+ }
+}
+
+void
+VGLFilledEllipse(VGLBitmap *object, int xc, int yc, int a, int b, u_long color)
+{
+ int x = 0, y = b, asq = a*a, asq2 = a*a*2, bsq = b*b;
+ int bsq2 = b*b*2, d = bsq-asq*b+asq/4, dx = 0, dy = asq2*b;
+
+ while (dx<dy) {
+ set2lines(object, x, y, xc, yc, color);
+ if (d>0) {
+ y--; dy-=asq2; d-=dy;
+ }
+ x++; dx+=bsq2; d+=bsq+dx;
+ }
+ d+=(3*(asq-bsq)/2-(dx+dy))/2;
+ while (y>=0) {
+ set2lines(object, x, y, xc, yc, color);
+ if (d<0) {
+ x++; dx+=bsq2; d+=dx;
+ }
+ y--; dy-=asq2; d+=asq-dy;
+ }
+}
+
+void
+VGLClear(VGLBitmap *object, u_long color)
+{
+ int offset;
+ int len;
+ int i, total = 0;
+ byte b[4];
+
+ VGLCheckSwitch();
+ VGLMouseFreeze(0, 0, object->Xsize, object->Ysize, color); /* XXX */
+ switch (object->Type) {
+ case MEMBUF:
+ case VIDBUF8:
+ memset(object->Bitmap, (byte)color, object->VXsize*object->VYsize);
+ break;
+
+ case VIDBUF8S:
+ for (offset = 0; offset < object->VXsize*object->VYsize; ) {
+ VGLSetSegment(offset);
+ len = min(object->VXsize*object->VYsize - offset,
+ VGLAdpInfo.va_window_size);
+ memset(object->Bitmap, (byte)color, len);
+ offset += len;
+ }
+ break;
+ case VIDBUF16:
+ case VIDBUF24:
+ case VIDBUF32:
+ color2mem(color, b, object->PixelBytes);
+ total = object->VXsize*object->VYsize*object->PixelBytes;
+ for (i = 0; i < total; i += object->PixelBytes)
+ bcopy(b, object->Bitmap + i, object->PixelBytes);
+ break;
+
+ case VIDBUF16S:
+ case VIDBUF24S:
+ case VIDBUF32S:
+ color2mem(color, b, object->PixelBytes);
+ total = object->VXsize*object->VYsize*object->PixelBytes;
+ for (offset = 0; offset < total; ) {
+ VGLSetSegment(offset);
+ len = min(total - offset, VGLAdpInfo.va_window_size);
+ for (i = 0; i < len; i += object->PixelBytes)
+ bcopy(b, object->Bitmap + offset + i, object->PixelBytes);
+ offset += len;
+ }
+ break;
+
+ case VIDBUF8X:
+ /* XXX works only for Xsize % 4 = 0 */
+ outb(0x3c6, 0xff);
+ outb(0x3c4, 0x02); outb(0x3c5, 0x0f);
+ memset(object->Bitmap, (byte)color, VGLAdpInfo.va_line_width*object->VYsize);
+ break;
+
+ case VIDBUF4:
+ case VIDBUF4S:
+ /* XXX works only for Xsize % 8 = 0 */
+ outb(0x3c4, 0x02); outb(0x3c5, 0x0f);
+ outb(0x3ce, 0x05); outb(0x3cf, 0x02); /* mode 2 */
+ outb(0x3ce, 0x01); outb(0x3cf, 0x00); /* set/reset enable */
+ outb(0x3ce, 0x08); outb(0x3cf, 0xff); /* bit mask */
+ for (offset = 0; offset < VGLAdpInfo.va_line_width*object->VYsize; ) {
+ VGLSetSegment(offset);
+ len = min(object->VXsize*object->VYsize - offset,
+ VGLAdpInfo.va_window_size);
+ memset(object->Bitmap, (byte)color, len);
+ offset += len;
+ }
+ outb(0x3ce, 0x05); outb(0x3cf, 0x00);
+ break;
+ }
+ VGLMouseUnFreeze();
+}
+
+void
+VGLRestorePalette()
+{
+ int i;
+
+ outb(0x3C6, 0xFF);
+ inb(0x3DA);
+ outb(0x3C8, 0x00);
+ for (i=0; i<256; i++) {
+ outb(0x3C9, VGLSavePaletteRed[i]);
+ inb(0x84);
+ outb(0x3C9, VGLSavePaletteGreen[i]);
+ inb(0x84);
+ outb(0x3C9, VGLSavePaletteBlue[i]);
+ inb(0x84);
+ }
+ inb(0x3DA);
+ outb(0x3C0, 0x20);
+}
+
+void
+VGLSavePalette()
+{
+ int i;
+
+ outb(0x3C6, 0xFF);
+ inb(0x3DA);
+ outb(0x3C7, 0x00);
+ for (i=0; i<256; i++) {
+ VGLSavePaletteRed[i] = inb(0x3C9);
+ inb(0x84);
+ VGLSavePaletteGreen[i] = inb(0x3C9);
+ inb(0x84);
+ VGLSavePaletteBlue[i] = inb(0x3C9);
+ inb(0x84);
+ }
+ inb(0x3DA);
+ outb(0x3C0, 0x20);
+}
+
+void
+VGLSetPalette(byte *red, byte *green, byte *blue)
+{
+ int i;
+
+ for (i=0; i<256; i++) {
+ VGLSavePaletteRed[i] = red[i];
+ VGLSavePaletteGreen[i] = green[i];
+ VGLSavePaletteBlue[i] = blue[i];
+ }
+ VGLCheckSwitch();
+ outb(0x3C6, 0xFF);
+ inb(0x3DA);
+ outb(0x3C8, 0x00);
+ for (i=0; i<256; i++) {
+ outb(0x3C9, VGLSavePaletteRed[i]);
+ inb(0x84);
+ outb(0x3C9, VGLSavePaletteGreen[i]);
+ inb(0x84);
+ outb(0x3C9, VGLSavePaletteBlue[i]);
+ inb(0x84);
+ }
+ inb(0x3DA);
+ outb(0x3C0, 0x20);
+}
+
+void
+VGLSetPaletteIndex(byte color, byte red, byte green, byte blue)
+{
+ VGLSavePaletteRed[color] = red;
+ VGLSavePaletteGreen[color] = green;
+ VGLSavePaletteBlue[color] = blue;
+ VGLCheckSwitch();
+ outb(0x3C6, 0xFF);
+ inb(0x3DA);
+ outb(0x3C8, color);
+ outb(0x3C9, red); outb(0x3C9, green); outb(0x3C9, blue);
+ inb(0x3DA);
+ outb(0x3C0, 0x20);
+}
+
+void
+VGLSetBorder(byte color)
+{
+ VGLCheckSwitch();
+ inb(0x3DA);
+ outb(0x3C0,0x11); outb(0x3C0, color);
+ inb(0x3DA);
+ outb(0x3C0, 0x20);
+}
+
+void
+VGLBlankDisplay(int blank)
+{
+ byte val;
+
+ VGLCheckSwitch();
+ outb(0x3C4, 0x01); val = inb(0x3C5); outb(0x3C4, 0x01);
+ outb(0x3C5, ((blank) ? (val |= 0x20) : (val &= 0xDF)));
+}
diff --git a/lib/libvgl/text.c b/lib/libvgl/text.c
new file mode 100644
index 0000000..757702f
--- /dev/null
+++ b/lib/libvgl/text.c
@@ -0,0 +1,245 @@
+/*-
+ * Copyright (c) 1991-1997 Søren Schmidt
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 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 <stdio.h>
+#include <sys/fbio.h>
+#include "vgl.h"
+
+static VGLText *VGLTextFont = 0;
+
+extern byte VGLFont[];
+
+int
+VGLTextSetFontFile(char *filename)
+{
+FILE *fd;
+
+ if (VGLTextFont) {
+ if (VGLTextFont->BitmapArray != VGLFont)
+ free (VGLTextFont->BitmapArray);
+ free(VGLTextFont);
+ }
+
+ if ((VGLTextFont=(VGLText*)malloc(sizeof(VGLText))) == (VGLText*)0)
+ return 1;
+
+ if (filename==NULL) {
+ VGLTextFont->Width = 8;
+ VGLTextFont->Height = 8;
+ VGLTextFont->BitmapArray = VGLFont;
+ }
+ else {
+ if ((fd=fopen(filename, "r"))==(FILE*)0)
+ return 1;
+ fread(&VGLTextFont->Width, 1 , 1, fd);
+ fread(&VGLTextFont->Height, 1 , 1, fd);
+ VGLTextFont->BitmapArray =
+ (byte*)malloc(256*((VGLTextFont->Width + 7)/8)*VGLTextFont->Height);
+ fread(VGLTextFont->BitmapArray, 1,
+ (256*VGLTextFont->Width* VGLTextFont->Height), fd);
+ fclose(fd);
+ }
+ return 0;
+}
+
+void
+VGLBitmapPutChar(VGLBitmap *Object, int x, int y, byte ch,
+ byte fgcol, byte bgcol, int fill, int dir)
+{
+ int lin, bit;
+
+ for(lin = 0; lin < VGLTextFont->Height; lin++) {
+ for(bit = 0; bit < VGLTextFont->Width; bit++) {
+ if (VGLTextFont->BitmapArray[((ch*VGLTextFont->Height)+lin)]&(1<<bit))
+ switch (dir) {
+ case 0:
+ VGLSetXY(Object, (x+7-bit), (y+lin), fgcol);
+ break;
+ case 1:
+ VGLSetXY(Object, (x+lin), (y-7+bit), fgcol);
+ break;
+ case 2:
+ VGLSetXY(Object, (x-7+bit), (y-lin), fgcol);
+ break;
+ case 3:
+ VGLSetXY(Object, (x-lin), (y+7-bit), fgcol);
+ break;
+ case 4:
+ VGLSetXY(Object, (x+lin+7-bit), (y+lin+bit), fgcol);
+ break;
+ }
+ else if (fill)
+ switch (dir) {
+ case 0:
+ VGLSetXY(Object, (x+7-bit), (y+lin), bgcol);
+ break;
+ case 1:
+ VGLSetXY(Object, (x+lin), (y-7+bit), bgcol);
+ break;
+ case 2:
+ VGLSetXY(Object, (x-7+bit), (y-lin), bgcol);
+ break;
+ case 3:
+ VGLSetXY(Object, (x-lin), (y+7-bit), bgcol);
+ break;
+ case 4:
+ VGLSetXY(Object, (x+lin+7-bit), (y+lin+bit), bgcol);
+ break;
+ }
+ }
+ }
+}
+
+void
+VGLBitmapString(VGLBitmap *Object, int x, int y, char *str,
+ byte fgcol, byte bgcol, int fill, int dir)
+{
+ int pos;
+
+ for (pos=0; pos<strlen(str); pos++) {
+ switch (dir) {
+ case 0:
+ VGLBitmapPutChar(Object, x+(pos*VGLTextFont->Width), y,
+ str[pos], fgcol, bgcol, fill, dir);
+ break;
+ case 1:
+ VGLBitmapPutChar(Object, x, y-(pos*VGLTextFont->Width),
+ str[pos], fgcol, bgcol, fill, dir);
+ break;
+ case 2:
+ VGLBitmapPutChar(Object, x-(pos*VGLTextFont->Width), y,
+ str[pos], fgcol, bgcol, fill, dir);
+ break;
+ case 3:
+ VGLBitmapPutChar(Object, x, y+(pos*VGLTextFont->Width),
+ str[pos], fgcol, bgcol, fill, dir);
+ break;
+ case 4:
+ VGLBitmapPutChar(Object, x+(pos*VGLTextFont->Width),
+ y-(pos*VGLTextFont->Width),
+ str[pos], fgcol, bgcol, fill, dir);
+ break;
+ }
+ }
+}
+
+byte VGLFont[] = {
+0,0,0,0,0,0,0,0,126,129,165,129,189,153,129,126,126,255,219,255,195,231,
+255,126,108,254,254,254,124,56,16,0,16,56,124,254,124,56,16,0,56,124,56,
+254,254,124,56,124,16,16,56,124,254,124,56,124,0,0,24,60,60,24,0,0,255,
+255,231,195,195,231,255,255,0,60,102,66,66,102,60,0,255,195,153,189,189,
+153,195,255,15,7,15,125,204,204,204,120,60,102,102,102,60,24,126,24,63,
+51,63,48,48,112,240,224,127,99,127,99,99,103,230,192,153,90,60,231,231,
+60,90,153,128,224,248,254,248,224,128,0,2,14,62,254,62,14,2,0,24,60,126,
+24,24,126,60,24,102,102,102,102,102,0,102,0,127,219,219,123,27,27,27,0,
+62,99,56,108,108,56,204,120,0,0,0,0,126,126,126,0,24,60,126,24,126,60,24,
+255,24,60,126,24,24,24,24,0,24,24,24,24,126,60,24,0,0,24,12,254,12,24,0,
+0,0,48,96,254,96,48,0,0,0,0,192,192,192,254,0,0,0,36,102,255,102,36,0,0,
+0,24,60,126,255,255,0,0,0,255,255,126,60,24,0,0,0,0,0,0,0,0,0,0,48,120,
+120,48,48,0,48,0,108,108,108,0,0,0,0,0,108,108,254,108,254,108,108,0,48,
+124,192,120,12,248,48,0,0,198,204,24,48,102,198,0,56,108,56,118,220,204,
+118,0,96,96,192,0,0,0,0,0,24,48,96,96,96,48,24,0,96,48,24,24,24,48,96,0,
+0,102,60,255,60,102,0,0,0,48,48,252,48,48,0,0,0,0,0,0,0,48,48,96,0,0,0,
+252,0,0,0,0,0,0,0,0,0,48,48,0,6,12,24,48,96,192,128,0,124,198,206,222,246,
+230,124,0,48,112,48,48,48,48,252,0,120,204,12,56,96,204,252,0,120,204,12,
+56,12,204,120,0,28,60,108,204,254,12,30,0,252,192,248,12,12,204,120,0,56,
+96,192,248,204,204,120,0,252,204,12,24,48,48,48,0,120,204,204,120,204,204,
+120,0,120,204,204,124,12,24,112,0,0,48,48,0,0,48,48,0,0,48,48,0,0,48,48,
+96,24,48,96,192,96,48,24,0,0,0,252,0,0,252,0,0,96,48,24,12,24,48,96,0,120,
+204,12,24,48,0,48,0,124,198,222,222,222,192,120,0,48,120,204,204,252,204,
+204,0,252,102,102,124,102,102,252,0,60,102,192,192,192,102,60,0,248,108,
+102,102,102,108,248,0,254,98,104,120,104,98,254,0,254,98,104,120,104,96,
+240,0,60,102,192,192,206,102,62,0,204,204,204,252,204,204,204,0,120,48,
+48,48,48,48,120,0,30,12,12,12,204,204,120,0,230,102,108,120,108,102,230,
+0,240,96,96,96,98,102,254,0,198,238,254,254,214,198,198,0,198,230,246,222,
+206,198,198,0,56,108,198,198,198,108,56,0,252,102,102,124,96,96,240,0,120,
+204,204,204,220,120,28,0,252,102,102,124,108,102,230,0,120,204,224,112,
+28,204,120,0,252,180,48,48,48,48,120,0,204,204,204,204,204,204,252,0,204,
+204,204,204,204,120,48,0,198,198,198,214,254,238,198,0,198,198,108,56,56,
+108,198,0,204,204,204,120,48,48,120,0,254,198,140,24,50,102,254,0,120,96,
+96,96,96,96,120,0,192,96,48,24,12,6,2,0,120,24,24,24,24,24,120,0,16,56,
+108,198,0,0,0,0,0,0,0,0,0,0,0,255,48,48,24,0,0,0,0,0,0,0,120,12,124,204,
+118,0,224,96,96,124,102,102,220,0,0,0,120,204,192,204,120,0,28,12,12,124,
+204,204,118,0,0,0,120,204,252,192,120,0,56,108,96,240,96,96,240,0,0,0,118,
+204,204,124,12,248,224,96,108,118,102,102,230,0,48,0,112,48,48,48,120,0,
+12,0,12,12,12,204,204,120,224,96,102,108,120,108,230,0,112,48,48,48,48,
+48,120,0,0,0,204,254,254,214,198,0,0,0,248,204,204,204,204,0,0,0,120,204,
+204,204,120,0,0,0,220,102,102,124,96,240,0,0,118,204,204,124,12,30,0,0,
+220,118,102,96,240,0,0,0,124,192,120,12,248,0,16,48,124,48,48,52,24,0,0,
+0,204,204,204,204,118,0,0,0,204,204,204,120,48,0,0,0,198,214,254,254,108,
+0,0,0,198,108,56,108,198,0,0,0,204,204,204,124,12,248,0,0,252,152,48,100,
+252,0,28,48,48,224,48,48,28,0,24,24,24,0,24,24,24,0,224,48,48,28,48,48,
+224,0,118,220,0,0,0,0,0,0,0,16,56,108,198,198,254,0,0,0,0,0,0,0,0,0,0,0,
+60,126,255,126,24,0,170,85,85,170,170,85,85,170,68,68,68,68,31,4,4,4,124,
+64,64,64,31,16,16,16,56,68,68,56,30,17,20,19,64,64,64,124,31,16,16,16,56,
+108,56,0,0,0,0,0,0,0,24,24,24,24,126,0,68,100,76,68,16,16,16,31,68,68,40,
+16,31,4,4,4,24,24,24,24,248,0,0,0,0,0,0,0,248,24,24,24,0,0,0,0,31,24,24,
+24,24,24,24,24,31,0,0,0,24,24,24,24,255,24,24,24,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,24,24,24,
+24,31,24,24,24,24,24,24,24,248,24,24,24,24,24,24,24,255,0,0,0,0,0,0,0,255,
+24,24,24,24,24,24,24,24,24,24,24,0,12,48,96,24,12,126,0,0,48,12,6,24,48,
+126,0,0,0,3,62,54,54,108,0,0,0,4,126,16,126,64,0,0,28,48,48,48,48,126,0,
+0,0,0,24,0,0,0,0,0,0,0,0,0,0,0,0,48,0,48,48,120,120,48,0,0,0,16,124,192,
+192,124,16,0,56,96,96,240,96,252,0,0,195,60,102,102,60,195,0,0,204,204,
+120,48,252,48,0,24,24,24,0,24,24,24,0,126,192,124,198,124,6,252,0,198,0,
+0,0,0,0,0,0,124,130,186,162,186,130,124,0,28,6,30,34,31,63,0,0,0,51,102,
+204,102,51,0,0,0,254,6,0,0,0,0,0,0,0,0,0,0,0,0,0,124,130,186,178,170,130,
+124,0,254,0,0,0,0,0,0,0,56,108,56,0,0,0,0,0,0,16,124,16,0,124,0,0,28,54,
+6,24,62,0,0,0,30,2,14,2,30,0,0,0,24,48,0,0,0,0,0,0,0,0,204,204,204,204,
+118,192,126,202,202,126,10,10,10,0,0,0,0,24,0,0,0,0,0,0,0,0,0,0,24,48,6,
+14,6,6,6,0,0,0,14,17,17,17,14,31,0,0,0,204,102,51,102,204,0,0,96,224,102,
+108,51,103,15,3,96,224,102,108,54,106,4,14,240,32,150,108,51,103,15,3,48,
+0,48,96,192,204,120,0,24,12,48,120,204,252,204,0,96,192,48,120,204,252,
+204,0,120,132,48,120,204,252,204,0,102,152,48,120,204,252,204,0,204,0,48,
+120,204,252,204,0,48,72,48,120,204,252,204,0,62,120,152,156,248,152,158,
+0,60,102,192,192,192,102,28,48,48,24,254,98,120,98,254,0,24,48,254,98,120,
+98,254,0,56,68,254,98,120,98,254,0,102,0,254,98,120,98,254,0,96,48,120,
+48,48,48,120,0,24,48,120,48,48,48,120,0,120,132,120,48,48,48,120,0,204,
+0,120,48,48,48,120,0,120,108,102,246,102,108,120,0,102,152,230,246,222,
+206,198,0,48,24,124,198,198,198,124,0,24,48,124,198,198,198,124,0,56,68,
+124,198,198,198,124,0,102,152,124,198,198,198,124,0,198,0,124,198,198,198,
+124,0,0,198,108,56,56,108,198,0,6,124,206,154,178,230,120,192,96,48,204,
+204,204,204,252,0,24,48,204,204,204,204,252,0,120,132,204,204,204,204,252,
+0,204,0,204,204,204,204,252,0,24,48,204,204,120,48,120,0,96,120,108,120,
+96,96,96,0,120,204,196,220,198,198,220,192,48,24,120,12,124,204,118,0,24,
+48,120,12,124,204,118,0,120,132,120,12,124,204,118,0,102,152,120,12,124,
+204,118,0,204,0,120,12,124,204,118,0,48,72,56,12,124,204,118,0,0,0,236,
+50,126,176,110,0,0,0,60,102,192,102,28,48,48,24,120,204,252,192,120,0,24,
+48,120,204,252,192,120,0,120,132,120,204,252,192,120,0,204,0,120,204,252,
+192,120,0,96,48,0,112,48,48,120,0,24,48,0,112,48,48,120,0,112,136,0,112,
+48,48,120,0,204,0,0,112,48,48,120,0,108,56,108,12,108,204,120,0,102,152,
+248,204,204,204,204,0,96,48,0,124,198,198,124,0,24,48,0,124,198,198,124,
+0,56,68,0,124,198,198,124,0,102,152,0,124,198,198,124,0,198,0,0,124,198,
+198,124,0,0,0,24,0,126,0,24,0,0,0,6,124,222,246,124,192,96,48,0,204,204,
+204,118,0,24,48,0,204,204,204,118,0,48,72,0,204,204,204,118,0,204,0,0,204,
+204,204,118,0,24,48,204,204,204,124,12,248,224,120,108,102,108,120,224,
+0,204,0,204,204,204,124,12,248
+};
diff --git a/lib/libvgl/vgl.3 b/lib/libvgl/vgl.3
new file mode 100644
index 0000000..06d05a5
--- /dev/null
+++ b/lib/libvgl/vgl.3
@@ -0,0 +1,470 @@
+.\" Copyright (c) 1997 Søren Schmidt
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer,
+.\" in this position and unchanged.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 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 November 7, 1999
+.Dt VGL 3
+.Os
+.Sh NAME
+.Nm VGLBitmapAllocateBits ,
+.Nm VGLBitmapCopy ,
+.Nm VGLBitmapCreate ,
+.Nm VGLBitmapDestroy ,
+.Nm VGLBitmapPutChar ,
+.Nm VGLBitmapString ,
+.Nm VGLBlankDisplay ,
+.Nm VGLBox ,
+.Nm VGLCheckSwitch ,
+.Nm VGLClear ,
+.Nm VGLEllipse ,
+.Nm VGLEnd ,
+.Nm VGLFilledBox ,
+.Nm VGLFilledEllipse ,
+.Nm VGLGetXY ,
+.Nm VGLInit ,
+.Nm VGLLine ,
+.Nm VGLKeyboardInit ,
+.Nm VGLKeyboardEnd ,
+.Nm VGLKeyboardGetCh ,
+.Nm VGLMouseInit ,
+.Nm VGLMouseMode ,
+.Nm VGLMouseSetImage ,
+.Nm VGLMouseSetStdImage ,
+.Nm VGLMouseStatus ,
+.Nm VGLPanScreen ,
+.Nm VGLSetBorder ,
+.Nm VGLSetPalette ,
+.Nm VGLSetPaletteIndex ,
+.Nm VGLSetVScreenSize ,
+.Nm VGLSetXY ,
+.Nm VGLTextSetFontFile
+.Nd Video Graphics Library functions
+.Sh LIBRARY
+.Lb libvgl
+.Sh SYNOPSIS
+.In sys/fbio.h
+.In sys/consio.h
+.In sys/kbio.h
+.In vgl.h
+.Ft int
+.Fn VGLInit "int mode"
+.Ft void
+.Fn VGLEnd "void"
+.Ft void
+.Fn VGLCheckSwitch "void"
+.Ft int
+.Fn VGLTextSetFontFile "char *filename"
+.Ft int
+.Fn VGLKeyboardInit "int code"
+.Ft void
+.Fn VGLKeyboardEnd "void"
+.Ft int
+.Fn VGLKeyboardGetCh "void"
+.Ft int
+.Fn VGLMouseInit "int mode"
+.Ft void
+.Fn VGLMouseMode "int mode"
+.Ft int
+.Fn VGLMouseStatus "int *x" "int *y" "char *buttons"
+.Ft void
+.Fn VGLMouseSetImage "VGLBitmap *AndMask" "VGLBitmap *OrMask"
+.Ft void
+.Fn VGLMouseSetStdImage "void"
+.Ft u_long
+.Fn VGLGetXY "VGLBitmap *object" "int x" "int y"
+.Ft void
+.Fn VGLSetXY "VGLBitmap *object" "int x" "int y" "u_long color"
+.Ft void
+.Fn VGLLine "VGLBitmap *object" "int x1" "int y1" "int x2" "int y2" "u_long color"
+.Ft void
+.Fn VGLBox "VGLBitmap *object" "int x1" "int y1" "int x2" "int y2" "u_long color"
+.Ft void
+.Fn VGLFilledBox "VGLBitmap *object" "int x1" "int y1" "int x2" "int y2" "u_long color"
+.Ft void
+.Fn VGLEllipse "VGLBitmap *object" "int xc" "int yc" "int a" "int b" "u_long color"
+.Ft void
+.Fn VGLFilledEllipse "VGLBitmap *object" "int xc" "int yc" "int a" "int b" "u_long color"
+.Ft VGLBitmap *
+.Fn VGLBitmapCreate "int type" "int xsize" "int ysize" "byte *bits"
+.Ft void
+.Fn VGLBitmapDestroy "VGLBitmap *object"
+.Ft int
+.Fn VGLBitmapAllocateBits "VGLBitmap *object"
+.Ft int
+.Fn VGLBitmapCopy "VGLBitmap *src" "int srcx" "int srcy" "VGLBitmap *dst" "int dstx" "int dsty" "int width" "int hight"
+.Ft void
+.Fn VGLBitmapPutChar "VGLBitmap *Object" "int x" "int y" "byte ch" "byte fgcol" "byte bgcol" "int fill" "int dir"
+.Ft void
+.Fn VGLBitmapString "VGLBitmap *Object" "int x" "int y" "char *str" "byte fgcol" "byte bgcol" "int fill" "int dir"
+.Ft void
+.Fn VGLClear "VGLBitmap *object" "u_long color"
+.Ft void
+.Fn VGLSetPalette "byte *red" "byte *green" "byte *blue"
+.Ft void
+.Fn VGLSetPaletteIndex "byte color" "byte red" "byte green" "byte blue"
+.Ft void
+.Fn VGLSetBorder "byte color"
+.Ft int
+.Fn VGLSetVScreenSize "VGLBitmap *object" "int vxsize" "int vysize"
+.Ft int
+.Fn VGLPanScreen "VGLBitmap *object" "int x" "int y"
+.Ft void
+.Fn VGLBlankDisplay "int blank"
+.Sh DESCRIPTION
+.Nm Libvgl
+is a library that enables the programmer access to the graphics
+modes supported by the console driver (syscons).
+The library takes care of
+programming the actual video hardware, and provides a number of simple
+functions to do various graphic operations.
+There is also support for a
+mouse via the standard mouse system in
+.Fx ,
+see
+.Xr mouse 4 ,
+including the ability to transparently have a mouse pointer superimposed on
+the graphic image currently being worked on.
+The library takes care of screen switching by storing the current image in
+memory before switching to another virtual console, and restoring when the
+user switches back.
+This allows several graphic applications at once, but
+on different virtual consoles.
+.Pp
+Below is a short description of the various functions:
+.Pp
+.Fn VGLInit
+initialize the library and set up the graphic mode
+.Va mode .
+.Pp
+.Fn VGLEnd
+terminate graphic mode, and restore the screenmode that was active before
+.Fn VGLInit
+was called.
+.Pp
+.Fn VGLCheckSwitch
+if the program goes into longer periods of processing without doing
+any graphics output, calling this function occasionally will allow
+the system to switch screens.
+.Pp
+.Fn VGLTextSetFontFile
+instruct the char/string functions to use the font in file
+.Pa filename
+instead of the builtin font.
+.Pp
+.Fn VGLKeyboardInit
+set up the keyboard in the
+.Dq raw
+I/O mode and
+specify the key code to be used.
+.Va code
+must be
+.Dv VGL_XLATEKEYS ,
+.Dv VGL_CODEKEYS ,
+or
+.Dv VGL_RAWKEYS .
+When
+.Dv VGL_XLATEKEYS
+is specified, the keyboard translates the raw keyboard scan code into
+a character code.
+If
+.Dv VGL_RAWKEYS
+is used, the raw keyboard scan code is read as is.
+.Dv VGL_CODEKEYS
+is the intermediate key code; each key is assigned a unique code whereas
+more than one raw scan code may be generated when a key is pressed.
+.Pp
+.Fn VGLKeyboardEnd
+when you have finished using the keyboard, call this function.
+.Pp
+.Fn VGLKeyboardGetCh
+read one byte from the keyboard.
+As the keyboard I/O is in the
+.Dq raw
+input mode, the function will not block even if there is no input data,
+and returns 0.
+.Pp
+.Fn VGLMouseInit
+initialize the mouse.
+The optional on-screen mouse pointer is shown if the
+argument is
+.Dv VGL_MOUSESHOW .
+.Pp
+.Fn VGLMouseMode
+either shows the mouse pointer if the argument is
+.Dv VGL_MOUSESHOW ,
+or hides the mouse pointer if the argument is
+.Dv VGL_MOUSEHIDE .
+.Pp
+.Fn VGLMouseStatus
+returns the current mouse pointer coordinates and button state in
+.Va x , y ,
+buttons.
+The return value reflects if the mouse pointer
+is currently shown on screen or not.
+.Pp
+.Fn VGLMouseSetImage
+with this function it is possible to change the image of the mouse pointer
+on screen.
+.Pp
+.Fn VGLMouseSetStdImage
+this function restores the mouse pointer to the standard arrow.
+.Pp
+.Fn VGLGetXY
+retrieves the color of the pixel located at
+.Va x , y ,
+coordinates of the
+.Va object
+argument, and returns it as a byte value.
+.Pp
+.Fn VGLSetXY
+sets the color of the pixel located at
+.Va x , y ,
+coordinates of the
+.Va object
+argument to
+.Va color
+byte value.
+.Pp
+.Fn VGLLine
+draw a line from
+.Va x1 , y1
+to
+.Va x2 , y2
+in color
+.Va color .
+.Pp
+.Fn VGLBox
+draw a box with upper left hand corner at
+.Va x1 , y1
+and lower right hand corner at
+.Va x2 , y2
+in color
+.Va color .
+.Pp
+.Fn VGLFilledBox
+draw a filled (solid) box with upper left hand corner at
+.Va x1 , y1
+and lower right hand corner at
+.Va x2 , y2
+in color
+.Va color .
+.Pp
+.Fn VGLEllipse
+draw an ellipse centered at
+.Va xc , yc
+make it
+.Va a
+pixels wide, and
+.Va b
+pixels high in color
+.Va color .
+.Pp
+.Fn VGLFilledEllipse
+draw a filled (solid) ellipse centered at
+.Va xc , yc
+make it
+.Va a
+pixels wide, and
+.Va b
+pixels high in color
+.Va color .
+.Pp
+.Fn VGLBitmapCreate
+create a bitmap object and initialize it with the specified
+values and bit data.
+.Va type
+must be
+.Dv MEMBUF
+for the in-memory bitmap.
+.Va bits
+may be NULL so that bitmap data may be associated later.
+.Pp
+There also is a macro,
+.Fn VGLBITMAP_INITIALIZER "type" "xsize" "ysize" "bits"
+to initialize a statically declared bitmap object.
+.Pp
+.Fn VGLBitmapDestroy
+free the bitmap data and the bitmap object.
+.Pp
+.Fn VGLBitmapAllocateBits
+allocate a bit data buffer for the specified object.
+.Pp
+.Fn VGLBitmapCopy
+copy a rectangle of pixels from bitmap
+.Va src
+upper left hand corner at
+.Va srcx , srcy
+to bitmap
+.Va dst
+at
+.Va dstx , dsty
+of the size
+.Va width , height .
+.Pp
+.Fn VGLBitmapPutChar
+write the character
+.Va ch
+at position
+.Va x , y
+in foreground color
+.Va fgcol .
+If
+.Va fill
+is != 0, use the color
+.Va bgcol
+as background otherwise the background is transparent.
+The character is drawn in the direction specified by the argument
+.Va dir .
+.Pp
+.Fn VGLBitmapString
+write the string
+.Va str
+at position
+.Va x , y
+in foreground color
+.Va fgcol .
+If
+.Va fill
+is != 0, use the color
+.Va bgcol
+as background otherwise the background is transparent.
+The string is drawn in the direction specified by the argument
+.Va dir .
+.Pp
+.Fn VGLClear
+clears the entire bitmap to color
+.Va color .
+.Pp
+.Fn VGLSetPalette
+this function sets the palette used, the arguments
+.Va red , green , blue
+should point to byte arrays of 256 positions each.
+.Pp
+.Fn VGLSetPaletteIndex
+set the palette index
+.Va color
+to the specified RGB value.
+.Pp
+.Fn VGLSetBorder
+set the border color to color
+.Va color .
+.Pp
+.Fn VGLSetVScreenSize
+change the virtual screen size of the display.
+Note that this
+function must be called when our vty is in the foreground.
+And
+.Va object
+must be
+.Va VGLDisplay .
+Passing an in-memory bitmap to this function results in error.
+.Pp
+The desired virtual screen width may not be achievable because
+of the video card hardware.
+In such case the video driver (and
+underlaying video BIOS) may choose the next largest values.
+Always examine
+.Va object->VXsize
+and
+.Va VYsize
+after calling this function, in order to see how the virtual screen
+is actually set up.
+.Pp
+In order to set up the largest possible virtual screen, you may
+call this function with arbitrary large values.
+.Pp
+.Dl VGLSetVScreenSize(10000, 10000);
+.Pp
+.Fn VGLPanSreen
+change the origin of the displayed screen in the virtual screen.
+Note that this function must be called when our vty is in the
+foreground.
+.Va object
+must be
+.Va VGLDisplay .
+Passing an in-memory bitmap to this function results in error.
+.Pp
+.Fn VGLBlankDisplay
+blank the display if the argument
+.Va blank
+\*(Ne 0.
+This can be done to shut off the screen during display updates that
+the user should first see when it is done.
+.Ss Program termination and signal processing
+It is important to call
+.Fn VGLEnd
+before terminating the program.
+Care must be taken if you install signal handlers and try to call
+.Fn VGLEnd
+and
+.Xr exit 3
+to end the program.
+If a signal is caught while the program is inside
+.Nm libvgl
+functions,
+.Fn VGLEnd
+may not be able to properly restore the graphics hardware.
+.Pp
+The recommended way to handle signals and program termination is to
+have a flag to indicate signal's delivery.
+Your signal handlers set this flag but do not terminate
+the program immediately.
+The main part of the program checks the flag to see if it is
+supposed to terminate, and calls
+.Fn VGLEnd
+and
+.Xr exit 3
+if the flag is set.
+.Pp
+Note that
+.Fn VGLInit
+installs its internal signal handlers for
+.Dv SIGINT , SIGTERM , SIGSEGV ,
+and
+.Dv SIGBUS ,
+and terminates the program at appropriate time,
+after one of these signals is caught.
+If you want to have your own signal handlers for these signals,
+install handlers
+.Em after
+.Fn VGLInit .
+.Pp
+.Dv SIGUSR1
+and
+.Dv SIGUSR2
+are internally used by
+.Nm libvgl
+to control screen switching and the mouse pointer,
+and are not available to
+.Nm libvgl
+client programs.
+.Sh HISTORY
+The
+.Nm vgl
+library appeared in
+.Fx 3.0 .
+.Sh AUTHORS
+.An S\(/oren Schmidt Aq sos@FreeBSD.org
diff --git a/lib/libvgl/vgl.h b/lib/libvgl/vgl.h
new file mode 100644
index 0000000..1b84382
--- /dev/null
+++ b/lib/libvgl/vgl.h
@@ -0,0 +1,154 @@
+/*-
+ * Copyright (c) 1991-1997 Søren Schmidt
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 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$
+ */
+
+#ifndef _VGL_H_
+#define _VGL_H_
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <machine/cpufunc.h>
+
+typedef unsigned char byte;
+typedef struct {
+ byte Type;
+ int Xsize, Ysize;
+ int VXsize, VYsize;
+ int Xorigin, Yorigin;
+ byte *Bitmap;
+ int PixelBytes;
+} VGLBitmap;
+
+#define VGLBITMAP_INITIALIZER(t, x, y, bits) \
+ { (t), (x), (y), (x), (y), 0, 0, (bits) }
+
+/*
+ * Defined Type's
+ */
+#define MEMBUF 0
+#define VIDBUF4 1
+#define VIDBUF8 2
+#define VIDBUF8X 3
+#define VIDBUF8S 4
+#define VIDBUF4S 5
+#define VIDBUF16 6 /* Direct Color linear buffer */
+#define VIDBUF24 7 /* Direct Color linear buffer */
+#define VIDBUF32 8 /* Direct Color linear buffer */
+#define VIDBUF16S 9 /* Direct Color segmented buffer */
+#define VIDBUF24S 10 /* Direct Color segmented buffer */
+#define VIDBUF32S 11 /* Direct Color segmented buffer */
+#define NOBUF 255
+
+typedef struct VGLText {
+ byte Width, Height;
+ byte *BitmapArray;
+} VGLText;
+
+typedef struct VGLObject {
+ int Id;
+ int Type;
+ int Status;
+ int Xpos, Ypos;
+ int Xhot, Yhot;
+ VGLBitmap *Image;
+ VGLBitmap *Mask;
+ int (*CallBackFunction)();
+} VGLObject;
+
+#define MOUSE_IMG_SIZE 16
+#define VGL_MOUSEHIDE 0
+#define VGL_MOUSESHOW 1
+#define VGL_MOUSEFREEZE 0
+#define VGL_MOUSEUNFREEZE 1
+#define VGL_DIR_RIGHT 0
+#define VGL_DIR_UP 1
+#define VGL_DIR_LEFT 2
+#define VGL_DIR_DOWN 3
+#define VGL_RAWKEYS 1
+#define VGL_CODEKEYS 2
+#define VGL_XLATEKEYS 3
+
+extern video_adapter_info_t VGLAdpInfo;
+extern video_info_t VGLModeInfo;
+extern VGLBitmap *VGLDisplay;
+extern byte *VGLBuf;
+
+/*
+ * Prototypes
+ */
+/* bitmap.c */
+int __VGLBitmapCopy(VGLBitmap *src, int srcx, int srcy, VGLBitmap *dst, int dstx, int dsty, int width, int hight);
+int VGLBitmapCopy(VGLBitmap *src, int srcx, int srcy, VGLBitmap *dst, int dstx, int dsty, int width, int hight);
+VGLBitmap *VGLBitmapCreate(int type, int xsize, int ysize, byte *bits);
+void VGLBitmapDestroy(VGLBitmap *object);
+int VGLBitmapAllocateBits(VGLBitmap *object);
+/* keyboard.c */
+int VGLKeyboardInit(int mode);
+void VGLKeyboardEnd(void);
+int VGLKeyboardGetCh(void);
+/* main.c */
+void VGLEnd(void);
+int VGLInit(int mode);
+void VGLCheckSwitch(void);
+int VGLSetVScreenSize(VGLBitmap *object, int VXsize, int VYsize);
+int VGLPanScreen(VGLBitmap *object, int x, int y);
+int VGLSetSegment(unsigned int offset);
+/* mouse.c */
+void VGLMousePointerShow(void);
+void VGLMousePointerHide(void);
+void VGLMouseMode(int mode);
+void VGLMouseAction(int dummy);
+void VGLMouseSetImage(VGLBitmap *AndMask, VGLBitmap *OrMask);
+void VGLMouseSetStdImage(void);
+int VGLMouseInit(int mode);
+int VGLMouseStatus(int *x, int *y, char *buttons);
+int VGLMouseFreeze(int x, int y, int width, int hight, byte color);
+void VGLMouseUnFreeze(void);
+/* simple.c */
+void VGLSetXY(VGLBitmap *object, int x, int y, u_long color);
+u_long VGLGetXY(VGLBitmap *object, int x, int y);
+void VGLLine(VGLBitmap *object, int x1, int y1, int x2, int y2, u_long color);
+void VGLBox(VGLBitmap *object, int x1, int y1, int x2, int y2, u_long color);
+void VGLFilledBox(VGLBitmap *object, int x1, int y1, int x2, int y2, u_long color);
+void VGLEllipse(VGLBitmap *object, int xc, int yc, int a, int b, u_long color);
+void VGLFilledEllipse(VGLBitmap *object, int xc, int yc, int a, int b, u_long color);
+void VGLClear(VGLBitmap *object, u_long color);
+void VGLRestorePalette(void);
+void VGLSavePalette(void);
+void VGLSetPalette(byte *red, byte *green, byte *blue);
+void VGLSetPaletteIndex(byte color, byte red, byte green, byte blue);
+void VGLSetBorder(byte color);
+void VGLBlankDisplay(int blank);
+/* text.c */
+int VGLTextSetFontFile(char *filename);
+void VGLBitmapPutChar(VGLBitmap *Object, int x, int y, byte ch, byte fgcol, byte bgcol, int fill, int dir);
+void VGLBitmapString(VGLBitmap *Object, int x, int y, char *str, byte fgcol, byte bgcol, int fill, int dir);
+
+#endif /* !_VGL_H_ */
diff --git a/lib/libwrap/Makefile b/lib/libwrap/Makefile
new file mode 100644
index 0000000..c477b38
--- /dev/null
+++ b/lib/libwrap/Makefile
@@ -0,0 +1,34 @@
+#
+# $FreeBSD$
+#
+
+.include <bsd.own.mk>
+
+LIB= wrap
+SHLIB_MAJOR= 4
+INCS= tcpd.h
+MAN= hosts_access.3
+MAN+= hosts_access.5 hosts_options.5
+MLINKS= hosts_access.3 hosts_ctl.3 hosts_access.3 request_init.3 \
+ hosts_access.3 request_set.3
+
+.PATH: ${.CURDIR}/../../contrib/tcp_wrappers
+
+CFLAGS+=-DFACILITY=LOG_AUTH -DHOSTS_ACCESS -DNETGROUP -DDAEMON_UMASK=022 \
+ -DREAL_DAEMON_DIR=\"/usr/libexec\" -DPROCESS_OPTIONS \
+ -DSEVERITY=LOG_INFO -DRFC931_TIMEOUT=10 \
+ -DHOSTS_DENY=\"/etc/hosts.deny\" -DHOSTS_ALLOW=\"/etc/hosts.allow\" \
+ -DSYS_ERRLIST_DEFINED -DALWAYS_HOSTNAME -DUSE_STRSEP -DPROCESS_OPTIONS
+.if ${MK_NIS} == "no"
+CFLAGS+= -DUSE_GETDOMAIN
+.endif
+.if ${MK_INET6_SUPPORT} != "no"
+CFLAGS+=-DINET6
+.endif
+
+SRCS= clean_exit.c diag.c eval.c fix_options.c fromhost.c \
+ hosts_access.c hosts_ctl.c misc.c myvsyslog.c options.c \
+ percent_m.c percent_x.c refuse.c rfc931.c shell_cmd.c \
+ socket.c tli.c update.c workarounds.c libvars.c
+
+.include <bsd.lib.mk>
diff --git a/lib/libwrap/libvars.c b/lib/libwrap/libvars.c
new file mode 100644
index 0000000..5935c83
--- /dev/null
+++ b/lib/libwrap/libvars.c
@@ -0,0 +1,2 @@
+int allow_severity;
+int deny_severity;
diff --git a/lib/liby/Makefile b/lib/liby/Makefile
new file mode 100644
index 0000000..b7a3aff
--- /dev/null
+++ b/lib/liby/Makefile
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+LIB= y
+SRCS= main.c yyerror.c
+NO_PIC=
+
+.include <bsd.lib.mk>
diff --git a/lib/liby/main.c b/lib/liby/main.c
new file mode 100644
index 0000000..c2955c4
--- /dev/null
+++ b/lib/liby/main.c
@@ -0,0 +1,49 @@
+/*-
+ * 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. 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifndef lint
+static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/4/93";
+#endif /* not lint */
+
+#include <stdlib.h>
+
+int yyparse(void);
+
+int
+main(void)
+{
+ exit(yyparse());
+}
diff --git a/lib/liby/yyerror.c b/lib/liby/yyerror.c
new file mode 100644
index 0000000..c2159c8
--- /dev/null
+++ b/lib/liby/yyerror.c
@@ -0,0 +1,49 @@
+/*-
+ * 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. 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifndef lint
+static char sccsid[] = "@(#)yyerror.c 8.1 (Berkeley) 6/4/93";
+#endif /* not lint */
+
+#include <stdio.h>
+
+int
+yyerror(msg)
+char *msg;
+{
+ (void)fprintf(stderr, "%s\n", msg);
+ return(0);
+}
diff --git a/lib/libypclnt/Makefile b/lib/libypclnt/Makefile
new file mode 100644
index 0000000..de237de
--- /dev/null
+++ b/lib/libypclnt/Makefile
@@ -0,0 +1,55 @@
+# $FreeBSD$
+
+LIB= ypclnt
+SHLIB_MAJOR= 2
+SRCS= ypclnt_connect.c \
+ ypclnt_error.c \
+ ypclnt_free.c \
+ ypclnt_new.c \
+ ypclnt_passwd.c \
+ ${GENSRCS}
+CLEANFILES+= ${GENSRCS}
+INCS= ypclnt.h
+
+CFLAGS+= -I.
+WARNS?= 5
+
+GENSRCS=yp.h \
+ yp_clnt.c \
+ yppasswd.h \
+ yppasswd_xdr.c \
+ yppasswd_clnt.c \
+ yppasswd_private.h \
+ yppasswd_private_clnt.c \
+ yppasswd_private_xdr.c
+
+RPCGEN= rpcgen -C
+RPCSRC= ${.CURDIR}/../../include/rpcsvc/yp.x
+RPCSRC_PW= ${.CURDIR}/../../include/rpcsvc/yppasswd.x
+RPCSRC_PRIV= ${.CURDIR}/../../usr.sbin/rpc.yppasswdd/yppasswd_private.x
+
+yp.h: ${RPCSRC}
+ ${RPCGEN} -h -o ${.TARGET} ${RPCSRC}
+
+yp_clnt.c: ${RPCSRC}
+ ${RPCGEN} -l -o ${.TARGET} ${RPCSRC}
+
+yppasswd.h: ${RPCSRC_PW}
+ ${RPCGEN} -h -o ${.TARGET} ${RPCSRC_PW}
+
+yppasswd_xdr.c: ${RPCSRC_PW}
+ ${RPCGEN} -c -o ${.TARGET} ${RPCSRC_PW}
+
+yppasswd_clnt.c: ${RPCSRC_PW}
+ ${RPCGEN} -l -o ${.TARGET} ${RPCSRC_PW}
+
+yppasswd_private.h: ${RPCSRC_PRIV}
+ ${RPCGEN} -h -o ${.TARGET} ${RPCSRC_PRIV}
+
+yppasswd_private_xdr.c: ${RPCSRC_PRIV}
+ ${RPCGEN} -c -o ${.TARGET} ${RPCSRC_PRIV}
+
+yppasswd_private_clnt.c: ${RPCSRC_PRIV}
+ ${RPCGEN} -l -o ${.TARGET} ${RPCSRC_PRIV}
+
+.include <bsd.lib.mk>
diff --git a/lib/libypclnt/ypclnt.h b/lib/libypclnt/ypclnt.h
new file mode 100644
index 0000000..476981c
--- /dev/null
+++ b/lib/libypclnt/ypclnt.h
@@ -0,0 +1,62 @@
+/*-
+ * Copyright (c) 2002 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project by ThinkSec AS 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 _YPCLNT_H_INCLUDED
+
+typedef struct ypclnt ypclnt_t;
+struct ypclnt {
+ char *domain; /* Domain name */
+ char *map; /* Map name */
+ char *server; /* Server name */
+ char *error; /* Error message */
+};
+
+struct passwd;
+
+ypclnt_t *ypclnt_new(const char *, const char *, const char *);
+void ypclnt_free(ypclnt_t *);
+void ypclnt_error(ypclnt_t *, const char *, const char *, ...);
+int ypclnt_connect(ypclnt_t *);
+int ypclnt_havepasswdd(ypclnt_t *);
+int ypclnt_passwd(ypclnt_t *, const struct passwd *, const char *);
+
+#if defined(DEBUG) && defined(__GNUC__)
+#define YPCLNT_DEBUG(fmt...) warnx(__FUNCTION__ ": " fmt, ##fmt)
+#else
+#define YPCLNT_DEBUG(fmt...)
+#endif
+
+#endif
diff --git a/lib/libypclnt/ypclnt_connect.c b/lib/libypclnt/ypclnt_connect.c
new file mode 100644
index 0000000..5670fa4
--- /dev/null
+++ b/lib/libypclnt/ypclnt_connect.c
@@ -0,0 +1,90 @@
+/*-
+ * Copyright (c) 2002 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project by ThinkSec AS 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <rpcsvc/ypclnt.h>
+
+#include "ypclnt.h"
+
+int
+ypclnt_connect(ypclnt_t *ypclnt)
+{
+ int r;
+
+ /* get default domain name unless specified */
+ if (ypclnt->domain == NULL) {
+ if ((ypclnt->domain = malloc(MAXHOSTNAMELEN)) == NULL) {
+ ypclnt_error(ypclnt, __func__,
+ "%s", strerror(errno));
+ return (-1);
+ }
+ if (getdomainname(ypclnt->domain, MAXHOSTNAMELEN) != 0) {
+ ypclnt_error(ypclnt, __func__,
+ "can't get NIS domain name");
+ return (-1);
+ }
+ }
+ YPCLNT_DEBUG("domain '%s'", ypclnt->domain);
+
+ /* map must be specified */
+ if (ypclnt->map == NULL) {
+ ypclnt_error(ypclnt, __func__,
+ "caller must specify map name");
+ return (-1);
+ }
+ YPCLNT_DEBUG("map '%s'", ypclnt->map);
+
+ /* get master server for requested map unless specified */
+ if (ypclnt->server == NULL) {
+ r = yp_master(ypclnt->domain, ypclnt->map, &ypclnt->server);
+ if (r != 0) {
+ ypclnt_error(ypclnt, __func__,
+ "can't get NIS server name: %s", yperr_string(r));
+ return (-1);
+ }
+ }
+ YPCLNT_DEBUG("server '%s'", ypclnt->server);
+
+ ypclnt_error(ypclnt, NULL, NULL);
+ return (0);
+}
diff --git a/lib/libypclnt/ypclnt_error.c b/lib/libypclnt/ypclnt_error.c
new file mode 100644
index 0000000..a7d986f
--- /dev/null
+++ b/lib/libypclnt/ypclnt_error.c
@@ -0,0 +1,59 @@
+/*-
+ * Copyright (c) 2002 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project by ThinkSec AS 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "ypclnt.h"
+
+void
+ypclnt_error(ypclnt_t *ypclnt, const char *func, const char *fmt, ...)
+{
+ char *errmsg;
+ va_list ap;
+
+ free(ypclnt->error);
+ ypclnt->error = NULL;
+ if (fmt == NULL)
+ return;
+
+ va_start(ap, fmt);
+ vasprintf(&errmsg, fmt, ap);
+ va_end(ap);
+ asprintf(&ypclnt->error, "%s(): %s", func, errmsg);
+ free(errmsg);
+}
diff --git a/lib/libypclnt/ypclnt_free.c b/lib/libypclnt/ypclnt_free.c
new file mode 100644
index 0000000..f5e78a4
--- /dev/null
+++ b/lib/libypclnt/ypclnt_free.c
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 2002 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project by ThinkSec AS 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 "ypclnt.h"
+
+void
+ypclnt_free(ypclnt_t *ypclnt)
+{
+ if (ypclnt != NULL) {
+ free(ypclnt->domain);
+ free(ypclnt->map);
+ free(ypclnt->server);
+ free(ypclnt->error);
+ free(ypclnt);
+ }
+}
diff --git a/lib/libypclnt/ypclnt_get.c b/lib/libypclnt/ypclnt_get.c
new file mode 100644
index 0000000..8a70971
--- /dev/null
+++ b/lib/libypclnt/ypclnt_get.c
@@ -0,0 +1,52 @@
+/*-
+ * Copyright (c) 2002 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project by ThinkSec AS 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 "ypclnt.h"
+
+char *
+ypclnt_get(ypclnt_t *ypc, const char *key)
+{
+ char *value;
+ int len, r;
+
+ r = yp_match(ypc->domain, ypc->map,
+ key, (int)strlen(key), &value, &len);
+ if (r != 0) {
+ ypclnt_error(ypc, __func__, "%s", yperr_string(r));
+ return (NULL);
+ }
+ return (value);
+}
diff --git a/lib/libypclnt/ypclnt_new.c b/lib/libypclnt/ypclnt_new.c
new file mode 100644
index 0000000..650cfdd
--- /dev/null
+++ b/lib/libypclnt/ypclnt_new.c
@@ -0,0 +1,62 @@
+/*-
+ * Copyright (c) 2002 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project by ThinkSec AS 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 <string.h>
+
+#include "ypclnt.h"
+
+ypclnt_t *
+ypclnt_new(const char *domain, const char *map, const char *server)
+{
+ ypclnt_t *ypclnt;
+
+ if ((ypclnt = calloc(1, sizeof *ypclnt)) == NULL)
+ return (NULL);
+ if (domain != NULL && (ypclnt->domain = strdup(domain)) == NULL)
+ goto fail;
+ if (map != NULL && (ypclnt->map = strdup(map)) == NULL)
+ goto fail;
+ if (server != NULL && (ypclnt->server = strdup(server)) == NULL)
+ goto fail;
+ return (ypclnt);
+ fail:
+ free(ypclnt->domain);
+ free(ypclnt->map);
+ free(ypclnt->server);
+ free(ypclnt);
+ return (NULL);
+}
diff --git a/lib/libypclnt/ypclnt_passwd.c b/lib/libypclnt/ypclnt_passwd.c
new file mode 100644
index 0000000..6483794
--- /dev/null
+++ b/lib/libypclnt/ypclnt_passwd.c
@@ -0,0 +1,316 @@
+/*-
+ * Copyright (c) 2002 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project by ThinkSec AS 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <err.h>
+#include <errno.h>
+#include <netconfig.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <rpcsvc/ypclnt.h>
+#include <rpcsvc/yppasswd.h>
+
+#include "ypclnt.h"
+#include "yppasswd_private.h"
+
+static int yppasswd_remote(ypclnt_t *, const struct passwd *, const char *);
+static int yppasswd_local(ypclnt_t *, const struct passwd *);
+
+/*
+ * Determines the availability of rpc.yppasswdd. Returns -1 for not
+ * available (or unable to determine), 0 for available, 1 for available in
+ * master mode.
+ */
+int
+ypclnt_havepasswdd(ypclnt_t *ypclnt)
+{
+ struct netconfig *nc = NULL;
+ void *localhandle = 0;
+ CLIENT *clnt = NULL;
+ int ret;
+
+ /* check if rpc.yppasswdd is running */
+ if (getrpcport(ypclnt->server, YPPASSWDPROG,
+ YPPASSWDPROC_UPDATE, IPPROTO_UDP) == 0) {
+ ypclnt_error(ypclnt, __func__, "no rpc.yppasswdd on server");
+ return (-1);
+ }
+
+ /* if we're not root, use remote method */
+ if (getuid() != 0)
+ return (0);
+
+ /* try to connect to rpc.yppasswdd */
+ localhandle = setnetconfig();
+ while ((nc = getnetconfig(localhandle)) != NULL) {
+ if (nc->nc_protofmly != NULL &&
+ strcmp(nc->nc_protofmly, NC_LOOPBACK) == 0)
+ break;
+ }
+ if (nc == NULL) {
+ ypclnt_error(ypclnt, __func__,
+ "getnetconfig: %s", nc_sperror());
+ ret = 0;
+ goto done;
+ }
+ if ((clnt = clnt_tp_create(NULL, MASTER_YPPASSWDPROG,
+ MASTER_YPPASSWDVERS, nc)) == NULL) {
+ ypclnt_error(ypclnt, __func__,
+ "failed to connect to rpc.yppasswdd: %s",
+ clnt_spcreateerror(ypclnt->server));
+ ret = 0;
+ goto done;
+ } else
+ ret = 1;
+
+done:
+ if (clnt != NULL) {
+ clnt_destroy(clnt);
+ }
+ endnetconfig(localhandle);
+ return (ret);
+}
+
+/*
+ * Updates the NIS user information for the specified user.
+ */
+int
+ypclnt_passwd(ypclnt_t *ypclnt, const struct passwd *pwd, const char *passwd)
+{
+ switch (ypclnt_havepasswdd(ypclnt)) {
+ case 0:
+ YPCLNT_DEBUG("using remote update method");
+ return (yppasswd_remote(ypclnt, pwd, passwd));
+ case 1:
+ YPCLNT_DEBUG("using local update method");
+ return (yppasswd_local(ypclnt, pwd));
+ default:
+ YPCLNT_DEBUG("no rpc.yppasswdd");
+ return (-1);
+ }
+}
+
+/*
+ * yppasswd_remote and yppasswd_local are quite similar but still
+ * sufficiently different that merging them into one makes the code
+ * significantly less readable, IMHO, so we keep them separate.
+ */
+
+static int
+yppasswd_local(ypclnt_t *ypclnt, const struct passwd *pwd)
+{
+ struct master_yppasswd yppwd;
+ struct rpc_err rpcerr;
+ struct netconfig *nc = NULL;
+ void *localhandle = 0;
+ CLIENT *clnt = NULL;
+ int ret, *result;
+
+ /* fill the master_yppasswd structure */
+ memset(&yppwd, 0, sizeof yppwd);
+ yppwd.newpw.pw_uid = pwd->pw_uid;
+ yppwd.newpw.pw_gid = pwd->pw_gid;
+ yppwd.newpw.pw_change = pwd->pw_change;
+ yppwd.newpw.pw_expire = pwd->pw_expire;
+ yppwd.newpw.pw_fields = pwd->pw_fields;
+ yppwd.oldpass = strdup("");
+ yppwd.domain = strdup(ypclnt->domain);
+ if ((yppwd.newpw.pw_name = strdup(pwd->pw_name)) == NULL ||
+ (yppwd.newpw.pw_passwd = strdup(pwd->pw_passwd)) == NULL ||
+ (yppwd.newpw.pw_class = strdup(pwd->pw_class)) == NULL ||
+ (yppwd.newpw.pw_gecos = strdup(pwd->pw_gecos)) == NULL ||
+ (yppwd.newpw.pw_dir = strdup(pwd->pw_dir)) == NULL ||
+ (yppwd.newpw.pw_shell = strdup(pwd->pw_shell)) == NULL) {
+ ypclnt_error(ypclnt, __func__, strerror(errno));
+ ret = -1;
+ goto done;
+ }
+
+ /* connect to rpc.yppasswdd */
+ localhandle = setnetconfig();
+ while ((nc = getnetconfig(localhandle)) != NULL) {
+ if (nc->nc_protofmly != NULL &&
+ strcmp(nc->nc_protofmly, NC_LOOPBACK) == 0)
+ break;
+ }
+ if (nc == NULL) {
+ ypclnt_error(ypclnt, __func__,
+ "getnetconfig: %s", nc_sperror());
+ ret = -1;
+ goto done;
+ }
+ if ((clnt = clnt_tp_create(NULL, MASTER_YPPASSWDPROG,
+ MASTER_YPPASSWDVERS, nc)) == NULL) {
+ ypclnt_error(ypclnt, __func__,
+ "failed to connect to rpc.yppasswdd: %s",
+ clnt_spcreateerror(ypclnt->server));
+ ret = -1;
+ goto done;
+ }
+ clnt->cl_auth = authunix_create_default();
+
+ /* request the update */
+ result = yppasswdproc_update_master_1(&yppwd, clnt);
+
+ /* check for RPC errors */
+ clnt_geterr(clnt, &rpcerr);
+ if (rpcerr.re_status != RPC_SUCCESS) {
+ ypclnt_error(ypclnt, __func__,
+ "NIS password update failed: %s",
+ clnt_sperror(clnt, ypclnt->server));
+ ret = -1;
+ goto done;
+ }
+
+ /* check the result of the update */
+ if (result == NULL || *result != 0) {
+ ypclnt_error(ypclnt, __func__,
+ "NIS password update failed");
+ /* XXX how do we get more details? */
+ ret = -1;
+ goto done;
+ }
+
+ ypclnt_error(ypclnt, NULL, NULL);
+ ret = 0;
+
+ done:
+ if (clnt != NULL) {
+ auth_destroy(clnt->cl_auth);
+ clnt_destroy(clnt);
+ }
+ endnetconfig(localhandle);
+ free(yppwd.newpw.pw_name);
+ if (yppwd.newpw.pw_passwd != NULL) {
+ memset(yppwd.newpw.pw_passwd, 0, strlen(yppwd.newpw.pw_passwd));
+ free(yppwd.newpw.pw_passwd);
+ }
+ free(yppwd.newpw.pw_class);
+ free(yppwd.newpw.pw_gecos);
+ free(yppwd.newpw.pw_dir);
+ free(yppwd.newpw.pw_shell);
+ if (yppwd.oldpass != NULL) {
+ memset(yppwd.oldpass, 0, strlen(yppwd.oldpass));
+ free(yppwd.oldpass);
+ }
+ return (ret);
+}
+
+static int
+yppasswd_remote(ypclnt_t *ypclnt, const struct passwd *pwd, const char *passwd)
+{
+ struct yppasswd yppwd;
+ struct rpc_err rpcerr;
+ CLIENT *clnt = NULL;
+ int ret, *result;
+
+ /* fill the yppasswd structure */
+ memset(&yppwd, 0, sizeof yppwd);
+ yppwd.newpw.pw_uid = pwd->pw_uid;
+ yppwd.newpw.pw_gid = pwd->pw_gid;
+ if ((yppwd.newpw.pw_name = strdup(pwd->pw_name)) == NULL ||
+ (yppwd.newpw.pw_passwd = strdup(pwd->pw_passwd)) == NULL ||
+ (yppwd.newpw.pw_gecos = strdup(pwd->pw_gecos)) == NULL ||
+ (yppwd.newpw.pw_dir = strdup(pwd->pw_dir)) == NULL ||
+ (yppwd.newpw.pw_shell = strdup(pwd->pw_shell)) == NULL ||
+ (yppwd.oldpass = strdup(passwd ? passwd : "")) == NULL) {
+ ypclnt_error(ypclnt, __func__, strerror(errno));
+ ret = -1;
+ goto done;
+ }
+
+ /* connect to rpc.yppasswdd */
+ clnt = clnt_create(ypclnt->server, YPPASSWDPROG, YPPASSWDVERS, "udp");
+ if (clnt == NULL) {
+ ypclnt_error(ypclnt, __func__,
+ "failed to connect to rpc.yppasswdd: %s",
+ clnt_spcreateerror(ypclnt->server));
+ ret = -1;
+ goto done;
+ }
+ clnt->cl_auth = authunix_create_default();
+
+ /* request the update */
+ result = yppasswdproc_update_1(&yppwd, clnt);
+
+ /* check for RPC errors */
+ clnt_geterr(clnt, &rpcerr);
+ if (rpcerr.re_status != RPC_SUCCESS) {
+ ypclnt_error(ypclnt, __func__,
+ "NIS password update failed: %s",
+ clnt_sperror(clnt, ypclnt->server));
+ ret = -1;
+ goto done;
+ }
+
+ /* check the result of the update */
+ if (result == NULL || *result != 0) {
+ ypclnt_error(ypclnt, __func__,
+ "NIS password update failed");
+ /* XXX how do we get more details? */
+ ret = -1;
+ goto done;
+ }
+
+ ypclnt_error(ypclnt, NULL, NULL);
+ ret = 0;
+
+ done:
+ if (clnt != NULL) {
+ auth_destroy(clnt->cl_auth);
+ clnt_destroy(clnt);
+ }
+ free(yppwd.newpw.pw_name);
+ if (yppwd.newpw.pw_passwd != NULL) {
+ memset(yppwd.newpw.pw_passwd, 0, strlen(yppwd.newpw.pw_passwd));
+ free(yppwd.newpw.pw_passwd);
+ }
+ free(yppwd.newpw.pw_gecos);
+ free(yppwd.newpw.pw_dir);
+ free(yppwd.newpw.pw_shell);
+ if (yppwd.oldpass != NULL) {
+ memset(yppwd.oldpass, 0, strlen(yppwd.oldpass));
+ free(yppwd.oldpass);
+ }
+ return (ret);
+}
diff --git a/lib/libz/ChangeLog b/lib/libz/ChangeLog
new file mode 100644
index 0000000..7f6869d
--- /dev/null
+++ b/lib/libz/ChangeLog
@@ -0,0 +1,855 @@
+
+ ChangeLog file for zlib
+
+Changes in 1.2.3 (18 July 2005)
+- Apply security vulnerability fixes to contrib/infback9 as well
+- Clean up some text files (carriage returns, trailing space)
+- Update testzlib, vstudio, masmx64, and masmx86 in contrib [Vollant]
+
+Changes in 1.2.2.4 (11 July 2005)
+- Add inflatePrime() function for starting inflation at bit boundary
+- Avoid some Visual C warnings in deflate.c
+- Avoid more silly Visual C warnings in inflate.c and inftrees.c for 64-bit
+ compile
+- Fix some spelling errors in comments [Betts]
+- Correct inflateInit2() error return documentation in zlib.h
+- Added zran.c example of compressed data random access to examples
+ directory, shows use of inflatePrime()
+- Fix cast for assignments to strm->state in inflate.c and infback.c
+- Fix zlibCompileFlags() in zutil.c to use 1L for long shifts [Oberhumer]
+- Move declarations of gf2 functions to right place in crc32.c [Oberhumer]
+- Add cast in trees.c t avoid a warning [Oberhumer]
+- Avoid some warnings in fitblk.c, gun.c, gzjoin.c in examples [Oberhumer]
+- Update make_vms.com [Zinser]
+- Initialize state->write in inflateReset() since copied in inflate_fast()
+- Be more strict on incomplete code sets in inflate_table() and increase
+ ENOUGH and MAXD -- this repairs a possible security vulnerability for
+ invalid inflate input. Thanks to Tavis Ormandy and Markus Oberhumer for
+ discovering the vulnerability and providing test cases.
+- Add ia64 support to configure for HP-UX [Smith]
+- Add error return to gzread() for format or i/o error [Levin]
+- Use malloc.h for OS/2 [Necasek]
+
+Changes in 1.2.2.3 (27 May 2005)
+- Replace 1U constants in inflate.c and inftrees.c for 64-bit compile
+- Typecast fread() return values in gzio.c [Vollant]
+- Remove trailing space in minigzip.c outmode (VC++ can't deal with it)
+- Fix crc check bug in gzread() after gzungetc() [Heiner]
+- Add the deflateTune() function to adjust internal compression parameters
+- Add a fast gzip decompressor, gun.c, to examples (use of inflateBack)
+- Remove an incorrect assertion in examples/zpipe.c
+- Add C++ wrapper in infback9.h [Donais]
+- Fix bug in inflateCopy() when decoding fixed codes
+- Note in zlib.h how much deflateSetDictionary() actually uses
+- Remove USE_DICT_HEAD in deflate.c (would mess up inflate if used)
+- Add _WIN32_WCE to define WIN32 in zconf.in.h [Spencer]
+- Don't include stderr.h or errno.h for _WIN32_WCE in zutil.h [Spencer]
+- Add gzdirect() function to indicate transparent reads
+- Update contrib/minizip [Vollant]
+- Fix compilation of deflate.c when both ASMV and FASTEST [Oberhumer]
+- Add casts in crc32.c to avoid warnings [Oberhumer]
+- Add contrib/masmx64 [Vollant]
+- Update contrib/asm586, asm686, masmx86, testzlib, vstudio [Vollant]
+
+Changes in 1.2.2.2 (30 December 2004)
+- Replace structure assignments in deflate.c and inflate.c with zmemcpy to
+ avoid implicit memcpy calls (portability for no-library compilation)
+- Increase sprintf() buffer size in gzdopen() to allow for large numbers
+- Add INFLATE_STRICT to check distances against zlib header
+- Improve WinCE errno handling and comments [Chang]
+- Remove comment about no gzip header processing in FAQ
+- Add Z_FIXED strategy option to deflateInit2() to force fixed trees
+- Add updated make_vms.com [Coghlan], update README
+- Create a new "examples" directory, move gzappend.c there, add zpipe.c,
+ fitblk.c, gzlog.[ch], gzjoin.c, and zlib_how.html.
+- Add FAQ entry and comments in deflate.c on uninitialized memory access
+- Add Solaris 9 make options in configure [Gilbert]
+- Allow strerror() usage in gzio.c for STDC
+- Fix DecompressBuf in contrib/delphi/ZLib.pas [ManChesTer]
+- Update contrib/masmx86/inffas32.asm and gvmat32.asm [Vollant]
+- Use z_off_t for adler32_combine() and crc32_combine() lengths
+- Make adler32() much faster for small len
+- Use OS_CODE in deflate() default gzip header
+
+Changes in 1.2.2.1 (31 October 2004)
+- Allow inflateSetDictionary() call for raw inflate
+- Fix inflate header crc check bug for file names and comments
+- Add deflateSetHeader() and gz_header structure for custom gzip headers
+- Add inflateGetheader() to retrieve gzip headers
+- Add crc32_combine() and adler32_combine() functions
+- Add alloc_func, free_func, in_func, out_func to Z_PREFIX list
+- Use zstreamp consistently in zlib.h (inflate_back functions)
+- Remove GUNZIP condition from definition of inflate_mode in inflate.h
+ and in contrib/inflate86/inffast.S [Truta, Anderson]
+- Add support for AMD64 in contrib/inflate86/inffas86.c [Anderson]
+- Update projects/README.projects and projects/visualc6 [Truta]
+- Update win32/DLL_FAQ.txt [Truta]
+- Avoid warning under NO_GZCOMPRESS in gzio.c; fix typo [Truta]
+- Deprecate Z_ASCII; use Z_TEXT instead [Truta]
+- Use a new algorithm for setting strm->data_type in trees.c [Truta]
+- Do not define an exit() prototype in zutil.c unless DEBUG defined
+- Remove prototype of exit() from zutil.c, example.c, minigzip.c [Truta]
+- Add comment in zlib.h for Z_NO_FLUSH parameter to deflate()
+- Fix Darwin build version identification [Peterson]
+
+Changes in 1.2.2 (3 October 2004)
+- Update zlib.h comments on gzip in-memory processing
+- Set adler to 1 in inflateReset() to support Java test suite [Walles]
+- Add contrib/dotzlib [Ravn]
+- Update win32/DLL_FAQ.txt [Truta]
+- Update contrib/minizip [Vollant]
+- Move contrib/visual-basic.txt to old/ [Truta]
+- Fix assembler builds in projects/visualc6/ [Truta]
+
+Changes in 1.2.1.2 (9 September 2004)
+- Update INDEX file
+- Fix trees.c to update strm->data_type (no one ever noticed!)
+- Fix bug in error case in inflate.c, infback.c, and infback9.c [Brown]
+- Add "volatile" to crc table flag declaration (for DYNAMIC_CRC_TABLE)
+- Add limited multitasking protection to DYNAMIC_CRC_TABLE
+- Add NO_vsnprintf for VMS in zutil.h [Mozilla]
+- Don't declare strerror() under VMS [Mozilla]
+- Add comment to DYNAMIC_CRC_TABLE to use get_crc_table() to initialize
+- Update contrib/ada [Anisimkov]
+- Update contrib/minizip [Vollant]
+- Fix configure to not hardcode directories for Darwin [Peterson]
+- Fix gzio.c to not return error on empty files [Brown]
+- Fix indentation; update version in contrib/delphi/ZLib.pas and
+ contrib/pascal/zlibpas.pas [Truta]
+- Update mkasm.bat in contrib/masmx86 [Truta]
+- Update contrib/untgz [Truta]
+- Add projects/README.projects [Truta]
+- Add project for MS Visual C++ 6.0 in projects/visualc6 [Cadieux, Truta]
+- Update win32/DLL_FAQ.txt [Truta]
+- Update list of Z_PREFIX symbols in zconf.h [Randers-Pehrson, Truta]
+- Remove an unnecessary assignment to curr in inftrees.c [Truta]
+- Add OS/2 to exe builds in configure [Poltorak]
+- Remove err dummy parameter in zlib.h [Kientzle]
+
+Changes in 1.2.1.1 (9 January 2004)
+- Update email address in README
+- Several FAQ updates
+- Fix a big fat bug in inftrees.c that prevented decoding valid
+ dynamic blocks with only literals and no distance codes --
+ Thanks to "Hot Emu" for the bug report and sample file
+- Add a note to puff.c on no distance codes case.
+
+Changes in 1.2.1 (17 November 2003)
+- Remove a tab in contrib/gzappend/gzappend.c
+- Update some interfaces in contrib for new zlib functions
+- Update zlib version number in some contrib entries
+- Add Windows CE definition for ptrdiff_t in zutil.h [Mai, Truta]
+- Support shared libraries on Hurd and KFreeBSD [Brown]
+- Fix error in NO_DIVIDE option of adler32.c
+
+Changes in 1.2.0.8 (4 November 2003)
+- Update version in contrib/delphi/ZLib.pas and contrib/pascal/zlibpas.pas
+- Add experimental NO_DIVIDE #define in adler32.c
+ - Possibly faster on some processors (let me know if it is)
+- Correct Z_BLOCK to not return on first inflate call if no wrap
+- Fix strm->data_type on inflate() return to correctly indicate EOB
+- Add deflatePrime() function for appending in the middle of a byte
+- Add contrib/gzappend for an example of appending to a stream
+- Update win32/DLL_FAQ.txt [Truta]
+- Delete Turbo C comment in README [Truta]
+- Improve some indentation in zconf.h [Truta]
+- Fix infinite loop on bad input in configure script [Church]
+- Fix gzeof() for concatenated gzip files [Johnson]
+- Add example to contrib/visual-basic.txt [Michael B.]
+- Add -p to mkdir's in Makefile.in [vda]
+- Fix configure to properly detect presence or lack of printf functions
+- Add AS400 support [Monnerat]
+- Add a little Cygwin support [Wilson]
+
+Changes in 1.2.0.7 (21 September 2003)
+- Correct some debug formats in contrib/infback9
+- Cast a type in a debug statement in trees.c
+- Change search and replace delimiter in configure from % to # [Beebe]
+- Update contrib/untgz to 0.2 with various fixes [Truta]
+- Add build support for Amiga [Nikl]
+- Remove some directories in old that have been updated to 1.2
+- Add dylib building for Mac OS X in configure and Makefile.in
+- Remove old distribution stuff from Makefile
+- Update README to point to DLL_FAQ.txt, and add comment on Mac OS X
+- Update links in README
+
+Changes in 1.2.0.6 (13 September 2003)
+- Minor FAQ updates
+- Update contrib/minizip to 1.00 [Vollant]
+- Remove test of gz functions in example.c when GZ_COMPRESS defined [Truta]
+- Update POSTINC comment for 68060 [Nikl]
+- Add contrib/infback9 with deflate64 decoding (unsupported)
+- For MVS define NO_vsnprintf and undefine FAR [van Burik]
+- Add pragma for fdopen on MVS [van Burik]
+
+Changes in 1.2.0.5 (8 September 2003)
+- Add OF to inflateBackEnd() declaration in zlib.h
+- Remember start when using gzdopen in the middle of a file
+- Use internal off_t counters in gz* functions to properly handle seeks
+- Perform more rigorous check for distance-too-far in inffast.c
+- Add Z_BLOCK flush option to return from inflate at block boundary
+- Set strm->data_type on return from inflate
+ - Indicate bits unused, if at block boundary, and if in last block
+- Replace size_t with ptrdiff_t in crc32.c, and check for correct size
+- Add condition so old NO_DEFLATE define still works for compatibility
+- FAQ update regarding the Windows DLL [Truta]
+- INDEX update: add qnx entry, remove aix entry [Truta]
+- Install zlib.3 into mandir [Wilson]
+- Move contrib/zlib_dll_FAQ.txt to win32/DLL_FAQ.txt; update [Truta]
+- Adapt the zlib interface to the new DLL convention guidelines [Truta]
+- Introduce ZLIB_WINAPI macro to allow the export of functions using
+ the WINAPI calling convention, for Visual Basic [Vollant, Truta]
+- Update msdos and win32 scripts and makefiles [Truta]
+- Export symbols by name, not by ordinal, in win32/zlib.def [Truta]
+- Add contrib/ada [Anisimkov]
+- Move asm files from contrib/vstudio/vc70_32 to contrib/asm386 [Truta]
+- Rename contrib/asm386 to contrib/masmx86 [Truta, Vollant]
+- Add contrib/masm686 [Truta]
+- Fix offsets in contrib/inflate86 and contrib/masmx86/inffas32.asm
+ [Truta, Vollant]
+- Update contrib/delphi; rename to contrib/pascal; add example [Truta]
+- Remove contrib/delphi2; add a new contrib/delphi [Truta]
+- Avoid inclusion of the nonstandard <memory.h> in contrib/iostream,
+ and fix some method prototypes [Truta]
+- Fix the ZCR_SEED2 constant to avoid warnings in contrib/minizip
+ [Truta]
+- Avoid the use of backslash (\) in contrib/minizip [Vollant]
+- Fix file time handling in contrib/untgz; update makefiles [Truta]
+- Update contrib/vstudio/vc70_32 to comply with the new DLL guidelines
+ [Vollant]
+- Remove contrib/vstudio/vc15_16 [Vollant]
+- Rename contrib/vstudio/vc70_32 to contrib/vstudio/vc7 [Truta]
+- Update README.contrib [Truta]
+- Invert the assignment order of match_head and s->prev[...] in
+ INSERT_STRING [Truta]
+- Compare TOO_FAR with 32767 instead of 32768, to avoid 16-bit warnings
+ [Truta]
+- Compare function pointers with 0, not with NULL or Z_NULL [Truta]
+- Fix prototype of syncsearch in inflate.c [Truta]
+- Introduce ASMINF macro to be enabled when using an ASM implementation
+ of inflate_fast [Truta]
+- Change NO_DEFLATE to NO_GZCOMPRESS [Truta]
+- Modify test_gzio in example.c to take a single file name as a
+ parameter [Truta]
+- Exit the example.c program if gzopen fails [Truta]
+- Add type casts around strlen in example.c [Truta]
+- Remove casting to sizeof in minigzip.c; give a proper type
+ to the variable compared with SUFFIX_LEN [Truta]
+- Update definitions of STDC and STDC99 in zconf.h [Truta]
+- Synchronize zconf.h with the new Windows DLL interface [Truta]
+- Use SYS16BIT instead of __32BIT__ to distinguish between
+ 16- and 32-bit platforms [Truta]
+- Use far memory allocators in small 16-bit memory models for
+ Turbo C [Truta]
+- Add info about the use of ASMV, ASMINF and ZLIB_WINAPI in
+ zlibCompileFlags [Truta]
+- Cygwin has vsnprintf [Wilson]
+- In Windows16, OS_CODE is 0, as in MSDOS [Truta]
+- In Cygwin, OS_CODE is 3 (Unix), not 11 (Windows32) [Wilson]
+
+Changes in 1.2.0.4 (10 August 2003)
+- Minor FAQ updates
+- Be more strict when checking inflateInit2's windowBits parameter
+- Change NO_GUNZIP compile option to NO_GZIP to cover deflate as well
+- Add gzip wrapper option to deflateInit2 using windowBits
+- Add updated QNX rule in configure and qnx directory [Bonnefoy]
+- Make inflate distance-too-far checks more rigorous
+- Clean up FAR usage in inflate
+- Add casting to sizeof() in gzio.c and minigzip.c
+
+Changes in 1.2.0.3 (19 July 2003)
+- Fix silly error in gzungetc() implementation [Vollant]
+- Update contrib/minizip and contrib/vstudio [Vollant]
+- Fix printf format in example.c
+- Correct cdecl support in zconf.in.h [Anisimkov]
+- Minor FAQ updates
+
+Changes in 1.2.0.2 (13 July 2003)
+- Add ZLIB_VERNUM in zlib.h for numerical preprocessor comparisons
+- Attempt to avoid warnings in crc32.c for pointer-int conversion
+- Add AIX to configure, remove aix directory [Bakker]
+- Add some casts to minigzip.c
+- Improve checking after insecure sprintf() or vsprintf() calls
+- Remove #elif's from crc32.c
+- Change leave label to inf_leave in inflate.c and infback.c to avoid
+ library conflicts
+- Remove inflate gzip decoding by default--only enable gzip decoding by
+ special request for stricter backward compatibility
+- Add zlibCompileFlags() function to return compilation information
+- More typecasting in deflate.c to avoid warnings
+- Remove leading underscore from _Capital #defines [Truta]
+- Fix configure to link shared library when testing
+- Add some Windows CE target adjustments [Mai]
+- Remove #define ZLIB_DLL in zconf.h [Vollant]
+- Add zlib.3 [Rodgers]
+- Update RFC URL in deflate.c and algorithm.txt [Mai]
+- Add zlib_dll_FAQ.txt to contrib [Truta]
+- Add UL to some constants [Truta]
+- Update minizip and vstudio [Vollant]
+- Remove vestigial NEED_DUMMY_RETURN from zconf.in.h
+- Expand use of NO_DUMMY_DECL to avoid all dummy structures
+- Added iostream3 to contrib [Schwardt]
+- Replace rewind() with fseek() for WinCE [Truta]
+- Improve setting of zlib format compression level flags
+ - Report 0 for huffman and rle strategies and for level == 0 or 1
+ - Report 2 only for level == 6
+- Only deal with 64K limit when necessary at compile time [Truta]
+- Allow TOO_FAR check to be turned off at compile time [Truta]
+- Add gzclearerr() function [Souza]
+- Add gzungetc() function
+
+Changes in 1.2.0.1 (17 March 2003)
+- Add Z_RLE strategy for run-length encoding [Truta]
+ - When Z_RLE requested, restrict matches to distance one
+ - Update zlib.h, minigzip.c, gzopen(), gzdopen() for Z_RLE
+- Correct FASTEST compilation to allow level == 0
+- Clean up what gets compiled for FASTEST
+- Incorporate changes to zconf.in.h [Vollant]
+ - Refine detection of Turbo C need for dummy returns
+ - Refine ZLIB_DLL compilation
+ - Include additional header file on VMS for off_t typedef
+- Try to use _vsnprintf where it supplants vsprintf [Vollant]
+- Add some casts in inffast.c
+- Enchance comments in zlib.h on what happens if gzprintf() tries to
+ write more than 4095 bytes before compression
+- Remove unused state from inflateBackEnd()
+- Remove exit(0) from minigzip.c, example.c
+- Get rid of all those darn tabs
+- Add "check" target to Makefile.in that does the same thing as "test"
+- Add "mostlyclean" and "maintainer-clean" targets to Makefile.in
+- Update contrib/inflate86 [Anderson]
+- Update contrib/testzlib, contrib/vstudio, contrib/minizip [Vollant]
+- Add msdos and win32 directories with makefiles [Truta]
+- More additions and improvements to the FAQ
+
+Changes in 1.2.0 (9 March 2003)
+- New and improved inflate code
+ - About 20% faster
+ - Does not allocate 32K window unless and until needed
+ - Automatically detects and decompresses gzip streams
+ - Raw inflate no longer needs an extra dummy byte at end
+ - Added inflateBack functions using a callback interface--even faster
+ than inflate, useful for file utilities (gzip, zip)
+ - Added inflateCopy() function to record state for random access on
+ externally generated deflate streams (e.g. in gzip files)
+ - More readable code (I hope)
+- New and improved crc32()
+ - About 50% faster, thanks to suggestions from Rodney Brown
+- Add deflateBound() and compressBound() functions
+- Fix memory leak in deflateInit2()
+- Permit setting dictionary for raw deflate (for parallel deflate)
+- Fix const declaration for gzwrite()
+- Check for some malloc() failures in gzio.c
+- Fix bug in gzopen() on single-byte file 0x1f
+- Fix bug in gzread() on concatenated file with 0x1f at end of buffer
+ and next buffer doesn't start with 0x8b
+- Fix uncompress() to return Z_DATA_ERROR on truncated input
+- Free memory at end of example.c
+- Remove MAX #define in trees.c (conflicted with some libraries)
+- Fix static const's in deflate.c, gzio.c, and zutil.[ch]
+- Declare malloc() and free() in gzio.c if STDC not defined
+- Use malloc() instead of calloc() in zutil.c if int big enough
+- Define STDC for AIX
+- Add aix/ with approach for compiling shared library on AIX
+- Add HP-UX support for shared libraries in configure
+- Add OpenUNIX support for shared libraries in configure
+- Use $cc instead of gcc to build shared library
+- Make prefix directory if needed when installing
+- Correct Macintosh avoidance of typedef Byte in zconf.h
+- Correct Turbo C memory allocation when under Linux
+- Use libz.a instead of -lz in Makefile (assure use of compiled library)
+- Update configure to check for snprintf or vsnprintf functions and their
+ return value, warn during make if using an insecure function
+- Fix configure problem with compile-time knowledge of HAVE_UNISTD_H that
+ is lost when library is used--resolution is to build new zconf.h
+- Documentation improvements (in zlib.h):
+ - Document raw deflate and inflate
+ - Update RFCs URL
+ - Point out that zlib and gzip formats are different
+ - Note that Z_BUF_ERROR is not fatal
+ - Document string limit for gzprintf() and possible buffer overflow
+ - Note requirement on avail_out when flushing
+ - Note permitted values of flush parameter of inflate()
+- Add some FAQs (and even answers) to the FAQ
+- Add contrib/inflate86/ for x86 faster inflate
+- Add contrib/blast/ for PKWare Data Compression Library decompression
+- Add contrib/puff/ simple inflate for deflate format description
+
+Changes in 1.1.4 (11 March 2002)
+- ZFREE was repeated on same allocation on some error conditions.
+ This creates a security problem described in
+ http://www.zlib.org/advisory-2002-03-11.txt
+- Returned incorrect error (Z_MEM_ERROR) on some invalid data
+- Avoid accesses before window for invalid distances with inflate window
+ less than 32K.
+- force windowBits > 8 to avoid a bug in the encoder for a window size
+ of 256 bytes. (A complete fix will be available in 1.1.5).
+
+Changes in 1.1.3 (9 July 1998)
+- fix "an inflate input buffer bug that shows up on rare but persistent
+ occasions" (Mark)
+- fix gzread and gztell for concatenated .gz files (Didier Le Botlan)
+- fix gzseek(..., SEEK_SET) in write mode
+- fix crc check after a gzeek (Frank Faubert)
+- fix miniunzip when the last entry in a zip file is itself a zip file
+ (J Lillge)
+- add contrib/asm586 and contrib/asm686 (Brian Raiter)
+ See http://www.muppetlabs.com/~breadbox/software/assembly.html
+- add support for Delphi 3 in contrib/delphi (Bob Dellaca)
+- add support for C++Builder 3 and Delphi 3 in contrib/delphi2 (Davide Moretti)
+- do not exit prematurely in untgz if 0 at start of block (Magnus Holmgren)
+- use macro EXTERN instead of extern to support DLL for BeOS (Sander Stoks)
+- added a FAQ file
+
+- Support gzdopen on Mac with Metrowerks (Jason Linhart)
+- Do not redefine Byte on Mac (Brad Pettit & Jason Linhart)
+- define SEEK_END too if SEEK_SET is not defined (Albert Chin-A-Young)
+- avoid some warnings with Borland C (Tom Tanner)
+- fix a problem in contrib/minizip/zip.c for 16-bit MSDOS (Gilles Vollant)
+- emulate utime() for WIN32 in contrib/untgz (Gilles Vollant)
+- allow several arguments to configure (Tim Mooney, Frodo Looijaard)
+- use libdir and includedir in Makefile.in (Tim Mooney)
+- support shared libraries on OSF1 V4 (Tim Mooney)
+- remove so_locations in "make clean" (Tim Mooney)
+- fix maketree.c compilation error (Glenn, Mark)
+- Python interface to zlib now in Python 1.5 (Jeremy Hylton)
+- new Makefile.riscos (Rich Walker)
+- initialize static descriptors in trees.c for embedded targets (Nick Smith)
+- use "foo-gz" in example.c for RISCOS and VMS (Nick Smith)
+- add the OS/2 files in Makefile.in too (Andrew Zabolotny)
+- fix fdopen and halloc macros for Microsoft C 6.0 (Tom Lane)
+- fix maketree.c to allow clean compilation of inffixed.h (Mark)
+- fix parameter check in deflateCopy (Gunther Nikl)
+- cleanup trees.c, use compressed_len only in debug mode (Christian Spieler)
+- Many portability patches by Christian Spieler:
+ . zutil.c, zutil.h: added "const" for zmem*
+ . Make_vms.com: fixed some typos
+ . Make_vms.com: msdos/Makefile.*: removed zutil.h from some dependency lists
+ . msdos/Makefile.msc: remove "default rtl link library" info from obj files
+ . msdos/Makefile.*: use model-dependent name for the built zlib library
+ . msdos/Makefile.emx, nt/Makefile.emx, nt/Makefile.gcc:
+ new makefiles, for emx (DOS/OS2), emx&rsxnt and mingw32 (Windows 9x / NT)
+- use define instead of typedef for Bytef also for MSC small/medium (Tom Lane)
+- replace __far with _far for better portability (Christian Spieler, Tom Lane)
+- fix test for errno.h in configure (Tim Newsham)
+
+Changes in 1.1.2 (19 March 98)
+- added contrib/minzip, mini zip and unzip based on zlib (Gilles Vollant)
+ See http://www.winimage.com/zLibDll/unzip.html
+- preinitialize the inflate tables for fixed codes, to make the code
+ completely thread safe (Mark)
+- some simplifications and slight speed-up to the inflate code (Mark)
+- fix gzeof on non-compressed files (Allan Schrum)
+- add -std1 option in configure for OSF1 to fix gzprintf (Martin Mokrejs)
+- use default value of 4K for Z_BUFSIZE for 16-bit MSDOS (Tim Wegner + Glenn)
+- added os2/Makefile.def and os2/zlib.def (Andrew Zabolotny)
+- add shared lib support for UNIX_SV4.2MP (MATSUURA Takanori)
+- do not wrap extern "C" around system includes (Tom Lane)
+- mention zlib binding for TCL in README (Andreas Kupries)
+- added amiga/Makefile.pup for Amiga powerUP SAS/C PPC (Andreas Kleinert)
+- allow "make install prefix=..." even after configure (Glenn Randers-Pehrson)
+- allow "configure --prefix $HOME" (Tim Mooney)
+- remove warnings in example.c and gzio.c (Glenn Randers-Pehrson)
+- move Makefile.sas to amiga/Makefile.sas
+
+Changes in 1.1.1 (27 Feb 98)
+- fix macros _tr_tally_* in deflate.h for debug mode (Glenn Randers-Pehrson)
+- remove block truncation heuristic which had very marginal effect for zlib
+ (smaller lit_bufsize than in gzip 1.2.4) and degraded a little the
+ compression ratio on some files. This also allows inlining _tr_tally for
+ matches in deflate_slow.
+- added msdos/Makefile.w32 for WIN32 Microsoft Visual C++ (Bob Frazier)
+
+Changes in 1.1.0 (24 Feb 98)
+- do not return STREAM_END prematurely in inflate (John Bowler)
+- revert to the zlib 1.0.8 inflate to avoid the gcc 2.8.0 bug (Jeremy Buhler)
+- compile with -DFASTEST to get compression code optimized for speed only
+- in minigzip, try mmap'ing the input file first (Miguel Albrecht)
+- increase size of I/O buffers in minigzip.c and gzio.c (not a big gain
+ on Sun but significant on HP)
+
+- add a pointer to experimental unzip library in README (Gilles Vollant)
+- initialize variable gcc in configure (Chris Herborth)
+
+Changes in 1.0.9 (17 Feb 1998)
+- added gzputs and gzgets functions
+- do not clear eof flag in gzseek (Mark Diekhans)
+- fix gzseek for files in transparent mode (Mark Diekhans)
+- do not assume that vsprintf returns the number of bytes written (Jens Krinke)
+- replace EXPORT with ZEXPORT to avoid conflict with other programs
+- added compress2 in zconf.h, zlib.def, zlib.dnt
+- new asm code from Gilles Vollant in contrib/asm386
+- simplify the inflate code (Mark):
+ . Replace ZALLOC's in huft_build() with single ZALLOC in inflate_blocks_new()
+ . ZALLOC the length list in inflate_trees_fixed() instead of using stack
+ . ZALLOC the value area for huft_build() instead of using stack
+ . Simplify Z_FINISH check in inflate()
+
+- Avoid gcc 2.8.0 comparison bug a little differently than zlib 1.0.8
+- in inftrees.c, avoid cc -O bug on HP (Farshid Elahi)
+- in zconf.h move the ZLIB_DLL stuff earlier to avoid problems with
+ the declaration of FAR (Gilles VOllant)
+- install libz.so* with mode 755 (executable) instead of 644 (Marc Lehmann)
+- read_buf buf parameter of type Bytef* instead of charf*
+- zmemcpy parameters are of type Bytef*, not charf* (Joseph Strout)
+- do not redeclare unlink in minigzip.c for WIN32 (John Bowler)
+- fix check for presence of directories in "make install" (Ian Willis)
+
+Changes in 1.0.8 (27 Jan 1998)
+- fixed offsets in contrib/asm386/gvmat32.asm (Gilles Vollant)
+- fix gzgetc and gzputc for big endian systems (Markus Oberhumer)
+- added compress2() to allow setting the compression level
+- include sys/types.h to get off_t on some systems (Marc Lehmann & QingLong)
+- use constant arrays for the static trees in trees.c instead of computing
+ them at run time (thanks to Ken Raeburn for this suggestion). To create
+ trees.h, compile with GEN_TREES_H and run "make test".
+- check return code of example in "make test" and display result
+- pass minigzip command line options to file_compress
+- simplifying code of inflateSync to avoid gcc 2.8 bug
+
+- support CC="gcc -Wall" in configure -s (QingLong)
+- avoid a flush caused by ftell in gzopen for write mode (Ken Raeburn)
+- fix test for shared library support to avoid compiler warnings
+- zlib.lib -> zlib.dll in msdos/zlib.rc (Gilles Vollant)
+- check for TARGET_OS_MAC in addition to MACOS (Brad Pettit)
+- do not use fdopen for Metrowerks on Mac (Brad Pettit))
+- add checks for gzputc and gzputc in example.c
+- avoid warnings in gzio.c and deflate.c (Andreas Kleinert)
+- use const for the CRC table (Ken Raeburn)
+- fixed "make uninstall" for shared libraries
+- use Tracev instead of Trace in infblock.c
+- in example.c use correct compressed length for test_sync
+- suppress +vnocompatwarnings in configure for HPUX (not always supported)
+
+Changes in 1.0.7 (20 Jan 1998)
+- fix gzseek which was broken in write mode
+- return error for gzseek to negative absolute position
+- fix configure for Linux (Chun-Chung Chen)
+- increase stack space for MSC (Tim Wegner)
+- get_crc_table and inflateSyncPoint are EXPORTed (Gilles Vollant)
+- define EXPORTVA for gzprintf (Gilles Vollant)
+- added man page zlib.3 (Rick Rodgers)
+- for contrib/untgz, fix makedir() and improve Makefile
+
+- check gzseek in write mode in example.c
+- allocate extra buffer for seeks only if gzseek is actually called
+- avoid signed/unsigned comparisons (Tim Wegner, Gilles Vollant)
+- add inflateSyncPoint in zconf.h
+- fix list of exported functions in nt/zlib.dnt and mdsos/zlib.def
+
+Changes in 1.0.6 (19 Jan 1998)
+- add functions gzprintf, gzputc, gzgetc, gztell, gzeof, gzseek, gzrewind and
+ gzsetparams (thanks to Roland Giersig and Kevin Ruland for some of this code)
+- Fix a deflate bug occurring only with compression level 0 (thanks to
+ Andy Buckler for finding this one).
+- In minigzip, pass transparently also the first byte for .Z files.
+- return Z_BUF_ERROR instead of Z_OK if output buffer full in uncompress()
+- check Z_FINISH in inflate (thanks to Marc Schluper)
+- Implement deflateCopy (thanks to Adam Costello)
+- make static libraries by default in configure, add --shared option.
+- move MSDOS or Windows specific files to directory msdos
+- suppress the notion of partial flush to simplify the interface
+ (but the symbol Z_PARTIAL_FLUSH is kept for compatibility with 1.0.4)
+- suppress history buffer provided by application to simplify the interface
+ (this feature was not implemented anyway in 1.0.4)
+- next_in and avail_in must be initialized before calling inflateInit or
+ inflateInit2
+- add EXPORT in all exported functions (for Windows DLL)
+- added Makefile.nt (thanks to Stephen Williams)
+- added the unsupported "contrib" directory:
+ contrib/asm386/ by Gilles Vollant <info@winimage.com>
+ 386 asm code replacing longest_match().
+ contrib/iostream/ by Kevin Ruland <kevin@rodin.wustl.edu>
+ A C++ I/O streams interface to the zlib gz* functions
+ contrib/iostream2/ by Tyge Løvset <Tyge.Lovset@cmr.no>
+ Another C++ I/O streams interface
+ contrib/untgz/ by "Pedro A. Aranda Guti\irrez" <paag@tid.es>
+ A very simple tar.gz file extractor using zlib
+ contrib/visual-basic.txt by Carlos Rios <c_rios@sonda.cl>
+ How to use compress(), uncompress() and the gz* functions from VB.
+- pass params -f (filtered data), -h (huffman only), -1 to -9 (compression
+ level) in minigzip (thanks to Tom Lane)
+
+- use const for rommable constants in deflate
+- added test for gzseek and gztell in example.c
+- add undocumented function inflateSyncPoint() (hack for Paul Mackerras)
+- add undocumented function zError to convert error code to string
+ (for Tim Smithers)
+- Allow compilation of gzio with -DNO_DEFLATE to avoid the compression code.
+- Use default memcpy for Symantec MSDOS compiler.
+- Add EXPORT keyword for check_func (needed for Windows DLL)
+- add current directory to LD_LIBRARY_PATH for "make test"
+- create also a link for libz.so.1
+- added support for FUJITSU UXP/DS (thanks to Toshiaki Nomura)
+- use $(SHAREDLIB) instead of libz.so in Makefile.in (for HPUX)
+- added -soname for Linux in configure (Chun-Chung Chen,
+- assign numbers to the exported functions in zlib.def (for Windows DLL)
+- add advice in zlib.h for best usage of deflateSetDictionary
+- work around compiler bug on Atari (cast Z_NULL in call of s->checkfn)
+- allow compilation with ANSI keywords only enabled for TurboC in large model
+- avoid "versionString"[0] (Borland bug)
+- add NEED_DUMMY_RETURN for Borland
+- use variable z_verbose for tracing in debug mode (L. Peter Deutsch).
+- allow compilation with CC
+- defined STDC for OS/2 (David Charlap)
+- limit external names to 8 chars for MVS (Thomas Lund)
+- in minigzip.c, use static buffers only for 16-bit systems
+- fix suffix check for "minigzip -d foo.gz"
+- do not return an error for the 2nd of two consecutive gzflush() (Felix Lee)
+- use _fdopen instead of fdopen for MSC >= 6.0 (Thomas Fanslau)
+- added makelcc.bat for lcc-win32 (Tom St Denis)
+- in Makefile.dj2, use copy and del instead of install and rm (Frank Donahoe)
+- Avoid expanded $Id$. Use "rcs -kb" or "cvs admin -kb" to avoid Id expansion.
+- check for unistd.h in configure (for off_t)
+- remove useless check parameter in inflate_blocks_free
+- avoid useless assignment of s->check to itself in inflate_blocks_new
+- do not flush twice in gzclose (thanks to Ken Raeburn)
+- rename FOPEN as F_OPEN to avoid clash with /usr/include/sys/file.h
+- use NO_ERRNO_H instead of enumeration of operating systems with errno.h
+- work around buggy fclose on pipes for HP/UX
+- support zlib DLL with BORLAND C++ 5.0 (thanks to Glenn Randers-Pehrson)
+- fix configure if CC is already equal to gcc
+
+Changes in 1.0.5 (3 Jan 98)
+- Fix inflate to terminate gracefully when fed corrupted or invalid data
+- Use const for rommable constants in inflate
+- Eliminate memory leaks on error conditions in inflate
+- Removed some vestigial code in inflate
+- Update web address in README
+
+Changes in 1.0.4 (24 Jul 96)
+- In very rare conditions, deflate(s, Z_FINISH) could fail to produce an EOF
+ bit, so the decompressor could decompress all the correct data but went
+ on to attempt decompressing extra garbage data. This affected minigzip too.
+- zlibVersion and gzerror return const char* (needed for DLL)
+- port to RISCOS (no fdopen, no multiple dots, no unlink, no fileno)
+- use z_error only for DEBUG (avoid problem with DLLs)
+
+Changes in 1.0.3 (2 Jul 96)
+- use z_streamp instead of z_stream *, which is now a far pointer in MSDOS
+ small and medium models; this makes the library incompatible with previous
+ versions for these models. (No effect in large model or on other systems.)
+- return OK instead of BUF_ERROR if previous deflate call returned with
+ avail_out as zero but there is nothing to do
+- added memcmp for non STDC compilers
+- define NO_DUMMY_DECL for more Mac compilers (.h files merged incorrectly)
+- define __32BIT__ if __386__ or i386 is defined (pb. with Watcom and SCO)
+- better check for 16-bit mode MSC (avoids problem with Symantec)
+
+Changes in 1.0.2 (23 May 96)
+- added Windows DLL support
+- added a function zlibVersion (for the DLL support)
+- fixed declarations using Bytef in infutil.c (pb with MSDOS medium model)
+- Bytef is define's instead of typedef'd only for Borland C
+- avoid reading uninitialized memory in example.c
+- mention in README that the zlib format is now RFC1950
+- updated Makefile.dj2
+- added algorithm.doc
+
+Changes in 1.0.1 (20 May 96) [1.0 skipped to avoid confusion]
+- fix array overlay in deflate.c which sometimes caused bad compressed data
+- fix inflate bug with empty stored block
+- fix MSDOS medium model which was broken in 0.99
+- fix deflateParams() which could generated bad compressed data.
+- Bytef is define'd instead of typedef'ed (work around Borland bug)
+- added an INDEX file
+- new makefiles for DJGPP (Makefile.dj2), 32-bit Borland (Makefile.b32),
+ Watcom (Makefile.wat), Amiga SAS/C (Makefile.sas)
+- speed up adler32 for modern machines without auto-increment
+- added -ansi for IRIX in configure
+- static_init_done in trees.c is an int
+- define unlink as delete for VMS
+- fix configure for QNX
+- add configure branch for SCO and HPUX
+- avoid many warnings (unused variables, dead assignments, etc...)
+- no fdopen for BeOS
+- fix the Watcom fix for 32 bit mode (define FAR as empty)
+- removed redefinition of Byte for MKWERKS
+- work around an MWKERKS bug (incorrect merge of all .h files)
+
+Changes in 0.99 (27 Jan 96)
+- allow preset dictionary shared between compressor and decompressor
+- allow compression level 0 (no compression)
+- add deflateParams in zlib.h: allow dynamic change of compression level
+ and compression strategy.
+- test large buffers and deflateParams in example.c
+- add optional "configure" to build zlib as a shared library
+- suppress Makefile.qnx, use configure instead
+- fixed deflate for 64-bit systems (detected on Cray)
+- fixed inflate_blocks for 64-bit systems (detected on Alpha)
+- declare Z_DEFLATED in zlib.h (possible parameter for deflateInit2)
+- always return Z_BUF_ERROR when deflate() has nothing to do
+- deflateInit and inflateInit are now macros to allow version checking
+- prefix all global functions and types with z_ with -DZ_PREFIX
+- make falloc completely reentrant (inftrees.c)
+- fixed very unlikely race condition in ct_static_init
+- free in reverse order of allocation to help memory manager
+- use zlib-1.0/* instead of zlib/* inside the tar.gz
+- make zlib warning-free with "gcc -O3 -Wall -Wwrite-strings -Wpointer-arith
+ -Wconversion -Wstrict-prototypes -Wmissing-prototypes"
+- allow gzread on concatenated .gz files
+- deflateEnd now returns Z_DATA_ERROR if it was premature
+- deflate is finally (?) fully deterministic (no matches beyond end of input)
+- Document Z_SYNC_FLUSH
+- add uninstall in Makefile
+- Check for __cpluplus in zlib.h
+- Better test in ct_align for partial flush
+- avoid harmless warnings for Borland C++
+- initialize hash_head in deflate.c
+- avoid warning on fdopen (gzio.c) for HP cc -Aa
+- include stdlib.h for STDC compilers
+- include errno.h for Cray
+- ignore error if ranlib doesn't exist
+- call ranlib twice for NeXTSTEP
+- use exec_prefix instead of prefix for libz.a
+- renamed ct_* as _tr_* to avoid conflict with applications
+- clear z->msg in inflateInit2 before any error return
+- initialize opaque in example.c, gzio.c, deflate.c and inflate.c
+- fixed typo in zconf.h (_GNUC__ => __GNUC__)
+- check for WIN32 in zconf.h and zutil.c (avoid farmalloc in 32-bit mode)
+- fix typo in Make_vms.com (f$trnlnm -> f$getsyi)
+- in fcalloc, normalize pointer if size > 65520 bytes
+- don't use special fcalloc for 32 bit Borland C++
+- use STDC instead of __GO32__ to avoid redeclaring exit, calloc, etc...
+- use Z_BINARY instead of BINARY
+- document that gzclose after gzdopen will close the file
+- allow "a" as mode in gzopen.
+- fix error checking in gzread
+- allow skipping .gz extra-field on pipes
+- added reference to Perl interface in README
+- put the crc table in FAR data (I dislike more and more the medium model :)
+- added get_crc_table
+- added a dimension to all arrays (Borland C can't count).
+- workaround Borland C bug in declaration of inflate_codes_new & inflate_fast
+- guard against multiple inclusion of *.h (for precompiled header on Mac)
+- Watcom C pretends to be Microsoft C small model even in 32 bit mode.
+- don't use unsized arrays to avoid silly warnings by Visual C++:
+ warning C4746: 'inflate_mask' : unsized array treated as '__far'
+ (what's wrong with far data in far model?).
+- define enum out of inflate_blocks_state to allow compilation with C++
+
+Changes in 0.95 (16 Aug 95)
+- fix MSDOS small and medium model (now easier to adapt to any compiler)
+- inlined send_bits
+- fix the final (:-) bug for deflate with flush (output was correct but
+ not completely flushed in rare occasions).
+- default window size is same for compression and decompression
+ (it's now sufficient to set MAX_WBITS in zconf.h).
+- voidp -> voidpf and voidnp -> voidp (for consistency with other
+ typedefs and because voidnp was not near in large model).
+
+Changes in 0.94 (13 Aug 95)
+- support MSDOS medium model
+- fix deflate with flush (could sometimes generate bad output)
+- fix deflateReset (zlib header was incorrectly suppressed)
+- added support for VMS
+- allow a compression level in gzopen()
+- gzflush now calls fflush
+- For deflate with flush, flush even if no more input is provided.
+- rename libgz.a as libz.a
+- avoid complex expression in infcodes.c triggering Turbo C bug
+- work around a problem with gcc on Alpha (in INSERT_STRING)
+- don't use inline functions (problem with some gcc versions)
+- allow renaming of Byte, uInt, etc... with #define.
+- avoid warning about (unused) pointer before start of array in deflate.c
+- avoid various warnings in gzio.c, example.c, infblock.c, adler32.c, zutil.c
+- avoid reserved word 'new' in trees.c
+
+Changes in 0.93 (25 June 95)
+- temporarily disable inline functions
+- make deflate deterministic
+- give enough lookahead for PARTIAL_FLUSH
+- Set binary mode for stdin/stdout in minigzip.c for OS/2
+- don't even use signed char in inflate (not portable enough)
+- fix inflate memory leak for segmented architectures
+
+Changes in 0.92 (3 May 95)
+- don't assume that char is signed (problem on SGI)
+- Clear bit buffer when starting a stored block
+- no memcpy on Pyramid
+- suppressed inftest.c
+- optimized fill_window, put longest_match inline for gcc
+- optimized inflate on stored blocks.
+- untabify all sources to simplify patches
+
+Changes in 0.91 (2 May 95)
+- Default MEM_LEVEL is 8 (not 9 for Unix) as documented in zlib.h
+- Document the memory requirements in zconf.h
+- added "make install"
+- fix sync search logic in inflateSync
+- deflate(Z_FULL_FLUSH) now works even if output buffer too short
+- after inflateSync, don't scare people with just "lo world"
+- added support for DJGPP
+
+Changes in 0.9 (1 May 95)
+- don't assume that zalloc clears the allocated memory (the TurboC bug
+ was Mark's bug after all :)
+- let again gzread copy uncompressed data unchanged (was working in 0.71)
+- deflate(Z_FULL_FLUSH), inflateReset and inflateSync are now fully implemented
+- added a test of inflateSync in example.c
+- moved MAX_WBITS to zconf.h because users might want to change that.
+- document explicitly that zalloc(64K) on MSDOS must return a normalized
+ pointer (zero offset)
+- added Makefiles for Microsoft C, Turbo C, Borland C++
+- faster crc32()
+
+Changes in 0.8 (29 April 95)
+- added fast inflate (inffast.c)
+- deflate(Z_FINISH) now returns Z_STREAM_END when done. Warning: this
+ is incompatible with previous versions of zlib which returned Z_OK.
+- work around a TurboC compiler bug (bad code for b << 0, see infutil.h)
+ (actually that was not a compiler bug, see 0.81 above)
+- gzread no longer reads one extra byte in certain cases
+- In gzio destroy(), don't reference a freed structure
+- avoid many warnings for MSDOS
+- avoid the ERROR symbol which is used by MS Windows
+
+Changes in 0.71 (14 April 95)
+- Fixed more MSDOS compilation problems :( There is still a bug with
+ TurboC large model.
+
+Changes in 0.7 (14 April 95)
+- Added full inflate support.
+- Simplified the crc32() interface. The pre- and post-conditioning
+ (one's complement) is now done inside crc32(). WARNING: this is
+ incompatible with previous versions; see zlib.h for the new usage.
+
+Changes in 0.61 (12 April 95)
+- workaround for a bug in TurboC. example and minigzip now work on MSDOS.
+
+Changes in 0.6 (11 April 95)
+- added minigzip.c
+- added gzdopen to reopen a file descriptor as gzFile
+- added transparent reading of non-gziped files in gzread.
+- fixed bug in gzread (don't read crc as data)
+- fixed bug in destroy (gzio.c) (don't return Z_STREAM_END for gzclose).
+- don't allocate big arrays in the stack (for MSDOS)
+- fix some MSDOS compilation problems
+
+Changes in 0.5:
+- do real compression in deflate.c. Z_PARTIAL_FLUSH is supported but
+ not yet Z_FULL_FLUSH.
+- support decompression but only in a single step (forced Z_FINISH)
+- added opaque object for zalloc and zfree.
+- added deflateReset and inflateReset
+- added a variable zlib_version for consistency checking.
+- renamed the 'filter' parameter of deflateInit2 as 'strategy'.
+ Added Z_FILTERED and Z_HUFFMAN_ONLY constants.
+
+Changes in 0.4:
+- avoid "zip" everywhere, use zlib instead of ziplib.
+- suppress Z_BLOCK_FLUSH, interpret Z_PARTIAL_FLUSH as block flush
+ if compression method == 8.
+- added adler32 and crc32
+- renamed deflateOptions as deflateInit2, call one or the other but not both
+- added the method parameter for deflateInit2.
+- added inflateInit2
+- simplied considerably deflateInit and inflateInit by not supporting
+ user-provided history buffer. This is supported only in deflateInit2
+ and inflateInit2.
+
+Changes in 0.3:
+- prefix all macro names with Z_
+- use Z_FINISH instead of deflateEnd to finish compression.
+- added Z_HUFFMAN_ONLY
+- added gzerror()
diff --git a/lib/libz/FAQ b/lib/libz/FAQ
new file mode 100644
index 0000000..441d910
--- /dev/null
+++ b/lib/libz/FAQ
@@ -0,0 +1,339 @@
+
+ Frequently Asked Questions about zlib
+
+
+If your question is not there, please check the zlib home page
+http://www.zlib.org which may have more recent information.
+The lastest zlib FAQ is at http://www.gzip.org/zlib/zlib_faq.html
+
+
+ 1. Is zlib Y2K-compliant?
+
+ Yes. zlib doesn't handle dates.
+
+ 2. Where can I get a Windows DLL version?
+
+ The zlib sources can be compiled without change to produce a DLL.
+ See the file win32/DLL_FAQ.txt in the zlib distribution.
+ Pointers to the precompiled DLL are found in the zlib web site at
+ http://www.zlib.org.
+
+ 3. Where can I get a Visual Basic interface to zlib?
+
+ See
+ * http://www.dogma.net/markn/articles/zlibtool/zlibtool.htm
+ * contrib/visual-basic.txt in the zlib distribution
+ * win32/DLL_FAQ.txt in the zlib distribution
+
+ 4. compress() returns Z_BUF_ERROR.
+
+ Make sure that before the call of compress, the length of the compressed
+ buffer is equal to the total size of the compressed buffer and not
+ zero. For Visual Basic, check that this parameter is passed by reference
+ ("as any"), not by value ("as long").
+
+ 5. deflate() or inflate() returns Z_BUF_ERROR.
+
+ Before making the call, make sure that avail_in and avail_out are not
+ zero. When setting the parameter flush equal to Z_FINISH, also make sure
+ that avail_out is big enough to allow processing all pending input.
+ Note that a Z_BUF_ERROR is not fatal--another call to deflate() or
+ inflate() can be made with more input or output space. A Z_BUF_ERROR
+ may in fact be unavoidable depending on how the functions are used, since
+ it is not possible to tell whether or not there is more output pending
+ when strm.avail_out returns with zero.
+
+ 6. Where's the zlib documentation (man pages, etc.)?
+
+ It's in zlib.h for the moment, and Francis S. Lin has converted it to a
+ web page zlib.html. Volunteers to transform this to Unix-style man pages,
+ please contact us (zlib@gzip.org). Examples of zlib usage are in the files
+ example.c and minigzip.c.
+
+ 7. Why don't you use GNU autoconf or libtool or ...?
+
+ Because we would like to keep zlib as a very small and simple
+ package. zlib is rather portable and doesn't need much configuration.
+
+ 8. I found a bug in zlib.
+
+ Most of the time, such problems are due to an incorrect usage of
+ zlib. Please try to reproduce the problem with a small program and send
+ the corresponding source to us at zlib@gzip.org . Do not send
+ multi-megabyte data files without prior agreement.
+
+ 9. Why do I get "undefined reference to gzputc"?
+
+ If "make test" produces something like
+
+ example.o(.text+0x154): undefined reference to `gzputc'
+
+ check that you don't have old files libz.* in /usr/lib, /usr/local/lib or
+ /usr/X11R6/lib. Remove any old versions, then do "make install".
+
+10. I need a Delphi interface to zlib.
+
+ See the contrib/delphi directory in the zlib distribution.
+
+11. Can zlib handle .zip archives?
+
+ Not by itself, no. See the directory contrib/minizip in the zlib
+ distribution.
+
+12. Can zlib handle .Z files?
+
+ No, sorry. You have to spawn an uncompress or gunzip subprocess, or adapt
+ the code of uncompress on your own.
+
+13. How can I make a Unix shared library?
+
+ make clean
+ ./configure -s
+ make
+
+14. How do I install a shared zlib library on Unix?
+
+ After the above, then:
+
+ make install
+
+ However, many flavors of Unix come with a shared zlib already installed.
+ Before going to the trouble of compiling a shared version of zlib and
+ trying to install it, you may want to check if it's already there! If you
+ can #include <zlib.h>, it's there. The -lz option will probably link to it.
+
+15. I have a question about OttoPDF.
+
+ We are not the authors of OttoPDF. The real author is on the OttoPDF web
+ site: Joel Hainley, jhainley@myndkryme.com.
+
+16. Can zlib decode Flate data in an Adobe PDF file?
+
+ Yes. See http://www.fastio.com/ (ClibPDF), or http://www.pdflib.com/ .
+ To modify PDF forms, see http://sourceforge.net/projects/acroformtool/ .
+
+17. Why am I getting this "register_frame_info not found" error on Solaris?
+
+ After installing zlib 1.1.4 on Solaris 2.6, running applications using zlib
+ generates an error such as:
+
+ ld.so.1: rpm: fatal: relocation error: file /usr/local/lib/libz.so:
+ symbol __register_frame_info: referenced symbol not found
+
+ The symbol __register_frame_info is not part of zlib, it is generated by
+ the C compiler (cc or gcc). You must recompile applications using zlib
+ which have this problem. This problem is specific to Solaris. See
+ http://www.sunfreeware.com for Solaris versions of zlib and applications
+ using zlib.
+
+18. Why does gzip give an error on a file I make with compress/deflate?
+
+ The compress and deflate functions produce data in the zlib format, which
+ is different and incompatible with the gzip format. The gz* functions in
+ zlib on the other hand use the gzip format. Both the zlib and gzip
+ formats use the same compressed data format internally, but have different
+ headers and trailers around the compressed data.
+
+19. Ok, so why are there two different formats?
+
+ The gzip format was designed to retain the directory information about
+ a single file, such as the name and last modification date. The zlib
+ format on the other hand was designed for in-memory and communication
+ channel applications, and has a much more compact header and trailer and
+ uses a faster integrity check than gzip.
+
+20. Well that's nice, but how do I make a gzip file in memory?
+
+ You can request that deflate write the gzip format instead of the zlib
+ format using deflateInit2(). You can also request that inflate decode
+ the gzip format using inflateInit2(). Read zlib.h for more details.
+
+21. Is zlib thread-safe?
+
+ Yes. However any library routines that zlib uses and any application-
+ provided memory allocation routines must also be thread-safe. zlib's gz*
+ functions use stdio library routines, and most of zlib's functions use the
+ library memory allocation routines by default. zlib's Init functions allow
+ for the application to provide custom memory allocation routines.
+
+ Of course, you should only operate on any given zlib or gzip stream from a
+ single thread at a time.
+
+22. Can I use zlib in my commercial application?
+
+ Yes. Please read the license in zlib.h.
+
+23. Is zlib under the GNU license?
+
+ No. Please read the license in zlib.h.
+
+24. The license says that altered source versions must be "plainly marked". So
+ what exactly do I need to do to meet that requirement?
+
+ You need to change the ZLIB_VERSION and ZLIB_VERNUM #defines in zlib.h. In
+ particular, the final version number needs to be changed to "f", and an
+ identification string should be appended to ZLIB_VERSION. Version numbers
+ x.x.x.f are reserved for modifications to zlib by others than the zlib
+ maintainers. For example, if the version of the base zlib you are altering
+ is "1.2.3.4", then in zlib.h you should change ZLIB_VERNUM to 0x123f, and
+ ZLIB_VERSION to something like "1.2.3.f-zachary-mods-v3". You can also
+ update the version strings in deflate.c and inftrees.c.
+
+ For altered source distributions, you should also note the origin and
+ nature of the changes in zlib.h, as well as in ChangeLog and README, along
+ with the dates of the alterations. The origin should include at least your
+ name (or your company's name), and an email address to contact for help or
+ issues with the library.
+
+ Note that distributing a compiled zlib library along with zlib.h and
+ zconf.h is also a source distribution, and so you should change
+ ZLIB_VERSION and ZLIB_VERNUM and note the origin and nature of the changes
+ in zlib.h as you would for a full source distribution.
+
+25. Will zlib work on a big-endian or little-endian architecture, and can I
+ exchange compressed data between them?
+
+ Yes and yes.
+
+26. Will zlib work on a 64-bit machine?
+
+ It should. It has been tested on 64-bit machines, and has no dependence
+ on any data types being limited to 32-bits in length. If you have any
+ difficulties, please provide a complete problem report to zlib@gzip.org
+
+27. Will zlib decompress data from the PKWare Data Compression Library?
+
+ No. The PKWare DCL uses a completely different compressed data format
+ than does PKZIP and zlib. However, you can look in zlib's contrib/blast
+ directory for a possible solution to your problem.
+
+28. Can I access data randomly in a compressed stream?
+
+ No, not without some preparation. If when compressing you periodically
+ use Z_FULL_FLUSH, carefully write all the pending data at those points,
+ and keep an index of those locations, then you can start decompression
+ at those points. You have to be careful to not use Z_FULL_FLUSH too
+ often, since it can significantly degrade compression.
+
+29. Does zlib work on MVS, OS/390, CICS, etc.?
+
+ We don't know for sure. We have heard occasional reports of success on
+ these systems. If you do use it on one of these, please provide us with
+ a report, instructions, and patches that we can reference when we get
+ these questions. Thanks.
+
+30. Is there some simpler, easier to read version of inflate I can look at
+ to understand the deflate format?
+
+ First off, you should read RFC 1951. Second, yes. Look in zlib's
+ contrib/puff directory.
+
+31. Does zlib infringe on any patents?
+
+ As far as we know, no. In fact, that was originally the whole point behind
+ zlib. Look here for some more information:
+
+ http://www.gzip.org/#faq11
+
+32. Can zlib work with greater than 4 GB of data?
+
+ Yes. inflate() and deflate() will process any amount of data correctly.
+ Each call of inflate() or deflate() is limited to input and output chunks
+ of the maximum value that can be stored in the compiler's "unsigned int"
+ type, but there is no limit to the number of chunks. Note however that the
+ strm.total_in and strm_total_out counters may be limited to 4 GB. These
+ counters are provided as a convenience and are not used internally by
+ inflate() or deflate(). The application can easily set up its own counters
+ updated after each call of inflate() or deflate() to count beyond 4 GB.
+ compress() and uncompress() may be limited to 4 GB, since they operate in a
+ single call. gzseek() and gztell() may be limited to 4 GB depending on how
+ zlib is compiled. See the zlibCompileFlags() function in zlib.h.
+
+ The word "may" appears several times above since there is a 4 GB limit
+ only if the compiler's "long" type is 32 bits. If the compiler's "long"
+ type is 64 bits, then the limit is 16 exabytes.
+
+33. Does zlib have any security vulnerabilities?
+
+ The only one that we are aware of is potentially in gzprintf(). If zlib
+ is compiled to use sprintf() or vsprintf(), then there is no protection
+ against a buffer overflow of a 4K string space, other than the caller of
+ gzprintf() assuring that the output will not exceed 4K. On the other
+ hand, if zlib is compiled to use snprintf() or vsnprintf(), which should
+ normally be the case, then there is no vulnerability. The ./configure
+ script will display warnings if an insecure variation of sprintf() will
+ be used by gzprintf(). Also the zlibCompileFlags() function will return
+ information on what variant of sprintf() is used by gzprintf().
+
+ If you don't have snprintf() or vsnprintf() and would like one, you can
+ find a portable implementation here:
+
+ http://www.ijs.si/software/snprintf/
+
+ Note that you should be using the most recent version of zlib. Versions
+ 1.1.3 and before were subject to a double-free vulnerability.
+
+34. Is there a Java version of zlib?
+
+ Probably what you want is to use zlib in Java. zlib is already included
+ as part of the Java SDK in the java.util.zip package. If you really want
+ a version of zlib written in the Java language, look on the zlib home
+ page for links: http://www.zlib.org/
+
+35. I get this or that compiler or source-code scanner warning when I crank it
+ up to maximally-pedantic. Can't you guys write proper code?
+
+ Many years ago, we gave up attempting to avoid warnings on every compiler
+ in the universe. It just got to be a waste of time, and some compilers
+ were downright silly. So now, we simply make sure that the code always
+ works.
+
+36. Valgrind (or some similar memory access checker) says that deflate is
+ performing a conditional jump that depends on an uninitialized value.
+ Isn't that a bug?
+
+ No. That is intentional for performance reasons, and the output of
+ deflate is not affected. This only started showing up recently since
+ zlib 1.2.x uses malloc() by default for allocations, whereas earlier
+ versions used calloc(), which zeros out the allocated memory.
+
+37. Will zlib read the (insert any ancient or arcane format here) compressed
+ data format?
+
+ Probably not. Look in the comp.compression FAQ for pointers to various
+ formats and associated software.
+
+38. How can I encrypt/decrypt zip files with zlib?
+
+ zlib doesn't support encryption. The original PKZIP encryption is very weak
+ and can be broken with freely available programs. To get strong encryption,
+ use GnuPG, http://www.gnupg.org/ , which already includes zlib compression.
+ For PKZIP compatible "encryption", look at http://www.info-zip.org/
+
+39. What's the difference between the "gzip" and "deflate" HTTP 1.1 encodings?
+
+ "gzip" is the gzip format, and "deflate" is the zlib format. They should
+ probably have called the second one "zlib" instead to avoid confusion
+ with the raw deflate compressed data format. While the HTTP 1.1 RFC 2616
+ correctly points to the zlib specification in RFC 1950 for the "deflate"
+ transfer encoding, there have been reports of servers and browsers that
+ incorrectly produce or expect raw deflate data per the deflate
+ specficiation in RFC 1951, most notably Microsoft. So even though the
+ "deflate" transfer encoding using the zlib format would be the more
+ efficient approach (and in fact exactly what the zlib format was designed
+ for), using the "gzip" transfer encoding is probably more reliable due to
+ an unfortunate choice of name on the part of the HTTP 1.1 authors.
+
+ Bottom line: use the gzip format for HTTP 1.1 encoding.
+
+40. Does zlib support the new "Deflate64" format introduced by PKWare?
+
+ No. PKWare has apparently decided to keep that format proprietary, since
+ they have not documented it as they have previous compression formats.
+ In any case, the compression improvements are so modest compared to other
+ more modern approaches, that it's not worth the effort to implement.
+
+41. Can you please sign these lengthy legal documents and fax them back to us
+ so that we can use your software in our product?
+
+ No. Go away. Shoo.
diff --git a/lib/libz/FREEBSD-upgrade b/lib/libz/FREEBSD-upgrade
new file mode 100644
index 0000000..4ee4eeb
--- /dev/null
+++ b/lib/libz/FREEBSD-upgrade
@@ -0,0 +1,44 @@
+$FreeBSD$
+
+ZLib 1.2.2
+
+Original distribution from http://www.gzip.org/zlib/
+
+Vendor files removed from distribution before import:
+ INDEX configure qnx/
+ Makefile contrib/ win32/
+ Makefile.in msdos/ zconf.in.h
+ amiga/ old/
+ as400/ projects/
+
+Vendor files imported:
+ ChangeLog example.c minigzip.c
+ FAQ gzio.c trees.c
+ README infback.c trees.h
+ adler32.c inffast.c uncompr.c
+ algorithm.txt inffast.h zconf.h
+ compress.c inffixed.h zlib.3
+ crc32.c inflate.c zlib.h
+ crc32.h inflate.h zutil.c
+ deflate.c inftrees.c zutil.h
+ deflate.h inftrees.h
+
+As of April, 2005, only the following three vendor files
+had non-trivial local changes:
+ gzio.c minigzip.c zconf.h
+
+Added files (not from vendor):
+ Makefile zopen.c FREEBSD-upgrade
+
+To Update:
+ 1) Unpack vendor sources into a clean directory.
+ 2) Delete unnecessary files.
+ 3) Import onto the vendor branch. The 1.2.2 import was done like this:
+ cvs -d <CVSROOT> import -ko -m "ZLib 1.2.2" src/lib/libz ZLIB v1_2_2
+ 4) In a clean directory, check out a fresh copy of HEAD,
+ merging in vendor changes since the last import.
+ cvs -d <CVSROOT> co -jZLIB:yesterday -jZLIB src/lib/libz
+ 5) Resolve any conflicts and commit them.
+ 6) Update this file with any changes to the file list or update procedure.
+
+kientzle@FreeBSD.org
diff --git a/lib/libz/Makefile b/lib/libz/Makefile
new file mode 100644
index 0000000..63383b4
--- /dev/null
+++ b/lib/libz/Makefile
@@ -0,0 +1,33 @@
+#
+# $FreeBSD$
+#
+
+LIB= z
+SHLIBDIR?= /lib
+MAN= zlib.3
+
+#CFLAGS+= -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7
+#CFLAGS+= -g -DDEBUG
+#CFLAGS+= -Wall -Wwrite-strings -Wpointer-arith -Wconversion \
+# -Wstrict-prototypes -Wmissing-prototypes
+
+CFLAGS+= -DHAS_snprintf -DHAS_vsnprintf
+
+CLEANFILES+= example.o example foo.gz minigzip.o minigzip
+
+SRCS = adler32.c compress.c crc32.c gzio.c uncompr.c deflate.c trees.c \
+ zutil.c inflate.c inftrees.c inffast.c zopen.c infback.c
+INCS= zconf.h zlib.h
+
+minigzip: all minigzip.o
+ $(CC) -o minigzip minigzip.o -L. -lz
+
+example: all example.o
+ $(CC) -o example example.o -L. -lz
+
+test: example minigzip
+ (export LD_LIBRARY_PATH=. ; ./example )
+ (export LD_LIBRARY_PATH=. ; \
+ echo hello world | ./minigzip | ./minigzip -d )
+
+.include <bsd.lib.mk>
diff --git a/lib/libz/README b/lib/libz/README
new file mode 100644
index 0000000..758cc50
--- /dev/null
+++ b/lib/libz/README
@@ -0,0 +1,125 @@
+ZLIB DATA COMPRESSION LIBRARY
+
+zlib 1.2.3 is a general purpose data compression library. All the code is
+thread safe. The data format used by the zlib library is described by RFCs
+(Request for Comments) 1950 to 1952 in the files
+http://www.ietf.org/rfc/rfc1950.txt (zlib format), rfc1951.txt (deflate format)
+and rfc1952.txt (gzip format). These documents are also available in other
+formats from ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html
+
+All functions of the compression library are documented in the file zlib.h
+(volunteer to write man pages welcome, contact zlib@gzip.org). A usage example
+of the library is given in the file example.c which also tests that the library
+is working correctly. Another example is given in the file minigzip.c. The
+compression library itself is composed of all source files except example.c and
+minigzip.c.
+
+To compile all files and run the test program, follow the instructions given at
+the top of Makefile. In short "make test; make install" should work for most
+machines. For Unix: "./configure; make test; make install". For MSDOS, use one
+of the special makefiles such as Makefile.msc. For VMS, use make_vms.com.
+
+Questions about zlib should be sent to <zlib@gzip.org>, or to Gilles Vollant
+<info@winimage.com> for the Windows DLL version. The zlib home page is
+http://www.zlib.org or http://www.gzip.org/zlib/ Before reporting a problem,
+please check this site to verify that you have the latest version of zlib;
+otherwise get the latest version and check whether the problem still exists or
+not.
+
+PLEASE read the zlib FAQ http://www.gzip.org/zlib/zlib_faq.html before asking
+for help.
+
+Mark Nelson <markn@ieee.org> wrote an article about zlib for the Jan. 1997
+issue of Dr. Dobb's Journal; a copy of the article is available in
+http://dogma.net/markn/articles/zlibtool/zlibtool.htm
+
+The changes made in version 1.2.3 are documented in the file ChangeLog.
+
+Unsupported third party contributions are provided in directory "contrib".
+
+A Java implementation of zlib is available in the Java Development Kit
+http://java.sun.com/j2se/1.4.2/docs/api/java/util/zip/package-summary.html
+See the zlib home page http://www.zlib.org for details.
+
+A Perl interface to zlib written by Paul Marquess <pmqs@cpan.org> is in the
+CPAN (Comprehensive Perl Archive Network) sites
+http://www.cpan.org/modules/by-module/Compress/
+
+A Python interface to zlib written by A.M. Kuchling <amk@amk.ca> is
+available in Python 1.5 and later versions, see
+http://www.python.org/doc/lib/module-zlib.html
+
+A zlib binding for TCL written by Andreas Kupries <a.kupries@westend.com> is
+availlable at http://www.oche.de/~akupries/soft/trf/trf_zip.html
+
+An experimental package to read and write files in .zip format, written on top
+of zlib by Gilles Vollant <info@winimage.com>, is available in the
+contrib/minizip directory of zlib.
+
+
+Notes for some targets:
+
+- For Windows DLL versions, please see win32/DLL_FAQ.txt
+
+- For 64-bit Irix, deflate.c must be compiled without any optimization. With
+ -O, one libpng test fails. The test works in 32 bit mode (with the -n32
+ compiler flag). The compiler bug has been reported to SGI.
+
+- zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1 it works
+ when compiled with cc.
+
+- On Digital Unix 4.0D (formely OSF/1) on AlphaServer, the cc option -std1 is
+ necessary to get gzprintf working correctly. This is done by configure.
+
+- zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works with
+ other compilers. Use "make test" to check your compiler.
+
+- gzdopen is not supported on RISCOS, BEOS and by some Mac compilers.
+
+- For PalmOs, see http://palmzlib.sourceforge.net/
+
+- When building a shared, i.e. dynamic library on Mac OS X, the library must be
+ installed before testing (do "make install" before "make test"), since the
+ library location is specified in the library.
+
+
+Acknowledgments:
+
+ The deflate format used by zlib was defined by Phil Katz. The deflate
+ and zlib specifications were written by L. Peter Deutsch. Thanks to all the
+ people who reported problems and suggested various improvements in zlib;
+ they are too numerous to cite here.
+
+Copyright notice:
+
+ (C) 1995-2004 Jean-loup Gailly and Mark Adler
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jean-loup Gailly Mark Adler
+ jloup@gzip.org madler@alumni.caltech.edu
+
+If you use the zlib library in a product, we would appreciate *not*
+receiving lengthy legal documents to sign. The sources are provided
+for free but without warranty of any kind. The library has been
+entirely written by Jean-loup Gailly and Mark Adler; it does not
+include third-party code.
+
+If you redistribute modified sources, we would appreciate that you include
+in the file ChangeLog history information documenting your changes. Please
+read the FAQ for more information on the distribution of modified source
+versions.
diff --git a/lib/libz/adler32.c b/lib/libz/adler32.c
new file mode 100644
index 0000000..007ba26
--- /dev/null
+++ b/lib/libz/adler32.c
@@ -0,0 +1,149 @@
+/* adler32.c -- compute the Adler-32 checksum of a data stream
+ * Copyright (C) 1995-2004 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+#define BASE 65521UL /* largest prime smaller than 65536 */
+#define NMAX 5552
+/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+
+#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;}
+#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
+#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
+#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
+#define DO16(buf) DO8(buf,0); DO8(buf,8);
+
+/* use NO_DIVIDE if your processor does not do division in hardware */
+#ifdef NO_DIVIDE
+# define MOD(a) \
+ do { \
+ if (a >= (BASE << 16)) a -= (BASE << 16); \
+ if (a >= (BASE << 15)) a -= (BASE << 15); \
+ if (a >= (BASE << 14)) a -= (BASE << 14); \
+ if (a >= (BASE << 13)) a -= (BASE << 13); \
+ if (a >= (BASE << 12)) a -= (BASE << 12); \
+ if (a >= (BASE << 11)) a -= (BASE << 11); \
+ if (a >= (BASE << 10)) a -= (BASE << 10); \
+ if (a >= (BASE << 9)) a -= (BASE << 9); \
+ if (a >= (BASE << 8)) a -= (BASE << 8); \
+ if (a >= (BASE << 7)) a -= (BASE << 7); \
+ if (a >= (BASE << 6)) a -= (BASE << 6); \
+ if (a >= (BASE << 5)) a -= (BASE << 5); \
+ if (a >= (BASE << 4)) a -= (BASE << 4); \
+ if (a >= (BASE << 3)) a -= (BASE << 3); \
+ if (a >= (BASE << 2)) a -= (BASE << 2); \
+ if (a >= (BASE << 1)) a -= (BASE << 1); \
+ if (a >= BASE) a -= BASE; \
+ } while (0)
+# define MOD4(a) \
+ do { \
+ if (a >= (BASE << 4)) a -= (BASE << 4); \
+ if (a >= (BASE << 3)) a -= (BASE << 3); \
+ if (a >= (BASE << 2)) a -= (BASE << 2); \
+ if (a >= (BASE << 1)) a -= (BASE << 1); \
+ if (a >= BASE) a -= BASE; \
+ } while (0)
+#else
+# define MOD(a) a %= BASE
+# define MOD4(a) a %= BASE
+#endif
+
+/* ========================================================================= */
+uLong ZEXPORT adler32(adler, buf, len)
+ uLong adler;
+ const Bytef *buf;
+ uInt len;
+{
+ unsigned long sum2;
+ unsigned n;
+
+ /* split Adler-32 into component sums */
+ sum2 = (adler >> 16) & 0xffff;
+ adler &= 0xffff;
+
+ /* in case user likes doing a byte at a time, keep it fast */
+ if (len == 1) {
+ adler += buf[0];
+ if (adler >= BASE)
+ adler -= BASE;
+ sum2 += adler;
+ if (sum2 >= BASE)
+ sum2 -= BASE;
+ return adler | (sum2 << 16);
+ }
+
+ /* initial Adler-32 value (deferred check for len == 1 speed) */
+ if (buf == Z_NULL)
+ return 1L;
+
+ /* in case short lengths are provided, keep it somewhat fast */
+ if (len < 16) {
+ while (len--) {
+ adler += *buf++;
+ sum2 += adler;
+ }
+ if (adler >= BASE)
+ adler -= BASE;
+ MOD4(sum2); /* only added so many BASE's */
+ return adler | (sum2 << 16);
+ }
+
+ /* do length NMAX blocks -- requires just one modulo operation */
+ while (len >= NMAX) {
+ len -= NMAX;
+ n = NMAX / 16; /* NMAX is divisible by 16 */
+ do {
+ DO16(buf); /* 16 sums unrolled */
+ buf += 16;
+ } while (--n);
+ MOD(adler);
+ MOD(sum2);
+ }
+
+ /* do remaining bytes (less than NMAX, still just one modulo) */
+ if (len) { /* avoid modulos if none remaining */
+ while (len >= 16) {
+ len -= 16;
+ DO16(buf);
+ buf += 16;
+ }
+ while (len--) {
+ adler += *buf++;
+ sum2 += adler;
+ }
+ MOD(adler);
+ MOD(sum2);
+ }
+
+ /* return recombined sums */
+ return adler | (sum2 << 16);
+}
+
+/* ========================================================================= */
+uLong ZEXPORT adler32_combine(adler1, adler2, len2)
+ uLong adler1;
+ uLong adler2;
+ z_off_t len2;
+{
+ unsigned long sum1;
+ unsigned long sum2;
+ unsigned rem;
+
+ /* the derivation of this formula is left as an exercise for the reader */
+ rem = (unsigned)(len2 % BASE);
+ sum1 = adler1 & 0xffff;
+ sum2 = rem * sum1;
+ MOD(sum2);
+ sum1 += (adler2 & 0xffff) + BASE - 1;
+ sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem;
+ if (sum1 > BASE) sum1 -= BASE;
+ if (sum1 > BASE) sum1 -= BASE;
+ if (sum2 > (BASE << 1)) sum2 -= (BASE << 1);
+ if (sum2 > BASE) sum2 -= BASE;
+ return sum1 | (sum2 << 16);
+}
diff --git a/lib/libz/algorithm.txt b/lib/libz/algorithm.txt
new file mode 100644
index 0000000..b022dde
--- /dev/null
+++ b/lib/libz/algorithm.txt
@@ -0,0 +1,209 @@
+1. Compression algorithm (deflate)
+
+The deflation algorithm used by gzip (also zip and zlib) is a variation of
+LZ77 (Lempel-Ziv 1977, see reference below). It finds duplicated strings in
+the input data. The second occurrence of a string is replaced by a
+pointer to the previous string, in the form of a pair (distance,
+length). Distances are limited to 32K bytes, and lengths are limited
+to 258 bytes. When a string does not occur anywhere in the previous
+32K bytes, it is emitted as a sequence of literal bytes. (In this
+description, `string' must be taken as an arbitrary sequence of bytes,
+and is not restricted to printable characters.)
+
+Literals or match lengths are compressed with one Huffman tree, and
+match distances are compressed with another tree. The trees are stored
+in a compact form at the start of each block. The blocks can have any
+size (except that the compressed data for one block must fit in
+available memory). A block is terminated when deflate() determines that
+it would be useful to start another block with fresh trees. (This is
+somewhat similar to the behavior of LZW-based _compress_.)
+
+Duplicated strings are found using a hash table. All input strings of
+length 3 are inserted in the hash table. A hash index is computed for
+the next 3 bytes. If the hash chain for this index is not empty, all
+strings in the chain are compared with the current input string, and
+the longest match is selected.
+
+The hash chains are searched starting with the most recent strings, to
+favor small distances and thus take advantage of the Huffman encoding.
+The hash chains are singly linked. There are no deletions from the
+hash chains, the algorithm simply discards matches that are too old.
+
+To avoid a worst-case situation, very long hash chains are arbitrarily
+truncated at a certain length, determined by a runtime option (level
+parameter of deflateInit). So deflate() does not always find the longest
+possible match but generally finds a match which is long enough.
+
+deflate() also defers the selection of matches with a lazy evaluation
+mechanism. After a match of length N has been found, deflate() searches for
+a longer match at the next input byte. If a longer match is found, the
+previous match is truncated to a length of one (thus producing a single
+literal byte) and the process of lazy evaluation begins again. Otherwise,
+the original match is kept, and the next match search is attempted only N
+steps later.
+
+The lazy match evaluation is also subject to a runtime parameter. If
+the current match is long enough, deflate() reduces the search for a longer
+match, thus speeding up the whole process. If compression ratio is more
+important than speed, deflate() attempts a complete second search even if
+the first match is already long enough.
+
+The lazy match evaluation is not performed for the fastest compression
+modes (level parameter 1 to 3). For these fast modes, new strings
+are inserted in the hash table only when no match was found, or
+when the match is not too long. This degrades the compression ratio
+but saves time since there are both fewer insertions and fewer searches.
+
+
+2. Decompression algorithm (inflate)
+
+2.1 Introduction
+
+The key question is how to represent a Huffman code (or any prefix code) so
+that you can decode fast. The most important characteristic is that shorter
+codes are much more common than longer codes, so pay attention to decoding the
+short codes fast, and let the long codes take longer to decode.
+
+inflate() sets up a first level table that covers some number of bits of
+input less than the length of longest code. It gets that many bits from the
+stream, and looks it up in the table. The table will tell if the next
+code is that many bits or less and how many, and if it is, it will tell
+the value, else it will point to the next level table for which inflate()
+grabs more bits and tries to decode a longer code.
+
+How many bits to make the first lookup is a tradeoff between the time it
+takes to decode and the time it takes to build the table. If building the
+table took no time (and if you had infinite memory), then there would only
+be a first level table to cover all the way to the longest code. However,
+building the table ends up taking a lot longer for more bits since short
+codes are replicated many times in such a table. What inflate() does is
+simply to make the number of bits in the first table a variable, and then
+to set that variable for the maximum speed.
+
+For inflate, which has 286 possible codes for the literal/length tree, the size
+of the first table is nine bits. Also the distance trees have 30 possible
+values, and the size of the first table is six bits. Note that for each of
+those cases, the table ended up one bit longer than the ``average'' code
+length, i.e. the code length of an approximately flat code which would be a
+little more than eight bits for 286 symbols and a little less than five bits
+for 30 symbols.
+
+
+2.2 More details on the inflate table lookup
+
+Ok, you want to know what this cleverly obfuscated inflate tree actually
+looks like. You are correct that it's not a Huffman tree. It is simply a
+lookup table for the first, let's say, nine bits of a Huffman symbol. The
+symbol could be as short as one bit or as long as 15 bits. If a particular
+symbol is shorter than nine bits, then that symbol's translation is duplicated
+in all those entries that start with that symbol's bits. For example, if the
+symbol is four bits, then it's duplicated 32 times in a nine-bit table. If a
+symbol is nine bits long, it appears in the table once.
+
+If the symbol is longer than nine bits, then that entry in the table points
+to another similar table for the remaining bits. Again, there are duplicated
+entries as needed. The idea is that most of the time the symbol will be short
+and there will only be one table look up. (That's whole idea behind data
+compression in the first place.) For the less frequent long symbols, there
+will be two lookups. If you had a compression method with really long
+symbols, you could have as many levels of lookups as is efficient. For
+inflate, two is enough.
+
+So a table entry either points to another table (in which case nine bits in
+the above example are gobbled), or it contains the translation for the symbol
+and the number of bits to gobble. Then you start again with the next
+ungobbled bit.
+
+You may wonder: why not just have one lookup table for how ever many bits the
+longest symbol is? The reason is that if you do that, you end up spending
+more time filling in duplicate symbol entries than you do actually decoding.
+At least for deflate's output that generates new trees every several 10's of
+kbytes. You can imagine that filling in a 2^15 entry table for a 15-bit code
+would take too long if you're only decoding several thousand symbols. At the
+other extreme, you could make a new table for every bit in the code. In fact,
+that's essentially a Huffman tree. But then you spend two much time
+traversing the tree while decoding, even for short symbols.
+
+So the number of bits for the first lookup table is a trade of the time to
+fill out the table vs. the time spent looking at the second level and above of
+the table.
+
+Here is an example, scaled down:
+
+The code being decoded, with 10 symbols, from 1 to 6 bits long:
+
+A: 0
+B: 10
+C: 1100
+D: 11010
+E: 11011
+F: 11100
+G: 11101
+H: 11110
+I: 111110
+J: 111111
+
+Let's make the first table three bits long (eight entries):
+
+000: A,1
+001: A,1
+010: A,1
+011: A,1
+100: B,2
+101: B,2
+110: -> table X (gobble 3 bits)
+111: -> table Y (gobble 3 bits)
+
+Each entry is what the bits decode as and how many bits that is, i.e. how
+many bits to gobble. Or the entry points to another table, with the number of
+bits to gobble implicit in the size of the table.
+
+Table X is two bits long since the longest code starting with 110 is five bits
+long:
+
+00: C,1
+01: C,1
+10: D,2
+11: E,2
+
+Table Y is three bits long since the longest code starting with 111 is six
+bits long:
+
+000: F,2
+001: F,2
+010: G,2
+011: G,2
+100: H,2
+101: H,2
+110: I,3
+111: J,3
+
+So what we have here are three tables with a total of 20 entries that had to
+be constructed. That's compared to 64 entries for a single table. Or
+compared to 16 entries for a Huffman tree (six two entry tables and one four
+entry table). Assuming that the code ideally represents the probability of
+the symbols, it takes on the average 1.25 lookups per symbol. That's compared
+to one lookup for the single table, or 1.66 lookups per symbol for the
+Huffman tree.
+
+There, I think that gives you a picture of what's going on. For inflate, the
+meaning of a particular symbol is often more than just a letter. It can be a
+byte (a "literal"), or it can be either a length or a distance which
+indicates a base value and a number of bits to fetch after the code that is
+added to the base value. Or it might be the special end-of-block code. The
+data structures created in inftrees.c try to encode all that information
+compactly in the tables.
+
+
+Jean-loup Gailly Mark Adler
+jloup@gzip.org madler@alumni.caltech.edu
+
+
+References:
+
+[LZ77] Ziv J., Lempel A., ``A Universal Algorithm for Sequential Data
+Compression,'' IEEE Transactions on Information Theory, Vol. 23, No. 3,
+pp. 337-343.
+
+``DEFLATE Compressed Data Format Specification'' available in
+http://www.ietf.org/rfc/rfc1951.txt
diff --git a/lib/libz/compress.c b/lib/libz/compress.c
new file mode 100644
index 0000000..df04f01
--- /dev/null
+++ b/lib/libz/compress.c
@@ -0,0 +1,79 @@
+/* compress.c -- compress a memory buffer
+ * Copyright (C) 1995-2003 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+/* ===========================================================================
+ Compresses the source buffer into the destination buffer. The level
+ parameter has the same meaning as in deflateInit. sourceLen is the byte
+ length of the source buffer. Upon entry, destLen is the total size of the
+ destination buffer, which must be at least 0.1% larger than sourceLen plus
+ 12 bytes. Upon exit, destLen is the actual size of the compressed buffer.
+
+ compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+ Z_STREAM_ERROR if the level parameter is invalid.
+*/
+int ZEXPORT compress2 (dest, destLen, source, sourceLen, level)
+ Bytef *dest;
+ uLongf *destLen;
+ const Bytef *source;
+ uLong sourceLen;
+ int level;
+{
+ z_stream stream;
+ int err;
+
+ stream.next_in = (Bytef*)source;
+ stream.avail_in = (uInt)sourceLen;
+#ifdef MAXSEG_64K
+ /* Check for source > 64K on 16-bit machine: */
+ if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
+#endif
+ stream.next_out = dest;
+ stream.avail_out = (uInt)*destLen;
+ if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
+
+ stream.zalloc = (alloc_func)0;
+ stream.zfree = (free_func)0;
+ stream.opaque = (voidpf)0;
+
+ err = deflateInit(&stream, level);
+ if (err != Z_OK) return err;
+
+ err = deflate(&stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ deflateEnd(&stream);
+ return err == Z_OK ? Z_BUF_ERROR : err;
+ }
+ *destLen = stream.total_out;
+
+ err = deflateEnd(&stream);
+ return err;
+}
+
+/* ===========================================================================
+ */
+int ZEXPORT compress (dest, destLen, source, sourceLen)
+ Bytef *dest;
+ uLongf *destLen;
+ const Bytef *source;
+ uLong sourceLen;
+{
+ return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION);
+}
+
+/* ===========================================================================
+ If the default memLevel or windowBits for deflateInit() is changed, then
+ this function needs to be updated.
+ */
+uLong ZEXPORT compressBound (sourceLen)
+ uLong sourceLen;
+{
+ return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + 11;
+}
diff --git a/lib/libz/crc32.c b/lib/libz/crc32.c
new file mode 100644
index 0000000..f658a9e
--- /dev/null
+++ b/lib/libz/crc32.c
@@ -0,0 +1,423 @@
+/* crc32.c -- compute the CRC-32 of a data stream
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Thanks to Rodney Brown <rbrown64@csc.com.au> for his contribution of faster
+ * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing
+ * tables for updating the shift register in one step with three exclusive-ors
+ * instead of four steps with four exclusive-ors. This results in about a
+ * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3.
+ */
+
+/* @(#) $Id$ */
+
+/*
+ Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore
+ protection on the static variables used to control the first-use generation
+ of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should
+ first call get_crc_table() to initialize the tables before allowing more than
+ one thread to use crc32().
+ */
+
+#ifdef MAKECRCH
+# include <stdio.h>
+# ifndef DYNAMIC_CRC_TABLE
+# define DYNAMIC_CRC_TABLE
+# endif /* !DYNAMIC_CRC_TABLE */
+#endif /* MAKECRCH */
+
+#include "zutil.h" /* for STDC and FAR definitions */
+
+#define local static
+
+/* Find a four-byte integer type for crc32_little() and crc32_big(). */
+#ifndef NOBYFOUR
+# ifdef STDC /* need ANSI C limits.h to determine sizes */
+# include <limits.h>
+# define BYFOUR
+# if (UINT_MAX == 0xffffffffUL)
+ typedef unsigned int u4;
+# else
+# if (ULONG_MAX == 0xffffffffUL)
+ typedef unsigned long u4;
+# else
+# if (USHRT_MAX == 0xffffffffUL)
+ typedef unsigned short u4;
+# else
+# undef BYFOUR /* can't find a four-byte integer type! */
+# endif
+# endif
+# endif
+# endif /* STDC */
+#endif /* !NOBYFOUR */
+
+/* Definitions for doing the crc four data bytes at a time. */
+#ifdef BYFOUR
+# define REV(w) (((w)>>24)+(((w)>>8)&0xff00)+ \
+ (((w)&0xff00)<<8)+(((w)&0xff)<<24))
+ local unsigned long crc32_little OF((unsigned long,
+ const unsigned char FAR *, unsigned));
+ local unsigned long crc32_big OF((unsigned long,
+ const unsigned char FAR *, unsigned));
+# define TBLS 8
+#else
+# define TBLS 1
+#endif /* BYFOUR */
+
+/* Local functions for crc concatenation */
+local unsigned long gf2_matrix_times OF((unsigned long *mat,
+ unsigned long vec));
+local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat));
+
+#ifdef DYNAMIC_CRC_TABLE
+
+local volatile int crc_table_empty = 1;
+local unsigned long FAR crc_table[TBLS][256];
+local void make_crc_table OF((void));
+#ifdef MAKECRCH
+ local void write_table OF((FILE *, const unsigned long FAR *));
+#endif /* MAKECRCH */
+/*
+ Generate tables for a byte-wise 32-bit CRC calculation on the polynomial:
+ x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.
+
+ Polynomials over GF(2) are represented in binary, one bit per coefficient,
+ with the lowest powers in the most significant bit. Then adding polynomials
+ is just exclusive-or, and multiplying a polynomial by x is a right shift by
+ one. If we call the above polynomial p, and represent a byte as the
+ polynomial q, also with the lowest power in the most significant bit (so the
+ byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,
+ where a mod b means the remainder after dividing a by b.
+
+ This calculation is done using the shift-register method of multiplying and
+ taking the remainder. The register is initialized to zero, and for each
+ incoming bit, x^32 is added mod p to the register if the bit is a one (where
+ x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by
+ x (which is shifting right by one and adding x^32 mod p if the bit shifted
+ out is a one). We start with the highest power (least significant bit) of
+ q and repeat for all eight bits of q.
+
+ The first table is simply the CRC of all possible eight bit values. This is
+ all the information needed to generate CRCs on data a byte at a time for all
+ combinations of CRC register values and incoming bytes. The remaining tables
+ allow for word-at-a-time CRC calculation for both big-endian and little-
+ endian machines, where a word is four bytes.
+*/
+local void make_crc_table()
+{
+ unsigned long c;
+ int n, k;
+ unsigned long poly; /* polynomial exclusive-or pattern */
+ /* terms of polynomial defining this crc (except x^32): */
+ static volatile int first = 1; /* flag to limit concurrent making */
+ static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
+
+ /* See if another task is already doing this (not thread-safe, but better
+ than nothing -- significantly reduces duration of vulnerability in
+ case the advice about DYNAMIC_CRC_TABLE is ignored) */
+ if (first) {
+ first = 0;
+
+ /* make exclusive-or pattern from polynomial (0xedb88320UL) */
+ poly = 0UL;
+ for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++)
+ poly |= 1UL << (31 - p[n]);
+
+ /* generate a crc for every 8-bit value */
+ for (n = 0; n < 256; n++) {
+ c = (unsigned long)n;
+ for (k = 0; k < 8; k++)
+ c = c & 1 ? poly ^ (c >> 1) : c >> 1;
+ crc_table[0][n] = c;
+ }
+
+#ifdef BYFOUR
+ /* generate crc for each value followed by one, two, and three zeros,
+ and then the byte reversal of those as well as the first table */
+ for (n = 0; n < 256; n++) {
+ c = crc_table[0][n];
+ crc_table[4][n] = REV(c);
+ for (k = 1; k < 4; k++) {
+ c = crc_table[0][c & 0xff] ^ (c >> 8);
+ crc_table[k][n] = c;
+ crc_table[k + 4][n] = REV(c);
+ }
+ }
+#endif /* BYFOUR */
+
+ crc_table_empty = 0;
+ }
+ else { /* not first */
+ /* wait for the other guy to finish (not efficient, but rare) */
+ while (crc_table_empty)
+ ;
+ }
+
+#ifdef MAKECRCH
+ /* write out CRC tables to crc32.h */
+ {
+ FILE *out;
+
+ out = fopen("crc32.h", "w");
+ if (out == NULL) return;
+ fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n");
+ fprintf(out, " * Generated automatically by crc32.c\n */\n\n");
+ fprintf(out, "local const unsigned long FAR ");
+ fprintf(out, "crc_table[TBLS][256] =\n{\n {\n");
+ write_table(out, crc_table[0]);
+# ifdef BYFOUR
+ fprintf(out, "#ifdef BYFOUR\n");
+ for (k = 1; k < 8; k++) {
+ fprintf(out, " },\n {\n");
+ write_table(out, crc_table[k]);
+ }
+ fprintf(out, "#endif\n");
+# endif /* BYFOUR */
+ fprintf(out, " }\n};\n");
+ fclose(out);
+ }
+#endif /* MAKECRCH */
+}
+
+#ifdef MAKECRCH
+local void write_table(out, table)
+ FILE *out;
+ const unsigned long FAR *table;
+{
+ int n;
+
+ for (n = 0; n < 256; n++)
+ fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", table[n],
+ n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", "));
+}
+#endif /* MAKECRCH */
+
+#else /* !DYNAMIC_CRC_TABLE */
+/* ========================================================================
+ * Tables of CRC-32s of all single-byte values, made by make_crc_table().
+ */
+#include "crc32.h"
+#endif /* DYNAMIC_CRC_TABLE */
+
+/* =========================================================================
+ * This function can be used by asm versions of crc32()
+ */
+const unsigned long FAR * ZEXPORT get_crc_table()
+{
+#ifdef DYNAMIC_CRC_TABLE
+ if (crc_table_empty)
+ make_crc_table();
+#endif /* DYNAMIC_CRC_TABLE */
+ return (const unsigned long FAR *)crc_table;
+}
+
+/* ========================================================================= */
+#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8)
+#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1
+
+/* ========================================================================= */
+unsigned long ZEXPORT crc32(crc, buf, len)
+ unsigned long crc;
+ const unsigned char FAR *buf;
+ unsigned len;
+{
+ if (buf == Z_NULL) return 0UL;
+
+#ifdef DYNAMIC_CRC_TABLE
+ if (crc_table_empty)
+ make_crc_table();
+#endif /* DYNAMIC_CRC_TABLE */
+
+#ifdef BYFOUR
+ if (sizeof(void *) == sizeof(ptrdiff_t)) {
+ u4 endian;
+
+ endian = 1;
+ if (*((unsigned char *)(&endian)))
+ return crc32_little(crc, buf, len);
+ else
+ return crc32_big(crc, buf, len);
+ }
+#endif /* BYFOUR */
+ crc = crc ^ 0xffffffffUL;
+ while (len >= 8) {
+ DO8;
+ len -= 8;
+ }
+ if (len) do {
+ DO1;
+ } while (--len);
+ return crc ^ 0xffffffffUL;
+}
+
+#ifdef BYFOUR
+
+/* ========================================================================= */
+#define DOLIT4 c ^= *buf4++; \
+ c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \
+ crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24]
+#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4
+
+/* ========================================================================= */
+local unsigned long crc32_little(crc, buf, len)
+ unsigned long crc;
+ const unsigned char FAR *buf;
+ unsigned len;
+{
+ register u4 c;
+ register const u4 FAR *buf4;
+
+ c = (u4)crc;
+ c = ~c;
+ while (len && ((ptrdiff_t)buf & 3)) {
+ c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
+ len--;
+ }
+
+ buf4 = (const u4 FAR *)(const void FAR *)buf;
+ while (len >= 32) {
+ DOLIT32;
+ len -= 32;
+ }
+ while (len >= 4) {
+ DOLIT4;
+ len -= 4;
+ }
+ buf = (const unsigned char FAR *)buf4;
+
+ if (len) do {
+ c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
+ } while (--len);
+ c = ~c;
+ return (unsigned long)c;
+}
+
+/* ========================================================================= */
+#define DOBIG4 c ^= *++buf4; \
+ c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \
+ crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24]
+#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4
+
+/* ========================================================================= */
+local unsigned long crc32_big(crc, buf, len)
+ unsigned long crc;
+ const unsigned char FAR *buf;
+ unsigned len;
+{
+ register u4 c;
+ register const u4 FAR *buf4;
+
+ c = REV((u4)crc);
+ c = ~c;
+ while (len && ((ptrdiff_t)buf & 3)) {
+ c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
+ len--;
+ }
+
+ buf4 = (const u4 FAR *)(const void FAR *)buf;
+ buf4--;
+ while (len >= 32) {
+ DOBIG32;
+ len -= 32;
+ }
+ while (len >= 4) {
+ DOBIG4;
+ len -= 4;
+ }
+ buf4++;
+ buf = (const unsigned char FAR *)buf4;
+
+ if (len) do {
+ c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
+ } while (--len);
+ c = ~c;
+ return (unsigned long)(REV(c));
+}
+
+#endif /* BYFOUR */
+
+#define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */
+
+/* ========================================================================= */
+local unsigned long gf2_matrix_times(mat, vec)
+ unsigned long *mat;
+ unsigned long vec;
+{
+ unsigned long sum;
+
+ sum = 0;
+ while (vec) {
+ if (vec & 1)
+ sum ^= *mat;
+ vec >>= 1;
+ mat++;
+ }
+ return sum;
+}
+
+/* ========================================================================= */
+local void gf2_matrix_square(square, mat)
+ unsigned long *square;
+ unsigned long *mat;
+{
+ int n;
+
+ for (n = 0; n < GF2_DIM; n++)
+ square[n] = gf2_matrix_times(mat, mat[n]);
+}
+
+/* ========================================================================= */
+uLong ZEXPORT crc32_combine(crc1, crc2, len2)
+ uLong crc1;
+ uLong crc2;
+ z_off_t len2;
+{
+ int n;
+ unsigned long row;
+ unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */
+ unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */
+
+ /* degenerate case */
+ if (len2 == 0)
+ return crc1;
+
+ /* put operator for one zero bit in odd */
+ odd[0] = 0xedb88320L; /* CRC-32 polynomial */
+ row = 1;
+ for (n = 1; n < GF2_DIM; n++) {
+ odd[n] = row;
+ row <<= 1;
+ }
+
+ /* put operator for two zero bits in even */
+ gf2_matrix_square(even, odd);
+
+ /* put operator for four zero bits in odd */
+ gf2_matrix_square(odd, even);
+
+ /* apply len2 zeros to crc1 (first square will put the operator for one
+ zero byte, eight zero bits, in even) */
+ do {
+ /* apply zeros operator for this bit of len2 */
+ gf2_matrix_square(even, odd);
+ if (len2 & 1)
+ crc1 = gf2_matrix_times(even, crc1);
+ len2 >>= 1;
+
+ /* if no more bits set, then done */
+ if (len2 == 0)
+ break;
+
+ /* another iteration of the loop with odd and even swapped */
+ gf2_matrix_square(odd, even);
+ if (len2 & 1)
+ crc1 = gf2_matrix_times(odd, crc1);
+ len2 >>= 1;
+
+ /* if no more bits set, then done */
+ } while (len2 != 0);
+
+ /* return combined crc */
+ crc1 ^= crc2;
+ return crc1;
+}
diff --git a/lib/libz/crc32.h b/lib/libz/crc32.h
new file mode 100644
index 0000000..8053b61
--- /dev/null
+++ b/lib/libz/crc32.h
@@ -0,0 +1,441 @@
+/* crc32.h -- tables for rapid CRC calculation
+ * Generated automatically by crc32.c
+ */
+
+local const unsigned long FAR crc_table[TBLS][256] =
+{
+ {
+ 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL,
+ 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL,
+ 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL,
+ 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL,
+ 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL,
+ 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL,
+ 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL,
+ 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL,
+ 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL,
+ 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL,
+ 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL,
+ 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL,
+ 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL,
+ 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL,
+ 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL,
+ 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL,
+ 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL,
+ 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL,
+ 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL,
+ 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL,
+ 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL,
+ 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL,
+ 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL,
+ 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL,
+ 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL,
+ 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL,
+ 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL,
+ 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL,
+ 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL,
+ 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL,
+ 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL,
+ 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL,
+ 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL,
+ 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL,
+ 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL,
+ 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL,
+ 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL,
+ 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL,
+ 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL,
+ 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL,
+ 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL,
+ 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL,
+ 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL,
+ 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL,
+ 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL,
+ 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL,
+ 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL,
+ 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL,
+ 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL,
+ 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL,
+ 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL,
+ 0x2d02ef8dUL
+#ifdef BYFOUR
+ },
+ {
+ 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL,
+ 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL,
+ 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL,
+ 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL,
+ 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL,
+ 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL,
+ 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL,
+ 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL,
+ 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL,
+ 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL,
+ 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL,
+ 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL,
+ 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL,
+ 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL,
+ 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL,
+ 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL,
+ 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL,
+ 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL,
+ 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL,
+ 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL,
+ 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL,
+ 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL,
+ 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL,
+ 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL,
+ 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL,
+ 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL,
+ 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL,
+ 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL,
+ 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL,
+ 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL,
+ 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL,
+ 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL,
+ 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL,
+ 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL,
+ 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL,
+ 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL,
+ 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL,
+ 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL,
+ 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL,
+ 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL,
+ 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL,
+ 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL,
+ 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL,
+ 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL,
+ 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL,
+ 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL,
+ 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL,
+ 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL,
+ 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL,
+ 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL,
+ 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL,
+ 0x9324fd72UL
+ },
+ {
+ 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL,
+ 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL,
+ 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL,
+ 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL,
+ 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL,
+ 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL,
+ 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL,
+ 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL,
+ 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL,
+ 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL,
+ 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL,
+ 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL,
+ 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL,
+ 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL,
+ 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL,
+ 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL,
+ 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL,
+ 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL,
+ 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL,
+ 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL,
+ 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL,
+ 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL,
+ 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL,
+ 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL,
+ 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL,
+ 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL,
+ 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL,
+ 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL,
+ 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL,
+ 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL,
+ 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL,
+ 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL,
+ 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL,
+ 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL,
+ 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL,
+ 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL,
+ 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL,
+ 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL,
+ 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL,
+ 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL,
+ 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL,
+ 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL,
+ 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL,
+ 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL,
+ 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL,
+ 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL,
+ 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL,
+ 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL,
+ 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL,
+ 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL,
+ 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL,
+ 0xbe9834edUL
+ },
+ {
+ 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL,
+ 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL,
+ 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL,
+ 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL,
+ 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL,
+ 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL,
+ 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL,
+ 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL,
+ 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL,
+ 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL,
+ 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL,
+ 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL,
+ 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL,
+ 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL,
+ 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL,
+ 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL,
+ 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL,
+ 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL,
+ 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL,
+ 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL,
+ 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL,
+ 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL,
+ 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL,
+ 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL,
+ 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL,
+ 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL,
+ 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL,
+ 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL,
+ 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL,
+ 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL,
+ 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL,
+ 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL,
+ 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL,
+ 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL,
+ 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL,
+ 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL,
+ 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL,
+ 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL,
+ 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL,
+ 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL,
+ 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL,
+ 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL,
+ 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL,
+ 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL,
+ 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL,
+ 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL,
+ 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL,
+ 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL,
+ 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL,
+ 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL,
+ 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL,
+ 0xde0506f1UL
+ },
+ {
+ 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL,
+ 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL,
+ 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL,
+ 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL,
+ 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL,
+ 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL,
+ 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL,
+ 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL,
+ 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL,
+ 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL,
+ 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL,
+ 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL,
+ 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL,
+ 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL,
+ 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL,
+ 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL,
+ 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL,
+ 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL,
+ 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL,
+ 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL,
+ 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL,
+ 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL,
+ 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL,
+ 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL,
+ 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL,
+ 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL,
+ 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL,
+ 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL,
+ 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL,
+ 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL,
+ 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL,
+ 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL,
+ 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL,
+ 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL,
+ 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL,
+ 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL,
+ 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL,
+ 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL,
+ 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL,
+ 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL,
+ 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL,
+ 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL,
+ 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL,
+ 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL,
+ 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL,
+ 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL,
+ 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL,
+ 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL,
+ 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL,
+ 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL,
+ 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL,
+ 0x8def022dUL
+ },
+ {
+ 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL,
+ 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL,
+ 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL,
+ 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL,
+ 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL,
+ 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL,
+ 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL,
+ 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL,
+ 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL,
+ 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL,
+ 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL,
+ 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL,
+ 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL,
+ 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL,
+ 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL,
+ 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL,
+ 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL,
+ 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL,
+ 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL,
+ 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL,
+ 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL,
+ 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL,
+ 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL,
+ 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL,
+ 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL,
+ 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL,
+ 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL,
+ 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL,
+ 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL,
+ 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL,
+ 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL,
+ 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL,
+ 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL,
+ 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL,
+ 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL,
+ 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL,
+ 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL,
+ 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL,
+ 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL,
+ 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL,
+ 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL,
+ 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL,
+ 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL,
+ 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL,
+ 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL,
+ 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL,
+ 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL,
+ 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL,
+ 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL,
+ 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL,
+ 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL,
+ 0x72fd2493UL
+ },
+ {
+ 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL,
+ 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL,
+ 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL,
+ 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL,
+ 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL,
+ 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL,
+ 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL,
+ 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL,
+ 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL,
+ 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL,
+ 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL,
+ 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL,
+ 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL,
+ 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL,
+ 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL,
+ 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL,
+ 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL,
+ 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL,
+ 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL,
+ 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL,
+ 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL,
+ 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL,
+ 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL,
+ 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL,
+ 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL,
+ 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL,
+ 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL,
+ 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL,
+ 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL,
+ 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL,
+ 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL,
+ 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL,
+ 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL,
+ 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL,
+ 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL,
+ 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL,
+ 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL,
+ 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL,
+ 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL,
+ 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL,
+ 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL,
+ 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL,
+ 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL,
+ 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL,
+ 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL,
+ 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL,
+ 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL,
+ 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL,
+ 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL,
+ 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL,
+ 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL,
+ 0xed3498beUL
+ },
+ {
+ 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL,
+ 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL,
+ 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL,
+ 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL,
+ 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL,
+ 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL,
+ 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL,
+ 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL,
+ 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL,
+ 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL,
+ 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL,
+ 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL,
+ 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL,
+ 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL,
+ 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL,
+ 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL,
+ 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL,
+ 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL,
+ 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL,
+ 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL,
+ 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL,
+ 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL,
+ 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL,
+ 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL,
+ 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL,
+ 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL,
+ 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL,
+ 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL,
+ 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL,
+ 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL,
+ 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL,
+ 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL,
+ 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL,
+ 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL,
+ 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL,
+ 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL,
+ 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL,
+ 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL,
+ 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL,
+ 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL,
+ 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL,
+ 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL,
+ 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL,
+ 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL,
+ 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL,
+ 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL,
+ 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL,
+ 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL,
+ 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL,
+ 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL,
+ 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL,
+ 0xf10605deUL
+#endif
+ }
+};
diff --git a/lib/libz/deflate.c b/lib/libz/deflate.c
new file mode 100644
index 0000000..29ce1f6
--- /dev/null
+++ b/lib/libz/deflate.c
@@ -0,0 +1,1736 @@
+/* deflate.c -- compress data using the deflation algorithm
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * ALGORITHM
+ *
+ * The "deflation" process depends on being able to identify portions
+ * of the input text which are identical to earlier input (within a
+ * sliding window trailing behind the input currently being processed).
+ *
+ * The most straightforward technique turns out to be the fastest for
+ * most input files: try all possible matches and select the longest.
+ * The key feature of this algorithm is that insertions into the string
+ * dictionary are very simple and thus fast, and deletions are avoided
+ * completely. Insertions are performed at each input character, whereas
+ * string matches are performed only when the previous match ends. So it
+ * is preferable to spend more time in matches to allow very fast string
+ * insertions and avoid deletions. The matching algorithm for small
+ * strings is inspired from that of Rabin & Karp. A brute force approach
+ * is used to find longer strings when a small match has been found.
+ * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
+ * (by Leonid Broukhis).
+ * A previous version of this file used a more sophisticated algorithm
+ * (by Fiala and Greene) which is guaranteed to run in linear amortized
+ * time, but has a larger average cost, uses more memory and is patented.
+ * However the F&G algorithm may be faster for some highly redundant
+ * files if the parameter max_chain_length (described below) is too large.
+ *
+ * ACKNOWLEDGEMENTS
+ *
+ * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
+ * I found it in 'freeze' written by Leonid Broukhis.
+ * Thanks to many people for bug reports and testing.
+ *
+ * REFERENCES
+ *
+ * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification".
+ * Available in http://www.ietf.org/rfc/rfc1951.txt
+ *
+ * A description of the Rabin and Karp algorithm is given in the book
+ * "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
+ *
+ * Fiala,E.R., and Greene,D.H.
+ * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
+ *
+ */
+
+/* @(#) $Id$ */
+
+#include "deflate.h"
+
+const char deflate_copyright[] =
+ " deflate 1.2.3 Copyright 1995-2005 Jean-loup Gailly ";
+/*
+ If you use the zlib library in a product, an acknowledgment is welcome
+ in the documentation of your product. If for some reason you cannot
+ include such an acknowledgment, I would appreciate that you keep this
+ copyright string in the executable of your product.
+ */
+
+/* ===========================================================================
+ * Function prototypes.
+ */
+typedef enum {
+ need_more, /* block not completed, need more input or more output */
+ block_done, /* block flush performed */
+ finish_started, /* finish started, need only more output at next deflate */
+ finish_done /* finish done, accept no more input or output */
+} block_state;
+
+typedef block_state (*compress_func) OF((deflate_state *s, int flush));
+/* Compression function. Returns the block state after the call. */
+
+local void fill_window OF((deflate_state *s));
+local block_state deflate_stored OF((deflate_state *s, int flush));
+local block_state deflate_fast OF((deflate_state *s, int flush));
+#ifndef FASTEST
+local block_state deflate_slow OF((deflate_state *s, int flush));
+#endif
+local void lm_init OF((deflate_state *s));
+local void putShortMSB OF((deflate_state *s, uInt b));
+local void flush_pending OF((z_streamp strm));
+local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size));
+#ifndef FASTEST
+#ifdef ASMV
+ void match_init OF((void)); /* asm code initialization */
+ uInt longest_match OF((deflate_state *s, IPos cur_match));
+#else
+local uInt longest_match OF((deflate_state *s, IPos cur_match));
+#endif
+#endif
+local uInt longest_match_fast OF((deflate_state *s, IPos cur_match));
+
+#ifdef DEBUG
+local void check_match OF((deflate_state *s, IPos start, IPos match,
+ int length));
+#endif
+
+/* ===========================================================================
+ * Local data
+ */
+
+#define NIL 0
+/* Tail of hash chains */
+
+#ifndef TOO_FAR
+# define TOO_FAR 4096
+#endif
+/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+/* Values for max_lazy_match, good_match and max_chain_length, depending on
+ * the desired pack level (0..9). The values given below have been tuned to
+ * exclude worst case performance for pathological files. Better values may be
+ * found for specific files.
+ */
+typedef struct config_s {
+ ush good_length; /* reduce lazy search above this match length */
+ ush max_lazy; /* do not perform lazy search above this match length */
+ ush nice_length; /* quit search above this match length */
+ ush max_chain;
+ compress_func func;
+} config;
+
+#ifdef FASTEST
+local const config configuration_table[2] = {
+/* good lazy nice chain */
+/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */
+/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */
+#else
+local const config configuration_table[10] = {
+/* good lazy nice chain */
+/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */
+/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */
+/* 2 */ {4, 5, 16, 8, deflate_fast},
+/* 3 */ {4, 6, 32, 32, deflate_fast},
+
+/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */
+/* 5 */ {8, 16, 32, 32, deflate_slow},
+/* 6 */ {8, 16, 128, 128, deflate_slow},
+/* 7 */ {8, 32, 128, 256, deflate_slow},
+/* 8 */ {32, 128, 258, 1024, deflate_slow},
+/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */
+#endif
+
+/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
+ * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
+ * meaning.
+ */
+
+#define EQUAL 0
+/* result of memcmp for equal strings */
+
+#ifndef NO_DUMMY_DECL
+struct static_tree_desc_s {int dummy;}; /* for buggy compilers */
+#endif
+
+/* ===========================================================================
+ * Update a hash value with the given input byte
+ * IN assertion: all calls to to UPDATE_HASH are made with consecutive
+ * input characters, so that a running hash key can be computed from the
+ * previous key instead of complete recalculation each time.
+ */
+#define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask)
+
+
+/* ===========================================================================
+ * Insert string str in the dictionary and set match_head to the previous head
+ * of the hash chain (the most recent string with same hash key). Return
+ * the previous length of the hash chain.
+ * If this file is compiled with -DFASTEST, the compression level is forced
+ * to 1, and no hash chains are maintained.
+ * IN assertion: all calls to to INSERT_STRING are made with consecutive
+ * input characters and the first MIN_MATCH bytes of str are valid
+ * (except for the last MIN_MATCH-1 bytes of the input file).
+ */
+#ifdef FASTEST
+#define INSERT_STRING(s, str, match_head) \
+ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+ match_head = s->head[s->ins_h], \
+ s->head[s->ins_h] = (Pos)(str))
+#else
+#define INSERT_STRING(s, str, match_head) \
+ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+ match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \
+ s->head[s->ins_h] = (Pos)(str))
+#endif
+
+/* ===========================================================================
+ * Initialize the hash table (avoiding 64K overflow for 16 bit systems).
+ * prev[] will be initialized on the fly.
+ */
+#define CLEAR_HASH(s) \
+ s->head[s->hash_size-1] = NIL; \
+ zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head));
+
+/* ========================================================================= */
+int ZEXPORT deflateInit_(strm, level, version, stream_size)
+ z_streamp strm;
+ int level;
+ const char *version;
+ int stream_size;
+{
+ return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,
+ Z_DEFAULT_STRATEGY, version, stream_size);
+ /* To do: ignore strm->next_in if we use it as window */
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
+ version, stream_size)
+ z_streamp strm;
+ int level;
+ int method;
+ int windowBits;
+ int memLevel;
+ int strategy;
+ const char *version;
+ int stream_size;
+{
+ deflate_state *s;
+ int wrap = 1;
+ static const char my_version[] = ZLIB_VERSION;
+
+ ushf *overlay;
+ /* We overlay pending_buf and d_buf+l_buf. This works since the average
+ * output size for (length,distance) codes is <= 24 bits.
+ */
+
+ if (version == Z_NULL || version[0] != my_version[0] ||
+ stream_size != sizeof(z_stream)) {
+ return Z_VERSION_ERROR;
+ }
+ if (strm == Z_NULL) return Z_STREAM_ERROR;
+
+ strm->msg = Z_NULL;
+ if (strm->zalloc == (alloc_func)0) {
+ strm->zalloc = zcalloc;
+ strm->opaque = (voidpf)0;
+ }
+ if (strm->zfree == (free_func)0) strm->zfree = zcfree;
+
+#ifdef FASTEST
+ if (level != 0) level = 1;
+#else
+ if (level == Z_DEFAULT_COMPRESSION) level = 6;
+#endif
+
+ if (windowBits < 0) { /* suppress zlib wrapper */
+ wrap = 0;
+ windowBits = -windowBits;
+ }
+#ifdef GZIP
+ else if (windowBits > 15) {
+ wrap = 2; /* write gzip wrapper instead */
+ windowBits -= 16;
+ }
+#endif
+ if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED ||
+ windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||
+ strategy < 0 || strategy > Z_FIXED) {
+ return Z_STREAM_ERROR;
+ }
+ if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */
+ s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state));
+ if (s == Z_NULL) return Z_MEM_ERROR;
+ strm->state = (struct internal_state FAR *)s;
+ s->strm = strm;
+
+ s->wrap = wrap;
+ s->gzhead = Z_NULL;
+ s->w_bits = windowBits;
+ s->w_size = 1 << s->w_bits;
+ s->w_mask = s->w_size - 1;
+
+ s->hash_bits = memLevel + 7;
+ s->hash_size = 1 << s->hash_bits;
+ s->hash_mask = s->hash_size - 1;
+ s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH);
+
+ s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));
+ s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos));
+ s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos));
+
+ s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
+
+ overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);
+ s->pending_buf = (uchf *) overlay;
+ s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L);
+
+ if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL ||
+ s->pending_buf == Z_NULL) {
+ s->status = FINISH_STATE;
+ strm->msg = (char*)ERR_MSG(Z_MEM_ERROR);
+ deflateEnd (strm);
+ return Z_MEM_ERROR;
+ }
+ s->d_buf = overlay + s->lit_bufsize/sizeof(ush);
+ s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;
+
+ s->level = level;
+ s->strategy = strategy;
+ s->method = (Byte)method;
+
+ return deflateReset(strm);
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength)
+ z_streamp strm;
+ const Bytef *dictionary;
+ uInt dictLength;
+{
+ deflate_state *s;
+ uInt length = dictLength;
+ uInt n;
+ IPos hash_head = 0;
+
+ if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL ||
+ strm->state->wrap == 2 ||
+ (strm->state->wrap == 1 && strm->state->status != INIT_STATE))
+ return Z_STREAM_ERROR;
+
+ s = strm->state;
+ if (s->wrap)
+ strm->adler = adler32(strm->adler, dictionary, dictLength);
+
+ if (length < MIN_MATCH) return Z_OK;
+ if (length > MAX_DIST(s)) {
+ length = MAX_DIST(s);
+ dictionary += dictLength - length; /* use the tail of the dictionary */
+ }
+ zmemcpy(s->window, dictionary, length);
+ s->strstart = length;
+ s->block_start = (long)length;
+
+ /* Insert all strings in the hash table (except for the last two bytes).
+ * s->lookahead stays null, so s->ins_h will be recomputed at the next
+ * call of fill_window.
+ */
+ s->ins_h = s->window[0];
+ UPDATE_HASH(s, s->ins_h, s->window[1]);
+ for (n = 0; n <= length - MIN_MATCH; n++) {
+ INSERT_STRING(s, n, hash_head);
+ }
+ if (hash_head) hash_head = 0; /* to make compiler happy */
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateReset (strm)
+ z_streamp strm;
+{
+ deflate_state *s;
+
+ if (strm == Z_NULL || strm->state == Z_NULL ||
+ strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) {
+ return Z_STREAM_ERROR;
+ }
+
+ strm->total_in = strm->total_out = 0;
+ strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */
+ strm->data_type = Z_UNKNOWN;
+
+ s = (deflate_state *)strm->state;
+ s->pending = 0;
+ s->pending_out = s->pending_buf;
+
+ if (s->wrap < 0) {
+ s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */
+ }
+ s->status = s->wrap ? INIT_STATE : BUSY_STATE;
+ strm->adler =
+#ifdef GZIP
+ s->wrap == 2 ? crc32(0L, Z_NULL, 0) :
+#endif
+ adler32(0L, Z_NULL, 0);
+ s->last_flush = Z_NO_FLUSH;
+
+ _tr_init(s);
+ lm_init(s);
+
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateSetHeader (strm, head)
+ z_streamp strm;
+ gz_headerp head;
+{
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ if (strm->state->wrap != 2) return Z_STREAM_ERROR;
+ strm->state->gzhead = head;
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflatePrime (strm, bits, value)
+ z_streamp strm;
+ int bits;
+ int value;
+{
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ strm->state->bi_valid = bits;
+ strm->state->bi_buf = (ush)(value & ((1 << bits) - 1));
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateParams(strm, level, strategy)
+ z_streamp strm;
+ int level;
+ int strategy;
+{
+ deflate_state *s;
+ compress_func func;
+ int err = Z_OK;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ s = strm->state;
+
+#ifdef FASTEST
+ if (level != 0) level = 1;
+#else
+ if (level == Z_DEFAULT_COMPRESSION) level = 6;
+#endif
+ if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) {
+ return Z_STREAM_ERROR;
+ }
+ func = configuration_table[s->level].func;
+
+ if (func != configuration_table[level].func && strm->total_in != 0) {
+ /* Flush the last buffer: */
+ err = deflate(strm, Z_PARTIAL_FLUSH);
+ }
+ if (s->level != level) {
+ s->level = level;
+ s->max_lazy_match = configuration_table[level].max_lazy;
+ s->good_match = configuration_table[level].good_length;
+ s->nice_match = configuration_table[level].nice_length;
+ s->max_chain_length = configuration_table[level].max_chain;
+ }
+ s->strategy = strategy;
+ return err;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain)
+ z_streamp strm;
+ int good_length;
+ int max_lazy;
+ int nice_length;
+ int max_chain;
+{
+ deflate_state *s;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ s = strm->state;
+ s->good_match = good_length;
+ s->max_lazy_match = max_lazy;
+ s->nice_match = nice_length;
+ s->max_chain_length = max_chain;
+ return Z_OK;
+}
+
+/* =========================================================================
+ * For the default windowBits of 15 and memLevel of 8, this function returns
+ * a close to exact, as well as small, upper bound on the compressed size.
+ * They are coded as constants here for a reason--if the #define's are
+ * changed, then this function needs to be changed as well. The return
+ * value for 15 and 8 only works for those exact settings.
+ *
+ * For any setting other than those defaults for windowBits and memLevel,
+ * the value returned is a conservative worst case for the maximum expansion
+ * resulting from using fixed blocks instead of stored blocks, which deflate
+ * can emit on compressed data for some combinations of the parameters.
+ *
+ * This function could be more sophisticated to provide closer upper bounds
+ * for every combination of windowBits and memLevel, as well as wrap.
+ * But even the conservative upper bound of about 14% expansion does not
+ * seem onerous for output buffer allocation.
+ */
+uLong ZEXPORT deflateBound(strm, sourceLen)
+ z_streamp strm;
+ uLong sourceLen;
+{
+ deflate_state *s;
+ uLong destLen;
+
+ /* conservative upper bound */
+ destLen = sourceLen +
+ ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 11;
+
+ /* if can't get parameters, return conservative bound */
+ if (strm == Z_NULL || strm->state == Z_NULL)
+ return destLen;
+
+ /* if not default parameters, return conservative bound */
+ s = strm->state;
+ if (s->w_bits != 15 || s->hash_bits != 8 + 7)
+ return destLen;
+
+ /* default settings: return tight bound for that case */
+ return compressBound(sourceLen);
+}
+
+/* =========================================================================
+ * Put a short in the pending buffer. The 16-bit value is put in MSB order.
+ * IN assertion: the stream state is correct and there is enough room in
+ * pending_buf.
+ */
+local void putShortMSB (s, b)
+ deflate_state *s;
+ uInt b;
+{
+ put_byte(s, (Byte)(b >> 8));
+ put_byte(s, (Byte)(b & 0xff));
+}
+
+/* =========================================================================
+ * Flush as much pending output as possible. All deflate() output goes
+ * through this function so some applications may wish to modify it
+ * to avoid allocating a large strm->next_out buffer and copying into it.
+ * (See also read_buf()).
+ */
+local void flush_pending(strm)
+ z_streamp strm;
+{
+ unsigned len = strm->state->pending;
+
+ if (len > strm->avail_out) len = strm->avail_out;
+ if (len == 0) return;
+
+ zmemcpy(strm->next_out, strm->state->pending_out, len);
+ strm->next_out += len;
+ strm->state->pending_out += len;
+ strm->total_out += len;
+ strm->avail_out -= len;
+ strm->state->pending -= len;
+ if (strm->state->pending == 0) {
+ strm->state->pending_out = strm->state->pending_buf;
+ }
+}
+
+/* ========================================================================= */
+int ZEXPORT deflate (strm, flush)
+ z_streamp strm;
+ int flush;
+{
+ int old_flush; /* value of flush param for previous deflate call */
+ deflate_state *s;
+
+ if (strm == Z_NULL || strm->state == Z_NULL ||
+ flush > Z_FINISH || flush < 0) {
+ return Z_STREAM_ERROR;
+ }
+ s = strm->state;
+
+ if (strm->next_out == Z_NULL ||
+ (strm->next_in == Z_NULL && strm->avail_in != 0) ||
+ (s->status == FINISH_STATE && flush != Z_FINISH)) {
+ ERR_RETURN(strm, Z_STREAM_ERROR);
+ }
+ if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR);
+
+ s->strm = strm; /* just in case */
+ old_flush = s->last_flush;
+ s->last_flush = flush;
+
+ /* Write the header */
+ if (s->status == INIT_STATE) {
+#ifdef GZIP
+ if (s->wrap == 2) {
+ strm->adler = crc32(0L, Z_NULL, 0);
+ put_byte(s, 31);
+ put_byte(s, 139);
+ put_byte(s, 8);
+ if (s->gzhead == NULL) {
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, s->level == 9 ? 2 :
+ (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?
+ 4 : 0));
+ put_byte(s, OS_CODE);
+ s->status = BUSY_STATE;
+ }
+ else {
+ put_byte(s, (s->gzhead->text ? 1 : 0) +
+ (s->gzhead->hcrc ? 2 : 0) +
+ (s->gzhead->extra == Z_NULL ? 0 : 4) +
+ (s->gzhead->name == Z_NULL ? 0 : 8) +
+ (s->gzhead->comment == Z_NULL ? 0 : 16)
+ );
+ put_byte(s, (Byte)(s->gzhead->time & 0xff));
+ put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff));
+ put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff));
+ put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff));
+ put_byte(s, s->level == 9 ? 2 :
+ (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?
+ 4 : 0));
+ put_byte(s, s->gzhead->os & 0xff);
+ if (s->gzhead->extra != NULL) {
+ put_byte(s, s->gzhead->extra_len & 0xff);
+ put_byte(s, (s->gzhead->extra_len >> 8) & 0xff);
+ }
+ if (s->gzhead->hcrc)
+ strm->adler = crc32(strm->adler, s->pending_buf,
+ s->pending);
+ s->gzindex = 0;
+ s->status = EXTRA_STATE;
+ }
+ }
+ else
+#endif
+ {
+ uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;
+ uInt level_flags;
+
+ if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2)
+ level_flags = 0;
+ else if (s->level < 6)
+ level_flags = 1;
+ else if (s->level == 6)
+ level_flags = 2;
+ else
+ level_flags = 3;
+ header |= (level_flags << 6);
+ if (s->strstart != 0) header |= PRESET_DICT;
+ header += 31 - (header % 31);
+
+ s->status = BUSY_STATE;
+ putShortMSB(s, header);
+
+ /* Save the adler32 of the preset dictionary: */
+ if (s->strstart != 0) {
+ putShortMSB(s, (uInt)(strm->adler >> 16));
+ putShortMSB(s, (uInt)(strm->adler & 0xffff));
+ }
+ strm->adler = adler32(0L, Z_NULL, 0);
+ }
+ }
+#ifdef GZIP
+ if (s->status == EXTRA_STATE) {
+ if (s->gzhead->extra != NULL) {
+ uInt beg = s->pending; /* start of bytes to update crc */
+
+ while (s->gzindex < (s->gzhead->extra_len & 0xffff)) {
+ if (s->pending == s->pending_buf_size) {
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ flush_pending(strm);
+ beg = s->pending;
+ if (s->pending == s->pending_buf_size)
+ break;
+ }
+ put_byte(s, s->gzhead->extra[s->gzindex]);
+ s->gzindex++;
+ }
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ if (s->gzindex == s->gzhead->extra_len) {
+ s->gzindex = 0;
+ s->status = NAME_STATE;
+ }
+ }
+ else
+ s->status = NAME_STATE;
+ }
+ if (s->status == NAME_STATE) {
+ if (s->gzhead->name != NULL) {
+ uInt beg = s->pending; /* start of bytes to update crc */
+ int val;
+
+ do {
+ if (s->pending == s->pending_buf_size) {
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ flush_pending(strm);
+ beg = s->pending;
+ if (s->pending == s->pending_buf_size) {
+ val = 1;
+ break;
+ }
+ }
+ val = s->gzhead->name[s->gzindex++];
+ put_byte(s, val);
+ } while (val != 0);
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ if (val == 0) {
+ s->gzindex = 0;
+ s->status = COMMENT_STATE;
+ }
+ }
+ else
+ s->status = COMMENT_STATE;
+ }
+ if (s->status == COMMENT_STATE) {
+ if (s->gzhead->comment != NULL) {
+ uInt beg = s->pending; /* start of bytes to update crc */
+ int val;
+
+ do {
+ if (s->pending == s->pending_buf_size) {
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ flush_pending(strm);
+ beg = s->pending;
+ if (s->pending == s->pending_buf_size) {
+ val = 1;
+ break;
+ }
+ }
+ val = s->gzhead->comment[s->gzindex++];
+ put_byte(s, val);
+ } while (val != 0);
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ if (val == 0)
+ s->status = HCRC_STATE;
+ }
+ else
+ s->status = HCRC_STATE;
+ }
+ if (s->status == HCRC_STATE) {
+ if (s->gzhead->hcrc) {
+ if (s->pending + 2 > s->pending_buf_size)
+ flush_pending(strm);
+ if (s->pending + 2 <= s->pending_buf_size) {
+ put_byte(s, (Byte)(strm->adler & 0xff));
+ put_byte(s, (Byte)((strm->adler >> 8) & 0xff));
+ strm->adler = crc32(0L, Z_NULL, 0);
+ s->status = BUSY_STATE;
+ }
+ }
+ else
+ s->status = BUSY_STATE;
+ }
+#endif
+
+ /* Flush as much pending output as possible */
+ if (s->pending != 0) {
+ flush_pending(strm);
+ if (strm->avail_out == 0) {
+ /* Since avail_out is 0, deflate will be called again with
+ * more output space, but possibly with both pending and
+ * avail_in equal to zero. There won't be anything to do,
+ * but this is not an error situation so make sure we
+ * return OK instead of BUF_ERROR at next call of deflate:
+ */
+ s->last_flush = -1;
+ return Z_OK;
+ }
+
+ /* Make sure there is something to do and avoid duplicate consecutive
+ * flushes. For repeated and useless calls with Z_FINISH, we keep
+ * returning Z_STREAM_END instead of Z_BUF_ERROR.
+ */
+ } else if (strm->avail_in == 0 && flush <= old_flush &&
+ flush != Z_FINISH) {
+ ERR_RETURN(strm, Z_BUF_ERROR);
+ }
+
+ /* User must not provide more input after the first FINISH: */
+ if (s->status == FINISH_STATE && strm->avail_in != 0) {
+ ERR_RETURN(strm, Z_BUF_ERROR);
+ }
+
+ /* Start a new block or continue the current one.
+ */
+ if (strm->avail_in != 0 || s->lookahead != 0 ||
+ (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {
+ block_state bstate;
+
+ bstate = (*(configuration_table[s->level].func))(s, flush);
+
+ if (bstate == finish_started || bstate == finish_done) {
+ s->status = FINISH_STATE;
+ }
+ if (bstate == need_more || bstate == finish_started) {
+ if (strm->avail_out == 0) {
+ s->last_flush = -1; /* avoid BUF_ERROR next call, see above */
+ }
+ return Z_OK;
+ /* If flush != Z_NO_FLUSH && avail_out == 0, the next call
+ * of deflate should use the same flush parameter to make sure
+ * that the flush is complete. So we don't have to output an
+ * empty block here, this will be done at next call. This also
+ * ensures that for a very small output buffer, we emit at most
+ * one empty block.
+ */
+ }
+ if (bstate == block_done) {
+ if (flush == Z_PARTIAL_FLUSH) {
+ _tr_align(s);
+ } else { /* FULL_FLUSH or SYNC_FLUSH */
+ _tr_stored_block(s, (char*)0, 0L, 0);
+ /* For a full flush, this empty block will be recognized
+ * as a special marker by inflate_sync().
+ */
+ if (flush == Z_FULL_FLUSH) {
+ CLEAR_HASH(s); /* forget history */
+ }
+ }
+ flush_pending(strm);
+ if (strm->avail_out == 0) {
+ s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */
+ return Z_OK;
+ }
+ }
+ }
+ Assert(strm->avail_out > 0, "bug2");
+
+ if (flush != Z_FINISH) return Z_OK;
+ if (s->wrap <= 0) return Z_STREAM_END;
+
+ /* Write the trailer */
+#ifdef GZIP
+ if (s->wrap == 2) {
+ put_byte(s, (Byte)(strm->adler & 0xff));
+ put_byte(s, (Byte)((strm->adler >> 8) & 0xff));
+ put_byte(s, (Byte)((strm->adler >> 16) & 0xff));
+ put_byte(s, (Byte)((strm->adler >> 24) & 0xff));
+ put_byte(s, (Byte)(strm->total_in & 0xff));
+ put_byte(s, (Byte)((strm->total_in >> 8) & 0xff));
+ put_byte(s, (Byte)((strm->total_in >> 16) & 0xff));
+ put_byte(s, (Byte)((strm->total_in >> 24) & 0xff));
+ }
+ else
+#endif
+ {
+ putShortMSB(s, (uInt)(strm->adler >> 16));
+ putShortMSB(s, (uInt)(strm->adler & 0xffff));
+ }
+ flush_pending(strm);
+ /* If avail_out is zero, the application will call deflate again
+ * to flush the rest.
+ */
+ if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */
+ return s->pending != 0 ? Z_OK : Z_STREAM_END;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateEnd (strm)
+ z_streamp strm;
+{
+ int status;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+
+ status = strm->state->status;
+ if (status != INIT_STATE &&
+ status != EXTRA_STATE &&
+ status != NAME_STATE &&
+ status != COMMENT_STATE &&
+ status != HCRC_STATE &&
+ status != BUSY_STATE &&
+ status != FINISH_STATE) {
+ return Z_STREAM_ERROR;
+ }
+
+ /* Deallocate in reverse order of allocations: */
+ TRY_FREE(strm, strm->state->pending_buf);
+ TRY_FREE(strm, strm->state->head);
+ TRY_FREE(strm, strm->state->prev);
+ TRY_FREE(strm, strm->state->window);
+
+ ZFREE(strm, strm->state);
+ strm->state = Z_NULL;
+
+ return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
+}
+
+/* =========================================================================
+ * Copy the source state to the destination state.
+ * To simplify the source, this is not supported for 16-bit MSDOS (which
+ * doesn't have enough memory anyway to duplicate compression states).
+ */
+int ZEXPORT deflateCopy (dest, source)
+ z_streamp dest;
+ z_streamp source;
+{
+#ifdef MAXSEG_64K
+ return Z_STREAM_ERROR;
+#else
+ deflate_state *ds;
+ deflate_state *ss;
+ ushf *overlay;
+
+
+ if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) {
+ return Z_STREAM_ERROR;
+ }
+
+ ss = source->state;
+
+ zmemcpy(dest, source, sizeof(z_stream));
+
+ ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state));
+ if (ds == Z_NULL) return Z_MEM_ERROR;
+ dest->state = (struct internal_state FAR *) ds;
+ zmemcpy(ds, ss, sizeof(deflate_state));
+ ds->strm = dest;
+
+ ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte));
+ ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos));
+ ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos));
+ overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2);
+ ds->pending_buf = (uchf *) overlay;
+
+ if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL ||
+ ds->pending_buf == Z_NULL) {
+ deflateEnd (dest);
+ return Z_MEM_ERROR;
+ }
+ /* following zmemcpy do not work for 16-bit MSDOS */
+ zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte));
+ zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos));
+ zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos));
+ zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size);
+
+ ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);
+ ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush);
+ ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize;
+
+ ds->l_desc.dyn_tree = ds->dyn_ltree;
+ ds->d_desc.dyn_tree = ds->dyn_dtree;
+ ds->bl_desc.dyn_tree = ds->bl_tree;
+
+ return Z_OK;
+#endif /* MAXSEG_64K */
+}
+
+/* ===========================================================================
+ * Read a new buffer from the current input stream, update the adler32
+ * and total number of bytes read. All deflate() input goes through
+ * this function so some applications may wish to modify it to avoid
+ * allocating a large strm->next_in buffer and copying from it.
+ * (See also flush_pending()).
+ */
+local int read_buf(strm, buf, size)
+ z_streamp strm;
+ Bytef *buf;
+ unsigned size;
+{
+ unsigned len = strm->avail_in;
+
+ if (len > size) len = size;
+ if (len == 0) return 0;
+
+ strm->avail_in -= len;
+
+ if (strm->state->wrap == 1) {
+ strm->adler = adler32(strm->adler, strm->next_in, len);
+ }
+#ifdef GZIP
+ else if (strm->state->wrap == 2) {
+ strm->adler = crc32(strm->adler, strm->next_in, len);
+ }
+#endif
+ zmemcpy(buf, strm->next_in, len);
+ strm->next_in += len;
+ strm->total_in += len;
+
+ return (int)len;
+}
+
+/* ===========================================================================
+ * Initialize the "longest match" routines for a new zlib stream
+ */
+local void lm_init (s)
+ deflate_state *s;
+{
+ s->window_size = (ulg)2L*s->w_size;
+
+ CLEAR_HASH(s);
+
+ /* Set the default configuration parameters:
+ */
+ s->max_lazy_match = configuration_table[s->level].max_lazy;
+ s->good_match = configuration_table[s->level].good_length;
+ s->nice_match = configuration_table[s->level].nice_length;
+ s->max_chain_length = configuration_table[s->level].max_chain;
+
+ s->strstart = 0;
+ s->block_start = 0L;
+ s->lookahead = 0;
+ s->match_length = s->prev_length = MIN_MATCH-1;
+ s->match_available = 0;
+ s->ins_h = 0;
+#ifndef FASTEST
+#ifdef ASMV
+ match_init(); /* initialize the asm code */
+#endif
+#endif
+}
+
+#ifndef FASTEST
+/* ===========================================================================
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ * OUT assertion: the match length is not greater than s->lookahead.
+ */
+#ifndef ASMV
+/* For 80x86 and 680x0, an optimized version will be provided in match.asm or
+ * match.S. The code will be functionally equivalent.
+ */
+local uInt longest_match(s, cur_match)
+ deflate_state *s;
+ IPos cur_match; /* current match */
+{
+ unsigned chain_length = s->max_chain_length;/* max hash chain length */
+ register Bytef *scan = s->window + s->strstart; /* current string */
+ register Bytef *match; /* matched string */
+ register int len; /* length of current match */
+ int best_len = s->prev_length; /* best match length so far */
+ int nice_match = s->nice_match; /* stop if match long enough */
+ IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
+ s->strstart - (IPos)MAX_DIST(s) : NIL;
+ /* Stop when cur_match becomes <= limit. To simplify the code,
+ * we prevent matches with the string of window index 0.
+ */
+ Posf *prev = s->prev;
+ uInt wmask = s->w_mask;
+
+#ifdef UNALIGNED_OK
+ /* Compare two bytes at a time. Note: this is not always beneficial.
+ * Try with and without -DUNALIGNED_OK to check.
+ */
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;
+ register ush scan_start = *(ushf*)scan;
+ register ush scan_end = *(ushf*)(scan+best_len-1);
+#else
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+ register Byte scan_end1 = scan[best_len-1];
+ register Byte scan_end = scan[best_len];
+#endif
+
+ /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+ * It is easy to get rid of this optimization if necessary.
+ */
+ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+ /* Do not waste too much time if we already have a good match: */
+ if (s->prev_length >= s->good_match) {
+ chain_length >>= 2;
+ }
+ /* Do not look for matches beyond the end of the input. This is necessary
+ * to make deflate deterministic.
+ */
+ if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
+
+ Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+ do {
+ Assert(cur_match < s->strstart, "no future");
+ match = s->window + cur_match;
+
+ /* Skip to next match if the match length cannot increase
+ * or if the match length is less than 2. Note that the checks below
+ * for insufficient lookahead only occur occasionally for performance
+ * reasons. Therefore uninitialized memory will be accessed, and
+ * conditional jumps will be made that depend on those values.
+ * However the length of the match is limited to the lookahead, so
+ * the output of deflate is not affected by the uninitialized values.
+ */
+#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
+ /* This code assumes sizeof(unsigned short) == 2. Do not use
+ * UNALIGNED_OK if your compiler uses a different size.
+ */
+ if (*(ushf*)(match+best_len-1) != scan_end ||
+ *(ushf*)match != scan_start) continue;
+
+ /* It is not necessary to compare scan[2] and match[2] since they are
+ * always equal when the other bytes match, given that the hash keys
+ * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
+ * strstart+3, +5, ... up to strstart+257. We check for insufficient
+ * lookahead only every 4th comparison; the 128th check will be made
+ * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
+ * necessary to put more guard bytes at the end of the window, or
+ * to check more often for insufficient lookahead.
+ */
+ Assert(scan[2] == match[2], "scan[2]?");
+ scan++, match++;
+ do {
+ } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ scan < strend);
+ /* The funny "do {}" generates better code on most compilers */
+
+ /* Here, scan <= window+strstart+257 */
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+ if (*scan == *match) scan++;
+
+ len = (MAX_MATCH - 1) - (int)(strend-scan);
+ scan = strend - (MAX_MATCH-1);
+
+#else /* UNALIGNED_OK */
+
+ if (match[best_len] != scan_end ||
+ match[best_len-1] != scan_end1 ||
+ *match != *scan ||
+ *++match != scan[1]) continue;
+
+ /* The check at best_len-1 can be removed because it will be made
+ * again later. (This heuristic is not always a win.)
+ * It is not necessary to compare scan[2] and match[2] since they
+ * are always equal when the other bytes match, given that
+ * the hash keys are equal and that HASH_BITS >= 8.
+ */
+ scan += 2, match++;
+ Assert(*scan == *match, "match[2]?");
+
+ /* We check for insufficient lookahead only every 8th comparison;
+ * the 256th check will be made at strstart+258.
+ */
+ do {
+ } while (*++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ scan < strend);
+
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+ len = MAX_MATCH - (int)(strend - scan);
+ scan = strend - MAX_MATCH;
+
+#endif /* UNALIGNED_OK */
+
+ if (len > best_len) {
+ s->match_start = cur_match;
+ best_len = len;
+ if (len >= nice_match) break;
+#ifdef UNALIGNED_OK
+ scan_end = *(ushf*)(scan+best_len-1);
+#else
+ scan_end1 = scan[best_len-1];
+ scan_end = scan[best_len];
+#endif
+ }
+ } while ((cur_match = prev[cur_match & wmask]) > limit
+ && --chain_length != 0);
+
+ if ((uInt)best_len <= s->lookahead) return (uInt)best_len;
+ return s->lookahead;
+}
+#endif /* ASMV */
+#endif /* FASTEST */
+
+/* ---------------------------------------------------------------------------
+ * Optimized version for level == 1 or strategy == Z_RLE only
+ */
+local uInt longest_match_fast(s, cur_match)
+ deflate_state *s;
+ IPos cur_match; /* current match */
+{
+ register Bytef *scan = s->window + s->strstart; /* current string */
+ register Bytef *match; /* matched string */
+ register int len; /* length of current match */
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+
+ /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+ * It is easy to get rid of this optimization if necessary.
+ */
+ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+ Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+ Assert(cur_match < s->strstart, "no future");
+
+ match = s->window + cur_match;
+
+ /* Return failure if the match length is less than 2:
+ */
+ if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1;
+
+ /* The check at best_len-1 can be removed because it will be made
+ * again later. (This heuristic is not always a win.)
+ * It is not necessary to compare scan[2] and match[2] since they
+ * are always equal when the other bytes match, given that
+ * the hash keys are equal and that HASH_BITS >= 8.
+ */
+ scan += 2, match += 2;
+ Assert(*scan == *match, "match[2]?");
+
+ /* We check for insufficient lookahead only every 8th comparison;
+ * the 256th check will be made at strstart+258.
+ */
+ do {
+ } while (*++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ scan < strend);
+
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+ len = MAX_MATCH - (int)(strend - scan);
+
+ if (len < MIN_MATCH) return MIN_MATCH - 1;
+
+ s->match_start = cur_match;
+ return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead;
+}
+
+#ifdef DEBUG
+/* ===========================================================================
+ * Check that the match at match_start is indeed a match.
+ */
+local void check_match(s, start, match, length)
+ deflate_state *s;
+ IPos start, match;
+ int length;
+{
+ /* check that the match is indeed a match */
+ if (zmemcmp(s->window + match,
+ s->window + start, length) != EQUAL) {
+ fprintf(stderr, " start %u, match %u, length %d\n",
+ start, match, length);
+ do {
+ fprintf(stderr, "%c%c", s->window[match++], s->window[start++]);
+ } while (--length != 0);
+ z_error("invalid match");
+ }
+ if (z_verbose > 1) {
+ fprintf(stderr,"\\[%d,%d]", start-match, length);
+ do { putc(s->window[start++], stderr); } while (--length != 0);
+ }
+}
+#else
+# define check_match(s, start, match, length)
+#endif /* DEBUG */
+
+/* ===========================================================================
+ * Fill the window when the lookahead becomes insufficient.
+ * Updates strstart and lookahead.
+ *
+ * IN assertion: lookahead < MIN_LOOKAHEAD
+ * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
+ * At least one byte has been read, or avail_in == 0; reads are
+ * performed for at least two bytes (required for the zip translate_eol
+ * option -- not supported here).
+ */
+local void fill_window(s)
+ deflate_state *s;
+{
+ register unsigned n, m;
+ register Posf *p;
+ unsigned more; /* Amount of free space at the end of the window. */
+ uInt wsize = s->w_size;
+
+ do {
+ more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
+
+ /* Deal with !@#$% 64K limit: */
+ if (sizeof(int) <= 2) {
+ if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
+ more = wsize;
+
+ } else if (more == (unsigned)(-1)) {
+ /* Very unlikely, but possible on 16 bit machine if
+ * strstart == 0 && lookahead == 1 (input done a byte at time)
+ */
+ more--;
+ }
+ }
+
+ /* If the window is almost full and there is insufficient lookahead,
+ * move the upper half to the lower one to make room in the upper half.
+ */
+ if (s->strstart >= wsize+MAX_DIST(s)) {
+
+ zmemcpy(s->window, s->window+wsize, (unsigned)wsize);
+ s->match_start -= wsize;
+ s->strstart -= wsize; /* we now have strstart >= MAX_DIST */
+ s->block_start -= (long) wsize;
+
+ /* Slide the hash table (could be avoided with 32 bit values
+ at the expense of memory usage). We slide even when level == 0
+ to keep the hash table consistent if we switch back to level > 0
+ later. (Using level 0 permanently is not an optimal usage of
+ zlib, so we don't care about this pathological case.)
+ */
+ /* %%% avoid this when Z_RLE */
+ n = s->hash_size;
+ p = &s->head[n];
+ do {
+ m = *--p;
+ *p = (Pos)(m >= wsize ? m-wsize : NIL);
+ } while (--n);
+
+ n = wsize;
+#ifndef FASTEST
+ p = &s->prev[n];
+ do {
+ m = *--p;
+ *p = (Pos)(m >= wsize ? m-wsize : NIL);
+ /* If n is not on any hash chain, prev[n] is garbage but
+ * its value will never be used.
+ */
+ } while (--n);
+#endif
+ more += wsize;
+ }
+ if (s->strm->avail_in == 0) return;
+
+ /* If there was no sliding:
+ * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
+ * more == window_size - lookahead - strstart
+ * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
+ * => more >= window_size - 2*WSIZE + 2
+ * In the BIG_MEM or MMAP case (not yet supported),
+ * window_size == input_size + MIN_LOOKAHEAD &&
+ * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
+ * Otherwise, window_size == 2*WSIZE so more >= 2.
+ * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
+ */
+ Assert(more >= 2, "more < 2");
+
+ n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more);
+ s->lookahead += n;
+
+ /* Initialize the hash value now that we have some input: */
+ if (s->lookahead >= MIN_MATCH) {
+ s->ins_h = s->window[s->strstart];
+ UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+ Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+ }
+ /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
+ * but this is not important since only literal bytes will be emitted.
+ */
+
+ } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0);
+}
+
+/* ===========================================================================
+ * Flush the current block, with given end-of-file flag.
+ * IN assertion: strstart is set to the end of the current match.
+ */
+#define FLUSH_BLOCK_ONLY(s, eof) { \
+ _tr_flush_block(s, (s->block_start >= 0L ? \
+ (charf *)&s->window[(unsigned)s->block_start] : \
+ (charf *)Z_NULL), \
+ (ulg)((long)s->strstart - s->block_start), \
+ (eof)); \
+ s->block_start = s->strstart; \
+ flush_pending(s->strm); \
+ Tracev((stderr,"[FLUSH]")); \
+}
+
+/* Same but force premature exit if necessary. */
+#define FLUSH_BLOCK(s, eof) { \
+ FLUSH_BLOCK_ONLY(s, eof); \
+ if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \
+}
+
+/* ===========================================================================
+ * Copy without compression as much as possible from the input stream, return
+ * the current block state.
+ * This function does not insert new strings in the dictionary since
+ * uncompressible data is probably not useful. This function is used
+ * only for the level=0 compression option.
+ * NOTE: this function should be optimized to avoid extra copying from
+ * window to pending_buf.
+ */
+local block_state deflate_stored(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ /* Stored blocks are limited to 0xffff bytes, pending_buf is limited
+ * to pending_buf_size, and each stored block has a 5 byte header:
+ */
+ ulg max_block_size = 0xffff;
+ ulg max_start;
+
+ if (max_block_size > s->pending_buf_size - 5) {
+ max_block_size = s->pending_buf_size - 5;
+ }
+
+ /* Copy as much as possible from input to output: */
+ for (;;) {
+ /* Fill the window as much as possible: */
+ if (s->lookahead <= 1) {
+
+ Assert(s->strstart < s->w_size+MAX_DIST(s) ||
+ s->block_start >= (long)s->w_size, "slide too late");
+
+ fill_window(s);
+ if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more;
+
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+ Assert(s->block_start >= 0L, "block gone");
+
+ s->strstart += s->lookahead;
+ s->lookahead = 0;
+
+ /* Emit a stored block if pending_buf will be full: */
+ max_start = s->block_start + max_block_size;
+ if (s->strstart == 0 || (ulg)s->strstart >= max_start) {
+ /* strstart == 0 is possible when wraparound on 16-bit machine */
+ s->lookahead = (uInt)(s->strstart - max_start);
+ s->strstart = (uInt)max_start;
+ FLUSH_BLOCK(s, 0);
+ }
+ /* Flush if we may have to slide, otherwise block_start may become
+ * negative and the data will be gone:
+ */
+ if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) {
+ FLUSH_BLOCK(s, 0);
+ }
+ }
+ FLUSH_BLOCK(s, flush == Z_FINISH);
+ return flush == Z_FINISH ? finish_done : block_done;
+}
+
+/* ===========================================================================
+ * Compress as much as possible from the input stream, return the current
+ * block state.
+ * This function does not perform lazy evaluation of matches and inserts
+ * new strings in the dictionary only for unmatched strings or for short
+ * matches. It is used only for the fast compression options.
+ */
+local block_state deflate_fast(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ IPos hash_head = NIL; /* head of the hash chain */
+ int bflush; /* set if current block must be flushed */
+
+ for (;;) {
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the next match, plus MIN_MATCH bytes to insert the
+ * string following the next match.
+ */
+ if (s->lookahead < MIN_LOOKAHEAD) {
+ fill_window(s);
+ if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+ return need_more;
+ }
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+
+ /* Insert the string window[strstart .. strstart+2] in the
+ * dictionary, and set hash_head to the head of the hash chain:
+ */
+ if (s->lookahead >= MIN_MATCH) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+
+ /* Find the longest match, discarding those <= prev_length.
+ * At this point we have always match_length < MIN_MATCH
+ */
+ if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) {
+ /* To simplify the code, we prevent matches with the string
+ * of window index 0 (in particular we have to avoid a match
+ * of the string with itself at the start of the input file).
+ */
+#ifdef FASTEST
+ if ((s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) ||
+ (s->strategy == Z_RLE && s->strstart - hash_head == 1)) {
+ s->match_length = longest_match_fast (s, hash_head);
+ }
+#else
+ if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) {
+ s->match_length = longest_match (s, hash_head);
+ } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) {
+ s->match_length = longest_match_fast (s, hash_head);
+ }
+#endif
+ /* longest_match() or longest_match_fast() sets match_start */
+ }
+ if (s->match_length >= MIN_MATCH) {
+ check_match(s, s->strstart, s->match_start, s->match_length);
+
+ _tr_tally_dist(s, s->strstart - s->match_start,
+ s->match_length - MIN_MATCH, bflush);
+
+ s->lookahead -= s->match_length;
+
+ /* Insert new strings in the hash table only if the match length
+ * is not too large. This saves time but degrades compression.
+ */
+#ifndef FASTEST
+ if (s->match_length <= s->max_insert_length &&
+ s->lookahead >= MIN_MATCH) {
+ s->match_length--; /* string at strstart already in table */
+ do {
+ s->strstart++;
+ INSERT_STRING(s, s->strstart, hash_head);
+ /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+ * always MIN_MATCH bytes ahead.
+ */
+ } while (--s->match_length != 0);
+ s->strstart++;
+ } else
+#endif
+ {
+ s->strstart += s->match_length;
+ s->match_length = 0;
+ s->ins_h = s->window[s->strstart];
+ UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+ Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+ /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
+ * matter since it will be recomputed at next deflate call.
+ */
+ }
+ } else {
+ /* No match, output a literal byte */
+ Tracevv((stderr,"%c", s->window[s->strstart]));
+ _tr_tally_lit (s, s->window[s->strstart], bflush);
+ s->lookahead--;
+ s->strstart++;
+ }
+ if (bflush) FLUSH_BLOCK(s, 0);
+ }
+ FLUSH_BLOCK(s, flush == Z_FINISH);
+ return flush == Z_FINISH ? finish_done : block_done;
+}
+
+#ifndef FASTEST
+/* ===========================================================================
+ * Same as above, but achieves better compression. We use a lazy
+ * evaluation for matches: a match is finally adopted only if there is
+ * no better match at the next window position.
+ */
+local block_state deflate_slow(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ IPos hash_head = NIL; /* head of hash chain */
+ int bflush; /* set if current block must be flushed */
+
+ /* Process the input block. */
+ for (;;) {
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the next match, plus MIN_MATCH bytes to insert the
+ * string following the next match.
+ */
+ if (s->lookahead < MIN_LOOKAHEAD) {
+ fill_window(s);
+ if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+ return need_more;
+ }
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+
+ /* Insert the string window[strstart .. strstart+2] in the
+ * dictionary, and set hash_head to the head of the hash chain:
+ */
+ if (s->lookahead >= MIN_MATCH) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+
+ /* Find the longest match, discarding those <= prev_length.
+ */
+ s->prev_length = s->match_length, s->prev_match = s->match_start;
+ s->match_length = MIN_MATCH-1;
+
+ if (hash_head != NIL && s->prev_length < s->max_lazy_match &&
+ s->strstart - hash_head <= MAX_DIST(s)) {
+ /* To simplify the code, we prevent matches with the string
+ * of window index 0 (in particular we have to avoid a match
+ * of the string with itself at the start of the input file).
+ */
+ if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) {
+ s->match_length = longest_match (s, hash_head);
+ } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) {
+ s->match_length = longest_match_fast (s, hash_head);
+ }
+ /* longest_match() or longest_match_fast() sets match_start */
+
+ if (s->match_length <= 5 && (s->strategy == Z_FILTERED
+#if TOO_FAR <= 32767
+ || (s->match_length == MIN_MATCH &&
+ s->strstart - s->match_start > TOO_FAR)
+#endif
+ )) {
+
+ /* If prev_match is also MIN_MATCH, match_start is garbage
+ * but we will ignore the current match anyway.
+ */
+ s->match_length = MIN_MATCH-1;
+ }
+ }
+ /* If there was a match at the previous step and the current
+ * match is not better, output the previous match:
+ */
+ if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {
+ uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
+ /* Do not insert strings in hash table beyond this. */
+
+ check_match(s, s->strstart-1, s->prev_match, s->prev_length);
+
+ _tr_tally_dist(s, s->strstart -1 - s->prev_match,
+ s->prev_length - MIN_MATCH, bflush);
+
+ /* Insert in hash table all strings up to the end of the match.
+ * strstart-1 and strstart are already inserted. If there is not
+ * enough lookahead, the last two strings are not inserted in
+ * the hash table.
+ */
+ s->lookahead -= s->prev_length-1;
+ s->prev_length -= 2;
+ do {
+ if (++s->strstart <= max_insert) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+ } while (--s->prev_length != 0);
+ s->match_available = 0;
+ s->match_length = MIN_MATCH-1;
+ s->strstart++;
+
+ if (bflush) FLUSH_BLOCK(s, 0);
+
+ } else if (s->match_available) {
+ /* If there was no match at the previous position, output a
+ * single literal. If there was a match but the current match
+ * is longer, truncate the previous match to a single literal.
+ */
+ Tracevv((stderr,"%c", s->window[s->strstart-1]));
+ _tr_tally_lit(s, s->window[s->strstart-1], bflush);
+ if (bflush) {
+ FLUSH_BLOCK_ONLY(s, 0);
+ }
+ s->strstart++;
+ s->lookahead--;
+ if (s->strm->avail_out == 0) return need_more;
+ } else {
+ /* There is no previous match to compare with, wait for
+ * the next step to decide.
+ */
+ s->match_available = 1;
+ s->strstart++;
+ s->lookahead--;
+ }
+ }
+ Assert (flush != Z_NO_FLUSH, "no flush?");
+ if (s->match_available) {
+ Tracevv((stderr,"%c", s->window[s->strstart-1]));
+ _tr_tally_lit(s, s->window[s->strstart-1], bflush);
+ s->match_available = 0;
+ }
+ FLUSH_BLOCK(s, flush == Z_FINISH);
+ return flush == Z_FINISH ? finish_done : block_done;
+}
+#endif /* FASTEST */
+
+#if 0
+/* ===========================================================================
+ * For Z_RLE, simply look for runs of bytes, generate matches only of distance
+ * one. Do not maintain a hash table. (It will be regenerated if this run of
+ * deflate switches away from Z_RLE.)
+ */
+local block_state deflate_rle(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ int bflush; /* set if current block must be flushed */
+ uInt run; /* length of run */
+ uInt max; /* maximum length of run */
+ uInt prev; /* byte at distance one to match */
+ Bytef *scan; /* scan for end of run */
+
+ for (;;) {
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the longest encodable run.
+ */
+ if (s->lookahead < MAX_MATCH) {
+ fill_window(s);
+ if (s->lookahead < MAX_MATCH && flush == Z_NO_FLUSH) {
+ return need_more;
+ }
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+
+ /* See how many times the previous byte repeats */
+ run = 0;
+ if (s->strstart > 0) { /* if there is a previous byte, that is */
+ max = s->lookahead < MAX_MATCH ? s->lookahead : MAX_MATCH;
+ scan = s->window + s->strstart - 1;
+ prev = *scan++;
+ do {
+ if (*scan++ != prev)
+ break;
+ } while (++run < max);
+ }
+
+ /* Emit match if have run of MIN_MATCH or longer, else emit literal */
+ if (run >= MIN_MATCH) {
+ check_match(s, s->strstart, s->strstart - 1, run);
+ _tr_tally_dist(s, 1, run - MIN_MATCH, bflush);
+ s->lookahead -= run;
+ s->strstart += run;
+ } else {
+ /* No match, output a literal byte */
+ Tracevv((stderr,"%c", s->window[s->strstart]));
+ _tr_tally_lit (s, s->window[s->strstart], bflush);
+ s->lookahead--;
+ s->strstart++;
+ }
+ if (bflush) FLUSH_BLOCK(s, 0);
+ }
+ FLUSH_BLOCK(s, flush == Z_FINISH);
+ return flush == Z_FINISH ? finish_done : block_done;
+}
+#endif
diff --git a/lib/libz/deflate.h b/lib/libz/deflate.h
new file mode 100644
index 0000000..05a5ab3
--- /dev/null
+++ b/lib/libz/deflate.h
@@ -0,0 +1,331 @@
+/* deflate.h -- internal compression state
+ * Copyright (C) 1995-2004 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id$ */
+
+#ifndef DEFLATE_H
+#define DEFLATE_H
+
+#include "zutil.h"
+
+/* define NO_GZIP when compiling if you want to disable gzip header and
+ trailer creation by deflate(). NO_GZIP would be used to avoid linking in
+ the crc code when it is not needed. For shared libraries, gzip encoding
+ should be left enabled. */
+#ifndef NO_GZIP
+# define GZIP
+#endif
+
+/* ===========================================================================
+ * Internal compression state.
+ */
+
+#define LENGTH_CODES 29
+/* number of length codes, not counting the special END_BLOCK code */
+
+#define LITERALS 256
+/* number of literal bytes 0..255 */
+
+#define L_CODES (LITERALS+1+LENGTH_CODES)
+/* number of Literal or Length codes, including the END_BLOCK code */
+
+#define D_CODES 30
+/* number of distance codes */
+
+#define BL_CODES 19
+/* number of codes used to transfer the bit lengths */
+
+#define HEAP_SIZE (2*L_CODES+1)
+/* maximum heap size */
+
+#define MAX_BITS 15
+/* All codes must not exceed MAX_BITS bits */
+
+#define INIT_STATE 42
+#define EXTRA_STATE 69
+#define NAME_STATE 73
+#define COMMENT_STATE 91
+#define HCRC_STATE 103
+#define BUSY_STATE 113
+#define FINISH_STATE 666
+/* Stream status */
+
+
+/* Data structure describing a single value and its code string. */
+typedef struct ct_data_s {
+ union {
+ ush freq; /* frequency count */
+ ush code; /* bit string */
+ } fc;
+ union {
+ ush dad; /* father node in Huffman tree */
+ ush len; /* length of bit string */
+ } dl;
+} FAR ct_data;
+
+#define Freq fc.freq
+#define Code fc.code
+#define Dad dl.dad
+#define Len dl.len
+
+typedef struct static_tree_desc_s static_tree_desc;
+
+typedef struct tree_desc_s {
+ ct_data *dyn_tree; /* the dynamic tree */
+ int max_code; /* largest code with non zero frequency */
+ static_tree_desc *stat_desc; /* the corresponding static tree */
+} FAR tree_desc;
+
+typedef ush Pos;
+typedef Pos FAR Posf;
+typedef unsigned IPos;
+
+/* A Pos is an index in the character window. We use short instead of int to
+ * save space in the various tables. IPos is used only for parameter passing.
+ */
+
+typedef struct internal_state {
+ z_streamp strm; /* pointer back to this zlib stream */
+ int status; /* as the name implies */
+ Bytef *pending_buf; /* output still pending */
+ ulg pending_buf_size; /* size of pending_buf */
+ Bytef *pending_out; /* next pending byte to output to the stream */
+ uInt pending; /* nb of bytes in the pending buffer */
+ int wrap; /* bit 0 true for zlib, bit 1 true for gzip */
+ gz_headerp gzhead; /* gzip header information to write */
+ uInt gzindex; /* where in extra, name, or comment */
+ Byte method; /* STORED (for zip only) or DEFLATED */
+ int last_flush; /* value of flush param for previous deflate call */
+
+ /* used by deflate.c: */
+
+ uInt w_size; /* LZ77 window size (32K by default) */
+ uInt w_bits; /* log2(w_size) (8..16) */
+ uInt w_mask; /* w_size - 1 */
+
+ Bytef *window;
+ /* Sliding window. Input bytes are read into the second half of the window,
+ * and move to the first half later to keep a dictionary of at least wSize
+ * bytes. With this organization, matches are limited to a distance of
+ * wSize-MAX_MATCH bytes, but this ensures that IO is always
+ * performed with a length multiple of the block size. Also, it limits
+ * the window size to 64K, which is quite useful on MSDOS.
+ * To do: use the user input buffer as sliding window.
+ */
+
+ ulg window_size;
+ /* Actual size of window: 2*wSize, except when the user input buffer
+ * is directly used as sliding window.
+ */
+
+ Posf *prev;
+ /* Link to older string with same hash index. To limit the size of this
+ * array to 64K, this link is maintained only for the last 32K strings.
+ * An index in this array is thus a window index modulo 32K.
+ */
+
+ Posf *head; /* Heads of the hash chains or NIL. */
+
+ uInt ins_h; /* hash index of string to be inserted */
+ uInt hash_size; /* number of elements in hash table */
+ uInt hash_bits; /* log2(hash_size) */
+ uInt hash_mask; /* hash_size-1 */
+
+ uInt hash_shift;
+ /* Number of bits by which ins_h must be shifted at each input
+ * step. It must be such that after MIN_MATCH steps, the oldest
+ * byte no longer takes part in the hash key, that is:
+ * hash_shift * MIN_MATCH >= hash_bits
+ */
+
+ long block_start;
+ /* Window position at the beginning of the current output block. Gets
+ * negative when the window is moved backwards.
+ */
+
+ uInt match_length; /* length of best match */
+ IPos prev_match; /* previous match */
+ int match_available; /* set if previous match exists */
+ uInt strstart; /* start of string to insert */
+ uInt match_start; /* start of matching string */
+ uInt lookahead; /* number of valid bytes ahead in window */
+
+ uInt prev_length;
+ /* Length of the best match at previous step. Matches not greater than this
+ * are discarded. This is used in the lazy match evaluation.
+ */
+
+ uInt max_chain_length;
+ /* To speed up deflation, hash chains are never searched beyond this
+ * length. A higher limit improves compression ratio but degrades the
+ * speed.
+ */
+
+ uInt max_lazy_match;
+ /* Attempt to find a better match only when the current match is strictly
+ * smaller than this value. This mechanism is used only for compression
+ * levels >= 4.
+ */
+# define max_insert_length max_lazy_match
+ /* Insert new strings in the hash table only if the match length is not
+ * greater than this length. This saves time but degrades compression.
+ * max_insert_length is used only for compression levels <= 3.
+ */
+
+ int level; /* compression level (1..9) */
+ int strategy; /* favor or force Huffman coding*/
+
+ uInt good_match;
+ /* Use a faster search when the previous match is longer than this */
+
+ int nice_match; /* Stop searching when current match exceeds this */
+
+ /* used by trees.c: */
+ /* Didn't use ct_data typedef below to supress compiler warning */
+ struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */
+ struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
+ struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */
+
+ struct tree_desc_s l_desc; /* desc. for literal tree */
+ struct tree_desc_s d_desc; /* desc. for distance tree */
+ struct tree_desc_s bl_desc; /* desc. for bit length tree */
+
+ ush bl_count[MAX_BITS+1];
+ /* number of codes at each bit length for an optimal tree */
+
+ int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */
+ int heap_len; /* number of elements in the heap */
+ int heap_max; /* element of largest frequency */
+ /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+ * The same heap array is used to build all trees.
+ */
+
+ uch depth[2*L_CODES+1];
+ /* Depth of each subtree used as tie breaker for trees of equal frequency
+ */
+
+ uchf *l_buf; /* buffer for literals or lengths */
+
+ uInt lit_bufsize;
+ /* Size of match buffer for literals/lengths. There are 4 reasons for
+ * limiting lit_bufsize to 64K:
+ * - frequencies can be kept in 16 bit counters
+ * - if compression is not successful for the first block, all input
+ * data is still in the window so we can still emit a stored block even
+ * when input comes from standard input. (This can also be done for
+ * all blocks if lit_bufsize is not greater than 32K.)
+ * - if compression is not successful for a file smaller than 64K, we can
+ * even emit a stored file instead of a stored block (saving 5 bytes).
+ * This is applicable only for zip (not gzip or zlib).
+ * - creating new Huffman trees less frequently may not provide fast
+ * adaptation to changes in the input data statistics. (Take for
+ * example a binary file with poorly compressible code followed by
+ * a highly compressible string table.) Smaller buffer sizes give
+ * fast adaptation but have of course the overhead of transmitting
+ * trees more frequently.
+ * - I can't count above 4
+ */
+
+ uInt last_lit; /* running index in l_buf */
+
+ ushf *d_buf;
+ /* Buffer for distances. To simplify the code, d_buf and l_buf have
+ * the same number of elements. To use different lengths, an extra flag
+ * array would be necessary.
+ */
+
+ ulg opt_len; /* bit length of current block with optimal trees */
+ ulg static_len; /* bit length of current block with static trees */
+ uInt matches; /* number of string matches in current block */
+ int last_eob_len; /* bit length of EOB code for last block */
+
+#ifdef DEBUG
+ ulg compressed_len; /* total bit length of compressed file mod 2^32 */
+ ulg bits_sent; /* bit length of compressed data sent mod 2^32 */
+#endif
+
+ ush bi_buf;
+ /* Output buffer. bits are inserted starting at the bottom (least
+ * significant bits).
+ */
+ int bi_valid;
+ /* Number of valid bits in bi_buf. All bits above the last valid bit
+ * are always zero.
+ */
+
+} FAR deflate_state;
+
+/* Output a byte on the stream.
+ * IN assertion: there is enough room in pending_buf.
+ */
+#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);}
+
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD)
+/* In order to simplify the code, particularly on 16 bit machines, match
+ * distances are limited to MAX_DIST instead of WSIZE.
+ */
+
+ /* in trees.c */
+void _tr_init OF((deflate_state *s));
+int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc));
+void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len,
+ int eof));
+void _tr_align OF((deflate_state *s));
+void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len,
+ int eof));
+
+#define d_code(dist) \
+ ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)])
+/* Mapping from a distance to a distance code. dist is the distance - 1 and
+ * must not have side effects. _dist_code[256] and _dist_code[257] are never
+ * used.
+ */
+
+#ifndef DEBUG
+/* Inline versions of _tr_tally for speed: */
+
+#if defined(GEN_TREES_H) || !defined(STDC)
+ extern uch _length_code[];
+ extern uch _dist_code[];
+#else
+ extern const uch _length_code[];
+ extern const uch _dist_code[];
+#endif
+
+# define _tr_tally_lit(s, c, flush) \
+ { uch cc = (c); \
+ s->d_buf[s->last_lit] = 0; \
+ s->l_buf[s->last_lit++] = cc; \
+ s->dyn_ltree[cc].Freq++; \
+ flush = (s->last_lit == s->lit_bufsize-1); \
+ }
+# define _tr_tally_dist(s, distance, length, flush) \
+ { uch len = (length); \
+ ush dist = (distance); \
+ s->d_buf[s->last_lit] = dist; \
+ s->l_buf[s->last_lit++] = len; \
+ dist--; \
+ s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \
+ s->dyn_dtree[d_code(dist)].Freq++; \
+ flush = (s->last_lit == s->lit_bufsize-1); \
+ }
+#else
+# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c)
+# define _tr_tally_dist(s, distance, length, flush) \
+ flush = _tr_tally(s, distance, length)
+#endif
+
+#endif /* DEFLATE_H */
diff --git a/lib/libz/example.c b/lib/libz/example.c
new file mode 100644
index 0000000..6c8a0ee
--- /dev/null
+++ b/lib/libz/example.c
@@ -0,0 +1,565 @@
+/* example.c -- usage example of the zlib compression library
+ * Copyright (C) 1995-2004 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#include <stdio.h>
+#include "zlib.h"
+
+#ifdef STDC
+# include <string.h>
+# include <stdlib.h>
+#endif
+
+#if defined(VMS) || defined(RISCOS)
+# define TESTFILE "foo-gz"
+#else
+# define TESTFILE "foo.gz"
+#endif
+
+#define CHECK_ERR(err, msg) { \
+ if (err != Z_OK) { \
+ fprintf(stderr, "%s error: %d\n", msg, err); \
+ exit(1); \
+ } \
+}
+
+const char hello[] = "hello, hello!";
+/* "hello world" would be more standard, but the repeated "hello"
+ * stresses the compression code better, sorry...
+ */
+
+const char dictionary[] = "hello";
+uLong dictId; /* Adler32 value of the dictionary */
+
+void test_compress OF((Byte *compr, uLong comprLen,
+ Byte *uncompr, uLong uncomprLen));
+void test_gzio OF((const char *fname,
+ Byte *uncompr, uLong uncomprLen));
+void test_deflate OF((Byte *compr, uLong comprLen));
+void test_inflate OF((Byte *compr, uLong comprLen,
+ Byte *uncompr, uLong uncomprLen));
+void test_large_deflate OF((Byte *compr, uLong comprLen,
+ Byte *uncompr, uLong uncomprLen));
+void test_large_inflate OF((Byte *compr, uLong comprLen,
+ Byte *uncompr, uLong uncomprLen));
+void test_flush OF((Byte *compr, uLong *comprLen));
+void test_sync OF((Byte *compr, uLong comprLen,
+ Byte *uncompr, uLong uncomprLen));
+void test_dict_deflate OF((Byte *compr, uLong comprLen));
+void test_dict_inflate OF((Byte *compr, uLong comprLen,
+ Byte *uncompr, uLong uncomprLen));
+int main OF((int argc, char *argv[]));
+
+/* ===========================================================================
+ * Test compress() and uncompress()
+ */
+void test_compress(compr, comprLen, uncompr, uncomprLen)
+ Byte *compr, *uncompr;
+ uLong comprLen, uncomprLen;
+{
+ int err;
+ uLong len = (uLong)strlen(hello)+1;
+
+ err = compress(compr, &comprLen, (const Bytef*)hello, len);
+ CHECK_ERR(err, "compress");
+
+ strcpy((char*)uncompr, "garbage");
+
+ err = uncompress(uncompr, &uncomprLen, compr, comprLen);
+ CHECK_ERR(err, "uncompress");
+
+ if (strcmp((char*)uncompr, hello)) {
+ fprintf(stderr, "bad uncompress\n");
+ exit(1);
+ } else {
+ printf("uncompress(): %s\n", (char *)uncompr);
+ }
+}
+
+/* ===========================================================================
+ * Test read/write of .gz files
+ */
+void test_gzio(fname, uncompr, uncomprLen)
+ const char *fname; /* compressed file name */
+ Byte *uncompr;
+ uLong uncomprLen;
+{
+#ifdef NO_GZCOMPRESS
+ fprintf(stderr, "NO_GZCOMPRESS -- gz* functions cannot compress\n");
+#else
+ int err;
+ int len = (int)strlen(hello)+1;
+ gzFile file;
+ z_off_t pos;
+
+ file = gzopen(fname, "wb");
+ if (file == NULL) {
+ fprintf(stderr, "gzopen error\n");
+ exit(1);
+ }
+ gzputc(file, 'h');
+ if (gzputs(file, "ello") != 4) {
+ fprintf(stderr, "gzputs err: %s\n", gzerror(file, &err));
+ exit(1);
+ }
+ if (gzprintf(file, ", %s!", "hello") != 8) {
+ fprintf(stderr, "gzprintf err: %s\n", gzerror(file, &err));
+ exit(1);
+ }
+ gzseek(file, 1L, SEEK_CUR); /* add one zero byte */
+ gzclose(file);
+
+ file = gzopen(fname, "rb");
+ if (file == NULL) {
+ fprintf(stderr, "gzopen error\n");
+ exit(1);
+ }
+ strcpy((char*)uncompr, "garbage");
+
+ if (gzread(file, uncompr, (unsigned)uncomprLen) != len) {
+ fprintf(stderr, "gzread err: %s\n", gzerror(file, &err));
+ exit(1);
+ }
+ if (strcmp((char*)uncompr, hello)) {
+ fprintf(stderr, "bad gzread: %s\n", (char*)uncompr);
+ exit(1);
+ } else {
+ printf("gzread(): %s\n", (char*)uncompr);
+ }
+
+ pos = gzseek(file, -8L, SEEK_CUR);
+ if (pos != 6 || gztell(file) != pos) {
+ fprintf(stderr, "gzseek error, pos=%ld, gztell=%ld\n",
+ (long)pos, (long)gztell(file));
+ exit(1);
+ }
+
+ if (gzgetc(file) != ' ') {
+ fprintf(stderr, "gzgetc error\n");
+ exit(1);
+ }
+
+ if (gzungetc(' ', file) != ' ') {
+ fprintf(stderr, "gzungetc error\n");
+ exit(1);
+ }
+
+ gzgets(file, (char*)uncompr, (int)uncomprLen);
+ if (strlen((char*)uncompr) != 7) { /* " hello!" */
+ fprintf(stderr, "gzgets err after gzseek: %s\n", gzerror(file, &err));
+ exit(1);
+ }
+ if (strcmp((char*)uncompr, hello + 6)) {
+ fprintf(stderr, "bad gzgets after gzseek\n");
+ exit(1);
+ } else {
+ printf("gzgets() after gzseek: %s\n", (char*)uncompr);
+ }
+
+ gzclose(file);
+#endif
+}
+
+/* ===========================================================================
+ * Test deflate() with small buffers
+ */
+void test_deflate(compr, comprLen)
+ Byte *compr;
+ uLong comprLen;
+{
+ z_stream c_stream; /* compression stream */
+ int err;
+ uLong len = (uLong)strlen(hello)+1;
+
+ c_stream.zalloc = (alloc_func)0;
+ c_stream.zfree = (free_func)0;
+ c_stream.opaque = (voidpf)0;
+
+ err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION);
+ CHECK_ERR(err, "deflateInit");
+
+ c_stream.next_in = (Bytef*)hello;
+ c_stream.next_out = compr;
+
+ while (c_stream.total_in != len && c_stream.total_out < comprLen) {
+ c_stream.avail_in = c_stream.avail_out = 1; /* force small buffers */
+ err = deflate(&c_stream, Z_NO_FLUSH);
+ CHECK_ERR(err, "deflate");
+ }
+ /* Finish the stream, still forcing small buffers: */
+ for (;;) {
+ c_stream.avail_out = 1;
+ err = deflate(&c_stream, Z_FINISH);
+ if (err == Z_STREAM_END) break;
+ CHECK_ERR(err, "deflate");
+ }
+
+ err = deflateEnd(&c_stream);
+ CHECK_ERR(err, "deflateEnd");
+}
+
+/* ===========================================================================
+ * Test inflate() with small buffers
+ */
+void test_inflate(compr, comprLen, uncompr, uncomprLen)
+ Byte *compr, *uncompr;
+ uLong comprLen, uncomprLen;
+{
+ int err;
+ z_stream d_stream; /* decompression stream */
+
+ strcpy((char*)uncompr, "garbage");
+
+ d_stream.zalloc = (alloc_func)0;
+ d_stream.zfree = (free_func)0;
+ d_stream.opaque = (voidpf)0;
+
+ d_stream.next_in = compr;
+ d_stream.avail_in = 0;
+ d_stream.next_out = uncompr;
+
+ err = inflateInit(&d_stream);
+ CHECK_ERR(err, "inflateInit");
+
+ while (d_stream.total_out < uncomprLen && d_stream.total_in < comprLen) {
+ d_stream.avail_in = d_stream.avail_out = 1; /* force small buffers */
+ err = inflate(&d_stream, Z_NO_FLUSH);
+ if (err == Z_STREAM_END) break;
+ CHECK_ERR(err, "inflate");
+ }
+
+ err = inflateEnd(&d_stream);
+ CHECK_ERR(err, "inflateEnd");
+
+ if (strcmp((char*)uncompr, hello)) {
+ fprintf(stderr, "bad inflate\n");
+ exit(1);
+ } else {
+ printf("inflate(): %s\n", (char *)uncompr);
+ }
+}
+
+/* ===========================================================================
+ * Test deflate() with large buffers and dynamic change of compression level
+ */
+void test_large_deflate(compr, comprLen, uncompr, uncomprLen)
+ Byte *compr, *uncompr;
+ uLong comprLen, uncomprLen;
+{
+ z_stream c_stream; /* compression stream */
+ int err;
+
+ c_stream.zalloc = (alloc_func)0;
+ c_stream.zfree = (free_func)0;
+ c_stream.opaque = (voidpf)0;
+
+ err = deflateInit(&c_stream, Z_BEST_SPEED);
+ CHECK_ERR(err, "deflateInit");
+
+ c_stream.next_out = compr;
+ c_stream.avail_out = (uInt)comprLen;
+
+ /* At this point, uncompr is still mostly zeroes, so it should compress
+ * very well:
+ */
+ c_stream.next_in = uncompr;
+ c_stream.avail_in = (uInt)uncomprLen;
+ err = deflate(&c_stream, Z_NO_FLUSH);
+ CHECK_ERR(err, "deflate");
+ if (c_stream.avail_in != 0) {
+ fprintf(stderr, "deflate not greedy\n");
+ exit(1);
+ }
+
+ /* Feed in already compressed data and switch to no compression: */
+ deflateParams(&c_stream, Z_NO_COMPRESSION, Z_DEFAULT_STRATEGY);
+ c_stream.next_in = compr;
+ c_stream.avail_in = (uInt)comprLen/2;
+ err = deflate(&c_stream, Z_NO_FLUSH);
+ CHECK_ERR(err, "deflate");
+
+ /* Switch back to compressing mode: */
+ deflateParams(&c_stream, Z_BEST_COMPRESSION, Z_FILTERED);
+ c_stream.next_in = uncompr;
+ c_stream.avail_in = (uInt)uncomprLen;
+ err = deflate(&c_stream, Z_NO_FLUSH);
+ CHECK_ERR(err, "deflate");
+
+ err = deflate(&c_stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ fprintf(stderr, "deflate should report Z_STREAM_END\n");
+ exit(1);
+ }
+ err = deflateEnd(&c_stream);
+ CHECK_ERR(err, "deflateEnd");
+}
+
+/* ===========================================================================
+ * Test inflate() with large buffers
+ */
+void test_large_inflate(compr, comprLen, uncompr, uncomprLen)
+ Byte *compr, *uncompr;
+ uLong comprLen, uncomprLen;
+{
+ int err;
+ z_stream d_stream; /* decompression stream */
+
+ strcpy((char*)uncompr, "garbage");
+
+ d_stream.zalloc = (alloc_func)0;
+ d_stream.zfree = (free_func)0;
+ d_stream.opaque = (voidpf)0;
+
+ d_stream.next_in = compr;
+ d_stream.avail_in = (uInt)comprLen;
+
+ err = inflateInit(&d_stream);
+ CHECK_ERR(err, "inflateInit");
+
+ for (;;) {
+ d_stream.next_out = uncompr; /* discard the output */
+ d_stream.avail_out = (uInt)uncomprLen;
+ err = inflate(&d_stream, Z_NO_FLUSH);
+ if (err == Z_STREAM_END) break;
+ CHECK_ERR(err, "large inflate");
+ }
+
+ err = inflateEnd(&d_stream);
+ CHECK_ERR(err, "inflateEnd");
+
+ if (d_stream.total_out != 2*uncomprLen + comprLen/2) {
+ fprintf(stderr, "bad large inflate: %ld\n", d_stream.total_out);
+ exit(1);
+ } else {
+ printf("large_inflate(): OK\n");
+ }
+}
+
+/* ===========================================================================
+ * Test deflate() with full flush
+ */
+void test_flush(compr, comprLen)
+ Byte *compr;
+ uLong *comprLen;
+{
+ z_stream c_stream; /* compression stream */
+ int err;
+ uInt len = (uInt)strlen(hello)+1;
+
+ c_stream.zalloc = (alloc_func)0;
+ c_stream.zfree = (free_func)0;
+ c_stream.opaque = (voidpf)0;
+
+ err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION);
+ CHECK_ERR(err, "deflateInit");
+
+ c_stream.next_in = (Bytef*)hello;
+ c_stream.next_out = compr;
+ c_stream.avail_in = 3;
+ c_stream.avail_out = (uInt)*comprLen;
+ err = deflate(&c_stream, Z_FULL_FLUSH);
+ CHECK_ERR(err, "deflate");
+
+ compr[3]++; /* force an error in first compressed block */
+ c_stream.avail_in = len - 3;
+
+ err = deflate(&c_stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ CHECK_ERR(err, "deflate");
+ }
+ err = deflateEnd(&c_stream);
+ CHECK_ERR(err, "deflateEnd");
+
+ *comprLen = c_stream.total_out;
+}
+
+/* ===========================================================================
+ * Test inflateSync()
+ */
+void test_sync(compr, comprLen, uncompr, uncomprLen)
+ Byte *compr, *uncompr;
+ uLong comprLen, uncomprLen;
+{
+ int err;
+ z_stream d_stream; /* decompression stream */
+
+ strcpy((char*)uncompr, "garbage");
+
+ d_stream.zalloc = (alloc_func)0;
+ d_stream.zfree = (free_func)0;
+ d_stream.opaque = (voidpf)0;
+
+ d_stream.next_in = compr;
+ d_stream.avail_in = 2; /* just read the zlib header */
+
+ err = inflateInit(&d_stream);
+ CHECK_ERR(err, "inflateInit");
+
+ d_stream.next_out = uncompr;
+ d_stream.avail_out = (uInt)uncomprLen;
+
+ inflate(&d_stream, Z_NO_FLUSH);
+ CHECK_ERR(err, "inflate");
+
+ d_stream.avail_in = (uInt)comprLen-2; /* read all compressed data */
+ err = inflateSync(&d_stream); /* but skip the damaged part */
+ CHECK_ERR(err, "inflateSync");
+
+ err = inflate(&d_stream, Z_FINISH);
+ if (err != Z_DATA_ERROR) {
+ fprintf(stderr, "inflate should report DATA_ERROR\n");
+ /* Because of incorrect adler32 */
+ exit(1);
+ }
+ err = inflateEnd(&d_stream);
+ CHECK_ERR(err, "inflateEnd");
+
+ printf("after inflateSync(): hel%s\n", (char *)uncompr);
+}
+
+/* ===========================================================================
+ * Test deflate() with preset dictionary
+ */
+void test_dict_deflate(compr, comprLen)
+ Byte *compr;
+ uLong comprLen;
+{
+ z_stream c_stream; /* compression stream */
+ int err;
+
+ c_stream.zalloc = (alloc_func)0;
+ c_stream.zfree = (free_func)0;
+ c_stream.opaque = (voidpf)0;
+
+ err = deflateInit(&c_stream, Z_BEST_COMPRESSION);
+ CHECK_ERR(err, "deflateInit");
+
+ err = deflateSetDictionary(&c_stream,
+ (const Bytef*)dictionary, sizeof(dictionary));
+ CHECK_ERR(err, "deflateSetDictionary");
+
+ dictId = c_stream.adler;
+ c_stream.next_out = compr;
+ c_stream.avail_out = (uInt)comprLen;
+
+ c_stream.next_in = (Bytef*)hello;
+ c_stream.avail_in = (uInt)strlen(hello)+1;
+
+ err = deflate(&c_stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ fprintf(stderr, "deflate should report Z_STREAM_END\n");
+ exit(1);
+ }
+ err = deflateEnd(&c_stream);
+ CHECK_ERR(err, "deflateEnd");
+}
+
+/* ===========================================================================
+ * Test inflate() with a preset dictionary
+ */
+void test_dict_inflate(compr, comprLen, uncompr, uncomprLen)
+ Byte *compr, *uncompr;
+ uLong comprLen, uncomprLen;
+{
+ int err;
+ z_stream d_stream; /* decompression stream */
+
+ strcpy((char*)uncompr, "garbage");
+
+ d_stream.zalloc = (alloc_func)0;
+ d_stream.zfree = (free_func)0;
+ d_stream.opaque = (voidpf)0;
+
+ d_stream.next_in = compr;
+ d_stream.avail_in = (uInt)comprLen;
+
+ err = inflateInit(&d_stream);
+ CHECK_ERR(err, "inflateInit");
+
+ d_stream.next_out = uncompr;
+ d_stream.avail_out = (uInt)uncomprLen;
+
+ for (;;) {
+ err = inflate(&d_stream, Z_NO_FLUSH);
+ if (err == Z_STREAM_END) break;
+ if (err == Z_NEED_DICT) {
+ if (d_stream.adler != dictId) {
+ fprintf(stderr, "unexpected dictionary");
+ exit(1);
+ }
+ err = inflateSetDictionary(&d_stream, (const Bytef*)dictionary,
+ sizeof(dictionary));
+ }
+ CHECK_ERR(err, "inflate with dict");
+ }
+
+ err = inflateEnd(&d_stream);
+ CHECK_ERR(err, "inflateEnd");
+
+ if (strcmp((char*)uncompr, hello)) {
+ fprintf(stderr, "bad inflate with dict\n");
+ exit(1);
+ } else {
+ printf("inflate with dictionary: %s\n", (char *)uncompr);
+ }
+}
+
+/* ===========================================================================
+ * Usage: example [output.gz [input.gz]]
+ */
+
+int main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ Byte *compr, *uncompr;
+ uLong comprLen = 10000*sizeof(int); /* don't overflow on MSDOS */
+ uLong uncomprLen = comprLen;
+ static const char* myVersion = ZLIB_VERSION;
+
+ if (zlibVersion()[0] != myVersion[0]) {
+ fprintf(stderr, "incompatible zlib version\n");
+ exit(1);
+
+ } else if (strcmp(zlibVersion(), ZLIB_VERSION) != 0) {
+ fprintf(stderr, "warning: different zlib version\n");
+ }
+
+ printf("zlib version %s = 0x%04x, compile flags = 0x%lx\n",
+ ZLIB_VERSION, ZLIB_VERNUM, zlibCompileFlags());
+
+ compr = (Byte*)calloc((uInt)comprLen, 1);
+ uncompr = (Byte*)calloc((uInt)uncomprLen, 1);
+ /* compr and uncompr are cleared to avoid reading uninitialized
+ * data and to ensure that uncompr compresses well.
+ */
+ if (compr == Z_NULL || uncompr == Z_NULL) {
+ printf("out of memory\n");
+ exit(1);
+ }
+ test_compress(compr, comprLen, uncompr, uncomprLen);
+
+ test_gzio((argc > 1 ? argv[1] : TESTFILE),
+ uncompr, uncomprLen);
+
+ test_deflate(compr, comprLen);
+ test_inflate(compr, comprLen, uncompr, uncomprLen);
+
+ test_large_deflate(compr, comprLen, uncompr, uncomprLen);
+ test_large_inflate(compr, comprLen, uncompr, uncomprLen);
+
+ test_flush(compr, &comprLen);
+ test_sync(compr, comprLen, uncompr, uncomprLen);
+ comprLen = uncomprLen;
+
+ test_dict_deflate(compr, comprLen);
+ test_dict_inflate(compr, comprLen, uncompr, uncomprLen);
+
+ free(compr);
+ free(uncompr);
+
+ return 0;
+}
diff --git a/lib/libz/gzio.c b/lib/libz/gzio.c
new file mode 100644
index 0000000..0aa03e9
--- /dev/null
+++ b/lib/libz/gzio.c
@@ -0,0 +1,1027 @@
+/* gzio.c -- IO on .gz files
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Compile this file with -DNO_GZCOMPRESS to avoid the compression code.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+
+#include "zutil.h"
+
+#ifdef NO_DEFLATE /* for compatibility with old definition */
+# define NO_GZCOMPRESS
+#endif
+
+#ifndef NO_DUMMY_DECL
+struct internal_state {int dummy;}; /* for buggy compilers */
+#endif
+
+#ifndef Z_BUFSIZE
+# ifdef MAXSEG_64K
+# define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */
+# else
+# define Z_BUFSIZE 16384
+# endif
+#endif
+#ifndef Z_PRINTF_BUFSIZE
+# define Z_PRINTF_BUFSIZE 4096
+#endif
+
+#ifdef __MVS__
+# pragma map (fdopen , "\174\174FDOPEN")
+ FILE *fdopen(int, const char *);
+#endif
+
+#ifndef STDC
+extern voidp malloc OF((uInt size));
+extern void free OF((voidpf ptr));
+#endif
+
+#define ALLOC(size) malloc(size)
+#define TRYFREE(p) {if (p) free(p);}
+
+static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
+
+/* gzip flag byte */
+#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
+#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
+#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
+#define COMMENT 0x10 /* bit 4 set: file comment present */
+#define RESERVED 0xE0 /* bits 5..7: reserved */
+
+typedef struct gz_stream {
+ z_stream stream;
+ int z_err; /* error code for last stream operation */
+ int z_eof; /* set if end of input file */
+ FILE *file; /* .gz file */
+ Byte *inbuf; /* input buffer */
+ Byte *outbuf; /* output buffer */
+ uLong crc; /* crc32 of uncompressed data */
+ char *msg; /* error message */
+ char *path; /* path name for debugging only */
+ int transparent; /* 1 if input file is not a .gz file */
+ char mode; /* 'w' or 'r' */
+ z_off_t start; /* start of compressed data in file (header skipped) */
+ z_off_t in; /* bytes into deflate or inflate */
+ z_off_t out; /* bytes out of deflate or inflate */
+ int back; /* one character push-back */
+ int last; /* true if push-back is last character */
+} gz_stream;
+
+
+local gzFile gz_open OF((const char *path, const char *mode, int fd));
+local int do_flush OF((gzFile file, int flush));
+local int get_byte OF((gz_stream *s));
+local void check_header OF((gz_stream *s));
+local int destroy OF((gz_stream *s));
+local void putLong OF((FILE *file, uLong x));
+local uLong getLong OF((gz_stream *s));
+
+/* ===========================================================================
+ Opens a gzip (.gz) file for reading or writing. The mode parameter
+ is as in fopen ("rb" or "wb"). The file is given either by file descriptor
+ or path name (if fd == -1).
+ gz_open returns NULL if the file could not be opened or if there was
+ insufficient memory to allocate the (de)compression state; errno
+ can be checked to distinguish the two cases (if errno is zero, the
+ zlib error is Z_MEM_ERROR).
+*/
+local gzFile gz_open (path, mode, fd)
+ const char *path;
+ const char *mode;
+ int fd;
+{
+ int err;
+ int level = Z_DEFAULT_COMPRESSION; /* compression level */
+ int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */
+ char *p = (char*)mode;
+ gz_stream *s;
+ char fmode[80]; /* copy of mode, without the compression level */
+ char *m = fmode;
+
+ if (!path || !mode) return Z_NULL;
+
+ s = (gz_stream *)ALLOC(sizeof(gz_stream));
+ if (!s) return Z_NULL;
+
+ s->stream.zalloc = (alloc_func)0;
+ s->stream.zfree = (free_func)0;
+ s->stream.opaque = (voidpf)0;
+ s->stream.next_in = s->inbuf = Z_NULL;
+ s->stream.next_out = s->outbuf = Z_NULL;
+ s->stream.avail_in = s->stream.avail_out = 0;
+ s->file = NULL;
+ s->z_err = Z_OK;
+ s->z_eof = 0;
+ s->in = 0;
+ s->out = 0;
+ s->back = EOF;
+ s->crc = crc32(0L, Z_NULL, 0);
+ s->msg = NULL;
+ s->transparent = 0;
+
+ s->path = (char*)ALLOC(strlen(path)+1);
+ if (s->path == NULL) {
+ return destroy(s), (gzFile)Z_NULL;
+ }
+ strcpy(s->path, path); /* do this early for debugging */
+
+ s->mode = '\0';
+ do {
+ if (*p == 'r') s->mode = 'r';
+ if (*p == 'w' || *p == 'a') s->mode = 'w';
+ if (*p >= '0' && *p <= '9') {
+ level = *p - '0';
+ } else if (*p == 'f') {
+ strategy = Z_FILTERED;
+ } else if (*p == 'h') {
+ strategy = Z_HUFFMAN_ONLY;
+ } else if (*p == 'R') {
+ strategy = Z_RLE;
+ } else {
+ *m++ = *p; /* copy the mode */
+ }
+ } while (*p++ && m != fmode + sizeof(fmode));
+ if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL;
+
+ if (s->mode == 'w') {
+#ifdef NO_GZCOMPRESS
+ err = Z_STREAM_ERROR;
+#else
+ err = deflateInit2(&(s->stream), level,
+ Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy);
+ /* windowBits is passed < 0 to suppress zlib header */
+
+ s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
+#endif
+ if (err != Z_OK || s->outbuf == Z_NULL) {
+ return destroy(s), (gzFile)Z_NULL;
+ }
+ } else {
+ s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE);
+
+ err = inflateInit2(&(s->stream), -MAX_WBITS);
+ /* windowBits is passed < 0 to tell that there is no zlib header.
+ * Note that in this case inflate *requires* an extra "dummy" byte
+ * after the compressed stream in order to complete decompression and
+ * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are
+ * present after the compressed stream.
+ */
+ if (err != Z_OK || s->inbuf == Z_NULL) {
+ return destroy(s), (gzFile)Z_NULL;
+ }
+ }
+ s->stream.avail_out = Z_BUFSIZE;
+
+ errno = 0;
+ s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode);
+
+ if (s->file == NULL) {
+ return destroy(s), (gzFile)Z_NULL;
+ }
+ if (s->mode == 'w') {
+ /* Write a very simple .gz header:
+ */
+ fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1],
+ Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE);
+ s->start = 10L;
+ /* We use 10L instead of ftell(s->file) to because ftell causes an
+ * fflush on some systems. This version of the library doesn't use
+ * start anyway in write mode, so this initialization is not
+ * necessary.
+ */
+ } else {
+ check_header(s); /* skip the .gz header */
+ s->start = ftell(s->file) - s->stream.avail_in;
+ }
+
+ return (gzFile)s;
+}
+
+/* ===========================================================================
+ Opens a gzip (.gz) file for reading or writing.
+*/
+gzFile ZEXPORT gzopen (path, mode)
+ const char *path;
+ const char *mode;
+{
+ return gz_open (path, mode, -1);
+}
+
+/* ===========================================================================
+ Associate a gzFile with the file descriptor fd. fd is not dup'ed here
+ to mimic the behavio(u)r of fdopen.
+*/
+gzFile ZEXPORT gzdopen (fd, mode)
+ int fd;
+ const char *mode;
+{
+ char name[46]; /* allow for up to 128-bit integers */
+
+ if (fd < 0) return (gzFile)Z_NULL;
+ snprintf(name, sizeof(name), "<fd:%d>", fd); /* for debugging */
+
+ return gz_open (name, mode, fd);
+}
+
+/* ===========================================================================
+ * Update the compression level and strategy
+ */
+int ZEXPORT gzsetparams (file, level, strategy)
+ gzFile file;
+ int level;
+ int strategy;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
+
+ /* Make room to allow flushing */
+ if (s->stream.avail_out == 0) {
+
+ s->stream.next_out = s->outbuf;
+ if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
+ s->z_err = Z_ERRNO;
+ }
+ s->stream.avail_out = Z_BUFSIZE;
+ }
+
+ return deflateParams (&(s->stream), level, strategy);
+}
+
+/* ===========================================================================
+ Read a byte from a gz_stream; update next_in and avail_in. Return EOF
+ for end of file.
+ IN assertion: the stream s has been sucessfully opened for reading.
+*/
+local int get_byte(s)
+ gz_stream *s;
+{
+ if (s->z_eof) return EOF;
+ if (s->stream.avail_in == 0) {
+ errno = 0;
+ s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file);
+ if (s->stream.avail_in == 0) {
+ s->z_eof = 1;
+ if (ferror(s->file)) s->z_err = Z_ERRNO;
+ return EOF;
+ }
+ s->stream.next_in = s->inbuf;
+ }
+ s->stream.avail_in--;
+ return *(s->stream.next_in)++;
+}
+
+/* ===========================================================================
+ Check the gzip header of a gz_stream opened for reading. Set the stream
+ mode to transparent if the gzip magic header is not present; set s->err
+ to Z_DATA_ERROR if the magic header is present but the rest of the header
+ is incorrect.
+ IN assertion: the stream s has already been created sucessfully;
+ s->stream.avail_in is zero for the first time, but may be non-zero
+ for concatenated .gz files.
+*/
+local void check_header(s)
+ gz_stream *s;
+{
+ int method; /* method byte */
+ int flags; /* flags byte */
+ uInt len;
+ int c;
+
+ /* Assure two bytes in the buffer so we can peek ahead -- handle case
+ where first byte of header is at the end of the buffer after the last
+ gzip segment */
+ len = s->stream.avail_in;
+ if (len < 2) {
+ if (len) s->inbuf[0] = s->stream.next_in[0];
+ errno = 0;
+ len = (uInt)fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file);
+ if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO;
+ s->stream.avail_in += len;
+ s->stream.next_in = s->inbuf;
+ if (s->stream.avail_in < 2) {
+ s->transparent = s->stream.avail_in;
+ return;
+ }
+ }
+
+ /* Peek ahead to check the gzip magic header */
+ if (s->stream.next_in[0] != gz_magic[0] ||
+ s->stream.next_in[1] != gz_magic[1]) {
+ s->transparent = 1;
+ return;
+ }
+ s->stream.avail_in -= 2;
+ s->stream.next_in += 2;
+
+ /* Check the rest of the gzip header */
+ method = get_byte(s);
+ flags = get_byte(s);
+ if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
+ s->z_err = Z_DATA_ERROR;
+ return;
+ }
+
+ /* Discard time, xflags and OS code: */
+ for (len = 0; len < 6; len++) (void)get_byte(s);
+
+ if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
+ len = (uInt)get_byte(s);
+ len += ((uInt)get_byte(s))<<8;
+ /* len is garbage if EOF but the loop below will quit anyway */
+ while (len-- != 0 && get_byte(s) != EOF) ;
+ }
+ if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
+ while ((c = get_byte(s)) != 0 && c != EOF) ;
+ }
+ if ((flags & COMMENT) != 0) { /* skip the .gz file comment */
+ while ((c = get_byte(s)) != 0 && c != EOF) ;
+ }
+ if ((flags & HEAD_CRC) != 0) { /* skip the header crc */
+ for (len = 0; len < 2; len++) (void)get_byte(s);
+ }
+ s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK;
+}
+
+ /* ===========================================================================
+ * Cleanup then free the given gz_stream. Return a zlib error code.
+ Try freeing in the reverse order of allocations.
+ */
+local int destroy (s)
+ gz_stream *s;
+{
+ int err = Z_OK;
+
+ if (!s) return Z_STREAM_ERROR;
+
+ TRYFREE(s->msg);
+
+ if (s->stream.state != NULL) {
+ if (s->mode == 'w') {
+#ifdef NO_GZCOMPRESS
+ err = Z_STREAM_ERROR;
+#else
+ err = deflateEnd(&(s->stream));
+#endif
+ } else if (s->mode == 'r') {
+ err = inflateEnd(&(s->stream));
+ }
+ }
+ if (s->file != NULL && fclose(s->file)) {
+#ifdef ESPIPE
+ if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */
+#endif
+ err = Z_ERRNO;
+ }
+ if (s->z_err < 0) err = s->z_err;
+
+ TRYFREE(s->inbuf);
+ TRYFREE(s->outbuf);
+ TRYFREE(s->path);
+ TRYFREE(s);
+ return err;
+}
+
+/* ===========================================================================
+ Reads the given number of uncompressed bytes from the compressed file.
+ gzread returns the number of bytes actually read (0 for end of file).
+*/
+int ZEXPORT gzread (file, buf, len)
+ gzFile file;
+ voidp buf;
+ unsigned len;
+{
+ gz_stream *s = (gz_stream*)file;
+ Bytef *start = (Bytef*)buf; /* starting point for crc computation */
+ Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */
+
+ if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR;
+
+ if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1;
+ if (s->z_err == Z_STREAM_END) return 0; /* EOF */
+
+ next_out = (Byte*)buf;
+ s->stream.next_out = (Bytef*)buf;
+ s->stream.avail_out = len;
+
+ if (s->stream.avail_out && s->back != EOF) {
+ *next_out++ = s->back;
+ s->stream.next_out++;
+ s->stream.avail_out--;
+ s->back = EOF;
+ s->out++;
+ start++;
+ if (s->last) {
+ s->z_err = Z_STREAM_END;
+ return 1;
+ }
+ }
+
+ while (s->stream.avail_out != 0) {
+
+ if (s->transparent) {
+ /* Copy first the lookahead bytes: */
+ uInt n = s->stream.avail_in;
+ if (n > s->stream.avail_out) n = s->stream.avail_out;
+ if (n > 0) {
+ zmemcpy(s->stream.next_out, s->stream.next_in, n);
+ next_out += n;
+ s->stream.next_out = next_out;
+ s->stream.next_in += n;
+ s->stream.avail_out -= n;
+ s->stream.avail_in -= n;
+ }
+ if (s->stream.avail_out > 0) {
+ s->stream.avail_out -=
+ (uInt)fread(next_out, 1, s->stream.avail_out, s->file);
+ }
+ len -= s->stream.avail_out;
+ s->in += len;
+ s->out += len;
+ if (len == 0) s->z_eof = 1;
+ return (int)len;
+ }
+ if (s->stream.avail_in == 0 && !s->z_eof) {
+
+ errno = 0;
+ s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file);
+ if (s->stream.avail_in == 0) {
+ s->z_eof = 1;
+ if (ferror(s->file)) {
+ s->z_err = Z_ERRNO;
+ break;
+ }
+ }
+ s->stream.next_in = s->inbuf;
+ }
+ s->in += s->stream.avail_in;
+ s->out += s->stream.avail_out;
+ s->z_err = inflate(&(s->stream), Z_NO_FLUSH);
+ s->in -= s->stream.avail_in;
+ s->out -= s->stream.avail_out;
+
+ if (s->z_err == Z_STREAM_END) {
+ /* Check CRC and original size */
+ s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
+ start = s->stream.next_out;
+
+ if (getLong(s) != s->crc) {
+ s->z_err = Z_DATA_ERROR;
+ } else {
+ (void)getLong(s);
+ /* The uncompressed length returned by above getlong() may be
+ * different from s->out in case of concatenated .gz files.
+ * Check for such files:
+ */
+ check_header(s);
+ if (s->z_err == Z_OK) {
+ inflateReset(&(s->stream));
+ s->crc = crc32(0L, Z_NULL, 0);
+ }
+ }
+ }
+ if (s->z_err != Z_OK || s->z_eof) break;
+ }
+ s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
+
+ if (len == s->stream.avail_out &&
+ (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO))
+ return -1;
+ return (int)(len - s->stream.avail_out);
+}
+
+
+/* ===========================================================================
+ Reads one byte from the compressed file. gzgetc returns this byte
+ or -1 in case of end of file or error.
+*/
+int ZEXPORT gzgetc(file)
+ gzFile file;
+{
+ unsigned char c;
+
+ return gzread(file, &c, 1) == 1 ? c : -1;
+}
+
+
+/* ===========================================================================
+ Push one byte back onto the stream.
+*/
+int ZEXPORT gzungetc(c, file)
+ int c;
+ gzFile file;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || s->mode != 'r' || c == EOF || s->back != EOF) return EOF;
+ s->back = c;
+ s->out--;
+ s->last = (s->z_err == Z_STREAM_END);
+ if (s->last) s->z_err = Z_OK;
+ s->z_eof = 0;
+ return c;
+}
+
+
+/* ===========================================================================
+ Reads bytes from the compressed file until len-1 characters are
+ read, or a newline character is read and transferred to buf, or an
+ end-of-file condition is encountered. The string is then terminated
+ with a null character.
+ gzgets returns buf, or Z_NULL in case of error.
+
+ The current implementation is not optimized at all.
+*/
+char * ZEXPORT gzgets(file, buf, len)
+ gzFile file;
+ char *buf;
+ int len;
+{
+ char *b = buf;
+ if (buf == Z_NULL || len <= 0) return Z_NULL;
+
+ while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ;
+ *buf = '\0';
+ return b == buf && len > 0 ? Z_NULL : b;
+}
+
+
+#ifndef NO_GZCOMPRESS
+/* ===========================================================================
+ Writes the given number of uncompressed bytes into the compressed file.
+ gzwrite returns the number of bytes actually written (0 in case of error).
+*/
+int ZEXPORT gzwrite (file, buf, len)
+ gzFile file;
+ voidpc buf;
+ unsigned len;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
+
+ s->stream.next_in = (Bytef*)buf;
+ s->stream.avail_in = len;
+
+ while (s->stream.avail_in != 0) {
+
+ if (s->stream.avail_out == 0) {
+
+ s->stream.next_out = s->outbuf;
+ if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
+ s->z_err = Z_ERRNO;
+ break;
+ }
+ s->stream.avail_out = Z_BUFSIZE;
+ }
+ s->in += s->stream.avail_in;
+ s->out += s->stream.avail_out;
+ s->z_err = deflate(&(s->stream), Z_NO_FLUSH);
+ s->in -= s->stream.avail_in;
+ s->out -= s->stream.avail_out;
+ if (s->z_err != Z_OK) break;
+ }
+ s->crc = crc32(s->crc, (const Bytef *)buf, len);
+
+ return (int)(len - s->stream.avail_in);
+}
+
+
+/* ===========================================================================
+ Converts, formats, and writes the args to the compressed file under
+ control of the format string, as in fprintf. gzprintf returns the number of
+ uncompressed bytes actually written (0 in case of error).
+*/
+#ifdef STDC
+#include <stdarg.h>
+
+int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...)
+{
+ char buf[Z_PRINTF_BUFSIZE];
+ va_list va;
+ int len;
+
+ buf[sizeof(buf) - 1] = 0;
+ va_start(va, format);
+#ifdef NO_vsnprintf
+# ifdef HAS_vsprintf_void
+ (void)vsprintf(buf, format, va);
+ va_end(va);
+ for (len = 0; len < sizeof(buf); len++)
+ if (buf[len] == 0) break;
+# else
+ len = vsprintf(buf, format, va);
+ va_end(va);
+# endif
+#else
+# ifdef HAS_vsnprintf_void
+ (void)vsnprintf(buf, sizeof(buf), format, va);
+ va_end(va);
+ len = strlen(buf);
+# else
+ len = vsnprintf(buf, sizeof(buf), format, va);
+ va_end(va);
+# endif
+#endif
+ if (len <= 0 || len >= (int)sizeof(buf) || buf[sizeof(buf) - 1] != 0)
+ return 0;
+ return gzwrite(file, buf, (unsigned)len);
+}
+#else /* not ANSI C */
+
+int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
+ a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
+ gzFile file;
+ const char *format;
+ int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
+ a11, a12, a13, a14, a15, a16, a17, a18, a19, a20;
+{
+ char buf[Z_PRINTF_BUFSIZE];
+ int len;
+
+ buf[sizeof(buf) - 1] = 0;
+#ifdef NO_snprintf
+# ifdef HAS_sprintf_void
+ sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8,
+ a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+ for (len = 0; len < sizeof(buf); len++)
+ if (buf[len] == 0) break;
+# else
+ len = sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8,
+ a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+# endif
+#else
+# ifdef HAS_snprintf_void
+ snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8,
+ a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+ len = strlen(buf);
+# else
+ len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8,
+ a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+# endif
+#endif
+ if (len <= 0 || len >= sizeof(buf) || buf[sizeof(buf) - 1] != 0)
+ return 0;
+ return gzwrite(file, buf, len);
+}
+#endif
+
+/* ===========================================================================
+ Writes c, converted to an unsigned char, into the compressed file.
+ gzputc returns the value that was written, or -1 in case of error.
+*/
+int ZEXPORT gzputc(file, c)
+ gzFile file;
+ int c;
+{
+ unsigned char cc = (unsigned char) c; /* required for big endian systems */
+
+ return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1;
+}
+
+
+/* ===========================================================================
+ Writes the given null-terminated string to the compressed file, excluding
+ the terminating null character.
+ gzputs returns the number of characters written, or -1 in case of error.
+*/
+int ZEXPORT gzputs(file, s)
+ gzFile file;
+ const char *s;
+{
+ return gzwrite(file, (char*)s, (unsigned)strlen(s));
+}
+
+
+/* ===========================================================================
+ Flushes all pending output into the compressed file. The parameter
+ flush is as in the deflate() function.
+*/
+local int do_flush (file, flush)
+ gzFile file;
+ int flush;
+{
+ uInt len;
+ int done = 0;
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
+
+ s->stream.avail_in = 0; /* should be zero already anyway */
+
+ for (;;) {
+ len = Z_BUFSIZE - s->stream.avail_out;
+
+ if (len != 0) {
+ if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) {
+ s->z_err = Z_ERRNO;
+ return Z_ERRNO;
+ }
+ s->stream.next_out = s->outbuf;
+ s->stream.avail_out = Z_BUFSIZE;
+ }
+ if (done) break;
+ s->out += s->stream.avail_out;
+ s->z_err = deflate(&(s->stream), flush);
+ s->out -= s->stream.avail_out;
+
+ /* Ignore the second of two consecutive flushes: */
+ if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK;
+
+ /* deflate has finished flushing only when it hasn't used up
+ * all the available space in the output buffer:
+ */
+ done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END);
+
+ if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break;
+ }
+ return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
+}
+
+int ZEXPORT gzflush (file, flush)
+ gzFile file;
+ int flush;
+{
+ gz_stream *s = (gz_stream*)file;
+ int err = do_flush (file, flush);
+
+ if (err) return err;
+ fflush(s->file);
+ return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
+}
+#endif /* NO_GZCOMPRESS */
+
+/* ===========================================================================
+ Sets the starting position for the next gzread or gzwrite on the given
+ compressed file. The offset represents a number of bytes in the
+ gzseek returns the resulting offset location as measured in bytes from
+ the beginning of the uncompressed stream, or -1 in case of error.
+ SEEK_END is not implemented, returns error.
+ In this version of the library, gzseek can be extremely slow.
+*/
+z_off_t ZEXPORT gzseek (file, offset, whence)
+ gzFile file;
+ z_off_t offset;
+ int whence;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || whence == SEEK_END ||
+ s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) {
+ return -1L;
+ }
+
+ if (s->mode == 'w') {
+#ifdef NO_GZCOMPRESS
+ return -1L;
+#else
+ if (whence == SEEK_SET) {
+ offset -= s->in;
+ }
+ if (offset < 0) return -1L;
+
+ /* At this point, offset is the number of zero bytes to write. */
+ if (s->inbuf == Z_NULL) {
+ s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */
+ if (s->inbuf == Z_NULL) return -1L;
+ zmemzero(s->inbuf, Z_BUFSIZE);
+ }
+ while (offset > 0) {
+ uInt size = Z_BUFSIZE;
+ if (offset < Z_BUFSIZE) size = (uInt)offset;
+
+ size = gzwrite(file, s->inbuf, size);
+ if (size == 0) return -1L;
+
+ offset -= size;
+ }
+ return s->in;
+#endif
+ }
+ /* Rest of function is for reading only */
+
+ /* compute absolute position */
+ if (whence == SEEK_CUR) {
+ offset += s->out;
+ }
+ if (offset < 0) return -1L;
+
+ if (s->transparent) {
+ /* map to fseek */
+ s->back = EOF;
+ s->stream.avail_in = 0;
+ s->stream.next_in = s->inbuf;
+ if (fseek(s->file, offset, SEEK_SET) < 0) return -1L;
+
+ s->in = s->out = offset;
+ return offset;
+ }
+
+ /* For a negative seek, rewind and use positive seek */
+ if (offset >= s->out) {
+ offset -= s->out;
+ } else if (gzrewind(file) < 0) {
+ return -1L;
+ }
+ /* offset is now the number of bytes to skip. */
+
+ if (offset != 0 && s->outbuf == Z_NULL) {
+ s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
+ if (s->outbuf == Z_NULL) return -1L;
+ }
+ if (offset && s->back != EOF) {
+ s->back = EOF;
+ s->out++;
+ offset--;
+ if (s->last) s->z_err = Z_STREAM_END;
+ }
+ while (offset > 0) {
+ int size = Z_BUFSIZE;
+ if (offset < Z_BUFSIZE) size = (int)offset;
+
+ size = gzread(file, s->outbuf, (uInt)size);
+ if (size <= 0) return -1L;
+ offset -= size;
+ }
+ return s->out;
+}
+
+/* ===========================================================================
+ Rewinds input file.
+*/
+int ZEXPORT gzrewind (file)
+ gzFile file;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || s->mode != 'r') return -1;
+
+ s->z_err = Z_OK;
+ s->z_eof = 0;
+ s->back = EOF;
+ s->stream.avail_in = 0;
+ s->stream.next_in = s->inbuf;
+ s->crc = crc32(0L, Z_NULL, 0);
+ if (!s->transparent) (void)inflateReset(&s->stream);
+ s->in = 0;
+ s->out = 0;
+ return fseek(s->file, s->start, SEEK_SET);
+}
+
+/* ===========================================================================
+ Returns the starting position for the next gzread or gzwrite on the
+ given compressed file. This position represents a number of bytes in the
+ uncompressed data stream.
+*/
+z_off_t ZEXPORT gztell (file)
+ gzFile file;
+{
+ return gzseek(file, 0L, SEEK_CUR);
+}
+
+/* ===========================================================================
+ Returns 1 when EOF has previously been detected reading the given
+ input stream, otherwise zero.
+*/
+int ZEXPORT gzeof (file)
+ gzFile file;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ /* With concatenated compressed files that can have embedded
+ * crc trailers, z_eof is no longer the only/best indicator of EOF
+ * on a gz_stream. Handle end-of-stream error explicitly here.
+ */
+ if (s == NULL || s->mode != 'r') return 0;
+ if (s->z_eof) return 1;
+ return s->z_err == Z_STREAM_END;
+}
+
+/* ===========================================================================
+ Returns 1 if reading and doing so transparently, otherwise zero.
+*/
+int ZEXPORT gzdirect (file)
+ gzFile file;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || s->mode != 'r') return 0;
+ return s->transparent;
+}
+
+/* ===========================================================================
+ Outputs a long in LSB order to the given file
+*/
+local void putLong (file, x)
+ FILE *file;
+ uLong x;
+{
+ int n;
+ for (n = 0; n < 4; n++) {
+ fputc((int)(x & 0xff), file);
+ x >>= 8;
+ }
+}
+
+/* ===========================================================================
+ Reads a long in LSB order from the given gz_stream. Sets z_err in case
+ of error.
+*/
+local uLong getLong (s)
+ gz_stream *s;
+{
+ uLong x = (uLong)get_byte(s);
+ int c;
+
+ x += ((uLong)get_byte(s))<<8;
+ x += ((uLong)get_byte(s))<<16;
+ c = get_byte(s);
+ if (c == EOF) s->z_err = Z_DATA_ERROR;
+ x += ((uLong)c)<<24;
+ return x;
+}
+
+/* ===========================================================================
+ Flushes all pending output if necessary, closes the compressed file
+ and deallocates all the (de)compression state.
+*/
+int ZEXPORT gzclose (file)
+ gzFile file;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL) return Z_STREAM_ERROR;
+
+ if (s->mode == 'w') {
+#ifdef NO_GZCOMPRESS
+ return Z_STREAM_ERROR;
+#else
+ if (do_flush (file, Z_FINISH) != Z_OK)
+ return destroy((gz_stream*)file);
+
+ putLong (s->file, s->crc);
+ putLong (s->file, (uLong)(s->in & 0xffffffff));
+#endif
+ }
+ return destroy((gz_stream*)file);
+}
+
+#ifdef STDC
+# define zstrerror(errnum) strerror(errnum)
+#else
+# define zstrerror(errnum) ""
+#endif
+
+/* ===========================================================================
+ Returns the error message for the last error which occurred on the
+ given compressed file. errnum is set to zlib error number. If an
+ error occurred in the file system and not in the compression library,
+ errnum is set to Z_ERRNO and the application may consult errno
+ to get the exact error code.
+*/
+const char * ZEXPORT gzerror (file, errnum)
+ gzFile file;
+ int *errnum;
+{
+ char *m;
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL) {
+ *errnum = Z_STREAM_ERROR;
+ return (const char*)ERR_MSG(Z_STREAM_ERROR);
+ }
+ *errnum = s->z_err;
+ if (*errnum == Z_OK) return (const char*)"";
+
+ m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg);
+
+ if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err);
+
+ TRYFREE(s->msg);
+ s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3);
+ if (s->msg == Z_NULL) return (const char*)ERR_MSG(Z_MEM_ERROR);
+ strcpy(s->msg, s->path);
+ strcat(s->msg, ": ");
+ strcat(s->msg, m);
+ return (const char*)s->msg;
+}
+
+/* ===========================================================================
+ Clear the error and end-of-file flags, and do the same for the real file.
+*/
+void ZEXPORT gzclearerr (file)
+ gzFile file;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL) return;
+ if (s->z_err != Z_STREAM_END) s->z_err = Z_OK;
+ s->z_eof = 0;
+ clearerr(s->file);
+}
diff --git a/lib/libz/infback.c b/lib/libz/infback.c
new file mode 100644
index 0000000..455dbc9
--- /dev/null
+++ b/lib/libz/infback.c
@@ -0,0 +1,623 @@
+/* infback.c -- inflate using a call-back interface
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ This code is largely copied from inflate.c. Normally either infback.o or
+ inflate.o would be linked into an application--not both. The interface
+ with inffast.c is retained so that optimized assembler-coded versions of
+ inflate_fast() can be used with either inflate.c or infback.c.
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+/* function prototypes */
+local void fixedtables OF((struct inflate_state FAR *state));
+
+/*
+ strm provides memory allocation functions in zalloc and zfree, or
+ Z_NULL to use the library memory allocation functions.
+
+ windowBits is in the range 8..15, and window is a user-supplied
+ window and output buffer that is 2**windowBits bytes.
+ */
+int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size)
+z_streamp strm;
+int windowBits;
+unsigned char FAR *window;
+const char *version;
+int stream_size;
+{
+ struct inflate_state FAR *state;
+
+ if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+ stream_size != (int)(sizeof(z_stream)))
+ return Z_VERSION_ERROR;
+ if (strm == Z_NULL || window == Z_NULL ||
+ windowBits < 8 || windowBits > 15)
+ return Z_STREAM_ERROR;
+ strm->msg = Z_NULL; /* in case we return an error */
+ if (strm->zalloc == (alloc_func)0) {
+ strm->zalloc = zcalloc;
+ strm->opaque = (voidpf)0;
+ }
+ if (strm->zfree == (free_func)0) strm->zfree = zcfree;
+ state = (struct inflate_state FAR *)ZALLOC(strm, 1,
+ sizeof(struct inflate_state));
+ if (state == Z_NULL) return Z_MEM_ERROR;
+ Tracev((stderr, "inflate: allocated\n"));
+ strm->state = (struct internal_state FAR *)state;
+ state->dmax = 32768U;
+ state->wbits = windowBits;
+ state->wsize = 1U << windowBits;
+ state->window = window;
+ state->write = 0;
+ state->whave = 0;
+ return Z_OK;
+}
+
+/*
+ Return state with length and distance decoding tables and index sizes set to
+ fixed code decoding. Normally this returns fixed tables from inffixed.h.
+ If BUILDFIXED is defined, then instead this routine builds the tables the
+ first time it's called, and returns those tables the first time and
+ thereafter. This reduces the size of the code by about 2K bytes, in
+ exchange for a little execution time. However, BUILDFIXED should not be
+ used for threaded applications, since the rewriting of the tables and virgin
+ may not be thread-safe.
+ */
+local void fixedtables(state)
+struct inflate_state FAR *state;
+{
+#ifdef BUILDFIXED
+ static int virgin = 1;
+ static code *lenfix, *distfix;
+ static code fixed[544];
+
+ /* build fixed huffman tables if first call (may not be thread safe) */
+ if (virgin) {
+ unsigned sym, bits;
+ static code *next;
+
+ /* literal/length table */
+ sym = 0;
+ while (sym < 144) state->lens[sym++] = 8;
+ while (sym < 256) state->lens[sym++] = 9;
+ while (sym < 280) state->lens[sym++] = 7;
+ while (sym < 288) state->lens[sym++] = 8;
+ next = fixed;
+ lenfix = next;
+ bits = 9;
+ inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);
+
+ /* distance table */
+ sym = 0;
+ while (sym < 32) state->lens[sym++] = 5;
+ distfix = next;
+ bits = 5;
+ inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);
+
+ /* do this just once */
+ virgin = 0;
+ }
+#else /* !BUILDFIXED */
+# include "inffixed.h"
+#endif /* BUILDFIXED */
+ state->lencode = lenfix;
+ state->lenbits = 9;
+ state->distcode = distfix;
+ state->distbits = 5;
+}
+
+/* Macros for inflateBack(): */
+
+/* Load returned state from inflate_fast() */
+#define LOAD() \
+ do { \
+ put = strm->next_out; \
+ left = strm->avail_out; \
+ next = strm->next_in; \
+ have = strm->avail_in; \
+ hold = state->hold; \
+ bits = state->bits; \
+ } while (0)
+
+/* Set state from registers for inflate_fast() */
+#define RESTORE() \
+ do { \
+ strm->next_out = put; \
+ strm->avail_out = left; \
+ strm->next_in = next; \
+ strm->avail_in = have; \
+ state->hold = hold; \
+ state->bits = bits; \
+ } while (0)
+
+/* Clear the input bit accumulator */
+#define INITBITS() \
+ do { \
+ hold = 0; \
+ bits = 0; \
+ } while (0)
+
+/* Assure that some input is available. If input is requested, but denied,
+ then return a Z_BUF_ERROR from inflateBack(). */
+#define PULL() \
+ do { \
+ if (have == 0) { \
+ have = in(in_desc, &next); \
+ if (have == 0) { \
+ next = Z_NULL; \
+ ret = Z_BUF_ERROR; \
+ goto inf_leave; \
+ } \
+ } \
+ } while (0)
+
+/* Get a byte of input into the bit accumulator, or return from inflateBack()
+ with an error if there is no input available. */
+#define PULLBYTE() \
+ do { \
+ PULL(); \
+ have--; \
+ hold += (unsigned long)(*next++) << bits; \
+ bits += 8; \
+ } while (0)
+
+/* Assure that there are at least n bits in the bit accumulator. If there is
+ not enough available input to do that, then return from inflateBack() with
+ an error. */
+#define NEEDBITS(n) \
+ do { \
+ while (bits < (unsigned)(n)) \
+ PULLBYTE(); \
+ } while (0)
+
+/* Return the low n bits of the bit accumulator (n < 16) */
+#define BITS(n) \
+ ((unsigned)hold & ((1U << (n)) - 1))
+
+/* Remove n bits from the bit accumulator */
+#define DROPBITS(n) \
+ do { \
+ hold >>= (n); \
+ bits -= (unsigned)(n); \
+ } while (0)
+
+/* Remove zero to seven bits as needed to go to a byte boundary */
+#define BYTEBITS() \
+ do { \
+ hold >>= bits & 7; \
+ bits -= bits & 7; \
+ } while (0)
+
+/* Assure that some output space is available, by writing out the window
+ if it's full. If the write fails, return from inflateBack() with a
+ Z_BUF_ERROR. */
+#define ROOM() \
+ do { \
+ if (left == 0) { \
+ put = state->window; \
+ left = state->wsize; \
+ state->whave = left; \
+ if (out(out_desc, put, left)) { \
+ ret = Z_BUF_ERROR; \
+ goto inf_leave; \
+ } \
+ } \
+ } while (0)
+
+/*
+ strm provides the memory allocation functions and window buffer on input,
+ and provides information on the unused input on return. For Z_DATA_ERROR
+ returns, strm will also provide an error message.
+
+ in() and out() are the call-back input and output functions. When
+ inflateBack() needs more input, it calls in(). When inflateBack() has
+ filled the window with output, or when it completes with data in the
+ window, it calls out() to write out the data. The application must not
+ change the provided input until in() is called again or inflateBack()
+ returns. The application must not change the window/output buffer until
+ inflateBack() returns.
+
+ in() and out() are called with a descriptor parameter provided in the
+ inflateBack() call. This parameter can be a structure that provides the
+ information required to do the read or write, as well as accumulated
+ information on the input and output such as totals and check values.
+
+ in() should return zero on failure. out() should return non-zero on
+ failure. If either in() or out() fails, than inflateBack() returns a
+ Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it
+ was in() or out() that caused in the error. Otherwise, inflateBack()
+ returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format
+ error, or Z_MEM_ERROR if it could not allocate memory for the state.
+ inflateBack() can also return Z_STREAM_ERROR if the input parameters
+ are not correct, i.e. strm is Z_NULL or the state was not initialized.
+ */
+int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc)
+z_streamp strm;
+in_func in;
+void FAR *in_desc;
+out_func out;
+void FAR *out_desc;
+{
+ struct inflate_state FAR *state;
+ unsigned char FAR *next; /* next input */
+ unsigned char FAR *put; /* next output */
+ unsigned have, left; /* available input and output */
+ unsigned long hold; /* bit buffer */
+ unsigned bits; /* bits in bit buffer */
+ unsigned copy; /* number of stored or match bytes to copy */
+ unsigned char FAR *from; /* where to copy match bytes from */
+ code this; /* current decoding table entry */
+ code last; /* parent table entry */
+ unsigned len; /* length to copy for repeats, bits to drop */
+ int ret; /* return code */
+ static const unsigned short order[19] = /* permutation of code lengths */
+ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+ /* Check that the strm exists and that the state was initialized */
+ if (strm == Z_NULL || strm->state == Z_NULL)
+ return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+
+ /* Reset the state */
+ strm->msg = Z_NULL;
+ state->mode = TYPE;
+ state->last = 0;
+ state->whave = 0;
+ next = strm->next_in;
+ have = next != Z_NULL ? strm->avail_in : 0;
+ hold = 0;
+ bits = 0;
+ put = state->window;
+ left = state->wsize;
+
+ /* Inflate until end of block marked as last */
+ for (;;)
+ switch (state->mode) {
+ case TYPE:
+ /* determine and dispatch block type */
+ if (state->last) {
+ BYTEBITS();
+ state->mode = DONE;
+ break;
+ }
+ NEEDBITS(3);
+ state->last = BITS(1);
+ DROPBITS(1);
+ switch (BITS(2)) {
+ case 0: /* stored block */
+ Tracev((stderr, "inflate: stored block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = STORED;
+ break;
+ case 1: /* fixed block */
+ fixedtables(state);
+ Tracev((stderr, "inflate: fixed codes block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = LEN; /* decode codes */
+ break;
+ case 2: /* dynamic block */
+ Tracev((stderr, "inflate: dynamic codes block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = TABLE;
+ break;
+ case 3:
+ strm->msg = (char *)"invalid block type";
+ state->mode = BAD;
+ }
+ DROPBITS(2);
+ break;
+
+ case STORED:
+ /* get and verify stored block length */
+ BYTEBITS(); /* go to byte boundary */
+ NEEDBITS(32);
+ if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
+ strm->msg = (char *)"invalid stored block lengths";
+ state->mode = BAD;
+ break;
+ }
+ state->length = (unsigned)hold & 0xffff;
+ Tracev((stderr, "inflate: stored length %u\n",
+ state->length));
+ INITBITS();
+
+ /* copy stored block from input to output */
+ while (state->length != 0) {
+ copy = state->length;
+ PULL();
+ ROOM();
+ if (copy > have) copy = have;
+ if (copy > left) copy = left;
+ zmemcpy(put, next, copy);
+ have -= copy;
+ next += copy;
+ left -= copy;
+ put += copy;
+ state->length -= copy;
+ }
+ Tracev((stderr, "inflate: stored end\n"));
+ state->mode = TYPE;
+ break;
+
+ case TABLE:
+ /* get dynamic table entries descriptor */
+ NEEDBITS(14);
+ state->nlen = BITS(5) + 257;
+ DROPBITS(5);
+ state->ndist = BITS(5) + 1;
+ DROPBITS(5);
+ state->ncode = BITS(4) + 4;
+ DROPBITS(4);
+#ifndef PKZIP_BUG_WORKAROUND
+ if (state->nlen > 286 || state->ndist > 30) {
+ strm->msg = (char *)"too many length or distance symbols";
+ state->mode = BAD;
+ break;
+ }
+#endif
+ Tracev((stderr, "inflate: table sizes ok\n"));
+
+ /* get code length code lengths (not a typo) */
+ state->have = 0;
+ while (state->have < state->ncode) {
+ NEEDBITS(3);
+ state->lens[order[state->have++]] = (unsigned short)BITS(3);
+ DROPBITS(3);
+ }
+ while (state->have < 19)
+ state->lens[order[state->have++]] = 0;
+ state->next = state->codes;
+ state->lencode = (code const FAR *)(state->next);
+ state->lenbits = 7;
+ ret = inflate_table(CODES, state->lens, 19, &(state->next),
+ &(state->lenbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid code lengths set";
+ state->mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: code lengths ok\n"));
+
+ /* get length and distance code code lengths */
+ state->have = 0;
+ while (state->have < state->nlen + state->ndist) {
+ for (;;) {
+ this = state->lencode[BITS(state->lenbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if (this.val < 16) {
+ NEEDBITS(this.bits);
+ DROPBITS(this.bits);
+ state->lens[state->have++] = this.val;
+ }
+ else {
+ if (this.val == 16) {
+ NEEDBITS(this.bits + 2);
+ DROPBITS(this.bits);
+ if (state->have == 0) {
+ strm->msg = (char *)"invalid bit length repeat";
+ state->mode = BAD;
+ break;
+ }
+ len = (unsigned)(state->lens[state->have - 1]);
+ copy = 3 + BITS(2);
+ DROPBITS(2);
+ }
+ else if (this.val == 17) {
+ NEEDBITS(this.bits + 3);
+ DROPBITS(this.bits);
+ len = 0;
+ copy = 3 + BITS(3);
+ DROPBITS(3);
+ }
+ else {
+ NEEDBITS(this.bits + 7);
+ DROPBITS(this.bits);
+ len = 0;
+ copy = 11 + BITS(7);
+ DROPBITS(7);
+ }
+ if (state->have + copy > state->nlen + state->ndist) {
+ strm->msg = (char *)"invalid bit length repeat";
+ state->mode = BAD;
+ break;
+ }
+ while (copy--)
+ state->lens[state->have++] = (unsigned short)len;
+ }
+ }
+
+ /* handle error breaks in while */
+ if (state->mode == BAD) break;
+
+ /* build code tables */
+ state->next = state->codes;
+ state->lencode = (code const FAR *)(state->next);
+ state->lenbits = 9;
+ ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
+ &(state->lenbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid literal/lengths set";
+ state->mode = BAD;
+ break;
+ }
+ state->distcode = (code const FAR *)(state->next);
+ state->distbits = 6;
+ ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
+ &(state->next), &(state->distbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid distances set";
+ state->mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: codes ok\n"));
+ state->mode = LEN;
+
+ case LEN:
+ /* use inflate_fast() if we have enough input and output */
+ if (have >= 6 && left >= 258) {
+ RESTORE();
+ if (state->whave < state->wsize)
+ state->whave = state->wsize - left;
+ inflate_fast(strm, state->wsize);
+ LOAD();
+ break;
+ }
+
+ /* get a literal, length, or end-of-block code */
+ for (;;) {
+ this = state->lencode[BITS(state->lenbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if (this.op && (this.op & 0xf0) == 0) {
+ last = this;
+ for (;;) {
+ this = state->lencode[last.val +
+ (BITS(last.bits + last.op) >> last.bits)];
+ if ((unsigned)(last.bits + this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ DROPBITS(last.bits);
+ }
+ DROPBITS(this.bits);
+ state->length = (unsigned)this.val;
+
+ /* process literal */
+ if (this.op == 0) {
+ Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ?
+ "inflate: literal '%c'\n" :
+ "inflate: literal 0x%02x\n", this.val));
+ ROOM();
+ *put++ = (unsigned char)(state->length);
+ left--;
+ state->mode = LEN;
+ break;
+ }
+
+ /* process end of block */
+ if (this.op & 32) {
+ Tracevv((stderr, "inflate: end of block\n"));
+ state->mode = TYPE;
+ break;
+ }
+
+ /* invalid code */
+ if (this.op & 64) {
+ strm->msg = (char *)"invalid literal/length code";
+ state->mode = BAD;
+ break;
+ }
+
+ /* length code -- get extra bits, if any */
+ state->extra = (unsigned)(this.op) & 15;
+ if (state->extra != 0) {
+ NEEDBITS(state->extra);
+ state->length += BITS(state->extra);
+ DROPBITS(state->extra);
+ }
+ Tracevv((stderr, "inflate: length %u\n", state->length));
+
+ /* get distance code */
+ for (;;) {
+ this = state->distcode[BITS(state->distbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if ((this.op & 0xf0) == 0) {
+ last = this;
+ for (;;) {
+ this = state->distcode[last.val +
+ (BITS(last.bits + last.op) >> last.bits)];
+ if ((unsigned)(last.bits + this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ DROPBITS(last.bits);
+ }
+ DROPBITS(this.bits);
+ if (this.op & 64) {
+ strm->msg = (char *)"invalid distance code";
+ state->mode = BAD;
+ break;
+ }
+ state->offset = (unsigned)this.val;
+
+ /* get distance extra bits, if any */
+ state->extra = (unsigned)(this.op) & 15;
+ if (state->extra != 0) {
+ NEEDBITS(state->extra);
+ state->offset += BITS(state->extra);
+ DROPBITS(state->extra);
+ }
+ if (state->offset > state->wsize - (state->whave < state->wsize ?
+ left : 0)) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+ Tracevv((stderr, "inflate: distance %u\n", state->offset));
+
+ /* copy match from window to output */
+ do {
+ ROOM();
+ copy = state->wsize - state->offset;
+ if (copy < left) {
+ from = put + copy;
+ copy = left - copy;
+ }
+ else {
+ from = put - state->offset;
+ copy = left;
+ }
+ if (copy > state->length) copy = state->length;
+ state->length -= copy;
+ left -= copy;
+ do {
+ *put++ = *from++;
+ } while (--copy);
+ } while (state->length != 0);
+ break;
+
+ case DONE:
+ /* inflate stream terminated properly -- write leftover output */
+ ret = Z_STREAM_END;
+ if (left < state->wsize) {
+ if (out(out_desc, state->window, state->wsize - left))
+ ret = Z_BUF_ERROR;
+ }
+ goto inf_leave;
+
+ case BAD:
+ ret = Z_DATA_ERROR;
+ goto inf_leave;
+
+ default: /* can't happen, but makes compilers happy */
+ ret = Z_STREAM_ERROR;
+ goto inf_leave;
+ }
+
+ /* Return unused input */
+ inf_leave:
+ strm->next_in = next;
+ strm->avail_in = have;
+ return ret;
+}
+
+int ZEXPORT inflateBackEnd(strm)
+z_streamp strm;
+{
+ if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
+ return Z_STREAM_ERROR;
+ ZFREE(strm, strm->state);
+ strm->state = Z_NULL;
+ Tracev((stderr, "inflate: end\n"));
+ return Z_OK;
+}
diff --git a/lib/libz/inffast.c b/lib/libz/inffast.c
new file mode 100644
index 0000000..bbee92e
--- /dev/null
+++ b/lib/libz/inffast.c
@@ -0,0 +1,318 @@
+/* inffast.c -- fast decoding
+ * Copyright (C) 1995-2004 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+#ifndef ASMINF
+
+/* Allow machine dependent optimization for post-increment or pre-increment.
+ Based on testing to date,
+ Pre-increment preferred for:
+ - PowerPC G3 (Adler)
+ - MIPS R5000 (Randers-Pehrson)
+ Post-increment preferred for:
+ - none
+ No measurable difference:
+ - Pentium III (Anderson)
+ - M68060 (Nikl)
+ */
+#ifdef POSTINC
+# define OFF 0
+# define PUP(a) *(a)++
+#else
+# define OFF 1
+# define PUP(a) *++(a)
+#endif
+
+/*
+ Decode literal, length, and distance codes and write out the resulting
+ literal and match bytes until either not enough input or output is
+ available, an end-of-block is encountered, or a data error is encountered.
+ When large enough input and output buffers are supplied to inflate(), for
+ example, a 16K input buffer and a 64K output buffer, more than 95% of the
+ inflate execution time is spent in this routine.
+
+ Entry assumptions:
+
+ state->mode == LEN
+ strm->avail_in >= 6
+ strm->avail_out >= 258
+ start >= strm->avail_out
+ state->bits < 8
+
+ On return, state->mode is one of:
+
+ LEN -- ran out of enough output space or enough available input
+ TYPE -- reached end of block code, inflate() to interpret next block
+ BAD -- error in block data
+
+ Notes:
+
+ - The maximum input bits used by a length/distance pair is 15 bits for the
+ length code, 5 bits for the length extra, 15 bits for the distance code,
+ and 13 bits for the distance extra. This totals 48 bits, or six bytes.
+ Therefore if strm->avail_in >= 6, then there is enough input to avoid
+ checking for available input while decoding.
+
+ - The maximum bytes that a single length/distance pair can output is 258
+ bytes, which is the maximum length that can be coded. inflate_fast()
+ requires strm->avail_out >= 258 for each loop to avoid checking for
+ output space.
+ */
+void inflate_fast(strm, start)
+z_streamp strm;
+unsigned start; /* inflate()'s starting value for strm->avail_out */
+{
+ struct inflate_state FAR *state;
+ unsigned char FAR *in; /* local strm->next_in */
+ unsigned char FAR *last; /* while in < last, enough input available */
+ unsigned char FAR *out; /* local strm->next_out */
+ unsigned char FAR *beg; /* inflate()'s initial strm->next_out */
+ unsigned char FAR *end; /* while out < end, enough space available */
+#ifdef INFLATE_STRICT
+ unsigned dmax; /* maximum distance from zlib header */
+#endif
+ unsigned wsize; /* window size or zero if not using window */
+ unsigned whave; /* valid bytes in the window */
+ unsigned write; /* window write index */
+ unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */
+ unsigned long hold; /* local strm->hold */
+ unsigned bits; /* local strm->bits */
+ code const FAR *lcode; /* local strm->lencode */
+ code const FAR *dcode; /* local strm->distcode */
+ unsigned lmask; /* mask for first level of length codes */
+ unsigned dmask; /* mask for first level of distance codes */
+ code this; /* retrieved table entry */
+ unsigned op; /* code bits, operation, extra bits, or */
+ /* window position, window bytes to copy */
+ unsigned len; /* match length, unused bytes */
+ unsigned dist; /* match distance */
+ unsigned char FAR *from; /* where to copy match from */
+
+ /* copy state to local variables */
+ state = (struct inflate_state FAR *)strm->state;
+ in = strm->next_in - OFF;
+ last = in + (strm->avail_in - 5);
+ out = strm->next_out - OFF;
+ beg = out - (start - strm->avail_out);
+ end = out + (strm->avail_out - 257);
+#ifdef INFLATE_STRICT
+ dmax = state->dmax;
+#endif
+ wsize = state->wsize;
+ whave = state->whave;
+ write = state->write;
+ window = state->window;
+ hold = state->hold;
+ bits = state->bits;
+ lcode = state->lencode;
+ dcode = state->distcode;
+ lmask = (1U << state->lenbits) - 1;
+ dmask = (1U << state->distbits) - 1;
+
+ /* decode literals and length/distances until end-of-block or not enough
+ input data or output space */
+ do {
+ if (bits < 15) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ this = lcode[hold & lmask];
+ dolen:
+ op = (unsigned)(this.bits);
+ hold >>= op;
+ bits -= op;
+ op = (unsigned)(this.op);
+ if (op == 0) { /* literal */
+ Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ?
+ "inflate: literal '%c'\n" :
+ "inflate: literal 0x%02x\n", this.val));
+ PUP(out) = (unsigned char)(this.val);
+ }
+ else if (op & 16) { /* length base */
+ len = (unsigned)(this.val);
+ op &= 15; /* number of extra bits */
+ if (op) {
+ if (bits < op) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ len += (unsigned)hold & ((1U << op) - 1);
+ hold >>= op;
+ bits -= op;
+ }
+ Tracevv((stderr, "inflate: length %u\n", len));
+ if (bits < 15) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ this = dcode[hold & dmask];
+ dodist:
+ op = (unsigned)(this.bits);
+ hold >>= op;
+ bits -= op;
+ op = (unsigned)(this.op);
+ if (op & 16) { /* distance base */
+ dist = (unsigned)(this.val);
+ op &= 15; /* number of extra bits */
+ if (bits < op) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ if (bits < op) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ }
+ dist += (unsigned)hold & ((1U << op) - 1);
+#ifdef INFLATE_STRICT
+ if (dist > dmax) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+#endif
+ hold >>= op;
+ bits -= op;
+ Tracevv((stderr, "inflate: distance %u\n", dist));
+ op = (unsigned)(out - beg); /* max distance in output */
+ if (dist > op) { /* see if copy from window */
+ op = dist - op; /* distance back in window */
+ if (op > whave) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+ from = window - OFF;
+ if (write == 0) { /* very common case */
+ from += wsize - op;
+ if (op < len) { /* some from window */
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = out - dist; /* rest from output */
+ }
+ }
+ else if (write < op) { /* wrap around window */
+ from += wsize + write - op;
+ op -= write;
+ if (op < len) { /* some from end of window */
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = window - OFF;
+ if (write < len) { /* some from start of window */
+ op = write;
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = out - dist; /* rest from output */
+ }
+ }
+ }
+ else { /* contiguous in window */
+ from += write - op;
+ if (op < len) { /* some from window */
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = out - dist; /* rest from output */
+ }
+ }
+ while (len > 2) {
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ len -= 3;
+ }
+ if (len) {
+ PUP(out) = PUP(from);
+ if (len > 1)
+ PUP(out) = PUP(from);
+ }
+ }
+ else {
+ from = out - dist; /* copy direct from output */
+ do { /* minimum length is three */
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ len -= 3;
+ } while (len > 2);
+ if (len) {
+ PUP(out) = PUP(from);
+ if (len > 1)
+ PUP(out) = PUP(from);
+ }
+ }
+ }
+ else if ((op & 64) == 0) { /* 2nd level distance code */
+ this = dcode[this.val + (hold & ((1U << op) - 1))];
+ goto dodist;
+ }
+ else {
+ strm->msg = (char *)"invalid distance code";
+ state->mode = BAD;
+ break;
+ }
+ }
+ else if ((op & 64) == 0) { /* 2nd level length code */
+ this = lcode[this.val + (hold & ((1U << op) - 1))];
+ goto dolen;
+ }
+ else if (op & 32) { /* end-of-block */
+ Tracevv((stderr, "inflate: end of block\n"));
+ state->mode = TYPE;
+ break;
+ }
+ else {
+ strm->msg = (char *)"invalid literal/length code";
+ state->mode = BAD;
+ break;
+ }
+ } while (in < last && out < end);
+
+ /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
+ len = bits >> 3;
+ in -= len;
+ bits -= len << 3;
+ hold &= (1U << bits) - 1;
+
+ /* update state and return */
+ strm->next_in = in + OFF;
+ strm->next_out = out + OFF;
+ strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));
+ strm->avail_out = (unsigned)(out < end ?
+ 257 + (end - out) : 257 - (out - end));
+ state->hold = hold;
+ state->bits = bits;
+ return;
+}
+
+/*
+ inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe):
+ - Using bit fields for code structure
+ - Different op definition to avoid & for extra bits (do & for table bits)
+ - Three separate decoding do-loops for direct, window, and write == 0
+ - Special case for distance > 1 copies to do overlapped load and store copy
+ - Explicit branch predictions (based on measured branch probabilities)
+ - Deferring match copy and interspersed it with decoding subsequent codes
+ - Swapping literal/length else
+ - Swapping window/direct else
+ - Larger unrolled copy loops (three is about right)
+ - Moving len -= 3 statement into middle of loop
+ */
+
+#endif /* !ASMINF */
diff --git a/lib/libz/inffast.h b/lib/libz/inffast.h
new file mode 100644
index 0000000..1e88d2d
--- /dev/null
+++ b/lib/libz/inffast.h
@@ -0,0 +1,11 @@
+/* inffast.h -- header to use inffast.c
+ * Copyright (C) 1995-2003 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+void inflate_fast OF((z_streamp strm, unsigned start));
diff --git a/lib/libz/inffixed.h b/lib/libz/inffixed.h
new file mode 100644
index 0000000..75ed4b5
--- /dev/null
+++ b/lib/libz/inffixed.h
@@ -0,0 +1,94 @@
+ /* inffixed.h -- table for decoding fixed codes
+ * Generated automatically by makefixed().
+ */
+
+ /* WARNING: this file should *not* be used by applications. It
+ is part of the implementation of the compression library and
+ is subject to change. Applications should only use zlib.h.
+ */
+
+ static const code lenfix[512] = {
+ {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48},
+ {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128},
+ {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59},
+ {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176},
+ {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20},
+ {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100},
+ {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8},
+ {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216},
+ {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76},
+ {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114},
+ {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2},
+ {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148},
+ {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42},
+ {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86},
+ {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15},
+ {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236},
+ {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62},
+ {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142},
+ {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31},
+ {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162},
+ {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25},
+ {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105},
+ {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4},
+ {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202},
+ {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69},
+ {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125},
+ {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13},
+ {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195},
+ {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35},
+ {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91},
+ {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19},
+ {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246},
+ {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55},
+ {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135},
+ {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99},
+ {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190},
+ {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16},
+ {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96},
+ {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6},
+ {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209},
+ {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72},
+ {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116},
+ {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4},
+ {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153},
+ {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44},
+ {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82},
+ {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11},
+ {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229},
+ {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58},
+ {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138},
+ {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51},
+ {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173},
+ {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30},
+ {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110},
+ {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0},
+ {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195},
+ {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65},
+ {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121},
+ {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9},
+ {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258},
+ {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37},
+ {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93},
+ {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23},
+ {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251},
+ {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51},
+ {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131},
+ {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67},
+ {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183},
+ {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23},
+ {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103},
+ {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9},
+ {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223},
+ {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79},
+ {0,9,255}
+ };
+
+ static const code distfix[32] = {
+ {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025},
+ {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193},
+ {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385},
+ {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577},
+ {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073},
+ {22,5,193},{64,5,0}
+ };
diff --git a/lib/libz/inflate.c b/lib/libz/inflate.c
new file mode 100644
index 0000000..792fdee
--- /dev/null
+++ b/lib/libz/inflate.c
@@ -0,0 +1,1368 @@
+/* inflate.c -- zlib decompression
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * Change history:
+ *
+ * 1.2.beta0 24 Nov 2002
+ * - First version -- complete rewrite of inflate to simplify code, avoid
+ * creation of window when not needed, minimize use of window when it is
+ * needed, make inffast.c even faster, implement gzip decoding, and to
+ * improve code readability and style over the previous zlib inflate code
+ *
+ * 1.2.beta1 25 Nov 2002
+ * - Use pointers for available input and output checking in inffast.c
+ * - Remove input and output counters in inffast.c
+ * - Change inffast.c entry and loop from avail_in >= 7 to >= 6
+ * - Remove unnecessary second byte pull from length extra in inffast.c
+ * - Unroll direct copy to three copies per loop in inffast.c
+ *
+ * 1.2.beta2 4 Dec 2002
+ * - Change external routine names to reduce potential conflicts
+ * - Correct filename to inffixed.h for fixed tables in inflate.c
+ * - Make hbuf[] unsigned char to match parameter type in inflate.c
+ * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset)
+ * to avoid negation problem on Alphas (64 bit) in inflate.c
+ *
+ * 1.2.beta3 22 Dec 2002
+ * - Add comments on state->bits assertion in inffast.c
+ * - Add comments on op field in inftrees.h
+ * - Fix bug in reuse of allocated window after inflateReset()
+ * - Remove bit fields--back to byte structure for speed
+ * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths
+ * - Change post-increments to pre-increments in inflate_fast(), PPC biased?
+ * - Add compile time option, POSTINC, to use post-increments instead (Intel?)
+ * - Make MATCH copy in inflate() much faster for when inflate_fast() not used
+ * - Use local copies of stream next and avail values, as well as local bit
+ * buffer and bit count in inflate()--for speed when inflate_fast() not used
+ *
+ * 1.2.beta4 1 Jan 2003
+ * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings
+ * - Move a comment on output buffer sizes from inffast.c to inflate.c
+ * - Add comments in inffast.c to introduce the inflate_fast() routine
+ * - Rearrange window copies in inflate_fast() for speed and simplification
+ * - Unroll last copy for window match in inflate_fast()
+ * - Use local copies of window variables in inflate_fast() for speed
+ * - Pull out common write == 0 case for speed in inflate_fast()
+ * - Make op and len in inflate_fast() unsigned for consistency
+ * - Add FAR to lcode and dcode declarations in inflate_fast()
+ * - Simplified bad distance check in inflate_fast()
+ * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new
+ * source file infback.c to provide a call-back interface to inflate for
+ * programs like gzip and unzip -- uses window as output buffer to avoid
+ * window copying
+ *
+ * 1.2.beta5 1 Jan 2003
+ * - Improved inflateBack() interface to allow the caller to provide initial
+ * input in strm.
+ * - Fixed stored blocks bug in inflateBack()
+ *
+ * 1.2.beta6 4 Jan 2003
+ * - Added comments in inffast.c on effectiveness of POSTINC
+ * - Typecasting all around to reduce compiler warnings
+ * - Changed loops from while (1) or do {} while (1) to for (;;), again to
+ * make compilers happy
+ * - Changed type of window in inflateBackInit() to unsigned char *
+ *
+ * 1.2.beta7 27 Jan 2003
+ * - Changed many types to unsigned or unsigned short to avoid warnings
+ * - Added inflateCopy() function
+ *
+ * 1.2.0 9 Mar 2003
+ * - Changed inflateBack() interface to provide separate opaque descriptors
+ * for the in() and out() functions
+ * - Changed inflateBack() argument and in_func typedef to swap the length
+ * and buffer address return values for the input function
+ * - Check next_in and next_out for Z_NULL on entry to inflate()
+ *
+ * The history for versions after 1.2.0 are in ChangeLog in zlib distribution.
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+#ifdef MAKEFIXED
+# ifndef BUILDFIXED
+# define BUILDFIXED
+# endif
+#endif
+
+/* function prototypes */
+local void fixedtables OF((struct inflate_state FAR *state));
+local int updatewindow OF((z_streamp strm, unsigned out));
+#ifdef BUILDFIXED
+ void makefixed OF((void));
+#endif
+local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf,
+ unsigned len));
+
+int ZEXPORT inflateReset(strm)
+z_streamp strm;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ strm->total_in = strm->total_out = state->total = 0;
+ strm->msg = Z_NULL;
+ strm->adler = 1; /* to support ill-conceived Java test suite */
+ state->mode = HEAD;
+ state->last = 0;
+ state->havedict = 0;
+ state->dmax = 32768U;
+ state->head = Z_NULL;
+ state->wsize = 0;
+ state->whave = 0;
+ state->write = 0;
+ state->hold = 0;
+ state->bits = 0;
+ state->lencode = state->distcode = state->next = state->codes;
+ Tracev((stderr, "inflate: reset\n"));
+ return Z_OK;
+}
+
+int ZEXPORT inflatePrime(strm, bits, value)
+z_streamp strm;
+int bits;
+int value;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR;
+ value &= (1L << bits) - 1;
+ state->hold += value << state->bits;
+ state->bits += bits;
+ return Z_OK;
+}
+
+int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size)
+z_streamp strm;
+int windowBits;
+const char *version;
+int stream_size;
+{
+ struct inflate_state FAR *state;
+
+ if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+ stream_size != (int)(sizeof(z_stream)))
+ return Z_VERSION_ERROR;
+ if (strm == Z_NULL) return Z_STREAM_ERROR;
+ strm->msg = Z_NULL; /* in case we return an error */
+ if (strm->zalloc == (alloc_func)0) {
+ strm->zalloc = zcalloc;
+ strm->opaque = (voidpf)0;
+ }
+ if (strm->zfree == (free_func)0) strm->zfree = zcfree;
+ state = (struct inflate_state FAR *)
+ ZALLOC(strm, 1, sizeof(struct inflate_state));
+ if (state == Z_NULL) return Z_MEM_ERROR;
+ Tracev((stderr, "inflate: allocated\n"));
+ strm->state = (struct internal_state FAR *)state;
+ if (windowBits < 0) {
+ state->wrap = 0;
+ windowBits = -windowBits;
+ }
+ else {
+ state->wrap = (windowBits >> 4) + 1;
+#ifdef GUNZIP
+ if (windowBits < 48) windowBits &= 15;
+#endif
+ }
+ if (windowBits < 8 || windowBits > 15) {
+ ZFREE(strm, state);
+ strm->state = Z_NULL;
+ return Z_STREAM_ERROR;
+ }
+ state->wbits = (unsigned)windowBits;
+ state->window = Z_NULL;
+ return inflateReset(strm);
+}
+
+int ZEXPORT inflateInit_(strm, version, stream_size)
+z_streamp strm;
+const char *version;
+int stream_size;
+{
+ return inflateInit2_(strm, DEF_WBITS, version, stream_size);
+}
+
+/*
+ Return state with length and distance decoding tables and index sizes set to
+ fixed code decoding. Normally this returns fixed tables from inffixed.h.
+ If BUILDFIXED is defined, then instead this routine builds the tables the
+ first time it's called, and returns those tables the first time and
+ thereafter. This reduces the size of the code by about 2K bytes, in
+ exchange for a little execution time. However, BUILDFIXED should not be
+ used for threaded applications, since the rewriting of the tables and virgin
+ may not be thread-safe.
+ */
+local void fixedtables(state)
+struct inflate_state FAR *state;
+{
+#ifdef BUILDFIXED
+ static int virgin = 1;
+ static code *lenfix, *distfix;
+ static code fixed[544];
+
+ /* build fixed huffman tables if first call (may not be thread safe) */
+ if (virgin) {
+ unsigned sym, bits;
+ static code *next;
+
+ /* literal/length table */
+ sym = 0;
+ while (sym < 144) state->lens[sym++] = 8;
+ while (sym < 256) state->lens[sym++] = 9;
+ while (sym < 280) state->lens[sym++] = 7;
+ while (sym < 288) state->lens[sym++] = 8;
+ next = fixed;
+ lenfix = next;
+ bits = 9;
+ inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);
+
+ /* distance table */
+ sym = 0;
+ while (sym < 32) state->lens[sym++] = 5;
+ distfix = next;
+ bits = 5;
+ inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);
+
+ /* do this just once */
+ virgin = 0;
+ }
+#else /* !BUILDFIXED */
+# include "inffixed.h"
+#endif /* BUILDFIXED */
+ state->lencode = lenfix;
+ state->lenbits = 9;
+ state->distcode = distfix;
+ state->distbits = 5;
+}
+
+#ifdef MAKEFIXED
+#include <stdio.h>
+
+/*
+ Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also
+ defines BUILDFIXED, so the tables are built on the fly. makefixed() writes
+ those tables to stdout, which would be piped to inffixed.h. A small program
+ can simply call makefixed to do this:
+
+ void makefixed(void);
+
+ int main(void)
+ {
+ makefixed();
+ return 0;
+ }
+
+ Then that can be linked with zlib built with MAKEFIXED defined and run:
+
+ a.out > inffixed.h
+ */
+void makefixed()
+{
+ unsigned low, size;
+ struct inflate_state state;
+
+ fixedtables(&state);
+ puts(" /* inffixed.h -- table for decoding fixed codes");
+ puts(" * Generated automatically by makefixed().");
+ puts(" */");
+ puts("");
+ puts(" /* WARNING: this file should *not* be used by applications.");
+ puts(" It is part of the implementation of this library and is");
+ puts(" subject to change. Applications should only use zlib.h.");
+ puts(" */");
+ puts("");
+ size = 1U << 9;
+ printf(" static const code lenfix[%u] = {", size);
+ low = 0;
+ for (;;) {
+ if ((low % 7) == 0) printf("\n ");
+ printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits,
+ state.lencode[low].val);
+ if (++low == size) break;
+ putchar(',');
+ }
+ puts("\n };");
+ size = 1U << 5;
+ printf("\n static const code distfix[%u] = {", size);
+ low = 0;
+ for (;;) {
+ if ((low % 6) == 0) printf("\n ");
+ printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits,
+ state.distcode[low].val);
+ if (++low == size) break;
+ putchar(',');
+ }
+ puts("\n };");
+}
+#endif /* MAKEFIXED */
+
+/*
+ Update the window with the last wsize (normally 32K) bytes written before
+ returning. If window does not exist yet, create it. This is only called
+ when a window is already in use, or when output has been written during this
+ inflate call, but the end of the deflate stream has not been reached yet.
+ It is also called to create a window for dictionary data when a dictionary
+ is loaded.
+
+ Providing output buffers larger than 32K to inflate() should provide a speed
+ advantage, since only the last 32K of output is copied to the sliding window
+ upon return from inflate(), and since all distances after the first 32K of
+ output will fall in the output data, making match copies simpler and faster.
+ The advantage may be dependent on the size of the processor's data caches.
+ */
+local int updatewindow(strm, out)
+z_streamp strm;
+unsigned out;
+{
+ struct inflate_state FAR *state;
+ unsigned copy, dist;
+
+ state = (struct inflate_state FAR *)strm->state;
+
+ /* if it hasn't been done already, allocate space for the window */
+ if (state->window == Z_NULL) {
+ state->window = (unsigned char FAR *)
+ ZALLOC(strm, 1U << state->wbits,
+ sizeof(unsigned char));
+ if (state->window == Z_NULL) return 1;
+ }
+
+ /* if window not in use yet, initialize */
+ if (state->wsize == 0) {
+ state->wsize = 1U << state->wbits;
+ state->write = 0;
+ state->whave = 0;
+ }
+
+ /* copy state->wsize or less output bytes into the circular window */
+ copy = out - strm->avail_out;
+ if (copy >= state->wsize) {
+ zmemcpy(state->window, strm->next_out - state->wsize, state->wsize);
+ state->write = 0;
+ state->whave = state->wsize;
+ }
+ else {
+ dist = state->wsize - state->write;
+ if (dist > copy) dist = copy;
+ zmemcpy(state->window + state->write, strm->next_out - copy, dist);
+ copy -= dist;
+ if (copy) {
+ zmemcpy(state->window, strm->next_out - copy, copy);
+ state->write = copy;
+ state->whave = state->wsize;
+ }
+ else {
+ state->write += dist;
+ if (state->write == state->wsize) state->write = 0;
+ if (state->whave < state->wsize) state->whave += dist;
+ }
+ }
+ return 0;
+}
+
+/* Macros for inflate(): */
+
+/* check function to use adler32() for zlib or crc32() for gzip */
+#ifdef GUNZIP
+# define UPDATE(check, buf, len) \
+ (state->flags ? crc32(check, buf, len) : adler32(check, buf, len))
+#else
+# define UPDATE(check, buf, len) adler32(check, buf, len)
+#endif
+
+/* check macros for header crc */
+#ifdef GUNZIP
+# define CRC2(check, word) \
+ do { \
+ hbuf[0] = (unsigned char)(word); \
+ hbuf[1] = (unsigned char)((word) >> 8); \
+ check = crc32(check, hbuf, 2); \
+ } while (0)
+
+# define CRC4(check, word) \
+ do { \
+ hbuf[0] = (unsigned char)(word); \
+ hbuf[1] = (unsigned char)((word) >> 8); \
+ hbuf[2] = (unsigned char)((word) >> 16); \
+ hbuf[3] = (unsigned char)((word) >> 24); \
+ check = crc32(check, hbuf, 4); \
+ } while (0)
+#endif
+
+/* Load registers with state in inflate() for speed */
+#define LOAD() \
+ do { \
+ put = strm->next_out; \
+ left = strm->avail_out; \
+ next = strm->next_in; \
+ have = strm->avail_in; \
+ hold = state->hold; \
+ bits = state->bits; \
+ } while (0)
+
+/* Restore state from registers in inflate() */
+#define RESTORE() \
+ do { \
+ strm->next_out = put; \
+ strm->avail_out = left; \
+ strm->next_in = next; \
+ strm->avail_in = have; \
+ state->hold = hold; \
+ state->bits = bits; \
+ } while (0)
+
+/* Clear the input bit accumulator */
+#define INITBITS() \
+ do { \
+ hold = 0; \
+ bits = 0; \
+ } while (0)
+
+/* Get a byte of input into the bit accumulator, or return from inflate()
+ if there is no input available. */
+#define PULLBYTE() \
+ do { \
+ if (have == 0) goto inf_leave; \
+ have--; \
+ hold += (unsigned long)(*next++) << bits; \
+ bits += 8; \
+ } while (0)
+
+/* Assure that there are at least n bits in the bit accumulator. If there is
+ not enough available input to do that, then return from inflate(). */
+#define NEEDBITS(n) \
+ do { \
+ while (bits < (unsigned)(n)) \
+ PULLBYTE(); \
+ } while (0)
+
+/* Return the low n bits of the bit accumulator (n < 16) */
+#define BITS(n) \
+ ((unsigned)hold & ((1U << (n)) - 1))
+
+/* Remove n bits from the bit accumulator */
+#define DROPBITS(n) \
+ do { \
+ hold >>= (n); \
+ bits -= (unsigned)(n); \
+ } while (0)
+
+/* Remove zero to seven bits as needed to go to a byte boundary */
+#define BYTEBITS() \
+ do { \
+ hold >>= bits & 7; \
+ bits -= bits & 7; \
+ } while (0)
+
+/* Reverse the bytes in a 32-bit value */
+#define REVERSE(q) \
+ ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \
+ (((q) & 0xff00) << 8) + (((q) & 0xff) << 24))
+
+/*
+ inflate() uses a state machine to process as much input data and generate as
+ much output data as possible before returning. The state machine is
+ structured roughly as follows:
+
+ for (;;) switch (state) {
+ ...
+ case STATEn:
+ if (not enough input data or output space to make progress)
+ return;
+ ... make progress ...
+ state = STATEm;
+ break;
+ ...
+ }
+
+ so when inflate() is called again, the same case is attempted again, and
+ if the appropriate resources are provided, the machine proceeds to the
+ next state. The NEEDBITS() macro is usually the way the state evaluates
+ whether it can proceed or should return. NEEDBITS() does the return if
+ the requested bits are not available. The typical use of the BITS macros
+ is:
+
+ NEEDBITS(n);
+ ... do something with BITS(n) ...
+ DROPBITS(n);
+
+ where NEEDBITS(n) either returns from inflate() if there isn't enough
+ input left to load n bits into the accumulator, or it continues. BITS(n)
+ gives the low n bits in the accumulator. When done, DROPBITS(n) drops
+ the low n bits off the accumulator. INITBITS() clears the accumulator
+ and sets the number of available bits to zero. BYTEBITS() discards just
+ enough bits to put the accumulator on a byte boundary. After BYTEBITS()
+ and a NEEDBITS(8), then BITS(8) would return the next byte in the stream.
+
+ NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return
+ if there is no input available. The decoding of variable length codes uses
+ PULLBYTE() directly in order to pull just enough bytes to decode the next
+ code, and no more.
+
+ Some states loop until they get enough input, making sure that enough
+ state information is maintained to continue the loop where it left off
+ if NEEDBITS() returns in the loop. For example, want, need, and keep
+ would all have to actually be part of the saved state in case NEEDBITS()
+ returns:
+
+ case STATEw:
+ while (want < need) {
+ NEEDBITS(n);
+ keep[want++] = BITS(n);
+ DROPBITS(n);
+ }
+ state = STATEx;
+ case STATEx:
+
+ As shown above, if the next state is also the next case, then the break
+ is omitted.
+
+ A state may also return if there is not enough output space available to
+ complete that state. Those states are copying stored data, writing a
+ literal byte, and copying a matching string.
+
+ When returning, a "goto inf_leave" is used to update the total counters,
+ update the check value, and determine whether any progress has been made
+ during that inflate() call in order to return the proper return code.
+ Progress is defined as a change in either strm->avail_in or strm->avail_out.
+ When there is a window, goto inf_leave will update the window with the last
+ output written. If a goto inf_leave occurs in the middle of decompression
+ and there is no window currently, goto inf_leave will create one and copy
+ output to the window for the next call of inflate().
+
+ In this implementation, the flush parameter of inflate() only affects the
+ return code (per zlib.h). inflate() always writes as much as possible to
+ strm->next_out, given the space available and the provided input--the effect
+ documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers
+ the allocation of and copying into a sliding window until necessary, which
+ provides the effect documented in zlib.h for Z_FINISH when the entire input
+ stream available. So the only thing the flush parameter actually does is:
+ when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it
+ will return Z_BUF_ERROR if it has not reached the end of the stream.
+ */
+
+int ZEXPORT inflate(strm, flush)
+z_streamp strm;
+int flush;
+{
+ struct inflate_state FAR *state;
+ unsigned char FAR *next; /* next input */
+ unsigned char FAR *put; /* next output */
+ unsigned have, left; /* available input and output */
+ unsigned long hold; /* bit buffer */
+ unsigned bits; /* bits in bit buffer */
+ unsigned in, out; /* save starting available input and output */
+ unsigned copy; /* number of stored or match bytes to copy */
+ unsigned char FAR *from; /* where to copy match bytes from */
+ code this; /* current decoding table entry */
+ code last; /* parent table entry */
+ unsigned len; /* length to copy for repeats, bits to drop */
+ int ret; /* return code */
+#ifdef GUNZIP
+ unsigned char hbuf[4]; /* buffer for gzip header crc calculation */
+#endif
+ static const unsigned short order[19] = /* permutation of code lengths */
+ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+ if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL ||
+ (strm->next_in == Z_NULL && strm->avail_in != 0))
+ return Z_STREAM_ERROR;
+
+ state = (struct inflate_state FAR *)strm->state;
+ if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */
+ LOAD();
+ in = have;
+ out = left;
+ ret = Z_OK;
+ for (;;)
+ switch (state->mode) {
+ case HEAD:
+ if (state->wrap == 0) {
+ state->mode = TYPEDO;
+ break;
+ }
+ NEEDBITS(16);
+#ifdef GUNZIP
+ if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */
+ state->check = crc32(0L, Z_NULL, 0);
+ CRC2(state->check, hold);
+ INITBITS();
+ state->mode = FLAGS;
+ break;
+ }
+ state->flags = 0; /* expect zlib header */
+ if (state->head != Z_NULL)
+ state->head->done = -1;
+ if (!(state->wrap & 1) || /* check if zlib header allowed */
+#else
+ if (
+#endif
+ ((BITS(8) << 8) + (hold >> 8)) % 31) {
+ strm->msg = (char *)"incorrect header check";
+ state->mode = BAD;
+ break;
+ }
+ if (BITS(4) != Z_DEFLATED) {
+ strm->msg = (char *)"unknown compression method";
+ state->mode = BAD;
+ break;
+ }
+ DROPBITS(4);
+ len = BITS(4) + 8;
+ if (len > state->wbits) {
+ strm->msg = (char *)"invalid window size";
+ state->mode = BAD;
+ break;
+ }
+ state->dmax = 1U << len;
+ Tracev((stderr, "inflate: zlib header ok\n"));
+ strm->adler = state->check = adler32(0L, Z_NULL, 0);
+ state->mode = hold & 0x200 ? DICTID : TYPE;
+ INITBITS();
+ break;
+#ifdef GUNZIP
+ case FLAGS:
+ NEEDBITS(16);
+ state->flags = (int)(hold);
+ if ((state->flags & 0xff) != Z_DEFLATED) {
+ strm->msg = (char *)"unknown compression method";
+ state->mode = BAD;
+ break;
+ }
+ if (state->flags & 0xe000) {
+ strm->msg = (char *)"unknown header flags set";
+ state->mode = BAD;
+ break;
+ }
+ if (state->head != Z_NULL)
+ state->head->text = (int)((hold >> 8) & 1);
+ if (state->flags & 0x0200) CRC2(state->check, hold);
+ INITBITS();
+ state->mode = TIME;
+ case TIME:
+ NEEDBITS(32);
+ if (state->head != Z_NULL)
+ state->head->time = hold;
+ if (state->flags & 0x0200) CRC4(state->check, hold);
+ INITBITS();
+ state->mode = OS;
+ case OS:
+ NEEDBITS(16);
+ if (state->head != Z_NULL) {
+ state->head->xflags = (int)(hold & 0xff);
+ state->head->os = (int)(hold >> 8);
+ }
+ if (state->flags & 0x0200) CRC2(state->check, hold);
+ INITBITS();
+ state->mode = EXLEN;
+ case EXLEN:
+ if (state->flags & 0x0400) {
+ NEEDBITS(16);
+ state->length = (unsigned)(hold);
+ if (state->head != Z_NULL)
+ state->head->extra_len = (unsigned)hold;
+ if (state->flags & 0x0200) CRC2(state->check, hold);
+ INITBITS();
+ }
+ else if (state->head != Z_NULL)
+ state->head->extra = Z_NULL;
+ state->mode = EXTRA;
+ case EXTRA:
+ if (state->flags & 0x0400) {
+ copy = state->length;
+ if (copy > have) copy = have;
+ if (copy) {
+ if (state->head != Z_NULL &&
+ state->head->extra != Z_NULL) {
+ len = state->head->extra_len - state->length;
+ zmemcpy(state->head->extra + len, next,
+ len + copy > state->head->extra_max ?
+ state->head->extra_max - len : copy);
+ }
+ if (state->flags & 0x0200)
+ state->check = crc32(state->check, next, copy);
+ have -= copy;
+ next += copy;
+ state->length -= copy;
+ }
+ if (state->length) goto inf_leave;
+ }
+ state->length = 0;
+ state->mode = NAME;
+ case NAME:
+ if (state->flags & 0x0800) {
+ if (have == 0) goto inf_leave;
+ copy = 0;
+ do {
+ len = (unsigned)(next[copy++]);
+ if (state->head != Z_NULL &&
+ state->head->name != Z_NULL &&
+ state->length < state->head->name_max)
+ state->head->name[state->length++] = len;
+ } while (len && copy < have);
+ if (state->flags & 0x0200)
+ state->check = crc32(state->check, next, copy);
+ have -= copy;
+ next += copy;
+ if (len) goto inf_leave;
+ }
+ else if (state->head != Z_NULL)
+ state->head->name = Z_NULL;
+ state->length = 0;
+ state->mode = COMMENT;
+ case COMMENT:
+ if (state->flags & 0x1000) {
+ if (have == 0) goto inf_leave;
+ copy = 0;
+ do {
+ len = (unsigned)(next[copy++]);
+ if (state->head != Z_NULL &&
+ state->head->comment != Z_NULL &&
+ state->length < state->head->comm_max)
+ state->head->comment[state->length++] = len;
+ } while (len && copy < have);
+ if (state->flags & 0x0200)
+ state->check = crc32(state->check, next, copy);
+ have -= copy;
+ next += copy;
+ if (len) goto inf_leave;
+ }
+ else if (state->head != Z_NULL)
+ state->head->comment = Z_NULL;
+ state->mode = HCRC;
+ case HCRC:
+ if (state->flags & 0x0200) {
+ NEEDBITS(16);
+ if (hold != (state->check & 0xffff)) {
+ strm->msg = (char *)"header crc mismatch";
+ state->mode = BAD;
+ break;
+ }
+ INITBITS();
+ }
+ if (state->head != Z_NULL) {
+ state->head->hcrc = (int)((state->flags >> 9) & 1);
+ state->head->done = 1;
+ }
+ strm->adler = state->check = crc32(0L, Z_NULL, 0);
+ state->mode = TYPE;
+ break;
+#endif
+ case DICTID:
+ NEEDBITS(32);
+ strm->adler = state->check = REVERSE(hold);
+ INITBITS();
+ state->mode = DICT;
+ case DICT:
+ if (state->havedict == 0) {
+ RESTORE();
+ return Z_NEED_DICT;
+ }
+ strm->adler = state->check = adler32(0L, Z_NULL, 0);
+ state->mode = TYPE;
+ case TYPE:
+ if (flush == Z_BLOCK) goto inf_leave;
+ case TYPEDO:
+ if (state->last) {
+ BYTEBITS();
+ state->mode = CHECK;
+ break;
+ }
+ NEEDBITS(3);
+ state->last = BITS(1);
+ DROPBITS(1);
+ switch (BITS(2)) {
+ case 0: /* stored block */
+ Tracev((stderr, "inflate: stored block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = STORED;
+ break;
+ case 1: /* fixed block */
+ fixedtables(state);
+ Tracev((stderr, "inflate: fixed codes block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = LEN; /* decode codes */
+ break;
+ case 2: /* dynamic block */
+ Tracev((stderr, "inflate: dynamic codes block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = TABLE;
+ break;
+ case 3:
+ strm->msg = (char *)"invalid block type";
+ state->mode = BAD;
+ }
+ DROPBITS(2);
+ break;
+ case STORED:
+ BYTEBITS(); /* go to byte boundary */
+ NEEDBITS(32);
+ if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
+ strm->msg = (char *)"invalid stored block lengths";
+ state->mode = BAD;
+ break;
+ }
+ state->length = (unsigned)hold & 0xffff;
+ Tracev((stderr, "inflate: stored length %u\n",
+ state->length));
+ INITBITS();
+ state->mode = COPY;
+ case COPY:
+ copy = state->length;
+ if (copy) {
+ if (copy > have) copy = have;
+ if (copy > left) copy = left;
+ if (copy == 0) goto inf_leave;
+ zmemcpy(put, next, copy);
+ have -= copy;
+ next += copy;
+ left -= copy;
+ put += copy;
+ state->length -= copy;
+ break;
+ }
+ Tracev((stderr, "inflate: stored end\n"));
+ state->mode = TYPE;
+ break;
+ case TABLE:
+ NEEDBITS(14);
+ state->nlen = BITS(5) + 257;
+ DROPBITS(5);
+ state->ndist = BITS(5) + 1;
+ DROPBITS(5);
+ state->ncode = BITS(4) + 4;
+ DROPBITS(4);
+#ifndef PKZIP_BUG_WORKAROUND
+ if (state->nlen > 286 || state->ndist > 30) {
+ strm->msg = (char *)"too many length or distance symbols";
+ state->mode = BAD;
+ break;
+ }
+#endif
+ Tracev((stderr, "inflate: table sizes ok\n"));
+ state->have = 0;
+ state->mode = LENLENS;
+ case LENLENS:
+ while (state->have < state->ncode) {
+ NEEDBITS(3);
+ state->lens[order[state->have++]] = (unsigned short)BITS(3);
+ DROPBITS(3);
+ }
+ while (state->have < 19)
+ state->lens[order[state->have++]] = 0;
+ state->next = state->codes;
+ state->lencode = (code const FAR *)(state->next);
+ state->lenbits = 7;
+ ret = inflate_table(CODES, state->lens, 19, &(state->next),
+ &(state->lenbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid code lengths set";
+ state->mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: code lengths ok\n"));
+ state->have = 0;
+ state->mode = CODELENS;
+ case CODELENS:
+ while (state->have < state->nlen + state->ndist) {
+ for (;;) {
+ this = state->lencode[BITS(state->lenbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if (this.val < 16) {
+ NEEDBITS(this.bits);
+ DROPBITS(this.bits);
+ state->lens[state->have++] = this.val;
+ }
+ else {
+ if (this.val == 16) {
+ NEEDBITS(this.bits + 2);
+ DROPBITS(this.bits);
+ if (state->have == 0) {
+ strm->msg = (char *)"invalid bit length repeat";
+ state->mode = BAD;
+ break;
+ }
+ len = state->lens[state->have - 1];
+ copy = 3 + BITS(2);
+ DROPBITS(2);
+ }
+ else if (this.val == 17) {
+ NEEDBITS(this.bits + 3);
+ DROPBITS(this.bits);
+ len = 0;
+ copy = 3 + BITS(3);
+ DROPBITS(3);
+ }
+ else {
+ NEEDBITS(this.bits + 7);
+ DROPBITS(this.bits);
+ len = 0;
+ copy = 11 + BITS(7);
+ DROPBITS(7);
+ }
+ if (state->have + copy > state->nlen + state->ndist) {
+ strm->msg = (char *)"invalid bit length repeat";
+ state->mode = BAD;
+ break;
+ }
+ while (copy--)
+ state->lens[state->have++] = (unsigned short)len;
+ }
+ }
+
+ /* handle error breaks in while */
+ if (state->mode == BAD) break;
+
+ /* build code tables */
+ state->next = state->codes;
+ state->lencode = (code const FAR *)(state->next);
+ state->lenbits = 9;
+ ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
+ &(state->lenbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid literal/lengths set";
+ state->mode = BAD;
+ break;
+ }
+ state->distcode = (code const FAR *)(state->next);
+ state->distbits = 6;
+ ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
+ &(state->next), &(state->distbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid distances set";
+ state->mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: codes ok\n"));
+ state->mode = LEN;
+ case LEN:
+ if (have >= 6 && left >= 258) {
+ RESTORE();
+ inflate_fast(strm, out);
+ LOAD();
+ break;
+ }
+ for (;;) {
+ this = state->lencode[BITS(state->lenbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if (this.op && (this.op & 0xf0) == 0) {
+ last = this;
+ for (;;) {
+ this = state->lencode[last.val +
+ (BITS(last.bits + last.op) >> last.bits)];
+ if ((unsigned)(last.bits + this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ DROPBITS(last.bits);
+ }
+ DROPBITS(this.bits);
+ state->length = (unsigned)this.val;
+ if ((int)(this.op) == 0) {
+ Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ?
+ "inflate: literal '%c'\n" :
+ "inflate: literal 0x%02x\n", this.val));
+ state->mode = LIT;
+ break;
+ }
+ if (this.op & 32) {
+ Tracevv((stderr, "inflate: end of block\n"));
+ state->mode = TYPE;
+ break;
+ }
+ if (this.op & 64) {
+ strm->msg = (char *)"invalid literal/length code";
+ state->mode = BAD;
+ break;
+ }
+ state->extra = (unsigned)(this.op) & 15;
+ state->mode = LENEXT;
+ case LENEXT:
+ if (state->extra) {
+ NEEDBITS(state->extra);
+ state->length += BITS(state->extra);
+ DROPBITS(state->extra);
+ }
+ Tracevv((stderr, "inflate: length %u\n", state->length));
+ state->mode = DIST;
+ case DIST:
+ for (;;) {
+ this = state->distcode[BITS(state->distbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if ((this.op & 0xf0) == 0) {
+ last = this;
+ for (;;) {
+ this = state->distcode[last.val +
+ (BITS(last.bits + last.op) >> last.bits)];
+ if ((unsigned)(last.bits + this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ DROPBITS(last.bits);
+ }
+ DROPBITS(this.bits);
+ if (this.op & 64) {
+ strm->msg = (char *)"invalid distance code";
+ state->mode = BAD;
+ break;
+ }
+ state->offset = (unsigned)this.val;
+ state->extra = (unsigned)(this.op) & 15;
+ state->mode = DISTEXT;
+ case DISTEXT:
+ if (state->extra) {
+ NEEDBITS(state->extra);
+ state->offset += BITS(state->extra);
+ DROPBITS(state->extra);
+ }
+#ifdef INFLATE_STRICT
+ if (state->offset > state->dmax) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+#endif
+ if (state->offset > state->whave + out - left) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+ Tracevv((stderr, "inflate: distance %u\n", state->offset));
+ state->mode = MATCH;
+ case MATCH:
+ if (left == 0) goto inf_leave;
+ copy = out - left;
+ if (state->offset > copy) { /* copy from window */
+ copy = state->offset - copy;
+ if (copy > state->write) {
+ copy -= state->write;
+ from = state->window + (state->wsize - copy);
+ }
+ else
+ from = state->window + (state->write - copy);
+ if (copy > state->length) copy = state->length;
+ }
+ else { /* copy from output */
+ from = put - state->offset;
+ copy = state->length;
+ }
+ if (copy > left) copy = left;
+ left -= copy;
+ state->length -= copy;
+ do {
+ *put++ = *from++;
+ } while (--copy);
+ if (state->length == 0) state->mode = LEN;
+ break;
+ case LIT:
+ if (left == 0) goto inf_leave;
+ *put++ = (unsigned char)(state->length);
+ left--;
+ state->mode = LEN;
+ break;
+ case CHECK:
+ if (state->wrap) {
+ NEEDBITS(32);
+ out -= left;
+ strm->total_out += out;
+ state->total += out;
+ if (out)
+ strm->adler = state->check =
+ UPDATE(state->check, put - out, out);
+ out = left;
+ if ((
+#ifdef GUNZIP
+ state->flags ? hold :
+#endif
+ REVERSE(hold)) != state->check) {
+ strm->msg = (char *)"incorrect data check";
+ state->mode = BAD;
+ break;
+ }
+ INITBITS();
+ Tracev((stderr, "inflate: check matches trailer\n"));
+ }
+#ifdef GUNZIP
+ state->mode = LENGTH;
+ case LENGTH:
+ if (state->wrap && state->flags) {
+ NEEDBITS(32);
+ if (hold != (state->total & 0xffffffffUL)) {
+ strm->msg = (char *)"incorrect length check";
+ state->mode = BAD;
+ break;
+ }
+ INITBITS();
+ Tracev((stderr, "inflate: length matches trailer\n"));
+ }
+#endif
+ state->mode = DONE;
+ case DONE:
+ ret = Z_STREAM_END;
+ goto inf_leave;
+ case BAD:
+ ret = Z_DATA_ERROR;
+ goto inf_leave;
+ case MEM:
+ return Z_MEM_ERROR;
+ case SYNC:
+ default:
+ return Z_STREAM_ERROR;
+ }
+
+ /*
+ Return from inflate(), updating the total counts and the check value.
+ If there was no progress during the inflate() call, return a buffer
+ error. Call updatewindow() to create and/or update the window state.
+ Note: a memory error from inflate() is non-recoverable.
+ */
+ inf_leave:
+ RESTORE();
+ if (state->wsize || (state->mode < CHECK && out != strm->avail_out))
+ if (updatewindow(strm, out)) {
+ state->mode = MEM;
+ return Z_MEM_ERROR;
+ }
+ in -= strm->avail_in;
+ out -= strm->avail_out;
+ strm->total_in += in;
+ strm->total_out += out;
+ state->total += out;
+ if (state->wrap && out)
+ strm->adler = state->check =
+ UPDATE(state->check, strm->next_out - out, out);
+ strm->data_type = state->bits + (state->last ? 64 : 0) +
+ (state->mode == TYPE ? 128 : 0);
+ if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK)
+ ret = Z_BUF_ERROR;
+ return ret;
+}
+
+int ZEXPORT inflateEnd(strm)
+z_streamp strm;
+{
+ struct inflate_state FAR *state;
+ if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
+ return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (state->window != Z_NULL) ZFREE(strm, state->window);
+ ZFREE(strm, strm->state);
+ strm->state = Z_NULL;
+ Tracev((stderr, "inflate: end\n"));
+ return Z_OK;
+}
+
+int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength)
+z_streamp strm;
+const Bytef *dictionary;
+uInt dictLength;
+{
+ struct inflate_state FAR *state;
+ unsigned long id;
+
+ /* check state */
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (state->wrap != 0 && state->mode != DICT)
+ return Z_STREAM_ERROR;
+
+ /* check for correct dictionary id */
+ if (state->mode == DICT) {
+ id = adler32(0L, Z_NULL, 0);
+ id = adler32(id, dictionary, dictLength);
+ if (id != state->check)
+ return Z_DATA_ERROR;
+ }
+
+ /* copy dictionary to window */
+ if (updatewindow(strm, strm->avail_out)) {
+ state->mode = MEM;
+ return Z_MEM_ERROR;
+ }
+ if (dictLength > state->wsize) {
+ zmemcpy(state->window, dictionary + dictLength - state->wsize,
+ state->wsize);
+ state->whave = state->wsize;
+ }
+ else {
+ zmemcpy(state->window + state->wsize - dictLength, dictionary,
+ dictLength);
+ state->whave = dictLength;
+ }
+ state->havedict = 1;
+ Tracev((stderr, "inflate: dictionary set\n"));
+ return Z_OK;
+}
+
+int ZEXPORT inflateGetHeader(strm, head)
+z_streamp strm;
+gz_headerp head;
+{
+ struct inflate_state FAR *state;
+
+ /* check state */
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if ((state->wrap & 2) == 0) return Z_STREAM_ERROR;
+
+ /* save header structure */
+ state->head = head;
+ head->done = 0;
+ return Z_OK;
+}
+
+/*
+ Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found
+ or when out of input. When called, *have is the number of pattern bytes
+ found in order so far, in 0..3. On return *have is updated to the new
+ state. If on return *have equals four, then the pattern was found and the
+ return value is how many bytes were read including the last byte of the
+ pattern. If *have is less than four, then the pattern has not been found
+ yet and the return value is len. In the latter case, syncsearch() can be
+ called again with more data and the *have state. *have is initialized to
+ zero for the first call.
+ */
+local unsigned syncsearch(have, buf, len)
+unsigned FAR *have;
+unsigned char FAR *buf;
+unsigned len;
+{
+ unsigned got;
+ unsigned next;
+
+ got = *have;
+ next = 0;
+ while (next < len && got < 4) {
+ if ((int)(buf[next]) == (got < 2 ? 0 : 0xff))
+ got++;
+ else if (buf[next])
+ got = 0;
+ else
+ got = 4 - got;
+ next++;
+ }
+ *have = got;
+ return next;
+}
+
+int ZEXPORT inflateSync(strm)
+z_streamp strm;
+{
+ unsigned len; /* number of bytes to look at or looked at */
+ unsigned long in, out; /* temporary to save total_in and total_out */
+ unsigned char buf[4]; /* to restore bit buffer to byte string */
+ struct inflate_state FAR *state;
+
+ /* check parameters */
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR;
+
+ /* if first time, start search in bit buffer */
+ if (state->mode != SYNC) {
+ state->mode = SYNC;
+ state->hold <<= state->bits & 7;
+ state->bits -= state->bits & 7;
+ len = 0;
+ while (state->bits >= 8) {
+ buf[len++] = (unsigned char)(state->hold);
+ state->hold >>= 8;
+ state->bits -= 8;
+ }
+ state->have = 0;
+ syncsearch(&(state->have), buf, len);
+ }
+
+ /* search available input */
+ len = syncsearch(&(state->have), strm->next_in, strm->avail_in);
+ strm->avail_in -= len;
+ strm->next_in += len;
+ strm->total_in += len;
+
+ /* return no joy or set up to restart inflate() on a new block */
+ if (state->have != 4) return Z_DATA_ERROR;
+ in = strm->total_in; out = strm->total_out;
+ inflateReset(strm);
+ strm->total_in = in; strm->total_out = out;
+ state->mode = TYPE;
+ return Z_OK;
+}
+
+/*
+ Returns true if inflate is currently at the end of a block generated by
+ Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
+ implementation to provide an additional safety check. PPP uses
+ Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored
+ block. When decompressing, PPP checks that at the end of input packet,
+ inflate is waiting for these length bytes.
+ */
+int ZEXPORT inflateSyncPoint(strm)
+z_streamp strm;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ return state->mode == STORED && state->bits == 0;
+}
+
+int ZEXPORT inflateCopy(dest, source)
+z_streamp dest;
+z_streamp source;
+{
+ struct inflate_state FAR *state;
+ struct inflate_state FAR *copy;
+ unsigned char FAR *window;
+ unsigned wsize;
+
+ /* check input */
+ if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL ||
+ source->zalloc == (alloc_func)0 || source->zfree == (free_func)0)
+ return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)source->state;
+
+ /* allocate space */
+ copy = (struct inflate_state FAR *)
+ ZALLOC(source, 1, sizeof(struct inflate_state));
+ if (copy == Z_NULL) return Z_MEM_ERROR;
+ window = Z_NULL;
+ if (state->window != Z_NULL) {
+ window = (unsigned char FAR *)
+ ZALLOC(source, 1U << state->wbits, sizeof(unsigned char));
+ if (window == Z_NULL) {
+ ZFREE(source, copy);
+ return Z_MEM_ERROR;
+ }
+ }
+
+ /* copy state */
+ zmemcpy(dest, source, sizeof(z_stream));
+ zmemcpy(copy, state, sizeof(struct inflate_state));
+ if (state->lencode >= state->codes &&
+ state->lencode <= state->codes + ENOUGH - 1) {
+ copy->lencode = copy->codes + (state->lencode - state->codes);
+ copy->distcode = copy->codes + (state->distcode - state->codes);
+ }
+ copy->next = copy->codes + (state->next - state->codes);
+ if (window != Z_NULL) {
+ wsize = 1U << state->wbits;
+ zmemcpy(window, state->window, wsize);
+ }
+ copy->window = window;
+ dest->state = (struct internal_state FAR *)copy;
+ return Z_OK;
+}
diff --git a/lib/libz/inflate.h b/lib/libz/inflate.h
new file mode 100644
index 0000000..07bd3e7
--- /dev/null
+++ b/lib/libz/inflate.h
@@ -0,0 +1,115 @@
+/* inflate.h -- internal inflate state definition
+ * Copyright (C) 1995-2004 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* define NO_GZIP when compiling if you want to disable gzip header and
+ trailer decoding by inflate(). NO_GZIP would be used to avoid linking in
+ the crc code when it is not needed. For shared libraries, gzip decoding
+ should be left enabled. */
+#ifndef NO_GZIP
+# define GUNZIP
+#endif
+
+/* Possible inflate modes between inflate() calls */
+typedef enum {
+ HEAD, /* i: waiting for magic header */
+ FLAGS, /* i: waiting for method and flags (gzip) */
+ TIME, /* i: waiting for modification time (gzip) */
+ OS, /* i: waiting for extra flags and operating system (gzip) */
+ EXLEN, /* i: waiting for extra length (gzip) */
+ EXTRA, /* i: waiting for extra bytes (gzip) */
+ NAME, /* i: waiting for end of file name (gzip) */
+ COMMENT, /* i: waiting for end of comment (gzip) */
+ HCRC, /* i: waiting for header crc (gzip) */
+ DICTID, /* i: waiting for dictionary check value */
+ DICT, /* waiting for inflateSetDictionary() call */
+ TYPE, /* i: waiting for type bits, including last-flag bit */
+ TYPEDO, /* i: same, but skip check to exit inflate on new block */
+ STORED, /* i: waiting for stored size (length and complement) */
+ COPY, /* i/o: waiting for input or output to copy stored block */
+ TABLE, /* i: waiting for dynamic block table lengths */
+ LENLENS, /* i: waiting for code length code lengths */
+ CODELENS, /* i: waiting for length/lit and distance code lengths */
+ LEN, /* i: waiting for length/lit code */
+ LENEXT, /* i: waiting for length extra bits */
+ DIST, /* i: waiting for distance code */
+ DISTEXT, /* i: waiting for distance extra bits */
+ MATCH, /* o: waiting for output space to copy string */
+ LIT, /* o: waiting for output space to write literal */
+ CHECK, /* i: waiting for 32-bit check value */
+ LENGTH, /* i: waiting for 32-bit length (gzip) */
+ DONE, /* finished check, done -- remain here until reset */
+ BAD, /* got a data error -- remain here until reset */
+ MEM, /* got an inflate() memory error -- remain here until reset */
+ SYNC /* looking for synchronization bytes to restart inflate() */
+} inflate_mode;
+
+/*
+ State transitions between above modes -
+
+ (most modes can go to the BAD or MEM mode -- not shown for clarity)
+
+ Process header:
+ HEAD -> (gzip) or (zlib)
+ (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME
+ NAME -> COMMENT -> HCRC -> TYPE
+ (zlib) -> DICTID or TYPE
+ DICTID -> DICT -> TYPE
+ Read deflate blocks:
+ TYPE -> STORED or TABLE or LEN or CHECK
+ STORED -> COPY -> TYPE
+ TABLE -> LENLENS -> CODELENS -> LEN
+ Read deflate codes:
+ LEN -> LENEXT or LIT or TYPE
+ LENEXT -> DIST -> DISTEXT -> MATCH -> LEN
+ LIT -> LEN
+ Process trailer:
+ CHECK -> LENGTH -> DONE
+ */
+
+/* state maintained between inflate() calls. Approximately 7K bytes. */
+struct inflate_state {
+ inflate_mode mode; /* current inflate mode */
+ int last; /* true if processing last block */
+ int wrap; /* bit 0 true for zlib, bit 1 true for gzip */
+ int havedict; /* true if dictionary provided */
+ int flags; /* gzip header method and flags (0 if zlib) */
+ unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */
+ unsigned long check; /* protected copy of check value */
+ unsigned long total; /* protected copy of output count */
+ gz_headerp head; /* where to save gzip header information */
+ /* sliding window */
+ unsigned wbits; /* log base 2 of requested window size */
+ unsigned wsize; /* window size or zero if not using window */
+ unsigned whave; /* valid bytes in the window */
+ unsigned write; /* window write index */
+ unsigned char FAR *window; /* allocated sliding window, if needed */
+ /* bit accumulator */
+ unsigned long hold; /* input bit accumulator */
+ unsigned bits; /* number of bits in "in" */
+ /* for string and stored block copying */
+ unsigned length; /* literal or length of data to copy */
+ unsigned offset; /* distance back to copy string from */
+ /* for table and code decoding */
+ unsigned extra; /* extra bits needed */
+ /* fixed and dynamic code tables */
+ code const FAR *lencode; /* starting table for length/literal codes */
+ code const FAR *distcode; /* starting table for distance codes */
+ unsigned lenbits; /* index bits for lencode */
+ unsigned distbits; /* index bits for distcode */
+ /* dynamic table building */
+ unsigned ncode; /* number of code length code lengths */
+ unsigned nlen; /* number of length code lengths */
+ unsigned ndist; /* number of distance code lengths */
+ unsigned have; /* number of code lengths in lens[] */
+ code FAR *next; /* next available space in codes[] */
+ unsigned short lens[320]; /* temporary storage for code lengths */
+ unsigned short work[288]; /* work area for code table building */
+ code codes[ENOUGH]; /* space for code tables */
+};
diff --git a/lib/libz/inftrees.c b/lib/libz/inftrees.c
new file mode 100644
index 0000000..8a9c13f
--- /dev/null
+++ b/lib/libz/inftrees.c
@@ -0,0 +1,329 @@
+/* inftrees.c -- generate Huffman trees for efficient decoding
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+
+#define MAXBITS 15
+
+const char inflate_copyright[] =
+ " inflate 1.2.3 Copyright 1995-2005 Mark Adler ";
+/*
+ If you use the zlib library in a product, an acknowledgment is welcome
+ in the documentation of your product. If for some reason you cannot
+ include such an acknowledgment, I would appreciate that you keep this
+ copyright string in the executable of your product.
+ */
+
+/*
+ Build a set of tables to decode the provided canonical Huffman code.
+ The code lengths are lens[0..codes-1]. The result starts at *table,
+ whose indices are 0..2^bits-1. work is a writable array of at least
+ lens shorts, which is used as a work area. type is the type of code
+ to be generated, CODES, LENS, or DISTS. On return, zero is success,
+ -1 is an invalid code, and +1 means that ENOUGH isn't enough. table
+ on return points to the next available entry's address. bits is the
+ requested root table index bits, and on return it is the actual root
+ table index bits. It will differ if the request is greater than the
+ longest code or if it is less than the shortest code.
+ */
+int inflate_table(type, lens, codes, table, bits, work)
+codetype type;
+unsigned short FAR *lens;
+unsigned codes;
+code FAR * FAR *table;
+unsigned FAR *bits;
+unsigned short FAR *work;
+{
+ unsigned len; /* a code's length in bits */
+ unsigned sym; /* index of code symbols */
+ unsigned min, max; /* minimum and maximum code lengths */
+ unsigned root; /* number of index bits for root table */
+ unsigned curr; /* number of index bits for current table */
+ unsigned drop; /* code bits to drop for sub-table */
+ int left; /* number of prefix codes available */
+ unsigned used; /* code entries in table used */
+ unsigned huff; /* Huffman code */
+ unsigned incr; /* for incrementing code, index */
+ unsigned fill; /* index for replicating entries */
+ unsigned low; /* low bits for current root entry */
+ unsigned mask; /* mask for low root bits */
+ code this; /* table entry for duplication */
+ code FAR *next; /* next available space in table */
+ const unsigned short FAR *base; /* base value table to use */
+ const unsigned short FAR *extra; /* extra bits table to use */
+ int end; /* use base and extra for symbol > end */
+ unsigned short count[MAXBITS+1]; /* number of codes of each length */
+ unsigned short offs[MAXBITS+1]; /* offsets in table for each length */
+ static const unsigned short lbase[31] = { /* Length codes 257..285 base */
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+ static const unsigned short lext[31] = { /* Length codes 257..285 extra */
+ 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
+ 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 201, 196};
+ static const unsigned short dbase[32] = { /* Distance codes 0..29 base */
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+ 8193, 12289, 16385, 24577, 0, 0};
+ static const unsigned short dext[32] = { /* Distance codes 0..29 extra */
+ 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,
+ 23, 23, 24, 24, 25, 25, 26, 26, 27, 27,
+ 28, 28, 29, 29, 64, 64};
+
+ /*
+ Process a set of code lengths to create a canonical Huffman code. The
+ code lengths are lens[0..codes-1]. Each length corresponds to the
+ symbols 0..codes-1. The Huffman code is generated by first sorting the
+ symbols by length from short to long, and retaining the symbol order
+ for codes with equal lengths. Then the code starts with all zero bits
+ for the first code of the shortest length, and the codes are integer
+ increments for the same length, and zeros are appended as the length
+ increases. For the deflate format, these bits are stored backwards
+ from their more natural integer increment ordering, and so when the
+ decoding tables are built in the large loop below, the integer codes
+ are incremented backwards.
+
+ This routine assumes, but does not check, that all of the entries in
+ lens[] are in the range 0..MAXBITS. The caller must assure this.
+ 1..MAXBITS is interpreted as that code length. zero means that that
+ symbol does not occur in this code.
+
+ The codes are sorted by computing a count of codes for each length,
+ creating from that a table of starting indices for each length in the
+ sorted table, and then entering the symbols in order in the sorted
+ table. The sorted table is work[], with that space being provided by
+ the caller.
+
+ The length counts are used for other purposes as well, i.e. finding
+ the minimum and maximum length codes, determining if there are any
+ codes at all, checking for a valid set of lengths, and looking ahead
+ at length counts to determine sub-table sizes when building the
+ decoding tables.
+ */
+
+ /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */
+ for (len = 0; len <= MAXBITS; len++)
+ count[len] = 0;
+ for (sym = 0; sym < codes; sym++)
+ count[lens[sym]]++;
+
+ /* bound code lengths, force root to be within code lengths */
+ root = *bits;
+ for (max = MAXBITS; max >= 1; max--)
+ if (count[max] != 0) break;
+ if (root > max) root = max;
+ if (max == 0) { /* no symbols to code at all */
+ this.op = (unsigned char)64; /* invalid code marker */
+ this.bits = (unsigned char)1;
+ this.val = (unsigned short)0;
+ *(*table)++ = this; /* make a table to force an error */
+ *(*table)++ = this;
+ *bits = 1;
+ return 0; /* no symbols, but wait for decoding to report error */
+ }
+ for (min = 1; min <= MAXBITS; min++)
+ if (count[min] != 0) break;
+ if (root < min) root = min;
+
+ /* check for an over-subscribed or incomplete set of lengths */
+ left = 1;
+ for (len = 1; len <= MAXBITS; len++) {
+ left <<= 1;
+ left -= count[len];
+ if (left < 0) return -1; /* over-subscribed */
+ }
+ if (left > 0 && (type == CODES || max != 1))
+ return -1; /* incomplete set */
+
+ /* generate offsets into symbol table for each length for sorting */
+ offs[1] = 0;
+ for (len = 1; len < MAXBITS; len++)
+ offs[len + 1] = offs[len] + count[len];
+
+ /* sort symbols by length, by symbol order within each length */
+ for (sym = 0; sym < codes; sym++)
+ if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym;
+
+ /*
+ Create and fill in decoding tables. In this loop, the table being
+ filled is at next and has curr index bits. The code being used is huff
+ with length len. That code is converted to an index by dropping drop
+ bits off of the bottom. For codes where len is less than drop + curr,
+ those top drop + curr - len bits are incremented through all values to
+ fill the table with replicated entries.
+
+ root is the number of index bits for the root table. When len exceeds
+ root, sub-tables are created pointed to by the root entry with an index
+ of the low root bits of huff. This is saved in low to check for when a
+ new sub-table should be started. drop is zero when the root table is
+ being filled, and drop is root when sub-tables are being filled.
+
+ When a new sub-table is needed, it is necessary to look ahead in the
+ code lengths to determine what size sub-table is needed. The length
+ counts are used for this, and so count[] is decremented as codes are
+ entered in the tables.
+
+ used keeps track of how many table entries have been allocated from the
+ provided *table space. It is checked when a LENS table is being made
+ against the space in *table, ENOUGH, minus the maximum space needed by
+ the worst case distance code, MAXD. This should never happen, but the
+ sufficiency of ENOUGH has not been proven exhaustively, hence the check.
+ This assumes that when type == LENS, bits == 9.
+
+ sym increments through all symbols, and the loop terminates when
+ all codes of length max, i.e. all codes, have been processed. This
+ routine permits incomplete codes, so another loop after this one fills
+ in the rest of the decoding tables with invalid code markers.
+ */
+
+ /* set up for code type */
+ switch (type) {
+ case CODES:
+ base = extra = work; /* dummy value--not used */
+ end = 19;
+ break;
+ case LENS:
+ base = lbase;
+ base -= 257;
+ extra = lext;
+ extra -= 257;
+ end = 256;
+ break;
+ default: /* DISTS */
+ base = dbase;
+ extra = dext;
+ end = -1;
+ }
+
+ /* initialize state for loop */
+ huff = 0; /* starting code */
+ sym = 0; /* starting code symbol */
+ len = min; /* starting code length */
+ next = *table; /* current table to fill in */
+ curr = root; /* current table index bits */
+ drop = 0; /* current bits to drop from code for index */
+ low = (unsigned)(-1); /* trigger new sub-table when len > root */
+ used = 1U << root; /* use root table entries */
+ mask = used - 1; /* mask for comparing low */
+
+ /* check available table space */
+ if (type == LENS && used >= ENOUGH - MAXD)
+ return 1;
+
+ /* process all codes and make table entries */
+ for (;;) {
+ /* create table entry */
+ this.bits = (unsigned char)(len - drop);
+ if ((int)(work[sym]) < end) {
+ this.op = (unsigned char)0;
+ this.val = work[sym];
+ }
+ else if ((int)(work[sym]) > end) {
+ this.op = (unsigned char)(extra[work[sym]]);
+ this.val = base[work[sym]];
+ }
+ else {
+ this.op = (unsigned char)(32 + 64); /* end of block */
+ this.val = 0;
+ }
+
+ /* replicate for those indices with low len bits equal to huff */
+ incr = 1U << (len - drop);
+ fill = 1U << curr;
+ min = fill; /* save offset to next table */
+ do {
+ fill -= incr;
+ next[(huff >> drop) + fill] = this;
+ } while (fill != 0);
+
+ /* backwards increment the len-bit code huff */
+ incr = 1U << (len - 1);
+ while (huff & incr)
+ incr >>= 1;
+ if (incr != 0) {
+ huff &= incr - 1;
+ huff += incr;
+ }
+ else
+ huff = 0;
+
+ /* go to next symbol, update count, len */
+ sym++;
+ if (--(count[len]) == 0) {
+ if (len == max) break;
+ len = lens[work[sym]];
+ }
+
+ /* create new sub-table if needed */
+ if (len > root && (huff & mask) != low) {
+ /* if first time, transition to sub-tables */
+ if (drop == 0)
+ drop = root;
+
+ /* increment past last table */
+ next += min; /* here min is 1 << curr */
+
+ /* determine length of next table */
+ curr = len - drop;
+ left = (int)(1 << curr);
+ while (curr + drop < max) {
+ left -= count[curr + drop];
+ if (left <= 0) break;
+ curr++;
+ left <<= 1;
+ }
+
+ /* check for enough space */
+ used += 1U << curr;
+ if (type == LENS && used >= ENOUGH - MAXD)
+ return 1;
+
+ /* point entry in root table to sub-table */
+ low = huff & mask;
+ (*table)[low].op = (unsigned char)curr;
+ (*table)[low].bits = (unsigned char)root;
+ (*table)[low].val = (unsigned short)(next - *table);
+ }
+ }
+
+ /*
+ Fill in rest of table for incomplete codes. This loop is similar to the
+ loop above in incrementing huff for table indices. It is assumed that
+ len is equal to curr + drop, so there is no loop needed to increment
+ through high index bits. When the current sub-table is filled, the loop
+ drops back to the root table to fill in any remaining entries there.
+ */
+ this.op = (unsigned char)64; /* invalid code marker */
+ this.bits = (unsigned char)(len - drop);
+ this.val = (unsigned short)0;
+ while (huff != 0) {
+ /* when done with sub-table, drop back to root table */
+ if (drop != 0 && (huff & mask) != low) {
+ drop = 0;
+ len = root;
+ next = *table;
+ this.bits = (unsigned char)len;
+ }
+
+ /* put invalid code marker in table */
+ next[huff >> drop] = this;
+
+ /* backwards increment the len-bit code huff */
+ incr = 1U << (len - 1);
+ while (huff & incr)
+ incr >>= 1;
+ if (incr != 0) {
+ huff &= incr - 1;
+ huff += incr;
+ }
+ else
+ huff = 0;
+ }
+
+ /* set return parameters */
+ *table += used;
+ *bits = root;
+ return 0;
+}
diff --git a/lib/libz/inftrees.h b/lib/libz/inftrees.h
new file mode 100644
index 0000000..b1104c8
--- /dev/null
+++ b/lib/libz/inftrees.h
@@ -0,0 +1,55 @@
+/* inftrees.h -- header to use inftrees.c
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* Structure for decoding tables. Each entry provides either the
+ information needed to do the operation requested by the code that
+ indexed that table entry, or it provides a pointer to another
+ table that indexes more bits of the code. op indicates whether
+ the entry is a pointer to another table, a literal, a length or
+ distance, an end-of-block, or an invalid code. For a table
+ pointer, the low four bits of op is the number of index bits of
+ that table. For a length or distance, the low four bits of op
+ is the number of extra bits to get after the code. bits is
+ the number of bits in this code or part of the code to drop off
+ of the bit buffer. val is the actual byte to output in the case
+ of a literal, the base length or distance, or the offset from
+ the current table to the next table. Each entry is four bytes. */
+typedef struct {
+ unsigned char op; /* operation, extra bits, table bits */
+ unsigned char bits; /* bits in this part of the code */
+ unsigned short val; /* offset in table or code value */
+} code;
+
+/* op values as set by inflate_table():
+ 00000000 - literal
+ 0000tttt - table link, tttt != 0 is the number of table index bits
+ 0001eeee - length or distance, eeee is the number of extra bits
+ 01100000 - end of block
+ 01000000 - invalid code
+ */
+
+/* Maximum size of dynamic tree. The maximum found in a long but non-
+ exhaustive search was 1444 code structures (852 for length/literals
+ and 592 for distances, the latter actually the result of an
+ exhaustive search). The true maximum is not known, but the value
+ below is more than safe. */
+#define ENOUGH 2048
+#define MAXD 592
+
+/* Type of code to build for inftable() */
+typedef enum {
+ CODES,
+ LENS,
+ DISTS
+} codetype;
+
+extern int inflate_table OF((codetype type, unsigned short FAR *lens,
+ unsigned codes, code FAR * FAR *table,
+ unsigned FAR *bits, unsigned short FAR *work));
diff --git a/lib/libz/minigzip.c b/lib/libz/minigzip.c
new file mode 100644
index 0000000..b29d14a
--- /dev/null
+++ b/lib/libz/minigzip.c
@@ -0,0 +1,372 @@
+/* minigzip.c -- simulate gzip using the zlib compression library
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * minigzip is a minimal implementation of the gzip utility. This is
+ * only an example of using zlib and isn't meant to replace the
+ * full-featured gzip. No attempt is made to deal with file systems
+ * limiting names to 14 or 8+3 characters, etc... Error checking is
+ * very limited. So use minigzip only for testing; use gzip for the
+ * real thing. On MSDOS, use only on file names without extension
+ * or in pipe mode.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include "zlib.h"
+
+#ifdef STDC
+# include <string.h>
+# include <stdlib.h>
+#endif
+
+#ifdef USE_MMAP
+# include <sys/types.h>
+# include <sys/mman.h>
+# include <sys/stat.h>
+#endif
+
+#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__)
+# include <fcntl.h>
+# include <io.h>
+# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
+#else
+# define SET_BINARY_MODE(file)
+#endif
+
+#ifdef VMS
+# define unlink delete
+# define GZ_SUFFIX "-gz"
+#endif
+#ifdef RISCOS
+# define unlink remove
+# define GZ_SUFFIX "-gz"
+# define fileno(file) file->__file
+#endif
+#if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
+# include <unix.h> /* for fileno */
+#endif
+
+#ifndef WIN32 /* unlink already in stdio.h for WIN32 */
+ extern int unlink OF((const char *));
+#endif
+
+#ifndef GZ_SUFFIX
+# define GZ_SUFFIX ".gz"
+#endif
+#define SUFFIX_LEN (sizeof(GZ_SUFFIX)-1)
+
+#define BUFLEN 16384
+#define MAX_NAME_LEN 1024
+
+#ifdef MAXSEG_64K
+# define local static
+ /* Needed for systems with limitation on stack size. */
+#else
+# define local
+#endif
+
+char *prog;
+
+void error OF((const char *msg));
+void gz_compress OF((FILE *in, gzFile out));
+#ifdef USE_MMAP
+int gz_compress_mmap OF((FILE *in, gzFile out));
+#endif
+void gz_uncompress OF((gzFile in, FILE *out));
+void file_compress OF((char *file, char *mode));
+void file_uncompress OF((char *file));
+int main OF((int argc, char *argv[]));
+
+/* ===========================================================================
+ * Display error message and exit
+ */
+void error(msg)
+ const char *msg;
+{
+ fprintf(stderr, "%s: %s\n", prog, msg);
+ exit(1);
+}
+
+/* ===========================================================================
+ * Compress input to output then close both files.
+ */
+
+void gz_compress(in, out)
+ FILE *in;
+ gzFile out;
+{
+ local char buf[BUFLEN];
+ int len;
+ int err;
+
+#ifdef USE_MMAP
+ /* Try first compressing with mmap. If mmap fails (minigzip used in a
+ * pipe), use the normal fread loop.
+ */
+ if (gz_compress_mmap(in, out) == Z_OK) return;
+#endif
+ for (;;) {
+ len = (int)fread(buf, 1, sizeof(buf), in);
+ if (ferror(in)) {
+ perror("fread");
+ exit(1);
+ }
+ if (len == 0) break;
+
+ if (gzwrite(out, buf, (unsigned)len) != len) error(gzerror(out, &err));
+ }
+ fclose(in);
+ if (gzclose(out) != Z_OK) error("failed gzclose");
+}
+
+#ifdef USE_MMAP /* MMAP version, Miguel Albrecht <malbrech@eso.org> */
+
+/* Try compressing the input file at once using mmap. Return Z_OK if
+ * if success, Z_ERRNO otherwise.
+ */
+int gz_compress_mmap(in, out)
+ FILE *in;
+ gzFile out;
+{
+ int len;
+ int err;
+ int ifd = fileno(in);
+ caddr_t buf; /* mmap'ed buffer for the entire input file */
+ off_t buf_len; /* length of the input file */
+ struct stat sb;
+
+ /* Determine the size of the file, needed for mmap: */
+ if (fstat(ifd, &sb) < 0) return Z_ERRNO;
+ buf_len = sb.st_size;
+ if (buf_len <= 0) return Z_ERRNO;
+
+ /* Now do the actual mmap: */
+ buf = mmap((caddr_t) 0, buf_len, PROT_READ, MAP_SHARED, ifd, (off_t)0);
+ if (buf == (caddr_t)(-1)) return Z_ERRNO;
+
+ /* Compress the whole file at once: */
+ len = gzwrite(out, (char *)buf, (unsigned)buf_len);
+
+ if (len != (int)buf_len) error(gzerror(out, &err));
+
+ munmap(buf, buf_len);
+ fclose(in);
+ if (gzclose(out) != Z_OK) error("failed gzclose");
+ return Z_OK;
+}
+#endif /* USE_MMAP */
+
+/* ===========================================================================
+ * Uncompress input to output then close both files.
+ */
+void gz_uncompress(in, out)
+ gzFile in;
+ FILE *out;
+{
+ local char buf[BUFLEN];
+ int len;
+ int err;
+
+ for (;;) {
+ len = gzread(in, buf, sizeof(buf));
+ if (len < 0) error (gzerror(in, &err));
+ if (len == 0) break;
+
+ if ((int)fwrite(buf, 1, (unsigned)len, out) != len) {
+ error("failed fwrite");
+ }
+ }
+ if (fclose(out)) error("failed fclose");
+
+ if (gzclose(in) != Z_OK) error("failed gzclose");
+}
+
+
+/* ===========================================================================
+ * Compress the given file: create a corresponding .gz file and remove the
+ * original.
+ */
+void file_compress(file, mode)
+ char *file;
+ char *mode;
+{
+ local char outfile[MAX_NAME_LEN];
+ FILE *in;
+ gzFile out;
+
+ if (strlen(file) + strlen(GZ_SUFFIX) >= sizeof(outfile)) {
+ fprintf(stderr, "%s: filename too long\n", prog);
+ exit(1);
+ }
+
+ strcpy(outfile, file);
+ strcat(outfile, GZ_SUFFIX);
+
+ in = fopen(file, "rb");
+ if (in == NULL) {
+ perror(file);
+ exit(1);
+ }
+ out = gzopen(outfile, mode);
+ if (out == NULL) {
+ fprintf(stderr, "%s: can't gzopen %s\n", prog, outfile);
+ exit(1);
+ }
+ gz_compress(in, out);
+
+ unlink(file);
+}
+
+
+/* ===========================================================================
+ * Uncompress the given file and remove the original.
+ */
+void file_uncompress(file)
+ char *file;
+{
+ local char buf[MAX_NAME_LEN];
+ char *infile, *outfile;
+ FILE *out;
+ gzFile in;
+ size_t len = strlen(file);
+
+ if (len + strlen(GZ_SUFFIX) >= sizeof(buf)) {
+ fprintf(stderr, "%s: filename too long\n", prog);
+ exit(1);
+ }
+
+ strcpy(buf, file);
+
+ if (len > SUFFIX_LEN && strcmp(file+len-SUFFIX_LEN, GZ_SUFFIX) == 0) {
+ infile = file;
+ outfile = buf;
+ outfile[len-3] = '\0';
+ } else {
+ outfile = file;
+ infile = buf;
+ strcat(infile, GZ_SUFFIX);
+ }
+ in = gzopen(infile, "rb");
+ if (in == NULL) {
+ fprintf(stderr, "%s: can't gzopen %s\n", prog, infile);
+ exit(1);
+ }
+ out = fopen(outfile, "wb");
+ if (out == NULL) {
+ perror(file);
+ exit(1);
+ }
+
+ gz_uncompress(in, out);
+
+ unlink(infile);
+}
+
+
+/* ===========================================================================
+ * Usage: minigzip [-c] [-d] [-f] [-h] [-r] [-1 to -9] [files...]
+ * -c : write to standard output
+ * -d : decompress
+ * -f : compress with Z_FILTERED
+ * -h : compress with Z_HUFFMAN_ONLY
+ * -r : compress with Z_RLE
+ * -1 to -9 : compression level
+ */
+
+int main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int copyout = 0;
+ int uncompr = 0;
+ gzFile file;
+ char *bname, outmode[20];
+
+ strcpy(outmode, "wb6 ");
+
+ prog = argv[0];
+ bname = strrchr(argv[0], '/');
+ if (bname)
+ bname++;
+ else
+ bname = argv[0];
+ argc--, argv++;
+
+ if (!strcmp(bname, "gunzip"))
+ uncompr = 1;
+ else if (!strcmp(bname, "zcat"))
+ copyout = uncompr = 1;
+
+ while (argc > 0) {
+ if (strcmp(*argv, "-c") == 0)
+ copyout = 1;
+ else if (strcmp(*argv, "-d") == 0)
+ uncompr = 1;
+ else if (strcmp(*argv, "-f") == 0)
+ outmode[3] = 'f';
+ else if (strcmp(*argv, "-h") == 0)
+ outmode[3] = 'h';
+ else if (strcmp(*argv, "-r") == 0)
+ outmode[3] = 'R';
+ else if ((*argv)[0] == '-' && (*argv)[1] >= '1' && (*argv)[1] <= '9' &&
+ (*argv)[2] == 0)
+ outmode[2] = (*argv)[1];
+ else
+ break;
+ argc--, argv++;
+ }
+ if (outmode[3] == ' ')
+ outmode[3] = 0;
+ if (argc == 0) {
+ SET_BINARY_MODE(stdin);
+ SET_BINARY_MODE(stdout);
+ if (uncompr) {
+ file = gzdopen(fileno(stdin), "rb");
+ if (file == NULL) error("can't gzdopen stdin");
+ gz_uncompress(file, stdout);
+ } else {
+ file = gzdopen(fileno(stdout), outmode);
+ if (file == NULL) error("can't gzdopen stdout");
+ gz_compress(stdin, file);
+ }
+ } else {
+ if (copyout) {
+ SET_BINARY_MODE(stdout);
+ }
+ do {
+ if (uncompr) {
+ if (copyout) {
+ file = gzopen(*argv, "rb");
+ if (file == NULL)
+ fprintf(stderr, "%s: can't gzopen %s\n", prog, *argv);
+ else
+ gz_uncompress(file, stdout);
+ } else {
+ file_uncompress(*argv);
+ }
+ } else {
+ if (copyout) {
+ FILE * in = fopen(*argv, "rb");
+
+ if (in == NULL) {
+ perror(*argv);
+ } else {
+ file = gzdopen(fileno(stdout), outmode);
+ if (file == NULL) error("can't gzdopen stdout");
+
+ gz_compress(in, file);
+ }
+
+ } else {
+ file_compress(*argv, outmode);
+ }
+ }
+ } while (argv++, --argc);
+ }
+ return 0;
+}
diff --git a/lib/libz/trees.c b/lib/libz/trees.c
new file mode 100644
index 0000000..395e4e1
--- /dev/null
+++ b/lib/libz/trees.c
@@ -0,0 +1,1219 @@
+/* trees.c -- output deflated data using Huffman coding
+ * Copyright (C) 1995-2005 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * ALGORITHM
+ *
+ * The "deflation" process uses several Huffman trees. The more
+ * common source values are represented by shorter bit sequences.
+ *
+ * Each code tree is stored in a compressed form which is itself
+ * a Huffman encoding of the lengths of all the code strings (in
+ * ascending order by source values). The actual code strings are
+ * reconstructed from the lengths in the inflate process, as described
+ * in the deflate specification.
+ *
+ * REFERENCES
+ *
+ * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification".
+ * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc
+ *
+ * Storer, James A.
+ * Data Compression: Methods and Theory, pp. 49-50.
+ * Computer Science Press, 1988. ISBN 0-7167-8156-5.
+ *
+ * Sedgewick, R.
+ * Algorithms, p290.
+ * Addison-Wesley, 1983. ISBN 0-201-06672-6.
+ */
+
+/* @(#) $Id$ */
+
+/* #define GEN_TREES_H */
+
+#include "deflate.h"
+
+#ifdef DEBUG
+# include <ctype.h>
+#endif
+
+/* ===========================================================================
+ * Constants
+ */
+
+#define MAX_BL_BITS 7
+/* Bit length codes must not exceed MAX_BL_BITS bits */
+
+#define END_BLOCK 256
+/* end of block literal code */
+
+#define REP_3_6 16
+/* repeat previous bit length 3-6 times (2 bits of repeat count) */
+
+#define REPZ_3_10 17
+/* repeat a zero length 3-10 times (3 bits of repeat count) */
+
+#define REPZ_11_138 18
+/* repeat a zero length 11-138 times (7 bits of repeat count) */
+
+local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */
+ = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};
+
+local const int extra_dbits[D_CODES] /* extra bits for each distance code */
+ = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
+
+local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */
+ = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
+
+local const uch bl_order[BL_CODES]
+ = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
+/* The lengths of the bit length codes are sent in order of decreasing
+ * probability, to avoid transmitting the lengths for unused bit length codes.
+ */
+
+#define Buf_size (8 * 2*sizeof(char))
+/* Number of bits used within bi_buf. (bi_buf might be implemented on
+ * more than 16 bits on some systems.)
+ */
+
+/* ===========================================================================
+ * Local data. These are initialized only once.
+ */
+
+#define DIST_CODE_LEN 512 /* see definition of array dist_code below */
+
+#if defined(GEN_TREES_H) || !defined(STDC)
+/* non ANSI compilers may not accept trees.h */
+
+local ct_data static_ltree[L_CODES+2];
+/* The static literal tree. Since the bit lengths are imposed, there is no
+ * need for the L_CODES extra codes used during heap construction. However
+ * The codes 286 and 287 are needed to build a canonical tree (see _tr_init
+ * below).
+ */
+
+local ct_data static_dtree[D_CODES];
+/* The static distance tree. (Actually a trivial tree since all codes use
+ * 5 bits.)
+ */
+
+uch _dist_code[DIST_CODE_LEN];
+/* Distance codes. The first 256 values correspond to the distances
+ * 3 .. 258, the last 256 values correspond to the top 8 bits of
+ * the 15 bit distances.
+ */
+
+uch _length_code[MAX_MATCH-MIN_MATCH+1];
+/* length code for each normalized match length (0 == MIN_MATCH) */
+
+local int base_length[LENGTH_CODES];
+/* First normalized length for each code (0 = MIN_MATCH) */
+
+local int base_dist[D_CODES];
+/* First normalized distance for each code (0 = distance of 1) */
+
+#else
+# include "trees.h"
+#endif /* GEN_TREES_H */
+
+struct static_tree_desc_s {
+ const ct_data *static_tree; /* static tree or NULL */
+ const intf *extra_bits; /* extra bits for each code or NULL */
+ int extra_base; /* base index for extra_bits */
+ int elems; /* max number of elements in the tree */
+ int max_length; /* max bit length for the codes */
+};
+
+local static_tree_desc static_l_desc =
+{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};
+
+local static_tree_desc static_d_desc =
+{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS};
+
+local static_tree_desc static_bl_desc =
+{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS};
+
+/* ===========================================================================
+ * Local (static) routines in this file.
+ */
+
+local void tr_static_init OF((void));
+local void init_block OF((deflate_state *s));
+local void pqdownheap OF((deflate_state *s, ct_data *tree, int k));
+local void gen_bitlen OF((deflate_state *s, tree_desc *desc));
+local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count));
+local void build_tree OF((deflate_state *s, tree_desc *desc));
+local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code));
+local void send_tree OF((deflate_state *s, ct_data *tree, int max_code));
+local int build_bl_tree OF((deflate_state *s));
+local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes,
+ int blcodes));
+local void compress_block OF((deflate_state *s, ct_data *ltree,
+ ct_data *dtree));
+local void set_data_type OF((deflate_state *s));
+local unsigned bi_reverse OF((unsigned value, int length));
+local void bi_windup OF((deflate_state *s));
+local void bi_flush OF((deflate_state *s));
+local void copy_block OF((deflate_state *s, charf *buf, unsigned len,
+ int header));
+
+#ifdef GEN_TREES_H
+local void gen_trees_header OF((void));
+#endif
+
+#ifndef DEBUG
+# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len)
+ /* Send a code of the given tree. c and tree must not have side effects */
+
+#else /* DEBUG */
+# define send_code(s, c, tree) \
+ { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \
+ send_bits(s, tree[c].Code, tree[c].Len); }
+#endif
+
+/* ===========================================================================
+ * Output a short LSB first on the stream.
+ * IN assertion: there is enough room in pendingBuf.
+ */
+#define put_short(s, w) { \
+ put_byte(s, (uch)((w) & 0xff)); \
+ put_byte(s, (uch)((ush)(w) >> 8)); \
+}
+
+/* ===========================================================================
+ * Send a value on a given number of bits.
+ * IN assertion: length <= 16 and value fits in length bits.
+ */
+#ifdef DEBUG
+local void send_bits OF((deflate_state *s, int value, int length));
+
+local void send_bits(s, value, length)
+ deflate_state *s;
+ int value; /* value to send */
+ int length; /* number of bits */
+{
+ Tracevv((stderr," l %2d v %4x ", length, value));
+ Assert(length > 0 && length <= 15, "invalid length");
+ s->bits_sent += (ulg)length;
+
+ /* If not enough room in bi_buf, use (valid) bits from bi_buf and
+ * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
+ * unused bits in value.
+ */
+ if (s->bi_valid > (int)Buf_size - length) {
+ s->bi_buf |= (value << s->bi_valid);
+ put_short(s, s->bi_buf);
+ s->bi_buf = (ush)value >> (Buf_size - s->bi_valid);
+ s->bi_valid += length - Buf_size;
+ } else {
+ s->bi_buf |= value << s->bi_valid;
+ s->bi_valid += length;
+ }
+}
+#else /* !DEBUG */
+
+#define send_bits(s, value, length) \
+{ int len = length;\
+ if (s->bi_valid > (int)Buf_size - len) {\
+ int val = value;\
+ s->bi_buf |= (val << s->bi_valid);\
+ put_short(s, s->bi_buf);\
+ s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\
+ s->bi_valid += len - Buf_size;\
+ } else {\
+ s->bi_buf |= (value) << s->bi_valid;\
+ s->bi_valid += len;\
+ }\
+}
+#endif /* DEBUG */
+
+
+/* the arguments must not have side effects */
+
+/* ===========================================================================
+ * Initialize the various 'constant' tables.
+ */
+local void tr_static_init()
+{
+#if defined(GEN_TREES_H) || !defined(STDC)
+ static int static_init_done = 0;
+ int n; /* iterates over tree elements */
+ int bits; /* bit counter */
+ int length; /* length value */
+ int code; /* code value */
+ int dist; /* distance index */
+ ush bl_count[MAX_BITS+1];
+ /* number of codes at each bit length for an optimal tree */
+
+ if (static_init_done) return;
+
+ /* For some embedded targets, global variables are not initialized: */
+ static_l_desc.static_tree = static_ltree;
+ static_l_desc.extra_bits = extra_lbits;
+ static_d_desc.static_tree = static_dtree;
+ static_d_desc.extra_bits = extra_dbits;
+ static_bl_desc.extra_bits = extra_blbits;
+
+ /* Initialize the mapping length (0..255) -> length code (0..28) */
+ length = 0;
+ for (code = 0; code < LENGTH_CODES-1; code++) {
+ base_length[code] = length;
+ for (n = 0; n < (1<<extra_lbits[code]); n++) {
+ _length_code[length++] = (uch)code;
+ }
+ }
+ Assert (length == 256, "tr_static_init: length != 256");
+ /* Note that the length 255 (match length 258) can be represented
+ * in two different ways: code 284 + 5 bits or code 285, so we
+ * overwrite length_code[255] to use the best encoding:
+ */
+ _length_code[length-1] = (uch)code;
+
+ /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
+ dist = 0;
+ for (code = 0 ; code < 16; code++) {
+ base_dist[code] = dist;
+ for (n = 0; n < (1<<extra_dbits[code]); n++) {
+ _dist_code[dist++] = (uch)code;
+ }
+ }
+ Assert (dist == 256, "tr_static_init: dist != 256");
+ dist >>= 7; /* from now on, all distances are divided by 128 */
+ for ( ; code < D_CODES; code++) {
+ base_dist[code] = dist << 7;
+ for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
+ _dist_code[256 + dist++] = (uch)code;
+ }
+ }
+ Assert (dist == 256, "tr_static_init: 256+dist != 512");
+
+ /* Construct the codes of the static literal tree */
+ for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
+ n = 0;
+ while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
+ while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
+ while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
+ while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;
+ /* Codes 286 and 287 do not exist, but we must include them in the
+ * tree construction to get a canonical Huffman tree (longest code
+ * all ones)
+ */
+ gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count);
+
+ /* The static distance tree is trivial: */
+ for (n = 0; n < D_CODES; n++) {
+ static_dtree[n].Len = 5;
+ static_dtree[n].Code = bi_reverse((unsigned)n, 5);
+ }
+ static_init_done = 1;
+
+# ifdef GEN_TREES_H
+ gen_trees_header();
+# endif
+#endif /* defined(GEN_TREES_H) || !defined(STDC) */
+}
+
+/* ===========================================================================
+ * Genererate the file trees.h describing the static trees.
+ */
+#ifdef GEN_TREES_H
+# ifndef DEBUG
+# include <stdio.h>
+# endif
+
+# define SEPARATOR(i, last, width) \
+ ((i) == (last)? "\n};\n\n" : \
+ ((i) % (width) == (width)-1 ? ",\n" : ", "))
+
+void gen_trees_header()
+{
+ FILE *header = fopen("trees.h", "w");
+ int i;
+
+ Assert (header != NULL, "Can't open trees.h");
+ fprintf(header,
+ "/* header created automatically with -DGEN_TREES_H */\n\n");
+
+ fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n");
+ for (i = 0; i < L_CODES+2; i++) {
+ fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code,
+ static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5));
+ }
+
+ fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n");
+ for (i = 0; i < D_CODES; i++) {
+ fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code,
+ static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5));
+ }
+
+ fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n");
+ for (i = 0; i < DIST_CODE_LEN; i++) {
+ fprintf(header, "%2u%s", _dist_code[i],
+ SEPARATOR(i, DIST_CODE_LEN-1, 20));
+ }
+
+ fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n");
+ for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) {
+ fprintf(header, "%2u%s", _length_code[i],
+ SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20));
+ }
+
+ fprintf(header, "local const int base_length[LENGTH_CODES] = {\n");
+ for (i = 0; i < LENGTH_CODES; i++) {
+ fprintf(header, "%1u%s", base_length[i],
+ SEPARATOR(i, LENGTH_CODES-1, 20));
+ }
+
+ fprintf(header, "local const int base_dist[D_CODES] = {\n");
+ for (i = 0; i < D_CODES; i++) {
+ fprintf(header, "%5u%s", base_dist[i],
+ SEPARATOR(i, D_CODES-1, 10));
+ }
+
+ fclose(header);
+}
+#endif /* GEN_TREES_H */
+
+/* ===========================================================================
+ * Initialize the tree data structures for a new zlib stream.
+ */
+void _tr_init(s)
+ deflate_state *s;
+{
+ tr_static_init();
+
+ s->l_desc.dyn_tree = s->dyn_ltree;
+ s->l_desc.stat_desc = &static_l_desc;
+
+ s->d_desc.dyn_tree = s->dyn_dtree;
+ s->d_desc.stat_desc = &static_d_desc;
+
+ s->bl_desc.dyn_tree = s->bl_tree;
+ s->bl_desc.stat_desc = &static_bl_desc;
+
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+ s->last_eob_len = 8; /* enough lookahead for inflate */
+#ifdef DEBUG
+ s->compressed_len = 0L;
+ s->bits_sent = 0L;
+#endif
+
+ /* Initialize the first block of the first file: */
+ init_block(s);
+}
+
+/* ===========================================================================
+ * Initialize a new block.
+ */
+local void init_block(s)
+ deflate_state *s;
+{
+ int n; /* iterates over tree elements */
+
+ /* Initialize the trees. */
+ for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0;
+ for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0;
+ for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;
+
+ s->dyn_ltree[END_BLOCK].Freq = 1;
+ s->opt_len = s->static_len = 0L;
+ s->last_lit = s->matches = 0;
+}
+
+#define SMALLEST 1
+/* Index within the heap array of least frequent node in the Huffman tree */
+
+
+/* ===========================================================================
+ * Remove the smallest element from the heap and recreate the heap with
+ * one less element. Updates heap and heap_len.
+ */
+#define pqremove(s, tree, top) \
+{\
+ top = s->heap[SMALLEST]; \
+ s->heap[SMALLEST] = s->heap[s->heap_len--]; \
+ pqdownheap(s, tree, SMALLEST); \
+}
+
+/* ===========================================================================
+ * Compares to subtrees, using the tree depth as tie breaker when
+ * the subtrees have equal frequency. This minimizes the worst case length.
+ */
+#define smaller(tree, n, m, depth) \
+ (tree[n].Freq < tree[m].Freq || \
+ (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
+
+/* ===========================================================================
+ * Restore the heap property by moving down the tree starting at node k,
+ * exchanging a node with the smallest of its two sons if necessary, stopping
+ * when the heap property is re-established (each father smaller than its
+ * two sons).
+ */
+local void pqdownheap(s, tree, k)
+ deflate_state *s;
+ ct_data *tree; /* the tree to restore */
+ int k; /* node to move down */
+{
+ int v = s->heap[k];
+ int j = k << 1; /* left son of k */
+ while (j <= s->heap_len) {
+ /* Set j to the smallest of the two sons: */
+ if (j < s->heap_len &&
+ smaller(tree, s->heap[j+1], s->heap[j], s->depth)) {
+ j++;
+ }
+ /* Exit if v is smaller than both sons */
+ if (smaller(tree, v, s->heap[j], s->depth)) break;
+
+ /* Exchange v with the smallest son */
+ s->heap[k] = s->heap[j]; k = j;
+
+ /* And continue down the tree, setting j to the left son of k */
+ j <<= 1;
+ }
+ s->heap[k] = v;
+}
+
+/* ===========================================================================
+ * Compute the optimal bit lengths for a tree and update the total bit length
+ * for the current block.
+ * IN assertion: the fields freq and dad are set, heap[heap_max] and
+ * above are the tree nodes sorted by increasing frequency.
+ * OUT assertions: the field len is set to the optimal bit length, the
+ * array bl_count contains the frequencies for each bit length.
+ * The length opt_len is updated; static_len is also updated if stree is
+ * not null.
+ */
+local void gen_bitlen(s, desc)
+ deflate_state *s;
+ tree_desc *desc; /* the tree descriptor */
+{
+ ct_data *tree = desc->dyn_tree;
+ int max_code = desc->max_code;
+ const ct_data *stree = desc->stat_desc->static_tree;
+ const intf *extra = desc->stat_desc->extra_bits;
+ int base = desc->stat_desc->extra_base;
+ int max_length = desc->stat_desc->max_length;
+ int h; /* heap index */
+ int n, m; /* iterate over the tree elements */
+ int bits; /* bit length */
+ int xbits; /* extra bits */
+ ush f; /* frequency */
+ int overflow = 0; /* number of elements with bit length too large */
+
+ for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0;
+
+ /* In a first pass, compute the optimal bit lengths (which may
+ * overflow in the case of the bit length tree).
+ */
+ tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */
+
+ for (h = s->heap_max+1; h < HEAP_SIZE; h++) {
+ n = s->heap[h];
+ bits = tree[tree[n].Dad].Len + 1;
+ if (bits > max_length) bits = max_length, overflow++;
+ tree[n].Len = (ush)bits;
+ /* We overwrite tree[n].Dad which is no longer needed */
+
+ if (n > max_code) continue; /* not a leaf node */
+
+ s->bl_count[bits]++;
+ xbits = 0;
+ if (n >= base) xbits = extra[n-base];
+ f = tree[n].Freq;
+ s->opt_len += (ulg)f * (bits + xbits);
+ if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits);
+ }
+ if (overflow == 0) return;
+
+ Trace((stderr,"\nbit length overflow\n"));
+ /* This happens for example on obj2 and pic of the Calgary corpus */
+
+ /* Find the first bit length which could increase: */
+ do {
+ bits = max_length-1;
+ while (s->bl_count[bits] == 0) bits--;
+ s->bl_count[bits]--; /* move one leaf down the tree */
+ s->bl_count[bits+1] += 2; /* move one overflow item as its brother */
+ s->bl_count[max_length]--;
+ /* The brother of the overflow item also moves one step up,
+ * but this does not affect bl_count[max_length]
+ */
+ overflow -= 2;
+ } while (overflow > 0);
+
+ /* Now recompute all bit lengths, scanning in increasing frequency.
+ * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
+ * lengths instead of fixing only the wrong ones. This idea is taken
+ * from 'ar' written by Haruhiko Okumura.)
+ */
+ for (bits = max_length; bits != 0; bits--) {
+ n = s->bl_count[bits];
+ while (n != 0) {
+ m = s->heap[--h];
+ if (m > max_code) continue;
+ if ((unsigned) tree[m].Len != (unsigned) bits) {
+ Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
+ s->opt_len += ((long)bits - (long)tree[m].Len)
+ *(long)tree[m].Freq;
+ tree[m].Len = (ush)bits;
+ }
+ n--;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Generate the codes for a given tree and bit counts (which need not be
+ * optimal).
+ * IN assertion: the array bl_count contains the bit length statistics for
+ * the given tree and the field len is set for all tree elements.
+ * OUT assertion: the field code is set for all tree elements of non
+ * zero code length.
+ */
+local void gen_codes (tree, max_code, bl_count)
+ ct_data *tree; /* the tree to decorate */
+ int max_code; /* largest code with non zero frequency */
+ ushf *bl_count; /* number of codes at each bit length */
+{
+ ush next_code[MAX_BITS+1]; /* next code value for each bit length */
+ ush code = 0; /* running code value */
+ int bits; /* bit index */
+ int n; /* code index */
+
+ /* The distribution counts are first used to generate the code values
+ * without bit reversal.
+ */
+ for (bits = 1; bits <= MAX_BITS; bits++) {
+ next_code[bits] = code = (code + bl_count[bits-1]) << 1;
+ }
+ /* Check that the bit counts in bl_count are consistent. The last code
+ * must be all ones.
+ */
+ Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
+ "inconsistent bit counts");
+ Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
+
+ for (n = 0; n <= max_code; n++) {
+ int len = tree[n].Len;
+ if (len == 0) continue;
+ /* Now reverse the bits */
+ tree[n].Code = bi_reverse(next_code[len]++, len);
+
+ Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
+ n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
+ }
+}
+
+/* ===========================================================================
+ * Construct one Huffman tree and assigns the code bit strings and lengths.
+ * Update the total bit length for the current block.
+ * IN assertion: the field freq is set for all tree elements.
+ * OUT assertions: the fields len and code are set to the optimal bit length
+ * and corresponding code. The length opt_len is updated; static_len is
+ * also updated if stree is not null. The field max_code is set.
+ */
+local void build_tree(s, desc)
+ deflate_state *s;
+ tree_desc *desc; /* the tree descriptor */
+{
+ ct_data *tree = desc->dyn_tree;
+ const ct_data *stree = desc->stat_desc->static_tree;
+ int elems = desc->stat_desc->elems;
+ int n, m; /* iterate over heap elements */
+ int max_code = -1; /* largest code with non zero frequency */
+ int node; /* new node being created */
+
+ /* Construct the initial heap, with least frequent element in
+ * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
+ * heap[0] is not used.
+ */
+ s->heap_len = 0, s->heap_max = HEAP_SIZE;
+
+ for (n = 0; n < elems; n++) {
+ if (tree[n].Freq != 0) {
+ s->heap[++(s->heap_len)] = max_code = n;
+ s->depth[n] = 0;
+ } else {
+ tree[n].Len = 0;
+ }
+ }
+
+ /* The pkzip format requires that at least one distance code exists,
+ * and that at least one bit should be sent even if there is only one
+ * possible code. So to avoid special checks later on we force at least
+ * two codes of non zero frequency.
+ */
+ while (s->heap_len < 2) {
+ node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0);
+ tree[node].Freq = 1;
+ s->depth[node] = 0;
+ s->opt_len--; if (stree) s->static_len -= stree[node].Len;
+ /* node is 0 or 1 so it does not have extra bits */
+ }
+ desc->max_code = max_code;
+
+ /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
+ * establish sub-heaps of increasing lengths:
+ */
+ for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n);
+
+ /* Construct the Huffman tree by repeatedly combining the least two
+ * frequent nodes.
+ */
+ node = elems; /* next internal node of the tree */
+ do {
+ pqremove(s, tree, n); /* n = node of least frequency */
+ m = s->heap[SMALLEST]; /* m = node of next least frequency */
+
+ s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */
+ s->heap[--(s->heap_max)] = m;
+
+ /* Create a new node father of n and m */
+ tree[node].Freq = tree[n].Freq + tree[m].Freq;
+ s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ?
+ s->depth[n] : s->depth[m]) + 1);
+ tree[n].Dad = tree[m].Dad = (ush)node;
+#ifdef DUMP_BL_TREE
+ if (tree == s->bl_tree) {
+ fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)",
+ node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
+ }
+#endif
+ /* and insert the new node in the heap */
+ s->heap[SMALLEST] = node++;
+ pqdownheap(s, tree, SMALLEST);
+
+ } while (s->heap_len >= 2);
+
+ s->heap[--(s->heap_max)] = s->heap[SMALLEST];
+
+ /* At this point, the fields freq and dad are set. We can now
+ * generate the bit lengths.
+ */
+ gen_bitlen(s, (tree_desc *)desc);
+
+ /* The field len is now set, we can generate the bit codes */
+ gen_codes ((ct_data *)tree, max_code, s->bl_count);
+}
+
+/* ===========================================================================
+ * Scan a literal or distance tree to determine the frequencies of the codes
+ * in the bit length tree.
+ */
+local void scan_tree (s, tree, max_code)
+ deflate_state *s;
+ ct_data *tree; /* the tree to be scanned */
+ int max_code; /* and its largest code of non zero frequency */
+{
+ int n; /* iterates over all tree elements */
+ int prevlen = -1; /* last emitted length */
+ int curlen; /* length of current code */
+ int nextlen = tree[0].Len; /* length of next code */
+ int count = 0; /* repeat count of the current code */
+ int max_count = 7; /* max repeat count */
+ int min_count = 4; /* min repeat count */
+
+ if (nextlen == 0) max_count = 138, min_count = 3;
+ tree[max_code+1].Len = (ush)0xffff; /* guard */
+
+ for (n = 0; n <= max_code; n++) {
+ curlen = nextlen; nextlen = tree[n+1].Len;
+ if (++count < max_count && curlen == nextlen) {
+ continue;
+ } else if (count < min_count) {
+ s->bl_tree[curlen].Freq += count;
+ } else if (curlen != 0) {
+ if (curlen != prevlen) s->bl_tree[curlen].Freq++;
+ s->bl_tree[REP_3_6].Freq++;
+ } else if (count <= 10) {
+ s->bl_tree[REPZ_3_10].Freq++;
+ } else {
+ s->bl_tree[REPZ_11_138].Freq++;
+ }
+ count = 0; prevlen = curlen;
+ if (nextlen == 0) {
+ max_count = 138, min_count = 3;
+ } else if (curlen == nextlen) {
+ max_count = 6, min_count = 3;
+ } else {
+ max_count = 7, min_count = 4;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Send a literal or distance tree in compressed form, using the codes in
+ * bl_tree.
+ */
+local void send_tree (s, tree, max_code)
+ deflate_state *s;
+ ct_data *tree; /* the tree to be scanned */
+ int max_code; /* and its largest code of non zero frequency */
+{
+ int n; /* iterates over all tree elements */
+ int prevlen = -1; /* last emitted length */
+ int curlen; /* length of current code */
+ int nextlen = tree[0].Len; /* length of next code */
+ int count = 0; /* repeat count of the current code */
+ int max_count = 7; /* max repeat count */
+ int min_count = 4; /* min repeat count */
+
+ /* tree[max_code+1].Len = -1; */ /* guard already set */
+ if (nextlen == 0) max_count = 138, min_count = 3;
+
+ for (n = 0; n <= max_code; n++) {
+ curlen = nextlen; nextlen = tree[n+1].Len;
+ if (++count < max_count && curlen == nextlen) {
+ continue;
+ } else if (count < min_count) {
+ do { send_code(s, curlen, s->bl_tree); } while (--count != 0);
+
+ } else if (curlen != 0) {
+ if (curlen != prevlen) {
+ send_code(s, curlen, s->bl_tree); count--;
+ }
+ Assert(count >= 3 && count <= 6, " 3_6?");
+ send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2);
+
+ } else if (count <= 10) {
+ send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3);
+
+ } else {
+ send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7);
+ }
+ count = 0; prevlen = curlen;
+ if (nextlen == 0) {
+ max_count = 138, min_count = 3;
+ } else if (curlen == nextlen) {
+ max_count = 6, min_count = 3;
+ } else {
+ max_count = 7, min_count = 4;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Construct the Huffman tree for the bit lengths and return the index in
+ * bl_order of the last bit length code to send.
+ */
+local int build_bl_tree(s)
+ deflate_state *s;
+{
+ int max_blindex; /* index of last bit length code of non zero freq */
+
+ /* Determine the bit length frequencies for literal and distance trees */
+ scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code);
+ scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code);
+
+ /* Build the bit length tree: */
+ build_tree(s, (tree_desc *)(&(s->bl_desc)));
+ /* opt_len now includes the length of the tree representations, except
+ * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
+ */
+
+ /* Determine the number of bit length codes to send. The pkzip format
+ * requires that at least 4 bit length codes be sent. (appnote.txt says
+ * 3 but the actual value used is 4.)
+ */
+ for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
+ if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;
+ }
+ /* Update opt_len to include the bit length tree and counts */
+ s->opt_len += 3*(max_blindex+1) + 5+5+4;
+ Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
+ s->opt_len, s->static_len));
+
+ return max_blindex;
+}
+
+/* ===========================================================================
+ * Send the header for a block using dynamic Huffman trees: the counts, the
+ * lengths of the bit length codes, the literal tree and the distance tree.
+ * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
+ */
+local void send_all_trees(s, lcodes, dcodes, blcodes)
+ deflate_state *s;
+ int lcodes, dcodes, blcodes; /* number of codes for each tree */
+{
+ int rank; /* index in bl_order */
+
+ Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
+ Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
+ "too many codes");
+ Tracev((stderr, "\nbl counts: "));
+ send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */
+ send_bits(s, dcodes-1, 5);
+ send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */
+ for (rank = 0; rank < blcodes; rank++) {
+ Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
+ send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);
+ }
+ Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
+
+ send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */
+ Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
+
+ send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */
+ Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
+}
+
+/* ===========================================================================
+ * Send a stored block
+ */
+void _tr_stored_block(s, buf, stored_len, eof)
+ deflate_state *s;
+ charf *buf; /* input block */
+ ulg stored_len; /* length of input block */
+ int eof; /* true if this is the last block for a file */
+{
+ send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */
+#ifdef DEBUG
+ s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;
+ s->compressed_len += (stored_len + 4) << 3;
+#endif
+ copy_block(s, buf, (unsigned)stored_len, 1); /* with header */
+}
+
+/* ===========================================================================
+ * Send one empty static block to give enough lookahead for inflate.
+ * This takes 10 bits, of which 7 may remain in the bit buffer.
+ * The current inflate code requires 9 bits of lookahead. If the
+ * last two codes for the previous block (real code plus EOB) were coded
+ * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
+ * the last real code. In this case we send two empty static blocks instead
+ * of one. (There are no problems if the previous block is stored or fixed.)
+ * To simplify the code, we assume the worst case of last real code encoded
+ * on one bit only.
+ */
+void _tr_align(s)
+ deflate_state *s;
+{
+ send_bits(s, STATIC_TREES<<1, 3);
+ send_code(s, END_BLOCK, static_ltree);
+#ifdef DEBUG
+ s->compressed_len += 10L; /* 3 for block type, 7 for EOB */
+#endif
+ bi_flush(s);
+ /* Of the 10 bits for the empty block, we have already sent
+ * (10 - bi_valid) bits. The lookahead for the last real code (before
+ * the EOB of the previous block) was thus at least one plus the length
+ * of the EOB plus what we have just sent of the empty static block.
+ */
+ if (1 + s->last_eob_len + 10 - s->bi_valid < 9) {
+ send_bits(s, STATIC_TREES<<1, 3);
+ send_code(s, END_BLOCK, static_ltree);
+#ifdef DEBUG
+ s->compressed_len += 10L;
+#endif
+ bi_flush(s);
+ }
+ s->last_eob_len = 7;
+}
+
+/* ===========================================================================
+ * Determine the best encoding for the current block: dynamic trees, static
+ * trees or store, and output the encoded block to the zip file.
+ */
+void _tr_flush_block(s, buf, stored_len, eof)
+ deflate_state *s;
+ charf *buf; /* input block, or NULL if too old */
+ ulg stored_len; /* length of input block */
+ int eof; /* true if this is the last block for a file */
+{
+ ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
+ int max_blindex = 0; /* index of last bit length code of non zero freq */
+
+ /* Build the Huffman trees unless a stored block is forced */
+ if (s->level > 0) {
+
+ /* Check if the file is binary or text */
+ if (stored_len > 0 && s->strm->data_type == Z_UNKNOWN)
+ set_data_type(s);
+
+ /* Construct the literal and distance trees */
+ build_tree(s, (tree_desc *)(&(s->l_desc)));
+ Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
+ s->static_len));
+
+ build_tree(s, (tree_desc *)(&(s->d_desc)));
+ Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
+ s->static_len));
+ /* At this point, opt_len and static_len are the total bit lengths of
+ * the compressed block data, excluding the tree representations.
+ */
+
+ /* Build the bit length tree for the above two trees, and get the index
+ * in bl_order of the last bit length code to send.
+ */
+ max_blindex = build_bl_tree(s);
+
+ /* Determine the best encoding. Compute the block lengths in bytes. */
+ opt_lenb = (s->opt_len+3+7)>>3;
+ static_lenb = (s->static_len+3+7)>>3;
+
+ Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
+ opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
+ s->last_lit));
+
+ if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
+
+ } else {
+ Assert(buf != (char*)0, "lost buf");
+ opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
+ }
+
+#ifdef FORCE_STORED
+ if (buf != (char*)0) { /* force stored block */
+#else
+ if (stored_len+4 <= opt_lenb && buf != (char*)0) {
+ /* 4: two words for the lengths */
+#endif
+ /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
+ * Otherwise we can't have processed more than WSIZE input bytes since
+ * the last block flush, because compression would have been
+ * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+ * transform a block into a stored block.
+ */
+ _tr_stored_block(s, buf, stored_len, eof);
+
+#ifdef FORCE_STATIC
+ } else if (static_lenb >= 0) { /* force static trees */
+#else
+ } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) {
+#endif
+ send_bits(s, (STATIC_TREES<<1)+eof, 3);
+ compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree);
+#ifdef DEBUG
+ s->compressed_len += 3 + s->static_len;
+#endif
+ } else {
+ send_bits(s, (DYN_TREES<<1)+eof, 3);
+ send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1,
+ max_blindex+1);
+ compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree);
+#ifdef DEBUG
+ s->compressed_len += 3 + s->opt_len;
+#endif
+ }
+ Assert (s->compressed_len == s->bits_sent, "bad compressed size");
+ /* The above check is made mod 2^32, for files larger than 512 MB
+ * and uLong implemented on 32 bits.
+ */
+ init_block(s);
+
+ if (eof) {
+ bi_windup(s);
+#ifdef DEBUG
+ s->compressed_len += 7; /* align on byte boundary */
+#endif
+ }
+ Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
+ s->compressed_len-7*eof));
+}
+
+/* ===========================================================================
+ * Save the match info and tally the frequency counts. Return true if
+ * the current block must be flushed.
+ */
+int _tr_tally (s, dist, lc)
+ deflate_state *s;
+ unsigned dist; /* distance of matched string */
+ unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */
+{
+ s->d_buf[s->last_lit] = (ush)dist;
+ s->l_buf[s->last_lit++] = (uch)lc;
+ if (dist == 0) {
+ /* lc is the unmatched char */
+ s->dyn_ltree[lc].Freq++;
+ } else {
+ s->matches++;
+ /* Here, lc is the match length - MIN_MATCH */
+ dist--; /* dist = match distance - 1 */
+ Assert((ush)dist < (ush)MAX_DIST(s) &&
+ (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
+ (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match");
+
+ s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++;
+ s->dyn_dtree[d_code(dist)].Freq++;
+ }
+
+#ifdef TRUNCATE_BLOCK
+ /* Try to guess if it is profitable to stop the current block here */
+ if ((s->last_lit & 0x1fff) == 0 && s->level > 2) {
+ /* Compute an upper bound for the compressed length */
+ ulg out_length = (ulg)s->last_lit*8L;
+ ulg in_length = (ulg)((long)s->strstart - s->block_start);
+ int dcode;
+ for (dcode = 0; dcode < D_CODES; dcode++) {
+ out_length += (ulg)s->dyn_dtree[dcode].Freq *
+ (5L+extra_dbits[dcode]);
+ }
+ out_length >>= 3;
+ Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
+ s->last_lit, in_length, out_length,
+ 100L - out_length*100L/in_length));
+ if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;
+ }
+#endif
+ return (s->last_lit == s->lit_bufsize-1);
+ /* We avoid equality with lit_bufsize because of wraparound at 64K
+ * on 16 bit machines and because stored blocks are restricted to
+ * 64K-1 bytes.
+ */
+}
+
+/* ===========================================================================
+ * Send the block data compressed using the given Huffman trees
+ */
+local void compress_block(s, ltree, dtree)
+ deflate_state *s;
+ ct_data *ltree; /* literal tree */
+ ct_data *dtree; /* distance tree */
+{
+ unsigned dist; /* distance of matched string */
+ int lc; /* match length or unmatched char (if dist == 0) */
+ unsigned lx = 0; /* running index in l_buf */
+ unsigned code; /* the code to send */
+ int extra; /* number of extra bits to send */
+
+ if (s->last_lit != 0) do {
+ dist = s->d_buf[lx];
+ lc = s->l_buf[lx++];
+ if (dist == 0) {
+ send_code(s, lc, ltree); /* send a literal byte */
+ Tracecv(isgraph(lc), (stderr," '%c' ", lc));
+ } else {
+ /* Here, lc is the match length - MIN_MATCH */
+ code = _length_code[lc];
+ send_code(s, code+LITERALS+1, ltree); /* send the length code */
+ extra = extra_lbits[code];
+ if (extra != 0) {
+ lc -= base_length[code];
+ send_bits(s, lc, extra); /* send the extra length bits */
+ }
+ dist--; /* dist is now the match distance - 1 */
+ code = d_code(dist);
+ Assert (code < D_CODES, "bad d_code");
+
+ send_code(s, code, dtree); /* send the distance code */
+ extra = extra_dbits[code];
+ if (extra != 0) {
+ dist -= base_dist[code];
+ send_bits(s, dist, extra); /* send the extra distance bits */
+ }
+ } /* literal or match pair ? */
+
+ /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
+ Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx,
+ "pendingBuf overflow");
+
+ } while (lx < s->last_lit);
+
+ send_code(s, END_BLOCK, ltree);
+ s->last_eob_len = ltree[END_BLOCK].Len;
+}
+
+/* ===========================================================================
+ * Set the data type to BINARY or TEXT, using a crude approximation:
+ * set it to Z_TEXT if all symbols are either printable characters (33 to 255)
+ * or white spaces (9 to 13, or 32); or set it to Z_BINARY otherwise.
+ * IN assertion: the fields Freq of dyn_ltree are set.
+ */
+local void set_data_type(s)
+ deflate_state *s;
+{
+ int n;
+
+ for (n = 0; n < 9; n++)
+ if (s->dyn_ltree[n].Freq != 0)
+ break;
+ if (n == 9)
+ for (n = 14; n < 32; n++)
+ if (s->dyn_ltree[n].Freq != 0)
+ break;
+ s->strm->data_type = (n == 32) ? Z_TEXT : Z_BINARY;
+}
+
+/* ===========================================================================
+ * Reverse the first len bits of a code, using straightforward code (a faster
+ * method would use a table)
+ * IN assertion: 1 <= len <= 15
+ */
+local unsigned bi_reverse(code, len)
+ unsigned code; /* the value to invert */
+ int len; /* its bit length */
+{
+ register unsigned res = 0;
+ do {
+ res |= code & 1;
+ code >>= 1, res <<= 1;
+ } while (--len > 0);
+ return res >> 1;
+}
+
+/* ===========================================================================
+ * Flush the bit buffer, keeping at most 7 bits in it.
+ */
+local void bi_flush(s)
+ deflate_state *s;
+{
+ if (s->bi_valid == 16) {
+ put_short(s, s->bi_buf);
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+ } else if (s->bi_valid >= 8) {
+ put_byte(s, (Byte)s->bi_buf);
+ s->bi_buf >>= 8;
+ s->bi_valid -= 8;
+ }
+}
+
+/* ===========================================================================
+ * Flush the bit buffer and align the output on a byte boundary
+ */
+local void bi_windup(s)
+ deflate_state *s;
+{
+ if (s->bi_valid > 8) {
+ put_short(s, s->bi_buf);
+ } else if (s->bi_valid > 0) {
+ put_byte(s, (Byte)s->bi_buf);
+ }
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+#ifdef DEBUG
+ s->bits_sent = (s->bits_sent+7) & ~7;
+#endif
+}
+
+/* ===========================================================================
+ * Copy a stored block, storing first the length and its
+ * one's complement if requested.
+ */
+local void copy_block(s, buf, len, header)
+ deflate_state *s;
+ charf *buf; /* the input data */
+ unsigned len; /* its length */
+ int header; /* true if block header must be written */
+{
+ bi_windup(s); /* align on byte boundary */
+ s->last_eob_len = 8; /* enough lookahead for inflate */
+
+ if (header) {
+ put_short(s, (ush)len);
+ put_short(s, (ush)~len);
+#ifdef DEBUG
+ s->bits_sent += 2*16;
+#endif
+ }
+#ifdef DEBUG
+ s->bits_sent += (ulg)len<<3;
+#endif
+ while (len--) {
+ put_byte(s, *buf++);
+ }
+}
diff --git a/lib/libz/trees.h b/lib/libz/trees.h
new file mode 100644
index 0000000..72facf9
--- /dev/null
+++ b/lib/libz/trees.h
@@ -0,0 +1,128 @@
+/* header created automatically with -DGEN_TREES_H */
+
+local const ct_data static_ltree[L_CODES+2] = {
+{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}},
+{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}},
+{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}},
+{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}},
+{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}},
+{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}},
+{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}},
+{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}},
+{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}},
+{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}},
+{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}},
+{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}},
+{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}},
+{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}},
+{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}},
+{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}},
+{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}},
+{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}},
+{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}},
+{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}},
+{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}},
+{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}},
+{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}},
+{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}},
+{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}},
+{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}},
+{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}},
+{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}},
+{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}},
+{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}},
+{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}},
+{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}},
+{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}},
+{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}},
+{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}},
+{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}},
+{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}},
+{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}},
+{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}},
+{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}},
+{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}},
+{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}},
+{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}},
+{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}},
+{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}},
+{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}},
+{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}},
+{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}},
+{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}},
+{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}},
+{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}},
+{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}},
+{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}},
+{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}},
+{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}},
+{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}},
+{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}},
+{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}}
+};
+
+local const ct_data static_dtree[D_CODES] = {
+{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}},
+{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}},
+{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}},
+{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}},
+{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}},
+{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}}
+};
+
+const uch _dist_code[DIST_CODE_LEN] = {
+ 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8,
+ 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10,
+10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17,
+18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29
+};
+
+const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12,
+13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16,
+17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19,
+19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22,
+22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28
+};
+
+local const int base_length[LENGTH_CODES] = {
+0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56,
+64, 80, 96, 112, 128, 160, 192, 224, 0
+};
+
+local const int base_dist[D_CODES] = {
+ 0, 1, 2, 3, 4, 6, 8, 12, 16, 24,
+ 32, 48, 64, 96, 128, 192, 256, 384, 512, 768,
+ 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576
+};
+
diff --git a/lib/libz/uncompr.c b/lib/libz/uncompr.c
new file mode 100644
index 0000000..b59e3d0
--- /dev/null
+++ b/lib/libz/uncompr.c
@@ -0,0 +1,61 @@
+/* uncompr.c -- decompress a memory buffer
+ * Copyright (C) 1995-2003 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+/* ===========================================================================
+ Decompresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total
+ size of the destination buffer, which must be large enough to hold the
+ entire uncompressed data. (The size of the uncompressed data must have
+ been saved previously by the compressor and transmitted to the decompressor
+ by some mechanism outside the scope of this compression library.)
+ Upon exit, destLen is the actual size of the compressed buffer.
+ This function can be used to decompress a whole file at once if the
+ input file is mmap'ed.
+
+ uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer, or Z_DATA_ERROR if the input data was corrupted.
+*/
+int ZEXPORT uncompress (dest, destLen, source, sourceLen)
+ Bytef *dest;
+ uLongf *destLen;
+ const Bytef *source;
+ uLong sourceLen;
+{
+ z_stream stream;
+ int err;
+
+ stream.next_in = (Bytef*)source;
+ stream.avail_in = (uInt)sourceLen;
+ /* Check for source > 64K on 16-bit machine: */
+ if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
+
+ stream.next_out = dest;
+ stream.avail_out = (uInt)*destLen;
+ if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
+
+ stream.zalloc = (alloc_func)0;
+ stream.zfree = (free_func)0;
+
+ err = inflateInit(&stream);
+ if (err != Z_OK) return err;
+
+ err = inflate(&stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ inflateEnd(&stream);
+ if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0))
+ return Z_DATA_ERROR;
+ return err;
+ }
+ *destLen = stream.total_out;
+
+ err = inflateEnd(&stream);
+ return err;
+}
diff --git a/lib/libz/zconf.h b/lib/libz/zconf.h
new file mode 100644
index 0000000..205db95
--- /dev/null
+++ b/lib/libz/zconf.h
@@ -0,0 +1,341 @@
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $FreeBSD$ */
+
+#ifndef ZCONF_H
+#define ZCONF_H
+
+/*
+ * If you *really* need a unique prefix for all types and library functions,
+ * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
+ */
+#ifdef Z_PREFIX
+# define deflateInit_ z_deflateInit_
+# define deflate z_deflate
+# define deflateEnd z_deflateEnd
+# define inflateInit_ z_inflateInit_
+# define inflate z_inflate
+# define inflateEnd z_inflateEnd
+# define deflateInit2_ z_deflateInit2_
+# define deflateSetDictionary z_deflateSetDictionary
+# define deflateCopy z_deflateCopy
+# define deflateReset z_deflateReset
+# define deflateParams z_deflateParams
+# define deflateBound z_deflateBound
+# define deflatePrime z_deflatePrime
+# define inflateInit2_ z_inflateInit2_
+# define inflateSetDictionary z_inflateSetDictionary
+# define inflateSync z_inflateSync
+# define inflateSyncPoint z_inflateSyncPoint
+# define inflateCopy z_inflateCopy
+# define inflateReset z_inflateReset
+# define inflateBack z_inflateBack
+# define inflateBackEnd z_inflateBackEnd
+# define compress z_compress
+# define compress2 z_compress2
+# define compressBound z_compressBound
+# define uncompress z_uncompress
+# define adler32 z_adler32
+# define crc32 z_crc32
+# define get_crc_table z_get_crc_table
+# define zError z_zError
+
+# define alloc_func z_alloc_func
+# define free_func z_free_func
+# define in_func z_in_func
+# define out_func z_out_func
+# define Byte z_Byte
+# define uInt z_uInt
+# define uLong z_uLong
+# define Bytef z_Bytef
+# define charf z_charf
+# define intf z_intf
+# define uIntf z_uIntf
+# define uLongf z_uLongf
+# define voidpf z_voidpf
+# define voidp z_voidp
+#endif
+
+#if defined(__MSDOS__) && !defined(MSDOS)
+# define MSDOS
+#endif
+#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)
+# define OS2
+#endif
+#if defined(_WINDOWS) && !defined(WINDOWS)
+# define WINDOWS
+#endif
+#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)
+# ifndef WIN32
+# define WIN32
+# endif
+#endif
+#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)
+# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)
+# ifndef SYS16BIT
+# define SYS16BIT
+# endif
+# endif
+#endif
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ */
+#ifdef SYS16BIT
+# define MAXSEG_64K
+#endif
+#ifdef MSDOS
+# define UNALIGNED_OK
+#endif
+
+#ifdef __STDC_VERSION__
+# ifndef STDC
+# define STDC
+# endif
+# if __STDC_VERSION__ >= 199901L
+# ifndef STDC99
+# define STDC99
+# endif
+# endif
+#endif
+#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))
+# define STDC
+#endif
+#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))
+# define STDC
+#endif
+#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
+# define STDC
+#endif
+#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))
+# define STDC
+#endif
+
+#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */
+# define STDC
+#endif
+
+#ifndef STDC
+# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
+# define const /* note: need a more gentle solution here */
+# endif
+#endif
+
+/* Some Mac compilers merge all .h files incorrectly: */
+#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
+# define NO_DUMMY_DECL
+#endif
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+# ifdef MAXSEG_64K
+# define MAX_MEM_LEVEL 8
+# else
+# define MAX_MEM_LEVEL 9
+# endif
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2.
+ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
+ * created by gzip. (Files created by minigzip can still be extracted by
+ * gzip.)
+ */
+#ifndef MAX_WBITS
+# define MAX_WBITS 15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+ (1 << (windowBits+2)) + (1 << (memLevel+9))
+ that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+ make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+ The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+ /* Type declarations */
+
+#ifndef OF /* function prototypes */
+# ifdef STDC
+# define OF(args) args
+# else
+# define OF(args) ()
+# endif
+#endif
+
+/* The following definitions for FAR are needed only for MSDOS mixed
+ * model programming (small or medium model with some far allocations).
+ * This was tested only with MSC; for other MSDOS compilers you may have
+ * to define NO_MEMCPY in zutil.h. If you don't need the mixed model,
+ * just define FAR to be empty.
+ */
+#ifdef SYS16BIT
+# if defined(M_I86SM) || defined(M_I86MM)
+ /* MSC small or medium model */
+# define SMALL_MEDIUM
+# ifdef _MSC_VER
+# define FAR _far
+# else
+# define FAR far
+# endif
+# endif
+# if (defined(__SMALL__) || defined(__MEDIUM__))
+ /* Turbo C small or medium model */
+# define SMALL_MEDIUM
+# ifdef __BORLANDC__
+# define FAR _far
+# else
+# define FAR far
+# endif
+# endif
+#endif
+
+#if defined(WINDOWS) || defined(WIN32)
+ /* If building or using zlib as a DLL, define ZLIB_DLL.
+ * This is not mandatory, but it offers a little performance increase.
+ */
+# ifdef ZLIB_DLL
+# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))
+# ifdef ZLIB_INTERNAL
+# define ZEXTERN extern __declspec(dllexport)
+# else
+# define ZEXTERN extern __declspec(dllimport)
+# endif
+# endif
+# endif /* ZLIB_DLL */
+ /* If building or using zlib with the WINAPI/WINAPIV calling convention,
+ * define ZLIB_WINAPI.
+ * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
+ */
+# ifdef ZLIB_WINAPI
+# ifdef FAR
+# undef FAR
+# endif
+# include <windows.h>
+ /* No need for _export, use ZLIB.DEF instead. */
+ /* For complete Windows compatibility, use WINAPI, not __stdcall. */
+# define ZEXPORT WINAPI
+# ifdef WIN32
+# define ZEXPORTVA WINAPIV
+# else
+# define ZEXPORTVA FAR CDECL
+# endif
+# endif
+#endif
+
+#if defined (__BEOS__)
+# ifdef ZLIB_DLL
+# ifdef ZLIB_INTERNAL
+# define ZEXPORT __declspec(dllexport)
+# define ZEXPORTVA __declspec(dllexport)
+# else
+# define ZEXPORT __declspec(dllimport)
+# define ZEXPORTVA __declspec(dllimport)
+# endif
+# endif
+#endif
+
+#ifndef ZEXTERN
+# define ZEXTERN extern
+#endif
+#ifndef ZEXPORT
+# define ZEXPORT
+#endif
+#ifndef ZEXPORTVA
+# define ZEXPORTVA
+#endif
+
+#ifndef FAR
+# define FAR
+#endif
+
+#if !defined(__MACTYPES__)
+typedef unsigned char Byte; /* 8 bits */
+#endif
+typedef unsigned int uInt; /* 16 bits or more */
+typedef unsigned long uLong; /* 32 bits or more */
+
+#ifdef SMALL_MEDIUM
+ /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
+# define Bytef Byte FAR
+#else
+ typedef Byte FAR Bytef;
+#endif
+typedef char FAR charf;
+typedef int FAR intf;
+typedef uInt FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+ typedef void const *voidpc;
+ typedef void FAR *voidpf;
+ typedef void *voidp;
+#else
+ typedef Byte const *voidpc;
+ typedef Byte FAR *voidpf;
+ typedef Byte *voidp;
+#endif
+
+#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */
+# include <sys/types.h> /* for off_t */
+# include <unistd.h> /* for SEEK_* and off_t */
+# ifdef VMS
+# include <unixio.h> /* for off_t */
+# endif
+# define z_off_t off_t
+#endif
+#ifndef SEEK_SET
+# define SEEK_SET 0 /* Seek from beginning of file. */
+# define SEEK_CUR 1 /* Seek from current position. */
+# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */
+#endif
+
+/*
+ * This is hard-configured for FreeBSD, since zlib doesn't actually support
+ * using the system off_t for offsets unless off_t is no longer than long.
+ * To minimize the diff, we just "undef z_off_t" rather than modifying
+ * the following lines.
+ */
+#undef z_off_t
+
+#ifndef z_off_t
+# define z_off_t long
+#endif
+
+#if defined(__OS400__)
+# define NO_vsnprintf
+#endif
+
+#if defined(__MVS__)
+# define NO_vsnprintf
+# ifdef FAR
+# undef FAR
+# endif
+#endif
+
+/* MVS linker does not support external names larger than 8 bytes */
+#if defined(__MVS__)
+# pragma map(deflateInit_,"DEIN")
+# pragma map(deflateInit2_,"DEIN2")
+# pragma map(deflateEnd,"DEEND")
+# pragma map(deflateBound,"DEBND")
+# pragma map(inflateInit_,"ININ")
+# pragma map(inflateInit2_,"ININ2")
+# pragma map(inflateEnd,"INEND")
+# pragma map(inflateSync,"INSY")
+# pragma map(inflateSetDictionary,"INSEDI")
+# pragma map(compressBound,"CMBND")
+# pragma map(inflate_table,"INTABL")
+# pragma map(inflate_fast,"INFA")
+# pragma map(inflate_copyright,"INCOPY")
+#endif
+
+#endif /* ZCONF_H */
diff --git a/lib/libz/zlib.3 b/lib/libz/zlib.3
new file mode 100644
index 0000000..90b8162
--- /dev/null
+++ b/lib/libz/zlib.3
@@ -0,0 +1,159 @@
+.TH ZLIB 3 "18 July 2005"
+.SH NAME
+zlib \- compression/decompression library
+.SH SYNOPSIS
+[see
+.I zlib.h
+for full description]
+.SH DESCRIPTION
+The
+.I zlib
+library is a general purpose data compression library.
+The code is thread safe.
+It provides in-memory compression and decompression functions,
+including integrity checks of the uncompressed data.
+This version of the library supports only one compression method (deflation)
+but other algorithms will be added later
+and will have the same stream interface.
+.LP
+Compression can be done in a single step if the buffers are large enough
+(for example if an input file is mmap'ed),
+or can be done by repeated calls of the compression function.
+In the latter case,
+the application must provide more input and/or consume the output
+(providing more output space) before each call.
+.LP
+The library also supports reading and writing files in
+.IR gzip (1)
+(.gz) format
+with an interface similar to that of stdio.
+.LP
+The library does not install any signal handler.
+The decoder checks the consistency of the compressed data,
+so the library should never crash even in case of corrupted input.
+.LP
+All functions of the compression library are documented in the file
+.IR zlib.h .
+The distribution source includes examples of use of the library
+in the files
+.I example.c
+and
+.IR minigzip.c .
+.LP
+Changes to this version are documented in the file
+.I ChangeLog
+that accompanies the source,
+and are concerned primarily with bug fixes and portability enhancements.
+.LP
+A Java implementation of
+.I zlib
+is available in the Java Development Kit 1.1:
+.IP
+http://www.javasoft.com/products/JDK/1.1/docs/api/Package-java.util.zip.html
+.LP
+A Perl interface to
+.IR zlib ,
+written by Paul Marquess (pmqs@cpan.org),
+is available at CPAN (Comprehensive Perl Archive Network) sites,
+including:
+.IP
+http://www.cpan.org/modules/by-module/Compress/
+.LP
+A Python interface to
+.IR zlib ,
+written by A.M. Kuchling (amk@magnet.com),
+is available in Python 1.5 and later versions:
+.IP
+http://www.python.org/doc/lib/module-zlib.html
+.LP
+A
+.I zlib
+binding for
+.IR tcl (1),
+written by Andreas Kupries (a.kupries@westend.com),
+is availlable at:
+.IP
+http://www.westend.com/~kupries/doc/trf/man/man.html
+.LP
+An experimental package to read and write files in .zip format,
+written on top of
+.I zlib
+by Gilles Vollant (info@winimage.com),
+is available at:
+.IP
+http://www.winimage.com/zLibDll/unzip.html
+and also in the
+.I contrib/minizip
+directory of the main
+.I zlib
+web site.
+.SH "SEE ALSO"
+The
+.I zlib
+web site can be found at either of these locations:
+.IP
+http://www.zlib.org
+.br
+http://www.gzip.org/zlib/
+.LP
+The data format used by the zlib library is described by RFC
+(Request for Comments) 1950 to 1952 in the files:
+.IP
+http://www.ietf.org/rfc/rfc1950.txt (concerning zlib format)
+.br
+http://www.ietf.org/rfc/rfc1951.txt (concerning deflate format)
+.br
+http://www.ietf.org/rfc/rfc1952.txt (concerning gzip format)
+.LP
+These documents are also available in other formats from:
+.IP
+ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html
+.LP
+Mark Nelson (markn@ieee.org) wrote an article about
+.I zlib
+for the Jan. 1997 issue of Dr. Dobb's Journal;
+a copy of the article is available at:
+.IP
+http://dogma.net/markn/articles/zlibtool/zlibtool.htm
+.SH "REPORTING PROBLEMS"
+Before reporting a problem,
+please check the
+.I zlib
+web site to verify that you have the latest version of
+.IR zlib ;
+otherwise,
+obtain the latest version and see if the problem still exists.
+Please read the
+.I zlib
+FAQ at:
+.IP
+http://www.gzip.org/zlib/zlib_faq.html
+.LP
+before asking for help.
+Send questions and/or comments to zlib@gzip.org,
+or (for the Windows DLL version) to Gilles Vollant (info@winimage.com).
+.SH AUTHORS
+Version 1.2.3
+Copyright (C) 1995-2005 Jean-loup Gailly (jloup@gzip.org)
+and Mark Adler (madler@alumni.caltech.edu).
+.LP
+This software is provided "as-is,"
+without any express or implied warranty.
+In no event will the authors be held liable for any damages
+arising from the use of this software.
+See the distribution directory with respect to requirements
+governing redistribution.
+The deflate format used by
+.I zlib
+was defined by Phil Katz.
+The deflate and
+.I zlib
+specifications were written by L. Peter Deutsch.
+Thanks to all the people who reported problems and suggested various
+improvements in
+.IR zlib ;
+who are too numerous to cite here.
+.LP
+UNIX manual page by R. P. C. Rodgers,
+U.S. National Library of Medicine (rodgers@nlm.nih.gov).
+.\" end of man page
diff --git a/lib/libz/zlib.h b/lib/libz/zlib.h
new file mode 100644
index 0000000..0228179
--- /dev/null
+++ b/lib/libz/zlib.h
@@ -0,0 +1,1357 @@
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+ version 1.2.3, July 18th, 2005
+
+ Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jean-loup Gailly Mark Adler
+ jloup@gzip.org madler@alumni.caltech.edu
+
+
+ The data format used by the zlib library is described by RFCs (Request for
+ Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt
+ (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
+*/
+
+#ifndef ZLIB_H
+#define ZLIB_H
+
+#include "zconf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ZLIB_VERSION "1.2.3"
+#define ZLIB_VERNUM 0x1230
+
+/*
+ The 'zlib' compression library provides in-memory compression and
+ decompression functions, including integrity checks of the uncompressed
+ data. This version of the library supports only one compression method
+ (deflation) but other algorithms will be added later and will have the same
+ stream interface.
+
+ Compression can be done in a single step if the buffers are large
+ enough (for example if an input file is mmap'ed), or can be done by
+ repeated calls of the compression function. In the latter case, the
+ application must provide more input and/or consume the output
+ (providing more output space) before each call.
+
+ The compressed data format used by default by the in-memory functions is
+ the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped
+ around a deflate stream, which is itself documented in RFC 1951.
+
+ The library also supports reading and writing files in gzip (.gz) format
+ with an interface similar to that of stdio using the functions that start
+ with "gz". The gzip format is different from the zlib format. gzip is a
+ gzip wrapper, documented in RFC 1952, wrapped around a deflate stream.
+
+ This library can optionally read and write gzip streams in memory as well.
+
+ The zlib format was designed to be compact and fast for use in memory
+ and on communications channels. The gzip format was designed for single-
+ file compression on file systems, has a larger header than zlib to maintain
+ directory information, and uses a different, slower check method than zlib.
+
+ The library does not install any signal handler. The decoder checks
+ the consistency of the compressed data, so the library should never
+ crash even in case of corrupted input.
+*/
+
+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
+typedef void (*free_func) OF((voidpf opaque, voidpf address));
+
+struct internal_state;
+
+typedef struct z_stream_s {
+ Bytef *next_in; /* next input byte */
+ uInt avail_in; /* number of bytes available at next_in */
+ uLong total_in; /* total nb of input bytes read so far */
+
+ Bytef *next_out; /* next output byte should be put there */
+ uInt avail_out; /* remaining free space at next_out */
+ uLong total_out; /* total nb of bytes output so far */
+
+ char *msg; /* last error message, NULL if no error */
+ struct internal_state FAR *state; /* not visible by applications */
+
+ alloc_func zalloc; /* used to allocate the internal state */
+ free_func zfree; /* used to free the internal state */
+ voidpf opaque; /* private data object passed to zalloc and zfree */
+
+ int data_type; /* best guess about the data type: binary or text */
+ uLong adler; /* adler32 value of the uncompressed data */
+ uLong reserved; /* reserved for future use */
+} z_stream;
+
+typedef z_stream FAR *z_streamp;
+
+/*
+ gzip header information passed to and from zlib routines. See RFC 1952
+ for more details on the meanings of these fields.
+*/
+typedef struct gz_header_s {
+ int text; /* true if compressed data believed to be text */
+ uLong time; /* modification time */
+ int xflags; /* extra flags (not used when writing a gzip file) */
+ int os; /* operating system */
+ Bytef *extra; /* pointer to extra field or Z_NULL if none */
+ uInt extra_len; /* extra field length (valid if extra != Z_NULL) */
+ uInt extra_max; /* space at extra (only when reading header) */
+ Bytef *name; /* pointer to zero-terminated file name or Z_NULL */
+ uInt name_max; /* space at name (only when reading header) */
+ Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */
+ uInt comm_max; /* space at comment (only when reading header) */
+ int hcrc; /* true if there was or will be a header crc */
+ int done; /* true when done reading gzip header (not used
+ when writing a gzip file) */
+} gz_header;
+
+typedef gz_header FAR *gz_headerp;
+
+/*
+ The application must update next_in and avail_in when avail_in has
+ dropped to zero. It must update next_out and avail_out when avail_out
+ has dropped to zero. The application must initialize zalloc, zfree and
+ opaque before calling the init function. All other fields are set by the
+ compression library and must not be updated by the application.
+
+ The opaque value provided by the application will be passed as the first
+ parameter for calls of zalloc and zfree. This can be useful for custom
+ memory management. The compression library attaches no meaning to the
+ opaque value.
+
+ zalloc must return Z_NULL if there is not enough memory for the object.
+ If zlib is used in a multi-threaded application, zalloc and zfree must be
+ thread safe.
+
+ On 16-bit systems, the functions zalloc and zfree must be able to allocate
+ exactly 65536 bytes, but will not be required to allocate more than this
+ if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
+ pointers returned by zalloc for objects of exactly 65536 bytes *must*
+ have their offset normalized to zero. The default allocation function
+ provided by this library ensures this (see zutil.c). To reduce memory
+ requirements and avoid any allocation of 64K objects, at the expense of
+ compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
+
+ The fields total_in and total_out can be used for statistics or
+ progress reports. After compression, total_in holds the total size of
+ the uncompressed data and may be saved for use in the decompressor
+ (particularly if the decompressor wants to decompress everything in
+ a single step).
+*/
+
+ /* constants */
+
+#define Z_NO_FLUSH 0
+#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */
+#define Z_SYNC_FLUSH 2
+#define Z_FULL_FLUSH 3
+#define Z_FINISH 4
+#define Z_BLOCK 5
+/* Allowed flush values; see deflate() and inflate() below for details */
+
+#define Z_OK 0
+#define Z_STREAM_END 1
+#define Z_NEED_DICT 2
+#define Z_ERRNO (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR (-3)
+#define Z_MEM_ERROR (-4)
+#define Z_BUF_ERROR (-5)
+#define Z_VERSION_ERROR (-6)
+/* Return codes for the compression/decompression functions. Negative
+ * values are errors, positive values are used for special but normal events.
+ */
+
+#define Z_NO_COMPRESSION 0
+#define Z_BEST_SPEED 1
+#define Z_BEST_COMPRESSION 9
+#define Z_DEFAULT_COMPRESSION (-1)
+/* compression levels */
+
+#define Z_FILTERED 1
+#define Z_HUFFMAN_ONLY 2
+#define Z_RLE 3
+#define Z_FIXED 4
+#define Z_DEFAULT_STRATEGY 0
+/* compression strategy; see deflateInit2() below for details */
+
+#define Z_BINARY 0
+#define Z_TEXT 1
+#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */
+#define Z_UNKNOWN 2
+/* Possible values of the data_type field (though see inflate()) */
+
+#define Z_DEFLATED 8
+/* The deflate compression method (the only one supported in this version) */
+
+#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */
+
+#define zlib_version zlibVersion()
+/* for compatibility with versions < 1.0.2 */
+
+ /* basic functions */
+
+ZEXTERN const char * ZEXPORT zlibVersion OF((void));
+/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
+ If the first character differs, the library code actually used is
+ not compatible with the zlib.h header file used by the application.
+ This check is automatically made by deflateInit and inflateInit.
+ */
+
+/*
+ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));
+
+ Initializes the internal stream state for compression. The fields
+ zalloc, zfree and opaque must be initialized before by the caller.
+ If zalloc and zfree are set to Z_NULL, deflateInit updates them to
+ use default allocation functions.
+
+ The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
+ 1 gives best speed, 9 gives best compression, 0 gives no compression at
+ all (the input data is simply copied a block at a time).
+ Z_DEFAULT_COMPRESSION requests a default compromise between speed and
+ compression (currently equivalent to level 6).
+
+ deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if level is not a valid compression level,
+ Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
+ with the version assumed by the caller (ZLIB_VERSION).
+ msg is set to null if there is no error message. deflateInit does not
+ perform any compression: this will be done by deflate().
+*/
+
+
+ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
+/*
+ deflate compresses as much data as possible, and stops when the input
+ buffer becomes empty or the output buffer becomes full. It may introduce some
+ output latency (reading input without producing any output) except when
+ forced to flush.
+
+ The detailed semantics are as follows. deflate performs one or both of the
+ following actions:
+
+ - Compress more input starting at next_in and update next_in and avail_in
+ accordingly. If not all input can be processed (because there is not
+ enough room in the output buffer), next_in and avail_in are updated and
+ processing will resume at this point for the next call of deflate().
+
+ - Provide more output starting at next_out and update next_out and avail_out
+ accordingly. This action is forced if the parameter flush is non zero.
+ Forcing flush frequently degrades the compression ratio, so this parameter
+ should be set only when necessary (in interactive applications).
+ Some output may be provided even if flush is not set.
+
+ Before the call of deflate(), the application should ensure that at least
+ one of the actions is possible, by providing more input and/or consuming
+ more output, and updating avail_in or avail_out accordingly; avail_out
+ should never be zero before the call. The application can consume the
+ compressed output when it wants, for example when the output buffer is full
+ (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK
+ and with zero avail_out, it must be called again after making room in the
+ output buffer because there might be more output pending.
+
+ Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to
+ decide how much data to accumualte before producing output, in order to
+ maximize compression.
+
+ If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
+ flushed to the output buffer and the output is aligned on a byte boundary, so
+ that the decompressor can get all input data available so far. (In particular
+ avail_in is zero after the call if enough output space has been provided
+ before the call.) Flushing may degrade compression for some compression
+ algorithms and so it should be used only when necessary.
+
+ If flush is set to Z_FULL_FLUSH, all output is flushed as with
+ Z_SYNC_FLUSH, and the compression state is reset so that decompression can
+ restart from this point if previous compressed data has been damaged or if
+ random access is desired. Using Z_FULL_FLUSH too often can seriously degrade
+ compression.
+
+ If deflate returns with avail_out == 0, this function must be called again
+ with the same value of the flush parameter and more output space (updated
+ avail_out), until the flush is complete (deflate returns with non-zero
+ avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that
+ avail_out is greater than six to avoid repeated flush markers due to
+ avail_out == 0 on return.
+
+ If the parameter flush is set to Z_FINISH, pending input is processed,
+ pending output is flushed and deflate returns with Z_STREAM_END if there
+ was enough output space; if deflate returns with Z_OK, this function must be
+ called again with Z_FINISH and more output space (updated avail_out) but no
+ more input data, until it returns with Z_STREAM_END or an error. After
+ deflate has returned Z_STREAM_END, the only possible operations on the
+ stream are deflateReset or deflateEnd.
+
+ Z_FINISH can be used immediately after deflateInit if all the compression
+ is to be done in a single step. In this case, avail_out must be at least
+ the value returned by deflateBound (see below). If deflate does not return
+ Z_STREAM_END, then it must be called again as described above.
+
+ deflate() sets strm->adler to the adler32 checksum of all input read
+ so far (that is, total_in bytes).
+
+ deflate() may update strm->data_type if it can make a good guess about
+ the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered
+ binary. This field is only for information purposes and does not affect
+ the compression algorithm in any manner.
+
+ deflate() returns Z_OK if some progress has been made (more input
+ processed or more output produced), Z_STREAM_END if all input has been
+ consumed and all output has been produced (only when flush is set to
+ Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
+ if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible
+ (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not
+ fatal, and deflate() can be called again with more input and more output
+ space to continue compressing.
+*/
+
+
+ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm));
+/*
+ All dynamically allocated data structures for this stream are freed.
+ This function discards any unprocessed input and does not flush any
+ pending output.
+
+ deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
+ stream state was inconsistent, Z_DATA_ERROR if the stream was freed
+ prematurely (some input or output was discarded). In the error case,
+ msg may be set but then points to a static string (which must not be
+ deallocated).
+*/
+
+
+/*
+ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm));
+
+ Initializes the internal stream state for decompression. The fields
+ next_in, avail_in, zalloc, zfree and opaque must be initialized before by
+ the caller. If next_in is not Z_NULL and avail_in is large enough (the exact
+ value depends on the compression method), inflateInit determines the
+ compression method from the zlib header and allocates all data structures
+ accordingly; otherwise the allocation will be deferred to the first call of
+ inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to
+ use default allocation functions.
+
+ inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
+ version assumed by the caller. msg is set to null if there is no error
+ message. inflateInit does not perform any decompression apart from reading
+ the zlib header if present: this will be done by inflate(). (So next_in and
+ avail_in may be modified, but next_out and avail_out are unchanged.)
+*/
+
+
+ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));
+/*
+ inflate decompresses as much data as possible, and stops when the input
+ buffer becomes empty or the output buffer becomes full. It may introduce
+ some output latency (reading input without producing any output) except when
+ forced to flush.
+
+ The detailed semantics are as follows. inflate performs one or both of the
+ following actions:
+
+ - Decompress more input starting at next_in and update next_in and avail_in
+ accordingly. If not all input can be processed (because there is not
+ enough room in the output buffer), next_in is updated and processing
+ will resume at this point for the next call of inflate().
+
+ - Provide more output starting at next_out and update next_out and avail_out
+ accordingly. inflate() provides as much output as possible, until there
+ is no more input data or no more space in the output buffer (see below
+ about the flush parameter).
+
+ Before the call of inflate(), the application should ensure that at least
+ one of the actions is possible, by providing more input and/or consuming
+ more output, and updating the next_* and avail_* values accordingly.
+ The application can consume the uncompressed output when it wants, for
+ example when the output buffer is full (avail_out == 0), or after each
+ call of inflate(). If inflate returns Z_OK and with zero avail_out, it
+ must be called again after making room in the output buffer because there
+ might be more output pending.
+
+ The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH,
+ Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much
+ output as possible to the output buffer. Z_BLOCK requests that inflate() stop
+ if and when it gets to the next deflate block boundary. When decoding the
+ zlib or gzip format, this will cause inflate() to return immediately after
+ the header and before the first block. When doing a raw inflate, inflate()
+ will go ahead and process the first block, and will return when it gets to
+ the end of that block, or when it runs out of data.
+
+ The Z_BLOCK option assists in appending to or combining deflate streams.
+ Also to assist in this, on return inflate() will set strm->data_type to the
+ number of unused bits in the last byte taken from strm->next_in, plus 64
+ if inflate() is currently decoding the last block in the deflate stream,
+ plus 128 if inflate() returned immediately after decoding an end-of-block
+ code or decoding the complete header up to just before the first byte of the
+ deflate stream. The end-of-block will not be indicated until all of the
+ uncompressed data from that block has been written to strm->next_out. The
+ number of unused bits may in general be greater than seven, except when
+ bit 7 of data_type is set, in which case the number of unused bits will be
+ less than eight.
+
+ inflate() should normally be called until it returns Z_STREAM_END or an
+ error. However if all decompression is to be performed in a single step
+ (a single call of inflate), the parameter flush should be set to
+ Z_FINISH. In this case all pending input is processed and all pending
+ output is flushed; avail_out must be large enough to hold all the
+ uncompressed data. (The size of the uncompressed data may have been saved
+ by the compressor for this purpose.) The next operation on this stream must
+ be inflateEnd to deallocate the decompression state. The use of Z_FINISH
+ is never required, but can be used to inform inflate that a faster approach
+ may be used for the single inflate() call.
+
+ In this implementation, inflate() always flushes as much output as
+ possible to the output buffer, and always uses the faster approach on the
+ first call. So the only effect of the flush parameter in this implementation
+ is on the return value of inflate(), as noted below, or when it returns early
+ because Z_BLOCK is used.
+
+ If a preset dictionary is needed after this call (see inflateSetDictionary
+ below), inflate sets strm->adler to the adler32 checksum of the dictionary
+ chosen by the compressor and returns Z_NEED_DICT; otherwise it sets
+ strm->adler to the adler32 checksum of all output produced so far (that is,
+ total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described
+ below. At the end of the stream, inflate() checks that its computed adler32
+ checksum is equal to that saved by the compressor and returns Z_STREAM_END
+ only if the checksum is correct.
+
+ inflate() will decompress and check either zlib-wrapped or gzip-wrapped
+ deflate data. The header type is detected automatically. Any information
+ contained in the gzip header is not retained, so applications that need that
+ information should instead use raw inflate, see inflateInit2() below, or
+ inflateBack() and perform their own processing of the gzip header and
+ trailer.
+
+ inflate() returns Z_OK if some progress has been made (more input processed
+ or more output produced), Z_STREAM_END if the end of the compressed data has
+ been reached and all uncompressed output has been produced, Z_NEED_DICT if a
+ preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
+ corrupted (input stream not conforming to the zlib format or incorrect check
+ value), Z_STREAM_ERROR if the stream structure was inconsistent (for example
+ if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory,
+ Z_BUF_ERROR if no progress is possible or if there was not enough room in the
+ output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and
+ inflate() can be called again with more input and more output space to
+ continue decompressing. If Z_DATA_ERROR is returned, the application may then
+ call inflateSync() to look for a good compression block if a partial recovery
+ of the data is desired.
+*/
+
+
+ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm));
+/*
+ All dynamically allocated data structures for this stream are freed.
+ This function discards any unprocessed input and does not flush any
+ pending output.
+
+ inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+ was inconsistent. In the error case, msg may be set but then points to a
+ static string (which must not be deallocated).
+*/
+
+ /* Advanced functions */
+
+/*
+ The following functions are needed only in some special applications.
+*/
+
+/*
+ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
+ int level,
+ int method,
+ int windowBits,
+ int memLevel,
+ int strategy));
+
+ This is another version of deflateInit with more compression options. The
+ fields next_in, zalloc, zfree and opaque must be initialized before by
+ the caller.
+
+ The method parameter is the compression method. It must be Z_DEFLATED in
+ this version of the library.
+
+ The windowBits parameter is the base two logarithm of the window size
+ (the size of the history buffer). It should be in the range 8..15 for this
+ version of the library. Larger values of this parameter result in better
+ compression at the expense of memory usage. The default value is 15 if
+ deflateInit is used instead.
+
+ windowBits can also be -8..-15 for raw deflate. In this case, -windowBits
+ determines the window size. deflate() will then generate raw deflate data
+ with no zlib header or trailer, and will not compute an adler32 check value.
+
+ windowBits can also be greater than 15 for optional gzip encoding. Add
+ 16 to windowBits to write a simple gzip header and trailer around the
+ compressed data instead of a zlib wrapper. The gzip header will have no
+ file name, no extra data, no comment, no modification time (set to zero),
+ no header crc, and the operating system will be set to 255 (unknown). If a
+ gzip stream is being written, strm->adler is a crc32 instead of an adler32.
+
+ The memLevel parameter specifies how much memory should be allocated
+ for the internal compression state. memLevel=1 uses minimum memory but
+ is slow and reduces compression ratio; memLevel=9 uses maximum memory
+ for optimal speed. The default value is 8. See zconf.h for total memory
+ usage as a function of windowBits and memLevel.
+
+ The strategy parameter is used to tune the compression algorithm. Use the
+ value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
+ filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no
+ string match), or Z_RLE to limit match distances to one (run-length
+ encoding). Filtered data consists mostly of small values with a somewhat
+ random distribution. In this case, the compression algorithm is tuned to
+ compress them better. The effect of Z_FILTERED is to force more Huffman
+ coding and less string matching; it is somewhat intermediate between
+ Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as
+ Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy
+ parameter only affects the compression ratio but not the correctness of the
+ compressed output even if it is not set appropriately. Z_FIXED prevents the
+ use of dynamic Huffman codes, allowing for a simpler decoder for special
+ applications.
+
+ deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid
+ method). msg is set to null if there is no error message. deflateInit2 does
+ not perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm,
+ const Bytef *dictionary,
+ uInt dictLength));
+/*
+ Initializes the compression dictionary from the given byte sequence
+ without producing any compressed output. This function must be called
+ immediately after deflateInit, deflateInit2 or deflateReset, before any
+ call of deflate. The compressor and decompressor must use exactly the same
+ dictionary (see inflateSetDictionary).
+
+ The dictionary should consist of strings (byte sequences) that are likely
+ to be encountered later in the data to be compressed, with the most commonly
+ used strings preferably put towards the end of the dictionary. Using a
+ dictionary is most useful when the data to be compressed is short and can be
+ predicted with good accuracy; the data can then be compressed better than
+ with the default empty dictionary.
+
+ Depending on the size of the compression data structures selected by
+ deflateInit or deflateInit2, a part of the dictionary may in effect be
+ discarded, for example if the dictionary is larger than the window size in
+ deflate or deflate2. Thus the strings most likely to be useful should be
+ put at the end of the dictionary, not at the front. In addition, the
+ current implementation of deflate will use at most the window size minus
+ 262 bytes of the provided dictionary.
+
+ Upon return of this function, strm->adler is set to the adler32 value
+ of the dictionary; the decompressor may later use this value to determine
+ which dictionary has been used by the compressor. (The adler32 value
+ applies to the whole dictionary even if only a subset of the dictionary is
+ actually used by the compressor.) If a raw deflate was requested, then the
+ adler32 value is not computed and strm->adler is not set.
+
+ deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
+ parameter is invalid (such as NULL dictionary) or the stream state is
+ inconsistent (for example if deflate has already been called for this stream
+ or if the compression method is bsort). deflateSetDictionary does not
+ perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest,
+ z_streamp source));
+/*
+ Sets the destination stream as a complete copy of the source stream.
+
+ This function can be useful when several compression strategies will be
+ tried, for example when there are several ways of pre-processing the input
+ data with a filter. The streams that will be discarded should then be freed
+ by calling deflateEnd. Note that deflateCopy duplicates the internal
+ compression state which can be quite large, so this strategy is slow and
+ can consume lots of memory.
+
+ deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+ (such as zalloc being NULL). msg is left unchanged in both source and
+ destination.
+*/
+
+ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm));
+/*
+ This function is equivalent to deflateEnd followed by deflateInit,
+ but does not free and reallocate all the internal compression state.
+ The stream will keep the same compression level and any other attributes
+ that may have been set by deflateInit2.
+
+ deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm,
+ int level,
+ int strategy));
+/*
+ Dynamically update the compression level and compression strategy. The
+ interpretation of level and strategy is as in deflateInit2. This can be
+ used to switch between compression and straight copy of the input data, or
+ to switch to a different kind of input data requiring a different
+ strategy. If the compression level is changed, the input available so far
+ is compressed with the old level (and may be flushed); the new level will
+ take effect only at the next call of deflate().
+
+ Before the call of deflateParams, the stream state must be set as for
+ a call of deflate(), since the currently available input may have to
+ be compressed and flushed. In particular, strm->avail_out must be non-zero.
+
+ deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
+ stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR
+ if strm->avail_out was zero.
+*/
+
+ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm,
+ int good_length,
+ int max_lazy,
+ int nice_length,
+ int max_chain));
+/*
+ Fine tune deflate's internal compression parameters. This should only be
+ used by someone who understands the algorithm used by zlib's deflate for
+ searching for the best matching string, and even then only by the most
+ fanatic optimizer trying to squeeze out the last compressed bit for their
+ specific input data. Read the deflate.c source code for the meaning of the
+ max_lazy, good_length, nice_length, and max_chain parameters.
+
+ deflateTune() can be called after deflateInit() or deflateInit2(), and
+ returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream.
+ */
+
+ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm,
+ uLong sourceLen));
+/*
+ deflateBound() returns an upper bound on the compressed size after
+ deflation of sourceLen bytes. It must be called after deflateInit()
+ or deflateInit2(). This would be used to allocate an output buffer
+ for deflation in a single pass, and so would be called before deflate().
+*/
+
+ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm,
+ int bits,
+ int value));
+/*
+ deflatePrime() inserts bits in the deflate output stream. The intent
+ is that this function is used to start off the deflate output with the
+ bits leftover from a previous deflate stream when appending to it. As such,
+ this function can only be used for raw deflate, and must be used before the
+ first deflate() call after a deflateInit2() or deflateReset(). bits must be
+ less than or equal to 16, and that many of the least significant bits of
+ value will be inserted in the output.
+
+ deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+*/
+
+ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm,
+ gz_headerp head));
+/*
+ deflateSetHeader() provides gzip header information for when a gzip
+ stream is requested by deflateInit2(). deflateSetHeader() may be called
+ after deflateInit2() or deflateReset() and before the first call of
+ deflate(). The text, time, os, extra field, name, and comment information
+ in the provided gz_header structure are written to the gzip header (xflag is
+ ignored -- the extra flags are set according to the compression level). The
+ caller must assure that, if not Z_NULL, name and comment are terminated with
+ a zero byte, and that if extra is not Z_NULL, that extra_len bytes are
+ available there. If hcrc is true, a gzip header crc is included. Note that
+ the current versions of the command-line version of gzip (up through version
+ 1.3.x) do not support header crc's, and will report that it is a "multi-part
+ gzip file" and give up.
+
+ If deflateSetHeader is not used, the default gzip header has text false,
+ the time set to zero, and os set to 255, with no extra, name, or comment
+ fields. The gzip header is returned to the default state by deflateReset().
+
+ deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
+ int windowBits));
+
+ This is another version of inflateInit with an extra parameter. The
+ fields next_in, avail_in, zalloc, zfree and opaque must be initialized
+ before by the caller.
+
+ The windowBits parameter is the base two logarithm of the maximum window
+ size (the size of the history buffer). It should be in the range 8..15 for
+ this version of the library. The default value is 15 if inflateInit is used
+ instead. windowBits must be greater than or equal to the windowBits value
+ provided to deflateInit2() while compressing, or it must be equal to 15 if
+ deflateInit2() was not used. If a compressed stream with a larger window
+ size is given as input, inflate() will return with the error code
+ Z_DATA_ERROR instead of trying to allocate a larger window.
+
+ windowBits can also be -8..-15 for raw inflate. In this case, -windowBits
+ determines the window size. inflate() will then process raw deflate data,
+ not looking for a zlib or gzip header, not generating a check value, and not
+ looking for any check values for comparison at the end of the stream. This
+ is for use with other formats that use the deflate compressed data format
+ such as zip. Those formats provide their own check values. If a custom
+ format is developed using the raw deflate format for compressed data, it is
+ recommended that a check value such as an adler32 or a crc32 be applied to
+ the uncompressed data as is done in the zlib, gzip, and zip formats. For
+ most applications, the zlib format should be used as is. Note that comments
+ above on the use in deflateInit2() applies to the magnitude of windowBits.
+
+ windowBits can also be greater than 15 for optional gzip decoding. Add
+ 32 to windowBits to enable zlib and gzip decoding with automatic header
+ detection, or add 16 to decode only the gzip format (the zlib format will
+ return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is
+ a crc32 instead of an adler32.
+
+ inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_STREAM_ERROR if a parameter is invalid (such as a null strm). msg
+ is set to null if there is no error message. inflateInit2 does not perform
+ any decompression apart from reading the zlib header if present: this will
+ be done by inflate(). (So next_in and avail_in may be modified, but next_out
+ and avail_out are unchanged.)
+*/
+
+ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm,
+ const Bytef *dictionary,
+ uInt dictLength));
+/*
+ Initializes the decompression dictionary from the given uncompressed byte
+ sequence. This function must be called immediately after a call of inflate,
+ if that call returned Z_NEED_DICT. The dictionary chosen by the compressor
+ can be determined from the adler32 value returned by that call of inflate.
+ The compressor and decompressor must use exactly the same dictionary (see
+ deflateSetDictionary). For raw inflate, this function can be called
+ immediately after inflateInit2() or inflateReset() and before any call of
+ inflate() to set the dictionary. The application must insure that the
+ dictionary that was used for compression is provided.
+
+ inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
+ parameter is invalid (such as NULL dictionary) or the stream state is
+ inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
+ expected one (incorrect adler32 value). inflateSetDictionary does not
+ perform any decompression: this will be done by subsequent calls of
+ inflate().
+*/
+
+ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm));
+/*
+ Skips invalid compressed data until a full flush point (see above the
+ description of deflate with Z_FULL_FLUSH) can be found, or until all
+ available input is skipped. No output is provided.
+
+ inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR
+ if no more input was provided, Z_DATA_ERROR if no flush point has been found,
+ or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
+ case, the application may save the current current value of total_in which
+ indicates where valid compressed data was found. In the error case, the
+ application may repeatedly call inflateSync, providing more input each time,
+ until success or end of the input data.
+*/
+
+ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest,
+ z_streamp source));
+/*
+ Sets the destination stream as a complete copy of the source stream.
+
+ This function can be useful when randomly accessing a large stream. The
+ first pass through the stream can periodically record the inflate state,
+ allowing restarting inflate at those points when randomly accessing the
+ stream.
+
+ inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+ (such as zalloc being NULL). msg is left unchanged in both source and
+ destination.
+*/
+
+ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm));
+/*
+ This function is equivalent to inflateEnd followed by inflateInit,
+ but does not free and reallocate all the internal decompression state.
+ The stream will keep attributes that may have been set by inflateInit2.
+
+ inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm,
+ int bits,
+ int value));
+/*
+ This function inserts bits in the inflate input stream. The intent is
+ that this function is used to start inflating at a bit position in the
+ middle of a byte. The provided bits will be used before any bytes are used
+ from next_in. This function should only be used with raw inflate, and
+ should be used before the first inflate() call after inflateInit2() or
+ inflateReset(). bits must be less than or equal to 16, and that many of the
+ least significant bits of value will be inserted in the input.
+
+ inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+*/
+
+ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm,
+ gz_headerp head));
+/*
+ inflateGetHeader() requests that gzip header information be stored in the
+ provided gz_header structure. inflateGetHeader() may be called after
+ inflateInit2() or inflateReset(), and before the first call of inflate().
+ As inflate() processes the gzip stream, head->done is zero until the header
+ is completed, at which time head->done is set to one. If a zlib stream is
+ being decoded, then head->done is set to -1 to indicate that there will be
+ no gzip header information forthcoming. Note that Z_BLOCK can be used to
+ force inflate() to return immediately after header processing is complete
+ and before any actual data is decompressed.
+
+ The text, time, xflags, and os fields are filled in with the gzip header
+ contents. hcrc is set to true if there is a header CRC. (The header CRC
+ was valid if done is set to one.) If extra is not Z_NULL, then extra_max
+ contains the maximum number of bytes to write to extra. Once done is true,
+ extra_len contains the actual extra field length, and extra contains the
+ extra field, or that field truncated if extra_max is less than extra_len.
+ If name is not Z_NULL, then up to name_max characters are written there,
+ terminated with a zero unless the length is greater than name_max. If
+ comment is not Z_NULL, then up to comm_max characters are written there,
+ terminated with a zero unless the length is greater than comm_max. When
+ any of extra, name, or comment are not Z_NULL and the respective field is
+ not present in the header, then that field is set to Z_NULL to signal its
+ absence. This allows the use of deflateSetHeader() with the returned
+ structure to duplicate the header. However if those fields are set to
+ allocated memory, then the application will need to save those pointers
+ elsewhere so that they can be eventually freed.
+
+ If inflateGetHeader is not used, then the header information is simply
+ discarded. The header is always checked for validity, including the header
+ CRC if present. inflateReset() will reset the process to discard the header
+ information. The application would need to call inflateGetHeader() again to
+ retrieve the header from the next gzip stream.
+
+ inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits,
+ unsigned char FAR *window));
+
+ Initialize the internal stream state for decompression using inflateBack()
+ calls. The fields zalloc, zfree and opaque in strm must be initialized
+ before the call. If zalloc and zfree are Z_NULL, then the default library-
+ derived memory allocation routines are used. windowBits is the base two
+ logarithm of the window size, in the range 8..15. window is a caller
+ supplied buffer of that size. Except for special applications where it is
+ assured that deflate was used with small window sizes, windowBits must be 15
+ and a 32K byte window must be supplied to be able to decompress general
+ deflate streams.
+
+ See inflateBack() for the usage of these routines.
+
+ inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of
+ the paramaters are invalid, Z_MEM_ERROR if the internal state could not
+ be allocated, or Z_VERSION_ERROR if the version of the library does not
+ match the version of the header file.
+*/
+
+typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *));
+typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned));
+
+ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm,
+ in_func in, void FAR *in_desc,
+ out_func out, void FAR *out_desc));
+/*
+ inflateBack() does a raw inflate with a single call using a call-back
+ interface for input and output. This is more efficient than inflate() for
+ file i/o applications in that it avoids copying between the output and the
+ sliding window by simply making the window itself the output buffer. This
+ function trusts the application to not change the output buffer passed by
+ the output function, at least until inflateBack() returns.
+
+ inflateBackInit() must be called first to allocate the internal state
+ and to initialize the state with the user-provided window buffer.
+ inflateBack() may then be used multiple times to inflate a complete, raw
+ deflate stream with each call. inflateBackEnd() is then called to free
+ the allocated state.
+
+ A raw deflate stream is one with no zlib or gzip header or trailer.
+ This routine would normally be used in a utility that reads zip or gzip
+ files and writes out uncompressed files. The utility would decode the
+ header and process the trailer on its own, hence this routine expects
+ only the raw deflate stream to decompress. This is different from the
+ normal behavior of inflate(), which expects either a zlib or gzip header and
+ trailer around the deflate stream.
+
+ inflateBack() uses two subroutines supplied by the caller that are then
+ called by inflateBack() for input and output. inflateBack() calls those
+ routines until it reads a complete deflate stream and writes out all of the
+ uncompressed data, or until it encounters an error. The function's
+ parameters and return types are defined above in the in_func and out_func
+ typedefs. inflateBack() will call in(in_desc, &buf) which should return the
+ number of bytes of provided input, and a pointer to that input in buf. If
+ there is no input available, in() must return zero--buf is ignored in that
+ case--and inflateBack() will return a buffer error. inflateBack() will call
+ out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out()
+ should return zero on success, or non-zero on failure. If out() returns
+ non-zero, inflateBack() will return with an error. Neither in() nor out()
+ are permitted to change the contents of the window provided to
+ inflateBackInit(), which is also the buffer that out() uses to write from.
+ The length written by out() will be at most the window size. Any non-zero
+ amount of input may be provided by in().
+
+ For convenience, inflateBack() can be provided input on the first call by
+ setting strm->next_in and strm->avail_in. If that input is exhausted, then
+ in() will be called. Therefore strm->next_in must be initialized before
+ calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called
+ immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in
+ must also be initialized, and then if strm->avail_in is not zero, input will
+ initially be taken from strm->next_in[0 .. strm->avail_in - 1].
+
+ The in_desc and out_desc parameters of inflateBack() is passed as the
+ first parameter of in() and out() respectively when they are called. These
+ descriptors can be optionally used to pass any information that the caller-
+ supplied in() and out() functions need to do their job.
+
+ On return, inflateBack() will set strm->next_in and strm->avail_in to
+ pass back any unused input that was provided by the last in() call. The
+ return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR
+ if in() or out() returned an error, Z_DATA_ERROR if there was a format
+ error in the deflate stream (in which case strm->msg is set to indicate the
+ nature of the error), or Z_STREAM_ERROR if the stream was not properly
+ initialized. In the case of Z_BUF_ERROR, an input or output error can be
+ distinguished using strm->next_in which will be Z_NULL only if in() returned
+ an error. If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to
+ out() returning non-zero. (in() will always be called before out(), so
+ strm->next_in is assured to be defined if out() returns non-zero.) Note
+ that inflateBack() cannot return Z_OK.
+*/
+
+ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm));
+/*
+ All memory allocated by inflateBackInit() is freed.
+
+ inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream
+ state was inconsistent.
+*/
+
+ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void));
+/* Return flags indicating compile-time options.
+
+ Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other:
+ 1.0: size of uInt
+ 3.2: size of uLong
+ 5.4: size of voidpf (pointer)
+ 7.6: size of z_off_t
+
+ Compiler, assembler, and debug options:
+ 8: DEBUG
+ 9: ASMV or ASMINF -- use ASM code
+ 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention
+ 11: 0 (reserved)
+
+ One-time table building (smaller code, but not thread-safe if true):
+ 12: BUILDFIXED -- build static block decoding tables when needed
+ 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed
+ 14,15: 0 (reserved)
+
+ Library content (indicates missing functionality):
+ 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking
+ deflate code when not needed)
+ 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect
+ and decode gzip streams (to avoid linking crc code)
+ 18-19: 0 (reserved)
+
+ Operation variations (changes in library functionality):
+ 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate
+ 21: FASTEST -- deflate algorithm with only one, lowest compression level
+ 22,23: 0 (reserved)
+
+ The sprintf variant used by gzprintf (zero is best):
+ 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format
+ 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure!
+ 26: 0 = returns value, 1 = void -- 1 means inferred string length returned
+
+ Remainder:
+ 27-31: 0 (reserved)
+ */
+
+
+ /* utility functions */
+
+/*
+ The following utility functions are implemented on top of the
+ basic stream-oriented functions. To simplify the interface, some
+ default options are assumed (compression level and memory usage,
+ standard memory allocation functions). The source code of these
+ utility functions can easily be modified if you need special options.
+*/
+
+ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen));
+/*
+ Compresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total
+ size of the destination buffer, which must be at least the value returned
+ by compressBound(sourceLen). Upon exit, destLen is the actual size of the
+ compressed buffer.
+ This function can be used to compress a whole file at once if the
+ input file is mmap'ed.
+ compress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer.
+*/
+
+ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen,
+ int level));
+/*
+ Compresses the source buffer into the destination buffer. The level
+ parameter has the same meaning as in deflateInit. sourceLen is the byte
+ length of the source buffer. Upon entry, destLen is the total size of the
+ destination buffer, which must be at least the value returned by
+ compressBound(sourceLen). Upon exit, destLen is the actual size of the
+ compressed buffer.
+
+ compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+ Z_STREAM_ERROR if the level parameter is invalid.
+*/
+
+ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen));
+/*
+ compressBound() returns an upper bound on the compressed size after
+ compress() or compress2() on sourceLen bytes. It would be used before
+ a compress() or compress2() call to allocate the destination buffer.
+*/
+
+ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen));
+/*
+ Decompresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total
+ size of the destination buffer, which must be large enough to hold the
+ entire uncompressed data. (The size of the uncompressed data must have
+ been saved previously by the compressor and transmitted to the decompressor
+ by some mechanism outside the scope of this compression library.)
+ Upon exit, destLen is the actual size of the compressed buffer.
+ This function can be used to decompress a whole file at once if the
+ input file is mmap'ed.
+
+ uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete.
+*/
+
+
+typedef voidp gzFile;
+
+ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode));
+/*
+ Opens a gzip (.gz) file for reading or writing. The mode parameter
+ is as in fopen ("rb" or "wb") but can also include a compression level
+ ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for
+ Huffman only compression as in "wb1h", or 'R' for run-length encoding
+ as in "wb1R". (See the description of deflateInit2 for more information
+ about the strategy parameter.)
+
+ gzopen can be used to read a file which is not in gzip format; in this
+ case gzread will directly read from the file without decompression.
+
+ gzopen returns NULL if the file could not be opened or if there was
+ insufficient memory to allocate the (de)compression state; errno
+ can be checked to distinguish the two cases (if errno is zero, the
+ zlib error is Z_MEM_ERROR). */
+
+ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode));
+/*
+ gzdopen() associates a gzFile with the file descriptor fd. File
+ descriptors are obtained from calls like open, dup, creat, pipe or
+ fileno (in the file has been previously opened with fopen).
+ The mode parameter is as in gzopen.
+ The next call of gzclose on the returned gzFile will also close the
+ file descriptor fd, just like fclose(fdopen(fd), mode) closes the file
+ descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode).
+ gzdopen returns NULL if there was insufficient memory to allocate
+ the (de)compression state.
+*/
+
+ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy));
+/*
+ Dynamically update the compression level or strategy. See the description
+ of deflateInit2 for the meaning of these parameters.
+ gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not
+ opened for writing.
+*/
+
+ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len));
+/*
+ Reads the given number of uncompressed bytes from the compressed file.
+ If the input file was not in gzip format, gzread copies the given number
+ of bytes into the buffer.
+ gzread returns the number of uncompressed bytes actually read (0 for
+ end of file, -1 for error). */
+
+ZEXTERN int ZEXPORT gzwrite OF((gzFile file,
+ voidpc buf, unsigned len));
+/*
+ Writes the given number of uncompressed bytes into the compressed file.
+ gzwrite returns the number of uncompressed bytes actually written
+ (0 in case of error).
+*/
+
+ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...));
+/*
+ Converts, formats, and writes the args to the compressed file under
+ control of the format string, as in fprintf. gzprintf returns the number of
+ uncompressed bytes actually written (0 in case of error). The number of
+ uncompressed bytes written is limited to 4095. The caller should assure that
+ this limit is not exceeded. If it is exceeded, then gzprintf() will return
+ return an error (0) with nothing written. In this case, there may also be a
+ buffer overflow with unpredictable consequences, which is possible only if
+ zlib was compiled with the insecure functions sprintf() or vsprintf()
+ because the secure snprintf() or vsnprintf() functions were not available.
+*/
+
+ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s));
+/*
+ Writes the given null-terminated string to the compressed file, excluding
+ the terminating null character.
+ gzputs returns the number of characters written, or -1 in case of error.
+*/
+
+ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len));
+/*
+ Reads bytes from the compressed file until len-1 characters are read, or
+ a newline character is read and transferred to buf, or an end-of-file
+ condition is encountered. The string is then terminated with a null
+ character.
+ gzgets returns buf, or Z_NULL in case of error.
+*/
+
+ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c));
+/*
+ Writes c, converted to an unsigned char, into the compressed file.
+ gzputc returns the value that was written, or -1 in case of error.
+*/
+
+ZEXTERN int ZEXPORT gzgetc OF((gzFile file));
+/*
+ Reads one byte from the compressed file. gzgetc returns this byte
+ or -1 in case of end of file or error.
+*/
+
+ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file));
+/*
+ Push one character back onto the stream to be read again later.
+ Only one character of push-back is allowed. gzungetc() returns the
+ character pushed, or -1 on failure. gzungetc() will fail if a
+ character has been pushed but not read yet, or if c is -1. The pushed
+ character will be discarded if the stream is repositioned with gzseek()
+ or gzrewind().
+*/
+
+ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush));
+/*
+ Flushes all pending output into the compressed file. The parameter
+ flush is as in the deflate() function. The return value is the zlib
+ error number (see function gzerror below). gzflush returns Z_OK if
+ the flush parameter is Z_FINISH and all output could be flushed.
+ gzflush should be called only when strictly necessary because it can
+ degrade compression.
+*/
+
+ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file,
+ z_off_t offset, int whence));
+/*
+ Sets the starting position for the next gzread or gzwrite on the
+ given compressed file. The offset represents a number of bytes in the
+ uncompressed data stream. The whence parameter is defined as in lseek(2);
+ the value SEEK_END is not supported.
+ If the file is opened for reading, this function is emulated but can be
+ extremely slow. If the file is opened for writing, only forward seeks are
+ supported; gzseek then compresses a sequence of zeroes up to the new
+ starting position.
+
+ gzseek returns the resulting offset location as measured in bytes from
+ the beginning of the uncompressed stream, or -1 in case of error, in
+ particular if the file is opened for writing and the new starting position
+ would be before the current position.
+*/
+
+ZEXTERN int ZEXPORT gzrewind OF((gzFile file));
+/*
+ Rewinds the given file. This function is supported only for reading.
+
+ gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)
+*/
+
+ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file));
+/*
+ Returns the starting position for the next gzread or gzwrite on the
+ given compressed file. This position represents a number of bytes in the
+ uncompressed data stream.
+
+ gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)
+*/
+
+ZEXTERN int ZEXPORT gzeof OF((gzFile file));
+/*
+ Returns 1 when EOF has previously been detected reading the given
+ input stream, otherwise zero.
+*/
+
+ZEXTERN int ZEXPORT gzdirect OF((gzFile file));
+/*
+ Returns 1 if file is being read directly without decompression, otherwise
+ zero.
+*/
+
+ZEXTERN int ZEXPORT gzclose OF((gzFile file));
+/*
+ Flushes all pending output if necessary, closes the compressed file
+ and deallocates all the (de)compression state. The return value is the zlib
+ error number (see function gzerror below).
+*/
+
+ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum));
+/*
+ Returns the error message for the last error which occurred on the
+ given compressed file. errnum is set to zlib error number. If an
+ error occurred in the file system and not in the compression library,
+ errnum is set to Z_ERRNO and the application may consult errno
+ to get the exact error code.
+*/
+
+ZEXTERN void ZEXPORT gzclearerr OF((gzFile file));
+/*
+ Clears the error and end-of-file flags for file. This is analogous to the
+ clearerr() function in stdio. This is useful for continuing to read a gzip
+ file that is being written concurrently.
+*/
+
+ /* checksum functions */
+
+/*
+ These functions are not related to compression but are exported
+ anyway because they might be useful in applications using the
+ compression library.
+*/
+
+ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
+/*
+ Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+ return the updated checksum. If buf is NULL, this function returns
+ the required initial value for the checksum.
+ An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+ much faster. Usage example:
+
+ uLong adler = adler32(0L, Z_NULL, 0);
+
+ while (read_buffer(buffer, length) != EOF) {
+ adler = adler32(adler, buffer, length);
+ }
+ if (adler != original_adler) error();
+*/
+
+ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2,
+ z_off_t len2));
+/*
+ Combine two Adler-32 checksums into one. For two sequences of bytes, seq1
+ and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for
+ each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of
+ seq1 and seq2 concatenated, requiring only adler1, adler2, and len2.
+*/
+
+ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len));
+/*
+ Update a running CRC-32 with the bytes buf[0..len-1] and return the
+ updated CRC-32. If buf is NULL, this function returns the required initial
+ value for the for the crc. Pre- and post-conditioning (one's complement) is
+ performed within this function so it shouldn't be done by the application.
+ Usage example:
+
+ uLong crc = crc32(0L, Z_NULL, 0);
+
+ while (read_buffer(buffer, length) != EOF) {
+ crc = crc32(crc, buffer, length);
+ }
+ if (crc != original_crc) error();
+*/
+
+ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2));
+
+/*
+ Combine two CRC-32 check values into one. For two sequences of bytes,
+ seq1 and seq2 with lengths len1 and len2, CRC-32 check values were
+ calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32
+ check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and
+ len2.
+*/
+
+
+ /* various hacks, don't look :) */
+
+/* deflateInit and inflateInit are macros to allow checking the zlib version
+ * and the compiler's view of z_stream:
+ */
+ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level,
+ const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm,
+ const char *version, int stream_size));
+ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method,
+ int windowBits, int memLevel,
+ int strategy, const char *version,
+ int stream_size));
+ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits,
+ const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits,
+ unsigned char FAR *window,
+ const char *version,
+ int stream_size));
+#define deflateInit(strm, level) \
+ deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit(strm) \
+ inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream))
+#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
+ deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
+ (strategy), ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit2(strm, windowBits) \
+ inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
+#define inflateBackInit(strm, windowBits, window) \
+ inflateBackInit_((strm), (windowBits), (window), \
+ ZLIB_VERSION, sizeof(z_stream))
+
+
+#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL)
+ struct internal_state {int dummy;}; /* hack for buggy compilers */
+#endif
+
+ZEXTERN const char * ZEXPORT zError OF((int));
+ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z));
+ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ZLIB_H */
diff --git a/lib/libz/zopen.c b/lib/libz/zopen.c
new file mode 100644
index 0000000..025899f
--- /dev/null
+++ b/lib/libz/zopen.c
@@ -0,0 +1,37 @@
+/*
+ * Public domain stdio wrapper for libz, written by Johan Danielsson.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <zlib.h>
+
+FILE *zopen(const char *fname, const char *mode);
+
+/* convert arguments */
+static int
+xgzread(void *cookie, char *data, int size)
+{
+ return gzread(cookie, data, size);
+}
+
+static int
+xgzwrite(void *cookie, const char *data, int size)
+{
+ return gzwrite(cookie, (void*)data, size);
+}
+
+FILE *
+zopen(const char *fname, const char *mode)
+{
+ gzFile gz = gzopen(fname, mode);
+ if(gz == NULL)
+ return NULL;
+
+ if(*mode == 'r')
+ return (funopen(gz, xgzread, NULL, NULL, gzclose));
+ else
+ return (funopen(gz, NULL, xgzwrite, NULL, gzclose));
+}
diff --git a/lib/libz/zutil.c b/lib/libz/zutil.c
new file mode 100644
index 0000000..d55f594
--- /dev/null
+++ b/lib/libz/zutil.c
@@ -0,0 +1,318 @@
+/* zutil.c -- target dependent utility functions for the compression library
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#include "zutil.h"
+
+#ifndef NO_DUMMY_DECL
+struct internal_state {int dummy;}; /* for buggy compilers */
+#endif
+
+const char * const z_errmsg[10] = {
+"need dictionary", /* Z_NEED_DICT 2 */
+"stream end", /* Z_STREAM_END 1 */
+"", /* Z_OK 0 */
+"file error", /* Z_ERRNO (-1) */
+"stream error", /* Z_STREAM_ERROR (-2) */
+"data error", /* Z_DATA_ERROR (-3) */
+"insufficient memory", /* Z_MEM_ERROR (-4) */
+"buffer error", /* Z_BUF_ERROR (-5) */
+"incompatible version",/* Z_VERSION_ERROR (-6) */
+""};
+
+
+const char * ZEXPORT zlibVersion()
+{
+ return ZLIB_VERSION;
+}
+
+uLong ZEXPORT zlibCompileFlags()
+{
+ uLong flags;
+
+ flags = 0;
+ switch (sizeof(uInt)) {
+ case 2: break;
+ case 4: flags += 1; break;
+ case 8: flags += 2; break;
+ default: flags += 3;
+ }
+ switch (sizeof(uLong)) {
+ case 2: break;
+ case 4: flags += 1 << 2; break;
+ case 8: flags += 2 << 2; break;
+ default: flags += 3 << 2;
+ }
+ switch (sizeof(voidpf)) {
+ case 2: break;
+ case 4: flags += 1 << 4; break;
+ case 8: flags += 2 << 4; break;
+ default: flags += 3 << 4;
+ }
+ switch (sizeof(z_off_t)) {
+ case 2: break;
+ case 4: flags += 1 << 6; break;
+ case 8: flags += 2 << 6; break;
+ default: flags += 3 << 6;
+ }
+#ifdef DEBUG
+ flags += 1 << 8;
+#endif
+#if defined(ASMV) || defined(ASMINF)
+ flags += 1 << 9;
+#endif
+#ifdef ZLIB_WINAPI
+ flags += 1 << 10;
+#endif
+#ifdef BUILDFIXED
+ flags += 1 << 12;
+#endif
+#ifdef DYNAMIC_CRC_TABLE
+ flags += 1 << 13;
+#endif
+#ifdef NO_GZCOMPRESS
+ flags += 1L << 16;
+#endif
+#ifdef NO_GZIP
+ flags += 1L << 17;
+#endif
+#ifdef PKZIP_BUG_WORKAROUND
+ flags += 1L << 20;
+#endif
+#ifdef FASTEST
+ flags += 1L << 21;
+#endif
+#ifdef STDC
+# ifdef NO_vsnprintf
+ flags += 1L << 25;
+# ifdef HAS_vsprintf_void
+ flags += 1L << 26;
+# endif
+# else
+# ifdef HAS_vsnprintf_void
+ flags += 1L << 26;
+# endif
+# endif
+#else
+ flags += 1L << 24;
+# ifdef NO_snprintf
+ flags += 1L << 25;
+# ifdef HAS_sprintf_void
+ flags += 1L << 26;
+# endif
+# else
+# ifdef HAS_snprintf_void
+ flags += 1L << 26;
+# endif
+# endif
+#endif
+ return flags;
+}
+
+#ifdef DEBUG
+
+# ifndef verbose
+# define verbose 0
+# endif
+int z_verbose = verbose;
+
+void z_error (m)
+ char *m;
+{
+ fprintf(stderr, "%s\n", m);
+ exit(1);
+}
+#endif
+
+/* exported to allow conversion of error code to string for compress() and
+ * uncompress()
+ */
+const char * ZEXPORT zError(err)
+ int err;
+{
+ return ERR_MSG(err);
+}
+
+#if defined(_WIN32_WCE)
+ /* The Microsoft C Run-Time Library for Windows CE doesn't have
+ * errno. We define it as a global variable to simplify porting.
+ * Its value is always 0 and should not be used.
+ */
+ int errno = 0;
+#endif
+
+#ifndef HAVE_MEMCPY
+
+void zmemcpy(dest, source, len)
+ Bytef* dest;
+ const Bytef* source;
+ uInt len;
+{
+ if (len == 0) return;
+ do {
+ *dest++ = *source++; /* ??? to be unrolled */
+ } while (--len != 0);
+}
+
+int zmemcmp(s1, s2, len)
+ const Bytef* s1;
+ const Bytef* s2;
+ uInt len;
+{
+ uInt j;
+
+ for (j = 0; j < len; j++) {
+ if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;
+ }
+ return 0;
+}
+
+void zmemzero(dest, len)
+ Bytef* dest;
+ uInt len;
+{
+ if (len == 0) return;
+ do {
+ *dest++ = 0; /* ??? to be unrolled */
+ } while (--len != 0);
+}
+#endif
+
+
+#ifdef SYS16BIT
+
+#ifdef __TURBOC__
+/* Turbo C in 16-bit mode */
+
+# define MY_ZCALLOC
+
+/* Turbo C malloc() does not allow dynamic allocation of 64K bytes
+ * and farmalloc(64K) returns a pointer with an offset of 8, so we
+ * must fix the pointer. Warning: the pointer must be put back to its
+ * original form in order to free it, use zcfree().
+ */
+
+#define MAX_PTR 10
+/* 10*64K = 640K */
+
+local int next_ptr = 0;
+
+typedef struct ptr_table_s {
+ voidpf org_ptr;
+ voidpf new_ptr;
+} ptr_table;
+
+local ptr_table table[MAX_PTR];
+/* This table is used to remember the original form of pointers
+ * to large buffers (64K). Such pointers are normalized with a zero offset.
+ * Since MSDOS is not a preemptive multitasking OS, this table is not
+ * protected from concurrent access. This hack doesn't work anyway on
+ * a protected system like OS/2. Use Microsoft C instead.
+ */
+
+voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+ voidpf buf = opaque; /* just to make some compilers happy */
+ ulg bsize = (ulg)items*size;
+
+ /* If we allocate less than 65520 bytes, we assume that farmalloc
+ * will return a usable pointer which doesn't have to be normalized.
+ */
+ if (bsize < 65520L) {
+ buf = farmalloc(bsize);
+ if (*(ush*)&buf != 0) return buf;
+ } else {
+ buf = farmalloc(bsize + 16L);
+ }
+ if (buf == NULL || next_ptr >= MAX_PTR) return NULL;
+ table[next_ptr].org_ptr = buf;
+
+ /* Normalize the pointer to seg:0 */
+ *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;
+ *(ush*)&buf = 0;
+ table[next_ptr++].new_ptr = buf;
+ return buf;
+}
+
+void zcfree (voidpf opaque, voidpf ptr)
+{
+ int n;
+ if (*(ush*)&ptr != 0) { /* object < 64K */
+ farfree(ptr);
+ return;
+ }
+ /* Find the original pointer */
+ for (n = 0; n < next_ptr; n++) {
+ if (ptr != table[n].new_ptr) continue;
+
+ farfree(table[n].org_ptr);
+ while (++n < next_ptr) {
+ table[n-1] = table[n];
+ }
+ next_ptr--;
+ return;
+ }
+ ptr = opaque; /* just to make some compilers happy */
+ Assert(0, "zcfree: ptr not found");
+}
+
+#endif /* __TURBOC__ */
+
+
+#ifdef M_I86
+/* Microsoft C in 16-bit mode */
+
+# define MY_ZCALLOC
+
+#if (!defined(_MSC_VER) || (_MSC_VER <= 600))
+# define _halloc halloc
+# define _hfree hfree
+#endif
+
+voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+ if (opaque) opaque = 0; /* to make compiler happy */
+ return _halloc((long)items, size);
+}
+
+void zcfree (voidpf opaque, voidpf ptr)
+{
+ if (opaque) opaque = 0; /* to make compiler happy */
+ _hfree(ptr);
+}
+
+#endif /* M_I86 */
+
+#endif /* SYS16BIT */
+
+
+#ifndef MY_ZCALLOC /* Any system without a special alloc function */
+
+#ifndef STDC
+extern voidp malloc OF((uInt size));
+extern voidp calloc OF((uInt items, uInt size));
+extern void free OF((voidpf ptr));
+#endif
+
+voidpf zcalloc (opaque, items, size)
+ voidpf opaque;
+ unsigned items;
+ unsigned size;
+{
+ if (opaque) items += size - size; /* make compiler happy */
+ return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) :
+ (voidpf)calloc(items, size);
+}
+
+void zcfree (opaque, ptr)
+ voidpf opaque;
+ voidpf ptr;
+{
+ free(ptr);
+ if (opaque) return; /* make compiler happy */
+}
+
+#endif /* MY_ZCALLOC */
diff --git a/lib/libz/zutil.h b/lib/libz/zutil.h
new file mode 100644
index 0000000..b7d5eff
--- /dev/null
+++ b/lib/libz/zutil.h
@@ -0,0 +1,269 @@
+/* zutil.h -- internal interface and configuration of the compression library
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id$ */
+
+#ifndef ZUTIL_H
+#define ZUTIL_H
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+#ifdef STDC
+# ifndef _WIN32_WCE
+# include <stddef.h>
+# endif
+# include <string.h>
+# include <stdlib.h>
+#endif
+#ifdef NO_ERRNO_H
+# ifdef _WIN32_WCE
+ /* The Microsoft C Run-Time Library for Windows CE doesn't have
+ * errno. We define it as a global variable to simplify porting.
+ * Its value is always 0 and should not be used. We rename it to
+ * avoid conflict with other libraries that use the same workaround.
+ */
+# define errno z_errno
+# endif
+ extern int errno;
+#else
+# ifndef _WIN32_WCE
+# include <errno.h>
+# endif
+#endif
+
+#ifndef local
+# define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+typedef unsigned char uch;
+typedef uch FAR uchf;
+typedef unsigned short ush;
+typedef ush FAR ushf;
+typedef unsigned long ulg;
+
+extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
+/* (size given to avoid silly warnings with Visual C++) */
+
+#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]
+
+#define ERR_RETURN(strm,err) \
+ return (strm->msg = (char*)ERR_MSG(err), (err))
+/* To be used only when the state is known to be valid */
+
+ /* common constants */
+
+#ifndef DEF_WBITS
+# define DEF_WBITS MAX_WBITS
+#endif
+/* default windowBits for decompression. MAX_WBITS is for compression only */
+
+#if MAX_MEM_LEVEL >= 8
+# define DEF_MEM_LEVEL 8
+#else
+# define DEF_MEM_LEVEL MAX_MEM_LEVEL
+#endif
+/* default memLevel */
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES 2
+/* The three kinds of block type */
+
+#define MIN_MATCH 3
+#define MAX_MATCH 258
+/* The minimum and maximum match lengths */
+
+#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
+
+ /* target dependencies */
+
+#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32))
+# define OS_CODE 0x00
+# if defined(__TURBOC__) || defined(__BORLANDC__)
+# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__))
+ /* Allow compilation with ANSI keywords only enabled */
+ void _Cdecl farfree( void *block );
+ void *_Cdecl farmalloc( unsigned long nbytes );
+# else
+# include <alloc.h>
+# endif
+# else /* MSC or DJGPP */
+# include <malloc.h>
+# endif
+#endif
+
+#ifdef AMIGA
+# define OS_CODE 0x01
+#endif
+
+#if defined(VAXC) || defined(VMS)
+# define OS_CODE 0x02
+# define F_OPEN(name, mode) \
+ fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
+#endif
+
+#if defined(ATARI) || defined(atarist)
+# define OS_CODE 0x05
+#endif
+
+#ifdef OS2
+# define OS_CODE 0x06
+# ifdef M_I86
+ #include <malloc.h>
+# endif
+#endif
+
+#if defined(MACOS) || defined(TARGET_OS_MAC)
+# define OS_CODE 0x07
+# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
+# include <unix.h> /* for fdopen */
+# else
+# ifndef fdopen
+# define fdopen(fd,mode) NULL /* No fdopen() */
+# endif
+# endif
+#endif
+
+#ifdef TOPS20
+# define OS_CODE 0x0a
+#endif
+
+#ifdef WIN32
+# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */
+# define OS_CODE 0x0b
+# endif
+#endif
+
+#ifdef __50SERIES /* Prime/PRIMOS */
+# define OS_CODE 0x0f
+#endif
+
+#if defined(_BEOS_) || defined(RISCOS)
+# define fdopen(fd,mode) NULL /* No fdopen() */
+#endif
+
+#if (defined(_MSC_VER) && (_MSC_VER > 600))
+# if defined(_WIN32_WCE)
+# define fdopen(fd,mode) NULL /* No fdopen() */
+# ifndef _PTRDIFF_T_DEFINED
+ typedef int ptrdiff_t;
+# define _PTRDIFF_T_DEFINED
+# endif
+# else
+# define fdopen(fd,type) _fdopen(fd,type)
+# endif
+#endif
+
+ /* common defaults */
+
+#ifndef OS_CODE
+# define OS_CODE 0x03 /* assume Unix */
+#endif
+
+#ifndef F_OPEN
+# define F_OPEN(name, mode) fopen((name), (mode))
+#endif
+
+ /* functions */
+
+#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550)
+# ifndef HAVE_VSNPRINTF
+# define HAVE_VSNPRINTF
+# endif
+#endif
+#if defined(__CYGWIN__)
+# ifndef HAVE_VSNPRINTF
+# define HAVE_VSNPRINTF
+# endif
+#endif
+#ifndef HAVE_VSNPRINTF
+# ifdef MSDOS
+ /* vsnprintf may exist on some MS-DOS compilers (DJGPP?),
+ but for now we just assume it doesn't. */
+# define NO_vsnprintf
+# endif
+# ifdef __TURBOC__
+# define NO_vsnprintf
+# endif
+# ifdef WIN32
+ /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */
+# if !defined(vsnprintf) && !defined(NO_vsnprintf)
+# define vsnprintf _vsnprintf
+# endif
+# endif
+# ifdef __SASC
+# define NO_vsnprintf
+# endif
+#endif
+#ifdef VMS
+# define NO_vsnprintf
+#endif
+
+#if defined(pyr)
+# define NO_MEMCPY
+#endif
+#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__)
+ /* Use our own functions for small and medium model with MSC <= 5.0.
+ * You may have to use the same strategy for Borland C (untested).
+ * The __SC__ check is for Symantec.
+ */
+# define NO_MEMCPY
+#endif
+#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
+# define HAVE_MEMCPY
+#endif
+#ifdef HAVE_MEMCPY
+# ifdef SMALL_MEDIUM /* MSDOS small or medium model */
+# define zmemcpy _fmemcpy
+# define zmemcmp _fmemcmp
+# define zmemzero(dest, len) _fmemset(dest, 0, len)
+# else
+# define zmemcpy memcpy
+# define zmemcmp memcmp
+# define zmemzero(dest, len) memset(dest, 0, len)
+# endif
+#else
+ extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len));
+ extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len));
+ extern void zmemzero OF((Bytef* dest, uInt len));
+#endif
+
+/* Diagnostic functions */
+#ifdef DEBUG
+# include <stdio.h>
+ extern int z_verbose;
+ extern void z_error OF((char *m));
+# define Assert(cond,msg) {if(!(cond)) z_error(msg);}
+# define Trace(x) {if (z_verbose>=0) fprintf x ;}
+# define Tracev(x) {if (z_verbose>0) fprintf x ;}
+# define Tracevv(x) {if (z_verbose>1) fprintf x ;}
+# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;}
+# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;}
+#else
+# define Assert(cond,msg)
+# define Trace(x)
+# define Tracev(x)
+# define Tracevv(x)
+# define Tracec(c,x)
+# define Tracecv(c,x)
+#endif
+
+
+voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size));
+void zcfree OF((voidpf opaque, voidpf ptr));
+
+#define ZALLOC(strm, items, size) \
+ (*((strm)->zalloc))((strm)->opaque, (items), (size))
+#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
+#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
+
+#endif /* ZUTIL_H */
diff --git a/lib/msun/Makefile b/lib/msun/Makefile
new file mode 100644
index 0000000..de8a54e
--- /dev/null
+++ b/lib/msun/Makefile
@@ -0,0 +1,164 @@
+# @(#)Makefile 5.1beta 93/09/24
+# $FreeBSD$
+#
+# ====================================================
+# 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.
+# ====================================================
+#
+#
+
+.if ${MACHINE_ARCH} == "i386"
+ARCH_SUBDIR= i387
+.else
+ARCH_SUBDIR= ${MACHINE_ARCH}
+.endif
+
+.include "${ARCH_SUBDIR}/Makefile.inc"
+
+.PATH: ${.CURDIR}/bsdsrc
+.PATH: ${.CURDIR}/man
+.PATH: ${.CURDIR}/src
+
+LIB= m
+SHLIBDIR?= /lib
+SHLIB_MAJOR= 4
+COMMON_SRCS= b_exp.c b_log.c b_tgamma.c \
+ e_acos.c e_acosf.c e_acosh.c e_acoshf.c e_asin.c e_asinf.c \
+ e_atan2.c e_atan2f.c e_atanh.c e_atanhf.c e_cosh.c e_coshf.c e_exp.c \
+ e_expf.c e_fmod.c e_fmodf.c e_gamma.c e_gamma_r.c e_gammaf.c \
+ e_gammaf_r.c e_hypot.c e_hypotf.c e_j0.c e_j0f.c e_j1.c e_j1f.c \
+ e_jn.c e_jnf.c e_lgamma.c e_lgamma_r.c e_lgammaf.c e_lgammaf_r.c \
+ e_log.c e_log10.c e_log10f.c e_logf.c e_pow.c e_powf.c e_rem_pio2.c \
+ e_rem_pio2f.c e_remainder.c e_remainderf.c e_scalb.c e_scalbf.c \
+ e_sinh.c e_sinhf.c e_sqrt.c e_sqrtf.c fenv.c \
+ k_cos.c k_cosf.c k_rem_pio2.c k_sin.c k_sinf.c \
+ k_tan.c k_tanf.c \
+ s_asinh.c s_asinhf.c s_atan.c s_atanf.c s_cbrt.c s_cbrtf.c \
+ s_ceil.c s_ceilf.c s_ceill.c \
+ s_copysign.c s_copysignf.c s_cos.c s_cosf.c s_erf.c s_erff.c \
+ s_exp2.c s_exp2f.c s_expm1.c s_expm1f.c s_fabsf.c s_fdim.c \
+ s_finite.c s_finitef.c \
+ s_floor.c s_floorf.c s_floorl.c s_fma.c s_fmaf.c \
+ s_fmax.c s_fmaxf.c s_fmaxl.c s_fmin.c \
+ s_fminf.c s_fminl.c s_frexp.c s_frexpf.c s_ilogb.c s_ilogbf.c \
+ s_ilogbl.c s_isfinite.c s_isnan.c s_isnormal.c \
+ s_llrint.c s_llrintf.c s_llround.c s_llroundf.c s_llroundl.c \
+ s_log1p.c s_log1pf.c s_logb.c s_logbf.c s_lrint.c s_lrintf.c \
+ s_lround.c s_lroundf.c s_lroundl.c s_modff.c \
+ s_nearbyint.c s_nextafter.c s_nextafterf.c \
+ s_nexttowardf.c s_remquo.c s_remquof.c \
+ s_rint.c s_rintf.c s_round.c s_roundf.c s_roundl.c \
+ s_scalbln.c s_scalbn.c s_scalbnf.c s_signbit.c \
+ s_signgam.c s_significand.c s_significandf.c s_sin.c s_sinf.c s_tan.c \
+ s_tanf.c s_tanh.c s_tanhf.c s_trunc.c s_truncf.c s_truncl.c \
+ w_cabs.c w_cabsf.c w_drem.c w_dremf.c
+
+# Location of fpmath.h and _fpmath.h
+LIBCDIR= ${.CURDIR}/../libc
+CFLAGS+= -I${LIBCDIR}/include -I${LIBCDIR}/${MACHINE_ARCH}
+SYM_MAPS+= ${.CURDIR}/Symbol.map
+
+.if defined(SYMVER_ENABLED)
+VERSION_DEF= ${LIBCDIR}/Versions.def
+SYMBOL_MAPS= ${SYM_MAPS}
+.endif
+
+# C99 long double functions
+COMMON_SRCS+= s_copysignl.c s_fabsl.c
+.if ${LDBL_PREC} != 53
+# If long double != double use these; otherwise, we alias the double versions.
+COMMON_SRCS+= s_fmal.c s_frexpl.c s_nextafterl.c s_nexttoward.c s_scalbnl.c
+.endif
+
+# C99 complex functions
+COMMON_SRCS+= s_cimag.c s_cimagf.c s_cimagl.c s_conj.c s_conjf.c s_conjl.c \
+ s_creal.c s_crealf.c s_creall.c
+
+# FreeBSD's C library supplies these functions:
+#COMMON_SRCS+= s_fabs.c s_frexp.c s_isnan.c s_ldexp.c s_modf.c
+
+# Exclude the generic versions of what we provide in the MD area.
+.PATH: ${.CURDIR}/${ARCH_SUBDIR}
+.if defined(ARCH_SRCS)
+.for i in ${ARCH_SRCS}
+COMMON_SRCS:= ${COMMON_SRCS:N${i:R}.c}
+.endfor
+.endif
+
+SRCS= ${COMMON_SRCS} ${ARCH_SRCS}
+
+INCS= fenv.h math.h
+
+MAN= acos.3 acosh.3 asin.3 asinh.3 atan.3 atan2.3 atanh.3 ceil.3 \
+ cimag.3 copysign.3 cos.3 cosh.3 erf.3 exp.3 fabs.3 fdim.3 \
+ feclearexcept.3 feenableexcept.3 fegetenv.3 \
+ fegetround.3 fenv.3 floor.3 \
+ fma.3 fmax.3 fmod.3 hypot.3 ieee.3 ieee_test.3 ilogb.3 j0.3 \
+ lgamma.3 lrint.3 lround.3 math.3 nextafter.3 remainder.3 rint.3 \
+ round.3 scalbn.3 signbit.3 sin.3 sinh.3 sqrt.3 tan.3 tanh.3 trunc.3
+
+MLINKS+=acos.3 acosf.3
+MLINKS+=acosh.3 acoshf.3
+MLINKS+=asin.3 asinf.3
+MLINKS+=asinh.3 asinhf.3
+MLINKS+=atan.3 atanf.3
+MLINKS+=atanh.3 atanhf.3
+MLINKS+=atan2.3 atan2f.3
+MLINKS+=ceil.3 ceilf.3 ceil.3 ceill.3
+MLINKS+=cimag.3 cimagf.3 cimag.3 cimagl.3 \
+ cimag.3 conj.3 cimag.3 conjf.3 cimag.3 conjl.3 \
+ cimag.3 creal.3 cimag.3 crealf.3 cimag.3 creall.3
+MLINKS+=copysign.3 copysignf.3 copysign.3 copysignl.3
+MLINKS+=cos.3 cosf.3
+MLINKS+=cosh.3 coshf.3
+MLINKS+=erf.3 erfc.3 erf.3 erff.3 erf.3 erfcf.3
+MLINKS+=exp.3 expm1.3 exp.3 log.3 exp.3 log10.3 exp.3 log1p.3 exp.3 pow.3 \
+ exp.3 exp2.3 exp.3 exp2f.3 exp.3 expf.3 \
+ exp.3 expm1f.3 exp.3 logf.3 exp.3 powf.3 \
+ exp.3 log10f.3 exp.3 log1pf.3
+MLINKS+=fabs.3 fabsf.3 fabs.3 fabsl.3
+MLINKS+=fdim.3 fdimf.3 fdim.3 fdiml.3
+MLINKS+=feclearexcept.3 fegetexceptflag.3 feclearexcept.3 feraiseexcept.3 \
+ feclearexcept.3 fesetexceptflag.3 feclearexcept.3 fetestexcept.3
+MLINKS+=feenableexcept.3 fedisableexcept.3 feenableexcept.3 fegetexcept.3
+MLINKS+=fegetenv.3 feholdexcept.3 fegetenv.3 fesetenv.3 \
+ fegetenv.3 feupdateenv.3
+MLINKS+=fegetround.3 fesetround.3
+MLINKS+=floor.3 floorf.3 floor.3 floorl.3
+MLINKS+=fma.3 fmaf.3 fma.3 fmal.3
+MLINKS+=fmax.3 fmaxf.3 fmax.3 fmaxl.3 \
+ fmax.3 fmin.3 fmax.3 fminf.3 fmax.3 fminl.3
+MLINKS+=fmod.3 fmodf.3
+MLINKS+=hypot.3 cabs.3 hypot.3 cabsf.3 hypot.3 hypotf.3
+MLINKS+=ieee_test.3 scalb.3 ieee_test.3 scalbf.3
+MLINKS+=ieee_test.3 significand.3 ieee_test.3 significandf.3
+MLINKS+=ilogb.3 ilogbf.3 ilogb.3 ilogbl.3 \
+ ilogb.3 logb.3 ilogb.3 logbf.3
+MLINKS+=j0.3 j1.3 j0.3 jn.3 j0.3 y0.3 j0.3 y1.3 j0.3 y1f.3 j0.3 yn.3
+MLINKS+=j0.3 j0f.3 j0.3 j1f.3 j0.3 jnf.3 j0.3 y0f.3 j0.3 ynf.3
+MLINKS+=lgamma.3 gamma.3 lgamma.3 gammaf.3 lgamma.3 lgammaf.3 lgamma.3 tgamma.3
+MLINKS+=lrint.3 llrint.3 lrint.3 llrintf.3 lrint.3 lrintf.3
+MLINKS+=lround.3 llround.3 lround.3 llroundf.3 lround.3 llroundl.3 \
+ lround.3 lroundf.3 lround.3 lroundl.3
+MLINKS+=nextafter.3 nextafterf.3 nextafter.3 nextafterl.3
+MLINKS+=nextafter.3 nexttoward.3 nextafter.3 nexttowardf.3
+MLINKS+=nextafter.3 nexttowardl.3
+MLINKS+=remainder.3 remainderf.3
+MLINKS+=remainder.3 remquo.3 remainder.3 remquof.3
+MLINKS+=rint.3 rintf.3 rint.3 nearbyint.3 rint.3 nearbyintf.3
+MLINKS+=round.3 roundf.3 round.3 roundl.3
+MLINKS+=scalbn.3 scalbln.3 scalbn.3 scalblnf.3 scalbn.3 scalblnl.3
+MLINKS+=scalbn.3 scalbnf.3 scalbn.3 scalbnl.3
+MLINKS+=sin.3 sinf.3
+MLINKS+=sinh.3 sinhf.3
+MLINKS+=sqrt.3 cbrt.3 sqrt.3 cbrtf.3 sqrt.3 sqrtf.3
+MLINKS+=tan.3 tanf.3
+MLINKS+=tanh.3 tanhf.3
+MLINKS+=trunc.3 truncf.3 trunc.3 truncl.3
+
+.include <bsd.lib.mk>
diff --git a/lib/msun/Symbol.map b/lib/msun/Symbol.map
new file mode 100644
index 0000000..42b8f71
--- /dev/null
+++ b/lib/msun/Symbol.map
@@ -0,0 +1,181 @@
+# $FreeBSD$
+FBSD_1.0 {
+ __fe_dfl_env;
+ tgamma;
+ acos;
+ acosf;
+ acosh;
+ acoshf;
+ asin;
+ asinf;
+ atan2;
+ atan2f;
+ atanh;
+ atanhf;
+ cosh;
+ coshf;
+ exp;
+ expf;
+ fmod;
+ fmodf;
+ gamma;
+ gamma_r;
+ gammaf;
+ gammaf_r;
+ hypot;
+ hypotf;
+ j0;
+ y0;
+ j0f;
+ y0f;
+ j1;
+ y1;
+ j1f;
+ y1f;
+ jn;
+ yn;
+ jnf;
+ ynf;
+ lgamma;
+ lgamma_r;
+ lgammaf;
+ lgammaf_r;
+ log;
+ log10;
+ log10f;
+ logf;
+ pow;
+ powf;
+ remainder;
+ remainderf;
+ scalb;
+ scalbf;
+ sinh;
+ sinhf;
+ sqrt;
+ sqrtf;
+ asinh;
+ asinhf;
+ atan;
+ atanf;
+ cbrt;
+ cbrtf;
+ ceil;
+ ceilf;
+ ceill;
+ cimag;
+ cimagf;
+ cimagl;
+ conj;
+ conjf;
+ conjl;
+ copysign;
+ copysignf;
+ copysignl;
+ cos;
+ cosf;
+ creal;
+ crealf;
+ creall;
+ erf;
+ erfc;
+ erff;
+ erfcf;
+ exp2;
+ exp2f;
+ expm1;
+ expm1f;
+ fabs;
+ fabsf;
+ fabsl;
+ fdim;
+ fdimf;
+ fdiml;
+ finite;
+ finitef;
+ floor;
+ floorf;
+ floorl;
+ fma;
+ fmaf;
+ fmal;
+ fmax;
+ fmaxf;
+ fmaxl;
+ fmin;
+ fminf;
+ fminl;
+ frexp;
+ frexpf;
+ frexpl;
+ ilogb;
+ ilogbf;
+ ilogbl;
+ __isfinite;
+ __isfinitef;
+ __isfinitel;
+ isnanf;
+ __isnanl;
+ __isnormal;
+ __isnormalf;
+ __isnormall;
+ llrint;
+ llrintf;
+ llround;
+ llroundf;
+ llroundl;
+ log1p;
+ log1pf;
+ logb;
+ logbf;
+ lrint;
+ lrintf;
+ lround;
+ lroundf;
+ lroundl;
+ modf;
+ modff;
+ nearbyint;
+ nearbyintf;
+ nextafter;
+ nexttoward;
+ nexttowardl;
+ nextafterl;
+ nextafterf;
+ nexttowardf;
+ remquo;
+ remquof;
+ rint;
+ rintf;
+ round;
+ roundf;
+ roundl;
+ scalbln;
+ scalblnf;
+ scalblnl;
+ scalbn;
+ scalbnl;
+ scalbnf;
+ ldexpf;
+ ldexpl;
+ __signbit;
+ __signbitf;
+ __signbitl;
+ signgam;
+ significand;
+ significandf;
+ sin;
+ sinf;
+ tan;
+ tanf;
+ tanh;
+ tanhf;
+ trunc;
+ truncf;
+ truncl;
+ cabs;
+ z_abs;
+ cabsf;
+ drem;
+ dremf;
+};
diff --git a/lib/msun/alpha/Makefile.inc b/lib/msun/alpha/Makefile.inc
new file mode 100644
index 0000000..f2fc86a
--- /dev/null
+++ b/lib/msun/alpha/Makefile.inc
@@ -0,0 +1,11 @@
+# $FreeBSD$
+
+ARCH_SRCS = s_copysign.S s_copysignf.S
+LDBL_PREC = 53
+SYM_MAPS += ${.CURDIR}/alpha/Symbol.map
+
+# XXX Comment from NetBSD/Alpha:
+# XXX LINT SIGFPEs in e_exp.c's strtod(). FP underflow/denorm software
+# handling is broken (doesn't exist!) on the Alpha port.
+# Stock gcc 2.7.2.1 doesn't understand these options.
+#CFLAGS += -mtrap-precision=i -mfp-trap-mode=su
diff --git a/lib/msun/alpha/Symbol.map b/lib/msun/alpha/Symbol.map
new file mode 100644
index 0000000..1eaba2e
--- /dev/null
+++ b/lib/msun/alpha/Symbol.map
@@ -0,0 +1,13 @@
+# $FreeBSD$
+FBSD_1.0 {
+ fegetenv;
+ feholdexcept;
+ fesetenv;
+ feupdateenv;
+ __feenableexcept;
+ __fedisableexcept;
+ __fegetexcept;
+ feenableexcept;
+ fedisableexcept;
+ fegetexcept;
+};
diff --git a/lib/msun/alpha/fenv.c b/lib/msun/alpha/fenv.c
new file mode 100644
index 0000000..5f0182c
--- /dev/null
+++ b/lib/msun/alpha/fenv.c
@@ -0,0 +1,144 @@
+/*-
+ * Copyright (c) 2004-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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/cdefs.h>
+#include <machine/sysarch.h>
+#include <fenv.h>
+
+const fenv_t __fe_dfl_env = 0x680e000000000000ULL;
+
+struct mask_args {
+ fenv_t mask;
+};
+
+/*
+ * The lower 49 bits of the FPCR are unused by the hardware, so we use
+ * the lower order bits to store the kernel's idea of the FP mask as
+ * described in the Alpha Architecture Manual.
+ */
+int
+fegetenv(fenv_t *envp)
+{
+ struct mask_args p;
+ union __fpcr r;
+
+ /*
+ * The syscall acts as an implicit exception barrier, so we
+ * only need to issue an excb after the mf_fpcr to ensure that
+ * the read is executed before any subsequent FP ops.
+ */
+ sysarch(ALPHA_GET_FPMASK, (char *)&p);
+ __mf_fpcr(&r.__d);
+ *envp = r.__bits | p.mask;
+ __excb();
+ return (0);
+}
+
+int
+feholdexcept(fenv_t *envp)
+{
+ struct mask_args p;
+ union __fpcr r;
+
+ sysarch(ALPHA_GET_FPMASK, (char *)&p);
+ __mf_fpcr(&r.__d);
+ *envp = r.__bits | p.mask;
+ r.__bits &= ~((fenv_t)FE_ALL_EXCEPT << _FPUSW_SHIFT);
+ __mt_fpcr(r.__d);
+ if (p.mask & FE_ALL_EXCEPT) {
+ p.mask = 0;
+ sysarch(ALPHA_SET_FPMASK, &p);
+ }
+ __excb();
+ return (0);
+}
+
+int
+fesetenv(const fenv_t *envp)
+{
+ struct mask_args p;
+ union __fpcr r;
+
+ p.mask = *envp & FE_ALL_EXCEPT;
+ sysarch(ALPHA_SET_FPMASK, &p);
+ r.__bits = *envp & ~FE_ALL_EXCEPT;
+ __mt_fpcr(r.__d);
+ __excb();
+ return (0);
+}
+
+int
+feupdateenv(const fenv_t *envp)
+{
+ struct mask_args p;
+ union __fpcr oldr, newr;
+
+ p.mask = *envp & FE_ALL_EXCEPT;
+ sysarch(ALPHA_SET_FPMASK, &p);
+ __mf_fpcr(&oldr.__d);
+ newr.__bits = *envp & ~FE_ALL_EXCEPT;
+ __excb();
+ __mt_fpcr(newr.__d);
+ feraiseexcept((oldr.__bits >> _FPUSW_SHIFT) & FE_ALL_EXCEPT);
+ return (0);
+}
+
+int
+__feenableexcept(int mask)
+{
+ struct mask_args p;
+
+ sysarch(ALPHA_GET_FPMASK, &p);
+ p.mask |= (mask & FE_ALL_EXCEPT);
+ sysarch(ALPHA_SET_FPMASK, &p);
+ return (p.mask);
+}
+
+int
+__fedisableexcept(int mask)
+{
+ struct mask_args p;
+
+ sysarch(ALPHA_GET_FPMASK, &p);
+ p.mask &= ~(mask & FE_ALL_EXCEPT);
+ sysarch(ALPHA_SET_FPMASK, &p);
+ return (p.mask);
+}
+
+int
+__fegetexcept(void)
+{
+ struct mask_args p;
+
+ sysarch(ALPHA_GET_FPMASK, &p);
+ return (p.mask);
+}
+
+__weak_reference(__feenableexcept, feenableexcept);
+__weak_reference(__fedisableexcept, fedisableexcept);
+__weak_reference(__fegetexcept, fegetexcept);
diff --git a/lib/msun/alpha/fenv.h b/lib/msun/alpha/fenv.h
new file mode 100644
index 0000000..b940a60
--- /dev/null
+++ b/lib/msun/alpha/fenv.h
@@ -0,0 +1,185 @@
+/*-
+ * Copyright (c) 2004-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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _FENV_H_
+#define _FENV_H_
+
+#include <sys/_types.h>
+
+typedef __uint64_t fenv_t;
+typedef __uint16_t fexcept_t;
+
+/* Exception flags */
+#define FE_INVALID 0x02
+#define FE_DIVBYZERO 0x04
+#define FE_OVERFLOW 0x08
+#define FE_UNDERFLOW 0x10
+#define FE_INEXACT 0x20
+#define FE_INTOVF 0x40 /* not maskable */
+#define FE_ALL_EXCEPT (FE_DIVBYZERO | FE_INEXACT | FE_INTOVF | \
+ FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW)
+
+/* Rounding modes */
+#define FE_TOWARDZERO 0x00
+#define FE_DOWNWARD 0x01
+#define FE_TONEAREST 0x02
+#define FE_UPWARD 0x03
+#define _ROUND_MASK (FE_TONEAREST | FE_DOWNWARD | \
+ FE_UPWARD | FE_TOWARDZERO)
+#define _ROUND_SHIFT 58
+
+#define _FPUSW_SHIFT 51
+
+#define __excb() __asm __volatile("excb")
+#define __mf_fpcr(__cw) __asm __volatile("mf_fpcr %0" : "=f" (*(__cw)))
+#define __mt_fpcr(__cw) __asm __volatile("mt_fpcr %0" : : "f" (__cw))
+
+union __fpcr {
+ double __d;
+ fenv_t __bits;
+};
+
+__BEGIN_DECLS
+
+/* Default floating-point environment */
+extern const fenv_t __fe_dfl_env;
+#define FE_DFL_ENV (&__fe_dfl_env)
+
+static __inline int
+feclearexcept(int __excepts)
+{
+ union __fpcr __r;
+
+ __excb();
+ __mf_fpcr(&__r.__d);
+ __r.__bits &= ~((fenv_t)__excepts << _FPUSW_SHIFT);
+ __mt_fpcr(__r.__d);
+ __excb();
+ return (0);
+}
+
+static __inline int
+fegetexceptflag(fexcept_t *__flagp, int __excepts)
+{
+ union __fpcr __r;
+
+ __excb();
+ __mf_fpcr(&__r.__d);
+ __excb();
+ *__flagp = (__r.__bits >> _FPUSW_SHIFT) & __excepts;
+ return (0);
+}
+
+static __inline int
+fesetexceptflag(const fexcept_t *__flagp, int __excepts)
+{
+ union __fpcr __r;
+ fenv_t __xflag, __xexcepts;
+
+ __xflag = (fenv_t)*__flagp << _FPUSW_SHIFT;
+ __xexcepts = (fenv_t)__excepts << _FPUSW_SHIFT;
+ __excb();
+ __mf_fpcr(&__r.__d);
+ __r.__bits &= ~__xexcepts;
+ __r.__bits |= __xflag & __xexcepts;
+ __mt_fpcr(__r.__d);
+ __excb();
+ return (0);
+}
+
+static __inline int
+feraiseexcept(int __excepts)
+{
+
+ /*
+ * XXX Generating exceptions this way does not actually invoke
+ * a userland trap handler when enabled, but neither do
+ * arithmetic operations as far as I can tell. Perhaps there
+ * are more bugs in the kernel trap handler.
+ */
+ fexcept_t __ex = __excepts;
+ fesetexceptflag(&__ex, __excepts);
+ return (0);
+}
+
+static __inline int
+fetestexcept(int __excepts)
+{
+ union __fpcr __r;
+
+ __excb();
+ __mf_fpcr(&__r.__d);
+ __excb();
+ return ((__r.__bits >> _FPUSW_SHIFT) & __excepts);
+}
+
+static __inline int
+fegetround(void)
+{
+ union __fpcr __r;
+
+ /*
+ * No exception barriers should be required here if we assume
+ * that only fesetround() can change the rounding mode.
+ */
+ __mf_fpcr(&__r.__d);
+ return ((int)(__r.__bits >> _ROUND_SHIFT) & _ROUND_MASK);
+}
+
+static __inline int
+fesetround(int __round)
+{
+ union __fpcr __r;
+
+ if (__round & ~_ROUND_MASK)
+ return (-1);
+ __excb();
+ __mf_fpcr(&__r.__d);
+ __r.__bits &= ~((fenv_t)_ROUND_MASK << _ROUND_SHIFT);
+ __r.__bits |= (fenv_t)__round << _ROUND_SHIFT;
+ __mt_fpcr(__r.__d);
+ __excb();
+ return (0);
+}
+
+int fegetenv(fenv_t *__envp);
+int feholdexcept(fenv_t *__envp);
+int fesetenv(const fenv_t *__envp);
+int feupdateenv(const fenv_t *__envp);
+
+#if __BSD_VISIBLE
+
+int feenableexcept(int __mask);
+int fedisableexcept(int __mask);
+int fegetexcept(void);
+
+#endif /* __BSD_VISIBLE */
+
+__END_DECLS
+
+#endif /* !_FENV_H_ */
diff --git a/lib/msun/alpha/s_copysign.S b/lib/msun/alpha/s_copysign.S
new file mode 100644
index 0000000..2a724e2
--- /dev/null
+++ b/lib/msun/alpha/s_copysign.S
@@ -0,0 +1,45 @@
+/* $FreeBSD$ */
+/* From: NetBSD: s_copysign.S,v 1.3 1997/07/30 23:58:38 jtc Exp */
+
+/*-
+ * Copyright (c) 1996 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 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.
+ */
+
+#include <machine/asm.h>
+
+LEAF(copysign, 2)
+ cpys fa1, fa0, fv0
+ RET
+END(copysign)
diff --git a/lib/msun/alpha/s_copysignf.S b/lib/msun/alpha/s_copysignf.S
new file mode 100644
index 0000000..d8a42a4
--- /dev/null
+++ b/lib/msun/alpha/s_copysignf.S
@@ -0,0 +1,45 @@
+/* $FreeBSD$ */
+/* From: NetBSD: s_copysignf.S,v 1.3 1997/07/30 23:58:41 jtc Exp */
+
+/*-
+ * Copyright (c) 1996 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 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.
+ */
+
+#include <machine/asm.h>
+
+LEAF(copysignf, 2)
+ cpys fa1, fa0, fv0
+ RET
+END(copysignf)
diff --git a/lib/msun/amd64/Makefile.inc b/lib/msun/amd64/Makefile.inc
new file mode 100644
index 0000000..d4696a6
--- /dev/null
+++ b/lib/msun/amd64/Makefile.inc
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+ARCH_SRCS = e_sqrt.S e_sqrtf.S s_llrint.S s_llrintf.S s_lrint.S s_lrintf.S \
+ s_remquo.S s_remquof.S s_scalbn.S s_scalbnf.S s_scalbnl.S
+LDBL_PREC = 64
+SYM_MAPS += ${.CURDIR}/amd64/Symbol.map
diff --git a/lib/msun/amd64/Symbol.map b/lib/msun/amd64/Symbol.map
new file mode 100644
index 0000000..470febd
--- /dev/null
+++ b/lib/msun/amd64/Symbol.map
@@ -0,0 +1,12 @@
+# $FreeBSD$
+FBSD_1.0 {
+ fesetexceptflag;
+ feraiseexcept;
+ fegetenv;
+ feholdexcept;
+ feupdateenv;
+ __feenableexcept;
+ __fedisableexcept;
+ feenableexcept;
+ fedisableexcept;
+};
diff --git a/lib/msun/amd64/e_sqrt.S b/lib/msun/amd64/e_sqrt.S
new file mode 100644
index 0000000..f4b4f62
--- /dev/null
+++ b/lib/msun/amd64/e_sqrt.S
@@ -0,0 +1,33 @@
+/*-
+ * 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 <machine/asm.h>
+__FBSDID("$FreeBSD$")
+
+ENTRY(sqrt)
+ sqrtsd %xmm0, %xmm0
+ ret
+
diff --git a/lib/msun/amd64/e_sqrtf.S b/lib/msun/amd64/e_sqrtf.S
new file mode 100644
index 0000000..25f4dfc
--- /dev/null
+++ b/lib/msun/amd64/e_sqrtf.S
@@ -0,0 +1,32 @@
+/*-
+ * 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 <machine/asm.h>
+__FBSDID("$FreeBSD$")
+
+ENTRY(sqrtf)
+ sqrtss %xmm0, %xmm0
+ ret
diff --git a/lib/msun/amd64/fenv.c b/lib/msun/amd64/fenv.c
new file mode 100644
index 0000000..95c82de
--- /dev/null
+++ b/lib/msun/amd64/fenv.c
@@ -0,0 +1,148 @@
+/*-
+ * Copyright (c) 2004-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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <machine/fpu.h>
+#include <fenv.h>
+
+const fenv_t __fe_dfl_env = {
+ { 0xffff0000 | __INITIAL_FPUCW__,
+ 0xffff0000,
+ 0xffffffff,
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff }
+ },
+ __INITIAL_MXCSR__
+};
+
+int
+fesetexceptflag(const fexcept_t *flagp, int excepts)
+{
+ fenv_t env;
+
+ __fnstenv(&env.__x87);
+ env.__x87.__status &= ~excepts;
+ env.__x87.__status |= *flagp & excepts;
+ __fldenv(env.__x87);
+
+ __stmxcsr(&env.__mxcsr);
+ env.__mxcsr &= ~excepts;
+ env.__mxcsr |= *flagp & excepts;
+ __ldmxcsr(env.__mxcsr);
+
+ return (0);
+}
+
+int
+feraiseexcept(int excepts)
+{
+ fexcept_t ex = excepts;
+
+ fesetexceptflag(&ex, excepts);
+ __fwait();
+ return (0);
+}
+
+int
+fegetenv(fenv_t *envp)
+{
+ int control;
+
+ /*
+ * fnstenv masks all exceptions, so we need to save and
+ * restore the control word to avoid this side effect.
+ */
+ __fnstcw(&control);
+ __fnstenv(&envp->__x87);
+ __stmxcsr(&envp->__mxcsr);
+ __fldcw(control);
+ return (0);
+}
+
+int
+feholdexcept(fenv_t *envp)
+{
+ int mxcsr;
+
+ __stmxcsr(&mxcsr);
+ __fnstenv(&envp->__x87);
+ __fnclex();
+ envp->__mxcsr = mxcsr;
+ mxcsr &= ~FE_ALL_EXCEPT;
+ mxcsr |= FE_ALL_EXCEPT << _SSE_EMASK_SHIFT;
+ __ldmxcsr(mxcsr);
+ return (0);
+}
+
+int
+feupdateenv(const fenv_t *envp)
+{
+ int mxcsr, status;
+
+ __fnstsw(&status);
+ __stmxcsr(&mxcsr);
+ fesetenv(envp);
+ feraiseexcept((mxcsr | status) & FE_ALL_EXCEPT);
+ return (0);
+}
+
+int
+__feenableexcept(int mask)
+{
+ int mxcsr, control, omask;
+
+ mask &= FE_ALL_EXCEPT;
+ __fnstcw(&control);
+ __stmxcsr(&mxcsr);
+ omask = (control | mxcsr >> _SSE_EMASK_SHIFT) & FE_ALL_EXCEPT;
+ control &= ~mask;
+ __fldcw(control);
+ mxcsr &= ~(mask << _SSE_EMASK_SHIFT);
+ __ldmxcsr(mxcsr);
+ return (~omask);
+}
+
+int
+__fedisableexcept(int mask)
+{
+ int mxcsr, control, omask;
+
+ mask &= FE_ALL_EXCEPT;
+ __fnstcw(&control);
+ __stmxcsr(&mxcsr);
+ omask = (control | mxcsr >> _SSE_EMASK_SHIFT) & FE_ALL_EXCEPT;
+ control |= mask;
+ __fldcw(control);
+ mxcsr |= mask << _SSE_EMASK_SHIFT;
+ __ldmxcsr(mxcsr);
+ return (~omask);
+}
+
+__weak_reference(__feenableexcept, feenableexcept);
+__weak_reference(__fedisableexcept, fedisableexcept);
diff --git a/lib/msun/amd64/fenv.h b/lib/msun/amd64/fenv.h
new file mode 100644
index 0000000..cb213c2
--- /dev/null
+++ b/lib/msun/amd64/fenv.h
@@ -0,0 +1,203 @@
+/*-
+ * Copyright (c) 2004-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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _FENV_H_
+#define _FENV_H_
+
+#include <sys/cdefs.h>
+#include <sys/_types.h>
+
+typedef struct {
+ struct {
+ __uint32_t __control;
+ __uint32_t __status;
+ __uint32_t __tag;
+ char __other[16];
+ } __x87;
+ __uint32_t __mxcsr;
+} fenv_t;
+
+typedef __uint16_t fexcept_t;
+
+/* Exception flags */
+#define FE_INVALID 0x01
+#define FE_DENORMAL 0x02
+#define FE_DIVBYZERO 0x04
+#define FE_OVERFLOW 0x08
+#define FE_UNDERFLOW 0x10
+#define FE_INEXACT 0x20
+#define FE_ALL_EXCEPT (FE_DIVBYZERO | FE_DENORMAL | FE_INEXACT | \
+ FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW)
+
+/* Rounding modes */
+#define FE_TONEAREST 0x0000
+#define FE_DOWNWARD 0x0400
+#define FE_UPWARD 0x0800
+#define FE_TOWARDZERO 0x0c00
+#define _ROUND_MASK (FE_TONEAREST | FE_DOWNWARD | \
+ FE_UPWARD | FE_TOWARDZERO)
+
+/*
+ * As compared to the x87 control word, the SSE unit's control word
+ * has the rounding control bits offset by 3 and the exception mask
+ * bits offset by 7.
+ */
+#define _SSE_ROUND_SHIFT 3
+#define _SSE_EMASK_SHIFT 7
+
+__BEGIN_DECLS
+
+/* Default floating-point environment */
+extern const fenv_t __fe_dfl_env;
+#define FE_DFL_ENV (&__fe_dfl_env)
+
+#define __fldcw(__cw) __asm __volatile("fldcw %0" : : "m" (__cw))
+#define __fldenv(__env) __asm __volatile("fldenv %0" : : "m" (__env))
+#define __fnclex() __asm __volatile("fnclex")
+#define __fnstenv(__env) __asm __volatile("fnstenv %0" : "=m" (*(__env)))
+#define __fnstcw(__cw) __asm __volatile("fnstcw %0" : "=m" (*(__cw)))
+#define __fnstsw(__sw) __asm __volatile("fnstsw %0" : "=am" (*(__sw)))
+#define __fwait() __asm __volatile("fwait")
+#define __ldmxcsr(__csr) __asm __volatile("ldmxcsr %0" : : "m" (__csr))
+#define __stmxcsr(__csr) __asm __volatile("stmxcsr %0" : "=m" (*(__csr)))
+
+static __inline int
+feclearexcept(int __excepts)
+{
+ fenv_t __env;
+
+ if (__excepts == FE_ALL_EXCEPT) {
+ __fnclex();
+ } else {
+ __fnstenv(&__env.__x87);
+ __env.__x87.__status &= ~__excepts;
+ __fldenv(__env.__x87);
+ }
+ __stmxcsr(&__env.__mxcsr);
+ __env.__mxcsr &= ~__excepts;
+ __ldmxcsr(__env.__mxcsr);
+ return (0);
+}
+
+static __inline int
+fegetexceptflag(fexcept_t *__flagp, int __excepts)
+{
+ int __mxcsr, __status;
+
+ __stmxcsr(&__mxcsr);
+ __fnstsw(&__status);
+ *__flagp = (__mxcsr | __status) & __excepts;
+ return (0);
+}
+
+int fesetexceptflag(const fexcept_t *__flagp, int __excepts);
+int feraiseexcept(int __excepts);
+
+static __inline int
+fetestexcept(int __excepts)
+{
+ int __mxcsr, __status;
+
+ __stmxcsr(&__mxcsr);
+ __fnstsw(&__status);
+ return ((__status | __mxcsr) & __excepts);
+}
+
+static __inline int
+fegetround(void)
+{
+ int __control;
+
+ /*
+ * We assume that the x87 and the SSE unit agree on the
+ * rounding mode. Reading the control word on the x87 turns
+ * out to be about 5 times faster than reading it on the SSE
+ * unit on an Opteron 244.
+ */
+ __fnstcw(&__control);
+ return (__control & _ROUND_MASK);
+}
+
+static __inline int
+fesetround(int __round)
+{
+ int __mxcsr, __control;
+
+ if (__round & ~_ROUND_MASK)
+ return (-1);
+
+ __fnstcw(&__control);
+ __control &= ~_ROUND_MASK;
+ __control |= __round;
+ __fldcw(__control);
+
+ __stmxcsr(&__mxcsr);
+ __mxcsr &= ~(_ROUND_MASK << _SSE_ROUND_SHIFT);
+ __mxcsr |= __round << _SSE_ROUND_SHIFT;
+ __ldmxcsr(__mxcsr);
+
+ return (0);
+}
+
+int fegetenv(fenv_t *__envp);
+int feholdexcept(fenv_t *__envp);
+
+static __inline int
+fesetenv(const fenv_t *__envp)
+{
+
+ __fldenv(__envp->__x87);
+ __ldmxcsr(__envp->__mxcsr);
+ return (0);
+}
+
+int feupdateenv(const fenv_t *__envp);
+
+#if __BSD_VISIBLE
+
+int feenableexcept(int __mask);
+int fedisableexcept(int __mask);
+
+static __inline int
+fegetexcept(void)
+{
+ int __control;
+
+ /*
+ * We assume that the masks for the x87 and the SSE unit are
+ * the same.
+ */
+ __fnstcw(&__control);
+ return (~__control & FE_ALL_EXCEPT);
+}
+
+#endif /* __BSD_VISIBLE */
+
+__END_DECLS
+
+#endif /* !_FENV_H_ */
diff --git a/lib/msun/amd64/s_llrint.S b/lib/msun/amd64/s_llrint.S
new file mode 100644
index 0000000..ab09846
--- /dev/null
+++ b/lib/msun/amd64/s_llrint.S
@@ -0,0 +1,6 @@
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$")
+
+/* sizeof(long) == sizeof(long long) */
+#define fn llrint
+#include "s_lrint.S"
diff --git a/lib/msun/amd64/s_llrintf.S b/lib/msun/amd64/s_llrintf.S
new file mode 100644
index 0000000..e810e40
--- /dev/null
+++ b/lib/msun/amd64/s_llrintf.S
@@ -0,0 +1,6 @@
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$")
+
+/* sizeof(long) == sizeof(long long) */
+#define fn llrintf
+#include "s_lrintf.S"
diff --git a/lib/msun/amd64/s_lrint.S b/lib/msun/amd64/s_lrint.S
new file mode 100644
index 0000000..9059a38
--- /dev/null
+++ b/lib/msun/amd64/s_lrint.S
@@ -0,0 +1,36 @@
+/*-
+ * 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 <machine/asm.h>
+
+#ifndef fn
+__FBSDID("$FreeBSD$")
+#define fn lrint
+#endif
+
+ENTRY(fn)
+ cvtsd2si %xmm0, %rax
+ ret
diff --git a/lib/msun/amd64/s_lrintf.S b/lib/msun/amd64/s_lrintf.S
new file mode 100644
index 0000000..cc27d20
--- /dev/null
+++ b/lib/msun/amd64/s_lrintf.S
@@ -0,0 +1,36 @@
+/*-
+ * 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 <machine/asm.h>
+
+#ifndef fn
+__FBSDID("$FreeBSD$")
+#define fn lrintf
+#endif
+
+ENTRY(fn)
+ cvtss2si %xmm0, %rax
+ ret
diff --git a/lib/msun/amd64/s_remquo.S b/lib/msun/amd64/s_remquo.S
new file mode 100644
index 0000000..eb113d7
--- /dev/null
+++ b/lib/msun/amd64/s_remquo.S
@@ -0,0 +1,65 @@
+/*-
+ * 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.
+ */
+
+/*
+ * Based on public-domain remainder routine by J.T. Conklin <jtc@NetBSD.org>.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+ENTRY(remquo)
+ movsd %xmm0,-8(%rsp)
+ movsd %xmm1,-16(%rsp)
+ fldl -16(%rsp)
+ fldl -8(%rsp)
+1: fprem1
+ fstsw %ax
+ btw $10,%ax
+ jc 1b
+ fstp %st(1)
+/* Extract the three low-order bits of the quotient from C0,C3,C1. */
+ shrl $6,%eax
+ movl %eax,%ecx
+ andl $0x108,%eax
+ rorl $7,%eax
+ orl %eax,%ecx
+ roll $4,%eax
+ orl %ecx,%eax
+ andl $7,%eax
+/* Negate the quotient bits if x*y<0. Avoid using an unpredictable branch. */
+ movl -12(%rsp),%ecx
+ xorl -4(%rsp),%ecx
+ sarl $16,%ecx
+ sarl $16,%ecx
+ xorl %ecx,%eax
+ andl $1,%ecx
+ addl %ecx,%eax
+/* Store the quotient and return. */
+ movl %eax,(%rdi)
+ fstpl -8(%rsp)
+ movsd -8(%rsp),%xmm0
+ ret
diff --git a/lib/msun/amd64/s_remquof.S b/lib/msun/amd64/s_remquof.S
new file mode 100644
index 0000000..0833f5b
--- /dev/null
+++ b/lib/msun/amd64/s_remquof.S
@@ -0,0 +1,65 @@
+/*-
+ * 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.
+ */
+
+/*
+ * Based on public-domain remainder routine by J.T. Conklin <jtc@NetBSD.org>.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+ENTRY(remquof)
+ movss %xmm0,-4(%rsp)
+ movss %xmm1,-8(%rsp)
+ flds -8(%rsp)
+ flds -4(%rsp)
+1: fprem1
+ fstsw %ax
+ btw $10,%ax
+ jc 1b
+ fstp %st(1)
+/* Extract the three low-order bits of the quotient from C0,C3,C1. */
+ shrl $6,%eax
+ movl %eax,%ecx
+ andl $0x108,%eax
+ rorl $7,%eax
+ orl %eax,%ecx
+ roll $4,%eax
+ orl %ecx,%eax
+ andl $7,%eax
+/* Negate the quotient bits if x*y<0. Avoid using an unpredictable branch. */
+ movl -8(%rsp),%ecx
+ xorl -4(%rsp),%ecx
+ sarl $16,%ecx
+ sarl $16,%ecx
+ xorl %ecx,%eax
+ andl $1,%ecx
+ addl %ecx,%eax
+/* Store the quotient and return. */
+ movl %eax,(%rdi)
+ fstps -4(%rsp)
+ movss -4(%rsp),%xmm0
+ ret
diff --git a/lib/msun/amd64/s_scalbn.S b/lib/msun/amd64/s_scalbn.S
new file mode 100644
index 0000000..c9ac808
--- /dev/null
+++ b/lib/msun/amd64/s_scalbn.S
@@ -0,0 +1,39 @@
+/*-
+ * 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 <machine/asm.h>
+__FBSDID("$FreeBSD$")
+
+ENTRY(scalbn)
+ movsd %xmm0,-8(%rsp)
+ movl %edi,-12(%rsp)
+ fildl -12(%rsp)
+ fldl -8(%rsp)
+ fscale
+ fstp %st(1)
+ fstpl -8(%rsp)
+ movsd -8(%rsp),%xmm0
+ ret
diff --git a/lib/msun/amd64/s_scalbnf.S b/lib/msun/amd64/s_scalbnf.S
new file mode 100644
index 0000000..a9b9f80
--- /dev/null
+++ b/lib/msun/amd64/s_scalbnf.S
@@ -0,0 +1,42 @@
+/*-
+ * 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 <machine/asm.h>
+__FBSDID("$FreeBSD$")
+
+ENTRY(scalbnf)
+ movss %xmm0,-8(%rsp)
+ movl %edi,-4(%rsp)
+ fildl -4(%rsp)
+ flds -8(%rsp)
+ fscale
+ fstp %st(1)
+ fstps -8(%rsp)
+ movss -8(%rsp),%xmm0
+ ret
+
+.globl CNAME(ldexpf)
+.set CNAME(ldexpf),CNAME(scalbnf)
diff --git a/lib/msun/amd64/s_scalbnl.S b/lib/msun/amd64/s_scalbnl.S
new file mode 100644
index 0000000..8dfa810
--- /dev/null
+++ b/lib/msun/amd64/s_scalbnl.S
@@ -0,0 +1,19 @@
+/*
+ * Based on code written by J.T. Conklin <jtc@netbsd.org>.
+ * Public domain.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$")
+/* RCSID("$NetBSD: s_scalbnf.S,v 1.4 1999/01/02 05:15:40 kristerw Exp $") */
+
+ENTRY(scalbnl)
+ movl %edi,-4(%rsp)
+ fildl -4(%rsp)
+ fldt 8(%rsp)
+ fscale
+ fstp %st(1)
+ ret
+
+.globl CNAME(ldexpl)
+.set CNAME(ldexpl),CNAME(scalbnl)
diff --git a/lib/msun/arm/Makefile.inc b/lib/msun/arm/Makefile.inc
new file mode 100644
index 0000000..7d9e10b
--- /dev/null
+++ b/lib/msun/arm/Makefile.inc
@@ -0,0 +1,4 @@
+# $FreeBSD$
+
+LDBL_PREC = 53
+SYM_MAPS += ${.CURDIR}/arm/Symbol.map
diff --git a/lib/msun/arm/Symbol.map b/lib/msun/arm/Symbol.map
new file mode 100644
index 0000000..7e6e56d
--- /dev/null
+++ b/lib/msun/arm/Symbol.map
@@ -0,0 +1,3 @@
+# $FreeBSD$
+FBSD_1.0 {
+};
diff --git a/lib/msun/arm/fenv.c b/lib/msun/arm/fenv.c
new file mode 100644
index 0000000..a6781e0
--- /dev/null
+++ b/lib/msun/arm/fenv.c
@@ -0,0 +1,35 @@
+/*-
+ * 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 <fenv.h>
+
+/*
+ * Hopefully the system ID byte is immutable, so it's valid to use
+ * this as a default environment.
+ */
+const fenv_t __fe_dfl_env = 0;
diff --git a/lib/msun/arm/fenv.h b/lib/msun/arm/fenv.h
new file mode 100644
index 0000000..d540ae2
--- /dev/null
+++ b/lib/msun/arm/fenv.h
@@ -0,0 +1,217 @@
+/*-
+ * Copyright (c) 2004-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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _FENV_H_
+#define _FENV_H_
+
+#include <sys/_types.h>
+
+typedef __uint32_t fenv_t;
+typedef __uint32_t fexcept_t;
+
+/* Exception flags */
+#define FE_INVALID 0x0001
+#define FE_DIVBYZERO 0x0002
+#define FE_OVERFLOW 0x0004
+#define FE_UNDERFLOW 0x0008
+#define FE_INEXACT 0x0010
+#define FE_ALL_EXCEPT (FE_DIVBYZERO | FE_INEXACT | \
+ FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW)
+
+/* Rounding modes */
+#define FE_TONEAREST 0x0000
+#define FE_TOWARDZERO 0x0001
+#define FE_UPWARD 0x0002
+#define FE_DOWNWARD 0x0003
+#define _ROUND_MASK (FE_TONEAREST | FE_DOWNWARD | \
+ FE_UPWARD | FE_TOWARDZERO)
+__BEGIN_DECLS
+
+/* Default floating-point environment */
+extern const fenv_t __fe_dfl_env;
+#define FE_DFL_ENV (&__fe_dfl_env)
+
+/* We need to be able to map status flag positions to mask flag positions */
+#define _FPUSW_SHIFT 16
+#define _ENABLE_MASK (FE_ALL_EXCEPT << _FPUSW_SHIFT)
+
+#ifdef ARM_HARD_FLOAT
+#define __rfs(__fpsr) __asm __volatile("rfs %0" : "=r" (*(__fpsr)))
+#define __wfs(__fpsr) __asm __volatile("wfs %0" : : "r" (__fpsr))
+#else
+#define __rfs(__fpsr)
+#define __wfs(__fpsr)
+#endif
+
+static __inline int
+feclearexcept(int __excepts)
+{
+ fexcept_t __fpsr;
+
+ __rfs(&__fpsr);
+ __fpsr &= ~__excepts;
+ __wfs(__fpsr);
+ return (0);
+}
+
+static __inline int
+fegetexceptflag(fexcept_t *__flagp, int __excepts)
+{
+ fexcept_t __fpsr;
+
+ __rfs(&__fpsr);
+ *__flagp = __fpsr & __excepts;
+ return (0);
+}
+
+static __inline int
+fesetexceptflag(const fexcept_t *__flagp, int __excepts)
+{
+ fexcept_t __fpsr;
+
+ __rfs(&__fpsr);
+ __fpsr &= ~__excepts;
+ __fpsr |= *__flagp & __excepts;
+ __wfs(__fpsr);
+ return (0);
+}
+
+static __inline int
+feraiseexcept(int __excepts)
+{
+ fexcept_t __ex = __excepts;
+
+ fesetexceptflag(&__ex, __excepts); /* XXX */
+ return (0);
+}
+
+static __inline int
+fetestexcept(int __excepts)
+{
+ fexcept_t __fpsr;
+
+ __rfs(&__fpsr);
+ return (__fpsr & __excepts);
+}
+
+static __inline int
+fegetround(void)
+{
+
+ /*
+ * Apparently, the rounding mode is specified as part of the
+ * instruction format on ARM, so the dynamic rounding mode is
+ * indeterminate. Some FPUs may differ.
+ */
+ return (-1);
+}
+
+static __inline int
+fesetround(int __round)
+{
+
+ return (-1);
+}
+
+static __inline int
+fegetenv(fenv_t *__envp)
+{
+
+ __rfs(__envp);
+ return (0);
+}
+
+static __inline int
+feholdexcept(fenv_t *__envp)
+{
+ fenv_t __env;
+
+ __rfs(&__env);
+ *__envp = __env;
+ __env &= ~(FE_ALL_EXCEPT | _ENABLE_MASK);
+ __wfs(__env);
+ return (0);
+}
+
+static __inline int
+fesetenv(const fenv_t *__envp)
+{
+
+ __wfs(*__envp);
+ return (0);
+}
+
+static __inline int
+feupdateenv(const fenv_t *__envp)
+{
+ fexcept_t __fpsr;
+
+ __rfs(&__fpsr);
+ __wfs(*__envp);
+ feraiseexcept(__fpsr & FE_ALL_EXCEPT);
+ return (0);
+}
+
+#if __BSD_VISIBLE
+
+static __inline int
+feenableexcept(int __mask)
+{
+ fenv_t __old_fpsr, __new_fpsr;
+
+ __rfs(&__old_fpsr);
+ __new_fpsr = __old_fpsr | (__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT;
+ __wfs(__new_fpsr);
+ return ((__old_fpsr >> _FPUSW_SHIFT) & FE_ALL_EXCEPT);
+}
+
+static __inline int
+fedisableexcept(int __mask)
+{
+ fenv_t __old_fpsr, __new_fpsr;
+
+ __rfs(&__old_fpsr);
+ __new_fpsr = __old_fpsr & ~((__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT);
+ __wfs(__new_fpsr);
+ return ((__old_fpsr >> _FPUSW_SHIFT) & FE_ALL_EXCEPT);
+}
+
+static __inline int
+fegetexcept(void)
+{
+ fenv_t __fpsr;
+
+ __rfs(&__fpsr);
+ return ((__fpsr & _ENABLE_MASK) >> _FPUSW_SHIFT);
+}
+
+#endif /* __BSD_VISIBLE */
+
+__END_DECLS
+
+#endif /* !_FENV_H_ */
diff --git a/lib/msun/bsdsrc/b_exp.c b/lib/msun/bsdsrc/b_exp.c
new file mode 100644
index 0000000..98d2247
--- /dev/null
+++ b/lib/msun/bsdsrc/b_exp.c
@@ -0,0 +1,177 @@
+/*
+ * 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. 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)exp.c 8.1 (Berkeley) 6/4/93";
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+
+/* EXP(X)
+ * RETURN THE EXPONENTIAL OF X
+ * DOUBLE PRECISION (IEEE 53 bits, VAX D FORMAT 56 BITS)
+ * CODED IN C BY K.C. NG, 1/19/85;
+ * REVISED BY K.C. NG on 2/6/85, 2/15/85, 3/7/85, 3/24/85, 4/16/85, 6/14/86.
+ *
+ * Required system supported functions:
+ * scalb(x,n)
+ * copysign(x,y)
+ * finite(x)
+ *
+ * Method:
+ * 1. Argument Reduction: given the input x, find r and integer k such
+ * that
+ * x = k*ln2 + r, |r| <= 0.5*ln2 .
+ * r will be represented as r := z+c for better accuracy.
+ *
+ * 2. Compute exp(r) by
+ *
+ * exp(r) = 1 + r + r*R1/(2-R1),
+ * where
+ * R1 = x - x^2*(p1+x^2*(p2+x^2*(p3+x^2*(p4+p5*x^2)))).
+ *
+ * 3. exp(x) = 2^k * exp(r) .
+ *
+ * Special cases:
+ * exp(INF) is INF, exp(NaN) is NaN;
+ * exp(-INF)= 0;
+ * for finite argument, only exp(0)=1 is exact.
+ *
+ * Accuracy:
+ * exp(x) returns the exponential of x nearly rounded. In a test run
+ * with 1,156,000 random arguments on a VAX, the maximum observed
+ * error was 0.869 ulps (units in the last place).
+ */
+
+#include "mathimpl.h"
+
+const static double p1 = 0x1.555555555553ep-3;
+const static double p2 = -0x1.6c16c16bebd93p-9;
+const static double p3 = 0x1.1566aaf25de2cp-14;
+const static double p4 = -0x1.bbd41c5d26bf1p-20;
+const static double p5 = 0x1.6376972bea4d0p-25;
+const static double ln2hi = 0x1.62e42fee00000p-1;
+const static double ln2lo = 0x1.a39ef35793c76p-33;
+const static double lnhuge = 0x1.6602b15b7ecf2p9;
+const static double lntiny = -0x1.77af8ebeae354p9;
+const static double invln2 = 0x1.71547652b82fep0;
+
+#if 0
+double exp(x)
+double x;
+{
+ double z,hi,lo,c;
+ int k;
+
+#if !defined(vax)&&!defined(tahoe)
+ if(x!=x) return(x); /* x is NaN */
+#endif /* !defined(vax)&&!defined(tahoe) */
+ if( x <= lnhuge ) {
+ if( x >= lntiny ) {
+
+ /* argument reduction : x --> x - k*ln2 */
+
+ k=invln2*x+copysign(0.5,x); /* k=NINT(x/ln2) */
+
+ /* express x-k*ln2 as hi-lo and let x=hi-lo rounded */
+
+ hi=x-k*ln2hi;
+ x=hi-(lo=k*ln2lo);
+
+ /* return 2^k*[1+x+x*c/(2+c)] */
+ z=x*x;
+ c= x - z*(p1+z*(p2+z*(p3+z*(p4+z*p5))));
+ return scalb(1.0+(hi-(lo-(x*c)/(2.0-c))),k);
+
+ }
+ /* end of x > lntiny */
+
+ else
+ /* exp(-big#) underflows to zero */
+ if(finite(x)) return(scalb(1.0,-5000));
+
+ /* exp(-INF) is zero */
+ else return(0.0);
+ }
+ /* end of x < lnhuge */
+
+ else
+ /* exp(INF) is INF, exp(+big#) overflows to INF */
+ return( finite(x) ? scalb(1.0,5000) : x);
+}
+#endif
+
+/* returns exp(r = x + c) for |c| < |x| with no overlap. */
+
+double __exp__D(x, c)
+double x, c;
+{
+ double z,hi,lo;
+ int k;
+
+ if (x != x) /* x is NaN */
+ return(x);
+ if ( x <= lnhuge ) {
+ if ( x >= lntiny ) {
+
+ /* argument reduction : x --> x - k*ln2 */
+ z = invln2*x;
+ k = z + copysign(.5, x);
+
+ /* express (x+c)-k*ln2 as hi-lo and let x=hi-lo rounded */
+
+ hi=(x-k*ln2hi); /* Exact. */
+ x= hi - (lo = k*ln2lo-c);
+ /* return 2^k*[1+x+x*c/(2+c)] */
+ z=x*x;
+ c= x - z*(p1+z*(p2+z*(p3+z*(p4+z*p5))));
+ c = (x*c)/(2.0-c);
+
+ return scalb(1.+(hi-(lo - c)), k);
+ }
+ /* end of x > lntiny */
+
+ else
+ /* exp(-big#) underflows to zero */
+ if(finite(x)) return(scalb(1.0,-5000));
+
+ /* exp(-INF) is zero */
+ else return(0.0);
+ }
+ /* end of x < lnhuge */
+
+ else
+ /* exp(INF) is INF, exp(+big#) overflows to INF */
+ return( finite(x) ? scalb(1.0,5000) : x);
+}
diff --git a/lib/msun/bsdsrc/b_log.c b/lib/msun/bsdsrc/b_log.c
new file mode 100644
index 0000000..b9f1473
--- /dev/null
+++ b/lib/msun/bsdsrc/b_log.c
@@ -0,0 +1,473 @@
+/*
+ * 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. 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)log.c 8.2 (Berkeley) 11/30/93";
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <math.h>
+#include <errno.h>
+
+#include "mathimpl.h"
+
+/* Table-driven natural logarithm.
+ *
+ * This code was derived, with minor modifications, from:
+ * Peter Tang, "Table-Driven Implementation of the
+ * Logarithm in IEEE Floating-Point arithmetic." ACM Trans.
+ * Math Software, vol 16. no 4, pp 378-400, Dec 1990).
+ *
+ * Calculates log(2^m*F*(1+f/F)), |f/j| <= 1/256,
+ * where F = j/128 for j an integer in [0, 128].
+ *
+ * log(2^m) = log2_hi*m + log2_tail*m
+ * since m is an integer, the dominant term is exact.
+ * m has at most 10 digits (for subnormal numbers),
+ * and log2_hi has 11 trailing zero bits.
+ *
+ * log(F) = logF_hi[j] + logF_lo[j] is in tabular form in log_table.h
+ * logF_hi[] + 512 is exact.
+ *
+ * log(1+f/F) = 2*f/(2*F + f) + 1/12 * (2*f/(2*F + f))**3 + ...
+ * the leading term is calculated to extra precision in two
+ * parts, the larger of which adds exactly to the dominant
+ * m and F terms.
+ * There are two cases:
+ * 1. when m, j are non-zero (m | j), use absolute
+ * precision for the leading term.
+ * 2. when m = j = 0, |1-x| < 1/256, and log(x) ~= (x-1).
+ * In this case, use a relative precision of 24 bits.
+ * (This is done differently in the original paper)
+ *
+ * Special cases:
+ * 0 return signalling -Inf
+ * neg return signalling NaN
+ * +Inf return +Inf
+*/
+
+#define N 128
+
+/* Table of log(Fj) = logF_head[j] + logF_tail[j], for Fj = 1+j/128.
+ * Used for generation of extend precision logarithms.
+ * The constant 35184372088832 is 2^45, so the divide is exact.
+ * It ensures correct reading of logF_head, even for inaccurate
+ * decimal-to-binary conversion routines. (Everybody gets the
+ * right answer for integers less than 2^53.)
+ * Values for log(F) were generated using error < 10^-57 absolute
+ * with the bc -l package.
+*/
+static double A1 = .08333333333333178827;
+static double A2 = .01250000000377174923;
+static double A3 = .002232139987919447809;
+static double A4 = .0004348877777076145742;
+
+static double logF_head[N+1] = {
+ 0.,
+ .007782140442060381246,
+ .015504186535963526694,
+ .023167059281547608406,
+ .030771658666765233647,
+ .038318864302141264488,
+ .045809536031242714670,
+ .053244514518837604555,
+ .060624621816486978786,
+ .067950661908525944454,
+ .075223421237524235039,
+ .082443669210988446138,
+ .089612158689760690322,
+ .096729626458454731618,
+ .103796793681567578460,
+ .110814366340264314203,
+ .117783035656430001836,
+ .124703478501032805070,
+ .131576357788617315236,
+ .138402322859292326029,
+ .145182009844575077295,
+ .151916042025732167530,
+ .158605030176659056451,
+ .165249572895390883786,
+ .171850256926518341060,
+ .178407657472689606947,
+ .184922338493834104156,
+ .191394852999565046047,
+ .197825743329758552135,
+ .204215541428766300668,
+ .210564769107350002741,
+ .216873938300523150246,
+ .223143551314024080056,
+ .229374101064877322642,
+ .235566071312860003672,
+ .241719936886966024758,
+ .247836163904594286577,
+ .253915209980732470285,
+ .259957524436686071567,
+ .265963548496984003577,
+ .271933715484010463114,
+ .277868451003087102435,
+ .283768173130738432519,
+ .289633292582948342896,
+ .295464212893421063199,
+ .301261330578199704177,
+ .307025035294827830512,
+ .312755710004239517729,
+ .318453731118097493890,
+ .324119468654316733591,
+ .329753286372579168528,
+ .335355541920762334484,
+ .340926586970454081892,
+ .346466767346100823488,
+ .351976423156884266063,
+ .357455888922231679316,
+ .362905493689140712376,
+ .368325561158599157352,
+ .373716409793814818840,
+ .379078352934811846353,
+ .384411698910298582632,
+ .389716751140440464951,
+ .394993808240542421117,
+ .400243164127459749579,
+ .405465108107819105498,
+ .410659924985338875558,
+ .415827895143593195825,
+ .420969294644237379543,
+ .426084395310681429691,
+ .431173464818130014464,
+ .436236766774527495726,
+ .441274560805140936281,
+ .446287102628048160113,
+ .451274644139630254358,
+ .456237433481874177232,
+ .461175715122408291790,
+ .466089729924533457960,
+ .470979715219073113985,
+ .475845904869856894947,
+ .480688529345570714212,
+ .485507815781602403149,
+ .490303988045525329653,
+ .495077266798034543171,
+ .499827869556611403822,
+ .504556010751912253908,
+ .509261901790523552335,
+ .513945751101346104405,
+ .518607764208354637958,
+ .523248143765158602036,
+ .527867089620485785417,
+ .532464798869114019908,
+ .537041465897345915436,
+ .541597282432121573947,
+ .546132437597407260909,
+ .550647117952394182793,
+ .555141507540611200965,
+ .559615787935399566777,
+ .564070138285387656651,
+ .568504735352689749561,
+ .572919753562018740922,
+ .577315365035246941260,
+ .581691739635061821900,
+ .586049045003164792433,
+ .590387446602107957005,
+ .594707107746216934174,
+ .599008189645246602594,
+ .603290851438941899687,
+ .607555250224322662688,
+ .611801541106615331955,
+ .616029877215623855590,
+ .620240409751204424537,
+ .624433288012369303032,
+ .628608659422752680256,
+ .632766669570628437213,
+ .636907462236194987781,
+ .641031179420679109171,
+ .645137961373620782978,
+ .649227946625615004450,
+ .653301272011958644725,
+ .657358072709030238911,
+ .661398482245203922502,
+ .665422632544505177065,
+ .669430653942981734871,
+ .673422675212350441142,
+ .677398823590920073911,
+ .681359224807238206267,
+ .685304003098281100392,
+ .689233281238557538017,
+ .693147180560117703862
+};
+
+static double logF_tail[N+1] = {
+ 0.,
+ -.00000000000000543229938420049,
+ .00000000000000172745674997061,
+ -.00000000000001323017818229233,
+ -.00000000000001154527628289872,
+ -.00000000000000466529469958300,
+ .00000000000005148849572685810,
+ -.00000000000002532168943117445,
+ -.00000000000005213620639136504,
+ -.00000000000001819506003016881,
+ .00000000000006329065958724544,
+ .00000000000008614512936087814,
+ -.00000000000007355770219435028,
+ .00000000000009638067658552277,
+ .00000000000007598636597194141,
+ .00000000000002579999128306990,
+ -.00000000000004654729747598444,
+ -.00000000000007556920687451336,
+ .00000000000010195735223708472,
+ -.00000000000017319034406422306,
+ -.00000000000007718001336828098,
+ .00000000000010980754099855238,
+ -.00000000000002047235780046195,
+ -.00000000000008372091099235912,
+ .00000000000014088127937111135,
+ .00000000000012869017157588257,
+ .00000000000017788850778198106,
+ .00000000000006440856150696891,
+ .00000000000016132822667240822,
+ -.00000000000007540916511956188,
+ -.00000000000000036507188831790,
+ .00000000000009120937249914984,
+ .00000000000018567570959796010,
+ -.00000000000003149265065191483,
+ -.00000000000009309459495196889,
+ .00000000000017914338601329117,
+ -.00000000000001302979717330866,
+ .00000000000023097385217586939,
+ .00000000000023999540484211737,
+ .00000000000015393776174455408,
+ -.00000000000036870428315837678,
+ .00000000000036920375082080089,
+ -.00000000000009383417223663699,
+ .00000000000009433398189512690,
+ .00000000000041481318704258568,
+ -.00000000000003792316480209314,
+ .00000000000008403156304792424,
+ -.00000000000034262934348285429,
+ .00000000000043712191957429145,
+ -.00000000000010475750058776541,
+ -.00000000000011118671389559323,
+ .00000000000037549577257259853,
+ .00000000000013912841212197565,
+ .00000000000010775743037572640,
+ .00000000000029391859187648000,
+ -.00000000000042790509060060774,
+ .00000000000022774076114039555,
+ .00000000000010849569622967912,
+ -.00000000000023073801945705758,
+ .00000000000015761203773969435,
+ .00000000000003345710269544082,
+ -.00000000000041525158063436123,
+ .00000000000032655698896907146,
+ -.00000000000044704265010452446,
+ .00000000000034527647952039772,
+ -.00000000000007048962392109746,
+ .00000000000011776978751369214,
+ -.00000000000010774341461609578,
+ .00000000000021863343293215910,
+ .00000000000024132639491333131,
+ .00000000000039057462209830700,
+ -.00000000000026570679203560751,
+ .00000000000037135141919592021,
+ -.00000000000017166921336082431,
+ -.00000000000028658285157914353,
+ -.00000000000023812542263446809,
+ .00000000000006576659768580062,
+ -.00000000000028210143846181267,
+ .00000000000010701931762114254,
+ .00000000000018119346366441110,
+ .00000000000009840465278232627,
+ -.00000000000033149150282752542,
+ -.00000000000018302857356041668,
+ -.00000000000016207400156744949,
+ .00000000000048303314949553201,
+ -.00000000000071560553172382115,
+ .00000000000088821239518571855,
+ -.00000000000030900580513238244,
+ -.00000000000061076551972851496,
+ .00000000000035659969663347830,
+ .00000000000035782396591276383,
+ -.00000000000046226087001544578,
+ .00000000000062279762917225156,
+ .00000000000072838947272065741,
+ .00000000000026809646615211673,
+ -.00000000000010960825046059278,
+ .00000000000002311949383800537,
+ -.00000000000058469058005299247,
+ -.00000000000002103748251144494,
+ -.00000000000023323182945587408,
+ -.00000000000042333694288141916,
+ -.00000000000043933937969737844,
+ .00000000000041341647073835565,
+ .00000000000006841763641591466,
+ .00000000000047585534004430641,
+ .00000000000083679678674757695,
+ -.00000000000085763734646658640,
+ .00000000000021913281229340092,
+ -.00000000000062242842536431148,
+ -.00000000000010983594325438430,
+ .00000000000065310431377633651,
+ -.00000000000047580199021710769,
+ -.00000000000037854251265457040,
+ .00000000000040939233218678664,
+ .00000000000087424383914858291,
+ .00000000000025218188456842882,
+ -.00000000000003608131360422557,
+ -.00000000000050518555924280902,
+ .00000000000078699403323355317,
+ -.00000000000067020876961949060,
+ .00000000000016108575753932458,
+ .00000000000058527188436251509,
+ -.00000000000035246757297904791,
+ -.00000000000018372084495629058,
+ .00000000000088606689813494916,
+ .00000000000066486268071468700,
+ .00000000000063831615170646519,
+ .00000000000025144230728376072,
+ -.00000000000017239444525614834
+};
+
+#if 0
+double
+#ifdef _ANSI_SOURCE
+log(double x)
+#else
+log(x) double x;
+#endif
+{
+ int m, j;
+ double F, f, g, q, u, u2, v, zero = 0.0, one = 1.0;
+ volatile double u1;
+
+ /* Catch special cases */
+ if (x <= 0)
+ if (x == zero) /* log(0) = -Inf */
+ return (-one/zero);
+ else /* log(neg) = NaN */
+ return (zero/zero);
+ else if (!finite(x))
+ return (x+x); /* x = NaN, Inf */
+
+ /* Argument reduction: 1 <= g < 2; x/2^m = g; */
+ /* y = F*(1 + f/F) for |f| <= 2^-8 */
+
+ m = logb(x);
+ g = ldexp(x, -m);
+ if (m == -1022) {
+ j = logb(g), m += j;
+ g = ldexp(g, -j);
+ }
+ j = N*(g-1) + .5;
+ F = (1.0/N) * j + 1; /* F*128 is an integer in [128, 512] */
+ f = g - F;
+
+ /* Approximate expansion for log(1+f/F) ~= u + q */
+ g = 1/(2*F+f);
+ u = 2*f*g;
+ v = u*u;
+ q = u*v*(A1 + v*(A2 + v*(A3 + v*A4)));
+
+ /* case 1: u1 = u rounded to 2^-43 absolute. Since u < 2^-8,
+ * u1 has at most 35 bits, and F*u1 is exact, as F has < 8 bits.
+ * It also adds exactly to |m*log2_hi + log_F_head[j] | < 750
+ */
+ if (m | j)
+ u1 = u + 513, u1 -= 513;
+
+ /* case 2: |1-x| < 1/256. The m- and j- dependent terms are zero;
+ * u1 = u to 24 bits.
+ */
+ else
+ u1 = u, TRUNC(u1);
+ u2 = (2.0*(f - F*u1) - u1*f) * g;
+ /* u1 + u2 = 2f/(2F+f) to extra precision. */
+
+ /* log(x) = log(2^m*F*(1+f/F)) = */
+ /* (m*log2_hi+logF_head[j]+u1) + (m*log2_lo+logF_tail[j]+q); */
+ /* (exact) + (tiny) */
+
+ u1 += m*logF_head[N] + logF_head[j]; /* exact */
+ u2 = (u2 + logF_tail[j]) + q; /* tiny */
+ u2 += logF_tail[N]*m;
+ return (u1 + u2);
+}
+#endif
+
+/*
+ * Extra precision variant, returning struct {double a, b;};
+ * log(x) = a+b to 63 bits, with a rounded to 26 bits.
+ */
+struct Double
+#ifdef _ANSI_SOURCE
+__log__D(double x)
+#else
+__log__D(x) double x;
+#endif
+{
+ int m, j;
+ double F, f, g, q, u, v, u2;
+ volatile double u1;
+ struct Double r;
+
+ /* Argument reduction: 1 <= g < 2; x/2^m = g; */
+ /* y = F*(1 + f/F) for |f| <= 2^-8 */
+
+ m = logb(x);
+ g = ldexp(x, -m);
+ if (m == -1022) {
+ j = logb(g), m += j;
+ g = ldexp(g, -j);
+ }
+ j = N*(g-1) + .5;
+ F = (1.0/N) * j + 1;
+ f = g - F;
+
+ g = 1/(2*F+f);
+ u = 2*f*g;
+ v = u*u;
+ q = u*v*(A1 + v*(A2 + v*(A3 + v*A4)));
+ if (m | j)
+ u1 = u + 513, u1 -= 513;
+ else
+ u1 = u, TRUNC(u1);
+ u2 = (2.0*(f - F*u1) - u1*f) * g;
+
+ u1 += m*logF_head[N] + logF_head[j];
+
+ u2 += logF_tail[j]; u2 += q;
+ u2 += logF_tail[N]*m;
+ r.a = u1 + u2; /* Only difference is here */
+ TRUNC(r.a);
+ r.b = (u1 - r.a) + u2;
+ return (r);
+}
diff --git a/lib/msun/bsdsrc/b_tgamma.c b/lib/msun/bsdsrc/b_tgamma.c
new file mode 100644
index 0000000..a8e5755
--- /dev/null
+++ b/lib/msun/bsdsrc/b_tgamma.c
@@ -0,0 +1,315 @@
+/*-
+ * 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. 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)gamma.c 8.1 (Berkeley) 6/4/93";
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * This code by P. McIlroy, Oct 1992;
+ *
+ * The financial support of UUNET Communications Services is greatfully
+ * acknowledged.
+ */
+
+#include <math.h>
+#include "mathimpl.h"
+#include <errno.h>
+
+/* METHOD:
+ * x < 0: Use reflection formula, G(x) = pi/(sin(pi*x)*x*G(x))
+ * At negative integers, return +Inf, and set errno.
+ *
+ * x < 6.5:
+ * Use argument reduction G(x+1) = xG(x) to reach the
+ * range [1.066124,2.066124]. Use a rational
+ * approximation centered at the minimum (x0+1) to
+ * ensure monotonicity.
+ *
+ * x >= 6.5: Use the asymptotic approximation (Stirling's formula)
+ * adjusted for equal-ripples:
+ *
+ * log(G(x)) ~= (x-.5)*(log(x)-1) + .5(log(2*pi)-1) + 1/x*P(1/(x*x))
+ *
+ * Keep extra precision in multiplying (x-.5)(log(x)-1), to
+ * avoid premature round-off.
+ *
+ * Special values:
+ * non-positive integer: Set overflow trap; return +Inf;
+ * x > 171.63: Set overflow trap; return +Inf;
+ * NaN: Set invalid trap; return NaN
+ *
+ * Accuracy: Gamma(x) is accurate to within
+ * x > 0: error provably < 0.9ulp.
+ * Maximum observed in 1,000,000 trials was .87ulp.
+ * x < 0:
+ * Maximum observed error < 4ulp in 1,000,000 trials.
+ */
+
+static double neg_gam(double);
+static double small_gam(double);
+static double smaller_gam(double);
+static struct Double large_gam(double);
+static struct Double ratfun_gam(double, double);
+
+/*
+ * Rational approximation, A0 + x*x*P(x)/Q(x), on the interval
+ * [1.066.., 2.066..] accurate to 4.25e-19.
+ */
+#define LEFT -.3955078125 /* left boundary for rat. approx */
+#define x0 .461632144968362356785 /* xmin - 1 */
+
+#define a0_hi 0.88560319441088874992
+#define a0_lo -.00000000000000004996427036469019695
+#define P0 6.21389571821820863029017800727e-01
+#define P1 2.65757198651533466104979197553e-01
+#define P2 5.53859446429917461063308081748e-03
+#define P3 1.38456698304096573887145282811e-03
+#define P4 2.40659950032711365819348969808e-03
+#define Q0 1.45019531250000000000000000000e+00
+#define Q1 1.06258521948016171343454061571e+00
+#define Q2 -2.07474561943859936441469926649e-01
+#define Q3 -1.46734131782005422506287573015e-01
+#define Q4 3.07878176156175520361557573779e-02
+#define Q5 5.12449347980666221336054633184e-03
+#define Q6 -1.76012741431666995019222898833e-03
+#define Q7 9.35021023573788935372153030556e-05
+#define Q8 6.13275507472443958924745652239e-06
+/*
+ * Constants for large x approximation (x in [6, Inf])
+ * (Accurate to 2.8*10^-19 absolute)
+ */
+#define lns2pi_hi 0.418945312500000
+#define lns2pi_lo -.000006779295327258219670263595
+#define Pa0 8.33333333333333148296162562474e-02
+#define Pa1 -2.77777777774548123579378966497e-03
+#define Pa2 7.93650778754435631476282786423e-04
+#define Pa3 -5.95235082566672847950717262222e-04
+#define Pa4 8.41428560346653702135821806252e-04
+#define Pa5 -1.89773526463879200348872089421e-03
+#define Pa6 5.69394463439411649408050664078e-03
+#define Pa7 -1.44705562421428915453880392761e-02
+
+static const double zero = 0., one = 1.0, tiny = 1e-300;
+
+double
+tgamma(x)
+ double x;
+{
+ struct Double u;
+
+ if (x >= 6) {
+ if(x > 171.63)
+ return(one/zero);
+ u = large_gam(x);
+ return(__exp__D(u.a, u.b));
+ } else if (x >= 1.0 + LEFT + x0)
+ return (small_gam(x));
+ else if (x > 1.e-17)
+ return (smaller_gam(x));
+ else if (x > -1.e-17) {
+ if (x == 0.0)
+ return (one/x);
+ one+1e-20; /* Raise inexact flag. */
+ return (one/x);
+ } else if (!finite(x))
+ return (x*x); /* x = NaN, -Inf */
+ else
+ return (neg_gam(x));
+}
+/*
+ * Accurate to max(ulp(1/128) absolute, 2^-66 relative) error.
+ */
+static struct Double
+large_gam(x)
+ double x;
+{
+ double z, p;
+ struct Double t, u, v;
+
+ z = one/(x*x);
+ p = Pa0+z*(Pa1+z*(Pa2+z*(Pa3+z*(Pa4+z*(Pa5+z*(Pa6+z*Pa7))))));
+ p = p/x;
+
+ u = __log__D(x);
+ u.a -= one;
+ v.a = (x -= .5);
+ TRUNC(v.a);
+ v.b = x - v.a;
+ t.a = v.a*u.a; /* t = (x-.5)*(log(x)-1) */
+ t.b = v.b*u.a + x*u.b;
+ /* return t.a + t.b + lns2pi_hi + lns2pi_lo + p */
+ t.b += lns2pi_lo; t.b += p;
+ u.a = lns2pi_hi + t.b; u.a += t.a;
+ u.b = t.a - u.a;
+ u.b += lns2pi_hi; u.b += t.b;
+ return (u);
+}
+/*
+ * Good to < 1 ulp. (provably .90 ulp; .87 ulp on 1,000,000 runs.)
+ * It also has correct monotonicity.
+ */
+static double
+small_gam(x)
+ double x;
+{
+ double y, ym1, t;
+ struct Double yy, r;
+ y = x - one;
+ ym1 = y - one;
+ if (y <= 1.0 + (LEFT + x0)) {
+ yy = ratfun_gam(y - x0, 0);
+ return (yy.a + yy.b);
+ }
+ r.a = y;
+ TRUNC(r.a);
+ yy.a = r.a - one;
+ y = ym1;
+ yy.b = r.b = y - yy.a;
+ /* Argument reduction: G(x+1) = x*G(x) */
+ for (ym1 = y-one; ym1 > LEFT + x0; y = ym1--, yy.a--) {
+ t = r.a*yy.a;
+ r.b = r.a*yy.b + y*r.b;
+ r.a = t;
+ TRUNC(r.a);
+ r.b += (t - r.a);
+ }
+ /* Return r*tgamma(y). */
+ yy = ratfun_gam(y - x0, 0);
+ y = r.b*(yy.a + yy.b) + r.a*yy.b;
+ y += yy.a*r.a;
+ return (y);
+}
+/*
+ * Good on (0, 1+x0+LEFT]. Accurate to 1ulp.
+ */
+static double
+smaller_gam(x)
+ double x;
+{
+ double t, d;
+ struct Double r, xx;
+ if (x < x0 + LEFT) {
+ t = x, TRUNC(t);
+ d = (t+x)*(x-t);
+ t *= t;
+ xx.a = (t + x), TRUNC(xx.a);
+ xx.b = x - xx.a; xx.b += t; xx.b += d;
+ t = (one-x0); t += x;
+ d = (one-x0); d -= t; d += x;
+ x = xx.a + xx.b;
+ } else {
+ xx.a = x, TRUNC(xx.a);
+ xx.b = x - xx.a;
+ t = x - x0;
+ d = (-x0 -t); d += x;
+ }
+ r = ratfun_gam(t, d);
+ d = r.a/x, TRUNC(d);
+ r.a -= d*xx.a; r.a -= d*xx.b; r.a += r.b;
+ return (d + r.a/x);
+}
+/*
+ * returns (z+c)^2 * P(z)/Q(z) + a0
+ */
+static struct Double
+ratfun_gam(z, c)
+ double z, c;
+{
+ double p, q;
+ struct Double r, t;
+
+ q = Q0 +z*(Q1+z*(Q2+z*(Q3+z*(Q4+z*(Q5+z*(Q6+z*(Q7+z*Q8)))))));
+ p = P0 + z*(P1 + z*(P2 + z*(P3 + z*P4)));
+
+ /* return r.a + r.b = a0 + (z+c)^2*p/q, with r.a truncated to 26 bits. */
+ p = p/q;
+ t.a = z, TRUNC(t.a); /* t ~= z + c */
+ t.b = (z - t.a) + c;
+ t.b *= (t.a + z);
+ q = (t.a *= t.a); /* t = (z+c)^2 */
+ TRUNC(t.a);
+ t.b += (q - t.a);
+ r.a = p, TRUNC(r.a); /* r = P/Q */
+ r.b = p - r.a;
+ t.b = t.b*p + t.a*r.b + a0_lo;
+ t.a *= r.a; /* t = (z+c)^2*(P/Q) */
+ r.a = t.a + a0_hi, TRUNC(r.a);
+ r.b = ((a0_hi-r.a) + t.a) + t.b;
+ return (r); /* r = a0 + t */
+}
+
+static double
+neg_gam(x)
+ double x;
+{
+ int sgn = 1;
+ struct Double lg, lsine;
+ double y, z;
+
+ y = floor(x + .5);
+ if (y == x) /* Negative integer. */
+ return (one/zero);
+ z = fabs(x - y);
+ y = .5*ceil(x);
+ if (y == ceil(y))
+ sgn = -1;
+ if (z < .25)
+ z = sin(M_PI*z);
+ else
+ z = cos(M_PI*(0.5-z));
+ /* Special case: G(1-x) = Inf; G(x) may be nonzero. */
+ if (x < -170) {
+ if (x < -190)
+ return ((double)sgn*tiny*tiny);
+ y = one - x; /* exact: 128 < |x| < 255 */
+ lg = large_gam(y);
+ lsine = __log__D(M_PI/z); /* = TRUNC(log(u)) + small */
+ lg.a -= lsine.a; /* exact (opposite signs) */
+ lg.b -= lsine.b;
+ y = -(lg.a + lg.b);
+ z = (y + lg.a) + lg.b;
+ y = __exp__D(y, z);
+ if (sgn < 0) y = -y;
+ return (y);
+ }
+ y = one-x;
+ if (one-y == x)
+ y = tgamma(y);
+ else /* 1-x is inexact */
+ y = -x*tgamma(-x);
+ if (sgn < 0) y = -y;
+ return (M_PI / (y*z));
+}
diff --git a/lib/msun/bsdsrc/mathimpl.h b/lib/msun/bsdsrc/mathimpl.h
new file mode 100644
index 0000000..04a4b6e
--- /dev/null
+++ b/lib/msun/bsdsrc/mathimpl.h
@@ -0,0 +1,74 @@
+/*
+ * 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. 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.
+ *
+ * @(#)mathimpl.h 8.1 (Berkeley) 6/4/93
+ * $FreeBSD$
+ */
+
+#ifndef _MATHIMPL_H_
+#define _MATHIMPL_H_
+
+#include <sys/cdefs.h>
+#include <math.h>
+
+#include "../src/math_private.h"
+
+/*
+ * TRUNC() is a macro that sets the trailing 27 bits in the mantissa of an
+ * IEEE double variable to zero. It must be expression-like for syntactic
+ * reasons, and we implement this expression using an inline function
+ * instead of a pure macro to avoid depending on the gcc feature of
+ * statement-expressions.
+ */
+#define TRUNC(d) (_b_trunc(&(d)))
+
+static __inline void
+_b_trunc(volatile double *_dp)
+{
+ uint32_t _lw;
+
+ GET_LOW_WORD(_lw, *_dp);
+ SET_LOW_WORD(*_dp, _lw & 0xf8000000);
+}
+
+struct Double {
+ double a;
+ double b;
+};
+
+/*
+ * Functions internal to the math package, yet not static.
+ */
+double __exp__D(double, double);
+struct Double __log__D(double);
+
+#endif /* !_MATHIMPL_H_ */
diff --git a/lib/msun/i387/Makefile.inc b/lib/msun/i387/Makefile.inc
new file mode 100644
index 0000000..c02653e
--- /dev/null
+++ b/lib/msun/i387/Makefile.inc
@@ -0,0 +1,19 @@
+# $FreeBSD$
+
+ARCH_SRCS = e_exp.S e_fmod.S e_log.S e_log10.S \
+ e_remainder.S e_scalb.S e_sqrt.S s_ceil.S s_copysign.S \
+ s_cos.S s_finite.S s_floor.S s_llrint.S s_logb.S s_lrint.S \
+ s_remquo.S s_rint.S s_scalbn.S s_significand.S s_sin.S s_tan.S \
+ s_trunc.S
+
+# float counterparts
+ARCH_SRCS+= e_log10f.S e_logf.S e_remainderf.S e_scalbf.S \
+ e_sqrtf.S s_ceilf.S s_copysignf.S s_floorf.S \
+ s_llrintf.S s_logbf.S s_lrintf.S \
+ s_remquof.S s_rintf.S s_scalbnf.S s_significandf.S s_truncf.S
+
+# long double counterparts
+ARCH_SRCS+= s_ceill.S s_copysignl.S s_floorl.S s_scalbnl.S s_truncl.S
+
+LDBL_PREC = 64 # XXX 64-bit format, but truncated to 53 bits
+SYM_MAPS += ${.CURDIR}/i387/Symbol.map
diff --git a/lib/msun/i387/Symbol.map b/lib/msun/i387/Symbol.map
new file mode 100644
index 0000000..7285179
--- /dev/null
+++ b/lib/msun/i387/Symbol.map
@@ -0,0 +1,14 @@
+# $FreeBSD$
+FBSD_1.0 {
+ __has_sse;
+ __test_sse;
+ fesetexceptflag;
+ feraiseexcept;
+ fegetenv;
+ feholdexcept;
+ feupdateenv;
+ __feenableexcept;
+ __fedisableexcept;
+ feenableexcept;
+ fedisableexcept;
+};
diff --git a/lib/msun/i387/e_exp.S b/lib/msun/i387/e_exp.S
new file mode 100644
index 0000000..9c87407
--- /dev/null
+++ b/lib/msun/i387/e_exp.S
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ */
+
+/*
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+#include <machine/asm.h>
+
+RCSID("$FreeBSD$")
+
+/* e^x = 2^(x * log2(e)) */
+ENTRY(exp)
+ /*
+ * If x is +-Inf, then the subtraction would give Inf-Inf = NaN.
+ * Avoid this. Also avoid it if x is NaN for convenience.
+ */
+ movl 8(%esp),%eax
+ andl $0x7fffffff,%eax
+ cmpl $0x7ff00000,%eax
+ jae x_Inf_or_NaN
+
+ fldl 4(%esp)
+
+ /*
+ * Extended precision is needed to reduce the maximum error from
+ * hundreds of ulps to less than 1 ulp. Switch to it if necessary.
+ * We may as well set the rounding mode to to-nearest and mask traps
+ * if we switch.
+ */
+ fstcw 4(%esp)
+ movl 4(%esp),%eax
+ andl $0x0300,%eax
+ cmpl $0x0300,%eax /* RC == 0 && PC == 3? */
+ je 1f /* jump if mode is good */
+ movl $0x137f,8(%esp)
+ fldcw 8(%esp)
+1:
+ fldl2e
+ fmulp /* x * log2(e) */
+ fst %st(1)
+ frndint /* int(x * log2(e)) */
+ fst %st(2)
+ fsubrp /* fract(x * log2(e)) */
+ f2xm1 /* 2^(fract(x * log2(e))) - 1 */
+ fld1
+ faddp /* 2^(fract(x * log2(e))) */
+ fscale /* e^x */
+ fstp %st(1)
+ je 1f
+ fldcw 4(%esp)
+1:
+ ret
+
+x_Inf_or_NaN:
+ /*
+ * Return 0 if x is -Inf. Otherwise just return x; when x is Inf
+ * this gives Inf, and when x is a NaN this gives the same result
+ * as (x + x) (x quieted).
+ */
+ cmpl $0xfff00000,8(%esp)
+ jne x_not_minus_Inf
+ cmpl $0,4(%esp)
+ jne x_not_minus_Inf
+ fldz
+ ret
+
+x_not_minus_Inf:
+ fldl 4(%esp)
+ ret
diff --git a/lib/msun/i387/e_fmod.S b/lib/msun/i387/e_fmod.S
new file mode 100644
index 0000000..71c4c30
--- /dev/null
+++ b/lib/msun/i387/e_fmod.S
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+/*
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+#include <machine/asm.h>
+
+RCSID("$FreeBSD$")
+
+ENTRY(fmod)
+ fldl 12(%esp)
+ fldl 4(%esp)
+1: fprem
+ fstsw %ax
+ sahf
+ jp 1b
+ fstp %st(1)
+ ret
diff --git a/lib/msun/i387/e_log.S b/lib/msun/i387/e_log.S
new file mode 100644
index 0000000..0d06940
--- /dev/null
+++ b/lib/msun/i387/e_log.S
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+/*
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+#include <machine/asm.h>
+
+RCSID("$FreeBSD$")
+
+ENTRY(log)
+ fldln2
+ fldl 4(%esp)
+ fyl2x
+ ret
diff --git a/lib/msun/i387/e_log10.S b/lib/msun/i387/e_log10.S
new file mode 100644
index 0000000..edc13ff
--- /dev/null
+++ b/lib/msun/i387/e_log10.S
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+/*
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+#include <machine/asm.h>
+
+RCSID("$FreeBSD$")
+
+ENTRY(log10)
+ fldlg2
+ fldl 4(%esp)
+ fyl2x
+ ret
diff --git a/lib/msun/i387/e_log10f.S b/lib/msun/i387/e_log10f.S
new file mode 100644
index 0000000..44410bc
--- /dev/null
+++ b/lib/msun/i387/e_log10f.S
@@ -0,0 +1,15 @@
+/*
+ * Written by J.T. Conklin <jtc@netbsd.org>.
+ * Public domain.
+ */
+
+#include <machine/asm.h>
+
+__FBSDID("$FreeBSD$");
+/* RCSID("$NetBSD: e_log10f.S,v 1.1 1996/07/03 16:50:22 jtc Exp $") */
+
+ENTRY(log10f)
+ fldlg2
+ flds 4(%esp)
+ fyl2x
+ ret
diff --git a/lib/msun/i387/e_logf.S b/lib/msun/i387/e_logf.S
new file mode 100644
index 0000000..e66c844
--- /dev/null
+++ b/lib/msun/i387/e_logf.S
@@ -0,0 +1,15 @@
+/*
+ * Written by J.T. Conklin <jtc@netbsd.org>.
+ * Public domain.
+ */
+
+#include <machine/asm.h>
+
+__FBSDID("$FreeBSD$");
+/* RCSID("$NetBSD: e_logf.S,v 1.2 1996/07/06 00:15:45 jtc Exp $") */
+
+ENTRY(logf)
+ fldln2
+ flds 4(%esp)
+ fyl2x
+ ret
diff --git a/lib/msun/i387/e_remainder.S b/lib/msun/i387/e_remainder.S
new file mode 100644
index 0000000..ff2f142
--- /dev/null
+++ b/lib/msun/i387/e_remainder.S
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+/*
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+#include <machine/asm.h>
+
+RCSID("$FreeBSD$")
+
+ENTRY(remainder)
+ fldl 12(%esp)
+ fldl 4(%esp)
+1: fprem1
+ fstsw %ax
+ sahf
+ jp 1b
+ fstp %st(1)
+ ret
diff --git a/lib/msun/i387/e_remainderf.S b/lib/msun/i387/e_remainderf.S
new file mode 100644
index 0000000..4093c8a
--- /dev/null
+++ b/lib/msun/i387/e_remainderf.S
@@ -0,0 +1,19 @@
+/*
+ * Written by J.T. Conklin <jtc@netbsd.org>.
+ * Public domain.
+ */
+
+#include <machine/asm.h>
+
+__FBSDID("$FreeBSD$");
+/* RCSID("$NetBSD: e_remainderf.S,v 1.2 1995/05/08 23:49:47 jtc Exp $") */
+
+ENTRY(remainderf)
+ flds 8(%esp)
+ flds 4(%esp)
+1: fprem1
+ fstsw %ax
+ sahf
+ jp 1b
+ fstp %st(1)
+ ret
diff --git a/lib/msun/i387/e_scalb.S b/lib/msun/i387/e_scalb.S
new file mode 100644
index 0000000..1aa510f
--- /dev/null
+++ b/lib/msun/i387/e_scalb.S
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+/*
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+#include <machine/asm.h>
+
+RCSID("$FreeBSD$")
+
+ENTRY(scalb)
+ fldl 12(%esp)
+ fldl 4(%esp)
+ fscale
+ fstp %st(1)
+ ret
diff --git a/lib/msun/i387/e_scalbf.S b/lib/msun/i387/e_scalbf.S
new file mode 100644
index 0000000..d937dd5
--- /dev/null
+++ b/lib/msun/i387/e_scalbf.S
@@ -0,0 +1,15 @@
+/*
+ * Written by J.T. Conklin <jtc@netbsd.org>.
+ * Public domain.
+ */
+
+#include <machine/asm.h>
+
+__FBSDID("$FreeBSD$");
+/* RCSID("$NetBSD: e_scalbf.S,v 1.1 1996/07/03 16:50:24 jtc Exp $") */
+
+ENTRY(scalbf)
+ flds 8(%esp)
+ flds 4(%esp)
+ fscale
+ ret
diff --git a/lib/msun/i387/e_sqrt.S b/lib/msun/i387/e_sqrt.S
new file mode 100644
index 0000000..554beb7
--- /dev/null
+++ b/lib/msun/i387/e_sqrt.S
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+/*
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+#include <machine/asm.h>
+
+RCSID("$FreeBSD$")
+
+ENTRY(sqrt)
+ fldl 4(%esp)
+ fsqrt
+ ret
diff --git a/lib/msun/i387/e_sqrtf.S b/lib/msun/i387/e_sqrtf.S
new file mode 100644
index 0000000..9d78725
--- /dev/null
+++ b/lib/msun/i387/e_sqrtf.S
@@ -0,0 +1,14 @@
+/*
+ * Written by J.T. Conklin <jtc@netbsd.org>.
+ * Public domain.
+ */
+
+#include <machine/asm.h>
+
+__FBSDID("$FreeBSD$");
+/* RCSID("$NetBSD: e_sqrtf.S,v 1.2 1995/05/08 23:50:14 jtc Exp $") */
+
+ENTRY(sqrtf)
+ flds 4(%esp)
+ fsqrt
+ ret
diff --git a/lib/msun/i387/fenv.c b/lib/msun/i387/fenv.c
new file mode 100644
index 0000000..567d699
--- /dev/null
+++ b/lib/msun/i387/fenv.c
@@ -0,0 +1,211 @@
+/*-
+ * Copyright (c) 2004-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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <machine/npx.h>
+#include "fenv.h"
+
+const fenv_t __fe_dfl_env = {
+ __INITIAL_NPXCW__,
+ 0x0000,
+ 0x0000,
+ 0x1f80,
+ 0xffffffff,
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff }
+};
+
+enum __sse_support __has_sse =
+#ifdef __SSE__
+ __SSE_YES;
+#else
+ __SSE_UNK;
+#endif
+
+#define getfl(x) __asm __volatile("pushfl\n\tpopl %0" : "=mr" (*(x)))
+#define setfl(x) __asm __volatile("pushl %0\n\tpopfl" : : "g" (x))
+#define cpuid_dx(x) __asm __volatile("pushl %%ebx\n\tmovl $1, %%eax\n\t" \
+ "cpuid\n\tpopl %%ebx" \
+ : "=d" (*(x)) : : "eax", "ecx")
+
+/*
+ * Test for SSE support on this processor. We need to do this because
+ * we need to use ldmxcsr/stmxcsr to get correct results if any part
+ * of the program was compiled to use SSE floating-point, but we can't
+ * use SSE on older processors.
+ */
+int
+__test_sse(void)
+{
+ int flag, nflag;
+ int dx_features;
+
+ /* Am I a 486? */
+ getfl(&flag);
+ nflag = flag ^ 0x200000;
+ setfl(nflag);
+ getfl(&nflag);
+ if (flag != nflag) {
+ /* Not a 486, so CPUID should work. */
+ cpuid_dx(&dx_features);
+ if (dx_features & 0x2000000) {
+ __has_sse = __SSE_YES;
+ return (1);
+ }
+ }
+ __has_sse = __SSE_NO;
+ return (0);
+}
+
+int
+fesetexceptflag(const fexcept_t *flagp, int excepts)
+{
+ fenv_t env;
+ int mxcsr;
+
+ __fnstenv(&env);
+ env.__status &= ~excepts;
+ env.__status |= *flagp & excepts;
+ __fldenv(env);
+
+ if (__HAS_SSE()) {
+ __stmxcsr(&mxcsr);
+ mxcsr &= ~excepts;
+ mxcsr |= *flagp & excepts;
+ __ldmxcsr(mxcsr);
+ }
+
+ return (0);
+}
+
+int
+feraiseexcept(int excepts)
+{
+ fexcept_t ex = excepts;
+
+ fesetexceptflag(&ex, excepts);
+ __fwait();
+ return (0);
+}
+
+int
+fegetenv(fenv_t *envp)
+{
+ int control, mxcsr;
+
+ /*
+ * fnstenv masks all exceptions, so we need to save and
+ * restore the control word to avoid this side effect.
+ */
+ __fnstcw(&control);
+ __fnstenv(envp);
+ if (__HAS_SSE()) {
+ __stmxcsr(&mxcsr);
+ __set_mxcsr(*envp, mxcsr);
+ }
+ __fldcw(control);
+ return (0);
+}
+
+int
+feholdexcept(fenv_t *envp)
+{
+ int mxcsr;
+
+ __fnstenv(envp);
+ __fnclex();
+ if (__HAS_SSE()) {
+ __stmxcsr(&mxcsr);
+ __set_mxcsr(*envp, mxcsr);
+ mxcsr &= ~FE_ALL_EXCEPT;
+ mxcsr |= FE_ALL_EXCEPT << _SSE_EMASK_SHIFT;
+ __ldmxcsr(mxcsr);
+ }
+ return (0);
+}
+
+int
+feupdateenv(const fenv_t *envp)
+{
+ int mxcsr, status;
+
+ __fnstsw(&status);
+ if (__HAS_SSE())
+ __stmxcsr(&mxcsr);
+ else
+ mxcsr = 0;
+ fesetenv(envp);
+ feraiseexcept((mxcsr | status) & FE_ALL_EXCEPT);
+ return (0);
+}
+
+int
+__feenableexcept(int mask)
+{
+ int mxcsr, control, omask;
+
+ mask &= FE_ALL_EXCEPT;
+ __fnstcw(&control);
+ if (__HAS_SSE())
+ __stmxcsr(&mxcsr);
+ else
+ mxcsr = 0;
+ omask = (control | mxcsr >> _SSE_EMASK_SHIFT) & FE_ALL_EXCEPT;
+ control &= ~mask;
+ __fldcw(control);
+ if (__HAS_SSE()) {
+ mxcsr &= ~(mask << _SSE_EMASK_SHIFT);
+ __ldmxcsr(mxcsr);
+ }
+ return (~omask);
+}
+
+int
+__fedisableexcept(int mask)
+{
+ int mxcsr, control, omask;
+
+ mask &= FE_ALL_EXCEPT;
+ __fnstcw(&control);
+ if (__HAS_SSE())
+ __stmxcsr(&mxcsr);
+ else
+ mxcsr = 0;
+ omask = (control | mxcsr >> _SSE_EMASK_SHIFT) & FE_ALL_EXCEPT;
+ control |= mask;
+ __fldcw(control);
+ if (__HAS_SSE()) {
+ mxcsr |= mask << _SSE_EMASK_SHIFT;
+ __ldmxcsr(mxcsr);
+ }
+ return (~omask);
+}
+
+__weak_reference(__feenableexcept, feenableexcept);
+__weak_reference(__fedisableexcept, fedisableexcept);
diff --git a/lib/msun/i387/fenv.h b/lib/msun/i387/fenv.h
new file mode 100644
index 0000000..d62dcf8
--- /dev/null
+++ b/lib/msun/i387/fenv.h
@@ -0,0 +1,240 @@
+/*-
+ * Copyright (c) 2004-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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _FENV_H_
+#define _FENV_H_
+
+#include <sys/cdefs.h>
+#include <sys/_types.h>
+
+/*
+ * To preserve binary compatibility with FreeBSD 5.3, we pack the
+ * mxcsr into some reserved fields, rather than changing sizeof(fenv_t).
+ */
+typedef struct {
+ __uint16_t __control;
+ __uint16_t __mxcsr_hi;
+ __uint16_t __status;
+ __uint16_t __mxcsr_lo;
+ __uint32_t __tag;
+ char __other[16];
+} fenv_t;
+
+#define __get_mxcsr(env) (((env).__mxcsr_hi << 16) | \
+ ((env).__mxcsr_lo))
+#define __set_mxcsr(env, x) do { \
+ (env).__mxcsr_hi = (__uint32_t)(x) >> 16; \
+ (env).__mxcsr_lo = (__uint16_t)(x); \
+} while (0)
+
+typedef __uint16_t fexcept_t;
+
+/* Exception flags */
+#define FE_INVALID 0x01
+#define FE_DENORMAL 0x02
+#define FE_DIVBYZERO 0x04
+#define FE_OVERFLOW 0x08
+#define FE_UNDERFLOW 0x10
+#define FE_INEXACT 0x20
+#define FE_ALL_EXCEPT (FE_DIVBYZERO | FE_DENORMAL | FE_INEXACT | \
+ FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW)
+
+/* Rounding modes */
+#define FE_TONEAREST 0x0000
+#define FE_DOWNWARD 0x0400
+#define FE_UPWARD 0x0800
+#define FE_TOWARDZERO 0x0c00
+#define _ROUND_MASK (FE_TONEAREST | FE_DOWNWARD | \
+ FE_UPWARD | FE_TOWARDZERO)
+
+/*
+ * As compared to the x87 control word, the SSE unit's control word
+ * has the rounding control bits offset by 3 and the exception mask
+ * bits offset by 7.
+ */
+#define _SSE_ROUND_SHIFT 3
+#define _SSE_EMASK_SHIFT 7
+
+/* After testing for SSE support once, we cache the result in __has_sse. */
+enum __sse_support { __SSE_YES, __SSE_NO, __SSE_UNK };
+extern enum __sse_support __has_sse;
+int __test_sse(void);
+#ifdef __SSE__
+#define __HAS_SSE() 1
+#else
+#define __HAS_SSE() (__has_sse == __SSE_YES || \
+ (__has_sse == __SSE_UNK && __test_sse()))
+#endif
+
+__BEGIN_DECLS
+
+/* Default floating-point environment */
+extern const fenv_t __fe_dfl_env;
+#define FE_DFL_ENV (&__fe_dfl_env)
+
+#define __fldcw(__cw) __asm __volatile("fldcw %0" : : "m" (__cw))
+#define __fldenv(__env) __asm __volatile("fldenv %0" : : "m" (__env))
+#define __fnclex() __asm __volatile("fnclex")
+#define __fnstenv(__env) __asm __volatile("fnstenv %0" : "=m" (*(__env)))
+#define __fnstcw(__cw) __asm __volatile("fnstcw %0" : "=m" (*(__cw)))
+#define __fnstsw(__sw) __asm __volatile("fnstsw %0" : "=am" (*(__sw)))
+#define __fwait() __asm __volatile("fwait")
+#define __ldmxcsr(__csr) __asm __volatile("ldmxcsr %0" : : "m" (__csr))
+#define __stmxcsr(__csr) __asm __volatile("stmxcsr %0" : "=m" (*(__csr)))
+
+static __inline int
+feclearexcept(int __excepts)
+{
+ fenv_t __env;
+ int __mxcsr;
+
+ if (__excepts == FE_ALL_EXCEPT) {
+ __fnclex();
+ } else {
+ __fnstenv(&__env);
+ __env.__status &= ~__excepts;
+ __fldenv(__env);
+ }
+ if (__HAS_SSE()) {
+ __stmxcsr(&__mxcsr);
+ __mxcsr &= ~__excepts;
+ __ldmxcsr(__mxcsr);
+ }
+ return (0);
+}
+
+static __inline int
+fegetexceptflag(fexcept_t *__flagp, int __excepts)
+{
+ int __mxcsr, __status;
+
+ __fnstsw(&__status);
+ if (__HAS_SSE())
+ __stmxcsr(&__mxcsr);
+ else
+ __mxcsr = 0;
+ *__flagp = (__mxcsr | __status) & __excepts;
+ return (0);
+}
+
+int fesetexceptflag(const fexcept_t *__flagp, int __excepts);
+int feraiseexcept(int __excepts);
+
+static __inline int
+fetestexcept(int __excepts)
+{
+ int __mxcsr, __status;
+
+ __fnstsw(&__status);
+ if (__HAS_SSE())
+ __stmxcsr(&__mxcsr);
+ else
+ __mxcsr = 0;
+ return ((__status | __mxcsr) & __excepts);
+}
+
+static __inline int
+fegetround(void)
+{
+ int __control;
+
+ /*
+ * We assume that the x87 and the SSE unit agree on the
+ * rounding mode. Reading the control word on the x87 turns
+ * out to be about 5 times faster than reading it on the SSE
+ * unit on an Opteron 244.
+ */
+ __fnstcw(&__control);
+ return (__control & _ROUND_MASK);
+}
+
+static __inline int
+fesetround(int __round)
+{
+ int __mxcsr, __control;
+
+ if (__round & ~_ROUND_MASK)
+ return (-1);
+
+ __fnstcw(&__control);
+ __control &= ~_ROUND_MASK;
+ __control |= __round;
+ __fldcw(__control);
+
+ if (__HAS_SSE()) {
+ __stmxcsr(&__mxcsr);
+ __mxcsr &= ~(_ROUND_MASK << _SSE_ROUND_SHIFT);
+ __mxcsr |= __round << _SSE_ROUND_SHIFT;
+ __ldmxcsr(__mxcsr);
+ }
+
+ return (0);
+}
+
+int fegetenv(fenv_t *__envp);
+int feholdexcept(fenv_t *__envp);
+
+static __inline int
+fesetenv(const fenv_t *__envp)
+{
+ fenv_t __env = *__envp;
+ int __mxcsr;
+
+ __mxcsr = __get_mxcsr(__env);
+ __set_mxcsr(__env, 0xffffffff);
+ __fldenv(__env);
+ if (__HAS_SSE())
+ __ldmxcsr(__mxcsr);
+ return (0);
+}
+
+int feupdateenv(const fenv_t *__envp);
+
+#if __BSD_VISIBLE
+
+int feenableexcept(int __mask);
+int fedisableexcept(int __mask);
+
+static __inline int
+fegetexcept(void)
+{
+ int __control;
+
+ /*
+ * We assume that the masks for the x87 and the SSE unit are
+ * the same.
+ */
+ __fnstcw(&__control);
+ return (~__control & FE_ALL_EXCEPT);
+}
+
+#endif /* __BSD_VISIBLE */
+
+__END_DECLS
+
+#endif /* !_FENV_H_ */
diff --git a/lib/msun/i387/s_ceil.S b/lib/msun/i387/s_ceil.S
new file mode 100644
index 0000000..e805d85
--- /dev/null
+++ b/lib/msun/i387/s_ceil.S
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+/*
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+#include <machine/asm.h>
+
+RCSID("$FreeBSD$")
+
+ENTRY(ceil)
+ pushl %ebp
+ movl %esp,%ebp
+ subl $8,%esp
+
+ fstcw -4(%ebp) /* store fpu control word */
+ movw -4(%ebp),%dx
+ orw $0x0800,%dx /* round towards +oo */
+ andw $0xfbff,%dx
+ movw %dx,-8(%ebp)
+ fldcw -8(%ebp) /* load modfied control word */
+
+ fldl 8(%ebp); /* round */
+ frndint
+
+ fldcw -4(%ebp) /* restore original control word */
+
+ leave
+ ret
diff --git a/lib/msun/i387/s_ceilf.S b/lib/msun/i387/s_ceilf.S
new file mode 100644
index 0000000..473d309
--- /dev/null
+++ b/lib/msun/i387/s_ceilf.S
@@ -0,0 +1,29 @@
+/*
+ * Written by J.T. Conklin <jtc@netbsd.org>.
+ * Public domain.
+ */
+
+#include <machine/asm.h>
+
+__FBSDID("$FreeBSD$");
+/* RCSID("$NetBSD: s_ceilf.S,v 1.3 1995/05/08 23:52:44 jtc Exp $") */
+
+ENTRY(ceilf)
+ pushl %ebp
+ movl %esp,%ebp
+ subl $8,%esp
+
+ fstcw -4(%ebp) /* store fpu control word */
+ movw -4(%ebp),%dx
+ orw $0x0800,%dx /* round towards +oo */
+ andw $0xfbff,%dx
+ movw %dx,-8(%ebp)
+ fldcw -8(%ebp) /* load modfied control word */
+
+ flds 8(%ebp); /* round */
+ frndint
+
+ fldcw -4(%ebp) /* restore original control word */
+
+ leave
+ ret
diff --git a/lib/msun/i387/s_ceill.S b/lib/msun/i387/s_ceill.S
new file mode 100644
index 0000000..ae64abf
--- /dev/null
+++ b/lib/msun/i387/s_ceill.S
@@ -0,0 +1,27 @@
+/*
+ * Based on code written by J.T. Conklin <jtc@NetBSD.org>.
+ * Public domain.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$")
+
+ENTRY(ceill)
+ pushl %ebp
+ movl %esp,%ebp
+ subl $8,%esp
+
+ fstcw -4(%ebp) /* store fpu control word */
+ movw -4(%ebp),%dx
+ orw $0x0800,%dx /* round towards +oo */
+ andw $0xfbff,%dx
+ movw %dx,-8(%ebp)
+ fldcw -8(%ebp) /* load modfied control word */
+
+ fldt 8(%ebp) /* round */
+ frndint
+
+ fldcw -4(%ebp) /* restore original control word */
+
+ leave
+ ret
diff --git a/lib/msun/i387/s_copysign.S b/lib/msun/i387/s_copysign.S
new file mode 100644
index 0000000..ec28b45
--- /dev/null
+++ b/lib/msun/i387/s_copysign.S
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+/*
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+#include <machine/asm.h>
+
+RCSID("$FreeBSD$")
+
+ENTRY(copysign)
+ movl 16(%esp),%edx
+ andl $0x80000000,%edx
+ movl 8(%esp),%eax
+ andl $0x7fffffff,%eax
+ orl %edx,%eax
+ movl %eax,8(%esp)
+ fldl 4(%esp)
+ ret
diff --git a/lib/msun/i387/s_copysignf.S b/lib/msun/i387/s_copysignf.S
new file mode 100644
index 0000000..e78ad24
--- /dev/null
+++ b/lib/msun/i387/s_copysignf.S
@@ -0,0 +1,19 @@
+/*
+ * Written by J.T. Conklin <jtc@netbsd.org>.
+ * Public domain.
+ */
+
+#include <machine/asm.h>
+
+__FBSDID("$FreeBSD$");
+/* RCSID("$NetBSD: s_copysignf.S,v 1.3 1995/05/08 23:53:25 jtc Exp $") */
+
+ENTRY(copysignf)
+ movl 8(%esp),%edx
+ andl $0x80000000,%edx
+ movl 4(%esp),%eax
+ andl $0x7fffffff,%eax
+ orl %edx,%eax
+ movl %eax,4(%esp)
+ flds 4(%esp)
+ ret
diff --git a/lib/msun/i387/s_copysignl.S b/lib/msun/i387/s_copysignl.S
new file mode 100644
index 0000000..7878591
--- /dev/null
+++ b/lib/msun/i387/s_copysignl.S
@@ -0,0 +1,17 @@
+/*
+ * Based on code written by J.T. Conklin <jtc@NetBSD.org>.
+ * Public domain.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$")
+
+ENTRY(copysignl)
+ movl 24(%esp),%edx
+ andl $0x8000,%edx
+ movl 12(%esp),%eax
+ andl $0x7fff,%eax
+ orl %edx,%eax
+ movl %eax,12(%esp)
+ fldt 4(%esp)
+ ret
diff --git a/lib/msun/i387/s_cos.S b/lib/msun/i387/s_cos.S
new file mode 100644
index 0000000..a73ba06
--- /dev/null
+++ b/lib/msun/i387/s_cos.S
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+/*
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+#include <machine/asm.h>
+
+RCSID("$FreeBSD$")
+
+ENTRY(cos)
+ fldl 4(%esp)
+ fcos
+ fnstsw %ax
+ andw $0x400,%ax
+ jnz 1f
+ ret
+1: fldpi
+ fadd %st(0)
+ fxch %st(1)
+2: fprem1
+ fnstsw %ax
+ andw $0x400,%ax
+ jnz 2b
+ fstp %st(1)
+ fcos
+ ret
diff --git a/lib/msun/i387/s_finite.S b/lib/msun/i387/s_finite.S
new file mode 100644
index 0000000..b27b7d1
--- /dev/null
+++ b/lib/msun/i387/s_finite.S
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+/*
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+#include <machine/asm.h>
+
+RCSID("$FreeBSD$")
+
+ENTRY(finite)
+ movl 8(%esp),%eax
+ andl $0x7ff00000, %eax
+ cmpl $0x7ff00000, %eax
+ setneb %al
+ andl $0x000000ff, %eax
+ ret
diff --git a/lib/msun/i387/s_floor.S b/lib/msun/i387/s_floor.S
new file mode 100644
index 0000000..66c1d9f9
--- /dev/null
+++ b/lib/msun/i387/s_floor.S
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+/*
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+#include <machine/asm.h>
+
+RCSID("$FreeBSD$")
+
+ENTRY(floor)
+ pushl %ebp
+ movl %esp,%ebp
+ subl $8,%esp
+
+ fstcw -4(%ebp) /* store fpu control word */
+ movw -4(%ebp),%dx
+ orw $0x0400,%dx /* round towards -oo */
+ andw $0xf7ff,%dx
+ movw %dx,-8(%ebp)
+ fldcw -8(%ebp) /* load modfied control word */
+
+ fldl 8(%ebp); /* round */
+ frndint
+
+ fldcw -4(%ebp) /* restore original control word */
+
+ leave
+ ret
diff --git a/lib/msun/i387/s_floorf.S b/lib/msun/i387/s_floorf.S
new file mode 100644
index 0000000..f1000fe
--- /dev/null
+++ b/lib/msun/i387/s_floorf.S
@@ -0,0 +1,29 @@
+/*
+ * Written by J.T. Conklin <jtc@netbsd.org>.
+ * Public domain.
+ */
+
+#include <machine/asm.h>
+
+__FBSDID("$FreeBSD$");
+/* RCSID("$NetBSD: s_floorf.S,v 1.3 1995/05/09 00:04:32 jtc Exp $") */
+
+ENTRY(floorf)
+ pushl %ebp
+ movl %esp,%ebp
+ subl $8,%esp
+
+ fstcw -4(%ebp) /* store fpu control word */
+ movw -4(%ebp),%dx
+ orw $0x0400,%dx /* round towards -oo */
+ andw $0xf7ff,%dx
+ movw %dx,-8(%ebp)
+ fldcw -8(%ebp) /* load modfied control word */
+
+ flds 8(%ebp); /* round */
+ frndint
+
+ fldcw -4(%ebp) /* restore original control word */
+
+ leave
+ ret
diff --git a/lib/msun/i387/s_floorl.S b/lib/msun/i387/s_floorl.S
new file mode 100644
index 0000000..a0bb048
--- /dev/null
+++ b/lib/msun/i387/s_floorl.S
@@ -0,0 +1,27 @@
+/*
+ * Based on code written by J.T. Conklin <jtc@NetBSD.org>.
+ * Public domain.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$")
+
+ENTRY(floorl)
+ pushl %ebp
+ movl %esp,%ebp
+ subl $8,%esp
+
+ fstcw -4(%ebp) /* store fpu control word */
+ movw -4(%ebp),%dx
+ orw $0x0400,%dx /* round towards -oo */
+ andw $0xf7ff,%dx
+ movw %dx,-8(%ebp)
+ fldcw -8(%ebp) /* load modfied control word */
+
+ fldt 8(%ebp) /* round */
+ frndint
+
+ fldcw -4(%ebp) /* restore original control word */
+
+ leave
+ ret
diff --git a/lib/msun/i387/s_llrint.S b/lib/msun/i387/s_llrint.S
new file mode 100644
index 0000000..1b8a638
--- /dev/null
+++ b/lib/msun/i387/s_llrint.S
@@ -0,0 +1,36 @@
+/*-
+ * 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 <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+ENTRY(llrint)
+ fldl 4(%esp)
+ subl $8,%esp
+ fistpll (%esp)
+ popl %eax
+ popl %edx
+ ret
diff --git a/lib/msun/i387/s_llrintf.S b/lib/msun/i387/s_llrintf.S
new file mode 100644
index 0000000..4f398b6
--- /dev/null
+++ b/lib/msun/i387/s_llrintf.S
@@ -0,0 +1,36 @@
+/*-
+ * 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 <machine/asm.h>
+__FBSDID("$FreeBSD$")
+
+ENTRY(llrintf)
+ flds 4(%esp)
+ subl $8,%esp
+ fistpll (%esp)
+ popl %eax
+ popl %edx
+ ret
diff --git a/lib/msun/i387/s_logb.S b/lib/msun/i387/s_logb.S
new file mode 100644
index 0000000..9e09f84
--- /dev/null
+++ b/lib/msun/i387/s_logb.S
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+/*
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+#include <machine/asm.h>
+
+RCSID("$FreeBSD$")
+
+ENTRY(logb)
+ fldl 4(%esp)
+ fxtract
+ fstp %st
+ ret
diff --git a/lib/msun/i387/s_logbf.S b/lib/msun/i387/s_logbf.S
new file mode 100644
index 0000000..4cfa02b
--- /dev/null
+++ b/lib/msun/i387/s_logbf.S
@@ -0,0 +1,15 @@
+/*
+ * Written by J.T. Conklin <jtc@netbsd.org>.
+ * Public domain.
+ */
+
+#include <machine/asm.h>
+
+__FBSDID("$FreeBSD$");
+/* RCSID("$NetBSD: s_logbf.S,v 1.3 1995/05/09 00:15:12 jtc Exp $") */
+
+ENTRY(logbf)
+ flds 4(%esp)
+ fxtract
+ fstp %st
+ ret
diff --git a/lib/msun/i387/s_lrint.S b/lib/msun/i387/s_lrint.S
new file mode 100644
index 0000000..82269c8
--- /dev/null
+++ b/lib/msun/i387/s_lrint.S
@@ -0,0 +1,35 @@
+/*-
+ * 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 <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+ENTRY(lrint)
+ fldl 4(%esp)
+ subl $4,%esp
+ fistpl (%esp)
+ popl %eax
+ ret
diff --git a/lib/msun/i387/s_lrintf.S b/lib/msun/i387/s_lrintf.S
new file mode 100644
index 0000000..b9915fa
--- /dev/null
+++ b/lib/msun/i387/s_lrintf.S
@@ -0,0 +1,35 @@
+/*-
+ * 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 <machine/asm.h>
+__FBSDID("$FreeBSD$")
+
+ENTRY(lrintf)
+ flds 4(%esp)
+ subl $4,%esp
+ fistpl (%esp)
+ popl %eax
+ ret
diff --git a/lib/msun/i387/s_remquo.S b/lib/msun/i387/s_remquo.S
new file mode 100644
index 0000000..fd8af5e
--- /dev/null
+++ b/lib/msun/i387/s_remquo.S
@@ -0,0 +1,62 @@
+/*-
+ * 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.
+ */
+
+/*
+ * Based on public-domain remainder routine by J.T. Conklin <jtc@NetBSD.org>.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+ENTRY(remquo)
+ fldl 12(%esp)
+ fldl 4(%esp)
+1: fprem1
+ fstsw %ax
+ sahf
+ jp 1b
+ fstp %st(1)
+/* Extract the three low-order bits of the quotient from C0,C3,C1. */
+ shrl $6,%eax
+ movl %eax,%ecx
+ andl $0x108,%eax
+ rorl $7,%eax
+ orl %eax,%ecx
+ roll $4,%eax
+ orl %ecx,%eax
+ andl $7,%eax
+/* Negate the quotient bits if x*y<0. Avoid using an unpredictable branch. */
+ movl 16(%esp),%ecx
+ xorl 8(%esp),%ecx
+ sarl $16,%ecx
+ sarl $16,%ecx
+ xorl %ecx,%eax
+ andl $1,%ecx
+ addl %ecx,%eax
+/* Store the quotient and return. */
+ movl 20(%esp),%ecx
+ movl %eax,(%ecx)
+ ret
diff --git a/lib/msun/i387/s_remquof.S b/lib/msun/i387/s_remquof.S
new file mode 100644
index 0000000..70a43f4
--- /dev/null
+++ b/lib/msun/i387/s_remquof.S
@@ -0,0 +1,62 @@
+/*-
+ * 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.
+ */
+
+/*
+ * Based on public-domain remainder routine by J.T. Conklin <jtc@NetBSD.org>.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+ENTRY(remquof)
+ flds 8(%esp)
+ flds 4(%esp)
+1: fprem1
+ fstsw %ax
+ sahf
+ jp 1b
+ fstp %st(1)
+/* Extract the three low-order bits of the quotient from C0,C3,C1. */
+ shrl $6,%eax
+ movl %eax,%ecx
+ andl $0x108,%eax
+ rorl $7,%eax
+ orl %eax,%ecx
+ roll $4,%eax
+ orl %ecx,%eax
+ andl $7,%eax
+/* Negate the quotient bits if x*y<0. Avoid using an unpredictable branch. */
+ movl 8(%esp),%ecx
+ xorl 4(%esp),%ecx
+ sarl $16,%ecx
+ sarl $16,%ecx
+ xorl %ecx,%eax
+ andl $1,%ecx
+ addl %ecx,%eax
+/* Store the quotient and return. */
+ movl 12(%esp),%ecx
+ movl %eax,(%ecx)
+ ret
diff --git a/lib/msun/i387/s_rint.S b/lib/msun/i387/s_rint.S
new file mode 100644
index 0000000..79da080
--- /dev/null
+++ b/lib/msun/i387/s_rint.S
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+/*
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+#include <machine/asm.h>
+
+RCSID("$FreeBSD$")
+
+ENTRY(rint)
+ fldl 4(%esp)
+ frndint
+ ret
diff --git a/lib/msun/i387/s_rintf.S b/lib/msun/i387/s_rintf.S
new file mode 100644
index 0000000..646dcb5
--- /dev/null
+++ b/lib/msun/i387/s_rintf.S
@@ -0,0 +1,14 @@
+/*
+ * Written by J.T. Conklin <jtc@netbsd.org>.
+ * Public domain.
+ */
+
+#include <machine/asm.h>
+
+__FBSDID("$FreeBSD$");
+/* RCSID("$NetBSD: s_rintf.S,v 1.3 1995/05/09 00:17:22 jtc Exp $") */
+
+ENTRY(rintf)
+ flds 4(%esp)
+ frndint
+ ret
diff --git a/lib/msun/i387/s_scalbn.S b/lib/msun/i387/s_scalbn.S
new file mode 100644
index 0000000..c00e1fb
--- /dev/null
+++ b/lib/msun/i387/s_scalbn.S
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+/*
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+#include <machine/asm.h>
+
+RCSID("$FreeBSD$")
+
+ENTRY(scalbn)
+ fildl 12(%esp)
+ fldl 4(%esp)
+ fscale
+ fstp %st(1)
+ ret
diff --git a/lib/msun/i387/s_scalbnf.S b/lib/msun/i387/s_scalbnf.S
new file mode 100644
index 0000000..3c84749
--- /dev/null
+++ b/lib/msun/i387/s_scalbnf.S
@@ -0,0 +1,19 @@
+/*
+ * Written by J.T. Conklin <jtc@netbsd.org>.
+ * Public domain.
+ */
+
+#include <machine/asm.h>
+
+__FBSDID("$FreeBSD$");
+/* RCSID("$NetBSD: s_scalbnf.S,v 1.4 1999/01/02 05:15:40 kristerw Exp $") */
+
+ENTRY(scalbnf)
+ fildl 8(%esp)
+ flds 4(%esp)
+ fscale
+ fstp %st(1) /* bug fix for fp stack overflow */
+ ret
+
+.globl CNAME(ldexpf)
+.set CNAME(ldexpf),CNAME(scalbnf)
diff --git a/lib/msun/i387/s_scalbnl.S b/lib/msun/i387/s_scalbnl.S
new file mode 100644
index 0000000..c166326
--- /dev/null
+++ b/lib/msun/i387/s_scalbnl.S
@@ -0,0 +1,19 @@
+/*
+ * Written by J.T. Conklin <jtc@netbsd.org>.
+ * Public domain.
+ */
+
+#include <machine/asm.h>
+
+__FBSDID("$FreeBSD$");
+/* RCSID("$NetBSD: s_scalbnf.S,v 1.4 1999/01/02 05:15:40 kristerw Exp $") */
+
+ENTRY(scalbnl)
+ fildl 16(%esp)
+ fldt 4(%esp)
+ fscale
+ fstp %st(1)
+ ret
+
+.globl CNAME(ldexpl)
+.set CNAME(ldexpl),CNAME(scalbnl)
diff --git a/lib/msun/i387/s_significand.S b/lib/msun/i387/s_significand.S
new file mode 100644
index 0000000..13f1f3e
--- /dev/null
+++ b/lib/msun/i387/s_significand.S
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+/*
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+#include <machine/asm.h>
+
+RCSID("$FreeBSD$")
+
+ENTRY(significand)
+ fldl 4(%esp)
+ fxtract
+ fstp %st(1)
+ ret
diff --git a/lib/msun/i387/s_significandf.S b/lib/msun/i387/s_significandf.S
new file mode 100644
index 0000000..9929981
--- /dev/null
+++ b/lib/msun/i387/s_significandf.S
@@ -0,0 +1,15 @@
+/*
+ * Written by J.T. Conklin <jtc@netbsd.org>.
+ * Public domain.
+ */
+
+#include <machine/asm.h>
+
+__FBSDID("$FreeBSD$");
+/* RCSID("$NetBSD: s_significandf.S,v 1.3 1995/05/09 00:24:07 jtc Exp $") */
+
+ENTRY(significandf)
+ flds 4(%esp)
+ fxtract
+ fstp %st(1)
+ ret
diff --git a/lib/msun/i387/s_sin.S b/lib/msun/i387/s_sin.S
new file mode 100644
index 0000000..d152352
--- /dev/null
+++ b/lib/msun/i387/s_sin.S
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+/*
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+#include <machine/asm.h>
+
+RCSID("$FreeBSD$")
+
+ENTRY(sin)
+ fldl 4(%esp)
+ fsin
+ fnstsw %ax
+ andw $0x400,%ax
+ jnz 1f
+ ret
+1: fldpi
+ fadd %st(0)
+ fxch %st(1)
+2: fprem1
+ fnstsw %ax
+ andw $0x400,%ax
+ jnz 2b
+ fstp %st(1)
+ fsin
+ ret
diff --git a/lib/msun/i387/s_tan.S b/lib/msun/i387/s_tan.S
new file mode 100644
index 0000000..d0cbc0a
--- /dev/null
+++ b/lib/msun/i387/s_tan.S
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+/*
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+#include <machine/asm.h>
+
+RCSID("$FreeBSD$")
+
+ENTRY(tan)
+ fldl 4(%esp)
+ fptan
+ fnstsw %ax
+ andw $0x400,%ax
+ jnz 1f
+ fstp %st(0)
+ ret
+1: fldpi
+ fadd %st(0)
+ fxch %st(1)
+2: fprem1
+ fstsw %ax
+ andw $0x400,%ax
+ jnz 2b
+ fstp %st(1)
+ fptan
+ fstp %st(0)
+ ret
diff --git a/lib/msun/i387/s_trunc.S b/lib/msun/i387/s_trunc.S
new file mode 100644
index 0000000..91926d7
--- /dev/null
+++ b/lib/msun/i387/s_trunc.S
@@ -0,0 +1,26 @@
+/*
+ * Based on code written by J.T. Conklin <jtc@NetBSD.org>.
+ * Public domain.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$")
+
+ENTRY(trunc)
+ pushl %ebp
+ movl %esp,%ebp
+ subl $8,%esp
+
+ fstcw -4(%ebp) /* store fpu control word */
+ movw -4(%ebp),%dx
+ orw $0x0c00,%dx /* round towards -oo */
+ movw %dx,-8(%ebp)
+ fldcw -8(%ebp) /* load modfied control word */
+
+ fldl 8(%ebp) /* round */
+ frndint
+
+ fldcw -4(%ebp) /* restore original control word */
+
+ leave
+ ret
diff --git a/lib/msun/i387/s_truncf.S b/lib/msun/i387/s_truncf.S
new file mode 100644
index 0000000..0001367
--- /dev/null
+++ b/lib/msun/i387/s_truncf.S
@@ -0,0 +1,26 @@
+/*
+ * Based on code written by J.T. Conklin <jtc@NetBSD.org>.
+ * Public domain.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$")
+
+ENTRY(truncf)
+ pushl %ebp
+ movl %esp,%ebp
+ subl $8,%esp
+
+ fstcw -4(%ebp) /* store fpu control word */
+ movw -4(%ebp),%dx
+ orw $0x0c00,%dx /* round towards -oo */
+ movw %dx,-8(%ebp)
+ fldcw -8(%ebp) /* load modfied control word */
+
+ flds 8(%ebp) /* round */
+ frndint
+
+ fldcw -4(%ebp) /* restore original control word */
+
+ leave
+ ret
diff --git a/lib/msun/i387/s_truncl.S b/lib/msun/i387/s_truncl.S
new file mode 100644
index 0000000..b20b06e
--- /dev/null
+++ b/lib/msun/i387/s_truncl.S
@@ -0,0 +1,26 @@
+/*
+ * Based on code written by J.T. Conklin <jtc@NetBSD.org>.
+ * Public domain.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$")
+
+ENTRY(truncl)
+ pushl %ebp
+ movl %esp,%ebp
+ subl $8,%esp
+
+ fstcw -4(%ebp) /* store fpu control word */
+ movw -4(%ebp),%dx
+ orw $0x0c00,%dx /* round towards -oo */
+ movw %dx,-8(%ebp)
+ fldcw -8(%ebp) /* load modfied control word */
+
+ fldt 8(%ebp) /* round */
+ frndint
+
+ fldcw -4(%ebp) /* restore original control word */
+
+ leave
+ ret
diff --git a/lib/msun/ia64/Makefile.inc b/lib/msun/ia64/Makefile.inc
new file mode 100644
index 0000000..c941c66
--- /dev/null
+++ b/lib/msun/ia64/Makefile.inc
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+ARCH_SRCS = s_fma.S s_fmaf.S s_fmal.S
+LDBL_PREC = 64
+SYM_MAPS += ${.CURDIR}/ia64/Symbol.map
diff --git a/lib/msun/ia64/Symbol.map b/lib/msun/ia64/Symbol.map
new file mode 100644
index 0000000..9b63e4f
--- /dev/null
+++ b/lib/msun/ia64/Symbol.map
@@ -0,0 +1,4 @@
+# $FreeBSD$
+FBSD_1.0 {
+ feupdateenv;
+};
diff --git a/lib/msun/ia64/fenv.c b/lib/msun/ia64/fenv.c
new file mode 100644
index 0000000..95a5809
--- /dev/null
+++ b/lib/msun/ia64/fenv.c
@@ -0,0 +1,49 @@
+/*-
+ * 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 <sys/types.h>
+#include <fenv.h>
+
+const fenv_t __fe_dfl_env = 0x0009804c8a70033fULL;
+
+/*
+ * It doesn't pay to inline feupdateenv() because it includes one of
+ * the rare uses of feraiseexcept() where the argument is not a
+ * constant. Thus, no dead code elimination can occur, resulting in
+ * significant bloat.
+ */
+int
+feupdateenv(const fenv_t *envp)
+{
+ fenv_t fpsr;
+
+ __stfpsr(&fpsr);
+ __ldfpsr(*envp);
+ feraiseexcept((fpsr >> _FPUSW_SHIFT) & FE_ALL_EXCEPT);
+ return (0);
+}
diff --git a/lib/msun/ia64/fenv.h b/lib/msun/ia64/fenv.h
new file mode 100644
index 0000000..6f0240f
--- /dev/null
+++ b/lib/msun/ia64/fenv.h
@@ -0,0 +1,242 @@
+/*-
+ * Copyright (c) 2004-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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _FENV_H_
+#define _FENV_H_
+
+#include <sys/_types.h>
+
+typedef __uint64_t fenv_t;
+typedef __uint16_t fexcept_t;
+
+/* Exception flags */
+#define FE_INVALID 0x01
+#define FE_DENORMAL 0x02
+#define FE_DIVBYZERO 0x04
+#define FE_OVERFLOW 0x08
+#define FE_UNDERFLOW 0x10
+#define FE_INEXACT 0x20
+#define FE_ALL_EXCEPT (FE_DIVBYZERO | FE_DENORMAL | FE_INEXACT | \
+ FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW)
+
+/* Rounding modes */
+#define FE_TONEAREST 0x0000
+#define FE_DOWNWARD 0x0400
+#define FE_UPWARD 0x0800
+#define FE_TOWARDZERO 0x0c00
+#define _ROUND_MASK (FE_TONEAREST | FE_DOWNWARD | \
+ FE_UPWARD | FE_TOWARDZERO)
+
+__BEGIN_DECLS
+
+/* Default floating-point environment */
+extern const fenv_t __fe_dfl_env;
+#define FE_DFL_ENV (&__fe_dfl_env)
+
+#define _FPUSW_SHIFT 13
+
+#define __stfpsr(__r) __asm __volatile("mov %0=ar.fpsr" : "=r" (*(__r)))
+#define __ldfpsr(__r) __asm __volatile("mov ar.fpsr=%0;;" : : "r" (__r))
+
+static __inline int
+feclearexcept(int __excepts)
+{
+ fenv_t __fpsr;
+
+ __stfpsr(&__fpsr);
+ __fpsr &= ~((fenv_t)__excepts << _FPUSW_SHIFT);
+ __ldfpsr(__fpsr);
+ return (0);
+}
+
+static __inline int
+fegetexceptflag(fexcept_t *__flagp, int __excepts)
+{
+ fenv_t __fpsr;
+
+ __stfpsr(&__fpsr);
+ *__flagp = (fexcept_t)(__fpsr >> _FPUSW_SHIFT) & __excepts;
+ return (0);
+}
+
+static __inline int
+fesetexceptflag(const fexcept_t *__flagp, int __excepts)
+{
+ fenv_t __fpsr;
+
+ __stfpsr(&__fpsr);
+ __fpsr &= ~((fenv_t)__excepts << _FPUSW_SHIFT);
+ __fpsr |= (fenv_t)(__excepts & *__flagp) << _FPUSW_SHIFT;
+ __ldfpsr(__fpsr);
+ return (0);
+}
+
+/*
+ * It is worthwhile to use the inline version of this function iff it
+ * is called with arguments that are compile-time constants (due to
+ * dead code elimination). Unfortunately, gcc isn't smart enough to
+ * figure this out automatically, and there's no way to tell it.
+ * We assume that constant arguments will be the common case.
+ */
+static __inline int
+feraiseexcept(int __excepts)
+{
+ volatile double d;
+
+ /*
+ * With a compiler that supports the FENV_ACCESS pragma
+ * properly, simple expressions like '0.0 / 0.0' should
+ * be sufficient to generate traps. Unfortunately, we
+ * need to bring a volatile variable into the equation
+ * to prevent incorrect optimizations.
+ */
+ if (__excepts & FE_INVALID) {
+ d = 0.0;
+ d = 0.0 / d;
+ }
+ if (__excepts & FE_DIVBYZERO) {
+ d = 0.0;
+ d = 1.0 / d;
+ }
+ if (__excepts & FE_OVERFLOW) {
+ d = 0x1.ffp1023;
+ d *= 2.0;
+ }
+ if (__excepts & FE_UNDERFLOW) {
+ d = 0x1p-1022;
+ d /= 0x1p1023;
+ }
+ if (__excepts & FE_INEXACT) {
+ d = 0x1p-1022;
+ d += 1.0;
+ }
+ return (0);
+}
+
+static __inline int
+fetestexcept(int __excepts)
+{
+ fenv_t __fpsr;
+
+ __stfpsr(&__fpsr);
+ return ((__fpsr >> _FPUSW_SHIFT) & __excepts);
+}
+
+
+static __inline int
+fegetround(void)
+{
+ fenv_t __fpsr;
+
+ __stfpsr(&__fpsr);
+ return (__fpsr & _ROUND_MASK);
+}
+
+static __inline int
+fesetround(int __round)
+{
+ fenv_t __fpsr;
+
+ if (__round & ~_ROUND_MASK)
+ return (-1);
+ __stfpsr(&__fpsr);
+ __fpsr &= ~_ROUND_MASK;
+ __fpsr |= __round;
+ __ldfpsr(__fpsr);
+ return (0);
+}
+
+static __inline int
+fegetenv(fenv_t *__envp)
+{
+
+ __stfpsr(__envp);
+ return (0);
+}
+
+static __inline int
+feholdexcept(fenv_t *__envp)
+{
+ fenv_t __fpsr;
+
+ __stfpsr(&__fpsr);
+ *__envp = __fpsr;
+ __fpsr &= ~((fenv_t)FE_ALL_EXCEPT << _FPUSW_SHIFT);
+ __fpsr |= FE_ALL_EXCEPT;
+ __ldfpsr(__fpsr);
+ return (0);
+}
+
+static __inline int
+fesetenv(const fenv_t *__envp)
+{
+
+ __ldfpsr(*__envp);
+ return (0);
+}
+
+int feupdateenv(const fenv_t *__envp);
+
+#if __BSD_VISIBLE
+
+static __inline int
+feenableexcept(int __mask)
+{
+ fenv_t __newfpsr, __oldfpsr;
+
+ __stfpsr(&__oldfpsr);
+ __newfpsr = __oldfpsr & ~(__mask & FE_ALL_EXCEPT);
+ __ldfpsr(__newfpsr);
+ return (~__oldfpsr & FE_ALL_EXCEPT);
+}
+
+static __inline int
+fedisableexcept(int __mask)
+{
+ fenv_t __newfpsr, __oldfpsr;
+
+ __stfpsr(&__oldfpsr);
+ __newfpsr = __oldfpsr | (__mask & FE_ALL_EXCEPT);
+ __ldfpsr(__newfpsr);
+ return (~__oldfpsr & FE_ALL_EXCEPT);
+}
+
+static __inline int
+fegetexcept(void)
+{
+ fenv_t __fpsr;
+
+ __stfpsr(&__fpsr);
+ return (~__fpsr & FE_ALL_EXCEPT);
+}
+
+#endif /* __BSD_VISIBLE */
+
+__END_DECLS
+
+#endif /* !_FENV_H_ */
diff --git a/lib/msun/ia64/s_fma.S b/lib/msun/ia64/s_fma.S
new file mode 100644
index 0000000..3e69359
--- /dev/null
+++ b/lib/msun/ia64/s_fma.S
@@ -0,0 +1,34 @@
+/*-
+ * 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 <machine/asm.h>
+__FBSDID("$FreeBSD$")
+
+ENTRY(fma, 3)
+{
+ fma.d f8 = f8, f9, f10
+ br.ret.sptk b0
+}
diff --git a/lib/msun/ia64/s_fmaf.S b/lib/msun/ia64/s_fmaf.S
new file mode 100644
index 0000000..1e122bb
--- /dev/null
+++ b/lib/msun/ia64/s_fmaf.S
@@ -0,0 +1,34 @@
+/*-
+ * 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 <machine/asm.h>
+__FBSDID("$FreeBSD$")
+
+ENTRY(fmaf, 3)
+{
+ fma.s f8 = f8, f9, f10
+ br.ret.sptk b0
+}
diff --git a/lib/msun/ia64/s_fmal.S b/lib/msun/ia64/s_fmal.S
new file mode 100644
index 0000000..c24a1de
--- /dev/null
+++ b/lib/msun/ia64/s_fmal.S
@@ -0,0 +1,34 @@
+/*-
+ * 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 <machine/asm.h>
+__FBSDID("$FreeBSD$")
+
+ENTRY(fmal, 3)
+{
+ fma f8 = f8, f9, f10
+ br.ret.sptk b0
+}
diff --git a/lib/msun/man/acos.3 b/lib/msun/man/acos.3
new file mode 100644
index 0000000..a08230a
--- /dev/null
+++ b/lib/msun/man/acos.3
@@ -0,0 +1,92 @@
+.\" Copyright (c) 1991 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce 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.
+.\"
+.\" from: @(#)acos.3 5.1 (Berkeley) 5/2/91
+.\" $FreeBSD$
+.\"
+.Dd January 14, 2005
+.Dt ACOS 3
+.Os
+.Sh NAME
+.Nm acos ,
+.Nm acosf
+.Nd arc cosine functions
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In math.h
+.Ft double
+.Fn acos "double x"
+.Ft float
+.Fn acosf "float x"
+.Sh DESCRIPTION
+The
+.Fn acos
+and the
+.Fn acosf
+functions compute the principal value of the arc cosine of
+.Fa x .
+A domain error occurs for arguments not in the range
+.Bq -1 , +1 .
+For a discussion of error due to roundoff, see
+.Xr math 3 .
+.Sh RETURN VALUES
+The
+.Fn acos
+and the
+.Fn acosf
+functions return the arc cosine in the range
+.Bq 0 , \*(Pi
+radians.
+If:
+.Bd -unfilled -offset indent
+.Pf \&| Ns Ar x Ns \&| > 1 ,
+.Ed
+.Pp
+.Fn acos x
+raises an invalid exception and returns an \*(Na.
+.Sh SEE ALSO
+.Xr asin 3 ,
+.Xr atan 3 ,
+.Xr atan2 3 ,
+.Xr cos 3 ,
+.Xr cosh 3 ,
+.Xr fenv 3 ,
+.Xr math 3 ,
+.Xr sin 3 ,
+.Xr sinh 3 ,
+.Xr tan 3 ,
+.Xr tanh 3
+.Sh STANDARDS
+The
+.Fn acos
+function conforms to
+.St -isoC .
diff --git a/lib/msun/man/acosh.3 b/lib/msun/man/acosh.3
new file mode 100644
index 0000000..b133901
--- /dev/null
+++ b/lib/msun/man/acosh.3
@@ -0,0 +1,82 @@
+.\" Copyright (c) 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.
+.\" 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.
+.\"
+.\" from: @(#)acosh.3 5.2 (Berkeley) 5/6/91
+.\" $FreeBSD$
+.\"
+.Dd January 14, 2005
+.Dt ACOSH 3
+.Os
+.Sh NAME
+.Nm acosh ,
+.Nm acoshf
+.Nd inverse hyperbolic cosine functions
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In math.h
+.Ft double
+.Fn acosh "double x"
+.Ft float
+.Fn acoshf "float x"
+.Sh DESCRIPTION
+The
+.Fn acosh
+and the
+.Fn acoshf
+functions compute the inverse hyperbolic cosine
+of the real
+argument
+.Ar x .
+For a discussion of error due to roundoff, see
+.Xr math 3 .
+.Sh RETURN VALUES
+The
+.Fn acosh
+and the
+.Fn acoshf
+functions
+return the inverse hyperbolic cosine of
+.Ar x .
+If the argument is less than 1,
+.Fn acosh
+raises an invalid exception and returns an \*(Na.
+.Sh SEE ALSO
+.Xr asinh 3 ,
+.Xr atanh 3 ,
+.Xr exp 3 ,
+.Xr fenv 3 ,
+.Xr math 3
+.Sh HISTORY
+The
+.Fn acosh
+function appeared in
+.Bx 4.3 .
diff --git a/lib/msun/man/asin.3 b/lib/msun/man/asin.3
new file mode 100644
index 0000000..e33623d
--- /dev/null
+++ b/lib/msun/man/asin.3
@@ -0,0 +1,94 @@
+.\" Copyright (c) 1991 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce 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.
+.\"
+.\" from: @(#)asin.3 5.1 (Berkeley) 5/2/91
+.\" $FreeBSD$
+.\"
+.Dd January 14, 2005
+.Dt ASIN 3
+.Os
+.Sh NAME
+.Nm asin ,
+.Nm asinf
+.Nd arc sine functions
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In math.h
+.Ft double
+.Fn asin "double x"
+.Ft float
+.Fn asinf "float x"
+.Sh DESCRIPTION
+The
+.Fn asin
+and the
+.Fn asinf
+functions compute the principal value of the arc sine of
+.Fa x .
+A domain error occurs for arguments not in the range
+.Bq -1 , +1 .
+For a discussion of error due to roundoff, see
+.Xr math 3 .
+.Sh RETURN VALUES
+The
+.Fn asin
+and the
+.Fn asinf
+functions return the arc sine in the range
+.Bk -words
+.Bq -\*(Pi/2 , +\*(Pi/2
+.Ek
+radians.
+If:
+.Bd -unfilled -offset indent
+.Pf \&| Ns Ar x Ns \&| > 1
+.Ed
+.Pp
+.Fn asin x
+raises an invalid exception and returns an \*(Na.
+.Sh SEE ALSO
+.Xr acos 3 ,
+.Xr atan 3 ,
+.Xr atan2 3 ,
+.Xr cos 3 ,
+.Xr cosh 3 ,
+.Xr fenv 3 ,
+.Xr math 3 ,
+.Xr sin 3 ,
+.Xr sinh 3 ,
+.Xr tan 3 ,
+.Xr tanh 3
+.Sh STANDARDS
+The
+.Fn asin
+function conforms to
+.St -isoC .
diff --git a/lib/msun/man/asinh.3 b/lib/msun/man/asinh.3
new file mode 100644
index 0000000..636bbe0
--- /dev/null
+++ b/lib/msun/man/asinh.3
@@ -0,0 +1,78 @@
+.\" Copyright (c) 1985, 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.
+.\" 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.
+.\"
+.\" from: @(#)asinh.3 6.4 (Berkeley) 5/6/91
+.\" $FreeBSD$
+.\"
+.Dd May 6, 1991
+.Dt ASINH 3
+.Os
+.Sh NAME
+.Nm asinh ,
+.Nm asinhf
+.Nd inverse hyperbolic sine functions
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In math.h
+.Ft double
+.Fn asinh "double x"
+.Ft float
+.Fn asinhf "float x"
+.Sh DESCRIPTION
+The
+.Fn asinh
+and the
+.Fn asinhf
+functions compute the inverse hyperbolic sine
+of the real
+argument
+.Ar x .
+For a discussion of error due to roundoff, see
+.Xr math 3 .
+.Sh RETURN VALUES
+The
+.Fn asinh
+and the
+.Fn asinhf
+functions
+return the inverse hyperbolic sine of
+.Ar x .
+.Sh SEE ALSO
+.Xr acosh 3 ,
+.Xr atanh 3 ,
+.Xr exp 3 ,
+.Xr math 3
+.Sh HISTORY
+The
+.Fn asinh
+function appeared in
+.Bx 4.3 .
diff --git a/lib/msun/man/atan.3 b/lib/msun/man/atan.3
new file mode 100644
index 0000000..b6417c6
--- /dev/null
+++ b/lib/msun/man/atan.3
@@ -0,0 +1,84 @@
+.\" Copyright (c) 1991 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce 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.
+.\"
+.\" from: @(#)atan.3 5.1 (Berkeley) 5/2/91
+.\" $FreeBSD$
+.\"
+.Dd May 2, 1991
+.Dt ATAN 3
+.Os
+.Sh NAME
+.Nm atan ,
+.Nm atanf
+.Nd arc tangent functions of one variable
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In math.h
+.Ft double
+.Fn atan "double x"
+.Ft float
+.Fn atanf "float x"
+.Sh DESCRIPTION
+The
+.Fn atan
+and the
+.Fn atanf
+functions compute the principal value of the arc tangent of
+.Fa x .
+For a discussion of error due to roundoff, see
+.Xr math 3 .
+.Sh RETURN VALUES
+The
+.Fn atan
+and the
+.Fn atanf
+function returns the arc tangent in the range
+.Bk -words
+.Bq -\*(Pi/2 , +\*(Pi/2
+.Ek
+radians.
+.Sh SEE ALSO
+.Xr acos 3 ,
+.Xr asin 3 ,
+.Xr atan2 3 ,
+.Xr cos 3 ,
+.Xr cosh 3 ,
+.Xr math 3 ,
+.Xr sin 3 ,
+.Xr sinh 3 ,
+.Xr tan 3 ,
+.Xr tanh 3
+.Sh STANDARDS
+The
+.Fn atan
+function conforms to
+.St -isoC .
diff --git a/lib/msun/man/atan2.3 b/lib/msun/man/atan2.3
new file mode 100644
index 0000000..684124b
--- /dev/null
+++ b/lib/msun/man/atan2.3
@@ -0,0 +1,187 @@
+.\" Copyright (c) 1991 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce 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.
+.\"
+.\" from: @(#)atan2.3 5.1 (Berkeley) 5/2/91
+.\" $FreeBSD$
+.\"
+.Dd January 14, 2005
+.Dt ATAN2 3
+.Os
+.Sh NAME
+.Nm atan2 ,
+.Nm atan2f
+.Nd arc tangent functions of two variables
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In math.h
+.Ft double
+.Fn atan2 "double y" "double x"
+.Ft float
+.Fn atan2f "float y" "float x"
+.Sh DESCRIPTION
+The
+.Fn atan2
+and the
+.Fn atan2f
+functions compute the principal value of the arc tangent of
+.Fa y/ Ns Ar x ,
+using the signs of both arguments to determine the quadrant of
+the return value.
+.Sh RETURN VALUES
+The
+.Fn atan2
+and the
+.Fn atan2f
+functions, if successful,
+return the arc tangent of
+.Fa y/ Ns Ar x
+in the range
+.Bk -words
+.Bq \&- Ns \*(Pi , \&+ Ns \*(Pi
+.Ek
+radians.
+Here are some of the special cases:
+.Bl -column atan_(y,x)_:=____ sign(y)_(Pi_atan2(Xy_xX))___
+.It Fn atan2 y x No := Ta
+.Fn atan y/x Ta
+if
+.Ar x
+> 0,
+.It Ta sign( Ns Ar y Ns )*(\*(Pi -
+.Fn atan "\\*(Bay/x\\*(Ba" ) Ta
+if
+.Ar x
+< 0,
+.It Ta
+.No 0 Ta
+if x = y = 0, or
+.It Ta
+.Pf sign( Ar y Ns )*\\*(Pi/2 Ta
+if
+.Ar x
+= 0 \(!=
+.Ar y .
+.El
+.Sh NOTES
+The function
+.Fn atan2
+defines "if x > 0,"
+.Fn atan2 0 0
+= 0 despite that previously
+.Fn atan2 0 0
+may have generated an error message.
+The reasons for assigning a value to
+.Fn atan2 0 0
+are these:
+.Bl -enum -offset indent
+.It
+Programs that test arguments to avoid computing
+.Fn atan2 0 0
+must be indifferent to its value.
+Programs that require it to be invalid are vulnerable
+to diverse reactions to that invalidity on diverse computer systems.
+.It
+The
+.Fn atan2
+function is used mostly to convert from rectangular (x,y)
+to polar
+.if n\
+(r,theta)
+.if t\
+(r,\(*h)
+coordinates that must satisfy x =
+.if n\
+r\(**cos theta
+.if t\
+r\(**cos\(*h
+and y =
+.if n\
+r\(**sin theta.
+.if t\
+r\(**sin\(*h.
+These equations are satisfied when (x=0,y=0)
+is mapped to
+.if n \
+(r=0,theta=0).
+.if t \
+(r=0,\(*h=0).
+In general, conversions to polar coordinates
+should be computed thus:
+.Bd -unfilled -offset indent
+.if n \{\
+r := hypot(x,y); ... := sqrt(x\(**x+y\(**y)
+theta := atan2(y,x).
+.\}
+.if t \{\
+r := hypot(x,y); ... := \(sr(x\u\s82\s10\d+y\u\s82\s10\d)
+\(*h := atan2(y,x).
+.\}
+.Ed
+.It
+The foregoing formulas need not be altered to cope in a
+reasonable way with signed zeros and infinities
+on a machine that conforms to
+.Tn IEEE 754 ;
+the versions of
+.Xr hypot 3
+and
+.Fn atan2
+provided for
+such a machine are designed to handle all cases.
+That is why
+.Fn atan2 \(+-0 \-0
+= \(+-\*(Pi
+for instance.
+In general the formulas above are equivalent to these:
+.Bd -unfilled -offset indent
+.if n \
+r := sqrt(x\(**x+y\(**y); if r = 0 then x := copysign(1,x);
+.if t \
+r := \(sr(x\(**x+y\(**y);\0\0if r = 0 then x := copysign(1,x);
+.Ed
+.El
+.Sh SEE ALSO
+.Xr acos 3 ,
+.Xr asin 3 ,
+.Xr atan 3 ,
+.Xr cos 3 ,
+.Xr cosh 3 ,
+.Xr math 3 ,
+.Xr sin 3 ,
+.Xr sinh 3 ,
+.Xr tan 3 ,
+.Xr tanh 3
+.Sh STANDARDS
+The
+.Fn atan2
+function conforms to
+.St -isoC .
diff --git a/lib/msun/man/atanh.3 b/lib/msun/man/atanh.3
new file mode 100644
index 0000000..abd0c7d
--- /dev/null
+++ b/lib/msun/man/atanh.3
@@ -0,0 +1,85 @@
+.\" Copyright (c) 1985, 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.
+.\" 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.
+.\"
+.\" from: @(#)atanh.3 5.2 (Berkeley) 5/6/91
+.\" $FreeBSD$
+.\"
+.Dd January 14, 2005
+.Dt ATANH 3
+.Os
+.Sh NAME
+.Nm atanh ,
+.Nm atanhf
+.Nd inverse hyperbolic tangent functions
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In math.h
+.Ft double
+.Fn atanh "double x"
+.Ft float
+.Fn atanhf "float x"
+.Sh DESCRIPTION
+The
+.Fn atanh
+and the
+.Fn atanhf
+functions compute the inverse hyperbolic tangent
+of the real
+argument
+.Ar x .
+For a discussion of error due to roundoff, see
+.Xr math 3 .
+.Sh RETURN VALUES
+The
+.Fn atanh
+and the
+.Fn atanhf
+functions
+return the inverse hyperbolic tangent of
+.Ar x
+if successful.
+If the argument has absolute value 1, a divide-by-zero exception
+is raised and an infinity is returned.
+If
+.Ar |x|
+> 1, an invalid exception is raised and an \*(Na is returned.
+.Sh SEE ALSO
+.Xr acosh 3 ,
+.Xr asinh 3 ,
+.Xr exp 3 ,
+.Xr fenv 3 ,
+.Xr math 3
+.Sh HISTORY
+The
+.Fn atanh
+function appeared in
+.Bx 4.3 .
diff --git a/lib/msun/man/ceil.3 b/lib/msun/man/ceil.3
new file mode 100644
index 0000000..3f825c9
--- /dev/null
+++ b/lib/msun/man/ceil.3
@@ -0,0 +1,82 @@
+.\" Copyright (c) 1991 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce 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.
+.\"
+.\" from: @(#)ceil.3 5.1 (Berkeley) 5/2/91
+.\" $FreeBSD$
+.\"
+.Dd January 13, 2005
+.Dt CEIL 3
+.Os
+.Sh NAME
+.Nm ceil ,
+.Nm ceilf ,
+.Nm ceill
+.Nd smallest integral value greater than or equal to x
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In math.h
+.Ft double
+.Fn ceil "double x"
+.Ft float
+.Fn ceilf "float x"
+.Ft "long double"
+.Fn ceill "long double x"
+.Sh DESCRIPTION
+The
+.Fn ceil ,
+.Fn ceilf
+and
+.Fn ceill
+functions return the smallest integral value
+greater than or equal to
+.Fa x ,
+expressed as a floating-point number.
+.Sh SEE ALSO
+.Xr abs 3 ,
+.Xr fabs 3 ,
+.Xr floor 3 ,
+.Xr ieee 3 ,
+.Xr math 3 ,
+.Xr rint 3 ,
+.Xr round 3 ,
+.Xr trunc 3
+.Sh STANDARDS
+The
+.Fn ceil
+function conforms to
+.St -isoC .
+The
+.Fn ceilf
+and
+.Fn ceill
+functions conform to
+.St -isoC-99 .
diff --git a/lib/msun/man/cimag.3 b/lib/msun/man/cimag.3
new file mode 100644
index 0000000..10a3b2c
--- /dev/null
+++ b/lib/msun/man/cimag.3
@@ -0,0 +1,96 @@
+.\" Copyright (c) 2004 Stefan Farfeleder
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING 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, 2004
+.Dt CIMAG 3
+.Os
+.Sh NAME
+.Nm cimag , cimagf , cimagl ,
+.Nm conj , conjf , conjl ,
+.Nm creal , crealf , creall
+.Nd "functions to manipulate complex numbers"
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In complex.h
+.Ft double
+.Fn cimag "double complex z"
+.Ft float
+.Fn cimagf "float complex z"
+.Ft "long double"
+.Fn cimagl "long double complex z"
+.Ft "double complex"
+.Fn conj "double complex z"
+.Ft "float complex"
+.Fn conjf "float complex z"
+.Ft "long double complex"
+.Fn conjl "long double complex z"
+.Ft double
+.Fn creal "double complex z"
+.Ft float
+.Fn crealf "float complex z"
+.Ft "long double"
+.Fn creall "long double complex z"
+.Sh DESCRIPTION
+Let
+.Sm off
+.Fa a + b * Em i
+.Sm on
+denote the complex number
+.Fa z .
+.Pp
+The
+.Fn cimag
+functions return the imaginary part
+.Fa b .
+.Pp
+The
+.Fn conj
+functions return the complex conjugate
+.Sm off
+.Fa a - b * Em i .
+.Sm on
+.Pp
+The
+.Fn creal
+functions return the real part
+.Fa a .
+.Sh STANDARDS
+The
+.Fn cimag ,
+.Fn conj
+and
+.Fn creal
+functions conform to
+.St -isoC-99 .
+.Sh HISTORY
+The
+.Fn cimag ,
+.Fn conj
+and
+.Fn creal
+functions first appeared in
+.Fx 5.3 .
diff --git a/lib/msun/man/copysign.3 b/lib/msun/man/copysign.3
new file mode 100644
index 0000000..83fc126
--- /dev/null
+++ b/lib/msun/man/copysign.3
@@ -0,0 +1,90 @@
+.\" Copyright (c) 1985, 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.
+.\" 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.
+.\"
+.\" from: @(#)ieee.3 6.4 (Berkeley) 5/6/91
+.\" $FreeBSD$
+.\"
+.Dd January 26, 2005
+.Dt COPYSIGN 3
+.Os
+.Sh NAME
+.Nm copysign ,
+.Nm copysignf ,
+.Nm copysignl
+.Nd copy sign
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In math.h
+.Ft double
+.Fn copysign "double x" "double y"
+.Ft float
+.Fn copysignf "float x" "float y"
+.Ft long double
+.Fn copysignl "long double x" "long double y"
+.Sh DESCRIPTION
+The
+.Fn copysign ,
+.Fn copysignf
+and
+.Fn copysignl
+functions
+return
+.Fa x
+with its sign changed to
+.Fa y Ns 's .
+.Sh SEE ALSO
+.Xr fabs 3 ,
+.Xr fdim 3 ,
+.Xr ieee 3 ,
+.Xr math 3
+.Sh STANDARDS
+The
+.Fn copysign ,
+.Fn copysignf ,
+and
+.Fn copysignl
+routines conform to
+.St -isoC-99 .
+They implement the Copysign function recommended by
+.St -ieee754 .
+.Sh HISTORY
+The
+.Fn copysign ,
+.Fn copysignf ,
+and
+.Fn copysignl
+functions appeared in
+.Bx 4.3 ,
+.Fx 2.0 ,
+and
+.Fx 5.3 ,
+respectively.
diff --git a/lib/msun/man/cos.3 b/lib/msun/man/cos.3
new file mode 100644
index 0000000..38d8ccf
--- /dev/null
+++ b/lib/msun/man/cos.3
@@ -0,0 +1,83 @@
+.\" Copyright (c) 1991 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce 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.
+.\"
+.\" from: @(#)cos.3 5.1 (Berkeley) 5/2/91
+.\" $FreeBSD$
+.\"
+.Dd May 2, 1991
+.Dt COS 3
+.Os
+.Sh NAME
+.Nm cos ,
+.Nm cosf
+.Nd cosine functions
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In math.h
+.Ft double
+.Fn cos "double x"
+.Ft float
+.Fn cosf "float x"
+.Sh DESCRIPTION
+The
+.Fn cos
+and the
+.Fn cosf
+functions compute the cosine of
+.Fa x
+(measured in radians).
+A large magnitude argument may yield a result with little or no
+significance.
+For a discussion of error due to roundoff, see
+.Xr math 3 .
+.Sh RETURN VALUES
+The
+.Fn cos
+and the
+.Fn cosf
+functions return the cosine value.
+.Sh SEE ALSO
+.Xr acos 3 ,
+.Xr asin 3 ,
+.Xr atan 3 ,
+.Xr atan2 3 ,
+.Xr cosh 3 ,
+.Xr math 3 ,
+.Xr sin 3 ,
+.Xr sinh 3 ,
+.Xr tan 3 ,
+.Xr tanh 3
+.Sh STANDARDS
+The
+.Fn cos
+function conforms to
+.St -isoC .
diff --git a/lib/msun/man/cosh.3 b/lib/msun/man/cosh.3
new file mode 100644
index 0000000..74744d4
--- /dev/null
+++ b/lib/msun/man/cosh.3
@@ -0,0 +1,72 @@
+.\" Copyright (c) 1989, 1991 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce 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.
+.\"
+.\" from: @(#)cosh.3 5.1 (Berkeley) 5/2/91
+.\" $FreeBSD$
+.\"
+.Dd January 14, 2005
+.Dt COSH 3
+.Os
+.Sh NAME
+.Nm cosh ,
+.Nm coshf
+.Nd hyperbolic cosine functions
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In math.h
+.Ft double
+.Fn cosh "double x"
+.Ft float
+.Fn coshf "float x"
+.Sh DESCRIPTION
+The
+.Fn cosh
+and the
+.Fn coshf
+functions compute the hyperbolic cosine of
+.Fa x .
+.Sh SEE ALSO
+.Xr acos 3 ,
+.Xr asin 3 ,
+.Xr atan 3 ,
+.Xr atan2 3 ,
+.Xr cos 3 ,
+.Xr math 3 ,
+.Xr sin 3 ,
+.Xr sinh 3 ,
+.Xr tan 3 ,
+.Xr tanh 3
+.Sh STANDARDS
+The
+.Fn cosh
+function conforms to
+.St -isoC .
diff --git a/lib/msun/man/erf.3 b/lib/msun/man/erf.3
new file mode 100644
index 0000000..0ebb6a7
--- /dev/null
+++ b/lib/msun/man/erf.3
@@ -0,0 +1,97 @@
+.\" Copyright (c) 1985, 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.
+.\" 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.
+.\"
+.\" from: @(#)erf.3 6.4 (Berkeley) 4/20/91
+.\" $FreeBSD$
+.\"
+.Dd April 20, 1991
+.Dt ERF 3
+.Os
+.Sh NAME
+.Nm erf ,
+.Nm erff ,
+.Nm erfc ,
+.Nm erfcf
+.Nd error function operators
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In math.h
+.Ft double
+.Fn erf "double x"
+.Ft float
+.Fn erff "float x"
+.Ft double
+.Fn erfc "double x"
+.Ft float
+.Fn erfcf "float x"
+.Sh DESCRIPTION
+These functions calculate the error function of
+.Fa x .
+.Pp
+The
+.Fn erf
+and the
+.Fn erff
+functions calculate the error function of x; where
+.Bd -ragged -offset indent
+.if n \{\
+erf(x) = 2/sqrt(pi)\(**\|integral from 0 to x of exp(\-t\(**t) dt.
+\}
+.if t \{\
+erf\|(x) :=
+(2/\(sr\(*p)\|\(is\d\s8\z0\s10\u\u\s8x\s10\d\|exp(\-t\u\s82\s10\d)\|dt.
+\}
+.Ed
+.Pp
+The
+.Fn erfc
+and the
+.Fn erfcf
+functions calculate the complementary error function of
+.Fa x ;
+that is
+.Fn erfc
+subtracts the result of the error function
+.Fn erf x
+from 1.0.
+This is useful, since for large
+.Fa x
+places disappear.
+.Sh SEE ALSO
+.Xr math 3
+.Sh HISTORY
+The
+.Fn erf
+and
+.Fn erfc
+functions appeared in
+.Bx 4.3 .
diff --git a/lib/msun/man/exp.3 b/lib/msun/man/exp.3
new file mode 100644
index 0000000..0fb5878
--- /dev/null
+++ b/lib/msun/man/exp.3
@@ -0,0 +1,236 @@
+.\" Copyright (c) 1985, 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.
+.\" 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.
+.\"
+.\" from: @(#)exp.3 6.12 (Berkeley) 7/31/91
+.\" $FreeBSD$
+.\"
+.Dd April 5, 2005
+.Dt EXP 3
+.Os
+.Sh NAME
+.Nm exp ,
+.Nm expf ,
+.\" The sorting error is intentional. exp and expf should be adjacent.
+.Nm exp2 ,
+.Nm exp2f ,
+.Nm expm1 ,
+.Nm expm1f ,
+.Nm log ,
+.Nm logf ,
+.Nm log10 ,
+.Nm log10f ,
+.Nm log1p ,
+.Nm log1pf ,
+.Nm pow ,
+.Nm powf
+.Nd exponential, logarithm, power functions
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In math.h
+.Ft double
+.Fn exp "double x"
+.Ft float
+.Fn expf "float x"
+.Ft double
+.Fn exp2 "double x"
+.Ft float
+.Fn exp2f "float x"
+.Ft double
+.Fn expm1 "double x"
+.Ft float
+.Fn expm1f "float x"
+.Ft double
+.Fn log "double x"
+.Ft float
+.Fn logf "float x"
+.Ft double
+.Fn log10 "double x"
+.Ft float
+.Fn log10f "float x"
+.Ft double
+.Fn log1p "double x"
+.Ft float
+.Fn log1pf "float x"
+.Ft double
+.Fn pow "double x" "double y"
+.Ft float
+.Fn powf "float x" "float y"
+.Sh DESCRIPTION
+The
+.Fn exp
+and the
+.Fn expf
+functions compute the base
+.Ms e
+exponential value of the given argument
+.Fa x .
+.Pp
+The
+.Fn exp2
+and the
+.Fn exp2f
+functions compute the base 2 exponential of the given argument
+.Fa x .
+.Pp
+The
+.Fn expm1
+and the
+.Fn expm1f
+functions compute the value exp(x)\-1 accurately even for tiny argument
+.Fa x .
+.Pp
+The
+.Fn log
+and the
+.Fn logf
+functions compute the value of the natural logarithm of argument
+.Fa x .
+.Pp
+The
+.Fn log10
+and the
+.Fn log10f
+functions compute the value of the logarithm of argument
+.Fa x
+to base 10.
+.Pp
+The
+.Fn log1p
+and the
+.Fn log1pf
+functions compute
+the value of log(1+x) accurately even for tiny argument
+.Fa x .
+.Pp
+The
+.Fn pow
+and the
+.Fn powf
+functions compute the value
+of
+.Ar x
+to the exponent
+.Ar y .
+.Sh ERROR (due to Roundoff etc.)
+The values of
+.Fn exp 0 ,
+.Fn expm1 0 ,
+.Fn exp2 integer ,
+and
+.Fn pow integer integer
+are exact provided that they are representable.
+.\" XXX Is this really true for pow()?
+Otherwise the error in these functions is generally below one
+.Em ulp .
+.Sh RETURN VALUES
+These functions will return the appropriate computation unless an error
+occurs or an argument is out of range.
+The functions
+.Fn pow x y
+and
+.Fn powf x y
+raise an invalid exception and return an \*(Na if
+.Fa x
+< 0 and
+.Fa y
+is not an integer.
+An attempt to take the logarithm of \*(Pm0 will result in
+a divide-by-zero exception, and an infinity will be returned.
+An attempt to take the logarithm of a negative number will
+result in an invalid exception, and an \*(Na will be generated.
+.Sh NOTES
+The functions exp(x)\-1 and log(1+x) are called
+expm1 and logp1 in
+.Tn BASIC
+on the Hewlett\-Packard
+.Tn HP Ns \-71B
+and
+.Tn APPLE
+Macintosh,
+.Tn EXP1
+and
+.Tn LN1
+in Pascal, exp1 and log1 in C
+on
+.Tn APPLE
+Macintoshes, where they have been provided to make
+sure financial calculations of ((1+x)**n\-1)/x, namely
+expm1(n\(**log1p(x))/x, will be accurate when x is tiny.
+They also provide accurate inverse hyperbolic functions.
+.Pp
+The function
+.Fn pow x 0
+returns x**0 = 1 for all x including x = 0, \*(If, and \*(Na .
+Previous implementations of pow may
+have defined x**0 to be undefined in some or all of these
+cases.
+Here are reasons for returning x**0 = 1 always:
+.Bl -enum -width indent
+.It
+Any program that already tests whether x is zero (or
+infinite or \*(Na) before computing x**0 cannot care
+whether 0**0 = 1 or not.
+Any program that depends
+upon 0**0 to be invalid is dubious anyway since that
+expression's meaning and, if invalid, its consequences
+vary from one computer system to another.
+.It
+Some Algebra texts (e.g.\& Sigler's) define x**0 = 1 for
+all x, including x = 0.
+This is compatible with the convention that accepts a[0]
+as the value of polynomial
+.Bd -literal -offset indent
+p(x) = a[0]\(**x**0 + a[1]\(**x**1 + a[2]\(**x**2 +...+ a[n]\(**x**n
+.Ed
+.Pp
+at x = 0 rather than reject a[0]\(**0**0 as invalid.
+.It
+Analysts will accept 0**0 = 1 despite that x**y can
+approach anything or nothing as x and y approach 0
+independently.
+The reason for setting 0**0 = 1 anyway is this:
+.Bd -ragged -offset indent
+If x(z) and y(z) are
+.Em any
+functions analytic (expandable
+in power series) in z around z = 0, and if there
+x(0) = y(0) = 0, then x(z)**y(z) \(-> 1 as z \(-> 0.
+.Ed
+.It
+If 0**0 = 1, then
+\*(If**0 = 1/0**0 = 1 too; and
+then \*(Na**0 = 1 too because x**0 = 1 for all finite
+and infinite x, i.e., independently of x.
+.El
+.Sh SEE ALSO
+.Xr fenv 3 ,
+.Xr math 3
diff --git a/lib/msun/man/fabs.3 b/lib/msun/man/fabs.3
new file mode 100644
index 0000000..9d93484
--- /dev/null
+++ b/lib/msun/man/fabs.3
@@ -0,0 +1,87 @@
+.\" Copyright (c) 1991 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" @(#)fabs.3 5.1 (Berkeley) 5/2/91
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce 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.
+.\"
+.\" from: @(#)fabs.3 5.1 (Berkeley) 5/2/91
+.\" $FreeBSD$
+.\"
+.Dd October 25, 2003
+.Dt FABS 3
+.Os
+.Sh NAME
+.Nm fabs ,
+.Nm fabsf ,
+.Nm fabsl
+.Nd floating-point absolute value functions
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In math.h
+.Ft double
+.Fn fabs "double x"
+.Ft float
+.Fn fabsf "float x"
+.Ft long double
+.Fn fabsl "long double x"
+.Sh DESCRIPTION
+The
+.Fn fabs ,
+.Fn fabsf
+and
+.Fn fabsl
+functions compute the absolute value of a floating-point number
+.Fa x .
+.Sh RETURN VALUES
+The
+.Fn fabs ,
+.Fn fabsf
+and
+.Fn fabsl
+functions return the absolute value of
+.Fa x .
+.Sh SEE ALSO
+.Xr abs 3 ,
+.Xr ceil 3 ,
+.Xr floor 3 ,
+.Xr ieee 3 ,
+.Xr math 3 ,
+.Xr rint 3
+.Sh STANDARDS
+The
+.Fn fabs
+function conforms to
+.St -isoC .
+The
+.Fn fabsf
+and
+.Fn fabsl
+functions conform to
+.St -isoC-99 .
diff --git a/lib/msun/man/fdim.3 b/lib/msun/man/fdim.3
new file mode 100644
index 0000000..2de2e32
--- /dev/null
+++ b/lib/msun/man/fdim.3
@@ -0,0 +1,86 @@
+.\" 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$
+.\"
+.Dd June 29, 2004
+.Dt FDIM 3
+.Os
+.Sh NAME
+.Nm fdim ,
+.Nm fdimf ,
+.Nm fdiml
+.Nd positive difference functions
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In math.h
+.Ft double
+.Fn fdim "double x" "double y"
+.Ft float
+.Fn fdimf "float x" "float y"
+.Ft long double
+.Fn fdiml "long double x" "long double y"
+.Sh DESCRIPTION
+The
+.Fn fdim ,
+.Fn fdimf ,
+and
+.Fn fdiml
+functions return the positive difference between
+.Fa x
+and
+.Fa y .
+That is, if
+.Fa x\- Ns Fa y
+is positive, then
+.Fa x\- Ns Fa y
+is returned.
+If either
+.Fa x
+or
+.Fa y
+is an \*(Na, then an \*(Na is returned.
+Otherwise, the result is
+.Li +0.0 .
+.Pp
+Overflow or underflow may occur iff the exact result is not
+representable in the return type.
+No other exceptions are raised.
+.Sh SEE ALSO
+.Xr fabs 3 ,
+.Xr fmax 3 ,
+.Xr fmin 3 ,
+.Xr math 3
+.Sh STANDARDS
+The
+.Fn fdim ,
+.Fn fdimf ,
+and
+.Fn fdiml
+functions conform to
+.St -isoC-99 .
+.Sh HISTORY
+These routines first appeared in
+.Fx 5.3 .
diff --git a/lib/msun/man/feclearexcept.3 b/lib/msun/man/feclearexcept.3
new file mode 100644
index 0000000..217642c
--- /dev/null
+++ b/lib/msun/man/feclearexcept.3
@@ -0,0 +1,139 @@
+.\" 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$
+.\"
+.Dd May 8, 2004
+.Dt FECLEAREXCEPT 3
+.Os
+.Sh NAME
+.Nm feclearexcept ,
+.Nm fegetexceptflag ,
+.Nm feraiseexcept ,
+.Nm fesetexceptflag ,
+.Nm fetestexcept
+.Nd floating-point exception flag manipulation
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In fenv.h
+.Fd "#pragma STDC FENV_ACCESS ON"
+.Ft int
+.Fn feclearexcept "int excepts"
+.Ft int
+.Fn fegetexceptflag "fexcept_t *flagp" "int excepts"
+.Ft int
+.Fn feraiseexcept "int excepts"
+.Ft int
+.Fn fesetexceptflag "const fexcept_t *flagp" "int excepts"
+.Ft int
+.Fn fetestexcept "int excepts"
+.Sh DESCRIPTION
+The
+.Fn feclearexcept
+routine clears the floating-point exception flags specified by
+.Fa excepts ,
+whereas
+.Fn feraiseexcept
+raises the specified exceptions.
+Raising an exception causes the corresponding flag to be set,
+and a
+.Dv SIGFPE
+is delivered to the process if the exception is unmasked.
+.Pp
+The
+.Fn fetestexcept
+function determines which flags are currently set, of those specified by
+.Fa excepts .
+.Pp
+The
+.Fn fegetexceptflag
+function stores the state of the exception flags specified in
+.Fa excepts
+in the opaque object pointed to by
+.Fa flagp .
+Similarly,
+.Fn fesetexceptflag
+changes the specified exception flags to reflect the state stored in
+the object pointed to by
+.Fa flagp .
+Note that the flags restored with
+.Fn fesetexceptflag
+must be a (not necessarily proper) subset of the flags recorded by
+a prior call to
+.Fn fegetexceptflag .
+.Pp
+For all of these functions, the possible types of exceptions
+include those described in
+.Xr fenv 3 .
+Some architectures may define other types of floating-point exceptions.
+.Sh IMPLEMENTATION NOTES
+On some architectures, raising an overflow or underflow exception
+also causes an inexact exception to be raised.
+In these cases, the overflow or underflow will be raised first.
+.Pp
+The
+.Fn fegetexceptflag
+and
+.Fn fesetexceptflag
+routines are preferred to
+.Fn fetestexcept
+and
+.Fn feraiseexcept ,
+respectively, for saving and restoring exception flags.
+The latter do not re-raise exceptions and may preserve
+architecture-specific information such as addresses where
+exceptions occurred.
+.Sh RETURN VALUES
+The
+.Fn feclearexcept ,
+.Fn fegetexceptflag ,
+.Fn feraiseexcept ,
+and
+.Fn fesetexceptflag
+functions return 0 upon success, and non-zero otherwise.
+The
+.Fn fetestexcept
+function returns the bitwise OR of the values of the current exception
+flags that were requested.
+.Sh SEE ALSO
+.Xr sigaction 2 ,
+.Xr feholdexcept 3 ,
+.Xr fenv 3 ,
+.Xr feupdateenv 3 ,
+.Xr fpgetsticky 3 ,
+.Xr fpresetsticky 3
+.Sh STANDARDS
+The
+.Fn feclearexcept ,
+.Fn fegetexceptflag ,
+.Fn feraiseexcept ,
+.Fn fesetexceptflag ,
+and
+.Fn fetestexcept
+routines conform to
+.St -isoC-99 .
+.Sh HISTORY
+These functions first appeared in
+.Fx 5.3 .
diff --git a/lib/msun/man/feenableexcept.3 b/lib/msun/man/feenableexcept.3
new file mode 100644
index 0000000..40bb892
--- /dev/null
+++ b/lib/msun/man/feenableexcept.3
@@ -0,0 +1,98 @@
+.\" 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$
+.\"
+.Dd March 16, 2005
+.Dt FEENABLEEXCEPT 3
+.Os
+.Sh NAME
+.Nm feenableexcept ,
+.Nm fedisableexcept ,
+.Nm fegetexcept
+.Nd floating-point exception masking
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In fenv.h
+.Fd "#pragma STDC FENV_ACCESS ON"
+.Ft int
+.Fn feenableexcept "int excepts"
+.Ft int
+.Fn fedisableexcept "int excepts"
+.Ft int
+.Fn fegetexcept "void"
+.Sh DESCRIPTION
+The
+.Fn feenableexcept
+and
+.Fn fedisableexcept
+functions
+unmask and mask (respectively) exceptions specified in
+.Fa excepts .
+The
+.Fn fegetexcept
+function
+returns the current exception mask.
+All exceptions are masked by default.
+.Pp
+Floating-point operations that produce unmasked exceptions will trap, and a
+.Dv SIGFPE
+will be delivered to the process.
+By installing a signal handler for
+.Dv SIGFPE ,
+applications can take appropriate action immediately without
+testing the exception flags after every operation.
+Note that the trap may not be immediate, but it should occur
+before the next floating-point instruction is executed.
+.Pp
+For all of these functions, the possible types of exceptions
+include those described in
+.Xr fenv 3 .
+Some architectures may define other types of floating-point exceptions.
+.Sh RETURN VALUES
+The
+.Fn feenableexcept ,
+.Fn fedisableexcept ,
+and
+.Fn fegetexcept
+functions return a bitmap of the exceptions that were unmasked
+prior to the call.
+.Sh SEE ALSO
+.Xr sigaction 2 ,
+.Xr feclearexcept 3 ,
+.Xr feholdexcept 3 ,
+.Xr fenv 3 ,
+.Xr feupdateenv 3
+.Sh BUGS
+Functions in the standard library may trigger exceptions multiple
+times as a result of intermediate computations;
+however, they generally do not trigger spurious exceptions.
+.Pp
+No interface is provided to permit exceptions to be handled in
+nontrivial ways.
+There is no uniform way for an exception handler to access
+information about the exception-causing instruction, or
+to determine whether that instruction should be reexecuted
+after returning from the handler.
diff --git a/lib/msun/man/fegetenv.3 b/lib/msun/man/fegetenv.3
new file mode 100644
index 0000000..c99663e
--- /dev/null
+++ b/lib/msun/man/fegetenv.3
@@ -0,0 +1,113 @@
+.\" 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$
+.\"
+.Dd May 8, 2004
+.Dt FEGETENV 3
+.Os
+.Sh NAME
+.Nm fegetenv ,
+.Nm feholdexcept ,
+.Nm fesetenv ,
+.Nm feupdateenv
+.Nd floating-point environment save and restore
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In fenv.h
+.Fd "#pragma STDC FENV_ACCESS ON"
+.Ft int
+.Fn fegetenv "fenv_t *envp"
+.Ft int
+.Fn feholdexcept "fenv_t *envp"
+.Ft int
+.Fn fesetenv "const fenv_t *envp"
+.Ft int
+.Fn feupdateenv "const fenv_t *envp"
+.Sh DESCRIPTION
+The floating-point environment includes exception flags and masks, the
+current rounding mode, and other architecture-specific settings.
+However, it does not include the floating-point register file.
+.Pp
+The
+.Fn fegetenv
+function stores the current floating-point environment in the object
+pointed to by
+.Fa envp ,
+whereas
+.Fn feholdexcept
+saves the current environment, then clears all exception flags
+and masks all floating-point exceptions.
+.Pp
+The
+.Fn fesetenv
+function restores a previously saved environment.
+The
+.Fn feupdateenv
+function restores a saved environment as well, but it also
+raises any exceptions that were set in the environment it
+replaces.
+.Pp
+The
+.Fn feholdexcept
+function is often used with
+.Fn feupdateenv
+or
+.Fn fesetenv
+to suppress spurious exceptions that occur as a result of
+intermediate computations.
+An example in
+.Xr fenv 3
+demonstrates how to do this.
+.Sh RETURN VALUES
+The
+.Fn fegetenv ,
+.Fn feholdexcept ,
+.Fn fesetenv ,
+and
+.Fn feupdateenv
+functions return 0 if they succeed, and non-zero otherwise.
+.Sh SEE ALSO
+.Xr feclearexcept 3 ,
+.Xr fenv 3 ,
+.Xr feraiseexcept 3 ,
+.Xr fesetenv 3 ,
+.Xr fetestexcept 3 ,
+.Xr fpgetmask 3 ,
+.Xr fpgetprec 3 ,
+.Xr fpsetmask 3 ,
+.Xr fpsetprec 3
+.Sh STANDARDS
+The
+.Fn fegetenv ,
+.Fn feholdexcept ,
+.Fn fesetenv ,
+and
+.Fn feupdateenv
+functions conform to
+.St -isoC-99 .
+.Sh HISTORY
+These routines first appeared in
+.Fx 5.3 .
diff --git a/lib/msun/man/fegetround.3 b/lib/msun/man/fegetround.3
new file mode 100644
index 0000000..c6cd417
--- /dev/null
+++ b/lib/msun/man/fegetround.3
@@ -0,0 +1,83 @@
+.\" 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$
+.\"
+.Dd May 8, 2004
+.Dt FEGETROUND 3
+.Os
+.Sh NAME
+.Nm fegetround ,
+.Nm fesetround
+.Nd floating-point rounding control
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In fenv.h
+.Fd "#pragma STDC FENV_ACCESS ON"
+.Ft int
+.Fn fegetround void
+.Ft int
+.Fn fesetround "int round"
+.Sh DESCRIPTION
+The
+.Fn fegetround
+function determines the current floating-point rounding mode,
+and the
+.Fn fesetround
+function sets the current rounding mode to
+.Fa round .
+The rounding mode is one of
+.Dv FE_TONEAREST , FE_DOWNWARD , FE_UPWARD ,
+or
+.Dv FE_TOWARDZERO ,
+as described in
+.Xr fenv 3 .
+.Sh RETURN VALUES
+The
+.Fn fegetround
+routine returns the current rounding mode.
+The
+.Fn fesetround
+function returns 0 on success and non-zero otherwise;
+however, the present implementation always succeeds.
+.Sh SEE ALSO
+.Xr fenv 3 ,
+.Xr fpgetround 3 ,
+.Xr fpsetround 3
+.Sh STANDARDS
+The
+.Fn fegetround
+and
+.Fn fesetround
+functions conform to
+.St -isoC-99 .
+.Sh HISTORY
+These routines first appeared in
+.Fx 5.3 .
+They supersede the non-standard
+.Xr fpgetround 3
+and
+.Xr fpsetround 3
+functions.
diff --git a/lib/msun/man/fenv.3 b/lib/msun/man/fenv.3
new file mode 100644
index 0000000..3450153
--- /dev/null
+++ b/lib/msun/man/fenv.3
@@ -0,0 +1,289 @@
+.\" 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$
+.\"
+.Dd March 16, 2005
+.Dt FENV 3
+.Os
+.Sh NAME
+.Nm feclearexcept ,
+.Nm fegetexceptflag ,
+.Nm feraiseexcept ,
+.Nm fesetexceptflag ,
+.Nm fetestexcept ,
+.Nm fegetround ,
+.Nm fesetround ,
+.Nm fegetenv ,
+.Nm feholdexcept ,
+.Nm fesetenv ,
+.Nm feupdateenv ,
+.Nm feenableexcept ,
+.Nm fedisableexcept ,
+.Nm fegetexcept
+.Nd floating-point environment control
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In fenv.h
+.Fd "#pragma STDC FENV_ACCESS ON"
+.Ft int
+.Fn feclearexcept "int excepts"
+.Ft int
+.Fn fegetexceptflag "fexcept_t *flagp" "int excepts"
+.Ft int
+.Fn feraiseexcept "int excepts"
+.Ft int
+.Fn fesetexceptflag "const fexcept_t *flagp" "int excepts"
+.Ft int
+.Fn fetestexcept "int excepts"
+.Ft int
+.Fn fegetround void
+.Ft int
+.Fn fesetround "int round"
+.Ft int
+.Fn fegetenv "fenv_t *envp"
+.Ft int
+.Fn feholdexcept "fenv_t *envp"
+.Ft int
+.Fn fesetenv "const fenv_t *envp"
+.Ft int
+.Fn feupdateenv "const fenv_t *envp"
+.Ft int
+.Fn feenableexcept "int excepts"
+.Ft int
+.Fn fedisableexcept "int excepts"
+.Ft int
+.Fn fegetexcept void
+.Sh DESCRIPTION
+The
+.In fenv.h
+routines manipulate the floating-point environment,
+which includes the exception flags and rounding modes defined in
+.St -ieee754 .
+.Ss Exceptions
+Exception flags are set as side-effects of floating-point arithmetic
+operations and math library routines, and they remain set until
+explicitly cleared.
+The following macros expand to bit flags of type
+.Vt int
+representing the five standard floating-point exceptions.
+.Bl -tag -width ".Dv FE_DIVBYZERO"
+.It Dv FE_DIVBYZERO
+A divide-by-zero exception occurs when the program attempts to
+divide a finite non-zero number by zero.
+.It Dv FE_INEXACT
+An inexact exception is raised whenever there is a loss of precision
+due to rounding.
+.It Dv FE_INVALID
+Invalid operation exceptions occur when a program attempts to
+perform calculations for which there is no reasonable representable
+answer.
+For instance, subtraction of infinities, division of zero by zero,
+ordered comparison involving \*(Nas, and taking the square root of a
+negative number are all invalid operations.
+.It Dv FE_OVERFLOW
+An overflow exception occurs when the magnitude of the result of a
+computation is too large to fit in the destination type.
+.It Dv FE_UNDERFLOW
+Underflow occurs when the result of a computation is too close to zero
+to be represented as a non-zero value in the destination type.
+.El
+.Pp
+Additionally, the
+.Dv FE_ALL_EXCEPT
+macro expands to the bitwise OR of the above flags and any
+architecture-specific flags.
+Combinations of these flags are passed to the
+.Fn feclearexcept ,
+.Fn fegetexceptflag ,
+.Fn feraiseexcept ,
+.Fn fesetexceptflag ,
+and
+.Fn fetestexcept
+functions to clear, save, raise, restore, and examine the
+processor's floating-point exception flags, respectively.
+.Pp
+Exceptions may be
+.Em unmasked
+with
+.Fn feenableexcept
+and masked with
+.Fn fedisableexcept .
+Unmasked exceptions cause a trap when they are produced, and
+all exceptions are masked by default.
+The current mask can be tested with
+.Fn fegetexcept .
+.Ss Rounding Modes
+.St -ieee754
+specifies four rounding modes.
+These modes control the direction in which results are rounded
+from their exact values in order to fit them into binary
+floating-point variables.
+The four modes correspond with the following symbolic constants.
+.Bl -tag -width ".Dv FE_TOWARDZERO"
+.It Dv FE_TONEAREST
+Results are rounded to the closest representable value.
+If the exact result is exactly half way between two representable
+values, the value whose last binary digit is even (zero) is chosen.
+This is the default mode.
+.It Dv FE_DOWNWARD
+Results are rounded towards negative \*[If].
+.It Dv FE_UPWARD
+Results are rounded towards positive \*[If].
+.It Dv FE_TOWARDZERO
+Results are rounded towards zero.
+.El
+.Pp
+The
+.Fn fegetround
+and
+.Fn fesetround
+functions query and set the rounding mode.
+.Ss Environment Control
+The
+.Fn fegetenv
+and
+.Fn fesetenv
+functions save and restore the floating-point environment,
+which includes exception flags, the current exception mask,
+the rounding mode, and possibly other implementation-specific
+state.
+The
+.Fn feholdexcept
+function behaves like
+.Fn fegetenv ,
+but with the additional effect of clearing the exception flags and
+installing a
+.Em non-stop
+mode.
+In non-stop mode, floating-point operations will set exception flags
+as usual, but no
+.Dv SIGFPE
+signals will be generated as a result.
+Non-stop mode is the default, but it may be altered by
+non-standard mechanisms.
+.\" XXX Mention fe[gs]etmask() here after the interface is finalized
+.\" XXX and ready to be officially documented.
+The
+.Fn feupdateenv
+function restores a saved environment similarly to
+.Fn fesetenv ,
+but it also re-raises any floating-point exceptions from the old
+environment.
+.Pp
+The macro
+.Dv FE_DFL_ENV
+expands to a pointer to the default environment.
+.Sh CAVEATS
+The FENV_ACCESS pragma can be enabled with
+.Dl "#pragma STDC FENV_ACCESS ON"
+and disabled with the
+.Dl "#pragma STDC FENV_ACCESS OFF"
+directive.
+This lexically-scoped annotation tells the compiler that the program
+may access the floating-point environment, so optimizations that would
+violate strict IEEE-754 semantics are disabled.
+If execution reaches a block of code for which
+.Dv FENV_ACCESS
+is off, the floating-point environment will become undefined.
+.Sh EXAMPLES
+The following routine computes the square root function.
+It explicitly raises an invalid exception on appropriate inputs using
+.Fn feraiseexcept .
+It also defers inexact exceptions while it computes intermediate
+values, and then it allows an inexact exception to be raised only if
+the final answer is inexact.
+.Bd -literal -offset indent
+#pragma STDC FENV_ACCESS ON
+double sqrt(double n) {
+ double x = 1.0;
+ fenv_t env;
+
+ if (isnan(n) || n < 0.0) {
+ feraiseexcept(FE_INVALID);
+ return (NAN);
+ }
+ if (isinf(n) || n == 0.0)
+ return (n);
+ feholdexcept(&env);
+ while (fabs((x * x) - n) > DBL_EPSILON * 2 * x)
+ x = (x / 2) + (n / (2 * x));
+ if (x * x == n)
+ feclearexcept(FE_INEXACT);
+ feupdateenv(&env);
+ return (x);
+}
+.Ed
+.Sh SEE ALSO
+.Xr cc 1 ,
+.Xr feclearexcept 3 ,
+.Xr fedisableexcept 3 ,
+.Xr feenableexcept 3 ,
+.Xr fegetenv 3 ,
+.Xr fegetexcept 3 ,
+.Xr fegetexceptflag 3 ,
+.Xr fegetround 3 ,
+.Xr feholdexcept 3 ,
+.Xr feraiseexcept 3 ,
+.Xr fesetenv 3 ,
+.Xr fesetexceptflag 3 ,
+.Xr fesetround 3 ,
+.Xr fetestexcept 3 ,
+.Xr feupdateenv 3 ,
+.Xr fpgetprec 3 ,
+.Xr fpsetprec 3
+.Sh STANDARDS
+Except as noted below,
+.In fenv.h
+conforms to
+.St -isoC-99 .
+The
+.Fn feenableexcept ,
+.Fn fedisableexcept ,
+and
+.Fn fegetexcept
+routines are extensions.
+.Sh HISTORY
+The
+.In fenv.h
+header first appeared in
+.Fx 5.3 .
+It supersedes the non-standard routines defined in
+.In ieeefp.h
+and documented in
+.Xr fpgetround 3 .
+.Sh BUGS
+The
+.Dv FENV_ACCESS
+pragma is unimplemented in the system compiler.
+However, non-constant expressions generally produce the correct
+side-effects at low optimization levels.
+.Pp
+On the Alpha platform,
+.Xr cc 1
+must be passed the
+.Fl mieee-with-inexact mfp-rounding-mode=d
+options in order to generate code that has the standard
+side-effects and uses the specified rounding modes.
diff --git a/lib/msun/man/floor.3 b/lib/msun/man/floor.3
new file mode 100644
index 0000000..ed46689
--- /dev/null
+++ b/lib/msun/man/floor.3
@@ -0,0 +1,82 @@
+.\" Copyright (c) 1985, 1991 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce 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.
+.\"
+.\" from: @(#)floor.3 6.5 (Berkeley) 4/19/91
+.\" $FreeBSD$
+.\"
+.Dd January 13, 2005
+.Dt FLOOR 3
+.Os
+.Sh NAME
+.Nm floor ,
+.Nm floorf ,
+.Nm floorl
+.Nd largest integral value less than or equal to x
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In math.h
+.Ft double
+.Fn floor "double x"
+.Ft float
+.Fn floorf "float x"
+.Ft "long double"
+.Fn floorl "long double x"
+.Sh DESCRIPTION
+The
+.Fn floor ,
+.Fn floorf
+and
+.Fn floorl
+functions return the largest integral value
+less than or equal to
+.Fa x ,
+expressed as a floating-point number.
+.Sh SEE ALSO
+.Xr abs 3 ,
+.Xr ceil 3 ,
+.Xr fabs 3 ,
+.Xr ieee 3 ,
+.Xr math 3 ,
+.Xr rint 3 ,
+.Xr round 3 ,
+.Xr trunc 3
+.Sh STANDARDS
+The
+.Fn floor
+function conforms to
+.St -isoC .
+The
+.Fn floorf
+and
+.Fn floorl
+functions conform to
+.St -isoC-99 .
diff --git a/lib/msun/man/fma.3 b/lib/msun/man/fma.3
new file mode 100644
index 0000000..ce3086d
--- /dev/null
+++ b/lib/msun/man/fma.3
@@ -0,0 +1,116 @@
+.\" 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd January 22, 2005
+.Dt FMA 3
+.Os
+.Sh NAME
+.Nm fma ,
+.Nm fmaf ,
+.Nm fmal
+.Nd fused multiply-add
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In math.h
+.Ft double
+.Fn fma "double x" "double y" "double z"
+.Ft float
+.Fn fmaf "float x" "float y" "float z"
+.Ft long double
+.Fn fmal "long double x" "long double y" "long double z"
+.Sh DESCRIPTION
+The
+.Fn fma ,
+.Fn fmaf ,
+and
+.Fn fmal
+functions return
+.No "(x * y) + z" ,
+computed with only one rounding error.
+Using the ordinary multiplication and addition operators, by contrast,
+results in two roundings: one for the intermediate product and one for
+the final result.
+.Pp
+For instance, the expression
+.No "1.2e100 * 2.0e208 - 1.4e308"
+produces \*(If due to overflow in the intermediate product, whereas
+.No "fma(1.2e100, 2.0e208, -1.4e308)"
+returns approximately 1.0e308.
+.Pp
+The fused multiply-add operation is often used to improve the
+accuracy of calculations such as dot products.
+It may also be used to improve performance on machines that implement
+it natively.
+The macros
+.Dv FP_FAST_FMA ,
+.Dv FP_FAST_FMAF
+and
+.Dv FP_FAST_FMAL
+may be defined in
+.In math.h
+to indicate that
+.Fn fma ,
+.Fn fmaf ,
+and
+.Fn fmal
+(respectively) have comparable or faster speed than a multiply
+operation followed by an add operation.
+.Sh IMPLEMENTATION NOTES
+In general, these routines will behave as one would expect if
+.No "x * y + z"
+were computed with unbounded precision and range,
+then rounded to the precision of the return type.
+However, on some platforms, if
+.Fa z
+is \*(Na, these functions may not raise an exception even
+when the computation of
+.No "x * y"
+would have otherwise generated an invalid exception.
+.Sh SEE ALSO
+.Xr fenv 3 ,
+.Xr math 3
+.Sh STANDARDS
+The
+.Fn fma ,
+.Fn fmaf ,
+and
+.Fn fmal
+functions conform to
+.St -isoC-99 .
+A fused multiply-add operation with virtually identical
+characteristics appears in IEEE draft standard 754R.
+.Sh HISTORY
+The
+.Fn fma
+and
+.Fn fmaf
+routines first appeared in
+.Fx 5.4 ,
+and
+.Fn fmal
+appeared in
+.Fx 6.0 .
diff --git a/lib/msun/man/fmax.3 b/lib/msun/man/fmax.3
new file mode 100644
index 0000000..71cb7d9
--- /dev/null
+++ b/lib/msun/man/fmax.3
@@ -0,0 +1,97 @@
+.\" 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$
+.\"
+.Dd June 29, 2004
+.Dt FMAX 3
+.Os
+.Sh NAME
+.Nm fmax ,
+.Nm fmaxf ,
+.Nm fmaxl ,
+.Nm fmin ,
+.Nm fminf ,
+.Nm fminl
+.Nd floating-point maximum and minimum functions
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In math.h
+.Ft double
+.Fn fmax "double x" "double y"
+.Ft float
+.Fn fmaxf "float x" "float y"
+.Ft "long double"
+.Fn fmaxl "long double x" "long double y"
+.Ft double
+.Fn fmin "double x" "double y"
+.Ft float
+.Fn fminf "float x" "float y"
+.Ft "long double"
+.Fn fminl "long double x" "long double y"
+.Sh DESCRIPTION
+The
+.Fn fmax ,
+.Fn fmaxf ,
+and
+.Fn fmaxl
+functions return the larger of
+.Fa x
+and
+.Fa y ,
+and likewise, the
+.Fn fmin ,
+.Fn fminf ,
+and
+.Fn fminl
+functions return the smaller of
+.Fa x
+and
+.Fa y .
+They treat
+.Li +0.0
+as being larger than
+.Li -0.0 .
+If one argument is an \*(Na, then the other argument is returned.
+If both arguments are \*(Nas, then the result is an \*(Na.
+These routines do not raise any floating-point exceptions.
+.Sh SEE ALSO
+.Xr fabs 3 ,
+.Xr fdim 3 ,
+.Xr math 3
+.Sh STANDARDS
+The
+.Fn fmax ,
+.Fn fmaxf ,
+.Fn fmaxl ,
+.Fn fmin ,
+.Fn fminf ,
+and
+.Fn fminl
+functions conform to
+.St -isoC-99 .
+.Sh HISTORY
+These routines first appeared in
+.Fx 5.3 .
diff --git a/lib/msun/man/fmod.3 b/lib/msun/man/fmod.3
new file mode 100644
index 0000000..c585408
--- /dev/null
+++ b/lib/msun/man/fmod.3
@@ -0,0 +1,87 @@
+.\" Copyright (c) 1991 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce 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.
+.\"
+.\" from: @(#)fmod.3 5.1 (Berkeley) 5/2/91
+.\" $FreeBSD$
+.\"
+.Dd May 2, 1991
+.Dt FMOD 3
+.Os
+.Sh NAME
+.Nm fmod ,
+.Nm fmodf
+.Nd floating-point remainder functions
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In math.h
+.Ft double
+.Fn fmod "double x" "double y"
+.Ft float
+.Fn fmodf "float x" "float y"
+.Sh DESCRIPTION
+The
+.Fn fmod
+and the
+.Fn fmodf
+functions compute the floating-point remainder of
+.Fa x Ns / Fa y .
+.Sh RETURN VALUES
+The
+.Fn fmod
+and the
+.Fn fmodf
+functions return the value
+.Sm off
+.Fa x - Em i * Fa y ,
+.Sm on
+for some integer
+.Em i
+such that, if
+.Fa y
+is non-zero, the result has the same sign as
+.Fa x
+and magnitude less than the magnitude of
+.Fa y .
+If
+.Fa y
+is zero, whether a domain error occurs or the
+.Fn fmod
+and the
+.Fn fmodf
+function returns zero is implementation-defined.
+.Sh SEE ALSO
+.Xr math 3
+.Sh STANDARDS
+The
+.Fn fmod
+function conforms to
+.St -isoC .
diff --git a/lib/msun/man/hypot.3 b/lib/msun/man/hypot.3
new file mode 100644
index 0000000..4843e44
--- /dev/null
+++ b/lib/msun/man/hypot.3
@@ -0,0 +1,134 @@
+.\" Copyright (c) 1985, 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.
+.\" 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.
+.\"
+.\" from: @(#)hypot.3 6.7 (Berkeley) 5/6/91
+.\" $FreeBSD$
+.\"
+.Dd January 14, 2005
+.Dt HYPOT 3
+.Os
+.Sh NAME
+.Nm hypot ,
+.Nm hypotf ,
+.Nm cabs ,
+.Nm cabsf
+.Nd Euclidean distance and complex absolute value functions
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In math.h
+.Ft double
+.Fn hypot "double x" "double y"
+.Ft float
+.Fn hypotf "float x" "float y"
+.In complex.h
+.Ft double
+.Fn cabs "double complex z"
+.Ft float
+.Fn cabsf "float complex z"
+.Sh DESCRIPTION
+The
+.Fn hypot
+and
+.Fn hypotf
+functions
+compute the
+sqrt(x*x+y*y)
+in such a way that underflow will not happen, and overflow
+occurs only if the final result deserves it.
+The
+.Fn cabs
+and
+.Fn cabsf
+functions compute the complex absolute value of
+.Fa z .
+.Pp
+.Fn hypot "\*(If" "v"
+=
+.Fn hypot "v" "\*(If"
+= +\*(If for all
+.Fa v ,
+including \*(Na.
+.Sh ERROR (due to Roundoff, etc.)
+Below 0.97
+.Em ulps .
+Consequently
+.Fn hypot "5.0" "12.0"
+= 13.0
+exactly;
+in general, hypot and cabs return an integer whenever an
+integer might be expected.
+.Pp
+The same cannot be said for the shorter and faster version of hypot
+and cabs that is provided in the comments in cabs.c; its error can
+exceed 1.2
+.Em ulps .
+.Sh NOTES
+As might be expected,
+.Fn hypot "v" "\*(Na"
+and
+.Fn hypot "\*(Na" "v"
+are \*(Na for all
+.Em finite
+.Fa v .
+But programmers
+might be surprised at first to discover that
+.Fn hypot "\(+-\*(If" "\*(Na"
+= +\*(If.
+This is intentional; it happens because
+.Fn hypot "\*(If" "v"
+= +\*(If
+for
+.Em all
+.Fa v ,
+finite or infinite.
+Hence
+.Fn hypot "\*(If" "v"
+is independent of
+.Fa v .
+Unlike the reserved operand fault on a
+.Tn VAX ,
+the
+.Tn IEEE
+\*(Na is designed to
+disappear when it turns out to be irrelevant, as it does in
+.Fn hypot "\*(If" "\*(Na" .
+.Sh SEE ALSO
+.Xr math 3 ,
+.Xr sqrt 3
+.Sh HISTORY
+Both a
+.Fn hypot
+function and a
+.Fn cabs
+function
+appeared in
+.At v7 .
diff --git a/lib/msun/man/ieee.3 b/lib/msun/man/ieee.3
new file mode 100644
index 0000000..4d93d63
--- /dev/null
+++ b/lib/msun/man/ieee.3
@@ -0,0 +1,448 @@
+.\" Copyright (c) 1985 Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce 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.
+.\"
+.\" from: @(#)ieee.3 6.4 (Berkeley) 5/6/91
+.\" $FreeBSD$
+.\"
+.Dd January 26, 2005
+.Dt IEEE 3
+.Os
+.Sh NAME
+.Nm ieee
+.Nd IEEE standard 754 for floating-point arithmetic
+.Sh DESCRIPTION
+The IEEE Standard 754 for Binary Floating-Point Arithmetic
+defines representations of floating-point numbers and abstract
+properties of arithmetic operations relating to precision,
+rounding, and exceptional cases, as described below.
+.Ss IEEE STANDARD 754 Floating-Point Arithmetic
+Radix: Binary.
+.Pp
+Overflow and underflow:
+.Bd -ragged -offset indent -compact
+Overflow goes by default to a signed \*(If.
+Underflow is
+.Em gradual .
+.Ed
+.Pp
+Zero is represented ambiguously as +0 or \-0.
+.Bd -ragged -offset indent -compact
+Its sign transforms correctly through multiplication or
+division, and is preserved by addition of zeros
+with like signs; but x\-x yields +0 for every
+finite x.
+The only operations that reveal zero's
+sign are division by zero and
+.Fn copysign x \(+-0 .
+In particular, comparison (x > y, x \(>= y, etc.)\&
+cannot be affected by the sign of zero; but if
+finite x = y then \*(If = 1/(x\-y) \(!= \-1/(y\-x) = \-\*(If.
+.Ed
+.Pp
+Infinity is signed.
+.Bd -ragged -offset indent -compact
+It persists when added to itself
+or to any finite number.
+Its sign transforms
+correctly through multiplication and division, and
+(finite)/\(+-\*(If\0=\0\(+-0
+(nonzero)/0 = \(+-\*(If.
+But
+\*(If\-\*(If, \*(If\(**0 and \*(If/\*(If
+are, like 0/0 and sqrt(\-3),
+invalid operations that produce \*(Na. ...
+.Ed
+.Pp
+Reserved operands (\*(Nas):
+.Bd -ragged -offset indent -compact
+An \*(Na is
+.Em ( N Ns ot Em a N Ns umber ) .
+Some \*(Nas, called Signaling \*(Nas, trap any floating-point operation
+performed upon them; they are used to mark missing
+or uninitialized values, or nonexistent elements
+of arrays.
+The rest are Quiet \*(Nas; they are
+the default results of Invalid Operations, and
+propagate through subsequent arithmetic operations.
+If x \(!= x then x is \*(Na; every other predicate
+(x > y, x = y, x < y, ...) is FALSE if \*(Na is involved.
+.Ed
+.Pp
+Rounding:
+.Bd -ragged -offset indent -compact
+Every algebraic operation (+, \-, \(**, /,
+\(sr)
+is rounded by default to within half an
+.Em ulp ,
+and when the rounding error is exactly half an
+.Em ulp
+then
+the rounded value's least significant bit is zero.
+(An
+.Em ulp
+is one
+.Em U Ns nit
+in the
+.Em L Ns ast
+.Em P Ns lace . )
+This kind of rounding is usually the best kind,
+sometimes provably so; for instance, for every
+x = 1.0, 2.0, 3.0, 4.0, ..., 2.0**52, we find
+(x/3.0)\(**3.0 == x and (x/10.0)\(**10.0 == x and ...
+despite that both the quotients and the products
+have been rounded.
+Only rounding like IEEE 754 can do that.
+But no single kind of rounding can be
+proved best for every circumstance, so IEEE 754
+provides rounding towards zero or towards
++\*(If or towards \-\*(If
+at the programmer's option.
+.Ed
+.Pp
+Exceptions:
+.Bd -ragged -offset indent -compact
+IEEE 754 recognizes five kinds of floating-point exceptions,
+listed below in declining order of probable importance.
+.Bl -column -offset indent "Invalid Operation" "Gradual Underflow"
+.Em "Exception Default Result"
+Invalid Operation \*(Na, or FALSE
+Overflow \(+-\*(If
+Divide by Zero \(+-\*(If
+Underflow Gradual Underflow
+Inexact Rounded value
+.El
+.Pp
+NOTE: An Exception is not an Error unless handled
+badly.
+What makes a class of exceptions exceptional
+is that no single default response can be satisfactory
+in every instance.
+On the other hand, if a default
+response will serve most instances satisfactorily,
+the unsatisfactory instances cannot justify aborting
+computation every time the exception occurs.
+.Ed
+.Ss Data Formats
+Single-precision:
+.Bd -ragged -offset indent -compact
+Type name:
+.Vt float
+.Pp
+Wordsize: 32 bits.
+.Pp
+Precision: 24 significant bits,
+roughly like 7 significant decimals.
+.Bd -ragged -offset indent -compact
+If x and x' are consecutive positive single-precision
+numbers (they differ by 1
+.Em ulp ) ,
+then
+.Bd -ragged -compact
+5.9e\-08 < 0.5**24 < (x'\-x)/x \(<= 0.5**23 < 1.2e\-07.
+.Ed
+.Ed
+.Pp
+.Bl -column "XXX" -compact
+Range: Overflow threshold = 2.0**128 = 3.4e38
+ Underflow threshold = 0.5**126 = 1.2e\-38
+.El
+.Bd -ragged -offset indent -compact
+Underflowed results round to the nearest
+integer multiple of 0.5**149 = 1.4e\-45.
+.Ed
+.Ed
+.Pp
+Double-precision:
+.Bd -ragged -offset indent -compact
+Type name:
+.Vt double
+.Bd -ragged -offset indent -compact
+On some architectures,
+.Vt long double
+is the the same as
+.Vt double .
+.Ed
+.Pp
+Wordsize: 64 bits.
+.Pp
+Precision: 53 significant bits,
+roughly like 16 significant decimals.
+.Bd -ragged -offset indent -compact
+If x and x' are consecutive positive double-precision
+numbers (they differ by 1
+.Em ulp ) ,
+then
+.Bd -ragged -compact
+1.1e\-16 < 0.5**53 < (x'\-x)/x \(<= 0.5**52 < 2.3e\-16.
+.Ed
+.Ed
+.Pp
+.Bl -column "XXX" -compact
+Range: Overflow threshold = 2.0**1024 = 1.8e308
+ Underflow threshold = 0.5**1022 = 2.2e\-308
+.El
+.Bd -ragged -offset indent -compact
+Underflowed results round to the nearest
+integer multiple of 0.5**1074 = 4.9e\-324.
+.Ed
+.Ed
+.Pp
+Extended-precision:
+.Bd -ragged -offset indent -compact
+Type name:
+.Vt long double
+(when supported by the hardware)
+.Pp
+Wordsize: 96 bits.
+.Pp
+Precision: 64 significant bits,
+roughly like 19 significant decimals.
+.Bd -ragged -offset indent -compact
+If x and x' are consecutive positive double-precision
+numbers (they differ by 1
+.Em ulp ) ,
+then
+.Bd -ragged -compact
+1.0e\-19 < 0.5**63 < (x'\-x)/x \(<= 0.5**62 < 2.2e\-19.
+.Ed
+.Ed
+.Pp
+.Bl -column "XXX" -compact
+Range: Overflow threshold = 2.0**16384 = 1.2e4932
+ Underflow threshold = 0.5**16382 = 3.4e\-4932
+.El
+.Bd -ragged -offset indent -compact
+Underflowed results round to the nearest
+integer multiple of 0.5**16445 = 5.7e\-4953.
+.Ed
+.Ed
+.Pp
+Quad-extended-precision:
+.Bd -ragged -offset indent -compact
+Type name:
+.Vt long double
+(when supported by the hardware)
+.Pp
+Wordsize: 128 bits.
+.Pp
+Precision: 113 significant bits,
+roughly like 34 significant decimals.
+.Bd -ragged -offset indent -compact
+If x and x' are consecutive positive double-precision
+numbers (they differ by 1
+.Em ulp ) ,
+then
+.Bd -ragged -compact
+9.6e\-35 < 0.5**113 < (x'\-x)/x \(<= 0.5**112 < 2.0e\-34.
+.Ed
+.Ed
+.Pp
+.Bl -column "XXX" -compact
+Range: Overflow threshold = 2.0**16384 = 1.2e4932
+ Underflow threshold = 0.5**16382 = 3.4e\-4932
+.El
+.Bd -ragged -offset indent -compact
+Underflowed results round to the nearest
+integer multiple of 0.5**16494 = 6.5e\-4966.
+.Ed
+.Ed
+.Ss Additional Information Regarding Exceptions
+.Pp
+For each kind of floating-point exception, IEEE 754
+provides a Flag that is raised each time its exception
+is signaled, and stays raised until the program resets
+it.
+Programs may also test, save and restore a flag.
+Thus, IEEE 754 provides three ways by which programs
+may cope with exceptions for which the default result
+might be unsatisfactory:
+.Bl -enum
+.It
+Test for a condition that might cause an exception
+later, and branch to avoid the exception.
+.It
+Test a flag to see whether an exception has occurred
+since the program last reset its flag.
+.It
+Test a result to see whether it is a value that only
+an exception could have produced.
+.Pp
+CAUTION: The only reliable ways to discover
+whether Underflow has occurred are to test whether
+products or quotients lie closer to zero than the
+underflow threshold, or to test the Underflow
+flag.
+(Sums and differences cannot underflow in
+IEEE 754; if x \(!= y then x\-y is correct to
+full precision and certainly nonzero regardless of
+how tiny it may be.)
+Products and quotients that
+underflow gradually can lose accuracy gradually
+without vanishing, so comparing them with zero
+(as one might on a VAX) will not reveal the loss.
+Fortunately, if a gradually underflowed value is
+destined to be added to something bigger than the
+underflow threshold, as is almost always the case,
+digits lost to gradual underflow will not be missed
+because they would have been rounded off anyway.
+So gradual underflows are usually
+.Em provably
+ignorable.
+The same cannot be said of underflows flushed to 0.
+.El
+.Pp
+At the option of an implementor conforming to IEEE 754,
+other ways to cope with exceptions may be provided:
+.Bl -enum
+.It
+ABORT.
+This mechanism classifies an exception in
+advance as an incident to be handled by means
+traditionally associated with error-handling
+statements like "ON ERROR GO TO ...".
+Different
+languages offer different forms of this statement,
+but most share the following characteristics:
+.Bl -dash
+.It
+No means is provided to substitute a value for
+the offending operation's result and resume
+computation from what may be the middle of an
+expression.
+An exceptional result is abandoned.
+.It
+In a subprogram that lacks an error-handling
+statement, an exception causes the subprogram to
+abort within whatever program called it, and so
+on back up the chain of calling subprograms until
+an error-handling statement is encountered or the
+whole task is aborted and memory is dumped.
+.El
+.It
+STOP.
+This mechanism, requiring an interactive
+debugging environment, is more for the programmer
+than the program.
+It classifies an exception in
+advance as a symptom of a programmer's error; the
+exception suspends execution as near as it can to
+the offending operation so that the programmer can
+look around to see how it happened.
+Quite often
+the first several exceptions turn out to be quite
+unexceptionable, so the programmer ought ideally
+to be able to resume execution after each one as if
+execution had not been stopped.
+.It
+\&... Other ways lie beyond the scope of this document.
+.El
+.Pp
+Ideally, each
+elementary function should act as if it were indivisible, or
+atomic, in the sense that ...
+.Bl -enum
+.It
+No exception should be signaled that is not deserved by
+the data supplied to that function.
+.It
+Any exception signaled should be identified with that
+function rather than with one of its subroutines.
+.It
+The internal behavior of an atomic function should not
+be disrupted when a calling program changes from
+one to another of the five or so ways of handling
+exceptions listed above, although the definition
+of the function may be correlated intentionally
+with exception handling.
+.El
+.Pp
+The functions in
+.Nm libm
+are only approximately atomic.
+They signal no inappropriate exception except possibly ...
+.Bl -tag -width indent -offset indent -compact
+.It Xo
+Over/Underflow
+.Xc
+when a result, if properly computed, might have lain barely within range, and
+.It Xo
+Inexact in
+.Fn cabs ,
+.Fn cbrt ,
+.Fn hypot ,
+.Fn log10
+and
+.Fn pow
+.Xc
+when it happens to be exact, thanks to fortuitous cancellation of errors.
+.El
+Otherwise, ...
+.Bl -tag -width indent -offset indent -compact
+.It Xo
+Invalid Operation is signaled only when
+.Xc
+any result but \*(Na would probably be misleading.
+.It Xo
+Overflow is signaled only when
+.Xc
+the exact result would be finite but beyond the overflow threshold.
+.It Xo
+Divide-by-Zero is signaled only when
+.Xc
+a function takes exactly infinite values at finite operands.
+.It Xo
+Underflow is signaled only when
+.Xc
+the exact result would be nonzero but tinier than the underflow threshold.
+.It Xo
+Inexact is signaled only when
+.Xc
+greater range or precision would be needed to represent the exact result.
+.El
+.Sh SEE ALSO
+.Xr fenv 3 ,
+.Xr ieee_test 3 ,
+.Xr math 3
+.Pp
+An explanation of IEEE 754 and its proposed extension p854
+was published in the IEEE magazine MICRO in August 1984 under
+the title "A Proposed Radix- and Word-length-independent
+Standard for Floating-point Arithmetic" by
+.An "W. J. Cody"
+et al.
+The manuals for Pascal, C and BASIC on the Apple Macintosh
+document the features of IEEE 754 pretty well.
+Articles in the IEEE magazine COMPUTER vol.\& 14 no.\& 3 (Mar.\&
+1981), and in the ACM SIGNUM Newsletter Special Issue of
+Oct.\& 1979, may be helpful although they pertain to
+superseded drafts of the standard.
+.Sh STANDARDS
+.St -ieee754
diff --git a/lib/msun/man/ieee_test.3 b/lib/msun/man/ieee_test.3
new file mode 100644
index 0000000..2727045
--- /dev/null
+++ b/lib/msun/man/ieee_test.3
@@ -0,0 +1,93 @@
+.\" Copyright (c) 1985, 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.
+.\" 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.
+.\"
+.\" from: @(#)ieee.3 6.4 (Berkeley) 5/6/91
+.\" $FreeBSD$
+.\"
+.Dd November 6, 2005
+.Dt IEEE_TEST 3
+.Os
+.Sh NAME
+.Nm scalb ,
+.Nm scalbf ,
+.Nm significand ,
+.Nm significandf
+.Nd IEEE test functions
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In math.h
+.Ft double
+.Fn scalb "double x" "double n"
+.Ft float
+.Fn scalbf "float x" "float n"
+.Ft double
+.Fn significand "double x"
+.Ft float
+.Fn significandf "float x"
+.Sh DESCRIPTION
+These functions allow users to test conformance to
+.St -ieee754 .
+Their use is not otherwise recommended.
+.Pp
+.Fn scalb x n
+and
+.Fn scalbf x n
+return
+.Fa x Ns \(**(2** Ns Fa n )
+computed by exponent manipulation.
+If
+.Fa n
+is not an integer, \*(Pm\*(If, or an \*(Na, the result is unspecified.
+.Pp
+.Fn significand x
+and
+.Fn significandf x
+return
+.Fa sig ,
+where
+.Fa x
+:=
+.Fa sig No \(** 2** Ns Fa n
+with 1 \(<=
+.Fa sig
+< 2.
+.Fn significand x
+and
+.Fn significandf x
+are not defined when
+.Fa x
+is 0, \*(Pm\*(If, or \*(Na.
+.Sh SEE ALSO
+.Xr ieee 3 ,
+.Xr math 3
+.Sh STANDARDS
+.St -ieee754
diff --git a/lib/msun/man/ilogb.3 b/lib/msun/man/ilogb.3
new file mode 100644
index 0000000..c840ded
--- /dev/null
+++ b/lib/msun/man/ilogb.3
@@ -0,0 +1,127 @@
+.\" Copyright (c) 1985, 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.
+.\" 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.
+.\"
+.\" from: @(#)ieee.3 6.4 (Berkeley) 5/6/91
+.\" $FreeBSD$
+.\"
+.Dd November 6, 2005
+.Dt ILOGB 3
+.Os
+.Sh NAME
+.Nm ilogb ,
+.Nm ilogbf ,
+.Nm ilogbl ,
+.Nm logb ,
+.Nm logbf
+.Nd extract exponent
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In math.h
+.Ft int
+.Fn ilogb "double x"
+.Ft int
+.Fn ilogbf "float x"
+.Ft int
+.Fn ilogbl "long double x"
+.Ft double
+.Fn logb "double x"
+.Ft float
+.Fn logbf "float x"
+.Sh DESCRIPTION
+.Fn ilogb ,
+.Fn ilogbf
+and
+.Fn ilogbl
+return
+.Fa x Ns 's exponent
+in integer format.
+.Fn ilogb \*(Pm\*(If
+returns
+.Dv INT_MAX ,
+.Fn ilogb \*(Pm\*(Na
+returns
+.Dv FP_ILOGBNAN ,
+and
+.Fn ilogb 0
+returns
+.Dv FP_ILOGB0 .
+.Pp
+.Fn logb x
+and
+.Fn logbf x
+return
+.Fa x Ns 's exponent
+in floating\-point format with the same precision as
+.Fa x .
+.Fn logb \*(Pm\*(If
+returns +\*(If, and
+.Fn logb 0
+returns -\*(If with a division by zero exception.
+.Sh SEE ALSO
+.Xr frexp 3 ,
+.Xr ieee 3 ,
+.Xr math 3 ,
+.Xr scalbn 3
+.Sh STANDARDS
+The
+.Fn ilogb ,
+.Fn ilogbf ,
+.Fn ilogbl ,
+.Fn logb
+and
+.Fn logbf
+routines conform to
+.St -isoC-99 .
+.Fn logb
+and
+.Fn logbf
+implement the logb function recommended by
+.St -ieee754 .
+.Sh HISTORY
+The
+.Fn logb
+function appeared in
+.Bx 4.3 .
+The
+.Fn ilogb
+function appeared in
+.Fx 1.1.5 .
+The
+.Fn ilogbf
+and
+.Fn logbf
+functions appeared in
+.Fx 2.0 .
+The
+.Fn ilogbl
+function appeared in
+.Fx 5.4 .
diff --git a/lib/msun/man/j0.3 b/lib/msun/man/j0.3
new file mode 100644
index 0000000..2d80810
--- /dev/null
+++ b/lib/msun/man/j0.3
@@ -0,0 +1,142 @@
+.\" Copyright (c) 1985, 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.
+.\" 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.
+.\"
+.\" from: @(#)j0.3 6.7 (Berkeley) 4/19/91
+.\" $FreeBSD$
+.\"
+.Dd January 14, 2005
+.Dt J0 3
+.Os
+.Sh NAME
+.Nm j0 ,
+.Nm j0f ,
+.Nm j1 ,
+.Nm j1f ,
+.Nm jn ,
+.Nm jnf ,
+.Nm y0 ,
+.Nm y0f ,
+.Nm y1 ,
+.Nm y1f ,
+.Nm yn ,
+.Nm ynf
+.Nd Bessel functions of first and second kind
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In math.h
+.Ft double
+.Fn j0 "double x"
+.Ft float
+.Fn j0f "float x"
+.Ft double
+.Fn j1 "double x"
+.Ft float
+.Fn j1f "float x"
+.Ft double
+.Fn jn "int n" "double x"
+.Ft float
+.Fn jnf "int n" "float x"
+.Ft double
+.Fn y0 "double x"
+.Ft float
+.Fn y0f "float x"
+.Ft double
+.Fn y1 "double x"
+.Ft float
+.Fn y1f "float x"
+.Ft double
+.Fn yn "int n" "double x"
+.Ft float
+.Fn ynf "int n" "float x"
+.Sh DESCRIPTION
+The functions
+.Fn j0 ,
+.Fn j0f ,
+.Fn j1
+and
+.Fn j1f
+compute the
+.Em Bessel function of the first kind of the order
+0 and the
+.Em order
+1, respectively,
+for the
+real value
+.Fa x ;
+the functions
+.Fn jn
+and
+.Fn jnf
+compute the
+.Em Bessel function of the first kind of the integer
+.Em order
+.Fa n
+for the real value
+.Fa x .
+.Pp
+The functions
+.Fn y0 ,
+.Fn y0f ,
+.Fn y1 ,
+and
+.Fn y1f
+compute the linearly independent
+.Em Bessel function of the second kind of the order
+0 and the
+.Em order
+1, respectively,
+for the
+positive
+.Em real
+value
+.Fa x ;
+the functions
+.Fn yn
+and
+.Fn ynf
+compute the
+.Em Bessel function of the second kind for the integer
+.Em order
+.Fa n
+for the positive
+.Em real
+value
+.Fa x .
+.Sh RETURN VALUES
+If these functions are successful,
+the computed value is returned.
+.Sh SEE ALSO
+.Xr math 3
+.Sh HISTORY
+This set of functions
+appeared in
+.At v7 .
diff --git a/lib/msun/man/lgamma.3 b/lib/msun/man/lgamma.3
new file mode 100644
index 0000000..f7812c9
--- /dev/null
+++ b/lib/msun/man/lgamma.3
@@ -0,0 +1,185 @@
+.\" Copyright (c) 1985, 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.
+.\" 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.
+.\"
+.\" from: @(#)lgamma.3 6.6 (Berkeley) 12/3/92
+.\" $FreeBSD$
+.\"
+.Dd January 14, 2005
+.Dt LGAMMA 3
+.Os
+.Sh NAME
+.Nm lgamma ,
+.Nm lgamma_r ,
+.Nm lgammaf ,
+.Nm lgammaf_r ,
+.Nm gamma ,
+.Nm gamma_r ,
+.Nm gammaf ,
+.Nm gammaf_r ,
+.Nm tgamma
+.Nd log gamma functions, gamma function
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In math.h
+.Ft extern int
+.Fa signgam ;
+.sp
+.Ft double
+.Fn lgamma "double x"
+.Ft double
+.Fn lgamma_r "double x" "int *signgamp"
+.Ft float
+.Fn lgammaf "float x"
+.Ft float
+.Fn lgammaf_r "float x" "int *signgamp"
+.Ft double
+.Fn gamma "double x"
+.Ft double
+.Fn gamma_r "double x" "int *signgamp"
+.Ft float
+.Fn gammaf "float x"
+.Ft float
+.Fn gammaf_r "float x" "int *signgamp"
+.Ft double
+.Fn tgamma "double x"
+.Sh DESCRIPTION
+.Fn lgamma x
+and
+.Fn lgammaf x
+.if t \{\
+return ln\||\(*G(x)| where
+.Bd -unfilled -offset indent
+\(*G(x) = \(is\d\s8\z0\s10\u\u\s8\(if\s10\d t\u\s8x\-1\s10\d e\u\s8\-t\s10\d dt for x > 0 and
+\(*G(x) = \(*p/(\(*G(1\-x)\|sin(\(*px)) for x < 1.
+.Ed
+.\}
+.if n \
+return ln\||\(*G(x)|.
+.Pp
+The external integer
+.Fa signgam
+returns the sign of \(*G(x).
+.Pp
+.Fn lgamma_r x signgamp
+and
+.Fn lgammaf_r x signgamp
+provide the same functionality as
+.Fn lgamma x
+and
+.Fn lgammaf x
+but the caller must provide an integer to store the sign of \(*G(x).
+.Pp
+.Fn gamma ,
+.Fn gammaf ,
+.Fn gamma_r ,
+and
+.Fn gammaf_r
+are deprecated aliases for
+.Fn lgamma ,
+.Fn lgammaf ,
+.Fn lgamma_r ,
+and
+.Fn lgammaf_r ,
+respectively.
+.Fn tgamma x
+returns \(*G(x), with no effect on
+.Fa signgam .
+.Sh IDIOSYNCRASIES
+Do not use the expression
+.Dq Li signgam\(**exp(lgamma(x))
+to compute g := \(*G(x).
+Instead use a program like this (in C):
+.Bd -literal -offset indent
+lg = lgamma(x); g = signgam\(**exp(lg);
+.Ed
+.Pp
+Only after
+.Fn lgamma
+or
+.Fn lgammaf
+has returned can signgam be correct.
+.Pp
+For arguments in its range,
+.Fn tgamma
+is preferred, as for positive arguments
+it is accurate to within one unit in the last place.
+Exponentiation of
+.Fn lgamma
+will lose up to 10 significant bits.
+.Sh RETURN VALUES
+.Fn gamma ,
+.Fn gamma_r ,
+.Fn gammaf ,
+.Fn gammaf_r ,
+.Fn lgamma ,
+.Fn lgamma_r ,
+.Fn lgammaf ,
+and
+.Fn lgammaf_r
+return appropriate values unless an argument is out of range.
+Overflow will occur for sufficiently large positive values, and
+non-positive integers.
+For large non-integer negative values,
+.Fn tgamma
+will underflow.
+.Sh SEE ALSO
+.Xr math 3
+.Sh STANDARDS
+The
+.Fn lgamma
+and
+.Fn tgamma
+functions are expected to conform to
+.St -isoC-99 .
+.Sh HISTORY
+The
+.Fn lgamma
+function appeared in
+.Bx 4.3 .
+The
+.Fn gamma
+function appeared in
+.Bx 4.4
+as a function which computed \(*G(x).
+This version was used in
+.Fx 1.1 .
+The name
+.Fn gamma
+was originally dedicated to the
+.Fn lgamma
+function,
+and that usage was restored by switching to Sun's fdlibm in
+.Fx 1.1.5 .
+The
+.Fn tgamma
+function appeared in
+.Fx 5.0 .
diff --git a/lib/msun/man/lrint.3 b/lib/msun/man/lrint.3
new file mode 100644
index 0000000..bae9c45
--- /dev/null
+++ b/lib/msun/man/lrint.3
@@ -0,0 +1,94 @@
+.\" 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd January 11, 2005
+.Dt LRINT 3
+.Os
+.Sh NAME
+.Nm llrint ,
+.Nm llrintf ,
+.Nm lrint ,
+.Nm lrintf
+.Nd "convert to integer"
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In math.h
+.Ft "long long"
+.Fn llrint "double x"
+.Ft "long long"
+.Fn llrintf "float x"
+.Ft long
+.Fn lrint "double x"
+.Ft long
+.Fn lrintf "float x"
+.Sh DESCRIPTION
+The
+.Fn lrint
+function returns the integer nearest to its argument
+.Fa x
+according to the current rounding mode.
+If the rounded result is too large to be represented as a
+.Vt long
+value, an invalid exception is raised and the return value is undefined.
+Otherwise, if
+.Fa x
+is not an integer,
+.Fn lrint
+raises an inexact exception.
+When the rounded result is representable as a
+.Vt long ,
+the expression
+.Fn lrint x
+is equivalent to
+.Po Vt long Pc Ns Fn rint x
+(although the former may be more efficient).
+.Pp
+The
+.Fn llrint ,
+.Fn llrintf ,
+and
+.Fn lrintf
+functions differ from
+.Fn lrint
+only in their input and output types.
+.Sh SEE ALSO
+.Xr lround 3 ,
+.Xr math 3 ,
+.Xr rint 3 ,
+.Xr round 3
+.Sh STANDARDS
+The
+.Fn llrint ,
+.Fn llrintf ,
+.Fn lrint ,
+and
+.Fn lrintf
+functions conform to
+.St -isoC-99 .
+.Sh HISTORY
+These routines first appeared in
+.Fx 5.4 .
diff --git a/lib/msun/man/lround.3 b/lib/msun/man/lround.3
new file mode 100644
index 0000000..a98229d
--- /dev/null
+++ b/lib/msun/man/lround.3
@@ -0,0 +1,112 @@
+.\" 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd April 7, 2005
+.Dt LROUND 3
+.Os
+.Sh NAME
+.Nm llround ,
+.Nm llroundf ,
+.Nm llroundl ,
+.Nm lround ,
+.Nm lroundf ,
+.Nm lroundl
+.Nd "convert to nearest integral value"
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In math.h
+.Ft "long long"
+.Fn llround "double x"
+.Ft "long long"
+.Fn llroundf "float x"
+.Ft "long long"
+.Fn llroundl "long double x"
+.Ft long
+.Fn lround "double x"
+.Ft long
+.Fn lroundf "float x"
+.Ft long
+.Fn lroundl "long double x"
+.Sh DESCRIPTION
+The
+.Fn lround
+function returns the integer nearest to its argument
+.Fa x ,
+rounding away from zero in halfway cases.
+If the rounded result is too large to be represented as a
+.Vt long
+value, an invalid exception is raised and the return value is undefined.
+Otherwise, if
+.Fa x
+is not an integer,
+.Fn lround
+may raise an inexact exception.
+When the rounded result is representable as a
+.Vt long ,
+the expression
+.Fn lround x
+is equivalent to
+.Po Vt long Pc Ns Fn round x
+(although the former may be more efficient).
+.Pp
+The
+.Fn llround ,
+.Fn llroundf ,
+.Fn llroundl ,
+.Fn lroundf
+and
+.Fn lroundl
+functions differ from
+.Fn lround
+only in their input and output types.
+.Sh SEE ALSO
+.Xr lrint 3 ,
+.Xr math 3 ,
+.Xr rint 3 ,
+.Xr round 3
+.Sh STANDARDS
+The
+.Fn llround ,
+.Fn llroundf ,
+.Fn llroundl ,
+.Fn lround ,
+.Fn lroundf ,
+and
+.Fn lroundl
+functions conform to
+.St -isoC-99 .
+.Sh HISTORY
+The
+.Vt float
+and
+.Vt double
+versions of these routines first appeared in
+.Fx 5.4 .
+The
+.Vt "long double"
+versions appeared in
+.Fx 6.0 .
diff --git a/lib/msun/man/math.3 b/lib/msun/man/math.3
new file mode 100644
index 0000000..4808532
--- /dev/null
+++ b/lib/msun/man/math.3
@@ -0,0 +1,242 @@
+.\" Copyright (c) 1985 Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce 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.
+.\"
+.\" from: @(#)math.3 6.10 (Berkeley) 5/6/91
+.\" $FreeBSD$
+.\"
+.Dd November 6, 2005
+.Dt MATH 3
+.Os
+.if n \{\
+.char \[sr] "sqrt
+.\}
+.Sh NAME
+.Nm math
+.Nd "floating-point mathematical library"
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In math.h
+.Sh DESCRIPTION
+These functions constitute the C math library.
+.Sh "LIST OF FUNCTIONS"
+Each of the following
+.Vt double
+functions has a
+.Vt float
+counterpart with an
+.Ql f
+appended to the name and a
+.Vt "long double"
+counterpart with an
+.Ql l
+appended.
+As an example, the
+.Vt float
+and
+.Vt "long double"
+counterparts of
+.Ft double
+.Fn acos "double x"
+are
+.Ft float
+.Fn acosf "float x"
+and
+.Ft "long double"
+.Fn acosl "long double x" ,
+respectively.
+.de Cl
+.Bl -column "isgreaterequal" "bessel function of the second kind of the order 0"
+.Em "Name Description"
+..
+.Ss Algebraic Functions
+.Cl
+cbrt cube root
+fma fused multiply-add
+hypot Euclidean distance
+sqrt square root
+.El
+.Ss Classification Functions
+.Cl
+fpclassify classify a floating-point value
+isfinite determine whether a value is finite
+isinf determine whether a value is infinite
+isnan determine whether a value is \*(Na
+isnormal determine whether a value is normalized
+.El
+.Ss Exponent Manipulation Functions
+.Cl
+frexp extract exponent and mantissa
+ilogb extract exponent
+ldexp multiply by power of 2
+logb extract exponent
+scalbln adjust exponent
+scalbn adjust exponent
+.El
+.Ss Extremum- and Sign-Related Functions
+.Cl
+copysign copy sign bit
+fabs absolute value
+fdim positive difference
+fmax maximum function
+fmin minimum function
+signbit extract sign bit
+.El
+.\" .Ss Not a Number
+.\" .Cl
+.\" nan return quiet \*(Na) 0
+.\" .El
+.Ss Residue and Rounding Functions
+.Cl
+ceil integer no less than
+floor integer no greater than
+fmod positive remainder
+llrint round to integer in fixed-point format
+llround round to nearest integer in fixed-point format
+lrint round to integer in fixed-point format
+lround round to nearest integer in fixed-point format
+modf extract integer and fractional parts
+nearbyint round to integer (silent)
+nextafter next representable value
+nexttoward next representable value
+remainder remainder
+remquo remainder with partial quotient
+rint round to integer
+round round to nearest integer
+trunc integer no greater in magnitude than
+.El
+.Pp
+The
+.Fn ceil ,
+.Fn floor ,
+.Fn llround ,
+.Fn lround ,
+.Fn round ,
+and
+.Fn trunc
+functions round in predetermined directions, whereas
+.Fn llrint ,
+.Fn lrint ,
+and
+.Fn rint
+round according to the current (dynamic) rounding mode.
+For more information on controlling the dynamic rounding mode, see
+.Xr fenv 3
+and
+.Xr fesetround 3 .
+.Ss Silent Order Predicates
+.Cl
+isgreater greater than relation
+isgreaterequal greater than or equal to relation
+isless less than relation
+islessequal less than or equal to relation
+islessgreater less than or greater than relation
+isunordered unordered relation
+.El
+.Ss Transcendental Functions
+.Cl
+acos inverse cosine
+acosh inverse hyperbolic cosine
+asin inverse sine
+asinh inverse hyperbolic sine
+atan inverse tangent
+atanh inverse hyperbolic tangent
+atan2 atan(y/x); complex argument
+cos cosine
+cosh hyperbolic cosine
+erf error function
+erfc complementary error function
+exp exponential base e
+exp2 exponential base 2
+expm1 exp(x)\-1
+j0 Bessel function of the first kind of the order 0
+j1 Bessel function of the first kind of the order 1
+jn Bessel function of the first kind of the order n
+lgamma log gamma function
+log natural logarithm
+log10 logarithm to base 10
+log1p log(1+x)
+.\" log2 base 2 logarithm
+pow exponential x**y
+sin trigonometric function
+sinh hyperbolic function
+tan trigonometric function
+tanh hyperbolic function
+tgamma gamma function
+y0 Bessel function of the second kind of the order 0
+y1 Bessel function of the second kind of the order 1
+yn Bessel function of the second kind of the order n
+.El
+.Pp
+Unlike the algebraic functions listed earlier, the routines
+in this section may not produce a result that is correctly rounded,
+so reproducible results cannot be guaranteed across platforms.
+For most of these functions, however, incorrect rounding occurs
+rarely, and then only in very-close-to-halfway cases.
+.Sh SEE ALSO
+.Xr fenv 3 ,
+.Xr ieee 3
+.Sh HISTORY
+A math library with many of the present functions appeared in
+.At v7 .
+The library was substantially rewritten for
+.Bx 4.3
+to provide
+better accuracy and speed on machines supporting either VAX
+or IEEE 754 floating-point.
+Most of this library was replaced with FDLIBM, developed at Sun
+Microsystems, in
+.Fx 1.1.5 .
+Additional routines, including ones for
+.Vt float
+and
+.Vt long double
+values, were written for or imported into subsequent versions of FreeBSD.
+.Sh BUGS
+The
+.Fn log2
+and
+.Fn nan
+functions are missing, and many functions are not available in their
+.Vt "long double"
+variants.
+.Pp
+Many of the routines to compute transcendental functions produce
+inaccurate results in other than the default rounding mode.
+.Pp
+On some architectures, trigonometric argument reduction is not
+performed accurately, resulting in errors greater than 1
+.Em ulp
+for large arguments to
+.Fn cos ,
+.Fn sin ,
+and
+.Fn tan .
diff --git a/lib/msun/man/nextafter.3 b/lib/msun/man/nextafter.3
new file mode 100644
index 0000000..e958b5a
--- /dev/null
+++ b/lib/msun/man/nextafter.3
@@ -0,0 +1,100 @@
+.\" Copyright (c) 1985, 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.
+.\" 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.
+.\"
+.\" from: @(#)ieee.3 6.4 (Berkeley) 5/6/91
+.\" $FreeBSD$
+.\"
+.Dd May 4, 2005
+.Dt NEXTAFTER 3
+.Os
+.Sh NAME
+.Nm nextafter ,
+.Nm nextafterf ,
+.Nm nextafterl ,
+.Nm nexttoward ,
+.Nm nexttowardf ,
+.Nm nexttowardl
+.Nd next representable value
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In math.h
+.Ft double
+.Fn nextafter "double x" "double y"
+.Ft float
+.Fn nextafterf "float x" "float y"
+.Ft long double
+.Fn nextafterl "long double x" "long double y"
+.Ft double
+.Fn nexttoward "double x" "long double y"
+.Ft float
+.Fn nexttowardf "float x" "long double y"
+.Ft long double
+.Fn nexttowardl "long double x" "long double y"
+.Sh DESCRIPTION
+These functions
+return the next machine representable number from
+.Fa x
+in direction
+.Fa y .
+.Sh SEE ALSO
+.Xr ieee 3 ,
+.Xr math 3
+.Sh STANDARDS
+The
+.Fn nextafter ,
+.Fn nextafterf ,
+.Fn nextafterl ,
+.Fn nexttoward ,
+.Fn nexttowardf ,
+and
+.Fn nexttowardl
+routines conform to
+.St -isoC-99 .
+They implement the Nextafter function recommended by
+.St -ieee754 ,
+with the extension that
+.Fn nextafter +0.0, -0.0
+returns
+.Li -0.0 ,
+and
+.Fn nextafter -0.0, +0.0
+returns
+.Li +0.0 .
+.Sh HISTORY
+The
+.Fn nextafter
+function appeared in
+.Bx 4.3 ,
+and
+.Fn nextafterf
+appeared in
+.Fx 2.0 .
diff --git a/lib/msun/man/remainder.3 b/lib/msun/man/remainder.3
new file mode 100644
index 0000000..8e9c86c
--- /dev/null
+++ b/lib/msun/man/remainder.3
@@ -0,0 +1,146 @@
+.\" Copyright (c) 1985, 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.
+.\" 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.
+.\"
+.\" from: @(#)ieee.3 6.4 (Berkeley) 5/6/91
+.\" $FreeBSD$
+.\"
+.Dd March 24, 2005
+.Dt REMAINDER 3
+.Os
+.Sh NAME
+.Nm remainder ,
+.Nm remainderf ,
+.Nm remquo ,
+.Nm remquof
+.Nd minimal residue functions
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In math.h
+.Ft double
+.Fn remainder "double x" "double y"
+.Ft float
+.Fn remainderf "float x" "float y"
+.Ft double
+.Fn remquo "double x" "double y" "int *quo"
+.Ft float
+.Fn remquof "float x" "float y" "int *quo"
+.Sh DESCRIPTION
+.Fn remainder ,
+.Fn remainderf ,
+.Fn remquo ,
+and
+.Fn remquof
+return the remainder
+.Fa r
+:=
+.Fa x
+\-
+.Fa n\(**y
+where
+.Fa n
+is the integer nearest the exact value of
+.Bk -words
+.Fa x Ns / Ns Fa y ;
+.Ek
+moreover if
+.Pf \\*(Ba Fa n
+\-
+.Sm off
+.Fa x No / Fa y No \\*(Ba
+.Sm on
+=
+1/2
+then
+.Fa n
+is even.
+Consequently
+the remainder is computed exactly and
+.Sm off
+.Pf \\*(Ba Fa r No \\*(Ba
+.Sm on
+\*(Le
+.Sm off
+.Pf \\*(Ba Fa y No \\*(Ba/2 .
+.Sm on
+But attempting to take the remainder when
+.Fa y
+is 0 or
+.Fa x
+is \*(Pm\*(If is an invalid operation that produces a \*(Na.
+.Pp
+The
+.Fn remquo
+and
+.Fn remquof
+functions also store the last
+.Va k
+bits of
+.Fa n
+in the location pointed to by
+.Fa quo ,
+provided that
+.Fa n
+exists.
+The number of bits
+.Va k
+is platform-specific, but is guaranteed to be at least 3.
+.Sh SEE ALSO
+.Xr fmod 3 ,
+.Xr ieee 3 ,
+.Xr math 3
+.Sh STANDARDS
+The
+.Fn remainder ,
+.Fn remainderf ,
+.Fn remquo ,
+and
+.Fn remquof
+routines conform to
+.St -isoC-99 .
+The remainder is as defined in
+.St -ieee754 .
+.Sh HISTORY
+The
+.Fn remainder
+and
+.Fn remainderf
+functions appeared in
+.Bx 4.3
+and
+.Fx 2.0 ,
+respectively.
+The
+.Fn remquo
+and
+.Fn remquof
+functions were added in
+.Fx 6.0 .
diff --git a/lib/msun/man/rint.3 b/lib/msun/man/rint.3
new file mode 100644
index 0000000..bd1a7d3
--- /dev/null
+++ b/lib/msun/man/rint.3
@@ -0,0 +1,103 @@
+.\" Copyright (c) 1985, 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.
+.\" 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.
+.\"
+.\" from: @(#)rint.3 5.1 (Berkeley) 5/2/91
+.\" $FreeBSD$
+.\"
+.Dd July 5, 2004
+.Dt RINT 3
+.Os
+.Sh NAME
+.Nm nearbyint ,
+.Nm nearbyintf ,
+.Nm rint ,
+.Nm rintf
+.Nd round to integral value in floating-point format
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In math.h
+.Ft double
+.Fn nearbyint "double x"
+.Ft float
+.Fn nearbyintf "float x"
+.Ft double
+.Fn rint "double x"
+.Ft float
+.Fn rintf "float x"
+.Sh DESCRIPTION
+The
+.Fn rint
+and the
+.Fn rintf
+functions return the integral value nearest to
+.Fa x
+according to the prevailing rounding mode.
+These functions raise an inexact exception when the original argument
+is not an exact integer.
+.Pp
+The
+.Fn nearbyint
+and
+.Fn nearbyintf
+functions perform the same operation, except that they do not raise
+an inexact exception.
+.Sh SEE ALSO
+.Xr abs 3 ,
+.Xr ceil 3 ,
+.Xr fabs 3 ,
+.Xr fenv 3 ,
+.Xr floor 3 ,
+.Xr ieee 3 ,
+.Xr lrint 3 ,
+.Xr lround 3 ,
+.Xr math 3 ,
+.Xr round 3
+.Sh STANDARDS
+The
+.Fn nearbyint ,
+.Fn nearbyintf ,
+.Fn rint ,
+and
+.Fn rintf
+functions conform to
+.St -isoC-99 .
+.Sh HISTORY
+A
+.Fn rint
+function appeared in
+.At v6 .
+The
+.Fn nearbyint
+and
+.Fn nearbyintf
+functions appeared in
+.Fx 5.3 .
diff --git a/lib/msun/man/round.3 b/lib/msun/man/round.3
new file mode 100644
index 0000000..24b3970
--- /dev/null
+++ b/lib/msun/man/round.3
@@ -0,0 +1,80 @@
+.\" Copyright (c) 2003, Steven G. Kargl
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this 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 7, 2005
+.Dt ROUND 3
+.Os
+.Sh NAME
+.Nm round ,
+.Nm roundf ,
+.Nm roundl
+.Nd round to nearest integral value
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In math.h
+.Ft double
+.Fn round "double x"
+.Ft float
+.Fn roundf "float x"
+.Ft "long double"
+.Fn roundl "long double x"
+.Sh DESCRIPTION
+The
+.Fn round ,
+.Fn roundf ,
+and
+.Fn roundl
+functions return the nearest integral value to
+.Fa x ;
+if
+.Fa x
+lies halfway between two integral values, then these
+functions return the integral value with the larger
+absolute value (i.e., they round away from zero).
+.Sh SEE ALSO
+.Xr ceil 3 ,
+.Xr floor 3 ,
+.Xr ieee 3 ,
+.Xr lrint 3 ,
+.Xr lround 3 ,
+.Xr math 3 ,
+.Xr rint 3 ,
+.Xr trunc 3
+.Sh STANDARDS
+These functions conform to
+.St -isoC-99 .
+.Sh HISTORY
+The
+.Fn round
+and
+.Fn roundf
+functions appeared in
+.Fx 5.3 .
+The
+.Fn roundl
+function appeared in
+.Fx 6.0 .
diff --git a/lib/msun/man/scalbn.3 b/lib/msun/man/scalbn.3
new file mode 100644
index 0000000..f4469cd
--- /dev/null
+++ b/lib/msun/man/scalbn.3
@@ -0,0 +1,95 @@
+.\" Copyright (c) 1985, 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.
+.\" 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.
+.\"
+.\" from: @(#)ieee.3 6.4 (Berkeley) 5/6/91
+.\" $FreeBSD$
+.\"
+.Dd March 4, 2005
+.Dt SCALBN 3
+.Os
+.Sh NAME
+.Nm scalbln ,
+.Nm scalblnf ,
+.Nm scalblnl ,
+.Nm scalbn ,
+.Nm scalbnf ,
+.Nm scalbnl
+.Nd adjust exponent
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In math.h
+.Ft double
+.Fn scalbln "double x" "long n"
+.Ft float
+.Fn scalblnf "float x" "long n"
+.Ft long double
+.Fn scalblnl "long double x" "long n"
+.Ft double
+.Fn scalbn "double x" "int n"
+.Ft float
+.Fn scalbnf "float x" "int n"
+.Ft long double
+.Fn scalbnl "long double x" "int n"
+.Sh DESCRIPTION
+These routines return
+.Fa x Ns \(**(2** Ns Fa n )
+computed by exponent manipulation.
+.Sh SEE ALSO
+.Xr ieee 3 ,
+.Xr math 3
+.Sh STANDARDS
+These routines conform to
+.St -isoC-99 ,
+and they implement the Scalb function recommended by
+.St -ieee754 .
+.Sh HISTORY
+The
+.Fn scalbn
+and
+.Fn scalbnf
+functions appeared in
+.Bx 4.3
+and
+.Fx 2.0 ,
+respectively.
+The
+.Fn scalbln
+and
+.Fn scalblnf
+functions first appeared in
+.Fx 5.3 ,
+and
+.Fn scalblnl
+and
+.Fn scalbln
+in
+.Fx 6.0 .
diff --git a/lib/msun/man/signbit.3 b/lib/msun/man/signbit.3
new file mode 100644
index 0000000..dd0a39f
--- /dev/null
+++ b/lib/msun/man/signbit.3
@@ -0,0 +1,57 @@
+.\" 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 July 18, 2004
+.Dt SIGNBIT 3
+.Os
+.Sh NAME
+.Nm signbit
+.Nd "determine whether a floating-point number's sign is negative"
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In math.h
+.Ft int
+.Fn signbit "real-floating x"
+.Sh DESCRIPTION
+The
+.Fn signbit
+macro takes an argument of
+.Fa x
+and returns non-zero if the value of its sign is negative, otherwise 0.
+.Sh SEE ALSO
+.Xr fpclassify 3 ,
+.Xr math 3
+.Sh STANDARDS
+The
+.Fn signbit
+macro conforms to
+.St -isoC-99 .
+.Sh HISTORY
+The
+.Fn signbit
+macro was added in
+.Fx 5.1 .
diff --git a/lib/msun/man/sin.3 b/lib/msun/man/sin.3
new file mode 100644
index 0000000..f3e2db1
--- /dev/null
+++ b/lib/msun/man/sin.3
@@ -0,0 +1,82 @@
+.\" Copyright (c) 1991 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" @(#)sin.3 6.7 (Berkeley) 4/19/91
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce 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.
+.\"
+.\" from: @(#)sin.3 6.7 (Berkeley) 4/19/91
+.\" $FreeBSD$
+.\"
+.Dd April 19, 1991
+.Dt SIN 3
+.Os
+.Sh NAME
+.Nm sin ,
+.Nm sinf
+.Nd sine functions
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In math.h
+.Ft double
+.Fn sin "double x"
+.Ft float
+.Fn sinf "float x"
+.Sh DESCRIPTION
+The
+.Fn sin
+and the
+.Fn sinf
+functions compute the sine of
+.Fa x
+(measured in radians).
+A large magnitude argument may yield a result with little
+or no significance.
+.Sh RETURN VALUES
+The
+.Fn sin
+and the
+.Fn sinf
+functions return the sine value.
+.Sh SEE ALSO
+.Xr acos 3 ,
+.Xr asin 3 ,
+.Xr atan 3 ,
+.Xr atan2 3 ,
+.Xr cos 3 ,
+.Xr cosh 3 ,
+.Xr math 3 ,
+.Xr sinh 3 ,
+.Xr tan 3 ,
+.Xr tanh 3
+.Sh STANDARDS
+The
+.Fn sin
+function conforms to
+.St -isoC .
diff --git a/lib/msun/man/sinh.3 b/lib/msun/man/sinh.3
new file mode 100644
index 0000000..f7e6995
--- /dev/null
+++ b/lib/msun/man/sinh.3
@@ -0,0 +1,71 @@
+.\" Copyright (c) 1991 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce 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.
+.\"
+.\" from: @(#)sinh.3 6.6 (Berkeley) 4/19/91
+.\" $FreeBSD$
+.Dd January 14, 2005
+.Dt SINH 3
+.Os
+.Sh NAME
+.Nm sinh ,
+.Nm sinhf
+.Nd hyperbolic sine function
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In math.h
+.Ft double
+.Fn sinh "double x"
+.Ft float
+.Fn sinhf "float x"
+.Sh DESCRIPTION
+The
+.Fn sinh
+and the
+.Fn sinhf
+functions compute the hyperbolic sine of
+.Fa x .
+.Sh SEE ALSO
+.Xr acos 3 ,
+.Xr asin 3 ,
+.Xr atan 3 ,
+.Xr atan2 3 ,
+.Xr cos 3 ,
+.Xr cosh 3 ,
+.Xr math 3 ,
+.Xr sin 3 ,
+.Xr tan 3 ,
+.Xr tanh 3
+.Sh STANDARDS
+The
+.Fn sinh
+function conforms to
+.St -isoC .
diff --git a/lib/msun/man/sqrt.3 b/lib/msun/man/sqrt.3
new file mode 100644
index 0000000..9939900
--- /dev/null
+++ b/lib/msun/man/sqrt.3
@@ -0,0 +1,100 @@
+.\" Copyright (c) 1985, 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.
+.\" 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.
+.\"
+.\" from: @(#)sqrt.3 6.4 (Berkeley) 5/6/91
+.\" $FreeBSD$
+.\"
+.Dd May 6, 1991
+.Dt SQRT 3
+.Os
+.Sh NAME
+.Nm cbrt ,
+.Nm cbrtf ,
+.Nm sqrt ,
+.Nm sqrtf
+.Nd cube root and square root functions
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In math.h
+.Ft double
+.Fn cbrt "double x"
+.Ft float
+.Fn cbrtf "float x"
+.Ft double
+.Fn sqrt "double x"
+.Ft float
+.Fn sqrtf "float x"
+.Sh DESCRIPTION
+The
+.Fn cbrt
+and the
+.Fn cbrtf
+functions compute
+the cube root of
+.Ar x .
+.Pp
+The
+.Fn sqrt
+and the
+.Fn sqrtf
+functions compute the
+non-negative square root of x.
+.Sh RETURN VALUES
+The
+.Fn cbrt
+and the
+.Fn cbrtf
+functions return the requested cube root.
+The
+.Fn sqrt
+and the
+.Fn sqrtf
+functions return the requested square root
+unless an error occurs.
+An attempt to take the
+.Fn sqrt
+of negative
+.Fa x
+raises an invalid exception and causes an \*(Na to be returned.
+.Sh SEE ALSO
+.Xr fenv 3 ,
+.Xr math 3
+.Sh STANDARDS
+The
+.Fn sqrt
+function conforms to
+.St -isoC .
+.Sh HISTORY
+The
+.Fn cbrt
+function appeared in
+.Bx 4.3 .
diff --git a/lib/msun/man/tan.3 b/lib/msun/man/tan.3
new file mode 100644
index 0000000..fee9fb2
--- /dev/null
+++ b/lib/msun/man/tan.3
@@ -0,0 +1,81 @@
+.\" Copyright (c) 1991 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce 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.
+.\"
+.\" from: @(#)tan.3 5.1 (Berkeley) 5/2/91
+.\" $FreeBSD$
+.\"
+.Dd May 2, 1991
+.Dt TAN 3
+.Os
+.Sh NAME
+.Nm tan ,
+.Nm tanf
+.Nd tangent functions
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In math.h
+.Ft double
+.Fn tan "double x"
+.Ft float
+.Fn tanf "float x"
+.Sh DESCRIPTION
+The
+.Fn tan
+and the
+.Fn tanf
+functions compute the tangent of
+.Fa x
+(measured in radians).
+A large magnitude argument may yield a result
+with little or no significance.
+For a discussion of error due to roundoff, see
+.Xr math 3 .
+.Sh RETURN VALUES
+The
+.Fn tan
+function returns the tangent value.
+.Sh SEE ALSO
+.Xr acos 3 ,
+.Xr asin 3 ,
+.Xr atan 3 ,
+.Xr atan2 3 ,
+.Xr cos 3 ,
+.Xr cosh 3 ,
+.Xr math 3 ,
+.Xr sin 3 ,
+.Xr sinh 3 ,
+.Xr tanh 3
+.Sh STANDARDS
+The
+.Fn tan
+function conforms to
+.St -isoC .
diff --git a/lib/msun/man/tanh.3 b/lib/msun/man/tanh.3
new file mode 100644
index 0000000..39315e2
--- /dev/null
+++ b/lib/msun/man/tanh.3
@@ -0,0 +1,80 @@
+.\" Copyright (c) 1991 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce 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.
+.\"
+.\" from: @(#)tanh.3 5.1 (Berkeley) 5/2/91
+.\" $FreeBSD$
+.\"
+.Dd May 2, 1991
+.Dt TANH 3
+.Os
+.Sh NAME
+.Nm tanh ,
+.Nm tanhf
+.Nd hyperbolic tangent functions
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In math.h
+.Ft double
+.Fn tanh "double x"
+.Ft float
+.Fn tanhf "float x"
+.Sh DESCRIPTION
+The
+.Fn tanh
+and the
+.Fn tanhf
+functions compute the hyperbolic tangent of
+.Fa x .
+For a discussion of error due to roundoff, see
+.Xr math 3 .
+.Sh RETURN VALUES
+The
+.Fn tanh
+and the
+.Fn tanhf
+functions return the hyperbolic tangent value.
+.Sh SEE ALSO
+.Xr acos 3 ,
+.Xr asin 3 ,
+.Xr atan 3 ,
+.Xr atan2 3 ,
+.Xr cos 3 ,
+.Xr cosh 3 ,
+.Xr math 3 ,
+.Xr sin 3 ,
+.Xr sinh 3 ,
+.Xr tan 3
+.Sh STANDARDS
+The
+.Fn tanh
+function conforms to
+.St -isoC .
diff --git a/lib/msun/man/trunc.3 b/lib/msun/man/trunc.3
new file mode 100644
index 0000000..7d9e828
--- /dev/null
+++ b/lib/msun/man/trunc.3
@@ -0,0 +1,80 @@
+.\" Copyright (c) 2004, 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd April 16, 2005
+.Dt TRUNC 3
+.Os
+.Sh NAME
+.Nm trunc ,
+.Nm truncf ,
+.Nm truncl
+.Nd nearest integral value with magnitude less than or equal to |x|
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In math.h
+.Ft double
+.Fn trunc "double x"
+.Ft float
+.Fn truncf "float x"
+.Ft "long double"
+.Fn truncl "long double x"
+.Sh DESCRIPTION
+The
+.Fn trunc ,
+.Fn truncf ,
+and
+.Fn truncl
+functions return the nearest integral value with magnitude less than
+or equal to
+.Pf | Fa x Ns | .
+They are equivalent to
+.Fn rint ,
+.Fn rintf ,
+and
+.Fn rintl ,
+respectively, in the
+.Dv FE_TOWARDZERO
+rounding mode.
+.Sh SEE ALSO
+.Xr ceil 3 ,
+.Xr fesetround 3 ,
+.Xr floor 3 ,
+.Xr math 3 ,
+.Xr nextafter 3 ,
+.Xr rint 3 ,
+.Xr round 3
+.Sh STANDARDS
+The
+.Fn trunc ,
+.Fn truncf ,
+and
+.Fn truncl
+functions conform to
+.St -isoC-99 .
+.Sh HISTORY
+These routines first appeared in
+.Fx 5.3 .
diff --git a/lib/msun/powerpc/Makefile.inc b/lib/msun/powerpc/Makefile.inc
new file mode 100644
index 0000000..bc62448
--- /dev/null
+++ b/lib/msun/powerpc/Makefile.inc
@@ -0,0 +1,4 @@
+# $FreeBSD$
+
+LDBL_PREC = 53
+SYM_MAPS += ${.CURDIR}/powerpc/Symbol.map
diff --git a/lib/msun/powerpc/Symbol.map b/lib/msun/powerpc/Symbol.map
new file mode 100644
index 0000000..7e6e56d
--- /dev/null
+++ b/lib/msun/powerpc/Symbol.map
@@ -0,0 +1,3 @@
+# $FreeBSD$
+FBSD_1.0 {
+};
diff --git a/lib/msun/powerpc/fenv.c b/lib/msun/powerpc/fenv.c
new file mode 100644
index 0000000..04bbeaf
--- /dev/null
+++ b/lib/msun/powerpc/fenv.c
@@ -0,0 +1,31 @@
+/*-
+ * 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 <fenv.h>
+
+const fenv_t __fe_dfl_env = 0x00000000;
diff --git a/lib/msun/powerpc/fenv.h b/lib/msun/powerpc/fenv.h
new file mode 100644
index 0000000..3010472
--- /dev/null
+++ b/lib/msun/powerpc/fenv.h
@@ -0,0 +1,263 @@
+/*-
+ * Copyright (c) 2004-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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _FENV_H_
+#define _FENV_H_
+
+#include <sys/_types.h>
+
+typedef __uint32_t fenv_t;
+typedef __uint32_t fexcept_t;
+
+/* Exception flags */
+#define FE_INEXACT 0x02000000
+#define FE_DIVBYZERO 0x04000000
+#define FE_UNDERFLOW 0x08000000
+#define FE_OVERFLOW 0x10000000
+#define FE_INVALID 0x20000000 /* all types of invalid FP ops */
+
+/*
+ * The PowerPC architecture has extra invalid flags that indicate the
+ * specific type of invalid operation occurred. These flags may be
+ * tested, set, and cleared---but not masked---separately. All of
+ * these bits are cleared when FE_INVALID is cleared, but only
+ * FE_VXSOFT is set when FE_INVALID is explicitly set in software.
+ */
+#define FE_VXCVI 0x00000100 /* invalid integer convert */
+#define FE_VXSQRT 0x00000200 /* square root of a negative */
+#define FE_VXSOFT 0x00000400 /* software-requested exception */
+#define FE_VXVC 0x00080000 /* ordered comparison involving NaN */
+#define FE_VXIMZ 0x00100000 /* inf * 0 */
+#define FE_VXZDZ 0x00200000 /* 0 / 0 */
+#define FE_VXIDI 0x00400000 /* inf / inf */
+#define FE_VXISI 0x00800000 /* inf - inf */
+#define FE_VXSNAN 0x01000000 /* operation on a signalling NaN */
+#define FE_ALL_INVALID (FE_VXCVI | FE_VXSQRT | FE_VXSOFT | FE_VXVC | \
+ FE_VXIMZ | FE_VXZDZ | FE_VXIDI | FE_VXISI | \
+ FE_VXSNAN | FE_INVALID)
+#define FE_ALL_EXCEPT (FE_DIVBYZERO | FE_INEXACT | \
+ FE_ALL_INVALID | FE_OVERFLOW | FE_UNDERFLOW)
+
+/* Rounding modes */
+#define FE_TONEAREST 0x0000
+#define FE_TOWARDZERO 0x0001
+#define FE_UPWARD 0x0002
+#define FE_DOWNWARD 0x0003
+#define _ROUND_MASK (FE_TONEAREST | FE_DOWNWARD | \
+ FE_UPWARD | FE_TOWARDZERO)
+
+__BEGIN_DECLS
+
+/* Default floating-point environment */
+extern const fenv_t __fe_dfl_env;
+#define FE_DFL_ENV (&__fe_dfl_env)
+
+/* We need to be able to map status flag positions to mask flag positions */
+#define _FPUSW_SHIFT 22
+#define _ENABLE_MASK ((FE_DIVBYZERO | FE_INEXACT | FE_INVALID | \
+ FE_OVERFLOW | FE_UNDERFLOW) >> _FPUSW_SHIFT)
+
+#define __mffs(__env) __asm __volatile("mffs %0" : "=f" (*(__env)))
+#define __mtfsf(__env) __asm __volatile("mtfsf 255,%0" : : "f" (__env))
+
+union __fpscr {
+ double __d;
+ struct {
+ __uint32_t __junk;
+ fenv_t __reg;
+ } __bits;
+};
+
+static __inline int
+feclearexcept(int __excepts)
+{
+ union __fpscr __r;
+
+ if (__excepts & FE_INVALID)
+ __excepts |= FE_ALL_INVALID;
+ __mffs(&__r.__d);
+ __r.__bits.__reg &= ~__excepts;
+ __mtfsf(__r.__d);
+ return (0);
+}
+
+static __inline int
+fegetexceptflag(fexcept_t *__flagp, int __excepts)
+{
+ union __fpscr __r;
+
+ __mffs(&__r.__d);
+ *__flagp = __r.__bits.__reg & __excepts;
+ return (0);
+}
+
+static __inline int
+fesetexceptflag(const fexcept_t *__flagp, int __excepts)
+{
+ union __fpscr __r;
+
+ if (__excepts & FE_INVALID)
+ __excepts |= FE_ALL_EXCEPT;
+ __mffs(&__r.__d);
+ __r.__bits.__reg &= ~__excepts;
+ __r.__bits.__reg |= *__flagp & __excepts;
+ __mtfsf(__r.__d);
+ return (0);
+}
+
+static __inline int
+feraiseexcept(int __excepts)
+{
+ union __fpscr __r;
+
+ if (__excepts & FE_INVALID)
+ __excepts |= FE_VXSOFT;
+ __mffs(&__r.__d);
+ __r.__bits.__reg |= __excepts;
+ __mtfsf(__r.__d);
+ return (0);
+}
+
+static __inline int
+fetestexcept(int __excepts)
+{
+ union __fpscr __r;
+
+ __mffs(&__r.__d);
+ return (__r.__bits.__reg & __excepts);
+}
+
+static __inline int
+fegetround(void)
+{
+ union __fpscr __r;
+
+ __mffs(&__r.__d);
+ return (__r.__bits.__reg & _ROUND_MASK);
+}
+
+static __inline int
+fesetround(int __round)
+{
+ union __fpscr __r;
+
+ if (__round & ~_ROUND_MASK)
+ return (-1);
+ __mffs(&__r.__d);
+ __r.__bits.__reg &= ~_ROUND_MASK;
+ __r.__bits.__reg |= __round;
+ __mtfsf(__r.__d);
+ return (0);
+}
+
+static __inline int
+fegetenv(fenv_t *__envp)
+{
+ union __fpscr __r;
+
+ __mffs(&__r.__d);
+ *__envp = __r.__bits.__reg;
+ return (0);
+}
+
+static __inline int
+feholdexcept(fenv_t *__envp)
+{
+ union __fpscr __r;
+
+ __mffs(&__r.__d);
+ *__envp = __r.__d;
+ __r.__bits.__reg &= ~(FE_ALL_EXCEPT | _ENABLE_MASK);
+ __mtfsf(__r.__d);
+ return (0);
+}
+
+static __inline int
+fesetenv(const fenv_t *__envp)
+{
+ union __fpscr __r;
+
+ __r.__bits.__reg = *__envp;
+ __mtfsf(__r.__d);
+ return (0);
+}
+
+static __inline int
+feupdateenv(const fenv_t *__envp)
+{
+ union __fpscr __r;
+
+ __mffs(&__r.__d);
+ __r.__bits.__reg &= FE_ALL_EXCEPT;
+ __r.__bits.__reg |= *__envp;
+ __mtfsf(__r.__d);
+ return (0);
+}
+
+#if __BSD_VISIBLE
+
+static __inline int
+feenableexcept(int __mask)
+{
+ union __fpscr __r;
+ fenv_t __oldmask;
+
+ __mffs(&__r.__d);
+ __oldmask = __r.__bits.__reg;
+ __r.__bits.__reg |= (__mask & FE_ALL_EXCEPT) >> _FPUSW_SHIFT;
+ __mtfsf(__r.__d);
+ return ((__oldmask & _ENABLE_MASK) << _FPUSW_SHIFT);
+}
+
+static __inline int
+fedisableexcept(int __mask)
+{
+ union __fpscr __r;
+ fenv_t __oldmask;
+
+ __mffs(&__r.__d);
+ __oldmask = __r.__bits.__reg;
+ __r.__bits.__reg &= ~((__mask & FE_ALL_EXCEPT) >> _FPUSW_SHIFT);
+ __mtfsf(__r.__d);
+ return ((__oldmask & _ENABLE_MASK) << _FPUSW_SHIFT);
+}
+
+static __inline int
+fegetexcept(void)
+{
+ union __fpscr __r;
+
+ __mffs(&__r.__d);
+ return ((__r.__bits.__reg & _ENABLE_MASK) << _FPUSW_SHIFT);
+}
+
+#endif /* __BSD_VISIBLE */
+
+__END_DECLS
+
+#endif /* !_FENV_H_ */
diff --git a/lib/msun/sparc64/Makefile.inc b/lib/msun/sparc64/Makefile.inc
new file mode 100644
index 0000000..052dc4d
--- /dev/null
+++ b/lib/msun/sparc64/Makefile.inc
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+ARCH_SRCS= e_sqrt.S e_sqrtf.S
+LDBL_PREC= 113
+SYM_MAPS+= ${.CURDIR}/sparc64/Symbol.map
diff --git a/lib/msun/sparc64/Symbol.map b/lib/msun/sparc64/Symbol.map
new file mode 100644
index 0000000..7e6e56d
--- /dev/null
+++ b/lib/msun/sparc64/Symbol.map
@@ -0,0 +1,3 @@
+# $FreeBSD$
+FBSD_1.0 {
+};
diff --git a/lib/msun/sparc64/e_sqrt.S b/lib/msun/sparc64/e_sqrt.S
new file mode 100644
index 0000000..8c90c16
--- /dev/null
+++ b/lib/msun/sparc64/e_sqrt.S
@@ -0,0 +1,33 @@
+/*-
+ * 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 <machine/asm.h>
+__FBSDID("$FreeBSD$")
+
+ENTRY(sqrt)
+ retl
+ fsqrtd %f0, %f0
+END(sqrt)
diff --git a/lib/msun/sparc64/e_sqrtf.S b/lib/msun/sparc64/e_sqrtf.S
new file mode 100644
index 0000000..bf63f33
--- /dev/null
+++ b/lib/msun/sparc64/e_sqrtf.S
@@ -0,0 +1,33 @@
+/*-
+ * 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 <machine/asm.h>
+__FBSDID("$FreeBSD$")
+
+ENTRY(sqrtf)
+ retl
+ fsqrts %f1, %f0
+END(sqrtf)
diff --git a/lib/msun/sparc64/fenv.c b/lib/msun/sparc64/fenv.c
new file mode 100644
index 0000000..6e8220f
--- /dev/null
+++ b/lib/msun/sparc64/fenv.c
@@ -0,0 +1,36 @@
+/*-
+ * 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 <fenv.h>
+
+/*
+ * The FSR_version field may be different on different
+ * implementations, but it is immutable and opaque to the
+ * application. Thus, 0 is valid as the default environment.
+ */
+const fenv_t __fe_dfl_env = 0;
diff --git a/lib/msun/sparc64/fenv.h b/lib/msun/sparc64/fenv.h
new file mode 100644
index 0000000..8273299
--- /dev/null
+++ b/lib/msun/sparc64/fenv.h
@@ -0,0 +1,254 @@
+/*-
+ * Copyright (c) 2004-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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _FENV_H_
+#define _FENV_H_
+
+#include <sys/_types.h>
+
+typedef __uint64_t fenv_t;
+typedef __uint64_t fexcept_t;
+
+/* Exception flags */
+#define FE_INVALID 0x00000200
+#define FE_DIVBYZERO 0x00000040
+#define FE_OVERFLOW 0x00000100
+#define FE_UNDERFLOW 0x00000080
+#define FE_INEXACT 0x00000020
+#define FE_ALL_EXCEPT (FE_DIVBYZERO | FE_INEXACT | \
+ FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW)
+
+/*
+ * Rounding modes
+ *
+ * We can't just use the hardware bit values here, because that would
+ * make FE_UPWARD and FE_DOWNWARD negative, which is not allowed.
+ */
+#define FE_TONEAREST 0x0
+#define FE_TOWARDZERO 0x1
+#define FE_UPWARD 0x2
+#define FE_DOWNWARD 0x3
+#define _ROUND_MASK (FE_TONEAREST | FE_DOWNWARD | \
+ FE_UPWARD | FE_TOWARDZERO)
+#define _ROUND_SHIFT 30
+
+__BEGIN_DECLS
+
+/* Default floating-point environment */
+extern const fenv_t __fe_dfl_env;
+#define FE_DFL_ENV (&__fe_dfl_env)
+
+/* We need to be able to map status flag positions to mask flag positions */
+#define _FPUSW_SHIFT 18
+#define _ENABLE_MASK (FE_ALL_EXCEPT << _FPUSW_SHIFT)
+
+#define __ldxfsr(__r) __asm __volatile("ldx %0, %%fsr" : : "m" (__r))
+#define __stxfsr(__r) __asm __volatile("stx %%fsr, %0" : "=m" (*(__r)))
+
+static __inline int
+feclearexcept(int __excepts)
+{
+ fexcept_t __r;
+
+ __stxfsr(&__r);
+ __r &= ~__excepts;
+ __ldxfsr(__r);
+ return (0);
+}
+
+static __inline int
+fegetexceptflag(fexcept_t *__flagp, int __excepts)
+{
+ fexcept_t __r;
+
+ __stxfsr(&__r);
+ *__flagp = __r & __excepts;
+ return (0);
+}
+
+static __inline int
+fesetexceptflag(const fexcept_t *__flagp, int __excepts)
+{
+ fexcept_t __r;
+
+ __stxfsr(&__r);
+ __r &= ~__excepts;
+ __r |= *__flagp & __excepts;
+ __ldxfsr(__r);
+ return (0);
+}
+
+/*
+ * In contrast with the ia64 platform, it seems to be worthwhile to
+ * inline this function on sparc64 even when the arguments are not
+ * compile-time constants. Perhaps this depends on the register window.
+ */
+static __inline int
+feraiseexcept(int __excepts)
+{
+ volatile double d;
+
+ /*
+ * With a compiler that supports the FENV_ACCESS pragma
+ * properly, simple expressions like '0.0 / 0.0' should
+ * be sufficient to generate traps. Unfortunately, we
+ * need to bring a volatile variable into the equation
+ * to prevent incorrect optimizations.
+ */
+ if (__excepts & FE_INVALID) {
+ d = 0.0;
+ d = 0.0 / d;
+ }
+ if (__excepts & FE_DIVBYZERO) {
+ d = 0.0;
+ d = 1.0 / d;
+ }
+ if (__excepts & FE_OVERFLOW) {
+ d = 0x1.ffp1023;
+ d *= 2.0;
+ }
+ if (__excepts & FE_UNDERFLOW) {
+ d = 0x1p-1022;
+ d /= 0x1p1023;
+ }
+ if (__excepts & FE_INEXACT) {
+ d = 0x1p-1022;
+ d += 1.0;
+ }
+ return (0);
+}
+
+static __inline int
+fetestexcept(int __excepts)
+{
+ fexcept_t __r;
+
+ __stxfsr(&__r);
+ return (__r & __excepts);
+}
+
+static __inline int
+fegetround(void)
+{
+ fenv_t __r;
+
+ __stxfsr(&__r);
+ return ((__r >> _ROUND_SHIFT) & _ROUND_MASK);
+}
+
+static __inline int
+fesetround(int __round)
+{
+ fenv_t __r;
+
+ if (__round & ~_ROUND_MASK)
+ return (-1);
+ __stxfsr(&__r);
+ __r &= ~(_ROUND_MASK << _ROUND_SHIFT);
+ __r |= __round << _ROUND_SHIFT;
+ __ldxfsr(__r);
+ return (0);
+}
+
+static __inline int
+fegetenv(fenv_t *__envp)
+{
+
+ __stxfsr(__envp);
+ return (0);
+}
+
+static __inline int
+feholdexcept(fenv_t *__envp)
+{
+ fenv_t __r;
+
+ __stxfsr(&__r);
+ *__envp = __r;
+ __r &= ~(FE_ALL_EXCEPT | _ENABLE_MASK);
+ __ldxfsr(__r);
+ return (0);
+}
+
+static __inline int
+fesetenv(const fenv_t *__envp)
+{
+
+ __ldxfsr(*__envp);
+ return (0);
+}
+
+static __inline int
+feupdateenv(const fenv_t *__envp)
+{
+ fexcept_t __r;
+
+ __stxfsr(&__r);
+ __ldxfsr(*__envp);
+ feraiseexcept(__r & FE_ALL_EXCEPT);
+ return (0);
+}
+
+#if __BSD_VISIBLE
+
+static __inline int
+feenableexcept(int __mask)
+{
+ fenv_t __old_r, __new_r;
+
+ __stxfsr(&__old_r);
+ __new_r = __old_r | ((__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT);
+ __ldxfsr(__new_r);
+ return ((__old_r >> _FPUSW_SHIFT) & FE_ALL_EXCEPT);
+}
+
+static __inline int
+fedisableexcept(int __mask)
+{
+ fenv_t __old_r, __new_r;
+
+ __stxfsr(&__old_r);
+ __new_r = __old_r & ~((__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT);
+ __ldxfsr(__new_r);
+ return ((__old_r >> _FPUSW_SHIFT) & FE_ALL_EXCEPT);
+}
+
+static __inline int
+fegetexcept(void)
+{
+ fenv_t __r;
+
+ __stxfsr(&__r);
+ return ((__r & _ENABLE_MASK) >> _FPUSW_SHIFT);
+}
+
+#endif /* __BSD_VISIBLE */
+
+__END_DECLS
+
+#endif /* !_FENV_H_ */
diff --git a/lib/msun/src/e_acos.c b/lib/msun/src/e_acos.c
new file mode 100644
index 0000000..b021a1e
--- /dev/null
+++ b/lib/msun/src/e_acos.c
@@ -0,0 +1,104 @@
+
+/* @(#)e_acos.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/* __ieee754_acos(x)
+ * Method :
+ * acos(x) = pi/2 - asin(x)
+ * acos(-x) = pi/2 + asin(x)
+ * For |x|<=0.5
+ * acos(x) = pi/2 - (x + x*x^2*R(x^2)) (see asin.c)
+ * For x>0.5
+ * acos(x) = pi/2 - (pi/2 - 2asin(sqrt((1-x)/2)))
+ * = 2asin(sqrt((1-x)/2))
+ * = 2s + 2s*z*R(z) ...z=(1-x)/2, s=sqrt(z)
+ * = 2f + (2c + 2s*z*R(z))
+ * where f=hi part of s, and c = (z-f*f)/(s+f) is the correction term
+ * for f so that f+c ~ sqrt(z).
+ * For x<-0.5
+ * acos(x) = pi - 2asin(sqrt((1-|x|)/2))
+ * = pi - 0.5*(s+s*z*R(z)), where z=(1-|x|)/2,s=sqrt(z)
+ *
+ * Special cases:
+ * if x is NaN, return x itself;
+ * if |x|>1, return NaN with invalid signal.
+ *
+ * Function needed: sqrt
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+static const double
+one= 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+pi = 3.14159265358979311600e+00, /* 0x400921FB, 0x54442D18 */
+pio2_hi = 1.57079632679489655800e+00, /* 0x3FF921FB, 0x54442D18 */
+pio2_lo = 6.12323399573676603587e-17, /* 0x3C91A626, 0x33145C07 */
+pS0 = 1.66666666666666657415e-01, /* 0x3FC55555, 0x55555555 */
+pS1 = -3.25565818622400915405e-01, /* 0xBFD4D612, 0x03EB6F7D */
+pS2 = 2.01212532134862925881e-01, /* 0x3FC9C155, 0x0E884455 */
+pS3 = -4.00555345006794114027e-02, /* 0xBFA48228, 0xB5688F3B */
+pS4 = 7.91534994289814532176e-04, /* 0x3F49EFE0, 0x7501B288 */
+pS5 = 3.47933107596021167570e-05, /* 0x3F023DE1, 0x0DFDF709 */
+qS1 = -2.40339491173441421878e+00, /* 0xC0033A27, 0x1C8A2D4B */
+qS2 = 2.02094576023350569471e+00, /* 0x40002AE5, 0x9C598AC8 */
+qS3 = -6.88283971605453293030e-01, /* 0xBFE6066C, 0x1B8D0159 */
+qS4 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */
+
+double
+__ieee754_acos(double x)
+{
+ double z,p,q,r,w,s,c,df;
+ int32_t hx,ix;
+ GET_HIGH_WORD(hx,x);
+ ix = hx&0x7fffffff;
+ if(ix>=0x3ff00000) { /* |x| >= 1 */
+ u_int32_t lx;
+ GET_LOW_WORD(lx,x);
+ if(((ix-0x3ff00000)|lx)==0) { /* |x|==1 */
+ if(hx>0) return 0.0; /* acos(1) = 0 */
+ else return pi+2.0*pio2_lo; /* acos(-1)= pi */
+ }
+ return (x-x)/(x-x); /* acos(|x|>1) is NaN */
+ }
+ if(ix<0x3fe00000) { /* |x| < 0.5 */
+ if(ix<=0x3c600000) return pio2_hi+pio2_lo;/*if|x|<2**-57*/
+ z = x*x;
+ p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))));
+ q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4)));
+ r = p/q;
+ return pio2_hi - (x - (pio2_lo-x*r));
+ } else if (hx<0) { /* x < -0.5 */
+ z = (one+x)*0.5;
+ p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))));
+ q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4)));
+ s = sqrt(z);
+ r = p/q;
+ w = r*s-pio2_lo;
+ return pi - 2.0*(s+w);
+ } else { /* x > 0.5 */
+ z = (one-x)*0.5;
+ s = sqrt(z);
+ df = s;
+ SET_LOW_WORD(df,0);
+ c = (z-df*df)/(s+df);
+ p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))));
+ q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4)));
+ r = p/q;
+ w = r*s+c;
+ return 2.0*(df+w);
+ }
+}
diff --git a/lib/msun/src/e_acosf.c b/lib/msun/src/e_acosf.c
new file mode 100644
index 0000000..0688edf
--- /dev/null
+++ b/lib/msun/src/e_acosf.c
@@ -0,0 +1,81 @@
+/* e_acosf.c -- float version of e_acos.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+#include "math.h"
+#include "math_private.h"
+
+static const float
+one = 1.0000000000e+00, /* 0x3F800000 */
+pi = 3.1415925026e+00, /* 0x40490fda */
+pio2_hi = 1.5707962513e+00, /* 0x3fc90fda */
+pio2_lo = 7.5497894159e-08, /* 0x33a22168 */
+pS0 = 1.6666667163e-01, /* 0x3e2aaaab */
+pS1 = -3.2556581497e-01, /* 0xbea6b090 */
+pS2 = 2.0121252537e-01, /* 0x3e4e0aa8 */
+pS3 = -4.0055535734e-02, /* 0xbd241146 */
+pS4 = 7.9153501429e-04, /* 0x3a4f7f04 */
+pS5 = 3.4793309169e-05, /* 0x3811ef08 */
+qS1 = -2.4033949375e+00, /* 0xc019d139 */
+qS2 = 2.0209457874e+00, /* 0x4001572d */
+qS3 = -6.8828397989e-01, /* 0xbf303361 */
+qS4 = 7.7038154006e-02; /* 0x3d9dc62e */
+
+float
+__ieee754_acosf(float x)
+{
+ float z,p,q,r,w,s,c,df;
+ int32_t hx,ix;
+ GET_FLOAT_WORD(hx,x);
+ ix = hx&0x7fffffff;
+ if(ix==0x3f800000) { /* |x|==1 */
+ if(hx>0) return 0.0; /* acos(1) = 0 */
+ else return pi+(float)2.0*pio2_lo; /* acos(-1)= pi */
+ } else if(ix>0x3f800000) { /* |x| >= 1 */
+ return (x-x)/(x-x); /* acos(|x|>1) is NaN */
+ }
+ if(ix<0x3f000000) { /* |x| < 0.5 */
+ if(ix<=0x23000000) return pio2_hi+pio2_lo;/*if|x|<2**-57*/
+ z = x*x;
+ p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))));
+ q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4)));
+ r = p/q;
+ return pio2_hi - (x - (pio2_lo-x*r));
+ } else if (hx<0) { /* x < -0.5 */
+ z = (one+x)*(float)0.5;
+ p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))));
+ q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4)));
+ s = __ieee754_sqrtf(z);
+ r = p/q;
+ w = r*s-pio2_lo;
+ return pi - (float)2.0*(s+w);
+ } else { /* x > 0.5 */
+ int32_t idf;
+ z = (one-x)*(float)0.5;
+ s = __ieee754_sqrtf(z);
+ df = s;
+ GET_FLOAT_WORD(idf,df);
+ SET_FLOAT_WORD(df,idf&0xfffff000);
+ c = (z-df*df)/(s+df);
+ p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))));
+ q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4)));
+ r = p/q;
+ w = r*s+c;
+ return (float)2.0*(df+w);
+ }
+}
diff --git a/lib/msun/src/e_acosh.c b/lib/msun/src/e_acosh.c
new file mode 100644
index 0000000..25e11c3
--- /dev/null
+++ b/lib/msun/src/e_acosh.c
@@ -0,0 +1,63 @@
+
+/* @(#)e_acosh.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/* __ieee754_acosh(x)
+ * Method :
+ * Based on
+ * acosh(x) = log [ x + sqrt(x*x-1) ]
+ * we have
+ * acosh(x) := log(x)+ln2, if x is large; else
+ * acosh(x) := log(2x-1/(sqrt(x*x-1)+x)) if x>2; else
+ * acosh(x) := log1p(t+sqrt(2.0*t+t*t)); where t=x-1.
+ *
+ * Special cases:
+ * acosh(x) is NaN with signal if x<1.
+ * acosh(NaN) is NaN without signal.
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+static const double
+one = 1.0,
+ln2 = 6.93147180559945286227e-01; /* 0x3FE62E42, 0xFEFA39EF */
+
+double
+__ieee754_acosh(double x)
+{
+ double t;
+ int32_t hx;
+ u_int32_t lx;
+ EXTRACT_WORDS(hx,lx,x);
+ if(hx<0x3ff00000) { /* x < 1 */
+ return (x-x)/(x-x);
+ } else if(hx >=0x41b00000) { /* x > 2**28 */
+ if(hx >=0x7ff00000) { /* x is inf of NaN */
+ return x+x;
+ } else
+ return __ieee754_log(x)+ln2; /* acosh(huge)=log(2x) */
+ } else if(((hx-0x3ff00000)|lx)==0) {
+ return 0.0; /* acosh(1) = 0 */
+ } else if (hx > 0x40000000) { /* 2**28 > x > 2 */
+ t=x*x;
+ return __ieee754_log(2.0*x-one/(x+sqrt(t-one)));
+ } else { /* 1<x<2 */
+ t = x-one;
+ return log1p(t+sqrt(2.0*t+t*t));
+ }
+}
diff --git a/lib/msun/src/e_acoshf.c b/lib/msun/src/e_acoshf.c
new file mode 100644
index 0000000..5138d72
--- /dev/null
+++ b/lib/msun/src/e_acoshf.c
@@ -0,0 +1,49 @@
+/* e_acoshf.c -- float version of e_acosh.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+#include "math.h"
+#include "math_private.h"
+
+static const float
+one = 1.0,
+ln2 = 6.9314718246e-01; /* 0x3f317218 */
+
+float
+__ieee754_acoshf(float x)
+{
+ float t;
+ int32_t hx;
+ GET_FLOAT_WORD(hx,x);
+ if(hx<0x3f800000) { /* x < 1 */
+ return (x-x)/(x-x);
+ } else if(hx >=0x4d800000) { /* x > 2**28 */
+ if(hx >=0x7f800000) { /* x is inf of NaN */
+ return x+x;
+ } else
+ return __ieee754_logf(x)+ln2; /* acosh(huge)=log(2x) */
+ } else if (hx==0x3f800000) {
+ return 0.0; /* acosh(1) = 0 */
+ } else if (hx > 0x40000000) { /* 2**28 > x > 2 */
+ t=x*x;
+ return __ieee754_logf((float)2.0*x-one/(x+__ieee754_sqrtf(t-one)));
+ } else { /* 1<x<2 */
+ t = x-one;
+ return log1pf(t+__ieee754_sqrtf((float)2.0*t+t*t));
+ }
+}
diff --git a/lib/msun/src/e_asin.c b/lib/msun/src/e_asin.c
new file mode 100644
index 0000000..044c1be
--- /dev/null
+++ b/lib/msun/src/e_asin.c
@@ -0,0 +1,113 @@
+
+/* @(#)e_asin.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/* __ieee754_asin(x)
+ * Method :
+ * Since asin(x) = x + x^3/6 + x^5*3/40 + x^7*15/336 + ...
+ * we approximate asin(x) on [0,0.5] by
+ * asin(x) = x + x*x^2*R(x^2)
+ * where
+ * R(x^2) is a rational approximation of (asin(x)-x)/x^3
+ * and its remez error is bounded by
+ * |(asin(x)-x)/x^3 - R(x^2)| < 2^(-58.75)
+ *
+ * For x in [0.5,1]
+ * asin(x) = pi/2-2*asin(sqrt((1-x)/2))
+ * Let y = (1-x), z = y/2, s := sqrt(z), and pio2_hi+pio2_lo=pi/2;
+ * then for x>0.98
+ * asin(x) = pi/2 - 2*(s+s*z*R(z))
+ * = pio2_hi - (2*(s+s*z*R(z)) - pio2_lo)
+ * For x<=0.98, let pio4_hi = pio2_hi/2, then
+ * f = hi part of s;
+ * c = sqrt(z) - f = (z-f*f)/(s+f) ...f+c=sqrt(z)
+ * and
+ * asin(x) = pi/2 - 2*(s+s*z*R(z))
+ * = pio4_hi+(pio4-2s)-(2s*z*R(z)-pio2_lo)
+ * = pio4_hi+(pio4-2f)-(2s*z*R(z)-(pio2_lo+2c))
+ *
+ * Special cases:
+ * if x is NaN, return x itself;
+ * if |x|>1, return NaN with invalid signal.
+ *
+ */
+
+
+#include "math.h"
+#include "math_private.h"
+
+static const double
+one = 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+huge = 1.000e+300,
+pio2_hi = 1.57079632679489655800e+00, /* 0x3FF921FB, 0x54442D18 */
+pio2_lo = 6.12323399573676603587e-17, /* 0x3C91A626, 0x33145C07 */
+pio4_hi = 7.85398163397448278999e-01, /* 0x3FE921FB, 0x54442D18 */
+ /* coefficient for R(x^2) */
+pS0 = 1.66666666666666657415e-01, /* 0x3FC55555, 0x55555555 */
+pS1 = -3.25565818622400915405e-01, /* 0xBFD4D612, 0x03EB6F7D */
+pS2 = 2.01212532134862925881e-01, /* 0x3FC9C155, 0x0E884455 */
+pS3 = -4.00555345006794114027e-02, /* 0xBFA48228, 0xB5688F3B */
+pS4 = 7.91534994289814532176e-04, /* 0x3F49EFE0, 0x7501B288 */
+pS5 = 3.47933107596021167570e-05, /* 0x3F023DE1, 0x0DFDF709 */
+qS1 = -2.40339491173441421878e+00, /* 0xC0033A27, 0x1C8A2D4B */
+qS2 = 2.02094576023350569471e+00, /* 0x40002AE5, 0x9C598AC8 */
+qS3 = -6.88283971605453293030e-01, /* 0xBFE6066C, 0x1B8D0159 */
+qS4 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */
+
+double
+__ieee754_asin(double x)
+{
+ double t=0.0,w,p,q,c,r,s;
+ int32_t hx,ix;
+ GET_HIGH_WORD(hx,x);
+ ix = hx&0x7fffffff;
+ if(ix>= 0x3ff00000) { /* |x|>= 1 */
+ u_int32_t lx;
+ GET_LOW_WORD(lx,x);
+ if(((ix-0x3ff00000)|lx)==0)
+ /* asin(1)=+-pi/2 with inexact */
+ return x*pio2_hi+x*pio2_lo;
+ return (x-x)/(x-x); /* asin(|x|>1) is NaN */
+ } else if (ix<0x3fe00000) { /* |x|<0.5 */
+ if(ix<0x3e400000) { /* if |x| < 2**-27 */
+ if(huge+x>one) return x;/* return x with inexact if x!=0*/
+ } else
+ t = x*x;
+ p = t*(pS0+t*(pS1+t*(pS2+t*(pS3+t*(pS4+t*pS5)))));
+ q = one+t*(qS1+t*(qS2+t*(qS3+t*qS4)));
+ w = p/q;
+ return x+x*w;
+ }
+ /* 1> |x|>= 0.5 */
+ w = one-fabs(x);
+ t = w*0.5;
+ p = t*(pS0+t*(pS1+t*(pS2+t*(pS3+t*(pS4+t*pS5)))));
+ q = one+t*(qS1+t*(qS2+t*(qS3+t*qS4)));
+ s = sqrt(t);
+ if(ix>=0x3FEF3333) { /* if |x| > 0.975 */
+ w = p/q;
+ t = pio2_hi-(2.0*(s+s*w)-pio2_lo);
+ } else {
+ w = s;
+ SET_LOW_WORD(w,0);
+ c = (t-w*w)/(s+w);
+ r = p/q;
+ p = 2.0*s*r-(pio2_lo-2.0*c);
+ q = pio4_hi-2.0*w;
+ t = pio4_hi-(p-q);
+ }
+ if(hx>0) return t; else return -t;
+}
diff --git a/lib/msun/src/e_asinf.c b/lib/msun/src/e_asinf.c
new file mode 100644
index 0000000..c0cf8a4
--- /dev/null
+++ b/lib/msun/src/e_asinf.c
@@ -0,0 +1,84 @@
+/* e_asinf.c -- float version of e_asin.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+#include "math.h"
+#include "math_private.h"
+
+static const float
+one = 1.0000000000e+00, /* 0x3F800000 */
+huge = 1.000e+30,
+pio2_hi = 1.5707962513e+00, /* 0x3fc90fda */
+pio2_lo = 7.5497894159e-08, /* 0x33a22168 */
+pio4_hi = 7.8539812565e-01, /* 0x3f490fda */
+ /* coefficient for R(x^2) */
+pS0 = 1.6666667163e-01, /* 0x3e2aaaab */
+pS1 = -3.2556581497e-01, /* 0xbea6b090 */
+pS2 = 2.0121252537e-01, /* 0x3e4e0aa8 */
+pS3 = -4.0055535734e-02, /* 0xbd241146 */
+pS4 = 7.9153501429e-04, /* 0x3a4f7f04 */
+pS5 = 3.4793309169e-05, /* 0x3811ef08 */
+qS1 = -2.4033949375e+00, /* 0xc019d139 */
+qS2 = 2.0209457874e+00, /* 0x4001572d */
+qS3 = -6.8828397989e-01, /* 0xbf303361 */
+qS4 = 7.7038154006e-02; /* 0x3d9dc62e */
+
+float
+__ieee754_asinf(float x)
+{
+ float t=0.0,w,p,q,c,r,s;
+ int32_t hx,ix;
+ GET_FLOAT_WORD(hx,x);
+ ix = hx&0x7fffffff;
+ if(ix==0x3f800000) {
+ /* asin(1)=+-pi/2 with inexact */
+ return x*pio2_hi+x*pio2_lo;
+ } else if(ix> 0x3f800000) { /* |x|>= 1 */
+ return (x-x)/(x-x); /* asin(|x|>1) is NaN */
+ } else if (ix<0x3f000000) { /* |x|<0.5 */
+ if(ix<0x32000000) { /* if |x| < 2**-27 */
+ if(huge+x>one) return x;/* return x with inexact if x!=0*/
+ } else
+ t = x*x;
+ p = t*(pS0+t*(pS1+t*(pS2+t*(pS3+t*(pS4+t*pS5)))));
+ q = one+t*(qS1+t*(qS2+t*(qS3+t*qS4)));
+ w = p/q;
+ return x+x*w;
+ }
+ /* 1> |x|>= 0.5 */
+ w = one-fabsf(x);
+ t = w*(float)0.5;
+ p = t*(pS0+t*(pS1+t*(pS2+t*(pS3+t*(pS4+t*pS5)))));
+ q = one+t*(qS1+t*(qS2+t*(qS3+t*qS4)));
+ s = __ieee754_sqrtf(t);
+ if(ix>=0x3F79999A) { /* if |x| > 0.975 */
+ w = p/q;
+ t = pio2_hi-((float)2.0*(s+s*w)-pio2_lo);
+ } else {
+ int32_t iw;
+ w = s;
+ GET_FLOAT_WORD(iw,w);
+ SET_FLOAT_WORD(w,iw&0xfffff000);
+ c = (t-w*w)/(s+w);
+ r = p/q;
+ p = (float)2.0*s*r-(pio2_lo-(float)2.0*c);
+ q = pio4_hi-(float)2.0*w;
+ t = pio4_hi-(p-q);
+ }
+ if(hx>0) return t; else return -t;
+}
diff --git a/lib/msun/src/e_atan2.c b/lib/msun/src/e_atan2.c
new file mode 100644
index 0000000..a05a840
--- /dev/null
+++ b/lib/msun/src/e_atan2.c
@@ -0,0 +1,124 @@
+
+/* @(#)e_atan2.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/* __ieee754_atan2(y,x)
+ * Method :
+ * 1. Reduce y to positive by atan2(y,x)=-atan2(-y,x).
+ * 2. Reduce x to positive by (if x and y are unexceptional):
+ * ARG (x+iy) = arctan(y/x) ... if x > 0,
+ * ARG (x+iy) = pi - arctan[y/(-x)] ... if x < 0,
+ *
+ * Special cases:
+ *
+ * ATAN2((anything), NaN ) is NaN;
+ * ATAN2(NAN , (anything) ) is NaN;
+ * ATAN2(+-0, +(anything but NaN)) is +-0 ;
+ * ATAN2(+-0, -(anything but NaN)) is +-pi ;
+ * ATAN2(+-(anything but 0 and NaN), 0) is +-pi/2;
+ * ATAN2(+-(anything but INF and NaN), +INF) is +-0 ;
+ * ATAN2(+-(anything but INF and NaN), -INF) is +-pi;
+ * ATAN2(+-INF,+INF ) is +-pi/4 ;
+ * ATAN2(+-INF,-INF ) is +-3pi/4;
+ * ATAN2(+-INF, (anything but,0,NaN, and INF)) is +-pi/2;
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following
+ * constants. The decimal values may be used, provided that the
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+static const double
+tiny = 1.0e-300,
+zero = 0.0,
+pi_o_4 = 7.8539816339744827900E-01, /* 0x3FE921FB, 0x54442D18 */
+pi_o_2 = 1.5707963267948965580E+00, /* 0x3FF921FB, 0x54442D18 */
+pi = 3.1415926535897931160E+00, /* 0x400921FB, 0x54442D18 */
+pi_lo = 1.2246467991473531772E-16; /* 0x3CA1A626, 0x33145C07 */
+
+double
+__ieee754_atan2(double y, double x)
+{
+ double z;
+ int32_t k,m,hx,hy,ix,iy;
+ u_int32_t lx,ly;
+
+ EXTRACT_WORDS(hx,lx,x);
+ ix = hx&0x7fffffff;
+ EXTRACT_WORDS(hy,ly,y);
+ iy = hy&0x7fffffff;
+ if(((ix|((lx|-lx)>>31))>0x7ff00000)||
+ ((iy|((ly|-ly)>>31))>0x7ff00000)) /* x or y is NaN */
+ return x+y;
+ if((hx-0x3ff00000|lx)==0) return atan(y); /* x=1.0 */
+ m = ((hy>>31)&1)|((hx>>30)&2); /* 2*sign(x)+sign(y) */
+
+ /* when y = 0 */
+ if((iy|ly)==0) {
+ switch(m) {
+ case 0:
+ case 1: return y; /* atan(+-0,+anything)=+-0 */
+ case 2: return pi+tiny;/* atan(+0,-anything) = pi */
+ case 3: return -pi-tiny;/* atan(-0,-anything) =-pi */
+ }
+ }
+ /* when x = 0 */
+ if((ix|lx)==0) return (hy<0)? -pi_o_2-tiny: pi_o_2+tiny;
+
+ /* when x is INF */
+ if(ix==0x7ff00000) {
+ if(iy==0x7ff00000) {
+ switch(m) {
+ case 0: return pi_o_4+tiny;/* atan(+INF,+INF) */
+ case 1: return -pi_o_4-tiny;/* atan(-INF,+INF) */
+ case 2: return 3.0*pi_o_4+tiny;/*atan(+INF,-INF)*/
+ case 3: return -3.0*pi_o_4-tiny;/*atan(-INF,-INF)*/
+ }
+ } else {
+ switch(m) {
+ case 0: return zero ; /* atan(+...,+INF) */
+ case 1: return -zero ; /* atan(-...,+INF) */
+ case 2: return pi+tiny ; /* atan(+...,-INF) */
+ case 3: return -pi-tiny ; /* atan(-...,-INF) */
+ }
+ }
+ }
+ /* when y is INF */
+ if(iy==0x7ff00000) return (hy<0)? -pi_o_2-tiny: pi_o_2+tiny;
+
+ /* compute y/x */
+ k = (iy-ix)>>20;
+ if(k > 60) z=pi_o_2+0.5*pi_lo; /* |y/x| > 2**60 */
+ else if(hx<0&&k<-60) z=0.0; /* |y|/x < -2**60 */
+ else z=atan(fabs(y/x)); /* safe to do y/x */
+ switch (m) {
+ case 0: return z ; /* atan(+,+) */
+ case 1: {
+ u_int32_t zh;
+ GET_HIGH_WORD(zh,z);
+ SET_HIGH_WORD(z,zh ^ 0x80000000);
+ }
+ return z ; /* atan(-,+) */
+ case 2: return pi-(z-pi_lo);/* atan(+,-) */
+ default: /* case 3 */
+ return (z-pi_lo)-pi;/* atan(-,-) */
+ }
+}
diff --git a/lib/msun/src/e_atan2f.c b/lib/msun/src/e_atan2f.c
new file mode 100644
index 0000000..af011318
--- /dev/null
+++ b/lib/msun/src/e_atan2f.c
@@ -0,0 +1,97 @@
+/* e_atan2f.c -- float version of e_atan2.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+#include "math.h"
+#include "math_private.h"
+
+static const float
+tiny = 1.0e-30,
+zero = 0.0,
+pi_o_4 = 7.8539818525e-01, /* 0x3f490fdb */
+pi_o_2 = 1.5707963705e+00, /* 0x3fc90fdb */
+pi = 3.1415927410e+00, /* 0x40490fdb */
+pi_lo = -8.7422776573e-08; /* 0xb3bbbd2e */
+
+float
+__ieee754_atan2f(float y, float x)
+{
+ float z;
+ int32_t k,m,hx,hy,ix,iy;
+
+ GET_FLOAT_WORD(hx,x);
+ ix = hx&0x7fffffff;
+ GET_FLOAT_WORD(hy,y);
+ iy = hy&0x7fffffff;
+ if((ix>0x7f800000)||
+ (iy>0x7f800000)) /* x or y is NaN */
+ return x+y;
+ if(hx==0x3f800000) return atanf(y); /* x=1.0 */
+ m = ((hy>>31)&1)|((hx>>30)&2); /* 2*sign(x)+sign(y) */
+
+ /* when y = 0 */
+ if(iy==0) {
+ switch(m) {
+ case 0:
+ case 1: return y; /* atan(+-0,+anything)=+-0 */
+ case 2: return pi+tiny;/* atan(+0,-anything) = pi */
+ case 3: return -pi-tiny;/* atan(-0,-anything) =-pi */
+ }
+ }
+ /* when x = 0 */
+ if(ix==0) return (hy<0)? -pi_o_2-tiny: pi_o_2+tiny;
+
+ /* when x is INF */
+ if(ix==0x7f800000) {
+ if(iy==0x7f800000) {
+ switch(m) {
+ case 0: return pi_o_4+tiny;/* atan(+INF,+INF) */
+ case 1: return -pi_o_4-tiny;/* atan(-INF,+INF) */
+ case 2: return (float)3.0*pi_o_4+tiny;/*atan(+INF,-INF)*/
+ case 3: return (float)-3.0*pi_o_4-tiny;/*atan(-INF,-INF)*/
+ }
+ } else {
+ switch(m) {
+ case 0: return zero ; /* atan(+...,+INF) */
+ case 1: return -zero ; /* atan(-...,+INF) */
+ case 2: return pi+tiny ; /* atan(+...,-INF) */
+ case 3: return -pi-tiny ; /* atan(-...,-INF) */
+ }
+ }
+ }
+ /* when y is INF */
+ if(iy==0x7f800000) return (hy<0)? -pi_o_2-tiny: pi_o_2+tiny;
+
+ /* compute y/x */
+ k = (iy-ix)>>23;
+ if(k > 60) z=pi_o_2+(float)0.5*pi_lo; /* |y/x| > 2**60 */
+ else if(hx<0&&k<-60) z=0.0; /* |y|/x < -2**60 */
+ else z=atanf(fabsf(y/x)); /* safe to do y/x */
+ switch (m) {
+ case 0: return z ; /* atan(+,+) */
+ case 1: {
+ u_int32_t zh;
+ GET_FLOAT_WORD(zh,z);
+ SET_FLOAT_WORD(z,zh ^ 0x80000000);
+ }
+ return z ; /* atan(-,+) */
+ case 2: return pi-(z-pi_lo);/* atan(+,-) */
+ default: /* case 3 */
+ return (z-pi_lo)-pi;/* atan(-,-) */
+ }
+}
diff --git a/lib/msun/src/e_atanh.c b/lib/msun/src/e_atanh.c
new file mode 100644
index 0000000..9a89669
--- /dev/null
+++ b/lib/msun/src/e_atanh.c
@@ -0,0 +1,63 @@
+
+/* @(#)e_atanh.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/* __ieee754_atanh(x)
+ * Method :
+ * 1.Reduced x to positive by atanh(-x) = -atanh(x)
+ * 2.For x>=0.5
+ * 1 2x x
+ * atanh(x) = --- * log(1 + -------) = 0.5 * log1p(2 * --------)
+ * 2 1 - x 1 - x
+ *
+ * For x<0.5
+ * atanh(x) = 0.5*log1p(2x+2x*x/(1-x))
+ *
+ * Special cases:
+ * atanh(x) is NaN if |x| > 1 with signal;
+ * atanh(NaN) is that NaN with no signal;
+ * atanh(+-1) is +-INF with signal.
+ *
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+static const double one = 1.0, huge = 1e300;
+static const double zero = 0.0;
+
+double
+__ieee754_atanh(double x)
+{
+ double t;
+ int32_t hx,ix;
+ u_int32_t lx;
+ EXTRACT_WORDS(hx,lx,x);
+ ix = hx&0x7fffffff;
+ if ((ix|((lx|(-lx))>>31))>0x3ff00000) /* |x|>1 */
+ return (x-x)/(x-x);
+ if(ix==0x3ff00000)
+ return x/zero;
+ if(ix<0x3e300000&&(huge+x)>zero) return x; /* x<2**-28 */
+ SET_HIGH_WORD(x,ix);
+ if(ix<0x3fe00000) { /* x < 0.5 */
+ t = x+x;
+ t = 0.5*log1p(t+t*x/(one-x));
+ } else
+ t = 0.5*log1p((x+x)/(one-x));
+ if(hx>=0) return t; else return -t;
+}
diff --git a/lib/msun/src/e_atanhf.c b/lib/msun/src/e_atanhf.c
new file mode 100644
index 0000000..c7cf3e0
--- /dev/null
+++ b/lib/msun/src/e_atanhf.c
@@ -0,0 +1,46 @@
+/* e_atanhf.c -- float version of e_atanh.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+#include "math.h"
+#include "math_private.h"
+
+static const float one = 1.0, huge = 1e30;
+
+static const float zero = 0.0;
+
+float
+__ieee754_atanhf(float x)
+{
+ float t;
+ int32_t hx,ix;
+ GET_FLOAT_WORD(hx,x);
+ ix = hx&0x7fffffff;
+ if (ix>0x3f800000) /* |x|>1 */
+ return (x-x)/(x-x);
+ if(ix==0x3f800000)
+ return x/zero;
+ if(ix<0x31800000&&(huge+x)>zero) return x; /* x<2**-28 */
+ SET_FLOAT_WORD(x,ix);
+ if(ix<0x3f000000) { /* x < 0.5 */
+ t = x+x;
+ t = (float)0.5*log1pf(t+t*x/(one-x));
+ } else
+ t = (float)0.5*log1pf((x+x)/(one-x));
+ if(hx>=0) return t; else return -t;
+}
diff --git a/lib/msun/src/e_cosh.c b/lib/msun/src/e_cosh.c
new file mode 100644
index 0000000..f8a2b9b
--- /dev/null
+++ b/lib/msun/src/e_cosh.c
@@ -0,0 +1,86 @@
+
+/* @(#)e_cosh.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/* __ieee754_cosh(x)
+ * Method :
+ * mathematically cosh(x) if defined to be (exp(x)+exp(-x))/2
+ * 1. Replace x by |x| (cosh(x) = cosh(-x)).
+ * 2.
+ * [ exp(x) - 1 ]^2
+ * 0 <= x <= ln2/2 : cosh(x) := 1 + -------------------
+ * 2*exp(x)
+ *
+ * exp(x) + 1/exp(x)
+ * ln2/2 <= x <= 22 : cosh(x) := -------------------
+ * 2
+ * 22 <= x <= lnovft : cosh(x) := exp(x)/2
+ * lnovft <= x <= ln2ovft: cosh(x) := exp(x/2)/2 * exp(x/2)
+ * ln2ovft < x : cosh(x) := huge*huge (overflow)
+ *
+ * Special cases:
+ * cosh(x) is |x| if x is +INF, -INF, or NaN.
+ * only cosh(0)=1 is exact for finite x.
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+static const double one = 1.0, half=0.5, huge = 1.0e300;
+
+double
+__ieee754_cosh(double x)
+{
+ double t,w;
+ int32_t ix;
+ u_int32_t lx;
+
+ /* High word of |x|. */
+ GET_HIGH_WORD(ix,x);
+ ix &= 0x7fffffff;
+
+ /* x is INF or NaN */
+ if(ix>=0x7ff00000) return x*x;
+
+ /* |x| in [0,0.5*ln2], return 1+expm1(|x|)^2/(2*exp(|x|)) */
+ if(ix<0x3fd62e43) {
+ t = expm1(fabs(x));
+ w = one+t;
+ if (ix<0x3c800000) return w; /* cosh(tiny) = 1 */
+ return one+(t*t)/(w+w);
+ }
+
+ /* |x| in [0.5*ln2,22], return (exp(|x|)+1/exp(|x|)/2; */
+ if (ix < 0x40360000) {
+ t = __ieee754_exp(fabs(x));
+ return half*t+half/t;
+ }
+
+ /* |x| in [22, log(maxdouble)] return half*exp(|x|) */
+ if (ix < 0x40862E42) return half*__ieee754_exp(fabs(x));
+
+ /* |x| in [log(maxdouble), overflowthresold] */
+ GET_LOW_WORD(lx,x);
+ if (ix<0x408633CE ||
+ ((ix==0x408633ce)&&(lx<=(u_int32_t)0x8fb9f87d))) {
+ w = __ieee754_exp(half*fabs(x));
+ t = half*w;
+ return t*w;
+ }
+
+ /* |x| > overflowthresold, cosh(x) overflow */
+ return huge*huge;
+}
diff --git a/lib/msun/src/e_coshf.c b/lib/msun/src/e_coshf.c
new file mode 100644
index 0000000..ebd659e
--- /dev/null
+++ b/lib/msun/src/e_coshf.c
@@ -0,0 +1,63 @@
+/* e_coshf.c -- float version of e_cosh.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+#include "math.h"
+#include "math_private.h"
+
+static const float one = 1.0, half=0.5, huge = 1.0e30;
+
+float
+__ieee754_coshf(float x)
+{
+ float t,w;
+ int32_t ix;
+
+ GET_FLOAT_WORD(ix,x);
+ ix &= 0x7fffffff;
+
+ /* x is INF or NaN */
+ if(ix>=0x7f800000) return x*x;
+
+ /* |x| in [0,0.5*ln2], return 1+expm1(|x|)^2/(2*exp(|x|)) */
+ if(ix<0x3eb17218) {
+ t = expm1f(fabsf(x));
+ w = one+t;
+ if (ix<0x39800000) return one; /* cosh(tiny) = 1 */
+ return one+(t*t)/(w+w);
+ }
+
+ /* |x| in [0.5*ln2,9], return (exp(|x|)+1/exp(|x|))/2; */
+ if (ix < 0x41100000) {
+ t = __ieee754_expf(fabsf(x));
+ return half*t+half/t;
+ }
+
+ /* |x| in [9, log(maxfloat)] return half*exp(|x|) */
+ if (ix < 0x42b17217) return half*__ieee754_expf(fabsf(x));
+
+ /* |x| in [log(maxfloat), overflowthresold] */
+ if (ix<=0x42b2d4fc) {
+ w = __ieee754_expf(half*fabsf(x));
+ t = half*w;
+ return t*w;
+ }
+
+ /* |x| > overflowthresold, cosh(x) overflow */
+ return huge*huge;
+}
diff --git a/lib/msun/src/e_exp.c b/lib/msun/src/e_exp.c
new file mode 100644
index 0000000..60b8b2a
--- /dev/null
+++ b/lib/msun/src/e_exp.c
@@ -0,0 +1,159 @@
+
+/* @(#)e_exp.c 1.6 04/04/22 */
+/*
+ * ====================================================
+ * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/* __ieee754_exp(x)
+ * Returns the exponential of x.
+ *
+ * Method
+ * 1. Argument reduction:
+ * Reduce x to an r so that |r| <= 0.5*ln2 ~ 0.34658.
+ * Given x, find r and integer k such that
+ *
+ * x = k*ln2 + r, |r| <= 0.5*ln2.
+ *
+ * Here r will be represented as r = hi-lo for better
+ * accuracy.
+ *
+ * 2. Approximation of exp(r) by a special rational function on
+ * the interval [0,0.34658]:
+ * Write
+ * R(r**2) = r*(exp(r)+1)/(exp(r)-1) = 2 + r*r/6 - r**4/360 + ...
+ * We use a special Remes algorithm on [0,0.34658] to generate
+ * a polynomial of degree 5 to approximate R. The maximum error
+ * of this polynomial approximation is bounded by 2**-59. In
+ * other words,
+ * R(z) ~ 2.0 + P1*z + P2*z**2 + P3*z**3 + P4*z**4 + P5*z**5
+ * (where z=r*r, and the values of P1 to P5 are listed below)
+ * and
+ * | 5 | -59
+ * | 2.0+P1*z+...+P5*z - R(z) | <= 2
+ * | |
+ * The computation of exp(r) thus becomes
+ * 2*r
+ * exp(r) = 1 + -------
+ * R - r
+ * r*R1(r)
+ * = 1 + r + ----------- (for better accuracy)
+ * 2 - R1(r)
+ * where
+ * 2 4 10
+ * R1(r) = r - (P1*r + P2*r + ... + P5*r ).
+ *
+ * 3. Scale back to obtain exp(x):
+ * From step 1, we have
+ * exp(x) = 2^k * exp(r)
+ *
+ * Special cases:
+ * exp(INF) is INF, exp(NaN) is NaN;
+ * exp(-INF) is 0, and
+ * for finite argument, only exp(0)=1 is exact.
+ *
+ * Accuracy:
+ * according to an error analysis, the error is always less than
+ * 1 ulp (unit in the last place).
+ *
+ * Misc. info.
+ * For IEEE double
+ * if x > 7.09782712893383973096e+02 then exp(x) overflow
+ * if x < -7.45133219101941108420e+02 then exp(x) underflow
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following
+ * constants. The decimal values may be used, provided that the
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+static const double
+one = 1.0,
+halF[2] = {0.5,-0.5,},
+huge = 1.0e+300,
+twom1000= 9.33263618503218878990e-302, /* 2**-1000=0x01700000,0*/
+o_threshold= 7.09782712893383973096e+02, /* 0x40862E42, 0xFEFA39EF */
+u_threshold= -7.45133219101941108420e+02, /* 0xc0874910, 0xD52D3051 */
+ln2HI[2] ={ 6.93147180369123816490e-01, /* 0x3fe62e42, 0xfee00000 */
+ -6.93147180369123816490e-01,},/* 0xbfe62e42, 0xfee00000 */
+ln2LO[2] ={ 1.90821492927058770002e-10, /* 0x3dea39ef, 0x35793c76 */
+ -1.90821492927058770002e-10,},/* 0xbdea39ef, 0x35793c76 */
+invln2 = 1.44269504088896338700e+00, /* 0x3ff71547, 0x652b82fe */
+P1 = 1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */
+P2 = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */
+P3 = 6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */
+P4 = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */
+P5 = 4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */
+
+
+double
+__ieee754_exp(double x) /* default IEEE double exp */
+{
+ double y,hi=0.0,lo=0.0,c,t;
+ int32_t k=0,xsb;
+ u_int32_t hx;
+
+ GET_HIGH_WORD(hx,x);
+ xsb = (hx>>31)&1; /* sign bit of x */
+ hx &= 0x7fffffff; /* high word of |x| */
+
+ /* filter out non-finite argument */
+ if(hx >= 0x40862E42) { /* if |x|>=709.78... */
+ if(hx>=0x7ff00000) {
+ u_int32_t lx;
+ GET_LOW_WORD(lx,x);
+ if(((hx&0xfffff)|lx)!=0)
+ return x+x; /* NaN */
+ else return (xsb==0)? x:0.0; /* exp(+-inf)={inf,0} */
+ }
+ if(x > o_threshold) return huge*huge; /* overflow */
+ if(x < u_threshold) return twom1000*twom1000; /* underflow */
+ }
+
+ /* argument reduction */
+ if(hx > 0x3fd62e42) { /* if |x| > 0.5 ln2 */
+ if(hx < 0x3FF0A2B2) { /* and |x| < 1.5 ln2 */
+ hi = x-ln2HI[xsb]; lo=ln2LO[xsb]; k = 1-xsb-xsb;
+ } else {
+ k = (int)(invln2*x+halF[xsb]);
+ t = k;
+ hi = x - t*ln2HI[0]; /* t*ln2HI is exact here */
+ lo = t*ln2LO[0];
+ }
+ x = hi - lo;
+ }
+ else if(hx < 0x3e300000) { /* when |x|<2**-28 */
+ if(huge+x>one) return one+x;/* trigger inexact */
+ }
+ else k = 0;
+
+ /* x is now in primary range */
+ t = x*x;
+ c = x - t*(P1+t*(P2+t*(P3+t*(P4+t*P5))));
+ if(k==0) return one-((x*c)/(c-2.0)-x);
+ else y = one-((lo-(x*c)/(2.0-c))-hi);
+ if(k >= -1021) {
+ u_int32_t hy;
+ GET_HIGH_WORD(hy,y);
+ SET_HIGH_WORD(y,hy+(k<<20)); /* add k to y's exponent */
+ return y;
+ } else {
+ u_int32_t hy;
+ GET_HIGH_WORD(hy,y);
+ SET_HIGH_WORD(y,hy+((k+1000)<<20)); /* add k to y's exponent */
+ return y*twom1000;
+ }
+}
diff --git a/lib/msun/src/e_expf.c b/lib/msun/src/e_expf.c
new file mode 100644
index 0000000..b9eb0fc
--- /dev/null
+++ b/lib/msun/src/e_expf.c
@@ -0,0 +1,95 @@
+/* e_expf.c -- float version of e_exp.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+#include "math.h"
+#include "math_private.h"
+
+static const float
+one = 1.0,
+halF[2] = {0.5,-0.5,},
+huge = 1.0e+30,
+twom100 = 7.8886090522e-31, /* 2**-100=0x0d800000 */
+o_threshold= 8.8721679688e+01, /* 0x42b17180 */
+u_threshold= -1.0397208405e+02, /* 0xc2cff1b5 */
+ln2HI[2] ={ 6.9314575195e-01, /* 0x3f317200 */
+ -6.9314575195e-01,}, /* 0xbf317200 */
+ln2LO[2] ={ 1.4286067653e-06, /* 0x35bfbe8e */
+ -1.4286067653e-06,}, /* 0xb5bfbe8e */
+invln2 = 1.4426950216e+00, /* 0x3fb8aa3b */
+P1 = 1.6666667163e-01, /* 0x3e2aaaab */
+P2 = -2.7777778450e-03, /* 0xbb360b61 */
+P3 = 6.6137559770e-05, /* 0x388ab355 */
+P4 = -1.6533901999e-06, /* 0xb5ddea0e */
+P5 = 4.1381369442e-08; /* 0x3331bb4c */
+
+float
+__ieee754_expf(float x) /* default IEEE double exp */
+{
+ float y,hi=0.0,lo=0.0,c,t;
+ int32_t k=0,xsb;
+ u_int32_t hx;
+
+ GET_FLOAT_WORD(hx,x);
+ xsb = (hx>>31)&1; /* sign bit of x */
+ hx &= 0x7fffffff; /* high word of |x| */
+
+ /* filter out non-finite argument */
+ if(hx >= 0x42b17218) { /* if |x|>=88.721... */
+ if(hx>0x7f800000)
+ return x+x; /* NaN */
+ if(hx==0x7f800000)
+ return (xsb==0)? x:0.0; /* exp(+-inf)={inf,0} */
+ if(x > o_threshold) return huge*huge; /* overflow */
+ if(x < u_threshold) return twom100*twom100; /* underflow */
+ }
+
+ /* argument reduction */
+ if(hx > 0x3eb17218) { /* if |x| > 0.5 ln2 */
+ if(hx < 0x3F851592) { /* and |x| < 1.5 ln2 */
+ hi = x-ln2HI[xsb]; lo=ln2LO[xsb]; k = 1-xsb-xsb;
+ } else {
+ k = invln2*x+halF[xsb];
+ t = k;
+ hi = x - t*ln2HI[0]; /* t*ln2HI is exact here */
+ lo = t*ln2LO[0];
+ }
+ x = hi - lo;
+ }
+ else if(hx < 0x31800000) { /* when |x|<2**-28 */
+ if(huge+x>one) return one+x;/* trigger inexact */
+ }
+ else k = 0;
+
+ /* x is now in primary range */
+ t = x*x;
+ c = x - t*(P1+t*(P2+t*(P3+t*(P4+t*P5))));
+ if(k==0) return one-((x*c)/(c-(float)2.0)-x);
+ else y = one-((lo-(x*c)/((float)2.0-c))-hi);
+ if(k >= -125) {
+ u_int32_t hy;
+ GET_FLOAT_WORD(hy,y);
+ SET_FLOAT_WORD(y,hy+(k<<23)); /* add k to y's exponent */
+ return y;
+ } else {
+ u_int32_t hy;
+ GET_FLOAT_WORD(hy,y);
+ SET_FLOAT_WORD(y,hy+((k+100)<<23)); /* add k to y's exponent */
+ return y*twom100;
+ }
+}
diff --git a/lib/msun/src/e_fmod.c b/lib/msun/src/e_fmod.c
new file mode 100644
index 0000000..b731ce1
--- /dev/null
+++ b/lib/msun/src/e_fmod.c
@@ -0,0 +1,133 @@
+
+/* @(#)e_fmod.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/*
+ * __ieee754_fmod(x,y)
+ * Return x mod y in exact arithmetic
+ * Method: shift and subtract
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+static const double one = 1.0, Zero[] = {0.0, -0.0,};
+
+double
+__ieee754_fmod(double x, double y)
+{
+ int32_t n,hx,hy,hz,ix,iy,sx,i;
+ u_int32_t lx,ly,lz;
+
+ EXTRACT_WORDS(hx,lx,x);
+ EXTRACT_WORDS(hy,ly,y);
+ sx = hx&0x80000000; /* sign of x */
+ hx ^=sx; /* |x| */
+ hy &= 0x7fffffff; /* |y| */
+
+ /* purge off exception values */
+ if((hy|ly)==0||(hx>=0x7ff00000)|| /* y=0,or x not finite */
+ ((hy|((ly|-ly)>>31))>0x7ff00000)) /* or y is NaN */
+ return (x*y)/(x*y);
+ if(hx<=hy) {
+ if((hx<hy)||(lx<ly)) return x; /* |x|<|y| return x */
+ if(lx==ly)
+ return Zero[(u_int32_t)sx>>31]; /* |x|=|y| return x*0*/
+ }
+
+ /* determine ix = ilogb(x) */
+ if(hx<0x00100000) { /* subnormal x */
+ if(hx==0) {
+ for (ix = -1043, i=lx; i>0; i<<=1) ix -=1;
+ } else {
+ for (ix = -1022,i=(hx<<11); i>0; i<<=1) ix -=1;
+ }
+ } else ix = (hx>>20)-1023;
+
+ /* determine iy = ilogb(y) */
+ if(hy<0x00100000) { /* subnormal y */
+ if(hy==0) {
+ for (iy = -1043, i=ly; i>0; i<<=1) iy -=1;
+ } else {
+ for (iy = -1022,i=(hy<<11); i>0; i<<=1) iy -=1;
+ }
+ } else iy = (hy>>20)-1023;
+
+ /* set up {hx,lx}, {hy,ly} and align y to x */
+ if(ix >= -1022)
+ hx = 0x00100000|(0x000fffff&hx);
+ else { /* subnormal x, shift x to normal */
+ n = -1022-ix;
+ if(n<=31) {
+ hx = (hx<<n)|(lx>>(32-n));
+ lx <<= n;
+ } else {
+ hx = lx<<(n-32);
+ lx = 0;
+ }
+ }
+ if(iy >= -1022)
+ hy = 0x00100000|(0x000fffff&hy);
+ else { /* subnormal y, shift y to normal */
+ n = -1022-iy;
+ if(n<=31) {
+ hy = (hy<<n)|(ly>>(32-n));
+ ly <<= n;
+ } else {
+ hy = ly<<(n-32);
+ ly = 0;
+ }
+ }
+
+ /* fix point fmod */
+ n = ix - iy;
+ while(n--) {
+ hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
+ if(hz<0){hx = hx+hx+(lx>>31); lx = lx+lx;}
+ else {
+ if((hz|lz)==0) /* return sign(x)*0 */
+ return Zero[(u_int32_t)sx>>31];
+ hx = hz+hz+(lz>>31); lx = lz+lz;
+ }
+ }
+ hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
+ if(hz>=0) {hx=hz;lx=lz;}
+
+ /* convert back to floating value and restore the sign */
+ if((hx|lx)==0) /* return sign(x)*0 */
+ return Zero[(u_int32_t)sx>>31];
+ while(hx<0x00100000) { /* normalize x */
+ hx = hx+hx+(lx>>31); lx = lx+lx;
+ iy -= 1;
+ }
+ if(iy>= -1022) { /* normalize output */
+ hx = ((hx-0x00100000)|((iy+1023)<<20));
+ INSERT_WORDS(x,hx|sx,lx);
+ } else { /* subnormal output */
+ n = -1022 - iy;
+ if(n<=20) {
+ lx = (lx>>n)|((u_int32_t)hx<<(32-n));
+ hx >>= n;
+ } else if (n<=31) {
+ lx = (hx<<(32-n))|(lx>>n); hx = sx;
+ } else {
+ lx = hx>>(n-32); hx = sx;
+ }
+ INSERT_WORDS(x,hx|sx,lx);
+ x *= one; /* create necessary signal */
+ }
+ return x; /* exact output */
+}
diff --git a/lib/msun/src/e_fmodf.c b/lib/msun/src/e_fmodf.c
new file mode 100644
index 0000000..e3865c4
--- /dev/null
+++ b/lib/msun/src/e_fmodf.c
@@ -0,0 +1,105 @@
+/* e_fmodf.c -- float version of e_fmod.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/*
+ * __ieee754_fmodf(x,y)
+ * Return x mod y in exact arithmetic
+ * Method: shift and subtract
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+static const float one = 1.0, Zero[] = {0.0, -0.0,};
+
+float
+__ieee754_fmodf(float x, float y)
+{
+ int32_t n,hx,hy,hz,ix,iy,sx,i;
+
+ GET_FLOAT_WORD(hx,x);
+ GET_FLOAT_WORD(hy,y);
+ sx = hx&0x80000000; /* sign of x */
+ hx ^=sx; /* |x| */
+ hy &= 0x7fffffff; /* |y| */
+
+ /* purge off exception values */
+ if(hy==0||(hx>=0x7f800000)|| /* y=0,or x not finite */
+ (hy>0x7f800000)) /* or y is NaN */
+ return (x*y)/(x*y);
+ if(hx<hy) return x; /* |x|<|y| return x */
+ if(hx==hy)
+ return Zero[(u_int32_t)sx>>31]; /* |x|=|y| return x*0*/
+
+ /* determine ix = ilogb(x) */
+ if(hx<0x00800000) { /* subnormal x */
+ for (ix = -126,i=(hx<<8); i>0; i<<=1) ix -=1;
+ } else ix = (hx>>23)-127;
+
+ /* determine iy = ilogb(y) */
+ if(hy<0x00800000) { /* subnormal y */
+ for (iy = -126,i=(hy<<8); i>=0; i<<=1) iy -=1;
+ } else iy = (hy>>23)-127;
+
+ /* set up {hx,lx}, {hy,ly} and align y to x */
+ if(ix >= -126)
+ hx = 0x00800000|(0x007fffff&hx);
+ else { /* subnormal x, shift x to normal */
+ n = -126-ix;
+ hx = hx<<n;
+ }
+ if(iy >= -126)
+ hy = 0x00800000|(0x007fffff&hy);
+ else { /* subnormal y, shift y to normal */
+ n = -126-iy;
+ hy = hy<<n;
+ }
+
+ /* fix point fmod */
+ n = ix - iy;
+ while(n--) {
+ hz=hx-hy;
+ if(hz<0){hx = hx+hx;}
+ else {
+ if(hz==0) /* return sign(x)*0 */
+ return Zero[(u_int32_t)sx>>31];
+ hx = hz+hz;
+ }
+ }
+ hz=hx-hy;
+ if(hz>=0) {hx=hz;}
+
+ /* convert back to floating value and restore the sign */
+ if(hx==0) /* return sign(x)*0 */
+ return Zero[(u_int32_t)sx>>31];
+ while(hx<0x00800000) { /* normalize x */
+ hx = hx+hx;
+ iy -= 1;
+ }
+ if(iy>= -126) { /* normalize output */
+ hx = ((hx-0x00800000)|((iy+127)<<23));
+ SET_FLOAT_WORD(x,hx|sx);
+ } else { /* subnormal output */
+ n = -126 - iy;
+ hx >>= n;
+ SET_FLOAT_WORD(x,hx|sx);
+ x *= one; /* create necessary signal */
+ }
+ return x; /* exact output */
+}
diff --git a/lib/msun/src/e_gamma.c b/lib/msun/src/e_gamma.c
new file mode 100644
index 0000000..e3ebd7c
--- /dev/null
+++ b/lib/msun/src/e_gamma.c
@@ -0,0 +1,34 @@
+
+/* @(#)e_gamma.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/* __ieee754_gamma(x)
+ * Return the logarithm of the Gamma function of x.
+ *
+ * Method: call __ieee754_gamma_r
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+extern int signgam;
+
+double
+__ieee754_gamma(double x)
+{
+ return __ieee754_gamma_r(x,&signgam);
+}
diff --git a/lib/msun/src/e_gamma_r.c b/lib/msun/src/e_gamma_r.c
new file mode 100644
index 0000000..48b981a
--- /dev/null
+++ b/lib/msun/src/e_gamma_r.c
@@ -0,0 +1,33 @@
+
+/* @(#)e_gamma_r.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/* __ieee754_gamma_r(x, signgamp)
+ * Reentrant version of the logarithm of the Gamma function
+ * with user provide pointer for the sign of Gamma(x).
+ *
+ * Method: See __ieee754_lgamma_r
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+double
+__ieee754_gamma_r(double x, int *signgamp)
+{
+ return __ieee754_lgamma_r(x,signgamp);
+}
diff --git a/lib/msun/src/e_gammaf.c b/lib/msun/src/e_gammaf.c
new file mode 100644
index 0000000..da31d9f
--- /dev/null
+++ b/lib/msun/src/e_gammaf.c
@@ -0,0 +1,35 @@
+/* e_gammaf.c -- float version of e_gamma.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/* __ieee754_gammaf(x)
+ * Return the logarithm of the Gamma function of x.
+ *
+ * Method: call __ieee754_gammaf_r
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+extern int signgam;
+
+float
+__ieee754_gammaf(float x)
+{
+ return __ieee754_gammaf_r(x,&signgam);
+}
diff --git a/lib/msun/src/e_gammaf_r.c b/lib/msun/src/e_gammaf_r.c
new file mode 100644
index 0000000..c14870d
--- /dev/null
+++ b/lib/msun/src/e_gammaf_r.c
@@ -0,0 +1,34 @@
+/* e_gammaf_r.c -- float version of e_gamma_r.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/* __ieee754_gammaf_r(x, signgamp)
+ * Reentrant version of the logarithm of the Gamma function
+ * with user provide pointer for the sign of Gamma(x).
+ *
+ * Method: See __ieee754_lgammaf_r
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+float
+__ieee754_gammaf_r(float x, int *signgamp)
+{
+ return __ieee754_lgammaf_r(x,signgamp);
+}
diff --git a/lib/msun/src/e_hypot.c b/lib/msun/src/e_hypot.c
new file mode 100644
index 0000000..e2f82ac
--- /dev/null
+++ b/lib/msun/src/e_hypot.c
@@ -0,0 +1,125 @@
+
+/* @(#)e_hypot.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/* __ieee754_hypot(x,y)
+ *
+ * Method :
+ * If (assume round-to-nearest) z=x*x+y*y
+ * has error less than sqrt(2)/2 ulp, than
+ * sqrt(z) has error less than 1 ulp (exercise).
+ *
+ * So, compute sqrt(x*x+y*y) with some care as
+ * follows to get the error below 1 ulp:
+ *
+ * Assume x>y>0;
+ * (if possible, set rounding to round-to-nearest)
+ * 1. if x > 2y use
+ * x1*x1+(y*y+(x2*(x+x1))) for x*x+y*y
+ * where x1 = x with lower 32 bits cleared, x2 = x-x1; else
+ * 2. if x <= 2y use
+ * t1*y1+((x-y)*(x-y)+(t1*y2+t2*y))
+ * where t1 = 2x with lower 32 bits cleared, t2 = 2x-t1,
+ * y1= y with lower 32 bits chopped, y2 = y-y1.
+ *
+ * NOTE: scaling may be necessary if some argument is too
+ * large or too tiny
+ *
+ * Special cases:
+ * hypot(x,y) is INF if x or y is +INF or -INF; else
+ * hypot(x,y) is NAN if x or y is NAN.
+ *
+ * Accuracy:
+ * hypot(x,y) returns sqrt(x^2+y^2) with error less
+ * than 1 ulps (units in the last place)
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+double
+__ieee754_hypot(double x, double y)
+{
+ double a=x,b=y,t1,t2,y1,y2,w;
+ int32_t j,k,ha,hb;
+
+ GET_HIGH_WORD(ha,x);
+ ha &= 0x7fffffff;
+ GET_HIGH_WORD(hb,y);
+ hb &= 0x7fffffff;
+ if(hb > ha) {a=y;b=x;j=ha; ha=hb;hb=j;} else {a=x;b=y;}
+ SET_HIGH_WORD(a,ha); /* a <- |a| */
+ SET_HIGH_WORD(b,hb); /* b <- |b| */
+ if((ha-hb)>0x3c00000) {return a+b;} /* x/y > 2**60 */
+ k=0;
+ if(ha > 0x5f300000) { /* a>2**500 */
+ if(ha >= 0x7ff00000) { /* Inf or NaN */
+ u_int32_t low;
+ w = a+b; /* for sNaN */
+ GET_LOW_WORD(low,a);
+ if(((ha&0xfffff)|low)==0) w = a;
+ GET_LOW_WORD(low,b);
+ if(((hb^0x7ff00000)|low)==0) w = b;
+ return w;
+ }
+ /* scale a and b by 2**-600 */
+ ha -= 0x25800000; hb -= 0x25800000; k += 600;
+ SET_HIGH_WORD(a,ha);
+ SET_HIGH_WORD(b,hb);
+ }
+ if(hb < 0x20b00000) { /* b < 2**-500 */
+ if(hb <= 0x000fffff) { /* subnormal b or 0 */
+ u_int32_t low;
+ GET_LOW_WORD(low,b);
+ if((hb|low)==0) return a;
+ t1=0;
+ SET_HIGH_WORD(t1,0x7fd00000); /* t1=2^1022 */
+ b *= t1;
+ a *= t1;
+ k -= 1022;
+ } else { /* scale a and b by 2^600 */
+ ha += 0x25800000; /* a *= 2^600 */
+ hb += 0x25800000; /* b *= 2^600 */
+ k -= 600;
+ SET_HIGH_WORD(a,ha);
+ SET_HIGH_WORD(b,hb);
+ }
+ }
+ /* medium size a and b */
+ w = a-b;
+ if (w>b) {
+ t1 = 0;
+ SET_HIGH_WORD(t1,ha);
+ t2 = a-t1;
+ w = sqrt(t1*t1-(b*(-b)-t2*(a+t1)));
+ } else {
+ a = a+a;
+ y1 = 0;
+ SET_HIGH_WORD(y1,hb);
+ y2 = b - y1;
+ t1 = 0;
+ SET_HIGH_WORD(t1,ha+0x00100000);
+ t2 = a - t1;
+ w = sqrt(t1*y1-(w*(-w)-(t1*y2+t2*b)));
+ }
+ if(k!=0) {
+ u_int32_t high;
+ t1 = 1.0;
+ GET_HIGH_WORD(high,t1);
+ SET_HIGH_WORD(t1,high+(k<<20));
+ return t1*w;
+ } else return w;
+}
diff --git a/lib/msun/src/e_hypotf.c b/lib/msun/src/e_hypotf.c
new file mode 100644
index 0000000..0624a39
--- /dev/null
+++ b/lib/msun/src/e_hypotf.c
@@ -0,0 +1,83 @@
+/* e_hypotf.c -- float version of e_hypot.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+#include "math.h"
+#include "math_private.h"
+
+float
+__ieee754_hypotf(float x, float y)
+{
+ float a=x,b=y,t1,t2,y1,y2,w;
+ int32_t j,k,ha,hb;
+
+ GET_FLOAT_WORD(ha,x);
+ ha &= 0x7fffffff;
+ GET_FLOAT_WORD(hb,y);
+ hb &= 0x7fffffff;
+ if(hb > ha) {a=y;b=x;j=ha; ha=hb;hb=j;} else {a=x;b=y;}
+ SET_FLOAT_WORD(a,ha); /* a <- |a| */
+ SET_FLOAT_WORD(b,hb); /* b <- |b| */
+ if((ha-hb)>0xf000000) {return a+b;} /* x/y > 2**30 */
+ k=0;
+ if(ha > 0x58800000) { /* a>2**50 */
+ if(ha >= 0x7f800000) { /* Inf or NaN */
+ w = a+b; /* for sNaN */
+ if(ha == 0x7f800000) w = a;
+ if(hb == 0x7f800000) w = b;
+ return w;
+ }
+ /* scale a and b by 2**-68 */
+ ha -= 0x22000000; hb -= 0x22000000; k += 68;
+ SET_FLOAT_WORD(a,ha);
+ SET_FLOAT_WORD(b,hb);
+ }
+ if(hb < 0x26800000) { /* b < 2**-50 */
+ if(hb <= 0x007fffff) { /* subnormal b or 0 */
+ if(hb==0) return a;
+ SET_FLOAT_WORD(t1,0x7e800000); /* t1=2^126 */
+ b *= t1;
+ a *= t1;
+ k -= 126;
+ } else { /* scale a and b by 2^68 */
+ ha += 0x22000000; /* a *= 2^68 */
+ hb += 0x22000000; /* b *= 2^68 */
+ k -= 68;
+ SET_FLOAT_WORD(a,ha);
+ SET_FLOAT_WORD(b,hb);
+ }
+ }
+ /* medium size a and b */
+ w = a-b;
+ if (w>b) {
+ SET_FLOAT_WORD(t1,ha&0xfffff000);
+ t2 = a-t1;
+ w = __ieee754_sqrtf(t1*t1-(b*(-b)-t2*(a+t1)));
+ } else {
+ a = a+a;
+ SET_FLOAT_WORD(y1,hb&0xfffff000);
+ y2 = b - y1;
+ SET_FLOAT_WORD(t1,ha+0x00800000);
+ t2 = a - t1;
+ w = __ieee754_sqrtf(t1*y1-(w*(-w)-(t1*y2+t2*b)));
+ }
+ if(k!=0) {
+ SET_FLOAT_WORD(t1,0x3f800000+(k<<23));
+ return t1*w;
+ } else return w;
+}
diff --git a/lib/msun/src/e_j0.c b/lib/msun/src/e_j0.c
new file mode 100644
index 0000000..493f0ef
--- /dev/null
+++ b/lib/msun/src/e_j0.c
@@ -0,0 +1,382 @@
+
+/* @(#)e_j0.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/* __ieee754_j0(x), __ieee754_y0(x)
+ * Bessel function of the first and second kinds of order zero.
+ * Method -- j0(x):
+ * 1. For tiny x, we use j0(x) = 1 - x^2/4 + x^4/64 - ...
+ * 2. Reduce x to |x| since j0(x)=j0(-x), and
+ * for x in (0,2)
+ * j0(x) = 1-z/4+ z^2*R0/S0, where z = x*x;
+ * (precision: |j0-1+z/4-z^2R0/S0 |<2**-63.67 )
+ * for x in (2,inf)
+ * j0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)-q0(x)*sin(x0))
+ * where x0 = x-pi/4. It is better to compute sin(x0),cos(x0)
+ * as follow:
+ * cos(x0) = cos(x)cos(pi/4)+sin(x)sin(pi/4)
+ * = 1/sqrt(2) * (cos(x) + sin(x))
+ * sin(x0) = sin(x)cos(pi/4)-cos(x)sin(pi/4)
+ * = 1/sqrt(2) * (sin(x) - cos(x))
+ * (To avoid cancellation, use
+ * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
+ * to compute the worse one.)
+ *
+ * 3 Special cases
+ * j0(nan)= nan
+ * j0(0) = 1
+ * j0(inf) = 0
+ *
+ * Method -- y0(x):
+ * 1. For x<2.
+ * Since
+ * y0(x) = 2/pi*(j0(x)*(ln(x/2)+Euler) + x^2/4 - ...)
+ * therefore y0(x)-2/pi*j0(x)*ln(x) is an even function.
+ * We use the following function to approximate y0,
+ * y0(x) = U(z)/V(z) + (2/pi)*(j0(x)*ln(x)), z= x^2
+ * where
+ * U(z) = u00 + u01*z + ... + u06*z^6
+ * V(z) = 1 + v01*z + ... + v04*z^4
+ * with absolute approximation error bounded by 2**-72.
+ * Note: For tiny x, U/V = u0 and j0(x)~1, hence
+ * y0(tiny) = u0 + (2/pi)*ln(tiny), (choose tiny<2**-27)
+ * 2. For x>=2.
+ * y0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)+q0(x)*sin(x0))
+ * where x0 = x-pi/4. It is better to compute sin(x0),cos(x0)
+ * by the method mentioned above.
+ * 3. Special cases: y0(0)=-inf, y0(x<0)=NaN, y0(inf)=0.
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+static double pzero(double), qzero(double);
+
+static const double
+huge = 1e300,
+one = 1.0,
+invsqrtpi= 5.64189583547756279280e-01, /* 0x3FE20DD7, 0x50429B6D */
+tpi = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */
+ /* R0/S0 on [0, 2.00] */
+R02 = 1.56249999999999947958e-02, /* 0x3F8FFFFF, 0xFFFFFFFD */
+R03 = -1.89979294238854721751e-04, /* 0xBF28E6A5, 0xB61AC6E9 */
+R04 = 1.82954049532700665670e-06, /* 0x3EBEB1D1, 0x0C503919 */
+R05 = -4.61832688532103189199e-09, /* 0xBE33D5E7, 0x73D63FCE */
+S01 = 1.56191029464890010492e-02, /* 0x3F8FFCE8, 0x82C8C2A4 */
+S02 = 1.16926784663337450260e-04, /* 0x3F1EA6D2, 0xDD57DBF4 */
+S03 = 5.13546550207318111446e-07, /* 0x3EA13B54, 0xCE84D5A9 */
+S04 = 1.16614003333790000205e-09; /* 0x3E1408BC, 0xF4745D8F */
+
+static const double zero = 0.0;
+
+double
+__ieee754_j0(double x)
+{
+ double z, s,c,ss,cc,r,u,v;
+ int32_t hx,ix;
+
+ GET_HIGH_WORD(hx,x);
+ ix = hx&0x7fffffff;
+ if(ix>=0x7ff00000) return one/(x*x);
+ x = fabs(x);
+ if(ix >= 0x40000000) { /* |x| >= 2.0 */
+ s = sin(x);
+ c = cos(x);
+ ss = s-c;
+ cc = s+c;
+ if(ix<0x7fe00000) { /* make sure x+x not overflow */
+ z = -cos(x+x);
+ if ((s*c)<zero) cc = z/ss;
+ else ss = z/cc;
+ }
+ /*
+ * j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x)
+ * y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x)
+ */
+ if(ix>0x48000000) z = (invsqrtpi*cc)/sqrt(x);
+ else {
+ u = pzero(x); v = qzero(x);
+ z = invsqrtpi*(u*cc-v*ss)/sqrt(x);
+ }
+ return z;
+ }
+ if(ix<0x3f200000) { /* |x| < 2**-13 */
+ if(huge+x>one) { /* raise inexact if x != 0 */
+ if(ix<0x3e400000) return one; /* |x|<2**-27 */
+ else return one - 0.25*x*x;
+ }
+ }
+ z = x*x;
+ r = z*(R02+z*(R03+z*(R04+z*R05)));
+ s = one+z*(S01+z*(S02+z*(S03+z*S04)));
+ if(ix < 0x3FF00000) { /* |x| < 1.00 */
+ return one + z*(-0.25+(r/s));
+ } else {
+ u = 0.5*x;
+ return((one+u)*(one-u)+z*(r/s));
+ }
+}
+
+static const double
+u00 = -7.38042951086872317523e-02, /* 0xBFB2E4D6, 0x99CBD01F */
+u01 = 1.76666452509181115538e-01, /* 0x3FC69D01, 0x9DE9E3FC */
+u02 = -1.38185671945596898896e-02, /* 0xBF8C4CE8, 0xB16CFA97 */
+u03 = 3.47453432093683650238e-04, /* 0x3F36C54D, 0x20B29B6B */
+u04 = -3.81407053724364161125e-06, /* 0xBECFFEA7, 0x73D25CAD */
+u05 = 1.95590137035022920206e-08, /* 0x3E550057, 0x3B4EABD4 */
+u06 = -3.98205194132103398453e-11, /* 0xBDC5E43D, 0x693FB3C8 */
+v01 = 1.27304834834123699328e-02, /* 0x3F8A1270, 0x91C9C71A */
+v02 = 7.60068627350353253702e-05, /* 0x3F13ECBB, 0xF578C6C1 */
+v03 = 2.59150851840457805467e-07, /* 0x3E91642D, 0x7FF202FD */
+v04 = 4.41110311332675467403e-10; /* 0x3DFE5018, 0x3BD6D9EF */
+
+double
+__ieee754_y0(double x)
+{
+ double z, s,c,ss,cc,u,v;
+ int32_t hx,ix,lx;
+
+ EXTRACT_WORDS(hx,lx,x);
+ ix = 0x7fffffff&hx;
+ /* Y0(NaN) is NaN, y0(-inf) is Nan, y0(inf) is 0 */
+ if(ix>=0x7ff00000) return one/(x+x*x);
+ if((ix|lx)==0) return -one/zero;
+ if(hx<0) return zero/zero;
+ if(ix >= 0x40000000) { /* |x| >= 2.0 */
+ /* y0(x) = sqrt(2/(pi*x))*(p0(x)*sin(x0)+q0(x)*cos(x0))
+ * where x0 = x-pi/4
+ * Better formula:
+ * cos(x0) = cos(x)cos(pi/4)+sin(x)sin(pi/4)
+ * = 1/sqrt(2) * (sin(x) + cos(x))
+ * sin(x0) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4)
+ * = 1/sqrt(2) * (sin(x) - cos(x))
+ * To avoid cancellation, use
+ * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
+ * to compute the worse one.
+ */
+ s = sin(x);
+ c = cos(x);
+ ss = s-c;
+ cc = s+c;
+ /*
+ * j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x)
+ * y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x)
+ */
+ if(ix<0x7fe00000) { /* make sure x+x not overflow */
+ z = -cos(x+x);
+ if ((s*c)<zero) cc = z/ss;
+ else ss = z/cc;
+ }
+ if(ix>0x48000000) z = (invsqrtpi*ss)/sqrt(x);
+ else {
+ u = pzero(x); v = qzero(x);
+ z = invsqrtpi*(u*ss+v*cc)/sqrt(x);
+ }
+ return z;
+ }
+ if(ix<=0x3e400000) { /* x < 2**-27 */
+ return(u00 + tpi*__ieee754_log(x));
+ }
+ z = x*x;
+ u = u00+z*(u01+z*(u02+z*(u03+z*(u04+z*(u05+z*u06)))));
+ v = one+z*(v01+z*(v02+z*(v03+z*v04)));
+ return(u/v + tpi*(__ieee754_j0(x)*__ieee754_log(x)));
+}
+
+/* The asymptotic expansions of pzero is
+ * 1 - 9/128 s^2 + 11025/98304 s^4 - ..., where s = 1/x.
+ * For x >= 2, We approximate pzero by
+ * pzero(x) = 1 + (R/S)
+ * where R = pR0 + pR1*s^2 + pR2*s^4 + ... + pR5*s^10
+ * S = 1 + pS0*s^2 + ... + pS4*s^10
+ * and
+ * | pzero(x)-1-R/S | <= 2 ** ( -60.26)
+ */
+static const double pR8[6] = { /* for x in [inf, 8]=1/[0,0.125] */
+ 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */
+ -7.03124999999900357484e-02, /* 0xBFB1FFFF, 0xFFFFFD32 */
+ -8.08167041275349795626e+00, /* 0xC02029D0, 0xB44FA779 */
+ -2.57063105679704847262e+02, /* 0xC0701102, 0x7B19E863 */
+ -2.48521641009428822144e+03, /* 0xC0A36A6E, 0xCD4DCAFC */
+ -5.25304380490729545272e+03, /* 0xC0B4850B, 0x36CC643D */
+};
+static const double pS8[5] = {
+ 1.16534364619668181717e+02, /* 0x405D2233, 0x07A96751 */
+ 3.83374475364121826715e+03, /* 0x40ADF37D, 0x50596938 */
+ 4.05978572648472545552e+04, /* 0x40E3D2BB, 0x6EB6B05F */
+ 1.16752972564375915681e+05, /* 0x40FC810F, 0x8F9FA9BD */
+ 4.76277284146730962675e+04, /* 0x40E74177, 0x4F2C49DC */
+};
+
+static const double pR5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */
+ -1.14125464691894502584e-11, /* 0xBDA918B1, 0x47E495CC */
+ -7.03124940873599280078e-02, /* 0xBFB1FFFF, 0xE69AFBC6 */
+ -4.15961064470587782438e+00, /* 0xC010A370, 0xF90C6BBF */
+ -6.76747652265167261021e+01, /* 0xC050EB2F, 0x5A7D1783 */
+ -3.31231299649172967747e+02, /* 0xC074B3B3, 0x6742CC63 */
+ -3.46433388365604912451e+02, /* 0xC075A6EF, 0x28A38BD7 */
+};
+static const double pS5[5] = {
+ 6.07539382692300335975e+01, /* 0x404E6081, 0x0C98C5DE */
+ 1.05125230595704579173e+03, /* 0x40906D02, 0x5C7E2864 */
+ 5.97897094333855784498e+03, /* 0x40B75AF8, 0x8FBE1D60 */
+ 9.62544514357774460223e+03, /* 0x40C2CCB8, 0xFA76FA38 */
+ 2.40605815922939109441e+03, /* 0x40A2CC1D, 0xC70BE864 */
+};
+
+static const double pR3[6] = {/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */
+ -2.54704601771951915620e-09, /* 0xBE25E103, 0x6FE1AA86 */
+ -7.03119616381481654654e-02, /* 0xBFB1FFF6, 0xF7C0E24B */
+ -2.40903221549529611423e+00, /* 0xC00345B2, 0xAEA48074 */
+ -2.19659774734883086467e+01, /* 0xC035F74A, 0x4CB94E14 */
+ -5.80791704701737572236e+01, /* 0xC04D0A22, 0x420A1A45 */
+ -3.14479470594888503854e+01, /* 0xC03F72AC, 0xA892D80F */
+};
+static const double pS3[5] = {
+ 3.58560338055209726349e+01, /* 0x4041ED92, 0x84077DD3 */
+ 3.61513983050303863820e+02, /* 0x40769839, 0x464A7C0E */
+ 1.19360783792111533330e+03, /* 0x4092A66E, 0x6D1061D6 */
+ 1.12799679856907414432e+03, /* 0x40919FFC, 0xB8C39B7E */
+ 1.73580930813335754692e+02, /* 0x4065B296, 0xFC379081 */
+};
+
+static const double pR2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */
+ -8.87534333032526411254e-08, /* 0xBE77D316, 0xE927026D */
+ -7.03030995483624743247e-02, /* 0xBFB1FF62, 0x495E1E42 */
+ -1.45073846780952986357e+00, /* 0xBFF73639, 0x8A24A843 */
+ -7.63569613823527770791e+00, /* 0xC01E8AF3, 0xEDAFA7F3 */
+ -1.11931668860356747786e+01, /* 0xC02662E6, 0xC5246303 */
+ -3.23364579351335335033e+00, /* 0xC009DE81, 0xAF8FE70F */
+};
+static const double pS2[5] = {
+ 2.22202997532088808441e+01, /* 0x40363865, 0x908B5959 */
+ 1.36206794218215208048e+02, /* 0x4061069E, 0x0EE8878F */
+ 2.70470278658083486789e+02, /* 0x4070E786, 0x42EA079B */
+ 1.53875394208320329881e+02, /* 0x40633C03, 0x3AB6FAFF */
+ 1.46576176948256193810e+01, /* 0x402D50B3, 0x44391809 */
+};
+
+ static double pzero(double x)
+{
+ const double *p,*q;
+ double z,r,s;
+ int32_t ix;
+ GET_HIGH_WORD(ix,x);
+ ix &= 0x7fffffff;
+ if(ix>=0x40200000) {p = pR8; q= pS8;}
+ else if(ix>=0x40122E8B){p = pR5; q= pS5;}
+ else if(ix>=0x4006DB6D){p = pR3; q= pS3;}
+ else if(ix>=0x40000000){p = pR2; q= pS2;}
+ z = one/(x*x);
+ r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))));
+ s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4]))));
+ return one+ r/s;
+}
+
+
+/* For x >= 8, the asymptotic expansions of qzero is
+ * -1/8 s + 75/1024 s^3 - ..., where s = 1/x.
+ * We approximate pzero by
+ * qzero(x) = s*(-1.25 + (R/S))
+ * where R = qR0 + qR1*s^2 + qR2*s^4 + ... + qR5*s^10
+ * S = 1 + qS0*s^2 + ... + qS5*s^12
+ * and
+ * | qzero(x)/s +1.25-R/S | <= 2 ** ( -61.22)
+ */
+static const double qR8[6] = { /* for x in [inf, 8]=1/[0,0.125] */
+ 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */
+ 7.32421874999935051953e-02, /* 0x3FB2BFFF, 0xFFFFFE2C */
+ 1.17682064682252693899e+01, /* 0x40278952, 0x5BB334D6 */
+ 5.57673380256401856059e+02, /* 0x40816D63, 0x15301825 */
+ 8.85919720756468632317e+03, /* 0x40C14D99, 0x3E18F46D */
+ 3.70146267776887834771e+04, /* 0x40E212D4, 0x0E901566 */
+};
+static const double qS8[6] = {
+ 1.63776026895689824414e+02, /* 0x406478D5, 0x365B39BC */
+ 8.09834494656449805916e+03, /* 0x40BFA258, 0x4E6B0563 */
+ 1.42538291419120476348e+05, /* 0x41016652, 0x54D38C3F */
+ 8.03309257119514397345e+05, /* 0x412883DA, 0x83A52B43 */
+ 8.40501579819060512818e+05, /* 0x4129A66B, 0x28DE0B3D */
+ -3.43899293537866615225e+05, /* 0xC114FD6D, 0x2C9530C5 */
+};
+
+static const double qR5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */
+ 1.84085963594515531381e-11, /* 0x3DB43D8F, 0x29CC8CD9 */
+ 7.32421766612684765896e-02, /* 0x3FB2BFFF, 0xD172B04C */
+ 5.83563508962056953777e+00, /* 0x401757B0, 0xB9953DD3 */
+ 1.35111577286449829671e+02, /* 0x4060E392, 0x0A8788E9 */
+ 1.02724376596164097464e+03, /* 0x40900CF9, 0x9DC8C481 */
+ 1.98997785864605384631e+03, /* 0x409F17E9, 0x53C6E3A6 */
+};
+static const double qS5[6] = {
+ 8.27766102236537761883e+01, /* 0x4054B1B3, 0xFB5E1543 */
+ 2.07781416421392987104e+03, /* 0x40A03BA0, 0xDA21C0CE */
+ 1.88472887785718085070e+04, /* 0x40D267D2, 0x7B591E6D */
+ 5.67511122894947329769e+04, /* 0x40EBB5E3, 0x97E02372 */
+ 3.59767538425114471465e+04, /* 0x40E19118, 0x1F7A54A0 */
+ -5.35434275601944773371e+03, /* 0xC0B4EA57, 0xBEDBC609 */
+};
+
+static const double qR3[6] = {/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */
+ 4.37741014089738620906e-09, /* 0x3E32CD03, 0x6ADECB82 */
+ 7.32411180042911447163e-02, /* 0x3FB2BFEE, 0x0E8D0842 */
+ 3.34423137516170720929e+00, /* 0x400AC0FC, 0x61149CF5 */
+ 4.26218440745412650017e+01, /* 0x40454F98, 0x962DAEDD */
+ 1.70808091340565596283e+02, /* 0x406559DB, 0xE25EFD1F */
+ 1.66733948696651168575e+02, /* 0x4064D77C, 0x81FA21E0 */
+};
+static const double qS3[6] = {
+ 4.87588729724587182091e+01, /* 0x40486122, 0xBFE343A6 */
+ 7.09689221056606015736e+02, /* 0x40862D83, 0x86544EB3 */
+ 3.70414822620111362994e+03, /* 0x40ACF04B, 0xE44DFC63 */
+ 6.46042516752568917582e+03, /* 0x40B93C6C, 0xD7C76A28 */
+ 2.51633368920368957333e+03, /* 0x40A3A8AA, 0xD94FB1C0 */
+ -1.49247451836156386662e+02, /* 0xC062A7EB, 0x201CF40F */
+};
+
+static const double qR2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */
+ 1.50444444886983272379e-07, /* 0x3E84313B, 0x54F76BDB */
+ 7.32234265963079278272e-02, /* 0x3FB2BEC5, 0x3E883E34 */
+ 1.99819174093815998816e+00, /* 0x3FFFF897, 0xE727779C */
+ 1.44956029347885735348e+01, /* 0x402CFDBF, 0xAAF96FE5 */
+ 3.16662317504781540833e+01, /* 0x403FAA8E, 0x29FBDC4A */
+ 1.62527075710929267416e+01, /* 0x403040B1, 0x71814BB4 */
+};
+static const double qS2[6] = {
+ 3.03655848355219184498e+01, /* 0x403E5D96, 0xF7C07AED */
+ 2.69348118608049844624e+02, /* 0x4070D591, 0xE4D14B40 */
+ 8.44783757595320139444e+02, /* 0x408A6645, 0x22B3BF22 */
+ 8.82935845112488550512e+02, /* 0x408B977C, 0x9C5CC214 */
+ 2.12666388511798828631e+02, /* 0x406A9553, 0x0E001365 */
+ -5.31095493882666946917e+00, /* 0xC0153E6A, 0xF8B32931 */
+};
+
+ static double qzero(double x)
+{
+ const double *p,*q;
+ double s,r,z;
+ int32_t ix;
+ GET_HIGH_WORD(ix,x);
+ ix &= 0x7fffffff;
+ if(ix>=0x40200000) {p = qR8; q= qS8;}
+ else if(ix>=0x40122E8B){p = qR5; q= qS5;}
+ else if(ix>=0x4006DB6D){p = qR3; q= qS3;}
+ else if(ix>=0x40000000){p = qR2; q= qS2;}
+ z = one/(x*x);
+ r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))));
+ s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5])))));
+ return (-.125 + r/s)/x;
+}
diff --git a/lib/msun/src/e_j0f.c b/lib/msun/src/e_j0f.c
new file mode 100644
index 0000000..6d98582
--- /dev/null
+++ b/lib/msun/src/e_j0f.c
@@ -0,0 +1,338 @@
+/* e_j0f.c -- float version of e_j0.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+#include "math.h"
+#include "math_private.h"
+
+static float pzerof(float), qzerof(float);
+
+static const float
+huge = 1e30,
+one = 1.0,
+invsqrtpi= 5.6418961287e-01, /* 0x3f106ebb */
+tpi = 6.3661974669e-01, /* 0x3f22f983 */
+ /* R0/S0 on [0, 2.00] */
+R02 = 1.5625000000e-02, /* 0x3c800000 */
+R03 = -1.8997929874e-04, /* 0xb947352e */
+R04 = 1.8295404516e-06, /* 0x35f58e88 */
+R05 = -4.6183270541e-09, /* 0xb19eaf3c */
+S01 = 1.5619102865e-02, /* 0x3c7fe744 */
+S02 = 1.1692678527e-04, /* 0x38f53697 */
+S03 = 5.1354652442e-07, /* 0x3509daa6 */
+S04 = 1.1661400734e-09; /* 0x30a045e8 */
+
+static const float zero = 0.0;
+
+float
+__ieee754_j0f(float x)
+{
+ float z, s,c,ss,cc,r,u,v;
+ int32_t hx,ix;
+
+ GET_FLOAT_WORD(hx,x);
+ ix = hx&0x7fffffff;
+ if(ix>=0x7f800000) return one/(x*x);
+ x = fabsf(x);
+ if(ix >= 0x40000000) { /* |x| >= 2.0 */
+ s = sinf(x);
+ c = cosf(x);
+ ss = s-c;
+ cc = s+c;
+ if(ix<0x7f000000) { /* make sure x+x not overflow */
+ z = -cosf(x+x);
+ if ((s*c)<zero) cc = z/ss;
+ else ss = z/cc;
+ }
+ /*
+ * j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x)
+ * y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x)
+ */
+ if(ix>0x80000000) z = (invsqrtpi*cc)/sqrtf(x);
+ else {
+ u = pzerof(x); v = qzerof(x);
+ z = invsqrtpi*(u*cc-v*ss)/sqrtf(x);
+ }
+ return z;
+ }
+ if(ix<0x39000000) { /* |x| < 2**-13 */
+ if(huge+x>one) { /* raise inexact if x != 0 */
+ if(ix<0x32000000) return one; /* |x|<2**-27 */
+ else return one - (float)0.25*x*x;
+ }
+ }
+ z = x*x;
+ r = z*(R02+z*(R03+z*(R04+z*R05)));
+ s = one+z*(S01+z*(S02+z*(S03+z*S04)));
+ if(ix < 0x3F800000) { /* |x| < 1.00 */
+ return one + z*((float)-0.25+(r/s));
+ } else {
+ u = (float)0.5*x;
+ return((one+u)*(one-u)+z*(r/s));
+ }
+}
+
+static const float
+u00 = -7.3804296553e-02, /* 0xbd9726b5 */
+u01 = 1.7666645348e-01, /* 0x3e34e80d */
+u02 = -1.3818567619e-02, /* 0xbc626746 */
+u03 = 3.4745343146e-04, /* 0x39b62a69 */
+u04 = -3.8140706238e-06, /* 0xb67ff53c */
+u05 = 1.9559013964e-08, /* 0x32a802ba */
+u06 = -3.9820518410e-11, /* 0xae2f21eb */
+v01 = 1.2730483897e-02, /* 0x3c509385 */
+v02 = 7.6006865129e-05, /* 0x389f65e0 */
+v03 = 2.5915085189e-07, /* 0x348b216c */
+v04 = 4.4111031494e-10; /* 0x2ff280c2 */
+
+float
+__ieee754_y0f(float x)
+{
+ float z, s,c,ss,cc,u,v;
+ int32_t hx,ix;
+
+ GET_FLOAT_WORD(hx,x);
+ ix = 0x7fffffff&hx;
+ /* Y0(NaN) is NaN, y0(-inf) is Nan, y0(inf) is 0 */
+ if(ix>=0x7f800000) return one/(x+x*x);
+ if(ix==0) return -one/zero;
+ if(hx<0) return zero/zero;
+ if(ix >= 0x40000000) { /* |x| >= 2.0 */
+ /* y0(x) = sqrt(2/(pi*x))*(p0(x)*sin(x0)+q0(x)*cos(x0))
+ * where x0 = x-pi/4
+ * Better formula:
+ * cos(x0) = cos(x)cos(pi/4)+sin(x)sin(pi/4)
+ * = 1/sqrt(2) * (sin(x) + cos(x))
+ * sin(x0) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4)
+ * = 1/sqrt(2) * (sin(x) - cos(x))
+ * To avoid cancellation, use
+ * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
+ * to compute the worse one.
+ */
+ s = sinf(x);
+ c = cosf(x);
+ ss = s-c;
+ cc = s+c;
+ /*
+ * j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x)
+ * y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x)
+ */
+ if(ix<0x7f000000) { /* make sure x+x not overflow */
+ z = -cosf(x+x);
+ if ((s*c)<zero) cc = z/ss;
+ else ss = z/cc;
+ }
+ if(ix>0x80000000) z = (invsqrtpi*ss)/sqrtf(x);
+ else {
+ u = pzerof(x); v = qzerof(x);
+ z = invsqrtpi*(u*ss+v*cc)/sqrtf(x);
+ }
+ return z;
+ }
+ if(ix<=0x32000000) { /* x < 2**-27 */
+ return(u00 + tpi*__ieee754_logf(x));
+ }
+ z = x*x;
+ u = u00+z*(u01+z*(u02+z*(u03+z*(u04+z*(u05+z*u06)))));
+ v = one+z*(v01+z*(v02+z*(v03+z*v04)));
+ return(u/v + tpi*(__ieee754_j0f(x)*__ieee754_logf(x)));
+}
+
+/* The asymptotic expansions of pzero is
+ * 1 - 9/128 s^2 + 11025/98304 s^4 - ..., where s = 1/x.
+ * For x >= 2, We approximate pzero by
+ * pzero(x) = 1 + (R/S)
+ * where R = pR0 + pR1*s^2 + pR2*s^4 + ... + pR5*s^10
+ * S = 1 + pS0*s^2 + ... + pS4*s^10
+ * and
+ * | pzero(x)-1-R/S | <= 2 ** ( -60.26)
+ */
+static const float pR8[6] = { /* for x in [inf, 8]=1/[0,0.125] */
+ 0.0000000000e+00, /* 0x00000000 */
+ -7.0312500000e-02, /* 0xbd900000 */
+ -8.0816707611e+00, /* 0xc1014e86 */
+ -2.5706311035e+02, /* 0xc3808814 */
+ -2.4852163086e+03, /* 0xc51b5376 */
+ -5.2530439453e+03, /* 0xc5a4285a */
+};
+static const float pS8[5] = {
+ 1.1653436279e+02, /* 0x42e91198 */
+ 3.8337448730e+03, /* 0x456f9beb */
+ 4.0597855469e+04, /* 0x471e95db */
+ 1.1675296875e+05, /* 0x47e4087c */
+ 4.7627726562e+04, /* 0x473a0bba */
+};
+static const float pR5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */
+ -1.1412546255e-11, /* 0xad48c58a */
+ -7.0312492549e-02, /* 0xbd8fffff */
+ -4.1596107483e+00, /* 0xc0851b88 */
+ -6.7674766541e+01, /* 0xc287597b */
+ -3.3123129272e+02, /* 0xc3a59d9b */
+ -3.4643338013e+02, /* 0xc3ad3779 */
+};
+static const float pS5[5] = {
+ 6.0753936768e+01, /* 0x42730408 */
+ 1.0512523193e+03, /* 0x44836813 */
+ 5.9789707031e+03, /* 0x45bad7c4 */
+ 9.6254453125e+03, /* 0x461665c8 */
+ 2.4060581055e+03, /* 0x451660ee */
+};
+
+static const float pR3[6] = {/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */
+ -2.5470459075e-09, /* 0xb12f081b */
+ -7.0311963558e-02, /* 0xbd8fffb8 */
+ -2.4090321064e+00, /* 0xc01a2d95 */
+ -2.1965976715e+01, /* 0xc1afba52 */
+ -5.8079170227e+01, /* 0xc2685112 */
+ -3.1447946548e+01, /* 0xc1fb9565 */
+};
+static const float pS3[5] = {
+ 3.5856033325e+01, /* 0x420f6c94 */
+ 3.6151397705e+02, /* 0x43b4c1ca */
+ 1.1936077881e+03, /* 0x44953373 */
+ 1.1279968262e+03, /* 0x448cffe6 */
+ 1.7358093262e+02, /* 0x432d94b8 */
+};
+
+static const float pR2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */
+ -8.8753431271e-08, /* 0xb3be98b7 */
+ -7.0303097367e-02, /* 0xbd8ffb12 */
+ -1.4507384300e+00, /* 0xbfb9b1cc */
+ -7.6356959343e+00, /* 0xc0f4579f */
+ -1.1193166733e+01, /* 0xc1331736 */
+ -3.2336456776e+00, /* 0xc04ef40d */
+};
+static const float pS2[5] = {
+ 2.2220300674e+01, /* 0x41b1c32d */
+ 1.3620678711e+02, /* 0x430834f0 */
+ 2.7047027588e+02, /* 0x43873c32 */
+ 1.5387539673e+02, /* 0x4319e01a */
+ 1.4657617569e+01, /* 0x416a859a */
+};
+
+ static float pzerof(float x)
+{
+ const float *p,*q;
+ float z,r,s;
+ int32_t ix;
+ GET_FLOAT_WORD(ix,x);
+ ix &= 0x7fffffff;
+ if(ix>=0x41000000) {p = pR8; q= pS8;}
+ else if(ix>=0x40f71c58){p = pR5; q= pS5;}
+ else if(ix>=0x4036db68){p = pR3; q= pS3;}
+ else if(ix>=0x40000000){p = pR2; q= pS2;}
+ z = one/(x*x);
+ r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))));
+ s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4]))));
+ return one+ r/s;
+}
+
+
+/* For x >= 8, the asymptotic expansions of qzero is
+ * -1/8 s + 75/1024 s^3 - ..., where s = 1/x.
+ * We approximate pzero by
+ * qzero(x) = s*(-1.25 + (R/S))
+ * where R = qR0 + qR1*s^2 + qR2*s^4 + ... + qR5*s^10
+ * S = 1 + qS0*s^2 + ... + qS5*s^12
+ * and
+ * | qzero(x)/s +1.25-R/S | <= 2 ** ( -61.22)
+ */
+static const float qR8[6] = { /* for x in [inf, 8]=1/[0,0.125] */
+ 0.0000000000e+00, /* 0x00000000 */
+ 7.3242187500e-02, /* 0x3d960000 */
+ 1.1768206596e+01, /* 0x413c4a93 */
+ 5.5767340088e+02, /* 0x440b6b19 */
+ 8.8591972656e+03, /* 0x460a6cca */
+ 3.7014625000e+04, /* 0x471096a0 */
+};
+static const float qS8[6] = {
+ 1.6377603149e+02, /* 0x4323c6aa */
+ 8.0983447266e+03, /* 0x45fd12c2 */
+ 1.4253829688e+05, /* 0x480b3293 */
+ 8.0330925000e+05, /* 0x49441ed4 */
+ 8.4050156250e+05, /* 0x494d3359 */
+ -3.4389928125e+05, /* 0xc8a7eb69 */
+};
+
+static const float qR5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */
+ 1.8408595828e-11, /* 0x2da1ec79 */
+ 7.3242180049e-02, /* 0x3d95ffff */
+ 5.8356351852e+00, /* 0x40babd86 */
+ 1.3511157227e+02, /* 0x43071c90 */
+ 1.0272437744e+03, /* 0x448067cd */
+ 1.9899779053e+03, /* 0x44f8bf4b */
+};
+static const float qS5[6] = {
+ 8.2776611328e+01, /* 0x42a58da0 */
+ 2.0778142090e+03, /* 0x4501dd07 */
+ 1.8847289062e+04, /* 0x46933e94 */
+ 5.6751113281e+04, /* 0x475daf1d */
+ 3.5976753906e+04, /* 0x470c88c1 */
+ -5.3543427734e+03, /* 0xc5a752be */
+};
+
+static const float qR3[6] = {/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */
+ 4.3774099900e-09, /* 0x3196681b */
+ 7.3241114616e-02, /* 0x3d95ff70 */
+ 3.3442313671e+00, /* 0x405607e3 */
+ 4.2621845245e+01, /* 0x422a7cc5 */
+ 1.7080809021e+02, /* 0x432acedf */
+ 1.6673394775e+02, /* 0x4326bbe4 */
+};
+static const float qS3[6] = {
+ 4.8758872986e+01, /* 0x42430916 */
+ 7.0968920898e+02, /* 0x44316c1c */
+ 3.7041481934e+03, /* 0x4567825f */
+ 6.4604252930e+03, /* 0x45c9e367 */
+ 2.5163337402e+03, /* 0x451d4557 */
+ -1.4924745178e+02, /* 0xc3153f59 */
+};
+
+static const float qR2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */
+ 1.5044444979e-07, /* 0x342189db */
+ 7.3223426938e-02, /* 0x3d95f62a */
+ 1.9981917143e+00, /* 0x3fffc4bf */
+ 1.4495602608e+01, /* 0x4167edfd */
+ 3.1666231155e+01, /* 0x41fd5471 */
+ 1.6252708435e+01, /* 0x4182058c */
+};
+static const float qS2[6] = {
+ 3.0365585327e+01, /* 0x41f2ecb8 */
+ 2.6934811401e+02, /* 0x4386ac8f */
+ 8.4478375244e+02, /* 0x44533229 */
+ 8.8293585205e+02, /* 0x445cbbe5 */
+ 2.1266638184e+02, /* 0x4354aa98 */
+ -5.3109550476e+00, /* 0xc0a9f358 */
+};
+
+ static float qzerof(float x)
+{
+ const float *p,*q;
+ float s,r,z;
+ int32_t ix;
+ GET_FLOAT_WORD(ix,x);
+ ix &= 0x7fffffff;
+ if(ix>=0x41000000) {p = qR8; q= qS8;}
+ else if(ix>=0x40f71c58){p = qR5; q= qS5;}
+ else if(ix>=0x4036db68){p = qR3; q= qS3;}
+ else if(ix>=0x40000000){p = qR2; q= qS2;}
+ z = one/(x*x);
+ r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))));
+ s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5])))));
+ return (-(float).125 + r/s)/x;
+}
diff --git a/lib/msun/src/e_j1.c b/lib/msun/src/e_j1.c
new file mode 100644
index 0000000..a01b812
--- /dev/null
+++ b/lib/msun/src/e_j1.c
@@ -0,0 +1,377 @@
+
+/* @(#)e_j1.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/* __ieee754_j1(x), __ieee754_y1(x)
+ * Bessel function of the first and second kinds of order zero.
+ * Method -- j1(x):
+ * 1. For tiny x, we use j1(x) = x/2 - x^3/16 + x^5/384 - ...
+ * 2. Reduce x to |x| since j1(x)=-j1(-x), and
+ * for x in (0,2)
+ * j1(x) = x/2 + x*z*R0/S0, where z = x*x;
+ * (precision: |j1/x - 1/2 - R0/S0 |<2**-61.51 )
+ * for x in (2,inf)
+ * j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x1)-q1(x)*sin(x1))
+ * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1))
+ * where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1)
+ * as follow:
+ * cos(x1) = cos(x)cos(3pi/4)+sin(x)sin(3pi/4)
+ * = 1/sqrt(2) * (sin(x) - cos(x))
+ * sin(x1) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4)
+ * = -1/sqrt(2) * (sin(x) + cos(x))
+ * (To avoid cancellation, use
+ * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
+ * to compute the worse one.)
+ *
+ * 3 Special cases
+ * j1(nan)= nan
+ * j1(0) = 0
+ * j1(inf) = 0
+ *
+ * Method -- y1(x):
+ * 1. screen out x<=0 cases: y1(0)=-inf, y1(x<0)=NaN
+ * 2. For x<2.
+ * Since
+ * y1(x) = 2/pi*(j1(x)*(ln(x/2)+Euler)-1/x-x/2+5/64*x^3-...)
+ * therefore y1(x)-2/pi*j1(x)*ln(x)-1/x is an odd function.
+ * We use the following function to approximate y1,
+ * y1(x) = x*U(z)/V(z) + (2/pi)*(j1(x)*ln(x)-1/x), z= x^2
+ * where for x in [0,2] (abs err less than 2**-65.89)
+ * U(z) = U0[0] + U0[1]*z + ... + U0[4]*z^4
+ * V(z) = 1 + v0[0]*z + ... + v0[4]*z^5
+ * Note: For tiny x, 1/x dominate y1 and hence
+ * y1(tiny) = -2/pi/tiny, (choose tiny<2**-54)
+ * 3. For x>=2.
+ * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1))
+ * where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1)
+ * by method mentioned above.
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+static double pone(double), qone(double);
+
+static const double
+huge = 1e300,
+one = 1.0,
+invsqrtpi= 5.64189583547756279280e-01, /* 0x3FE20DD7, 0x50429B6D */
+tpi = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */
+ /* R0/S0 on [0,2] */
+r00 = -6.25000000000000000000e-02, /* 0xBFB00000, 0x00000000 */
+r01 = 1.40705666955189706048e-03, /* 0x3F570D9F, 0x98472C61 */
+r02 = -1.59955631084035597520e-05, /* 0xBEF0C5C6, 0xBA169668 */
+r03 = 4.96727999609584448412e-08, /* 0x3E6AAAFA, 0x46CA0BD9 */
+s01 = 1.91537599538363460805e-02, /* 0x3F939D0B, 0x12637E53 */
+s02 = 1.85946785588630915560e-04, /* 0x3F285F56, 0xB9CDF664 */
+s03 = 1.17718464042623683263e-06, /* 0x3EB3BFF8, 0x333F8498 */
+s04 = 5.04636257076217042715e-09, /* 0x3E35AC88, 0xC97DFF2C */
+s05 = 1.23542274426137913908e-11; /* 0x3DAB2ACF, 0xCFB97ED8 */
+
+static const double zero = 0.0;
+
+double
+__ieee754_j1(double x)
+{
+ double z, s,c,ss,cc,r,u,v,y;
+ int32_t hx,ix;
+
+ GET_HIGH_WORD(hx,x);
+ ix = hx&0x7fffffff;
+ if(ix>=0x7ff00000) return one/x;
+ y = fabs(x);
+ if(ix >= 0x40000000) { /* |x| >= 2.0 */
+ s = sin(y);
+ c = cos(y);
+ ss = -s-c;
+ cc = s-c;
+ if(ix<0x7fe00000) { /* make sure y+y not overflow */
+ z = cos(y+y);
+ if ((s*c)>zero) cc = z/ss;
+ else ss = z/cc;
+ }
+ /*
+ * j1(x) = 1/sqrt(pi) * (P(1,x)*cc - Q(1,x)*ss) / sqrt(x)
+ * y1(x) = 1/sqrt(pi) * (P(1,x)*ss + Q(1,x)*cc) / sqrt(x)
+ */
+ if(ix>0x48000000) z = (invsqrtpi*cc)/sqrt(y);
+ else {
+ u = pone(y); v = qone(y);
+ z = invsqrtpi*(u*cc-v*ss)/sqrt(y);
+ }
+ if(hx<0) return -z;
+ else return z;
+ }
+ if(ix<0x3e400000) { /* |x|<2**-27 */
+ if(huge+x>one) return 0.5*x;/* inexact if x!=0 necessary */
+ }
+ z = x*x;
+ r = z*(r00+z*(r01+z*(r02+z*r03)));
+ s = one+z*(s01+z*(s02+z*(s03+z*(s04+z*s05))));
+ r *= x;
+ return(x*0.5+r/s);
+}
+
+static const double U0[5] = {
+ -1.96057090646238940668e-01, /* 0xBFC91866, 0x143CBC8A */
+ 5.04438716639811282616e-02, /* 0x3FA9D3C7, 0x76292CD1 */
+ -1.91256895875763547298e-03, /* 0xBF5F55E5, 0x4844F50F */
+ 2.35252600561610495928e-05, /* 0x3EF8AB03, 0x8FA6B88E */
+ -9.19099158039878874504e-08, /* 0xBE78AC00, 0x569105B8 */
+};
+static const double V0[5] = {
+ 1.99167318236649903973e-02, /* 0x3F94650D, 0x3F4DA9F0 */
+ 2.02552581025135171496e-04, /* 0x3F2A8C89, 0x6C257764 */
+ 1.35608801097516229404e-06, /* 0x3EB6C05A, 0x894E8CA6 */
+ 6.22741452364621501295e-09, /* 0x3E3ABF1D, 0x5BA69A86 */
+ 1.66559246207992079114e-11, /* 0x3DB25039, 0xDACA772A */
+};
+
+double
+__ieee754_y1(double x)
+{
+ double z, s,c,ss,cc,u,v;
+ int32_t hx,ix,lx;
+
+ EXTRACT_WORDS(hx,lx,x);
+ ix = 0x7fffffff&hx;
+ /* if Y1(NaN) is NaN, Y1(-inf) is NaN, Y1(inf) is 0 */
+ if(ix>=0x7ff00000) return one/(x+x*x);
+ if((ix|lx)==0) return -one/zero;
+ if(hx<0) return zero/zero;
+ if(ix >= 0x40000000) { /* |x| >= 2.0 */
+ s = sin(x);
+ c = cos(x);
+ ss = -s-c;
+ cc = s-c;
+ if(ix<0x7fe00000) { /* make sure x+x not overflow */
+ z = cos(x+x);
+ if ((s*c)>zero) cc = z/ss;
+ else ss = z/cc;
+ }
+ /* y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x0)+q1(x)*cos(x0))
+ * where x0 = x-3pi/4
+ * Better formula:
+ * cos(x0) = cos(x)cos(3pi/4)+sin(x)sin(3pi/4)
+ * = 1/sqrt(2) * (sin(x) - cos(x))
+ * sin(x0) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4)
+ * = -1/sqrt(2) * (cos(x) + sin(x))
+ * To avoid cancellation, use
+ * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
+ * to compute the worse one.
+ */
+ if(ix>0x48000000) z = (invsqrtpi*ss)/sqrt(x);
+ else {
+ u = pone(x); v = qone(x);
+ z = invsqrtpi*(u*ss+v*cc)/sqrt(x);
+ }
+ return z;
+ }
+ if(ix<=0x3c900000) { /* x < 2**-54 */
+ return(-tpi/x);
+ }
+ z = x*x;
+ u = U0[0]+z*(U0[1]+z*(U0[2]+z*(U0[3]+z*U0[4])));
+ v = one+z*(V0[0]+z*(V0[1]+z*(V0[2]+z*(V0[3]+z*V0[4]))));
+ return(x*(u/v) + tpi*(__ieee754_j1(x)*__ieee754_log(x)-one/x));
+}
+
+/* For x >= 8, the asymptotic expansions of pone is
+ * 1 + 15/128 s^2 - 4725/2^15 s^4 - ..., where s = 1/x.
+ * We approximate pone by
+ * pone(x) = 1 + (R/S)
+ * where R = pr0 + pr1*s^2 + pr2*s^4 + ... + pr5*s^10
+ * S = 1 + ps0*s^2 + ... + ps4*s^10
+ * and
+ * | pone(x)-1-R/S | <= 2 ** ( -60.06)
+ */
+
+static const double pr8[6] = { /* for x in [inf, 8]=1/[0,0.125] */
+ 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */
+ 1.17187499999988647970e-01, /* 0x3FBDFFFF, 0xFFFFFCCE */
+ 1.32394806593073575129e+01, /* 0x402A7A9D, 0x357F7FCE */
+ 4.12051854307378562225e+02, /* 0x4079C0D4, 0x652EA590 */
+ 3.87474538913960532227e+03, /* 0x40AE457D, 0xA3A532CC */
+ 7.91447954031891731574e+03, /* 0x40BEEA7A, 0xC32782DD */
+};
+static const double ps8[5] = {
+ 1.14207370375678408436e+02, /* 0x405C8D45, 0x8E656CAC */
+ 3.65093083420853463394e+03, /* 0x40AC85DC, 0x964D274F */
+ 3.69562060269033463555e+04, /* 0x40E20B86, 0x97C5BB7F */
+ 9.76027935934950801311e+04, /* 0x40F7D42C, 0xB28F17BB */
+ 3.08042720627888811578e+04, /* 0x40DE1511, 0x697A0B2D */
+};
+
+static const double pr5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */
+ 1.31990519556243522749e-11, /* 0x3DAD0667, 0xDAE1CA7D */
+ 1.17187493190614097638e-01, /* 0x3FBDFFFF, 0xE2C10043 */
+ 6.80275127868432871736e+00, /* 0x401B3604, 0x6E6315E3 */
+ 1.08308182990189109773e+02, /* 0x405B13B9, 0x452602ED */
+ 5.17636139533199752805e+02, /* 0x40802D16, 0xD052D649 */
+ 5.28715201363337541807e+02, /* 0x408085B8, 0xBB7E0CB7 */
+};
+static const double ps5[5] = {
+ 5.92805987221131331921e+01, /* 0x404DA3EA, 0xA8AF633D */
+ 9.91401418733614377743e+02, /* 0x408EFB36, 0x1B066701 */
+ 5.35326695291487976647e+03, /* 0x40B4E944, 0x5706B6FB */
+ 7.84469031749551231769e+03, /* 0x40BEA4B0, 0xB8A5BB15 */
+ 1.50404688810361062679e+03, /* 0x40978030, 0x036F5E51 */
+};
+
+static const double pr3[6] = {
+ 3.02503916137373618024e-09, /* 0x3E29FC21, 0xA7AD9EDD */
+ 1.17186865567253592491e-01, /* 0x3FBDFFF5, 0x5B21D17B */
+ 3.93297750033315640650e+00, /* 0x400F76BC, 0xE85EAD8A */
+ 3.51194035591636932736e+01, /* 0x40418F48, 0x9DA6D129 */
+ 9.10550110750781271918e+01, /* 0x4056C385, 0x4D2C1837 */
+ 4.85590685197364919645e+01, /* 0x4048478F, 0x8EA83EE5 */
+};
+static const double ps3[5] = {
+ 3.47913095001251519989e+01, /* 0x40416549, 0xA134069C */
+ 3.36762458747825746741e+02, /* 0x40750C33, 0x07F1A75F */
+ 1.04687139975775130551e+03, /* 0x40905B7C, 0x5037D523 */
+ 8.90811346398256432622e+02, /* 0x408BD67D, 0xA32E31E9 */
+ 1.03787932439639277504e+02, /* 0x4059F26D, 0x7C2EED53 */
+};
+
+static const double pr2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */
+ 1.07710830106873743082e-07, /* 0x3E7CE9D4, 0xF65544F4 */
+ 1.17176219462683348094e-01, /* 0x3FBDFF42, 0xBE760D83 */
+ 2.36851496667608785174e+00, /* 0x4002F2B7, 0xF98FAEC0 */
+ 1.22426109148261232917e+01, /* 0x40287C37, 0x7F71A964 */
+ 1.76939711271687727390e+01, /* 0x4031B1A8, 0x177F8EE2 */
+ 5.07352312588818499250e+00, /* 0x40144B49, 0xA574C1FE */
+};
+static const double ps2[5] = {
+ 2.14364859363821409488e+01, /* 0x40356FBD, 0x8AD5ECDC */
+ 1.25290227168402751090e+02, /* 0x405F5293, 0x14F92CD5 */
+ 2.32276469057162813669e+02, /* 0x406D08D8, 0xD5A2DBD9 */
+ 1.17679373287147100768e+02, /* 0x405D6B7A, 0xDA1884A9 */
+ 8.36463893371618283368e+00, /* 0x4020BAB1, 0xF44E5192 */
+};
+
+ static double pone(double x)
+{
+ const double *p,*q;
+ double z,r,s;
+ int32_t ix;
+ GET_HIGH_WORD(ix,x);
+ ix &= 0x7fffffff;
+ if(ix>=0x40200000) {p = pr8; q= ps8;}
+ else if(ix>=0x40122E8B){p = pr5; q= ps5;}
+ else if(ix>=0x4006DB6D){p = pr3; q= ps3;}
+ else if(ix>=0x40000000){p = pr2; q= ps2;}
+ z = one/(x*x);
+ r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))));
+ s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4]))));
+ return one+ r/s;
+}
+
+
+/* For x >= 8, the asymptotic expansions of qone is
+ * 3/8 s - 105/1024 s^3 - ..., where s = 1/x.
+ * We approximate pone by
+ * qone(x) = s*(0.375 + (R/S))
+ * where R = qr1*s^2 + qr2*s^4 + ... + qr5*s^10
+ * S = 1 + qs1*s^2 + ... + qs6*s^12
+ * and
+ * | qone(x)/s -0.375-R/S | <= 2 ** ( -61.13)
+ */
+
+static const double qr8[6] = { /* for x in [inf, 8]=1/[0,0.125] */
+ 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */
+ -1.02539062499992714161e-01, /* 0xBFBA3FFF, 0xFFFFFDF3 */
+ -1.62717534544589987888e+01, /* 0xC0304591, 0xA26779F7 */
+ -7.59601722513950107896e+02, /* 0xC087BCD0, 0x53E4B576 */
+ -1.18498066702429587167e+04, /* 0xC0C724E7, 0x40F87415 */
+ -4.84385124285750353010e+04, /* 0xC0E7A6D0, 0x65D09C6A */
+};
+static const double qs8[6] = {
+ 1.61395369700722909556e+02, /* 0x40642CA6, 0xDE5BCDE5 */
+ 7.82538599923348465381e+03, /* 0x40BE9162, 0xD0D88419 */
+ 1.33875336287249578163e+05, /* 0x4100579A, 0xB0B75E98 */
+ 7.19657723683240939863e+05, /* 0x4125F653, 0x72869C19 */
+ 6.66601232617776375264e+05, /* 0x412457D2, 0x7719AD5C */
+ -2.94490264303834643215e+05, /* 0xC111F969, 0x0EA5AA18 */
+};
+
+static const double qr5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */
+ -2.08979931141764104297e-11, /* 0xBDB6FA43, 0x1AA1A098 */
+ -1.02539050241375426231e-01, /* 0xBFBA3FFF, 0xCB597FEF */
+ -8.05644828123936029840e+00, /* 0xC0201CE6, 0xCA03AD4B */
+ -1.83669607474888380239e+02, /* 0xC066F56D, 0x6CA7B9B0 */
+ -1.37319376065508163265e+03, /* 0xC09574C6, 0x6931734F */
+ -2.61244440453215656817e+03, /* 0xC0A468E3, 0x88FDA79D */
+};
+static const double qs5[6] = {
+ 8.12765501384335777857e+01, /* 0x405451B2, 0xFF5A11B2 */
+ 1.99179873460485964642e+03, /* 0x409F1F31, 0xE77BF839 */
+ 1.74684851924908907677e+04, /* 0x40D10F1F, 0x0D64CE29 */
+ 4.98514270910352279316e+04, /* 0x40E8576D, 0xAABAD197 */
+ 2.79480751638918118260e+04, /* 0x40DB4B04, 0xCF7C364B */
+ -4.71918354795128470869e+03, /* 0xC0B26F2E, 0xFCFFA004 */
+};
+
+static const double qr3[6] = {
+ -5.07831226461766561369e-09, /* 0xBE35CFA9, 0xD38FC84F */
+ -1.02537829820837089745e-01, /* 0xBFBA3FEB, 0x51AEED54 */
+ -4.61011581139473403113e+00, /* 0xC01270C2, 0x3302D9FF */
+ -5.78472216562783643212e+01, /* 0xC04CEC71, 0xC25D16DA */
+ -2.28244540737631695038e+02, /* 0xC06C87D3, 0x4718D55F */
+ -2.19210128478909325622e+02, /* 0xC06B66B9, 0x5F5C1BF6 */
+};
+static const double qs3[6] = {
+ 4.76651550323729509273e+01, /* 0x4047D523, 0xCCD367E4 */
+ 6.73865112676699709482e+02, /* 0x40850EEB, 0xC031EE3E */
+ 3.38015286679526343505e+03, /* 0x40AA684E, 0x448E7C9A */
+ 5.54772909720722782367e+03, /* 0x40B5ABBA, 0xA61D54A6 */
+ 1.90311919338810798763e+03, /* 0x409DBC7A, 0x0DD4DF4B */
+ -1.35201191444307340817e+02, /* 0xC060E670, 0x290A311F */
+};
+
+static const double qr2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */
+ -1.78381727510958865572e-07, /* 0xBE87F126, 0x44C626D2 */
+ -1.02517042607985553460e-01, /* 0xBFBA3E8E, 0x9148B010 */
+ -2.75220568278187460720e+00, /* 0xC0060484, 0x69BB4EDA */
+ -1.96636162643703720221e+01, /* 0xC033A9E2, 0xC168907F */
+ -4.23253133372830490089e+01, /* 0xC04529A3, 0xDE104AAA */
+ -2.13719211703704061733e+01, /* 0xC0355F36, 0x39CF6E52 */
+};
+static const double qs2[6] = {
+ 2.95333629060523854548e+01, /* 0x403D888A, 0x78AE64FF */
+ 2.52981549982190529136e+02, /* 0x406F9F68, 0xDB821CBA */
+ 7.57502834868645436472e+02, /* 0x4087AC05, 0xCE49A0F7 */
+ 7.39393205320467245656e+02, /* 0x40871B25, 0x48D4C029 */
+ 1.55949003336666123687e+02, /* 0x40637E5E, 0x3C3ED8D4 */
+ -4.95949898822628210127e+00, /* 0xC013D686, 0xE71BE86B */
+};
+
+ static double qone(double x)
+{
+ const double *p,*q;
+ double s,r,z;
+ int32_t ix;
+ GET_HIGH_WORD(ix,x);
+ ix &= 0x7fffffff;
+ if(ix>=0x40200000) {p = qr8; q= qs8;}
+ else if(ix>=0x40122E8B){p = qr5; q= qs5;}
+ else if(ix>=0x4006DB6D){p = qr3; q= qs3;}
+ else if(ix>=0x40000000){p = qr2; q= qs2;}
+ z = one/(x*x);
+ r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))));
+ s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5])))));
+ return (.375 + r/s)/x;
+}
diff --git a/lib/msun/src/e_j1f.c b/lib/msun/src/e_j1f.c
new file mode 100644
index 0000000..6ccc0697
--- /dev/null
+++ b/lib/msun/src/e_j1f.c
@@ -0,0 +1,334 @@
+/* e_j1f.c -- float version of e_j1.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+#include "math.h"
+#include "math_private.h"
+
+static float ponef(float), qonef(float);
+
+static const float
+huge = 1e30,
+one = 1.0,
+invsqrtpi= 5.6418961287e-01, /* 0x3f106ebb */
+tpi = 6.3661974669e-01, /* 0x3f22f983 */
+ /* R0/S0 on [0,2] */
+r00 = -6.2500000000e-02, /* 0xbd800000 */
+r01 = 1.4070566976e-03, /* 0x3ab86cfd */
+r02 = -1.5995563444e-05, /* 0xb7862e36 */
+r03 = 4.9672799207e-08, /* 0x335557d2 */
+s01 = 1.9153760746e-02, /* 0x3c9ce859 */
+s02 = 1.8594678841e-04, /* 0x3942fab6 */
+s03 = 1.1771846857e-06, /* 0x359dffc2 */
+s04 = 5.0463624390e-09, /* 0x31ad6446 */
+s05 = 1.2354227016e-11; /* 0x2d59567e */
+
+static const float zero = 0.0;
+
+float
+__ieee754_j1f(float x)
+{
+ float z, s,c,ss,cc,r,u,v,y;
+ int32_t hx,ix;
+
+ GET_FLOAT_WORD(hx,x);
+ ix = hx&0x7fffffff;
+ if(ix>=0x7f800000) return one/x;
+ y = fabsf(x);
+ if(ix >= 0x40000000) { /* |x| >= 2.0 */
+ s = sinf(y);
+ c = cosf(y);
+ ss = -s-c;
+ cc = s-c;
+ if(ix<0x7f000000) { /* make sure y+y not overflow */
+ z = cosf(y+y);
+ if ((s*c)>zero) cc = z/ss;
+ else ss = z/cc;
+ }
+ /*
+ * j1(x) = 1/sqrt(pi) * (P(1,x)*cc - Q(1,x)*ss) / sqrt(x)
+ * y1(x) = 1/sqrt(pi) * (P(1,x)*ss + Q(1,x)*cc) / sqrt(x)
+ */
+ if(ix>0x80000000) z = (invsqrtpi*cc)/sqrtf(y);
+ else {
+ u = ponef(y); v = qonef(y);
+ z = invsqrtpi*(u*cc-v*ss)/sqrtf(y);
+ }
+ if(hx<0) return -z;
+ else return z;
+ }
+ if(ix<0x32000000) { /* |x|<2**-27 */
+ if(huge+x>one) return (float)0.5*x;/* inexact if x!=0 necessary */
+ }
+ z = x*x;
+ r = z*(r00+z*(r01+z*(r02+z*r03)));
+ s = one+z*(s01+z*(s02+z*(s03+z*(s04+z*s05))));
+ r *= x;
+ return(x*(float)0.5+r/s);
+}
+
+static const float U0[5] = {
+ -1.9605709612e-01, /* 0xbe48c331 */
+ 5.0443872809e-02, /* 0x3d4e9e3c */
+ -1.9125689287e-03, /* 0xbafaaf2a */
+ 2.3525259166e-05, /* 0x37c5581c */
+ -9.1909917899e-08, /* 0xb3c56003 */
+};
+static const float V0[5] = {
+ 1.9916731864e-02, /* 0x3ca3286a */
+ 2.0255257550e-04, /* 0x3954644b */
+ 1.3560879779e-06, /* 0x35b602d4 */
+ 6.2274145840e-09, /* 0x31d5f8eb */
+ 1.6655924903e-11, /* 0x2d9281cf */
+};
+
+float
+__ieee754_y1f(float x)
+{
+ float z, s,c,ss,cc,u,v;
+ int32_t hx,ix;
+
+ GET_FLOAT_WORD(hx,x);
+ ix = 0x7fffffff&hx;
+ /* if Y1(NaN) is NaN, Y1(-inf) is NaN, Y1(inf) is 0 */
+ if(ix>=0x7f800000) return one/(x+x*x);
+ if(ix==0) return -one/zero;
+ if(hx<0) return zero/zero;
+ if(ix >= 0x40000000) { /* |x| >= 2.0 */
+ s = sinf(x);
+ c = cosf(x);
+ ss = -s-c;
+ cc = s-c;
+ if(ix<0x7f000000) { /* make sure x+x not overflow */
+ z = cosf(x+x);
+ if ((s*c)>zero) cc = z/ss;
+ else ss = z/cc;
+ }
+ /* y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x0)+q1(x)*cos(x0))
+ * where x0 = x-3pi/4
+ * Better formula:
+ * cos(x0) = cos(x)cos(3pi/4)+sin(x)sin(3pi/4)
+ * = 1/sqrt(2) * (sin(x) - cos(x))
+ * sin(x0) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4)
+ * = -1/sqrt(2) * (cos(x) + sin(x))
+ * To avoid cancellation, use
+ * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
+ * to compute the worse one.
+ */
+ if(ix>0x48000000) z = (invsqrtpi*ss)/sqrtf(x);
+ else {
+ u = ponef(x); v = qonef(x);
+ z = invsqrtpi*(u*ss+v*cc)/sqrtf(x);
+ }
+ return z;
+ }
+ if(ix<=0x24800000) { /* x < 2**-54 */
+ return(-tpi/x);
+ }
+ z = x*x;
+ u = U0[0]+z*(U0[1]+z*(U0[2]+z*(U0[3]+z*U0[4])));
+ v = one+z*(V0[0]+z*(V0[1]+z*(V0[2]+z*(V0[3]+z*V0[4]))));
+ return(x*(u/v) + tpi*(__ieee754_j1f(x)*__ieee754_logf(x)-one/x));
+}
+
+/* For x >= 8, the asymptotic expansions of pone is
+ * 1 + 15/128 s^2 - 4725/2^15 s^4 - ..., where s = 1/x.
+ * We approximate pone by
+ * pone(x) = 1 + (R/S)
+ * where R = pr0 + pr1*s^2 + pr2*s^4 + ... + pr5*s^10
+ * S = 1 + ps0*s^2 + ... + ps4*s^10
+ * and
+ * | pone(x)-1-R/S | <= 2 ** ( -60.06)
+ */
+
+static const float pr8[6] = { /* for x in [inf, 8]=1/[0,0.125] */
+ 0.0000000000e+00, /* 0x00000000 */
+ 1.1718750000e-01, /* 0x3df00000 */
+ 1.3239480972e+01, /* 0x4153d4ea */
+ 4.1205184937e+02, /* 0x43ce06a3 */
+ 3.8747453613e+03, /* 0x45722bed */
+ 7.9144794922e+03, /* 0x45f753d6 */
+};
+static const float ps8[5] = {
+ 1.1420736694e+02, /* 0x42e46a2c */
+ 3.6509309082e+03, /* 0x45642ee5 */
+ 3.6956207031e+04, /* 0x47105c35 */
+ 9.7602796875e+04, /* 0x47bea166 */
+ 3.0804271484e+04, /* 0x46f0a88b */
+};
+
+static const float pr5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */
+ 1.3199052094e-11, /* 0x2d68333f */
+ 1.1718749255e-01, /* 0x3defffff */
+ 6.8027510643e+00, /* 0x40d9b023 */
+ 1.0830818176e+02, /* 0x42d89dca */
+ 5.1763616943e+02, /* 0x440168b7 */
+ 5.2871520996e+02, /* 0x44042dc6 */
+};
+static const float ps5[5] = {
+ 5.9280597687e+01, /* 0x426d1f55 */
+ 9.9140142822e+02, /* 0x4477d9b1 */
+ 5.3532670898e+03, /* 0x45a74a23 */
+ 7.8446904297e+03, /* 0x45f52586 */
+ 1.5040468750e+03, /* 0x44bc0180 */
+};
+
+static const float pr3[6] = {
+ 3.0250391081e-09, /* 0x314fe10d */
+ 1.1718686670e-01, /* 0x3defffab */
+ 3.9329774380e+00, /* 0x407bb5e7 */
+ 3.5119403839e+01, /* 0x420c7a45 */
+ 9.1055007935e+01, /* 0x42b61c2a */
+ 4.8559066772e+01, /* 0x42423c7c */
+};
+static const float ps3[5] = {
+ 3.4791309357e+01, /* 0x420b2a4d */
+ 3.3676245117e+02, /* 0x43a86198 */
+ 1.0468714600e+03, /* 0x4482dbe3 */
+ 8.9081134033e+02, /* 0x445eb3ed */
+ 1.0378793335e+02, /* 0x42cf936c */
+};
+
+static const float pr2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */
+ 1.0771083225e-07, /* 0x33e74ea8 */
+ 1.1717621982e-01, /* 0x3deffa16 */
+ 2.3685150146e+00, /* 0x401795c0 */
+ 1.2242610931e+01, /* 0x4143e1bc */
+ 1.7693971634e+01, /* 0x418d8d41 */
+ 5.0735230446e+00, /* 0x40a25a4d */
+};
+static const float ps2[5] = {
+ 2.1436485291e+01, /* 0x41ab7dec */
+ 1.2529022980e+02, /* 0x42fa9499 */
+ 2.3227647400e+02, /* 0x436846c7 */
+ 1.1767937469e+02, /* 0x42eb5bd7 */
+ 8.3646392822e+00, /* 0x4105d590 */
+};
+
+ static float ponef(float x)
+{
+ const float *p,*q;
+ float z,r,s;
+ int32_t ix;
+ GET_FLOAT_WORD(ix,x);
+ ix &= 0x7fffffff;
+ if(ix>=0x41000000) {p = pr8; q= ps8;}
+ else if(ix>=0x40f71c58){p = pr5; q= ps5;}
+ else if(ix>=0x4036db68){p = pr3; q= ps3;}
+ else if(ix>=0x40000000){p = pr2; q= ps2;}
+ z = one/(x*x);
+ r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))));
+ s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4]))));
+ return one+ r/s;
+}
+
+
+/* For x >= 8, the asymptotic expansions of qone is
+ * 3/8 s - 105/1024 s^3 - ..., where s = 1/x.
+ * We approximate pone by
+ * qone(x) = s*(0.375 + (R/S))
+ * where R = qr1*s^2 + qr2*s^4 + ... + qr5*s^10
+ * S = 1 + qs1*s^2 + ... + qs6*s^12
+ * and
+ * | qone(x)/s -0.375-R/S | <= 2 ** ( -61.13)
+ */
+
+static const float qr8[6] = { /* for x in [inf, 8]=1/[0,0.125] */
+ 0.0000000000e+00, /* 0x00000000 */
+ -1.0253906250e-01, /* 0xbdd20000 */
+ -1.6271753311e+01, /* 0xc1822c8d */
+ -7.5960174561e+02, /* 0xc43de683 */
+ -1.1849806641e+04, /* 0xc639273a */
+ -4.8438511719e+04, /* 0xc73d3683 */
+};
+static const float qs8[6] = {
+ 1.6139537048e+02, /* 0x43216537 */
+ 7.8253862305e+03, /* 0x45f48b17 */
+ 1.3387534375e+05, /* 0x4802bcd6 */
+ 7.1965775000e+05, /* 0x492fb29c */
+ 6.6660125000e+05, /* 0x4922be94 */
+ -2.9449025000e+05, /* 0xc88fcb48 */
+};
+
+static const float qr5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */
+ -2.0897993405e-11, /* 0xadb7d219 */
+ -1.0253904760e-01, /* 0xbdd1fffe */
+ -8.0564479828e+00, /* 0xc100e736 */
+ -1.8366960144e+02, /* 0xc337ab6b */
+ -1.3731937256e+03, /* 0xc4aba633 */
+ -2.6124443359e+03, /* 0xc523471c */
+};
+static const float qs5[6] = {
+ 8.1276550293e+01, /* 0x42a28d98 */
+ 1.9917987061e+03, /* 0x44f8f98f */
+ 1.7468484375e+04, /* 0x468878f8 */
+ 4.9851425781e+04, /* 0x4742bb6d */
+ 2.7948074219e+04, /* 0x46da5826 */
+ -4.7191835938e+03, /* 0xc5937978 */
+};
+
+static const float qr3[6] = {
+ -5.0783124372e-09, /* 0xb1ae7d4f */
+ -1.0253783315e-01, /* 0xbdd1ff5b */
+ -4.6101160049e+00, /* 0xc0938612 */
+ -5.7847221375e+01, /* 0xc267638e */
+ -2.2824453735e+02, /* 0xc3643e9a */
+ -2.1921012878e+02, /* 0xc35b35cb */
+};
+static const float qs3[6] = {
+ 4.7665153503e+01, /* 0x423ea91e */
+ 6.7386511230e+02, /* 0x4428775e */
+ 3.3801528320e+03, /* 0x45534272 */
+ 5.5477290039e+03, /* 0x45ad5dd5 */
+ 1.9031191406e+03, /* 0x44ede3d0 */
+ -1.3520118713e+02, /* 0xc3073381 */
+};
+
+static const float qr2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */
+ -1.7838172539e-07, /* 0xb43f8932 */
+ -1.0251704603e-01, /* 0xbdd1f475 */
+ -2.7522056103e+00, /* 0xc0302423 */
+ -1.9663616180e+01, /* 0xc19d4f16 */
+ -4.2325313568e+01, /* 0xc2294d1f */
+ -2.1371921539e+01, /* 0xc1aaf9b2 */
+};
+static const float qs2[6] = {
+ 2.9533363342e+01, /* 0x41ec4454 */
+ 2.5298155212e+02, /* 0x437cfb47 */
+ 7.5750280762e+02, /* 0x443d602e */
+ 7.3939318848e+02, /* 0x4438d92a */
+ 1.5594900513e+02, /* 0x431bf2f2 */
+ -4.9594988823e+00, /* 0xc09eb437 */
+};
+
+ static float qonef(float x)
+{
+ const float *p,*q;
+ float s,r,z;
+ int32_t ix;
+ GET_FLOAT_WORD(ix,x);
+ ix &= 0x7fffffff;
+ if(ix>=0x40200000) {p = qr8; q= qs8;}
+ else if(ix>=0x40f71c58){p = qr5; q= qs5;}
+ else if(ix>=0x4036db68){p = qr3; q= qs3;}
+ else if(ix>=0x40000000){p = qr2; q= qs2;}
+ z = one/(x*x);
+ r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))));
+ s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5])))));
+ return ((float).375 + r/s)/x;
+}
diff --git a/lib/msun/src/e_jn.c b/lib/msun/src/e_jn.c
new file mode 100644
index 0000000..ca26230
--- /dev/null
+++ b/lib/msun/src/e_jn.c
@@ -0,0 +1,266 @@
+
+/* @(#)e_jn.c 1.4 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/*
+ * __ieee754_jn(n, x), __ieee754_yn(n, x)
+ * floating point Bessel's function of the 1st and 2nd kind
+ * of order n
+ *
+ * Special cases:
+ * y0(0)=y1(0)=yn(n,0) = -inf with division by zero signal;
+ * y0(-ve)=y1(-ve)=yn(n,-ve) are NaN with invalid signal.
+ * Note 2. About jn(n,x), yn(n,x)
+ * For n=0, j0(x) is called,
+ * for n=1, j1(x) is called,
+ * for n<x, forward recursion us used starting
+ * from values of j0(x) and j1(x).
+ * for n>x, a continued fraction approximation to
+ * j(n,x)/j(n-1,x) is evaluated and then backward
+ * recursion is used starting from a supposed value
+ * for j(n,x). The resulting value of j(0,x) is
+ * compared with the actual value to correct the
+ * supposed value of j(n,x).
+ *
+ * yn(n,x) is similar in all respects, except
+ * that forward recursion is used for all
+ * values of n>1.
+ *
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+static const double
+invsqrtpi= 5.64189583547756279280e-01, /* 0x3FE20DD7, 0x50429B6D */
+two = 2.00000000000000000000e+00, /* 0x40000000, 0x00000000 */
+one = 1.00000000000000000000e+00; /* 0x3FF00000, 0x00000000 */
+
+static const double zero = 0.00000000000000000000e+00;
+
+double
+__ieee754_jn(int n, double x)
+{
+ int32_t i,hx,ix,lx, sgn;
+ double a, b, temp, di;
+ double z, w;
+
+ /* J(-n,x) = (-1)^n * J(n, x), J(n, -x) = (-1)^n * J(n, x)
+ * Thus, J(-n,x) = J(n,-x)
+ */
+ EXTRACT_WORDS(hx,lx,x);
+ ix = 0x7fffffff&hx;
+ /* if J(n,NaN) is NaN */
+ if((ix|((u_int32_t)(lx|-lx))>>31)>0x7ff00000) return x+x;
+ if(n<0){
+ n = -n;
+ x = -x;
+ hx ^= 0x80000000;
+ }
+ if(n==0) return(__ieee754_j0(x));
+ if(n==1) return(__ieee754_j1(x));
+ sgn = (n&1)&(hx>>31); /* even n -- 0, odd n -- sign(x) */
+ x = fabs(x);
+ if((ix|lx)==0||ix>=0x7ff00000) /* if x is 0 or inf */
+ b = zero;
+ else if((double)n<=x) {
+ /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */
+ if(ix>=0x52D00000) { /* x > 2**302 */
+ /* (x >> n**2)
+ * Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi)
+ * Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi)
+ * Let s=sin(x), c=cos(x),
+ * xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then
+ *
+ * n sin(xn)*sqt2 cos(xn)*sqt2
+ * ----------------------------------
+ * 0 s-c c+s
+ * 1 -s-c -c+s
+ * 2 -s+c -c-s
+ * 3 s+c c-s
+ */
+ switch(n&3) {
+ case 0: temp = cos(x)+sin(x); break;
+ case 1: temp = -cos(x)+sin(x); break;
+ case 2: temp = -cos(x)-sin(x); break;
+ case 3: temp = cos(x)-sin(x); break;
+ }
+ b = invsqrtpi*temp/sqrt(x);
+ } else {
+ a = __ieee754_j0(x);
+ b = __ieee754_j1(x);
+ for(i=1;i<n;i++){
+ temp = b;
+ b = b*((double)(i+i)/x) - a; /* avoid underflow */
+ a = temp;
+ }
+ }
+ } else {
+ if(ix<0x3e100000) { /* x < 2**-29 */
+ /* x is tiny, return the first Taylor expansion of J(n,x)
+ * J(n,x) = 1/n!*(x/2)^n - ...
+ */
+ if(n>33) /* underflow */
+ b = zero;
+ else {
+ temp = x*0.5; b = temp;
+ for (a=one,i=2;i<=n;i++) {
+ a *= (double)i; /* a = n! */
+ b *= temp; /* b = (x/2)^n */
+ }
+ b = b/a;
+ }
+ } else {
+ /* use backward recurrence */
+ /* x x^2 x^2
+ * J(n,x)/J(n-1,x) = ---- ------ ------ .....
+ * 2n - 2(n+1) - 2(n+2)
+ *
+ * 1 1 1
+ * (for large x) = ---- ------ ------ .....
+ * 2n 2(n+1) 2(n+2)
+ * -- - ------ - ------ -
+ * x x x
+ *
+ * Let w = 2n/x and h=2/x, then the above quotient
+ * is equal to the continued fraction:
+ * 1
+ * = -----------------------
+ * 1
+ * w - -----------------
+ * 1
+ * w+h - ---------
+ * w+2h - ...
+ *
+ * To determine how many terms needed, let
+ * Q(0) = w, Q(1) = w(w+h) - 1,
+ * Q(k) = (w+k*h)*Q(k-1) - Q(k-2),
+ * When Q(k) > 1e4 good for single
+ * When Q(k) > 1e9 good for double
+ * When Q(k) > 1e17 good for quadruple
+ */
+ /* determine k */
+ double t,v;
+ double q0,q1,h,tmp; int32_t k,m;
+ w = (n+n)/(double)x; h = 2.0/(double)x;
+ q0 = w; z = w+h; q1 = w*z - 1.0; k=1;
+ while(q1<1.0e9) {
+ k += 1; z += h;
+ tmp = z*q1 - q0;
+ q0 = q1;
+ q1 = tmp;
+ }
+ m = n+n;
+ for(t=zero, i = 2*(n+k); i>=m; i -= 2) t = one/(i/x-t);
+ a = t;
+ b = one;
+ /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n)
+ * Hence, if n*(log(2n/x)) > ...
+ * single 8.8722839355e+01
+ * double 7.09782712893383973096e+02
+ * long double 1.1356523406294143949491931077970765006170e+04
+ * then recurrent value may overflow and the result is
+ * likely underflow to zero
+ */
+ tmp = n;
+ v = two/x;
+ tmp = tmp*__ieee754_log(fabs(v*tmp));
+ if(tmp<7.09782712893383973096e+02) {
+ for(i=n-1,di=(double)(i+i);i>0;i--){
+ temp = b;
+ b *= di;
+ b = b/x - a;
+ a = temp;
+ di -= two;
+ }
+ } else {
+ for(i=n-1,di=(double)(i+i);i>0;i--){
+ temp = b;
+ b *= di;
+ b = b/x - a;
+ a = temp;
+ di -= two;
+ /* scale b to avoid spurious overflow */
+ if(b>1e100) {
+ a /= b;
+ t /= b;
+ b = one;
+ }
+ }
+ }
+ b = (t*__ieee754_j0(x)/b);
+ }
+ }
+ if(sgn==1) return -b; else return b;
+}
+
+double
+__ieee754_yn(int n, double x)
+{
+ int32_t i,hx,ix,lx;
+ int32_t sign;
+ double a, b, temp;
+
+ EXTRACT_WORDS(hx,lx,x);
+ ix = 0x7fffffff&hx;
+ /* if Y(n,NaN) is NaN */
+ if((ix|((u_int32_t)(lx|-lx))>>31)>0x7ff00000) return x+x;
+ if((ix|lx)==0) return -one/zero;
+ if(hx<0) return zero/zero;
+ sign = 1;
+ if(n<0){
+ n = -n;
+ sign = 1 - ((n&1)<<1);
+ }
+ if(n==0) return(__ieee754_y0(x));
+ if(n==1) return(sign*__ieee754_y1(x));
+ if(ix==0x7ff00000) return zero;
+ if(ix>=0x52D00000) { /* x > 2**302 */
+ /* (x >> n**2)
+ * Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi)
+ * Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi)
+ * Let s=sin(x), c=cos(x),
+ * xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then
+ *
+ * n sin(xn)*sqt2 cos(xn)*sqt2
+ * ----------------------------------
+ * 0 s-c c+s
+ * 1 -s-c -c+s
+ * 2 -s+c -c-s
+ * 3 s+c c-s
+ */
+ switch(n&3) {
+ case 0: temp = sin(x)-cos(x); break;
+ case 1: temp = -sin(x)-cos(x); break;
+ case 2: temp = -sin(x)+cos(x); break;
+ case 3: temp = sin(x)+cos(x); break;
+ }
+ b = invsqrtpi*temp/sqrt(x);
+ } else {
+ u_int32_t high;
+ a = __ieee754_y0(x);
+ b = __ieee754_y1(x);
+ /* quit if b is -inf */
+ GET_HIGH_WORD(high,b);
+ for(i=1;i<n&&high!=0xfff00000;i++){
+ temp = b;
+ b = ((double)(i+i)/x)*b - a;
+ GET_HIGH_WORD(high,b);
+ a = temp;
+ }
+ }
+ if(sign>0) return b; else return -b;
+}
diff --git a/lib/msun/src/e_jnf.c b/lib/msun/src/e_jnf.c
new file mode 100644
index 0000000..17a7008
--- /dev/null
+++ b/lib/msun/src/e_jnf.c
@@ -0,0 +1,196 @@
+/* e_jnf.c -- float version of e_jn.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+#include "math.h"
+#include "math_private.h"
+
+static const float
+invsqrtpi= 5.6418961287e-01, /* 0x3f106ebb */
+two = 2.0000000000e+00, /* 0x40000000 */
+one = 1.0000000000e+00; /* 0x3F800000 */
+
+static const float zero = 0.0000000000e+00;
+
+float
+__ieee754_jnf(int n, float x)
+{
+ int32_t i,hx,ix, sgn;
+ float a, b, temp, di;
+ float z, w;
+
+ /* J(-n,x) = (-1)^n * J(n, x), J(n, -x) = (-1)^n * J(n, x)
+ * Thus, J(-n,x) = J(n,-x)
+ */
+ GET_FLOAT_WORD(hx,x);
+ ix = 0x7fffffff&hx;
+ /* if J(n,NaN) is NaN */
+ if(ix>0x7f800000) return x+x;
+ if(n<0){
+ n = -n;
+ x = -x;
+ hx ^= 0x80000000;
+ }
+ if(n==0) return(__ieee754_j0f(x));
+ if(n==1) return(__ieee754_j1f(x));
+ sgn = (n&1)&(hx>>31); /* even n -- 0, odd n -- sign(x) */
+ x = fabsf(x);
+ if(ix==0||ix>=0x7f800000) /* if x is 0 or inf */
+ b = zero;
+ else if((float)n<=x) {
+ /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */
+ a = __ieee754_j0f(x);
+ b = __ieee754_j1f(x);
+ for(i=1;i<n;i++){
+ temp = b;
+ b = b*((float)(i+i)/x) - a; /* avoid underflow */
+ a = temp;
+ }
+ } else {
+ if(ix<0x30800000) { /* x < 2**-29 */
+ /* x is tiny, return the first Taylor expansion of J(n,x)
+ * J(n,x) = 1/n!*(x/2)^n - ...
+ */
+ if(n>33) /* underflow */
+ b = zero;
+ else {
+ temp = x*(float)0.5; b = temp;
+ for (a=one,i=2;i<=n;i++) {
+ a *= (float)i; /* a = n! */
+ b *= temp; /* b = (x/2)^n */
+ }
+ b = b/a;
+ }
+ } else {
+ /* use backward recurrence */
+ /* x x^2 x^2
+ * J(n,x)/J(n-1,x) = ---- ------ ------ .....
+ * 2n - 2(n+1) - 2(n+2)
+ *
+ * 1 1 1
+ * (for large x) = ---- ------ ------ .....
+ * 2n 2(n+1) 2(n+2)
+ * -- - ------ - ------ -
+ * x x x
+ *
+ * Let w = 2n/x and h=2/x, then the above quotient
+ * is equal to the continued fraction:
+ * 1
+ * = -----------------------
+ * 1
+ * w - -----------------
+ * 1
+ * w+h - ---------
+ * w+2h - ...
+ *
+ * To determine how many terms needed, let
+ * Q(0) = w, Q(1) = w(w+h) - 1,
+ * Q(k) = (w+k*h)*Q(k-1) - Q(k-2),
+ * When Q(k) > 1e4 good for single
+ * When Q(k) > 1e9 good for double
+ * When Q(k) > 1e17 good for quadruple
+ */
+ /* determine k */
+ float t,v;
+ float q0,q1,h,tmp; int32_t k,m;
+ w = (n+n)/(float)x; h = (float)2.0/(float)x;
+ q0 = w; z = w+h; q1 = w*z - (float)1.0; k=1;
+ while(q1<(float)1.0e9) {
+ k += 1; z += h;
+ tmp = z*q1 - q0;
+ q0 = q1;
+ q1 = tmp;
+ }
+ m = n+n;
+ for(t=zero, i = 2*(n+k); i>=m; i -= 2) t = one/(i/x-t);
+ a = t;
+ b = one;
+ /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n)
+ * Hence, if n*(log(2n/x)) > ...
+ * single 8.8722839355e+01
+ * double 7.09782712893383973096e+02
+ * long double 1.1356523406294143949491931077970765006170e+04
+ * then recurrent value may overflow and the result is
+ * likely underflow to zero
+ */
+ tmp = n;
+ v = two/x;
+ tmp = tmp*__ieee754_logf(fabsf(v*tmp));
+ if(tmp<(float)8.8721679688e+01) {
+ for(i=n-1,di=(float)(i+i);i>0;i--){
+ temp = b;
+ b *= di;
+ b = b/x - a;
+ a = temp;
+ di -= two;
+ }
+ } else {
+ for(i=n-1,di=(float)(i+i);i>0;i--){
+ temp = b;
+ b *= di;
+ b = b/x - a;
+ a = temp;
+ di -= two;
+ /* scale b to avoid spurious overflow */
+ if(b>(float)1e10) {
+ a /= b;
+ t /= b;
+ b = one;
+ }
+ }
+ }
+ b = (t*__ieee754_j0f(x)/b);
+ }
+ }
+ if(sgn==1) return -b; else return b;
+}
+
+float
+__ieee754_ynf(int n, float x)
+{
+ int32_t i,hx,ix,ib;
+ int32_t sign;
+ float a, b, temp;
+
+ GET_FLOAT_WORD(hx,x);
+ ix = 0x7fffffff&hx;
+ /* if Y(n,NaN) is NaN */
+ if(ix>0x7f800000) return x+x;
+ if(ix==0) return -one/zero;
+ if(hx<0) return zero/zero;
+ sign = 1;
+ if(n<0){
+ n = -n;
+ sign = 1 - ((n&1)<<1);
+ }
+ if(n==0) return(__ieee754_y0f(x));
+ if(n==1) return(sign*__ieee754_y1f(x));
+ if(ix==0x7f800000) return zero;
+
+ a = __ieee754_y0f(x);
+ b = __ieee754_y1f(x);
+ /* quit if b is -inf */
+ GET_FLOAT_WORD(ib,b);
+ for(i=1;i<n&&ib!=0xff800000;i++){
+ temp = b;
+ b = ((float)(i+i)/x)*b - a;
+ GET_FLOAT_WORD(ib,b);
+ a = temp;
+ }
+ if(sign>0) return b; else return -b;
+}
diff --git a/lib/msun/src/e_lgamma.c b/lib/msun/src/e_lgamma.c
new file mode 100644
index 0000000..39d3f85
--- /dev/null
+++ b/lib/msun/src/e_lgamma.c
@@ -0,0 +1,34 @@
+
+/* @(#)e_lgamma.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/* __ieee754_lgamma(x)
+ * Return the logarithm of the Gamma function of x.
+ *
+ * Method: call __ieee754_lgamma_r
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+extern int signgam;
+
+double
+__ieee754_lgamma(double x)
+{
+ return __ieee754_lgamma_r(x,&signgam);
+}
diff --git a/lib/msun/src/e_lgamma_r.c b/lib/msun/src/e_lgamma_r.c
new file mode 100644
index 0000000..91989d5
--- /dev/null
+++ b/lib/msun/src/e_lgamma_r.c
@@ -0,0 +1,297 @@
+
+/* @(#)e_lgamma_r.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/* __ieee754_lgamma_r(x, signgamp)
+ * Reentrant version of the logarithm of the Gamma function
+ * with user provide pointer for the sign of Gamma(x).
+ *
+ * Method:
+ * 1. Argument Reduction for 0 < x <= 8
+ * Since gamma(1+s)=s*gamma(s), for x in [0,8], we may
+ * reduce x to a number in [1.5,2.5] by
+ * lgamma(1+s) = log(s) + lgamma(s)
+ * for example,
+ * lgamma(7.3) = log(6.3) + lgamma(6.3)
+ * = log(6.3*5.3) + lgamma(5.3)
+ * = log(6.3*5.3*4.3*3.3*2.3) + lgamma(2.3)
+ * 2. Polynomial approximation of lgamma around its
+ * minimun ymin=1.461632144968362245 to maintain monotonicity.
+ * On [ymin-0.23, ymin+0.27] (i.e., [1.23164,1.73163]), use
+ * Let z = x-ymin;
+ * lgamma(x) = -1.214862905358496078218 + z^2*poly(z)
+ * where
+ * poly(z) is a 14 degree polynomial.
+ * 2. Rational approximation in the primary interval [2,3]
+ * We use the following approximation:
+ * s = x-2.0;
+ * lgamma(x) = 0.5*s + s*P(s)/Q(s)
+ * with accuracy
+ * |P/Q - (lgamma(x)-0.5s)| < 2**-61.71
+ * Our algorithms are based on the following observation
+ *
+ * zeta(2)-1 2 zeta(3)-1 3
+ * lgamma(2+s) = s*(1-Euler) + --------- * s - --------- * s + ...
+ * 2 3
+ *
+ * where Euler = 0.5771... is the Euler constant, which is very
+ * close to 0.5.
+ *
+ * 3. For x>=8, we have
+ * lgamma(x)~(x-0.5)log(x)-x+0.5*log(2pi)+1/(12x)-1/(360x**3)+....
+ * (better formula:
+ * lgamma(x)~(x-0.5)*(log(x)-1)-.5*(log(2pi)-1) + ...)
+ * Let z = 1/x, then we approximation
+ * f(z) = lgamma(x) - (x-0.5)(log(x)-1)
+ * by
+ * 3 5 11
+ * w = w0 + w1*z + w2*z + w3*z + ... + w6*z
+ * where
+ * |w - f(z)| < 2**-58.74
+ *
+ * 4. For negative x, since (G is gamma function)
+ * -x*G(-x)*G(x) = pi/sin(pi*x),
+ * we have
+ * G(x) = pi/(sin(pi*x)*(-x)*G(-x))
+ * since G(-x) is positive, sign(G(x)) = sign(sin(pi*x)) for x<0
+ * Hence, for x<0, signgam = sign(sin(pi*x)) and
+ * lgamma(x) = log(|Gamma(x)|)
+ * = log(pi/(|x*sin(pi*x)|)) - lgamma(-x);
+ * Note: one should avoid compute pi*(-x) directly in the
+ * computation of sin(pi*(-x)).
+ *
+ * 5. Special Cases
+ * lgamma(2+s) ~ s*(1-Euler) for tiny s
+ * lgamma(1)=lgamma(2)=0
+ * lgamma(x) ~ -log(x) for tiny x
+ * lgamma(0) = lgamma(inf) = inf
+ * lgamma(-integer) = +-inf
+ *
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+static const double
+two52= 4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */
+half= 5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */
+one = 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+pi = 3.14159265358979311600e+00, /* 0x400921FB, 0x54442D18 */
+a0 = 7.72156649015328655494e-02, /* 0x3FB3C467, 0xE37DB0C8 */
+a1 = 3.22467033424113591611e-01, /* 0x3FD4A34C, 0xC4A60FAD */
+a2 = 6.73523010531292681824e-02, /* 0x3FB13E00, 0x1A5562A7 */
+a3 = 2.05808084325167332806e-02, /* 0x3F951322, 0xAC92547B */
+a4 = 7.38555086081402883957e-03, /* 0x3F7E404F, 0xB68FEFE8 */
+a5 = 2.89051383673415629091e-03, /* 0x3F67ADD8, 0xCCB7926B */
+a6 = 1.19270763183362067845e-03, /* 0x3F538A94, 0x116F3F5D */
+a7 = 5.10069792153511336608e-04, /* 0x3F40B6C6, 0x89B99C00 */
+a8 = 2.20862790713908385557e-04, /* 0x3F2CF2EC, 0xED10E54D */
+a9 = 1.08011567247583939954e-04, /* 0x3F1C5088, 0x987DFB07 */
+a10 = 2.52144565451257326939e-05, /* 0x3EFA7074, 0x428CFA52 */
+a11 = 4.48640949618915160150e-05, /* 0x3F07858E, 0x90A45837 */
+tc = 1.46163214496836224576e+00, /* 0x3FF762D8, 0x6356BE3F */
+tf = -1.21486290535849611461e-01, /* 0xBFBF19B9, 0xBCC38A42 */
+/* tt = -(tail of tf) */
+tt = -3.63867699703950536541e-18, /* 0xBC50C7CA, 0xA48A971F */
+t0 = 4.83836122723810047042e-01, /* 0x3FDEF72B, 0xC8EE38A2 */
+t1 = -1.47587722994593911752e-01, /* 0xBFC2E427, 0x8DC6C509 */
+t2 = 6.46249402391333854778e-02, /* 0x3FB08B42, 0x94D5419B */
+t3 = -3.27885410759859649565e-02, /* 0xBFA0C9A8, 0xDF35B713 */
+t4 = 1.79706750811820387126e-02, /* 0x3F9266E7, 0x970AF9EC */
+t5 = -1.03142241298341437450e-02, /* 0xBF851F9F, 0xBA91EC6A */
+t6 = 6.10053870246291332635e-03, /* 0x3F78FCE0, 0xE370E344 */
+t7 = -3.68452016781138256760e-03, /* 0xBF6E2EFF, 0xB3E914D7 */
+t8 = 2.25964780900612472250e-03, /* 0x3F6282D3, 0x2E15C915 */
+t9 = -1.40346469989232843813e-03, /* 0xBF56FE8E, 0xBF2D1AF1 */
+t10 = 8.81081882437654011382e-04, /* 0x3F4CDF0C, 0xEF61A8E9 */
+t11 = -5.38595305356740546715e-04, /* 0xBF41A610, 0x9C73E0EC */
+t12 = 3.15632070903625950361e-04, /* 0x3F34AF6D, 0x6C0EBBF7 */
+t13 = -3.12754168375120860518e-04, /* 0xBF347F24, 0xECC38C38 */
+t14 = 3.35529192635519073543e-04, /* 0x3F35FD3E, 0xE8C2D3F4 */
+u0 = -7.72156649015328655494e-02, /* 0xBFB3C467, 0xE37DB0C8 */
+u1 = 6.32827064025093366517e-01, /* 0x3FE4401E, 0x8B005DFF */
+u2 = 1.45492250137234768737e+00, /* 0x3FF7475C, 0xD119BD6F */
+u3 = 9.77717527963372745603e-01, /* 0x3FEF4976, 0x44EA8450 */
+u4 = 2.28963728064692451092e-01, /* 0x3FCD4EAE, 0xF6010924 */
+u5 = 1.33810918536787660377e-02, /* 0x3F8B678B, 0xBF2BAB09 */
+v1 = 2.45597793713041134822e+00, /* 0x4003A5D7, 0xC2BD619C */
+v2 = 2.12848976379893395361e+00, /* 0x40010725, 0xA42B18F5 */
+v3 = 7.69285150456672783825e-01, /* 0x3FE89DFB, 0xE45050AF */
+v4 = 1.04222645593369134254e-01, /* 0x3FBAAE55, 0xD6537C88 */
+v5 = 3.21709242282423911810e-03, /* 0x3F6A5ABB, 0x57D0CF61 */
+s0 = -7.72156649015328655494e-02, /* 0xBFB3C467, 0xE37DB0C8 */
+s1 = 2.14982415960608852501e-01, /* 0x3FCB848B, 0x36E20878 */
+s2 = 3.25778796408930981787e-01, /* 0x3FD4D98F, 0x4F139F59 */
+s3 = 1.46350472652464452805e-01, /* 0x3FC2BB9C, 0xBEE5F2F7 */
+s4 = 2.66422703033638609560e-02, /* 0x3F9B481C, 0x7E939961 */
+s5 = 1.84028451407337715652e-03, /* 0x3F5E26B6, 0x7368F239 */
+s6 = 3.19475326584100867617e-05, /* 0x3F00BFEC, 0xDD17E945 */
+r1 = 1.39200533467621045958e+00, /* 0x3FF645A7, 0x62C4AB74 */
+r2 = 7.21935547567138069525e-01, /* 0x3FE71A18, 0x93D3DCDC */
+r3 = 1.71933865632803078993e-01, /* 0x3FC601ED, 0xCCFBDF27 */
+r4 = 1.86459191715652901344e-02, /* 0x3F9317EA, 0x742ED475 */
+r5 = 7.77942496381893596434e-04, /* 0x3F497DDA, 0xCA41A95B */
+r6 = 7.32668430744625636189e-06, /* 0x3EDEBAF7, 0xA5B38140 */
+w0 = 4.18938533204672725052e-01, /* 0x3FDACFE3, 0x90C97D69 */
+w1 = 8.33333333333329678849e-02, /* 0x3FB55555, 0x5555553B */
+w2 = -2.77777777728775536470e-03, /* 0xBF66C16C, 0x16B02E5C */
+w3 = 7.93650558643019558500e-04, /* 0x3F4A019F, 0x98CF38B6 */
+w4 = -5.95187557450339963135e-04, /* 0xBF4380CB, 0x8C0FE741 */
+w5 = 8.36339918996282139126e-04, /* 0x3F4B67BA, 0x4CDAD5D1 */
+w6 = -1.63092934096575273989e-03; /* 0xBF5AB89D, 0x0B9E43E4 */
+
+static const double zero= 0.00000000000000000000e+00;
+
+ static double sin_pi(double x)
+{
+ double y,z;
+ int n,ix;
+
+ GET_HIGH_WORD(ix,x);
+ ix &= 0x7fffffff;
+
+ if(ix<0x3fd00000) return __kernel_sin(pi*x,zero,0);
+ y = -x; /* x is assume negative */
+
+ /*
+ * argument reduction, make sure inexact flag not raised if input
+ * is an integer
+ */
+ z = floor(y);
+ if(z!=y) { /* inexact anyway */
+ y *= 0.5;
+ y = 2.0*(y - floor(y)); /* y = |x| mod 2.0 */
+ n = (int) (y*4.0);
+ } else {
+ if(ix>=0x43400000) {
+ y = zero; n = 0; /* y must be even */
+ } else {
+ if(ix<0x43300000) z = y+two52; /* exact */
+ GET_LOW_WORD(n,z);
+ n &= 1;
+ y = n;
+ n<<= 2;
+ }
+ }
+ switch (n) {
+ case 0: y = __kernel_sin(pi*y,zero,0); break;
+ case 1:
+ case 2: y = __kernel_cos(pi*(0.5-y),zero); break;
+ case 3:
+ case 4: y = __kernel_sin(pi*(one-y),zero,0); break;
+ case 5:
+ case 6: y = -__kernel_cos(pi*(y-1.5),zero); break;
+ default: y = __kernel_sin(pi*(y-2.0),zero,0); break;
+ }
+ return -y;
+}
+
+
+double
+__ieee754_lgamma_r(double x, int *signgamp)
+{
+ double t,y,z,nadj,p,p1,p2,p3,q,r,w;
+ int i,hx,lx,ix;
+
+ EXTRACT_WORDS(hx,lx,x);
+
+ /* purge off +-inf, NaN, +-0, and negative arguments */
+ *signgamp = 1;
+ ix = hx&0x7fffffff;
+ if(ix>=0x7ff00000) return x*x;
+ if((ix|lx)==0) return one/zero;
+ if(ix<0x3b900000) { /* |x|<2**-70, return -log(|x|) */
+ if(hx<0) {
+ *signgamp = -1;
+ return -__ieee754_log(-x);
+ } else return -__ieee754_log(x);
+ }
+ if(hx<0) {
+ if(ix>=0x43300000) /* |x|>=2**52, must be -integer */
+ return one/zero;
+ t = sin_pi(x);
+ if(t==zero) return one/zero; /* -integer */
+ nadj = __ieee754_log(pi/fabs(t*x));
+ if(t<zero) *signgamp = -1;
+ x = -x;
+ }
+
+ /* purge off 1 and 2 */
+ if((((ix-0x3ff00000)|lx)==0)||(((ix-0x40000000)|lx)==0)) r = 0;
+ /* for x < 2.0 */
+ else if(ix<0x40000000) {
+ if(ix<=0x3feccccc) { /* lgamma(x) = lgamma(x+1)-log(x) */
+ r = -__ieee754_log(x);
+ if(ix>=0x3FE76944) {y = one-x; i= 0;}
+ else if(ix>=0x3FCDA661) {y= x-(tc-one); i=1;}
+ else {y = x; i=2;}
+ } else {
+ r = zero;
+ if(ix>=0x3FFBB4C3) {y=2.0-x;i=0;} /* [1.7316,2] */
+ else if(ix>=0x3FF3B4C4) {y=x-tc;i=1;} /* [1.23,1.73] */
+ else {y=x-one;i=2;}
+ }
+ switch(i) {
+ case 0:
+ z = y*y;
+ p1 = a0+z*(a2+z*(a4+z*(a6+z*(a8+z*a10))));
+ p2 = z*(a1+z*(a3+z*(a5+z*(a7+z*(a9+z*a11)))));
+ p = y*p1+p2;
+ r += (p-0.5*y); break;
+ case 1:
+ z = y*y;
+ w = z*y;
+ p1 = t0+w*(t3+w*(t6+w*(t9 +w*t12))); /* parallel comp */
+ p2 = t1+w*(t4+w*(t7+w*(t10+w*t13)));
+ p3 = t2+w*(t5+w*(t8+w*(t11+w*t14)));
+ p = z*p1-(tt-w*(p2+y*p3));
+ r += (tf + p); break;
+ case 2:
+ p1 = y*(u0+y*(u1+y*(u2+y*(u3+y*(u4+y*u5)))));
+ p2 = one+y*(v1+y*(v2+y*(v3+y*(v4+y*v5))));
+ r += (-0.5*y + p1/p2);
+ }
+ }
+ else if(ix<0x40200000) { /* x < 8.0 */
+ i = (int)x;
+ t = zero;
+ y = x-(double)i;
+ p = y*(s0+y*(s1+y*(s2+y*(s3+y*(s4+y*(s5+y*s6))))));
+ q = one+y*(r1+y*(r2+y*(r3+y*(r4+y*(r5+y*r6)))));
+ r = half*y+p/q;
+ z = one; /* lgamma(1+s) = log(s) + lgamma(s) */
+ switch(i) {
+ case 7: z *= (y+6.0); /* FALLTHRU */
+ case 6: z *= (y+5.0); /* FALLTHRU */
+ case 5: z *= (y+4.0); /* FALLTHRU */
+ case 4: z *= (y+3.0); /* FALLTHRU */
+ case 3: z *= (y+2.0); /* FALLTHRU */
+ r += __ieee754_log(z); break;
+ }
+ /* 8.0 <= x < 2**58 */
+ } else if (ix < 0x43900000) {
+ t = __ieee754_log(x);
+ z = one/x;
+ y = z*z;
+ w = w0+z*(w1+y*(w2+y*(w3+y*(w4+y*(w5+y*w6)))));
+ r = (x-half)*(t-one)+w;
+ } else
+ /* 2**58 <= x <= inf */
+ r = x*(__ieee754_log(x)-one);
+ if(hx<0) r = nadj - r;
+ return r;
+}
diff --git a/lib/msun/src/e_lgammaf.c b/lib/msun/src/e_lgammaf.c
new file mode 100644
index 0000000..4fcf943
--- /dev/null
+++ b/lib/msun/src/e_lgammaf.c
@@ -0,0 +1,35 @@
+/* e_lgammaf.c -- float version of e_lgamma.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/* __ieee754_lgammaf(x)
+ * Return the logarithm of the Gamma function of x.
+ *
+ * Method: call __ieee754_lgammaf_r
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+extern int signgam;
+
+float
+__ieee754_lgammaf(float x)
+{
+ return __ieee754_lgammaf_r(x,&signgam);
+}
diff --git a/lib/msun/src/e_lgammaf_r.c b/lib/msun/src/e_lgammaf_r.c
new file mode 100644
index 0000000..16087d3
--- /dev/null
+++ b/lib/msun/src/e_lgammaf_r.c
@@ -0,0 +1,231 @@
+/* e_lgammaf_r.c -- float version of e_lgamma_r.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+#include "math.h"
+#include "math_private.h"
+
+static const float
+two23= 8.3886080000e+06, /* 0x4b000000 */
+half= 5.0000000000e-01, /* 0x3f000000 */
+one = 1.0000000000e+00, /* 0x3f800000 */
+pi = 3.1415927410e+00, /* 0x40490fdb */
+a0 = 7.7215664089e-02, /* 0x3d9e233f */
+a1 = 3.2246702909e-01, /* 0x3ea51a66 */
+a2 = 6.7352302372e-02, /* 0x3d89f001 */
+a3 = 2.0580807701e-02, /* 0x3ca89915 */
+a4 = 7.3855509982e-03, /* 0x3bf2027e */
+a5 = 2.8905137442e-03, /* 0x3b3d6ec6 */
+a6 = 1.1927076848e-03, /* 0x3a9c54a1 */
+a7 = 5.1006977446e-04, /* 0x3a05b634 */
+a8 = 2.2086278477e-04, /* 0x39679767 */
+a9 = 1.0801156895e-04, /* 0x38e28445 */
+a10 = 2.5214456400e-05, /* 0x37d383a2 */
+a11 = 4.4864096708e-05, /* 0x383c2c75 */
+tc = 1.4616321325e+00, /* 0x3fbb16c3 */
+tf = -1.2148628384e-01, /* 0xbdf8cdcd */
+/* tt = -(tail of tf) */
+tt = 6.6971006518e-09, /* 0x31e61c52 */
+t0 = 4.8383611441e-01, /* 0x3ef7b95e */
+t1 = -1.4758771658e-01, /* 0xbe17213c */
+t2 = 6.4624942839e-02, /* 0x3d845a15 */
+t3 = -3.2788541168e-02, /* 0xbd064d47 */
+t4 = 1.7970675603e-02, /* 0x3c93373d */
+t5 = -1.0314224288e-02, /* 0xbc28fcfe */
+t6 = 6.1005386524e-03, /* 0x3bc7e707 */
+t7 = -3.6845202558e-03, /* 0xbb7177fe */
+t8 = 2.2596477065e-03, /* 0x3b141699 */
+t9 = -1.4034647029e-03, /* 0xbab7f476 */
+t10 = 8.8108185446e-04, /* 0x3a66f867 */
+t11 = -5.3859531181e-04, /* 0xba0d3085 */
+t12 = 3.1563205994e-04, /* 0x39a57b6b */
+t13 = -3.1275415677e-04, /* 0xb9a3f927 */
+t14 = 3.3552918467e-04, /* 0x39afe9f7 */
+u0 = -7.7215664089e-02, /* 0xbd9e233f */
+u1 = 6.3282704353e-01, /* 0x3f2200f4 */
+u2 = 1.4549225569e+00, /* 0x3fba3ae7 */
+u3 = 9.7771751881e-01, /* 0x3f7a4bb2 */
+u4 = 2.2896373272e-01, /* 0x3e6a7578 */
+u5 = 1.3381091878e-02, /* 0x3c5b3c5e */
+v1 = 2.4559779167e+00, /* 0x401d2ebe */
+v2 = 2.1284897327e+00, /* 0x4008392d */
+v3 = 7.6928514242e-01, /* 0x3f44efdf */
+v4 = 1.0422264785e-01, /* 0x3dd572af */
+v5 = 3.2170924824e-03, /* 0x3b52d5db */
+s0 = -7.7215664089e-02, /* 0xbd9e233f */
+s1 = 2.1498242021e-01, /* 0x3e5c245a */
+s2 = 3.2577878237e-01, /* 0x3ea6cc7a */
+s3 = 1.4635047317e-01, /* 0x3e15dce6 */
+s4 = 2.6642270386e-02, /* 0x3cda40e4 */
+s5 = 1.8402845599e-03, /* 0x3af135b4 */
+s6 = 3.1947532989e-05, /* 0x3805ff67 */
+r1 = 1.3920053244e+00, /* 0x3fb22d3b */
+r2 = 7.2193557024e-01, /* 0x3f38d0c5 */
+r3 = 1.7193385959e-01, /* 0x3e300f6e */
+r4 = 1.8645919859e-02, /* 0x3c98bf54 */
+r5 = 7.7794247773e-04, /* 0x3a4beed6 */
+r6 = 7.3266842264e-06, /* 0x36f5d7bd */
+w0 = 4.1893854737e-01, /* 0x3ed67f1d */
+w1 = 8.3333335817e-02, /* 0x3daaaaab */
+w2 = -2.7777778450e-03, /* 0xbb360b61 */
+w3 = 7.9365057172e-04, /* 0x3a500cfd */
+w4 = -5.9518753551e-04, /* 0xba1c065c */
+w5 = 8.3633989561e-04, /* 0x3a5b3dd2 */
+w6 = -1.6309292987e-03; /* 0xbad5c4e8 */
+
+static const float zero= 0.0000000000e+00;
+
+ static float sin_pif(float x)
+{
+ float y,z;
+ int n,ix;
+
+ GET_FLOAT_WORD(ix,x);
+ ix &= 0x7fffffff;
+
+ if(ix<0x3e800000) return __kernel_sindf(pi*x);
+ y = -x; /* x is assume negative */
+
+ /*
+ * argument reduction, make sure inexact flag not raised if input
+ * is an integer
+ */
+ z = floorf(y);
+ if(z!=y) { /* inexact anyway */
+ y *= (float)0.5;
+ y = (float)2.0*(y - floorf(y)); /* y = |x| mod 2.0 */
+ n = (int) (y*(float)4.0);
+ } else {
+ if(ix>=0x4b800000) {
+ y = zero; n = 0; /* y must be even */
+ } else {
+ if(ix<0x4b000000) z = y+two23; /* exact */
+ GET_FLOAT_WORD(n,z);
+ n &= 1;
+ y = n;
+ n<<= 2;
+ }
+ }
+ switch (n) {
+ case 0: y = __kernel_sindf(pi*y); break;
+ case 1:
+ case 2: y = __kernel_cosdf(pi*((float)0.5-y)); break;
+ case 3:
+ case 4: y = __kernel_sindf(pi*(one-y)); break;
+ case 5:
+ case 6: y = -__kernel_cosdf(pi*(y-(float)1.5)); break;
+ default: y = __kernel_sindf(pi*(y-(float)2.0)); break;
+ }
+ return -y;
+}
+
+
+float
+__ieee754_lgammaf_r(float x, int *signgamp)
+{
+ float t,y,z,nadj,p,p1,p2,p3,q,r,w;
+ int i,hx,ix;
+
+ GET_FLOAT_WORD(hx,x);
+
+ /* purge off +-inf, NaN, +-0, and negative arguments */
+ *signgamp = 1;
+ ix = hx&0x7fffffff;
+ if(ix>=0x7f800000) return x*x;
+ if(ix==0) return one/zero;
+ if(ix<0x35000000) { /* |x|<2**-21, return -log(|x|) */
+ if(hx<0) {
+ *signgamp = -1;
+ return -__ieee754_logf(-x);
+ } else return -__ieee754_logf(x);
+ }
+ if(hx<0) {
+ if(ix>=0x4b000000) /* |x|>=2**23, must be -integer */
+ return one/zero;
+ t = sin_pif(x);
+ if(t==zero) return one/zero; /* -integer */
+ nadj = __ieee754_logf(pi/fabsf(t*x));
+ if(t<zero) *signgamp = -1;
+ x = -x;
+ }
+
+ /* purge off 1 and 2 */
+ if (ix==0x3f800000||ix==0x40000000) r = 0;
+ /* for x < 2.0 */
+ else if(ix<0x40000000) {
+ if(ix<=0x3f666666) { /* lgamma(x) = lgamma(x+1)-log(x) */
+ r = -__ieee754_logf(x);
+ if(ix>=0x3f3b4a20) {y = one-x; i= 0;}
+ else if(ix>=0x3e6d3308) {y= x-(tc-one); i=1;}
+ else {y = x; i=2;}
+ } else {
+ r = zero;
+ if(ix>=0x3fdda618) {y=(float)2.0-x;i=0;} /* [1.7316,2] */
+ else if(ix>=0x3F9da620) {y=x-tc;i=1;} /* [1.23,1.73] */
+ else {y=x-one;i=2;}
+ }
+ switch(i) {
+ case 0:
+ z = y*y;
+ p1 = a0+z*(a2+z*(a4+z*(a6+z*(a8+z*a10))));
+ p2 = z*(a1+z*(a3+z*(a5+z*(a7+z*(a9+z*a11)))));
+ p = y*p1+p2;
+ r += (p-(float)0.5*y); break;
+ case 1:
+ z = y*y;
+ w = z*y;
+ p1 = t0+w*(t3+w*(t6+w*(t9 +w*t12))); /* parallel comp */
+ p2 = t1+w*(t4+w*(t7+w*(t10+w*t13)));
+ p3 = t2+w*(t5+w*(t8+w*(t11+w*t14)));
+ p = z*p1-(tt-w*(p2+y*p3));
+ r += (tf + p); break;
+ case 2:
+ p1 = y*(u0+y*(u1+y*(u2+y*(u3+y*(u4+y*u5)))));
+ p2 = one+y*(v1+y*(v2+y*(v3+y*(v4+y*v5))));
+ r += (-(float)0.5*y + p1/p2);
+ }
+ }
+ else if(ix<0x41000000) { /* x < 8.0 */
+ i = (int)x;
+ t = zero;
+ y = x-(float)i;
+ p = y*(s0+y*(s1+y*(s2+y*(s3+y*(s4+y*(s5+y*s6))))));
+ q = one+y*(r1+y*(r2+y*(r3+y*(r4+y*(r5+y*r6)))));
+ r = half*y+p/q;
+ z = one; /* lgamma(1+s) = log(s) + lgamma(s) */
+ switch(i) {
+ case 7: z *= (y+(float)6.0); /* FALLTHRU */
+ case 6: z *= (y+(float)5.0); /* FALLTHRU */
+ case 5: z *= (y+(float)4.0); /* FALLTHRU */
+ case 4: z *= (y+(float)3.0); /* FALLTHRU */
+ case 3: z *= (y+(float)2.0); /* FALLTHRU */
+ r += __ieee754_logf(z); break;
+ }
+ /* 8.0 <= x < 2**58 */
+ } else if (ix < 0x5c800000) {
+ t = __ieee754_logf(x);
+ z = one/x;
+ y = z*z;
+ w = w0+z*(w1+y*(w2+y*(w3+y*(w4+y*(w5+y*w6)))));
+ r = (x-half)*(t-one)+w;
+ } else
+ /* 2**58 <= x <= inf */
+ r = x*(__ieee754_logf(x)-one);
+ if(hx<0) r = nadj - r;
+ return r;
+}
diff --git a/lib/msun/src/e_log.c b/lib/msun/src/e_log.c
new file mode 100644
index 0000000..eee7cf9
--- /dev/null
+++ b/lib/msun/src/e_log.c
@@ -0,0 +1,135 @@
+
+/* @(#)e_log.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/* __ieee754_log(x)
+ * Return the logrithm of x
+ *
+ * Method :
+ * 1. Argument Reduction: find k and f such that
+ * x = 2^k * (1+f),
+ * where sqrt(2)/2 < 1+f < sqrt(2) .
+ *
+ * 2. Approximation of log(1+f).
+ * Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s)
+ * = 2s + 2/3 s**3 + 2/5 s**5 + .....,
+ * = 2s + s*R
+ * We use a special Reme algorithm on [0,0.1716] to generate
+ * a polynomial of degree 14 to approximate R The maximum error
+ * of this polynomial approximation is bounded by 2**-58.45. In
+ * other words,
+ * 2 4 6 8 10 12 14
+ * R(z) ~ Lg1*s +Lg2*s +Lg3*s +Lg4*s +Lg5*s +Lg6*s +Lg7*s
+ * (the values of Lg1 to Lg7 are listed in the program)
+ * and
+ * | 2 14 | -58.45
+ * | Lg1*s +...+Lg7*s - R(z) | <= 2
+ * | |
+ * Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2.
+ * In order to guarantee error in log below 1ulp, we compute log
+ * by
+ * log(1+f) = f - s*(f - R) (if f is not too large)
+ * log(1+f) = f - (hfsq - s*(hfsq+R)). (better accuracy)
+ *
+ * 3. Finally, log(x) = k*ln2 + log(1+f).
+ * = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo)))
+ * Here ln2 is split into two floating point number:
+ * ln2_hi + ln2_lo,
+ * where n*ln2_hi is always exact for |n| < 2000.
+ *
+ * Special cases:
+ * log(x) is NaN with signal if x < 0 (including -INF) ;
+ * log(+INF) is +INF; log(0) is -INF with signal;
+ * log(NaN) is that NaN with no signal.
+ *
+ * Accuracy:
+ * according to an error analysis, the error is always less than
+ * 1 ulp (unit in the last place).
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following
+ * constants. The decimal values may be used, provided that the
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+static const double
+ln2_hi = 6.93147180369123816490e-01, /* 3fe62e42 fee00000 */
+ln2_lo = 1.90821492927058770002e-10, /* 3dea39ef 35793c76 */
+two54 = 1.80143985094819840000e+16, /* 43500000 00000000 */
+Lg1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */
+Lg2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */
+Lg3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */
+Lg4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */
+Lg5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */
+Lg6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */
+Lg7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */
+
+static const double zero = 0.0;
+
+double
+__ieee754_log(double x)
+{
+ double hfsq,f,s,z,R,w,t1,t2,dk;
+ int32_t k,hx,i,j;
+ u_int32_t lx;
+
+ EXTRACT_WORDS(hx,lx,x);
+
+ k=0;
+ if (hx < 0x00100000) { /* x < 2**-1022 */
+ if (((hx&0x7fffffff)|lx)==0)
+ return -two54/zero; /* log(+-0)=-inf */
+ if (hx<0) return (x-x)/zero; /* log(-#) = NaN */
+ k -= 54; x *= two54; /* subnormal number, scale up x */
+ GET_HIGH_WORD(hx,x);
+ }
+ if (hx >= 0x7ff00000) return x+x;
+ k += (hx>>20)-1023;
+ hx &= 0x000fffff;
+ i = (hx+0x95f64)&0x100000;
+ SET_HIGH_WORD(x,hx|(i^0x3ff00000)); /* normalize x or x/2 */
+ k += (i>>20);
+ f = x-1.0;
+ if((0x000fffff&(2+hx))<3) { /* |f| < 2**-20 */
+ if(f==zero) if(k==0) return zero; else {dk=(double)k;
+ return dk*ln2_hi+dk*ln2_lo;}
+ R = f*f*(0.5-0.33333333333333333*f);
+ if(k==0) return f-R; else {dk=(double)k;
+ return dk*ln2_hi-((R-dk*ln2_lo)-f);}
+ }
+ s = f/(2.0+f);
+ dk = (double)k;
+ z = s*s;
+ i = hx-0x6147a;
+ w = z*z;
+ j = 0x6b851-hx;
+ t1= w*(Lg2+w*(Lg4+w*Lg6));
+ t2= z*(Lg1+w*(Lg3+w*(Lg5+w*Lg7)));
+ i |= j;
+ R = t2+t1;
+ if(i>0) {
+ hfsq=0.5*f*f;
+ if(k==0) return f-(hfsq-s*(hfsq+R)); else
+ return dk*ln2_hi-((hfsq-(s*(hfsq+R)+dk*ln2_lo))-f);
+ } else {
+ if(k==0) return f-s*(f-R); else
+ return dk*ln2_hi-((s*(f-R)-dk*ln2_lo)-f);
+ }
+}
diff --git a/lib/msun/src/e_log10.c b/lib/msun/src/e_log10.c
new file mode 100644
index 0000000..871a44a
--- /dev/null
+++ b/lib/msun/src/e_log10.c
@@ -0,0 +1,87 @@
+
+/* @(#)e_log10.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/* __ieee754_log10(x)
+ * Return the base 10 logarithm of x
+ *
+ * Method :
+ * Let log10_2hi = leading 40 bits of log10(2) and
+ * log10_2lo = log10(2) - log10_2hi,
+ * ivln10 = 1/log(10) rounded.
+ * Then
+ * n = ilogb(x),
+ * if(n<0) n = n+1;
+ * x = scalbn(x,-n);
+ * log10(x) := n*log10_2hi + (n*log10_2lo + ivln10*log(x))
+ *
+ * Note 1:
+ * To guarantee log10(10**n)=n, where 10**n is normal, the rounding
+ * mode must set to Round-to-Nearest.
+ * Note 2:
+ * [1/log(10)] rounded to 53 bits has error .198 ulps;
+ * log10 is monotonic at all binary break points.
+ *
+ * Special cases:
+ * log10(x) is NaN with signal if x < 0;
+ * log10(+INF) is +INF with no signal; log10(0) is -INF with signal;
+ * log10(NaN) is that NaN with no signal;
+ * log10(10**N) = N for N=0,1,...,22.
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following constants.
+ * The decimal values may be used, provided that the compiler will convert
+ * from decimal to binary accurately enough to produce the hexadecimal values
+ * shown.
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+static const double
+two54 = 1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */
+ivln10 = 4.34294481903251816668e-01, /* 0x3FDBCB7B, 0x1526E50E */
+log10_2hi = 3.01029995663611771306e-01, /* 0x3FD34413, 0x509F6000 */
+log10_2lo = 3.69423907715893078616e-13; /* 0x3D59FEF3, 0x11F12B36 */
+
+static const double zero = 0.0;
+
+double
+__ieee754_log10(double x)
+{
+ double y,z;
+ int32_t i,k,hx;
+ u_int32_t lx;
+
+ EXTRACT_WORDS(hx,lx,x);
+
+ k=0;
+ if (hx < 0x00100000) { /* x < 2**-1022 */
+ if (((hx&0x7fffffff)|lx)==0)
+ return -two54/zero; /* log(+-0)=-inf */
+ if (hx<0) return (x-x)/zero; /* log(-#) = NaN */
+ k -= 54; x *= two54; /* subnormal number, scale up x */
+ GET_HIGH_WORD(hx,x);
+ }
+ if (hx >= 0x7ff00000) return x+x;
+ k += (hx>>20)-1023;
+ i = ((u_int32_t)k&0x80000000)>>31;
+ hx = (hx&0x000fffff)|((0x3ff-i)<<20);
+ y = (double)(k+i);
+ SET_HIGH_WORD(x,hx);
+ z = y*log10_2lo + ivln10*__ieee754_log(x);
+ return z+y*log10_2hi;
+}
diff --git a/lib/msun/src/e_log10f.c b/lib/msun/src/e_log10f.c
new file mode 100644
index 0000000..beb2271
--- /dev/null
+++ b/lib/msun/src/e_log10f.c
@@ -0,0 +1,55 @@
+/* e_log10f.c -- float version of e_log10.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+#include "math.h"
+#include "math_private.h"
+
+static const float
+two25 = 3.3554432000e+07, /* 0x4c000000 */
+ivln10 = 4.3429449201e-01, /* 0x3ede5bd9 */
+log10_2hi = 3.0102920532e-01, /* 0x3e9a2080 */
+log10_2lo = 7.9034151668e-07; /* 0x355427db */
+
+static const float zero = 0.0;
+
+float
+__ieee754_log10f(float x)
+{
+ float y,z;
+ int32_t i,k,hx;
+
+ GET_FLOAT_WORD(hx,x);
+
+ k=0;
+ if (hx < 0x00800000) { /* x < 2**-126 */
+ if ((hx&0x7fffffff)==0)
+ return -two25/zero; /* log(+-0)=-inf */
+ if (hx<0) return (x-x)/zero; /* log(-#) = NaN */
+ k -= 25; x *= two25; /* subnormal number, scale up x */
+ GET_FLOAT_WORD(hx,x);
+ }
+ if (hx >= 0x7f800000) return x+x;
+ k += (hx>>23)-127;
+ i = ((u_int32_t)k&0x80000000)>>31;
+ hx = (hx&0x007fffff)|((0x7f-i)<<23);
+ y = (float)(k+i);
+ SET_FLOAT_WORD(x,hx);
+ z = y*log10_2lo + ivln10*__ieee754_logf(x);
+ return z+y*log10_2hi;
+}
diff --git a/lib/msun/src/e_logf.c b/lib/msun/src/e_logf.c
new file mode 100644
index 0000000..b47b77b
--- /dev/null
+++ b/lib/msun/src/e_logf.c
@@ -0,0 +1,83 @@
+/* e_logf.c -- float version of e_log.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+#include "math.h"
+#include "math_private.h"
+
+static const float
+ln2_hi = 6.9313812256e-01, /* 0x3f317180 */
+ln2_lo = 9.0580006145e-06, /* 0x3717f7d1 */
+two25 = 3.355443200e+07, /* 0x4c000000 */
+/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */
+Lg1 = 0xaaaaaa.0p-24, /* 0.66666662693 */
+Lg2 = 0xccce13.0p-25, /* 0.40000972152 */
+Lg3 = 0x91e9ee.0p-25, /* 0.28498786688 */
+Lg4 = 0xf89e26.0p-26; /* 0.24279078841 */
+
+static const float zero = 0.0;
+
+float
+__ieee754_logf(float x)
+{
+ float hfsq,f,s,z,R,w,t1,t2,dk;
+ int32_t k,ix,i,j;
+
+ GET_FLOAT_WORD(ix,x);
+
+ k=0;
+ if (ix < 0x00800000) { /* x < 2**-126 */
+ if ((ix&0x7fffffff)==0)
+ return -two25/zero; /* log(+-0)=-inf */
+ if (ix<0) return (x-x)/zero; /* log(-#) = NaN */
+ k -= 25; x *= two25; /* subnormal number, scale up x */
+ GET_FLOAT_WORD(ix,x);
+ }
+ if (ix >= 0x7f800000) return x+x;
+ k += (ix>>23)-127;
+ ix &= 0x007fffff;
+ i = (ix+(0x95f64<<3))&0x800000;
+ SET_FLOAT_WORD(x,ix|(i^0x3f800000)); /* normalize x or x/2 */
+ k += (i>>23);
+ f = x-(float)1.0;
+ if((0x007fffff&(15+ix))<16) { /* |f| < 2**-20 */
+ if(f==zero) if(k==0) return zero; else {dk=(float)k;
+ return dk*ln2_hi+dk*ln2_lo;}
+ R = f*f*((float)0.5-(float)0.33333333333333333*f);
+ if(k==0) return f-R; else {dk=(float)k;
+ return dk*ln2_hi-((R-dk*ln2_lo)-f);}
+ }
+ s = f/((float)2.0+f);
+ dk = (float)k;
+ z = s*s;
+ i = ix-(0x6147a<<3);
+ w = z*z;
+ j = (0x6b851<<3)-ix;
+ t1= w*(Lg2+w*Lg4);
+ t2= z*(Lg1+w*Lg3);
+ i |= j;
+ R = t2+t1;
+ if(i>0) {
+ hfsq=(float)0.5*f*f;
+ if(k==0) return f-(hfsq-s*(hfsq+R)); else
+ return dk*ln2_hi-((hfsq-(s*(hfsq+R)+dk*ln2_lo))-f);
+ } else {
+ if(k==0) return f-s*(f-R); else
+ return dk*ln2_hi-((s*(f-R)-dk*ln2_lo)-f);
+ }
+}
diff --git a/lib/msun/src/e_pow.c b/lib/msun/src/e_pow.c
new file mode 100644
index 0000000..95d0855
--- /dev/null
+++ b/lib/msun/src/e_pow.c
@@ -0,0 +1,304 @@
+/* @(#)e_pow.c 1.5 04/04/22 SMI */
+/*
+ * ====================================================
+ * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/* __ieee754_pow(x,y) return x**y
+ *
+ * n
+ * Method: Let x = 2 * (1+f)
+ * 1. Compute and return log2(x) in two pieces:
+ * log2(x) = w1 + w2,
+ * where w1 has 53-24 = 29 bit trailing zeros.
+ * 2. Perform y*log2(x) = n+y' by simulating muti-precision
+ * arithmetic, where |y'|<=0.5.
+ * 3. Return x**y = 2**n*exp(y'*log2)
+ *
+ * Special cases:
+ * 1. (anything) ** 0 is 1
+ * 2. (anything) ** 1 is itself
+ * 3. (anything) ** NAN is NAN
+ * 4. NAN ** (anything except 0) is NAN
+ * 5. +-(|x| > 1) ** +INF is +INF
+ * 6. +-(|x| > 1) ** -INF is +0
+ * 7. +-(|x| < 1) ** +INF is +0
+ * 8. +-(|x| < 1) ** -INF is +INF
+ * 9. +-1 ** +-INF is NAN
+ * 10. +0 ** (+anything except 0, NAN) is +0
+ * 11. -0 ** (+anything except 0, NAN, odd integer) is +0
+ * 12. +0 ** (-anything except 0, NAN) is +INF
+ * 13. -0 ** (-anything except 0, NAN, odd integer) is +INF
+ * 14. -0 ** (odd integer) = -( +0 ** (odd integer) )
+ * 15. +INF ** (+anything except 0,NAN) is +INF
+ * 16. +INF ** (-anything except 0,NAN) is +0
+ * 17. -INF ** (anything) = -0 ** (-anything)
+ * 18. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer)
+ * 19. (-anything except 0 and inf) ** (non-integer) is NAN
+ *
+ * Accuracy:
+ * pow(x,y) returns x**y nearly rounded. In particular
+ * pow(integer,integer)
+ * always returns the correct integer provided it is
+ * representable.
+ *
+ * Constants :
+ * The hexadecimal values are the intended ones for the following
+ * constants. The decimal values may be used, provided that the
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+static const double
+bp[] = {1.0, 1.5,},
+dp_h[] = { 0.0, 5.84962487220764160156e-01,}, /* 0x3FE2B803, 0x40000000 */
+dp_l[] = { 0.0, 1.35003920212974897128e-08,}, /* 0x3E4CFDEB, 0x43CFD006 */
+zero = 0.0,
+one = 1.0,
+two = 2.0,
+two53 = 9007199254740992.0, /* 0x43400000, 0x00000000 */
+huge = 1.0e300,
+tiny = 1.0e-300,
+ /* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */
+L1 = 5.99999999999994648725e-01, /* 0x3FE33333, 0x33333303 */
+L2 = 4.28571428578550184252e-01, /* 0x3FDB6DB6, 0xDB6FABFF */
+L3 = 3.33333329818377432918e-01, /* 0x3FD55555, 0x518F264D */
+L4 = 2.72728123808534006489e-01, /* 0x3FD17460, 0xA91D4101 */
+L5 = 2.30660745775561754067e-01, /* 0x3FCD864A, 0x93C9DB65 */
+L6 = 2.06975017800338417784e-01, /* 0x3FCA7E28, 0x4A454EEF */
+P1 = 1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */
+P2 = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */
+P3 = 6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */
+P4 = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */
+P5 = 4.13813679705723846039e-08, /* 0x3E663769, 0x72BEA4D0 */
+lg2 = 6.93147180559945286227e-01, /* 0x3FE62E42, 0xFEFA39EF */
+lg2_h = 6.93147182464599609375e-01, /* 0x3FE62E43, 0x00000000 */
+lg2_l = -1.90465429995776804525e-09, /* 0xBE205C61, 0x0CA86C39 */
+ovt = 8.0085662595372944372e-0017, /* -(1024-log2(ovfl+.5ulp)) */
+cp = 9.61796693925975554329e-01, /* 0x3FEEC709, 0xDC3A03FD =2/(3ln2) */
+cp_h = 9.61796700954437255859e-01, /* 0x3FEEC709, 0xE0000000 =(float)cp */
+cp_l = -7.02846165095275826516e-09, /* 0xBE3E2FE0, 0x145B01F5 =tail of cp_h*/
+ivln2 = 1.44269504088896338700e+00, /* 0x3FF71547, 0x652B82FE =1/ln2 */
+ivln2_h = 1.44269502162933349609e+00, /* 0x3FF71547, 0x60000000 =24b 1/ln2*/
+ivln2_l = 1.92596299112661746887e-08; /* 0x3E54AE0B, 0xF85DDF44 =1/ln2 tail*/
+
+double
+__ieee754_pow(double x, double y)
+{
+ double z,ax,z_h,z_l,p_h,p_l;
+ double y1,t1,t2,r,s,t,u,v,w;
+ int32_t i,j,k,yisint,n;
+ int32_t hx,hy,ix,iy;
+ u_int32_t lx,ly;
+
+ EXTRACT_WORDS(hx,lx,x);
+ EXTRACT_WORDS(hy,ly,y);
+ ix = hx&0x7fffffff; iy = hy&0x7fffffff;
+
+ /* y==zero: x**0 = 1 */
+ if((iy|ly)==0) return one;
+
+ /* +-NaN return x+y */
+ if(ix > 0x7ff00000 || ((ix==0x7ff00000)&&(lx!=0)) ||
+ iy > 0x7ff00000 || ((iy==0x7ff00000)&&(ly!=0)))
+ return x+y;
+
+ /* determine if y is an odd int when x < 0
+ * yisint = 0 ... y is not an integer
+ * yisint = 1 ... y is an odd int
+ * yisint = 2 ... y is an even int
+ */
+ yisint = 0;
+ if(hx<0) {
+ if(iy>=0x43400000) yisint = 2; /* even integer y */
+ else if(iy>=0x3ff00000) {
+ k = (iy>>20)-0x3ff; /* exponent */
+ if(k>20) {
+ j = ly>>(52-k);
+ if((j<<(52-k))==ly) yisint = 2-(j&1);
+ } else if(ly==0) {
+ j = iy>>(20-k);
+ if((j<<(20-k))==iy) yisint = 2-(j&1);
+ }
+ }
+ }
+
+ /* special value of y */
+ if(ly==0) {
+ if (iy==0x7ff00000) { /* y is +-inf */
+ if(((ix-0x3ff00000)|lx)==0)
+ return y - y; /* inf**+-1 is NaN */
+ else if (ix >= 0x3ff00000)/* (|x|>1)**+-inf = inf,0 */
+ return (hy>=0)? y: zero;
+ else /* (|x|<1)**-,+inf = inf,0 */
+ return (hy<0)?-y: zero;
+ }
+ if(iy==0x3ff00000) { /* y is +-1 */
+ if(hy<0) return one/x; else return x;
+ }
+ if(hy==0x40000000) return x*x; /* y is 2 */
+ if(hy==0x3fe00000) { /* y is 0.5 */
+ if(hx>=0) /* x >= +0 */
+ return sqrt(x);
+ }
+ }
+
+ ax = fabs(x);
+ /* special value of x */
+ if(lx==0) {
+ if(ix==0x7ff00000||ix==0||ix==0x3ff00000){
+ z = ax; /*x is +-0,+-inf,+-1*/
+ if(hy<0) z = one/z; /* z = (1/|x|) */
+ if(hx<0) {
+ if(((ix-0x3ff00000)|yisint)==0) {
+ z = (z-z)/(z-z); /* (-1)**non-int is NaN */
+ } else if(yisint==1)
+ z = -z; /* (x<0)**odd = -(|x|**odd) */
+ }
+ return z;
+ }
+ }
+
+ /* CYGNUS LOCAL + fdlibm-5.3 fix: This used to be
+ n = (hx>>31)+1;
+ but ANSI C says a right shift of a signed negative quantity is
+ implementation defined. */
+ n = ((u_int32_t)hx>>31)-1;
+
+ /* (x<0)**(non-int) is NaN */
+ if((n|yisint)==0) return (x-x)/(x-x);
+
+ s = one; /* s (sign of result -ve**odd) = -1 else = 1 */
+ if((n|(yisint-1))==0) s = -one;/* (-ve)**(odd int) */
+
+ /* |y| is huge */
+ if(iy>0x41e00000) { /* if |y| > 2**31 */
+ if(iy>0x43f00000){ /* if |y| > 2**64, must o/uflow */
+ if(ix<=0x3fefffff) return (hy<0)? huge*huge:tiny*tiny;
+ if(ix>=0x3ff00000) return (hy>0)? huge*huge:tiny*tiny;
+ }
+ /* over/underflow if x is not close to one */
+ if(ix<0x3fefffff) return (hy<0)? s*huge*huge:s*tiny*tiny;
+ if(ix>0x3ff00000) return (hy>0)? s*huge*huge:s*tiny*tiny;
+ /* now |1-x| is tiny <= 2**-20, suffice to compute
+ log(x) by x-x^2/2+x^3/3-x^4/4 */
+ t = ax-one; /* t has 20 trailing zeros */
+ w = (t*t)*(0.5-t*(0.3333333333333333333333-t*0.25));
+ u = ivln2_h*t; /* ivln2_h has 21 sig. bits */
+ v = t*ivln2_l-w*ivln2;
+ t1 = u+v;
+ SET_LOW_WORD(t1,0);
+ t2 = v-(t1-u);
+ } else {
+ double ss,s2,s_h,s_l,t_h,t_l;
+ n = 0;
+ /* take care subnormal number */
+ if(ix<0x00100000)
+ {ax *= two53; n -= 53; GET_HIGH_WORD(ix,ax); }
+ n += ((ix)>>20)-0x3ff;
+ j = ix&0x000fffff;
+ /* determine interval */
+ ix = j|0x3ff00000; /* normalize ix */
+ if(j<=0x3988E) k=0; /* |x|<sqrt(3/2) */
+ else if(j<0xBB67A) k=1; /* |x|<sqrt(3) */
+ else {k=0;n+=1;ix -= 0x00100000;}
+ SET_HIGH_WORD(ax,ix);
+
+ /* compute ss = s_h+s_l = (x-1)/(x+1) or (x-1.5)/(x+1.5) */
+ u = ax-bp[k]; /* bp[0]=1.0, bp[1]=1.5 */
+ v = one/(ax+bp[k]);
+ ss = u*v;
+ s_h = ss;
+ SET_LOW_WORD(s_h,0);
+ /* t_h=ax+bp[k] High */
+ t_h = zero;
+ SET_HIGH_WORD(t_h,((ix>>1)|0x20000000)+0x00080000+(k<<18));
+ t_l = ax - (t_h-bp[k]);
+ s_l = v*((u-s_h*t_h)-s_h*t_l);
+ /* compute log(ax) */
+ s2 = ss*ss;
+ r = s2*s2*(L1+s2*(L2+s2*(L3+s2*(L4+s2*(L5+s2*L6)))));
+ r += s_l*(s_h+ss);
+ s2 = s_h*s_h;
+ t_h = 3.0+s2+r;
+ SET_LOW_WORD(t_h,0);
+ t_l = r-((t_h-3.0)-s2);
+ /* u+v = ss*(1+...) */
+ u = s_h*t_h;
+ v = s_l*t_h+t_l*ss;
+ /* 2/(3log2)*(ss+...) */
+ p_h = u+v;
+ SET_LOW_WORD(p_h,0);
+ p_l = v-(p_h-u);
+ z_h = cp_h*p_h; /* cp_h+cp_l = 2/(3*log2) */
+ z_l = cp_l*p_h+p_l*cp+dp_l[k];
+ /* log2(ax) = (ss+..)*2/(3*log2) = n + dp_h + z_h + z_l */
+ t = (double)n;
+ t1 = (((z_h+z_l)+dp_h[k])+t);
+ SET_LOW_WORD(t1,0);
+ t2 = z_l-(((t1-t)-dp_h[k])-z_h);
+ }
+
+ /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */
+ y1 = y;
+ SET_LOW_WORD(y1,0);
+ p_l = (y-y1)*t1+y*t2;
+ p_h = y1*t1;
+ z = p_l+p_h;
+ EXTRACT_WORDS(j,i,z);
+ if (j>=0x40900000) { /* z >= 1024 */
+ if(((j-0x40900000)|i)!=0) /* if z > 1024 */
+ return s*huge*huge; /* overflow */
+ else {
+ if(p_l+ovt>z-p_h) return s*huge*huge; /* overflow */
+ }
+ } else if((j&0x7fffffff)>=0x4090cc00 ) { /* z <= -1075 */
+ if(((j-0xc090cc00)|i)!=0) /* z < -1075 */
+ return s*tiny*tiny; /* underflow */
+ else {
+ if(p_l<=z-p_h) return s*tiny*tiny; /* underflow */
+ }
+ }
+ /*
+ * compute 2**(p_h+p_l)
+ */
+ i = j&0x7fffffff;
+ k = (i>>20)-0x3ff;
+ n = 0;
+ if(i>0x3fe00000) { /* if |z| > 0.5, set n = [z+0.5] */
+ n = j+(0x00100000>>(k+1));
+ k = ((n&0x7fffffff)>>20)-0x3ff; /* new k for n */
+ t = zero;
+ SET_HIGH_WORD(t,n&~(0x000fffff>>k));
+ n = ((n&0x000fffff)|0x00100000)>>(20-k);
+ if(j<0) n = -n;
+ p_h -= t;
+ }
+ t = p_l+p_h;
+ SET_LOW_WORD(t,0);
+ u = t*lg2_h;
+ v = (p_l-(t-p_h))*lg2+t*lg2_l;
+ z = u+v;
+ w = v-(z-u);
+ t = z*z;
+ t1 = z - t*(P1+t*(P2+t*(P3+t*(P4+t*P5))));
+ r = (z*t1)/(t1-two)-(w+z*w);
+ z = one-(r-z);
+ GET_HIGH_WORD(j,z);
+ j += (n<<20);
+ if((j>>20)<=0) z = scalbn(z,n); /* subnormal output */
+ else SET_HIGH_WORD(z,j);
+ return s*z;
+}
diff --git a/lib/msun/src/e_powf.c b/lib/msun/src/e_powf.c
new file mode 100644
index 0000000..09fb59c
--- /dev/null
+++ b/lib/msun/src/e_powf.c
@@ -0,0 +1,247 @@
+/* e_powf.c -- float version of e_pow.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+#include "math.h"
+#include "math_private.h"
+
+static const float
+bp[] = {1.0, 1.5,},
+dp_h[] = { 0.0, 5.84960938e-01,}, /* 0x3f15c000 */
+dp_l[] = { 0.0, 1.56322085e-06,}, /* 0x35d1cfdc */
+zero = 0.0,
+one = 1.0,
+two = 2.0,
+two24 = 16777216.0, /* 0x4b800000 */
+huge = 1.0e30,
+tiny = 1.0e-30,
+ /* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */
+L1 = 6.0000002384e-01, /* 0x3f19999a */
+L2 = 4.2857143283e-01, /* 0x3edb6db7 */
+L3 = 3.3333334327e-01, /* 0x3eaaaaab */
+L4 = 2.7272811532e-01, /* 0x3e8ba305 */
+L5 = 2.3066075146e-01, /* 0x3e6c3255 */
+L6 = 2.0697501302e-01, /* 0x3e53f142 */
+P1 = 1.6666667163e-01, /* 0x3e2aaaab */
+P2 = -2.7777778450e-03, /* 0xbb360b61 */
+P3 = 6.6137559770e-05, /* 0x388ab355 */
+P4 = -1.6533901999e-06, /* 0xb5ddea0e */
+P5 = 4.1381369442e-08, /* 0x3331bb4c */
+lg2 = 6.9314718246e-01, /* 0x3f317218 */
+lg2_h = 6.93145752e-01, /* 0x3f317200 */
+lg2_l = 1.42860654e-06, /* 0x35bfbe8c */
+ovt = 4.2995665694e-08, /* -(128-log2(ovfl+.5ulp)) */
+cp = 9.6179670095e-01, /* 0x3f76384f =2/(3ln2) */
+cp_h = 9.6179199219e-01, /* 0x3f763800 =head of cp */
+cp_l = 4.7017383622e-06, /* 0x369dc3a0 =tail of cp_h */
+ivln2 = 1.4426950216e+00, /* 0x3fb8aa3b =1/ln2 */
+ivln2_h = 1.4426879883e+00, /* 0x3fb8aa00 =16b 1/ln2*/
+ivln2_l = 7.0526075433e-06; /* 0x36eca570 =1/ln2 tail*/
+
+float
+__ieee754_powf(float x, float y)
+{
+ float z,ax,z_h,z_l,p_h,p_l;
+ float y1,t1,t2,r,s,sn,t,u,v,w;
+ int32_t i,j,k,yisint,n;
+ int32_t hx,hy,ix,iy,is;
+
+ GET_FLOAT_WORD(hx,x);
+ GET_FLOAT_WORD(hy,y);
+ ix = hx&0x7fffffff; iy = hy&0x7fffffff;
+
+ /* y==zero: x**0 = 1 */
+ if(iy==0) return one;
+
+ /* +-NaN return x+y */
+ if(ix > 0x7f800000 ||
+ iy > 0x7f800000)
+ return x+y;
+
+ /* determine if y is an odd int when x < 0
+ * yisint = 0 ... y is not an integer
+ * yisint = 1 ... y is an odd int
+ * yisint = 2 ... y is an even int
+ */
+ yisint = 0;
+ if(hx<0) {
+ if(iy>=0x4b800000) yisint = 2; /* even integer y */
+ else if(iy>=0x3f800000) {
+ k = (iy>>23)-0x7f; /* exponent */
+ j = iy>>(23-k);
+ if((j<<(23-k))==iy) yisint = 2-(j&1);
+ }
+ }
+
+ /* special value of y */
+ if (iy==0x7f800000) { /* y is +-inf */
+ if (ix==0x3f800000)
+ return y - y; /* inf**+-1 is NaN */
+ else if (ix > 0x3f800000)/* (|x|>1)**+-inf = inf,0 */
+ return (hy>=0)? y: zero;
+ else /* (|x|<1)**-,+inf = inf,0 */
+ return (hy<0)?-y: zero;
+ }
+ if(iy==0x3f800000) { /* y is +-1 */
+ if(hy<0) return one/x; else return x;
+ }
+ if(hy==0x40000000) return x*x; /* y is 2 */
+ if(hy==0x3f000000) { /* y is 0.5 */
+ if(hx>=0) /* x >= +0 */
+ return __ieee754_sqrtf(x);
+ }
+
+ ax = fabsf(x);
+ /* special value of x */
+ if(ix==0x7f800000||ix==0||ix==0x3f800000){
+ z = ax; /*x is +-0,+-inf,+-1*/
+ if(hy<0) z = one/z; /* z = (1/|x|) */
+ if(hx<0) {
+ if(((ix-0x3f800000)|yisint)==0) {
+ z = (z-z)/(z-z); /* (-1)**non-int is NaN */
+ } else if(yisint==1)
+ z = -z; /* (x<0)**odd = -(|x|**odd) */
+ }
+ return z;
+ }
+
+ n = ((u_int32_t)hx>>31)-1;
+
+ /* (x<0)**(non-int) is NaN */
+ if((n|yisint)==0) return (x-x)/(x-x);
+
+ sn = one; /* s (sign of result -ve**odd) = -1 else = 1 */
+ if((n|(yisint-1))==0) sn = -one;/* (-ve)**(odd int) */
+
+ /* |y| is huge */
+ if(iy>0x4d000000) { /* if |y| > 2**27 */
+ /* over/underflow if x is not close to one */
+ if(ix<0x3f7ffff8) return (hy<0)? sn*huge*huge:sn*tiny*tiny;
+ if(ix>0x3f800007) return (hy>0)? sn*huge*huge:sn*tiny*tiny;
+ /* now |1-x| is tiny <= 2**-20, suffice to compute
+ log(x) by x-x^2/2+x^3/3-x^4/4 */
+ t = ax-1; /* t has 20 trailing zeros */
+ w = (t*t)*((float)0.5-t*((float)0.333333333333-t*(float)0.25));
+ u = ivln2_h*t; /* ivln2_h has 16 sig. bits */
+ v = t*ivln2_l-w*ivln2;
+ t1 = u+v;
+ GET_FLOAT_WORD(is,t1);
+ SET_FLOAT_WORD(t1,is&0xfffff000);
+ t2 = v-(t1-u);
+ } else {
+ float s2,s_h,s_l,t_h,t_l;
+ n = 0;
+ /* take care subnormal number */
+ if(ix<0x00800000)
+ {ax *= two24; n -= 24; GET_FLOAT_WORD(ix,ax); }
+ n += ((ix)>>23)-0x7f;
+ j = ix&0x007fffff;
+ /* determine interval */
+ ix = j|0x3f800000; /* normalize ix */
+ if(j<=0x1cc471) k=0; /* |x|<sqrt(3/2) */
+ else if(j<0x5db3d7) k=1; /* |x|<sqrt(3) */
+ else {k=0;n+=1;ix -= 0x00800000;}
+ SET_FLOAT_WORD(ax,ix);
+
+ /* compute s = s_h+s_l = (x-1)/(x+1) or (x-1.5)/(x+1.5) */
+ u = ax-bp[k]; /* bp[0]=1.0, bp[1]=1.5 */
+ v = one/(ax+bp[k]);
+ s = u*v;
+ s_h = s;
+ GET_FLOAT_WORD(is,s_h);
+ SET_FLOAT_WORD(s_h,is&0xfffff000);
+ /* t_h=ax+bp[k] High */
+ is = ((ix>>1)&0xfffff000)|0x20000000;
+ SET_FLOAT_WORD(t_h,is+0x00400000+(k<<21));
+ t_l = ax - (t_h-bp[k]);
+ s_l = v*((u-s_h*t_h)-s_h*t_l);
+ /* compute log(ax) */
+ s2 = s*s;
+ r = s2*s2*(L1+s2*(L2+s2*(L3+s2*(L4+s2*(L5+s2*L6)))));
+ r += s_l*(s_h+s);
+ s2 = s_h*s_h;
+ t_h = (float)3.0+s2+r;
+ GET_FLOAT_WORD(is,t_h);
+ SET_FLOAT_WORD(t_h,is&0xfffff000);
+ t_l = r-((t_h-(float)3.0)-s2);
+ /* u+v = s*(1+...) */
+ u = s_h*t_h;
+ v = s_l*t_h+t_l*s;
+ /* 2/(3log2)*(s+...) */
+ p_h = u+v;
+ GET_FLOAT_WORD(is,p_h);
+ SET_FLOAT_WORD(p_h,is&0xfffff000);
+ p_l = v-(p_h-u);
+ z_h = cp_h*p_h; /* cp_h+cp_l = 2/(3*log2) */
+ z_l = cp_l*p_h+p_l*cp+dp_l[k];
+ /* log2(ax) = (s+..)*2/(3*log2) = n + dp_h + z_h + z_l */
+ t = (float)n;
+ t1 = (((z_h+z_l)+dp_h[k])+t);
+ GET_FLOAT_WORD(is,t1);
+ SET_FLOAT_WORD(t1,is&0xfffff000);
+ t2 = z_l-(((t1-t)-dp_h[k])-z_h);
+ }
+
+ /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */
+ GET_FLOAT_WORD(is,y);
+ SET_FLOAT_WORD(y1,is&0xfffff000);
+ p_l = (y-y1)*t1+y*t2;
+ p_h = y1*t1;
+ z = p_l+p_h;
+ GET_FLOAT_WORD(j,z);
+ if (j>0x43000000) /* if z > 128 */
+ return sn*huge*huge; /* overflow */
+ else if (j==0x43000000) { /* if z == 128 */
+ if(p_l+ovt>z-p_h) return sn*huge*huge; /* overflow */
+ }
+ else if ((j&0x7fffffff)>0x43160000) /* z <= -150 */
+ return sn*tiny*tiny; /* underflow */
+ else if (j==0xc3160000){ /* z == -150 */
+ if(p_l<=z-p_h) return sn*tiny*tiny; /* underflow */
+ }
+ /*
+ * compute 2**(p_h+p_l)
+ */
+ i = j&0x7fffffff;
+ k = (i>>23)-0x7f;
+ n = 0;
+ if(i>0x3f000000) { /* if |z| > 0.5, set n = [z+0.5] */
+ n = j+(0x00800000>>(k+1));
+ k = ((n&0x7fffffff)>>23)-0x7f; /* new k for n */
+ SET_FLOAT_WORD(t,n&~(0x007fffff>>k));
+ n = ((n&0x007fffff)|0x00800000)>>(23-k);
+ if(j<0) n = -n;
+ p_h -= t;
+ }
+ t = p_l+p_h;
+ GET_FLOAT_WORD(is,t);
+ SET_FLOAT_WORD(t,is&0xffff8000);
+ u = t*lg2_h;
+ v = (p_l-(t-p_h))*lg2+t*lg2_l;
+ z = u+v;
+ w = v-(z-u);
+ t = z*z;
+ t1 = z - t*(P1+t*(P2+t*(P3+t*(P4+t*P5))));
+ r = (z*t1)/(t1-two)-(w+z*w);
+ z = one-(r-z);
+ GET_FLOAT_WORD(j,z);
+ j += (n<<23);
+ if((j>>23)<=0) z = scalbnf(z,n); /* subnormal output */
+ else SET_FLOAT_WORD(z,j);
+ return sn*z;
+}
diff --git a/lib/msun/src/e_rem_pio2.c b/lib/msun/src/e_rem_pio2.c
new file mode 100644
index 0000000..5b4a08d
--- /dev/null
+++ b/lib/msun/src/e_rem_pio2.c
@@ -0,0 +1,168 @@
+
+/* @(#)e_rem_pio2.c 1.4 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/* __ieee754_rem_pio2(x,y)
+ *
+ * return the remainder of x rem pi/2 in y[0]+y[1]
+ * use __kernel_rem_pio2()
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+/*
+ * Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi
+ */
+static const int32_t two_over_pi[] = {
+0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62,
+0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A,
+0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129,
+0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41,
+0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8,
+0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF,
+0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5,
+0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08,
+0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3,
+0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880,
+0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B,
+};
+
+static const int32_t npio2_hw[] = {
+0x3FF921FB, 0x400921FB, 0x4012D97C, 0x401921FB, 0x401F6A7A, 0x4022D97C,
+0x4025FDBB, 0x402921FB, 0x402C463A, 0x402F6A7A, 0x4031475C, 0x4032D97C,
+0x40346B9C, 0x4035FDBB, 0x40378FDB, 0x403921FB, 0x403AB41B, 0x403C463A,
+0x403DD85A, 0x403F6A7A, 0x40407E4C, 0x4041475C, 0x4042106C, 0x4042D97C,
+0x4043A28C, 0x40446B9C, 0x404534AC, 0x4045FDBB, 0x4046C6CB, 0x40478FDB,
+0x404858EB, 0x404921FB,
+};
+
+/*
+ * invpio2: 53 bits of 2/pi
+ * pio2_1: first 33 bit of pi/2
+ * pio2_1t: pi/2 - pio2_1
+ * pio2_2: second 33 bit of pi/2
+ * pio2_2t: pi/2 - (pio2_1+pio2_2)
+ * pio2_3: third 33 bit of pi/2
+ * pio2_3t: pi/2 - (pio2_1+pio2_2+pio2_3)
+ */
+
+static const double
+zero = 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */
+half = 5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */
+two24 = 1.67772160000000000000e+07, /* 0x41700000, 0x00000000 */
+invpio2 = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */
+pio2_1 = 1.57079632673412561417e+00, /* 0x3FF921FB, 0x54400000 */
+pio2_1t = 6.07710050650619224932e-11, /* 0x3DD0B461, 0x1A626331 */
+pio2_2 = 6.07710050630396597660e-11, /* 0x3DD0B461, 0x1A600000 */
+pio2_2t = 2.02226624879595063154e-21, /* 0x3BA3198A, 0x2E037073 */
+pio2_3 = 2.02226624871116645580e-21, /* 0x3BA3198A, 0x2E000000 */
+pio2_3t = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */
+
+ int32_t __ieee754_rem_pio2(double x, double *y)
+{
+ double z,w,t,r,fn;
+ double tx[3];
+ int32_t e0,i,j,nx,n,ix,hx;
+ u_int32_t low;
+
+ GET_HIGH_WORD(hx,x); /* high word of x */
+ ix = hx&0x7fffffff;
+ if(ix<=0x3fe921fb) /* |x| ~<= pi/4 , no need for reduction */
+ {y[0] = x; y[1] = 0; return 0;}
+ if(ix<0x4002d97c) { /* |x| < 3pi/4, special case with n=+-1 */
+ if(hx>0) {
+ z = x - pio2_1;
+ if(ix!=0x3ff921fb) { /* 33+53 bit pi is good enough */
+ y[0] = z - pio2_1t;
+ y[1] = (z-y[0])-pio2_1t;
+ } else { /* near pi/2, use 33+33+53 bit pi */
+ z -= pio2_2;
+ y[0] = z - pio2_2t;
+ y[1] = (z-y[0])-pio2_2t;
+ }
+ return 1;
+ } else { /* negative x */
+ z = x + pio2_1;
+ if(ix!=0x3ff921fb) { /* 33+53 bit pi is good enough */
+ y[0] = z + pio2_1t;
+ y[1] = (z-y[0])+pio2_1t;
+ } else { /* near pi/2, use 33+33+53 bit pi */
+ z += pio2_2;
+ y[0] = z + pio2_2t;
+ y[1] = (z-y[0])+pio2_2t;
+ }
+ return -1;
+ }
+ }
+ if(ix<=0x413921fb) { /* |x| ~<= 2^19*(pi/2), medium size */
+ t = fabs(x);
+ n = (int32_t) (t*invpio2+half);
+ fn = (double)n;
+ r = t-fn*pio2_1;
+ w = fn*pio2_1t; /* 1st round good to 85 bit */
+ if(n<32&&ix!=npio2_hw[n-1]) {
+ y[0] = r-w; /* quick check no cancellation */
+ } else {
+ u_int32_t high;
+ j = ix>>20;
+ y[0] = r-w;
+ GET_HIGH_WORD(high,y[0]);
+ i = j-((high>>20)&0x7ff);
+ if(i>16) { /* 2nd iteration needed, good to 118 */
+ t = r;
+ w = fn*pio2_2;
+ r = t-w;
+ w = fn*pio2_2t-((t-r)-w);
+ y[0] = r-w;
+ GET_HIGH_WORD(high,y[0]);
+ i = j-((high>>20)&0x7ff);
+ if(i>49) { /* 3rd iteration need, 151 bits acc */
+ t = r; /* will cover all possible cases */
+ w = fn*pio2_3;
+ r = t-w;
+ w = fn*pio2_3t-((t-r)-w);
+ y[0] = r-w;
+ }
+ }
+ }
+ y[1] = (r-y[0])-w;
+ if(hx<0) {y[0] = -y[0]; y[1] = -y[1]; return -n;}
+ else return n;
+ }
+ /*
+ * all other (large) arguments
+ */
+ if(ix>=0x7ff00000) { /* x is inf or NaN */
+ y[0]=y[1]=x-x; return 0;
+ }
+ /* set z = scalbn(|x|,ilogb(x)-23) */
+ GET_LOW_WORD(low,x);
+ SET_LOW_WORD(z,low);
+ e0 = (ix>>20)-1046; /* e0 = ilogb(z)-23; */
+ SET_HIGH_WORD(z, ix - ((int32_t)(e0<<20)));
+ for(i=0;i<2;i++) {
+ tx[i] = (double)((int32_t)(z));
+ z = (z-tx[i])*two24;
+ }
+ tx[2] = z;
+ nx = 3;
+ while(tx[nx-1]==zero) nx--; /* skip zero term */
+ n = __kernel_rem_pio2(tx,y,e0,nx,2,two_over_pi);
+ if(hx<0) {y[0] = -y[0]; y[1] = -y[1]; return -n;}
+ return n;
+}
diff --git a/lib/msun/src/e_rem_pio2f.c b/lib/msun/src/e_rem_pio2f.c
new file mode 100644
index 0000000..261323b
--- /dev/null
+++ b/lib/msun/src/e_rem_pio2f.c
@@ -0,0 +1,98 @@
+/* e_rem_pio2f.c -- float version of e_rem_pio2.c
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ * Debugged and optimized by Bruce D. Evans.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/* __ieee754_rem_pio2f(x,y)
+ *
+ * return the remainder of x rem pi/2 in y[0]+y[1]
+ * use double precision internally
+ * use __kernel_rem_pio2() for large x
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+/*
+ * Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi
+ */
+static const int32_t two_over_pi[] = {
+0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62,
+0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A,
+0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129,
+0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41,
+0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8,
+0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF,
+0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5,
+0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08,
+0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3,
+0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880,
+0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B,
+};
+
+/*
+ * invpio2: 53 bits of 2/pi
+ * pio2_1: first 33 bit of pi/2
+ * pio2_1t: pi/2 - pio2_1
+ */
+
+static const double
+zero = 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */
+half = 5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */
+two24 = 1.67772160000000000000e+07, /* 0x41700000, 0x00000000 */
+invpio2 = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */
+pio2_1 = 1.57079632673412561417e+00, /* 0x3FF921FB, 0x54400000 */
+pio2_1t = 6.07710050650619224932e-11; /* 0x3DD0B461, 0x1A626331 */
+
+ int32_t __ieee754_rem_pio2f(float x, float *y)
+{
+ double w,t,r,fn;
+ double tx[1],ty[2];
+ float z;
+ int32_t e0,n,ix,hx;
+
+ GET_FLOAT_WORD(hx,x);
+ ix = hx&0x7fffffff;
+ /* 33+53 bit pi is good enough for medium size */
+ if(ix<=0x49490f80) { /* |x| ~<= 2^19*(pi/2), medium size */
+ t = fabsf(x);
+ n = (int32_t) (t*invpio2+half);
+ fn = (double)n;
+ r = t-fn*pio2_1;
+ w = fn*pio2_1t;
+ y[0] = r-w;
+ y[1] = (r-y[0])-w;
+ if(hx<0) {y[0] = -y[0]; y[1] = -y[1]; return -n;}
+ else return n;
+ }
+ /*
+ * all other (large) arguments
+ */
+ if(ix>=0x7f800000) { /* x is inf or NaN */
+ y[0]=y[1]=x-x; return 0;
+ }
+ /* set z = scalbn(|x|,ilogb(|x|)-23) */
+ e0 = (ix>>23)-150; /* e0 = ilogb(|x|)-23; */
+ SET_FLOAT_WORD(z, ix - ((int32_t)(e0<<23)));
+ tx[0] = z;
+ n = __kernel_rem_pio2(tx,ty,e0,1,1,two_over_pi);
+ y[0] = ty[0];
+ y[1] = ty[0] - y[0];
+ if(hx<0) {y[0] = -y[0]; y[1] = -y[1]; return -n;}
+ return n;
+}
diff --git a/lib/msun/src/e_remainder.c b/lib/msun/src/e_remainder.c
new file mode 100644
index 0000000..1cea6c1
--- /dev/null
+++ b/lib/msun/src/e_remainder.c
@@ -0,0 +1,73 @@
+
+/* @(#)e_remainder.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/* __ieee754_remainder(x,p)
+ * Return :
+ * returns x REM p = x - [x/p]*p as if in infinite
+ * precise arithmetic, where [x/p] is the (infinite bit)
+ * integer nearest x/p (in half way case choose the even one).
+ * Method :
+ * Based on fmod() return x-[x/p]chopped*p exactlp.
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+static const double zero = 0.0;
+
+
+double
+__ieee754_remainder(double x, double p)
+{
+ int32_t hx,hp;
+ u_int32_t sx,lx,lp;
+ double p_half;
+
+ EXTRACT_WORDS(hx,lx,x);
+ EXTRACT_WORDS(hp,lp,p);
+ sx = hx&0x80000000;
+ hp &= 0x7fffffff;
+ hx &= 0x7fffffff;
+
+ /* purge off exception values */
+ if((hp|lp)==0) return (x*p)/(x*p); /* p = 0 */
+ if((hx>=0x7ff00000)|| /* x not finite */
+ ((hp>=0x7ff00000)&& /* p is NaN */
+ (((hp-0x7ff00000)|lp)!=0)))
+ return (x*p)/(x*p);
+
+
+ if (hp<=0x7fdfffff) x = __ieee754_fmod(x,p+p); /* now x < 2p */
+ if (((hx-hp)|(lx-lp))==0) return zero*x;
+ x = fabs(x);
+ p = fabs(p);
+ if (hp<0x00200000) {
+ if(x+x>p) {
+ x-=p;
+ if(x+x>=p) x -= p;
+ }
+ } else {
+ p_half = 0.5*p;
+ if(x>p_half) {
+ x-=p;
+ if(x>=p_half) x -= p;
+ }
+ }
+ GET_HIGH_WORD(hx,x);
+ SET_HIGH_WORD(x,hx^sx);
+ return x;
+}
diff --git a/lib/msun/src/e_remainderf.c b/lib/msun/src/e_remainderf.c
new file mode 100644
index 0000000..7841bdc
--- /dev/null
+++ b/lib/msun/src/e_remainderf.c
@@ -0,0 +1,65 @@
+/* e_remainderf.c -- float version of e_remainder.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+#include "math.h"
+#include "math_private.h"
+
+static const float zero = 0.0;
+
+
+float
+__ieee754_remainderf(float x, float p)
+{
+ int32_t hx,hp;
+ u_int32_t sx;
+ float p_half;
+
+ GET_FLOAT_WORD(hx,x);
+ GET_FLOAT_WORD(hp,p);
+ sx = hx&0x80000000;
+ hp &= 0x7fffffff;
+ hx &= 0x7fffffff;
+
+ /* purge off exception values */
+ if(hp==0) return (x*p)/(x*p); /* p = 0 */
+ if((hx>=0x7f800000)|| /* x not finite */
+ ((hp>0x7f800000))) /* p is NaN */
+ return (x*p)/(x*p);
+
+
+ if (hp<=0x7effffff) x = __ieee754_fmodf(x,p+p); /* now x < 2p */
+ if ((hx-hp)==0) return zero*x;
+ x = fabsf(x);
+ p = fabsf(p);
+ if (hp<0x01000000) {
+ if(x+x>p) {
+ x-=p;
+ if(x+x>=p) x -= p;
+ }
+ } else {
+ p_half = (float)0.5*p;
+ if(x>p_half) {
+ x-=p;
+ if(x>=p_half) x -= p;
+ }
+ }
+ GET_FLOAT_WORD(hx,x);
+ SET_FLOAT_WORD(x,hx^sx);
+ return x;
+}
diff --git a/lib/msun/src/e_scalb.c b/lib/msun/src/e_scalb.c
new file mode 100644
index 0000000..f7d46d0
--- /dev/null
+++ b/lib/msun/src/e_scalb.c
@@ -0,0 +1,48 @@
+
+/* @(#)e_scalb.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/*
+ * __ieee754_scalb(x, fn) is provide for
+ * passing various standard test suite. One
+ * should use scalbn() instead.
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+#ifdef _SCALB_INT
+double
+__ieee754_scalb(double x, int fn)
+#else
+double
+__ieee754_scalb(double x, double fn)
+#endif
+{
+#ifdef _SCALB_INT
+ return scalbn(x,fn);
+#else
+ if (isnan(x)||isnan(fn)) return x*fn;
+ if (!finite(fn)) {
+ if(fn>0.0) return x*fn;
+ else return x/(-fn);
+ }
+ if (rint(fn)!=fn) return (fn-fn)/(fn-fn);
+ if ( fn > 65000.0) return scalbn(x, 65000);
+ if (-fn > 65000.0) return scalbn(x,-65000);
+ return scalbn(x,(int)fn);
+#endif
+}
diff --git a/lib/msun/src/e_scalbf.c b/lib/msun/src/e_scalbf.c
new file mode 100644
index 0000000..41945d2
--- /dev/null
+++ b/lib/msun/src/e_scalbf.c
@@ -0,0 +1,46 @@
+/* e_scalbf.c -- float version of e_scalb.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+#include "math.h"
+#include "math_private.h"
+
+#ifdef _SCALB_INT
+float
+__ieee754_scalbf(float x, int fn)
+#else
+float
+__ieee754_scalbf(float x, float fn)
+#endif
+{
+#ifdef _SCALB_INT
+ return scalbnf(x,fn);
+#else
+ if ((isnanf)(x)||(isnanf)(fn)) return x*fn;
+ if (!finitef(fn)) {
+ if(fn>(float)0.0) return x*fn;
+ else return x/(-fn);
+ }
+ if (rintf(fn)!=fn) return (fn-fn)/(fn-fn);
+ if ( fn > (float)65000.0) return scalbnf(x, 65000);
+ if (-fn > (float)65000.0) return scalbnf(x,-65000);
+ return scalbnf(x,(int)fn);
+#endif
+}
+
+__weak_reference(scalbf, ldexpf);
diff --git a/lib/msun/src/e_sinh.c b/lib/msun/src/e_sinh.c
new file mode 100644
index 0000000..09b0597
--- /dev/null
+++ b/lib/msun/src/e_sinh.c
@@ -0,0 +1,79 @@
+
+/* @(#)e_sinh.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/* __ieee754_sinh(x)
+ * Method :
+ * mathematically sinh(x) if defined to be (exp(x)-exp(-x))/2
+ * 1. Replace x by |x| (sinh(-x) = -sinh(x)).
+ * 2.
+ * E + E/(E+1)
+ * 0 <= x <= 22 : sinh(x) := --------------, E=expm1(x)
+ * 2
+ *
+ * 22 <= x <= lnovft : sinh(x) := exp(x)/2
+ * lnovft <= x <= ln2ovft: sinh(x) := exp(x/2)/2 * exp(x/2)
+ * ln2ovft < x : sinh(x) := x*shuge (overflow)
+ *
+ * Special cases:
+ * sinh(x) is |x| if x is +INF, -INF, or NaN.
+ * only sinh(0)=0 is exact for finite x.
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+static const double one = 1.0, shuge = 1.0e307;
+
+double
+__ieee754_sinh(double x)
+{
+ double t,w,h;
+ int32_t ix,jx;
+ u_int32_t lx;
+
+ /* High word of |x|. */
+ GET_HIGH_WORD(jx,x);
+ ix = jx&0x7fffffff;
+
+ /* x is INF or NaN */
+ if(ix>=0x7ff00000) return x+x;
+
+ h = 0.5;
+ if (jx<0) h = -h;
+ /* |x| in [0,22], return sign(x)*0.5*(E+E/(E+1))) */
+ if (ix < 0x40360000) { /* |x|<22 */
+ if (ix<0x3e300000) /* |x|<2**-28 */
+ if(shuge+x>one) return x;/* sinh(tiny) = tiny with inexact */
+ t = expm1(fabs(x));
+ if(ix<0x3ff00000) return h*(2.0*t-t*t/(t+one));
+ return h*(t+t/(t+one));
+ }
+
+ /* |x| in [22, log(maxdouble)] return 0.5*exp(|x|) */
+ if (ix < 0x40862E42) return h*__ieee754_exp(fabs(x));
+
+ /* |x| in [log(maxdouble), overflowthresold] */
+ GET_LOW_WORD(lx,x);
+ if (ix<0x408633CE || ((ix==0x408633ce)&&(lx<=(u_int32_t)0x8fb9f87d))) {
+ w = __ieee754_exp(0.5*fabs(x));
+ t = h*w;
+ return t*w;
+ }
+
+ /* |x| > overflowthresold, sinh(x) overflow */
+ return x*shuge;
+}
diff --git a/lib/msun/src/e_sinhf.c b/lib/msun/src/e_sinhf.c
new file mode 100644
index 0000000..50388fa
--- /dev/null
+++ b/lib/msun/src/e_sinhf.c
@@ -0,0 +1,60 @@
+/* e_sinhf.c -- float version of e_sinh.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+#include "math.h"
+#include "math_private.h"
+
+static const float one = 1.0, shuge = 1.0e37;
+
+float
+__ieee754_sinhf(float x)
+{
+ float t,w,h;
+ int32_t ix,jx;
+
+ GET_FLOAT_WORD(jx,x);
+ ix = jx&0x7fffffff;
+
+ /* x is INF or NaN */
+ if(ix>=0x7f800000) return x+x;
+
+ h = 0.5;
+ if (jx<0) h = -h;
+ /* |x| in [0,9], return sign(x)*0.5*(E+E/(E+1))) */
+ if (ix < 0x41100000) { /* |x|<9 */
+ if (ix<0x39800000) /* |x|<2**-12 */
+ if(shuge+x>one) return x;/* sinh(tiny) = tiny with inexact */
+ t = expm1f(fabsf(x));
+ if(ix<0x3f800000) return h*((float)2.0*t-t*t/(t+one));
+ return h*(t+t/(t+one));
+ }
+
+ /* |x| in [9, logf(maxfloat)] return 0.5*exp(|x|) */
+ if (ix < 0x42b17217) return h*__ieee754_expf(fabsf(x));
+
+ /* |x| in [logf(maxfloat), overflowthresold] */
+ if (ix<=0x42b2d4fc) {
+ w = __ieee754_expf((float)0.5*fabsf(x));
+ t = h*w;
+ return t*w;
+ }
+
+ /* |x| > overflowthresold, sinh(x) overflow */
+ return x*shuge;
+}
diff --git a/lib/msun/src/e_sqrt.c b/lib/msun/src/e_sqrt.c
new file mode 100644
index 0000000..3b3b2a7
--- /dev/null
+++ b/lib/msun/src/e_sqrt.c
@@ -0,0 +1,446 @@
+
+/* @(#)e_sqrt.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/* __ieee754_sqrt(x)
+ * Return correctly rounded sqrt.
+ * ------------------------------------------
+ * | Use the hardware sqrt if you have one |
+ * ------------------------------------------
+ * Method:
+ * Bit by bit method using integer arithmetic. (Slow, but portable)
+ * 1. Normalization
+ * Scale x to y in [1,4) with even powers of 2:
+ * find an integer k such that 1 <= (y=x*2^(2k)) < 4, then
+ * sqrt(x) = 2^k * sqrt(y)
+ * 2. Bit by bit computation
+ * Let q = sqrt(y) truncated to i bit after binary point (q = 1),
+ * i 0
+ * i+1 2
+ * s = 2*q , and y = 2 * ( y - q ). (1)
+ * i i i i
+ *
+ * To compute q from q , one checks whether
+ * i+1 i
+ *
+ * -(i+1) 2
+ * (q + 2 ) <= y. (2)
+ * i
+ * -(i+1)
+ * If (2) is false, then q = q ; otherwise q = q + 2 .
+ * i+1 i i+1 i
+ *
+ * With some algebric manipulation, it is not difficult to see
+ * that (2) is equivalent to
+ * -(i+1)
+ * s + 2 <= y (3)
+ * i i
+ *
+ * The advantage of (3) is that s and y can be computed by
+ * i i
+ * the following recurrence formula:
+ * if (3) is false
+ *
+ * s = s , y = y ; (4)
+ * i+1 i i+1 i
+ *
+ * otherwise,
+ * -i -(i+1)
+ * s = s + 2 , y = y - s - 2 (5)
+ * i+1 i i+1 i i
+ *
+ * One may easily use induction to prove (4) and (5).
+ * Note. Since the left hand side of (3) contain only i+2 bits,
+ * it does not necessary to do a full (53-bit) comparison
+ * in (3).
+ * 3. Final rounding
+ * After generating the 53 bits result, we compute one more bit.
+ * Together with the remainder, we can decide whether the
+ * result is exact, bigger than 1/2ulp, or less than 1/2ulp
+ * (it will never equal to 1/2ulp).
+ * The rounding mode can be detected by checking whether
+ * huge + tiny is equal to huge, and whether huge - tiny is
+ * equal to huge for some floating point number "huge" and "tiny".
+ *
+ * Special cases:
+ * sqrt(+-0) = +-0 ... exact
+ * sqrt(inf) = inf
+ * sqrt(-ve) = NaN ... with invalid signal
+ * sqrt(NaN) = NaN ... with invalid signal for signaling NaN
+ *
+ * Other methods : see the appended file at the end of the program below.
+ *---------------
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+static const double one = 1.0, tiny=1.0e-300;
+
+double
+__ieee754_sqrt(double x)
+{
+ double z;
+ int32_t sign = (int)0x80000000;
+ int32_t ix0,s0,q,m,t,i;
+ u_int32_t r,t1,s1,ix1,q1;
+
+ EXTRACT_WORDS(ix0,ix1,x);
+
+ /* take care of Inf and NaN */
+ if((ix0&0x7ff00000)==0x7ff00000) {
+ return x*x+x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf
+ sqrt(-inf)=sNaN */
+ }
+ /* take care of zero */
+ if(ix0<=0) {
+ if(((ix0&(~sign))|ix1)==0) return x;/* sqrt(+-0) = +-0 */
+ else if(ix0<0)
+ return (x-x)/(x-x); /* sqrt(-ve) = sNaN */
+ }
+ /* normalize x */
+ m = (ix0>>20);
+ if(m==0) { /* subnormal x */
+ while(ix0==0) {
+ m -= 21;
+ ix0 |= (ix1>>11); ix1 <<= 21;
+ }
+ for(i=0;(ix0&0x00100000)==0;i++) ix0<<=1;
+ m -= i-1;
+ ix0 |= (ix1>>(32-i));
+ ix1 <<= i;
+ }
+ m -= 1023; /* unbias exponent */
+ ix0 = (ix0&0x000fffff)|0x00100000;
+ if(m&1){ /* odd m, double x to make it even */
+ ix0 += ix0 + ((ix1&sign)>>31);
+ ix1 += ix1;
+ }
+ m >>= 1; /* m = [m/2] */
+
+ /* generate sqrt(x) bit by bit */
+ ix0 += ix0 + ((ix1&sign)>>31);
+ ix1 += ix1;
+ q = q1 = s0 = s1 = 0; /* [q,q1] = sqrt(x) */
+ r = 0x00200000; /* r = moving bit from right to left */
+
+ while(r!=0) {
+ t = s0+r;
+ if(t<=ix0) {
+ s0 = t+r;
+ ix0 -= t;
+ q += r;
+ }
+ ix0 += ix0 + ((ix1&sign)>>31);
+ ix1 += ix1;
+ r>>=1;
+ }
+
+ r = sign;
+ while(r!=0) {
+ t1 = s1+r;
+ t = s0;
+ if((t<ix0)||((t==ix0)&&(t1<=ix1))) {
+ s1 = t1+r;
+ if(((t1&sign)==sign)&&(s1&sign)==0) s0 += 1;
+ ix0 -= t;
+ if (ix1 < t1) ix0 -= 1;
+ ix1 -= t1;
+ q1 += r;
+ }
+ ix0 += ix0 + ((ix1&sign)>>31);
+ ix1 += ix1;
+ r>>=1;
+ }
+
+ /* use floating add to find out rounding direction */
+ if((ix0|ix1)!=0) {
+ z = one-tiny; /* trigger inexact flag */
+ if (z>=one) {
+ z = one+tiny;
+ if (q1==(u_int32_t)0xffffffff) { q1=0; q += 1;}
+ else if (z>one) {
+ if (q1==(u_int32_t)0xfffffffe) q+=1;
+ q1+=2;
+ } else
+ q1 += (q1&1);
+ }
+ }
+ ix0 = (q>>1)+0x3fe00000;
+ ix1 = q1>>1;
+ if ((q&1)==1) ix1 |= sign;
+ ix0 += (m <<20);
+ INSERT_WORDS(z,ix0,ix1);
+ return z;
+}
+
+/*
+Other methods (use floating-point arithmetic)
+-------------
+(This is a copy of a drafted paper by Prof W. Kahan
+and K.C. Ng, written in May, 1986)
+
+ Two algorithms are given here to implement sqrt(x)
+ (IEEE double precision arithmetic) in software.
+ Both supply sqrt(x) correctly rounded. The first algorithm (in
+ Section A) uses newton iterations and involves four divisions.
+ The second one uses reciproot iterations to avoid division, but
+ requires more multiplications. Both algorithms need the ability
+ to chop results of arithmetic operations instead of round them,
+ and the INEXACT flag to indicate when an arithmetic operation
+ is executed exactly with no roundoff error, all part of the
+ standard (IEEE 754-1985). The ability to perform shift, add,
+ subtract and logical AND operations upon 32-bit words is needed
+ too, though not part of the standard.
+
+A. sqrt(x) by Newton Iteration
+
+ (1) Initial approximation
+
+ Let x0 and x1 be the leading and the trailing 32-bit words of
+ a floating point number x (in IEEE double format) respectively
+
+ 1 11 52 ...widths
+ ------------------------------------------------------
+ x: |s| e | f |
+ ------------------------------------------------------
+ msb lsb msb lsb ...order
+
+
+ ------------------------ ------------------------
+ x0: |s| e | f1 | x1: | f2 |
+ ------------------------ ------------------------
+
+ By performing shifts and subtracts on x0 and x1 (both regarded
+ as integers), we obtain an 8-bit approximation of sqrt(x) as
+ follows.
+
+ k := (x0>>1) + 0x1ff80000;
+ y0 := k - T1[31&(k>>15)]. ... y ~ sqrt(x) to 8 bits
+ Here k is a 32-bit integer and T1[] is an integer array containing
+ correction terms. Now magically the floating value of y (y's
+ leading 32-bit word is y0, the value of its trailing word is 0)
+ approximates sqrt(x) to almost 8-bit.
+
+ Value of T1:
+ static int T1[32]= {
+ 0, 1024, 3062, 5746, 9193, 13348, 18162, 23592,
+ 29598, 36145, 43202, 50740, 58733, 67158, 75992, 85215,
+ 83599, 71378, 60428, 50647, 41945, 34246, 27478, 21581,
+ 16499, 12183, 8588, 5674, 3403, 1742, 661, 130,};
+
+ (2) Iterative refinement
+
+ Apply Heron's rule three times to y, we have y approximates
+ sqrt(x) to within 1 ulp (Unit in the Last Place):
+
+ y := (y+x/y)/2 ... almost 17 sig. bits
+ y := (y+x/y)/2 ... almost 35 sig. bits
+ y := y-(y-x/y)/2 ... within 1 ulp
+
+
+ Remark 1.
+ Another way to improve y to within 1 ulp is:
+
+ y := (y+x/y) ... almost 17 sig. bits to 2*sqrt(x)
+ y := y - 0x00100006 ... almost 18 sig. bits to sqrt(x)
+
+ 2
+ (x-y )*y
+ y := y + 2* ---------- ...within 1 ulp
+ 2
+ 3y + x
+
+
+ This formula has one division fewer than the one above; however,
+ it requires more multiplications and additions. Also x must be
+ scaled in advance to avoid spurious overflow in evaluating the
+ expression 3y*y+x. Hence it is not recommended uless division
+ is slow. If division is very slow, then one should use the
+ reciproot algorithm given in section B.
+
+ (3) Final adjustment
+
+ By twiddling y's last bit it is possible to force y to be
+ correctly rounded according to the prevailing rounding mode
+ as follows. Let r and i be copies of the rounding mode and
+ inexact flag before entering the square root program. Also we
+ use the expression y+-ulp for the next representable floating
+ numbers (up and down) of y. Note that y+-ulp = either fixed
+ point y+-1, or multiply y by nextafter(1,+-inf) in chopped
+ mode.
+
+ I := FALSE; ... reset INEXACT flag I
+ R := RZ; ... set rounding mode to round-toward-zero
+ z := x/y; ... chopped quotient, possibly inexact
+ If(not I) then { ... if the quotient is exact
+ if(z=y) {
+ I := i; ... restore inexact flag
+ R := r; ... restore rounded mode
+ return sqrt(x):=y.
+ } else {
+ z := z - ulp; ... special rounding
+ }
+ }
+ i := TRUE; ... sqrt(x) is inexact
+ If (r=RN) then z=z+ulp ... rounded-to-nearest
+ If (r=RP) then { ... round-toward-+inf
+ y = y+ulp; z=z+ulp;
+ }
+ y := y+z; ... chopped sum
+ y0:=y0-0x00100000; ... y := y/2 is correctly rounded.
+ I := i; ... restore inexact flag
+ R := r; ... restore rounded mode
+ return sqrt(x):=y.
+
+ (4) Special cases
+
+ Square root of +inf, +-0, or NaN is itself;
+ Square root of a negative number is NaN with invalid signal.
+
+
+B. sqrt(x) by Reciproot Iteration
+
+ (1) Initial approximation
+
+ Let x0 and x1 be the leading and the trailing 32-bit words of
+ a floating point number x (in IEEE double format) respectively
+ (see section A). By performing shifs and subtracts on x0 and y0,
+ we obtain a 7.8-bit approximation of 1/sqrt(x) as follows.
+
+ k := 0x5fe80000 - (x0>>1);
+ y0:= k - T2[63&(k>>14)]. ... y ~ 1/sqrt(x) to 7.8 bits
+
+ Here k is a 32-bit integer and T2[] is an integer array
+ containing correction terms. Now magically the floating
+ value of y (y's leading 32-bit word is y0, the value of
+ its trailing word y1 is set to zero) approximates 1/sqrt(x)
+ to almost 7.8-bit.
+
+ Value of T2:
+ static int T2[64]= {
+ 0x1500, 0x2ef8, 0x4d67, 0x6b02, 0x87be, 0xa395, 0xbe7a, 0xd866,
+ 0xf14a, 0x1091b,0x11fcd,0x13552,0x14999,0x15c98,0x16e34,0x17e5f,
+ 0x18d03,0x19a01,0x1a545,0x1ae8a,0x1b5c4,0x1bb01,0x1bfde,0x1c28d,
+ 0x1c2de,0x1c0db,0x1ba73,0x1b11c,0x1a4b5,0x1953d,0x18266,0x16be0,
+ 0x1683e,0x179d8,0x18a4d,0x19992,0x1a789,0x1b445,0x1bf61,0x1c989,
+ 0x1d16d,0x1d77b,0x1dddf,0x1e2ad,0x1e5bf,0x1e6e8,0x1e654,0x1e3cd,
+ 0x1df2a,0x1d635,0x1cb16,0x1be2c,0x1ae4e,0x19bde,0x1868e,0x16e2e,
+ 0x1527f,0x1334a,0x11051,0xe951, 0xbe01, 0x8e0d, 0x5924, 0x1edd,};
+
+ (2) Iterative refinement
+
+ Apply Reciproot iteration three times to y and multiply the
+ result by x to get an approximation z that matches sqrt(x)
+ to about 1 ulp. To be exact, we will have
+ -1ulp < sqrt(x)-z<1.0625ulp.
+
+ ... set rounding mode to Round-to-nearest
+ y := y*(1.5-0.5*x*y*y) ... almost 15 sig. bits to 1/sqrt(x)
+ y := y*((1.5-2^-30)+0.5*x*y*y)... about 29 sig. bits to 1/sqrt(x)
+ ... special arrangement for better accuracy
+ z := x*y ... 29 bits to sqrt(x), with z*y<1
+ z := z + 0.5*z*(1-z*y) ... about 1 ulp to sqrt(x)
+
+ Remark 2. The constant 1.5-2^-30 is chosen to bias the error so that
+ (a) the term z*y in the final iteration is always less than 1;
+ (b) the error in the final result is biased upward so that
+ -1 ulp < sqrt(x) - z < 1.0625 ulp
+ instead of |sqrt(x)-z|<1.03125ulp.
+
+ (3) Final adjustment
+
+ By twiddling y's last bit it is possible to force y to be
+ correctly rounded according to the prevailing rounding mode
+ as follows. Let r and i be copies of the rounding mode and
+ inexact flag before entering the square root program. Also we
+ use the expression y+-ulp for the next representable floating
+ numbers (up and down) of y. Note that y+-ulp = either fixed
+ point y+-1, or multiply y by nextafter(1,+-inf) in chopped
+ mode.
+
+ R := RZ; ... set rounding mode to round-toward-zero
+ switch(r) {
+ case RN: ... round-to-nearest
+ if(x<= z*(z-ulp)...chopped) z = z - ulp; else
+ if(x<= z*(z+ulp)...chopped) z = z; else z = z+ulp;
+ break;
+ case RZ:case RM: ... round-to-zero or round-to--inf
+ R:=RP; ... reset rounding mod to round-to-+inf
+ if(x<z*z ... rounded up) z = z - ulp; else
+ if(x>=(z+ulp)*(z+ulp) ...rounded up) z = z+ulp;
+ break;
+ case RP: ... round-to-+inf
+ if(x>(z+ulp)*(z+ulp)...chopped) z = z+2*ulp; else
+ if(x>z*z ...chopped) z = z+ulp;
+ break;
+ }
+
+ Remark 3. The above comparisons can be done in fixed point. For
+ example, to compare x and w=z*z chopped, it suffices to compare
+ x1 and w1 (the trailing parts of x and w), regarding them as
+ two's complement integers.
+
+ ...Is z an exact square root?
+ To determine whether z is an exact square root of x, let z1 be the
+ trailing part of z, and also let x0 and x1 be the leading and
+ trailing parts of x.
+
+ If ((z1&0x03ffffff)!=0) ... not exact if trailing 26 bits of z!=0
+ I := 1; ... Raise Inexact flag: z is not exact
+ else {
+ j := 1 - [(x0>>20)&1] ... j = logb(x) mod 2
+ k := z1 >> 26; ... get z's 25-th and 26-th
+ fraction bits
+ I := i or (k&j) or ((k&(j+j+1))!=(x1&3));
+ }
+ R:= r ... restore rounded mode
+ return sqrt(x):=z.
+
+ If multiplication is cheaper then the foregoing red tape, the
+ Inexact flag can be evaluated by
+
+ I := i;
+ I := (z*z!=x) or I.
+
+ Note that z*z can overwrite I; this value must be sensed if it is
+ True.
+
+ Remark 4. If z*z = x exactly, then bit 25 to bit 0 of z1 must be
+ zero.
+
+ --------------------
+ z1: | f2 |
+ --------------------
+ bit 31 bit 0
+
+ Further more, bit 27 and 26 of z1, bit 0 and 1 of x1, and the odd
+ or even of logb(x) have the following relations:
+
+ -------------------------------------------------
+ bit 27,26 of z1 bit 1,0 of x1 logb(x)
+ -------------------------------------------------
+ 00 00 odd and even
+ 01 01 even
+ 10 10 odd
+ 10 00 even
+ 11 01 even
+ -------------------------------------------------
+
+ (4) Special cases (see (4) of Section A).
+
+ */
+
diff --git a/lib/msun/src/e_sqrtf.c b/lib/msun/src/e_sqrtf.c
new file mode 100644
index 0000000..7eba4d0
--- /dev/null
+++ b/lib/msun/src/e_sqrtf.c
@@ -0,0 +1,89 @@
+/* e_sqrtf.c -- float version of e_sqrt.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+#include "math.h"
+#include "math_private.h"
+
+static const float one = 1.0, tiny=1.0e-30;
+
+float
+__ieee754_sqrtf(float x)
+{
+ float z;
+ int32_t sign = (int)0x80000000;
+ int32_t ix,s,q,m,t,i;
+ u_int32_t r;
+
+ GET_FLOAT_WORD(ix,x);
+
+ /* take care of Inf and NaN */
+ if((ix&0x7f800000)==0x7f800000) {
+ return x*x+x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf
+ sqrt(-inf)=sNaN */
+ }
+ /* take care of zero */
+ if(ix<=0) {
+ if((ix&(~sign))==0) return x;/* sqrt(+-0) = +-0 */
+ else if(ix<0)
+ return (x-x)/(x-x); /* sqrt(-ve) = sNaN */
+ }
+ /* normalize x */
+ m = (ix>>23);
+ if(m==0) { /* subnormal x */
+ for(i=0;(ix&0x00800000)==0;i++) ix<<=1;
+ m -= i-1;
+ }
+ m -= 127; /* unbias exponent */
+ ix = (ix&0x007fffff)|0x00800000;
+ if(m&1) /* odd m, double x to make it even */
+ ix += ix;
+ m >>= 1; /* m = [m/2] */
+
+ /* generate sqrt(x) bit by bit */
+ ix += ix;
+ q = s = 0; /* q = sqrt(x) */
+ r = 0x01000000; /* r = moving bit from right to left */
+
+ while(r!=0) {
+ t = s+r;
+ if(t<=ix) {
+ s = t+r;
+ ix -= t;
+ q += r;
+ }
+ ix += ix;
+ r>>=1;
+ }
+
+ /* use floating add to find out rounding direction */
+ if(ix!=0) {
+ z = one-tiny; /* trigger inexact flag */
+ if (z>=one) {
+ z = one+tiny;
+ if (z>one)
+ q += 2;
+ else
+ q += (q&1);
+ }
+ }
+ ix = (q>>1)+0x3f000000;
+ ix += (m <<23);
+ SET_FLOAT_WORD(z,ix);
+ return z;
+}
diff --git a/lib/msun/src/k_cos.c b/lib/msun/src/k_cos.c
new file mode 100644
index 0000000..dfd9867
--- /dev/null
+++ b/lib/msun/src/k_cos.c
@@ -0,0 +1,79 @@
+
+/* @(#)k_cos.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/*
+ * __kernel_cos( x, y )
+ * kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164
+ * Input x is assumed to be bounded by ~pi/4 in magnitude.
+ * Input y is the tail of x.
+ *
+ * Algorithm
+ * 1. Since cos(-x) = cos(x), we need only to consider positive x.
+ * 2. if x < 2^-27 (hx<0x3e400000 0), return 1 with inexact if x!=0.
+ * 3. cos(x) is approximated by a polynomial of degree 14 on
+ * [0,pi/4]
+ * 4 14
+ * cos(x) ~ 1 - x*x/2 + C1*x + ... + C6*x
+ * where the remez error is
+ *
+ * | 2 4 6 8 10 12 14 | -58
+ * |cos(x)-(1-.5*x +C1*x +C2*x +C3*x +C4*x +C5*x +C6*x )| <= 2
+ * | |
+ *
+ * 4 6 8 10 12 14
+ * 4. let r = C1*x +C2*x +C3*x +C4*x +C5*x +C6*x , then
+ * cos(x) ~ 1 - x*x/2 + r
+ * since cos(x+y) ~ cos(x) - sin(x)*y
+ * ~ cos(x) - x*y,
+ * a correction term is necessary in cos(x) and hence
+ * cos(x+y) = 1 - (x*x/2 - (r - x*y))
+ * For better accuracy, rearrange to
+ * cos(x+y) ~ w + (tmp + (r-x*y))
+ * where w = 1 - x*x/2 and tmp is a tiny correction term
+ * (1 - x*x/2 == w + tmp exactly in infinite precision).
+ * The exactness of w + tmp in infinite precision depends on w
+ * and tmp having the same precision as x. If they have extra
+ * precision due to compiler bugs, then the extra precision is
+ * only good provided it is retained in all terms of the final
+ * expression for cos(). Retention happens in all cases tested
+ * under FreeBSD, so don't pessimize things by forcibly clipping
+ * any extra precision in w.
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+static const double
+one = 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+C1 = 4.16666666666666019037e-02, /* 0x3FA55555, 0x5555554C */
+C2 = -1.38888888888741095749e-03, /* 0xBF56C16C, 0x16C15177 */
+C3 = 2.48015872894767294178e-05, /* 0x3EFA01A0, 0x19CB1590 */
+C4 = -2.75573143513906633035e-07, /* 0xBE927E4F, 0x809C52AD */
+C5 = 2.08757232129817482790e-09, /* 0x3E21EE9E, 0xBDB4B1C4 */
+C6 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */
+
+double
+__kernel_cos(double x, double y)
+{
+ double hz,z,r,w;
+
+ z = x*x;
+ r = z*(C1+z*(C2+z*(C3+z*(C4+z*(C5+z*C6)))));
+ hz = (float)0.5*z;
+ w = one-hz;
+ return w + (((one-w)-hz) + (z*r-x*y));
+}
diff --git a/lib/msun/src/k_cosf.c b/lib/msun/src/k_cosf.c
new file mode 100644
index 0000000..6a0afe9
--- /dev/null
+++ b/lib/msun/src/k_cosf.c
@@ -0,0 +1,47 @@
+/* k_cosf.c -- float version of k_cos.c
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ * Debugged and optimized by Bruce D. Evans.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef INLINE_KERNEL_COSDF
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+#endif
+
+#include "math.h"
+#include "math_private.h"
+
+/* |cos(x) - c(x)| < 2**-34.1 (~[-5.37e-11, 5.295e-11]). */
+static const double
+one = 1.0,
+C0 = -0x1ffffffd0c5e81.0p-54, /* -0.499999997251031003120 */
+C1 = 0x155553e1053a42.0p-57, /* 0.0416666233237390631894 */
+C2 = -0x16c087e80f1e27.0p-62, /* -0.00138867637746099294692 */
+C3 = 0x199342e0ee5069.0p-68; /* 0.0000243904487962774090654 */
+
+#ifdef INLINE_KERNEL_COSDF
+extern inline
+#endif
+float
+__kernel_cosdf(double x)
+{
+ double r, w, z;
+
+ /* Try to optimize for parallel evaluation as in k_tanf.c. */
+ z = x*x;
+ w = z*z;
+ r = C2+z*C3;
+ return ((one+z*C0) + w*C1) + (w*z)*r;
+}
diff --git a/lib/msun/src/k_rem_pio2.c b/lib/msun/src/k_rem_pio2.c
new file mode 100644
index 0000000..61f7dce
--- /dev/null
+++ b/lib/msun/src/k_rem_pio2.c
@@ -0,0 +1,304 @@
+
+/* @(#)k_rem_pio2.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/*
+ * __kernel_rem_pio2(x,y,e0,nx,prec,ipio2)
+ * double x[],y[]; int e0,nx,prec; int ipio2[];
+ *
+ * __kernel_rem_pio2 return the last three digits of N with
+ * y = x - N*pi/2
+ * so that |y| < pi/2.
+ *
+ * The method is to compute the integer (mod 8) and fraction parts of
+ * (2/pi)*x without doing the full multiplication. In general we
+ * skip the part of the product that are known to be a huge integer (
+ * more accurately, = 0 mod 8 ). Thus the number of operations are
+ * independent of the exponent of the input.
+ *
+ * (2/pi) is represented by an array of 24-bit integers in ipio2[].
+ *
+ * Input parameters:
+ * x[] The input value (must be positive) is broken into nx
+ * pieces of 24-bit integers in double precision format.
+ * x[i] will be the i-th 24 bit of x. The scaled exponent
+ * of x[0] is given in input parameter e0 (i.e., x[0]*2^e0
+ * match x's up to 24 bits.
+ *
+ * Example of breaking a double positive z into x[0]+x[1]+x[2]:
+ * e0 = ilogb(z)-23
+ * z = scalbn(z,-e0)
+ * for i = 0,1,2
+ * x[i] = floor(z)
+ * z = (z-x[i])*2**24
+ *
+ *
+ * y[] ouput result in an array of double precision numbers.
+ * The dimension of y[] is:
+ * 24-bit precision 1
+ * 53-bit precision 2
+ * 64-bit precision 2
+ * 113-bit precision 3
+ * The actual value is the sum of them. Thus for 113-bit
+ * precison, one may have to do something like:
+ *
+ * long double t,w,r_head, r_tail;
+ * t = (long double)y[2] + (long double)y[1];
+ * w = (long double)y[0];
+ * r_head = t+w;
+ * r_tail = w - (r_head - t);
+ *
+ * e0 The exponent of x[0]
+ *
+ * nx dimension of x[]
+ *
+ * prec an integer indicating the precision:
+ * 0 24 bits (single)
+ * 1 53 bits (double)
+ * 2 64 bits (extended)
+ * 3 113 bits (quad)
+ *
+ * ipio2[]
+ * integer array, contains the (24*i)-th to (24*i+23)-th
+ * bit of 2/pi after binary point. The corresponding
+ * floating value is
+ *
+ * ipio2[i] * 2^(-24(i+1)).
+ *
+ * External function:
+ * double scalbn(), floor();
+ *
+ *
+ * Here is the description of some local variables:
+ *
+ * jk jk+1 is the initial number of terms of ipio2[] needed
+ * in the computation. The recommended value is 2,3,4,
+ * 6 for single, double, extended,and quad.
+ *
+ * jz local integer variable indicating the number of
+ * terms of ipio2[] used.
+ *
+ * jx nx - 1
+ *
+ * jv index for pointing to the suitable ipio2[] for the
+ * computation. In general, we want
+ * ( 2^e0*x[0] * ipio2[jv-1]*2^(-24jv) )/8
+ * is an integer. Thus
+ * e0-3-24*jv >= 0 or (e0-3)/24 >= jv
+ * Hence jv = max(0,(e0-3)/24).
+ *
+ * jp jp+1 is the number of terms in PIo2[] needed, jp = jk.
+ *
+ * q[] double array with integral value, representing the
+ * 24-bits chunk of the product of x and 2/pi.
+ *
+ * q0 the corresponding exponent of q[0]. Note that the
+ * exponent for q[i] would be q0-24*i.
+ *
+ * PIo2[] double precision array, obtained by cutting pi/2
+ * into 24 bits chunks.
+ *
+ * f[] ipio2[] in floating point
+ *
+ * iq[] integer array by breaking up q[] in 24-bits chunk.
+ *
+ * fq[] final product of x*(2/pi) in fq[0],..,fq[jk]
+ *
+ * ih integer. If >0 it indicates q[] is >= 0.5, hence
+ * it also indicates the *sign* of the result.
+ *
+ */
+
+
+/*
+ * Constants:
+ * The hexadecimal values are the intended ones for the following
+ * constants. The decimal values may be used, provided that the
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+static const int init_jk[] = {2,3,4,6}; /* initial value for jk */
+
+static const double PIo2[] = {
+ 1.57079625129699707031e+00, /* 0x3FF921FB, 0x40000000 */
+ 7.54978941586159635335e-08, /* 0x3E74442D, 0x00000000 */
+ 5.39030252995776476554e-15, /* 0x3CF84698, 0x80000000 */
+ 3.28200341580791294123e-22, /* 0x3B78CC51, 0x60000000 */
+ 1.27065575308067607349e-29, /* 0x39F01B83, 0x80000000 */
+ 1.22933308981111328932e-36, /* 0x387A2520, 0x40000000 */
+ 2.73370053816464559624e-44, /* 0x36E38222, 0x80000000 */
+ 2.16741683877804819444e-51, /* 0x3569F31D, 0x00000000 */
+};
+
+static const double
+zero = 0.0,
+one = 1.0,
+two24 = 1.67772160000000000000e+07, /* 0x41700000, 0x00000000 */
+twon24 = 5.96046447753906250000e-08; /* 0x3E700000, 0x00000000 */
+
+ int __kernel_rem_pio2(double *x, double *y, int e0, int nx, int prec, const int32_t *ipio2)
+{
+ int32_t jz,jx,jv,jp,jk,carry,n,iq[20],i,j,k,m,q0,ih;
+ double z,fw,f[20],fq[20],q[20];
+
+ /* initialize jk*/
+ jk = init_jk[prec];
+ jp = jk;
+
+ /* determine jx,jv,q0, note that 3>q0 */
+ jx = nx-1;
+ jv = (e0-3)/24; if(jv<0) jv=0;
+ q0 = e0-24*(jv+1);
+
+ /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */
+ j = jv-jx; m = jx+jk;
+ for(i=0;i<=m;i++,j++) f[i] = (j<0)? zero : (double) ipio2[j];
+
+ /* compute q[0],q[1],...q[jk] */
+ for (i=0;i<=jk;i++) {
+ for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j]; q[i] = fw;
+ }
+
+ jz = jk;
+recompute:
+ /* distill q[] into iq[] reversingly */
+ for(i=0,j=jz,z=q[jz];j>0;i++,j--) {
+ fw = (double)((int32_t)(twon24* z));
+ iq[i] = (int32_t)(z-two24*fw);
+ z = q[j-1]+fw;
+ }
+
+ /* compute n */
+ z = scalbn(z,q0); /* actual value of z */
+ z -= 8.0*floor(z*0.125); /* trim off integer >= 8 */
+ n = (int32_t) z;
+ z -= (double)n;
+ ih = 0;
+ if(q0>0) { /* need iq[jz-1] to determine n */
+ i = (iq[jz-1]>>(24-q0)); n += i;
+ iq[jz-1] -= i<<(24-q0);
+ ih = iq[jz-1]>>(23-q0);
+ }
+ else if(q0==0) ih = iq[jz-1]>>23;
+ else if(z>=0.5) ih=2;
+
+ if(ih>0) { /* q > 0.5 */
+ n += 1; carry = 0;
+ for(i=0;i<jz ;i++) { /* compute 1-q */
+ j = iq[i];
+ if(carry==0) {
+ if(j!=0) {
+ carry = 1; iq[i] = 0x1000000- j;
+ }
+ } else iq[i] = 0xffffff - j;
+ }
+ if(q0>0) { /* rare case: chance is 1 in 12 */
+ switch(q0) {
+ case 1:
+ iq[jz-1] &= 0x7fffff; break;
+ case 2:
+ iq[jz-1] &= 0x3fffff; break;
+ }
+ }
+ if(ih==2) {
+ z = one - z;
+ if(carry!=0) z -= scalbn(one,q0);
+ }
+ }
+
+ /* check if recomputation is needed */
+ if(z==zero) {
+ j = 0;
+ for (i=jz-1;i>=jk;i--) j |= iq[i];
+ if(j==0) { /* need recomputation */
+ for(k=1;iq[jk-k]==0;k++); /* k = no. of terms needed */
+
+ for(i=jz+1;i<=jz+k;i++) { /* add q[jz+1] to q[jz+k] */
+ f[jx+i] = (double) ipio2[jv+i];
+ for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j];
+ q[i] = fw;
+ }
+ jz += k;
+ goto recompute;
+ }
+ }
+
+ /* chop off zero terms */
+ if(z==0.0) {
+ jz -= 1; q0 -= 24;
+ while(iq[jz]==0) { jz--; q0-=24;}
+ } else { /* break z into 24-bit if necessary */
+ z = scalbn(z,-q0);
+ if(z>=two24) {
+ fw = (double)((int32_t)(twon24*z));
+ iq[jz] = (int32_t)(z-two24*fw);
+ jz += 1; q0 += 24;
+ iq[jz] = (int32_t) fw;
+ } else iq[jz] = (int32_t) z ;
+ }
+
+ /* convert integer "bit" chunk to floating-point value */
+ fw = scalbn(one,q0);
+ for(i=jz;i>=0;i--) {
+ q[i] = fw*(double)iq[i]; fw*=twon24;
+ }
+
+ /* compute PIo2[0,...,jp]*q[jz,...,0] */
+ for(i=jz;i>=0;i--) {
+ for(fw=0.0,k=0;k<=jp&&k<=jz-i;k++) fw += PIo2[k]*q[i+k];
+ fq[jz-i] = fw;
+ }
+
+ /* compress fq[] into y[] */
+ switch(prec) {
+ case 0:
+ fw = 0.0;
+ for (i=jz;i>=0;i--) fw += fq[i];
+ y[0] = (ih==0)? fw: -fw;
+ break;
+ case 1:
+ case 2:
+ fw = 0.0;
+ for (i=jz;i>=0;i--) fw += fq[i];
+ y[0] = (ih==0)? fw: -fw;
+ fw = fq[0]-fw;
+ for (i=1;i<=jz;i++) fw += fq[i];
+ y[1] = (ih==0)? fw: -fw;
+ break;
+ case 3: /* painful */
+ for (i=jz;i>0;i--) {
+ fw = fq[i-1]+fq[i];
+ fq[i] += fq[i-1]-fw;
+ fq[i-1] = fw;
+ }
+ for (i=jz;i>1;i--) {
+ fw = fq[i-1]+fq[i];
+ fq[i] += fq[i-1]-fw;
+ fq[i-1] = fw;
+ }
+ for (fw=0.0,i=jz;i>=2;i--) fw += fq[i];
+ if(ih==0) {
+ y[0] = fq[0]; y[1] = fq[1]; y[2] = fw;
+ } else {
+ y[0] = -fq[0]; y[1] = -fq[1]; y[2] = -fw;
+ }
+ }
+ return n&7;
+}
diff --git a/lib/msun/src/k_rem_pio2f.c b/lib/msun/src/k_rem_pio2f.c
new file mode 100644
index 0000000..958c863
--- /dev/null
+++ b/lib/msun/src/k_rem_pio2f.c
@@ -0,0 +1,197 @@
+/* k_rem_pio2f.c -- float version of k_rem_pio2.c
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+#include "math.h"
+#include "math_private.h"
+
+/* In the float version, the input parameter x contains 8 bit
+ integers, not 24 bit integers. 113 bit precision is not supported. */
+
+static const int init_jk[] = {4,7,9}; /* initial value for jk */
+
+static const float PIo2[] = {
+ 1.5703125000e+00, /* 0x3fc90000 */
+ 4.5776367188e-04, /* 0x39f00000 */
+ 2.5987625122e-05, /* 0x37da0000 */
+ 7.5437128544e-08, /* 0x33a20000 */
+ 6.0026650317e-11, /* 0x2e840000 */
+ 7.3896444519e-13, /* 0x2b500000 */
+ 5.3845816694e-15, /* 0x27c20000 */
+ 5.6378512969e-18, /* 0x22d00000 */
+ 8.3009228831e-20, /* 0x1fc40000 */
+ 3.2756352257e-22, /* 0x1bc60000 */
+ 6.3331015649e-25, /* 0x17440000 */
+};
+
+static const float
+zero = 0.0,
+one = 1.0,
+two8 = 2.5600000000e+02, /* 0x43800000 */
+twon8 = 3.9062500000e-03; /* 0x3b800000 */
+
+ int __kernel_rem_pio2f(float *x, float *y, int e0, int nx, int prec, const int32_t *ipio2)
+{
+ int32_t jz,jx,jv,jp,jk,carry,n,iq[20],i,j,k,m,q0,ih;
+ float z,fw,f[20],fq[20],q[20];
+
+ /* initialize jk*/
+ jk = init_jk[prec];
+ jp = jk;
+
+ /* determine jx,jv,q0, note that 3>q0 */
+ jx = nx-1;
+ jv = (e0-3)/8; if(jv<0) jv=0;
+ q0 = e0-8*(jv+1);
+
+ /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */
+ j = jv-jx; m = jx+jk;
+ for(i=0;i<=m;i++,j++) f[i] = (j<0)? zero : (float) ipio2[j];
+
+ /* compute q[0],q[1],...q[jk] */
+ for (i=0;i<=jk;i++) {
+ for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j]; q[i] = fw;
+ }
+
+ jz = jk;
+recompute:
+ /* distill q[] into iq[] reversingly */
+ for(i=0,j=jz,z=q[jz];j>0;i++,j--) {
+ fw = (float)((int32_t)(twon8* z));
+ iq[i] = (int32_t)(z-two8*fw);
+ z = q[j-1]+fw;
+ }
+
+ /* compute n */
+ z = scalbnf(z,q0); /* actual value of z */
+ z -= (float)8.0*floorf(z*(float)0.125); /* trim off integer >= 8 */
+ n = (int32_t) z;
+ z -= (float)n;
+ ih = 0;
+ if(q0>0) { /* need iq[jz-1] to determine n */
+ i = (iq[jz-1]>>(8-q0)); n += i;
+ iq[jz-1] -= i<<(8-q0);
+ ih = iq[jz-1]>>(7-q0);
+ }
+ else if(q0==0) ih = iq[jz-1]>>7;
+ else if(z>=(float)0.5) ih=2;
+
+ if(ih>0) { /* q > 0.5 */
+ n += 1; carry = 0;
+ for(i=0;i<jz ;i++) { /* compute 1-q */
+ j = iq[i];
+ if(carry==0) {
+ if(j!=0) {
+ carry = 1; iq[i] = 0x100- j;
+ }
+ } else iq[i] = 0xff - j;
+ }
+ if(q0>0) { /* rare case: chance is 1 in 12 */
+ switch(q0) {
+ case 1:
+ iq[jz-1] &= 0x7f; break;
+ case 2:
+ iq[jz-1] &= 0x3f; break;
+ }
+ }
+ if(ih==2) {
+ z = one - z;
+ if(carry!=0) z -= scalbnf(one,q0);
+ }
+ }
+
+ /* check if recomputation is needed */
+ if(z==zero) {
+ j = 0;
+ for (i=jz-1;i>=jk;i--) j |= iq[i];
+ if(j==0) { /* need recomputation */
+ for(k=1;iq[jk-k]==0;k++); /* k = no. of terms needed */
+
+ for(i=jz+1;i<=jz+k;i++) { /* add q[jz+1] to q[jz+k] */
+ f[jx+i] = (float) ipio2[jv+i];
+ for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j];
+ q[i] = fw;
+ }
+ jz += k;
+ goto recompute;
+ }
+ }
+
+ /* chop off zero terms */
+ if(z==(float)0.0) {
+ jz -= 1; q0 -= 8;
+ while(iq[jz]==0) { jz--; q0-=8;}
+ } else { /* break z into 8-bit if necessary */
+ z = scalbnf(z,-q0);
+ if(z>=two8) {
+ fw = (float)((int32_t)(twon8*z));
+ iq[jz] = (int32_t)(z-two8*fw);
+ jz += 1; q0 += 8;
+ iq[jz] = (int32_t) fw;
+ } else iq[jz] = (int32_t) z ;
+ }
+
+ /* convert integer "bit" chunk to floating-point value */
+ fw = scalbnf(one,q0);
+ for(i=jz;i>=0;i--) {
+ q[i] = fw*(float)iq[i]; fw*=twon8;
+ }
+
+ /* compute PIo2[0,...,jp]*q[jz,...,0] */
+ for(i=jz;i>=0;i--) {
+ for(fw=0.0,k=0;k<=jp&&k<=jz-i;k++) fw += PIo2[k]*q[i+k];
+ fq[jz-i] = fw;
+ }
+
+ /* compress fq[] into y[] */
+ switch(prec) {
+ case 0:
+ fw = 0.0;
+ for (i=jz;i>=0;i--) fw += fq[i];
+ y[0] = (ih==0)? fw: -fw;
+ break;
+ case 1:
+ case 2:
+ fw = 0.0;
+ for (i=jz;i>=0;i--) fw += fq[i];
+ fw = *(volatile float *)&fw; /* clip any extra precision */
+ y[0] = (ih==0)? fw: -fw;
+ fw = fq[0]-fw;
+ for (i=1;i<=jz;i++) fw += fq[i];
+ y[1] = (ih==0)? fw: -fw;
+ break;
+ case 3: /* painful */
+ for (i=jz;i>0;i--) {
+ fw = fq[i-1]+fq[i];
+ fq[i] += fq[i-1]-fw;
+ fq[i-1] = fw;
+ }
+ for (i=jz;i>1;i--) {
+ fw = fq[i-1]+fq[i];
+ fq[i] += fq[i-1]-fw;
+ fq[i-1] = fw;
+ }
+ for (fw=0.0,i=jz;i>=2;i--) fw += fq[i];
+ if(ih==0) {
+ y[0] = fq[0]; y[1] = fq[1]; y[2] = fw;
+ } else {
+ y[0] = -fq[0]; y[1] = -fq[1]; y[2] = -fw;
+ }
+ }
+ return n&7;
+}
diff --git a/lib/msun/src/k_sin.c b/lib/msun/src/k_sin.c
new file mode 100644
index 0000000..fe2a56c
--- /dev/null
+++ b/lib/msun/src/k_sin.c
@@ -0,0 +1,70 @@
+
+/* @(#)k_sin.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/* __kernel_sin( x, y, iy)
+ * kernel sin function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854
+ * Input x is assumed to be bounded by ~pi/4 in magnitude.
+ * Input y is the tail of x.
+ * Input iy indicates whether y is 0. (if iy=0, y assume to be 0).
+ *
+ * Algorithm
+ * 1. Since sin(-x) = -sin(x), we need only to consider positive x.
+ * 2. Callers must return sin(-0) = -0 without calling here since our
+ * odd polynomial is not evaluated in a way that preserves -0.
+ * Callers may do the optimization sin(x) ~ x for tiny x.
+ * 3. sin(x) is approximated by a polynomial of degree 13 on
+ * [0,pi/4]
+ * 3 13
+ * sin(x) ~ x + S1*x + ... + S6*x
+ * where
+ *
+ * |sin(x) 2 4 6 8 10 12 | -58
+ * |----- - (1+S1*x +S2*x +S3*x +S4*x +S5*x +S6*x )| <= 2
+ * | x |
+ *
+ * 4. sin(x+y) = sin(x) + sin'(x')*y
+ * ~ sin(x) + (1-x*x/2)*y
+ * For better accuracy, let
+ * 3 2 2 2 2
+ * r = x *(S2+x *(S3+x *(S4+x *(S5+x *S6))))
+ * then 3 2
+ * sin(x) = x + (S1*x + (x *(r-y/2)+y))
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+static const double
+half = 5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */
+S1 = -1.66666666666666324348e-01, /* 0xBFC55555, 0x55555549 */
+S2 = 8.33333333332248946124e-03, /* 0x3F811111, 0x1110F8A6 */
+S3 = -1.98412698298579493134e-04, /* 0xBF2A01A0, 0x19C161D5 */
+S4 = 2.75573137070700676789e-06, /* 0x3EC71DE3, 0x57B1FE7D */
+S5 = -2.50507602534068634195e-08, /* 0xBE5AE5E6, 0x8A2B9CEB */
+S6 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */
+
+double
+__kernel_sin(double x, double y, int iy)
+{
+ double z,r,v;
+
+ z = x*x;
+ v = z*x;
+ r = S2+z*(S3+z*(S4+z*(S5+z*S6)));
+ if(iy==0) return x+v*(S1+z*r);
+ else return x-((z*(half*y-v*r)-y)-v*S1);
+}
diff --git a/lib/msun/src/k_sinf.c b/lib/msun/src/k_sinf.c
new file mode 100644
index 0000000..79f32a1
--- /dev/null
+++ b/lib/msun/src/k_sinf.c
@@ -0,0 +1,47 @@
+/* k_sinf.c -- float version of k_sin.c
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ * Optimized by Bruce D. Evans.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef INLINE_KERNEL_SINDF
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+#endif
+
+#include "math.h"
+#include "math_private.h"
+
+/* |sin(x)/x - s(x)| < 2**-37.5 (~[-4.89e-12, 4.824e-12]). */
+static const double
+S1 = -0x15555554cbac77.0p-55, /* -0.166666666416265235595 */
+S2 = 0x111110896efbb2.0p-59, /* 0.0083333293858894631756 */
+S3 = -0x1a00f9e2cae774.0p-65, /* -0.000198393348360966317347 */
+S4 = 0x16cd878c3b46a7.0p-71; /* 0.0000027183114939898219064 */
+
+#ifdef INLINE_KERNEL_SINDF
+extern inline
+#endif
+float
+__kernel_sindf(double x)
+{
+ double r, s, w, z;
+
+ /* Try to optimize for parallel evaluation as in k_tanf.c. */
+ z = x*x;
+ w = z*z;
+ r = S3+z*S4;
+ s = z*x;
+ return (x + s*(S1+z*S2)) + s*w*r;
+}
diff --git a/lib/msun/src/k_tan.c b/lib/msun/src/k_tan.c
new file mode 100644
index 0000000..13737d0
--- /dev/null
+++ b/lib/msun/src/k_tan.c
@@ -0,0 +1,133 @@
+/* @(#)k_tan.c 1.5 04/04/22 SMI */
+
+/*
+ * ====================================================
+ * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* INDENT OFF */
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/* __kernel_tan( x, y, k )
+ * kernel tan function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854
+ * Input x is assumed to be bounded by ~pi/4 in magnitude.
+ * Input y is the tail of x.
+ * Input k indicates whether tan (if k = 1) or -1/tan (if k = -1) is returned.
+ *
+ * Algorithm
+ * 1. Since tan(-x) = -tan(x), we need only to consider positive x.
+ * 2. Callers must return tan(-0) = -0 without calling here since our
+ * odd polynomial is not evaluated in a way that preserves -0.
+ * Callers may do the optimization tan(x) ~ x for tiny x.
+ * 3. tan(x) is approximated by a odd polynomial of degree 27 on
+ * [0,0.67434]
+ * 3 27
+ * tan(x) ~ x + T1*x + ... + T13*x
+ * where
+ *
+ * |tan(x) 2 4 26 | -59.2
+ * |----- - (1+T1*x +T2*x +.... +T13*x )| <= 2
+ * | x |
+ *
+ * Note: tan(x+y) = tan(x) + tan'(x)*y
+ * ~ tan(x) + (1+x*x)*y
+ * Therefore, for better accuracy in computing tan(x+y), let
+ * 3 2 2 2 2
+ * r = x *(T2+x *(T3+x *(...+x *(T12+x *T13))))
+ * then
+ * 3 2
+ * tan(x+y) = x + (T1*x + (x *(r+y)+y))
+ *
+ * 4. For x in [0.67434,pi/4], let y = pi/4 - x, then
+ * tan(x) = tan(pi/4-y) = (1-tan(y))/(1+tan(y))
+ * = 1 - 2*(tan(y) - (tan(y)^2)/(1+tan(y)))
+ */
+
+#include "math.h"
+#include "math_private.h"
+static const double xxx[] = {
+ 3.33333333333334091986e-01, /* 3FD55555, 55555563 */
+ 1.33333333333201242699e-01, /* 3FC11111, 1110FE7A */
+ 5.39682539762260521377e-02, /* 3FABA1BA, 1BB341FE */
+ 2.18694882948595424599e-02, /* 3F9664F4, 8406D637 */
+ 8.86323982359930005737e-03, /* 3F8226E3, E96E8493 */
+ 3.59207910759131235356e-03, /* 3F6D6D22, C9560328 */
+ 1.45620945432529025516e-03, /* 3F57DBC8, FEE08315 */
+ 5.88041240820264096874e-04, /* 3F4344D8, F2F26501 */
+ 2.46463134818469906812e-04, /* 3F3026F7, 1A8D1068 */
+ 7.81794442939557092300e-05, /* 3F147E88, A03792A6 */
+ 7.14072491382608190305e-05, /* 3F12B80F, 32F0A7E9 */
+ -1.85586374855275456654e-05, /* BEF375CB, DB605373 */
+ 2.59073051863633712884e-05, /* 3EFB2A70, 74BF7AD4 */
+/* one */ 1.00000000000000000000e+00, /* 3FF00000, 00000000 */
+/* pio4 */ 7.85398163397448278999e-01, /* 3FE921FB, 54442D18 */
+/* pio4lo */ 3.06161699786838301793e-17 /* 3C81A626, 33145C07 */
+};
+#define one xxx[13]
+#define pio4 xxx[14]
+#define pio4lo xxx[15]
+#define T xxx
+/* INDENT ON */
+
+double
+__kernel_tan(double x, double y, int iy) {
+ double z, r, v, w, s;
+ int32_t ix, hx;
+
+ GET_HIGH_WORD(hx,x);
+ ix = hx & 0x7fffffff; /* high word of |x| */
+ if (ix >= 0x3FE59428) { /* |x| >= 0.6744 */
+ if (hx < 0) {
+ x = -x;
+ y = -y;
+ }
+ z = pio4 - x;
+ w = pio4lo - y;
+ x = z + w;
+ y = 0.0;
+ }
+ z = x * x;
+ w = z * z;
+ /*
+ * Break x^5*(T[1]+x^2*T[2]+...) into
+ * x^5(T[1]+x^4*T[3]+...+x^20*T[11]) +
+ * x^5(x^2*(T[2]+x^4*T[4]+...+x^22*[T12]))
+ */
+ r = T[1] + w * (T[3] + w * (T[5] + w * (T[7] + w * (T[9] +
+ w * T[11]))));
+ v = z * (T[2] + w * (T[4] + w * (T[6] + w * (T[8] + w * (T[10] +
+ w * T[12])))));
+ s = z * x;
+ r = y + z * (s * (r + v) + y);
+ r += T[0] * s;
+ w = x + r;
+ if (ix >= 0x3FE59428) {
+ v = (double) iy;
+ return (double) (1 - ((hx >> 30) & 2)) *
+ (v - 2.0 * (x - (w * w / (w + v) - r)));
+ }
+ if (iy == 1)
+ return w;
+ else {
+ /*
+ * if allow error up to 2 ulp, simply return
+ * -1.0 / (x+r) here
+ */
+ /* compute -1.0 / (x+r) accurately */
+ double a, t;
+ z = w;
+ SET_LOW_WORD(z,0);
+ v = r - (z - x); /* z+v = r+x */
+ t = a = -1.0 / w; /* a = -1.0/w */
+ SET_LOW_WORD(t,0);
+ s = 1.0 + t * z;
+ return t + a * (s + t * v);
+ }
+}
diff --git a/lib/msun/src/k_tanf.c b/lib/msun/src/k_tanf.c
new file mode 100644
index 0000000..bdda30a
--- /dev/null
+++ b/lib/msun/src/k_tanf.c
@@ -0,0 +1,67 @@
+/* k_tanf.c -- float version of k_tan.c
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ * Optimized by Bruce D. Evans.
+ */
+
+/*
+ * ====================================================
+ * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef INLINE_KERNEL_TANDF
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+#endif
+
+#include "math.h"
+#include "math_private.h"
+
+/* |tan(x)/x - t(x)| < 2**-25.5 (~[-2e-08, 2e-08]). */
+static const double
+T[] = {
+ 0x15554d3418c99f.0p-54, /* 0.333331395030791399758 */
+ 0x1112fd38999f72.0p-55, /* 0.133392002712976742718 */
+ 0x1b54c91d865afe.0p-57, /* 0.0533812378445670393523 */
+ 0x191df3908c33ce.0p-58, /* 0.0245283181166547278873 */
+ 0x185dadfcecf44e.0p-61, /* 0.00297435743359967304927 */
+ 0x1362b9bf971bcd.0p-59, /* 0.00946564784943673166728 */
+};
+
+#ifdef INLINE_KERNEL_TANDF
+extern inline
+#endif
+float
+__kernel_tandf(double x, int iy)
+{
+ double z,r,w,s,t,u;
+
+ z = x*x;
+ /*
+ * Split up the polynomial into small independent terms to give
+ * opportunities for parallel evaluation. The chosen splitting is
+ * micro-optimized for Athlons (XP, X64). It costs 2 multiplications
+ * relative to Horner's method on sequential machines.
+ *
+ * We add the small terms from lowest degree up for efficiency on
+ * non-sequential machines (the lowest degree terms tend to be ready
+ * earlier). Apart from this, we don't care about order of
+ * operations, and don't need to to care since we have precision to
+ * spare. However, the chosen splitting is good for accuracy too,
+ * and would give results as accurate as Horner's method if the
+ * small terms were added from highest degree down.
+ */
+ r = T[4]+z*T[5];
+ t = T[2]+z*T[3];
+ w = z*z;
+ s = z*x;
+ u = T[0]+z*T[1];
+ r = (x+s*u)+(s*w)*(t+w*r);
+ if(iy==1) return r;
+ else return -1.0/r;
+}
diff --git a/lib/msun/src/math.h b/lib/msun/src/math.h
new file mode 100644
index 0000000..ba918a3
--- /dev/null
+++ b/lib/msun/src/math.h
@@ -0,0 +1,473 @@
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+/*
+ * from: @(#)fdlibm.h 5.1 93/09/24
+ * $FreeBSD$
+ */
+
+#ifndef _MATH_H_
+#define _MATH_H_
+
+#include <sys/cdefs.h>
+#include <sys/_types.h>
+#include <machine/_limits.h>
+
+/*
+ * ANSI/POSIX
+ */
+extern const union __infinity_un {
+ unsigned char __uc[8];
+ double __ud;
+} __infinity;
+
+extern const union __nan_un {
+ unsigned char __uc[sizeof(float)];
+ float __uf;
+} __nan;
+
+#if __GNUC_PREREQ__(3, 3) || (defined(__INTEL_COMPILER) && __INTEL_COMPILER >= 800)
+#define __MATH_BUILTIN_CONSTANTS
+#endif
+
+#if __GNUC_PREREQ__(3, 0) && !defined(__INTEL_COMPILER)
+#define __MATH_BUILTIN_RELOPS
+#endif
+
+#ifdef __MATH_BUILTIN_CONSTANTS
+#define HUGE_VAL __builtin_huge_val()
+#else
+#define HUGE_VAL (__infinity.__ud)
+#endif
+
+#if __ISO_C_VISIBLE >= 1999
+#define FP_ILOGB0 (-__INT_MAX)
+#define FP_ILOGBNAN __INT_MAX
+
+#ifdef __MATH_BUILTIN_CONSTANTS
+#define HUGE_VALF __builtin_huge_valf()
+#define HUGE_VALL __builtin_huge_vall()
+#define INFINITY __builtin_inf()
+#define NAN __builtin_nan("")
+#else
+#define HUGE_VALF (float)HUGE_VAL
+#define HUGE_VALL (long double)HUGE_VAL
+#define INFINITY HUGE_VALF
+#define NAN (__nan.__uf)
+#endif /* __MATH_BUILTIN_CONSTANTS */
+
+#define MATH_ERRNO 1
+#define MATH_ERREXCEPT 2
+#define math_errhandling MATH_ERREXCEPT
+
+/* XXX We need a <machine/math.h>. */
+#if defined(__ia64__) || defined(__sparc64__)
+#define FP_FAST_FMA
+#endif
+#ifdef __ia64__
+#define FP_FAST_FMAL
+#endif
+#define FP_FAST_FMAF
+
+/* Symbolic constants to classify floating point numbers. */
+#define FP_INFINITE 0x01
+#define FP_NAN 0x02
+#define FP_NORMAL 0x04
+#define FP_SUBNORMAL 0x08
+#define FP_ZERO 0x10
+#define fpclassify(x) \
+ ((sizeof (x) == sizeof (float)) ? __fpclassifyf(x) \
+ : (sizeof (x) == sizeof (double)) ? __fpclassifyd(x) \
+ : __fpclassifyl(x))
+
+#define isfinite(x) \
+ ((sizeof (x) == sizeof (float)) ? __isfinitef(x) \
+ : (sizeof (x) == sizeof (double)) ? __isfinite(x) \
+ : __isfinitel(x))
+#define isinf(x) \
+ ((sizeof (x) == sizeof (float)) ? __isinff(x) \
+ : (sizeof (x) == sizeof (double)) ? isinf(x) \
+ : __isinfl(x))
+#define isnan(x) \
+ ((sizeof (x) == sizeof (float)) ? isnanf(x) \
+ : (sizeof (x) == sizeof (double)) ? isnan(x) \
+ : __isnanl(x))
+#define isnormal(x) \
+ ((sizeof (x) == sizeof (float)) ? __isnormalf(x) \
+ : (sizeof (x) == sizeof (double)) ? __isnormal(x) \
+ : __isnormall(x))
+
+#ifdef __MATH_BUILTIN_RELOPS
+#define isgreater(x, y) __builtin_isgreater((x), (y))
+#define isgreaterequal(x, y) __builtin_isgreaterequal((x), (y))
+#define isless(x, y) __builtin_isless((x), (y))
+#define islessequal(x, y) __builtin_islessequal((x), (y))
+#define islessgreater(x, y) __builtin_islessgreater((x), (y))
+#define isunordered(x, y) __builtin_isunordered((x), (y))
+#else
+#define isgreater(x, y) (!isunordered((x), (y)) && (x) > (y))
+#define isgreaterequal(x, y) (!isunordered((x), (y)) && (x) >= (y))
+#define isless(x, y) (!isunordered((x), (y)) && (x) < (y))
+#define islessequal(x, y) (!isunordered((x), (y)) && (x) <= (y))
+#define islessgreater(x, y) (!isunordered((x), (y)) && \
+ ((x) > (y) || (y) > (x)))
+#define isunordered(x, y) (isnan(x) || isnan(y))
+#endif /* __MATH_BUILTIN_RELOPS */
+
+#define signbit(x) \
+ ((sizeof (x) == sizeof (float)) ? __signbitf(x) \
+ : (sizeof (x) == sizeof (double)) ? __signbit(x) \
+ : __signbitl(x))
+
+typedef __double_t double_t;
+typedef __float_t float_t;
+#endif /* __ISO_C_VISIBLE >= 1999 */
+
+/*
+ * XOPEN/SVID
+ */
+#if __BSD_VISIBLE || __XSI_VISIBLE
+#define M_E 2.7182818284590452354 /* e */
+#define M_LOG2E 1.4426950408889634074 /* log 2e */
+#define M_LOG10E 0.43429448190325182765 /* log 10e */
+#define M_LN2 0.69314718055994530942 /* log e2 */
+#define M_LN10 2.30258509299404568402 /* log e10 */
+#define M_PI 3.14159265358979323846 /* pi */
+#define M_PI_2 1.57079632679489661923 /* pi/2 */
+#define M_PI_4 0.78539816339744830962 /* pi/4 */
+#define M_1_PI 0.31830988618379067154 /* 1/pi */
+#define M_2_PI 0.63661977236758134308 /* 2/pi */
+#define M_2_SQRTPI 1.12837916709551257390 /* 2/sqrt(pi) */
+#define M_SQRT2 1.41421356237309504880 /* sqrt(2) */
+#define M_SQRT1_2 0.70710678118654752440 /* 1/sqrt(2) */
+
+#define MAXFLOAT ((float)3.40282346638528860e+38)
+extern int signgam;
+#endif /* __BSD_VISIBLE || __XSI_VISIBLE */
+
+#if __BSD_VISIBLE
+#if 0
+/* Old value from 4.4BSD-Lite math.h; this is probably better. */
+#define HUGE HUGE_VAL
+#else
+#define HUGE MAXFLOAT
+#endif
+#endif /* __BSD_VISIBLE */
+
+/*
+ * Most of these functions depend on the rounding mode and have the side
+ * effect of raising floating-point exceptions, so they are not declared
+ * as __pure2. In C99, FENV_ACCESS affects the purity of these functions.
+ */
+__BEGIN_DECLS
+/*
+ * ANSI/POSIX
+ */
+int __fpclassifyd(double) __pure2;
+int __fpclassifyf(float) __pure2;
+int __fpclassifyl(long double) __pure2;
+int __isfinitef(float) __pure2;
+int __isfinite(double) __pure2;
+int __isfinitel(long double) __pure2;
+int __isinff(float) __pure2;
+int __isinfl(long double) __pure2;
+int __isnanl(long double) __pure2;
+int __isnormalf(float) __pure2;
+int __isnormal(double) __pure2;
+int __isnormall(long double) __pure2;
+int __signbit(double) __pure2;
+int __signbitf(float) __pure2;
+int __signbitl(long double) __pure2;
+
+double acos(double);
+double asin(double);
+double atan(double);
+double atan2(double, double);
+double cos(double);
+double sin(double);
+double tan(double);
+
+double cosh(double);
+double sinh(double);
+double tanh(double);
+
+double exp(double);
+double frexp(double, int *); /* fundamentally !__pure2 */
+double ldexp(double, int);
+double log(double);
+double log10(double);
+double modf(double, double *); /* fundamentally !__pure2 */
+
+double pow(double, double);
+double sqrt(double);
+
+double ceil(double);
+double fabs(double) __pure2;
+double floor(double);
+double fmod(double, double);
+
+/*
+ * These functions are not in C90.
+ */
+#if __BSD_VISIBLE || __ISO_C_VISIBLE >= 1999 || __XSI_VISIBLE
+double acosh(double);
+double asinh(double);
+double atanh(double);
+double cbrt(double);
+double erf(double);
+double erfc(double);
+double exp2(double);
+double expm1(double);
+double fma(double, double, double);
+double hypot(double, double);
+int ilogb(double) __pure2;
+int (isinf)(double) __pure2;
+int (isnan)(double) __pure2;
+double lgamma(double);
+long long llrint(double);
+long long llround(double);
+double log1p(double);
+double logb(double);
+long lrint(double);
+long lround(double);
+double nextafter(double, double);
+double remainder(double, double);
+double remquo(double, double, int *);
+double rint(double);
+#endif /* __BSD_VISIBLE || __ISO_C_VISIBLE >= 1999 || __XSI_VISIBLE */
+
+#if __BSD_VISIBLE || __XSI_VISIBLE
+double j0(double);
+double j1(double);
+double jn(int, double);
+double scalb(double, double);
+double y0(double);
+double y1(double);
+double yn(int, double);
+
+#if __XSI_VISIBLE <= 500 || __BSD_VISIBLE
+double gamma(double);
+#endif
+#endif /* __BSD_VISIBLE || __XSI_VISIBLE */
+
+#if __BSD_VISIBLE || __ISO_C_VISIBLE >= 1999
+double copysign(double, double) __pure2;
+double fdim(double, double);
+double fmax(double, double) __pure2;
+double fmin(double, double) __pure2;
+double nearbyint(double);
+double round(double);
+double scalbln(double, long);
+double scalbn(double, int);
+double tgamma(double);
+double trunc(double);
+#endif
+
+/*
+ * BSD math library entry points
+ */
+#if __BSD_VISIBLE
+double drem(double, double);
+int finite(double) __pure2;
+int isnanf(float) __pure2;
+
+/*
+ * Reentrant version of gamma & lgamma; passes signgam back by reference
+ * as the second argument; user must allocate space for signgam.
+ */
+double gamma_r(double, int *);
+double lgamma_r(double, int *);
+
+/*
+ * IEEE Test Vector
+ */
+double significand(double);
+#endif /* __BSD_VISIBLE */
+
+/* float versions of ANSI/POSIX functions */
+#if __ISO_C_VISIBLE >= 1999
+float acosf(float);
+float asinf(float);
+float atanf(float);
+float atan2f(float, float);
+float cosf(float);
+float sinf(float);
+float tanf(float);
+
+float coshf(float);
+float sinhf(float);
+float tanhf(float);
+
+float exp2f(float);
+float expf(float);
+float expm1f(float);
+float frexpf(float, int *); /* fundamentally !__pure2 */
+int ilogbf(float) __pure2;
+float ldexpf(float, int);
+float log10f(float);
+float log1pf(float);
+float logf(float);
+float modff(float, float *); /* fundamentally !__pure2 */
+
+float powf(float, float);
+float sqrtf(float);
+
+float ceilf(float);
+float fabsf(float) __pure2;
+float floorf(float);
+float fmodf(float, float);
+float roundf(float);
+
+float erff(float);
+float erfcf(float);
+float hypotf(float, float);
+float lgammaf(float);
+
+float acoshf(float);
+float asinhf(float);
+float atanhf(float);
+float cbrtf(float);
+float logbf(float);
+float copysignf(float, float) __pure2;
+long long llrintf(float);
+long long llroundf(float);
+long lrintf(float);
+long lroundf(float);
+float nearbyintf(float);
+float nextafterf(float, float);
+float remainderf(float, float);
+float remquof(float, float, int *);
+float rintf(float);
+float scalblnf(float, long);
+float scalbnf(float, int);
+float truncf(float);
+
+float fdimf(float, float);
+float fmaf(float, float, float);
+float fmaxf(float, float) __pure2;
+float fminf(float, float) __pure2;
+#endif
+
+/*
+ * float versions of BSD math library entry points
+ */
+#if __BSD_VISIBLE
+float dremf(float, float);
+int finitef(float) __pure2;
+float gammaf(float);
+float j0f(float);
+float j1f(float);
+float jnf(int, float);
+float scalbf(float, float);
+float y0f(float);
+float y1f(float);
+float ynf(int, float);
+
+/*
+ * Float versions of reentrant version of gamma & lgamma; passes
+ * signgam back by reference as the second argument; user must
+ * allocate space for signgam.
+ */
+float gammaf_r(float, int *);
+float lgammaf_r(float, int *);
+
+/*
+ * float version of IEEE Test Vector
+ */
+float significandf(float);
+#endif /* __BSD_VISIBLE */
+
+/*
+ * long double versions of ISO/POSIX math functions
+ */
+#if __ISO_C_VISIBLE >= 1999
+#if 0
+long double acoshl(long double);
+long double acosl(long double);
+long double asinhl(long double);
+long double asinl(long double);
+long double atan2l(long double, long double);
+long double atanhl(long double);
+long double atanl(long double);
+long double cbrtl(long double);
+#endif
+long double ceill(long double);
+long double copysignl(long double, long double) __pure2;
+#if 0
+long double coshl(long double);
+long double cosl(long double);
+long double erfcl(long double);
+long double erfl(long double);
+long double exp2l(long double);
+long double expl(long double);
+long double expm1l(long double);
+#endif
+long double fabsl(long double) __pure2;
+long double fdiml(long double, long double);
+long double floorl(long double);
+long double fmal(long double, long double, long double);
+long double fmaxl(long double, long double) __pure2;
+long double fminl(long double, long double) __pure2;
+#if 0
+long double fmodl(long double, long double);
+#endif
+long double frexpl(long double value, int *); /* fundamentally !__pure2 */
+#if 0
+long double hypotl(long double, long double);
+#endif
+int ilogbl(long double) __pure2;
+long double ldexpl(long double, int);
+#if 0
+long double lgammal(long double);
+long long llrintl(long double);
+#endif
+long long llroundl(long double);
+#if 0
+long double log10l(long double);
+long double log1pl(long double);
+long double log2l(long double);
+long double logbl(long double);
+long double logl(long double);
+long lrintl(long double);
+#endif
+long lroundl(long double);
+#if 0
+long double modfl(long double, long double *); /* fundamentally !__pure2 */
+long double nanl(const char *) __pure2;
+long double nearbyintl(long double);
+#endif
+long double nextafterl(long double, long double);
+double nexttoward(double, long double);
+float nexttowardf(float, long double);
+long double nexttowardl(long double, long double);
+#if 0
+long double powl(long double, long double);
+long double remainderl(long double, long double);
+long double remquol(long double, long double, int *);
+long double rintl(long double);
+#endif
+long double roundl(long double);
+long double scalblnl(long double, long);
+long double scalbnl(long double, int);
+#if 0
+long double sinhl(long double);
+long double sinl(long double);
+long double sqrtl(long double);
+long double tanhl(long double);
+long double tanl(long double);
+long double tgammal(long double);
+#endif
+long double truncl(long double);
+
+#endif /* __ISO_C_VISIBLE >= 1999 */
+__END_DECLS
+
+#endif /* !_MATH_H_ */
diff --git a/lib/msun/src/math_private.h b/lib/msun/src/math_private.h
new file mode 100644
index 0000000..9b38480
--- /dev/null
+++ b/lib/msun/src/math_private.h
@@ -0,0 +1,272 @@
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+/*
+ * from: @(#)fdlibm.h 5.1 93/09/24
+ * $FreeBSD$
+ */
+
+#ifndef _MATH_PRIVATE_H_
+#define _MATH_PRIVATE_H_
+
+#include <sys/types.h>
+#include <machine/endian.h>
+
+/*
+ * The original fdlibm code used statements like:
+ * n0 = ((*(int*)&one)>>29)^1; * index of high word *
+ * ix0 = *(n0+(int*)&x); * high word of x *
+ * ix1 = *((1-n0)+(int*)&x); * low word of x *
+ * to dig two 32 bit words out of the 64 bit IEEE floating point
+ * value. That is non-ANSI, and, moreover, the gcc instruction
+ * scheduler gets it wrong. We instead use the following macros.
+ * Unlike the original code, we determine the endianness at compile
+ * time, not at run time; I don't see much benefit to selecting
+ * endianness at run time.
+ */
+
+/*
+ * A union which permits us to convert between a double and two 32 bit
+ * ints.
+ */
+
+#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)
+
+/* Get the less significant 32 bit int from a double. */
+
+#define GET_LOW_WORD(i,d) \
+do { \
+ ieee_double_shape_type gl_u; \
+ gl_u.value = (d); \
+ (i) = gl_u.parts.lsw; \
+} 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)
+
+/* 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)
+
+/* Set the less significant 32 bits of a double from an int. */
+
+#define SET_LOW_WORD(d,v) \
+do { \
+ ieee_double_shape_type sl_u; \
+ sl_u.value = (d); \
+ sl_u.parts.lsw = (v); \
+ (d) = sl_u.value; \
+} while (0)
+
+/*
+ * A union which permits us to convert between a float and a 32 bit
+ * int.
+ */
+
+typedef union
+{
+ float value;
+ /* FIXME: Assumes 32 bit int. */
+ unsigned int word;
+} ieee_float_shape_type;
+
+/* Get a 32 bit int from a float. */
+
+#define GET_FLOAT_WORD(i,d) \
+do { \
+ ieee_float_shape_type gf_u; \
+ gf_u.value = (d); \
+ (i) = gf_u.word; \
+} while (0)
+
+/* Set a float from a 32 bit int. */
+
+#define SET_FLOAT_WORD(d,i) \
+do { \
+ ieee_float_shape_type sf_u; \
+ sf_u.word = (i); \
+ (d) = sf_u.value; \
+} while (0)
+
+#ifdef _COMPLEX_H
+/*
+ * Inline functions that can be used to construct complex values.
+ *
+ * The C99 standard intends x+I*y to be used for this, but x+I*y is
+ * currently unusable in general since gcc introduces many overflow,
+ * underflow, sign and efficiency bugs by rewriting I*y as
+ * (0.0+I)*(y+0.0*I) and laboriously computing the full complex product.
+ * In particular, I*Inf is corrupted to NaN+I*Inf, and I*-0 is corrupted
+ * to -0.0+I*0.0.
+ */
+static __inline float complex
+cpackf(float x, float y)
+{
+ float complex z;
+
+ __real__ z = x;
+ __imag__ z = y;
+ return (z);
+}
+
+static __inline double complex
+cpack(double x, double y)
+{
+ double complex z;
+
+ __real__ z = x;
+ __imag__ z = y;
+ return (z);
+}
+
+static __inline long double complex
+cpackl(long double x, long double y)
+{
+ long double complex z;
+
+ __real__ z = x;
+ __imag__ z = y;
+ return (z);
+}
+#endif /* _COMPLEX_H */
+
+/*
+ * ieee style elementary functions
+ *
+ * We rename functions here to improve other sources' diffability
+ * against fdlibm.
+ */
+#define __ieee754_sqrt sqrt
+#define __ieee754_acos acos
+#define __ieee754_acosh acosh
+#define __ieee754_log log
+#define __ieee754_atanh atanh
+#define __ieee754_asin asin
+#define __ieee754_atan2 atan2
+#define __ieee754_exp exp
+#define __ieee754_cosh cosh
+#define __ieee754_fmod fmod
+#define __ieee754_pow pow
+#define __ieee754_lgamma lgamma
+#define __ieee754_gamma gamma
+#define __ieee754_lgamma_r lgamma_r
+#define __ieee754_gamma_r gamma_r
+#define __ieee754_log10 log10
+#define __ieee754_sinh sinh
+#define __ieee754_hypot hypot
+#define __ieee754_j0 j0
+#define __ieee754_j1 j1
+#define __ieee754_y0 y0
+#define __ieee754_y1 y1
+#define __ieee754_jn jn
+#define __ieee754_yn yn
+#define __ieee754_remainder remainder
+#define __ieee754_scalb scalb
+#define __ieee754_sqrtf sqrtf
+#define __ieee754_acosf acosf
+#define __ieee754_acoshf acoshf
+#define __ieee754_logf logf
+#define __ieee754_atanhf atanhf
+#define __ieee754_asinf asinf
+#define __ieee754_atan2f atan2f
+#define __ieee754_expf expf
+#define __ieee754_coshf coshf
+#define __ieee754_fmodf fmodf
+#define __ieee754_powf powf
+#define __ieee754_lgammaf lgammaf
+#define __ieee754_gammaf gammaf
+#define __ieee754_lgammaf_r lgammaf_r
+#define __ieee754_gammaf_r gammaf_r
+#define __ieee754_log10f log10f
+#define __ieee754_sinhf sinhf
+#define __ieee754_hypotf hypotf
+#define __ieee754_j0f j0f
+#define __ieee754_j1f j1f
+#define __ieee754_y0f y0f
+#define __ieee754_y1f y1f
+#define __ieee754_jnf jnf
+#define __ieee754_ynf ynf
+#define __ieee754_remainderf remainderf
+#define __ieee754_scalbf scalbf
+
+/* fdlibm kernel function */
+int __ieee754_rem_pio2(double,double*);
+double __kernel_sin(double,double,int);
+double __kernel_cos(double,double);
+double __kernel_tan(double,double,int);
+int __kernel_rem_pio2(double*,double*,int,int,int,const int*);
+
+/* float versions of fdlibm kernel functions */
+int __ieee754_rem_pio2f(float,float*);
+float __kernel_sindf(double);
+float __kernel_cosdf(double);
+float __kernel_tandf(double,int);
+int __kernel_rem_pio2f(float*,float*,int,int,int,const int*);
+
+#endif /* !_MATH_PRIVATE_H_ */
diff --git a/lib/msun/src/s_asinh.c b/lib/msun/src/s_asinh.c
new file mode 100644
index 0000000..95a539d
--- /dev/null
+++ b/lib/msun/src/s_asinh.c
@@ -0,0 +1,57 @@
+/* @(#)s_asinh.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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/* asinh(x)
+ * Method :
+ * Based on
+ * asinh(x) = sign(x) * log [ |x| + sqrt(x*x+1) ]
+ * we have
+ * asinh(x) := x if 1+x*x=1,
+ * := sign(x)*(log(x)+ln2)) for large |x|, else
+ * := sign(x)*log(2|x|+1/(|x|+sqrt(x*x+1))) if|x|>2, else
+ * := sign(x)*log1p(|x| + x^2/(1 + sqrt(1+x^2)))
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+static const double
+one = 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+ln2 = 6.93147180559945286227e-01, /* 0x3FE62E42, 0xFEFA39EF */
+huge= 1.00000000000000000000e+300;
+
+double
+asinh(double x)
+{
+ double t,w;
+ int32_t hx,ix;
+ GET_HIGH_WORD(hx,x);
+ ix = hx&0x7fffffff;
+ if(ix>=0x7ff00000) return x+x; /* x is inf or NaN */
+ if(ix< 0x3e300000) { /* |x|<2**-28 */
+ if(huge+x>one) return x; /* return x inexact except 0 */
+ }
+ if(ix>0x41b00000) { /* |x| > 2**28 */
+ w = __ieee754_log(fabs(x))+ln2;
+ } else if (ix>0x40000000) { /* 2**28 > |x| > 2.0 */
+ t = fabs(x);
+ w = __ieee754_log(2.0*t+one/(__ieee754_sqrt(x*x+one)+t));
+ } else { /* 2.0 > |x| > 2**-28 */
+ t = x*x;
+ w =log1p(fabs(x)+t/(one+__ieee754_sqrt(one+t)));
+ }
+ if(hx>0) return w; else return -w;
+}
diff --git a/lib/msun/src/s_asinhf.c b/lib/msun/src/s_asinhf.c
new file mode 100644
index 0000000..6dcfc5b
--- /dev/null
+++ b/lib/msun/src/s_asinhf.c
@@ -0,0 +1,49 @@
+/* s_asinhf.c -- float version of s_asinh.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+#include "math.h"
+#include "math_private.h"
+
+static const float
+one = 1.0000000000e+00, /* 0x3F800000 */
+ln2 = 6.9314718246e-01, /* 0x3f317218 */
+huge= 1.0000000000e+30;
+
+float
+asinhf(float x)
+{
+ float t,w;
+ int32_t hx,ix;
+ GET_FLOAT_WORD(hx,x);
+ ix = hx&0x7fffffff;
+ if(ix>=0x7f800000) return x+x; /* x is inf or NaN */
+ if(ix< 0x31800000) { /* |x|<2**-28 */
+ if(huge+x>one) return x; /* return x inexact except 0 */
+ }
+ if(ix>0x4d800000) { /* |x| > 2**28 */
+ w = __ieee754_logf(fabsf(x))+ln2;
+ } else if (ix>0x40000000) { /* 2**28 > |x| > 2.0 */
+ t = fabsf(x);
+ w = __ieee754_logf((float)2.0*t+one/(__ieee754_sqrtf(x*x+one)+t));
+ } else { /* 2.0 > |x| > 2**-28 */
+ t = x*x;
+ w =log1pf(fabsf(x)+t/(one+__ieee754_sqrtf(one+t)));
+ }
+ if(hx>0) return w; else return -w;
+}
diff --git a/lib/msun/src/s_atan.c b/lib/msun/src/s_atan.c
new file mode 100644
index 0000000..5ef6700
--- /dev/null
+++ b/lib/msun/src/s_atan.c
@@ -0,0 +1,119 @@
+/* @(#)s_atan.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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/* atan(x)
+ * Method
+ * 1. Reduce x to positive by atan(x) = -atan(-x).
+ * 2. According to the integer k=4t+0.25 chopped, t=x, the argument
+ * is further reduced to one of the following intervals and the
+ * arctangent of t is evaluated by the corresponding formula:
+ *
+ * [0,7/16] atan(x) = t-t^3*(a1+t^2*(a2+...(a10+t^2*a11)...)
+ * [7/16,11/16] atan(x) = atan(1/2) + atan( (t-0.5)/(1+t/2) )
+ * [11/16.19/16] atan(x) = atan( 1 ) + atan( (t-1)/(1+t) )
+ * [19/16,39/16] atan(x) = atan(3/2) + atan( (t-1.5)/(1+1.5t) )
+ * [39/16,INF] atan(x) = atan(INF) + atan( -1/t )
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following
+ * constants. The decimal values may be used, provided that the
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+static const double atanhi[] = {
+ 4.63647609000806093515e-01, /* atan(0.5)hi 0x3FDDAC67, 0x0561BB4F */
+ 7.85398163397448278999e-01, /* atan(1.0)hi 0x3FE921FB, 0x54442D18 */
+ 9.82793723247329054082e-01, /* atan(1.5)hi 0x3FEF730B, 0xD281F69B */
+ 1.57079632679489655800e+00, /* atan(inf)hi 0x3FF921FB, 0x54442D18 */
+};
+
+static const double atanlo[] = {
+ 2.26987774529616870924e-17, /* atan(0.5)lo 0x3C7A2B7F, 0x222F65E2 */
+ 3.06161699786838301793e-17, /* atan(1.0)lo 0x3C81A626, 0x33145C07 */
+ 1.39033110312309984516e-17, /* atan(1.5)lo 0x3C700788, 0x7AF0CBBD */
+ 6.12323399573676603587e-17, /* atan(inf)lo 0x3C91A626, 0x33145C07 */
+};
+
+static const double aT[] = {
+ 3.33333333333329318027e-01, /* 0x3FD55555, 0x5555550D */
+ -1.99999999998764832476e-01, /* 0xBFC99999, 0x9998EBC4 */
+ 1.42857142725034663711e-01, /* 0x3FC24924, 0x920083FF */
+ -1.11111104054623557880e-01, /* 0xBFBC71C6, 0xFE231671 */
+ 9.09088713343650656196e-02, /* 0x3FB745CD, 0xC54C206E */
+ -7.69187620504482999495e-02, /* 0xBFB3B0F2, 0xAF749A6D */
+ 6.66107313738753120669e-02, /* 0x3FB10D66, 0xA0D03D51 */
+ -5.83357013379057348645e-02, /* 0xBFADDE2D, 0x52DEFD9A */
+ 4.97687799461593236017e-02, /* 0x3FA97B4B, 0x24760DEB */
+ -3.65315727442169155270e-02, /* 0xBFA2B444, 0x2C6A6C2F */
+ 1.62858201153657823623e-02, /* 0x3F90AD3A, 0xE322DA11 */
+};
+
+ static const double
+one = 1.0,
+huge = 1.0e300;
+
+double
+atan(double x)
+{
+ double w,s1,s2,z;
+ int32_t ix,hx,id;
+
+ GET_HIGH_WORD(hx,x);
+ ix = hx&0x7fffffff;
+ if(ix>=0x44100000) { /* if |x| >= 2^66 */
+ u_int32_t low;
+ GET_LOW_WORD(low,x);
+ if(ix>0x7ff00000||
+ (ix==0x7ff00000&&(low!=0)))
+ return x+x; /* NaN */
+ if(hx>0) return atanhi[3]+atanlo[3];
+ else return -atanhi[3]-atanlo[3];
+ } if (ix < 0x3fdc0000) { /* |x| < 0.4375 */
+ if (ix < 0x3e200000) { /* |x| < 2^-29 */
+ if(huge+x>one) return x; /* raise inexact */
+ }
+ id = -1;
+ } else {
+ x = fabs(x);
+ if (ix < 0x3ff30000) { /* |x| < 1.1875 */
+ if (ix < 0x3fe60000) { /* 7/16 <=|x|<11/16 */
+ id = 0; x = (2.0*x-one)/(2.0+x);
+ } else { /* 11/16<=|x|< 19/16 */
+ id = 1; x = (x-one)/(x+one);
+ }
+ } else {
+ if (ix < 0x40038000) { /* |x| < 2.4375 */
+ id = 2; x = (x-1.5)/(one+1.5*x);
+ } else { /* 2.4375 <= |x| < 2^66 */
+ id = 3; x = -1.0/x;
+ }
+ }}
+ /* end of argument reduction */
+ z = x*x;
+ w = z*z;
+ /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */
+ s1 = z*(aT[0]+w*(aT[2]+w*(aT[4]+w*(aT[6]+w*(aT[8]+w*aT[10])))));
+ s2 = w*(aT[1]+w*(aT[3]+w*(aT[5]+w*(aT[7]+w*aT[9]))));
+ if (id<0) return x - x*(s1+s2);
+ else {
+ z = atanhi[id] - ((x*(s1+s2) - atanlo[id]) - x);
+ return (hx<0)? -z:z;
+ }
+}
diff --git a/lib/msun/src/s_atanf.c b/lib/msun/src/s_atanf.c
new file mode 100644
index 0000000..d4a500f
--- /dev/null
+++ b/lib/msun/src/s_atanf.c
@@ -0,0 +1,99 @@
+/* s_atanf.c -- float version of s_atan.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+#include "math.h"
+#include "math_private.h"
+
+static const float atanhi[] = {
+ 4.6364760399e-01, /* atan(0.5)hi 0x3eed6338 */
+ 7.8539812565e-01, /* atan(1.0)hi 0x3f490fda */
+ 9.8279368877e-01, /* atan(1.5)hi 0x3f7b985e */
+ 1.5707962513e+00, /* atan(inf)hi 0x3fc90fda */
+};
+
+static const float atanlo[] = {
+ 5.0121582440e-09, /* atan(0.5)lo 0x31ac3769 */
+ 3.7748947079e-08, /* atan(1.0)lo 0x33222168 */
+ 3.4473217170e-08, /* atan(1.5)lo 0x33140fb4 */
+ 7.5497894159e-08, /* atan(inf)lo 0x33a22168 */
+};
+
+static const float aT[] = {
+ 3.3333334327e-01, /* 0x3eaaaaaa */
+ -2.0000000298e-01, /* 0xbe4ccccd */
+ 1.4285714924e-01, /* 0x3e124925 */
+ -1.1111110449e-01, /* 0xbde38e38 */
+ 9.0908870101e-02, /* 0x3dba2e6e */
+ -7.6918758452e-02, /* 0xbd9d8795 */
+ 6.6610731184e-02, /* 0x3d886b35 */
+ -5.8335702866e-02, /* 0xbd6ef16b */
+ 4.9768779427e-02, /* 0x3d4bda59 */
+ -3.6531571299e-02, /* 0xbd15a221 */
+ 1.6285819933e-02, /* 0x3c8569d7 */
+};
+
+ static const float
+one = 1.0,
+huge = 1.0e30;
+
+float
+atanf(float x)
+{
+ float w,s1,s2,z;
+ int32_t ix,hx,id;
+
+ GET_FLOAT_WORD(hx,x);
+ ix = hx&0x7fffffff;
+ if(ix>=0x50800000) { /* if |x| >= 2^34 */
+ if(ix>0x7f800000)
+ return x+x; /* NaN */
+ if(hx>0) return atanhi[3]+atanlo[3];
+ else return -atanhi[3]-atanlo[3];
+ } if (ix < 0x3ee00000) { /* |x| < 0.4375 */
+ if (ix < 0x31000000) { /* |x| < 2^-29 */
+ if(huge+x>one) return x; /* raise inexact */
+ }
+ id = -1;
+ } else {
+ x = fabsf(x);
+ if (ix < 0x3f980000) { /* |x| < 1.1875 */
+ if (ix < 0x3f300000) { /* 7/16 <=|x|<11/16 */
+ id = 0; x = ((float)2.0*x-one)/((float)2.0+x);
+ } else { /* 11/16<=|x|< 19/16 */
+ id = 1; x = (x-one)/(x+one);
+ }
+ } else {
+ if (ix < 0x401c0000) { /* |x| < 2.4375 */
+ id = 2; x = (x-(float)1.5)/(one+(float)1.5*x);
+ } else { /* 2.4375 <= |x| < 2^66 */
+ id = 3; x = -(float)1.0/x;
+ }
+ }}
+ /* end of argument reduction */
+ z = x*x;
+ w = z*z;
+ /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */
+ s1 = z*(aT[0]+w*(aT[2]+w*(aT[4]+w*(aT[6]+w*(aT[8]+w*aT[10])))));
+ s2 = w*(aT[1]+w*(aT[3]+w*(aT[5]+w*(aT[7]+w*aT[9]))));
+ if (id<0) return x - x*(s1+s2);
+ else {
+ z = atanhi[id] - ((x*(s1+s2) - atanlo[id]) - x);
+ return (hx<0)? -z:z;
+ }
+}
diff --git a/lib/msun/src/s_cbrt.c b/lib/msun/src/s_cbrt.c
new file mode 100644
index 0000000..545b0e7
--- /dev/null
+++ b/lib/msun/src/s_cbrt.c
@@ -0,0 +1,114 @@
+/* @(#)s_cbrt.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.
+ * ====================================================
+ *
+ * Optimized by Bruce D. Evans.
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+#include "math.h"
+#include "math_private.h"
+
+/* cbrt(x)
+ * Return cube root of x
+ */
+static const u_int32_t
+ B1 = 715094163, /* B1 = (1023-1023/3-0.03306235651)*2**20 */
+ B2 = 696219795; /* B2 = (1023-1023/3-54/3-0.03306235651)*2**20 */
+
+/* |1/cbrt(x) - p(x)| < 2**-23.5 (~[-7.93e-8, 7.929e-8]). */
+static const double
+P0 = 1.87595182427177009643, /* 0x3ffe03e6, 0x0f61e692 */
+P1 = -1.88497979543377169875, /* 0xbffe28e0, 0x92f02420 */
+P2 = 1.621429720105354466140, /* 0x3ff9f160, 0x4a49d6c2 */
+P3 = -0.758397934778766047437, /* 0xbfe844cb, 0xbee751d9 */
+P4 = 0.145996192886612446982; /* 0x3fc2b000, 0xd4e4edd7 */
+
+double
+cbrt(double x)
+{
+ int32_t hx;
+ union {
+ double value;
+ uint64_t bits;
+ } u;
+ double r,s,t=0.0,w;
+ u_int32_t sign;
+ u_int32_t high,low;
+
+ EXTRACT_WORDS(hx,low,x);
+ sign=hx&0x80000000; /* sign= sign(x) */
+ hx ^=sign;
+ if(hx>=0x7ff00000) return(x+x); /* cbrt(NaN,INF) is itself */
+
+ /*
+ * Rough cbrt to 5 bits:
+ * cbrt(2**e*(1+m) ~= 2**(e/3)*(1+(e%3+m)/3)
+ * where e is integral and >= 0, m is real and in [0, 1), and "/" and
+ * "%" are integer division and modulus with rounding towards minus
+ * infinity. The RHS is always >= the LHS and has a maximum relative
+ * error of about 1 in 16. Adding a bias of -0.03306235651 to the
+ * (e%3+m)/3 term reduces the error to about 1 in 32. With the IEEE
+ * floating point representation, for finite positive normal values,
+ * ordinary integer divison of the value in bits magically gives
+ * almost exactly the RHS of the above provided we first subtract the
+ * exponent bias (1023 for doubles) and later add it back. We do the
+ * subtraction virtually to keep e >= 0 so that ordinary integer
+ * division rounds towards minus infinity; this is also efficient.
+ */
+ if(hx<0x00100000) { /* zero or subnormal? */
+ if((hx|low)==0)
+ return(x); /* cbrt(0) is itself */
+ SET_HIGH_WORD(t,0x43500000); /* set t= 2**54 */
+ t*=x;
+ GET_HIGH_WORD(high,t);
+ INSERT_WORDS(t,sign|((high&0x7fffffff)/3+B2),0);
+ } else
+ INSERT_WORDS(t,sign|(hx/3+B1),0);
+
+ /*
+ * New cbrt to 23 bits:
+ * cbrt(x) = t*cbrt(x/t**3) ~= t*P(t**3/x)
+ * where P(r) is a polynomial of degree 4 that approximates 1/cbrt(r)
+ * to within 2**-23.5 when |r - 1| < 1/10. The rough approximation
+ * has produced t such than |t/cbrt(x) - 1| ~< 1/32, and cubing this
+ * gives us bounds for r = t**3/x.
+ *
+ * Try to optimize for parallel evaluation as in k_tanf.c.
+ */
+ r=(t*t)*(t/x);
+ t=t*((P0+r*(P1+r*P2))+((r*r)*r)*(P3+r*P4));
+
+ /*
+ * Round t away from zero to 23 bits (sloppily except for ensuring that
+ * the result is larger in magnitude than cbrt(x) but not much more than
+ * 2 23-bit ulps larger). With rounding towards zero, the error bound
+ * would be ~5/6 instead of ~4/6. With a maximum error of 2 23-bit ulps
+ * in the rounded t, the infinite-precision error in the Newton
+ * approximation barely affects third digit in the the final error
+ * 0.667; the error in the rounded t can be up to about 3 23-bit ulps
+ * before the final error is larger than 0.667 ulps.
+ */
+ u.value=t;
+ u.bits=(u.bits+0x80000000)&0xffffffffc0000000ULL;
+ t=u.value;
+
+ /* one step Newton iteration to 53 bits with error < 0.667 ulps */
+ s=t*t; /* t*t is exact */
+ r=x/s; /* error <= 0.5 ulps; |r| < |t| */
+ w=t+t; /* t+t is exact */
+ r=(r-t)/(w+r); /* r-t is exact; w+r ~= 3*t */
+ t=t+t*r; /* error <= 0.5 + 0.5/3 + epsilon */
+
+ return(t);
+}
diff --git a/lib/msun/src/s_cbrtf.c b/lib/msun/src/s_cbrtf.c
new file mode 100644
index 0000000..5fcd795
--- /dev/null
+++ b/lib/msun/src/s_cbrtf.c
@@ -0,0 +1,74 @@
+/* s_cbrtf.c -- float version of s_cbrt.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ * Debugged and optimized by Bruce D. Evans.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+#include "math.h"
+#include "math_private.h"
+
+/* cbrtf(x)
+ * Return cube root of x
+ */
+static const unsigned
+ B1 = 709958130, /* B1 = (127-127.0/3-0.03306235651)*2**23 */
+ B2 = 642849266; /* B2 = (127-127.0/3-24/3-0.03306235651)*2**23 */
+
+float
+cbrtf(float x)
+{
+ double r,T;
+ float t;
+ int32_t hx;
+ u_int32_t sign;
+ u_int32_t high;
+
+ GET_FLOAT_WORD(hx,x);
+ sign=hx&0x80000000; /* sign= sign(x) */
+ hx ^=sign;
+ if(hx>=0x7f800000) return(x+x); /* cbrt(NaN,INF) is itself */
+ if(hx==0)
+ return(x); /* cbrt(0) is itself */
+
+ /* rough cbrt to 5 bits */
+ if(hx<0x00800000) { /* subnormal number */
+ SET_FLOAT_WORD(t,0x4b800000); /* set t= 2**24 */
+ t*=x;
+ GET_FLOAT_WORD(high,t);
+ SET_FLOAT_WORD(t,sign|((high&0x7fffffff)/3+B2));
+ } else
+ SET_FLOAT_WORD(t,sign|(hx/3+B1));
+
+ /*
+ * First step Newton iteration (solving t*t-x/t == 0) to 16 bits. In
+ * double precision so that its terms can be arranged for efficiency
+ * without causing overflow or underflow.
+ */
+ T=t;
+ r=T*T*T;
+ T=T*((double)x+x+r)/(x+r+r);
+
+ /*
+ * Second step Newton iteration to 47 bits. In double precision for
+ * efficiency and accuracy.
+ */
+ r=T*T*T;
+ T=T*((double)x+x+r)/(x+r+r);
+
+ /* rounding to 24 bits is perfect in round-to-nearest mode */
+ return(T);
+}
diff --git a/lib/msun/src/s_ceil.c b/lib/msun/src/s_ceil.c
new file mode 100644
index 0000000..210b7ee
--- /dev/null
+++ b/lib/msun/src/s_ceil.c
@@ -0,0 +1,72 @@
+/* @(#)s_ceil.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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/*
+ * ceil(x)
+ * Return x rounded toward -inf to integral value
+ * Method:
+ * Bit twiddling.
+ * Exception:
+ * Inexact flag raised if x not equal to ceil(x).
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+static const double huge = 1.0e300;
+
+double
+ceil(double x)
+{
+ int32_t i0,i1,j0;
+ u_int32_t i,j;
+ EXTRACT_WORDS(i0,i1,x);
+ j0 = ((i0>>20)&0x7ff)-0x3ff;
+ if(j0<20) {
+ if(j0<0) { /* raise inexact if x != 0 */
+ if(huge+x>0.0) {/* return 0*sign(x) if |x|<1 */
+ if(i0<0) {i0=0x80000000;i1=0;}
+ else if((i0|i1)!=0) { i0=0x3ff00000;i1=0;}
+ }
+ } else {
+ i = (0x000fffff)>>j0;
+ if(((i0&i)|i1)==0) return x; /* x is integral */
+ if(huge+x>0.0) { /* raise inexact flag */
+ if(i0>0) i0 += (0x00100000)>>j0;
+ i0 &= (~i); i1=0;
+ }
+ }
+ } else if (j0>51) {
+ if(j0==0x400) return x+x; /* inf or NaN */
+ else return x; /* x is integral */
+ } else {
+ i = ((u_int32_t)(0xffffffff))>>(j0-20);
+ if((i1&i)==0) return x; /* x is integral */
+ if(huge+x>0.0) { /* raise inexact flag */
+ if(i0>0) {
+ if(j0==20) i0+=1;
+ else {
+ j = i1 + (1<<(52-j0));
+ if(j<i1) i0+=1; /* got a carry */
+ i1 = j;
+ }
+ }
+ i1 &= (~i);
+ }
+ }
+ INSERT_WORDS(x,i0,i1);
+ return x;
+}
diff --git a/lib/msun/src/s_ceilf.c b/lib/msun/src/s_ceilf.c
new file mode 100644
index 0000000..96a0f48
--- /dev/null
+++ b/lib/msun/src/s_ceilf.c
@@ -0,0 +1,53 @@
+/* s_ceilf.c -- float version of s_ceil.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+#include "math.h"
+#include "math_private.h"
+
+static const float huge = 1.0e30;
+
+float
+ceilf(float x)
+{
+ int32_t i0,j0;
+ u_int32_t i;
+
+ GET_FLOAT_WORD(i0,x);
+ j0 = ((i0>>23)&0xff)-0x7f;
+ if(j0<23) {
+ if(j0<0) { /* raise inexact if x != 0 */
+ if(huge+x>(float)0.0) {/* return 0*sign(x) if |x|<1 */
+ if(i0<0) {i0=0x80000000;}
+ else if(i0!=0) { i0=0x3f800000;}
+ }
+ } else {
+ i = (0x007fffff)>>j0;
+ if((i0&i)==0) return x; /* x is integral */
+ if(huge+x>(float)0.0) { /* raise inexact flag */
+ if(i0>0) i0 += (0x00800000)>>j0;
+ i0 &= (~i);
+ }
+ }
+ } else {
+ if(j0==0x80) return x+x; /* inf or NaN */
+ else return x; /* x is integral */
+ }
+ SET_FLOAT_WORD(x,i0);
+ return x;
+}
diff --git a/lib/msun/src/s_ceill.c b/lib/msun/src/s_ceill.c
new file mode 100644
index 0000000..1de973b
--- /dev/null
+++ b/lib/msun/src/s_ceill.c
@@ -0,0 +1,102 @@
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ *
+ * From: @(#)s_ceil.c 5.1 93/09/24
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/*
+ * ceill(x)
+ * Return x rounded toward -inf to integral value
+ * Method:
+ * Bit twiddling.
+ * Exception:
+ * Inexact flag raised if x not equal to ceill(x).
+ */
+
+#include <float.h>
+#include <math.h>
+#include <stdint.h>
+
+#include "fpmath.h"
+
+#ifdef LDBL_IMPLICIT_NBIT
+#define MANH_SIZE (LDBL_MANH_SIZE + 1)
+#define INC_MANH(u, c) do { \
+ uint64_t o = u.bits.manh; \
+ u.bits.manh += (c); \
+ if (u.bits.manh < o) \
+ u.bits.exp++; \
+} while (0)
+#else
+#define MANH_SIZE LDBL_MANH_SIZE
+#define INC_MANH(u, c) do { \
+ uint64_t o = u.bits.manh; \
+ u.bits.manh += (c); \
+ if (u.bits.manh < o) { \
+ u.bits.exp++; \
+ u.bits.manh |= 1llu << (LDBL_MANH_SIZE - 1); \
+ } \
+} while (0)
+#endif
+
+static const long double huge = 1.0e300;
+
+long double
+ceill(long double x)
+{
+ union IEEEl2bits u = { .e = x };
+ int e = u.bits.exp - LDBL_MAX_EXP + 1;
+
+ if (e < MANH_SIZE - 1) {
+ if (e < 0) { /* raise inexact if x != 0 */
+ if (huge + x > 0.0)
+ if (u.bits.exp > 0 ||
+ (u.bits.manh | u.bits.manl) != 0)
+ u.e = u.bits.sign ? 0.0 : 1.0;
+ } else {
+ uint64_t m = ((1llu << MANH_SIZE) - 1) >> (e + 1);
+ if (((u.bits.manh & m) | u.bits.manl) == 0)
+ return (x); /* x is integral */
+ if (!u.bits.sign) {
+#ifdef LDBL_IMPLICIT_NBIT
+ if (e == 0)
+ u.bits.exp++;
+ else
+#endif
+ INC_MANH(u, 1llu << (MANH_SIZE - e - 1));
+ }
+ if (huge + x > 0.0) { /* raise inexact flag */
+ u.bits.manh &= ~m;
+ u.bits.manl = 0;
+ }
+ }
+ } else if (e < LDBL_MANT_DIG - 1) {
+ uint64_t m = (uint64_t)-1 >> (64 - LDBL_MANT_DIG + e + 1);
+ if ((u.bits.manl & m) == 0)
+ return (x); /* x is integral */
+ if (!u.bits.sign) {
+ if (e == MANH_SIZE - 1)
+ INC_MANH(u, 1);
+ else {
+ uint64_t o = u.bits.manl;
+ u.bits.manl += 1llu << (LDBL_MANT_DIG - e - 1);
+ if (u.bits.manl < o) /* got a carry */
+ INC_MANH(u, 1);
+ }
+ }
+ if (huge + x > 0.0) /* raise inexact flag */
+ u.bits.manl &= ~m;
+ }
+ return (u.e);
+}
diff --git a/lib/msun/src/s_cimag.c b/lib/msun/src/s_cimag.c
new file mode 100644
index 0000000..03ddf79
--- /dev/null
+++ b/lib/msun/src/s_cimag.c
@@ -0,0 +1,35 @@
+/*-
+ * Copyright (c) 2004 Stefan Farfeleder
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, 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$
+ */
+
+#include <complex.h>
+
+double
+cimag(double complex z)
+{
+ return -z * I;
+}
diff --git a/lib/msun/src/s_cimagf.c b/lib/msun/src/s_cimagf.c
new file mode 100644
index 0000000..6f943d8
--- /dev/null
+++ b/lib/msun/src/s_cimagf.c
@@ -0,0 +1,35 @@
+/*-
+ * Copyright (c) 2004 Stefan Farfeleder
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, 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$
+ */
+
+#include <complex.h>
+
+float
+cimagf(float complex z)
+{
+ return -z * I;
+}
diff --git a/lib/msun/src/s_cimagl.c b/lib/msun/src/s_cimagl.c
new file mode 100644
index 0000000..7f531d0
--- /dev/null
+++ b/lib/msun/src/s_cimagl.c
@@ -0,0 +1,35 @@
+/*-
+ * Copyright (c) 2004 Stefan Farfeleder
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, 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$
+ */
+
+#include <complex.h>
+
+long double
+cimagl(long double complex z)
+{
+ return -z * I;
+}
diff --git a/lib/msun/src/s_conj.c b/lib/msun/src/s_conj.c
new file mode 100644
index 0000000..1d0011b
--- /dev/null
+++ b/lib/msun/src/s_conj.c
@@ -0,0 +1,35 @@
+/*-
+ * Copyright (c) 2004 Stefan Farfeleder
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, 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$
+ */
+
+#include <complex.h>
+
+double complex
+conj(double complex z)
+{
+ return creal(z) - I * cimag(z);
+}
diff --git a/lib/msun/src/s_conjf.c b/lib/msun/src/s_conjf.c
new file mode 100644
index 0000000..ea951b9
--- /dev/null
+++ b/lib/msun/src/s_conjf.c
@@ -0,0 +1,35 @@
+/*-
+ * Copyright (c) 2004 Stefan Farfeleder
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, 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$
+ */
+
+#include <complex.h>
+
+float complex
+conjf(float complex z)
+{
+ return crealf(z) - I * cimagf(z);
+}
diff --git a/lib/msun/src/s_conjl.c b/lib/msun/src/s_conjl.c
new file mode 100644
index 0000000..e6cb2ef
--- /dev/null
+++ b/lib/msun/src/s_conjl.c
@@ -0,0 +1,35 @@
+/*-
+ * Copyright (c) 2004 Stefan Farfeleder
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, 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$
+ */
+
+#include <complex.h>
+
+long double complex
+conjl(long double complex z)
+{
+ return creall(z) - I * cimagl(z);
+}
diff --git a/lib/msun/src/s_copysign.c b/lib/msun/src/s_copysign.c
new file mode 100644
index 0000000..7b0fc38
--- /dev/null
+++ b/lib/msun/src/s_copysign.c
@@ -0,0 +1,34 @@
+/* @(#)s_copysign.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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/*
+ * copysign(double x, double y)
+ * copysign(x,y) returns a value with the magnitude of x and
+ * with the sign bit of y.
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+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;
+}
diff --git a/lib/msun/src/s_copysignf.c b/lib/msun/src/s_copysignf.c
new file mode 100644
index 0000000..df5304f
--- /dev/null
+++ b/lib/msun/src/s_copysignf.c
@@ -0,0 +1,37 @@
+/* s_copysignf.c -- float version of s_copysign.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/*
+ * copysignf(float x, float y)
+ * copysignf(x,y) returns a value with the magnitude of x and
+ * with the sign bit of y.
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+float
+copysignf(float x, float y)
+{
+ u_int32_t ix,iy;
+ GET_FLOAT_WORD(ix,x);
+ GET_FLOAT_WORD(iy,y);
+ SET_FLOAT_WORD(x,(ix&0x7fffffff)|(iy&0x80000000));
+ return x;
+}
diff --git a/lib/msun/src/s_copysignl.c b/lib/msun/src/s_copysignl.c
new file mode 100644
index 0000000..8d39f84
--- /dev/null
+++ b/lib/msun/src/s_copysignl.c
@@ -0,0 +1,42 @@
+/*-
+ * Copyright (c) 2004 Stefan Farfeleder
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, 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$
+ */
+
+#include <math.h>
+
+#include "fpmath.h"
+
+long double
+copysignl(long double x, long double y)
+{
+ union IEEEl2bits ux, uy;
+
+ ux.e = x;
+ uy.e = y;
+ ux.bits.sign = uy.bits.sign;
+ return (ux.e);
+}
diff --git a/lib/msun/src/s_cos.c b/lib/msun/src/s_cos.c
new file mode 100644
index 0000000..17afa34
--- /dev/null
+++ b/lib/msun/src/s_cos.c
@@ -0,0 +1,82 @@
+/* @(#)s_cos.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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/* cos(x)
+ * Return cosine function of x.
+ *
+ * kernel function:
+ * __kernel_sin ... sine function on [-pi/4,pi/4]
+ * __kernel_cos ... cosine function on [-pi/4,pi/4]
+ * __ieee754_rem_pio2 ... argument reduction routine
+ *
+ * Method.
+ * Let S,C and T denote the sin, cos and tan respectively on
+ * [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2
+ * in [-pi/4 , +pi/4], and let n = k mod 4.
+ * We have
+ *
+ * n sin(x) cos(x) tan(x)
+ * ----------------------------------------------------------
+ * 0 S C T
+ * 1 C -S -1/T
+ * 2 -S -C T
+ * 3 -C S -1/T
+ * ----------------------------------------------------------
+ *
+ * Special cases:
+ * Let trig be any of sin, cos, or tan.
+ * trig(+-INF) is NaN, with signals;
+ * trig(NaN) is that NaN;
+ *
+ * Accuracy:
+ * TRIG(x) returns trig(x) nearly rounded
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+double
+cos(double x)
+{
+ double y[2],z=0.0;
+ int32_t n, ix;
+
+ /* High word of x. */
+ GET_HIGH_WORD(ix,x);
+
+ /* |x| ~< pi/4 */
+ ix &= 0x7fffffff;
+ if(ix <= 0x3fe921fb) {
+ if(ix<0x3e400000) /* if x < 2**-27 */
+ if(((int)x)==0) return 1.0; /* generate inexact */
+ return __kernel_cos(x,z);
+ }
+
+ /* cos(Inf or NaN) is NaN */
+ else if (ix>=0x7ff00000) return x-x;
+
+ /* argument reduction needed */
+ else {
+ n = __ieee754_rem_pio2(x,y);
+ switch(n&3) {
+ case 0: return __kernel_cos(y[0],y[1]);
+ case 1: return -__kernel_sin(y[0],y[1],1);
+ case 2: return -__kernel_cos(y[0],y[1]);
+ default:
+ return __kernel_sin(y[0],y[1],1);
+ }
+ }
+}
diff --git a/lib/msun/src/s_cosf.c b/lib/msun/src/s_cosf.c
new file mode 100644
index 0000000..b800a8e
--- /dev/null
+++ b/lib/msun/src/s_cosf.c
@@ -0,0 +1,84 @@
+/* s_cosf.c -- float version of s_cos.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ * Optimized by Bruce D. Evans.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+#include "math.h"
+#define INLINE_KERNEL_COSDF
+#define INLINE_KERNEL_SINDF
+#include "math_private.h"
+#include "k_cosf.c"
+#include "k_sinf.c"
+
+/* Small multiples of pi/2 rounded to double precision. */
+static const double
+c1pio2 = 1*M_PI_2, /* 0x3FF921FB, 0x54442D18 */
+c2pio2 = 2*M_PI_2, /* 0x400921FB, 0x54442D18 */
+c3pio2 = 3*M_PI_2, /* 0x4012D97C, 0x7F3321D2 */
+c4pio2 = 4*M_PI_2; /* 0x401921FB, 0x54442D18 */
+
+float
+cosf(float x)
+{
+ float y[2];
+ int32_t n, hx, ix;
+
+ GET_FLOAT_WORD(hx,x);
+ ix = hx & 0x7fffffff;
+
+ if(ix <= 0x3f490fda) { /* |x| ~<= pi/4 */
+ if(ix<0x39800000) /* |x| < 2**-12 */
+ if(((int)x)==0) return 1.0; /* 1 with inexact if x != 0 */
+ return __kernel_cosdf(x);
+ }
+ if(ix<=0x407b53d1) { /* |x| ~<= 5*pi/4 */
+ if(ix>0x4016cbe3) /* |x| ~> 3*pi/4 */
+ return -__kernel_cosdf(x + (hx > 0 ? -c2pio2 : c2pio2));
+ else {
+ if(hx>0)
+ return __kernel_sindf(c1pio2 - x);
+ else
+ return __kernel_sindf(x + c1pio2);
+ }
+ }
+ if(ix<=0x40e231d5) { /* |x| ~<= 9*pi/4 */
+ if(ix>0x40afeddf) /* |x| ~> 7*pi/4 */
+ return __kernel_cosdf(x + (hx > 0 ? -c4pio2 : c4pio2));
+ else {
+ if(hx>0)
+ return __kernel_sindf(x - c3pio2);
+ else
+ return __kernel_sindf(-c3pio2 - x);
+ }
+ }
+
+ /* cos(Inf or NaN) is NaN */
+ else if (ix>=0x7f800000) return x-x;
+
+ /* general argument reduction needed */
+ else {
+ n = __ieee754_rem_pio2f(x,y);
+ switch(n&3) {
+ case 0: return __kernel_cosdf((double)y[0]+y[1]);
+ case 1: return __kernel_sindf(-(double)y[0]-y[1]);
+ case 2: return -__kernel_cosdf((double)y[0]+y[1]);
+ default:
+ return __kernel_sindf((double)y[0]+y[1]);
+ }
+ }
+}
diff --git a/lib/msun/src/s_creal.c b/lib/msun/src/s_creal.c
new file mode 100644
index 0000000..3295ff2
--- /dev/null
+++ b/lib/msun/src/s_creal.c
@@ -0,0 +1,35 @@
+/*-
+ * Copyright (c) 2004 Stefan Farfeleder
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, 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$
+ */
+
+#include <complex.h>
+
+double
+creal(double complex z)
+{
+ return z;
+}
diff --git a/lib/msun/src/s_crealf.c b/lib/msun/src/s_crealf.c
new file mode 100644
index 0000000..5819b86
--- /dev/null
+++ b/lib/msun/src/s_crealf.c
@@ -0,0 +1,35 @@
+/*-
+ * Copyright (c) 2004 Stefan Farfeleder
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, 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$
+ */
+
+#include <complex.h>
+
+float
+crealf(float complex z)
+{
+ return z;
+}
diff --git a/lib/msun/src/s_creall.c b/lib/msun/src/s_creall.c
new file mode 100644
index 0000000..e4946f9
--- /dev/null
+++ b/lib/msun/src/s_creall.c
@@ -0,0 +1,35 @@
+/*-
+ * Copyright (c) 2004 Stefan Farfeleder
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, 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$
+ */
+
+#include <complex.h>
+
+long double
+creall(long double complex z)
+{
+ return z;
+}
diff --git a/lib/msun/src/s_erf.c b/lib/msun/src/s_erf.c
new file mode 100644
index 0000000..8461425
--- /dev/null
+++ b/lib/msun/src/s_erf.c
@@ -0,0 +1,302 @@
+/* @(#)s_erf.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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/* double erf(double x)
+ * double erfc(double x)
+ * x
+ * 2 |\
+ * erf(x) = --------- | exp(-t*t)dt
+ * sqrt(pi) \|
+ * 0
+ *
+ * erfc(x) = 1-erf(x)
+ * Note that
+ * erf(-x) = -erf(x)
+ * erfc(-x) = 2 - erfc(x)
+ *
+ * Method:
+ * 1. For |x| in [0, 0.84375]
+ * erf(x) = x + x*R(x^2)
+ * erfc(x) = 1 - erf(x) if x in [-.84375,0.25]
+ * = 0.5 + ((0.5-x)-x*R) if x in [0.25,0.84375]
+ * where R = P/Q where P is an odd poly of degree 8 and
+ * Q is an odd poly of degree 10.
+ * -57.90
+ * | R - (erf(x)-x)/x | <= 2
+ *
+ *
+ * Remark. The formula is derived by noting
+ * erf(x) = (2/sqrt(pi))*(x - x^3/3 + x^5/10 - x^7/42 + ....)
+ * and that
+ * 2/sqrt(pi) = 1.128379167095512573896158903121545171688
+ * is close to one. The interval is chosen because the fix
+ * point of erf(x) is near 0.6174 (i.e., erf(x)=x when x is
+ * near 0.6174), and by some experiment, 0.84375 is chosen to
+ * guarantee the error is less than one ulp for erf.
+ *
+ * 2. For |x| in [0.84375,1.25], let s = |x| - 1, and
+ * c = 0.84506291151 rounded to single (24 bits)
+ * erf(x) = sign(x) * (c + P1(s)/Q1(s))
+ * erfc(x) = (1-c) - P1(s)/Q1(s) if x > 0
+ * 1+(c+P1(s)/Q1(s)) if x < 0
+ * |P1/Q1 - (erf(|x|)-c)| <= 2**-59.06
+ * Remark: here we use the taylor series expansion at x=1.
+ * erf(1+s) = erf(1) + s*Poly(s)
+ * = 0.845.. + P1(s)/Q1(s)
+ * That is, we use rational approximation to approximate
+ * erf(1+s) - (c = (single)0.84506291151)
+ * Note that |P1/Q1|< 0.078 for x in [0.84375,1.25]
+ * where
+ * P1(s) = degree 6 poly in s
+ * Q1(s) = degree 6 poly in s
+ *
+ * 3. For x in [1.25,1/0.35(~2.857143)],
+ * erfc(x) = (1/x)*exp(-x*x-0.5625+R1/S1)
+ * erf(x) = 1 - erfc(x)
+ * where
+ * R1(z) = degree 7 poly in z, (z=1/x^2)
+ * S1(z) = degree 8 poly in z
+ *
+ * 4. For x in [1/0.35,28]
+ * erfc(x) = (1/x)*exp(-x*x-0.5625+R2/S2) if x > 0
+ * = 2.0 - (1/x)*exp(-x*x-0.5625+R2/S2) if -6<x<0
+ * = 2.0 - tiny (if x <= -6)
+ * erf(x) = sign(x)*(1.0 - erfc(x)) if x < 6, else
+ * erf(x) = sign(x)*(1.0 - tiny)
+ * where
+ * R2(z) = degree 6 poly in z, (z=1/x^2)
+ * S2(z) = degree 7 poly in z
+ *
+ * Note1:
+ * To compute exp(-x*x-0.5625+R/S), let s be a single
+ * precision number and s := x; then
+ * -x*x = -s*s + (s-x)*(s+x)
+ * exp(-x*x-0.5626+R/S) =
+ * exp(-s*s-0.5625)*exp((s-x)*(s+x)+R/S);
+ * Note2:
+ * Here 4 and 5 make use of the asymptotic series
+ * exp(-x*x)
+ * erfc(x) ~ ---------- * ( 1 + Poly(1/x^2) )
+ * x*sqrt(pi)
+ * We use rational approximation to approximate
+ * g(s)=f(1/x^2) = log(erfc(x)*x) - x*x + 0.5625
+ * Here is the error bound for R1/S1 and R2/S2
+ * |R1/S1 - f(x)| < 2**(-62.57)
+ * |R2/S2 - f(x)| < 2**(-61.52)
+ *
+ * 5. For inf > x >= 28
+ * erf(x) = sign(x) *(1 - tiny) (raise inexact)
+ * erfc(x) = tiny*tiny (raise underflow) if x > 0
+ * = 2 - tiny if x<0
+ *
+ * 7. Special case:
+ * erf(0) = 0, erf(inf) = 1, erf(-inf) = -1,
+ * erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2,
+ * erfc/erf(NaN) is NaN
+ */
+
+
+#include "math.h"
+#include "math_private.h"
+
+static const double
+tiny = 1e-300,
+half= 5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */
+one = 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+two = 2.00000000000000000000e+00, /* 0x40000000, 0x00000000 */
+ /* c = (float)0.84506291151 */
+erx = 8.45062911510467529297e-01, /* 0x3FEB0AC1, 0x60000000 */
+/*
+ * Coefficients for approximation to erf on [0,0.84375]
+ */
+efx = 1.28379167095512586316e-01, /* 0x3FC06EBA, 0x8214DB69 */
+efx8= 1.02703333676410069053e+00, /* 0x3FF06EBA, 0x8214DB69 */
+pp0 = 1.28379167095512558561e-01, /* 0x3FC06EBA, 0x8214DB68 */
+pp1 = -3.25042107247001499370e-01, /* 0xBFD4CD7D, 0x691CB913 */
+pp2 = -2.84817495755985104766e-02, /* 0xBF9D2A51, 0xDBD7194F */
+pp3 = -5.77027029648944159157e-03, /* 0xBF77A291, 0x236668E4 */
+pp4 = -2.37630166566501626084e-05, /* 0xBEF8EAD6, 0x120016AC */
+qq1 = 3.97917223959155352819e-01, /* 0x3FD97779, 0xCDDADC09 */
+qq2 = 6.50222499887672944485e-02, /* 0x3FB0A54C, 0x5536CEBA */
+qq3 = 5.08130628187576562776e-03, /* 0x3F74D022, 0xC4D36B0F */
+qq4 = 1.32494738004321644526e-04, /* 0x3F215DC9, 0x221C1A10 */
+qq5 = -3.96022827877536812320e-06, /* 0xBED09C43, 0x42A26120 */
+/*
+ * Coefficients for approximation to erf in [0.84375,1.25]
+ */
+pa0 = -2.36211856075265944077e-03, /* 0xBF6359B8, 0xBEF77538 */
+pa1 = 4.14856118683748331666e-01, /* 0x3FDA8D00, 0xAD92B34D */
+pa2 = -3.72207876035701323847e-01, /* 0xBFD7D240, 0xFBB8C3F1 */
+pa3 = 3.18346619901161753674e-01, /* 0x3FD45FCA, 0x805120E4 */
+pa4 = -1.10894694282396677476e-01, /* 0xBFBC6398, 0x3D3E28EC */
+pa5 = 3.54783043256182359371e-02, /* 0x3FA22A36, 0x599795EB */
+pa6 = -2.16637559486879084300e-03, /* 0xBF61BF38, 0x0A96073F */
+qa1 = 1.06420880400844228286e-01, /* 0x3FBB3E66, 0x18EEE323 */
+qa2 = 5.40397917702171048937e-01, /* 0x3FE14AF0, 0x92EB6F33 */
+qa3 = 7.18286544141962662868e-02, /* 0x3FB2635C, 0xD99FE9A7 */
+qa4 = 1.26171219808761642112e-01, /* 0x3FC02660, 0xE763351F */
+qa5 = 1.36370839120290507362e-02, /* 0x3F8BEDC2, 0x6B51DD1C */
+qa6 = 1.19844998467991074170e-02, /* 0x3F888B54, 0x5735151D */
+/*
+ * Coefficients for approximation to erfc in [1.25,1/0.35]
+ */
+ra0 = -9.86494403484714822705e-03, /* 0xBF843412, 0x600D6435 */
+ra1 = -6.93858572707181764372e-01, /* 0xBFE63416, 0xE4BA7360 */
+ra2 = -1.05586262253232909814e+01, /* 0xC0251E04, 0x41B0E726 */
+ra3 = -6.23753324503260060396e+01, /* 0xC04F300A, 0xE4CBA38D */
+ra4 = -1.62396669462573470355e+02, /* 0xC0644CB1, 0x84282266 */
+ra5 = -1.84605092906711035994e+02, /* 0xC067135C, 0xEBCCABB2 */
+ra6 = -8.12874355063065934246e+01, /* 0xC0545265, 0x57E4D2F2 */
+ra7 = -9.81432934416914548592e+00, /* 0xC023A0EF, 0xC69AC25C */
+sa1 = 1.96512716674392571292e+01, /* 0x4033A6B9, 0xBD707687 */
+sa2 = 1.37657754143519042600e+02, /* 0x4061350C, 0x526AE721 */
+sa3 = 4.34565877475229228821e+02, /* 0x407B290D, 0xD58A1A71 */
+sa4 = 6.45387271733267880336e+02, /* 0x40842B19, 0x21EC2868 */
+sa5 = 4.29008140027567833386e+02, /* 0x407AD021, 0x57700314 */
+sa6 = 1.08635005541779435134e+02, /* 0x405B28A3, 0xEE48AE2C */
+sa7 = 6.57024977031928170135e+00, /* 0x401A47EF, 0x8E484A93 */
+sa8 = -6.04244152148580987438e-02, /* 0xBFAEEFF2, 0xEE749A62 */
+/*
+ * Coefficients for approximation to erfc in [1/.35,28]
+ */
+rb0 = -9.86494292470009928597e-03, /* 0xBF843412, 0x39E86F4A */
+rb1 = -7.99283237680523006574e-01, /* 0xBFE993BA, 0x70C285DE */
+rb2 = -1.77579549177547519889e+01, /* 0xC031C209, 0x555F995A */
+rb3 = -1.60636384855821916062e+02, /* 0xC064145D, 0x43C5ED98 */
+rb4 = -6.37566443368389627722e+02, /* 0xC083EC88, 0x1375F228 */
+rb5 = -1.02509513161107724954e+03, /* 0xC0900461, 0x6A2E5992 */
+rb6 = -4.83519191608651397019e+02, /* 0xC07E384E, 0x9BDC383F */
+sb1 = 3.03380607434824582924e+01, /* 0x403E568B, 0x261D5190 */
+sb2 = 3.25792512996573918826e+02, /* 0x40745CAE, 0x221B9F0A */
+sb3 = 1.53672958608443695994e+03, /* 0x409802EB, 0x189D5118 */
+sb4 = 3.19985821950859553908e+03, /* 0x40A8FFB7, 0x688C246A */
+sb5 = 2.55305040643316442583e+03, /* 0x40A3F219, 0xCEDF3BE6 */
+sb6 = 4.74528541206955367215e+02, /* 0x407DA874, 0xE79FE763 */
+sb7 = -2.24409524465858183362e+01; /* 0xC03670E2, 0x42712D62 */
+
+double
+erf(double x)
+{
+ int32_t hx,ix,i;
+ double R,S,P,Q,s,y,z,r;
+ GET_HIGH_WORD(hx,x);
+ ix = hx&0x7fffffff;
+ if(ix>=0x7ff00000) { /* erf(nan)=nan */
+ i = ((u_int32_t)hx>>31)<<1;
+ return (double)(1-i)+one/x; /* erf(+-inf)=+-1 */
+ }
+
+ if(ix < 0x3feb0000) { /* |x|<0.84375 */
+ if(ix < 0x3e300000) { /* |x|<2**-28 */
+ if (ix < 0x00800000)
+ return 0.125*(8.0*x+efx8*x); /*avoid underflow */
+ return x + efx*x;
+ }
+ z = x*x;
+ r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4)));
+ s = one+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5))));
+ y = r/s;
+ return x + x*y;
+ }
+ if(ix < 0x3ff40000) { /* 0.84375 <= |x| < 1.25 */
+ s = fabs(x)-one;
+ P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6)))));
+ Q = one+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6)))));
+ if(hx>=0) return erx + P/Q; else return -erx - P/Q;
+ }
+ if (ix >= 0x40180000) { /* inf>|x|>=6 */
+ if(hx>=0) return one-tiny; else return tiny-one;
+ }
+ x = fabs(x);
+ s = one/(x*x);
+ if(ix< 0x4006DB6E) { /* |x| < 1/0.35 */
+ R=ra0+s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*(
+ ra5+s*(ra6+s*ra7))))));
+ S=one+s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*(
+ sa5+s*(sa6+s*(sa7+s*sa8)))))));
+ } else { /* |x| >= 1/0.35 */
+ R=rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*(
+ rb5+s*rb6)))));
+ S=one+s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*(
+ sb5+s*(sb6+s*sb7))))));
+ }
+ z = x;
+ SET_LOW_WORD(z,0);
+ r = __ieee754_exp(-z*z-0.5625)*__ieee754_exp((z-x)*(z+x)+R/S);
+ if(hx>=0) return one-r/x; else return r/x-one;
+}
+
+double
+erfc(double x)
+{
+ int32_t hx,ix;
+ double R,S,P,Q,s,y,z,r;
+ GET_HIGH_WORD(hx,x);
+ ix = hx&0x7fffffff;
+ if(ix>=0x7ff00000) { /* erfc(nan)=nan */
+ /* erfc(+-inf)=0,2 */
+ return (double)(((u_int32_t)hx>>31)<<1)+one/x;
+ }
+
+ if(ix < 0x3feb0000) { /* |x|<0.84375 */
+ if(ix < 0x3c700000) /* |x|<2**-56 */
+ return one-x;
+ z = x*x;
+ r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4)));
+ s = one+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5))));
+ y = r/s;
+ if(hx < 0x3fd00000) { /* x<1/4 */
+ return one-(x+x*y);
+ } else {
+ r = x*y;
+ r += (x-half);
+ return half - r ;
+ }
+ }
+ if(ix < 0x3ff40000) { /* 0.84375 <= |x| < 1.25 */
+ s = fabs(x)-one;
+ P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6)))));
+ Q = one+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6)))));
+ if(hx>=0) {
+ z = one-erx; return z - P/Q;
+ } else {
+ z = erx+P/Q; return one+z;
+ }
+ }
+ if (ix < 0x403c0000) { /* |x|<28 */
+ x = fabs(x);
+ s = one/(x*x);
+ if(ix< 0x4006DB6D) { /* |x| < 1/.35 ~ 2.857143*/
+ R=ra0+s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*(
+ ra5+s*(ra6+s*ra7))))));
+ S=one+s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*(
+ sa5+s*(sa6+s*(sa7+s*sa8)))))));
+ } else { /* |x| >= 1/.35 ~ 2.857143 */
+ if(hx<0&&ix>=0x40180000) return two-tiny;/* x < -6 */
+ R=rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*(
+ rb5+s*rb6)))));
+ S=one+s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*(
+ sb5+s*(sb6+s*sb7))))));
+ }
+ z = x;
+ SET_LOW_WORD(z,0);
+ r = __ieee754_exp(-z*z-0.5625)*
+ __ieee754_exp((z-x)*(z+x)+R/S);
+ if(hx>0) return r/x; else return two-r/x;
+ } else {
+ if(hx>0) return tiny*tiny; else return two-tiny;
+ }
+}
diff --git a/lib/msun/src/s_erff.c b/lib/msun/src/s_erff.c
new file mode 100644
index 0000000..6bb24cf
--- /dev/null
+++ b/lib/msun/src/s_erff.c
@@ -0,0 +1,211 @@
+/* s_erff.c -- float version of s_erf.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+#include "math.h"
+#include "math_private.h"
+
+static const float
+tiny = 1e-30,
+half= 5.0000000000e-01, /* 0x3F000000 */
+one = 1.0000000000e+00, /* 0x3F800000 */
+two = 2.0000000000e+00, /* 0x40000000 */
+ /* c = (subfloat)0.84506291151 */
+erx = 8.4506291151e-01, /* 0x3f58560b */
+/*
+ * Coefficients for approximation to erf on [0,0.84375]
+ */
+efx = 1.2837916613e-01, /* 0x3e0375d4 */
+efx8= 1.0270333290e+00, /* 0x3f8375d4 */
+pp0 = 1.2837916613e-01, /* 0x3e0375d4 */
+pp1 = -3.2504209876e-01, /* 0xbea66beb */
+pp2 = -2.8481749818e-02, /* 0xbce9528f */
+pp3 = -5.7702702470e-03, /* 0xbbbd1489 */
+pp4 = -2.3763017452e-05, /* 0xb7c756b1 */
+qq1 = 3.9791721106e-01, /* 0x3ecbbbce */
+qq2 = 6.5022252500e-02, /* 0x3d852a63 */
+qq3 = 5.0813062117e-03, /* 0x3ba68116 */
+qq4 = 1.3249473704e-04, /* 0x390aee49 */
+qq5 = -3.9602282413e-06, /* 0xb684e21a */
+/*
+ * Coefficients for approximation to erf in [0.84375,1.25]
+ */
+pa0 = -2.3621185683e-03, /* 0xbb1acdc6 */
+pa1 = 4.1485610604e-01, /* 0x3ed46805 */
+pa2 = -3.7220788002e-01, /* 0xbebe9208 */
+pa3 = 3.1834661961e-01, /* 0x3ea2fe54 */
+pa4 = -1.1089469492e-01, /* 0xbde31cc2 */
+pa5 = 3.5478305072e-02, /* 0x3d1151b3 */
+pa6 = -2.1663755178e-03, /* 0xbb0df9c0 */
+qa1 = 1.0642088205e-01, /* 0x3dd9f331 */
+qa2 = 5.4039794207e-01, /* 0x3f0a5785 */
+qa3 = 7.1828655899e-02, /* 0x3d931ae7 */
+qa4 = 1.2617121637e-01, /* 0x3e013307 */
+qa5 = 1.3637083583e-02, /* 0x3c5f6e13 */
+qa6 = 1.1984500103e-02, /* 0x3c445aa3 */
+/*
+ * Coefficients for approximation to erfc in [1.25,1/0.35]
+ */
+ra0 = -9.8649440333e-03, /* 0xbc21a093 */
+ra1 = -6.9385856390e-01, /* 0xbf31a0b7 */
+ra2 = -1.0558626175e+01, /* 0xc128f022 */
+ra3 = -6.2375331879e+01, /* 0xc2798057 */
+ra4 = -1.6239666748e+02, /* 0xc322658c */
+ra5 = -1.8460508728e+02, /* 0xc3389ae7 */
+ra6 = -8.1287437439e+01, /* 0xc2a2932b */
+ra7 = -9.8143291473e+00, /* 0xc11d077e */
+sa1 = 1.9651271820e+01, /* 0x419d35ce */
+sa2 = 1.3765776062e+02, /* 0x4309a863 */
+sa3 = 4.3456588745e+02, /* 0x43d9486f */
+sa4 = 6.4538726807e+02, /* 0x442158c9 */
+sa5 = 4.2900814819e+02, /* 0x43d6810b */
+sa6 = 1.0863500214e+02, /* 0x42d9451f */
+sa7 = 6.5702495575e+00, /* 0x40d23f7c */
+sa8 = -6.0424413532e-02, /* 0xbd777f97 */
+/*
+ * Coefficients for approximation to erfc in [1/.35,28]
+ */
+rb0 = -9.8649431020e-03, /* 0xbc21a092 */
+rb1 = -7.9928326607e-01, /* 0xbf4c9dd4 */
+rb2 = -1.7757955551e+01, /* 0xc18e104b */
+rb3 = -1.6063638306e+02, /* 0xc320a2ea */
+rb4 = -6.3756646729e+02, /* 0xc41f6441 */
+rb5 = -1.0250950928e+03, /* 0xc480230b */
+rb6 = -4.8351919556e+02, /* 0xc3f1c275 */
+sb1 = 3.0338060379e+01, /* 0x41f2b459 */
+sb2 = 3.2579251099e+02, /* 0x43a2e571 */
+sb3 = 1.5367296143e+03, /* 0x44c01759 */
+sb4 = 3.1998581543e+03, /* 0x4547fdbb */
+sb5 = 2.5530502930e+03, /* 0x451f90ce */
+sb6 = 4.7452853394e+02, /* 0x43ed43a7 */
+sb7 = -2.2440952301e+01; /* 0xc1b38712 */
+
+float
+erff(float x)
+{
+ int32_t hx,ix,i;
+ float R,S,P,Q,s,y,z,r;
+ GET_FLOAT_WORD(hx,x);
+ ix = hx&0x7fffffff;
+ if(ix>=0x7f800000) { /* erf(nan)=nan */
+ i = ((u_int32_t)hx>>31)<<1;
+ return (float)(1-i)+one/x; /* erf(+-inf)=+-1 */
+ }
+
+ if(ix < 0x3f580000) { /* |x|<0.84375 */
+ if(ix < 0x31800000) { /* |x|<2**-28 */
+ if (ix < 0x04000000)
+ /*avoid underflow */
+ return (float)0.125*((float)8.0*x+efx8*x);
+ return x + efx*x;
+ }
+ z = x*x;
+ r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4)));
+ s = one+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5))));
+ y = r/s;
+ return x + x*y;
+ }
+ if(ix < 0x3fa00000) { /* 0.84375 <= |x| < 1.25 */
+ s = fabsf(x)-one;
+ P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6)))));
+ Q = one+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6)))));
+ if(hx>=0) return erx + P/Q; else return -erx - P/Q;
+ }
+ if (ix >= 0x40c00000) { /* inf>|x|>=6 */
+ if(hx>=0) return one-tiny; else return tiny-one;
+ }
+ x = fabsf(x);
+ s = one/(x*x);
+ if(ix< 0x4036DB6E) { /* |x| < 1/0.35 */
+ R=ra0+s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*(
+ ra5+s*(ra6+s*ra7))))));
+ S=one+s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*(
+ sa5+s*(sa6+s*(sa7+s*sa8)))))));
+ } else { /* |x| >= 1/0.35 */
+ R=rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*(
+ rb5+s*rb6)))));
+ S=one+s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*(
+ sb5+s*(sb6+s*sb7))))));
+ }
+ GET_FLOAT_WORD(ix,x);
+ SET_FLOAT_WORD(z,ix&0xfffff000);
+ r = __ieee754_expf(-z*z-(float)0.5625)*__ieee754_expf((z-x)*(z+x)+R/S);
+ if(hx>=0) return one-r/x; else return r/x-one;
+}
+
+float
+erfcf(float x)
+{
+ int32_t hx,ix;
+ float R,S,P,Q,s,y,z,r;
+ GET_FLOAT_WORD(hx,x);
+ ix = hx&0x7fffffff;
+ if(ix>=0x7f800000) { /* erfc(nan)=nan */
+ /* erfc(+-inf)=0,2 */
+ return (float)(((u_int32_t)hx>>31)<<1)+one/x;
+ }
+
+ if(ix < 0x3f580000) { /* |x|<0.84375 */
+ if(ix < 0x23800000) /* |x|<2**-56 */
+ return one-x;
+ z = x*x;
+ r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4)));
+ s = one+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5))));
+ y = r/s;
+ if(hx < 0x3e800000) { /* x<1/4 */
+ return one-(x+x*y);
+ } else {
+ r = x*y;
+ r += (x-half);
+ return half - r ;
+ }
+ }
+ if(ix < 0x3fa00000) { /* 0.84375 <= |x| < 1.25 */
+ s = fabsf(x)-one;
+ P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6)))));
+ Q = one+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6)))));
+ if(hx>=0) {
+ z = one-erx; return z - P/Q;
+ } else {
+ z = erx+P/Q; return one+z;
+ }
+ }
+ if (ix < 0x41e00000) { /* |x|<28 */
+ x = fabsf(x);
+ s = one/(x*x);
+ if(ix< 0x4036DB6D) { /* |x| < 1/.35 ~ 2.857143*/
+ R=ra0+s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*(
+ ra5+s*(ra6+s*ra7))))));
+ S=one+s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*(
+ sa5+s*(sa6+s*(sa7+s*sa8)))))));
+ } else { /* |x| >= 1/.35 ~ 2.857143 */
+ if(hx<0&&ix>=0x40c00000) return two-tiny;/* x < -6 */
+ R=rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*(
+ rb5+s*rb6)))));
+ S=one+s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*(
+ sb5+s*(sb6+s*sb7))))));
+ }
+ GET_FLOAT_WORD(ix,x);
+ SET_FLOAT_WORD(z,ix&0xfffff000);
+ r = __ieee754_expf(-z*z-(float)0.5625)*
+ __ieee754_expf((z-x)*(z+x)+R/S);
+ if(hx>0) return r/x; else return two-r/x;
+ } else {
+ if(hx>0) return tiny*tiny; else return two-tiny;
+ }
+}
diff --git a/lib/msun/src/s_exp2.c b/lib/msun/src/s_exp2.c
new file mode 100644
index 0000000..8dce338
--- /dev/null
+++ b/lib/msun/src/s_exp2.c
@@ -0,0 +1,389 @@
+/*-
+ * 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 "math.h"
+#include "math_private.h"
+
+#define TBLBITS 8
+#define TBLSIZE (1 << TBLBITS)
+
+static const double
+ huge = 0x1p1000,
+ twom1000 = 0x1p-1000,
+ redux = 0x1.8p52 / TBLSIZE,
+ P1 = 0x1.62e42fefa39efp-1,
+ P2 = 0x1.ebfbdff82c575p-3,
+ P3 = 0x1.c6b08d704a0a6p-5,
+ P4 = 0x1.3b2ab88f70400p-7,
+ P5 = 0x1.5d88003875c74p-10;
+
+static const double tbl[TBLSIZE * 2] = {
+/* exp2(z + eps) eps */
+ 0x1.6a09e667f3d5dp-1, 0x1.9880p-44,
+ 0x1.6b052fa751744p-1, 0x1.8000p-50,
+ 0x1.6c012750bd9fep-1, -0x1.8780p-45,
+ 0x1.6cfdcddd476bfp-1, 0x1.ec00p-46,
+ 0x1.6dfb23c651a29p-1, -0x1.8000p-50,
+ 0x1.6ef9298593ae3p-1, -0x1.c000p-52,
+ 0x1.6ff7df9519386p-1, -0x1.fd80p-45,
+ 0x1.70f7466f42da3p-1, -0x1.c880p-45,
+ 0x1.71f75e8ec5fc3p-1, 0x1.3c00p-46,
+ 0x1.72f8286eacf05p-1, -0x1.8300p-44,
+ 0x1.73f9a48a58152p-1, -0x1.0c00p-47,
+ 0x1.74fbd35d7ccfcp-1, 0x1.f880p-45,
+ 0x1.75feb564267f1p-1, 0x1.3e00p-47,
+ 0x1.77024b1ab6d48p-1, -0x1.7d00p-45,
+ 0x1.780694fde5d38p-1, -0x1.d000p-50,
+ 0x1.790b938ac1d00p-1, 0x1.3000p-49,
+ 0x1.7a11473eb0178p-1, -0x1.d000p-49,
+ 0x1.7b17b0976d060p-1, 0x1.0400p-45,
+ 0x1.7c1ed0130c133p-1, 0x1.0000p-53,
+ 0x1.7d26a62ff8636p-1, -0x1.6900p-45,
+ 0x1.7e2f336cf4e3bp-1, -0x1.2e00p-47,
+ 0x1.7f3878491c3e8p-1, -0x1.4580p-45,
+ 0x1.80427543e1b4ep-1, 0x1.3000p-44,
+ 0x1.814d2add1071ap-1, 0x1.f000p-47,
+ 0x1.82589994ccd7ep-1, -0x1.1c00p-45,
+ 0x1.8364c1eb942d0p-1, 0x1.9d00p-45,
+ 0x1.8471a4623cab5p-1, 0x1.7100p-43,
+ 0x1.857f4179f5bbcp-1, 0x1.2600p-45,
+ 0x1.868d99b4491afp-1, -0x1.2c40p-44,
+ 0x1.879cad931a395p-1, -0x1.3000p-45,
+ 0x1.88ac7d98a65b8p-1, -0x1.a800p-45,
+ 0x1.89bd0a4785800p-1, -0x1.d000p-49,
+ 0x1.8ace5422aa223p-1, 0x1.3280p-44,
+ 0x1.8be05bad619fap-1, 0x1.2b40p-43,
+ 0x1.8cf3216b54383p-1, -0x1.ed00p-45,
+ 0x1.8e06a5e08664cp-1, -0x1.0500p-45,
+ 0x1.8f1ae99157807p-1, 0x1.8280p-45,
+ 0x1.902fed0282c0ep-1, -0x1.cb00p-46,
+ 0x1.9145b0b91ff96p-1, -0x1.5e00p-47,
+ 0x1.925c353aa2ff9p-1, 0x1.5400p-48,
+ 0x1.93737b0cdc64ap-1, 0x1.7200p-46,
+ 0x1.948b82b5f98aep-1, -0x1.9000p-47,
+ 0x1.95a44cbc852cbp-1, 0x1.5680p-45,
+ 0x1.96bdd9a766f21p-1, -0x1.6d00p-44,
+ 0x1.97d829fde4e2ap-1, -0x1.1000p-47,
+ 0x1.98f33e47a23a3p-1, 0x1.d000p-45,
+ 0x1.9a0f170ca0604p-1, -0x1.8a40p-44,
+ 0x1.9b2bb4d53ff89p-1, 0x1.55c0p-44,
+ 0x1.9c49182a3f15bp-1, 0x1.6b80p-45,
+ 0x1.9d674194bb8c5p-1, -0x1.c000p-49,
+ 0x1.9e86319e3238ep-1, 0x1.7d00p-46,
+ 0x1.9fa5e8d07f302p-1, 0x1.6400p-46,
+ 0x1.a0c667b5de54dp-1, -0x1.5000p-48,
+ 0x1.a1e7aed8eb8f6p-1, 0x1.9e00p-47,
+ 0x1.a309bec4a2e27p-1, 0x1.ad80p-45,
+ 0x1.a42c980460a5dp-1, -0x1.af00p-46,
+ 0x1.a5503b23e259bp-1, 0x1.b600p-47,
+ 0x1.a674a8af46213p-1, 0x1.8880p-44,
+ 0x1.a799e1330b3a7p-1, 0x1.1200p-46,
+ 0x1.a8bfe53c12e8dp-1, 0x1.6c00p-47,
+ 0x1.a9e6b5579fcd2p-1, -0x1.9b80p-45,
+ 0x1.ab0e521356fb8p-1, 0x1.b700p-45,
+ 0x1.ac36bbfd3f381p-1, 0x1.9000p-50,
+ 0x1.ad5ff3a3c2780p-1, 0x1.4000p-49,
+ 0x1.ae89f995ad2a3p-1, -0x1.c900p-45,
+ 0x1.afb4ce622f367p-1, 0x1.6500p-46,
+ 0x1.b0e07298db790p-1, 0x1.fd40p-45,
+ 0x1.b20ce6c9a89a9p-1, 0x1.2700p-46,
+ 0x1.b33a2b84f1a4bp-1, 0x1.d470p-43,
+ 0x1.b468415b747e7p-1, -0x1.8380p-44,
+ 0x1.b59728de5593ap-1, 0x1.8000p-54,
+ 0x1.b6c6e29f1c56ap-1, 0x1.ad00p-47,
+ 0x1.b7f76f2fb5e50p-1, 0x1.e800p-50,
+ 0x1.b928cf22749b2p-1, -0x1.4c00p-47,
+ 0x1.ba5b030a10603p-1, -0x1.d700p-47,
+ 0x1.bb8e0b79a6f66p-1, 0x1.d900p-47,
+ 0x1.bcc1e904bc1ffp-1, 0x1.2a00p-47,
+ 0x1.bdf69c3f3a16fp-1, -0x1.f780p-46,
+ 0x1.bf2c25bd71db8p-1, -0x1.0a00p-46,
+ 0x1.c06286141b2e9p-1, -0x1.1400p-46,
+ 0x1.c199bdd8552e0p-1, 0x1.be00p-47,
+ 0x1.c2d1cd9fa64eep-1, -0x1.9400p-47,
+ 0x1.c40ab5fffd02fp-1, -0x1.ed00p-47,
+ 0x1.c544778fafd15p-1, 0x1.9660p-44,
+ 0x1.c67f12e57d0cbp-1, -0x1.a100p-46,
+ 0x1.c7ba88988c1b6p-1, -0x1.8458p-42,
+ 0x1.c8f6d9406e733p-1, -0x1.a480p-46,
+ 0x1.ca3405751c4dfp-1, 0x1.b000p-51,
+ 0x1.cb720dcef9094p-1, 0x1.1400p-47,
+ 0x1.ccb0f2e6d1689p-1, 0x1.0200p-48,
+ 0x1.cdf0b555dc412p-1, 0x1.3600p-48,
+ 0x1.cf3155b5bab3bp-1, -0x1.6900p-47,
+ 0x1.d072d4a0789bcp-1, 0x1.9a00p-47,
+ 0x1.d1b532b08c8fap-1, -0x1.5e00p-46,
+ 0x1.d2f87080d8a85p-1, 0x1.d280p-46,
+ 0x1.d43c8eacaa203p-1, 0x1.1a00p-47,
+ 0x1.d5818dcfba491p-1, 0x1.f000p-50,
+ 0x1.d6c76e862e6a1p-1, -0x1.3a00p-47,
+ 0x1.d80e316c9834ep-1, -0x1.cd80p-47,
+ 0x1.d955d71ff6090p-1, 0x1.4c00p-48,
+ 0x1.da9e603db32aep-1, 0x1.f900p-48,
+ 0x1.dbe7cd63a8325p-1, 0x1.9800p-49,
+ 0x1.dd321f301b445p-1, -0x1.5200p-48,
+ 0x1.de7d5641c05bfp-1, -0x1.d700p-46,
+ 0x1.dfc97337b9aecp-1, -0x1.6140p-46,
+ 0x1.e11676b197d5ep-1, 0x1.b480p-47,
+ 0x1.e264614f5a3e7p-1, 0x1.0ce0p-43,
+ 0x1.e3b333b16ee5cp-1, 0x1.c680p-47,
+ 0x1.e502ee78b3fb4p-1, -0x1.9300p-47,
+ 0x1.e653924676d68p-1, -0x1.5000p-49,
+ 0x1.e7a51fbc74c44p-1, -0x1.7f80p-47,
+ 0x1.e8f7977cdb726p-1, -0x1.3700p-48,
+ 0x1.ea4afa2a490e8p-1, 0x1.5d00p-49,
+ 0x1.eb9f4867ccae4p-1, 0x1.61a0p-46,
+ 0x1.ecf482d8e680dp-1, 0x1.5500p-48,
+ 0x1.ee4aaa2188514p-1, 0x1.6400p-51,
+ 0x1.efa1bee615a13p-1, -0x1.e800p-49,
+ 0x1.f0f9c1cb64106p-1, -0x1.a880p-48,
+ 0x1.f252b376bb963p-1, -0x1.c900p-45,
+ 0x1.f3ac948dd7275p-1, 0x1.a000p-53,
+ 0x1.f50765b6e4524p-1, -0x1.4f00p-48,
+ 0x1.f6632798844fdp-1, 0x1.a800p-51,
+ 0x1.f7bfdad9cbe38p-1, 0x1.abc0p-48,
+ 0x1.f91d802243c82p-1, -0x1.4600p-50,
+ 0x1.fa7c1819e908ep-1, -0x1.b0c0p-47,
+ 0x1.fbdba3692d511p-1, -0x1.0e00p-51,
+ 0x1.fd3c22b8f7194p-1, -0x1.0de8p-46,
+ 0x1.fe9d96b2a23eep-1, 0x1.e430p-49,
+ 0x1.0000000000000p+0, 0x0.0000p+0,
+ 0x1.00b1afa5abcbep+0, -0x1.3400p-52,
+ 0x1.0163da9fb3303p+0, -0x1.2170p-46,
+ 0x1.02168143b0282p+0, 0x1.a400p-52,
+ 0x1.02c9a3e77806cp+0, 0x1.f980p-49,
+ 0x1.037d42e11bbcap+0, -0x1.7400p-51,
+ 0x1.04315e86e7f89p+0, 0x1.8300p-50,
+ 0x1.04e5f72f65467p+0, -0x1.a3f0p-46,
+ 0x1.059b0d315855ap+0, -0x1.2840p-47,
+ 0x1.0650a0e3c1f95p+0, 0x1.1600p-48,
+ 0x1.0706b29ddf71ap+0, 0x1.5240p-46,
+ 0x1.07bd42b72a82dp+0, -0x1.9a00p-49,
+ 0x1.0874518759bd0p+0, 0x1.6400p-49,
+ 0x1.092bdf66607c8p+0, -0x1.0780p-47,
+ 0x1.09e3ecac6f383p+0, -0x1.8000p-54,
+ 0x1.0a9c79b1f3930p+0, 0x1.fa00p-48,
+ 0x1.0b5586cf988fcp+0, -0x1.ac80p-48,
+ 0x1.0c0f145e46c8ap+0, 0x1.9c00p-50,
+ 0x1.0cc922b724816p+0, 0x1.5200p-47,
+ 0x1.0d83b23395dd8p+0, -0x1.ad00p-48,
+ 0x1.0e3ec32d3d1f3p+0, 0x1.bac0p-46,
+ 0x1.0efa55fdfa9a6p+0, -0x1.4e80p-47,
+ 0x1.0fb66affed2f0p+0, -0x1.d300p-47,
+ 0x1.1073028d7234bp+0, 0x1.1500p-48,
+ 0x1.11301d0125b5bp+0, 0x1.c000p-49,
+ 0x1.11edbab5e2af9p+0, 0x1.6bc0p-46,
+ 0x1.12abdc06c31d5p+0, 0x1.8400p-49,
+ 0x1.136a814f2047dp+0, -0x1.ed00p-47,
+ 0x1.1429aaea92de9p+0, 0x1.8e00p-49,
+ 0x1.14e95934f3138p+0, 0x1.b400p-49,
+ 0x1.15a98c8a58e71p+0, 0x1.5300p-47,
+ 0x1.166a45471c3dfp+0, 0x1.3380p-47,
+ 0x1.172b83c7d5211p+0, 0x1.8d40p-45,
+ 0x1.17ed48695bb9fp+0, -0x1.5d00p-47,
+ 0x1.18af9388c8d93p+0, -0x1.c880p-46,
+ 0x1.1972658375d66p+0, 0x1.1f00p-46,
+ 0x1.1a35beb6fcba7p+0, 0x1.0480p-46,
+ 0x1.1af99f81387e3p+0, -0x1.7390p-43,
+ 0x1.1bbe084045d54p+0, 0x1.4e40p-45,
+ 0x1.1c82f95281c43p+0, -0x1.a200p-47,
+ 0x1.1d4873168b9b2p+0, 0x1.3800p-49,
+ 0x1.1e0e75eb44031p+0, 0x1.ac00p-49,
+ 0x1.1ed5022fcd938p+0, 0x1.1900p-47,
+ 0x1.1f9c18438cdf7p+0, -0x1.b780p-46,
+ 0x1.2063b88628d8fp+0, 0x1.d940p-45,
+ 0x1.212be3578a81ep+0, 0x1.8000p-50,
+ 0x1.21f49917ddd41p+0, 0x1.b340p-45,
+ 0x1.22bdda2791323p+0, 0x1.9f80p-46,
+ 0x1.2387a6e7561e7p+0, -0x1.9c80p-46,
+ 0x1.2451ffb821427p+0, 0x1.2300p-47,
+ 0x1.251ce4fb2a602p+0, -0x1.3480p-46,
+ 0x1.25e85711eceb0p+0, 0x1.2700p-46,
+ 0x1.26b4565e27d16p+0, 0x1.1d00p-46,
+ 0x1.2780e341de00fp+0, 0x1.1ee0p-44,
+ 0x1.284dfe1f5633ep+0, -0x1.4c00p-46,
+ 0x1.291ba7591bb30p+0, -0x1.3d80p-46,
+ 0x1.29e9df51fdf09p+0, 0x1.8b00p-47,
+ 0x1.2ab8a66d10e9bp+0, -0x1.27c0p-45,
+ 0x1.2b87fd0dada3ap+0, 0x1.a340p-45,
+ 0x1.2c57e39771af9p+0, -0x1.0800p-46,
+ 0x1.2d285a6e402d9p+0, -0x1.ed00p-47,
+ 0x1.2df961f641579p+0, -0x1.4200p-48,
+ 0x1.2ecafa93e2ecfp+0, -0x1.4980p-45,
+ 0x1.2f9d24abd8822p+0, -0x1.6300p-46,
+ 0x1.306fe0a31b625p+0, -0x1.2360p-44,
+ 0x1.31432edeea50bp+0, -0x1.0df8p-40,
+ 0x1.32170fc4cd7b8p+0, -0x1.2480p-45,
+ 0x1.32eb83ba8e9a2p+0, -0x1.5980p-45,
+ 0x1.33c08b2641766p+0, 0x1.ed00p-46,
+ 0x1.3496266e3fa27p+0, -0x1.c000p-50,
+ 0x1.356c55f929f0fp+0, -0x1.0d80p-44,
+ 0x1.36431a2de88b9p+0, 0x1.2c80p-45,
+ 0x1.371a7373aaa39p+0, 0x1.0600p-45,
+ 0x1.37f26231e74fep+0, -0x1.6600p-46,
+ 0x1.38cae6d05d838p+0, -0x1.ae00p-47,
+ 0x1.39a401b713ec3p+0, -0x1.4720p-43,
+ 0x1.3a7db34e5a020p+0, 0x1.8200p-47,
+ 0x1.3b57fbfec6e95p+0, 0x1.e800p-44,
+ 0x1.3c32dc313a8f2p+0, 0x1.f800p-49,
+ 0x1.3d0e544ede122p+0, -0x1.7a00p-46,
+ 0x1.3dea64c1234bbp+0, 0x1.6300p-45,
+ 0x1.3ec70df1c4eccp+0, -0x1.8a60p-43,
+ 0x1.3fa4504ac7e8cp+0, -0x1.cdc0p-44,
+ 0x1.40822c367a0bbp+0, 0x1.5b80p-45,
+ 0x1.4160a21f72e95p+0, 0x1.ec00p-46,
+ 0x1.423fb27094646p+0, -0x1.3600p-46,
+ 0x1.431f5d950a920p+0, 0x1.3980p-45,
+ 0x1.43ffa3f84b9ebp+0, 0x1.a000p-48,
+ 0x1.44e0860618919p+0, -0x1.6c00p-48,
+ 0x1.45c2042a7d201p+0, -0x1.bc00p-47,
+ 0x1.46a41ed1d0016p+0, -0x1.2800p-46,
+ 0x1.4786d668b3326p+0, 0x1.0e00p-44,
+ 0x1.486a2b5c13c00p+0, -0x1.d400p-45,
+ 0x1.494e1e192af04p+0, 0x1.c200p-47,
+ 0x1.4a32af0d7d372p+0, -0x1.e500p-46,
+ 0x1.4b17dea6db801p+0, 0x1.7800p-47,
+ 0x1.4bfdad53629e1p+0, -0x1.3800p-46,
+ 0x1.4ce41b817c132p+0, 0x1.0800p-47,
+ 0x1.4dcb299fddddbp+0, 0x1.c700p-45,
+ 0x1.4eb2d81d8ab96p+0, -0x1.ce00p-46,
+ 0x1.4f9b2769d2d02p+0, 0x1.9200p-46,
+ 0x1.508417f4531c1p+0, -0x1.8c00p-47,
+ 0x1.516daa2cf662ap+0, -0x1.a000p-48,
+ 0x1.5257de83f51eap+0, 0x1.a080p-43,
+ 0x1.5342b569d4edap+0, -0x1.6d80p-45,
+ 0x1.542e2f4f6ac1ap+0, -0x1.2440p-44,
+ 0x1.551a4ca5d94dbp+0, 0x1.83c0p-43,
+ 0x1.56070dde9116bp+0, 0x1.4b00p-45,
+ 0x1.56f4736b529dep+0, 0x1.15a0p-43,
+ 0x1.57e27dbe2c40ep+0, -0x1.9e00p-45,
+ 0x1.58d12d497c76fp+0, -0x1.3080p-45,
+ 0x1.59c0827ff0b4cp+0, 0x1.dec0p-43,
+ 0x1.5ab07dd485427p+0, -0x1.4000p-51,
+ 0x1.5ba11fba87af4p+0, 0x1.0080p-44,
+ 0x1.5c9268a59460bp+0, -0x1.6c80p-45,
+ 0x1.5d84590998e3fp+0, 0x1.69a0p-43,
+ 0x1.5e76f15ad20e1p+0, -0x1.b400p-46,
+ 0x1.5f6a320dcebcap+0, 0x1.7700p-46,
+ 0x1.605e1b976dcb8p+0, 0x1.6f80p-45,
+ 0x1.6152ae6cdf715p+0, 0x1.1000p-47,
+ 0x1.6247eb03a5531p+0, -0x1.5d00p-46,
+ 0x1.633dd1d1929b5p+0, -0x1.2d00p-46,
+ 0x1.6434634ccc313p+0, -0x1.a800p-49,
+ 0x1.652b9febc8efap+0, -0x1.8600p-45,
+ 0x1.6623882553397p+0, 0x1.1fe0p-40,
+ 0x1.671c1c708328ep+0, -0x1.7200p-44,
+ 0x1.68155d44ca97ep+0, 0x1.6800p-49,
+ 0x1.690f4b19e9471p+0, -0x1.9780p-45,
+};
+
+/*
+ * exp2(x): compute the base 2 exponential of x
+ *
+ * Accuracy: Peak error < 0.503 ulp for normalized results.
+ *
+ * Method: (accurate tables)
+ *
+ * Reduce x:
+ * x = 2**k + y, for integer k and |y| <= 1/2.
+ * Thus we have exp2(x) = 2**k * exp2(y).
+ *
+ * Reduce y:
+ * y = i/TBLSIZE + z - eps[i] for integer i near y * TBLSIZE.
+ * Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z - eps[i]),
+ * with |z - eps[i]| <= 2**-9 + 2**-39 for the table used.
+ *
+ * We compute exp2(i/TBLSIZE) via table lookup and exp2(z - eps[i]) via
+ * a degree-5 minimax polynomial with maximum error under 1.3 * 2**-61.
+ * The values in exp2t[] and eps[] are chosen such that
+ * exp2t[i] = exp2(i/TBLSIZE + eps[i]), and eps[i] is a small offset such
+ * that exp2t[i] is accurate to 2**-64.
+ *
+ * Note that the range of i is +-TBLSIZE/2, so we actually index the tables
+ * by i0 = i + TBLSIZE/2. For cache efficiency, exp2t[] and eps[] are
+ * virtual tables, interleaved in the real table tbl[].
+ *
+ * This method is due to Gal, with many details due to Gal and Bachelis:
+ *
+ * Gal, S. and Bachelis, B. An Accurate Elementary Mathematical Library
+ * for the IEEE Floating Point Standard. TOMS 17(1), 26-46 (1991).
+ */
+double
+exp2(double x)
+{
+ double r, t, z;
+ uint32_t hx, hr, ix, lx, i0;
+ int k;
+
+ /* Filter out exceptional cases. */
+ GET_HIGH_WORD(hx,x);
+ ix = hx & 0x7fffffff; /* high word of |x| */
+ if(ix >= 0x40900000) { /* |x| >= 1024 */
+ if(ix >= 0x7ff00000) {
+ GET_LOW_WORD(lx,x);
+ if(((ix & 0xfffff) | lx) != 0 || (hx & 0x80000000) == 0)
+ return (x); /* x is NaN or +Inf */
+ else
+ return (0.0); /* x is -Inf */
+ }
+ if(x >= 0x1.0p10)
+ return (huge * huge); /* overflow */
+ if(x <= -0x1.0ccp10)
+ return (twom1000 * twom1000); /* underflow */
+ } else if (ix < 0x3c900000) { /* |x| < 0x1p-54 */
+ return (1.0 + x);
+ }
+
+ /* Reduce x, computing z, i0, and k. */
+ t = x + redux;
+ GET_LOW_WORD(i0, t);
+ i0 += TBLSIZE / 2;
+ k = (i0 >> TBLBITS) << 20;
+ i0 = (i0 & (TBLSIZE - 1)) << 1;
+ t -= redux;
+ z = x - t;
+
+ /* Compute r = exp2(y) = exp2t[i0] * p(z - eps[i]). */
+ t = tbl[i0]; /* exp2t[i0] */
+ z -= tbl[i0 + 1]; /* eps[i0] */
+ r = t + t * z * (P1 + z * (P2 + z * (P3 + z * (P4 + z * P5))));
+
+ /* Scale by 2**(k>>20). */
+ if(k >= -1021 << 20) {
+ if (k != 0) {
+ GET_HIGH_WORD(hr, r);
+ SET_HIGH_WORD(r, hr + k);
+ }
+ return (r);
+ } else {
+ GET_HIGH_WORD(hr, r);
+ SET_HIGH_WORD(r, hr + (k + (1000 << 20)));
+ return (r * twom1000);
+ }
+}
diff --git a/lib/msun/src/s_exp2f.c b/lib/msun/src/s_exp2f.c
new file mode 100644
index 0000000..1bc026a
--- /dev/null
+++ b/lib/msun/src/s_exp2f.c
@@ -0,0 +1,141 @@
+/*-
+ * 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 "math.h"
+#include "math_private.h"
+
+#define TBLBITS 4
+#define TBLSIZE (1 << TBLBITS)
+
+static const float
+ huge = 0x1p100f,
+ twom100 = 0x1p-100f,
+ redux = 0x1.8p23f / TBLSIZE,
+ P1 = 0x1.62e430p-1f,
+ P2 = 0x1.ebfbe0p-3f,
+ P3 = 0x1.c6b348p-5f,
+ P4 = 0x1.3b2c9cp-7f;
+
+static const double exp2ft[TBLSIZE] = {
+ 0x1.6a09e667f3bcdp-1,
+ 0x1.7a11473eb0187p-1,
+ 0x1.8ace5422aa0dbp-1,
+ 0x1.9c49182a3f090p-1,
+ 0x1.ae89f995ad3adp-1,
+ 0x1.c199bdd85529cp-1,
+ 0x1.d5818dcfba487p-1,
+ 0x1.ea4afa2a490dap-1,
+ 0x1.0000000000000p+0,
+ 0x1.0b5586cf9890fp+0,
+ 0x1.172b83c7d517bp+0,
+ 0x1.2387a6e756238p+0,
+ 0x1.306fe0a31b715p+0,
+ 0x1.3dea64c123422p+0,
+ 0x1.4bfdad5362a27p+0,
+ 0x1.5ab07dd485429p+0,
+};
+
+/*
+ * exp2f(x): compute the base 2 exponential of x
+ *
+ * Accuracy: Peak error < 0.501 ulp; location of peak: -0.030110927.
+ *
+ * Method: (equally-spaced tables)
+ *
+ * Reduce x:
+ * x = 2**k + y, for integer k and |y| <= 1/2.
+ * Thus we have exp2f(x) = 2**k * exp2(y).
+ *
+ * Reduce y:
+ * y = i/TBLSIZE + z for integer i near y * TBLSIZE.
+ * Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z),
+ * with |z| <= 2**-(TBLSIZE+1).
+ *
+ * We compute exp2(i/TBLSIZE) via table lookup and exp2(z) via a
+ * degree-4 minimax polynomial with maximum error under 1.4 * 2**-33.
+ * Using double precision in the final calculation avoids roundoff error.
+ *
+ * This method is due to Tang, but I do not use his suggested parameters:
+ *
+ * Tang, P. Table-driven Implementation of the Exponential Function
+ * in IEEE Floating-Point Arithmetic. TOMS 15(2), 144-157 (1989).
+ */
+float
+exp2f(float x)
+{
+ double tv;
+ float r, z;
+ volatile float t; /* prevent gcc from using too much precision */
+ uint32_t hx, hr, ix, i0;
+ int32_t k;
+
+ /* Filter out exceptional cases. */
+ GET_FLOAT_WORD(hx,x);
+ ix = hx & 0x7fffffff; /* high word of |x| */
+ if(ix >= 0x43000000) { /* |x| >= 128 */
+ if(ix >= 0x7f800000) {
+ if ((ix & 0x7fffff) != 0 || (hx & 0x80000000) == 0)
+ return (x); /* x is NaN or +Inf */
+ else
+ return (0.0); /* x is -Inf */
+ }
+ if(x >= 0x1.0p7f)
+ return (huge * huge); /* overflow */
+ if(x <= -0x1.2cp7f)
+ return (twom100 * twom100); /* underflow */
+ } else if (ix <= 0x33000000) { /* |x| <= 0x1p-25 */
+ return (1.0f + x);
+ }
+
+ /* Reduce x, computing z, i0, and k. */
+ t = x + redux;
+ GET_FLOAT_WORD(i0, t);
+ i0 += TBLSIZE / 2;
+ k = (i0 >> TBLBITS) << 23;
+ i0 &= TBLSIZE - 1;
+ t -= redux;
+ z = x - t;
+
+ /* Compute r = exp2(y) = exp2ft[i0] * p(z). */
+ tv = exp2ft[i0];
+ r = tv + tv * (z * (P1 + z * (P2 + z * (P3 + z * P4))));
+
+ /* Scale by 2**(k>>23). */
+ if(k >= -125 << 23) {
+ if (k != 0) {
+ GET_FLOAT_WORD(hr, r);
+ SET_FLOAT_WORD(r, hr + k);
+ }
+ return (r);
+ } else {
+ GET_FLOAT_WORD(hr, r);
+ SET_FLOAT_WORD(r, hr + (k + (100 << 23)));
+ return (r * twom100);
+ }
+}
diff --git a/lib/msun/src/s_expm1.c b/lib/msun/src/s_expm1.c
new file mode 100644
index 0000000..1bf4aa6
--- /dev/null
+++ b/lib/msun/src/s_expm1.c
@@ -0,0 +1,220 @@
+/* @(#)s_expm1.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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/* expm1(x)
+ * Returns exp(x)-1, the exponential of x minus 1.
+ *
+ * Method
+ * 1. Argument reduction:
+ * Given x, find r and integer k such that
+ *
+ * x = k*ln2 + r, |r| <= 0.5*ln2 ~ 0.34658
+ *
+ * Here a correction term c will be computed to compensate
+ * the error in r when rounded to a floating-point number.
+ *
+ * 2. Approximating expm1(r) by a special rational function on
+ * the interval [0,0.34658]:
+ * Since
+ * r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 - r^4/360 + ...
+ * we define R1(r*r) by
+ * r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 * R1(r*r)
+ * That is,
+ * R1(r**2) = 6/r *((exp(r)+1)/(exp(r)-1) - 2/r)
+ * = 6/r * ( 1 + 2.0*(1/(exp(r)-1) - 1/r))
+ * = 1 - r^2/60 + r^4/2520 - r^6/100800 + ...
+ * We use a special Reme algorithm on [0,0.347] to generate
+ * a polynomial of degree 5 in r*r to approximate R1. The
+ * maximum error of this polynomial approximation is bounded
+ * by 2**-61. In other words,
+ * R1(z) ~ 1.0 + Q1*z + Q2*z**2 + Q3*z**3 + Q4*z**4 + Q5*z**5
+ * where Q1 = -1.6666666666666567384E-2,
+ * Q2 = 3.9682539681370365873E-4,
+ * Q3 = -9.9206344733435987357E-6,
+ * Q4 = 2.5051361420808517002E-7,
+ * Q5 = -6.2843505682382617102E-9;
+ * (where z=r*r, and the values of Q1 to Q5 are listed below)
+ * with error bounded by
+ * | 5 | -61
+ * | 1.0+Q1*z+...+Q5*z - R1(z) | <= 2
+ * | |
+ *
+ * expm1(r) = exp(r)-1 is then computed by the following
+ * specific way which minimize the accumulation rounding error:
+ * 2 3
+ * r r [ 3 - (R1 + R1*r/2) ]
+ * expm1(r) = r + --- + --- * [--------------------]
+ * 2 2 [ 6 - r*(3 - R1*r/2) ]
+ *
+ * To compensate the error in the argument reduction, we use
+ * expm1(r+c) = expm1(r) + c + expm1(r)*c
+ * ~ expm1(r) + c + r*c
+ * Thus c+r*c will be added in as the correction terms for
+ * expm1(r+c). Now rearrange the term to avoid optimization
+ * screw up:
+ * ( 2 2 )
+ * ({ ( r [ R1 - (3 - R1*r/2) ] ) } r )
+ * expm1(r+c)~r - ({r*(--- * [--------------------]-c)-c} - --- )
+ * ({ ( 2 [ 6 - r*(3 - R1*r/2) ] ) } 2 )
+ * ( )
+ *
+ * = r - E
+ * 3. Scale back to obtain expm1(x):
+ * From step 1, we have
+ * expm1(x) = either 2^k*[expm1(r)+1] - 1
+ * = or 2^k*[expm1(r) + (1-2^-k)]
+ * 4. Implementation notes:
+ * (A). To save one multiplication, we scale the coefficient Qi
+ * to Qi*2^i, and replace z by (x^2)/2.
+ * (B). To achieve maximum accuracy, we compute expm1(x) by
+ * (i) if x < -56*ln2, return -1.0, (raise inexact if x!=inf)
+ * (ii) if k=0, return r-E
+ * (iii) if k=-1, return 0.5*(r-E)-0.5
+ * (iv) if k=1 if r < -0.25, return 2*((r+0.5)- E)
+ * else return 1.0+2.0*(r-E);
+ * (v) if (k<-2||k>56) return 2^k(1-(E-r)) - 1 (or exp(x)-1)
+ * (vi) if k <= 20, return 2^k((1-2^-k)-(E-r)), else
+ * (vii) return 2^k(1-((E+2^-k)-r))
+ *
+ * Special cases:
+ * expm1(INF) is INF, expm1(NaN) is NaN;
+ * expm1(-INF) is -1, and
+ * for finite argument, only expm1(0)=0 is exact.
+ *
+ * Accuracy:
+ * according to an error analysis, the error is always less than
+ * 1 ulp (unit in the last place).
+ *
+ * Misc. info.
+ * For IEEE double
+ * if x > 7.09782712893383973096e+02 then expm1(x) overflow
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following
+ * constants. The decimal values may be used, provided that the
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+static const double
+one = 1.0,
+huge = 1.0e+300,
+tiny = 1.0e-300,
+o_threshold = 7.09782712893383973096e+02,/* 0x40862E42, 0xFEFA39EF */
+ln2_hi = 6.93147180369123816490e-01,/* 0x3fe62e42, 0xfee00000 */
+ln2_lo = 1.90821492927058770002e-10,/* 0x3dea39ef, 0x35793c76 */
+invln2 = 1.44269504088896338700e+00,/* 0x3ff71547, 0x652b82fe */
+ /* scaled coefficients related to expm1 */
+Q1 = -3.33333333333331316428e-02, /* BFA11111 111110F4 */
+Q2 = 1.58730158725481460165e-03, /* 3F5A01A0 19FE5585 */
+Q3 = -7.93650757867487942473e-05, /* BF14CE19 9EAADBB7 */
+Q4 = 4.00821782732936239552e-06, /* 3ED0CFCA 86E65239 */
+Q5 = -2.01099218183624371326e-07; /* BE8AFDB7 6E09C32D */
+
+double
+expm1(double x)
+{
+ double y,hi,lo,c,t,e,hxs,hfx,r1;
+ int32_t k,xsb;
+ u_int32_t hx;
+
+ GET_HIGH_WORD(hx,x);
+ xsb = hx&0x80000000; /* sign bit of x */
+ if(xsb==0) y=x; else y= -x; /* y = |x| */
+ hx &= 0x7fffffff; /* high word of |x| */
+
+ /* filter out huge and non-finite argument */
+ if(hx >= 0x4043687A) { /* if |x|>=56*ln2 */
+ if(hx >= 0x40862E42) { /* if |x|>=709.78... */
+ if(hx>=0x7ff00000) {
+ u_int32_t low;
+ GET_LOW_WORD(low,x);
+ if(((hx&0xfffff)|low)!=0)
+ return x+x; /* NaN */
+ else return (xsb==0)? x:-1.0;/* exp(+-inf)={inf,-1} */
+ }
+ if(x > o_threshold) return huge*huge; /* overflow */
+ }
+ if(xsb!=0) { /* x < -56*ln2, return -1.0 with inexact */
+ if(x+tiny<0.0) /* raise inexact */
+ return tiny-one; /* return -1 */
+ }
+ }
+
+ /* argument reduction */
+ if(hx > 0x3fd62e42) { /* if |x| > 0.5 ln2 */
+ if(hx < 0x3FF0A2B2) { /* and |x| < 1.5 ln2 */
+ if(xsb==0)
+ {hi = x - ln2_hi; lo = ln2_lo; k = 1;}
+ else
+ {hi = x + ln2_hi; lo = -ln2_lo; k = -1;}
+ } else {
+ k = invln2*x+((xsb==0)?0.5:-0.5);
+ t = k;
+ hi = x - t*ln2_hi; /* t*ln2_hi is exact here */
+ lo = t*ln2_lo;
+ }
+ x = hi - lo;
+ c = (hi-x)-lo;
+ }
+ else if(hx < 0x3c900000) { /* when |x|<2**-54, return x */
+ t = huge+x; /* return x with inexact flags when x!=0 */
+ return x - (t-(huge+x));
+ }
+ else k = 0;
+
+ /* x is now in primary range */
+ hfx = 0.5*x;
+ hxs = x*hfx;
+ r1 = one+hxs*(Q1+hxs*(Q2+hxs*(Q3+hxs*(Q4+hxs*Q5))));
+ t = 3.0-r1*hfx;
+ e = hxs*((r1-t)/(6.0 - x*t));
+ if(k==0) return x - (x*e-hxs); /* c is 0 */
+ else {
+ e = (x*(e-c)-c);
+ e -= hxs;
+ if(k== -1) return 0.5*(x-e)-0.5;
+ if(k==1)
+ if(x < -0.25) return -2.0*(e-(x+0.5));
+ else return one+2.0*(x-e);
+ if (k <= -2 || k>56) { /* suffice to return exp(x)-1 */
+ u_int32_t high;
+ y = one-(e-x);
+ GET_HIGH_WORD(high,y);
+ SET_HIGH_WORD(y,high+(k<<20)); /* add k to y's exponent */
+ return y-one;
+ }
+ t = one;
+ if(k<20) {
+ u_int32_t high;
+ SET_HIGH_WORD(t,0x3ff00000 - (0x200000>>k)); /* t=1-2^-k */
+ y = t-(e-x);
+ GET_HIGH_WORD(high,y);
+ SET_HIGH_WORD(y,high+(k<<20)); /* add k to y's exponent */
+ } else {
+ u_int32_t high;
+ SET_HIGH_WORD(t,((0x3ff-k)<<20)); /* 2^-k */
+ y = x-(e+t);
+ y += one;
+ GET_HIGH_WORD(high,y);
+ SET_HIGH_WORD(y,high+(k<<20)); /* add k to y's exponent */
+ }
+ }
+ return y;
+}
diff --git a/lib/msun/src/s_expm1f.c b/lib/msun/src/s_expm1f.c
new file mode 100644
index 0000000..f8191b2
--- /dev/null
+++ b/lib/msun/src/s_expm1f.c
@@ -0,0 +1,125 @@
+/* s_expm1f.c -- float version of s_expm1.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+#include "math.h"
+#include "math_private.h"
+
+static const float
+one = 1.0,
+huge = 1.0e+30,
+tiny = 1.0e-30,
+o_threshold = 8.8721679688e+01,/* 0x42b17180 */
+ln2_hi = 6.9313812256e-01,/* 0x3f317180 */
+ln2_lo = 9.0580006145e-06,/* 0x3717f7d1 */
+invln2 = 1.4426950216e+00,/* 0x3fb8aa3b */
+ /* scaled coefficients related to expm1 */
+Q1 = -3.3333335072e-02, /* 0xbd088889 */
+Q2 = 1.5873016091e-03, /* 0x3ad00d01 */
+Q3 = -7.9365076090e-05, /* 0xb8a670cd */
+Q4 = 4.0082177293e-06, /* 0x36867e54 */
+Q5 = -2.0109921195e-07; /* 0xb457edbb */
+
+float
+expm1f(float x)
+{
+ float y,hi,lo,c,t,e,hxs,hfx,r1;
+ int32_t k,xsb;
+ u_int32_t hx;
+
+ GET_FLOAT_WORD(hx,x);
+ xsb = hx&0x80000000; /* sign bit of x */
+ if(xsb==0) y=x; else y= -x; /* y = |x| */
+ hx &= 0x7fffffff; /* high word of |x| */
+
+ /* filter out huge and non-finite argument */
+ if(hx >= 0x4195b844) { /* if |x|>=27*ln2 */
+ if(hx >= 0x42b17218) { /* if |x|>=88.721... */
+ if(hx>0x7f800000)
+ return x+x; /* NaN */
+ if(hx==0x7f800000)
+ return (xsb==0)? x:-1.0;/* exp(+-inf)={inf,-1} */
+ if(x > o_threshold) return huge*huge; /* overflow */
+ }
+ if(xsb!=0) { /* x < -27*ln2, return -1.0 with inexact */
+ if(x+tiny<(float)0.0) /* raise inexact */
+ return tiny-one; /* return -1 */
+ }
+ }
+
+ /* argument reduction */
+ if(hx > 0x3eb17218) { /* if |x| > 0.5 ln2 */
+ if(hx < 0x3F851592) { /* and |x| < 1.5 ln2 */
+ if(xsb==0)
+ {hi = x - ln2_hi; lo = ln2_lo; k = 1;}
+ else
+ {hi = x + ln2_hi; lo = -ln2_lo; k = -1;}
+ } else {
+ k = invln2*x+((xsb==0)?(float)0.5:(float)-0.5);
+ t = k;
+ hi = x - t*ln2_hi; /* t*ln2_hi is exact here */
+ lo = t*ln2_lo;
+ }
+ x = hi - lo;
+ c = (hi-x)-lo;
+ }
+ else if(hx < 0x33000000) { /* when |x|<2**-25, return x */
+ t = huge+x; /* return x with inexact flags when x!=0 */
+ return x - (t-(huge+x));
+ }
+ else k = 0;
+
+ /* x is now in primary range */
+ hfx = (float)0.5*x;
+ hxs = x*hfx;
+ r1 = one+hxs*(Q1+hxs*(Q2+hxs*(Q3+hxs*(Q4+hxs*Q5))));
+ t = (float)3.0-r1*hfx;
+ e = hxs*((r1-t)/((float)6.0 - x*t));
+ if(k==0) return x - (x*e-hxs); /* c is 0 */
+ else {
+ e = (x*(e-c)-c);
+ e -= hxs;
+ if(k== -1) return (float)0.5*(x-e)-(float)0.5;
+ if(k==1)
+ if(x < (float)-0.25) return -(float)2.0*(e-(x+(float)0.5));
+ else return one+(float)2.0*(x-e);
+ if (k <= -2 || k>56) { /* suffice to return exp(x)-1 */
+ int32_t i;
+ y = one-(e-x);
+ GET_FLOAT_WORD(i,y);
+ SET_FLOAT_WORD(y,i+(k<<23)); /* add k to y's exponent */
+ return y-one;
+ }
+ t = one;
+ if(k<23) {
+ int32_t i;
+ SET_FLOAT_WORD(t,0x3f800000 - (0x1000000>>k)); /* t=1-2^-k */
+ y = t-(e-x);
+ GET_FLOAT_WORD(i,y);
+ SET_FLOAT_WORD(y,i+(k<<23)); /* add k to y's exponent */
+ } else {
+ int32_t i;
+ SET_FLOAT_WORD(t,((0x7f-k)<<23)); /* 2^-k */
+ y = x-(e+t);
+ y += one;
+ GET_FLOAT_WORD(i,y);
+ SET_FLOAT_WORD(y,i+(k<<23)); /* add k to y's exponent */
+ }
+ }
+ return y;
+}
diff --git a/lib/msun/src/s_fabs.c b/lib/msun/src/s_fabs.c
new file mode 100644
index 0000000..15529e5
--- /dev/null
+++ b/lib/msun/src/s_fabs.c
@@ -0,0 +1,31 @@
+/* @(#)s_fabs.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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/*
+ * fabs(x) returns the absolute value of x.
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+double
+fabs(double x)
+{
+ u_int32_t high;
+ GET_HIGH_WORD(high,x);
+ SET_HIGH_WORD(x,high&0x7fffffff);
+ return x;
+}
diff --git a/lib/msun/src/s_fabsf.c b/lib/msun/src/s_fabsf.c
new file mode 100644
index 0000000..6b7d0a1
--- /dev/null
+++ b/lib/msun/src/s_fabsf.c
@@ -0,0 +1,34 @@
+/* s_fabsf.c -- float version of s_fabs.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/*
+ * fabsf(x) returns the absolute value of x.
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+float
+fabsf(float x)
+{
+ u_int32_t ix;
+ GET_FLOAT_WORD(ix,x);
+ SET_FLOAT_WORD(x,ix&0x7fffffff);
+ return x;
+}
diff --git a/lib/msun/src/s_fabsl.c b/lib/msun/src/s_fabsl.c
new file mode 100644
index 0000000..f150ddd
--- /dev/null
+++ b/lib/msun/src/s_fabsl.c
@@ -0,0 +1,43 @@
+/*-
+ * Copyright (c) 2003 Dag-Erling Coïdan Smørgrav
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 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$
+ */
+
+#include <math.h>
+
+#include "fpmath.h"
+
+long double
+fabsl(long double x)
+{
+ union IEEEl2bits u;
+
+ u.e = x;
+ u.bits.sign = 0;
+ return (u.e);
+}
diff --git a/lib/msun/src/s_fdim.c b/lib/msun/src/s_fdim.c
new file mode 100644
index 0000000..2f347fd
--- /dev/null
+++ b/lib/msun/src/s_fdim.c
@@ -0,0 +1,46 @@
+/*-
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <math.h>
+
+#define DECL(type, fn) \
+type \
+fn(type x, type y) \
+{ \
+ \
+ if (isnan(x)) \
+ return (x); \
+ if (isnan(y)) \
+ return (y); \
+ return (x > y ? x - y : 0.0); \
+}
+
+DECL(double, fdim)
+DECL(float, fdimf)
+DECL(long double, fdiml)
diff --git a/lib/msun/src/s_finite.c b/lib/msun/src/s_finite.c
new file mode 100644
index 0000000..8e7c175
--- /dev/null
+++ b/lib/msun/src/s_finite.c
@@ -0,0 +1,30 @@
+/* @(#)s_finite.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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/*
+ * finite(x) returns 1 is x is finite, else 0;
+ * no branching!
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+ int finite(double x)
+{
+ int32_t hx;
+ GET_HIGH_WORD(hx,x);
+ return (int)((u_int32_t)((hx&0x7fffffff)-0x7ff00000)>>31);
+}
diff --git a/lib/msun/src/s_finitef.c b/lib/msun/src/s_finitef.c
new file mode 100644
index 0000000..a8ccb92
--- /dev/null
+++ b/lib/msun/src/s_finitef.c
@@ -0,0 +1,33 @@
+/* s_finitef.c -- float version of s_finite.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/*
+ * finitef(x) returns 1 is x is finite, else 0;
+ * no branching!
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+ int finitef(float x)
+{
+ int32_t ix;
+ GET_FLOAT_WORD(ix,x);
+ return (int)((u_int32_t)((ix&0x7fffffff)-0x7f800000)>>31);
+}
diff --git a/lib/msun/src/s_floor.c b/lib/msun/src/s_floor.c
new file mode 100644
index 0000000..16fc7f6
--- /dev/null
+++ b/lib/msun/src/s_floor.c
@@ -0,0 +1,73 @@
+/* @(#)s_floor.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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/*
+ * floor(x)
+ * Return x rounded toward -inf to integral value
+ * Method:
+ * Bit twiddling.
+ * Exception:
+ * Inexact flag raised if x not equal to floor(x).
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+static const double huge = 1.0e300;
+
+double
+floor(double x)
+{
+ int32_t i0,i1,j0;
+ u_int32_t i,j;
+ EXTRACT_WORDS(i0,i1,x);
+ j0 = ((i0>>20)&0x7ff)-0x3ff;
+ if(j0<20) {
+ if(j0<0) { /* raise inexact if x != 0 */
+ if(huge+x>0.0) {/* return 0*sign(x) if |x|<1 */
+ if(i0>=0) {i0=i1=0;}
+ else if(((i0&0x7fffffff)|i1)!=0)
+ { i0=0xbff00000;i1=0;}
+ }
+ } else {
+ i = (0x000fffff)>>j0;
+ if(((i0&i)|i1)==0) return x; /* x is integral */
+ if(huge+x>0.0) { /* raise inexact flag */
+ if(i0<0) i0 += (0x00100000)>>j0;
+ i0 &= (~i); i1=0;
+ }
+ }
+ } else if (j0>51) {
+ if(j0==0x400) return x+x; /* inf or NaN */
+ else return x; /* x is integral */
+ } else {
+ i = ((u_int32_t)(0xffffffff))>>(j0-20);
+ if((i1&i)==0) return x; /* x is integral */
+ if(huge+x>0.0) { /* raise inexact flag */
+ if(i0<0) {
+ if(j0==20) i0+=1;
+ else {
+ j = i1+(1<<(52-j0));
+ if(j<i1) i0 +=1 ; /* got a carry */
+ i1=j;
+ }
+ }
+ i1 &= (~i);
+ }
+ }
+ INSERT_WORDS(x,i0,i1);
+ return x;
+}
diff --git a/lib/msun/src/s_floorf.c b/lib/msun/src/s_floorf.c
new file mode 100644
index 0000000..d4bb6c5
--- /dev/null
+++ b/lib/msun/src/s_floorf.c
@@ -0,0 +1,62 @@
+/* s_floorf.c -- float version of s_floor.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/*
+ * floorf(x)
+ * Return x rounded toward -inf to integral value
+ * Method:
+ * Bit twiddling.
+ * Exception:
+ * Inexact flag raised if x not equal to floorf(x).
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+static const float huge = 1.0e30;
+
+float
+floorf(float x)
+{
+ int32_t i0,j0;
+ u_int32_t i;
+ GET_FLOAT_WORD(i0,x);
+ j0 = ((i0>>23)&0xff)-0x7f;
+ if(j0<23) {
+ if(j0<0) { /* raise inexact if x != 0 */
+ if(huge+x>(float)0.0) {/* return 0*sign(x) if |x|<1 */
+ if(i0>=0) {i0=0;}
+ else if((i0&0x7fffffff)!=0)
+ { i0=0xbf800000;}
+ }
+ } else {
+ i = (0x007fffff)>>j0;
+ if((i0&i)==0) return x; /* x is integral */
+ if(huge+x>(float)0.0) { /* raise inexact flag */
+ if(i0<0) i0 += (0x00800000)>>j0;
+ i0 &= (~i);
+ }
+ }
+ } else {
+ if(j0==0x80) return x+x; /* inf or NaN */
+ else return x; /* x is integral */
+ }
+ SET_FLOAT_WORD(x,i0);
+ return x;
+}
diff --git a/lib/msun/src/s_floorl.c b/lib/msun/src/s_floorl.c
new file mode 100644
index 0000000..9dd13b6
--- /dev/null
+++ b/lib/msun/src/s_floorl.c
@@ -0,0 +1,102 @@
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ *
+ * From: @(#)s_floor.c 5.1 93/09/24
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/*
+ * floorl(x)
+ * Return x rounded toward -inf to integral value
+ * Method:
+ * Bit twiddling.
+ * Exception:
+ * Inexact flag raised if x not equal to floorl(x).
+ */
+
+#include <float.h>
+#include <math.h>
+#include <stdint.h>
+
+#include "fpmath.h"
+
+#ifdef LDBL_IMPLICIT_NBIT
+#define MANH_SIZE (LDBL_MANH_SIZE + 1)
+#define INC_MANH(u, c) do { \
+ uint64_t o = u.bits.manh; \
+ u.bits.manh += (c); \
+ if (u.bits.manh < o) \
+ u.bits.exp++; \
+} while (0)
+#else
+#define MANH_SIZE LDBL_MANH_SIZE
+#define INC_MANH(u, c) do { \
+ uint64_t o = u.bits.manh; \
+ u.bits.manh += (c); \
+ if (u.bits.manh < o) { \
+ u.bits.exp++; \
+ u.bits.manh |= 1llu << (LDBL_MANH_SIZE - 1); \
+ } \
+} while (0)
+#endif
+
+static const long double huge = 1.0e300;
+
+long double
+floorl(long double x)
+{
+ union IEEEl2bits u = { .e = x };
+ int e = u.bits.exp - LDBL_MAX_EXP + 1;
+
+ if (e < MANH_SIZE - 1) {
+ if (e < 0) { /* raise inexact if x != 0 */
+ if (huge + x > 0.0)
+ if (u.bits.exp > 0 ||
+ (u.bits.manh | u.bits.manl) != 0)
+ u.e = u.bits.sign ? -1.0 : 0.0;
+ } else {
+ uint64_t m = ((1llu << MANH_SIZE) - 1) >> (e + 1);
+ if (((u.bits.manh & m) | u.bits.manl) == 0)
+ return (x); /* x is integral */
+ if (u.bits.sign) {
+#ifdef LDBL_IMPLICIT_NBIT
+ if (e == 0)
+ u.bits.exp++;
+ else
+#endif
+ INC_MANH(u, 1llu << (MANH_SIZE - e - 1));
+ }
+ if (huge + x > 0.0) { /* raise inexact flag */
+ u.bits.manh &= ~m;
+ u.bits.manl = 0;
+ }
+ }
+ } else if (e < LDBL_MANT_DIG - 1) {
+ uint64_t m = (uint64_t)-1 >> (64 - LDBL_MANT_DIG + e + 1);
+ if ((u.bits.manl & m) == 0)
+ return (x); /* x is integral */
+ if (u.bits.sign) {
+ if (e == MANH_SIZE - 1)
+ INC_MANH(u, 1);
+ else {
+ uint64_t o = u.bits.manl;
+ u.bits.manl += 1llu << (LDBL_MANT_DIG - e - 1);
+ if (u.bits.manl < o) /* got a carry */
+ INC_MANH(u, 1);
+ }
+ }
+ if (huge + x > 0.0) /* raise inexact flag */
+ u.bits.manl &= ~m;
+ }
+ return (u.e);
+}
diff --git a/lib/msun/src/s_fma.c b/lib/msun/src/s_fma.c
new file mode 100644
index 0000000..c6d27bd
--- /dev/null
+++ b/lib/msun/src/s_fma.c
@@ -0,0 +1,202 @@
+/*-
+ * 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 <fenv.h>
+#include <float.h>
+#include <math.h>
+
+/*
+ * Fused multiply-add: Compute x * y + z with a single rounding error.
+ *
+ * We use scaling to avoid overflow/underflow, along with the
+ * canonical precision-doubling technique adapted from:
+ *
+ * Dekker, T. A Floating-Point Technique for Extending the
+ * Available Precision. Numer. Math. 18, 224-242 (1971).
+ *
+ * This algorithm is sensitive to the rounding precision. FPUs such
+ * as the i387 must be set in double-precision mode if variables are
+ * to be stored in FP registers in order to avoid incorrect results.
+ * This is the default on FreeBSD, but not on many other systems.
+ *
+ * Hardware instructions should be used on architectures that support it,
+ * since this implementation will likely be several times slower.
+ */
+#if LDBL_MANT_DIG != 113
+double
+fma(double x, double y, double z)
+{
+ static const double split = 0x1p27 + 1.0;
+ double xs, ys, zs;
+ double c, cc, hx, hy, p, q, tx, ty;
+ double r, rr, s;
+ int oround;
+ int ex, ey, ez;
+ int spread;
+
+ if (z == 0.0)
+ return (x * y);
+ if (x == 0.0 || y == 0.0)
+ return (x * y + z);
+
+ /* Results of frexp() are undefined for these cases. */
+ if (!isfinite(x) || !isfinite(y) || !isfinite(z))
+ return (x * y + z);
+
+ xs = frexp(x, &ex);
+ ys = frexp(y, &ey);
+ zs = frexp(z, &ez);
+ oround = fegetround();
+ spread = ex + ey - ez;
+
+ /*
+ * If x * y and z are many orders of magnitude apart, the scaling
+ * will overflow, so we handle these cases specially. Rounding
+ * modes other than FE_TONEAREST are painful.
+ */
+ if (spread > DBL_MANT_DIG * 2) {
+ fenv_t env;
+ feraiseexcept(FE_INEXACT);
+ switch(oround) {
+ case FE_TONEAREST:
+ return (x * y);
+ case FE_TOWARDZERO:
+ if (x > 0.0 ^ y < 0.0 ^ z < 0.0)
+ return (x * y);
+ feholdexcept(&env);
+ r = x * y;
+ if (!fetestexcept(FE_INEXACT))
+ r = nextafter(r, 0);
+ feupdateenv(&env);
+ return (r);
+ case FE_DOWNWARD:
+ if (z > 0.0)
+ return (x * y);
+ feholdexcept(&env);
+ r = x * y;
+ if (!fetestexcept(FE_INEXACT))
+ r = nextafter(r, -INFINITY);
+ feupdateenv(&env);
+ return (r);
+ default: /* FE_UPWARD */
+ if (z < 0.0)
+ return (x * y);
+ feholdexcept(&env);
+ r = x * y;
+ if (!fetestexcept(FE_INEXACT))
+ r = nextafter(r, INFINITY);
+ feupdateenv(&env);
+ return (r);
+ }
+ }
+ if (spread < -DBL_MANT_DIG) {
+ feraiseexcept(FE_INEXACT);
+ if (!isnormal(z))
+ feraiseexcept(FE_UNDERFLOW);
+ switch (oround) {
+ case FE_TONEAREST:
+ return (z);
+ case FE_TOWARDZERO:
+ if (x > 0.0 ^ y < 0.0 ^ z < 0.0)
+ return (z);
+ else
+ return (nextafter(z, 0));
+ case FE_DOWNWARD:
+ if (x > 0.0 ^ y < 0.0)
+ return (z);
+ else
+ return (nextafter(z, -INFINITY));
+ default: /* FE_UPWARD */
+ if (x > 0.0 ^ y < 0.0)
+ return (nextafter(z, INFINITY));
+ else
+ return (z);
+ }
+ }
+
+ /*
+ * Use Dekker's algorithm to perform the multiplication and
+ * subsequent addition in twice the machine precision.
+ * Arrange so that x * y = c + cc, and x * y + z = r + rr.
+ */
+ fesetround(FE_TONEAREST);
+
+ p = xs * split;
+ hx = xs - p;
+ hx += p;
+ tx = xs - hx;
+
+ p = ys * split;
+ hy = ys - p;
+ hy += p;
+ ty = ys - hy;
+
+ p = hx * hy;
+ q = hx * ty + tx * hy;
+ c = p + q;
+ cc = p - c + q + tx * ty;
+
+ zs = ldexp(zs, -spread);
+ r = c + zs;
+ s = r - c;
+ rr = (c - (r - s)) + (zs - s) + cc;
+
+ spread = ex + ey;
+ if (spread + ilogb(r) > -1023) {
+ fesetround(oround);
+ r = r + rr;
+ } else {
+ /*
+ * The result is subnormal, so we round before scaling to
+ * avoid double rounding.
+ */
+ p = ldexp(copysign(0x1p-1022, r), -spread);
+ c = r + p;
+ s = c - r;
+ cc = (r - (c - s)) + (p - s) + rr;
+ fesetround(oround);
+ r = (c + cc) - p;
+ }
+ return (ldexp(r, spread));
+}
+#else /* LDBL_MANT_DIG == 113 */
+/*
+ * 113 bits of precision is more than twice the precision of a double,
+ * so it is enough to represent the intermediate product exactly.
+ */
+double
+fma(double x, double y, double z)
+{
+ return ((long double)x * y + z);
+}
+#endif /* LDBL_MANT_DIG != 113 */
+
+#if (LDBL_MANT_DIG == 53)
+__weak_reference(fma, fmal);
+#endif
diff --git a/lib/msun/src/s_fmaf.c b/lib/msun/src/s_fmaf.c
new file mode 100644
index 0000000..1b483b7
--- /dev/null
+++ b/lib/msun/src/s_fmaf.c
@@ -0,0 +1,47 @@
+/*-
+ * 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$");
+
+/*
+ * Fused multiply-add: Compute x * y + z with a single rounding error.
+ *
+ * A double has more than twice as much precision than a float, so
+ * direct double-precision arithmetic suffices.
+ *
+ * XXX We are relying on the compiler to convert from double to float
+ * using the current rounding mode and with the appropriate
+ * side-effects. But on at least one platform (gcc 3.4.2/sparc64),
+ * this appears to be too much to ask for. The precision
+ * reduction should be done manually.
+ */
+float
+fmaf(float x, float y, float z)
+{
+
+ return ((double)x * y + z);
+}
diff --git a/lib/msun/src/s_fmal.c b/lib/msun/src/s_fmal.c
new file mode 100644
index 0000000..1604778
--- /dev/null
+++ b/lib/msun/src/s_fmal.c
@@ -0,0 +1,182 @@
+/*-
+ * 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 <fenv.h>
+#include <float.h>
+#include <math.h>
+
+/*
+ * Fused multiply-add: Compute x * y + z with a single rounding error.
+ *
+ * We use scaling to avoid overflow/underflow, along with the
+ * canonical precision-doubling technique adapted from:
+ *
+ * Dekker, T. A Floating-Point Technique for Extending the
+ * Available Precision. Numer. Math. 18, 224-242 (1971).
+ */
+long double
+fmal(long double x, long double y, long double z)
+{
+#if LDBL_MANT_DIG == 64
+ static const long double split = 0x1p32L + 1.0;
+#elif LDBL_MANT_DIG == 113
+ static const long double split = 0x1p57L + 1.0;
+#endif
+ long double xs, ys, zs;
+ long double c, cc, hx, hy, p, q, tx, ty;
+ long double r, rr, s;
+ int oround;
+ int ex, ey, ez;
+ int spread;
+
+ if (z == 0.0)
+ return (x * y);
+ if (x == 0.0 || y == 0.0)
+ return (x * y + z);
+
+ /* Results of frexp() are undefined for these cases. */
+ if (!isfinite(x) || !isfinite(y) || !isfinite(z))
+ return (x * y + z);
+
+ xs = frexpl(x, &ex);
+ ys = frexpl(y, &ey);
+ zs = frexpl(z, &ez);
+ oround = fegetround();
+ spread = ex + ey - ez;
+
+ /*
+ * If x * y and z are many orders of magnitude apart, the scaling
+ * will overflow, so we handle these cases specially. Rounding
+ * modes other than FE_TONEAREST are painful.
+ */
+ if (spread > LDBL_MANT_DIG * 2) {
+ fenv_t env;
+ feraiseexcept(FE_INEXACT);
+ switch(oround) {
+ case FE_TONEAREST:
+ return (x * y);
+ case FE_TOWARDZERO:
+ if (x > 0.0 ^ y < 0.0 ^ z < 0.0)
+ return (x * y);
+ feholdexcept(&env);
+ r = x * y;
+ if (!fetestexcept(FE_INEXACT))
+ r = nextafterl(r, 0);
+ feupdateenv(&env);
+ return (r);
+ case FE_DOWNWARD:
+ if (z > 0.0)
+ return (x * y);
+ feholdexcept(&env);
+ r = x * y;
+ if (!fetestexcept(FE_INEXACT))
+ r = nextafterl(r, -INFINITY);
+ feupdateenv(&env);
+ return (r);
+ default: /* FE_UPWARD */
+ if (z < 0.0)
+ return (x * y);
+ feholdexcept(&env);
+ r = x * y;
+ if (!fetestexcept(FE_INEXACT))
+ r = nextafterl(r, INFINITY);
+ feupdateenv(&env);
+ return (r);
+ }
+ }
+ if (spread < -LDBL_MANT_DIG) {
+ feraiseexcept(FE_INEXACT);
+ if (!isnormal(z))
+ feraiseexcept(FE_UNDERFLOW);
+ switch (oround) {
+ case FE_TONEAREST:
+ return (z);
+ case FE_TOWARDZERO:
+ if (x > 0.0 ^ y < 0.0 ^ z < 0.0)
+ return (z);
+ else
+ return (nextafterl(z, 0));
+ case FE_DOWNWARD:
+ if (x > 0.0 ^ y < 0.0)
+ return (z);
+ else
+ return (nextafterl(z, -INFINITY));
+ default: /* FE_UPWARD */
+ if (x > 0.0 ^ y < 0.0)
+ return (nextafterl(z, INFINITY));
+ else
+ return (z);
+ }
+ }
+
+ /*
+ * Use Dekker's algorithm to perform the multiplication and
+ * subsequent addition in twice the machine precision.
+ * Arrange so that x * y = c + cc, and x * y + z = r + rr.
+ */
+ fesetround(FE_TONEAREST);
+
+ p = xs * split;
+ hx = xs - p;
+ hx += p;
+ tx = xs - hx;
+
+ p = ys * split;
+ hy = ys - p;
+ hy += p;
+ ty = ys - hy;
+
+ p = hx * hy;
+ q = hx * ty + tx * hy;
+ c = p + q;
+ cc = p - c + q + tx * ty;
+
+ zs = ldexpl(zs, -spread);
+ r = c + zs;
+ s = r - c;
+ rr = (c - (r - s)) + (zs - s) + cc;
+
+ spread = ex + ey;
+ if (spread + ilogbl(r) > -16383) {
+ fesetround(oround);
+ r = r + rr;
+ } else {
+ /*
+ * The result is subnormal, so we round before scaling to
+ * avoid double rounding.
+ */
+ p = ldexpl(copysignl(0x1p-16382L, r), -spread);
+ c = r + p;
+ s = c - r;
+ cc = (r - (c - s)) + (p - s) + rr;
+ fesetround(oround);
+ r = (c + cc) - p;
+ }
+ return (ldexpl(r, spread));
+}
diff --git a/lib/msun/src/s_fmax.c b/lib/msun/src/s_fmax.c
new file mode 100644
index 0000000..b51b865
--- /dev/null
+++ b/lib/msun/src/s_fmax.c
@@ -0,0 +1,53 @@
+/*-
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <math.h>
+
+#include "fpmath.h"
+
+double
+fmax(double x, double y)
+{
+ union IEEEd2bits u[2];
+
+ u[0].d = x;
+ u[1].d = y;
+
+ /* Check for NaNs to avoid raising spurious exceptions. */
+ if (u[0].bits.exp == 2047 && (u[0].bits.manh | u[0].bits.manl) != 0)
+ return (y);
+ if (u[1].bits.exp == 2047 && (u[1].bits.manh | u[1].bits.manl) != 0)
+ return (x);
+
+ /* Handle comparisons of signed zeroes. */
+ if (u[0].bits.sign != u[1].bits.sign)
+ return (u[u[0].bits.sign].d);
+
+ return (x > y ? x : y);
+}
diff --git a/lib/msun/src/s_fmaxf.c b/lib/msun/src/s_fmaxf.c
new file mode 100644
index 0000000..423da54
--- /dev/null
+++ b/lib/msun/src/s_fmaxf.c
@@ -0,0 +1,53 @@
+/*-
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <math.h>
+
+#include "fpmath.h"
+
+float
+fmaxf(float x, float y)
+{
+ union IEEEf2bits u[2];
+
+ u[0].f = x;
+ u[1].f = y;
+
+ /* Check for NaNs to avoid raising spurious exceptions. */
+ if (u[0].bits.exp == 255 && u[0].bits.man != 0)
+ return (y);
+ if (u[1].bits.exp == 255 && u[1].bits.man != 0)
+ return (x);
+
+ /* Handle comparisons of signed zeroes. */
+ if (u[0].bits.sign != u[1].bits.sign)
+ return (u[u[0].bits.sign].f);
+
+ return (x > y ? x : y);
+}
diff --git a/lib/msun/src/s_fmaxl.c b/lib/msun/src/s_fmaxl.c
new file mode 100644
index 0000000..0ac48a9
--- /dev/null
+++ b/lib/msun/src/s_fmaxl.c
@@ -0,0 +1,55 @@
+/*-
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <math.h>
+
+#include "fpmath.h"
+
+long double
+fmaxl(long double x, long double y)
+{
+ union IEEEl2bits u[2];
+
+ u[0].e = x;
+ mask_nbit_l(u[0]);
+ u[1].e = y;
+ mask_nbit_l(u[1]);
+
+ /* Check for NaNs to avoid raising spurious exceptions. */
+ if (u[0].bits.exp == 32767 && (u[0].bits.manh | u[0].bits.manl) != 0)
+ return (y);
+ if (u[1].bits.exp == 32767 && (u[1].bits.manh | u[1].bits.manl) != 0)
+ return (x);
+
+ /* Handle comparisons of signed zeroes. */
+ if (u[0].bits.sign != u[1].bits.sign)
+ return (u[0].bits.sign ? y : x);
+
+ return (x > y ? x : y);
+}
diff --git a/lib/msun/src/s_fmin.c b/lib/msun/src/s_fmin.c
new file mode 100644
index 0000000..3500c84
--- /dev/null
+++ b/lib/msun/src/s_fmin.c
@@ -0,0 +1,53 @@
+/*-
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <math.h>
+
+#include "fpmath.h"
+
+double
+fmin(double x, double y)
+{
+ union IEEEd2bits u[2];
+
+ u[0].d = x;
+ u[1].d = y;
+
+ /* Check for NaNs to avoid raising spurious exceptions. */
+ if (u[0].bits.exp == 2047 && (u[0].bits.manh | u[0].bits.manl) != 0)
+ return (y);
+ if (u[1].bits.exp == 2047 && (u[1].bits.manh | u[1].bits.manl) != 0)
+ return (x);
+
+ /* Handle comparisons of signed zeroes. */
+ if (u[0].bits.sign != u[1].bits.sign)
+ return (u[u[1].bits.sign].d);
+
+ return (x < y ? x : y);
+}
diff --git a/lib/msun/src/s_fminf.c b/lib/msun/src/s_fminf.c
new file mode 100644
index 0000000..76a5c76
--- /dev/null
+++ b/lib/msun/src/s_fminf.c
@@ -0,0 +1,53 @@
+/*-
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <math.h>
+
+#include "fpmath.h"
+
+float
+fminf(float x, float y)
+{
+ union IEEEf2bits u[2];
+
+ u[0].f = x;
+ u[1].f = y;
+
+ /* Check for NaNs to avoid raising spurious exceptions. */
+ if (u[0].bits.exp == 255 && u[0].bits.man != 0)
+ return (y);
+ if (u[1].bits.exp == 255 && u[1].bits.man != 0)
+ return (x);
+
+ /* Handle comparisons of signed zeroes. */
+ if (u[0].bits.sign != u[1].bits.sign)
+ return (u[u[1].bits.sign].f);
+
+ return (x < y ? x : y);
+}
diff --git a/lib/msun/src/s_fminl.c b/lib/msun/src/s_fminl.c
new file mode 100644
index 0000000..f9d3ebb
--- /dev/null
+++ b/lib/msun/src/s_fminl.c
@@ -0,0 +1,55 @@
+/*-
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <math.h>
+
+#include "fpmath.h"
+
+long double
+fminl(long double x, long double y)
+{
+ union IEEEl2bits u[2];
+
+ u[0].e = x;
+ mask_nbit_l(u[0]);
+ u[1].e = y;
+ mask_nbit_l(u[1]);
+
+ /* Check for NaNs to avoid raising spurious exceptions. */
+ if (u[0].bits.exp == 32767 && (u[0].bits.manh | u[0].bits.manl) != 0)
+ return (y);
+ if (u[1].bits.exp == 32767 && (u[1].bits.manh | u[1].bits.manl) != 0)
+ return (x);
+
+ /* Handle comparisons of signed zeroes. */
+ if (u[0].bits.sign != u[1].bits.sign)
+ return (u[1].bits.sign ? y : x);
+
+ return (x < y ? x : y);
+}
diff --git a/lib/msun/src/s_frexp.c b/lib/msun/src/s_frexp.c
new file mode 100644
index 0000000..1b5b9bd
--- /dev/null
+++ b/lib/msun/src/s_frexp.c
@@ -0,0 +1,58 @@
+/* @(#)s_frexp.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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/*
+ * for non-zero x
+ * x = frexp(arg,&exp);
+ * return a double fp quantity x such that 0.5 <= |x| <1.0
+ * and the corresponding binary exponent "exp". That is
+ * arg = x*2^exp.
+ * If arg is inf, 0.0, or NaN, then frexp(arg,&exp) returns arg
+ * with *exp=0.
+ */
+
+#include <sys/cdefs.h>
+#include <float.h>
+
+#include "math.h"
+#include "math_private.h"
+
+static const double
+two54 = 1.80143985094819840000e+16; /* 0x43500000, 0x00000000 */
+
+double
+frexp(double x, int *eptr)
+{
+ int32_t hx, ix, lx;
+ EXTRACT_WORDS(hx,lx,x);
+ ix = 0x7fffffff&hx;
+ *eptr = 0;
+ if(ix>=0x7ff00000||((ix|lx)==0)) return x; /* 0,inf,nan */
+ if (ix<0x00100000) { /* subnormal */
+ x *= two54;
+ GET_HIGH_WORD(hx,x);
+ ix = hx&0x7fffffff;
+ *eptr = -54;
+ }
+ *eptr += (ix>>20)-1022;
+ hx = (hx&0x800fffff)|0x3fe00000;
+ SET_HIGH_WORD(x,hx);
+ return x;
+}
+
+#if (LDBL_MANT_DIG == 53)
+__weak_reference(frexp, frexpl);
+#endif
diff --git a/lib/msun/src/s_frexpf.c b/lib/msun/src/s_frexpf.c
new file mode 100644
index 0000000..1952836
--- /dev/null
+++ b/lib/msun/src/s_frexpf.c
@@ -0,0 +1,44 @@
+/* s_frexpf.c -- float version of s_frexp.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+#include "math.h"
+#include "math_private.h"
+
+static const float
+two25 = 3.3554432000e+07; /* 0x4c000000 */
+
+float
+frexpf(float x, int *eptr)
+{
+ int32_t hx,ix;
+ GET_FLOAT_WORD(hx,x);
+ ix = 0x7fffffff&hx;
+ *eptr = 0;
+ if(ix>=0x7f800000||(ix==0)) return x; /* 0,inf,nan */
+ if (ix<0x00800000) { /* subnormal */
+ x *= two25;
+ GET_FLOAT_WORD(hx,x);
+ ix = hx&0x7fffffff;
+ *eptr = -25;
+ }
+ *eptr += (ix>>23)-126;
+ hx = (hx&0x807fffff)|0x3f000000;
+ *(int*)&x = hx;
+ return x;
+}
diff --git a/lib/msun/src/s_frexpl.c b/lib/msun/src/s_frexpl.c
new file mode 100644
index 0000000..d34f55d
--- /dev/null
+++ b/lib/msun/src/s_frexpl.c
@@ -0,0 +1,62 @@
+/*-
+ * Copyright (c) 2004-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.
+ *
+ * $FreeBSD$
+ */
+
+#include <float.h>
+#include <math.h>
+
+#include "fpmath.h"
+
+#if LDBL_MAX_EXP != 0x4000
+#error "Unsupported long double format"
+#endif
+
+long double
+frexpl(long double x, int *ex)
+{
+ union IEEEl2bits u;
+
+ u.e = x;
+ switch (u.bits.exp) {
+ case 0: /* 0 or subnormal */
+ if ((u.bits.manl | u.bits.manh) == 0) {
+ *ex = 0;
+ } else {
+ u.e *= 0x1.0p514;
+ *ex = u.bits.exp - 0x4200;
+ u.bits.exp = 0x3ffe;
+ }
+ break;
+ case 0x7fff: /* infinity or NaN; value of *ex is unspecified */
+ break;
+ default: /* normal */
+ *ex = u.bits.exp - 0x3ffe;
+ u.bits.exp = 0x3ffe;
+ break;
+ }
+ return (u.e);
+}
diff --git a/lib/msun/src/s_ilogb.c b/lib/msun/src/s_ilogb.c
new file mode 100644
index 0000000..69077af
--- /dev/null
+++ b/lib/msun/src/s_ilogb.c
@@ -0,0 +1,49 @@
+/* @(#)s_ilogb.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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/* ilogb(double x)
+ * return the binary exponent of non-zero x
+ * ilogb(0) = FP_ILOGB0
+ * ilogb(NaN) = FP_ILOGBNAN (no signal is raised)
+ * ilogb(inf) = INT_MAX (no signal is raised)
+ */
+
+#include <limits.h>
+
+#include "math.h"
+#include "math_private.h"
+
+ int ilogb(double x)
+{
+ int32_t hx,lx,ix;
+
+ EXTRACT_WORDS(hx,lx,x);
+ hx &= 0x7fffffff;
+ if(hx<0x00100000) {
+ if((hx|lx)==0)
+ return FP_ILOGB0;
+ else /* subnormal x */
+ if(hx==0) {
+ for (ix = -1043; lx>0; lx<<=1) ix -=1;
+ } else {
+ for (ix = -1022,hx<<=11; hx>0; hx<<=1) ix -=1;
+ }
+ return ix;
+ }
+ else if (hx<0x7ff00000) return (hx>>20)-1023;
+ else if (hx>0x7ff00000 || lx!=0) return FP_ILOGBNAN;
+ else return INT_MAX;
+}
diff --git a/lib/msun/src/s_ilogbf.c b/lib/msun/src/s_ilogbf.c
new file mode 100644
index 0000000..ff58813
--- /dev/null
+++ b/lib/msun/src/s_ilogbf.c
@@ -0,0 +1,41 @@
+/* s_ilogbf.c -- float version of s_ilogb.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+#include <limits.h>
+
+#include "math.h"
+#include "math_private.h"
+
+ int ilogbf(float x)
+{
+ int32_t hx,ix;
+
+ GET_FLOAT_WORD(hx,x);
+ hx &= 0x7fffffff;
+ if(hx<0x00800000) {
+ if(hx==0)
+ return FP_ILOGB0;
+ else /* subnormal x */
+ for (ix = -126,hx<<=8; hx>0; hx<<=1) ix -=1;
+ return ix;
+ }
+ else if (hx<0x7f800000) return (hx>>23)-127;
+ else if (hx>0x7f800000) return FP_ILOGBNAN;
+ else return INT_MAX;
+}
diff --git a/lib/msun/src/s_ilogbl.c b/lib/msun/src/s_ilogbl.c
new file mode 100644
index 0000000..a6a4708
--- /dev/null
+++ b/lib/msun/src/s_ilogbl.c
@@ -0,0 +1,54 @@
+/*
+ * From: @(#)s_ilogb.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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+#include <float.h>
+#include <limits.h>
+#include <math.h>
+
+#include "fpmath.h"
+
+int
+ilogbl(long double x)
+{
+ union IEEEl2bits u;
+ unsigned long m;
+ int b;
+
+ u.e = x;
+ if (u.bits.exp == 0) {
+ if ((u.bits.manl | u.bits.manh) == 0)
+ return (FP_ILOGB0);
+ /* denormalized */
+ if (u.bits.manh == 0) {
+ m = 1lu << (LDBL_MANL_SIZE - 1);
+ for (b = LDBL_MANH_SIZE; !(u.bits.manl & m); m >>= 1)
+ b++;
+ } else {
+ m = 1lu << (LDBL_MANH_SIZE - 1);
+ for (b = 0; !(u.bits.manh & m); m >>= 1)
+ b++;
+ }
+#ifdef LDBL_IMPLICIT_NBIT
+ b++;
+#endif
+ return (LDBL_MIN_EXP - b - 1);
+ } else if (u.bits.exp < (LDBL_MAX_EXP << 1) - 1)
+ return (u.bits.exp - LDBL_MAX_EXP + 1);
+ else if (u.bits.manl != 0 || u.bits.manh != 0)
+ return (FP_ILOGBNAN);
+ else
+ return (INT_MAX);
+}
diff --git a/lib/msun/src/s_isfinite.c b/lib/msun/src/s_isfinite.c
new file mode 100644
index 0000000..c9d1bd7
--- /dev/null
+++ b/lib/msun/src/s_isfinite.c
@@ -0,0 +1,58 @@
+/*-
+ * 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"
+
+int
+__isfinite(double d)
+{
+ union IEEEd2bits u;
+
+ u.d = d;
+ return (u.bits.exp != 2047);
+}
+
+int
+__isfinitef(float f)
+{
+ union IEEEf2bits u;
+
+ u.f = f;
+ return (u.bits.exp != 255);
+}
+
+int
+__isfinitel(long double e)
+{
+ union IEEEl2bits u;
+
+ u.e = e;
+ return (u.bits.exp != 32767);
+}
diff --git a/lib/msun/src/s_isnan.c b/lib/msun/src/s_isnan.c
new file mode 100644
index 0000000..5de99ad
--- /dev/null
+++ b/lib/msun/src/s_isnan.c
@@ -0,0 +1,62 @@
+/*-
+ * 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"
+
+/* Provided by libc */
+#if 0
+int
+isnan(double d)
+{
+ union IEEEd2bits u;
+
+ u.d = d;
+ return (u.bits.exp == 2047 && (u.bits.manl != 0 || u.bits.manh != 0));
+}
+#endif
+
+int
+isnanf(float f)
+{
+ union IEEEf2bits u;
+
+ u.f = f;
+ return (u.bits.exp == 255 && u.bits.man != 0);
+}
+
+int
+__isnanl(long double e)
+{
+ union IEEEl2bits u;
+
+ u.e = e;
+ mask_nbit_l(u);
+ return (u.bits.exp == 32767 && (u.bits.manl != 0 || u.bits.manh != 0));
+}
diff --git a/lib/msun/src/s_isnormal.c b/lib/msun/src/s_isnormal.c
new file mode 100644
index 0000000..49f2a74
--- /dev/null
+++ b/lib/msun/src/s_isnormal.c
@@ -0,0 +1,58 @@
+/*-
+ * 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"
+
+int
+__isnormal(double d)
+{
+ union IEEEd2bits u;
+
+ u.d = d;
+ return (u.bits.exp != 0 && u.bits.exp != 2047);
+}
+
+int
+__isnormalf(float f)
+{
+ union IEEEf2bits u;
+
+ u.f = f;
+ return (u.bits.exp != 0 && u.bits.exp != 255);
+}
+
+int
+__isnormall(long double e)
+{
+ union IEEEl2bits u;
+
+ u.e = e;
+ return (u.bits.exp != 0 && u.bits.exp != 32767);
+}
diff --git a/lib/msun/src/s_llrint.c b/lib/msun/src/s_llrint.c
new file mode 100644
index 0000000..7c959ec
--- /dev/null
+++ b/lib/msun/src/s_llrint.c
@@ -0,0 +1,9 @@
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#define type double
+#define roundit rint
+#define dtype long long
+#define fn llrint
+
+#include "s_lrint.c"
diff --git a/lib/msun/src/s_llrintf.c b/lib/msun/src/s_llrintf.c
new file mode 100644
index 0000000..7ec6015
--- /dev/null
+++ b/lib/msun/src/s_llrintf.c
@@ -0,0 +1,9 @@
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#define type float
+#define roundit rintf
+#define dtype long long
+#define fn llrintf
+
+#include "s_lrint.c"
diff --git a/lib/msun/src/s_llround.c b/lib/msun/src/s_llround.c
new file mode 100644
index 0000000..827dfc1
--- /dev/null
+++ b/lib/msun/src/s_llround.c
@@ -0,0 +1,11 @@
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#define type double
+#define roundit round
+#define dtype long long
+#define DTYPE_MIN LLONG_MIN
+#define DTYPE_MAX LLONG_MAX
+#define fn llround
+
+#include "s_lround.c"
diff --git a/lib/msun/src/s_llroundf.c b/lib/msun/src/s_llroundf.c
new file mode 100644
index 0000000..c037a18
--- /dev/null
+++ b/lib/msun/src/s_llroundf.c
@@ -0,0 +1,11 @@
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#define type float
+#define roundit roundf
+#define dtype long long
+#define DTYPE_MIN LLONG_MIN
+#define DTYPE_MAX LLONG_MAX
+#define fn llroundf
+
+#include "s_lround.c"
diff --git a/lib/msun/src/s_llroundl.c b/lib/msun/src/s_llroundl.c
new file mode 100644
index 0000000..02c44eb
--- /dev/null
+++ b/lib/msun/src/s_llroundl.c
@@ -0,0 +1,11 @@
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#define type long double
+#define roundit roundl
+#define dtype long long
+#define DTYPE_MIN LLONG_MIN
+#define DTYPE_MAX LLONG_MAX
+#define fn llroundl
+
+#include "s_lround.c"
diff --git a/lib/msun/src/s_log1p.c b/lib/msun/src/s_log1p.c
new file mode 100644
index 0000000..0ee69a6
--- /dev/null
+++ b/lib/msun/src/s_log1p.c
@@ -0,0 +1,168 @@
+/* @(#)s_log1p.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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/* double log1p(double x)
+ *
+ * Method :
+ * 1. Argument Reduction: find k and f such that
+ * 1+x = 2^k * (1+f),
+ * where sqrt(2)/2 < 1+f < sqrt(2) .
+ *
+ * Note. If k=0, then f=x is exact. However, if k!=0, then f
+ * may not be representable exactly. In that case, a correction
+ * term is need. Let u=1+x rounded. Let c = (1+x)-u, then
+ * log(1+x) - log(u) ~ c/u. Thus, we proceed to compute log(u),
+ * and add back the correction term c/u.
+ * (Note: when x > 2**53, one can simply return log(x))
+ *
+ * 2. Approximation of log1p(f).
+ * Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s)
+ * = 2s + 2/3 s**3 + 2/5 s**5 + .....,
+ * = 2s + s*R
+ * We use a special Reme algorithm on [0,0.1716] to generate
+ * a polynomial of degree 14 to approximate R The maximum error
+ * of this polynomial approximation is bounded by 2**-58.45. In
+ * other words,
+ * 2 4 6 8 10 12 14
+ * R(z) ~ Lp1*s +Lp2*s +Lp3*s +Lp4*s +Lp5*s +Lp6*s +Lp7*s
+ * (the values of Lp1 to Lp7 are listed in the program)
+ * and
+ * | 2 14 | -58.45
+ * | Lp1*s +...+Lp7*s - R(z) | <= 2
+ * | |
+ * Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2.
+ * In order to guarantee error in log below 1ulp, we compute log
+ * by
+ * log1p(f) = f - (hfsq - s*(hfsq+R)).
+ *
+ * 3. Finally, log1p(x) = k*ln2 + log1p(f).
+ * = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo)))
+ * Here ln2 is split into two floating point number:
+ * ln2_hi + ln2_lo,
+ * where n*ln2_hi is always exact for |n| < 2000.
+ *
+ * Special cases:
+ * log1p(x) is NaN with signal if x < -1 (including -INF) ;
+ * log1p(+INF) is +INF; log1p(-1) is -INF with signal;
+ * log1p(NaN) is that NaN with no signal.
+ *
+ * Accuracy:
+ * according to an error analysis, the error is always less than
+ * 1 ulp (unit in the last place).
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following
+ * constants. The decimal values may be used, provided that the
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ *
+ * Note: Assuming log() return accurate answer, the following
+ * algorithm can be used to compute log1p(x) to within a few ULP:
+ *
+ * u = 1+x;
+ * if(u==1.0) return x ; else
+ * return log(u)*(x/(u-1.0));
+ *
+ * See HP-15C Advanced Functions Handbook, p.193.
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+static const double
+ln2_hi = 6.93147180369123816490e-01, /* 3fe62e42 fee00000 */
+ln2_lo = 1.90821492927058770002e-10, /* 3dea39ef 35793c76 */
+two54 = 1.80143985094819840000e+16, /* 43500000 00000000 */
+Lp1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */
+Lp2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */
+Lp3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */
+Lp4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */
+Lp5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */
+Lp6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */
+Lp7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */
+
+static const double zero = 0.0;
+
+double
+log1p(double x)
+{
+ double hfsq,f,c,s,z,R,u;
+ int32_t k,hx,hu,ax;
+
+ GET_HIGH_WORD(hx,x);
+ ax = hx&0x7fffffff;
+
+ k = 1;
+ if (hx < 0x3FDA827A) { /* 1+x < sqrt(2)+ */
+ if(ax>=0x3ff00000) { /* x <= -1.0 */
+ if(x==-1.0) return -two54/zero; /* log1p(-1)=+inf */
+ else return (x-x)/(x-x); /* log1p(x<-1)=NaN */
+ }
+ if(ax<0x3e200000) { /* |x| < 2**-29 */
+ if(two54+x>zero /* raise inexact */
+ &&ax<0x3c900000) /* |x| < 2**-54 */
+ return x;
+ else
+ return x - x*x*0.5;
+ }
+ if(hx>0||hx<=((int32_t)0xbfd2bec4)) {
+ k=0;f=x;hu=1;} /* sqrt(2)/2- <= 1+x < sqrt(2)+ */
+ }
+ if (hx >= 0x7ff00000) return x+x;
+ if(k!=0) {
+ if(hx<0x43400000) {
+ u = 1.0+x;
+ GET_HIGH_WORD(hu,u);
+ k = (hu>>20)-1023;
+ c = (k>0)? 1.0-(u-x):x-(u-1.0);/* correction term */
+ c /= u;
+ } else {
+ u = x;
+ GET_HIGH_WORD(hu,u);
+ k = (hu>>20)-1023;
+ c = 0;
+ }
+ hu &= 0x000fffff;
+ /*
+ * The approximation to sqrt(2) used in thresholds is not
+ * critical. However, the ones used above must give less
+ * strict bounds than the one here so that the k==0 case is
+ * never reached from here, since here we have committed to
+ * using the correction term but don't use it if k==0.
+ */
+ if(hu<0x6a09e) { /* u ~< sqrt(2) */
+ SET_HIGH_WORD(u,hu|0x3ff00000); /* normalize u */
+ } else {
+ k += 1;
+ SET_HIGH_WORD(u,hu|0x3fe00000); /* normalize u/2 */
+ hu = (0x00100000-hu)>>2;
+ }
+ f = u-1.0;
+ }
+ hfsq=0.5*f*f;
+ if(hu==0) { /* |f| < 2**-20 */
+ if(f==zero) if(k==0) return zero;
+ else {c += k*ln2_lo; return k*ln2_hi+c;}
+ R = hfsq*(1.0-0.66666666666666666*f);
+ if(k==0) return f-R; else
+ return k*ln2_hi-((R-(k*ln2_lo+c))-f);
+ }
+ s = f/(2.0+f);
+ z = s*s;
+ R = z*(Lp1+z*(Lp2+z*(Lp3+z*(Lp4+z*(Lp5+z*(Lp6+z*Lp7))))));
+ if(k==0) return f-(hfsq-s*(hfsq+R)); else
+ return k*ln2_hi-((hfsq-(s*(hfsq+R)+(k*ln2_lo+c)))-f);
+}
diff --git a/lib/msun/src/s_log1pf.c b/lib/msun/src/s_log1pf.c
new file mode 100644
index 0000000..eb0f4af
--- /dev/null
+++ b/lib/msun/src/s_log1pf.c
@@ -0,0 +1,107 @@
+/* s_log1pf.c -- float version of s_log1p.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+#include "math.h"
+#include "math_private.h"
+
+static const float
+ln2_hi = 6.9313812256e-01, /* 0x3f317180 */
+ln2_lo = 9.0580006145e-06, /* 0x3717f7d1 */
+two25 = 3.355443200e+07, /* 0x4c000000 */
+Lp1 = 6.6666668653e-01, /* 3F2AAAAB */
+Lp2 = 4.0000000596e-01, /* 3ECCCCCD */
+Lp3 = 2.8571429849e-01, /* 3E924925 */
+Lp4 = 2.2222198546e-01, /* 3E638E29 */
+Lp5 = 1.8183572590e-01, /* 3E3A3325 */
+Lp6 = 1.5313838422e-01, /* 3E1CD04F */
+Lp7 = 1.4798198640e-01; /* 3E178897 */
+
+static const float zero = 0.0;
+
+float
+log1pf(float x)
+{
+ float hfsq,f,c,s,z,R,u;
+ int32_t k,hx,hu,ax;
+
+ GET_FLOAT_WORD(hx,x);
+ ax = hx&0x7fffffff;
+
+ k = 1;
+ if (hx < 0x3ed413d0) { /* 1+x < sqrt(2)+ */
+ if(ax>=0x3f800000) { /* x <= -1.0 */
+ if(x==(float)-1.0) return -two25/zero; /* log1p(-1)=+inf */
+ else return (x-x)/(x-x); /* log1p(x<-1)=NaN */
+ }
+ if(ax<0x31000000) { /* |x| < 2**-29 */
+ if(two25+x>zero /* raise inexact */
+ &&ax<0x24800000) /* |x| < 2**-54 */
+ return x;
+ else
+ return x - x*x*(float)0.5;
+ }
+ if(hx>0||hx<=((int32_t)0xbe95f619)) {
+ k=0;f=x;hu=1;} /* sqrt(2)/2- <= 1+x < sqrt(2)+ */
+ }
+ if (hx >= 0x7f800000) return x+x;
+ if(k!=0) {
+ if(hx<0x5a000000) {
+ *(volatile float *)&u = (float)1.0+x;
+ GET_FLOAT_WORD(hu,u);
+ k = (hu>>23)-127;
+ /* correction term */
+ c = (k>0)? (float)1.0-(u-x):x-(u-(float)1.0);
+ c /= u;
+ } else {
+ u = x;
+ GET_FLOAT_WORD(hu,u);
+ k = (hu>>23)-127;
+ c = 0;
+ }
+ hu &= 0x007fffff;
+ /*
+ * The approximation to sqrt(2) used in thresholds is not
+ * critical. However, the ones used above must give less
+ * strict bounds than the one here so that the k==0 case is
+ * never reached from here, since here we have committed to
+ * using the correction term but don't use it if k==0.
+ */
+ if(hu<0x3504f4) { /* u < sqrt(2) */
+ SET_FLOAT_WORD(u,hu|0x3f800000);/* normalize u */
+ } else {
+ k += 1;
+ SET_FLOAT_WORD(u,hu|0x3f000000); /* normalize u/2 */
+ hu = (0x00800000-hu)>>2;
+ }
+ f = u-(float)1.0;
+ }
+ hfsq=(float)0.5*f*f;
+ if(hu==0) { /* |f| < 2**-20 */
+ if(f==zero) if(k==0) return zero;
+ else {c += k*ln2_lo; return k*ln2_hi+c;}
+ R = hfsq*((float)1.0-(float)0.66666666666666666*f);
+ if(k==0) return f-R; else
+ return k*ln2_hi-((R-(k*ln2_lo+c))-f);
+ }
+ s = f/((float)2.0+f);
+ z = s*s;
+ R = z*(Lp1+z*(Lp2+z*(Lp3+z*(Lp4+z*(Lp5+z*(Lp6+z*Lp7))))));
+ if(k==0) return f-(hfsq-s*(hfsq+R)); else
+ return k*ln2_hi-((hfsq-(s*(hfsq+R)+(k*ln2_lo+c)))-f);
+}
diff --git a/lib/msun/src/s_logb.c b/lib/msun/src/s_logb.c
new file mode 100644
index 0000000..f667bf2
--- /dev/null
+++ b/lib/msun/src/s_logb.c
@@ -0,0 +1,44 @@
+/* @(#)s_logb.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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/*
+ * double logb(x)
+ * IEEE 754 logb. Included to pass IEEE test suite. Not recommend.
+ * Use ilogb instead.
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+static const double
+two54 = 1.80143985094819840000e+16; /* 43500000 00000000 */
+
+double
+logb(double x)
+{
+ int32_t lx,ix;
+ EXTRACT_WORDS(ix,lx,x);
+ ix &= 0x7fffffff; /* high |x| */
+ if((ix|lx)==0) return -1.0/fabs(x);
+ if(ix>=0x7ff00000) return x*x;
+ if(ix<0x00100000) {
+ x *= two54; /* convert subnormal x to normal */
+ GET_FLOAT_WORD(ix,x);
+ ix &= 0x7fffffff;
+ return (float) ((ix>>20)-1023-54);
+ } else
+ return (double) ((ix>>20)-1023);
+}
diff --git a/lib/msun/src/s_logbf.c b/lib/msun/src/s_logbf.c
new file mode 100644
index 0000000..97ccd02
--- /dev/null
+++ b/lib/msun/src/s_logbf.c
@@ -0,0 +1,41 @@
+/* s_logbf.c -- float version of s_logb.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+#include "math.h"
+#include "math_private.h"
+
+static const float
+two25 = 3.355443200e+07; /* 0x4c000000 */
+
+float
+logbf(float x)
+{
+ int32_t ix;
+ GET_FLOAT_WORD(ix,x);
+ ix &= 0x7fffffff; /* high |x| */
+ if(ix==0) return (float)-1.0/fabsf(x);
+ if(ix>=0x7f800000) return x*x;
+ if(ix<0x00800000) {
+ x *= two25; /* convert subnormal x to normal */
+ GET_FLOAT_WORD(ix,x);
+ ix &= 0x7fffffff;
+ return (float) ((ix>>23)-127-25);
+ } else
+ return (float) ((ix>>23)-127);
+}
diff --git a/lib/msun/src/s_lrint.c b/lib/msun/src/s_lrint.c
new file mode 100644
index 0000000..27ff5ff
--- /dev/null
+++ b/lib/msun/src/s_lrint.c
@@ -0,0 +1,58 @@
+/*-
+ * 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>
+#include <fenv.h>
+#include <math.h>
+
+#ifndef type
+__FBSDID("$FreeBSD$");
+#define type double
+#define roundit rint
+#define dtype long
+#define fn lrint
+#endif
+
+/*
+ * C99 says we should not raise a spurious inexact exception when an
+ * invalid exception is raised. Unfortunately, the set of inputs
+ * that overflows depends on the rounding mode when 'dtype' has more
+ * significant bits than 'type'. Hence, we bend over backwards for the
+ * sake of correctness; an MD implementation could be more efficient.
+ */
+dtype
+fn(type x)
+{
+ fenv_t env;
+ dtype d;
+
+ feholdexcept(&env);
+ d = (dtype)roundit(x);
+ if (fetestexcept(FE_INVALID))
+ feclearexcept(FE_INEXACT);
+ feupdateenv(&env);
+ return (d);
+}
diff --git a/lib/msun/src/s_lrintf.c b/lib/msun/src/s_lrintf.c
new file mode 100644
index 0000000..a757ded
--- /dev/null
+++ b/lib/msun/src/s_lrintf.c
@@ -0,0 +1,9 @@
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#define type float
+#define roundit rintf
+#define dtype long
+#define fn lrintf
+
+#include "s_lrint.c"
diff --git a/lib/msun/src/s_lround.c b/lib/msun/src/s_lround.c
new file mode 100644
index 0000000..3cff489
--- /dev/null
+++ b/lib/msun/src/s_lround.c
@@ -0,0 +1,66 @@
+/*-
+ * 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>
+#include <sys/limits.h>
+#include <fenv.h>
+#include <math.h>
+
+#ifndef type
+__FBSDID("$FreeBSD$");
+#define type double
+#define roundit round
+#define dtype long
+#define DTYPE_MIN LONG_MIN
+#define DTYPE_MAX LONG_MAX
+#define fn lround
+#endif
+
+/*
+ * If type has more precision than dtype, the endpoints dtype_(min|max) are
+ * of the form xxx.5; they are "out of range" because lround() rounds away
+ * from 0. On the other hand, if type has less precision than dtype, then
+ * all values that are out of range are integral, so we might as well assume
+ * that everything is in range. At compile time, INRANGE(x) should reduce to
+ * two floating-point comparisons in the former case, or TRUE otherwise.
+ */
+static const type dtype_min = DTYPE_MIN - 0.5;
+static const type dtype_max = DTYPE_MAX + 0.5;
+#define INRANGE(x) (dtype_max - DTYPE_MAX != 0.5 || \
+ ((x) > dtype_min && (x) < dtype_max))
+
+dtype
+fn(type x)
+{
+
+ if (INRANGE(x)) {
+ x = roundit(x);
+ return ((dtype)x);
+ } else {
+ feraiseexcept(FE_INVALID);
+ return (DTYPE_MAX);
+ }
+}
diff --git a/lib/msun/src/s_lroundf.c b/lib/msun/src/s_lroundf.c
new file mode 100644
index 0000000..e24fe7f
--- /dev/null
+++ b/lib/msun/src/s_lroundf.c
@@ -0,0 +1,11 @@
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#define type float
+#define roundit roundf
+#define dtype long
+#define DTYPE_MIN LONG_MIN
+#define DTYPE_MAX LONG_MAX
+#define fn lroundf
+
+#include "s_lround.c"
diff --git a/lib/msun/src/s_lroundl.c b/lib/msun/src/s_lroundl.c
new file mode 100644
index 0000000..e410827
--- /dev/null
+++ b/lib/msun/src/s_lroundl.c
@@ -0,0 +1,11 @@
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#define type long double
+#define roundit roundl
+#define dtype long
+#define DTYPE_MIN LONG_MIN
+#define DTYPE_MAX LONG_MAX
+#define fn lroundl
+
+#include "s_lround.c"
diff --git a/lib/msun/src/s_modf.c b/lib/msun/src/s_modf.c
new file mode 100644
index 0000000..8cfe568
--- /dev/null
+++ b/lib/msun/src/s_modf.c
@@ -0,0 +1,75 @@
+/* @(#)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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/*
+ * 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 "math.h"
+#include "math_private.h"
+
+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;
+ *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/msun/src/s_modff.c b/lib/msun/src/s_modff.c
new file mode 100644
index 0000000..69b64e9
--- /dev/null
+++ b/lib/msun/src/s_modff.c
@@ -0,0 +1,56 @@
+/* s_modff.c -- float version of s_modf.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+#include "math.h"
+#include "math_private.h"
+
+static const float one = 1.0;
+
+float
+modff(float x, float *iptr)
+{
+ int32_t i0,j0;
+ u_int32_t i;
+ GET_FLOAT_WORD(i0,x);
+ j0 = ((i0>>23)&0xff)-0x7f; /* exponent of x */
+ if(j0<23) { /* integer part in x */
+ if(j0<0) { /* |x|<1 */
+ SET_FLOAT_WORD(*iptr,i0&0x80000000); /* *iptr = +-0 */
+ return x;
+ } else {
+ i = (0x007fffff)>>j0;
+ if((i0&i)==0) { /* x is integral */
+ u_int32_t ix;
+ *iptr = x;
+ GET_FLOAT_WORD(ix,x);
+ SET_FLOAT_WORD(x,ix&0x80000000); /* return +-0 */
+ return x;
+ } else {
+ SET_FLOAT_WORD(*iptr,i0&(~i));
+ return x - *iptr;
+ }
+ }
+ } else { /* no fraction part */
+ u_int32_t ix;
+ *iptr = x*one;
+ GET_FLOAT_WORD(ix,x);
+ SET_FLOAT_WORD(x,ix&0x80000000); /* return +-0 */
+ return x;
+ }
+}
diff --git a/lib/msun/src/s_nearbyint.c b/lib/msun/src/s_nearbyint.c
new file mode 100644
index 0000000..a075d2f
--- /dev/null
+++ b/lib/msun/src/s_nearbyint.c
@@ -0,0 +1,54 @@
+/*-
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <fenv.h>
+#include <math.h>
+
+/*
+ * We save and restore the floating-point environment to avoid raising
+ * an inexact exception. We can get away with using fesetenv()
+ * instead of feclearexcept()/feupdateenv() to restore the environment
+ * because the only exception defined for rint() is overflow, and
+ * rounding can't overflow as long as emax >= p.
+ */
+#define DECL(type, fn, rint) \
+type \
+fn(type x) \
+{ \
+ type ret; \
+ fenv_t env; \
+ \
+ fegetenv(&env); \
+ ret = rint(x); \
+ fesetenv(&env); \
+ return (ret); \
+}
+
+DECL(double, nearbyint, rint)
+DECL(float, nearbyintf, rintf)
diff --git a/lib/msun/src/s_nextafter.c b/lib/msun/src/s_nextafter.c
new file mode 100644
index 0000000..674e9c1
--- /dev/null
+++ b/lib/msun/src/s_nextafter.c
@@ -0,0 +1,85 @@
+/* @(#)s_nextafter.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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/* IEEE functions
+ * nextafter(x,y)
+ * return the next machine floating-point number of x in the
+ * direction toward y.
+ * Special cases:
+ */
+
+#include <sys/cdefs.h>
+#include <float.h>
+
+#include "math.h"
+#include "math_private.h"
+
+double
+nextafter(double x, double y)
+{
+ volatile double t;
+ int32_t hx,hy,ix,iy;
+ u_int32_t lx,ly;
+
+ EXTRACT_WORDS(hx,lx,x);
+ EXTRACT_WORDS(hy,ly,y);
+ ix = hx&0x7fffffff; /* |x| */
+ iy = hy&0x7fffffff; /* |y| */
+
+ if(((ix>=0x7ff00000)&&((ix-0x7ff00000)|lx)!=0) || /* x is nan */
+ ((iy>=0x7ff00000)&&((iy-0x7ff00000)|ly)!=0)) /* y is nan */
+ return x+y;
+ if(x==y) return y; /* x=y, return y */
+ if((ix|lx)==0) { /* x == 0 */
+ INSERT_WORDS(x,hy&0x80000000,1); /* return +-minsubnormal */
+ t = x*x;
+ if(t==x) return t; else return x; /* raise underflow flag */
+ }
+ if(hx>=0) { /* x > 0 */
+ if(hx>hy||((hx==hy)&&(lx>ly))) { /* x > y, x -= ulp */
+ if(lx==0) hx -= 1;
+ lx -= 1;
+ } else { /* x < y, x += ulp */
+ lx += 1;
+ if(lx==0) hx += 1;
+ }
+ } else { /* x < 0 */
+ if(hy>=0||hx>hy||((hx==hy)&&(lx>ly))){/* x < y, x -= ulp */
+ if(lx==0) hx -= 1;
+ lx -= 1;
+ } else { /* x > y, x += ulp */
+ lx += 1;
+ if(lx==0) hx += 1;
+ }
+ }
+ hy = hx&0x7ff00000;
+ if(hy>=0x7ff00000) return x+x; /* overflow */
+ if(hy<0x00100000) { /* underflow */
+ t = x*x;
+ if(t!=x) { /* raise underflow flag */
+ INSERT_WORDS(y,hx,lx);
+ return y;
+ }
+ }
+ INSERT_WORDS(x,hx,lx);
+ return x;
+}
+
+#if (LDBL_MANT_DIG == 53)
+__weak_reference(nextafter, nexttoward);
+__weak_reference(nextafter, nexttowardl);
+__weak_reference(nextafter, nextafterl);
+#endif
diff --git a/lib/msun/src/s_nextafterf.c b/lib/msun/src/s_nextafterf.c
new file mode 100644
index 0000000..b8a1125
--- /dev/null
+++ b/lib/msun/src/s_nextafterf.c
@@ -0,0 +1,67 @@
+/* s_nextafterf.c -- float version of s_nextafter.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+#include "math.h"
+#include "math_private.h"
+
+float
+nextafterf(float x, float y)
+{
+ volatile float t;
+ int32_t hx,hy,ix,iy;
+
+ GET_FLOAT_WORD(hx,x);
+ GET_FLOAT_WORD(hy,y);
+ ix = hx&0x7fffffff; /* |x| */
+ iy = hy&0x7fffffff; /* |y| */
+
+ if((ix>0x7f800000) || /* x is nan */
+ (iy>0x7f800000)) /* y is nan */
+ return x+y;
+ if(x==y) return y; /* x=y, return y */
+ if(ix==0) { /* x == 0 */
+ SET_FLOAT_WORD(x,(hy&0x80000000)|1);/* return +-minsubnormal */
+ t = x*x;
+ if(t==x) return t; else return x; /* raise underflow flag */
+ }
+ if(hx>=0) { /* x > 0 */
+ if(hx>hy) { /* x > y, x -= ulp */
+ hx -= 1;
+ } else { /* x < y, x += ulp */
+ hx += 1;
+ }
+ } else { /* x < 0 */
+ if(hy>=0||hx>hy){ /* x < y, x -= ulp */
+ hx -= 1;
+ } else { /* x > y, x += ulp */
+ hx += 1;
+ }
+ }
+ hy = hx&0x7f800000;
+ if(hy>=0x7f800000) return x+x; /* overflow */
+ if(hy<0x00800000) { /* underflow */
+ t = x*x;
+ if(t!=x) { /* raise underflow flag */
+ SET_FLOAT_WORD(y,hx);
+ return y;
+ }
+ }
+ SET_FLOAT_WORD(x,hx);
+ return x;
+}
diff --git a/lib/msun/src/s_nextafterl.c b/lib/msun/src/s_nextafterl.c
new file mode 100644
index 0000000..a74dd79
--- /dev/null
+++ b/lib/msun/src/s_nextafterl.c
@@ -0,0 +1,82 @@
+/* @(#)s_nextafter.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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/* IEEE functions
+ * nextafter(x,y)
+ * return the next machine floating-point number of x in the
+ * direction toward y.
+ * Special cases:
+ */
+
+#include <sys/cdefs.h>
+#include <float.h>
+
+#include "fpmath.h"
+#include "math.h"
+#include "math_private.h"
+
+#if LDBL_MAX_EXP != 0x4000
+#error "Unsupported long double format"
+#endif
+
+long double
+nextafterl(long double x, long double y)
+{
+ volatile long double t;
+ union IEEEl2bits ux, uy;
+
+ ux.e = x;
+ uy.e = y;
+
+ if ((ux.bits.exp == 0x7fff &&
+ ((ux.bits.manh&~LDBL_NBIT)|ux.bits.manl) != 0) ||
+ (uy.bits.exp == 0x7fff &&
+ ((uy.bits.manh&~LDBL_NBIT)|uy.bits.manl) != 0))
+ return x+y; /* x or y is nan */
+ if(x==y) return y; /* x=y, return y */
+ if(x==0.0) {
+ ux.bits.manh = 0; /* return +-minsubnormal */
+ ux.bits.manl = 1;
+ ux.bits.sign = uy.bits.sign;
+ t = ux.e*ux.e;
+ if(t==ux.e) return t; else return ux.e; /* raise underflow flag */
+ }
+ if(x>0.0 ^ x<y) { /* x -= ulp */
+ if(ux.bits.manl==0) {
+ if ((ux.bits.manh&~LDBL_NBIT)==0)
+ ux.bits.exp -= 1;
+ ux.bits.manh = (ux.bits.manh - 1) | (ux.bits.manh & LDBL_NBIT);
+ }
+ ux.bits.manl -= 1;
+ } else { /* x += ulp */
+ ux.bits.manl += 1;
+ if(ux.bits.manl==0) {
+ ux.bits.manh = (ux.bits.manh + 1) | (ux.bits.manh & LDBL_NBIT);
+ if ((ux.bits.manh&~LDBL_NBIT)==0)
+ ux.bits.exp += 1;
+ }
+ }
+ if(ux.bits.exp==0x7fff) return x+x; /* overflow */
+ if(ux.bits.exp==0) { /* underflow */
+ mask_nbit_l(ux);
+ t = ux.e * ux.e;
+ if(t!=ux.e) /* raise underflow flag */
+ return ux.e;
+ }
+ return ux.e;
+}
+
+__strong_reference(nextafterl, nexttowardl);
diff --git a/lib/msun/src/s_nexttoward.c b/lib/msun/src/s_nexttoward.c
new file mode 100644
index 0000000..a493c83
--- /dev/null
+++ b/lib/msun/src/s_nexttoward.c
@@ -0,0 +1,73 @@
+/* @(#)s_nextafter.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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/*
+ * We assume that a long double has a 15-bit exponent. On systems
+ * where long double is the same as double, nexttoward() is an alias
+ * for nextafter(), so we don't use this routine.
+ */
+
+#include <float.h>
+
+#include "fpmath.h"
+#include "math.h"
+#include "math_private.h"
+
+#if LDBL_MAX_EXP != 0x4000
+#error "Unsupported long double format"
+#endif
+
+double
+nexttoward(double x, long double y)
+{
+ union IEEEl2bits uy;
+ volatile double t;
+ int32_t hx,ix;
+ u_int32_t lx;
+
+ EXTRACT_WORDS(hx,lx,x);
+ ix = hx&0x7fffffff; /* |x| */
+ uy.e = y;
+
+ if(((ix>=0x7ff00000)&&((ix-0x7ff00000)|lx)!=0) ||
+ (uy.bits.exp == 0x7fff &&
+ ((uy.bits.manh&~LDBL_NBIT)|uy.bits.manl) != 0))
+ return x+y; /* x or y is nan */
+ if(x==y) return (double)y; /* x=y, return y */
+ if(x==0.0) {
+ INSERT_WORDS(x,uy.bits.sign<<31,1); /* return +-minsubnormal */
+ t = x*x;
+ if(t==x) return t; else return x; /* raise underflow flag */
+ }
+ if(hx>0.0 ^ x < y) { /* x -= ulp */
+ if(lx==0) hx -= 1;
+ lx -= 1;
+ } else { /* x += ulp */
+ lx += 1;
+ if(lx==0) hx += 1;
+ }
+ ix = hx&0x7ff00000;
+ if(ix>=0x7ff00000) return x+x; /* overflow */
+ if(ix<0x00100000) { /* underflow */
+ t = x*x;
+ if(t!=x) { /* raise underflow flag */
+ INSERT_WORDS(y,hx,lx);
+ return y;
+ }
+ }
+ INSERT_WORDS(x,hx,lx);
+ return x;
+}
diff --git a/lib/msun/src/s_nexttowardf.c b/lib/msun/src/s_nexttowardf.c
new file mode 100644
index 0000000..38005ae
--- /dev/null
+++ b/lib/msun/src/s_nexttowardf.c
@@ -0,0 +1,60 @@
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+#include <float.h>
+
+#include "fpmath.h"
+#include "math.h"
+#include "math_private.h"
+
+#define LDBL_INFNAN_EXP (LDBL_MAX_EXP * 2 - 1)
+
+float
+nexttowardf(float x, long double y)
+{
+ union IEEEl2bits uy;
+ volatile float t;
+ int32_t hx,ix;
+
+ GET_FLOAT_WORD(hx,x);
+ ix = hx&0x7fffffff; /* |x| */
+ uy.e = y;
+
+ if((ix>0x7f800000) ||
+ (uy.bits.exp == LDBL_INFNAN_EXP &&
+ ((uy.bits.manh&~LDBL_NBIT)|uy.bits.manl) != 0))
+ return x+y; /* x or y is nan */
+ if(x==y) return (float)y; /* x=y, return y */
+ if(ix==0) { /* x == 0 */
+ SET_FLOAT_WORD(x,(uy.bits.sign<<31)|1);/* return +-minsubnormal */
+ t = x*x;
+ if(t==x) return t; else return x; /* raise underflow flag */
+ }
+ if(hx>=0 ^ x < y) /* x -= ulp */
+ hx -= 1;
+ else /* x += ulp */
+ hx += 1;
+ ix = hx&0x7f800000;
+ if(ix>=0x7f800000) return x+x; /* overflow */
+ if(ix<0x00800000) { /* underflow */
+ t = x*x;
+ if(t!=x) { /* raise underflow flag */
+ SET_FLOAT_WORD(y,hx);
+ return y;
+ }
+ }
+ SET_FLOAT_WORD(x,hx);
+ return x;
+}
diff --git a/lib/msun/src/s_remquo.c b/lib/msun/src/s_remquo.c
new file mode 100644
index 0000000..8756c2a
--- /dev/null
+++ b/lib/msun/src/s_remquo.c
@@ -0,0 +1,152 @@
+/* @(#)e_fmod.c 1.3 95/01/18 */
+/*-
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "math.h"
+#include "math_private.h"
+
+static const double Zero[] = {0.0, -0.0,};
+
+/*
+ * Return the IEEE remainder and set *quo to the last n bits of the
+ * quotient, rounded to the nearest integer. We choose n=31 because
+ * we wind up computing all the integer bits of the quotient anyway as
+ * a side-effect of computing the remainder by the shift and subtract
+ * method. In practice, this is far more bits than are needed to use
+ * remquo in reduction algorithms.
+ */
+double
+remquo(double x, double y, int *quo)
+{
+ int32_t n,hx,hy,hz,ix,iy,sx,i;
+ u_int32_t lx,ly,lz,q,sxy;
+
+ EXTRACT_WORDS(hx,lx,x);
+ EXTRACT_WORDS(hy,ly,y);
+ sxy = (hx ^ hy) & 0x80000000;
+ sx = hx&0x80000000; /* sign of x */
+ hx ^=sx; /* |x| */
+ hy &= 0x7fffffff; /* |y| */
+
+ /* purge off exception values */
+ if((hy|ly)==0||(hx>=0x7ff00000)|| /* y=0,or x not finite */
+ ((hy|((ly|-ly)>>31))>0x7ff00000)) /* or y is NaN */
+ return (x*y)/(x*y);
+ if(hx<=hy) {
+ if((hx<hy)||(lx<ly)) {
+ q = 0;
+ goto fixup; /* |x|<|y| return x or x-y */
+ }
+ if(lx==ly) {
+ *quo = 1;
+ return Zero[(u_int32_t)sx>>31]; /* |x|=|y| return x*0*/
+ }
+ }
+
+ /* determine ix = ilogb(x) */
+ if(hx<0x00100000) { /* subnormal x */
+ if(hx==0) {
+ for (ix = -1043, i=lx; i>0; i<<=1) ix -=1;
+ } else {
+ for (ix = -1022,i=(hx<<11); i>0; i<<=1) ix -=1;
+ }
+ } else ix = (hx>>20)-1023;
+
+ /* determine iy = ilogb(y) */
+ if(hy<0x00100000) { /* subnormal y */
+ if(hy==0) {
+ for (iy = -1043, i=ly; i>0; i<<=1) iy -=1;
+ } else {
+ for (iy = -1022,i=(hy<<11); i>0; i<<=1) iy -=1;
+ }
+ } else iy = (hy>>20)-1023;
+
+ /* set up {hx,lx}, {hy,ly} and align y to x */
+ if(ix >= -1022)
+ hx = 0x00100000|(0x000fffff&hx);
+ else { /* subnormal x, shift x to normal */
+ n = -1022-ix;
+ if(n<=31) {
+ hx = (hx<<n)|(lx>>(32-n));
+ lx <<= n;
+ } else {
+ hx = lx<<(n-32);
+ lx = 0;
+ }
+ }
+ if(iy >= -1022)
+ hy = 0x00100000|(0x000fffff&hy);
+ else { /* subnormal y, shift y to normal */
+ n = -1022-iy;
+ if(n<=31) {
+ hy = (hy<<n)|(ly>>(32-n));
+ ly <<= n;
+ } else {
+ hy = ly<<(n-32);
+ ly = 0;
+ }
+ }
+
+ /* fix point fmod */
+ n = ix - iy;
+ q = 0;
+ while(n--) {
+ hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
+ if(hz<0){hx = hx+hx+(lx>>31); lx = lx+lx;}
+ else {hx = hz+hz+(lz>>31); lx = lz+lz; q++;}
+ q <<= 1;
+ }
+ hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
+ if(hz>=0) {hx=hz;lx=lz;q++;}
+
+ /* convert back to floating value and restore the sign */
+ if((hx|lx)==0) { /* return sign(x)*0 */
+ *quo = (sxy ? -q : q);
+ return Zero[(u_int32_t)sx>>31];
+ }
+ while(hx<0x00100000) { /* normalize x */
+ hx = hx+hx+(lx>>31); lx = lx+lx;
+ iy -= 1;
+ }
+ if(iy>= -1022) { /* normalize output */
+ hx = ((hx-0x00100000)|((iy+1023)<<20));
+ } else { /* subnormal output */
+ n = -1022 - iy;
+ if(n<=20) {
+ lx = (lx>>n)|((u_int32_t)hx<<(32-n));
+ hx >>= n;
+ } else if (n<=31) {
+ lx = (hx<<(32-n))|(lx>>n); hx = sx;
+ } else {
+ lx = hx>>(n-32); hx = sx;
+ }
+ }
+fixup:
+ INSERT_WORDS(x,hx,lx);
+ y = fabs(y);
+ if (y < 0x1p-1021) {
+ if (x+x>y || (x+x==y && (q & 1))) {
+ q++;
+ x-=y;
+ }
+ } else if (x>0.5*y || (x==0.5*y && (q & 1))) {
+ q++;
+ x-=y;
+ }
+ GET_HIGH_WORD(hx,x);
+ SET_HIGH_WORD(x,hx^sx);
+ q &= 0x7fffffff;
+ *quo = (sxy ? -q : q);
+ return x;
+}
diff --git a/lib/msun/src/s_remquof.c b/lib/msun/src/s_remquof.c
new file mode 100644
index 0000000..3141642
--- /dev/null
+++ b/lib/msun/src/s_remquof.c
@@ -0,0 +1,121 @@
+/* @(#)e_fmod.c 1.3 95/01/18 */
+/*-
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "math.h"
+#include "math_private.h"
+
+static const float Zero[] = {0.0, -0.0,};
+
+/*
+ * Return the IEEE remainder and set *quo to the last n bits of the
+ * quotient, rounded to the nearest integer. We choose n=31 because
+ * we wind up computing all the integer bits of the quotient anyway as
+ * a side-effect of computing the remainder by the shift and subtract
+ * method. In practice, this is far more bits than are needed to use
+ * remquo in reduction algorithms.
+ */
+float
+remquof(float x, float y, int *quo)
+{
+ int32_t n,hx,hy,hz,ix,iy,sx,i;
+ u_int32_t q,sxy;
+
+ GET_FLOAT_WORD(hx,x);
+ GET_FLOAT_WORD(hy,y);
+ sxy = (hx ^ hy) & 0x80000000;
+ sx = hx&0x80000000; /* sign of x */
+ hx ^=sx; /* |x| */
+ hy &= 0x7fffffff; /* |y| */
+
+ /* purge off exception values */
+ if(hy==0||hx>=0x7f800000||hy>0x7f800000) /* y=0,NaN;or x not finite */
+ return (x*y)/(x*y);
+ if(hx<hy) {
+ q = 0;
+ goto fixup; /* |x|<|y| return x or x-y */
+ } else if(hx==hy) {
+ *quo = 1;
+ return Zero[(u_int32_t)sx>>31]; /* |x|=|y| return x*0*/
+ }
+
+ /* determine ix = ilogb(x) */
+ if(hx<0x00800000) { /* subnormal x */
+ for (ix = -126,i=(hx<<8); i>0; i<<=1) ix -=1;
+ } else ix = (hx>>23)-127;
+
+ /* determine iy = ilogb(y) */
+ if(hy<0x00800000) { /* subnormal y */
+ for (iy = -126,i=(hy<<8); i>0; i<<=1) iy -=1;
+ } else iy = (hy>>23)-127;
+
+ /* set up {hx,lx}, {hy,ly} and align y to x */
+ if(ix >= -126)
+ hx = 0x00800000|(0x007fffff&hx);
+ else { /* subnormal x, shift x to normal */
+ n = -126-ix;
+ hx <<= n;
+ }
+ if(iy >= -126)
+ hy = 0x00800000|(0x007fffff&hy);
+ else { /* subnormal y, shift y to normal */
+ n = -126-iy;
+ hy <<= n;
+ }
+
+ /* fix point fmod */
+ n = ix - iy;
+ q = 0;
+ while(n--) {
+ hz=hx-hy;
+ if(hz<0) hx = hx << 1;
+ else {hx = hz << 1; q++;}
+ q <<= 1;
+ }
+ hz=hx-hy;
+ if(hz>=0) {hx=hz;q++;}
+
+ /* convert back to floating value and restore the sign */
+ if(hx==0) { /* return sign(x)*0 */
+ *quo = (sxy ? -q : q);
+ return Zero[(u_int32_t)sx>>31];
+ }
+ while(hx<0x00800000) { /* normalize x */
+ hx <<= 1;
+ iy -= 1;
+ }
+ if(iy>= -126) { /* normalize output */
+ hx = ((hx-0x00800000)|((iy+127)<<23));
+ } else { /* subnormal output */
+ n = -126 - iy;
+ hx >>= n;
+ }
+fixup:
+ SET_FLOAT_WORD(x,hx);
+ y = fabsf(y);
+ if (y < 0x1p-125f) {
+ if (x+x>y || (x+x==y && (q & 1))) {
+ q++;
+ x-=y;
+ }
+ } else if (x>0.5f*y || (x==0.5f*y && (q & 1))) {
+ q++;
+ x-=y;
+ }
+ GET_FLOAT_WORD(hx,x);
+ SET_FLOAT_WORD(x,hx^sx);
+ q &= 0x7fffffff;
+ *quo = (sxy ? -q : q);
+ return x;
+}
diff --git a/lib/msun/src/s_rint.c b/lib/msun/src/s_rint.c
new file mode 100644
index 0000000..0a7bfc4
--- /dev/null
+++ b/lib/msun/src/s_rint.c
@@ -0,0 +1,87 @@
+/* @(#)s_rint.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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/*
+ * rint(x)
+ * Return x rounded to integral value according to the prevailing
+ * rounding mode.
+ * Method:
+ * Using floating addition.
+ * Exception:
+ * Inexact flag raised if x not equal to rint(x).
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+static const double
+TWO52[2]={
+ 4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */
+ -4.50359962737049600000e+15, /* 0xC3300000, 0x00000000 */
+};
+
+double
+rint(double x)
+{
+ int32_t i0,j0,sx;
+ u_int32_t i,i1;
+ double w,t;
+ EXTRACT_WORDS(i0,i1,x);
+ sx = (i0>>31)&1;
+ j0 = ((i0>>20)&0x7ff)-0x3ff;
+ if(j0<20) {
+ if(j0<0) {
+ if(((i0&0x7fffffff)|i1)==0) return x;
+ i1 |= (i0&0x0fffff);
+ i0 &= 0xfffe0000;
+ i0 |= ((i1|-i1)>>12)&0x80000;
+ SET_HIGH_WORD(x,i0);
+ w = TWO52[sx]+x;
+ t = w-TWO52[sx];
+ GET_HIGH_WORD(i0,t);
+ SET_HIGH_WORD(t,(i0&0x7fffffff)|(sx<<31));
+ return t;
+ } else {
+ i = (0x000fffff)>>j0;
+ if(((i0&i)|i1)==0) return x; /* x is integral */
+ i>>=1;
+ if(((i0&i)|i1)!=0) {
+ /*
+ * Some bit is set after the 0.5 bit. To avoid the
+ * possibility of errors from double rounding in
+ * w = TWO52[sx]+x, adjust the 0.25 bit to a lower
+ * guard bit. We do this for all j0<=51. The
+ * adjustment is trickiest for j0==18 and j0==19
+ * since then it spans the word boundary.
+ */
+ if(j0==19) i1 = 0x40000000; else
+ if(j0==18) i1 = 0x80000000; else
+ i0 = (i0&(~i))|((0x20000)>>j0);
+ }
+ }
+ } else if (j0>51) {
+ if(j0==0x400) return x+x; /* inf or NaN */
+ else return x; /* x is integral */
+ } else {
+ i = ((u_int32_t)(0xffffffff))>>(j0-20);
+ if((i1&i)==0) return x; /* x is integral */
+ i>>=1;
+ if((i1&i)!=0) i1 = (i1&(~i))|((0x40000000)>>(j0-20));
+ }
+ INSERT_WORDS(x,i0,i1);
+ *(volatile double *)&w = TWO52[sx]+x; /* clip any extra precision */
+ return w-TWO52[sx];
+}
diff --git a/lib/msun/src/s_rintf.c b/lib/msun/src/s_rintf.c
new file mode 100644
index 0000000..32697fb
--- /dev/null
+++ b/lib/msun/src/s_rintf.c
@@ -0,0 +1,52 @@
+/* s_rintf.c -- float version of s_rint.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+#include <sys/types.h>
+#include "math.h"
+#include "math_private.h"
+
+static const float
+TWO23[2]={
+ 8.3886080000e+06, /* 0x4b000000 */
+ -8.3886080000e+06, /* 0xcb000000 */
+};
+
+float
+rintf(float x)
+{
+ int32_t i0,j0,sx;
+ volatile float w,t; /* volatile works around gcc bug */
+ GET_FLOAT_WORD(i0,x);
+ sx = (i0>>31)&1;
+ j0 = ((i0>>23)&0xff)-0x7f;
+ if(j0<23) {
+ if(j0<0) {
+ if((i0&0x7fffffff)==0) return x;
+ w = TWO23[sx]+x;
+ t = w-TWO23[sx];
+ GET_FLOAT_WORD(i0,t);
+ SET_FLOAT_WORD(t,(i0&0x7fffffff)|(sx<<31));
+ return t;
+ }
+ w = TWO23[sx]+x;
+ return w-TWO23[sx];
+ }
+ if(j0==0x80) return x+x; /* inf or NaN */
+ else return x; /* x is integral */
+}
diff --git a/lib/msun/src/s_round.c b/lib/msun/src/s_round.c
new file mode 100644
index 0000000..65de31b
--- /dev/null
+++ b/lib/msun/src/s_round.c
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 2003, Steven G. Kargl
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, 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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, 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 <math.h>
+
+double
+round(double x)
+{
+ double t;
+
+ if (!isfinite(x))
+ return (x);
+
+ if (x >= 0.0) {
+ t = floor(x);
+ if (t - x <= -0.5)
+ t += 1.0;
+ return (t);
+ } else {
+ t = floor(-x);
+ if (t + x <= -0.5)
+ t += 1.0;
+ return (-t);
+ }
+}
diff --git a/lib/msun/src/s_roundf.c b/lib/msun/src/s_roundf.c
new file mode 100644
index 0000000..952e8e7
--- /dev/null
+++ b/lib/msun/src/s_roundf.c
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 2003, Steven G. Kargl
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, 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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, 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 <math.h>
+
+float
+roundf(float x)
+{
+ float t;
+
+ if (!isfinite(x))
+ return (x);
+
+ if (x >= 0.0) {
+ t = floorf(x);
+ if (t - x <= -0.5)
+ t += 1.0;
+ return (t);
+ } else {
+ t = floorf(-x);
+ if (t + x <= -0.5)
+ t += 1.0;
+ return (-t);
+ }
+}
diff --git a/lib/msun/src/s_roundl.c b/lib/msun/src/s_roundl.c
new file mode 100644
index 0000000..a70b617
--- /dev/null
+++ b/lib/msun/src/s_roundl.c
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 2003, Steven G. Kargl
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, 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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, 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 <math.h>
+
+long double
+roundl(long double x)
+{
+ long double t;
+
+ if (!isfinite(x))
+ return (x);
+
+ if (x >= 0.0) {
+ t = floorl(x);
+ if (t - x <= -0.5)
+ t += 1.0;
+ return (t);
+ } else {
+ t = floorl(-x);
+ if (t + x <= -0.5)
+ t += 1.0;
+ return (-t);
+ }
+}
diff --git a/lib/msun/src/s_scalbln.c b/lib/msun/src/s_scalbln.c
new file mode 100644
index 0000000..d609d4e
--- /dev/null
+++ b/lib/msun/src/s_scalbln.c
@@ -0,0 +1,76 @@
+/*-
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <limits.h>
+#include <math.h>
+
+double
+scalbln (double x, long n)
+{
+ int in;
+
+ in = (int)n;
+ if (in != n) {
+ if (n > 0)
+ in = INT_MAX;
+ else
+ in = INT_MIN;
+ }
+ return (scalbn(x, in));
+}
+
+float
+scalblnf (float x, long n)
+{
+ int in;
+
+ in = (int)n;
+ if (in != n) {
+ if (n > 0)
+ in = INT_MAX;
+ else
+ in = INT_MIN;
+ }
+ return (scalbnf(x, in));
+}
+
+long double
+scalblnl (long double x, long n)
+{
+ int in;
+
+ in = (int)n;
+ if (in != n) {
+ if (n > 0)
+ in = INT_MAX;
+ else
+ in = INT_MIN;
+ }
+ return (scalbnl(x, (int)n));
+}
diff --git a/lib/msun/src/s_scalbn.c b/lib/msun/src/s_scalbn.c
new file mode 100644
index 0000000..e7efaab
--- /dev/null
+++ b/lib/msun/src/s_scalbn.c
@@ -0,0 +1,66 @@
+/* @(#)s_scalbn.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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/*
+ * scalbn (double x, int n)
+ * scalbn(x,n) returns x* 2**n computed by exponent
+ * manipulation rather than by actually performing an
+ * exponentiation or a multiplication.
+ */
+
+#include <sys/cdefs.h>
+#include <float.h>
+
+#include "math.h"
+#include "math_private.h"
+
+static const double
+two54 = 1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */
+twom54 = 5.55111512312578270212e-17, /* 0x3C900000, 0x00000000 */
+huge = 1.0e+300,
+tiny = 1.0e-300;
+
+double
+scalbn (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;
+}
+
+#if (LDBL_MANT_DIG == 53)
+__weak_reference(scalbn, ldexpl);
+__weak_reference(scalbn, scalbnl);
+#endif
diff --git a/lib/msun/src/s_scalbnf.c b/lib/msun/src/s_scalbnf.c
new file mode 100644
index 0000000..7666c74
--- /dev/null
+++ b/lib/msun/src/s_scalbnf.c
@@ -0,0 +1,58 @@
+/* s_scalbnf.c -- float version of s_scalbn.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+#include <sys/cdefs.h>
+
+#include "math.h"
+#include "math_private.h"
+
+static const float
+two25 = 3.355443200e+07, /* 0x4c000000 */
+twom25 = 2.9802322388e-08, /* 0x33000000 */
+huge = 1.0e+30,
+tiny = 1.0e-30;
+
+float
+scalbnf (float x, int n)
+{
+ int32_t k,ix;
+ GET_FLOAT_WORD(ix,x);
+ k = (ix&0x7f800000)>>23; /* extract exponent */
+ if (k==0) { /* 0 or subnormal x */
+ if ((ix&0x7fffffff)==0) return x; /* +-0 */
+ x *= two25;
+ GET_FLOAT_WORD(ix,x);
+ k = ((ix&0x7f800000)>>23) - 25;
+ if (n< -50000) return tiny*x; /*underflow*/
+ }
+ if (k==0xff) return x+x; /* NaN or Inf */
+ k = k+n;
+ if (k > 0xfe) return huge*copysignf(huge,x); /* overflow */
+ if (k > 0) /* normal result */
+ {SET_FLOAT_WORD(x,(ix&0x807fffff)|(k<<23)); return x;}
+ if (k <= -25)
+ if (n > 50000) /* in case integer overflow in n+k */
+ return huge*copysignf(huge,x); /*overflow*/
+ else return tiny*copysignf(tiny,x); /*underflow*/
+ k += 25; /* subnormal result */
+ SET_FLOAT_WORD(x,(ix&0x807fffff)|(k<<23));
+ return x*twom25;
+}
+
+__strong_reference(scalbnf, ldexpf);
diff --git a/lib/msun/src/s_scalbnl.c b/lib/msun/src/s_scalbnl.c
new file mode 100644
index 0000000..fc89f8d
--- /dev/null
+++ b/lib/msun/src/s_scalbnl.c
@@ -0,0 +1,71 @@
+/* @(#)s_scalbn.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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/*
+ * scalbnl (long double x, int n)
+ * scalbnl(x,n) returns x* 2**n computed by exponent
+ * manipulation rather than by actually performing an
+ * exponentiation or a multiplication.
+ */
+
+/*
+ * We assume that a long double has a 15-bit exponent. On systems
+ * where long double is the same as double, scalbnl() is an alias
+ * for scalbn(), so we don't use this routine.
+ */
+
+#include <sys/cdefs.h>
+#include <float.h>
+#include <math.h>
+
+#include "fpmath.h"
+
+#if LDBL_MAX_EXP != 0x4000
+#error "Unsupported long double format"
+#endif
+
+static const long double
+huge = 0x1p16000L,
+tiny = 0x1p-16000L;
+
+long double
+scalbnl (long double x, int n)
+{
+ union IEEEl2bits u;
+ int k;
+ u.e = x;
+ k = u.bits.exp; /* extract exponent */
+ if (k==0) { /* 0 or subnormal x */
+ if ((u.bits.manh|u.bits.manl)==0) return x; /* +-0 */
+ u.e *= 0x1p+128;
+ k = u.bits.exp - 128;
+ if (n< -50000) return tiny*x; /*underflow*/
+ }
+ if (k==0x7fff) return x+x; /* NaN or Inf */
+ k = k+n;
+ if (k >= 0x7fff) return huge*copysignl(huge,x); /* overflow */
+ if (k > 0) /* normal result */
+ {u.bits.exp = k; return u.e;}
+ if (k <= -128)
+ if (n > 50000) /* in case integer overflow in n+k */
+ return huge*copysign(huge,x); /*overflow*/
+ else return tiny*copysign(tiny,x); /*underflow*/
+ k += 128; /* subnormal result */
+ u.bits.exp = k;
+ return u.e*0x1p-128;
+}
+
+__strong_reference(scalbnl, ldexpl);
diff --git a/lib/msun/src/s_signbit.c b/lib/msun/src/s_signbit.c
new file mode 100644
index 0000000..01eb3ab
--- /dev/null
+++ b/lib/msun/src/s_signbit.c
@@ -0,0 +1,58 @@
+/*-
+ * 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 "fpmath.h"
+
+int
+__signbit(double d)
+{
+ union IEEEd2bits u;
+
+ u.d = d;
+ return (u.bits.sign);
+}
+
+int
+__signbitf(float f)
+{
+ union IEEEf2bits u;
+
+ u.f = f;
+ return (u.bits.sign);
+}
+
+int
+__signbitl(long double e)
+{
+ union IEEEl2bits u;
+
+ u.e = e;
+ return (u.bits.sign);
+}
diff --git a/lib/msun/src/s_signgam.c b/lib/msun/src/s_signgam.c
new file mode 100644
index 0000000..d67d591
--- /dev/null
+++ b/lib/msun/src/s_signgam.c
@@ -0,0 +1,3 @@
+#include "math.h"
+#include "math_private.h"
+int signgam = 0;
diff --git a/lib/msun/src/s_significand.c b/lib/msun/src/s_significand.c
new file mode 100644
index 0000000..a91bcde
--- /dev/null
+++ b/lib/msun/src/s_significand.c
@@ -0,0 +1,30 @@
+/* @(#)s_signif.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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/*
+ * significand(x) computes just
+ * scalb(x, (double) -ilogb(x)),
+ * for exercising the fraction-part(F) IEEE 754-1985 test vector.
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+double
+significand(double x)
+{
+ return __ieee754_scalb(x,(double) -ilogb(x));
+}
diff --git a/lib/msun/src/s_significandf.c b/lib/msun/src/s_significandf.c
new file mode 100644
index 0000000..c11a089
--- /dev/null
+++ b/lib/msun/src/s_significandf.c
@@ -0,0 +1,27 @@
+/* s_significandf.c -- float version of s_significand.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+#include "math.h"
+#include "math_private.h"
+
+float
+significandf(float x)
+{
+ return __ieee754_scalbf(x,(float) -ilogbf(x));
+}
diff --git a/lib/msun/src/s_sin.c b/lib/msun/src/s_sin.c
new file mode 100644
index 0000000..af9ee62
--- /dev/null
+++ b/lib/msun/src/s_sin.c
@@ -0,0 +1,82 @@
+/* @(#)s_sin.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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/* sin(x)
+ * Return sine function of x.
+ *
+ * kernel function:
+ * __kernel_sin ... sine function on [-pi/4,pi/4]
+ * __kernel_cos ... cose function on [-pi/4,pi/4]
+ * __ieee754_rem_pio2 ... argument reduction routine
+ *
+ * Method.
+ * Let S,C and T denote the sin, cos and tan respectively on
+ * [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2
+ * in [-pi/4 , +pi/4], and let n = k mod 4.
+ * We have
+ *
+ * n sin(x) cos(x) tan(x)
+ * ----------------------------------------------------------
+ * 0 S C T
+ * 1 C -S -1/T
+ * 2 -S -C T
+ * 3 -C S -1/T
+ * ----------------------------------------------------------
+ *
+ * Special cases:
+ * Let trig be any of sin, cos, or tan.
+ * trig(+-INF) is NaN, with signals;
+ * trig(NaN) is that NaN;
+ *
+ * Accuracy:
+ * TRIG(x) returns trig(x) nearly rounded
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+double
+sin(double x)
+{
+ double y[2],z=0.0;
+ int32_t n, ix;
+
+ /* High word of x. */
+ GET_HIGH_WORD(ix,x);
+
+ /* |x| ~< pi/4 */
+ ix &= 0x7fffffff;
+ if(ix <= 0x3fe921fb) {
+ if(ix<0x3e400000) /* |x| < 2**-27 */
+ {if((int)x==0) return x;} /* generate inexact */
+ return __kernel_sin(x,z,0);
+ }
+
+ /* sin(Inf or NaN) is NaN */
+ else if (ix>=0x7ff00000) return x-x;
+
+ /* argument reduction needed */
+ else {
+ n = __ieee754_rem_pio2(x,y);
+ switch(n&3) {
+ case 0: return __kernel_sin(y[0],y[1],1);
+ case 1: return __kernel_cos(y[0],y[1]);
+ case 2: return -__kernel_sin(y[0],y[1],1);
+ default:
+ return -__kernel_cos(y[0],y[1]);
+ }
+ }
+}
diff --git a/lib/msun/src/s_sinf.c b/lib/msun/src/s_sinf.c
new file mode 100644
index 0000000..5842014
--- /dev/null
+++ b/lib/msun/src/s_sinf.c
@@ -0,0 +1,82 @@
+/* s_sinf.c -- float version of s_sin.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ * Optimized by Bruce D. Evans.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+#include "math.h"
+#define INLINE_KERNEL_COSDF
+#define INLINE_KERNEL_SINDF
+#include "math_private.h"
+#include "k_cosf.c"
+#include "k_sinf.c"
+
+/* Small multiples of pi/2 rounded to double precision. */
+static const double
+s1pio2 = 1*M_PI_2, /* 0x3FF921FB, 0x54442D18 */
+s2pio2 = 2*M_PI_2, /* 0x400921FB, 0x54442D18 */
+s3pio2 = 3*M_PI_2, /* 0x4012D97C, 0x7F3321D2 */
+s4pio2 = 4*M_PI_2; /* 0x401921FB, 0x54442D18 */
+
+float
+sinf(float x)
+{
+ float y[2];
+ int32_t n, hx, ix;
+
+ GET_FLOAT_WORD(hx,x);
+ ix = hx & 0x7fffffff;
+
+ if(ix <= 0x3f490fda) { /* |x| ~<= pi/4 */
+ if(ix<0x39800000) /* |x| < 2**-12 */
+ if(((int)x)==0) return x; /* x with inexact if x != 0 */
+ return __kernel_sindf(x);
+ }
+ if(ix<=0x407b53d1) { /* |x| ~<= 5*pi/4 */
+ if(ix<=0x4016cbe3) { /* |x| ~<= 3pi/4 */
+ if(hx>0)
+ return __kernel_cosdf(x - s1pio2);
+ else
+ return -__kernel_cosdf(x + s1pio2);
+ } else
+ return __kernel_sindf((hx > 0 ? s2pio2 : -s2pio2) - x);
+ }
+ if(ix<=0x40e231d5) { /* |x| ~<= 9*pi/4 */
+ if(ix<=0x40afeddf) { /* |x| ~<= 7*pi/4 */
+ if(hx>0)
+ return -__kernel_cosdf(x - s3pio2);
+ else
+ return __kernel_cosdf(x + s3pio2);
+ } else
+ return __kernel_sindf(x + (hx > 0 ? -s4pio2 : s4pio2));
+ }
+
+ /* sin(Inf or NaN) is NaN */
+ else if (ix>=0x7f800000) return x-x;
+
+ /* general argument reduction needed */
+ else {
+ n = __ieee754_rem_pio2f(x,y);
+ switch(n&3) {
+ case 0: return __kernel_sindf((double)y[0]+y[1]);
+ case 1: return __kernel_cosdf((double)y[0]+y[1]);
+ case 2: return __kernel_sindf(-(double)y[0]-y[1]);
+ default:
+ return -__kernel_cosdf((double)y[0]+y[1]);
+ }
+ }
+}
diff --git a/lib/msun/src/s_tan.c b/lib/msun/src/s_tan.c
new file mode 100644
index 0000000..d707ecd
--- /dev/null
+++ b/lib/msun/src/s_tan.c
@@ -0,0 +1,76 @@
+/* @(#)s_tan.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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/* tan(x)
+ * Return tangent function of x.
+ *
+ * kernel function:
+ * __kernel_tan ... tangent function on [-pi/4,pi/4]
+ * __ieee754_rem_pio2 ... argument reduction routine
+ *
+ * Method.
+ * Let S,C and T denote the sin, cos and tan respectively on
+ * [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2
+ * in [-pi/4 , +pi/4], and let n = k mod 4.
+ * We have
+ *
+ * n sin(x) cos(x) tan(x)
+ * ----------------------------------------------------------
+ * 0 S C T
+ * 1 C -S -1/T
+ * 2 -S -C T
+ * 3 -C S -1/T
+ * ----------------------------------------------------------
+ *
+ * Special cases:
+ * Let trig be any of sin, cos, or tan.
+ * trig(+-INF) is NaN, with signals;
+ * trig(NaN) is that NaN;
+ *
+ * Accuracy:
+ * TRIG(x) returns trig(x) nearly rounded
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+double
+tan(double x)
+{
+ double y[2],z=0.0;
+ int32_t n, ix;
+
+ /* High word of x. */
+ GET_HIGH_WORD(ix,x);
+
+ /* |x| ~< pi/4 */
+ ix &= 0x7fffffff;
+ if(ix <= 0x3fe921fb) {
+ if(ix<0x3e300000) /* x < 2**-28 */
+ if((int)x==0) return x; /* generate inexact */
+ return __kernel_tan(x,z,1);
+ }
+
+ /* tan(Inf or NaN) is NaN */
+ else if (ix>=0x7ff00000) return x-x; /* NaN */
+
+ /* argument reduction needed */
+ else {
+ n = __ieee754_rem_pio2(x,y);
+ return __kernel_tan(y[0],y[1],1-((n&1)<<1)); /* 1 -- n even
+ -1 -- n odd */
+ }
+}
diff --git a/lib/msun/src/s_tanf.c b/lib/msun/src/s_tanf.c
new file mode 100644
index 0000000..9a83555
--- /dev/null
+++ b/lib/msun/src/s_tanf.c
@@ -0,0 +1,69 @@
+/* s_tanf.c -- float version of s_tan.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ * Optimized by Bruce D. Evans.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+#include "math.h"
+#define INLINE_KERNEL_TANDF
+#include "math_private.h"
+#include "k_tanf.c"
+
+/* Small multiples of pi/2 rounded to double precision. */
+static const double
+t1pio2 = 1*M_PI_2, /* 0x3FF921FB, 0x54442D18 */
+t2pio2 = 2*M_PI_2, /* 0x400921FB, 0x54442D18 */
+t3pio2 = 3*M_PI_2, /* 0x4012D97C, 0x7F3321D2 */
+t4pio2 = 4*M_PI_2; /* 0x401921FB, 0x54442D18 */
+
+float
+tanf(float x)
+{
+ float y[2];
+ int32_t n, hx, ix;
+
+ GET_FLOAT_WORD(hx,x);
+ ix = hx & 0x7fffffff;
+
+ if(ix <= 0x3f490fda) { /* |x| ~<= pi/4 */
+ if(ix<0x39800000) /* |x| < 2**-12 */
+ if(((int)x)==0) return x; /* x with inexact if x != 0 */
+ return __kernel_tandf(x,1);
+ }
+ if(ix<=0x407b53d1) { /* |x| ~<= 5*pi/4 */
+ if(ix<=0x4016cbe3) /* |x| ~<= 3pi/4 */
+ return __kernel_tandf(x + (hx>0 ? -t1pio2 : t1pio2), -1);
+ else
+ return __kernel_tandf(x + (hx>0 ? -t2pio2 : t2pio2), 1);
+ }
+ if(ix<=0x40e231d5) { /* |x| ~<= 9*pi/4 */
+ if(ix<=0x40afeddf) /* |x| ~<= 7*pi/4 */
+ return __kernel_tandf(x + (hx>0 ? -t3pio2 : t3pio2), -1);
+ else
+ return __kernel_tandf(x + (hx>0 ? -t4pio2 : t4pio2), 1);
+ }
+
+ /* tan(Inf or NaN) is NaN */
+ else if (ix>=0x7f800000) return x-x;
+
+ /* general argument reduction needed */
+ else {
+ n = __ieee754_rem_pio2f(x,y);
+ /* integer parameter: 1 -- n even; -1 -- n odd */
+ return __kernel_tandf((double)y[0]+y[1],1-((n&1)<<1));
+ }
+}
diff --git a/lib/msun/src/s_tanh.c b/lib/msun/src/s_tanh.c
new file mode 100644
index 0000000..e3bbf47
--- /dev/null
+++ b/lib/msun/src/s_tanh.c
@@ -0,0 +1,78 @@
+/* @(#)s_tanh.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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/* Tanh(x)
+ * Return the Hyperbolic Tangent of x
+ *
+ * Method :
+ * x -x
+ * e - e
+ * 0. tanh(x) is defined to be -----------
+ * x -x
+ * e + e
+ * 1. reduce x to non-negative by tanh(-x) = -tanh(x).
+ * 2. 0 <= x <= 2**-55 : tanh(x) := x*(one+x)
+ * -t
+ * 2**-55 < x <= 1 : tanh(x) := -----; t = expm1(-2x)
+ * t + 2
+ * 2
+ * 1 <= x <= 22.0 : tanh(x) := 1- ----- ; t=expm1(2x)
+ * t + 2
+ * 22.0 < x <= INF : tanh(x) := 1.
+ *
+ * Special cases:
+ * tanh(NaN) is NaN;
+ * only tanh(0)=0 is exact for finite argument.
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+static const double one=1.0, two=2.0, tiny = 1.0e-300;
+
+double
+tanh(double x)
+{
+ double t,z;
+ int32_t jx,ix;
+
+ /* High word of |x|. */
+ GET_HIGH_WORD(jx,x);
+ ix = jx&0x7fffffff;
+
+ /* x is INF or NaN */
+ if(ix>=0x7ff00000) {
+ if (jx>=0) return one/x+one; /* tanh(+-inf)=+-1 */
+ else return one/x-one; /* tanh(NaN) = NaN */
+ }
+
+ /* |x| < 22 */
+ if (ix < 0x40360000) { /* |x|<22 */
+ if (ix<0x3c800000) /* |x|<2**-55 */
+ return x*(one+x); /* tanh(small) = small */
+ if (ix>=0x3ff00000) { /* |x|>=1 */
+ t = expm1(two*fabs(x));
+ z = one - two/(t+two);
+ } else {
+ t = expm1(-two*fabs(x));
+ z= -t/(t+two);
+ }
+ /* |x| > 22, return +-1 */
+ } else {
+ z = one - tiny; /* raised inexact flag */
+ }
+ return (jx>=0)? z: -z;
+}
diff --git a/lib/msun/src/s_tanhf.c b/lib/msun/src/s_tanhf.c
new file mode 100644
index 0000000..8f062c8
--- /dev/null
+++ b/lib/msun/src/s_tanhf.c
@@ -0,0 +1,56 @@
+/* s_tanhf.c -- float version of s_tanh.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+#include "math.h"
+#include "math_private.h"
+
+static const float one=1.0, two=2.0, tiny = 1.0e-30, huge = 1.0e30;
+float
+tanhf(float x)
+{
+ float t,z;
+ int32_t jx,ix;
+
+ GET_FLOAT_WORD(jx,x);
+ ix = jx&0x7fffffff;
+
+ /* x is INF or NaN */
+ if(ix>=0x7f800000) {
+ if (jx>=0) return one/x+one; /* tanh(+-inf)=+-1 */
+ else return one/x-one; /* tanh(NaN) = NaN */
+ }
+
+ /* |x| < 9 */
+ if (ix < 0x41100000) { /* |x|<9 */
+ if (ix<0x39800000) { /* |x|<2**-12 */
+ if(huge+x>one) return x; /* tanh(tiny) = tiny with inexact */
+ }
+ if (ix>=0x3f800000) { /* |x|>=1 */
+ t = expm1f(two*fabsf(x));
+ z = one - two/(t+two);
+ } else {
+ t = expm1f(-two*fabsf(x));
+ z= -t/(t+two);
+ }
+ /* |x| >= 9, return +-1 */
+ } else {
+ z = one - tiny; /* raise inexact flag */
+ }
+ return (jx>=0)? z: -z;
+}
diff --git a/lib/msun/src/s_trunc.c b/lib/msun/src/s_trunc.c
new file mode 100644
index 0000000..cce9e15
--- /dev/null
+++ b/lib/msun/src/s_trunc.c
@@ -0,0 +1,61 @@
+/* @(#)s_floor.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$");
+
+/*
+ * trunc(x)
+ * Return x rounded toward 0 to integral value
+ * Method:
+ * Bit twiddling.
+ * Exception:
+ * Inexact flag raised if x not equal to trunc(x).
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+static const double huge = 1.0e300;
+
+double
+trunc(double x)
+{
+ int32_t i0,i1,j0;
+ u_int32_t i,j;
+ EXTRACT_WORDS(i0,i1,x);
+ j0 = ((i0>>20)&0x7ff)-0x3ff;
+ if(j0<20) {
+ if(j0<0) { /* raise inexact if x != 0 */
+ if(huge+x>0.0) {/* |x|<1, so return 0*sign(x) */
+ i0 &= 0x80000000U;
+ i1 = 0;
+ }
+ } else {
+ i = (0x000fffff)>>j0;
+ if(((i0&i)|i1)==0) return x; /* x is integral */
+ if(huge+x>0.0) { /* raise inexact flag */
+ i0 &= (~i); i1=0;
+ }
+ }
+ } else if (j0>51) {
+ if(j0==0x400) return x+x; /* inf or NaN */
+ else return x; /* x is integral */
+ } else {
+ i = ((u_int32_t)(0xffffffff))>>(j0-20);
+ if((i1&i)==0) return x; /* x is integral */
+ if(huge+x>0.0) /* raise inexact flag */
+ i1 &= (~i);
+ }
+ INSERT_WORDS(x,i0,i1);
+ return x;
+}
diff --git a/lib/msun/src/s_truncf.c b/lib/msun/src/s_truncf.c
new file mode 100644
index 0000000..384eaee
--- /dev/null
+++ b/lib/msun/src/s_truncf.c
@@ -0,0 +1,53 @@
+/* @(#)s_floor.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$");
+
+/*
+ * truncf(x)
+ * Return x rounded toward 0 to integral value
+ * Method:
+ * Bit twiddling.
+ * Exception:
+ * Inexact flag raised if x not equal to truncf(x).
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+static const float huge = 1.0e30F;
+
+float
+truncf(float x)
+{
+ int32_t i0,j0;
+ u_int32_t i;
+ GET_FLOAT_WORD(i0,x);
+ j0 = ((i0>>23)&0xff)-0x7f;
+ if(j0<23) {
+ if(j0<0) { /* raise inexact if x != 0 */
+ if(huge+x>0.0F) /* |x|<1, so return 0*sign(x) */
+ i0 &= 0x80000000;
+ } else {
+ i = (0x007fffff)>>j0;
+ if((i0&i)==0) return x; /* x is integral */
+ if(huge+x>0.0F) /* raise inexact flag */
+ i0 &= (~i);
+ }
+ } else {
+ if(j0==0x80) return x+x; /* inf or NaN */
+ else return x; /* x is integral */
+ }
+ SET_FLOAT_WORD(x,i0);
+ return x;
+}
diff --git a/lib/msun/src/s_truncl.c b/lib/msun/src/s_truncl.c
new file mode 100644
index 0000000..c475b90
--- /dev/null
+++ b/lib/msun/src/s_truncl.c
@@ -0,0 +1,68 @@
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ *
+ * From: @(#)s_floor.c 5.1 93/09/24
+ */
+
+#ifndef lint
+static char rcsid[] = "$FreeBSD$";
+#endif
+
+/*
+ * truncl(x)
+ * Return x rounded toward 0 to integral value
+ * Method:
+ * Bit twiddling.
+ * Exception:
+ * Inexact flag raised if x not equal to truncl(x).
+ */
+
+#include <float.h>
+#include <math.h>
+#include <stdint.h>
+
+#include "fpmath.h"
+
+#ifdef LDBL_IMPLICIT_NBIT
+#define MANH_SIZE (LDBL_MANH_SIZE + 1)
+#else
+#define MANH_SIZE LDBL_MANH_SIZE
+#endif
+
+static const long double huge = 1.0e300;
+
+long double
+truncl(long double x)
+{
+ union IEEEl2bits u = { .e = x };
+ int e = u.bits.exp - LDBL_MAX_EXP + 1;
+
+ if (e < MANH_SIZE - 1) {
+ if (e < 0) { /* raise inexact if x != 0 */
+ if (huge + x > 0.0)
+ u.e = 0.0;
+ } else {
+ uint64_t m = ((1llu << MANH_SIZE) - 1) >> (e + 1);
+ if (((u.bits.manh & m) | u.bits.manl) == 0)
+ return (x); /* x is integral */
+ if (huge + x > 0.0) { /* raise inexact flag */
+ u.bits.manh &= ~m;
+ u.bits.manl = 0;
+ }
+ }
+ } else if (e < LDBL_MANT_DIG - 1) {
+ uint64_t m = (uint64_t)-1 >> (64 - LDBL_MANT_DIG + e + 1);
+ if ((u.bits.manl & m) == 0)
+ return (x); /* x is integral */
+ if (huge + x > 0.0) /* raise inexact flag */
+ u.bits.manl &= ~m;
+ }
+ return (u.e);
+}
diff --git a/lib/msun/src/w_cabs.c b/lib/msun/src/w_cabs.c
new file mode 100644
index 0000000..a33a41f
--- /dev/null
+++ b/lib/msun/src/w_cabs.c
@@ -0,0 +1,28 @@
+/*
+ * cabs() wrapper for hypot().
+ *
+ * Written by J.T. Conklin, <jtc@wimsey.com>
+ * Placed into the Public Domain, 1994.
+ */
+
+#ifndef lint
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif /* not lint */
+
+#include <complex.h>
+#include <math.h>
+
+double
+cabs(z)
+ double complex z;
+{
+ return hypot(creal(z), cimag(z));
+}
+
+double
+z_abs(z)
+ double complex *z;
+{
+ return hypot(creal(*z), cimag(*z));
+}
diff --git a/lib/msun/src/w_cabsf.c b/lib/msun/src/w_cabsf.c
new file mode 100644
index 0000000..e7bfe22
--- /dev/null
+++ b/lib/msun/src/w_cabsf.c
@@ -0,0 +1,23 @@
+/*
+ * cabsf() wrapper for hypotf().
+ *
+ * Written by J.T. Conklin, <jtc@wimsey.com>
+ * Placed into the Public Domain, 1994.
+ */
+
+#ifndef lint
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif /* not lint */
+
+#include <complex.h>
+#include <math.h>
+#include "math_private.h"
+
+float
+cabsf(z)
+ float complex z;
+{
+
+ return hypotf(crealf(z), cimagf(z));
+}
diff --git a/lib/msun/src/w_drem.c b/lib/msun/src/w_drem.c
new file mode 100644
index 0000000..0f68409
--- /dev/null
+++ b/lib/msun/src/w_drem.c
@@ -0,0 +1,15 @@
+/*
+ * drem() wrapper for remainder().
+ *
+ * Written by J.T. Conklin, <jtc@wimsey.com>
+ * Placed into the Public Domain, 1994.
+ */
+
+#include <math.h>
+
+double
+drem(x, y)
+ double x, y;
+{
+ return remainder(x, y);
+}
diff --git a/lib/msun/src/w_dremf.c b/lib/msun/src/w_dremf.c
new file mode 100644
index 0000000..4bfcff2
--- /dev/null
+++ b/lib/msun/src/w_dremf.c
@@ -0,0 +1,16 @@
+/*
+ * dremf() wrapper for remainderf().
+ *
+ * Written by J.T. Conklin, <jtc@wimsey.com>
+ * Placed into the Public Domain, 1994.
+ */
+/* $FreeBSD$ */
+
+#include "math.h"
+#include "math_private.h"
+
+float
+dremf(float x, float y)
+{
+ return remainderf(x, y);
+}
diff --git a/lib/ncurses/form/Makefile b/lib/ncurses/form/Makefile
new file mode 100644
index 0000000..027be49
--- /dev/null
+++ b/lib/ncurses/form/Makefile
@@ -0,0 +1,100 @@
+# Makefile for libform
+# $FreeBSD$
+
+NCURSES=${.CURDIR}/../../contrib/ncurses
+
+.PATH: ${NCURSES}/form
+.PATH: ${NCURSES}/include
+.PATH: ${NCURSES}/man
+
+LIB= form
+DPADD= ${LIBNCURSES}
+LDADD= -lncurses
+
+AWK?= awk
+
+SRCS= ncurses_def.h \
+ fld_arg.c fld_attr.c fld_current.c fld_def.c fld_dup.c fld_ftchoice.c \
+ fld_ftlink.c fld_info.c fld_just.c fld_link.c fld_max.c fld_move.c \
+ fld_newftyp.c fld_opts.c fld_pad.c fld_page.c fld_stat.c fld_type.c \
+ fld_user.c frm_cursor.c frm_data.c frm_def.c frm_driver.c frm_hook.c \
+ frm_opts.c frm_page.c frm_post.c frm_req_name.c frm_scale.c frm_sub.c \
+ frm_user.c frm_win.c fty_alnum.c fty_alpha.c fty_enum.c fty_int.c \
+ fty_ipv4.c fty_num.c fty_regex.c
+INCS= ${NCURSES}/form/form.h
+
+CLEANFILES+= ncurses_def.h
+CFLAGS+= -I.
+.if exists(${.OBJDIR}/../libncurses)
+CFLAGS+= -I${.OBJDIR}/../libncurses
+.endif
+CFLAGS+=-I${.CURDIR}/../libncurses -I${NCURSES}/form -I${NCURSES}/menu \
+ -I${NCURSES}/include -Wall -DNDEBUG -DHAVE_CONFIG_H
+
+ncurses_def.h: MKncurses_def.sh ncurses_defs
+ AWK=${AWK} sh ${NCURSES}/include/MKncurses_def.sh \
+ ${NCURSES}/include/ncurses_defs > ncurses_def.h
+
+MANx= form.3x form_cursor.3x form_data.3x form_driver.3x \
+ form_field.3x form_field_attributes.3x form_field_buffer.3x \
+ form_field_info.3x form_field_just.3x form_field_new.3x \
+ form_field_opts.3x form_field_userptr.3x \
+ form_field_validation.3x form_fieldtype.3x form_hook.3x \
+ form_new.3x form_new_page.3x form_opts.3x form_page.3x \
+ form_post.3x form_requestname.3x form_userptr.3x form_win.3x
+
+# Generate the MAN list from MANx
+.for page in ${MANx}
+CLEANFILES+=${page:T:S/x$//g}
+MAN+=${page:T:S/x$//g}
+${page:T:S/x$//g}: ${page}
+ cat ${.ALLSRC} > ${.TARGET}
+.endfor
+
+MLINKS+=form_cursor.3 pos_form_cursor.3
+MLINKS+=form_data.3 data_ahead.3 form_data.3 data_behind.3
+MLINKS+=form_field.3 field_count.3 form_field.3 form_fields.3 \
+ form_field.3 move_field.3 form_field.3 set_form_fields.3
+MLINKS+=form_field_attributes.3 field_back.3 \
+ form_field_attributes.3 field_fore.3 \
+ form_field_attributes.3 field_pad.3 \
+ form_field_attributes.3 set_field_back.3 \
+ form_field_attributes.3 set_field_fore.3 \
+ form_field_attributes.3 set_field_pad.3
+MLINKS+=form_field_buffer.3 field_buffer.3 \
+ form_field_buffer.3 field_status.3 \
+ form_field_buffer.3 set_field_buffer.3 \
+ form_field_buffer.3 set_field_status.3 \
+ form_field_buffer.3 set_max_field.3
+MLINKS+=form_field_info.3 dynamic_fieldinfo.3 form_field_info.3 field_info.3
+MLINKS+=form_field_just.3 field_just.3 form_field_just.3 set_field_just.3
+MLINKS+=form_field_new.3 dup_field.3 form_field_new.3 free_field.3 \
+ form_field_new.3 link_field.3 form_field_new.3 new_field.3
+MLINKS+=form_field_opts.3 field_opts.3 form_field_opts.3 field_opts_off.3 \
+ form_field_opts.3 field_opts_on.3 form_field_opts.3 set_field_opts.3 \
+ form_field_opts.3 set_form_opts.3
+MLINKS+=form_field_userptr.3 field_userptr.3 \
+ form_field_userptr.3 set_field_userptr.3
+MLINKS+=form_field_validation.3 field_arg.3 \
+ form_field_validation.3 field_type.3 \
+ form_field_validation.3 set_field_type.3
+MLINKS+=form_fieldtype.3 link_fieldtype.3 \
+ form_fieldtype.3 set_fieldtype_arg.3 \
+ form_fieldtype.3 set_fieldtype_choice.3
+MLINKS+=form_hook.3 field_init.3 form_hook.3 field_term.3 \
+ form_hook.3 form_init.3 form_hook.3 form_term.3 \
+ form_hook.3 set_field_init.3 form_hook.3 set_field_term.3 \
+ form_hook.3 set_form_init.3 form_hook.3 set_form_term.3
+MLINKS+=form_new.3 free_form.3 form_new.3 new_form.3
+MLINKS+=form_new_page.3 new_page.3 form_new_page.3 set_new_page.3
+MLINKS+=form_opts.3 form_opts_off.3 form_opts.3 form_opts_on.3
+MLINKS+=form_page.3 current_field.3 form_page.3 field_index.3 \
+ form_page.3 set_current_field.3 form_page.3 set_form_page.3
+MLINKS+=form_post.3 post_form.3 form_post.3 unpost_form.3
+MLINKS+=form_requestname.3 form_request_by_name.3 \
+ form_requestname.3 form_request_name.3
+MLINKS+=form_userptr.3 set_form_userptr.3
+MLINKS+=form_win.3 form_sub.3 form_win.3 scale_form.3 \
+ form_win.3 set_form_sub.3 form_win.3 set_form_win.3
+
+.include <bsd.lib.mk>
diff --git a/lib/ncurses/menu/Makefile b/lib/ncurses/menu/Makefile
new file mode 100644
index 0000000..6e05739
--- /dev/null
+++ b/lib/ncurses/menu/Makefile
@@ -0,0 +1,84 @@
+# Makefile for libmenu
+# $FreeBSD$
+
+NCURSES=${.CURDIR}/../../contrib/ncurses
+
+.PATH: ${NCURSES}/menu ${NCURSES}/include
+.PATH: ${NCURSES}/man
+
+LIB= menu
+DPADD= ${LIBNCURSES}
+LDADD= -lncurses
+AWK?= awk
+
+SRCS= ncurses_def.h \
+ m_attribs.c m_cursor.c m_driver.c m_format.c m_global.c m_hook.c \
+ m_item_cur.c m_item_nam.c m_item_new.c m_item_opt.c m_item_top.c \
+ m_item_use.c m_item_val.c m_item_vis.c m_items.c m_new.c m_opts.c \
+ m_pad.c m_pattern.c m_post.c m_req_name.c m_scale.c m_spacing.c \
+ m_sub.c m_userptr.c m_win.c
+INCS= ${NCURSES}/menu/menu.h ${NCURSES}/menu/eti.h
+
+CLEANFILES+= ncurses_def.h
+CFLAGS+= -I.
+.if exists(${.OBJDIR}/../libncurses)
+CFLAGS+= -I${.OBJDIR}/../libncurses
+.endif
+CFLAGS+=-I${.CURDIR}/../libncurses -I${NCURSES}/menu -I${NCURSES}/include \
+ -Wall -DNDEBUG -DHAVE_CONFIG_H
+
+ncurses_def.h: MKncurses_def.sh ncurses_defs
+ AWK=${AWK} sh ${NCURSES}/include/MKncurses_def.sh \
+ ${NCURSES}/include/ncurses_defs > ncurses_def.h
+
+MANx= menu.3x menu_attributes.3x menu_cursor.3x \
+ menu_driver.3x menu_format.3x menu_hook.3x menu_items.3x \
+ menu_mark.3x menu_new.3x menu_opts.3x menu_pattern.3x \
+ menu_post.3x menu_requestname.3x menu_spacing.3x \
+ menu_userptr.3x menu_win.3x mitem_current.3x mitem_name.3x \
+ mitem_new.3x mitem_opts.3x mitem_userptr.3x mitem_value.3x \
+ mitem_visible.3x
+
+# Generate the MAN list from MANx
+.for page in ${MANx}
+CLEANFILES+=${page:T:S/x$//g}
+MAN+=${page:T:S/x$//g}
+${page:T:S/x$//g}: ${page}
+ cat ${.ALLSRC} > ${.TARGET}
+.endfor
+
+MLINKS+=menu_attributes.3 menu_back.3 menu_attributes.3 menu_fore.3 \
+ menu_attributes.3 menu_grey.3 menu_attributes.3 menu_pad.3 \
+ menu_attributes.3 set_menu_back.3 menu_attributes.3 set_menu_fore.3 \
+ menu_attributes.3 set_menu_grey.3 menu_attributes.3 set_menu_pad.3
+MLINKS+=menu_cursor.3 pos_menu_cursor.3
+MLINKS+=menu_format.3 set_menu_format.3
+MLINKS+=menu_hook.3 item_init.3 menu_hook.3 item_term.3 \
+ menu_hook.3 menu_init.3 menu_hook.3 menu_term.3 \
+ menu_hook.3 set_item_init.3 menu_hook.3 set_item_term.3 \
+ menu_hook.3 set_menu_init.3 menu_hook.3 set_menu_term.3
+MLINKS+=menu_items.3 item_count.3 menu_items.3 set_menu_items.3
+MLINKS+=menu_mark.3 set_menu_mark.3
+MLINKS+=menu_new.3 free_menu.3 menu_new.3 new_menu.3
+MLINKS+=menu_opts.3 menu_opts_off.3 menu_opts.3 menu_opts_on.3
+MLINKS+=menu_pattern.3 set_menu_pattern.3
+MLINKS+=menu_post.3 post_menu.3 menu_post.3 unpost_menu.3
+MLINKS+=menu_requestname.3 menu_request_by_name.3 \
+ menu_requestname.3 menu_request_name.3
+MLINKS+=menu_spacing.3 set_menu_spacing.3
+MLINKS+=menu_userptr.3 set_menu_userptr.3
+MLINKS+=menu_win.3 menu_sub.3 menu_win.3 scale_menu.3 \
+ menu_win.3 set_menu_sub.3 menu_win.3 set_menu_win.3
+MLINKS+=mitem_current.3 current_item.3 mitem_current.3 item_index.3 \
+ mitem_current.3 set_top_row.3 mitem_current.3 top_row.3 \
+ mitem_current.3 set_current_item.3
+MLINKS+=mitem_name.3 item_description.3 mitem_name.3 item_name.3
+MLINKS+=mitem_new.3 free_item.3 mitem_new.3 new_item.3
+MLINKS+=mitem_opts.3 item_opts.3 mitem_opts.3 item_opts_off.3 \
+ mitem_opts.3 item_opts_on.3 mitem_opts.3 set_item_opts.3 \
+ mitem_opts.3 set_menu_opts.3
+MLINKS+=mitem_userptr.3 item_userptr.3 mitem_userptr.3 set_item_userptr.3
+MLINKS+=mitem_value.3 item_value.3 mitem_value.3 set_item_value.3
+MLINKS+=mitem_visible.3 item_visible.3
+
+.include <bsd.lib.mk>
diff --git a/lib/ncurses/ncurses/Makefile b/lib/ncurses/ncurses/Makefile
new file mode 100644
index 0000000..4fddbdc
--- /dev/null
+++ b/lib/ncurses/ncurses/Makefile
@@ -0,0 +1,564 @@
+# $FreeBSD$
+
+SHLIBDIR?= /lib
+
+.include <bsd.own.mk>
+
+NCURSES=${.CURDIR}/../../contrib/ncurses
+
+LIB= ncurses
+SHLIB_MAJOR=6
+
+# Should be elsewhere
+AWK?= awk
+TERMINFODIR?= ${SHAREDIR}/misc
+
+NCURSES_MAJOR!=egrep 'NCURSES_MAJOR[ ]*=' ${NCURSES}/dist.mk | sed -e 's%^[^0-9]*%%'
+NCURSES_MINOR!=egrep 'NCURSES_MINOR[ ]*=' ${NCURSES}/dist.mk | sed -e 's%^[^0-9]*%%'
+NCURSES_PATCH!=egrep 'NCURSES_PATCH[ ]*=' ${NCURSES}/dist.mk | sed -e 's%^[^0-9]*%%'
+
+# From autoconf (!)
+NCURSES_CONST= const
+NCURSES_XNAMES= 1
+NCURSES_OSPEED= short
+NCURSES_CH_T= chtype
+NCURSES_EXT_FUNCS= 1
+NCURSES_LIBUTF8= 0
+NCURSES_MBSTATE_T= 0
+BROKEN_LINKER= 0
+BUILTIN_BOOL= 1
+BOOL_TYPE= 0
+HAVE_VSSCANF= 1
+HEADER_STDBOOL= 1
+TYPE_OF_BOOL= unsigned char
+TYPEOF_CHTYPE= long
+WIDEC_SHIFT= 8
+SHIFT_LIMIT= 32
+ONEUL= 1UL
+
+.PATH: ${NCURSES}/ncurses
+.PATH: ${NCURSES}/ncurses/base
+.PATH: ${NCURSES}/ncurses/tinfo
+.PATH: ${NCURSES}/ncurses/tty
+.PATH: ${NCURSES}/ncurses/trace
+.PATH: ${NCURSES}/include
+.PATH: ${NCURSES}/man
+
+CFLAGS+=-I. -I${.CURDIR} -I${NCURSES}/ncurses -I${NCURSES}/include
+CFLAGS+=-Wall -DFREEBSD_NATIVE -DNDEBUG -DHAVE_CONFIG_H -DTERMIOS
+
+GENSRC= \
+ codes.c \
+ expanded.c \
+ fallback.c \
+ lib_gen.c \
+ lib_keyname.c \
+ names.c \
+ unctrl.c
+
+GENHDR= \
+ curses.h \
+ hashsize.h \
+ init_keytry.h \
+ ncurses_def.h \
+ nomacros.h \
+ parametrized.h \
+ term.h \
+ termcap.h \
+ unctrl.h
+
+# Installed
+HEADERS=curses.h term.h termcap.h unctrl.h
+SRCHDRS=ncurses_dll.h
+INCS= ${HEADERS} ${SRCHDRS}
+INCSLINKS= curses.h ${INCLUDEDIR}/ncurses.h
+
+# Components of names.c and codes.c
+NAMESRC=boolnames boolfnames numnames numfnames strnames strfnames
+CODESRC=boolcodes numcodes strcodes
+
+SRCS= ${GENHDR} ${GENSRC} \
+ access.c \
+ add_tries.c \
+ alloc_entry.c \
+ alloc_ttype.c \
+ captoinfo.c \
+ comp_captab.c \
+ comp_error.c \
+ comp_expand.c \
+ comp_hash.c \
+ comp_parse.c \
+ comp_scan.c \
+ define_key.c \
+ doalloc.c \
+ free_ttype.c \
+ getenv_num.c \
+ hardscroll.c \
+ hashmap.c \
+ home_terminfo.c \
+ init_keytry.c \
+ keybound.c \
+ keyok.c \
+ lib_acs.c \
+ lib_addch.c \
+ lib_addstr.c \
+ lib_baudrate.c \
+ lib_beep.c \
+ lib_bkgd.c \
+ lib_box.c \
+ lib_chgat.c \
+ lib_clear.c \
+ lib_clearok.c \
+ lib_clrbot.c \
+ lib_clreol.c \
+ lib_color.c \
+ lib_colorset.c \
+ lib_cur_term.c \
+ lib_data.c \
+ lib_delch.c \
+ lib_delwin.c \
+ lib_dft_fgbg.c \
+ lib_echo.c \
+ lib_endwin.c \
+ lib_erase.c \
+ lib_flash.c \
+ lib_freeall.c \
+ lib_getch.c \
+ lib_getstr.c \
+ lib_has_cap.c \
+ lib_hline.c \
+ lib_immedok.c \
+ lib_inchstr.c \
+ lib_initscr.c \
+ lib_insch.c \
+ lib_insdel.c \
+ lib_insstr.c \
+ lib_instr.c \
+ lib_isendwin.c \
+ lib_kernel.c \
+ lib_leaveok.c \
+ lib_longname.c \
+ lib_mouse.c \
+ lib_move.c \
+ lib_mvcur.c \
+ lib_mvwin.c \
+ lib_napms.c \
+ lib_newterm.c \
+ lib_newwin.c \
+ lib_nl.c \
+ lib_options.c \
+ lib_overlay.c \
+ lib_pad.c \
+ lib_print.c \
+ lib_printw.c \
+ lib_raw.c \
+ lib_redrawln.c \
+ lib_refresh.c \
+ lib_restart.c \
+ lib_scanw.c \
+ lib_screen.c \
+ lib_scroll.c \
+ lib_scrollok.c \
+ lib_scrreg.c \
+ lib_set_term.c \
+ lib_setup.c \
+ lib_slk.c \
+ lib_slkatr_set.c \
+ lib_slkatrof.c \
+ lib_slkatron.c \
+ lib_slkatrset.c \
+ lib_slkattr.c \
+ lib_slkclear.c \
+ lib_slkcolor.c \
+ lib_slkinit.c \
+ lib_slklab.c \
+ lib_slkrefr.c \
+ lib_slkset.c \
+ lib_slktouch.c \
+ lib_termcap.c \
+ lib_termname.c \
+ lib_tgoto.c \
+ lib_ti.c \
+ lib_touch.c \
+ lib_tparm.c \
+ lib_tputs.c \
+ lib_trace.c \
+ lib_tstp.c \
+ lib_ttyflags.c \
+ lib_twait.c \
+ lib_ungetch.c \
+ lib_vidattr.c \
+ lib_vline.c \
+ lib_wattroff.c \
+ lib_wattron.c \
+ lib_winch.c \
+ lib_window.c \
+ memmove.c \
+ name_match.c \
+ nc_panel.c \
+ parse_entry.c \
+ read_entry.c \
+ resizeterm.c \
+ safe_sprintf.c \
+ setbuf.c \
+ sigaction.c \
+ strings.c \
+ tries.c \
+ tty_update.c \
+ varargs.c \
+ version.c \
+ visbuf.c \
+ vsscanf.c \
+ wresize.c \
+ write_entry.c
+
+# Currently unused, for debugging libncurses itself.
+DBGSRCS=lib_traceatr.c \
+ lib_tracebits.c \
+ lib_tracechr.c \
+ lib_tracedmp.c \
+ lib_tracemse.c \
+ trace_buf.c \
+ trace_tries.c \
+ trace_xnames.c
+
+# From our old libtermcap.
+# Used instead of the hideous read_termcap.c abomination.
+SRCS+= termcap.c
+
+CLEANFILES+= ${GENSRC} ${GENHDR} keys.list make_hash term.h.new \
+ make_keys MKterm.h.awk comp_captab.c curses.head \
+ namehdr nameftr codeftr ${NAMESRC} ${CODESRC}
+
+.if !defined(NO_INSTALLLIB)
+SYMLINKS+=libncurses.a ${LIBDIR}/libcurses.a
+SYMLINKS+=libncurses.a ${LIBDIR}/libtermcap.a
+SYMLINKS+=libncurses.a ${LIBDIR}/libtermlib.a
+SYMLINKS+=libncurses.a ${LIBDIR}/libmytinfo.a
+SYMLINKS+=libncurses.a ${LIBDIR}/libtinfo.a
+.endif
+.if !defined(NO_PIC)
+# no need for major at all, it's an ld-time redirection only
+SYMLINKS+=libncurses.so ${LIBDIR}/libcurses.so
+SYMLINKS+=libncurses.so ${LIBDIR}/libtermcap.so
+SYMLINKS+=libncurses.so ${LIBDIR}/libtermlib.so
+SYMLINKS+=libncurses.so ${LIBDIR}/libmytinfo.so
+SYMLINKS+=libncurses.so ${LIBDIR}/libtinfo.so
+.endif
+.if ${MK_PROFILE} != "no"
+SYMLINKS+=libncurses_p.a ${LIBDIR}/libcurses_p.a
+SYMLINKS+=libncurses_p.a ${LIBDIR}/libtermcap_p.a
+SYMLINKS+=libncurses_p.a ${LIBDIR}/libtermlib_p.a
+SYMLINKS+=libncurses_p.a ${LIBDIR}/libmytinfo_p.a
+SYMLINKS+=libncurses_p.a ${LIBDIR}/libtinfo_p.a
+.endif
+
+DOCSDIR= /usr/share/doc/ncurses
+DOCS= ncurses-intro.html hackguide.html
+
+.if ${MK_HTML} != "no"
+.PATH: ${NCURSES}/doc/html
+FILESGROUPS= DOCS
+.endif
+
+# Generated source
+namehdr nameftr codeftr ${NAMESRC} ${CODESRC}: MKnames.awk Caps
+ ${AWK} -f ${NCURSES}/ncurses/tinfo/MKnames.awk ${NCURSES}/include/Caps
+
+.ORDER: namehdr ${NAMESRC} ${CODESRC} nameftr codeftr names.c codes.c
+
+names.c: namehdr ${NAMESRC} nameftr
+ cat namehdr ${NAMESRC} nameftr > $@
+
+codes.c: namehdr ${CODESRC} codeftr
+ cat namehdr ${CODESRC} codeftr > $@
+
+lib_gen.c: MKlib_gen.sh curses.h
+ LC_ALL=C sh ${NCURSES}/ncurses/base/MKlib_gen.sh "${CC} -E ${CFLAGS}" \
+ "${AWK}" generated < curses.h >$@
+
+lib_keyname.c: keys.list MKkeyname.awk
+ ${AWK} -f ${NCURSES}/ncurses/base/MKkeyname.awk keys.list > lib_keyname.c
+
+unctrl.c: MKunctrl.awk
+ echo | ${AWK} -f ${NCURSES}/ncurses/base/MKunctrl.awk > unctrl.c
+
+comp_captab.c: MKcaptab.awk Caps make_hash
+ sh ${NCURSES}/ncurses/tinfo/MKcaptab.awk "${AWK}" \
+ ${NCURSES}/include/Caps > comp_captab.c
+
+expanded.c: MKexpanded.sh
+ sh ${NCURSES}/ncurses/tty/MKexpanded.sh "${CC} -E" ${CFLAGS} >expanded.c
+
+fallback.c: MKfallback.sh
+ sh ${NCURSES}/ncurses/tinfo/MKfallback.sh > fallback.c
+
+# Generated headers
+ncurses_def.h: MKncurses_def.sh ncurses_defs
+ AWK=${AWK} sh ${NCURSES}/include/MKncurses_def.sh \
+ ${NCURSES}/include/ncurses_defs > ncurses_def.h
+
+nomacros.h: MKlib_gen.sh curses.h
+ LC_ALL=C sh ${NCURSES}/ncurses/base/MKlib_gen.sh "${CC} -E ${CFLAGS}" \
+ "${AWK}" generated < curses.h | fgrep undef > $@
+
+init_keytry.h: keys.list make_keys
+ ./make_keys keys.list > init_keytry.h
+
+hashsize.h: MKhashsize.sh Caps
+ sh ${NCURSES}/include/MKhashsize.sh ${NCURSES}/include/Caps > $@
+
+parametrized.h: MKparametrized.sh Caps
+ AWK=${AWK} sh ${NCURSES}/include/MKparametrized.sh \
+ ${NCURSES}/include/Caps > $@
+
+term.h: MKterm.h.awk edit_cfg.sh Caps
+ ${AWK} -f MKterm.h.awk ${NCURSES}/include/Caps > $@.new
+ sh ${NCURSES}/include/edit_cfg.sh ${.CURDIR}/ncurses_cfg.h $@.new
+ mv -f $@.new $@
+
+curses.h: curses.head MKkey_defs.sh Caps
+ cat curses.head > $@.new
+ AWK=${AWK} _POSIX2_VERSION=199209 sh ${NCURSES}/include/MKkey_defs.sh \
+ ${NCURSES}/include/Caps >> $@.new
+ cat ${NCURSES}/include/curses.tail >> $@.new
+ mv -f $@.new $@
+
+# Generated intermediate files
+keys.list: MKkeys_list.sh Caps
+ AWK=${AWK} sh ${NCURSES}/ncurses/tinfo/MKkeys_list.sh \
+ ${NCURSES}/include/Caps | LC_ALL=C sort > keys.list
+
+# Build tools
+build-tools: make_hash make_keys
+
+make_keys: make_keys.c names.c ncurses_def.h ${HEADERS}
+ ${CC} -o $@ ${CFLAGS} ${NCURSES}/ncurses/tinfo/make_keys.c
+
+make_hash: comp_hash.c hashsize.h ncurses_def.h ${HEADERS}
+ ${CC} -o $@ ${CFLAGS} -DMAIN_PROGRAM \
+ ${NCURSES}/ncurses/tinfo/comp_hash.c
+
+# ./configure generated
+MKterm.h.awk: MKterm.h.awk.in
+ sed <${NCURSES}/include/MKterm.h.awk.in >$@ \
+ -e "/@NCURSES_MAJOR@/s%%${NCURSES_MAJOR}%" \
+ -e "/@NCURSES_MINOR@/s%%${NCURSES_MINOR}%" \
+ -e "/@NCURSES_CONST@/s%%${NCURSES_CONST}%" \
+ -e "/@NCURSES_XNAMES@/s%%${NCURSES_XNAMES}%"
+
+termcap.h: termcap.h.in
+ sed <${NCURSES}/include/termcap.h.in >$@ \
+ -e "/@NCURSES_MAJOR@/s%%${NCURSES_MAJOR}%" \
+ -e "/@NCURSES_MINOR@/s%%${NCURSES_MINOR}%" \
+ -e "/@NCURSES_CONST@/s%%${NCURSES_CONST}%" \
+ -e "/@NCURSES_OSPEED@/s%%${NCURSES_OSPEED}%"
+
+curses.head: curses.h.in
+ sed <${NCURSES}/include/curses.h.in >$@ \
+ -e "/@BROKEN_LINKER@/s%%${BROKEN_LINKER}%" \
+ -e "/@HAVE_VSSCANF@/s%%${HAVE_VSSCANF}%" \
+ -e "/@NCURSES_CONST@/s%%${NCURSES_CONST}%" \
+ -e "/@NCURSES_MAJOR@/s%%${NCURSES_MAJOR}%" \
+ -e "/@NCURSES_MINOR@/s%%${NCURSES_MINOR}%" \
+ -e "/@NCURSES_PATCH@/s%%${NCURSES_PATCH}%" \
+ -e "/@NCURSES_CH_T@/s%%${NCURSES_CH_T}%" \
+ -e "/@NCURSES_EXT_FUNCS@/s%%${NCURSES_EXT_FUNCS}%" \
+ -e "/@NCURSES_LIBUTF8@/s%%${NCURSES_LIBUTF8}%" \
+ -e "/@NCURSES_MBSTATE_T@/s%%${NCURSES_MBSTATE_T}%" \
+ -e "s%@cf_cv_1UL@%${ONEUL}%g" \
+ -e "s%@cf_cv_builtin_bool@%${BUILTIN_BOOL}%g" \
+ -e "s%@cf_cv_cc_bool_type@%${BOOL_TYPE}%g" \
+ -e "s%@cf_cv_shift_limit@%${SHIFT_LIMIT}%g" \
+ -e "s%@cf_cv_header_stdbool_h@%${HEADER_STDBOOL}%g" \
+ -e "s%@cf_cv_type_of_bool@%${TYPE_OF_BOOL}%g" \
+ -e "s%@cf_cv_typeof_chtype@%${TYPEOF_CHTYPE}%g" \
+ -e "s%@cf_cv_widec_shift@%${WIDEC_SHIFT}%g" \
+ -e "s/ _WCHAR_T/ __wchar_t/g" \
+ -e "s/ _WINT_T/ __wint_t/g" \
+
+unctrl.h: unctrl.h.in
+ sed <${NCURSES}/include/$@.in >$@ \
+ -e "/@NCURSES_MAJOR@/s%%${NCURSES_MAJOR}%" \
+ -e "/@NCURSES_MINOR@/s%%${NCURSES_MINOR}%"
+
+# MAN page gunk
+terminfo.5: MKterminfo.sh terminfo.head Caps
+ sh ${NCURSES}/man/MKterminfo.sh ${NCURSES}/man/terminfo.head \
+ ${NCURSES}/include/Caps ${NCURSES}/man/terminfo.tail >$@
+
+CLEANFILES+= terminfo.5
+MANFILTER= sed -e 's%@TERMINFO@%${TERMINFODIR}/terminfo%g' \
+ -e 's%@NCURSES_OSPEED@%${NCURSES_OSPEED}%g'
+
+MANx= curs_addch.3x curs_addchstr.3x curs_addstr.3x curs_attr.3x \
+ curs_beep.3x curs_bkgd.3x curs_border.3x curs_clear.3x curs_color.3x \
+ curs_delch.3x curs_deleteln.3x curs_extend.3x curs_getch.3x \
+ curs_getstr.3x \
+ curs_getyx.3x curs_inch.3x curs_inchstr.3x curs_initscr.3x \
+ curs_inopts.3x curs_insch.3x curs_insstr.3x curs_instr.3x \
+ curs_kernel.3x curs_mouse.3x curs_move.3x curs_outopts.3x \
+ curs_overlay.3x curs_pad.3x curs_print.3x curs_printw.3x \
+ curs_refresh.3x curs_scanw.3x curs_scr_dump.3x curs_scroll.3x \
+ curs_slk.3x curs_termattrs.3x curs_termcap.3x curs_terminfo.3x \
+ curs_touch.3x curs_trace.3x curs_util.3x curs_window.3x \
+ default_colors.3x define_key.3x \
+ keybound.3x keyok.3x ncurses.3x resizeterm.3x wresize.3x
+MAN= term.5 terminfo.5
+MAN+= term.7
+
+# Generate the MAN list from MANx
+.for page in ${MANx}
+CLEANFILES+=${page:T:S/x$//g}
+MAN+=${page:T:S/x$//g}
+${page:T:S/x$//g}: ${page}
+ cat ${.ALLSRC} > ${.TARGET}
+.endfor
+
+MLINKS+=ncurses.3 curses.3
+MLINKS+=curs_addch.3 addch.3 curs_addch.3 echochar.3 curs_addch.3 mvaddch.3 \
+ curs_addch.3 mvwaddch.3 curs_addch.3 waddch.3 curs_addch.3 wechochar.3
+MLINKS+=curs_addchstr.3 addchnstr.3 curs_addchstr.3 addchstr.3 \
+ curs_addchstr.3 mvaddchnstr.3 curs_addchstr.3 mvaddchstr.3 \
+ curs_addchstr.3 mvwaddchnstr.3 curs_addchstr.3 mvwaddchstr.3 \
+ curs_addchstr.3 waddchnstr.3 curs_addchstr.3 waddchstr.3
+MLINKS+=curs_addstr.3 addnstr.3 curs_addstr.3 addstr.3 \
+ curs_addstr.3 mvaddnstr.3 curs_addstr.3 mvaddstr.3 \
+ curs_addstr.3 mvwaddnstr.3 curs_addstr.3 mvwaddstr.3 \
+ curs_addstr.3 waddnstr.3 curs_addstr.3 waddstr.3
+MLINKS+=curs_attr.3 PAIR_NUMBER.3 \
+ curs_attr.3 attr_get.3 curs_attr.3 attr_off.3 curs_attr.3 attr_on.3 \
+ curs_attr.3 attr_set.3 curs_attr.3 attroff.3 curs_attr.3 attron.3 \
+ curs_attr.3 attrset.3 curs_attr.3 chgat.3 curs_attr.3 color_set.3 \
+ curs_attr.3 mvchgat.3 curs_attr.3 mvwchgat.3 curs_attr.3 standend.3 \
+ curs_attr.3 standout.3 curs_attr.3 wattr_get.3 curs_attr.3 wattr_off.3 \
+ curs_attr.3 wattr_on.3 curs_attr.3 wattr_set.3 curs_attr.3 wattroff.3 \
+ curs_attr.3 wattron.3 curs_attr.3 wattrset.3 curs_attr.3 wchgat.3 \
+ curs_attr.3 wcolor_set.3 curs_attr.3 wstandend.3 \
+ curs_attr.3 wstandout.3
+MLINKS+=curs_beep.3 beep.3 curs_beep.3 flash.3
+MLINKS+=curs_bkgd.3 bkgd.3 curs_bkgd.3 bkgdset.3 curs_bkgd.3 getbkgd.3 \
+ curs_bkgd.3 wbkgd.3 curs_bkgd.3 wbkgdset.3
+MLINKS+=curs_border.3 border.3 curs_border.3 box.3 curs_border.3 hline.3 \
+ curs_border.3 mvhline.3 curs_border.3 mvvline.3 \
+ curs_border.3 mvwhline.3 \
+ curs_border.3 mvwvline.3 curs_border.3 vline.3 curs_border.3 wborder.3 \
+ curs_border.3 whline.3 curs_border.3 wvline.3
+MLINKS+=curs_clear.3 clear.3 curs_clear.3 clrtobot.3 curs_clear.3 clrtoeol.3 \
+ curs_clear.3 erase.3 curs_clear.3 wclear.3 curs_clear.3 wclrtobot.3 \
+ curs_clear.3 wclrtoeol.3 curs_clear.3 werase.3
+MLINKS+=curs_color.3 COLOR_PAIR.3 \
+ curs_color.3 can_change_color.3 curs_color.3 color_content.3 \
+ curs_color.3 has_colors.3 curs_color.3 init_color.3 \
+ curs_color.3 init_pair.3 curs_color.3 pair_content.3 \
+ curs_color.3 start_color.3
+MLINKS+=curs_delch.3 delch.3 curs_delch.3 mvdelch.3 curs_delch.3 mvwdelch.3 \
+ curs_delch.3 wdelch.3
+MLINKS+=curs_deleteln.3 deleteln.3 curs_deleteln.3 insdelln.3 \
+ curs_deleteln.3 insertln.3 curs_deleteln.3 wdeleteln.3 \
+ curs_deleteln.3 winsdelln.3 curs_deleteln.3 winsertln.3
+MLINKS+=curs_extend.3 curses_version.3 curs_extend.3 use_extended_names.3
+MLINKS+=curs_getch.3 getch.3 curs_getch.3 has_key.3 curs_getch.3 mvgetch.3 \
+ curs_getch.3 mvwgetch.3 curs_getch.3 ungetch.3 curs_getch.3 wgetch.3
+MLINKS+=curs_getstr.3 getnstr.3 curs_getstr.3 getstr.3 \
+ curs_getstr.3 mvgetnstr.3 curs_getstr.3 mvgetstr.3 \
+ curs_getstr.3 mvwgetnstr.3 curs_getstr.3 mvwgetstr.3 \
+ curs_getstr.3 wgetnstr.3 curs_getstr.3 wgetstr.3
+MLINKS+=curs_getyx.3 getbegyx.3 curs_getyx.3 getmaxyx.3 \
+ curs_getyx.3 getparyx.3 curs_getyx.3 getyx.3
+MLINKS+=curs_inch.3 inch.3 curs_inch.3 mvinch.3 curs_inch.3 mvwinch.3 \
+ curs_inch.3 winch.3
+MLINKS+=curs_inchstr.3 inchnstr.3 curs_inchstr.3 inchstr.3 \
+ curs_inchstr.3 mvinchnstr.3 curs_inchstr.3 mvinchstr.3 \
+ curs_inchstr.3 mvwinchnstr.3 curs_inchstr.3 mvwinchstr.3 \
+ curs_inchstr.3 winchnstr.3 curs_inchstr.3 winchstr.3
+MLINKS+=curs_initscr.3 delscreen.3 curs_initscr.3 endwin.3 \
+ curs_initscr.3 initscr.3 curs_initscr.3 isendwin.3 \
+ curs_initscr.3 newterm.3 curs_initscr.3 set_term.3
+MLINKS+=curs_inopts.3 cbreak.3 curs_inopts.3 echo.3 curs_inopts.3 halfdelay.3 \
+ curs_inopts.3 intrflush.3 curs_inopts.3 keypad.3 curs_inopts.3 meta.3 \
+ curs_inopts.3 nocbreak.3 curs_inopts.3 nodelay.3 \
+ curs_inopts.3 noecho.3 curs_inopts.3 noqiflush.3 curs_inopts.3 noraw.3 \
+ curs_inopts.3 notimeout.3 curs_inopts.3 qiflush.3 curs_inopts.3 raw.3 \
+ curs_inopts.3 timeout.3 curs_inopts.3 typeahead.3 \
+ curs_inopts.3 wtimeout.3
+MLINKS+=curs_insch.3 insch.3 curs_insch.3 mvinsch.3 curs_insch.3 mvwinsch.3 \
+ curs_insch.3 winsch.3
+MLINKS+=curs_insstr.3 insnstr.3 curs_insstr.3 insstr.3 \
+ curs_insstr.3 mvinsnstr.3 curs_insstr.3 mvinsstr.3 \
+ curs_insstr.3 mvwinsnstr.3 curs_insstr.3 mvwinsstr.3 \
+ curs_insstr.3 winsnstr.3 curs_insstr.3 winsstr.3
+MLINKS+=curs_instr.3 innstr.3 curs_instr.3 instr.3 curs_instr.3 mvinnstr.3 \
+ curs_instr.3 mvinstr.3 curs_instr.3 mvwinnstr.3 \
+ curs_instr.3 mvwinstr.3 curs_instr.3 winnstr.3 curs_instr.3 winstr.3
+MLINKS+=curs_kernel.3 curs_set.3 curs_kernel.3 def_prog_mode.3 \
+ curs_kernel.3 def_shell_mode.3 curs_kernel.3 getsyx.3 \
+ curs_kernel.3 napms.3 curs_kernel.3 reset_prog_mode.3 \
+ curs_kernel.3 reset_shell_mode.3 curs_kernel.3 resetty.3 \
+ curs_kernel.3 ripoffline.3 curs_kernel.3 savetty.3 \
+ curs_kernel.3 setsyx.3
+MLINKS+=curs_mouse.3 getmouse.3 curs_mouse.3 mouse_trafo.3 \
+ curs_mouse.3 mouseinterval.3 \
+ curs_mouse.3 mousemask.3 curs_mouse.3 ungetmouse.3 \
+ curs_mouse.3 wenclose.3 curs_mouse.3 wmouse_trafo.3
+MLINKS+=curs_move.3 move.3 curs_move.3 wmove.3
+MLINKS+=curs_outopts.3 clearok.3 curs_outopts.3 idcok.3 curs_outopts.3 idlok.3 \
+ curs_outopts.3 immedok.3 curs_outopts.3 leaveok.3 curs_outopts.3 nl.3 \
+ curs_outopts.3 nonl.3 curs_outopts.3 scrollok.3 \
+ curs_outopts.3 setscrreg.3 curs_outopts.3 wsetscrreg.3
+MLINKS+=curs_overlay.3 copywin.3 curs_overlay.3 overlay.3 \
+ curs_overlay.3 overwrite.3
+MLINKS+=curs_pad.3 newpad.3 curs_pad.3 pechochar.3 curs_pad.3 pnoutrefresh.3 \
+ curs_pad.3 prefresh.3 curs_pad.3 subpad.3
+MLINKS+=curs_print.3 mcprint.3
+MLINKS+=curs_printw.3 mvprintw.3 curs_printw.3 mvwprintw.3 \
+ curs_printw.3 printw.3 curs_printw.3 vw_printw.3 \
+ curs_printw.3 vwprintw.3 curs_printw.3 wprintw.3
+MLINKS+=curs_refresh.3 doupdate.3 curs_refresh.3 redrawwin.3 \
+ curs_refresh.3 refresh.3 curs_refresh.3 wnoutrefresh.3 \
+ curs_refresh.3 wredrawln.3 curs_refresh.3 wrefresh.3
+MLINKS+=curs_scanw.3 mvscanw.3 curs_scanw.3 mvwscanw.3 curs_scanw.3 scanw.3 \
+ curs_scanw.3 vw_scanw.3 curs_scanw.3 vwscanw.3 curs_scanw.3 wscanw.3
+MLINKS+=curs_scr_dump.3 scr_dump.3 curs_scr_dump.3 scr_init.3 \
+ curs_scr_dump.3 scr_restore.3 curs_scr_dump.3 scr_set.3
+MLINKS+=curs_scroll.3 scrl.3 curs_scroll.3 scroll.3 curs_scroll.3 wscrl.3
+MLINKS+=curs_slk.3 slk_attr.3 curs_slk.3 slk_attr_off.3 \
+ curs_slk.3 slk_attr_on.3 curs_slk.3 slk_attr_set.3 \
+ curs_slk.3 slk_attroff.3 curs_slk.3 slk_attron.3 \
+ curs_slk.3 slk_attrset.3 curs_slk.3 slk_clear.3 \
+ curs_slk.3 slk_color.3 curs_slk.3 slk_init.3 curs_slk.3 slk_label.3 \
+ curs_slk.3 slk_noutrefresh.3 curs_slk.3 slk_refresh.3 \
+ curs_slk.3 slk_restore.3 curs_slk.3 slk_set.3 curs_slk.3 slk_touch.3
+MLINKS+=curs_termattrs.3 baudrate.3 curs_termattrs.3 erasechar.3 \
+ curs_termattrs.3 has_ic.3 curs_termattrs.3 has_il.3 \
+ curs_termattrs.3 killchar.3 curs_termattrs.3 longname.3 \
+ curs_termattrs.3 termattrs.3 curs_termattrs.3 termname.3
+MLINKS+=curs_termcap.3 termcap.3 curs_termcap.3 tgetent.3 \
+ curs_termcap.3 tgetflag.3 curs_termcap.3 tgetnum.3 \
+ curs_termcap.3 tgetstr.3 curs_termcap.3 tgoto.3 \
+ curs_termcap.3 tputs.3
+MLINKS+=curs_terminfo.3 del_curterm.3 curs_terminfo.3 mvcur.3 \
+ curs_terminfo.3 putp.3 curs_terminfo.3 restartterm.3 \
+ curs_terminfo.3 set_curterm.3 curs_terminfo.3 setterm.3 \
+ curs_terminfo.3 setupterm.3 curs_terminfo.3 tigetflag.3 \
+ curs_terminfo.3 tigetnum.3 curs_terminfo.3 tigetstr.3 \
+ curs_terminfo.3 tparm.3 curs_terminfo.3 tputs.3 \
+ curs_terminfo.3 vidattr.3 curs_terminfo.3 vidputs.3
+MLINKS+=curs_touch.3 is_linetouched.3 curs_touch.3 is_wintouched.3 \
+ curs_touch.3 touchline.3 curs_touch.3 touchwin.3 \
+ curs_touch.3 untouchwin.3 curs_touch.3 wtouchln.3
+MLINKS+=curs_util.3 delay_output.3 curs_util.3 filter.3 \
+ curs_util.3 flushinp.3 curs_util.3 getwin.3 \
+ curs_util.3 keyname.3 curs_util.3 putwin.3 \
+ curs_util.3 unctrl.3 curs_util.3 use_env.3
+MLINKS+=curs_window.3 delwin.3 curs_window.3 derwin.3 curs_window.3 dupwin.3 \
+ curs_window.3 mvderwin.3 curs_window.3 mvwin.3 curs_window.3 newwin.3 \
+ curs_window.3 subwin.3 curs_window.3 syncok.3 \
+ curs_window.3 wcursyncup.3 curs_window.3 wsyncdown.3 \
+ curs_window.3 wsyncup.3
+MLINKS+=default_colors.3 assume_default_colors.3 \
+ default_colors.3 use_default_colors.3
+
+NO_LINT=
+
+.include <bsd.lib.mk>
diff --git a/lib/ncurses/ncurses/ncurses_cfg.h b/lib/ncurses/ncurses/ncurses_cfg.h
new file mode 100644
index 0000000..3fc4c2b
--- /dev/null
+++ b/lib/ncurses/ncurses/ncurses_cfg.h
@@ -0,0 +1,155 @@
+/* include/ncurses_cfg.h. Generated automatically by configure. */
+/****************************************************************************
+ * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Author: Thomas E. Dickey <dickey@clark.net> 1997 *
+ ****************************************************************************/
+/*
+ * $Id: ncurses_cfg.hin,v 1.3 2000/09/02 17:13:32 tom Exp $
+ *
+ * This is a template-file used to generate the "ncurses_cfg.h" file.
+ *
+ * Rather than list every definition, the configuration script substitutes the
+ * definitions that it finds using 'sed'. You need a patch (original date
+ * 971222) to autoconf 2.12 or 2.13 to do this.
+ *
+ * See:
+ * http://dickey.his.com/autoconf/
+ * ftp://dickey.his.com/autoconf/
+ */
+
+/* $FreeBSD$ */
+
+#ifndef NC_CONFIG_H
+#define NC_CONFIG_H
+
+#define BSD_TPUTS 1
+#define CC_HAS_INLINE_FUNCS 1
+#define CC_HAS_PROTOS 1
+#define GCC_NORETURN __dead2
+#define GCC_PRINTF 1
+#define GCC_SCANF 1
+#define GCC_UNUSED __unused
+#define HAVE_BIG_CORE 1
+#define HAVE_BSD_CGETENT 1
+#define HAVE_CURSES_VERSION 1
+#define HAVE_DIRENT_H 1
+#define HAVE_ERRNO 1
+#define HAVE_FCNTL_H 1
+#define HAVE_FORM_H 1
+#define HAVE_GETCWD 1
+#define HAVE_GETEGID 1
+#define HAVE_GETEUID 1
+#define HAVE_GETTIMEOFDAY 1
+#define HAVE_GETTTYNAM 1
+#define HAVE_HAS_KEY 1
+#define HAVE_ISASCII 1
+#define HAVE_ISSETUGID 1
+#define HAVE_LIBFORM 1
+#define HAVE_LIBMENU 1
+#define HAVE_LIBPANEL 1
+#define HAVE_LIMITS_H 1
+#define HAVE_LINK 1
+#define HAVE_LOCALE_H 1
+#define HAVE_LONG_FILE_NAMES 1
+#define HAVE_MEMCCPY 1
+#define HAVE_MENU_H 1
+#define HAVE_MKSTEMP 1
+#define HAVE_NANOSLEEP 1
+#define HAVE_NC_ALLOC_H 1
+#define HAVE_PANEL_H 1
+#define HAVE_POLL 1
+#define HAVE_POLL_H 1
+#define HAVE_REGEX_H_FUNCS 1
+#define HAVE_REMOVE 1
+#define HAVE_REMOVE 1
+#define HAVE_RESIZETERM 1
+#define HAVE_SELECT 1
+#define HAVE_SETBUF 1
+#define HAVE_SETBUFFER 1
+#define HAVE_SETVBUF 1
+#define HAVE_SIGACTION 1
+#define HAVE_SIGVEC 1
+#define HAVE_SIZECHANGE 1
+#define HAVE_STRDUP 1
+#define HAVE_STRSTR 1
+#define HAVE_SYMLINK 1
+#define HAVE_SYS_IOCTL_H 1
+#define HAVE_SYS_PARAM_H 1
+#define HAVE_SYS_POLL_H 1
+#define HAVE_SYS_SELECT_H 1
+#define HAVE_SYS_TIMES_H 1
+#define HAVE_SYS_TIME_H 1
+#define HAVE_SYS_TIME_SELECT 1
+#define HAVE_TCGETATTR 1
+#define HAVE_TCGETPGRP 1
+#define HAVE_TERMIOS_H 1
+#define HAVE_TIMES 1
+#define HAVE_TTYENT_H 1
+#define HAVE_UNISTD_H 1
+#define HAVE_UNISTD_H 1
+#define HAVE_UNLINK 1
+#define HAVE_USE_DEFAULT_COLORS 1
+#define HAVE_VSNPRINTF 1
+#define HAVE_VSSCANF 1
+#define HAVE_WORKING_POLL 1
+#define HAVE_WRESIZE 1
+#define MIXEDCASE_FILENAMES 1
+#define NCURSES_EXT_FUNCS 1
+#define NCURSES_NO_PADDING 1
+#define NCURSES_PATHSEP ':'
+#define NDEBUG 1
+#define RETSIGTYPE void
+#define STDC_HEADERS 1
+#define SYSTEM_NAME "FreeBSD"
+#define TERMINFO "/usr/share/misc/terminfo"
+#define TERMINFO_DIRS "/usr/share/misc/terminfo"
+#define TIME_WITH_SYS_TIME 1
+#define TYPEOF_CHTYPE long
+#define USE_ASSUMED_COLOR 1
+#define USE_COLORFGBG 1
+#define USE_DATABASE 1
+#define USE_GETCAP 1
+#define USE_HASHMAP 1
+#define USE_SIGWINCH 1
+
+#include <ncurses_def.h>
+
+ /* The C compiler may not treat these properly but C++ has to */
+#ifdef __cplusplus
+#undef const
+#undef inline
+#else
+#if defined(lint) || defined(TRACE)
+#undef inline
+#define inline /* nothing */
+#endif
+#endif
+
+#endif /* NC_CONFIG_H */
diff --git a/lib/ncurses/ncurses/pathnames.h b/lib/ncurses/ncurses/pathnames.h
new file mode 100644
index 0000000..5cac36f
--- /dev/null
+++ b/lib/ncurses/ncurses/pathnames.h
@@ -0,0 +1,38 @@
+/*
+ * 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. 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.
+ *
+ * @(#)pathnames.h 8.1 (Berkeley) 6/4/93
+ * $FreeBSD$
+ */
+
+#define _PATH_DEF ".termcap /usr/share/misc/termcap"
+#define _PATH_DEF_SEC "/usr/share/misc/termcap"
diff --git a/lib/ncurses/ncurses/termcap.c b/lib/ncurses/ncurses/termcap.c
new file mode 100644
index 0000000..24e71d3
--- /dev/null
+++ b/lib/ncurses/ncurses/termcap.c
@@ -0,0 +1,267 @@
+/* A portion of this file is from ncurses: */
+/***************************************************************************
+* COPYRIGHT NOTICE *
+****************************************************************************
+* ncurses is copyright (C) 1992-1995 *
+* Zeyd M. Ben-Halim *
+* zmbenhal@netcom.com *
+* Eric S. Raymond *
+* esr@snark.thyrsus.com *
+* *
+* Permission is hereby granted to reproduce and distribute ncurses *
+* by any means and for any fee, whether alone or as part of a *
+* larger distribution, in source or in binary form, PROVIDED *
+* this notice is included with any such distribution, and is not *
+* removed from any of its header files. Mention of ncurses in any *
+* applications linked with it is highly appreciated. *
+* *
+* ncurses comes AS IS with no warranty, implied or expressed. *
+* *
+***************************************************************************/
+
+#include <curses.priv.h>
+
+#include <string.h>
+#include <term.h>
+#include <tic.h>
+#include <term_entry.h>
+
+/* The rest is from BSD */
+/*
+ * 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.
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifndef lint
+static const char sccsid[] = "@(#)termcap.c 8.1 (Berkeley) 6/4/93";
+#endif /* not lint */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include "pathnames.h"
+
+#define PBUFSIZ MAXPATHLEN /* max length of filename path */
+#define PVECSIZ 32 /* max number of names in path */
+#define TBUFSIZ 1024 /* max length of _nc_tgetent buffer */
+
+char _nc_termcap[TBUFSIZ + 1]; /* Last getcap, provided to tgetent() emul */
+
+/*
+ * termcap - routines for dealing with the terminal capability data base
+ *
+ * BUG: Should use a "last" pointer in tbuf, so that searching
+ * for capabilities alphabetically would not be a n**2/2
+ * process when large numbers of capabilities are given.
+ * Note: If we add a last pointer now we will screw up the
+ * tc capability. We really should compile termcap.
+ *
+ * Essentially all the work here is scanning and decoding escapes
+ * in string capabilities. We don't use stdio because the editor
+ * doesn't, and because living w/o it is not hard.
+ */
+
+/*
+ * Get an entry for terminal name in buffer _nc_termcap from the termcap
+ * file.
+ */
+int
+_nc_read_termcap_entry(const char *const name, TERMTYPE *const tp)
+{
+ ENTRY *ep;
+ char *p;
+ char *cp;
+ char *dummy;
+ char **fname;
+ char *home;
+ int i;
+ char pathbuf[PBUFSIZ]; /* holds raw path of filenames */
+ char *pathvec[PVECSIZ]; /* to point to names in pathbuf */
+ char **pvec; /* holds usable tail of path vector */
+ char *termpath;
+
+ _nc_termcap[0] = '\0'; /* in case */
+ dummy = NULL;
+ fname = pathvec;
+ pvec = pathvec;
+ p = pathbuf;
+ cp = getenv("TERMCAP");
+ /*
+ * TERMCAP can have one of two things in it. It can be the
+ * name of a file to use instead of /etc/termcap. In this
+ * case it better start with a "/". Or it can be an entry to
+ * use so we don't have to read the file. In this case it
+ * has to already have the newlines crunched out. If TERMCAP
+ * does not hold a file name then a path of names is searched
+ * instead. The path is found in the TERMPATH variable, or
+ * becomes "$HOME/.termcap /etc/termcap" if no TERMPATH exists.
+ */
+ if (!cp || *cp != '/') { /* no TERMCAP or it holds an entry */
+ if ( (termpath = getenv("TERMPATH")) )
+ strncpy(pathbuf, termpath, PBUFSIZ);
+ else {
+ if ( (home = getenv("HOME")) ) {/* set up default */
+ strncpy(pathbuf, home, PBUFSIZ - 1); /* $HOME first */
+ pathbuf[PBUFSIZ - 2] = '\0'; /* -2 because we add a slash */
+ p += strlen(pathbuf); /* path, looking in */
+ *p++ = '/';
+ } /* if no $HOME look in current directory */
+ strncpy(p, _PATH_DEF, PBUFSIZ - (p - pathbuf));
+ }
+ }
+ else /* user-defined name in TERMCAP */
+ strncpy(pathbuf, cp, PBUFSIZ); /* still can be tokenized */
+
+ /* For safety */
+ if (issetugid())
+ strcpy(pathbuf, _PATH_DEF_SEC);
+
+ pathbuf[PBUFSIZ - 1] = '\0';
+
+ *fname++ = pathbuf; /* tokenize path into vector of names */
+ while (*++p)
+ if (*p == ' ' || *p == ':') {
+ *p = '\0';
+ while (*++p)
+ if (*p != ' ' && *p != ':')
+ break;
+ if (*p == '\0')
+ break;
+ *fname++ = p;
+ if (fname >= pathvec + PVECSIZ) {
+ fname--;
+ break;
+ }
+ }
+ *fname = (char *) 0; /* mark end of vector */
+ if (cp && *cp && *cp != '/')
+ if (cgetset(cp) < 0)
+ return(-2);
+
+ i = cgetent(&dummy, pathvec, (char *)name);
+
+ if (i == 0) {
+ char *pd, *ps, *tok, *s, *tcs;
+ size_t len;
+
+ pd = _nc_termcap;
+ ps = dummy;
+ if ((tok = strchr(ps, ':')) == NULL) {
+ len = strlen(ps);
+ if (len >= TBUFSIZ)
+ i = -1;
+ else
+ strcpy(pd, ps);
+ goto done;
+ }
+ len = tok - ps + 1;
+ if (pd + len + 1 - _nc_termcap >= TBUFSIZ) {
+ i = -1;
+ goto done;
+ }
+ memcpy(pd, ps, len);
+ ps += len;
+ pd += len;
+ *pd = '\0';
+ tcs = pd - 1;
+ for (;;) {
+ while ((tok = strsep(&ps, ":")) != NULL &&
+ *(tok - 2) != '\\' &&
+ (*tok == '\0' || *tok == '\\' || !isgraph(*tok)))
+ ;
+ if (tok == NULL)
+ break;
+ for (s = tcs; s != NULL && s[1] != '\0';
+ s = strchr(s, ':')) {
+ s++;
+ if (s[0] == tok[0] && s[1] == tok[1])
+ goto skip_it;
+ }
+ len = strlen(tok);
+ if (pd + len + 1 - _nc_termcap >= TBUFSIZ) {
+ i = -1;
+ break;
+ }
+ memcpy(pd, tok, len);
+ pd += len;
+ *pd++ = ':';
+ *pd = '\0';
+ skip_it: ;
+ }
+ }
+done:
+ if (dummy)
+ free(dummy);
+
+
+/*
+ * From here on is ncurses-specific glue code
+ */
+
+ if (i < 0)
+ return(ERR);
+
+ _nc_set_source("TERMCAP");
+ _nc_read_entry_source((FILE *)NULL, _nc_termcap, FALSE, TRUE, NULLHOOK);
+
+ if (_nc_head == (ENTRY *)NULL)
+ return(ERR);
+
+ /* resolve all use references */
+ _nc_resolve_uses(TRUE);
+
+ for_entry_list(ep)
+ if (_nc_name_match(ep->tterm.term_names, name, "|:"))
+ {
+ /*
+ * Make a local copy of the terminal capabilities. free
+ * all entry storage except the string table for the
+ * loaded type (which we disconnected from the list by
+ * NULLing out ep->tterm.str_table above).
+ */
+ memcpy(tp, &ep->tterm, sizeof(TERMTYPE));
+ ep->tterm.str_table = (char *)NULL;
+ _nc_free_entries(_nc_head);
+ _nc_head = _nc_tail = NULL; /* do not reuse! */
+
+ return 1; /* OK */
+ }
+
+ _nc_free_entries(_nc_head);
+ _nc_head = _nc_tail = NULL; /* do not reuse! */
+ return(0); /* not found */
+}
diff --git a/lib/ncurses/panel/Makefile b/lib/ncurses/panel/Makefile
new file mode 100644
index 0000000..6d828b2
--- /dev/null
+++ b/lib/ncurses/panel/Makefile
@@ -0,0 +1,48 @@
+# Makefile for libpanel
+# $FreeBSD$
+
+NCURSES=${.CURDIR}/../../contrib/ncurses
+
+.PATH: ${NCURSES}/panel ${NCURSES}/include
+.PATH: ${NCURSES}/man
+
+LIB= panel
+DPADD= ${LIBNCURSES}
+LDADD= -lncurses
+AWK?= awk
+
+SRCS= ncurses_def.h \
+ p_above.c p_below.c p_bottom.c p_delete.c p_hidden.c \
+ p_hide.c p_move.c p_new.c p_replace.c p_show.c p_top.c \
+ p_update.c p_user.c p_win.c panel.c
+INCS= ${NCURSES}/panel/panel.h
+
+CLEANFILES+= ncurses_def.h
+CFLAGS+= -I.
+.if exists(${.OBJDIR}/../libncurses)
+CFLAGS+= -I${.OBJDIR}/../libncurses
+.endif
+CFLAGS+= -I${.CURDIR}/../libncurses
+CFLAGS+= -I${NCURSES}/panel -I${NCURSES}/include -I${NCURSES}/ncurses \
+ -Wall -DNDEBUG -DHAVE_CONFIG_H
+
+ncurses_def.h: MKncurses_def.sh ncurses_defs
+ AWK=${AWK} sh ${NCURSES}/include/MKncurses_def.sh \
+ ${NCURSES}/include/ncurses_defs > ncurses_def.h
+
+# generate MAN
+CLEANFILES+= panel.3
+MAN= panel.3
+panel.3: panel.3x
+ cat ${.ALLSRC} > ${.TARGET}
+
+MLINKS+=panel.3 bottom_panel.3 panel.3 del_panel.3 panel.3 hide_panel.3 \
+ panel.3 move_panel.3 panel.3 new_panel.3 panel.3 panel_above.3 \
+ panel.3 panel_below.3 panel.3 panel_hidden.3 \
+ panel.3 panel_userptr.3 panel.3 panel_window.3 \
+ panel.3 replace_panel.3 panel.3 set_panel_userptr.3 \
+ panel.3 show_panel.3 panel.3 top_panel.3 panel.3 update_panels.3
+
+.include <bsd.lib.mk>
+
+.SUFFIXES: .3x .3
OpenPOWER on IntegriCloud